Index: /tags/gsdl-2_61-distribution/gli/.java.policy
===================================================================
--- /tags/gsdl-2_61-distribution/gli/.java.policy	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/.java.policy	(revision 10506)
@@ -0,0 +1,12 @@
+
+grant {
+        permission java.io.FilePermission "<<ALL FILES>>", "read, write";
+        permission javax.sound.sampled.AudioPermission "record";
+        permission java.util.PropertyPermission "user.dir", "read";
+        permission java.util.PropertyPermission "user.home", "read";
+
+        permission java.lang.RuntimePermission "modifyThread";
+
+	permission java.util.prefs.syncInterval "write";
+	permission java.library.path "read, write";
+}
Index: /tags/gsdl-2_61-distribution/gli/LICENSE.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gli/LICENSE.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/LICENSE.txt	(revision 10506)
@@ -0,0 +1,350 @@
+Copyright (c) 2003 Greenstone Digital Libraries, 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 Greenstone Digital Libraries, 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 Greenstone Digital Libraries, 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: /tags/gsdl-2_61-distribution/gli/READMEen.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gli/READMEen.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/READMEen.txt	(revision 10506)
@@ -0,0 +1,50 @@
+The Greenstone Librarian Interface
+----------------------------------
+
+This folder contains the Greenstone Librarian Interface (GLI), a tool to
+assist you with building digital libraries using Greenstone. The GLI gives
+you access to Greenstone's functionality from an easy-to-use, 'point and
+click' interface.
+
+To use the GLI, you need a suitable version of the Java Runtime Environment
+(version 1.4.0 or newer). If you don't already have one, you can download
+one from http://java.sun.com/j2se/downloads.html
+
+Note that the GLI is run in conjunction with Greenstone, and assumes that
+it is installed in a subdirectory of your Greenstone installation. If you
+have downloaded one of the Greenstone distributions, or installed from a 
+Greenstone CD-ROM, this will be the case.
+
+
+-- Running the GLI under Windows --
+
+To run the GLI under Windows, browse to the GLI folder in your Greenstone
+installation (using Windows Explorer), and double-click on the gli.bat
+file. This file will check that Greenstone, Perl, and the Java Runtime
+Environment are installed, then start the Greenstone Librarian Interface.
+
+
+-- Running the GLI under Unix --
+
+To run the GLI under Unix, change to the GLI directory in your Greenstone
+installation, then run the gli.sh script. This script will check that
+Greenstone, Perl, and the Java Runtime Environment are installed (make sure
+they are on your search path), then start the Greenstone Librarian
+Interface.
+
+
+Please report any problems you have running or using the Librarian
+Interface to greenstone@cs.waikato.ac.nz.
+
+
+-- Compiling the GLI --
+
+If you have downloaded the Greenstone source distribution, or you have
+obtained the GLI via CVS, you will have the source code (Java) of the
+Librarian Interface. Compiling it requires a suitable version of the Java
+Software Development Kit (version 1.4.0 or newer). You can download one
+from http://java.sun.com/j2se/downloads.html
+
+To compile this source code, run the makegli.bat (Windows) or makegli.sh
+(Unix) files. Once this has been done, you can run the GLI using the
+instructions above.
Index: /tags/gsdl-2_61-distribution/gli/READMEes.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gli/READMEes.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/READMEes.txt	(revision 10506)
@@ -0,0 +1,54 @@
+Interfaz de la Biblioteca Digital Greenstone
+--------------------------------------------
+
+Esta carpeta contiene la Interfaz de la Biblioteca Digital Greenstone (GLI
+por sus siglas en inglés), una herramienta que le ayudará a crear y 
+construir bibliotecas digitales por medio de Greenstone. La GLI le da 
+acceso a las funciones de Greenstone desde una interfaz fácil de usar con 
+la que solo tiene que apuntar y hacer click.
+
+Para poder usar la GLI usted necesita una versión adecuada del Ambiente 
+de Ejecución Java (versión 1.4.0 o posterior). Si aún no la tiene, podrá 
+bajarla desde http://java.sun.com/j2se/downloads.html.
+
+Recuerde que la GLI se ejecuta junto con los programas Greenstone, por 
+lo que se asume que estará instalada en un subdirectorio de Greenstone. 
+Si usted ya bajó de la Web una de las versiones de Greenstone o la instaló  
+desde un CD-ROM, entonces éste será el caso.
+
+
+-- Ejecución de la GLI bajo Windows --
+
+Para correr la GLI bajo Windows explore la carpeta GLI que se encuentra 
+en su instalación Greenstone (por medio de Windows Explorer) y haga 
+doble click en el archivo gli.bat. Este archivo verificará que Greenstone, 
+Perl y el Ambiente de Ejecución Java están instalados. A continuación 
+inicie la Interfaz de la Biblioteca Digital Greenstone.
+
+
+-- Ejecución de la GLI bajo UNIX --
+
+Para correr la GLI bajo UNIX cambie al directorio GLI que se encuentra en 
+su instalación Greenstone y ejecute el guión gli.sh. Este guión 
+verificará que Greenstone, Perl y el Ambiente de Ejecución Java están 
+instalados (asegúrese de que están en su ruta de búsqueda). A 
+continuación inicie la Interfaz de la Biblioteca Digital Greenstone.
+
+
+Por favor informe sobre cualquier problema que tenga al correr o usar la 
+Interfaz de la Biblioteca Digital a la siguiente dirección:
+greenstone@cs.waikato.ac.nz.
+
+
+-- Compilación de la GLI --
+
+Si usted ha bajado la versión con el código fuente de Greenstone o ha 
+obtenido la GLI por medio de CVS, entonces tendrá el código fuente 
+(Java) de la Interfaz de la Biblioteca Digital. Para compilarlo se necesita 
+una versión adecuada del Kit de Desarrollo de Software Java (versión 
+1.4.0 o posterior). Usted puede bajarlo desde 
+http://java.sun.com/j2se/downloads.html.
+
+Para compilar este código fuente ejecute los archivos makegli.bat 
+(Windows) o makegli.sh (UNIX). Una vez que haya hecho esto usted 
+podrá correr la GLI usando las instrucciones que aparecen arriba.
Index: /tags/gsdl-2_61-distribution/gli/READMEfr.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gli/READMEfr.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/READMEfr.txt	(revision 10506)
@@ -0,0 +1,49 @@
+L'Interface du Bibliothécaire de Greenstone (Greenstone Librarian Interface)
+----------------------------------------------------------------------------
+
+Ce dossier contient l'Interface du Bibliothécaire de Greenstone - Greenstone 
+Librarian Interface (GLI), un outil qui vous assiste pour la création de 
+bibliothèques numérique avec Greenstone. GLI vous donne accès aux fonctions 
+de Greenstone à partir d'une interce 'pointer et cliquer' facile à utiliser.
+
+Pour utiliser GLI, vous avez besoin d'une version adéquate de Java Runtime 
+Environment (version 1.4.0 ou supérieure). Si vous n'en disposez pas, vous 
+pouvez le télécharger de http://java.sun.com/j2se/downloads.html
+
+Notez que GLI est lancé avec Greenstone et suppose qu'il est installé dans 
+un sous-répertoire de votre installation Greenstone. Si vous avez téléchargé 
+une des distributions de Greenstone ou si vous avez installé à partir d'un 
+CD-ROM, ceci sera le cas.
+
+
+-- Exécuter GLI sous Windows --
+
+Pour exécuter GLI sous Windows, parcourez votre système de fichiers jusqu'au 
+répertoire GLI (en utilisant Windows Explorer), et double-cliquez sur le 
+fichier gli.bat. Ce fichier va vérifier que Greenstone, Perl et Java Runtime 
+Environment sont installés, puis démarre Greenstone Librarian Interface.
+
+
+-- Exécuter GLI sous Unix --
+
+Pour exécuter GLI sous Unix, aller au répertoire GLI de votre installation 
+Greenstone et lancer le script gli.sh. Ce script va vérifier que Greenstone, 
+Perl et Java Runtime Environment sont installés (assurez-vous qu'ils sont 
+dans le chemin de recherche), puis démarre Greenstone Librarian Interface.
+
+
+Prière de signaler tous problèmes rencontrés lors de l'exécution ou de 
+l'utilisation de Librarian Interface à greenstone@cs.waikato.ac.nz.
+
+
+-- Compiler GLI --
+
+Si vous avez téléchargé la distribution source de Greenstone, ou si vous 
+avez obtenu Greenstone à travers CVS, alors vous avez le code source (Java) 
+de Librarian Interface. Le compiler requière une version adéquate de Java 
+Software Development Kit (version 1.4.0 ou supérieure). Vous pouvez le 
+télécharger de http://java.sun.com/j2se/downloads.html
+
+Pour compiler ce code source, exécutez makegli.bat (Windows) ou makegli.sh 
+(Unix). Une fois ceci fait, vous pouvez exécuter GLI en suivant les 
+instructions ci-dessus.
Index: /tags/gsdl-2_61-distribution/gli/READMEru.txt-cp1251
===================================================================
--- /tags/gsdl-2_61-distribution/gli/READMEru.txt-cp1251	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/READMEru.txt-cp1251	(revision 10506)
@@ -0,0 +1,51 @@
+Èíòåðôåéñ áèáëèîòåêè Greenstone
+-------------------------------
+
+Ýòà ïàïêà ñîäåðæèò èíòåðôåéñ Áèáëèîòåêè Greenstone (GLI) - èíñòðóìåíò,
+êîòîðûé ïîìîæåò Âàì â ïîñòðîåíèè öèôðîâûõ áèáëèîòåê ñ èñïîëüçîâàíèåì
+Greenstone. GLI äàžò Âàì âîçìîæíîñòü ïîëó÷èòü äîñòóï ê ôóíêöèîíàëüíûì
+âîçìîæíîñòÿì Greenstone, óäîáíîìó â ðàáîòå èíòåðôåéñó - óêàæèòå è ùåëêíèòå.
+
+×òîáû èñïîëüçîâàòü GLI, Âàì íåîáõîäèìà ïîäõîäÿùàÿ âåðñèÿ Java Runtime
+Environment (JRE) (âåðñèÿ 1.4.0 èëè áîëåå íîâàÿ). Åñëè ó Âàñ îíà
+îòñóòñòâóåò, Âû ìîæåòå çàãðóçèòü åž ñ ñàéòà
+http://java.sun.com/j2se/downloads.html
+
+Îáðàòèòå âíèìàíèå, ÷òî GLI ñâÿçàíà ñ Greenstone. Ïðåäïîëàãàåòñÿ, ÷òî îíà
+óñòàíîâëåíà â ïîääèðåêòîðèè ïðè èíñòàëëÿöèè Greenstone. Åñëè Âû çàãðóçèëè
+îäèí èç äèñòðèáóòèâîâ Greenstone èëè óñòàíîâèëè åãî ñ CD-ROM, òî ýòî áóäåò
+èìåòü ìåñòî.
+
+
+-- Çàïóñê GLI ïîä Windows --
+
+×òîáû çàïóñòèòü GLI ïîä Windows, ðàññìîòðèòå ïàïêó GLI â èíñòàëëèðîâàííîì ó
+Âàñ Greenstone, èñïîëüçóÿ Windows Explorer, è ùåëêíèòå 2 ðàçà íà ôàéë
+gli.bat. Ýòîò ôàéë ïðîâåðèò, ÷òî Greenstone, Perl è JRE óñòàíîâëåíû, ïîñëå
+÷åãî çàïóñêàåòñÿ èíòåðôåéñ Greenstone.
+
+
+-- Çàïóñê GLI ïîä Unix --
+
+×òîáû çàïóñòèòü GLI ïîä Unix, èçìåíèòå äèðåêòîðèþ GLI â âàøåì
+èíñòàëëèðîâàííîì Greenstone, çàòåì îáðàòèòåñü ê ñêðèïòó gli.sh. Ýòîò ñêðèïò
+ïðîâåðèò, ÷òî Greenstone, Perl è JRE óñòàíîâëåíû (óäîñòîâåðüòåñü, ÷òî îíè
+íàõîäÿòñÿ íà óêàçàííîì âàìè ïóòè ïîèñêà), ïîñëå ÷åãî ñòàðòóåò èíòåðôåéñ
+Greenstone.
+
+
+Ïîæàëóéñòà, ñîîáùèòå î ëþáûõ ïðîáëåìàõ, êîòîðûå ó Âàñ èìåþòñÿ ïðè çàïóñêå
+èëè èñïîëüçîâàíèè èíòåðôåéñà GS, ê greenstone@cs.waikato.ac.nz.
+
+
+-- Êîìïèëèðîâàíèå GLI --
+
+Åñëè Âû çàãðóçèëè èñòî÷íèê äèñòðèáóòèâà Greenstone èëè æå ðàñïîëàãàåòå GLI
+îò CVS, òî Âû ðàñïîëàãàåòå èñõîäíîé ïðîãðàììîé Java èíòåðôåéñà áèáëèîòåêè.
+Êîìïèëÿöèÿ åž òðåáóåò ïîäõîäÿùåé âåðñèè ïðîãðàììíîãî îáåñïå÷åíèÿ Java
+Software Development Kit (âåðñèÿ 1.4.0 èëè áîëåå íîâàÿ). Âû ìîæåòå çàãðóçèòü
+åž ñ ñàéòà http://java.sun.com/j2se/downloads.html.
+
+×òîáû ñîáðàòü ýòó èñõîäíóþ ïðîãðàììó, âîéäèòå â ôàéëû makegli.bat (Windows)
+èëè makegli.sh (Unix). Êàê òîëüêî ýòî áóäåò ñäåëàíî, ìîæåòå çàïóñòèòü GLI,
+èñïîëüçóÿ äàííûå âûøå èíñòðóêöèè.
Index: /tags/gsdl-2_61-distribution/gli/READMEru.txt-koi8-r
===================================================================
--- /tags/gsdl-2_61-distribution/gli/READMEru.txt-koi8-r	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/READMEru.txt-koi8-r	(revision 10506)
@@ -0,0 +1,51 @@
+éÎÔÅÒÆÅÊÓ ÂÉÂÌÉÏÔÅËÉ Greenstone
+-------------------------------
+
+üÔÁ ÐÁÐËÁ ÓÏÄÅÒÖÉÔ ÉÎÔÅÒÆÅÊÓ âÉÂÌÉÏÔÅËÉ Greenstone (GLI) - ÉÎÓÔÒÕÍÅÎÔ,
+ËÏÔÏÒÙÊ ÐÏÍÏÖÅÔ ÷ÁÍ × ÐÏÓÔÒÏÅÎÉÉ ÃÉÆÒÏ×ÙÈ ÂÉÂÌÉÏÔÅË Ó ÉÓÐÏÌØÚÏ×ÁÎÉÅÍ
+Greenstone. GLI ÄÁ£Ô ÷ÁÍ ×ÏÚÍÏÖÎÏÓÔØ ÐÏÌÕÞÉÔØ ÄÏÓÔÕÐ Ë ÆÕÎËÃÉÏÎÁÌØÎÙÍ
+×ÏÚÍÏÖÎÏÓÔÑÍ Greenstone, ÕÄÏÂÎÏÍÕ × ÒÁÂÏÔÅ ÉÎÔÅÒÆÅÊÓÕ - ÕËÁÖÉÔÅ É ÝÅÌËÎÉÔÅ.
+
+þÔÏÂÙ ÉÓÐÏÌØÚÏ×ÁÔØ GLI, ÷ÁÍ ÎÅÏÂÈÏÄÉÍÁ ÐÏÄÈÏÄÑÝÁÑ ×ÅÒÓÉÑ Java Runtime
+Environment (JRE) (×ÅÒÓÉÑ 1.4.0 ÉÌÉ ÂÏÌÅÅ ÎÏ×ÁÑ). åÓÌÉ Õ ÷ÁÓ ÏÎÁ
+ÏÔÓÕÔÓÔ×ÕÅÔ, ÷Ù ÍÏÖÅÔÅ ÚÁÇÒÕÚÉÔØ Å£ Ó ÓÁÊÔÁ
+http://java.sun.com/j2se/downloads.html
+
+ïÂÒÁÔÉÔÅ ×ÎÉÍÁÎÉÅ, ÞÔÏ GLI Ó×ÑÚÁÎÁ Ó Greenstone. ðÒÅÄÐÏÌÁÇÁÅÔÓÑ, ÞÔÏ ÏÎÁ
+ÕÓÔÁÎÏ×ÌÅÎÁ × ÐÏÄÄÉÒÅËÔÏÒÉÉ ÐÒÉ ÉÎÓÔÁÌÌÑÃÉÉ Greenstone. åÓÌÉ ÷Ù ÚÁÇÒÕÚÉÌÉ
+ÏÄÉÎ ÉÚ ÄÉÓÔÒÉÂÕÔÉ×Ï× Greenstone ÉÌÉ ÕÓÔÁÎÏ×ÉÌÉ ÅÇÏ Ó CD-ROM, ÔÏ ÜÔÏ ÂÕÄÅÔ
+ÉÍÅÔØ ÍÅÓÔÏ.
+
+
+-- úÁÐÕÓË GLI ÐÏÄ Windows --
+
+þÔÏÂÙ ÚÁÐÕÓÔÉÔØ GLI ÐÏÄ Windows, ÒÁÓÓÍÏÔÒÉÔÅ ÐÁÐËÕ GLI × ÉÎÓÔÁÌÌÉÒÏ×ÁÎÎÏÍ Õ
+÷ÁÓ Greenstone, ÉÓÐÏÌØÚÕÑ Windows Explorer, É ÝÅÌËÎÉÔÅ 2 ÒÁÚÁ ÎÁ ÆÁÊÌ
+gli.bat. üÔÏÔ ÆÁÊÌ ÐÒÏ×ÅÒÉÔ, ÞÔÏ Greenstone, Perl É JRE ÕÓÔÁÎÏ×ÌÅÎÙ, ÐÏÓÌÅ
+ÞÅÇÏ ÚÁÐÕÓËÁÅÔÓÑ ÉÎÔÅÒÆÅÊÓ Greenstone.
+
+
+-- úÁÐÕÓË GLI ÐÏÄ Unix --
+
+þÔÏÂÙ ÚÁÐÕÓÔÉÔØ GLI ÐÏÄ Unix, ÉÚÍÅÎÉÔÅ ÄÉÒÅËÔÏÒÉÀ GLI × ×ÁÛÅÍ
+ÉÎÓÔÁÌÌÉÒÏ×ÁÎÎÏÍ Greenstone, ÚÁÔÅÍ ÏÂÒÁÔÉÔÅÓØ Ë ÓËÒÉÐÔÕ gli.sh. üÔÏÔ ÓËÒÉÐÔ
+ÐÒÏ×ÅÒÉÔ, ÞÔÏ Greenstone, Perl É JRE ÕÓÔÁÎÏ×ÌÅÎÙ (ÕÄÏÓÔÏ×ÅÒØÔÅÓØ, ÞÔÏ ÏÎÉ
+ÎÁÈÏÄÑÔÓÑ ÎÁ ÕËÁÚÁÎÎÏÍ ×ÁÍÉ ÐÕÔÉ ÐÏÉÓËÁ), ÐÏÓÌÅ ÞÅÇÏ ÓÔÁÒÔÕÅÔ ÉÎÔÅÒÆÅÊÓ
+Greenstone.
+
+
+ðÏÖÁÌÕÊÓÔÁ, ÓÏÏÂÝÉÔÅ Ï ÌÀÂÙÈ ÐÒÏÂÌÅÍÁÈ, ËÏÔÏÒÙÅ Õ ÷ÁÓ ÉÍÅÀÔÓÑ ÐÒÉ ÚÁÐÕÓËÅ
+ÉÌÉ ÉÓÐÏÌØÚÏ×ÁÎÉÉ ÉÎÔÅÒÆÅÊÓÁ GS, Ë greenstone@cs.waikato.ac.nz.
+
+
+-- ëÏÍÐÉÌÉÒÏ×ÁÎÉÅ GLI --
+
+åÓÌÉ ÷Ù ÚÁÇÒÕÚÉÌÉ ÉÓÔÏÞÎÉË ÄÉÓÔÒÉÂÕÔÉ×Á Greenstone ÉÌÉ ÖÅ ÒÁÓÐÏÌÁÇÁÅÔÅ GLI
+ÏÔ CVS, ÔÏ ÷Ù ÒÁÓÐÏÌÁÇÁÅÔÅ ÉÓÈÏÄÎÏÊ ÐÒÏÇÒÁÍÍÏÊ Java ÉÎÔÅÒÆÅÊÓÁ ÂÉÂÌÉÏÔÅËÉ.
+ëÏÍÐÉÌÑÃÉÑ Å£ ÔÒÅÂÕÅÔ ÐÏÄÈÏÄÑÝÅÊ ×ÅÒÓÉÉ ÐÒÏÇÒÁÍÍÎÏÇÏ ÏÂÅÓÐÅÞÅÎÉÑ Java
+Software Development Kit (×ÅÒÓÉÑ 1.4.0 ÉÌÉ ÂÏÌÅÅ ÎÏ×ÁÑ). ÷Ù ÍÏÖÅÔÅ ÚÁÇÒÕÚÉÔØ
+Å£ Ó ÓÁÊÔÁ http://java.sun.com/j2se/downloads.html.
+
+þÔÏÂÙ ÓÏÂÒÁÔØ ÜÔÕ ÉÓÈÏÄÎÕÀ ÐÒÏÇÒÁÍÍÕ, ×ÏÊÄÉÔÅ × ÆÁÊÌÙ makegli.bat (Windows)
+ÉÌÉ makegli.sh (Unix). ëÁË ÔÏÌØËÏ ÜÔÏ ÂÕÄÅÔ ÓÄÅÌÁÎÏ, ÍÏÖÅÔÅ ÚÁÐÕÓÔÉÔØ GLI,
+ÉÓÐÏÌØÚÕÑ ÄÁÎÎÙÅ ×ÙÛÅ ÉÎÓÔÒÕËÃÉÉ.
Index: /tags/gsdl-2_61-distribution/gli/classes/META-INF/MANIFEST.MF
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/META-INF/MANIFEST.MF	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/META-INF/MANIFEST.MF	(revision 10506)
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Created-By: 1.3.0 (Sun Microsystems Inc.)
+Main-Class: org.greenstone.gatherer.Gatherer
+Classpath: .\Gatherer.jar
Index: /tags/gsdl-2_61-distribution/gli/classes/dictionary.properties
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/dictionary.properties	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/dictionary.properties	(revision 10506)
@@ -0,0 +1,1022 @@
+#*******************
+#
+#***** AboutDialog *****
+AboutDialog.Acknowledgement:Acknowledgements for proprietary programs, packages or classes...
+AboutDialog.Date:(August 2005)
+AboutDialog.Item0:'Xerces Java 1' from The Apache Software Foundation (http://www.apache.org/)
+AboutDialog.Item2:'WGet' from Free Software Foundation, Inc. (http://www.gnu.org/software/wget/wget.html)
+AboutDialog.Item3:'qflib' from Quality First Software GmbH. (http://www.qfs.de/en/qflib/index.html)
+AboutDialog.Item4:'ExtensionFileFilter.class' by Bruno Dumon and contributors (http://pollo.sourceforge.net/)
+AboutDialog.Item5:'How to disable file renaming in file chooser' - vladi21 (http://www.experts-exchange.com/)
+AboutDialog.Item6:'Autoscrolling' - Java Swing by Robert Eckstein, Marc Loy & Dave Wood (http://www.oreilly.com/catalog/jswing/chapter/dnd.beta.pdf)
+AboutDialog.Item7:'Add ghosted drag images to your JTrees' - By Andrew J. Armstrong (http://www.javaworld.com/javaworld/javatips/jw-javatip114.html)
+AboutDialog.Item8:'Stop annoying java.prefs error when you don't have superuser access' - Thanks to Walter Schatz
+AboutDialog.Java_Req:Java is a trademark of Sun Microsystems Inc. The JRE is redistributed as per the Supplemental License Terms, found at http://java.sun.com/j2se/1.4.1/j2re-1_4_1_02-license.html
+AboutDialog.Java_Req_One:This product includes code licensed from RSA Security, Inc.
+AboutDialog.Java_Req_Two:Some portions licensed from IBM are available at http\://oss.software.ibm.com/icu4j/
+AboutDialog.Thanks:Also thanks to those who posted helpful java information on the web...
+AboutDialog.Title:About...
+AboutDialog.Title_One:Greenstone Librarian Interface
+AboutDialog.Title_Two:Greenstone Digital Library, University of Waikato
+AboutDialog.Copyright:Copyright (C) 2003 New Zealand Digital Library Project
+AboutDialog.Copyright_Two:Published under the GPL. See LICENSE.txt for details.
+#***********************
+#
+#***** Audit Table *****
+AuditTable.File:Filename
+#***********************
+#
+#***** Auto Filter *****
+Autofilter.AND:AND
+Autofilter.Ascending:Ascending
+Autofilter.Case_Sensitive:Match Case
+Autofilter.Custom_Filter:Advanced
+Autofilter.Descending:Descending
+Autofilter.Filter_By_Value:Simple
+Autofilter.Name:Column Name
+Autofilter.None:None
+Autofilter.Operator:Condition
+Autofilter.OR:OR
+Autofilter.Order:Ordering
+Autofilter.Order_Tooltip:Sort the matching items in this order
+Autofilter.Remove:Remove Filter
+Autofilter.Remove_Tooltip:Remove this filter from the table column
+Autofilter.Set:Set Filter
+Autofilter.Set_Tooltip:Add this filter to the table column
+Autofilter.Table_Header_Tooltip:Filter by {0}
+Autofilter.Title:Autofilter Metadata
+Autofilter.eqeq:equal to
+Autofilter.!eq:does not equal
+Autofilter.<:is less than
+Autofilter.<eq:is less than or equal to
+Autofilter.>:is greater than
+Autofilter.>eq:is greater than or equal to
+Autofilter.^:starts with
+Autofilter.!^:does not start with
+Autofilter.$:ends with
+Autofilter.!$:does not end with
+Autofilter.?:contains
+Autofilter.!?:does not contain
+#
+#     ********************************************************
+#     *************** Collection Design Module ***************
+#     ********************************************************
+#     * The dictionary  phrases  used in the creation of the *
+#     * Colection  Design  Module. Note that we  still  have *
+#     * access  to the format  arguments (argument  32+) for *
+#     * html formatting.                                     *
+#     ********************************************************
+CDM.ArgumentConfiguration.Add:Add
+CDM.ArgumentConfiguration.Bad_Integer:<html>The argument '{0}' requires an integer value,<br>but no integer can be parsed from {1}.</html>
+CDM.ArgumentConfiguration.Custom_Header:Custom
+CDM.ArgumentConfiguration.Custom:Custom Arguments:
+CDM.ArgumentConfiguration.Error_Title:Error In Arguments
+CDM.ArgumentConfiguration.Header:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Please configure the arguments for {0}.</CENTER></FONT></STRONG></HTML>
+CDM.ArgumentConfiguration.No_Value:The argument '{0}' requires a value, but no value is specified.
+CDM.ArgumentConfiguration.Remove:Remove
+CDM.ArgumentConfiguration.Required_Argument:The argument '{0}' must be given a value.
+CDM.ArgumentConfiguration.Title:Configuring Arguments
+CDM.ClassifierManager.Add:Add Classifier
+CDM.ClassifierManager.Add_Tooltip:Use the specified classifier with this collection
+CDM.ClassifierManager.Assigned:Currently Assigned Classifiers
+CDM.ClassifierManager.Classifier:Select classifier to add:
+CDM.ClassifierManager.Classifier_Tooltip:The classifiers available for use in the collection
+CDM.ClassifierManager.Classifier_Exists:That classifier has already been assigned for this collection.
+CDM.ClassifierManager.Classifier_Str:classifier
+CDM.ClassifierManager.Classifier_XML_Parse_Failed:Unable to determine the arguments for the {0}\nclassifier. Please ensure that the classifier in question\nprovides the -xml flag by running the classinfo.pl script\nsimilar to the description of the pluginfo.pl script in\nsection 2.1 of the Greenstone Developers Guide.
+CDM.ClassifierManager.Configure:Configure Classifier
+CDM.ClassifierManager.Configure_Tooltip:Change the options of the selected classifier
+CDM.ClassifierManager.Controls:Editing Controls
+CDM.ClassifierManager.Instructions:Use this view to add, configure or remove classifiers in your collection. To add a classifier, choose it from the combobox and click 'Add Classifier'.\nTo remove a classifier, choose it from the list of assigned classifiers and click 'Remove Classifier'.\nTo configure a classifier, choose it from the list of assigned classifiers, and click 'Configure Classifier'.\n\nWhen you configure a classifier a scrollable list of its arguments will appear. Enable arguments and enter or select values as necessary.
+CDM.ClassifierManager.Remove:Remove Classifier
+CDM.ClassifierManager.Remove_Tooltip:Remove the selected classifier from the list
+CDM.ClassifierManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Classifier Selection & Configuration</CENTER></FONT></STRONG></HTML>
+CDM.ClassifierManager.Parsing.Message:Design tool is loading classifier information.
+CDM.ClassifierManager.Parsing.Title:Loading Classifiers
+CDM.FormatManager.Add:Add Format
+CDM.FormatManager.Add_Tooltip:Use the specified format command with the collection
+CDM.FormatManager.Assigned_Formats:Currently Assigned Format Commands
+CDM.FormatManager.Editor:HTML Format String
+CDM.FormatManager.Editor_Tooltip:Enter the format command here
+CDM.FormatManager.Editing_Controls:Editing Controls
+CDM.FormatManager.Enabled:Enabled
+CDM.FormatManager.Feature:Choose Feature
+CDM.FormatManager.Feature_Tooltip:The feature to format
+CDM.FormatManager.Insert:Insert
+CDM.FormatManager.Insert_Tooltip:Insert the selected variable into the format command
+CDM.FormatManager.Instructions:The web pages you see when using Greenstone are not pre-stored but are generated 'on the fly' as they are needed. Format commands are used to change the appearance of these generated pages. Some are switches that control the display of documents or parts of documents; others are more complex and require html code as an argument.\nTo add a format command, choose it from the 'feature' list. If a True/False option panel appears, select the state by clicking on the appropriate button. If a panel containing the 'Affected Feature' and 'Edit Format Strings' controls appears, you need to enter html text. You can include preset variables by selecting them from the list.\nOnce you are statisfied with your changes, press 'Add Format' to add it to the configuration file.\nRemove a format command by selecting it from the 'Assigned Format Commands' and clicking 'Remove Format'.
+CDM.FormatManager.Part:Affected Component
+CDM.FormatManager.Part_Tooltip:The aspect of the selected feature to format
+CDM.FormatManager.Remove:Remove Format
+CDM.FormatManager.Remove_Tooltip:Remove the selected format command from the list
+CDM.FormatManager.Replace:Replace Format
+CDM.FormatManager.Replace_Tooltip:Update the selected format command
+CDM.FormatManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Format Commands</CENTER></FONT></STRONG></HTML>
+CDM.FormatManager.Variable:Variables
+CDM.FormatManager.Variable_Tooltip:Variables available for use with the format command
+CDM.General.Access:This collection should be publicly accessible
+CDM.General.Beta:This collection is still under construction
+CDM.General.Browser_Title:Select An Image
+CDM.General.Collection_Extra:Collection description:
+CDM.General.Collection_Extra_Tooltip:A description of the purpose and content of the collection
+CDM.General.Collection_Name:Collection title:
+CDM.General.Collection_Name_Tooltip:Name of the collection
+CDM.General.Copy_Image:In order to use this image for your collection\nfiles must be copied into the images folder. Proceed?
+CDM.General.Email.Creator:Creator's email
+CDM.General.Email.Creator_Tooltip:E-mail address of the collection's creator
+CDM.General.Email.Maintainer:Maintainer's email
+CDM.General.Email.Maintainer_Tooltip:E-mail address of the collection's maintainer
+CDM.General.Icon_Collection:URL to 'about page' icon:
+CDM.General.Icon_Collection_Tooltip:The URL of the image to display on the collection's about page
+CDM.General.Icon_Collection_Small:URL to 'home page' icon:
+CDM.General.Icon_Collection_Small_Tooltip:The URL of the image to display on the library's home page 
+CDM.General.Image_Copy_Failed:An error has occurred which prevents the image you selected being copied.\nPlease try copying the image to the images folder of your collection manually.
+CDM.General.Image_Filter:Images (gifs, jpgs and pngs)
+CDM.General.Instructions:The design section of the Librarian Interface allows you to control many aspects of your collection's appearance. The design is split up into several sections. This section contains general options and settings. To choose a different section, click on its name in the list to the left.
+CDM.General.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>General Options</CENTER></FONT></STRONG></HTML>
+CDM.GUI.Classifiers:Browsing Classifiers
+CDM.GUI.Design_Topics:Design Sections
+CDM.GUI.Formats:Format Features
+CDM.GUI.General:General
+CDM.GUI.Indexes:Search Indexes
+CDM.GUI.MetadataSets:Metadata Sets
+CDM.GUI.Plugins:Document Plugins
+CDM.GUI.Root:CDM_ROOT
+CDM.GUI.SearchTypes:Search Types
+CDM.GUI.Subcollections:Partition Indexes
+CDM.GUI.SuperCollection:Cross-Collection Search
+CDM.GUI.Translation:Translate Text
+CDM.IndexManager.Add_Index:Add Index
+CDM.IndexManager.Add_Index_Tooltip:Build the specified index for this collection
+CDM.IndexManager.Default_Index_Indicator:[Default Index]
+CDM.IndexManager.Document:document
+CDM.IndexManager.Index_Exists:That index has already been assigned for this collection.
+CDM.IndexManager.Index_Name:Index Name:
+CDM.IndexManager.Index_Name_Tooltip:A unique name for the new index
+CDM.IndexManager.Indexes:Assigned Indexes
+CDM.IndexManager.Instructions:Here you choose what searchable indexes the collection will have.\nTo add a new index, select what material is to be indexed, choose the level of the index, and click 'Add Index'.\nTo remove an index, select it from the assigned indexes list and click 'Remove Index'.\nTo set the default index, select it from the assigned indexes list and click 'Set Default'.
+CDM.IndexManager.Level:At the level:
+CDM.IndexManager.Level_Exists:That level has already been assigned for this collection.
+CDM.IndexManager.Level_Tooltip:The document level to build the index on
+CDM.IndexManager.MGPP.Add_All_Metadata:Add All
+CDM.IndexManager.MGPP.Add_All_Metadata_Tooltip:Build a separate index for each available source, using the source as the index name
+CDM.IndexManager.MGPP.Add_Level:Add Level
+CDM.IndexManager.MGPP.Add_Level_Tooltip:Build an index on the specified level
+CDM.IndexManager.MGPP.Current_Indexes:Currently Assigned Indexes
+CDM.IndexManager.MGPP.Current_Levels:Currently Assigned Levels
+CDM.IndexManager.MGPP.Index:Index Source:
+CDM.IndexManager.MGPP.Index_Tooltip:Metadata element to build index on
+CDM.IndexManager.MGPP.Indexes:Manage Indexes
+CDM.IndexManager.MGPP.Instructions:Here you choose what searchable indexes the collection will have.\nTo add a new index, enter a unique name for the index, select material/metadata is to be indexed, and click 'Add Index'.\nIf you wish to add all of the available sources so as to have indexes built on them, then click 'Add All' (the name for each index will default to be the name of the source). Note that this is subtly different from adding the 'AllFields' source, as the ordering of the indexes is important.\nIf you wish to edit a particular index, select it from the currently assigned indexes list, edit as necessary, and then click 'Replace Index', to replace the old version.\nTo remove an index, select it from the currently assigned indexes list and click 'Remove Index'.
+CDM.IndexManager.MGPP.Level:Level Source:
+CDM.IndexManager.MGPP.Level_Name:Level Name:
+CDM.IndexManager.MGPP.Level_Name_Tooltip:A unique name for the new level index
+CDM.IndexManager.MGPP.Levels:Manage Levels
+CDM.IndexManager.MGPP.Remove_Level:Remove Level
+CDM.IndexManager.MGPP.Remove_Level_Tooltip:Remove the selected level index
+CDM.IndexManager.MGPP.Replace_Index:Replace Index
+CDM.IndexManager.MGPP.Replace_Index_Tooltip:Update the selected index
+CDM.IndexManager.MGPP.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Index And Level Selection</CENTER></FONT></STRONG></HTML>
+CDM.IndexManager.Paragraph:paragraph
+CDM.IndexManager.Remove_Index:Remove Index
+CDM.IndexManager.Remove_Index_Tooltip:Remove the selected index from the list
+CDM.IndexManager.Section:section
+CDM.IndexManager.Set_Default:Set Default Index
+CDM.IndexManager.Set_Default_Tooltip:Make the selected index the default index
+CDM.IndexManager.Source:Build index on:
+CDM.IndexManager.Source_Tooltip:The metadata elements to build the index on
+CDM.IndexManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Index Selection</CENTER></FONT></STRONG></HTML>
+CDM.LanguageManager.Add:Add Language
+CDM.LanguageManager.Add_Tooltip:Add the specified language to the list
+CDM.LanguageManager.Assigned_Languages:Assigned Languages
+CDM.LanguageManager.Default_Language:Default Language
+CDM.LanguageManager.Remove:Remove Language
+CDM.LanguageManager.Remove_Tooltip:Remove the selected language from the list
+CDM.LanguageManager.Selector:Language to add: 
+CDM.LanguageManager.Selector_Tooltip:The language to build a partition index on
+CDM.LanguageManager.Set_Default:Set Default
+CDM.LanguageManager.Set_Default_Tooltip:Make the selected language the default
+CDM.MetadataSetManager.Add:Add Metadata Set
+CDM.MetadataSetManager.Add_Tooltip:Add a new metadata set to the collection.
+CDM.MetadataSetManager.Edit:Edit Metadata Set
+CDM.MetadataSetManager.Edit_Message:Metadata sets can be edited using GEMS (Greenstone Editor for Metadata Sets).\nStart GEMS by running gems.bat (Windows) or gems.sh (Linux) from the gli folder of your Greenstone installation.
+CDM.MetadataSetManager.Edit_Message_Title:Editing Metadata Sets
+CDM.MetadataSetManager.Edit_Tooltip:Edit the selected metadata set.
+CDM.MetadataSetManager.Elements:Elements in selected Metadata Set
+CDM.MetadataSetManager.Instructions:In this design view you can add, configure and remove the Metadata Sets in your collection and what Elements they contain.
+CDM.MetadataSetManager.Remove:Remove Metadata Set
+CDM.MetadataSetManager.Remove_Tooltip:Remove the selected metadata set from the collection.
+CDM.MetadataSetManager.Sets:Available Metadata Sets
+CDM.MetadataSetManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Metadata Sets</CENTER></FONT></STRONG></HTML>
+CDM.Move.At_Bottom:Cannot move the {0} {1} lower as it is already at the bottom of the list.
+CDM.Move.At_Top:Cannot move the {0} {1} higher as it is already at the top of the list.
+CDM.Move.Cannot:Cannot move the plugin {0} any lower as RecPlug and ArcPlug must be at the bottom of the list.
+CDM.Move.Fixed:<html>RecPlug and ArcPlug are generally required to be last and so are fixed in place.<br>If you really must move them please hand edit the collect.cfg file.</html>
+CDM.Move.Move_Down:Move Down
+CDM.Move.Move_Down_Tooltip:Move the selected item down the list
+CDM.Move.Move_Up:Move Up
+CDM.Move.Move_Up_Tooltip:Move the selected item up the list
+CDM.Move.Title:Error - Cannot Move
+CDM.PlugInManager.Add:Add Plugin
+CDM.PlugInManager.Add_Tooltip:Use the specified plugin with this collection
+CDM.PlugInManager.Assigned:Currently Assigned Plugins
+CDM.PlugInManager.Configure:Configure Plugin
+CDM.PlugInManager.Configure_Tooltip:Change the options of the selected plugin
+CDM.PlugInManager.Controls:Editing Controls
+CDM.PlugInManager.Ignore:Don't Add Plugin
+CDM.PlugInManager.Ignore_Tooltip:Don't add any plugins to this collection.
+CDM.PlugInManager.Instructions:Use this view to add, configure or remove plugins from your collection. To add one choose it from the combobox and click 'Add Plugin'.\nTo configure or remove one, select it from the list of assigned plugins then:\ni)   Change its position in the plugin order by clicking on the arrow buttons. (Note: The position of RecPlug and ArcPlug are fixed).\nii)  Configure it by clicking 'Configure Plugin',\niii) Remove it by clicking 'Remove Plugin'.\n\nPlugins are configured using a pop-up design area with a scrollable list of arguments. Enable arguments and enter or select values as necessary.
+CDM.PlugInManager.PlugIn:Select plugin to add:
+CDM.PlugInManager.PlugIn_Tooltip:The plugins available for use in the collection
+CDM.PlugInManager.PlugIn_Exists:That plugin has already been assigned for this collection.
+CDM.PlugInManager.PlugIn_Str:plugin
+CDM.PlugInManager.PlugIn_XML_Parse_Failed:Unable to determine the arguments for the {0}\nplugin. Please ensure that the plugin in question provides\nthe -xml flag by running the pluginfo.pl script described\nin section 2.1 of the Greenstone Developers Guide.
+CDM.PluginManager.Plugin_Suggestion_Prompt:None of the plugins in this collection are expected to process the file "{0}". The following plugins can be used to process this file. You can add one to your collection now by selecting it and pressing the Add button. (Note that you can change the list of plugins at any time by going to "Document Plugins" on the Design Pane.)
+CDM.PlugInManager.Remove:Remove Plugin
+CDM.PlugInManager.Remove_Tooltip:Remove the selected plugin from the list
+CDM.PluginManager.SuggestedPluginListTitle:Suggested plugins for file
+CDM.PlugInManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Plugin Selection & Configuration</CENTER></FONT></STRONG></HTML>
+CDM.PlugInManager.Parsing.Message:Design tool is loading plugin information.
+CDM.PlugInManager.Parsing.Title:Loading Plugins
+CDM.SearchTypeManager.Add:Add Search Type
+CDM.SearchTypeManager.Add_Tooltip:Allow the specified type of searching with this collection
+CDM.SearchTypeManager.Assigned:Currently Assigned Search Types
+CDM.SearchTypeManager.BuildType_Selection:Indexer:
+CDM.SearchTypeManager.BuildType_Selection_Tooltip:Select the indexer to be used for this collection.
+CDM.SearchTypeManager.Enable:Enable Advanced Searches
+CDM.SearchTypeManager.Instructions:Defining the search type is an advanced feature only available when enabled (by checking the 'Enable Advanced Searches' box). Once enabled further controls for selecting and changing the order of search types become available. Select a search type from the combobox and 'Add Search Type', if enabled, to add the search type. Select an existing search type from the list, and use 'Move Up' and 'Move Down' to change the order, or 'Remove Search Type' to remove it.\n\nThe search types specify what kind of search interface should be provided: form, for fields searching, and/or plain for regular searching. The ordering is important as the first one will be used for the initial search page by default.\n\nIt is also important to note that enabling search types causes the appearance of the Indexes view to change as well. Fielded searching is a newer feature of Greenstone, and thus requires different index information. When search types is enabled all current indexes are modified to be valid indexes under the new schema, while disabling search types will cause GLI to do its best to convert new indexes back into the old style but it may not always be successful, in which case the indexes will be removed. In either case a copy of the original index command line will be available as a comment in the configuration file. 
+CDM.SearchTypeManager.Remove:Remove Search Type
+CDM.SearchTypeManager.Remove_Tooltip:Do not allow the selected type of searching with this collection
+CDM.SearchTypeManager.SearchType:Search Type
+CDM.SearchTypeManager.SearchType_Selection:Search Types:
+CDM.SearchTypeManager.SearchType_Selection_Tooltip:The search types available for use with this collection
+CDM.SearchTypeManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Search Type Selection & Ordering</CENTER></FONT></STRONG></HTML>
+CDM.SubcollectionManager.Add:Add Filter
+CDM.SubcollectionManager.Add_Tooltip:Add the specified filter to the collection
+CDM.SubcollectionManager.Assigned:Defined Subcollection Filters
+CDM.SubcollectionManager.Exclude:Exclude
+CDM.SubcollectionManager.Flags:Flags to set when matching
+CDM.SubcollectionManager.Flags_Tooltip:Regular expression flags to use when matching (eg. "i" for case-insensitive matching)
+CDM.SubcollectionManager.Include:Include
+CDM.SubcollectionManager.Inclusive:What do we do with files that match?
+CDM.SubcollectionManager.Instructions:Use this panel to refine index creation.\ni)  Define subcollection filters, which screen the collection documents based on the specified metadata values. Once defined, you can then generate partitions on any previously specified index, based on one or more of these filters.\nii) Generate index partitions based on language. This filters the collection documents so that only those in the chosen language are included.\nNote that the total number of partitions generated is a combination of all indexes, subcollection filters and languages chosen. Two indexes with two subcollection filters in two languages would yield eight index partitions.
+CDM.SubcollectionManager.Language_Controls:Assign Languages
+CDM.SubcollectionManager.Match:Regular expression to match with: 
+CDM.SubcollectionManager.Match_Tooltip:A regular expression defining the documents in the subcollection
+CDM.SubcollectionManager.Name:Subcollection filter name:
+CDM.SubcollectionManager.Name_Tooltip:The name of the new subcollection filter
+CDM.SubcollectionManager.Partitions_Disabled:This facility is currently disabled because you are operating in {0-Current Mode} mode. It can only be accessed in {1-Systems} and {2-Expert} modes. Use File->Preferences to alter the mode of operation.
+CDM.SubcollectionManager.Remove:Remove Filter
+CDM.SubcollectionManager.Remove_Tooltip:Remove the selected filter from the list
+CDM.SubcollectionManager.Replace:Replace Filter
+CDM.SubcollectionManager.Replace_Tooltip:Update the details of the selected filter
+CDM.SubcollectionManager.Source:Document attribute to match against:
+CDM.SubcollectionManager.Source_Tooltip:The document attribute to filter on
+CDM.SubcollectionManager.Subcollection_Controls:Define Filters
+CDM.SubcollectionManager.Subindex_Controls:Assign Partitions
+CDM.SubcollectionManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Partition Indexes</CENTER></FONT></STRONG></HTML>
+CDM.SubcollectionIndexManager.Add_Subindex:Add Partition
+CDM.SubcollectionIndexManager.Add_Subindex_Tooltip:Add the specified partition to this collection
+CDM.SubcollectionIndexManager.Default_Partition_Indicator:[Default Partition]
+CDM.SubcollectionIndexManager.PartitionName:Partition Name:
+CDM.SubcollectionIndexManager.PartitionName_Tooltip:The name of the new partition
+CDM.SubcollectionIndexManager.Remove_Subindex:Remove Partition
+CDM.SubcollectionIndexManager.Remove_Subindex_Tooltip:Remove the selected partition from this collection
+CDM.SubcollectionIndexManager.Replace_Subindex:Replace Partition
+CDM.SubcollectionIndexManager.Replace_Subindex_Tooltip:Update the selected partition
+CDM.SubcollectionIndexManager.Set_Default_Subindex:Set Default
+CDM.SubcollectionIndexManager.Set_Default_Subindex_Tooltip:Make the selected partition the default
+CDM.SubcollectionIndexManager.Source:Build partition on:
+CDM.SubcollectionIndexManager.Source_Tooltip:The subcollection filters to build the partition on
+CDM.SubcollectionIndexManager.Subindexes:Assigned Subcollection Partitions
+CDM.SuperCollectionManager.Instructions:Cross-collection searching is where a single search is performed over several collections, as if all the collections were one. Specify the collections to include in a search by clicking on the appropriate collection's name in the list below. The current collection will automatically be included. \nWARNING: If the individual collections do not have the same indexes (including subcollection partitions and language partitions) as each other, cross-collection searching will not work properly. The user will only be able to search using indexes common to all collections.
+CDM.SuperCollectionManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Cross-Collection Search Configuration</CENTER></FONT></STRONG></HTML>
+CDM.TranslationManager.Add:Add Translation
+CDM.TranslationManager.Add_Tooltip:Add the specified translation to the collection
+CDM.TranslationManager.Affected_Features:Features
+CDM.TranslationManager.Assigned_Fragments:Assigned Translations
+CDM.TranslationManager.Default_Text:Initial Text Fragment
+CDM.TranslationManager.Fragment_Column:Text Fragment
+CDM.TranslationManager.Instructions:Use this view to review and assign translations of text fragments in your collection. First, select an entry from the list of features (e.g. collection level metadata and classifier names). Next, select and edit a text fragment, or select a language from the combobox in order to add a new fragment. Type the text into the white text area, referring to the initial text fragment as necessary. Any changes will appear immediately in the collection.
+CDM.TranslationManager.Language:Language of translation:
+CDM.TranslationManager.Language_Column:Language
+CDM.TranslationManager.Language_Tooltip:The language being translated into
+CDM.TranslationManager.Remove:Remove Translation
+CDM.TranslationManager.Remove_Tooltip:Remove the selected translation from the collection
+CDM.TranslationManager.Replace:Replace Translation
+CDM.TranslationManager.Replace_Tooltip:Update the selected translation
+CDM.TranslationManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Text Translation</CENTER></FONT></STRONG></HTML>
+CDM.TranslationManager.Translation:Translated Text
+CDM.TranslationManager.Translation_Tooltip:Enter the translation of the string here
+#*******************
+#
+#***** Collection *****
+Collection.Collection:<HTML><STRONG><FONT FACE={FONT} COLOR=Black>Collection</FONT></STRONG></HTML>
+Collection.Delete_Tooltip:Delete selected files and folders
+Collection.Filter_Tooltip:Restrict the files shown in the file tree
+Collection.New_Folder_Tooltip:Create a new folder
+Collection.No_Collection:No Collection
+Collection.Stop:Stop
+Collection.Stop_Tooltip:Stop copying files
+Collection.Workspace:<HTML><STRONG><FONT FACE={FONT} COLOR=Black>Workspace</FONT></STRONG></HTML>
+#**********************
+#
+#***** CollectionBuilt *****
+CollectionBuilt.Message:The collection has been built and is ready for previewing.
+CollectionBuilt.Title:Collection Creation Result
+#***************************
+#
+#***** CollectionManager *****
+CollectionManager.Build_Cancelled:Building the collection has been cancelled.
+CollectionManager.Cannot_Create_Collection:An error has occurred and the collection could not be created.
+CollectionManager.Cannot_Create_Collection_With_Reason:The collection could not be created because:\n{0-Error message}
+CollectionManager.Cannot_Delete_Index:This collection cannot be rebuilt because the old index files cannot be deleted.\nPlease make sure that Greenstone or some other program is not using these files,\n and try again.
+CollectionManager.Cannot_Delete_Index_Log:Old index files unable to be deleted so importing stopped.
+CollectionManager.Cannot_Open:The collection at:\n{0-Collection file path}\ncannot be opened.
+CollectionManager.Cannot_Open_With_Reason:The collection at:\n{0-Collection file path}\ncannot be opened because:\n{1-Error message}
+CollectionManager.Creating_New:Creating a new collection.
+CollectionManager.Log_Created:The log folder created.
+CollectionManager.Loading_Collection:Loading collection
+CollectionManager.Loading_Collection_Please_Wait:Loading collection, please wait...
+CollectionManager.Loading_Successful:Loaded collection {0}.
+CollectionManager.Missing_Config:This collection does not have a valid collect.cfg file 
+CollectionManager.Not_Col_File:'{0}' is not a Librarian Interface Collection File (.col)
+CollectionManager.No_Config_File:The collect.cfg file has not been created by mkcol.pl.
+CollectionManager.Preview_Ready_Failed:An error has occurred which will prevent the collection being previewed.
+CollectionManager.Preview_Ready_Title:Collection Preview State.
+CollectionManager.Session_Ready:Collection {0} ready for use.
+#*****************************
+#
+#***** CollectionPopupMenu *****
+CollectionPopupMenu.Delete:Delete
+CollectionPopupMenu.New_Dummy_Doc:New dummy document
+CollectionPopupMenu.New_Folder:New folder
+#*******************************
+#
+#***** CreatePane *****
+CreatePane.Build:Build Options
+CreatePane.Build_Tooltip:Options for the indexing and classification stage of collection formation
+CreatePane.Build_Collection:Build Collection
+CreatePane.Build_Collection_Tooltip:Start the collection formation process
+CreatePane.Build_Progress:Build Progress
+CreatePane.Cancel_Build:Cancel Build
+CreatePane.Cancel_Build_Tooltip:Stop the collection formation process
+CreatePane.Full_Build:Complete Rebuild
+CreatePane.Full_Build_Tooltip:Completely rebuild the collection from scratch
+CreatePane.Import:Import Options
+CreatePane.Import_Tooltip:Options for the file conversion and metadata assignment stage of collection formation
+CreatePane.Import_Progress:Import Progress
+CreatePane.Incremental_Build:Incremental Rebuild
+CreatePane.Incremental_Build_Tooltip:Faster, as only the parts of the collection building process that are necessary are performed
+CreatePane.Log:Message Log
+CreatePane.Log_Tooltip:View output from previous collection formation attempts
+CreatePane.Mode_All:all
+CreatePane.Options:Option Groups
+CreatePane.Options_Title:Collection Import & Build Options
+CreatePane.Preview_Collection:Preview Collection
+CreatePane.Preview_Collection_Tooltip:Preview the built collection
+#**********************
+#
+#***** Dates *****
+Dates.Mon:Monday
+Dates.Tue:Tuesday
+Dates.Wed:Wednesday
+Dates.Thu:Thursday
+Dates.Fri:Friday
+Dates.Sat:Saturday
+Dates.Sun:Sunday
+Dates.Jan:January
+Dates.Feb:February
+Dates.Mar:March
+Dates.Apr:April
+Dates.May:May
+Dates.Jun:June
+Dates.Jul:July
+Dates.Aug:August
+Dates.Sep:September
+Dates.Oct:October
+Dates.Nov:November
+Dates.Dec:December
+#**********************
+#
+#***** Delete Collection Prompt *****
+DeleteCollectionPrompt.Collection_Details:Selected collection's details
+DeleteCollectionPrompt.Collection_List:Available collections
+DeleteCollectionPrompt.Confirm_Delete:Please tick the box to confirm collection deletion.
+DeleteCollectionPrompt.Delete:Delete
+DeleteCollectionPrompt.Delete_Tooltip:Delete the selected collection
+DeleteCollectionPrompt.Details:Creator - {0}\nMaintainer - {1}\nDescription\n{2}
+DeleteCollectionPrompt.Failed_Delete:Collection could not be completely deleted.
+DeleteCollectionPrompt.Failed_Title:Deletion Failed!
+DeleteCollectionPrompt.No_Collection:No collection selected.
+DeleteCollectionPrompt.Successful_Delete:Collection has been deleted.
+DeleteCollectionPrompt.Successful_Title:Deletion Complete!
+DeleteCollectionPrompt.Title:Collection Deletion
+#**********************
+#
+#***** DirectoryLevelMetadata *****
+DirectoryLevelMetadata.Message:You are about to assign 'folder level' metadata to the selected folder (or folders). Such metadata will be automatically inherited by all files and folders in this folder. Furthermore this metadata cannot be removed from specific children, only replaced. To continue with this action click 'OK'.
+DirectoryLevelMetadata.Title:About to add folder level metadata
+#********************
+#
+#***** EnrichPane *****
+EnrichPane.Accumulate:Append
+EnrichPane.Accumulate_Tooltip:Append this value to the selected metadata element
+EnrichPane.AutoMessage:This element, {0}, belongs to the Greenstone metadata set. This set represents metadata that can usually be extracted automatically. To check what {0} metadata can be extracted create the collection using the 'Create' tab.
+EnrichPane.ExistingValues:Existing values for {0}
+EnrichPane.Expand:...
+EnrichPane.Expand_Tooltip:Edit the value in a larger text box
+EnrichPane.InheritedMetadataSelected:This piece of metadata is inherited from a folder above it, and cannot be edited. You can visit the actual folder containing the metadata by clicking on the folder icon at the start of the row.
+EnrichPane.No_File:No File Selected
+EnrichPane.No_Metadata:No Metadata Available
+EnrichPane.No_Metadata_Element:<HTML><STRONG><FONT FACE={FONT} COLOR=Black>No Metadata Element Selected</FONT></STRONG></HTML>
+EnrichPane.Overwrite:Replace
+EnrichPane.Overwrite_Tooltip:Assign this value to the selected metadata element, replacing the current value
+EnrichPane.Remove:Remove
+EnrichPane.Remove_Tooltip:Remove this value from the selected metadata element
+EnrichPane.Value:Value
+EnrichPane.Value_Field_Tooltip:Value to assign to the selected metadata element
+EnrichPane.Value_Field_Tooltip_Uneditable:Value assigned to the selected metadata element
+#***********************
+#
+#****** ExplodeMetadataPrompt *******
+ExplodeMetadataPrompt.Explode:Explode
+ExplodeMetadataPrompt.Explode_Tooltip:Explode the metadata file 
+ExplodeMetadataPrompt.Instructions:Exploding this metadata file will produce individual records with editable metadata. This is an irreversible process and the original metadata file will be removed from the collection.
+ExplodeMetadataPrompt.Failed_Title:Exploding Failed.
+ExplodeMetadataPrompt.Failed_Explode:The database {0} could not be exploded.
+ExplodeMetadataPrompt.NotExplodable:This file is not explodable.
+ExplodeMetadataPrompt.Successful_Explode:Database {0} successfully exploded.
+ExplodeMetadataPrompt.Successful_Title:Exploding Complete.
+ExplodeMetadataPrompt.Title:Explode Metadata Database
+#***********************
+#
+#****** WriteCDImagePrompt *******
+WriteCDImagePrompt.CD_Name:CD/DVD name
+WriteCDImagePrompt.Export:Write CD/DVD image
+WriteCDImagePrompt.Export_Tooltip:Write the selected collections as a Windows CD/DVD Image
+WriteCDImagePrompt.Failed_Export:The collections ({0}) could not be exported.
+WriteCDImagePrompt.Failed_Title:Export Failed
+WriteCDImagePrompt.Instructions:Export one or more collections to a self-installing Windows CD/DVD (although this works on any platform, the CD/DVD that is created only runs under Windows).
+WriteCDImagePrompt.Progress_Label:Copying Files. This could take some time...
+WriteCDImagePrompt.Successful_Export:The collections ({0}) have been exported.
+WriteCDImagePrompt.Successful_Title:Export Complete
+WriteCDImagePrompt.Title:Export Collection to CD/DVD
+#************************
+#
+#****** ExportAsPrompt *******
+ExportAsPrompt.Export_Name:Export directory name
+ExportAsPrompt.Export:Export collection(s)
+ExportAsPrompt.Export_Tooltip:Export the selected collections in the chosen file format into the designated directory
+ExportAsPrompt.Failed_ExportOne:The collection, {0}, could not be exported.
+ExportAsPrompt.Failed_ExportMany:The collections -- {0} -- could not be exported.
+ExportAsPrompt.Failed_Details:See {1} for details
+ExportAsPrompt.Failed_Title:Export Failed
+ExportAsPrompt.Instructions:Export one or more collections in the chosen format to into the stipulated directory
+ExportAsPrompt.Progress_Label:Exporting Files. This could take some time...
+ExportAsPrompt.Successful_ExportOne:The collection, {0}, has been exported.
+ExportAsPrompt.Successful_ExportMany:The collections -- {0} -- have been exported.
+ExportAsPrompt.Successful_Details:Files exported to: {1}
+ExportAsPrompt.Successful_Title:Export Complete
+ExportAsPrompt.Title:Export Collections
+ExportAsPrompt.SaveAs:Export to
+ExportAsPrompt.SaveAs_Tooltip:Select the format you want to export to
+#************************
+#
+#*****ExternalCollectionPrompt********
+ExternalCollectionPrompt.NewMDS:Create a new, empty metadata set.
+ExternalCollectionPrompt.ExistingMDS:Choose one or more existing metadata sets
+ExternalCollectionPrompt.Title:Load external collection
+ExternalCollectionPrompt.Instructions_1:You are about to load a collection that has not been created by the GLI. You will be asked to select one or more metadata sets to use for this collection. Existing metadata will be imported into the selected set(s). Original metadata files will be saved in a folder called import.bak.
+ExternalCollectionPrompt.Instructions_2:You are about to load a collection that has not been created by the GLI. You need to add a metadata set to this collection. You can create a new empty metadata set to which all the metadata elements found in the collection will be automatically added. Alternatively, you can select existing metadata sets, and elements from the collection will be merged with or added to the elements already in those sets. Original metadata files will be saved in a folder called import.bak.
+#****************************************
+#
+#***** Inherited Metadata *****
+ExtractedMetadata.Message:The selected file or folder contains extracted metadata, but it is currently hidden. To view extracted metadata go to the "[F]ile" menu and select "[P]references". In the "General" properties sheet select "View Extracted Metadata", then click "[O]k".
+ExtractedMetadata.Title:This File/Folder Has Hidden Extracted Metadata
+#
+#***** FileActions *****
+FileActions.Calculating_Size:Calculating total size of selected files
+FileActions.Copying:Copying {0}
+FileActions.Deleting:Deleting {0}
+FileActions.Directories_Selected:{0} folders selected
+FileActions.Directory_Exists:<html>The folder<br>{0}<br>already exists within the collection. Files will be copied into it.</html>
+FileActions.Directory_Selected:1 folder selected
+FileActions.File_Already_Exists_No_Create:The file '{0}' already exists. 
+FileActions.File_Already_Exists_Message:{0}\nA file with the name shown above already exists at the\ndestination, and despite your previous choice the Librarian Interface\nis unable to overwrite it. Please check file permissions.
+FileActions.File_Already_Exists_Title:Error - File Already Exists.
+FileActions.File_And_Directories_Selected:1 file and {0} folders selected
+FileActions.File_And_Directory_Selected:1 file and 1 folder selected
+FileActions.File_Create_Error:The file {0} could not be created.
+FileActions.Folder_Create_Error:The folder {0} could not be created.
+FileActions.File_Exists:<html>{0} already exists in the destination folder. Overwrite it?</html>
+FileActions.File_Not_Found_Message:{0}\nThe file named above can not be found. Once file view\nhas refreshed, please check the file still exists.
+FileActions.File_Not_Found_Title:Error - File Not Found.
+FileActions.File_Selected:1 file selected
+FileActions.Files_And_Directory_Selected:{0} files and 1 folder selected
+FileActions.Files_Selected:{0} files selected
+FileActions.Folder_Already_Exists:The folder name '{0}' is already in use. Cannot create folder.
+FileActions.Increase_Depth:Increase Depth by 1
+FileActions.Insufficient_Space_Message:The file action has failed because of insufficient disk\nspace. For the file to copy successfully you require a\nfurther: {0}
+FileActions.Insufficient_Space_Title:Error - Insufficient Space
+FileActions.Moving:Moving {0}
+FileActions.No_Activity:No action requested
+FileActions.Possible_Cyclic_Path:{1} is {0} directories deep and may be a recursive path? Should file actioning continue?
+FileActions.Read_Only:Files from the workspace are read only and cannot be deleted.
+FileActions.Selected:{0} files and {1} folders selected
+FileActions.Unknown_File_Error_Message:Although no error message was reported during the file\naction, a final check has shown that the destination\ncopy is not the same as the source file. The reason\nfor this is unknown. Please check your media and update\nyour installed JVM.
+FileActions.Unknown_File_Error_Title:Error - Unknown File Error
+FileActions.Write_Not_Permitted_Message:The Librarian Interface does not have permission to write to\n{0}\nPlease check file permissions.
+FileActions.Write_Not_Permitted_Title:Error - Incorrect File Permissions
+FileActions.Yes_To_All:Yes to All
+#************************
+#
+#******* File Associations dialog **********
+FileAssociationDialog.Add:Add
+FileAssociationDialog.Add_Tooltip:Use this application to view files of this type
+FileAssociationDialog.Batch_File:Batch files
+FileAssociationDialog.Browse:Browse
+FileAssociationDialog.Browse_Tooltip:Choose the application to use from your filespace
+FileAssociationDialog.Browse_Tooltip_Mac:Browsing for your application is currently disabled for MacOS
+FileAssociationDialog.Browse_Title:Choose Application
+FileAssociationDialog.Close:Close
+FileAssociationDialog.Close_Tooltip:Close this dialog and return to the main window
+FileAssociationDialog.Command:Launch command:
+FileAssociationDialog.Command_File:Command files
+FileAssociationDialog.Command_Tooltip:Enter the command to launch the application to use
+FileAssociationDialog.Details:New File Association Details
+FileAssociationDialog.Executable_File:Executable files
+FileAssociationDialog.Existing_Associations:Current File Associations
+FileAssociationDialog.Extension:For files ending:
+FileAssociationDialog.Extension_Tooltip:The file extension of the files to view
+FileAssociationDialog.Instructions:Use this dialog to set what external programs are used to view a certain file-type, and what command is sent to launch this program.\nTo add a new file-type, type its extension in 'For files ending'. To add or modify a launch command, type the new command in 'Launch command' or click 'Browse' to search the file system for an appropriate program. Use the special string '%1' to indicate where the name of the file to be opened should be inserted, e.g. "C:\\Windows\\System\\MSPaint.exe %1". '%1' will be appended to the end of a command if not otherwise specified.\nMacOS users should always try the mac specific command "open [-a <application_name>] %1" first.
+FileAssociationDialog.Table.Command:Command
+FileAssociationDialog.Table.Extension:Extension
+FileAssociationDialog.Title:Edit File Associations
+FileAssociationDialog.Remove:Remove
+FileAssociationDialog.Remove_Tooltip:Remove the current selected association from the existing associations
+FileAssociationDialog.Replace:Replace
+FileAssociationDialog.Replace_Tooltip:Replace the currently selected association with the new association details
+#*******************
+#
+#******Filter***************
+Filter.0:HTM & HTML
+Filter.1:XML
+Filter.2:Text Files
+Filter.3:Images
+Filter.All_Files:All Files
+Filter.Filter_Tree:Show Files
+Filter.Invalid_Pattern:<HTML><FONT FACE={FONT} COLOR=Black>The pattern you have entered for filtering files is invalid.<BR>Please try again using regular expression syntax and with<BR>* for the wildcard character.</FONT></HTML>
+#***********************
+#
+#***** GAuthenticator *****
+GAuthenticator.Password:Password:
+GAuthenticator.Password_Tooltip:Enter your password here
+GAuthenticator.Title:Password Required.
+GAuthenticator.Username:User Name:
+GAuthenticator.Username_Tooltip:Enter your username here
+#**************************
+#
+#***** General Messages *****
+# 0 - A String representing the name and method of the class in question.
+General.Apply:Apply
+General.Apply_Tooltip:Apply the current settings but do not exit the dialog
+General.Browse:Browse...
+General.Cancel:Cancel
+General.Cancel_Tooltip:Cancel the changes (will not undo any that have been applied already)
+General.Close:Close
+General.Close_Tooltip:Close this dialog box
+General.Edit:Edit Value
+General.Error:Error
+General.No:No
+General.NotSunJava:Java vendor: {0}\nNote that the Librarian Interface has been developed and tested with Java from Sun Microsystems. 
+General.OK:OK
+General.OK_Tooltip:Accept the current settings and exit the dialog
+General.Open:Open
+General.Outstanding_Processes:<html>The Librarian Interface cannot close completely until all programs<br>started within The Librarian Interface have also exited.</html>
+General.Outstanding_Processes_Title:Waiting To Exit
+General.Pure_Cancel_Tooltip:Abort this action (no changes will be made)
+General.Review_Output:Please review output below:
+General.Usage:Usage: {0} <params>\nAll parameters are optional but the Librarian Interface may fail to work if -gsdl and -library aren't set.\n -gsdl <path>  : Force path to gsdl\n -library <path> : Path to cgi-bin\n -mozilla <path> : Enabled mozilla\n -mirror : Enable web-mirroring controls\n -laf [java|windows|motif|mac] : Look and feel\n -debug : Enable debug messages\n -no_load : Don't load previously open collection\n -load <path> : Load the specified collection
+General.View:View Value
+General.Warning:Warning
+General.Yes:Yes
+#****************************
+#
+#***** GShell *****
+GShell.Build.Auxilary:Creating auxiliary files and tidying up...
+GShell.Build.BuildBegun1:************** Build  Started **************
+GShell.Build.BuildCancelled:**************   Cancelled    **************
+GShell.Build.BuildComplete1:************** Build Finished **************
+GShell.Build.CompressText:Compressing text...
+GShell.Build.Index:Creating an index based on {0-index source and level}...
+GShell.Build.InfoDatabase:Creating information database...
+GShell.Build.Phind:Generating a Phind classifier. This may take some time...
+GShell.Command:Command
+GShell.Failure:Command failed.
+GShell.Import.FileNotProcessed:The file {0-target file path} was recognised but could not be processed by any plugin.
+GShell.Import.FileNotRecognised:The file {0-target file path} was not recognised by any plugin.
+GShell.Import.FileProcessing:The file {0-target file path} is being processed by {1-plugin name}.
+GShell.Import.FileProcessingError:The file {0-target file path} encountered an error during processing.
+GShell.Import.ImportBegun1:************** Import  Started **************
+GShell.Import.ImportComplete1:************** Import Finished **************
+GShell.Import.ImportComplete2:{0-number documents considered} documents were considered for processing:
+GShell.Import.ImportComplete2.1:1 document was considered for processing:
+GShell.Import.ImportComplete.Processed:{0-number processed} documents were processed and included in the collection. 
+GShell.Import.ImportComplete.Processed.1:1 document was processed and included in the collection. 
+GShell.Import.ImportComplete.Blocked:{0-number blocked} were prevented from being added by plugins (such as images in web pages).
+GShell.Import.ImportComplete.Blocked.1:1 was prevented from being added by plugins (such as images in web pages).
+GShell.Import.ImportComplete.Ignored:{0-number ignored} were unrecognised.
+GShell.Import.ImportComplete.Ignored.1:1 was unrecognised.
+GShell.Import.ImportComplete.Failed:{0-number failed} were rejected.
+GShell.Import.ImportComplete.Failed.1:1 was rejected.
+GShell.Import.ImportComplete3:\n
+GShell.Parsing_Metadata_Complete:Archived metadata extraction complete.
+GShell.Parsing_Metadata_Start:Extracting new metadata from archive files.
+GShell.Success:Command complete.
+#*********************
+#
+#***** GUI *****
+# Currently Enabled and Disabled display the same text but in different
+# colours. If necessary this can be changed.
+GUI.Create:Create
+GUI.Create_Tooltip:Build your collection using Greenstone
+GUI.Design:Design
+GUI.Design_Tooltip:Design the functionality and appearance of your collection
+GUI.Download:Download
+GUI.Download_Tooltip:Download resources from the internet for your collection
+GUI.Enrich:Enrich
+GUI.Enrich_Tooltip:Assign metadata to the files in your collection
+GUI.Gather:Gather
+GUI.Gather_Tooltip:Select the files to include in your collection
+#***************
+#
+#***** HELP *****
+Help.Contents:Contents
+Help.Title:Librarian Interface Help Pages
+#
+#***** LockFileDialog *****
+LockFileDialog.Cancel_Tooltip:Do not steal control of the lock file (collection will not open)
+LockFileDialog.Date:Date
+LockFileDialog.Error:#error
+LockFileDialog.Lockfile_Message_One:The presence of a lock file suggests this collection is already open.
+LockFileDialog.Lockfile_Message_Two:Do you wish to 'steal' control of this lock file?
+LockFileDialog.Machine:Where
+LockFileDialog.Name:Name
+LockFileDialog.OK_Tooltip:Steal control of the lock file
+LockFileDialog.Title:Lock File Detected
+LockFileDialog.User:Who
+#********************
+#
+#*****MappingPrompt **********
+MappingPrompt.File:Folder
+MappingPrompt.Map:Create Shortcut
+MappingPrompt.Name:Name
+MappingPrompt.Title:Set Folder Shortcut
+MappingPrompt.Unmap:Remove Shortcut
+#*******************
+#
+#***** Menu Options *****
+Menu.Collapse:Close Folder
+Menu.Edit:Edit
+Menu.Edit_Copy:Copy (ctrl-c)
+Menu.Edit_Cut:Cut (ctrl-x)
+Menu.Edit_Paste:Paste (ctrl-v)
+Menu.Expand:Open Folder
+Menu.Explode_Metadata_Database:Explode metadata database
+Menu.File:File
+Menu.File_Associations:File Associations...
+Menu.File_CDimage:Write CD/DVD image...
+Menu.File_Close:Close
+Menu.File_Delete:Delete...
+Menu.File_Exit:Exit
+Menu.File_ExportAs:Export...
+Menu.File_New:New...
+Menu.File_Open:Open...
+Menu.File_Options:Preferences...
+Menu.File_Save:Save
+Menu.Help:Help
+Menu.Help_About:About...
+Menu.Metadata_View:Assigned Metadata for the {0}
+Menu.Open_Externally:Open in external program
+#********************
+#
+#***** MetaAudit *****
+MetaAudit.Close:Close
+MetaAudit.Close_Tooltip:Close this dialog box
+MetaAudit.Title:All Metadata
+#*********************
+#
+#***** Metadata *****
+Metadata.Element:Element
+Metadata.Value:Value
+MetadataSet.Files:Metadata Set Files
+#*********************************************
+#
+#******** MetadataImportMappingPrompt *********
+MIMP.Add:Add
+MIMP.Add_Tooltip:Add the metadata element to the selected set
+MIMP.Ignore:Ignore
+MIMP.Ignore_Tooltip:Ignore this metadata element
+MIMP.Instructions:The metadata element {0} cannot be automatically imported into the collection. Select a metadata set and either:\n(1) press 'Add' to add the metadata to that set (only if there is not already {0} metadata in the set), or\n(2) choose an element and press 'Merge' to import {0} metadata to this element, or\n(3) ignore this metadata element.
+MIMP.Merge:Merge
+MIMP.Merge_Tooltip:Map the metadata element to the specified element in the selected set
+MIMP.Source_Element:Source metadata element:
+MIMP.Target_Element:Target metadata element:
+MIMP.Target_Set:Target metadata set:
+MIMP.Title:Merging Action Required.
+#*****************************
+#
+#***** Mirroring *****
+Mirroring.ClearCache:Clear Cache
+Mirroring.ClearCache_Tooltip:Delete all downloaded files
+Mirroring.Download:Download
+Mirroring.Download_Tooltip:Start a new download job
+Mirroring.Download_Controls:Download Settings
+Mirroring.Download_Depth:Download Depth:
+Mirroring.Download_Depth.Zero:Zero
+Mirroring.Download_Depth.Unlimited:Unlimited
+Mirroring.Download_Depth_Tooltip:How many hyperlinks deep to go when downloading
+Mirroring.Download_Embedded:Download text only (no images, stylesheets etc)
+Mirroring.DownloadJob.Close:Close
+Mirroring.DownloadJob.Close_Tooltip:Remove this job from the list, stopping it if it is currently running
+Mirroring.DownloadJob.Downloading:Downloading {0}
+Mirroring.DownloadJob.Download_Complete:Download complete
+Mirroring.DownloadJob.Download_Stopped:Download halted
+Mirroring.DownloadJob.Download_Progress:Downloading in progress
+Mirroring.DownloadJob.Log:View Log
+Mirroring.DownloadJob.Log_Tooltip:View details about this download
+Mirroring.DownloadJob.Pause:Pause
+Mirroring.DownloadJob.Pause_Tooltip:Pause this download
+Mirroring.DownloadJob.Resume:Resume
+Mirroring.DownloadJob.Resume_Tooltip:Resume this download
+Mirroring.DownloadJob.Status:Downloaded {0} of {1} files ({2} warnings, {3} errors)
+Mirroring.DownloadJob.Waiting:Waiting to start
+Mirroring.DownloadJob.Waiting_User:Waiting for user action
+Mirroring.Higher_Directories:Only mirror files below this URL
+Mirroring.Invalid_URL:The URL entered is not valid. Please correct.
+Mirroring.Invalid_URL_Title:Invalid URL
+Mirroring.Preferences:Preferences...
+Mirroring.Preferences_Tooltip:Enable proxy and/or edit proxy settings
+Mirroring.Same_Host:Only mirror files within the same site
+Mirroring.Source_URL:Source URL:
+Mirroring.Source_URL_Tooltip:URL to download
+#*********************
+#
+#***** Missing EXEC *****
+MissingEXEC.Message:Warning! You will not be able to view your new collections within the Librarian Interface unless you specify the path to the locally running Greenstone Library Webserver. You can enter this now in the text field below, or later by going to Preferences and choosing the Connection tab. Remember that a valid url must start with the protocol "http://", and will probably end with the executable name ("gsdl" for Greenstone local library server, "library" for other web servers).
+MissingEXEC.Title:Missing Greenstone Library Address
+#***** Missing EXEC_GS3 *****
+MissingEXEC_GS3.Message:Warning! You will not be able to view your new collections within the Librarian Interface unless you specify the path to the Greenstone context in the locally running Tomcat Webserver. You can enter this now in the text field below, or later by going to Preferences and choosing the Connection tab. Remember that a valid url must start with the protocol "http://". The default address is http://localhost:8080/gsdl3.
+MissingEXEC_GS3.Title:Missing Greenstone Library Address
+#***** Missing GSDL *****
+MissingGSDL.Message:Warning! You will not be able to access all of the Librarian Interface's features without a local copy of Greenstone Digital Library also installed. If you believe you are receiving this message in error please check your installation, and the paths specified in Librarian Interface batch or script file.
+MissingGSDL.Title:Missing Greenstone Path
+#***** Missing PERL *****
+MissingPERL.Message:Warning! You will not be able to create new collections, nor build existing ones, without PERL installed, and the Librarian Interface was unable to find PERL on your system. If you believe you are receiving this message in error please check your installation, and the paths specified in Librarian Interface batch or script file.
+MissingPERL.Title:Missing PERL Path
+#******* MissingWGET ********
+MissingWGET.Message:Warning! Web mirroring is disabled because the Librarian Interface failed to locate an appropriate version of WGet. If you believe you are receiving this message in error please check your installation and the paths specified in the Librarian Interface batch or script file.
+MissingWGET.Title:Missing WGet
+#******* MissingImageMagick ********
+MissingImageMagick.Message:Warning! The Librarian Interface failed to locate an appropriate version of ImageMagick, and consequently ImagePlug will not work. Please install ImageMagick if you wish to build image collections.
+MissingImageMagick.Title:Missing ImageMagick
+#*****************************
+#
+#***** New Session *****
+NewCollectionPrompt.Base_Collection:Base this collection on:
+NewCollectionPrompt.Base_Collection_Tooltip:Select an existing collection to base the new collection on
+NewCollectionPrompt.Collection_Description:Description of content:
+#NewCollectionPrompt.Collection_Email:Author's Email:
+NewCollectionPrompt.Collection_Name:Collection folder:
+#NewCollectionPrompt.Collection_Name_Tooltip:Short collection name, used internally (must be 8 characters or less)
+NewCollectionPrompt.Description_Error:The description field must be filled out. Please correct.
+NewCollectionPrompt.Error:Error in new collection.
+NewCollectionPrompt.Instructions:To create a new collection fill out the fields below.
+NewCollectionPrompt.Metadata_Elements:Elements within selected set:
+NewCollectionPrompt.Metadata_Instructions1:Check the boxes beside the metadata sets to include in your collection.
+NewCollectionPrompt.Metadata_Instructions2:(Note: You can add new ones later).
+NewCollectionPrompt.Metadata_Title_Existing:Select metadata sets.
+#NewCollectionPrompt.Name_Error:You have either failed to enter a name for the collection, or the name you have choosen is already in use. Please correct.
+NewCollectionPrompt.NewCollection:-- New Collection --
+NewCollectionPrompt.Select_MDS:Available metadata sets:
+NewCollectionPrompt.Title:Create a new Collection.
+NewCollectionPrompt.Title_Clash:The title you have chosen for your collection is already in use. Continue?
+NewCollectionPrompt.Title_Error:The title field must be filled out. Please correct.
+#***** New Folder OrFilePrompt *****
+NewFolderOrFilePrompt.Default_File_Name:dummy
+NewFolderOrFilePrompt.Default_Folder_Name:new folder
+NewFolderOrFilePrompt.Destination_Name:Destination Folder
+NewFolderOrFilePrompt.File_Name:File Name
+NewFolderOrFilePrompt.File_Name_Tooltip:Enter a name for the new file
+NewFolderOrFilePrompt.Folder_Name:Folder Name
+NewFolderOrFilePrompt.Folder_Name_Tooltip:Enter a name for the new folder
+NewFolderOrFilePrompt.Title_Folder:Create a new folder
+NewFolderOrFilePrompt.Title_File:Create a new dummy document
+#***********************
+#
+NoMetadataSetsSelected.Message:If you create the collection now it will have no initial metadata sets. You will not be able to import nor assign any metadata until a set is imported or added to your collection. Do you wish to continue?
+NoMetadataSetsSelected.Title:No Metadata Sets Selected
+#**********************
+#
+#******* OldWGET *******
+NoPluginExpectedToProcessFile.Message:None of Greenstone's plugins are expected to process the file "{0}". Check that the file has the correct extension. If it is correct then you may have to use UnknownPlug to process this file.
+NoPluginExpectedToProcessFile.Title:No plugin expected to process file
+#**********************
+#
+#******* OldWGET *******
+OldWGET.Message:Warning! The version of WGet you have installed has a known bug when mirroring files which contain encoded characters such as space and tilde in their URL. While this shouldn't be a problem, we recommend installing WGet 1.9 or higher.
+OldWGET.Title:Old WGet
+#***********************
+#
+#***** OpenCollectionDialog *****
+OpenCollectionDialog.Available_Collections:Available Collections
+OpenCollectionDialog.Browse:Browse
+OpenCollectionDialog.Browse_Tooltip:Choose a collection from your filespace
+OpenCollectionDialog.Collection:Greenstone Collection (".col")
+OpenCollectionDialog.Description:Collection Description
+OpenCollectionDialog.Locked_Collection:Greenstone collection already in use
+OpenCollectionDialog.No_Description:Please select a greenstone collection (".col" file) to see description.
+OpenCollectionDialog.Normal_Collection:Greenstone collection
+OpenCollectionDialog.Open:Open
+OpenCollectionDialog.Open_Tooltip:Load the selected collection into the Librarian Interface
+OpenCollectionDialog.Title:Open Greenstone Collection
+#**********************
+#
+#***** Options Pane inside CreatePane *****
+OptionsPane.Cancelled: - cancelled
+OptionsPane.LogHistory:Log history
+OptionsPane.Successful: - successful
+OptionsPane.Unknown: - unknown
+OptionsPane.Unsuccessful: - unsuccessful
+#*******************
+#
+#***** Preferences *****
+Preferences:Preferences
+Preferences.Connection:Connection
+Preferences.Connection_Tooltip:Set the URL to the greenstone library and configure a proxy connection if appropriate
+Preferences.Connection.Library_Path:Library Path:
+Preferences.Connection.Library_Path_GS3:Greenstone Web Path:
+Preferences.Connection.Library_Path_Tooltip:The URL of the Greenstone web-server
+Preferences.Connection.Library_Path_Tooltip_GS3:The URL of the Greenstone web-server
+Preferences.Connection.ProgramCommand:Preview Command:
+Preferences.Connection.ProgramCommand_Tooltip:The launch command for the program used to view the collection preview. Remember to use %1 as the placeholder for the collection address, and to use speechmarks where necessary.
+Preferences.Connection.Proxy_Host:Proxy Host:
+Preferences.Connection.Proxy_Host_Tooltip:The address of your proxy server
+Preferences.Connection.Proxy_Port:Proxy Port:
+Preferences.Connection.Proxy_Port_Tooltip:The port number of your proxy server
+Preferences.Connection.Servlet:Servlet:
+Preferences.Connection.Servlet_Tooltip:The servlet to use to view your site
+Preferences.Connection.Servlet_Tooltip2:There is no servlet specified for this site, you can still build collections, but you wont be able to view them
+Preferences.Connection.Site:Site:
+Preferences.Connection.Site_Tooltip:The site you want to work in
+Preferences.Connection.Use_Proxy:Use proxy connection?
+Preferences.General:General
+Preferences.General_Tooltip:Set some general preferences
+Preferences.General.Email:User's Email:
+Preferences.General.Email_Tooltip:The email address automatically used for any collection created with the GLI
+Preferences.General.Font:Font:
+Preferences.General.Font_Tooltip:The font used for the GLI interface.
+Preferences.General.Interface_Language:Interface Language:
+Preferences.General.Interface_Language_Tooltip:Select the language you wish the interface and its controls to be displayed in. 
+Preferences.General.Restart_Required:GLI should now be restarted in order to complete updating its interface.
+Preferences.General.Show_File_Size:Show file sizes
+Preferences.General.Show_File_Size_Tooltip:Show file sizes next to entries in the Workspace and Collection file trees.
+Preferences.General.View_Extracted_Metadata:View Extracted Metadata
+Preferences.General.View_Extracted_Metadata_Tooltip:Display metadata extracted by the greenstone plugins in the metadata list in the Enrich view.
+Preferences.Mode:Mode
+Preferences.Mode_Tooltip:Click on an entry to select a suitable level of operation
+Preferences.Mode.Assistant:Library Assistant
+Preferences.Mode.Assistant_Description:Use this setting to gain access to the basic features of the Greenstone Librarian Interface: adding documents and metadata to collections, creating new collections whose structure mirrors existing ones, and building collections.
+Preferences.Mode.Librarian:Librarian
+Preferences.Mode.Librarian_Description:This setting gives normal use of the Greenstone Librarian Interface: creating and designing new collections, adding documents and metadata to collections, designing new collections, and building collections.
+Preferences.Mode.Systems:Library Systems Specialist
+Preferences.Mode.Systems_Description: This setting enables full use of the Greenstone Librarian Interface. To take advantage of all the features available, you will need to be able to formulate regular expressions.
+Preferences.Mode.Expert:Expert
+Preferences.Mode.Expert_Description:This setting enables expert use of the Greenstone Librarian Interface. It is recommended for users who are experienced with Greenstone, and are able to perform troubleshooting tasks that involve interpreting debugging output from PERL scripts. All features of the Greenstone Librarian Interface are enabled.
+Preferences.Warnings:Warnings
+Preferences.Warnings_Tooltip:Enable or disable various warning dialogs
+Preferences.Workflow:Workflow
+Preferences.Workflow_Tooltip:Design the interface workflow: set which views should be enabled
+Preferences.Workflow.Create:Create - Build your collection using Greenstone 
+Preferences.Workflow.Design:Design - Change collection appearence
+Preferences.Workflow.Download:Download - Download web-based resources
+Preferences.Workflow.Enrich:Enrich - Annotate with metadata
+Preferences.Workflow.Gather:Gather - Select files for collection
+Preferences.Workflow.Predefined.Label:Predefined Workflows
+Preferences.Workflow.Title:Check box to enable view
+#**********************
+#
+#**** PreviewCommandDialog *******
+PreviewCommandDialog.Instructions:Enter the command for opening the program to view collection preview. Remember to use %1 as the placeholder for the collection address, and to use speechmarks where necessary.
+PreviewCommandDialog.Title:Preview Command
+#**********************
+#
+#***** Save Collection Box *****
+SaveCollectionBox.File_Name:File Name:
+SaveCollectionBox.Files_Of_Type:Files of Type:
+SaveCollectionBox.Look_In:Look In:
+#**********************
+#
+#***** Save Progress Box *******
+SaveProgressDialog.Title:Saving Collection
+#*******************************
+#
+Server.QuitManual:The Librarian Interface was unable to close the local\nlibrary server automatically. Please exit the server\nmanually by clicking on the cross icon in its top\nright-hand corner, then click OK on this dialog.
+Server.QuitTimeOut:The greenstone local library has not responded to the\nautomatic close command for sixty seconds. Do you\nwish to wait for another minute?
+#
+#***** Sources *****
+Source.General:General
+#*******************
+#
+#***** TitleClash *****
+TitleClashes.Message:The title you have chosen for your collection is already in use. Continue?
+TitleClashes.Title:Entered Title Clashes
+#**********************
+#
+#***** Trees *****
+Tree.DownloadedFiles:Downloaded Files
+Tree.Files:files
+Tree.Home:Home Folder ({0})
+Tree.Root:Local Filespace
+Tree.World:Documents in Greenstone Collections
+#***********************
+#
+#***** Warning Dialog *****
+WarningDialog.Dont_Show_Again:Do not show this warning again
+WarningDialog.Dont_Show_Again_Message:Do not show this message again
+WarningDialog.Invalid_Value:The value you have entered in the value field\nis not valid for the specified property.
+WarningDialog.Value:Enter value:
+#
+#****** WGet *****
+WGet.Prompt:WGet Mirroring Client
+#
+#****** Workflows *****
+Workflow.AllPanels:All panels
+Workflow.LocalSourceCollectionBuilding:Local source collection building
+Workflow.DocumentEnriching:Document enriching
+
+GEMS.Already_Loaded_Set_Error: The metadata set you selected is currently open.
+GEMS.Element_Already_Exists:An element with this name already exists.
+GEMS.Set_Already_Exists:A set with this namespace already exists.
+GEMS.Cannot_Delete_Core_Sets_Error:You cannot remove a core GLI metadata set.
+
+GEMS.Preferences.Selected_Languages_Tooltip: Selected languages to display:
+
+GEMS.Add_Attribute:Add attribute
+GEMS.Add_Attribute_Tooltip:Add a new attribute to the selected item
+GEMS.Add_Element:Add element
+GEMS.Add_Element_Tooltip:Add a new element to the selected set
+GEMS.Add_Subelement:Add subelement
+GEMS.Add_Subelement_Tooltip:Add a new subelement to the selected element
+GEMS.Add_Set:Add Set
+GEMS.Attribute:Attribute
+GEMS.Attribute_Already_Exists:This attribute already exists.
+GEMS.Attribute_Name_Tooltip:The name of the new attribute
+GEMS.Attribute_Language_Tooltip:The language of the new attribute
+GEMS.Attribute_Value_Tooltip:The value of the new attribute
+GEMS.Attributes:Attributes
+GEMS.Cannot_Undo:(this action cannot be undone)
+GEMS.Cannot_Add_Elements_To_Greenstone_MDS:You cannot manually add elements to the Greenstone Metadata. If\nnecessary create a new set, then add your new element to it instead.
+GEMS.Confirm_Exit_Save: Would you like to save before exiting?
+GEMS.Confirm_Exit_Save_Title: Save Before Exit?
+GEMS.Confirm_Removal:Are you sure you wish to remove this {0}?
+GEMS.Confirm_Removal_Title:Confirm Removal
+GEMS.Edit_Attribute:Edit Attribute
+GEMS.Edit_Value:Edit Value
+GEMS.Edit_Value_Tooltip:Change the selected value
+GEMS.Element:Element
+GEMS.Element_Name_Tooltip:The name of the new element
+GEMS.Element_Details:Metadata Element Details
+GEMS.Language:Language
+GEMS.Language_Code:Language
+GEMS.Name:Name
+GEMS.Namespace:Namespace
+GEMS.New_Name:New Name
+GEMS.No_Description:No description found.
+GEMS.No_Name:No name found.
+GEMS.Open_Set:Open Set
+GEMS.Remove_Attribute:Remove attribute
+GEMS.Remove_Attribute_Tooltip:Remove the selected attribute
+GEMS.Remove_Element:Remove element
+GEMS.Remove_Element_Tooltip:Remove the selected element from the set
+GEMS.Remove_Set:Remove set
+GEMS.Remove_Set_Tooltip:Remove the selected set
+GEMS.Rename_Element:Rename element
+GEMS.Rename_Element_Tooltip:The element's new name
+GEMS.Rename_Name_Tooltip:The metadata set's new name
+GEMS.Rename_Namespace_Tooltip:The metadata set's unique namespace
+GEMS.Rename_Set:Rename set
+GEMS.Rename_Set_Tooltip:Rename the metadata set
+GEMS.Set:Set
+GEMS.Set_Details:Metadata Set Details
+GEMS.Set_Name_Tooltip:The name of the new metadata set
+GEMS.Set_Namespace_Tooltip:A unique namespace for the new metadata set
+GEMS.Subelement_Name_Tooltip:The name of the new subelement
+GEMS.Subelement_Already_Exists:A subelement with this name already exists.
+GEMS.Target:Element
+GEMS.Title:Greenstone Editor for Metadata Sets
+GEMS.Value:Value
+GEMS.Values:Values
+GEMS.inheritMetadataSet:Inherit from Metadataset:
+GEMS.Add_Set.No_Inherit:Do not inherit
Index: /tags/gsdl-2_61-distribution/gli/classes/dictionary_es.properties
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/dictionary_es.properties	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/dictionary_es.properties	(revision 10506)
@@ -0,0 +1,1016 @@
+#*******************
+#
+#***** AboutDialog *****
+AboutDialog.Acknowledgement:Reconocimientos de marca de paquetes, clases y programas propietarios...
+AboutDialog.Date:(Agosto 2005)
+AboutDialog.Item0:Xerces Java 1' de The Apache Software Foundation (http://www.apache.org/)
+AboutDialog.Item2:WGet' de Free Software Foundation, Inc. (http://www.gnu.org/software/wget/wget.html)
+AboutDialog.Item3:qflib' de Quality First Software GmbH. (http://www.qfs.de/en/qflib/index.html)
+AboutDialog.Item4:ExtensionFileFilter.class', por Bruno Dumon y asociados (http://pollo.sourceforge.net/)
+AboutDialog.Item5:How to disable file renaming in file chooser' - vladi21 (http://www.experts-exchange.com/)
+AboutDialog.Item6:Autoscrolling' - Java Swing, por Robert Eckstein, Marc Loy & Dave Wood (http://www.oreilly.com/catalog/jswing/chapter/dnd.beta.pdf)
+AboutDialog.Item7:Add ghosted drag images to your JTrees', por Andrew J. Armstrong (http://www.javaworld.com/javaworld/javatips/jw-javatip114.html)
+AboutDialog.Item8:Stop annoying java.prefs error when you don't have superuser access', cortesÃ­a de Walter Schatz
+AboutDialog.Java_Req:Java es una marca registrada de Sun Microsystems Inc. El Ambiente de EjecuciÃ³n Java (JRE por sus siglas en inglÃ©s) se distribuye de acuerdo a los tÃ©rminos de la licencia suplementaria que se encuentra en http://java.sun.com/j2se/1.4.1/j2re-1_4_1_02-license.html
+AboutDialog.Java_Req_One:Este producto incluye un cÃ³digo con licencia de uso de RSA Security, Inc.
+AboutDialog.Java_Req_Two:Algunas partes con licencia de IBM estÃ¡n disponibles en http\://oss.software.ibm.com/icu4j/
+AboutDialog.Thanks:TambiÃ©n queremos agradecer a todos aquellos que nos proporcionaron su valiosa informaciÃ³n sobre Java a travÃ©s de la Web...
+AboutDialog.Title:Acerca de...
+AboutDialog.Title_One:Interfaz de la Biblioteca Digital Greenstone
+AboutDialog.Title_Two:Biblioteca Digital Greenstone, Universidad de Waikato
+AboutDialog.Copyright:Copyright (C) 2003 New Zealand Digital Library Project
+AboutDialog.Copyright_Two:Publicado conforme a los tÃ©rminos y condiciones de la Licencia PÃºblica General. Para mayor informaciÃ³n vea LICENSE.txt
+#***********************
+#
+#***** Audit Table *****
+AuditTable.File:Nombre del archivo
+#***********************
+#
+#***** Auto Filter *****
+Autofilter.AND:Y
+Autofilter.Ascending:Ascendente
+Autofilter.Case_Sensitive:Concordancia de caso
+Autofilter.Custom_Filter:Avanzada
+Autofilter.Descending:Descendente
+Autofilter.Filter_By_Value:Sencilla
+Autofilter.Name:TÃ­tulo de la columna
+Autofilter.None:Ninguno
+Autofilter.Operator:CondiciÃ³n
+Autofilter.OR:O
+Autofilter.Order:Ordenar
+Autofilter.Order_Tooltip:Clasifica los elementos en este orden
+Autofilter.Remove:Eliminar filtro
+Autofilter.Remove_Tooltip:Quita este filtro de la columna
+Autofilter.Set:Filtrar
+Autofilter.Set_Tooltip:AÃ±ade este filtro a la columna
+Autofilter.Table_Header_Tooltip:Filtrar por {0}
+Autofilter.Title:Filtrar metadatos
+Autofilter.eqeq:igual a
+Autofilter.!eq:does not equal
+Autofilter.<:is less than
+Autofilter.<eq:is less than or equal to
+Autofilter.>:is greater than
+Autofilter.>eq:is greater than or equal to
+Autofilter.^:starts with
+Autofilter.!^:does not start with
+Autofilter.$:ends with
+Autofilter.!$:does not end with
+Autofilter.?:contains
+Autofilter.!?:does not contain
+#
+#     ********************************************************
+#     *************** Collection Design Module ***************
+#     ********************************************************
+#     * The dictionary  phrases  used in the creation of the *
+#     * Colection  Design  Module. Note that we  still  have *
+#     * access  to the format  arguments (argument  32+) for *
+#     * html formatting.                                     *
+#     ********************************************************
+CDM.ArgumentConfiguration.Add:AÃ±adir
+CDM.ArgumentConfiguration.Bad_Integer:<html>El argumento '{0}' requiere un nÃºmero entero,<br>pero no se puede obtener ningÃºn entero de {1}.</html>
+CDM.ArgumentConfiguration.Custom_Header:A la medida
+CDM.ArgumentConfiguration.Custom:Argumentos personalizados:
+CDM.ArgumentConfiguration.Error_Title:Error en los argumentos
+CDM.ArgumentConfiguration.Header:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Por favor, configure los argumentos para {0}.</CENTER></FONT></STRONG></HTML>
+CDM.ArgumentConfiguration.No_Value:El argumento â{0}â requiere un valor, pero no se ha especificado ninguno.
+CDM.ArgumentConfiguration.Remove:Eliminar
+CDM.ArgumentConfiguration.Required_Argument:El argumento '{0}' deberÃ¡ ser un valor dado.
+CDM.ArgumentConfiguration.Title:Configurando argumentos
+CDM.ClassifierManager.Add:AÃ±adir clasificador
+CDM.ClassifierManager.Add_Tooltip:Utilice el clasificador especificado con esta colecciÃ³n
+CDM.ClassifierManager.Assigned:Clasificadores asignados actualmente
+CDM.ClassifierManager.Classifier:Seleccione el clasificador que se va a aÃ±adir:
+CDM.ClassifierManager.Classifier_Tooltip:Son los clasificadores disponibles para esta colecciÃ³n
+CDM.ClassifierManager.Classifier_Exists:Ese clasificador ya se le ha asignado a esta colecciÃ³n.
+CDM.ClassifierManager.Classifier_Str:clasificador
+CDM.ClassifierManager.Classifier_XML_Parse_Failed:No se pudieron determinar los argumentos del clasificador {0}\n. Por favor, asegÃºrese que el clasificador\n contiene el indicador -xml ejecutando el guiÃ³n classinfo.pl\n, el cual es similar a la descripciÃ³n del guiÃ³n pluginfo.pl que se encuentra en\n la secciÃ³n 2.1 de la GuÃ­a del Programador de Greenstone.
+CDM.ClassifierManager.Configure:Configurar clasificador
+CDM.ClassifierManager.Configure_Tooltip:Cambia las opciones del clasificador seleccionado
+CDM.ClassifierManager.Controls:Controles de ediciÃ³n
+CDM.ClassifierManager.Instructions:Utilice esta pantalla para aÃ±adir, configurar o eliminar clasificadores de su colecciÃ³n. Para aÃ±adir un clasificador, selecciÃ³nelo del cuadro de utilerÃ­as y haga click en 'AÃ±adir Clasificador'.\n Para eliminar un clasificador, selecciÃ³nelo de la lista de clasificadores asignados y haga click en 'Eliminar Clasificador'.\n Para configurar un clasificador, selecciÃ³nelo de la lista de clasificadores asignados y haga click en 'Configurar Clasificador'.\n\n Cuando se configure un clasificador aparecerÃ¡ una lista de sus argumentos. Active los argumentos e ingrese o seleccione los valores segÃºn sea necesario.
+CDM.ClassifierManager.Remove:Eliminar clasificador
+CDM.ClassifierManager.Remove_Tooltip:Elimina el clasificador seleccionado de la lista
+CDM.ClassifierManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>SelecciÃ³n y configuraciÃ³n de clasificadores</CENTER></FONT></STRONG></HTML>
+CDM.ClassifierManager.Parsing.Message:La herramienta de diseÃ±o estÃ¡ cargando la informaciÃ³n sobre el clasificador
+CDM.ClassifierManager.Parsing.Title:Cargando clasificadores
+CDM.FormatManager.Add:AÃ±adir formato
+CDM.FormatManager.Add_Tooltip:Utilice el comando de formato especificado junto con la colecciÃ³n
+CDM.FormatManager.Assigned_Formats:Comandos de formato asignados actualmente.
+CDM.FormatManager.Editor:Cadena de formato HTML
+CDM.FormatManager.Editor_Tooltip:Ingrese aquÃ­ el comando de formato
+CDM.FormatManager.Editing_Controls:Controles de ediciÃ³n
+CDM.FormatManager.Enabled:Activo
+CDM.FormatManager.Feature:Elegir funciÃ³n
+CDM.FormatManager.Feature_Tooltip:Es la funciÃ³n a la que se darÃ¡ formato
+CDM.FormatManager.Insert:Insertar
+CDM.FormatManager.Insert_Tooltip:Inserta la variable seleccionada en el comando de formato
+CDM.FormatManager.Instructions:Las pÃ¡ginas Web que usted ve cuando utiliza Greenstone no han sido guardadas previamente sino que se generan âal vueloâ conforme se van necesitando. Los comandos de formato se utilizan para cambiar la apariencia de las pÃ¡ginas generadas. Algunos son modificadores que controlan la presentaciÃ³n en pantalla de los documentos o partes de ellos, otros son mÃ¡s complejos y requieren un cÃ³digo html como argumento.\n Para aÃ±adir un comando de formato, selecciÃ³nelo de la lista de âfuncionesâ. Si aparece un cuadro de opciones Falso/Verdadero, elija el estado haciendo click en el botÃ³n correspondiente. Si aparece un cuadro con los controles âcomponente afectadoâ y âeditar cadenas de formatoâ, entonces necesita ingresar el texto html. Usted puede incluir variables predeterminadas seleccionÃ¡ndolas de la lista.\n Una vez que estÃ© satisfecho con los cambios, oprima el botÃ³n âAÃ±adir Formatoâ para agregarlo al archivo de la configuraciÃ³n.\n Elimine un comando de formato seleccionÃ¡ndolo de la lista âComandos de formato asignadosâ y haciendo click en âEliminar Formato'.
+CDM.FormatManager.Part:Componente afectado
+CDM.FormatManager.Part_Tooltip:Es el aspecto del componente afectado al que se va a dar formato
+CDM.FormatManager.Remove:Eliminar formato
+CDM.FormatManager.Remove_Tooltip:Elimina el comando de formato seleccionado de la lista
+CDM.FormatManager.Replace:Reemplazar formato
+CDM.FormatManager.Replace_Tooltip:Actualiza el comando de formato seleccionado
+CDM.FormatManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Comandos de formato</CENTER></FONT></STRONG></HTML>
+CDM.FormatManager.Variable:Variables
+CDM.FormatManager.Variable_Tooltip:Son las variables disponibles para el comando de formato
+CDM.General.Access:La colecciÃ³n serÃ¡ de acceso pÃºblico
+CDM.General.Beta:La colecciÃ³n sigue en construcciÃ³n
+CDM.General.Browser_Title:Seleccione una imagen
+CDM.General.Collection_Extra:DescripciÃ³n de la colecciÃ³n:
+CDM.General.Collection_Extra_Tooltip:Es una descripciÃ³n del propÃ³sito y los contenidos de la colecciÃ³n
+CDM.General.Collection_Name:TÃ­tulo de la colecciÃ³n:
+CDM.General.Collection_Name_Tooltip:Es el nombre de la colecciÃ³n
+CDM.General.Copy_Image:Para usar esta imagen para su colecciÃ³n, deberÃ¡n copiarse \n archivos a su carpeta de imÃ¡genes. Proceder?
+CDM.General.Email.Creator:E-mail del creador de la colecciÃ³n
+CDM.General.Email.Creator_Tooltip:es la direcciÃ³n de e-mail del creador de la colecciÃ³n
+CDM.General.Email.Maintainer:E-mail del administrador de la colecciÃ³n
+CDM.General.Email.Maintainer_Tooltip:Es la direcciÃ³n de e-mail del administrador de la colecciÃ³n
+CDM.General.Icon_Collection:URL del Ã­cono de la pÃ¡gina 'acerca de':
+CDM.General.Icon_Collection_Tooltip:Es el URL de la imagen que aparecerÃ¡ en la pÃ¡gina "Acerca de" de la biblioteca digital
+CDM.General.Icon_Collection_Small:URL del Ã­cono de la 'pÃ¡gina principal':
+CDM.General.Icon_Collection_Small_Tooltip:Es el URL de la imagen que aparecerÃ¡ en la pÃ¡gina principal de la biblioteca digital
+CDM.General.Image_Copy_Failed:Ha ocurrido un error que evita que la imagen que usted seleccionÃ³ se copie.\n Por favor trate de copiarla manualmente en la carpeta de imÃ¡genes de su colecciÃ³n.
+CDM.General.Image_Filter:ImÃ¡genes (gifs, jpgs y pngs)
+CDM.General.Instructions:La secciÃ³n de diseÃ±o de la Interfaz de la Biblioteca Digital le permite controlar varios aspectos relativos a la apariencia de su colecciÃ³n. El diseÃ±o se divide en varias secciones. Esta secciÃ³n contiene las opciones y ajustes generales. Para ver una secciÃ³n diferente, haga click en el nombre de la secciÃ³n en la lista que se encuentra a la izquierda.
+CDM.General.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Opciones generales</CENTER></FONT></STRONG></HTML>
+CDM.GUI.Classifiers:Clasificadores de exploraciÃ³n
+CDM.GUI.Design_Topics:Secciones de diseÃ±o
+CDM.GUI.Formats:Formatos
+CDM.GUI.General:General
+CDM.GUI.Indexes:Ãndices de bÃºsqueda
+CDM.GUI.MetadataSets:Conjuntos de metadatos
+CDM.GUI.Plugins:Plugins de documento
+CDM.GUI.Root:CDM_ROOT
+CDM.GUI.SearchTypes:Tipos de bÃºsqueda
+CDM.GUI.Subcollections:Particionar Ã­ndices
+CDM.GUI.SuperCollection:BÃºsqueda cruzada a travÃ©s de varias colecciones
+CDM.GUI.Translation:Traducir texto
+CDM.IndexManager.Add_Index:AÃ±adir Ã­ndice
+CDM.IndexManager.Add_Index_Tooltip:Crea el Ã­ndice especificado para esta colecciÃ³n
+CDM.IndexManager.Default_Index_Indicator:[Ãndice por omisiÃ³n]
+CDM.IndexManager.Document:documento
+CDM.IndexManager.Index_Exists:Ese Ã­ndice ya se le ha asignado a esta colecciÃ³n.
+CDM.IndexManager.Index_Name:Nombre del Ã­ndice
+CDM.IndexManager.Index_Name_Tooltip:Es un nombre exclusivo para el nuevo Ã­ndice
+CDM.IndexManager.Indexes:Ãndices asignados
+CDM.IndexManager.Instructions:AquÃ­ usted puede seleccionar los Ã­ndices de bÃºsqueda que la colecciÃ³n tendrÃ¡.\n Para aÃ±adir un nuevo Ã­ndice, seleccione el material que se va a indexar, elija el nivel del Ã­ndice y haga click en âAÃ±adir Ã­ndiceâ.\n Para eliminar un Ã­ndice, selecciÃ³nelo de la lista de Ã­ndices asignados y haga click en âEliminar Ã­ndiceâ.\n Para establecer un Ã­ndice por omisiÃ³n, selecciÃ³nelo de la lista y haga click en âPredeterminarâ'.
+CDM.IndexManager.Level:Nivel:
+CDM.IndexManager.Level_Exists:Ese nivel ya se le ha asignado a esta colecciÃ³n.
+CDM.IndexManager.Level_Tooltip:Es el nivel de documento sobre el que se crearÃ¡ el Ã­ndice
+CDM.IndexManager.MGPP.Add_All_Metadata:AÃ±adir todas
+CDM.IndexManager.MGPP.Add_All_Metadata_Tooltip:Construya un Ã­ndice separado para cada fuente disponible usando la fuente como nombre del Ã­ndice.
+CDM.IndexManager.MGPP.Add_Level:AÃ±adir nivel
+CDM.IndexManager.MGPP.Add_Level_Tooltip:Crea un Ã­ndice en el nivel especificado
+CDM.IndexManager.MGPP.Current_Indexes:Ãndices asignados
+CDM.IndexManager.MGPP.Current_Levels:Niveles asignados
+CDM.IndexManager.MGPP.Index:Fuente del Ã­ndice:
+CDM.IndexManager.MGPP.Index_Tooltip:Es elemento de metadato sobre el que crearÃ¡ el Ã­ndice
+CDM.IndexManager.MGPP.Indexes:Administrar Ã­ndices
+CDM.IndexManager.MGPP.Instructions:AquÃ­ usted elige los Ã­ndices de bÃºsqueda que la colecciÃ³n tendrÃ¡.\n Para aÃ±adir un nuevo Ã­ndice ingrese un nombre exclusivo para ese Ã­ndice, seleccione el material/metadato que se va a indexar y haga click en âAÃ±adir Ã­ndiceâ\n Si desea aÃ±adir todas las fuentes disponibles con el fin de construir Ã­ndices en ellas, entonces haga click en âAÃ±adir todosâ (el nombre para cada Ã­ndice serÃ¡ por omisiÃ³n el nombre de la fuente). Recuerde que esto es ligeramente diferente a aÃ±adir la fuente âAllFieldsâ, ya que el orden de los Ã­ndices es importante.\n Si desea editar un Ã­ndice en particular, selecciÃ³nelo de la lista de Ã­ndices asignados actualmente, edÃ­telo segÃºn sea necesario y luego haga click en âReemplazar Ã­ndiceâ para poder sustituir la versiÃ³n anterior.\n Para eliminar un Ã­ndice selecciÃ³nelo de la lista de Ã­ndices asignados actualmente y haga click en âEliminar Ã­ndiceâ.
+CDM.IndexManager.MGPP.Level:Nivel de la fuente:
+CDM.IndexManager.MGPP.Level_Name:Nombre del nivel:
+CDM.IndexManager.MGPP.Level_Name_Tooltip:Es un nombre Ãºnico para el Ã­ndice del nuevo nivel
+CDM.IndexManager.MGPP.Levels:Administrar niveles
+CDM.IndexManager.MGPP.Remove_Level:Eliminar nivel
+CDM.IndexManager.MGPP.Remove_Level_Tooltip:Elimina el Ã­ndice del nivel seleccionado
+CDM.IndexManager.MGPP.Replace_Index:Reemplazar Ã­ndice
+CDM.IndexManager.MGPP.Replace_Index_Tooltip:Actualiza el Ã­ndice seleccionado
+CDM.IndexManager.MGPP.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>SelecciÃ³n de Ã­ndice y nivel</CENTER></FONT></STRONG></HTML>
+CDM.IndexManager.Paragraph:pÃ¡rrafo
+CDM.IndexManager.Remove_Index:Eliminar Ã­ndice
+CDM.IndexManager.Remove_Index_Tooltip:Elimina el Ã­ndice seleccionado de la lista
+CDM.IndexManager.Section:secciÃ³n
+CDM.IndexManager.Set_Default:Establecer un Ã­ndice por omisiÃ³n
+CDM.IndexManager.Set_Default_Tooltip:Hace que el Ã­ndice seleccionado sea el Ã­ndice por omisiÃ³n
+CDM.IndexManager.Source:Crear el Ã­ndice con base en:
+CDM.IndexManager.Source_Tooltip:Son los elementos de metadato sobre los que se crearÃ¡ el Ã­ndice
+CDM.IndexManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>SelecciÃ³n del Ã­ndice</CENTER></FONT></STRONG></HTML>
+CDM.LanguageManager.Add:AÃ±adir idioma
+CDM.LanguageManager.Add_Tooltip:AÃ±ade el idioma especificado en la lista
+CDM.LanguageManager.Assigned_Languages:Idiomas asignados
+CDM.LanguageManager.Default_Language:Idioma predeterminado
+CDM.LanguageManager.Remove:Eliminar idioma
+CDM.LanguageManager.Remove_Tooltip:Elimina el idioma seleccionado de la lista
+CDM.LanguageManager.Selector:Idioma que se va a aÃ±adir
+CDM.LanguageManager.Selector_Tooltip:Es el idioma sobre el que se va a crear una particiÃ³n
+CDM.LanguageManager.Set_Default:Predeterminar
+CDM.LanguageManager.Set_Default_Tooltip:Hace que el idioma seleccionado sea el idioma por omisiÃ³n
+CDM.MetadataSetManager.Add:AÃ±adir un conjunto de metadatos
+CDM.MetadataSetManager.Add_Tooltip:AÃ±adir un nuevo conjunto de metadatos a la colecciÃ³n.
+CDM.MetadataSetManager.Edit:Editar conjunto de metadatos
+CDM.MetadataSetManager.Edit_Message:Los conjuntos de metadatos pueden editarse usando GEMS (Editor Greenstone para Conjuntos de Metadatos)./n Inicie GEMS ejecutando gems.bat (en Windows) o gems.sh (en Linux), que se encuentran en el directorio gli de su instalaciÃ³n de Greenstone.
+CDM.MetadataSetManager.Edit_Message_Title:Editando conjuntos de metadatos
+CDM.MetadataSetManager.Edit_Tooltip:Editar el conjunto de metadatos seleccionado.
+CDM.MetadataSetManager.Elements:Elementos del conjunto de metadatos seleccionado
+CDM.MetadataSetManager.Instructions:Por medio de la pantalla de diseÃ±o usted puede aÃ±adir, configurar y eliminar los conjuntos de metadatos de su colecciÃ³n, asÃ­ como los elementos que contienen.
+CDM.MetadataSetManager.Remove:Eliminar un conjunto de metadatos
+CDM.MetadataSetManager.Remove_Tooltip:Borrar el conjunto de metadatos seleccionado de la colecciÃ³n.
+CDM.MetadataSetManager.Sets:Conjuntos de metadatos disponibles
+CDM.MetadataSetManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Conjuntos de metadatos</CENTER></FONT></STRONG></HTML>
+CDM.Move.At_Bottom:{0} {1} no se puede mover mÃ¡s abajo puesto que ya se encuentra al final de la lista.
+CDM.Move.At_Top:{0} {1} no se puede mover mÃ¡s arriba puesto que ya se encuentra al principio de la lista.
+CDM.Move.Cannot:El plugin {0} no se puede mover mÃ¡s abajo ya que RecPlug y ArcPlug deben estar al final de la lista.
+CDM.Move.Fixed:<html>Por regla general RecPlug y ArcPlug siempre deben estar al final.<br>Si por alguna razÃ³n tiene que moverlos de lugar, por favor edite manualmente el archivo collect.cfg.</html>
+CDM.Move.Move_Down:Mover abajo
+CDM.Move.Move_Down_Tooltip:Mueve el elemento seleccionado hacia abajo en la lista
+CDM.Move.Move_Up:Mover arriba
+CDM.Move.Move_Up_Tooltip:Mueve el elemento seleccionado hacia arriba en la lista
+CDM.Move.Title:Error - no se puede mover
+CDM.PlugInManager.Add:AÃ±adir plugin
+CDM.PlugInManager.Add_Tooltip:Utilice el plugin especificado con esta colecciÃ³n
+CDM.PlugInManager.Assigned:Plugins asignados actualmente
+CDM.PlugInManager.Configure:Configurar un plugin
+CDM.PlugInManager.Configure_Tooltip:Cambia las opciones del plugin seleccionado
+CDM.PlugInManager.Controls:Controles de ediciÃ³n
+CDM.PlugInManager.Ignore:No Agregar Plugin
+CDM.PlugInManager.Ignore_Tooltip:No agregar ningÃºn Plugin a esta colecciÃ³n.
+CDM.PlugInManager.Instructions:Utilice esta pantalla para aÃ±adir, configurar o eliminar plugins de su colecciÃ³n. Para aÃ±adir uno selecciÃ³nelo del cuadro de utilerÃ­as y haga click en âAÃ±adir Pluginâ.\n Para configurar o eliminar uno, elÃ­jalo de la lista de plugins asignados y a continuaciÃ³n:\n i) Cambie su posiciÃ³n en el orden haciendo click en las flechas. (Recuerde: la posiciÃ³n de RecPlug y ArcPlug es fija.)\n ii) ConfigÃºrelo haciendo click en âConfigurar Pluginâ,\n o iii) ElimÃ­nelo haciendo click en âEliminar Pluginâ.\n\n Los plugins se configuran por medio de un Ã¡rea de diseÃ±o que aparece cuando se selecciona esta opciÃ³n y que contiene una lista de argumentos. Active los argumentos e ingrese o seleccione los valores segÃºn sea necesario.
+CDM.PlugInManager.PlugIn:Seleccione el plugin que se va a aÃ±adir
+CDM.PlugInManager.PlugIn_Tooltip:Son los plugins disponibles para esta colecciÃ³n
+CDM.PlugInManager.PlugIn_Exists:Ese plugin ya se le ha asignado a esta colecciÃ³n.
+CDM.PlugInManager.PlugIn_Str:plugin
+CDM.PlugInManager.PlugIn_XML_Parse_Failed:No se pudieron determinar los argumentos del plugin {0}\n. Por favor, asegÃºrese que el plugin contiene\n el indicador -xml ejecutando el guiÃ³n pluginfo.pl descrito\n en la secciÃ³n 2.1 de la GuÃ­a del Programador de Greenstone.
+CDM.PluginManager.Plugin_Suggestion_Prompt:Ninguno de los plugins de esta colecciÃ³n puede procesar el archivo "{0}". Para procesar este archivo pueden utilizarse los siguientes plugins. En este momento usted puede agregar uno a su colecciÃ³n, seleccionÃ¡ndolo y oprimiendo el botÃ³n Agregar. (Tenga en cuenta que en cualquier momento puede cambiar la lista de plugins dirigiÃ©ndose a "Document Plugins" en el Panel de DiseÃ±o.)
+CDM.PlugInManager.Remove:Eliminar plugin
+CDM.PlugInManager.Remove_Tooltip:Elimina el plugin seleccionado de la lista
+CDM.PluginManager.SuggestedPluginListTitle:Plugins sugeridos para el archivo
+CDM.PlugInManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>SelecciÃ³n y configuraciÃ³n de plugins</CENTER></FONT></STRONG></HTML>
+CDM.PlugInManager.Parsing.Message:La herramienta de diseÃ±o estÃ¡ cargando la informaciÃ³n del plugin
+CDM.PlugInManager.Parsing.Title:Cargando Plugins
+CDM.SearchTypeManager.Add:AÃ±adir tipo de bÃºsqueda
+CDM.SearchTypeManager.Add_Tooltip:Permite el tipo especificado de bÃºsqueda en esta colecciÃ³n
+CDM.SearchTypeManager.Assigned:Tipos de bÃºsqueda asignados actualmente
+# -- Missing translation: CDM.SearchTypeManager.BuildType_Selection
+# -- Missing translation: CDM.SearchTypeManager.BuildType_Selection_Tooltip
+CDM.SearchTypeManager.Enable:Permitir bÃºsquedas avanzadas
+CDM.SearchTypeManager.Instructions:Definir el tipo de bÃºsqueda es una funciÃ³n avanzada que sÃ³lo estÃ¡ disponible cuando se marca el recuadro âPermitir bÃºsquedas avanzadasâ. Una vez que se activa, otros controles para seleccionar y cambiar el orden de los tipos de bÃºsqueda tambiÃ©n estÃ¡n disponibles. Seleccione un tipo de bÃºsqueda del cuadro de utilerÃ­as y haga click en âAÃ±adir tipo de bÃºsquedaâ para agregarlo. Seleccione de la lista un tipo de bÃºsqueda existente y use los botones âMover arribaâ y âMover abajoâ para cambiar su orden, o el botÃ³n âEliminar tipo de bÃºsquedaâ para quitarlo de la lista.\n\n Los tipos de bÃºsqueda especifican el tipo de bÃºsqueda con el que contarÃ¡n las interfaces: formas, bÃºsqueda por campos y/o bÃºsqueda de sÃ³lo texto. El orden es importante, ya que el primero se usarÃ¡ por omisiÃ³n para la pÃ¡gina de bÃºsqueda inicial.\n\n Asimismo es importante recordar que al activar los diferentes tipos de bÃºsqueda, la apariencia de la pantalla de Ãndices tambiÃ©n cambia. La bÃºsqueda por campos es una funciÃ³n reciente de Greenstone y por lo tanto requiere de informaciÃ³n diferente. Cuando se active la funciÃ³n de tipos de bÃºsqueda todos los Ã­ndices se modificarÃ¡n para que sean vÃ¡lidos de acuerdo al nuevo esquema, mientras que al desactivar los tipos de bÃºsqueda la Interfaz de la Biblioteca Digital harÃ¡ lo posible por convertir los nuevos Ã­ndices de regreso al estilo anterior, aunque puede ser que no siempre tenga Ã©xito, en cuyo caso los Ã­ndices se eliminarÃ¡n. De cualquier manera, una copia de la lÃ­nea de comando del Ã­ndice original estarÃ¡ disponible como comentario en el archivo de configuraciÃ³n.
+CDM.SearchTypeManager.Remove:Eliminar tipo de bÃºsqueda
+CDM.SearchTypeManager.Remove_Tooltip:No permite el tipo seleccionado de bÃºsqueda para esta colecciÃ³n
+CDM.SearchTypeManager.SearchType:Tipo de bÃºsqueda
+CDM.SearchTypeManager.SearchType_Selection:Tipos de bÃºsqueda:
+CDM.SearchTypeManager.SearchType_Selection_Tooltip:Son los tipos de bÃºsqueda disponibles para esta colecciÃ³n
+CDM.SearchTypeManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>SelecciÃ³n y orden de los tipos de bÃºsqueda</CENTER></FONT></STRONG></HTML>
+CDM.SubcollectionManager.Add:AÃ±adir filtro
+CDM.SubcollectionManager.Add_Tooltip:AÃ±ade el filtro especificado a la colecciÃ³n
+CDM.SubcollectionManager.Assigned:Filtros definidos para la subcolecciÃ³n
+CDM.SubcollectionManager.Exclude:Excluir
+CDM.SubcollectionManager.Flags:Indicadores que se usarÃ¡n al momento de contrastar
+CDM.SubcollectionManager.Flags_Tooltip:Indicadores de expresiones regulares que se utilizarÃ¡n al momento de cotejar (p. ej. âiâ para comparaciones que no toman en cuenta el caso)
+CDM.SubcollectionManager.Include:Incluir
+CDM.SubcollectionManager.Inclusive:Â¿QuÃ© hacemos con los archivos que concuerdan?
+CDM.SubcollectionManager.Instructions:Utilice esta pantalla para refinar la creaciÃ³n de Ã­ndices.\n i) Defina los filtros de la subcolecciÃ³n que se emplearÃ¡n para depurar la selecciÃ³n de documentos de la colecciÃ³n con base en los valores de los metadatos especificados. Una vez definidos usted puede generar particiones sobre cualquier Ã­ndice especificado previamente a partir de uno o mÃ¡s de dichos filtros.\n ii) Genere particiones de Ã­ndices con base en el idioma. Esto filtra los documentos de la colecciÃ³n de tal manera que Ãºnicamente se incluyen aquellos documentos en el idioma seleccionado.\n Recuerde que el nÃºmero total de particiones generadas es una combinaciÃ³n de todos los Ã­ndices, filtros de subcolecciÃ³n e idiomas seleccionados. De esta manera, dos Ã­ndices con dos filtros de subcolecciÃ³n en dos idiomas producirÃ¡n ocho particiones.
+CDM.SubcollectionManager.Language_Controls:Asignar idiomas
+CDM.SubcollectionManager.Match:ExpresiÃ³n regular con la que se contrastarÃ¡:
+CDM.SubcollectionManager.Match_Tooltip:Es una expresiÃ³n regular que define los documentos de la subcolecciÃ³n
+CDM.SubcollectionManager.Name:Nombre del filtro de la subcolecciÃ³n:
+CDM.SubcollectionManager.Name_Tooltip:Es el nombre del nuevo filtro de la subcolecciÃ³n
+CDM.SubcollectionManager.Partitions_Disabled:Este programa no estÃ¡ activo en este momento ya que usted estÃ¡ operando en el modo {0-Modo Actual}. Ãnicamente se puede tener acceso a Ã©l en los modos {1-Sistemas} y {2-Avanzado}. Utilice la opciÃ³n de Preferencias que se encuentra en el menÃº de Archivo para cambiar el modo de operaciÃ³n.
+CDM.SubcollectionManager.Remove:Eliminar filtro
+CDM.SubcollectionManager.Remove_Tooltip:Quita el filtro seleccionado de la lista
+CDM.SubcollectionManager.Replace:Reemplazar filtro
+CDM.SubcollectionManager.Replace_Tooltip:Actualiza los detalles del filtro seleccionado
+CDM.SubcollectionManager.Source:Atributo del documento con el cual se va a contrastar:
+CDM.SubcollectionManager.Source_Tooltip:Es el atributo con base en el cual se filtrarÃ¡n los documentos
+CDM.SubcollectionManager.Subcollection_Controls:Definir filtros
+CDM.SubcollectionManager.Subindex_Controls:Asignar particiones
+CDM.SubcollectionManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Particionando Ã­ndices</CENTER></FONT></STRONG></HTML>
+CDM.SubcollectionIndexManager.Add_Subindex:AÃ±adir particiÃ³n
+CDM.SubcollectionIndexManager.Add_Subindex_Tooltip:AÃ±ade la particiÃ³n especificada a esta colecciÃ³n
+CDM.SubcollectionIndexManager.Default_Partition_Indicator:[ParticiÃ³n por Defecto]
+CDM.SubcollectionIndexManager.PartitionName:Nombre de la particiÃ³n:
+CDM.SubcollectionIndexManager.PartitionName_Tooltip:Es el nombre de la nueva particiÃ³n
+CDM.SubcollectionIndexManager.Remove_Subindex:Eliminar particiÃ³n
+CDM.SubcollectionIndexManager.Remove_Subindex_Tooltip:Elimina la particiÃ³n seleccionada de esta colecciÃ³n
+CDM.SubcollectionIndexManager.Replace_Subindex:Remplazar ParticiÃ³n
+CDM.SubcollectionIndexManager.Replace_Subindex_Tooltip:Actualizar la particiÃ³n seleccionada
+CDM.SubcollectionIndexManager.Set_Default_Subindex:Predeterminar
+CDM.SubcollectionIndexManager.Set_Default_Subindex_Tooltip:Hace que la particiÃ³n seleccionada sea la particiÃ³n por omisiÃ³n
+CDM.SubcollectionIndexManager.Source:Construir particiÃ³n en:
+CDM.SubcollectionIndexManager.Source_Tooltip:Los filtros de la subcolecciÃ³n para construir la particiÃ³n en
+CDM.SubcollectionIndexManager.Subindexes:Particiones asignadas a la subcolecciÃ³n
+CDM.SuperCollectionManager.Instructions:BÃºsqueda cruzada es cuando una bÃºsqueda se realiza a travÃ©s de varias colecciones distintas, como si las colecciones fueran una sola. Especifique las colecciones que se incluirÃ¡n en la bÃºsqueda haciendo click en el nombre de la colecciÃ³n de entre la lista que aparece abajo. La colecciÃ³n actual se incluirÃ¡ automÃ¡ticamente. \n CUIDADO: Si las colecciones no tienen los mismos Ã­ndices (incluyendo particiones en subcolecciones e idiomas) la bÃºsqueda cruzada no funcionarÃ¡ correctamente. El usuario Ãºnicamente serÃ¡ capaz de buscar usando Ã­ndices comunes a todas las colecciones.
+CDM.SuperCollectionManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>ConfiguraciÃ³n de la bÃºsqueda cruzada a travÃ©s de varias colecciones</CENTER></FONT></STRONG></HTML>
+CDM.TranslationManager.Add:AÃ±adir traducciÃ³n
+CDM.TranslationManager.Add_Tooltip:AÃ±ade la traducciÃ³n especificada a la colecciÃ³n
+CDM.TranslationManager.Affected_Features:Funciones
+CDM.TranslationManager.Assigned_Fragments:Traducciones asignadas
+CDM.TranslationManager.Default_Text:Fragmento de texto inicial
+CDM.TranslationManager.Fragment_Column:Fragmento de texto
+CDM.TranslationManager.Instructions:Utilice esta pantalla para revisar y asignar traducciones de fragmentos de texto a su colecciÃ³n. Primero, seleccione una entrada de la lista de funciones (p. ej. nombres de clasificadores y metadatos a nivel de colecciÃ³n). A continuaciÃ³n, seleccione y edite un fragmento de texto, o seleccione un idioma del cuadro de utilerÃ­as a fin de aÃ±adir un nuevo fragmento. Escriba el texto en el Ã¡rea en blanco, haciendo referencia al fragmento de texto inicial segÃºn sea necesario. Cualquier cambio que se haga aparecerÃ¡ inmediatamente en la colecciÃ³n.
+CDM.TranslationManager.Language:Idioma de la traducciÃ³n
+CDM.TranslationManager.Language_Column:Idioma
+CDM.TranslationManager.Language_Tooltip:Es el idioma al que se traducirÃ¡
+CDM.TranslationManager.Remove:Eliminar traducciÃ³n
+CDM.TranslationManager.Remove_Tooltip:Quita la traducciÃ³n seleccionada de la colecciÃ³n
+CDM.TranslationManager.Replace:Reemplazar traducciÃ³n
+CDM.TranslationManager.Replace_Tooltip:Actualiza la traducciÃ³n seleccionada
+CDM.TranslationManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>TraducciÃ³n de textos</CENTER></FONT></STRONG></HTML>
+CDM.TranslationManager.Translation:Texto traducido
+CDM.TranslationManager.Translation_Tooltip:Escriba aquÃ­ la traducciÃ³n de la cadena de texto
+#*******************
+#
+#***** Collection *****
+Collection.Collection:<HTML><STRONG><FONT FACE={FONT} COLOR=Black>ColecciÃ³n</FONT></STRONG></HTML>
+Collection.Delete_Tooltip:Elimina los archivos y carpetas seleccionados
+Collection.Filter_Tooltip:Limita el nÃºmero de archivos mostrados en este Ã¡rbol de archivos
+Collection.New_Folder_Tooltip:Crea una nueva carpeta
+Collection.No_Collection:No hay colecciÃ³n
+Collection.Stop:Detener
+Collection.Stop_Tooltip:Detiene la copia de los archivos
+Collection.Workspace:<HTML><STRONG><FONT FACE={FONT} COLOR=Black>Ãrea de trabajo</FONT></STRONG></HTML>
+#**********************
+#
+#***** CollectionBuilt *****
+CollectionBuilt.Message:Se ha construido la colecciÃ³n y estÃ¡ lista para verse.
+CollectionBuilt.Title:Resultado del proceso de creaciÃ³n de la colecciÃ³n
+#***************************
+#
+#***** CollectionManager *****
+CollectionManager.Build_Cancelled:Se ha cancelado la construcciÃ³n de la colecciÃ³n.
+CollectionManager.Cannot_Create_Collection:Ha ocurrido un error y no se ha podido crear la colecciÃ³n
+CollectionManager.Cannot_Delete_Index:Esta colecciÃ³n no se puede reconstruir debido a que los archivos de Ã­ndices anteriores no se pueden suprimir.\n Por favor asegÃºrese que Greenstone o algÃºn otro programa no estÃ¡ usando estos archivos\n e intÃ©ntelo de nuevo.
+CollectionManager.Cannot_Delete_Index_Log:Los archivos de Ã­ndices anteriores no se pudieron suprimir, por lo cual la importaciÃ³n se detuvo.
+CollectionManager.Cannot_Open:La colecciÃ³n en:\n{0-ruta del archivo de la colecciÃ³n}\n no se pudo abrir.
+CollectionManager.Cannot_Open_With_Reason:La colecciÃ³n en:\n{0-ruta de acceso al archivo de la colecciÃ³n}\n no pudo abrirse debido a:\n{1-mensaje de error}
+CollectionManager.Creating_New:Creando una nueva colecciÃ³n.
+CollectionManager.Log_Created:Se ha creado la carpeta de registro.
+CollectionManager.Loading_Collection:Cargando colecciÃ³n
+CollectionManager.Loading_Collection_Please_Wait:Cargando colecciÃ³n, espere por favorâŠ
+CollectionManager.Loading_Successful:ColecciÃ³n cargada {0}.
+CollectionManager.Missing_Config:Esta colecciÃ³n no cuenta con un archivo collect.cfg vÃ¡lido
+CollectionManager.Not_Col_File:{0}' no es un archivo de colecciÃ³n de la Interfaz de la Biblioteca Digital (.col)
+CollectionManager.Preview_Ready_Failed:Ha ocurrido un error que evitarÃ¡ que la colecciÃ³n se pueda ver de forma preliminar.
+CollectionManager.Preview_Ready_Title:Vista preliminar de la colecciÃ³n.
+CollectionManager.Session_Ready:La colecciÃ³n {0} estÃ¡ lista para usarse.
+#*****************************
+#
+#***** CollectionPopupMenu *****
+CollectionPopupMenu.Delete:Suprimir
+CollectionPopupMenu.New_Dummy_Doc:Nuevo documento postizo
+CollectionPopupMenu.New_Folder:Nueva carpeta
+#*******************************
+#
+#***** CreatePane *****
+CreatePane.Build:Opciones de construcciÃ³n de la colecciÃ³n
+CreatePane.Build_Tooltip:Opciones para las fases de indexaciÃ³n y clasificaciÃ³n en la formaciÃ³n de la colecciÃ³n
+CreatePane.Build_Collection:Crear colecciÃ³n
+CreatePane.Build_Collection_Tooltip:Inicia el proceso de formaciÃ³n de la colecciÃ³n
+CreatePane.Build_Progress:Grado de avance en el proceso de construcciÃ³n
+CreatePane.Cancel_Build:Cancelar la construcciÃ³n
+CreatePane.Cancel_Build_Tooltip:Detiene el proceso de formaciÃ³n de la colecciÃ³n
+CreatePane.Import:Opciones de importaciÃ³n de la colecciÃ³n
+CreatePane.Import_Tooltip:Opciones para las fases de conversiÃ³n de archivos y asignaciÃ³n de metadatos en la formaciÃ³n de la colecciÃ³n
+CreatePane.Import_Progress:Grado de avance del proceso de importaciÃ³n
+CreatePane.Log:Registro de mensajes
+CreatePane.Log_Tooltip:Muestra los resultados de intentos anteriores de construcciÃ³n de la colecciÃ³n
+CreatePane.Mode_All:todos
+CreatePane.Options:Grupos opcionales
+CreatePane.Options_Title:Opciones de importaciÃ³n y construcciÃ³n de la colecciÃ³n
+CreatePane.Preview_Collection:Vista previa de la colecciÃ³n
+CreatePane.Preview_Collection_Tooltip:Vista previa de la colecciÃ³n que se ha construido
+#**********************
+#
+#***** Dates *****
+Dates.Mon:Lunes
+Dates.Tue:Martes
+Dates.Wed:MiÃ©rcoles
+Dates.Thu:Jueves
+Dates.Fri:Viernes
+Dates.Sat:SÃ¡bado
+Dates.Sun:Domingo
+Dates.Jan:Enero
+Dates.Feb:Febrero
+Dates.Mar:Marzo
+Dates.Apr:Abril
+Dates.May:Mayo
+Dates.Jun:Junio
+Dates.Jul:Julio
+Dates.Aug:Agosto
+Dates.Sep:Septiembre
+Dates.Oct:Octubre
+Dates.Nov:Noviembre
+Dates.Dec:Diciembre
+#**********************
+#
+#***** Delete Collection Prompt *****
+DeleteCollectionPrompt.Collection_Details:Detalles de la colecciÃ³n seleccionada
+DeleteCollectionPrompt.Collection_List:Colecciones disponibles
+DeleteCollectionPrompt.Confirm_Delete:Por favor marque el recuadro para confirmar que desea eliminar la colecciÃ³n.
+DeleteCollectionPrompt.Delete:Suprimir
+DeleteCollectionPrompt.Delete_Tooltip:Elimina la colecciÃ³n seleccionada
+DeleteCollectionPrompt.Details:Creador - {0}\nAdministrador - {1}\nDescripciÃ³n\n{2}
+DeleteCollectionPrompt.Failed_Delete:La colecciÃ³n no se pudo eliminar por completo.
+DeleteCollectionPrompt.Failed_Title:Â¡No se puede eliminar!
+DeleteCollectionPrompt.No_Collection:No se ha seleccionado ninguna colecciÃ³n.
+DeleteCollectionPrompt.Successful_Delete:La colecciÃ³n ha sido eliminada.
+DeleteCollectionPrompt.Successful_Title:Â¡Se ha eliminado por completo!
+DeleteCollectionPrompt.Title:EliminaciÃ³n de la colecciÃ³n
+#**********************
+#
+#***** DirectoryLevelMetadata *****
+DirectoryLevelMetadata.Message:EstÃ¡ a punto de asignar metadatos âa nivel de carpetaâ a la carpeta (o carpetas) seleccionadas. Estos metadatos serÃ¡n heredados automÃ¡ticamente por todos sus archivos y subcarpetas, y  no podrÃ¡n eliminarse de ninguno de ellos de forma individual, sino sÃ³lo reemplazarse. Para continuar haga click en âAceptarâ.
+DirectoryLevelMetadata.Title:A punto de aÃ±adir metadatos a nivel de carpeta
+#********************
+#
+#***** EnrichPane *****
+EnrichPane.Accumulate:Agregar
+EnrichPane.Accumulate_Tooltip:Agrega este valor al elemento de metadato seleccionado
+EnrichPane.AutoMessage:Este elemento, {0}, pertenece al conjunto de metadatos de Greenstone, el cual representa metadatos que normalmente pueden extraerse automÃ¡ticamente. Para saber quÃ© metadatos {0} pueden extraerse, construya una colecciÃ³n por medio de la pantalla âCrearâ.
+# -- Missing translation: EnrichPane.ExistingValues
+EnrichPane.Expand:...
+EnrichPane.Expand_Tooltip:Edita el valor en un cuadro de texto mÃ¡s grande
+# -- Missing translation: EnrichPane.InheritedMetadataSelected
+EnrichPane.No_File:No se ha seleccionado ningÃºn archivo
+EnrichPane.No_Metadata:No hay metadatos disponibles
+EnrichPane.No_Metadata_Element:<HTML><STRONG><FONT FACE={FONT} COLOR=Black>No se ha seleccionado ningÃºn elemento de metadato</FONT></STRONG></HTML>
+EnrichPane.Overwrite:Reemplazar
+EnrichPane.Overwrite_Tooltip:Asigna este valor al elemento de metadato seleccionado, reemplazando el valor actual
+EnrichPane.Remove:Eliminar
+EnrichPane.Remove_Tooltip:Elimina este valor del elemento de metadato seleccionado
+EnrichPane.Value:Valor
+EnrichPane.Value_Field_Tooltip:Es el valor que se asignarÃ¡ al elemento de metadato seleccionado.
+EnrichPane.Value_Field_Tooltip_Uneditable:Valor asignado al meta-dato seleccionado
+#***********************
+#
+#****** ExplodeMetadataPrompt *******
+ExplodeMetadataPrompt.Explode:Explotar
+ExplodeMetadataPrompt.Explode_Tooltip:Explotar el archivo de metadatos
+ExplodeMetadataPrompt.Instructions:La explosiÃ³n de este archivo de metadatos producirÃ¡ registros individuales con metadatos editables. Este proceso es irreversible y el archivo original de metadatos serÃ¡ eliminado de la colecciÃ³n.
+ExplodeMetadataPrompt.Failed_Title:FallÃ³ la ExplosiÃ³n.
+ExplodeMetadataPrompt.Failed_Explode:No se pudo explotar la base de datos {0}
+ExplodeMetadataPrompt.NotExplodable:Este archivo no es explotable.
+ExplodeMetadataPrompt.Successful_Explode:La base de datos {0} ha sido explotada con Ã©xito
+ExplodeMetadataPrompt.Successful_Title:Se completÃ³ la ExplosiÃ³n.
+ExplodeMetadataPrompt.Title:Explotar la Base de Datos de Metadatos
+#***********************
+#
+#****** WriteCDImagePrompt *******
+WriteCDImagePrompt.CD_Name:Nombre del CD-ROM
+WriteCDImagePrompt.Export:Exportar
+WriteCDImagePrompt.Export_Tooltip:Exportar las colecciones seleccionadas al CD-ROM para Windows
+WriteCDImagePrompt.Failed_Export:Las colecciones  ({0}) no se pudieron exportar al CD-ROM
+WriteCDImagePrompt.Failed_Title:No se pudo exportar
+WriteCDImagePrompt.Instructions:Exportar una o mÃ¡s colecciones a un CD-ROM para Windows que se podrÃ¡ instalar automÃ¡ticamente (aunque esto funciona en cualquier plataforma, el CD-ROM que se crea Ãºnicamente correrÃ¡ bajo Windows).
+WriteCDImagePrompt.Progress_Label:Copiando archivos. Esto podrÃ¡ tomar algÃºn tiempo...
+WriteCDImagePrompt.Successful_Export:Se han exportado las colecciones ({0}).
+WriteCDImagePrompt.Successful_Title:ExportaciÃ³n completa
+WriteCDImagePrompt.Title:Exportar la colecciÃ³n a un CD-ROM
+#************************
+#
+#****** ExportAsPrompt *******
+ExportAsPrompt.Export_Name:Exportar el nombre del directorio
+ExportAsPrompt.Export:Exportar la(s) colecciÃ³n(ciones)
+ExportAsPrompt.Export_Tooltip:Exportar las colecciones seleccionadas en el formato de archivo escogido al directorio designado
+ExportAsPrompt.Failed_ExportOne:La colecciÃ³n, {0}, no pudo exportarse.
+ExportAsPrompt.Failed_ExportMany:Las colecciones -- {0} -- no pudieron exportarse.
+ExportAsPrompt.Failed_Details:Ver detalles en {1}
+ExportAsPrompt.Failed_Title:FallÃ³ la ExportaciÃ³n
+ExportAsPrompt.Instructions:Exportar una o mÃ¡s colecciones en el formato escogido al directorio estipulado
+ExportAsPrompt.Progress_Label:Exportando Archivos. Esto puede tomar algÃºn tiempoâŠ
+ExportAsPrompt.Successful_ExportOne:La colecciÃ³n -- {0} -- ha sido exportada
+ExportAsPrompt.Successful_ExportMany:Las colecciones -- {0} -- han sido exportadas
+ExportAsPrompt.Successful_Details:Archivos exportados a: {1}
+ExportAsPrompt.Successful_Title:ExportaciÃ³n Completada
+ExportAsPrompt.Title:Exportar Colecciones
+ExportAsPrompt.SaveAs:Exportar a
+ExportAsPrompt.SaveAs_Tooltip:Seleccione el formato al cual desea exportar
+#************************
+#
+#*****ExternalCollectionPrompt********
+ExternalCollectionPrompt.NewMDS:Crear un nuevo conjunto vacÃ­o de metadatos
+ExternalCollectionPrompt.ExistingMDS:Elija uno o mÃ¡s de los conjuntos de metadatos
+ExternalCollectionPrompt.Title:Cargar una colecciÃ³n externa
+ExternalCollectionPrompt.Instructions_1:EstÃ¡ a punto de cargar una colecciÃ³n que no ha sido creada por medio de GLI. Se le pedirÃ¡ que seleccione uno o mÃ¡s conjuntos de metadatos para esta colecciÃ³n. Los metadatos existentes se importarÃ¡n al conjunto o los conjuntos seleccionados. Los archivos de metadatos originales se guardarÃ¡n en una carpeta llamada import.bak.
+ExternalCollectionPrompt.Instructions_2:EstÃ¡ a punto de cargar una colecciÃ³n que no ha sido creada por medio de GLI. Necesita aÃ±adir un conjunto de metadatos a esta colecciÃ³n. Usted puede crear un conjunto vacÃ­o de metadatos en el que todos los elementos encontrados en la colecciÃ³n se incluirÃ¡n automÃ¡ticamente. Otra opciÃ³n es seleccionar conjuntos existentes de metadatos y los elementos de la colecciÃ³n se combinarÃ¡n o aÃ±adirÃ¡n a los elementos que ya se encuentran en dichos conjuntos. Los archivos de metadatos originales se guardarÃ¡n en una carpeta llamada import.bak.
+#****************************************
+#
+#***** Inherited Metadata *****
+ExtractedMetadata.Message:El archivo o carpeta seleccionada contiene metadatos extraÃ­dos, los cuales estÃ¡n ocultos. Para verlos vaya al menÃº "[A]rchivo" y seleccione la opciÃ³n "[P]referencias". En la hoja de propiedades "Generales" seleccione "Ver metadatos extraÃ­dos" y haga click en "[A]ceptar".
+ExtractedMetadata.Title:Este archivo/carpeta tiene metadatos extraÃ­dos ocultos
+#
+#***** FileActions *****
+FileActions.Calculating_Size:Calculando el tamaÃ±o total de los archivos seleccionados
+FileActions.Copying:Copiando {0}
+FileActions.Deleting:Eliminando {0}
+FileActions.Directories_Selected:{0} carpetas seleccionadas
+FileActions.Directory_Exists:<html>La carpeta<br>{0}<br>ya existe dentro de la colecciÃ³n. Los archivos se copiarÃ¡n en ella.</html>
+FileActions.Directory_Selected:1 carpeta seleccionada
+FileActions.File_Already_Exists_No_Create:El archivo '{0}' ya existe.
+FileActions.File_Already_Exists_Message:{0}\nYa existe un archivo con este nombre en la\n carpeta de destino y a pesar de que usted ha decidido reemplazarlo la Interfaz de la Biblioteca Digital\n no puede sobreescribirlo. Por favor verifique los permisos de acceso al archivo.
+FileActions.File_Already_Exists_Title:Error - El archivo ya existe.
+FileActions.File_And_Directories_Selected:1 archivo y {0} carpetas seleccionadas
+FileActions.File_And_Directory_Selected:1 archivo y 1 carpeta seleccionadas
+FileActions.File_Create_Error:El archivo {0} no pudo ser creado.
+FileActions.Folder_Create_Error:La carpeta {0} no pudo ser creada.
+FileActions.File_Exists:<html>{0} ya existe en la carpeta de destino. Â¿Desea reemplazarlo?</html>
+FileActions.File_Not_Found_Message:{0}\nNo se encontrÃ³ el archivo mencionado. Una vez que la vista de los archivos\n se haya refrescado, por favor verifique si el archivo aÃºn existe.
+FileActions.File_Not_Found_Title:Error - No se encontrÃ³ el archivo.
+FileActions.File_Selected:1 archivo seleccionado
+FileActions.Files_And_Directory_Selected:{0} archivos y 1 carpeta seleccionados
+FileActions.Files_Selected:{0} archivos seleccionados
+FileActions.Folder_Already_Exists:El nombre de la carpeta '{0}' ya se estÃ¡ usando. No se puede crear la carpeta.
+FileActions.Increase_Depth:Aumentar la profundidad 1 nivel
+FileActions.Insufficient_Space_Message:La acciÃ³n no se pudo realizar debido a que no hay suficiente espacio en el disco.\n Para que el archivo se pueda copiar se requiere de uno\n adicional: {0}
+FileActions.Insufficient_Space_Title:Error - Espacio insuficiente
+FileActions.Moving:Moviendo {0}
+FileActions.No_Activity:No se requiere ninguna acciÃ³n
+FileActions.Possible_Cyclic_Path:{1} tiene una profundidad de {0} directorios y puede ser una ruta recursiva. Â¿Desea continuar?
+FileActions.Read_Only:Los archivos del Ã¡rea de trabajo son de sÃ³lo lectura y no se pueden eliminar.
+FileActions.Selected:{0} archivos y {1} carpetas seleccionadas
+FileActions.Unknown_File_Error_Message:Aunque no se registrÃ³ ningÃºn mensaje de error durante la acciÃ³n\n, la revisiÃ³n final ha mostrado que la copia\n no es igual al archivo original. La razÃ³n\n de esto es desconocida. Por favor revise la media y actualice\n su JVM instalado.
+FileActions.Unknown_File_Error_Title:Error - Error de archivo desconocido
+FileActions.Write_Not_Permitted_Message:La Interfaz de la Biblioteca Digital no tiene permiso para escribir en\n{0}\n Por favor revise los permisos de acceso al archivo.
+FileActions.Write_Not_Permitted_Title:Error - Permisos de acceso al archivo incorrectos
+FileActions.Yes_To_All:Si a todo
+#************************
+#
+#******* File Associations dialog **********
+FileAssociationDialog.Add:AÃ±adir
+FileAssociationDialog.Add_Tooltip:Utilice este programa para ver archivos de este tipo
+FileAssociationDialog.Batch_File:Archivos de procesamiento por lotes
+FileAssociationDialog.Browse:Explorar
+FileAssociationDialog.Browse_Tooltip:Escoge el programa que se usarÃ¡ desde el espacio de archivos de su computadora
+FileAssociationDialog.Browse_Tooltip_Mac:La bÃºsqueda de su aplicaciÃ³n no estÃ¡ activa en este momento para MacOS
+FileAssociationDialog.Browse_Title:Elegir aplicaciÃ³n
+FileAssociationDialog.Close:Cerrar
+FileAssociationDialog.Close_Tooltip:Cerrar este cuadro de diÃ¡logo y regresar a la ventana principal
+FileAssociationDialog.Command:Comando de inicio:
+FileAssociationDialog.Command_File:Archivo de comandos
+FileAssociationDialog.Command_Tooltip:Ingrese el comando para iniciar el programa que se va a usar
+FileAssociationDialog.Details:Detalles de la nueva asociaciÃ³n
+FileAssociationDialog.Executable_File:Archivos ejecutables
+FileAssociationDialog.Existing_Associations:Asociaciones actuales
+FileAssociationDialog.Extension:Para archivos que terminan en:
+FileAssociationDialog.Extension_Tooltip:La extensiÃ³n de los archivos que se van a ver
+FileAssociationDialog.Instructions:Utilice este cuadro de diÃ¡logo para establecer los programas externos que se usarÃ¡n para ver un cierto tipo de archivo y el comando que se enviarÃ¡ para iniciar este programa.\n Para aÃ±adir un nuevo tipo de archivo escriba su extensiÃ³n en âPara archivos que terminan enâ. Para aÃ±adir o modificar un comando de inicio escriba el nuevo comando en âComando de inicioâ o haga click en âExplorarâ para buscar el sistema de archivos de un programa apropiado. Use la cadena de caracteres especiales â%1â para indicar el lugar en el que el nombre del archivo que se abrirÃ¡ deberÃ¡ insertarse, p. ej. "C:\\Windows\\System\\MSPaint.exe %1". '%1' se anexarÃ¡ al final de un comando si no se especifica de otra manera.\n Los usuarios de Mac OS siempre deberÃ¡n intentar primero el comando especÃ­fico para mac "open [-a <application_name>] %1".
+FileAssociationDialog.Table.Command:Comando
+FileAssociationDialog.Table.Extension:ExtensiÃ³n
+FileAssociationDialog.Title:Editar asociaciones de archivos
+FileAssociationDialog.Remove:Eliminar
+FileAssociationDialog.Remove_Tooltip:Elimine la asociaciÃ³n seleccionada del conjunto de asociaciones existentes
+FileAssociationDialog.Replace:Reemplazar
+FileAssociationDialog.Replace_Tooltip:Reemplace la asociaciÃ³n seleccionada con los detalles de la nueva asociaciÃ³n
+#*******************
+#
+#******Filter***************
+Filter.0:HTM y HTML
+Filter.1:XML
+Filter.2:Archivos de texto
+Filter.3:ImÃ¡genes
+Filter.All_Files:Todos los archivos
+Filter.Filter_Tree:Mostrar archivos
+Filter.Invalid_Pattern:<HTML><FONT FACE={FONT} COLOR=Black>El patrÃ³n que usted ha ingresado para filtrar archivos no es vÃ¡lido.<BR> Por favor intÃ©ntelo de nuevo usando la sintaxis de expresiones regulares con<BR>* como comodÃ­n.</FONT></HTML>
+#***********************
+#
+#***** GAuthenticator *****
+GAuthenticator.Password:ContraseÃ±a:
+GAuthenticator.Password_Tooltip:Escriba aquÃ­ su contraseÃ±a
+GAuthenticator.Title:Requiere contraseÃ±a.
+GAuthenticator.Username:Nombre de usuario:
+GAuthenticator.Username_Tooltip:Escriba aquÃ­ su nombre de usuario
+#**************************
+#
+#***** General Messages *****
+# 0 - A String representing the name and method of the class in question.
+General.Apply:Aplicar
+General.Apply_Tooltip:Aplica los ajustes, pero sin salir del cuadro de diÃ¡logo
+General.Browse:Explorar
+General.Cancel:Cancelar
+General.Cancel_Tooltip:Cancela los cambios (no desharÃ¡ ninguno de los cambios que ya se hayan aplicado)
+General.Close:Cerrar
+General.Close_Tooltip:Cierra este cuadro de diÃ¡logo
+General.Edit:Editar valor
+General.Error:Error
+General.No:No
+General.NotSunJava:Proveedor de Java: {0}\nTenga en cuenta que la Interfaz de Bibliotecario ha sido desarrollada y probada con Java de Sun Microsystems
+General.OK:Aceptar
+General.OK_Tooltip:Acepta los cambios actuales y sale del cuadro de diÃ¡logo
+General.Open:Abrir
+General.Outstanding_Processes:<html>La Interfaz de la Biblioteca Digital no se podrÃ¡ cerrar completamente hasta que se haya salido de todos los programas<br>.</html>
+General.Outstanding_Processes_Title:Esperando para salir
+General.Pure_Cancel_Tooltip:Aborta esta acciÃ³n (no se harÃ¡ ningÃºn cambio)
+General.Review_Output:Por favor revise los resultados que estÃ¡n a continuaciÃ³n:
+General.Usage:Uso: {0} <params>\nTodos los parÃ¡metros son opcionales, pero es probable que la Interfaz de la Biblioteca Digital no funcione si -gsdl y -library no se han establecido.\n -gsdl <path>  : Forzar la ruta hacia gsdl\n -library <path> : Ruta hacia cgi-bin\n -mozilla <path> : Habilitada mozilla\n -mirror : Activar los controles para el espejeo de archivos de la web\n -laf [java|windows|motif|mac] : Imagen y apariencia\n -debug : Permite depurar mensajes\n -no_load : No carga una colecciÃ³n abierta previamente\n -load <path> : Carga la colecciÃ³n especificada
+General.View:Ver Valor
+General.Warning:Advertencia
+General.Yes:Si
+#****************************
+#
+#***** GShell *****
+GShell.Build.Auxilary:Creando los archivos auxiliares y poniÃ©ndolos en orden...
+GShell.Build.BuildBegun1:************ Iniciando el proceso de construcciÃ³n de la colecciÃ³n ************
+GShell.Build.BuildCancelled:************** Cancelado **************
+GShell.Build.BuildComplete1:*********** El proceso de construcciÃ³n de la colecciÃ³n ha terminado ***********
+GShell.Build.CompressText:Comprimiendo el texto...
+GShell.Build.Index:Creando un Ã­ndice basado en {0-fuente y nivel del Ã­ndice}...
+GShell.Build.InfoDatabase:Creando una base de datos de informaciÃ³n...
+GShell.Build.Phind:Generando un clasificador Phind...
+GShell.Command:Comando
+GShell.Failure:El comando no se pudo ejecutar.
+GShell.Import.FileNotProcessed:El archivo {0-target file path} fue reconocido pero no pudo ser procesado por ningÃºn plugin.
+GShell.Import.FileNotRecognised:El archivo que se encuentra en {0-ruta del archivo objetivo} no se puede aÃ±adir debido a que su tipo no es reconocible por ninguno de los plugins de Greenstone.
+GShell.Import.FileProcessing:El archivo {0-target file path} estÃ¡ siendo procesado por {1-plugin name}.
+GShell.Import.FileProcessingError:El archivo {0-target file path} generÃ³ un error al ser procesado.
+GShell.Import.ImportBegun1:************ Iniciando el proceso de importaciÃ³n de la colecciÃ³n ************
+GShell.Import.ImportComplete1:*********** El proceso de importaciÃ³n de la colecciÃ³n ha terminado ***********
+GShell.Import.ImportComplete2:{0-nÃºmero de documentos considerados} de los documentos fueron considerados a efecto de ser procesados:
+GShell.Import.ImportComplete2.1:1 documento fue considerado a efecto de ser procesado:
+GShell.Import.ImportComplete.Processed:{0-nÃºmero procesado} se procesaron e incluidos en la colecciÃ³n.
+GShell.Import.ImportComplete.Processed.1:1 fue procesado e incluido en la colecciÃ³n.
+GShell.Import.ImportComplete.Blocked:{0-nÃºmero bloqueado} eran ser aÃ±adidos por los plugins (como por ejemplo las imÃ¡genes de las pÃ¡ginas web).
+GShell.Import.ImportComplete.Blocked.1:1 era ser aÃ±adidos por los plugins (como por ejemplo las imÃ¡genes de las pÃ¡ginas web).
+GShell.Import.ImportComplete.Ignored:{0-nÃºmero ignorado} no eran ser reconocidos por los plugins y son disponibles en la colecciÃ³n.
+GShell.Import.ImportComplete.Ignored.1:1 no era ser reconocidos por los plugins y es disponibles en la colecciÃ³n.
+GShell.Import.ImportComplete.Failed:{0-number failed} rechazados.
+GShell.Import.ImportComplete.Failed.1:1 fue rechazado.
+GShell.Import.ImportComplete3:\n
+GShell.Parsing_Metadata_Complete:ExtracciÃ³n completa de metadatos archivados.
+GShell.Parsing_Metadata_Start:Extrayendo nuevos metadatos de los archivos.
+GShell.Success:Comando completo.
+#*********************
+#
+#***** GUI *****
+# Currently Enabled and Disabled display the same text but in different
+# colours. If necessary this can be changed.
+GUI.Create:Crear
+GUI.Create_Tooltip:Le ayuda a crear su colecciÃ³n por medio del conjunto de programas Greenstone
+GUI.Design:DiseÃ±o
+GUI.Design_Tooltip:DiseÃ±a la funcionalidad y apariencia de su colecciÃ³n
+GUI.Download:Bajar
+GUI.Download_Tooltip:Baja recursos de Internet para su colecciÃ³n
+GUI.Enrich:Enriquecer
+GUI.Enrich_Tooltip:Asigna metadatos a los archivos de su colecciÃ³n
+GUI.Gather:Reunir
+GUI.Gather_Tooltip:Selecciona los archivos que se incluirÃ¡n en su colecciÃ³n
+#***************
+#
+#***** HELP *****
+Help.Contents:Contenido
+Help.Title:PÃ¡ginas de ayuda de la Interfaz de la Biblioteca Digital
+#
+#***** LockFileDialog *****
+LockFileDialog.Cancel_Tooltip:No tome el control del archivo de bloqueo (o la colecciÃ³n no se abrirÃ¡)
+LockFileDialog.Date:Fecha
+LockFileDialog.Error:#error
+LockFileDialog.Lockfile_Message_One:La presencia de un archivo de bloqueo sugiere que esta colecciÃ³n estÃ¡ siendo usada por otra persona.
+LockFileDialog.Lockfile_Message_Two:Â¿Desea tomar el control de este archivo de bloqueo?
+LockFileDialog.Machine:Donde
+LockFileDialog.Name:Nombre
+LockFileDialog.OK_Tooltip:Toma el control del archivo de bloqueo
+LockFileDialog.Title:Se detectÃ³ un archivo de bloqueo
+LockFileDialog.User:Quien
+#********************
+#
+#*****MappingPrompt **********
+MappingPrompt.File:Carpeta
+MappingPrompt.Map:Crear un acceso directo
+MappingPrompt.Name:Nombre
+MappingPrompt.Title:Establecer un acceso directo a la carpeta
+MappingPrompt.Unmap:Eliminar acceso directo
+#*******************
+#
+#***** Menu Options *****
+Menu.Collapse:Cerrar carpeta
+Menu.Edit:Editar
+Menu.Edit_Copy:Copiar (ctrl-c)
+Menu.Edit_Cut:Cortar (ctrl-x)
+Menu.Edit_Paste:Pegar (ctrl-v)
+Menu.Expand:Abrir carpeta
+Menu.Explode_Metadata_Database:Explotar la base de datos de metadatos
+Menu.File:Archivo
+Menu.File_Associations:AsociaciÃ³n de archivos...
+Menu.File_CDimage:Exportar a un CD-ROM/DVD...
+Menu.File_Close:Cerrar
+Menu.File_Delete:Suprimir...
+Menu.File_Exit:Salir
+Menu.File_ExportAs:Exportar...
+Menu.File_New:Nueva...
+Menu.File_Open:Abrir...
+Menu.File_Options:Preferencias...
+Menu.File_Save:Guardar
+Menu.Help:Ayuda
+Menu.Help_About:Acerca de...
+Menu.Metadata_View:Metadatos asignados para {0}
+Menu.Open_Externally:Abrir en un programa externo
+#********************
+#
+#***** MetaAudit *****
+MetaAudit.Close:Cerrar
+MetaAudit.Close_Tooltip:Cierra este cuadro de diÃ¡logo
+MetaAudit.Title:Todos los metadatos
+#*********************
+#
+#***** Metadata *****
+Metadata.Element:Elemento
+Metadata.Value:Valor
+MetadataSet.Files:Archivos de conjunto de metadatos
+#*********************************************
+#
+#******** MetadataImportMappingPrompt *********
+MIMP.Add::AÃ±adir
+MIMP.Add_Tooltip:AÃ±ade el elemento de metadato al conjunto seleccionado
+MIMP.Ignore:Ignorar
+MIMP.Ignore_Tooltip:Ignora este elemento de metadato
+MIMP.Instructions:El elemento de metadato {0} no se puede importar automÃ¡ticamente a la colecciÃ³n. Seleccione un conjunto de metadatos y:\n(1) haga click en âAÃ±adirâ para agregar el metadato a ese conjunto (sÃ³lo si el metadato {0} no se encuentra ya en el conjunto), o\n(2) elija un elemento y haga click en âCombinarâ para importar el metadato {0} a este elemento, o\n(3) ignore este elemento de metadato.
+MIMP.Merge:Combinar
+MIMP.Merge_Tooltip:Mapea el elemento de metadato hacia el elemento especificado en el conjunto seleccionado
+MIMP.Source_Element:Elemento de metadatos origen:
+MIMP.Target_Element:Elemento de metadatos destino:
+MIMP.Target_Set:Conjunto de metadatos destino:
+MIMP.Title:Es necesario combinar los elementos.
+#*****************************
+#
+#***** Mirroring *****
+Mirroring.ClearCache:Borrar CachÃ©
+Mirroring.ClearCache_Tooltip:Borrar todos los archivos descargados
+Mirroring.Download:Bajar
+Mirroring.Download_Tooltip:Inicia una nueva descarga
+Mirroring.Download_Controls:Controles para bajar archivos de Internet
+Mirroring.Download_Depth:Profundidad de la descarga:
+Mirroring.Download_Depth.Zero:Cero
+Mirroring.Download_Depth.Unlimited:Ilimitado
+Mirroring.Download_Depth_Tooltip:CuÃ¡ntos hipervÃ­nculos se bajarÃ¡n al momento de descargar los archivos de Internet
+Mirroring.Download_Embedded:Descargar sÃ³lo texto (omitir imÃ¡genes, hojas de estilo, etc.)
+Mirroring.DownloadJob.Close:Cerrar
+Mirroring.DownloadJob.Close_Tooltip:Quitar este job de la lista, deteniÃ©ndolo si todavÃ­a estÃ¡ en ejecuciÃ³n
+Mirroring.DownloadJob.Downloading:Bajando {0}
+Mirroring.DownloadJob.Download_Complete:Descarga completa
+Mirroring.DownloadJob.Download_Stopped:Descarga detenida
+Mirroring.DownloadJob.Download_Progress:Descarga en ejecuciÃ³n
+Mirroring.DownloadJob.Log:Ver BitÃ¡cora
+Mirroring.DownloadJob.Log_Tooltip:Ver detalles acerca de esta descarga
+Mirroring.DownloadJob.Pause:Pausa
+Mirroring.DownloadJob.Pause_Tooltip:Pausa
+Mirroring.DownloadJob.Resume:Reiniciar
+Mirroring.DownloadJob.Resume_Tooltip:Reiniciar esta descarga
+Mirroring.DownloadJob.Status:{0} bajado de {1} archivos ({2} mensajes de advertencia, {3} errores)
+Mirroring.DownloadJob.Waiting:Esperando para iniciar
+Mirroring.DownloadJob.Waiting_User:Esperando instrucciones
+Mirroring.Higher_Directories:Â¿Desea bajar archivos de carpetas que estÃ©n a un nivel mÃ¡s arriba del url dado?
+Mirroring.Invalid_URL:El URL que se ingresÃ³ no es vÃ¡lido. Por favor corrÃ­jalo.
+Mirroring.Invalid_URL_Title:URL invÃ¡lida
+Mirroring.Preferences:Preferencias...
+Mirroring.Preferences_Tooltip:Habilitar proxy y/o editar la configuraciÃ³n del proxy
+Mirroring.Same_Host:SÃ³lo archivos espejo dentro del mismo sitio
+Mirroring.Source_URL:URL fuente:
+Mirroring.Source_URL_Tooltip:Es el URL que se va a bajar
+#*********************
+#
+#***** Missing EXEC *****
+MissingEXEC.Message:Â¡Cuidado! Usted no podrÃ¡ ver sus nuevas colecciÃ³n dentro de la Interfaz de la Biblioteca Digital a menos que especifique la ruta hacia el servidor web de la Biblioteca Greenstone local. Usted puede ingresarla en este momento en el campo de texto que se encuentra abajo o mÃ¡s adelante por medio del cuadro de Preferencias eligiendo la etiqueta de ConexiÃ³n. Recuerde que para que el url sea vÃ¡lido debe empezar con el protocolo "http://" y terminar con el nombre del ejecutable ("gsdl" para el servidor de la biblioteca local Greenstone, "library" para otros servidores web).
+MissingEXEC.Title:Falta la direcciÃ³n de la Biblioteca Greenstone
+#***** Missing EXEC_GS3 *****
+MissingEXEC_GS3.Message:Â¡AtenciÃ³n! No podrÃ¡ ver las nuevas colecciones con la Interfaz de Bibliotecario a menos que especifique la ruta al entorno Greenstone en el servidor local Tomcat. Puede introducirla ahora en el campo de texto situado debajo, o mÃ¡s tarde en Preferencias, pestaÃ±a ConexiÃ³n. Recuerde que un URL vÃ¡lido debe comenzar con el protocolo "http://" La direcciÃ³n predefinida es http://localhost:8080/gsdl3
+MissingEXEC_GS3.Title:No se encuentra la direcciÃ³n de la Biblioteca Greenstone
+#***** Missing GSDL *****
+MissingGSDL.Message:Â¡Cuidado! Usted no podrÃ¡ tener acceso a todas las funciones de la Interfaz de la Biblioteca Digital a menos que una copia de la Biblioteca Digital Greenstone tambiÃ©n estÃ© instalada. Si usted cree que estÃ¡ recibiendo este mensaje por error, por favor revise su instalaciÃ³n y las rutas especificadas en el archivo de guiones y procesamiento por lotes de la Interfaz de la Biblioteca Digital.
+MissingGSDL.Title:Falta la ruta de conexiÃ³n con Greenstone
+#***** Missing PERL *****
+MissingPERL.Message:Â¡Cuidado! Usted no podrÃ¡ crear nuevas colecciones ni construir las que ya existen a menos que tenga el lenguaje de programaciÃ³n PERL instalado y la Interfaz de la Biblioteca Digital no pudo encontrarlo en su sistema. Si usted cree que estÃ¡ recibiendo este mensaje por error, por favor revise su instalaciÃ³n y las rutas especificadas en el archivo de guiones y procesamiento por lotes de la Interfaz de la Biblioteca Digital.
+MissingPERL.Title:Falta la ruta PERL
+#******* MissingWGET ********
+MissingWGET.Message:AtenciÃ³n! Se ha deshabilitado la capacidad de poner la Web en espejo porque el interfaz del 'Librarian' no pudo localizar una versiÃ³n apropiada de Wget. Si usted cree que estÃ¡ recibiendo este mensaje debido a un error, por favor revise su instalaciÃ³n y las rutas especificadas en el archivo batch o script del 'Librarian'
+MissingWGET.Title:Falta Wget
+#******* MissingImageMagick ********
+MissingImageMagick.Message:AtenciÃ³n! La interfaz del bibliotecario fallÃ³ al ubicar un versiÃ³n apropiada de imageMagick y por lo tanto la imagePlug no funcionarÃ¡
+MissingImageMagick.Title:Falta ImageMagick
+#*****************************
+#
+#***** New Session *****
+NewCollectionPrompt.Base_Collection:Construir esta colecciÃ³n con base en:
+NewCollectionPrompt.Base_Collection_Tooltip:Seleccione una colecciÃ³n existente para basar en ella la nueva colecciÃ³n
+NewCollectionPrompt.Collection_Description:DescripciÃ³n de contenidos:
+#NewCollectionPrompt.Collection_Email:Author's Email:
+NewCollectionPrompt.Collection_Name:Carpeta de la colecciÃ³n:
+#NewCollectionPrompt.Collection_Name_Tooltip:Short collection name, used internally (must be 8 characters or less)
+NewCollectionPrompt.Description_Error:El campo de descripciÃ³n debe llenarse. Por favor corrija.
+NewCollectionPrompt.Error:Error en la nueva colecciÃ³n
+NewCollectionPrompt.Instructions:Para crear una nueva colecciÃ³n llene los campos que estÃ¡n a continuaciÃ³n.
+NewCollectionPrompt.Metadata_Elements:Elementos dentro del conjunto seleccionado:
+NewCollectionPrompt.Metadata_Instructions1:Marque los conjuntos de metadatos que se incluirÃ¡n en su colecciÃ³n.
+NewCollectionPrompt.Metadata_Instructions2:(Recuerde: usted puede aÃ±adir otros mÃ¡s adelante).
+NewCollectionPrompt.Metadata_Title_Existing:Seleccionar conjuntos de metadatos
+#NewCollectionPrompt.Name_Error:You have either failed to enter a name for the collection, or the name you have choosen is already in use. Please correct.
+NewCollectionPrompt.NewCollection:-- Nueva colecciÃ³n --
+NewCollectionPrompt.Select_MDS:Conjuntos de metadatos disponibles:
+NewCollectionPrompt.Title:Crear una nueva colecciÃ³n.
+NewCollectionPrompt.Title_Clash:El tÃ­tulo que usted ha elegido para su colecciÃ³n ya se estÃ¡ usando. Â¿Desea continuar?
+NewCollectionPrompt.Title_Error:El tÃ­tulo debe llenarse. Por favor corrija.
+#***** New Folder OrFilePrompt *****
+NewFolderOrFilePrompt.Default_File_Name:postizo
+NewFolderOrFilePrompt.Default_Folder_Name:nueva carpeta
+NewFolderOrFilePrompt.Destination_Name:Carpeta Destino
+NewFolderOrFilePrompt.File_Name:Nombre del Archivo
+NewFolderOrFilePrompt.File_Name_Tooltip:Dar un nombre para el nuevo archivo
+NewFolderOrFilePrompt.Folder_Name:Nombre de la Carpeta
+NewFolderOrFilePrompt.Folder_Name_Tooltip:Dar un nombre para la nueva carpeta
+NewFolderOrFilePrompt.Title_Folder:Crear una nueva carpeta
+NewFolderOrFilePrompt.Title_File:Crear un nuevo documento postizo
+#***********************
+#
+NoMetadataSetsSelected.Message:Si usted crea la colecciÃ³n en este momento no tendrÃ¡ un conjunto inicial de metadatos y no podrÃ¡ importar o asignar ningÃºn metadato hasta que un conjunto se importe o aÃ±ada a su colecciÃ³n. Â¿Desea continuar?
+NoMetadataSetsSelected.Title:No se ha seleccionado ningÃºn conjunto de metadatos
+#**********************
+#
+#******* OldWGET *******
+NoPluginExpectedToProcessFile.Message:No se encuentra ningÃºn plugin de Greenstone que pueda procesar el archivo "{0}". Compruebe que el archivo tiene la extensiÃ³n correcta. Si la extensiÃ³n es correcta entonces tendrÃ¡ que usar el plugin Unkowm para procesar este archivo.
+NoPluginExpectedToProcessFile.Title:No se encuentra un plugin que pueda procesar el archivo
+#**********************
+#
+#******* OldWGET *******
+OldWGET.Message:AtenciÃ³n! La versiÃ³n de Wget que ha instalado tiene un defecto conocido cuando se manejan archivos espejo que contienen caracteres codificados tales como espacio y tilde en su URL. Aunque este no debe ser un problema, recomendamos instalar Wget 1.9 o posterior
+OldWGET.Title:Wget viejo
+#***********************
+#
+#***** OpenCollectionDialog *****
+OpenCollectionDialog.Available_Collections:Colecciones disponibles
+OpenCollectionDialog.Browse:Explorar
+OpenCollectionDialog.Browse_Tooltip:Elija una colecciÃ³n del espacio de archivos de su computadora
+OpenCollectionDialog.Collection:ColecciÃ³n Greenstone (".col")
+OpenCollectionDialog.Description:DescripciÃ³n de la colecciÃ³n
+OpenCollectionDialog.Locked_Collection:La colecciÃ³n Greenstone ya se estÃ¡ usando
+OpenCollectionDialog.No_Description:Por favor seleccione una colecciÃ³n Greenstone (archivo ".col") para ver su descripciÃ³n.
+OpenCollectionDialog.Normal_Collection:ColecciÃ³n Greenstone
+OpenCollectionDialog.Open:Abrir
+OpenCollectionDialog.Open_Tooltip:Carga la colecciÃ³n seleccionada en la Interfaz de la Biblioteca Digital
+OpenCollectionDialog.Title:Abrir la colecciÃ³n Greenstone
+#**********************
+#
+#***** Options Pane inside CreatePane *****
+OptionsPane.Cancelled:- cancelada
+OptionsPane.LogHistory:Historial de registro
+OptionsPane.Successful:- con Ã©xito
+OptionsPane.Unknown:- desconocido
+OptionsPane.Unsuccessful:- sin Ã©xito
+#*******************
+#
+#***** Preferences *****
+Preferences:Preferencias
+Preferences.Connection:ConexiÃ³n
+Preferences.Connection_Tooltip:Escriba el URL de la Biblioteca Greenstone y configure una conexiÃ³n proxy segÃºn sea necesario
+Preferences.Connection.Library_Path:Ruta de la biblioteca
+Preferences.Connection.Library_Path_GS3:Ruta Web de Greenstone:
+Preferences.Connection.Library_Path_Tooltip:Es el URL del servidor Web Greenstone
+Preferences.Connection.Library_Path_Tooltip_GS3:URL del servidor web de Greenstone
+Preferences.Connection.ProgramCommand:Comando de vista previa:
+Preferences.Connection.ProgramCommand_Tooltip:Es el comando de inicio del programa usado para tener una vista previa de la colecciÃ³n. Recuerde usar %1 para indicar el lugar donde deberÃ¡ insertarse la direcciÃ³n de la colecciÃ³n y usar las marcas de habla donde sea necesario.
+Preferences.Connection.Proxy_Host:Servidor proxy
+Preferences.Connection.Proxy_Host_Tooltip:Es la direcciÃ³n del servidor proxy
+Preferences.Connection.Proxy_Port:Puerto para el servidor proxy
+Preferences.Connection.Proxy_Port_Tooltip:Es el nÃºmero de puerto del servidor proxy
+Preferences.Connection.Servlet:Servlet:
+Preferences.Connection.Servlet_Tooltip:Servlet a utilizar para ver su sitio
+Preferences.Connection.Servlet_Tooltip2:No se ha especificado 'servlet' para este sitio, es posible construir colecciones, pero no podrÃ¡ verlas
+Preferences.Connection.Site:Sitio:
+Preferences.Connection.Site_Tooltip:El sitio en el cual quiere trabajar
+Preferences.Connection.Use_Proxy:Â¿Desea usar la conexiÃ³n del servidor proxy?
+Preferences.General:General
+Preferences.General_Tooltip:Determine algunas preferencias generales
+Preferences.General.Email:E-mail del usuario:
+Preferences.General.Email_Tooltip:La direcciÃ³n de correo electrÃ³nico usada automÃ¡ticamente para cualquier colecciÃ³n creada por medio de GLI.
+Preferences.General.Font:Fuente:
+Preferences.General.Font_Tooltip:La fuente utilizada para el interfaz GLI.
+Preferences.General.Interface_Language:Idioma de la interfaz:
+Preferences.General.Interface_Language_Tooltip:Seleccione el idioma en el que usted desea que aparezcan los controles y la interfaz.
+Preferences.General.Restart_Required:Se debe reiniciar GLI para completar la actualizaciÃ³n de su interfaz.
+Preferences.General.Show_File_Size:Mostrar el tamaÃ±o de los archivos
+Preferences.General.Show_File_Size_Tooltip:Muestra el tamaÃ±o de los archivos junto a cada una de las entradas de las estructuras de archivos en el Ã¡rea de trabajo y en la colecciÃ³n.
+Preferences.General.View_Extracted_Metadata:Ver metadatos extraÃ­dos
+Preferences.General.View_Extracted_Metadata_Tooltip:Muestra los metadatos extraÃ­dos por los plugins de Greenstone en la lista de metadatos de la pantalla Enriquecer
+Preferences.Mode:Modo
+Preferences.Mode_Tooltip:Haga click en una entrada para seleccionar el nivel de operaciÃ³n
+Preferences.Mode.Assistant:Asistente de biblioteca
+Preferences.Mode.Assistant_Description:Utilice esta opciÃ³n para tener acceso a las funciones bÃ¡sicas de la Interfaz de la Biblioteca Digital Greenstone: aÃ±adir documentos y metadatos a las colecciones, crear nuevas colecciones cuya estructura refleje la de colecciones que ya existen y construir colecciones.
+Preferences.Mode.Librarian:Bibliotecario
+Preferences.Mode.Librarian_Description:Este control le da un uso normal de la Interfaz de la Biblioteca Digital Greenstone: crear y diseÃ±ar nuevas colecciones, aÃ±adir documentos y metadatos a las colecciones, diseÃ±ar nuevas colecciones y construir colecciones.
+Preferences.Mode.Systems:Especialista en Sistemas de Bibliotecas
+Preferences.Mode.Systems_Description:Esta opciÃ³n permite el uso completo de la Interfaz de la Biblioteca Digital Greenstone. Para aprovechar todas las funciones disponibles usted deberÃ¡ ser capaz de formular expresiones regulares.
+Preferences.Mode.Expert:Avanzado
+Preferences.Mode.Expert_Description:Este control permite el uso avanzado de la Interfaz de la Biblioteca Digital Greenstone. Se recomienda para usuarios que tienen experiencia con Greenstone y son capaces de resolver problemas que impliquen interpretar la depuraciÃ³n de los resultados de los guiones PERL: Todas las funciones de la Biblioteca Digital estÃ¡n activas.
+Preferences.Warnings:Mensajes de advertencia
+Preferences.Warnings_Tooltip:Activa o desactiva los distintos mensajes de advertencia
+Preferences.Workflow:Flujo de trabajo
+Preferences.Workflow_Tooltip:DiseÃ±e el flujo de trabajo de la interfaz: determine las pantallas que estarÃ¡n activas
+Preferences.Workflow.Create:Crear - Construye la colecciÃ³n por medio del conjunto de programas Greenstone
+Preferences.Workflow.Design:DiseÃ±o - Cambia la apariencia de la colecciÃ³n
+Preferences.Workflow.Download:Bajar - Baja recursos de la Web
+Preferences.Workflow.Enrich:Enriquecer - Enriquece los documentos con metadatos
+Preferences.Workflow.Gather:Reunir - Selecciona los archivos para formar la colecciÃ³n
+Preferences.Workflow.Predefined.Label:Flujos de trabajo predeterminados
+Preferences.Workflow.Title:Marque el cuadro para activar la pantalla
+#**********************
+#
+#**** PreviewCommandDialog *******
+PreviewCommandDialog.Instructions:Ingrese el comando para abrir el programa a fin de tener una vista previa de la colecciÃ³n. Recuerde usar %1 para indicar el lugar donde deberÃ¡ insertarse la direcciÃ³n de la colecciÃ³n y usar las marcas de habla donde sea necesario.
+PreviewCommandDialog.Title:Comando de vista previa
+#**********************
+#
+#***** Save Collection Box *****
+SaveCollectionBox.File_Name:Nombre del archivo:
+SaveCollectionBox.Files_Of_Type:Archivos de tipo:
+SaveCollectionBox.Look_In:Visita rÃ¡pida:
+#**********************
+#
+#***** Save Progress Box *******
+SaveProgressDialog.Title:Guardando la colecciÃ³n
+#*******************************
+#
+Server.QuitManual:La Interfaz de la Biblioteca Digital no pudo cerrar el servidor local\n de forma automÃ¡tica. Por favor salga manualmente del servidor\n haciendo click en el icono en forma de tache o cruz que se encuentra en el Ã¡ngulo superior\n derecho de la pantalla y luego haga click en Aceptar.
+Server.QuitTimeOut:La biblioteca local Greenstone no ha respondido durante los Ãºltimos sesenta segundos a la\n instrucciÃ³n de cerrar. Â¿Desea\n esperar otro minuto?
+#
+#***** Sources *****
+Source.General:General
+#*******************
+#
+#***** TitleClash *****
+TitleClashes.Message:El tÃ­tulo que usted ha elegido para su colecciÃ³n ya se estÃ¡ usando. Â¿Desea continuar?
+TitleClashes.Title:Este tÃ­tulo ya existe
+#**********************
+#
+#***** Trees *****
+Tree.DownloadedFiles:Archivos Descargados
+Tree.Files:archivos
+Tree.Home:Carpeta principal ({0})
+Tree.Root:Espacio de archivos local
+Tree.World:Documentos en las Colecciones Greenstone
+#***********************
+#
+#***** Warning Dialog *****
+WarningDialog.Dont_Show_Again:No mostrar este aviso otra vez.
+WarningDialog.Dont_Show_Again_Message:No mostrar este mensaje otra vez
+WarningDialog.Invalid_Value:El valor que usted ha ingresado en el campo de valores\n no es vÃ¡lido para esta propiedad.
+WarningDialog.Value:Ingrese el valor:
+#
+#****** WGet *****
+WGet.Prompt:Cliente de Espejeo Wget
+#
+#****** Workflows *****
+Workflow.AllPanels:Todos los paneles
+Workflow.LocalSourceCollectionBuilding:Construyendo la colecciÃ³n de fuente local
+Workflow.DocumentEnriching:Enriqueciendo el documento
+
+GEMS.Already_Loaded_Set_Error:El conjunto de metadatos seleccionado ya estÃ¡ abierto.
+GEMS.Element_Already_Exists:Ya existe un elemento con ese nombre
+GEMS.Set_Already_Exists:Un conjunto con este namespace ya existe
+GEMS.Cannot_Delete_Core_Sets_Error:No puede borrar un conjunto de metadatos fundamental de GLI.
+
+GEMS.Preferences.Selected_Languages_Tooltip:Seleccionar los lenguajes a mostrar:
+
+GEMS.Add_Attribute:AÃ±adir atributo
+GEMS.Add_Attribute_Tooltip:Le aÃ±ade un nuevo atributo al elemento seleccionado
+GEMS.Add_Element:AÃ±adir elemento
+GEMS.Add_Element_Tooltip:Le aÃ±ade un nuevo elemento al conjunto seleccionado
+GEMS.Add_Subelement:Agregar subelemento
+GEMS.Add_Subelement_Tooltip:Agregar un  nuevo subelemento al elemento seleccionado
+GEMS.Add_Set:AÃ±adir conjunto
+GEMS.Attribute:Atributo
+GEMS.Attribute_Already_Exists:Este atributo ya existe.
+GEMS.Attribute_Name_Tooltip:Es el nombre del nuevo atributo
+GEMS.Attribute_Language_Tooltip:Es el idioma del nuevo atributo
+GEMS.Attribute_Value_Tooltip:Es el valor del nuevo atributo
+GEMS.Attributes:Atributos
+GEMS.Cannot_Undo:(esta acciÃ³n no se puede deshacer)
+GEMS.Cannot_Add_Elements_To_Greenstone_MDS:No se pueden aÃ±adir manualmente elementos a los Metadatos Greenstone. En caso\n necesario, construya un nuevo conjunto y aÃ±Ã¡dale el nuevo elemento.
+GEMS.Confirm_Exit_Save:Â¿Deasea salvar antes de salir?
+GEMS.Confirm_Exit_Save_Title:Â¿Salvar Antes de Salir?
+GEMS.Confirm_Removal:Â¿EstÃ¡ seguro de que desea eliminar este {0}?
+GEMS.Confirm_Removal_Title:Â¿EstÃ¡ seguro de querer eliminarlo?
+GEMS.Edit_Attribute:Editar atributo
+GEMS.Edit_Value:Editar valor
+GEMS.Edit_Value_Tooltip:Cambia el valor seleccionado
+GEMS.Element:Elemento
+GEMS.Element_Name_Tooltip:Es el nombre del nuevo elemento
+GEMS.Element_Details:Detalles del elemento de metadato
+GEMS.Language:Idioma
+GEMS.Language_Code:Idioma
+GEMS.Name:Nombre
+GEMS.Namespace:Indicador del conjunto
+GEMS.New_Name:Nuevo Nombre
+GEMS.No_Description:No se encontrÃ³ la descripciÃ³n.
+GEMS.No_Name:No se encontrÃ³ el nombre.
+GEMS.Open_Set:Conjunto Abierto
+GEMS.Remove_Attribute:Remover atributo
+GEMS.Remove_Attribute_Tooltip:Elimina el atributo seleccionado
+GEMS.Remove_Element:Remover elemento
+GEMS.Remove_Element_Tooltip:Elimina el elemento seleccionado del conjunto
+GEMS.Remove_Set:Remover conjunto
+GEMS.Remove_Set_Tooltip:Elimina el conjunto seleccionado
+GEMS.Rename_Element:Renombrar elemento
+GEMS.Rename_Element_Tooltip:Nuevo nombre del elemento
+GEMS.Rename_Name_Tooltip:Nuevo nombre del conjunto de metadatos
+GEMS.Rename_Namespace_Tooltip:Espacio de nombres Ãºnico del conjunto de metadatos
+GEMS.Rename_Set:Renombrar conjunto
+GEMS.Rename_Set_Tooltip:Renombrar el conjunto de metadatos
+GEMS.Set:Conjunto
+GEMS.Set_Details:Detalles del conjunto de metadatos
+GEMS.Set_Name_Tooltip:Es el nombre del nuevo conjunto de metadatos
+GEMS.Set_Namespace_Tooltip:Es un indicador Ãºnico para el nuevo conjunto de metadatos
+GEMS.Subelement_Name_Tooltip:Nombre del nuevo subelemento
+GEMS.Subelement_Already_Exists:Ya existe un subelemento con este nombre.
+GEMS.Target:Elemento
+GEMS.Title:Editar conjuntos de metadatos
+GEMS.Value:Valor
+GEMS.Values:Valores
+GEMS.inheritMetadataSet:Heredar del conjunto de metadatos:
+GEMS.Add_Set.No_Inherit:No heredar
Index: /tags/gsdl-2_61-distribution/gli/classes/dictionary_lv.properties
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/dictionary_lv.properties	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/dictionary_lv.properties	(revision 10506)
@@ -0,0 +1,1016 @@
+#*******************
+#
+#***** AboutDialog *****
+AboutDialog.Acknowledgement:PateicÄ«bas par programmÄm, paketÄm vai klasÄm...
+AboutDialog.Date:(Augusts 2005)
+AboutDialog.Item0:Xerces Java 1' no The Apache Software Foundation (http://www.apache.org/)
+AboutDialog.Item2:WGet' no Free Software Foundation, Inc. (http://www.gnu.org/software/wget/wget.html)
+AboutDialog.Item3:qflib' no Quality First Software GmbH. (http://www.qfs.de/en/qflib/index.html)
+AboutDialog.Item4:ExtensionFileFilter.class'  Bruno Dumon un lÄ«dzstrÄdnieki (http://pollo.sourceforge.net/)
+AboutDialog.Item5:KÄ aizliegt datnes pÄrdÄvÄÅ¡anu datnes izvÄlnÄ' - vladi21 (http://www.experts-exchange.com/)
+AboutDialog.Item6:Autoscrolling' - Java Swing pateicoties Robert Eckstein, Marc Loy & Dave Wood (http://www.oreilly.com/catalog/jswing/chapter/dnd.beta.pdf)
+AboutDialog.Item7:Add ghosted drag images to your JTrees' - pateicoties Andrew J. Armstrong (http://www.javaworld.com/javaworld/javatips/jw-javatip114.html)
+AboutDialog.Item8:NovÄrsta nepatÄ«kama java.prefs kÄŒÅ«da, ja jums nav administrÄtora pieejas' - pateicoties Walter Schatz
+AboutDialog.Java_Req:Java ir Sun Microsystems Inc. firmas zÄ«me. JRE tiek distribÅ«tÄta pie Papildus Licences NosacÄ«jumiem (Supplemental License Terms), kura atrodama uz http://java.sun.com/j2se/1.4.1/j2re-1_4_1_02-license.html
+AboutDialog.Java_Req_One:Å is produkts iekÄŒauj kodus licencÄtas RSA Security, Inc.
+AboutDialog.Java_Req_Two:DaÅŸas programmatÅ«ras daÄŒas ir IBM licencÄtas un pieejamas uz http\://oss.software.ibm.com/icu4j/
+AboutDialog.Thanks:ArÄ« pateicamies tiem, kuri publicÄja noderÄ«gu informÄciju par java uz web...
+AboutDialog.Title:Par...
+AboutDialog.Title_One:Greenstone BibliotekÄra Interfeiss (GBI)
+AboutDialog.Title_Two:Greenstone DigitÄlÄ BibliotÄka, Waikato UniversitÄte
+AboutDialog.Copyright:Copyright (C) 2003 New Zealand Digital Library Project
+AboutDialog.Copyright_Two:PublicÄts zem GPL. VairÄk skatÄ«t LICENSE.txt.
+#***********************
+#
+#***** Audit Table *****
+AuditTable.File:Datne
+#***********************
+#
+#***** Auto Filter *****
+Autofilter.AND:UN
+Autofilter.Ascending:PieaugoÅ¡s
+Autofilter.Case_Sensitive:SakritÄ«bas GadÄ«jums
+Autofilter.Custom_Filter:Uzlabots
+Autofilter.Descending:DilstoÅ¡s
+Autofilter.Filter_By_Value:VienkÄrÅ¡s
+Autofilter.Name:Kolonnas VÄrds
+Autofilter.None:NekÄds
+Autofilter.Operator:NosacÄ«jums
+Autofilter.OR:VAI
+Autofilter.Order:SakÄrtoÅ¡ana
+Autofilter.Order_Tooltip:SakÄrtot sakrÄ«toÅ¡os elementus Å¡ÄdÄ secÄ«bÄ
+Autofilter.Remove:NoÅemt Filtru
+Autofilter.Remove_Tooltip:NoÅemt Å¡o filtru no tabulas kolonnas
+Autofilter.Set:Uzdot Filtru
+Autofilter.Set_Tooltip:Pievienot Å¡o filtru tabulas kolonnai
+Autofilter.Table_Header_Tooltip:FiltrÄt pÄc {0}
+Autofilter.Title:Metadatu Autofiltrs
+Autofilter.eqeq:vienlÄ«dzÄ«gs
+Autofilter.!eq:does not equal
+Autofilter.<:is less than
+Autofilter.<eq:is less than or equal to
+Autofilter.>:is greater than
+Autofilter.>eq:is greater than or equal to
+Autofilter.^:starts with
+Autofilter.!^:does not start with
+Autofilter.$:ends with
+Autofilter.!$:does not end with
+Autofilter.?:contains
+Autofilter.!?:does not contain
+#
+#     ********************************************************
+#     *************** Collection Design Module ***************
+#     ********************************************************
+#     * The dictionary  phrases  used in the creation of the *
+#     * Colection  Design  Module. Note that we  still  have *
+#     * access  to the format  arguments (argument  32+) for *
+#     * html formatting.                                     *
+#     ********************************************************
+CDM.ArgumentConfiguration.Add:Pievienot
+CDM.ArgumentConfiguration.Bad_Integer:<html>Arguments '{0}' prasa veselu skaitli,<br>bet ne vesels skaitlis var bÅ«t analizÄts no {1}.</html>
+CDM.ArgumentConfiguration.Custom_Header:IestatÄ«Å¡ana
+CDM.ArgumentConfiguration.Custom:IestatÄ«Å¡anas Argumenti:
+CDM.ArgumentConfiguration.Error_Title:KÄŒÅ«da Argumentos
+CDM.ArgumentConfiguration.Header:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>LÅ«dzu konfigurÄt argumentus priekÅ¡ {0}.</CENTER></FONT></STRONG></HTML>
+CDM.ArgumentConfiguration.No_Value:Arguments '{0}'  prasa vÄrtÄ«bu, bet tÄ nav norÄdÄ«ta.
+CDM.ArgumentConfiguration.Remove:NoÅemt
+CDM.ArgumentConfiguration.Required_Argument:Argumentam '{0}' jÄbÅ«t norÄdÄ«ta vÄrtÄ«ba.
+CDM.ArgumentConfiguration.Title:Argumentu KonfigurÄÅ¡ana
+CDM.ClassifierManager.Add:Pievienot Klasifikatoru
+CDM.ClassifierManager.Add_Tooltip:Lietot norÄdÄ«to klasifikatoru ar Å¡o kolekciju
+CDM.ClassifierManager.Assigned:PaÅ¡laik PieÅ¡Ä·irtie Klasifikatori
+CDM.ClassifierManager.Classifier:IzvÄlieties klsifikatoru, ko pievienot:
+CDM.ClassifierManager.Classifier_Tooltip:Klasifikatori pieejami lietoÅ¡anai kolekcijÄ
+CDM.ClassifierManager.Classifier_Exists:Å is klasifikators ir jau nozÄ«mÄts Å¡ai kolekcijai.
+CDM.ClassifierManager.Classifier_Str:klasifikators
+CDM.ClassifierManager.Classifier_XML_Parse_Failed:NespÄju noteikt argumentus {0}\nklasifikatoram. LÅ«dzu pÄrliecinieties, ka klasifikators\nnodroÅ¡ina -xml karodziÅu, palaiÅŸot classinfo.pl skriptu\nlÄ«dzÄ«gi, ka skripta pluginfo.pl gadÄ«jumÄ,\nkÄ aprakstÄ«ts dokumentÄ Greenstone Developers Guide sekcijÄ 2.1.
+CDM.ClassifierManager.Configure:KonfigurÄt Klasifikatoru
+CDM.ClassifierManager.Configure_Tooltip:IzvÄlÄtÄ klasifikÄtora opciju maiÅa
+CDM.ClassifierManager.Controls:RediÄ£ÄÅ¡anas Kontrole
+CDM.ClassifierManager.Instructions:Izmantojiet Å¡o paneli lai pevienotu, noÅemtu vai konfigurÄtu klasifikatorus jÅ«su kolekcijÄ. Lai pievienotu klasifikatoru, izvÄlieties to no kombinÄtÄ saraksta\n un noklikÅ¡Ä·iniet 'Pievienot Klasifikatoru'. Lai noÅemtu klasifikatoru, izvÄlieties to no nozÄ«mÄto klasifikatoru\n saraksta un noklikÅ¡Ä·iniet 'NoÅemt Klasifikatoru'.\nLai konfigurÄtu klasifikatoru, izvÄlieties to no nozÄ«mÄto klasifikatoru saraksta, un noklikÅ¡Ä·iniet 'KonfigurÄt Klasifikatoru'.\n\nKad jÅ«s konfigurÄjiet klasifikatoru, tad parÄdÄs rullslejas argumentu saraksts. \nIzvÄlieties (atÄŒaujot) argumentus no saraksta, kuriem jÅ«s vÄlaties ievadÄ«t vai izvÄlÄties nepiecieÅ¡amÄs vÄrtÄ«bas.
+CDM.ClassifierManager.Remove:NoÅemt Klasifikatoru
+CDM.ClassifierManager.Remove_Tooltip:NoÅemt izvÄlÄto klasifikatoru no saraksta
+CDM.ClassifierManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Klasifikatora IzvÄle & KonfigurÄÅ¡ana</CENTER></FONT></STRONG></HTML>
+CDM.ClassifierManager.Parsing.Message:Dizaina rÄ«ks ielÄdÄ klasifikatoru informÄciju.
+CDM.ClassifierManager.Parsing.Title:Klasifikatoru IelÄdÄÅ¡ana
+CDM.FormatManager.Add:Pievienot FormÄtu
+CDM.FormatManager.Add_Tooltip:Izmantot specificÄto formÄta komandu ar kolekciju
+CDM.FormatManager.Assigned_Formats:PaÅ¡laik NozÄ«mÄtÄs FormÄta Komandas
+CDM.FormatManager.Editor:HTML FormÄta Rinda
+CDM.FormatManager.Editor_Tooltip:Ievadiet formÄta komandu Å¡eit
+CDM.FormatManager.Editing_Controls:RediÄ£ÄÅ¡anas Kontrole
+CDM.FormatManager.Enabled:AtÄŒauts
+CDM.FormatManager.Feature:IzvÄlÄties PazÄ«mi
+CDM.FormatManager.Feature_Tooltip:PazÄ«me kuru formatÄt
+CDM.FormatManager.Insert:Iespraust
+CDM.FormatManager.Insert_Tooltip:Iespraust izvÄlÄto mainÄ«go formÄta komandÄ
+CDM.FormatManager.Instructions:Web lappas, kuras jÅ«s redzat izmantojot Greenstone, nav iepriekÅ¡ saglabÄtas, bet tiek Ä£enerÄtas 'lidojumÄ', t.i., to pieprasÄ«Å¡anas brÄ«dÄ«. FormÄta komandas tiek izmantotas, lai izmainÄ«tu Ä£enerÄto lapu izskatu. DaÅŸi ir pÄrslÄgi (switches), kuri kontrolÄ dokumenta vai tÄ daÄŒas atrÄdÄ«Å¡anu; citi ir vairÄk komplicÄti un prasa html kodus kÄ argumentus.\nLai pievienotu formÄta komandu, izvÄlieties to no âpazÄ«mjuâ saraksta. Ja Äªsts/NeÄ«sts (True/False) opciju panelis parÄdÄs, tad izvÄlieties stÄvokli noklikÅ¡Ä·inot atbilstoÅ¡o pogu. Ja parÄdÄs panelis saturoÅ¡s kontroles âIetekmÄtÄ PazÄ«meâ un âRediÄ£Ät FormÄta Rindasâ, jums nepiecieÅ¡ams ievadÄ«t html tekstu. JÅ«s varat iekÄŒaut esoÅ¡os mainÄ«gos izvÄloties tos no saraksta.\n Kad jÅ«s esat veicis jÅ«su izmaiÅas, nospiediet âPievienot FormÄtuâ, lai to pievienotu konfigurÄcijas datnÄ (fails).\n NoÅemiet formÄta komandu, izvÄloties to no saraksta âNozÄ«mÄtÄs FormÄta Komandasâ un noklikÅ¡Ä·inot uz âNoÅemt FormÄtuâ pogas.
+CDM.FormatManager.Part:IetekmÄtÄ Komponente
+CDM.FormatManager.Part_Tooltip:IzvÄlÄtÄs pazÄ«mes aspekts, ko formatÄt
+CDM.FormatManager.Remove:NoÅemt FormÄtu
+CDM.FormatManager.Remove_Tooltip:NoÅemt izvÄlÄto formÄta komandu no saraksta
+CDM.FormatManager.Replace:NomainÄ«t FormÄtu
+CDM.FormatManager.Replace_Tooltip:AktualizÄt izvÄlÄto formÄta komandu
+CDM.FormatManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>FormÄta Komandas</CENTER></FONT></STRONG></HTML>
+CDM.FormatManager.Variable:MainÄ«gie
+CDM.FormatManager.Variable_Tooltip:MainÄ«gie pieejami izmantoÅ¡anai formÄta komandÄ
+CDM.General.Access:Å ai kolekcijai jÄbÅ«t publiski pieejamai
+CDM.General.Beta:Å Ä« kolekcija tiek vÄl konstruÄta
+CDM.General.Browser_Title:IzvÄlieties AttÄlu
+CDM.General.Collection_Extra:Kolekcijas apraksts:
+CDM.General.Collection_Extra_Tooltip:Kolekcijas satura un nodoma apraksts
+CDM.General.Collection_Name:Kolekcijas nosaukums:
+CDM.General.Collection_Name_Tooltip:Kolekcijas nosaukums
+CDM.General.Copy_Image:Lai Å¡o attÄlu (ikonu) izmantotu jÅ«su kolekcijÄ\ndatnÄm (failiem) jÄbÅ«t nokopÄtÄm images mapÄ. IzpildÄ«t?
+CDM.General.Email.Creator:Autora epasts
+CDM.General.Email.Creator_Tooltip:Kolekcijas autora e-pasta adrese
+CDM.General.Email.Maintainer:AtbalstÄ«tÄja epasts
+CDM.General.Email.Maintainer_Tooltip:Kolekcijas atbalstÄ«tÄja (apkalpotÄja) e-patsta adrese
+CDM.General.Icon_Collection:URL uz 'Par' lapas ikonu:
+CDM.General.Icon_Collection_Tooltip:URL uz attÄlu (ikonu), ko attÄlot kolekcijas 'Par' lapÄ
+CDM.General.Icon_Collection_Small:URL uz 'mÄjas' lapas ikonu:
+CDM.General.Icon_Collection_Small_Tooltip:URL uz attÄlu (ikonu), ko attÄlot bibliotÄkas mÄjas lapÄ
+CDM.General.Image_Copy_Failed:AtgadÄ«jÄs kÄŒÅ«da, kura neÄŒauj jÅ«su izvÄlÄto attÄlu(s) nokopÄt.\nLÅ«dzu mÄÄ£iniet nokopÄt attÄlu(s) uz jÅ«su kolekcijas images mapi manuÄli.
+CDM.General.Image_Filter:AttÄli (gifs, jpgs un pngs)
+CDM.General.Instructions:BibliotekÄra Interfeisa dizaina sekcija ÄŒauj jums kontrolÄt daudzus jÅ«su kolekcijas izskata aspektus. Dizains is sadalÄ«ts daudzÄs atseviÅ¡Ä·Äs sekcijÄs. Å Ä« sekcija satur vispÄrÄ«gas opcijas un iestatÄ«jumus. Lai izvÄlÄtos citu sekciju, noklikÅ¡Ä·iniet uz tÄs nosaukuma sarakstÄ pa kreisi.
+CDM.General.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>VispÄrÄ«gas Opcijas</CENTER></FONT></STRONG></HTML>
+CDM.GUI.Classifiers:PÄrlÅ«koÅ¡anas Klasifikatori
+CDM.GUI.Design_Topics:Dezaina Sekcijas
+CDM.GUI.Formats:FormatizÄÅ¡ana
+CDM.GUI.General:VispÄrÄ«gi
+CDM.GUI.Indexes:MeklÄÅ¡anas Indeksi
+CDM.GUI.MetadataSets:Metadatu Kopas
+CDM.GUI.Plugins:Dokumentu SpraudÅi
+CDM.GUI.Root:CDM_ROOT
+CDM.GUI.SearchTypes:MeklÄÅ¡anas Tipi
+CDM.GUI.Subcollections:SadalÄ«jumu Indeksi
+CDM.GUI.SuperCollection:Starp-Kolekciju MeklÄÅ¡ana
+CDM.GUI.Translation:Teksta TulkoÅ¡ana
+CDM.IndexManager.Add_Index:Pievienot Indeksu
+CDM.IndexManager.Add_Index_Tooltip:Izveidot specifisku indeksu Å¡ai kolekcijai
+CDM.IndexManager.Default_Index_Indicator:[NoklusÄjuma Indeks]
+CDM.IndexManager.Document:dokuments
+CDM.IndexManager.Index_Exists:Å is indeks esot jau bijis nozÄ«mÄts dotai kolekcijai.
+CDM.IndexManager.Index_Name:Indeksa VÄrds:
+CDM.IndexManager.Index_Name_Tooltip:UnikÄls nosaukums jaunam indeksam
+CDM.IndexManager.Indexes:NozÄ«mÄtie Indeksi
+CDM.IndexManager.Instructions:Å eit jÅ«s izvÄlÄties, kÄdi meklÄÅ¡anas indeksi bÅ«s kolekcijai.\nLai pievienotu jaunu indeksu, izvÄlieties, kÄds materiÄls tiks indeksÄts, indeksa lÄ«meni, un noklikÅ¡Ä·iniet âPievienot Indeksuâ.\nLai noÅemtu indeksu, izvÄlieties to no nozÄ«mÄto indeksu saraksta un noklikÅ¡Ä·iniet âNoÅemt Indeksuâ.\nLai uzstÄdÄ«tu indeksu pÄc noklusÄÅ¡anas, izvÄlieties to no nozÄ«mÄto indeksu saraksta un noklikÅ¡Ä·iniet âUzdot NoklusÄjuma Indeksuâ.
+CDM.IndexManager.Level:LÄ«menÄ«:
+CDM.IndexManager.Level_Exists:Å is lÄ«menis jau esot ticis nozÄ«mÄts dotai kolekcijai.
+CDM.IndexManager.Level_Tooltip:Dokumenta lÄ«menis uz kura veidot indeksu
+CDM.IndexManager.MGPP.Add_All_Metadata:Pievienot Visu
+CDM.IndexManager.MGPP.Add_All_Metadata_Tooltip:Izveidot atseviÅ¡Ä·u indeksu katram atseviÅ¡Ä·i pieejamam avotam, izmantojot avotu kÄ indeksa vÄrdu
+CDM.IndexManager.MGPP.Add_Level:Pievienot LÄ«meni
+CDM.IndexManager.MGPP.Add_Level_Tooltip:Izveidot indeksu uz norÄdÄ«to lÄ«meni
+CDM.IndexManager.MGPP.Current_Indexes:Patreiz NozÄ«mÄtie Indeksi
+CDM.IndexManager.MGPP.Current_Levels:Patreiz NozÄ«mÄtie LÄ«meÅi
+CDM.IndexManager.MGPP.Index:Indeksa Avots:
+CDM.IndexManager.MGPP.Index_Tooltip:Metadatu elements uz kura izveidot indeksu
+CDM.IndexManager.MGPP.Indexes:AdministrÄt Indeksus
+CDM.IndexManager.MGPP.Instructions:Å eit jÅ«s nosakÄt, kÄdi bÅ«s meklÄÅ¡anas indeksi kolekcijai.\nLai pievienotu jaunu indeksu, ievadiet indeksa unikÄlo vÄrdu, izvÄlieties materiÄlu/metadatus, kuri tiks indeksÄti, un noklikÅ¡Ä·iniet âPievienot Indeksuâ.\nJa jÅ«s vÄlaties pievienot indeksus visiem pieejamiem avotiem, tad noklikÅ¡Ä·iniet âPievienot Visusâ (katra indeksa vÄrds pÄc noklusÄÅ¡anas bÅ«s avota vÄrds). IevÄrojiet, ka tas atÅ¡Ä·iras no âVisiLaukiâ avota pievienoÅ¡anas, jo indeksu secÄ«ba ir svarÄ«ga.\nJa jÅ«s vÄlaties rediÄ£Ät kÄdu indeksu, izvÄlieties to no patreiz nozÄ«mÄto indeksu saraksta, rediÄ£Äjiet to, un tad noklikÅ¡Ä·iniet âNomainÄ«t Indeksuâ, lai nomainÄ«tu veco.\nLai noÅemtu indeksu, izvÄlieties to no patreiz nozÄ«mÄto indeksu saraksta un  noklikÅ¡Ä·iniet âNoÅemt Indeksuâ.
+CDM.IndexManager.MGPP.Level:LÄ«meÅa Avots:
+CDM.IndexManager.MGPP.Level_Name:LÄ«meÅa VÄrds:
+CDM.IndexManager.MGPP.Level_Name_Tooltip:UnikÄls vÄrds jauna lÄ«meÅa indeksam
+CDM.IndexManager.MGPP.Levels:AdministrÄt LÄ«meÅus
+CDM.IndexManager.MGPP.Remove_Level:NoÅemt LÄ«meni
+CDM.IndexManager.MGPP.Remove_Level_Tooltip:NoÅemt izvÄlÄtÄ lÄ«meÅa indeksu
+CDM.IndexManager.MGPP.Replace_Index:NomainÄ«t Indeksu
+CDM.IndexManager.MGPP.Replace_Index_Tooltip:AktualizÄt izvÄlÄto indeksu
+CDM.IndexManager.MGPP.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Indeksa Un LÄ«meÅa IzvÄle</CENTER></FONT></STRONG></HTML>
+CDM.IndexManager.Paragraph:paragrÄfs
+CDM.IndexManager.Remove_Index:NoÅemt Indeksu
+CDM.IndexManager.Remove_Index_Tooltip:NoÅemt izvÄlÄto indeksu no saraksta
+CDM.IndexManager.Section:sekcija
+CDM.IndexManager.Set_Default:Uzdot NoklusÄjuma Indeksu
+CDM.IndexManager.Set_Default_Tooltip:Uzdot izvÄlÄto indeksu, kÄ indeksu pÄc noklusÄjuma
+CDM.IndexManager.Source:Izveidot indeksu uz:
+CDM.IndexManager.Source_Tooltip:Metadatu elementi uz kuriem izveidot indeksus
+CDM.IndexManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Indeksu IzvÄle</CENTER></FONT></STRONG></HTML>
+CDM.LanguageManager.Add:Pievienot Valodu
+CDM.LanguageManager.Add_Tooltip:Pievienot norÄdÄ«to valodu sarakstam
+CDM.LanguageManager.Assigned_Languages:NozÄ«mÄtÄs Valodas
+CDM.LanguageManager.Default_Language:NoklusÄjuma Valoda
+CDM.LanguageManager.Remove:NoÅemt Valodu
+CDM.LanguageManager.Remove_Tooltip:NoÅemt izvÄlÄto valodu no saraksta
+CDM.LanguageManager.Selector:Valoda ko pievienot:
+CDM.LanguageManager.Selector_Tooltip:Valoda uz kuras izveidot sadalÄ«juma indeksu
+CDM.LanguageManager.Set_Default:Uzdot NoklusÄjumu
+CDM.LanguageManager.Set_Default_Tooltip:Uzdot izvÄlÄto valodu kÄ noklusÄjumu
+CDM.MetadataSetManager.Add:Pievienot Metadatu Kopu
+CDM.MetadataSetManager.Add_Tooltip:Pievienot kolekcijai jaunu metadatu kopu.
+CDM.MetadataSetManager.Edit:RediÄ£Ät Metadatu Kopu
+CDM.MetadataSetManager.Edit_Message:Metadatu kopas var bÅ«t rediÄ£Ätas, izmantojot Greenstone Metadatu Kopu Redaktoru GEMS (Greenstone Editor for Metadata Sets).\nPalaidiet GEMS ar gems.bat (Windows) vai gems.sh (Linux) no Greenstone instalÄcijas mapes ar nosaukumu gli.
+CDM.MetadataSetManager.Edit_Message_Title:Metadatu Kopu RediÄ£ÄÅ¡ana
+CDM.MetadataSetManager.Edit_Tooltip:RediÄ£Ät izvÄlÄto metadatu kopu.
+CDM.MetadataSetManager.Elements:Elementi izvÄlÄtÄ Metadatu KopÄ
+CDM.MetadataSetManager.Instructions:Å ajÄ dizaina skatÄ jÅ«s varat pievienot, konfigurÄt un dzÄst Metadatu Kopas, un definÄt kÄdus elementus tÄs satur jÅ«su kolekcijÄ.
+CDM.MetadataSetManager.Remove:DzÄst Metadatu Kopu
+CDM.MetadataSetManager.Remove_Tooltip:DzÄst izvÄlÄto metadatu kopu no kolekcijas.
+CDM.MetadataSetManager.Sets:PieejamÄs Metadatu Kopas
+CDM.MetadataSetManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Metadatu Kopas</CENTER></FONT></STRONG></HTML>
+CDM.Move.At_Bottom:Nevaru pÄrvietot {0} {1} zemÄk, jo tas jau ir paÅ¡Ä saraksta apakÅ¡Ä.
+CDM.Move.At_Top:Nevaru pÄrvietot {0} {1} augstÄk, jo tas jau ir paÅ¡Ä saraksta virsotnÄ.
+CDM.Move.Cannot:Nevaru pÄrvietot spraudni {0} zemÄk, jo RecPlug un ArcPlug jÄatrodas saraksta paÅ¡Ä apakÅ¡Ä.
+CDM.Move.Fixed:<html>RecPlug un ArcPlug parasti ir nepiecieÅ¡ams bÅ«t pÄdÄjiem un tÄdÄÄŒ ir fiksÄti savÄ vietÄ.<br>Ja jums patiesi vajag mainÄ«t viÅu pozÄ«cijas, tad lÅ«dzu rediÄ£Äjiet collect.cfg datni manuÄli.</html>
+CDM.Move.Move_Down:PÄrvietot ZemÄk
+CDM.Move.Move_Down_Tooltip:PÄrvietot izvÄlÄto elementu zemÄk sarakstÄ
+CDM.Move.Move_Up:PÄrvietot AugstÄk
+CDM.Move.Move_Up_Tooltip:PÄrvietot izvÄlÄto elementu augstÄk sarakstÄ
+CDM.Move.Title:KÄŒÅ«da - Nevaru PÄrvietot
+CDM.PlugInManager.Add:Pievienot Spraudni
+CDM.PlugInManager.Add_Tooltip:Izmantot norÄdÄ«to spraudni Å¡ajÄ kolekcijÄ
+CDM.PlugInManager.Assigned:Patreiz NozÄ«mÄtie SpraudÅi
+CDM.PlugInManager.Configure:KonfigurÄt Spraudni
+CDM.PlugInManager.Configure_Tooltip:IzmainÄ«t opcijas izvÄlÄtam spraudnim
+CDM.PlugInManager.Controls:RediÄ£ÄÅ¡anas Kontrole
+CDM.PlugInManager.Ignore:Nepievienot Spraudni
+CDM.PlugInManager.Ignore_Tooltip:Nepievienot nevienu spraudni Å¡ai kolekcijai.
+CDM.PlugInManager.Instructions:Izmantojiet Å¡o skatu, lai pievienotu, konfigurÄtu vai noÅemtu spraudÅus no jÅ«su kolekcijas. Lai pievienotu spraudni, izvÄlieties vienu no kombinÄtÄ sarasta un noklikÅ¡Ä·iniet âPievienot Spraudniâ.\nLai konfigurÄtu vai noÅemtu (dzÄstu) vienu, izvÄlieties to no pieÅ¡Ä·irto spraudÅu saraksta, un tad:\ni)  Izmainiet tÄ pozÄ«ciju spraudÅu rindÄ noklikÅ¡Ä·inot pogas ar bultÄm. (PiezÄ«me: RecPlug un ArcPlug pozÄ«cijas ir fiksÄtas).\nii)  KonfigurÄjiet to noklikÅ¡Ä·inot âKonfigurÄt Spraudniâ,\niii)  IzdzÄsiet to noklikÅ¡Ä·inot âNoÅemt Spraudniâ.\n\nSpraudÅi tiek konfigurÄti izmantojot uznirstoÅ¡u dialoga logu ar rullslejas argumentu sarakstu. AtÄŒaujiet attiecÄ«gos argumentus un ievadiet vai izvÄlieties vÄrtÄ«bas pÄc vajadzÄ«bas.
+CDM.PlugInManager.PlugIn:IzvÄlieties spraudni ko pievienot:
+CDM.PlugInManager.PlugIn_Tooltip:Pieejamie spraudÅi izmantoÅ¡anai kolekcijÄ
+CDM.PlugInManager.PlugIn_Exists:Å is spraudnis jau esot pievienots Å¡ai kolekcijai.
+CDM.PlugInManager.PlugIn_Str:spraudnis
+CDM.PlugInManager.PlugIn_XML_Parse_Failed:Nevaru noteikt argumentus {0}\nspraudnim. LÅ«dzu pÄrliecinieties, ka spraudnis nodroÅ¡ina\n -xml karodziÅu, palaiÅŸot pluginfo.pl skriptu, kÄ aprakstÄ«ts\ndokumentÄ Greenstone Developers Guide sekcijÄ 2.1.
+CDM.PluginManager.Plugin_Suggestion_Prompt:Nav sagaidÄms, ka kÄds no spraudÅiem Å¡ajÄ kolekcijÄ varÄtu apstrÄdÄt datni â{0}â.SekojoÅ¡ie spraudÅi var bÅ«t izmantoti, lai apstrÄdÄtu Å¡o datni. JÅ«s varat pievienot vienu tagad, izvÄloties to, un nospieÅŸot Pievienot pogu. (JÄpiezÄ«mÄ, ka jÅ«s varat jebkurÄ laikÄ izmainÄ«t spraudÅu sarakstu izmantojot âDokumentu SpraudÅiâ no paneÄŒa Dizains.)
+CDM.PlugInManager.Remove:NoÅemt Spraudni
+CDM.PlugInManager.Remove_Tooltip:DzÄst izvÄlÄto spraudni no saraksta
+CDM.PluginManager.SuggestedPluginListTitle:Ieteicamie spraudÅi datnei
+CDM.PlugInManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>SpraudÅu IzvÄle & KonfigurÄÅ¡ana</CENTER></FONT></STRONG></HTML>
+CDM.PlugInManager.Parsing.Message:Dizaina rÄ«ks ielÄdÄ spraudÅu informÄciju.
+CDM.PlugInManager.Parsing.Title:IelÄdÄ SpraudÅus
+CDM.SearchTypeManager.Add:Pievienot MeklÄÅ¡nas Tipu
+CDM.SearchTypeManager.Add_Tooltip:AtÄŒaut noteiktu meklÄÅ¡anas tipu Å¡ajÄ kolekcijÄ
+CDM.SearchTypeManager.Assigned:Patreiz NozÄ«mÄtie MeklÄÅ¡anas Tipi
+# -- Missing translation: CDM.SearchTypeManager.BuildType_Selection
+# -- Missing translation: CDM.SearchTypeManager.BuildType_Selection_Tooltip
+CDM.SearchTypeManager.Enable:AtÄŒaut PaplaÅ¡inÄtÄs MeklÄÅ¡anas
+CDM.SearchTypeManager.Instructions:MeklÄÅ¡anas tipu definÄÅ¡ana ir paplaÅ¡inÄtÄ iespÄja un tikai pieejama, ja ir atÄŒauta (iezÄ«mÄjot âAtÄŒaut PaplaÅ¡inÄtÄs MeklÄÅ¡anasâ). Ja ir atÄŒauta, tad pÄrÄjÄs kontroles, izvÄlei un meklÄÅ¡anas tipu secÄ«bas izmaiÅai, kÄŒÅ«st pieejamas. IzvÄlieties meklÄÅ¡anas tipu no kombosaraksta un nospiediet âPievienot MeklÄÅ¡anas Tipuâ, ja poga atÄŒauta, lai pievienotu meklÄÅ¡anas tipu. IzvÄlieties eksistÄjoÅ¡o meklÄÅ¡anas tipu no saraksta, un izmantojiet âPÄrvietot AugstÄkâ un âPÄrvietot ZemÄkâ, lai izmainÄ«tu tÄ secÄ«bu sarakstÄ, vai âDzÄst MeklÄÅ¡anas Tipuâ, lai to izdzÄstu.\n\nMeklÄÅ¡anas tipi nosaka kÄda veida meklÄÅ¡anas interfeisam jÄbÅ«t nodroÅ¡inÄtam: formas, meklÄÅ¡anai pÄc lauciÅiem, un/vai vienkÄrÅ¡ai, parastai meklÄÅ¡anai. SecÄ«ba ir svarÄ«ga, jo pirmais sarakstÄ noteiks meklÄÅ¡anas interfeisu pÄc noklusÄÅ¡anas.\n\nSvarÄ«gi arÄ« ir tas, ka atÄŒaujot meklÄÅ¡anas tipus, iespaido arÄ« Indeksu skatu izmaiÅas. MeklÄÅ¡ana pÄc lauciÅiem ir Greenstone jaunÄka iespÄja, un tas prasa citÄdu indeksu informÄciju. Kad meklÄÅ¡anas tipi ir atÄŒauti, visi patreiz esoÅ¡ie indeksi tiek modificÄti uz attiecÄ«giem indeksiem pÄc jaunÄs shÄmas, un otrÄdi, aizliedzot meklÄÅ¡anas tipus, liks GBI censties konvertÄt jaunos indeksus atpakaÄŒ uz veco stilu, bet tas ne vienmÄr var bÅ«t sekmÄ«gi. Å Ädos gadÄ«jumos (nesekmÄ«gos) indeksi tiks izdzÄsti. Abos gadÄ«jumos oriÄ£inÄlÄs indeksu komandas kopija bÅ«s pieejama kÄ komentÄrs konfigurÄcijas datnÄ.
+CDM.SearchTypeManager.Remove:DzÄst MeklÄÅ¡anas Tipu
+CDM.SearchTypeManager.Remove_Tooltip:NeatÄŒaut izvÄlÄto meklÄÅ¡anas tipu ar Å¡o kolekciju
+CDM.SearchTypeManager.SearchType:MeklÄÅ¡anas Tips
+CDM.SearchTypeManager.SearchType_Selection:MeklÄÅ¡anas Tipi:
+CDM.SearchTypeManager.SearchType_Selection_Tooltip:MeklÄÅ¡anas tipi pieejami izmantoÅ¡anai ar Å¡o kolekciju
+CDM.SearchTypeManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>MeklÄÅ¡anas Tipu IzvÄle & SecÄ«ba</CENTER></FONT></STRONG></HTML>
+CDM.SubcollectionManager.Add:Pievienot Filtru
+CDM.SubcollectionManager.Add_Tooltip:Pievienot norÄdÄ«to filtru kolekcijai
+CDM.SubcollectionManager.Assigned:DefinÄtie ApkÅ¡kolekciju Filtri
+CDM.SubcollectionManager.Exclude:IzslÄgt
+CDM.SubcollectionManager.Flags:Uzdodamais karodziÅÅ¡ pie sakritÄ«bas
+CDM.SubcollectionManager.Flags_Tooltip:KarodziÅu regulÄrÄ izteiksme, kura izmantojama pie sakritÄ«bas (piem. "i" reÄ£istrnejÅ«tÄ«gai sakritÄ«bai)
+CDM.SubcollectionManager.Include:IekÄŒaut
+CDM.SubcollectionManager.Inclusive:Ko mÄs darÄm ar datnÄm, kuras sakrÄ«t?
+CDM.SubcollectionManager.Instructions:Izmantojiet Å¡o paneli smalkÄkai indeksu veidoÅ¡anai.\ni)  DefinÄjiet apakÅ¡kolekciju filtrus, kuri parÄda kolekcijas dokumentus pamatojoties uz specificÄtÄm metadatu vÄrtÄ«bÄm. Vienreiz tie definÄti, jÅ«s varat Ä£enerÄt sadalÄ«jumus uz jebkuru iepriekÅ¡ specificÄto indeksu, bÄzÄjoties uz viena vai vairÄkiem no Å¡iem filtriem.\nii)  Ä¢enerÄt indeksu sadalÄ«jumus bÄzÄjoties uz valodas. Tas izfiltrÄs kolekcijas dokumentus tÄ, ka tikai dokumenti norÄdÄ«tajÄ valodÄ tiks iekÄŒauti parÄdÄ«Å¡anai.\nJÄpiezÄ«mÄ, ka summÄrais Ä£enerÄto sadalÄ«jumu skaits ir visu indeksu, apakÅ¡kolekciju filtru un izvÄlÄto valodu kombinÄcija. Divi indeksi ar diviem apakÅ¡kolekciju filtriem divÄs valodÄs dotu iznÄkumÄ astoÅus indeksu sadalÄ«jumus.
+CDM.SubcollectionManager.Language_Controls:NozÄ«mÄt Valodas
+CDM.SubcollectionManager.Match:SakritÄ«bas regulÄrÄ izteiksme:
+CDM.SubcollectionManager.Match_Tooltip:RegulÄrÄ izteiksme, kura definÄ dokumentus apakÅ¡kolekcijÄ
+CDM.SubcollectionManager.Name:ApakÅ¡kolekcijas filtra vÄrds:
+CDM.SubcollectionManager.Name_Tooltip:JaunÄ apakÅ¡kolekcijas filtra nosaukums
+CDM.SubcollectionManager.Partitions_Disabled:Å Ä« iespÄja patreiz ir aizliegta, jo jÅ«s operÄjat {0-Current Mode} reÅŸÄ«mÄ. Tas ir tikai pieejams {1-Systems} un {2-Expert} reÅŸÄ«mos. Lietojiet Datne->IestatÄ«jumi, lai izmainÄ«tu operÄÅ¡anas reÅŸÄ«mus.
+CDM.SubcollectionManager.Remove:NoÅemt Filtru
+CDM.SubcollectionManager.Remove_Tooltip:DzÄst izvÄlÄto filtru no saraksta
+CDM.SubcollectionManager.Replace:Aizvietot Filtru
+CDM.SubcollectionManager.Replace_Tooltip:Aizvietot un aktualizÄt izvÄlÄtÄ filtra detaÄŒas
+CDM.SubcollectionManager.Source:Dokumenta atribÅ«ts pÄc kura jÄsakrÄ«t:
+CDM.SubcollectionManager.Source_Tooltip:Dokumenta atribÅ«ts pÄc kura filtrÄt
+CDM.SubcollectionManager.Subcollection_Controls:DefinÄt Filtrus
+CDM.SubcollectionManager.Subindex_Controls:NozÄ«mÄt SadalÄ«jumus
+CDM.SubcollectionManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>SadalÄ«jumu Indeksi</CENTER></FONT></STRONG></HTML>
+CDM.SubcollectionIndexManager.Add_Subindex:Pieviento SadalÄ«jumu
+CDM.SubcollectionIndexManager.Add_Subindex_Tooltip:Pievienot norÄdÄ«to sadalÄ«jumu Å¡ai kolekcijai
+CDM.SubcollectionIndexManager.Default_Partition_Indicator:[NoklusÄjuma SadalÄ«jums]
+CDM.SubcollectionIndexManager.PartitionName:SadalÄ«juma VÄrds:
+CDM.SubcollectionIndexManager.PartitionName_Tooltip:JaunÄ sadalÄ«juma nosaukums
+CDM.SubcollectionIndexManager.Remove_Subindex:NoÅemt SadalÄ«jumu
+CDM.SubcollectionIndexManager.Remove_Subindex_Tooltip:IzdzÄst izvÄlÄto sadalÄ«jumu no Å¡Ä«s kolekcijas
+CDM.SubcollectionIndexManager.Replace_Subindex:Aizvietot SadalÄ«jumu
+CDM.SubcollectionIndexManager.Replace_Subindex_Tooltip:Azvietot izvÄlÄto sadalÄ«jumu
+CDM.SubcollectionIndexManager.Set_Default_Subindex:Uzdot NoklusÄjumu
+CDM.SubcollectionIndexManager.Set_Default_Subindex_Tooltip:Uzdot izvÄlÄto sadalÄ«jumu bÅ«t pÄc noklusÄjuma
+CDM.SubcollectionIndexManager.Source:Veidot sadalÄ«jumu uz:
+CDM.SubcollectionIndexManager.Source_Tooltip:ApakÅ¡kolekcijas filtri uz kuriem veidot sadalÄ«jumu
+CDM.SubcollectionIndexManager.Subindexes:NozÄ«mÄtie ApakÅ¡kolekcijas SadalÄ«jumi
+CDM.SuperCollectionManager.Instructions:Starp-kolekciju meklÄÅ¡ana nozÄ«mÄ vienu meklÄÅ¡anu, kura veikta pÄr daÅŸÄdÄm kolekcijÄm, it kÄ tÄs bÅ«tu kÄ viena kolekcija. NorÄdiet kolekcijas, kuras ieÄŒaut Å¡ajÄ meklÄÅ¡anÄ, noklikÅ¡Ä·inot uz attiecÄ«gÄs kolekcijas nosaukuma apakÅ¡Ä esoÅ¡ajÄ sarakstÄ. TekoÅ¡Ä kolekcija tiks iekÄŒauta meklÄÅ¡anÄ automÄtiski. \nBRÄªDINÄJUMS: Ja individuÄlÄm kolekcijÄm nav savstarpÄji vienÄdu indeksu ( tajÄ skaitÄ, apakÅ¡kolekciju  un valodas sadalÄ«jumu indeksu), starp-kolekciju meklÄÅ¡ana nedarbosies pareizi. LietotÄjs varÄs tikai meklÄt izmantojot kopÄjos indeksus visÄs izvÄlÄtÄs kolekcijÄs.
+CDM.SuperCollectionManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Starp-Kolekciju MeklÄÅ¡anas KofigurÄÅ¡ana</CENTER></FONT></STRONG></HTML>
+CDM.TranslationManager.Add:Pievienot Tulkojumu
+CDM.TranslationManager.Add_Tooltip:Pievienot specificÄto tulkojumu kolekcijai
+CDM.TranslationManager.Affected_Features:PazÄ«mes
+CDM.TranslationManager.Assigned_Fragments:NozÄ«mÄtie Tulkojumi
+CDM.TranslationManager.Default_Text:SÄkotnÄjs Teksta Fragments
+CDM.TranslationManager.Fragment_Column:Teksta Fragments
+CDM.TranslationManager.Instructions:Izmantojiet Å¡o paneli, lai pÄrskatÄ«tu un nozÄ«mÄtu teksta fragmentu tulkojumus jÅ«su kolekcijai. Vispirms, izvÄlieties ierakstu no pazÄ«mju saraksta (piem. kolekcijas lÄ«meÅa metadatus un klasifikatoru vÄrdus). TÄlÄk, izvÄlieties un rediÄ£Äjiet teksta fragmentu, vai izvÄlieties valodu no kombinÄtÄ saraksta, lai pievienotu jaunu fragmentu citÄ valodÄ. Ievadiet tekstu tukÅ¡Ä (baltÄ) teksta lauciÅÄ, pretim attiecÄ«gam sÄkotnÄja teksta fragmentam. Jebkuras izmaiÅas parÄdÄ«sies kolekcijÄ nekavÄjoties.
+CDM.TranslationManager.Language:Tulkojuma valoda:
+CDM.TranslationManager.Language_Column:Valoda
+CDM.TranslationManager.Language_Tooltip:Valoda uz kuru tiek tulkots
+CDM.TranslationManager.Remove:NoÅemt Tulkojumu
+CDM.TranslationManager.Remove_Tooltip:IzdzÄst izvÄlÄto tulkojumu no kolekcijas
+CDM.TranslationManager.Replace:Aizvietot Tulkojumu
+CDM.TranslationManager.Replace_Tooltip:AktualizÄt (aizvietot) izvÄlÄto tulkojumu
+CDM.TranslationManager.Title:<HTML><STRONG><FONT FACE={FONT} COLOR=Black SIZE=5><CENTER>Teksta Tulkojums</CENTER></FONT></STRONG></HTML>
+CDM.TranslationManager.Translation:Iztulkotais Teksts
+CDM.TranslationManager.Translation_Tooltip:Iztulkota teksta rindu ievadiet Å¡eit
+#*******************
+#
+#***** Collection *****
+Collection.Collection:<HTML><STRONG><FONT FACE={FONT} COLOR=Black>Kolekcija</FONT></STRONG></HTML>
+Collection.Delete_Tooltip:IzdzÄst izvÄlÄtÄs datnes un mapes
+Collection.Filter_Tooltip:IerobeÅŸot datÅu atrÄdÄ«Å¡anu datÅu kokÄ
+Collection.New_Folder_Tooltip:Izveidot jaunu mapi
+Collection.No_Collection:Nav Kolekcijas
+Collection.Stop:Stop
+Collection.Stop_Tooltip:PÄrtraukt datÅu kopÄÅ¡anu
+Collection.Workspace:<HTML><STRONG><FONT FACE={FONT} COLOR=Black>Darbatelpa</FONT></STRONG></HTML>
+#**********************
+#
+#***** CollectionBuilt *****
+CollectionBuilt.Message:Kolekcija esot izveidota un ir gatava priekÅ¡skatÄ«jumam.
+CollectionBuilt.Title:Kolekcijas IzveidoÅ¡anas RezultÄts
+#***************************
+#
+#***** CollectionManager *****
+CollectionManager.Build_Cancelled:Kolekcijas veidoÅ¡ana tikusi anulÄta.
+CollectionManager.Cannot_Create_Collection:AtgadÄ«jusies kÄŒÅ«da un kolekcija nevar bÅ«t izveidota.
+CollectionManager.Cannot_Delete_Index:Kolekcija nevar tikt veidota no jauna, jo nevaru izdzÄst vecÄs indeksa datnes.\n LÅ«dzu pÄrbaudiet, ka Greenstone vai cita programma neizmanto Å¡Ä«s datnes,\n un mÄÄ£iniet vÄlreiz.
+CollectionManager.Cannot_Delete_Index_Log:VecÄs indeksa datnes nevar tikt izdzÄstas, tÄpÄc importÄÅ¡ana pÄrtraukta.
+CollectionManager.Cannot_Open:Kolekcija:\n{0-Collection file path}\nnevar bÅ«t atvÄrta.
+CollectionManager.Cannot_Open_With_Reason:Kolekcija:\n{0-Collection file path}\nnevar bÅ«t atvÄrta jo:\n{1-Error message}
+CollectionManager.Creating_New:Jaunas kolekcijas radÄ«Å¡ana.
+CollectionManager.Log_Created:Log mape izveidota.
+CollectionManager.Loading_Collection:Kolekcijas ielÄdÄÅ¡ana
+CollectionManager.Loading_Collection_Please_Wait:Kolekcijas ielÄdÄÅ¡ana, lÅ«dzu uzgaidiet...
+CollectionManager.Loading_Successful:IelÄdÄtÄ kolekcija {0}.
+CollectionManager.Missing_Config:Å ai kolekcijai nav pareiza collect.cfg datne
+CollectionManager.Not_Col_File:{0}' neesot BibliotekÄra Interfeisa Kolekcijas Datne (.col)
+CollectionManager.Preview_Ready_Failed:AtgadÄ«jÄs kÄŒÅ«da, kura neÄŒauj, lai kolekcija tiktu priekÅ¡skatÄ«ta.
+CollectionManager.Preview_Ready_Title:Kolekcijas PriekÅ¡skatÄ«juma StÄvoklis.
+CollectionManager.Session_Ready:Kolekcija {0} gatava izmantoÅ¡anai.
+#*****************************
+#
+#***** CollectionPopupMenu *****
+CollectionPopupMenu.Delete:IzdzÄst
+CollectionPopupMenu.New_Dummy_Doc:Jauns fiktÄ«vs dokuments
+CollectionPopupMenu.New_Folder:Jauna mape
+#*******************************
+#
+#***** CreatePane *****
+CreatePane.Build:VeidoÅ¡anas Opcijas
+CreatePane.Build_Tooltip:Opcijas kolekcijas formÄÅ¡anas indeksÄcijas un klasifikÄcijas stadijÄ
+CreatePane.Build_Collection:Veidot Kolekciju
+CreatePane.Build_Collection_Tooltip:SÄkt kolekcijas formÄÅ¡anas procesu
+CreatePane.Build_Progress:VeidoÅ¡anas Progress
+CreatePane.Cancel_Build:Atcelt Veidot
+CreatePane.Cancel_Build_Tooltip:PÄrtraukt kolekcijas formÄÅ¡anas procesu
+CreatePane.Import:Importa Opcijas
+CreatePane.Import_Tooltip:Opcijas kolekcijas formÄÅ¡anas datÅu convertÄcijas un metadatu pieÅ¡Ä·irÅ¡anas stadijÄ
+CreatePane.Import_Progress:Importa Progress
+CreatePane.Log:PaziÅojumu Log
+CreatePane.Log_Tooltip:SkatÄ«t izvadu no iepriekÅ¡Äjiem kolekcijas formÄÅ¡anas mÄÄ£inÄjumiem
+CreatePane.Mode_All:viss
+CreatePane.Options:Opciju Grupas
+CreatePane.Options_Title:Kolekcijas Importa & VeidoÅ¡anas Opcijas
+CreatePane.Preview_Collection:PriekÅ¡skatÄ«t Kolekciju
+CreatePane.Preview_Collection_Tooltip:PriekÅ¡skatÄ«t izveidotu kolekciju
+#**********************
+#
+#***** Dates *****
+Dates.Mon:Pirmdiena
+Dates.Tue:Otrdiena
+Dates.Wed:TreÅ¡diena
+Dates.Thu:Ceturtdiena
+Dates.Fri:Piektdiena
+Dates.Sat:Sestdiena
+Dates.Sun:SvÄtdiena
+Dates.Jan:JanvÄris
+Dates.Feb:FerbruÄris
+Dates.Mar:Marts
+Dates.Apr:AprÄ«lis
+Dates.May:Maijs
+Dates.Jun:JÅ«nijs
+Dates.Jul:JÅ«lijs
+Dates.Aug:Augusts
+Dates.Sep:Septembris
+Dates.Oct:Oktobris
+Dates.Nov:Novembris
+Dates.Dec:Decembris
+#**********************
+#
+#***** Delete Collection Prompt *****
+DeleteCollectionPrompt.Collection_Details:IzvÄlÄtÄs kolekcijas detaÄŒas
+DeleteCollectionPrompt.Collection_List:Pieejamas kolekcijas
+DeleteCollectionPrompt.Confirm_Delete:LÅ«dzu atzÄ«mÄjiet rÅ«tiÅu, lai apstiprinÄtu kolekcijas izdzÄÅ¡anu.
+DeleteCollectionPrompt.Delete:IzdzÄst
+DeleteCollectionPrompt.Delete_Tooltip:IzdzÄst izvÄlÄto kolekciju
+DeleteCollectionPrompt.Details:VeidotÄjs - {0}\nAtbalstÄ«tÄjs - {1}\nApraksts\n{2}
+DeleteCollectionPrompt.Failed_Delete:Kolekcija nevar bÅ«t pilnÄ«gi izdzÄsta.
+DeleteCollectionPrompt.Failed_Title:IzdzÄÅ¡ana NeizdevÄs!
+DeleteCollectionPrompt.No_Collection:Nav izvÄlÄta kolekcija.
+DeleteCollectionPrompt.Successful_Delete:Kolekcija tikusi izdzÄsta.
+DeleteCollectionPrompt.Successful_Title:IzdzÄÅ¡ana Pabeigta!
+DeleteCollectionPrompt.Title:Kolekcijas IzdzÄÅ¡ana
+#**********************
+#
+#***** DirectoryLevelMetadata *****
+DirectoryLevelMetadata.Message:JÅ«s taisÄties pieÅ¡Ä·irt 'mapes lÄ«meÅa' metadatus izvÄlÄtai mapei (vai mapÄm). Å os metadatus automÄtiski pÄrmantos visas datnes un mapes Å¡ajÄ mapÄ. TurklÄt Å¡ie metadata nevar bÅ«t vienkÄrÅ¡i noÅemti, bet tikai aizvietoti. Lai turpinÄtu Å¡o darbÄ«bu nospiediet 'OK'.
+DirectoryLevelMetadata.Title:Par mapes lÄ«meÅa metadatu pievienoÅ¡anu
+#********************
+#
+#***** EnrichPane *****
+EnrichPane.Accumulate:Pievienot
+EnrichPane.Accumulate_Tooltip:Pievienot Å¡o vÄrtÄ«bu izvÄlÄtam metadatu elementam
+EnrichPane.AutoMessage:Å is elements, {0}, pieder Greenstone metadatu kopai. Å Ä« kopa reprezentÄ metadatus, kuri parasti var bÅ«t izvilkti automÄtiski. Lai pÄrbaudÄ«tu, kÄdi  {0} metadati var tikt izvilkti, radiet kolekciju izmantojot 'RadÄ«t' tab.
+# -- Missing translation: EnrichPane.ExistingValues
+EnrichPane.Expand:...
+EnrichPane.Expand_Tooltip:RediÄ£Ät saturu lielÄkÄ teksta lodziÅÄ
+# -- Missing translation: EnrichPane.InheritedMetadataSelected
+EnrichPane.No_File:Nav IzvÄlÄtas Datnes
+EnrichPane.No_Metadata:Nav Pieejami Metadati
+EnrichPane.No_Metadata_Element:<HTML><STRONG><FONT FACE={FONT} COLOR=Black>Nav Metadatu Elements IzvÄlÄts</FONT></STRONG></HTML>
+EnrichPane.Overwrite:Aizvietot
+EnrichPane.Overwrite_Tooltip:PieÅ¡Ä·irt Å¡o vÄrtÄ«bu izvÄlÄtam metadatu elementam, aizvietojot esoÅ¡o vÄrtÄ«bu
+EnrichPane.Remove:NoÅemt
+EnrichPane.Remove_Tooltip:IzdzÄst Å¡o vÄrtÄ«bu izvÄlÄtam metadatu elementam
+EnrichPane.Value:VÄrtÄ«ba
+EnrichPane.Value_Field_Tooltip:VÄrtÄ«ba, ko pieÅ¡Ä·irt izvÄlÄtam metadatu elementam
+EnrichPane.Value_Field_Tooltip_Uneditable:VÄrtÄ«ba, kura pieÅ¡Ä·irta izvÄlÄtam metadatu elementam
+#***********************
+#
+#****** ExplodeMetadataPrompt *******
+ExplodeMetadataPrompt.Explode:SadalÄ«t
+ExplodeMetadataPrompt.Explode_Tooltip:SadalÄ«t metadatu datni
+ExplodeMetadataPrompt.Instructions:Sadalot Å¡o metadatu datni tiks producÄti individuÄli ieraksti ar rediÄ£Äjamiem metadatiem. Å is ir neatgrieÅŸams process un kolekcijas originÄlÄ metadatu datne tiks izdzÄsta.
+ExplodeMetadataPrompt.Failed_Title:SadalÄ«Å¡ana NeizdevÄs.
+ExplodeMetadataPrompt.Failed_Explode:DatubÄze {0} nevar bÅ«t sadalÄ«ta.
+ExplodeMetadataPrompt.NotExplodable:DotÄ datne nav sadalÄma.
+ExplodeMetadataPrompt.Successful_Explode:DatubÄze {0} sekmÄ«gi sadalÄ«ta.
+ExplodeMetadataPrompt.Successful_Title:SadalÄ«Å¡ana Pabeigta.
+ExplodeMetadataPrompt.Title:SadalÄ«t Metadatu DatubÄzi
+#***********************
+#
+#****** WriteCDImagePrompt *******
+WriteCDImagePrompt.CD_Name:CD/DVD vÄrds
+WriteCDImagePrompt.Export:RakstÄ«t CD/DVD attÄlu
+WriteCDImagePrompt.Export_Tooltip:RakstÄ«t izvÄlÄtÄs kolekcijas, kÄ Windows CD/DVD AttÄlus
+WriteCDImagePrompt.Failed_Export:Kolekcijas ({0}) nevarÄja bÅ«t eksportÄtas.
+WriteCDImagePrompt.Failed_Title:Eksports NeizdevÄs
+WriteCDImagePrompt.Instructions:Vienas vai vairÄku kolekciju eksports uz paÅ¡instalÄjoÅ¡os Windows CD/DVD (kaut arÄ« tas darbojas uz jebkuras platformas, CD/DVD, kas tiek radÄ«ts, palaiÅŸas tikai zem Windows).
+WriteCDImagePrompt.Progress_Label:DatÅu kopÄÅ¡ana. Tas var aizÅemt zinÄmu laiku...
+WriteCDImagePrompt.Successful_Export:Kolekcijas ({0}) esot tikuÅ¡as eksportÄtas.
+WriteCDImagePrompt.Successful_Title:Eksports Pabeigts
+WriteCDImagePrompt.Title:Kolekcijas Eksports uz CD/DVD
+#************************
+#
+#****** ExportAsPrompt *******
+ExportAsPrompt.Export_Name:Eksporta mapes nosaukums
+ExportAsPrompt.Export:EksportÄt kolekciju(as)
+ExportAsPrompt.Export_Tooltip:EksportÄt izvÄlÄtÄs kolekcijas uz noteiktu mapi un izvÄlÄtÄ formÄtÄ
+ExportAsPrompt.Failed_ExportOne:Kolekcija, {0}, nevar bÅ«t eksportÄta.
+ExportAsPrompt.Failed_ExportMany:Kolekcijas -- {0} -- nevar bÅ«t eksportÄtas.
+ExportAsPrompt.Failed_Details:SkatÄ«t {1} sÄ«kÄk
+ExportAsPrompt.Failed_Title:Eksports NeizdevÄs
+ExportAsPrompt.Instructions:EksportÄt vienu vai vairÄkas kolekcijas izvÄlÄtÄ formÄtÄ uz noteiktu mapi
+ExportAsPrompt.Progress_Label:Datnes tiek eksportÄtas. Tas var aizÅemt zinÄmu laiku...
+ExportAsPrompt.Successful_ExportOne:Kolekcija, {0}, esot tikusi eksportÄta.
+ExportAsPrompt.Successful_ExportMany:Kolekcijas -- {0} -- esot tikuÅ¡as eksportÄtas.
+ExportAsPrompt.Successful_Details:Datnes eksportÄtas uz: {1}
+ExportAsPrompt.Successful_Title:Eksports Pabeigts
+ExportAsPrompt.Title:EksportÄt Kolekcijas
+ExportAsPrompt.SaveAs:EksportÄt uz
+ExportAsPrompt.SaveAs_Tooltip:IzvÄlieties formÄtu uz kuru jÅ«s vÄlaties eksportÄt
+#************************
+#
+#*****ExternalCollectionPrompt********
+ExternalCollectionPrompt.NewMDS:RadÄ«t jaunu, tukÅ¡u metadatu kopu.
+ExternalCollectionPrompt.ExistingMDS:IzvÄlieties vienu vai vairÄkas metadatu kopas
+ExternalCollectionPrompt.Title:IelÄdÄt Äreju kolekciju
+ExternalCollectionPrompt.Instructions_1:JÅ«s gribat ielÄdÄt kolekciju, kura netika izveidota ar GBI. JÅ«s tiksiet aicinÄti izvÄlÄties vienu vai vairÄkas metadatu kopas, kuras izmantot ar doto kolekciju. EksistÄjoÅ¡ie metadati tiks importÄti izvÄlÄtajÄ(s) metadatau kopÄ(s). OriginÄlÄs metadatu datnes tiks saglabÄtas mapÄ ar nosaukumu import.bak.
+ExternalCollectionPrompt.Instructions_2:JÅ«s gribat ielÄdÄt kolekciju, kura netika izveidota ar GBI. Jums nepiecieÅ¡ams pievienot metadatu kopu Å¡ai kolekcijai. JÅ«s varat radÄ«t jaunu tukÅ¡u metadatu kopu, kurai visi atrastie metadatu elementi kolekcijÄ tiks automÄtiski pievienoti. AlternatÄ«vi, jÅ«s varat izvÄlÄties eksistÄjoÅ¡as metadatu kopas, un elementi no kolekcijas tiks apvienoti vai pievienoti jau esoÅ¡iem elementiem Å¡ajÄs kopÄs. OriÄ£inÄlÄs metadatu datnes tiks saglabÄtas mapÄ ar nosaukumu import.bak.
+#****************************************
+#
+#***** Inherited Metadata *****
+ExtractedMetadata.Message:IzvÄletÄ datne vai mape satur izvilktus metadatus, bet patreiz tie ir neredzami. Lai redzÄtu izvilktus metadatus, dodieties uz "[D]atne" izvÄlni un izvÄlieties "[I]estatÄ«jumi". "VispÄrÄ«gi" rekvizÄ«tu lapÄ izvÄlieties "SkatÄ«t Izvilktus Metadatus", tad nospieÅŸiet "[O]k".
+ExtractedMetadata.Title:Å Ä« Datne/Mape satur Neredzamus Izvilktus Metadatus
+#
+#***** FileActions *****
+FileActions.Calculating_Size:Tiek kalkulÄts izvÄlÄto datÅu kopÄjais izmÄrs
+FileActions.Copying:KopÄju {0}
+FileActions.Deleting:IzdzÄÅ¡u {0}
+FileActions.Directories_Selected:{0} mapes izvÄlÄtas
+FileActions.Directory_Exists:<html>Mape<br>{0}<br>jau eksistÄ kolekcijÄ. Datnes tiks kopÄtas tajÄ.</html>
+FileActions.Directory_Selected:1 mape izvÄlÄta
+FileActions.File_Already_Exists_No_Create:Datne '{0}' jau eksistÄ.
+FileActions.File_Already_Exists_Message:{0}\nDatne ar nosaukumu, kas parÄdÄ«ta augstÄk jau eksistÄ\nun par spÄ«ti jÅ«su iepriekÅ¡Äjai izvÄlei BibliotekÄra Interfeiss\nnevar to pÄrrakstÄ«t. LÅ«dzu pÄrbaudiet vai datne ir rakstÄ«t atÄŒauta.
+FileActions.File_Already_Exists_Title:KÄŒÅ«da - Datne Jau EksistÄ.
+FileActions.File_And_Directories_Selected:1 datne un {0} mapes izvÄlÄtas
+FileActions.File_And_Directory_Selected:1 datne un 1 mape izvÄlÄta
+FileActions.File_Create_Error:Datne {0} nevar tikt radÄ«ta.
+FileActions.Folder_Create_Error:Mape {0} nevar tikt radÄ«ta.
+FileActions.File_Exists:<html>{0} jau eksistÄ saÅÄmÄjmapÄ. PÄrrakstÄ« to?</html>
+FileActions.File_Not_Found_Message:{0}\nAugstÄk minÄtÄ datne nevar tikt atrasta. LÄ«dz ar datÅu skata\natjaunoÅ¡anu, lÅ«dzu pÄrbaudiet, ka datne vÄl eksistÄ.
+FileActions.File_Not_Found_Title:KÄŒÅ«da - Datne nav atrasta.
+FileActions.File_Selected:1 datne izvÄlÄta
+FileActions.Files_And_Directory_Selected:{0} datnes un 1 mape izvÄlÄta
+FileActions.Files_Selected:{0} datnes izvÄlÄtas
+FileActions.Folder_Already_Exists:Mape ar nosaukumu '{0}' tiek jau lietota. Nevaru radÄ«t mapi.
+FileActions.Increase_Depth:PalielinÄt DziÄŒumu par 1
+FileActions.Insufficient_Space_Message:DarbÄ«ba ar datni neizdevÄs, jo nepietiek vietas\nuz diska. Lai sekmÄ«gi nokopÄtu datni jums turmÄk\nnepiecieÅ¡ams: {0}
+FileActions.Insufficient_Space_Title:KÄŒÅ«da - Nepietiek Vietas
+FileActions.Moving:PÄrvietoju {0}
+FileActions.No_Activity:Nav pieprasÄ«tas darbÄ«bas
+FileActions.Possible_Cyclic_Path:{1} ir {0} mapes dziÄŒumÄ un var bÅ«t rekursÄ«vs ceÄŒÅ¡? Vai datÅu darbÄ«bu turpinÄt?
+FileActions.Read_Only:Datnes no darbatelpas ir tikai lasÄmas un navar bÅ«t izdzÄstas.
+FileActions.Selected:{0} datnes un {1} mapes izvÄlÄtas
+FileActions.Unknown_File_Error_Message:Lai gan nebija kÄŒÅ«da reportÄta datnes darbÄ«bas\nlaikÄ, gala pÄrbaude parÄda, ka\nkopijas datne nav tÄ pati kÄ avota datne. TÄ cÄlonis\nnav zinÄms. LÅ«dzu pÄrbaudiet jÅ«su disku un atjaunojiet\njÅ«su instalÄto JVM.
+FileActions.Unknown_File_Error_Title:KÄŒÅ«da - NezinÄma Datnes KÄŒÅ«da
+FileActions.Write_Not_Permitted_Message:BibliotekÄra Interfeisam nav atÄŒaujas rakstÄ«t\n{0}\nLÅ«dzu pÄrbaudiet datnes atÄŒaujas atribÅ«tus.
+FileActions.Write_Not_Permitted_Title:KÄŒÅ«da - Nepareizas Datnes AtÄŒaujas
+FileActions.Yes_To_All:JÄ uz Visiem
+#************************
+#
+#******* File Associations dialog **********
+FileAssociationDialog.Add:Pievienot
+FileAssociationDialog.Add_Tooltip:Izmantojiet Å¡o lietojumprogrammu, lai skatÄ«tu Å¡Ä tipa datni
+FileAssociationDialog.Batch_File:PakeÅ¡datnes
+FileAssociationDialog.Browse:PÄrlÅ«kot
+FileAssociationDialog.Browse_Tooltip:IzvÄlieties lietojumprogrammu, ko izmantot no jÅ«su datÅutelpas
+FileAssociationDialog.Browse_Tooltip_Mac:JÅ«su lietojumprogrammas pÄrlÅ«koÅ¡ana patreiz ir aizliegta priekÅ¡ MacOS
+FileAssociationDialog.Browse_Title:IzvÄlieties Lietojumprogrammu
+FileAssociationDialog.Close:AizvÄrt
+FileAssociationDialog.Close_Tooltip:Aizveriet Å¡o dialogu un atgriezieties uz galveno logu
+FileAssociationDialog.Command:PalaiÅ¡anas komanda:
+FileAssociationDialog.Command_File:Komanddatnes
+FileAssociationDialog.Command_Tooltip:Ievadiet komandu ar kuru palaist lietojumprogrammu
+FileAssociationDialog.Details:JaunÄs Datnes AsociÄcijas DetaÄŒas
+FileAssociationDialog.Executable_File:IzpildÄmÄs datnes
+FileAssociationDialog.Existing_Associations:AktuÄlÄs Datnes AsociÄcijas
+FileAssociationDialog.Extension:DatnÄm kas beidzas ar:
+FileAssociationDialog.Extension_Tooltip:SkatÄmo datÅu datnes paplaÅ¡inÄjums
+FileAssociationDialog.Instructions:Izmantojiet Å¡o dialogu, lai uzstÄdÄ«tu, kÄdas ÄrÄjÄs programmas tiks lietotas skatot noteiktu datnes-tipu, un kÄda komanda tiks nosÅ«tÄ«ta, lai  palaistu Å¡o programmu.\nLai pievienotu jaunu datnes-tipu, ievadiet tÄs paplaÅ¡inÄjumu lauciÅÄ 'DatnÄm kas beidzas ar'. Lai pievienotu vai modificÄtu palaiÅ¡anas komandu, ievadiet jaunu komandu lodziÅÄ 'PalaiÅ¡anas Komanda' vai noklikÅ¡Ä·iniet 'PÄrlÅ«kot', ja vÄlaties meklÄt datÅu sistÄmÄ attiecÄ«go programmu. Izmantojiet formÄtu '%1', lai indicÄtu vietu, kur vajadzÄtu tikt iespraustam datnes nosaukumam atveramai datnei, piemÄram, "C:\\Windows\\System\\MSPaint.exe %1". '%1' tiks pievienots komandas galÄ, ja netiks specificÄts citÄdi.\nMacOS lietotÄjiem vienmÄr vispirms jÄmÄÄ£ina specifisko mac komandu "open [-a <application_name>] %1".
+FileAssociationDialog.Table.Command:Komanda
+FileAssociationDialog.Table.Extension:PaplaÅ¡inÄjums
+FileAssociationDialog.Title:RediÄ£Ät Datnes AsociÄcijas
+FileAssociationDialog.Remove:NoÅemt
+FileAssociationDialog.Remove_Tooltip:IzdzÄst patreiz izvÄlÄto asociÄciju no eksistÄjoÅ¡o asociÄciju saraksta
+FileAssociationDialog.Replace:Aizvietot
+FileAssociationDialog.Replace_Tooltip:Aizvietot patreiz izvÄlÄto asociÄciju ar jaunÄm asociÄcijas detaÄŒÄm
+#*******************
+#
+#******Filter***************
+Filter.0:HTM & HTML
+Filter.1:XML
+Filter.2:Teksta Datnes
+Filter.3:AttÄli
+Filter.All_Files:Visas Datnes
+Filter.Filter_Tree:ParÄdÄ«t Datnes
+Filter.Invalid_Pattern:<HTML><FONT FACE={FONT} COLOR=Black>Å ablonu, ko jÅ«s esat ievadÄ«juÅ¡i datÅu filtrÄcijai, ir nederÄ«gs.<BR>LÅ«dzu mÄÄ£iniet vÄlreiz, izmantojot regulÄras izteiksmes sintaksi un ar<BR>* norÄdot aizstÄjÄjzÄ«mi.</FONT></HTML>
+#***********************
+#
+#***** GAuthenticator *****
+GAuthenticator.Password:Parole:
+GAuthenticator.Password_Tooltip:Ievadiet Å¡eit jÅ«su paroli
+GAuthenticator.Title:Parole ir NepiecieÅ¡ama.
+GAuthenticator.Username:LietotÄja VÄrds:
+GAuthenticator.Username_Tooltip:Ievadiet Å¡eit jÅ«su lietotÄjvÄrdu
+#**************************
+#
+#***** General Messages *****
+# 0 - A String representing the name and method of the class in question.
+General.Apply:Lietot
+General.Apply_Tooltip:Pielietot patreizÄjos uzstatÄ«jumus, bet neiziet no dialoga
+General.Browse:PÄrlÅ«kot...
+General.Cancel:Atcelt
+General.Cancel_Tooltip:Atcelt izmaiÅas (neatsauks jebkuru jau pielietotu izmaiÅu)
+General.Close:AizvÄrt
+General.Close_Tooltip:AizvÄrt Å¡o dialoglodziÅu
+General.Edit:RediÄ£Ät VÄrtÄ«bu
+General.Error:KÄŒÅ«da
+General.No:NÄ
+General.NotSunJava:Java vendor: {0}\nIevÄrojiet, ka BibliotekÄra Interfeiss ir ticis attÄ«stÄ«ts un testÄts ar Java no Sun Microsystems.
+General.OK:OK
+General.OK_Tooltip:AkceptÄt patreizÄjos iestatÄ«jumus un iziet no dialoga
+General.Open:AtvÄrt
+General.Outstanding_Processes:<html>BibliotekÄra Interfeiss nevar pilnÄ«gi beigt darbu, kamÄr visas programmas<br>startÄtas ar BibliotekÄra Interfeisu arÄ« nav pabeigtas.</html>
+General.Outstanding_Processes_Title:GaidoÅ¡s lai Izietu
+General.Pure_Cancel_Tooltip:PÄrtraukt Å¡o darbÄ«bu (izmaiÅas netiks veiktas)
+General.Review_Output:LÅ«dzu pÄrlÅ«kojiet izvadu zemÄk:
+General.Usage:LietoÅ¡ana: {0} <params>\nVisi parametri ir neobligÄti, bet BibliotekÄra Interfeiss var nojukt darbÄ, ja -gsdl un -library nav uzstÄdÄ«ti.\n -gsdl <path> : NorÄda ceÄŒu uz gsdl\n - library <path> : CeÄŒu uz cgi-bin\n -mozilla <path> : NorÄda ceÄŒu uz mozilla\n -mirror : AtÄŒauj web-mirroring kontroles\n -laf [java|windows|motif|mac] : Look and feel\n debug : AtÄŒauj kÄŒÅ«du paziÅojumus\n -no_load : NeielÄdÄt iepriekÅ¡ atvÄrtu kolekciju\n -load <path> : IelÄdÄt norÄdÄ«to kolekciju
+General.View:JaunÄ VÄrtÄ«ba
+General.Warning:BrÄ«dinÄjums
+General.Yes:JÄ
+#****************************
+#
+#***** GShell *****
+GShell.Build.Auxilary:PalÄ«gdatÅu radÄ«Å¡ana un apstrÄde...
+GShell.Build.BuildBegun1:************** VeidoÅ¡ana  UzsÄkta **************
+GShell.Build.BuildCancelled:**************   AnulÄts    **************
+GShell.Build.BuildComplete1:************** VeidoÅ¡ana Pabeigta **************
+GShell.Build.CompressText:Teksta SaspieÅ¡ana...
+GShell.Build.Index:Indeksa radÄ«Å¡ana bÄzÄjoties uz {0-index source and level}...
+GShell.Build.InfoDatabase:InformÄcijas datu bÄzes radÄ«Å¡ana...
+GShell.Build.Phind:Klasifikatora Phind Ä£enerÄÅ¡ana. Tas var aizÅemt zinÄmu laiku...
+GShell.Command:Komanda
+GShell.Failure:Komanda izpildÄ«jÄs nesekmÄ«gi.
+GShell.Import.FileNotProcessed:Datne {0-target file path} bija atpazÄ«ta, bet nevarÄja tikt apstrÄdÄta ar kÄdu no spraudÅiem (plugin).
+GShell.Import.FileNotRecognised:Datne {0-target file path} nebija atpazÄ«ta ne ar vienu spraudni.
+GShell.Import.FileProcessing:Datne {0-target file path} tiek apstrÄdÄta ar {1-plugin name}.
+GShell.Import.FileProcessingError:Datnes {0-target file path} apstrÄdes process sadÅ«rÄs ar kÄŒÅ«du.
+GShell.Import.ImportBegun1:************** Imports  SÄcies **************
+GShell.Import.ImportComplete1:************** Imports Pabeigts **************
+GShell.Import.ImportComplete2:{0-number documents considered} dokumenti bija izskatÄ«ti apstrÄdei:
+GShell.Import.ImportComplete2.1:1 dokuments bija izskatÄ«ts apstrÄdei:
+GShell.Import.ImportComplete.Processed:{0-number processed} dokumenti bija apstrÄdÄti un iekÄŒauti kolekcijÄ.
+GShell.Import.ImportComplete.Processed.1:1 dokuments bija apstrÄdÄts un iekÄŒauts kolekcijÄ.
+GShell.Import.ImportComplete.Blocked:{0-number blocked} bija atturÄti no pievienoÅ¡anas ar spraudÅiem (tÄdi kÄ web lappuÅ¡u attÄli).
+GShell.Import.ImportComplete.Blocked.1:1 bija atturÄts no pievienoÅ¡anas ar spraudÅiem (tÄdi kÄ web lappuÅ¡u attÄli).
+GShell.Import.ImportComplete.Ignored:{0-number ignored} bija neatpazÄ«ti.
+GShell.Import.ImportComplete.Ignored.1:1 bija neatpazÄ«ts.
+GShell.Import.ImportComplete.Failed:{0-number failed} bija noraidÄ«ti.
+GShell.Import.ImportComplete.Failed.1:1 bija noraidÄ«ts.
+GShell.Import.ImportComplete3:\n
+GShell.Parsing_Metadata_Complete:ArhivÄtu metadatu izvilkÅ¡ana pabeigta.
+GShell.Parsing_Metadata_Start:Jaunu metadatu izvilkÅ¡ana no arhÄ«vu datnÄm.
+GShell.Success:Komanda pabeigta.
+#*********************
+#
+#***** GUI *****
+# Currently Enabled and Disabled display the same text but in different
+# colours. If necessary this can be changed.
+GUI.Create:RadÄ«t
+GUI.Create_Tooltip:Veidot jÅ«su kolekciju izmantojot Greenstone
+GUI.Design:Dizains
+GUI.Design_Tooltip:JÅ«su kolekcijas funkcionalitÄtes un izskata dizains
+GUI.Download:LejupielÄde
+GUI.Download_Tooltip:LejupielÄdÄt resursus no Interneta jÅ«su kolekcijai
+GUI.Enrich:PagÄtinÄt
+GUI.Enrich_Tooltip:NozÄ«mÄt metadatus datnÄm jÅ«su kolekcijÄ
+GUI.Gather:UzkrÄt
+GUI.Gather_Tooltip:IzvÄlÄties datnes, kuras iekÄŒaut jÅ«su kolekcijÄ
+#***************
+#
+#***** HELP *****
+Help.Contents:Saturs
+Help.Title:BibliotekÄra Interfeisa PalÄ«ga Lappuses
+#
+#***** LockFileDialog *****
+LockFileDialog.Cancel_Tooltip:NepÄrtvert slÄdzejdatnes kontroli (kolekcija netiks atvÄrta)
+LockFileDialog.Date:DatÄjums
+LockFileDialog.Error:#error
+LockFileDialog.Lockfile_Message_One:SlÄdzÄjdatnes (lock file) klÄtbÅ«tne norÄda uz to, ka kolekcija ir jau atvÄrta.
+LockFileDialog.Lockfile_Message_Two:Vai jÅ«s gribat 'pÄrtvert' slÄdzÄjdatnes kontroli?
+LockFileDialog.Machine:Kur
+LockFileDialog.Name:Nosaukums
+LockFileDialog.OK_Tooltip:PÄrtvert slÄdzÄjdatnes kontroli
+LockFileDialog.Title:SlÄdzÄjdatne AtklÄta
+LockFileDialog.User:KurÅ¡
+#********************
+#
+#*****MappingPrompt **********
+MappingPrompt.File:Mape
+MappingPrompt.Map:RadÄ«t ÄªsinÄjumikonu
+MappingPrompt.Name:Nosaukums
+MappingPrompt.Title:Uzdot Mapes ÄªsinÄjumikonu
+MappingPrompt.Unmap:NoÅemt ÄªsinÄjumikonu
+#*******************
+#
+#***** Menu Options *****
+Menu.Collapse:AizvÄrt Mapi
+Menu.Edit:RediÄ£Ät
+Menu.Edit_Copy:KopÄt (ctrl-c)
+Menu.Edit_Cut:Izgriezt (ctrl-x)
+Menu.Edit_Paste:IelÄ«mÄt (ctrl-v)
+Menu.Expand:AtvÄrt Mapi
+Menu.Explode_Metadata_Database:SadalÄ«t metadatu datu bÄzi
+Menu.File:Datne
+Menu.File_Associations:Datnes AsociÄcijas...
+Menu.File_CDimage:IerakstÄ«t CD/DVD attÄlu...
+Menu.File_Close:AizvÄrt
+Menu.File_Delete:IzdzÄst...
+Menu.File_Exit:Iziet
+Menu.File_ExportAs:EksportÄt...
+Menu.File_New:Jauns...
+Menu.File_Open:AtvÄrt...
+Menu.File_Options:IestatÄ«jumi...
+Menu.File_Save:SaglabÄt
+Menu.Help:PalÄ«gs
+Menu.Help_About:Par...
+Menu.Metadata_View:NozÄ«mÄtie metadati {0}
+Menu.Open_Externally:AtvÄrt ar ÄrÄjo programmu
+#********************
+#
+#***** MetaAudit *****
+MetaAudit.Close:AizvÄrt
+MetaAudit.Close_Tooltip:AizvÄrt Å¡o dialoglodziÅu
+MetaAudit.Title:Visi Metadati
+#*********************
+#
+#***** Metadata *****
+Metadata.Element:Elements
+Metadata.Value:VÄrtÄ«ba
+MetadataSet.Files:Metadatu Kopas Datnes
+#*********************************************
+#
+#******** MetadataImportMappingPrompt *********
+MIMP.Add:Pievienot
+MIMP.Add_Tooltip:Pievienot metadatu elementu atlasÄ«tai kopai
+MIMP.Ignore:IgnorÄt
+MIMP.Ignore_Tooltip:IgnorÄt Å¡o metadatu elementu
+MIMP.Instructions:Metadatu elements {0} nevar bÅ«t automÄtiski importÄts kolekcijÄ. IzvÄlieties metadatu kopu un sekojoÅ¡i:\n(1) nospiediet  'Pievienot', lai pievienotu metadatus Å¡ai kopai (pie nosacÄ«juma, ja kopÄ jau nÄesot metadatu {0}), vai\n(2) izvÄlieties elementu un nospiediet  'IekÄŒaut', lai importÄtu {0} metadatus Å¡ajÄ elementÄ, vai\n(3) ignorÄjiet Å¡o metadatu elementu.
+MIMP.Merge:IekÄŒaut
+MIMP.Merge_Tooltip:IekÄŒaut metadatu elelementu specificÄtÄ elementÄ izvÄlÄtÄ kopÄ
+MIMP.Source_Element:Avota metadatu elements:
+MIMP.Target_Element:MÄrÄ·a metadatu elements:
+MIMP.Target_Set:MÄrÄ·a metadatu kopa:
+MIMP.Title:NepieceÅ¡ama IekÄŒauÅ¡anas DarbÄ«ba.
+#*****************************
+#
+#***** Mirroring *****
+Mirroring.ClearCache:IztÄ«rÄ«t KeÅ¡u
+Mirroring.ClearCache_Tooltip:IzdzÄst visas lejupielÄdÄtas datnes
+Mirroring.Download:LejupielÄde
+Mirroring.Download_Tooltip:SÄkt jaunu lejupielÄdes uzdevumu
+Mirroring.Download_Controls:LejupielÄdes UzstatÄ«jumi
+Mirroring.Download_Depth:LejupielÄdes DziÄŒums:
+Mirroring.Download_Depth.Zero:Nulle
+Mirroring.Download_Depth.Unlimited:NeierobeÅŸots
+Mirroring.Download_Depth_Tooltip:Cik daudz hipersaites dziÄŒumÄ iet lejupielÄdÄjot
+Mirroring.Download_Embedded:LejupielÄdÄt tikai tekstu (ne attÄlus, ne stila lappuses utt)
+Mirroring.DownloadJob.Close:AizvÄrt
+Mirroring.DownloadJob.Close_Tooltip:NoÅemt Å¡o uzdevumu no saraksta, apstÄdinot to, ja tas patreiz izpildÄs
+Mirroring.DownloadJob.Downloading:{0} lejupielÄde
+Mirroring.DownloadJob.Download_Complete:LejupielÄde pabeigta
+Mirroring.DownloadJob.Download_Stopped:LejupielÄde apstÄdinÄta
+Mirroring.DownloadJob.Download_Progress:LejupielÄde ir progresÄ
+Mirroring.DownloadJob.Log:SkatÄ«t Log
+Mirroring.DownloadJob.Log_Tooltip:SkatÄ«t detalizÄtÄk par Å¡o lejupielÄdi
+Mirroring.DownloadJob.Pause:Pauze
+Mirroring.DownloadJob.Pause_Tooltip:PauzÄt Å¡o lejupielÄdi
+Mirroring.DownloadJob.Resume:AtsÄkt
+Mirroring.DownloadJob.Resume_Tooltip:AtsÄkt Å¡o lejupielÄdi
+Mirroring.DownloadJob.Status:LejupielÄdÄti {0} no {1} datnÄm ({2} brÄ«dinÄjumi, {3} kÄŒÅ«das)
+Mirroring.DownloadJob.Waiting:Gaida lai sÄktu
+Mirroring.DownloadJob.Waiting_User:Gaida uz lietotÄja darbÄ«bu
+Mirroring.Higher_Directories:Tikai atspoguÄŒot datnes zem Å¡Ä URL
+Mirroring.Invalid_URL:IevadÄ«tais URL nav pareizs. LÅ«dzu izlabojiet.
+Mirroring.Invalid_URL_Title:Nepareizs URL
+Mirroring.Preferences:IestatÄ«jumi...
+Mirroring.Preferences_Tooltip:AtÄŒaut starpnieku (proxy) un/vai rediÄ£Ät starpnieka iestatÄ«jumus
+Mirroring.Same_Host:Tikai atspoguÄŒot datnes Å¡ajÄ paÅ¡Ä vietnÄ
+Mirroring.Source_URL:Avota URL:
+Mirroring.Source_URL_Tooltip:LejupielÄdes URL
+#*********************
+#
+#***** Missing EXEC *****
+MissingEXEC.Message:BrÄ«dinÄjums! JÅ«s nevarÄsiet redzÄt jÅ«su jauno kolekciju no BibliotekÄra Interfeisa, ja jÅ«s nenorÄdÄ«siet ceÄŒu uz lokÄli darbojoÅ¡os Greenstone BibliotekÄra Webserveri. JÅ«s to varat tagad ievadÄ«t teksta lauciÅÄ zemÄk, vai vÄlÄk aizejot uz IestatÄ«jumi un izvÄloties Savienojums tabulatoru. Atcerieties, ka pareizam url jÄsÄkas ar protokolu  "http://", un jÄbeidzas ar izpildÄmÄs programmas nosaukumu ("gsdl" Greenstone lokÄlas bibliotÄkas servera gadÄ«jumÄ, "library" visu pÄrejo web serveru gadÄ«jumos (piem., Apache)).
+MissingEXEC.Title:IztrÅ«kst Greenstone BibliotÄkas Adrese
+#***** Missing EXEC_GS3 *****
+MissingEXEC_GS3.Message:BrÄ«dinÄjums! JÅ«s nevarÄsiet redzÄt jÅ«su jauno kolekciju no BibliotekÄra Interfeisa, ja jÅ«s nenorÄdÄ«siet ceÄŒu uz Greenstone kontekstu lokÄli darbojoÅ¡os Tomcat WebserverÄ«. JÅ«s to varat tagad ievadÄ«t teksta lauciÅÄ zemÄk, vai vÄlÄk aizejot uz IestatÄ«jumi un izvÄloties Savienojums tabulatoru. Atcerieties, ka pareizam url jÄsÄkas ar protokolu  http://. Adrese pÄc noklusÄjuma ir http://localhost:8080/gsdl3.
+MissingEXEC_GS3.Title:IztrÅ«kst Greenstone BibliotÄkas Adrese
+#***** Missing GSDL *****
+MissingGSDL.Message:BrÄ«dinÄjums! JÅ«s nevarÄsiet izmantot visas BibliotekÄra Interfeisa iespÄjas bez instalÄtÄs Greenstone DigitÄlÄs BibliotÄkas lokÄlÄs kopijas. LÅ«dzu, pÄrbaudiet jÅ«su instalÄciju, un ceÄŒus BibliotekÄra Interfeisa pakeÅ¡datnÄ vai skripta datnÄ.
+MissingGSDL.Title:IztrÅ«kst Greenstone CeÄŒÅ¡
+#***** Missing PERL *****
+MissingPERL.Message:BrÄ«dinÄjums! JÅ«s nevarÄsiet radÄ«t jaunas kolekcijas, kÄ arÄ« veidot esoÅ¡as, bez uzinstalÄtÄ PERL. BibliotekÄra Interfeiss nevarÄja atrast PERL jÅ«su sistÄmÄ. LÅ«dzu, pÄrbaudiet jÅ«su sistÄmas instalÄciju un ceÄŒus, kuri specificÄti BibliotekÄra Interfeisa pakeÅ¡datnÄ vai skripta datnÄ.
+MissingPERL.Title:IztrÅ«kst PERL CeÄŒÅ¡
+#******* MissingWGET ********
+MissingWGET.Message:BrÄ«dinÄjums! Web atspoguÄŒoÅ¡ana ir liegta, jo BibliotekÄra Interfeiss nesekmÄ«gi mÄÄ£inÄja atrast atbilstoÅ¡as versijas Wget. LÅ«dzu, pÄrbaudiet jÅ«su sistÄmas instalÄciju un ceÄŒus, kuri specificÄti BibliotekÄra Interfeisa pakeÅ¡datnÄ vai skripta datnÄ.
+MissingWGET.Title:IztrÅ«kst WGet
+#******* MissingImageMagick ********
+# -- Missing translation: MissingImageMagick.Message
+# -- Missing translation: MissingImageMagick.Title
+#*****************************
+#
+#***** New Session *****
+NewCollectionPrompt.Base_Collection:BÄzÄt Å¡o kolekciju uz:
+NewCollectionPrompt.Base_Collection_Tooltip:IzvÄlieties esoÅ¡o kolekciju uz kuras bÄzÄt jauno kolekciju
+NewCollectionPrompt.Collection_Description:Satura apraksts:
+#NewCollectionPrompt.Collection_Email:Author's Email:
+NewCollectionPrompt.Collection_Name:Kolekcijas mape:
+#NewCollectionPrompt.Collection_Name_Tooltip:Short collection name, used internally (must be 8 characters or less)
+NewCollectionPrompt.Description_Error:Apraksta lauciÅam jÄbÅ«t aizpildÄ«tam. LÅ«dzu aizpildiet to.
+NewCollectionPrompt.Error:KÄŒÅ«da jaunajÄ kolekcijÄ.
+NewCollectionPrompt.Instructions:Lai radÄ«tu jaunu kolekciju, aizpildiet lauciÅus zemÄk.
+NewCollectionPrompt.Metadata_Elements:Elementi izvÄlÄtajÄ kopÄ:
+NewCollectionPrompt.Metadata_Instructions1:IzvÄlieties rÅ«tiÅas blakus metadatu kopÄm, kuras iekÄŒaut jÅ«su kolekcijÄ.
+NewCollectionPrompt.Metadata_Instructions2:(PiezÄ«me: JÅ«s varat pievienot jaunas kopas vÄlÄk).
+NewCollectionPrompt.Metadata_Title_Existing:IzvÄlieties metadatu kopas.
+#NewCollectionPrompt.Name_Error:You have either failed to enter a name for the collection, or the name you have choosen is already in use. Please correct.
+NewCollectionPrompt.NewCollection:-- Jauna Kolekcija --
+NewCollectionPrompt.Select_MDS:Pieejamas metadatu kopas:
+NewCollectionPrompt.Title:RadÄ«t jaunu Kolekciju.
+NewCollectionPrompt.Title_Clash:Nosaukums, kuru jÅ«s izvÄlÄjaties jÅ«su kolekcijai, jau tiek izmantots. TurpinÄt?
+NewCollectionPrompt.Title_Error:Nosaukuma lauciÅam jÄbÅ«t aizpildÄ«tam. LÅ«dzu izlabojiet.
+#***** New Folder OrFilePrompt *****
+NewFolderOrFilePrompt.Default_File_Name:fiktÄ«vs
+NewFolderOrFilePrompt.Default_Folder_Name:jauna mape
+NewFolderOrFilePrompt.Destination_Name:SaÅÄmÄjMape
+NewFolderOrFilePrompt.File_Name:Datnes VÄrds
+NewFolderOrFilePrompt.File_Name_Tooltip:Ievadiet nosaukumu jaunai datnei
+NewFolderOrFilePrompt.Folder_Name:Mapes VÄrds
+NewFolderOrFilePrompt.Folder_Name_Tooltip:Ievadiet nosaukumu jaunai mapei
+NewFolderOrFilePrompt.Title_Folder:RadÄ«t jaunu mapi
+NewFolderOrFilePrompt.Title_File:RadÄ«t jaunu fiktÄ«vu dokumentu
+#***********************
+#
+NoMetadataSetsSelected.Message:Ja jÅ«s radÄ«siet tagad kolekciju, tad tai nebÅ«s sÄkotnÄjas metadatu kopas. JÅ«s nevarÄsiet importÄt vai pieÅ¡Ä·irt jebkÄdus metadatus, lÄ«dz nebÅ«s importÄta vai pievienota kopa jÅ«su kolekcijai. Vai jÅ«s vÄlaties turpinÄt?
+NoMetadataSetsSelected.Title:Nav Metadatu Kopa izvÄlÄta
+#**********************
+#
+#******* OldWGET *******
+NoPluginExpectedToProcessFile.Message:IzskatÄs, ka neviens no Greenstone spraudÅiem varÄtu apstrÄdÄt datni "{0}". PÄrbaudiet, ka datnei ir pareizs paplaÅ¡inÄjums. Ja tas ir pareizs, tad jums vajadzÄtu izmantot UnknownPlug spraudni, lai apstrÄdÄtu Å¡o datni.
+NoPluginExpectedToProcessFile.Title:Nav paredzamÄ spraudÅa datnes apstrÄdei
+#**********************
+#
+#******* OldWGET *******
+OldWGET.Message:BrÄ«dinÄjums! JÅ«su instalÄtai Wget versijai ir zinÄma kÄŒÅ«da, kad tiek atspoguÄŒotas datnes, kurÄs ir URL, kas satur kodÄtas zÄ«mes, tÄdas kÄ, atstarpi  un tildi. MÄs rekomendÄjam instalÄt Wget 1.9 un augstÄk.
+OldWGET.Title:Vecs Wget
+#***********************
+#
+#***** OpenCollectionDialog *****
+OpenCollectionDialog.Available_Collections:Pieejamas Kolekcijas
+OpenCollectionDialog.Browse:PÄrlÅ«kot
+OpenCollectionDialog.Browse_Tooltip:IzvÄlieties kolekciju no jÅ«su datÅu telpas
+OpenCollectionDialog.Collection:Greenstone Kolekcija (".col")
+OpenCollectionDialog.Description:Kolekcijas Apraksts
+OpenCollectionDialog.Locked_Collection:Greenstone kolekcija jau tiek lietota
+OpenCollectionDialog.No_Description:LÅ«dzu izvÄlieties greenstone kolekciju (".col" datne), lai redzÄtu aprakstu.
+OpenCollectionDialog.Normal_Collection:Greenstone kolekcija
+OpenCollectionDialog.Open:AtvÄrt
+OpenCollectionDialog.Open_Tooltip:IelÄdÄt izvÄlÄto kolekciju BibliotekÄra InterfeisÄ
+OpenCollectionDialog.Title:AtvÄrt Greenstone Kolekciju
+#**********************
+#
+#***** Options Pane inside CreatePane *****
+OptionsPane.Cancelled: - anulÄts
+OptionsPane.LogHistory:Log vÄsture
+OptionsPane.Successful: - sekmÄ«gi
+OptionsPane.Unknown: - nezinÄms
+OptionsPane.Unsuccessful: - nesekmÄ«gi
+#*******************
+#
+#***** Preferences *****
+Preferences:IestatÄ«jumi
+Preferences.Connection:Savienojums
+Preferences.Connection_Tooltip:UzstÄdiet URL uz greenstone bibliotÄku un nokonfigurÄjiet starpniekservera savienojumu, ja vajadzÄ«gs
+Preferences.Connection.Library_Path:BibliotÄkas CeÄŒÅ¡:
+Preferences.Connection.Library_Path_GS3:Greenstone Web CeÄŒÅ¡:
+Preferences.Connection.Library_Path_Tooltip:Greenstone web-servera URL
+Preferences.Connection.Library_Path_Tooltip_GS3:Greenstone web-servera URL
+Preferences.Connection.ProgramCommand:PriekÅ¡skatÄ«juma Komanda:
+Preferences.Connection.ProgramCommand_Tooltip:Programmas palaiÅ¡anas komanda, lai skatÄ«tu kolekcijas priekÅ¡skatÄ«jumu. Atcerieties, ka jÄizmanto %1, kÄ kolekcijas adreses vietturi, un dubultpÄdiÅas, kur nepiecieÅ¡ams.
+Preferences.Connection.Proxy_Host:Starpniekserveris:
+Preferences.Connection.Proxy_Host_Tooltip:JÅ«su starpniekservera adrese
+Preferences.Connection.Proxy_Port:Starpniekservera pieslÄgvieta:
+Preferences.Connection.Proxy_Port_Tooltip:JÅ«su starpniekservera pieslÄgvietas numurs
+Preferences.Connection.Servlet:ServersÄ«klietotne:
+Preferences.Connection.Servlet_Tooltip:ServersÄ«klietotne izmantojama, lai skatÄ«tu jÅ«su vietni
+Preferences.Connection.Servlet_Tooltip2:ServersÄ«klietotne nav specificÄta Å¡ai vietnei. JÅ«s joprojÄm varat veidot kolekcijas, bet jÅ«s nevarÄsiet tÄs skatÄ«t.
+Preferences.Connection.Site:Vietne:
+Preferences.Connection.Site_Tooltip:Vietne kurÄ jÅ«s gribat strÄdÄt
+Preferences.Connection.Use_Proxy:Izmantot starpniekservera savienojumu?
+Preferences.General:VispÄrÄ«gs
+Preferences.General_Tooltip:Uzdot daÅŸus vispÄrigus iestatÄ«jumus
+Preferences.General.Email:LietotÄja Epasts:
+Preferences.General.Email_Tooltip:Epasta adrese automÄtiski izmantojama jebkurai kolekcijai radÄ«tai ar GBI
+Preferences.General.Font:Fonts:
+Preferences.General.Font_Tooltip:Fonts izmantojams GBI interfeisÄ.
+Preferences.General.Interface_Language:Interfeisa Valoda:
+Preferences.General.Interface_Language_Tooltip:IzvÄlieties valodu, kurÄ interfeiss un tÄ kontroles tiktu parÄdÄ«ti.
+Preferences.General.Restart_Required:GBI (Greenstone BibliotekÄra Interfeisam) tagad jÄrestartÄ, lai pabeigtu savu interfeisa izmaiÅu aktualizÄciju.
+Preferences.General.Show_File_Size:RÄdÄ«t datÅu izmÄrus
+Preferences.General.Show_File_Size_Tooltip:RÄdÄ«t datÅu izmÄrus pie katras ieejas DarbatelpÄ un Kolekcijas datÅu kokÄ.
+Preferences.General.View_Extracted_Metadata:SkatÄ«t Izvilktus Metadatus
+Preferences.General.View_Extracted_Metadata_Tooltip:ParÄdÄ«t greenstone spraudÅu izvilktos metadatus metadatu sarakstÄ BagÄtinÄÅ¡anas panelÄ«.
+Preferences.Mode:ReÅŸÄ«ms
+Preferences.Mode_Tooltip:NokliÅ¡Ä·iniet uz ieeju, lai izvÄletos piemÄrotu operÄÅ¡anas lÄ«meni
+Preferences.Mode.Assistant:BibliotekÄra Asistents
+Preferences.Mode.Assistant_Description:Izmantojiet Å¡o iestatÄ«jumu, lai iegÅ«tu piekÄŒuvi Greenstone BibliotekÄra Interfeisa pamata iespÄjÄm: pievienot dokumentus un metadatus kolekcijÄm, jauno kolekciju radÄ«Å¡ana, kuru struktÅ«ra atspoguÄŒo jau esoÅ¡as kolekcijas, un kolekciju veidoÅ¡ana.
+Preferences.Mode.Librarian:BibliotekÄrs
+Preferences.Mode.Librarian_Description:Å is iestatÄ«jums ÄŒauj normÄli izmantot Greenstone BibliotekÄra Interfeisu: radÄ«t un noformÄt jaunas kolekcijas, pievienot dokumentus un metadatus kolekcijÄm, jaunu kolekciju noformÄÅ¡anu (dizainu), un kolekciju veidoÅ¡anu (bÅ«vÄÅ¡anu).
+Preferences.Mode.Systems:BibliotÄku SistÄmu SpeciÄlists
+Preferences.Mode.Systems_Description: Å is iestatÄ«jums atÄŒauj pilnu Greenstone BibliotekÄra Interfeisa izmantoÅ¡anu. Lai izmantotu visu iespÄju priekÅ¡rocÄ«bas, jums bÅ«s nepiecieÅ¡ams mÄcÄt formulÄt regulÄrÄs izteiksmes.
+Preferences.Mode.Expert:Eksperts
+Preferences.Mode.Expert_Description:Å is iestatÄ«jums ÄŒauj ekspertam izmantot Greenstone BibliotekÄra Interfeisu. Tas tiek rekomendÄts lietotÄjiem, kuri ir pieredzÄjuÅ¡i darbam ar Greenstone, un ir spÄjÄ«gi veikt kÄŒÅ«du laboÅ¡anas uzdevumus, kas prasa interpretÄt atkÄŒÅ«doÅ¡anas izvadi no PERL skriptiem. Visas Greenstone BibliotekÄra Interfeisa iespÄjas ir atÄŒautas.
+Preferences.Warnings:BrÄ«dinÄjumi
+Preferences.Warnings_Tooltip:AtÄŒaut vai aizliegt daÅŸÄdus brÄ«dinÄjumu dialogus
+Preferences.Workflow:DarbplÅ«sma
+Preferences.Workflow_Tooltip:IestÄdÄ«t interfeisa darbplÅ«smu: noteikt, kurus skatus (tabulÄtorus) atÄŒaut
+Preferences.Workflow.Create:RadÄ«t - Veidot jÅ«su kolekciju izmantojot Greenstone
+Preferences.Workflow.Design:Dezains - IzmainÄ«t kolekcijas Ärieni
+Preferences.Workflow.Download:LejupielÄde - LejupielÄdÄt web-bÄzÄtos resursus
+Preferences.Workflow.Enrich:BagÄtinÄt - AprakstÄ«t ar metadatiem
+Preferences.Workflow.Gather:UzkrÄt - AtlasÄ«t datnes kolekcijai
+Preferences.Workflow.Predefined.Label:IepriekÅ¡noteiktas DarbplÅ«smas
+Preferences.Workflow.Title:IzvÄlieties rÅ«tiÅu, lai atÄŒautu skatu
+#**********************
+#
+#**** PreviewCommandDialog *******
+PreviewCommandDialog.Instructions:Ievadiet komandu, programmas palaiÅ¡anai, lai skatÄ«tu kolekcijas priekÅ¡skatÄ«jumu. Atcerieties izmantot %1, kÄ kolekcijas adreses vietturi, un dubultpÄdiÅas kur nepiecieÅ¡ams.
+PreviewCommandDialog.Title:PriekÅ¡skatÄ«juma Komanda
+#**********************
+#
+#***** Save Collection Box *****
+SaveCollectionBox.File_Name:Datnes VÄrds:
+SaveCollectionBox.Files_Of_Type:DatÅu Tips:
+SaveCollectionBox.Look_In:IelÅ«koties:
+#**********************
+#
+#***** Save Progress Box *******
+SaveProgressDialog.Title:Kolekcijas SaglabÄÅ¡ana
+#*******************************
+#
+Server.QuitManual:BibliotekÄra Interfeiss nevarÄja aizvÄrt lokÄlo\n bibliotÄkas serveri automÄtiski. LÅ«dzu izejiet no servera\nmanuÄli, noklikÅ¡Ä·inot, uz tÄ augÅ¡ÄjÄ stÅ«rÄ« labÄs\npuses krusta ikonas.
+Server.QuitTimeOut:Greenstone lokÄlÄ bibliotÄka nav atbildÄjusi uz\nautomÄtisko aizvÄrt komandu 60 sekundes. Vai jÅ«s\nvÄlaties gaidÄ«t vÄl minÅ«ti?
+#
+#***** Sources *****
+Source.General:VispÄrÄ«gs
+#*******************
+#
+#***** TitleClash *****
+TitleClashes.Message:Nosaukums, kuru jÅ«s esat izvÄlÄjuÅ¡ies jÅ«su kolekcijai, tiek jau lietots. TurpinÄt?
+TitleClashes.Title:IevadÄ«tÄ Nosaukuma nesaskaÅas
+#**********************
+#
+#***** Trees *****
+Tree.DownloadedFiles:LejupielÄdÄtÄs Datnes
+Tree.Files:datnes
+Tree.Home:SÄkummape ({0})
+Tree.Root:LokÄlÄ DatÅutelpa
+Tree.World:Dokumenti Greenstone KolekcijÄs
+#***********************
+#
+#***** Warning Dialog *****
+WarningDialog.Dont_Show_Again:NerÄdÄ«t Å¡o brÄ«dinÄjumu vÄlreiz
+WarningDialog.Dont_Show_Again_Message:NerÄdÄ«t Å¡o paziÅojumu vÄlreiz
+WarningDialog.Invalid_Value:VÄrtÄ«ba, kuru jÅ«s esat ievadÄ«juÅ¡i vÄrtÄ«bas lauciÅÄ,\nnav pareiza specificÄtam rekvizÄ«tam.
+WarningDialog.Value:Ievadiet vÄrtÄ«bu:
+#
+#****** WGet *****
+WGet.Prompt:Wget AtspoguÄŒoÅ¡anas Klients
+#
+#****** Workflows *****
+Workflow.AllPanels:Visi paneÄŒi
+Workflow.LocalSourceCollectionBuilding:LokÄla avota kolekcijas veidoÅ¡ana
+Workflow.DocumentEnriching:Dokumenta bagÄtinÄÅ¡ana
+
+GEMS.Already_Loaded_Set_Error: JÅ«su izvÄletÄ metadatu kopa patreiz ir atvÄrta.
+GEMS.Element_Already_Exists:Elements ar Å¡o vÄrdu jau eksistÄ.
+GEMS.Set_Already_Exists:Kopa ar doto vÄrdutelpu jau eksistÄ.
+GEMS.Cannot_Delete_Core_Sets_Error:JÅ«s nevarat izdzÄst GBI kodola metadatu kopu.
+
+GEMS.Preferences.Selected_Languages_Tooltip: IzvÄlieties parÄdÄ«Å¡anas valodu:
+
+GEMS.Add_Attribute:Pievienot atribÅ«tu
+GEMS.Add_Attribute_Tooltip:Pievienot jaunu atribÅ«tu izvÄlÄtam vienumam
+GEMS.Add_Element:Pievienot elementu
+GEMS.Add_Element_Tooltip:Pievienot jaunu elementu izvÄlÄtai kopai
+GEMS.Add_Subelement:Pieviento apakÅ¡elementu
+GEMS.Add_Subelement_Tooltip:Pievienot jaunu apakÅ¡elementu izvÄlÄtam elementam
+GEMS.Add_Set:Pieviento Kopu
+GEMS.Attribute:AtribÅ«ts
+GEMS.Attribute_Already_Exists:Å is atribÅ«ts jau eksistÄ.
+GEMS.Attribute_Name_Tooltip:JaunÄ atribÅ«ta nosaukums
+GEMS.Attribute_Language_Tooltip:JaunÄ atribÅ«ta valoda
+GEMS.Attribute_Value_Tooltip:JaunÄ atribÅ«ta vÄrtÄ«ba
+GEMS.Attributes:AtribÅ«ti
+GEMS.Cannot_Undo:(Å¡Ä« darbÄ«ba nevar tikt atsaukta)
+GEMS.Cannot_Add_Elements_To_Greenstone_MDS:JÅ«s nevarat manuÄli pievienot elementus Greenstone Metadatiem. Ja\nnepiecieÅ¡ams radÄ«t jaunu kopu, tad ta vietÄ pievienojiet jÅ«su jauno elementu tam.
+GEMS.Confirm_Exit_Save: Vai jÅ«s nevÄlaties saglabÄt pirms izieÅ¡anas?
+GEMS.Confirm_Exit_Save_Title: SaglabÄt Pirms IzieÅ¡anas?
+GEMS.Confirm_Removal:Vai jÅ«s esat pÄrliecinÄti, ka gribat izdzÄst Å¡o {0}?
+GEMS.Confirm_Removal_Title:ApstiprinÄt IzdzÄÅ¡anu
+GEMS.Edit_Attribute:RediÄ£Ät AttribÅ«tu
+GEMS.Edit_Value:RediÄ£Ät VÄrtÄ«bu
+GEMS.Edit_Value_Tooltip:IzmainÄ«t izvÄlÄto vÄrtÄ«bu
+GEMS.Element:Elements
+GEMS.Element_Name_Tooltip:JaunÄ elementa nosaukums
+GEMS.Element_Details:Metadatu Elementa DetaÄŒas
+GEMS.Language:Valoda
+GEMS.Language_Code:Valoda
+GEMS.Name:Nosaukums
+GEMS.Namespace:VÄrdutelpa
+GEMS.New_Name:Jauns Nosaukums
+GEMS.No_Description:Apraksts nav atrasts.
+GEMS.No_Name:Nosaukums nav atrasts.
+GEMS.Open_Set:AtvÄrt Kopu
+GEMS.Remove_Attribute:NoÅemt attribÅ«tu
+GEMS.Remove_Attribute_Tooltip:IzdzÄst izvÄlÄto atribÅ«tu
+GEMS.Remove_Element:NoÅemt elementu
+GEMS.Remove_Element_Tooltip:IzdzÄst izvÄlÄto elementu no kopas
+GEMS.Remove_Set:NoÅemt kopu
+GEMS.Remove_Set_Tooltip:IzdzÄst izvÄlÄto kopu
+GEMS.Rename_Element:PÄrdÄvÄt elementu
+GEMS.Rename_Element_Tooltip:Elementa jauns nosaukums
+GEMS.Rename_Name_Tooltip:Metadatu kopas jaunais nosaukums
+GEMS.Rename_Namespace_Tooltip:Metadatu kopas unikÄlÄ vÄrdutelpa
+GEMS.Rename_Set:PÄrdÄvÄt kopu
+GEMS.Rename_Set_Tooltip:PÄrdÄvÄt metadatu kopu
+GEMS.Set:Kopa
+GEMS.Set_Details:Metadatu Kopas DetaÄŒas
+GEMS.Set_Name_Tooltip:JaunÄs metadatu kopas vÄrds (nosaukums)
+GEMS.Set_Namespace_Tooltip:UnikÄlÄ vÄrdutelpa jaunai metadatu kopai
+GEMS.Subelement_Name_Tooltip:JaunÄ apakÅ¡elementa nosaukums
+GEMS.Subelement_Already_Exists:ApakÅ¡elements ar Å¡o nosaukumu jau eksistÄ.
+GEMS.Target:Elements
+GEMS.Title:Greenstone Metadatu Kopu Redaktors
+GEMS.Value:VÄrtÄ«ba
+GEMS.Values:VÄrtÄ«bas
+GEMS.inheritMetadataSet:PÄrmantot no Metadatu kopas:
+GEMS.Add_Set.No_Inherit:NepÄrmantot
Index: /tags/gsdl-2_61-distribution/gli/classes/feedback.properties
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/feedback.properties	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/feedback.properties	(revision 10506)
@@ -0,0 +1,264 @@
+TextComponent=Text Component
+true=True
+false=False
+Button=Button
+icon=icon
+NoImage=No Image
+ProgressBar=Progress Bar
+Slider=Slider
+Spinner=Spinner
+Label=Label
+ComboBox=Combo Box
+Selected=Selected
+NotSelected=Not Selected
+ToggleButton=Toggle Button
+MenuItem=Menu Item
+MenuBar=Menu Bar
+Window=Window
+Panel=Panel
+Scroller=Scroller
+OptionPane=Option Pane
+ViewPort=View Port
+Box=Box
+Splitters=Splitters
+List=List
+ColorChooser=Color Chooser
+PreviewPanel=Preview Panel
+ChooserPanels=Chooser Panels
+DesktopPane=Desktop Pane
+black=BLACK
+BLACK=BLACK
+blue=BLUE
+BLUE=BLUE
+cyan=CYAN
+CYAN=cyan
+gray=GRAY
+GRAY=GRAY
+green=GREEN
+GREEN=GREEN
+DARK_GRAY=DARK_GRAY
+darkGray=DARK_GRAY
+LIGHT_GRAY=LIGHT_GRAY
+lightGray=LIGHT_GRAY
+magenta=MAGENTA
+MAGENTA=MAGENTA
+orange=ORANGE
+ORANGE=ORANGE
+pink=PINK
+PINK=PINK
+red=RED
+RED=RED
+white=WHITE
+WHITE=WHITE
+YELLOW=YELLOW
+Table=Table
+row=Row
+ScrollerBar=Scroller Bar
+Tree=Tree
+Container=Container
+RootPane=Root Pane
+LayeredPane=Layered Pane
+InternalFrameTitlePane=Internal Frame Title Pane
+TableHeader=Table Header
+ToolBar=Tool Bar
+Conformation=Conformation
+ConformationText=Thank you for using this Send Feedback feature.\n\nDo you want to preview the report details you are about to send to us?\n
+Preview=Preview
+ConformationPreview=View information you about to send.
+Send=Send
+ConformationSend=Send all information inputted.
+Don'tSend=Don't Send
+NotSend=Not Send
+ConformationNotSend=Do not send all information inputted.
+content=content
+command=command
+feedback=feedback
+SendFeedback=Send Feedback
+SendFeedbackButton=Open Send feedback form
+SendFeedbackForm=Send Feedback Form
+FeedbackOpeningText=Feedback\n\nSending this report indicate that you have found the applications you were doing have some problems.You do not have to fill out the form -- any information will help.\n\nDescriptions:
+Whatkindofproblemisit=What kind of problem is it
+ContentError=Content Error
+ImageNotShow=Image Not Show
+StrangeBehaviour=Strange Behaviour
+SomethingUnexpectedHappen=Something Unexpected Happen
+HardToUse=Hard To Use
+Other=Other
+Howbadistheproblem=How bad is the problem
+Critical=Critical
+Serious=Serious
+Medium=Medium
+Minor=Minor
+Trivial=Trivial
+Doyouwanttosendthescreenshot=Do you want to send the screen shot
+Yes=Yes
+No=No
+FeedbackSendButton=Send all information inputted
+FeedbackNotSendButton=Do not send all information inputted
+FeedbackHelpText=How to report feedback\n\nYou do not have to fill in any of the form -- any information will help.\n\nClicking on thumbnail will allow you to draw scribble lines marking the problem and type more comments about it.\nIf you finish scribbling then you can click Finish Scribble which will take you back to Feedback form, or Send button which will send all the information you gave so far.\n\nYou can type your comment inside the comments text area.\n\nIf you go to any opened window and select screen shot then it will add the screen shot's thumbnail to problem details area.\n\nDetails... button will allow you to preview the xml files that are going to be send.\nSend button will send all the information away.
+FeedbackAboutText=About\n\nMany open source projects are under-utilised because normal users find the software they produce hard to use. The Send feedback button is an attempt by members of the Greenstone project to involve the users of Greenstone in making the software easier to use.\n\nEvery time you click a button in GLI, some information is collected about what you were doing in GLI at the time. This information can hopefully help the people working on the Greenstone project to figure out what caused the problems you had, and how to fix it.
+FeedbackPrivacyText=Privacy\n\nYour privacy is important to us. We assure you that we will take no information that can lead to your personal identification. Any information you provide will be used strictly for the research and for determining how to make Greenstone more usable, no other uses of the data will be allowed.\n\nNo information about anything other than GLI and the technology you use to view it (for example your screen size) will be taken.\n\nThe information we you provide will have a timestamp on it, and may be correlated with your activity within Greenstone around the time you made your complaint.
+Form=Form
+About=About
+Privacy=Privacy
+screen=screen
+ErrorLineAnd=ErrorLineAnd
+ErrorLineFor=ErrorLineFor
+Don'twanttosendscreenshot=Don't want to send the screenshot
+SendFeedback=Send Feedback
+CurrentlyOpenWindow=CurrentlyOpenWindow
+WindowActivated=Window Activated
+WindowOpened=Window Opened
+WindowClosed=Window Closed
+WindowDeactivated=Window Deactivated
+ChangeState=Change State
+Node=Node
+ValueChanged=ValueChanged
+Change=Change
+Inserted=Inserted
+Removed=Removed
+TreeStructuredChanged=Tree Structure Changed
+ItemStateChanged=Item State Changed
+ListChanged=List Changed
+ListContentsAdded=List Contents Added
+ListContentRemoved=List Content Removed
+ListValueChanged=List Value Changed
+MenuCanceled=Menu Canceled
+MenuDeselected=Menu Deselected
+MenuSelected=Menu Selected
+ColumnIndex=Column Index
+AddedToTable=Added to table
+ColumnIndexFrom=From column index
+MoveToColumnIndex=move to column index
+InTheTable=in the table
+RemovedFromTheTable= removed from the table
+ViewReport=View Report
+ViewFeedbackForm=View Feedback Form
+ViewHistoryState=View History State
+ViewCommandState=View Commands
+Close=Close
+ClosePreview=Close the preview window
+HISTORY=HISTORY
+BUGS=BUGS
+IDCode=IDCode
+LastViewedWindow=LastViewedWindow
+Optionals=Optionals
+Details=Details
+Type=Type
+Urgency=Urgency
+User=User
+Name=Name
+HomeDirectory=HomeDirectory
+WorkingDirectory=WorkingDirectory
+OpenFormTime=OpenFormTime
+SendFormTime=SendFormTime
+OperatingSystem=OperatingSystem
+JavaInformation=JavaInformation
+DefaultLocale=DefaultLocale
+Browser=Greenstone
+LocalHostName=LocalHostName
+LocalHostAddress=LocalHostAddress
+ScreenResolution=ScreenResolution
+ScreenShot=ScreenShot
+ErrorLineAndScreenShot=ErrorLineAndScreenShot
+ErrorLineForScreenShot=ErrorLineForScreenShot
+COMPONENT=COMPONENT
+Type=Type
+Title=Title
+Content=Content
+Visible=Visible
+Image=Image
+Date=Date
+Command=Command
+COMPONENTS=COMPONENTS
+LOG=LOG
+View=View
+Showwhereistheproblem=Show where is the problem
+ScreenShotLabel=Use the mouse to indicate where the problem occured. Click send once you finished.
+Rectangle=Rectangle
+RectangleToolTip=Tool to draw rectangle
+Arrow=Arrow
+ArrowToolTip=Tool to draw arrow line
+SendTheImage=Sending the image
+SMTPaddress=What is your SMTP address
+Emailaddress=What is your e-mail address
+SendAttachment=Hereby attached 2 jar files.Please download them at the same place and parser.jar is an executable jar file.\nPlease keep referencing to this ID Code\nID Code:
+Email=Email
+SMTP=SMTP
+HISTORYCOMMANDS=COMMANDS
+TotalMemory=TotalMemory
+MaxMemory=MaxMemory
+FreeMemory=FreeMemory
+ViewFileTitle=Viewing the XML file
+ViewFeedbackFile=View FeedbackInterface form file
+ViewFeedbackCommandFile=View feedback command's history file
+ViewFeedbackContentFile=View feedback's history file
+ViewContentFile=View History file
+ViewCommandFile=View Command's history file
+ParsingXMLText=Select the checkbox of the file you want to see
+View=View
+ViewToolTip=View the files selected from the check box
+CloseToolTip=Close this application
+ViewCode=Please enter the id code as written in your email
+COMMANDS=COMMANDS
+Pleasewait=Please wait this may take a while
+Java=Java
+InternalError=Sorry. There was an internal error while sending your message!Please make sure you connected to the internet.
+SendFailed=Send Failed.Please make sure you connected to the internet.Do you want to try again?
+Error=Error
+NotFoundProvider=Provider not Found!\n\nPlease enter your SMTP adress again
+NotFoundProvider2=Please enter the email address for that SMTP address.
+Emaillater=We will try to send this feedback documents next time you send another feedback document.
+ScreenShotDescription=ScreenShotDescription
+ProblemDetails=Problem Details :
+Size=Size
+Height=Height
+Width=Width
+Icon=Icon
+Viewfeedback=View Feedback
+Viewcontent=View Content
+Viewcommand=View Command
+Separator=Separator
+NoComponent=No Component (it's a null object)
+TitlePane=Metal Title Pane (Platform dependent)
+ToolTipText=ToolTipText
+Feedback=Feedback
+LookHistory=View History
+LookHistoryButton=View History of all the commands you've done
+RecreateEvent=Recreate the Event
+RecreateOpeningText=You can add your comments in the text area.Click the Screen Shot button to take the screenshot of this window.Click Send button once you finished recreating the event.
+SendRecreate=Send Recreate
+SaveRecreate=Save Recreate
+RecreateSaveButton=Save all the comments entered.
+Comment=Comment
+RecreateOption=Can you recreate the event that you want to report?
+RecreateTitle=Recreate Event
+Save=Save
+RecordReady=If you are ready to recreate the event click start.
+Start=Start
+StartRecreate=Start Recreate Event
+StartRecText=Start recording all the action you did.
+ViewFeedbackHistoryState=View Feedback History
+ViewFeedbackCommandState=View Feedback Command
+DLGmessage=We start recording every action you do now.
+Ok=Ok
+SnapShot=Screen Shot
+SnapShotText=SnapShotText
+SnapShotButton=Take screen shot of the window you are in now.
+ViewMovie=View Picture
+ViewMovieText=View all the sequence of action
+FramesPerSecond=Frames Per Second
+GenerateMovie=Frames sequences
+image=Image
+notfound=Not Found
+COMMENTS=COMMENTS
+Viewcomment=View comment
+ViewCommentFile=View Comment File
+SnapShotAppend=Screen Shot taken
+Start=Start
+Finish=Finish
+Sequences=Sequences
+Sequence=Sequence
+ImageDescription=ImageDescription
+
+
Index: /tags/gsdl-2_61-distribution/gli/classes/xml/CollectionConfig.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/CollectionConfig.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/CollectionConfig.xml	(revision 10506)
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<CollectionConfig>
+</CollectionConfig>
Index: /tags/gsdl-2_61-distribution/gli/classes/xml/collect_cfg.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/collect_cfg.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/collect_cfg.xml	(revision 10506)
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE Configuration [
+  <!ELEMENT Configuration (Gatherer)>
+  <!ELEMENT Gatherer      (Workflow)>
+  <!ELEMENT Workflow      (Browse, Mirror, Import, Gather, Enrich, Design, Export, Preview)>
+  <!ELEMENT Browse        (#PCDATA)>
+  <!ELEMENT Mirror        (#PCDATA)>  
+  <!ELEMENT Gather        (#PCDATA)>
+  <!ELEMENT Enrich        (#PCDATA)>
+  <!ELEMENT Design        (#PCDATA)>
+  <!ELEMENT Export        (#PCDATA)>
+  <!ELEMENT Preview       (#PCDATA)>
+]>
+
+<Configuration>
+  <Gatherer>
+    <Workflow>
+	   <Browse  enabled="true"/>
+		<Mirror  enabled="true"/>
+		<Import  enabled="true"/>
+		<Gather  enabled="true"/>
+		<Enrich  enabled="true"/>
+		<Design  enabled="true"/>
+		<Export  enabled="true"/>
+		<Preview enabled="true"/>
+	 </Workflow>
+  </Gatherer>
+</Configuration>
+
+
Index: /tags/gsdl-2_61-distribution/gli/classes/xml/config.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/config.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/config.xml	(revision 10506)
@@ -0,0 +1,136 @@
+<?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.61">
+  <GathererConfig>
+    <!-- ***** General Options: apply globally to the GLI 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>
+    <Argument name="general.email"/>
+    <!-- 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.MissingEXEC">true</Argument>
+    <Argument name="warning.MissingEXEC_GS3">true</Argument>
+    <Argument name="warning.MissingGSDL">true</Argument>
+    <Argument name="warning.MissingImageMagick">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="workflow.download">true</Argument>
+    <Argument name="workflow.gather">true</Argument>
+    <Argument name="workflow.enrich">true</Argument>
+    <Argument name="workflow.design">true</Argument>
+    <Argument name="workflow.create">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: /tags/gsdl-2_61-distribution/gli/classes/xml/configRemote.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/configRemote.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/configRemote.xml	(revision 10506)
@@ -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.61">
+  <GathererConfig>
+    <!-- ***** General Options: apply globally to the GLI 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.MissingImageMagick">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="workflow.download">false</Argument>
+    <Argument name="workflow.gather">true</Argument>
+    <Argument name="workflow.enrich">true</Argument>
+    <Argument name="workflow.design">true</Argument>
+    <Argument name="workflow.create">true</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: /tags/gsdl-2_61-distribution/gli/classes/xml/gli.lck
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/gli.lck	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/gli.lck	(revision 10506)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="ASCII" ?>
+
+<LockFile>
+  <User></User>
+  <Machine></Machine>
+  <Date></Date>
+</LockFile>
Index: /tags/gsdl-2_61-distribution/gli/classes/xml/languages.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/languages.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/languages.xml	(revision 10506)
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE Languages [
+   <!ELEMENT Languages     (Language*)>
+   <!ELEMENT Language      (#PCDATA)>
+   <!-- name: The name of the language -->
+   <!-- code: The two letter language code -->
+   <!-- gs:   Does greenstone include support for this language? -->
+   <!-- gli:  Does gli have a dictionary for this language? -->
+   <!-- mds:  Does any metadata set include support for this language? -->
+   <!ATTLIST Language
+             name          CDATA #REQUIRED
+	     code          CDATA #REQUIRED
+	     gs            CDATA "false"
+	     gli           CDATA "false"
+	     mds           CDATA "false">
+]>
+
+<Languages>
+   <Language name="ABKHAZIAN"           code="AB">IBERO-CAUCASIAN</Language>
+   <Language name="AFAN(OROMO)"         code="OM">HAMITIC</Language>
+   <Language name="AFAR"                code="AA">HAMITIC</Language>
+   <Language name="AFRIKAANS"           code="AF">GERMANIC</Language>
+   <Language name="ALBANIAN"            code="SQ">INDO-EUROPEAN (OTHER)</Language>
+   <Language name="AMHARIC"             code="AM">SEMITIC</Language>
+   <Language name="ARABIC"              code="AR" gs="true" mds="true">SEMITIC</Language>
+   <Language name="ARMENIAN"            code="HY" gs="true">INDO-EUROPEAN (OTHER)</Language>
+   <Language name="ASSAMESE"            code="AS">INDIAN</Language>
+   <Language name="AYMARA"              code="AY">AMERINDIAN</Language>
+   <Language name="AZERBAIJANI"         code="AZ">TURKIC/ALTAIC</Language>
+   <Language name="BASHKIR"             code="BA">TURKIC/ALTAIC</Language>
+   <Language name="BASQUE"              code="EU">BASQUE</Language>
+   <Language name="BENGALI(BANGLA)"     code="BN">INDIAN</Language>
+   <Language name="BHUTANI"             code="DZ">ASIAN</Language>
+   <Language name="BIHARI"              code="BH">INDIAN</Language>
+   <Language name="BISLAMA"             code="BI">[not given]</Language>
+   <Language name="BRETON"              code="BR">CELTIC</Language>
+   <Language name="BULGARIAN"           code="BG">SLAVIC</Language>
+   <Language name="BURMESE"             code="MY">ASIAN</Language>
+   <Language name="BYELORUSSIAN"        code="BE">SLAVIC</Language>
+   <Language name="CAMBODIAN"           code="KM">ASIAN</Language>
+   <Language name="CATALAN"             code="CA">ROMANCE</Language>
+   <Language name="CHINESE-SIMPLIFIED"  code="CN" gs="true" mds="true">ASIAN</Language>
+   <Language name="CHINESE-TRADITIONAL" code="ZH" gs="true">ASIAN</Language>
+   <Language name="CORSICAN"            code="CO">ROMANCE</Language>
+   <Language name="CROATIAN"            code="HR" gs="true">SLAVIC</Language>
+   <Language name="CZECH"               code="CS" gs="true" mds="true">SLAVIC</Language>
+   <Language name="DANISH"              code="DA">GERMANIC</Language>
+   <Language name="DUTCH"               code="NL" gs="true" mds="true">GERMANIC</Language>
+   <Language name="ENGLISH"             code="EN" gs="true" gli="true" mds="true">GERMANIC</Language>
+   <Language name="ESPERANTO"           code="EO">INTERNATIONAL AUX.</Language>
+   <Language name="ESTONIAN"            code="ET">FINNO-UGRIC</Language>
+   <Language name="FAROESE"             code="FO">GERMANIC</Language>
+   <Language name="FIJI"                code="FJ">OCEANIC/INDONESIAN</Language>
+   <Language name="FINNISH"             code="FI" gs="true" mds="true">FINNO-UGRIC</Language>
+   <Language name="FRENCH"              code="FR" gs="true" gli="true" mds="true">ROMANCE</Language>
+   <Language name="FRISIAN"             code="FY">GERMANIC</Language>
+   <Language name="GALICIAN"            code="GL" gs="true">ROMANCE</Language>
+   <Language name="GEORGIAN"            code="KA">IBERO-CAUCASIAN</Language>
+   <Language name="GERMAN"              code="DE" gs="true">GERMANIC</Language>
+   <Language name="GREEK"               code="EL" gs="true">LATIN/GREEK</Language>
+   <Language name="GREENLANDIC"         code="KL">ESKIMO</Language>
+   <Language name="GUARANI"             code="GN">AMERINDIAN</Language>
+   <Language name="GUJARATI"            code="GU">INDIAN</Language>
+   <Language name="HAUSA"               code="HA">NEGRO-AFRICAN</Language>
+   <Language name="HEBREW"              code="IW" gs="true">SEMITIC [*Changed back from HE in 2003 by us. Not valid iso639, HE]</Language>
+   <Language name="HINDI"               code="HI" gs="true">INDIAN</Language>
+   <Language name="HUNGARIAN"           code="HU">FINNO-UGRIC</Language>
+   <Language name="ICELANDIC"           code="IS">GERMANIC</Language>
+   <Language name="INDONESIAN"          code="ID" gs="true">OCEANIC/INDONESIAN [*Changed 1989 from original ISO 639:1988, IN]</Language>
+   <Language name="INTERLINGUA"         code="IA" mds="true">INTERNATIONAL AUX.</Language>
+   <Language name="INTERLINGUE"         code="IE">INTERNATIONAL AUX.</Language>
+   <Language name="INUKTITUT"           code="IU">[        ]</Language>
+   <Language name="INUPIAK"             code="IK">ESKIMO</Language>
+   <Language name="IRISH"               code="GA">CELTIC</Language>
+   <Language name="ITALIAN"             code="IT" gs="true">ROMANCE</Language>
+   <Language name="JAPANESE"            code="JA" gs="true">ASIAN</Language>
+   <Language name="JAVANESE"            code="JV">OCEANIC/INDONESIAN</Language>
+   <Language name="KANNADA"             code="KN" gs="true">DRAVIDIAN</Language>
+   <Language name="KASHMIRI"            code="KS">INDIAN</Language>
+   <Language name="KAZAKH"              code="KZ" gs="true">TURKIC/ALTAIC [*Changed 2003 by us. Not valid iso639, KK]</Language>
+   <Language name="KINYARWANDA"         code="RW">NEGRO-AFRICAN</Language>
+   <Language name="KIRGHIZ"             code="KY">TURKIC/ALTAIC</Language>
+   <Language name="KOREAN"              code="KO">ASIAN</Language>
+   <Language name="KURDISH"             code="KU">IRANIAN</Language>
+   <Language name="KURUNDI"             code="RN">NEGRO-AFRICAN</Language>
+   <Language name="LAOTHIAN"            code="LO">ASIAN</Language>
+   <Language name="LATIN"               code="LA">LATIN/GREEK</Language>
+   <Language name="LATVIAN (LETTISH)"   code="LV" gli="true">BALTIC</Language>
+   <Language name="LINGALA"             code="LN">NEGRO-AFRICAN</Language>
+   <Language name="LITHUANIAN"          code="LT">BALTIC</Language>
+   <Language name="MACEDONIAN"          code="MK">SLAVIC</Language>
+   <Language name="MALAGASY"            code="MG">OCEANIC/INDONESIAN</Language>
+   <Language name="MALAY"               code="MS">OCEANIC/INDONESIAN</Language>
+   <Language name="MALAYALAM"           code="ML">DRAVIDIAN</Language>
+   <Language name="MALTESE"             code="MT">SEMITIC</Language>
+   <Language name="MAORI"               code="MI" gs="true" mds="true">OCEANIC/INDONESIAN</Language>
+   <Language name="MARATHI"             code="MR" mds="true">INDIAN</Language>
+   <Language name="MOLDAVIAN"           code="MO">ROMANCE</Language>
+   <Language name="MONGOLIAN"           code="MN">[not given]</Language>
+   <Language name="NAURU"               code="NA">[not given]</Language>
+   <Language name="NEPALI"              code="NE">INDIAN</Language>
+   <Language name="NORWEGIAN"           code="NO">GERMANIC</Language>
+   <Language name="OCCITAN"             code="OC">ROMANCE</Language>
+   <Language name="ORIYA"               code="OR">INDIAN</Language>
+   <Language name="PASHTO(PUSHTO)"      code="PS">IRANIAN</Language>
+   <Language name="PERSIAN(FARSI)"      code="FA">IRANIAN</Language>
+   <Language name="POLISH"              code="PL">SLAVIC</Language>
+   <Language name="PORTUGUESE"          code="PT" gs="true">ROMANCE</Language>
+   <Language name="PUNJABI"             code="PA">INDIAN</Language>
+   <Language name="QUECHUA"             code="QU">AMERINDIAN</Language>
+   <Language name="RHAETO-ROMANCE"      code="RM">ROMANCE</Language>
+   <Language name="ROMANIAN"            code="RO">ROMANCE</Language>
+   <Language name="RUSSIAN"             code="RU" gs="true" gli="true" mds="true">SLAVIC</Language>
+   <Language name="SAMOAN"              code="SM">OCEANIC/INDONESIAN</Language>
+   <Language name="SANGHO"              code="SG">NEGRO-AFRICAN</Language>
+   <Language name="SANSKRIT"            code="SA">INDIAN</Language>
+   <Language name="SCOTS(GAELIC)"       code="GD">CELTIC</Language>
+   <Language name="SERBIAN"             code="SR">SLAVIC</Language>
+   <Language name="SERBO-CROATIAN"      code="SH">SLAVIC</Language>
+   <Language name="SESOTHO"             code="ST">NEGRO-AFRICAN</Language>
+   <Language name="SETSWANA"            code="TN">NEGRO-AFRICAN</Language>
+   <Language name="SHONA"               code="SN">NEGRO-AFRICAN</Language>
+   <Language name="SINDHI"              code="SD">INDIAN</Language>
+   <Language name="SINGHALESE"          code="SI">INDIAN</Language>
+   <Language name="SISWATI"             code="SS">NEGRO-AFRICAN</Language>
+   <Language name="SLOVAK"              code="SK">SLAVIC</Language>
+   <Language name="SLOVENIAN"           code="SL">SLAVIC</Language>
+   <Language name="SOMALI"              code="SO">HAMITIC</Language>
+   <Language name="SPANISH"             code="ES" gs="true" gli="true" mds="true">ROMANCE</Language>
+   <Language name="SUNDANESE"           code="SU">OCEANIC/INDONESIAN</Language>
+   <Language name="SWAHILI"             code="SW">NEGRO-AFRICAN</Language>
+   <Language name="SWEDISH"             code="SV">GERMANIC</Language>
+   <Language name="TAGALOG"             code="TL">OCEANIC/INDONESIAN</Language>
+   <Language name="TAJIK"               code="TG">IRANIAN</Language>
+   <Language name="TAMIL"               code="TA">DRAVIDIAN</Language>
+   <Language name="TATAR"               code="TT">TURKIC/ALTAIC</Language>
+   <Language name="TELUGU"              code="TE">DRAVIDIAN</Language>
+   <Language name="THAI"                code="TH" gs="true">ASIAN</Language>
+   <Language name="TIBETAN"             code="BO">ASIAN</Language>
+   <Language name="TIGRINYA"            code="TI">SEMITIC</Language>
+   <Language name="TONGA"               code="TO">OCEANIC/INDONESIAN</Language>
+   <Language name="TSONGA"              code="TS">NEGRO-AFRICAN</Language>
+   <Language name="TURKISH"             code="TR" gs="true">TURKIC/ALTAIC</Language>
+   <Language name="TURKMEN"             code="TK">TURKIC/ALTAIC</Language>
+   <Language name="TWI"                 code="TW">NEGRO-AFRICAN</Language>
+   <Language name="UIGUR"               code="UG">[       ]</Language>
+   <Language name="UKRAINIAN"           code="UK" gs="true">SLAVIC</Language>
+   <Language name="URDU"                code="UR">INDIAN</Language>
+   <Language name="UZBEK"               code="UZ">TURKIC/ALTAIC</Language>
+   <Language name="VIETNAMESE"          code="VI">ASIAN</Language>
+   <Language name="VOLAPUK"             code="VO">INTERNATIONAL AUX.</Language>
+   <Language name="WELSH"               code="CY">CELTIC</Language>
+   <Language name="WOLOF"               code="WO">NEGRO-AFRICAN</Language>
+   <Language name="XHOSA"               code="XH">NEGRO-AFRICAN</Language>
+   <Language name="YIDDISH"             code="YI">GERMANIC [*Changed 1989 from original ISO 639:1988, JI]</Language>
+   <Language name="YORUBA"              code="YO">NEGRO-AFRICAN</Language>
+   <Language name="ZHUANG"              code="ZA">[       ]</Language>
+   <Language name="ZULU"                code="ZU">NEGRO-AFRICAN</Language>
+</Languages>
Index: /tags/gsdl-2_61-distribution/gli/classes/xml/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/metadata.xml	(revision 10506)
@@ -0,0 +1,3 @@
+<?xml version="1.0"  encoding="UTF-8" standalone="no"?>
+<!DOCTYPE DirectoryMetadata SYSTEM "http://greenstone.org/dtd/DirectoryMetadata/1.0/DirectoryMetadata.dtd">
+<DirectoryMetadata/>
Index: /tags/gsdl-2_61-distribution/gli/classes/xml/profile.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/profile.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/profile.xml	(revision 10506)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Profiles [
+<!ELEMENT Profiles (Action*)>
+<!ELEMENT Action (#PCDATA)>
+<!ATTLIST Action
+                source     CDATA #REQUIRED
+                target     CDATA "">
+]>
+<Profiles>
+</Profiles>
Index: /tags/gsdl-2_61-distribution/gli/classes/xml/template.col
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/template.col	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/template.col	(revision 10506)
@@ -0,0 +1,25 @@
+<?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">false</Argument>
+  <GathererConfig/>
+  <BuildConfig>
+    <Build/>
+	 <Import/>
+  </BuildConfig>
+</GathererCollection>
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/classes/xml/template.mds
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/template.mds	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/template.mds	(revision 10506)
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param description A description of this metadata set.                           -->
+  <!-- @param family      The namespace of this metadata set.                           -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param name        The name of this metadata set.                                -->
+  <!-- @param namespace   The abbreviated namespace of this metadata set.               -->
+  <!ELEMENT MetadataSet (Element+)>
+  <!ATTLIST MetadataSet
+				contact     CDATA #REQUIRED
+				creator     CDATA #REQUIRED
+				description CDATA #REQUIRED
+            family      CDATA #REQUIRED
+				lastchanged CDATA #REQUIRED
+            name        CDATA #REQUIRED
+				namespace   CDATA #REQUIRED>
+
+  <!-- An element in the metadata set. -->
+  <!ELEMENT Element (Attribute*,OptionList?,AssignedValues?)>
+  <!ATTLIST Element
+            name       CDATA #REQUIRED
+				occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+
+  <!-- Each element also contains a tree of values that have been assigned to it. This may include a multilayer nested subject hierachy. -->
+  <!ELEMENT AssignedValues (Subject+)>
+
+  <!-- A value. -->
+  <!ELEMENT Subject (Value|Alias?|Subject*)>
+  <!ELEMENT Value (#PCDATA)>
+  <!ATTLIST Value
+            occurances CDATA "1">
+  <!ELEMENT Alias (#PCDATA)>
+]>
+
+<MetadataSet>
+</MetadataSet>
Index: /tags/gsdl-2_61-distribution/gli/classes/xml/workflows.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/classes/xml/workflows.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/classes/xml/workflows.xml	(revision 10506)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE PredefinedWorkflows [
+  <!ELEMENT PredefinedWorkflows (Workflow*)>
+  <!ELEMENT Workflow            (#PCDATA)>
+  <!ATTLIST Workflow
+	download			  CDATA "true"
+	gather				  CDATA "true"
+	enrich				  CDATA "true"
+	design				  CDATA "true"
+	create				  CDATA "true"
+	export				  CDATA "true">
+]>
+
+<PredefinedWorkflows>
+  <Workflow>Workflow.AllPanels</Workflow>
+  <Workflow download="false">Workflow.LocalSourceCollectionBuilding</Workflow>
+  <Workflow design="false" create="false">Workflow.DocumentEnriching</Workflow>
+</PredefinedWorkflows>
Index: /tags/gsdl-2_61-distribution/gli/clean.bat
===================================================================
--- /tags/gsdl-2_61-distribution/gli/clean.bat	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/clean.bat	(revision 10506)
@@ -0,0 +1,47 @@
+@echo off
+set GLILANG=en
+
+
+::  -------- Clean up the Greenstone Librarian Interface directory --------
+
+:: This script must be run from within the directory in which it lives
+if exist clean.bat goto cleanGLI
+    if "%GLILANG%" == "en" echo This script must be run from the directory in which it resides.
+    if "%GLILANG%" == "es" echo Este gui¢n deber  ejecutarse desde el directorio en el que reside.
+    if "%GLILANG%" == "fr" echo Ce script doit tre excut 
+ partir du rpertoire dans lequel il se trouve.
+    if "%GLILANG%" == "ru" echo â®â áªàš¯â €®«Š¥­ ¡ëâì ¢§ïâ š§ €šà¥ªâ®àšš, ¢ ª®â®à®© ®­ à á¯®«®Š¥­
+    goto exit
+
+
+:cleanGLI
+:: ---- Remove class files ----
+echo.
+if "%GLILANG%" == "en" echo Removing the Greenstone Librarian Interface class files...
+if "%GLILANG%" == "es" echo Eliminando los archivos de clase de la Interfaz de la Biblioteca Digital Greenstone...
+if "%GLILANG%" == "fr" echo Suppression des fichiers de classe de Greenstone Librarian Interface
+if "%GLILANG%" == "ru" echo € «¥­š¥ ä ©«®¢ ª« áá  ¡š¡«š®â¥ç­®£® š­â¥àä¥©á  Greenstone
+
+if not exist classes\org\greenstone\gatherer goto done
+
+cd classes\org\greenstone\gatherer
+if exist "*.class" del "*.class"
+if exist "cdm\*.class" del "cdm\*.class"
+if exist "collection\*.class" del "collection\*.class"
+if exist "feedback\*.class" del "feedback\*.class"
+if exist "file\*.class" del "file\*.class"
+if exist "gems\*.class" del "gems\*.class"
+if exist "gui\*.class" del "gui\*.class"
+if exist "metadata\*.class" del "metadata\*.class"
+if exist "shell\*.class" del "shell\*.class"
+if exist "util\*.class" del "util\*.class"
+cd ..\..\..\..
+
+:done
+if "%GLILANG%" == "en" echo Done!
+if "%GLILANG%" == "es" echo ­Hecho!
+if "%GLILANG%" == "fr" echo Termin!
+if "%GLILANG%" == "ru" echo ë¯®«­¥­®!
+
+:exit
+echo.
Index: /tags/gsdl-2_61-distribution/gli/clean.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gli/clean.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/clean.sh	(revision 10506)
@@ -0,0 +1,31 @@
+#!/bin/sh
+glilang=en
+
+##  -------- Clean up the Greenstone Librarian Interface directory --------
+
+## ---- Remove class files ----
+echo
+if [ "$glilang" == "es" ]; then
+    echo "Eliminando los archivos de clase de la Interfaz de la Biblioteca "
+    echo "Digital Greenstone..."
+elif [ "$glilang" == "fr" ]; then
+    echo "Suppression des fichiers de classe de Greenstone Librarian Interface"
+elif [ "$glilang" == "ru" ]; then
+    echo "õÄÁÌÅÎÉÅ ÆÁÊÌÏ× ËÌÁÓÓÁ ÂÉÂÌÉÏÔÅÞÎÏÇÏ ÉÎÔÅÒÆÅÊÓÁ Greenstone"
+else
+    echo "Removing the Greenstone Librarian Interface class files..."
+fi
+
+rm -rf GLI.jar
+rm -rf classes/org/greenstone/gatherer/*
+
+if [ "$glilang" == "es" ]; then
+    echo "¡Hecho!"
+elif [ "$glilang" == "fr" ]; then
+    echo "Terminé!"
+elif [ "$glilang" == "ru" ]; then
+    echo "÷ÙÐÏÌÎÅÎÏ!"
+else
+    echo "Done!"
+fi
+echo
Index: /tags/gsdl-2_61-distribution/gli/copyright/apache_license.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gli/copyright/apache_license.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/copyright/apache_license.txt	(revision 10506)
@@ -0,0 +1,64 @@
+Pollo uses the following components from the Apache projects:
+
+ - Xerces: used to parse XML files. Pollo also depends heavely
+   on Xerces' DOM implementation (including the rarely found support
+   for mutation events).
+
+ - Commons Digester: used to parse the xml-based configuration file
+   of Pollo.
+
+ - log4j
+
+For more information about this projects, visit the following sites:
+http://xml.apache.org
+http://jakarta.apache.org
+
+The following license applies to all this software (substitute
+the word Xerces for all other mentioned projects):
+
+The Apache Software License, Version 1.1
+
+
+Copyright (c) 1999 The Apache Software Foundation.  All rights 
+reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer. 
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+3. The end-user documentation included with the redistribution,
+   if any, must include the following acknowledgment:  
+      "This product includes software developed by the
+       Apache Software Foundation (http://www.apache.org/)."
+   Alternately, this acknowledgment may appear in the software itself,
+   if and wherever such third-party acknowledgments normally appear.
+
+4. The names "Xerces" and "Apache Software Foundation" must
+   not be used to endorse or promote products derived from this
+   software without prior written permission. For written 
+   permission, please contact apache@apache.org.
+
+5. Products derived from this software may not be called "Apache",
+   nor may "Apache" appear in their name, without prior written
+   permission of the Apache Software Foundation.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
Index: /tags/gsdl-2_61-distribution/gli/copyright/mpl_1.1.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gli/copyright/mpl_1.1.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/copyright/mpl_1.1.txt	(revision 10506)
@@ -0,0 +1,171 @@
+MOZILLA PUBLIC LICENSE
+Version 1.1
+**********************
+
+1. Definitions.
+
+      1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party.
+
+      1.1. ''Contributor'' means each entity that creates or contributes to the creation of Modifications.
+
+      1.2. ''Contributor Version'' means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor.
+
+      1.3. ''Covered Code'' means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof.
+
+      1.4. ''Electronic Distribution Mechanism'' means a mechanism generally accepted in the software development community for the electronic transfer of data.
+
+      1.5. ''Executable'' means Covered Code in any form other than Source Code.
+
+      1.6. ''Initial Developer'' means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A.
+
+      1.7. ''Larger Work'' means a work which combines Covered Code or portions thereof with code not governed by the terms of this License.
+
+      1.8. ''License'' means this document.
+
+      1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein.
+
+      1.9. ''Modifications'' means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is:
+            A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications.
+
+            B. Any new file that contains any part of the Original Code or previous Modifications.
+             
+      1.10. ''Original Code'' means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License.
+
+      1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation,  method, process, and apparatus claims, in any patent Licensable by grantor.
+
+      1.11. ''Source Code'' means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge.
+
+      1.12. "You'' (or "Your")  means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You'' includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control'' means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
+
+2. Source Code License.
+
+      2.1. The Initial Developer Grant.
+      The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims:
+            (a)  under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and
+
+            (b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof).
+                          (c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License.
+
+            (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code;  or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices.
+             
+      2.2. Contributor Grant.
+      Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license
+             
+            (a)  under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and
+
+            (b) under Patent Claims infringed by the making, using, or selling of  Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of  Modifications made by that Contributor with its Contributor Version (or portions of such combination).
+
+            (c) the licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first makes Commercial Use of the Covered Code.
+
+            (d)    Notwithstanding Section 2.2(b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2)  separate from the Contributor Version;  3)  for infringements caused by: i) third party modifications of Contributor Version or ii)  the combination of Modifications made by that Contributor with other software  (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor.
+
+
+3. Distribution Obligations.
+
+      3.1. Application of License.
+      The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5.
+
+      3.2. Availability of Source Code.
+      Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party.
+
+      3.3. Description of Modifications.
+      You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code.
+
+      3.4. Intellectual Property Matters
+            (a) Third Party Claims.
+            If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "LEGAL'' which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained.
+
+            (b) Contributor APIs.
+            If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file.
+             
+                (c)    Representations.
+            Contributor represents that, except as disclosed pursuant to Section 3.4(a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License.
+
+
+      3.5. Required Notices.
+      You must duplicate the notice in Exhibit A in each file of the Source Code.  If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice.  If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A.  You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code.  You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer.
+
+      3.6. Distribution of Executable Versions.
+      You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer.
+
+      3.7. Larger Works.
+      You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+      If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it.
+
+5. Application of this License.
+
+      This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+      6.1. New Versions.
+      Netscape Communications Corporation (''Netscape'') may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number.
+
+      6.2. Effect of New Versions.
+      Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License.
+
+      6.3. Derivative Works.
+      If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must (a) rename Your license so that the phrases ''Mozilla'', ''MOZILLAPL'', ''MOZPL'', ''Netscape'', "MPL", ''NPL'' or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+      COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS'' BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+      8.1.  This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive.
+
+      8.2.  If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant")  alleging that:
+
+      (a)  such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i)  agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant.  If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above.
+
+      (b)  any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant.
+
+      8.3.  If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license.
+
+      8.4.  In the event of termination under Sections 8.1 or 8.2 above,  all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+      UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+      The Covered Code is a ''commercial item,'' as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of ''commercial computer software'' and ''commercial computer software documentation,'' as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein.
+
+11. MISCELLANEOUS.
+
+      This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+      As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+      Initial Developer may designate portions of the Covered Code as ?Multiple-Licensed?.  ?Multiple-Licensed? means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the MPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A.
+
+
+EXHIBIT A -Mozilla Public License.
+
+      ``The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+      http://www.mozilla.org/MPL/
+
+      Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
+      ANY KIND, either express or implied. See the License for the specific language governing rights and
+      limitations under the License.
+
+      The Original Code is ______________________________________.
+
+      The Initial Developer of the Original Code is ________________________. Portions created by
+       ______________________ are Copyright (C) ______ _______________________. All Rights
+      Reserved.
+
+      Contributor(s): ______________________________________.
+
+      Alternatively, the contents of this file may be used under the terms of the _____ license (the  ?[___] License?), in which case the provisions of [______] License are applicable  instead of those above.  If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting  the provisions above and replace  them with the notice and other provisions required by the [___] License.  If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the [___] License."
+
+      [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications.] 
Index: /tags/gsdl-2_61-distribution/gli/copyright/qfs_license.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gli/copyright/qfs_license.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/copyright/qfs_license.txt	(revision 10506)
@@ -0,0 +1,11 @@
+Copyright (C) 2003 Quality First Software GmbH
+
+qflib - License
+
+qflib is distributed for free under the terms of the Mozilla Public License Version 1.1, MPL for short. It comes without warranty of any kind. The license grants you free use of qflib, access to the source and the right to modify and redistribute it.
+
+The only restrictions are that you cannot remove Quality First Software GmbH's copyright and that modifications of qflib are automatically covered by the MPL as well. Code that just uses the library through its published interface (referred to as "greater work" in the license) is free to use any license whatever.
+
+As long as these conditions are met there is nothing to inhibit commercial use or commercial distribution of qflib, e.g. together with other software on a CD-rom.
+
+We decided in favor of the MPL because it appears to be a good compromise between protecting openness and free use on the one hand and enabling interoperation with third party software under any license on the other. The text of the license is short and precise compared to others and is comprehensible for the layman. 
Index: /tags/gsdl-2_61-distribution/gli/copyright/wget_license.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gli/copyright/wget_license.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/copyright/wget_license.txt	(revision 10506)
@@ -0,0 +1,100 @@
+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.
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+   1. 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.
+   2. 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.
+   3. 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:
+         1. You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+         2. 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.
+         3. 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.
+   4. 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:
+         1. 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,
+         2. 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,
+         3. 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.
+   5. 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.
+   6. 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.
+   7. 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.
+   8. 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.
+   9. 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.
+  10. 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.
+  11. 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
+  12. 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.
+  13. 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 an 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: /tags/gsdl-2_61-distribution/gli/document.bat
===================================================================
--- /tags/gsdl-2_61-distribution/gli/document.bat	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/document.bat	(revision 10506)
@@ -0,0 +1,103 @@
+@echo off
+set GLILANG=en
+
+
+::  -------- Generate documentation for the Greenstone Librarian Interface --------
+
+:: This script must be run from within the directory in which it lives
+if exist document.bat goto findJavadoc
+    if "%GLILANG%" == "en" echo This script must be run from the directory in which it resides.
+    if "%GLILANG%" == "es" echo Este gui¢n deber  ejecutarse desde el directorio en el que reside.
+    if "%GLILANG%" == "fr" echo Ce script doit tre excut 
+ partir du rpertoire dans lequel il se trouve.
+    if "%GLILANG%" == "ru" echo â®â áªàš¯â €®«Š¥­ ¡ëâì ¢§ïâ š§ €šà¥ªâ®àšš, ¢ ª®â®à®© ®­ à á¯®«®Š¥­
+    goto exit
+
+
+:findJavadoc
+:: ---- Check Javadoc exists ----
+set JAVADOCPATH=
+
+:: Some users may set the above line manually
+if not "%JAVADOCPATH%" == "" goto testJavadoc
+
+    :: If it is set, use the JAVA_HOME environment variable
+    if not "%JAVA_HOME%" == "" goto javahome
+
+    :: Check if Javadoc is on the search path
+    echo %PATH%| winutil\which javadoc.exe | winutil\setvar JAVADOCPATH > setjavadoc.bat
+    call setjavadoc.bat
+    del setjavadoc.bat
+    if not "%JAVADOCPATH%" == "" goto testJavadoc
+
+    :: 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
+
+    winutil\findjava jdk.txt | winutil\setvar JAVADOCPATH > setjavadoc.bat
+    del jdk.txt
+    call setjavadoc.bat
+    del setjavadoc.bat
+
+    :: If nothing was found in the registry, we're stuck
+    if "%JAVADOCPATH%" == "" goto noJavadoc
+
+    set JAVADOCPATH=%JAVADOCPATH%\bin
+    goto testJavadoc
+
+:javahome
+    set JAVADOCPATH=%JAVA_HOME%\bin
+
+:testJavadoc
+:: Check that a Javadoc executable has been found
+if "%GLILANG%" == "en" echo Checking Javadoc: %JAVADOCPATH%
+if "%GLILANG%" == "es" echo Revisando Javadoc: %JAVADOCPATH%
+if "%GLILANG%" == "fr" echo Vrification de Javadoc: %JAVADOCPATH%
+if "%GLILANG%" == "ru" echo à®¢¥àª  Javadoc: %JAVADOCPATH%
+if exist "%JAVADOCPATH%\javadoc.exe" goto docGLI
+
+:noJavadoc
+    echo.
+    if "%GLILANG%" == "en" echo Failed to locate an appropriate version of Javadoc. You must install a
+    if "%GLILANG%" == "en" echo Java Development Kit (version 1.4 or greater) before generating the
+    if "%GLILANG%" == "en" echo documentation for the Greenstone Librarian Interface.
+
+    if "%GLILANG%" == "es" echo No se pudo localizar una versi¢n apropiada de Javadoc. Usted deber 
+    if "%GLILANG%" == "es" echo instalar un Kit de Desarrollo de Software Java (versi¢n 1.4 o superior)
+    if "%GLILANG%" == "es" echo antes de generar la documentaci¢n para la Interfaz de la Biblioteca
+    if "%GLILANG%" == "es" echo Digital Greenstone.
+
+    if "%GLILANG%" == "fr" echo Une version approprie de Javadoc n'a pas pu tre localise. Vous devez
+    if "%GLILANG%" == "fr" echo installer un Kit de Dveloppement Java (version 1.4 ou suprieure) avant
+    if "%GLILANG%" == "fr" echo de produire la documentation de Greenstone Librarian Interface.
+
+    if "%GLILANG%" == "ru" echo ¥ ã€ «®áì ®¯à¥€¥«šâì ¬¥áâ®­ å®Š€¥­š¥ á®®â¢¥âáâ¢ãîé¥© ¢¥àášš Javadoc.
+    if "%GLILANG%" == "ru" echo ë €®«Š­ë š­áâ ««šà®¢ âì Java Development Kit (¢¥àášï 1.4 š«š ¢ëè¥)
+    if "%GLILANG%" == "ru" echo ¯à¥Š€¥, ç¥¬ £¥­¥àšà®¢ âì €®ªã¬¥­â æšî €«ï ¡š¡«š®â¥ç­®£®
+    if "%GLILANG%" == "ru" echo š­â¥àä¥©á  Greenstone.
+    goto exit
+
+
+:docGLI
+:: ---- Document the GLI ----
+echo.
+if "%GLILANG%" == "en" echo Generating documentation for the Greenstone Librarian Interface...
+if "%GLILANG%" == "es" echo Generando documentaci¢n para la Interfaz de la Biblioteca Digital Greenstone...
+if "%GLILANG%" == "fr" echo Production de documentation pour la Greenstone Librarian Interface
+if "%GLILANG%" == "ru" echo ¥­¥àšà®¢ ­š¥ €®ªã¬¥­â æšš €«ï ¡š¡«š®â¥ç­®£® š­â¥àä¥©á  Greenstone
+
+"%JAVADOCPATH%\javadoc.exe" -classpath classes/ -sourcepath src/ -source 1.4 -author -breakiterator -d docs/ -group "Greenstone Librarian Interface" org.greenstone.gatherer:org.greenstone.gatherer.cdm:org.greenstone.gatherer.collection:org.greenstone.gatherer.feedback:org.greenstone.gatherer.file:org.greenstone.gatherer.gems:org.greenstone.gatherer.gui:org.greenstone.gatherer.gui.metaaudit:org.greenstone.gatherer.gui.tree:org.greenstone.gatherer.metadata:org.greenstone.gatherer.shell:org.greenstone.gatherer.util -private -splitindex -version   org.greenstone.gatherer org.greenstone.gatherer.cdm org.greenstone.gatherer.collection org.greenstone.gatherer.feedback org.greenstone.gatherer.file org.greenstone.gatherer.gems org.greenstone.gatherer.gui org.greenstone.gatherer.gui.metaaudit org.greenstone.gatherer.gui.tree org.greenstone.gatherer.metadata org.greenstone.gatherer.shell org.greenstone.gatherer.util
+
+if "%GLILANG%" == "en" echo Done!
+if "%GLILANG%" == "es" echo ­Hecho!
+if "%GLILANG%" == "fr" echo Termin!
+if "%GLILANG%" == "ru" echo ë¯®«­¥­®!
+
+:exit
+echo.
+pause
+
+:: ---- Clean up ----
+set JAVADOCPATH=
Index: /tags/gsdl-2_61-distribution/gli/document.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gli/document.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/document.sh	(revision 10506)
@@ -0,0 +1,82 @@
+#!/bin/sh
+glilang=en
+
+
+##  -------- Generate documentation for the Greenstone Librarian Interface --------
+
+## ---- Check Javadoc exists ----
+javadocpath=
+
+# Some users may set the above line manually
+if [ "$javadocpath" == "" ]; then
+
+    # If it is set, use the JAVA_HOME environment variable
+    if [ "$JAVA_HOME" != "" ]; then
+	javadocpath="$JAVA_HOME/bin/javadoc"
+
+    # Check if Javadoc is on the search path
+    else
+	javadocpath=`which javadoc 2> /dev/null`
+    fi
+fi
+
+# Check that a Javadoc executable has been found
+if [ "$glilang" == "es" ]; then
+    echo "Revisando Javadoc: $javadocpath"
+elif [ "$glilang" == "fr" ]; then
+    echo "Vérification de Javadoc: $javadocpath"
+elif [ "$glilang" == "ru" ]; then
+    echo "ðÒÏ×ÅÒËÁ Javadoc: $javadocpath"
+else
+    echo "Checking Javadoc: $javadocpath"
+fi
+if [ ! -x "$javadocpath" ]; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "No se pudo localizar una versión apropiada de Javadoc. Usted deberá "
+        echo "instalar un Kit de Desarrollo de Software Java (versión 1.4 o "
+        echo "superior) antes de generar la documentación para la Interfaz de la "
+        echo "Biblioteca Digital Greenstone."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Une version appropriée de Javadoc n'a pas pu être localisée."
+	echo "Vous devez installer un Kit de Développement Java (version 1.4 ou"
+	echo "supérieure) avant de produire la documentation de Greenstone"
+	echo "Librarian Interface."
+    elif [ "$glilang" == "ru" ]; then
+	echo "îÅ ÕÄÁÌÏÓØ ÏÐÒÅÄÅÌÉÔØ ÍÅÓÔÏÎÁÈÏÖÄÅÎÉÅ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÅÊ ×ÅÒÓÉÉ Javadoc."
+	echo "÷Ù ÄÏÌÖÎÙ ÉÎÓÔÁÌÌÉÒÏ×ÁÔØ Java Development Kit (×ÅÒÓÉÑ 1.4 ÉÌÉ ×ÙÛÅ) "
+	echo "ÐÒÅÖÄÅ, ÞÅÍ ÇÅÎÅÒÉÒÏ×ÁÔØ ÄÏËÕÍÅÎÔÁÃÉÀ ÄÌÑ ÂÉÂÌÉÏÔÅÞÎÏÇÏ "
+	echo "ÉÎÔÅÒÆÅÊÓÁ Greenstone."
+    else
+	echo "Failed to locate an appropriate version of Javadoc. You must install a"
+	echo "Java Development Kit (version 1.4 or greater) before generating the"
+	echo "documentation for the Greenstone Librarian Interface."
+    fi
+    exit 1
+fi
+
+
+## ---- Document the GLI ----
+echo
+if [ "$glilang" == "es" ]; then
+    echo "Generando documentación para la Interfaz de la Biblioteca Digital"
+    echo "Greenstone..."
+elif [ "$glilang" == "fr" ]; then
+    echo "Production de documentation pour la Greenstone Librarian Interface"
+elif [ "$glilang" == "ru" ]; then
+    echo "çÅÎÅÒÉÒÏ×ÁÎÉÅ ÄÏËÕÍÅÎÔÁÃÉÉ ÄÌÑ ÂÉÂÌÉÏÔÅÞÎÏÇÏ ÉÎÔÅÒÆÅÊÓÁ Greenstone"
+else
+    echo "Generating documentation for the Greenstone Librarian Interface..."
+fi
+
+javadoc -classpath classes/:GLI.jar:lib/apache.jar:lib/qfslib.jar -sourcepath src/ -source 1.4 -author -breakiterator -d docs/ -group "Greenstone Librarian Interface" org.greenstone.gatherer:org.greenstone.gatherer.cdm:org.greenstone.gatherer.collection:org.greenstone.gatherer.feedback:org.greenstone.gatherer.file:org.greenstone.gatherer.gems:org.greenstone.gatherer.gui:org.greenstone.gatherer.gui.metaaudit:org.greenstone.gatherer.gui.tree:org.greenstone.gatherer.metadata:org.greenstone.gatherer.shell:org.greenstone.gatherer.util -private -splitindex -version   org.greenstone.gatherer org.greenstone.gatherer.cdm org.greenstone.gatherer.collection org.greenstone.gatherer.feedback org.greenstone.gatherer.file org.greenstone.gatherer.gems org.greenstone.gatherer.gui org.greenstone.gatherer.gui.metaaudit org.greenstone.gatherer.gui.tree org.greenstone.gatherer.metadata org.greenstone.gatherer.shell org.greenstone.gatherer.util
+
+if [ "$glilang" == "es" ]; then
+    echo "¡Hecho!"
+elif [ "$glilang" == "fr" ]; then
+    echo "Terminé!"
+elif [ "$glilang" == "ru" ]; then
+    echo "÷ÙÐÏÌÎÅÎÏ!"
+else
+    echo "Done!"
+fi
Index: /tags/gsdl-2_61-distribution/gli/gli.bat
===================================================================
--- /tags/gsdl-2_61-distribution/gli/gli.bat	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/gli.bat	(revision 10506)
@@ -0,0 +1,293 @@
+@echo off
+set GLILANG=en
+
+
+::  -------- Run the Greenstone Librarian Interface --------
+
+:: This script must be run from within the directory in which it lives
+if exist gli.bat goto start
+    if "%GLILANG%" == "en" echo This script must be run from the directory in which it resides.
+    if "%GLILANG%" == "es" echo Este gui¢n deber  ejecutarse desde el directorio en el que reside.
+    if "%GLILANG%" == "fr" echo Ce script doit tre excut 
+ partir du rpertoire dans lequel il se trouve.
+    if "%GLILANG%" == "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 "%GLILANG%" == "en" echo Greenstone Librarian Interface (GLI)
+if "%GLILANG%" == "en" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "en" echo GLI comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt
+if "%GLILANG%" == "en" echo This is free software, and you are welcome to redistribute it
+
+if "%GLILANG%" == "es" echo Interfaz de la Biblioteca Digital Greenstone (Greenstone Librarian Interface - GLI)
+if "%GLILANG%" == "es" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "es" echo La Interfaz de la Biblioteca Digital Greenstone NO INCLUYE ABSOLUTAMENTE NINGUNA GARANTÖA.
+if "%GLILANG%" == "es" echo Para mayor informaci¢n vea los trminos de la licencia en LICENSE.txt
+if "%GLILANG%" == "es" echo Este es un software abierto, por lo que lo invitamos a que lo distribuya de forma gratuita
+
+if "%GLILANG%" == "fr" echo Interface du Bibliothcaire Greenstone (Greenstone Librarian Interface - GLI)
+if "%GLILANG%" == "fr" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "fr" echo GLI est fourni sans AUCUNE GARANTIE; pour des dtails, voir LICENSE.txt
+if "%GLILANG%" == "fr" echo Ceci est un logiciel libre, et vous tes invit 
+ le redistribuer
+
+if "%GLILANG%" == "ru" echo š¡«š®â¥ç­ë© š­â¥àä¥©á Greenstone (Greenstone Librarian Interface - GLI)
+if "%GLILANG%" == "ru" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "ru" echo  ­¥ € ¥â   ; €¥â «š á¬. ¢ â¥ªáâ¥ LICENSE.TXT
+if "%GLILANG%" == "ru" echo â® - á¢®¡®€­® à á¯à®áâà ­ï¥¬®¥ ¯à®£à ¬¬­®¥ ®¡¥á¯¥ç¥­š¥ š ë ¬®Š¥â¥ à á¯à®áâà ­ïâì ¥£®
+
+echo.
+::  ---- Determine GSDLHOME ----
+set GSDLPATH=
+
+:: Some users may set the above line manually
+if not "%GSDLPATH%" == "" goto testGSDL
+
+    :: The default location for the GLI is a subdirectory of Greenstone
+    set GSDLPATH=..
+
+    :: If it is set, use the GSDLHOME environment variable
+    if "%GSDLHOME%" == "" goto testGSDL
+	set GSDLPATH=%GSDLHOME%
+
+:testGSDL
+:: Check that the Greenstone installation looks OK
+if "%GLILANG%" == "en" echo Checking GSDL: %GSDLPATH%
+if "%GLILANG%" == "es" echo Revisando GSDL: %GSDLPATH%
+if "%GLILANG%" == "fr" echo Vrification de GSDL: %GSDLPATH%
+if "%GLILANG%" == "ru" echo à®¢¥àª  GSDL: %GSDLPATH%
+if exist "%GSDLPATH%\setup.bat" goto prepGSDL
+    echo.
+    if "%GLILANG%" == "en" echo The Greenstone installation could not be found, or is incomplete.
+    if "%GLILANG%" == "en" echo Try reinstalling Greenstone then running this script again.
+
+    if "%GLILANG%" == "es" echo No se pudo encontrar la instalaci¢n de Greenstone o est  incompleta.
+    if "%GLILANG%" == "es" echo Trate de reinstalar Greenstone y a continuaci¢n ejecute nuevamente este gui¢n.
+
+    if "%GLILANG%" == "fr" echo L'installation de Greenstone est introuvable ou incomplte. Essayez
+    if "%GLILANG%" == "fr" echo de rinstaller Greenstone et excutez ce script 
+ nouveau.
+
+    if "%GLILANG%" == "ru" echo ­áâ ««ïæšï Greenstone ­¥ ¡ë«  ­ ©€¥­  š«š ®­  ­¥¯®«­ . ®¯à®¡ã©â¥ ¯®¢â®à­®
+    if "%GLILANG%" == "ru" echo ãáâ ­®¢šâì Greenstone,   § â¥¬ ¢¢¥áâš íâ®â áªàš¯â á­®¢ .
+    goto exit
+
+:prepGSDL
+:: Setup Greenstone, unless it has already been done
+if not "%GSDLHOME%" == "" goto doneGSDL
+    call "%GSDLPATH%\setup.bat" SetEnv > nul
+
+:doneGSDL
+:: GSDLPATH is no longer needed, since GSDLHOME should now be set
+set GSDLPATH=
+
+
+:findPerl
+::  ---- Check Perl exists ----
+set PERLPATH=
+
+:: Some users may set the above line manually
+if not "%PERLPATH%" == "" goto testPerl
+
+    :: Check if Perl is on the search path
+    echo %PATH%| winutil\which.exe perl.exe | winutil\setvar.exe PERLPATH > setperl.bat
+    call setperl.bat
+    del setperl.bat
+    if not "%PERLPATH%" == "" goto testPerl
+
+    :: If not, try GSDLHOME\bin\windows\perl\bin
+    if exist "%GSDLHOME%\bin\windows\perl\bin\perl.exe" goto gsdlPerl
+
+    :: Still haven't found anything, so try looking in the registry (gulp!)
+    type nul > perl.reg
+    regedit /E perl.reg "HKEY_LOCAL_MACHINE\SOFTWARE\Perl"
+    type perl.reg > perl.txt
+    del perl.reg
+
+    winutil\findperl.exe perl.txt | winutil\setvar.exe PERLPATH > setperl.bat
+    del perl.txt
+    call setperl.bat
+    del setperl.bat
+
+    :: If nothing was found in the registry, we're stuck
+    if "%PERLPATH%" == "" goto noPerl
+
+    goto testPerl
+
+:gsdlPerl
+    set PERLPATH=%GSDLHOME%\bin\windows\perl\bin
+
+:testPerl
+:: Check that a Perl executable has been found
+if "%GLILANG%" == "en" echo Checking Perl: %PERLPATH%
+if "%GLILANG%" == "es" echo Revisando Perl: %PERLPATH%
+if "%GLILANG%" == "fr" echo Vrification de Perl: %PERLPATH%
+if "%GLILANG%" == "ru" echo à®¢¥àª  Perl: %PERLPATH%
+if exist "%PERLPATH%\perl.exe" goto findJava
+
+:noPerl
+    echo.
+    if "%GLILANG%" == "en" echo The Greenstone Librarian Interface requires perl in order to operate,
+    if "%GLILANG%" == "en" echo but perl could not be detected on your system. Please ensure that perl
+    if "%GLILANG%" == "en" echo is installed and is on your search path, then rerun this script.
+
+    if "%GLILANG%" == "es" echo La Interfaz de la Biblioteca Digital Greenstone requiere Perl para poder
+    if "%GLILANG%" == "es" echo operar, pero ste no aparece en su sistema. Por favor aseg£rese de
+    if "%GLILANG%" == "es" echo que Perl est  instalado y se encuentra en su ruta de b£squeda.
+    if "%GLILANG%" == "es" echo A continuaci¢n ejecute nuevamente este gui¢n.
+
+    if "%GLILANG%" == "fr" echo Greenstone Librarian Interface ncessite perl pour son fonctionnement,
+    if "%GLILANG%" == "fr" echo mais perl n'a pas pu tre dtect dans votre systme. Veuillez vous 
+    if "%GLILANG%" == "fr" echo assurer que perl est install et est spcifi dans votre chemin de 
+    if "%GLILANG%" == "fr" echo recherche, puis redmarrez ce script.
+
+    if "%GLILANG%" == "ru" echo š¡«š®â¥ç­ë© š­â¥àä¥©á Greenstone âà¥¡ã¥â Perl, çâ®¡ë š¬¥âì ¢®§¬®Š­®áâì
+    if "%GLILANG%" == "ru" echo à ¡®â âì, ­® Perl ­¥ ¡ë« ¢ ¢ è¥© ášáâ¥¬¥. ®Š «ã©áâ , ¯®€â¢¥à€šâ¥,
+    if "%GLILANG%" == "ru" echo çâ® Perl ãáâ ­®¢«¥­ š ­ å®€šâáï ­  ¢ è¥¬ ¯ãâš ¯®šáª , § â¥¬
+    if "%GLILANG%" == "ru" echo ¯®¢â®à­®¢¢¥€šâ¥ íâ®â áªàš¯â.
+    goto exit
+
+
+: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 "%GLILANG%" == "en" echo Checking Java: %JAVAPATH%
+if "%GLILANG%" == "es" echo Revisando Java: %JAVAPATH%
+if "%GLILANG%" == "fr" echo Vrification de Java: %JAVAPATH%
+if "%GLILANG%" == "ru" echo à®¢¥àª  Java: %JAVAPATH%
+if exist "%JAVAPATH%\java.exe" goto checkGLI
+
+:noJava
+    echo.
+    if "%GLILANG%" == "en" echo Failed to locate an appropriate version of Java. You must install a
+    if "%GLILANG%" == "en" echo Java Runtime Environment (version 1.4 or greater) before running the
+    if "%GLILANG%" == "en" echo Greenstone Librarian Interface.
+
+    if "%GLILANG%" == "es" echo No se pudo localizar una versi¢n apropiada de Java. Usted deber 
+    if "%GLILANG%" == "es" echo instalar un Ambiente de Ejecuci¢n Java (versi¢n 1.4 o superior)
+    if "%GLILANG%" == "es" echo antes de correr la Interfaz de la Biblioteca Digital Greenstone.
+
+    if "%GLILANG%" == "fr" echo Une version adquate de Java n'a pas pu tre localise. Vous devez
+    if "%GLILANG%" == "fr" echo installer un Java Runtime Environment (version 1.4 ou suprieur)
+    if "%GLILANG%" == "fr" echo avant de dmarrer Greenstone Librarian Interface.
+
+    if "%GLILANG%" == "ru" echo ¥ ã€ «®áì ®¯à¥€¥«šâì ¬¥áâ®­ å®Š€¥­š¥ á®®â¢¥âáâ¢ãîé¥© ¢¥àášš Java.
+    if "%GLILANG%" == "ru" echo ë €®«Š­ë ãáâ ­®¢šâì Java Runtime Environment (¢¥àášî 1.4 š«š ¢ëè¥) ¯¥à¥€ ¢¢®€®¬
+    if "%GLILANG%" == "ru" echo ¡š¡«š®â¥ç­®£® š­â¥àä¥©á  Greenstone.
+    goto exit
+
+
+:checkGLI
+:: ---- Check that the GLI has been compiled ----
+if exist "classes/org/greenstone/gatherer/Gatherer.class" goto runGLI
+if exist "GLI.jar" goto runGLI
+    echo.
+    if "%GLILANG%" == "en" echo You need to compile the Greenstone Librarian Interface (using makegli.bat)
+    if "%GLILANG%" == "en" echo before running this script.
+
+    if "%GLILANG%" == "es" echo Usted necesita compilar la Interfaz de la Biblioteca Digital Greenstone
+    if "%GLILANG%" == "es" echo (por medio de makegli.bat) antes de ejecutar este gui¢n.
+
+    if "%GLILANG%" == "fr" echo Vous devez compiler le Greenstone Interface (en utilisant makegil.bat)
+    if "%GLILANG%" == "fr" echo avant d'excuter ce script.
+
+    if "%GLILANG%" == "ru" echo ë €®«Š­ë ª®¬¯š«šà®¢ âì ¡š¡«š®â¥ç­ë© š­â¥àä¥©á Greenstone (šá¯®«ì§ãï makegli.bat)
+    if "%GLILANG%" == "ru" echo ¯¥à¥€ ¢¢®€®¬ íâ®£® áªàš¯â 
+    goto exit
+
+
+:runGLI
+:: ---- Finally, run the GLI ----
+echo.
+
+:: ---- Set wget path manually if don't want to use the version (1.9) 
+:: that comes with Greenstone -------
+set WGETPATH=
+
+if "%GLILANG%" == "en" echo Running the Greenstone Librarian Interface...
+if "%GLILANG%" == "es" echo Ejecutando la Interfaz de la Biblioteca Digital Greenstone...
+if "%GLILANG%" == "fr" echo Excution de Greenstone Librarian Interface
+if "%GLILANG%" == "ru" echo ¥ªãéš© ¡š¡«š®â¥ç­ë© š­â¥àä¥©á Greenstone...
+
+:: -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
+
+if exist "%GSDLHOME%\server.exe" goto localLib 
+    "%JAVAPATH%\java" -cp classes/;GLI.jar;lib/apache.jar;lib/jp.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar org.greenstone.gatherer.GathererProg -gsdl %GSDLHOME% -perl %PERLPATH% -wget %WGETPATH% %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+    if "%GLILANG%" == "en" echo Done!
+    if "%GLILANG%" == "es" echo ­Hecho!
+    if "%GLILANG%" == "fr" echo Termin!
+    if "%GLILANG%" == "ru" echo ë¯®«­¥­®!
+    goto done
+
+:localLib
+    "%JAVAPATH%\java" -cp classes/;GLI.jar;lib/apache.jar;lib/jp.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar org.greenstone.gatherer.GathererProg -gsdl %GSDLHOME% -perl %PERLPATH% -local_library %GSDLHOME%\server.exe -wget %WGETPATH% %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+    if "%GLILANG%" == "en" echo Done!
+    if "%GLILANG%" == "es" echo ­Hecho!
+    if "%GLILANG%" == "fr" echo Termin!
+    if "%GLILANG%" == "ru" echo ë¯®«­¥­®!
+    goto done
+
+:exit
+echo.
+pause
+
+:done
+:: ---- Clean up ----
+set PERLPATH=
+set JAVAPATH=
+set WGETPATH=
Index: /tags/gsdl-2_61-distribution/gli/gli.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gli/gli.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/gli.sh	(revision 10506)
@@ -0,0 +1,293 @@
+#!/bin/sh
+glilang=en
+
+echo
+if [ "$glilang" == "es" ]; then
+    echo "Interfaz de la Biblioteca Digital Greenstone (Greenstone Librarian Interface - GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "La Interfaz de la Biblioteca Digital Greenstone NO INCLUYE ABSOLUTAMENTE NINGUNA GARANTÍA."
+    echo "Para mayor información vea los términos de la licencia en LICENSE.txt"
+    echo "Este es un software abierto, por lo que lo invitamos a que lo distribuya de forma gratuita"
+elif [ "$glilang" == "fr" ]; then
+    echo "Interface du Bibliothécaire Greenstone (Greenstone Librarian Interface - GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "GLI est fourni sans AUCUNE GARANTIE; pour des détails, voir LICENSE.txt"
+    echo "Ceci est un logiciel libre, et vous êtes invité à le redistribuer"
+elif [ "$glilang" == "ru" ]; then
+    echo "âÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone (Greenstone Librarian Interface - GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "âéç ÎÅ ÄÁÅÔ áâóïìàôîï îéëáëéè çáòáîôéê; ÄÅÔÁÌÉ ÓÍ. × ÔÅËÓÔÅ LICENSE.TXT"
+    echo "üÔÏ - Ó×ÏÂÏÄÎÏ ÒÁÓÐÒÏÓÔÒÁÎÑÅÍÏÅ ÐÒÏÇÒÁÍÍÎÏÅ ÏÂÅÓÐÅÞÅÎÉÅ É ÷Ù ÍÏÖÅÔÅ ÒÁÓÐÒÏÓÔÒÁÎÑÔØ ÅÇÏ"
+else
+    echo "Greenstone Librarian Interface (GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "GLI comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt"
+    echo "This is free software, and you are welcome to redistribute it"
+fi
+echo
+
+##  -------- Run the Greenstone Librarian Interface --------
+
+# This script must be run from within the directory in which it lives
+thisdir=`pwd`
+if [ ! -f "${thisdir}/gli.sh" ]; then
+    if [ "$glilang" == "es" ]; then
+        echo "Este guión deberá ejecutarse desde el directorio en el que reside."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Ce script doit être exécuté à partir du répertoire dans lequel il se trouve."
+    elif [ "$glilang" == "ru" ]; then
+	echo "üÔÏÔ ÓËÒÉÐÔ ÄÏÌÖÅÎ ÂÙÔØ ×ÚÑÔ ÉÚ ÄÉÒÅËÔÏÒÉÉ, × ËÏÔÏÒÏÊ ÏÎ ÒÁÓÐÏÌÏÖÅÎ"
+    else
+	echo "This script must be run from the directory in which it resides."
+    fi
+    exit 1
+fi
+
+
+##  ---- Determine GSDLHOME ----
+gsdlpath=
+
+# Some users may set the above line manually
+if [ "$gsdlpath" == "" ]; then
+    # Check the environment variable first
+    if [ "$GSDLHOME" != "" ]; then
+	gsdlpath=$GSDLHOME
+
+    # If it is not set, assume that the GLI is installed as a subdirectory of Greenstone
+    else
+	pushd .. > /dev/null
+	gsdlpath=`pwd`
+	popd > /dev/null
+    fi
+fi
+
+# Check that the Greenstone installation looks OK
+if [ "$glilang" == "es" ]; then
+    echo "Revisando GSDL: $gsdlpath"
+elif [ "$glilang" == "fr" ]; then
+    echo "Vérification de GSDL: $gsdlpath"
+elif [ "$glilang" == "ru" ]; then
+    echo "ðÒÏ×ÅÒËÁ GSDL: $gsdlpath"
+else
+    echo "Checking GSDL: $gsdlpath"
+fi
+if [ ! -f "${gsdlpath}/setup.bash" ] ; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "No se pudo encontrar la instalación de Greenstone o está incompleta."
+        echo "Trate de reinstalar Greenstone y a continuación ejecute nuevamente"
+	echo "este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "L'installation de Greenstone est introuvable ou incomplète."
+	echo "Essayez de réinstaller Greenstone et exécutez ce script à nouveau."
+    elif [ "$glilang" == "ru" ]; then
+	echo "éÎÓÔÁÌÌÑÃÉÑ Greenstone ÎÅ ÂÙÌÁ ÎÁÊÄÅÎÁ ÉÌÉ ÏÎÁ ÎÅÐÏÌÎÁ."
+	echo "ðÏÐÒÏÂÕÊÔÅ ÐÏ×ÔÏÒÎÏ ÕÓÔÁÎÏ×ÉÔØ Greenstone, Á ÚÁÔÅÍ ××ÅÓÔÉ ÜÔÏÔ ÓËÒÉÐÔ ÓÎÏ×Á."
+    else
+	echo "The Greenstone installation could not be found, or is incomplete."
+	echo "Try reinstalling Greenstone then running this script again."
+    fi
+    exit 1
+fi
+
+# Setup Greenstone, unless it has already been done
+if [ "$GSDLHOME" == "" ]; then
+    pushd $gsdlpath > /dev/null
+    source setup.bash
+    popd > /dev/null
+fi
+
+
+##  ---- Check Perl exists ----
+perlpath=
+
+# Some users may set the above line manually
+if [ "$perlpath" == "" ]; then
+    # Check if Perl is on the search path
+    perlpath=`which perl 2> /dev/null`
+fi
+
+# Check that a Perl executable has been found
+if [ "$glilang" == "es" ]; then
+    echo "Revisando Perl: $perlpath"
+elif [ "$glilang" == "fr" ]; then
+    echo "Vérification de Perl: $perlpath"
+elif [ "$glilang" == "ru" ]; then
+    echo "ðÒÏ×ÅÒËÁ Perl: $perlpath"
+else
+    echo "Checking Perl: $perlpath"
+fi
+if [ ! -x "$perlpath" ] ; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "La Interfaz de la Biblioteca Digital Greenstone requiere Perl para "
+	echo "poder operar, pero éste no aparece en su sistema. Por favor asegúrese "
+	echo "de que Perl está instalado y se encuentra en su ruta de búsqueda. A "
+	echo "continuación ejecute nuevamente este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Greenstone Librarian Interface nécessite perl pour son fonctionnement,"
+	echo "mais perl n'a pas pu être détecté dans votre système. Veuillez vous "
+	echo "assurer que perl est installé et est spécifié dans votre chemin de "
+	echo "recherche, puis redémarrez ce script."
+    elif [ "$glilang" == "ru" ]; then
+	echo "âÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone ÔÒÅÂÕÅÔ Perl, ÞÔÏÂÙ ÉÍÅÔØ ×ÏÚÍÏÖÎÏÓÔØ"
+	echo "ÒÁÂÏÔÁÔØ, ÎÏ Perl ÎÅ ÂÙÌ × ×ÁÛÅÊ ÓÉÓÔÅÍÅ. ðÏÖÁÌÕÊÓÔÁ, ÐÏÄÔ×ÅÒÄÉÔÅ, ÞÔÏ "
+	echo "Perl ÕÓÔÁÎÏ×ÌÅÎ É ÎÁÈÏÄÉÔÓÑ ÎÁ ×ÁÛÅÍ ÐÕÔÉ ÐÏÉÓËÁ, ÚÁÔÅÍ ÐÏ×ÔÏÒÎÏ××ÅÄÉÔÅ"
+	echo "ÜÔÏÔ ÓËÒÉÐÔ."
+    else
+	echo "The Greenstone Librarian Interface requires perl in order to operate,"
+	echo "but perl could not be detected on your system. Please ensure that perl"
+	echo "is installed and is on your search path, then rerun this script."
+    fi
+    exit 1
+fi
+
+
+## ---- Check Java exists ----
+javapath=
+
+# Some users may set the above line manually
+if [ "$javapath" == "" ]; then
+
+    # If it is set, use the JAVA_HOME environment variable
+    if [ "$JAVA_HOME" != "" ]; 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érification de Java: $javapath"
+elif [ "$glilang" == "ru" ]; then
+    echo "ðÒÏ×ÅÒËÁ Java: $javapath"
+else
+    echo "Checking Java: $javapath"
+fi
+if [ ! -x "$javapath" ]; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "No se pudo localizar una versión apropiada de Java. Usted deberá "
+	echo "instalar un Ambiente de Ejecución Java (versión 1.4 o superior) "
+	echo "antes de correr la Interfaz de la Biblioteca Digital Greenstone."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Une version adéquate de Java n'a pas pu être localisée."
+	echo "Vous devez installer un Java Runtime Environment (version 1.4 ou"
+	echo "supérieur) avant de démarrer Greenstone Librarian Interface."
+    elif [ "$glilang" == "ru" ]; then
+	echo "îÅ ÕÄÁÌÏÓØ ÏÐÒÅÄÅÌÉÔØ ÍÅÓÔÏÎÁÈÏÖÄÅÎÉÅ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÅÊ ×ÅÒÓÉÉ Java."
+	echo "÷Ù ÄÏÌÖÎÙ ÕÓÔÁÎÏ×ÉÔØ Java Runtime Environment (×ÅÒÓÉÀ 1.4 ÉÌÉ ×ÙÛÅ)"
+	echo "ÐÅÒÅÄ ××ÏÄÏÍ ÂÉÂÌÉÏÔÅÞÎÏÇÏ ÉÎÔÅÒÆÅÊÓÁ Greenstone."
+    else
+	echo "Failed to locate an appropriate version of Java. You must install a"
+	echo "Java Runtime Environment (version 1.4 or greater) before running the"
+	echo "Greenstone Librarian Interface."
+    fi
+    exit 1
+fi
+
+
+## -- Check the version of Java is new enough (1.4.0 or higher) to run the GLI --
+`$javapath -classpath . CheckJavaVersion > /dev/null`
+if [ $? -ne 2 ] ; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "La versión del Ambiente de Ejecución Java (JRE por sus siglas en "
+	echo "inglés) que usted tiene instalada es demasiado vieja para ejecutar "
+	echo "la Interfaz de la Biblioteca Digital Greenstone. Por favor instale "
+	echo "una nueva versión del Ambiente de Ejecución Java (versión 1.4 o "
+	echo "posterior) y ejecute nuevamente este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "La version de Java Runtime Environment que vous avez installée est"
+	echo "trop vielle pour faire fonctionner Greenstone Librarian Interface."
+	echo "Veuillez installer une nouvelle version du JRE (version 1.4 ou plus"
+	echo "récente) et redémarrez le script."
+    elif [ "$glilang" == "ru" ]; then
+	echo "÷ÅÒÓÉÑ Java Runtime Environment, ËÏÔÏÒÕÀ ÷Ù ÕÓÔÁÎÏ×ÉÌÉ, ÏÞÅÎØ ÓÔÁÒÁ,"
+	echo "ÞÔÏÂÙ ÕÐÒÁ×ÌÑÔØ ÂÉÂÌÉÏÔÅÞÎÙÍ ÉÎÔÅÒÆÅÊÓÏÍ Greenstone. ðÏÖÁÌÕÊÓÔÁ, "
+	echo "ÕÓÔÁÎÏ×ÉÔÅ ÎÏ×ÕÀ ×ÅÒÓÉÀ JRE (×ÅÒÓÉÀ 1.4 ÉÌÉ ÂÏÌÅÅ ÎÏ×ÕÀ) É"
+	echo "ÐÅÒÅÕÓÔÁÎÏ×ÉÔÅ ÜÔÏÔ ÓËÒÉÐÔ"
+    else
+	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."
+    fi
+    exit 1
+fi
+
+## ---- Set wgetpath manually if you don't want to use the default Greenstone version -----
+wgetpath=
+
+## ---- Check that the GLI has been compiled ----
+if [ ! -f "classes/org/greenstone/gatherer/GathererProg.class" ] && [ ! -f "GLI.jar" ]; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "Usted necesita compilar la Interfaz de la Biblioteca Digital Greenstone"
+	echo "(por medio de makegli.sh) antes de ejecutar este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Vous devez compiler le Greenstone Interface (en utilisant makegli.sh)"
+	echo "avant d'exécuter ce script."
+    elif [ "$glilang" == "ru" ]; then
+	echo "÷Ù ÄÏÌÖÎÙ ËÏÍÐÉÌÉÒÏ×ÁÔØ ÂÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone"
+	echo "(ÉÓÐÏÌØÚÕÑ makegli.sh) ÐÅÒÅÄ ××ÏÄÏÍ ÜÔÏÇÏ ÓËÒÉÐÔÁ"
+    else
+	echo "You need to compile the Greenstone Librarian Interface (using makegli.sh)"
+	echo "before running this script."
+    fi
+    exit 1
+fi
+
+if [ "$1" == "-test" ]; then
+    if [ "$glilang" == "es" ]; then
+	echo "Clase de prueba: $2"
+	echo "Argumentos $*"
+    elif [ "$glilang" == "fr" ]; then
+	echo "Classe de test: $2"
+	echo "Arguments $*"
+    elif [ "$glilang" == "ru" ]; then
+	echo "éÓÐÙÔÁÔÅÌØÎÙÊ ËÌÁÓÓ: $2"
+	echo "ðÁÒÁÍÅÔÒÙ $*"
+    else
+	echo "Testing class: $2"
+	echo "Arguments $*"
+    fi
+    $javapath -classpath classes/:GLI.jar:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar $2 $3
+    exit 0
+fi
+
+## ---- Finally, run the GLI ----
+echo
+if [ "$glilang" == "es" ]; then
+    echo "Ejecutando la Interfaz de la Biblioteca Digital Greenstone..."
+elif [ "$glilang" == "fr" ]; then
+    echo "Exécution de Greenstone Librarian Interface"
+elif [ "$glilang" == "ru" ]; then
+    echo "ôÅËÕÝÉÊ ÂÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone..."
+else
+    echo "Running the Greenstone Librarian Interface..."
+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 $*
+
+if [ "$glilang" == "es" ]; then
+    echo "¡Hecho!"
+elif [ "$glilang" == "fr" ]; then
+    echo "Terminé!"
+elif [ "$glilang" == "ru" ]; then
+    echo "÷ÙÐÏÌÎÅÎÏ!"
+else
+    echo "Done!"
+fi
Index: /tags/gsdl-2_61-distribution/gli/gli4gs3.bat
===================================================================
--- /tags/gsdl-2_61-distribution/gli/gli4gs3.bat	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/gli4gs3.bat	(revision 10506)
@@ -0,0 +1,333 @@
+@echo off
+set GLILANG=en
+
+
+::  -------- Run the Greenstone Librarian Interface --------
+
+:: This script must be run from within the directory in which it lives
+if exist gli4gs3.bat goto start
+    if "%GLILANG%" == "en" echo This script must be run from the directory in which it resides.
+    if "%GLILANG%" == "es" echo Este gui¢n deber  ejecutarse desde el directorio en el que reside.
+    if "%GLILANG%" == "fr" echo Ce script doit tre excut 
+ partir du rpertoire dans lequel il se trouve.
+    if "%GLILANG%" == "ru" echo â®â áªàš¯â €®«Š¥­ ¡ëâì ¢§ïâ š§ €šà¥ªâ®àšš, ¢ ª®â®à®© ®­ à á¯®«®Š¥­
+    goto exit
+
+:start
+if "%OS%" == "Windows_NT" goto findGSDL3
+    :: Invoke a new command processor to ensure there's enough environment space
+    if "%1" == "Second" goto findGSDL3
+        command /E:2048 /C %0 Second %1 %2 %3 %4 %5 %6 %7 %8 %9
+        goto done
+
+:findGSDL3
+echo.
+if "%GLILANG%" == "en" echo Greenstone Librarian Interface (GLI)
+if "%GLILANG%" == "en" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "en" echo GLI comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt
+if "%GLILANG%" == "en" echo This is free software, and you are welcome to redistribute it
+
+if "%GLILANG%" == "es" echo Interfaz de la Biblioteca Digital Greenstone (Greenstone Librarian Interface - GLI)
+if "%GLILANG%" == "es" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "es" echo La Interfaz de la Biblioteca Digital Greenstone NO INCLUYE ABSOLUTAMENTE NINGUNA GARANTÖA.
+if "%GLILANG%" == "es" echo Para mayor informaci¢n vea los trminos de la licencia en LICENSE.txt
+if "%GLILANG%" == "es" echo Este es un software abierto, por lo que lo invitamos a que lo distribuya de forma gratuita
+
+if "%GLILANG%" == "fr" echo Interface du Bibliothcaire Greenstone (Greenstone Librarian Interface - GLI)
+if "%GLILANG%" == "fr" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "fr" echo GLI est fourni sans AUCUNE GARANTIE; pour des dtails, voir LICENSE.txt
+if "%GLILANG%" == "fr" echo Ceci est un logiciel libre, et vous tes invit 
+ le redistribuer
+
+if "%GLILANG%" == "ru" echo š¡«š®â¥ç­ë© š­â¥àä¥©á Greenstone (Greenstone Librarian Interface - GLI)
+if "%GLILANG%" == "ru" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "ru" echo  ­¥ € ¥â   ; €¥â «š á¬. ¢ â¥ªáâ¥ LICENSE.TXT
+if "%GLILANG%" == "ru" echo â® - á¢®¡®€­® à á¯à®áâà ­ï¥¬®¥ ¯à®£à ¬¬­®¥ ®¡¥á¯¥ç¥­š¥ š ë ¬®Š¥â¥ à á¯à®áâà ­ïâì ¥£®
+
+echo.
+::  ---- Determine GSDL3HOME ----
+set GSDL3PATH=%GSDL3PATH%
+
+:: Some users may set the above line manually, or it may be set as an argument
+if not "%GSDL3PATH%" == "" goto testGSDL3
+
+    :: The default location for the GLI is a subdirectory of Greenstone 3
+    set GSDL3PATH=..
+
+    :: If it is set, use the GSDL3HOME environment variable
+    if "%GSDL3SRCHOME%" == "" goto testGSDL3
+	set GSDL3PATH=%GSDL3SRCHOME%
+
+:testGSDL3
+:: Check that the Greenstone 3 installation looks OK
+if "%GLILANG%" == "en" echo Checking GSDL3: %GSDL3PATH%
+if "%GLILANG%" == "es" echo Revisando GSDL3: %GSDL3PATH%
+if "%GLILANG%" == "fr" echo Vrification de GSDL3: %GSDL3PATH%
+if "%GLILANG%" == "ru" echo à®¢¥àª  GSDL3: %GSDL3PATH%
+if exist "%GSDL3PATH%\gs3-setup.bat" goto prepGSDL3
+    echo.
+    if "%GLILANG%" == "en" echo The Greenstone 3 installation could not be found, or is incomplete.
+    if "%GLILANG%" == "en" echo Try reinstalling Greenstone 3 then running this script again.
+
+    if "%GLILANG%" == "es" echo No se pudo encontrar la instalaci¢n de Greenstone 3 o est  incompleta.
+    if "%GLILANG%" == "es" echo Trate de reinstalar Greenstone 3 y a continuaci¢n ejecute nuevamente este gui¢n.
+
+    if "%GLILANG%" == "fr" echo L'installation de Greenstone 3 est introuvable ou incomplte. Essayez
+    if "%GLILANG%" == "fr" echo de rinstaller Greenstone 3 et excutez ce script 
+ nouveau.
+
+    if "%GLILANG%" == "ru" echo ­áâ ««ïæšï Greenstone 3 ­¥ ¡ë«  ­ ©€¥­  š«š ®­  ­¥¯®«­ . ®¯à®¡ã©â¥ ¯®¢â®à­®
+    if "%GLILANG%" == "ru" echo ãáâ ­®¢šâì Greenstone, 3   § â¥¬ ¢¢¥áâš íâ®â áªàš¯â á­®¢ .
+    goto exit
+
+:prepGSDL3
+:: Setup Greenstone 3, unless it has already been done
+if not "%GSDL3SRCHOME%" == "" goto doneGSDL3
+    cd | winutil\setvar.exe GLIDIR > setgli.bat
+    call setgli.bat
+    del setgli.bat
+    cd "%GSDL3PATH%"
+    call gs3-setup.bat SetEnv > nul
+    cd %GLIDIR%
+
+:doneGSDL3
+:: GSDL3PATH is no longer needed, since GSDL3HOME should now be set
+set GSDL3PATH=
+
+
+::  ---- Determine GSDLHOME ----
+set GSDLPATH=%GSDLPATH%
+
+:: Some users may set the above line manually, or it may be set in the environment
+if not "%GSDLPATH%" == "" goto testGSDL
+
+    :: The default location for Greenstone is a gs2build subdirectory of Greenstone 3
+    set GSDLPATH=%GSDL3SRCHOME%\gs2build
+
+    :: If it is set, use the GSDLHOME environment variable
+    if "%GSDLHOME%" == "" goto testGSDL
+	set GSDLPATH=%GSDLHOME%
+
+:testGSDL
+:: Check that the Greenstone installation looks OK
+if "%GLILANG%" == "en" echo Checking GSDL: %GSDLPATH%
+if "%GLILANG%" == "es" echo Revisando GSDL: %GSDLPATH%
+if "%GLILANG%" == "fr" echo Vrification de GSDL: %GSDLPATH%
+if "%GLILANG%" == "ru" echo à®¢¥àª  GSDL: %GSDLPATH%
+if exist "%GSDLPATH%\setup.bat" goto prepGSDL
+    echo.
+    if "%GLILANG%" == "en" echo The Greenstone installation could not be found, or is incomplete.
+    if "%GLILANG%" == "en" echo Try reinstalling Greenstone then running this script again.
+
+    if "%GLILANG%" == "es" echo No se pudo encontrar la instalaci¢n de Greenstone o est  incompleta.
+    if "%GLILANG%" == "es" echo Trate de reinstalar Greenstone y a continuaci¢n ejecute nuevamente este gui¢n.
+
+    if "%GLILANG%" == "fr" echo L'installation de Greenstone est introuvable ou incomplte. Essayez
+    if "%GLILANG%" == "fr" echo de rinstaller Greenstone et excutez ce script 
+ nouveau.
+
+    if "%GLILANG%" == "ru" echo ­áâ ««ïæšï Greenstone ­¥ ¡ë«  ­ ©€¥­  š«š ®­  ­¥¯®«­ . ®¯à®¡ã©â¥ ¯®¢â®à­®
+    if "%GLILANG%" == "ru" echo ãáâ ­®¢šâì Greenstone,   § â¥¬ ¢¢¥áâš íâ®â áªàš¯â á­®¢ .
+    goto exit
+
+:prepGSDL
+:: Setup Greenstone, unless it has already been done
+if not "%GSDLHOME%" == "" goto doneGSDL
+    call "%GSDLPATH%\setup.bat" SetEnv > nul
+
+:doneGSDL
+:: GSDLPATH is no longer needed, since GSDLHOME should now be set
+set GSDLPATH=
+
+
+:findPerl
+::  ---- Check Perl exists ----
+set PERLPATH=
+
+:: Some users may set the above line manually
+if not "%PERLPATH%" == "" goto testPerl
+
+    :: Check if Perl is on the search path
+    echo %PATH%| winutil\which.exe perl.exe | winutil\setvar.exe PERLPATH > setperl.bat
+    call setperl.bat
+    del setperl.bat
+    if not "%PERLPATH%" == "" goto testPerl
+
+    :: If not, try GSDLHOME\bin\windows\perl\bin
+    if exist "%GSDLHOME%\bin\windows\perl\bin\perl.exe" goto gsdlPerl
+
+    :: Still haven't found anything, so try looking in the registry (gulp!)
+    type nul > perl.reg
+    regedit /E perl.reg "HKEY_LOCAL_MACHINE\SOFTWARE\Perl"
+    type perl.reg > perl.txt
+    del perl.reg
+
+    winutil\findperl.exe perl.txt | winutil\setvar.exe PERLPATH > setperl.bat
+    del perl.txt
+    call setperl.bat
+    del setperl.bat
+
+    :: If nothing was found in the registry, we're stuck
+    if "%PERLPATH%" == "" goto noPerl
+
+    goto testPerl
+
+:gsdlPerl
+    set PERLPATH=%GSDLHOME%\bin\windows\perl\bin
+
+:testPerl
+:: Check that a Perl executable has been found
+if "%GLILANG%" == "en" echo Checking Perl: %PERLPATH%
+if "%GLILANG%" == "es" echo Revisando Perl: %PERLPATH%
+if "%GLILANG%" == "fr" echo Vrification de Perl: %PERLPATH%
+if "%GLILANG%" == "ru" echo à®¢¥àª  Perl: %PERLPATH%
+if exist "%PERLPATH%\perl.exe" goto findJava
+
+:noPerl
+    echo.
+    if "%GLILANG%" == "en" echo The Greenstone Librarian Interface requires perl in order to operate,
+    if "%GLILANG%" == "en" echo but perl could not be detected on your system. Please ensure that perl
+    if "%GLILANG%" == "en" echo is installed and is on your search path, then rerun this script.
+
+    if "%GLILANG%" == "es" echo La Interfaz de la Biblioteca Digital Greenstone requiere Perl para poder
+    if "%GLILANG%" == "es" echo operar, pero ste no aparece en su sistema. Por favor aseg£rese de
+    if "%GLILANG%" == "es" echo que Perl est  instalado y se encuentra en su ruta de b£squeda.
+    if "%GLILANG%" == "es" echo A continuaci¢n ejecute nuevamente este gui¢n.
+
+    if "%GLILANG%" == "fr" echo Greenstone Librarian Interface ncessite perl pour son fonctionnement,
+    if "%GLILANG%" == "fr" echo mais perl n'a pas pu tre dtect dans votre systme. Veuillez vous 
+    if "%GLILANG%" == "fr" echo assurer que perl est install et est spcifi dans votre chemin de 
+    if "%GLILANG%" == "fr" echo recherche, puis redmarrez ce script.
+
+    if "%GLILANG%" == "ru" echo š¡«š®â¥ç­ë© š­â¥àä¥©á Greenstone âà¥¡ã¥â Perl, çâ®¡ë š¬¥âì ¢®§¬®Š­®áâì
+    if "%GLILANG%" == "ru" echo à ¡®â âì, ­® Perl ­¥ ¡ë« ¢ ¢ è¥© ášáâ¥¬¥. ®Š «ã©áâ , ¯®€â¢¥à€šâ¥,
+    if "%GLILANG%" == "ru" echo çâ® Perl ãáâ ­®¢«¥­ š ­ å®€šâáï ­  ¢ è¥¬ ¯ãâš ¯®šáª , § â¥¬
+    if "%GLILANG%" == "ru" echo ¯®¢â®à­®¢¢¥€šâ¥ íâ®â áªàš¯â.
+    goto exit
+
+
+: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 "%GLILANG%" == "en" echo Checking Java: %JAVAPATH%
+if "%GLILANG%" == "es" echo Revisando Java: %JAVAPATH%
+if "%GLILANG%" == "fr" echo Vrification de Java: %JAVAPATH%
+if "%GLILANG%" == "ru" echo à®¢¥àª  Java: %JAVAPATH%
+if exist "%JAVAPATH%\java.exe" goto checkGLI
+
+:noJava
+    echo.
+    if "%GLILANG%" == "en" echo Failed to locate an appropriate version of Java. You must install a
+    if "%GLILANG%" == "en" echo Java Runtime Environment (version 1.4 or greater) before running the
+    if "%GLILANG%" == "en" echo Greenstone Librarian Interface.
+
+    if "%GLILANG%" == "es" echo No se pudo localizar una versi¢n apropiada de Java. Usted deber 
+    if "%GLILANG%" == "es" echo instalar un Ambiente de Ejecuci¢n Java (versi¢n 1.4 o superior)
+    if "%GLILANG%" == "es" echo antes de correr la Interfaz de la Biblioteca Digital Greenstone.
+
+    if "%GLILANG%" == "fr" echo Une version adquate de Java n'a pas pu tre localise. Vous devez
+    if "%GLILANG%" == "fr" echo installer un Java Runtime Environment (version 1.4 ou suprieur)
+    if "%GLILANG%" == "fr" echo avant de dmarrer Greenstone Librarian Interface.
+
+    if "%GLILANG%" == "ru" echo ¥ ã€ «®áì ®¯à¥€¥«šâì ¬¥áâ®­ å®Š€¥­š¥ á®®â¢¥âáâ¢ãîé¥© ¢¥àášš Java.
+    if "%GLILANG%" == "ru" echo ë €®«Š­ë ãáâ ­®¢šâì Java Runtime Environment (¢¥àášî 1.4 š«š ¢ëè¥) ¯¥à¥€ ¢¢®€®¬
+    if "%GLILANG%" == "ru" echo ¡š¡«š®â¥ç­®£® š­â¥àä¥©á  Greenstone.
+    goto exit
+
+
+:checkGLI
+:: ---- Check that the GLI has been compiled ----
+if exist "classes/org/greenstone/gatherer/GathererProg.class" goto runGLI
+if exist "GLI.jar" goto runGLI
+    echo.
+    if "%GLILANG%" == "en" echo You need to compile the Greenstone Librarian Interface (using makegli.bat)
+    if "%GLILANG%" == "en" echo before running this script.
+
+    if "%GLILANG%" == "es" echo Usted necesita compilar la Interfaz de la Biblioteca Digital Greenstone
+    if "%GLILANG%" == "es" echo (por medio de makegli.bat) antes de ejecutar este gui¢n.
+
+    if "%GLILANG%" == "fr" echo Vous devez compiler le Greenstone Interface (en utilisant makegil.bat)
+    if "%GLILANG%" == "fr" echo avant d'excuter ce script.
+
+    if "%GLILANG%" == "ru" echo ë €®«Š­ë ª®¬¯š«šà®¢ âì ¡š¡«š®â¥ç­ë© š­â¥àä¥©á Greenstone (šá¯®«ì§ãï makegli.bat)
+    if "%GLILANG%" == "ru" echo ¯¥à¥€ ¢¢®€®¬ íâ®£® áªàš¯â 
+    goto exit
+
+
+:runGLI
+:: ---- Finally, run the GLI ----
+echo.
+
+:: ---- Set wget path manually if don't want to use the version (1.9) 
+:: that comes with Greenstone -------
+set WGETPATH=
+
+if "%GLILANG%" == "en" echo Running the Greenstone Librarian Interface...
+if "%GLILANG%" == "es" echo Ejecutando la Interfaz de la Biblioteca Digital Greenstone...
+if "%GLILANG%" == "fr" echo Excution de Greenstone Librarian Interface
+if "%GLILANG%" == "ru" echo ¥ªãéš© ¡š¡«š®â¥ç­ë© š­â¥àä¥©á Greenstone...
+
+:: -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 classes/;GLI.jar;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar org.greenstone.gatherer.GathererProg -gsdl %GSDLHOME% -gsdl3 %GSDL3HOME% -gsdl3src %GSDL3SRCHOME% -perl %PERLPATH% -wget %WGETPATH% %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+if "%GLILANG%" == "en" echo Done!
+if "%GLILANG%" == "es" echo ­Hecho!
+if "%GLILANG%" == "fr" echo Termin!
+if "%GLILANG%" == "ru" echo ë¯®«­¥­®!
+goto done
+
+:exit
+echo.
+pause
+
+:done
+:: ---- Clean up ----
+set PERLPATH=
+set JAVAPATH=
+set WGETPATH=
Index: /tags/gsdl-2_61-distribution/gli/gli4gs3.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gli/gli4gs3.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/gli4gs3.sh	(revision 10506)
@@ -0,0 +1,347 @@
+#!/bin/sh
+glilang=en
+
+echo
+if [ "$glilang" == "es" ]; then
+    echo "Interfaz de la Biblioteca Digital Greenstone (Greenstone Librarian Interface - GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "La Interfaz de la Biblioteca Digital Greenstone NO INCLUYE ABSOLUTAMENTE NINGUNA GARANTÍA."
+    echo "Para mayor información vea los términos de la licencia en LICENSE.txt"
+    echo "Este es un software abierto, por lo que lo invitamos a que lo distribuya de forma gratuita"
+elif [ "$glilang" == "fr" ]; then
+    echo "Interface du Bibliothécaire Greenstone (Greenstone Librarian Interface - GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "GLI est fourni sans AUCUNE GARANTIE; pour des détails, voir LICENSE.txt"
+    echo "Ceci est un logiciel libre, et vous êtes invité à le redistribuer"
+elif [ "$glilang" == "ru" ]; then
+    echo "âÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone (Greenstone Librarian Interface - GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "âéç ÎÅ ÄÁÅÔ áâóïìàôîï îéëáëéè çáòáîôéê; ÄÅÔÁÌÉ ÓÍ. × ÔÅËÓÔÅ LICENSE.TXT"
+    echo "üÔÏ - Ó×ÏÂÏÄÎÏ ÒÁÓÐÒÏÓÔÒÁÎÑÅÍÏÅ ÐÒÏÇÒÁÍÍÎÏÅ ÏÂÅÓÐÅÞÅÎÉÅ É ÷Ù ÍÏÖÅÔÅ ÒÁÓÐÒÏÓÔÒÁÎÑÔØ ÅÇÏ"
+else
+    echo "Greenstone Librarian Interface (GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "GLI comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt"
+    echo "This is free software, and you are welcome to redistribute it"
+fi
+echo
+
+##  -------- Run the Greenstone Librarian Interface --------
+
+# This script must be run from within the directory in which it lives
+thisdir=`pwd`
+if [ ! -f "${thisdir}/gli4gs3.sh" ]; then
+    if [ "$glilang" == "es" ]; then
+        echo "Este guión deberá ejecutarse desde el directorio en el que reside."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Ce script doit être exécuté à partir du répertoire dans lequel il se trouve."
+    elif [ "$glilang" == "ru" ]; then
+	echo "üÔÏÔ ÓËÒÉÐÔ ÄÏÌÖÅÎ ÂÙÔØ ×ÚÑÔ ÉÚ ÄÉÒÅËÔÏÒÉÉ, × ËÏÔÏÒÏÊ ÏÎ ÒÁÓÐÏÌÏÖÅÎ"
+    else
+	echo "This script must be run from the directory in which it resides."
+    fi
+    exit 1
+fi
+
+
+##  ---- Determine GSDL3HOME ----
+## may be already set or manually entered here
+gsdl3path=$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 GLI is installed as a subdirectory of Greenstone 3
+    else
+	pushd .. > /dev/null
+	gsdl3path=`pwd`
+	popd > /dev/null
+    fi
+fi
+
+# Check that the Greenstone 3 installation looks OK
+if [ "$glilang" == "es" ]; then
+    echo "Revisando GSDL3: $gsdl3path"
+elif [ "$glilang" == "fr" ]; then
+    echo "Vérification de GSDL3: $gsdl3path"
+elif [ "$glilang" == "ru" ]; then
+    echo "ðÒÏ×ÅÒËÁ GSDL3: $gsdl3path"
+else
+    echo "Checking GSDL3: $gsdl3path"
+fi
+if [ ! -f "${gsdl3path}/gs3-setup.sh" ] ; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "No se pudo encontrar la instalación de Greenstone 3 o está incompleta."
+        echo "Trate de reinstalar Greenstone 3 y a continuación ejecute nuevamente"
+	echo "este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "L'installation de Greenstone 3 est introuvable ou incomplète."
+	echo "Essayez de réinstaller Greenstone 3 et exécutez ce script à nouveau."
+    elif [ "$glilang" == "ru" ]; then
+	echo "éÎÓÔÁÌÌÑÃÉÑ Greenstone 3 ÎÅ ÂÙÌÁ ÎÁÊÄÅÎÁ ÉÌÉ ÏÎÁ ÎÅÐÏÌÎÁ."
+	echo "ðÏÐÒÏÂÕÊÔÅ ÐÏ×ÔÏÒÎÏ ÕÓÔÁÎÏ×ÉÔØ Greenstone 3, Á ÚÁÔÅÍ ××ÅÓÔÉ ÜÔÏÔ ÓËÒÉÐÔ ÓÎÏ×Á."
+    else
+	echo "The Greenstone 3 installation could not be found, or is incomplete."
+	echo "Try reinstalling Greenstone 3 then running this script again."
+    fi
+    exit 1
+fi
+
+# Setup Greenstone 3, unless it has already been done
+if [ "$GSDL3HOME" == "" ] || [ "$GSDL3SRCHOME" == "" ]; then
+    pushd $gsdl3path > /dev/null
+    source gs3-setup.sh
+    popd > /dev/null
+fi
+
+
+##  ---- Determine GSDLHOME ----
+## may be already set, or manually entered here.
+gsdlpath=$gsdlpath
+
+# Some users may set the above line manually
+if [ "$gsdlpath" == "" ]; then
+    # Check the environment variable first
+    if [ "$GSDLHOME" != "" ]; then
+	gsdlpath=$GSDLHOME
+
+    # If it is not set, assume that the gs2build subdirectory of Greenstone 3 exists
+    else
+	gsdlpath=$GSDL3SRCHOME/gs2build
+    fi
+fi
+
+# Check that the Greenstone installation looks OK
+if [ "$glilang" == "es" ]; then
+    echo "Revisando GSDL: $gsdlpath"
+elif [ "$glilang" == "fr" ]; then
+    echo "Vérification de GSDL: $gsdlpath"
+elif [ "$glilang" == "ru" ]; then
+    echo "ðÒÏ×ÅÒËÁ GSDL: $gsdlpath"
+else
+    echo "Checking GSDL: $gsdlpath"
+fi
+if [ ! -f "${gsdlpath}/setup.bash" ] ; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "No se pudo encontrar la instalación de Greenstone o está incompleta."
+        echo "Trate de reinstalar Greenstone y a continuación ejecute nuevamente"
+	echo "este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "L'installation de Greenstone est introuvable ou incomplète."
+	echo "Essayez de réinstaller Greenstone et exécutez ce script à nouveau."
+    elif [ "$glilang" == "ru" ]; then
+	echo "éÎÓÔÁÌÌÑÃÉÑ Greenstone ÎÅ ÂÙÌÁ ÎÁÊÄÅÎÁ ÉÌÉ ÏÎÁ ÎÅÐÏÌÎÁ."
+	echo "ðÏÐÒÏÂÕÊÔÅ ÐÏ×ÔÏÒÎÏ ÕÓÔÁÎÏ×ÉÔØ Greenstone, Á ÚÁÔÅÍ ××ÅÓÔÉ ÜÔÏÔ ÓËÒÉÐÔ ÓÎÏ×Á."
+    else
+	echo "The Greenstone installation could not be found, or is incomplete."
+	echo "Try reinstalling Greenstone then running this script again."
+    fi
+    exit 1
+fi
+
+# Setup Greenstone, unless it has already been done
+if [ "$GSDLHOME" == "" ]; then
+    pushd $gsdlpath > /dev/null
+    source setup.bash
+    popd > /dev/null
+fi
+
+
+##  ---- Check Perl exists ----
+perlpath=
+
+# Some users may set the above line manually
+if [ "$perlpath" == "" ]; then
+    # Check if Perl is on the search path
+    perlpath=`which perl 2> /dev/null`
+fi
+
+# Check that a Perl executable has been found
+if [ "$glilang" == "es" ]; then
+    echo "Revisando Perl: $perlpath"
+elif [ "$glilang" == "fr" ]; then
+    echo "Vérification de Perl: $perlpath"
+elif [ "$glilang" == "ru" ]; then
+    echo "ðÒÏ×ÅÒËÁ Perl: $perlpath"
+else
+    echo "Checking Perl: $perlpath"
+fi
+if [ ! -x "$perlpath" ] ; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "La Interfaz de la Biblioteca Digital Greenstone requiere Perl para "
+	echo "poder operar, pero éste no aparece en su sistema. Por favor asegúrese "
+	echo "de que Perl está instalado y se encuentra en su ruta de búsqueda. A "
+	echo "continuación ejecute nuevamente este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Greenstone Librarian Interface nécessite perl pour son fonctionnement,"
+	echo "mais perl n'a pas pu être détecté dans votre système. Veuillez vous "
+	echo "assurer que perl est installé et est spécifié dans votre chemin de "
+	echo "recherche, puis redémarrez ce script."
+    elif [ "$glilang" == "ru" ]; then
+	echo "âÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone ÔÒÅÂÕÅÔ Perl, ÞÔÏÂÙ ÉÍÅÔØ ×ÏÚÍÏÖÎÏÓÔØ"
+	echo "ÒÁÂÏÔÁÔØ, ÎÏ Perl ÎÅ ÂÙÌ × ×ÁÛÅÊ ÓÉÓÔÅÍÅ. ðÏÖÁÌÕÊÓÔÁ, ÐÏÄÔ×ÅÒÄÉÔÅ, ÞÔÏ "
+	echo "Perl ÕÓÔÁÎÏ×ÌÅÎ É ÎÁÈÏÄÉÔÓÑ ÎÁ ×ÁÛÅÍ ÐÕÔÉ ÐÏÉÓËÁ, ÚÁÔÅÍ ÐÏ×ÔÏÒÎÏ××ÅÄÉÔÅ"
+	echo "ÜÔÏÔ ÓËÒÉÐÔ."
+    else
+	echo "The Greenstone Librarian Interface requires perl in order to operate,"
+	echo "but perl could not be detected on your system. Please ensure that perl"
+	echo "is installed and is on your search path, then rerun this script."
+    fi
+    exit 1
+fi
+
+
+## ---- Check Java exists ----
+javapath=
+
+# Some users may set the above line manually
+if [ "$javapath" == "" ]; then
+
+    # If it is set, use the JAVA_HOME environment variable
+    if [ "$JAVA_HOME" != "" ]; 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érification de Java: $javapath"
+elif [ "$glilang" == "ru" ]; then
+    echo "ðÒÏ×ÅÒËÁ Java: $javapath"
+else
+    echo "Checking Java: $javapath"
+fi
+if [ ! -x "$javapath" ]; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "No se pudo localizar una versión apropiada de Java. Usted deberá "
+	echo "instalar un Ambiente de Ejecución Java (versión 1.4 o superior) "
+	echo "antes de correr la Interfaz de la Biblioteca Digital Greenstone."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Une version adéquate de Java n'a pas pu être localisée."
+	echo "Vous devez installer un Java Runtime Environment (version 1.4 ou"
+	echo "supérieur) avant de démarrer Greenstone Librarian Interface."
+    elif [ "$glilang" == "ru" ]; then
+	echo "îÅ ÕÄÁÌÏÓØ ÏÐÒÅÄÅÌÉÔØ ÍÅÓÔÏÎÁÈÏÖÄÅÎÉÅ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÅÊ ×ÅÒÓÉÉ Java."
+	echo "÷Ù ÄÏÌÖÎÙ ÕÓÔÁÎÏ×ÉÔØ Java Runtime Environment (×ÅÒÓÉÀ 1.4 ÉÌÉ ×ÙÛÅ)"
+	echo "ÐÅÒÅÄ ××ÏÄÏÍ ÂÉÂÌÉÏÔÅÞÎÏÇÏ ÉÎÔÅÒÆÅÊÓÁ Greenstone."
+    else
+	echo "Failed to locate an appropriate version of Java. You must install a"
+	echo "Java Runtime Environment (version 1.4 or greater) before running the"
+	echo "Greenstone Librarian Interface."
+    fi
+    exit 1
+fi
+
+
+## -- Check the version of Java is new enough (1.4.0 or higher) to run the GLI --
+`$javapath -classpath . CheckJavaVersion > /dev/null`
+if [ $? -ne 2 ] ; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "La versión del Ambiente de Ejecución Java (JRE por sus siglas en "
+	echo "inglés) que usted tiene instalada es demasiado vieja para ejecutar "
+	echo "la Interfaz de la Biblioteca Digital Greenstone. Por favor instale "
+	echo "una nueva versión del Ambiente de Ejecución Java (versión 1.4 o "
+	echo "posterior) y ejecute nuevamente este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "La version de Java Runtime Environment que vous avez installée est"
+	echo "trop vielle pour faire fonctionner Greenstone Librarian Interface."
+	echo "Veuillez installer une nouvelle version du JRE (version 1.4 ou plus"
+	echo "récente) et redémarrez le script."
+    elif [ "$glilang" == "ru" ]; then
+	echo "÷ÅÒÓÉÑ Java Runtime Environment, ËÏÔÏÒÕÀ ÷Ù ÕÓÔÁÎÏ×ÉÌÉ, ÏÞÅÎØ ÓÔÁÒÁ,"
+	echo "ÞÔÏÂÙ ÕÐÒÁ×ÌÑÔØ ÂÉÂÌÉÏÔÅÞÎÙÍ ÉÎÔÅÒÆÅÊÓÏÍ Greenstone. ðÏÖÁÌÕÊÓÔÁ, "
+	echo "ÕÓÔÁÎÏ×ÉÔÅ ÎÏ×ÕÀ ×ÅÒÓÉÀ JRE (×ÅÒÓÉÀ 1.4 ÉÌÉ ÂÏÌÅÅ ÎÏ×ÕÀ) É"
+	echo "ÐÅÒÅÕÓÔÁÎÏ×ÉÔÅ ÜÔÏÔ ÓËÒÉÐÔ"
+    else
+	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."
+    fi
+    exit 1
+fi
+
+## ---- Set wgetpath manually if you don't want to use the default Greenstone version -----
+wgetpath=
+
+## ---- Check that the GLI has been compiled ----
+if [ ! -f "classes/org/greenstone/gatherer/GathererProg.class" ] && [ ! -f "GLI.jar" ]; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "Usted necesita compilar la Interfaz de la Biblioteca Digital Greenstone"
+	echo "(por medio de makegli.sh) antes de ejecutar este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Vous devez compiler le Greenstone Interface (en utilisant makegli.sh)"
+	echo "avant d'exécuter ce script."
+    elif [ "$glilang" == "ru" ]; then
+	echo "÷Ù ÄÏÌÖÎÙ ËÏÍÐÉÌÉÒÏ×ÁÔØ ÂÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone"
+	echo "(ÉÓÐÏÌØÚÕÑ makegli.sh) ÐÅÒÅÄ ××ÏÄÏÍ ÜÔÏÇÏ ÓËÒÉÐÔÁ"
+    else
+	echo "You need to compile the Greenstone Librarian Interface (using makegli.sh)"
+	echo "before running this script."
+    fi
+    exit 1
+fi
+
+if [ "$1" == "-test" ]; then
+    if [ "$glilang" == "es" ]; then
+	echo "Clase de prueba: $2"
+	echo "Argumentos $*"
+    elif [ "$glilang" == "fr" ]; then
+	echo "Classe de test: $2"
+	echo "Arguments $*"
+    elif [ "$glilang" == "ru" ]; then
+	echo "éÓÐÙÔÁÔÅÌØÎÙÊ ËÌÁÓÓ: $2"
+	echo "ðÁÒÁÍÅÔÒÙ $*"
+    else
+	echo "Testing class: $2"
+	echo "Arguments $*"
+    fi
+    $javapath -classpath classes/:GLI.jar:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar $2 $3
+    exit 0
+fi
+
+## ---- Finally, run the GLI ----
+echo
+if [ "$glilang" == "es" ]; then
+    echo "Ejecutando la Interfaz de la Biblioteca Digital Greenstone..."
+elif [ "$glilang" == "fr" ]; then
+    echo "Exécution de Greenstone Librarian Interface"
+elif [ "$glilang" == "ru" ]; then
+    echo "ôÅËÕÝÉÊ ÂÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone..."
+else
+    echo "Running the Greenstone Librarian Interface..."
+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 -gsdl3 $GSDL3HOME -gsdl3src $GSDL3SRCHOME -wget $wgetpath $*
+
+if [ "$glilang" == "es" ]; then
+    echo "¡Hecho!"
+elif [ "$glilang" == "fr" ]; then
+    echo "Terminé!"
+elif [ "$glilang" == "ru" ]; then
+    echo "÷ÙÐÏÌÎÅÎÏ!"
+else
+    echo "Done!"
+fi
Index: /tags/gsdl-2_61-distribution/gli/help/en/addingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/addingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/addingfiles.htm	(revision 10506)
@@ -0,0 +1,89 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="addingfiles"><font size="5" face="Verdana"><strong>4.3: Adding Files</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section shows how to get files into your collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Dragging a file
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Multiple files
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Existing metadata
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Files can be copied into the collection by dragging and dropping.  The mouse
+pointer becomes a ghost of the selected item (or, if more than one is selected,
+the number of them).  Drop the selection into the Collection Tree to copy the
+files there (if the source was the Workspace Tree) or move them around within
+the collection (if the source was the Collection Tree).
+<p></p>
+When copying multiple files, they are all placed in the target folder at the
+same level, irrespective of the folder structure they occupied originally.
+When you copy a second file with the same name into the same folder, you are
+asked whether to overwrite the first one.  Respond "No" and the file will not be
+copied, but the others will be.  To cancel all remaining copy actions, click the
+"stop" button.
+<p></p>
+Only the "highest" items in a selection are moved.  A folder is higher than its
+children.  You cannot select files within a folder and also the folder itself.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+When you add a file, the Librarian Interface searches through the source
+folders for auxiliary files containing metadata previously assigned to the
+added file and, if it finds one, begins to import this metadata.  As the
+operation proceeds, you may be prompted (perhaps several times) for extra
+information to match the imported metadata to the metadata sets in your
+collection.  This process involves many different prompts, described in the <a href="importingpreviouslyassignedmetadata.htm#importingpreviouslyassignedmetadata">Importing Previously Assigned Metadata</a> section.  For a more detailed
+explanation of associating metadata with files read Chapter 2 of the Greenstone
+Developer's Guide -- Getting the most out of your documents.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/addingpreviouslydefinedmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/addingpreviouslydefinedmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/addingpreviouslydefinedmetadata.htm	(revision 10506)
@@ -0,0 +1,60 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="addingpreviouslydefinedmetadata"><font size="5" face="Verdana"><strong>5.4: Adding Previously Defined Metadata</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains how to add metadata that uses values already present in the value tree.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Adding to files
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Adding to folders or multiple files
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+To add metadata that has an existing value, first select the file, then select
+the required value from the value tree, expanding hierarchy folders as
+necessary.  The value of the selected entry automatically appears in the Value
+text field (alternatively, use the value tree's auto-select and auto-complete
+features).  Click "Append" to add the metadata to the selected file.
+<p></p>
+The process of adding metadata with already-existing values to folders
+or multiple files is just the same.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/appendingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/appendingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/appendingmetadata.htm	(revision 10506)
@@ -0,0 +1,86 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="appendingmetadata"><font size="5" face="Verdana"><strong>5.3: Appending New Metadata</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains how to add metadata and values to files, and how to add new values for metadata elements.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Adding to files
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Adding to folders or multiple files
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Value hierarchies and editing values
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+We now add a metadata item -- both element and value -- to a file.  First select
+the file from the Collection file tree on the left.  The action causes any
+metadata previously assigned to this file to appear in the table at the right.
+<p></p>
+Next select the metadata element you want to add by clicking its row in the
+table.
+<p></p>
+Type the value into the value field.  Do not use the character "|", as it is
+used for constructing hierarchies.  When finished, click "Append" to add the new
+value as metadata for the chosen file.  The value immediately appears in the
+Metadata table.
+<p></p>
+You can also add metadata to a folder, or to several multiply selected files at
+once.  It is added to all files within the folder or selection, and to child
+folders.  Keep in mind that if you assign metadata to a folder, any new files in
+it automatically inherit the folder's values.
+<p></p>
+If you choose metadata that occurs in some of the selected files and click
+"Append", it is added to the other files in the selection too.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+You can add structure to metadata values by using paths as described in <a href="theenrichview.htm#theenrichview">The Enrich View</a>.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/assignlanguages.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/assignlanguages.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/assignlanguages.htm	(revision 10506)
@@ -0,0 +1,82 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="assignlanguages"><font size="5" face="Verdana"><strong>6.6.3: Assign Languages</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+This section details how to restrict search indexes to particular languages.
+You do this by generating a partition using the "Assign Languages" tab of the
+"Partition Indexes" view.
+        <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+          
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Language controls
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Add language
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Remove language
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Set default language
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Clear default language
+            </td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+        
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+To add a new language to partition by, use the "Assign Languages" tab to build
+an index for it.  Select the desired language from the "Language to add"
+pull-down list and click "Add Language".
+<p></p>
+To remove a language, select it from the "Language Selection" list and click
+"Remove Language".
+<p></p>
+To set the default language, select it from the list and click "Set Default".
+<p></p>
+To clear the default language, click "Clear Default".
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/assignpartitions.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/assignpartitions.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/assignpartitions.htm	(revision 10506)
@@ -0,0 +1,74 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="assignpartitions"><font size="5" face="Verdana"><strong>6.6.2: Assign Partitions</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+This section explains how to assign a previous defined partition filter.
+        <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+          
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Add a partition
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Remove a partition
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Set default partition
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Clear default partition
+            </td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+        
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Having defined a subcollection filter, use the "Assign Partitions" tab to build
+indexes for it (or for a group of filters).  Select the desired filter (or
+filters) from the "Defined Subcollection Filters" list, enter a name for your partition in the "Partition Name" field,  and click "Add Partition".
+<p></p>
+To remove a partition, select it from the list and click "Remove Partition".
+<p></p>
+To make a partition the default one, select it from the list and click "Set
+Default".
+<p></p>
+To clear the default partition, click "Clear Default".
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/buildsettings.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/buildsettings.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/buildsettings.htm	(revision 10506)
@@ -0,0 +1,66 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="buildsettings"><font size="5" face="Verdana"><strong>7.2: Import and Build Settings</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains how to access the various import and build settings.
+For more information of importing and building read Chapter 1 of the Greenstone
+Developer's Guide -- Understanding the collection-building process.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            General settings
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Import settings
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Build settings
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Controlling the various settings is done in a similar way to the
+"Configuring Arguments" window described in the <a href="plugins.htm#plugins">Document Plugins</a> section.  Some
+fields require numeric arguments, and you can either type these in or use the
+up and down arrows to increase or decrease the current value (in some cases,
+the interface restricts the range you can enter).  Others are enabled by
+clicking a checkbox (click again to disable).
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/classifiers.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/classifiers.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/classifiers.htm	(revision 10506)
@@ -0,0 +1,91 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="classifiers"><font size="5" face="Verdana"><strong>6.8: Classifiers</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains how to assign "classifiers", which are used for browsing,
+to the collection.  Under "Design Sections", click "Browsing Classifiers".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Classifier selection and configuration
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Add a classifier
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Remove a classifier
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Configure a classifier
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Alter classifier ordering
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+To add a classifier, select it using the "Select classifier to add" pull-down list near the
+bottom and then click "Add Specified Classifier".  A window appears entitled
+"Configuring Arguments"; instructions for this dialog are just the same as for
+plugins (see <a href="plugins.htm#plugins">Document Plugins</a>).  Once you have configured the new
+classifier, it is added to the end of the "Currently Assigned Classifiers"
+list.
+<p></p>
+To remove a classifier, select it from the list and click "Remove Selected
+Classifier".
+<p></p>
+To change the arguments a classifier, select it from the list and click
+"Configure Selected Classifier" (or double-click on the classifier in the
+list).
+<p></p>
+The ordering of classifiers in the collection's navigation bar is reflected in
+their order here.  To change it, select the classifier you want to move and
+click "Move Up" or "Move Down".
+<p></p>
+For further information on classifiers read Chapter 2, Greenstone
+Developer's Guide -- Getting the most out of your documents.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/collectingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/collectingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/collectingfiles.htm	(revision 10506)
@@ -0,0 +1,24 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="collectingfiles"><font size="5" face="Verdana"><strong>4: Collecting Files for Your Collection</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+Once you have a new collection you need to get some files into it.  These may
+come from your ordinary file space, or from other Greenstone collections.  Some
+may already have attached metadata.  This section describes how to import files.
+    
+    
+
+
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/creatingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/creatingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/creatingacollection.htm	(revision 10506)
@@ -0,0 +1,112 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="creatingacollection"><font size="5" face="Verdana"><strong>2.1: Creating a New Collection</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section describes how to create a new collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The new collection prompt
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The collection title
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Default metadata sets
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Collection description
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Creating the new collection
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Cancelling the new collection
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Quick keys
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+To create a new collection, open the "File" menu and choose "New".  Several
+fields need to be filled out -- but you can change their values later if you
+need to, in the design view.
+<p></p>
+"Collection title" is the text displayed at the top of your collection's home page.  It can
+be any length.
+<p></p>
+"Description of content"
+should describe, in as much detail as possible, what the collection is about.
+Use the [Enter] key to break it into paragraphs.
+<p></p>
+Finally you must specify whether the new collection will have the same
+appearance and metadata sets as an existing collection, or whether to start a
+default "New Collection".
+<p></p>
+Click "OK" to create the collection.  If you chose "New Collection" you are
+prompted for the metadata sets to use in it.  You can choose more than one, and
+you can add others later.
+<p></p>
+Clicking "Cancel" returns you to the main screen immediately.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+Buttons, like menus, have one character underlined.  To "click" the button,
+press [ALT] and the underlined character at the same time.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/creatingfolders.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/creatingfolders.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/creatingfolders.htm	(revision 10506)
@@ -0,0 +1,63 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="creatingfolders"><font size="5" face="Verdana"><strong>4.2: Creating Folders</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section shows how to create new folders.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The new folder button
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The right-button menu
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Use folders in the Collection file tree to group files together and make them
+easier to find.  Folders can be placed inside folders.  There is virtually no
+limit to how many folders you can have or how deeply they can be nested.
+<p></p>
+To create a new folder, optionally select an existing folder in the Collection
+Tree and click the New Folder button.  The new folder appears within the
+selected one, or at the top level if none is selected.  You are prompted for the
+folder's name (default "New Folder").
+<p></p>
+Folders can also be created by right-clicking over a folder, choosing "New
+Folder" and proceeding as above.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/definefilters.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/definefilters.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/definefilters.htm	(revision 10506)
@@ -0,0 +1,75 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="definefilters"><font size="5" face="Verdana"><strong>6.6.1: Define Filters</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+The section explains how to define a partition filter.
+        <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+          
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Add a filter
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Remove a filter
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Update a filter
+            </td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+        
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Filters allows you to group together into a subcollection all documents in an
+index for which a metadata value matches a given pattern.
+<p></p>
+To create a filter, click the "Define Filters" tab and enter a name for the
+new filter into the "Name the subcollection filter" field.  Next choose a
+document attribute to match against, either a metadata element or the name of
+the file in question.  Enter a regular expression to use during the matching.
+You can toggle between "Including" documents that match the filter, or
+"Excluding" them.  Finally, you can specify any of the standard PERL regular
+expression flags to use when matching (e.g.  "i" for case-insensitive matching).
+Finally, click "Add Filter" to add the filter to the "Defined Subcollection Filters"
+list.
+<p></p>
+To remove a filter, select it from the list and click "Remove Filter".
+<p></p>
+To alter a filter, select it from the list, change any of the values that
+appear in the editing controls and click "Replace Filter" to commit the changes.
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/deletingcollections.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/deletingcollections.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/deletingcollections.htm	(revision 10506)
@@ -0,0 +1,47 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="deletingcollections"><font size="5" face="Verdana"><strong>2.4: Deleting Collections</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains how to permanently delete collections from your Greenstone installation.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            How to delete collections
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+To permanently delete collections from your Greenstone installation, choose "Delete..." from the "File" menu. A list of your Greenstone collections appears. Select one to see its description, then tick the box at the bottom of the dialog and click "Delete" to delete the collection. This action is irreversible, so check carefully that you no longer need the collection before proceeding!
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/designingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/designingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/designingacollection.htm	(revision 10506)
@@ -0,0 +1,30 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="designingacollection"><font size="5" face="Verdana"><strong>6: Designing Your Collection's Appearance</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+Once your files are marked up with metadata, you next decide how it should
+appear to users as a Greenstone collection.  What kind of information is
+searchable?  What ways are provided to browse through the documents?  What
+languages are supported?  Where do the buttons appear on the page?  These
+things can be customized; this section describes how to do it.
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/downloadingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/downloadingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/downloadingfiles.htm	(revision 10506)
@@ -0,0 +1,16 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="downloadingfiles"><font size="5" face="Verdana"><strong>3: Downloading Files From the Internet</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+The "Download" view helps you download resources from the internet. This section explains the Librarian Interface's mirroring process.
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/enrichingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/enrichingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/enrichingacollection.htm	(revision 10506)
@@ -0,0 +1,27 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="enrichingacollection"><font size="5" face="Verdana"><strong>5: Enriching the Collection with Metadata</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+Having gathered several files into the collection, now enrich them with
+additional information called "metadata".  This section explains how metadata is
+created, edited, assigned and retrieved, and how to use external metadata
+sources (also see Chapter 2 of the Greenstone Developer's Guide -- Getting the most
+out of your documents).
+    
+    
+    
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/exportingcollections.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/exportingcollections.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/exportingcollections.htm	(revision 10506)
@@ -0,0 +1,63 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="exportingcollections"><font size="5" face="Verdana"><strong>8.3: Exporting Collections to CD-ROM</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      
+This section describes how to export collections to a self-installing 
+Greenstone CD-ROM. 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            How to export
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Greenstone can export one or more collections to a self-installing 
+CD-ROM for Windows. To do so, Greenstone's "Export to CD-ROM" package 
+must be installed. This is not included by default, so you may need to 
+modify your installation to include it.
+<p></p>
+To export a collection, open the "File" menu and choose "Export to 
+CD-ROM". A list of Greenstone collections appears; click on any one to 
+see its description. Tick the check boxes of the collections to export. 
+You can enter the CD-ROM's name in the box: this is what will appear in 
+the Start menu when the CD-ROM has been installed. Then click "Export". 
+The process involves copying many files and may take a few minutes.
+<p></p>
+Upon completion, Greenstone will show the name of a folder containing 
+the exported collections. Use a CD writer to copy its contents to a 
+blank CD-ROM.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/fileassociations.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/fileassociations.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/fileassociations.htm	(revision 10506)
@@ -0,0 +1,79 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="fileassociations"><font size="5" face="Verdana"><strong>8.2: File Associations</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+The Librarian Interface uses particular application programs to open particular
+file types.  This section explains how to assign and edit these file
+associations.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Add association
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Edit association
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Remove association
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+To alter file associations open the "File" menu and click "File
+Associations...".
+<p></p>
+To add an association, select the target file extension from the pull-down
+list, or type in a new extension (do not include the ".").  Next either type
+command that launches the desired application in the appropriate field, or
+choose the application from the "Browse" dialog.  "%1" can be used in the launch
+command to insert the name of the file being opened.  Once these are filled out,
+"Add Association" is enabled and can be clicked to add the association.
+<p></p>
+To edit an association, select an existing file extension.  Any existing
+associated command is shown in the launch command field.  Edit it, and then
+click "Replace Association".
+<p></p>
+To remove an association, select an existing file extension and click "Remove Association".
+(The file extension remains in the "For Files Ending" pull-down list.)
+<p></p>
+File associations are stored in the Librarian Interface's main folder, in a file
+called "associations.xml".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/filteringthetree.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/filteringthetree.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/filteringthetree.htm	(revision 10506)
@@ -0,0 +1,68 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="filteringthetree"><font size="5" face="Verdana"><strong>4.5: Filtering the Tree</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+"Filtering" the collection tree allows you to narrow down the search for particular files.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The filter control
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Custom filtering
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+The "Show Files" pull-down menu underneath each tree shows a list of predefined
+filters, such as "Images".  Choosing this temporarily hides all other files in
+the tree.  To restore the tree, change the filter back to "All Files".  These
+operations do not alter the collection, nor do they affect the folders in the
+tree.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+You can specify a custom filter by typing in a pattern to match files against.
+Use standard file system abbreviations such as "*.*" or "*.doc" ("*" matches
+any characters).
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/formatstatements.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/formatstatements.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/formatstatements.htm	(revision 10506)
@@ -0,0 +1,111 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="formatstatements"><font size="5" face="Verdana"><strong>6.9: Format Features</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+Format commands control the structure and appearance of the collection.  They
+affect such things as where buttons appear when a document is shown, and what
+links are displayed by the DateList classifier.  Format commands are not easy
+to develop, and you should read Chapter 2 of the Greenstone Developer's Guide.
+This section discusses the format settings, and how the Librarian Interface
+gives access to them.  Under "Design Sections", click "Format Features".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Formatting
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Add format command
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Remove format command
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Update format command
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Extended formatting options
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+You can apply a format command to anything in the "Choose Feature" pull-down
+list, which includes each classifier and a predefined list of features.  When
+you select a feature, there are two types of control.  Some features are simply
+enabled or disabled, and this is controlled by a checkbox.  Others require a
+format string to be specified.  For these there is a pull-down list ("Affected 
+Component") for selecting which part of the feature the string applies to 
+(if necessary), a text area ("HTML Format String") for entering the string, 
+and a selection of predefined "Variables".  To insert a variable into the 
+current position in the format string, select it from the pull-down list and 
+click "Insert".
+<p></p>
+You can specify a default format for a particular component by selecting the
+blank feature.  This format is then applied to all applicable features unless
+otherwise specified.
+<p></p>
+To add a new format command, fill out the information as explained above and
+click "Add Format".  The new format command appears in the list of "Currently
+Assigned Format Commands".  Only one format command can be assigned to each
+feature/component combination.
+<p></p>
+To remove a format command, select it from the list and click "Remove Format".
+<p></p>
+To change a format command, select it from the list, modify the settings, and
+click "Replace Format".
+<p></p>
+For more information about variables and the feature components, read Chapter 2
+of the Greenstone Developer's Guide.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+If the "Allow Extended Options" checkbox is ticked, some advanced formatting options are enabled. The list of features that can be formatted is changed slightly, and more variables are available to be used in the format command, providing greater control over the page layout.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/generalsettings.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/generalsettings.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/generalsettings.htm	(revision 10506)
@@ -0,0 +1,59 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="generalsettings"><font size="5" face="Verdana"><strong>6.2: General Settings</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains how to review and alter the general settings associated
+with your collection.  First, under "Design Sections", click "General".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            General settings
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Here the values provided during collection creation can be modified.
+<p></p>
+At the top of the page is an instruction box, which appears for each of the
+different sections.  It contains a brief list of instructions to remind you
+what functionality is available.
+<p></p>
+First are the contact emails of the collection's creator and maintainer.  
+The following field allows you to change the collection title. The folder that the collection is stored in is shown next, but this cannot be edited.
+The next one specifies (in the form of a URL) the
+icon to show at the top left of the collection's "About" page, and the next is
+the icon used in the Greenstone library page to link to the collection. Then, a checkbox controls whether the collection should be publicly accessible.
+Finally comes the "Collection Description" text area as described in <a href="creatingacollection.htm#creatingacollection">Creating A New Collection</a>.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/help.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/help.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/help.xml	(revision 10506)
@@ -0,0 +1,1457 @@
+<Document>
+  <Section name="introduction">
+    <Title>Introduction</Title>
+The Greenstone Librarian Interface is a tool for collecting and marking up documents, then building digital library collections.  It provides access to the Greenstone Digital Library Software's functionality from a graphical point and click interface.
+    <Section name="ofmiceandmenus">
+      <Title>Of Mice and Menus</Title>
+This section provides basic information about interacting with the Librarian Interface.
+If you are familiar with programs such as Internet Explorer or Microsoft
+Office and are comfortable with mouse clicks and menus, skip to the <Reference target="howtoavoidthisdocument">next section</Reference>.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    Basic concepts   
+            <ContentsItem>
+              Mouse actions
+	    </ContentsItem>
+            <ContentsItem>
+              Keyboard
+	    </ContentsItem>
+          </ContentsItem>
+          <ContentsItem>
+	    Exiting the program
+          </ContentsItem>
+	</ContentsGroup>
+	<ContentsGroup linkto="advanced">
+          <ContentsItem>
+	    Quick keys
+          </ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+The Librarian Interface follows Microsoft Windows conventions and draws upon
+ordinary knowledge of Windows.
+<Break/>
+Any part of the screen that you interact with, such as a button or text field,
+is called a "control".  At any given time one control, called the "focus", is
+highlighted and responds to the keyboard.  Several controls allow you to select
+parts that are highlighted in dark blue.  Some controls are greyed out to
+indicate that they are disabled.
+<Break/>
+You can move and left- or right-click the mouse in the usual way.  Many
+components also allow you to "drag" them, by clicking and holding the left
+mouse button, move them with the mouse, and "drop" them elsewhere by releasing
+the button.  Potential drop targets alter their appearance when a component
+hovers over them.
+<Break/>
+You can use the keyboard to type into text fields.  Keyboard alternatives are
+available for many controls, indicated by a key name in square brackets -- for
+example, [Tab] alters the focus.  The plus sign shows if other keys must be
+pressed at the same time.
+<Break/>
+Exit the Librarian Interface program by choosing "Exit" from the "File"
+menu.  Your collection will be saved first.
+       <Anchor name="advanced">Advanced Instructions:</Anchor>
+To access a menu, hold down [ALT] and press the corresponding letter
+(underlined).  For example, for the "File" menu press [ALT] + [F].  To choose an
+item, press the corresponding key.  For example, while in the File menu
+press [S] to "Save" a collection.
+    </Section>
+    <Section name="howtoavoidthisdocument">
+      <Title>How to Avoid Reading This Document</Title>
+Don't read this help text all the way through!  Just read enough to learn
+how to get help when you need it.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Context sensitive help
+          </ContentsItem>
+          <ContentsItem>
+            Tool tips
+          </ContentsItem>
+          <ContentsItem>
+            Other documents
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+The "Help" menu item marks what may be the most appropriate help item with a
+little book icon.
+<Break/>
+For many controls, if you station the mouse over them a
+"tool tip" appears that says what they do.
+<Break/>
+Before using the Librarian Interface, first read the Greenstone
+documentation.
+    </Section>
+  </Section>
+
+  <Section name="startingoff">
+    <Title>Starting Off</Title>
+    This section covers how to create, load, save and delete collections.
+    <Section name="creatingacollection">
+      <Title>Creating a New Collection</Title>
+<ObviousSentence>This section describes how to create a new collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            The new collection prompt
+          </ContentsItem>
+          <ContentsItem>
+            The collection title
+          </ContentsItem>
+          <ContentsItem>
+            Default metadata sets
+          </ContentsItem>
+          <ContentsItem>
+            Collection description
+          </ContentsItem>
+          <ContentsItem>
+            Creating the new collection
+          </ContentsItem>
+          <ContentsItem>
+            Cancelling the new collection
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Quick keys
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+To create a new collection, open the "File" menu and choose "New".  Several
+fields need to be filled out -- but you can change their values later if you
+need to, in the design view.
+<Break/>
+"Collection title" is the text displayed at the top of your collection's home page.  It can
+be any length.
+<Break/>
+"Description of content"
+should describe, in as much detail as possible, what the collection is about.
+Use the [Enter] key to break it into paragraphs.
+<Break/>
+Finally you must specify whether the new collection will have the same
+appearance and metadata sets as an existing collection, or whether to start a
+default "New Collection".
+<Break/>
+Click "OK" to create the collection.  If you chose "New Collection" you are
+prompted for the metadata sets to use in it.  You can choose more than one, and
+you can add others later.
+<Break/>
+Clicking "Cancel" returns you to the main screen immediately.
+      <Anchor name="advanced">Advanced Instructions:</Anchor>
+Buttons, like menus, have one character underlined.  To "click" the button,
+press [ALT] and the underlined character at the same time.
+    </Section>
+    <Section name="savingacollection">
+      <Title>Saving the Collection</Title>
+<ObviousSentence>This section describes how to save a collection, and the Save Collection Prompt.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            How to save
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Where the files are saved
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+Save your work regularly by opening the "File" menu and choosing "Save".
+Saving a collection is not the same as making it ready for use in Greenstone
+(see <Reference target="producingthecollection">Producing Your Collection</Reference>).
+<Break/>
+The Librarian Interface protects your work by saving it whenever you exit the
+program or load another collection.
+      <Anchor name="advanced">Advanced Instructions:</Anchor>
+Saved collections are written to a file named for the collection and with file
+extension ".col", located in a folder of the same name within your Greenstone
+installation's "collect" folder.
+    </Section>
+    <Section name="openingacollection">
+      <Title>Opening an Existing Collection</Title>
+<ObviousSentence>This section tells you how to open existing collections using the Open
+Collection prompt.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            How to open a collection
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Locked collections
+          </ContentsItem>
+	  <ContentsItem>
+	    Legacy collections
+	  </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+To open an existing collection, choose "Open" from the "File" menu to get the
+Open Collection prompt.  A list of your Greenstone collections appears.
+Select one to see its description, and click "Open" to load it.  If you seek a
+collection that resides outside Greenstone's "collect" folder, click "Browse"
+for a file system browsing dialog.
+      <Anchor name="advanced">Advanced Instructions:</Anchor>
+In case more than one Greenstone Librarian Interface program is running
+concurrently, the relevant directories are "locked" to prevent interference.
+On opening a collection, a small temporary lock file is created in its
+folder.  Before opening a collection, the Librarian Interface checks to ensure
+that no lock file already exists.  You can tell whether a collection is locked
+by the colour of its icon: green for a normal collection, red for a locked
+one.  However, when the Librarian Interface is exited prematurely the lock file
+is sometimes left in place.  When you open such a collection, the Librarian asks
+if you want to "steal" control of it.  Never steal a collection that someone
+else is currently working on.
+<Break/>
+When you open a collection that the Greenstone Librarian Interface did 
+not create, you will be asked to select a metadata set (or sets).  If 
+none are selected, any existing metadata will be ignored. Otherwise, 
+metadata will be imported just as it is when you drag in files with 
+existing metadata. The process is described in the <Reference target="importingpreviouslyassignedmetadata">Importing Previously Assigned Metadata</Reference> section. 
+    </Section>
+    <Section name="deletingcollections">
+      <Title>Deleting Collections</Title>
+<ObviousSentence>This section explains how to permanently delete collections from your Greenstone installation.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            How to delete collections
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+To permanently delete collections from your Greenstone installation, choose "Delete..." from the "File" menu. A list of your Greenstone collections appears. Select one to see its description, then tick the box at the bottom of the dialog and click "Delete" to delete the collection. This action is irreversible, so check carefully that you no longer need the collection before proceeding!
+    </Section>
+  </Section>
+
+ <Section name="downloadingfiles">
+    <Title>Downloading Files From the Internet</Title>
+The "Download" view helps you download resources from the internet. This section explains the Librarian Interface's mirroring process.
+    <Section name="themirrorview">
+      <Title>The Download view</Title>
+This section describes how to configure a download task and control the downloading process.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            The workspace tree
+          </ContentsItem>
+          <ContentsItem>
+            Download configuration
+          </ContentsItem>
+          <ContentsItem>
+            The download list
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Enabling web proxies
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+Access the "Download" view by clicking its tab. The top half of the screen shows the downloading controls. The bottom half is initially empty, but will show a list of pending and completed downloading jobs. 
+<Break/>
+Files are downloaded into a folder in the workspace called "Downloaded Files" (only present when mirroring is enabled), and can be used in all collections built with the Librarian Interface.  Files in this area are named by their full web URL. A new folder is created for each host, followed by others for each part of the path. This ensures that each file is distinct.
+<Break/>
+Use the first of the download configuration controls, "Source URL", to enter the URL of a target resource. Use the "Download Depth" control to limit how many  hyperlinks to follow when downloading: Set this to 0 to download a single web page; set it to 1 to download a page and all the pages it points to. The depth limit is ignored when downloading media other than html pages. Next, there are several checkbox controls which can be set to turn on the specified feature for a specific download. Once the configuration is set up, click "Download" to start the new download job. There are two other button controls: "Preferences", which links to the connection section of the Preferences where proxy settings can be edited; and "Clear Cache", which deletes all previously downloaded files.
+<Break/>
+The download list has an entry for each web page download.  Each entry has a text region that gives details of the task along with a progress bar showing current activity. Three buttons appear to the left of each entry. "Pause" is used for pausing a currently downloading task. "View Log" opens a window showing the download log file. "Close" terminates the download and removes the task from the list.  
+      <Anchor name="advanced">Advanced Instructions:</Anchor>
+The <Reference target="preferences">Preferences section</Reference> describes how to establish an Internet connection via a proxy.  If authentication is needed, the proxy server prompts for identification and password.  The Librarian Interface does not store passwords between sessions.
+    </Section>
+  </Section>
+
+  <Section name="collectingfiles">
+    <Title>Collecting Files for Your Collection</Title>
+Once you have a new collection you need to get some files into it.  These may
+come from your ordinary file space, or from other Greenstone collections.  Some
+may already have attached metadata.  This section describes how to import files.
+    <Section name="thegatherview">
+      <Title>The Gather View</Title>
+This section introduces the Gather area that you use to select what files
+to include in the collection you are building.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            How to view the gather screen
+          </ContentsItem>
+          <ContentsItem>
+            The file trees
+          </ContentsItem>
+          <ContentsItem>
+            The status area
+          </ContentsItem>
+          <ContentsItem>
+            Control buttons
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Selection methods
+          </ContentsItem>
+          <ContentsItem>
+            Special folder mapping
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+The Librarian Interface starts with the Gather view.  To return to this view
+later, click the "Gather" tab directly below the menu bar.
+<Break/>
+The two large areas titled "Workspace" and "Collection" are used to move files
+into your collection.  They contain "file trees", graphical structures that
+represent files and folders.
+<Break/>
+Select an item in the tree by clicking it.  (There are other ways; see below.)
+Double-click a folder, or single-click the switch symbol beside it, to expand (or collapse)
+its contents.  Double-click a file to open it using its associated application
+program (see <Reference target="fileassociations">File Associations</Reference>).
+<Break/>
+The Workspace file tree shows the sources of data available to the Librarian Interface -- the local file system (including disk and CD-ROM drives), the contents of existing Greenstone collections, and the cache of downloaded files if Web mirroring is enabled. You can copy and view these files but you cannot move, delete, or edit them, with the exception of the downloaded files, which can be deleted.  Navigate this space to find the files you want to include in the collection.
+<Break/>
+The Collection file tree represents the contents of the collection so
+far.  Initially, it is empty.
+<Break/>
+You can resize the spaces by mousing over the grey bar that separates the trees
+(the shape of the pointer changes) and dragging.
+<Break/>
+At the bottom of the window is a status area that shows the progress of actions involving files (copying, moving and deleting). These can take some time to complete. The "Stop" button stops any action that is currently in progress. 
+<Break/>
+Two large buttons occupy the lower right corner of the screen. "New Folder", with a picture
+of a folder, creates new folders (see <Reference target="creatingfolders">Creating folders</Reference>). 
+"Delete", with a garbage can, removes files. Clicking the Delete button will remove any selected files from the Collection file tree. Alternatively, files can be deleted by dragging them onto the Delete button. 
+       <Anchor name="advanced">Advanced Instructions:</Anchor>
+To select several sequential items, select the first and then hold down [Shift]
+and click on the last -- the selection will encompass all intervening
+items.  Select non-sequential files by holding down [Ctrl] while clicking.  Use
+these two methods together to select groups of non-adjacent items.
+<Break/>
+Certain folders -- such as the one containing your own web pages -- sometimes
+have special significance.  The Librarian Interface can map such folders to 
+the first level of the file tree.  To do this, right-click the desired
+folder.  Select "Create Shortcut", and enter a name for the folder.  To remove an item,
+right-click the mapped folder and select "Remove Shortcut".
+    </Section>
+    <Section name="creatingfolders">
+      <Title>Creating Folders</Title>
+<ObviousSentence>This section shows how to create new folders.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            The new folder button
+          </ContentsItem>
+          <ContentsItem>
+            The right-button menu
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+Use folders in the Collection file tree to group files together and make them
+easier to find.  Folders can be placed inside folders.  There is virtually no
+limit to how many folders you can have or how deeply they can be nested.
+<Break/>
+To create a new folder, optionally select an existing folder in the Collection
+Tree and click the New Folder button.  The new folder appears within the
+selected one, or at the top level if none is selected.  You are prompted for the
+folder's name (default "New Folder").
+<Break/>
+Folders can also be created by right-clicking over a folder, choosing "New
+Folder" and proceeding as above.
+    </Section>
+
+
+    <Section name="addingfiles">
+      <Title>Adding Files</Title>
+<ObviousSentence>This section shows how to get files into your collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Dragging a file
+          </ContentsItem>
+          <ContentsItem>
+            Multiple files
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Existing metadata
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+Files can be copied into the collection by dragging and dropping.  The mouse
+pointer becomes a ghost of the selected item (or, if more than one is selected,
+the number of them).  Drop the selection into the Collection Tree to copy the
+files there (if the source was the Workspace Tree) or move them around within
+the collection (if the source was the Collection Tree).
+<Break/>
+When copying multiple files, they are all placed in the target folder at the
+same level, irrespective of the folder structure they occupied originally.
+When you copy a second file with the same name into the same folder, you are
+asked whether to overwrite the first one.  Respond "No" and the file will not be
+copied, but the others will be.  To cancel all remaining copy actions, click the
+"stop" button.
+<Break/>
+Only the "highest" items in a selection are moved.  A folder is higher than its
+children.  You cannot select files within a folder and also the folder itself.
+      <Anchor name="advanced">Advanced Instructions:</Anchor>
+When you add a file, the Librarian Interface searches through the source
+folders for auxiliary files containing metadata previously assigned to the
+added file and, if it finds one, begins to import this metadata.  As the
+operation proceeds, you may be prompted (perhaps several times) for extra
+information to match the imported metadata to the metadata sets in your
+collection.  This process involves many different prompts, described in the <Reference target="importingpreviouslyassignedmetadata">Importing Previously Assigned Metadata</Reference> section.  For a more detailed
+explanation of associating metadata with files read Chapter 2 of the Greenstone
+Developer's Guide -- Getting the most out of your documents.
+    </Section>
+    <Section name="removingfiles">
+      <Title>Removing Files</Title>
+<ObviousSentence>This section describes how to remove files and folders from your collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            The delete button
+          </ContentsItem>
+          <ContentsItem>
+            The delete key
+          </ContentsItem>
+          <ContentsItem>
+            Delete by drag and drop
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+There are several methods for removing files and folders.  You must first
+indicate what items to remove by selecting one or more files and folders as
+described in <Reference target="thegatherview">The Gather View</Reference>.
+<Break/>
+Once files have been selected, click the "delete" button to remove them, or
+press the [Delete] key on your keyboard, or drag them from the collection to
+the delete button and drop them there.
+    </Section>
+    <Section name="filteringthetree">
+      <Title>Filtering the Tree</Title>
+"Filtering" the collection tree allows you to narrow down the search for particular files.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            The filter control
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Custom filtering
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+The "Show Files" pull-down menu underneath each tree shows a list of predefined
+filters, such as "Images".  Choosing this temporarily hides all other files in
+the tree.  To restore the tree, change the filter back to "All Files".  These
+operations do not alter the collection, nor do they affect the folders in the
+tree.
+      <Anchor name="advanced">Advanced Instructions:</Anchor>
+You can specify a custom filter by typing in a pattern to match files against.
+Use standard file system abbreviations such as "*.*" or "*.doc" ("*" matches
+any characters).
+    </Section>
+  </Section>
+
+  <Section name="enrichingacollection">
+    <Title>Enriching the Collection with Metadata</Title>
+Having gathered several files into the collection, now enrich them with
+additional information called "metadata".  This section explains how metadata is
+created, edited, assigned and retrieved, and how to use external metadata
+sources (also see Chapter 2 of the Greenstone Developer's Guide -- Getting the most
+out of your documents).
+    <Section name="theenrichview">
+      <Title>The Enrich View</Title>
+<ObviousSentence>This section describes how to input and edit metadata using the Enrich view.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            The collection tree
+          </ContentsItem>
+          <ContentsItem>
+            The metadata editing controls
+          </ContentsItem>
+          <ContentsItem>
+            The value tree
+          </ContentsItem>
+          <ContentsItem>
+            The metadata table
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+Use the Enrich view to assign metadata to the documents in the collection.
+Metadata is data about data -- typically title, author, creation date, and so
+on.  Each metadata item has two parts: "element" tells what kind of item it is
+(such as author), and "value" gives the value of that metadata element (such as
+the author's name).
+<Break/>
+On the left of the "Enrich" view is the Collection Tree. To the right is the Metadata Table, which shows metadata for any selected files or folders in the Collection Tree.  Columns are named in
+grey at the top, and can be resized by dragging the separating line. Clicking any row transfers its details to the metadata editing controls below. If several files are selected, black text indicates that the value is common to all of the
+selected files, while grey text indicates that it is not.  Black values may be
+updated or removed, while grey ones can be removed from those that have it, or
+appended to the others.
+<Break/>
+A folder icon may appear beside some metadata entries.  This indicates that the
+values are inherited from a parent (or ancestor) folder.  Inherited metadata
+cannot be edited or removed, only appended to or overwritten.  Click on the
+folder icon to go immediately to the folder where the metadata is assigned.
+<Break/>
+The metadata editing controls at the lower right appear only when a file is selected from the tree and a row is selected from the table. Use them to update, append,
+and remove the metadata value.  The value field is for entering or editing the
+metadata value.  Beside it is a button labelled "..." which, when clicked,
+opens a larger editing box.  In the buttons below, "Append" assigns the value as
+new metadata and adds it to any existing values for the selected element,
+"Replace" overwrites the selected existing value with the new one, and "Remove" clears
+the selected value.  Underneath, labelled "All Previous Values", is the "Value
+Tree".
+<Break/>
+The Value Tree expands and collapses.  Usually it is a list that shows all
+values entered previously for the selected element.  Clicking an entry
+automatically places it into the value field.  Conversely, typing in the text
+field selects the Value Tree entry that starts with the characters you have
+typed.  Pressing [Tab] auto-completes the typing with the selected value.
+<Break/>
+Metadata values can be organised into a hierarchy. This is shown in the Value Tree using folders for internal levels. Hierarchical values can be entered using the character "|" to separate the levels.  For
+example, "Cards|Red|Diamonds|Seven" might be used in a hierarchy that represents a pack of playing cards. This enables values to be grouped together. Groups can also be assigned as metadata to files.
+<Break/>
+Greenstone extracts metadata automatically from documents into a metadata set
+whose elements are prefixed by "ex.".  This has no value tree and cannot be
+edited, so the edit controls are hidden if such an entry is selected.  The
+"..." button still serves to expand the value, but the text cannot be edited.
+    </Section>
+    <Section name="selectingmetadatasets">
+      <Title>Selecting Metadata Sets</Title>
+<ObviousSentence>This section explains how to specify metadata elements and how to add metadata sets to your collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            What is a metadata set?
+          </ContentsItem>
+          <ContentsItem>
+            Controlling the metadata sets used
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+Sets of predefined metadata elements are known as "metadata sets".  An example
+is the Dublin Core metadata set.  When you add a metadata set to your
+collection, its elements become available for selection.  You can have more than
+one set; to prevent name clashes a short identifier that identifies the
+metadata set is pre-pended to the element name.  For instance the Dublin Core
+element Creator becomes "dc.Creator".  Metadata sets are stored in the
+Librarian Interface's metadata folder and have the suffix ".mds".
+<Break/>
+To control the metadata sets used in a collection, use the "Metadata Sets" entry on the Design view.
+    </Section>
+    <Section name="appendingmetadata">
+      <Title>Appending New Metadata</Title>
+<ObviousSentence>This section explains how to add metadata and values to files, and how to add new values for metadata elements.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Adding to files
+          </ContentsItem>
+          <ContentsItem>
+            Adding to folders or multiple files
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Value hierarchies and editing values
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+We now add a metadata item -- both element and value -- to a file.  First select
+the file from the Collection file tree on the left.  The action causes any
+metadata previously assigned to this file to appear in the table at the right.
+<Break/>
+Next select the metadata element you want to add by clicking its row in the
+table.
+<Break/>
+Type the value into the value field.  Do not use the character "|", as it is
+used for constructing hierarchies.  When finished, click "Append" to add the new
+value as metadata for the chosen file.  The value immediately appears in the
+Metadata table.
+<Break/>
+You can also add metadata to a folder, or to several multiply selected files at
+once.  It is added to all files within the folder or selection, and to child
+folders.  Keep in mind that if you assign metadata to a folder, any new files in
+it automatically inherit the folder's values.
+<Break/>
+If you choose metadata that occurs in some of the selected files and click
+"Append", it is added to the other files in the selection too.
+      <Anchor name="advanced">Advanced Instructions:</Anchor>
+You can add structure to metadata values by using paths as described in <Reference target="theenrichview">The Enrich View</Reference>.
+    </Section>
+    <Section name="addingpreviouslydefinedmetadata">
+      <Title>Adding Previously Defined Metadata</Title>
+<ObviousSentence>This section explains how to add metadata that uses values already present in the value tree.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Adding to files
+          </ContentsItem>
+          <ContentsItem>
+            Adding to folders or multiple files
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+To add metadata that has an existing value, first select the file, then select
+the required value from the value tree, expanding hierarchy folders as
+necessary.  The value of the selected entry automatically appears in the Value
+text field (alternatively, use the value tree's auto-select and auto-complete
+features).  Click "Append" to add the metadata to the selected file.
+<Break/>
+The process of adding metadata with already-existing values to folders
+or multiple files is just the same.
+    </Section>
+    <Section name="updatingmetadata">
+      <Title>Updating Metadata</Title>
+<ObviousSentence>This section explains how to update the metadata assigned to a file.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Updating files
+          </ContentsItem>
+          <ContentsItem>
+            Updating folders or multiple files
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+To update the value of a piece of metadata, first choose the file to which that
+value applies, and then the metadata element whose value you want to change.
+Your selection appears in the metadata edit controls.  Edit the value field and
+click "Replace" to alter the metadata.
+<Break/>
+The process is the same when updating a folder with child folders or multiple files, but you can only update metadata that is common to all files/folders selected.
+<Break/>
+The value tree shows all previous values, not just those currently assigned.
+Thus the value you have replaced will remain in the value tree.
+    </Section>
+    <Section name="removingmetadata">
+      <Title>Removing Metadata</Title>
+<ObviousSentence>This section explains how to remove metadata from a file.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Removing from files
+          </ContentsItem>
+          <ContentsItem>
+            Removing from folders or multiple files
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+You remove metadata the same way as you update it.  First select a file from the
+file tree, then use the metadata table to select the metadata. If the metadata has a value assigned, the "Remove" button becomes active.
+Click it to remove the metadata from the specified file.  Other files
+remain unchanged, and the value remains in the Value Tree.
+<Break/>
+Removing metadata from folders or multiple files works the same way.
+    </Section>
+    <Section name="reviewingmetadata">
+      <Title>Reviewing Assigned Metadata</Title>
+<ObviousSentence>This section describes how to view all metadata assigned to an entire collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            The audit table
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Right button menu
+          </ContentsItem>
+          <ContentsItem>
+            Autofilter
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+Sometimes you need to see the metadata assigned to many or all files at once -- for instance,
+to determine how many files are left to work on, or to get some idea of the
+spread of dates.
+<Break/>
+Select the files you wish to examine, then right-click and choose "Assigned Metadata...". A window called
+"All Metadata", dominated by a large table with many columns, appears.  The
+first column shows file names; the rows show all metadata values assigned to
+those files.
+<Break/>
+Drawing the table can take some time if many files are selected.  You can continue to use the Librarian
+Interface while the "All Metadata" window is open.
+<Break/>
+Click "Close" to hide the window.
+      <Anchor name="advanced">Advanced Instructions:</Anchor>
+You can also view the "All Metadata" table by selecting the files you wish to
+examine, right-clicking, and choosing "Assigned Metadata...".  If a folder has
+been selected, all its child files are included in the table.
+<Break/>
+When it gets too large, you can filter the "All Metadata" table by applying
+filters to the columns.  As new filters are added, only those rows that match
+them remain visible.  To set, modify or clear a filter, click on the "funnel"
+icon at the top of a column.  You are prompted for information about the filter.
+Once a filter is set, the column header changes colour.
+<Break/>
+The prompt has a "Simple" and an "Advanced" tab.  The Simple version filters
+columns so that they only show rows that contain a certain metadata value ("*"
+matches all values).  You can select metadata values from the pull-down list.
+The Advanced version allows different matching operations: must start with,
+does not contain, alphabetically less than and is equal to.  The value to be
+matched can be edited to be any string (including "*"), and you can choose
+whether the matching should be case insensitive.  Finally, you can specify a
+second matching condition that you can use to specify a range of values (by
+selecting AND) or alternative values (by selecting OR).  Below this area is a
+box that allows you to change the sort order (ascending or descending).  Once
+you have finished, click "Set Filter" to apply the new filter to the column.
+Click "Clear Filter" to remove a current filter.  Note that the filter details
+are retained even when the filter is cleared.
+<Break/>
+For example, to sort the "All Metadata" table, choose a column, select the
+default filter setting (a Simple filter on "*"), and choose ascending or
+descending ordering.
+    </Section>
+    <Section name="importingpreviouslyassignedmetadata">
+      <Title>Importing Previously Assigned Metadata</Title>
+This section describes how to import previously assigned metadata: metadata assigned to documents before they were added to the collection.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            While adding files
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+If metadata in a form recognized by the Librarian Interface has been previously
+assigned to a file -- for example, when you choose documents from an existing
+Greenstone collection -- it is imported automatically when you add the file.
+To do this, the metadata must be mapped to the metadata sets available in the
+collection.
+<Break/>
+The Librarian Interface prompts for the necessary information.  The prompt
+gives brief instructions and then shows the name of the metadata element that
+is being imported, just as it appears in the source file.  This field cannot be
+edited or changed.  Next you choose what metadata set the new element should map
+to, and then the appropriate metadata element in that set.  The system
+automatically selects the closest match, in terms of set and element, for the
+new metadata.
+<Break/>
+Having checked the mapping, you can choose "Add" to add the new metadata
+element to the chosen metadata set.  (This is only enabled if there is no
+element of the same name within the chosen set.) "Replace" maps the new element
+to the one chosen by the user.  Finally, "Ignore" does not import any metadata
+with this element name.  Once you have specified how to import a certain piece of metadata, the mapping
+information is retained for the collection's lifetime.
+<Break/>
+For details on the metadata.xml files which Greenstone uses to store the metadata, see Chapter 2 of the Greenstone
+Developer's Guide -- Getting the most out of your documents.
+    </Section>
+  </Section>
+
+  <Section name="designingacollection">
+    <Title>Designing Your Collection's Appearance</Title>
+Once your files are marked up with metadata, you next decide how it should
+appear to users as a Greenstone collection.  What kind of information is
+searchable?  What ways are provided to browse through the documents?  What
+languages are supported?  Where do the buttons appear on the page?  These
+things can be customized; this section describes how to do it.
+    <Section name="thedesignview">
+      <Title>The Design View</Title>
+This section introduces you to the design view and explains how to navigate
+between the various views within this pane.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Choosing a design section
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+With the Librarian Interface, you can configure how the collection appears to
+the user.  The configuration options are divided into different sections, each
+associated with a particular stage of navigating or presenting information.
+<Break/>
+On the left is a list of different views, and on the right are the controls
+associated with the current one.  To change to a different view, click its name
+in the list.
+<Break/>
+To understand the stages and terms involved in designing a collection, first
+read Chapters 1 and 2 of the Greenstone Developer's Guide.
+    </Section>
+    <Section name="generalsettings">
+      <Title>General Settings</Title>
+This section explains how to review and alter the general settings associated
+with your collection.  First, under "Design Sections", click "General".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            General settings
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+Here the values provided during collection creation can be modified.
+<Break/>
+At the top of the page is an instruction box, which appears for each of the
+different sections.  It contains a brief list of instructions to remind you
+what functionality is available.
+<Break/>
+First are the contact emails of the collection's creator and maintainer.  
+The following field allows you to change the collection title. The folder that the collection is stored in is shown next, but this cannot be edited.
+The next one specifies (in the form of a URL) the
+icon to show at the top left of the collection's "About" page, and the next is
+the icon used in the Greenstone library page to link to the collection. Then, a checkbox controls whether the collection should be publicly accessible.
+Finally comes the "Collection Description" text area as described in <Reference target="creatingacollection">Creating A New Collection</Reference>.
+    </Section>
+    <Section name="plugins">
+      <Title>Document Plugins</Title>
+This section describes how to configure the document plugins the
+collection uses.  It explains how you specify what
+plugins to use, what parameters to pass to them, and in what order
+they occur.  Under "Design Sections", click "Document Plugins".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Add a plugin
+          </ContentsItem>
+          <ContentsItem>
+            Remove a plugin
+          </ContentsItem>
+          <ContentsItem>
+            Configure a plugin
+          </ContentsItem>
+          <ContentsItem>
+            Change plugin order
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Custom configuration
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+To add a plugin, select it using the "Select plugin to add" pull-down list near the
+bottom and then click "Add Plugin".  A window appears entitled
+"Configuring Arguments"; it is described later.  Once you have configured the
+new plugin, it is added to the end of the "Currently Assigned Plugins" list.
+Note that, except for UnknownPlug, each plugin may only occur once in the list.
+<Break/>
+To remove a plugin, select it in the list and click "Remove Plugin".
+<Break/>
+Plugins are configured by providing arguments.  To alter them, select the
+plugin from the list and click "Configure Plugin" (or double-click
+the plugin). A "Configuring Arguments" dialog appears with various controls for specifying arguments.
+<Break/>
+There are different kinds of controls.  Some are checkboxes, and clicking one
+adds the appropriate option to the plugin.  Others are text strings, with a
+checkbox and a text field.  Click the box to enable the argument, then type
+appropriate text (regular expression, file path etc) in the box.  Others are
+pull-down menus from which you can select from a given set of values.  To learn what an
+argument does, let the mouse hover over its name for a moment and a description
+will appear.
+<Break/>
+When you have changed the configuration, click "OK" to commit the changes and
+close the dialog, or "Cancel" to close the dialog without changing any plugin
+arguments.
+<Break/>
+The plugins in the list are executed in order, and the ordering is sometimes
+important.  Two plugins, ArcPlug and RecPlug, are vital to the collection
+building process, and are fixed in place at the end of the list (with a
+separator line).  To change the ordering of the other ones, select the plugin you want to move
+and click "Move Up" or "Move Down".
+       <Anchor name="advanced">Advanced Instructions:</Anchor>
+The Librarian Interface does its best to determine what arguments a plugin
+supports. However, there may be cases where the user wants to specify special arguments, and for this a text field called "Custom Arguments" (at the bottom) is provided. Any text in it is appended verbatim to the end of the plugin
+command.
+    </Section>
+    <Section name="searchtypes">
+      <Title>Search Types</Title>
+This section explains how to modify a new design feature in Greenstone, Search Types, which allow fielded searching.  Under "Design Sections", click "Search Types".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            What enabling advanced searches means
+          </ContentsItem>
+          <ContentsItem>
+            Adding a new search type
+          </ContentsItem>
+          <ContentsItem>
+            Removing a search type
+          </ContentsItem>
+          <ContentsItem>
+            Changing the order of search types
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+When you enter the Search Types view, first check "Enable Advanced
+Searches", which activates the other controls.  This migrates the collection to
+Greenstone 2.4 format, which supports fielded searching, and means that (a)
+the index design is different (explained in the <Reference target="searchindexes">Search Indexes</Reference> section),
+(b) there are more text fragments to translate (see <Reference target="translatetext">Translation</Reference>), and (c) the collection will not be usable under older Greenstone
+installations.  If you later uncheck this field, most of your collection will
+be migrated back to Greenstone 2.39.  However the Librarian Interface cannot
+convert the new index specifications into older ones, so you will have to
+re-enter them manually.
+<Break/>
+To add a search type, select it from the "Search Types" list and click "Add Search Type".  Each type can only appear in the list once.
+<Break/>
+To remove a search type, select it from the "Currently Assigned Search Types"
+list and click "Remove Search Type".  The list must contain at least
+one search type.
+<Break/>
+To change to order of a search type, select it from the list and click "Move
+Up" or "Move Down". The first one will be the default.
+    </Section>
+    <Section name="searchindexes">
+      <Title>Search Indexes</Title>
+Indexes specify what parts of the collection are searchable.  This section explains how to add and remove indexes, and set a default index.  Under "Design Sections", click "Search Indexes".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Add an index
+          </ContentsItem>
+          <ContentsItem>
+            Edit an index
+          </ContentsItem>
+          <ContentsItem>
+            Remove an index
+          </ContentsItem>
+          <ContentsItem>
+            Set default index
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+To add an index, type a name for it into the "Index Name" field.  Select which
+of the possible information sources to index by clicking the checkboxes beside
+them.  The list shows all the assigned metadata elements, as well the full
+text.  Having selected the data sources, choose the granularity of the index,
+using the "At the level" menu.  Once these details are complete, "Add Index"
+becomes active (unless there is an existing index with the same settings).
+Click it to add the new index.
+<Break/>
+To edit an index, select it and change the index details, then click "Replace Index".
+<Break/>
+To remove an index, select it from the list of assigned indexes and click
+"Remove Index".
+<Break/>
+The default index, the one used on the collection's search page, is tagged with
+"[Default Index]" in the "Assigned Indexes" list.  To set it, select an index
+from the list and click "Set Default".
+<Break/>
+If advanced searching is enabled (via the Search Types view), the index controls are different.  Each index
+is based on just one data source.  There is a new pseudo-data source "allfields" which provides searching across all specified indexes at once.  Levels are not
+assigned to a specific index, but apply across all indexes: thus indexes and
+levels are added separately.  Indexes are removed in the same way as above, but
+the default index can no longer be set -- it is simply the
+first index assigned.
+<Break/>
+To create indexes on all sources, click the "Add All" button. The name of each index will default to the source name. To change the name, select an index, change its details, and click "Replace Index".
+    </Section>
+    <Section name="partitionindexes">
+      <Title>Partition Indexes</Title>
+Indexes are built on particular text or metadata sources.  The search space can
+be further controlled by partitioning the index, either by language or by a
+predetermined filter.  This section describes how to do this.  Under "Design
+Sections", click "Partition Indexes".
+<Break/>
+The "Partition Indexes" view has three tabs; "Define Filters", "Assign
+Partitions" and "Assign Languages".  To learn more about partitions read about
+subcollections and subindexes in Chapter 2 of the Greenstone Developer's Guide.
+
+      <Section name="definefilters">
+        <Title>Define Filters</Title>
+<ObviousSentence>The section explains how to define a partition filter.</ObviousSentence>
+        <Contents>
+          <ContentsGroup linkto="simple">
+            <ContentsItem>
+              Add a filter
+            </ContentsItem>
+            <ContentsItem>
+              Remove a filter
+            </ContentsItem>
+            <ContentsItem>
+              Update a filter
+            </ContentsItem>
+          </ContentsGroup>
+        </Contents>
+        <Anchor name="simple">Simple Instructions:</Anchor>
+Filters allows you to group together into a subcollection all documents in an
+index for which a metadata value matches a given pattern.
+<Break/>
+To create a filter, click the "Define Filters" tab and enter a name for the
+new filter into the "Name the subcollection filter" field.  Next choose a
+document attribute to match against, either a metadata element or the name of
+the file in question.  Enter a regular expression to use during the matching.
+You can toggle between "Including" documents that match the filter, or
+"Excluding" them.  Finally, you can specify any of the standard PERL regular
+expression flags to use when matching (e.g.  "i" for case-insensitive matching).
+Finally, click "Add Filter" to add the filter to the "Defined Subcollection Filters"
+list.
+<Break/>
+To remove a filter, select it from the list and click "Remove Filter".
+<Break/>
+To alter a filter, select it from the list, change any of the values that
+appear in the editing controls and click "Replace Filter" to commit the changes.
+      </Section>
+      <Section name="assignpartitions">
+        <Title>Assign Partitions</Title>
+<ObviousSentence>This section explains how to assign a previous defined partition filter.</ObviousSentence>
+        <Contents>
+          <ContentsGroup linkto="simple">
+            <ContentsItem>
+              Add a partition
+            </ContentsItem>
+            <ContentsItem>
+              Remove a partition
+            </ContentsItem>
+            <ContentsItem>
+              Set default partition
+            </ContentsItem>
+            <ContentsItem>
+              Clear default partition
+            </ContentsItem>
+          </ContentsGroup>
+        </Contents>
+        <Anchor name="simple">Simple Instructions:</Anchor>
+Having defined a subcollection filter, use the "Assign Partitions" tab to build
+indexes for it (or for a group of filters).  Select the desired filter (or
+filters) from the "Defined Subcollection Filters" list, enter a name for your partition in the "Partition Name" field,  and click "Add Partition".
+<Break/>
+To remove a partition, select it from the list and click "Remove Partition".
+<Break/>
+To make a partition the default one, select it from the list and click "Set
+Default".
+<Break/>
+To clear the default partition, click "Clear Default".
+      </Section>
+      <Section name="assignlanguages">
+        <Title>Assign Languages</Title>
+This section details how to restrict search indexes to particular languages.
+You do this by generating a partition using the "Assign Languages" tab of the
+"Partition Indexes" view.
+        <Contents>
+          <ContentsGroup linkto="simple">
+            <ContentsItem>
+              Language controls
+            </ContentsItem>
+            <ContentsItem>
+              Add language
+            </ContentsItem>
+            <ContentsItem>
+              Remove language
+            </ContentsItem>
+            <ContentsItem>
+              Set default language
+            </ContentsItem>
+            <ContentsItem>
+              Clear default language
+            </ContentsItem>
+          </ContentsGroup>
+        </Contents>
+        <Anchor name="simple">Simple Instructions:</Anchor>
+To add a new language to partition by, use the "Assign Languages" tab to build
+an index for it.  Select the desired language from the "Language to add"
+pull-down list and click "Add Language".
+<Break/>
+To remove a language, select it from the "Language Selection" list and click
+"Remove Language".
+<Break/>
+To set the default language, select it from the list and click "Set Default".
+<Break/>
+To clear the default language, click "Clear Default".
+      </Section>
+    </Section>
+    <Section name="xcollectionsearching">
+      <Title>Cross-Collection Searching</Title>
+Greenstone can search across several different collections as though they were
+one.  This is done by creating a "super-collection" that comprises the
+individual collections.  Under "Design Sections", click "Cross-Collection Search".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Selecting a collection
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+The Cross-Collection Search view shows a checklist of available collections.  The
+current collection is ticked and cannot be deselected.  To add another
+collection to be searched in parallel, click it in the list (click again to
+remove it).  If only one collection is selected, there is no cross-collection
+searching.
+<Break/>
+For further details, see Chapter 1 of the Greenstone Developer's Guide.
+    </Section>
+    <Section name="classifiers">
+      <Title>Classifiers</Title>
+This section explains how to assign "classifiers", which are used for browsing,
+to the collection.  Under "Design Sections", click "Browsing Classifiers".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Classifier selection and configuration
+          </ContentsItem>
+          <ContentsItem>
+            Add a classifier
+          </ContentsItem>
+          <ContentsItem>
+            Remove a classifier
+          </ContentsItem>
+          <ContentsItem>
+            Configure a classifier
+          </ContentsItem>
+          <ContentsItem>
+            Alter classifier ordering
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+To add a classifier, select it using the "Select classifier to add" pull-down list near the
+bottom and then click "Add Specified Classifier".  A window appears entitled
+"Configuring Arguments"; instructions for this dialog are just the same as for
+plugins (see <Reference target="plugins">Document Plugins</Reference>).  Once you have configured the new
+classifier, it is added to the end of the "Currently Assigned Classifiers"
+list.
+<Break/>
+To remove a classifier, select it from the list and click "Remove Selected
+Classifier".
+<Break/>
+To change the arguments a classifier, select it from the list and click
+"Configure Selected Classifier" (or double-click on the classifier in the
+list).
+<Break/>
+The ordering of classifiers in the collection's navigation bar is reflected in
+their order here.  To change it, select the classifier you want to move and
+click "Move Up" or "Move Down".
+<Break/>
+For further information on classifiers read Chapter 2, Greenstone
+Developer's Guide -- Getting the most out of your documents.
+    </Section>
+    <Section name="formatstatements">
+      <Title>Format Features</Title>
+Format commands control the structure and appearance of the collection.  They
+affect such things as where buttons appear when a document is shown, and what
+links are displayed by the DateList classifier.  Format commands are not easy
+to develop, and you should read Chapter 2 of the Greenstone Developer's Guide.
+This section discusses the format settings, and how the Librarian Interface
+gives access to them.  Under "Design Sections", click "Format Features".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Formatting
+          </ContentsItem>
+          <ContentsItem>
+            Add format command
+          </ContentsItem>
+          <ContentsItem>
+            Remove format command
+          </ContentsItem>
+          <ContentsItem>
+            Update format command
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Extended formatting options
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+You can apply a format command to anything in the "Choose Feature" pull-down
+list, which includes each classifier and a predefined list of features.  When
+you select a feature, there are two types of control.  Some features are simply
+enabled or disabled, and this is controlled by a checkbox.  Others require a
+format string to be specified.  For these there is a pull-down list ("Affected 
+Component") for selecting which part of the feature the string applies to 
+(if necessary), a text area ("HTML Format String") for entering the string, 
+and a selection of predefined "Variables".  To insert a variable into the 
+current position in the format string, select it from the pull-down list and 
+click "Insert".
+<Break/>
+You can specify a default format for a particular component by selecting the
+blank feature.  This format is then applied to all applicable features unless
+otherwise specified.
+<Break/>
+To add a new format command, fill out the information as explained above and
+click "Add Format".  The new format command appears in the list of "Currently
+Assigned Format Commands".  Only one format command can be assigned to each
+feature/component combination.
+<Break/>
+To remove a format command, select it from the list and click "Remove Format".
+<Break/>
+To change a format command, select it from the list, modify the settings, and
+click "Replace Format".
+<Break/>
+For more information about variables and the feature components, read Chapter 2
+of the Greenstone Developer's Guide.
+      <Anchor name="advanced">Advanced Instructions:</Anchor>
+If the "Allow Extended Options" checkbox is ticked, some advanced formatting options are enabled. The list of features that can be formatted is changed slightly, and more variables are available to be used in the format command, providing greater control over the page layout.
+    </Section>
+    <Section name="translatetext">
+      <Title>Translate Text</Title>
+This section describes the translation view, where you can define
+language-specific text fragments for parts of the collection's interface.
+Under "Design Sections", click "Translate Text".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Add translation
+          </ContentsItem>
+          <ContentsItem>
+            Remove translation
+          </ContentsItem>
+          <ContentsItem>
+            Update translation
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+First choose the an entry from the "Features" list.  The language-specific
+strings associated with this feature appear below.  Use the "Language of
+translation" pull-down list to select the target language, and type the
+translated text into the text area, referring to the "Initial Text Fragment" if
+necessary.  Click "Add Translation" when finished.
+<Break/>
+To remove an existing translation, select it in the "Assigned Translations"
+table and click "Remove Translation".
+<Break/>
+To edit a translation, select it, edit it in the "Translated Text" text
+area, and click "Replace Translation".
+    </Section>
+    <Section name="metadatasets">
+      <Title>Metadata Sets</Title>
+This section explains the metadata set review panel.
+Under "Design Sections", click "Metadata Sets".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Available metadata sets
+          </ContentsItem>
+          <ContentsItem>
+            Adding metadata sets
+          </ContentsItem>
+          <ContentsItem>
+            Editing metadata sets
+          </ContentsItem>
+          <ContentsItem>
+            Removing metadata sets
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+This view is used to review the metadata sets that the collection uses, and the
+elements that are available within each set.  Choose from the list of "Available
+Metadata Sets" in order to see details of their elements.
+<Break/>
+To use another metadata set with the loaded collection, click "Add Metadata Set" and select the metadata set file (.mds) for the new metadata set.
+<Break/>
+Editing metadata sets is done with the Greenstone Editor for Metadata Sets (GEMS). Clicking the "Edit Metadata Set" button provides information on how to run the GEMS.
+<Break/>
+If you no longer need a metadata set, select it and press "Remove Metadata Set" to remove it. If you have assigned any metadata to elements in the removed set you will be asked how to deal with this metadata when you next open the collection.
+    </Section>
+  </Section>
+
+  <Section name="producingthecollection">
+    <Title>Producing Your Collection</Title>
+Having collected the documents for the collection, annotated them with
+metadata, and designed how the collection will appear, you can now produce the
+collection using Greenstone.  This section explains how.
+    <Section name="thecreateview">
+      <Title>The Create View</Title>
+<ObviousSentence>This section explains the Create view used to produce a collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    Building the collection
+	  </ContentsItem>
+          <ContentsItem>
+	    Previewing the collection
+	  </ContentsItem>
+	</ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Message log
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+The Create view is used to create the collection by running Greenstone
+collection-building scripts on the information you have provided.
+Clicking "Build Collection" initiates the collection building process.  The time
+this takes depends on the size of the collection and the number of indexes
+being created (for huge collections it can be hours). A progress bar indicates how much of the process has been completed. To cancel the process at
+any time, click "Cancel Build".
+<Break/>
+<!-- added -->
+Once the collection has successfully built, clicking "Preview Collection" will launch a web browser showing the home page of the collection.
+      <Anchor name="advanced">Advanced Instructions:</Anchor>
+In Expert mode, you can use the "Message Log" entry at the left to review previous attempts to build the collection, whether successful or not. Select the log you want by clicking on the desired date in the "Log History" list.
+    </Section>
+    <Section name="buildsettings">
+      <Title>Import and Build Settings</Title>
+This section explains how to access the various import and build settings.
+For more information of importing and building read Chapter 1 of the Greenstone
+Developer's Guide -- Understanding the collection-building process.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            General settings
+          </ContentsItem>
+          <ContentsItem>
+            Import settings
+          </ContentsItem>
+          <ContentsItem>
+            Build settings
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+Controlling the various settings is done in a similar way to the
+"Configuring Arguments" window described in the <Reference target="plugins">Document Plugins</Reference> section.  Some
+fields require numeric arguments, and you can either type these in or use the
+up and down arrows to increase or decrease the current value (in some cases,
+the interface restricts the range you can enter).  Others are enabled by
+clicking a checkbox (click again to disable).
+    </Section>
+  </Section>
+
+  <Section name="miscellaneous">
+    <Title>Miscellaneous</Title>
+This section describes features of the Librarian Interface that are not associated
+with any particular view.
+    <Section name="preferences">
+      <Title>Preferences</Title>
+This section explains the preferences dialog, accessed by opening "File" -> "Preferences".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>
+	    General
+	  </ContentsItem>
+	  <ContentsItem>
+	    Mode
+	  </ContentsItem>
+          <ContentsItem>
+            Workflow
+          </ContentsItem>
+          <ContentsItem>
+            Connection
+          </ContentsItem>
+          <ContentsItem>
+            Warnings
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+The first "General" option is a text field for entering your e-mail address. This will be used for the "creator" and "maintainer" collection metadata items. The next option is a pull-down list of the languages in which the Librarian Interface can be presented. If you change the dictionary by choosing one from the list, you must
+restart the Librarian Interface in order to load the new language strings from
+the dictionary.
+<Break/>
+If "View Extracted Metadata" is checked, the
+various controls dealing with metadata always show all metadata that has been
+extracted automatically from documents.  Deselecting it hides this metadata
+(although it is still available during collection design, and within the
+final Greenstone collection). If "Show file sizes" is checked, the file size is shown next to each file in the Workspace and Collection file trees in the Gather and Enrich views.
+<Break/>
+The "Mode" panel is used to control the level of detail within the interface. At its lowest setting, "Library Assistant", the design view is disabled, arguments requiring regular expressions are hidden and the collection building produces a minimal log of events. In contrast the highest setting, "Expert", provides access to all of the features of design, including plugin positioning and regular expression arguments, and also allows the full output from the collection building to be recorded in the logs. To change or review modes, click the radio button next to the mode you are interested in. You can quickly review what mode you are in by looking at the Librarian Interface's title bar.
+<Break/>
+The Librarian Interface can support different workflows by determining which of
+the various view tabs are visible.  Use the "Workflow" tab to customise what
+views are available by checking the boxes next to the views that you want to be
+available.  Alternatively, use the pull-down list at the bottom to select
+predetermined configurations.  Closing the preferences dialog establishes these
+workflow settings.  These settings are stored with the collection, not in the
+Librarian Interface configuration file.
+<Break/>
+The "Connection" tab lets you alter the path to the locally-running Greenstone library server, which is used when Previewing collections. It also lets you set proxy information for connecting to the Internet (e.g. when downloading files; see the <Reference target="downloadingfiles">Downloading Files From the Internet</Reference> section for details). Check the box to enable proxy connection and supply details of the proxy host address and port number. The proxy connection is established when you close the Preferences dialog.
+<Break/>
+During the course of a session the Librarian Interface may give warning
+messages which inform you of possibly unforeseen consequences of an action.  You
+can disable the messages by checking the "Do not show this warning again" box.
+You can re-enable warning messages using the "Warnings" tab.  Check the box
+next to warning messages you want to see again.
+    </Section>
+    <Section name="fileassociations">
+      <Title>File Associations</Title>
+The Librarian Interface uses particular application programs to open particular
+file types.  This section explains how to assign and edit these file
+associations.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Add association
+          </ContentsItem>
+          <ContentsItem>
+            Edit association
+          </ContentsItem>
+          <ContentsItem>
+            Remove association
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+To alter file associations open the "File" menu and click "File
+Associations...".
+<Break/>
+To add an association, select the target file extension from the pull-down
+list, or type in a new extension (do not include the ".").  Next either type
+command that launches the desired application in the appropriate field, or
+choose the application from the "Browse" dialog.  "%1" can be used in the launch
+command to insert the name of the file being opened.  Once these are filled out,
+"Add Association" is enabled and can be clicked to add the association.
+<Break/>
+To edit an association, select an existing file extension.  Any existing
+associated command is shown in the launch command field.  Edit it, and then
+click "Replace Association".
+<Break/>
+To remove an association, select an existing file extension and click "Remove Association".
+(The file extension remains in the "For Files Ending" pull-down list.)
+<Break/>
+File associations are stored in the Librarian Interface's main folder, in a file
+called "associations.xml".
+    </Section>
+    <Section name="exportingcollections">
+      <Title>Exporting Collections to CD-ROM</Title>
+      
+This section describes how to export collections to a self-installing 
+Greenstone CD-ROM. 
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            How to export
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Simple Instructions:</Anchor>
+Greenstone can export one or more collections to a self-installing 
+CD-ROM for Windows. To do so, Greenstone's "Export to CD-ROM" package 
+must be installed. This is not included by default, so you may need to 
+modify your installation to include it.
+<Break/>
+To export a collection, open the "File" menu and choose "Export to 
+CD-ROM". A list of Greenstone collections appears; click on any one to 
+see its description. Tick the check boxes of the collections to export. 
+You can enter the CD-ROM's name in the box: this is what will appear in 
+the Start menu when the CD-ROM has been installed. Then click "Export". 
+The process involves copying many files and may take a few minutes.
+<Break/>
+Upon completion, Greenstone will show the name of a folder containing 
+the exported collections. Use a CD writer to copy its contents to a 
+blank CD-ROM.
+    </Section>
+  </Section>
+</Document>
Index: /tags/gsdl-2_61-distribution/gli/help/en/help_index.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/help_index.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/help_index.xml	(revision 10506)
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Document><Section name="introduction"><Title>Introduction</Title><Section name="ofmiceandmenus"><Title>Of Mice and Menus</Title></Section><Section name="howtoavoidthisdocument"><Title>How to Avoid Reading This Document</Title></Section></Section><Section name="startingoff"><Title>Starting Off</Title><Section name="creatingacollection"><Title>Creating a New Collection</Title></Section><Section name="savingacollection"><Title>Saving the Collection</Title></Section><Section name="openingacollection"><Title>Opening an Existing Collection</Title></Section><Section name="deletingcollections"><Title>Deleting Collections</Title></Section></Section><Section name="downloadingfiles"><Title>Downloading Files From the Internet</Title><Section name="themirrorview"><Title>The Download view</Title></Section></Section><Section name="collectingfiles"><Title>Collecting Files for Your Collection</Title><Section name="thegatherview"><Title>The Gather View</Title></Section><Section name="creatingfolders"><Title>Creating Folders</Title></Section><Section name="addingfiles"><Title>Adding Files</Title></Section><Section name="removingfiles"><Title>Removing Files</Title></Section><Section name="filteringthetree"><Title>Filtering the Tree</Title></Section></Section><Section name="enrichingacollection"><Title>Enriching the Collection with Metadata</Title><Section name="theenrichview"><Title>The Enrich View</Title></Section><Section name="selectingmetadatasets"><Title>Selecting Metadata Sets</Title></Section><Section name="appendingmetadata"><Title>Appending New Metadata</Title></Section><Section name="addingpreviouslydefinedmetadata"><Title>Adding Previously Defined Metadata</Title></Section><Section name="updatingmetadata"><Title>Updating Metadata</Title></Section><Section name="removingmetadata"><Title>Removing Metadata</Title></Section><Section name="reviewingmetadata"><Title>Reviewing Assigned Metadata</Title></Section><Section name="importingpreviouslyassignedmetadata"><Title>Importing Previously Assigned Metadata</Title></Section></Section><Section name="designingacollection"><Title>Designing Your Collection's Appearance</Title><Section name="thedesignview"><Title>The Design View</Title></Section><Section name="generalsettings"><Title>General Settings</Title></Section><Section name="plugins"><Title>Document Plugins</Title></Section><Section name="searchtypes"><Title>Search Types</Title></Section><Section name="searchindexes"><Title>Search Indexes</Title></Section><Section name="partitionindexes"><Title>Partition Indexes</Title><Section name="definefilters"><Title>Define Filters</Title></Section><Section name="assignpartitions"><Title>Assign Partitions</Title></Section><Section name="assignlanguages"><Title>Assign Languages</Title></Section></Section><Section name="xcollectionsearching"><Title>Cross-Collection Searching</Title></Section><Section name="classifiers"><Title>Classifiers</Title></Section><Section name="formatstatements"><Title>Format Features</Title></Section><Section name="translatetext"><Title>Translate Text</Title></Section><Section name="metadatasets"><Title>Metadata Sets</Title></Section></Section><Section name="producingthecollection"><Title>Producing Your Collection</Title><Section name="thecreateview"><Title>The Create View</Title></Section><Section name="buildsettings"><Title>Import and Build Settings</Title></Section></Section><Section name="miscellaneous"><Title>Miscellaneous</Title><Section name="preferences"><Title>Preferences</Title></Section><Section name="fileassociations"><Title>File Associations</Title></Section><Section name="exportingcollections"><Title>Exporting Collections to CD-ROM</Title></Section></Section></Document>
Index: /tags/gsdl-2_61-distribution/gli/help/en/howtoavoidthisdocument.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/howtoavoidthisdocument.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/howtoavoidthisdocument.htm	(revision 10506)
@@ -0,0 +1,67 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="howtoavoidthisdocument"><font size="5" face="Verdana"><strong>1.2: How to Avoid Reading This Document</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+Don't read this help text all the way through!  Just read enough to learn
+how to get help when you need it.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Context sensitive help
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Tool tips
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Other documents
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+The "Help" menu item marks what may be the most appropriate help item with a
+little book icon.
+<p></p>
+For many controls, if you station the mouse over them a
+"tool tip" appears that says what they do.
+<p></p>
+Before using the Librarian Interface, first read the Greenstone
+documentation.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/importingpreviouslyassignedmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/importingpreviouslyassignedmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/importingpreviouslyassignedmetadata.htm	(revision 10506)
@@ -0,0 +1,69 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="importingpreviouslyassignedmetadata"><font size="5" face="Verdana"><strong>5.8: Importing Previously Assigned Metadata</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section describes how to import previously assigned metadata: metadata assigned to documents before they were added to the collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            While adding files
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+If metadata in a form recognized by the Librarian Interface has been previously
+assigned to a file -- for example, when you choose documents from an existing
+Greenstone collection -- it is imported automatically when you add the file.
+To do this, the metadata must be mapped to the metadata sets available in the
+collection.
+<p></p>
+The Librarian Interface prompts for the necessary information.  The prompt
+gives brief instructions and then shows the name of the metadata element that
+is being imported, just as it appears in the source file.  This field cannot be
+edited or changed.  Next you choose what metadata set the new element should map
+to, and then the appropriate metadata element in that set.  The system
+automatically selects the closest match, in terms of set and element, for the
+new metadata.
+<p></p>
+Having checked the mapping, you can choose "Add" to add the new metadata
+element to the chosen metadata set.  (This is only enabled if there is no
+element of the same name within the chosen set.) "Replace" maps the new element
+to the one chosen by the user.  Finally, "Ignore" does not import any metadata
+with this element name.  Once you have specified how to import a certain piece of metadata, the mapping
+information is retained for the collection's lifetime.
+<p></p>
+For details on the metadata.xml files which Greenstone uses to store the metadata, see Chapter 2 of the Greenstone
+Developer's Guide -- Getting the most out of your documents.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/introduction.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/introduction.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/introduction.htm	(revision 10506)
@@ -0,0 +1,17 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="introduction"><font size="5" face="Verdana"><strong>1: Introduction</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+The Greenstone Librarian Interface is a tool for collecting and marking up documents, then building digital library collections.  It provides access to the Greenstone Digital Library Software's functionality from a graphical point and click interface.
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/metadatasets.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/metadatasets.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/metadatasets.htm	(revision 10506)
@@ -0,0 +1,74 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="metadatasets"><font size="5" face="Verdana"><strong>6.11: Metadata Sets</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains the metadata set review panel.
+Under "Design Sections", click "Metadata Sets".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Available metadata sets
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Adding metadata sets
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Editing metadata sets
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Removing metadata sets
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+This view is used to review the metadata sets that the collection uses, and the
+elements that are available within each set.  Choose from the list of "Available
+Metadata Sets" in order to see details of their elements.
+<p></p>
+To use another metadata set with the loaded collection, click "Add Metadata Set" and select the metadata set file (.mds) for the new metadata set.
+<p></p>
+Editing metadata sets is done with the Greenstone Editor for Metadata Sets (GEMS). Clicking the "Edit Metadata Set" button provides information on how to run the GEMS.
+<p></p>
+If you no longer need a metadata set, select it and press "Remove Metadata Set" to remove it. If you have assigned any metadata to elements in the removed set you will be asked how to deal with this metadata when you next open the collection.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/miscellaneous.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/miscellaneous.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/miscellaneous.htm	(revision 10506)
@@ -0,0 +1,19 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="miscellaneous"><font size="5" face="Verdana"><strong>8: Miscellaneous</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+This section describes features of the Librarian Interface that are not associated
+with any particular view.
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/ofmiceandmenus.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/ofmiceandmenus.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/ofmiceandmenus.htm	(revision 10506)
@@ -0,0 +1,106 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="ofmiceandmenus"><font size="5" face="Verdana"><strong>1.1: Of Mice and Menus</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section provides basic information about interacting with the Librarian Interface.
+If you are familiar with programs such as Internet Explorer or Microsoft
+Office and are comfortable with mouse clicks and menus, skip to the <a href="howtoavoidthisdocument.htm#howtoavoidthisdocument">next section</a>.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Basic concepts   
+            <tr>
+<td colspan="2"> </td><td colspan="1">
+              Mouse actions
+	    </td>
+</tr>
+            
+<tr>
+<td colspan="2"> </td><td colspan="1">
+              Keyboard
+	    </td>
+</tr>
+          
+</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Exiting the program
+          </td>
+</tr>
+	
+	
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Quick keys
+          </td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+The Librarian Interface follows Microsoft Windows conventions and draws upon
+ordinary knowledge of Windows.
+<p></p>
+Any part of the screen that you interact with, such as a button or text field,
+is called a "control".  At any given time one control, called the "focus", is
+highlighted and responds to the keyboard.  Several controls allow you to select
+parts that are highlighted in dark blue.  Some controls are greyed out to
+indicate that they are disabled.
+<p></p>
+You can move and left- or right-click the mouse in the usual way.  Many
+components also allow you to "drag" them, by clicking and holding the left
+mouse button, move them with the mouse, and "drop" them elsewhere by releasing
+the button.  Potential drop targets alter their appearance when a component
+hovers over them.
+<p></p>
+You can use the keyboard to type into text fields.  Keyboard alternatives are
+available for many controls, indicated by a key name in square brackets -- for
+example, [Tab] alters the focus.  The plus sign shows if other keys must be
+pressed at the same time.
+<p></p>
+Exit the Librarian Interface program by choosing "Exit" from the "File"
+menu.  Your collection will be saved first.
+       <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+To access a menu, hold down [ALT] and press the corresponding letter
+(underlined).  For example, for the "File" menu press [ALT] + [F].  To choose an
+item, press the corresponding key.  For example, while in the File menu
+press [S] to "Save" a collection.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/openingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/openingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/openingacollection.htm	(revision 10506)
@@ -0,0 +1,88 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="openingacollection"><font size="5" face="Verdana"><strong>2.3: Opening an Existing Collection</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section tells you how to open existing collections using the Open
+Collection prompt.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            How to open a collection
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Locked collections
+          </td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Legacy collections
+	  </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+To open an existing collection, choose "Open" from the "File" menu to get the
+Open Collection prompt.  A list of your Greenstone collections appears.
+Select one to see its description, and click "Open" to load it.  If you seek a
+collection that resides outside Greenstone's "collect" folder, click "Browse"
+for a file system browsing dialog.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+In case more than one Greenstone Librarian Interface program is running
+concurrently, the relevant directories are "locked" to prevent interference.
+On opening a collection, a small temporary lock file is created in its
+folder.  Before opening a collection, the Librarian Interface checks to ensure
+that no lock file already exists.  You can tell whether a collection is locked
+by the colour of its icon: green for a normal collection, red for a locked
+one.  However, when the Librarian Interface is exited prematurely the lock file
+is sometimes left in place.  When you open such a collection, the Librarian asks
+if you want to "steal" control of it.  Never steal a collection that someone
+else is currently working on.
+<p></p>
+When you open a collection that the Greenstone Librarian Interface did 
+not create, you will be asked to select a metadata set (or sets).  If 
+none are selected, any existing metadata will be ignored. Otherwise, 
+metadata will be imported just as it is when you drag in files with 
+existing metadata. The process is described in the <a href="importingpreviouslyassignedmetadata.htm#importingpreviouslyassignedmetadata">Importing Previously Assigned Metadata</a> section. 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/partitionindexes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/partitionindexes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/partitionindexes.htm	(revision 10506)
@@ -0,0 +1,26 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="partitionindexes"><font size="5" face="Verdana"><strong>6.6: Partition Indexes</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+Indexes are built on particular text or metadata sources.  The search space can
+be further controlled by partitioning the index, either by language or by a
+predetermined filter.  This section describes how to do this.  Under "Design
+Sections", click "Partition Indexes".
+<p></p>
+The "Partition Indexes" view has three tabs; "Define Filters", "Assign
+Partitions" and "Assign Languages".  To learn more about partitions read about
+subcollections and subindexes in Chapter 2 of the Greenstone Developer's Guide.
+
+      
+      
+      
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/plugins.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/plugins.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/plugins.htm	(revision 10506)
@@ -0,0 +1,113 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="plugins"><font size="5" face="Verdana"><strong>6.3: Document Plugins</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section describes how to configure the document plugins the
+collection uses.  It explains how you specify what
+plugins to use, what parameters to pass to them, and in what order
+they occur.  Under "Design Sections", click "Document Plugins".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Add a plugin
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Remove a plugin
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Configure a plugin
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Change plugin order
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Custom configuration
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+To add a plugin, select it using the "Select plugin to add" pull-down list near the
+bottom and then click "Add Plugin".  A window appears entitled
+"Configuring Arguments"; it is described later.  Once you have configured the
+new plugin, it is added to the end of the "Currently Assigned Plugins" list.
+Note that, except for UnknownPlug, each plugin may only occur once in the list.
+<p></p>
+To remove a plugin, select it in the list and click "Remove Plugin".
+<p></p>
+Plugins are configured by providing arguments.  To alter them, select the
+plugin from the list and click "Configure Plugin" (or double-click
+the plugin). A "Configuring Arguments" dialog appears with various controls for specifying arguments.
+<p></p>
+There are different kinds of controls.  Some are checkboxes, and clicking one
+adds the appropriate option to the plugin.  Others are text strings, with a
+checkbox and a text field.  Click the box to enable the argument, then type
+appropriate text (regular expression, file path etc) in the box.  Others are
+pull-down menus from which you can select from a given set of values.  To learn what an
+argument does, let the mouse hover over its name for a moment and a description
+will appear.
+<p></p>
+When you have changed the configuration, click "OK" to commit the changes and
+close the dialog, or "Cancel" to close the dialog without changing any plugin
+arguments.
+<p></p>
+The plugins in the list are executed in order, and the ordering is sometimes
+important.  Two plugins, ArcPlug and RecPlug, are vital to the collection
+building process, and are fixed in place at the end of the list (with a
+separator line).  To change the ordering of the other ones, select the plugin you want to move
+and click "Move Up" or "Move Down".
+       <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+The Librarian Interface does its best to determine what arguments a plugin
+supports. However, there may be cases where the user wants to specify special arguments, and for this a text field called "Custom Arguments" (at the bottom) is provided. Any text in it is appended verbatim to the end of the plugin
+command.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/preferences.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/preferences.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/preferences.htm	(revision 10506)
@@ -0,0 +1,97 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="preferences"><font size="5" face="Verdana"><strong>8.1: Preferences</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains the preferences dialog, accessed by opening "File" -&gt; "Preferences".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    General
+	  </td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Mode
+	  </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Workflow
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Connection
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Warnings
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+The first "General" option is a text field for entering your e-mail address. This will be used for the "creator" and "maintainer" collection metadata items. The next option is a pull-down list of the languages in which the Librarian Interface can be presented. If you change the dictionary by choosing one from the list, you must
+restart the Librarian Interface in order to load the new language strings from
+the dictionary.
+<p></p>
+If "View Extracted Metadata" is checked, the
+various controls dealing with metadata always show all metadata that has been
+extracted automatically from documents.  Deselecting it hides this metadata
+(although it is still available during collection design, and within the
+final Greenstone collection). If "Show file sizes" is checked, the file size is shown next to each file in the Workspace and Collection file trees in the Gather and Enrich views.
+<p></p>
+The "Mode" panel is used to control the level of detail within the interface. At its lowest setting, "Library Assistant", the design view is disabled, arguments requiring regular expressions are hidden and the collection building produces a minimal log of events. In contrast the highest setting, "Expert", provides access to all of the features of design, including plugin positioning and regular expression arguments, and also allows the full output from the collection building to be recorded in the logs. To change or review modes, click the radio button next to the mode you are interested in. You can quickly review what mode you are in by looking at the Librarian Interface's title bar.
+<p></p>
+The Librarian Interface can support different workflows by determining which of
+the various view tabs are visible.  Use the "Workflow" tab to customise what
+views are available by checking the boxes next to the views that you want to be
+available.  Alternatively, use the pull-down list at the bottom to select
+predetermined configurations.  Closing the preferences dialog establishes these
+workflow settings.  These settings are stored with the collection, not in the
+Librarian Interface configuration file.
+<p></p>
+The "Connection" tab lets you alter the path to the locally-running Greenstone library server, which is used when Previewing collections. It also lets you set proxy information for connecting to the Internet (e.g. when downloading files; see the <a href="downloadingfiles.htm#downloadingfiles">Downloading Files From the Internet</a> section for details). Check the box to enable proxy connection and supply details of the proxy host address and port number. The proxy connection is established when you close the Preferences dialog.
+<p></p>
+During the course of a session the Librarian Interface may give warning
+messages which inform you of possibly unforeseen consequences of an action.  You
+can disable the messages by checking the "Do not show this warning again" box.
+You can re-enable warning messages using the "Warnings" tab.  Check the box
+next to warning messages you want to see again.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/producingthecollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/producingthecollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/producingthecollection.htm	(revision 10506)
@@ -0,0 +1,19 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="producingthecollection"><font size="5" face="Verdana"><strong>7: Producing Your Collection</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+Having collected the documents for the collection, annotated them with
+metadata, and designed how the collection will appear, you can now produce the
+collection using Greenstone.  This section explains how.
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/removingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/removingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/removingfiles.htm	(revision 10506)
@@ -0,0 +1,65 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="removingfiles"><font size="5" face="Verdana"><strong>4.4: Removing Files</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section describes how to remove files and folders from your collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The delete button
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The delete key
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Delete by drag and drop
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+There are several methods for removing files and folders.  You must first
+indicate what items to remove by selecting one or more files and folders as
+described in <a href="thegatherview.htm#thegatherview">The Gather View</a>.
+<p></p>
+Once files have been selected, click the "delete" button to remove them, or
+press the [Delete] key on your keyboard, or drag them from the collection to
+the delete button and drop them there.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/removingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/removingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/removingmetadata.htm	(revision 10506)
@@ -0,0 +1,58 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="removingmetadata"><font size="5" face="Verdana"><strong>5.6: Removing Metadata</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains how to remove metadata from a file.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Removing from files
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Removing from folders or multiple files
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+You remove metadata the same way as you update it.  First select a file from the
+file tree, then use the metadata table to select the metadata. If the metadata has a value assigned, the "Remove" button becomes active.
+Click it to remove the metadata from the specified file.  Other files
+remain unchanged, and the value remains in the Value Tree.
+<p></p>
+Removing metadata from folders or multiple files works the same way.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/reviewingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/reviewingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/reviewingmetadata.htm	(revision 10506)
@@ -0,0 +1,106 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="reviewingmetadata"><font size="5" face="Verdana"><strong>5.7: Reviewing Assigned Metadata</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section describes how to view all metadata assigned to an entire collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The audit table
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Right button menu
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Autofilter
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Sometimes you need to see the metadata assigned to many or all files at once -- for instance,
+to determine how many files are left to work on, or to get some idea of the
+spread of dates.
+<p></p>
+Select the files you wish to examine, then right-click and choose "Assigned Metadata...". A window called
+"All Metadata", dominated by a large table with many columns, appears.  The
+first column shows file names; the rows show all metadata values assigned to
+those files.
+<p></p>
+Drawing the table can take some time if many files are selected.  You can continue to use the Librarian
+Interface while the "All Metadata" window is open.
+<p></p>
+Click "Close" to hide the window.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+You can also view the "All Metadata" table by selecting the files you wish to
+examine, right-clicking, and choosing "Assigned Metadata...".  If a folder has
+been selected, all its child files are included in the table.
+<p></p>
+When it gets too large, you can filter the "All Metadata" table by applying
+filters to the columns.  As new filters are added, only those rows that match
+them remain visible.  To set, modify or clear a filter, click on the "funnel"
+icon at the top of a column.  You are prompted for information about the filter.
+Once a filter is set, the column header changes colour.
+<p></p>
+The prompt has a "Simple" and an "Advanced" tab.  The Simple version filters
+columns so that they only show rows that contain a certain metadata value ("*"
+matches all values).  You can select metadata values from the pull-down list.
+The Advanced version allows different matching operations: must start with,
+does not contain, alphabetically less than and is equal to.  The value to be
+matched can be edited to be any string (including "*"), and you can choose
+whether the matching should be case insensitive.  Finally, you can specify a
+second matching condition that you can use to specify a range of values (by
+selecting AND) or alternative values (by selecting OR).  Below this area is a
+box that allows you to change the sort order (ascending or descending).  Once
+you have finished, click "Set Filter" to apply the new filter to the column.
+Click "Clear Filter" to remove a current filter.  Note that the filter details
+are retained even when the filter is cleared.
+<p></p>
+For example, to sort the "All Metadata" table, choose a column, select the
+default filter setting (a Simple filter on "*"), and choose ascending or
+descending ordering.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/savingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/savingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/savingacollection.htm	(revision 10506)
@@ -0,0 +1,69 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="savingacollection"><font size="5" face="Verdana"><strong>2.2: Saving the Collection</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section describes how to save a collection, and the Save Collection Prompt.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            How to save
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Where the files are saved
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Save your work regularly by opening the "File" menu and choosing "Save".
+Saving a collection is not the same as making it ready for use in Greenstone
+(see <a href="producingthecollection.htm#producingthecollection">Producing Your Collection</a>).
+<p></p>
+The Librarian Interface protects your work by saving it whenever you exit the
+program or load another collection.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+Saved collections are written to a file named for the collection and with file
+extension ".col", located in a folder of the same name within your Greenstone
+installation's "collect" folder.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/searchindexes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/searchindexes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/searchindexes.htm	(revision 10506)
@@ -0,0 +1,89 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="searchindexes"><font size="5" face="Verdana"><strong>6.5: Search Indexes</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+Indexes specify what parts of the collection are searchable.  This section explains how to add and remove indexes, and set a default index.  Under "Design Sections", click "Search Indexes".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Add an index
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Edit an index
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Remove an index
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Set default index
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+To add an index, type a name for it into the "Index Name" field.  Select which
+of the possible information sources to index by clicking the checkboxes beside
+them.  The list shows all the assigned metadata elements, as well the full
+text.  Having selected the data sources, choose the granularity of the index,
+using the "At the level" menu.  Once these details are complete, "Add Index"
+becomes active (unless there is an existing index with the same settings).
+Click it to add the new index.
+<p></p>
+To edit an index, select it and change the index details, then click "Replace Index".
+<p></p>
+To remove an index, select it from the list of assigned indexes and click
+"Remove Index".
+<p></p>
+The default index, the one used on the collection's search page, is tagged with
+"[Default Index]" in the "Assigned Indexes" list.  To set it, select an index
+from the list and click "Set Default".
+<p></p>
+If advanced searching is enabled (via the Search Types view), the index controls are different.  Each index
+is based on just one data source.  There is a new pseudo-data source "allfields" which provides searching across all specified indexes at once.  Levels are not
+assigned to a specific index, but apply across all indexes: thus indexes and
+levels are added separately.  Indexes are removed in the same way as above, but
+the default index can no longer be set -- it is simply the
+first index assigned.
+<p></p>
+To create indexes on all sources, click the "Add All" button. The name of each index will default to the source name. To change the name, select an index, change its details, and click "Replace Index".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/searchtypes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/searchtypes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/searchtypes.htm	(revision 10506)
@@ -0,0 +1,82 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="searchtypes"><font size="5" face="Verdana"><strong>6.4: Search Types</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains how to modify a new design feature in Greenstone, Search Types, which allow fielded searching.  Under "Design Sections", click "Search Types".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            What enabling advanced searches means
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Adding a new search type
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Removing a search type
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Changing the order of search types
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+When you enter the Search Types view, first check "Enable Advanced
+Searches", which activates the other controls.  This migrates the collection to
+Greenstone 2.4 format, which supports fielded searching, and means that (a)
+the index design is different (explained in the <a href="searchindexes.htm#searchindexes">Search Indexes</a> section),
+(b) there are more text fragments to translate (see <a href="translatetext.htm#translatetext">Translation</a>), and (c) the collection will not be usable under older Greenstone
+installations.  If you later uncheck this field, most of your collection will
+be migrated back to Greenstone 2.39.  However the Librarian Interface cannot
+convert the new index specifications into older ones, so you will have to
+re-enter them manually.
+<p></p>
+To add a search type, select it from the "Search Types" list and click "Add Search Type".  Each type can only appear in the list once.
+<p></p>
+To remove a search type, select it from the "Currently Assigned Search Types"
+list and click "Remove Search Type".  The list must contain at least
+one search type.
+<p></p>
+To change to order of a search type, select it from the list and click "Move
+Up" or "Move Down". The first one will be the default.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/selectingmetadatasets.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/selectingmetadatasets.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/selectingmetadatasets.htm	(revision 10506)
@@ -0,0 +1,61 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="selectingmetadatasets"><font size="5" face="Verdana"><strong>5.2: Selecting Metadata Sets</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains how to specify metadata elements and how to add metadata sets to your collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            What is a metadata set?
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Controlling the metadata sets used
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Sets of predefined metadata elements are known as "metadata sets".  An example
+is the Dublin Core metadata set.  When you add a metadata set to your
+collection, its elements become available for selection.  You can have more than
+one set; to prevent name clashes a short identifier that identifies the
+metadata set is pre-pended to the element name.  For instance the Dublin Core
+element Creator becomes "dc.Creator".  Metadata sets are stored in the
+Librarian Interface's metadata folder and have the suffix ".mds".
+<p></p>
+To control the metadata sets used in a collection, use the "Metadata Sets" entry on the Design view.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/startingoff.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/startingoff.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/startingoff.htm	(revision 10506)
@@ -0,0 +1,19 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="startingoff"><font size="5" face="Verdana"><strong>2: Starting Off</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    This section covers how to create, load, save and delete collections.
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/thecreateview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/thecreateview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/thecreateview.htm	(revision 10506)
@@ -0,0 +1,76 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thecreateview"><font size="5" face="Verdana"><strong>7.1: The Create View</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains the Create view used to produce a collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Building the collection
+	  </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Previewing the collection
+	  </td>
+</tr>
+	
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Message log
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+The Create view is used to create the collection by running Greenstone
+collection-building scripts on the information you have provided.
+Clicking "Build Collection" initiates the collection building process.  The time
+this takes depends on the size of the collection and the number of indexes
+being created (for huge collections it can be hours). A progress bar indicates how much of the process has been completed. To cancel the process at
+any time, click "Cancel Build".
+<p></p>
+
+Once the collection has successfully built, clicking "Preview Collection" will launch a web browser showing the home page of the collection.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+In Expert mode, you can use the "Message Log" entry at the left to review previous attempts to build the collection, whether successful or not. Select the log you want by clicking on the desired date in the "Log History" list.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/thedesignview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/thedesignview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/thedesignview.htm	(revision 10506)
@@ -0,0 +1,57 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thedesignview"><font size="5" face="Verdana"><strong>6.1: The Design View</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section introduces you to the design view and explains how to navigate
+between the various views within this pane.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Choosing a design section
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+With the Librarian Interface, you can configure how the collection appears to
+the user.  The configuration options are divided into different sections, each
+associated with a particular stage of navigating or presenting information.
+<p></p>
+On the left is a list of different views, and on the right are the controls
+associated with the current one.  To change to a different view, click its name
+in the list.
+<p></p>
+To understand the stages and terms involved in designing a collection, first
+read Chapters 1 and 2 of the Greenstone Developer's Guide.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/theenrichview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/theenrichview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/theenrichview.htm	(revision 10506)
@@ -0,0 +1,103 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="theenrichview"><font size="5" face="Verdana"><strong>5.1: The Enrich View</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section describes how to input and edit metadata using the Enrich view.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The collection tree
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The metadata editing controls
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The value tree
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The metadata table
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Use the Enrich view to assign metadata to the documents in the collection.
+Metadata is data about data -- typically title, author, creation date, and so
+on.  Each metadata item has two parts: "element" tells what kind of item it is
+(such as author), and "value" gives the value of that metadata element (such as
+the author's name).
+<p></p>
+On the left of the "Enrich" view is the Collection Tree. To the right is the Metadata Table, which shows metadata for any selected files or folders in the Collection Tree.  Columns are named in
+grey at the top, and can be resized by dragging the separating line. Clicking any row transfers its details to the metadata editing controls below. If several files are selected, black text indicates that the value is common to all of the
+selected files, while grey text indicates that it is not.  Black values may be
+updated or removed, while grey ones can be removed from those that have it, or
+appended to the others.
+<p></p>
+A folder icon may appear beside some metadata entries.  This indicates that the
+values are inherited from a parent (or ancestor) folder.  Inherited metadata
+cannot be edited or removed, only appended to or overwritten.  Click on the
+folder icon to go immediately to the folder where the metadata is assigned.
+<p></p>
+The metadata editing controls at the lower right appear only when a file is selected from the tree and a row is selected from the table. Use them to update, append,
+and remove the metadata value.  The value field is for entering or editing the
+metadata value.  Beside it is a button labelled "..." which, when clicked,
+opens a larger editing box.  In the buttons below, "Append" assigns the value as
+new metadata and adds it to any existing values for the selected element,
+"Replace" overwrites the selected existing value with the new one, and "Remove" clears
+the selected value.  Underneath, labelled "All Previous Values", is the "Value
+Tree".
+<p></p>
+The Value Tree expands and collapses.  Usually it is a list that shows all
+values entered previously for the selected element.  Clicking an entry
+automatically places it into the value field.  Conversely, typing in the text
+field selects the Value Tree entry that starts with the characters you have
+typed.  Pressing [Tab] auto-completes the typing with the selected value.
+<p></p>
+Metadata values can be organised into a hierarchy. This is shown in the Value Tree using folders for internal levels. Hierarchical values can be entered using the character "|" to separate the levels.  For
+example, "Cards|Red|Diamonds|Seven" might be used in a hierarchy that represents a pack of playing cards. This enables values to be grouped together. Groups can also be assigned as metadata to files.
+<p></p>
+Greenstone extracts metadata automatically from documents into a metadata set
+whose elements are prefixed by "ex.".  This has no value tree and cannot be
+edited, so the edit controls are hidden if such an entry is selected.  The
+"..." button still serves to expand the value, but the text cannot be edited.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/thegatherview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/thegatherview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/thegatherview.htm	(revision 10506)
@@ -0,0 +1,120 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thegatherview"><font size="5" face="Verdana"><strong>4.1: The Gather View</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section introduces the Gather area that you use to select what files
+to include in the collection you are building.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            How to view the gather screen
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The file trees
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The status area
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Control buttons
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Selection methods
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Special folder mapping
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+The Librarian Interface starts with the Gather view.  To return to this view
+later, click the "Gather" tab directly below the menu bar.
+<p></p>
+The two large areas titled "Workspace" and "Collection" are used to move files
+into your collection.  They contain "file trees", graphical structures that
+represent files and folders.
+<p></p>
+Select an item in the tree by clicking it.  (There are other ways; see below.)
+Double-click a folder, or single-click the switch symbol beside it, to expand (or collapse)
+its contents.  Double-click a file to open it using its associated application
+program (see <a href="fileassociations.htm#fileassociations">File Associations</a>).
+<p></p>
+The Workspace file tree shows the sources of data available to the Librarian Interface -- the local file system (including disk and CD-ROM drives), the contents of existing Greenstone collections, and the cache of downloaded files if Web mirroring is enabled. You can copy and view these files but you cannot move, delete, or edit them, with the exception of the downloaded files, which can be deleted.  Navigate this space to find the files you want to include in the collection.
+<p></p>
+The Collection file tree represents the contents of the collection so
+far.  Initially, it is empty.
+<p></p>
+You can resize the spaces by mousing over the grey bar that separates the trees
+(the shape of the pointer changes) and dragging.
+<p></p>
+At the bottom of the window is a status area that shows the progress of actions involving files (copying, moving and deleting). These can take some time to complete. The "Stop" button stops any action that is currently in progress. 
+<p></p>
+Two large buttons occupy the lower right corner of the screen. "New Folder", with a picture
+of a folder, creates new folders (see <a href="creatingfolders.htm#creatingfolders">Creating folders</a>). 
+"Delete", with a garbage can, removes files. Clicking the Delete button will remove any selected files from the Collection file tree. Alternatively, files can be deleted by dragging them onto the Delete button. 
+       <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+To select several sequential items, select the first and then hold down [Shift]
+and click on the last -- the selection will encompass all intervening
+items.  Select non-sequential files by holding down [Ctrl] while clicking.  Use
+these two methods together to select groups of non-adjacent items.
+<p></p>
+Certain folders -- such as the one containing your own web pages -- sometimes
+have special significance.  The Librarian Interface can map such folders to 
+the first level of the file tree.  To do this, right-click the desired
+folder.  Select "Create Shortcut", and enter a name for the folder.  To remove an item,
+right-click the mapped folder and select "Remove Shortcut".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/themirrorview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/themirrorview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/themirrorview.htm	(revision 10506)
@@ -0,0 +1,80 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="themirrorview"><font size="5" face="Verdana"><strong>3.1: The Download view</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section describes how to configure a download task and control the downloading process.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The workspace tree
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Download configuration
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            The download list
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Advanced Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Enabling web proxies
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+Access the "Download" view by clicking its tab. The top half of the screen shows the downloading controls. The bottom half is initially empty, but will show a list of pending and completed downloading jobs. 
+<p></p>
+Files are downloaded into a folder in the workspace called "Downloaded Files" (only present when mirroring is enabled), and can be used in all collections built with the Librarian Interface.  Files in this area are named by their full web URL. A new folder is created for each host, followed by others for each part of the path. This ensures that each file is distinct.
+<p></p>
+Use the first of the download configuration controls, "Source URL", to enter the URL of a target resource. Use the "Download Depth" control to limit how many  hyperlinks to follow when downloading: Set this to 0 to download a single web page; set it to 1 to download a page and all the pages it points to. The depth limit is ignored when downloading media other than html pages. Next, there are several checkbox controls which can be set to turn on the specified feature for a specific download. Once the configuration is set up, click "Download" to start the new download job. There are two other button controls: "Preferences", which links to the connection section of the Preferences where proxy settings can be edited; and "Clear Cache", which deletes all previously downloaded files.
+<p></p>
+The download list has an entry for each web page download.  Each entry has a text region that gives details of the task along with a progress bar showing current activity. Three buttons appear to the left of each entry. "Pause" is used for pausing a currently downloading task. "View Log" opens a window showing the download log file. "Close" terminates the download and removes the task from the list.  
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Advanced Instructions:</a>
+<p style="text-align:justify"></p>
+The <a href="preferences.htm#preferences">Preferences section</a> describes how to establish an Internet connection via a proxy.  If authentication is needed, the proxy server prompts for identification and password.  The Librarian Interface does not store passwords between sessions.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/translatetext.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/translatetext.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/translatetext.htm	(revision 10506)
@@ -0,0 +1,71 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="translatetext"><font size="5" face="Verdana"><strong>6.10: Translate Text</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section describes the translation view, where you can define
+language-specific text fragments for parts of the collection's interface.
+Under "Design Sections", click "Translate Text".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Add translation
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Remove translation
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Update translation
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+First choose the an entry from the "Features" list.  The language-specific
+strings associated with this feature appear below.  Use the "Language of
+translation" pull-down list to select the target language, and type the
+translated text into the text area, referring to the "Initial Text Fragment" if
+necessary.  Click "Add Translation" when finished.
+<p></p>
+To remove an existing translation, select it in the "Assigned Translations"
+table and click "Remove Translation".
+<p></p>
+To edit a translation, select it, edit it in the "Translated Text" text
+area, and click "Replace Translation".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/updatingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/updatingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/updatingmetadata.htm	(revision 10506)
@@ -0,0 +1,61 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="updatingmetadata"><font size="5" face="Verdana"><strong>5.5: Updating Metadata</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+This section explains how to update the metadata assigned to a file.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Updating files
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Updating folders or multiple files
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+To update the value of a piece of metadata, first choose the file to which that
+value applies, and then the metadata element whose value you want to change.
+Your selection appears in the metadata edit controls.  Edit the value field and
+click "Replace" to alter the metadata.
+<p></p>
+The process is the same when updating a folder with child folders or multiple files, but you can only update metadata that is common to all files/folders selected.
+<p></p>
+The value tree shows all previous values, not just those currently assigned.
+Thus the value you have replaced will remain in the value tree.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/en/xcollectionsearching.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/en/xcollectionsearching.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/en/xcollectionsearching.htm	(revision 10506)
@@ -0,0 +1,55 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="xcollectionsearching"><font size="5" face="Verdana"><strong>6.7: Cross-Collection Searching</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+Greenstone can search across several different collections as though they were
+one.  This is done by creating a "super-collection" that comprises the
+individual collections.  Under "Design Sections", click "Cross-Collection Search".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Simple Instructions:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Selecting a collection
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Simple Instructions:</a>
+<p style="text-align:justify"></p>
+The Cross-Collection Search view shows a checklist of available collections.  The
+current collection is ticked and cannot be deselected.  To add another
+collection to be searched in parallel, click it in the list (click again to
+remove it).  If only one collection is selected, there is no cross-collection
+searching.
+<p></p>
+For further details, see Chapter 1 of the Greenstone Developer's Guide.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/addingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/addingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/addingfiles.htm	(revision 10506)
@@ -0,0 +1,66 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="addingfiles"><font size="5" face="Verdana"><strong>4.3: A&ntilde;adiendo archivos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n muestra la forma de a&ntilde;adir archivos a su colecci&oacute;n.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Arrastrando un archivo</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Varios archivos</td>
+</tr>
+        
+	
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Metadatos existentes</td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Los archivos se pueden copiar arrastr&aacute;ndolos y coloc&aacute;ndolos en una colecci&oacute;n. El cursor se convierte en un fantasma del elemento seleccionado (o, si se ha seleccionado m&aacute;s de uno, del n&uacute;mero de ellos). Coloque la selecci&oacute;n en la estructura de directorios y subdirectorios de la colecci&oacute;n para copiar ah&iacute; los archivos (si la fuente son los archivos del &aacute;rea de trabajo) o mu&eacute;valos de lugar dentro de la misma colecci&oacute;n (si la fuente son los archivos de la colecci&oacute;n).
+      <p></p>
+      Cuando se copien varios archivos en una carpeta todos estar&aacute;n al mismo nivel, sin importar la estructura de las carpetas en las que se encontraban originalmente. Cuando se copie un segundo archivo con el mismo nombre en la misma carpeta se le preguntar&aacute; si desea reemplazar el archivo existente. Si la respuesta es "No" entonces el archivo no se copiar&aacute;, pero los dem&aacute;s s&iacute;. Para cancelar las acciones restantes de copiado haga click en el bot&oacute;n "Detener".
+      <p></p>
+      &Uacute;nicamente se mover&aacute;n los elementos "de m&aacute;s alto nivel" en una selecci&oacute;n. Una carpeta est&aacute; a un nivel m&aacute;s alto que los elementos que se encuentran en su interior, por lo que no se podr&aacute;n seleccionar los archivos de una carpeta y la carpeta al mismo tiempo.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      Cuando se a&ntilde;ada un archivo, la Interfaz de Bibliotecario buscar&aacute; a trav&eacute;s de las carpetas fuente los archivos auxiliares que contienen los metadatos asignados previamente a dicho archivo y, si encuentra alguno, empezar&aacute; a importar estos metadatos. Conforme la operaci&oacute;n siga adelante se le pedir&aacute; (quiz&aacute; varias veces) que proporcione informaci&oacute;n adicional para conciliar los metadatos importados con los conjuntos de metadatos de su colecci&oacute;n. Este proceso incluye muchos avisos diferentes, los cuales se describen en la secci&oacute;n <a href="importingpreviouslyassignedmetadata.htm#importingpreviouslyassignedmetadata">Importando metadatos previamente asignados</a>. Para obtener una explicaci&oacute;n m&aacute;s detallada sobre la forma de asociar metadatos a los archivos lea el Cap&iacute;tulo 2 de la Gu&iacute;a del Programador de Greenstone: Obteniendo el m&aacute;ximo beneficio de sus documentos.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/addingpreviouslydefinedmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/addingpreviouslydefinedmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/addingpreviouslydefinedmetadata.htm	(revision 10506)
@@ -0,0 +1,51 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="addingpreviouslydefinedmetadata"><font size="5" face="Verdana"><strong>5.4: A&ntilde;adiendo Metadatos Previamente Definidos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica la forma de a&ntilde;adir metadatos con valores que ya est&eacute;n presentes en la estructura de valores.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adiendo metadatos a archivos</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2"> A&ntilde;adiendo metadatos a carpetas o a varios archivos juntos</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Para a&ntilde;adir metadatos con un valor existente, seleccione primero el archivo y a continuaci&oacute;n el valor requerido de la estructura de valores, expandiendo las carpetas tanto como sea necesario. El valor de la entrada seleccionada aparecer&aacute; autom&aacute;ticamente en el campo de texto (otra alternativa es utilizar las funciones de selecci&oacute;n autom&aacute;tica y completamiento autom&aacute;tico de la estructura de valores). Haga click en "Agregar" para a&ntilde;adir el metadato al archivo seleccionado.
+      <p></p>
+      El proceso de a&ntilde;adir metadatos con valores existentes a carpetas o a varios archivos juntos es exactamente igual.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/appendingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/appendingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/appendingmetadata.htm	(revision 10506)
@@ -0,0 +1,70 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="appendingmetadata"><font size="5" face="Verdana"><strong>5.3: Agregando nuevos metadatos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica la forma de a&ntilde;adir metadatos y valores a los archivos y c&oacute;mo darle nuevos valores a los elementos de los metadatos.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adiendo metadatos a los archivos</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2"> A&ntilde;adiendo metadatos a carpetas o a varios archivos juntos</td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Jerarqu&iacute;as y edici&oacute;n de valores</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Ahora a&ntilde;adiremos un &iacute;tem de metadato -- tanto un elemento como un valor -- a un archivo. Primero, seleccione el archivo en la estructura de directorios y subdirectorios de la colecci&oacute;n que se encuentra a la izquierda. Esto hace que cualquier metadato asignado previamente a este archivo aparezca en la tabla de la derecha.
+      <p></p>
+      A continuaci&oacute;n, seleccione el elemento de metadato que desea a&ntilde;adir haciendo click en la fila correspondiente de la tabla.
+      <p></p>
+      Escriba el valor en el campo de valores. No use el car&aacute;cter "|", ya que &eacute;ste se utiliza para construir jerarqu&iacute;as. Una vez que haya terminado haga click en "Agregar" para a&ntilde;adir el nuevo valor como metadato del archivo seleccionado. El valor aparecer&aacute; inmediatamente en la tabla de metadatos.
+      <p></p>
+      Tambi&eacute;n se pueden a&ntilde;adir metadatos a una carpeta o a varios archivos seleccionados al mismo tiempo. Estos metadatos se a&ntilde;adir&aacute; a todos los archivos que forman parte de la carpeta o de la selecci&oacute;n, as&iacute; como a las subcarpetas. Recuerde que si usted asigna metadatos a una carpeta, todos los archivos nuevos que se encuentren en ella heredar&aacute;n autom&aacute;ticamente los valores de la carpeta.
+      <p></p>
+      Si usted eligi&oacute; un metadato que ya aparece en algunos de los archivos seleccionados y hace click en "Agregar", el metadato se a&ntilde;adir&aacute; a los dem&aacute;s archivos de la selecci&oacute;n.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      Usted tambi&eacute;n puede darle estructura a los valores de los metadatos por medio de rutas, tal como se describe en la secci&oacute;n de <a href="theenrichview.htm#theenrichview">Asignaci&oacute;n de metadatos</a>.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/assignlanguages.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/assignlanguages.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/assignlanguages.htm	(revision 10506)
@@ -0,0 +1,67 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="assignlanguages"><font size="5" face="Verdana"><strong>6.6.3: Asignar idiomas</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+	Esta secci&oacute;n describe la forma de limitar los &iacute;ndices de b&uacute;squeda a ciertos idiomas. Esto se hace generando una partici&oacute;n por medio de la pesta&ntilde;a "Asignar idiomas" que se encuentra en la pantalla "Particionar &iacute;ndices".
+	<p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+	  
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">Controles de idioma</td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adir idioma</td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminar idioma</td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">Predeterminar un idioma por omisi&oacute;n</td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">Borrar el idioma predeterminado</td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+	
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+	Para a&ntilde;adir un nuevo idioma use la pesta&ntilde;a "Asignar idiomas" a fin de construirle un &iacute;ndice. Seleccione el idioma en la lista descendente "Idioma que se va a a&ntilde;adir" y haga click en "A&ntilde;adir idioma".
+	<p></p>
+	Para quitar un idioma, esc&oacute;jalo de la lista "Selecci&oacute;n de idiomas" y haga click en "Eliminar idioma".
+	<p></p>
+	Para establecer un idioma por omisi&oacute;n, selecci&oacute;nelo de la lista y haga click en "Predeterminar".
+	<p></p>
+	Para borrar el idioma predeterminado haga click en "Borrar el valor por omisi&oacute;n".
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/assignpartitions.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/assignpartitions.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/assignpartitions.htm	(revision 10506)
@@ -0,0 +1,63 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="assignpartitions"><font size="5" face="Verdana"><strong>6.6.2: Asignar particiones</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+	Esta secci&oacute;n explica la forma de asignar un filtro de partici&oacute;n definido anteriormente.
+	<p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+	  
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adir una partici&oacute;n</td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminar una partici&oacute;n</td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">Predeterminar una partici&oacute;n por omisi&oacute;n</td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">Borrar la partici&oacute;n predeterminada</td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+	
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+	Una vez que haya definido el filtro de una subcolecci&oacute;n, utilice la pesta&ntilde;a "Asignar particiones" para construir los &iacute;ndices del filtro (o de un grupo de filtros). Seleccione el filtro o los filtros que desee de la lista "Filtros definidos para la subcolecci&oacute;n", ingrese un nombre para la partici&oacute;n en el campo "Nombre de la partici&oacute;n" y haga click en "A&ntilde;adir partici&oacute;n".
+	<p></p>
+	Para quitar una partici&oacute;n de la lista, selecci&oacute;nela y haga click en "Eliminar partici&oacute;n".
+	<p></p>
+	Para hacer que una partici&oacute;n determinada sea el valor por omisi&oacute;n, selecci&oacute;nela de la lista y haga click en "Predeterminar".
+	<p></p>
+	Para borrar la partici&oacute;n predeterminada haga click en "Borrar el valor por omisi&oacute;n".
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/buildsettings.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/buildsettings.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/buildsettings.htm	(revision 10506)
@@ -0,0 +1,53 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="buildsettings"><font size="5" face="Verdana"><strong>7.2: Controles de importaci&oacute;n y construcci&oacute;n</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica la forma de tener acceso a los diferentes controles de importaci&oacute;n y construcci&oacute;n. Para mayor informaci&oacute;n lea el Cap&iacute;tulo 1 de la Gu&iacute;a del Programador de Greenstone: Comprendiendo el proceso de creaci&oacute;n de una colecci&oacute;n.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Controles generales</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Controles de importaci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Controles de construcci&oacute;n</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      La forma de controlar los diferentes ajustes es similar a la de la ventana "Argumentos de configuraci&oacute;n" que se describe en la secci&oacute;n de <a href="plugins.htm#plugins">Plugins</a>. Algunos campos requerir&aacute;n argumentos num&eacute;ricos y usted puede escribirlos directamente en el campo o usar las flechas que se encuentran a un lado para aumentar o disminuir el n&uacute;mero (en algunos casos la interfaz limita el rango). Otros se activan (y desactivan) haciendo click en los recuadros correspondientes.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/classifiers.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/classifiers.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/classifiers.htm	(revision 10506)
@@ -0,0 +1,69 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="classifiers"><font size="5" face="Verdana"><strong>6.8: Clasificadores</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica la forma de asignar "clasificadores" a una colecci&oacute;n, los cuales se usan para navegar y buscar en ella. En la parte de "Secciones de dise&ntilde;o" haga click en "Clasificadores de exploraci&oacute;n".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Selecci&oacute;n y configuraci&oacute;n de un clasificador</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adir un clasificador</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminar un clasificador</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Configurar un clasificador</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Cambiar el orden de los clasificadores</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Para a&ntilde;adir un clasificador, esc&oacute;jalo por medio de la lista descendente "Seleccione el clasificador que se va a a&ntilde;adir" en la parte inferior de la pantalla y haga click en "A&ntilde;adir el clasificador especificado". Con esto aparecer&aacute; una ventana titulada "Argumentos de configuraci&oacute;n". Las instrucciones para este cuadro de di&aacute;logo son exactamente las mismas que para los plugins (vea la secci&oacute;n <a href="plugins.htm#plugins">Plugins</a>). Una vez que haya configurado el nuevo clasificador, &eacute;ste se a&ntilde;adir&aacute; al final de la lista de "Clasificadores asignados actualmente".
+      <p></p>
+      Para quitar un clasificador de la lista, selecci&oacute;nelo y haga click en "Eliminar el clasificador seleccionado".
+      <p></p>
+      Para cambiar los argumentos de un clasificador, selecci&oacute;nelo de la lista y haga click en "Configurar el clasificador seleccionado" o doble click en el nombre del clasificador.
+      <p></p>
+      El orden de los clasificadores en la barra de navegaci&oacute;n de la colecci&oacute;n se refleja aqu&iacute;. Para cambiarlo, seleccione el clasificador que desea mover y haga click en "Mover arriba" o "Mover abajo".
+      <p></p>
+      Para mayor informaci&oacute;n sobre los clasificadores, lea el Cap&iacute;tulo 2 de la Gu&iacute;a del Programador de Greenstone: Obteniendo el m&aacute;ximo beneficio de sus documentos.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/collectingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/collectingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/collectingfiles.htm	(revision 10506)
@@ -0,0 +1,20 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="collectingfiles"><font size="5" face="Verdana"><strong>4: Reuniendo archivos para su colecci&oacute;n</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Una vez que usted tiene una nueva colecci&oacute;n necesita meter algunos archivos en ella. Estos pueden venir desde la estructura de archivos de su computadora o de otras colecciones Greenstone. Algunos incluso ya pueden tener metadatos. Esta secci&oacute;n describe la forma de importar archivos.
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/creatingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/creatingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/creatingacollection.htm	(revision 10506)
@@ -0,0 +1,88 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="creatingacollection"><font size="5" face="Verdana"><strong>2.1: Creando una nueva colecci&oacute;n</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+       Esta secci&oacute;n describe la forma de crear una nueva colecci&oacute;n.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Aviso de la nueva colecci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">T&iacute;tulo de la colecci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Conjuntos de metadatos por omisi&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Descripci&oacute;n de la colecci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Crear una nueva colecci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Cancelar la nueva colecci&oacute;n</td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Teclas de m&eacute;todo abreviado</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Para crear una nueva colecci&oacute;n abra el men&uacute; "Archivo" y elija la opci&oacute;n "Nueva". Deber&aacute;n llenarse varios campos, aunque en caso de que lo requiera usted podr&aacute; cambiar despu&eacute;s sus valores en la pantalla de dise&ntilde;o.
+      <p></p>
+      El "T&iacute;tulo de la colecci&oacute;n" es el texto que aparece en la parte superior de la p&aacute;gina principal de su colecci&oacute;n. Puede tener la longitud  que usted quiera.
+      <p></p>
+      La "Descripci&oacute;n del contenido" deber&aacute; describir tan detalladamente como sea posible de lo que se trata la colecci&oacute;n. Utilice la tecla [Enter] o [Intro] para dividirla en p&aacute;rrafos.
+      <p></p>
+      Finalmente deber&aacute; especificar si desea que la nueva colecci&oacute;n tenga la misma apariencia y conjunto de metadatos que una colecci&oacute;n existente o si desea iniciar una "Nueva Colecci&oacute;n" por omisi&oacute;n.
+      <p></p>
+      Haga click en "Aceptar" para crear la colecci&oacute;n. Si usted escogi&oacute; "Nueva Colecci&oacute;n" se le pedir&aacute; que elija el conjunto de metadatos que usar&aacute; en ella.  Puede elegir m&aacute;s de uno y tambi&eacute;n puede a&ntilde;adir otros m&aacute;s adelante.
+      <p></p>
+      Si hace click en "Cancelar" regresar&aacute; inmediatamente a la pantalla principal.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      Los botones, al igual que los men&uacute;s, tienen una letra subrayada. Para seleccionar un bot&oacute;n oprima la tecla [ALT] y la letra que est&aacute; subrayada al mismo tiempo.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/creatingfolders.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/creatingfolders.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/creatingfolders.htm	(revision 10506)
@@ -0,0 +1,53 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="creatingfolders"><font size="5" face="Verdana"><strong>4.2: Creando carpetas</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n muestra la forma de crear nuevas carpetas.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">El bot&oacute;n de nueva carpeta</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">El men&uacute; del bot&oacute;n derecho del mouse</td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Utilice las carpetas que se encuentran en la estructura de directorios y subdirectorios de la colecci&oacute;n para agrupar archivos y hacer que sean m&aacute;s f&aacute;ciles de encontrar. Las carpetas pueden contener a su vez otras subcarpetas. No hay pr&aacute;cticamente ning&uacute;n l&iacute;mite en cuanto al n&uacute;mero de carpetas que se pueden tener o qu&eacute; tan profundamente anidadas puedan estar.
+      <p></p>
+      Para crear una nueva carpeta, una opci&oacute;n es seleccionar una carpeta existente en la estructura de directorios y subdirectorios de la colecci&oacute;n y hacer click en el bot&oacute;n "Nueva carpeta". La nueva carpeta aparecer&aacute; dentro de la que se seleccion&oacute; primero o en el nivel superior si no se seleccion&oacute; ninguna. Se le pedir&aacute; que le d&eacute; un nombre a la carpeta (el valor por omisi&oacute;n es "Nueva carpeta").
+      <p></p>
+      Tambi&eacute;n se pueden crear nuevas carpetas haciendo click sobre una carpeta con el bot&oacute;n derecho del mouse,  eligiendo la opci&oacute;n "Nueva carpeta" y continuando tal como se describe arriba.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/definefilters.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/definefilters.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/definefilters.htm	(revision 10506)
@@ -0,0 +1,59 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="definefilters"><font size="5" face="Verdana"><strong>6.6.1: Definir filtros</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+        Esta secci&oacute;n explica la forma de definir un filtro de partici&oacute;n.
+	<p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+	  
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adir un filtro</td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminar un filtro</td>
+</tr>
+	    
+<tr>
+<td colspan="1"> </td><td colspan="2">Actualizar un filtro</td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+	
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+	Los filtros le permiten agrupar en una subcolecci&oacute;n todos los documentos de un &iacute;ndice para los cuales un valor de metadato sigue un patr&oacute;n definido.
+	<p></p>
+	Para crear un filtro haga click en la pesta&ntilde;a "Definir filtros" y escriba el nombre del nuevo filtro en el campo titulado "Nombre del filtro de la subcolecci&oacute;n". A continuaci&oacute;n elija un atributo del documento con el cual se va a contrastar, ya sea un elemento de metadato o el nombre del archivo en cuesti&oacute;n. Ingrese una expresi&oacute;n regular que se utilizar&aacute; durante la contrastaci&oacute;n. Usted puede variar libremente entre "Incluir" documentos que concuerden con el filtro o "Excluirlos". Por &uacute;ltimo, usted tambi&eacute;n puede especificar cualquiera de los indicadores est&aacute;ndar de expresiones regulares PERL para usarlos al momento de contrastar (p. ej. "i" para concordancias que no tomen en cuenta el caso). Haga click en "A&ntilde;adir filtro" para a&ntilde;adir el filtro a la lista de "Filtros definidos para la subcolecci&oacute;n".
+	<p></p>
+	Para quitar un filtro de la lista, selecci&oacute;nelo y haga click en "Eliminar filtro".
+	<p></p>
+	Para modificar un filtro, selecci&oacute;nelo de la lista, cambie cualquiera de los valores que aparecen en los controles de edici&oacute;n y haga click en "Reemplazar filtro" para guardar los cambios.
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/deletingcollections.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/deletingcollections.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/deletingcollections.htm	(revision 10506)
@@ -0,0 +1,47 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="deletingcollections"><font size="5" face="Verdana"><strong>2.4: Borrando colecciones</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica como borrar definitivamente colecciones de su instalaci&oacute;n de Greenstone.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            C&oacute;mo borrar colecciones
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Para borrar definitivamente colecciones de su instalaci&oacute;n de Greenstone, elija "Borrar&hellip;" del men&uacute; "Archivo". Aparece una lista de sus colecciones. Seleccione una para ver su descripci&oacute;n, marque la casilla situada en la parte inferior del di&aacute;logo, y pulse "Borrar" para borrar la colecci&oacute;n. Esta acci&oacute;n es irreversible, por lo que debe comprobar cuidadosamente que no necesita la colecci&oacute;n antes de proceder.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/designingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/designingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/designingacollection.htm	(revision 10506)
@@ -0,0 +1,26 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="designingacollection"><font size="5" face="Verdana"><strong>6: Dise&ntilde;ando la apariencia de su colecci&oacute;n</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Una vez que los archivos est&aacute;n marcados con metadatos, a continuaci&oacute;n se debe decidir la forma en que aparecer&aacute;n ante los usuarios como parte de una colecci&oacute;n Greenstone. &iquest;Qu&eacute; tipo de informaci&oacute;n se podr&aacute; buscar? &iquest;De qu&eacute; medios se dispone para navegar por los documentos? &iquest;En qu&eacute; idiomas? &iquest;D&oacute;nde aparecer&aacute;n los botones en la p&aacute;gina? Todas estas cosas se pueden personalizar. Esta secci&oacute;n describe la forma de hacerlo.
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/downloadingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/downloadingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/downloadingfiles.htm	(revision 10506)
@@ -0,0 +1,16 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="downloadingfiles"><font size="5" face="Verdana"><strong>3: Descargando archivos de Internet</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    La vista "Bajar" le ayuda a descargar recursos de internet. Esta secci&oacute;n explica el interfaz del mecanismo de puesta en espejo del Bibliotecario.
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/enrichingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/enrichingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/enrichingacollection.htm	(revision 10506)
@@ -0,0 +1,23 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="enrichingacollection"><font size="5" face="Verdana"><strong>5: Enriqueciendo la colecci&oacute;n con metadatos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Despu&eacute;s de haber juntado varios archivos en una colecci&oacute;n, enriqu&eacute;zcalos con informaci&oacute;n adicional. Esta secci&oacute;n explica la forma en que se crean, editan, asignan y recuperan los metadatos, y la forma de usar fuentes externas de metadatos (v&eacute;ase tambi&eacute;n el Cap&iacute;tulo 2 de la Gu&iacute;a del Programador de Greenstone: Obteniendo el m&aacute;ximo beneficio de sus documentos).
+    
+    
+    
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/exportingcollections.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/exportingcollections.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/exportingcollections.htm	(revision 10506)
@@ -0,0 +1,49 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="exportingcollections"><font size="5" face="Verdana"><strong>8.3: Exportando colecciones a un CD-ROM</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe la forma de exportar colecciones a un CD-ROM Greenstone que se podr&aacute; instalar autom&aacute;ticamente.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">C&oacute;mo exportar</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Greenstone puede exportar una o m&aacute;s colecciones a un CD-ROM para Windows que se podr&aacute; instalar autom&aacute;ticamente. Para ello es indispensable que el paquete "Exportar a un CD-ROM" est&eacute; instalado. Esto no se incluye por omisi&oacute;n, por lo que ser&aacute; necesario modificar la instalaci&oacute;n para incluirlo.
+      <p></p>
+      Para exportar una colecci&oacute;n abra el men&uacute; "Archivo" y seleccione la opci&oacute;n "Exportar a un CD-ROM". Con esto aparecer&aacute; una lista de colecciones Greenstone. Haga click en una para ver su descripci&oacute;n. Marque los recuadros de las colecciones que desea exportar. Usted tambi&eacute;n puede ingresar el nombre de CD-ROM en el cuadro correspondiente, el cual aparecer&aacute; en el men&uacute; de Inicio una vez que el CD-ROM se haya instalado. A continuaci&oacute;n haga click en "Exportar". El proceso incluye la copia de varios archivos y requerir&aacute; de unos cuantos minutos.
+      <p></p>
+      Una vez que haya terminado Greenstone mostrar&aacute; el nombre de una carpeta en la que se encontrar&aacute;n las colecciones que se han exportado. Utilice una quemadora de CDs para copiar sus contenidos en un CD-ROM en blanco.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/fileassociations.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/fileassociations.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/fileassociations.htm	(revision 10506)
@@ -0,0 +1,61 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="fileassociations"><font size="5" face="Verdana"><strong>8.2: Asociaci&oacute;n de archivos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      La Interfaz de Bibliotecario utiliza diferentes programas de aplicaci&oacute;n para abrir tipos particulares de archivos. Esta secci&oacute;n explica la forma de asignar y editar estas asociaciones.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Establecer una asociaci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Editar una asociaci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminar una asociaci&oacute;n</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Para modificar la asociaci&oacute;n de archivos abra el men&uacute; "Archivo" y haga click en "Asociaci&oacute;n de archivos".
+      <p></p>
+      Para establecer una asociaci&oacute;n seleccione la extensi&oacute;n del archivo de la lista descendente o escriba una nueva extensi&oacute;n (no incluya "."). A continuaci&oacute;n escriba en el campo correspondiente el comando que da inicio a la aplicaci&oacute;n deseada o elija la aplicaci&oacute;n en el cuadro "Explorar". "%1" se puede utilizar en el comando de inicio para insertar el nombre del archivo que se est&aacute; abriendo. Una vez que se han llenado estos campos, el bot&oacute;n "Establecer asociaci&oacute;n" se activar&aacute;, con lo que ya se puede hacer click en &eacute;l para establecer la asociaci&oacute;n.
+      <p></p>
+      Para editar una asociaci&oacute;n, seleccione una extensi&oacute;n de archivo existente. El comando asociado aparecer&aacute; en el campo correspondiente a comando de inicio. Ed&iacute;telo y a continuaci&oacute;n haga click en "Reemplazar asociaci&oacute;n".
+      <p></p>
+      Para eliminar una asociaci&oacute;n, seleccione la extensi&oacute;n del archivo y haga click en "Eliminar asociaci&oacute;n". La extensi&oacute;n del archivo permanecer&aacute; en una lista llamada "Para archivos que terminan en...".
+      <p></p>
+      Las asociaciones de archivos se guardan en la carpeta principal de la Interfaz de Bibliotecario en un archivo llamado "associations.xml".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/filteringthetree.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/filteringthetree.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/filteringthetree.htm	(revision 10506)
@@ -0,0 +1,58 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="filteringthetree"><font size="5" face="Verdana"><strong>4.5: Filtrando la estructura de directorios y subdirectorios</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      "Filtrar" la estructura de directorios y subdirectorios de la colecci&oacute;n limita la b&uacute;squeda a determinados tipos de archivos.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">El control de filtros</td>
+</tr>
+	
+	
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Filtrado especial</td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      El men&uacute; "Mostrar archivos" debajo de cada estructura de directorios y subdirectorios muestra una lista de filtros definidos previamente, como por ejemplo el de "Im&aacute;genes". Al elegir uno se ocultan temporalmente todos los dem&aacute;s archivos. Para restaurarlos, cambie el filtro a "Todos los archivos". Estas operaciones no alteran la colecci&oacute;n ni afectan las carpetas en la estructura de archivos.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      Se puede especificar un filtro en particular escribiendo un patr&oacute;n que corresponda con los tipos de archivos que se desea filtrar. Utilice las abreviaturas est&aacute;ndar del sistema como "*.*" o "*.doc" ("*" equivale a cualquier caracter).
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/formatstatements.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/formatstatements.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/formatstatements.htm	(revision 10506)
@@ -0,0 +1,80 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="formatstatements"><font size="5" face="Verdana"><strong>6.9: Formatos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Los comandos de formato controlan la estructura y apariencia de la colecci&oacute;n. Afectan aspectos como el lugar donde aparecer&aacute;n los botones cuando se muestra un documento y qu&eacute; v&iacute;nculos despliega el clasificador DateList en pantalla. Los comandos de formato no son f&aacute;ciles de desarrollar, por lo que le recomendamos que lea el Cap&iacute;tulo 2 de la Gu&iacute;a del Programador de Greenstone. La presente secci&oacute;n describe los controles de los distintos formatos y la forma en que la Interfaz de Bibliotecario le da acceso a ellos. En la parte de "Secciones de dise&ntilde;o" haga click en "Formatos".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Formateo</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adir un comando de formato</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminar un comando de formato</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Actualizar un comando de formato</td>
+</tr>
+        
+	
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Opciones avanzadas</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Se puede aplicar un comando de formato a cualquier cosa que se encuentre en la lista llamada "Elegir funci&oacute;n", la cual incluye cada clasificador y una lista de funciones determinadas previamente. Cuando se selecciona una funci&oacute;n existen dos tipos de controles. Algunas funciones simplemente se activan o se desactivan por medio de un recuadro. Otras requieren que se especifique una cadena de formato, para las cuales hay una lista descendente (llamada "Componente afectado") que permite seleccionar la parte de la funci&oacute;n a la que se aplica la cadena (en caso necesario), un &aacute;rea de texto (llamada "cadena de formato HTML") para ingresar la cadena y una selecci&oacute;n de "variables" definidas previamente. Para insertar una variable en su posici&oacute;n actual dentro de la cadena de formato, selecci&oacute;nela de la lista descendente y haga click en "Insertar".
+      <p></p>
+      Tambi&eacute;n se puede especificar un formato predeterminado para un componente en particular seleccionando la funci&oacute;n que est&aacute; en blanco. Este formato se aplicar&aacute; a todas las funciones aplicables a menos que se especifique lo contrario.
+      <p></p>
+      Para a&ntilde;adir un nuevo formato de comando llene la informaci&oacute;n tal como se describe arriba y haga click en "A&ntilde;adir formato". El nuevo comando de formato aparecer&aacute; en la lista de "Comandos de formato asignados actualmente". Solamente se podr&aacute; asignar un comando de formato a cada combinaci&oacute;n de funci&oacute;n/componente.
+      <p></p>
+      Para quitar un comando de formato de la lista, selecci&oacute;nelo y haga click en "Eliminar formato".
+      <p></p>
+      Para cambiar un comando de formato, selecci&oacute;nelo de la lista, modifique sus par&aacute;metros y haga click en "Reemplazar formato".
+      <p></p>
+      Para mayor informaci&oacute;n acerca de las variables y los componentes de las funciones lea el Cap&iacute;tulo 2 de la Gu&iacute;a del Programador de Greenstone.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      Si se marca el recuadro "Permitir opciones avanzadas" se activar&aacute;n algunas opciones de formateo avanzado. La lista de funciones que se pueden formatear cambia ligeramente y m&aacute;s variables est&aacute;n disponibles para usarlas en los comandos de formato, proporcionando as&iacute; un mayor control sobre el dise&ntilde;o de la p&aacute;gina.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/generalsettings.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/generalsettings.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/generalsettings.htm	(revision 10506)
@@ -0,0 +1,49 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="generalsettings"><font size="5" face="Verdana"><strong>6.2: Ajustes generales</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica la forma de revisar y modificar los ajustes generales asociados a una colecci&oacute;n. Primero que nada, en la parte de "Secciones de dise&ntilde;o" haga click en "General".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Ajustes generales</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Aqu&iacute; pueden modificarse los valores proporcionados durante la fase de creaci&oacute;n de la colecci&oacute;n.
+      <p></p>
+      En la parte superior de la p&aacute;gina hay un cuadro de instrucciones que aparece con cada una de las secciones, el cual contiene una breve lista de indicaciones que le recuerdan cu&aacute;les son las funciones disponibles.
+      <p></p>
+      Primero se encuentran las direcciones de correo electr&oacute;nico del creador y del administrador de la colecci&oacute;n. El siguiente campo le permite cambiar el t&iacute;tulo de la colecci&oacute;n. El directorio en el que se almacena la colecci&oacute;n se muestra al lado, pero no puede editarse. El que sigue especifica (en forma de URL) el icono que aparecer&aacute; en el &aacute;ngulo superior izquierdo de la p&aacute;gina "Acerca de" y el siguiente es el icono usado en la p&aacute;gina de la biblioteca digital Greenstone para conectarse a la colecci&oacute;n. Entonces, una casilla controla que la colecci&oacute;n sea o no accesible p&uacute;blicamente. Finalmente viene el &aacute;rea de texto que permite dar una "Descripci&oacute;n de la Colecci&oacute;n", tal como se explica en la secci&oacute;n <a href="creatingacollection.htm#creatingacollection">Creando una nueva colecci&oacute;n</a>.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/help.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/help.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/help.xml	(revision 10506)
@@ -0,0 +1,820 @@
+<Document>
+  <Section name="introduction">
+    <Title>IntroducciÃ³n</Title>
+    La Interfaz de Bibliotecario de Greenstone es una herramienta que permite reunir y marcar documentos para luego crear colecciones digitales con ellos, dÃ¡ndole fÃ¡cil acceso a todas las funciones de los programas de software de la Biblioteca Digital Greenstone desde una interfaz grÃ¡fica de usuario con la que sÃ³lo tiene que apuntar y hacer click.
+    <Section name="ofmiceandmenus">
+      <Title>De menÃºs y ratones</Title>
+      Esta secciÃ³n proporciona informaciÃ³n bÃ¡sica para poder trabajar con la Interfaz de Bibliotecario. Si estÃ¡ familiarizado con programas como Internet Explorer o Microsoft Office y estÃ¡ acostumbrado a usar el mouse, entonces pase a la <Reference target="howtoavoidthisdocument">siguiente secciÃ³n</Reference>.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Conceptos bÃ¡sicos
+            <ContentsItem>Movimientos del mouse</ContentsItem>
+            <ContentsItem>Teclado</ContentsItem>
+          </ContentsItem>
+          <ContentsItem>Salir del programa</ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>Teclas de mÃ©todo abreviado</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      La Interfaz de Bibliotecario sigue las convenciones de Microsoft y se apoya en el conocimiento que comÃºnmente se tiene de Windows.
+      <Break/>
+      Cualquier parte de la pantalla con la que usted interactÃºe, como un botÃ³n o un campo de texto, se llama "control". En todo momento un botÃ³n o campo de texto llamado "control activo" aparecerÃ¡ resaltado y responderÃ¡ a las instrucciones del teclado. Asimismo, varios controles le permiten seleccionar las partes que estÃ©n resaltadas en azul marino. Algunos controles tambiÃ©n pueden aparecer sombreados para indicar que no estÃ¡n disponibles.
+      <Break/>
+      Usted puede mover y hacer click con el botÃ³n izquierdo o derecho del mouse de la forma acostumbrada. Muchos componentes tambiÃ©n se pueden "arrastrar" haciendo click en ellos y sosteniendo el botÃ³n izquierdo del mouse, para luego moverlos y "colocarlos" en algÃºn otro lugar soltando el botÃ³n. Normalmente el lugar de destino cambia de apariencia cuando un componente pasa sobre Ã©l.
+      <Break/>
+      Usted puede usar el teclado para escribir en los campos de texto. Muchos controles tambiÃ©n se pueden ejecutar por medio del teclado, lo que se indica por medio de corchetes -- por ejemplo la tecla de tabulaciÃ³n [Tab] cambia el control activo. El signo de mÃ¡s (+) indica que otras teclas deben oprimirse al mismo tiempo.
+      <Break/>
+      Salga de la Interfaz de Bibliotecario eligiendo "Salir" en el menÃº "Archivo". Su colecciÃ³n se guardarÃ¡ primero.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      Para tener acceso a un menÃº, oprima el botÃ³n [ALT] y presione la letra correspondiente (la cual aparece subrayada). Por ejemplo, para desplegar el menÃº "Archivo" oprima [ALT] + [A]. Para elegir un comando presione la tecla correspondiente. Por ejemplo, en el menÃº "Archivo" presione [G] para "Guardar" la colecciÃ³n.
+    </Section>
+    <Section name="howtoavoidthisdocument">
+      <Title>Temas de ayuda</Title>
+      Â¡Usted no necesita leer todo el texto de ayuda! SÃ³lo lea lo suficiente para saber cÃ³mo obtener ayuda cuando la necesite.
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Ayuda sensible al contexto</ContentsItem>
+	  <ContentsItem>Cuadros de sugerencias</ContentsItem>
+	  <ContentsItem>Otros documentos</ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      El comando del menÃº "Ayuda" indica los que serÃ­an los temas de ayuda mÃ¡s apropiados por medio de un pequeÃ±o icono en forma de libro.
+      <Break/>
+      Para muchos controles si se coloca el mouse encima de ellos aparecerÃ¡ un "cuadro de sugerencias" en el cual se explica su funciÃ³n.
+      <Break/>
+      Antes de usar la Interfaz de Bibliotecario lea primero la documentaciÃ³n de Greenstone.
+    </Section>
+  </Section>
+
+  <Section name="startingoff">
+    <Title>Para empezar</Title>
+    Esta secciÃ³n explica cÃ³mo crear, cargar, guardar y borrar colecciones.
+    <Section name="creatingacollection">
+      <Title>Creando una nueva colecciÃ³n</Title>
+      <ObviousSentence> Esta secciÃ³n describe la forma de crear una nueva colecciÃ³n.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Aviso de la nueva colecciÃ³n</ContentsItem>
+	  <ContentsItem>TÃ­tulo de la colecciÃ³n</ContentsItem>
+	  <ContentsItem>Conjuntos de metadatos por omisiÃ³n</ContentsItem>
+	  <ContentsItem>DescripciÃ³n de la colecciÃ³n</ContentsItem>
+	  <ContentsItem>Crear una nueva colecciÃ³n</ContentsItem>
+	  <ContentsItem>Cancelar la nueva colecciÃ³n</ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+	  <ContentsItem>Teclas de mÃ©todo abreviado</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Para crear una nueva colecciÃ³n abra el menÃº "Archivo" y elija la opciÃ³n "Nueva". DeberÃ¡n llenarse varios campos, aunque en caso de que lo requiera usted podrÃ¡ cambiar despuÃ©s sus valores en la pantalla de diseÃ±o.
+      <Break/>
+      El "TÃ­tulo de la colecciÃ³n" es el texto que aparece en la parte superior de la pÃ¡gina principal de su colecciÃ³n. Puede tener la longitud  que usted quiera.
+      <Break/>
+      La "DescripciÃ³n del contenido" deberÃ¡ describir tan detalladamente como sea posible de lo que se trata la colecciÃ³n. Utilice la tecla [Enter] o [Intro] para dividirla en pÃ¡rrafos.
+      <Break/>
+      Finalmente deberÃ¡ especificar si desea que la nueva colecciÃ³n tenga la misma apariencia y conjunto de metadatos que una colecciÃ³n existente o si desea iniciar una "Nueva ColecciÃ³n" por omisiÃ³n.
+      <Break/>
+      Haga click en "Aceptar" para crear la colecciÃ³n. Si usted escogiÃ³ "Nueva ColecciÃ³n" se le pedirÃ¡ que elija el conjunto de metadatos que usarÃ¡ en ella.  Puede elegir mÃ¡s de uno y tambiÃ©n puede aÃ±adir otros mÃ¡s adelante.
+      <Break/>
+      Si hace click en "Cancelar" regresarÃ¡ inmediatamente a la pantalla principal.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      Los botones, al igual que los menÃºs, tienen una letra subrayada. Para seleccionar un botÃ³n oprima la tecla [ALT] y la letra que estÃ¡ subrayada al mismo tiempo.
+    </Section>
+    <Section name="savingacollection">
+      <Title>Guardar la colecciÃ³n</Title>
+      <ObviousSentence> Esta secciÃ³n describe la forma de guardar una colecciÃ³n y el mensaje Guardar ColecciÃ³n.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>CÃ³mo guardar</ContentsItem>
+	</ContentsGroup>
+	<ContentsGroup linkto="advanced">
+	  <ContentsItem>DÃ³nde se guardan los archivos</ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Guarde su trabajo regularmente abriendo el menÃº "Archivo" y seleccionando "Guardar". Tome en cuenta que guardar una colecciÃ³n no es lo mismo que prepararla para que se pueda usar en Greenstone (vea la secciÃ³n <Reference target="producingthecollection">Produciendo una colecciÃ³n</Reference>).
+      <Break/>
+      La Interfaz de Bibliotecario protege su trabajo guardÃ¡ndolo cada vez que salga del programa o cargue otra colecciÃ³n.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      Las colecciones se guardan en un archivo que lleva el nombre de la colecciÃ³n y la extensiÃ³n ".col", ubicado en una carpeta del mismo nombre dentro de la carpeta "colecciones" del programa Greenstone.
+    </Section>
+    <Section name="openingacollection">
+      <Title>Abriendo una colecciÃ³n existente</Title>
+      <ObviousSentence>Esta secciÃ³n le dice la forma de abrir una colecciÃ³n existente por medio del mensaje Abrir ColecciÃ³n.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>CÃ³mo abrir una colecciÃ³n</ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+	  <ContentsItem>Colecciones protegidas</ContentsItem>
+	  <ContentsItem>Colecciones heredadas</ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Para abrir una colecciÃ³n existente elija la opciÃ³n "Abrir" en el menÃº "Archivo". Con esto aparecerÃ¡ una lista de sus colecciones Greenstone. Seleccione una para ver su descripciÃ³n y haga click en "Abrir" para cargarla. Si busca una colecciÃ³n que resida fuera de la carpeta de "colecciones" de Greenstone, entonces haga click en "Explorar" para que aparezca un cuadro de diÃ¡logo que le permita buscar en el sistema de archivos.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      En caso de que mÃ¡s de una Interfaz de Bibliotecario de Greenstone estÃ© corriendo al mismo tiempo, los directorios pertinentes se "bloquean" para evitar interferencias. Al abrir una colecciÃ³n se crea un pequeÃ±o archivo de bloqueo temporal en la carpeta. Antes de abrir una colecciÃ³n la Interfaz de Bibliotecario revisa que no haya un archivo de bloqueo en ella. Se puede saber si la colecciÃ³n estÃ¡ bloqueada por el color de su icono: verde para una colecciÃ³n normal, rojo para una colecciÃ³n bloqueada. Sin embargo, cuando se sale prematuramente de la Interfaz de Bibliotecario el archivo de bloqueo a veces permanece en la carpeta. Cuando posteriormente se abre esta colecciÃ³n, la Biblioteca Digital le pregunta si quiere tomar el control. Por favor, nunca le quite el control de una colecciÃ³n a alguien que este trabajando en ese momento con ella.
+      <Break/>
+      Cuando usted abra una colecciÃ³n que no haya sido creada por medio de la Interfaz de Bibliotecario de Greenstone se le pedirÃ¡ que seleccione uno o mÃ¡s conjuntos de metadatos. Si no selecciona ninguno, entonces los metadatos existentes se ignorarÃ¡n. De otra manera los metadatos se importarÃ¡n tal como son cuando usted arrastre los archivos. El proceso se describe en el documento llamado <Reference target="importingpreviouslyassignedmetadata">Importando Metadatos Previamente Asignados</Reference>.
+    </Section>
+    <Section name="deletingcollections">
+      <Title>Borrando colecciones</Title>
+      <ObviousSentence>Esta secciÃ³n explica como borrar definitivamente colecciones de su instalaciÃ³n de Greenstone.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            CÃ³mo borrar colecciones
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Para borrar definitivamente colecciones de su instalaciÃ³n de Greenstone, elija "BorrarâŠ" del menÃº "Archivo". Aparece una lista de sus colecciones. Seleccione una para ver su descripciÃ³n, marque la casilla situada en la parte inferior del diÃ¡logo, y pulse "Borrar" para borrar la colecciÃ³n. Esta acciÃ³n es irreversible, por lo que debe comprobar cuidadosamente que no necesita la colecciÃ³n antes de proceder.
+    </Section>
+  </Section>
+
+  <Section name="downloadingfiles">
+    <Title>Descargando archivos de Internet</Title>
+    La vista "Bajar" le ayuda a descargar recursos de internet. Esta secciÃ³n explica el interfaz del mecanismo de puesta en espejo del Bibliotecario.
+    <Section name="themirrorview">
+      <Title>La vista en Bajar</Title>
+      Esta secciÃ³n describe como configurar una tarea de descarga y como controlar el proceso de descargue.
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>El Ã¡rbol del Ã¡rea de trabajo</ContentsItem>
+	  <ContentsItem>ConfiguraciÃ³n de descarga</ContentsItem>
+	  <ContentsItem>Lista de descarga</ContentsItem>
+        </ContentsGroup>
+	<ContentsGroup linkto="advanced">
+	  <ContentsItem>ActivaciÃ³n de "web proxies"</ContentsItem>
+	  <ContentsItem>Modo avanzado</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Active la vista "Bajar" haciendo clic en su pestaÃ±a. La mitad superior de la pantalla contiene los controles para realizar descargas. La mitad inferior estÃ¡ vacÃ­a inicialmente, pero despuÃ©s va a mostrar una lista de tareas pendientes y terminadas.
+      <Break/>
+      Los archivos se descargan en una carpeta del espacio de trabajo denominada "Archivos Descargados" (que sÃ³lo existe cuando estÃ¡ habilitada la opciÃ³n de trabajar en espejo), y pueden utilizarse en todas las colecciones construidas con el interfaz del Bibliotecario. En esta Ã¡rea los archivos se designan con su URL completo. Para cada "host" se crea una nueva carpeta, seguida por otras para cada parte del "path". De esta manera se asegura que todos los archivos son distintos.
+      <Break/>
+      Utilice el primero de los controles de configuraciÃ³n de la descarga, "URL OrÃ­gen", para capturar el URL de un recurso deseado. Utilice el control "Profundidad de la Descarga" para limitar el nÃºmero de hiper-vÃ­nculos que se deben seguir al descargar: PÃ³ngalo en 0 para descargar una sola pÃ¡gina; pÃ³ngalo en 1 para descargar una pÃ¡gina y todas las pÃ¡ginas a las que apunta. El lÃ­mite de profundidad se ignora al descargar medios diferentes de pÃ¡ginas html. AdemÃ¡s, hay varios controles de chequeo que se pueden prender para activar determinadas capacidades durante una descarga especÃ­fica. Una vez se ha establecido la configuraciÃ³n, haga clic en "Descargar" para iniciar un nuevo proceso de descargue. Hay otros dos controles en forma de botones: "Preferencias", que enlaza con la secciÃ³n de conexiÃ³n de las Preferencias, en la cual se pueden editar las caracterÃ­sticas del "proxy"; y "Borrar CachÃ©", que borra todos los archivos descargados previamente.
+      <Break/>
+      La lista de descargas tiene una entrada por cada pÃ¡gina web descargada. Cada entrada tiene un Ã¡rea de texto que da detalles acerca de la tarea, junto con una barra que indica el avance de la actividad en ejecuciÃ³n. A la izquierda de cada entrada aparecen tres botones. "Pausa" se utiliza para detener temporalmente la descarga que se estÃ¡ ejecutando. "Ver BitÃ¡cora" abre una ventana que muestra el archivo de bitÃ¡cora de las descargas. "Cerrar" termina la descarga y quita de la lista la tarea correspondiente.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      La <Reference target="preferences">secciÃ³n Preferencias</Reference> describe como establecer una conexiÃ³n Internet por medio de un "proxy".  Si se necesita autenticaciÃ³n, el servidor "proxy" pide la identificaciÃ³n y la palabra clave. El interfaz del Bibliotecario no almacena palabras claves entre sesiones.
+    </Section>
+  </Section>
+
+  <Section name="collectingfiles">
+    <Title>Reuniendo archivos para su colecciÃ³n</Title>
+    Una vez que usted tiene una nueva colecciÃ³n necesita meter algunos archivos en ella. Estos pueden venir desde la estructura de archivos de su computadora o de otras colecciones Greenstone. Algunos incluso ya pueden tener metadatos. Esta secciÃ³n describe la forma de importar archivos.
+    <Section name="thegatherview">
+      <Title>La pantalla de selecciÃ³n de documentos</Title>
+      Esta secciÃ³n describe el funcionamiento de la pantalla "Reunir" que se utiliza para seleccionar los archivos que se van a incluir en la colecciÃ³n que se estÃ¡ construyendo.
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>CÃ³mo ver la pantalla Reunir</ContentsItem>
+	  <ContentsItem>La estructura de directorios y subdirectorios</ContentsItem>
+	  <ContentsItem>El Ã¡rea de estado</ContentsItem>
+	  <ContentsItem>Botones de control</ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+	  <ContentsItem>MÃ©todos de selecciÃ³n</ContentsItem>
+	  <ContentsItem>Mapeado de carpetas especiales</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      La Interfaz de Bibliotecario inicia con la pantalla "Reunir". Si despuÃ©s usted desea regresar a esta pantalla haga click en la pestaÃ±a del mismo nombre que se encuentra directamente debajo de la barra de menÃºs.
+      <Break/>
+      Dos grandes Ã¡reas tituladas "Area de trabajo" y "ColecciÃ³n" se utilizan para transferir los archivos a su colecciÃ³n. Cada una contiene "Ã¡rboles de archivos", los cuales son representaciones grÃ¡ficas de la estructura de directorios y subdirectorios de sus archivos y carpetas.
+      <Break/>
+      Seleccione un elemento del Ã¡rbol haciendo click en Ã©l. (TambiÃ©n existen otras formas; vÃ©ase mÃ¡s adelante.) Haga click en el signo que se encuentra junto a una carpeta o doble click en ella para expandir (o contraer) sus contenidos. Haga doble click en un archivo para abrirlo usando un programa de aplicaciÃ³n asociado (vea la secciÃ³n <Reference target="fileassociations">AsociaciÃ³n de archivos</Reference>).
+      <Break/>
+      El Ã¡rbol de archivos del Ã¡rea de trabajo muestra los orÃ­genes de la informaciÃ³n disponible al interfaz del Bibliotecario -- el sistema local de archivos (incluyendo unidades de disco y CD-ROM), los contenidos de las colecciones existentes de Greenstone, y el cachÃ© de archivos descargados si esta activada la opciÃ³n de poner en espejo la Web. Usted puede copiar y consultar estos archivos pero no puede moverlos, eliminarlos o editarlos, con la excepciÃ³n de los archivos descargados, los cuales pueden ser eliminados. Navegue por este espacio para buscar los archivos que desee incluir en la colecciÃ³n.
+      <Break/>
+      La estructura de directorios y subdirectorios de la colecciÃ³n muestra sus contenidos. Inicialmente estÃ¡ vacÃ­a.
+      <Break/>
+      Se puede cambiar el tamaÃ±o de las Ã¡reas oprimiendo el botÃ³n del mouse sobre la barra gris que separa las estructuras de directorios y subdirectorios (la forma del cursor cambia) y arrastrÃ¡ndola.
+      <Break/>
+      En la parte inferior de la ventana se muestra un Ã¡rea de estado que informa del progreso de las acciones sobre archivos (copiando, moviendo y borrando). Puede tardar un tiempo en terminar. El botÃ³n "Detener" interrumpe cualquier acciÃ³n que se estÃ© ejecutando en ese momento.
+      <Break/>
+      Dos grandes botones ocupan la esquina inferior derecha de la pantalla: "Nueva carpeta", con la imagen de una carpeta, crea nuevas carpetas (vea la secciÃ³n <Reference target="creatingfolders">Creando carpetas</Reference>), en tanto que "Eliminar", con la imagen de un bote de basura, descarta los archivos. Al hacer click en el botÃ³n "Eliminar" se suprimirÃ¡n los archivos seleccionados de la estructura de directorios y subdirectorios de la colecciÃ³n. Asimismo, los archivos pueden eliminarse arrastrÃ¡ndolos hacia este botÃ³n.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      Para seleccionar varios elementos consecutivos, seleccione el primero y a continuaciÃ³n manteniendo oprimida la tecla de mayÃºsculas o [Shift] haga click en el Ãºltimo: la selecciÃ³n incluirÃ¡ todos los elementos que se encuentran en medio. Para seleccionar varios archivos que no sean consecutivos mantenga oprimida la tecla de control o [Ctrl] mientras hace click en ellos. Utilice alternativamente estos dos mÃ©todos para seleccionar grupos de elementos que no estÃ©n juntos.
+      <Break/>
+      En ocasiones algunas carpetas, como la que contiene sus propias pÃ¡ginas Web, tienen un significado especial. La Interfaz de Bibliotecario puede asignar dichas carpetas al primer nivel de la estructura de directorios y subdirectorios. Para hacerlo haga click con el botÃ³n derecho del mouse sobre la carpeta deseada. Seleccione "Crear un acceso directo" y dÃ©le un nombre a la carpeta. Para quitar un elemento haga click con el botÃ³n derecho del mouse sobre la carpeta mapeada y seleccione "Eliminar acceso directo".
+    </Section>
+    <Section name="creatingfolders">
+      <Title>Creando carpetas</Title>
+      <ObviousSentence>Esta secciÃ³n muestra la forma de crear nuevas carpetas.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>El botÃ³n de nueva carpeta</ContentsItem>
+	  <ContentsItem>El menÃº del botÃ³n derecho del mouse</ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Utilice las carpetas que se encuentran en la estructura de directorios y subdirectorios de la colecciÃ³n para agrupar archivos y hacer que sean mÃ¡s fÃ¡ciles de encontrar. Las carpetas pueden contener a su vez otras subcarpetas. No hay prÃ¡cticamente ningÃºn lÃ­mite en cuanto al nÃºmero de carpetas que se pueden tener o quÃ© tan profundamente anidadas puedan estar.
+      <Break/>
+      Para crear una nueva carpeta, una opciÃ³n es seleccionar una carpeta existente en la estructura de directorios y subdirectorios de la colecciÃ³n y hacer click en el botÃ³n "Nueva carpeta". La nueva carpeta aparecerÃ¡ dentro de la que se seleccionÃ³ primero o en el nivel superior si no se seleccionÃ³ ninguna. Se le pedirÃ¡ que le dÃ© un nombre a la carpeta (el valor por omisiÃ³n es "Nueva carpeta").
+      <Break/>
+      TambiÃ©n se pueden crear nuevas carpetas haciendo click sobre una carpeta con el botÃ³n derecho del mouse,  eligiendo la opciÃ³n "Nueva carpeta" y continuando tal como se describe arriba.
+    </Section>
+    <Section name="addingfiles">
+      <Title>AÃ±adiendo archivos</Title>
+      <ObviousSentence>Esta secciÃ³n muestra la forma de aÃ±adir archivos a su colecciÃ³n.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Arrastrando un archivo</ContentsItem>
+	  <ContentsItem>Varios archivos</ContentsItem>
+        </ContentsGroup>
+	<ContentsGroup linkto="advanced">
+	  <ContentsItem>Metadatos existentes</ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Los archivos se pueden copiar arrastrÃ¡ndolos y colocÃ¡ndolos en una colecciÃ³n. El cursor se convierte en un fantasma del elemento seleccionado (o, si se ha seleccionado mÃ¡s de uno, del nÃºmero de ellos). Coloque la selecciÃ³n en la estructura de directorios y subdirectorios de la colecciÃ³n para copiar ahÃ­ los archivos (si la fuente son los archivos del Ã¡rea de trabajo) o muÃ©valos de lugar dentro de la misma colecciÃ³n (si la fuente son los archivos de la colecciÃ³n).
+      <Break/>
+      Cuando se copien varios archivos en una carpeta todos estarÃ¡n al mismo nivel, sin importar la estructura de las carpetas en las que se encontraban originalmente. Cuando se copie un segundo archivo con el mismo nombre en la misma carpeta se le preguntarÃ¡ si desea reemplazar el archivo existente. Si la respuesta es "No" entonces el archivo no se copiarÃ¡, pero los demÃ¡s sÃ­. Para cancelar las acciones restantes de copiado haga click en el botÃ³n "Detener".
+      <Break/>
+      Ãnicamente se moverÃ¡n los elementos "de mÃ¡s alto nivel" en una selecciÃ³n. Una carpeta estÃ¡ a un nivel mÃ¡s alto que los elementos que se encuentran en su interior, por lo que no se podrÃ¡n seleccionar los archivos de una carpeta y la carpeta al mismo tiempo.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      Cuando se aÃ±ada un archivo, la Interfaz de Bibliotecario buscarÃ¡ a travÃ©s de las carpetas fuente los archivos auxiliares que contienen los metadatos asignados previamente a dicho archivo y, si encuentra alguno, empezarÃ¡ a importar estos metadatos. Conforme la operaciÃ³n siga adelante se le pedirÃ¡ (quizÃ¡ varias veces) que proporcione informaciÃ³n adicional para conciliar los metadatos importados con los conjuntos de metadatos de su colecciÃ³n. Este proceso incluye muchos avisos diferentes, los cuales se describen en la secciÃ³n <Reference target="importingpreviouslyassignedmetadata">Importando metadatos previamente asignados</Reference>. Para obtener una explicaciÃ³n mÃ¡s detallada sobre la forma de asociar metadatos a los archivos lea el CapÃ­tulo 2 de la GuÃ­a del Programador de Greenstone: Obteniendo el mÃ¡ximo beneficio de sus documentos.
+    </Section>
+    <Section name="removingfiles">
+      <Title>Eliminando archivos</Title>
+      <ObviousSentence>Esta secciÃ³n describe la forma de eliminar archivos y carpetas de su colecciÃ³n.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>El botÃ³n eliminar</ContentsItem>
+	  <ContentsItem>La tecla suprimir</ContentsItem>
+	  <ContentsItem>Arrastrarlos y colocarlos en el botÃ³n "Eliminar"</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Existen varios mÃ©todos para eliminar archivos y carpetas. Primero se deben indicar los elementos que se desea eliminar seleccionando los archivos y carpetas tal como se describe en la secciÃ³n de <Reference target="thegatherview">selecciÃ³n de documentos para la colecciÃ³n</Reference>.
+      <Break/>
+      Una vez que se han seleccionado los archivos, haga click en el botÃ³n "Eliminar" o presione la tecla [Del], [Supr] o [Suprimir], dependiendo del teclado de su computadora, o arrÃ¡strelos desde la colecciÃ³n hasta el botÃ³n "Eliminar" y suÃ©ltelos ahÃ­.
+    </Section>
+    <Section name="filteringthetree">
+      <Title>Filtrando la estructura de directorios y subdirectorios</Title>
+      "Filtrar" la estructura de directorios y subdirectorios de la colecciÃ³n limita la bÃºsqueda a determinados tipos de archivos.
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>El control de filtros</ContentsItem>
+	</ContentsGroup>
+	<ContentsGroup linkto="advanced">
+	  <ContentsItem>Filtrado especial</ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      El menÃº "Mostrar archivos" debajo de cada estructura de directorios y subdirectorios muestra una lista de filtros definidos previamente, como por ejemplo el de "ImÃ¡genes". Al elegir uno se ocultan temporalmente todos los demÃ¡s archivos. Para restaurarlos, cambie el filtro a "Todos los archivos". Estas operaciones no alteran la colecciÃ³n ni afectan las carpetas en la estructura de archivos.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      Se puede especificar un filtro en particular escribiendo un patrÃ³n que corresponda con los tipos de archivos que se desea filtrar. Utilice las abreviaturas estÃ¡ndar del sistema como "*.*" o "*.doc" ("*" equivale a cualquier caracter).
+    </Section>
+  </Section>
+
+  <Section name="enrichingacollection">
+    <Title>Enriqueciendo la colecciÃ³n con metadatos</Title>
+    DespuÃ©s de haber juntado varios archivos en una colecciÃ³n, enriquÃ©zcalos con informaciÃ³n adicional. Esta secciÃ³n explica la forma en que se crean, editan, asignan y recuperan los metadatos, y la forma de usar fuentes externas de metadatos (vÃ©ase tambiÃ©n el CapÃ­tulo 2 de la GuÃ­a del Programador de Greenstone: Obteniendo el mÃ¡ximo beneficio de sus documentos).
+    <Section name="theenrichview">
+      <Title>La pantalla de asignaciÃ³n de metadatos</Title>
+      <ObviousSentence>Esta secciÃ³n describe la forma de aÃ±adir y editar metadatos por medio de la pantalla "Enriquecer".</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>La estructura de directorios y subdirectorios de la colecciÃ³n</ContentsItem>
+	  <ContentsItem>Controles de ediciÃ³n de metadatos</ContentsItem>
+	  <ContentsItem>La estructura de valores</ContentsItem>
+	  <ContentsItem>La tabla de metadatos</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Utilice la pantalla "Enriquecer" para asignar metadatos a los documentos de la colecciÃ³n. Los metadatos son datos acerca de los datos: tÃ­tulo, autor, fecha de creaciÃ³n, etc. Cada metadato tiene dos partes: el "elemento" dice el tipo de metadato que es (como por ejemplo el autor) y el "valor" da la informaciÃ³n de ese elemento (como por ejemplo el nombre del autor).
+      <Break/>
+      En la parte izquierda de la pantalla "Enriquecer" se encuentra la estructura de directorios y subdirectorios de la colecciÃ³n. A la derecha estÃ¡ la Tabla de Metadatos, la cual muestra los metadatos de los archivos y carpetas seleccionados. Los nombres de las columnas estÃ¡n en gris en la parte superior y se pueden cambiar de tamaÃ±o arrastrando la lÃ­nea que las separa. Pulsar sobre cualquier lÃ­nea transfiere sus detalles a los controles inferiores de ediciÃ³n de metadatos. Si se seleccionan varios archivos, el texto en negro indica que el valor es comÃºn a todos ellos, mientras que el texto sombreado indica que no. Los valores en negro se pueden actualizar o eliminar, mientras que los que estÃ¡n sombreados se pueden eliminar de los que los tienen o agregarse a los demÃ¡s.
+      <Break/>
+      Un icono en forma de carpeta puede aparecer junto a algunas entradas de metadatos. Esto indica que los valores se heredan de la carpeta en la que se encuentra el archivo. Los metadatos heredados no se pueden editar o eliminar, sino Ãºnicamente agregarse o sobreescribirse. Haga click en el icono de la carpeta para ir inmediatamente a la carpeta en la que se asignaron los metadatos.
+      <Break/>
+      Los controles de ediciÃ³n de metadatos de la parte inferior derecha aparecen sÃ³lo cuando se selecciona un archivo de la estructura y una lÃ­nea de la tabla. UtilÃ­celos para actualizar, agregar o eliminar valores de los metadatos. El campo de valores es para ingresar o editar el valor del metadato.  Junto hay un botÃ³n con la etiqueta "...", el cual abre un cuadro de ediciÃ³n mÃ¡s grande. De los botones que se encuentran debajo, "Agregar" asigna el valor en forma de nuevo metadato y lo aÃ±ade a los valores existentes para el elemento seleccionado, "Reemplazar" sobreescribe el valor seleccionado sustituyÃ©ndolo por uno nuevo y "Eliminar" borra el valor seleccionado. MÃ¡s abajo, con la etiqueta "Todos los valores anteriores", se encuentra la estructura de valores.
+      <Break/>
+      La estructura de valores se puede expandir y contraer. Normalmente es una lista que muestra todos los valores ingresados previamente para un elemento seleccionado. Al hacer click en una entrada Ã©sta aparece automÃ¡ticamente en el campo de valores. Y a la inversa, al escribir en el campo se selecciona la entrada de la estructura de valores que empieza con los caracteres ingresados. Al oprimir [Tab] se completa automÃ¡ticamente el valor seleccionado.
+      <Break/>
+      Los valores de los metadatos se pueden organizar jerÃ¡rquicamente. Esto se muestra en la estructura de valores por medio de carpetas para los niveles internos. Los valores jerÃ¡rquicos pueden ingresarse utilizando el carÃ¡cter "|" para separar los niveles. Por ejemplo, se puede usar "Cartas|Rojo|Diamantes|Siete" en una jerarquÃ­a que representa un mazo de cartas. Esto permite agrupar los valores, en tanto que los grupos tambiÃ©n pueden asignarse en forma de metadatos a los archivos.
+      <Break/>
+      Greenstone extrae automÃ¡ticamente los metadatos de los documentos para formar un conjunto de metadatos cuyos elementos llevan el prefijo "ex.". Ãste no tiene estructura de valores y no puede editarse, por lo que los controles de ediciÃ³n estÃ¡n ocultos si se selecciona dicha entrada. El botÃ³n "..." todavÃ­a sirve para expandir el valor, pero el texto no se puede editar.
+    </Section>
+    <Section name="selectingmetadatasets">
+      <Title>Seleccionando conjuntos de metadatos</Title>
+      <ObviousSentence>Esta secciÃ³n explica la forma de especificar los elementos de los metadatos y cÃ³mo aÃ±adir conjuntos de metadatos a su colecciÃ³n.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Â¿QuÃ© es un conjunto de metadatos?</ContentsItem>
+	  <ContentsItem>Controlando los conjuntos de metadatos usados</ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Los grupos de elementos de metadatos definidos previamente son conocidos como "conjuntos de metadatos". Un ejemplo es el conjunto de metadatos de Dublin Core. Cuando se aÃ±ade un conjunto de metadatos a una colecciÃ³n, sus elementos se vuelven elegibles para que el usuario los pueda seleccionar. TambiÃ©n se puede tener mÃ¡s de un conjunto. Para evitar conflictos de nombre, un identificador que describe al conjunto de metadatos se agrega como prefijo al nombre del elemento. Por ejemplo, el elemento Creator de Dublin Core se convierte en "dc.Creator". Los conjuntos de metadatos se guardan en la carpeta de metadatos de la Interfaz de Bibliotecario y llevan el sufijo ".mds".
+      <Break/>
+      Para controlar los conjuntos de metadatos usados en una colecciÃ³n, utilice la opciÃ³n "Conjuntos de metadatos" en la vista DiseÃ±o.
+    </Section>
+    <Section name="appendingmetadata">
+      <Title>Agregando nuevos metadatos</Title>
+      <ObviousSentence>Esta secciÃ³n explica la forma de aÃ±adir metadatos y valores a los archivos y cÃ³mo darle nuevos valores a los elementos de los metadatos.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>AÃ±adiendo metadatos a los archivos</ContentsItem>
+	  <ContentsItem> AÃ±adiendo metadatos a carpetas o a varios archivos juntos</ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>JerarquÃ­as y ediciÃ³n de valores</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Ahora aÃ±adiremos un Ã­tem de metadato -- tanto un elemento como un valor -- a un archivo. Primero, seleccione el archivo en la estructura de directorios y subdirectorios de la colecciÃ³n que se encuentra a la izquierda. Esto hace que cualquier metadato asignado previamente a este archivo aparezca en la tabla de la derecha.
+      <Break/>
+      A continuaciÃ³n, seleccione el elemento de metadato que desea aÃ±adir haciendo click en la fila correspondiente de la tabla.
+      <Break/>
+      Escriba el valor en el campo de valores. No use el carÃ¡cter "|", ya que Ã©ste se utiliza para construir jerarquÃ­as. Una vez que haya terminado haga click en "Agregar" para aÃ±adir el nuevo valor como metadato del archivo seleccionado. El valor aparecerÃ¡ inmediatamente en la tabla de metadatos.
+      <Break/>
+      TambiÃ©n se pueden aÃ±adir metadatos a una carpeta o a varios archivos seleccionados al mismo tiempo. Estos metadatos se aÃ±adirÃ¡ a todos los archivos que forman parte de la carpeta o de la selecciÃ³n, asÃ­ como a las subcarpetas. Recuerde que si usted asigna metadatos a una carpeta, todos los archivos nuevos que se encuentren en ella heredarÃ¡n automÃ¡ticamente los valores de la carpeta.
+      <Break/>
+      Si usted eligiÃ³ un metadato que ya aparece en algunos de los archivos seleccionados y hace click en "Agregar", el metadato se aÃ±adirÃ¡ a los demÃ¡s archivos de la selecciÃ³n.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      Usted tambiÃ©n puede darle estructura a los valores de los metadatos por medio de rutas, tal como se describe en la secciÃ³n de <Reference target="theenrichview">AsignaciÃ³n de metadatos</Reference>.
+    </Section>
+    <Section name="addingpreviouslydefinedmetadata">
+      <Title>AÃ±adiendo Metadatos Previamente Definidos</Title>
+      <ObviousSentence>Esta secciÃ³n explica la forma de aÃ±adir metadatos con valores que ya estÃ©n presentes en la estructura de valores.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>AÃ±adiendo metadatos a archivos</ContentsItem>
+	  <ContentsItem> AÃ±adiendo metadatos a carpetas o a varios archivos juntos</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Para aÃ±adir metadatos con un valor existente, seleccione primero el archivo y a continuaciÃ³n el valor requerido de la estructura de valores, expandiendo las carpetas tanto como sea necesario. El valor de la entrada seleccionada aparecerÃ¡ automÃ¡ticamente en el campo de texto (otra alternativa es utilizar las funciones de selecciÃ³n automÃ¡tica y completamiento automÃ¡tico de la estructura de valores). Haga click en "Agregar" para aÃ±adir el metadato al archivo seleccionado.
+      <Break/>
+      El proceso de aÃ±adir metadatos con valores existentes a carpetas o a varios archivos juntos es exactamente igual.
+    </Section>
+    <Section name="updatingmetadata">
+      <Title>Actualizando metadatos</Title>
+      <ObviousSentence>Esta secciÃ³n explica la forma de actualizar los metadatos asignados a un archivo.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Actualizando los metadatos de archivos</ContentsItem>
+	  <ContentsItem> Actualizando los metadatos de carpetas o de varios archivos juntos</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Para actualizar el valor de una parte del metadato, elija primero el archivo al que se aplicarÃ¡ dicho valor y luego el elemento de metadato cuyo valor desea cambiar. Su selecciÃ³n aparecerÃ¡ en los controles de ediciÃ³n de metadatos. Edite el valor y haga click en "Reemplazar" para modificarlo.
+      <Break/>
+      El proceso es el mismo cuando se actualiza un directorio que contiene subdirectorios o mÃºltiples archivos, pero sÃ³lo se pueden actualizar metadatos que sean comunes a todos los archivos y carpetas seleccionados.
+      <Break/>
+      La estructura de valores muestra todos los valores anteriores y no sÃ³lo aquellos que se asignaron en este momento. AsÃ­ el valor que usted reemplazÃ³ permanecerÃ¡ en la estructura de valores.
+    </Section>
+    <Section name="removingmetadata">
+      <Title>Eliminando metadatos</Title>
+      <ObviousSentence>Esta secciÃ³n explica la forma de eliminar los metadatos de un archivo.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Eliminando metadatos de un archivo</ContentsItem>
+	  <ContentsItem>Eliminando metadatos de carpetas o de varios archivos juntos</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Los metadatos se eliminan de la misma manera que se actualizan. Primero se selecciona un archivo de la estructura de directorios y subdirectorios, y se utiliza la tabla de metadatos para elegir el metadato que se desea eliminar. Si un metadato tiene asignado un valor, se activa el botÃ³n "Borrar". Haga click en Ã©l para quitar el metadato del archivo seleccionado. Los demÃ¡s archivos permanecerÃ¡n sin cambio y el valor se conservarÃ¡ en la estructura de valores.
+      <Break/>
+      Eliminar metadatos de directorios o de mÃºltiples archivos se hace de la misma forma.
+    </Section>
+    <Section name="reviewingmetadata">
+      <Title>Revisando los metadatos asignados</Title>
+      <ObviousSentence>Esta secciÃ³n describe la forma de ver todos los metadatos asignados a una colecciÃ³n completa.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>La tabla de auditorÃ­a</ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+	  <ContentsItem> El menÃº del botÃ³n derecho del mouse</ContentsItem>
+	  <ContentsItem>Filtros</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      En ocasiones es necesario ver los metadatos asignados a varios o a todos los archivos al mismo tiempo, por ejemplo, para determinar la forma en que quedan muchos archivos para trabajar en ellos o para tener una idea de la diferencia de tiempo entre las fechas.
+      <Break/>
+      Seleccione los archivos que desea examinar, pulse el botÃ³n derecho del ratÃ³n y elija "Metadatos AsignadosâŠ". Con lo que aparecerÃ¡ una ventana llamada "Todos los metadatos", ocupada en su mayor parte por una tabla de varias columnas. La primera columna muestra los nombres de los archivos, mientras que las filas muestran todos los valores asignados a dichos archivos.
+      <Break/>
+      Si se seleccionaron muchos archivos es posible que transcurra algÃºn tiempo antes de que se abra la ventana. Mientras tanto usted puede seguir usando la Interfaz de Bibliotecario.
+      <Break/>
+      Haga click en "Cerrar" para ocultar la ventana.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      TambiÃ©n se puede ver la tabla de "Todos los metadatos" seleccionando los archivos que desea examinar, haciendo click con el botÃ³n derecho del mouse y eligiendo la opciÃ³n "Metadatos asignados...". Si se seleccionÃ³ una carpeta, todos sus archivos estarÃ¡n incluidos en la tabla.
+      <Break/>
+      Cuando la tabla sea demasiado grande se puede refinar aplicando los filtros a las columnas. Conforme se aÃ±adan nuevos filtros, Ãºnicamente aquellas filas que concuerden con ellos seguirÃ¡n siendo visibles. Para establecer, modificar o borrar un filtro haga click en el icono con forma de embudo que se encuentra en la parte superior de la columna. Se le indicarÃ¡ que proporcione informaciÃ³n sobre el filtro. Una vez que un filtro se ha aplicado, el encabezado de la columna cambia de color.
+      <Break/>
+      El aviso tiene una pestaÃ±a "Sencilla" y una "Avanzada". La versiÃ³n sencilla filtra las columnas de tal manera que sÃ³lo muestren las filas que contienen un determinado valor ("*" corresponde a todos los valores). Los valores de los metadatos se pueden seleccionar de la lista. La versiÃ³n avanzada permite diferentes operaciones de concordancia: "debe empezar con", "no contiene", "alfabÃ©ticamente menos que" y "es igual a". El valor se puede editar con cualquier cadena de caracteres (incluyendo "*") y se puede elegir que la concordancia no tome en cuenta el caso. Finalmente, se puede especificar una segunda condiciÃ³n de concordancia que se puede usar para especificar un rango de valores (seleccionando "Y") o valores alternativos (seleccionando "O"). Debajo de esta Ã¡rea hay un cuadro que le permite cambiar el orden de clasificaciÃ³n (ascendente o descendente). Una vez que haya terminado, haga click en "Filtrar" para aplicar el nuevo filtro a la columna. Para quitar el filtro haga click en "Borrar filtro". Recuerde que los detalles del filtro se conservan incluso cuando el filtro se borra.
+      <Break/>
+      Por ejemplo, para ordenar la tabla elija una columna, seleccione el filtro por omisiÃ³n (un filtro Sencillo en "*") y escoja el orden ascendente o descendente.
+    </Section>
+    <Section name="importingpreviouslyassignedmetadata">
+      <Title>Importando metadatos previamente asignados</Title>
+      Esta secciÃ³n describe cÃ³mo importar metadtos previamente asignados, es decir, metadatos asignados a los documentos antes de que fuesen aÃ±adidos a la colecciÃ³n.
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Mientras se aÃ±aden archivos</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Si se han asignado previamente metadatos en una forma reconocible por la Interfaz de Bibliotecario, por ejemplo, cuando se seleccionan documentos de una colecciÃ³n Greenstone existente, entonces Ã©stos se importarÃ¡n automÃ¡ticamente cuando usted aÃ±ada el archivo. Para poder hacer esto los metadatos deben mapearse hacia el conjunto de metadatos disponible en la colecciÃ³n.
+      <Break/>
+      La Interfaz de Bibliotecario enviarÃ¡ un mensaje solicitando la informaciÃ³n necesaria. El mensaje incluirÃ¡ breves instrucciones y a continuaciÃ³n mostrarÃ¡ el nombre del elemento de metadato que se estÃ¡ importando, tal como aparece en el archivo fuente. Este campo no se podrÃ¡ editar o cambiar. A continuaciÃ³n elija el conjunto de metadatos hacia el que el nuevo elemento deberÃ¡ mapearse y el correspondiente elemento de metadato en ese conjunto. El sistema selecciona automÃ¡ticamente la correspondencia mÃ¡s cercana en tÃ©rminos de conjunto y elemento para el nuevo metadato.
+      <Break/>
+      DespuÃ©s de revisar el mapeo, usted puede elegir "AÃ±adir" para aÃ±adir el nuevo elemento de metadato al conjunto de metadatos que se haya seleccionado. (Esto sÃ³lo es posible si no hay un elemento del mismo nombre dentro del conjunto seleccionado.) "Reemplazar" mapea el nuevo elemento hacia el que el usuario haya elegido. Finalmente, "Ignorar" no importa ningÃºn metadato con este nombre de elemento. Una vez que usted haya especificado la forma de importar una parte del metadato, la informaciÃ³n del proceso se conserva durante todo el tiempo de vida de la colecciÃ³n.
+      <Break/>
+      Para mayor informaciÃ³n sobre los archivos metadata.xml que Greenstone utiliza para guardar metadatos, vea el CapÃ­tulo 2 de la GuÃ­a del Programador de Greenstone: Obteniendo el mÃ¡ximo beneficio de sus documentos.
+    </Section>
+  </Section>
+
+  <Section name="designingacollection">
+    <Title>DiseÃ±ando la apariencia de su colecciÃ³n</Title>
+    Una vez que los archivos estÃ¡n marcados con metadatos, a continuaciÃ³n se debe decidir la forma en que aparecerÃ¡n ante los usuarios como parte de una colecciÃ³n Greenstone. Â¿QuÃ© tipo de informaciÃ³n se podrÃ¡ buscar? Â¿De quÃ© medios se dispone para navegar por los documentos? Â¿En quÃ© idiomas? Â¿DÃ³nde aparecerÃ¡n los botones en la pÃ¡gina? Todas estas cosas se pueden personalizar. Esta secciÃ³n describe la forma de hacerlo.
+    <Section name="thedesignview">
+      <Title>La pantalla de diseÃ±o</Title>
+      Esta secciÃ³n le presenta la pantalla de DiseÃ±o y le explica la forma de navegar entre las diferentes opciones de este conjunto.
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Eligiendo la secciÃ³n de diseÃ±o</ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Con la Interfaz de Bibliotecario usted puede configurar la forma en que la colecciÃ³n aparecerÃ¡ frente al usuario. Las opciones se dividen en diferentes secciones, cada una relacionada con una etapa particular de navegaciÃ³n o presentaciÃ³n.
+      <Break/>
+      A la izquierda se encuentra una lista de las diferentes pantallas, en tanto que a la derecha estÃ¡n los controles asociados a la pantalla que estÃ¡ activa en ese momento. Para cambiar a una pantalla diferente haga click en la lista.
+      <Break/>
+      Para entender las etapas y los tÃ©rminos usados en el diseÃ±o de una colecciÃ³n, lea primero los CapÃ­tulos 1 y 2 de la GuÃ­a del Programador de Greenstone.
+    </Section>
+    <Section name="generalsettings">
+      <Title>Ajustes generales</Title>
+      Esta secciÃ³n explica la forma de revisar y modificar los ajustes generales asociados a una colecciÃ³n. Primero que nada, en la parte de "Secciones de diseÃ±o" haga click en "General".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Ajustes generales</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      AquÃ­ pueden modificarse los valores proporcionados durante la fase de creaciÃ³n de la colecciÃ³n.
+      <Break/>
+      En la parte superior de la pÃ¡gina hay un cuadro de instrucciones que aparece con cada una de las secciones, el cual contiene una breve lista de indicaciones que le recuerdan cuÃ¡les son las funciones disponibles.
+      <Break/>
+      Primero se encuentran las direcciones de correo electrÃ³nico del creador y del administrador de la colecciÃ³n. El siguiente campo le permite cambiar el tÃ­tulo de la colecciÃ³n. El directorio en el que se almacena la colecciÃ³n se muestra al lado, pero no puede editarse. El que sigue especifica (en forma de URL) el icono que aparecerÃ¡ en el Ã¡ngulo superior izquierdo de la pÃ¡gina "Acerca de" y el siguiente es el icono usado en la pÃ¡gina de la biblioteca digital Greenstone para conectarse a la colecciÃ³n. Entonces, una casilla controla que la colecciÃ³n sea o no accesible pÃºblicamente. Finalmente viene el Ã¡rea de texto que permite dar una "DescripciÃ³n de la ColecciÃ³n", tal como se explica en la secciÃ³n <Reference target="creatingacollection">Creando una nueva colecciÃ³n</Reference>.
+    </Section>
+    <Section name="plugins">
+      <Title>Plugins</Title>
+      Esta secciÃ³n describe la forma de configurar los plugins que la colecciÃ³n utiliza. Explica el modo de especificar los plugins que se utilizarÃ¡n, los parÃ¡metros que emplearÃ¡n y el orden en el que se aplicarÃ¡n. En la parte de "Secciones de diseÃ±o" haga click en "Plugins de documento".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>AÃ±adir un plugin</ContentsItem>
+	  <ContentsItem>Eliminar un plugin</ContentsItem>
+	  <ContentsItem>Configurar un plugin</ContentsItem>
+	  <ContentsItem>Cambiar el orden de los plugins</ContentsItem>
+        </ContentsGroup>
+	<ContentsGroup linkto="advanced">
+	  <ContentsItem>ConfiguraciÃ³n personalizada</ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Para aÃ±adir un plugin, escÃ³jalo de la lista "Seleccione el plugin que se va a aÃ±adir" que se encuentra en la parte inferior de la pantalla y haga click en "AÃ±adir plugin". AparecerÃ¡ una ventana titulada "Argumentos de configuraciÃ³n", la cual se explica mÃ¡s adelante. Una vez que usted haya configurado el nuevo plugin, este se aÃ±adirÃ¡ al final de la lista de "Plugins asignados actualmente". Note que, excepto para UnknownPlug, cada plugin sÃ³lo puede aparecer una vez en la lista.
+      <Break/>
+      Para quitar un plugin de la lista, selecciÃ³nelo y haga click en "Eliminar plugin".
+      <Break/>
+      Los plugins se configuran por medio de argumentos. Para modificarlos, seleccione un plugin de la lista y haga click en "Configurar plugin" (o doble click en el plugin). Aparece un diÃ¡logo "Configurando Argumentos" con varios controles para especificar argumentos.
+      <Break/>
+      Existen diferentes tipos de controles. Algunos son recuadros y al hacer click en ellos se aÃ±ade la opciÃ³n correspondiente al plugin. Otros son cadenas de texto con un recuadro y un campo de texto. Haga click en el cuadro para habilitarlo y escriba el argumento (expresiÃ³n regular, ruta de archivo, etc.). Otros son menÃºs descendentes desde los que se puede seleccionar un conjunto dado de valores. Para saber lo que hace un argumento, coloque el cursor del mouse encima de su nombre y la descripciÃ³n aparecerÃ¡.
+      <Break/>
+      Una vez que usted haya cambiado la configuraciÃ³n, haga click en "Aceptar" para guardar los cambios y cerrar el cuadro de diÃ¡logo o en "Cancelar" para cerrar el cuadro de diÃ¡logo sin cambiar ningÃºn argumento.
+      <Break/>
+      Los plugins de la lista se ejecutan en orden y en ocasiones Ã©ste es importante. Dos plugins, ArcPlug y RecPlug, son esenciales para el proceso de construcciÃ³n de la colecciÃ³n y se encuentran al final de la lista (separados del resto por una lÃ­nea). Para cambiar el orden de los demÃ¡s, seleccione el plugin que desea mover y haga click en "Mover arriba" o "Mover abajo".
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      La Interfaz de Bibliotecario hace lo posible por determinar los argumentos que un plugin soporta. Sin embargo, puede haber casos en los cuales el usuario quiera especificar argumentos especiales, y para esto se ofrece un campo de texto llamado "Argumentos personalizados" en la parte inferior. Cualquier texto que se escriba en Ã©l se agregarÃ¡ palabra por palabra al final del comando del plugin.
+    </Section>
+    <Section name="searchtypes">
+      <Title>Tipos de bÃºsqueda</Title>
+      Esta secciÃ³n explica la forma de modificar una nueva funciÃ³n de diseÃ±o de Greenstone llamada "Tipos de bÃºsqueda", que permite la bÃºsqueda por campos. En la parte de "Secciones de diseÃ±o" haga click en "Tipos de diseÃ±o".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Lo que significa activar las opciones de bÃºsqueda avanzada</ContentsItem>
+	  <ContentsItem>AÃ±adiendo un nuevo tipo de bÃºsqueda</ContentsItem>
+	  <ContentsItem>Eliminando un tipo de bÃºsqueda</ContentsItem>
+	  <ContentsItem>Cambiando el orden de los tipos de bÃºsqueda</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Cuando ingrese a la pantalla de tipos de bÃºsqueda marque primero el recuadro "Permitir bÃºsquedas avanzadas", lo cual activa todos los demÃ¡s controles. Esto transfiere la colecciÃ³n al formato Greenstone 2.4, el cual soporta la bÃºsqueda por campos y significa que (a) el diseÃ±o de Ã­ndices es diferente (lo cual se explica en la secciÃ³n <Reference target="searchindexes">Ãndices de bÃºsqueda</Reference>), (b) hay mÃ¡s fragmentos de texto para traducir (vea la secciÃ³n relativa a <Reference target="translatetext">TraducciÃ³n</Reference>) y (c) la colecciÃ³n no podrÃ¡ usarse con versiones anteriores de Greenstone. Si posteriormente usted quita la marca de este campo, la mayor parte de su colecciÃ³n regresarÃ¡ a Greenstone 2.39. No obstante, la Interfaz de Bibliotecario no podrÃ¡ convertir las especificaciones del nuevo Ã­ndice en las de las versiones anteriores, por lo que usted tendrÃ¡ que ingresarlas otra vez de forma manual.
+      <Break/>
+      Para aÃ±adir un tipo de bÃºsqueda, selecciÃ³nelo de la lista "Tipos de bÃºsqueda" y haga click en "AÃ±adir tipo de bÃºsqueda". Cada tipo puede aparecer en la lista solamente una vez.
+      <Break/>
+      Para quitar un tipo de bÃºsqueda, selecciÃ³nelo de la lista "Tipos de bÃºsqueda asignados actualmente" y haga click en "Eliminar tipo de bÃºsqueda". La lista deberÃ¡ contener al menos uno.
+      <Break/>
+      Para cambiar el orden de un tipo de bÃºsqueda, selecciÃ³nelo y haga click en "Mover arriba" o "Mover abajo". El primer tipo serÃ¡ el ajuste por omisiÃ³n.
+    </Section>
+    <Section name="searchindexes">
+      <Title>Ãndices de bÃºsqueda</Title>
+      Los Ã­ndices especifican las partes de la colecciÃ³n que se pueden buscar. Esta secciÃ³n explica la forma de aÃ±adir y eliminar Ã­ndices, asÃ­ como predeterminar un Ã­ndice por omisiÃ³n. En la parte correspondiente a "Secciones de diseÃ±o" haga click en "Ãndices de bÃºsqueda".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>AÃ±adir un Ã­ndice</ContentsItem>
+	  <ContentsItem>Editar un Ã­ndice</ContentsItem>
+	  <ContentsItem>Eliminar un Ã­ndice</ContentsItem>
+	  <ContentsItem>Predeterminar un Ã­ndice por omisiÃ³n</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Para aÃ±adir un Ã­ndice escriba el nombre que le quiera dar en el campo "Nombre del Ã­ndice". Seleccione las fuentes de informaciÃ³n que se van a indexar haciendo click en los recuadros que se encuentran a un lado. La lista mostrarÃ¡ todos los elementos de metadatos asignados, asÃ­ como el texto completo. DespuÃ©s de seleccionar las fuentes de datos, elija la granularidad del Ã­ndice usando el menÃº de "Nivel". Una vez que se han completado estos detalles, la opciÃ³n "AÃ±adir Ã­ndice" se activa (a menos que haya un Ã­ndice con los mismos parÃ¡metros). Haga click en ella para aÃ±adir el nuevo Ã­ndice.
+      <Break/>
+      Para editar un Ã­ndice, selecciÃ³nelo, cambie los detalles del Ã­ndice, y pulse "Reemplazar Ãndice".
+      <Break/>
+      Para quitar un Ã­ndice de la lista de Ã­ndices asignados, selecciÃ³nelo y haga click en "Eliminar Ã­ndice".
+      <Break/>
+      El Ã­ndice predeterminado es el que se usa en la pÃ¡gina de bÃºsqueda de la colecciÃ³n y lleva la etiqueta "[Indice por omisiÃ³n]" en la lista de "Ãndices asignados". Para establecer un Ã­ndice por omisiÃ³n, selecciÃ³nelo de la lista y haga click en "Predeterminar".
+      <Break/>
+      Si la opciÃ³n de bÃºsqueda avanzada estÃ¡ activa (a travÃ©s de la pantalla de tipos de bÃºsqueda) los controles de indexaciÃ³n serÃ¡n diferentes. Cada Ã­ndice se basa en una sola fuente de datos. Hay una nueva fuente de pseudodatos llamada "allfields" (todos los campos) que permite buscar a travÃ©s de todos los Ã­ndices especificados al mismo tiempo. Los niveles no se asignan a un Ã­ndice en particular, sino que se aplican a todos los Ã­ndices. De esta manera los Ã­ndices y niveles se aÃ±aden por separado. Los Ã­ndices se eliminan de la misma manera que arriba, pero el Ã­ndice por omisiÃ³n ya no se puede predeterminar: pasa a ser simplemente el primer Ã­ndice asignado.
+      <Break/>
+      Para crear Ã­ndices en todas las fuentes, haga click en el botÃ³n "AÃ±adir todas". El nombre de cada Ã­ndice serÃ¡ el de la fuente por omisiÃ³n. Para cambiar el nombre, seleccione un Ã­ndice, cambie sus detalles y haga click en "Reemplazar Ã­ndice".
+    </Section>
+    <Section name="partitionindexes">
+      <Title>Particiones</Title>
+      Los Ã­ndices se construyen sobre fuentes de metadatos o textos especÃ­ficos, por lo que el espacio de bÃºsqueda se puede controlar aÃºn mÃ¡s particionando el Ã­ndice, ya sea por idioma o por medio de un filtro determinado previamente. Esta secciÃ³n describe la forma de hacerlo. En la parte de "Secciones de diseÃ±o" haga click en "Particionar Ã­ndices".
+      <Break/>
+      La pantalla "Particionar Ã­ndices" tiene tres pestaÃ±as: "Definir filtros", "Asignar particiones" y "Asignar idiomas". Para saber mÃ¡s acerca de las particiones lea la secciÃ³n correspondiente a subcolecciones y subÃ­ndices en el CapÃ­tulo 2 de la GuÃ­a del Programador de Greenstone.
+      <Section name="definefilters">
+        <Title>Definir filtros</Title>
+        <ObviousSentence>Esta secciÃ³n explica la forma de definir un filtro de particiÃ³n.</ObviousSentence>
+	<Contents>
+	  <ContentsGroup linkto="simple">
+	    <ContentsItem>AÃ±adir un filtro</ContentsItem>
+	    <ContentsItem>Eliminar un filtro</ContentsItem>
+	    <ContentsItem>Actualizar un filtro</ContentsItem>
+          </ContentsGroup>
+        </Contents>
+	<Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+	Los filtros le permiten agrupar en una subcolecciÃ³n todos los documentos de un Ã­ndice para los cuales un valor de metadato sigue un patrÃ³n definido.
+	<Break/>
+	Para crear un filtro haga click en la pestaÃ±a "Definir filtros" y escriba el nombre del nuevo filtro en el campo titulado "Nombre del filtro de la subcolecciÃ³n". A continuaciÃ³n elija un atributo del documento con el cual se va a contrastar, ya sea un elemento de metadato o el nombre del archivo en cuestiÃ³n. Ingrese una expresiÃ³n regular que se utilizarÃ¡ durante la contrastaciÃ³n. Usted puede variar libremente entre "Incluir" documentos que concuerden con el filtro o "Excluirlos". Por Ãºltimo, usted tambiÃ©n puede especificar cualquiera de los indicadores estÃ¡ndar de expresiones regulares PERL para usarlos al momento de contrastar (p. ej. "i" para concordancias que no tomen en cuenta el caso). Haga click en "AÃ±adir filtro" para aÃ±adir el filtro a la lista de "Filtros definidos para la subcolecciÃ³n".
+	<Break/>
+	Para quitar un filtro de la lista, selecciÃ³nelo y haga click en "Eliminar filtro".
+	<Break/>
+	Para modificar un filtro, selecciÃ³nelo de la lista, cambie cualquiera de los valores que aparecen en los controles de ediciÃ³n y haga click en "Reemplazar filtro" para guardar los cambios.
+      </Section>
+      <Section name="assignpartitions">
+        <Title>Asignar particiones</Title>
+	<ObviousSentence>Esta secciÃ³n explica la forma de asignar un filtro de particiÃ³n definido anteriormente.</ObviousSentence>
+	<Contents>
+	  <ContentsGroup linkto="simple">
+	    <ContentsItem>AÃ±adir una particiÃ³n</ContentsItem>
+	    <ContentsItem>Eliminar una particiÃ³n</ContentsItem>
+	    <ContentsItem>Predeterminar una particiÃ³n por omisiÃ³n</ContentsItem>
+	    <ContentsItem>Borrar la particiÃ³n predeterminada</ContentsItem>
+          </ContentsGroup>
+        </Contents>
+	<Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+	Una vez que haya definido el filtro de una subcolecciÃ³n, utilice la pestaÃ±a "Asignar particiones" para construir los Ã­ndices del filtro (o de un grupo de filtros). Seleccione el filtro o los filtros que desee de la lista "Filtros definidos para la subcolecciÃ³n", ingrese un nombre para la particiÃ³n en el campo "Nombre de la particiÃ³n" y haga click en "AÃ±adir particiÃ³n".
+	<Break/>
+	Para quitar una particiÃ³n de la lista, selecciÃ³nela y haga click en "Eliminar particiÃ³n".
+	<Break/>
+	Para hacer que una particiÃ³n determinada sea el valor por omisiÃ³n, selecciÃ³nela de la lista y haga click en "Predeterminar".
+	<Break/>
+	Para borrar la particiÃ³n predeterminada haga click en "Borrar el valor por omisiÃ³n".
+      </Section>
+      <Section name="assignlanguages">
+        <Title>Asignar idiomas</Title>
+	Esta secciÃ³n describe la forma de limitar los Ã­ndices de bÃºsqueda a ciertos idiomas. Esto se hace generando una particiÃ³n por medio de la pestaÃ±a "Asignar idiomas" que se encuentra en la pantalla "Particionar Ã­ndices".
+	<Contents>
+	  <ContentsGroup linkto="simple">
+	    <ContentsItem>Controles de idioma</ContentsItem>
+	    <ContentsItem>AÃ±adir idioma</ContentsItem>
+	    <ContentsItem>Eliminar idioma</ContentsItem>
+	    <ContentsItem>Predeterminar un idioma por omisiÃ³n</ContentsItem>
+	    <ContentsItem>Borrar el idioma predeterminado</ContentsItem>
+          </ContentsGroup>
+        </Contents>
+	<Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+	Para aÃ±adir un nuevo idioma use la pestaÃ±a "Asignar idiomas" a fin de construirle un Ã­ndice. Seleccione el idioma en la lista descendente "Idioma que se va a aÃ±adir" y haga click en "AÃ±adir idioma".
+	<Break/>
+	Para quitar un idioma, escÃ³jalo de la lista "SelecciÃ³n de idiomas" y haga click en "Eliminar idioma".
+	<Break/>
+	Para establecer un idioma por omisiÃ³n, selecciÃ³nelo de la lista y haga click en "Predeterminar".
+	<Break/>
+	Para borrar el idioma predeterminado haga click en "Borrar el valor por omisiÃ³n".
+      </Section>
+    </Section>
+    <Section name="xcollectionsearching">
+      <Title>BÃºsqueda cruzada a travÃ©s de varias colecciones</Title>
+      Greenstone puede buscar a travÃ©s de varias colecciones distintas como si fueran una sola. Esto se hace creando una "supercolecciÃ³n" que abarca a las colecciones individuales. En la parte de "Secciones de diseÃ±o" haga click en "BÃºsqueda cruzada".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Seleccionando una colecciÃ³n</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      La pantalla de bÃºsqueda cruzada muestra una lista de las colecciones disponibles. La colecciÃ³n actual estÃ¡ marcada y no se puede quitar de la selecciÃ³n. Para aÃ±adir otra colecciÃ³n en la cual buscar de forma paralela, haga click en ella (o haga click en ella nuevamente para quitarla de la selecciÃ³n). Si sÃ³lo se seleccionÃ³ una colecciÃ³n, entonces no habrÃ¡ bÃºsqueda cruzada.
+      <Break/>
+      Para mayor informaciÃ³n vea el CapÃ­tulo 1 de la GuÃ­a del Programador de Greenstone.
+    </Section>
+    <Section name="classifiers">
+      <Title>Clasificadores</Title>
+      Esta secciÃ³n explica la forma de asignar "clasificadores" a una colecciÃ³n, los cuales se usan para navegar y buscar en ella. En la parte de "Secciones de diseÃ±o" haga click en "Clasificadores de exploraciÃ³n".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>SelecciÃ³n y configuraciÃ³n de un clasificador</ContentsItem>
+	  <ContentsItem>AÃ±adir un clasificador</ContentsItem>
+	  <ContentsItem>Eliminar un clasificador</ContentsItem>
+	  <ContentsItem>Configurar un clasificador</ContentsItem>
+	  <ContentsItem>Cambiar el orden de los clasificadores</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Para aÃ±adir un clasificador, escÃ³jalo por medio de la lista descendente "Seleccione el clasificador que se va a aÃ±adir" en la parte inferior de la pantalla y haga click en "AÃ±adir el clasificador especificado". Con esto aparecerÃ¡ una ventana titulada "Argumentos de configuraciÃ³n". Las instrucciones para este cuadro de diÃ¡logo son exactamente las mismas que para los plugins (vea la secciÃ³n <Reference target="plugins">Plugins</Reference>). Una vez que haya configurado el nuevo clasificador, Ã©ste se aÃ±adirÃ¡ al final de la lista de "Clasificadores asignados actualmente".
+      <Break/>
+      Para quitar un clasificador de la lista, selecciÃ³nelo y haga click en "Eliminar el clasificador seleccionado".
+      <Break/>
+      Para cambiar los argumentos de un clasificador, selecciÃ³nelo de la lista y haga click en "Configurar el clasificador seleccionado" o doble click en el nombre del clasificador.
+      <Break/>
+      El orden de los clasificadores en la barra de navegaciÃ³n de la colecciÃ³n se refleja aquÃ­. Para cambiarlo, seleccione el clasificador que desea mover y haga click en "Mover arriba" o "Mover abajo".
+      <Break/>
+      Para mayor informaciÃ³n sobre los clasificadores, lea el CapÃ­tulo 2 de la GuÃ­a del Programador de Greenstone: Obteniendo el mÃ¡ximo beneficio de sus documentos.
+    </Section>
+    <Section name="formatstatements">
+      <Title>Formatos</Title>
+      Los comandos de formato controlan la estructura y apariencia de la colecciÃ³n. Afectan aspectos como el lugar donde aparecerÃ¡n los botones cuando se muestra un documento y quÃ© vÃ­nculos despliega el clasificador DateList en pantalla. Los comandos de formato no son fÃ¡ciles de desarrollar, por lo que le recomendamos que lea el CapÃ­tulo 2 de la GuÃ­a del Programador de Greenstone. La presente secciÃ³n describe los controles de los distintos formatos y la forma en que la Interfaz de Bibliotecario le da acceso a ellos. En la parte de "Secciones de diseÃ±o" haga click en "Formatos".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Formateo</ContentsItem>
+	  <ContentsItem>AÃ±adir un comando de formato</ContentsItem>
+	  <ContentsItem>Eliminar un comando de formato</ContentsItem>
+	  <ContentsItem>Actualizar un comando de formato</ContentsItem>
+        </ContentsGroup>
+	<ContentsGroup linkto="advanced">
+	  <ContentsItem>Opciones avanzadas</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Se puede aplicar un comando de formato a cualquier cosa que se encuentre en la lista llamada "Elegir funciÃ³n", la cual incluye cada clasificador y una lista de funciones determinadas previamente. Cuando se selecciona una funciÃ³n existen dos tipos de controles. Algunas funciones simplemente se activan o se desactivan por medio de un recuadro. Otras requieren que se especifique una cadena de formato, para las cuales hay una lista descendente (llamada "Componente afectado") que permite seleccionar la parte de la funciÃ³n a la que se aplica la cadena (en caso necesario), un Ã¡rea de texto (llamada "cadena de formato HTML") para ingresar la cadena y una selecciÃ³n de "variables" definidas previamente. Para insertar una variable en su posiciÃ³n actual dentro de la cadena de formato, selecciÃ³nela de la lista descendente y haga click en "Insertar".
+      <Break/>
+      TambiÃ©n se puede especificar un formato predeterminado para un componente en particular seleccionando la funciÃ³n que estÃ¡ en blanco. Este formato se aplicarÃ¡ a todas las funciones aplicables a menos que se especifique lo contrario.
+      <Break/>
+      Para aÃ±adir un nuevo formato de comando llene la informaciÃ³n tal como se describe arriba y haga click en "AÃ±adir formato". El nuevo comando de formato aparecerÃ¡ en la lista de "Comandos de formato asignados actualmente". Solamente se podrÃ¡ asignar un comando de formato a cada combinaciÃ³n de funciÃ³n/componente.
+      <Break/>
+      Para quitar un comando de formato de la lista, selecciÃ³nelo y haga click en "Eliminar formato".
+      <Break/>
+      Para cambiar un comando de formato, selecciÃ³nelo de la lista, modifique sus parÃ¡metros y haga click en "Reemplazar formato".
+      <Break/>
+      Para mayor informaciÃ³n acerca de las variables y los componentes de las funciones lea el CapÃ­tulo 2 de la GuÃ­a del Programador de Greenstone.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      Si se marca el recuadro "Permitir opciones avanzadas" se activarÃ¡n algunas opciones de formateo avanzado. La lista de funciones que se pueden formatear cambia ligeramente y mÃ¡s variables estÃ¡n disponibles para usarlas en los comandos de formato, proporcionando asÃ­ un mayor control sobre el diseÃ±o de la pÃ¡gina.
+    </Section>
+    <Section name="translatetext">
+      <Title>TraducciÃ³n de textos</Title>
+      Esta secciÃ³n describe la pantalla de traducciÃ³n, donde se pueden definir fragmentos de texto en un idioma especÃ­fico para partes de la interfaz de la colecciÃ³n. En la parte de "Secciones de diseÃ±o" haga click en "Traducir texto".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>AÃ±adir traducciÃ³n</ContentsItem>
+	  <ContentsItem>Eliminar traducciÃ³n</ContentsItem>
+	  <ContentsItem>Actualizar traducciÃ³n</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Primero elija una entrada de la lista de "funciones". Las cadenas de texto asociadas a esta funciÃ³n aparecerÃ¡n abajo. Utilice la lista "Idioma de la traducciÃ³n" para seleccionar el idioma al que se va a traducir y escriba el texto traducido en el Ã¡rea de texto, haciendo referencia al "fragmento de texto inicial" en caso necesario. Una vez que haya terminado haga click en "AÃ±adir traducciÃ³n".
+      <Break/>
+      Para quitar una traducciÃ³n existente, selecciÃ³nela de la tabla "Traducciones asignadas" y haga click en "Eliminar traducciÃ³n".
+      <Break/>
+      Para actualizar una traducciÃ³n, selecciÃ³nela, edÃ­tela en el Ã¡rea de texto titulada "Texto traducido" y haga click en "Reemplazar traducciÃ³n".
+    </Section>
+    <Section name="metadatasets">
+      <Title>Conjuntos de metadatos</Title>
+      Esta secciÃ³n describe la pantalla de revisiÃ³n del conjunto de metadatos. En la parte de "Secciones de diseÃ±o" haga click en "Conjuntos de metadatos".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Conjuntos de metadatos disponibles</ContentsItem>
+          <ContentsItem>AÃ±adiendo conjuntos de metadatos</ContentsItem>
+          <ContentsItem>Editando conjuntos de metadatos</ContentsItem>
+          <ContentsItem>Borrando conjuntos de metadatos</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Esta pantalla se usa para revisar los conjuntos de metadatos que utiliza la colecciÃ³n, asÃ­ como los elementos que estÃ¡n disponibles dentro de cada conjunto. Elija uno de la lista de "Conjuntos de Metadatos Disponibles" para ver los detalles de sus elementos.
+      <Break/>
+      Para usar otro conjunto de metadatos con la colecciÃ³n cargada, pulse "AÃ±adir Conjunto de Metadatos", y seleccione el archivo de conjunto de metadatos (.mds) para el nuevo conjunto de metadatos.
+      <Break/>
+      La edicion de conjuntos de metadatos se hace con el Editor Greenstone para Conjuntos de Metadatos (GEMS). Pulsando el botÃ³n "Editar Conjunto de metadatos" obtendrÃ¡ informaciÃ³n sobre cÃ³mo utilizar GEMS.
+      <Break/>
+      Si ya no necesita mÃ¡s un conjunto de metadatos, selecciÃ³nelo y pulse "Borrar Conjunto de Metadatos" para eliminarlo. Si habÃ­a asignado metadatos a cualquier elemento del conjunto borrado, se le preguntarÃ¡ cÃ³mo actuar con estos metadatos cuando vuelva a abrir la colecciÃ³n.
+    </Section>
+  </Section>
+
+  <Section name="producingthecollection">
+    <Title> Produciendo una colecciÃ³n </Title>
+    Una vez que se han reunido los documentos para la colecciÃ³n, que se han enriquecido con metadatos y que se ha diseÃ±ado la forma en que la colecciÃ³n aparecerÃ¡, usted ya puede empezar a producir la colecciÃ³n. Esta secciÃ³n le explica cÃ³mo.
+    <Section name="thecreateview">
+      <Title>La pantalla de creaciÃ³n de la colecciÃ³n</Title>
+      <ObviousSentence>Esta secciÃ³n describe las caracterÃ­sticas de la pantalla "Crear" que se utiliza para producir una colecciÃ³n.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    ConstrucciÃ³n de la colecciÃ³n
+	  </ContentsItem>
+	  <ContentsItem>
+	    PresentaciÃ³n preliminar de la colecciÃ³n
+	  </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+	  <ContentsItem>Registro de mensajes</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      La pantalla "Crear" se utiliza para producir la colecciÃ³n ejecutando los guiones de los programas Greenstone con base en la informaciÃ³n que usted ha proporcionado. Al hacer click en el botÃ³n "Crear colecciÃ³n" se inicia el proceso de construcciÃ³n de la colecciÃ³n. El tiempo que se lleve dependerÃ¡ del tamaÃ±o de la colecciÃ³n y del nÃºmero de Ã­ndices que se estÃ©n creando (para colecciones de gran tamaÃ±o pueden ser horas). Una barra de progreso indica cuÃ¡nto se ha completado del proceso. Para cancelar el proceso en cualquier momento haga click en el botÃ³n "Cancelar la construcciÃ³n".
+      <Break/>
+      Una vez que la colecciÃ³n se ha construido exitosamente, al seleccionar "Vista previa de la colecciÃ³n" se iniciarÃ¡ un navegador de web que mostrarÃ¡ la pÃ¡gina inicial de la colecciÃ³n.
+      <Anchor name="advanced">Instrucciones avanzadas:</Anchor>
+      En modo Experto, puede usar las entradas del "Registro de mensajes" a la izquierda, para revisar intentos previos de construcciÃ³n de la colecciÃ³n, hayan tenido Ã©xito o no. Seleccione el registro que desee haciendo click en la fecha correspondiente en la lista "Historial de registro".
+    </Section>
+    <Section name="buildsettings">
+      <Title>Controles de importaciÃ³n y construcciÃ³n</Title>
+      Esta secciÃ³n explica la forma de tener acceso a los diferentes controles de importaciÃ³n y construcciÃ³n. Para mayor informaciÃ³n lea el CapÃ­tulo 1 de la GuÃ­a del Programador de Greenstone: Comprendiendo el proceso de creaciÃ³n de una colecciÃ³n.
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Controles generales</ContentsItem>
+	  <ContentsItem>Controles de importaciÃ³n</ContentsItem>
+	  <ContentsItem>Controles de construcciÃ³n</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      La forma de controlar los diferentes ajustes es similar a la de la ventana "Argumentos de configuraciÃ³n" que se describe en la secciÃ³n de <Reference target="plugins">Plugins</Reference>. Algunos campos requerirÃ¡n argumentos numÃ©ricos y usted puede escribirlos directamente en el campo o usar las flechas que se encuentran a un lado para aumentar o disminuir el nÃºmero (en algunos casos la interfaz limita el rango). Otros se activan (y desactivan) haciendo click en los recuadros correspondientes.
+    </Section>
+  </Section>
+
+  <Section name="miscellaneous">
+    <Title>MiscelÃ¡nea</Title>
+    Esta secciÃ³n describe funciones y caracterÃ­sticas de la Interfaz de Bibliotecario que no estÃ¡n asociadas a ninguna pantalla en particular.
+    <Section name="preferences">
+      <Title>Preferencias</Title>
+      Esta secciÃ³n explica el cuadro de preferencias, al cual se tiene acceso por medio de la opciÃ³n "Preferencias" en el menÃº "Archivo".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>General</ContentsItem>
+	  <ContentsItem>Modo</ContentsItem>
+	  <ContentsItem>Flujo de trabajo</ContentsItem>
+	  <ContentsItem>ConexiÃ³n</ContentsItem>
+	  <ContentsItem>Mensajes de advertencia</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      La primera opciÃ³n "General" es un campo de texto para introducir su direcciÃ³n de correo electrÃ³nico. SerÃ¡ usada para los elementos de metadatos "creador" y "administrador" de la colecciÃ³n. La siguiente opciÃ³n es un menÃº desplegable de los lenguajes en los cuales se puede presentar la Interfaz de Bibliotecario. Si usted cambia el diccionario eligiendo un idioma de la lista, entonces deberÃ¡ reinicar la Interfaz de Bibliotecario para poder cargar las cadenas de texto en el nuevo idioma.
+      <Break/>
+Si se marcÃ³ el recuadro "Ver metadatos extraÃ­dos", los diferentes controles que trabajan con metadatos siempre mostrarÃ¡n todos los metadatos que se han extraÃ­do automÃ¡ticamente de los documentos. Al quitar la marca del recuadro se ocultarÃ¡n estos metadatos (aunque la opciÃ³n seguirÃ¡ disponible durante el diseÃ±o de la colecciÃ³n y en la colecciÃ³n final). Si se marcÃ³ el recuadro "Mostrar el tamaÃ±o de los archivos" el tamaÃ±o del archivo aparecerÃ¡ junto a cada uno en las estructuras de archivos del Ã¡rea de trabajo y de la colecciÃ³n que se encuentran en las pantallas "Reunir" y "Enriquecer".
+      <Break/>
+      La pantalla de "Modo" se utiliza para controlar el nivel de detalle dentro de la interfaz. En su nivel mÃ¡s bÃ¡sico, "Asistente de Biblioteca", la pantalla de diseÃ±o estÃ¡ inhabilitada, los argumentos que requieren expresiones regulares estÃ¡n ocultos y el proceso de construcciÃ³n de la colecciÃ³n registra un mÃ­nimo de eventos. En comparaciÃ³n, el nivel mÃ¡s alto, "Avanzado", le da acceso a todas las funciones de diseÃ±o, incluyendo la posiciÃ³n de los plugins y argumentos con expresiones regulares, ademÃ¡s de permitir un registro completo del proceso de construcciÃ³n de la colecciÃ³n. Para cambiar o revisar los modos, haga click en el botÃ³n que se encuentra junto al modo en el que usted estÃ© interesado. De esta manera usted puede revisar rÃ¡pidamente el modo en el que estÃ¡ viendo la barra de tÃ­tulo de la Interfaz de Bibliotecario.
+      <Break/>
+      La Interfaz de Bibliotecario puede soportar diferentes flujos de trabajo determinando cuÃ¡les de las pestaÃ±as de las diferentes pantallas estarÃ¡n visibles. Utilice la pestaÃ±a "Flujo de trabajo" para determinar quÃ© pantallas estarÃ¡n disponibles marcando los recuadros que estÃ¡n junto al nombre de cada una de ellas. De forma alternativa utilice la lista descendente que se encuentra en la parte inferior para seleccionar las configuraciones predeterminadas. Al cerrar el cuadro de preferencias se aplicarÃ¡n los ajustes. Estos se guardan junto con la colecciÃ³n, no en el archivo de configuraciÃ³n de la Interfaz de Bibliotecario.
+      <Break/>
+      La pestaÃ±a de "ConexiÃ³n" le permite cambiar la ruta que lo conecta al servidor local de la biblioteca digital Greenstone, el cual se utiliza durante la presentaciÃ³n preliminar de la colecciÃ³n. TambiÃ©n le permite establecer la informaciÃ³n de proxy para conectarse a Internet (ejemplo: al descargar archivos; ver la secciÃ³n <Reference target="downloadingfiles">Descargando Archivos del Internet</Reference> para mÃ¡s detalles). Marque la casilla para permitir la conexiÃ³n por proxy y suministre los detalles de la direcciÃ³n y el nÃºmero de puerto del host que sirve de proxy. La conexiÃ³n con el proxy se establece cuando cierre el diÃ¡logo de Preferencias.
+      <Break/>
+      En el curso de una sesiÃ³n la Interfaz de Bibliotecario podrÃ¡ enviarle mensajes de advertencia que le avisarÃ¡n sobre las posibles consecuencias no previstas de una acciÃ³n. Usted puede desactivar los mensajes marcando el recuadro "No mostrar este mensaje otra vez". Para reactivarlos utilice la pestaÃ±a "Mensajes de advertencia" y marque los recuadros de los mensajes que desea volver a ver.
+    </Section>
+    <Section name="fileassociations">
+      <Title>AsociaciÃ³n de archivos</Title>
+      La Interfaz de Bibliotecario utiliza diferentes programas de aplicaciÃ³n para abrir tipos particulares de archivos. Esta secciÃ³n explica la forma de asignar y editar estas asociaciones.
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>Establecer una asociaciÃ³n</ContentsItem>
+	  <ContentsItem>Editar una asociaciÃ³n</ContentsItem>
+	  <ContentsItem>Eliminar una asociaciÃ³n</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Para modificar la asociaciÃ³n de archivos abra el menÃº "Archivo" y haga click en "AsociaciÃ³n de archivos".
+      <Break/>
+      Para establecer una asociaciÃ³n seleccione la extensiÃ³n del archivo de la lista descendente o escriba una nueva extensiÃ³n (no incluya "."). A continuaciÃ³n escriba en el campo correspondiente el comando que da inicio a la aplicaciÃ³n deseada o elija la aplicaciÃ³n en el cuadro "Explorar". "%1" se puede utilizar en el comando de inicio para insertar el nombre del archivo que se estÃ¡ abriendo. Una vez que se han llenado estos campos, el botÃ³n "Establecer asociaciÃ³n" se activarÃ¡, con lo que ya se puede hacer click en Ã©l para establecer la asociaciÃ³n.
+      <Break/>
+      Para editar una asociaciÃ³n, seleccione una extensiÃ³n de archivo existente. El comando asociado aparecerÃ¡ en el campo correspondiente a comando de inicio. EdÃ­telo y a continuaciÃ³n haga click en "Reemplazar asociaciÃ³n".
+      <Break/>
+      Para eliminar una asociaciÃ³n, seleccione la extensiÃ³n del archivo y haga click en "Eliminar asociaciÃ³n". La extensiÃ³n del archivo permanecerÃ¡ en una lista llamada "Para archivos que terminan en...".
+      <Break/>
+      Las asociaciones de archivos se guardan en la carpeta principal de la Interfaz de Bibliotecario en un archivo llamado "associations.xml".
+    </Section>
+    <Section name="exportingcollections">
+      <Title>Exportando colecciones a un CD-ROM</Title>
+      Esta secciÃ³n describe la forma de exportar colecciones a un CD-ROM Greenstone que se podrÃ¡ instalar automÃ¡ticamente.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>CÃ³mo exportar</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instrucciones bÃ¡sicas:</Anchor>
+      Greenstone puede exportar una o mÃ¡s colecciones a un CD-ROM para Windows que se podrÃ¡ instalar automÃ¡ticamente. Para ello es indispensable que el paquete "Exportar a un CD-ROM" estÃ© instalado. Esto no se incluye por omisiÃ³n, por lo que serÃ¡ necesario modificar la instalaciÃ³n para incluirlo.
+      <Break/>
+      Para exportar una colecciÃ³n abra el menÃº "Archivo" y seleccione la opciÃ³n "Exportar a un CD-ROM". Con esto aparecerÃ¡ una lista de colecciones Greenstone. Haga click en una para ver su descripciÃ³n. Marque los recuadros de las colecciones que desea exportar. Usted tambiÃ©n puede ingresar el nombre de CD-ROM en el cuadro correspondiente, el cual aparecerÃ¡ en el menÃº de Inicio una vez que el CD-ROM se haya instalado. A continuaciÃ³n haga click en "Exportar". El proceso incluye la copia de varios archivos y requerirÃ¡ de unos cuantos minutos.
+      <Break/>
+      Una vez que haya terminado Greenstone mostrarÃ¡ el nombre de una carpeta en la que se encontrarÃ¡n las colecciones que se han exportado. Utilice una quemadora de CDs para copiar sus contenidos en un CD-ROM en blanco.
+    </Section>
+  </Section>
+</Document>
Index: /tags/gsdl-2_61-distribution/gli/help/es/help_index.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/help_index.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/help_index.xml	(revision 10506)
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Document><Section name="introduction"><Title>IntroducciÃ³n</Title><Section name="ofmiceandmenus"><Title>De menÃºs y ratones</Title></Section><Section name="howtoavoidthisdocument"><Title>Temas de ayuda</Title></Section></Section><Section name="startingoff"><Title>Para empezar</Title><Section name="creatingacollection"><Title>Creando una nueva colecciÃ³n</Title></Section><Section name="savingacollection"><Title>Guardar la colecciÃ³n</Title></Section><Section name="openingacollection"><Title>Abriendo una colecciÃ³n existente</Title></Section><Section name="deletingcollections"><Title>Borrando colecciones</Title></Section></Section><Section name="downloadingfiles"><Title>Descargando archivos de Internet</Title><Section name="themirrorview"><Title>La vista en Bajar</Title></Section></Section><Section name="collectingfiles"><Title>Reuniendo archivos para su colecciÃ³n</Title><Section name="thegatherview"><Title>La pantalla de selecciÃ³n de documentos</Title></Section><Section name="creatingfolders"><Title>Creando carpetas</Title></Section><Section name="addingfiles"><Title>AÃ±adiendo archivos</Title></Section><Section name="removingfiles"><Title>Eliminando archivos</Title></Section><Section name="filteringthetree"><Title>Filtrando la estructura de directorios y subdirectorios</Title></Section></Section><Section name="enrichingacollection"><Title>Enriqueciendo la colecciÃ³n con metadatos</Title><Section name="theenrichview"><Title>La pantalla de asignaciÃ³n de metadatos</Title></Section><Section name="selectingmetadatasets"><Title>Seleccionando conjuntos de metadatos</Title></Section><Section name="appendingmetadata"><Title>Agregando nuevos metadatos</Title></Section><Section name="addingpreviouslydefinedmetadata"><Title>AÃ±adiendo Metadatos Previamente Definidos</Title></Section><Section name="updatingmetadata"><Title>Actualizando metadatos</Title></Section><Section name="removingmetadata"><Title>Eliminando metadatos</Title></Section><Section name="reviewingmetadata"><Title>Revisando los metadatos asignados</Title></Section><Section name="importingpreviouslyassignedmetadata"><Title>Importando metadatos previamente asignados</Title></Section></Section><Section name="designingacollection"><Title>DiseÃ±ando la apariencia de su colecciÃ³n</Title><Section name="thedesignview"><Title>La pantalla de diseÃ±o</Title></Section><Section name="generalsettings"><Title>Ajustes generales</Title></Section><Section name="plugins"><Title>Plugins</Title></Section><Section name="searchtypes"><Title>Tipos de bÃºsqueda</Title></Section><Section name="searchindexes"><Title>Ãndices de bÃºsqueda</Title></Section><Section name="partitionindexes"><Title>Particiones</Title><Section name="definefilters"><Title>Definir filtros</Title></Section><Section name="assignpartitions"><Title>Asignar particiones</Title></Section><Section name="assignlanguages"><Title>Asignar idiomas</Title></Section></Section><Section name="xcollectionsearching"><Title>BÃºsqueda cruzada a travÃ©s de varias colecciones</Title></Section><Section name="classifiers"><Title>Clasificadores</Title></Section><Section name="formatstatements"><Title>Formatos</Title></Section><Section name="translatetext"><Title>TraducciÃ³n de textos</Title></Section><Section name="metadatasets"><Title>Conjuntos de metadatos</Title></Section></Section><Section name="producingthecollection"><Title> Produciendo una colecciÃ³n </Title><Section name="thecreateview"><Title>La pantalla de creaciÃ³n de la colecciÃ³n</Title></Section><Section name="buildsettings"><Title>Controles de importaciÃ³n y construcciÃ³n</Title></Section></Section><Section name="miscellaneous"><Title>MiscelÃ¡nea</Title><Section name="preferences"><Title>Preferencias</Title></Section><Section name="fileassociations"><Title>AsociaciÃ³n de archivos</Title></Section><Section name="exportingcollections"><Title>Exportando colecciones a un CD-ROM</Title></Section></Section></Document>
Index: /tags/gsdl-2_61-distribution/gli/help/es/howtoavoidthisdocument.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/howtoavoidthisdocument.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/howtoavoidthisdocument.htm	(revision 10506)
@@ -0,0 +1,57 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="howtoavoidthisdocument"><font size="5" face="Verdana"><strong>1.2: Temas de ayuda</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      &iexcl;Usted no necesita leer todo el texto de ayuda! S&oacute;lo lea lo suficiente para saber c&oacute;mo obtener ayuda cuando la necesite.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Ayuda sensible al contexto</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Cuadros de sugerencias</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Otros documentos</td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      El comando del men&uacute; "Ayuda" indica los que ser&iacute;an los temas de ayuda m&aacute;s apropiados por medio de un peque&ntilde;o icono en forma de libro.
+      <p></p>
+      Para muchos controles si se coloca el mouse encima de ellos aparecer&aacute; un "cuadro de sugerencias" en el cual se explica su funci&oacute;n.
+      <p></p>
+      Antes de usar la Interfaz de Bibliotecario lea primero la documentaci&oacute;n de Greenstone.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/importingpreviouslyassignedmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/importingpreviouslyassignedmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/importingpreviouslyassignedmetadata.htm	(revision 10506)
@@ -0,0 +1,51 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="importingpreviouslyassignedmetadata"><font size="5" face="Verdana"><strong>5.8: Importando metadatos previamente asignados</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe c&oacute;mo importar metadtos previamente asignados, es decir, metadatos asignados a los documentos antes de que fuesen a&ntilde;adidos a la colecci&oacute;n.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Mientras se a&ntilde;aden archivos</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Si se han asignado previamente metadatos en una forma reconocible por la Interfaz de Bibliotecario, por ejemplo, cuando se seleccionan documentos de una colecci&oacute;n Greenstone existente, entonces &eacute;stos se importar&aacute;n autom&aacute;ticamente cuando usted a&ntilde;ada el archivo. Para poder hacer esto los metadatos deben mapearse hacia el conjunto de metadatos disponible en la colecci&oacute;n.
+      <p></p>
+      La Interfaz de Bibliotecario enviar&aacute; un mensaje solicitando la informaci&oacute;n necesaria. El mensaje incluir&aacute; breves instrucciones y a continuaci&oacute;n mostrar&aacute; el nombre del elemento de metadato que se est&aacute; importando, tal como aparece en el archivo fuente. Este campo no se podr&aacute; editar o cambiar. A continuaci&oacute;n elija el conjunto de metadatos hacia el que el nuevo elemento deber&aacute; mapearse y el correspondiente elemento de metadato en ese conjunto. El sistema selecciona autom&aacute;ticamente la correspondencia m&aacute;s cercana en t&eacute;rminos de conjunto y elemento para el nuevo metadato.
+      <p></p>
+      Despu&eacute;s de revisar el mapeo, usted puede elegir "A&ntilde;adir" para a&ntilde;adir el nuevo elemento de metadato al conjunto de metadatos que se haya seleccionado. (Esto s&oacute;lo es posible si no hay un elemento del mismo nombre dentro del conjunto seleccionado.) "Reemplazar" mapea el nuevo elemento hacia el que el usuario haya elegido. Finalmente, "Ignorar" no importa ning&uacute;n metadato con este nombre de elemento. Una vez que usted haya especificado la forma de importar una parte del metadato, la informaci&oacute;n del proceso se conserva durante todo el tiempo de vida de la colecci&oacute;n.
+      <p></p>
+      Para mayor informaci&oacute;n sobre los archivos metadata.xml que Greenstone utiliza para guardar metadatos, vea el Cap&iacute;tulo 2 de la Gu&iacute;a del Programador de Greenstone: Obteniendo el m&aacute;ximo beneficio de sus documentos.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/introduction.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/introduction.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/introduction.htm	(revision 10506)
@@ -0,0 +1,17 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="introduction"><font size="5" face="Verdana"><strong>1: Introducci&oacute;n</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    La Interfaz de Bibliotecario de Greenstone es una herramienta que permite reunir y marcar documentos para luego crear colecciones digitales con ellos, d&aacute;ndole f&aacute;cil acceso a todas las funciones de los programas de software de la Biblioteca Digital Greenstone desde una interfaz gr&aacute;fica de usuario con la que s&oacute;lo tiene que apuntar y hacer click.
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/metadatasets.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/metadatasets.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/metadatasets.htm	(revision 10506)
@@ -0,0 +1,63 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="metadatasets"><font size="5" face="Verdana"><strong>6.11: Conjuntos de metadatos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe la pantalla de revisi&oacute;n del conjunto de metadatos. En la parte de "Secciones de dise&ntilde;o" haga click en "Conjuntos de metadatos".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Conjuntos de metadatos disponibles</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adiendo conjuntos de metadatos</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Editando conjuntos de metadatos</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Borrando conjuntos de metadatos</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Esta pantalla se usa para revisar los conjuntos de metadatos que utiliza la colecci&oacute;n, as&iacute; como los elementos que est&aacute;n disponibles dentro de cada conjunto. Elija uno de la lista de "Conjuntos de Metadatos Disponibles" para ver los detalles de sus elementos.
+      <p></p>
+      Para usar otro conjunto de metadatos con la colecci&oacute;n cargada, pulse "A&ntilde;adir Conjunto de Metadatos", y seleccione el archivo de conjunto de metadatos (.mds) para el nuevo conjunto de metadatos.
+      <p></p>
+      La edicion de conjuntos de metadatos se hace con el Editor Greenstone para Conjuntos de Metadatos (GEMS). Pulsando el bot&oacute;n "Editar Conjunto de metadatos" obtendr&aacute; informaci&oacute;n sobre c&oacute;mo utilizar GEMS.
+      <p></p>
+      Si ya no necesita m&aacute;s un conjunto de metadatos, selecci&oacute;nelo y pulse "Borrar Conjunto de Metadatos" para eliminarlo. Si hab&iacute;a asignado metadatos a cualquier elemento del conjunto borrado, se le preguntar&aacute; c&oacute;mo actuar con estos metadatos cuando vuelva a abrir la colecci&oacute;n.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/miscellaneous.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/miscellaneous.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/miscellaneous.htm	(revision 10506)
@@ -0,0 +1,18 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="miscellaneous"><font size="5" face="Verdana"><strong>8: Miscel&aacute;nea</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Esta secci&oacute;n describe funciones y caracter&iacute;sticas de la Interfaz de Bibliotecario que no est&aacute;n asociadas a ninguna pantalla en particular.
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/ofmiceandmenus.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/ofmiceandmenus.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/ofmiceandmenus.htm	(revision 10506)
@@ -0,0 +1,80 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="ofmiceandmenus"><font size="5" face="Verdana"><strong>1.1: De men&uacute;s y ratones</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n proporciona informaci&oacute;n b&aacute;sica para poder trabajar con la Interfaz de Bibliotecario. Si est&aacute; familiarizado con programas como Internet Explorer o Microsoft Office y est&aacute; acostumbrado a usar el mouse, entonces pase a la <a href="howtoavoidthisdocument.htm#howtoavoidthisdocument">siguiente secci&oacute;n</a>.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Conceptos b&aacute;sicos
+            <tr>
+<td colspan="2"> </td><td colspan="1">Movimientos del mouse</td>
+</tr>
+            
+<tr>
+<td colspan="2"> </td><td colspan="1">Teclado</td>
+</tr>
+          
+</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Salir del programa</td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Teclas de m&eacute;todo abreviado</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      La Interfaz de Bibliotecario sigue las convenciones de Microsoft y se apoya en el conocimiento que com&uacute;nmente se tiene de Windows.
+      <p></p>
+      Cualquier parte de la pantalla con la que usted interact&uacute;e, como un bot&oacute;n o un campo de texto, se llama "control". En todo momento un bot&oacute;n o campo de texto llamado "control activo" aparecer&aacute; resaltado y responder&aacute; a las instrucciones del teclado. Asimismo, varios controles le permiten seleccionar las partes que est&eacute;n resaltadas en azul marino. Algunos controles tambi&eacute;n pueden aparecer sombreados para indicar que no est&aacute;n disponibles.
+      <p></p>
+      Usted puede mover y hacer click con el bot&oacute;n izquierdo o derecho del mouse de la forma acostumbrada. Muchos componentes tambi&eacute;n se pueden "arrastrar" haciendo click en ellos y sosteniendo el bot&oacute;n izquierdo del mouse, para luego moverlos y "colocarlos" en alg&uacute;n otro lugar soltando el bot&oacute;n. Normalmente el lugar de destino cambia de apariencia cuando un componente pasa sobre &eacute;l.
+      <p></p>
+      Usted puede usar el teclado para escribir en los campos de texto. Muchos controles tambi&eacute;n se pueden ejecutar por medio del teclado, lo que se indica por medio de corchetes -- por ejemplo la tecla de tabulaci&oacute;n [Tab] cambia el control activo. El signo de m&aacute;s (+) indica que otras teclas deben oprimirse al mismo tiempo.
+      <p></p>
+      Salga de la Interfaz de Bibliotecario eligiendo "Salir" en el men&uacute; "Archivo". Su colecci&oacute;n se guardar&aacute; primero.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      Para tener acceso a un men&uacute;, oprima el bot&oacute;n [ALT] y presione la letra correspondiente (la cual aparece subrayada). Por ejemplo, para desplegar el men&uacute; "Archivo" oprima [ALT] + [A]. Para elegir un comando presione la tecla correspondiente. Por ejemplo, en el men&uacute; "Archivo" presione [G] para "Guardar" la colecci&oacute;n.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/openingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/openingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/openingacollection.htm	(revision 10506)
@@ -0,0 +1,64 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="openingacollection"><font size="5" face="Verdana"><strong>2.3: Abriendo una colecci&oacute;n existente</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n le dice la forma de abrir una colecci&oacute;n existente por medio del mensaje Abrir Colecci&oacute;n.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">C&oacute;mo abrir una colecci&oacute;n</td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Colecciones protegidas</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Colecciones heredadas</td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Para abrir una colecci&oacute;n existente elija la opci&oacute;n "Abrir" en el men&uacute; "Archivo". Con esto aparecer&aacute; una lista de sus colecciones Greenstone. Seleccione una para ver su descripci&oacute;n y haga click en "Abrir" para cargarla. Si busca una colecci&oacute;n que resida fuera de la carpeta de "colecciones" de Greenstone, entonces haga click en "Explorar" para que aparezca un cuadro de di&aacute;logo que le permita buscar en el sistema de archivos.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      En caso de que m&aacute;s de una Interfaz de Bibliotecario de Greenstone est&eacute; corriendo al mismo tiempo, los directorios pertinentes se "bloquean" para evitar interferencias. Al abrir una colecci&oacute;n se crea un peque&ntilde;o archivo de bloqueo temporal en la carpeta. Antes de abrir una colecci&oacute;n la Interfaz de Bibliotecario revisa que no haya un archivo de bloqueo en ella. Se puede saber si la colecci&oacute;n est&aacute; bloqueada por el color de su icono: verde para una colecci&oacute;n normal, rojo para una colecci&oacute;n bloqueada. Sin embargo, cuando se sale prematuramente de la Interfaz de Bibliotecario el archivo de bloqueo a veces permanece en la carpeta. Cuando posteriormente se abre esta colecci&oacute;n, la Biblioteca Digital le pregunta si quiere tomar el control. Por favor, nunca le quite el control de una colecci&oacute;n a alguien que este trabajando en ese momento con ella.
+      <p></p>
+      Cuando usted abra una colecci&oacute;n que no haya sido creada por medio de la Interfaz de Bibliotecario de Greenstone se le pedir&aacute; que seleccione uno o m&aacute;s conjuntos de metadatos. Si no selecciona ninguno, entonces los metadatos existentes se ignorar&aacute;n. De otra manera los metadatos se importar&aacute;n tal como son cuando usted arrastre los archivos. El proceso se describe en el documento llamado <a href="importingpreviouslyassignedmetadata.htm#importingpreviouslyassignedmetadata">Importando Metadatos Previamente Asignados</a>.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/partitionindexes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/partitionindexes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/partitionindexes.htm	(revision 10506)
@@ -0,0 +1,20 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="partitionindexes"><font size="5" face="Verdana"><strong>6.6: Particiones</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Los &iacute;ndices se construyen sobre fuentes de metadatos o textos espec&iacute;ficos, por lo que el espacio de b&uacute;squeda se puede controlar a&uacute;n m&aacute;s particionando el &iacute;ndice, ya sea por idioma o por medio de un filtro determinado previamente. Esta secci&oacute;n describe la forma de hacerlo. En la parte de "Secciones de dise&ntilde;o" haga click en "Particionar &iacute;ndices".
+      <p></p>
+      La pantalla "Particionar &iacute;ndices" tiene tres pesta&ntilde;as: "Definir filtros", "Asignar particiones" y "Asignar idiomas". Para saber m&aacute;s acerca de las particiones lea la secci&oacute;n correspondiente a subcolecciones y sub&iacute;ndices en el Cap&iacute;tulo 2 de la Gu&iacute;a del Programador de Greenstone.
+      
+      
+      
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/plugins.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/plugins.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/plugins.htm	(revision 10506)
@@ -0,0 +1,80 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="plugins"><font size="5" face="Verdana"><strong>6.3: Plugins</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe la forma de configurar los plugins que la colecci&oacute;n utiliza. Explica el modo de especificar los plugins que se utilizar&aacute;n, los par&aacute;metros que emplear&aacute;n y el orden en el que se aplicar&aacute;n. En la parte de "Secciones de dise&ntilde;o" haga click en "Plugins de documento".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adir un plugin</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminar un plugin</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Configurar un plugin</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Cambiar el orden de los plugins</td>
+</tr>
+        
+	
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Configuraci&oacute;n personalizada</td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Para a&ntilde;adir un plugin, esc&oacute;jalo de la lista "Seleccione el plugin que se va a a&ntilde;adir" que se encuentra en la parte inferior de la pantalla y haga click en "A&ntilde;adir plugin". Aparecer&aacute; una ventana titulada "Argumentos de configuraci&oacute;n", la cual se explica m&aacute;s adelante. Una vez que usted haya configurado el nuevo plugin, este se a&ntilde;adir&aacute; al final de la lista de "Plugins asignados actualmente". Note que, excepto para UnknownPlug, cada plugin s&oacute;lo puede aparecer una vez en la lista.
+      <p></p>
+      Para quitar un plugin de la lista, selecci&oacute;nelo y haga click en "Eliminar plugin".
+      <p></p>
+      Los plugins se configuran por medio de argumentos. Para modificarlos, seleccione un plugin de la lista y haga click en "Configurar plugin" (o doble click en el plugin). Aparece un di&aacute;logo "Configurando Argumentos" con varios controles para especificar argumentos.
+      <p></p>
+      Existen diferentes tipos de controles. Algunos son recuadros y al hacer click en ellos se a&ntilde;ade la opci&oacute;n correspondiente al plugin. Otros son cadenas de texto con un recuadro y un campo de texto. Haga click en el cuadro para habilitarlo y escriba el argumento (expresi&oacute;n regular, ruta de archivo, etc.). Otros son men&uacute;s descendentes desde los que se puede seleccionar un conjunto dado de valores. Para saber lo que hace un argumento, coloque el cursor del mouse encima de su nombre y la descripci&oacute;n aparecer&aacute;.
+      <p></p>
+      Una vez que usted haya cambiado la configuraci&oacute;n, haga click en "Aceptar" para guardar los cambios y cerrar el cuadro de di&aacute;logo o en "Cancelar" para cerrar el cuadro de di&aacute;logo sin cambiar ning&uacute;n argumento.
+      <p></p>
+      Los plugins de la lista se ejecutan en orden y en ocasiones &eacute;ste es importante. Dos plugins, ArcPlug y RecPlug, son esenciales para el proceso de construcci&oacute;n de la colecci&oacute;n y se encuentran al final de la lista (separados del resto por una l&iacute;nea). Para cambiar el orden de los dem&aacute;s, seleccione el plugin que desea mover y haga click en "Mover arriba" o "Mover abajo".
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      La Interfaz de Bibliotecario hace lo posible por determinar los argumentos que un plugin soporta. Sin embargo, puede haber casos en los cuales el usuario quiera especificar argumentos especiales, y para esto se ofrece un campo de texto llamado "Argumentos personalizados" en la parte inferior. Cualquier texto que se escriba en &eacute;l se agregar&aacute; palabra por palabra al final del comando del plugin.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/preferences.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/preferences.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/preferences.htm	(revision 10506)
@@ -0,0 +1,71 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="preferences"><font size="5" face="Verdana"><strong>8.1: Preferencias</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica el cuadro de preferencias, al cual se tiene acceso por medio de la opci&oacute;n "Preferencias" en el men&uacute; "Archivo".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">General</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Modo</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Flujo de trabajo</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Conexi&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Mensajes de advertencia</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      La primera opci&oacute;n "General" es un campo de texto para introducir su direcci&oacute;n de correo electr&oacute;nico. Ser&aacute; usada para los elementos de metadatos "creador" y "administrador" de la colecci&oacute;n. La siguiente opci&oacute;n es un men&uacute; desplegable de los lenguajes en los cuales se puede presentar la Interfaz de Bibliotecario. Si usted cambia el diccionario eligiendo un idioma de la lista, entonces deber&aacute; reinicar la Interfaz de Bibliotecario para poder cargar las cadenas de texto en el nuevo idioma.
+      <p></p>
+Si se marc&oacute; el recuadro "Ver metadatos extra&iacute;dos", los diferentes controles que trabajan con metadatos siempre mostrar&aacute;n todos los metadatos que se han extra&iacute;do autom&aacute;ticamente de los documentos. Al quitar la marca del recuadro se ocultar&aacute;n estos metadatos (aunque la opci&oacute;n seguir&aacute; disponible durante el dise&ntilde;o de la colecci&oacute;n y en la colecci&oacute;n final). Si se marc&oacute; el recuadro "Mostrar el tama&ntilde;o de los archivos" el tama&ntilde;o del archivo aparecer&aacute; junto a cada uno en las estructuras de archivos del &aacute;rea de trabajo y de la colecci&oacute;n que se encuentran en las pantallas "Reunir" y "Enriquecer".
+      <p></p>
+      La pantalla de "Modo" se utiliza para controlar el nivel de detalle dentro de la interfaz. En su nivel m&aacute;s b&aacute;sico, "Asistente de Biblioteca", la pantalla de dise&ntilde;o est&aacute; inhabilitada, los argumentos que requieren expresiones regulares est&aacute;n ocultos y el proceso de construcci&oacute;n de la colecci&oacute;n registra un m&iacute;nimo de eventos. En comparaci&oacute;n, el nivel m&aacute;s alto, "Avanzado", le da acceso a todas las funciones de dise&ntilde;o, incluyendo la posici&oacute;n de los plugins y argumentos con expresiones regulares, adem&aacute;s de permitir un registro completo del proceso de construcci&oacute;n de la colecci&oacute;n. Para cambiar o revisar los modos, haga click en el bot&oacute;n que se encuentra junto al modo en el que usted est&eacute; interesado. De esta manera usted puede revisar r&aacute;pidamente el modo en el que est&aacute; viendo la barra de t&iacute;tulo de la Interfaz de Bibliotecario.
+      <p></p>
+      La Interfaz de Bibliotecario puede soportar diferentes flujos de trabajo determinando cu&aacute;les de las pesta&ntilde;as de las diferentes pantallas estar&aacute;n visibles. Utilice la pesta&ntilde;a "Flujo de trabajo" para determinar qu&eacute; pantallas estar&aacute;n disponibles marcando los recuadros que est&aacute;n junto al nombre de cada una de ellas. De forma alternativa utilice la lista descendente que se encuentra en la parte inferior para seleccionar las configuraciones predeterminadas. Al cerrar el cuadro de preferencias se aplicar&aacute;n los ajustes. Estos se guardan junto con la colecci&oacute;n, no en el archivo de configuraci&oacute;n de la Interfaz de Bibliotecario.
+      <p></p>
+      La pesta&ntilde;a de "Conexi&oacute;n" le permite cambiar la ruta que lo conecta al servidor local de la biblioteca digital Greenstone, el cual se utiliza durante la presentaci&oacute;n preliminar de la colecci&oacute;n. Tambi&eacute;n le permite establecer la informaci&oacute;n de proxy para conectarse a Internet (ejemplo: al descargar archivos; ver la secci&oacute;n <a href="downloadingfiles.htm#downloadingfiles">Descargando Archivos del Internet</a> para m&aacute;s detalles). Marque la casilla para permitir la conexi&oacute;n por proxy y suministre los detalles de la direcci&oacute;n y el n&uacute;mero de puerto del host que sirve de proxy. La conexi&oacute;n con el proxy se establece cuando cierre el di&aacute;logo de Preferencias.
+      <p></p>
+      En el curso de una sesi&oacute;n la Interfaz de Bibliotecario podr&aacute; enviarle mensajes de advertencia que le avisar&aacute;n sobre las posibles consecuencias no previstas de una acci&oacute;n. Usted puede desactivar los mensajes marcando el recuadro "No mostrar este mensaje otra vez". Para reactivarlos utilice la pesta&ntilde;a "Mensajes de advertencia" y marque los recuadros de los mensajes que desea volver a ver.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/producingthecollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/producingthecollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/producingthecollection.htm	(revision 10506)
@@ -0,0 +1,17 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="producingthecollection"><font size="5" face="Verdana"><strong>7:  Produciendo una colecci&oacute;n </strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Una vez que se han reunido los documentos para la colecci&oacute;n, que se han enriquecido con metadatos y que se ha dise&ntilde;ado la forma en que la colecci&oacute;n aparecer&aacute;, usted ya puede empezar a producir la colecci&oacute;n. Esta secci&oacute;n le explica c&oacute;mo.
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/removingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/removingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/removingfiles.htm	(revision 10506)
@@ -0,0 +1,55 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="removingfiles"><font size="5" face="Verdana"><strong>4.4: Eliminando archivos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe la forma de eliminar archivos y carpetas de su colecci&oacute;n.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">El bot&oacute;n eliminar</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">La tecla suprimir</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Arrastrarlos y colocarlos en el bot&oacute;n "Eliminar"</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Existen varios m&eacute;todos para eliminar archivos y carpetas. Primero se deben indicar los elementos que se desea eliminar seleccionando los archivos y carpetas tal como se describe en la secci&oacute;n de <a href="thegatherview.htm#thegatherview">selecci&oacute;n de documentos para la colecci&oacute;n</a>.
+      <p></p>
+      Una vez que se han seleccionado los archivos, haga click en el bot&oacute;n "Eliminar" o presione la tecla [Del], [Supr] o [Suprimir], dependiendo del teclado de su computadora, o arr&aacute;strelos desde la colecci&oacute;n hasta el bot&oacute;n "Eliminar" y su&eacute;ltelos ah&iacute;.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/removingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/removingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/removingmetadata.htm	(revision 10506)
@@ -0,0 +1,51 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="removingmetadata"><font size="5" face="Verdana"><strong>5.6: Eliminando metadatos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica la forma de eliminar los metadatos de un archivo.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminando metadatos de un archivo</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminando metadatos de carpetas o de varios archivos juntos</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Los metadatos se eliminan de la misma manera que se actualizan. Primero se selecciona un archivo de la estructura de directorios y subdirectorios, y se utiliza la tabla de metadatos para elegir el metadato que se desea eliminar. Si un metadato tiene asignado un valor, se activa el bot&oacute;n "Borrar". Haga click en &eacute;l para quitar el metadato del archivo seleccionado. Los dem&aacute;s archivos permanecer&aacute;n sin cambio y el valor se conservar&aacute; en la estructura de valores.
+      <p></p>
+      Eliminar metadatos de directorios o de m&uacute;ltiples archivos se hace de la misma forma.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/reviewingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/reviewingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/reviewingmetadata.htm	(revision 10506)
@@ -0,0 +1,74 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="reviewingmetadata"><font size="5" face="Verdana"><strong>5.7: Revisando los metadatos asignados</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe la forma de ver todos los metadatos asignados a una colecci&oacute;n completa.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">La tabla de auditor&iacute;a</td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2"> El men&uacute; del bot&oacute;n derecho del mouse</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Filtros</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      En ocasiones es necesario ver los metadatos asignados a varios o a todos los archivos al mismo tiempo, por ejemplo, para determinar la forma en que quedan muchos archivos para trabajar en ellos o para tener una idea de la diferencia de tiempo entre las fechas.
+      <p></p>
+      Seleccione los archivos que desea examinar, pulse el bot&oacute;n derecho del rat&oacute;n y elija "Metadatos Asignados&hellip;". Con lo que aparecer&aacute; una ventana llamada "Todos los metadatos", ocupada en su mayor parte por una tabla de varias columnas. La primera columna muestra los nombres de los archivos, mientras que las filas muestran todos los valores asignados a dichos archivos.
+      <p></p>
+      Si se seleccionaron muchos archivos es posible que transcurra alg&uacute;n tiempo antes de que se abra la ventana. Mientras tanto usted puede seguir usando la Interfaz de Bibliotecario.
+      <p></p>
+      Haga click en "Cerrar" para ocultar la ventana.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      Tambi&eacute;n se puede ver la tabla de "Todos los metadatos" seleccionando los archivos que desea examinar, haciendo click con el bot&oacute;n derecho del mouse y eligiendo la opci&oacute;n "Metadatos asignados...". Si se seleccion&oacute; una carpeta, todos sus archivos estar&aacute;n incluidos en la tabla.
+      <p></p>
+      Cuando la tabla sea demasiado grande se puede refinar aplicando los filtros a las columnas. Conforme se a&ntilde;adan nuevos filtros, &uacute;nicamente aquellas filas que concuerden con ellos seguir&aacute;n siendo visibles. Para establecer, modificar o borrar un filtro haga click en el icono con forma de embudo que se encuentra en la parte superior de la columna. Se le indicar&aacute; que proporcione informaci&oacute;n sobre el filtro. Una vez que un filtro se ha aplicado, el encabezado de la columna cambia de color.
+      <p></p>
+      El aviso tiene una pesta&ntilde;a "Sencilla" y una "Avanzada". La versi&oacute;n sencilla filtra las columnas de tal manera que s&oacute;lo muestren las filas que contienen un determinado valor ("*" corresponde a todos los valores). Los valores de los metadatos se pueden seleccionar de la lista. La versi&oacute;n avanzada permite diferentes operaciones de concordancia: "debe empezar con", "no contiene", "alfab&eacute;ticamente menos que" y "es igual a". El valor se puede editar con cualquier cadena de caracteres (incluyendo "*") y se puede elegir que la concordancia no tome en cuenta el caso. Finalmente, se puede especificar una segunda condici&oacute;n de concordancia que se puede usar para especificar un rango de valores (seleccionando "Y") o valores alternativos (seleccionando "O"). Debajo de esta &aacute;rea hay un cuadro que le permite cambiar el orden de clasificaci&oacute;n (ascendente o descendente). Una vez que haya terminado, haga click en "Filtrar" para aplicar el nuevo filtro a la columna. Para quitar el filtro haga click en "Borrar filtro". Recuerde que los detalles del filtro se conservan incluso cuando el filtro se borra.
+      <p></p>
+      Por ejemplo, para ordenar la tabla elija una columna, seleccione el filtro por omisi&oacute;n (un filtro Sencillo en "*") y escoja el orden ascendente o descendente.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/savingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/savingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/savingacollection.htm	(revision 10506)
@@ -0,0 +1,60 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="savingacollection"><font size="5" face="Verdana"><strong>2.2: Guardar la colecci&oacute;n</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+       Esta secci&oacute;n describe la forma de guardar una colecci&oacute;n y el mensaje Guardar Colecci&oacute;n.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">C&oacute;mo guardar</td>
+</tr>
+	
+	
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">D&oacute;nde se guardan los archivos</td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Guarde su trabajo regularmente abriendo el men&uacute; "Archivo" y seleccionando "Guardar". Tome en cuenta que guardar una colecci&oacute;n no es lo mismo que prepararla para que se pueda usar en Greenstone (vea la secci&oacute;n <a href="producingthecollection.htm#producingthecollection">Produciendo una colecci&oacute;n</a>).
+      <p></p>
+      La Interfaz de Bibliotecario protege su trabajo guard&aacute;ndolo cada vez que salga del programa o cargue otra colecci&oacute;n.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      Las colecciones se guardan en un archivo que lleva el nombre de la colecci&oacute;n y la extensi&oacute;n ".col", ubicado en una carpeta del mismo nombre dentro de la carpeta "colecciones" del programa Greenstone.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/searchindexes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/searchindexes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/searchindexes.htm	(revision 10506)
@@ -0,0 +1,67 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="searchindexes"><font size="5" face="Verdana"><strong>6.5: &Iacute;ndices de b&uacute;squeda</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Los &iacute;ndices especifican las partes de la colecci&oacute;n que se pueden buscar. Esta secci&oacute;n explica la forma de a&ntilde;adir y eliminar &iacute;ndices, as&iacute; como predeterminar un &iacute;ndice por omisi&oacute;n. En la parte correspondiente a "Secciones de dise&ntilde;o" haga click en "&Iacute;ndices de b&uacute;squeda".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adir un &iacute;ndice</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Editar un &iacute;ndice</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminar un &iacute;ndice</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Predeterminar un &iacute;ndice por omisi&oacute;n</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Para a&ntilde;adir un &iacute;ndice escriba el nombre que le quiera dar en el campo "Nombre del &iacute;ndice". Seleccione las fuentes de informaci&oacute;n que se van a indexar haciendo click en los recuadros que se encuentran a un lado. La lista mostrar&aacute; todos los elementos de metadatos asignados, as&iacute; como el texto completo. Despu&eacute;s de seleccionar las fuentes de datos, elija la granularidad del &iacute;ndice usando el men&uacute; de "Nivel". Una vez que se han completado estos detalles, la opci&oacute;n "A&ntilde;adir &iacute;ndice" se activa (a menos que haya un &iacute;ndice con los mismos par&aacute;metros). Haga click en ella para a&ntilde;adir el nuevo &iacute;ndice.
+      <p></p>
+      Para editar un &iacute;ndice, selecci&oacute;nelo, cambie los detalles del &iacute;ndice, y pulse "Reemplazar &Iacute;ndice".
+      <p></p>
+      Para quitar un &iacute;ndice de la lista de &iacute;ndices asignados, selecci&oacute;nelo y haga click en "Eliminar &iacute;ndice".
+      <p></p>
+      El &iacute;ndice predeterminado es el que se usa en la p&aacute;gina de b&uacute;squeda de la colecci&oacute;n y lleva la etiqueta "[Indice por omisi&oacute;n]" en la lista de "&Iacute;ndices asignados". Para establecer un &iacute;ndice por omisi&oacute;n, selecci&oacute;nelo de la lista y haga click en "Predeterminar".
+      <p></p>
+      Si la opci&oacute;n de b&uacute;squeda avanzada est&aacute; activa (a trav&eacute;s de la pantalla de tipos de b&uacute;squeda) los controles de indexaci&oacute;n ser&aacute;n diferentes. Cada &iacute;ndice se basa en una sola fuente de datos. Hay una nueva fuente de pseudodatos llamada "allfields" (todos los campos) que permite buscar a trav&eacute;s de todos los &iacute;ndices especificados al mismo tiempo. Los niveles no se asignan a un &iacute;ndice en particular, sino que se aplican a todos los &iacute;ndices. De esta manera los &iacute;ndices y niveles se a&ntilde;aden por separado. Los &iacute;ndices se eliminan de la misma manera que arriba, pero el &iacute;ndice por omisi&oacute;n ya no se puede predeterminar: pasa a ser simplemente el primer &iacute;ndice asignado.
+      <p></p>
+      Para crear &iacute;ndices en todas las fuentes, haga click en el bot&oacute;n "A&ntilde;adir todas". El nombre de cada &iacute;ndice ser&aacute; el de la fuente por omisi&oacute;n. Para cambiar el nombre, seleccione un &iacute;ndice, cambie sus detalles y haga click en "Reemplazar &iacute;ndice".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/searchtypes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/searchtypes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/searchtypes.htm	(revision 10506)
@@ -0,0 +1,63 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="searchtypes"><font size="5" face="Verdana"><strong>6.4: Tipos de b&uacute;squeda</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica la forma de modificar una nueva funci&oacute;n de dise&ntilde;o de Greenstone llamada "Tipos de b&uacute;squeda", que permite la b&uacute;squeda por campos. En la parte de "Secciones de dise&ntilde;o" haga click en "Tipos de dise&ntilde;o".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Lo que significa activar las opciones de b&uacute;squeda avanzada</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adiendo un nuevo tipo de b&uacute;squeda</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminando un tipo de b&uacute;squeda</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Cambiando el orden de los tipos de b&uacute;squeda</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Cuando ingrese a la pantalla de tipos de b&uacute;squeda marque primero el recuadro "Permitir b&uacute;squedas avanzadas", lo cual activa todos los dem&aacute;s controles. Esto transfiere la colecci&oacute;n al formato Greenstone 2.4, el cual soporta la b&uacute;squeda por campos y significa que (a) el dise&ntilde;o de &iacute;ndices es diferente (lo cual se explica en la secci&oacute;n <a href="searchindexes.htm#searchindexes">&Iacute;ndices de b&uacute;squeda</a>), (b) hay m&aacute;s fragmentos de texto para traducir (vea la secci&oacute;n relativa a <a href="translatetext.htm#translatetext">Traducci&oacute;n</a>) y (c) la colecci&oacute;n no podr&aacute; usarse con versiones anteriores de Greenstone. Si posteriormente usted quita la marca de este campo, la mayor parte de su colecci&oacute;n regresar&aacute; a Greenstone 2.39. No obstante, la Interfaz de Bibliotecario no podr&aacute; convertir las especificaciones del nuevo &iacute;ndice en las de las versiones anteriores, por lo que usted tendr&aacute; que ingresarlas otra vez de forma manual.
+      <p></p>
+      Para a&ntilde;adir un tipo de b&uacute;squeda, selecci&oacute;nelo de la lista "Tipos de b&uacute;squeda" y haga click en "A&ntilde;adir tipo de b&uacute;squeda". Cada tipo puede aparecer en la lista solamente una vez.
+      <p></p>
+      Para quitar un tipo de b&uacute;squeda, selecci&oacute;nelo de la lista "Tipos de b&uacute;squeda asignados actualmente" y haga click en "Eliminar tipo de b&uacute;squeda". La lista deber&aacute; contener al menos uno.
+      <p></p>
+      Para cambiar el orden de un tipo de b&uacute;squeda, selecci&oacute;nelo y haga click en "Mover arriba" o "Mover abajo". El primer tipo ser&aacute; el ajuste por omisi&oacute;n.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/selectingmetadatasets.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/selectingmetadatasets.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/selectingmetadatasets.htm	(revision 10506)
@@ -0,0 +1,51 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="selectingmetadatasets"><font size="5" face="Verdana"><strong>5.2: Seleccionando conjuntos de metadatos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica la forma de especificar los elementos de los metadatos y c&oacute;mo a&ntilde;adir conjuntos de metadatos a su colecci&oacute;n.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">&iquest;Qu&eacute; es un conjunto de metadatos?</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Controlando los conjuntos de metadatos usados</td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Los grupos de elementos de metadatos definidos previamente son conocidos como "conjuntos de metadatos". Un ejemplo es el conjunto de metadatos de Dublin Core. Cuando se a&ntilde;ade un conjunto de metadatos a una colecci&oacute;n, sus elementos se vuelven elegibles para que el usuario los pueda seleccionar. Tambi&eacute;n se puede tener m&aacute;s de un conjunto. Para evitar conflictos de nombre, un identificador que describe al conjunto de metadatos se agrega como prefijo al nombre del elemento. Por ejemplo, el elemento Creator de Dublin Core se convierte en "dc.Creator". Los conjuntos de metadatos se guardan en la carpeta de metadatos de la Interfaz de Bibliotecario y llevan el sufijo ".mds".
+      <p></p>
+      Para controlar los conjuntos de metadatos usados en una colecci&oacute;n, utilice la opci&oacute;n "Conjuntos de metadatos" en la vista Dise&ntilde;o.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/startingoff.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/startingoff.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/startingoff.htm	(revision 10506)
@@ -0,0 +1,19 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="startingoff"><font size="5" face="Verdana"><strong>2: Para empezar</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Esta secci&oacute;n explica c&oacute;mo crear, cargar, guardar y borrar colecciones.
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/thecreateview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/thecreateview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/thecreateview.htm	(revision 10506)
@@ -0,0 +1,68 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thecreateview"><font size="5" face="Verdana"><strong>7.1: La pantalla de creaci&oacute;n de la colecci&oacute;n</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe las caracter&iacute;sticas de la pantalla "Crear" que se utiliza para producir una colecci&oacute;n.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Construcci&oacute;n de la colecci&oacute;n
+	  </td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Presentaci&oacute;n preliminar de la colecci&oacute;n
+	  </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Registro de mensajes</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      La pantalla "Crear" se utiliza para producir la colecci&oacute;n ejecutando los guiones de los programas Greenstone con base en la informaci&oacute;n que usted ha proporcionado. Al hacer click en el bot&oacute;n "Crear colecci&oacute;n" se inicia el proceso de construcci&oacute;n de la colecci&oacute;n. El tiempo que se lleve depender&aacute; del tama&ntilde;o de la colecci&oacute;n y del n&uacute;mero de &iacute;ndices que se est&eacute;n creando (para colecciones de gran tama&ntilde;o pueden ser horas). Una barra de progreso indica cu&aacute;nto se ha completado del proceso. Para cancelar el proceso en cualquier momento haga click en el bot&oacute;n "Cancelar la construcci&oacute;n".
+      <p></p>
+      Una vez que la colecci&oacute;n se ha construido exitosamente, al seleccionar "Vista previa de la colecci&oacute;n" se iniciar&aacute; un navegador de web que mostrar&aacute; la p&aacute;gina inicial de la colecci&oacute;n.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      En modo Experto, puede usar las entradas del "Registro de mensajes" a la izquierda, para revisar intentos previos de construcci&oacute;n de la colecci&oacute;n, hayan tenido &eacute;xito o no. Seleccione el registro que desee haciendo click en la fecha correspondiente en la lista "Historial de registro".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/thedesignview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/thedesignview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/thedesignview.htm	(revision 10506)
@@ -0,0 +1,49 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thedesignview"><font size="5" face="Verdana"><strong>6.1: La pantalla de dise&ntilde;o</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n le presenta la pantalla de Dise&ntilde;o y le explica la forma de navegar entre las diferentes opciones de este conjunto.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Eligiendo la secci&oacute;n de dise&ntilde;o</td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Con la Interfaz de Bibliotecario usted puede configurar la forma en que la colecci&oacute;n aparecer&aacute; frente al usuario. Las opciones se dividen en diferentes secciones, cada una relacionada con una etapa particular de navegaci&oacute;n o presentaci&oacute;n.
+      <p></p>
+      A la izquierda se encuentra una lista de las diferentes pantallas, en tanto que a la derecha est&aacute;n los controles asociados a la pantalla que est&aacute; activa en ese momento. Para cambiar a una pantalla diferente haga click en la lista.
+      <p></p>
+      Para entender las etapas y los t&eacute;rminos usados en el dise&ntilde;o de una colecci&oacute;n, lea primero los Cap&iacute;tulos 1 y 2 de la Gu&iacute;a del Programador de Greenstone.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/theenrichview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/theenrichview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/theenrichview.htm	(revision 10506)
@@ -0,0 +1,69 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="theenrichview"><font size="5" face="Verdana"><strong>5.1: La pantalla de asignaci&oacute;n de metadatos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe la forma de a&ntilde;adir y editar metadatos por medio de la pantalla "Enriquecer".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">La estructura de directorios y subdirectorios de la colecci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Controles de edici&oacute;n de metadatos</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">La estructura de valores</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">La tabla de metadatos</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Utilice la pantalla "Enriquecer" para asignar metadatos a los documentos de la colecci&oacute;n. Los metadatos son datos acerca de los datos: t&iacute;tulo, autor, fecha de creaci&oacute;n, etc. Cada metadato tiene dos partes: el "elemento" dice el tipo de metadato que es (como por ejemplo el autor) y el "valor" da la informaci&oacute;n de ese elemento (como por ejemplo el nombre del autor).
+      <p></p>
+      En la parte izquierda de la pantalla "Enriquecer" se encuentra la estructura de directorios y subdirectorios de la colecci&oacute;n. A la derecha est&aacute; la Tabla de Metadatos, la cual muestra los metadatos de los archivos y carpetas seleccionados. Los nombres de las columnas est&aacute;n en gris en la parte superior y se pueden cambiar de tama&ntilde;o arrastrando la l&iacute;nea que las separa. Pulsar sobre cualquier l&iacute;nea transfiere sus detalles a los controles inferiores de edici&oacute;n de metadatos. Si se seleccionan varios archivos, el texto en negro indica que el valor es com&uacute;n a todos ellos, mientras que el texto sombreado indica que no. Los valores en negro se pueden actualizar o eliminar, mientras que los que est&aacute;n sombreados se pueden eliminar de los que los tienen o agregarse a los dem&aacute;s.
+      <p></p>
+      Un icono en forma de carpeta puede aparecer junto a algunas entradas de metadatos. Esto indica que los valores se heredan de la carpeta en la que se encuentra el archivo. Los metadatos heredados no se pueden editar o eliminar, sino &uacute;nicamente agregarse o sobreescribirse. Haga click en el icono de la carpeta para ir inmediatamente a la carpeta en la que se asignaron los metadatos.
+      <p></p>
+      Los controles de edici&oacute;n de metadatos de la parte inferior derecha aparecen s&oacute;lo cuando se selecciona un archivo de la estructura y una l&iacute;nea de la tabla. Util&iacute;celos para actualizar, agregar o eliminar valores de los metadatos. El campo de valores es para ingresar o editar el valor del metadato.  Junto hay un bot&oacute;n con la etiqueta "...", el cual abre un cuadro de edici&oacute;n m&aacute;s grande. De los botones que se encuentran debajo, "Agregar" asigna el valor en forma de nuevo metadato y lo a&ntilde;ade a los valores existentes para el elemento seleccionado, "Reemplazar" sobreescribe el valor seleccionado sustituy&eacute;ndolo por uno nuevo y "Eliminar" borra el valor seleccionado. M&aacute;s abajo, con la etiqueta "Todos los valores anteriores", se encuentra la estructura de valores.
+      <p></p>
+      La estructura de valores se puede expandir y contraer. Normalmente es una lista que muestra todos los valores ingresados previamente para un elemento seleccionado. Al hacer click en una entrada &eacute;sta aparece autom&aacute;ticamente en el campo de valores. Y a la inversa, al escribir en el campo se selecciona la entrada de la estructura de valores que empieza con los caracteres ingresados. Al oprimir [Tab] se completa autom&aacute;ticamente el valor seleccionado.
+      <p></p>
+      Los valores de los metadatos se pueden organizar jer&aacute;rquicamente. Esto se muestra en la estructura de valores por medio de carpetas para los niveles internos. Los valores jer&aacute;rquicos pueden ingresarse utilizando el car&aacute;cter "|" para separar los niveles. Por ejemplo, se puede usar "Cartas|Rojo|Diamantes|Siete" en una jerarqu&iacute;a que representa un mazo de cartas. Esto permite agrupar los valores, en tanto que los grupos tambi&eacute;n pueden asignarse en forma de metadatos a los archivos.
+      <p></p>
+      Greenstone extrae autom&aacute;ticamente los metadatos de los documentos para formar un conjunto de metadatos cuyos elementos llevan el prefijo "ex.". &Eacute;ste no tiene estructura de valores y no puede editarse, por lo que los controles de edici&oacute;n est&aacute;n ocultos si se selecciona dicha entrada. El bot&oacute;n "..." todav&iacute;a sirve para expandir el valor, pero el texto no se puede editar.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/thegatherview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/thegatherview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/thegatherview.htm	(revision 10506)
@@ -0,0 +1,90 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thegatherview"><font size="5" face="Verdana"><strong>4.1: La pantalla de selecci&oacute;n de documentos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe el funcionamiento de la pantalla "Reunir" que se utiliza para seleccionar los archivos que se van a incluir en la colecci&oacute;n que se est&aacute; construyendo.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">C&oacute;mo ver la pantalla Reunir</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">La estructura de directorios y subdirectorios</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">El &aacute;rea de estado</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Botones de control</td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">M&eacute;todos de selecci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Mapeado de carpetas especiales</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      La Interfaz de Bibliotecario inicia con la pantalla "Reunir". Si despu&eacute;s usted desea regresar a esta pantalla haga click en la pesta&ntilde;a del mismo nombre que se encuentra directamente debajo de la barra de men&uacute;s.
+      <p></p>
+      Dos grandes &aacute;reas tituladas "Area de trabajo" y "Colecci&oacute;n" se utilizan para transferir los archivos a su colecci&oacute;n. Cada una contiene "&aacute;rboles de archivos", los cuales son representaciones gr&aacute;ficas de la estructura de directorios y subdirectorios de sus archivos y carpetas.
+      <p></p>
+      Seleccione un elemento del &aacute;rbol haciendo click en &eacute;l. (Tambi&eacute;n existen otras formas; v&eacute;ase m&aacute;s adelante.) Haga click en el signo que se encuentra junto a una carpeta o doble click en ella para expandir (o contraer) sus contenidos. Haga doble click en un archivo para abrirlo usando un programa de aplicaci&oacute;n asociado (vea la secci&oacute;n <a href="fileassociations.htm#fileassociations">Asociaci&oacute;n de archivos</a>).
+      <p></p>
+      El &aacute;rbol de archivos del &aacute;rea de trabajo muestra los or&iacute;genes de la informaci&oacute;n disponible al interfaz del Bibliotecario -- el sistema local de archivos (incluyendo unidades de disco y CD-ROM), los contenidos de las colecciones existentes de Greenstone, y el cach&eacute; de archivos descargados si esta activada la opci&oacute;n de poner en espejo la Web. Usted puede copiar y consultar estos archivos pero no puede moverlos, eliminarlos o editarlos, con la excepci&oacute;n de los archivos descargados, los cuales pueden ser eliminados. Navegue por este espacio para buscar los archivos que desee incluir en la colecci&oacute;n.
+      <p></p>
+      La estructura de directorios y subdirectorios de la colecci&oacute;n muestra sus contenidos. Inicialmente est&aacute; vac&iacute;a.
+      <p></p>
+      Se puede cambiar el tama&ntilde;o de las &aacute;reas oprimiendo el bot&oacute;n del mouse sobre la barra gris que separa las estructuras de directorios y subdirectorios (la forma del cursor cambia) y arrastr&aacute;ndola.
+      <p></p>
+      En la parte inferior de la ventana se muestra un &aacute;rea de estado que informa del progreso de las acciones sobre archivos (copiando, moviendo y borrando). Puede tardar un tiempo en terminar. El bot&oacute;n "Detener" interrumpe cualquier acci&oacute;n que se est&eacute; ejecutando en ese momento.
+      <p></p>
+      Dos grandes botones ocupan la esquina inferior derecha de la pantalla: "Nueva carpeta", con la imagen de una carpeta, crea nuevas carpetas (vea la secci&oacute;n <a href="creatingfolders.htm#creatingfolders">Creando carpetas</a>), en tanto que "Eliminar", con la imagen de un bote de basura, descarta los archivos. Al hacer click en el bot&oacute;n "Eliminar" se suprimir&aacute;n los archivos seleccionados de la estructura de directorios y subdirectorios de la colecci&oacute;n. Asimismo, los archivos pueden eliminarse arrastr&aacute;ndolos hacia este bot&oacute;n.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      Para seleccionar varios elementos consecutivos, seleccione el primero y a continuaci&oacute;n manteniendo oprimida la tecla de may&uacute;sculas o [Shift] haga click en el &uacute;ltimo: la selecci&oacute;n incluir&aacute; todos los elementos que se encuentran en medio. Para seleccionar varios archivos que no sean consecutivos mantenga oprimida la tecla de control o [Ctrl] mientras hace click en ellos. Utilice alternativamente estos dos m&eacute;todos para seleccionar grupos de elementos que no est&eacute;n juntos.
+      <p></p>
+      En ocasiones algunas carpetas, como la que contiene sus propias p&aacute;ginas Web, tienen un significado especial. La Interfaz de Bibliotecario puede asignar dichas carpetas al primer nivel de la estructura de directorios y subdirectorios. Para hacerlo haga click con el bot&oacute;n derecho del mouse sobre la carpeta deseada. Seleccione "Crear un acceso directo" y d&eacute;le un nombre a la carpeta. Para quitar un elemento haga click con el bot&oacute;n derecho del mouse sobre la carpeta mapeada y seleccione "Eliminar acceso directo".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/themirrorview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/themirrorview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/themirrorview.htm	(revision 10506)
@@ -0,0 +1,76 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="themirrorview"><font size="5" face="Verdana"><strong>3.1: La vista en Bajar</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe como configurar una tarea de descarga y como controlar el proceso de descargue.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">El &aacute;rbol del &aacute;rea de trabajo</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Configuraci&oacute;n de descarga</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Lista de descarga</td>
+</tr>
+        
+	
+<tr>
+<td colspan="3"><a href="#advanced">Instrucciones avanzadas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Activaci&oacute;n de "web proxies"</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Modo avanzado</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Active la vista "Bajar" haciendo clic en su pesta&ntilde;a. La mitad superior de la pantalla contiene los controles para realizar descargas. La mitad inferior est&aacute; vac&iacute;a inicialmente, pero despu&eacute;s va a mostrar una lista de tareas pendientes y terminadas.
+      <p></p>
+      Los archivos se descargan en una carpeta del espacio de trabajo denominada "Archivos Descargados" (que s&oacute;lo existe cuando est&aacute; habilitada la opci&oacute;n de trabajar en espejo), y pueden utilizarse en todas las colecciones construidas con el interfaz del Bibliotecario. En esta &aacute;rea los archivos se designan con su URL completo. Para cada "host" se crea una nueva carpeta, seguida por otras para cada parte del "path". De esta manera se asegura que todos los archivos son distintos.
+      <p></p>
+      Utilice el primero de los controles de configuraci&oacute;n de la descarga, "URL Or&iacute;gen", para capturar el URL de un recurso deseado. Utilice el control "Profundidad de la Descarga" para limitar el n&uacute;mero de hiper-v&iacute;nculos que se deben seguir al descargar: P&oacute;ngalo en 0 para descargar una sola p&aacute;gina; p&oacute;ngalo en 1 para descargar una p&aacute;gina y todas las p&aacute;ginas a las que apunta. El l&iacute;mite de profundidad se ignora al descargar medios diferentes de p&aacute;ginas html. Adem&aacute;s, hay varios controles de chequeo que se pueden prender para activar determinadas capacidades durante una descarga espec&iacute;fica. Una vez se ha establecido la configuraci&oacute;n, haga clic en "Descargar" para iniciar un nuevo proceso de descargue. Hay otros dos controles en forma de botones: "Preferencias", que enlaza con la secci&oacute;n de conexi&oacute;n de las Preferencias, en la cual se pueden editar las caracter&iacute;sticas del "proxy"; y "Borrar Cach&eacute;", que borra todos los archivos descargados previamente.
+      <p></p>
+      La lista de descargas tiene una entrada por cada p&aacute;gina web descargada. Cada entrada tiene un &aacute;rea de texto que da detalles acerca de la tarea, junto con una barra que indica el avance de la actividad en ejecuci&oacute;n. A la izquierda de cada entrada aparecen tres botones. "Pausa" se utiliza para detener temporalmente la descarga que se est&aacute; ejecutando. "Ver Bit&aacute;cora" abre una ventana que muestra el archivo de bit&aacute;cora de las descargas. "Cerrar" termina la descarga y quita de la lista la tarea correspondiente.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instrucciones avanzadas:</a>
+<p style="text-align:justify"></p>
+      La <a href="preferences.htm#preferences">secci&oacute;n Preferencias</a> describe como establecer una conexi&oacute;n Internet por medio de un "proxy".  Si se necesita autenticaci&oacute;n, el servidor "proxy" pide la identificaci&oacute;n y la palabra clave. El interfaz del Bibliotecario no almacena palabras claves entre sesiones.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/translatetext.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/translatetext.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/translatetext.htm	(revision 10506)
@@ -0,0 +1,57 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="translatetext"><font size="5" face="Verdana"><strong>6.10: Traducci&oacute;n de textos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n describe la pantalla de traducci&oacute;n, donde se pueden definir fragmentos de texto en un idioma espec&iacute;fico para partes de la interfaz de la colecci&oacute;n. En la parte de "Secciones de dise&ntilde;o" haga click en "Traducir texto".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">A&ntilde;adir traducci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Eliminar traducci&oacute;n</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Actualizar traducci&oacute;n</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Primero elija una entrada de la lista de "funciones". Las cadenas de texto asociadas a esta funci&oacute;n aparecer&aacute;n abajo. Utilice la lista "Idioma de la traducci&oacute;n" para seleccionar el idioma al que se va a traducir y escriba el texto traducido en el &aacute;rea de texto, haciendo referencia al "fragmento de texto inicial" en caso necesario. Una vez que haya terminado haga click en "A&ntilde;adir traducci&oacute;n".
+      <p></p>
+      Para quitar una traducci&oacute;n existente, selecci&oacute;nela de la tabla "Traducciones asignadas" y haga click en "Eliminar traducci&oacute;n".
+      <p></p>
+      Para actualizar una traducci&oacute;n, selecci&oacute;nela, ed&iacute;tela en el &aacute;rea de texto titulada "Texto traducido" y haga click en "Reemplazar traducci&oacute;n".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/updatingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/updatingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/updatingmetadata.htm	(revision 10506)
@@ -0,0 +1,53 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="updatingmetadata"><font size="5" face="Verdana"><strong>5.5: Actualizando metadatos</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Esta secci&oacute;n explica la forma de actualizar los metadatos asignados a un archivo.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Actualizando los metadatos de archivos</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2"> Actualizando los metadatos de carpetas o de varios archivos juntos</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      Para actualizar el valor de una parte del metadato, elija primero el archivo al que se aplicar&aacute; dicho valor y luego el elemento de metadato cuyo valor desea cambiar. Su selecci&oacute;n aparecer&aacute; en los controles de edici&oacute;n de metadatos. Edite el valor y haga click en "Reemplazar" para modificarlo.
+      <p></p>
+      El proceso es el mismo cuando se actualiza un directorio que contiene subdirectorios o m&uacute;ltiples archivos, pero s&oacute;lo se pueden actualizar metadatos que sean comunes a todos los archivos y carpetas seleccionados.
+      <p></p>
+      La estructura de valores muestra todos los valores anteriores y no s&oacute;lo aquellos que se asignaron en este momento. As&iacute; el valor que usted reemplaz&oacute; permanecer&aacute; en la estructura de valores.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/es/xcollectionsearching.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/es/xcollectionsearching.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/es/xcollectionsearching.htm	(revision 10506)
@@ -0,0 +1,47 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="xcollectionsearching"><font size="5" face="Verdana"><strong>6.7: B&uacute;squeda cruzada a trav&eacute;s de varias colecciones</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Greenstone puede buscar a trav&eacute;s de varias colecciones distintas como si fueran una sola. Esto se hace creando una "supercolecci&oacute;n" que abarca a las colecciones individuales. En la parte de "Secciones de dise&ntilde;o" haga click en "B&uacute;squeda cruzada".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instrucciones b&aacute;sicas:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Seleccionando una colecci&oacute;n</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instrucciones b&aacute;sicas:</a>
+<p style="text-align:justify"></p>
+      La pantalla de b&uacute;squeda cruzada muestra una lista de las colecciones disponibles. La colecci&oacute;n actual est&aacute; marcada y no se puede quitar de la selecci&oacute;n. Para a&ntilde;adir otra colecci&oacute;n en la cual buscar de forma paralela, haga click en ella (o haga click en ella nuevamente para quitarla de la selecci&oacute;n). Si s&oacute;lo se seleccion&oacute; una colecci&oacute;n, entonces no habr&aacute; b&uacute;squeda cruzada.
+      <p></p>
+      Para mayor informaci&oacute;n vea el Cap&iacute;tulo 1 de la Gu&iacute;a del Programador de Greenstone.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/addingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/addingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/addingfiles.htm	(revision 10506)
@@ -0,0 +1,72 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="addingfiles"><font size="5" face="Verdana"><strong>4.3: Ajouter des fichiers</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section indique la mani&egrave;re d'inclure des fichiers dans la collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            glisser-d&eacute;placer
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            fichiers multiples
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions avanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            m&eacute;ta-donn&eacute;es existantes
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Les fichiers peuvent &ecirc;tre copi&eacute;s dans la collection par glisser-d&eacute;placer. Le pointeur &eacute;pouse la forme de l'&eacute;l&eacute;ment s&eacute;lectionn&eacute; (ou, si la s&eacute;lection comprend plus d'un, leur nombre). D&eacute;poser la s&eacute;lection dans l'arborescence de la collection pour les y copier (si la source est l'arborescence de l'espace de travail) ou les d&eacute;placer &agrave; l'int&eacute;rieur de la collection (si la source est l'arborescence de la collection).
+      <p></p>
+      Lorsque des fichiers multiples sont copi&eacute;s, ils sont tous plac&eacute; dans le dossier cible au m&ecirc;me niveau, quelle que soit la structure du dossier qui les contenait avant. Si vous copier un second fichier avec le m&ecirc;me nom dans le m&ecirc;me dossier, la question de savoir si le premier fichier doit &ecirc;tre &eacute;cras&eacute; est pos&eacute;e. Si la r&eacute;ponse est non, le fichier ne sera pas copi&eacute;, mais les autres le seront. Pour annuler toutes les autre t&acirc;ches de copie, cliquer sur le bouton "Stop".
+      <p></p>
+      Seuls les &eacute;l&eacute;ments situ&eacute;s au-dessus dans la s&eacute;lection sont d&eacute;plac&eacute;s. Un dossier est plus &eacute;lev&eacute; que son contenu. On ne peut s&eacute;lectionner en m&ecirc;me temps l'int&eacute;rieur d'un dossier et le dossier lui-m&ecirc;me.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions avanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      Lorsqu'un fichier est ajout&eacute;, l'Interface Biblioth&eacute;caire cherche les dossiers sources de fichiers auxiliaires contenant une m&eacute;ta-donn&eacute;e qui lui originellement assign&eacute;es et, s'il en trouve, commence &agrave; les importer. Au fur et &agrave; mesure que l'op&eacute;ration se poursuit, une confirmation est faite (peut-&ecirc;tre plusieurs fois) de fournir des informations compl&eacute;mentaires pour ajuster la m&eacute;ta-donn&eacute;e aux jeux de m&eacute;ta-donn&eacute;es de la collection. Ces confirmations sont d&eacute;crites dans la section <a href="importingpreviouslyassignedmetadata.htm#importingpreviouslyassignedmetadata">Importer des m&eacute;ta-donn&eacute;es originellement assign&eacute;es </a>. Pour une explication plus d&eacute;taill&eacute;e de l'association de m&eacute;ta-donn&eacute;es avec les fichiers, lire le chapitre 2 du Guide de d&eacute;veloppement de Greenstone -- "Exploitez vos documents au maximum".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/addingpreviouslydefinedmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/addingpreviouslydefinedmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/addingpreviouslydefinedmetadata.htm	(revision 10506)
@@ -0,0 +1,55 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="addingpreviouslydefinedmetadata"><font size="5" face="Verdana"><strong>5.4: Ajouter des M&eacute;ta-donn&eacute;es pr&eacute;d&eacute;finies</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique la mani&egrave;re d'ajouter une m&eacute;ta-donn&eacute;e qui utilise des valeurs d&eacute;j&agrave; pr&eacute;sentes dans l'arborescence des valeurs.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ajouter aux fichiers
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ajouter aux fichiers et aux fichiers multiples
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Pour ajouter une m&eacute;ta-donn&eacute;e ayant une valeur existante, s&eacute;lectionner d'abord le fichier, et ensuite la valeur requise &agrave; partir de l'arborescence des valeurs, en d&eacute;veloppant si n&eacute;cessaire les dossiers de hi&eacute;rarchie. La valeur de l'entr&eacute;e s&eacute;lectionn&eacute;e appara&icirc;t automatiquement dans le champ texte Valeur. (Utiliser alternativement la valeur auto-select de l'arborescence et les caract&eacute;ristiques auto-compl&egrave;tes. Cliquer sur "Append" pour ajouter la metadata au fichier s&eacute;lectionn&eacute;. 
+      <p></p>
+      La proc&eacute;dure d'ajouter m&eacute;ta-donn&eacute;es avec des valeurs d&eacute;j&agrave; existantes aux dossiers ou aux fichiers multiples est tout &agrave; fait identique.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/appendingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/appendingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/appendingmetadata.htm	(revision 10506)
@@ -0,0 +1,76 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="appendingmetadata"><font size="5" face="Verdana"><strong>5.3: Ajout de Nouvelles M&eacute;ta-donn&eacute;es</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique comment ajouter des m&eacute;ta-donn&eacute;es et des valeurs &agrave; des fichiers, et comment ajouter de nouvelles valeurs pour des &eacute;l&eacute;ments de m&eacute;ta-donn&eacute;es.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ajouter aux fichiers
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ajouter aux r&eacute;pertoires et aux fichiers multiples
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions advanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Hi&eacute;rarchies de valeur et &eacute;dition des valeurs
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      On ajoute un &eacute;l&eacute;ment m&eacute;ta-donn&eacute;e -- &eacute;l&eacute;ment et valeur &agrave; la fois -- &agrave; un fichier. S&eacute;lectionner d'abord le fichier &agrave; partir de l'arborescence de fichier de la collection situ&eacute;e &agrave; gauche. Cette action entra&icirc;ne l'apparition de toute m&eacute;ta-donn&eacute;e pr&eacute;-assign&eacute;e  dans le tableau de droite. 
+      <p></p>
+      S&eacute;lectionner ensuite l'&eacute;l&eacute;ment m&eacute;ta-donn&eacute;e &agrave; ajouter en cliquant sur sa rang&eacute;e dans le tableau.
+      <p></p>
+      Taper la valeur dans le champ valeur. Ne pas utiliser pas le caract&egrave;re "|", d&egrave;s lors qu'il est utilis&eacute; pour construire des hi&eacute;rarchies. Cliquer enfin sur "Append" pour ajouter la nouvelle valeur comme m&eacute;ta-donn&eacute;e pour le fichier choisi. La valeur appara&icirc;t imm&eacute;diatement dans le tableau de M&eacute;ta-donn&eacute;es.
+      <p></p>
+      Vous pouvez aussi ajouter des m&eacute;ta-donn&eacute;es &agrave; un dossier, ou &agrave; plusieurs fichiers s&eacute;lectionn&eacute;s &agrave; la fois. Elle est ajout&eacute;e &agrave; tous les fichiers ou &agrave; l'int&eacute;rieur du dossier ou de la s&eacute;l&eacute;ction, et aux sous-dossiers. Garder &agrave; l'esprit  que si des m&eacute;ta-donn&eacute;es sont ajout&eacute;es &agrave; un dossier tous les nouveaux fichiers en son sein h&eacute;rite automatiquement des valeurs du dossier.
+      <p></p>
+      Si on choisit une m&eacute;ta-donn&eacute;e qui intervient dans quelques uns des fichiers s&eacute;lectionn&eacute;s et que l'on clique sur "Coller", elle est aussi ajout&eacute;e aux autres fichiers de la s&eacute;lection.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions advanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      On peut ajouter une structure aux valeurs de m&eacute;ta-donn&eacute;es en utilisant les chemins comme d&eacute;crit dans <a href="theenrichview.htm#theenrichview">L'affichage Enrichir</a>.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/assignlanguages.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/assignlanguages.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/assignlanguages.htm	(revision 10506)
@@ -0,0 +1,77 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="assignlanguages"><font size="5" face="Verdana"><strong>6.6.3: Assigner Langages</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+	Cette section donne les d&eacute;tails de la mani&egrave;re de restreindre les index &agrave; des langages particuliers. On le fait en g&eacute;n&eacute;rant une partition par le biais de l'onglet "Assigner Langages" de l'Affichage "Index de Partition".
+        <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+          
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Contr&ocirc;les de Langage 
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Ajouter langage
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Enlever langage
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Langage par d&eacute;faut
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Enlever Langage par d&eacute;faut
+            </td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+        
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+	Pour ajouter un nouveau langage, dont la partition par le biais de l'onglet "Assigner langues" conf&egrave;re un index, S&eacute;lectionner le langage souhait&eacute; &agrave; partir de la liste "Langage &agrave; ajouter" et cliquer sur "Ajouter langue".
+	<p></p>
+	Pour supprimer une langue, s&eacute;lectionner-la &agrave; partir de la liste "S&eacute;lection de Langage" et cliquer sur "Enlever Langage". 
+	<p></p>
+	Pour installer un language par d&eacute;faut, s&eacute;lectionner-la dans la liste et cliquez sur "Par d&eacute;faut".
+	<p></p>
+	Pour enlever le langage par d&eacute;faut, cliquer sur "Enlever par D&eacute;faut".
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/assignpartitions.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/assignpartitions.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/assignpartitions.htm	(revision 10506)
@@ -0,0 +1,71 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="assignpartitions"><font size="5" face="Verdana"><strong>6.6.2: Assigner des Partitions</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+	Cette section explique l'assignation d'un filtre de partition pr&eacute;d&eacute;fini.
+        <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+          
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Ajouter une partition
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Enlever une partition
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Partition par d&eacute;faut
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Enlever partition par d&eacute;faut
+            </td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+        
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+	Apr&egrave;s avoir d&eacute;fini un filtre de sous-collection, utiliser l'onglet "Assigner des Partitions" pour construire ses indexes  (ou ceux pour un jeu de filtres.) S&eacute;lectionner le filtre (ou les filtres) de votre choix &agrave; partir de la liste "D&eacute;finir des Filtres de Sous-collection", entrer un nom pour la partition dans le champ "Nom de Partition Name", et cliquer sur "Ajouter Partition". 
+	<p></p>
+	Pour supprimer une partition, s&eacute;lectionner-la &agrave; partir de la liste et cliquer sur "Enlever Partition".
+	<p></p>
+	Pour faire d'une partition celle par d&eacute;faut, s&eacute;lectionner-la &agrave; partir de la liste et cliquer sur "Par D&eacute;faut".
+	<p></p>
+	Pour effacer la partition par d&eacute;faut, cliquez sur "Effacer d&eacute;faut".
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/buildsettings.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/buildsettings.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/buildsettings.htm	(revision 10506)
@@ -0,0 +1,59 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="buildsettings"><font size="5" face="Verdana"><strong>7.2: Param&egrave;tres d'Importation et de Construction</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique comment acc&eacute;der aux diff&eacute;rents param&egrave;tres de construction et d'importation. Pour plus d'informations sur l'importation et la construction lire le chapitre 1 du Guide du D&eacute;veloppeur de Greenstone -- Comprendre le processus de construction de la collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Param&egrave;tres G&eacute;n&eacute;raux
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Param&egrave;tres d'importation
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Param&egrave;tres de construction
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Le contr&ocirc;le des diff&eacute;rents param&egrave;tres se fait de fa&ccedil;on identique &agrave; la fen&ecirc;tre "Configurer Arguments" d&eacute;crit dans la section <a href="plugins.htm#plugins">Plugiciels de documents</a>. Certains champs requi&egrave;rent des arguments num&eacute;riques, et on peut: soit les incorporer en les saisissant, soit utiliser les fl&egrave;ches Haut et Bas pour augmenter ou diminuer la valeur pr&eacute;sente (dans certains cas, l'interface limite la classe qu'on peut entrer.) D'autres sont activ&eacute;s en cliquant sur une case de v&eacute;rification (re-cliquer pour d&eacute;sactiver.)
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/classifiers.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/classifiers.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/classifiers.htm	(revision 10506)
@@ -0,0 +1,79 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="classifiers"><font size="5" face="Verdana"><strong>6.8: Classificateurs</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique comment assigner &agrave; une collection des "classificateurs" qui sont utilis&eacute;s pour naviguer. Sous la section "Sections de conception", cliquer sur "Classificateurs de navigation".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Configuration et s&eacute;lection d'un classificateur
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ajouter un classificateur
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Enlever un classificateur
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Configurer un classificateur
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Changer l'ordre d'un classificateur
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Pour ajouter un classificateur, s&eacute;lectionner-le en utilisant la liste d&eacute;roulante "Choisir classificateur &agrave; ajouter" et cliquer sur "Ajouter Classificateur Sp&eacute;cifique". une fen&ecirc;tre qui s'intitule "Configurer Arguments" appara&icirc;t ; les instructions concernant ce dialogue sont les m&ecirc;mes que pour les plugiciels (voir <a href="plugins.htm#plugins">plugiciels de Documents</a>). Une fois le nouveau classificateur configur&eacute;, il s'ajoute &agrave; la fin de la liste des "Classificateurs couramment Assign&eacute;s". 
+      <p></p>
+      Pour supprimer un classificateur, s&eacute;lectionner-le dans la liste et cliquez sur "Enlever Classificateur Choisi".
+      <p></p>
+      Pour changer les arguments d'un classificateur, s&eacute;lectionner-le sur la liste et cliquer sur "Configurer Classificateur Choisi" (ou double-cliquer sur le classificateur sur la liste.) 
+      <p></p>
+      Le tri des classificateurs dans la barre de navigation de la collection est fourni ici dans l'ordre des classificateurs. Pour le changer, s&eacute;lectionner le classificateur &agrave; d&eacute;placer et cliquer sur "D&eacute;placer vers le haut" ou "D&eacute;placer vers le bas".
+      <p></p>
+      Pour plus d'informations sur les classificateurs lisez le chapitre 2 du Guide du D&eacute;veloppeur Greenstone -- Exploitez vos documents au maximum.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/collectingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/collectingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/collectingfiles.htm	(revision 10506)
@@ -0,0 +1,20 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="collectingfiles"><font size="5" face="Verdana"><strong>4: Collecter les fichiers pour la Collection</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    D&egrave;s lors que l'on dispose d'une nouvelle collection, la n&eacute;cessit&eacute; se fait sentir de la doter de fichiers. Ils peuvent provenir de votre espace fichier ordinaire ou d'autres collections Greenstone. Quelques uns peuvent avoir des m&eacute;ta-donn&eacute;es attach&eacute;es.Cette section d&eacute;crit comment importer des fichiers.
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/creatingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/creatingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/creatingacollection.htm	(revision 10506)
@@ -0,0 +1,102 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="creatingacollection"><font size="5" face="Verdana"><strong>2.1: Cr&eacute;er une nouvelle collection</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section d&eacute;crit la mani&egrave;re de cr&eacute;er une nouvelle collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            La nouvelle collection confirm&eacute;e
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Le titre de la collection
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            jeux de m&eacute;ta-donn&eacute;es par d&eacute;faut
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Description de la collection
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Cr&eacute;er la nouvelle collection
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Annuler la nouvelle collection
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions advanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Touches de raccourci
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Pour cr&eacute;er la nouvelle collection, ouvrir le menu "Fichier" et choisir "Nouveau". Plusieurs champs doivent &ecirc;tre remplis -- mais leurs valeurs sont susceptibles d'&ecirc;tre modifi&eacute;es &agrave; souhait dans l'affichage de la conception.
+      <p></p>
+      "Titre de la collection" est le texte affich&eacute; en haut de la page d'accueil de votre collection. Sa longueur peut &ecirc;tre quelconque.
+      <p></p>
+      "Description du contenu" doit d&eacute;crire avec le plus de d&eacute;tails possibles ce que la collection est. Utiliser la touche [Entr&eacute;e] pour la diviser en paragraphes.
+      <p></p>
+      On doit enfin sp&eacute;cifier soit que la nouvelle collection aura la m&ecirc;me forme et les m&ecirc;mes jeux de m&eacute;ta-donn&eacute;es que la collection existante, soit qu'elle est initi&eacute;e  "Nouvelle collection" par d&eacute;faut.
+      <p></p>
+      Cliquer sur "OK" pour cr&eacute;er la collection. Si on choisit "Nouvelle collection", les jeux de m&eacute;ta-donn&eacute;es disponibles sont affich&eacute;es. On peut en choisir plus d'une et en ajouter d'autres ult&eacute;rieurement.
+      <p></p>
+      Le clic sur "Annuler" ram&egrave;ne imm&eacute;diatement l'&eacute;cran principal.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions advanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      Les boutons, tels les menus, ont un caract&egrave;re soulign&eacute;. Pour cliquer sur le bouton, appuyer en m&ecirc;me temps sur [Alt] et sur le caract&egrave;re soulign&eacute;.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/creatingfolders.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/creatingfolders.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/creatingfolders.htm	(revision 10506)
@@ -0,0 +1,57 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="creatingfolders"><font size="5" face="Verdana"><strong>4.2: Cr&eacute;er des dossiers</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section indique la mani&egrave;re de cr&eacute;er de nouveaux dossiers
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Le bouton Nouveau Dossier
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Le menu bouton-droit
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Utiliser les dossiers de l'arborescence de fichiers de la collection pour rejeur les fichiers et les rendre ais&eacute;ment accessibles. Des dossiers peuvent &ecirc;tre plac&eacute;s &agrave; l'int&eacute;rieur d'autres dossiers. Aucune limite, virtuellement parlant, ni au nombre de dossiers dont on peut disposer ni &agrave; la complexit&eacute; de leur agencement.
+      <p></p>
+      Pour cr&eacute;er un nouveau dossier, on peut opter pour un dossier existant et cliquer sur le bouton Nouveau Dossier. Le nouveau dossier appara&icirc;t &agrave; l'int&eacute;rieur de celui choisi, ou au niveau sup&eacute;rieur si aucun n'est choisi. Le nom de ce dossier est r&eacute;clam&eacute; ( &agrave; d&eacute;faut, il sera nomm&eacute; "Nouveau Dossier").
+      <p></p>
+      Les dossiers peuvent aussi &ecirc;tre cr&eacute;&eacute;s en cliquant sur le dossier avec le bouton droit, et en choisissant "Nouveau Dossier" et proc&eacute;der comme ci-dessus.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/definefilters.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/definefilters.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/definefilters.htm	(revision 10506)
@@ -0,0 +1,65 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="definefilters"><font size="5" face="Verdana"><strong>6.6.1: D&eacute;finir les Filtres</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+	Cette section explique comment d&eacute;finir un filtre de partition.
+        <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+          
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ajouter un filtre
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Enlever un filtre
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Mettre &agrave; jour un filtre
+            </td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+        
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+	Les filtres permettent de jeur en sous-collection tous les documents dans un index pour laquelle une valeur m&eacute;ta-donn&eacute;e correspond &agrave; un type donn&eacute;.
+	<p></p>
+	Pour cr&eacute;er un filtre, cliquer sur le bouton "D&eacute;finir les Filtres" et entrer un nom pour le nouveau filtre dans le champ "Nom du filtre de la sous-collection". Ensuite choisir un attribut de document &agrave; faire correspondre  soit avec l'&eacute;l&eacute;ment de m&eacute;ta-donn&eacute;e soit avec le nom du fichier en question. Saisir une expression courante qu'il faut utiliser durant la correspondance. Vous pouvez choisir entre "Inclure" les documents qui correspondent au fichier ou les "Exclure". Enfin, on peut sp&eacute;cifier l'un quelconque des drapeaux standard PERL d'expression courante qu'il faut utiliser pour la correspondance (par exemple "i" pour les correspondances ne tenant pas compte des caract&egrave;res.) Pour finir, cliquez sur "Ajouter un Filtre" pour ajouter le filtre &agrave; la liste "Filtres de sous collection d&eacute;finis". 
+	<p></p>
+	Pour enlever un filtre, s&eacute;lectionner-le sur la liste et cliquer sur "Enlever Filtre".
+	<p></p>
+	Pour changer un filtre, s&eacute;lectionner-le sur la liste, changer l'une quelconque des valeurs apparaissant dans les contr&ocirc;les d'&eacute;dition et cliquer sur "Remplacer Filtre" pour valider les modifications.
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/deletingcollections.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/deletingcollections.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/deletingcollections.htm	(revision 10506)
@@ -0,0 +1,47 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="deletingcollections"><font size="5" face="Verdana"><strong>2.4: Suppression des collections</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique comment supprimer d&eacute;finitivement des collections de votre installation Greenstone.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Comment supprimer des collections
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Pour supprimer d&eacute;finitivement des collections de votre installation Greenstone, choisir "Supprimer..." dans le menu "Fichier". Une liste de vos collections Greenstone appara&icirc;t. Selectionner une collection pour vior sa description, puis cocher la case en bas du dialogue et clicquez "Supprimer" pour supprimer la collection. Cette operation est irr&eacute;versible, v&eacute;rifiez bien que vous n'avez plus besoin de cette collection avant de supprimer!
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/designingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/designingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/designingacollection.htm	(revision 10506)
@@ -0,0 +1,26 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="designingacollection"><font size="5" face="Verdana"><strong>6: D&eacute;coration de l'apparence de votre collection</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+Une fois les fichiers marqu&eacute;s avec les m&eacute;ta-donn&eacute;es, on peut d&eacute;cider comment ils devraient appara&icirc;tre aux utilisateurs comme une collection Greenstone. Quel type d'information peut &ecirc;tre recherch&eacute;? Quels sont les moyens qui sont fournis pour naviguer &agrave; travers les documents? Quels sont les langages support&eacute;s? o&ugrave; apparaissent les boutons sur la page? ces choses peuvent &ecirc;tre adapt&eacute;es; cette section d&eacute;crit comment proc&eacute;der.
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/downloadingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/downloadingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/downloadingfiles.htm	(revision 10506)
@@ -0,0 +1,16 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="downloadingfiles"><font size="5" face="Verdana"><strong>3: T&eacute;l&eacute;chargement de fichiers de lIinternet</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    La vue "T&eacute;l&eacute;chargement" vous permet de t&eacute;l&eacute;charger des resources de l'internet. Cette section explique le processus de miroir de l'interface biblioth&eacute;caire.
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/enrichingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/enrichingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/enrichingacollection.htm	(revision 10506)
@@ -0,0 +1,23 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="enrichingacollection"><font size="5" face="Verdana"><strong>5: Enrichir la Collection avec des m&eacute;ta-donn&eacute;es</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Apr&egrave;s avoir rassembl&eacute; plusieurs fichiers dans la collection, on les enrichit d'une information compl&eacute;mentaire appel&eacute;e "m&eacute;ta-donn&eacute;e". Cette section explique comment une m&eacute;tadonn&eacute;e est cr&eacute;&eacute;e, &eacute;dit&eacute;e, assign&eacute;e ou retir&eacute;e, et comment utiliser les sources de m&eacute;ta-donn&eacute;es externes (voir aussi le chapitre 2 du Guide de d&eacute;veloppement de Greenstone -- "Exploitez vos documents au maximum").
+    
+    
+    
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/exportingcollections.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/exportingcollections.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/exportingcollections.htm	(revision 10506)
@@ -0,0 +1,49 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="exportingcollections"><font size="5" face="Verdana"><strong>8.3: Exportation de collections vers CD-ROM</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section d&eacute;crit comment exporter des collections vers un CD-ROM d'auto-installation Greenstone.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Comment exporter</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Greenstone peut exporter une ou plusieurs collections vers un CD-ROM d'auto-installation pour Windows. Pour ce faire, le paquetage Greenstone "Export to CD-ROM" doit &ecirc;tre install&eacute;. Il n'est pas inclut par d&eacute;faut, donc vous aurez peut &ecirc;tre &agrave; modifier votre installation pour l'inclure.
+      <p></p>
+      Pour exporter une collection, ouvrir le menu "Fichier" et choisir "Exporter vers CD-ROM". Une liste de collections Greenstone appara&icirc;t; cliquez sur n'importe laquelle pour obtenir une description. Cochez la case des collections &agrave; exporter. Vous pouvez entrer le nom du CD-ROM dans la case: c'est ce qui va appara&icirc;tre dans le menu de d&eacute;marrage lorsque le CD-ROM aura &eacute;t&eacute; install&eacute;. Puis cliquez sur "Exporter". Ce processus implique la copie de plusieurs fichiers et peut durer quelques minutes.
+      <p></p>
+      A la fin de l'op&eacute;ration, Greenstone va afficher le nom d'un dossier contenant les collections export&eacute;es. Utilisez un graveur de CD pour copier le contenu dans un CD vierge.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/fileassociations.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/fileassociations.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/fileassociations.htm	(revision 10506)
@@ -0,0 +1,67 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="fileassociations"><font size="5" face="Verdana"><strong>8.2: Associations de fichiers</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      L'Interface Biblioth&eacute;caire utilise des programmes d'application particuli&egrave;res pour ouvrir des types de fichiers particuliers. Cette section explique comment assigner et &eacute;diter ces associations de fichiers. 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+           Ajouter association
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Editer association
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Enlever association
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Pour modifier des associations ouvrez le menu "Fichier" et cliquer sur "Association de fichiers". 
+      <p></p>
+      Pour ajouter une association, s&eacute;lectionner l'extension du fichier cible dans la liste d&eacute;roulant, ou taper dans une nouvelle extension (n'y incluer pas le ".") Ensuite soit taper la commande qui lance l'application voulue dans la champ appropri&eacute;, soit choisir l'application dans le dialogue "Navigation". "%1" Peut &ecirc;tre utilis&eacute; dans la commande de lancement pour ins&eacute;rer le nom du fichier qu'on veut ouvrir. Une fois cela, "Ajouter Association" est activ&eacute;. Cliquer dessus pour ajouter l'association.
+      <p></p>
+      Pour &eacute;diter une association, s&eacute;lectionner une extension de fichier existante. Toute commande existante associ&eacute;e est affich&eacute;e dans le champ de la commande de lancement. Corriger-la, et puis cliquer sur "Remplacer Association".
+      <p></p>
+      Pour enlever une association, s&eacute;lectionner une extension de fichier existante et cliquer sur "Enlever Association". (L'extension du fichier reste dans la liste d&eacute;roulante "For Files Ending").
+      <p></p>
+      Les associations de fichiers sont stock&eacute;es dans le dossier principal du r&eacute;pertoire principal de l'Interface Biblioth&eacute;caire, dans un fichier appel&eacute; "associations.xml".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/filteringthetree.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/filteringthetree.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/filteringthetree.htm	(revision 10506)
@@ -0,0 +1,62 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="filteringthetree"><font size="5" face="Verdana"><strong>4.5: Filtrer l'arborescence</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Le "Filtrage" de l'arborescence de la collection permet de r&eacute;duire la recherche de fichiers particuliers.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Le contr&ocirc;le du filtre
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions advanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Filtrage usuel
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Le menu d&eacute;roulant des "Montrer Fichiers" ("Show Files") au bas de chaque arborescence montre une liste de filtres pr&eacute;d&eacute;finis, tels "Images". Son choix cache temporairement tous les autres fichiers de l'arborescence. Pour restorer celle-ci, changer le filtre en "Tous Fichiers". Ces op&eacute;rations n'alt&egrave;rent ni la collection, ni n'affectent les dossiers dans l'arborescence.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions advanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      On peut sp&eacute;cifier un filtre usuel en saisissant un mod&egrave;le assorti aux fichiers vis&eacute;s. Utiliser un syst&egrave;me standard d'abr&eacute;viations de fichiers telles que "*.*" ou "*.doc" (*. concerne tous les caract&egrave;res).
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/formatstatements.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/formatstatements.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/formatstatements.htm	(revision 10506)
@@ -0,0 +1,90 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="formatstatements"><font size="5" face="Verdana"><strong>6.9: Caract&eacute;ristiques de Format</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+Les Format Features et les commandes de format contr&ocirc;lent la structure et l'apparence de la collection. Ils influencent le lieu d'apparition des boutons lorsqu'un document est affich&eacute;, et d&eacute;terminent les liens qui sont affich&eacute;s par le classificateur DateList. Les commandes de format ne sont pas faciles &agrave; concevoir, et la lecture du chapitre 2 de Greenstone Developer's Guide est recommand&eacute;e. Cette section concerne les cadres de format, et  indique comment l'Interface Biblioth&eacute;caire en fournit l'acc&egrave;s. Sous "Sections de conception", cliquer sur "Caract&eacute;ristiques de Format".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Formatage
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ajouter commande de format
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Enlever commande de format
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Mettre &agrave; jour commande de format
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions advanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Options de formatage &eacute;tendues
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      On peut appliquer une commande de format &agrave; n'importe quoi dans la liste d&eacute;roulante "Choisir Caract&eacute;ristique" qui comprend tous les classificateurs de m&ecirc;me qu'une liste pr&eacute;d&eacute;finie de caract&eacute;ristiques. Deux types de contr&ocirc;les existent lorsqu'on s&eacute;lectionne une caract&eacute;ristique: Certaines caract&eacute;ristiques sont simplement activ&eacute;es ou d&eacute;sactiv&eacute;es, et le contr&ocirc;le se fait gr&acirc;ce &agrave; une liste de v&eacute;rification. D'autres requi&egrave;rent qu'on sp&eacute;cifie une cha&icirc;ne de format. Pour ces caract&eacute;ristiques, il existe une liste de retrait ("Composante Affect&eacute;e") pour la s&eacute;lection des parties de la caraxt&eacute;ristique o&ugrave; s'applique la cha&icirc;ne (si n&eacute;cessaire), une zone de texte ("Cha&icirc;ne de Format HTML") o&ugrave; on saisit la cha&icirc;ne, et une s&eacute;lection de "Variables" pr&eacute;d&eacute;finies. Pour ins&eacute;rer une variable dans la position courante dans la cha&icirc;ne de format, s&eacute;lectionner la &agrave; partir de la liste de retrait et cliquer sur "Ins&eacute;rer". 
+      <p></p>
+      Vous pouvez sp&eacute;cifier un format par d&eacute;faut pour une composante particuli&egrave;re en s&eacute;lectionnant la caract&eacute;ristique vierge.Ce format est alors appliqu&eacute; &agrave; toutes les caract&eacute;ristiques applicables sauf instruction contraire. 
+      <p></p>
+      Pour ajouter une nouvelle commande de format, remplir l'information comme indiqu&eacute;e plus haut et cliquer sur "Ajouter Format". La nouvelle commande de Format appara&icirc;t dans la liste des  "Commandes de Format fr&eacute;quemment Assign&eacute;es". Seule une commande de format peut &ecirc;tre assign&eacute;e pour chaque combinaison caract&eacute;ristique/composante.
+      <p></p>
+      Pour enlever une commande de format, s&eacute;lectionner-la sur la liste et cliquer "Enlever Format".
+      <p></p>
+      Pour modifier une commande de format, s&eacute;lectionner-la  sur la liste et cliquer sur "Remplacer Format". 
+      <p></p>
+      Pour de plus amples informations sur les variables et les composantes de caract&eacute;ristiques, lire le chapitre 2 du Guide du D&eacute;veloppeur de Greenstone. 
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions advanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      Si la bo&icirc;te de v&eacute;rification "Permettre options &eacute;tendues" est coch&eacute;e, certaines options avanc&eacute;es de formatage sont activ&eacute;es. La liste des caract&eacute;ristiques pouvant &ecirc;tre format&eacute;es est l&eacute;g&egrave;rement chang&eacute;e, et plusieurs variables sont disponibles dans la commande de format, offrant un contr&ocirc;le plus grand sur la mise en forme. 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/generalsettings.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/generalsettings.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/generalsettings.htm	(revision 10506)
@@ -0,0 +1,51 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="generalsettings"><font size="5" face="Verdana"><strong>6.2: R&eacute;glages g&eacute;n&eacute;raux</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique comment passer en revue et changer les r&eacute;glages g&eacute;neraux associ&eacute;s &agrave; la collection. D'abord, sous "Design section" cliquer "General".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            R&eacute;glages g&eacute;n&eacute;raux
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Les valeurs fournies ici peuvent &ecirc;tre modifi&eacute;es au cours de la cr&eacute;ation de la collection.
+      <p></p>
+      En haut de la page, se trouve une bo&icirc;te &agrave; instruction, qui appara&icirc;t pour chacune des diff&eacute;rentes sections. Elle contient une br&egrave;ve liste d'instructions pour vous rappeler quelle fonctionalit&eacute; est disponible:
+      <p></p>
+      D'abord, les contacts E-mail du cr&eacute;ateur et mainteneur de la collection. Le champ suivant permet le changement de titre de la collection. Le dossier dans lequel est enregistr&eacute; la collection est affich&eacute; ensuite, mais ne peut &ecirc;tre &eacute;dit&eacute;. Celui qui suit sp&eacute;cifie (sous forme d'URL) l'&icirc;cone &agrave; montrer &agrave; l'extr&eacute;mit&eacute; sup&eacute;rieure gauche de la page "About" de la collection et la suivante est l'&icirc;cone utilis&eacute;e dans la page de la biblioth&eacute;que Greenstone &agrave; lier &agrave; la collection. Puis, une case permet de contr&ocirc;ler si la collection est accessible au public. Enfin, la zone texte de "la description de la Collection" comme d&eacute;crit <a href="creatingacollection.htm#creatingacollection">Cr&eacute;er une nouvelle collection</a>.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/help.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/help.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/help.xml	(revision 10506)
@@ -0,0 +1,1018 @@
+<Document>
+  <Section name="introduction">
+    <Title>Introduction</Title>
+    L'interface bibliothÃ©caire de Greenstone est un outil pour collecter et enrichir des documents et ensuite mettre sur pied des collections de bibliothÃšques numÃ©riques. Il fournit un accÃšs Ã  la fonctionnalitÃ© du logiciel de la BibliothÃšque numÃ©rique de Greenstone Ã  partir d'un point de vue graphique et d'une interface "clic".
+    <Section name="ofmiceandmenus">
+      <Title>Dessouris et Menus</Title>
+      La section "Dessouris et Menus" fournit une information de base sur la maniÃšre de dialoguer avec l'interface bibliothÃ©caire. Si on est familier avec des programmes comme Internet Explorer ou Microsoft Office et aussi Ã  l'aise avec les menus et les clics de la souris, passer Ã  <Reference target="howtoavoidthisdocument">section suivante</Reference>.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    Concepts de base
+            <ContentsItem>TÃ¢ches de la souris</ContentsItem>
+            <ContentsItem>Clavier</ContentsItem>
+          </ContentsItem>
+          <ContentsItem>Quitter le programme</ContentsItem>
+	</ContentsGroup>
+	<ContentsGroup linkto="advanced">
+          <ContentsItem>Touches de raccourcis</ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      L'interface bibliothÃ©caire suit les conventions de Microsoft Windows et requiert une connaissance de base de Windows.
+      <Break/>
+      Une position quelconque d'interaction sur l'Ã©cran, tel qu'un bouton ou un champ de texte, est appelÃ©e "contrÃŽle". A tout moment, un contrÃŽle appelÃ© "Foyer" est mis en relief et rÃ©pond au clavier. Plusieurs contrÃŽles vous permettent de sÃ©lectionner les parties qui sont mises en relief en bleu foncÃ©. Certains contrÃŽles virent au gris pour indiquer qu'ils sont Ã©teints.
+      <Break/>
+      On peut dÃ©placer la souris, cliquer sur son bouton gauche (cliquer-gauche) ou sur son bouton droit (cliquer-droite) de faÃ§on tout Ã  fait usuelle. Plusieurs Ã©lÃ©ments sont susceptibles d'Ãªtre entrainÃ©s par glissement de la souris son bouton gauche Ã©tant maintenu appuyÃ©, et d'Ãªtre ainsi dÃ©posÃ©s quelque part en relÃ¢chant le bouton. Des cibles de dÃ©pÃŽt potentielles changent d'apparence quand un composant les atteint.
+      <Break/>
+      On peut utiliser le clavier pour la saisie Ã  l'intÃ©rieur des champs de texte. Des alternatives au clavier sont disponibles pour plusieurs contrÃŽles indiquÃ©s par un nom clÃ© entre crochets --- par exemple [Tab] change le foyer. Le signe plus indique les autres touches susceptibles d'Ãªtre appuyÃ©es en mÃªme temps.
+      <Break/>
+      Pour quitter l'Interface BibliothÃ©caire, on utilise "Sortir" du menu "Fichier". Votre collection sera d'abord sauvegardÃ©e.
+      <Anchor name="advanced">Instructions avancÃ©es:</Anchor>
+      Pour accÃ©der au menu, appuyer sur le bouton [Alt] et sur la lettre correspondante (soulignÃ©e). Par exemple, pour le menu "Fichier" appuyer sur [Alt] + [F]. Pour choisir un Ã©lÃ©ment, appuyer sur la touche correspondante. Par exemple, lorsque le menu "Fichier" est dÃ©roulÃ©, appuyer sur "S" pour sauvegarder la collection.
+    </Section>
+    <Section name="howtoavoidthisdocument">
+      <Title>Comment Ã©viter de lire ce document</Title>
+      Ne pas lire l'Aide en entier! Lire juste ce qui est nÃ©cessaire pour obtenir l'aide dont on a besoin.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>Aide contextuelle intuitive</ContentsItem>
+          <ContentsItem>Outils (Tool tips)</ContentsItem>
+          <ContentsItem>Autres documents</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      L'Ã©lÃ©ment de menu Aide indique l'Ã©lÃ©ment d'aide le plus appropriÃ© par une icÃŽne sous forme de petit livre. 
+      <Break/>
+      Le positionnement de la souris sur plusieurs contrÃŽles entraÃ®ne l'apparition d'un "Tool tip" qui dit ce qu'il faut faire.
+      <Break/>
+      Avant d'utiliser l'Interface BibliothÃ©caire, il faut lire la documentation Greenstone. La section "CrÃ©er une Nouvelle Collection" dÃ©crit comment crÃ©er une nouvelle collection. Avant d'utiliser l'Interface BiblithÃ©caire, lire d'abord la documentation de Greenstone.
+    </Section>
+  </Section>
+
+  <Section name="startingoff">
+    <Title>DÃ©marrage</Title>
+    Cette section explique comment crÃ©er, charger, enregistrer et supprimer des collections.
+    <Section name="creatingacollection">
+      <Title>CrÃ©er une nouvelle collection</Title>
+      <ObviousSentence>Cette section dÃ©crit la maniÃšre de crÃ©er une nouvelle collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            La nouvelle collection confirmÃ©e
+          </ContentsItem>
+          <ContentsItem>
+            Le titre de la collection
+          </ContentsItem>
+          <ContentsItem>
+            jeux de mÃ©ta-donnÃ©es par dÃ©faut
+          </ContentsItem>
+          <ContentsItem>
+            Description de la collection
+          </ContentsItem>
+          <ContentsItem>
+            CrÃ©er la nouvelle collection
+          </ContentsItem>
+          <ContentsItem>
+            Annuler la nouvelle collection
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Touches de raccourci
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Pour crÃ©er la nouvelle collection, ouvrir le menu "Fichier" et choisir "Nouveau". Plusieurs champs doivent Ãªtre remplis -- mais leurs valeurs sont susceptibles d'Ãªtre modifiÃ©es Ã  souhait dans l'affichage de la conception.
+      <Break/>
+      "Titre de la collection" est le texte affichÃ© en haut de la page d'accueil de votre collection. Sa longueur peut Ãªtre quelconque.
+      <Break/>
+      "Description du contenu" doit dÃ©crire avec le plus de dÃ©tails possibles ce que la collection est. Utiliser la touche [EntrÃ©e] pour la diviser en paragraphes.
+      <Break/>
+      On doit enfin spÃ©cifier soit que la nouvelle collection aura la mÃªme forme et les mÃªmes jeux de mÃ©ta-donnÃ©es que la collection existante, soit qu'elle est initiÃ©e  "Nouvelle collection" par dÃ©faut.
+      <Break/>
+      Cliquer sur "OK" pour crÃ©er la collection. Si on choisit "Nouvelle collection", les jeux de mÃ©ta-donnÃ©es disponibles sont affichÃ©es. On peut en choisir plus d'une et en ajouter d'autres ultÃ©rieurement.
+      <Break/>
+      Le clic sur "Annuler" ramÃšne immÃ©diatement l'Ã©cran principal.
+      <Anchor name="advanced">Instructions advancÃ©es:</Anchor>
+      Les boutons, tels les menus, ont un caractÃšre soulignÃ©. Pour cliquer sur le bouton, appuyer en mÃªme temps sur [Alt] et sur le caractÃšre soulignÃ©.
+    </Section>
+    <Section name="savingacollection">
+      <Title>Enregistrer la Collection</Title>
+      <ObviousSentence>Cette section dÃ©crit la maniÃšre d'enregistrer une collection, et la confirmation d'enregistrement de la collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Comment enregistrer
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            OÃ¹ sont sauvegardÃ©s les fichiers
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Enregistrer rÃ©guliÃšrement votre travail en choisissant "Enregistrer" dans le fichier "Menu". Enregistrer une collection ne signifie pas la rendre prÃªte Ã  l'utilisation dans Greenstone (see <Reference target="producingthecollection">Confectionner votre Collection</Reference>).
+      <Break/>
+      L'Interface BiblithÃ©caire protÃšge votre travail en l'enregistrant Ã  la fermeture du programme ou Ã  l'ouverture d'une autre collection.
+      <Anchor name="advanced">Instructions advancÃ©es:</Anchor>
+      Les collections sont enregistrÃ©es en un fichier choisi pour la collection avec une extension ".col", localisÃ© dans un rÃ©pertoire de mÃªme nom Ã  l'intÃ©rieur du dossier "collect" de l'installation de Greenstone.
+    </Section>
+    <Section name="openingacollection">
+      <Title>Ouvrir une collection existante</Title>
+      <ObviousSentence>Cette section indique la maniÃšre d'ouvrir des collections existantes en utilisant "PrÃªt pour Ouvrir Collection".</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>Comment ouvrir la Collection</ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>Collections verrouillÃ©es</ContentsItem>
+	  <ContentsItem>Collections de versions antÃ©rieures</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Pour ouvrir une collection existante, choisir "ouvrir" Ã  partir du menu "Fichier" pour obtenir le "PrÃªt Ã  l'ouverture de la collection". Une liste de vos collections Greenstone apparaÃ®t. En sÃ©lectionner une pour voir sa description, et cliquer sur "Ouvrir" pour la charger. Si l'on cherche une collection qui est hors du dossier "Collect" de Greenstone, cliquer sur "Parcourir" pour un dialogue avec le systÃšme de fichiers concernÃ©.
+      <Anchor name="advanced">Instructions advancÃ©es:</Anchor>
+      Dans le cas oÃ¹ plusieurs programmes d'Interface BibliothÃ©caire de Greenstone sont exÃ©cutÃ©s simultanÃ©ment, les rÃ©pertoires concernÃ©s sont vÃ©rouillÃ©s pour prÃ©venir une interfÃ©rence. A l'ouverture d'une collection, un petit fichier de verrouillage temporaire est crÃ©Ã© dans son dossier. Avant d'ouvrir une collection, l'interface BibliothÃ©caire vÃ©rifie qu'aucun fichier de verrouillage n'existe dÃ©jÃ . Le verrouillage d'une collection est indiquÃ© par la couleur de son icÃŽne: verte pour une collection normale, rouge quand elle est vÃ©rouillÃ©e. Cependant, quand l'on quitte l'Interface BibliothÃ©caire prÃ©maturÃ©ment, le fichier de verrouillage est parfois laissÃ© en place. Quand une telle collection est ouverte, l'Interface BibliothÃ©caire demande si l'on veut se dÃ©faire de son contrÃŽle. Ne jamais sosutraire une collection en cours d'utilisation par un autre.
+      <Break/>
+      Lorsque vous ouvrez une collection qui n'a pas Ã©tÃ© crÃ©Ã©e par Greenstone Librarian Interface, on vous demande de sÃ©lectionner un ou plusieurs jeux de mÃ©ta-donnÃ©es. Si vous n'en sÃ©lectionnez aucun, les mÃ©ta-donnÃ©es existantes seront ignorÃ©es. Dans le cas contraire, les mÃ©ta-donnÃ©es seront importÃ©es comme lorsque vous cliquez et glisser dans des fichiers contenant des mÃ©ta-donnÃ©es. Ce processus est dÃ©crit dans la section <Reference target="importingpreviouslyassignedmetadata">Importation de MÃ©ta-donnÃ©es PrÃ©cÃ©demment AssignÃ©es</Reference>.
+    </Section>
+    <Section name="deletingcollections">
+      <Title>Suppression des collections</Title>
+      <ObviousSentence>Cette section explique comment supprimer dÃ©finitivement des collections de votre installation Greenstone.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Comment supprimer des collections
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Pour supprimer dÃ©finitivement des collections de votre installation Greenstone, choisir "Supprimer..." dans le menu "Fichier". Une liste de vos collections Greenstone apparaÃ®t. Selectionner une collection pour vior sa description, puis cocher la case en bas du dialogue et clicquez "Supprimer" pour supprimer la collection. Cette operation est irrÃ©versible, vÃ©rifiez bien que vous n'avez plus besoin de cette collection avant de supprimer!
+    </Section>
+  </Section>
+
+  <Section name="downloadingfiles">
+    <Title>TÃ©lÃ©chargement de fichiers de lIinternet</Title>
+    La vue "TÃ©lÃ©chargement" vous permet de tÃ©lÃ©charger des resources de l'internet. Cette section explique le processus de miroir de l'interface bibliothÃ©caire.
+    <Section name="themirrorview">
+      <Title>La vue TÃ©lÃ©chargement</Title>
+      Cette section dÃ©crit comment on configure une tache de tÃ©lÃ©chargement et comment on contrÃŽle le tÃ©lÃ©chargement.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            L'arbre espace de travail
+          </ContentsItem>
+          <ContentsItem>
+            Configuration de tÃ©lÃ©chargement
+          </ContentsItem>
+          <ContentsItem>
+            La liste des tÃ©lÃ©chargements
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Activation des proxies web
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      AccÃ©dez Ã  la vue "TÃ©lÃ©chargement" en cliquant son index. La moitiÃ© supÃ©rieure de l'Ã©cran montre le contrÃŽle des tÃ©lÃ©chargements. La moitiÃ© infÃ©rieure est initialement vide, mais montrera la liste des tÃ©lÃ©chargements en attente et rÃ©alisÃ©s.
+      <Break/>
+      Les fichiers sont tÃ©lÃ©chargÃ©s dans un dossier de l'espace de travail appelÃ© Â«Â Fichiers TÃ©lÃ©chargÃ©sÂ Â» (Uniquement prÃ©sent lorsque l'opÃ©ration Â«Â miroirÂ Â» est activÃ©e), et peut Ãªtre utilisÃ© pour toutes les collections construites avec l'interface bibliothÃ©caire. Les fichiers dans cette zone portent comme nom leur URL en entier. Un nouveau dossier est crÃ©Ã© pour chaque site hÃŽte, suivi par d'autres dossiers pour chaque Ã©lÃ©ment du chemin. Cela permet de s'assurer que chaque fichier a un nom distinct.
+      <Break/>
+      Utilisez le premier des contrÃŽles de la configuration de tÃ©lÃ©chargement, Â« Source URL Â», pour entrer l'URL de la ressource cible. Utilisez le contrÃŽle Â« Profondeur de TÃ©lÃ©chargement Â»  pour limiter le nombre de liens hypertextes Ã  suivre pour le tÃ©lÃ©chargement : utiliser 0 pour tÃ©lÃ©charger une seule page ; utiliser 1 pour tÃ©lÃ©charger la page et toutes les pages rÃ©fÃ©rencÃ©es par des liens hypertextes. La profondeur limite est ignorÃ©e lors du tÃ©lÃ©chargement de mÃ©dia autres que des pages html. Ensuite il y a plusieurs cases Ã  cocher qui peuvent Ãªtre cochÃ©es pour activer l'option spÃ©cifiÃ©e. Une fois la configuration prÃªte, cliquez Â« TÃ©lÃ©charger Â» pour dÃ©marrer l'opÃ©ration de tÃ©lÃ©chargement. Il y a deux autres boutons de contrÃŽle : Â« PrÃ©fÃ©rences Â», qui renvoie Ã  la section connexion de PrÃ©fÃ©rences ou les paramÃštre du proxy peuvent Ãªtre Ã©ditÃ©s ; et Â« Effacer la cache Â» qui supprimes tous les fichiers tÃ©lÃ©chargÃ©s prÃ©cÃ©demment.
+      <Break/>
+      La liste de tÃ©lÃ©chargement a une entrÃ©e pour chaque tÃ©lÃ©chargement de page Web.  Chaque entrÃ©e a une rÃ©gion de textes qui donne les dÃ©tails de la tÃ¢che avec une barre de progrÃšs montrant l'activitÃ© courante.  Trois boutons apparaissent Ã  la gauche de chaque entrÃ©e.  "Pause" est employÃ© pour pauser une tÃ¢che en cours de tÃ©lÃ©chargement.  "Voir le rÃ©sumÃ©" ouvre une fenÃªtre montrant l'historique du tÃ©lÃ©chargement.  "Fermer" termine le tÃ©lÃ©chargement et enlÃšve la tÃ¢che de la liste.
+      <Anchor name="advanced">Instructions advancÃ©es:</Anchor>
+      La <Reference target="preferences">section PrÃ©fÃ©rences</Reference> explique comment Ã©tablir une connection Internet Ã  travers un proxy.  Si l'authentification est nÃ©cessaire, le proxy server demande l'identification et le mot de passe.  L'interface bibliothÃ©caire n'enregistre pas les mots de passe entre les sessions.
+    </Section>
+  </Section>
+
+  <Section name="collectingfiles">
+    <Title>Collecter les fichiers pour la Collection</Title>
+    DÃšs lors que l'on dispose d'une nouvelle collection, la nÃ©cessitÃ© se fait sentir de la doter de fichiers. Ils peuvent provenir de votre espace fichier ordinaire ou d'autres collections Greenstone. Quelques uns peuvent avoir des mÃ©ta-donnÃ©es attachÃ©es.Cette section dÃ©crit comment importer des fichiers.
+    <Section name="thegatherview">
+      <Title>L'affichage Rassembler</Title>
+cette section introduit la zone Rassembler utilisÃ©e pour selectionner les fichiers Ã  inclure dans la collection Ã  crÃ©er. 
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+           comment afficher l'Ã©cran "gather"
+          </ContentsItem>
+          <ContentsItem>
+            Les arborescences de fichiers
+          </ContentsItem>
+          <ContentsItem>
+            La zone d'Ã©tat
+          </ContentsItem>
+          <ContentsItem>
+            Boutons de contrÃŽle
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            mÃ©thodes de sÃ©lection
+          </ContentsItem>
+          <ContentsItem>
+            Application de dossiers spÃ©ciaux
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      L'Interface BibliothÃ©caire dÃ©marre avec l'affichage "Rassembler". Pour revenir ultÃ©rieurement Ã  celui-ci, cliquer directement sur l'onglet "Rassembler" au bas de la barre des menus.
+      <Break/>
+      Les deux vastes zones intitulÃ©es "Espace de travail" et "Collection" servent au transfert des fichiers vers la collection. Elles contiennent des arborescences de fichiers, des structures graphiques qui reprÃ©sentent des fichiers et des dossiers.
+      <Break/>
+      Choisir un Ã©lÃ©ment dans l'arborescence en cliquant dessus. (d'autres maniÃšres de le faire existent; voir ci-dessous). Double-cliquer sur un dossier, ou cliquer simplement sur le symbole de commutateur placÃ© Ã  cÃŽtÃ© de lui, pour dÃ©velopper (ou rÃ©duire) son contenu. Double-cliquer sur un fichier pour l'ouvrir en utilisant un programme d'application associÃ© (voir <Reference target="fileassociations">Association de fichiers</Reference>).
+      <Break/>
+      L'arbre des fichiers de l'espace de travail montre les sources de donnÃ©es disponibles pour l'interface bibliothÃ©caire -- le systÃšme de fichiers local (ainsi que les unitÃ©s de disques et Cd-rom), le contenu des collection Greenstone, et la cache des fichiers tÃ©lÃ©chargÃ©s si l'option Web Â«Â miroirÂ Â» est active. Vous pouvez copier et afficher ces fichiers mais vous ne pouvez pas les dÃ©placer, supprimer ou Ã©diter, Ã  l'exception des fichiers tÃ©lÃ©chargÃ©s qui peuvent Ãªtre supprimÃ©. Vous pouvez naviguer Ã  l'intÃ©rieur de cet espace pour trouver les documents que vous souhaitez ajouter Ã  la collection.
+      <Break/>
+      L'arborescence des fichiers de la Collection ne reprÃ©sente jusque-lÃ  que le contenu de la collection. Elle est initialement vide.
+      <Break/>
+      On peut redimensionner les espaces en positionnant la souris sur la barre grise qui sÃ©pare les arborescences (le pointeur change de forme) et en la faisant glisser.
+      <Break/>
+      En bas de la fenÃªtre, il y a une barre d'Ã©tat qui montre l'Ã©volution des opÃ©rations sur les fichiers (copie, dÃ©placement et suppression). Ces opÃ©rations peuvent Ãªtre longues. Le bouton "Stop" arrÃªte toute tÃ¢che en cours.
+      <Break/>
+      Deux grands boutons occupent le coin droit infÃ©rieur de l'Ã©cran. "Nouveau dossier", avec une image d'un dossier, crÃ©e de nouveaux dossiers (voir <Reference target="creatingfolders">CrÃ©ation de dossiers</Reference>). "Supprimer", avec une corbeille, supprime les fichiers. Cliquer sur le bouton "Supprimer" dÃ©truit tous les fichiers sÃ©lectionnÃ©s de l'arborescence de fichiers de la collection. On peut de mÃªme rÃ©aliser cette suppression de fichiers en les faisant glisser jusqu'au bouton "Supprimer". 
+      <Anchor name="advanced">Instructions avancÃ©es:</Anchor>
+      Pour sÃ©lectionner plusieurs sÃ©quences d'Ã©lÃ©ments, sÃ©lectionner le premier, maintenir appuyÃ©e la touche [Maj] et cliquer sur le dernier Ã©lÃ©ment de la sÃ©quence -- la sÃ©lection comprendra tous les Ã©lÃ©ments compris entre les deux. Pour la sÃ©lection de fichiers qui ne se suivent pas, maintenir la touche [Ctrl] appuyÃ©e en cliquant sur chacun d'eux. Ces deux mÃ©thodes peuvent Ãªtre utilisÃ©es ensemble pour la sÃ©lection de jeux d'Ã©lÃ©ments non adjacents.
+      <Break/>
+      Certains dossiers -- tel que celui contenant vos propres pages Web -- ont parfois une signification spÃ©ciale. L'Interface BibliothÃ©caire peut appliquer de tels dossiers au premier niveau de l'arborescence de fichiers. Pour ce faire double-cliquer droite sur le dossier visÃ©. Choisir "CrÃ©er un Raccourci", saisir le nom du dossier. Pour enlever un Ã©lÃ©ment, cliquer-droite sur le fichier concernÃ© et sÃ©lectionner "Supprimer Raccourci".
+    </Section>
+    <Section name="creatingfolders">
+      <Title>CrÃ©er des dossiers</Title>
+      <ObviousSentence>Cette section indique la maniÃšre de crÃ©er de nouveaux dossiers</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Le bouton Nouveau Dossier
+          </ContentsItem>
+          <ContentsItem>
+            Le menu bouton-droit
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Utiliser les dossiers de l'arborescence de fichiers de la collection pour rejeur les fichiers et les rendre aisÃ©ment accessibles. Des dossiers peuvent Ãªtre placÃ©s Ã  l'intÃ©rieur d'autres dossiers. Aucune limite, virtuellement parlant, ni au nombre de dossiers dont on peut disposer ni Ã  la complexitÃ© de leur agencement.
+      <Break/>
+      Pour crÃ©er un nouveau dossier, on peut opter pour un dossier existant et cliquer sur le bouton Nouveau Dossier. Le nouveau dossier apparaÃ®t Ã  l'intÃ©rieur de celui choisi, ou au niveau supÃ©rieur si aucun n'est choisi. Le nom de ce dossier est rÃ©clamÃ© ( Ã  dÃ©faut, il sera nommÃ© "Nouveau Dossier").
+      <Break/>
+      Les dossiers peuvent aussi Ãªtre crÃ©Ã©s en cliquant sur le dossier avec le bouton droit, et en choisissant "Nouveau Dossier" et procÃ©der comme ci-dessus.
+    </Section>
+    <Section name="addingfiles">
+      <Title>Ajouter des fichiers</Title>
+      <ObviousSentence>Cette section indique la maniÃšre d'inclure des fichiers dans la collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            glisser-dÃ©placer
+          </ContentsItem>
+          <ContentsItem>
+            fichiers multiples
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            mÃ©ta-donnÃ©es existantes
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Les fichiers peuvent Ãªtre copiÃ©s dans la collection par glisser-dÃ©placer. Le pointeur Ã©pouse la forme de l'Ã©lÃ©ment sÃ©lectionnÃ© (ou, si la sÃ©lection comprend plus d'un, leur nombre). DÃ©poser la sÃ©lection dans l'arborescence de la collection pour les y copier (si la source est l'arborescence de l'espace de travail) ou les dÃ©placer Ã  l'intÃ©rieur de la collection (si la source est l'arborescence de la collection).
+      <Break/>
+      Lorsque des fichiers multiples sont copiÃ©s, ils sont tous placÃ© dans le dossier cible au mÃªme niveau, quelle que soit la structure du dossier qui les contenait avant. Si vous copier un second fichier avec le mÃªme nom dans le mÃªme dossier, la question de savoir si le premier fichier doit Ãªtre Ã©crasÃ© est posÃ©e. Si la rÃ©ponse est non, le fichier ne sera pas copiÃ©, mais les autres le seront. Pour annuler toutes les autre tÃ¢ches de copie, cliquer sur le bouton "Stop".
+      <Break/>
+      Seuls les Ã©lÃ©ments situÃ©s au-dessus dans la sÃ©lection sont dÃ©placÃ©s. Un dossier est plus Ã©levÃ© que son contenu. On ne peut sÃ©lectionner en mÃªme temps l'intÃ©rieur d'un dossier et le dossier lui-mÃªme.
+      <Anchor name="advanced">Instructions avancÃ©es:</Anchor>
+      Lorsqu'un fichier est ajoutÃ©, l'Interface BibliothÃ©caire cherche les dossiers sources de fichiers auxiliaires contenant une mÃ©ta-donnÃ©e qui lui originellement assignÃ©es et, s'il en trouve, commence Ã  les importer. Au fur et Ã  mesure que l'opÃ©ration se poursuit, une confirmation est faite (peut-Ãªtre plusieurs fois) de fournir des informations complÃ©mentaires pour ajuster la mÃ©ta-donnÃ©e aux jeux de mÃ©ta-donnÃ©es de la collection. Ces confirmations sont dÃ©crites dans la section <Reference target="importingpreviouslyassignedmetadata">Importer des mÃ©ta-donnÃ©es originellement assignÃ©es </Reference>. Pour une explication plus dÃ©taillÃ©e de l'association de mÃ©ta-donnÃ©es avec les fichiers, lire le chapitre 2 du Guide de dÃ©veloppement de Greenstone -- "Exploitez vos documents au maximum".
+    </Section>
+    <Section name="removingfiles">
+      <Title>Supprimer des Fichiers</Title>
+      <ObviousSentence>Cette section dÃ©crit la maniÃšre de supprimer des fichiers et des dossiers de la collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Le bouton Supprimer
+          </ContentsItem>
+          <ContentsItem>
+            La touche Supprimer
+          </ContentsItem>
+          <ContentsItem>
+            Supprimer par glisser-dÃ©placer
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Il existe plusieurs mÃ©thodes pour supprimer des fichiers et des dossiers. On doit d'abord indiquer les Ã©lÃ©ments Ã  supprimer en sÃ©lectionnant un ou plusieurs fichiers et dossiers comme dÃ©crit dans <Reference target="thegatherview">L'Affichage Rassembler (The Gather view)</Reference>.
+      <Break/>
+      DÃšs lors que les fichiers sont sÃ©lectionnÃ©s, cliquer sur le bouton "Supprimer" pour les dÃ©truire, ou appuyer sur la touche [Delete] de votre clavier, ou les glisser-dÃ©placer de la collection vers le bouton "Supprimer" et les y dÃ©poser.
+    </Section>
+    <Section name="filteringthetree">
+      <Title>Filtrer l'arborescence</Title>
+      Le "Filtrage" de l'arborescence de la collection permet de rÃ©duire la recherche de fichiers particuliers.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Le contrÃŽle du filtre
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Filtrage usuel
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Le menu dÃ©roulant des "Montrer Fichiers" ("Show Files") au bas de chaque arborescence montre une liste de filtres prÃ©dÃ©finis, tels "Images". Son choix cache temporairement tous les autres fichiers de l'arborescence. Pour restorer celle-ci, changer le filtre en "Tous Fichiers". Ces opÃ©rations n'altÃšrent ni la collection, ni n'affectent les dossiers dans l'arborescence.
+      <Anchor name="advanced">Instructions advancÃ©es:</Anchor>
+      On peut spÃ©cifier un filtre usuel en saisissant un modÃšle assorti aux fichiers visÃ©s. Utiliser un systÃšme standard d'abrÃ©viations de fichiers telles que "*.*" ou "*.doc" (*. concerne tous les caractÃšres).
+    </Section>
+  </Section>
+
+  <Section name="enrichingacollection">
+    <Title>Enrichir la Collection avec des mÃ©ta-donnÃ©es</Title>
+    AprÃšs avoir rassemblÃ© plusieurs fichiers dans la collection, on les enrichit d'une information complÃ©mentaire appelÃ©e "mÃ©ta-donnÃ©e". Cette section explique comment une mÃ©tadonnÃ©e est crÃ©Ã©e, Ã©ditÃ©e, assignÃ©e ou retirÃ©e, et comment utiliser les sources de mÃ©ta-donnÃ©es externes (voir aussi le chapitre 2 du Guide de dÃ©veloppement de Greenstone -- "Exploitez vos documents au maximum").
+    <Section name="theenrichview">
+      <Title>L'affichage Enrichir</Title>
+      <ObviousSentence>Cette section dÃ©crit comment insÃ©rer et Ã©diter une mÃ©ta-donnÃ©e en utilisant l'affichage Enrichir.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            L'arborescence de la collection
+          </ContentsItem>
+          <ContentsItem>
+            Les contrÃŽles d'Ã©dition de mÃ©ta-donnÃ©es
+          </ContentsItem>
+          <ContentsItem>
+            L'arborescence valeur
+          </ContentsItem>
+          <ContentsItem>
+           La mÃ©ta-donnÃ©e Table
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Utiliser l'affichage Enrichir pour assigner une mÃ©ta-donnÃ©e aux documents de la collection. Une mÃ©ta-donnÃ©e est une donnÃ©e sur une donnÃ©e -- de faÃ§on typique titre, auteur, date de crÃ©ation, et ainsi de suite. Chaque Ã©lÃ©ment de mÃ©ta-donnÃ©e a deux parties: "elÃ©ment" indique le type d'Ã©lÃ©ment (par exemple auteur), "valeur" qui donne la valeur de cette mÃ©ta-donnÃ©e Ã©lÃ©ment (par exemple le nom de l'auteur).
+      <Break/>
+      Sur la gauche de l'affichage "Enrichir" est l'arborescence de la collection. A sa droite, la Table de MÃ©ta-donnÃ©es, qui montre les mÃ©ta-donnÃ©es pour tous les fichiers et dossiers sÃ©lectionnÃ©es de l'arborescence de la collection. Les colonnes sont indiquÃ©es en gris en haut, et peuvent Ãªtre redimensionnÃ©es en faisant glisser la ligne de sÃ©paration. Clicquez sur n'importe quelle ligne pour transfÃ©rer ses informations aux contÃŽles de mÃ©ta-donnÃ©es ci-dessous. Si plusieurs fichiers sont sÃ©lectionnÃ©s, un texte en noir indique que la valeur est commune Ã  tous les fichiers sÃ©lectionnÃ©s, tandis qu'un texte en gris en indique le contraire. les valeurs en noir peuvent Ãªtre mises Ã  jour ou supprimÃ©es, tandis que celles en gris peuvent Ãªtre supprimÃ©es de ceux qui l'ont, ou ajoutÃ©es aux autres.
+      <Break/>
+      Une icÃŽne de dossier peut apparaÃ®tre Ã  cÃŽtÃ© de certaines entrÃ©es de mÃ©ta-donnÃ©es. Ceci indique que les valeurs ont Ã©tÃ© hÃ©ritÃ©es d'un dossier parent. Les mÃ©ta-donnÃ©es hÃ©ritÃ©es ne peuvent Ãªtre Ã©ditÃ©es ou supprimÃ©es, mais seulement ajoutÃ©es ou Ã©crasÃ©es. Cliquer sur l'icÃŽne du dossier pour aller immÃ©diatement au dossier oÃ¹ la mÃ©ta-donnÃ©e est assignÃ©e.
+      <Break/>
+      Les contrÃŽles d'Ã©dition de mÃ©ta-donnÃ©es en bas Ã  droite apparaissent seulement quand un fichier dans l'arbre et une ligne dans la table sont sÃ©lectionnÃ©s. Utiliser les pour mettre Ã  jour, ajouter et supprimer la valeur de la mÃ©ta-donnÃ©e. Le champ valeur sert Ã  la saisie et Ã  l'Ã©dition de la valeur de la mÃ©ta-donnÃ©e. A cÃŽtÃ©, le bouton de label "..." permet d'ouvrir une grande boÃ®te d'Ã©dition. Les autres boutons situÃ©s en-dessous sont: "Coller ou ajouter" assigne la valeur comme nouvelle mÃ©ta-donnÃ©e et l'ajoute aux valeurs existantes de l'Ã©lÃ©ment sÃ©lectionnÃ©; "Remplacer" Ã©crase la valeur existante sÃ©lectionnÃ©e avec la nouvelle; "Supprimer" efface la valeur sÃ©lectionnÃ©e. Au bas, le label "Toutes les valeurs prÃ©cÃ©dentes" est la "Value Tree" ("Arborescence Valeur").
+      <Break/>
+      Celle-ci, dÃ©veloppe et comprime. C'est une liste qui, de faÃ§on usuelle, montre toutes les valeurs prÃ©cÃ©demment saisies pour un Ã©lÃ©ment sÃ©lectionnÃ©. Le clic sur une entrÃ©e la place automatiquement dans le champ valeur. Inversement, la saisie dans le champ texte sÃ©lectionne l'entrÃ©e de l'Arborescence Valeur qui dÃ©bute avec les caractÃšres saisis. Appuyer sur [Tab] complÃšte automatiquement la saisie de la valeur sÃ©lectionnÃ©e.
+      <Break/>
+      Les valeurs de mÃ©ta-donnÃ©e peuvent Ãªtre organisÃ©es en une hiÃ©rarchie.Ceci est montrÃ© dans l'Arborescence Valeur utilisant des dossiers de niveau interne.Les valeurs hiÃ©rarchiques peuvent Ãªtre saisies en utilisant le caractÃšre "|" pour sÃ©parer les niveaux. Par exemple, "Cards|Red|Diamonds|Seven" peut Ãªtre utilisÃ© dans une hiÃ©rarchie qui reprÃ©sente un jeu de cartes. Cela permet le rejeument des valeurs. Les jeux peuvent aussi Ãªtrre assignÃ©s comme mÃ©ta-donnÃ©e.
+      <Break/>
+      Greenstone extrait automatiquement des mÃ©ta-donnÃ©es Ã  partir des documents en un jeu de mÃ©ta-donnÃ©es dont les Ã©lÃ©ments sont prÃ©fixÃ©s "ex.". Ceci n'a aucune valeur et ne peut Ãªtre Ã©ditÃ©, et dÃšs lors les contrÃŽles MetaEdit sont cachÃ©s si une telle entrÃ©e est sÃ©lectionnÃ©e. Le bouton "..." sert toujours au dÃ©veloppement de la valeur, mais le texte ne peut Ãªtre Ã©ditÃ©.
+    </Section>
+    <Section name="selectingmetadatasets">
+      <Title>SÃ©lectionner les jeux de mÃ©ta-donnÃ©es</Title>
+      <ObviousSentence>Cette section explique comment spÃ©cifier les Ã©lÃ©ments mÃ©ta-donnÃ©e et comment ajouter les jeux de mÃ©ta-donnÃ©es Ã  une collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    Qu'est-ce qu'un jeu de mÃ©ta-donnÃ©es?
+          </ContentsItem>
+          <ContentsItem>
+	    ContrÃŽle des jeux de mÃ©ta-donnÃ©es utilisÃ©s
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Les sÃ©ries d'Ã©lÃ©ments de mÃ©ta-donnÃ©es prÃ©dÃ©finis sont connus comme "jeux de MÃ©ta-donnÃ©es". "Dublin Core" en est un exemple. Quand on ajoute un Groupe de MÃ©ta-donnÃ©es Ã  la collection, ses Ã©lÃ©ments peuvent Ãªtre sÃ©lectionnÃ©s. On peut avoir plus d'un jeu de mÃ©ta-donnÃ©es ; pour Ã©viter des tÃ©lescopages de nom, un identificateur abrÃ©gÃ© qui identifie le jeu de mÃ©ta-donnÃ©es est suspendu au nom de l'Ã©lÃ©ment. Par exemple l'Ã©lement crÃ©ateur de Dublin Core devient "dc.Creator". Les jeux de mÃ©ta-donnÃ©es sont sauvÃ©gardÃ©s dans le dossier de mÃ©ta-donnÃ©es de l'Interface BibliothÃ©caire et ont le sufixe ".mds".
+      <Break/>
+      Pour contrÃŽler les jeux de mÃ©ta-donnÃ©es utilisÃ©s dans une collection, utilisez l'entrÃ©e "Jeux MÃ©ta-DonnÃ©es" sur la vue "Conception".
+    </Section>
+    <Section name="appendingmetadata">
+      <Title>Ajout de Nouvelles MÃ©ta-donnÃ©es</Title>
+      <ObviousSentence>Cette section explique comment ajouter des mÃ©ta-donnÃ©es et des valeurs Ã  des fichiers, et comment ajouter de nouvelles valeurs pour des Ã©lÃ©ments de mÃ©ta-donnÃ©es.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Ajouter aux fichiers
+          </ContentsItem>
+          <ContentsItem>
+            Ajouter aux rÃ©pertoires et aux fichiers multiples
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            HiÃ©rarchies de valeur et Ã©dition des valeurs
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      On ajoute un Ã©lÃ©ment mÃ©ta-donnÃ©e -- Ã©lÃ©ment et valeur Ã  la fois -- Ã  un fichier. SÃ©lectionner d'abord le fichier Ã  partir de l'arborescence de fichier de la collection situÃ©e Ã  gauche. Cette action entraÃ®ne l'apparition de toute mÃ©ta-donnÃ©e prÃ©-assignÃ©e  dans le tableau de droite. 
+      <Break/>
+      SÃ©lectionner ensuite l'Ã©lÃ©ment mÃ©ta-donnÃ©e Ã  ajouter en cliquant sur sa rangÃ©e dans le tableau.
+      <Break/>
+      Taper la valeur dans le champ valeur. Ne pas utiliser pas le caractÃšre "|", dÃšs lors qu'il est utilisÃ© pour construire des hiÃ©rarchies. Cliquer enfin sur "Append" pour ajouter la nouvelle valeur comme mÃ©ta-donnÃ©e pour le fichier choisi. La valeur apparaÃ®t immÃ©diatement dans le tableau de MÃ©ta-donnÃ©es.
+      <Break/>
+      Vous pouvez aussi ajouter des mÃ©ta-donnÃ©es Ã  un dossier, ou Ã  plusieurs fichiers sÃ©lectionnÃ©s Ã  la fois. Elle est ajoutÃ©e Ã  tous les fichiers ou Ã  l'intÃ©rieur du dossier ou de la sÃ©lÃ©ction, et aux sous-dossiers. Garder Ã  l'esprit  que si des mÃ©ta-donnÃ©es sont ajoutÃ©es Ã  un dossier tous les nouveaux fichiers en son sein hÃ©rite automatiquement des valeurs du dossier.
+      <Break/>
+      Si on choisit une mÃ©ta-donnÃ©e qui intervient dans quelques uns des fichiers sÃ©lectionnÃ©s et que l'on clique sur "Coller", elle est aussi ajoutÃ©e aux autres fichiers de la sÃ©lection.
+      <Anchor name="advanced">Instructions advancÃ©es:</Anchor>
+      On peut ajouter une structure aux valeurs de mÃ©ta-donnÃ©es en utilisant les chemins comme dÃ©crit dans <Reference target="theenrichview">L'affichage Enrichir</Reference>.
+    </Section>
+    <Section name="addingpreviouslydefinedmetadata">
+      <Title>Ajouter des MÃ©ta-donnÃ©es prÃ©dÃ©finies</Title>
+      <ObviousSentence>Cette section explique la maniÃšre d'ajouter une mÃ©ta-donnÃ©e qui utilise des valeurs dÃ©jÃ  prÃ©sentes dans l'arborescence des valeurs.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Ajouter aux fichiers
+          </ContentsItem>
+          <ContentsItem>
+            Ajouter aux fichiers et aux fichiers multiples
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Pour ajouter une mÃ©ta-donnÃ©e ayant une valeur existante, sÃ©lectionner d'abord le fichier, et ensuite la valeur requise Ã  partir de l'arborescence des valeurs, en dÃ©veloppant si nÃ©cessaire les dossiers de hiÃ©rarchie. La valeur de l'entrÃ©e sÃ©lectionnÃ©e apparaÃ®t automatiquement dans le champ texte Valeur. (Utiliser alternativement la valeur auto-select de l'arborescence et les caractÃ©ristiques auto-complÃštes. Cliquer sur "Append" pour ajouter la metadata au fichier sÃ©lectionnÃ©. 
+      <Break/>
+      La procÃ©dure d'ajouter mÃ©ta-donnÃ©es avec des valeurs dÃ©jÃ  existantes aux dossiers ou aux fichiers multiples est tout Ã  fait identique.
+    </Section>
+    <Section name="updatingmetadata">
+      <Title>Mettre Ã  jour des MÃ©ta-donnÃ©es</Title>
+      <ObviousSentence>Cette section explique la maniÃšre de mettre Ã  jour la mÃ©ta-donnÃ©e assignÃ©e Ã  un fichier.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Mettre Ã  jour des fichiers
+          </ContentsItem>
+          <ContentsItem>
+            Mettre Ã  jour des dossiers et des fichiers multiples
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Pour mettre Ã  jour la valeur d'un Ã©lÃ©ment mÃ©ta-donnÃ©e, choisir d'abord le fichier auquel la valeur s'applique, et ensuite l'Ã©lÃ©ment mÃ©ta-donnÃ©e dont on veut changer la valeur. Votre sÃ©lection apparaÃ®t dans les contrÃŽles d'Ã©dition des mÃ©ta-donnÃ©es. Editer le champ valeur et cliquer sur "Remplacer" pour Ã©craser la mÃ©ta-donnÃ©e.
+      <Break/>
+      Le processus est identique pour la mise Ã  jour d'un dossier avec des sous-dossiers ou plusieurs fichiers, mais vous pouvez seulement mettre Ã  jour les mÃ©ta-donnÃ©es qui sont communes Ã  tous les fichiers/dossiers sÃ©lectionnÃ©s.
+      <Break/>
+      L'arborescence des valeurs montre toutes les valeurs prÃ©cÃ©dentes, mais pas seulement celles dÃ©signÃ©es actuellement. Ainsi la valeur que vous avez remplacÃ©e restera dans l'arbre de valeur.
+    </Section>
+    <Section name="removingmetadata">
+      <Title>Enlever les mÃ©ta-donnÃ©es</Title>
+      <ObviousSentence>Cette section explique comment retirer des mÃ©ta-donnÃ©es d'un fichier.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Enlever Ã  partir de fichiers
+          </ContentsItem>
+          <ContentsItem>
+            Enlever Ã  partir de dossiers ou de fichiers multiples
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      On enlever la mÃ©ta-donnÃ©e de la mÃªme faÃ§on que sa mise Ã  jour. SÃ©lectionner d'abord un fichier Ã  partir de l'arborescence des fichiers, utiliser ensuite le tableau de mÃ©ta-donnÃ©e pour sÃ©lectionner la mÃ©ta-donnÃ©e. Si la mÃ©ta-donnÃ©e a une valeur, le bouton "Enlever" devient actif. Cliquer-le pour enlever la mÃ©ta-donnÃ©e du fichier spÃ©cifiÃ©. D'autres fichiers demeurent inchangÃ©s et la valeur reste dans l'arborescence des valeurs. 
+      <Break/>
+      La suppression de mÃ©ta-donnÃ©es de rÃ©pertoires ou de plusieurs fichiers fonctione de la mÃªme faÃ§on.
+    </Section>
+    <Section name="reviewingmetadata">
+      <Title>Passer en revue les MÃ©ta-donnÃ©es assignÃ©es</Title>
+      <ObviousSentence>Cette section dÃ©crit la maniÃšre de visionner toutes les mÃ©ta-donnÃ©es assignÃ©es Ã  la colletion entiÃšre.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Le tableau d'audit
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Le menu bouton droit
+          </ContentsItem>
+          <ContentsItem>
+            Autofiltrage
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      On Ã©prouve parfois le besoin de voir, Ã  la fois, les mÃ©ta-donnÃ©es affectÃ©es Ã  plusieurs ou Ã  tous les fichiers -- par exemple, pour dÃ©terminer combien de fichiers sont en cours d'utilisation ou pour avoir une idÃ©e de la chronologie. 
+      <Break/>
+      SÃ©lectionnez les fichiers que vous souhaitez examiner, puis clicquez sur le bouton droit et choisissez "MÃ©ta-donnÃ©es AssociÃ©es...". Une fenÃªtre appelÃ©e "Toutes les MÃ©ta-donnÃ©es", sous forme d'un grand tableau avec plusieurs colonnes, apparaÃ®t. La premiÃšre colonne montre les noms de fichiers; les lignes montrent toutes les valeurs de mÃ©ta-donnÃ©es assignÃ©es Ã  ces fichiers.
+      <Break/>
+      Dessiner le tableau peut prendre quelque temps si plusieurs fichiers sont sÃ©lectionnÃ©s. On peut continuer Ã  utiliser l'Interface BibliothÃ©caire pendant que la fenÃªtre "Toutes MÃ©ta-donnÃ©es" est ouverte.
+      <Break/>
+      Cliquer "Fermer" pour cacher la fenÃªtre.
+      <Anchor name="advanced">Instructions advancÃ©es:</Anchor>
+      On peut aussi visualiser le tableau "Toutes MÃ©tadonnÃ©es" en sÃ©lectionnant les fichiers Ã  examiner en cliquant sur le bouton droit et en choisissant "MÃ©ta-donnÃ©es AssignÃ©es...". Si un dossier a Ã©tÃ© sÃ©lectionnÃ©, tous ses fichiers sont inclus dans le tableau.
+      <Break/>
+      Quand il devient trop large, on peut filtrer le tableau "Toutes MÃ©ta-donnÃ©es" en appliquant des filtres aux colonnes. Alors que de nouveaux filtres sont ajoutÃ©s, seules les lignes qui concernent restent visibles. Pour installer, modifier ou effacer un filtre, cliquez sur l'Ã®cone "Funnel" situÃ© en haut de la colonne. Une information sur le filtre est rÃ©clamÃ©e. Une fois le filtre installÃ©, l'en-tÃªte de la colonne change de couleur.
+      <Break/>
+      La confirmation possÃšde un onglet "simple" et " advancÃ©". La version simple filtre  les colonnes afin qu'elles ne montrent que des lignes qui contiennent une certaine valeur de mÃ©ta-donnÃ©e ("*" concerne toutes les valeurs). On peut sÃ©lectionner des valeurs de mÃ©ta-donnÃ©es Ã  partir d'une liste dÃ©roulante. La version advancÃ©e permet diffÃ©rentes opÃ©rations d'harmonisation: doit commencer avec, ne contient pas, alphabÃ©tiquement et est Ã©gal Ã . La valeur Ã  harmoniser peut Ãªtre Ã©ditÃ©e et prise sous forme d'une chaÃ®ne quelconque (y compris "*"), et on peut opter pour une harmonisation insensible aux caractÃšres. Enfin, on peut spÃ©cifier une deuxiÃšme condition d'harmonisation prÃ©cisant une gamme de valeurs (en sÃ©lectionnant AND) ou des valeurs alternatives (en selectionnant OR). En dessous de cette zone, une boÃ®te qui permet de changer l'ordre de tri (ascendant ou descendant) est placÃ©e. Enfin, cliquer sur "Installer Filtre" pour appliquer le nouveau filtre Ã  la colonne. Cliquer sur "Effacer Filtre" pour enlever le filtre courant. Notez que les dÃ©tails du filtre sont retenus mÃªme si le filtre est effacÃ©.
+      <Break/>
+      Par exemple, pour trier le tableau "Toutes MÃ©ta-donnÃ©es" , choisir une colonne, sÃ©lectionner le cadre du filtre par dÃ©faut (Un filtre simple sur "*") et choisir un ordre ascendant ou descendant.
+    </Section>
+    <Section name="importingpreviouslyassignedmetadata">
+      <Title>Importer des MÃ©ta-donnÃ©es PrÃ©-assignÃ©es</Title>
+      Cette section explique comment importer des mÃ©ta-donnÃ©es affectÃ©es prÃ©cÃ©demment; mÃ©ta-donnÃ©es affectÃ©es avant d'Ãªtre ajoutÃ©es Ã  la collection.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    En ajoutant des fichiers
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Si la mÃ©ta-donnÃ©e dans une forme reconnue par l'Interface BibliothÃ©caire a Ã©tÃ© prÃ©alablement assignÃ©e Ã  un fichier, -- par exemple, quand on choisit des documents dans une collection Greenstone existante -- elle est importÃ©e automatiquement quand on ajoute le fichier. Pour ce faire, la mÃ©ta-donnÃ©e doit Ãªtre ajustÃ©e au jeu de mÃ©ta-donnÃ©es disponibles dans la collection.
+      <Break/>
+      L'Interface BibliothÃ©caire confirme l'information nÃ©cessaire. confirmation sous forme d'instructions brÃšves et qui montre ensuite le nom de l'Ã©lÃ©ment mÃ©ta-donnÃ©e qui est importÃ©e, comme il apparaÃ®t dans le fichier source. Ce champ ne peut Ãªtre ni Ã©ditÃ© ni changÃ©. Ensuite on choisit sur quel jeu de mÃ©ta-donnÃ©e le nouveau Ã©lÃ©ment devrait Ãªtre calquÃ© et enfin l'Ã©lÃ©ment mÃ©ta-donnÃ©e appropriÃ©. Le sytÃšme selectionne automatiquement le meilleur ajustement, en terme de jeu et d'Ã©lÃ©ment pour la nouvelle mÃ©ta-donnÃ©e.
+      <Break/>
+      AprÃšs cela,on peut choisir "Ajouter" pour ajouter le nouvel Ã©lÃ©ment mÃ©ta-donnÃ©e au jeu de mÃ©ta-donnÃ©es choisi. (Ceci n'est possible que si aucun Ã©lement de mÃªme nom n'est prÃ©sent Ã  l'interieur du jeu choisi.) "Remplacer" applique le nouvel Ã©lement Ã  celui choisi par l'utilisateur. Enfin, "Ignorer" n'importe aucune mÃ©ta-donnÃ©e avec ce nom d'Ã©lement. Une fois prÃ©cisÃ©e la maniÃšre d'importer un certain Ã©lÃ©ment de mÃ©ta-donnÃ©e, l'information d'application est retenue pour la durÃ©e de vie de la collection.
+      <Break/>
+      Pour des dÃ©tails concenant les fichiers mÃ©ta-donnÃ©e.xml que Greenstone utilise pour sauvegarder les mÃ©ta-donnÃ©es, il faut vous refÃ©rer au chapitre 2 du guide du DÃ©veloppeur de Greenstone -- "Exploitez vos documents au maximum".
+    </Section>
+  </Section>
+
+  <Section name="designingacollection">
+    <Title>DÃ©coration de l'apparence de votre collection</Title>
+Une fois les fichiers marquÃ©s avec les mÃ©ta-donnÃ©es, on peut dÃ©cider comment ils devraient apparaÃ®tre aux utilisateurs comme une collection Greenstone. Quel type d'information peut Ãªtre recherchÃ©? Quels sont les moyens qui sont fournis pour naviguer Ã  travers les documents? Quels sont les langages supportÃ©s? oÃ¹ apparaissent les boutons sur la page? ces choses peuvent Ãªtre adaptÃ©es; cette section dÃ©crit comment procÃ©der.
+    <Section name="thedesignview">
+      <Title>L'Affichage conception</Title>
+      Cette section prÃ©sente l'affichage de conception et explique comment on navigue entre les diffÃ©rents affichages Ã  l'intÃ©rieur de cette vitrine. 
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Choisir une section de conception
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Avec l'Interface BibliothÃ©caire, on peut configurer la faÃ§on dont la collection va apparaÃ®tre Ã  l'utilisateur. Les options de configuration sont divisÃ©es en diffÃ©rentes sections, chacune associÃ©e Ã  une Ã©tape particuliÃšre de navigation ou de prÃ©sentation d'information.
+      <Break/>
+      Sur la gauche est placÃ©e une liste de diffÃ©rents affichages et Ã  droite les commandes associÃ©es Ã  celles en cours. Pour passer Ã  un  affichage diffÃ©rent, cliquer son nom dans la liste.
+      <Break/>
+      Pour comprendre les diffÃ©rentes Ã©tapes et les termes implmiquÃ©s dans la conception d'une collection, lire les chapitres 1 et 2 de Greenstone's Developer's Guide. 
+    </Section>
+    <Section name="generalsettings">
+      <Title>RÃ©glages gÃ©nÃ©raux</Title>
+      Cette section explique comment passer en revue et changer les rÃ©glages gÃ©neraux associÃ©s Ã  la collection. D'abord, sous "Design section" cliquer "General".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            RÃ©glages gÃ©nÃ©raux
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Les valeurs fournies ici peuvent Ãªtre modifiÃ©es au cours de la crÃ©ation de la collection.
+      <Break/>
+      En haut de la page, se trouve une boÃ®te Ã  instruction, qui apparaÃ®t pour chacune des diffÃ©rentes sections. Elle contient une brÃšve liste d'instructions pour vous rappeler quelle fonctionalitÃ© est disponible:
+      <Break/>
+      D'abord, les contacts E-mail du crÃ©ateur et mainteneur de la collection. Le champ suivant permet le changement de titre de la collection. Le dossier dans lequel est enregistrÃ© la collection est affichÃ© ensuite, mais ne peut Ãªtre Ã©ditÃ©. Celui qui suit spÃ©cifie (sous forme d'URL) l'Ã®cone Ã  montrer Ã  l'extrÃ©mitÃ© supÃ©rieure gauche de la page "About" de la collection et la suivante est l'Ã®cone utilisÃ©e dans la page de la bibliothÃ©que Greenstone Ã  lier Ã  la collection. Puis, une case permet de contrÃŽler si la collection est accessible au public. Enfin, la zone texte de "la description de la Collection" comme dÃ©crit <Reference target="creatingacollection">CrÃ©er une nouvelle collection</Reference>.
+    </Section>
+    <Section name="plugins">
+      <Title>Plugiciels de Document</Title>
+      Cette section dÃ©crit comment faire la configuration des plugiciels des documents que la collection utilise. Elle explique comment spÃ©cifier les plugiciels utilisÃ©s, quels paramÃštres leur passer et dans quel ordre ils se dÃ©roulent. Sous "Sections de conception", cliquer "Plugiciels de document".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Ajouter un plugiciel
+          </ContentsItem>
+          <ContentsItem>
+            Enlever un plugiciel
+          </ContentsItem>
+          <ContentsItem>
+            Configurer un plugiciel
+          </ContentsItem>
+          <ContentsItem>
+            Changer l'ordre des plugiciels
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Configuration d'usage
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Pour ajouter un plugiciel, sÃ©lectionner-le sur la liste dÃ©roulante de "Choisir le plugiciel Ã  ajouter" situÃ©e Ã  cÃŽtÃ© du bouton et ensuite cliquer "Ajouter plugiciel". Une fenÃªtre dÃ©nommÃ©e "Configurer les arguments" apparaÃ®t; elle est dÃ©crite plus loin. Une fois la configuration du nouveau plugiciel achevÃ©e, il est ajoutÃ© Ã  la fin de la liste "Plugiciels couramment assignÃ©s". Veuillez noter que, Ã  l'exception de UnknownPlug, chaque plugin ne peut apparaÃ®tre qu'une seule fois dans la liste.
+      <Break/>
+      Pour enlever un plugiciel, sÃ©lectionner-le sur la liste et cliquer sur "Enlever plugiciel".
+      <Break/>
+      Les plugiciels sont configurÃ©s en fournissant des arguments. Pour les changer, il faut sÃ©lectionner le plugiciel Ã  partir de la liste et cliquer "Configurer plugiciel" (Ou double-cliquer sur le plugiciel). Un dialogue "Configuration des arguments" apparaÃ®t avec diffÃ©rent contÃŽles pour spÃ©cifier les arguments.
+      <Break/>
+      Il existe plusieurs types de contrÃŽles. Certains sont des boÃ®tes de dialogue et cliquer sur l'une ajoute l'option appropriÃ©e au plugiciel. Les autres sont des chaÃ®nes de textes avec une boÃ®te de dialogue et un champ texte. Cliquer sur la boÃ®te pour activer l'argument, ensuite saisir le texte appropriÃ© dans la boÃ®te (expression normale, chemin de fichier etc). Les autres sont des menus dÃ©roulants Ã  partir desquels on peut sÃ©lectionner Ã  partir d'une sÃ©rie de valeurs dÃ©terminÃ©es. Pour apprendre ce qu'un argument peut faire, promener la souris planer sur son nom pendant un instant une description apparaÃ®tra.
+      <Break/>
+      Pour changer la configuration, cliquer sur "OK" pour valider et fermer la boÃ®te de dialogue, ou "Annuler" pour fermer la boÃ®te de dialogue sans changer les arguments du plugiciel.
+      <Break/>
+      Les plugiciels dans la liste sont executÃ©s en ordre et l'ordre est parfois important. Les deux plugiciels Qrcplug et Recplug sont vitaux au processus de construction de la collection, et sont placÃ©s Ã  la fin de la liste (avec une ligne de sÃ©paration). Pour changer l'ordre des autres, sÃ©lectionner le plugiciel Ã  dÃ©placer et cliquer sur "DÃ©placer vers le haut" ou "DÃ©placer vers le bas".
+       <Anchor name="advanced">Instructions advancÃ©es:</Anchor>
+       L'Interface BibliothÃ©caire s'Ã©vertue Ã  dÃ©terminer les arguments supportÃ©s par le plugiciel. Cependant, l'utilisateur peut avoir Ã  indiquer d'autres arguments spÃ©ciaux; pour cela un champ texte appelÃ© "Arguments SpÃ©cifiques" (en bas) est disponible. Tout texte qu'il contient est annexÃ© Ã  la fin de la commande Plugiciel.
+    </Section>
+    <Section name="searchtypes">
+      <Title>Types de recherche</Title>
+      cette section explique comment modifier une nouvelle caractÃ©ristique de conception dans Greenstone, Types de recherche, qui permet une recherche de champ. Sous "Sections de conception", cliquer sur "Types de recherche".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Que signifie activer des recheches avancÃ©es?
+          </ContentsItem>
+          <ContentsItem>
+            Ajouter un nouveau type de recherche
+          </ContentsItem>
+          <ContentsItem>
+	    Enlever un type de recherche
+          </ContentsItem>
+          <ContentsItem>
+            Changer l'ordre des types de recherche
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Lorsqu'on pÃ©nÃštre dans l'affichage Types de recherche, vÃ©rifier d'abord "Activer recherches avancÃ©es", qui active les autres contrÃŽles. la collection prend le format 2.4 de Greenstone, qui supporte la recherche basÃ©e sur les champs, et signifie que: 1. l'index de conception est diffÃ©rent (expliquÃ© dans <Reference target="searchindexes">Recherche d'index</Reference> section), 2. plusieurs fragments de textes sont Ã  traduire (voir <Reference target="translatetext">Translation</Reference>), 3. la collection est inutilisable sous des versions plus vieilles de Greenstone. Si vous dÃ©-sÃ©lectionner ce champ, la plupart de la collection retourne Ã  la version 2.39 de Greenstone 2.39. Cependant, l'Interface BibliothÃ©caire ne peut pas convertir les nouvelles spÃ©cifications d'index en celles plus anciennes; elles doivent ainsi Ãªtre saisies de nouveau manuellement. 
+      <Break/>
+      pour ajouter un type de recherche, sÃ©lectionner-le Ã  partir de la liste "Types de recherche" et cliquer sur "Ajouter Type de recherche".  Chaque type n'apparaÃ®t qu'une fois sur la liste.
+      <Break/>
+      Pour enlever un type de recherche, il faut le selectionner Ã  partir de la liste "Currently Assigned Search type" et cliquer sur "Enlever type de recheche". La liste doit contenir au moins un type de recherche.
+      <Break/>
+      pour changer l'ordre d'un type de recherche, sÃ©lectionner-le Ã  partir de la liste et cliquer sur "DÃ©placer vers le haut" ou "DÃ©placer vers le bas". Le premier sera le dÃ©faut.
+    </Section>
+    <Section name="searchindexes">
+      <Title>Index de recherche</Title>
+      Les index prÃ©cisent les parties de la collection qui doivent Ãªtre recherchÃ©es. Cette section explique comment ajouter et enlever des index et fixer un index par dÃ©faut. Sous "Sections de conception", cliquer sur "Rechercher Index".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    Ajouter un index
+          </ContentsItem>
+	  <ContentsItem>
+	    Ãditer un index
+	  </ContentsItem>
+          <ContentsItem>
+            Enlever un index
+          </ContentsItem>
+          <ContentsItem>
+            Index par dÃ©faut
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Pour ajouter un index, taper un nom choisi dans le champ "Nom de l'Index". Selectionner les sources d'information Ã  indexer en cliquant les boÃ®tes de dialogue Ã  cÃŽtÃ© d'eux. La liste montre aussi bien tous les Ã©lÃ©ments de mÃ©ta-donnÃ©es assignÃ©s, que le texte entier. AprÃšs avoir sÃ©lectionnÃ© les sources de donnÃ©es, choisir la granularitÃ© de l'index en utilisant le menu "Au niveau". Une fois ces dÃ©tails completÃ©s, "Ajouter Index" devient actif  (Ã  moins qu'il n'ait un index existant avec les mÃªmes paramÃštres). Cliquez pour ajouter un nouvel index.
+      <Break/>
+      Pour Ã©diter un index, sÃ©lectionnez-le et changez les dÃ©tails de l'index, puis clicquez sur "Remplacer l'index".
+      <Break/>
+      Pour enlever un index, il faut le sÃ©lectionner sur la liste d'index assignÃ©s et cliquer "Enlever index". 
+      <Break/>
+      L'index par dÃ©faut, celui qui est utilisÃ© dans la page de recherche de la collection est labellÃ© parc "[Index par dÃ©faut]" dans la liste "Index assignÃ©s".
+      <Break/>
+      Si la recherche avancÃ©e est activÃ©e (voir Affichage des types de recherche), les contrÃŽles d'index sont diffÃ©rents.Chaque index est seulement basÃ© sur une source de donnÃ©es. Il existe une nouvelle pseudo-source de donnÃ©es "Tous champs" qui fournit une recherche Ã  travers tous les index spÃ©cifiÃ©s Ã  la fois. Des niveaux ne sont pas assignÃ©s Ã  un index spÃ©cifique, mais s'applique Ã  tous les index : ainsi index et niveaux sont ajoutÃ©s sÃ©parement. Les index sont enlevÃ©s de la mÃªme faÃ§on que prÃ©cÃ©demment, mais l'index par dÃ©faut ne peut plus Ãªtre mis activÃ©.. il est simplement le premier index assignÃ©. 
+      <Break/>
+      Pour crÃ©er des index sur toutes les sources cliquez le bouton "Ajouter Tous". Le nom de chaque index sera en dÃ©faut pour le nom de source. Pour changer le nom, SÃ©lectionner un index, changer ses dÃ©tails et cliquez "Remplacer Index". 
+    </Section>
+    <Section name="partitionindexes">
+      <Title>Index de Partition</Title>
+      Les index sont construits sur un texte particulier ou des sources MÃ©ta-donnÃ©es. L'espace de recherche peut Ãªtre plus tard contrÃŽlÃ© en morcelant l'index soit par langage ou par filtre choisi Ã  l'avance. Cette section en dÃ©crit la procÃ©dure. Sous "Sections de conception", cliquer "Index de Partition". 
+      <Break/>
+      L'affichage "Index de Partition" possÃšde trois onglets: "DÃ©finir les Filtres", "Assigner une partition" et "Assigner des langages". Pour en savoir davantage sur les partitions, lire sur les sous collections et les sous index au chapitre 2 de Greenstone developer's guide.
+      <Section name="definefilters">
+        <Title>DÃ©finir les Filtres</Title>
+	<ObviousSentence>Cette section explique comment dÃ©finir un filtre de partition.</ObviousSentence>
+        <Contents>
+          <ContentsGroup linkto="simple">
+            <ContentsItem>
+             Ajouter un filtre
+            </ContentsItem>
+            <ContentsItem>
+              Enlever un filtre
+            </ContentsItem>
+            <ContentsItem>
+              Mettre Ã  jour un filtre
+            </ContentsItem>
+          </ContentsGroup>
+        </Contents>
+        <Anchor name="simple">Instructions simples:</Anchor>
+	Les filtres permettent de jeur en sous-collection tous les documents dans un index pour laquelle une valeur mÃ©ta-donnÃ©e correspond Ã  un type donnÃ©.
+	<Break/>
+	Pour crÃ©er un filtre, cliquer sur le bouton "DÃ©finir les Filtres" et entrer un nom pour le nouveau filtre dans le champ "Nom du filtre de la sous-collection". Ensuite choisir un attribut de document Ã  faire correspondre  soit avec l'Ã©lÃ©ment de mÃ©ta-donnÃ©e soit avec le nom du fichier en question. Saisir une expression courante qu'il faut utiliser durant la correspondance. Vous pouvez choisir entre "Inclure" les documents qui correspondent au fichier ou les "Exclure". Enfin, on peut spÃ©cifier l'un quelconque des drapeaux standard PERL d'expression courante qu'il faut utiliser pour la correspondance (par exemple "i" pour les correspondances ne tenant pas compte des caractÃšres.) Pour finir, cliquez sur "Ajouter un Filtre" pour ajouter le filtre Ã  la liste "Filtres de sous collection dÃ©finis". 
+	<Break/>
+	Pour enlever un filtre, sÃ©lectionner-le sur la liste et cliquer sur "Enlever Filtre".
+	<Break/>
+	Pour changer un filtre, sÃ©lectionner-le sur la liste, changer l'une quelconque des valeurs apparaissant dans les contrÃŽles d'Ã©dition et cliquer sur "Remplacer Filtre" pour valider les modifications.
+      </Section>
+      <Section name="assignpartitions">
+        <Title>Assigner des Partitions</Title>
+	<ObviousSentence>Cette section explique l'assignation d'un filtre de partition prÃ©dÃ©fini.</ObviousSentence>
+        <Contents>
+          <ContentsGroup linkto="simple">
+            <ContentsItem>
+              Ajouter une partition
+            </ContentsItem>
+            <ContentsItem>
+              Enlever une partition
+            </ContentsItem>
+            <ContentsItem>
+              Partition par dÃ©faut
+            </ContentsItem>
+            <ContentsItem>
+             Enlever partition par dÃ©faut
+            </ContentsItem>
+          </ContentsGroup>
+        </Contents>
+        <Anchor name="simple">Instructions simples:</Anchor>
+	AprÃšs avoir dÃ©fini un filtre de sous-collection, utiliser l'onglet "Assigner des Partitions" pour construire ses indexes  (ou ceux pour un jeu de filtres.) SÃ©lectionner le filtre (ou les filtres) de votre choix Ã  partir de la liste "DÃ©finir des Filtres de Sous-collection", entrer un nom pour la partition dans le champ "Nom de Partition Name", et cliquer sur "Ajouter Partition". 
+	<Break/>
+	Pour supprimer une partition, sÃ©lectionner-la Ã  partir de la liste et cliquer sur "Enlever Partition".
+	<Break/>
+	Pour faire d'une partition celle par dÃ©faut, sÃ©lectionner-la Ã  partir de la liste et cliquer sur "Par DÃ©faut".
+	<Break/>
+	Pour effacer la partition par dÃ©faut, cliquez sur "Effacer dÃ©faut".
+      </Section>
+      <Section name="assignlanguages">
+        <Title>Assigner Langages</Title>
+	Cette section donne les dÃ©tails de la maniÃšre de restreindre les index Ã  des langages particuliers. On le fait en gÃ©nÃ©rant une partition par le biais de l'onglet "Assigner Langages" de l'Affichage "Index de Partition".
+        <Contents>
+          <ContentsGroup linkto="simple">
+            <ContentsItem>
+              ContrÃŽles de Langage 
+            </ContentsItem>
+            <ContentsItem>
+              Ajouter langage
+            </ContentsItem>
+            <ContentsItem>
+              Enlever langage
+            </ContentsItem>
+            <ContentsItem>
+              Langage par dÃ©faut
+            </ContentsItem>
+            <ContentsItem>
+              Enlever Langage par dÃ©faut
+            </ContentsItem>
+          </ContentsGroup>
+        </Contents>
+        <Anchor name="simple">Instructions simples:</Anchor>
+	Pour ajouter un nouveau langage, dont la partition par le biais de l'onglet "Assigner langues" confÃšre un index, SÃ©lectionner le langage souhaitÃ© Ã  partir de la liste "Langage Ã  ajouter" et cliquer sur "Ajouter langue".
+	<Break/>
+	Pour supprimer une langue, sÃ©lectionner-la Ã  partir de la liste "SÃ©lection de Langage" et cliquer sur "Enlever Langage". 
+	<Break/>
+	Pour installer un language par dÃ©faut, sÃ©lectionner-la dans la liste et cliquez sur "Par dÃ©faut".
+	<Break/>
+	Pour enlever le langage par dÃ©faut, cliquer sur "Enlever par DÃ©faut".
+      </Section>
+    </Section>
+    <Section name="xcollectionsearching">
+      <Title>Recherche unique Ã  travers plusieurs collections</Title>
+      Greenstone peut rechercher dans plusieurs collections comme si elles n'en constituaient qu'une. Cela se fait par la crÃ©ation d'une "super-collection" qui contient les collections individuelles. Sous "Sections de conception", cliquez sur "Recherche unique Ã  travers plusieurs collections".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            SÃ©lectionner une collection
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      L'Affichage de Recherche unique Ã  travers des collections montre une liste de collections disponibles. La collection courante est cochÃ©e et ne peut Ãªtre dÃ©-sÃ©lectionnÃ©e. Pour ajouter une autre collection qu'on peut rechercher parallÃšlement, cliquer sur une collection dans la liste (cliquer une deuxiÃšme fois pour l'enlever). Lorsqu'une seule collection est sÃ©lectionnÃ©e, aucune recherche Ã  travers collections n'est possible.
+      <Break/>
+      Pour plus de dÃ©tails, voir Chapitre 1 du Guide du DÃ©veloppeur Greenstone.
+    </Section>
+    <Section name="classifiers">
+      <Title>Classificateurs</Title>
+      Cette section explique comment assigner Ã  une collection des "classificateurs" qui sont utilisÃ©s pour naviguer. Sous la section "Sections de conception", cliquer sur "Classificateurs de navigation".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Configuration et sÃ©lection d'un classificateur
+          </ContentsItem>
+          <ContentsItem>
+            Ajouter un classificateur
+          </ContentsItem>
+          <ContentsItem>
+            Enlever un classificateur
+          </ContentsItem>
+          <ContentsItem>
+            Configurer un classificateur
+          </ContentsItem>
+          <ContentsItem>
+            Changer l'ordre d'un classificateur
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Pour ajouter un classificateur, sÃ©lectionner-le en utilisant la liste dÃ©roulante "Choisir classificateur Ã  ajouter" et cliquer sur "Ajouter Classificateur SpÃ©cifique". une fenÃªtre qui s'intitule "Configurer Arguments" apparaÃ®t ; les instructions concernant ce dialogue sont les mÃªmes que pour les plugiciels (voir <Reference target="plugins">plugiciels de Documents</Reference>). Une fois le nouveau classificateur configurÃ©, il s'ajoute Ã  la fin de la liste des "Classificateurs couramment AssignÃ©s". 
+      <Break/>
+      Pour supprimer un classificateur, sÃ©lectionner-le dans la liste et cliquez sur "Enlever Classificateur Choisi".
+      <Break/>
+      Pour changer les arguments d'un classificateur, sÃ©lectionner-le sur la liste et cliquer sur "Configurer Classificateur Choisi" (ou double-cliquer sur le classificateur sur la liste.) 
+      <Break/>
+      Le tri des classificateurs dans la barre de navigation de la collection est fourni ici dans l'ordre des classificateurs. Pour le changer, sÃ©lectionner le classificateur Ã  dÃ©placer et cliquer sur "DÃ©placer vers le haut" ou "DÃ©placer vers le bas".
+      <Break/>
+      Pour plus d'informations sur les classificateurs lisez le chapitre 2 du Guide du DÃ©veloppeur Greenstone -- Exploitez vos documents au maximum.
+    </Section>
+    <Section name="formatstatements">
+      <Title>CaractÃ©ristiques de Format</Title>
+Les Format Features et les commandes de format contrÃŽlent la structure et l'apparence de la collection. Ils influencent le lieu d'apparition des boutons lorsqu'un document est affichÃ©, et dÃ©terminent les liens qui sont affichÃ©s par le classificateur DateList. Les commandes de format ne sont pas faciles Ã  concevoir, et la lecture du chapitre 2 de Greenstone Developer's Guide est recommandÃ©e. Cette section concerne les cadres de format, et  indique comment l'Interface BibliothÃ©caire en fournit l'accÃšs. Sous "Sections de conception", cliquer sur "CaractÃ©ristiques de Format".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Formatage
+          </ContentsItem>
+          <ContentsItem>
+            Ajouter commande de format
+          </ContentsItem>
+          <ContentsItem>
+             Enlever commande de format
+          </ContentsItem>
+          <ContentsItem>
+            Mettre Ã  jour commande de format
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            Options de formatage Ã©tendues
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      On peut appliquer une commande de format Ã  n'importe quoi dans la liste dÃ©roulante "Choisir CaractÃ©ristique" qui comprend tous les classificateurs de mÃªme qu'une liste prÃ©dÃ©finie de caractÃ©ristiques. Deux types de contrÃŽles existent lorsqu'on sÃ©lectionne une caractÃ©ristique: Certaines caractÃ©ristiques sont simplement activÃ©es ou dÃ©sactivÃ©es, et le contrÃŽle se fait grÃ¢ce Ã  une liste de vÃ©rification. D'autres requiÃšrent qu'on spÃ©cifie une chaÃ®ne de format. Pour ces caractÃ©ristiques, il existe une liste de retrait ("Composante AffectÃ©e") pour la sÃ©lection des parties de la caraxtÃ©ristique oÃ¹ s'applique la chaÃ®ne (si nÃ©cessaire), une zone de texte ("ChaÃ®ne de Format HTML") oÃ¹ on saisit la chaÃ®ne, et une sÃ©lection de "Variables" prÃ©dÃ©finies. Pour insÃ©rer une variable dans la position courante dans la chaÃ®ne de format, sÃ©lectionner la Ã  partir de la liste de retrait et cliquer sur "InsÃ©rer". 
+      <Break/>
+      Vous pouvez spÃ©cifier un format par dÃ©faut pour une composante particuliÃšre en sÃ©lectionnant la caractÃ©ristique vierge.Ce format est alors appliquÃ© Ã  toutes les caractÃ©ristiques applicables sauf instruction contraire. 
+      <Break/>
+      Pour ajouter une nouvelle commande de format, remplir l'information comme indiquÃ©e plus haut et cliquer sur "Ajouter Format". La nouvelle commande de Format apparaÃ®t dans la liste des  "Commandes de Format frÃ©quemment AssignÃ©es". Seule une commande de format peut Ãªtre assignÃ©e pour chaque combinaison caractÃ©ristique/composante.
+      <Break/>
+      Pour enlever une commande de format, sÃ©lectionner-la sur la liste et cliquer "Enlever Format".
+      <Break/>
+      Pour modifier une commande de format, sÃ©lectionner-la  sur la liste et cliquer sur "Remplacer Format". 
+      <Break/>
+      Pour de plus amples informations sur les variables et les composantes de caractÃ©ristiques, lire le chapitre 2 du Guide du DÃ©veloppeur de Greenstone. 
+      <Anchor name="advanced">Instructions advancÃ©es:</Anchor>
+      Si la boÃ®te de vÃ©rification "Permettre options Ã©tendues" est cochÃ©e, certaines options avancÃ©es de formatage sont activÃ©es. La liste des caractÃ©ristiques pouvant Ãªtre formatÃ©es est lÃ©gÃšrement changÃ©e, et plusieurs variables sont disponibles dans la commande de format, offrant un contrÃŽle plus grand sur la mise en forme. 
+    </Section>
+    <Section name="translatetext">
+      <Title>Traduire Texte</Title>
+      Cette section dÃ©crit l'Affichage de traduction, oÃ¹ on peut dÃ©finir des fragments de texte spÃ©cifiques Ã  un langage pour des parties de l'interface de la collection. Sous "Sections de conception", cliquer sur "Traduire Texte".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Ajouter traduction
+          </ContentsItem>
+          <ContentsItem>
+            Enlever traduction
+          </ContentsItem>
+          <ContentsItem>
+            Mettre Ã  jour traduction
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Choisir d'abord une entrÃ©e dans la liste "CaractÃ©ristiques". Les chaÃ®nes spÃ©cifiques Ã  un langage associÃ©es Ã  la caractÃ©ristiques apparaissent en bas. Utiliser la liste dÃ©roulante de "Traduction de Langage" pour sÃ©lectionner le langage cible, et saisir le texte traduit dans la zone de texte, en se refÃ©rant Ã  "Fragment de Texte Initial" si nÃ©cessaire. Cliquez sur "Ajouter Traduction" Ã  la fin de l'opÃ©ration. 
+      <Break/>
+      Pour supprimer une traduction existante, sÃ©lectionner-la Ã  partir du tableau "Traduction AssignÃ©e" et cliquer sur "Enlever Traduction". 
+      <Break/>
+      Pour Ã©diter une traduction, sÃ©lectionner-la et Ã©diter-la dans la zone de texte "Texte Traduit", et cliquer sur "Remplacer Traduction". 
+    </Section>
+    <Section name="metadatasets">
+      <Title>jeux de MÃ©ta-donnÃ©es</Title>
+      Cette section explique le panel de visualisation du jeu de mÃ©ta-donnÃ©es. Sous "Sections de conception", cliquer sur "jeux de MÃ©ta-donnÃ©es". 
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            jeux de mÃ©ta-donnÃ©es disponibles
+          </ContentsItem>
+          <ContentsItem>
+            Ajout de jeux mÃ©ta-donnÃ©es
+          </ContentsItem>
+          <ContentsItem>
+            Ãdition de jeux mÃ©ta-donnÃ©es
+          </ContentsItem>
+          <ContentsItem>
+            Suppression de jeux mÃ©ta-donnÃ©es
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Cette fenÃªtre sert Ã  la revue des jeux de mÃ©ta-donnÃ©es utilisÃ©s dans la collection, et les Ã©lÃ©ments qui sont disponibles dans chaque jeu. Choisir dans la liste de "jeux de mÃ©ta-donnÃ©es disponibles" pour voir des informations dÃ©taillÃ©es Ã  ces Ã©lÃ©ments.
+      <Break/>
+      Pour utiliser un autre jeu de mÃ©ta-donnÃ©es avec la collection chargÃ©e, clicquez sur "Ajouter un jeu de mÃ©ta-donnÃ©es" et sÃ©lectionnez le fichier mÃ©ta-donnÃ©es (.mds) pour le nouveau jeu mÃ©ta-donnÃ©es.
+      <Break/>
+      L'Ã©dition de jeux mÃ©ta-donnÃ©es se fait avec l'Ã©diteur Greenstone de mÃ©ta-donnÃ©es (GEMS). En clicquant sur le bouton "Ãditer un jeux mÃ©ta-donnÃ©es" vous obtiendrez des informations sur l'utilisation de GEMS.
+      <Break/>
+      Si vous n'avez plus besoin d'un jeu mÃ©ta-donnÃ©es, sÃ©lectionnez le et clickez sur "Suppression du jeu mÃ©ta-donnÃ©es" pour l'enlever. Si vous avez affecttÃ© des mÃ©ta-donnÃ©es aux Ã©lÃ©ments du jeu supprimÃ©, on vous demandera ce que vous voulez en faire lorsque vous allez ouvrir Ã  nouveau cette collection.
+    </Section>
+  </Section>
+  <Section name="producingthecollection">
+    <Title>Pour produire votre collection</Title>
+    AprÃšs avoir rassemblÃ© les documents de la collection, les avoir annotÃ©s avec les mÃ©ta-donnÃ©es, et dÃ©fini comment la collection va apparaÃ®tre, la production de la collection en utilisant Greenstone est alors possible. Cette section vous en explique la maniÃšre.
+    <Section name="thecreateview">
+      <Title>L'Affichage CrÃ©er</Title>
+      <ObviousSentence>Cette section explique l'utilisation de l'affichage crÃ©er pour produire une collection.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    Construction de la collection
+	  </ContentsItem>
+	  <ContentsItem>
+	    AperÃ§u de la collection
+	  </ContentsItem>
+	</ContentsGroup>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    Journal des messages
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      L'Affichage CrÃ©er est utilisÃ© pour crÃ©er la collection en mettant en Åuvre les scripts Greenstone relatifs Ã  cette opÃ©ration. En cliquant sur "Construire Collection", on initie le processus de construction de la collection. Sa durÃ©e dÃ©pend de la taille de la collection  et du nombre d'index Ã  crÃ©er (pour les grandes collections cela peut prendre des heures). Une barre d'Ã©tat indique ou on en est dans le processus. Pour annuler le processus Ã  tout moment, cliquer sur "Annuler Construction".
+      <Break/>
+      Quand la collection est construite, appuyant "Preview Collection" initiera la page web hebergeant la collection.
+      <Anchor name="advanced">Instructions advancÃ©es:</Anchor>
+      En mode expert, vous pouvez utiliser l'entrÃ©e "Message Log" Ã  gauche pour revoir les tentatives prÃ©cÃ©dentes de construction de la collection avec ou san succÃ©s. SÃ©lectionnez le journal souhaitÃ© en cliquant sur la date correspondante dans la liste "Historique du Journal".
+    </Section>
+    <Section name="buildsettings">
+      <Title>ParamÃštres d'Importation et de Construction</Title>
+      Cette section explique comment accÃ©der aux diffÃ©rents paramÃštres de construction et d'importation. Pour plus d'informations sur l'importation et la construction lire le chapitre 1 du Guide du DÃ©veloppeur de Greenstone -- Comprendre le processus de construction de la collection.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            ParamÃštres GÃ©nÃ©raux
+          </ContentsItem>
+          <ContentsItem>
+            ParamÃštres d'importation
+          </ContentsItem>
+          <ContentsItem>
+            ParamÃštres de construction
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Le contrÃŽle des diffÃ©rents paramÃštres se fait de faÃ§on identique Ã  la fenÃªtre "Configurer Arguments" dÃ©crit dans la section <Reference target="plugins">Plugiciels de documents</Reference>. Certains champs requiÃšrent des arguments numÃ©riques, et on peut: soit les incorporer en les saisissant, soit utiliser les flÃšches Haut et Bas pour augmenter ou diminuer la valeur prÃ©sente (dans certains cas, l'interface limite la classe qu'on peut entrer.) D'autres sont activÃ©s en cliquant sur une case de vÃ©rification (re-cliquer pour dÃ©sactiver.)
+    </Section>
+  </Section>
+
+  <Section name="miscellaneous">
+    <Title>Miscellaneous</Title>
+    Cette section dÃ©crit les caractÃ©ristiques de l'Interface BibliothÃ©caire qui ne sont pas associÃ©es Ã  une fenÃªtre d'affichage particuliÃšre.
+    <Section name="preferences">
+      <Title>PrÃ©fÃ©rences</Title>
+      Cette section explique le dialogue des prÃ©fÃ©rences, auquel on accÃšde en ouvrant "Fichier" -> "PrÃ©fÃ©rences". 
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>GÃ©nÃ©ral</ContentsItem>
+	  <ContentsItem>Mode</ContentsItem>
+          <ContentsItem>Flux de travail</ContentsItem>
+          <ContentsItem>Connexion</ContentsItem>
+          <ContentsItem>Avertissement</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      La premiÃšre option "General" est un champ texte pour saisir votre adresse courriel. Ceci sera utilisÃ© pour les Ã©lÃ©ments mÃ©ta-donnÃ©es "crÃ©ateur" et "Mainteneur" de la collection. L'option suivante est un liste dÃ©roulante des langues dans lesquelles l'interface bibiothÃšquaire peut Ãªtre affichÃ©e. Si on change le dictionnaire par le choix d'un autre sur la liste, on doit redÃ©marrer l'Interface BibliothÃ©caire pour charger les chaÃ®nes du nouveau langage Ã  partir du dictionnaire.
+      <Break/>
+Si on coche "Affichage MÃ©ta-donnÃ©es Ã©tendues", les diffÃ©rents contrÃŽles relatifs aux mÃ©ta-donnÃ©es affichent toujours toutes les mÃ©ta-donnÃ©es qui ont Ã©tÃ© extraites automatiquement des documents. Lorsqu'on le dÃ©sÃ©lectionne, ces mÃ©ta-donnÃ©es sont cachÃ©es (bien qu'elles restent disponibles pendant la conception de la collection, et dans la collection Greenstone finale.) Si on coche "Montrer les tailles des fichiers", la taille du fichier apparaÃ®t Ã  cÃŽtÃ© de chaque fichier dans l'espace de travail et dans les arborescences de fichiers de la collection dans les Affichages Rassembler et Enrichir.
+      <Break/>
+      Le panneau "Mode" est utilisÃ© pour contrÃŽler le niveau du dÃ©tail dans l'interface. Dans sa configuration la plus basse, "Librarian Assistant", la vue de dÃ©coration, est dÃ©sactivÃ©e, les arguments qui requiÃšrent des expressions ordinaires sont cachÃ©s, et la construction de la collection produit un enregistrement minimal d'Ã©vÃšnements. Par contre, la configuration la plus Ã©levÃ©e, "Expert", donne l'accÃšs Ã  toutes les fonctionnalitÃ©s de dÃ©coration, y compris le positionnement de plugin, et les arguments d'expressions ordinaires; elle permet aussi l'enregistrement de l'intÃ©gralitÃ© des messages lors de la construction de la collection. Pour changer ou revoir les modes, cliquez sur le bouton radio situÃ© Ã  cÃŽtÃ© du mode qui vous intÃ©resse. Vous pouvez contrÃŽler rapidement le mode dans lequel vous vous trouvez en regardant la barre de titre de Librarian Interface.
+      <Break/>
+      L'Interface BibliothÃ©caire est capable de supporter diffÃ©rents flux de travail en dÃ©terminant lesquels des diffÃ©rents onglets d'affichage sont visibles. Utiliser l'onglet "Workflow" pour adapter les fenÃªtres d'affichage disponibles en cochant les boÃ®tes qui sont Ã  cÃŽtÃ© des affichages souhaitÃ©s. On peut aussi utiliser la liste dÃ©roulante pour sÃ©lectionner des configurations prÃ©dÃ©terminÃ©es. La fermeture du dialogue des prÃ©fÃ©rences Ã©tablit ces paramÃštres de workflow (flux de travail). Ces paramÃštres sont emmagasinnÃ©s dans la collection, et non dans le fichier de configuration de l'Interface BibliothÃ©caire.
+      <Break/>
+      L'onglet "Connexion" permet changer le chemin vers le serveur de bibliothÃšque local basÃ© sur Greenstone et utilisÃ© dans l'aperÃ§u des collections. Vous pouvez aussi prÃ©ciser le proxy de connection internet (c.a.d. pour lÃ©lÃ©charger les fichiers; voir la <Reference target="downloadingfiles">TÃ©lÃ©charger les fichiers de l'Internet</Reference> section pour les details). Cochez la case pour une connection proxy et donnez l'addresse du proxy et son numÃ©ro de port. La connection proxy sera Ã©tablie aprÃšs fermeture du dialogue.
+      <Break/>
+      En cours de session, l'Interface BibliothÃ©ccaire peut dÃ©livrer des messages d'avertissement qui informent sur d'Ã©ventuelles consÃ©quences d'une action. On peut dÃ©sactiver le message  en cochant la case "Ne pas afficher cet avertissement de nouveau" ("Do not show this warning again"). On peut rÃ©activer les messages d'avertissement en utilisant l'onglet "Avertissement" ("Warning"). Cocher la boÃ®te situÃ©e Ã  cÃŽtÃ© des messages d'avertissement que l'on souhaite reconsulter. 
+    </Section>
+    <Section name="fileassociations">
+      <Title>Associations de fichiers</Title>
+      L'Interface BibliothÃ©caire utilise des programmes d'application particuliÃšres pour ouvrir des types de fichiers particuliers. Cette section explique comment assigner et Ã©diter ces associations de fichiers. 
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+           Ajouter association
+          </ContentsItem>
+          <ContentsItem>
+            Editer association
+          </ContentsItem>
+          <ContentsItem>
+            Enlever association
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Pour modifier des associations ouvrez le menu "Fichier" et cliquer sur "Association de fichiers". 
+      <Break/>
+      Pour ajouter une association, sÃ©lectionner l'extension du fichier cible dans la liste dÃ©roulant, ou taper dans une nouvelle extension (n'y incluer pas le ".") Ensuite soit taper la commande qui lance l'application voulue dans la champ appropriÃ©, soit choisir l'application dans le dialogue "Navigation". "%1" Peut Ãªtre utilisÃ© dans la commande de lancement pour insÃ©rer le nom du fichier qu'on veut ouvrir. Une fois cela, "Ajouter Association" est activÃ©. Cliquer dessus pour ajouter l'association.
+      <Break/>
+      Pour Ã©diter une association, sÃ©lectionner une extension de fichier existante. Toute commande existante associÃ©e est affichÃ©e dans le champ de la commande de lancement. Corriger-la, et puis cliquer sur "Remplacer Association".
+      <Break/>
+      Pour enlever une association, sÃ©lectionner une extension de fichier existante et cliquer sur "Enlever Association". (L'extension du fichier reste dans la liste dÃ©roulante "For Files Ending").
+      <Break/>
+      Les associations de fichiers sont stockÃ©es dans le dossier principal du rÃ©pertoire principal de l'Interface BibliothÃ©caire, dans un fichier appelÃ© "associations.xml".
+    </Section>
+    <Section name="exportingcollections">
+      <Title>Exportation de collections vers CD-ROM</Title>
+      Cette section dÃ©crit comment exporter des collections vers un CD-ROM d'auto-installation Greenstone.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>Comment exporter</ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">Instructions simples:</Anchor>
+      Greenstone peut exporter une ou plusieurs collections vers un CD-ROM d'auto-installation pour Windows. Pour ce faire, le paquetage Greenstone "Export to CD-ROM" doit Ãªtre installÃ©. Il n'est pas inclut par dÃ©faut, donc vous aurez peut Ãªtre Ã  modifier votre installation pour l'inclure.
+      <Break/>
+      Pour exporter une collection, ouvrir le menu "Fichier" et choisir "Exporter vers CD-ROM". Une liste de collections Greenstone apparaÃ®t; cliquez sur n'importe laquelle pour obtenir une description. Cochez la case des collections Ã  exporter. Vous pouvez entrer le nom du CD-ROM dans la case: c'est ce qui va apparaÃ®tre dans le menu de dÃ©marrage lorsque le CD-ROM aura Ã©tÃ© installÃ©. Puis cliquez sur "Exporter". Ce processus implique la copie de plusieurs fichiers et peut durer quelques minutes.
+      <Break/>
+      A la fin de l'opÃ©ration, Greenstone va afficher le nom d'un dossier contenant les collections exportÃ©es. Utilisez un graveur de CD pour copier le contenu dans un CD vierge.
+    </Section>
+  </Section>
+</Document>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/help_index.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/help_index.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/help_index.xml	(revision 10506)
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Document><Section name="introduction"><Title>Introduction</Title><Section name="ofmiceandmenus"><Title>Dessouris et Menus</Title></Section><Section name="howtoavoidthisdocument"><Title>Comment Ã©viter de lire ce document</Title></Section></Section><Section name="startingoff"><Title>DÃ©marrage</Title><Section name="creatingacollection"><Title>CrÃ©er une nouvelle collection</Title></Section><Section name="savingacollection"><Title>Enregistrer la Collection</Title></Section><Section name="openingacollection"><Title>Ouvrir une collection existante</Title></Section><Section name="deletingcollections"><Title>Suppression des collections</Title></Section></Section><Section name="downloadingfiles"><Title>TÃ©lÃ©chargement de fichiers de lIinternet</Title><Section name="themirrorview"><Title>La vue TÃ©lÃ©chargement</Title></Section></Section><Section name="collectingfiles"><Title>Collecter les fichiers pour la Collection</Title><Section name="thegatherview"><Title>L'affichage Rassembler</Title></Section><Section name="creatingfolders"><Title>CrÃ©er des dossiers</Title></Section><Section name="addingfiles"><Title>Ajouter des fichiers</Title></Section><Section name="removingfiles"><Title>Supprimer des Fichiers</Title></Section><Section name="filteringthetree"><Title>Filtrer l'arborescence</Title></Section></Section><Section name="enrichingacollection"><Title>Enrichir la Collection avec des mÃ©ta-donnÃ©es</Title><Section name="theenrichview"><Title>L'affichage Enrichir</Title></Section><Section name="selectingmetadatasets"><Title>SÃ©lectionner les jeux de mÃ©ta-donnÃ©es</Title></Section><Section name="appendingmetadata"><Title>Ajout de Nouvelles MÃ©ta-donnÃ©es</Title></Section><Section name="addingpreviouslydefinedmetadata"><Title>Ajouter des MÃ©ta-donnÃ©es prÃ©dÃ©finies</Title></Section><Section name="updatingmetadata"><Title>Mettre Ã  jour des MÃ©ta-donnÃ©es</Title></Section><Section name="removingmetadata"><Title>Enlever les mÃ©ta-donnÃ©es</Title></Section><Section name="reviewingmetadata"><Title>Passer en revue les MÃ©ta-donnÃ©es assignÃ©es</Title></Section><Section name="importingpreviouslyassignedmetadata"><Title>Importer des MÃ©ta-donnÃ©es PrÃ©-assignÃ©es</Title></Section></Section><Section name="designingacollection"><Title>DÃ©coration de l'apparence de votre collection</Title><Section name="thedesignview"><Title>L'Affichage conception</Title></Section><Section name="generalsettings"><Title>RÃ©glages gÃ©nÃ©raux</Title></Section><Section name="plugins"><Title>Plugiciels de Document</Title></Section><Section name="searchtypes"><Title>Types de recherche</Title></Section><Section name="searchindexes"><Title>Index de recherche</Title></Section><Section name="partitionindexes"><Title>Index de Partition</Title><Section name="definefilters"><Title>DÃ©finir les Filtres</Title></Section><Section name="assignpartitions"><Title>Assigner des Partitions</Title></Section><Section name="assignlanguages"><Title>Assigner Langages</Title></Section></Section><Section name="xcollectionsearching"><Title>Recherche unique Ã  travers plusieurs collections</Title></Section><Section name="classifiers"><Title>Classificateurs</Title></Section><Section name="formatstatements"><Title>CaractÃ©ristiques de Format</Title></Section><Section name="translatetext"><Title>Traduire Texte</Title></Section><Section name="metadatasets"><Title>jeux de MÃ©ta-donnÃ©es</Title></Section></Section><Section name="producingthecollection"><Title>Pour produire votre collection</Title><Section name="thecreateview"><Title>L'Affichage CrÃ©er</Title></Section><Section name="buildsettings"><Title>ParamÃštres d'Importation et de Construction</Title></Section></Section><Section name="miscellaneous"><Title>Miscellaneous</Title><Section name="preferences"><Title>PrÃ©fÃ©rences</Title></Section><Section name="fileassociations"><Title>Associations de fichiers</Title></Section><Section name="exportingcollections"><Title>Exportation de collections vers CD-ROM</Title></Section></Section></Document>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/howtoavoidthisdocument.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/howtoavoidthisdocument.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/howtoavoidthisdocument.htm	(revision 10506)
@@ -0,0 +1,57 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="howtoavoidthisdocument"><font size="5" face="Verdana"><strong>1.2: Comment &eacute;viter de lire ce document</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Ne pas lire l'Aide en entier! Lire juste ce qui est n&eacute;cessaire pour obtenir l'aide dont on a besoin.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Aide contextuelle intuitive</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Outils (Tool tips)</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Autres documents</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      L'&eacute;l&eacute;ment de menu Aide indique l'&eacute;l&eacute;ment d'aide le plus appropri&eacute; par une ic&ocirc;ne sous forme de petit livre. 
+      <p></p>
+      Le positionnement de la souris sur plusieurs contr&ocirc;les entra&icirc;ne l'apparition d'un "Tool tip" qui dit ce qu'il faut faire.
+      <p></p>
+      Avant d'utiliser l'Interface Biblioth&eacute;caire, il faut lire la documentation Greenstone. La section "Cr&eacute;er une Nouvelle Collection" d&eacute;crit comment cr&eacute;er une nouvelle collection. Avant d'utiliser l'Interface Biblith&eacute;caire, lire d'abord la documentation de Greenstone.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/importingpreviouslyassignedmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/importingpreviouslyassignedmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/importingpreviouslyassignedmetadata.htm	(revision 10506)
@@ -0,0 +1,53 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="importingpreviouslyassignedmetadata"><font size="5" face="Verdana"><strong>5.8: Importer des M&eacute;ta-donn&eacute;es Pr&eacute;-assign&eacute;es</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique comment importer des m&eacute;ta-donn&eacute;es affect&eacute;es pr&eacute;c&eacute;demment; m&eacute;ta-donn&eacute;es affect&eacute;es avant d'&ecirc;tre ajout&eacute;es &agrave; la collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    En ajoutant des fichiers
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Si la m&eacute;ta-donn&eacute;e dans une forme reconnue par l'Interface Biblioth&eacute;caire a &eacute;t&eacute; pr&eacute;alablement assign&eacute;e &agrave; un fichier, -- par exemple, quand on choisit des documents dans une collection Greenstone existante -- elle est import&eacute;e automatiquement quand on ajoute le fichier. Pour ce faire, la m&eacute;ta-donn&eacute;e doit &ecirc;tre ajust&eacute;e au jeu de m&eacute;ta-donn&eacute;es disponibles dans la collection.
+      <p></p>
+      L'Interface Biblioth&eacute;caire confirme l'information n&eacute;cessaire. confirmation sous forme d'instructions br&egrave;ves et qui montre ensuite le nom de l'&eacute;l&eacute;ment m&eacute;ta-donn&eacute;e qui est import&eacute;e, comme il appara&icirc;t dans le fichier source. Ce champ ne peut &ecirc;tre ni &eacute;dit&eacute; ni chang&eacute;. Ensuite on choisit sur quel jeu de m&eacute;ta-donn&eacute;e le nouveau &eacute;l&eacute;ment devrait &ecirc;tre calqu&eacute; et enfin l'&eacute;l&eacute;ment m&eacute;ta-donn&eacute;e appropri&eacute;. Le syt&egrave;me selectionne automatiquement le meilleur ajustement, en terme de jeu et d'&eacute;l&eacute;ment pour la nouvelle m&eacute;ta-donn&eacute;e.
+      <p></p>
+      Apr&egrave;s cela,on peut choisir "Ajouter" pour ajouter le nouvel &eacute;l&eacute;ment m&eacute;ta-donn&eacute;e au jeu de m&eacute;ta-donn&eacute;es choisi. (Ceci n'est possible que si aucun &eacute;lement de m&ecirc;me nom n'est pr&eacute;sent &agrave; l'interieur du jeu choisi.) "Remplacer" applique le nouvel &eacute;lement &agrave; celui choisi par l'utilisateur. Enfin, "Ignorer" n'importe aucune m&eacute;ta-donn&eacute;e avec ce nom d'&eacute;lement. Une fois pr&eacute;cis&eacute;e la mani&egrave;re d'importer un certain &eacute;l&eacute;ment de m&eacute;ta-donn&eacute;e, l'information d'application est retenue pour la dur&eacute;e de vie de la collection.
+      <p></p>
+      Pour des d&eacute;tails concenant les fichiers m&eacute;ta-donn&eacute;e.xml que Greenstone utilise pour sauvegarder les m&eacute;ta-donn&eacute;es, il faut vous ref&eacute;rer au chapitre 2 du guide du D&eacute;veloppeur de Greenstone -- "Exploitez vos documents au maximum".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/introduction.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/introduction.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/introduction.htm	(revision 10506)
@@ -0,0 +1,17 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="introduction"><font size="5" face="Verdana"><strong>1: Introduction</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    L'interface biblioth&eacute;caire de Greenstone est un outil pour collecter et enrichir des documents et ensuite mettre sur pied des collections de biblioth&egrave;ques num&eacute;riques. Il fournit un acc&egrave;s &agrave; la fonctionnalit&eacute; du logiciel de la Biblioth&egrave;que num&eacute;rique de Greenstone &agrave; partir d'un point de vue graphique et d'une interface "clic".
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/metadatasets.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/metadatasets.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/metadatasets.htm	(revision 10506)
@@ -0,0 +1,71 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="metadatasets"><font size="5" face="Verdana"><strong>6.11: jeux de M&eacute;ta-donn&eacute;es</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique le panel de visualisation du jeu de m&eacute;ta-donn&eacute;es. Sous "Sections de conception", cliquer sur "jeux de M&eacute;ta-donn&eacute;es". 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            jeux de m&eacute;ta-donn&eacute;es disponibles
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ajout de jeux m&eacute;ta-donn&eacute;es
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            &Eacute;dition de jeux m&eacute;ta-donn&eacute;es
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Suppression de jeux m&eacute;ta-donn&eacute;es
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Cette fen&ecirc;tre sert &agrave; la revue des jeux de m&eacute;ta-donn&eacute;es utilis&eacute;s dans la collection, et les &eacute;l&eacute;ments qui sont disponibles dans chaque jeu. Choisir dans la liste de "jeux de m&eacute;ta-donn&eacute;es disponibles" pour voir des informations d&eacute;taill&eacute;es &agrave; ces &eacute;l&eacute;ments.
+      <p></p>
+      Pour utiliser un autre jeu de m&eacute;ta-donn&eacute;es avec la collection charg&eacute;e, clicquez sur "Ajouter un jeu de m&eacute;ta-donn&eacute;es" et s&eacute;lectionnez le fichier m&eacute;ta-donn&eacute;es (.mds) pour le nouveau jeu m&eacute;ta-donn&eacute;es.
+      <p></p>
+      L'&eacute;dition de jeux m&eacute;ta-donn&eacute;es se fait avec l'&eacute;diteur Greenstone de m&eacute;ta-donn&eacute;es (GEMS). En clicquant sur le bouton "&Eacute;diter un jeux m&eacute;ta-donn&eacute;es" vous obtiendrez des informations sur l'utilisation de GEMS.
+      <p></p>
+      Si vous n'avez plus besoin d'un jeu m&eacute;ta-donn&eacute;es, s&eacute;lectionnez le et clickez sur "Suppression du jeu m&eacute;ta-donn&eacute;es" pour l'enlever. Si vous avez affectt&eacute; des m&eacute;ta-donn&eacute;es aux &eacute;l&eacute;ments du jeu supprim&eacute;, on vous demandera ce que vous voulez en faire lorsque vous allez ouvrir &agrave; nouveau cette collection.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/miscellaneous.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/miscellaneous.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/miscellaneous.htm	(revision 10506)
@@ -0,0 +1,18 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="miscellaneous"><font size="5" face="Verdana"><strong>8: Miscellaneous</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Cette section d&eacute;crit les caract&eacute;ristiques de l'Interface Biblioth&eacute;caire qui ne sont pas associ&eacute;es &agrave; une fen&ecirc;tre d'affichage particuli&egrave;re.
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/ofmiceandmenus.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/ofmiceandmenus.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/ofmiceandmenus.htm	(revision 10506)
@@ -0,0 +1,80 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="ofmiceandmenus"><font size="5" face="Verdana"><strong>1.1: Dessouris et Menus</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      La section "Dessouris et Menus" fournit une information de base sur la mani&egrave;re de dialoguer avec l'interface biblioth&eacute;caire. Si on est familier avec des programmes comme Internet Explorer ou Microsoft Office et aussi &agrave; l'aise avec les menus et les clics de la souris, passer &agrave; <a href="howtoavoidthisdocument.htm#howtoavoidthisdocument">section suivante</a>.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Concepts de base
+            <tr>
+<td colspan="2"> </td><td colspan="1">T&acirc;ches de la souris</td>
+</tr>
+            
+<tr>
+<td colspan="2"> </td><td colspan="1">Clavier</td>
+</tr>
+          
+</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Quitter le programme</td>
+</tr>
+	
+	
+<tr>
+<td colspan="3"><a href="#advanced">Instructions avanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Touches de raccourcis</td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      L'interface biblioth&eacute;caire suit les conventions de Microsoft Windows et requiert une connaissance de base de Windows.
+      <p></p>
+      Une position quelconque d'interaction sur l'&eacute;cran, tel qu'un bouton ou un champ de texte, est appel&eacute;e "contr&ocirc;le". A tout moment, un contr&ocirc;le appel&eacute; "Foyer" est mis en relief et r&eacute;pond au clavier. Plusieurs contr&ocirc;les vous permettent de s&eacute;lectionner les parties qui sont mises en relief en bleu fonc&eacute;. Certains contr&ocirc;les virent au gris pour indiquer qu'ils sont &eacute;teints.
+      <p></p>
+      On peut d&eacute;placer la souris, cliquer sur son bouton gauche (cliquer-gauche) ou sur son bouton droit (cliquer-droite) de fa&ccedil;on tout &agrave; fait usuelle. Plusieurs &eacute;l&eacute;ments sont susceptibles d'&ecirc;tre entrain&eacute;s par glissement de la souris son bouton gauche &eacute;tant maintenu appuy&eacute;, et d'&ecirc;tre ainsi d&eacute;pos&eacute;s quelque part en rel&acirc;chant le bouton. Des cibles de d&eacute;p&ocirc;t potentielles changent d'apparence quand un composant les atteint.
+      <p></p>
+      On peut utiliser le clavier pour la saisie &agrave; l'int&eacute;rieur des champs de texte. Des alternatives au clavier sont disponibles pour plusieurs contr&ocirc;les indiqu&eacute;s par un nom cl&eacute; entre crochets --- par exemple [Tab] change le foyer. Le signe plus indique les autres touches susceptibles d'&ecirc;tre appuy&eacute;es en m&ecirc;me temps.
+      <p></p>
+      Pour quitter l'Interface Biblioth&eacute;caire, on utilise "Sortir" du menu "Fichier". Votre collection sera d'abord sauvegard&eacute;e.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions avanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      Pour acc&eacute;der au menu, appuyer sur le bouton [Alt] et sur la lettre correspondante (soulign&eacute;e). Par exemple, pour le menu "Fichier" appuyer sur [Alt] + [F]. Pour choisir un &eacute;l&eacute;ment, appuyer sur la touche correspondante. Par exemple, lorsque le menu "Fichier" est d&eacute;roul&eacute;, appuyer sur "S" pour sauvegarder la collection.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/openingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/openingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/openingacollection.htm	(revision 10506)
@@ -0,0 +1,64 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="openingacollection"><font size="5" face="Verdana"><strong>2.3: Ouvrir une collection existante</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section indique la mani&egrave;re d'ouvrir des collections existantes en utilisant "Pr&ecirc;t pour Ouvrir Collection".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Comment ouvrir la Collection</td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions advanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Collections verrouill&eacute;es</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Collections de versions ant&eacute;rieures</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Pour ouvrir une collection existante, choisir "ouvrir" &agrave; partir du menu "Fichier" pour obtenir le "Pr&ecirc;t &agrave; l'ouverture de la collection". Une liste de vos collections Greenstone appara&icirc;t. En s&eacute;lectionner une pour voir sa description, et cliquer sur "Ouvrir" pour la charger. Si l'on cherche une collection qui est hors du dossier "Collect" de Greenstone, cliquer sur "Parcourir" pour un dialogue avec le syst&egrave;me de fichiers concern&eacute;.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions advanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      Dans le cas o&ugrave; plusieurs programmes d'Interface Biblioth&eacute;caire de Greenstone sont ex&eacute;cut&eacute;s simultan&eacute;ment, les r&eacute;pertoires concern&eacute;s sont v&eacute;rouill&eacute;s pour pr&eacute;venir une interf&eacute;rence. A l'ouverture d'une collection, un petit fichier de verrouillage temporaire est cr&eacute;&eacute; dans son dossier. Avant d'ouvrir une collection, l'interface Biblioth&eacute;caire v&eacute;rifie qu'aucun fichier de verrouillage n'existe d&eacute;j&agrave;. Le verrouillage d'une collection est indiqu&eacute; par la couleur de son ic&ocirc;ne: verte pour une collection normale, rouge quand elle est v&eacute;rouill&eacute;e. Cependant, quand l'on quitte l'Interface Biblioth&eacute;caire pr&eacute;matur&eacute;ment, le fichier de verrouillage est parfois laiss&eacute; en place. Quand une telle collection est ouverte, l'Interface Biblioth&eacute;caire demande si l'on veut se d&eacute;faire de son contr&ocirc;le. Ne jamais sosutraire une collection en cours d'utilisation par un autre.
+      <p></p>
+      Lorsque vous ouvrez une collection qui n'a pas &eacute;t&eacute; cr&eacute;&eacute;e par Greenstone Librarian Interface, on vous demande de s&eacute;lectionner un ou plusieurs jeux de m&eacute;ta-donn&eacute;es. Si vous n'en s&eacute;lectionnez aucun, les m&eacute;ta-donn&eacute;es existantes seront ignor&eacute;es. Dans le cas contraire, les m&eacute;ta-donn&eacute;es seront import&eacute;es comme lorsque vous cliquez et glisser dans des fichiers contenant des m&eacute;ta-donn&eacute;es. Ce processus est d&eacute;crit dans la section <a href="importingpreviouslyassignedmetadata.htm#importingpreviouslyassignedmetadata">Importation de M&eacute;ta-donn&eacute;es Pr&eacute;c&eacute;demment Assign&eacute;es</a>.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/partitionindexes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/partitionindexes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/partitionindexes.htm	(revision 10506)
@@ -0,0 +1,20 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="partitionindexes"><font size="5" face="Verdana"><strong>6.6: Index de Partition</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Les index sont construits sur un texte particulier ou des sources M&eacute;ta-donn&eacute;es. L'espace de recherche peut &ecirc;tre plus tard contr&ocirc;l&eacute; en morcelant l'index soit par langage ou par filtre choisi &agrave; l'avance. Cette section en d&eacute;crit la proc&eacute;dure. Sous "Sections de conception", cliquer "Index de Partition". 
+      <p></p>
+      L'affichage "Index de Partition" poss&egrave;de trois onglets: "D&eacute;finir les Filtres", "Assigner une partition" et "Assigner des langages". Pour en savoir davantage sur les partitions, lire sur les sous collections et les sous index au chapitre 2 de Greenstone developer's guide.
+      
+      
+      
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/plugins.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/plugins.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/plugins.htm	(revision 10506)
@@ -0,0 +1,90 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="plugins"><font size="5" face="Verdana"><strong>6.3: Plugiciels de Document</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section d&eacute;crit comment faire la configuration des plugiciels des documents que la collection utilise. Elle explique comment sp&eacute;cifier les plugiciels utilis&eacute;s, quels param&egrave;tres leur passer et dans quel ordre ils se d&eacute;roulent. Sous "Sections de conception", cliquer "Plugiciels de document".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ajouter un plugiciel
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Enlever un plugiciel
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Configurer un plugiciel
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Changer l'ordre des plugiciels
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions advanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Configuration d'usage
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Pour ajouter un plugiciel, s&eacute;lectionner-le sur la liste d&eacute;roulante de "Choisir le plugiciel &agrave; ajouter" situ&eacute;e &agrave; c&ocirc;t&eacute; du bouton et ensuite cliquer "Ajouter plugiciel". Une fen&ecirc;tre d&eacute;nomm&eacute;e "Configurer les arguments" appara&icirc;t; elle est d&eacute;crite plus loin. Une fois la configuration du nouveau plugiciel achev&eacute;e, il est ajout&eacute; &agrave; la fin de la liste "Plugiciels couramment assign&eacute;s". Veuillez noter que, &agrave; l'exception de UnknownPlug, chaque plugin ne peut appara&icirc;tre qu'une seule fois dans la liste.
+      <p></p>
+      Pour enlever un plugiciel, s&eacute;lectionner-le sur la liste et cliquer sur "Enlever plugiciel".
+      <p></p>
+      Les plugiciels sont configur&eacute;s en fournissant des arguments. Pour les changer, il faut s&eacute;lectionner le plugiciel &agrave; partir de la liste et cliquer "Configurer plugiciel" (Ou double-cliquer sur le plugiciel). Un dialogue "Configuration des arguments" appara&icirc;t avec diff&eacute;rent cont&ocirc;les pour sp&eacute;cifier les arguments.
+      <p></p>
+      Il existe plusieurs types de contr&ocirc;les. Certains sont des bo&icirc;tes de dialogue et cliquer sur l'une ajoute l'option appropri&eacute;e au plugiciel. Les autres sont des cha&icirc;nes de textes avec une bo&icirc;te de dialogue et un champ texte. Cliquer sur la bo&icirc;te pour activer l'argument, ensuite saisir le texte appropri&eacute; dans la bo&icirc;te (expression normale, chemin de fichier etc). Les autres sont des menus d&eacute;roulants &agrave; partir desquels on peut s&eacute;lectionner &agrave; partir d'une s&eacute;rie de valeurs d&eacute;termin&eacute;es. Pour apprendre ce qu'un argument peut faire, promener la souris planer sur son nom pendant un instant une description appara&icirc;tra.
+      <p></p>
+      Pour changer la configuration, cliquer sur "OK" pour valider et fermer la bo&icirc;te de dialogue, ou "Annuler" pour fermer la bo&icirc;te de dialogue sans changer les arguments du plugiciel.
+      <p></p>
+      Les plugiciels dans la liste sont execut&eacute;s en ordre et l'ordre est parfois important. Les deux plugiciels Qrcplug et Recplug sont vitaux au processus de construction de la collection, et sont plac&eacute;s &agrave; la fin de la liste (avec une ligne de s&eacute;paration). Pour changer l'ordre des autres, s&eacute;lectionner le plugiciel &agrave; d&eacute;placer et cliquer sur "D&eacute;placer vers le haut" ou "D&eacute;placer vers le bas".
+       <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions advanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+       L'Interface Biblioth&eacute;caire s'&eacute;vertue &agrave; d&eacute;terminer les arguments support&eacute;s par le plugiciel. Cependant, l'utilisateur peut avoir &agrave; indiquer d'autres arguments sp&eacute;ciaux; pour cela un champ texte appel&eacute; "Arguments Sp&eacute;cifiques" (en bas) est disponible. Tout texte qu'il contient est annex&eacute; &agrave; la fin de la commande Plugiciel.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/preferences.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/preferences.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/preferences.htm	(revision 10506)
@@ -0,0 +1,71 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="preferences"><font size="5" face="Verdana"><strong>8.1: Pr&eacute;f&eacute;rences</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique le dialogue des pr&eacute;f&eacute;rences, auquel on acc&egrave;de en ouvrant "Fichier" -&gt; "Pr&eacute;f&eacute;rences". 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">G&eacute;n&eacute;ral</td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">Mode</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Flux de travail</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Connexion</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">Avertissement</td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      La premi&egrave;re option "General" est un champ texte pour saisir votre adresse courriel. Ceci sera utilis&eacute; pour les &eacute;l&eacute;ments m&eacute;ta-donn&eacute;es "cr&eacute;ateur" et "Mainteneur" de la collection. L'option suivante est un liste d&eacute;roulante des langues dans lesquelles l'interface bibioth&egrave;quaire peut &ecirc;tre affich&eacute;e. Si on change le dictionnaire par le choix d'un autre sur la liste, on doit red&eacute;marrer l'Interface Biblioth&eacute;caire pour charger les cha&icirc;nes du nouveau langage &agrave; partir du dictionnaire.
+      <p></p>
+Si on coche "Affichage M&eacute;ta-donn&eacute;es &eacute;tendues", les diff&eacute;rents contr&ocirc;les relatifs aux m&eacute;ta-donn&eacute;es affichent toujours toutes les m&eacute;ta-donn&eacute;es qui ont &eacute;t&eacute; extraites automatiquement des documents. Lorsqu'on le d&eacute;s&eacute;lectionne, ces m&eacute;ta-donn&eacute;es sont cach&eacute;es (bien qu'elles restent disponibles pendant la conception de la collection, et dans la collection Greenstone finale.) Si on coche "Montrer les tailles des fichiers", la taille du fichier appara&icirc;t &agrave; c&ocirc;t&eacute; de chaque fichier dans l'espace de travail et dans les arborescences de fichiers de la collection dans les Affichages Rassembler et Enrichir.
+      <p></p>
+      Le panneau "Mode" est utilis&eacute; pour contr&ocirc;ler le niveau du d&eacute;tail dans l'interface. Dans sa configuration la plus basse, "Librarian Assistant", la vue de d&eacute;coration, est d&eacute;sactiv&eacute;e, les arguments qui requi&egrave;rent des expressions ordinaires sont cach&eacute;s, et la construction de la collection produit un enregistrement minimal d'&eacute;v&egrave;nements. Par contre, la configuration la plus &eacute;lev&eacute;e, "Expert", donne l'acc&egrave;s &agrave; toutes les fonctionnalit&eacute;s de d&eacute;coration, y compris le positionnement de plugin, et les arguments d'expressions ordinaires; elle permet aussi l'enregistrement de l'int&eacute;gralit&eacute; des messages lors de la construction de la collection. Pour changer ou revoir les modes, cliquez sur le bouton radio situ&eacute; &agrave; c&ocirc;t&eacute; du mode qui vous int&eacute;resse. Vous pouvez contr&ocirc;ler rapidement le mode dans lequel vous vous trouvez en regardant la barre de titre de Librarian Interface.
+      <p></p>
+      L'Interface Biblioth&eacute;caire est capable de supporter diff&eacute;rents flux de travail en d&eacute;terminant lesquels des diff&eacute;rents onglets d'affichage sont visibles. Utiliser l'onglet "Workflow" pour adapter les fen&ecirc;tres d'affichage disponibles en cochant les bo&icirc;tes qui sont &agrave; c&ocirc;t&eacute; des affichages souhait&eacute;s. On peut aussi utiliser la liste d&eacute;roulante pour s&eacute;lectionner des configurations pr&eacute;d&eacute;termin&eacute;es. La fermeture du dialogue des pr&eacute;f&eacute;rences &eacute;tablit ces param&egrave;tres de workflow (flux de travail). Ces param&egrave;tres sont emmagasinn&eacute;s dans la collection, et non dans le fichier de configuration de l'Interface Biblioth&eacute;caire.
+      <p></p>
+      L'onglet "Connexion" permet changer le chemin vers le serveur de biblioth&egrave;que local bas&eacute; sur Greenstone et utilis&eacute; dans l'aper&ccedil;u des collections. Vous pouvez aussi pr&eacute;ciser le proxy de connection internet (c.a.d. pour l&eacute;l&eacute;charger les fichiers; voir la <a href="downloadingfiles.htm#downloadingfiles">T&eacute;l&eacute;charger les fichiers de l'Internet</a> section pour les details). Cochez la case pour une connection proxy et donnez l'addresse du proxy et son num&eacute;ro de port. La connection proxy sera &eacute;tablie apr&egrave;s fermeture du dialogue.
+      <p></p>
+      En cours de session, l'Interface Biblioth&eacute;ccaire peut d&eacute;livrer des messages d'avertissement qui informent sur d'&eacute;ventuelles cons&eacute;quences d'une action. On peut d&eacute;sactiver le message  en cochant la case "Ne pas afficher cet avertissement de nouveau" ("Do not show this warning again"). On peut r&eacute;activer les messages d'avertissement en utilisant l'onglet "Avertissement" ("Warning"). Cocher la bo&icirc;te situ&eacute;e &agrave; c&ocirc;t&eacute; des messages d'avertissement que l'on souhaite reconsulter. 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/producingthecollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/producingthecollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/producingthecollection.htm	(revision 10506)
@@ -0,0 +1,17 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="producingthecollection"><font size="5" face="Verdana"><strong>7: Pour produire votre collection</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Apr&egrave;s avoir rassembl&eacute; les documents de la collection, les avoir annot&eacute;s avec les m&eacute;ta-donn&eacute;es, et d&eacute;fini comment la collection va appara&icirc;tre, la production de la collection en utilisant Greenstone est alors possible. Cette section vous en explique la mani&egrave;re.
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/removingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/removingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/removingfiles.htm	(revision 10506)
@@ -0,0 +1,61 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="removingfiles"><font size="5" face="Verdana"><strong>4.4: Supprimer des Fichiers</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section d&eacute;crit la mani&egrave;re de supprimer des fichiers et des dossiers de la collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Le bouton Supprimer
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            La touche Supprimer
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Supprimer par glisser-d&eacute;placer
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Il existe plusieurs m&eacute;thodes pour supprimer des fichiers et des dossiers. On doit d'abord indiquer les &eacute;l&eacute;ments &agrave; supprimer en s&eacute;lectionnant un ou plusieurs fichiers et dossiers comme d&eacute;crit dans <a href="thegatherview.htm#thegatherview">L'Affichage Rassembler (The Gather view)</a>.
+      <p></p>
+      D&egrave;s lors que les fichiers sont s&eacute;lectionn&eacute;s, cliquer sur le bouton "Supprimer" pour les d&eacute;truire, ou appuyer sur la touche [Delete] de votre clavier, ou les glisser-d&eacute;placer de la collection vers le bouton "Supprimer" et les y d&eacute;poser.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/removingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/removingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/removingmetadata.htm	(revision 10506)
@@ -0,0 +1,55 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="removingmetadata"><font size="5" face="Verdana"><strong>5.6: Enlever les m&eacute;ta-donn&eacute;es</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique comment retirer des m&eacute;ta-donn&eacute;es d'un fichier.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Enlever &agrave; partir de fichiers
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Enlever &agrave; partir de dossiers ou de fichiers multiples
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      On enlever la m&eacute;ta-donn&eacute;e de la m&ecirc;me fa&ccedil;on que sa mise &agrave; jour. S&eacute;lectionner d'abord un fichier &agrave; partir de l'arborescence des fichiers, utiliser ensuite le tableau de m&eacute;ta-donn&eacute;e pour s&eacute;lectionner la m&eacute;ta-donn&eacute;e. Si la m&eacute;ta-donn&eacute;e a une valeur, le bouton "Enlever" devient actif. Cliquer-le pour enlever la m&eacute;ta-donn&eacute;e du fichier sp&eacute;cifi&eacute;. D'autres fichiers demeurent inchang&eacute;s et la valeur reste dans l'arborescence des valeurs. 
+      <p></p>
+      La suppression de m&eacute;ta-donn&eacute;es de r&eacute;pertoires ou de plusieurs fichiers fonctione de la m&ecirc;me fa&ccedil;on.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/reviewingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/reviewingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/reviewingmetadata.htm	(revision 10506)
@@ -0,0 +1,80 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="reviewingmetadata"><font size="5" face="Verdana"><strong>5.7: Passer en revue les M&eacute;ta-donn&eacute;es assign&eacute;es</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section d&eacute;crit la mani&egrave;re de visionner toutes les m&eacute;ta-donn&eacute;es assign&eacute;es &agrave; la colletion enti&egrave;re.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Le tableau d'audit
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions advanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Le menu bouton droit
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Autofiltrage
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      On &eacute;prouve parfois le besoin de voir, &agrave; la fois, les m&eacute;ta-donn&eacute;es affect&eacute;es &agrave; plusieurs ou &agrave; tous les fichiers -- par exemple, pour d&eacute;terminer combien de fichiers sont en cours d'utilisation ou pour avoir une id&eacute;e de la chronologie. 
+      <p></p>
+      S&eacute;lectionnez les fichiers que vous souhaitez examiner, puis clicquez sur le bouton droit et choisissez "M&eacute;ta-donn&eacute;es Associ&eacute;es...". Une fen&ecirc;tre appel&eacute;e "Toutes les M&eacute;ta-donn&eacute;es", sous forme d'un grand tableau avec plusieurs colonnes, appara&icirc;t. La premi&egrave;re colonne montre les noms de fichiers; les lignes montrent toutes les valeurs de m&eacute;ta-donn&eacute;es assign&eacute;es &agrave; ces fichiers.
+      <p></p>
+      Dessiner le tableau peut prendre quelque temps si plusieurs fichiers sont s&eacute;lectionn&eacute;s. On peut continuer &agrave; utiliser l'Interface Biblioth&eacute;caire pendant que la fen&ecirc;tre "Toutes M&eacute;ta-donn&eacute;es" est ouverte.
+      <p></p>
+      Cliquer "Fermer" pour cacher la fen&ecirc;tre.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions advanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      On peut aussi visualiser le tableau "Toutes M&eacute;tadonn&eacute;es" en s&eacute;lectionnant les fichiers &agrave; examiner en cliquant sur le bouton droit et en choisissant "M&eacute;ta-donn&eacute;es Assign&eacute;es...". Si un dossier a &eacute;t&eacute; s&eacute;lectionn&eacute;, tous ses fichiers sont inclus dans le tableau.
+      <p></p>
+      Quand il devient trop large, on peut filtrer le tableau "Toutes M&eacute;ta-donn&eacute;es" en appliquant des filtres aux colonnes. Alors que de nouveaux filtres sont ajout&eacute;s, seules les lignes qui concernent restent visibles. Pour installer, modifier ou effacer un filtre, cliquez sur l'&icirc;cone "Funnel" situ&eacute; en haut de la colonne. Une information sur le filtre est r&eacute;clam&eacute;e. Une fois le filtre install&eacute;, l'en-t&ecirc;te de la colonne change de couleur.
+      <p></p>
+      La confirmation poss&egrave;de un onglet "simple" et " advanc&eacute;". La version simple filtre  les colonnes afin qu'elles ne montrent que des lignes qui contiennent une certaine valeur de m&eacute;ta-donn&eacute;e ("*" concerne toutes les valeurs). On peut s&eacute;lectionner des valeurs de m&eacute;ta-donn&eacute;es &agrave; partir d'une liste d&eacute;roulante. La version advanc&eacute;e permet diff&eacute;rentes op&eacute;rations d'harmonisation: doit commencer avec, ne contient pas, alphab&eacute;tiquement et est &eacute;gal &agrave;. La valeur &agrave; harmoniser peut &ecirc;tre &eacute;dit&eacute;e et prise sous forme d'une cha&icirc;ne quelconque (y compris "*"), et on peut opter pour une harmonisation insensible aux caract&egrave;res. Enfin, on peut sp&eacute;cifier une deuxi&egrave;me condition d'harmonisation pr&eacute;cisant une gamme de valeurs (en s&eacute;lectionnant AND) ou des valeurs alternatives (en selectionnant OR). En dessous de cette zone, une bo&icirc;te qui permet de changer l'ordre de tri (ascendant ou descendant) est plac&eacute;e. Enfin, cliquer sur "Installer Filtre" pour appliquer le nouveau filtre &agrave; la colonne. Cliquer sur "Effacer Filtre" pour enlever le filtre courant. Notez que les d&eacute;tails du filtre sont retenus m&ecirc;me si le filtre est effac&eacute;.
+      <p></p>
+      Par exemple, pour trier le tableau "Toutes M&eacute;ta-donn&eacute;es" , choisir une colonne, s&eacute;lectionner le cadre du filtre par d&eacute;faut (Un filtre simple sur "*") et choisir un ordre ascendant ou descendant.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/savingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/savingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/savingacollection.htm	(revision 10506)
@@ -0,0 +1,64 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="savingacollection"><font size="5" face="Verdana"><strong>2.2: Enregistrer la Collection</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section d&eacute;crit la mani&egrave;re d'enregistrer une collection, et la confirmation d'enregistrement de la collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Comment enregistrer
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions advanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            O&ugrave; sont sauvegard&eacute;s les fichiers
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Enregistrer r&eacute;guli&egrave;rement votre travail en choisissant "Enregistrer" dans le fichier "Menu". Enregistrer une collection ne signifie pas la rendre pr&ecirc;te &agrave; l'utilisation dans Greenstone (see <a href="producingthecollection.htm#producingthecollection">Confectionner votre Collection</a>).
+      <p></p>
+      L'Interface Biblith&eacute;caire prot&egrave;ge votre travail en l'enregistrant &agrave; la fermeture du programme ou &agrave; l'ouverture d'une autre collection.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions advanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      Les collections sont enregistr&eacute;es en un fichier choisi pour la collection avec une extension ".col", localis&eacute; dans un r&eacute;pertoire de m&ecirc;me nom &agrave; l'int&eacute;rieur du dossier "collect" de l'installation de Greenstone.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/searchindexes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/searchindexes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/searchindexes.htm	(revision 10506)
@@ -0,0 +1,75 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="searchindexes"><font size="5" face="Verdana"><strong>6.5: Index de recherche</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Les index pr&eacute;cisent les parties de la collection qui doivent &ecirc;tre recherch&eacute;es. Cette section explique comment ajouter et enlever des index et fixer un index par d&eacute;faut. Sous "Sections de conception", cliquer sur "Rechercher Index".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Ajouter un index
+          </td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    &Eacute;diter un index
+	  </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Enlever un index
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Index par d&eacute;faut
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Pour ajouter un index, taper un nom choisi dans le champ "Nom de l'Index". Selectionner les sources d'information &agrave; indexer en cliquant les bo&icirc;tes de dialogue &agrave; c&ocirc;t&eacute; d'eux. La liste montre aussi bien tous les &eacute;l&eacute;ments de m&eacute;ta-donn&eacute;es assign&eacute;s, que le texte entier. Apr&egrave;s avoir s&eacute;lectionn&eacute; les sources de donn&eacute;es, choisir la granularit&eacute; de l'index en utilisant le menu "Au niveau". Une fois ces d&eacute;tails complet&eacute;s, "Ajouter Index" devient actif  (&agrave; moins qu'il n'ait un index existant avec les m&ecirc;mes param&egrave;tres). Cliquez pour ajouter un nouvel index.
+      <p></p>
+      Pour &eacute;diter un index, s&eacute;lectionnez-le et changez les d&eacute;tails de l'index, puis clicquez sur "Remplacer l'index".
+      <p></p>
+      Pour enlever un index, il faut le s&eacute;lectionner sur la liste d'index assign&eacute;s et cliquer "Enlever index". 
+      <p></p>
+      L'index par d&eacute;faut, celui qui est utilis&eacute; dans la page de recherche de la collection est labell&eacute; parc "[Index par d&eacute;faut]" dans la liste "Index assign&eacute;s".
+      <p></p>
+      Si la recherche avanc&eacute;e est activ&eacute;e (voir Affichage des types de recherche), les contr&ocirc;les d'index sont diff&eacute;rents.Chaque index est seulement bas&eacute; sur une source de donn&eacute;es. Il existe une nouvelle pseudo-source de donn&eacute;es "Tous champs" qui fournit une recherche &agrave; travers tous les index sp&eacute;cifi&eacute;s &agrave; la fois. Des niveaux ne sont pas assign&eacute;s &agrave; un index sp&eacute;cifique, mais s'applique &agrave; tous les index : ainsi index et niveaux sont ajout&eacute;s s&eacute;parement. Les index sont enlev&eacute;s de la m&ecirc;me fa&ccedil;on que pr&eacute;c&eacute;demment, mais l'index par d&eacute;faut ne peut plus &ecirc;tre mis activ&eacute;.. il est simplement le premier index assign&eacute;. 
+      <p></p>
+      Pour cr&eacute;er des index sur toutes les sources cliquez le bouton "Ajouter Tous". Le nom de chaque index sera en d&eacute;faut pour le nom de source. Pour changer le nom, S&eacute;lectionner un index, changer ses d&eacute;tails et cliquez "Remplacer Index". 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/searchtypes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/searchtypes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/searchtypes.htm	(revision 10506)
@@ -0,0 +1,71 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="searchtypes"><font size="5" face="Verdana"><strong>6.4: Types de recherche</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      cette section explique comment modifier une nouvelle caract&eacute;ristique de conception dans Greenstone, Types de recherche, qui permet une recherche de champ. Sous "Sections de conception", cliquer sur "Types de recherche".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Que signifie activer des recheches avanc&eacute;es?
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ajouter un nouveau type de recherche
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Enlever un type de recherche
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Changer l'ordre des types de recherche
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Lorsqu'on p&eacute;n&egrave;tre dans l'affichage Types de recherche, v&eacute;rifier d'abord "Activer recherches avanc&eacute;es", qui active les autres contr&ocirc;les. la collection prend le format 2.4 de Greenstone, qui supporte la recherche bas&eacute;e sur les champs, et signifie que: 1. l'index de conception est diff&eacute;rent (expliqu&eacute; dans <a href="searchindexes.htm#searchindexes">Recherche d'index</a> section), 2. plusieurs fragments de textes sont &agrave; traduire (voir <a href="translatetext.htm#translatetext">Translation</a>), 3. la collection est inutilisable sous des versions plus vieilles de Greenstone. Si vous d&eacute;-s&eacute;lectionner ce champ, la plupart de la collection retourne &agrave; la version 2.39 de Greenstone 2.39. Cependant, l'Interface Biblioth&eacute;caire ne peut pas convertir les nouvelles sp&eacute;cifications d'index en celles plus anciennes; elles doivent ainsi &ecirc;tre saisies de nouveau manuellement. 
+      <p></p>
+      pour ajouter un type de recherche, s&eacute;lectionner-le &agrave; partir de la liste "Types de recherche" et cliquer sur "Ajouter Type de recherche".  Chaque type n'appara&icirc;t qu'une fois sur la liste.
+      <p></p>
+      Pour enlever un type de recherche, il faut le selectionner &agrave; partir de la liste "Currently Assigned Search type" et cliquer sur "Enlever type de recheche". La liste doit contenir au moins un type de recherche.
+      <p></p>
+      pour changer l'ordre d'un type de recherche, s&eacute;lectionner-le &agrave; partir de la liste et cliquer sur "D&eacute;placer vers le haut" ou "D&eacute;placer vers le bas". Le premier sera le d&eacute;faut.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/selectingmetadatasets.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/selectingmetadatasets.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/selectingmetadatasets.htm	(revision 10506)
@@ -0,0 +1,55 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="selectingmetadatasets"><font size="5" face="Verdana"><strong>5.2: S&eacute;lectionner les jeux de m&eacute;ta-donn&eacute;es</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique comment sp&eacute;cifier les &eacute;l&eacute;ments m&eacute;ta-donn&eacute;e et comment ajouter les jeux de m&eacute;ta-donn&eacute;es &agrave; une collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Qu'est-ce qu'un jeu de m&eacute;ta-donn&eacute;es?
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Contr&ocirc;le des jeux de m&eacute;ta-donn&eacute;es utilis&eacute;s
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Les s&eacute;ries d'&eacute;l&eacute;ments de m&eacute;ta-donn&eacute;es pr&eacute;d&eacute;finis sont connus comme "jeux de M&eacute;ta-donn&eacute;es". "Dublin Core" en est un exemple. Quand on ajoute un Groupe de M&eacute;ta-donn&eacute;es &agrave; la collection, ses &eacute;l&eacute;ments peuvent &ecirc;tre s&eacute;lectionn&eacute;s. On peut avoir plus d'un jeu de m&eacute;ta-donn&eacute;es ; pour &eacute;viter des t&eacute;lescopages de nom, un identificateur abr&eacute;g&eacute; qui identifie le jeu de m&eacute;ta-donn&eacute;es est suspendu au nom de l'&eacute;l&eacute;ment. Par exemple l'&eacute;lement cr&eacute;ateur de Dublin Core devient "dc.Creator". Les jeux de m&eacute;ta-donn&eacute;es sont sauv&eacute;gard&eacute;s dans le dossier de m&eacute;ta-donn&eacute;es de l'Interface Biblioth&eacute;caire et ont le sufixe ".mds".
+      <p></p>
+      Pour contr&ocirc;ler les jeux de m&eacute;ta-donn&eacute;es utilis&eacute;s dans une collection, utilisez l'entr&eacute;e "Jeux M&eacute;ta-Donn&eacute;es" sur la vue "Conception".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/startingoff.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/startingoff.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/startingoff.htm	(revision 10506)
@@ -0,0 +1,19 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="startingoff"><font size="5" face="Verdana"><strong>2: D&eacute;marrage</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Cette section explique comment cr&eacute;er, charger, enregistrer et supprimer des collections.
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/thecreateview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/thecreateview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/thecreateview.htm	(revision 10506)
@@ -0,0 +1,70 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thecreateview"><font size="5" face="Verdana"><strong>7.1: L'Affichage Cr&eacute;er</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique l'utilisation de l'affichage cr&eacute;er pour produire une collection.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Construction de la collection
+	  </td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Aper&ccedil;u de la collection
+	  </td>
+</tr>
+	
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Journal des messages
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      L'Affichage Cr&eacute;er est utilis&eacute; pour cr&eacute;er la collection en mettant en Åuvre les scripts Greenstone relatifs &agrave; cette op&eacute;ration. En cliquant sur "Construire Collection", on initie le processus de construction de la collection. Sa dur&eacute;e d&eacute;pend de la taille de la collection  et du nombre d'index &agrave; cr&eacute;er (pour les grandes collections cela peut prendre des heures). Une barre d'&eacute;tat indique ou on en est dans le processus. Pour annuler le processus &agrave; tout moment, cliquer sur "Annuler Construction".
+      <p></p>
+      Quand la collection est construite, appuyant "Preview Collection" initiera la page web hebergeant la collection.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions advanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      En mode expert, vous pouvez utiliser l'entr&eacute;e "Message Log" &agrave; gauche pour revoir les tentatives pr&eacute;c&eacute;dentes de construction de la collection avec ou san succ&eacute;s. S&eacute;lectionnez le journal souhait&eacute; en cliquant sur la date correspondante dans la liste "Historique du Journal".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/thedesignview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/thedesignview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/thedesignview.htm	(revision 10506)
@@ -0,0 +1,51 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thedesignview"><font size="5" face="Verdana"><strong>6.1: L'Affichage conception</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section pr&eacute;sente l'affichage de conception et explique comment on navigue entre les diff&eacute;rents affichages &agrave; l'int&eacute;rieur de cette vitrine. 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Choisir une section de conception
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Avec l'Interface Biblioth&eacute;caire, on peut configurer la fa&ccedil;on dont la collection va appara&icirc;tre &agrave; l'utilisateur. Les options de configuration sont divis&eacute;es en diff&eacute;rentes sections, chacune associ&eacute;e &agrave; une &eacute;tape particuli&egrave;re de navigation ou de pr&eacute;sentation d'information.
+      <p></p>
+      Sur la gauche est plac&eacute;e une liste de diff&eacute;rents affichages et &agrave; droite les commandes associ&eacute;es &agrave; celles en cours. Pour passer &agrave; un  affichage diff&eacute;rent, cliquer son nom dans la liste.
+      <p></p>
+      Pour comprendre les diff&eacute;rentes &eacute;tapes et les termes implmiqu&eacute;s dans la conception d'une collection, lire les chapitres 1 et 2 de Greenstone's Developer's Guide. 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/theenrichview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/theenrichview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/theenrichview.htm	(revision 10506)
@@ -0,0 +1,77 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="theenrichview"><font size="5" face="Verdana"><strong>5.1: L'affichage Enrichir</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section d&eacute;crit comment ins&eacute;rer et &eacute;diter une m&eacute;ta-donn&eacute;e en utilisant l'affichage Enrichir.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            L'arborescence de la collection
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Les contr&ocirc;les d'&eacute;dition de m&eacute;ta-donn&eacute;es
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            L'arborescence valeur
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+           La m&eacute;ta-donn&eacute;e Table
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Utiliser l'affichage Enrichir pour assigner une m&eacute;ta-donn&eacute;e aux documents de la collection. Une m&eacute;ta-donn&eacute;e est une donn&eacute;e sur une donn&eacute;e -- de fa&ccedil;on typique titre, auteur, date de cr&eacute;ation, et ainsi de suite. Chaque &eacute;l&eacute;ment de m&eacute;ta-donn&eacute;e a deux parties: "el&eacute;ment" indique le type d'&eacute;l&eacute;ment (par exemple auteur), "valeur" qui donne la valeur de cette m&eacute;ta-donn&eacute;e &eacute;l&eacute;ment (par exemple le nom de l'auteur).
+      <p></p>
+      Sur la gauche de l'affichage "Enrichir" est l'arborescence de la collection. A sa droite, la Table de M&eacute;ta-donn&eacute;es, qui montre les m&eacute;ta-donn&eacute;es pour tous les fichiers et dossiers s&eacute;lectionn&eacute;es de l'arborescence de la collection. Les colonnes sont indiqu&eacute;es en gris en haut, et peuvent &ecirc;tre redimensionn&eacute;es en faisant glisser la ligne de s&eacute;paration. Clicquez sur n'importe quelle ligne pour transf&eacute;rer ses informations aux cont&ocirc;les de m&eacute;ta-donn&eacute;es ci-dessous. Si plusieurs fichiers sont s&eacute;lectionn&eacute;s, un texte en noir indique que la valeur est commune &agrave; tous les fichiers s&eacute;lectionn&eacute;s, tandis qu'un texte en gris en indique le contraire. les valeurs en noir peuvent &ecirc;tre mises &agrave; jour ou supprim&eacute;es, tandis que celles en gris peuvent &ecirc;tre supprim&eacute;es de ceux qui l'ont, ou ajout&eacute;es aux autres.
+      <p></p>
+      Une ic&ocirc;ne de dossier peut appara&icirc;tre &agrave; c&ocirc;t&eacute; de certaines entr&eacute;es de m&eacute;ta-donn&eacute;es. Ceci indique que les valeurs ont &eacute;t&eacute; h&eacute;rit&eacute;es d'un dossier parent. Les m&eacute;ta-donn&eacute;es h&eacute;rit&eacute;es ne peuvent &ecirc;tre &eacute;dit&eacute;es ou supprim&eacute;es, mais seulement ajout&eacute;es ou &eacute;cras&eacute;es. Cliquer sur l'ic&ocirc;ne du dossier pour aller imm&eacute;diatement au dossier o&ugrave; la m&eacute;ta-donn&eacute;e est assign&eacute;e.
+      <p></p>
+      Les contr&ocirc;les d'&eacute;dition de m&eacute;ta-donn&eacute;es en bas &agrave; droite apparaissent seulement quand un fichier dans l'arbre et une ligne dans la table sont s&eacute;lectionn&eacute;s. Utiliser les pour mettre &agrave; jour, ajouter et supprimer la valeur de la m&eacute;ta-donn&eacute;e. Le champ valeur sert &agrave; la saisie et &agrave; l'&eacute;dition de la valeur de la m&eacute;ta-donn&eacute;e. A c&ocirc;t&eacute;, le bouton de label "..." permet d'ouvrir une grande bo&icirc;te d'&eacute;dition. Les autres boutons situ&eacute;s en-dessous sont: "Coller ou ajouter" assigne la valeur comme nouvelle m&eacute;ta-donn&eacute;e et l'ajoute aux valeurs existantes de l'&eacute;l&eacute;ment s&eacute;lectionn&eacute;; "Remplacer" &eacute;crase la valeur existante s&eacute;lectionn&eacute;e avec la nouvelle; "Supprimer" efface la valeur s&eacute;lectionn&eacute;e. Au bas, le label "Toutes les valeurs pr&eacute;c&eacute;dentes" est la "Value Tree" ("Arborescence Valeur").
+      <p></p>
+      Celle-ci, d&eacute;veloppe et comprime. C'est une liste qui, de fa&ccedil;on usuelle, montre toutes les valeurs pr&eacute;c&eacute;demment saisies pour un &eacute;l&eacute;ment s&eacute;lectionn&eacute;. Le clic sur une entr&eacute;e la place automatiquement dans le champ valeur. Inversement, la saisie dans le champ texte s&eacute;lectionne l'entr&eacute;e de l'Arborescence Valeur qui d&eacute;bute avec les caract&egrave;res saisis. Appuyer sur [Tab] compl&egrave;te automatiquement la saisie de la valeur s&eacute;lectionn&eacute;e.
+      <p></p>
+      Les valeurs de m&eacute;ta-donn&eacute;e peuvent &ecirc;tre organis&eacute;es en une hi&eacute;rarchie.Ceci est montr&eacute; dans l'Arborescence Valeur utilisant des dossiers de niveau interne.Les valeurs hi&eacute;rarchiques peuvent &ecirc;tre saisies en utilisant le caract&egrave;re "|" pour s&eacute;parer les niveaux. Par exemple, "Cards|Red|Diamonds|Seven" peut &ecirc;tre utilis&eacute; dans une hi&eacute;rarchie qui repr&eacute;sente un jeu de cartes. Cela permet le rejeument des valeurs. Les jeux peuvent aussi &ecirc;trre assign&eacute;s comme m&eacute;ta-donn&eacute;e.
+      <p></p>
+      Greenstone extrait automatiquement des m&eacute;ta-donn&eacute;es &agrave; partir des documents en un jeu de m&eacute;ta-donn&eacute;es dont les &eacute;l&eacute;ments sont pr&eacute;fix&eacute;s "ex.". Ceci n'a aucune valeur et ne peut &ecirc;tre &eacute;dit&eacute;, et d&egrave;s lors les contr&ocirc;les MetaEdit sont cach&eacute;s si une telle entr&eacute;e est s&eacute;lectionn&eacute;e. Le bouton "..." sert toujours au d&eacute;veloppement de la valeur, mais le texte ne peut &ecirc;tre &eacute;dit&eacute;.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/thegatherview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/thegatherview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/thegatherview.htm	(revision 10506)
@@ -0,0 +1,102 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thegatherview"><font size="5" face="Verdana"><strong>4.1: L'affichage Rassembler</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+cette section introduit la zone Rassembler utilis&eacute;e pour selectionner les fichiers &agrave; inclure dans la collection &agrave; cr&eacute;er. 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+           comment afficher l'&eacute;cran "gather"
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Les arborescences de fichiers
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            La zone d'&eacute;tat
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Boutons de contr&ocirc;le
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions avanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            m&eacute;thodes de s&eacute;lection
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Application de dossiers sp&eacute;ciaux
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      L'Interface Biblioth&eacute;caire d&eacute;marre avec l'affichage "Rassembler". Pour revenir ult&eacute;rieurement &agrave; celui-ci, cliquer directement sur l'onglet "Rassembler" au bas de la barre des menus.
+      <p></p>
+      Les deux vastes zones intitul&eacute;es "Espace de travail" et "Collection" servent au transfert des fichiers vers la collection. Elles contiennent des arborescences de fichiers, des structures graphiques qui repr&eacute;sentent des fichiers et des dossiers.
+      <p></p>
+      Choisir un &eacute;l&eacute;ment dans l'arborescence en cliquant dessus. (d'autres mani&egrave;res de le faire existent; voir ci-dessous). Double-cliquer sur un dossier, ou cliquer simplement sur le symbole de commutateur plac&eacute; &agrave; c&ocirc;t&eacute; de lui, pour d&eacute;velopper (ou r&eacute;duire) son contenu. Double-cliquer sur un fichier pour l'ouvrir en utilisant un programme d'application associ&eacute; (voir <a href="fileassociations.htm#fileassociations">Association de fichiers</a>).
+      <p></p>
+      L'arbre des fichiers de l'espace de travail montre les sources de donn&eacute;es disponibles pour l'interface biblioth&eacute;caire -- le syst&egrave;me de fichiers local (ainsi que les unit&eacute;s de disques et Cd-rom), le contenu des collection Greenstone, et la cache des fichiers t&eacute;l&eacute;charg&eacute;s si l'option Web &laquo;&nbsp;miroir&nbsp;&raquo; est active. Vous pouvez copier et afficher ces fichiers mais vous ne pouvez pas les d&eacute;placer, supprimer ou &eacute;diter, &agrave; l'exception des fichiers t&eacute;l&eacute;charg&eacute;s qui peuvent &ecirc;tre supprim&eacute;. Vous pouvez naviguer &agrave; l'int&eacute;rieur de cet espace pour trouver les documents que vous souhaitez ajouter &agrave; la collection.
+      <p></p>
+      L'arborescence des fichiers de la Collection ne repr&eacute;sente jusque-l&agrave; que le contenu de la collection. Elle est initialement vide.
+      <p></p>
+      On peut redimensionner les espaces en positionnant la souris sur la barre grise qui s&eacute;pare les arborescences (le pointeur change de forme) et en la faisant glisser.
+      <p></p>
+      En bas de la fen&ecirc;tre, il y a une barre d'&eacute;tat qui montre l'&eacute;volution des op&eacute;rations sur les fichiers (copie, d&eacute;placement et suppression). Ces op&eacute;rations peuvent &ecirc;tre longues. Le bouton "Stop" arr&ecirc;te toute t&acirc;che en cours.
+      <p></p>
+      Deux grands boutons occupent le coin droit inf&eacute;rieur de l'&eacute;cran. "Nouveau dossier", avec une image d'un dossier, cr&eacute;e de nouveaux dossiers (voir <a href="creatingfolders.htm#creatingfolders">Cr&eacute;ation de dossiers</a>). "Supprimer", avec une corbeille, supprime les fichiers. Cliquer sur le bouton "Supprimer" d&eacute;truit tous les fichiers s&eacute;lectionn&eacute;s de l'arborescence de fichiers de la collection. On peut de m&ecirc;me r&eacute;aliser cette suppression de fichiers en les faisant glisser jusqu'au bouton "Supprimer". 
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions avanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      Pour s&eacute;lectionner plusieurs s&eacute;quences d'&eacute;l&eacute;ments, s&eacute;lectionner le premier, maintenir appuy&eacute;e la touche [Maj] et cliquer sur le dernier &eacute;l&eacute;ment de la s&eacute;quence -- la s&eacute;lection comprendra tous les &eacute;l&eacute;ments compris entre les deux. Pour la s&eacute;lection de fichiers qui ne se suivent pas, maintenir la touche [Ctrl] appuy&eacute;e en cliquant sur chacun d'eux. Ces deux m&eacute;thodes peuvent &ecirc;tre utilis&eacute;es ensemble pour la s&eacute;lection de jeux d'&eacute;l&eacute;ments non adjacents.
+      <p></p>
+      Certains dossiers -- tel que celui contenant vos propres pages Web -- ont parfois une signification sp&eacute;ciale. L'Interface Biblioth&eacute;caire peut appliquer de tels dossiers au premier niveau de l'arborescence de fichiers. Pour ce faire double-cliquer droite sur le dossier vis&eacute;. Choisir "Cr&eacute;er un Raccourci", saisir le nom du dossier. Pour enlever un &eacute;l&eacute;ment, cliquer-droite sur le fichier concern&eacute; et s&eacute;lectionner "Supprimer Raccourci".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/themirrorview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/themirrorview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/themirrorview.htm	(revision 10506)
@@ -0,0 +1,80 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="themirrorview"><font size="5" face="Verdana"><strong>3.1: La vue T&eacute;l&eacute;chargement</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section d&eacute;crit comment on configure une tache de t&eacute;l&eacute;chargement et comment on contr&ocirc;le le t&eacute;l&eacute;chargement.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            L'arbre espace de travail
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Configuration de t&eacute;l&eacute;chargement
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            La liste des t&eacute;l&eacute;chargements
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Instructions advanc&eacute;es:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Activation des proxies web
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Acc&eacute;dez &agrave; la vue "T&eacute;l&eacute;chargement" en cliquant son index. La moiti&eacute; sup&eacute;rieure de l'&eacute;cran montre le contr&ocirc;le des t&eacute;l&eacute;chargements. La moiti&eacute; inf&eacute;rieure est initialement vide, mais montrera la liste des t&eacute;l&eacute;chargements en attente et r&eacute;alis&eacute;s.
+      <p></p>
+      Les fichiers sont t&eacute;l&eacute;charg&eacute;s dans un dossier de l'espace de travail appel&eacute; &laquo;&nbsp;Fichiers T&eacute;l&eacute;charg&eacute;s&nbsp;&raquo; (Uniquement pr&eacute;sent lorsque l'op&eacute;ration &laquo;&nbsp;miroir&nbsp;&raquo; est activ&eacute;e), et peut &ecirc;tre utilis&eacute; pour toutes les collections construites avec l'interface biblioth&eacute;caire. Les fichiers dans cette zone portent comme nom leur URL en entier. Un nouveau dossier est cr&eacute;&eacute; pour chaque site h&ocirc;te, suivi par d'autres dossiers pour chaque &eacute;l&eacute;ment du chemin. Cela permet de s'assurer que chaque fichier a un nom distinct.
+      <p></p>
+      Utilisez le premier des contr&ocirc;les de la configuration de t&eacute;l&eacute;chargement, &laquo; Source URL &raquo;, pour entrer l'URL de la ressource cible. Utilisez le contr&ocirc;le &laquo; Profondeur de T&eacute;l&eacute;chargement &raquo;  pour limiter le nombre de liens hypertextes &agrave; suivre pour le t&eacute;l&eacute;chargement : utiliser 0 pour t&eacute;l&eacute;charger une seule page ; utiliser 1 pour t&eacute;l&eacute;charger la page et toutes les pages r&eacute;f&eacute;renc&eacute;es par des liens hypertextes. La profondeur limite est ignor&eacute;e lors du t&eacute;l&eacute;chargement de m&eacute;dia autres que des pages html. Ensuite il y a plusieurs cases &agrave; cocher qui peuvent &ecirc;tre coch&eacute;es pour activer l'option sp&eacute;cifi&eacute;e. Une fois la configuration pr&ecirc;te, cliquez &laquo; T&eacute;l&eacute;charger &raquo; pour d&eacute;marrer l'op&eacute;ration de t&eacute;l&eacute;chargement. Il y a deux autres boutons de contr&ocirc;le : &laquo; Pr&eacute;f&eacute;rences &raquo;, qui renvoie &agrave; la section connexion de Pr&eacute;f&eacute;rences ou les param&egrave;tre du proxy peuvent &ecirc;tre &eacute;dit&eacute;s ; et &laquo; Effacer la cache &raquo; qui supprimes tous les fichiers t&eacute;l&eacute;charg&eacute;s pr&eacute;c&eacute;demment.
+      <p></p>
+      La liste de t&eacute;l&eacute;chargement a une entr&eacute;e pour chaque t&eacute;l&eacute;chargement de page Web.  Chaque entr&eacute;e a une r&eacute;gion de textes qui donne les d&eacute;tails de la t&acirc;che avec une barre de progr&egrave;s montrant l'activit&eacute; courante.  Trois boutons apparaissent &agrave; la gauche de chaque entr&eacute;e.  "Pause" est employ&eacute; pour pauser une t&acirc;che en cours de t&eacute;l&eacute;chargement.  "Voir le r&eacute;sum&eacute;" ouvre une fen&ecirc;tre montrant l'historique du t&eacute;l&eacute;chargement.  "Fermer" termine le t&eacute;l&eacute;chargement et enl&egrave;ve la t&acirc;che de la liste.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Instructions advanc&eacute;es:</a>
+<p style="text-align:justify"></p>
+      La <a href="preferences.htm#preferences">section Pr&eacute;f&eacute;rences</a> explique comment &eacute;tablir une connection Internet &agrave; travers un proxy.  Si l'authentification est n&eacute;cessaire, le proxy server demande l'identification et le mot de passe.  L'interface biblioth&eacute;caire n'enregistre pas les mots de passe entre les sessions.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/translatetext.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/translatetext.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/translatetext.htm	(revision 10506)
@@ -0,0 +1,63 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="translatetext"><font size="5" face="Verdana"><strong>6.10: Traduire Texte</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section d&eacute;crit l'Affichage de traduction, o&ugrave; on peut d&eacute;finir des fragments de texte sp&eacute;cifiques &agrave; un langage pour des parties de l'interface de la collection. Sous "Sections de conception", cliquer sur "Traduire Texte".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ajouter traduction
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Enlever traduction
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Mettre &agrave; jour traduction
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Choisir d'abord une entr&eacute;e dans la liste "Caract&eacute;ristiques". Les cha&icirc;nes sp&eacute;cifiques &agrave; un langage associ&eacute;es &agrave; la caract&eacute;ristiques apparaissent en bas. Utiliser la liste d&eacute;roulante de "Traduction de Langage" pour s&eacute;lectionner le langage cible, et saisir le texte traduit dans la zone de texte, en se ref&eacute;rant &agrave; "Fragment de Texte Initial" si n&eacute;cessaire. Cliquez sur "Ajouter Traduction" &agrave; la fin de l'op&eacute;ration. 
+      <p></p>
+      Pour supprimer une traduction existante, s&eacute;lectionner-la &agrave; partir du tableau "Traduction Assign&eacute;e" et cliquer sur "Enlever Traduction". 
+      <p></p>
+      Pour &eacute;diter une traduction, s&eacute;lectionner-la et &eacute;diter-la dans la zone de texte "Texte Traduit", et cliquer sur "Remplacer Traduction". 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/updatingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/updatingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/updatingmetadata.htm	(revision 10506)
@@ -0,0 +1,57 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="updatingmetadata"><font size="5" face="Verdana"><strong>5.5: Mettre &agrave; jour des M&eacute;ta-donn&eacute;es</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Cette section explique la mani&egrave;re de mettre &agrave; jour la m&eacute;ta-donn&eacute;e assign&eacute;e &agrave; un fichier.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Mettre &agrave; jour des fichiers
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Mettre &agrave; jour des dossiers et des fichiers multiples
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      Pour mettre &agrave; jour la valeur d'un &eacute;l&eacute;ment m&eacute;ta-donn&eacute;e, choisir d'abord le fichier auquel la valeur s'applique, et ensuite l'&eacute;l&eacute;ment m&eacute;ta-donn&eacute;e dont on veut changer la valeur. Votre s&eacute;lection appara&icirc;t dans les contr&ocirc;les d'&eacute;dition des m&eacute;ta-donn&eacute;es. Editer le champ valeur et cliquer sur "Remplacer" pour &eacute;craser la m&eacute;ta-donn&eacute;e.
+      <p></p>
+      Le processus est identique pour la mise &agrave; jour d'un dossier avec des sous-dossiers ou plusieurs fichiers, mais vous pouvez seulement mettre &agrave; jour les m&eacute;ta-donn&eacute;es qui sont communes &agrave; tous les fichiers/dossiers s&eacute;lectionn&eacute;s.
+      <p></p>
+      L'arborescence des valeurs montre toutes les valeurs pr&eacute;c&eacute;dentes, mais pas seulement celles d&eacute;sign&eacute;es actuellement. Ainsi la valeur que vous avez remplac&eacute;e restera dans l'arbre de valeur.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/fr/xcollectionsearching.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/fr/xcollectionsearching.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/fr/xcollectionsearching.htm	(revision 10506)
@@ -0,0 +1,49 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="xcollectionsearching"><font size="5" face="Verdana"><strong>6.7: Recherche unique &agrave; travers plusieurs collections</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Greenstone peut rechercher dans plusieurs collections comme si elles n'en constituaient qu'une. Cela se fait par la cr&eacute;ation d'une "super-collection" qui contient les collections individuelles. Sous "Sections de conception", cliquez sur "Recherche unique &agrave; travers plusieurs collections".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">Instructions simples:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            S&eacute;lectionner une collection
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> Instructions simples:</a>
+<p style="text-align:justify"></p>
+      L'Affichage de Recherche unique &agrave; travers des collections montre une liste de collections disponibles. La collection courante est coch&eacute;e et ne peut &ecirc;tre d&eacute;-s&eacute;lectionn&eacute;e. Pour ajouter une autre collection qu'on peut rechercher parall&egrave;lement, cliquer sur une collection dans la liste (cliquer une deuxi&egrave;me fois pour l'enlever). Lorsqu'une seule collection est s&eacute;lectionn&eacute;e, aucune recherche &agrave; travers collections n'est possible.
+      <p></p>
+      Pour plus de d&eacute;tails, voir Chapitre 1 du Guide du D&eacute;veloppeur Greenstone.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/gen-index-xml.xsl
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/gen-index-xml.xsl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/gen-index-xml.xsl	(revision 10506)
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output method="xml" encoding="UTF-8"/>
+
+  <xsl:template match="Document">
+    <Document>
+    <xsl:for-each select="Section">
+      <xsl:call-template name="processSection"/>
+    </xsl:for-each>
+    </Document>
+  </xsl:template>
+
+  <xsl:template name="processSection">
+    <Section name="{@name}">
+      <xsl:for-each select="Title">
+        <Title>
+          <xsl:apply-templates/>
+        </Title>
+      </xsl:for-each>
+
+      <xsl:for-each select="Section">
+        <xsl:call-template name="processSection"/>
+      </xsl:for-each>
+    </Section>
+  </xsl:template>
+</xsl:stylesheet>
Index: /tags/gsdl-2_61-distribution/gli/help/gen-many-html.xsl
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/gen-many-html.xsl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/gen-many-html.xsl	(revision 10506)
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output method="html" encoding="UTF-8"/>
+
+
+  <xsl:template match="Anchor">
+    <p/>
+    <img height="20" src="../gatherer_small.gif" width="20"/>
+    <a name="{@name}"><xsl:text> </xsl:text><xsl:apply-templates/></a>
+    <p style="text-align:justify"/>
+  </xsl:template>
+
+
+  <xsl:template match="Break">
+    <p/>
+  </xsl:template>
+
+
+  <xsl:template match="Contents">
+    <p/>
+    <table align="center" border="2" cellpadding="2" width="480" bgcolor="#B0D0B0">
+      <tr>
+        <td align="center">
+          <font face="Verdana" size="4">
+            <strong>
+              Contents
+            </strong>
+          </font>
+        </td>
+      </tr>
+
+      <tr>
+        <td>
+          <table bgcolor="#FFFFFF" border="0" cellpadding="2" width="100%">
+            <xsl:apply-templates/>
+          </table>
+        </td>
+      </tr>
+    </table>
+    <p/>
+  </xsl:template>
+
+
+  <xsl:template match="ContentsGroup">
+    <tr>
+      <td colspan="3">
+        <a href="#{@linkto}">
+	  <xsl:variable name="linkTo" select="@linkto"/>
+	  <xsl:value-of select="parent::Contents/parent::Section/Anchor[@name=$linkTo]"/>
+	</a>
+      </td>
+    </tr>
+
+    <xsl:apply-templates/>
+  </xsl:template>
+
+
+  <xsl:template match="ContentsItem">
+    <xsl:variable name="depth" select="count(ancestor::ContentsItem) + 1"/>
+    <tr>
+      <td colspan="{$depth}">
+        <xsl:text> </xsl:text>
+      </td>
+      <td colspan="{3 - $depth}">
+        <xsl:apply-templates/>
+      </td>
+    </tr>
+  </xsl:template>
+
+
+  <xsl:template match="Document">
+    <xsl:for-each select="Section">
+      <xsl:call-template name="processSection">
+	<xsl:with-param name="sectionHead" select="position()"/>
+      </xsl:call-template>
+    </xsl:for-each>
+  </xsl:template>
+
+
+  <xsl:template match="Reference">
+    <a href="{@target}.htm#{@target}"><xsl:apply-templates/></a>
+  </xsl:template>
+
+
+  <xsl:template match="Section"/>
+
+
+  <xsl:template match="Title"/>
+
+
+  <xsl:template name="processSection">
+    <xsl:param name="sectionHead"/>
+
+    <html>
+      <head>
+        <title>The Greenstone Librarian Interface - Help Pages</title>
+      </head>
+      <body bgcolor="#E0F0E0">
+        <table border="2" bgcolor="#B0D0B0" cellpadding="5" cellspacing="0" width="100%">
+          <tr>
+            <td align="center" width="15%">
+              <img height="45" src="../gatherer_medium.gif" width="45"/>
+            </td>
+            <td align="center" width="*">
+              <a name="{@name}">
+                <xsl:call-template name="processTitle">
+                  <xsl:with-param name="sectionNumber" select="$sectionHead"/>
+	          <xsl:with-param name="sectionTitle" select="Title"/>
+                </xsl:call-template>
+              </a>	    
+            </td>
+            <td align="center" width="15%">
+              <img height="45" src="../gatherer_medium.gif" width="45"/>
+            </td>
+          </tr>
+        </table>
+
+        <xsl:apply-templates/>
+      </body>
+    </html>
+
+    <xsl:for-each select="Section">
+      <xsl:call-template name="processSection">
+        <xsl:with-param name="sectionHead" select="concat($sectionHead, '.', position())"/>
+      </xsl:call-template>
+    </xsl:for-each>
+  </xsl:template>
+
+
+  <xsl:template name="processTitle">
+    <xsl:param name="sectionNumber"/>
+    <xsl:param name="sectionTitle"/>
+
+    <font face="Verdana" size="5">
+      <strong>
+        <xsl:value-of select="concat($sectionNumber, ': ', $sectionTitle)"/>
+      </strong>
+    </font>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /tags/gsdl-2_61-distribution/gli/help/gen-one-html-for-doc.xsl
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/gen-one-html-for-doc.xsl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/gen-one-html-for-doc.xsl	(revision 10506)
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output method="html" encoding="UTF-8"/>
+
+  <xsl:template match="Anchor"/>
+
+  <xsl:template match="Break">
+    <p/>
+  </xsl:template>
+
+  <xsl:template match="Contents">
+    <p/>
+  </xsl:template>
+
+  <xsl:template match="Document">
+    <html>
+      <head>
+        <title>The Greenstone Librarian Interface - Help Pages</title>
+      </head>
+      <body bgcolor="#E0F0E0">
+	<xsl:for-each select="Section">
+	  <!-- Skip the first section -->
+	  <xsl:if test="position() > 1">
+	    <xsl:call-template name="processSection">
+	      <xsl:with-param name="sectionHead" select="position()"/>
+	    </xsl:call-template>
+          </xsl:if>
+	</xsl:for-each>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template match="ObviousSentence"/>
+
+  <xsl:template match="Reference">
+    <xsl:apply-templates/>
+  </xsl:template>
+
+  <xsl:template match="Section"/>
+
+  <xsl:template match="Title"/>
+
+
+  <xsl:template name="processSection">
+    <xsl:param name="sectionHead"/>
+
+    <xsl:if test="Title">
+        <xsl:call-template name="processTitle">
+          <xsl:with-param name="sectionNumber" select="$sectionHead"/>
+	  <xsl:with-param name="sectionTitle" select="Title"/>
+        </xsl:call-template>
+    </xsl:if>
+
+    <xsl:apply-templates/>
+
+    <xsl:for-each select="Section">
+      <xsl:call-template name="processSection">
+        <xsl:with-param name="sectionHead" select="concat($sectionHead, '.', position())"/>
+      </xsl:call-template>
+    </xsl:for-each>
+  </xsl:template>
+
+
+  <xsl:template name="processTitle">
+    <xsl:param name="sectionNumber"/>
+    <xsl:param name="sectionTitle"/>
+
+    <xsl:choose>
+      <xsl:when test="contains($sectionNumber, '.')">
+        <h4><xsl:value-of select="$sectionTitle"/></h4>
+      </xsl:when>
+      <xsl:otherwise>
+        <h3><xsl:value-of select="$sectionTitle"/></h3>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /tags/gsdl-2_61-distribution/gli/help/gen-one-html.xsl
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/gen-one-html.xsl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/gen-one-html.xsl	(revision 10506)
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output method="html" encoding="UTF-8"/>
+
+  <xsl:template match="Anchor"/>
+
+  <xsl:template match="Break">
+    <p/>
+  </xsl:template>
+
+  <xsl:template match="Contents">
+    <p/>
+  </xsl:template>
+
+  <xsl:template match="Document">
+    <html>
+      <head>
+        <title>The Greenstone Librarian Interface - Help Pages</title>
+      </head>
+      <body bgcolor="#E0F0E0">
+	<xsl:for-each select="Section">
+	  <xsl:call-template name="processSection">
+	    <xsl:with-param name="sectionHead" select="position()"/>
+	  </xsl:call-template>
+	</xsl:for-each>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template match="ObviousSentence"/>
+
+  <xsl:template match="Reference">
+    <a href="#{@target}"><xsl:apply-templates/></a>
+  </xsl:template>
+
+  <xsl:template match="Section"/>
+
+  <xsl:template match="Title"/>
+
+
+  <xsl:template name="processSection">
+    <xsl:param name="sectionHead"/>
+
+    <xsl:if test="Title">
+      <a name="{@name}">
+        <xsl:call-template name="processTitle">
+          <xsl:with-param name="sectionNumber" select="$sectionHead"/>
+	  <xsl:with-param name="sectionTitle" select="Title"/>
+        </xsl:call-template>
+      </a>
+    </xsl:if>
+
+    <xsl:apply-templates/>
+
+    <xsl:for-each select="Section">
+      <xsl:call-template name="processSection">
+        <xsl:with-param name="sectionHead" select="concat($sectionHead, '.', position())"/>
+      </xsl:call-template>
+    </xsl:for-each>
+  </xsl:template>
+
+
+  <xsl:template name="processTitle">
+    <xsl:param name="sectionNumber"/>
+    <xsl:param name="sectionTitle"/>
+
+    <xsl:choose>
+      <xsl:when test="contains($sectionNumber, '.')">
+        <h3>Section <xsl:value-of select="concat($sectionNumber, ': ', $sectionTitle)"/></h3>
+      </xsl:when>
+      <xsl:otherwise>
+        <h1>Section <xsl:value-of select="concat($sectionNumber, ': ', $sectionTitle)"/></h1>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /tags/gsdl-2_61-distribution/gli/help/gen-one-tex.xsl
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/gen-one-tex.xsl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/gen-one-tex.xsl	(revision 10506)
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output method="text" encoding="iso-8859-1"/>
+
+  <xsl:template match="Anchor"/>
+
+  <xsl:template match="Break">
+    <p/>
+  </xsl:template>
+
+  <xsl:template match="Contents">
+    <p/>
+  </xsl:template>
+
+  <xsl:template match="Document-old">
+    <html>
+      <head>
+        <title>The Greenstone Librarian Interface - Help Pages</title>
+      </head>
+      <body bgcolor="#E0F0E0">
+	<xsl:for-each select="Section">
+	  <!-- Skip the first section -->
+	  <xsl:if test="position() > 1">
+	    <xsl:call-template name="processSection">
+	      <xsl:with-param name="sectionHead" select="position()"/>
+	    </xsl:call-template>
+          </xsl:if>
+	</xsl:for-each>
+      </body>
+    </html>
+  </xsl:template>
+  <xsl:template match="Document">
+    % START OF AUTO-GENERATED GLI USER GUIDE
+    <xsl:for-each select="Section">
+      <!-- Skip the first section -->
+      <xsl:if test="position() > 1">
+	<xsl:call-template name="processSection">
+	  <xsl:with-param name="sectionHead" select="position()"/>
+	</xsl:call-template>
+      </xsl:if>
+    </xsl:for-each>
+  </xsl:template>
+  <xsl:template match="ObviousSentence"/>
+
+  <xsl:template match="Reference">
+    <xsl:apply-templates/>
+  </xsl:template>
+
+  <xsl:template match="Section"/>
+
+  <xsl:template match="Title"/>
+
+
+  <xsl:template name="processSection">
+    <xsl:param name="sectionHead"/>
+
+    <xsl:if test="Title">
+        <xsl:call-template name="processTitle">
+          <xsl:with-param name="sectionNumber" select="$sectionHead"/>
+	  <xsl:with-param name="sectionTitle" select="Title"/>
+        </xsl:call-template>
+    </xsl:if>
+
+    <xsl:apply-templates/>
+
+    <xsl:for-each select="Section">
+      <xsl:call-template name="processSection">
+        <xsl:with-param name="sectionHead" select="concat($sectionHead, '.', position())"/>
+      </xsl:call-template>
+    </xsl:for-each>
+  </xsl:template>
+
+
+  <xsl:template name="processTitle">
+    <xsl:param name="sectionNumber"/>
+    <xsl:param name="sectionTitle"/>
+
+    <xsl:choose>
+      <xsl:when test="contains($sectionNumber, '.')">
+        <!--<h4><xsl:value-of select="$sectionTitle"/></h4>-->
+\paragraph{\emph{<xsl:value-of select="$sectionTitle"/>}}<xsl:text>
+	</xsl:text>
+      </xsl:when>
+      <xsl:otherwise>
+        <!--<h3><xsl:value-of select="$sectionTitle"/></h3>-->
+\subsubsection{<xsl:value-of select="$sectionTitle"/>}<xsl:text>
+	</xsl:text>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /tags/gsdl-2_61-distribution/gli/help/gen-text.xsl
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/gen-text.xsl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/gen-text.xsl	(revision 10506)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output method="text" encoding="UTF-8"/>
+
+</xsl:stylesheet>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/addingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/addingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/addingfiles.htm	(revision 10506)
@@ -0,0 +1,90 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="addingfiles"><font size="5" face="Verdana"><strong>4.3: ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÐŸ,ÐºÐ°Ðº Ð²Ð²ÐµÑÑÐž ÑÐ°Ð¹Ð»Ñ Ð² ÐÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐµÑÐµÐŒÐµÑÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐœÐŸÐ¶ÐµÑÑÐ²ÐµÐœÐœÑÐµ(ÑÐŸÑÑÐ°Ð²ÐœÑÐµ) ÑÐ°Ð¹Ð»Ñ
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð¡ÑÑÐµÑÑÐ²ÑÑÑÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð€Ð°Ð¹Ð»Ñ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŒÑÑÑÑ Ð¿ÑÑÐµÐŒ ÐžÑ
+ Ð¿ÐµÑÐµÑÑÐ³ÐžÐ²Ð°ÐœÐžÑ Ðž ÐŸÑÐ¿ÑÑÐºÐ°ÐœÐžÑ. Ð£ÐºÐ°Ð·Ð°ÑÐµÐ»Ñ ÐŒÑÑÐž ÐŸÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÐµÑÑÑ ÐœÐ°ÐŽ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÐŒ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐŒ ÐžÐ»Ðž, ÐµÑÐ»Ðž Ð²ÑÐ±ÐžÑÐ°ÐµÑÑÑ Ð±ÐŸÐ»ÑÑÐµ,ÑÐµÐŒ ÐŸÐŽÐžÐœ,ÐœÐ°ÐŽ ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÐŒÐž. ÐÑÐŸÐ¿ÑÑÑÐžÑÐµ Ð²ÑÐ±ÑÐ°ÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» Ð² ÐÐµÑÐµÐ²ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÑÑÐŸÐ±Ñ Ð·ÐŽÐµÑÑ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÑÑ ÑÐ°Ð¹Ð»Ñ (ÐµÑÐ»Ðž ÐžÑÑÐŸÑÐœÐžÐºÐŸÐŒ Ð±ÑÐ»ÐŸ ÐÐµÑÐµÐ²ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž).
+<p></p>
+  ÐÑÐž ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÐž ÐŒÐœÐŸÐ¶ÐµÑÑÐ²ÐµÐœÐœÑÑ
+(ÑÐŸÑÑÐ°Ð²ÐœÑÑ
+) ÑÐ°Ð¹Ð»ÐŸÐ²,Ð²ÑÐµ ÐŸÐœÐž Ð¿ÐµÑÐµÐŒÐµÑÐ°ÑÑÑÑ Ð² ÑÐµÐ»ÐµÐ²ÑÑ Ð¿Ð°Ð¿ÐºÑ ÐœÐ° ÑÐŸÑ Ð¶Ðµ ÑÐ°ÐŒÑÐ¹ ÑÑÐŸÐ²ÐµÐœÑ,ÐœÐµÐ·Ð°Ð²ÐžÑÐžÐŒÐŸ ÐŸÑ ÑÑÑÑÐºÑÑÑÑ Ð¿Ð°Ð¿ÐºÐž,ÐºÐŸÑÐŸÑÑÑ ÐŸÐœÐž Ð·Ð°ÐœÐžÐŒÐ°Ð»Ðž Ð¿ÐµÑÐ²ÐŸÐœÐ°ÑÐ°Ð»ÑÐœÐŸ. ÐÐŸÐ³ÐŽÐ° ÐÑ ÐºÐŸÐ¿ÐžÑÑÐµÑÐµ Ð²ÑÐŸÑÐŸÐ¹ ÑÐ°Ð¹Ð» Ñ ÑÐµÐŒ Ð¶Ðµ ÑÐ°ÐŒÑÐŒ ÐžÐŒÐµÐœÐµÐŒ Ð² ÑÑ Ð¶Ðµ ÑÐ°ÐŒÑÑ Ð¿Ð°Ð¿ÐºÑ, ÐÐ°Ñ Ð·Ð°Ð¿ÑÐŸÑÑÑ, Ð·Ð°ÑÐµÑÐµÑÑ Ð»Ðž Ð¿ÐµÑÐ²ÑÐ¹. ÐÑÐ²ÐµÑÑÑÐµ "ÐÐµÑ" Ðž ÑÑÐŸÑ ÑÐ°Ð¹Ð» ÐœÐµ Ð±ÑÐŽÐµÑ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÑÑÑÑ,ÐœÐŸ ÐŽÑÑÐ³ÐžÐµ Ð±ÑÐŽÑÑ. Ð§ÑÐŸÐ±Ñ ÐŸÑÐŒÐµÐœÐžÑÑ Ð²ÑÐµ ÐŸÑÑÐ°ÑÑÐžÐµÑÑ ÐŽÐµÐ¹ÑÑÐ²ÐžÑ Ð¿ÐŸ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÐµ "Ð¡ÑÐŸÐ¿".   <p></p>
+ Ð¢ÐŸÐ»ÑÐºÐŸ "ÑÐ°ÐŒÑÐµ Ð²ÑÑÐŸÐºÐžÐµ"ÐžÐ· ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² Ð±ÑÐŽÑÑ Ð¿ÐµÑÐµÐŒÐµÑÐµÐœÑ. ÐÐ°Ð¿ÐºÐ° Ð²ÑÑÐµ, ÑÐµÐŒ ÐµÑ Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐœÑÐµ. ÐÑ ÐœÐµ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ ÑÐ°Ð¹Ð»Ñ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ Ð¿Ð°Ð¿ÐºÐž,Ð° ÑÐ°ÐºÐ¶Ðµ ÑÐ°ÐŒÑ Ð¿Ð°Ð¿ÐºÑ ÐœÐµÐ¿ÐŸÑÑÐµÐŽÑÑÐ²ÐµÐœÐœÐŸ. 
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÐŸÐ³ÐŽÐ° ÐÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÐµ ÑÐ°Ð¹Ð», ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð¿ÑÐŸÐ²ÐŸÐŽÐžÑ Ð¿ÐŸÐžÑÐº Ð² ÐžÑÑ
+ÐŸÐŽÐœÑÑ
+ Ð¿Ð°Ð¿ÐºÐ°Ñ
+ Ð²ÑÐ¿ÐŸÐŒÐŸÐ³Ð°ÑÐµÐ»ÑÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ², ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐžÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ Ðº ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÐŒÐŸÐŒÑ ÑÐ°Ð¹Ð»Ñ,Ðž ÐµÑÐ»Ðž ÐŸÐœ ÐœÐ°Ñ
+ÐŸÐŽÐžÑ ÐµÐ³ÐŸ,ÑÐŸ ÐœÐ°ÑÐžÐœÐ°ÐµÑ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÑÑÐž ÐŽÐ°ÐœÐœÑÐµ. ÐÑÐ»Ðž Ð¿ÑÐŸÑÐµÑÑ Ð¿ÑÐŸÐŽÐŸÐ»Ð¶Ð°ÐµÑÑÑ,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð±ÑÑÑ Ð·Ð°Ð¿ÑÐŸÑÐµÐœÑ (Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÑÐ°Ð·) ÐŸ ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž,ÑÑÐŸÐ±Ñ ÐŽÐŸÑÑÐžÑÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÑ ÐžÐŒÐ¿ÐŸÑÑÐžÑÑÐµÐŒÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ñ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž,ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐœÑÐŒÐž Ð² ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð­ÑÐŸÑ Ð¿ÑÐŸÑÐµÑÑ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÐŒÐœÐŸÐ³ÐžÐµ ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ Ð·Ð°Ð¿ÑÐŸÑÑ, ÐŸÐ¿ÐžÑÐ°ÐœÐœÑÐµ Ð² ÑÐ°Ð·ÐŽÐµÐ»Ðµ<a href="importingpreviouslyassignedmetadata.htm#importingpreviouslyassignedmetadata">ÐÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</a>.ÐÐ»Ñ Ð±ÐŸÐ»ÐµÐµ ÐŽÐµÑÐ°Ð»ÑÐœÐŸÐ³ÐŸ ÐŸÐ±ÑÑÑÐœÐµÐœÐžÑ Ð°ÑÑÐŸÑÐžÐžÑÐŸÐ²Ð°ÐœÐœÑÑ
+ Ñ ÑÐ°Ð¹Ð»Ð°ÐŒÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÑÐžÑÐ°Ð¹ÑÐµ ÐÐ»Ð°Ð²Ñ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone - ÐÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ Ð±ÐŸÐ»ÑÑÐžÐœÑÑÐ²Ð° Ð²Ð°ÑÐžÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ².  
+     </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/addingpreviouslydefinedmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/addingpreviouslydefinedmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/addingpreviouslydefinedmetadata.htm	(revision 10506)
@@ -0,0 +1,60 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="addingpreviouslydefinedmetadata"><font size="5" face="Verdana"><strong>5.4: ÐÐŸÐ±Ð°Ð²Ð»ÐœÐžÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ, ÐºÐ°Ðº ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, ÐºÐŸÑÐŸÑÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ,ÑÐ¶Ðµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐœÑÐµ Ð² ÐŽÐµÑÐµÐ²Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ Ðº Ð¿Ð°Ð¿ÐºÐ°ÐŒ ÐžÐ»Ðž Ðº ÐŒÐœÐŸÐ¶ÐµÑÑÐ²Ñ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ, ÑÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÐ°Ð¹Ð», Ð·Ð°ÑÐµÐŒ ÑÑÐµÐ±ÑÐµÐŒÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐŽÐµÑÐµÐ²Ð° Ð·ÐœÐ°ÑÐµÐœÐžÐ¹, ÑÐ°ÑÑÐžÑÑÑ Ð¿Ð°Ð¿ÐºÐž ÐžÐµÑÐ°ÑÑ
+ÐžÐž Ð¿ÐŸ ÐŒÐµÑÐµ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÑÑÐž. ÐÑÐ±ÑÐ°ÐœÐœÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² Ð¿ÐŸÐ»Ðµ ÑÐµÐºÑÑÐ° (Ð°Ð»ÑÑÐµÑÐœÐ°ÑÐžÐ²ÐœÐŸ ÐŒÐŸÐ¶ÐœÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð°Ð²ÑÐŸÐ²ÑÐ±ÐŸÑ Ð² ÐŽÐµÑÐµÐ²Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ Ðž ÑÑÐµÐŽÑÑÐ² Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐŸÐ³ÐŸ Ð·Ð°Ð²ÐµÑÑÐµÐœÐžÑ). Ð©ÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð² ÐºÐŸÐœÐµÑ",ÑÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðº ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐŒÑ ÑÐ°Ð¹Ð»Ñ.
+<p></p>
+ÐÑÐŸÑÐµÑÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ñ ÑÐ¶Ðµ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐŒÐž Ð·ÐœÐ°ÑÐµÐœÐžÑÐŒÐž Ðº Ð¿Ð°Ð¿ÐºÐ°ÐŒ ÐžÐ»Ðž ÐŒÐœÐŸÐ¶ÐµÑÑÐ²Ñ ÑÐ°Ð¹Ð»ÐŸÐ² ÑÐ°ÐºÐŸÐ¹ Ð¶Ðµ.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/appendingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/appendingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/appendingmetadata.htm	(revision 10506)
@@ -0,0 +1,94 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="appendingmetadata"><font size="5" face="Verdana"><strong>5.3: ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðž ÐžÑ
+ Ð·ÐœÐ°ÑÐµÐœÐžÑ Ðº ÑÐ°Ð¹Ð»Ð°ÐŒ Ðž ÐºÐ°Ðº ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŽÐ»Ñ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐŸÐ¿ÐŸÐ»ÐœÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐ¿ÐŸÐ»ÐœÐµÐœÐžÐµ Ð¿Ð°Ð¿ÐŸÐº ÐžÐ»Ðž ÑÐŸÑÑÐ°Ð²ÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐœÐ°ÑÐµÐœÐžÐµ ÐžÐµÑÐ°ÑÑ
+ÐžÐ¹ Ðž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð¢ÐµÐ¿ÐµÑÑ ÐŒÑ ÐŽÐŸÐ±Ð°Ð²ÐžÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ - Ðž ÑÐ°ÐŒ ÑÐ»ÐµÐŒÐµÐœÑ,Ðž ÐµÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ - Ðº ÑÐ°Ð¹Ð»Ñ. Ð¡ÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐµÐŒ ÑÐ°Ð¹Ð» ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ³ÐŸ ÐŽÐµÑÐµÐ²Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.Ð¢Ð°ÐºÐŸÐµ ÐŽÐµÐ¹ÑÑÐ²ÐžÐµ Ð²ÑÐ·ÑÐ²Ð°ÐµÑ Ð¿ÐŸÑÐ²Ð»ÐµÐœÐžÐµ Ð»ÑÐ±ÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ ÑÐ²ÑÐ·Ð°ÐœÐœÑÑ
+ Ñ ÑÑÐžÐŒ ÑÐ°Ð¹Ð»ÐŸÐŒ,Ð² ÑÐ°Ð±Ð»ÐžÑÐµ ÑÐ¿ÑÐ°Ð²Ð°. 
+<p></p>
+ÐÐ°ÑÐµÐŒ Ð²ÑÐ±ÐµÑÐµÐŒ ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÐºÐŸÑÐŸÑÑÐ¹ Ñ
+ÐŸÑÐžÐŒ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ,Ð¿ÑÑÐµÐŒ ÑÐµÐ»ÑÐºÐ° ÑÑÐŽÐŸÐŒ Ñ ÐœÐžÐŒ Ð² ÑÐ°Ð±Ð»ÐžÑÐµ. 
+ <p></p>
+ ÐÐ¿ÐžÑÐžÑÐµ ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ð² Ð¿ÐŸÐ»Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹. ÐÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ Ð·ÐœÐ°Ðº "|",Ð¿ÐŸÑÐºÐŸÐ»ÑÐºÑ ÐŸÐœ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐžÐµÑÐ°ÑÑ
+ÐžÐ¹. ÐÐŸ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÐž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð² ÐºÐŸÐœÐµÑ",ÑÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð°.Ð­ÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐœÐµÐŒÐµÐŽÐ»ÐµÐœÐœÐŸ Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² ÑÐ°Ð±Ð»ÐžÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.  
+<p></p>
+ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐ°ÐºÐ¶Ðµ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðº Ð¿Ð°Ð¿ÐºÐµ ÐžÐ»Ðž ÑÑÐ°Ð·Ñ Ðº ÐœÐµÐºÐŸÑÐŸÑÐŸÐŒÑ ÐŒÐœÐŸÐ¶ÐµÑÑÐ²Ñ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ². Ð­ÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÑÑ ÐºÐŸ Ð²ÑÐµÐŒ ÑÐ°Ð¹Ð»Ð°ÐŒ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ Ð¿Ð°Ð¿ÐºÐž ÐžÐ»Ðž Ðº ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÐŒ Ðž Ðº Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐœÑÐŒ Ð¿Ð°Ð¿ÐºÐ°ÐŒ. ÐÐŒÐµÐ¹ÑÐµ Ð² Ð²ÐžÐŽÑ,ÑÑÐŸ ÐµÑÐ»Ðž ÐÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÐ»Ðž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðº Ð¿Ð°Ð¿ÐºÐµ, ÑÐŸ Ð»ÑÐ±ÑÐµ ÐœÐŸÐ²ÑÐµ ÑÐ°Ð¹Ð»Ñ Ð² ÐœÐµÐ¹ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž ÑÐœÐ°ÑÐ»ÐµÐŽÑÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐžÐ· ÑÑÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐž.  
+ <p></p>
+ ÐÑÐ»Ðž ÐÑ Ð²ÑÐ±ÐµÑÐžÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ,ÐºÐŸÑÐŸÑÑÐµ ÐžÐŒÐµÑÑÑÑ Ð² ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ ÐžÐ· ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ²,Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð² ÐºÐŸÐœÐµÑ",ÑÐŸ ÐŸÐœÐž ÐŽÐŸÐ±Ð°Ð²Ð»ÑÑÑÑÑ ÑÐ°ÐºÐ¶Ðµ Ðº ÐŽÑÑÐ³ÐžÐŒ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÐŒ ÑÐ°Ð¹Ð»Ð°ÐŒ.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑ Ðº Ð·ÐœÐ°ÑÐµÐœÐžÑÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð¿ÑÑÑ, ÐŸÐ¿ÐžÑÐ°ÐœÐœÑÐ¹ Ð² <a href="theenrichview.htm#theenrichview">Ð Ð°ÑÑÐžÑÐµÐœÐœÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ</a>.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/assignlanguages.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/assignlanguages.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/assignlanguages.htm	(revision 10506)
@@ -0,0 +1,77 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="assignlanguages"><font size="5" face="Verdana"><strong>6.6.3: ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÑÐ·ÑÐºÐž</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŽÐµÑÐ°Ð»ÐžÐ·ÐžÑÐŸÐ²Ð°ÐœÐŸ,ÐºÐ°Ðº ÐŸÐ³ÑÐ°ÐœÐžÑÐžÑÑ ÐžÐœÐŽÐµÐºÑÑ Ð¿ÐŸÐžÑÐºÐ° ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐžÐŒÐž ÑÐ·ÑÐºÐ°ÐŒÐž. ÐÑ ÑÐŸÐ²ÐµÑÑÐ°ÐµÑÐµ ÑÑÐŸ Ð¿ÑÐž ÑÐµÐ³ÐµÐœÐµÑÐžÑÐŸÐ²Ð°ÐœÐžÐž ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÐºÐ»Ð°Ð²ÐžÑÑ "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÑÐ·ÑÐºÐž" Ð² Ð¿ÐµÑÐµÑÐœÐµ "ÐÐœÐŽÐµÐºÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ".
+        <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+          
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+               Ð£Ð¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐ·ÑÐºÐ°ÐŒÐž
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+               ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐ·ÑÐº
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+               Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐ·ÑÐº
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+               Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐ·ÑÐºÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+               ÐÑÐžÑÑÐºÐ° ÑÐ·ÑÐºÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+            </td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+        
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÐ¹ ÑÐ·ÑÐº ÐŽÐ»Ñ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÑÐ·ÑÐºÐž" ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐžÐœÐŽÐµÐºÑÐ° ÐŽÐ»Ñ ÑÑÐŸÐ³ÐŸ. ÐÑÐ±ÐµÑÐžÑÐµ Ð¶ÐµÐ»Ð°ÑÐµÐ»ÑÐœÑÐ¹ ÑÐ·ÑÐº ÐžÐ· ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐ³ÐŸ ÑÐ¿ÐžÑÐºÐ° "Ð¯Ð·ÑÐºÐž ÐŽÐ»Ñ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÑ" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐ·ÑÐº"
+<p></p>
+Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÐ·ÑÐº,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° "ÐÑÐ±ÐŸÑÑ ÑÐ·ÑÐºÐ°" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐ·ÑÐº".
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÑÐ·ÑÐº Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ".
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÐŸÑÐžÑÑÐžÑÑ ÑÐ·ÑÐº Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÑÐžÑÑÐžÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ".
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/assignpartitions.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/assignpartitions.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/assignpartitions.htm	(revision 10506)
@@ -0,0 +1,71 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="assignpartitions"><font size="5" face="Verdana"><strong>6.6.2: ÐÐ°Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐœÐ°Ð·ÐœÐ°ÑÐžÑÑ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÐ¹ ÑÐžÐ»ÑÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ.   
+        <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+          
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+               ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+               ÐÑÐžÑÑÐºÐ° ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+            </td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+        
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÐŒÐµÑ Ð·Ð°ÐŽÐ°ÐœÐœÑÐ¹ ÑÐžÐ»ÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ "ÐÐ°Ð·ÐœÐ°ÑÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ" ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐžÐœÐŽÐµÐºÑÐŸÐ² ÐŽÐ»Ñ ÑÑÐŸÐ³ÐŸ ÐžÐ»Ðž ÐŽÐ»Ñ Ð³ÑÑÐ¿Ð¿Ñ ÑÐžÐ»ÑÑÑÐŸÐ². ÐÑÐ±ÐµÑÐžÑÐµ Ð¶ÐµÐ»Ð°ÑÐµÐ»ÑÐœÑÐ¹ ÑÐžÐ»ÑÑÑ (ÐžÐ»Ðž ÑÐžÐ»ÑÑÑÑ) ÐžÐ· ÑÐ¿ÐžÑÐºÐ° "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÑÐžÐ»ÑÑÑÑ ÑÑÐ±ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž", Ð²Ð²ÐµÐŽÐžÑÐµ ÐžÐŒÑ ÐŽÐ»Ñ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ Ð² Ð¿ÐŸÐ»Ðµ "ÐÐŒÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐµ".
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐµ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐµ".
+<p></p>
+  Ð§ÑÐŸÐ±Ñ Ð¿ÑÐŸÐžÐ·Ð²ÐµÑÑÐž ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÑÑÐ°ÐœÐŸÐ²ÐžÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ".
+<p></p>
+Ð§ÑÐŸÐ±Ñ ÐŸÑÐžÑÑÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÑÐžÑÑÐžÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ".
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/buildsettings.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/buildsettings.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/buildsettings.htm	(revision 10506)
@@ -0,0 +1,65 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="buildsettings"><font size="5" face="Verdana"><strong>7.2: ÐÐŒÐ¿ÐŸÑÑ Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ, ÐºÐ°Ðº Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÑÑÑÐ¿ Ðº ÑÐ°Ð·Ð»ÐžÑÐœÑÐŒ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑÐŒ ÐžÐŒÐ¿ÐŸÑÑÐ° Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°ÐŒ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ. ÐÐ° ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐµÐ¹ Ð¿ÐŸ ÐžÐŒÐ¿ÐŸÑÑÑ Ðž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÑÐžÑÐ°Ð¹ÑÐµ Ð³Ð»Ð°Ð²Ñ 1 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.  
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ±ÑÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐžÐŒÐ¿ÐŸÑÑÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð£Ð¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐ°Ð·Ð»ÐžÑÐœÑÐŒÐž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°ÐŒÐž ÑÐŽÐµÐ»Ð°ÐœÐŸ Ð¿ÐŸÐŽÐŸÐ±ÐœÐŸ ÑÐŸÐŒÑ ÑÐ¿ÐŸÑÐŸÐ±Ñ, ÐºÐŸÑÐŸÑÑÐ¹ ÐŸÐ¿ÐžÑÐ°Ðœ Ð¿ÑÐž "ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐž Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ²" Ð² <a href="plugins.htm#plugins">ÐÐ»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°</a>. ÐÐµÐºÐŸÑÐŸÑÑÐµ Ð¿ÐŸÐ»Ñ ÑÑÐµÐ±ÑÑÑ ÑÐžÑÐ»ÐµÐœÐœÑÑ
+ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ². ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÑ
+ ÐžÐ»Ðž ÐœÐ°Ð¿ÐµÑÐ°ÑÐ°ÑÑ ÐžÐ»Ðž ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÑÑÑÐµÐ»ÐºÐž Ð²Ð²ÐµÑÑ
+ Ðž Ð²ÐœÐžÐ·, ÑÑÐŸÐ±Ñ ÑÐ²ÐµÐ»ÐžÑÐžÑÑ ÐžÐ»Ðž ÑÐŒÐµÐœÑÑÐžÑÑ ÑÐµÐºÑÑÐµÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ (Ð² ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ ÑÐ»ÑÑÐ°ÑÑ
+ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐŸÐ³ÑÐ°ÐœÐžÑÐžÐ²Ð°ÐµÑ ÐŽÐžÐ°Ð¿Ð°Ð·ÐŸÐœ, Ð² ÐºÐŸÑÐŸÑÑÐ¹ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÐŸÐ¹ÑÐž). ÐÑÑÐ³ÐžÐµ Ð¿ÐŸÐ»Ñ ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž Ð¿ÑÐž ÑÐµÐ»ÑÐºÐµ Ð¿ÐŸ ÐºÐœÐŸÐ¿ÐºÐµ (ÐÐŸÐ²ÑÐŸÑÐœÑÐ¹ ÑÐµÐ»ÑÐŸÐº ÐŽÐµÐ»Ð°ÐµÑ ÐžÑ
+ ÐœÐµÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž). 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/classifiers.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/classifiers.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/classifiers.htm	(revision 10506)
@@ -0,0 +1,82 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="classifiers"><font size="5" face="Verdana"><strong>6.8: ÐÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ Ðº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÐºÐŸÑÐŸÑÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ°. Ð "Ð Ð°Ð·ÐŽÐµÐ»Ð°Ñ
+ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÑÐŸÑÐŒÐŸÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ²". 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÑÐ±ÐŸÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° Ðž ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÐŽÐ°Ð»ÐžÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ·ÐŒÐµÐœÐžÑÑ Ð¿ÐŸÑÐ»ÐµÐŽÐŸÐ²Ð°ÑÐµÐ»ÑÐœÐŸÑÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ²
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº "ÐÑÐ±ÐŸÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° ÐŽÐ»Ñ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÑ" Ð²ÐœÐžÐ·Ñ ÐŸÐºÐœÐ°,Ðž Ð·Ð°ÑÐµÐŒ ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐºÐ°Ð·Ð°ÐœÐœÑÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ". ÐÐŸÑÐ²Ð»ÑÐµÑÑÑ ÐŸÐºÐœÐŸ, ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÐŸÐµ "ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ²".ÐÐœÑÑÑÑÐºÑÐžÐž ÐŽÐ»Ñ ÑÑÐŸÐ³ÐŸ ÐŽÐžÐ°Ð»ÐŸÐ³Ð° ÑÐµ Ð¶Ðµ ÑÐ°ÐŒÑÐµ,ÑÑÐŸ ÐºÐ°ÑÐ°ÑÑÑÑ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ² (<a href="plugins.htm#plugins">ÐÐ»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°</a>).ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐÑ ÑÑÐŸÑÐŒÐžÑÐŸÐ²Ð°Ð»Ðž ÐœÐŸÐ²ÑÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ, ÐŸÐœ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÑÑ Ð² ÐºÐŸÐœÐµÑ ÑÐ¿ÐžÑÐºÐ° "Ð¢ÐµÐºÑÑÐžÐµ Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ".  
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ".
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°" (ÐžÐ»Ðž ÑÐµÐ»ÐºÐœÑÑÑ ÐŽÐ²Ð° ÑÐ°Ð·Ð° ÐœÐ° ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐµ Ð² ÑÐ¿ÐžÑÐºÐµ).
+<p></p>
+ ÐÐŸÑÑÐŽÐŸÐº ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ² Ð² ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÐŸÐœÐœÐŸÐ¹ Ð»ÐžÐœÐµÐ¹ÐºÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐž ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ ÑÐŸÐŒÑ,ÐºÐŸÑÐŸÑÑÐ¹ Ð¿ÐŸÐºÐ°Ð·Ð°Ðœ Ð·ÐŽÐµÑÑ.Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð¿ÐŸÑÑÐŽÐŸÐº,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ, ÐºÐŸÑÐŸÑÑÐ¹ ÐÑ Ñ
+ÐŸÑÐžÑÐµ Ð¿ÐµÑÐµÐŒÐµÑÑÐžÑÑ, Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²Ð²ÐµÑÑ
+" ÐžÐ»Ðž "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²ÐœÐžÐ·".
+<p></p>
+ ÐÐ»Ñ ÐŽÐ°Ð»ÑÐœÐµÐ¹ÑÐµÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐŸÑÐœÐŸÑÐžÑÐµÐ»ÑÐœÐŸ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ² ÑÐžÑÐ°Ð¹ÑÐµ Ð³Ð»Ð°Ð²Ñ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/collectingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/collectingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/collectingfiles.htm	(revision 10506)
@@ -0,0 +1,23 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="collectingfiles"><font size="5" face="Verdana"><strong>4: Ð¡Ð±ÐŸÑ ÑÐ°Ð¹Ð»ÐŸÐ² ÐŽÐ»Ñ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+ ÐÑÐ»Ðž ÐÑ ÑÐŸÐ·ÐŽÐ°ÐµÑÐµ ÐœÐŸÐ²ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ,ÑÐŸ Ð²ÐŸÐ·ÐœÐžÐºÐ°ÐµÑ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÑÑÑ Ð²Ð²ÐŸÐŽÐ° Ð² ÐœÐµÐµ ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ².ÐÐœÐž ÐŒÐŸÐ³ÑÑ Ð¿ÐŸÑÑÑÐ¿ÐžÑÑ ÐžÐ· Ð²Ð°ÑÐµÐ³ÐŸ ÐŸÐ±ÑÑÐœÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ³ÐŸ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ð° ÐžÐ· ÐŽÑÑÐ³ÐžÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Greenstone. ÐÐµÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ ÑÐ¶Ðµ ÐžÐŒÐµÑÑ Ð¿ÑÐžÑÐŸÐµÐŽÐžÐœÐµÐœÐœÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ.Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ,ÐºÐ°Ðº ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐ°Ð¹Ð»Ñ.
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/creatingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/creatingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/creatingacollection.htm	(revision 10506)
@@ -0,0 +1,111 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="creatingacollection"><font size="5" face="Verdana"><strong>2.1: Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+       
+       
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ,ÐºÐ°Ðº ÑÐŸÐ·ÐŽÐ°ÑÑ ÐœÐŸÐ²ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÑÑÑÑÐŸÐµ ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐ°Ð³Ð»Ð°Ð²ÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ¿ÐžÑÐ°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÑÐŒÐµÐœÐ° ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÑÑÑÐžÐµ ÐºÐ»Ð°Ð²ÐžÑÐž
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐœÐŸÐ²ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐŸÑÐºÑÐŸÐ¹ÑÐµ ÐŒÐµÐœÑ "File" Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ Ð² ÐœÑÐŒ Ð¿ÑÐœÐºÑ "New". ÐÐµÐºÐŸÑÐŸÑÑÐµ Ð¿ÐŸÐ»Ñ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐŸÐ±ÑÐ·Ð°ÑÐµÐ»ÑÐœÐŸ Ð·Ð°Ð¿ÐŸÐ»ÐœÐµÐœÑ, ÐœÐŸ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð·Ð°ÐŒÐµÐœÐžÑÑ ÐžÑ
+ Ð·ÐœÐ°ÑÐµÐœÐžÑ Ð¿ÐŸÐ·Ð¶Ðµ, ÐµÑÐ»Ðž ÐÑ Ð² ÑÑÐŸÐŒ ÐœÑÐ¶ÐŽÐ°ÐµÑÐµÑÑ Ñ ÑÐŸÑÐºÐž Ð·ÑÐµÐœÐžÑ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°.
+ <p></p>
+ÐÐ°Ð³Ð»Ð°Ð²ÐžÐµ "ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ/Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐŸÐº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž" - ÑÑÐŸ ÑÐµÐºÑÑ, ÑÐ°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐœÑÐ¹ ÐœÐ°Ð²ÐµÑÑ
+Ñ ÐŽÐŸÐŒÐ°ÑÐœÐµÐ¹ ÑÑÑÐ°ÐœÐžÑÑ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐœÐŸ ÐŒÐŸÐ¶ÐµÑ ÐžÐŒÐµÑÑ Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐ»ÑÐœÑÑ ÐŽÐ»ÐžÐœÑ.
+<p></p>
+"ÐÐ¿ÐžÑÐ°ÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ" ÐŽÐŸÐ»Ð¶ÐœÐŸ Ð¿ÑÐµÐŽÑÑÐ°Ð²ÐžÑÑ ÐºÐ°Ðº ÐŒÐŸÐ¶ÐœÐŸ ÐŽÐµÑÐ°Ð»ÑÐœÐµÐµ ÑÐŸ,ÐŸ ÑÑÐŒ ÑÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ [Enter] ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ,ÑÑÐŸÐ±Ñ ÑÐ°Ð·Ð±ÐžÑÑ ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ ÐœÐ° Ð¿Ð°ÑÐ°Ð³ÑÐ°ÑÑ.
+<p></p>
+ ÐÐ°ÐºÐŸÐœÐµÑ ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ, ÐŽÐŸÐ»Ð¶ÐœÐ° Ð»Ðž ÐœÐŸÐ²Ð°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐŒÐµÑÑ ÑÐŸÑ Ð¶Ðµ ÑÐ°ÐŒÑÐ¹ Ð²ÐžÐŽ Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÑÑÐŸ Ðž ÑÑÑÐµÑÑÐ²ÑÑÑÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐžÐ»Ðž Ð¶Ðµ ÐœÐ°ÑÐ°ÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ "ÐÐŸÐ²ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ".
+<p></p>
+Ð©ÐµÐ»ÐºÐœÐžÑÐµ "OK", ÑÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ. ÐÑÐ»Ðž ÐÑ Ð²ÑÐ±ÑÐ°Ð»Ðž "New Collection", ÑÐŸ ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð²Ð²ÐµÑÑÐž ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÑÑÐŸÐ±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐžÑ
+ Ð² ÑÑÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ Ð±ÐŸÐ»ÑÑÐµ,ÑÐµÐŒ ÐŸÐŽÐœÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ, Ð° ÐŒÐŸÐ¶ÐµÑÐµ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŽÑÑÐ³ÐžÐµ Ð¿ÐŸÐ·Ð¶Ðµ. 
+<p></p>
+ÐÐ°Ð¶Ð°ÑÐžÐµ ÐºÐ»Ð°Ð²ÐžÑÐž "Cancel" ÐœÐµÐŒÐµÐŽÐ»ÐµÐœÐœÐŸ Ð²ÐŸÐ·Ð²ÑÐ°ÑÐ°ÐµÑ ÐÐ°Ñ Ðº Ð³Ð»Ð°Ð²ÐœÐŸÐŒÑ ÑÐºÑÐ°ÐœÑ. 
+    <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÐœÐŸÐ¿ÐºÐž, ÑÐžÐ¿Ð° ÐŒÐµÐœÑ, ÐžÐŒÐµÑÑ ÐŸÐŽÐžÐœ Ð¿ÐŸÐŽÑÑÑÐºÐœÑÑÑÐ¹ ÑÐžÐŒÐ²ÐŸÐ». Ð§ÑÐŸÐ±Ñ Ð²ÑÐ·Ð²Ð°ÑÑ ÐºÐœÐŸÐ¿ÐºÑ ÐœÐ°Ð¶ÐŒÐžÑÐµ [ALT] Ðž ÐŸÐŽÐœÐŸÐ²ÑÐµÐŒÐµÐœÐœÐŸ Ð¿ÐŸÐŽÑÐµÑÐºÐœÑÑÑÐ¹ ÑÐžÐŒÐ²ÐŸÐ». 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/creatingfolders.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/creatingfolders.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/creatingfolders.htm	(revision 10506)
@@ -0,0 +1,61 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="creatingfolders"><font size="5" face="Verdana"><strong>4.2: Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿Ð°Ð¿ÐŸÐº</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ, ÐºÐ°Ðº ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÑÑ ÐœÐŸÐ²ÑÐµ Ð¿Ð°Ð¿ÐºÐž
+
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐœÐŸÐ¿ÐºÐ° ÐœÐŸÐ²ÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐž
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐµÐœÑ Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐž ÐŒÑÑÐž
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ "ÐÐ°Ð¿ÐºÐž" Ð² ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐŒ ÐŽÐµÑÐµÐ²Ðµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÑÑÐŸÐ±Ñ Ð³ÑÑÐ¿Ð¿ÐžÑÐŸÐ²Ð°ÑÑ Ð²ÐŒÐµÑÑÐµ Ðž Ð±ÐŸÐ»ÐµÐµ Ð»ÐµÐ³ÐºÐŸ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑ ÐžÑ
+. ÐÐ°Ð¿ÐºÐž ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ Ð¿ÐŸÐŒÐµÑÐµÐœÑ Ð²ÐœÑÑÑÐž Ð¿Ð°Ð¿ÐŸÐº. Ð€Ð°ÐºÑÐžÑÐµÑÐºÐž ÐœÐµÑ ÐŸÐ³ÑÐ°ÐœÐžÑÐµÐœÐžÑ ÐœÐ° ÑÐŸ,ÑÐºÐŸÐ»ÑÐºÐŸ Ð¿Ð°Ð¿ÐŸÐº ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÐŒÐµÑÑ ÐžÐ»Ðž ÐºÐ°Ðº Ð³Ð»ÑÐ±ÐŸÐºÐŸ ÐŸÐœÐž ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ Ð²Ð»ÐŸÐ¶ÐµÐœÑ.
+<p></p>
+  Ð§ÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐœÐŸÐ²ÑÑ Ð¿Ð°Ð¿ÐºÑ, Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐ»ÑÐœÐŸ Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÑÑ Ð¿Ð°Ð¿ÐºÑ Ð² ÐÐµÑÐµÐ²Ðµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÐµ "ÐÐŸÐ²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°". ÐÐŸÐ²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ ÐžÐ»Ðž ÐœÐ° Ð²ÑÑÑÐµÐŒ ÑÑÐŸÐ²ÐœÐµ,ÐµÑÐ»Ðž ÐœÐž ÐŸÐŽÐœÐ° ÐœÐµ ÐŸÑÐŸÐ±ÑÐ°ÐœÐ°.ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÑÐŸÑÐ²ÐŸÐžÑÑ Ð¿Ð°Ð¿ÐºÐµ ÐžÐŒÑ (Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ "ÐÐŸÐ²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°").
+<p></p>
+ ÐÐ°Ð¿ÐºÐž ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐ°ÐºÐ¶Ðµ ÑÐŸÐ·ÐŽÐ°ÐœÑ ÑÐµÐ»ÑÐºÐŸÐŒ Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐž ÐŒÑÑÐž Ð¿ÐŸ Ð¿Ð°Ð¿ÐºÐµ,Ð²ÑÐ±ÐžÑÐ°Ñ "ÐÐŸÐ²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°" Ðž ÐŽÐµÐ¹ÑÑÐ²ÑÑ,ÐºÐ°Ðº ÑÐºÐ°Ð·Ð·Ð°ÐœÐŸ Ð²ÑÑÐµ.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/definefilters.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/definefilters.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/definefilters.htm	(revision 10506)
@@ -0,0 +1,69 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="definefilters"><font size="5" face="Verdana"><strong>6.6.1: ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐžÐ»ÑÑÑÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+        
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐžÐ»ÑÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ.
+        <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+          
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+               ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐžÐ»ÑÑÑ
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+               Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐžÐ»ÑÑÑ
+            </td>
+</tr>
+            
+<tr>
+<td colspan="1"> </td><td colspan="2">
+               ÐÐ·ÐŒÐµÐœÐžÑÑ ÑÐžÐ»ÑÑÑ
+            </td>
+</tr>
+          
+        
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+        
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð€ÐžÐ»ÑÑÑÑ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÑÑ ÐÐ°ÐŒ Ð³ÑÑÐ¿Ð¿ÐžÑÐŸÐ²Ð°ÑÑ Ð² Ð¿ÐŸÐŽÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð²ÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ð¿ÐŸ  ÐžÐœÐŽÐµÐºÑÑ,ÐŽÐ»Ñ ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ Ð·Ð°ÐŽÐ°ÐœÐœÐŸÐ¹ ÐŒÐŸÐŽÐµÐ»Ðž.
+ <p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÑÐžÐ»ÑÑÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ "ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐžÐ»ÑÑÑÑ" Ðž Ð²Ð²ÐµÐŽÐžÑÐµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐŽÐ»Ñ ÐœÐŸÐ²ÐŸÐ³ÐŸ ÑÐžÐ»ÑÑÑÐ° Ð² Ð¿ÐŸÐ»Ðµ "ÐÐŒÑ ÑÐžÐ»ÑÑÑÐ° ÑÑÐ±ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž".ÐÐ°ÑÐµÐŒ Ð²ÑÐ±ÐµÑÐžÑÐµ Ñ
+Ð°ÑÐ°ÐºÑÐµÑÐœÑÐµ Ð¿ÑÐžÐ·ÐœÐ°ÐºÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐžÐµ ÐžÐ»Ðž ÑÐ»ÐµÐŒÐµÐœÑÐ°ÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÐžÐ»Ðž ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ ÑÐ°ÑÑÐŒÐ°ÑÑÐžÐ²Ð°ÐµÐŒÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð°.ÐÐ²ÐµÐŽÐžÑÐµ Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ,ÑÑÐŸÐ±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð² ÑÐµÑÐµÐœÐžÐµ ÐŽÐµÐ¹ÑÑÐ²ÐžÑ ÑÑÐŸÐ³ÐŸ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÑ.ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐµÑÐµÐºÐ»ÑÑÐ°ÑÑ "ÐÐºÐ»ÑÑÐµÐœÐžÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²", ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑ ÑÐžÐ»ÑÑÑÑ, ÐžÐ»Ðž "ÐÑÐºÐ»ÑÑÐµÐœÐžÐµ" ÐžÑ
+.ÐÐ°ÐºÐŸÐœÐµÑ,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ Ð»ÑÐ±ÐŸÐ¹ ÑÑÐ°ÐœÐŽÐ°ÑÑ PERL, Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÑÐµ ÑÐ»Ð°Ð³Ðž Ð²ÑÑÐ°Ð¶ÐµÐœÐžÑ,ÑÑÐŸÐ±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð¿ÑÐž ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÐž (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ("i" ÐŽÐ»Ñ ÑÐ»ÑÑÐ°Ñ ÐœÐµÑÑÐ²ÑÑÐ²ÐžÑÐµÐ»ÑÐœÐŸÐ³ÐŸ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÑ),ÐÐ°ÐºÐŸÐœÐµÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐžÐ»ÑÑÑ",ÑÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐžÐ»ÑÑÑ Ðº ÑÐ¿ÐžÑÐºÑ "Ð€ÐžÐ»ÑÑÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÑÑÐ±ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹".
+ <p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÐžÐ»ÑÑÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐžÐ»ÑÑÑ". 
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÑÐžÐ»ÑÑÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ°,Ð·Ð°ÐŒÐµÐœÐžÑÐµ Ð»ÑÐ±ÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ, ÐºÐŸÑÐŸÑÐŸÐµ Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµÐŒ Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ ÑÐžÐ»ÑÑÑ",ÑÑÐŸÐ±Ñ Ð·Ð°ÐºÑÐµÐ¿ÐžÑÑ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ.
+      </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/deletingcollections.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/deletingcollections.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/deletingcollections.htm	(revision 10506)
@@ -0,0 +1,48 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="deletingcollections"><font size="5" face="Verdana"><strong>2.4: Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÑÐ°ÑÑÐºÐ°Ð·Ð°ÐœÐŸ, ÐºÐ°Ðº ÐœÐµÐžÐ·ÐŒÐµÐœÐœÐŸ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐ· ÐžÐœÑÑÐ°Ð»ÑÑÐžÐŸÐœÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž Greenstone.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐ°Ðº ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+      ÐÐ»Ñ ÑÐŸÐ³ÐŸ, ÑÑÐŸÐ±Ñ ÐœÐµÐžÐ·ÐŒÐµÐœÐœÐŸ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐ· ÐžÐœÑÑÐ°Ð»ÑÑÐžÐŸÐœÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž Greenstone, Ð²ÑÐ±ÐµÑÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ..." ÐžÐ· ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»". ÐÑÐºÑÐŸÐµÑÑÑ ÑÐ¿ÐžÑÐŸÐº Ð²ÑÐµÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Greenstone. ÐÑÐ±ÐµÑÐžÑÐµ ÐœÑÐ¶ÐœÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÐ° ÐµÐµ ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ, Ð¿ÐŸÑÐ»Ðµ ÑÑÐŸÐ³ÐŸ Ð¿ÐŸÑÑÐ°Ð²ÑÐµ Ð³Ð°Ð»ÐŸÑÐºÑ Ð² Ð¿ÑÐœÐºÑÐµ Ð²ÐœÐžÐ·Ñ ÐŽÐžÐ°Ð»ÐŸÐ³Ð° Ðž ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° "Ð£ÐŽÐ°Ð»ÐžÑÑ", ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ. Ð­ÑÐ° ÐŸÐ¿ÐµÑÐ°ÑÐžÑ Ð±ÐµÐ·Ð²ÐŸÐ·Ð²ÑÐ°ÑÐœÐ°, Ð¿ÐŸÑÑÐŸÐŒÑ Ð¿ÑÐŸÐ²ÐµÑÑÑÐµ Ð²ÐœÐžÐŒÐ°ÑÐµÐ»ÑÐœÐŸ, ÐŽÐµÐ¹ÑÑÐ²ÐžÑÐµÐ»ÑÐœÐŸ Ð»Ðž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµÐœÑÐ¶ÐœÐ°!
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/designingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/designingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/designingacollection.htm	(revision 10506)
@@ -0,0 +1,26 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="designingacollection"><font size="5" face="Verdana"><strong>6: ÐÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+ ÐÐŸÐ³ÐŽÐ° ÐÐ°ÑÐž ÑÐ°Ð¹Ð»Ñ ÑÐœÐ°Ð±Ð¶ÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž,ÐŽÐ°Ð»ÐµÐµ ÐÑ ÑÐµÑÐ°ÐµÑÐµ,Ð² ÐºÐ°ÐºÐŸÐŒ Ð²ÐžÐŽÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Greenstone ÐŽÐŸÐ»Ð¶ÐœÐ° Ð±ÑÑÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐ° Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÑÐŒ.ÐÐ°ÐºÐŸÐ³ÐŸ Ð²ÐžÐŽÐ° ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŽÐŸÑÑÑÐ¿ÐœÐ° ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°? ÐÐ°ÐºÐžÐµ Ð¿ÑÑÐž Ð¿ÑÐµÐŽÑÑÐŒÐŸÑÑÐµÐœÑ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°? ÐÐ°ÐºÐžÐµ ÑÐ·ÑÐºÐž Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑÑÑ? ÐÐŽÐµ ÑÐ°Ð·ÐŒÐµÑÑÐžÑÑ ÐºÐœÐŸÐ¿ÐºÐž ÐœÐ° ÑÑÑÐ°ÐœÐžÑÐµ? Ð­ÑÐž Ð²ÐµÑÐž ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐœÐ°ÑÑÑÐŸÐµÐœÑ;Ð² ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ,ÐºÐ°Ðº ÑÑÐŸ ÑÐŽÐµÐ»Ð°ÑÑ.
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/downloadingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/downloadingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/downloadingfiles.htm	(revision 10506)
@@ -0,0 +1,16 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="downloadingfiles"><font size="5" face="Verdana"><strong>3: ÐÐ°Ð³ÑÑÐ·ÐžÑÑ ÑÐ°Ð¹Ð»Ñ ÐžÐ· ÐžÐœÑÐµÑÐœÐµÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    ÐÐžÐŽ "ÐÐµÑÐºÐ°Ð»ÐŸ" Ð¿ÐŸÐŒÐŸÐ¶ÐµÑ Ð²Ð°ÐŒ Ð·Ð°Ð³ÑÑÐ·ÐžÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐžÐ· ÐÐœÑÐµÑÐœÐµÑÐ°. ÐÐ°ÐœÐœÐ°Ñ ÑÐµÐºÑÐžÑ ÐŸÐ±ÑÑÑÐœÑÐµÑ Ð¿ÑÐŸÑÐµÑÑ Ð·ÐµÑÐºÐ°Ð»ÐžÑÐŸÐ²Ð°ÐœÐžÑ Ð² ÐÐœÑÐµÑÑÐµÐ¹ÑÐµ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°ÑÑ.
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/enrichingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/enrichingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/enrichingacollection.htm	(revision 10506)
@@ -0,0 +1,28 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="enrichingacollection"><font size="5" face="Verdana"><strong>5: ÐÐ±ÐŸÐ³Ð°ÑÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+ ÐÐŒÐµÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÐœÐ°ÐºÐŸÐ¿Ð»ÐµÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,ÐœÐ°Ð¿ÐŸÐ»ÐœÐžÑÐµ ÐžÑ
+ ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐµÐ¹,ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÐŸÐ¹ "ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ".Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ, ÐºÐ°Ðº ÑÐŸÐ·ÐŽÐ°ÑÑÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ,ÐºÐ°Ðº ÐŸÐœÐž ÑÐµÐŽÐ°ÐºÑÐžÑÑÑÑÑÑ, ÐœÐ°Ð·ÐœÐ°ÑÐ°ÑÑÑÑ Ðž Ð²ÐŸÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÑÑÑÑ,Ð° ÑÐ°ÐºÐ¶Ðµ ÐºÐ°Ðº ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ Ð²ÐœÐµÑÐœÐžÐµ ÐžÑÑÐŸÑÐœÐžÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+    
+ (ÑÐ°ÐºÐ¶Ðµ ÑÐŒ.ÐÐ»Ð°Ð²Ñ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone - ÐÐŸÐ»ÑÑÐµÐœÐžÐµ Ð±ÐŸÐ»ÑÑÐµÐ¹ ÑÐ°ÑÑÐž ÐžÐ· Ð²Ð°ÑÐžÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²). 
+    
+    
+    
+    
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/exportingcollections.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/exportingcollections.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/exportingcollections.htm	(revision 10506)
@@ -0,0 +1,53 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="exportingcollections"><font size="5" face="Verdana"><strong>8.3: Ð­ÐºÑÐ¿ÐŸÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÐœÐ° CD-ROM</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      
+Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑ, ÐºÐ°Ðº ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð² ÑÐ°ÐŒÐŸÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÑÑÐžÐ¹ÑÑ CD-ROM Greenstone. 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐ°Ðº ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+Greenstone ÐŒÐŸÐ¶ÐµÑ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐŸÐŽÐœÑ ÐžÐ»Ðž Ð±ÐŸÐ»ÐµÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Ð² ÑÐ°ÐŒÐŸÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÑÑÐžÐ¹ÑÑ CD-ROM Ð¿ÐŸÐŽ Windows. Ð§ÑÐŸÐ±Ñ ÑÑÐŸ ÑÐŽÐµÐ»Ð°ÑÑ, ÐŽÐŸÐ»Ð¶ÐµÐœ  Ð±ÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ Ð¿Ð°ÐºÐµÑ "Ð­ÐºÑÐ¿ÐŸÑÑ Ð² CD-ROM". ÐÐœ ÐœÐµ Ð²ÐºÐ»ÑÑÐµÐœ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ, Ð¿ÐŸÑÑÐŸÐŒÑ ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐÐ°ÑÑ ÐžÐœÑÑÐ°Ð»Ð»ÑÑÐžÑ, ÑÑÐŸÐ±Ñ ÐµÐ³ÐŸ Ð²ÐºÐ»ÑÑÐžÑÑ.
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐŸÑÐºÑÐŸÐ¹ÑÐµ ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»" Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ "Ð­ÐºÑÐ¿ÐŸÑÑ Ð² CD-ROM". ÐÐŸÑÐ²Ð»ÑÐµÑÑÑ ÑÐ¿ÐžÑÐŸÐº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÑÐŸÐ±ÑÐ°ÐœÐžÐ¹ Greenstone; ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° Ð»ÑÐ±ÐŸÐ¹, ÑÑÐŸÐ±Ñ ÑÐ²ÐžÐŽÐµÑÑ ÐµÐµ ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ. ÐÐŸÐŒÐµÑÑÑÐµ Ð²ÑÐ±ÑÐ°ÐœÐœÑÐµ Ð¿ÐŸÐ»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÐŽÐ»Ñ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²Ð²ÐµÑÑÐž ÐžÐŒÑ CD-ROM Ð² Ð¿ÐŸÐ»Ðµ: ÑÑÐŸ ÑÐŸ, ÑÑÐŸ Ð¿ÐŸÑÐ²ÐžÑÑÑ Ð² ÑÑÐ°ÑÑÐŸÐ²ÐŸÐŒ ÐŒÐµÐœÑ, ÐºÐŸÐ³ÐŽÐ° CD-ROM Ð±ÑÐŽÐµÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ. ÐÐ°ÑÐµÐŒ ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð­ÐºÑÐ¿ÐŸÑÑ". ÐÑÐŸÑÐµÑÑ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐŒÐœÐŸÐ³ÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² Ðž ÐŒÐŸÐ¶ÐµÑ Ð·Ð°ÐœÑÑÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÐŒÐžÐœÑÑ.
+<p></p>
+ ÐÐŸÑÐ»Ðµ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÑ Greenstone Ð¿ÐŸÐºÐ°Ð¶ÐµÑ ÐžÐŒÑ Ð¿Ð°Ð¿ÐºÐž, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐµÐ¹ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ Ð¿ÐžÑÑÑÐžÐ¹ ÐºÐŸÐŒÐ¿Ð°ÐºÑ-ÐŽÐžÑÐº ÐŽÐ»Ñ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÑ ÐµÐ³ÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÐœÐ° ÑÐžÑÑÑÐ¹ CD-ROM.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/fileassociations.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/fileassociations.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/fileassociations.htm	(revision 10506)
@@ -0,0 +1,68 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="fileassociations"><font size="5" face="Verdana"><strong>8.2: ÐÑÑÐŸÑÐžÐ°ÑÐžÐž ÑÐ°Ð¹Ð»Ð°</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐÐœÑÐµÑÑÐµÐ¹Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐžÐµ Ð¿ÑÐžÐºÐ»Ð°ÐŽÐœÑÐµ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ, ÑÑÐŸÐ±Ñ ÐŸÑÐºÑÑÐ²Ð°ÑÑ ÑÐ¿ÐµÑÐžÑÐžÑÐœÑÐµ ÑÐžÐ¿Ñ ÑÐ°Ð¹Ð»ÐŸÐ². Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» ÐŸÐ±ÑÑÑÐœÑÐµÑ, ÐºÐ°Ðº ÐœÐ°Ð·ÐœÐ°ÑÐ°ÑÑ Ðž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÑÑÐž ÑÐ²ÑÐ·Ð°ÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÐž
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð ÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÐž
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÐŽÐ°Ð»ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÐž
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+  Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð°ÑÑÐŸÑÐžÐžÑÐŸÐ²Ð°ÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ ÐŸÑÐºÑÑÐ²Ð°ÑÑ ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»" Ðž ÑÐµÐ»ÐºÐ°ÑÑ "ÐÑÑÐŸÑÐžÐžÑÐŸÐ²Ð°ÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ".
+<p></p>
+Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÐž, Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÐµÐ»ÐµÐ²ÐŸÐµ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð° ÐžÐ· ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐ³ÐŸ ÑÐ¿ÐžÑÐºÐ° ÐžÐ»Ðž ÐœÐ°Ð¿ÐžÑÐžÑÐµ ÐœÐŸÐ²ÐŸÐµ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ (ÐœÐµ Ð²ÐºÐ»ÑÑÐ°Ñ "."). ÐÐ°ÑÐµÐŒ ÐžÐ»Ðž ÐœÐ°Ð¿ÐžÑÐžÑÐµ Ð² ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐŒ Ð¿ÐŸÐ»Ðµ ÐºÐŸÐŒÐ°ÐœÐŽÑ,Ð·Ð°Ð¿ÑÑÐºÐ°ÑÑÑÑ Ð¶ÐµÐ»Ð°ÑÐµÐ»ÑÐœÐŸÐµ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÐµ,ÐžÐ»Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÐµ ÐžÐ· ÐŽÐžÐ°Ð»ÐŸÐ³ÐŸÐ²ÐŸÐ³ÐŸ ÐŸÐºÐœÐ° "ÐÑÐŸÑÐŒÐŸÑÑ". ".%1" ÐŒÐŸÐ¶ÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ Ð² ÐºÐŸÐŒÐ°ÐœÐŽÐµ Ð·Ð°Ð¿ÑÑÐºÐ°, ÑÑÐŸÐ±Ñ Ð²ÑÑÐ°Ð²ÐžÑÑ ÐžÐŒÑ ÑÐ°Ð¹Ð»Ð°, ÐºÐŸÑÐŸÑÑÐ¹ ÐŽÐŸÐ»Ð¶ÐµÐœ ÐŸÑÐºÑÑÑÑÑÑ. ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐŸÐœÐž Ð·Ð°Ð¿ÐŸÐ»ÐœÐµÐœÑ,Ð¿ÑÐœÐºÑ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÐž" ÑÑÐ°ÐœÐŸÐ²ÐžÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒ Ðž ÐŒÐŸÐ¶ÐœÐŸ ÑÐµÐ»ÑÐºÐŸÐŒ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÑ.  
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐµ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð°. ÐÑÐ±Ð°Ñ ÑÑÑÐµÑÑÐ²ÑÑÑÐ°Ñ ÐºÐŸÐŒÐ°ÐœÐŽÐ° ÑÐ²ÑÐ·Ðž Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑÑÑ Ð² Ð¿ÐŸÐ»Ðµ Ð·Ð°Ð¿ÑÑÐºÐ° ÐºÐŸÐŒÐ°ÐœÐŽ. ÐÑÑÐµÐŽÐ°ÐºÑÐžÑÑÐ¹ÑÐµ ÐµÐµ Ðž Ð·Ð°ÑÐµÐŒ ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÑ".
+ <p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐµ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÑ".(Ð Ð°ÑÑÐžÑÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð° ÐŸÑÑÐ°ÐµÑÑÑ Ð² ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐŒ ÑÐ¿ÐžÑÐºÐµ "ÐÐ»Ñ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÑ ÑÐ°Ð¹Ð»ÐŸÐ²").
+ <p></p>
+ ÐÑÐŸÑÐžÐ°ÑÐžÐ²ÐœÑÐµ ÑÐ°Ð¹Ð»Ñ Ñ
+ÑÐ°ÐœÑÑÑÑ Ð² Ð³Ð»Ð°Ð²ÐœÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐµ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°, Ð² ÑÐ°Ð¹Ð»Ðµ, ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÐŸÐŒ "associations.xml".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/filteringthetree.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/filteringthetree.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/filteringthetree.htm	(revision 10506)
@@ -0,0 +1,65 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="filteringthetree"><font size="5" face="Verdana"><strong>4.5: Ð€ÐžÐ»ÑÑÑÐŸÐ²Ð°ÐœÐžÐµ ÐŽÐµÑÐµÐ²Ð°</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+"Ð€ÐžÐ»ÑÑÑÐŸÐ²Ð°ÐœÐžÐµ" ÐŽÐµÑÐµÐ²Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐÐ°ÐŒ ÑÑÐ¶Ð°ÑÑ Ð¿ÐŸÐžÑÐº ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ².
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ð£Ð¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐžÐ»ÑÑÑÐŸÐŒ
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+              ÐÐ°ÑÑÑÐŸÐ¹ÐºÐ° ÑÐžÐ»ÑÑÑÐ°
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ÐÑÐœÐºÑ "ÐÐŸÐºÐ°Ð·Ð°ÑÑ ÑÐ°Ð¹Ð»Ñ" Ð² ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐŒ ÐŒÐµÐœÑ Ð¿ÐŸÐŽ ÐºÐ°Ð¶ÐŽÑÐŒ ÐŽÐµÑÐµÐ²ÐŸÐŒ Ð²ÑÐ²ÐŸÐŽÐžÑ ÑÐ¿ÐžÑÐŸÐº Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÑÑ
+ ÑÐžÐ»ÑÑÑÐŸÐ² ÑÐžÐ¿Ð° "Images".ÐÑÐ±ÐµÑÐžÑÐµ Ðž Ð²ÑÐµ Ð²ÑÐµÐŒÐµÐœÐœÐŸ ÑÐºÑÑÑÑÐµ ÑÐ°Ð¹Ð»Ñ Ð² ÐŽÐµÑÐµÐ²Ðµ.Ð§ÑÐŸÐ±Ñ Ð²ÐŸÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐŽÐµÑÐµÐ²ÐŸ,Ð·Ð°ÐŒÐµÐœÐžÑÐµ ÑÐžÐ»ÑÑÑ ÑÐœÐŸÐ²Ð° ÐœÐ° "ÐÑÐµ ÑÐ°Ð¹Ð»Ñ".Ð­ÑÐž ÐŽÐµÐ¹ÑÑÐ²ÐžÑ ÐœÐµ ÐžÐ·ÐŒÐµÐœÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž Ð¿ÑÐž ÑÑÐŸÐŒ ÐŸÐœÐž ÐœÐµ Ð·Ð°ÑÑÐ°Ð³ÐžÐ²Ð°ÑÑ Ð¿Ð°Ð¿ÐºÐž Ð² ÐŽÐµÑÐµÐ²Ðµ. 
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð·Ð°ÐŽÐ°ÑÑ ÐœÐ°ÑÑÑÐŸÐ¹ÐºÑ ÑÐžÐ»ÑÑÑÐ°,ÐœÐ°Ð¿ÐµÑÐ°ÑÐ°Ð² Ð² ÑÑ
+ÐµÐŒÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ².ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÑÑÐ°ÐœÐŽÐ°ÑÑÐœÑÐµ Ð°Ð±Ð±ÑÐµÐ²ÐžÐ°ÑÑÑÑ ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ¹ ÑÐžÑÑÐµÐŒÑ ÑÐžÐ¿Ð° "*.*" ÐžÐ»Ðž "*.doc" ("*" ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ Ð»ÑÐ±ÑÐŒ ÑÐžÐŒÐ²ÐŸÐ»Ð°ÐŒ). 
+     </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/formatstatements.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/formatstatements.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/formatstatements.htm	(revision 10506)
@@ -0,0 +1,98 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="formatstatements"><font size="5" face="Verdana"><strong>6.9: ÐÑÐŸÐ±ÐµÐœÐœÐŸÑÑÐž ÑÐŸÑÐŒÐ°ÑÐ°</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ ÐÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ° ÑÐ¿ÑÐ°Ð²Ð»ÑÑÑ ÑÑÑÑÐºÑÑÑÐŸÐ¹ Ðž Ð²ÐžÐŽÐŸÐŒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐœÐž Ð·Ð°ÑÑÐ°Ð³ÐžÐ²Ð°ÑÑ ÑÐ°ÐºÐžÐµ Ð²ÐµÑÐž,ÐºÐ°Ðº ÐŒÐµÑÑÐŸ Ð¿ÐŸÑÐ²Ð»ÐµÐœÐžÑ ÐºÐœÐŸÐ¿ÐºÐž,ÐºÐŸÐ³ÐŽÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑÑÑ,Ðž ÐºÐ°ÐºÐžÐµ ÑÐ²ÑÐ·Ðž ÐŸÑÐŸÐ±ÑÐ°Ð¶Ð°ÑÑÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐŒ DateList. ÐÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ° ÐœÐµ Ð»ÐµÐ³ÐºÐŸ ÑÐ°Ð·ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÑÑ,Ðž ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÑÐŸÑÐžÑÐ°ÑÑ Ð³Ð»Ð°Ð²Ñ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone. Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÐ¶ÐŽÐ°ÑÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÑÐŸÑÐŒÐ°ÑÐ° Ðž ÑÐŸ, ÐºÐ°Ðº ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÐµÑ ÐŽÐŸÑÑÑÐ¿ Ðº ÐœÐžÐŒ. Ð "Ð Ð°Ð·ÐŽÐµÐ»Ð°Ñ
+ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÑÐŸÐ±ÐµÐœÐœÐŸÑÑÐž ÑÐŸÑÐŒÐ°ÑÐ°".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð€ÐŸÑÐŒÐ°ÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÐºÐŸÐŒÐ°ÐœÐŽ ÑÐŸÑÐŒÐ°ÑÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐºÐŸÐŒÐ°ÐœÐŽ ÑÐŸÑÐŒÐ°ÑÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ ÐºÐŸÐŒÐ°ÐœÐŽ ÑÐŸÑÐŒÐ°ÑÐ°
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ Ð²Ð°ÑÐžÐ°ÐœÑÑ ÑÐŸÑÐŒÐ°ÑÐžÑÐŸÐ²Ð°ÐœÐžÑ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÑÐžÐŒÐµÐœÐžÑÑ ÐºÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ° Ðº ÑÐµÐŒÑ-ÐœÐžÐ±ÑÐŽÑ Ð² ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐŒ ÑÐ¿ÐžÑÐºÐµ "ÐÑÐ±ÐŸÑ ÑÑÐµÐŽÑÑÐ²",ÐºÐŸÑÐŸÑÑÐ¹ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÐºÐ°Ð¶ÐŽÑÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ Ðž Ð²ÑÑÑÐŸÐµÐœÐœÑÐ¹ ÑÐ¿ÐžÑÐŸÐº ÑÑÐµÐŽÑÑÐ². ÐÐŸÐ³ÐŽÐ° ÐÑ Ð²ÑÐ±ÐžÑÐ°ÐµÑÐµ ÑÑÐµÐŽÑÑÐ²Ð°, ÐµÑÑÑ ÐŽÐ²Ð° ÑÐžÐ¿Ð° ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ. ÐÐµÐºÐŸÑÐŸÑÑÐµ ÑÑÐµÐŽÑÑÐ²Ð° ÑÐ²Ð»ÑÑÑÑÑ Ð¿ÑÐŸÑÑÐŸ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž ÐžÐ»Ðž ÐœÐµÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž,ÐŸÐœÐž ÑÐ¿ÑÐ°Ð²Ð»ÑÑÑÑÑ ÐºÐœÐŸÐ¿ÐºÐ°ÐŒÐž. ÐÑÑÐ³ÐžÐµ ÑÑÐµÐ±ÑÑÑ, ÑÑÐŸÐ±Ñ Ð±ÑÐ»Ð° ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐ° ÑÐŸÑÐŒÐ°ÑÐœÐ°Ñ ÑÑÑÐŸÐºÐ°. ÐÐ»Ñ ÐœÐžÑ
+ ÐžÐŒÐµÐµÑÑÑ ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº "ÐÐŸÐ·ÐŽÐµÐ¹ÑÑÐ²ÑÑÑÐžÐ¹ ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑ", ÑÑÐŸÐ±Ñ Ð²ÑÐ±ÑÐ°ÑÑ, Ðº ÐºÐ°ÐºÐŸÐ¹ ÑÐ°ÑÑÐž ÑÑÐµÐŽÑÑÐ² ÑÑÑÐŸÐºÐ° ÐŸÐ±ÑÐ°ÑÐ°ÐµÑÑÑ,ÐµÑÐ»Ðž ÑÑÐŸ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ, ÐŸÐ±Ð»Ð°ÑÑÑ ÑÐµÐºÑÑÐ°   ("Ð¡ÑÑÐŸÐºÐ° ÑÐŸÑÐŒÐ°ÑÐ° HTML") ÐŽÐ»Ñ Ð²Ð²ÐŸÐŽÐ° ÑÑÑÐŸÐºÐž, Ðž Ð²ÑÐ±ÐŸÑ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ "ÐÐµÑÐµÐŒÐµÐœÐœÑÑ
+". Ð§ÑÐŸÐ±Ñ Ð²ÑÑÐ°Ð²ÐžÑÑ Ð¿ÐµÑÐµÐŒÐµÐœÐœÑÑ Ð² ÑÐµÐºÑÑÑÑ Ð¿ÐŸÐ·ÐžÑÐžÑ Ð² ÑÐŸÑÐŒÐ°ÑÐœÑÑ ÑÑÑÐŸÐºÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÑ ÐžÐ· ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐ³ÐŸ ÑÐ¿ÐžÑÐºÐ°  Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÑÑÐ°Ð²ÐžÑÑ". 
+<p></p>
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐŸÑÐŒÐ°Ñ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ ÐŽÐ»Ñ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑÐ°, Ð²ÑÐ±ÐžÑÐ°Ñ Ð±Ð»Ð°ÐœÐº ÑÐ²ÐŸÐ¹ÑÑÐ². Ð­ÑÐŸÑ ÑÐŸÑÐŒÐ°Ñ Ð·Ð°ÑÐµÐŒ Ð¿ÑÐžÐŒÐµÐœÑÐµÑÑÑ ÐºÐŸ Ð²ÑÐµÐŒ Ð¿ÑÐžÐŒÐµÐœÐžÐŒÑÐŒ ÑÐ²ÐŸÐ¹ÑÑÐ²Ð°ÐŒ, ÐµÑÐ»Ðž ÐŽÑÑÐ³ÐŸÐµ ÐœÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐŸ.
+<p></p>
+Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÑ ÐºÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ°,Ð²ÐœÐµÑÐžÑÐµ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ,ÐºÐ°Ðº ÐŸÐ±ÑÑÑÐœÐµÐœÐŸ Ð²ÑÑÐµ, Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐŸÑÐŒÐ°Ñ".ÐÐŸÐ²Ð°Ñ ÐºÐŸÐŒÐ°ÐœÐŽÐ° ÑÐŸÑÐŒÐ°ÑÐ° Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² ÑÐ¿ÐžÑÐºÐµ "Ð¢ÐµÐºÑÑÐžÐµ Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÐºÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ°".Ð¢ÐŸÐ»ÑÐºÐŸ ÐŸÐŽÐœÐ° ÐºÐŸÐŒÐ°ÐœÐŽÐ° ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÑÐ²ÑÐ·Ð°ÐœÐ° Ñ ÐºÐ°Ð¶ÐŽÐŸÐ¹ ÐºÐŸÐŒÐ±ÐžÐœÐ°ÑÐžÐµÐ¹ ÑÐ²ÐŸÐ¹ÑÑÐ²ÐŸ/ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑ.
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ°, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÑ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐŸÑÐŒÐ°Ñ".
+<p></p>
+  Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐºÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ°, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÑ ÐŒÐ· ÑÐ¿ÐžÑÐºÐ°, ÐžÐ·ÐŒÐµÐœÐžÑÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ ÑÐŸÑÐŒÐ°Ñ".
+<p></p>
+ ÐÐ° ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐµÐ¹ ÐŸ Ð¿ÐµÑÐµÐŒÐµÐœÐœÑÑ
+ Ðž ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑÐ°Ñ
+ ÑÑÐµÐŽÑÑÐ² ÐŸÐ±ÑÐ°ÑÐžÑÐµÑÑ Ðº Ð³Ð»Ð°Ð²Ðµ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÑÐ»Ðž ÐºÐœÐŸÐ¿ÐºÐ° "ÐÐŸÐ·Ð²ÐŸÐ»ÐµÐœÐœÑÐµ ÑÐ°ÑÑÐžÑÐµÐœÐœÑÐµ Ð²Ð°ÑÐžÐ°ÐœÑÑ" Ð¿ÐŸÐŒÐµÑÐµÐœÐ°,ÑÐŸ ÑÐ°Ð·ÑÐµÑÐµÐœÑ ÐœÐµÐºÐŸÑÐŸÑÑÐµ Ð¿ÑÐŸÐŽÐ²ÐžÐœÑÑÑÐµ Ð²Ð°ÑÐžÐ°ÐœÑÑ ÑÐŸÑÐŒÐ°ÑÐžÑÐŸÐ²Ð°ÐœÐžÑ . Ð¡Ð¿ÐžÑÐŸÐº ÑÑÐµÐŽÑÑÐ², ÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐŸÑÐŒÐ°ÑÐžÑÐŸÐ²Ð°ÐœÑ, ÐœÐµÐŒÐœÐŸÐ³ÐŸ ÐžÐ·ÐŒÐµÐœÐµÐœ Ðž Ð±ÐŸÐ»ÑÑÐµÐµ ÑÐžÑÐ»ÐŸ Ð¿ÐµÑÐµÐŒÐµÐœÐœÑÑ
+ ÐŽÐŸÑÑÑÐ¿ÐœÐŸ ÐŽÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÐºÐŸÐŒÐ°ÐœÐŽÐŸÐ¹ ÑÐŸÑÐŒÐ°ÑÐ°, ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°Ñ Ð±ÐŸÐ»ÑÑÐµÐµ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÑÑÐ°ÐœÐžÑÐµÐ¹ ÐŸÑÐžÐ³ÐžÐœÐ°Ð»-ÐŒÐ°ÐºÐµÑÐ°.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/generalsettings.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/generalsettings.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/generalsettings.htm	(revision 10506)
@@ -0,0 +1,55 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="generalsettings"><font size="5" face="Verdana"><strong>6.2: ÐÐ±ÑÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ Ðž ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐŸÐ±ÑÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž, ÐŸÑÐœÐŸÑÑÑÐžÐµÑÑ Ðº ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.Ð¡ÐœÐ°ÑÐ°Ð»Ð° Ð² "Ð Ð°Ð·ÐŽÐµÐ»Ð°Ñ
+ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ±ÑÐžÐµ"
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ±ÑÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÐŽÐµÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ,Ð¿ÑÐµÐŽÑÑÐŒÐŸÑÑÐµÐœÐœÑÐµ Ð¿ÑÐž ÑÐŸÐ·ÐŽÐ°ÐœÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐžÐ·ÐŒÐµÐœÐµÐœÑ.
+<p></p>
+ ÐÐ°Ð²ÐµÑÑ
+Ñ ÑÑÑÐ°ÐœÐžÑÑ ÐžÐŒÐµÐµÑÑÑ Ð¿ÐŸÐ»Ðµ ÐžÐœÑÑÑÑÐºÑÐžÐž,ÐºÐŸÑÐŸÑÐ°Ñ ÐžÐŒÐµÐµÑÑÑ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÑÐ°Ð·ÐŽÐµÐ»Ð°.ÐÐœÐŸ ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÐºÑÐ°ÑÐºÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº ÑÐºÐ°Ð·Ð°ÐœÐžÐ¹,ÑÑÐŸÐ±Ñ ÐœÐ°Ð¿ÐŸÐŒÐœÐžÑÑ ÐÐ°ÐŒ,ÐºÐ°ÐºÐžÐµ ÑÑÐœÐºÑÐžÐŸÐœÐ°Ð»ÑÐœÑÐµ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÐž ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž.
+<p></p>
+ Ð¡ÐœÐ°ÑÐ°Ð»Ð° ÐžÐŽÑÑ ÐºÐŸÐœÑÐ°ÐºÑÐœÑÐµ Ð°ÐŽÑÐµÑÐ° ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ ÑÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑÐµÐ³ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð»ÐžÑÐ°. Ð¡Ð»ÐµÐŽÑÑÑÐµÐµ Ð¿ÐŸÐ»Ðµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐÐ°ÐŒ ÐžÐ·ÐŒÐµÐœÑÑÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð¡Ð»ÐµÐŽÑÑÐµÐµ ÑÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð¿Ð°Ð¿ÐºÑ, Ð² ÐºÐŸÑÐŸÑÐŸÐ¹ ÑÐŸÑ
+ÑÐ°ÐœÐµÐœÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐœÐŸ ÐœÐµ Ð¿ÐŸÐŽÐ»ÐµÐ¶ÐžÑ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑÐŒ. Ð¡Ð»ÐµÐŽÑÑÑÐµÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÑ (Ð² ÑÐŸÑÐŒÐµ URL) ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ,ÑÑÐŸÐ±Ñ Ð¿ÐŸÐºÐ°Ð·Ð°ÑÑ ÐœÐ°Ð²ÐµÑÑ
+Ñ ÑÐ»ÐµÐ²Ð° ÐŸÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÑÑÑÐ°ÐœÐžÑÑ ÐŸ ÐœÐµÐ¹, Ðž ÑÐ»ÐµÐŽÑÑÑÐµÐµ - ÐžÐºÐŸÐœÐºÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐ°Ñ Ð² Greenstone ÑÑÑÐ°ÐœÐžÑÐ° ÐŽÐ»Ñ ÑÐ²ÑÐ·Ðž Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹. ÐÐŸÑÐ»Ðµ ÑÑÐŸÐ³ÐŸ, Ð²Ñ ÑÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐŽÐµÐ»ÐžÑÑ Ð¿ÑÐœÐºÑ Ð³Ð°Ð»ÐŸÑÐºÐŸÐ¹, ÑÐºÐ°Ð·Ð°Ð², ÐŽÐŸÑÑÑÐ¿ÐœÐ° Ð»Ðž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŽÑÑÐ³ÐžÐŒ. ÐÐ°ÐºÐŸÐœÐµÑ, ÑÐ»ÐµÐŽÑÐµÑ ÐŸÐ±Ð»Ð°ÑÑÑ ÑÐµÐºÑÑÐ° "ÐÐ¿ÐžÑÐ°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž",Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐœÐ°Ñ ÑÐ°ÐœÐµÐµ Ð² <a href="creatingacollection.htm#creatingacollection">Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</a>.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/help.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/help.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/help.xml	(revision 10506)
@@ -0,0 +1,1427 @@
+<Document>
+  <Section name="introduction">
+    <Title>ÐÐ²ÐµÐŽÐµÐœÐžÐµ</Title>
+ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Greenstone - ÑÑÐŸ ÐžÐœÑÑÑÑÐŒÐµÐœÑ ÐŽÐ»Ñ ÑÐ±ÐŸÑÐ° Ðž ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐž
+ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Ñ Ð¿ÐŸÑÐ»ÐµÐŽÑÑÑÐžÐŒ ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµÐŒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÑÐžÑÑÐŸÐ²ÑÑ
+ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐº.ÐÐœ
+ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°ÐµÑ ÐŽÐŸÑÑÑÐ¿ Ðº ÑÑÐœÐºÑÐžÐŸÐœÐ°Ð»ÑÐœÑÐŒ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑÐŒ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐ³ÐŸ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ
+Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž Greenstone Ð³ÑÐ°ÑÐžÑÐµÑÐºÐžÐŒ Ð¿ÑÑÐµÐŒ Ðž ÑÐ°Ð±ÐŸÑÐŸÐ¹ ÐŒÑÑÑÑ.
+    <Section name="ofmiceandmenus">
+      <Title>ÐÑÑÑ Ðž ÐÐµÐœÑ</Title>
+Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» ÐŽÐ°ÐµÑ Ð±Ð°Ð·ÐŸÐ²ÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ Ð²Ð·Ð°ÐžÐŒÐŸÐŽÐµÐ¹ÑÑÐ²ÐžÐž Ñ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐŸÐŒ  Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž. 
+ÐÑÐ»Ðž ÐÑ Ð·ÐœÐ°ÐºÐŸÐŒÑ Ñ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°ÐŒÐž ÑÐžÐ¿Ð° Internet Explorer ÐžÐ»Ðž Microsoft office, Ð»ÐµÐ³ÐºÐŸ ÐŸÐ±ÑÐ°ÑÐ°ÐµÑÐµÑÑ Ñ ÐŒÑÑÑÑ Ðž ÐŒÐµÐœÑ, Ð¿ÑÐŸÐ¿ÑÑÑÐžÑÐµ <Reference target="howtoavoidthisdocument">Ðž Ð¿ÐµÑÐµÐ¹ÐŽÐžÑÐµ Ðº ÑÐ»ÐµÐŽÑÑÑÐµÐŒÑ ÑÐ°Ð·ÐŽÐµÐ»Ñ </Reference>.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    ÐÑÐœÐŸÐ²ÐœÑÐµ Ð¿ÐŸÐœÑÑÐžÑ ÐºÐŸÐœÑÐµÐ¿ÑÐžÐž
+            <ContentsItem>
+               ÐÐµÐ¹ÑÑÐ²ÐžÑ ÐŒÑÑÐž
+	    </ContentsItem>
+            <ContentsItem>
+               ÐÐ»Ð°Ð²ÐžÐ°ÑÑÑÐ°
+	    </ContentsItem>
+          </ContentsItem>
+          <ContentsItem>
+	    ÐÐµÑÐµÑ
+ÐŸÐŽ Ðº Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐµ
+          </ContentsItem>
+	</ContentsGroup>
+	<ContentsGroup linkto="advanced">
+          <ContentsItem>
+	    ÐÑÑÑÑÑÐµ ÐºÐ»ÑÑÐž
+          </ContentsItem>
+	</ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ ÑÐŸÐ³Ð»Ð°ÑÐµÐœÐžÑÐŒ Windows Microsoft Ðž ÑÑÐµÐ±ÑÐµÑ ÐŸÐ±ÑÑÐœÐŸÐ³ÐŸ Ð·ÐœÐ°ÐœÐžÑ Windows.   
+ <Break/>
+ ÐÑÐ±Ð°Ñ ÑÐ°ÑÑÑ ÑÐºÑÐ°ÐœÐ°, Ñ ÐºÐŸÑÐŸÑÐŸÐ¹ ÐÑ Ð²Ð·Ð°ÐžÐŒÐŸÐŽÐµÐ¹ÑÑÐ²ÑÐµÑÐµ, ÑÐžÐ¿Ð° ÐºÐœÐŸÐ¿ÐºÐž ÐžÐ»Ðž ÐŸÐ±Ð»Ð°ÑÑÐž ÑÐµÐºÑÑÐ°,ÐœÐ°Ð·ÑÐ²Ð°ÐµÑÑÑ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµÐŒ. Ð Ð»ÑÐ±ÐŸÐµ Ð·Ð°ÐŽÐ°ÐœÐœÐŸÐµ Ð²ÑÐµÐŒÑ ÐŸÐŽÐžÐœ ÑÐ»ÐµÐŒÐµÐœÑ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ, ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÑÐ¹ "ÑÐŸÐºÑÑ",Ð²ÑÐŽÐµÐ»ÑÐµÑÑÑ Ð¿ÐŸÐŽÑÐ²ÐµÑÐºÐŸÐ¹ Ðž ÐŸÑÐºÐ»ÐžÐºÐ°ÐµÑÑÑ ÐœÐ° ÐŽÐµÐ¹ÑÑÐ²ÐžÐµ ÐºÐ»Ð°Ð²ÐžÐ°ÑÑÑÑ. ÐÐµÑÐºÐŸÐ»ÑÐºÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÑÑ ÐÐ°ÐŒ Ð²ÑÐ±ÐžÑÐ°ÑÑ ÑÑÐ°ÑÑÐºÐž, ÐºÐŸÑÐŸÑÑÐµ Ð²ÑÐŽÐµÐ»ÑÑÑÑÑ ÑÐµÐŒÐœÐŸÑÐžÐœÐžÐŒ ÑÐ²ÐµÑÐŸÐŒ. ÐÐµÐºÐŸÑÐŸÑÑÐµ ÑÐ»ÐµÐŒÐµÐœÑÑ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐŸÑÐŸÐ±ÑÐ°Ð¶Ð°ÑÑÑÑ Ñ Ð¿ÐŸÐœÐžÐ¶ÐµÐœÐœÐŸÐ¹ ÑÑÐºÐŸÑÑÑÑ, Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°Ñ ÑÐµÐŒ ÑÐ°ÐŒÑÐŒ, ÑÑÐŸ ÐŸÐœÐž Ð·Ð°Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÐœÑ.
+<Break/>
+ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐµÑÐµÐŒÐµÑÐ°ÑÑÑÑ Ðž ÐŽÐµÐ¹ÑÑÐ²ÐŸÐ²Ð°ÑÑ  Ð»ÐµÐ²ÐŸÐ¹ ÐžÐ»Ðž Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐ°ÐŒÐž ÐŒÑÑÐž ÐŸÐ±ÑÑÐœÑÐŒ ÑÐ¿ÐŸÑÐŸÐ±ÐŸÐŒ. ÐÐœÐŸÐ³ÐžÐµ ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑÑ ÑÐ°ÐºÐ¶Ðµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÑÑ ÐÐ°ÐŒ "ÑÑÐœÑÑÑ" ÐžÑ
+, ÐœÐ°Ð¶ÐžÐŒÐ°Ñ Ðž ÑÐŽÐµÑÐ¶ÐžÐ²Ð°Ñ Ð»ÐµÐ²ÑÑ ÐºÐœÐŸÐ¿ÐºÑ ÐŒÑÑÐž, Ð¿ÐµÑÐµÐŒÐµÑÐ°ÑÑ ÐžÑ
+ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐŒÑÑÐž Ðž ÐŸÑÑÐ°Ð²ÐžÑÑ ÐžÑ
+ Ð² ÐŽÑÑÐ³ÐŸÐŒ ÐŒÐµÑÑÐµ, ÐŸÑÐ¿ÑÑÐºÐ°Ñ ÐºÐœÐŸÐ¿ÐºÑ. ÐÐŸÑÐµÐœÑÐžÐ°Ð»ÑÐœÑÐµ ÐŸÐ±ÑÐµÐºÑÑ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐžÐ·ÐŒÐµÐœÑÑÑ ÑÐ²ÐŸÐ¹ Ð²ÐžÐŽ, ÐºÐŸÐ³ÐŽÐ° ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑ ÑÐºÐŸÐ»ÑÐ·ÐžÑ Ð¿ÐŸ ÐœÐžÐŒ.  
+<Break/>
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐºÐ»Ð°Ð²ÐžÐ°ÑÑÑÑ ÐŽÐ»Ñ Ð·Ð°Ð¿ÐžÑÐž Ð² ÐŸÐ±Ð»Ð°ÑÑÐž ÑÐµÐºÑÑÐ°. ÐÐ»ÑÑÐµÑÐœÐ°ÑÐžÐ²Ñ ÐºÐ»Ð°Ð²ÐžÐ°ÑÑÑÐµ ÐŽÐŸÑÑÑÐ¿ÐœÑ ÐŽÐ»Ñ ÐŒÐœÐŸÐ³ÐžÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ, ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐœÑÑ
+ ÐºÐ»ÑÑÐµÐ²ÑÐŒ ÐžÐŒÐµÐœÐµÐŒ Ð² ÐºÐ²Ð°ÐŽÑÐ°ÑÐœÑÑ
+ ÑÐºÐŸÐ±ÐºÐ°Ñ
+. Ð Ð¿ÑÐžÐŒÐµÑÑ, [Tab] ÐžÐ·ÐŒÐµÐœÑÐµÑ ÑÐŸÐºÑÑ. ÐÐœÐ°Ðº Ð¿Ð»ÑÑ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ, ÑÑÐŸ ÐŽÑÑÐ³ÐžÐµ ÐºÐ»Ð°Ð²ÐžÑÐž ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐœÐ°Ð¶Ð°ÑÑ ÐŸÐŽÐœÐŸÐ²ÑÐµÐŒÐµÐœÐœÐŸ. 
+<Break/>
+ÐÑÐ¹ÐŽÐžÑÐµ ÐžÐ· Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°, Ð²ÑÐ±ÐžÑÐ°Ñ Ð¿ÑÐœÐºÑ "ÐÑÑ
+ÐŸÐŽ" Ð² ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»Ð°". ÐÐ°ÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±ÑÐŽÐµÑ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ  ÑÐŸÑ
+ÑÐ°ÐœÐµÐœÐ°.
+<Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+Ð§ÑÐŸÐ±Ñ Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÑÑÑÐ¿ Ðº ÐŒÐµÐœÑ, ÑÐŽÐµÑÐ¶ÐžÐ²Ð°Ð¹ÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ [ALT] Ðž ÐœÐ°Ð¶ÐŒÐžÑÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÑÑ Ð±ÑÐºÐ²Ñ (Ð¿ÐŸÐŽÑÐµÑÐºÐœÑÑÑÑ).ÐÐ°Ð¿ÑÐžÐŒÐµÑ,ÐŽÐ»Ñ Ð²ÑÐ±ÐŸÑÐ° ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»" ÐœÐ°Ð¶ÐŒÐžÑÐµ [ALT] + [F]. ÐÐ»Ñ Ð²ÑÐ±ÐŸÑÐ° ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÐŸÐ³ÐŸ Ð¿ÑÐœÐºÑÐ°, ÐœÐ°Ð¶ÐŒÐžÑÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÑÑ ÐºÐ»Ð°Ð²ÐžÑÑ. ÐÐ°Ð¿ÑÐžÐŒÐµÑ, ÐµÑÐ»Ðž ÐÑ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÐµÑÑ Ð² ÐŒÐµÐœÑ Ð€Ð°Ð¹Ð» ÐœÐ°Ð¶ÐŒÐžÑÐµ [S], ÑÑÐŸÐ±Ñ "Ð¡ÐŸÑ
+ÑÐ°ÐœÐžÑÑ"ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+</Section>
+<Section name="howtoavoidthisdocument">
+<Title>ÐÐ°Ðº ÐžÐ·Ð±ÐµÐ¶Ð°ÑÑ ÑÑÐµÐœÐžÑ ÑÑÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°</Title>
+ ÐÐµ ÑÐžÑÐ°Ð¹ÑÐµ ÑÑÐŸÑ ÑÐµÐºÑÑ Ð¿ÐŸÐŒÐŸÑÐž Ð¿ÐŸÐ»ÐœÐŸÑÑÑÑ! ÐÐŸÑÑÐ°ÑÐŸÑÐœÐŸ Ð¿ÑÐŸÑÐµÑÑÑ, ÐºÐ°Ðº ÑÑÐŒÐµÑÑ Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð¿ÐŸÐŒÐŸÑÑ, ÐºÐŸÐ³ÐŽÐ° ÐÑ ÐœÑÐ¶ÐŽÐ°ÐµÑÐµÑÑ Ð² ÑÑÐŸÐŒ.  
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+           Ð§ÑÐ²ÑÑÐ²ÐžÑÐµÐ»ÑÐœÐ°Ñ ÐºÐŸÐœÑÐµÐºÑÑÐœÐ°Ñ Ð¿ÐŸÐŒÐŸÑÑ
+          </ContentsItem>
+          <ContentsItem>
+            ÐÐœÑÑÑÑÐŒÐµÐœÑ Ð¿ÐŸÐŽÑÐºÐ°Ð·ÐŸÐº
+          </ContentsItem>
+          <ContentsItem>
+             ÐÑÑÐ³ÐžÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ÐÑÐœÐºÑÑ ÐŒÐµÐœÑ "ÐÐŸÐŒÐŸÑÑ" ÑÐºÐ°Ð·ÑÐ²Ð°ÑÑ ÑÐµ ÑÐ°Ð·ÐŽÐµÐ»Ñ,ÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐœÐ°ÐžÐ±ÐŸÐ»ÐµÐµ Ð°ÐŽÐµÐºÐ²Ð°ÑÐœÑÐŒÐž ÐŽÐ»Ñ Ð¿ÐŸÐŒÐŸÑÐž, Ðž ÑÐŸÐ¿ÑÐŸÐ²ÐŸÐ¶ÐŽÐ°ÑÑÑÑ ÐœÐµÐ±ÐŸÐ»ÑÑÐžÐŒ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµÐŒ ÐºÐœÐžÐ³Ðž  
+<Break/>
+ÐÐ»Ñ ÐŒÐœÐŸÐ³ÐžÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ, ÐµÑÐ»Ðž ÐÑ ÑÐ°Ð·ÐŒÐµÑÐ°ÐµÑÐµ ÐŒÑÑÑ ÐœÐ° ÐœÐžÑ
+,Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ 
+"Ð¿ÐŸÐŽÑÐºÐ°Ð·ÐºÐ°",ÐºÐŸÑÐŸÑÐ°Ñ ÐŸÐ±ÑÑÑÐœÑÐµÑ ÐŽÐµÐ¹ÑÑÐ²ÐžÑ,ÐºÐŸÑÐŸÑÑÐµ ÐŸÐœÐž Ð²ÑÐ¿ÐŸÐ»ÐœÑÑÑ  
+<Break/>
+ ÐÐµÑÐµÐŽ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐŒ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐŸÐŒ, ÑÐœÐ°ÑÐ°Ð»Ð° Ð¿ÑÐŸÑÑÐžÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÑÐžÑ Greenstone/
+    </Section>
+  </Section>
+  <Section name="startingoff">
+    <Title>ÐÐŸ ÑÑÐ°ÑÑÐ°</Title>
+    Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÑÐ°ÑÑÐºÐ°Ð·Ð°ÐœÐŸ, ÐºÐ°Ðº ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÑÑ, Ð·Ð°Ð³ÑÑÐ¶Ð°ÑÑ Ðž ÑÐŽÐ°Ð»ÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+    <Section name="creatingacollection">
+ <Title>Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title>      
+       
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ,ÐºÐ°Ðº ÑÐŸÐ·ÐŽÐ°ÑÑ ÐœÐŸÐ²ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            ÐÑÑÑÑÐŸÐµ ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </ContentsItem>
+          <ContentsItem>
+            ÐÐ°Ð³Ð»Ð°Ð²ÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐ¿ÐžÑÐ°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </ContentsItem>
+          <ContentsItem>
+             ÐÑÐŒÐµÐœÐ° ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </ContentsItem>
+          <ContentsItem>
+             Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+             ÐÐŸÑÑÑÐžÐµ ÐºÐ»Ð°Ð²ÐžÑÐž
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð§ÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐœÐŸÐ²ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐŸÑÐºÑÐŸÐ¹ÑÐµ ÐŒÐµÐœÑ "File" Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ Ð² ÐœÑÐŒ Ð¿ÑÐœÐºÑ "New". ÐÐµÐºÐŸÑÐŸÑÑÐµ Ð¿ÐŸÐ»Ñ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐŸÐ±ÑÐ·Ð°ÑÐµÐ»ÑÐœÐŸ Ð·Ð°Ð¿ÐŸÐ»ÐœÐµÐœÑ, ÐœÐŸ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð·Ð°ÐŒÐµÐœÐžÑÑ ÐžÑ
+ Ð·ÐœÐ°ÑÐµÐœÐžÑ Ð¿ÐŸÐ·Ð¶Ðµ, ÐµÑÐ»Ðž ÐÑ Ð² ÑÑÐŸÐŒ ÐœÑÐ¶ÐŽÐ°ÐµÑÐµÑÑ Ñ ÑÐŸÑÐºÐž Ð·ÑÐµÐœÐžÑ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°.
+ <Break/>
+ÐÐ°Ð³Ð»Ð°Ð²ÐžÐµ "ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ/Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐŸÐº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž" - ÑÑÐŸ ÑÐµÐºÑÑ, ÑÐ°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐœÑÐ¹ ÐœÐ°Ð²ÐµÑÑ
+Ñ ÐŽÐŸÐŒÐ°ÑÐœÐµÐ¹ ÑÑÑÐ°ÐœÐžÑÑ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐœÐŸ ÐŒÐŸÐ¶ÐµÑ ÐžÐŒÐµÑÑ Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐ»ÑÐœÑÑ ÐŽÐ»ÐžÐœÑ.
+<Break/>
+"ÐÐ¿ÐžÑÐ°ÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ" ÐŽÐŸÐ»Ð¶ÐœÐŸ Ð¿ÑÐµÐŽÑÑÐ°Ð²ÐžÑÑ ÐºÐ°Ðº ÐŒÐŸÐ¶ÐœÐŸ ÐŽÐµÑÐ°Ð»ÑÐœÐµÐµ ÑÐŸ,ÐŸ ÑÑÐŒ ÑÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ [Enter] ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ,ÑÑÐŸÐ±Ñ ÑÐ°Ð·Ð±ÐžÑÑ ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ ÐœÐ° Ð¿Ð°ÑÐ°Ð³ÑÐ°ÑÑ.
+<Break/>
+ ÐÐ°ÐºÐŸÐœÐµÑ ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ, ÐŽÐŸÐ»Ð¶ÐœÐ° Ð»Ðž ÐœÐŸÐ²Ð°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐŒÐµÑÑ ÑÐŸÑ Ð¶Ðµ ÑÐ°ÐŒÑÐ¹ Ð²ÐžÐŽ Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÑÑÐŸ Ðž ÑÑÑÐµÑÑÐ²ÑÑÑÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐžÐ»Ðž Ð¶Ðµ ÐœÐ°ÑÐ°ÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ "ÐÐŸÐ²ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ".
+<Break/>
+Ð©ÐµÐ»ÐºÐœÐžÑÐµ "OK", ÑÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ. ÐÑÐ»Ðž ÐÑ Ð²ÑÐ±ÑÐ°Ð»Ðž "New Collection", ÑÐŸ ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð²Ð²ÐµÑÑÐž ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÑÑÐŸÐ±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐžÑ
+ Ð² ÑÑÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ Ð±ÐŸÐ»ÑÑÐµ,ÑÐµÐŒ ÐŸÐŽÐœÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ, Ð° ÐŒÐŸÐ¶ÐµÑÐµ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŽÑÑÐ³ÐžÐµ Ð¿ÐŸÐ·Ð¶Ðµ. 
+<Break/>
+ÐÐ°Ð¶Ð°ÑÐžÐµ ÐºÐ»Ð°Ð²ÐžÑÐž "Cancel" ÐœÐµÐŒÐµÐŽÐ»ÐµÐœÐœÐŸ Ð²ÐŸÐ·Ð²ÑÐ°ÑÐ°ÐµÑ ÐÐ°Ñ Ðº Ð³Ð»Ð°Ð²ÐœÐŸÐŒÑ ÑÐºÑÐ°ÐœÑ. 
+    <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÐœÐŸÐ¿ÐºÐž, ÑÐžÐ¿Ð° ÐŒÐµÐœÑ, ÐžÐŒÐµÑÑ ÐŸÐŽÐžÐœ Ð¿ÐŸÐŽÑÑÑÐºÐœÑÑÑÐ¹ ÑÐžÐŒÐ²ÐŸÐ». Ð§ÑÐŸÐ±Ñ Ð²ÑÐ·Ð²Ð°ÑÑ ÐºÐœÐŸÐ¿ÐºÑ ÐœÐ°Ð¶ÐŒÐžÑÐµ [ALT] Ðž ÐŸÐŽÐœÐŸÐ²ÑÐµÐŒÐµÐœÐœÐŸ Ð¿ÐŸÐŽÑÐµÑÐºÐœÑÑÑÐ¹ ÑÐžÐŒÐ²ÐŸÐ». 
+    </Section>
+    <Section name="savingacollection">
+      <Title>Ð¡ÐŸÑ
+ÑÐ°ÐœÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ, ÐºÐ°Ðº ÑÐŸÑ
+ÑÐ°ÐœÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ðž ÐºÐ°Ðº ÑÐŸÑ
+ÑÐ°ÐœÐžÑÑ ÐµÑ ÐœÐµÐ·Ð°ÐŒÐµÐŽÐ»ÐžÑÐµÐ»ÑÐœÐŸ. 
+</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐ°Ðº ÑÐŸÑ
+ÑÐ°ÐœÐžÑÑ
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+            ÐÐŽÐµ ÑÐ°Ð¹Ð»Ñ ÑÐŸÑ
+ÑÐ°ÐœÐµÐœÑ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð¡ÐŸÑ
+ÑÐ°ÐœÑÐ¹ÑÐµ ÐÐ°ÑÑ ÑÐ°Ð±ÐŸÑÑ ÑÐµÐ³ÑÐ»ÑÑÐœÐŸ, ÐŸÑÐºÑÑÐ²Ð°Ñ ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»" Ðž Ð²ÑÐ±ÐžÑÐ°Ñ Ð² ÐœÑÐŒ Ð¿ÑÐœÐºÑ "Ð¡ÐŸÑ
+ÑÐ°ÐœÐžÑÑ". Ð¡ÐŸÑ
+ÑÐ°ÐœÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž - ÑÑÐŸ ÐœÐµ ÑÐŸ Ð¶Ðµ ÑÐ°ÐŒÐŸÐµ, ÐºÐ°Ðº  ÑÐŽÐµÐ»Ð°ÑÑ ÐµÑ Ð³ÐŸÑÐŸÐ²ÐŸÐ¹ Ðº ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ Ð² Greenstone.
+ (see <Reference target="producingthecollection">Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Reference>).
+<Break/>
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð·Ð°ÑÐžÑÐ°ÐµÑ ÐÐ°ÑÑ ÑÐ°Ð±ÐŸÑÑ Ð¿ÑÑÑÐŒ ÑÐŸÑ
+ÑÐ°ÐœÐµÐœÐžÑ ÐµÑ Ð²ÑÑÐºÐžÐ¹ ÑÐ°Ð·, ÐºÐŸÐ³ÐŽÐ° ÐÑ Ð²ÑÑ
+ÐŸÐŽÐžÑÐµ ÐžÐ· Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ ÐžÐ»Ðž Ð·Ð°Ð³ÑÑÐ¶Ð°ÐµÑÐµ ÐŽÑÑÐ³ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+      <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð¡ÐŸÑ
+ÑÐ°ÐœÐµÐœÐœÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð·Ð°Ð¿ÐžÑÑÐ²Ð°ÑÑÑÑ  Ð² ÑÐ°Ð¹Ð», ÐžÐŒÐµÑÑÐžÐ¹ ÑÐŸ Ð¶Ðµ ÐžÐŒÑ, ÑÑÐŸ Ðž ÐžÐŒÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ñ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµÐŒ ".col", Ðž ÑÐ°ÑÐ¿ÐŸÐ»Ð°Ð³Ð°ÐµÑÑÑ Ð² Ð¿Ð°Ð¿ÐºÐµ ÑÐŸÐ³ÐŸ Ð¶Ðµ ÐœÐ°ÐžÐŒÐµÐœÐŸÐ²Ð°ÐœÐžÑ, ÑÑÐŸ Ðž Ð¿Ð°Ð¿ÐºÐ° "collect" Ð¿ÑÐž ÐžÐœÑÑÐ°Ð»Ð»ÑÑÐžÐž Greenstone.
+    </Section>
+    <Section name="openingacollection">
+      <Title>ÐÑÐºÑÑÑÐžÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÑÐŸÐŸÐ±ÑÐ°ÐµÑÑÑ,ÐºÐ°Ðº ÐŸÑÐºÑÑÑÑ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Open Collection prompt.
+     </ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐ°Ðº ÐŸÑÐºÑÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+             ÐÐ°ÐºÑÑÑÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </ContentsItem>
+	  <ContentsItem>
+	     ÐÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐœÐ°ÑÐ»ÐµÐŽÑÑÐ²Ð°
+	  </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ÐÐ»Ñ ÑÐŸÐ³ÐŸ ÑÑÐŸÐ±Ñ ÐŸÑÐºÑÑÑÑ ÑÑÑÐµÑÑÐ²ÑÑÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ "ÐÑÐºÑÑÑÑ" Ð² ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»",ÑÑÐŸÐ±Ñ Ð±ÑÑÑÑÐŸ Ð¿ÐµÑÐµÐ¹ÑÐž Ðº ÐÑÐºÑÑÑÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐŸÑÐ²Ð»ÑÐµÑÑÑ ÑÐ¿ÐžÑÐŸÐº ÐÐ°ÑÐžÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Ð² Greenstone. ÐÑÐ±ÐµÑÐžÑÐµ ÐŸÐŽÐœÑ,ÑÑÐŸÐ±Ñ ÑÐ²ÐžÐŽÐµÑÑ ÐµÐµ ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ,Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ   "OÑÐºÑÑÑÑ", ÑÑÐŸÐ±Ñ Ð·Ð°Ð³ÑÑÐ·ÐžÑÑ ÐµÐµ. ÐÑÐ»Ðž ÐÑ ÐžÑÐžÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐºÐŸÑÐŸÑÐ°Ñ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ Ð²ÐœÐµ Ð¿Ð°Ð¿ÐºÐž "Ð¡ollect Greenstone",ÑÐŸ ÑÐµÐ»ÐºÐœÐžÑÐµ "Browse" ÐŽÐ»Ñ Ð²ÑÐ·ÐŸÐ²Ð° ÐŽÐžÐ°Ð»ÐŸÐ³ÐŸÐ²ÐŸÐ¹ ÑÐžÑÑÐµÐŒÑ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÑÐ°Ð¹Ð»ÐŸÐ².
+ <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð ÑÐ»ÑÑÐ°Ðµ, ÐµÑÐ»Ðž Ð±ÐŸÐ»ÑÑÐµ ÑÐµÐŒ ÐŸÐŽÐœÐ° Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ° ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° Greenstone Ð²Ð²ÐŸÐŽÐžÑÑÑ ÐŸÐŽÐœÐŸÐ²ÑÐµÐŒÐµÐœÐœÐŸ, ÑÐµÐ»ÐµÐ²Ð°ÐœÑÐœÑÐµ ÐŽÐžÑÐµÐºÑÑÐžÐž "Ð·Ð°ÐºÑÑÑÑ",ÑÑÐŸÐ±Ñ Ð¿ÑÐµÐŽÐŸÑÐ²ÑÐ°ÑÐžÑÑ ÐœÐ°Ð»ÐŸÐ¶ÐµÐœÐžÐµ.ÐÑÐž ÐŸÑÐºÑÑÑÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐœÐµÐ±ÐŸÐ»ÑÑÐŸÐ¹ Ð²ÑÐµÐŒÐµÐœÐœÑÐ¹ Ð±Ð»ÐŸÐºÐžÑÑÑÑÐžÐ¹ ÑÐ°Ð¹Ð» ÑÐŸÐ·ÐŽÐ°ÐµÑÑÑ Ð² ÐµÑ Ð¿Ð°Ð¿ÐºÐµ.ÐÐµÑÐµÐŽ ÐŸÑÐºÑÑÑÐžÐµÐŒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑ Ð¿ÑÐŸÐ²ÐµÑÐºÑ,ÑÑÐŸÐ±Ñ ÑÐ±ÐµÐŽÐžÑÑÑÑ,ÑÑÐŸ ÐœÐžÐºÐ°ÐºÐžÑ
+ Ð±Ð»ÐŸÐºÐžÑÑÑÑÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÐœÐµ ÑÑÑÐµÑÑÐ²ÑÐµÑ. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐºÐ°Ð·Ð°ÑÑ,Ð·Ð°ÐºÑÑÑÐ° Ð»Ðž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, Ð¿ÐŸ ÑÐ²ÐµÑÑ ÐµÑ ÐžÐºÐŸÐœÐºÐž:Ð·ÐµÐ»ÑÐœÑÐ¹ - ÐŽÐ»Ñ ÐœÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,ÐºÑÐ°ÑÐœÑÐ¹ - ÐŽÐ»Ñ Ð·Ð°ÐºÑÑÑÐŸÐ¹. ÐÐŽÐœÐ°ÐºÐŸ,ÐºÐŸÐ³ÐŽÐ° ÐžÐ· ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° Ð²ÑÑ
+ÐŸÐŽÑÑ Ð¿ÑÐµÐ¶ÐŽÐµÐ²ÑÐµÐŒÐµÐœÐœÐŸ, Ð±Ð»ÐŸÐºÐžÑÑÑÑÐžÐ¹ ÑÐ°Ð¹Ð» ÐžÐœÐŸÐ³ÐŽÐ° ÐŸÑÑÐ°ÐµÑÑÑ ÐœÐ° ÐŒÐµÑÑÐµ. ÐÐŸÐ³ÐŽÐ° ÐÑ ÐŸÑÐºÑÑÐ²Ð°ÐµÑÐµ ÑÐ°ÐºÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ° Ð·Ð°Ð¿ÑÐ°ÑÐžÐ²Ð°ÐµÑ,Ñ
+ÐŸÑÐžÑÐµ Ð»Ðž ÐÑ "ÑÐºÑÐ°ÑÑÑ" ÐµÐ³ÐŸ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ. ÐÐžÐºÐŸÐ³ÐŽÐ° ÐœÐµ ÐŽÐµÐ»Ð°Ð¹ÑÐµ ÑÑÐŸÐ³ÐŸ,ÐµÑÐ»Ðž ÐºÑÐŸ-ÑÐŸ ÐµÑÐµ Ð² ÑÐŸ Ð¶Ðµ ÑÐ°ÐŒÐŸÐµ Ð²ÑÐµÐŒÑ ÑÐ°Ð±ÐŸÑÐ°ÐµÑ.   
+<Break/>
+ÐÐŸÐ³ÐŽÐ° ÐÑ ÐŸÑÐºÑÑÐ²Ð°ÐµÑÐµ ÐºÐŸÐ»ÐµÐºÑÐžÑ, ÐºÐŸÑÐŸÑÐ°Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐ° ÐœÐµ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°  Greenstone, ÐÐ°Ñ Ð¿ÐŸÐ¿ÑÐŸÑÑÑ Ð²ÑÐ±ÑÐ°ÑÑ ÐœÐ°Ð±ÐŸÑ (ÐžÐ»Ðž ÐœÐ°Ð±ÐŸÑÑ) ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÑÐ»Ðž ÐœÐž ÐŸÐŽÐžÐœ ÐœÐµ ÐŸÑÐŸÐ±ÑÐ°Ðœ, Ð»ÑÐ±ÑÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð±ÑÐŽÑÑ ÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÑÑÑÑ. ÐÐœÐ°ÑÐµ, ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð±ÑÐŽÑÑ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÑ ÑÐ°Ðº Ð¶Ðµ, ÐºÐ°Ðº Ðž ÐºÐŸÐ³ÐŽÐ° ÐÑ Ð¿ÐµÑÐµÑÑÐ³ÐžÐ²Ð°ÐµÑÐµ Ð² ÑÐ°Ð¹Ð»Ñ Ñ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐŒÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž. ÐÑÐŸÑÐµÑÑ ÐŸÐ¿ÐžÑÐ°Ðœ Ð² <Reference target="importingpreviouslyassignedmetadata">ÐÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐž Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð²ÑÐ±ÑÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Reference>. 
+    </Section>
+    <Section name="deletingcollections">
+      <Title>Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹</Title>
+      <ObviousSentence>Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÑÐ°ÑÑÐºÐ°Ð·Ð°ÐœÐŸ, ÐºÐ°Ðº ÐœÐµÐžÐ·ÐŒÐµÐœÐœÐŸ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐ· ÐžÐœÑÑÐ°Ð»ÑÑÐžÐŸÐœÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž Greenstone.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            ÐÐ°Ðº ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+      ÐÐ»Ñ ÑÐŸÐ³ÐŸ, ÑÑÐŸÐ±Ñ ÐœÐµÐžÐ·ÐŒÐµÐœÐœÐŸ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐ· ÐžÐœÑÑÐ°Ð»ÑÑÐžÐŸÐœÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž Greenstone, Ð²ÑÐ±ÐµÑÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ..." ÐžÐ· ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»". ÐÑÐºÑÐŸÐµÑÑÑ ÑÐ¿ÐžÑÐŸÐº Ð²ÑÐµÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Greenstone. ÐÑÐ±ÐµÑÐžÑÐµ ÐœÑÐ¶ÐœÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÐ° ÐµÐµ ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ, Ð¿ÐŸÑÐ»Ðµ ÑÑÐŸÐ³ÐŸ Ð¿ÐŸÑÑÐ°Ð²ÑÐµ Ð³Ð°Ð»ÐŸÑÐºÑ Ð² Ð¿ÑÐœÐºÑÐµ Ð²ÐœÐžÐ·Ñ ÐŽÐžÐ°Ð»ÐŸÐ³Ð° Ðž ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° "Ð£ÐŽÐ°Ð»ÐžÑÑ", ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ. Ð­ÑÐ° ÐŸÐ¿ÐµÑÐ°ÑÐžÑ Ð±ÐµÐ·Ð²ÐŸÐ·Ð²ÑÐ°ÑÐœÐ°, Ð¿ÐŸÑÑÐŸÐŒÑ Ð¿ÑÐŸÐ²ÐµÑÑÑÐµ Ð²ÐœÐžÐŒÐ°ÑÐµÐ»ÑÐœÐŸ, ÐŽÐµÐ¹ÑÑÐ²ÐžÑÐµÐ»ÑÐœÐŸ Ð»Ðž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµÐœÑÐ¶ÐœÐ°!
+    </Section>
+  </Section>
+
+  <Section name="downloadingfiles">
+    <Title>ÐÐ°Ð³ÑÑÐ·ÐžÑÑ ÑÐ°Ð¹Ð»Ñ ÐžÐ· ÐžÐœÑÐµÑÐœÐµÑ</Title>
+    ÐÐžÐŽ "ÐÐµÑÐºÐ°Ð»ÐŸ" Ð¿ÐŸÐŒÐŸÐ¶ÐµÑ Ð²Ð°ÐŒ Ð·Ð°Ð³ÑÑÐ·ÐžÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐžÐ· ÐÐœÑÐµÑÐœÐµÑÐ°. ÐÐ°ÐœÐœÐ°Ñ ÑÐµÐºÑÐžÑ ÐŸÐ±ÑÑÑÐœÑÐµÑ Ð¿ÑÐŸÑÐµÑÑ Ð·ÐµÑÐºÐ°Ð»ÐžÑÐŸÐ²Ð°ÐœÐžÑ Ð² ÐÐœÑÐµÑÑÐµÐ¹ÑÐµ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°ÑÑ.
+    <Section name="themirrorview">
+      <Title>ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐÐ°Ð³ÑÑÐ·ÐžÑÑ</Title>
+      Ð­ÑÐ° ÑÐµÐºÑÐžÑ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑ ÐºÐ°Ðº ÐºÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÑÑ Ð·Ð°ÐŽÐ°ÑÑ Ðž ÐºÐŸÐœÑÑÐŸÐ»Ñ Ð¿ÑÐŸÑÐµÑÑÐ° Ð·Ð°Ð³ÑÑÐ·ÐºÐž.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+          ÐÐµÑÐµÐ²ÐŸ ÑÐ°Ð±ÐŸÑÐµÐ³ÐŸ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ð°
+	  </ContentsItem>
+          <ContentsItem>
+          ÐÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑ Ð·Ð°Ð³ÑÑÐ·ÐºÐž
+	  </ContentsItem>
+          <ContentsItem>
+          Ð¡Ð¿ÐžÑÐŸÐº Ð·Ð°Ð³ÑÑÐ·ÐºÐž
+	  </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+          Ð Ð°Ð·ÑÐµÑÐžÑÑ Ð¿ÑÐŸÐºÑÐž
+	  </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+      ÐÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐŸÑÐŒÐŸÑÑÑ "ÐÐ°Ð³ÑÑÐ·ÐžÑÑ" ÐœÐ°Ð¶Ð°ÑÐµÐŒ ÑÑÐŸÐ¹ Ð·Ð°ÐºÐ»Ð°ÐŽÐºÐž. ÐÐµÑÑ
+ÐœÑÑ Ð¿ÐŸÐ»ÐŸÐ²ÐžÐœÐ° ÑÐºÑÐ°ÐœÐ° Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐºÐŸÐœÑÑÐŸÐ»Ñ Ð·Ð°Ð³ÑÑÐ·ÐºÐž. ÐÐžÐ¶ÐœÑÑ Ð¿ÐŸÐ»ÐŸÐ²ÐžÐœÐ° Ð² ÐœÐ°ÑÐ°Ð»Ðµ Ð¿ÑÑÑÐ°, ÐŸÐŽÐœÐ°ÐºÐŸ Ð¿ÐŸÐºÐ°Ð¶ÐµÑ Ð¿ÐµÑÐµÑÐµÐœÑ ÐŸÐ¶ÐžÐŽÐ°ÐµÐŒÑÑ
+ Ðž Ð·Ð°ÐºÐŸÐœÑÐµÐœÐœÑÑ
+ Ð·Ð°Ð³ÑÑÐ·ÐŸÐº.
+      <Break/>
+      Ð€Ð°Ð¹Ð»Ñ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÑÐµ Ð² Ð¿Ð°Ð¿ÐºÑ ÑÐ°Ð±ÐŸÑÐµÐ³ÐŸ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ð° ÐœÐ°Ð·ÑÐ²Ð°ÑÑÑÑ "ÐÐ°Ð³ÑÑÐ¶Ð°ÐµÐŒÑÐµ ÑÐ°Ð¹Ð»Ñ" (ÑÐŸÐ»ÑÐºÐŸ ÑÐµÐ¹ÑÐ°Ñ ÐºÐŸÐ³ÐŽÐ° Ð·ÐµÑÐºÐ°Ð»ÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð²ÐºÐ»ÑÑÐµÐœÐŸ), Ðž ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐ° Ð²ÑÐµÐŒÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒÐž Ð¿ÐŸÑÑÑÐŸÐµÐœÐœÑÐŒÐž Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐÐœÑÐµÑÑÐµÐ¹ÑÐ° ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°ÑÑ. Ð€Ð°Ð¹Ð»Ñ Ð² ÑÑÐŸÐ¹ ÐŸÐ±Ð»Ð°ÑÑÐžÐžÐŒÐµÐœÑÑÑÑÑ Ð¿ÐŸ ÐžÑ
+ Ð¿ÐŸÐ»ÐœÐŸÐŒÑ URL Ð°ÐŽÑÐµÑÑ.  Ð¡ÐŸÐ·ÐŽÐ°ÐµÑÑÑ ÐœÐŸÐ²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° ÐœÐ° ÐºÐ°Ð¶ÐŽÐŸÐŒ Ñ
+ÐŸÑÑÐµ, ÐœÐ°ÑÐ»ÐµÐŽÑÐµÐŒÐ°Ñ ÐŽÑÑÐ³ÐžÐŒÐž ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÑÑÐ°Ð³ÐŒÐµÐœÑÐ° Ð¿ÑÑÐž.  Ð­ÑÐŸ Ð³Ð°ÑÐ°ÐœÑÐžÑÑÐµÑ ÐŸÑÐ»ÐžÑÐžÐµ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð°.
+      <Break/>
+      ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ Ð¿ÐµÑÐ²ÑÐ¹ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÑÑ
+ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐ¹ Ð·Ð°Ð³ÑÑÐ·ÐŸÐº, "Source URL",  ÑÑÐŸÐ±Ñ Ð²Ð²ÐµÑÑÐž URL Ð°ÐŽÑÐµÑ Ð² ÑÐµÐ»ÐµÐ²ÐŸÐ¹ ÑÐµÑÑÑÑ. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐŸÐœÑÑÐŸÐ»Ñ "ÐÐ»ÑÐ±ÐžÐœÑ ÐÐ°Ð³ÑÑÐ·ÐºÐž" ÐŽÐ»Ñ ÐŸÐ³ÑÐ°ÐœÐžÑÐµÐœÐžÑ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²Ð° Ð³ÐžÐ¿ÐµÑÑÑÑÐ»ÐŸÐº ÐŽÐ»Ñ Ð·Ð°Ð³ÑÑÐ·ÐºÐž: Ð£ÑÑÐ°ÐœÐŸÐ²ÐžÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ 0 ÐŽÐ»Ñ Ð·Ð°Ð³ÑÑÐ·ÐºÐž ÐŸÐŽÐœÐŸÐ¹ Ð²ÐµÐ± ÑÑÑÐ°ÐœÐžÑÑ; Ð·ÐœÐ°ÑÐµÐœÐžÐµ 1 ÑÑÐŸÐ±Ñ Ð·Ð°Ð³ÑÑÐ·ÐžÑÑ ÐŸÐŽÐœÑ ÑÑÑÐ°ÐœÐžÑÑ Ðž Ð²ÑÐµ ÑÑÑÐ°ÐœÐžÑÑ ÑÐ²ÑÐ·Ð°ÐœÐœÑÐµ Ñ ÐœÐµÐ¹ . Ð¿ÑÐµÐŽÐµÐ» Ð³Ð»ÑÐ±ÐžÐœÑ ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÑÐµÑÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐœÐ° html ÑÑÑÐ°ÐœÐžÑÑ. Ð¡Ð»ÐµÐŽÑÐ¹ÑÐµÐµ, Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐ° ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ "Ð³Ð°Ð»ÐŸÑÐµÐº", ÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ, ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ ÑÑÐŸÐ±Ñ ÑÑÐŸÐ±Ñ Ð²ÐºÐ»ÑÑÐžÑÑ ÑÐºÐ°Ð·Ð°ÐœÐœÑÑ ÐŸÑÐŸÐ±ÐµÐœÐœÐŸÑÑÑ ÐºÐŸÐœÐºÑÐµÑÐœÐŸÐ¹ Ð·Ð°Ð³ÑÑÐ·ÐºÐž. ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐ°, ÐœÐ°Ð¶ÐŒÐžÑÐµ "ÐÐ°Ð³ÑÑÐ·ÐºÐ°", ÑÑÐŸÐ±Ñ ÐœÐ°ÑÐ°ÑÑ ÐœÐŸÐ²ÑÑ Ð·Ð°Ð³ÑÑÐ·ÐºÑ. ÐÑÑÑ ÐŽÐ²Ðµ ÐŽÑÑÐ³ÐžÑ
+ ÐºÐœÐŸÐ¿ÐºÐž: Ð² ÑÐ°Ð·ÐŽÐµÐ»Ðµ "ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž", ÐºÐŸÑÐŸÑÑÐµ ÑÐ²ÑÐ·Ð°ÐœÑ Ñ ÑÐ°Ð·ÐŽÐµÐ»ÐŸÐŒ ÐœÐ°ÑÑÑÐŸÐ¹ÐºÐž ÑÐ²ÑÐ·Ðž, Ð³ÐŽÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ Ð¿ÑÐŸÐºÑÐž ÑÐµÑÐ²ÐµÑÐ° ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐžÐ·ÐŒÐµÐœÐµÐœÑ; Ðž "ÐÑÐžÑÑÐºÐ° ÐÑÑ", ÐºÐŸÑÐŸÑÐ°Ñ ÑÐŽÐ°Ð»ÑÐµÑ Ð²ÑÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ.
+      <Break/>
+      Ð¡Ð¿ÐžÑÐŸÐº Ð·Ð°Ð³ÑÑÐ·ÐºÐž ÐžÐŒÐµÐµÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ¹ Ð·Ð°Ð³ÑÑÐ¶Ð°ÐµÐŒÐŸÐ¹ Ð²ÐµÐ± ÑÑÑÐ°ÐœÐžÑÑ. ÐÐ°Ð¶ÐŽÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐŒÐµÐµÑ ÑÐµÐºÑÑ Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÑÑÐžÐ¹ ÐŽÐµÑÐ°Ð»Ðž Ð·Ð°ÐŽÐ°ÑÐž Ð²ÐŒÐµÑÑÐµ Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐŸÑÐŸÐŒ Ð¿ÑÐŸÐ³ÑÐµÑÑÐ° ÐŽÐµÐŒÐŸÐœÑÑÑÐžÑÑÑÑÐžÐŒ ÑÐµÐºÑÑÑÑ ÐŽÐµÑÑÐµÐ»ÑÐœÐŸÑÑÑ. Ð¢ÑÐž ÐºÐœÐŸÐ¿ÐºÐž Ð¿ÐŸÑÐ²Ð»ÑÑÑÑÑ ÑÐ»ÐµÐ²Ð° ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ. "ÐÐ°ÑÐ·Ð°" ÐŽÐ»Ñ Ð¿ÑÐžÐŸÑÑÐ°ÐœÐŸÐ²ÐºÐž Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐžÑ ÑÐµÐºÑÑÐµÐ³ÐŸ Ð¿ÑÐŸÑÐµÑÑÐ°. "Ð¡ÐŒÐŸÑÑÐµÑÑ ÐÐŸÐ³Ðž" ÐŸÑÐºÑÑÐ²Ð°ÐµÑ ÐŸÐºÐœÐŸ ÑÐ°Ð¹Ð»Ð° Ð·Ð°Ð³ÑÑÐ·ÐºÐž. "ÐÐ°ÐºÑÑÑÑ" Ð·Ð°Ð²ÐµÑÑÐ°ÐµÑ Ð·Ð°Ð³ÑÑÐ·ÐºÑ Ð·Ð°ÐŽÐ°ÑÐž ÐžÐ· ÑÐ¿ÐžÑÐºÐ°.
+      <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+      <Reference target="preferences">Ð¡ÐµÐºÑÐžÑ ÐÐ°ÑÑÑÐŸÐµÐº</Reference> ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑ ÐºÐ°Ðº ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐžÐœÑÐµÑÐœÐµÑ ÑÐŸÐµÐŽÐžÐœÐµÐœÐžÐµ ÑÐµÑÐµÐ· Ð¿ÑÐŸÐºÑÐž ÑÐµÑÐ²ÐµÑ.  ÐÑÐ»Ðž ÐœÑÐ¶ÐœÐ° ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐ°Ñ Ð°ÑÑÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÑ, Ð¿ÑÐŸÐºÑÐž ÑÐµÑÐ²ÐµÑ Ð·Ð°Ð¿ÑÐŸÑÐžÑ ÐžÐŒÑ Ðž Ð¿Ð°ÑÐŸÐ»Ñ.  ÐÐœÑÐµÑÑÐµÐ¹Ñ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°ÑÑ ÐœÐµ ÑÐŸÐ·ÑÐ°ÐœÑÐµÑ Ð¿Ð°ÑÐŸÐ»Ðž ÐŒÐµÐ¶ÐŽÑ ÑÐµÑÑÐžÑÐŒÐž.
+    </Section>
+  </Section>
+
+  <Section name="collectingfiles">
+    <Title>Ð¡Ð±ÐŸÑ ÑÐ°Ð¹Ð»ÐŸÐ² ÐŽÐ»Ñ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title>
+ ÐÑÐ»Ðž ÐÑ ÑÐŸÐ·ÐŽÐ°ÐµÑÐµ ÐœÐŸÐ²ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ,ÑÐŸ Ð²ÐŸÐ·ÐœÐžÐºÐ°ÐµÑ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÑÑÑ Ð²Ð²ÐŸÐŽÐ° Ð² ÐœÐµÐµ ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ².ÐÐœÐž ÐŒÐŸÐ³ÑÑ Ð¿ÐŸÑÑÑÐ¿ÐžÑÑ ÐžÐ· Ð²Ð°ÑÐµÐ³ÐŸ ÐŸÐ±ÑÑÐœÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ³ÐŸ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ð° ÐžÐ· ÐŽÑÑÐ³ÐžÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Greenstone. ÐÐµÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ ÑÐ¶Ðµ ÐžÐŒÐµÑÑ Ð¿ÑÐžÑÐŸÐµÐŽÐžÐœÐµÐœÐœÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ.Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ,ÐºÐ°Ðº ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐ°Ð¹Ð»Ñ.
+    <Section name="thegatherview">
+      <Title>ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐœÐ°ÐºÐŸÐ¿ÐžÑÐµÐ»Ñ</Title>
+ Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» Ð²Ð²ÐŸÐŽÐžÑ Ð² ÐŸÐ±Ð»Ð°ÑÑÑ ÐœÐ°ÐºÐŸÐ¿Ð»ÐµÐœÐžÑ,ÐºÐŸÑÐŸÑÑÑ ÐÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÐµ,ÑÑÐŸÐ±Ñ Ð²ÑÐ±ÑÐ°ÑÑ,ÐºÐ°ÐºÐžÐµ ÑÐ°Ð¹Ð»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð² ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÐµÐŒÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            ÐÐ°Ðº Ð¿ÑÐŸÑÐŒÐ°ÑÑÐžÐ²Ð°ÑÑ ÑÐºÑÐ°Ðœ ÐœÐ°ÐºÐŸÐ¿Ð»ÐµÐœÐžÑ 
+            </ContentsItem>
+          <ContentsItem>
+             Ð€Ð°Ð¹Ð»ÐŸÐ²ÐŸÐµ ÐŽÐµÑÐµÐ²ÐŸ
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐ±Ð»Ð°ÑÑÑ ÑÐŸÑÑÐŸÑÐœÐžÑ
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐœÐŸÐ¿ÐºÐž ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+             ÐÐµÑÐŸÐŽÑ ÐŸÑÐ±ÐŸÑÐ°
+          </ContentsItem>
+          <ContentsItem>
+             Ð¡Ð¿ÐµÑÐžÐ°Ð»ÑÐœÐ°Ñ Ð¿Ð°Ð¿ÐºÐ° ÐŸÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐœÐ°ÑÐžÐœÐ°ÐµÑÑÑ Ñ ÐŸÐ±Ð·ÐŸÑÐ° ÐœÐ°ÐºÐŸÐ¿Ð»ÐµÐœÐžÑ. Ð§ÑÐŸÐ±Ñ Ð²ÐµÑÐœÑÑÑÑÑ Ðº ÑÑÐŸÐŒÑ ÐŸÐ±Ð·ÐŸÑÑ Ð¿ÐŸÐ·Ð¶Ðµ,ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÑÐžÐŒÐ²ÐŸÐ»Ðµ "Gather", ÑÐ°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐœÑÐŒ ÐœÐµÐ¿ÐŸÑÑÐµÐŽÑÑÐ²ÐµÐœÐœÐŸ ÐœÐžÐ¶Ðµ Ð»ÐžÐœÐµÐ¹ÐºÐž ÐŒÐµÐœÑ.  
+<Break/>
+ÐÐ²Ðµ Ð±ÐŸÐ»ÑÑÐžÐµ ÐŸÐ±Ð»Ð°ÑÑÐž,ÐœÐ°Ð·Ð²Ð°ÐœÐœÑÐµ "Ð Ð°Ð±ÐŸÑÐµÐµ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²ÐŸ" Ðž "ÐoÐ»Ð»ÐµÐºÑÐžÑ" ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ,ÑÑÐŸÐ±Ñ Ð¿ÐµÑÐµÐŒÐµÑÑÐžÑÑ ÑÐ°Ð¹Ð»Ñ Ð² ÐÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ. ÐÐœÐž Ð²ÐºÐ»ÑÑÐ°ÑÑ "ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐµ ÐŽÐµÑÐµÐ²ÐŸ",Ð³ÑÐ°ÑÐžÑÐµÑÐºÐžÐµ ÑÑÑÑÐºÑÑÑÑ,ÐºÐŸÑÐŸÑÑÐµ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶Ð°ÑÑ ÑÐ°Ð¹Ð»Ñ Ðž Ð¿Ð°Ð¿ÐºÐž. 
+<Break/>
+ÐÑÐ±ÐµÑÐžÑÐµ ÑÐ»ÐµÐŒÐµÐœÑ ÐŽÐµÑÐµÐ²Ð°, ÐœÐ°Ð¶Ð°Ð² ÐœÐ° ÐœÐµÐ³ÐŸ Ð»ÐµÐ²ÐŸÐ¹ ÐºÐ»Ð°Ð²ÐžÑÐµÐ¹ ÐŒÑÑÐž. (Ð¢ÐŸ Ð¶Ðµ ÑÐ°ÐŒÐŸÐµ ÐŒÐŸÐ¶ÐœÐŸ ÑÐŽÐµÐ»Ð°ÑÑ ÐžÐœÐ°ÑÐµ, ÑÐŒ. ÐœÐžÐ¶Ðµ). ÐÐ²ÐŸÐ¹ÐœÑÐŒ ÑÐµÐ»ÑÐºÐŸÐŒ Ð²ÑÐ±ÐµÑÐžÑÐµ Ð¿Ð°Ð¿ÐºÑ, ÐžÐ»Ðž ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° ÑÐžÐŒÐ²ÐŸÐ» ÑÑÐŽÐŸÐŒ Ñ ÐœÐµÐ¹, ÑÑÐŸÐ±Ñ ÑÐ°Ð·Ð²ÐµÑÐœÑÑÑ (ÐžÐ»Ðž ÑÐ²ÐµÑÐœÑÑÑ) ÐµÐµ ÑÐŸÐŽÐµÑÐ¶ÐžÐŒÐŸÐµ. ÐÐ²ÐŸÐ¹ÐœÑÐŒ ÑÐµÐ»ÑÐºÐŸÐŒ ÐœÐ° ÐœÑÐ¶ÐœÐŸÐŒ ÑÐ°Ð¹Ð»Ðµ ÐŸÑÐºÑÐŸÐ¹ÑÐµ ÐµÐ³ÐŸ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÐŸÐ¹ ÐŽÐ°ÐœÐœÐŸÐŒÑ ÑÐžÐ¿Ñ ÑÐ°Ð¹Ð»ÐŸÐ² Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ (ÑÐŒ.<Reference target="fileassociations">ÐÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÐµ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ</Reference>).
+<Break/>
+ÐÐµÑÐµÐ²ÐŸ ÑÐ°Ð±ÐŸÑÐµÐ³ÐŸ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ð° Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐžÑÑÐŸÑÐœÐžÐºÐž ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐŸÑÑÑÐ¿ÐœÑÑ
+ Ð² ÐÐœÑÐµÑÑÐµÐ¹ÑÐµ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°ÑÑ -- ÑÐµÐºÑÑÑÑ ÑÐ°Ð¹Ð»ÐŸÐ²ÑÑ ÑÐžÑÑÐµÐŒÑ (Ð²ÐºÐ»ÑÑÐ°Ñ ÐŽÐžÑÐºÐŸÐ²ÐŸÐŽ Ðž CD-ROM), ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÐÑÐžÐœÑÑÐŸÑÐœ, Ðž ÐºÑÑ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ², Ð¿ÑÐž ÑÑÐ»ÐŸÐ²ÐžÐž Ð²ÐºÐ»ÑÑÐµÐœÐžÑ Ð²ÐµÐ± Ð·ÐµÑÐºÐ°Ð»ÐžÑÐŸÐ²Ð°ÐœÐžÑ. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÐžÐŽÐµÑÑ Ðž ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÑÑ ÑÑÐž ÑÐ°Ð¹Ð»Ñ, ÐŸÐŽÐœÐ°ÐºÐŸ ÐœÐµ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐµÑÐµÐœÐŸÑÐžÑÑ, ÑÐŽÐ°Ð»ÑÑÑ, ÐžÐ»Ðž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐžÑ
+, Ð·Ð° ÐžÑÐºÐ»ÑÑÐµÐœÐžÐµÐŒ ÑÐ¶Ðµ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐŽÐ°Ð»ÐµÐœÑ.  ÐÑÑÑÐµÑÑÐ²Ð»ÑÑÑ ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÑ Ð² ÑÑÐŸÐŒ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ðµ ÑÑÐŸÐ±Ñ ÐœÐ°Ð¹ÑÐž ÑÐ°Ð¹Ð»Ñ ÐºÐŸÑÐŸÑÑÐµ Ð²Ñ Ñ
+ÐŸÑÐžÑÐµ Ð²ÐºÐ»ÑÑÐžÑÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+<Break/>
+Ð€Ð°Ð¹Ð»ÐŸÐ²ÐŸÐµ ÐŽÐµÑÐµÐ²ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÑÐµÑ Ð¿ÐŸÐ»ÐœÐŸÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐµÑÐ²ÐŸÐœÐ°ÑÐ°Ð»ÑÐœÐŸ ÐŸÐœÐŸ Ð¿ÑÑÑÐŸ.
+<Break/>
+ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÑÐ°Ð·ÐŒÐµÑÑ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ð°, Ð¿ÐµÑÐµÐŽÐ²ÐžÐ³Ð°Ñ ÐŒÑÑÑ Ð¿ÐŸ ÑÐµÑÐŸÐ¹ Ð»ÐžÐœÐµÐ¹ÐºÐµ, ÐºÐŸÑÐŸÑÐ°Ñ ÐŸÑÐŽÐµÐ»ÑÐµÑ ÐŽÐµÑÐµÐ²ÑÑ (ÑÐŸÑÐŒÐ° ÑÐºÐ°Ð·Ð°ÑÐµÐ»Ñ ÐžÐ·ÐŒÐµÐœÑÐµÑÑÑ),Ðž Ð±ÑÐºÑÐžÑÑÑ ÐžÑ
+.
+<Break/>
+ÐÐœÐžÐ·Ñ ÐŸÐºÐœÐ° ÑÐ°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐ° ÑÑÐ°ÑÑÑÐœÐ°Ñ ÐŸÐ±Ð»Ð°ÑÑÑ, ÐºÐŸÑÐŸÑÐ°Ñ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð¿ÑÐŸÐ³ÑÐµÑÑ ÐŸÐ¿ÐµÑÐ°ÑÐžÐ¹ ÐœÐ°ÐŽ ÑÐ°Ð¹Ð»Ð°ÐŒÐž (ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÐµ, Ð¿ÐµÑÐµÐŒÐµÑÐµÐœÐžÐµ, ÑÐŽÐ°Ð»ÐµÐœÐžÐµ). ÐÐœÐž ÐŒÐŸÐ³ÑÑ Ð·Ð°ÐœÑÑÑ ÐºÐ°ÐºÐŸÐµ-ÑÐŸ Ð²ÑÐµÐŒÑ. ÐÐœÐŸÐ¿ÐºÐ° "Ð¡ÑÐŸÐ¿" ÐŸÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÐµÑ Ð»ÑÐ±ÐŸÐµ ÐŽÐµÐ¹ÑÑÐ²ÐžÐµ, ÐºÐŸÑÐŸÑÐŸÐµ Ð² ÐœÐ°ÑÑÐŸÑÑÐµÐµ Ð²ÑÐµÐŒÑ Ð¿ÑÐŸÐžÑÑ
+ÐŸÐŽÐžÑ. 
+<Break/>
+ ÐÐ²Ðµ Ð±ÐŸÐ»ÑÑÐžÐµ ÐºÐœÐŸÐ¿ÐºÐž Ð·Ð°ÐœÐžÐŒÐ°ÑÑ ÐœÐžÐ¶ÐœÐžÐ¹ Ð¿ÑÐ°Ð²ÑÐ¹ ÑÐ³ÐŸÐ» ÑÐºÑÐ°ÐœÐ°."ÐÐŸÐ²Ð°Ñ ÐÐ°Ð¿ÐºÐ°",Ñ ÐºÐ°ÑÑÐžÐœÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐž, ÑÐŸÐ·ÐŽÐ°ÑÑ ÐœÐŸÐ²ÑÐµ Ð¿Ð°Ð¿ÐºÐž (ÑÐŒ. <Reference target="creatingfolders">Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿Ð°Ð¿ÐŸÐº</Reference>). ÐÐœÐŸÐ¿ÐºÐ° "Ð£ÐŽÐ°Ð»ÐžÑÑ"ÑÐŽÐ°Ð»ÑÐµÑ ÑÐ°Ð¹Ð»Ñ Ñ ÐœÐµÐœÑÐ¶ÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐµÐ¹.Ð©ÐµÐ»ÑÐŸÐº ÐœÐ° ÐºÐœÐŸÐ¿ÐºÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ" ÑÐŽÐ°Ð»ÐžÑ Ð»ÑÐ±ÑÐµ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ³ÐŸ ÐŽÐµÑÐµÐ²Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐ»ÑÑÐµÑÐœÐ°ÑÐžÐ²ÐœÐŸ, ÑÐ°Ð¹Ð»Ñ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐŽÐ°Ð»ÐµÐœÑ Ð¿ÑÑÐµÐŒ Ð¿ÐµÑÐµÑÑÐ³ÐžÐ²Ð°ÐœÐžÑ ÐžÑ
+ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÑ "Ð£ÐŽÐ°Ð»ÐžÑÑ". 
+       <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð§ÑÐŸÐ±Ñ ÐŸÑÐŸÐ±ÑÐ°ÑÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ Ð¿ÐŸÑÐ»ÐµÐŽÐŸÐ²Ð°ÑÐµÐ»ÑÐœÑÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ²,Ð²ÑÐ±ÐµÑÐžÑÐµ Ð¿ÐµÑÐ²ÑÐ¹ Ðž Ð·Ð°ÑÐµÐŒ ÑÐŽÐµÑÐ¶ÐžÐ²Ð°Ñ [Shift],ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° Ð¿ÐŸÑÐ»ÐµÐŽÐœÐµÐŒ - Ð¿ÑÐž ÑÑÐŸÐŒ Ð±ÑÐŽÑÑ ÐŸÑÐŸÐ±ÑÐ°ÐœÑ Ð²ÑÐµ ÐŸÑ
+Ð²Ð°ÑÐµÐœÐœÑÐµ ÑÐ»ÐµÐŒÐµÐœÑÑ.ÐÑÐ±ÐŸÑ ÐœÐµ ÑÐ»ÐµÐŽÑÑÑÐžÑ
+ ÐŸÐŽÐžÐœ Ð·Ð° ÐŽÑÑÐ³ÐžÐŒ ÑÐ°Ð¹Ð»ÐŸÐ² Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑÑÑ Ð¿ÑÐž ÐœÐ°Ð¶Ð°ÑÐŸÐ¹ ÐºÐ»Ð°Ð²ÐžÑÐµ [Ctrl] Ðž ÑÐµÐ»ÑÐºÐµ ÐœÐ° Ð²ÑÐ±ÐžÑÐ°ÐµÐŒÑÑ
+ ÑÐ°Ð¹Ð»Ð°Ñ
+. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÑÑÐž ÐŽÐ²Ð° ÐŒÐµÑÐŸÐŽÐ° Ð²ÐŒÐµÑÑÐµ ÐŽÐ»Ñ Ð³ÑÑÐ¿Ð¿Ñ ÐœÐµÑÐŒÐµÐ¶ÐœÑÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ².  
+<Break/>
+ ÐÐµÐºÐŸÑÐŸÑÑÐµ Ð¿Ð°Ð¿ÐºÐž - ÑÐžÐ¿Ð° ÑÐµÑ
+,ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ ÐÐ°ÑÐž ÑÐŸÐ±ÑÑÐ²ÐµÐœÐœÑÐµ Ð²ÐµÐ±-ÑÑÑÐ°ÐœÐžÑÑ - ÐžÐœÐŸÐ³ÐŽÐ° ÐžÐŒÐµÑÑ ÐŸÑÐŸÐ±ÑÑ Ð²Ð°Ð¶ÐœÐŸÑÑÑ.ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð¿ÐµÑÐµÐœÐµÑÑÐž ÑÐ°ÐºÐžÐµ Ð¿Ð°Ð¿ÐºÐž ÐœÐ° Ð¿ÐµÑÐ²ÑÐ¹ ÑÑÐŸÐ²ÐµÐœÑ ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ³ÐŸ ÐŽÐµÑÐµÐ²Ð°. Ð§ÑÐŸÐ±Ñ ÑÐŽÐµÐ»Ð°ÑÑ ÑÑÐŸ, ÑÐµÐ»ÐºÐœÐžÑÐµ Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐŸÐ¹ ÐŒÑÑÐž ÐœÐ° Ð¶ÐµÐ»Ð°ÑÐµÐ»ÑÐœÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐµ. ÐÑÐ±ÐµÑÐžÑÐµ "Ð¡ÐŸÐ·ÐŽÐ°ÑÑ ÑÐŸÐºÑÐ°ÑÐµÐœÐžÐµ" Ðž Ð²Ð²ÐµÐŽÐžÑÐµ ÐžÐŒÑ ÐŽÐ»Ñ Ð¿Ð°Ð¿ÐºÐž. ÐÐ»Ñ ÑÐŽÐ°Ð»ÐµÐœÐžÑ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÑÐµÐ»ÐºÐœÐžÑÐµ Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐŸÐ¹ ÐŒÑÑÐž ÐœÐ° Ð¿ÐŸÐŒÐµÑÐµÐœÐœÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐµ Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐŸÐºÑÐ°ÑÐµÐœÐžÑ".
+    </Section>
+    <Section name="creatingfolders">
+      <Title>Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿Ð°Ð¿ÐŸÐº</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ, ÐºÐ°Ðº ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÑÑ ÐœÐŸÐ²ÑÐµ Ð¿Ð°Ð¿ÐºÐž
+</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐœÐŸÐ¿ÐºÐ° ÐœÐŸÐ²ÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐž
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐµÐœÑ Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐž ÐŒÑÑÐž
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ "ÐÐ°Ð¿ÐºÐž" Ð² ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐŒ ÐŽÐµÑÐµÐ²Ðµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÑÑÐŸÐ±Ñ Ð³ÑÑÐ¿Ð¿ÐžÑÐŸÐ²Ð°ÑÑ Ð²ÐŒÐµÑÑÐµ Ðž Ð±ÐŸÐ»ÐµÐµ Ð»ÐµÐ³ÐºÐŸ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑ ÐžÑ
+. ÐÐ°Ð¿ÐºÐž ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ Ð¿ÐŸÐŒÐµÑÐµÐœÑ Ð²ÐœÑÑÑÐž Ð¿Ð°Ð¿ÐŸÐº. Ð€Ð°ÐºÑÐžÑÐµÑÐºÐž ÐœÐµÑ ÐŸÐ³ÑÐ°ÐœÐžÑÐµÐœÐžÑ ÐœÐ° ÑÐŸ,ÑÐºÐŸÐ»ÑÐºÐŸ Ð¿Ð°Ð¿ÐŸÐº ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÐŒÐµÑÑ ÐžÐ»Ðž ÐºÐ°Ðº Ð³Ð»ÑÐ±ÐŸÐºÐŸ ÐŸÐœÐž ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ Ð²Ð»ÐŸÐ¶ÐµÐœÑ.
+<Break/>
+  Ð§ÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐœÐŸÐ²ÑÑ Ð¿Ð°Ð¿ÐºÑ, Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐ»ÑÐœÐŸ Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÑÑ Ð¿Ð°Ð¿ÐºÑ Ð² ÐÐµÑÐµÐ²Ðµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÐµ "ÐÐŸÐ²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°". ÐÐŸÐ²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ ÐžÐ»Ðž ÐœÐ° Ð²ÑÑÑÐµÐŒ ÑÑÐŸÐ²ÐœÐµ,ÐµÑÐ»Ðž ÐœÐž ÐŸÐŽÐœÐ° ÐœÐµ ÐŸÑÐŸÐ±ÑÐ°ÐœÐ°.ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÑÐŸÑÐ²ÐŸÐžÑÑ Ð¿Ð°Ð¿ÐºÐµ ÐžÐŒÑ (Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ "ÐÐŸÐ²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°").
+<Break/>
+ ÐÐ°Ð¿ÐºÐž ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐ°ÐºÐ¶Ðµ ÑÐŸÐ·ÐŽÐ°ÐœÑ ÑÐµÐ»ÑÐºÐŸÐŒ Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐž ÐŒÑÑÐž Ð¿ÐŸ Ð¿Ð°Ð¿ÐºÐµ,Ð²ÑÐ±ÐžÑÐ°Ñ "ÐÐŸÐ²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°" Ðž ÐŽÐµÐ¹ÑÑÐ²ÑÑ,ÐºÐ°Ðº ÑÐºÐ°Ð·Ð·Ð°ÐœÐŸ Ð²ÑÑÐµ.
+    </Section>
+    <Section name="addingfiles">
+      <Title>ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÐŸ,ÐºÐ°Ðº Ð²Ð²ÐµÑÑÐž ÑÐ°Ð¹Ð»Ñ Ð² ÐÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ </ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐµÑÐµÐŒÐµÑÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð°
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐœÐŸÐ¶ÐµÑÑÐ²ÐµÐœÐœÑÐµ(ÑÐŸÑÑÐ°Ð²ÐœÑÐµ) ÑÐ°Ð¹Ð»Ñ
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+             Ð¡ÑÑÐµÑÑÐ²ÑÑÑÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð€Ð°Ð¹Ð»Ñ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŒÑÑÑÑ Ð¿ÑÑÐµÐŒ ÐžÑ
+ Ð¿ÐµÑÐµÑÑÐ³ÐžÐ²Ð°ÐœÐžÑ Ðž ÐŸÑÐ¿ÑÑÐºÐ°ÐœÐžÑ. Ð£ÐºÐ°Ð·Ð°ÑÐµÐ»Ñ ÐŒÑÑÐž ÐŸÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÐµÑÑÑ ÐœÐ°ÐŽ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÐŒ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐŒ ÐžÐ»Ðž, ÐµÑÐ»Ðž Ð²ÑÐ±ÐžÑÐ°ÐµÑÑÑ Ð±ÐŸÐ»ÑÑÐµ,ÑÐµÐŒ ÐŸÐŽÐžÐœ,ÐœÐ°ÐŽ ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÐŒÐž. ÐÑÐŸÐ¿ÑÑÑÐžÑÐµ Ð²ÑÐ±ÑÐ°ÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» Ð² ÐÐµÑÐµÐ²ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÑÑÐŸÐ±Ñ Ð·ÐŽÐµÑÑ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÑÑ ÑÐ°Ð¹Ð»Ñ (ÐµÑÐ»Ðž ÐžÑÑÐŸÑÐœÐžÐºÐŸÐŒ Ð±ÑÐ»ÐŸ ÐÐµÑÐµÐ²ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž).
+<Break/>
+  ÐÑÐž ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÐž ÐŒÐœÐŸÐ¶ÐµÑÑÐ²ÐµÐœÐœÑÑ
+(ÑÐŸÑÑÐ°Ð²ÐœÑÑ
+) ÑÐ°Ð¹Ð»ÐŸÐ²,Ð²ÑÐµ ÐŸÐœÐž Ð¿ÐµÑÐµÐŒÐµÑÐ°ÑÑÑÑ Ð² ÑÐµÐ»ÐµÐ²ÑÑ Ð¿Ð°Ð¿ÐºÑ ÐœÐ° ÑÐŸÑ Ð¶Ðµ ÑÐ°ÐŒÑÐ¹ ÑÑÐŸÐ²ÐµÐœÑ,ÐœÐµÐ·Ð°Ð²ÐžÑÐžÐŒÐŸ ÐŸÑ ÑÑÑÑÐºÑÑÑÑ Ð¿Ð°Ð¿ÐºÐž,ÐºÐŸÑÐŸÑÑÑ ÐŸÐœÐž Ð·Ð°ÐœÐžÐŒÐ°Ð»Ðž Ð¿ÐµÑÐ²ÐŸÐœÐ°ÑÐ°Ð»ÑÐœÐŸ. ÐÐŸÐ³ÐŽÐ° ÐÑ ÐºÐŸÐ¿ÐžÑÑÐµÑÐµ Ð²ÑÐŸÑÐŸÐ¹ ÑÐ°Ð¹Ð» Ñ ÑÐµÐŒ Ð¶Ðµ ÑÐ°ÐŒÑÐŒ ÐžÐŒÐµÐœÐµÐŒ Ð² ÑÑ Ð¶Ðµ ÑÐ°ÐŒÑÑ Ð¿Ð°Ð¿ÐºÑ, ÐÐ°Ñ Ð·Ð°Ð¿ÑÐŸÑÑÑ, Ð·Ð°ÑÐµÑÐµÑÑ Ð»Ðž Ð¿ÐµÑÐ²ÑÐ¹. ÐÑÐ²ÐµÑÑÑÐµ "ÐÐµÑ" Ðž ÑÑÐŸÑ ÑÐ°Ð¹Ð» ÐœÐµ Ð±ÑÐŽÐµÑ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÑÑÑÑ,ÐœÐŸ ÐŽÑÑÐ³ÐžÐµ Ð±ÑÐŽÑÑ. Ð§ÑÐŸÐ±Ñ ÐŸÑÐŒÐµÐœÐžÑÑ Ð²ÑÐµ ÐŸÑÑÐ°ÑÑÐžÐµÑÑ ÐŽÐµÐ¹ÑÑÐ²ÐžÑ Ð¿ÐŸ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÐµ "Ð¡ÑÐŸÐ¿".   <Break/>
+ Ð¢ÐŸÐ»ÑÐºÐŸ "ÑÐ°ÐŒÑÐµ Ð²ÑÑÐŸÐºÐžÐµ"ÐžÐ· ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² Ð±ÑÐŽÑÑ Ð¿ÐµÑÐµÐŒÐµÑÐµÐœÑ. ÐÐ°Ð¿ÐºÐ° Ð²ÑÑÐµ, ÑÐµÐŒ ÐµÑ Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐœÑÐµ. ÐÑ ÐœÐµ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ ÑÐ°Ð¹Ð»Ñ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ Ð¿Ð°Ð¿ÐºÐž,Ð° ÑÐ°ÐºÐ¶Ðµ ÑÐ°ÐŒÑ Ð¿Ð°Ð¿ÐºÑ ÐœÐµÐ¿ÐŸÑÑÐµÐŽÑÑÐ²ÐµÐœÐœÐŸ. 
+      <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÐŸÐ³ÐŽÐ° ÐÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÐµ ÑÐ°Ð¹Ð», ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð¿ÑÐŸÐ²ÐŸÐŽÐžÑ Ð¿ÐŸÐžÑÐº Ð² ÐžÑÑ
+ÐŸÐŽÐœÑÑ
+ Ð¿Ð°Ð¿ÐºÐ°Ñ
+ Ð²ÑÐ¿ÐŸÐŒÐŸÐ³Ð°ÑÐµÐ»ÑÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ², ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐžÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ Ðº ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÐŒÐŸÐŒÑ ÑÐ°Ð¹Ð»Ñ,Ðž ÐµÑÐ»Ðž ÐŸÐœ ÐœÐ°Ñ
+ÐŸÐŽÐžÑ ÐµÐ³ÐŸ,ÑÐŸ ÐœÐ°ÑÐžÐœÐ°ÐµÑ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÑÑÐž ÐŽÐ°ÐœÐœÑÐµ. ÐÑÐ»Ðž Ð¿ÑÐŸÑÐµÑÑ Ð¿ÑÐŸÐŽÐŸÐ»Ð¶Ð°ÐµÑÑÑ,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð±ÑÑÑ Ð·Ð°Ð¿ÑÐŸÑÐµÐœÑ (Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÑÐ°Ð·) ÐŸ ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž,ÑÑÐŸÐ±Ñ ÐŽÐŸÑÑÐžÑÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÑ ÐžÐŒÐ¿ÐŸÑÑÐžÑÑÐµÐŒÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ñ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž,ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐœÑÐŒÐž Ð² ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð­ÑÐŸÑ Ð¿ÑÐŸÑÐµÑÑ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÐŒÐœÐŸÐ³ÐžÐµ ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ Ð·Ð°Ð¿ÑÐŸÑÑ, ÐŸÐ¿ÐžÑÐ°ÐœÐœÑÐµ Ð² ÑÐ°Ð·ÐŽÐµÐ»Ðµ<Reference target="importingpreviouslyassignedmetadata">ÐÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Reference>.ÐÐ»Ñ Ð±ÐŸÐ»ÐµÐµ ÐŽÐµÑÐ°Ð»ÑÐœÐŸÐ³ÐŸ ÐŸÐ±ÑÑÑÐœÐµÐœÐžÑ Ð°ÑÑÐŸÑÐžÐžÑÐŸÐ²Ð°ÐœÐœÑÑ
+ Ñ ÑÐ°Ð¹Ð»Ð°ÐŒÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÑÐžÑÐ°Ð¹ÑÐµ ÐÐ»Ð°Ð²Ñ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone - ÐÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ Ð±ÐŸÐ»ÑÑÐžÐœÑÑÐ²Ð° Ð²Ð°ÑÐžÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ².  
+     </Section>
+    <Section name="removingfiles">
+      <Title>Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ,ÐºÐ°Ðº ÑÐŽÐ°Ð»ÑÑÑ ÑÐ°Ð¹Ð»Ñ Ðž Ð¿Ð°Ð¿ÐºÐž ÐžÐ· ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.  
+</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐœÐŸÐ¿ÐºÐ° ÑÐŽÐ°Ð»ÐµÐœÐžÑ
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐ»Ð°Ð²ÐžÑÐ° ÑÐŽÐ°Ð»ÐµÐœÐžÑ
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ Ð¿ÑÑÐµÐŒ Ð¿ÐµÑÐµÑÑÐ³ÐžÐ²Ð°ÐœÐžÑ Ðž ÐŸÑÐ¿ÑÑÐºÐ°ÐœÐžÑ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð¡ÑÑÐµÑÑÐ²ÑÐµÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÐŒÐµÑÐŸÐŽÐŸÐ² ÑÐŽÐ°Ð»ÐµÐœÐžÑ ÑÐ°Ð¹Ð»ÐŸÐ² Ðž Ð¿Ð°Ð¿ÐŸÐº. ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ ÑÐœÐ°ÑÐ°Ð»Ð° ÑÐºÐ°Ð·Ð°ÑÑ,ÐºÐ°ÐºÐžÐµ ÐžÐ· ÐœÐžÑ
+ ÑÐŽÐ°Ð»ÑÑÑ, Ð²ÑÐ±ÐžÑÐ°Ñ ÐŸÐŽÐžÐœ ÐžÐ»Ðž Ð±ÐŸÐ»ÐµÐµ ÑÐ°Ð¹Ð»ÐŸÐ² Ðž Ð¿Ð°Ð¿ÐŸÐº, ÐºÐ°Ðº ÐŸÐ¿ÐžÑÐ°ÐœÐŸ Ð² <Reference target="thegatherview">ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐœÐ°ÐºÐŸÐ¿Ð»ÐµÐœÐžÐ¹</Reference>.
+<Break/>
+ ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÑÐ°Ð¹Ð»Ñ ÐŸÑÐŸÐ±ÑÐ°ÐœÑ, ÐŽÐ»Ñ ÐžÑ
+ ÑÐŽÐ°Ð»ÐµÐœÐžÑ ÑÐµÐ»ÐºÐ°ÑÑ ÐºÐœÐŸÐ¿ÐºÑ "Ð£ÐŽÐ°Ð»ÐžÑÑ"ÐžÐ»Ðž ÐœÐ°Ð¶ÐžÐŒÐ°ÑÑ ÐºÐºÐ»Ð°Ð²ÐžÑÑ [Ð£ÐŽÐ°Ð»ÐžÑÑ] ÐœÐ° ÐºÐ»Ð°Ð²ÐžÐ°ÑÑÑÐµ, ÐžÐ»Ðž Ð¶Ðµ ÑÑÐœÑÑ ÐžÑ
+ ÐžÐ· ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŽÐŸ ÐºÐœÐŸÐ¿ÐºÐž "Ð£ÐŽÐ°Ð»ÐžÑÑ" Ðž ÑÐ°ÐŒ ÐŸÑÐ¿ÑÑÐºÐ°ÑÑ.  
+    </Section>
+    <Section name ="filteringthetree">
+      <Title>Ð€ÐžÐ»ÑÑÑÐŸÐ²Ð°ÐœÐžÐµ ÐŽÐµÑÐµÐ²Ð°</Title>
+"Ð€ÐžÐ»ÑÑÑÐŸÐ²Ð°ÐœÐžÐµ" ÐŽÐµÑÐµÐ²Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐÐ°ÐŒ ÑÑÐ¶Ð°ÑÑ Ð¿ÐŸÐžÑÐº ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ².
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            Ð£Ð¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐžÐ»ÑÑÑÐŸÐŒ
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+              ÐÐ°ÑÑÑÐŸÐ¹ÐºÐ° ÑÐžÐ»ÑÑÑÐ°
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents >
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ÐÑÐœÐºÑ "ÐÐŸÐºÐ°Ð·Ð°ÑÑ ÑÐ°Ð¹Ð»Ñ" Ð² ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐŒ ÐŒÐµÐœÑ Ð¿ÐŸÐŽ ÐºÐ°Ð¶ÐŽÑÐŒ ÐŽÐµÑÐµÐ²ÐŸÐŒ Ð²ÑÐ²ÐŸÐŽÐžÑ ÑÐ¿ÐžÑÐŸÐº Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÑÑ
+ ÑÐžÐ»ÑÑÑÐŸÐ² ÑÐžÐ¿Ð° "Images".ÐÑÐ±ÐµÑÐžÑÐµ Ðž Ð²ÑÐµ Ð²ÑÐµÐŒÐµÐœÐœÐŸ ÑÐºÑÑÑÑÐµ ÑÐ°Ð¹Ð»Ñ Ð² ÐŽÐµÑÐµÐ²Ðµ.Ð§ÑÐŸÐ±Ñ Ð²ÐŸÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐŽÐµÑÐµÐ²ÐŸ,Ð·Ð°ÐŒÐµÐœÐžÑÐµ ÑÐžÐ»ÑÑÑ ÑÐœÐŸÐ²Ð° ÐœÐ° "ÐÑÐµ ÑÐ°Ð¹Ð»Ñ".Ð­ÑÐž ÐŽÐµÐ¹ÑÑÐ²ÐžÑ ÐœÐµ ÐžÐ·ÐŒÐµÐœÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž Ð¿ÑÐž ÑÑÐŸÐŒ ÐŸÐœÐž ÐœÐµ Ð·Ð°ÑÑÐ°Ð³ÐžÐ²Ð°ÑÑ Ð¿Ð°Ð¿ÐºÐž Ð² ÐŽÐµÑÐµÐ²Ðµ. 
+      <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð·Ð°ÐŽÐ°ÑÑ ÐœÐ°ÑÑÑÐŸÐ¹ÐºÑ ÑÐžÐ»ÑÑÑÐ°,ÐœÐ°Ð¿ÐµÑÐ°ÑÐ°Ð² Ð² ÑÑ
+ÐµÐŒÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ².ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÑÑÐ°ÐœÐŽÐ°ÑÑÐœÑÐµ Ð°Ð±Ð±ÑÐµÐ²ÐžÐ°ÑÑÑÑ ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ¹ ÑÐžÑÑÐµÐŒÑ ÑÐžÐ¿Ð° "*.*" ÐžÐ»Ðž "*.doc" ("*" ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ Ð»ÑÐ±ÑÐŒ ÑÐžÐŒÐ²ÐŸÐ»Ð°ÐŒ). 
+     </Section>
+  </Section>
+
+  <Section name="enrichingacollection">
+    <Title>ÐÐ±ÐŸÐ³Ð°ÑÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž</Title>
+ ÐÐŒÐµÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÐœÐ°ÐºÐŸÐ¿Ð»ÐµÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,ÐœÐ°Ð¿ÐŸÐ»ÐœÐžÑÐµ ÐžÑ
+ ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐµÐ¹,ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÐŸÐ¹ "ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ".Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ, ÐºÐ°Ðº ÑÐŸÐ·ÐŽÐ°ÑÑÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ,ÐºÐ°Ðº ÐŸÐœÐž ÑÐµÐŽÐ°ÐºÑÐžÑÑÑÑÑÑ, ÐœÐ°Ð·ÐœÐ°ÑÐ°ÑÑÑÑ Ðž Ð²ÐŸÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÑÑÑÑ,Ð° ÑÐ°ÐºÐ¶Ðµ ÐºÐ°Ðº ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ Ð²ÐœÐµÑÐœÐžÐµ ÐžÑÑÐŸÑÐœÐžÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+    
+ (ÑÐ°ÐºÐ¶Ðµ ÑÐŒ.ÐÐ»Ð°Ð²Ñ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone - ÐÐŸÐ»ÑÑÐµÐœÐžÐµ Ð±ÐŸÐ»ÑÑÐµÐ¹ ÑÐ°ÑÑÐž ÐžÐ· Ð²Ð°ÑÐžÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²). 
+    <Section name="theenrichview">
+      <Title>ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐŸÐ±ÐŸÐ³Ð°ÑÐµÐœÐžÑ</Title>
+<ObviousSentence>T Ð ÑÑÐŸÐž ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ, ÐºÐ°Ðº Ð²Ð²ÐŸÐŽÐžÑÑ Ðž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐŸÐ±ÐŸÐ³Ð°ÑÐµÐœÐžÑ.
+</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐµÑÐµÐ²ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </ContentsItem>
+          <ContentsItem>
+            ÐÐŸÐœÑÑÐŸÐ»Ñ ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐœÐžÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+          </ContentsItem>
+          <ContentsItem>
+            ÐÐµÑÐµÐ²ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹
+          </ContentsItem>
+          <ContentsItem>
+             Ð¢Ð°Ð±Ð»ÐžÑÐ° ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐŸÐ±ÐŸÐ³Ð°ÑÐµÐœÐžÑ ÐŽÐ»Ñ Ð·Ð°ÐŽÐ°ÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. 
+MeÑÐ°ÐŽÐ°ÐœÐœÑÐµ - ÑÑÐŸ ÐŽÐ°ÐœÐœÑÐµ ÐŸ ÐŽÐ°ÐœÐœÑÑ
+ - ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ,ÐÐ²ÑÐŸÑ,ÐÐ°ÑÐ° ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ Ðž Ñ.ÐŽ. ÐÐ°Ð¶ÐŽÑÐ¹ Ð¿ÑÐœÐºÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÑÐŸÑÑÐŸÐžÑ ÐžÐ· ÐŽÐ²ÑÑ
+ ÑÐ°ÑÑÐµÐ¹: "ÑÐ»ÐµÐŒÐµÐœÑ"- Ðº ÐºÐ°ÐºÐŸÐŒÑ ÑÐžÐ¿Ñ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÐŸÐœ ÐŸÑÐœÐŸÑÐžÑÑÑ (Ðº Ð¿ÑÐžÐŒÐµÑÑ,ÐÐ²ÑÐŸÑ),Ðž "Ð·ÐœÐ°ÑÐµÐœÐžÐµ"- ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÑÐŸÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,Ð² ÐºÐŸÑÐŸÑÑÑ
+ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐŽÐ»Ñ Ð»ÑÐ±ÑÑ
+ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÐžÐ»Ðž Ð¿Ð°Ð¿ÐŸÐº Ð² ÐÐµÑÐµÐ²Ðµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð¡ÑÐŸÐ»Ð±ÑÑ ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÑ ÑÐµÑÑÐŒ ÑÐ²ÐµÑÐŸÐŒ Ð²Ð²ÐµÑÑ
+Ñ Ðž ÐžÑ
+ ÑÐ°Ð·ÐŒÐµÑ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐžÐ·ÐŒÐµÐœÑÐœ Ð¿ÑÑÑÐŒ Ð¿ÐµÑÐµÐŽÐ²ÐžÐ¶ÐµÐœÐžÑ Ð»ÐžÐœÐžÐž ÑÐ°Ð·ÐŽÐµÐ»Ð°. Ð©ÐµÐ»ÑÐŸÐº ÐœÐ° Ð»ÑÐ±ÐŸÐ¹ ÑÑÑÐŸÐºÐµ Ð¿ÐµÑÐµÐœÐŸÑÐžÑ ÐµÑ ÐŽÐµÑÐ°Ð»Ðž Ð²ÐœÐžÐ· ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐ°Ð¶Ð°Ð² ÐœÐ° Ð»ÑÐ±ÐŸÐ¹ ÑÑÐŽ Ð² ÑÐ°Ð±Ð»ÐžÑÐµ, Ð²Ñ ÑÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ Ðž ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐŽÐµÑÐ°Ð»Ðž ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ Ð² ÐœÐžÐ¶ÐœÐµÐ¹ ÑÐµÐºÑÐžÐž ÐŸÐºÐœÐ°. Ð§ÐµÑÐœÑÐ¹ ÑÐµÐºÑÑ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ, ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŸÐ±ÑÐžÐŒ ÐŽÐ»Ñ Ð²ÑÐµÑ
+ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ²,ÑÐŸÐ³ÐŽÐ° ÐºÐ°Ðº ÑÐµÑÑÐ¹ ÑÐµÐºÑÑ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ,ÑÑÐŸ ÑÑÐŸ - ÐœÐµ ÑÐ°Ðº.Ð§ÐµÑÐœÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÑ ÐžÐ»Ðž ÑÐŽÐ°Ð»ÐµÐœÑ, Ð² ÑÐŸ Ð²ÑÐµÐŒÑ ÐºÐ°Ðº ÑÐµÑÑÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐŽÐ°Ð»ÐµÐœÑ ÐžÐ· ÑÐµÑ
+,ÐºÐŸÑÐŸÑÑÐµ ÐžÐŒÐµÑÑ ÐžÑ
+,ÐžÐ»Ðž ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÑ Ðº ÐŽÑÑÐ³ÐžÐŒ.  
+ <Break/>
+ ÐÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ Ð¿Ð°Ð¿ÐºÐž ÐŒÐŸÐ¶ÐµÑ Ð¿ÐŸÑÐ²Ð»ÑÑÑÑÑ ÐŸÐºÐŸÐ»ÐŸ ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ Ð²Ñ
+ÐŸÐŽÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.Ð­ÑÐŸ ÑÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐœÐ° ÑÐŸ,ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÑÐœÐ°ÑÐ»ÐµÐŽÐŸÐ²Ð°ÐœÑ ÐŸÑ Ð¿Ð°Ð¿ÐŸÐº ÑÐŸÐŽÐžÑÐµÐ»ÐµÐ¹ (ÐžÐ»Ðž Ð¿ÑÐµÐŽÐºÐŸÐ²). Ð£ÐœÐ°ÑÐ»ÐµÐŽÐŸÐ²Ð°ÐœÐœÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐœÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÑ ÐžÐ»Ðž ÑÐŽÐ°Ð»ÐµÐœÑ, Ð° ÑÐŸÐ»ÑÐºÐŸ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÑ Ð² ÐºÐŸÐœÐµÑ ÑÐ¿ÐžÑÐºÐ° ÐžÐ»Ðž Ð¿ÐµÑÐµÐ¿ÐžÑÐ°ÐœÑ.Ð©ÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐž Ð¿Ð°Ð¿ÐºÐž,ÑÑÐŸÐ±Ñ ÐœÐµÐŒÐµÐŽÐ»ÐµÐœÐœÐŸ Ð¿ÐµÑÐµÐ¹ÑÐž Ð² ÑÑ Ð¿Ð°Ð¿ÐºÑ, Ð³ÐŽÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð·Ð°ÐŽÐ°ÐœÑ.  
+<Break/>
+ÐÐŸÐœÑÑÐŸÐ»Ñ ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐœÐžÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ Ð²ÐœÐžÐ·Ñ ÑÐ¿ÑÐ°Ð²Ð° Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐµÑÐ»Ðž ÑÐ°Ð¹Ð» Ð²ÑÐ±ÑÐ°Ðœ ÐžÐ· ÐŽÐµÑÐµÐ²Ð°, Ð° ÑÑÐŽ Ð² ÑÐ°Ð±Ð»ÐžÑÐµ. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐžÑ
+, ÑÑÐŸÐ±Ñ ÐŸÐ±ÐœÐŸÐ²ÐžÑÑ, ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ Ð² ÐºÐŸÐœÐµÑ ÐžÐ»Ðž ÑÐŽÐ°Ð»ÐžÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ Ð¿ÑÐµÐŽÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐŸ ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ, ÑÑÐŸÐ±Ñ Ð²Ð²ÐµÑÑÐž ÐžÐ»Ðž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐºÐŸÐ»ÐŸ ÐœÐµÐ³ÐŸ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐœÐ°Ñ ÐºÐœÐŸÐ¿ÐºÐ°, ÐºÐŸÑÐŸÑÐ°Ñ Ð¿ÑÐž ÑÐµÐ»ÑÐºÐµ ÐŸÑÐºÑÑÐ²Ð°ÐµÑ Ð±ÐŸÐ»ÑÑÐµÐµ Ð¿ÐŸÐ»Ðµ ÐŽÐ»Ñ ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÑ. Ð Ð°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐœÐ°Ñ ÐœÐžÐ¶Ðµ ÐºÐœÐŸÐ¿ÐºÐ° "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð² ÐºÐŸÐœÐµÑ" Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ðž ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐžÑ
+ Ðº ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐŒ Ð·ÐœÐ°ÑÐµÐœÐžÑÐŒ ÐŽÐ»Ñ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐ°. ÐÐœÐŸÐ¿ÐºÐ° "ÐÐ°ÐŒÐµÐœÐžÑÑ" Ð¿ÑÐžÐŒÐµÐœÑÐµÑ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ðº ÐœÐŸÐ²ÑÐŒ, Ð° "Ð£ÐŽÐ°Ð»ÐžÑÑ" ÑÑÐžÑÐ°ÐµÑ Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ.ÐÐœÐžÐ·Ñ Ð¿ÑÐœÐºÑÐ°,ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐœÐŸÐ³ÐŸ ÐºÐ°Ðº "ÐÑÐµ Ð¿ÑÐµÐŽÑÐŽÑÑÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ", ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ "ÐÐµÑÐµÐ²ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹".  
+<Break/> 
+ ÐÐµÑÐµÐ²ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ ÐŒÐŸÐ¶ÐµÑ ÑÐ°ÑÑÐžÑÑÑÑÑÑ Ðž ÑÐ°Ð·ÑÑÑÐ°ÑÑÑÑ. ÐÐ±ÑÑÐœÐŸ ÑÑÐŸ - ÑÐ¿ÐžÑÐŸÐº, ÐºÐŸÑÐŸÑÑÐ¹ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð²ÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ, Ð²Ð²ÐµÐŽÐµÐœÐœÑÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ ÐŽÐ»Ñ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐ°. Ð©ÐµÐ»ÑÐŸÐº ÐœÐ° Ð²Ñ
+ÐŸÐŽÐµ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž ÑÐ°Ð·ÐŒÐµÑÐ°ÐµÑ ÐµÐ³ÐŸ Ð² Ð¿ÐŸÐ»Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹. Ð¡ ÐŽÑÑÐ³ÐŸÐ¹ ÑÑÐŸÑÐŸÐœÑ,Ð¿ÑÐž ÐœÐ°Ð¿ÐµÑÐ°ÑÐ°ÐœÐœÐŸÐŒ Ð·ÐœÐ°ÑÐµÐœÐžÐž Ð² ÑÐµÐºÑÑÐŸÐ²ÐŸÐŒ Ð¿ÐŸÐ»Ðµ Ð²ÑÐ±ÐŸÑÐºÐž ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÐÐµÑÐµÐ²Ð° Ð·ÐœÐ°ÑÐµÐœÐžÐ¹, ÑÐžÑÑÐµÐŒÐ° ÐœÐ°ÑÐžÐœÐ°ÐµÑ ÑÐ°Ð±ÐŸÑÑ Ñ ÑÐžÐŒÐ²ÐŸÐ»ÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐÑ Ð²Ð²ÐµÐ»Ðž. ÐÐ°Ð¶Ð°ÑÐžÐµ [Tab] Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž Ð·Ð°Ð²ÐµÑÑÐ°ÐµÑ Ð¿ÐµÑÐ°ÑÐ°ÐœÐžÐµ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ.
+ <Break/>
+ÐÐœÐ°ÑÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐŸÑÐ³Ð°ÐœÐžÐ·ÐŸÐ²Ð°ÐœÑ Ð² ÐžÐµÑÐ°ÑÑ
+ÐžÑ. Ð­ÑÐŸ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÐŸ Ð² ÐÐµÑÐµÐ²Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð¿Ð°Ð¿ÐºÐž ÐŽÐ»Ñ Ð²ÐœÑÑÑÐµÐœÐœÐžÑ
+ ÑÑÐŸÐ²ÐœÐµÐ¹. ÐÐµÑÐ°ÑÑ
+ÐžÑÐµÑÐºÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ Ð²Ð²ÐµÐŽÐµÐœÑ,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð·ÐœÐ°Ðº "|" ÐŽÐ»Ñ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ ÑÑÐŸÐ²ÐœÐµÐ¹. ÐÐ°Ð¿ÑÐžÐŒÐµÑ,"Cards|Red|Diamonds|Seven" ÐŒÐŸÐ³ Ð±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ Ð² ÐžÐµÑÐ°ÑÑ
+ÐžÐž, Ð¿ÑÐžÐŒÐµÑÐŸÐŒ ÐºÐŸÑÐŸÑÐŸÐ¹ ÑÐ²Ð»ÑÐµÑÑÑ Ð¿Ð°ÐºÐµÑ ÐžÐ³ÑÑ Ð² ÐºÐ°ÑÑÑ.Ð­ÑÐŸ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð³ÑÑÐ¿Ð¿ÐžÑÐŸÐ²Ð°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ Ð²ÐŒÐµÑÑÐµ. ÐÑÑÐ¿Ð¿Ñ ÐŒÐŸÐ³ÑÑ ÑÐ°ÐºÐ¶Ðµ ÐœÐ°Ð·ÐœÐ°ÑÐ°ÑÑÑÑ ÐºÐ°Ðº ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðº ÑÐ°Ð¹Ð»Ð°ÐŒ.  
+<Break/> 
+ Greenstone Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž ÐžÐ·Ð²Ð»ÐµÐºÐ°ÐµÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÐ· ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Ð² ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÑÐ»ÐµÐŒÐµÐœÑÑ ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ ÐžÐŒÐµÑÑ Ð¿ÑÐµÑÐžÐºÑ "ex.". Ð­ÑÐŸ ÐœÐµ ÐžÐŒÐµÐµÑ ÐœÐžÐºÐ°ÐºÐŸÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŽÐµÑÐµÐ²Ð° Ðž ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐŸ,Ð¿ÐŸÑÐŸÐŒÑ ÑÑÐŸ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµÐŒ ÑÐºÑÑÑÐŸ,ÐµÑÐ»Ðž ÑÐ°ÐºÐŸÐ¹ ÑÐžÐ¿ Ð²Ð²ÐŸÐŽÐ° Ð²ÑÐ±ÑÐ°Ðœ.ÐÐœÐŸÐ¿ÐºÐ° "..." Ð²ÑÑ ÐµÑÑ ÑÐ»ÑÐ¶ÐžÑ ÐŽÐ»Ñ ÑÐ°ÑÑÐžÑÐµÐœÐžÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ,ÐœÐŸ ÑÐµÐºÑÑ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°Ðœ. 
+    </Section>
+    <Section name="selectingmetadatasets">
+      <Title>ÐÑÐ±ÐŸÑ ÐœÐ°Ð±ÐŸÑÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title>
+<ObviousSentence>Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐ»ÐµÐŒÐµÐœÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ðž ÐºÐ°Ðº ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ðº ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    Ð§ÑÐŸ ÑÐ°ÐºÐŸÐµ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+?
+          </ContentsItem>
+          <ContentsItem>
+	    ÐÑÐ±ÑÐ°Ðœ ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐžÐ·Ð²ÐµÑÑÐœÐ° ÐºÐ°Ðº "ÐœÐ°Ð±ÐŸÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+". ÐÑÐžÐŒÐµÑÐŸÐŒ ÑÐ²Ð»ÑÐµÑÑÑ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Dublin Core. ÐÐŸÐ³ÐŽÐ° ÐÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÐµ ÐºÐŸÐŒÐ¿Ð»ÐµÐºÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ðº ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÑÐŸ ÐµÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÑ ÑÑÐ°ÐœÐŸÐ²ÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž ÐŽÐ»Ñ Ð²ÑÐ±ÐŸÑÐ°. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÐŒÐµÑÑ Ð±ÐŸÐ»ÑÑÐµ,ÑÐµÐŒ ÐŸÐŽÐžÐœ ÐœÐ°Ð±ÐŸÑ. ÐÐ»Ñ Ð¿ÑÐµÐŽÐŸÑÐ²ÑÐ°ÑÐµÐœÐžÑ ÑÑÐŸÐ»ÐºÐœÐŸÐ²ÐµÐœÐžÑ ÐŸÐŽÐžÐœÐ°ÐºÐŸÐ²ÑÑ
+ ÐžÐŒÑÐœ Ðº ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ ÑÐ»ÐµÐŒÐµÐœÑÐ° Ð¿ÑÐžÑÐŸÐµÐŽÐžÐœÑÐµÑÑÑ ÐºÐŸÑÐŸÑÐºÐžÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ,ÐºÐŸÑÐŸÑÑÐ¹ Ð²ÑÐŽÐµÐ»ÑÐµÑ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐ»ÐµÐŒÐµÐœÑ Dublin Core "Creator" ÑÑÐ°ÐœÐµÑ "dc.Creator".ÐÐ°Ð±ÐŸÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ñ
+ÑÐ°ÐœÑÑÑÑ Ð² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° Ðž ÐžÐŒÐµÑÑ ÑÑÑÑÐžÐºÑ ".mds".
+<Break/>
+Ð§ÑÐŸÐ±Ñ ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÐŸÐ²Ð°ÑÑ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÑ
+ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ð²ÑÐ±ÐµÑÐžÑÐµ "ÐÐ°Ð±ÐŸÑ ÐÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+" Ð² Ð¿ÑÐŸÑÐŒÐŸÑÑÐµ "ÐÐžÐ·Ð°Ð¹Ðœ".
+    </Section>
+    <Section name="appendingmetadata">
+      <Title>ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title>
+<ObviousSentence>Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðž ÐžÑ
+ Ð·ÐœÐ°ÑÐµÐœÐžÑ Ðº ÑÐ°Ð¹Ð»Ð°ÐŒ Ðž ÐºÐ°Ðº ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŽÐ»Ñ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            ÐÐŸÐ¿ÐŸÐ»ÐœÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐŸÐ¿ÐŸÐ»ÐœÐµÐœÐžÐµ Ð¿Ð°Ð¿ÐŸÐº ÐžÐ»Ðž ÑÐŸÑÑÐ°Ð²ÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+             ÐÐœÐ°ÑÐµÐœÐžÐµ ÐžÐµÑÐ°ÑÑ
+ÐžÐ¹ Ðž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð¢ÐµÐ¿ÐµÑÑ ÐŒÑ ÐŽÐŸÐ±Ð°Ð²ÐžÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ - Ðž ÑÐ°ÐŒ ÑÐ»ÐµÐŒÐµÐœÑ,Ðž ÐµÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ - Ðº ÑÐ°Ð¹Ð»Ñ. Ð¡ÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐµÐŒ ÑÐ°Ð¹Ð» ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ³ÐŸ ÐŽÐµÑÐµÐ²Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.Ð¢Ð°ÐºÐŸÐµ ÐŽÐµÐ¹ÑÑÐ²ÐžÐµ Ð²ÑÐ·ÑÐ²Ð°ÐµÑ Ð¿ÐŸÑÐ²Ð»ÐµÐœÐžÐµ Ð»ÑÐ±ÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ ÑÐ²ÑÐ·Ð°ÐœÐœÑÑ
+ Ñ ÑÑÐžÐŒ ÑÐ°Ð¹Ð»ÐŸÐŒ,Ð² ÑÐ°Ð±Ð»ÐžÑÐµ ÑÐ¿ÑÐ°Ð²Ð°. 
+<Break/>
+ÐÐ°ÑÐµÐŒ Ð²ÑÐ±ÐµÑÐµÐŒ ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÐºÐŸÑÐŸÑÑÐ¹ Ñ
+ÐŸÑÐžÐŒ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ,Ð¿ÑÑÐµÐŒ ÑÐµÐ»ÑÐºÐ° ÑÑÐŽÐŸÐŒ Ñ ÐœÐžÐŒ Ð² ÑÐ°Ð±Ð»ÐžÑÐµ. 
+ <Break/>
+ ÐÐ¿ÐžÑÐžÑÐµ ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ð² Ð¿ÐŸÐ»Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹. ÐÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ Ð·ÐœÐ°Ðº "|",Ð¿ÐŸÑÐºÐŸÐ»ÑÐºÑ ÐŸÐœ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐžÐµÑÐ°ÑÑ
+ÐžÐ¹. ÐÐŸ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÐž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð² ÐºÐŸÐœÐµÑ",ÑÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð°.Ð­ÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐœÐµÐŒÐµÐŽÐ»ÐµÐœÐœÐŸ Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² ÑÐ°Ð±Ð»ÐžÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.  
+<Break/>
+ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐ°ÐºÐ¶Ðµ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðº Ð¿Ð°Ð¿ÐºÐµ ÐžÐ»Ðž ÑÑÐ°Ð·Ñ Ðº ÐœÐµÐºÐŸÑÐŸÑÐŸÐŒÑ ÐŒÐœÐŸÐ¶ÐµÑÑÐ²Ñ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ². Ð­ÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÑÑ ÐºÐŸ Ð²ÑÐµÐŒ ÑÐ°Ð¹Ð»Ð°ÐŒ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ Ð¿Ð°Ð¿ÐºÐž ÐžÐ»Ðž Ðº ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÐŒ Ðž Ðº Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐœÑÐŒ Ð¿Ð°Ð¿ÐºÐ°ÐŒ. ÐÐŒÐµÐ¹ÑÐµ Ð² Ð²ÐžÐŽÑ,ÑÑÐŸ ÐµÑÐ»Ðž ÐÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÐ»Ðž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðº Ð¿Ð°Ð¿ÐºÐµ, ÑÐŸ Ð»ÑÐ±ÑÐµ ÐœÐŸÐ²ÑÐµ ÑÐ°Ð¹Ð»Ñ Ð² ÐœÐµÐ¹ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž ÑÐœÐ°ÑÐ»ÐµÐŽÑÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐžÐ· ÑÑÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐž.  
+ <Break/>
+ ÐÑÐ»Ðž ÐÑ Ð²ÑÐ±ÐµÑÐžÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ,ÐºÐŸÑÐŸÑÑÐµ ÐžÐŒÐµÑÑÑÑ Ð² ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ ÐžÐ· ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ²,Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð² ÐºÐŸÐœÐµÑ",ÑÐŸ ÐŸÐœÐž ÐŽÐŸÐ±Ð°Ð²Ð»ÑÑÑÑÑ ÑÐ°ÐºÐ¶Ðµ Ðº ÐŽÑÑÐ³ÐžÐŒ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÐŒ ÑÐ°Ð¹Ð»Ð°ÐŒ.
+      <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑ Ðº Ð·ÐœÐ°ÑÐµÐœÐžÑÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð¿ÑÑÑ, ÐŸÐ¿ÐžÑÐ°ÐœÐœÑÐ¹ Ð² <Reference target="theenrichview">Ð Ð°ÑÑÐžÑÐµÐœÐœÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ</Reference>.
+    </Section>
+    <Section name="addingpreviouslydefinedmetadata">
+      <Title>ÐÐŸÐ±Ð°Ð²Ð»ÐœÐžÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ, ÐºÐ°Ðº ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, ÐºÐŸÑÐŸÑÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ,ÑÐ¶Ðµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐœÑÐµ Ð² ÐŽÐµÑÐµÐ²Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ Ðº Ð¿Ð°Ð¿ÐºÐ°ÐŒ ÐžÐ»Ðž Ðº ÐŒÐœÐŸÐ¶ÐµÑÑÐ²Ñ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ, ÑÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÐ°Ð¹Ð», Ð·Ð°ÑÐµÐŒ ÑÑÐµÐ±ÑÐµÐŒÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐŽÐµÑÐµÐ²Ð° Ð·ÐœÐ°ÑÐµÐœÐžÐ¹, ÑÐ°ÑÑÐžÑÑÑ Ð¿Ð°Ð¿ÐºÐž ÐžÐµÑÐ°ÑÑ
+ÐžÐž Ð¿ÐŸ ÐŒÐµÑÐµ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÑÑÐž. ÐÑÐ±ÑÐ°ÐœÐœÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² Ð¿ÐŸÐ»Ðµ ÑÐµÐºÑÑÐ° (Ð°Ð»ÑÑÐµÑÐœÐ°ÑÐžÐ²ÐœÐŸ ÐŒÐŸÐ¶ÐœÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð°Ð²ÑÐŸÐ²ÑÐ±ÐŸÑ Ð² ÐŽÐµÑÐµÐ²Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ Ðž ÑÑÐµÐŽÑÑÐ² Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐŸÐ³ÐŸ Ð·Ð°Ð²ÐµÑÑÐµÐœÐžÑ). Ð©ÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð² ÐºÐŸÐœÐµÑ",ÑÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðº ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐŒÑ ÑÐ°Ð¹Ð»Ñ.
+<Break/>
+ÐÑÐŸÑÐµÑÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ñ ÑÐ¶Ðµ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐŒÐž Ð·ÐœÐ°ÑÐµÐœÐžÑÐŒÐž Ðº Ð¿Ð°Ð¿ÐºÐ°ÐŒ ÐžÐ»Ðž ÐŒÐœÐŸÐ¶ÐµÑÑÐ²Ñ ÑÐ°Ð¹Ð»ÐŸÐ² ÑÐ°ÐºÐŸÐ¹ Ð¶Ðµ.
+    </Section>
+    <Section name="updatingmetadata">
+      <Title>ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ, ÐºÐ°Ðº ÐŒÐŸÐŽÐµÑÐœÐžÐ·ÐžÑÐŸÐ²Ð°ÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÐµ Ðº ÑÐ°Ð¹Ð»Ñ.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ Ð¿Ð°Ð¿ÐŸÐº ÐžÐ»Ðž ÐŒÐœÐŸÐ¶ÐµÑÑÐ²ÐŸ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð§ÑÐŸÐ±Ñ ÐŸÐ±ÐœÐŸÐ²ÐžÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÑÐ°ÑÑÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÑÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÐ°Ð¹Ð»,Ðº ÐºÐŸÑÐŸÑÐŸÐŒÑ ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÑÐžÐŒÐµÐœÐµÐœÐŸ,Ð° Ð·Ð°ÑÐµÐŒ ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ ÐÑ Ñ
+ÐŸÑÐžÑÐµ ÐžÐ·ÐŒÐµÐœÐžÑÑ.Ð ÐµÐ·ÑÐ»ÑÑÐ°Ñ Ð²ÑÐ±ÐŸÑÐ° Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. Ð ÐµÐŽÐ°ÐºÑÐžÑÑÐ¹ÑÐµ Ð¿ÐŸÐ»Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÑ Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ", ÑÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ.
+<Break/>
+ÐÑÐŸÑÐµÑÑ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÑ ÐŽÐ°ÐœÐœÑÑ
+ Ð¿Ð°Ð¿ÐºÐž Ñ Ð¿ÐŸÐŽÐ¿Ð°Ð¿ÐºÐ°ÐŒÐž ÐžÐ»Ðž ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÑÐŸÑ Ð¶Ðµ ÑÐ°ÐŒÑÐ¹, ÐœÐŸ Ð²Ñ ÑÐŒÐŸÐ¶ÐµÑÐµ ÐŸÐ±ÐœÐŸÐ²ÐžÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ, ÐŸÐ±ÑÐžÐµ ÐŽÐ»Ñ Ð²ÑÐµÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ²/Ð¿Ð°Ð¿ÐŸÐº.
+<Break/>
+ ÐÐµÑÐµÐ²ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð²ÑÐµ Ð¿ÑÐµÐŽÑÐŽÑÑÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ, Ð° ÐœÐµ ÑÐŸÐ»ÑÐºÐŸ ÑÐµ, ÐºÐŸÑÐŸÑÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÑ Ð² ÐœÐ°ÑÑÐŸÑÑÐµÐµ Ð²ÑÐµÐŒÑ. Ð¢Ð°ÐºÐžÐŒ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ, Ð·ÐœÐ°ÑÐµÐœÐžÐµ, ÐºÐŸÑÐŸÑÐŸÐµ ÐÑ Ð·Ð°ÐŒÐµÐœÐžÐ»Ðž, ÐŸÑÑÐ°ÑÑÑÑ Ð² ÐŽÐµÑÐµÐ²Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹.
+    </Section>
+    <Section name="removingmetadata">
+      <Title>Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÑÐŽÐ°Ð»ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ².</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ² 
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐžÐ· Ð¿Ð°Ð¿ÐŸÐº ÐžÐ»Ðž ÐŒÐœÐŸÐ¶ÐµÑÑÐ²Ð° ÑÐ°Ð¹Ð»ÐŸÐ²
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð²ÑÐ¿ÐŸÐ»ÐœÑÐµÑÑÑ ÑÐ°ÐºÐžÐŒ Ð¶Ðµ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ,ÐºÐ°Ðº Ðž ÐžÑ
+ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ. Ð¡ÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÐ°Ð¹Ð» ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ³ÐŸ ÐŽÐµÑÐµÐ²Ð°,Ð·Ð°ÑÐµÐŒ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÑÐ°Ð±Ð»ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÑÑÐŸÐ±Ñ Ð²ÑÐ±ÑÐ°ÑÑ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÐµ. ÐÑÐ»Ðž Ðº ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÐŸÐŒÑ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ, ÐºÐœÐŸÐ¿ÐºÐ° "Ð£ÐŽÐ°Ð»ÐžÑÑ" Ð°ÐºÑÐžÐ²ÐžÑÑÐµÑÑÑ. Ð©ÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÐœÐµÐ¹,ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÑÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÐ· ÑÐºÐ°Ð·Ð°ÐœÐœÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð°. ÐÑÑÐ³ÐžÐµ ÑÐ°Ð¹Ð»Ñ ÐŸÑÑÐ°ÑÑÑÑ ÐœÐµÐžÐ·ÐŒÐµÐœÐœÑÐŒÐž, Ðž ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŸÑÑÐ°ÑÑÑÑ Ð² ÐŽÐµÑÐµÐ²Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹.
+<Break/>
+ÐÑÐŸÑÐµÑÑ ÑÐŽÐ°Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ Ñ Ð¿Ð°Ð¿ÐŸÐº ÐžÐ»Ðž ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÑÐŸÑ Ð¶Ðµ ÑÐ°ÐŒÑÐ¹.
+    </Section>
+    <Section name="reviewingmetadata">
+      <Title>ÐÑÐŸÑÐŒÐŸÑÑ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title>
+<ObviousSentence>Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ, ÐºÐ°Ðº Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ Ð²ÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÐŽÐ»Ñ Ð¿ÐŸÐ»ÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.</ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐŸÐœÑÑÐŸÐ»ÑÐœÐ°Ñ ÑÐ°Ð±Ð»ÐžÑÐ°
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+             ÐÑÐ°Ð²Ð°Ñ ÐºÐœÐŸÐ¿ÐºÐ° ÐŒÐµÐœÑ
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐ²ÑÐŸÑÐžÐ»ÑÑÑ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÐœÐŸÐ³ÐŽÐ° ÐÐ°ÐŒ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ,Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÐŽÐ»Ñ ÐŒÐœÐŸÐ³ÐžÑ
+ ÐžÐ»Ðž Ð²ÑÐµÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÑÑÐ°Ð·Ñ - ÐœÐ°Ð¿ÑÐžÐŒÐµÑ,ÑÑÐŸÐ±Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ,ÑÐºÐŸÐ»ÑÐºÐŸ ÑÐ°Ð¹Ð»ÐŸÐ² ÐŸÑÑÐ°ÑÑÑÑ ÐŽÐ»Ñ Ð²ÐŸÐ·ÐŽÐµÐ¹ÑÑÐ²ÐžÑ ÐžÐ»Ðž Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐœÐµÐºÐŸÑÐŸÑÑÐµ ÐžÐŽÐµÐž ÐŸÑÐœÐŸÑÐžÑÐµÐ»ÑÐœÐŸ ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÐµÐœÐžÑ ÐŽÐ°ÐœÐœÑÑ
+.
+<Break/>
+ÐÑÐ±ÐµÑÐžÑÐµ ÑÐ°Ð¹Ð»Ñ, ÐºÐŸÑÐŸÑÑÐµ Ð²Ñ Ñ
+ÐŸÑÐžÑÐµ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ, Ð¿ÐŸÑÐŸÐŒ ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° Ð¿ÑÐ°Ð²ÑÑ ÐºÐœÐŸÐ¿ÐºÑ ÐŒÑÑÐž Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ "ÐÐ°Ð·ÐœÐ°ÑÐµÐœÑÐµ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ...". ÐÐŸÑÐ²Ð»ÑÐµÑÑÑ ÐŸÐºÐœÐŸ,ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÐŸÐµ "ÐÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ", Ð·Ð°ÐœÑÑÐŸÐµ Ð±ÐŸÐ»ÑÑÐŸÐ¹ ÑÐ°Ð±Ð»ÐžÑÐµÐ¹,ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐµÐ¹ ÐŒÐœÐŸÐ³ÐŸ ÐºÐŸÐ»ÐŸÐœÐŸÐº.ÐÐµÑÐ²Ð°Ñ ÐºÐŸÐ»ÐŸÐœÐºÐž Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐžÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÐŸÐ²;ÑÑÑÐŸÐºÐž Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÑ Ð²ÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ ÑÑÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ².  
+ <Break/>
+ Ð ÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÑÐ°Ð±Ð»ÐžÑÑ ÐŒÐŸÐ¶ÐµÑ Ð·Ð°ÐœÑÑÑ ÐœÐµÐºÐŸÑÐŸÑÐŸÐµ Ð²ÑÐµÐŒÑ,ÐµÑÐ»Ðž Ð²ÑÐ¿Ð°Ð»ÐŸ ÐŒÐœÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»ÐŸÐ².ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÑÐŸÐŽÐŸÐ»Ð¶Ð°ÑÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐŒ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐŸÐŒ Ð¿ÑÐž ÐŸÑÐºÑÑÑÐŸÐŒ ÐŸÐºÐœÐµ "ÐÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ". 
+<Break/>
+Ð©ÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐºÑÑÑÑ", ÑÑÐŸÐ±Ñ ÑÐºÑÑÑÑ ÐŸÐºÐœÐŸ.
+      <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐ°ÐºÐ¶Ðµ ÑÐ°ÑÑÐŒÐŸÑÑÐµÑÑ ÑÐ°Ð±Ð»ÐžÑÑ "ÐÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ",Ð²ÑÐ±ÐžÑÐ°Ñ ÑÐµ ÑÐ°Ð¹Ð»Ñ, ÐºÐŸÑÐŸÑÑÐµ ÐÑ Ð¶ÐµÐ»Ð°ÐµÑÐµ ÐžÐ·ÑÑÐžÑÑ, ÑÐµÐ»ÐºÐœÑÐ² Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐŸÐ¹ Ðž Ð²ÑÐ±ÐžÑÐ°Ñ "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ".ÐÑÐ»Ðž Ð±ÑÐ»Ð° Ð²ÑÐ±ÑÐ°ÐœÐ° Ð¿Ð°Ð¿ÐºÐ°,ÑÐŸ Ð²ÑÐµ ÐµÑ ÐŽÐŸÑÐµÑÐœÐžÐµ ÑÐ°Ð¹Ð»Ñ Ð²ÐºÐ»ÑÑÐµÐœÑ Ð² ÑÐ°Ð±Ð»ÐžÑÑ.  
+<Break/>
+ ÐÐŸÐ³ÐŽÐ° ÐŸÐœÐ° ÑÑÐ°ÐœÐŸÐ²ÐžÑÑÑ ÑÐ»ÐžÑÐºÐŸÐŒ Ð±ÐŸÐ»ÑÑÐŸÐ¹,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÑÑÐžÐ»ÑÑÑÐŸÐ²Ð°ÑÑ ÑÐ°Ð±Ð»ÐžÑÑ "ÐÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ",Ð¿ÑÐžÐŒÐµÐœÑÑ ÑÐžÐ»ÑÑÑÑ Ðº ÐºÐŸÐ»ÐŸÐœÐºÐ°ÐŒ.ÐÐŸÑÐºÐŸÐ»ÑÐºÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÑ ÐœÐŸÐ²ÑÐµ ÑÐžÐ»ÑÑÑÑ, ÑÐŸÐ»ÑÐºÐŸ ÑÐµ ÑÑÑÐŸÐºÐž,ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑ ÐžÐŒ,ÐŸÑÑÐ°ÑÑÑÑ Ð²ÐžÐŽÐžÐŒÑÐŒÐž.Ð§ÑÐŸÐ±Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ,ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐžÐ»Ðž ÐŸÑÐžÑÑÐžÑÑ ÑÐžÐ»ÑÑÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ Ð¿ÐŸ ÐžÐºÐŸÐœÐºÐµ "ÐÐŸÑÐŸÐœÐºÐ°" ÐœÐ°Ð²ÐµÑÑ
+Ñ ÐºÐŸÐ»ÐŸÐœÐºÐž. Ð£ Ð²Ð°Ñ Ð±ÑÐŽÐµÑ Ð·Ð°Ð¿ÑÐŸÑÐµÐœÐ° ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ ÑÐžÐ»ÑÑÑÐµ. ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÑÐžÐ»ÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ,ÐžÐ·ÐŒÐµÐœÑÐµÑÑÑ ÑÐ²ÐµÑ ÐºÐŸÐ»ÐŸÐœÐºÐž.
+<Break/>
+ ÐÐ°Ð¿ÑÐŸÑ ÐžÐŒÐµÐµÑ ÑÐžÐŒÐ²ÐŸÐ»Ñ "ÐÑÐŸÑÑÐŸÐ¹" Ðž "ÐÑÐŸÐŽÐ²ÐžÐœÑÑÑÐ¹".ÐÑÐŸÑÑÐ°Ñ Ð²ÐµÑÑÐžÑ ÑÐžÐ»ÑÑÑÑÐµÑ ÐºÐŸÐ»ÐŸÐœÐºÐž ÑÐ°Ðº,ÑÑÐŸ ÐŸÐœÐž Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÑ ÑÐŸÐ»ÑÐºÐŸ ÑÑÑÐŸÐºÐž, ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ("*" ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ Ð²ÑÐµÐŒ Ð·ÐœÐ°ÑÐµÐœÐžÑÐŒ).ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐžÐ· ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐ³ÐŸ ÑÐ¿ÐžÑÐºÐ°.ÐÑÐŸÐŽÐ²ÐžÐœÑÑÐ°Ñ Ð²ÐµÑÑÐžÑ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð²ÑÐ¿ÐŸÐ»ÐœÑÑÑ ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ ÐŽÐµÐ¹ÑÑÐ²ÐžÑ:ÐÐŸÐ»Ð¶ÐµÐœ ÐœÐ°ÑÐ°ÑÑÑÑ Ñ,ÐÐµ ÑÐŸÐŽÐµÑÐ¶ÐžÑ,Ð Ð°Ð»ÑÐ°Ð²ÐžÑÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ,ÐÐµÐœÑÑÐµ ÑÐµÐŒ, Ð­ÐºÐ²ÐžÐ²Ð°Ð»ÐµÐœÑÐµÐœ. ÐÐœÐ°ÑÐµÐœÐžÐµ, ÐºÐŸÑÐŸÑÐŸÐµ Ð±ÑÐŽÐµÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐŸÐ²Ð°ÑÑ, ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐŸ ÑÐ°Ðº,ÑÑÐŸÐ±Ñ Ð±ÑÑÑ Ð»ÑÐ±ÐŸÐ¹ ÑÑÑÐŸÐºÐŸÐ¹,Ð²ÐºÐ»ÑÑÐ°Ñ "*". ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ,ÐŽÐŸÐ»Ð¶ÐœÐŸ Ð»Ðž ÑÑÐŸ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÐµ Ð±ÑÑÑ ÐœÐµ ÑÑÐ²ÑÑÐ²ÐžÑÐµÐ»ÑÐœÑÐŒ ÑÐ»ÑÑÐ°ÐµÐŒ. ÐÐ°ÐºÐŸÐœÐµÑ,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ Ð²ÑÐŸÑÐŸÐµ ÑÑÐ»ÐŸÐ²ÐžÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÑ,ÐºÐŸÑÐŸÑÐŸÐµ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐŽÐ»Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÑÐ°ÐœÐ³Ð° Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ (Ð²ÑÐ±ÐžÑÐ°Ñ Ð Ð±ÐŸÐ»ÑÑÐŸÐµ) ÐžÐ»Ðž Ð°Ð»ÑÑÐµÑÐœÐ°ÑÐžÐ²ÐœÑÑ
+ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ (Ð²ÑÐ±ÐžÑÐ°Ñ ÐÐÐ).ÐÐžÐ¶Ðµ ÑÑÐŸÐ¹ ÐŸÐ±Ð»Ð°ÑÑÐž ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ Ð¿ÐŸÐ»Ðµ, ÐºÐŸÑÐŸÑÐŸÐµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐÐ°ÐŒ ÐžÐ·ÐŒÐµÐœÑÑÑ Ð¿ÐŸÑÑÐŽÐŸÐº ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž (Ð²ÐŸÐ·ÑÐ°ÑÑÐ°ÑÑÐžÐ¹ ÐžÐ»Ðž Ð¿ÐŸÐœÐžÐ¶Ð°ÑÐžÐ¹ÑÑ).ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐÑ Ð·Ð°ÐºÐŸÐœÑÐžÑÐµ,ÐœÐ°Ð¶ÐŒÐžÑÐµ "Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐžÐ»ÑÑÑÐ°",ÑÑÐŸÐ±Ñ Ð¿ÑÐžÐŒÐµÐœÐžÑÑ ÐœÐŸÐ²ÑÐ¹ ÑÐžÐ»ÑÑÑ Ðº ÐºÐŸÐ»ÐŸÐœÐºÐµ.ÐÐ°Ð¶ÐŒÐžÑÐµ "ÐÑÐžÑÑÐžÑÑ ÑÐžÐ»ÑÑÑ",ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÐµÐºÑÑÐžÐ¹ ÑÐžÐ»ÑÑÑ.ÐÐ±ÑÐ°ÑÐžÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ ÐœÐ° ÑÐŸ,ÑÑÐŸ ÐŽÐµÑÐ°Ð»Ðž ÑÐžÐ»ÑÑÑÐ° ÑÐŸÑ
+ÑÐ°ÐœÑÑÑÑÑ, ÐŽÐ°Ð¶Ðµ ÐºÐŸÐ³ÐŽÐ° ÑÐžÐ»ÑÑÑ ÐŸÑÐžÑÐµÐœ.
+ <Break/>
+ÐÐ°Ð¿ÑÐžÐŒÐµÑ,ÑÑÐŸÐ±Ñ ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐ°Ð±Ð»ÐžÑÑ "ÐÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ",Ð²ÑÐ±ÐµÑÐžÑÐµ ÐºÐŸÐ»ÐŸÐœÐºÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÑ ÑÐžÐ»ÑÑÑÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ (Ð¿ÑÐŸÑÑÐŸÐ¹ ÑÐžÐ»ÑÑÑ ÐœÐ° "*") Ðž Ð²ÐŸÐ·ÑÐ°ÑÑÐ°ÑÑÐžÐ¹ ÐžÐ»Ðž Ð¿ÐŸÐœÐžÐ¶Ð°ÑÑÐžÐ¹ÑÑ Ð¿ÐŸÑÑÐŽÐŸÐº.   
+    </Section>
+    <Section name="importingpreviouslyassignedmetadata">
+      <Title>ÐÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title>
+      Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÑÐ°ÑÑÐºÐ°Ð·Ð°ÐœÐŸ, ÐºÐ°Ðº ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÐµ ÑÐ°ÐœÑÑÐµ. Ð ÐµÑÑ ÐžÐŽÐµÑ ÐŸ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+, ÐºÐŸÑÐŸÑÑÐµ Ð±ÑÐ»Ðž ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÑ Ðº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÑÐ°ÐœÑÑÐµ.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÑÐž ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐž ÑÐ°Ð¹Ð»ÐŸÐ²
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÑÐ»Ðž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð² ÑÐŸÑÐŒÐµ,ÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°Ð²Ð°ÐµÐŒÐŸÐ¹ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐŒ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐŸÐŒ,Ð±ÑÐ»Ðž Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÑ ÑÐ°Ð¹Ð»Ñ - ÐœÐ°Ð¿ÑÐžÐŒÐµÑ,ÐºÐŸÐ³ÐŽÐ° ÐÑ Ð²ÑÐ±ÐžÑÐ°ÐµÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ ÐžÐ· ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Greenstone - ÐŸÐœÐž ÐžÐŒÐ¿ÐŸÑÑÐžÑÑÑÑÑÑ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž,ÐºÐŸÐ³ÐŽÐ° ÐÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÐµ ÑÐ°Ð¹Ð».Ð§ÑÐŸÐ±Ñ ÑÐŽÐµÐ»Ð°ÑÑ ÑÑÐŸ, ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÑ Ð² ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°Ñ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÐŽÐŸÑÑÑÐ¿ÐœÑÑ
+ Ð² ÑÑÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+<Break/>
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð·Ð°Ð¿ÑÐ°ÑÐžÐ²Ð°ÐµÑ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ.ÐÐ°Ð¿ÑÐŸÑ ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÐºÑÐ°ÑÐºÐžÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž Ðž Ð·Ð°ÑÐµÐŒ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐžÐŒÑ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÐºÐŸÑÐŸÑÑÐµ ÐžÐŒÐ¿ÐŸÑÑÐžÑÑÑÑÑÑ,ÐºÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐŸÐœ Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² ÐžÑÑ
+ÐŸÐŽÐœÐŸÐŒ ÑÐ°Ð¹Ð»Ðµ.Ð­ÑÐŸ Ð¿ÐŸÐ»Ðµ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐŸ ÐžÐ»Ðž ÐžÐ·ÐŒÐµÐœÐµÐœÐŸ.ÐÐ°ÑÐµÐŒ ÐÑ Ð²ÑÐ±ÐžÑÐ°ÐµÑÐµ,ÐºÐ°ÐºÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐœÐŸÐ²ÐŸÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÑ,Ð° Ð·Ð°ÑÐµÐŒ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐžÐ¹ ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð² ÑÑÐžÑ
+ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°Ñ
+.Ð¡ÐžÑÑÐµÐŒÐ° Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž Ð²ÑÐ±ÐžÑÐ°ÐµÑ ÑÐ°ÐŒÐŸÐµ Ð±Ð»ÐžÐ·ÐºÐŸÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÐµ Ð² ÑÐµÑÐŒÐžÐœÐ°Ñ
+ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž Ðž ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐŽÐ»Ñ ÐœÐŸÐ²ÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. 
+<Break/>
+ ÐÑÐŸÐ²ÐµÑÐžÐ² ÑÑÐž ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐžÑ,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ",ÑÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÐ¹ ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ðº Ð²ÑÐ±ÑÐ°ÐœÐœÑÐŒ ÐœÐ°Ð±ÐŸÑÐ°ÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.Ð­ÑÐŸ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÑÐŸÐ»ÑÐºÐŸ ÑÐŸÐ³ÐŽÐ°,ÐºÐŸÐ³ÐŽÐ° ÐŸÑÑÑÑÑÑÐ²ÑÐµÑ ÑÐ»ÐµÐŒÐµÐœÑ Ñ ÑÐµÐŒ Ð¶Ðµ ÑÐ°ÐŒÑÐŒ ÐžÐŒÐµÐœÐµÐŒ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ Ð²ÑÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÑÑÐ°ÐœÐŸÐ²ÐŸÐº; "ÐÐ°ÐŒÐµÐœÐžÑÑ" ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐ°ÐµÑ Ð¿ÑÐžÑÐŸÐµÐŽÐžÐœÐµÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐ° Ðº ÑÐ¶Ðµ ÑÐ°ÐœÐµÐµ Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐŒÑ  Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÐµÐŒ;ÐœÐ°ÐºÐŸÐœÐµÑ, "ÐÐµ ÑÑÐžÑÑÐ²Ð°ÑÑ", ÑÑÐŸÐ±Ñ ÐœÐµ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐœÐžÐºÐ°ÐºÐžÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ñ ÑÑÐžÐŒ ÐžÐŒÐµÐœÐµÐŒ ÑÐ»ÐµÐŒÐµÐœÑÐ°. ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÐ»Ðž,ÐºÐ°Ðº ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐœÐµÐºÐŸÑÐŸÑÑÑ ÑÐ°ÑÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, Ð·Ð°Ð¿ÐžÑÐ°ÐœÐœÐ°Ñ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÑÐŸÑ
+ÑÐ°ÐœÑÐµÑÑÑ ÐœÐ° Ð²ÑÐµÐŒÑ ÑÑÑÐµÑÑÐ²ÐŸÐ²Ð°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+<Break/>
+ ÐÐ»Ñ ÐŽÐµÑÐ°Ð»ÐµÐ¹ ÐŸÑÐœÐŸÑÐžÑÐµÐ»ÑÐœÐŸ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð² metadata.xml, ÐºÐŸÑÐŸÑÑÐ¹ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ Ð² Greenstone ÐŽÐ»Ñ Ñ
+ÑÐ°ÐœÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÑÐŒ.Ð³Ð»Ð°Ð²Ñ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.
+ </Section>
+  </Section>
+
+  <Section name="designingacollection">
+    <Title>ÐÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title>
+ ÐÐŸÐ³ÐŽÐ° ÐÐ°ÑÐž ÑÐ°Ð¹Ð»Ñ ÑÐœÐ°Ð±Ð¶ÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž,ÐŽÐ°Ð»ÐµÐµ ÐÑ ÑÐµÑÐ°ÐµÑÐµ,Ð² ÐºÐ°ÐºÐŸÐŒ Ð²ÐžÐŽÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Greenstone ÐŽÐŸÐ»Ð¶ÐœÐ° Ð±ÑÑÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐ° Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÑÐŒ.ÐÐ°ÐºÐŸÐ³ÐŸ Ð²ÐžÐŽÐ° ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŽÐŸÑÑÑÐ¿ÐœÐ° ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°? ÐÐ°ÐºÐžÐµ Ð¿ÑÑÐž Ð¿ÑÐµÐŽÑÑÐŒÐŸÑÑÐµÐœÑ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°? ÐÐ°ÐºÐžÐµ ÑÐ·ÑÐºÐž Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑÑÑ? ÐÐŽÐµ ÑÐ°Ð·ÐŒÐµÑÑÐžÑÑ ÐºÐœÐŸÐ¿ÐºÐž ÐœÐ° ÑÑÑÐ°ÐœÐžÑÐµ? Ð­ÑÐž Ð²ÐµÑÐž ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐœÐ°ÑÑÑÐŸÐµÐœÑ;Ð² ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ,ÐºÐ°Ðº ÑÑÐŸ ÑÐŽÐµÐ»Ð°ÑÑ.
+    <Section name="thedesignview">
+      <Title>ÐÐžÐŽ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°</Title>
+ Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» Ð²Ð²ÐŸÐŽÐžÑ ÐÐ°Ñ Ð² ÑÐ°ÑÑÐŒÐ°ÑÑÐžÐ²Ð°ÐµÐŒÑÐ¹ Ð¿ÑÐŸÐµÐºÑ Ðž ÐŸÐ±ÑÑÑÐœÑÐµÑ,ÐºÐ°Ðº Ð²ÑÐ±ÑÐ°ÑÑ ÐŒÐµÐ¶ÐŽÑ ÑÐ°Ð·Ð»ÐžÑÐœÑÐŒÐž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑÐŒÐž Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ Ð°ÐºÑÐžÐ²ÐœÐŸÐ¹ ÑÐ°ÑÑÐž ÐŸÐºÐœÐ°.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÑÐ±ÐŸÑ ÑÐ°Ð·ÐŽÐµÐ»Ð° Ð¿ÑÐŸÐµÐºÑÐ°
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÑÐž Ð¿ÐŸÐŒÐŸÑÐž ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÑÑ Ð²ÐžÐŽÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÑÐµÐŒÐŸÐ¹ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ.ÐÐ°ÑÐžÐ°ÐœÑÑ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÑ ÐœÐ° ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ ÑÐ°Ð·ÐŽÐµÐ»Ñ, ÐºÐ°Ð¶ÐŽÑÐ¹ ÐžÐ· ÐºÐŸÑÐŸÑÑÑ
+ ÑÐ²ÑÐ·Ð°Ðœ ÑÐŸ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐŸÐ¹ ÑÑÐ°ÐŽÐžÐµÐ¹ ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÐž ÐžÐ»Ðž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž.
+<Break/>
+ Ð¡Ð»ÐµÐ²Ð° ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ ÑÐ¿ÐžÑÐŸÐº ÑÐ°Ð·Ð»ÐžÑÐœÑÑ
+ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐ¹,Ð° ÑÐ¿ÑÐ°Ð²Ð° - ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐµÐºÑÑÐžÐŒ ÑÐ¿ÐžÑÐºÐŸÐŒ.Ð§ÑÐŸÐ±Ñ Ð¿ÐµÑÐµÐ¹ÑÐž ÐœÐ° Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ,ÑÐµÐ»ÐºÐœÐžÑÐµ ÐµÐ³ÐŸ ÐžÐŒÑ Ð² ÑÐ¿ÐžÑÐºÐµ. 
+<Break/>
+ Ð§ÑÐŸÐ±Ñ Ð¿ÐŸÐœÐžÐŒÐ°ÑÑ ÑÑÐ°ÐŽÐžÐž Ðž ÑÐµÑÐŒÐžÐœÑ,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÐµ Ð¿ÑÐž Ð¿ÑÐŸÐµÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÑÐœÐ°ÑÐ°Ð»Ð° Ð¿ÑÐŸÑÑÐžÑÐµ Ð³Ð»Ð°Ð²Ñ 1 Ðž 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone. 
+    </Section>
+    <Section name="generalsettings">
+      <Title>ÐÐ±ÑÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž</Title>
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ Ðž ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐŸÐ±ÑÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž, ÐŸÑÐœÐŸÑÑÑÐžÐµÑÑ Ðº ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.Ð¡ÐœÐ°ÑÐ°Ð»Ð° Ð² "Ð Ð°Ð·ÐŽÐµÐ»Ð°Ñ
+ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ±ÑÐžÐµ"
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐ±ÑÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÐŽÐµÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ,Ð¿ÑÐµÐŽÑÑÐŒÐŸÑÑÐµÐœÐœÑÐµ Ð¿ÑÐž ÑÐŸÐ·ÐŽÐ°ÐœÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐžÐ·ÐŒÐµÐœÐµÐœÑ.
+<Break/>
+ ÐÐ°Ð²ÐµÑÑ
+Ñ ÑÑÑÐ°ÐœÐžÑÑ ÐžÐŒÐµÐµÑÑÑ Ð¿ÐŸÐ»Ðµ ÐžÐœÑÑÑÑÐºÑÐžÐž,ÐºÐŸÑÐŸÑÐ°Ñ ÐžÐŒÐµÐµÑÑÑ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÑÐ°Ð·ÐŽÐµÐ»Ð°.ÐÐœÐŸ ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÐºÑÐ°ÑÐºÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº ÑÐºÐ°Ð·Ð°ÐœÐžÐ¹,ÑÑÐŸÐ±Ñ ÐœÐ°Ð¿ÐŸÐŒÐœÐžÑÑ ÐÐ°ÐŒ,ÐºÐ°ÐºÐžÐµ ÑÑÐœÐºÑÐžÐŸÐœÐ°Ð»ÑÐœÑÐµ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÐž ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž.
+<Break/>
+ Ð¡ÐœÐ°ÑÐ°Ð»Ð° ÐžÐŽÑÑ ÐºÐŸÐœÑÐ°ÐºÑÐœÑÐµ Ð°ÐŽÑÐµÑÐ° ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ ÑÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑÐµÐ³ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð»ÐžÑÐ°. Ð¡Ð»ÐµÐŽÑÑÑÐµÐµ Ð¿ÐŸÐ»Ðµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐÐ°ÐŒ ÐžÐ·ÐŒÐµÐœÑÑÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð¡Ð»ÐµÐŽÑÑÐµÐµ ÑÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð¿Ð°Ð¿ÐºÑ, Ð² ÐºÐŸÑÐŸÑÐŸÐ¹ ÑÐŸÑ
+ÑÐ°ÐœÐµÐœÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐœÐŸ ÐœÐµ Ð¿ÐŸÐŽÐ»ÐµÐ¶ÐžÑ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑÐŒ. Ð¡Ð»ÐµÐŽÑÑÑÐµÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÑ (Ð² ÑÐŸÑÐŒÐµ URL) ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ,ÑÑÐŸÐ±Ñ Ð¿ÐŸÐºÐ°Ð·Ð°ÑÑ ÐœÐ°Ð²ÐµÑÑ
+Ñ ÑÐ»ÐµÐ²Ð° ÐŸÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÑÑÑÐ°ÐœÐžÑÑ ÐŸ ÐœÐµÐ¹, Ðž ÑÐ»ÐµÐŽÑÑÑÐµÐµ - ÐžÐºÐŸÐœÐºÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐ°Ñ Ð² Greenstone ÑÑÑÐ°ÐœÐžÑÐ° ÐŽÐ»Ñ ÑÐ²ÑÐ·Ðž Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹. ÐÐŸÑÐ»Ðµ ÑÑÐŸÐ³ÐŸ, Ð²Ñ ÑÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐŽÐµÐ»ÐžÑÑ Ð¿ÑÐœÐºÑ Ð³Ð°Ð»ÐŸÑÐºÐŸÐ¹, ÑÐºÐ°Ð·Ð°Ð², ÐŽÐŸÑÑÑÐ¿ÐœÐ° Ð»Ðž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŽÑÑÐ³ÐžÐŒ. ÐÐ°ÐºÐŸÐœÐµÑ, ÑÐ»ÐµÐŽÑÐµÑ ÐŸÐ±Ð»Ð°ÑÑÑ ÑÐµÐºÑÑÐ° "ÐÐ¿ÐžÑÐ°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž",Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐœÐ°Ñ ÑÐ°ÐœÐµÐµ Ð² <Reference target="creatingacollection">Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Reference>.
+    </Section>
+    <Section name="plugins">
+      <Title>ÐÐ»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°</Title>
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÐ°ÐœÐŸ,ÐºÐ°Ðº ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÑÑ Ð¿Ð»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÐŽÐ»Ñ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹.Ð ÐœÑÐŒ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ,ÐºÐ°ÐºÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ, ÐºÐ°ÐºÐžÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ Ð¿ÐµÑÐµÐŽÐ°Ð²Ð°ÑÑ Ðº ÐœÐžÐŒ Ðž Ð² ÐºÐ°ÐºÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ ÐŸÐœÐž Ð²Ñ
+ÐŸÐŽÑÑ. Ð©ÐµÐ»ÐºÐœÐžÑÐµ
+ "ÐÐ»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²" Ð² Ð¿ÑÐœÐºÑÐµ "Ð Ð°Ð·ÐŽÐµÐ»Ñ Ð¿ÑÐŸÐµÐºÑÐ°".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐ°
+          </ContentsItem>
+          <ContentsItem>
+            Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐ°
+          </ContentsItem>
+          <ContentsItem>
+             Ð€ÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐ°
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐ·ÐŒÐµÐœÐµÐœÐžÐµ Ð¿ÐŸÑÑÐŽÐºÐ° Ð¿Ð»Ð°Ð³ÐžÐœÐ°
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+             ÐÐ°ÑÑÑÐŸÐ¹ÐºÐ° ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž</Anchor>
+Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÑÑ Ð¿Ð»Ð°Ð³ÐžÐœ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ "ÐÑÐ±ÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœÐ° ÐŽÐ»Ñ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÑ" Ð² ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐŒ ÑÐ¿ÐžÑÐºÐµ ÐŸÐºÐŸÐ»ÐŸ ÐŸÑÐœÐŸÐ²Ð°ÐœÐžÑ,Ðž Ð·Ð°ÑÐµÐŒ ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð¿Ð»Ð°Ð³ÐžÐœ". ÐÐŸÑÐ²Ð»ÑÐµÑÑÑ ÐŸÐºÐœÐŸ Ñ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµÐŒ "ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ²";ÐŸÐœÐŸ ÐŸÐ¿ÐžÑÐ°ÐœÐŸ ÐœÐžÐ¶Ðµ. ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐÑ ÑÑÐŸÑÐŒÐžÑÐŸÐ²Ð°Ð»Ðž ÐœÐŸÐ²ÑÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ, ÐŸÐœ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÑÑ Ð² ÐºÐŸÐœÐµÑ ÑÐ¿ÐžÑÐºÐ° "Ð£ÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐœÑÐµ ÑÐµÐºÑÑÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÑ". ÐÐ°ÐŒÐµÑÑÑÐµ, ÑÑÐŸ, ÐºÑÐŸÐŒÐµ UnknownPlug, ÐºÐ°Ð¶ÐŽÑÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ Ð²ÑÐ²ÐµÐŽÐµÐœ ÑÐŸÐ»ÑÐºÐŸ ÐŸÐŽÐžÐœ ÑÐ°Ð· Ð² ÑÐ¿ÐžÑÐºÐµ.
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ Ð¿Ð»Ð°Ð³ÐžÐœ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ Ð² ÑÐ¿ÐžÑÐºÐµ Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ Ð¿Ð»Ð°Ð³ÐžÐœ".
+<Break/>
+ ÐÐ»Ð°Ð³ÐžÐœÑ ÑÐŸÑÐŒÐžÑÑÑÑÑÑ Ð¿ÑÑÐµÐŒ Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ². Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐžÑ
+, Ð²ÑÐ±ÐµÑÐžÑÐµ Ð¿Ð»Ð°Ð³ÐžÐœ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð€ÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ²"(ÐžÐ»Ðž ÐŽÐ²ÐŸÐ¹ÐœÑÐŒ ÑÐµÐ»ÑÐºÐŸÐŒ ÐœÐ° Ð¿Ð»Ð°Ð³ÐžÐœÐµ). ÐÐžÐ°Ð»ÐŸÐ³ "ÐÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÑÐµ ÐÑÐ³ÑÐŒÐµÐœÑÑ" Ð²ÐŸÐ·ÐœÐžÐºÐ°ÐµÑ Ñ ÑÐ°Ð·Ð»ÐžÑÐœÑÐŒÐž ÐŸÐ¿ÑÐžÑÐŒÐž ÐŽÐ»Ñ ÑÐºÐ°Ð·Ð°ÐœÐžÑ Ð°ÑÐ³ÑÐŒÐµÐœÑÐŸÐ².
+<Break/>
+ Ð¡ÑÑÐµÑÑÐ²ÑÑÑ ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ Ð²ÐžÐŽÑ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ. ÐÐµÐºÐŸÑÐŸÑÑÐµ ÑÐ²Ð»ÑÑÑÑÑ ÐœÐµÐ·Ð°Ð²ÐžÑÐžÐŒÑÐŒÐž ÐºÐœÐŸÐ¿ÐºÐ°ÐŒÐž Ðž ÑÐµÐ»ÑÐŸÐº ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÑÑ ÐŸÐ¿ÑÐžÑ Ðº Ð¿Ð»Ð°Ð³ÐžÐœÑ. ÐÑÑÐ³ÐžÐµ Ð²ÑÑÑÑÐ¿Ð°ÑÑ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÑÑÑÐŸÐºÐž ÑÐµÐºÑÑÐ° Ñ ÐœÐµÐ·Ð°Ð²ÐžÑÐžÐŒÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐŸÐ¹ Ðž ÐŸÐ±Ð»Ð°ÑÑÑÑ ÑÐµÐºÑÑÐ°. Ð©ÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° Ð¿ÐŸÐ»Ðµ,ÑÑÐŸÐ±Ñ Ð²ÑÐ·Ð²Ð°ÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑ,Ð·Ð°ÑÐµÐŒ ÐœÐ°Ð¿ÐµÑÐ°ÑÐ°Ð¹ÑÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐžÐ¹ ÑÐµÐºÑÑ (Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ,Ð¿ÑÑÑ ÑÐ°Ð¹Ð»Ð° Ðž Ñ.ÐŽ.) Ð² Ð¿ÐŸÐ»Ðµ. ÐÑÑÐ³ÐžÐµ - ÑÑÐŸ ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐžÐµ ÐŒÐµÐœÑ,Ð² ÐºÐŸÑÐŸÑÑÑ
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÐžÑÐ°ÑÑ ÐœÑÐ¶ÐœÐŸÐµ ÐžÐ· Ð·Ð°ÐŽÐ°ÐœÐœÐŸÐ³ÐŸ ÐœÐ°Ð±ÐŸÑÐ° Ð·ÐœÐ°ÑÐµÐœÐžÐ¹. Ð§ÑÐŸÐ±Ñ Ð¿ÐŸÐœÑÑÑ,ÑÑÐŸ ÐŽÐµÐ»Ð°ÐµÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑ, ÐŽÐ°Ð¹ÑÐµ ÐŒÑÑÐž ÐœÐ° ÐŒÐ³ÐœÐŸÐ²ÐµÐœÐžÐµ Ð¿ÑÐŸÐ¹ÑÐž Ð¿ÐŸ ÐµÐ³ÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ Ðž ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ Ð¿ÐŸÑÐ²ÐžÑÑÑ. 
+<Break/>
+ ÐÐŸÐ³ÐŽÐ° ÐÑ ÐžÐ·ÐŒÐµÐœÐžÐ»Ðž ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑ,ÐœÐ°Ð¶ÐŒÐžÑÐµ "ÐÐ", ÑÑÐŸÐ±Ñ Ð¿ÑÐžÐœÑÑÑ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ Ðž Ð·Ð°ÐºÑÑÑÑ ÐŽÐžÐ°Ð»ÐŸÐ³,ÐžÐ»Ðž "ÐÑÐŒÐµÐœÐžÑÑ",ÑÑÐŸÐ±Ñ Ð·Ð°ÐºÑÑÑÑ ÐŽÐžÐ°Ð»ÐŸÐ³ Ð±ÐµÐ· ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ Ð»ÑÐ±ÑÑ
+ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ² Ð¿Ð»Ð°Ð³ÐžÐœÐ°. 
+ <Break/>
+ ÐÐ»Ð°Ð³ÐžÐœÑ Ð² ÑÐ¿ÐžÑÐºÐµ ÑÐ°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÑ Ð² ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ,ÑÐ°Ðº ÐºÐ°Ðº ÑÐ¿ÐŸÑÑÐŽÐŸÑÐµÐœÐžÐµ ÐžÐœÐŸÐ³ÐŽÐ° Ð²Ð°Ð¶ÐœÐŸ. ÐÐ²Ð° Ð¿Ð»Ð°Ð³ÐžÐœÐ° - ArcPlug Ðž RecPlug - ÑÐ²Ð»ÑÑÑÑÑ Ð¶ÐžÐ·ÐœÐµÐœÐœÐŸ Ð²Ð°Ð¶ÐœÑÐŒÐž ÐŽÐ»Ñ Ð¿ÑÐŸÑÐµÑÑÐ° ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ Ð² ÐºÐŸÐœÑÐµ ÑÐ¿ÐžÑÐ°ÐºÐ° (Ñ ÐŸÑÐŽÐµÐ»ÑÑÑÐµÐ¹ Ð»ÐžÐœÐžÐµÐ¹).Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð¿ÐŸÑÑÐŽÐŸÐº ÐŽÑÑÐ³ÐžÑ
+ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ²,Ð²ÑÐ±ÐµÑÐžÑÐµ Ð¿Ð»Ð°Ð³ÐžÐœ,ÐºÐŸÑÐŸÑÑÐ¹ ÐÑ Ñ
+ÐŸÑÐžÑÐµ Ð¿ÐµÑÐµÐŒÐµÑÑÐžÑÑ,Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²Ð²ÐµÑÑ
+" ÐžÐ»Ðž "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²ÐœÐžÐ·".  
+       <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐŸÑÐµÐœÑ Ñ
+ÐŸÑÐŸÑÐŸ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÑ,ÐºÐ°ÐºÐžÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ Ð¿Ð»Ð°Ð³ÐžÐœÐ° Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑ. ÐÐŽÐœÐ°ÐºÐŸ, ÐµÑÑÑ ÑÐ»ÑÑÐ°Ðž, Ð² ÐºÐŸÑÐŸÑÑÑ
+ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ Ñ
+ÐŸÑÐµÑ ÑÐºÐ°Ð·Ð°ÑÑ ÑÐ¿ÐµÑÐžÐ°Ð»ÑÐœÑÐµ Ð°ÑÐ³ÑÐŒÐµÐœÑÑ. ÐÐ»Ñ ÑÑÐŸÐ³ÐŸ ÐµÑÑÑ Ð²ÐœÐžÐ·Ñ ÑÐµÐºÑÑÐŸÐ²ÐŸÐµ Ð¿ÐŸÐ»Ðµ "ÐÐœÐŽÐžÐ²ÐžÐŽÑÐ°Ð»ÑÐœÑÐµ ÐÑÐ³ÑÐŒÐµÐœÑÑ". ÐÑÐ±ÐŸÐ¹ ÑÐµÐºÑÑ Ð² ÑÑÐŸÐŒ Ð¿ÐŸÐ»Ðµ ÐŽÐŸÑÐ»ÐŸÐ²ÐœÐŸ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÑÑ Ð² ÐºÐŸÐœÐµÑ ÐºÐŸÐŒÐ°ÐœÐŽÑ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ². 
+    </Section>
+    <Section name="searchtypes">
+      <Title>ÐÐžÐŽÑ Ð¿ÐŸÐžÑÐºÐ°</Title>
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐŸÑÐŸÐ±ÐµÐœÐœÐŸÑÑÐž ÐœÐŸÐ²ÐŸÐ³ÐŸ ÐŽÐžÐ·Ð°Ð¹ÐœÐ° Ð² Greenstone; Ð²ÐžÐŽÑ Ð¿ÐŸÐžÑÐºÐ°,ÐºÐŸÑÐŸÑÑÐµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÑÑ Ð¿ÑÐŸÐ²ÐŸÐŽÐžÑÑ Ð¿ÐŸÐžÑÐº Ð¿ÐŸ Ð¿ÐŸÐ»ÑÐŒ. Ð©ÐµÐ»ÐºÐœÐžÑÐµ Ð²ÐžÐŽÑ Ð¿ÐŸÐžÑÐºÐ° Ð² "Ð Ð°Ð·ÐŽÐµÐ»Ð°Ñ
+ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" 
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            ÐÐ°Ðº Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÑÑÑÑ ÑÑÐµÐŽÑÑÐ²Ð° ÑÐ°ÑÑÐžÑÐµÐœÐœÐŸÐ³ÐŸ Ð¿ÐŸÐžÑÐºÐ°
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ³ÐŸ Ð²ÐžÐŽÐ° Ð¿ÐŸÐžÑÐºÐ°
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ Ð²ÐžÐŽÐ° Ð¿ÐŸÐžÑÐºÐ°
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐ·ÐŒÐµÐœÐµÐœÐžÐµ Ð¿ÐŸÑÑÐŽÐºÐ° Ð²ÐžÐŽÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÐŸÐ³ÐŽÐ° ÐÑ ÐœÐ°ÑÐžÐœÐ°ÐµÑÐµ Ð¿ÑÐŸÑÐŒÐŸÑÑ Ð²ÐžÐŽÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°, ÑÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐžÑÐµ "ÐÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑ ÑÐ°ÑÑÐžÑÐµÐœÐœÐŸÐ³ÐŸ Ð¿ÐŸÐžÑÐºÐ°",ÐºÐŸÑÐŸÑÑÐ¹ Ð°ÐºÑÐžÐ²ÐžÐ·ÐžÑÑÐµÑ ÐŽÑÑÐ³ÐžÐµ ÑÑÐµÐŽÑÑÐ²Ð° ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ.Ð­ÑÐŸ Ð¿ÐµÑÐµÐ²ÐŸÐŽÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð² ÑÐŸÑÐŒÐ°Ñ Greenstone 2.4, ÐºÐŸÑÐŸÑÑÐ¹ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÐµÑ Ð¿ÐŸÐžÑÐº Ð¿ÐŸ Ð¿ÐŸÐ»ÑÐŒ Ðž ÐŸÐ·ÐœÐ°ÑÐ°ÐµÑ, ÑÑÐŸ (Ð°) - ÐžÐœÐŽÐµÐºÑ ÐŽÐžÐ·Ð°Ð¹ÐœÐ° ÑÐ²Ð»ÑÐµÑÑÑ ÐŸÑÐ»ÐžÑÐ°ÑÑÐžÐŒÑÑ,ÐŸÐ±ÑÑÑÐœÐµÐœ Ð²
+ (<Reference target="searchindexes">ÐÐœÐŽÐµÐºÑÑ Ð¿ÐŸÐžÑÐºÐ°</Reference> section);
+(b) - ÐžÐŒÐµÐµÑÑÑ Ð±ÐŸÐ»ÑÑÐµ ÑÑÐ°Ð³ÐŒÐµÐœÑÐŸÐ² ÑÐµÐºÑÑÐ° ÐŽÐ»Ñ Ð¿ÐµÑÐµÐ²ÐŸÐŽÐ° (<Reference target="translatetext">ÐÐµÑÐµÐ²ÐŸÐŽ</Reference>);(c) - ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµ Ð±ÑÐŽÐµÑ Ð³ÐŸÐŽÐœÐ° Ðº ÑÐ¿ÐŸÑÑÐµÐ±Ð»ÐµÐœÐžÑ Ð¿ÑÐž Ð±ÐŸÐ»ÐµÐµ ÑÑÐ°ÑÑÑ
+ Ð²ÐµÑÑÐžÑÑ
+ Greenstone. ÐÑÐ»Ðž ÐÑ Ð¿ÐŸÐ·Ð¶Ðµ ÐœÐµ Ð¿ÑÐŸÐ²ÐµÑÐžÑÐµ ÑÑÐŸ Ð¿ÐŸÐ»Ðµ,ÑÐŸ Ð±ÐŸÐ»ÑÑÐ°Ñ ÑÐ°ÑÑÑ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð²ÐµÑÐœÑÑÑÑ Ðº Greenstone 2.39.ÐÐŽÐœÐ°ÐºÐŸ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð¿ÑÐµÐŸÐ±ÑÐ°Ð·ÐŸÐ²Ð°ÑÑ ÐœÐŸÐ²ÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÐžÐœÐŽÐµÐºÑÐ° Ð² Ð±ÐŸÐ»ÐµÐµ ÑÑÐ°ÑÑÐµ,ÑÐ°Ðº ÑÑÐŸ ÐÑ Ð±ÑÐŽÐµÑÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð²ÐµÑÐœÑÑÑ ÐžÑ
+ Ð²ÑÑÑÐœÑÑ.
+ <Break/>
+ Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ°,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° "ÐÐžÐŽÑ Ð¿ÐŸÐžÑÐºÐ°" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ°".ÐÐ°Ð¶ÐŽÑÐ¹ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ° ÐŒÐŸÐ¶ÐµÑ Ð¿ÐŸÑÐ²ÐžÑÑÑÑ Ð² ÑÐ¿ÐžÑÐºÐµ ÑÐŸÐ»ÑÐºÐŸ ÐŸÐŽÐžÐœ ÑÐ°Ð·.
+<Break/>
+Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ°, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° "Ð¢ÐµÐºÑÑÐžÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ Ð²ÐžÐŽÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ°".Ð¡Ð¿ÐžÑÐŸÐº ÐŽÐŸÐ»Ð¶ÐµÐœ ÑÐŸÐŽÐµÑÐ¶Ð°ÑÑ Ð¿ÐŸ ÐºÑÐ°Ð¹ÐœÐµÐ¹ ÐŒÐµÑÐµ ÐŸÐŽÐžÐœ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ°. 
+ <Break/>
+ Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð¿ÐŸÑÑÐŽÐŸÐº ÑÐ»ÐµÐŽÐŸÐ²Ð°ÐœÐžÑ Ð²ÐžÐŽÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²Ð²ÐµÑÑ
+" ÐžÐ»Ðž "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²ÐœÐžÐ·". ÐÐµÑÐ²ÑÐ¹ ÐžÐ· ÐœÐŒÑ
+ Ð±ÑÐŽÐµÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ.
+    </Section>
+    <Section name="searchindexes">
+      <Title>ÐÐœÐŽÐµÐºÑÑ Ð¿ÐŸÐžÑÐºÐ°</Title>
+ ÐÐœÐŽÐµÐºÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÑÑ,ÐºÐ°ÐºÐžÐµ ÑÐ°ÑÑÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°. Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ Ðž ÑÐŽÐ°Ð»ÐžÑÑ ÐžÐœÐŽÐµÐºÑÑ,Ð° ÑÐ°ÐºÐ¶Ðµ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐžÐœÐŽÐµÐºÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ.ÐÐŸÐŽ "Ð Ð°Ð·ÐŽÐµÐ»Ð°ÐŒÐž ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ ÐžÐœÐŽÐµÐºÑÑ Ð¿ÐŸÐžÑÐºÐ°.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐžÐœÐŽÐµÐºÑ
+          </ContentsItem>
+	  <ContentsItem>
+	    ÐÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐžÐœÐŽÐµÐºÑ
+	  </ContentsItem>
+          <ContentsItem>
+             Ð£ÐŽÐ°Ð»ÐžÑÑ ÐžÐœÐŽÐµÐºÑ
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÐžÐœÐŽÐµÐºÑÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐžÐœÐŽÐµÐºÑ,Ð²Ð²ÐµÐŽÐžÑÐµ ÐžÐŒÑ ÐŽÐ»Ñ ÐœÐµÐ³ÐŸ Ð² Ð¿ÐŸÐ»Ðµ "ÐÐŒÑ ÐžÐœÐŽÐµÐºÑÐ°".ÐÑÐ±ÐµÑÐžÑÐµ, ÐºÐ°ÐºÐžÐµ ÐžÐ· Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÑÑ
+ ÐžÑÑÐŸÑÐœÐžÐºÐŸÐ² ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž Ð¿ÑÐžÑÐŸÐµÐŽÐžÐœÐžÑÑ Ðº ÐžÐœÐŽÐµÐºÑÑ, ÑÐµÐ»ÐºÐ°Ñ ÐœÐ° Ð¿ÐŸÐ»Ðµ ÐŸÐºÐŸÐ»ÐŸ ÐœÐžÑ
+. Ð¡Ð¿ÐžÑÐŸÐº Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð²ÑÐµ Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÑÐ»ÐµÐŒÐµÐœÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, Ð° ÑÐ°ÐºÐ¶Ðµ Ð¿ÐŸÐ»ÐœÑÐ¹ ÑÐµÐºÑÑ. Ð Ð°ÑÐ¿ÐŸÐ»Ð°Ð³Ð°Ñ Ð²ÑÐ±ÑÐ°ÐœÐœÑÐŒÐž ÐžÑÑÐŸÑÐœÐžÐºÐ°ÐŒÐž ÐŽÐ°ÐœÐœÑÑ
+, Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÑÐµÐ¿ÐµÐœÑ ÐŽÐµÑÐ°Ð»ÐžÐ·Ð°ÑÐžÐž ÐžÐœÐŽÐµÐºÑÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÐŒÐµÐœÑ "ÐÐ° ÑÑÐŸÐ²ÐœÐµ". ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÑÑÐž ÐŽÐµÑÐ°Ð»Ðž ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ,Ð¿ÑÐœÐºÑ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐžÐœÐŽÐµÐºÑ" ÑÑÐ°ÐœÐŸÐ²ÐžÑÑÑ Ð°ÐºÑÐžÐ²ÐœÑÐŒ (ÐµÑÐ»Ðž ÐœÐµÑ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÐžÐœÐŽÐµÐºÑÐ° Ñ ÑÐµÐŒÐž Ð¶Ðµ ÑÐ°ÐŒÑÐŒÐž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°ÐŒÐž).Ð©ÐµÐºÐœÐžÑÐµ ÐœÐ° ÐœÑÐŒ, ÑÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÐ¹ ÐžÐœÐŽÐµÐºÑ.
+<Break/>
+Ð§ÑÐŸÐ±Ñ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐžÐœÐŽÐµÐºÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ Ðž ÐžÐ·ÐŒÐµÐœÐžÑÐµ ÐŽÐµÑÐ°Ð»Ðž. ÐÐŸÐŽÑÐ²ÐµÑÐŽÐžÑÐµ, ÐœÐ°Ð¶Ð°Ð² ÐœÐ° "ÐÐ°ÐŒÐµÐœÐžÑÑ ÐžÐœÐŽÐµÐºÑ".
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÐžÐœÐŽÐµÐºÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÑ
+ ÐžÐœÐŽÐµÐºÑÐŸÐ² Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÐžÐœÐŽÐµÐºÑ".
+<Break/>
+ ÐÐœÐŽÐµÐºÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ - ÑÐŸÑ, ÐºÐŸÑÐŸÑÑÐ¹ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐœÐ° Ð¿ÐŸÐžÑÐºÐŸÐ²ÐŸÐ¹ ÑÑÑÐ°ÐœÐžÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,Ð¿ÐŸÐŒÐµÑÐµÐœ ÑÑÐ³Ð°ÐŒÐž "[ÐÐœÐŽÐµÐºÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ]" Ð² ÑÐ¿ÐžÑÐºÐµ "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÐœÐŽÐµÐºÑÑ".Ð§ÑÐŸÐ±Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐµÐ³ÐŸ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐžÐœÐŽÐµÐºÑ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÑÑÐ°ÐœÐŸÐ²ÐžÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ".
+<Break/>
+ ÐÑÐ»Ðž Ð¿ÐŸÐ·Ð²ÐŸÐ»ÐµÐœ ÑÐ°ÑÑÐžÑÐµÐœÐœÑÐ¹ Ð¿ÐŸÐžÑÐº (ÑÐµÑÐµÐ· Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð²ÐžÐŽÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°), ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐžÐœÐŽÐµÐºÑÐŸÐŒ ÐŸÑÐ»ÐžÑÐ°ÐµÑÑÑ.ÐÐ°Ð¶ÐŽÑÐ¹ ÐžÐœÐŽÐµÐºÑ Ð±Ð°Ð·ÐžÑÑÐµÑÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐœÐ° ÐŸÐŽÐœÐŸÐŒ ÐžÑÑÐŸÑÐœÐžÐºÐµ ÐŽÐ°ÐœÐœÑÑ
+.ÐÐŒÐµÐµÑÑÑ ÐœÐŸÐ²ÑÐ¹ ÐžÑÑÐŸÑÐœÐžÐº Ð¿ÑÐµÐ²ÐŽÐŸÐŽÐ°ÐœÐœÑÑ
+ "Ð²ÑÐµ Ð¿ÐŸÐ»Ñ",ÐºÐŸÑÐŸÑÑÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°ÑÑ Ð¿ÐŸÐžÑÐº Ð¿ÐŸ Ð²ÑÐµÐŒ ÑÐºÐ°Ð·Ð°ÐœÐœÑÐŒ ÐžÐœÐŽÐµÐºÑÐ°ÐŒ ÑÑÐ°Ð·Ñ.Ð£ÑÐŸÐ²ÐœÐž ÐœÐµ Ð¿ÑÐžÐ²ÑÐ·Ð°ÐœÑ Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐŸÐŒÑ ÐžÐœÐŽÐµÐºÑÑ,Ð° Ð¿ÑÐžÐŒÐµÐœÑÑÑÑÑ ÐºÐŸ Ð²ÑÐµÐŒ ÐžÐœÐŽÐµÐºÑÐ°ÐŒ.Ð¢Ð°ÐºÐžÐŒ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ,ÐžÐœÐŽÐµÐºÑÑ Ðž ÑÑÐŸÐ²ÐœÐž ÐŽÐŸÐ±Ð°Ð²Ð»ÑÑÑÑÑ ÐŸÑÐŽÐµÐ»ÑÐœÐŸ.ÐÐœÐŽÐµÐºÑÑ ÑÐŽÐ°Ð»ÑÑÑÑÑ ÑÐµÐŒ Ð¶Ðµ ÑÐ°ÐŒÑÐŒ ÑÐ¿ÐŸÑÐŸÐ±ÐŸÐŒ,ÐºÐ°Ðº Ð±ÑÐ»ÐŸ ÑÐºÐ°Ð·Ð°ÐœÐŸ Ð²ÑÑÐµ,ÐœÐŸ ÐžÐœÐŽÐµÐºÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ Ð±ÐŸÐ»ÑÑÐµ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ. Ð­ÑÐŸ Ð¿ÑÐŸÑÑÐŸ Ð¿ÐµÑÐ²ÑÐ¹ ÐžÐ· ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÑ
+ ÐžÐœÐŽÐµÐºÑÐŸÐ².   
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐžÐœÐŽÐµÐºÑÑ ÐœÐ° Ð²ÑÐµÑ
+ ÐžÑÑÐŸÑÐœÐžÐºÐ°Ñ
+,ÑÐµÐ»ÐºÐœÐžÑÐµ ÐºÐœÐŸÐ¿ÐºÑ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð²ÑÐµ". ÐÐŒÑ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐžÐœÐŽÐµÐºÑÐ° Ð±ÑÐŽÐµÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ ÑÐ²ÑÐ·Ð°ÐœÐŸ Ñ ÐžÐŒÐµÐœÐµÐŒ ÐžÑÑÐŸÑÐœÐžÐºÐ°.Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐžÐŒÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐžÐœÐŽÐµÐºÑ,ÐžÐ·ÐŒÐµÐœÐžÑÐµ ÐµÐ³ÐŸ ÐŽÐµÑÐ°Ð»Ðž Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ ÐžÐœÐŽÐµÐºÑ".   
+    </Section>
+    <Section name="partitionindexes">
+      <Title>ÐÐœÐŽÐµÐºÑÑ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ</Title>
+ ÐÐœÐŽÐµÐºÑÑ Ð¿ÐŸÑÑÑÐŸÐµÐœÑ ÐœÐ° ÐŽÐµÑÐ°Ð»ÑÐœÐŸÐŒ ÑÐµÐºÑÑÐµ ÐžÐ»Ðž ÐžÑÑÐŸÑÐœÐžÐºÐ°Ñ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐµÑÑÐŸ Ð¿ÐŸÐžÑÐºÐ° ÐŒÐŸÐ¶ÐµÑ Ð² ÐŽÐ°Ð»ÑÐœÐµÐ¹ÑÐµÐŒ ÑÐ¿ÑÐ°Ð²Ð»ÑÑÑÑÑ Ð¿ÑÑÑÐŒ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ ÐžÐœÐŽÐµÐºÑÐŸÐ² Ð»ÐžÐ±ÐŸ Ð¿ÐŸ ÑÐ·ÑÐºÑ ÐžÐ»Ðž Ð¿ÐŸ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÐŒ ÑÐžÐ»ÑÑÑÐ°ÐŒ.Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ,ÐºÐ°Ðº ÑÑÐŸ ÑÐŽÐµÐ»Ð°ÑÑ. ÐÐœÑÑÑÐž "Ð Ð°Ð·ÐŽÐµÐ»ÐŸÐ² ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐœÐŽÐµÐºÑÑ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ".
+<Break/>
+ÐÐžÐŽ "ÐÐœÐŽÐµÐºÑÑ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ" ÐžÐŒÐµÐµÑ ÑÑÐž Ð·ÐœÐ°ÑÐµÐœÐžÑ:"ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐžÐ»ÑÑÑÑ","ÐÐ°Ð·ÐœÐ°ÑÐžÑÑ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÐµ" Ðž "ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐ·ÑÐºÐž". ÐÐ»Ñ ÑÐŸÐ³ÐŸ ÑÑÐŸÐ±Ñ Ð±ÐŸÐ»ÑÑÐµ ÑÐ·ÐœÐ°ÑÑ ÐŸ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐž, ÑÐžÑÐ°Ð¹ÑÐµ  ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+ Ðž Ð¿ÐŸÐŽÐžÐœÐŽÐµÐºÑÐ°Ñ
+ Ð² Ð³Ð»Ð°Ð²Ðµ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.
+
+      <Section name="definefilters">
+        <Title>ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐžÐ»ÑÑÑÑ</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐžÐ»ÑÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ.</ObviousSentence>
+        <Contents>
+          <ContentsGroup linkto="simple">
+            <ContentsItem>
+               ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐžÐ»ÑÑÑ
+            </ContentsItem>
+            <ContentsItem>
+               Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐžÐ»ÑÑÑ
+            </ContentsItem>
+            <ContentsItem>
+               ÐÐ·ÐŒÐµÐœÐžÑÑ ÑÐžÐ»ÑÑÑ
+            </ContentsItem>
+          </ContentsGroup>
+        </Contents>
+        <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð€ÐžÐ»ÑÑÑÑ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÑÑ ÐÐ°ÐŒ Ð³ÑÑÐ¿Ð¿ÐžÑÐŸÐ²Ð°ÑÑ Ð² Ð¿ÐŸÐŽÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð²ÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ð¿ÐŸ  ÐžÐœÐŽÐµÐºÑÑ,ÐŽÐ»Ñ ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ Ð·Ð°ÐŽÐ°ÐœÐœÐŸÐ¹ ÐŒÐŸÐŽÐµÐ»Ðž.
+ <Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÑÐžÐ»ÑÑÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ "ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐžÐ»ÑÑÑÑ" Ðž Ð²Ð²ÐµÐŽÐžÑÐµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐŽÐ»Ñ ÐœÐŸÐ²ÐŸÐ³ÐŸ ÑÐžÐ»ÑÑÑÐ° Ð² Ð¿ÐŸÐ»Ðµ "ÐÐŒÑ ÑÐžÐ»ÑÑÑÐ° ÑÑÐ±ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž".ÐÐ°ÑÐµÐŒ Ð²ÑÐ±ÐµÑÐžÑÐµ Ñ
+Ð°ÑÐ°ÐºÑÐµÑÐœÑÐµ Ð¿ÑÐžÐ·ÐœÐ°ÐºÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐžÐµ ÐžÐ»Ðž ÑÐ»ÐµÐŒÐµÐœÑÐ°ÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÐžÐ»Ðž ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ ÑÐ°ÑÑÐŒÐ°ÑÑÐžÐ²Ð°ÐµÐŒÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð°.ÐÐ²ÐµÐŽÐžÑÐµ Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ,ÑÑÐŸÐ±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð² ÑÐµÑÐµÐœÐžÐµ ÐŽÐµÐ¹ÑÑÐ²ÐžÑ ÑÑÐŸÐ³ÐŸ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÑ.ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐµÑÐµÐºÐ»ÑÑÐ°ÑÑ "ÐÐºÐ»ÑÑÐµÐœÐžÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²", ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑ ÑÐžÐ»ÑÑÑÑ, ÐžÐ»Ðž "ÐÑÐºÐ»ÑÑÐµÐœÐžÐµ" ÐžÑ
+.ÐÐ°ÐºÐŸÐœÐµÑ,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ Ð»ÑÐ±ÐŸÐ¹ ÑÑÐ°ÐœÐŽÐ°ÑÑ PERL, Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÑÐµ ÑÐ»Ð°Ð³Ðž Ð²ÑÑÐ°Ð¶ÐµÐœÐžÑ,ÑÑÐŸÐ±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð¿ÑÐž ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÐž (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ("i" ÐŽÐ»Ñ ÑÐ»ÑÑÐ°Ñ ÐœÐµÑÑÐ²ÑÑÐ²ÐžÑÐµÐ»ÑÐœÐŸÐ³ÐŸ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÑ),ÐÐ°ÐºÐŸÐœÐµÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐžÐ»ÑÑÑ",ÑÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐžÐ»ÑÑÑ Ðº ÑÐ¿ÐžÑÐºÑ "Ð€ÐžÐ»ÑÑÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÑÑÐ±ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹".
+ <Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÐžÐ»ÑÑÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐžÐ»ÑÑÑ". 
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÑÐžÐ»ÑÑÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ°,Ð·Ð°ÐŒÐµÐœÐžÑÐµ Ð»ÑÐ±ÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ, ÐºÐŸÑÐŸÑÐŸÐµ Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµÐŒ Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ ÑÐžÐ»ÑÑÑ",ÑÑÐŸÐ±Ñ Ð·Ð°ÐºÑÐµÐ¿ÐžÑÑ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ.
+      </Section>
+      <Section name="assignpartitions">
+        <Title>ÐÐ°Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐœÐ°Ð·ÐœÐ°ÑÐžÑÑ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÐ¹ ÑÐžÐ»ÑÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ.   </ObviousSentence>
+        <Contents>
+          <ContentsGroup linkto="simple">
+            <ContentsItem>
+               ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ
+            </ContentsItem>
+            <ContentsItem>
+              Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ
+            </ContentsItem>
+            <ContentsItem>
+              Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+            </ContentsItem>
+            <ContentsItem>
+               ÐÑÐžÑÑÐºÐ° ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+            </ContentsItem>
+          </ContentsGroup>
+        </Contents>
+        <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÐŒÐµÑ Ð·Ð°ÐŽÐ°ÐœÐœÑÐ¹ ÑÐžÐ»ÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ "ÐÐ°Ð·ÐœÐ°ÑÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ" ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐžÐœÐŽÐµÐºÑÐŸÐ² ÐŽÐ»Ñ ÑÑÐŸÐ³ÐŸ ÐžÐ»Ðž ÐŽÐ»Ñ Ð³ÑÑÐ¿Ð¿Ñ ÑÐžÐ»ÑÑÑÐŸÐ². ÐÑÐ±ÐµÑÐžÑÐµ Ð¶ÐµÐ»Ð°ÑÐµÐ»ÑÐœÑÐ¹ ÑÐžÐ»ÑÑÑ (ÐžÐ»Ðž ÑÐžÐ»ÑÑÑÑ) ÐžÐ· ÑÐ¿ÐžÑÐºÐ° "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÑÐžÐ»ÑÑÑÑ ÑÑÐ±ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž", Ð²Ð²ÐµÐŽÐžÑÐµ ÐžÐŒÑ ÐŽÐ»Ñ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ Ð² Ð¿ÐŸÐ»Ðµ "ÐÐŒÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐµ".
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐµ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐµ".
+<Break/>
+  Ð§ÑÐŸÐ±Ñ Ð¿ÑÐŸÐžÐ·Ð²ÐµÑÑÐž ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÑÑÐ°ÐœÐŸÐ²ÐžÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ".
+<Break/>
+Ð§ÑÐŸÐ±Ñ ÐŸÑÐžÑÑÐžÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÑÐžÑÑÐžÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ".
+      </Section>
+      <Section name="assignlanguages">
+        <Title>ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÑÐ·ÑÐºÐž</Title>
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŽÐµÑÐ°Ð»ÐžÐ·ÐžÑÐŸÐ²Ð°ÐœÐŸ,ÐºÐ°Ðº ÐŸÐ³ÑÐ°ÐœÐžÑÐžÑÑ ÐžÐœÐŽÐµÐºÑÑ Ð¿ÐŸÐžÑÐºÐ° ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐžÐŒÐž ÑÐ·ÑÐºÐ°ÐŒÐž. ÐÑ ÑÐŸÐ²ÐµÑÑÐ°ÐµÑÐµ ÑÑÐŸ Ð¿ÑÐž ÑÐµÐ³ÐµÐœÐµÑÐžÑÐŸÐ²Ð°ÐœÐžÐž ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÐºÐ»Ð°Ð²ÐžÑÑ "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÑÐ·ÑÐºÐž" Ð² Ð¿ÐµÑÐµÑÐœÐµ "ÐÐœÐŽÐµÐºÑÑ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ".
+        <Contents>
+          <ContentsGroup linkto="simple">
+            <ContentsItem>
+               Ð£Ð¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐ·ÑÐºÐ°ÐŒÐž
+            </ContentsItem>
+            <ContentsItem>
+               ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐ·ÑÐº
+            </ContentsItem>
+            <ContentsItem>
+               Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐ·ÑÐº
+            </ContentsItem>
+            <ContentsItem>
+               Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐ·ÑÐºÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+            </ContentsItem>
+            <ContentsItem>
+               ÐÑÐžÑÑÐºÐ° ÑÐ·ÑÐºÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+            </ContentsItem>
+          </ContentsGroup>
+        </Contents>
+        <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÐ¹ ÑÐ·ÑÐº ÐŽÐ»Ñ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÑÐ·ÑÐºÐž" ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐžÐœÐŽÐµÐºÑÐ° ÐŽÐ»Ñ ÑÑÐŸÐ³ÐŸ. ÐÑÐ±ÐµÑÐžÑÐµ Ð¶ÐµÐ»Ð°ÑÐµÐ»ÑÐœÑÐ¹ ÑÐ·ÑÐº ÐžÐ· ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐ³ÐŸ ÑÐ¿ÐžÑÐºÐ° "Ð¯Ð·ÑÐºÐž ÐŽÐ»Ñ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÑ" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐ·ÑÐº"
+<Break/>
+Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÐ·ÑÐº,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° "ÐÑÐ±ÐŸÑÑ ÑÐ·ÑÐºÐ°" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐ·ÑÐº".
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÑÐ·ÑÐº Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ".
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÐŸÑÐžÑÑÐžÑÑ ÑÐ·ÑÐº Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÑÐžÑÑÐžÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ".
+      </Section>
+    </Section>
+    <Section name="xcollectionsearching">
+      <Title>Ð¡ÐŸÐ²ÐŒÐµÑÑÐœÑÐ¹ Ð¿ÐŸÐžÑÐº Ð² ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+</Title>
+ Greenstone Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑÑ Ð¿ÐŸÐžÑÐº Ð² ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ ÑÐ°Ð·Ð»ÐžÑÐœÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+, ÐºÐ°Ðº ÐµÑÐ»Ðž Ð±Ñ ÐŸÐœÐž Ð±ÑÐ»Ðž ÐŸÐ±ÑÐµÐŽÐžÐœÐµÐœÑ.Ð­ÑÐŸ ÑÐŽÐµÐ»Ð°ÐœÐŸ ÐŽÐ»Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ "Ð¡ÑÐ¿ÐµÑÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž", ÐºÐŸÑÐŸÑÐ°Ñ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÐžÐœÐŽÐžÐ²ÐžÐŽÑÐ°Ð»ÑÐœÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.Ð "Ð Ð°Ð·ÐŽÐµÐ»Ð°Ñ
+ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐžÑÐº Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            ÐÑÐ±ÐŸÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÐµÐ¶ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐŸÐœÐœÑÐ¹ Ð¿ÐŸÐžÑÐº Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐºÐŸÐœÑÑÐŸÐ»ÑÐœÑÐ¹ ÑÐ¿ÐžÑÐŸÐº ÐŽÐŸÑÑÑÐ¿ÐœÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹.Ð¢ÐµÐºÑÑÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¿ÐŸÐŒÐµÑÐµÐœÑ Ðž ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÑÐµÑÐœÐ°. Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŽÑÑÐ³ÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ð² ÐºÐŸÑÐŸÑÑÑ
+ Ð¿ÐŸÐžÑÐº Ð±ÑÐŽÐµÑ Ð¿ÑÐŸÐ²ÐŸÐŽÐžÑÑÑÑ Ð¿Ð°ÑÐ°Ð»Ð»ÐµÐ»ÑÐœÐŸ, ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÐœÐžÑ
+ Ð² ÑÐ¿ÐžÑÐºÐµ (ÑÐµÐ»ÐºÐœÐžÑÐµ ÑÐœÐŸÐ²Ð°, ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÐžÑ
+). ÐÑÐ»Ðž ÐŸÑÐŸÐ±ÑÐ°ÐœÐ° ÑÐŸÐ»ÑÐºÐŸ ÐŸÐŽÐœÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÑÐŸ ÐŒÐµÐ¶ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐŸÐœÐœÑÐ¹ Ð¿ÐŸÐžÑÐº ÐœÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐµÐœ.
+<Break/>
+ ÐÐ»Ñ ÐŽÐ°Ð»ÑÐœÐµÐ¹ÑÐžÑ
+ ÐŽÐµÑÐ°Ð»ÐµÐ¹ ÑÐŒ.Ð³Ð»Ð°Ð²Ñ 1 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.
+    </Section>
+    <Section name="classifiers">
+      <Title>ÐÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ</Title>
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ Ðº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÐºÐŸÑÐŸÑÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ°. Ð "Ð Ð°Ð·ÐŽÐµÐ»Ð°Ñ
+ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÑÐŸÑÐŒÐŸÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ²". 
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÑÐ±ÐŸÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° Ðž ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÐŽÐ°Ð»ÐžÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ
+          </ContentsItem>
+          <ContentsItem>
+            ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐ·ÐŒÐµÐœÐžÑÑ Ð¿ÐŸÑÐ»ÐµÐŽÐŸÐ²Ð°ÑÐµÐ»ÑÐœÐŸÑÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ²
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº "ÐÑÐ±ÐŸÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° ÐŽÐ»Ñ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÑ" Ð²ÐœÐžÐ·Ñ ÐŸÐºÐœÐ°,Ðž Ð·Ð°ÑÐµÐŒ ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐºÐ°Ð·Ð°ÐœÐœÑÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ". ÐÐŸÑÐ²Ð»ÑÐµÑÑÑ ÐŸÐºÐœÐŸ, ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÐŸÐµ "ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ²".ÐÐœÑÑÑÑÐºÑÐžÐž ÐŽÐ»Ñ ÑÑÐŸÐ³ÐŸ ÐŽÐžÐ°Ð»ÐŸÐ³Ð° ÑÐµ Ð¶Ðµ ÑÐ°ÐŒÑÐµ,ÑÑÐŸ ÐºÐ°ÑÐ°ÑÑÑÑ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ² (<Reference target="plugins">ÐÐ»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°</Reference>).ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐÑ ÑÑÐŸÑÐŒÐžÑÐŸÐ²Ð°Ð»Ðž ÐœÐŸÐ²ÑÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ, ÐŸÐœ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÑÑ Ð² ÐºÐŸÐœÐµÑ ÑÐ¿ÐžÑÐºÐ° "Ð¢ÐµÐºÑÑÐžÐµ Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ".  
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ".
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°" (ÐžÐ»Ðž ÑÐµÐ»ÐºÐœÑÑÑ ÐŽÐ²Ð° ÑÐ°Ð·Ð° ÐœÐ° ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐµ Ð² ÑÐ¿ÐžÑÐºÐµ).
+<Break/>
+ ÐÐŸÑÑÐŽÐŸÐº ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ² Ð² ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÐŸÐœÐœÐŸÐ¹ Ð»ÐžÐœÐµÐ¹ÐºÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐž ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ ÑÐŸÐŒÑ,ÐºÐŸÑÐŸÑÑÐ¹ Ð¿ÐŸÐºÐ°Ð·Ð°Ðœ Ð·ÐŽÐµÑÑ.Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð¿ÐŸÑÑÐŽÐŸÐº,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ, ÐºÐŸÑÐŸÑÑÐ¹ ÐÑ Ñ
+ÐŸÑÐžÑÐµ Ð¿ÐµÑÐµÐŒÐµÑÑÐžÑÑ, Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²Ð²ÐµÑÑ
+" ÐžÐ»Ðž "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²ÐœÐžÐ·".
+<Break/>
+ ÐÐ»Ñ ÐŽÐ°Ð»ÑÐœÐµÐ¹ÑÐµÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐŸÑÐœÐŸÑÐžÑÐµÐ»ÑÐœÐŸ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ² ÑÐžÑÐ°Ð¹ÑÐµ Ð³Ð»Ð°Ð²Ñ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.
+    </Section>
+    <Section name="formatstatements">
+      <Title>ÐÑÐŸÐ±ÐµÐœÐœÐŸÑÑÐž ÑÐŸÑÐŒÐ°ÑÐ°</Title>
+ ÐÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ° ÑÐ¿ÑÐ°Ð²Ð»ÑÑÑ ÑÑÑÑÐºÑÑÑÐŸÐ¹ Ðž Ð²ÐžÐŽÐŸÐŒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐœÐž Ð·Ð°ÑÑÐ°Ð³ÐžÐ²Ð°ÑÑ ÑÐ°ÐºÐžÐµ Ð²ÐµÑÐž,ÐºÐ°Ðº ÐŒÐµÑÑÐŸ Ð¿ÐŸÑÐ²Ð»ÐµÐœÐžÑ ÐºÐœÐŸÐ¿ÐºÐž,ÐºÐŸÐ³ÐŽÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑÑÑ,Ðž ÐºÐ°ÐºÐžÐµ ÑÐ²ÑÐ·Ðž ÐŸÑÐŸÐ±ÑÐ°Ð¶Ð°ÑÑÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐŒ DateList. ÐÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ° ÐœÐµ Ð»ÐµÐ³ÐºÐŸ ÑÐ°Ð·ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÑÑ,Ðž ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÑÐŸÑÐžÑÐ°ÑÑ Ð³Ð»Ð°Ð²Ñ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone. Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÐ¶ÐŽÐ°ÑÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÑÐŸÑÐŒÐ°ÑÐ° Ðž ÑÐŸ, ÐºÐ°Ðº ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÐµÑ ÐŽÐŸÑÑÑÐ¿ Ðº ÐœÐžÐŒ. Ð "Ð Ð°Ð·ÐŽÐµÐ»Ð°Ñ
+ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÑÐŸÐ±ÐµÐœÐœÐŸÑÑÐž ÑÐŸÑÐŒÐ°ÑÐ°".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             Ð€ÐŸÑÐŒÐ°ÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÐºÐŸÐŒÐ°ÐœÐŽ ÑÐŸÑÐŒÐ°ÑÐ°
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐºÐŸÐŒÐ°ÐœÐŽ ÑÐŸÑÐŒÐ°ÑÐ°
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ ÐºÐŸÐŒÐ°ÐœÐŽ ÑÐŸÑÐŒÐ°ÑÐ°
+          </ContentsItem>
+        </ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+             Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ Ð²Ð°ÑÐžÐ°ÐœÑÑ ÑÐŸÑÐŒÐ°ÑÐžÑÐŸÐ²Ð°ÐœÐžÑ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÑÐžÐŒÐµÐœÐžÑÑ ÐºÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ° Ðº ÑÐµÐŒÑ-ÐœÐžÐ±ÑÐŽÑ Ð² ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐŒ ÑÐ¿ÐžÑÐºÐµ "ÐÑÐ±ÐŸÑ ÑÑÐµÐŽÑÑÐ²",ÐºÐŸÑÐŸÑÑÐ¹ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÐºÐ°Ð¶ÐŽÑÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ Ðž Ð²ÑÑÑÐŸÐµÐœÐœÑÐ¹ ÑÐ¿ÐžÑÐŸÐº ÑÑÐµÐŽÑÑÐ². ÐÐŸÐ³ÐŽÐ° ÐÑ Ð²ÑÐ±ÐžÑÐ°ÐµÑÐµ ÑÑÐµÐŽÑÑÐ²Ð°, ÐµÑÑÑ ÐŽÐ²Ð° ÑÐžÐ¿Ð° ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ. ÐÐµÐºÐŸÑÐŸÑÑÐµ ÑÑÐµÐŽÑÑÐ²Ð° ÑÐ²Ð»ÑÑÑÑÑ Ð¿ÑÐŸÑÑÐŸ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž ÐžÐ»Ðž ÐœÐµÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž,ÐŸÐœÐž ÑÐ¿ÑÐ°Ð²Ð»ÑÑÑÑÑ ÐºÐœÐŸÐ¿ÐºÐ°ÐŒÐž. ÐÑÑÐ³ÐžÐµ ÑÑÐµÐ±ÑÑÑ, ÑÑÐŸÐ±Ñ Ð±ÑÐ»Ð° ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐ° ÑÐŸÑÐŒÐ°ÑÐœÐ°Ñ ÑÑÑÐŸÐºÐ°. ÐÐ»Ñ ÐœÐžÑ
+ ÐžÐŒÐµÐµÑÑÑ ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº "ÐÐŸÐ·ÐŽÐµÐ¹ÑÑÐ²ÑÑÑÐžÐ¹ ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑ", ÑÑÐŸÐ±Ñ Ð²ÑÐ±ÑÐ°ÑÑ, Ðº ÐºÐ°ÐºÐŸÐ¹ ÑÐ°ÑÑÐž ÑÑÐµÐŽÑÑÐ² ÑÑÑÐŸÐºÐ° ÐŸÐ±ÑÐ°ÑÐ°ÐµÑÑÑ,ÐµÑÐ»Ðž ÑÑÐŸ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ, ÐŸÐ±Ð»Ð°ÑÑÑ ÑÐµÐºÑÑÐ°   ("Ð¡ÑÑÐŸÐºÐ° ÑÐŸÑÐŒÐ°ÑÐ° HTML") ÐŽÐ»Ñ Ð²Ð²ÐŸÐŽÐ° ÑÑÑÐŸÐºÐž, Ðž Ð²ÑÐ±ÐŸÑ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ "ÐÐµÑÐµÐŒÐµÐœÐœÑÑ
+". Ð§ÑÐŸÐ±Ñ Ð²ÑÑÐ°Ð²ÐžÑÑ Ð¿ÐµÑÐµÐŒÐµÐœÐœÑÑ Ð² ÑÐµÐºÑÑÑÑ Ð¿ÐŸÐ·ÐžÑÐžÑ Ð² ÑÐŸÑÐŒÐ°ÑÐœÑÑ ÑÑÑÐŸÐºÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÑ ÐžÐ· ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐ³ÐŸ ÑÐ¿ÐžÑÐºÐ°  Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÑÑÐ°Ð²ÐžÑÑ". 
+<Break/>
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐŸÑÐŒÐ°Ñ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ ÐŽÐ»Ñ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑÐ°, Ð²ÑÐ±ÐžÑÐ°Ñ Ð±Ð»Ð°ÐœÐº ÑÐ²ÐŸÐ¹ÑÑÐ². Ð­ÑÐŸÑ ÑÐŸÑÐŒÐ°Ñ Ð·Ð°ÑÐµÐŒ Ð¿ÑÐžÐŒÐµÐœÑÐµÑÑÑ ÐºÐŸ Ð²ÑÐµÐŒ Ð¿ÑÐžÐŒÐµÐœÐžÐŒÑÐŒ ÑÐ²ÐŸÐ¹ÑÑÐ²Ð°ÐŒ, ÐµÑÐ»Ðž ÐŽÑÑÐ³ÐŸÐµ ÐœÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐŸ.
+<Break/>
+Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÑ ÐºÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ°,Ð²ÐœÐµÑÐžÑÐµ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ,ÐºÐ°Ðº ÐŸÐ±ÑÑÑÐœÐµÐœÐŸ Ð²ÑÑÐµ, Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐŸÑÐŒÐ°Ñ".ÐÐŸÐ²Ð°Ñ ÐºÐŸÐŒÐ°ÐœÐŽÐ° ÑÐŸÑÐŒÐ°ÑÐ° Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² ÑÐ¿ÐžÑÐºÐµ "Ð¢ÐµÐºÑÑÐžÐµ Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÐºÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ°".Ð¢ÐŸÐ»ÑÐºÐŸ ÐŸÐŽÐœÐ° ÐºÐŸÐŒÐ°ÐœÐŽÐ° ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÑÐ²ÑÐ·Ð°ÐœÐ° Ñ ÐºÐ°Ð¶ÐŽÐŸÐ¹ ÐºÐŸÐŒÐ±ÐžÐœÐ°ÑÐžÐµÐ¹ ÑÐ²ÐŸÐ¹ÑÑÐ²ÐŸ/ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑ.
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ°, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÑ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐŸÑÐŒÐ°Ñ".
+<Break/>
+  Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐºÐŸÐŒÐ°ÐœÐŽÑ ÑÐŸÑÐŒÐ°ÑÐ°, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÑ ÐŒÐ· ÑÐ¿ÐžÑÐºÐ°, ÐžÐ·ÐŒÐµÐœÐžÑÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ ÑÐŸÑÐŒÐ°Ñ".
+<Break/>
+ ÐÐ° ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐµÐ¹ ÐŸ Ð¿ÐµÑÐµÐŒÐµÐœÐœÑÑ
+ Ðž ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑÐ°Ñ
+ ÑÑÐµÐŽÑÑÐ² ÐŸÐ±ÑÐ°ÑÐžÑÐµÑÑ Ðº Ð³Ð»Ð°Ð²Ðµ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.
+      <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ ÐÑÐ»Ðž ÐºÐœÐŸÐ¿ÐºÐ° "ÐÐŸÐ·Ð²ÐŸÐ»ÐµÐœÐœÑÐµ ÑÐ°ÑÑÐžÑÐµÐœÐœÑÐµ Ð²Ð°ÑÐžÐ°ÐœÑÑ" Ð¿ÐŸÐŒÐµÑÐµÐœÐ°,ÑÐŸ ÑÐ°Ð·ÑÐµÑÐµÐœÑ ÐœÐµÐºÐŸÑÐŸÑÑÐµ Ð¿ÑÐŸÐŽÐ²ÐžÐœÑÑÑÐµ Ð²Ð°ÑÐžÐ°ÐœÑÑ ÑÐŸÑÐŒÐ°ÑÐžÑÐŸÐ²Ð°ÐœÐžÑ . Ð¡Ð¿ÐžÑÐŸÐº ÑÑÐµÐŽÑÑÐ², ÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐŸÑÐŒÐ°ÑÐžÑÐŸÐ²Ð°ÐœÑ, ÐœÐµÐŒÐœÐŸÐ³ÐŸ ÐžÐ·ÐŒÐµÐœÐµÐœ Ðž Ð±ÐŸÐ»ÑÑÐµÐµ ÑÐžÑÐ»ÐŸ Ð¿ÐµÑÐµÐŒÐµÐœÐœÑÑ
+ ÐŽÐŸÑÑÑÐ¿ÐœÐŸ ÐŽÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÐºÐŸÐŒÐ°ÐœÐŽÐŸÐ¹ ÑÐŸÑÐŒÐ°ÑÐ°, ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°Ñ Ð±ÐŸÐ»ÑÑÐµÐµ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÑÑÐ°ÐœÐžÑÐµÐ¹ ÐŸÑÐžÐ³ÐžÐœÐ°Ð»-ÐŒÐ°ÐºÐµÑÐ°.
+    </Section>
+    <Section name="translatetext">
+      <Title>ÐÐµÑÐµÐ²ÐŸÐŽ ÑÐµÐºÑÑÐ°</Title>
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐµÑÐµÐ²ÐŸÐŽÐ°, Ð³ÐŽÐµ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐ·ÑÐº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÑ
+ ÑÑÐ°Ð³ÐŒÐµÐœÑÐŸÐ² ÑÐµÐºÑÑÐ° ÐŽÐ»Ñ ÑÐ°ÑÑÐµÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð "Ð Ð°Ð·ÐŽÐµÐ»Ðµ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐµÑÐµÐ²ÐµÑÑÐž ÑÐµÐºÑÑ".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÐŽÐ°Ð»ÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ
+          </ContentsItem>
+          <ContentsItem>
+             ÐÐ±ÐœÐŸÐ²ÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽÐ°
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð¡ÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐžÑÐµ Ð²Ñ
+ÐŸÐŽ Ð² ÑÐ¿ÐžÑÐŸÐº "Ð¡Ð²ÐŸÐ¹ÑÑÐ²Ð°". ÐÐžÐ¶Ðµ Ð¿ÐŸÑÐ²ÑÑÑÑ ÑÑÑÐŸÐºÐž ÑÐ¿ÐµÑÐžÑÐžÑÐœÐŸÐ³ÐŸ ÑÐ·ÑÐºÐ°, ÑÐ²ÑÐ·Ð°ÐœÐœÑÐµ Ñ ÑÑÐžÐŒ ÑÐ²ÐŸÐ¹ÑÑÐ²ÐŸÐŒ. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº "Ð¯Ð·ÑÐº Ð¿ÐµÑÐµÐ²ÐŸÐŽÐ°",ÑÑÐŸÐ±Ñ Ð²ÑÐ±ÑÐ°ÑÑ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÐ¹ ÑÐ·ÑÐº Ðž Ð²Ð²ÐµÑÑÐž Ð¿ÐµÑÐµÐ²ÐµÐŽÐµÐœÐœÑÐ¹ ÑÐµÐºÑÑ Ð² ÐŸÐ±Ð»Ð°ÑÑÑ ÑÐµÐºÑÑÐ°, ÐŸÐ±ÑÐ°ÑÐ°ÑÑÑ Ðº "ÐÐ°ÑÐ°Ð»ÑÐœÐŸÐŒÑ ÑÑÐ°Ð³ÐŒÐµÐœÑÑ ÑÐµÐºÑÑÐ°",ÐµÑÐ»Ðž ÑÑÐŸ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ. ÐÐŸ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÐž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ".
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐ¹ Ð¿ÐµÑÐµÐ²ÐŸÐŽ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ Ð² ÑÐ°Ð±Ð»ÐžÑÐµ "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ Ð¿ÐµÑÐµÐ²ÐŸÐŽÑ" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ".
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ, ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÑÐ¹ÑÐµ Ð² ÑÐµÐºÑÑÐŸÐ²ÐŸÐ¹ ÐŸÐ±Ð»Ð°ÑÑÐž "ÐÐµÑÐµÐ²ÐµÐŽÐµÐœÐœÑÐ¹ ÑÐµÐºÑÑ" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ".
+    </Section>
+    <Section name="metadatasets">
+      <Title>Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title>
+ Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» ÐŸÐ±ÑÑÑÐœÑÐµÑ ÐŸÐ±Ð·ÐŸÑÐœÑÑ Ð¿Ð°ÐœÐµÐ»Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. Ð "Ð Ð°Ð·ÐŽÐµÐ»Ðµ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+".
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            ÐÐŸÑÑÑÐ¿ÐœÑÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+
+          </ContentsItem>
+          <ContentsItem>
+            ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÐœÐ°Ð±ÐŸÑÐ° ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+          </ContentsItem>
+          <ContentsItem>
+            Ð ÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐœÐ°Ð±ÐŸÑÐ° ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+          </ContentsItem>
+          <ContentsItem>
+            Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐœÐ°Ð±ÐŸÑÐ° ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð­ÑÐŸ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ,ÑÑÐŸÐ±Ñ ÑÐ°ÑÑÐŒÐŸÑÑÐµÑÑ ÐœÐ°Ð±ÐŸÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÐºÐŸÑÐŸÑÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹,Ðž ÑÐ»ÐµÐŒÐµÐœÑÑ,ÐºÐŸÑÐŸÑÑÐµ ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐœÐ°Ð±ÐŸÑÐ°. ÐÑÐ±ÐµÑÐžÑÐµ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° "ÐÐŸÑÑÑÐ¿ÐœÑÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+",ÑÑÐŸÐ±Ñ Ð²ÐžÐŽÐµÑÑ ÐŽÐµÑÐ°Ð»Ðž ÐžÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ².
+<Break/>
+Ð§ÑÐŸÐ±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐŽÑÑÐ³ÐŸÐ¹ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐÐ°Ð±ÐŸÑ ÐÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+" Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÐ°Ð¹Ð» Ñ ÐœÐ°Ð±ÐŸÑÐŸÐŒ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ (.mds).
+<Break/>
+Ð ÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐœÐ°Ð±ÐŸÑÐ° ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐŸ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ Greenstone Editor for Metadata Sets (GEMS). ÐÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÑ "Ð ÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐÐ°Ð±ÐŸÑ ÐÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+", ÑÑÐŸÐ±Ñ Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ GEMS.
+<Break/>
+ÐÑÐ»Ðž ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ Ð²Ð°ÐŒ Ð±ÐŸÐ»ÑÑÐµ ÐœÐµ ÐœÑÐ¶ÐµÐœ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ Ðž ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° "Ð£ÐŽÐ°Ð»ÐžÑÑ ÐÐ°Ð±ÐŸÑ ÐÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+". ÐÑÐ»Ðž Ð²Ñ ÐœÐ°Ð·ÐœÐ°ÑÐžÐ»Ðž ÐºÐ°ÐºÐžÐµ-Ð»ÐžÐ±ÐŸ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ Ðº ÑÐ»ÐµÐŒÐµÐœÑÐ°ÐŒ Ð² ÑÐŽÐ°Ð»ÐµÐœÐœÐŸÐŒ ÐœÐ°Ð±ÐŸÑÐµ, Ñ Ð²Ð°Ñ ÑÐ¿ÑÐŸÑÑÑ ÐºÐ°Ðº Ñ ÐœÐžÐŒÐž Ð¿ÐŸÑÑÑÐ¿ÐžÑÑ Ð¿ÑÐž ÑÐ»ÐµÐŽÑÑÐµÐ¹ Ð·Ð°Ð³ÑÑÐ·ÐºÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+    </Section>
+  </Section>
+
+  <Section name="producingthecollection">
+    <Title>ÐÐŸÑÑÑÐŸÐµÐœÐžÐµ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title>
+ ÐÐŒÐµÑ ÑÐŸÐ±ÑÐ°ÐœÐœÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ ÐŽÐ»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ð°ÐœÐœÐŸÑÐžÑÐŸÐ²Ð°Ð² ÐžÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž Ðž ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÐ°Ð² ÐŽÐžÐ·Ð°Ð¹Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐµÐ¿ÐµÑÑ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Greenstone. Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÑÑÐŸ ÑÐŽÐµÐ»Ð°ÑÑ.
+    <Section name="thecreateview">
+      <Title>Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ</Title>
+<ObviousSentence> Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. </ObviousSentence>
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+	    Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+	  </ContentsItem>
+	  <ContentsItem>
+	    ÐÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÑÐ¹ Ð¿ÑÐŸÑÐŒÐŸÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+	  </ContentsItem>
+	</ContentsGroup>
+        <ContentsGroup linkto="advanced">
+          <ContentsItem>
+             Ð ÐµÐ³ÐžÑÑÑÐ°ÑÐžÑ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐ¹
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ,ÑÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ,Ð²ÑÐ¿ÐŸÐ»ÐœÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÐµ ÑÑÐµÐœÐ°ÑÐžÐž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Greenstone ÐžÐ· ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž, ÐºÐŸÑÐŸÑÑÑ ÐÑ Ð¿ÐŸÐŽÐ³ÐŸÑÐŸÐ²ÐžÐ»Ðž. Ð©ÐµÐ»ÑÐŸÐº ÐœÐ° "ÐÐŸÑÑÑÐŸÐµÐœÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž" ÐœÐ°ÑÐžÐœÐ°ÐµÑ Ð¿ÑÐŸÑÐµÑÑ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑÐµÐŒÑ, ÐºÐŸÑÐŸÑÐŸÐµ ÐŽÐ»Ñ ÑÑÐŸÐ³ÐŸ Ð¿ÐŸÑÑÐµÐ±ÑÐµÑÑÑ, Ð·Ð°Ð²ÐžÑÐžÑ ÐŸÑ ÑÐ°Ð·ÐŒÐµÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž ÑÐžÑÐ»Ð° ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÐµÐŒÑÑ
+ ÐžÐœÐŽÐµÐºÑÐŸÐ² (ÐŽÐ»Ñ ÐŸÐ³ÑÐŸÐŒÐœÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÑÑÐŸ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐ°ÑÑ). ÐÐœÐŽÐžÐºÐ°ÑÐŸÑ Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐžÑ ÑÐºÐ°Ð·ÑÐ²Ð°ÐµÑ, ÐœÐ°ÑÐºÐŸÐ»ÑÐºÐŸ Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœ Ð¿ÑÐŸÑÐµÑÑ. Ð§ÑÐŸÐ±Ñ ÐŸÑÐŒÐµÐœÐžÑÑ Ð¿ÑÐŸÑÐµÑÑ Ð² Ð»ÑÐ±ÐŸÐµ Ð²ÑÐµÐŒÑ, ÐœÐ°Ð¶ÐŒÐžÑÐµ "ÐÑÐŒÐµÐœÐ° Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ".
+      <Break/>
+      ÐÐ°Ð¶Ð°Ð² ÐœÐ° "ÐÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÑÐ¹ Ð¿ÑÐŸÑÐŒÐŸÑÑ" Ð¿ÐŸÑÐ»Ðµ ÑÐŸÐ³ÐŸ, ÐºÐ°Ðº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±ÑÐ»Ð° ÑÑÐ¿ÐµÑÐœÐŸ ÑÐŸÐ±ÑÐ°ÐœÐ°, ÐŒÐŸÐ¶ÐœÐŸ ÐŸÑÐºÑÑÑÑ Ð²ÐµÐ±-Ð±ÑÐ°ÑÐ·ÐµÑ Ñ Ð³Ð»Ð°Ð²ÐœÐŸÐ¹ ÑÑÑÐ°ÐœÐžÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+      <Anchor name="advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+      Ð ÐŒÐŸÐŽÑÑÐµ Ð­ÐºÑÐ¿ÐµÑÑ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð·Ð°Ð¿ÐžÑÑ "ÐÐŸÐ³ Ð¡ÐŸÐŸÐ±ÑÐµÐœÐžÐ¹" ÑÐ»ÐµÐ²Ð°, ÑÑÐŸÐ±Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ, Ð±ÑÐ»Ðž Ð»Ðž Ð¿ÑÐµÐŽÑÐŽÑÑÐžÐµ Ð¿ÐŸÐ¿ÑÑÐºÐž ÑÐºÐŸÐœÑÑÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÑÐ¿ÐµÑÐœÑ ÐžÐ»Ðž ÐœÐµÑ. ÐÑÐ±ÐµÑÐžÑÐµ Ð¶ÐµÐ»Ð°ÐµÐŒÑÑ Ð·Ð°Ð¿ÐžÑÑ,ÑÐµÐ»ÐºÐ°Ñ Ð¿ÐŸ Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐ¹ ÐŽÐ°ÑÐµ Ð² ÑÐ¿ÐžÑÐºÐµ "ÐÑÑÐŸÑÐžÑ Ð·Ð°Ð¿ÐžÑÐž".
+    </Section>
+    <Section name="buildsettings">
+      <Title>ÐÐŒÐ¿ÐŸÑÑ Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ</Title>
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ, ÐºÐ°Ðº Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÑÑÑÐ¿ Ðº ÑÐ°Ð·Ð»ÐžÑÐœÑÐŒ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑÐŒ ÐžÐŒÐ¿ÐŸÑÑÐ° Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°ÐŒ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ. ÐÐ° ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐµÐ¹ Ð¿ÐŸ ÐžÐŒÐ¿ÐŸÑÑÑ Ðž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÑÐžÑÐ°Ð¹ÑÐµ Ð³Ð»Ð°Ð²Ñ 1 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.  
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐ±ÑÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐžÐŒÐ¿ÐŸÑÑÐ°
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ Ð£Ð¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐ°Ð·Ð»ÐžÑÐœÑÐŒÐž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°ÐŒÐž ÑÐŽÐµÐ»Ð°ÐœÐŸ Ð¿ÐŸÐŽÐŸÐ±ÐœÐŸ ÑÐŸÐŒÑ ÑÐ¿ÐŸÑÐŸÐ±Ñ, ÐºÐŸÑÐŸÑÑÐ¹ ÐŸÐ¿ÐžÑÐ°Ðœ Ð¿ÑÐž "ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐž Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ²" Ð² <Reference target="plugins">ÐÐ»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°</Reference>. ÐÐµÐºÐŸÑÐŸÑÑÐµ Ð¿ÐŸÐ»Ñ ÑÑÐµÐ±ÑÑÑ ÑÐžÑÐ»ÐµÐœÐœÑÑ
+ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ². ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÑ
+ ÐžÐ»Ðž ÐœÐ°Ð¿ÐµÑÐ°ÑÐ°ÑÑ ÐžÐ»Ðž ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÑÑÑÐµÐ»ÐºÐž Ð²Ð²ÐµÑÑ
+ Ðž Ð²ÐœÐžÐ·, ÑÑÐŸÐ±Ñ ÑÐ²ÐµÐ»ÐžÑÐžÑÑ ÐžÐ»Ðž ÑÐŒÐµÐœÑÑÐžÑÑ ÑÐµÐºÑÑÐµÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ (Ð² ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ ÑÐ»ÑÑÐ°ÑÑ
+ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐŸÐ³ÑÐ°ÐœÐžÑÐžÐ²Ð°ÐµÑ ÐŽÐžÐ°Ð¿Ð°Ð·ÐŸÐœ, Ð² ÐºÐŸÑÐŸÑÑÐ¹ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÐŸÐ¹ÑÐž). ÐÑÑÐ³ÐžÐµ Ð¿ÐŸÐ»Ñ ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž Ð¿ÑÐž ÑÐµÐ»ÑÐºÐµ Ð¿ÐŸ ÐºÐœÐŸÐ¿ÐºÐµ (ÐÐŸÐ²ÑÐŸÑÐœÑÐ¹ ÑÐµÐ»ÑÐŸÐº ÐŽÐµÐ»Ð°ÐµÑ ÐžÑ
+ ÐœÐµÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž). 
+    </Section>
+  </Section>
+
+  <Section name="miscellaneous">
+    <Title>Ð Ð°Ð·ÐœÐŸÐµ</Title>
+ Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑ ÐŸÑÐŸÐ±ÐµÐœÐœÐŸÑÑÐž ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°,ÐºÐŸÑÐŸÑÑÐµ ÐœÐµ ÑÐ²ÑÐ·Ð°ÐœÑ ÐœÐž Ñ ÐºÐ°ÐºÐžÐŒ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐžÐŒ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµÐŒ.
+    <Section name="preferences">
+      <Title>ÐÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÑ</Title>
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ ÐŽÐžÐ°Ð»ÐŸÐ³ Ð¿ÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÐ¹,ÐŽÐŸÑÑÑÐ¿ÐœÑÐ¹ Ð¿ÑÐž ÐŸÑÐºÑÑÑÐžÐž "Ð€Ð°Ð¹Ð»Ð°", Ð° Ð·Ð°ÑÐµÐŒ "ÐÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÐ¹".
+      <Contents>
+        <ContentsGroup linkto="simple">
+	  <ContentsItem>
+	    ÐÐ±ÑÐµÐµ
+	  </ContentsItem>
+	  <ContentsItem>
+	    Ð¡Ð¿ÐŸÑÐŸÐ±
+	  </ContentsItem>
+          <ContentsItem>
+            Ð¢ÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÑÐµÑÐºÐžÐ¹ Ð¿ÑÐŸÑÐµÑÑ
+          </ContentsItem>
+          <ContentsItem>
+             Ð¡Ð²ÑÐ·Ñ
+          </ContentsItem>
+          <ContentsItem>
+             ÐÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐµÐœÐžÐµ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+ÐÐµÑÐ²Ð°Ñ ÐŸÐ¿ÑÐžÑ "ÐÐ±ÑÐµÐµ" - ÑÑÐŸ ÑÐµÐºÑÑÐŸÐ²ÐŸÐµ Ð¿ÐŸÐ»Ðµ ÐŽÐ»Ñ Ð²Ð²ÐµÐŽÐµÐœÐžÑ Ð°ÐŽÑÐµÑÐ° Ð²Ð°ÑÐµÐ¹ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ. ÐÐœ Ð±ÑÐŽÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°Ðœ Ð² Ð·ÐœÐ°ÑÐµÐœÐžÐž ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ "Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ" Ðž "ÐÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÑÐ¹". Ð¡Ð»ÐµÐŽÑÑÐ°Ñ ÐŸÐ¿ÑÐžÑ - ÑÑÐŸ Ð²ÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐµ ÐŒÐµÐœÑ Ñ ÑÐ·ÑÐºÐ°ÐŒÐž, Ð² ÐºÐŸÑÐŸÑÑÑ
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐÐœÑÐµÑÑÐµÐ¹Ñ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœ. ÐÑÐ»Ðž ÐÑ ÐžÐ·ÐŒÐµÐœÑÐµÑÐµ ÑÐ»ÐŸÐ²Ð°ÑÑ, Ð²ÑÐ±ÐžÑÐ°Ñ ÐºÐ°ÐºÐŸÐ¹-Ð»ÐžÐ±ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ°, ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÐµÑÐµÐ·Ð°Ð³ÑÑÐ·ÐžÑÑ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ, ÑÑÐŸÐ±Ñ Ð·Ð°Ð³ÑÑÐ·ÐžÑÑ ÐœÐŸÐ²ÑÐµ ÑÑÑÐŸÐºÐž ÑÐ·ÑÐºÐ° ÐžÐ· ÑÑÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ.
+<Break/>
+ÐÑÐ»Ðž Ð²ÑÐ±ÑÐ°ÐœÐ° "ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐžÐ·Ð²Ð»ÐµÐºÐ°ÐµÐŒÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+", ÑÐ°Ð·Ð»ÐžÑÐœÐŸÐµ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ, ÑÐ²ÑÐ·Ð°ÐœÐœÐŸÐµ Ñ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž, Ð²ÑÐµÐ³ÐŽÐ° Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð²ÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, ÐºÐŸÑÐŸÑÑÐµ Ð±ÑÐ»Ðž Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž ÐžÐ·Ð²Ð»ÐµÑÐµÐœÑ ÐžÐ· ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ². ÐÑÐŒÐµÐœÐ° ÑÑÐŸÐ³ÐŸ Ð²ÑÐ±ÐŸÑÐ° ÑÐºÑÑÐ²Ð°ÐµÑ ÑÑÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, Ñ
+ÐŸÑÑ ÐŸÐœÐž Ð²ÑÑ ÐµÑÑ  ÐŽÐŸÑÑÑÐ¿ÐœÑ Ð² ÑÐµÑÐµÐœÐžÐµ ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÐºÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž Ð² ÑÐ°ÐŒÐºÐ°Ñ
+ ÐŸÐºÐŸÐœÑÐ°ÑÐµÐ»ÑÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Greenstone. ÐÑÐ»Ðž Ð²ÑÐ±ÑÐ°ÐœÐŸ "ÐÐŸÐºÐ°Ð·Ð°ÑÑ ÑÐ°Ð·ÐŒÐµÑÑ ÑÐ°Ð¹Ð»Ð°", ÑÐŸ ÑÐ°Ð·ÐŒÐµÑ ÑÐ°Ð¹Ð»Ð° Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑÑÑ ÑÑÐŽÐŸÐŒ Ñ ÐºÐ°Ð¶ÐŽÑÐŒ ÑÐ°Ð¹Ð»ÐŸÐŒ Ð² ÑÐ°Ð±ÐŸÑÐµÐŒ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ðµ, Ð° ÑÐ°ÐºÐ¶Ðµ Ð² ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐŒ ÐŽÐµÑÐµÐ²Ðµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð² Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑÑ
+ Gather Ðž Enrich.
+<Break/>
+ÐÐ°ÐœÐµÐ»Ñ "Ð¡Ð¿ÐŸÑÐŸÐ±" ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ ÑÑÐŸÐ²ÐœÐµÐŒ Ð¿ÐŸÐŽÑÐŸÐ±ÐœÐŸÑÑÐµÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°. ÐÐ° ÑÐ°ÐŒÐŸÐŒ ÐœÐžÐ¶ÐœÐµÐŒ ÑÑÐŸÐ²ÐœÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐŸÐº ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ "ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ Ð¿ÐŸÐŒÐŸÑÐœÐžÐº", Ð¿ÑÐž ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐž ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ Ð¿ÑÐŸÐµÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÐœÐŸ, Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ, ÑÑÐµÐ±ÑÑÑÐžÐµ Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸÐ³ÐŸ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÑ, ÑÐºÑÑÑÑ Ðž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑÑÑ ÐŒÐžÐœÐžÐŒÐ°Ð»ÑÐœÐŸ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÑÐŒ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸÐŒ Ð·Ð°Ð¿ÐžÑÐµÐ¹. ÐÐ°ÐŸÐ±ÐŸÑÐŸÑ, ÐœÐ°ÐžÐ²ÑÑÑÐ°Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ° "Ð­ÐºÑÐ¿ÐµÑÑ" ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°ÐµÑ ÐŽÐŸÑÑÑÐ¿ ÐºÐŸ Ð²ÑÐµÐŒ ÑÑÐµÐŽÑÑÐ²Ð°ÐŒ Ð¿ÑÐŸÐµÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÑ, Ð²ÐºÐ»ÑÑÐ°Ñ Ð¿ÐŸÐ·ÐžÑÐžÐŸÐœÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ² Ðž Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ², Ð° ÑÐ°ÐºÐ¶Ðµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð¿ÐŸÐ»ÐœÑÐ¹ Ð²ÑÑ
+ÐŸÐŽ ÐžÐ· Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÑÑÐŸÐ±Ñ Ð·Ð°ÑÐžÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð² Ð¶ÑÑÐœÐ°Ð»Ðµ Ð·Ð°Ð¿ÐžÑÐµÐ¹. Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐžÐ»Ðž Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ ÑÐ¿ÐŸÑÐŸÐ±Ñ, ÐºÐ»ÐžÐºÐœÐžÑÐµ ÑÐ°ÐŽÐžÐŸ-ÐºÐœÐŸÐ¿ÐºÑ, ÑÐ»ÐµÐŽÑÑÑÑÑ Ð·Ð° ÑÐ¿ÐŸÑÐŸÐ±ÐŸÐŒ, ÐºÐŸÑÐŸÑÑÐ¹ ÐžÐœÑÐµÑÐµÑÑÐµÑ ÐÐ°Ñ. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð±ÑÑÑÑÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ, ÐºÐ°ÐºÐŸÐ¹ ÑÐ¿ÐŸÑÐŸÐ± ÐÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÐµ, ÑÐ°ÑÑÐŒÐ°ÑÑÐžÐ²Ð°Ñ Ð»ÐžÐœÐµÐ¹ÐºÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ Ð² ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐŒ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐµ. 
+<Break/>
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐŒÐŸÐ¶ÐµÑ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑ ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ ÑÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÑÐµÑÐºÐžÐµ Ð¿ÑÐŸÑÐµÑÑÑ Ð¿ÑÐž ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÐž, ÐºÐ°ÐºÐžÐµ ÐžÐ· ÑÐ°Ð·Ð»ÐžÑÐœÑÑ
+ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐ¹ ÑÐžÐŒÐ²ÐŸÐ»ÐŸÐ² ÑÐ²Ð»ÑÑÑÑÑ Ð²ÐžÐŽÐžÐŒÑÐŒÐž. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ "Ð¢ÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÑÐµÑÐºÐžÐµ Ð¿ÑÐŸÑÐµÑÑÑ", ÑÑÐŸÐ±Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ, ÐºÐ°ÐºÐžÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž, Ð¿ÑÐŸÐ²ÐµÑÑÑ Ð¿ÐŸÐ»Ñ ÑÑÐŽÐŸÐŒ Ñ ÑÐµÐŒÐž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑÐŒÐž, ÐºÐŸÑÐŸÑÑÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž. ÐÐŒÐµÑÑÐŸ ÑÑÐŸÐ³ÐŸ ÐŒÐŸÐ¶ÐœÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº Ð²ÐœÐžÐ·Ñ ÑÐºÑÐ°ÐœÐ°,ÑÑÐŸÐ±Ñ Ð²ÑÐ±ÑÐ°ÑÑ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž. ÐÐ°ÐºÑÑÑÐžÐµ ÐŽÐžÐ°Ð»ÐŸÐ³Ð° Ð¿ÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÐ¹ Ð·Ð°ÐºÑÐµÐ¿Ð»ÑÐµÑ ÑÑÐž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÑÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÑÐµÑÐºÐŸÐ³ÐŸ Ð¿ÑÐŸÑÐµÑÑÐ°. Ð­ÑÐž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž Ñ
+ÑÐ°ÐœÑÑÑÑ Ð²ÐŒÐµÑÑÐµ Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹,Ð° ÐœÐµ Ð² ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÐŸÐŒ ÑÐ°Ð¹Ð»Ðµ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°.
+<Break/>
+ÐÐ»Ð°Ð²ÐžÑÐ° "Ð¡ÐŸÐµÐŽÐžÐœÐµÐœÐžÐµ" Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐÐ°ÐŒ ÐžÐ·ÐŒÐµÐœÑÑÑ Ð¿ÑÑÑ Ðº Ð»ÐŸÐºÐ°Ð»ÑÐœÐŸÐŒÑ ÑÐµÑÐ²ÐµÑÑ Greenstone, ÐºÐŸÑÐŸÑÑÐ¹ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸÐ³ÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑÐŸÐŒÐµ ÑÐŸÐ³ÐŸ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐŒÐŸÐŽÑÐ»Ñ ÐŽÐŸÑÑÑÐ¿Ð° Ðº ÐÐœÑÐµÑÐœÐµÑÑ Ð¿ÑÐŸÐºÑÐž (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐŽÐ»Ñ Ð·Ð°Ð³ÑÑÐ·ÐºÐž ÑÐ°Ð¹Ð»ÐŸÐ²; ÑÐŒÐŸÑÑÐž ÑÐ°Ð·ÐŽÐµÐ» <Reference target="downloadingfiles">ÐÐ°Ð³ÑÑÐ¶Ð°ÑÑ Ð€Ð°Ð¹Ð»Ñ ÐžÐ· ÐÐœÑÐµÑÐœÐµÑÐ°</Reference> ÐŽÐ»Ñ Ð¿ÐŸÐŽÑÐŸÐ±ÐœÐŸÑÑÐµÐ¹). ÐÐŸÐŒÐµÑÑÑÐµ ÑÐ»Ð°Ð³ÐŸÐ²ÑÑ ÐºÐœÐŸÐ¿ÐºÑ, ÑÑÐŸÐ±Ñ Ð²ÐºÐ»ÑÑÐžÑÑ ÐŒÐŸÐŽÑÐ»Ñ ÐŽÐŸÑÑÑÐ¿Ð°, Ðž ÑÐºÐ°Ð¶ÐžÑÐµ ÐŽÐµÑÐ°Ð»Ðž Ð°ÐŽÑÐµÑÐ° ÑÐµÑÐ²ÐµÑÐ° Ð¿ÑÐŸÐºÑÐž Ðž ÐœÐŸÐŒÐµÑ Ð¿ÐŸÑÑÐ°. ÐÐŸÐŽÑÐ»Ñ ÐŽÐŸÑÑÑÐ¿Ð° Ð±ÑÐŽÐµÑ Ð°ÐºÑÐžÐ²ÐžÑÐŸÐ²Ð°Ðœ Ð¿ÑÐž Ð·Ð°ÐºÑÑÑÐžÐž ÐŽÐžÐ°Ð»ÐŸÐ³ÐŸÐ²ÐŸÐ³ÐŸ ÐŸÐºÐœÐ° ÐÐ¿ÑÐžÐ¹.
+<Break/>
+Ð ÑÐµÑÐµÐœÐžÐµ ÑÐµÑÑÐžÐž ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐŒÐŸÐ¶ÐµÑ ÐŽÐ°Ð²Ð°ÑÑ Ð¿ÑÐµÐŽÑÐ¿ÑÐµÐŽÐžÑÐµÐ»ÑÐœÑÐµ ÑÐŸÐŸÐ±ÑÐµÐœÐžÑ, ÐºÐŸÑÐŸÑÑÐµ ÐžÐœÑÐŸÑÐŒÐžÑÑÑÑ ÐÐ°Ñ ÐŸ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÑÑ
+ ÐœÐµÐ¿ÑÐµÐŽÐ²ÐžÐŽÐµÐœÐœÑÑ
+ Ð¿ÐŸÑÐ»ÐµÐŽÑÑÐ²ÐžÑÑ
+ ÐÐ°ÑÐžÑ
+ ÐŽÐµÐ¹ÑÑÐ²ÐžÐ¹. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð·Ð°Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÑÑ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐµ, Ð²ÑÐ±ÐžÑÐ°Ñ Ð¿ÐŸÐ»Ðµ "ÐÐµ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÑ ÑÑÐŸ Ð¿ÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐµÐœÐžÐµ ÑÐœÐŸÐ²Ð°". ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÐŸÐ·ÐŸÐ±ÐœÐŸÐ²ÐžÑÑ Ð¿ÐŸÑÐ²Ð»ÐµÐœÐžÐµ Ð¿ÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐ°ÑÑÐžÑ
+ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐ¹,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÐºÐ»Ð°Ð²ÐžÑÑ "ÐÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐµÐœÐžÐµ". ÐÑÐ±ÐµÑÐžÑÐµ Ð¿ÐŸÐ»Ðµ ÑÑÐŽÐŸÐŒ Ñ Ð¿ÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐ°ÑÑÐžÐŒÐž ÑÐŸÐŸÐ±ÑÐµÐœÐžÑÐŒÐž, ÐµÑÐ»Ðž ÐÑ Ñ
+ÐŸÑÐžÑÐµ ÑÐœÐŸÐ²Ð° Ð¿ÐŸÐ»ÑÑÐ°ÑÑ ÐžÑ
+.
+     </Section>
+    <Section name="fileassociations">
+      <Title>ÐÑÑÐŸÑÐžÐ°ÑÐžÐž ÑÐ°Ð¹Ð»Ð°</Title>
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐÐœÑÐµÑÑÐµÐ¹Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐžÐµ Ð¿ÑÐžÐºÐ»Ð°ÐŽÐœÑÐµ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ, ÑÑÐŸÐ±Ñ ÐŸÑÐºÑÑÐ²Ð°ÑÑ ÑÐ¿ÐµÑÐžÑÐžÑÐœÑÐµ ÑÐžÐ¿Ñ ÑÐ°Ð¹Ð»ÐŸÐ². Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» ÐŸÐ±ÑÑÑÐœÑÐµÑ, ÐºÐ°Ðº ÐœÐ°Ð·ÐœÐ°ÑÐ°ÑÑ Ðž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÑÑÐž ÑÐ²ÑÐ·Ð°ÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ.
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+             ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÐž
+          </ContentsItem>
+          <ContentsItem>
+             Ð ÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÐž
+          </ContentsItem>
+          <ContentsItem>
+             Ð£ÐŽÐ°Ð»ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÐž
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+  Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð°ÑÑÐŸÑÐžÐžÑÐŸÐ²Ð°ÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ ÐŸÑÐºÑÑÐ²Ð°ÑÑ ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»" Ðž ÑÐµÐ»ÐºÐ°ÑÑ "ÐÑÑÐŸÑÐžÐžÑÐŸÐ²Ð°ÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ".
+<Break/>
+Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÐž, Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÐµÐ»ÐµÐ²ÐŸÐµ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð° ÐžÐ· ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐ³ÐŸ ÑÐ¿ÐžÑÐºÐ° ÐžÐ»Ðž ÐœÐ°Ð¿ÐžÑÐžÑÐµ ÐœÐŸÐ²ÐŸÐµ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ (ÐœÐµ Ð²ÐºÐ»ÑÑÐ°Ñ "."). ÐÐ°ÑÐµÐŒ ÐžÐ»Ðž ÐœÐ°Ð¿ÐžÑÐžÑÐµ Ð² ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐŒ Ð¿ÐŸÐ»Ðµ ÐºÐŸÐŒÐ°ÐœÐŽÑ,Ð·Ð°Ð¿ÑÑÐºÐ°ÑÑÑÑ Ð¶ÐµÐ»Ð°ÑÐµÐ»ÑÐœÐŸÐµ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÐµ,ÐžÐ»Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÐµ ÐžÐ· ÐŽÐžÐ°Ð»ÐŸÐ³ÐŸÐ²ÐŸÐ³ÐŸ ÐŸÐºÐœÐ° "ÐÑÐŸÑÐŒÐŸÑÑ". ".%1" ÐŒÐŸÐ¶ÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ Ð² ÐºÐŸÐŒÐ°ÐœÐŽÐµ Ð·Ð°Ð¿ÑÑÐºÐ°, ÑÑÐŸÐ±Ñ Ð²ÑÑÐ°Ð²ÐžÑÑ ÐžÐŒÑ ÑÐ°Ð¹Ð»Ð°, ÐºÐŸÑÐŸÑÑÐ¹ ÐŽÐŸÐ»Ð¶ÐµÐœ ÐŸÑÐºÑÑÑÑÑÑ. ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐŸÐœÐž Ð·Ð°Ð¿ÐŸÐ»ÐœÐµÐœÑ,Ð¿ÑÐœÐºÑ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÐž" ÑÑÐ°ÐœÐŸÐ²ÐžÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒ Ðž ÐŒÐŸÐ¶ÐœÐŸ ÑÐµÐ»ÑÐºÐŸÐŒ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÑ.  
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐµ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð°. ÐÑÐ±Ð°Ñ ÑÑÑÐµÑÑÐ²ÑÑÑÐ°Ñ ÐºÐŸÐŒÐ°ÐœÐŽÐ° ÑÐ²ÑÐ·Ðž Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑÑÑ Ð² Ð¿ÐŸÐ»Ðµ Ð·Ð°Ð¿ÑÑÐºÐ° ÐºÐŸÐŒÐ°ÐœÐŽ. ÐÑÑÐµÐŽÐ°ÐºÑÐžÑÑÐ¹ÑÐµ ÐµÐµ Ðž Ð·Ð°ÑÐµÐŒ ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÑ".
+ <Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐµ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ Ð°ÑÑÐŸÑÐžÐ°ÑÐžÑ".(Ð Ð°ÑÑÐžÑÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð° ÐŸÑÑÐ°ÐµÑÑÑ Ð² ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐŒ ÑÐ¿ÐžÑÐºÐµ "ÐÐ»Ñ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÑ ÑÐ°Ð¹Ð»ÐŸÐ²").
+ <Break/>
+ ÐÑÐŸÑÐžÐ°ÑÐžÐ²ÐœÑÐµ ÑÐ°Ð¹Ð»Ñ Ñ
+ÑÐ°ÐœÑÑÑÑ Ð² Ð³Ð»Ð°Ð²ÐœÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐµ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°, Ð² ÑÐ°Ð¹Ð»Ðµ, ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÐŸÐŒ "associations.xml".
+    </Section>
+    <Section name="exportingcollections">
+      <Title>Ð­ÐºÑÐ¿ÐŸÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÐœÐ° CD-ROM</Title>
+      
+Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑ, ÐºÐ°Ðº ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð² ÑÐ°ÐŒÐŸÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÑÑÐžÐ¹ÑÑ CD-ROM Greenstone. 
+      <Contents>
+        <ContentsGroup linkto="simple">
+          <ContentsItem>
+            ÐÐ°Ðº ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ
+          </ContentsItem>
+        </ContentsGroup>
+      </Contents>
+      <Anchor name="simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</Anchor>
+Greenstone ÐŒÐŸÐ¶ÐµÑ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐŸÐŽÐœÑ ÐžÐ»Ðž Ð±ÐŸÐ»ÐµÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Ð² ÑÐ°ÐŒÐŸÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÑÑÐžÐ¹ÑÑ CD-ROM Ð¿ÐŸÐŽ Windows. Ð§ÑÐŸÐ±Ñ ÑÑÐŸ ÑÐŽÐµÐ»Ð°ÑÑ, ÐŽÐŸÐ»Ð¶ÐµÐœ  Ð±ÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ Ð¿Ð°ÐºÐµÑ "Ð­ÐºÑÐ¿ÐŸÑÑ Ð² CD-ROM". ÐÐœ ÐœÐµ Ð²ÐºÐ»ÑÑÐµÐœ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ, Ð¿ÐŸÑÑÐŸÐŒÑ ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐÐ°ÑÑ ÐžÐœÑÑÐ°Ð»Ð»ÑÑÐžÑ, ÑÑÐŸÐ±Ñ ÐµÐ³ÐŸ Ð²ÐºÐ»ÑÑÐžÑÑ.
+<Break/>
+ Ð§ÑÐŸÐ±Ñ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐŸÑÐºÑÐŸÐ¹ÑÐµ ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»" Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ "Ð­ÐºÑÐ¿ÐŸÑÑ Ð² CD-ROM". ÐÐŸÑÐ²Ð»ÑÐµÑÑÑ ÑÐ¿ÐžÑÐŸÐº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÑÐŸÐ±ÑÐ°ÐœÐžÐ¹ Greenstone; ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° Ð»ÑÐ±ÐŸÐ¹, ÑÑÐŸÐ±Ñ ÑÐ²ÐžÐŽÐµÑÑ ÐµÐµ ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ. ÐÐŸÐŒÐµÑÑÑÐµ Ð²ÑÐ±ÑÐ°ÐœÐœÑÐµ Ð¿ÐŸÐ»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÐŽÐ»Ñ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²Ð²ÐµÑÑÐž ÐžÐŒÑ CD-ROM Ð² Ð¿ÐŸÐ»Ðµ: ÑÑÐŸ ÑÐŸ, ÑÑÐŸ Ð¿ÐŸÑÐ²ÐžÑÑÑ Ð² ÑÑÐ°ÑÑÐŸÐ²ÐŸÐŒ ÐŒÐµÐœÑ, ÐºÐŸÐ³ÐŽÐ° CD-ROM Ð±ÑÐŽÐµÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ. ÐÐ°ÑÐµÐŒ ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð­ÐºÑÐ¿ÐŸÑÑ". ÐÑÐŸÑÐµÑÑ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐŒÐœÐŸÐ³ÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² Ðž ÐŒÐŸÐ¶ÐµÑ Ð·Ð°ÐœÑÑÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÐŒÐžÐœÑÑ.
+<Break/>
+ ÐÐŸÑÐ»Ðµ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÑ Greenstone Ð¿ÐŸÐºÐ°Ð¶ÐµÑ ÐžÐŒÑ Ð¿Ð°Ð¿ÐºÐž, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐµÐ¹ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ Ð¿ÐžÑÑÑÐžÐ¹ ÐºÐŸÐŒÐ¿Ð°ÐºÑ-ÐŽÐžÑÐº ÐŽÐ»Ñ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÑ ÐµÐ³ÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÐœÐ° ÑÐžÑÑÑÐ¹ CD-ROM.
+    </Section>
+  </Section>
+</Document>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/help_index.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/help_index.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/help_index.xml	(revision 10506)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Document><Section name="introduction"><Title>ÐÐ²ÐµÐŽÐµÐœÐžÐµ</Title><Section name="ofmiceandmenus"><Title>ÐÑÑÑ Ðž ÐÐµÐœÑ</Title></Section><Section name="howtoavoidthisdocument"><Title>ÐÐ°Ðº ÐžÐ·Ð±ÐµÐ¶Ð°ÑÑ ÑÑÐµÐœÐžÑ ÑÑÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°</Title></Section></Section><Section name="startingoff"><Title>ÐÐŸ ÑÑÐ°ÑÑÐ°</Title><Section name="creatingacollection"><Title>Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title></Section><Section name="savingacollection"><Title>Ð¡ÐŸÑ
+ÑÐ°ÐœÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title></Section><Section name="openingacollection"><Title>ÐÑÐºÑÑÑÐžÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title></Section><Section name="deletingcollections"><Title>Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹</Title></Section></Section><Section name="downloadingfiles"><Title>ÐÐ°Ð³ÑÑÐ·ÐžÑÑ ÑÐ°Ð¹Ð»Ñ ÐžÐ· ÐžÐœÑÐµÑÐœÐµÑ</Title><Section name="themirrorview"><Title>ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐÐ°Ð³ÑÑÐ·ÐžÑÑ</Title></Section></Section><Section name="collectingfiles"><Title>Ð¡Ð±ÐŸÑ ÑÐ°Ð¹Ð»ÐŸÐ² ÐŽÐ»Ñ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title><Section name="thegatherview"><Title>ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐœÐ°ÐºÐŸÐ¿ÐžÑÐµÐ»Ñ</Title></Section><Section name="creatingfolders"><Title>Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿Ð°Ð¿ÐŸÐº</Title></Section><Section name="addingfiles"><Title>ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²</Title></Section><Section name="removingfiles"><Title>Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²</Title></Section><Section name="filteringthetree"><Title>Ð€ÐžÐ»ÑÑÑÐŸÐ²Ð°ÐœÐžÐµ ÐŽÐµÑÐµÐ²Ð°</Title></Section></Section><Section name="enrichingacollection"><Title>ÐÐ±ÐŸÐ³Ð°ÑÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž</Title><Section name="theenrichview"><Title>ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐŸÐ±ÐŸÐ³Ð°ÑÐµÐœÐžÑ</Title></Section><Section name="selectingmetadatasets"><Title>ÐÑÐ±ÐŸÑ ÐœÐ°Ð±ÐŸÑÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title></Section><Section name="appendingmetadata"><Title>ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title></Section><Section name="addingpreviouslydefinedmetadata"><Title>ÐÐŸÐ±Ð°Ð²Ð»ÐœÐžÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title></Section><Section name="updatingmetadata"><Title>ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title></Section><Section name="removingmetadata"><Title>Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title></Section><Section name="reviewingmetadata"><Title>ÐÑÐŸÑÐŒÐŸÑÑ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title></Section><Section name="importingpreviouslyassignedmetadata"><Title>ÐÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title></Section></Section><Section name="designingacollection"><Title>ÐÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title><Section name="thedesignview"><Title>ÐÐžÐŽ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°</Title></Section><Section name="generalsettings"><Title>ÐÐ±ÑÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž</Title></Section><Section name="plugins"><Title>ÐÐ»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°</Title></Section><Section name="searchtypes"><Title>ÐÐžÐŽÑ Ð¿ÐŸÐžÑÐºÐ°</Title></Section><Section name="searchindexes"><Title>ÐÐœÐŽÐµÐºÑÑ Ð¿ÐŸÐžÑÐºÐ°</Title></Section><Section name="partitionindexes"><Title>ÐÐœÐŽÐµÐºÑÑ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ</Title><Section name="definefilters"><Title>ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐžÐ»ÑÑÑÑ</Title></Section><Section name="assignpartitions"><Title>ÐÐ°Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ</Title></Section><Section name="assignlanguages"><Title>ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÑÐ·ÑÐºÐž</Title></Section></Section><Section name="xcollectionsearching"><Title>Ð¡ÐŸÐ²ÐŒÐµÑÑÐœÑÐ¹ Ð¿ÐŸÐžÑÐº Ð² ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+</Title></Section><Section name="classifiers"><Title>ÐÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ</Title></Section><Section name="formatstatements"><Title>ÐÑÐŸÐ±ÐµÐœÐœÐŸÑÑÐž ÑÐŸÑÐŒÐ°ÑÐ°</Title></Section><Section name="translatetext"><Title>ÐÐµÑÐµÐ²ÐŸÐŽ ÑÐµÐºÑÑÐ°</Title></Section><Section name="metadatasets"><Title>Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</Title></Section></Section><Section name="producingthecollection"><Title>ÐÐŸÑÑÑÐŸÐµÐœÐžÐµ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</Title><Section name="thecreateview"><Title>Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ</Title></Section><Section name="buildsettings"><Title>ÐÐŒÐ¿ÐŸÑÑ Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ</Title></Section></Section><Section name="miscellaneous"><Title>Ð Ð°Ð·ÐœÐŸÐµ</Title><Section name="preferences"><Title>ÐÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÑ</Title></Section><Section name="fileassociations"><Title>ÐÑÑÐŸÑÐžÐ°ÑÐžÐž ÑÐ°Ð¹Ð»Ð°</Title></Section><Section name="exportingcollections"><Title>Ð­ÐºÑÐ¿ÐŸÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÐœÐ° CD-ROM</Title></Section></Section></Document>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/howtoavoidthisdocument.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/howtoavoidthisdocument.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/howtoavoidthisdocument.htm	(revision 10506)
@@ -0,0 +1,66 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="howtoavoidthisdocument"><font size="5" face="Verdana"><strong>1.2: ÐÐ°Ðº ÐžÐ·Ð±ÐµÐ¶Ð°ÑÑ ÑÑÐµÐœÐžÑ ÑÑÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+
+ ÐÐµ ÑÐžÑÐ°Ð¹ÑÐµ ÑÑÐŸÑ ÑÐµÐºÑÑ Ð¿ÐŸÐŒÐŸÑÐž Ð¿ÐŸÐ»ÐœÐŸÑÑÑÑ! ÐÐŸÑÑÐ°ÑÐŸÑÐœÐŸ Ð¿ÑÐŸÑÐµÑÑÑ, ÐºÐ°Ðº ÑÑÐŒÐµÑÑ Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð¿ÐŸÐŒÐŸÑÑ, ÐºÐŸÐ³ÐŽÐ° ÐÑ ÐœÑÐ¶ÐŽÐ°ÐµÑÐµÑÑ Ð² ÑÑÐŸÐŒ.  
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+           Ð§ÑÐ²ÑÑÐ²ÐžÑÐµÐ»ÑÐœÐ°Ñ ÐºÐŸÐœÑÐµÐºÑÑÐœÐ°Ñ Ð¿ÐŸÐŒÐŸÑÑ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐœÑÑÑÑÐŒÐµÐœÑ Ð¿ÐŸÐŽÑÐºÐ°Ð·ÐŸÐº
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÑÑÐ³ÐžÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ÐÑÐœÐºÑÑ ÐŒÐµÐœÑ "ÐÐŸÐŒÐŸÑÑ" ÑÐºÐ°Ð·ÑÐ²Ð°ÑÑ ÑÐµ ÑÐ°Ð·ÐŽÐµÐ»Ñ,ÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐœÐ°ÐžÐ±ÐŸÐ»ÐµÐµ Ð°ÐŽÐµÐºÐ²Ð°ÑÐœÑÐŒÐž ÐŽÐ»Ñ Ð¿ÐŸÐŒÐŸÑÐž, Ðž ÑÐŸÐ¿ÑÐŸÐ²ÐŸÐ¶ÐŽÐ°ÑÑÑÑ ÐœÐµÐ±ÐŸÐ»ÑÑÐžÐŒ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµÐŒ ÐºÐœÐžÐ³Ðž  
+<p></p>
+ÐÐ»Ñ ÐŒÐœÐŸÐ³ÐžÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ, ÐµÑÐ»Ðž ÐÑ ÑÐ°Ð·ÐŒÐµÑÐ°ÐµÑÐµ ÐŒÑÑÑ ÐœÐ° ÐœÐžÑ
+,Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ 
+"Ð¿ÐŸÐŽÑÐºÐ°Ð·ÐºÐ°",ÐºÐŸÑÐŸÑÐ°Ñ ÐŸÐ±ÑÑÑÐœÑÐµÑ ÐŽÐµÐ¹ÑÑÐ²ÐžÑ,ÐºÐŸÑÐŸÑÑÐµ ÐŸÐœÐž Ð²ÑÐ¿ÐŸÐ»ÐœÑÑÑ  
+<p></p>
+ ÐÐµÑÐµÐŽ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐŒ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐŸÐŒ, ÑÐœÐ°ÑÐ°Ð»Ð° Ð¿ÑÐŸÑÑÐžÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÑÐžÑ Greenstone/
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/importingpreviouslyassignedmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/importingpreviouslyassignedmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/importingpreviouslyassignedmetadata.htm	(revision 10506)
@@ -0,0 +1,80 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="importingpreviouslyassignedmetadata"><font size="5" face="Verdana"><strong>5.8: ÐÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÑÐ°ÑÑÐºÐ°Ð·Ð°ÐœÐŸ, ÐºÐ°Ðº ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÐµ ÑÐ°ÐœÑÑÐµ. Ð ÐµÑÑ ÐžÐŽÐµÑ ÐŸ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+, ÐºÐŸÑÐŸÑÑÐµ Ð±ÑÐ»Ðž ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÑ Ðº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÑÐ°ÐœÑÑÐµ.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÑÐž ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐž ÑÐ°Ð¹Ð»ÐŸÐ²
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÑÐ»Ðž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð² ÑÐŸÑÐŒÐµ,ÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°Ð²Ð°ÐµÐŒÐŸÐ¹ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐŒ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐŸÐŒ,Ð±ÑÐ»Ðž Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÑ ÑÐ°Ð¹Ð»Ñ - ÐœÐ°Ð¿ÑÐžÐŒÐµÑ,ÐºÐŸÐ³ÐŽÐ° ÐÑ Ð²ÑÐ±ÐžÑÐ°ÐµÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ ÐžÐ· ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Greenstone - ÐŸÐœÐž ÐžÐŒÐ¿ÐŸÑÑÐžÑÑÑÑÑÑ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž,ÐºÐŸÐ³ÐŽÐ° ÐÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÐµ ÑÐ°Ð¹Ð».Ð§ÑÐŸÐ±Ñ ÑÐŽÐµÐ»Ð°ÑÑ ÑÑÐŸ, ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÑ Ð² ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°Ñ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÐŽÐŸÑÑÑÐ¿ÐœÑÑ
+ Ð² ÑÑÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+<p></p>
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð·Ð°Ð¿ÑÐ°ÑÐžÐ²Ð°ÐµÑ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ.ÐÐ°Ð¿ÑÐŸÑ ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÐºÑÐ°ÑÐºÐžÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž Ðž Ð·Ð°ÑÐµÐŒ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐžÐŒÑ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÐºÐŸÑÐŸÑÑÐµ ÐžÐŒÐ¿ÐŸÑÑÐžÑÑÑÑÑÑ,ÐºÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐŸÐœ Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² ÐžÑÑ
+ÐŸÐŽÐœÐŸÐŒ ÑÐ°Ð¹Ð»Ðµ.Ð­ÑÐŸ Ð¿ÐŸÐ»Ðµ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐŸ ÐžÐ»Ðž ÐžÐ·ÐŒÐµÐœÐµÐœÐŸ.ÐÐ°ÑÐµÐŒ ÐÑ Ð²ÑÐ±ÐžÑÐ°ÐµÑÐµ,ÐºÐ°ÐºÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐœÐŸÐ²ÐŸÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÑ,Ð° Ð·Ð°ÑÐµÐŒ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐžÐ¹ ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð² ÑÑÐžÑ
+ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°Ñ
+.Ð¡ÐžÑÑÐµÐŒÐ° Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž Ð²ÑÐ±ÐžÑÐ°ÐµÑ ÑÐ°ÐŒÐŸÐµ Ð±Ð»ÐžÐ·ÐºÐŸÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÐµ Ð² ÑÐµÑÐŒÐžÐœÐ°Ñ
+ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž Ðž ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐŽÐ»Ñ ÐœÐŸÐ²ÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. 
+<p></p>
+ ÐÑÐŸÐ²ÐµÑÐžÐ² ÑÑÐž ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐžÑ,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ",ÑÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÐ¹ ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ðº Ð²ÑÐ±ÑÐ°ÐœÐœÑÐŒ ÐœÐ°Ð±ÐŸÑÐ°ÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.Ð­ÑÐŸ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÑÐŸÐ»ÑÐºÐŸ ÑÐŸÐ³ÐŽÐ°,ÐºÐŸÐ³ÐŽÐ° ÐŸÑÑÑÑÑÑÐ²ÑÐµÑ ÑÐ»ÐµÐŒÐµÐœÑ Ñ ÑÐµÐŒ Ð¶Ðµ ÑÐ°ÐŒÑÐŒ ÐžÐŒÐµÐœÐµÐŒ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ Ð²ÑÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÑÑÐ°ÐœÐŸÐ²ÐŸÐº; "ÐÐ°ÐŒÐµÐœÐžÑÑ" ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐ°ÐµÑ Ð¿ÑÐžÑÐŸÐµÐŽÐžÐœÐµÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐ° Ðº ÑÐ¶Ðµ ÑÐ°ÐœÐµÐµ Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐŒÑ  Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÐµÐŒ;ÐœÐ°ÐºÐŸÐœÐµÑ, "ÐÐµ ÑÑÐžÑÑÐ²Ð°ÑÑ", ÑÑÐŸÐ±Ñ ÐœÐµ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐœÐžÐºÐ°ÐºÐžÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ñ ÑÑÐžÐŒ ÐžÐŒÐµÐœÐµÐŒ ÑÐ»ÐµÐŒÐµÐœÑÐ°. ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÐ»Ðž,ÐºÐ°Ðº ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐœÐµÐºÐŸÑÐŸÑÑÑ ÑÐ°ÑÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, Ð·Ð°Ð¿ÐžÑÐ°ÐœÐœÐ°Ñ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÑÐŸÑ
+ÑÐ°ÐœÑÐµÑÑÑ ÐœÐ° Ð²ÑÐµÐŒÑ ÑÑÑÐµÑÑÐ²ÐŸÐ²Ð°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+<p></p>
+ ÐÐ»Ñ ÐŽÐµÑÐ°Ð»ÐµÐ¹ ÐŸÑÐœÐŸÑÐžÑÐµÐ»ÑÐœÐŸ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð² metadata.xml, ÐºÐŸÑÐŸÑÑÐ¹ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ Ð² Greenstone ÐŽÐ»Ñ Ñ
+ÑÐ°ÐœÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÑÐŒ.Ð³Ð»Ð°Ð²Ñ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.
+ </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/introduction.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/introduction.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/introduction.htm	(revision 10506)
@@ -0,0 +1,21 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="introduction"><font size="5" face="Verdana"><strong>1: ÐÐ²ÐµÐŽÐµÐœÐžÐµ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Greenstone - ÑÑÐŸ ÐžÐœÑÑÑÑÐŒÐµÐœÑ ÐŽÐ»Ñ ÑÐ±ÐŸÑÐ° Ðž ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐž
+ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Ñ Ð¿ÐŸÑÐ»ÐµÐŽÑÑÑÐžÐŒ ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµÐŒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÑÐžÑÑÐŸÐ²ÑÑ
+ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐº.ÐÐœ
+ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°ÐµÑ ÐŽÐŸÑÑÑÐ¿ Ðº ÑÑÐœÐºÑÐžÐŸÐœÐ°Ð»ÑÐœÑÐŒ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑÐŒ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐ³ÐŸ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ
+Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž Greenstone Ð³ÑÐ°ÑÐžÑÐµÑÐºÐžÐŒ Ð¿ÑÑÐµÐŒ Ðž ÑÐ°Ð±ÐŸÑÐŸÐ¹ ÐŒÑÑÑÑ.
+    
+
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/metadatasets.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/metadatasets.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/metadatasets.htm	(revision 10506)
@@ -0,0 +1,89 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="metadatasets"><font size="5" face="Verdana"><strong>6.11: Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» ÐŸÐ±ÑÑÑÐœÑÐµÑ ÐŸÐ±Ð·ÐŸÑÐœÑÑ Ð¿Ð°ÐœÐµÐ»Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. Ð "Ð Ð°Ð·ÐŽÐµÐ»Ðµ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐŸÑÑÑÐ¿ÐœÑÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÐœÐ°Ð±ÐŸÑÐ° ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ð ÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐœÐ°Ð±ÐŸÑÐ° ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐœÐ°Ð±ÐŸÑÐ° ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð­ÑÐŸ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ,ÑÑÐŸÐ±Ñ ÑÐ°ÑÑÐŒÐŸÑÑÐµÑÑ ÐœÐ°Ð±ÐŸÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÐºÐŸÑÐŸÑÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹,Ðž ÑÐ»ÐµÐŒÐµÐœÑÑ,ÐºÐŸÑÐŸÑÑÐµ ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐœÐ°Ð±ÐŸÑÐ°. ÐÑÐ±ÐµÑÐžÑÐµ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° "ÐÐŸÑÑÑÐ¿ÐœÑÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+",ÑÑÐŸÐ±Ñ Ð²ÐžÐŽÐµÑÑ ÐŽÐµÑÐ°Ð»Ðž ÐžÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ².
+<p></p>
+Ð§ÑÐŸÐ±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐŽÑÑÐ³ÐŸÐ¹ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐÐ°Ð±ÐŸÑ ÐÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+" Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÐ°Ð¹Ð» Ñ ÐœÐ°Ð±ÐŸÑÐŸÐŒ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ (.mds).
+<p></p>
+Ð ÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐœÐ°Ð±ÐŸÑÐ° ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐŸ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ Greenstone Editor for Metadata Sets (GEMS). ÐÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÑ "Ð ÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐÐ°Ð±ÐŸÑ ÐÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+", ÑÑÐŸÐ±Ñ Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ GEMS.
+<p></p>
+ÐÑÐ»Ðž ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ Ð²Ð°ÐŒ Ð±ÐŸÐ»ÑÑÐµ ÐœÐµ ÐœÑÐ¶ÐµÐœ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ Ðž ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° "Ð£ÐŽÐ°Ð»ÐžÑÑ ÐÐ°Ð±ÐŸÑ ÐÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+". ÐÑÐ»Ðž Ð²Ñ ÐœÐ°Ð·ÐœÐ°ÑÐžÐ»Ðž ÐºÐ°ÐºÐžÐµ-Ð»ÐžÐ±ÐŸ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ Ðº ÑÐ»ÐµÐŒÐµÐœÑÐ°ÐŒ Ð² ÑÐŽÐ°Ð»ÐµÐœÐœÐŸÐŒ ÐœÐ°Ð±ÐŸÑÐµ, Ñ Ð²Ð°Ñ ÑÐ¿ÑÐŸÑÑÑ ÐºÐ°Ðº Ñ ÐœÐžÐŒÐž Ð¿ÐŸÑÑÑÐ¿ÐžÑÑ Ð¿ÑÐž ÑÐ»ÐµÐŽÑÑÐµÐ¹ Ð·Ð°Ð³ÑÑÐ·ÐºÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/miscellaneous.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/miscellaneous.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/miscellaneous.htm	(revision 10506)
@@ -0,0 +1,18 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="miscellaneous"><font size="5" face="Verdana"><strong>8: Ð Ð°Ð·ÐœÐŸÐµ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+ Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑ ÐŸÑÐŸÐ±ÐµÐœÐœÐŸÑÑÐž ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°,ÐºÐŸÑÐŸÑÑÐµ ÐœÐµ ÑÐ²ÑÐ·Ð°ÐœÑ ÐœÐž Ñ ÐºÐ°ÐºÐžÐŒ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐžÐŒ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµÐŒ.
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/ofmiceandmenus.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/ofmiceandmenus.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/ofmiceandmenus.htm	(revision 10506)
@@ -0,0 +1,101 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="ofmiceandmenus"><font size="5" face="Verdana"><strong>1.1: ÐÑÑÑ Ðž ÐÐµÐœÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» ÐŽÐ°ÐµÑ Ð±Ð°Ð·ÐŸÐ²ÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ Ð²Ð·Ð°ÐžÐŒÐŸÐŽÐµÐ¹ÑÑÐ²ÐžÐž Ñ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐŸÐŒ  Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž. 
+ÐÑÐ»Ðž ÐÑ Ð·ÐœÐ°ÐºÐŸÐŒÑ Ñ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°ÐŒÐž ÑÐžÐ¿Ð° Internet Explorer ÐžÐ»Ðž Microsoft office, Ð»ÐµÐ³ÐºÐŸ ÐŸÐ±ÑÐ°ÑÐ°ÐµÑÐµÑÑ Ñ ÐŒÑÑÑÑ Ðž ÐŒÐµÐœÑ, Ð¿ÑÐŸÐ¿ÑÑÑÐžÑÐµ <a href="howtoavoidthisdocument.htm#howtoavoidthisdocument">Ðž Ð¿ÐµÑÐµÐ¹ÐŽÐžÑÐµ Ðº ÑÐ»ÐµÐŽÑÑÑÐµÐŒÑ ÑÐ°Ð·ÐŽÐµÐ»Ñ </a>.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    ÐÑÐœÐŸÐ²ÐœÑÐµ Ð¿ÐŸÐœÑÑÐžÑ ÐºÐŸÐœÑÐµÐ¿ÑÐžÐž
+            <tr>
+<td colspan="2"> </td><td colspan="1">
+               ÐÐµÐ¹ÑÑÐ²ÐžÑ ÐŒÑÑÐž
+	    </td>
+</tr>
+            
+<tr>
+<td colspan="2"> </td><td colspan="1">
+               ÐÐ»Ð°Ð²ÐžÐ°ÑÑÑÐ°
+	    </td>
+</tr>
+          
+</td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    ÐÐµÑÐµÑ
+ÐŸÐŽ Ðº Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐµ
+          </td>
+</tr>
+	
+	
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    ÐÑÑÑÑÑÐµ ÐºÐ»ÑÑÐž
+          </td>
+</tr>
+	
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ ÑÐŸÐ³Ð»Ð°ÑÐµÐœÐžÑÐŒ Windows Microsoft Ðž ÑÑÐµÐ±ÑÐµÑ ÐŸÐ±ÑÑÐœÐŸÐ³ÐŸ Ð·ÐœÐ°ÐœÐžÑ Windows.   
+ <p></p>
+ ÐÑÐ±Ð°Ñ ÑÐ°ÑÑÑ ÑÐºÑÐ°ÐœÐ°, Ñ ÐºÐŸÑÐŸÑÐŸÐ¹ ÐÑ Ð²Ð·Ð°ÐžÐŒÐŸÐŽÐµÐ¹ÑÑÐ²ÑÐµÑÐµ, ÑÐžÐ¿Ð° ÐºÐœÐŸÐ¿ÐºÐž ÐžÐ»Ðž ÐŸÐ±Ð»Ð°ÑÑÐž ÑÐµÐºÑÑÐ°,ÐœÐ°Ð·ÑÐ²Ð°ÐµÑÑÑ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµÐŒ. Ð Ð»ÑÐ±ÐŸÐµ Ð·Ð°ÐŽÐ°ÐœÐœÐŸÐµ Ð²ÑÐµÐŒÑ ÐŸÐŽÐžÐœ ÑÐ»ÐµÐŒÐµÐœÑ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ, ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÑÐ¹ "ÑÐŸÐºÑÑ",Ð²ÑÐŽÐµÐ»ÑÐµÑÑÑ Ð¿ÐŸÐŽÑÐ²ÐµÑÐºÐŸÐ¹ Ðž ÐŸÑÐºÐ»ÐžÐºÐ°ÐµÑÑÑ ÐœÐ° ÐŽÐµÐ¹ÑÑÐ²ÐžÐµ ÐºÐ»Ð°Ð²ÐžÐ°ÑÑÑÑ. ÐÐµÑÐºÐŸÐ»ÑÐºÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÑÑ ÐÐ°ÐŒ Ð²ÑÐ±ÐžÑÐ°ÑÑ ÑÑÐ°ÑÑÐºÐž, ÐºÐŸÑÐŸÑÑÐµ Ð²ÑÐŽÐµÐ»ÑÑÑÑÑ ÑÐµÐŒÐœÐŸÑÐžÐœÐžÐŒ ÑÐ²ÐµÑÐŸÐŒ. ÐÐµÐºÐŸÑÐŸÑÑÐµ ÑÐ»ÐµÐŒÐµÐœÑÑ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐŸÑÐŸÐ±ÑÐ°Ð¶Ð°ÑÑÑÑ Ñ Ð¿ÐŸÐœÐžÐ¶ÐµÐœÐœÐŸÐ¹ ÑÑÐºÐŸÑÑÑÑ, Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°Ñ ÑÐµÐŒ ÑÐ°ÐŒÑÐŒ, ÑÑÐŸ ÐŸÐœÐž Ð·Ð°Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÐœÑ.
+<p></p>
+ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐµÑÐµÐŒÐµÑÐ°ÑÑÑÑ Ðž ÐŽÐµÐ¹ÑÑÐ²ÐŸÐ²Ð°ÑÑ  Ð»ÐµÐ²ÐŸÐ¹ ÐžÐ»Ðž Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐ°ÐŒÐž ÐŒÑÑÐž ÐŸÐ±ÑÑÐœÑÐŒ ÑÐ¿ÐŸÑÐŸÐ±ÐŸÐŒ. ÐÐœÐŸÐ³ÐžÐµ ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑÑ ÑÐ°ÐºÐ¶Ðµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÑÑ ÐÐ°ÐŒ "ÑÑÐœÑÑÑ" ÐžÑ
+, ÐœÐ°Ð¶ÐžÐŒÐ°Ñ Ðž ÑÐŽÐµÑÐ¶ÐžÐ²Ð°Ñ Ð»ÐµÐ²ÑÑ ÐºÐœÐŸÐ¿ÐºÑ ÐŒÑÑÐž, Ð¿ÐµÑÐµÐŒÐµÑÐ°ÑÑ ÐžÑ
+ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐŒÑÑÐž Ðž ÐŸÑÑÐ°Ð²ÐžÑÑ ÐžÑ
+ Ð² ÐŽÑÑÐ³ÐŸÐŒ ÐŒÐµÑÑÐµ, ÐŸÑÐ¿ÑÑÐºÐ°Ñ ÐºÐœÐŸÐ¿ÐºÑ. ÐÐŸÑÐµÐœÑÐžÐ°Ð»ÑÐœÑÐµ ÐŸÐ±ÑÐµÐºÑÑ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐžÐ·ÐŒÐµÐœÑÑÑ ÑÐ²ÐŸÐ¹ Ð²ÐžÐŽ, ÐºÐŸÐ³ÐŽÐ° ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑ ÑÐºÐŸÐ»ÑÐ·ÐžÑ Ð¿ÐŸ ÐœÐžÐŒ.  
+<p></p>
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐºÐ»Ð°Ð²ÐžÐ°ÑÑÑÑ ÐŽÐ»Ñ Ð·Ð°Ð¿ÐžÑÐž Ð² ÐŸÐ±Ð»Ð°ÑÑÐž ÑÐµÐºÑÑÐ°. ÐÐ»ÑÑÐµÑÐœÐ°ÑÐžÐ²Ñ ÐºÐ»Ð°Ð²ÐžÐ°ÑÑÑÐµ ÐŽÐŸÑÑÑÐ¿ÐœÑ ÐŽÐ»Ñ ÐŒÐœÐŸÐ³ÐžÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ, ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐœÑÑ
+ ÐºÐ»ÑÑÐµÐ²ÑÐŒ ÐžÐŒÐµÐœÐµÐŒ Ð² ÐºÐ²Ð°ÐŽÑÐ°ÑÐœÑÑ
+ ÑÐºÐŸÐ±ÐºÐ°Ñ
+. Ð Ð¿ÑÐžÐŒÐµÑÑ, [Tab] ÐžÐ·ÐŒÐµÐœÑÐµÑ ÑÐŸÐºÑÑ. ÐÐœÐ°Ðº Ð¿Ð»ÑÑ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ, ÑÑÐŸ ÐŽÑÑÐ³ÐžÐµ ÐºÐ»Ð°Ð²ÐžÑÐž ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐœÐ°Ð¶Ð°ÑÑ ÐŸÐŽÐœÐŸÐ²ÑÐµÐŒÐµÐœÐœÐŸ. 
+<p></p>
+ÐÑÐ¹ÐŽÐžÑÐµ ÐžÐ· Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°, Ð²ÑÐ±ÐžÑÐ°Ñ Ð¿ÑÐœÐºÑ "ÐÑÑ
+ÐŸÐŽ" Ð² ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»Ð°". ÐÐ°ÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±ÑÐŽÐµÑ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ  ÑÐŸÑ
+ÑÐ°ÐœÐµÐœÐ°.
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+Ð§ÑÐŸÐ±Ñ Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÑÑÑÐ¿ Ðº ÐŒÐµÐœÑ, ÑÐŽÐµÑÐ¶ÐžÐ²Ð°Ð¹ÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ [ALT] Ðž ÐœÐ°Ð¶ÐŒÐžÑÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÑÑ Ð±ÑÐºÐ²Ñ (Ð¿ÐŸÐŽÑÐµÑÐºÐœÑÑÑÑ).ÐÐ°Ð¿ÑÐžÐŒÐµÑ,ÐŽÐ»Ñ Ð²ÑÐ±ÐŸÑÐ° ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»" ÐœÐ°Ð¶ÐŒÐžÑÐµ [ALT] + [F]. ÐÐ»Ñ Ð²ÑÐ±ÐŸÑÐ° ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÐŸÐ³ÐŸ Ð¿ÑÐœÐºÑÐ°, ÐœÐ°Ð¶ÐŒÐžÑÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÑÑ ÐºÐ»Ð°Ð²ÐžÑÑ. ÐÐ°Ð¿ÑÐžÐŒÐµÑ, ÐµÑÐ»Ðž ÐÑ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÐµÑÑ Ð² ÐŒÐµÐœÑ Ð€Ð°Ð¹Ð» ÐœÐ°Ð¶ÐŒÐžÑÐµ [S], ÑÑÐŸÐ±Ñ "Ð¡ÐŸÑ
+ÑÐ°ÐœÐžÑÑ"ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+</body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/openingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/openingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/openingacollection.htm	(revision 10506)
@@ -0,0 +1,80 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="openingacollection"><font size="5" face="Verdana"><strong>2.3: ÐÑÐºÑÑÑÐžÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÑÐŸÐŸÐ±ÑÐ°ÐµÑÑÑ,ÐºÐ°Ðº ÐŸÑÐºÑÑÑÑ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Open Collection prompt.
+     
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ°Ðº ÐŸÑÐºÑÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ°ÐºÑÑÑÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	     ÐÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐœÐ°ÑÐ»ÐµÐŽÑÑÐ²Ð°
+	  </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ÐÐ»Ñ ÑÐŸÐ³ÐŸ ÑÑÐŸÐ±Ñ ÐŸÑÐºÑÑÑÑ ÑÑÑÐµÑÑÐ²ÑÑÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ "ÐÑÐºÑÑÑÑ" Ð² ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»",ÑÑÐŸÐ±Ñ Ð±ÑÑÑÑÐŸ Ð¿ÐµÑÐµÐ¹ÑÐž Ðº ÐÑÐºÑÑÑÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐŸÑÐ²Ð»ÑÐµÑÑÑ ÑÐ¿ÐžÑÐŸÐº ÐÐ°ÑÐžÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Ð² Greenstone. ÐÑÐ±ÐµÑÐžÑÐµ ÐŸÐŽÐœÑ,ÑÑÐŸÐ±Ñ ÑÐ²ÐžÐŽÐµÑÑ ÐµÐµ ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ,Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ   "OÑÐºÑÑÑÑ", ÑÑÐŸÐ±Ñ Ð·Ð°Ð³ÑÑÐ·ÐžÑÑ ÐµÐµ. ÐÑÐ»Ðž ÐÑ ÐžÑÐžÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐºÐŸÑÐŸÑÐ°Ñ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ Ð²ÐœÐµ Ð¿Ð°Ð¿ÐºÐž "Ð¡ollect Greenstone",ÑÐŸ ÑÐµÐ»ÐºÐœÐžÑÐµ "Browse" ÐŽÐ»Ñ Ð²ÑÐ·ÐŸÐ²Ð° ÐŽÐžÐ°Ð»ÐŸÐ³ÐŸÐ²ÐŸÐ¹ ÑÐžÑÑÐµÐŒÑ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÑÐ°Ð¹Ð»ÐŸÐ².
+ <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð ÑÐ»ÑÑÐ°Ðµ, ÐµÑÐ»Ðž Ð±ÐŸÐ»ÑÑÐµ ÑÐµÐŒ ÐŸÐŽÐœÐ° Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ° ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° Greenstone Ð²Ð²ÐŸÐŽÐžÑÑÑ ÐŸÐŽÐœÐŸÐ²ÑÐµÐŒÐµÐœÐœÐŸ, ÑÐµÐ»ÐµÐ²Ð°ÐœÑÐœÑÐµ ÐŽÐžÑÐµÐºÑÑÐžÐž "Ð·Ð°ÐºÑÑÑÑ",ÑÑÐŸÐ±Ñ Ð¿ÑÐµÐŽÐŸÑÐ²ÑÐ°ÑÐžÑÑ ÐœÐ°Ð»ÐŸÐ¶ÐµÐœÐžÐµ.ÐÑÐž ÐŸÑÐºÑÑÑÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐœÐµÐ±ÐŸÐ»ÑÑÐŸÐ¹ Ð²ÑÐµÐŒÐµÐœÐœÑÐ¹ Ð±Ð»ÐŸÐºÐžÑÑÑÑÐžÐ¹ ÑÐ°Ð¹Ð» ÑÐŸÐ·ÐŽÐ°ÐµÑÑÑ Ð² ÐµÑ Ð¿Ð°Ð¿ÐºÐµ.ÐÐµÑÐµÐŽ ÐŸÑÐºÑÑÑÐžÐµÐŒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑ Ð¿ÑÐŸÐ²ÐµÑÐºÑ,ÑÑÐŸÐ±Ñ ÑÐ±ÐµÐŽÐžÑÑÑÑ,ÑÑÐŸ ÐœÐžÐºÐ°ÐºÐžÑ
+ Ð±Ð»ÐŸÐºÐžÑÑÑÑÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÐœÐµ ÑÑÑÐµÑÑÐ²ÑÐµÑ. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐºÐ°Ð·Ð°ÑÑ,Ð·Ð°ÐºÑÑÑÐ° Ð»Ðž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, Ð¿ÐŸ ÑÐ²ÐµÑÑ ÐµÑ ÐžÐºÐŸÐœÐºÐž:Ð·ÐµÐ»ÑÐœÑÐ¹ - ÐŽÐ»Ñ ÐœÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,ÐºÑÐ°ÑÐœÑÐ¹ - ÐŽÐ»Ñ Ð·Ð°ÐºÑÑÑÐŸÐ¹. ÐÐŽÐœÐ°ÐºÐŸ,ÐºÐŸÐ³ÐŽÐ° ÐžÐ· ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° Ð²ÑÑ
+ÐŸÐŽÑÑ Ð¿ÑÐµÐ¶ÐŽÐµÐ²ÑÐµÐŒÐµÐœÐœÐŸ, Ð±Ð»ÐŸÐºÐžÑÑÑÑÐžÐ¹ ÑÐ°Ð¹Ð» ÐžÐœÐŸÐ³ÐŽÐ° ÐŸÑÑÐ°ÐµÑÑÑ ÐœÐ° ÐŒÐµÑÑÐµ. ÐÐŸÐ³ÐŽÐ° ÐÑ ÐŸÑÐºÑÑÐ²Ð°ÐµÑÐµ ÑÐ°ÐºÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ° Ð·Ð°Ð¿ÑÐ°ÑÐžÐ²Ð°ÐµÑ,Ñ
+ÐŸÑÐžÑÐµ Ð»Ðž ÐÑ "ÑÐºÑÐ°ÑÑÑ" ÐµÐ³ÐŸ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ. ÐÐžÐºÐŸÐ³ÐŽÐ° ÐœÐµ ÐŽÐµÐ»Ð°Ð¹ÑÐµ ÑÑÐŸÐ³ÐŸ,ÐµÑÐ»Ðž ÐºÑÐŸ-ÑÐŸ ÐµÑÐµ Ð² ÑÐŸ Ð¶Ðµ ÑÐ°ÐŒÐŸÐµ Ð²ÑÐµÐŒÑ ÑÐ°Ð±ÐŸÑÐ°ÐµÑ.   
+<p></p>
+ÐÐŸÐ³ÐŽÐ° ÐÑ ÐŸÑÐºÑÑÐ²Ð°ÐµÑÐµ ÐºÐŸÐ»ÐµÐºÑÐžÑ, ÐºÐŸÑÐŸÑÐ°Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐ° ÐœÐµ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°  Greenstone, ÐÐ°Ñ Ð¿ÐŸÐ¿ÑÐŸÑÑÑ Ð²ÑÐ±ÑÐ°ÑÑ ÐœÐ°Ð±ÐŸÑ (ÐžÐ»Ðž ÐœÐ°Ð±ÐŸÑÑ) ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÑÐ»Ðž ÐœÐž ÐŸÐŽÐžÐœ ÐœÐµ ÐŸÑÐŸÐ±ÑÐ°Ðœ, Ð»ÑÐ±ÑÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð±ÑÐŽÑÑ ÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÑÑÑÑ. ÐÐœÐ°ÑÐµ, ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð±ÑÐŽÑÑ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÑ ÑÐ°Ðº Ð¶Ðµ, ÐºÐ°Ðº Ðž ÐºÐŸÐ³ÐŽÐ° ÐÑ Ð¿ÐµÑÐµÑÑÐ³ÐžÐ²Ð°ÐµÑÐµ Ð² ÑÐ°Ð¹Ð»Ñ Ñ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐŒÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž. ÐÑÐŸÑÐµÑÑ ÐŸÐ¿ÐžÑÐ°Ðœ Ð² <a href="importingpreviouslyassignedmetadata.htm#importingpreviouslyassignedmetadata">ÐÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐž Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð²ÑÐ±ÑÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</a>. 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/partitionindexes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/partitionindexes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/partitionindexes.htm	(revision 10506)
@@ -0,0 +1,25 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="partitionindexes"><font size="5" face="Verdana"><strong>6.6: ÐÐœÐŽÐµÐºÑÑ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ ÐÐœÐŽÐµÐºÑÑ Ð¿ÐŸÑÑÑÐŸÐµÐœÑ ÐœÐ° ÐŽÐµÑÐ°Ð»ÑÐœÐŸÐŒ ÑÐµÐºÑÑÐµ ÐžÐ»Ðž ÐžÑÑÐŸÑÐœÐžÐºÐ°Ñ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐµÑÑÐŸ Ð¿ÐŸÐžÑÐºÐ° ÐŒÐŸÐ¶ÐµÑ Ð² ÐŽÐ°Ð»ÑÐœÐµÐ¹ÑÐµÐŒ ÑÐ¿ÑÐ°Ð²Ð»ÑÑÑÑÑ Ð¿ÑÑÑÐŒ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ ÐžÐœÐŽÐµÐºÑÐŸÐ² Ð»ÐžÐ±ÐŸ Ð¿ÐŸ ÑÐ·ÑÐºÑ ÐžÐ»Ðž Ð¿ÐŸ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÐŒ ÑÐžÐ»ÑÑÑÐ°ÐŒ.Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ,ÐºÐ°Ðº ÑÑÐŸ ÑÐŽÐµÐ»Ð°ÑÑ. ÐÐœÑÑÑÐž "Ð Ð°Ð·ÐŽÐµÐ»ÐŸÐ² ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐœÐŽÐµÐºÑÑ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ".
+<p></p>
+ÐÐžÐŽ "ÐÐœÐŽÐµÐºÑÑ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ" ÐžÐŒÐµÐµÑ ÑÑÐž Ð·ÐœÐ°ÑÐµÐœÐžÑ:"ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐžÐ»ÑÑÑÑ","ÐÐ°Ð·ÐœÐ°ÑÐžÑÑ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÐµ" Ðž "ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐ·ÑÐºÐž". ÐÐ»Ñ ÑÐŸÐ³ÐŸ ÑÑÐŸÐ±Ñ Ð±ÐŸÐ»ÑÑÐµ ÑÐ·ÐœÐ°ÑÑ ÐŸ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÐž, ÑÐžÑÐ°Ð¹ÑÐµ  ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+ Ðž Ð¿ÐŸÐŽÐžÐœÐŽÐµÐºÑÐ°Ñ
+ Ð² Ð³Ð»Ð°Ð²Ðµ 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.
+
+      
+      
+      
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/plugins.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/plugins.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/plugins.htm	(revision 10506)
@@ -0,0 +1,101 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="plugins"><font size="5" face="Verdana"><strong>6.3: ÐÐ»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÐ°ÐœÐŸ,ÐºÐ°Ðº ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÑÑ Ð¿Ð»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÐŽÐ»Ñ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹.Ð ÐœÑÐŒ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ,ÐºÐ°ÐºÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ, ÐºÐ°ÐºÐžÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ Ð¿ÐµÑÐµÐŽÐ°Ð²Ð°ÑÑ Ðº ÐœÐžÐŒ Ðž Ð² ÐºÐ°ÐºÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ ÐŸÐœÐž Ð²Ñ
+ÐŸÐŽÑÑ. Ð©ÐµÐ»ÐºÐœÐžÑÐµ
+ "ÐÐ»Ð°Ð³ÐžÐœÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²" Ð² Ð¿ÑÐœÐºÑÐµ "Ð Ð°Ð·ÐŽÐµÐ»Ñ Ð¿ÑÐŸÐµÐºÑÐ°".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð€ÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ·ÐŒÐµÐœÐµÐœÐžÐµ Ð¿ÐŸÑÑÐŽÐºÐ° Ð¿Ð»Ð°Ð³ÐžÐœÐ°
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ°ÑÑÑÐŸÐ¹ÐºÐ° ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž</a>
+<p style="text-align:justify"></p>
+Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÑÑ Ð¿Ð»Ð°Ð³ÐžÐœ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ "ÐÑÐ±ÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœÐ° ÐŽÐ»Ñ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÑ" Ð² ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐŒ ÑÐ¿ÐžÑÐºÐµ ÐŸÐºÐŸÐ»ÐŸ ÐŸÑÐœÐŸÐ²Ð°ÐœÐžÑ,Ðž Ð·Ð°ÑÐµÐŒ ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð¿Ð»Ð°Ð³ÐžÐœ". ÐÐŸÑÐ²Ð»ÑÐµÑÑÑ ÐŸÐºÐœÐŸ Ñ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµÐŒ "ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ²";ÐŸÐœÐŸ ÐŸÐ¿ÐžÑÐ°ÐœÐŸ ÐœÐžÐ¶Ðµ. ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐÑ ÑÑÐŸÑÐŒÐžÑÐŸÐ²Ð°Ð»Ðž ÐœÐŸÐ²ÑÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ, ÐŸÐœ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÑÑ Ð² ÐºÐŸÐœÐµÑ ÑÐ¿ÐžÑÐºÐ° "Ð£ÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐœÑÐµ ÑÐµÐºÑÑÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÑ". ÐÐ°ÐŒÐµÑÑÑÐµ, ÑÑÐŸ, ÐºÑÐŸÐŒÐµ UnknownPlug, ÐºÐ°Ð¶ÐŽÑÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ Ð²ÑÐ²ÐµÐŽÐµÐœ ÑÐŸÐ»ÑÐºÐŸ ÐŸÐŽÐžÐœ ÑÐ°Ð· Ð² ÑÐ¿ÐžÑÐºÐµ.
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ Ð¿Ð»Ð°Ð³ÐžÐœ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ Ð² ÑÐ¿ÐžÑÐºÐµ Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ Ð¿Ð»Ð°Ð³ÐžÐœ".
+<p></p>
+ ÐÐ»Ð°Ð³ÐžÐœÑ ÑÐŸÑÐŒÐžÑÑÑÑÑÑ Ð¿ÑÑÐµÐŒ Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ². Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐžÑ
+, Ð²ÑÐ±ÐµÑÐžÑÐµ Ð¿Ð»Ð°Ð³ÐžÐœ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð€ÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ²"(ÐžÐ»Ðž ÐŽÐ²ÐŸÐ¹ÐœÑÐŒ ÑÐµÐ»ÑÐºÐŸÐŒ ÐœÐ° Ð¿Ð»Ð°Ð³ÐžÐœÐµ). ÐÐžÐ°Ð»ÐŸÐ³ "ÐÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÑÐµ ÐÑÐ³ÑÐŒÐµÐœÑÑ" Ð²ÐŸÐ·ÐœÐžÐºÐ°ÐµÑ Ñ ÑÐ°Ð·Ð»ÐžÑÐœÑÐŒÐž ÐŸÐ¿ÑÐžÑÐŒÐž ÐŽÐ»Ñ ÑÐºÐ°Ð·Ð°ÐœÐžÑ Ð°ÑÐ³ÑÐŒÐµÐœÑÐŸÐ².
+<p></p>
+ Ð¡ÑÑÐµÑÑÐ²ÑÑÑ ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ Ð²ÐžÐŽÑ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ. ÐÐµÐºÐŸÑÐŸÑÑÐµ ÑÐ²Ð»ÑÑÑÑÑ ÐœÐµÐ·Ð°Ð²ÐžÑÐžÐŒÑÐŒÐž ÐºÐœÐŸÐ¿ÐºÐ°ÐŒÐž Ðž ÑÐµÐ»ÑÐŸÐº ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÑÑ ÐŸÐ¿ÑÐžÑ Ðº Ð¿Ð»Ð°Ð³ÐžÐœÑ. ÐÑÑÐ³ÐžÐµ Ð²ÑÑÑÑÐ¿Ð°ÑÑ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÑÑÑÐŸÐºÐž ÑÐµÐºÑÑÐ° Ñ ÐœÐµÐ·Ð°Ð²ÐžÑÐžÐŒÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐŸÐ¹ Ðž ÐŸÐ±Ð»Ð°ÑÑÑÑ ÑÐµÐºÑÑÐ°. Ð©ÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° Ð¿ÐŸÐ»Ðµ,ÑÑÐŸÐ±Ñ Ð²ÑÐ·Ð²Ð°ÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑ,Ð·Ð°ÑÐµÐŒ ÐœÐ°Ð¿ÐµÑÐ°ÑÐ°Ð¹ÑÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐžÐ¹ ÑÐµÐºÑÑ (Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ,Ð¿ÑÑÑ ÑÐ°Ð¹Ð»Ð° Ðž Ñ.ÐŽ.) Ð² Ð¿ÐŸÐ»Ðµ. ÐÑÑÐ³ÐžÐµ - ÑÑÐŸ ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐžÐµ ÐŒÐµÐœÑ,Ð² ÐºÐŸÑÐŸÑÑÑ
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÐžÑÐ°ÑÑ ÐœÑÐ¶ÐœÐŸÐµ ÐžÐ· Ð·Ð°ÐŽÐ°ÐœÐœÐŸÐ³ÐŸ ÐœÐ°Ð±ÐŸÑÐ° Ð·ÐœÐ°ÑÐµÐœÐžÐ¹. Ð§ÑÐŸÐ±Ñ Ð¿ÐŸÐœÑÑÑ,ÑÑÐŸ ÐŽÐµÐ»Ð°ÐµÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑ, ÐŽÐ°Ð¹ÑÐµ ÐŒÑÑÐž ÐœÐ° ÐŒÐ³ÐœÐŸÐ²ÐµÐœÐžÐµ Ð¿ÑÐŸÐ¹ÑÐž Ð¿ÐŸ ÐµÐ³ÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ Ðž ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ Ð¿ÐŸÑÐ²ÐžÑÑÑ. 
+<p></p>
+ ÐÐŸÐ³ÐŽÐ° ÐÑ ÐžÐ·ÐŒÐµÐœÐžÐ»Ðž ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑ,ÐœÐ°Ð¶ÐŒÐžÑÐµ "ÐÐ", ÑÑÐŸÐ±Ñ Ð¿ÑÐžÐœÑÑÑ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ Ðž Ð·Ð°ÐºÑÑÑÑ ÐŽÐžÐ°Ð»ÐŸÐ³,ÐžÐ»Ðž "ÐÑÐŒÐµÐœÐžÑÑ",ÑÑÐŸÐ±Ñ Ð·Ð°ÐºÑÑÑÑ ÐŽÐžÐ°Ð»ÐŸÐ³ Ð±ÐµÐ· ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ Ð»ÑÐ±ÑÑ
+ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ² Ð¿Ð»Ð°Ð³ÐžÐœÐ°. 
+ <p></p>
+ ÐÐ»Ð°Ð³ÐžÐœÑ Ð² ÑÐ¿ÐžÑÐºÐµ ÑÐ°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÑ Ð² ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ,ÑÐ°Ðº ÐºÐ°Ðº ÑÐ¿ÐŸÑÑÐŽÐŸÑÐµÐœÐžÐµ ÐžÐœÐŸÐ³ÐŽÐ° Ð²Ð°Ð¶ÐœÐŸ. ÐÐ²Ð° Ð¿Ð»Ð°Ð³ÐžÐœÐ° - ArcPlug Ðž RecPlug - ÑÐ²Ð»ÑÑÑÑÑ Ð¶ÐžÐ·ÐœÐµÐœÐœÐŸ Ð²Ð°Ð¶ÐœÑÐŒÐž ÐŽÐ»Ñ Ð¿ÑÐŸÑÐµÑÑÐ° ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ Ð² ÐºÐŸÐœÑÐµ ÑÐ¿ÐžÑÐ°ÐºÐ° (Ñ ÐŸÑÐŽÐµÐ»ÑÑÑÐµÐ¹ Ð»ÐžÐœÐžÐµÐ¹).Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð¿ÐŸÑÑÐŽÐŸÐº ÐŽÑÑÐ³ÐžÑ
+ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ²,Ð²ÑÐ±ÐµÑÐžÑÐµ Ð¿Ð»Ð°Ð³ÐžÐœ,ÐºÐŸÑÐŸÑÑÐ¹ ÐÑ Ñ
+ÐŸÑÐžÑÐµ Ð¿ÐµÑÐµÐŒÐµÑÑÐžÑÑ,Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²Ð²ÐµÑÑ
+" ÐžÐ»Ðž "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²ÐœÐžÐ·".  
+       <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐŸÑÐµÐœÑ Ñ
+ÐŸÑÐŸÑÐŸ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÑ,ÐºÐ°ÐºÐžÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ Ð¿Ð»Ð°Ð³ÐžÐœÐ° Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑ. ÐÐŽÐœÐ°ÐºÐŸ, ÐµÑÑÑ ÑÐ»ÑÑÐ°Ðž, Ð² ÐºÐŸÑÐŸÑÑÑ
+ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ Ñ
+ÐŸÑÐµÑ ÑÐºÐ°Ð·Ð°ÑÑ ÑÐ¿ÐµÑÐžÐ°Ð»ÑÐœÑÐµ Ð°ÑÐ³ÑÐŒÐµÐœÑÑ. ÐÐ»Ñ ÑÑÐŸÐ³ÐŸ ÐµÑÑÑ Ð²ÐœÐžÐ·Ñ ÑÐµÐºÑÑÐŸÐ²ÐŸÐµ Ð¿ÐŸÐ»Ðµ "ÐÐœÐŽÐžÐ²ÐžÐŽÑÐ°Ð»ÑÐœÑÐµ ÐÑÐ³ÑÐŒÐµÐœÑÑ". ÐÑÐ±ÐŸÐ¹ ÑÐµÐºÑÑ Ð² ÑÑÐŸÐŒ Ð¿ÐŸÐ»Ðµ ÐŽÐŸÑÐ»ÐŸÐ²ÐœÐŸ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÑÑ Ð² ÐºÐŸÐœÐµÑ ÐºÐŸÐŒÐ°ÐœÐŽÑ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ². 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/preferences.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/preferences.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/preferences.htm	(revision 10506)
@@ -0,0 +1,103 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="preferences"><font size="5" face="Verdana"><strong>8.1: ÐÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ ÐŽÐžÐ°Ð»ÐŸÐ³ Ð¿ÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÐ¹,ÐŽÐŸÑÑÑÐ¿ÐœÑÐ¹ Ð¿ÑÐž ÐŸÑÐºÑÑÑÐžÐž "Ð€Ð°Ð¹Ð»Ð°", Ð° Ð·Ð°ÑÐµÐŒ "ÐÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÐ¹".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    ÐÐ±ÑÐµÐµ
+	  </td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Ð¡Ð¿ÐŸÑÐŸÐ±
+	  </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            Ð¢ÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÑÐµÑÐºÐžÐ¹ Ð¿ÑÐŸÑÐµÑÑ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð¡Ð²ÑÐ·Ñ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐµÐœÐžÐµ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ÐÐµÑÐ²Ð°Ñ ÐŸÐ¿ÑÐžÑ "ÐÐ±ÑÐµÐµ" - ÑÑÐŸ ÑÐµÐºÑÑÐŸÐ²ÐŸÐµ Ð¿ÐŸÐ»Ðµ ÐŽÐ»Ñ Ð²Ð²ÐµÐŽÐµÐœÐžÑ Ð°ÐŽÑÐµÑÐ° Ð²Ð°ÑÐµÐ¹ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ. ÐÐœ Ð±ÑÐŽÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°Ðœ Ð² Ð·ÐœÐ°ÑÐµÐœÐžÐž ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ "Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ" Ðž "ÐÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÑÐ¹". Ð¡Ð»ÐµÐŽÑÑÐ°Ñ ÐŸÐ¿ÑÐžÑ - ÑÑÐŸ Ð²ÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐµ ÐŒÐµÐœÑ Ñ ÑÐ·ÑÐºÐ°ÐŒÐž, Ð² ÐºÐŸÑÐŸÑÑÑ
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐÐœÑÐµÑÑÐµÐ¹Ñ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœ. ÐÑÐ»Ðž ÐÑ ÐžÐ·ÐŒÐµÐœÑÐµÑÐµ ÑÐ»ÐŸÐ²Ð°ÑÑ, Ð²ÑÐ±ÐžÑÐ°Ñ ÐºÐ°ÐºÐŸÐ¹-Ð»ÐžÐ±ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ°, ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÐµÑÐµÐ·Ð°Ð³ÑÑÐ·ÐžÑÑ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ, ÑÑÐŸÐ±Ñ Ð·Ð°Ð³ÑÑÐ·ÐžÑÑ ÐœÐŸÐ²ÑÐµ ÑÑÑÐŸÐºÐž ÑÐ·ÑÐºÐ° ÐžÐ· ÑÑÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ.
+<p></p>
+ÐÑÐ»Ðž Ð²ÑÐ±ÑÐ°ÐœÐ° "ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐžÐ·Ð²Ð»ÐµÐºÐ°ÐµÐŒÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+", ÑÐ°Ð·Ð»ÐžÑÐœÐŸÐµ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ, ÑÐ²ÑÐ·Ð°ÐœÐœÐŸÐµ Ñ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž, Ð²ÑÐµÐ³ÐŽÐ° Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð²ÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, ÐºÐŸÑÐŸÑÑÐµ Ð±ÑÐ»Ðž Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž ÐžÐ·Ð²Ð»ÐµÑÐµÐœÑ ÐžÐ· ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ². ÐÑÐŒÐµÐœÐ° ÑÑÐŸÐ³ÐŸ Ð²ÑÐ±ÐŸÑÐ° ÑÐºÑÑÐ²Ð°ÐµÑ ÑÑÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, Ñ
+ÐŸÑÑ ÐŸÐœÐž Ð²ÑÑ ÐµÑÑ  ÐŽÐŸÑÑÑÐ¿ÐœÑ Ð² ÑÐµÑÐµÐœÐžÐµ ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÐºÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž Ð² ÑÐ°ÐŒÐºÐ°Ñ
+ ÐŸÐºÐŸÐœÑÐ°ÑÐµÐ»ÑÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Greenstone. ÐÑÐ»Ðž Ð²ÑÐ±ÑÐ°ÐœÐŸ "ÐÐŸÐºÐ°Ð·Ð°ÑÑ ÑÐ°Ð·ÐŒÐµÑÑ ÑÐ°Ð¹Ð»Ð°", ÑÐŸ ÑÐ°Ð·ÐŒÐµÑ ÑÐ°Ð¹Ð»Ð° Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑÑÑ ÑÑÐŽÐŸÐŒ Ñ ÐºÐ°Ð¶ÐŽÑÐŒ ÑÐ°Ð¹Ð»ÐŸÐŒ Ð² ÑÐ°Ð±ÐŸÑÐµÐŒ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ðµ, Ð° ÑÐ°ÐºÐ¶Ðµ Ð² ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐŒ ÐŽÐµÑÐµÐ²Ðµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð² Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑÑ
+ Gather Ðž Enrich.
+<p></p>
+ÐÐ°ÐœÐµÐ»Ñ "Ð¡Ð¿ÐŸÑÐŸÐ±" ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ ÑÑÐŸÐ²ÐœÐµÐŒ Ð¿ÐŸÐŽÑÐŸÐ±ÐœÐŸÑÑÐµÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°. ÐÐ° ÑÐ°ÐŒÐŸÐŒ ÐœÐžÐ¶ÐœÐµÐŒ ÑÑÐŸÐ²ÐœÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐŸÐº ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ "ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ Ð¿ÐŸÐŒÐŸÑÐœÐžÐº", Ð¿ÑÐž ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐž ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ Ð¿ÑÐŸÐµÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÐœÐŸ, Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ, ÑÑÐµÐ±ÑÑÑÐžÐµ Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸÐ³ÐŸ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÑ, ÑÐºÑÑÑÑ Ðž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑÑÑ ÐŒÐžÐœÐžÐŒÐ°Ð»ÑÐœÐŸ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÑÐŒ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸÐŒ Ð·Ð°Ð¿ÐžÑÐµÐ¹. ÐÐ°ÐŸÐ±ÐŸÑÐŸÑ, ÐœÐ°ÐžÐ²ÑÑÑÐ°Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ° "Ð­ÐºÑÐ¿ÐµÑÑ" ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°ÐµÑ ÐŽÐŸÑÑÑÐ¿ ÐºÐŸ Ð²ÑÐµÐŒ ÑÑÐµÐŽÑÑÐ²Ð°ÐŒ Ð¿ÑÐŸÐµÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÑ, Ð²ÐºÐ»ÑÑÐ°Ñ Ð¿ÐŸÐ·ÐžÑÐžÐŸÐœÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ² Ðž Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ², Ð° ÑÐ°ÐºÐ¶Ðµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð¿ÐŸÐ»ÐœÑÐ¹ Ð²ÑÑ
+ÐŸÐŽ ÐžÐ· Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÑÑÐŸÐ±Ñ Ð·Ð°ÑÐžÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð² Ð¶ÑÑÐœÐ°Ð»Ðµ Ð·Ð°Ð¿ÐžÑÐµÐ¹. Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐžÐ»Ðž Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ ÑÐ¿ÐŸÑÐŸÐ±Ñ, ÐºÐ»ÐžÐºÐœÐžÑÐµ ÑÐ°ÐŽÐžÐŸ-ÐºÐœÐŸÐ¿ÐºÑ, ÑÐ»ÐµÐŽÑÑÑÑÑ Ð·Ð° ÑÐ¿ÐŸÑÐŸÐ±ÐŸÐŒ, ÐºÐŸÑÐŸÑÑÐ¹ ÐžÐœÑÐµÑÐµÑÑÐµÑ ÐÐ°Ñ. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð±ÑÑÑÑÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ, ÐºÐ°ÐºÐŸÐ¹ ÑÐ¿ÐŸÑÐŸÐ± ÐÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÐµ, ÑÐ°ÑÑÐŒÐ°ÑÑÐžÐ²Ð°Ñ Ð»ÐžÐœÐµÐ¹ÐºÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ Ð² ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐŒ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐµ. 
+<p></p>
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐŒÐŸÐ¶ÐµÑ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑ ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ ÑÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÑÐµÑÐºÐžÐµ Ð¿ÑÐŸÑÐµÑÑÑ Ð¿ÑÐž ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÐž, ÐºÐ°ÐºÐžÐµ ÐžÐ· ÑÐ°Ð·Ð»ÐžÑÐœÑÑ
+ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐ¹ ÑÐžÐŒÐ²ÐŸÐ»ÐŸÐ² ÑÐ²Ð»ÑÑÑÑÑ Ð²ÐžÐŽÐžÐŒÑÐŒÐž. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐ»Ð°Ð²ÐžÑÑ "Ð¢ÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÑÐµÑÐºÐžÐµ Ð¿ÑÐŸÑÐµÑÑÑ", ÑÑÐŸÐ±Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ, ÐºÐ°ÐºÐžÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž, Ð¿ÑÐŸÐ²ÐµÑÑÑ Ð¿ÐŸÐ»Ñ ÑÑÐŽÐŸÐŒ Ñ ÑÐµÐŒÐž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑÐŒÐž, ÐºÐŸÑÐŸÑÑÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž. ÐÐŒÐµÑÑÐŸ ÑÑÐŸÐ³ÐŸ ÐŒÐŸÐ¶ÐœÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº Ð²ÐœÐžÐ·Ñ ÑÐºÑÐ°ÐœÐ°,ÑÑÐŸÐ±Ñ Ð²ÑÐ±ÑÐ°ÑÑ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž. ÐÐ°ÐºÑÑÑÐžÐµ ÐŽÐžÐ°Ð»ÐŸÐ³Ð° Ð¿ÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÐ¹ Ð·Ð°ÐºÑÐµÐ¿Ð»ÑÐµÑ ÑÑÐž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž ÑÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÑÐµÑÐºÐŸÐ³ÐŸ Ð¿ÑÐŸÑÐµÑÑÐ°. Ð­ÑÐž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž Ñ
+ÑÐ°ÐœÑÑÑÑ Ð²ÐŒÐµÑÑÐµ Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹,Ð° ÐœÐµ Ð² ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÐŸÐŒ ÑÐ°Ð¹Ð»Ðµ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°.
+<p></p>
+ÐÐ»Ð°Ð²ÐžÑÐ° "Ð¡ÐŸÐµÐŽÐžÐœÐµÐœÐžÐµ" Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐÐ°ÐŒ ÐžÐ·ÐŒÐµÐœÑÑÑ Ð¿ÑÑÑ Ðº Ð»ÐŸÐºÐ°Ð»ÑÐœÐŸÐŒÑ ÑÐµÑÐ²ÐµÑÑ Greenstone, ÐºÐŸÑÐŸÑÑÐ¹ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸÐ³ÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑÐŸÐŒÐµ ÑÐŸÐ³ÐŸ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐŒÐŸÐŽÑÐ»Ñ ÐŽÐŸÑÑÑÐ¿Ð° Ðº ÐÐœÑÐµÑÐœÐµÑÑ Ð¿ÑÐŸÐºÑÐž (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐŽÐ»Ñ Ð·Ð°Ð³ÑÑÐ·ÐºÐž ÑÐ°Ð¹Ð»ÐŸÐ²; ÑÐŒÐŸÑÑÐž ÑÐ°Ð·ÐŽÐµÐ» <a href="downloadingfiles.htm#downloadingfiles">ÐÐ°Ð³ÑÑÐ¶Ð°ÑÑ Ð€Ð°Ð¹Ð»Ñ ÐžÐ· ÐÐœÑÐµÑÐœÐµÑÐ°</a> ÐŽÐ»Ñ Ð¿ÐŸÐŽÑÐŸÐ±ÐœÐŸÑÑÐµÐ¹). ÐÐŸÐŒÐµÑÑÑÐµ ÑÐ»Ð°Ð³ÐŸÐ²ÑÑ ÐºÐœÐŸÐ¿ÐºÑ, ÑÑÐŸÐ±Ñ Ð²ÐºÐ»ÑÑÐžÑÑ ÐŒÐŸÐŽÑÐ»Ñ ÐŽÐŸÑÑÑÐ¿Ð°, Ðž ÑÐºÐ°Ð¶ÐžÑÐµ ÐŽÐµÑÐ°Ð»Ðž Ð°ÐŽÑÐµÑÐ° ÑÐµÑÐ²ÐµÑÐ° Ð¿ÑÐŸÐºÑÐž Ðž ÐœÐŸÐŒÐµÑ Ð¿ÐŸÑÑÐ°. ÐÐŸÐŽÑÐ»Ñ ÐŽÐŸÑÑÑÐ¿Ð° Ð±ÑÐŽÐµÑ Ð°ÐºÑÐžÐ²ÐžÑÐŸÐ²Ð°Ðœ Ð¿ÑÐž Ð·Ð°ÐºÑÑÑÐžÐž ÐŽÐžÐ°Ð»ÐŸÐ³ÐŸÐ²ÐŸÐ³ÐŸ ÐŸÐºÐœÐ° ÐÐ¿ÑÐžÐ¹.
+<p></p>
+Ð ÑÐµÑÐµÐœÐžÐµ ÑÐµÑÑÐžÐž ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐŒÐŸÐ¶ÐµÑ ÐŽÐ°Ð²Ð°ÑÑ Ð¿ÑÐµÐŽÑÐ¿ÑÐµÐŽÐžÑÐµÐ»ÑÐœÑÐµ ÑÐŸÐŸÐ±ÑÐµÐœÐžÑ, ÐºÐŸÑÐŸÑÑÐµ ÐžÐœÑÐŸÑÐŒÐžÑÑÑÑ ÐÐ°Ñ ÐŸ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÑÑ
+ ÐœÐµÐ¿ÑÐµÐŽÐ²ÐžÐŽÐµÐœÐœÑÑ
+ Ð¿ÐŸÑÐ»ÐµÐŽÑÑÐ²ÐžÑÑ
+ ÐÐ°ÑÐžÑ
+ ÐŽÐµÐ¹ÑÑÐ²ÐžÐ¹. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð·Ð°Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÑÑ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐµ, Ð²ÑÐ±ÐžÑÐ°Ñ Ð¿ÐŸÐ»Ðµ "ÐÐµ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÑ ÑÑÐŸ Ð¿ÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐµÐœÐžÐµ ÑÐœÐŸÐ²Ð°". ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÐŸÐ·ÐŸÐ±ÐœÐŸÐ²ÐžÑÑ Ð¿ÐŸÑÐ²Ð»ÐµÐœÐžÐµ Ð¿ÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐ°ÑÑÐžÑ
+ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐ¹,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÐºÐ»Ð°Ð²ÐžÑÑ "ÐÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐµÐœÐžÐµ". ÐÑÐ±ÐµÑÐžÑÐµ Ð¿ÐŸÐ»Ðµ ÑÑÐŽÐŸÐŒ Ñ Ð¿ÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐ°ÑÑÐžÐŒÐž ÑÐŸÐŸÐ±ÑÐµÐœÐžÑÐŒÐž, ÐµÑÐ»Ðž ÐÑ Ñ
+ÐŸÑÐžÑÐµ ÑÐœÐŸÐ²Ð° Ð¿ÐŸÐ»ÑÑÐ°ÑÑ ÐžÑ
+.
+     </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/producingthecollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/producingthecollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/producingthecollection.htm	(revision 10506)
@@ -0,0 +1,18 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="producingthecollection"><font size="5" face="Verdana"><strong>7: ÐÐŸÑÑÑÐŸÐµÐœÐžÐµ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+ ÐÐŒÐµÑ ÑÐŸÐ±ÑÐ°ÐœÐœÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ ÐŽÐ»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ð°ÐœÐœÐŸÑÐžÑÐŸÐ²Ð°Ð² ÐžÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž Ðž ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÐ°Ð² ÐŽÐžÐ·Ð°Ð¹Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐµÐ¿ÐµÑÑ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Greenstone. Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÑÑÐŸ ÑÐŽÐµÐ»Ð°ÑÑ.
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/removingfiles.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/removingfiles.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/removingfiles.htm	(revision 10506)
@@ -0,0 +1,65 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="removingfiles"><font size="5" face="Verdana"><strong>4.4: Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ,ÐºÐ°Ðº ÑÐŽÐ°Ð»ÑÑÑ ÑÐ°Ð¹Ð»Ñ Ðž Ð¿Ð°Ð¿ÐºÐž ÐžÐ· ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.  
+
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐœÐŸÐ¿ÐºÐ° ÑÐŽÐ°Ð»ÐµÐœÐžÑ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ»Ð°Ð²ÐžÑÐ° ÑÐŽÐ°Ð»ÐµÐœÐžÑ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ Ð¿ÑÑÐµÐŒ Ð¿ÐµÑÐµÑÑÐ³ÐžÐ²Ð°ÐœÐžÑ Ðž ÐŸÑÐ¿ÑÑÐºÐ°ÐœÐžÑ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð¡ÑÑÐµÑÑÐ²ÑÐµÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÐŒÐµÑÐŸÐŽÐŸÐ² ÑÐŽÐ°Ð»ÐµÐœÐžÑ ÑÐ°Ð¹Ð»ÐŸÐ² Ðž Ð¿Ð°Ð¿ÐŸÐº. ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ ÑÐœÐ°ÑÐ°Ð»Ð° ÑÐºÐ°Ð·Ð°ÑÑ,ÐºÐ°ÐºÐžÐµ ÐžÐ· ÐœÐžÑ
+ ÑÐŽÐ°Ð»ÑÑÑ, Ð²ÑÐ±ÐžÑÐ°Ñ ÐŸÐŽÐžÐœ ÐžÐ»Ðž Ð±ÐŸÐ»ÐµÐµ ÑÐ°Ð¹Ð»ÐŸÐ² Ðž Ð¿Ð°Ð¿ÐŸÐº, ÐºÐ°Ðº ÐŸÐ¿ÐžÑÐ°ÐœÐŸ Ð² <a href="thegatherview.htm#thegatherview">ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐœÐ°ÐºÐŸÐ¿Ð»ÐµÐœÐžÐ¹</a>.
+<p></p>
+ ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÑÐ°Ð¹Ð»Ñ ÐŸÑÐŸÐ±ÑÐ°ÐœÑ, ÐŽÐ»Ñ ÐžÑ
+ ÑÐŽÐ°Ð»ÐµÐœÐžÑ ÑÐµÐ»ÐºÐ°ÑÑ ÐºÐœÐŸÐ¿ÐºÑ "Ð£ÐŽÐ°Ð»ÐžÑÑ"ÐžÐ»Ðž ÐœÐ°Ð¶ÐžÐŒÐ°ÑÑ ÐºÐºÐ»Ð°Ð²ÐžÑÑ [Ð£ÐŽÐ°Ð»ÐžÑÑ] ÐœÐ° ÐºÐ»Ð°Ð²ÐžÐ°ÑÑÑÐµ, ÐžÐ»Ðž Ð¶Ðµ ÑÑÐœÑÑ ÐžÑ
+ ÐžÐ· ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŽÐŸ ÐºÐœÐŸÐ¿ÐºÐž "Ð£ÐŽÐ°Ð»ÐžÑÑ" Ðž ÑÐ°ÐŒ ÐŸÑÐ¿ÑÑÐºÐ°ÑÑ.  
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/removingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/removingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/removingmetadata.htm	(revision 10506)
@@ -0,0 +1,62 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="removingmetadata"><font size="5" face="Verdana"><strong>5.6: Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÑÐŽÐ°Ð»ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ².
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ² 
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐžÐ· Ð¿Ð°Ð¿ÐŸÐº ÐžÐ»Ðž ÐŒÐœÐŸÐ¶ÐµÑÑÐ²Ð° ÑÐ°Ð¹Ð»ÐŸÐ²
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð²ÑÐ¿ÐŸÐ»ÐœÑÐµÑÑÑ ÑÐ°ÐºÐžÐŒ Ð¶Ðµ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ,ÐºÐ°Ðº Ðž ÐžÑ
+ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ. Ð¡ÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÐ°Ð¹Ð» ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ³ÐŸ ÐŽÐµÑÐµÐ²Ð°,Ð·Ð°ÑÐµÐŒ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÑÐ°Ð±Ð»ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÑÑÐŸÐ±Ñ Ð²ÑÐ±ÑÐ°ÑÑ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÐµ. ÐÑÐ»Ðž Ðº ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÐŸÐŒÑ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ, ÐºÐœÐŸÐ¿ÐºÐ° "Ð£ÐŽÐ°Ð»ÐžÑÑ" Ð°ÐºÑÐžÐ²ÐžÑÑÐµÑÑÑ. Ð©ÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÐœÐµÐ¹,ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÑÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÐ· ÑÐºÐ°Ð·Ð°ÐœÐœÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð°. ÐÑÑÐ³ÐžÐµ ÑÐ°Ð¹Ð»Ñ ÐŸÑÑÐ°ÑÑÑÑ ÐœÐµÐžÐ·ÐŒÐµÐœÐœÑÐŒÐž, Ðž ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŸÑÑÐ°ÑÑÑÑ Ð² ÐŽÐµÑÐµÐ²Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹.
+<p></p>
+ÐÑÐŸÑÐµÑÑ ÑÐŽÐ°Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ Ñ Ð¿Ð°Ð¿ÐŸÐº ÐžÐ»Ðž ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÑÐŸÑ Ð¶Ðµ ÑÐ°ÐŒÑÐ¹.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/reviewingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/reviewingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/reviewingmetadata.htm	(revision 10506)
@@ -0,0 +1,97 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="reviewingmetadata"><font size="5" face="Verdana"><strong>5.7: ÐÑÐŸÑÐŒÐŸÑÑ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ, ÐºÐ°Ðº Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ Ð²ÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÐŽÐ»Ñ Ð¿ÐŸÐ»ÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐœÑÑÐŸÐ»ÑÐœÐ°Ñ ÑÐ°Ð±Ð»ÐžÑÐ°
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÑÐ°Ð²Ð°Ñ ÐºÐœÐŸÐ¿ÐºÐ° ÐŒÐµÐœÑ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ²ÑÐŸÑÐžÐ»ÑÑÑ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÐœÐŸÐ³ÐŽÐ° ÐÐ°ÐŒ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ,Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÐŽÐ»Ñ ÐŒÐœÐŸÐ³ÐžÑ
+ ÐžÐ»Ðž Ð²ÑÐµÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÑÑÐ°Ð·Ñ - ÐœÐ°Ð¿ÑÐžÐŒÐµÑ,ÑÑÐŸÐ±Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ,ÑÐºÐŸÐ»ÑÐºÐŸ ÑÐ°Ð¹Ð»ÐŸÐ² ÐŸÑÑÐ°ÑÑÑÑ ÐŽÐ»Ñ Ð²ÐŸÐ·ÐŽÐµÐ¹ÑÑÐ²ÐžÑ ÐžÐ»Ðž Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐœÐµÐºÐŸÑÐŸÑÑÐµ ÐžÐŽÐµÐž ÐŸÑÐœÐŸÑÐžÑÐµÐ»ÑÐœÐŸ ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÐµÐœÐžÑ ÐŽÐ°ÐœÐœÑÑ
+.
+<p></p>
+ÐÑÐ±ÐµÑÐžÑÐµ ÑÐ°Ð¹Ð»Ñ, ÐºÐŸÑÐŸÑÑÐµ Ð²Ñ Ñ
+ÐŸÑÐžÑÐµ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ, Ð¿ÐŸÑÐŸÐŒ ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° Ð¿ÑÐ°Ð²ÑÑ ÐºÐœÐŸÐ¿ÐºÑ ÐŒÑÑÐž Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ "ÐÐ°Ð·ÐœÐ°ÑÐµÐœÑÐµ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ...". ÐÐŸÑÐ²Ð»ÑÐµÑÑÑ ÐŸÐºÐœÐŸ,ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÐŸÐµ "ÐÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ", Ð·Ð°ÐœÑÑÐŸÐµ Ð±ÐŸÐ»ÑÑÐŸÐ¹ ÑÐ°Ð±Ð»ÐžÑÐµÐ¹,ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐµÐ¹ ÐŒÐœÐŸÐ³ÐŸ ÐºÐŸÐ»ÐŸÐœÐŸÐº.ÐÐµÑÐ²Ð°Ñ ÐºÐŸÐ»ÐŸÐœÐºÐž Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐžÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÐŸÐ²;ÑÑÑÐŸÐºÐž Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÑ Ð²ÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ ÑÑÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ².  
+ <p></p>
+ Ð ÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÑÐ°Ð±Ð»ÐžÑÑ ÐŒÐŸÐ¶ÐµÑ Ð·Ð°ÐœÑÑÑ ÐœÐµÐºÐŸÑÐŸÑÐŸÐµ Ð²ÑÐµÐŒÑ,ÐµÑÐ»Ðž Ð²ÑÐ¿Ð°Ð»ÐŸ ÐŒÐœÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»ÐŸÐ².ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÑÐŸÐŽÐŸÐ»Ð¶Ð°ÑÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐŒ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐŸÐŒ Ð¿ÑÐž ÐŸÑÐºÑÑÑÐŸÐŒ ÐŸÐºÐœÐµ "ÐÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ". 
+<p></p>
+Ð©ÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐºÑÑÑÑ", ÑÑÐŸÐ±Ñ ÑÐºÑÑÑÑ ÐŸÐºÐœÐŸ.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐ°ÐºÐ¶Ðµ ÑÐ°ÑÑÐŒÐŸÑÑÐµÑÑ ÑÐ°Ð±Ð»ÐžÑÑ "ÐÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ",Ð²ÑÐ±ÐžÑÐ°Ñ ÑÐµ ÑÐ°Ð¹Ð»Ñ, ÐºÐŸÑÐŸÑÑÐµ ÐÑ Ð¶ÐµÐ»Ð°ÐµÑÐµ ÐžÐ·ÑÑÐžÑÑ, ÑÐµÐ»ÐºÐœÑÐ² Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐŸÐ¹ Ðž Ð²ÑÐ±ÐžÑÐ°Ñ "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ".ÐÑÐ»Ðž Ð±ÑÐ»Ð° Ð²ÑÐ±ÑÐ°ÐœÐ° Ð¿Ð°Ð¿ÐºÐ°,ÑÐŸ Ð²ÑÐµ ÐµÑ ÐŽÐŸÑÐµÑÐœÐžÐµ ÑÐ°Ð¹Ð»Ñ Ð²ÐºÐ»ÑÑÐµÐœÑ Ð² ÑÐ°Ð±Ð»ÐžÑÑ.  
+<p></p>
+ ÐÐŸÐ³ÐŽÐ° ÐŸÐœÐ° ÑÑÐ°ÐœÐŸÐ²ÐžÑÑÑ ÑÐ»ÐžÑÐºÐŸÐŒ Ð±ÐŸÐ»ÑÑÐŸÐ¹,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÑÑÐžÐ»ÑÑÑÐŸÐ²Ð°ÑÑ ÑÐ°Ð±Ð»ÐžÑÑ "ÐÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ",Ð¿ÑÐžÐŒÐµÐœÑÑ ÑÐžÐ»ÑÑÑÑ Ðº ÐºÐŸÐ»ÐŸÐœÐºÐ°ÐŒ.ÐÐŸÑÐºÐŸÐ»ÑÐºÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÑ ÐœÐŸÐ²ÑÐµ ÑÐžÐ»ÑÑÑÑ, ÑÐŸÐ»ÑÐºÐŸ ÑÐµ ÑÑÑÐŸÐºÐž,ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑ ÐžÐŒ,ÐŸÑÑÐ°ÑÑÑÑ Ð²ÐžÐŽÐžÐŒÑÐŒÐž.Ð§ÑÐŸÐ±Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ,ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐžÐ»Ðž ÐŸÑÐžÑÑÐžÑÑ ÑÐžÐ»ÑÑÑ,ÑÐµÐ»ÐºÐœÐžÑÐµ Ð¿ÐŸ ÐžÐºÐŸÐœÐºÐµ "ÐÐŸÑÐŸÐœÐºÐ°" ÐœÐ°Ð²ÐµÑÑ
+Ñ ÐºÐŸÐ»ÐŸÐœÐºÐž. Ð£ Ð²Ð°Ñ Ð±ÑÐŽÐµÑ Ð·Ð°Ð¿ÑÐŸÑÐµÐœÐ° ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ ÑÐžÐ»ÑÑÑÐµ. ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÑÐžÐ»ÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ,ÐžÐ·ÐŒÐµÐœÑÐµÑÑÑ ÑÐ²ÐµÑ ÐºÐŸÐ»ÐŸÐœÐºÐž.
+<p></p>
+ ÐÐ°Ð¿ÑÐŸÑ ÐžÐŒÐµÐµÑ ÑÐžÐŒÐ²ÐŸÐ»Ñ "ÐÑÐŸÑÑÐŸÐ¹" Ðž "ÐÑÐŸÐŽÐ²ÐžÐœÑÑÑÐ¹".ÐÑÐŸÑÑÐ°Ñ Ð²ÐµÑÑÐžÑ ÑÐžÐ»ÑÑÑÑÐµÑ ÐºÐŸÐ»ÐŸÐœÐºÐž ÑÐ°Ðº,ÑÑÐŸ ÐŸÐœÐž Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÑ ÑÐŸÐ»ÑÐºÐŸ ÑÑÑÐŸÐºÐž, ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ("*" ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ Ð²ÑÐµÐŒ Ð·ÐœÐ°ÑÐµÐœÐžÑÐŒ).ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐžÐ· ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐ³ÐŸ ÑÐ¿ÐžÑÐºÐ°.ÐÑÐŸÐŽÐ²ÐžÐœÑÑÐ°Ñ Ð²ÐµÑÑÐžÑ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð²ÑÐ¿ÐŸÐ»ÐœÑÑÑ ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ ÐŽÐµÐ¹ÑÑÐ²ÐžÑ:ÐÐŸÐ»Ð¶ÐµÐœ ÐœÐ°ÑÐ°ÑÑÑÑ Ñ,ÐÐµ ÑÐŸÐŽÐµÑÐ¶ÐžÑ,Ð Ð°Ð»ÑÐ°Ð²ÐžÑÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ,ÐÐµÐœÑÑÐµ ÑÐµÐŒ, Ð­ÐºÐ²ÐžÐ²Ð°Ð»ÐµÐœÑÐµÐœ. ÐÐœÐ°ÑÐµÐœÐžÐµ, ÐºÐŸÑÐŸÑÐŸÐµ Ð±ÑÐŽÐµÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐŸÐ²Ð°ÑÑ, ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐŸ ÑÐ°Ðº,ÑÑÐŸÐ±Ñ Ð±ÑÑÑ Ð»ÑÐ±ÐŸÐ¹ ÑÑÑÐŸÐºÐŸÐ¹,Ð²ÐºÐ»ÑÑÐ°Ñ "*". ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ,ÐŽÐŸÐ»Ð¶ÐœÐŸ Ð»Ðž ÑÑÐŸ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÐµ Ð±ÑÑÑ ÐœÐµ ÑÑÐ²ÑÑÐ²ÐžÑÐµÐ»ÑÐœÑÐŒ ÑÐ»ÑÑÐ°ÐµÐŒ. ÐÐ°ÐºÐŸÐœÐµÑ,ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ Ð²ÑÐŸÑÐŸÐµ ÑÑÐ»ÐŸÐ²ÐžÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÑ,ÐºÐŸÑÐŸÑÐŸÐµ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐŽÐ»Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÑÐ°ÐœÐ³Ð° Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ (Ð²ÑÐ±ÐžÑÐ°Ñ Ð Ð±ÐŸÐ»ÑÑÐŸÐµ) ÐžÐ»Ðž Ð°Ð»ÑÑÐµÑÐœÐ°ÑÐžÐ²ÐœÑÑ
+ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ (Ð²ÑÐ±ÐžÑÐ°Ñ ÐÐÐ).ÐÐžÐ¶Ðµ ÑÑÐŸÐ¹ ÐŸÐ±Ð»Ð°ÑÑÐž ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ Ð¿ÐŸÐ»Ðµ, ÐºÐŸÑÐŸÑÐŸÐµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐÐ°ÐŒ ÐžÐ·ÐŒÐµÐœÑÑÑ Ð¿ÐŸÑÑÐŽÐŸÐº ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž (Ð²ÐŸÐ·ÑÐ°ÑÑÐ°ÑÑÐžÐ¹ ÐžÐ»Ðž Ð¿ÐŸÐœÐžÐ¶Ð°ÑÐžÐ¹ÑÑ).ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐÑ Ð·Ð°ÐºÐŸÐœÑÐžÑÐµ,ÐœÐ°Ð¶ÐŒÐžÑÐµ "Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐžÐ»ÑÑÑÐ°",ÑÑÐŸÐ±Ñ Ð¿ÑÐžÐŒÐµÐœÐžÑÑ ÐœÐŸÐ²ÑÐ¹ ÑÐžÐ»ÑÑÑ Ðº ÐºÐŸÐ»ÐŸÐœÐºÐµ.ÐÐ°Ð¶ÐŒÐžÑÐµ "ÐÑÐžÑÑÐžÑÑ ÑÐžÐ»ÑÑÑ",ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÐµÐºÑÑÐžÐ¹ ÑÐžÐ»ÑÑÑ.ÐÐ±ÑÐ°ÑÐžÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ ÐœÐ° ÑÐŸ,ÑÑÐŸ ÐŽÐµÑÐ°Ð»Ðž ÑÐžÐ»ÑÑÑÐ° ÑÐŸÑ
+ÑÐ°ÐœÑÑÑÑÑ, ÐŽÐ°Ð¶Ðµ ÐºÐŸÐ³ÐŽÐ° ÑÐžÐ»ÑÑÑ ÐŸÑÐžÑÐµÐœ.
+ <p></p>
+ÐÐ°Ð¿ÑÐžÐŒÐµÑ,ÑÑÐŸÐ±Ñ ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐ°Ð±Ð»ÐžÑÑ "ÐÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ",Ð²ÑÐ±ÐµÑÐžÑÐµ ÐºÐŸÐ»ÐŸÐœÐºÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÑÑÐ°ÐœÐŸÐ²ÐºÑ ÑÐžÐ»ÑÑÑÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ (Ð¿ÑÐŸÑÑÐŸÐ¹ ÑÐžÐ»ÑÑÑ ÐœÐ° "*") Ðž Ð²ÐŸÐ·ÑÐ°ÑÑÐ°ÑÑÐžÐ¹ ÐžÐ»Ðž Ð¿ÐŸÐœÐžÐ¶Ð°ÑÑÐžÐ¹ÑÑ Ð¿ÐŸÑÑÐŽÐŸÐº.   
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/savingacollection.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/savingacollection.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/savingacollection.htm	(revision 10506)
@@ -0,0 +1,77 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="savingacollection"><font size="5" face="Verdana"><strong>2.2: Ð¡ÐŸÑ
+ÑÐ°ÐœÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ, ÐºÐ°Ðº ÑÐŸÑ
+ÑÐ°ÐœÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ðž ÐºÐ°Ðº ÑÐŸÑ
+ÑÐ°ÐœÐžÑÑ ÐµÑ ÐœÐµÐ·Ð°ÐŒÐµÐŽÐ»ÐžÑÐµÐ»ÑÐœÐŸ. 
+
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ°Ðº ÑÐŸÑ
+ÑÐ°ÐœÐžÑÑ
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐŽÐµ ÑÐ°Ð¹Ð»Ñ ÑÐŸÑ
+ÑÐ°ÐœÐµÐœÑ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð¡ÐŸÑ
+ÑÐ°ÐœÑÐ¹ÑÐµ ÐÐ°ÑÑ ÑÐ°Ð±ÐŸÑÑ ÑÐµÐ³ÑÐ»ÑÑÐœÐŸ, ÐŸÑÐºÑÑÐ²Ð°Ñ ÐŒÐµÐœÑ "Ð€Ð°Ð¹Ð»" Ðž Ð²ÑÐ±ÐžÑÐ°Ñ Ð² ÐœÑÐŒ Ð¿ÑÐœÐºÑ "Ð¡ÐŸÑ
+ÑÐ°ÐœÐžÑÑ". Ð¡ÐŸÑ
+ÑÐ°ÐœÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž - ÑÑÐŸ ÐœÐµ ÑÐŸ Ð¶Ðµ ÑÐ°ÐŒÐŸÐµ, ÐºÐ°Ðº  ÑÐŽÐµÐ»Ð°ÑÑ ÐµÑ Ð³ÐŸÑÐŸÐ²ÐŸÐ¹ Ðº ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ Ð² Greenstone.
+ (see <a href="producingthecollection.htm#producingthecollection">Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</a>).
+<p></p>
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð·Ð°ÑÐžÑÐ°ÐµÑ ÐÐ°ÑÑ ÑÐ°Ð±ÐŸÑÑ Ð¿ÑÑÑÐŒ ÑÐŸÑ
+ÑÐ°ÐœÐµÐœÐžÑ ÐµÑ Ð²ÑÑÐºÐžÐ¹ ÑÐ°Ð·, ÐºÐŸÐ³ÐŽÐ° ÐÑ Ð²ÑÑ
+ÐŸÐŽÐžÑÐµ ÐžÐ· Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ ÐžÐ»Ðž Ð·Ð°Ð³ÑÑÐ¶Ð°ÐµÑÐµ ÐŽÑÑÐ³ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð¡ÐŸÑ
+ÑÐ°ÐœÐµÐœÐœÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð·Ð°Ð¿ÐžÑÑÐ²Ð°ÑÑÑÑ  Ð² ÑÐ°Ð¹Ð», ÐžÐŒÐµÑÑÐžÐ¹ ÑÐŸ Ð¶Ðµ ÐžÐŒÑ, ÑÑÐŸ Ðž ÐžÐŒÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ñ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµÐŒ ".col", Ðž ÑÐ°ÑÐ¿ÐŸÐ»Ð°Ð³Ð°ÐµÑÑÑ Ð² Ð¿Ð°Ð¿ÐºÐµ ÑÐŸÐ³ÐŸ Ð¶Ðµ ÐœÐ°ÐžÐŒÐµÐœÐŸÐ²Ð°ÐœÐžÑ, ÑÑÐŸ Ðž Ð¿Ð°Ð¿ÐºÐ° "collect" Ð¿ÑÐž ÐžÐœÑÑÐ°Ð»Ð»ÑÑÐžÐž Greenstone.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/searchindexes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/searchindexes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/searchindexes.htm	(revision 10506)
@@ -0,0 +1,85 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="searchindexes"><font size="5" face="Verdana"><strong>6.5: ÐÐœÐŽÐµÐºÑÑ Ð¿ÐŸÐžÑÐºÐ°</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ ÐÐœÐŽÐµÐºÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÑÑ,ÐºÐ°ÐºÐžÐµ ÑÐ°ÑÑÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°. Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ Ðž ÑÐŽÐ°Ð»ÐžÑÑ ÐžÐœÐŽÐµÐºÑÑ,Ð° ÑÐ°ÐºÐ¶Ðµ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐžÐœÐŽÐµÐºÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ.ÐÐŸÐŽ "Ð Ð°Ð·ÐŽÐµÐ»Ð°ÐŒÐž ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ ÐžÐœÐŽÐµÐºÑÑ Ð¿ÐŸÐžÑÐºÐ°.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐžÐœÐŽÐµÐºÑ
+          </td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    ÐÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐžÐœÐŽÐµÐºÑ
+	  </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÐŽÐ°Ð»ÐžÑÑ ÐžÐœÐŽÐµÐºÑ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÐžÐœÐŽÐµÐºÑÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐžÐœÐŽÐµÐºÑ,Ð²Ð²ÐµÐŽÐžÑÐµ ÐžÐŒÑ ÐŽÐ»Ñ ÐœÐµÐ³ÐŸ Ð² Ð¿ÐŸÐ»Ðµ "ÐÐŒÑ ÐžÐœÐŽÐµÐºÑÐ°".ÐÑÐ±ÐµÑÐžÑÐµ, ÐºÐ°ÐºÐžÐµ ÐžÐ· Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÑÑ
+ ÐžÑÑÐŸÑÐœÐžÐºÐŸÐ² ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž Ð¿ÑÐžÑÐŸÐµÐŽÐžÐœÐžÑÑ Ðº ÐžÐœÐŽÐµÐºÑÑ, ÑÐµÐ»ÐºÐ°Ñ ÐœÐ° Ð¿ÐŸÐ»Ðµ ÐŸÐºÐŸÐ»ÐŸ ÐœÐžÑ
+. Ð¡Ð¿ÐžÑÐŸÐº Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð²ÑÐµ Ð·Ð°ÐŽÐ°ÐœÐœÑÐµ ÑÐ»ÐµÐŒÐµÐœÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, Ð° ÑÐ°ÐºÐ¶Ðµ Ð¿ÐŸÐ»ÐœÑÐ¹ ÑÐµÐºÑÑ. Ð Ð°ÑÐ¿ÐŸÐ»Ð°Ð³Ð°Ñ Ð²ÑÐ±ÑÐ°ÐœÐœÑÐŒÐž ÐžÑÑÐŸÑÐœÐžÐºÐ°ÐŒÐž ÐŽÐ°ÐœÐœÑÑ
+, Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÑÐµÐ¿ÐµÐœÑ ÐŽÐµÑÐ°Ð»ÐžÐ·Ð°ÑÐžÐž ÐžÐœÐŽÐµÐºÑÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÐŒÐµÐœÑ "ÐÐ° ÑÑÐŸÐ²ÐœÐµ". ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÑÑÐž ÐŽÐµÑÐ°Ð»Ðž ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ,Ð¿ÑÐœÐºÑ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐžÐœÐŽÐµÐºÑ" ÑÑÐ°ÐœÐŸÐ²ÐžÑÑÑ Ð°ÐºÑÐžÐ²ÐœÑÐŒ (ÐµÑÐ»Ðž ÐœÐµÑ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÐžÐœÐŽÐµÐºÑÐ° Ñ ÑÐµÐŒÐž Ð¶Ðµ ÑÐ°ÐŒÑÐŒÐž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°ÐŒÐž).Ð©ÐµÐºÐœÐžÑÐµ ÐœÐ° ÐœÑÐŒ, ÑÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÐ¹ ÐžÐœÐŽÐµÐºÑ.
+<p></p>
+Ð§ÑÐŸÐ±Ñ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐžÐœÐŽÐµÐºÑ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ Ðž ÐžÐ·ÐŒÐµÐœÐžÑÐµ ÐŽÐµÑÐ°Ð»Ðž. ÐÐŸÐŽÑÐ²ÐµÑÐŽÐžÑÐµ, ÐœÐ°Ð¶Ð°Ð² ÐœÐ° "ÐÐ°ÐŒÐµÐœÐžÑÑ ÐžÐœÐŽÐµÐºÑ".
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÐžÐœÐŽÐµÐºÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÑ
+ ÐžÐœÐŽÐµÐºÑÐŸÐ² Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÐžÐœÐŽÐµÐºÑ".
+<p></p>
+ ÐÐœÐŽÐµÐºÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ - ÑÐŸÑ, ÐºÐŸÑÐŸÑÑÐ¹ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐœÐ° Ð¿ÐŸÐžÑÐºÐŸÐ²ÐŸÐ¹ ÑÑÑÐ°ÐœÐžÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž,Ð¿ÐŸÐŒÐµÑÐµÐœ ÑÑÐ³Ð°ÐŒÐž "[ÐÐœÐŽÐµÐºÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ]" Ð² ÑÐ¿ÐžÑÐºÐµ "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÐœÐŽÐµÐºÑÑ".Ð§ÑÐŸÐ±Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐµÐ³ÐŸ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐžÐœÐŽÐµÐºÑ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÑÑÐ°ÐœÐŸÐ²ÐžÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ".
+<p></p>
+ ÐÑÐ»Ðž Ð¿ÐŸÐ·Ð²ÐŸÐ»ÐµÐœ ÑÐ°ÑÑÐžÑÐµÐœÐœÑÐ¹ Ð¿ÐŸÐžÑÐº (ÑÐµÑÐµÐ· Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð²ÐžÐŽÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°), ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐžÐœÐŽÐµÐºÑÐŸÐŒ ÐŸÑÐ»ÐžÑÐ°ÐµÑÑÑ.ÐÐ°Ð¶ÐŽÑÐ¹ ÐžÐœÐŽÐµÐºÑ Ð±Ð°Ð·ÐžÑÑÐµÑÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐœÐ° ÐŸÐŽÐœÐŸÐŒ ÐžÑÑÐŸÑÐœÐžÐºÐµ ÐŽÐ°ÐœÐœÑÑ
+.ÐÐŒÐµÐµÑÑÑ ÐœÐŸÐ²ÑÐ¹ ÐžÑÑÐŸÑÐœÐžÐº Ð¿ÑÐµÐ²ÐŽÐŸÐŽÐ°ÐœÐœÑÑ
+ "Ð²ÑÐµ Ð¿ÐŸÐ»Ñ",ÐºÐŸÑÐŸÑÑÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°ÑÑ Ð¿ÐŸÐžÑÐº Ð¿ÐŸ Ð²ÑÐµÐŒ ÑÐºÐ°Ð·Ð°ÐœÐœÑÐŒ ÐžÐœÐŽÐµÐºÑÐ°ÐŒ ÑÑÐ°Ð·Ñ.Ð£ÑÐŸÐ²ÐœÐž ÐœÐµ Ð¿ÑÐžÐ²ÑÐ·Ð°ÐœÑ Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐŸÐŒÑ ÐžÐœÐŽÐµÐºÑÑ,Ð° Ð¿ÑÐžÐŒÐµÐœÑÑÑÑÑ ÐºÐŸ Ð²ÑÐµÐŒ ÐžÐœÐŽÐµÐºÑÐ°ÐŒ.Ð¢Ð°ÐºÐžÐŒ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ,ÐžÐœÐŽÐµÐºÑÑ Ðž ÑÑÐŸÐ²ÐœÐž ÐŽÐŸÐ±Ð°Ð²Ð»ÑÑÑÑÑ ÐŸÑÐŽÐµÐ»ÑÐœÐŸ.ÐÐœÐŽÐµÐºÑÑ ÑÐŽÐ°Ð»ÑÑÑÑÑ ÑÐµÐŒ Ð¶Ðµ ÑÐ°ÐŒÑÐŒ ÑÐ¿ÐŸÑÐŸÐ±ÐŸÐŒ,ÐºÐ°Ðº Ð±ÑÐ»ÐŸ ÑÐºÐ°Ð·Ð°ÐœÐŸ Ð²ÑÑÐµ,ÐœÐŸ ÐžÐœÐŽÐµÐºÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ Ð±ÐŸÐ»ÑÑÐµ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ. Ð­ÑÐŸ Ð¿ÑÐŸÑÑÐŸ Ð¿ÐµÑÐ²ÑÐ¹ ÐžÐ· ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÑ
+ ÐžÐœÐŽÐµÐºÑÐŸÐ².   
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐžÐœÐŽÐµÐºÑÑ ÐœÐ° Ð²ÑÐµÑ
+ ÐžÑÑÐŸÑÐœÐžÐºÐ°Ñ
+,ÑÐµÐ»ÐºÐœÐžÑÐµ ÐºÐœÐŸÐ¿ÐºÑ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð²ÑÐµ". ÐÐŒÑ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐžÐœÐŽÐµÐºÑÐ° Ð±ÑÐŽÐµÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ ÑÐ²ÑÐ·Ð°ÐœÐŸ Ñ ÐžÐŒÐµÐœÐµÐŒ ÐžÑÑÐŸÑÐœÐžÐºÐ°.Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐžÐŒÑ,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐžÐœÐŽÐµÐºÑ,ÐžÐ·ÐŒÐµÐœÐžÑÐµ ÐµÐ³ÐŸ ÐŽÐµÑÐ°Ð»Ðž Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ ÐžÐœÐŽÐµÐºÑ".   
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/searchtypes.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/searchtypes.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/searchtypes.htm	(revision 10506)
@@ -0,0 +1,79 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="searchtypes"><font size="5" face="Verdana"><strong>6.4: ÐÐžÐŽÑ Ð¿ÐŸÐžÑÐºÐ°</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐŸÑÐŸÐ±ÐµÐœÐœÐŸÑÑÐž ÐœÐŸÐ²ÐŸÐ³ÐŸ ÐŽÐžÐ·Ð°Ð¹ÐœÐ° Ð² Greenstone; Ð²ÐžÐŽÑ Ð¿ÐŸÐžÑÐºÐ°,ÐºÐŸÑÐŸÑÑÐµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÑÑ Ð¿ÑÐŸÐ²ÐŸÐŽÐžÑÑ Ð¿ÐŸÐžÑÐº Ð¿ÐŸ Ð¿ÐŸÐ»ÑÐŒ. Ð©ÐµÐ»ÐºÐœÐžÑÐµ Ð²ÐžÐŽÑ Ð¿ÐŸÐžÑÐºÐ° Ð² "Ð Ð°Ð·ÐŽÐµÐ»Ð°Ñ
+ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐ°Ðº Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÑÑÑÑ ÑÑÐµÐŽÑÑÐ²Ð° ÑÐ°ÑÑÐžÑÐµÐœÐœÐŸÐ³ÐŸ Ð¿ÐŸÐžÑÐºÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ³ÐŸ Ð²ÐžÐŽÐ° Ð¿ÐŸÐžÑÐºÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ Ð²ÐžÐŽÐ° Ð¿ÐŸÐžÑÐºÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ·ÐŒÐµÐœÐµÐœÐžÐµ Ð¿ÐŸÑÑÐŽÐºÐ° Ð²ÐžÐŽÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÐŸÐ³ÐŽÐ° ÐÑ ÐœÐ°ÑÐžÐœÐ°ÐµÑÐµ Ð¿ÑÐŸÑÐŒÐŸÑÑ Ð²ÐžÐŽÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°, ÑÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐžÑÐµ "ÐÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑ ÑÐ°ÑÑÐžÑÐµÐœÐœÐŸÐ³ÐŸ Ð¿ÐŸÐžÑÐºÐ°",ÐºÐŸÑÐŸÑÑÐ¹ Ð°ÐºÑÐžÐ²ÐžÐ·ÐžÑÑÐµÑ ÐŽÑÑÐ³ÐžÐµ ÑÑÐµÐŽÑÑÐ²Ð° ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ.Ð­ÑÐŸ Ð¿ÐµÑÐµÐ²ÐŸÐŽÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð² ÑÐŸÑÐŒÐ°Ñ Greenstone 2.4, ÐºÐŸÑÐŸÑÑÐ¹ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÐµÑ Ð¿ÐŸÐžÑÐº Ð¿ÐŸ Ð¿ÐŸÐ»ÑÐŒ Ðž ÐŸÐ·ÐœÐ°ÑÐ°ÐµÑ, ÑÑÐŸ (Ð°) - ÐžÐœÐŽÐµÐºÑ ÐŽÐžÐ·Ð°Ð¹ÐœÐ° ÑÐ²Ð»ÑÐµÑÑÑ ÐŸÑÐ»ÐžÑÐ°ÑÑÐžÐŒÑÑ,ÐŸÐ±ÑÑÑÐœÐµÐœ Ð²
+ (<a href="searchindexes.htm#searchindexes">ÐÐœÐŽÐµÐºÑÑ Ð¿ÐŸÐžÑÐºÐ°</a> section);
+(b) - ÐžÐŒÐµÐµÑÑÑ Ð±ÐŸÐ»ÑÑÐµ ÑÑÐ°Ð³ÐŒÐµÐœÑÐŸÐ² ÑÐµÐºÑÑÐ° ÐŽÐ»Ñ Ð¿ÐµÑÐµÐ²ÐŸÐŽÐ° (<a href="translatetext.htm#translatetext">ÐÐµÑÐµÐ²ÐŸÐŽ</a>);(c) - ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµ Ð±ÑÐŽÐµÑ Ð³ÐŸÐŽÐœÐ° Ðº ÑÐ¿ÐŸÑÑÐµÐ±Ð»ÐµÐœÐžÑ Ð¿ÑÐž Ð±ÐŸÐ»ÐµÐµ ÑÑÐ°ÑÑÑ
+ Ð²ÐµÑÑÐžÑÑ
+ Greenstone. ÐÑÐ»Ðž ÐÑ Ð¿ÐŸÐ·Ð¶Ðµ ÐœÐµ Ð¿ÑÐŸÐ²ÐµÑÐžÑÐµ ÑÑÐŸ Ð¿ÐŸÐ»Ðµ,ÑÐŸ Ð±ÐŸÐ»ÑÑÐ°Ñ ÑÐ°ÑÑÑ ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð²ÐµÑÐœÑÑÑÑ Ðº Greenstone 2.39.ÐÐŽÐœÐ°ÐºÐŸ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð¿ÑÐµÐŸÐ±ÑÐ°Ð·ÐŸÐ²Ð°ÑÑ ÐœÐŸÐ²ÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÐžÐœÐŽÐµÐºÑÐ° Ð² Ð±ÐŸÐ»ÐµÐµ ÑÑÐ°ÑÑÐµ,ÑÐ°Ðº ÑÑÐŸ ÐÑ Ð±ÑÐŽÐµÑÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð²ÐµÑÐœÑÑÑ ÐžÑ
+ Ð²ÑÑÑÐœÑÑ.
+ <p></p>
+ Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ°,Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° "ÐÐžÐŽÑ Ð¿ÐŸÐžÑÐºÐ°" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ°".ÐÐ°Ð¶ÐŽÑÐ¹ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ° ÐŒÐŸÐ¶ÐµÑ Ð¿ÐŸÑÐ²ÐžÑÑÑÑ Ð² ÑÐ¿ÐžÑÐºÐµ ÑÐŸÐ»ÑÐºÐŸ ÐŸÐŽÐžÐœ ÑÐ°Ð·.
+<p></p>
+Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ°, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° "Ð¢ÐµÐºÑÑÐžÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ Ð²ÐžÐŽÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ°".Ð¡Ð¿ÐžÑÐŸÐº ÐŽÐŸÐ»Ð¶ÐµÐœ ÑÐŸÐŽÐµÑÐ¶Ð°ÑÑ Ð¿ÐŸ ÐºÑÐ°Ð¹ÐœÐµÐ¹ ÐŒÐµÑÐµ ÐŸÐŽÐžÐœ Ð²ÐžÐŽ Ð¿ÐŸÐžÑÐºÐ°. 
+ <p></p>
+ Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð¿ÐŸÑÑÐŽÐŸÐº ÑÐ»ÐµÐŽÐŸÐ²Ð°ÐœÐžÑ Ð²ÐžÐŽÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ ÐžÐ· ÑÐ¿ÐžÑÐºÐ° Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²Ð²ÐµÑÑ
+" ÐžÐ»Ðž "ÐÐ²ÐžÐ³Ð°ÑÑÑÑ Ð²ÐœÐžÐ·". ÐÐµÑÐ²ÑÐ¹ ÐžÐ· ÐœÐŒÑ
+ Ð±ÑÐŽÐµÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/selectingmetadatasets.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/selectingmetadatasets.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/selectingmetadatasets.htm	(revision 10506)
@@ -0,0 +1,74 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="selectingmetadatasets"><font size="5" face="Verdana"><strong>5.2: ÐÑÐ±ÐŸÑ ÐœÐ°Ð±ÐŸÑÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐ»ÐµÐŒÐµÐœÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ðž ÐºÐ°Ðº ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ðº ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Ð§ÑÐŸ ÑÐ°ÐºÐŸÐµ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+?
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    ÐÑÐ±ÑÐ°Ðœ ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð£ÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐžÐ·Ð²ÐµÑÑÐœÐ° ÐºÐ°Ðº "ÐœÐ°Ð±ÐŸÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+". ÐÑÐžÐŒÐµÑÐŸÐŒ ÑÐ²Ð»ÑÐµÑÑÑ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Dublin Core. ÐÐŸÐ³ÐŽÐ° ÐÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÐµÑÐµ ÐºÐŸÐŒÐ¿Ð»ÐµÐºÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ðº ÐÐ°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÑÐŸ ÐµÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÑ ÑÑÐ°ÐœÐŸÐ²ÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž ÐŽÐ»Ñ Ð²ÑÐ±ÐŸÑÐ°. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÐŒÐµÑÑ Ð±ÐŸÐ»ÑÑÐµ,ÑÐµÐŒ ÐŸÐŽÐžÐœ ÐœÐ°Ð±ÐŸÑ. ÐÐ»Ñ Ð¿ÑÐµÐŽÐŸÑÐ²ÑÐ°ÑÐµÐœÐžÑ ÑÑÐŸÐ»ÐºÐœÐŸÐ²ÐµÐœÐžÑ ÐŸÐŽÐžÐœÐ°ÐºÐŸÐ²ÑÑ
+ ÐžÐŒÑÐœ Ðº ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ ÑÐ»ÐµÐŒÐµÐœÑÐ° Ð¿ÑÐžÑÐŸÐµÐŽÐžÐœÑÐµÑÑÑ ÐºÐŸÑÐŸÑÐºÐžÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ,ÐºÐŸÑÐŸÑÑÐ¹ Ð²ÑÐŽÐµÐ»ÑÐµÑ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐ»ÐµÐŒÐµÐœÑ Dublin Core "Creator" ÑÑÐ°ÐœÐµÑ "dc.Creator".ÐÐ°Ð±ÐŸÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ñ
+ÑÐ°ÐœÑÑÑÑ Ð² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° Ðž ÐžÐŒÐµÑÑ ÑÑÑÑÐžÐºÑ ".mds".
+<p></p>
+Ð§ÑÐŸÐ±Ñ ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÐŸÐ²Ð°ÑÑ ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÑ
+ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ð²ÑÐ±ÐµÑÐžÑÐµ "ÐÐ°Ð±ÐŸÑ ÐÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+" Ð² Ð¿ÑÐŸÑÐŒÐŸÑÑÐµ "ÐÐžÐ·Ð°Ð¹Ðœ".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/startingoff.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/startingoff.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/startingoff.htm	(revision 10506)
@@ -0,0 +1,19 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="startingoff"><font size="5" face="Verdana"><strong>2: ÐÐŸ ÑÑÐ°ÑÑÐ°</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+    
+    Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÑÐ°ÑÑÐºÐ°Ð·Ð°ÐœÐŸ, ÐºÐ°Ðº ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÑÑ, Ð·Ð°Ð³ÑÑÐ¶Ð°ÑÑ Ðž ÑÐŽÐ°Ð»ÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+    
+    
+    
+    
+  </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/thecreateview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/thecreateview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/thecreateview.htm	(revision 10506)
@@ -0,0 +1,72 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thecreateview"><font size="5" face="Verdana"><strong>7.1: Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ,ÐºÐ°Ðº ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. 
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+	  </td>
+</tr>
+	  
+<tr>
+<td colspan="1"> </td><td colspan="2">
+	    ÐÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÑÐ¹ Ð¿ÑÐŸÑÐŒÐŸÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+	  </td>
+</tr>
+	
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð ÐµÐ³ÐžÑÑÑÐ°ÑÐžÑ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐ¹
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ,ÑÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ,Ð²ÑÐ¿ÐŸÐ»ÐœÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÐµ ÑÑÐµÐœÐ°ÑÐžÐž Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Greenstone ÐžÐ· ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž, ÐºÐŸÑÐŸÑÑÑ ÐÑ Ð¿ÐŸÐŽÐ³ÐŸÑÐŸÐ²ÐžÐ»Ðž. Ð©ÐµÐ»ÑÐŸÐº ÐœÐ° "ÐÐŸÑÑÑÐŸÐµÐœÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž" ÐœÐ°ÑÐžÐœÐ°ÐµÑ Ð¿ÑÐŸÑÐµÑÑ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑÐµÐŒÑ, ÐºÐŸÑÐŸÑÐŸÐµ ÐŽÐ»Ñ ÑÑÐŸÐ³ÐŸ Ð¿ÐŸÑÑÐµÐ±ÑÐµÑÑÑ, Ð·Ð°Ð²ÐžÑÐžÑ ÐŸÑ ÑÐ°Ð·ÐŒÐµÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž ÑÐžÑÐ»Ð° ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÐµÐŒÑÑ
+ ÐžÐœÐŽÐµÐºÑÐŸÐ² (ÐŽÐ»Ñ ÐŸÐ³ÑÐŸÐŒÐœÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÑÑÐŸ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐ°ÑÑ). ÐÐœÐŽÐžÐºÐ°ÑÐŸÑ Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐžÑ ÑÐºÐ°Ð·ÑÐ²Ð°ÐµÑ, ÐœÐ°ÑÐºÐŸÐ»ÑÐºÐŸ Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœ Ð¿ÑÐŸÑÐµÑÑ. Ð§ÑÐŸÐ±Ñ ÐŸÑÐŒÐµÐœÐžÑÑ Ð¿ÑÐŸÑÐµÑÑ Ð² Ð»ÑÐ±ÐŸÐµ Ð²ÑÐµÐŒÑ, ÐœÐ°Ð¶ÐŒÐžÑÐµ "ÐÑÐŒÐµÐœÐ° Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ".
+      <p></p>
+      ÐÐ°Ð¶Ð°Ð² ÐœÐ° "ÐÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÑÐ¹ Ð¿ÑÐŸÑÐŒÐŸÑÑ" Ð¿ÐŸÑÐ»Ðµ ÑÐŸÐ³ÐŸ, ÐºÐ°Ðº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±ÑÐ»Ð° ÑÑÐ¿ÐµÑÐœÐŸ ÑÐŸÐ±ÑÐ°ÐœÐ°, ÐŒÐŸÐ¶ÐœÐŸ ÐŸÑÐºÑÑÑÑ Ð²ÐµÐ±-Ð±ÑÐ°ÑÐ·ÐµÑ Ñ Ð³Ð»Ð°Ð²ÐœÐŸÐ¹ ÑÑÑÐ°ÐœÐžÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+      Ð ÐŒÐŸÐŽÑÑÐµ Ð­ÐºÑÐ¿ÐµÑÑ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð·Ð°Ð¿ÐžÑÑ "ÐÐŸÐ³ Ð¡ÐŸÐŸÐ±ÑÐµÐœÐžÐ¹" ÑÐ»ÐµÐ²Ð°, ÑÑÐŸÐ±Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ, Ð±ÑÐ»Ðž Ð»Ðž Ð¿ÑÐµÐŽÑÐŽÑÑÐžÐµ Ð¿ÐŸÐ¿ÑÑÐºÐž ÑÐºÐŸÐœÑÑÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÑÐ¿ÐµÑÐœÑ ÐžÐ»Ðž ÐœÐµÑ. ÐÑÐ±ÐµÑÐžÑÐµ Ð¶ÐµÐ»Ð°ÐµÐŒÑÑ Ð·Ð°Ð¿ÐžÑÑ,ÑÐµÐ»ÐºÐ°Ñ Ð¿ÐŸ Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐ¹ ÐŽÐ°ÑÐµ Ð² ÑÐ¿ÐžÑÐºÐµ "ÐÑÑÐŸÑÐžÑ Ð·Ð°Ð¿ÐžÑÐž".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/thedesignview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/thedesignview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/thedesignview.htm	(revision 10506)
@@ -0,0 +1,55 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thedesignview"><font size="5" face="Verdana"><strong>6.1: ÐÐžÐŽ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» Ð²Ð²ÐŸÐŽÐžÑ ÐÐ°Ñ Ð² ÑÐ°ÑÑÐŒÐ°ÑÑÐžÐ²Ð°ÐµÐŒÑÐ¹ Ð¿ÑÐŸÐµÐºÑ Ðž ÐŸÐ±ÑÑÑÐœÑÐµÑ,ÐºÐ°Ðº Ð²ÑÐ±ÑÐ°ÑÑ ÐŒÐµÐ¶ÐŽÑ ÑÐ°Ð·Ð»ÐžÑÐœÑÐŒÐž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑÐŒÐž Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ Ð°ÐºÑÐžÐ²ÐœÐŸÐ¹ ÑÐ°ÑÑÐž ÐŸÐºÐœÐ°.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÑÐ±ÐŸÑ ÑÐ°Ð·ÐŽÐµÐ»Ð° Ð¿ÑÐŸÐµÐºÑÐ°
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÑÐž Ð¿ÐŸÐŒÐŸÑÐž ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ³ÐŸ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÑÑ Ð²ÐžÐŽÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÑÐµÐŒÐŸÐ¹ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ.ÐÐ°ÑÐžÐ°ÐœÑÑ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÑ ÐœÐ° ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ ÑÐ°Ð·ÐŽÐµÐ»Ñ, ÐºÐ°Ð¶ÐŽÑÐ¹ ÐžÐ· ÐºÐŸÑÐŸÑÑÑ
+ ÑÐ²ÑÐ·Ð°Ðœ ÑÐŸ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐŸÐ¹ ÑÑÐ°ÐŽÐžÐµÐ¹ ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÐž ÐžÐ»Ðž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž.
+<p></p>
+ Ð¡Ð»ÐµÐ²Ð° ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ ÑÐ¿ÐžÑÐŸÐº ÑÐ°Ð·Ð»ÐžÑÐœÑÑ
+ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐ¹,Ð° ÑÐ¿ÑÐ°Ð²Ð° - ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐµÐºÑÑÐžÐŒ ÑÐ¿ÐžÑÐºÐŸÐŒ.Ð§ÑÐŸÐ±Ñ Ð¿ÐµÑÐµÐ¹ÑÐž ÐœÐ° Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ,ÑÐµÐ»ÐºÐœÐžÑÐµ ÐµÐ³ÐŸ ÐžÐŒÑ Ð² ÑÐ¿ÐžÑÐºÐµ. 
+<p></p>
+ Ð§ÑÐŸÐ±Ñ Ð¿ÐŸÐœÐžÐŒÐ°ÑÑ ÑÑÐ°ÐŽÐžÐž Ðž ÑÐµÑÐŒÐžÐœÑ,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÐµ Ð¿ÑÐž Ð¿ÑÐŸÐµÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÑÐœÐ°ÑÐ°Ð»Ð° Ð¿ÑÐŸÑÑÐžÑÐµ Ð³Ð»Ð°Ð²Ñ 1 Ðž 2 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone. 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/theenrichview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/theenrichview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/theenrichview.htm	(revision 10506)
@@ -0,0 +1,113 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="theenrichview"><font size="5" face="Verdana"><strong>5.1: ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐŸÐ±ÐŸÐ³Ð°ÑÐµÐœÐžÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+T Ð ÑÑÐŸÐž ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ, ÐºÐ°Ðº Ð²Ð²ÐŸÐŽÐžÑÑ Ðž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐŸÐ±ÐŸÐ³Ð°ÑÐµÐœÐžÑ.
+
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐµÑÐµÐ²ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐŸÐœÑÑÐŸÐ»Ñ ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐœÐžÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐµÑÐµÐ²ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð¢Ð°Ð±Ð»ÐžÑÐ° ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐŸÐ±ÐŸÐ³Ð°ÑÐµÐœÐžÑ ÐŽÐ»Ñ Ð·Ð°ÐŽÐ°ÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. 
+MeÑÐ°ÐŽÐ°ÐœÐœÑÐµ - ÑÑÐŸ ÐŽÐ°ÐœÐœÑÐµ ÐŸ ÐŽÐ°ÐœÐœÑÑ
+ - ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ,ÐÐ²ÑÐŸÑ,ÐÐ°ÑÐ° ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ Ðž Ñ.ÐŽ. ÐÐ°Ð¶ÐŽÑÐ¹ Ð¿ÑÐœÐºÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÑÐŸÑÑÐŸÐžÑ ÐžÐ· ÐŽÐ²ÑÑ
+ ÑÐ°ÑÑÐµÐ¹: "ÑÐ»ÐµÐŒÐµÐœÑ"- Ðº ÐºÐ°ÐºÐŸÐŒÑ ÑÐžÐ¿Ñ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÐŸÐœ ÐŸÑÐœÐŸÑÐžÑÑÑ (Ðº Ð¿ÑÐžÐŒÐµÑÑ,ÐÐ²ÑÐŸÑ),Ðž "Ð·ÐœÐ°ÑÐµÐœÐžÐµ"- ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÑÐŸÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,Ð² ÐºÐŸÑÐŸÑÑÑ
+ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐŽÐ»Ñ Ð»ÑÐ±ÑÑ
+ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÐžÐ»Ðž Ð¿Ð°Ð¿ÐŸÐº Ð² ÐÐµÑÐµÐ²Ðµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð¡ÑÐŸÐ»Ð±ÑÑ ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÑ ÑÐµÑÑÐŒ ÑÐ²ÐµÑÐŸÐŒ Ð²Ð²ÐµÑÑ
+Ñ Ðž ÐžÑ
+ ÑÐ°Ð·ÐŒÐµÑ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐžÐ·ÐŒÐµÐœÑÐœ Ð¿ÑÑÑÐŒ Ð¿ÐµÑÐµÐŽÐ²ÐžÐ¶ÐµÐœÐžÑ Ð»ÐžÐœÐžÐž ÑÐ°Ð·ÐŽÐµÐ»Ð°. Ð©ÐµÐ»ÑÐŸÐº ÐœÐ° Ð»ÑÐ±ÐŸÐ¹ ÑÑÑÐŸÐºÐµ Ð¿ÐµÑÐµÐœÐŸÑÐžÑ ÐµÑ ÐŽÐµÑÐ°Ð»Ðž Ð²ÐœÐžÐ· ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐ°Ð¶Ð°Ð² ÐœÐ° Ð»ÑÐ±ÐŸÐ¹ ÑÑÐŽ Ð² ÑÐ°Ð±Ð»ÐžÑÐµ, Ð²Ñ ÑÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ Ðž ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐŽÐµÑÐ°Ð»Ðž ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ Ð² ÐœÐžÐ¶ÐœÐµÐ¹ ÑÐµÐºÑÐžÐž ÐŸÐºÐœÐ°. Ð§ÐµÑÐœÑÐ¹ ÑÐµÐºÑÑ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ, ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÐŸÐ±ÑÐžÐŒ ÐŽÐ»Ñ Ð²ÑÐµÑ
+ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ²,ÑÐŸÐ³ÐŽÐ° ÐºÐ°Ðº ÑÐµÑÑÐ¹ ÑÐµÐºÑÑ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ,ÑÑÐŸ ÑÑÐŸ - ÐœÐµ ÑÐ°Ðº.Ð§ÐµÑÐœÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÑ ÐžÐ»Ðž ÑÐŽÐ°Ð»ÐµÐœÑ, Ð² ÑÐŸ Ð²ÑÐµÐŒÑ ÐºÐ°Ðº ÑÐµÑÑÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐŽÐ°Ð»ÐµÐœÑ ÐžÐ· ÑÐµÑ
+,ÐºÐŸÑÐŸÑÑÐµ ÐžÐŒÐµÑÑ ÐžÑ
+,ÐžÐ»Ðž ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÑ Ðº ÐŽÑÑÐ³ÐžÐŒ.  
+ <p></p>
+ ÐÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ Ð¿Ð°Ð¿ÐºÐž ÐŒÐŸÐ¶ÐµÑ Ð¿ÐŸÑÐ²Ð»ÑÑÑÑÑ ÐŸÐºÐŸÐ»ÐŸ ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ Ð²Ñ
+ÐŸÐŽÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.Ð­ÑÐŸ ÑÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐœÐ° ÑÐŸ,ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÑÐœÐ°ÑÐ»ÐµÐŽÐŸÐ²Ð°ÐœÑ ÐŸÑ Ð¿Ð°Ð¿ÐŸÐº ÑÐŸÐŽÐžÑÐµÐ»ÐµÐ¹ (ÐžÐ»Ðž Ð¿ÑÐµÐŽÐºÐŸÐ²). Ð£ÐœÐ°ÑÐ»ÐµÐŽÐŸÐ²Ð°ÐœÐœÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐœÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÑ ÐžÐ»Ðž ÑÐŽÐ°Ð»ÐµÐœÑ, Ð° ÑÐŸÐ»ÑÐºÐŸ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÑ Ð² ÐºÐŸÐœÐµÑ ÑÐ¿ÐžÑÐºÐ° ÐžÐ»Ðž Ð¿ÐµÑÐµÐ¿ÐžÑÐ°ÐœÑ.Ð©ÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐž Ð¿Ð°Ð¿ÐºÐž,ÑÑÐŸÐ±Ñ ÐœÐµÐŒÐµÐŽÐ»ÐµÐœÐœÐŸ Ð¿ÐµÑÐµÐ¹ÑÐž Ð² ÑÑ Ð¿Ð°Ð¿ÐºÑ, Ð³ÐŽÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð·Ð°ÐŽÐ°ÐœÑ.  
+<p></p>
+ÐÐŸÐœÑÑÐŸÐ»Ñ ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐœÐžÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ Ð²ÐœÐžÐ·Ñ ÑÐ¿ÑÐ°Ð²Ð° Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐµÑÐ»Ðž ÑÐ°Ð¹Ð» Ð²ÑÐ±ÑÐ°Ðœ ÐžÐ· ÐŽÐµÑÐµÐ²Ð°, Ð° ÑÑÐŽ Ð² ÑÐ°Ð±Ð»ÐžÑÐµ. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐžÑ
+, ÑÑÐŸÐ±Ñ ÐŸÐ±ÐœÐŸÐ²ÐžÑÑ, ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ Ð² ÐºÐŸÐœÐµÑ ÐžÐ»Ðž ÑÐŽÐ°Ð»ÐžÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÐŸÐ»Ñ Ð¿ÑÐµÐŽÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐŸ ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ, ÑÑÐŸÐ±Ñ Ð²Ð²ÐµÑÑÐž ÐžÐ»Ðž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐºÐŸÐ»ÐŸ ÐœÐµÐ³ÐŸ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐœÐ°Ñ ÐºÐœÐŸÐ¿ÐºÐ°, ÐºÐŸÑÐŸÑÐ°Ñ Ð¿ÑÐž ÑÐµÐ»ÑÐºÐµ ÐŸÑÐºÑÑÐ²Ð°ÐµÑ Ð±ÐŸÐ»ÑÑÐµÐµ Ð¿ÐŸÐ»Ðµ ÐŽÐ»Ñ ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÑ. Ð Ð°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐœÐ°Ñ ÐœÐžÐ¶Ðµ ÐºÐœÐŸÐ¿ÐºÐ° "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð² ÐºÐŸÐœÐµÑ" Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ðž ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐžÑ
+ Ðº ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐŒ Ð·ÐœÐ°ÑÐµÐœÐžÑÐŒ ÐŽÐ»Ñ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐ°. ÐÐœÐŸÐ¿ÐºÐ° "ÐÐ°ÐŒÐµÐœÐžÑÑ" Ð¿ÑÐžÐŒÐµÐœÑÐµÑ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ðº ÐœÐŸÐ²ÑÐŒ, Ð° "Ð£ÐŽÐ°Ð»ÐžÑÑ" ÑÑÐžÑÐ°ÐµÑ Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ.ÐÐœÐžÐ·Ñ Ð¿ÑÐœÐºÑÐ°,ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐœÐŸÐ³ÐŸ ÐºÐ°Ðº "ÐÑÐµ Ð¿ÑÐµÐŽÑÐŽÑÑÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ", ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ "ÐÐµÑÐµÐ²ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹".  
+<p></p> 
+ ÐÐµÑÐµÐ²ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ ÐŒÐŸÐ¶ÐµÑ ÑÐ°ÑÑÐžÑÑÑÑÑÑ Ðž ÑÐ°Ð·ÑÑÑÐ°ÑÑÑÑ. ÐÐ±ÑÑÐœÐŸ ÑÑÐŸ - ÑÐ¿ÐžÑÐŸÐº, ÐºÐŸÑÐŸÑÑÐ¹ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð²ÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ, Ð²Ð²ÐµÐŽÐµÐœÐœÑÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ ÐŽÐ»Ñ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ ÑÐ»ÐµÐŒÐµÐœÑÐ°. Ð©ÐµÐ»ÑÐŸÐº ÐœÐ° Ð²Ñ
+ÐŸÐŽÐµ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž ÑÐ°Ð·ÐŒÐµÑÐ°ÐµÑ ÐµÐ³ÐŸ Ð² Ð¿ÐŸÐ»Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹. Ð¡ ÐŽÑÑÐ³ÐŸÐ¹ ÑÑÐŸÑÐŸÐœÑ,Ð¿ÑÐž ÐœÐ°Ð¿ÐµÑÐ°ÑÐ°ÐœÐœÐŸÐŒ Ð·ÐœÐ°ÑÐµÐœÐžÐž Ð² ÑÐµÐºÑÑÐŸÐ²ÐŸÐŒ Ð¿ÐŸÐ»Ðµ Ð²ÑÐ±ÐŸÑÐºÐž ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÐÐµÑÐµÐ²Ð° Ð·ÐœÐ°ÑÐµÐœÐžÐ¹, ÑÐžÑÑÐµÐŒÐ° ÐœÐ°ÑÐžÐœÐ°ÐµÑ ÑÐ°Ð±ÐŸÑÑ Ñ ÑÐžÐŒÐ²ÐŸÐ»ÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐÑ Ð²Ð²ÐµÐ»Ðž. ÐÐ°Ð¶Ð°ÑÐžÐµ [Tab] Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž Ð·Ð°Ð²ÐµÑÑÐ°ÐµÑ Ð¿ÐµÑÐ°ÑÐ°ÐœÐžÐµ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÐŸÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ.
+ <p></p>
+ÐÐœÐ°ÑÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐŸÑÐ³Ð°ÐœÐžÐ·ÐŸÐ²Ð°ÐœÑ Ð² ÐžÐµÑÐ°ÑÑ
+ÐžÑ. Ð­ÑÐŸ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÐŸ Ð² ÐÐµÑÐµÐ²Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð¿Ð°Ð¿ÐºÐž ÐŽÐ»Ñ Ð²ÐœÑÑÑÐµÐœÐœÐžÑ
+ ÑÑÐŸÐ²ÐœÐµÐ¹. ÐÐµÑÐ°ÑÑ
+ÐžÑÐµÑÐºÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ Ð²Ð²ÐµÐŽÐµÐœÑ,ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð·ÐœÐ°Ðº "|" ÐŽÐ»Ñ ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐžÑ ÑÑÐŸÐ²ÐœÐµÐ¹. ÐÐ°Ð¿ÑÐžÐŒÐµÑ,"Cards|Red|Diamonds|Seven" ÐŒÐŸÐ³ Ð±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ Ð² ÐžÐµÑÐ°ÑÑ
+ÐžÐž, Ð¿ÑÐžÐŒÐµÑÐŸÐŒ ÐºÐŸÑÐŸÑÐŸÐ¹ ÑÐ²Ð»ÑÐµÑÑÑ Ð¿Ð°ÐºÐµÑ ÐžÐ³ÑÑ Ð² ÐºÐ°ÑÑÑ.Ð­ÑÐŸ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð³ÑÑÐ¿Ð¿ÐžÑÐŸÐ²Ð°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ Ð²ÐŒÐµÑÑÐµ. ÐÑÑÐ¿Ð¿Ñ ÐŒÐŸÐ³ÑÑ ÑÐ°ÐºÐ¶Ðµ ÐœÐ°Ð·ÐœÐ°ÑÐ°ÑÑÑÑ ÐºÐ°Ðº ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðº ÑÐ°Ð¹Ð»Ð°ÐŒ.  
+<p></p> 
+ Greenstone Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž ÐžÐ·Ð²Ð»ÐµÐºÐ°ÐµÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÐ· ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Ð² ÐœÐ°Ð±ÐŸÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÑÐ»ÐµÐŒÐµÐœÑÑ ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ ÐžÐŒÐµÑÑ Ð¿ÑÐµÑÐžÐºÑ "ex.". Ð­ÑÐŸ ÐœÐµ ÐžÐŒÐµÐµÑ ÐœÐžÐºÐ°ÐºÐŸÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŽÐµÑÐµÐ²Ð° Ðž ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐŸ,Ð¿ÐŸÑÐŸÐŒÑ ÑÑÐŸ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµÐŒ ÑÐºÑÑÑÐŸ,ÐµÑÐ»Ðž ÑÐ°ÐºÐŸÐ¹ ÑÐžÐ¿ Ð²Ð²ÐŸÐŽÐ° Ð²ÑÐ±ÑÐ°Ðœ.ÐÐœÐŸÐ¿ÐºÐ° "..." Ð²ÑÑ ÐµÑÑ ÑÐ»ÑÐ¶ÐžÑ ÐŽÐ»Ñ ÑÐ°ÑÑÐžÑÐµÐœÐžÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ,ÐœÐŸ ÑÐµÐºÑÑ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°Ðœ. 
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/thegatherview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/thegatherview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/thegatherview.htm	(revision 10506)
@@ -0,0 +1,119 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="thegatherview"><font size="5" face="Verdana"><strong>4.1: ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐœÐ°ÐºÐŸÐ¿ÐžÑÐµÐ»Ñ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð­ÑÐŸÑ ÑÐ°Ð·ÐŽÐµÐ» Ð²Ð²ÐŸÐŽÐžÑ Ð² ÐŸÐ±Ð»Ð°ÑÑÑ ÐœÐ°ÐºÐŸÐ¿Ð»ÐµÐœÐžÑ,ÐºÐŸÑÐŸÑÑÑ ÐÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÐµ,ÑÑÐŸÐ±Ñ Ð²ÑÐ±ÑÐ°ÑÑ,ÐºÐ°ÐºÐžÐµ ÑÐ°Ð¹Ð»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð² ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÐµÐŒÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÐ°Ðº Ð¿ÑÐŸÑÐŒÐ°ÑÑÐžÐ²Ð°ÑÑ ÑÐºÑÐ°Ðœ ÐœÐ°ÐºÐŸÐ¿Ð»ÐµÐœÐžÑ 
+            </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð€Ð°Ð¹Ð»ÐŸÐ²ÐŸÐµ ÐŽÐµÑÐµÐ²ÐŸ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ±Ð»Ð°ÑÑÑ ÑÐŸÑÑÐŸÑÐœÐžÑ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐœÐŸÐ¿ÐºÐž ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ
+          </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐµÑÐŸÐŽÑ ÐŸÑÐ±ÐŸÑÐ°
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð¡Ð¿ÐµÑÐžÐ°Ð»ÑÐœÐ°Ñ Ð¿Ð°Ð¿ÐºÐ° ÐŸÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐœÐ°ÑÐžÐœÐ°ÐµÑÑÑ Ñ ÐŸÐ±Ð·ÐŸÑÐ° ÐœÐ°ÐºÐŸÐ¿Ð»ÐµÐœÐžÑ. Ð§ÑÐŸÐ±Ñ Ð²ÐµÑÐœÑÑÑÑÑ Ðº ÑÑÐŸÐŒÑ ÐŸÐ±Ð·ÐŸÑÑ Ð¿ÐŸÐ·Ð¶Ðµ,ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÑÐžÐŒÐ²ÐŸÐ»Ðµ "Gather", ÑÐ°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐœÑÐŒ ÐœÐµÐ¿ÐŸÑÑÐµÐŽÑÑÐ²ÐµÐœÐœÐŸ ÐœÐžÐ¶Ðµ Ð»ÐžÐœÐµÐ¹ÐºÐž ÐŒÐµÐœÑ.  
+<p></p>
+ÐÐ²Ðµ Ð±ÐŸÐ»ÑÑÐžÐµ ÐŸÐ±Ð»Ð°ÑÑÐž,ÐœÐ°Ð·Ð²Ð°ÐœÐœÑÐµ "Ð Ð°Ð±ÐŸÑÐµÐµ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²ÐŸ" Ðž "ÐoÐ»Ð»ÐµÐºÑÐžÑ" ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ,ÑÑÐŸÐ±Ñ Ð¿ÐµÑÐµÐŒÐµÑÑÐžÑÑ ÑÐ°Ð¹Ð»Ñ Ð² ÐÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ. ÐÐœÐž Ð²ÐºÐ»ÑÑÐ°ÑÑ "ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐµ ÐŽÐµÑÐµÐ²ÐŸ",Ð³ÑÐ°ÑÐžÑÐµÑÐºÐžÐµ ÑÑÑÑÐºÑÑÑÑ,ÐºÐŸÑÐŸÑÑÐµ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶Ð°ÑÑ ÑÐ°Ð¹Ð»Ñ Ðž Ð¿Ð°Ð¿ÐºÐž. 
+<p></p>
+ÐÑÐ±ÐµÑÐžÑÐµ ÑÐ»ÐµÐŒÐµÐœÑ ÐŽÐµÑÐµÐ²Ð°, ÐœÐ°Ð¶Ð°Ð² ÐœÐ° ÐœÐµÐ³ÐŸ Ð»ÐµÐ²ÐŸÐ¹ ÐºÐ»Ð°Ð²ÐžÑÐµÐ¹ ÐŒÑÑÐž. (Ð¢ÐŸ Ð¶Ðµ ÑÐ°ÐŒÐŸÐµ ÐŒÐŸÐ¶ÐœÐŸ ÑÐŽÐµÐ»Ð°ÑÑ ÐžÐœÐ°ÑÐµ, ÑÐŒ. ÐœÐžÐ¶Ðµ). ÐÐ²ÐŸÐ¹ÐœÑÐŒ ÑÐµÐ»ÑÐºÐŸÐŒ Ð²ÑÐ±ÐµÑÐžÑÐµ Ð¿Ð°Ð¿ÐºÑ, ÐžÐ»Ðž ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° ÑÐžÐŒÐ²ÐŸÐ» ÑÑÐŽÐŸÐŒ Ñ ÐœÐµÐ¹, ÑÑÐŸÐ±Ñ ÑÐ°Ð·Ð²ÐµÑÐœÑÑÑ (ÐžÐ»Ðž ÑÐ²ÐµÑÐœÑÑÑ) ÐµÐµ ÑÐŸÐŽÐµÑÐ¶ÐžÐŒÐŸÐµ. ÐÐ²ÐŸÐ¹ÐœÑÐŒ ÑÐµÐ»ÑÐºÐŸÐŒ ÐœÐ° ÐœÑÐ¶ÐœÐŸÐŒ ÑÐ°Ð¹Ð»Ðµ ÐŸÑÐºÑÐŸÐ¹ÑÐµ ÐµÐ³ÐŸ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÐŸÐ¹ ÐŽÐ°ÐœÐœÐŸÐŒÑ ÑÐžÐ¿Ñ ÑÐ°Ð¹Ð»ÐŸÐ² Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ (ÑÐŒ.<a href="fileassociations.htm#fileassociations">ÐÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÐµ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ</a>).
+<p></p>
+ÐÐµÑÐµÐ²ÐŸ ÑÐ°Ð±ÐŸÑÐµÐ³ÐŸ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ð° Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐžÑÑÐŸÑÐœÐžÐºÐž ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐŸÑÑÑÐ¿ÐœÑÑ
+ Ð² ÐÐœÑÐµÑÑÐµÐ¹ÑÐµ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°ÑÑ -- ÑÐµÐºÑÑÑÑ ÑÐ°Ð¹Ð»ÐŸÐ²ÑÑ ÑÐžÑÑÐµÐŒÑ (Ð²ÐºÐ»ÑÑÐ°Ñ ÐŽÐžÑÐºÐŸÐ²ÐŸÐŽ Ðž CD-ROM), ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÐÑÐžÐœÑÑÐŸÑÐœ, Ðž ÐºÑÑ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ², Ð¿ÑÐž ÑÑÐ»ÐŸÐ²ÐžÐž Ð²ÐºÐ»ÑÑÐµÐœÐžÑ Ð²ÐµÐ± Ð·ÐµÑÐºÐ°Ð»ÐžÑÐŸÐ²Ð°ÐœÐžÑ. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÐžÐŽÐµÑÑ Ðž ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÑÑ ÑÑÐž ÑÐ°Ð¹Ð»Ñ, ÐŸÐŽÐœÐ°ÐºÐŸ ÐœÐµ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐµÑÐµÐœÐŸÑÐžÑÑ, ÑÐŽÐ°Ð»ÑÑÑ, ÐžÐ»Ðž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÐžÑ
+, Ð·Ð° ÐžÑÐºÐ»ÑÑÐµÐœÐžÐµÐŒ ÑÐ¶Ðµ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐŽÐ°Ð»ÐµÐœÑ.  ÐÑÑÑÐµÑÑÐ²Ð»ÑÑÑ ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÑ Ð² ÑÑÐŸÐŒ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ðµ ÑÑÐŸÐ±Ñ ÐœÐ°Ð¹ÑÐž ÑÐ°Ð¹Ð»Ñ ÐºÐŸÑÐŸÑÑÐµ Ð²Ñ Ñ
+ÐŸÑÐžÑÐµ Ð²ÐºÐ»ÑÑÐžÑÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+<p></p>
+Ð€Ð°Ð¹Ð»ÐŸÐ²ÐŸÐµ ÐŽÐµÑÐµÐ²ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÑÐµÑ Ð¿ÐŸÐ»ÐœÐŸÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐµÑÐ²ÐŸÐœÐ°ÑÐ°Ð»ÑÐœÐŸ ÐŸÐœÐŸ Ð¿ÑÑÑÐŸ.
+<p></p>
+ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÑÐ°Ð·ÐŒÐµÑÑ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ð°, Ð¿ÐµÑÐµÐŽÐ²ÐžÐ³Ð°Ñ ÐŒÑÑÑ Ð¿ÐŸ ÑÐµÑÐŸÐ¹ Ð»ÐžÐœÐµÐ¹ÐºÐµ, ÐºÐŸÑÐŸÑÐ°Ñ ÐŸÑÐŽÐµÐ»ÑÐµÑ ÐŽÐµÑÐµÐ²ÑÑ (ÑÐŸÑÐŒÐ° ÑÐºÐ°Ð·Ð°ÑÐµÐ»Ñ ÐžÐ·ÐŒÐµÐœÑÐµÑÑÑ),Ðž Ð±ÑÐºÑÐžÑÑÑ ÐžÑ
+.
+<p></p>
+ÐÐœÐžÐ·Ñ ÐŸÐºÐœÐ° ÑÐ°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐ° ÑÑÐ°ÑÑÑÐœÐ°Ñ ÐŸÐ±Ð»Ð°ÑÑÑ, ÐºÐŸÑÐŸÑÐ°Ñ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð¿ÑÐŸÐ³ÑÐµÑÑ ÐŸÐ¿ÐµÑÐ°ÑÐžÐ¹ ÐœÐ°ÐŽ ÑÐ°Ð¹Ð»Ð°ÐŒÐž (ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÐµ, Ð¿ÐµÑÐµÐŒÐµÑÐµÐœÐžÐµ, ÑÐŽÐ°Ð»ÐµÐœÐžÐµ). ÐÐœÐž ÐŒÐŸÐ³ÑÑ Ð·Ð°ÐœÑÑÑ ÐºÐ°ÐºÐŸÐµ-ÑÐŸ Ð²ÑÐµÐŒÑ. ÐÐœÐŸÐ¿ÐºÐ° "Ð¡ÑÐŸÐ¿" ÐŸÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÐµÑ Ð»ÑÐ±ÐŸÐµ ÐŽÐµÐ¹ÑÑÐ²ÐžÐµ, ÐºÐŸÑÐŸÑÐŸÐµ Ð² ÐœÐ°ÑÑÐŸÑÑÐµÐµ Ð²ÑÐµÐŒÑ Ð¿ÑÐŸÐžÑÑ
+ÐŸÐŽÐžÑ. 
+<p></p>
+ ÐÐ²Ðµ Ð±ÐŸÐ»ÑÑÐžÐµ ÐºÐœÐŸÐ¿ÐºÐž Ð·Ð°ÐœÐžÐŒÐ°ÑÑ ÐœÐžÐ¶ÐœÐžÐ¹ Ð¿ÑÐ°Ð²ÑÐ¹ ÑÐ³ÐŸÐ» ÑÐºÑÐ°ÐœÐ°."ÐÐŸÐ²Ð°Ñ ÐÐ°Ð¿ÐºÐ°",Ñ ÐºÐ°ÑÑÐžÐœÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐž, ÑÐŸÐ·ÐŽÐ°ÑÑ ÐœÐŸÐ²ÑÐµ Ð¿Ð°Ð¿ÐºÐž (ÑÐŒ. <a href="creatingfolders.htm#creatingfolders">Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ Ð¿Ð°Ð¿ÐŸÐº</a>). ÐÐœÐŸÐ¿ÐºÐ° "Ð£ÐŽÐ°Ð»ÐžÑÑ"ÑÐŽÐ°Ð»ÑÐµÑ ÑÐ°Ð¹Ð»Ñ Ñ ÐœÐµÐœÑÐ¶ÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐµÐ¹.Ð©ÐµÐ»ÑÐŸÐº ÐœÐ° ÐºÐœÐŸÐ¿ÐºÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ" ÑÐŽÐ°Ð»ÐžÑ Ð»ÑÐ±ÑÐµ ÐŸÑÐŸÐ±ÑÐ°ÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ³ÐŸ ÐŽÐµÑÐµÐ²Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐ»ÑÑÐµÑÐœÐ°ÑÐžÐ²ÐœÐŸ, ÑÐ°Ð¹Ð»Ñ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐŽÐ°Ð»ÐµÐœÑ Ð¿ÑÑÐµÐŒ Ð¿ÐµÑÐµÑÑÐ³ÐžÐ²Ð°ÐœÐžÑ ÐžÑ
+ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÑ "Ð£ÐŽÐ°Ð»ÐžÑÑ". 
+       <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð§ÑÐŸÐ±Ñ ÐŸÑÐŸÐ±ÑÐ°ÑÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ Ð¿ÐŸÑÐ»ÐµÐŽÐŸÐ²Ð°ÑÐµÐ»ÑÐœÑÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ²,Ð²ÑÐ±ÐµÑÐžÑÐµ Ð¿ÐµÑÐ²ÑÐ¹ Ðž Ð·Ð°ÑÐµÐŒ ÑÐŽÐµÑÐ¶ÐžÐ²Ð°Ñ [Shift],ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° Ð¿ÐŸÑÐ»ÐµÐŽÐœÐµÐŒ - Ð¿ÑÐž ÑÑÐŸÐŒ Ð±ÑÐŽÑÑ ÐŸÑÐŸÐ±ÑÐ°ÐœÑ Ð²ÑÐµ ÐŸÑ
+Ð²Ð°ÑÐµÐœÐœÑÐµ ÑÐ»ÐµÐŒÐµÐœÑÑ.ÐÑÐ±ÐŸÑ ÐœÐµ ÑÐ»ÐµÐŽÑÑÑÐžÑ
+ ÐŸÐŽÐžÐœ Ð·Ð° ÐŽÑÑÐ³ÐžÐŒ ÑÐ°Ð¹Ð»ÐŸÐ² Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑÑÑ Ð¿ÑÐž ÐœÐ°Ð¶Ð°ÑÐŸÐ¹ ÐºÐ»Ð°Ð²ÐžÑÐµ [Ctrl] Ðž ÑÐµÐ»ÑÐºÐµ ÐœÐ° Ð²ÑÐ±ÐžÑÐ°ÐµÐŒÑÑ
+ ÑÐ°Ð¹Ð»Ð°Ñ
+. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÑÑÐž ÐŽÐ²Ð° ÐŒÐµÑÐŸÐŽÐ° Ð²ÐŒÐµÑÑÐµ ÐŽÐ»Ñ Ð³ÑÑÐ¿Ð¿Ñ ÐœÐµÑÐŒÐµÐ¶ÐœÑÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ².  
+<p></p>
+ ÐÐµÐºÐŸÑÐŸÑÑÐµ Ð¿Ð°Ð¿ÐºÐž - ÑÐžÐ¿Ð° ÑÐµÑ
+,ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ ÐÐ°ÑÐž ÑÐŸÐ±ÑÑÐ²ÐµÐœÐœÑÐµ Ð²ÐµÐ±-ÑÑÑÐ°ÐœÐžÑÑ - ÐžÐœÐŸÐ³ÐŽÐ° ÐžÐŒÐµÑÑ ÐŸÑÐŸÐ±ÑÑ Ð²Ð°Ð¶ÐœÐŸÑÑÑ.ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð¿ÐµÑÐµÐœÐµÑÑÐž ÑÐ°ÐºÐžÐµ Ð¿Ð°Ð¿ÐºÐž ÐœÐ° Ð¿ÐµÑÐ²ÑÐ¹ ÑÑÐŸÐ²ÐµÐœÑ ÑÐ°Ð¹Ð»ÐŸÐ²ÐŸÐ³ÐŸ ÐŽÐµÑÐµÐ²Ð°. Ð§ÑÐŸÐ±Ñ ÑÐŽÐµÐ»Ð°ÑÑ ÑÑÐŸ, ÑÐµÐ»ÐºÐœÐžÑÐµ Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐŸÐ¹ ÐŒÑÑÐž ÐœÐ° Ð¶ÐµÐ»Ð°ÑÐµÐ»ÑÐœÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐµ. ÐÑÐ±ÐµÑÐžÑÐµ "Ð¡ÐŸÐ·ÐŽÐ°ÑÑ ÑÐŸÐºÑÐ°ÑÐµÐœÐžÐµ" Ðž Ð²Ð²ÐµÐŽÐžÑÐµ ÐžÐŒÑ ÐŽÐ»Ñ Ð¿Ð°Ð¿ÐºÐž. ÐÐ»Ñ ÑÐŽÐ°Ð»ÐµÐœÐžÑ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÑÐµÐ»ÐºÐœÐžÑÐµ Ð¿ÑÐ°Ð²ÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐŸÐ¹ ÐŒÑÑÐž ÐœÐ° Ð¿ÐŸÐŒÐµÑÐµÐœÐœÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐµ Ðž Ð²ÑÐ±ÐµÑÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÐŸÐºÑÐ°ÑÐµÐœÐžÑ".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/themirrorview.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/themirrorview.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/themirrorview.htm	(revision 10506)
@@ -0,0 +1,89 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="themirrorview"><font size="5" face="Verdana"><strong>3.1: ÐÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐÐ°Ð³ÑÑÐ·ÐžÑÑ</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+      Ð­ÑÐ° ÑÐµÐºÑÐžÑ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑ ÐºÐ°Ðº ÐºÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÑÑ Ð·Ð°ÐŽÐ°ÑÑ Ðž ÐºÐŸÐœÑÑÐŸÐ»Ñ Ð¿ÑÐŸÑÐµÑÑÐ° Ð·Ð°Ð³ÑÑÐ·ÐºÐž.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+          ÐÐµÑÐµÐ²ÐŸ ÑÐ°Ð±ÐŸÑÐµÐ³ÐŸ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ð°
+	  </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+          ÐÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑ Ð·Ð°Ð³ÑÑÐ·ÐºÐž
+	  </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+          Ð¡Ð¿ÐžÑÐŸÐº Ð·Ð°Ð³ÑÑÐ·ÐºÐž
+	  </td>
+</tr>
+        
+        
+<tr>
+<td colspan="3"><a href="#advanced">Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+          Ð Ð°Ð·ÑÐµÑÐžÑÑ Ð¿ÑÐŸÐºÑÐž
+	  </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+      ÐÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐŸÑÐŒÐŸÑÑÑ "ÐÐ°Ð³ÑÑÐ·ÐžÑÑ" ÐœÐ°Ð¶Ð°ÑÐµÐŒ ÑÑÐŸÐ¹ Ð·Ð°ÐºÐ»Ð°ÐŽÐºÐž. ÐÐµÑÑ
+ÐœÑÑ Ð¿ÐŸÐ»ÐŸÐ²ÐžÐœÐ° ÑÐºÑÐ°ÐœÐ° Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐºÐŸÐœÑÑÐŸÐ»Ñ Ð·Ð°Ð³ÑÑÐ·ÐºÐž. ÐÐžÐ¶ÐœÑÑ Ð¿ÐŸÐ»ÐŸÐ²ÐžÐœÐ° Ð² ÐœÐ°ÑÐ°Ð»Ðµ Ð¿ÑÑÑÐ°, ÐŸÐŽÐœÐ°ÐºÐŸ Ð¿ÐŸÐºÐ°Ð¶ÐµÑ Ð¿ÐµÑÐµÑÐµÐœÑ ÐŸÐ¶ÐžÐŽÐ°ÐµÐŒÑÑ
+ Ðž Ð·Ð°ÐºÐŸÐœÑÐµÐœÐœÑÑ
+ Ð·Ð°Ð³ÑÑÐ·ÐŸÐº.
+      <p></p>
+      Ð€Ð°Ð¹Ð»Ñ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÑÐµ Ð² Ð¿Ð°Ð¿ÐºÑ ÑÐ°Ð±ÐŸÑÐµÐ³ÐŸ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²Ð° ÐœÐ°Ð·ÑÐ²Ð°ÑÑÑÑ "ÐÐ°Ð³ÑÑÐ¶Ð°ÐµÐŒÑÐµ ÑÐ°Ð¹Ð»Ñ" (ÑÐŸÐ»ÑÐºÐŸ ÑÐµÐ¹ÑÐ°Ñ ÐºÐŸÐ³ÐŽÐ° Ð·ÐµÑÐºÐ°Ð»ÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð²ÐºÐ»ÑÑÐµÐœÐŸ), Ðž ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐ° Ð²ÑÐµÐŒÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒÐž Ð¿ÐŸÑÑÑÐŸÐµÐœÐœÑÐŒÐž Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐÐœÑÐµÑÑÐµÐ¹ÑÐ° ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°ÑÑ. Ð€Ð°Ð¹Ð»Ñ Ð² ÑÑÐŸÐ¹ ÐŸÐ±Ð»Ð°ÑÑÐžÐžÐŒÐµÐœÑÑÑÑÑ Ð¿ÐŸ ÐžÑ
+ Ð¿ÐŸÐ»ÐœÐŸÐŒÑ URL Ð°ÐŽÑÐµÑÑ.  Ð¡ÐŸÐ·ÐŽÐ°ÐµÑÑÑ ÐœÐŸÐ²Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° ÐœÐ° ÐºÐ°Ð¶ÐŽÐŸÐŒ Ñ
+ÐŸÑÑÐµ, ÐœÐ°ÑÐ»ÐµÐŽÑÐµÐŒÐ°Ñ ÐŽÑÑÐ³ÐžÐŒÐž ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÑÑÐ°Ð³ÐŒÐµÐœÑÐ° Ð¿ÑÑÐž.  Ð­ÑÐŸ Ð³Ð°ÑÐ°ÐœÑÐžÑÑÐµÑ ÐŸÑÐ»ÐžÑÐžÐµ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð°.
+      <p></p>
+      ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ Ð¿ÐµÑÐ²ÑÐ¹ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÑÑ
+ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐ¹ Ð·Ð°Ð³ÑÑÐ·ÐŸÐº, "Source URL",  ÑÑÐŸÐ±Ñ Ð²Ð²ÐµÑÑÐž URL Ð°ÐŽÑÐµÑ Ð² ÑÐµÐ»ÐµÐ²ÐŸÐ¹ ÑÐµÑÑÑÑ. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐŸÐœÑÑÐŸÐ»Ñ "ÐÐ»ÑÐ±ÐžÐœÑ ÐÐ°Ð³ÑÑÐ·ÐºÐž" ÐŽÐ»Ñ ÐŸÐ³ÑÐ°ÐœÐžÑÐµÐœÐžÑ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²Ð° Ð³ÐžÐ¿ÐµÑÑÑÑÐ»ÐŸÐº ÐŽÐ»Ñ Ð·Ð°Ð³ÑÑÐ·ÐºÐž: Ð£ÑÑÐ°ÐœÐŸÐ²ÐžÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ 0 ÐŽÐ»Ñ Ð·Ð°Ð³ÑÑÐ·ÐºÐž ÐŸÐŽÐœÐŸÐ¹ Ð²ÐµÐ± ÑÑÑÐ°ÐœÐžÑÑ; Ð·ÐœÐ°ÑÐµÐœÐžÐµ 1 ÑÑÐŸÐ±Ñ Ð·Ð°Ð³ÑÑÐ·ÐžÑÑ ÐŸÐŽÐœÑ ÑÑÑÐ°ÐœÐžÑÑ Ðž Ð²ÑÐµ ÑÑÑÐ°ÐœÐžÑÑ ÑÐ²ÑÐ·Ð°ÐœÐœÑÐµ Ñ ÐœÐµÐ¹ . Ð¿ÑÐµÐŽÐµÐ» Ð³Ð»ÑÐ±ÐžÐœÑ ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÑÐµÑÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐœÐ° html ÑÑÑÐ°ÐœÐžÑÑ. Ð¡Ð»ÐµÐŽÑÐ¹ÑÐµÐµ, Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐ° ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ "Ð³Ð°Ð»ÐŸÑÐµÐº", ÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ, ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ ÑÑÐŸÐ±Ñ ÑÑÐŸÐ±Ñ Ð²ÐºÐ»ÑÑÐžÑÑ ÑÐºÐ°Ð·Ð°ÐœÐœÑÑ ÐŸÑÐŸÐ±ÐµÐœÐœÐŸÑÑÑ ÐºÐŸÐœÐºÑÐµÑÐœÐŸÐ¹ Ð·Ð°Ð³ÑÑÐ·ÐºÐž. ÐÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐ°, ÐœÐ°Ð¶ÐŒÐžÑÐµ "ÐÐ°Ð³ÑÑÐ·ÐºÐ°", ÑÑÐŸÐ±Ñ ÐœÐ°ÑÐ°ÑÑ ÐœÐŸÐ²ÑÑ Ð·Ð°Ð³ÑÑÐ·ÐºÑ. ÐÑÑÑ ÐŽÐ²Ðµ ÐŽÑÑÐ³ÐžÑ
+ ÐºÐœÐŸÐ¿ÐºÐž: Ð² ÑÐ°Ð·ÐŽÐµÐ»Ðµ "ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž", ÐºÐŸÑÐŸÑÑÐµ ÑÐ²ÑÐ·Ð°ÐœÑ Ñ ÑÐ°Ð·ÐŽÐµÐ»ÐŸÐŒ ÐœÐ°ÑÑÑÐŸÐ¹ÐºÐž ÑÐ²ÑÐ·Ðž, Ð³ÐŽÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ Ð¿ÑÐŸÐºÑÐž ÑÐµÑÐ²ÐµÑÐ° ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐžÐ·ÐŒÐµÐœÐµÐœÑ; Ðž "ÐÑÐžÑÑÐºÐ° ÐÑÑ", ÐºÐŸÑÐŸÑÐ°Ñ ÑÐŽÐ°Ð»ÑÐµÑ Ð²ÑÐµ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ.
+      <p></p>
+      Ð¡Ð¿ÐžÑÐŸÐº Ð·Ð°Ð³ÑÑÐ·ÐºÐž ÐžÐŒÐµÐµÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ¹ Ð·Ð°Ð³ÑÑÐ¶Ð°ÐµÐŒÐŸÐ¹ Ð²ÐµÐ± ÑÑÑÐ°ÐœÐžÑÑ. ÐÐ°Ð¶ÐŽÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐŒÐµÐµÑ ÑÐµÐºÑÑ Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÑÑÐžÐ¹ ÐŽÐµÑÐ°Ð»Ðž Ð·Ð°ÐŽÐ°ÑÐž Ð²ÐŒÐµÑÑÐµ Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐŸÑÐŸÐŒ Ð¿ÑÐŸÐ³ÑÐµÑÑÐ° ÐŽÐµÐŒÐŸÐœÑÑÑÐžÑÑÑÑÐžÐŒ ÑÐµÐºÑÑÑÑ ÐŽÐµÑÑÐµÐ»ÑÐœÐŸÑÑÑ. Ð¢ÑÐž ÐºÐœÐŸÐ¿ÐºÐž Ð¿ÐŸÑÐ²Ð»ÑÑÑÑÑ ÑÐ»ÐµÐ²Ð° ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ. "ÐÐ°ÑÐ·Ð°" ÐŽÐ»Ñ Ð¿ÑÐžÐŸÑÑÐ°ÐœÐŸÐ²ÐºÐž Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐžÑ ÑÐµÐºÑÑÐµÐ³ÐŸ Ð¿ÑÐŸÑÐµÑÑÐ°. "Ð¡ÐŒÐŸÑÑÐµÑÑ ÐÐŸÐ³Ðž" ÐŸÑÐºÑÑÐ²Ð°ÐµÑ ÐŸÐºÐœÐŸ ÑÐ°Ð¹Ð»Ð° Ð·Ð°Ð³ÑÑÐ·ÐºÐž. "ÐÐ°ÐºÑÑÑÑ" Ð·Ð°Ð²ÐµÑÑÐ°ÐµÑ Ð·Ð°Ð³ÑÑÐ·ÐºÑ Ð·Ð°ÐŽÐ°ÑÐž ÐžÐ· ÑÐ¿ÐžÑÐºÐ°.
+      <p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="advanced"> Ð Ð°ÑÑÐžÑÐµÐœÐœÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+      
+<a href="preferences.htm#preferences">Ð¡ÐµÐºÑÐžÑ ÐÐ°ÑÑÑÐŸÐµÐº</a> ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑ ÐºÐ°Ðº ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐžÐœÑÐµÑÐœÐµÑ ÑÐŸÐµÐŽÐžÐœÐµÐœÐžÐµ ÑÐµÑÐµÐ· Ð¿ÑÐŸÐºÑÐž ÑÐµÑÐ²ÐµÑ.  ÐÑÐ»Ðž ÐœÑÐ¶ÐœÐ° ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐ°Ñ Ð°ÑÑÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÑ, Ð¿ÑÐŸÐºÑÐž ÑÐµÑÐ²ÐµÑ Ð·Ð°Ð¿ÑÐŸÑÐžÑ ÐžÐŒÑ Ðž Ð¿Ð°ÑÐŸÐ»Ñ.  ÐÐœÑÐµÑÑÐµÐ¹Ñ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°ÑÑ ÐœÐµ ÑÐŸÐ·ÑÐ°ÐœÑÐµÑ Ð¿Ð°ÑÐŸÐ»Ðž ÐŒÐµÐ¶ÐŽÑ ÑÐµÑÑÐžÑÐŒÐž.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/translatetext.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/translatetext.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/translatetext.htm	(revision 10506)
@@ -0,0 +1,66 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="translatetext"><font size="5" face="Verdana"><strong>6.10: ÐÐµÑÐµÐ²ÐŸÐŽ ÑÐµÐºÑÑÐ°</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÐµÑÑÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐµÑÐµÐ²ÐŸÐŽÐ°, Ð³ÐŽÐµ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÑÐ·ÑÐº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÑ
+ ÑÑÐ°Ð³ÐŒÐµÐœÑÐŸÐ² ÑÐµÐºÑÑÐ° ÐŽÐ»Ñ ÑÐ°ÑÑÐµÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð "Ð Ð°Ð·ÐŽÐµÐ»Ðµ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐµÑÐµÐ²ÐµÑÑÐž ÑÐµÐºÑÑ".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             Ð£ÐŽÐ°Ð»ÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ±ÐœÐŸÐ²ÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽÐ°
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð¡ÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐžÑÐµ Ð²Ñ
+ÐŸÐŽ Ð² ÑÐ¿ÐžÑÐŸÐº "Ð¡Ð²ÐŸÐ¹ÑÑÐ²Ð°". ÐÐžÐ¶Ðµ Ð¿ÐŸÑÐ²ÑÑÑÑ ÑÑÑÐŸÐºÐž ÑÐ¿ÐµÑÐžÑÐžÑÐœÐŸÐ³ÐŸ ÑÐ·ÑÐºÐ°, ÑÐ²ÑÐ·Ð°ÐœÐœÑÐµ Ñ ÑÑÐžÐŒ ÑÐ²ÐŸÐ¹ÑÑÐ²ÐŸÐŒ. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐœÐžÑÐ¿Ð°ÐŽÐ°ÑÑÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº "Ð¯Ð·ÑÐº Ð¿ÐµÑÐµÐ²ÐŸÐŽÐ°",ÑÑÐŸÐ±Ñ Ð²ÑÐ±ÑÐ°ÑÑ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÐ¹ ÑÐ·ÑÐº Ðž Ð²Ð²ÐµÑÑÐž Ð¿ÐµÑÐµÐ²ÐµÐŽÐµÐœÐœÑÐ¹ ÑÐµÐºÑÑ Ð² ÐŸÐ±Ð»Ð°ÑÑÑ ÑÐµÐºÑÑÐ°, ÐŸÐ±ÑÐ°ÑÐ°ÑÑÑ Ðº "ÐÐ°ÑÐ°Ð»ÑÐœÐŸÐŒÑ ÑÑÐ°Ð³ÐŒÐµÐœÑÑ ÑÐµÐºÑÑÐ°",ÐµÑÐ»Ðž ÑÑÐŸ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ. ÐÐŸ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÐž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐ±Ð°Ð²ÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ".
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐ¹ Ð¿ÐµÑÐµÐ²ÐŸÐŽ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ Ð² ÑÐ°Ð±Ð»ÐžÑÐµ "ÐÐ°ÐŽÐ°ÐœÐœÑÐµ Ð¿ÐµÑÐµÐ²ÐŸÐŽÑ" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "Ð£ÐŽÐ°Ð»ÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ".
+<p></p>
+ Ð§ÑÐŸÐ±Ñ ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐµÐ³ÐŸ, ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÑÐ¹ÑÐµ Ð² ÑÐµÐºÑÑÐŸÐ²ÐŸÐ¹ ÐŸÐ±Ð»Ð°ÑÑÐž "ÐÐµÑÐµÐ²ÐµÐŽÐµÐœÐœÑÐ¹ ÑÐµÐºÑÑ" Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽ".
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/updatingmetadata.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/updatingmetadata.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/updatingmetadata.htm	(revision 10506)
@@ -0,0 +1,65 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="updatingmetadata"><font size="5" face="Verdana"><strong>5.5: ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Ð ÑÑÐŸÐŒ ÑÐ°Ð·ÐŽÐµÐ»Ðµ ÐŸÐ±ÑÑÑÐœÑÐµÑÑÑ, ÐºÐ°Ðº ÐŒÐŸÐŽÐµÑÐœÐžÐ·ÐžÑÐŸÐ²Ð°ÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÐµ Ðº ÑÐ°Ð¹Ð»Ñ.
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+             ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ Ð¿Ð°Ð¿ÐŸÐº ÐžÐ»Ðž ÐŒÐœÐŸÐ¶ÐµÑÑÐ²ÐŸ ÑÐ°Ð¹Ð»ÐŸÐ²
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ Ð§ÑÐŸÐ±Ñ ÐŸÐ±ÐœÐŸÐ²ÐžÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÑÐ°ÑÑÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,ÑÐœÐ°ÑÐ°Ð»Ð° Ð²ÑÐ±ÐµÑÐžÑÐµ ÑÐ°Ð¹Ð»,Ðº ÐºÐŸÑÐŸÑÐŸÐŒÑ ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ð¿ÑÐžÐŒÐµÐœÐµÐœÐŸ,Ð° Ð·Ð°ÑÐµÐŒ ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+,Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ ÐÑ Ñ
+ÐŸÑÐžÑÐµ ÐžÐ·ÐŒÐµÐœÐžÑÑ.Ð ÐµÐ·ÑÐ»ÑÑÐ°Ñ Ð²ÑÐ±ÐŸÑÐ° Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ Ð² ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐž ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. Ð ÐµÐŽÐ°ÐºÑÐžÑÑÐ¹ÑÐµ Ð¿ÐŸÐ»Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÑ Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐ°ÐŒÐµÐœÐžÑÑ", ÑÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ.
+<p></p>
+ÐÑÐŸÑÐµÑÑ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÑ ÐŽÐ°ÐœÐœÑÑ
+ Ð¿Ð°Ð¿ÐºÐž Ñ Ð¿ÐŸÐŽÐ¿Ð°Ð¿ÐºÐ°ÐŒÐž ÐžÐ»Ðž ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÑÐŸÑ Ð¶Ðµ ÑÐ°ÐŒÑÐ¹, ÐœÐŸ Ð²Ñ ÑÐŒÐŸÐ¶ÐµÑÐµ ÐŸÐ±ÐœÐŸÐ²ÐžÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ, ÐŸÐ±ÑÐžÐµ ÐŽÐ»Ñ Ð²ÑÐµÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ²/Ð¿Ð°Ð¿ÐŸÐº.
+<p></p>
+ ÐÐµÑÐµÐ²ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ Ð²ÑÐµ Ð¿ÑÐµÐŽÑÐŽÑÑÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ, Ð° ÐœÐµ ÑÐŸÐ»ÑÐºÐŸ ÑÐµ, ÐºÐŸÑÐŸÑÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÑ Ð² ÐœÐ°ÑÑÐŸÑÑÐµÐµ Ð²ÑÐµÐŒÑ. Ð¢Ð°ÐºÐžÐŒ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ, Ð·ÐœÐ°ÑÐµÐœÐžÐµ, ÐºÐŸÑÐŸÑÐŸÐµ ÐÑ Ð·Ð°ÐŒÐµÐœÐžÐ»Ðž, ÐŸÑÑÐ°ÑÑÑÑ Ð² ÐŽÐµÑÐµÐ²Ðµ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/ru/xcollectionsearching.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/ru/xcollectionsearching.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/ru/xcollectionsearching.htm	(revision 10506)
@@ -0,0 +1,62 @@
+<html>
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>The Greenstone Librarian Interface - Help Pages</title>
+</head>
+<body bgcolor="#E0F0E0">
+<table width="100%" cellspacing="0" cellpadding="5" bgcolor="#B0D0B0" border="2">
+<tr>
+<td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td><td width="*" align="center"><a name="xcollectionsearching"><font size="5" face="Verdana"><strong>6.7: Ð¡ÐŸÐ²ÐŒÐµÑÑÐœÑÐ¹ Ð¿ÐŸÐžÑÐº Ð² ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+</strong></font></a></td><td width="15%" align="center"><img width="45" src="../gatherer_medium.gif" height="45"></td>
+</tr>
+</table>
+      
+ Greenstone Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑÑ Ð¿ÐŸÐžÑÐº Ð² ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÑ
+ ÑÐ°Ð·Ð»ÐžÑÐœÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+, ÐºÐ°Ðº ÐµÑÐ»Ðž Ð±Ñ ÐŸÐœÐž Ð±ÑÐ»Ðž ÐŸÐ±ÑÐµÐŽÐžÐœÐµÐœÑ.Ð­ÑÐŸ ÑÐŽÐµÐ»Ð°ÐœÐŸ ÐŽÐ»Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ "Ð¡ÑÐ¿ÐµÑÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž", ÐºÐŸÑÐŸÑÐ°Ñ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÐžÐœÐŽÐžÐ²ÐžÐŽÑÐ°Ð»ÑÐœÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.Ð "Ð Ð°Ð·ÐŽÐµÐ»Ð°Ñ
+ ÐŽÐžÐ·Ð°Ð¹ÐœÐ°" ÑÐµÐ»ÐºÐœÐžÑÐµ "ÐÐŸÐžÑÐº Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+".
+      <p></p>
+<table bgcolor="#B0D0B0" width="480" cellpadding="2" border="2" align="center">
+<tr>
+<td align="center"><font size="4" face="Verdana"><strong>
+              Contents
+            </strong></font></td>
+</tr>
+<tr>
+<td>
+<table width="100%" cellpadding="2" border="0" bgcolor="#FFFFFF">
+        
+<tr>
+<td colspan="3"><a href="#simple">ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a></td>
+</tr>
+          
+<tr>
+<td colspan="1"> </td><td colspan="2">
+            ÐÑÐ±ÐŸÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+          </td>
+</tr>
+        
+      
+</table>
+</td>
+</tr>
+</table>
+<p></p>
+      
+<p></p>
+<img width="20" src="../gatherer_small.gif" height="20"><a name="simple"> ÐÑÐŸÑÑÑÐµ ÐžÐœÑÑÑÑÐºÑÐžÐž:</a>
+<p style="text-align:justify"></p>
+ ÐÐµÐ¶ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐŸÐœÐœÑÐ¹ Ð¿ÐŸÐžÑÐº Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑ
+ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐºÐŸÐœÑÑÐŸÐ»ÑÐœÑÐ¹ ÑÐ¿ÐžÑÐŸÐº ÐŽÐŸÑÑÑÐ¿ÐœÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹.Ð¢ÐµÐºÑÑÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¿ÐŸÐŒÐµÑÐµÐœÑ Ðž ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÑÐµÑÐœÐ°. Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŽÑÑÐ³ÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ð² ÐºÐŸÑÐŸÑÑÑ
+ Ð¿ÐŸÐžÑÐº Ð±ÑÐŽÐµÑ Ð¿ÑÐŸÐ²ÐŸÐŽÐžÑÑÑÑ Ð¿Ð°ÑÐ°Ð»Ð»ÐµÐ»ÑÐœÐŸ, ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° ÐœÐžÑ
+ Ð² ÑÐ¿ÐžÑÐºÐµ (ÑÐµÐ»ÐºÐœÐžÑÐµ ÑÐœÐŸÐ²Ð°, ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ ÐžÑ
+). ÐÑÐ»Ðž ÐŸÑÐŸÐ±ÑÐ°ÐœÐ° ÑÐŸÐ»ÑÐºÐŸ ÐŸÐŽÐœÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÑÐŸ ÐŒÐµÐ¶ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐŸÐœÐœÑÐ¹ Ð¿ÐŸÐžÑÐº ÐœÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐµÐœ.
+<p></p>
+ ÐÐ»Ñ ÐŽÐ°Ð»ÑÐœÐµÐ¹ÑÐžÑ
+ ÐŽÐµÑÐ°Ð»ÐµÐ¹ ÑÐŒ.Ð³Ð»Ð°Ð²Ñ 1 Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ° Greenstone.
+    </body>
+</html>
Index: /tags/gsdl-2_61-distribution/gli/help/splithelpdocument.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gli/help/splithelpdocument.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/help/splithelpdocument.pl	(revision 10506)
@@ -0,0 +1,66 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# splithelpdocument.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+sub main
+{
+    local @lines = <STDIN>;
+
+    local $filestart = 0;
+    local $filename = "";
+    for ($i = 0; $i < scalar(@lines); $i++) {
+	local $line = $lines[$i];
+
+	if ($line =~ /\<a name=\"([^\"]+)\"\>/ && $filename eq "") {
+	    $filename = $1;
+	}
+
+	if ($line =~ /^\<html\>/ && $i > $filestart) {
+	    open(FILE_OUT, ">$filename.htm") or die "Error: Could not write $filename.htm.\n";
+	    for ($j = $filestart; $j < $i; $j++) {
+		print FILE_OUT $lines[$j];
+	    }
+	    close(FILE_OUT);
+
+	    $filestart = $i;
+	    $filename = "";
+	}
+    }
+
+    # Deal with the last file
+    if ($filename ne "") {
+	open(FILE_OUT, ">$filename.htm") or die "Error: Could not write $filename.htm.\n";
+	for ($j = $filestart; $j < $i; $j++) {
+	    print FILE_OUT $lines[$j];
+	}
+	close(FILE_OUT);
+    }
+}
+
+
+&main(@ARGV);
Index: /tags/gsdl-2_61-distribution/gli/makegli.bat
===================================================================
--- /tags/gsdl-2_61-distribution/gli/makegli.bat	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/makegli.bat	(revision 10506)
@@ -0,0 +1,161 @@
+@echo off
+set GLILANG=en
+
+
+::  -------- Compile the Greenstone Librarian Interface --------
+
+echo.
+if "%GLILANG%" == "en" echo Greenstone Librarian Interface (GLI)
+if "%GLILANG%" == "en" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "en" echo GLI comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt
+if "%GLILANG%" == "en" echo This is free software, and you are welcome to redistribute it
+
+if "%GLILANG%" == "es" echo Interfaz de la Biblioteca Digital Greenstone (Greenstone Librarian Interface - GLI)
+if "%GLILANG%" == "es" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "es" echo La Interfaz de la Biblioteca Digital Greenstone NO INCLUYE ABSOLUTAMENTE NINGUNA GARANTÖA.
+if "%GLILANG%" == "es" echo Para mayor informaci¢n vea los trminos de la licencia en LICENSE.txt
+if "%GLILANG%" == "es" echo Este es un software abierto, por lo que lo invitamos a que lo distribuya de forma gratuita
+
+if "%GLILANG%" == "fr" echo Interface du Bibliothcaire Greenstone (Greenstone Librarian Interface - GLI)
+if "%GLILANG%" == "fr" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "fr" echo GLI est fourni sans AUCUNE GARANTIE; pour des dtails, voir LICENSE.txt
+if "%GLILANG%" == "fr" echo Ceci est un logiciel libre, et vous tes invit 
+ le redistribuer
+
+if "%GLILANG%" == "ru" echo š¡«š®â¥ç­ë© š­â¥àä¥©á Greenstone (Greenstone Librarian Interface - GLI)
+if "%GLILANG%" == "ru" echo Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato
+if "%GLILANG%" == "ru" echo  ­¥ € ¥â   ; €¥â «š á¬. ¢ â¥ªáâ¥ LICENSE.TXT
+if "%GLILANG%" == "ru" echo â® - á¢®¡®€­® à á¯à®áâà ­ï¥¬®¥ ¯à®£à ¬¬­®¥ ®¡¥á¯¥ç¥­š¥ š ë ¬®Š¥â¥ à á¯à®áâà ­ïâì ¥£®
+
+echo.
+
+:: This script must be run from within the directory in which it lives
+if exist makegli.bat goto findJavac
+    if "%GLILANG%" == "en" echo This script must be run from the directory in which it resides.
+    if "%GLILANG%" == "es" echo Este gui¢n deber  ejecutarse desde el directorio en el que reside.
+    if "%GLILANG%" == "fr" echo Ce script doit tre excut 
+ partir du rpertoire dans lequel il se trouve.
+    if "%GLILANG%" == "ru" echo â®â áªàš¯â €®«Š¥­ ¡ëâì ¢§ïâ š§ €šà¥ªâ®àšš, ¢ ª®â®à®© ®­ à á¯®«®Š¥­
+    goto exit
+
+
+:findJavac
+:: ---- Check Javac exists ----
+set JAVACPATH=
+
+:: Some users may set the above line manually
+if not "%JAVACPATH%" == "" goto testJavac
+
+    :: If it is set, use the JAVA_HOME environment variable
+    if not "%JAVA_HOME%" == "" goto javahome
+
+    :: Check if Javac is on the search path
+    echo %PATH%| winutil\which.exe javac.exe | winutil\setvar.exe JAVACPATH > setjavac.bat
+    call setjavac.bat
+    del setjavac.bat
+    if not "%JAVACPATH%" == "" goto testJavac
+
+    :: 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
+
+    winutil\findjava.exe jdk.txt | winutil\setvar.exe JAVACPATH > setjavac.bat
+    del jdk.txt
+    call setjavac.bat
+    del setjavac.bat
+
+    :: If nothing was found in the registry, we're stuck
+    if "%JAVACPATH%" == "" goto noJavac
+
+    set JAVACPATH=%JAVACPATH%\bin
+    goto testJavac
+
+:javahome
+    set JAVACPATH=%JAVA_HOME%\bin
+
+:testJavac
+:: Check that a Javac executable has been found
+if "%GLILANG%" == "en" echo Checking Javac: %JAVACPATH%
+if "%GLILANG%" == "es" echo Revisando Javac: %JAVACPATH%
+if "%GLILANG%" == "fr" echo Vrification de Javac: %JAVACPATH%
+if "%GLILANG%" == "ru" echo à®¢¥àª  Javac: %JAVACPATH%
+if exist "%JAVACPATH%\javac.exe" goto makeGLI
+
+:noJavac
+    echo.
+    if "%GLILANG%" == "en" echo Failed to locate an appropriate version of Javac. You must install a
+    if "%GLILANG%" == "en" echo Java Development Kit (version 1.4 or greater) before compiling the
+    if "%GLILANG%" == "en" echo Greenstone Librarian Interface.
+
+    if "%GLILANG%" == "es" echo No se pudo localizar una versi¢n apropiada de Javac. Usted deber 
+    if "%GLILANG%" == "es" echo instalar un Kit de Desarrollo de Software Java (versi¢n 1.4 o superior)
+    if "%GLILANG%" == "es" echo antes de generar la documentaci¢n para la Interfaz de la Biblioteca
+    if "%GLILANG%" == "es" echo Digital Greenstone.
+
+    if "%GLILANG%" == "fr" echo Une version approprie de Javac n'a pas pu tre localise. Vous devez
+    if "%GLILANG%" == "fr" echo installer un Kit de Dveloppement Java (version 1.4 ou suprieure) 
+    if "%GLILANG%" == "fr" echo avant de produire la documentation de Greenstone Librarian Interface.
+
+    if "%GLILANG%" == "ru" echo ¥ ã€ «®áì ®¯à¥€¥«šâì ¬¥áâ®­ å®Š€¥­š¥ á®®â¢¥âáâ¢ãîé¥© ¢¥àášš Javac.
+    if "%GLILANG%" == "ru" echo ë €®«Š­ë š­áâ ««šà®¢ âì Java Development Kit (¢¥àášï 1.4 š«š ¢ëè¥)
+    if "%GLILANG%" == "ru" echo ¯à¥Š€¥, ç¥¬ £¥­¥àšà®¢ âì €®ªã¬¥­â æšî €«ï ¡š¡«š®â¥ç­®£®
+    if "%GLILANG%" == "ru" echo š­â¥àä¥©á  Greenstone.
+    goto exit
+
+
+:makeGLI
+:: ---- Compile the GLI ----
+
+if "%1" == "" goto makeAll
+    :: If a file has been specified as a command-line argument, just compile that file
+    echo.
+    if "%GLILANG%" == "en" echo Compiling %1 and dependent classes...
+    if "%GLILANG%" == "es" echo Compilando %1 y clases dependientes...
+    if "%GLILANG%" == "fr" echo Compilation de %1 et des classes dpendantes,,,
+    if "%GLILANG%" == "ru" echo ®¬¯š«šà®¢ ­š¥ %1 š § ¢šáš¬ë¥ ª« ááë...
+
+    "%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar %1
+
+    if "%GLILANG%" == "en" echo Done!
+    if "%GLILANG%" == "es" echo ­Hecho!
+    if "%GLILANG%" == "fr" echo Termin!
+    if "%GLILANG%" == "ru" echo ë¯®«­¥­®!
+    goto done
+
+:makeAll
+:: Otherwise compile the lot...
+
+:: Remove any existing class files first
+call clean.bat
+
+if "%GLILANG%" == "en" echo Compiling the Greenstone Librarian Interface...
+if "%GLILANG%" == "es" echo Compilando la Interfaz de la Biblioteca Digital Greenstone...
+if "%GLILANG%" == "fr" echo Compilation de Greenstone Librarian Interface,,,
+if "%GLILANG%" == "ru" echo ®¬¯š«šà®¢ ­š¥ ¡š¡«š®â¥ç­®£® š­â¥àä¥©á  Greenstone...
+
+:: Compile the GLI
+"%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/GathererProg.java src/org/greenstone/gatherer/util/DragTreeSelectionModel.java 
+"%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/GathererApplet.java
+
+:: Compile the GEMS
+"%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/gems/GEMS.java
+
+:: Compile the stand-alone programs used by the GLI applet
+"%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/util/Unzip.java
+"%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/util/Zipup.java
+
+if "%GLILANG%" == "en" echo Done!
+if "%GLILANG%" == "es" echo ­Hecho!
+if "%GLILANG%" == "fr" echo Termin!
+if "%GLILANG%" == "ru" echo ë¯®«­¥­®!
+goto done
+
+:exit
+echo.
+pause
+
+:done
+:: ---- Clean up ----
+set JAVACPATH=
Index: /tags/gsdl-2_61-distribution/gli/makegli.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gli/makegli.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/makegli.sh	(revision 10506)
@@ -0,0 +1,143 @@
+#!/bin/sh
+glilang=en
+
+echo
+if [ "$glilang" == "es" ]; then
+    echo "Interfaz de la Biblioteca Digital Greenstone (Greenstone Librarian Interface - GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "La Interfaz de la Biblioteca Digital Greenstone NO INCLUYE ABSOLUTAMENTE NINGUNA GARANTÍA."
+    echo "Para mayor información vea los términos de la licencia en LICENSE.txt"
+    echo "Este es un software abierto, por lo que lo invitamos a que lo distribuya de forma gratuita"
+elif [ "$glilang" == "fr" ]; then
+    echo "Interface du Bibliothécaire Greenstone (Greenstone Librarian Interface - GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "GLI est fourni sans AUCUNE GARANTIE; pour des détails, voir LICENSE.txt"
+    echo "Ceci est un logiciel libre, et vous êtes invité à le redistribuer"
+elif [ "$glilang" == "ru" ]; then
+    echo "âÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone (Greenstone Librarian Interface - GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "âéç ÎÅ ÄÁÅÔ áâóïìàôîï îéëáëéè çáòáîôéê; ÄÅÔÁÌÉ ÓÍ. × ÔÅËÓÔÅ LICENSE.TXT"
+    echo "üÔÏ - Ó×ÏÂÏÄÎÏ ÒÁÓÐÒÏÓÔÒÁÎÑÅÍÏÅ ÐÒÏÇÒÁÍÍÎÏÅ ÏÂÅÓÐÅÞÅÎÉÅ É ÷Ù ÍÏÖÅÔÅ ÒÁÓÐÒÏÓÔÒÁÎÑÔØ ÅÇÏ"
+else
+    echo "Greenstone Librarian Interface (GLI)"
+    echo "Copyright (C) 2005, New Zealand Digital Library Project, University Of Waikato"
+    echo "GLI comes with ABSOLUTELY NO WARRANTY; for details see LICENSE.txt"
+    echo "This is free software, and you are welcome to redistribute it"
+fi
+echo
+
+##  -------- Compile the Greenstone Librarian Interface --------
+
+## ---- Check Javac exists ----
+javacpath=
+
+# Some users may set the above line manually
+if [ "$javacpath" == "" ]; then
+
+    # If it is set, use the JAVA_HOME environment variable
+    if [ "$JAVA_HOME" != "" ]; then
+	javacpath="$JAVA_HOME/bin/javac"
+
+    # Check if Javac is on the search path
+    else
+	javacpath=`which javac 2> /dev/null`
+    fi
+fi
+
+# Check that a Javac executable has been found
+if [ "$glilang" == "es" ]; then
+    echo "Revisando Javac: $javacpath"
+elif [ "$glilang" == "fr" ]; then
+    echo "Vérification de Javac: $javacpath"
+elif [ "$glilang" == "ru" ]; then
+    echo "ðÒÏ×ÅÒËÁ Javac: $javacpath"
+else
+    echo "Checking Javac: $javacpath"
+fi
+if [ ! -x "$javacpath" ]; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "No se pudo localizar una versión apropiada de Javac."
+	echo "Por favor instale una nueva versión del Kit de Desarrollo de"
+	echo "Software Java (versión 1.4 o posterior) y ejecute nuevamente"
+	echo "este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Une version appropriée de Javac n'a pas pu être localisée."
+	echo "Veuillez installer une nouvelle version de Java SDK (version 1.4 ou"
+	echo "plus récente) et redémarrez ce script."
+    elif [ "$glilang" == "ru" ]; then
+	echo "îÅ ÕÄÁÌÏÓØ ÏÐÒÅÄÅÌÉÔØ ÍÅÓÔÏÎÁÈÏÖÄÅÎÉÅ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÅÊ ×ÅÒÓÉÉ Javac."
+	echo "ðÏÖÁÌÕÊÓÔÁ, ÕÓÔÁÎÏ×ÉÔÅ ÎÏ×ÕÀ ×ÅÒÓÉÀ Java SDK (×ÅÒÓÉÀ 1.4 ÉÌÉ ÂÏÌÅÅ"
+	echo "ÎÏ×ÕÀ) É ÐÅÒÅÕÓÔÁÎÏ×ÉÔÅ ÜÔÏÔ ÓËÒÉÐÔ."
+    else
+	echo "Failed to locate an appropriate version of Javac. You must install a"
+	echo "Java Development Kit (version 1.4 or greater) before compiling the"
+	echo "Greenstone Librarian Interface."
+    fi
+    exit 1
+fi
+
+## ---- Compile the GLI ----
+
+# If a file has been specified at the command-line, just compile that file
+if [ ! "x$*" = "x" ] ; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "Compilando $* y clases dependientes..."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Compilation de $* et des classes dépendantes,,,"
+    elif [ "$glilang" == "ru" ]; then
+	echo "ëÏÍÐÉÌÉÒÏ×ÁÎÉÅ $* É ÚÁ×ÉÓÉÍÙÅ ËÌÁÓÓÙ..."
+    else
+	echo "Compiling $* and dependent classes..."
+    fi
+
+    $javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar $*
+
+    if [ "$glilang" == "es" ]; then
+	echo "¡Hecho!"
+    elif [ "$glilang" == "fr" ]; then
+	echo "Terminé!"
+    elif [ "$glilang" == "ru" ]; then
+	echo "÷ÙÐÏÌÎÅÎÏ!"
+    else
+	echo "Done!"
+    fi
+    exit 0
+fi
+
+# Otherwise compile the lot...
+
+# Remove any existing class files first
+./clean.sh
+
+if [ "$glilang" == "es" ]; then
+    echo "Compilando la Interfaz de la Biblioteca Digital Greenstone..."
+elif [ "$glilang" == "fr" ]; then
+    echo "Compilation de Greenstone Librarian Interface,,,"
+elif [ "$glilang" == "ru" ]; then
+    echo "ëÏÍÐÉÌÉÒÏ×ÁÎÉÅ ÂÉÂÌÉÏÔÅÞÎÏÇÏ ÉÎÔÅÒÆÅÊÓÁ Greenstone..."
+else
+    echo "Compiling the Greenstone Librarian Interface..."
+fi
+
+# Compile the GLI
+$javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/GathererProg.java
+$javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/GathererApplet.java
+
+# Compile the GEMS
+$javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/gems/GEMS.java
+
+# Compile the stand-alone programs used by the GLI applet
+$javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/util/Unzip.java
+$javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/util/Zipup.java
+
+if [ "$glilang" == "es" ]; then
+    echo "¡Hecho!"
+elif [ "$glilang" == "fr" ]; then
+    echo "Terminé!"
+elif [ "$glilang" == "ru" ]; then
+    echo "÷ÙÐÏÌÎÅÎÏ!"
+else
+    echo "Done!"
+fi
Index: /tags/gsdl-2_61-distribution/gli/makejar.bat
===================================================================
--- /tags/gsdl-2_61-distribution/gli/makejar.bat	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/makejar.bat	(revision 10506)
@@ -0,0 +1,175 @@
+echo off
+set GLILANG=en
+
+:: This script must be run from within the directory in which it lives
+if exist makejar.bat goto findJar
+    if "%GLILANG%" == "en" echo This script must be run from the directory in which it resides.
+    if "%GLILANG%" == "es" echo Este gui¢n deber  ejecutarse desde el directorio en el que reside.
+    if "%GLILANG%" == "fr" echo Ce script doit tre excut 
+ partir du rpertoire dans lequel il se trouve.
+    if "%GLILANG%" == "ru" echo â®â áªàš¯â €®«Š¥­ ¡ëâì ¢§ïâ š§ €šà¥ªâ®àšš, ¢ ª®â®à®© ®­ à á¯®«®Š¥­
+    goto exit
+
+
+
+
+:findJar
+:: ---- Check jar exists ----
+set JARPATH=
+
+:: Some users may set the above line manually
+if not "%JARPATH%" == "" goto testJar
+
+    :: If it is set, use the JAVA_HOME environment variable
+    if not "%JAVA_HOME%" == "" goto javahome
+
+    :: Check if jar is on the search path
+    echo %PATH%| winutil\which.exe jar.exe | winutil\setvar.exe JARPATH > setjar.bat
+    call setjar.bat
+    del setjar.bat
+    if not "%JARPATH%" == "" goto testJar
+
+    :: 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
+
+    winutil\findjava.exe jdk.txt | winutil\setvar.exe JARPATH > setjar.bat
+    del jdk.txt
+    call setjar.bat
+    del setjar.bat
+
+    :: If nothing was found in the registry, we're stuck
+    if "%JARPATH%" == "" goto noJar
+
+    set JARPATH=%JARPATH%\bin
+    goto testJar
+
+:javahome
+    set JARPATH=%JAVA_HOME%\bin
+
+:testJar
+:: Check that a jar executable has been found
+if "%GLILANG%" == "en" echo Checking jar: %JARPATH%
+if "%GLILANG%" == "es" echo Revisando jar: %JARPATH%
+if "%GLILANG%" == "fr" echo Vrification de jar: %JARPATH%
+if "%GLILANG%" == "ru" echo à®¢¥àª  jar: %JARPATH%
+if exist "%JARPATH%\jar.exe" goto checkCompile
+
+:noJar
+    echo.
+    if "%GLILANG%" == "en" echo Failed to locate an appropriate version of jar. You must install a
+    if "%GLILANG%" == "en" echo Java Development Kit (version 1.4 or greater) before compiling the
+    if "%GLILANG%" == "en" echo Greenstone Librarian Interface.
+
+    if "%GLILANG%" == "es" echo No se pudo localizar una versi¢n apropiada de jar. Usted deber 
+    if "%GLILANG%" == "es" echo instalar un Kit de Desarrollo de Software Java (versi¢n 1.4 o superior)
+    if "%GLILANG%" == "es" echo antes de generar la documentaci¢n para la Interfaz de la Biblioteca
+    if "%GLILANG%" == "es" echo Digital Greenstone.
+
+    if "%GLILANG%" == "fr" echo Une version approprie de jar n'a pas pu tre localise. Vous devez
+    if "%GLILANG%" == "fr" echo installer un Kit de Dveloppement Java (version 1.4 ou suprieure) 
+    if "%GLILANG%" == "fr" echo avant de produire la documentation de Greenstone Librarian Interface.
+
+    if "%GLILANG%" == "ru" echo ¥ ã€ «®áì ®¯à¥€¥«šâì ¬¥áâ®­ å®Š€¥­š¥ á®®â¢¥âáâ¢ãîé¥© ¢¥àášš jar.
+    if "%GLILANG%" == "ru" echo ë €®«Š­ë š­áâ ««šà®¢ âì Java Development Kit (¢¥àášï 1.4 š«š ¢ëè¥)
+    if "%GLILANG%" == "ru" echo ¯à¥Š€¥, ç¥¬ £¥­¥àšà®¢ âì €®ªã¬¥­â æšî €«ï ¡š¡«š®â¥ç­®£®
+    if "%GLILANG%" == "ru" echo š­â¥àä¥©á  Greenstone.
+    goto exit
+
+
+
+:checkCompile
+:: Check that the GLI has been compiled 
+if exist classes\org\greenstone\gatherer\GathererProg.class goto makeJar
+    if "%GLILANG%" == "es"  (
+	echo Usted necesita compilar la Interfaz de la Biblioteca Digital Greenstone
+	echo (por medio de makegli.sh) antes de ejecutar este guión.
+    )
+    if "%GLILANG%" == "fr" (
+	echo Vous devez compiler le Greenstone Interface (en utilisant makegli.sh)
+	echo avant d'exécuter ce script.
+    )
+    if "%GLILANG%" == "ru" (
+	echo ÷Ù ÄÏÌÖÎÙ ËÏÍÐÉÌÉÒÏ×ÁÔØ ÂÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone
+	echo (ÉÓÐÏÌØÚÕÑ makegli.sh) ÐÅÒÅÄ ××ÏÄÏÍ ÜÔÏÇÏ ÓËÒÉÐÔÁ
+    )
+    if "%GLILANG%" == "en" (
+	echo You need to compile the Greenstone Librarian Interface (using makegli.sh)
+	echo before running this script.
+    )
+    goto exit
+fi
+
+
+:makeJar
+:: All the GLI class files and supporting libraries are put into the "jar" directory
+
+echo Assuming that Java code is freshly compiled...
+
+if NOT exist jar (
+  mkdir jar
+
+  cd lib
+  %JARPATH%\jar xf activation.jar com javax
+  %JARPATH%\jar xf apache.jar com org
+  %JARPATH%\jar xf mail.jar com javax
+  %JARPATH%\jar xf qfslib.jar de
+
+  move com ..\jar\com     >NUL
+  move de ..\jar\de       >NUL
+  move javax ..\jar\javax >NUL
+  move org ..\jar\org     >NUL
+
+  cd ..
+)
+
+:: Copy the latest version of the GLI classes into the jar directory
+if exist jar\org\greenstone (
+  rmdir /q /s jar\org\greenstone
+)
+xcopy /i /e /q classes\org\greenstone jar\org\greenstone
+
+:: Some of the things to go into the JAR file are optional, and may not exist
+set optional=
+if exist collect.zip (
+    set optional=%optional% collect.zip
+)
+if exist classifiers.dat (
+    set optional=%optional% classifiers.dat
+)
+if exist plugins.dat (
+    set optional=%optional% plugins.dat
+)
+
+:: Recreate the metadata.zip file (contains the GLI metadata directory)
+if exist jar\org\greenstone (
+  del /f metadata.zip
+)
+winutil\zip.exe -r metadata.zip metadata >NUL
+
+:: Jar everything up
+%JARPATH%\jar cf GLI.jar .java.policy metadata.zip %optional% help -C classes dictionary.properties -C classes dictionary_es.properties -C classes dictionary_fr.properties -C classes dictionary_ru.properties -C classes feedback.properties -C classes images -C classes xml -C jar com -C jar de -C jar javax -C jar org
+
+
+
+:: ---- Make signed JAR file for the applet, if desired ----
+if  (%1) == (-sign) (
+
+    if not exist appletstore (
+      %JARPATH%\keytool -genkey -alias privateKey -keystore appletstore -storepass greenstone
+    )
+
+    if exist SignedGatherer.jar del /f SignedGatherer.jar
+    if exist appletpasswd (
+      echo Using jarsigner to make signed jar file ...
+      %JARPATH%\jarsigner -keystore appletstore -signedjar SignedGatherer.jar GLI.jar privateKey < appletpasswd >NUL 2>NUL
+      echo ... done.
+    ) ELSE (
+      %JARPATH%\jarsigner -keystore appletstore -signedjar SignedGatherer.jar GLI.jar privateKey
+    )
+    echo Installing SignedGatherer in ..\bin\java
+    move SignedGatherer.jar ..\bin\java\SignedGatherer.jar
+)
+
Index: /tags/gsdl-2_61-distribution/gli/makejar.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gli/makejar.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/makejar.sh	(revision 10506)
@@ -0,0 +1,90 @@
+#!/bin/sh
+glilang=en
+
+
+# This script must be run from within the directory in which it lives
+thisdir=`pwd`
+if [ ! -f "${thisdir}/makejar.sh" ]; then
+    if [ "$glilang" == "es" ]; then
+        echo "Este guión deberá ejecutarse desde el directorio en el que reside."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Ce script doit être exécuté à partir du répertoire dans lequel il se trouve."
+    elif [ "$glilang" == "ru" ]; then
+	echo "üÔÏÔ ÓËÒÉÐÔ ÄÏÌÖÅÎ ÂÙÔØ ×ÚÑÔ ÉÚ ÄÉÒÅËÔÏÒÉÉ, × ËÏÔÏÒÏÊ ÏÎ ÒÁÓÐÏÌÏÖÅÎ"
+    else
+	echo "This script must be run from the directory in which it resides."
+    fi
+    exit 1
+fi
+
+## ---- Check that the GLI has been compiled ----
+if [ ! -f "classes/org/greenstone/gatherer/GathererProg.class" ]; then
+    echo
+    if [ "$glilang" == "es" ]; then
+	echo "Usted necesita compilar la Interfaz de la Biblioteca Digital Greenstone"
+	echo "(por medio de makegli.sh) antes de ejecutar este guión."
+    elif [ "$glilang" == "fr" ]; then
+	echo "Vous devez compiler le Greenstone Interface (en utilisant makegli.sh)"
+	echo "avant d'exécuter ce script."
+    elif [ "$glilang" == "ru" ]; then
+	echo "÷Ù ÄÏÌÖÎÙ ËÏÍÐÉÌÉÒÏ×ÁÔØ ÂÉÂÌÉÏÔÅÞÎÙÊ ÉÎÔÅÒÆÅÊÓ Greenstone"
+	echo "(ÉÓÐÏÌØÚÕÑ makegli.sh) ÐÅÒÅÄ ××ÏÄÏÍ ÜÔÏÇÏ ÓËÒÉÐÔÁ"
+    else
+	echo "You need to compile the Greenstone Librarian Interface (using makegli.sh)"
+	echo "before running this script."
+    fi
+    exit 1
+fi
+
+echo "Assuming that Java code is freshly compiled..."
+
+# All the GLI class files and supporting libraries are put into the "jar" directory
+if [ ! -d jar ]; then
+  mkdir jar
+
+  cd lib
+  jar xf activation.jar com javax
+  jar xf apache.jar com org
+  jar xf mail.jar com javax
+  jar xf qfslib.jar de
+
+  mv com de javax org ../jar/.
+  cd ..
+fi
+
+# Copy the latest version of the GLI classes into the jar directory
+rm -rf jar/org/greenstone
+cp -r classes/org/greenstone jar/org
+
+# Some of the things to go into the JAR file are optional, and may not exist
+optional=
+if [ -f collect.zip ]; then
+    optional="$optional collect.zip"
+fi
+if [ -f classifiers.dat ]; then
+    optional="$optional classifiers.dat"
+fi
+if [ -f plugins.dat ]; then
+    optional="$optional plugins.dat"
+fi
+
+# Recreate the metadata.zip file (contains the GLI metadata directory)
+rm -f metadata.zip
+zip -r metadata.zip metadata >/dev/null
+
+# Jar everything up
+jar cf GLI.jar .java.policy metadata.zip $optional help \
+    -C classes dictionary.properties -C classes dictionary_es.properties \
+    -C classes dictionary_fr.properties -C classes dictionary_ru.properties \
+    -C classes feedback.properties -C classes images -C classes xml \
+    -C jar com -C jar de -C jar javax -C jar org
+
+
+# ---- Make signed JAR file for the applet, if desired ----
+if [ "$1" == "-sign" ]; then
+    rm -f SignedGatherer.jar
+    echo "greenstone" | jarsigner -keystore .greenstonestore -signedjar SignedGatherer.jar GLI.jar privateKey 2> /dev/null
+    echo
+    echo "Installing SignedGatherer in ../bin/java"
+    mv SignedGatherer.jar ../bin/java/.
+fi
Index: /tags/gsdl-2_61-distribution/gli/metadata/adding_translations.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gli/metadata/adding_translations.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/metadata/adding_translations.txt	(revision 10506)
@@ -0,0 +1,88 @@
+How to add a translation for a metadata set.
+
+Note: When using the word element, we are speaking of a document object model element. Whereas when we say Element we are talking about a particular document object model element used to describe an item from the current set.
+
+1. Prepare your source text in a UTF8 encoded document, or use a fully Unicode compliant text editor. Open the metadata set file that you want to edit.
+
+Example: To add a new language to the dublin.mds, open the file in a UTF8 editor.
+
+2. In MetadataSet DOM element edit, or add if necessary, an argument named "language_dependent". As its value add a list of comma separated attribute names. These are the names of the attributes which are taken to be language dependent (see 4). 
+
+Example: While editing the dublin.mds scroll down to the start of the MetadataSet xml block, which looks like:
+
+<MetadataSet 
+  contact     = "dcmi-feedback@dublincore.org"
+  creator     = "Dublin Core Metadata Initiative"
+  family      = "Dublin Core"
+  lastchanged = "Tue Jun 04 10:35:30 2002 - jmt12 on blackbird"
+  namespace   = "dc" 
+>
+
+and add the mentioned line so it reads something like:
+
+<MetadataSet 
+  contact     = "dcmi-feedback@dublincore.org"
+  creator     = "Dublin Core Metadata Initiative"
+  family      = "Dublin Core"
+  lastchanged = "Tue Jun 04 10:35:30 2002 - jmt12 on blackbird"
+  namespace   = "dc" 
+  language_dependent = "identifier, definition, comment"
+>
+
+where identifier, definition and command are the attributes that we wish to be language specific.
+
+3. Near the top of the document add a language specific set description block of the form
+
+  <SetLanguage code="**">
+    <Name>**</Name>
+    <Description>**</Description>
+  </SetLanguage>
+
+  Replace the ** with the relevant detail. Code is the two letter language code according to ISO 3166.
+
+Example: To add the French translation to the dublin.mds scroll down to just below the MetadataSet xml block, and add the SetLanguage xml block:
+
+  <SetLanguage code="fr">
+    <Name language="fr">El\303\251ments de m\303\251tadonn\303\251es du Dublin Core, Version 1.1: Description de R\303\251ference</Name>
+    <Description language="fr">Ce document r\303\251sume...</Description>
+  </SetLanguage>
+
+4. For each Element xml block defined in the metadata set, add a new Language xml block and within it add the language specfic Attributes. The block is of the form:
+
+    <Language code="**">
+       <Attribute name="**">**</Attribute>
+       ...
+    </Language>
+
+  Replace the ** with the relevant detail. Once again code is the two letter language code according to ISO 3166. Note that the names specified in the name argument of an Attribute must also be listed in the language_dependent argument of the MetadataSet (see 1)
+
+Example: Thus to add a French translation for the Element "Title", scroll down to the Element xml block defining Title. This should start:
+
+  <Element name="Title" remember_values="true">
+  ...
+  ...
+  ...
+  </Element>
+
+Now add in a new Language block so it looks something like this:
+
+  <Element name="Title" remember_values="true">
+  ...
+     <!-- French -->
+     <Language code="fr">
+        <Attribute name="identifier">Titre</Attribute>
+        <Attribute name="definition">Le nom donn\303\251 \303\240  la ressource.</Attribute>
+        <Attribute name="comment">Typiquement, un titre sera le nom par lequel la ressource est officiellement connue.</Attribute>
+     </Language>
+  ...
+  </Element>    
+
+5. Finally edit the file <gli_install>/classes/xml/languages.xml. Locate the appropriate Language and add the argument mds="true" to enable this language. This controls what languages appear on the preferences page within the GLI.
+
+Example: Finally to enable the French translation, find the entry in the languages.xml file that reads:
+
+  <Language name="FRENCH"              code="FR" ... >ROMANCE</Language>
+
+And change it so it now says:
+
+  <Language name="FRENCH"              code="FR" ... mds="true">ROMANCE</Language> 
Index: /tags/gsdl-2_61-distribution/gli/metadata/agls.mds
===================================================================
--- /tags/gsdl-2_61-distribution/gli/metadata/agls.mds	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/metadata/agls.mds	(revision 10506)
@@ -0,0 +1,334 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param description A description of this metadata set.                           -->
+  <!-- @param family      The namespace of this metadata set.                           -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param name        The name of this metadata set.                                -->
+  <!-- @param namespace   The abbreviated namespace of this metadata set.               -->
+  <!ELEMENT MetadataSet (Element+)>
+  <!ATTLIST MetadataSet
+				contact     CDATA #REQUIRED
+				creator     CDATA #REQUIRED
+				description CDATA #REQUIRED
+            family      CDATA #REQUIRED
+				lastchanged CDATA #REQUIRED
+            name        CDATA #REQUIRED
+				namespace   CDATA #REQUIRED>
+
+  <!-- An element in the metadata set. -->
+  <!ELEMENT Element (Attribute*,OptionList?,AssignedValues?)>
+  <!ATTLIST Element
+            name       CDATA #REQUIRED
+				occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+
+  <!-- Each element also contains a tree of values that have been assigned to it. This may include a multilayer nested subject hierachy. -->
+  <!ELEMENT AssignedValues (Subject+)>
+
+  <!-- A value. -->
+  <!ELEMENT Subject (Value|Alias?|Subject*)>
+  <!ELEMENT Value (#PCDATA)>
+  <!ATTLIST Value
+            occurances CDATA "1">
+  <!ELEMENT Alias (#PCDATA)>
+]>
+<MetadataSet contact="agls@naa.gov.au" creator="The National Archives of Australia" lastchanged="Friday December 3 2004 03:07:42 - mgw5 on narya.cs.waikato.ac.nz" namespace="agls">
+    <Name language="en">Australian Government Locator Service Metadata Element Set, Version 1.3</Name>
+    <Element name="Creator">
+        <Attribute language="en" name="identifier">Creator</Attribute>
+        <Attribute language="en" name="obligation">Mandatory if known</Attribute>
+        <Attribute language="en" name="definition">An entity primarily responsible for making the content of the resource.</Attribute>
+        <Attribute language="en" name="comment">Examples of a Creator include a person, or an organisation.</Attribute>
+    </Element>
+    <Element name="Date">
+        <Attribute language="en" name="identifier">Date</Attribute>
+        <Attribute language="en" name="definition">A date of an event in the lifecycle of the resource.</Attribute>
+        <Attribute language="en" name="obligation">Mandatory</Attribute>
+        <Attribute language="en" name="comment">Typically, Date will be associated with the creator or availability of the resource. Recommended best practice for encoding the date value is defined in a profile of ISO 8601 [W3CDTF] and follows the YYYY-MM-DD format.</Attribute>
+        <Element name="created">
+            <Attribute language="en" name="identifier">Created</Attribute>
+            <Attribute language="en" name="definition">Creation date of the resource</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+        </Element>
+        <Element name="modified">
+            <Attribute language="en" name="identifier">Modified</Attribute>
+            <Attribute language="en" name="definition">Creation date of the resource</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+        </Element>
+        <Element name="valid">
+            <Attribute language="en" name="identifier">Valid</Attribute>
+            <Attribute language="en" name="comment">Typically, a date the resource becomes valid or ceases to be valid, or the date range for which the resource is valid.</Attribute>
+            <Attribute language="en" name="definition">A date (often a range) of validity of a resource.</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+        </Element>
+        <Element name="issued">
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">A date on which the rescource was made formally available in its current form.</Attribute>
+            <Attribute language="en" name="identifier">Issued</Attribute>
+        </Element>
+    </Element>
+    <Element name="Title">
+        <Attribute language="en" name="identifier">Title</Attribute>
+        <Attribute language="en" name="definition">A name given to the resource.</Attribute>
+        <Attribute language="en" name="obligation">Mandatory</Attribute>
+        <Attribute language="en" name="comment">This qualifier could include abbreviations and acronyms by which a resource may be known.</Attribute>
+        <Element name="alternative">
+            <Attribute language="en" name="identifier">Alternative</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">Any form of the title used as a substitute or alternative to the formal title or the resource</Attribute>
+            <Attribute language="en" name="comment">This qualifier could include abbreviations and acronyms by which a resource may be known.</Attribute>
+        </Element>
+    </Element>
+    <Element name="Availability">
+        <Attribute language="en" name="definition">How the resource can be obtained or contact information for obtaining the resource.</Attribute>
+        <Attribute language="en" name="obligation">Mandatory for offline resources.</Attribute>
+        <Attribute language="en" name="comment">The Availability element is primarily used for non-electronic resources to provide information on how to obtain physical access to the resource.</Attribute>
+        <Attribute language="en" name="identifier">Availability</Attribute>
+    </Element>
+    <Element name="Function">
+        <Attribute language="en" name="identifier">Function</Attribute>
+        <Attribute language="en" name="definition">The business function of the organisation to which the resource relates.</Attribute>
+        <Attribute language="en" name="obligation">Mandatory if no Subject element specified.</Attribute>
+        <Attribute language="en" name="comment">Used to indicate the business role of the resource in terms of business functions and activities. Functions are the major units of activity which organisations pursue in order to meet the mission and goals of the organisation. They are defined in the Australian Records Management Standard (AS 4390) as the largest unit of business activity in an organisation. Recommended best practice is to select a value from a controlled vocabulary or formal classification scheme.</Attribute>
+    </Element>
+    <Element name="Identifier">
+        <Attribute language="en" name="identifier">Resource Identifier</Attribute>
+        <Attribute language="en" name="definition">An unambiguous reference to the resource within a given context.</Attribute>
+        <Attribute language="en" name="obligation">Mandatory for online resources.</Attribute>
+        <Attribute language="en" name="comment">Recommended best practice is to identify the resource by means of a string or number conforming to a formal identification system. Example formal identification systems include the Uniform Resource Identifier (URI) (including the Uniform Resource Locator (URL)), the Digital Object Identifier (DOI) and the International Standard Book Number (ISBN).</Attribute>
+    </Element>
+    <Element name="Publisher">
+        <Attribute language="en" name="identifier">Publisher</Attribute>
+        <Attribute language="en" name="definition">An entity responsible for making the resource available.</Attribute>
+        <Attribute language="en" name="obligation">Mandatory for information resources.</Attribute>
+        <Attribute language="en" name="comment">This field is often the name of the organisation that owns or controls or publishes the resource. It is not recommended that this element be used for the name of the entity which merely acts as the host for a website.</Attribute>
+    </Element>
+    <Element name="Subject">
+        <Attribute language="en" name="identifier">Subject and Keywords</Attribute>
+        <Attribute language="en" name="definition">A subject and/or topic of the content of the resource.</Attribute>
+        <Attribute language="en" name="obligation">Mandatory if no Function element specified.</Attribute>
+        <Attribute language="en" name="comment">Typically, a Subject will be expressed as keywords, key phrases or classification codes that describe a topic of the resource content. Recommended best practice is to select a value from a controlled vocabulary or formal classification scheme.</Attribute>
+    </Element>
+    <Element name="Audience">
+        <Attribute language="en" name="identifier">Audience</Attribute>
+        <Attribute language="en" name="definition">A target audience of the resource.</Attribute>
+        <Attribute language="en" name="obligation">Optional</Attribute>
+        <Attribute language="en" name="comment">Types of audiences commonly used in this element include particular industry sectors, education levels, skill levels, occupations, and EEO categories. Recommended best practice is to select a value from a controlled vocabulary or formal classification scheme.</Attribute>
+    </Element>
+    <Element name="Contributor">
+        <Attribute language="en" name="identifier">Contributor</Attribute>
+        <Attribute language="en" name="definition">An entity responsible for making a contribution to the content of the resource.</Attribute>
+        <Attribute language="en" name="obligation">Optional</Attribute>
+        <Attribute language="en" name="comment">Typically, a contributor will be an entity that has played an important but secondary role in creating the content of the resource and is not specified in the creator element.</Attribute>
+    </Element>
+    <Element name="Coverage">
+        <Attribute language="en" name="identifier">Coverage</Attribute>
+        <Attribute language="en" name="definition">The extent or scope of the content of the resource.</Attribute>
+        <Attribute language="en" name="obligation">Optional</Attribute>
+        <Attribute language="en" name="comment">Coverage will typically include spatial location (a place name or geographic coordinates), temporal period (a period label, date, or date range) or jurisdiction (such as a named administrative entity). Recommended best practice is to select a value from a controlled vocabulary (for example, the Thesaurus of Geographic Names [TGN]) and that, where appropriate, named places or time periods be used in preference to numeric identifiers such as sets of coordinates or date ranges. </Attribute>
+        <Element name="jurisdiction">
+            <Attribute language="en" name="identifier">Jurisdiction</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The name of the political/administrative entity covered by the content of the resource.</Attribute>
+            <Attribute language="en" name="comment">Jurisdiction is a description of the territory over which a particular government exercises its authority or a particualar business transacts its operations, to which the resource content is applicable.</Attribute>
+        </Element>
+        <Element name="spatial">
+            <Attribute language="en" name="identifier">Spatial</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">Spatial (geographic) characteristics of the intellectual content of the resource.</Attribute>
+        </Element>
+        <Element name="temporal">
+            <Attribute language="en" name="identifier">Temporal</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">Temporal characteristics of the intellectual content of the resource.</Attribute>
+        </Element>
+        <Element name="postcode">
+            <Attribute language="en" name="identifier">Postcode</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">Australian postcode(s) applicable to the spatial coverage of the resource content.</Attribute>
+            <Attribute language="en" name="comment">Postcode refers to the actual Australian postcode(s) which is relevant to the spatial coverage of the resource content. This qualifier will be of particular use in describing services.</Attribute>
+        </Element>
+    </Element>
+    <Element name="Description">
+        <Attribute language="en" name="identifier">Description</Attribute>
+        <Attribute language="en" name="definition">An account of the content of the resource.</Attribute>
+        <Attribute language="en" name="obligation">Optional</Attribute>
+        <Attribute language="en" name="comment">Description may include but is not limited to: an abstract, table of contents, reference to a graphical representation of content (eg a thumbnail of an image), or a free-text account of the content.</Attribute>
+    </Element>
+    <Element name="Format">
+        <Attribute language="en" name="identifier">Format</Attribute>
+        <Attribute language="en" name="definition">The physical or digital manifestation of the resource. </Attribute>
+        <Attribute language="en" name="obligation">Optional</Attribute>
+        <Attribute language="en" name="comment">Typically, Format may include the media-type or dimensions of the resource. Format may be used to determine the software, hardware or other equipment needed to display or operate the resource. Examples of dimensions include size and duration. Recommended best practice is to select a value from a controlled vocabulary (for example, the list of Internet Media Types [MIME] defining computer media formats).</Attribute>
+        <Element name="extent">
+            <Attribute language="en" name="identifier">Extent</Attribute>
+            <Attribute language="en" name="qualifier type">Element refinement</Attribute>
+            <Attribute language="en" name="definition">The size or duration of the resource.</Attribute>
+            <Attribute language="en" name="comment">The extent qualifier allows the description of the physical dimensions, file size or duration of the resource.</Attribute>
+        </Element>
+        <Element name="medium">
+            <Attribute language="en" name="identifier">Medium</Attribute>
+            <Attribute language="en" name="qualifier type">Element refinement</Attribute>
+            <Attribute language="en" name="definition">The material or physical carrier of the resource.</Attribute>
+        </Element>
+    </Element>
+    <Element name="Language">
+        <Attribute language="en" name="identifier">Language</Attribute>
+        <Attribute language="en" name="definition">A language of the intellectual content of the resource.</Attribute>
+        <Attribute language="en" name="obligation">Optional</Attribute>
+        <Attribute language="en" name="comment">Recommended best practice for the values of the Language element is defined by RFC 3066 [RFC 3066] which includes a two-letter Language Code (taken from the ISO 639 standard [ISO 639]), followed optionally, by a two-letter Country Code (taken from the ISO 3166 standard [ISO 3166]). For example, &apos;en&apos; for English, &apos;fr&apos; for French, or &apos;en-uk&apos; for English used in the United Kingdom.</Attribute>
+    </Element>
+    <Element name="Mandate">
+        <Attribute language="en" name="identifier">Mandate</Attribute>
+        <Attribute language="en" name="definition">A specific warrant which requires the resource to be created or provided.</Attribute>
+        <Attribute language="en" name="obligation">Optional </Attribute>
+        <Attribute language="en" name="comment">The element is useful to indicate the specific legal mandate which requires the resource being described to be created or provided to the public. The content of this element will usually be a reference to a specific Act, Regulation or Case, but may be a URI pointing to the legal instrument in question. </Attribute>
+        <Element name="act">
+            <Attribute language="en" name="identifier">Act</Attribute>
+            <Attribute language="en" name="definition">A reference to a specific State or Federal Act which requires the creation or provision of the resource</Attribute>
+            <Attribute language="en" name="qualifier type">Element refinement</Attribute>
+        </Element>
+        <Element name="regulation">
+            <Attribute language="en" name="identifier">Regulation</Attribute>
+            <Attribute language="en" name="definition">A reference to a specific regulation which requires the creation or provision of the resource.</Attribute>
+            <Attribute language="en" name="qualifier type">Element refinement</Attribute>
+        </Element>
+        <Element name="case">
+            <Attribute language="en" name="identifier">Case Law</Attribute>
+            <Attribute language="en" name="qualifier type">Element refinement</Attribute>
+            <Attribute language="en" name="definition">A reference to a specific case which requires the creation or provision of the resource</Attribute>
+        </Element>
+    </Element>
+    <Element name="Relation">
+        <Attribute language="en" name="identifier">Relation</Attribute>
+        <Attribute language="en" name="definition">A reference to a related resource.</Attribute>
+        <Attribute language="en" name="obligation">Optional</Attribute>
+        <Attribute language="en" name="comment">Recommended best practice is to reference the resource by means of a string or number conforming to a formal identification system.</Attribute>
+        <Element name="isVersionOf">
+            <Attribute language="en" name="identifier">Is Version Of</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource is a version, edition, or adaption of the referenced resource. Changes in version imply substative changes in content rather than differences in format.</Attribute>
+        </Element>
+        <Element name="hasVersion">
+            <Attribute language="en" name="identifier">Has Version</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource has a version, edition, or adaptation, namely, the referenced resource.</Attribute>
+        </Element>
+        <Element name="isReplacedBy">
+            <Attribute language="en" name="identifier">Is Replaced By</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource is supplanted, displaced, or superseded by the referenced resource.</Attribute>
+        </Element>
+        <Element name="replaces">
+            <Attribute language="en" name="identifier">Replaces</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resources supplants, displaces, or supersedes the referenced reource.</Attribute>
+        </Element>
+        <Element name="isRequiredBy">
+            <Attribute language="en" name="identifier">Is Required By</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource is required by the referenced resource, either physically or logically. </Attribute>
+        </Element>
+        <Element name="requires">
+            <Attribute language="en" name="identifier">Requires</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource requires the referenced resource to support its function, delivery, or coherence of content. </Attribute>
+        </Element>
+        <Element name="isPartOf">
+            <Attribute language="en" name="identifier">Is Part Of</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource is a physical or logical part of the referenced resource. </Attribute>
+        </Element>
+        <Element name="hasPart">
+            <Attribute language="en" name="identifier">Has Part</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource includes the referenced resource either physically or logically. </Attribute>
+        </Element>
+        <Element name="isReferencedBy">
+            <Attribute language="en" name="identifier">Is Referenced By</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource is referenced, cited, or otherwise pointed to by the referenced resource. </Attribute>
+        </Element>
+        <Element name="references">
+            <Attribute language="en" name="identifier">References</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource references, cites, or otherwise points to the referenced resource. </Attribute>
+        </Element>
+        <Element name="isFormatOf">
+            <Attribute language="en" name="identifier">Is Format Of</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource is the same intellectual content of the referenced resource, but presented in another format. </Attribute>
+        </Element>
+        <Element name="hasFormat">
+            <Attribute language="en" name="identifier">Has Format</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource pre-existed the referenced resource, which is essentially the same intellectual content presented in another format. </Attribute>
+        </Element>
+        <Element name="isBasisFor">
+            <Attribute language="en" name="identifier">Is Basis For</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Attribute language="en" name="definition">The described resource pre-existed the referenced resource, which is a performance, production, derivation, translation, or interpretation of the described resource. </Attribute>
+        </Element>
+        <Element name="isBasedOn">
+            <Attribute language="en" name="identifier">Is Based On</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement </Attribute>
+            <Attribute language="en" name="definition">The described resource is a performance, production, derivation, translation, or interpretation of the referenced resource. </Attribute>
+        </Element>
+    </Element>
+    <Element name="Rights">
+        <Attribute language="en" name="identifier">Rights Management</Attribute>
+        <Attribute language="en" name="definition">Information about rights held in and over the resource.</Attribute>
+        <Attribute language="en" name="obligation">Optional</Attribute>
+        <Attribute language="en" name="comment">Typically, the Rights element will contain a rights management statement for the resource, or refer to a service providing such information. Rights information often encompasses Intellectual Property Rights (IPR), Copyright, and various Property Rights. If the Rights element is absent, no assumptions can be made about the status of these and other rights with respect to the resource.</Attribute>
+    </Element>
+    <Element name="Source">
+        <Attribute language="en" name="identifier">Source</Attribute>
+        <Attribute language="en" name="definition">A reference to a resource from which the present resource is derived.</Attribute>
+        <Attribute language="en" name="obligation">Optional</Attribute>
+        <Attribute language="en" name="comment">The present resource may be derived from the Source resource in whole or in part. Recommended best practice is to reference the source resource by means of a string or number conforming to a formal identification system.</Attribute>
+    </Element>
+    <Element name="Type">
+        <Attribute language="en" name="identifier">Type</Attribute>
+        <Attribute language="en" name="defintion">The nature or genre of the content of the resource.</Attribute>
+        <Attribute language="en" name="obligation">Optional</Attribute>
+        <Attribute language="en" name="comment">Type includes terms describing general categories, genres, or aggregation levels for content. Recommended best practice is to select a value from a controlled vocabulary (for example, the working draft list of Dublin Core Types [DCT1]). To describe the physical or digital manifestation of the resource, use the FORMAT element.</Attribute>
+        <Element name="category">
+            <Attribute language="en" name="identifier">Category</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement </Attribute>
+            <Attribute language="en" name="definition">The generic type of the resource being described. </Attribute>
+            <Attribute language="en" name="comment">The value for this qualifier must be one of either service, document, or agency. </Attribute>
+        </Element>
+        <Element name="aggregtionLevel">
+            <Attribute language="en" name="identifier">Aggregtion Level</Attribute>
+            <Attribute language="en" name="qualifier type">Element refinement</Attribute>
+            <Attribute language="en" name="definition">The level of aggregation of the resource being described.</Attribute>
+            <Attribute language="en" name="comment">There are only two values possible for this qualifier, either item or collection.</Attribute>
+        </Element>
+        <Element name="documentType">
+            <Attribute language="en" name="identifier">Document Type</Attribute>
+            <Attribute language="en" name="qualifier type">Element refinement</Attribute>
+            <Attribute language="en" name="definition">The form of the resource where category = document.</Attribute>
+            <Attribute language="en" name="comment">Document is used in its widest sense and includes such things as software sound files and images. </Attribute>
+        </Element>
+        <Element name="serviceType">
+            <Attribute language="en" name="identifier">Service Type</Attribute>
+            <Attribute language="en" name="qualifier type">Element refinement</Attribute>
+            <Attribute language="en" name="definition">The type of service being offered where category = service. </Attribute>
+        </Element>
+    </Element>
+</MetadataSet>
Index: /tags/gsdl-2_61-distribution/gli/metadata/dls.mds
===================================================================
--- /tags/gsdl-2_61-distribution/gli/metadata/dls.mds	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/metadata/dls.mds	(revision 10506)
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param family      The namespace of this metadata set.                           -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param namespace   The abbreviated namespace of this metadata set.               -->
+  <!ELEMENT MetadataSet (Element+)>
+  <!ATTLIST MetadataSet
+				contact     CDATA #REQUIRED
+				creator     CDATA #REQUIRED
+            family      CDATA #REQUIRED
+				lastchanged CDATA #REQUIRED
+				namespace   CDATA #REQUIRED>
+
+  <!-- The name of a metadata set. Is language specific. -->
+  <!ELEMENT Name (#PCDATA)>
+  <!ATTLIST Name
+            language CDATA "en">
+
+  <!-- The description of a metadata set. Is language specific. -->
+  <!ELEMENT Description (#PCDATA)>
+  <!ATTLIST Description
+            language CDATA "en">
+
+  <!-- An element in the metadata set. -->
+  <!ELEMENT Element (Attribute*,OptionList?)>
+  <!ATTLIST Element
+				hierarchy  CDATA "false"
+            name       CDATA #REQUIRED
+				occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+]>
+
+<MetadataSet 
+contact = "nzdl.org"
+creator = "New Zealand Digital Libraries Project: Greenstone"
+family = "Development Library Subset"
+lastchanged = "Tue Jun 04 10:35:30 2002 - jmt12 on blackbird"
+namespace = "dls">
+
+  <Name language="en">Development Library Subset Example Metadata</Name>
+
+  <Description language="en">A metadata set file for use in The Gatherer, created from original metadata found within the Development Library Subset.</Description>
+
+  <Element name="Title" remember_values="true">
+    <Attribute name="comment" language="en"></Attribute>
+    <Attribute name="definition" language="en">The title of this resource.</Attribute>
+    <Attribute name="identifier" language="en">Title</Attribute>
+    <Attribute name="version">1.0</Attribute>
+  </Element>
+
+  <Element name="Organization" hierarchy="true" remember_values="true">
+    <Attribute name="comment" language="en"></Attribute>
+    <Attribute name="definition" language="en">The organization responsible for producing this resource.</Attribute>
+    <Attribute name="identifier" language="en">Organization</Attribute>
+    <Attribute name="version">1.0</Attribute>
+  </Element>
+
+  <Element name="Subject" hierarchy="true" remember_values="true">
+    <Attribute name="comment" language="en">Currently uses a hierarchy.</Attribute>
+    <Attribute name="definition" language="en">The subject of this resource.</Attribute>
+    <Attribute name="identifier" language="en">Subject And Keywords</Attribute>
+    <Attribute name="version">1.0</Attribute>
+  </Element>
+
+  <Element name="Keyword" hierarchy="true" remember_values="true">
+    <Attribute name="comment" language="en">Informal.</Attribute>
+    <Attribute name="definition" language="en">A more specific indication of what the resource can be used for.</Attribute>
+    <Attribute name="identifier" language="en">Keyword</Attribute>
+    <Attribute name="version">1.0</Attribute>
+  </Element>
+
+  <Element name="Language" remember_values="true">
+    <Attribute name="comment" language="en"></Attribute>
+    <Attribute name="definition" language="en">The language of this resource.</Attribute>
+    <Attribute name="identifier" language="en">Language</Attribute>
+    <Attribute name="version">1.0</Attribute>
+  </Element>
+
+  <Element name="AZList" hierarchy="true" remember_values="true">
+    <Attribute name="comment" language="en">Not the same as an AZList classifier.</Attribute>
+    <Attribute name="definition" language="en">A customizable AZList based on document titles.</Attribute>
+    <Attribute name="identifier" language="en">AZList</Attribute>
+    <Attribute name="version">1.0</Attribute>
+  </Element>
+
+</MetadataSet>
+
Index: /tags/gsdl-2_61-distribution/gli/metadata/dublin.mds
===================================================================
--- /tags/gsdl-2_61-distribution/gli/metadata/dublin.mds	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/metadata/dublin.mds	(revision 10506)
@@ -0,0 +1,1841 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param family      The name of this sets family.                                 -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param namespace   The namespace of this metadata set.                           -->
+  <!ELEMENT MetadataSet ((Name|Description|SetLanguage|Element)+)>
+  <!ATTLIST MetadataSet
+	    contact            CDATA #REQUIRED
+	    creator            CDATA #REQUIRED
+	    description        CDATA #REQUIRED
+            family             CDATA #REQUIRED
+	    lastchanged        CDATA #REQUIRED
+            name               CDATA #REQUIRED
+	    namespace          CDATA #REQUIRED
+	    language_dependent CDATA "">
+
+  <!-- The name of a metadata set. Is language specific. -->
+  <!ELEMENT Name (#PCDATA)>
+  <!ATTLIST Name
+            language CDATA "en">
+
+  <!-- The description of a metadata set. Is language specific. -->
+  <!ELEMENT Description (#PCDATA)>
+  <!ATTLIST Description
+            language CDATA "en">
+
+  <!-- When used in conjuction with defer-node-expansion, allows for better memory use when dealing with several or more languages. -->
+  <!ELEMENT SetLanguage (Name, Description?)>
+  <!ATTLIST Language
+	    code CDATA #REQUIRED>
+
+  <!-- An element in the metadata set. -->
+  <!-- Note that the name attribute isn't really Dublin Core compliant - it was just the first thing I came up with. -->
+  <!ELEMENT Element (Attribute*,Language*,OptionList?)>
+  <!ATTLIST Element
+            name       CDATA #REQUIRED
+	    occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->	
+  <!-- Given that name was already used for an Element, I decided to use identifier for the language specific 'name', which I've been told isn't really compliant with Dublin Core. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA "">
+
+  <!-- When used in conjuction with defer-node-expansion, allows for better memory use when dealing with several or more languages. -->
+  <!ELEMENT Language (Attribute*)>
+  <!ATTLIST Language
+	    code CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+]>
+
+<MetadataSet 
+contact     = "dcmi-feedback@dublincore.org"
+creator     = "Dublin Core Metadata Initiative"
+family      = "Dublin Core"
+lastchanged = "Tue Jun 04 10:35:30 2002 - jmt12 on blackbird"
+namespace   = "dc" 
+language_dependent = "identifier, definition, comment"
+>
+
+  <!-- English Version sourced from http://www.dublincore.org/documents/dces/ -->
+  <SetLanguage code="en">
+    <Name language="en">Dublin Core Metadata Element Set, Version 1.1: Reference Description</Name>
+    <Description language="en">This document is the reference description, version 1.1 of the Dublin Core Metadata Element Set. This document supersedes the Dublin Core Metadata Element Set, version 1.0. See the Dublin Core Home Page (http://dublincore.org) for further information about the workshops, reports, working group papers, projects, and new developments concerning the Dublin Core Metadata Element set</Description>
+  </SetLanguage>
+
+  <!-- Maori Version sourced from http://www.tki.org.nz/r/maori/pedagogy/dc_elements_m.php -->
+  <SetLanguage code="mi">
+    <Name>Dublin Core Huanga - Maori (He Tauira)</Name>
+  </SetLanguage>
+
+    <!-- French Version sourced from http://www-rocq.inria.fr/%7Evercoust/METADATA/DC-fr.1.1.html -->
+    <!--  by Anne-Marie Vercoustre, Inria -->
+  <SetLanguage code="fr">
+    <Name language="fr">ElÃ©ments de mÃ©tadonnÃ©es du Dublin Core, Version 1.1: Description de RÃ©ference</Name>
+    <Description language="fr">Ce document rÃ©sume les derniÃšres dÃ©finitions des Ã©lÃ©ments demÃ©tadonnÃ©es du Dublin Core originellement dÃ©finis dans le document[RFC2413]. Ces nouvelles dÃ©finitions seront officiellement connues comme la Version 1.1. Elles utilisent un standard dÃ©fini formellement pour la description d'Ã©lÃ©ments de mÃ©tadonnÃ©es. Cette formalisation contribue Ã  amÃ©liorer la cohÃ©rence avec d'autres communautÃ©s dÃ©crivant des mÃ©tadonnÃ©es et Ã  augmenter la prÃ©cision, la portÃ©e et la cohÃ©rence interne de la dÃ©finition des Ã©lÃ©ments du Dublin Core.</Description>
+  </SetLanguage>
+
+  <!-- Russian Version sourced from -->
+  <!-- by Olga Barysheva, National Library of Russia -->
+  <SetLanguage code="ru">
+    <Name language="ru">ÐÐ°Ð±ÐŸÑ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Dublin Core (ÐÑÐ±Ð»ÐžÐœÑÐºÐŸÐ³ÐŸ ÑÐŽÑÐ°) ÐÐµÑÑÐžÑ 1.1: Ð¡Ð¿ÑÐ°Ð²ÐŸÑÐœÐŸÐµ ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ</Name>
+    <Description language="ru">ÐÐ°ÑÑÐŸÑÑÐžÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ ÐŸÐ±ÐŸÐ±ÑÐ°ÐµÑ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐœÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Dublin Core (ÐÑÐ±Ð»ÐžÐœÑÐºÐŸÐ³ÐŸ ÑÐŽÑÐ°), Ð¿ÐµÑÐ²ÐŸÐœÐ°ÑÐ°Ð»ÑÐœÐŸ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÑ
+ Ð² RFC2413 (ÐÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Dublin Core ÐŽÐ»Ñ ÐœÐ°Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÑ ÑÐµÑÑÑÑÐŸÐ²). Ð­ÑÐž ÐœÐŸÐ²ÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÐŸÑÐžÑÐžÐ°Ð»ÑÐœÐŸ ÐžÐ·Ð²ÐµÑÑÐœÑ ÐºÐ°Ðº ÐÐµÑÑÐžÑ 1.1.</Description>
+  </SetLanguage>
+
+  <!-- Spanish Version sourced from http://www.rediris.es/metadata/. Please note that this is a translation for Dublin Core v1.0 -->
+  <!-- by Javi Masa, RedIRIS -->
+  <SetLanguage code="es">
+    <Name language="es">Elementos del conjunto de metadatas de Dublin Core: DescripciÃ³n de Referencia</Name>
+    <Description language="es">Este documento corresponde a una traducciÃ³n del original en lengua inglesa, con fecha 02/11/1997 que se encuentra en http://purl.org/metadata/dublin_core_elements. Este documento es una descripciÃ³n de referencia de los elementos del conjunto de "Dublin Core". Para mÃ¡s informaciÃ³n sobre reuniones de trabajo, documentos de trabajo, proyectos y nuevos desarrollos relacionados con el conjunto de elementos que aquÃ­ se describen consultar la "Home Page" de "Dublin Core" (http://purl.org/metadata/dublin_core). Los elementos poseen nombres descriptivos que pretenden transmitir un significado semÃ¡ntico a los mismos. Para promover una interoperabilidad global, una descripciÃ³n del valor de algunos elementos prodrÃ¡ ser asociada a vocabularios controlados. Se asume que otros vocabularios controlados serÃ¡n desarrollados para asegurar esta interoperabilidad en dominios especÃ­ficos. Cada elemento es opcional y puede repetirse. AdemÃ¡s, los elementos pueden aparecer en cualquier orden. Aunque algunos entornos, como HTML, no diferencian entre mayÃºsculas y minÃºsculas, es recomendable escribir correctamente cada metadata segÃºn su definiciÃ³n para evitar conflictos con otros entornos, como XML (Extensible Markup Language) http://www.w3.org/TR/PR-xml</Description>
+  </SetLanguage>
+
+  <!-- Arabic Version sourced from http://haddouti.de/DC_arabic.html -->
+  <!-- maintained by Hachim Haddouti. -->
+  <SetLanguage code="ar">
+  <Name>Ø¯ØšÙÙÙ ÙÙØ±</Name>
+  <Description>ÙØ±Ø­Øš ØšÙÙ
+ ÙÙ ØµÙØ­Ø©  Ø¯ ØšÙÙÙ ÙÙ  Ø± ØšØ§ÙØ¹Ø±ØšÙ    ÙÙ  ÙØ°Ù Ø§ÙØµÙØ­Ø©  Ù ØšØ§ÙØªØ¹Ø§ÙÙ Ù
+Ø¹ Ø§ÙØ§Ø®ÙØ§Ù Ø§ÙØ¹Ø±Øš Ù
+Ù Ø§ÙÙ
+ÙØªØšØ§ØªØ Ø¯Ø§Ø± Ø§ÙÙØŽØ±Ø Ø§ÙØšØ­ÙØ« Ø§ÙØ¹ÙÙ
+ÙØ© Ù    ÙØ±ØŽØ© Ø¹Ù
+ÙWorking Group On Multilingual Dublin Core (DC-International) Ø</Description>
+  </SetLanguage>
+
+  <!-- Chinese - Simplified Version from http://dc.library.sh.cn/DC/1-1.htm -->
+  <!-- by Liu Wei, Shanghai Library -->
+  <SetLanguage code="cn">
+    <Name>éœæææ žå¿å
+æ°æ®å
+çŽ é1.1çïŒåèæè¿°</Name>
+    <Description>æ¬ææ¡£å
+³äºéœæææ žå¿å
+æ°æ®å
+çŽ é1.1çæ¬çåèæè¿°ãæ­€æè¿°äžå·²ç»æäº€ç»ISOçšäºåœé
+æç¥šçNISOå®æ¹æ åä¿æäžèŽã    éœæææ žå¿å
+æ°æ®éæ¯äžç§è·šé¢åçä¿¡æ¯èµæºæè¿°æ åãè¿éçä¿¡æ¯èµæºè¢«å®ä¹äžºâä»»äœå
+·ææ è¯çäžè¥¿âãæ­€å®ä¹æ¥èªäºTim Berners-Leeç­äººæèçInternet RFC2396 "Uniform Resource Identifiers (URI): Generic Syntax"æä»¶ãéœæææ žå¿å
+æ°æ®çåºçšé¢åæ²¡ææ ¹æ¬çéå¶ã</Description>
+  </SetLanguage>
+
+  <!-- Czech Version from http://www.ics.muni.cz/dublin_core/DC-czech-1.1.html -->
+  <!-- Ustav vypocetni techniky Masarykovy univerzity v Brne -->
+  <SetLanguage code="cs">
+    <Name>Soubor metadatovÃœch prvkÅ¯ Dublin Core, verze 1.1: referenÄnÃ­ popis</Name>
+    <Description>Tento dokument je ÄeskÃœm pÅekladem anglickÃ© verze referenÄnÃ­ho popisu souboru metadatovÃœch prvkÅ¯  Dublin Core, verze 1.1 [DCEN1.1]. Tento dokument nahrazuje ÄeskÃœ pÅeklad souboru metadatovÃœch prvkÅ¯ Dublin Core, verze 1.0 [DCCS1.0]. DalÅ¡Ã­ informace o pracovnÃ­ch seminÃ¡ÅÃ­ch (workshopech), zprÃ¡vÃ¡ch, studiÃ­ch pracovnÃ­ch skupin, projektech a dalÅ¡Ã­m vÃœvoji souboru metadatovÃœch prvkÅ¯ Dublin Core najdete na domovskÃ© strÃ¡nce Dublin Core (http://purl.org/dc)</Description>
+  </SetLanguage>
+
+  <!-- Dutch Version from http://www.kb.nl/coop/donor/project-nl-index.html?/coop/donor/rapporten/DCsimpleformat.html -->
+  <!-- by ... -->
+  <SetLanguage code="nl">
+    <Name>Rapporten Dublin Core Simple Format</Name>
+    <Description>Dit document beschrijft welke Dublin Core metadata elementen er zijn en geeft een korte definitie van elk element. Voor uitgebreide uitleg en gebruik van de Dublin Core elementen wordt u verwezen naar de gebruikershandleiding. Deze vertaling geeft ook de keuzes aan voor standaarden (taalcodes, datum codes) die wij in DONOR verband gaan hanteren. In zoverre kan deze vertaling afwijken van het oorspronkelijke document "Description of Dublin Core Elements" http://purl.org/metadata/dublin_core_elements"</Description>
+  </SetLanguage>
+
+  <!-- Finnish Version from http://www.lib.helsinki.fi/dublin_core/dcref-fin.html -->
+  <!-- by Jani Stenvall and Juha Hakala, Helsinki University Library -->
+  <SetLanguage code="fi">
+    <Name></Name>
+    <Description></Description>
+  </SetLanguage>
+
+  <!-- Interlingua Version sourced from http://www.nautilus.com.br/%7Eensjo/ia/purl.org/dc/documents/rec-dces-19990702.htm -->
+  <!-- by Emerson Jose` Silveira da Costa -->
+  <SetLanguage code="ia">
+    <Name>Collection de elementos de metadatos de Dublin Core, version 1.1: Description de referentia</Name>
+    <Description>Isto es un traduction de un Recommendation del Dublin Core Metadata Initiative. Le publication como un recommendation significa que le specificationes es stabile e su adoption es supportate per le communitate Dublin Core (http://purl.org/dc/).</Description>
+  </SetLanguage>
+
+  <!-- Marathi Version sourced from http://bioinfo.ernet.in/library/dc/ele.txt -->
+  <!-- by by Shubhada Nagarkar, Bioinformatics Centre, University of Pune -->
+  <SetLanguage code="mr">
+    <Name>à€¡à€¬à¥à€²à€¿à€š à€à¥à€° à€®à¥à€à€Ÿà€¡à¥à€à€Ÿ à€žà¥à€ à€à€µà¥à€€à¥à€€à¥ à¥§.à¥§ à€žà€à€Šà€°à¥à€­ à€žà¥à€ªà€·à¥à€à¥à€à€°à€£ à¥§.à¥§ à€¡à€¬à¥à€²à€¿à€š à€à¥à€° à€®à¥à€à€Ÿà€¡à¥à€à€Ÿà€à€µà¥à€€à¥à€€à¥ à¥§.à¥§.</Name>
+    <Description>à¥§.à¥§ à€¡à€¬à¥à€²à€¿à€š à€à¥à€° à€®à¥à€à€Ÿà€¡à¥à€à€Ÿ à€¹à¥ à€µà¥à€à€µà¥à€à€³à¥à€¯à€Ÿ à€µà€¿à€·à€¯à€Ÿà€€à¥à€² à€®à€Ÿà€¹à¥à€€à¥ à€žà€Ÿà€ à¥à€¯à€Ÿà€à€µà€Šà¥à€Šà€²à€à¥ à€®à€Ÿà€¹à¥à€€à¥ à€Šà¥à€£à¥à€¯à€Ÿà€à¥ à€®à€Ÿà€šà€ à€à€¹à¥.  à€¯à€Ÿà€€ à€®à€Ÿà€¹à¥à€€à¥à€žà€Ÿà€ à€Ÿ à€®à¥à€¹à€£à€à¥ à€à¥à€¯à€Ÿà€²à€Ÿ à€à€³à€ à€à€¹à¥ à€
+à€žà€Ÿ à€à€žà€€à¥.  à€
+à€¶à€Ÿ à€ªà¥à€°à€à€Ÿà€°à€à¥ à€µà¥à€¯à€Ÿà€à¥à€¯à€Ÿ à€®à€Ÿà€¹à¥à€€à¥ à€à€Ÿà€³à¥à€¯à€µà€°à¥à€² à€. à€à€«.à€žà¥. à¥šà¥©à¥¯à¥¬URI: Generic Syntax -- Tim Berners Lee et al. à€¡à€¬à¥à€²à€¿à€š à€à¥à€° à€®à€Ÿà€šà€ à€à¥à€£à€€à¥à€¯à€Ÿà€¹à¥ à€ªà¥à€°à€à€Ÿà€°à€à¥à€¯à€Ÿ à€®à€Ÿà€¹à¥à€€à¥ à€žà€Ÿà€ à¥à€¯à€Ÿà€à€žà€Ÿà€ à¥ à€µà€Ÿà€ªà€°à€€à€Ÿ à€¯à¥à€€à¥.  à€€à¥à€¯à€Ÿà€žà€Ÿà€ à¥ à€à¥à€£à€€à€Ÿà€¹à¥ à€®à€à¥à€à€Ÿà€µ à€šà€Ÿà€¹à¥.</Description>
+  </SetLanguage>
+
+  <Element name="Title" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+      <Attribute name="identifier">Title</Attribute>
+      <Attribute name="definition">A name given to the resource.</Attribute>
+      <Attribute name="comment">Typically, a Title will be a name by which the resource is formally known.</Attribute>
+    </Language>
+
+    <!-- Maori -->
+    <Language code="mi">
+      <Attribute name="identifier">Taitara</Attribute>
+      <Attribute name="definition">Te ingoa ka tapaina tetahi rauemi.</Attribute>
+      <Attribute name="comment">Ko te tikanga, ko te Taitara te ingoa ka mohio whanuitia te ingoa.</Attribute>
+    </Language>
+
+    <!-- French -->
+    <Language code="fr">
+      <Attribute name="identifier">Titre</Attribute>
+      <Attribute name="definition">Le nom donnÃ© Ã  la ressource.</Attribute>
+      <Attribute name="comment">Typiquement, un titre sera le nom par lequel la ressource est officiellement connue.</Attribute>
+    </Language>
+
+    <!-- Russian -->
+    <Language code="ru">
+      <Attribute name="identifier">ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ</Attribute>
+      <Attribute name="definition">ÐÐŒÑ, ÐŽÐ°ÐœÐœÐŸÐµ ÑÐµÑÑÑÑÑ.</Attribute>
+      <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµÐŒ ÑÐ²Ð»ÑÐµÑÑÑ ÐžÐŒÑ, Ð¿ÐŸÐŽ ÐºÐŸÑÐŸÑÑÐŒ ÑÐµÑÑÑÑ ÐŸÑÐžÑÐžÐ°Ð»ÑÐœÐŸ ÐžÐ·Ð²ÐµÑÑÐµÐœ.</Attribute>
+    </Language>
+
+    <!-- Spanish -->
+    <Language code="es">
+      <Attribute name="identifier">TÃ­tulo</Attribute>
+      <Attribute name="definition">El nombre dado a un recurso, usualmente por el autor.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙØ¹ÙÙØ§Ù</Attribute>
+      <Attribute name="definition">ÙØ°Ø§ Ø§ÙØ§Ø³Ù
+ ÙØ¹Ø·Ù ÙÙÙ
+ØµØ¯Ø±, Ù
+Ù ÙØšÙ Ø§ÙÙ
+ØšØ¯Ø¹ Ø§Ù Ø§ÙÙØ§ØŽØ±</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">èµæºå</Attribute>
+      <Attribute name="definition">èµäºèµæºçåç§°ã</Attribute>
+      <Attribute name="comment">èµæºåäžè¬æèµæºå¯¹è±¡æ­£åŒå
+¬åŒçåç§°ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">NÃ¡zev</Attribute>
+      <Attribute name="definition">JmÃ©no danÃ© zdroji.</Attribute>
+      <Attribute name="comment">NÃ¡zev bude typicky jmÃ©no, pod nÃ­mÅŸ je zdroj oficiÃ¡lnÄ znÃ¡m.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Titel</Attribute>
+      <Attribute name="definition">De naam van de Internetbron. Meestal gegeven door de auteur, maker of uitgever</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language> 
+
+    <!-- Interlingua -->
+    <Language code="ia">
+      <Attribute name="identifier">Titulo</Attribute>
+      <Attribute name="definition">Un nomine date al ressource.</Attribute>
+      <Attribute name="comment">Typicamente se utiliza un nomine per le qual le ressource es formalmente cognite.</Attribute>
+    </Language>  
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€¶à¥à€°à¥à€·à€</Attribute>
+      <Attribute name="definition">à€ªà€°à¥à€¯à€Ÿà€¯à¥ à€¶à¥à€°à¥à€·à€</Attribute>
+      <Attribute name="comment">à€žà€à€à¥à€·à€¿à€ªà¥à€€ ,  à€­à€Ÿà€·à€Ÿà€à€€à€°à¥à€€  à€¶à¥à€°à¥à€·à€</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->	   
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Character String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Creator" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+      <Attribute name="identifier">Creator</Attribute>
+      <Attribute name="definition">An entity primarily responsible for making the content of the resource.</Attribute>
+      <Attribute name="comment">Examples of a Creator include a person, an organisation, or a service. Typically, the name of a Creator should be used to indicate the entity.</Attribute>
+    </Language>
+
+    <!-- Maori -->
+    <Language code="mi">
+      <Attribute name="identifier">Kaihanga</Attribute>
+      <Attribute name="definition">Te putahi, nana, na ratou ranei i matua oti ai te hanganga o te rauemi.</Attribute>
+      <Attribute name="comment">Ko te tangata, he putahitanga, he ratonga ranei etahi tauira Kaihanga. Ko te tikanga, ko te Kaihanga te ingoa ka whakamahia hei tohu i te putahi na ratou te hanganga.</Attribute>
+    </Language>
+
+    <!-- French -->
+    <Language code="fr">
+      <Attribute name="identifier">CrÃ©ateur</Attribute>
+      <Attribute name="definition">L'entitÃ© principalement responsable de la crÃ©ation du contenu de la ressource.</Attribute>
+      <Attribute name="comment">Exemples de CrÃ©ateur incluent une personne, une organisation, ou un service. Typiquement, un nom du CrÃ©ateur devrait Ãªtre utilisÃ© pour dÃ©signer cette entitÃ©.</Attribute>
+    </Language>
+
+    <!-- Russian -->
+    <Language code="ru">
+      <Attribute name="identifier">Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ</Attribute>
+      <Attribute name="definition">ÐÐžÑÐŸ, ÐœÐµÑÑÑÐµÐµ Ð¿ÐµÑÐ²ÐžÑÐœÑÑ ÐŸÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÐŸÑÑÑ Ð·Ð° ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+      <Attribute name="comment">ÐÑÐžÐŒÐµÑÑ Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð¿ÐµÑÑÐŸÐœÑ, ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ ÐžÐ»Ðž ÑÐ»ÑÐ¶Ð±Ñ. ÐÐ±ÑÑÐœÐŸ ÐžÐŒÑ Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐžÐž ÐŸÐ±ÑÐµÐºÑÐ°.</Attribute>
+    </Language>
+
+    <!-- Spanish -->
+    <Language code="es">
+      <Attribute name="identifier">Autor o Creador</Attribute>
+      <Attribute name="definition">La persona u organizaciÃ³n responsable de la creaciÃ³n del contenido intelectual del recurso. Por ejemplo, los autores en el caso de documentos escritos, artistas, fotografos e ilustradores en el caso de recursos visuales.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙÙØ§ØªØš Ø§Ù Ø§ÙÙ
+ØšØ¯Ø¹</Attribute>
+      <Attribute name="definition">ÙÙ Ø§ÙØŽØ®Øµ Ø§Ù Ø§ÙÙ
+Ø€Ø³Ø³Ø© Ø£ÙÙØ§  Ø¹Ù ÙØŽØŠ Ø§ÙÙ
+Ø­ØªÙÙ Ø§ÙÙÙØ± Ù ÙÙÙ
+ØµØ¯Ø± , Ø¹ÙÙ Ø³ØšÙÙ Ø§ÙÙ
+Ø«Ø§Ù , Ø§ÙÙ
+Ø€ÙÙÙÙ ÙÙ Ø­Ø§ÙØ© Ø§ÙØ«Ø§ØŠÙ Ø§ÙÙ
+ÙØªÙØšØ© , Ù Ø§ÙÙÙØ§ÙÙÙ , Ø§ÙÙ
+ØµÙØ±ÙÙ ÙÙ Ø­Ø§ÙØ© Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙÙ
+Ø±ØŠÙØ©</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">åå»ºè
+</Attribute>
+      <Attribute name="definition">åå»ºèµæºå
+å®¹çäž»èŠèŽ£ä»»è
+ã</Attribute>
+      <Attribute name="comment">åå»ºè
+çå®äŸå
+æ¬äžªäººïŒç»ç»ææé¡¹æå¡ãäžè¬èèšïŒçšåå»ºè
+çåç§°æ¥æ è¯è¿äžæ¡ç®ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">TvÅ¯rce</Attribute>
+      <Attribute name="definition">Entita primÃ¡rnÄ odpovÄdnÃ¡ za vytvoÅenÃ­ obsahu zdroje.</Attribute>
+      <Attribute name="comment">PÅÃ­klady TvÅ¯rce zahrnujÃ­ osobu, organizaci nebo sluÅŸbu. K oznaÄenÃ­ entity se typicky pouÅŸÃ­vÃ¡ jmÃ©no tvÅ¯rce.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Auteur of maker</Attribute>
+      <Attribute name="definition">De auteur, maker of organisatie die primair verantwoordelijk is voor de intellectuele inhoud van het werk. Bijvoorbeeld auteurs in geval van geschreven documenten, artiesten, fotografen of illustrators in geval van visuele bronnen.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+      <Attribute name="identifier">Creator</Attribute>
+      <Attribute name="definition">Le entitate primarimente responsabile pro producer le contento del ressource.</Attribute>
+      <Attribute name="comment">Exemplos de creator include un persona, un organization, o un servicio. Typicamente se utiliza un nomine de creator pro indicar iste entitate.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€šà€¿à€°à¥à€®à€Ÿà€€à€Ÿ, à€à€šà€</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ à€šà€¿à€°à¥à€®à€Ÿà€£  à€à€°à€£à€Ÿà€°à€Ÿ</Attribute>
+      <Attribute name="comment">à€à€Šà€Ÿ.  à€²à¥à€à€, à€²à¥à€à€¿à€à€Ÿ,  à€µà¥à€¯à€à¥à€€à¥, à€žà€à€žà¥à€¥à€Ÿ,  à€žà€à€ªà€Ÿà€Šà€, à€žà€à€ªà€Ÿà€Šà€¿à€à€Ÿ</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Subject" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Subject and Keywords</Attribute>
+    <Attribute name="definition">The topic of the content of the resource.</Attribute>
+    <Attribute name="comment">Typically, a Subject will be expressed as keywords, key phrases or classification codes that describe a topic of the resource. Recommended best practice is to select a value from a controlled vocabulary or formal classification scheme.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Kaupapa</Attribute>
+    <Attribute name="definition">Te take/ nga take o te kaupapa, o te rauemi.</Attribute>
+    <Attribute name="comment">Ko te tikanga, ka whakaaturia te kaupapa o te rauemi e nga kupu matua, nga kimahi matua, nga tohu wehewehenga whakaahua ranei.</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Sujet</Attribute>
+    <Attribute name="definition">Le sujet du contenu de la ressource.</Attribute>
+    <Attribute name="comment">Typiquement, le sujet sera dÃ©crit par un ensemble de mots-clefs ou de phrases ou un code de classification qui prÃ©cisent le sujet de la ressource. L'utilisation de vocabulaires contrÃŽlÃ©s et de schÃ©mas formels de classification est encouragÃ©e.</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">ÐÑÐµÐŽÐŒÐµÑ Ðž ÐºÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð°</Attribute>
+    <Attribute name="definition">Ð¢ÐµÐŒÐ° ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+    <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÐÑÐµÐŽÐŒÐµÑ Ð²ÑÑÐ°Ð¶Ð°ÐµÑÑÑ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐºÐ»ÑÑÐµÐ²ÑÑ
+ ÑÐ»ÐŸÐ², ÐºÐ»ÑÑÐµÐ²ÑÑ
+ ÑÑÐ°Ð· ÐžÐ»Ðž  ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÑÑ
+ ÐºÐŸÐŽÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÑÑ ÑÐµÐŒÑ ÑÐµÑÑÑÑÐ°. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ ÐžÐ»Ðž ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÑ
+ÐµÐŒÑ.</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Claves</Attribute>
+    <Attribute name="definition">Los tÃ³picos del recurso. TÃ­picamente, Subject expresarÃ¡ las claves o frases que describen el tÃ­tulo o el contenido del recurso. Se fomentarÃ¡ el uso de vocabularios controlados y de sistemas de clasificaciÃ³n formales. Se pueden ver ejemplos de vocabularios controlados en: Controlled vocabularies, thesauri and classification systems available in the WWW. DC Subject</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙÙ
+ÙØ¶ÙØ¹ Ù Ø§ÙÙÙÙ
+Ø§Øª Ø§ÙØ±ØŠÙØ³ÙØ©</Attribute>
+      <Attribute name="definition">ÙÙ Ù
+ÙØ¶ÙØ¹ Ø§ÙÙ
+ØµØ¯Ø±. ÙÙ
+ÙØ°Ø¬ÙØ§  ÙØ¹ØšØ± Ø¹Ù Ø§ÙÙ
+ÙØ¶ÙØ¹ ØšØ§Ø³ØªØ®Ø¯Ø§Ù
+Ù
+ÙØªØ§Ø­  Ø§ÙÙÙÙ
+Ø§Øª  Ø§Ù Ø¬Ù
+Ù Ø§ÙØªÙ  ØªØµÙ Ù
+ÙØ¶ÙØ¹ Ø§Ù Ù
+Ø­ØªÙÙ Ø§ÙÙ
+ØµØ¯Ø± , Ù ÙØ³ØªØ­Ø³Ù Ø§Ø³ØªØ®Ø¯Ø§Ù
+ Ù
+ÙØ±Ø¯Ø§Øª Ù
+Ø®Ø·Ø·Ø©Ù Ù
+Ø­ÙÙ
+Ø©  ÙØ§Ø¯ÙØ© ØªØµÙÙÙ ØŽÙÙÙØ©</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">äž»é¢åå
+³é®è¯</Attribute>
+      <Attribute name="definition">èµæºå
+å®¹çäž»é¢æè¿°ã</Attribute>
+      <Attribute name="comment">åŠæèŠæè¿°ç¹å®èµæºçæäžäž»é¢ïŒäžè¬éçšå
+³é®è¯ãå
+³é®å­ç­è¯­æåç±»å·ïŒæå¥œäž»é¢åå
+³é®è¯ä»åæ§    è¯è¡šæè§èçåç±»äœç³»äž­ååŒã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">PÅedmÄt a klÃ­ÄovÃ¡ slova</Attribute>
+      <Attribute name="definition">TÃ©ma obsahu zdroje.</Attribute>
+      <Attribute name="comment">PÅedmÄt bude typicky vyjÃ¡dÅen pomocÃ­ klÃ­ÄovÃœch slov, klÃ­ÄovÃœch frÃ¡zÃ­ nebo klasifikaÄnÃ­ch znakÅ¯ popisujÃ­cÃ­ch tÃ©ma zdroje. DoporuÄuje se vybÃ­rat hodnotu prvku z ÅÃ­zenÃ©ho slovnÃ­ku nebo formÃ¡lnÃ­ho klasifikaÄnÃ­ho schÃ©matu.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Onderwerp en trefwoorden</Attribute>
+      <Attribute name="definition">Het onderwerp van de Internetbron. Het onderwerp wordt beschreven in korte zinnen of door het gebruik van trefwoorden. Het gebruik van gecontroleerde trefwoorden of classificatie schema's wordt aanbevolen.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Subjecto e parolas-clave</Attribute>
+    <Attribute name="definition">Le topico del contento del ressource.</Attribute>
+    <Attribute name="comment">Typicamente le subjecto es expresse per medio de parolas-clave, phrases-clave, o codices de classification que describe le topico del ressource. Le melior practica recommendate es selectionar un valor a partir de un vocabulario controlate o un schema formal de classification.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€µà€¿à€·à€¯</Attribute>
+      <Attribute name="definition">à€µà€¿à€·à€¯</Attribute>
+      <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ, à€à¥à€à€Ÿà€šà€žà€Ÿà€§à€šà¥ à€¯à€Ÿà€€à¥à€² à€à€¶à€¯ à€žà¥à€ªà€·à¥à€ à€à€°à€£à€Ÿà€°à¥ à€¶à€¬à¥à€Š, à€µà€¿à€·à€¯à€Ÿà€à¥ à€µà€°à¥à€à¥à€à€°à€£ à€à€°à€€à€Ÿà€šà€Ÿ à€¶à€¬à¥à€Šà€žà€à€à¥à€°à€¹ à€
+à€¥à€µà€Ÿ à€¶à€¬à¥à€Š à€à¥à€·à€Ÿà€à€Ÿ à€µà€Ÿà€ªà€° à€à€°à€Ÿà€µà€Ÿ</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Description" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Description</Attribute>
+    <Attribute name="definition">An account of the content of the resource.</Attribute>
+    <Attribute name="comment">Description may include but is not limited to: an abstract, table of contents, reference to a graphical representation of content or a free-text account of the content.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">	
+    <Attribute name="identifier">Whakaaturanga</Attribute>
+    <Attribute name="definition">He whakaaturanga o nga kaupapa o te rauemi.</Attribute>
+    <Attribute name="comment">Ka uru atu, engari ehara noa ko: te whakarapopototanga korero, te ihirangi, te tohutanga o te kaupapa ma te whakaahua, te whakaaturanga kore kupu ranei, o te kauapapa.</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Description</Attribute>
+    <Attribute name="definition">Une description du contenu de la ressource.</Attribute>
+    <Attribute name="comment">Une Description peut contenir, mais ce n'est pas limitatif: un rÃ©sumÃ©, une table des matiÃšres, une rÃ©fÃ©rence Ã  une reprÃ©sentation graphique du contenu, ou un texte libre sur le contenu.</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">ÐÐ¿ÐžÑÐ°ÐœÐžÐµ</Attribute>
+    <Attribute name="definition">Ð¡ÐŸÐŸÐ±ÑÐµÐœÐžÐµ ÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐž ÑÐµÑÑÑÑÐ°.</Attribute>
+    <Attribute name="comment">ÐÐ¿ÐžÑÐ°ÐœÐžÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐŸ (Ð¿ÐŸ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÑÑÐž) Ð² Ð²ÐžÐŽÐµ: ÑÐµÑÐµÑÐ°ÑÐ°, ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÑ, ÑÑÑÐ»ÐºÐž ÐœÐ° Ð³ÑÐ°ÑÐžÑÐµÑÐºÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÐžÐ»Ðž Ð¿ÑÐŸÑÑÐŸÐ³ÐŸ ÑÐµÐºÑÑÐŸÐ²ÐŸÐ³ÐŸ ÐžÐ·Ð»ÐŸÐ¶ÐµÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ.</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">DescripciÃ³n</Attribute>
+    <Attribute name="definition">Una descripciÃ³n textual del recurso, tal como un resumen en el caso de un documento o una descripciÃ³n del contenido en el caso de un documento visual.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙÙØµÙ</Attribute>
+      <Attribute name="definition">ÙÙ ÙØµÙ ÙØµÙ  ÙÙ
+Ø­ØªÙÙ Ø§ÙÙ
+ØµØ¯Ø±, ÙÙØ¶Ù
+ Ø§ÙÙ
+ÙØ®ØµØ§Øª ÙÙ Ø­Ø§ÙØ© Ø§ÙÙØ«Ø§ØŠÙ Ù
+Ø«Ù Ø§ÙØ§ØŽÙØ§Ø¡ Ø§ÙÙ
+ÙØªÙØšØ© Ø§Ù ØªÙØµÙÙ Ø§ÙÙ
+Ø­ØªÙÙ ÙÙ Ø­Ø§ÙØ© Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙÙ
+Ø±ØŠÙØ©</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">è¯Žæ</Attribute>
+      <Attribute name="definition">èµæºå
+å®¹çè§£é</Attribute>
+      <Attribute name="comment">è¯Žæå¯ä»¥å
+æ¬äœäžéäºä»¥äžå
+å®¹ïŒææãç®åœãå¯¹ä»¥åŸåœ¢æ¥æ­ç€ºå
+å®¹çèµæºèèšçæå­è¯Žæãæè
+äž    äžªæå
+³èµæºå
+å®¹çèªç±ææ¬æè¿°ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">Popis</Attribute>
+      <Attribute name="definition">VysvÄtlenÃ­ obsahu zdroje.</Attribute>
+      <Attribute name="comment">Popis mÅ¯ÅŸe obsahovat (mimo jinÃ©): abstrakt, obsah, odkaz na grafickÃ© nebo volnÃ© textovÃ© vyjÃ¡dÅenÃ­ obsahu.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Omschrijving</Attribute>
+      <Attribute name="definition">Een omschrijving van de inhoud van de Internetbron. Abstracts of inhoudsomschrijvingen.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Description</Attribute>
+    <Attribute name="definition">Un description del contento del ressource.</Attribute>
+    <Attribute name="comment">Le description pote includer, ma non se limita a: summario, indice, referentia a un representation graphic del contento o un texto libere a proposito del contento.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€µà€°à¥à€£à€š</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥, à€à¥à€à€Ÿà€šà€žà€Ÿà€§à€šà€Ÿà€à¥à€µà€°à¥à€£à€š</Attribute>
+      <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€šà€¿à€µà¥à€Šà€š, à€à€²à¥à€, à€à€¿à€€à¥à€°à€°à¥à€ª</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Publisher" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Publisher</Attribute>
+    <Attribute name="definition">An entity responsible for making the resource available.</Attribute>
+    <Attribute name="comment">Examples of a Publisher include a person, an organisation, or a service. Typically, the name of a Publisher should be used to indicate the entity.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Kaiwhakaputa</Attribute>
+    <Attribute name="definition">Te putahi nana i whakaputa te rauemi.</Attribute>
+    <Attribute name="comment">Ko te tangata, he putahitanga, he ratonga ranei etahi tauira Kaiwhakaputa. Ko te tikanga, ka whakamahia te ingoa o te Kaiwhakaputa hei tohu i te putahi.</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Editeur</Attribute>
+    <Attribute name="definition">L'entitÃ© responsable de la diffusion de la ressource, dans sa forme actuelle, tels, un dÃ©partement universitaire, une entreprise.</Attribute>
+    <Attribute name="comment">Exemples d'Editeurs incluent une personne, une organisation, ou un service. Typiquement, le nom d'une maison d'Ã©dition devrait Ãªtre utilisÃ© ici.</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">ÐÐ·ÐŽÐ°ÑÐµÐ»Ñ</Attribute>
+    <Attribute name="definition">ÐÐžÑÐŸ, ÐŸÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÐŸÐµ Ð·Ð° Ð²Ð²ÐŸÐŽ ÑÐµÑÑÑÑÐ° Ð² ÐŸÐ±ÑÐ°ÑÐµÐœÐžÐµ.</Attribute>
+    <Attribute name="comment">ÐÑÐžÐŒÐµÑÑ ÐÐ·ÐŽÐ°ÑÐµÐ»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð¿ÐµÑÑÐŸÐœÑ, ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ ÐžÐ»Ðž ÑÐ»ÑÐ¶Ð±Ñ. ÐÐ±ÑÑÐœÐŸ ÐžÐŒÑ ÐÐ·ÐŽÐ°ÑÐµÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐžÐž ÐŸÐ±ÑÐµÐºÑÐ°.</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Editor</Attribute>
+    <Attribute name="definition">>La entidad responsable de hacer que el recurso se encuentre disponible en la red en su formato actual, por ejemplo la empresa editora, un departamento universitario u otro tipo de organizaciÃ³n.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙÙØ§ØŽØ±</Attribute>
+      <Attribute name="definition">ÙÙ Ø§ÙÙÙØŠØ© Ø§ÙÙ
+Ø³Ø€ÙÙØ© Ø¹Ù ØµÙØ§Ø¹Ø© Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙÙ
+ØªÙÙØ± ÙÙ Ø­Ø§ÙØªÙ Ø§ÙØ­Ø§Ø¶Ø±Ø©, Ù
+Ø«Ù Ø¯Ø§Ø± Ø§ÙÙØŽØ±, ÙØ³Ù
+ Ø¬Ø§Ù
+Ø¹Ù Ø§Ù Ù
+Ø€Ø³Ø³Ø© Ø§Ø¹Ù
+Ø§Ù</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">åºçè
+</Attribute>
+      <Attribute name="definition">äœ¿èµæºæäžºå¯ä»¥è·åŸå¹¶å¯çšçèŽ£ä»»è
+ã</Attribute>
+      <Attribute name="comment">åºçè
+çå®äŸå
+æ¬äžªäœïŒç»ç»ïŒææå¡ãäžè¬èèšïŒåºè¯¥çšåºçè
+çåç§°æ¥æ è¯è¿äžæ¡ç®ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">Vydavatel</Attribute>
+      <Attribute name="definition">Entita odpovÄdnÃ¡ za zpÅÃ­stupnÄnÃ­ zdroje.</Attribute>
+      <Attribute name="comment">PÅÃ­klady Vydavatele zahrnujÃ­ osobu, organizaci nebo sluÅŸbu. K oznaÄenÃ­ entity se typicky pouÅŸÃ­vÃ¡ jmÃ©no vydavatele.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Uitgever</Attribute>
+      <Attribute name="definition">De entiteit die verantwoordelijk is voor het beschikbaarstellen van de Internetbron in de huidig vorm. Bijvoorbeeld een uitgeversbedrijf, een universiteitsafdeling.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Editor</Attribute>
+    <Attribute name="definition">Un entitate responsabile pro disponibilizar le ressource.</Attribute>
+    <Attribute name="comment">Exemplos de editor include un persona, un organization, o un servicio. Typicamente se utiliza un nomine de editor pro indicar le entitate.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€ªà¥à€°à€à€Ÿà€¶à€</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ  à€à€ªà€²à€¬à¥à€§ à€à€°à¥à€š à€Šà¥à€£à€Ÿà€°à€Ÿ</Attribute>
+      <Attribute name="comment">à€à€Šà€Ÿ.à€ à€ªà¥à€°à€à€Ÿà€¶à€ , à€ªà¥à€°à€à€Ÿà€¶à€š  à€žà€à€žà¥à€¥à€Ÿ, à€žà¥à€µà€Ÿ    à€®à€Ÿà€¹à€¿à€€à¥ à€à€Ÿà€ªà¥à€² à€°à¥à€ªà€Ÿà€€  à€
+à€¥à€µà€Ÿ à€à€à€à€°à€šà¥à€ à€µà€° à€à€ªà€²à€¬à¥à€§ à€à€°à¥à€š à€Šà¥à€£à€Ÿà€°à€Ÿ</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Contributor" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Contributor</Attribute>
+    <Attribute name="definition">An entity responsible for making contributions to the content of the resource.</Attribute>
+    <Attribute name="comment">Examples of a Contributor include a person, an organisation, or a service. Typically, the name of a Contributor should be used to indicate the entity.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Kaiwhakaaro</Attribute>
+    <Attribute name="definition">Te putahi nana, na ratou ranei nga whakakaupapatanga whakaaro o te rauemi.</Attribute>
+    <Attribute name="comment">Ko te tangata, he putahitanga, he ratonga ranei etahi tauira Kaiwhakaaro. Ko te tikanga ka whakamahia te ingoa o te Kaiwhakaaro hei tohu i te putahi.</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Contributeur</Attribute>
+    <Attribute name="definition">Une entitÃ© qui a contribuÃ© Ã  la crÃ©ation du contenu de la ressource.</Attribute>
+    <Attribute name="comment">Exemples de Contributeur incluent une personne, une organisation, ou un service. Typiquement, le nom d'un contributeur devrait Ãªtre utilisÃ© ici pour dÃ©signer l'entitÃ©.</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">Ð¡ÐŸÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ</Attribute>
+    <Attribute name="definition">ÐÐžÑÐŸ, Ð²ÐœÐµÑÑÐµÐµ Ð²ÐºÐ»Ð°ÐŽ Ð² ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+    <Attribute name="comment">ÐÑÐžÐŒÐµÑÑ Ð¡ÐŸÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð¿ÐµÑÑÐŸÐœÑ, ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ ÐžÐ»Ðž ÑÐ»ÑÐ¶Ð±Ñ. ÐÐ±ÑÑÐœÐŸ ÐžÐŒÑ Ð¡ÐŸÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐžÐž ÐŸÐ±ÑÐµÐºÑÐ°.</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Otros Colaboradores</Attribute>
+    <Attribute name="definition">Una persona u organizacion que haya tenido una contribuciÃ³n intelectual significativa en la creaciÃ³n del recurso pero cuyas contribuciones son secundarias en comparaciÃ³n a las de las personas u organizaciones especificadas en el elementeo Creator (por ejemplo, editor, ilustrador y traductor).</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙÙ
+Ø³Ø§ÙÙ
+ Ø§ÙØ§Ø®Ø±</Attribute>
+      <Attribute name="definition">ÙÙ Ø§ÙØŽØ®Øµ Ø§Ù Ø§ÙÙ
+Ø€Ø³Ø³Ø© Ø§ÙØºÙØ± Ù
+Ø°ÙÙØ± ØµØ±Ø§Ø­Ø© ÙÙ Ø¹Ø§Ù
+Ù " Ø§ÙÙ
+ØšØ¯Ø¹ " Ù Ø§ÙØ°Ù ÙØ¯Ù
+ Ù
+Ø³Ø§ÙÙ
+Ø§Øª ÙÙØ±ÙØ© ÙØ§Ù
+Ø© ÙÙÙ
+ØµØ¯Ø±, ÙÙÙ Ù
+Ø³Ø§ÙÙ
+ØªÙØªØšÙÙ    Ø«Ø§ÙÙÙØ© Ù
+ÙØ§Ø±ÙØ© Ù
+Ø¹ Ø§ÙØŽØ®Øµ Ø£Ù Ø§ÙÙ
+Ø€Ø³Ø³Ø© Ø§ÙÙ
+Ø°ÙÙØ±Ø© ÙØµØ§ ÙÙ Ø¹Ø§Ù
+Ù " Ø§ÙÙ
+ÙØŽØŠ " Ù
+Ø«ÙØ§Ù Ù
+ØµØ­Ø­, Ø§ÙÙ
+ØªØ±Ø¬Ù
+, Ø§Ù Ø§ÙÙ
+ÙØ³Ø±</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">å
+¶ä»èŽ£ä»»è
+</Attribute>
+      <Attribute name="definition">å¯¹èµæºçå
+å®¹äœåºèŽ¡ç®çå
+¶ä»å®äœã</Attribute>
+      <Attribute name="comment">å
+¶ä»èŽ£ä»»è
+çå®äŸå¯å
+æ¬äžªäººãç»ç»ææé¡¹æå¡ãäžè¬èèšïŒçšå
+¶ä»èŽ£ä»»è
+çåå­æ¥æ è¯è¿äžæ¡ç®ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">PÅispÄvatel</Attribute>
+      <Attribute name="definition">Entita, kterÃ¡ pÅispÄla k vytvoÅenÃ­ obsahu zdroje.</Attribute>
+      <Attribute name="comment">PÅÃ­klady PÅispÄvatele zahrnujÃ­ osobu, organizaci nebo sluÅŸbu. K oznaÄenÃ­ entity se typicky pouÅŸÃ­vÃ¡ jmÃ©no pÅispÄvatele.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Andere medewerkers</Attribute>
+      <Attribute name="definition">Een persoon of organisatie die een belangrijke bijdrage heeft geleverd, maar die secondair is aan de persoon of organisatie die bij "Creator" genoemd wordt. Gedacht kan worden aan editors, vertalers en illustrators.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Contribuente</Attribute>
+    <Attribute name="definition">Un entitate responsabile pro facer contributiones al contento del ressource.</Attribute>
+    <Attribute name="comment">Exemplos de contribuente include un persona, un organization, o un servicio. Typicamente se utiliza un nomine de contribuente pro indicar le entitate.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier"> à€žà€¹à€¯à¥à€à€, à€žà€¹à€¯à¥à€à¥, à€žà€¹à€Ÿà€¯à¥à€¯à€</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ à€žà€à€à€²à¥à€€ à€à€°à€£à¥à¥à€Ÿà€ž  à€®à€Šà€€ à€à€°à€£à€Ÿà€°à¥ à€µà¥à€¯à€à¥à€€à¥</Attribute>
+      <Attribute name="comment">à€à€Šà€Ÿ.à€ à€µà¥à€¯à€à¥à€€à¥, à€žà¥à€µà€Ÿ, à€žà€à€žà¥à€¥à€Ÿ</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Date" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Date</Attribute>
+    <Attribute name="definition">A date associated with an event in the life cycle of the resource.</Attribute>
+    <Attribute name="comment">Typically, Date will be associated with the creation or availability of the resource.  Recommended best practice for encoding the date value is defined in a profile of ISO 8601 and follows the YYYY-MM-DD format.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Ra</Attribute>
+    <Attribute name="definition">He ra e whai panga ana ki te huringa ora o te rauemi.</Attribute>
+    <Attribute name="comment">Ko te tikanga, ka whai panga te ra ki te hanganga, te wateatanga ranei, o te rauemi. Ko te huarahi tino pai hei tohu i te uara o te ra (date value) kua whakaritea i roto i te whakaritenga IS0 8601 [W3CDTF], a, e whai atu ana ki te whakatakotoranga YYYY-MM-DD.</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Date</Attribute>
+    <Attribute name="definition">Une date associÃ©e avec un Ã©vÃ©nement dans le cycle de vie de la ressource.</Attribute>
+    <Attribute name="comment">Typiquement, une date sera associÃ©e Ã  la crÃ©ation ou Ã  la publication d'une ressource. Il est fortement recommandÃ© d'encoder la valeur de la date en utilisant le format dÃ©fini par l'ISO 8601 [W3CDTF] sous la forme AAAA-MM-JJ.</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">ÐÐ°ÑÐ°</Attribute>
+    <Attribute name="definition">ÐÐ°ÑÐ°, ÑÐ²ÑÐ·Ð°ÐœÐœÐ°Ñ Ñ ÑÐŸÐ±ÑÑÐžÐµÐŒ Ð² Ð¶ÐžÐ·ÐœÐµÐœÐœÐŸÐŒ ÑÐžÐºÐ»Ðµ ÑÐµÑÑÑÑÐ°.</Attribute>
+    <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÐÐ°ÑÐ° Ð°ÑÑÐŸÑÐžÐžÑÑÐµÑÑÑ Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµÐŒ ÐžÐ»Ðž ÐŽÐŸÑÑÑÐ¿ÐœÐŸÑÑÑÑ ÑÐµÑÑÑÑÐ°. ÐÐ° Ð¿ÑÐ°ÐºÑÐžÐºÐµ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐŽÐ»Ñ ÐºÐŸÐŽÐžÑÐŸÐ²ÐºÐž Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŽÐ°ÑÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÐµ Ð¿ÑÐŸÑÐžÐ»Ñ ISO 8601 (Ð€ÐŸÑÐŒÐ°ÑÑ ÐŽÐ°ÑÑ Ðž Ð²ÑÐµÐŒÐµÐœÐž W3C), ÐºÐŸÑÐŸÑÐŸÐµ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÐµÑ ÑÐŸÑÐŒÐ°Ñ ÐÐÐÐ-ÐÐ-ÐÐ.</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Fecha</Attribute>
+    <Attribute name="definition">Una fecha en la que el recurso se puso a disposiciÃ³n del usuario en su forma actual. Esta fecha no ha de confundirse con la que pertenece al elemento Coverage, que serÃ­a asociada con el recurso sÃ³lo en la medida en que el contenido intelectual estÃ¡ de algÃºn modo relacionado con esa fecha. Recomendamos la utiliazaciÃ³n de uno de los formatos definidos en el documento "Date and Time Formats", http://www.w3.org/TR/NOTE-datetime basado en la norma ISO 8601 que incluye, entre otras, fechas en el formato AAAA y AAAA-MM-DD. De esta forma la fecha 1994-11-05 corresponderÃ­a al 5 de Noviembre de 1994.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙØªØ§Ø±Ø®</Attribute>
+      <Attribute name="definition">ÙÙ Ø§ÙØªØ§Ø±ÙØ® Ø§ÙÙ
+ØªØ¹ÙÙ ØšÙÙØª ÙØŽØŠ Ø£Ù ØªÙÙØ± Ø§ÙÙ
+ØµØ¯Ø± . Ù ÙØ¬Øš Ø£Ù ÙØ§ ÙØ®ÙØ· ÙØ°Ø§ Ø§ÙØªØ§Ø±ÙØ® Ø§ÙØ¹Ø§ØŠØ¯ ÙØ¹Ø§Ù
+Ù Ø§ÙØªØºØ·ÙØ© , Ù Ø§ÙØ° Ù ÙØ¬Øš Ø£Ù    ÙÙØ­Ù ØšØ§ÙÙ
+ØµØ¯Ø± ÙÙØ· Ù
+Ù ÙØ§Ø­ÙØ© Ø§ÙÙ
+Ø­ØªÙÙØ§ÙÙÙØ±Ù ÙÙÙÙÙ ÙÙØ¹Ø§ Ù
+Ø§ ÙÙ ÙØ°Ø§ Ø§ÙØªØ§Ø±ÙØ®. Ø§ÙØµÙØºØ© Ø§ÙÙ
+Ø³Ø«Ø­Ø³ÙØ© ÙÙØ§Ø­Ø³Ù Ø§ÙÙ
+ØªØ¹Ø§Ø±Ù Ø¹ÙÙÙ    Ø¹ÙØ¯ Ø§ÙØªØ·ØšÙÙ ÙÙ Ø§ÙØµÙØºØ© Ø§ÙÙ
+Ø¹ØªÙ
+Ø¯Ø© ÙÙ ØªØŽÙÙÙ (ISO 8601) ØµÙØºØ© ØªØ§Ø±ÙØ® Ø§ÙÙÙÙ
+ Ù Ø§ÙÙÙØª ) Ø§Ø¹ØªÙ
+Ø§Ø¯Ø§ Ø¹ÙÙ (ISO 8601) Ø§ÙÙ
+ÙØ§Ø­ØžØ© Ø§ÙÙÙÙØ© http://www.w3.org/TR/NOTE-datetime, W3C. ÙÙÙ    ÙØ°Ø§ Ø§ÙÙØ³Ù , Ù
+Ø«ÙØ§, ØªØ§Ø±ÙØ® Ø§ÙÙÙÙ
+ 1994-11-04 ÙÙØ§ØžØ± ÙÙÙ
+ 5 ÙÙÙÙ
+ØšØ± 1994</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">æ¥æ</Attribute>
+      <Attribute name="definition">äžèµæºçåœåšæäž­çäžäžªäºä»¶çžå
+³çæ¶éŽã</Attribute>
+      <Attribute name="comment">äžè¬èèšïŒæ¥æåºäžèµæºçåå»ºæåºçæ¥æçžå
+³ãå»ºè®®éçšçæ¥ææ ŒåŒåºç¬ŠåISO 8601 [W3CDTF]è§    èïŒå¹¶äœ¿çšYYYY-MM-DDçæ ŒåŒã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">Datum</Attribute>
+      <Attribute name="definition">Datum spojenÃ© s urÄitou udÃ¡lostÃ­ bÄhem existence zdroje.</Attribute>
+      <Attribute name="comment">Datum bude typicky spojeno s vytvoÅenÃ­m nebo zpÅÃ­stupnÄnÃ­m zdroje. DoporuÄenÃœ postup pro kÃ³dovÃ¡nÃ­ hodnoty data je definovÃ¡n v ISO 8601 [W3CDTF]: formÃ¡t RRRR-MM-DD.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Datum</Attribute>
+      <Attribute name="definition">De datum van de totstandkoming of beschikbaarstelling van een Internetbron. Deze datum moet niet verward worden met de datum in "Coverage". De datum in "Coverage" geeft de tijdsperiode van de inhoud van de Internetbron aan. Voorgeschreven wordt de ISO 8601 standaard voor datum, zoals beschreven in W3C Technical Note http://www.w3.org/TR/NOTE-datetime. Hierin wordt het formaat YYYY-MM-DD beschreven. Het formaat YYYY-MM-DD wordt de voorgeschreven standaard. 3 September 1998 wordt in dit geval 1998-09-03.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Data</Attribute>
+    <Attribute name="definition">Un data associate a un evento in le cyclo vital del ressource.</Attribute>
+    <Attribute name="comment">Typicamente le data es associate al creation o disponibilization del ressource. Le practica recommendate pro codificar le valor del datas es definite in un profilo de ISO 8601 [W3CDTF] e seque le formato AAAA-MM-DD.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€€à€Ÿà€°à¥à€,  à€Šà€¿à€šà€Ÿà€à€</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ à€€à€¯à€Ÿà€° à€à¥à€²à¥à€¯à€Ÿà€à¥ à€€à€Ÿà€°à¥à€</Attribute>
+      <Attribute name="comment">à€€à€Ÿà€°à¥à€  à€²à€¿à€¹à¥à€£à¥à€¯à€Ÿà€à¥ à€žà¥à€µà€°à¥à€ª à€ à€µà€°à¥à€·. à€®à€¹à€¿à€šà€Ÿ. à€Šà€¿à€µà€ž
+à¥§à¥¯à¥«à¥Š. à¥Šà¥ª. à¥Šà¥ª</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Type" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Resource Type</Attribute>
+    <Attribute name="definition">The nature or genre of the content of the resource.</Attribute>
+    <Attribute name="comment">Type includes terms describing general categories, functions, genres, or aggregation levels for content. Recommended best practice is to select a value from a controlled vocabulary (for example, the working draft list of Dublin Core Types). To describe the physical or digital manifestation of the resource, use the FORMAT element.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Tumomo</Attribute>
+    <Attribute name="definition">Te ahua, te tu-ahuatanga ranei o nga kaupapa o te rauemi.</Attribute>
+    <Attribute name="comment">Kei roto i te Tumomo nga kupu whakaatu i nga wehewehenga whanui, nga aheinga, nga tu-ahuatanga, te whakaritenga ranei o nga taumata o te/ nga kaupapa. Ko te huarahi tino pai kua tohua, ko te tipako i tetahi uara mai i nga kupu kua whakaritea (hei tauira, ko te tauira rarangi e whakamahia ana o nga Dublin Core Types [DCT1]. Hei whakaatu i te whakatinanatanga o te rauemi, whakamahia ko te huanga WHAKATAKOTORANGA (FORMAT).</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Type</Attribute>
+    <Attribute name="definition">La nature ou le genre du contenu de la ressource.</Attribute>
+    <Attribute name="comment">Type inclut des termes dÃ©crivant des catÃ©gories, fonctions ou genres gÃ©nÃ©raux pour le contenu, ou des niveaux d'agrÃ©gation. Il est recommandÃ© de choisir la valeur du type dans une liste de vocabulaire contrÃŽlÃ© (par exemple, la liste provisoire de Types du Dublin Core[DCT1]). Pour dÃ©crire la matÃ©rialisation physique ou digitale de la ressource, il faut utiliser l'Ã©lÃ©ment Format.</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">Ð¢ÐžÐ¿ ÑÐµÑÑÑÑÐ°</Attribute>
+    <Attribute name="definition">ÐÑÐžÑÐŸÐŽÐ° ÐžÐ»Ðž Ð¶Ð°ÐœÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+    <Attribute name="comment">Ð¢ÐžÐ¿ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÑÐµÑÐŒÐžÐœÑ, ÐŸÐ¿ÐžÑÑÐ²Ð°ÑÑÐžÐµ ÐŸÐ±ÑÐžÐµ ÐºÐ°ÑÐµÐ³ÐŸÑÐžÐž, ÑÑÐœÐºÑÐžÐž, Ð¶Ð°ÐœÑÑ ÐžÐ»Ðž ÐŸÐ±ÑÐµÐŽÐžÐœÐµÐœÐœÑÐµ ÑÑÐŸÐ²ÐœÐž ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐ°Ð±ÐŸÑÐµÐ³ÐŸ Ð¿ÑÐŸÐµÐºÑÐ° ÑÐ¿ÐžÑÐºÐ° Ð¢ÐžÐ¿ÐŸÐ² Dublin Core DCT1). ÐÐ»Ñ ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ ÑÐžÐ·ÐžÑÐµÑ-ÐºÐŸÐ³ÐŸ ÐžÐ»Ðž ÑÐžÑÑÐŸÐ²ÐŸÐ³ÐŸ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÑÐµÑÑÑÑÐ° ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÑÐ»ÐµÐŒÐµÐœÑ Ð€ÐŸÑÐŒÐ°Ñ.</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Tipo del Recurso</Attribute>
+    <Attribute name="definition">La categorÃ­a del recurso, por ejemplo pÃ¡gina personal, romance, poema, minuta, diccionario. Para asegurar la interoperabilidad, Type deberÃ­a ser seleccionado de entre una lista de valores que actualmente se encuentra bajo desarrollo en un grupo de trabajo. En http://sunsite.berkeley.edu/Metadata/types.html se puede consultar el estado actual de la discusiÃ³n en torno a este tema.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">ÙÙØ¹ Ø§ÙÙ
+ØµØ¯Ø±</Attribute>
+      <Attribute name="definition">ÙÙ ÙØŠØ© Ø§ÙÙ
+ØµØ¯Ø± , Ù
+Ø«ÙØ§ Ø§ÙØµÙØ­Ø© Ø§ÙØ§Ù
+, Ø±ÙØ§ÙØ© , ÙØ·Ø¹Ø© ØŽØ¹Ø±ÙØ© , ÙØ±ÙØ© Ø¹Ù
+Ù , ØªÙØ±ÙØ± ÙÙÙ , Ù
+ÙØ§Ù , ÙØ§Ù
+ÙØ³ . Ù Ù
+Ù Ø£Ø¬Ù Ø§ÙØªØ¹Ø§Ù
+Ù Ø§ÙÙ
+ØŽØªØ±Ù    ÙØ¬Øš Ø£Ù ÙØ®ØªØ§Ø± Ø§ÙÙÙØ¹ Ù
+Ù Ø§ÙÙØ§ØŠÙ
+Ø© Ø§ÙÙ
+Ø±ÙÙ
+Ø© ÙØ§ÙØªÙ ÙÙÙ
+ Ø§Ø¹Ø¯Ø§Ø¯ÙØ§ Ø­Ø§ÙÙØ§ Ø¶Ù
+Ù Ø­ÙÙØ§Øª ÙØ±ØŽØ© Ø¹Ù
+Ù</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">èµæºç±»å</Attribute>
+      <Attribute name="definition">èµæºå
+å®¹çç¹åŸæç±»åã</Attribute>
+      <Attribute name="comment">èµæºç±»åå
+æ¬æè¿°èµæºå
+å®¹çäžè¬èçŽïŒåèœïŒç§å±ïŒæèç±»å±æ¬¡çæ¯è¯­ãå»ºè®®éçšæ¥èªäºåæ§è¯è¡š    äž­çåŒïŒäŸåŠDCMIç±»åè¯æ±è¡š[DCMITYPE]ïŒãèŠæè¿°èµæºçç©çææ°å­åè¡šç°åœ¢åŒïŒè¯·äœ¿çšâæ ŒåŒïŒFORMATïŒâå
+çŽ ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">Typ zdroje</Attribute>
+      <Attribute name="definition">Povaha nebo druh obsahu zdroje.</Attribute>
+      <Attribute name="comment">Typ obsahuje termÃ­ny popisujÃ­cÃ­ obecnÃ© kategorie, funkce, druhy nebo agregaÄnÃ­ ÃºrovnÄ obsahu. DoporuÄuje se vybÃ­rat hodnotu z ÅÃ­zenÃ©ho slovnÃ­ku (napÅ. pracovnÃ­ nÃ¡vrh seznamu TypÅ¯ Dublin Core [DCT1]). K popisu fyzickÃ© nebo digitÃ¡lnÃ­ reprezentace zdroje uÅŸijte prvek FormÃ¡t.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Bestands type</Attribute>
+      <Attribute name="definition">Het soort Internetbron, bijvoorbeeld home page, gedicht, working paper, technical report, essay, woordenboek etc. De DC working groups zijn momenteel bezig met twee voorstellen; een minimalist draft: http://sunsite.berkeley.edu/Metadata/minimalist.html en een structuralist draft: http://sunsite.berkely.edu/Metadata/structuralist.html. Het wordt sterk aanbevolen om "Type" van deze lijsten te selecteren.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Typo del ressource</Attribute>
+    <Attribute name="definition">Le natura o genere del contento del ressource.</Attribute>
+    <Attribute name="comment">Le typo del ressource include terminos que describe categorias general, functiones, generes, o nivellos de aggregation pro le contento. Le practica recommendate es selectionar un valor a partir de un vocabulario controlate (per exemplo, le lista de schizzos de travalio de typos de Dublin Core [DCT1]). Pro describer le manifestation physic o digital del ressource, utiliza le elemento Formato.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€ªà¥à€°à€à€Ÿà€°</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à€Ÿà€ªà¥à€°à€à€Ÿà€°</Attribute>
+      <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€µà€°à¥à€à¥à€à€°à€£, à€µà€°à¥à€à€µà€Ÿà€°à¥à€®à€§à¥à€¯à¥ à€à€à€Ÿà€Šà¥à€¯à€Ÿ à€šà¥à€à€Šà¥à€à€Ÿ à€®à¥à€à¥à€¯ à€à€à€ªà¥à€°à€à€Ÿà€°</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Format" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Format</Attribute>
+    <Attribute name="definition">The physical or digital manifestation of the resource.</Attribute>
+    <Attribute name="comment">Typically, Format may include the media-type or dimensions of the resource. Format may be used to determine the software, hardware or other equipment needed to display or operate the resource. Examples of dimensions include size and duration. Recommended best practice is to select a value from a controlled vocabulary (for example, the list of Internet Media Types [MIME] defining computer media formats).</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Whakatakotoranga</Attribute>
+    <Attribute name="definition">Te whakatinanatanga, te whakaputanga a-mati o te rauemi.</Attribute>
+    <Attribute name="comment">Ko te tikanga, ka taea te Whakatakotoranga te whakamahi hei whakarite i te rawa-ngohe (software), te rawa-maro (hardware), ma etahi taputapu ranei me matua whiwhi, hei whakahaere i te rauemi. Ko te rahi me te roanga etahi tauira hanga. Ko te tino huarahi kua tohua ko te tipako uara mai i tetahi whakaritenga kupu (hei tauira, te rarangi o nga Tumomo Papaho Ipurangi (Internet Media Types [MIME]) e whakaatu ana i nga whakatakotoranga papaho rorohiko.</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Format</Attribute>
+    <Attribute name="definition">La matÃ©rialisation physique ou digitale de la ressource.</Attribute>
+    <Attribute name="comment">Typiquement, Format peut inclure le media ou les dimensions de la ressource. Format peut Ãªtre utilisÃ© pour prÃ©ciser le logiciel, le matÃ©riel ou autre Ã©quipement nÃ©cessaire pour afficher ou faire fonctionner la ressource. Exemples de dimensions incluent la taille et la durÃ©e. Il est recommandÃ© de choisir la valeur du format dans une liste de vocabulaire contrÃŽlÃ©(par exemple, la liste des types de media dÃ©finis sur Internet [MIME]).</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">Ð€ÐŸÑÐŒÐ°Ñ</Attribute>
+    <Attribute name="definition">Ð€ÐžÐ·ÐžÑÐµÑÐºÐŸÐµ ÐžÐ»Ðž ÑÐžÑÑÐŸÐ²ÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐµÑÑÑÑÐ°.</Attribute>
+    <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ Ð€ÐŸÑÐŒÐ°Ñ ÐŒÐŸÐ¶ÐµÑ Ð²ÐºÐ»ÑÑÐ°ÑÑ ÑÐžÐ¿ Ð°ÑÐŽÐžÐŸÐ²ÐžÐ·ÑÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž (ÐŒÐµÐŽÐžÐ°-ÑÐžÐ¿) ÐžÐ»Ðž Ð²ÐµÐ»ÐžÑÐžÐœÑ ÑÐµÑÑÑÑÐ°. Ð€ÐŸÑÐŒÐ°Ñ ÐŒÐŸÐ¶ÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ ÐŽÐ»Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ Ð°Ð¿Ð¿Ð°ÑÐ°ÑÐœÐŸÐ³ÐŸ, Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐ³ÐŸ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ ÐžÐ»Ðž ÐŽÑÑÐ³ÐŸÐ³ÐŸ ÐŸÐ±ÐŸÑÑÐŽÐŸÐ²Ð°ÐœÐžÑ, ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÐ³ÐŸ ÐŽÐ»Ñ Ð²ÐŸÑÐ¿ÑÐŸÐžÐ·Ð²ÐµÐŽÐµÐœÐžÑ ÐžÐ»Ðž ÑÐ°Ð±ÐŸÑÑ Ñ ÑÐµÑÑÑÑÐŸÐŒ. ÐÑÐžÐŒÐµÑÑ Ð²ÐµÐ»ÐžÑÐžÐœÑ Ð²ÐºÐ»ÑÑÐ°ÑÑ ÑÐ°Ð·ÐŒÐµÑ Ðž Ð¿ÑÐŸÐŽÐŸÐ»Ð¶ÐžÑÐµÐ»ÑÐœÐŸÑÑÑ. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐ¿ÐžÑÐºÐ° ÐÐµÐŽÐžÐ°-ÑÐžÐ¿ÐŸÐ² ÐÐœÑÐµÑÐœÐµÑ MIME, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÑÑÐµÐ³ÐŸ ÐºÐŸÐŒÐ¿ÑÑÑÐµÑÐœÑÐµ ÑÐŸÑÐŒÐ°ÑÑ Ð°ÑÐŽÐžÐŸÐ²ÐžÐ·ÑÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž).</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Formato</Attribute>
+    <Attribute name="definition">El formato de datos de un recurso, usado para identificar el software y posiblemente, el hardware que se necesitarÃ­a para mostrar el recurso. Para asegurar la interoperabilidad, los valores de Format deberÃ­an ser seleccionados de entre una lista de valores que actualmente se encuentra bajo desarrollo en un grupo de trabajo.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙØµÙØºØ©</Attribute>
+      <Attribute name="definition">ÙØ°Ù ØµÙØºØ© Ø§ÙÙ
+Ø¹ÙÙÙ
+Ø© Ø§ÙØ®Ø§ØµØ© ØšØ§ÙÙ
+ØµØ¯Ø± , Ù ØªØ³ØªØ®Ø¯Ù
+ ÙÙØªØ¹Ø±ÙÙ ØšØ§ÙØšØ±Ù
+Ø¬ÙØ§Øª ÙØ±ØšÙ
+Ø§ Ø§ÙØµÙØš ÙÙØ­Ø§Ø³ÙØš Ù Ø§ÙØªÙ ÙÙ
+ÙÙ Ø£Ù ÙØ­ØªØ§Ø¬    ÙÙØ§ ÙØ¹Ø±Ø¶ Ø£Ù ØªØŽØºÙÙ Ø§ÙÙ
+ØµØ¯Ø± . Ù
+Ù Ø£Ø¬Ù Ø§ÙØªØ¹Ø§Ù
+Ù Ø§ÙÙ
+ØŽØªØ±Ù, ÙØ¬Øš Ø£Ù ØªØ®ØªØ§Ø± Ø§ÙØµÙØºØ© Ù
+Ù Ø§ÙÙØ§ØŠÙ
+Ø© Ø§ÙÙ
+Ø±ÙÙ
+Ø© Ù Ø§ÙØªÙ ÙØªÙ
+ Ø§Ø¹Ø¯Ø§Ø¯ÙØ§    Ø­Ø§ÙÙØ§ Ø¶Ù
+Ù Ø­ÙÙØ§Øª ÙØ±ØŽØ© Ø¹Ù
+Ù</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">æ ŒåŒ</Attribute>
+      <Attribute name="definition">èµæºçç©çææ°å­è¡šç°åœ¢åŒã</Attribute>
+      <Attribute name="comment">äžè¬èèšïŒæ ŒåŒå¯èœå
+æ¬èµæºçåªäœç±»åæèµæºçå€§å°ïŒæ ŒåŒå
+çŽ å¯ä»¥çšæ¥å³å®å±ç€ºææäœèµæºæé    çèœ¯ç¡¬ä»¶æå
+¶ä»çžåºè®Ÿå€ïŒäŸåŠå€§å°å
+æ¬èµæºæå çå­åšç©ºéŽåæç»­æ¶éŽãå»ºè®®éçšæ¥èªäºåæ§è¯è¡š    äž­çåŒïŒïŒäŸåŠInternetåªäœç±»å[MIME]å®ä¹è®¡ç®æºåªäœæ ŒåŒïŒã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">FormÃ¡t</Attribute>
+      <Attribute name="definition">FyzickÃ¡ nebo digitÃ¡lnÃ­ reprezentace zdroje.</Attribute>
+      <Attribute name="comment">Typicky mÅ¯ÅŸe FormÃ¡t obsahovat typ mÃ©dia nebo rozmÄry zdroje. FormÃ¡t lze pouÅŸÃ­vat k urÄenÃ­ softwaru, hardwaru nebo dalÅ¡Ã­ho zaÅÃ­zenÃ­ potÅebnÃ©ho k zobrazenÃ­ nebo k manipulaci se zdrojem. PÅÃ­klady rozmÄrÅ¯ zahrnujÃ­ velikost a dobu trvÃ¡nÃ­. DoporuÄuje se vybÃ­rat hodnotu z ÅÃ­zenÃ©ho slovnÃ­ku (napÅ. seznam typÅ¯ internetovÃœch mÃ©diÃ­ [MIME] definujÃ­cÃ­ formÃ¡ty poÄÃ­taÄovÃœch mÃ©diÃ­).</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Format</Attribute>
+      <Attribute name="definition">Het data formaat van het Internetbestand. Dit gegeven kan gebruikt worden om systeemvereisten (hard- en software) te identificeren die nodig zijn voor raadpleging of bediening van de Internetbron. "Format" is nog in ontwikkeling bij de DC workshop. Uit compatibiliteitsoverwegingen wordt aanbevolen formaatgegevens te selecteren uit een gecontroleerde lijst. Formaten kunnen van de Internet Media Types (MIME types) lijst gekozen worden: http://www.isi.edu/in-notes/iana/assignments/media-types/media-types</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Formato</Attribute>
+    <Attribute name="definition">Le manifestation physic o digital del ressource.</Attribute>
+    <Attribute name="comment">Typicamente le formato pote includer le typo de medio o dimensiones del ressource. Le formato pote esser utilizate pro determinar le software o le equipamento necessari pro exhibir o operar le ressource. Exemplos de dimensiones include grandessa e duration. Le practica recommendate es selectionar un valor de un vocabulario controlate (per exemplo, le lista de typos de medios de Internet [MIME] que defini formatos de medios).</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€°à€à€šà€Ÿ</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€°à€à€šà€Ÿ, à€šà€®à¥à€šà€Ÿà€¬à¥à€Š à€°à€à€šà€Ÿ</Attribute>
+      <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€žà¥à€µà€°à¥à€ª, à€°à€à€šà€Ÿà€à€Šà€Ÿ. à€€à¥à€¯à€Ÿà€à¥ à€°à¥à€ª à€à€žà¥ à€ªà¥à€žà¥à€€à€à€°à¥à€ª, à€žà€à€à€£à€à¥à€¯ à€°à¥à€ª, à€µà€¿à€Šà¥à€¯à¥à€€ à€ªà€°à€®à€Ÿà€£à¥à€à€à¥à€¯à€Ÿ à€žà€¹à€Ÿà€¯à¥à€¯à€Ÿà€šà¥ à€žà€à€à€£à€à¥à€à¥à€€ à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Identifier" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Resource Identifier</Attribute>
+    <Attribute name="definition">An unambiguous reference to the resource within a given context.</Attribute>
+    <Attribute name="comment">Recommended best practice is to identify the resource by means of a string or number conforming to a formal identification system. Example formal identification systems include the Uniform Resource Identifier (URI) (including the Uniform Resource Locator (URL)), the Digital Object Identifier (DOI) and the International Standard Book Number (ISBN).</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Taututanga</Attribute>
+    <Attribute name="definition">He tohutoro e hangai ana ki te rauemi i roto i tetahi horopaki.</Attribute>
+    <Attribute name="comment">Ko te tino huarahi kua tohua, ko te tautu i te rauemi ma tetahi aho (string), tau ranei, e hangai ana ki tetahi punaha taututanga okawa. Ko etahi punaha taututanga okawa ko te Taututanga Rauemi Orite (Uniform Resource Identifier - URI), te Taututanga Rauemi Tohu-wahi (Uniform Resource Locator - URL), Te Mea A-mati (Digital Object Identifier - DOI) me te Tau Pukapuka Aro Whanui o te Ao (International Standard Book Number - ISBN).</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Identifiant</Attribute>
+    <Attribute name="definition">Une rÃ©fÃ©rence non ambiguÃ« Ã  la ressource dans un contexte donnÃ©</Attribute>
+    <Attribute name="comment">Il est recommandÃ© d'identifier la ressource par une chaÃ®ne de caractÃšre ou un nombre conforme Ã  un sytÃšme formel d'identification. Exemples de systemes formels d'identification incluent le "Uniform Resource Identifier" (URI) (qui inclut le "Uniform Resource Locator" (URL)), le "Digital Object Identifier"(DOI) et le "International Standard Book Number"(ISBN).</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ ÑÐµÑÑÑÑÐ°</Attribute>
+    <Attribute name="definition">ÐÐŽÐœÐŸÐ·ÐœÐ°ÑÐœÐ°Ñ ÑÑÑÐ»ÐºÐ° ÐœÐ° ÑÐµÑÑÑÑ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÐŽÐ°ÐœÐœÐŸÐ³ÐŸ ÐºÐŸÐœÑÐµÐºÑÑÐ°.</Attribute>
+    <Attribute name="comment">ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÑÑÑÑ Ð¿ÐŸÑÑÐµÐŽÑÑÐ²ÐŸÐŒ ÑÑÑÐŸÐºÐž ÐžÐ»Ðž ÑÐžÑÐ»Ð°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÐžÑÑÐµÐŒÐµ. ÐÑÐžÐŒÐµÑÑ ÑÐŸÑÐŒÐ°Ð»ÑÐœÑÑ
+ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÑÑ
+ ÑÐžÑÑÐµÐŒ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð£ÐœÐžÑÐžÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ Ð ÐµÑÑÑÑÐ° (URI), (Ð²ÐºÐ»ÑÑÐ°Ñ Ð£ÐœÐžÑÐžÑÐžÑÐŸÐ²Ð°ÐœÐœÑÑÐ¹ ÐÐŸÐºÐ°ÑÐŸÑ Ð ÐµÑÑÑÑÐ° URL), ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ ÐŠÐžÑÑÐŸÐ²ÐŸÐ³ÐŸ ÐÐ±ÑÐµÐºÑÐ° (DOI) Ðž ÐÐµÐ¶ÐŽÑÐœÐ°ÑÐŸÐŽÐœÑÐ¹ Ð¡ÑÐ°ÐœÐŽÐ°ÑÑÐœÑÐ¹ ÐÐœÐžÐ¶ÐœÑÐ¹ ÐÐŸÐŒÐµÑ (ISBN).</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Identificador del Recurso</Attribute>
+    <Attribute name="definition">Secuencia de caracteres usados para identificar unÃ­vocamente un recurso. Ejemplos para recursos en lÃ­nea pueden ser URLs y URNs (cuando estÃ©n implementados). Para otros recursos pueden ser usados otros formatos de identificadores, como por ejemplo ISBN ("International Standard Book Number" - NÃºmero Internacional Normalizado para Libros)</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ù
+Ø¹Ø±Ù Ø§ÙÙ
+ØµØ¯Ø±</Attribute>
+      <Attribute name="definition">ÙÙ Ù
+Ø¬Ù
+ÙØ¹Ø© Ø­Ø±ÙÙØ© Ø£Ù Ø±ÙÙ
+ ÙØ³ØªØ®Ø¯Ù
+ ÙØªØ¹Ø±ÙÙ Ø§ÙÙ
+ØµØ¯Ø± Ø§Ø­Ø¯ÙØ§ : Ø§ÙØ§Ù
+Ø«ÙØ© ÙØ°Ø§ÙÙ ÙÙ Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙØŽØšÙÙØ©ØªØ¶Ù
+ ) URNs, URLs Ø¹ÙØ¯ ØšÙØ§ØŠÙØ§ (    ÙØ°ÙÙ ÙÙ
+ÙÙ Ø§Ø¹ØªØšØ§Ø± Ø§ÙÙ
+Ø¹Ø±ÙØ§Øª Ø§ÙØ¹Ø§ÙÙ
+ÙØ© Ø§ÙØ§Ø­Ø§Ø¯ÙØ© Ù
+Ø«Ù Ø§ÙØ±ÙÙ
+ Ø§ÙØ¯ÙÙÙ ÙØªØµÙÙÙ Ø§ÙÙØ§ØªØš (ISBN) Ù
+Ø±ØŽØ­Ø© ÙÙØ°Ø§ Ø§ÙØ¹Ø§Ù
+Ù</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">èµæºæ è¯ç¬Š</Attribute>
+      <Attribute name="definition">åšç¹å®çèåŽå
+ç»äºèµæºçäžäžªæç¡®çæ è¯ã</Attribute>
+      <Attribute name="comment">å»ºè®®å¯¹èµæºçæ è¯éçšç¬Šåæäžæ­£åŒæ è¯äœç³»çå­ç¬Šäž²åæ°å­ç»åãäŸåŠæ­£åŒçæ è¯äœç³»å
+æ¬ç»äžèµ    æºæ è¯ç¬Š(URI) (å
+æ¬åäžèµæºå®äœç¬ŠURL)ãæ°å­å¯¹è±¡æ è¯ç¬Š(DOI)ååœé
+æ åä¹Šå·(ISBN)ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">IdentifikÃ¡tor zdroje</Attribute>
+      <Attribute name="definition">JednoznaÄnÃœ odkaz na zdroj v rÃ¡mci danÃ©ho kontextu.</Attribute>
+      <Attribute name="comment">DoporuÄuje se
+identifikovat zdroj znakovÃœm ÅetÄzcem nebo ÄÃ­slem odpovÃ­dajÃ­cÃ­m nÄkterÃ©mu z formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯. PÅÃ­klady formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯ zahrnujÃ­ Uniform Resource Identifier (URI) (vÄetnÄ Uniform Resource Locator (URL)), Digital Object Identifier (DOI) a MezinÃ¡rodnÃ­ standardnÃ­ ÄÃ­slo knihy (ISBN).</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Bestandsidentificatie</Attribute>
+      <Attribute name="definition">Een unieke string of nummer ter identificatie van de Internetbron. Voorbeelden zijn URL's of URN's Andere voorbeelden zijn International Standard Book Number (ISBN) of International Standard Serial Number (ISSN)</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Identificator del ressource</Attribute>
+    <Attribute name="definition">Un referentia inambigue al ressource intra un date contexto.</Attribute>
+    <Attribute name="comment">Se recommenda identificar le ressource per medio de un catena de characteres o numero conforme a un systema formal de identification. Exemplos de systemas formal de identification include le Uniform Resource Identifier (URI) (includente le Uniform Resource Locator (URL)), le Digital Object Identifier (DOI) e le International Standard Book Number (ISBN).</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€à€³à€</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à€Ÿ à€à€ à€
+à€°à¥à€¥à¥ à€žà€à€Šà€°à¥à€­</Attribute>
+      <Attribute name="comment">à€à€Šà€Ÿ. à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿà€³à¥à€¯à€Ÿà€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿ, à€µà€¿à€¶à€¿à€·à¥à€  à€žà¥à€¥à€³,  à€ªà¥à€žà¥à€€à€à€Ÿà€à€Ÿ à€à€à€€à€°à€°à€Ÿà€·à¥à€à¥à€°à¥à€¯  à€®à€Ÿà€šà€ à€à¥à€°à€®à€Ÿà€à€,  à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€à€³à€ à€ªà€à€µà€¿à€£à€Ÿà€°à€Ÿ à€à€à€à€°à€šà¥à€ à€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿ</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Source" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Source</Attribute>
+    <Attribute name="definition">A Reference to a resource from which the present resource is derived.</Attribute>
+    <Attribute name="comment">The present resource may be derived from the Source resource in whole or in part.  Recommended best practice is to reference the resource by means of a string or number conforming to a formal identification system.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Matapuna</Attribute>
+    <Attribute name="definition">He tohutoro ki tetahi rauemi koira te matapuna o te rauemi e tirohia ana.</Attribute>
+    <Attribute name="comment">Tera pea i puta te katoa, tetahi wahanga ranei o te rauemi, e tirohia ana, mai i te Matapuna rauemi. Ko te tino huarahi kua tohua ko te tohutoro ki te rauemi ma te aho, ma te tau ranei e hangai ana ki tetahi punaha taututanga okawa.</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Source</Attribute>
+    <Attribute name="definition">Une rÃ©fÃ©rence Ã  une ressource Ã  partir de laquelle la ressource actuelle a Ã©tÃ© dÃ©rivÃ©e.</Attribute>
+    <Attribute name="comment">La ressource actuelle peut avoir Ã©tÃ© dÃ©rivÃ©e d'une autre ressource source, en totalitÃ© ou en partie. Il est recommandÃ© de refÃ©rencer cette source par une chaÃ®ne de caractÃšre ou un nombre conforme Ã  un systÃšme formel d'identification.</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">ÐÑÑÐŸÑÐœÐžÐº</Attribute>
+    <Attribute name="definition">Ð¡ÑÑÐ»ÐºÐ° ÐœÐ° ÑÐµÑÑÑÑ, ÐžÐ· ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ ÐžÐ·Ð²Ð»ÐµÑÐµÐœ ÐœÐ°ÑÑÐŸÑÑÐžÐ¹.</Attribute>
+    <Attribute name="comment">ÐÐ°ÑÑÐŸÑÑÐžÐ¹ ÑÐµÑÑÑÑ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐžÐ·Ð²Ð»ÐµÑÐµÐœ ÐžÐ· ÐÑÑÐŸÑÐœÐžÐºÐ° ÑÐµÐ»ÐžÐºÐŸÐŒ ÐžÐ»Ðž ÑÐ°ÑÑÐžÑÐœÐŸ. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÑÑÑÑ Ð¿ÐŸÑÑÐµÐŽÑÑÐ²ÐŸÐŒ ÑÑÑÐŸÐºÐž ÐžÐ»Ðž ÑÐžÑÐ»Ð°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÐžÑÑÐµÐŒÐµ.</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Fuente</Attribute>
+    <Attribute name="definition">Secuencia de caracteres utilizado para identificar unÃ­vocamente un trabajo a partir del cual proviene el recurso actual. Por ejemplo, es posible usar Source con la fecha de 1603 como descripciÃ³n de una pelÃ­cula basada en una obra de Shakespeare, pero es preferible, en ese caso, usar Relation "IsBasedOn" con una referencia a un recurso distinto cuya descripciÃ³n contenga el elemento Date con valor 1603.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙÙ
+ØµØ¯Ø±</Attribute>
+      <Attribute name="definition">Ø§ÙÙ
+Ø¹ÙÙÙ
+Ø§Øª Ø§ÙØ®Ø§ØµØ© ØšÙ
+ØµØ¯Ø± Ø«Ø§ÙÙ Ù Ø§ÙØ°Ù Ø§Ø³ØªÙ
+Ø¯ Ù
+ÙÙ Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ. Ù
+Ø¹ Ø£ÙÙ Ù
+Ù Ø§ÙÙ
+ÙØµÙ ØšÙ Ø£Ù ØªÙØ¯Ù
+ Ø§ÙØ¹ÙØ§Ù
+Ù    Ù
+Ø¹ÙÙÙ
+Ø§Øª Ø¹Ù Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ ÙÙØ· , ÙÙÙ
+ÙÙ Ø£Ù ÙØ­ÙÙ ÙØ°Ø§ Ø§ÙØ¹Ø§Ù
+Ù Ø§ÙØªØ§Ø±ÙØ®, Ø§ÙÙ
+ÙØŽØŠ , Ø§ÙØµÙØºØ© , Ø§ÙÙ
+Ø¹Ø±Ù , Ø§Ù Ø§ÙØ© Ù
+ÙØ© - Ù
+Ø¹ÙÙÙ
+Ø§Øª Ø§Ø®Ø±Ù ÙÙÙ
+ØµØ¯Ø± Ø§ÙØ«Ø§ÙÙ Ø¹ÙØ¯Ù
+Ø§ ØªØ¹ØªØšØ± Ù
+ÙÙ
+Ø© ÙØ§ÙØªØŽØ§Ù Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ , Ù ÙØ°Ø§ÙÙ ÙÙØµÙ Ø¹ÙØ¯ Ø§ÙØªØ·ØšÙÙÙÙ Ø§Ø­Ø³Ù     Ø§ÙÙ
+ØªØ¹Ø§Ø±Ù Ø¹ÙÙÙ ØšØ§Ø³ØªØ®Ø¯Ø§Ù
+ Ø¹Ø§Ù
+Ù Ø§ÙØ¹ÙØ§ÙØ©</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">æ¥æº</Attribute>
+      <Attribute name="definition">ç°æèµæºæ¥æºçåç
+§ã</Attribute>
+      <Attribute name="comment">åœåèµæºå¯èœéšåæå
+šéšæºèªè¯¥å
+çŽ ææ è¯çèµæºïŒå»ºè®®å¯¹è¿äžèµæºçæ è¯éçšäžäžªç¬Šåæ­£åŒæ è¯ç³»    ç»çå­äž²åæ°å­ç»å ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">Zdroj</Attribute>
+      <Attribute name="definition">Odkaz na zdroj, z nÄhoÅŸ je popisovanÃœ zdroj odvozen.</Attribute>
+      <Attribute name="comment">PopisovanÃœ zdroj mÅ¯ÅŸe bÃœt zcela nebo zÄÃ¡sti odvozen ze zdroje uvedenÃ©ho v prvku Zdroj. DoporuÄuje se odkazovat zdroj znakovÃœm ÅetÄzcem nebo ÄÃ­slem odpovÃ­dajÃ­cÃ­m nÄkterÃ©mu z formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Bron</Attribute>
+      <Attribute name="definition">Informatie over een tweede bron waar de huidige Internetbron is van afgeleid. Bij "Source" mag een datum, auteur of maker, formaat, identificatie of andere metadata voor de tweede bron worden ingevuld. Voorbeeld: het is mogelijk om een "Source" datum 1603 in een omschrijving van een 1996 film bewerking van een Shakespeare stuk te gebruiken. "Source" is niet bruikbaar wanneer de huidige bron de orginele is.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Fonte</Attribute>
+    <Attribute name="definition">Un referentia a un ressource del qual se deriva le ressource presente.</Attribute>
+    <Attribute name="comment">Le ressource presente pote derivar se del ressource-fonte in toto o in parte. Le practica recommendate es facer referentia al ressource per medio de un catena de characteres o un numero conforme a un systema formal de identification.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€à€à€®</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿ à€à€à€® à€žà€Ÿà€à€à€£à€Ÿà€°à€Ÿ à€à€à€
+à€°à¥à€¥à¥ à€žà€à€Šà€°à¥à€­</Attribute>
+      <Attribute name="comment">à€à€Šà€Ÿ. à€ªà¥à€žà¥à€€à€, à€®à€Ÿà€žà€¿à€,  à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿà€³à¥à€¯à€Ÿà€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿà€¯à€Ÿà€à€à€Ÿ à€žà€à€Šà€°à¥à€­</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Language" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Language</Attribute>
+    <Attribute name="definition">A language of the intellectual content of the resource.</Attribute>
+    <Attribute name="comment" language="en">Recommended best practice for the values of the Language element is defined by RFC 1766 which includes a two-letter Language Code (taken from the ISO 639 standard, followed optionally, by a two-letter Country Code (taken from the ISO 3166 standard). For example, 'en' for English, 'fr' for French, or 'en-uk' for English used in the United Kingdom.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Reo</Attribute>
+    <Attribute name="definition">Te reo o te whakakaupapatanga o nga matauranga o te rauemi.</Attribute>
+    <Attribute name="comment">Ko te tino huarahi kua tohua mo nga uara o te huanga Reo kua whakaritea ki te RFC 1766 [RFC1766] kei roto te Tohu Reo kupu-rua (two-letter Language Code) (no te aro whanui ISO 639 [ISO639], ka taea e tetahi tohu kupu-rua te whai atu (no te aro whanui ISO 3166) [ISO366]). Hei tauira, te 'en' mo te English, te 'fr' mo te French, 'te en-uk' mo te English e whakamahia ana i Ingarangi (UK).</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Langue</Attribute>
+    <Attribute name="definition">La langue du contenu intellectuel de la ressource.</Attribute>
+    <Attribute name="comment">Il est recommandÃ© d'utiliser comme valeur de l'Ã©lÃ©ment Langue celles definies par la RFC 1766 [RFC1766] qui comprend un code de langage Ã  deux caractÃšres(venant du standard ISO 639 [ISO639]), Ã©ventuellement suivi d'un code Ã  deux lettres pour le pays (venant du standard ISO 3166 [ISO3166] ou en franÃ§ais [ISO3166]). Par exemple, 'en' pour l'anglais, 'fr' pour le franÃ§ais, ou 'en-uk' pour l'anglais utilisÃ© au Royaume-Uni.</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">Ð¯Ð·ÑÐº</Attribute>
+    <Attribute name="definition">Ð¯Ð·ÑÐº ÐžÐœÑÐµÐ»Ð»ÐµÐºÑÑÐ°Ð»ÑÐœÐŸÐ³ÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+    <Attribute name="comment">ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÐ»ÐµÐŒÐµÐœÑÐ° Ð¯Ð·ÑÐº, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÐŒÐŸÐµ RFC 1766 (Ð¢ÑÐ³Ðž ÐŽÐ»Ñ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐž ÑÐ·ÑÐºÐ°), Ð²ÐºÐ»ÑÑÐ°ÑÑÐžÐŒ ÐŽÐ²ÑÑ
+Ð±ÑÐºÐ²ÐµÐœÐœÑÐ¹ ÐºÐŸÐŽ ÑÐ·ÑÐºÐ° (Ð²Ð·ÑÑÑÐ¹ ÐžÐ· ÑÑÐ°ÐœÐŽÐ°ÑÑÐ° ISO 639 (ÐÐŸÐŽÑ ÐŽÐ»Ñ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ ÑÐ·ÑÐºÐŸÐ²)), Ð·Ð° ÐºÐŸÑÐŸÑÑÐŒ ÑÐ»ÐµÐŽÑÐµÑ (Ð¿ÑÐž ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÑÑÐž) ÐŽÐ²ÑÑ
+Ð±ÑÐºÐ²ÐµÐœÐœÑÐ¹ ÐºÐŸÐŽ ÑÑÑÐ°ÐœÑ (Ð²Ð·ÑÑÑÐŒÐž ÐžÐ· ÑÑÐ°ÐœÐŽÐ°ÑÑÐ° ISO 3166 (ÐÐŸÐŽÑ ÐŽÐ»Ñ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ ÑÑÑÐ°Ðœ)). ÐÐ°Ð¿ÑÐžÐŒÐµÑ, "en" - ÐŽÐ»Ñ Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐŸÐ³ÐŸ, "fr" - ÐŽÐ»Ñ ÑÑÐ°ÐœÑÑÐ·ÑÐºÐŸÐ³ÐŸ, "en-uk" - ÐŽÐ»Ñ Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐŸÐ³ÐŸ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐŸÐ³ÐŸ Ð² ÐÐµÐ»ÐžÐºÐŸÐ±ÑÐžÑÐ°ÐœÐžÐž.</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Lengua</Attribute>
+    <Attribute name="definition">Lengua/s del contenido intelectual del recurso. Practicamente el contenido de este campo deberÃ­a coincidir con los de la RFC 1766 (Tags para la identificaciÃ³n de lenguas, http://ds.internic.net/rfc/rfc1766.txt); por ejemplo: en, es, de, fi, ja y zh.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙÙØºØ©</Attribute>
+      <Attribute name="definition">ÙØ°Ù ÙÙ ÙØºØ© Ø§ÙÙ
+Ø­ØªÙÙ Ø§ÙÙÙØ±Ù ÙÙÙ
+ØµØ¯Ø± . ÙÙÙ
+Ø§ ÙØ§Ù  Ø¹Ù
+ÙÙØ§ , Ù
+Ø­ØªÙÙ ÙØžØ§ Ø§ÙØ­ÙÙ ÙØ¬Øš Ø£Ù ÙØªØ·Ø§ØšÙ Ù
+Ø¹ RFC 1766    ] Ø§ÙØ§Ù
+Ø«ÙØ© ØªØ¶Ù
+ th, ja, fr, es, fi, de, en Ù zh ÙØ±Ù
+ÙØ² ÙÙØªØ¹Ø±ÙÙ ØšØ§ÙÙØºØ© [</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">è¯­ç§</Attribute>
+      <Attribute name="definition">æè¿°èµæºç¥è¯å
+å®¹çè¯­ç§ã</Attribute>
+      <Attribute name="comment">å»ºè®®æ¬å
+çŽ çåŒéçšRFC 3066[RFC3066]ïŒè¯¥æ åäžISO 639 [ISO639]äžèµ·å®ä¹äºç±äž€äžªåäžäžªè±    æå­æ¯ç»æçäž»è¯­èšæ ç­Ÿåå­æ ç­ŸäŸåŠå
+æ¬âenâæâengâæ¥è¡šç€ºEnglish, "akk" æ¥è¡šç€º    "en-GB"è¡šç€ºè±åœè±è¯­ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">Jazyk</Attribute>
+      <Attribute name="definition">Jazyk intelektuÃ¡lnÃ­ho obsahu zdroje.</Attribute>
+      <Attribute name="comment">DoporuÄenÃœ postup pro hodnoty prvku Jazyk je definovÃ¡n v RFC 1766 [RFC1766]: dvouznakovÃœ kÃ³d jazyka (pÅevzatÃœ z normy ISO 639 [ISO639]) volitelnÄ nÃ¡sledovanÃœ dvouznakovÃœm kÃ³dem zemÄ (pÅevzatÃœm z normy ISO 3166 [ISO3166]). NapÅÃ­klad 'en' pro angliÄtinu, 'fr' pro francouzÅ¡tinu, 'cs' pro ÄeÅ¡tinu, nebo 'en-uk' pro angliÄtinu uÅŸÃ­vanou ve SpojenÃ©m krÃ¡lovstvÃ­.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Taal</Attribute>
+      <Attribute name="definition">De taal waarin het document is beschreven. Voorgeschreven wordt de ISO639-1 norm, een twee karakter taalcode van de ISO 639(639-1 en 639-2) norm. Taalcodes kunnen van een lijst worden gekozen: http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt, Eventueel kan ISO3166 (landencodes) gebruikt worden om aan te geven in welk gebied de taal wordt gesproken. Deze kunnen ook van een lijst worden gekozen:  http://www.ics.uci.edu/pub/ietf/http/related/iso3166.txt.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Lingua</Attribute>
+    <Attribute name="definition">Le lingua del contento intellectual del ressource.</Attribute>
+    <Attribute name="comment">Le practica recommendate pro le valores del elemento lingua es definite per RFC 1766 [RFC1766], que include un codice de lingua de duo litteras (prendite del standard ISO 639 [ISO639]), sequite optionalmente per un codice de pais de duo litteras (prendite del standard ISO 3166 [ISO3166]). Per exemplo, 'ia' pro interlingua, 'fr' pro francese, o 'en-uk' pro le anglese del Regno Unite.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€­à€Ÿà€·à€Ÿ</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€­à€Ÿà€·à€Ÿ</Attribute>
+      <Attribute name="comment">à€à€Šà€Ÿ. à€®à€°à€Ÿà€ à¥ - à€­à€Ÿà€°à€€à¥à€¯ à€­à€Ÿà€·à€Ÿ</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Relation" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Relation</Attribute>
+    <Attribute name="definition">A reference to a related resource.</Attribute>
+    <Attribute name="comment">Recommended best practice is to reference the resource by means of a string or number conforming to a formal identification system.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Whai Panga</Attribute>
+    <Attribute name="definition">He tohutoro ki tetahi rauemi whai panga.</Attribute>
+    <Attribute name="comment">Ko te tino huarahi kua tohua, ko te tohutoro ki te rauemi ma te aho, te tau ranei, e hangai ana ki te punaha taututanga okawa.</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Relation</Attribute>
+    <Attribute name="definition">Une rÃ©fÃ©rence Ã  une autre ressource qui a un rapport avec cette ressource.</Attribute>
+    <Attribute name="comment">Il est recommandÃ© de rÃ©fÃ©rencer cette ressource par une chaÃ®ne de caractÃšres ou un numÃ©ro conforme Ã  un systÃšme formel d'identification.</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">ÐÑÐœÐŸÑÐµÐœÐžÐµ</Attribute>
+    <Attribute name="definition">²ÐµÐœÐœÑÐ¹ ÑÐµÑÑÑÑ.</Attribute>
+    <Attribute name="comment">ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÑÑÑÑ Ð¿ÐŸÑÑÐµÐŽÑÑÐ²ÐŸÐŒ ÑÑÑÐŸÐºÐž ÐžÐ»Ðž ÑÐžÑÐ»Ð°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÐžÑÑÐµÐŒÐµ.</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">RelaciÃ³n</Attribute>
+    <Attribute name="definition">Un identificador de un segundo recurso y su relaciÃ³n con el recurso actual. Este elemento permite enlazar los recursos relacionados y las descripciones de los recursos. Por ejemplo: IsVersionOf - Incluye la ediciÃ³n de un trabajo, IsBasedOn - La traducciÃ³n de un trabajo, IsPartOf - Un capÃ­tulo de un libro, IsFormatOf - Un mecanismo de transformaciÃ³n de un conjunto de datos en una imagen. Para asegurar la interoperabilidad, las relaciones deberÃ­an ser seleccionadas de una lista de elementos que actualmente se encuentra bajo desarrollo en un grupo de trabajo.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙØ¹ÙØ§ÙØ©</Attribute>
+      <Attribute name="definition">ÙØ°Ø§ Ù
+Ø¹Ø±Ù ÙÙÙ
+ØµØ¯Ø± Ø§ÙØ«Ø§ÙÙ Ù Ø¹ÙØ§ÙØªÙ ØšØ§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ . ÙØ³Ù
+Ø­ ÙØ°Ø§ Ø§ÙØ¹Ø§Ù
+Ù ØšØªÙØ¶ÙØ­ Ø§ÙØ±ÙØ§ØšØ· ØšÙÙ Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙÙ
+ØªØ¹ÙÙØ©     ØšØšØ¹Ø¶ÙØ§ Ù ØªÙØµÙÙ Ø§ÙÙ
+ØµØ¯Ø± . Ø§ÙØ§Ù
+Ø«ÙØ© ØªØ¶Ù
+ Ø·ØšØ¹Ø© Ø§ÙØ¹Ù
+Ù ) ÙØ³Ø®Ø© Ù
+Ù ( ØªØ±Ø¬Ù
+Ø© Ø¹Ù
+Ù ) Ø§Ø¹ØªÙ
+Ø§Ø¯Ø§ Ø¹ÙÙ ( ÙØµÙ Ù
+Ù ÙØªØ§Øš ) Ø¬Ø²Ø¡ Ù
+Ù (    Ù ØªØ­ÙÙÙÙ Ù
+ÙÙØ§ÙÙÙÙØ© ÙÙ
+Ø¬Ù
+ÙØ¹Ø© Ù
+Ø¹ÙÙÙ
+Ø§ØªÙØ© Ø§ÙÙ ØµÙØ±Ø© ) ØµÙØºØ© Ù
+Ù ( Ù
+Ù Ø£Ø¬Ù Ø§ÙØªØ¹Ø§Ù
+Ù Ø§ÙÙ
+ØŽØªØ±Ù , ÙØ¬Øš Ø§Ø®ØªÙØ§Ø± Ø§ÙØ¹ÙØ§ÙØ§Øª Ù
+Ù    Ø§ÙÙØ§ØŠÙ
+Ø© Ø§ÙÙ
+Ø±ÙÙ
+Ø© Ù Ø§ÙØªÙ ÙØªÙ
+ Ø§Ø¹Ø¯Ø§Ø¯ÙØ§ Ø­Ø§ÙÙØ§ Ø¶Ù
+Ù Ø­ÙÙØ§Øª ÙØ±ØŽØ© Ø¹Ù
+Ù</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">å
+³è</Attribute>
+      <Attribute name="definition">æ¶åççžå
+³èµæºã</Attribute>
+      <Attribute name="comment">èåœçžå
+³èµæºæ¶ïŒå»ºè®®äœ¿çšç¬Šåæ­£åŒæ è¯ç³»ç»çå­ç¬Šäž²æè
+æ°å­ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">Vztah</Attribute>
+      <Attribute name="definition">Odkaz na pÅÃ­buznÃœ zdroj.</Attribute>
+      <Attribute name="comment">DoporuÄuje se odkazovat zdroj znakovÃœm ÅetÄzcem nebo ÄÃ­slem odpovÃ­dajÃ­cÃ­m nÄkterÃ©mu z formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Relatie</Attribute>
+      <Attribute name="definition">Een identificatie van een tweede bron en de relatie met de huide Internetbron. Voorbeelden zijn een editie van een werk (IsVersionOf), een vertaling van een werk (IsBasedOn), een hoofdstuk van een boek (IsPartOf) en een mechanische transformatie van een dataset in een plaatje (IsFormatOf). De DC Working Groups zijn bezig met een lijst met de meest verwachte relaties. Aanbevolen wordt om de relaties van deze lijst te gebruiken: http://purl.oclc.org/metadata/dublin_core/wrelationdraft.html.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="definition">Relation</Attribute>
+    <Attribute name="definition">Un referentia a un ressource correlate.</Attribute>
+    <Attribute name="comment">Le practica recommendate es facer referentia al ressource per medio de un catena de characteres o numero conforme a un systema de identification formal.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€šà€Ÿà€€à¥ , à€žà€à€¬à€à€§</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€¶à¥ à€žà€à€¬à€à€§ à€Šà€Ÿà€à€µà€£à€Ÿà€°à€Ÿ à€žà€à€Šà€°à¥à€­</Attribute>
+      <Attribute name="comment">à€à€Šà€Ÿ.  à€®à€Ÿà€¹à€¿à€€à¥ à€à€Ÿà€³à¥à€¯à€Ÿà€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿ(URL)</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Coverage" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Coverage</Attribute>
+    <Attribute name="definition">The extent or scope of the content of the resource.</Attribute>
+<Attribute name="comment">Coverage will typically include spatial location (a place name or geographic coordinates), temporal period (a period label, date, or date range) or jurisdiction (such as a named administrative entity). Recommended best practice is to select a value from a controlled vocabulary (for example, the Thesaurus of Geographic Names [TGN]) and that, where appropriate, named places or time periods be used in preference to numeric identifiers such as sets of coordinates or date ranges.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Kapitanga</Attribute>
+    <Attribute name="definition">Te roanga, te whanuitanga ranei o te whakakaupapatanga o te rauemi.</Attribute>
+    <Attribute name="comment">Ko te tikanga, ka uru atu te wahi mokowa (te ingoa o tetahi wahi, whakapiritanga matawhenua ranei), whakaritenga wa (he tapatanga wa (period label, ra, whakatakotoranga whanui o nga ra), te whakaritenga ture (penei i te putahi whakahaere). Ko te tino huarahi kua tohua, ko te tipako uara mai i tetahi whakaritenga kupu (hei tauira, i tetahi Puna Kupu Ingoa Matawhenua (Geographic Names [TGN] i nga wahi tika, ko nga wahi me nga whakaritenga wa ka whakamahia i mua i te whakamahitanga o nga taututanga tau penei i nga huinga whakapiritanga me nga whakatakotoranga whanui o nga ra.</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Couverture</Attribute>
+    <Attribute name="definition">La portÃ©e ou la couverture spatio-temporelle de la ressource.</Attribute>
+    <Attribute name="comment">La couverture typiquement inclut une position gÃ©ographique (le nom d'un lieu ou ses coordonnÃ©es), une pÃ©riode de temps (un nom de pÃ©riode, une date, ou un intervalle de temps) ou une juridiction (telle que le nom d'une entitÃ© administrative). Il est recommandÃ© de choisir la  valeur de Couverture dans un vocabulaire contrÃŽlÃ© (par exemple, un thÃ©saurus de noms gÃ©ographiques, comme[TGN]) et, quand cela est appropriÃ©, des noms de lieux ou de pÃ©riodes plutÃŽt que des identifiants numÃ©riques tels que des coordonnÃ©es ou des intervalles de dates. </Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">ÐÑ
+Ð²Ð°Ñ</Attribute>
+    <Attribute name="definition">ÐÑÐŸÑÑÐ¶ÐµÐœÐœÐŸÑÑÑ Ðž Ð³ÑÐ°ÐœÐžÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+    <Attribute name="comment">ÐÑ
+Ð²Ð°Ñ ÐŸÐ±ÑÐºÐœÐŸÐ²ÐµÐœÐœÐŸ Ð²ÐºÐ»ÑÑÐ°ÐµÑ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²ÐµÐœÐœÐŸÐµ ÐŒÐµÑÑÐŸÐœÐ°Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÐµ (ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐŒÐµÑÑÐœÐŸÑÑÐž ÐžÐ»Ðž Ð³ÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÐµ ÐºÐŸÐŸÑÐŽÐžÐœÐ°ÑÑ), Ð²ÑÐµÐŒÐµÐœÐœÐŸÐ¹ Ð¿ÑÐŸÐŒÐµÐ¶ÑÑÐŸÐº (ÑÐºÐ°Ð·Ð°ÐœÐžÐµ Ð¿ÐµÑÐžÐŸÐŽÐ°, ÐŽÐ°ÑÐ° ÐžÐ»Ðž ÑÑÐŽ ÐŽÐ°Ñ) ÐžÐ»Ðž ÑÑÐžÑÐŽÐžÐºÑÐžÑ (ÑÐºÐ°Ð·Ð°ÐœÐžÐµ ÐµÐŽÐžÐœÐžÑÑ Ð°ÐŽÐŒÐžÐœÐžÑÑÑÐ°ÑÐžÐ²ÐœÐŸÐ³ÐŸ ÐŽÐµÐ»ÐµÐœÐžÑ). ÐÐ° Ð¿ÑÐ°ÐºÑÐžÐºÐµ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, Ð¢ÐµÐ·Ð°ÑÑÑÑÐ° Ð³ÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÑ
+ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ TGN), Ðž, ÐµÑÐ»Ðž ÑÑÐŸ ÑÐŒÐµÑÑÐœÐŸ, Ð¿ÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÐµ ÐŸÑÐŽÐ°ÐµÑÑÑ ÑÐºÐ°Ð·Ð°ÐœÐžÑÐŒ ÐŒÐµÑÑÐœÐŸÑÑÐµÐ¹ ÐžÐ»Ðž Ð²ÑÐµÐŒÐµÐœÐœÑÑ
+ Ð¿ÑÐŸÐŒÐµÐ¶ÑÑÐºÐŸÐ² Ð²ÐŒÐµÑÑÐŸ ÑÐžÑÑÐŸÐ²ÑÑ
+ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ², ÐºÐ°Ðº, ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐžÑÑÐµÐŒ ÐºÐŸÐŸÑÐŽÐžÐœÐ°Ñ ÐžÐ»Ðž Ð²ÑÐµÐŒÐµÐœÐœÑÑ
+ ÑÑÐŽÐŸÐ².</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Cobertura</Attribute>
+    <Attribute name="definition">La caracterÃ­stica de cobertura espacial y/o temporal del contenido intelectual del recurso. La cobertura espacial se refiere a una regiÃ³n fÃ­sica (por ejemplo, sector celestial); uso de coordenadas (por ejemplo, longitud y latitud) o nombres de lugares extraidos de una lista controlada. La cobertura temporal se refiere al contenido del recurso en vez de a cuando fue creado o puesto accesible ya que este Ãºltimo pertenece al elemento Date. Se usa el mismo formato basado en http://www.w3.org/TR/NOTE-datetime.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø§ÙØªØºØ·ÙØ©</Attribute>
+      <Attribute name="definition">ÙÙ Ø§ÙØ®ØµØ§ØŠØµ Ø§ÙÙ
+ÙØ§ÙÙØ© Ø§Ù Ø§ÙØ²Ù
+ÙÙØ© ÙÙÙ
+Ø­ØªÙÙ Ø§ÙÙÙØ±Ù ÙÙÙ
+ØµØ¯Ø± . Ø§ÙØªØºØ·ÙØ© Ø§ÙÙ
+ÙØ§ÙÙØ© ØªØŽÙØ± Ø§ÙÙ Ø¬ÙØ© Ø·ØšÙØ¹ÙØ© )Ù
+Ø«Ù , ÙØ·Ø§Ø¹ Ø³Ù
+Ø§ÙÙ (    Ø§Ø³ØªØ®Ø¯Ø§Ù
+ Ø§ÙØ§Ø­Ø¯Ø§Ø«ÙØ§Øª ) Ù
+Ø«Ù  Ø®Ø· Ø§ÙØ·ÙÙ Ù Ø®Ø· Ø§ÙØ¹Ø±Ø¶ ( ÙÙ Ø£Ø³Ù
+Ø§Ø¡ Ø§Ù
+ÙÙØ© Ù
+Ø³ØªØ­ÙÙ
+Ø© Ø§Ù Ù
+ØªØ¬ÙØ§Øª ØšØ§ÙÙØ§Ù
+Ù . Ø§ÙØªØºØ·ÙØ© Ø§ÙØ²Ù
+ÙÙØ©    Ø«Ø¹ÙØ¯ Ø§ÙÙ Ù
+Ø§ ÙØ±Ø¬Ø¹ Ø§ÙÙÙ Ø§ÙÙ
+ØµØ¯Ø± Ù ÙÙØ³ Ø§Ù Ù
+ØªÙ ØªÙ
+ ØªÙÙÙØ±Ù ) Ø§ÙØ§Ø®ÙØ± ÙØªØ¹ÙÙ ØšØ¹Ø§Ù
+Ù Ø§ÙØªØ§Ø±ÙØ® ( Ø§Ø³ØªØ®Ø¯Ø§Ù
+ ÙÙØ³ ØµÙØºØ© Ø§ÙØªØ§Ø±ÙØ®  Ø§Ù Ø§ÙÙÙØª    ) Ø¹Ø§Ø¯Ø© Ù
+Ø¯Ù ] ( ØµÙØ§ØºØ§Øª Ø§ÙÙÙÙ
+ Ù Ø§ÙÙÙØª ) Ø§Ø¹ØªÙ
+Ø§Ø¯Ø§ Ø¹ÙÙ (ISO 8601 Ø§ÙÙ
+ÙØ§Ø­ØžØ© Ø§ÙÙÙÙØ© [http://www.w3.org/TR/NOTE-datetime, W3C    ÙÙ
+Ø§ ÙÙ Ù
+ÙØµÙ ØšÙ ÙØ¹Ø§Ù
+Ù Ø§ÙØªØ§Ø±ÙØ® Ø§Ù ÙØªØ±Ø§Øª Ø²Ù
+ÙÙØ© Ù
+Ù ÙØ§ØŠÙ
+Ø© Ù
+Ø³ØªØ­ÙÙ
+Ø© Ø§Ù Ù
+ØªØ¬ÙØ§Øª ØšØ§ÙÙØ§Ù
+Ù</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">èŠçèåŽ</Attribute>
+      <Attribute name="definition">èµæºå
+å®¹ææ¶åçå€å»¶äžèŠçèåŽ</Attribute>
+      <Attribute name="comment">èŠçèåŽäžè¬å
+æ¬ç©ºéŽäœçœ®ïŒäžäžªå°åæå°çåæ ïŒãæ¶éŽåºéŽïŒäžäžªæ¶éŽæ è¯ïŒæ¥ææäžäžªæ¥æè    åŽïŒãæè
+æéïŒæ¯åŠåœåçææå®äœïŒæšèèŠçèåŽæå¥œæ¯åèªäºäžäžªåæ§è¯è¡šïŒäŸåŠå°åè¯åº    [TGN]ïŒïŒå¹¶åºå°œå¯èœå°äœ¿çšç±æ°å­è¡šç€ºçåæ ææ¥æåºéŽæ¥æè¿°å°åäžæ¶éŽæ®µã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">PokrytÃ­</Attribute>
+      <Attribute name="definition">Rozsah nebo zÃ¡bÄr obsahu zdroje.</Attribute>
+      <Attribute name="comment">PokrytÃ­ bude typicky obsahovat prostorovÃ© umÃ­stÄnÃ­ (jmÃ©no mÃ­sta nebo zemÄpisnÃ© souÅadnice), ÄasovÃ© obdobÃ­ (oznaÄenÃ­ obdobÃ­, datum nebo ÄasovÃœ interval) nebo jurisdikci (napÅ. jmÃ©no administrativnÃ­ jednotky). DoporuÄuje se vybÃ­rat hodnotu z ÅÃ­zenÃ©ho slovnÃ­ku (napÅ. Thesaurus of Geographic Names [TGN]) a tam, kde je to vhodnÃ©, uvÃ¡dÄt mÃ­sta nebo ÄasovÃ© Ãºseky spÃ­Å¡e jmÃ©nem neÅŸ ÄÃ­selnÃœmi identifikÃ¡tory jako jsou soubory souÅadnic nebo ÄasovÃ© intervaly.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Dekking</Attribute>
+      <Attribute name="definition">De ruimtelijke of tijdelijke karakteristieken van de intellectuele inhoud van de Internetbron. Ruimtelijke dekking verwijst naar een geografisch gebied. Gebruik coordinaten (longitude (lengtegraad) en latitude (breedtegraad)) of plaatsnamen die van een gecontroleerde lijst komen of volledig uitgeschreven zijn. Dekking in de tijd geeft de tijdsperiode aan waarop de inhoud van de Internetbron betrekking heeft en niet wanneer de Internetbron is gemaakt of beschikbaar is gesteld (dit laatste hoort ingevult te worden bij "Date"). Gebruik dezelfde datum/tijd formaat als bij "Date"; W3C Technical Note http://www.w3.org/TR/NOTE-datetime of tijdsperioden die van een gecontroleerde lijst komen of volledig uitgeschreven zijn. Coverage is in ontwikkeling bij de Dublin Core Working group http://www.alexandria.ucsb.edu/docs/metadata/dc_coverage.html.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Copertura</Attribute>
+    <Attribute name="definition">Le extension physic o abstracte del contento del ressource.</Attribute>
+    <Attribute name="comment">Le copertura typicamente include un location spatial (un nomine de localitate o coordinatas geographic), un periodo de tempore (un etiquetta de periodo, data, o gamma de datas), o un jurisdiction (tal como un entitate administrative nominate). Le practica recommendate es selectionar un valor a partir de un vocabulario controlate (per exemplo, le Thesaurus of Geographical Names [TGN]) e que, quando appropriate, localitates o periodos de tempore nominate sia utilizate in preferentia a identificatores numeric tales como collectiones de coordinatas o gammas de datas.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€µà¥à€¯à€Ÿà€ªà¥à€€à¥</Attribute>
+      <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€­à¥à€à¥à€²à€¿à€  à€®à€Ÿà€¹à€¿à€€à¥</Attribute>
+      <Attribute name="comment">à€à€Šà€Ÿ. à€­à¥à€à¥à€²à€¿à€ à€µà¥à€¯à€Ÿà€ªà¥à€€à¥</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+  <Element name="Rights" remember_values="true">
+    <!-- English -->
+    <Language code="en">
+    <Attribute name="identifier">Rights Management</Attribute>
+    <Attribute name="definition">Information about rights held in and over the resource.</Attribute>
+    <Attribute name="comment">Typically, a Rights element will contain a rights management statement for the resource, or reference a service providing such information. Rights information often encompasses Intellectual Property Rights (IPR), Copyright, and various Property Rights. If the Rights element is absent, no assumptions can be made about the status of these and other rights with respect to the resource.</Attribute>
+    </Language>
+    <!-- Maori -->
+    <Language code="mi">
+    <Attribute name="identifier">Motika</Attribute>
+    <Attribute name="definition">Ko nga mohiohio ki nga motika o tetahi rauemi.</Attribute>
+    <Attribute name="comment">Ko te tikanga, kei te huanga Motika e pupuri ana he korero mo te whakaritenga motika mo te rauemi, he ratonga tohutoro e whakarato ana ranei i enei tumomo mohiohio. He nui nga wa, puta ai i roto i te mohiohio Motika te Mana Whakairo Hinegaro (Intellectual Property Rights - (IPR)), te Manatarua me nga Tuahua Mana Taonga (Property Rights). Ki te kore te huanga Motika, kaore e taea te pohehe noa ki te mana o enei, nga motika ranei e pa ana ki te rauemi.</Attribute>
+    </Language>
+    <!-- French -->
+    <Language code="fr">
+    <Attribute name="identifier">Droits</Attribute>
+    <Attribute name="definition">Information sur les droits sur et au sujet de la ressource.</Attribute>
+    <Attribute name="comment">Typiquement, un Ã©lÃ©ment Droits contiendra un Ã©tat du droit Ã  gÃ©rer une ressource, ou la refÃ©rence Ã  un service fournissant cette information. Ces droits souvent couvrent les droits de propriÃ©tÃ© intellectuelle (IPR), Copyright, et divers droits de propriÃ©tÃ©. Si l'Ã©lÃ©ment Droits est absent, aucune hypothÃšse ne peut Ãªtre faite sur l'Ã©tat de ces droits, ou de tout autre, par rapport Ã  la ressource.</Attribute>
+    </Language>
+    <!-- Russian -->
+    <Language code="ru">
+    <Attribute name="identifier">ÐÑÐ°Ð²ÐŸÐ²ÐŸÐµ ÑÐµÐ³ÑÐ»ÐžÑÐŸÐ²Ð°ÐœÐžÐµ</Attribute>
+    <Attribute name="definition">ÐÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ Ð¿ÑÐ°Ð²Ð°Ñ
+ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐ°ÑÑÑ Ð²ÐœÑÑÑÐž Ðž Ð²ÐœÐµ ÑÐµÑÑÑÑÐ°.</Attribute>
+    <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÑÐ»ÐµÐŒÐµÐœÑ ÐÑÐ°Ð²Ð° ÑÐŸÐŽÐµÑÐ¶ÐžÑ Ð¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐžÐµ ÐŸ Ð¿ÑÐ°Ð²ÐŸÐ²ÑÑ
+ ÐœÐŸÑÐŒÐ°Ñ
+, ÑÐµÐ³ÑÐ»ÐžÑÑÑÑÐžÑ
+ ÑÑÐœÐºÑÐžÐŸÐœÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÑÐµÑÑÑÑÐ° ÐžÐ»Ðž ÑÑÑÐ»ÐºÑ ÐœÐ° ÑÐ»ÑÐ¶Ð±Ñ, Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÑÑÑÑ ÑÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ. ÐÑÐ°Ð²ÐŸÐ²Ð°Ñ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸÐ±ÑÑÐœÐŸ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÑÐ²ÐµÐŽÐµÐœÐžÑ ÐŸ ÐÑÐ°Ð²Ð°Ñ
+ ÐžÐœÑÐµÐ»Ð»ÐµÐºÑÑÐ°Ð»ÑÐœÐŸÐ¹ ÑÐŸÐ±ÑÑÐ²ÐµÐœÐœÐŸÑÑÐž, ÐÐ²ÑÐŸÑÑÐºÐŸÐŒ Ð¿ÑÐ°Ð²Ðµ Ðž ÐŽÑÑÐ³ÐžÑ
+ ÐÐŒÑÑÐµÑÑÐ²ÐµÐœÐœÑÑ
+ Ð¿ÑÐ°Ð²Ð°Ñ
+. ÐÑÑÑÑÑÑÐ²ÐžÐµ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐÑÐ°Ð²Ð° ÐœÐµ ÐŒÐŸÐ¶ÐµÑ ÑÐ²Ð»ÑÑÑÑÑ ÐŸÑÐœÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐŽÐ»Ñ ÐºÐ°ÐºÐžÑ
+-Ð»ÐžÐ±ÐŸ Ð¿ÑÐµÐŽÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐžÐ¹ ÐŸ Ð¿ÑÐ°Ð²ÐŸÐ²ÐŸÐŒ ÑÑÐ°ÑÑÑÐµ Ðž ÐŽÑÑÐ³ÐžÑ
+ Ð¿ÑÐ°Ð²Ð°Ñ
+, ÐºÐ°ÑÐ°ÑÑÐžÑ
+ÑÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+    </Language>
+    <!-- Spanish -->
+    <Language code="es">
+    <Attribute name="identifier">Derechos</Attribute>
+    <Attribute name="definition">Una referencia (URL, por ejemplo) para una nota sobre derechos de autor, para un servicio de gestiÃ³n de derechos o para un servicio que darÃ¡ informaciÃ³n sobre tÃ©rminos y condiciones de acceso a un recurso. Una especificaciÃ³n formal del elemento Rights se encuentra catualmente en discusiÃ³n y por lo tanto su uso se considera experimental.</Attribute>
+    </Language>
+
+    <!-- Arabic -->
+    <Language code="ar">
+      <Attribute name="identifier">Ø­ÙÙÙ Ø§ÙØ§Ø¯Ø§Ø±Ø©</Attribute>
+      <Attribute name="definition">ÙÙ Ø§ÙØ§Ø¯Ø© Ø­ÙÙÙ Ø§ÙØ§Ø¯Ø§Ø±Ø© , Ù
+Ø¹Ø±Ù Ù
+Ø±ØªØšØ· ØšØ§ÙØ§Ø¯Ø© Ø­ÙÙÙ Ø§ ÙØ§Ø¯Ø§Ø±Ø© , Ù
+Ø¹Ø±Ù Ù
+Ø±ØªØšØ· ØšØ®Ø¯Ù
+Ø© ØªÙØ¯Ù
+ Ù
+Ø¹ÙÙÙ
+Ø§Øª Ø¹Ù Ø­ÙÙÙ Ø§ÙØ§Ø¯Ø§Ø±Ø© Ø§ÙØ®Ø§ØµØ© ØšØ§ÙÙ
+ØµØ¯Ø±</Attribute>
+    </Language>
+
+    <!-- Chinese - Simplified -->
+    <Language code="cn">
+      <Attribute name="identifier">æé</Attribute>
+      <Attribute name="definition">æå
+³èµæºæ¬èº«ææçæè¢«èµäºçæéä¿¡æ¯</Attribute>
+      <Attribute name="comment">äžè¬èèšïŒæéå
+çŽ åºå
+æ¬äžäžªå¯¹èµæºçæéå£°æïŒæè
+æ¯å¯¹æäŸè¿äžä¿¡æ¯çæå¡çåç
+§ãæéäžè¬    å
+æ¬ç¥è¯äº§æ(IPR)ïŒçææå
+¶ä»åç§åæ ·çäº§æãåŠææ²¡ææéå
+çŽ çæ æ³šïŒäžå¯ä»¥å¯¹äžèµæºçžå
+³    çäžè¿°æå
+¶ä»æå©çæ
+åµäœåºä»»äœåå®ã</Attribute>
+    </Language>
+
+    <!-- Czech -->
+    <Language code="cs">
+      <Attribute name="identifier">PrÃ¡va</Attribute>
+      <Attribute name="definition">Informace o prÃ¡vech vztahujÃ­cÃ­ch se k popisovanÃ©mu zdroji.</Attribute>
+      <Attribute name="comment">Prvek PrÃ¡va bude typicky obsahovat ustanovenÃ­ o sprÃ¡vÄ autorskÃœch/vlastnickÃœch prÃ¡v ke zdroji nebo odkaz na sluÅŸbu poskytujÃ­cÃ­ takovÃ©to informace. Informace o prÃ¡vech Äasto zahrnujÃ­ prÃ¡va duÅ¡evnÃ­ho vlastnictvÃ­ (IPR), autorskÃ© prÃ¡vo a rÅ¯znÃ¡ vlastnickÃ¡ prÃ¡va. JestliÅŸe prvek PrÃ¡va chybÃ­, nelze odvozovat ÅŸÃ¡dnÃ© pÅedpoklady o stavu tÄchto a jinÃœch prÃ¡v vztahujÃ­cÃ­ch se k popisovanÃ©mu zdroji.</Attribute>
+    </Language>
+
+    <!-- Dutch -->
+    <Language code="nl">
+      <Attribute name="identifier">Copyright</Attribute>
+      <Attribute name="definition">Een copyright verklaring of een link naar een copyright verklaring of een link naar een service die informatie geeft over de copyright van de Internetbron.</Attribute>
+    </Language>
+
+    <!-- Finnish -->
+    <Language code="fi">
+      <Attribute name="identifier"></Attribute>
+      <Attribute name="definition"></Attribute>
+      <Attribute name="comment"></Attribute>
+    </Language>
+
+    <!-- Interlingua -->
+    <Language code="ia">
+    <Attribute name="identifier">Gestion de derectos</Attribute>
+    <Attribute name="definition">Information super derectos detenite super e a proposito del ressource.</Attribute>
+    <Attribute name="comment">Typicamente le elemento derectos continera un declaration de gestion de derectos pro le ressource, o un referentia a un servicio que provide tal information. Information de derectos frequentemente involve derectos de proprietate intellectual (IPR), copyright e varie derectos de proprietate. Si le elemento Derectos es absente, necun hypothese pote esser facite quanto al stato de iste e altere derectos concernente ressource.</Attribute>
+    </Language>
+
+    <!-- Marathi -->
+    <Language code="mr">
+      <Attribute name="identifier">à€¹à€à¥à€</Attribute>
+      <Attribute name="definition">à€¬à¥à€§à¥à€Šà€¿à€ à€žà€à€ªà€Šà¥à€à€Ÿà€¹à€à¥à€</Attribute>
+      <Attribute name="comment">à€žà¥à€µà€€à€à€¹à€Ÿà€à¥ à€²à¥à€à€š à€à€Ÿà€ªà¥à€š à€
+à€¥à€µà€Ÿ à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿà€³à¥à€¯à€Ÿà€µà€° à€ªà¥à€°à€à€Ÿà€¶à€¿à€€ à€à€°à€£à¥à€¯à€Ÿà€à€Ÿ à€²à¥à€à€ à€
+à€¥à€µà€Ÿ à€²à¥à€à€¿à€à¥à€à€Ÿ à€¬à¥à€§à¥à€Šà€¿à€ à€žà€à€ªà€Šà¥à€à€Ÿà€¹à€à¥à€</Attribute>
+    </Language>
+
+    <!-- Non-language specific -->
+    <Attribute name="version">1.1</Attribute>
+    <Attribute name="registration_authority" language="en">Dublin Core Metadata Initiative</Attribute>
+    <Attribute name="obligation">Optional</Attribute>
+    <Attribute name="datatype">Charater String</Attribute>
+    <Attribute name="maximum_occurance">Unlimited</Attribute>
+  </Element>
+
+</MetadataSet>
Index: /tags/gsdl-2_61-distribution/gli/metadata/ex.mds
===================================================================
--- /tags/gsdl-2_61-distribution/gli/metadata/ex.mds	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/metadata/ex.mds	(revision 10506)
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param family      The name of this sets family.                                 -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param namespace   The namespace of this metadata set.                           -->
+  <!ELEMENT MetadataSet ((Name|Description|Element)+)>
+  <!ATTLIST MetadataSet
+				contact     CDATA #REQUIRED
+				creator     CDATA #REQUIRED
+				description CDATA #REQUIRED
+            family      CDATA #REQUIRED
+				lastchanged CDATA #REQUIRED
+            name        CDATA #REQUIRED
+				namespace   CDATA #REQUIRED>
+
+  <!-- The name of a metadata set. Is language specific. -->
+  <!ELEMENT Name (#PCDATA)>
+  <!ATTLIST Name
+            language CDATA "en">
+
+  <!-- The description of a metadata set. Is language specific. -->
+  <!ELEMENT Description (#PCDATA)>
+  <!ATTLIST Description
+            language CDATA "en">
+
+  <!-- An element in the metadata set. -->
+  <!ELEMENT Element (Attribute*,OptionList?)>
+  <!ATTLIST Element
+            name       CDATA #REQUIRED
+				occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+]>
+
+<MetadataSet 
+contact     = "nzdl.org"
+creator     = "New Zealand Digital Libraries Project: Greenstone"
+family      = "Extracted Greenstone"
+lastchanged = "Tue May 20 10:30:32 2003 - jmt12 on narya"
+namespace   = "ex" 
+>
+
+  <Name language="en">Extracted Greenstone Metadata 1.0</Name>
+
+  <Description language="en">This document is the reference description, version 1.0 of the automatically extracted Greenstone Metadata Element Set.</Description>
+
+  <Element name="Encoding">
+    <Attribute name="comment" language="en">Not always available.</Attribute>
+    <Attribute name="definition" language="en">The encoding of the imported document as extracted by Greenstone.</Attribute>
+    <Attribute name="identifier" language="en">Encoding</Attribute>
+  </Element>
+
+  <Element name="Language">
+    <Attribute name="comment" language="en">Not always available.</Attribute>
+    <Attribute name="definition" language="en">The language of the imported document as extracted by Greenstone.</Attribute>
+    <Attribute name="identifier" language="en">Language</Attribute>
+  </Element>
+
+  <Element name="Source">
+    <Attribute name="comment" language="en">Hidden in the Librarian Interface as it already shown by the various file trees.</Attribute>
+    <Attribute name="definition" language="en">The filename of the document imported by Greenstone.</Attribute>
+    <Attribute name="identifier" language="en">Source</Attribute>
+  </Element>
+
+  <Element name="Title">
+    <Attribute name="comment" language="en">Not always available.</Attribute>
+    <Attribute name="definition" language="en">The title of the imported document as extracted by Greenstone.</Attribute>
+    <Attribute name="identifier" language="en">Title</Attribute>
+  </Element>
+
+</MetadataSet>
Index: /tags/gsdl-2_61-distribution/gli/metadata/nzgls.mds
===================================================================
--- /tags/gsdl-2_61-distribution/gli/metadata/nzgls.mds	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/metadata/nzgls.mds	(revision 10506)
@@ -0,0 +1,1830 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param family      The name of this sets family.                                 -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param namespace   The namespace of this metadata set.                           -->
+  <!ELEMENT MetadataSet ((Name|Description|SetLanguage|Element)+)>
+  <!ATTLIST MetadataSet
+	    contact            CDATA #REQUIRED
+	    creator            CDATA #REQUIRED
+	    description        CDATA #REQUIRED
+            family             CDATA #REQUIRED
+	    lastchanged        CDATA #REQUIRED
+            name               CDATA #REQUIRED
+	    namespace          CDATA #REQUIRED
+	    language_dependent CDATA "">
+
+  <!-- The name of a metadata set. Is language specific. -->
+  <!ELEMENT Name (#PCDATA)>
+  <!ATTLIST Name
+            language CDATA "en">
+
+  <!-- The description of a metadata set. Is language specific. -->
+  <!ELEMENT Description (#PCDATA)>
+  <!ATTLIST Description
+            language CDATA "en">
+
+  <!-- When used in conjuction with defer-node-expansion, allows for better memory use when dealing with several or more languages. -->
+  <!ELEMENT SetLanguage (Name, Description?)>
+  <!ATTLIST Language
+	    code CDATA #REQUIRED>
+
+  <!-- An element in the metadata set. -->
+  <!-- Note that the name attribute isn't really Dublin Core compliant - it was just the first thing I came up with. -->
+  <!ELEMENT Element (Attribute*,Language*,OptionList?)>
+  <!ATTLIST Element
+            name       CDATA #REQUIRED
+	    occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->	
+  <!-- Given that name was already used for an Element, I decided to use identifier for the language specific 'name', which I've been told isn't really compliant with Dublin Core. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA "">
+
+  <!-- When used in conjuction with defer-node-expansion, allows for better memory use when dealing with several or more languages. -->
+  <!ELEMENT Language (Attribute*)>
+  <!ATTLIST Language
+	    code CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+]>
+<MetadataSet contact="nzgls@ssc.govt.nz" creator="Archives New Zealand" language_dependent="identifier, definition, comment" lastchanged="Fri Dec 03 14:35 2004 - mgw5 on narya" namespace="nzgls">
+    <!-- English Version sourced from http://www.e-government.govt.nz/nzgls/standard/ -->
+    <SetLanguage code="en">
+        <Name language="en">New Zealand Government Locator Service Metadata Standard version 2.1</Name>
+        <Description language="en">The NZGLS metadata standard is the official New Zealand Government standard for creating discovery-level metadata (see Cabinet Circular CO (02) 3). The standard is based closely on two well established standards: the Dublin Core Metadata Element Set and the Australian Government Locator Service.</Description>
+    </SetLanguage>
+    <Element name="Title" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Title</Attribute>
+            <Attribute name="definition">A name given to the resource.</Attribute>
+            <Attribute name="comment">Typically, a Title will be a name by which the resource is formally known.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Taitara</Attribute>
+            <Attribute name="definition">Te ingoa ka tapaina tetahi rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, ko te Taitara te ingoa ka mohio whanuitia te ingoa.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Titre</Attribute>
+            <Attribute name="definition">Le nom donnÃ© Ã  la ressource.</Attribute>
+            <Attribute name="comment">Typiquement, un titre sera le nom par lequel la ressource est officiellement connue.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ</Attribute>
+            <Attribute name="definition">ÐÐŒÑ, ÐŽÐ°ÐœÐœÐŸÐµ ÑÐµÑÑÑÑÑ.</Attribute>
+            <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµÐŒ ÑÐ²Ð»ÑÐµÑÑÑ ÐžÐŒÑ, Ð¿ÐŸÐŽ ÐºÐŸÑÐŸÑÑÐŒ ÑÐµÑÑÑÑ ÐŸÑÐžÑÐžÐ°Ð»ÑÐœÐŸ ÐžÐ·Ð²ÐµÑÑÐµÐœ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">TÃ­tulo</Attribute>
+            <Attribute name="definition">El nombre dado a un recurso, usualmente por el autor.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙØ¹ÙÙØ§Ù</Attribute>
+            <Attribute name="definition">ÙØ°Ø§ Ø§ÙØ§Ø³Ù
+ ÙØ¹Ø·Ù ÙÙÙ
+ØµØ¯Ø±, Ù
+Ù ÙØšÙ Ø§ÙÙ
+ØšØ¯Ø¹ Ø§Ù Ø§ÙÙØ§ØŽØ±</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">èµæºå</Attribute>
+            <Attribute name="definition">èµäºèµæºçåç§°ã</Attribute>
+            <Attribute name="comment">èµæºåäžè¬æèµæºå¯¹è±¡æ­£åŒå
+¬åŒçåç§°ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">NÃ¡zev</Attribute>
+            <Attribute name="definition">JmÃ©no danÃ© zdroji.</Attribute>
+            <Attribute name="comment">NÃ¡zev bude typicky jmÃ©no, pod nÃ­mÅŸ je zdroj oficiÃ¡lnÄ znÃ¡m.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Titel</Attribute>
+            <Attribute name="definition">De naam van de Internetbron. Meestal gegeven door de auteur, maker of uitgever</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Titulo</Attribute>
+            <Attribute name="definition">Un nomine date al ressource.</Attribute>
+            <Attribute name="comment">Typicamente se utiliza un nomine per le qual le ressource es formalmente cognite.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€¶à¥à€°à¥à€·à€</Attribute>
+            <Attribute name="definition">à€ªà€°à¥à€¯à€Ÿà€¯à¥ à€¶à¥à€°à¥à€·à€</Attribute>
+            <Attribute name="comment">à€žà€à€à¥à€·à€¿à€ªà¥à€€ ,  à€­à€Ÿà€·à€Ÿà€à€€à€°à¥à€€  à€¶à¥à€°à¥à€·à€</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Creator" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Creator</Attribute>
+            <Attribute name="definition">An entity primarily responsible for making the content of the resource.</Attribute>
+            <Attribute name="comment">Examples of a Creator include a person, an organisation, or a service. Typically, the name of a Creator should be used to indicate the entity.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Kaihanga</Attribute>
+            <Attribute name="definition">Te putahi, nana, na ratou ranei i matua oti ai te hanganga o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tangata, he putahitanga, he ratonga ranei etahi tauira Kaihanga. Ko te tikanga, ko te Kaihanga te ingoa ka whakamahia hei tohu i te putahi na ratou te hanganga.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">CrÃ©ateur</Attribute>
+            <Attribute name="definition">L&apos;entitÃ© principalement responsable de la crÃ©ation du contenu de la ressource.</Attribute>
+            <Attribute name="comment">Exemples de CrÃ©ateur incluent une personne, une organisation, ou un service. Typiquement, un nom du CrÃ©ateur devrait Ãªtre utilisÃ© pour dÃ©signer cette entitÃ©.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ</Attribute>
+            <Attribute name="definition">ÐÐžÑÐŸ, ÐœÐµÑÑÑÐµÐµ Ð¿ÐµÑÐ²ÐžÑÐœÑÑ ÐŸÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÐŸÑÑÑ Ð·Ð° ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÑÐžÐŒÐµÑÑ Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð¿ÐµÑÑÐŸÐœÑ, ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ ÐžÐ»Ðž ÑÐ»ÑÐ¶Ð±Ñ. ÐÐ±ÑÑÐœÐŸ ÐžÐŒÑ Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐžÐž ÐŸÐ±ÑÐµÐºÑÐ°.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Autor o Creador</Attribute>
+            <Attribute name="definition">La persona u organizaciÃ³n responsable de la creaciÃ³n del contenido intelectual del recurso. Por ejemplo, los autores en el caso de documentos escritos, artistas, fotografos e ilustradores en el caso de recursos visuales.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙØ§ØªØš Ø§Ù Ø§ÙÙ
+ØšØ¯Ø¹</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙØŽØ®Øµ Ø§Ù Ø§ÙÙ
+Ø€Ø³Ø³Ø© Ø£ÙÙØ§  Ø¹Ù ÙØŽØŠ Ø§ÙÙ
+Ø­ØªÙÙ Ø§ÙÙÙØ± Ù ÙÙÙ
+ØµØ¯Ø± , Ø¹ÙÙ Ø³ØšÙÙ Ø§ÙÙ
+Ø«Ø§Ù , Ø§ÙÙ
+Ø€ÙÙÙÙ ÙÙ Ø­Ø§ÙØ© Ø§ÙØ«Ø§ØŠÙ Ø§ÙÙ
+ÙØªÙØšØ© , Ù Ø§ÙÙÙØ§ÙÙÙ , Ø§ÙÙ
+ØµÙØ±ÙÙ ÙÙ Ø­Ø§ÙØ© Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙÙ
+Ø±ØŠÙØ©</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">åå»ºè
+</Attribute>
+            <Attribute name="definition">åå»ºèµæºå
+å®¹çäž»èŠèŽ£ä»»è
+ã</Attribute>
+            <Attribute name="comment">åå»ºè
+çå®äŸå
+æ¬äžªäººïŒç»ç»ææé¡¹æå¡ãäžè¬èèšïŒçšåå»ºè
+çåç§°æ¥æ è¯è¿äžæ¡ç®ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">TvÅ¯rce</Attribute>
+            <Attribute name="definition">Entita primÃ¡rnÄ odpovÄdnÃ¡ za vytvoÅenÃ­ obsahu zdroje.</Attribute>
+            <Attribute name="comment">PÅÃ­klady TvÅ¯rce zahrnujÃ­ osobu, organizaci nebo sluÅŸbu. K oznaÄenÃ­ entity se typicky pouÅŸÃ­vÃ¡ jmÃ©no tvÅ¯rce.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Auteur of maker</Attribute>
+            <Attribute name="definition">De auteur, maker of organisatie die primair verantwoordelijk is voor de intellectuele inhoud van het werk. Bijvoorbeeld auteurs in geval van geschreven documenten, artiesten, fotografen of illustrators in geval van visuele bronnen.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Creator</Attribute>
+            <Attribute name="definition">Le entitate primarimente responsabile pro producer le contento del ressource.</Attribute>
+            <Attribute name="comment">Exemplos de creator include un persona, un organization, o un servicio. Typicamente se utiliza un nomine de creator pro indicar iste entitate.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€šà€¿à€°à¥à€®à€Ÿà€€à€Ÿ, à€à€šà€</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ à€šà€¿à€°à¥à€®à€Ÿà€£  à€à€°à€£à€Ÿà€°à€Ÿ</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ.  à€²à¥à€à€, à€²à¥à€à€¿à€à€Ÿ,  à€µà¥à€¯à€à¥à€€à¥, à€žà€à€žà¥à€¥à€Ÿ,  à€žà€à€ªà€Ÿà€Šà€, à€žà€à€ªà€Ÿà€Šà€¿à€à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Function">
+        <Attribute language="en" name="identifier">Function</Attribute>
+        <Attribute language="en" name="obligation">Mandatory</Attribute>
+        <Attribute language="en" name="definition">The business function of the organisation to which the resource relates</Attribute>
+        <Attribute language="en" name="comment">Used to indicate the business role of the resource in terms of business functions and activities. Functions are the major units of activity which organisations pursue in order to meet the mission and goals of the organisation. They are defined in the Australian Records Management Standard [AS4390] as the largest unit of business activity in an organisation. Recommended best practice is to select a value from a controlled vocabulary or formal classification scheme. Resources being described within the NZ Government should use the Functions of New Zealand (FONZ) thesaurus. Use of this encoding scheme is mandatory for metadata prepared for use by the NZ Government Portal.</Attribute>
+    </Element>
+    <Element name="Subject" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Subject and Keywords</Attribute>
+            <Attribute name="definition">The topic of the content of the resource.</Attribute>
+            <Attribute name="comment">Typically, a Subject will be expressed as keywords, key phrases or classification codes that describe a topic of the resource. Recommended best practice is to select a value from a controlled vocabulary or formal classification scheme.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Kaupapa</Attribute>
+            <Attribute name="definition">Te take/ nga take o te kaupapa, o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, ka whakaaturia te kaupapa o te rauemi e nga kupu matua, nga kimahi matua, nga tohu wehewehenga whakaahua ranei.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Sujet</Attribute>
+            <Attribute name="definition">Le sujet du contenu de la ressource.</Attribute>
+            <Attribute name="comment">Typiquement, le sujet sera dÃ©crit par un ensemble de mots-clefs ou de phrases ou un code de classification qui prÃ©cisent le sujet de la ressource. L&apos;utilisation de vocabulaires contrÃŽlÃ©s et de schÃ©mas formels de classification est encouragÃ©e.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÑÐµÐŽÐŒÐµÑ Ðž ÐºÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð°</Attribute>
+            <Attribute name="definition">Ð¢ÐµÐŒÐ° ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÐÑÐµÐŽÐŒÐµÑ Ð²ÑÑÐ°Ð¶Ð°ÐµÑÑÑ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐºÐ»ÑÑÐµÐ²ÑÑ
+ ÑÐ»ÐŸÐ², ÐºÐ»ÑÑÐµÐ²ÑÑ
+ ÑÑÐ°Ð· ÐžÐ»Ðž  ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÑÑ
+ ÐºÐŸÐŽÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÑÑ ÑÐµÐŒÑ ÑÐµÑÑÑÑÐ°. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ ÐžÐ»Ðž ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÑ
+ÐµÐŒÑ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Claves</Attribute>
+            <Attribute name="definition">Los tÃ³picos del recurso. TÃ­picamente, Subject expresarÃ¡ las claves o frases que describen el tÃ­tulo o el contenido del recurso. Se fomentarÃ¡ el uso de vocabularios controlados y de sistemas de clasificaciÃ³n formales. Se pueden ver ejemplos de vocabularios controlados en: Controlled vocabularies, thesauri and classification systems available in the WWW. DC Subject</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙ
+ÙØ¶ÙØ¹ Ù Ø§ÙÙÙÙ
+Ø§Øª Ø§ÙØ±ØŠÙØ³ÙØ©</Attribute>
+            <Attribute name="definition">ÙÙ Ù
+ÙØ¶ÙØ¹ Ø§ÙÙ
+ØµØ¯Ø±. ÙÙ
+ÙØ°Ø¬ÙØ§  ÙØ¹ØšØ± Ø¹Ù Ø§ÙÙ
+ÙØ¶ÙØ¹ ØšØ§Ø³ØªØ®Ø¯Ø§Ù
+Ù
+ÙØªØ§Ø­  Ø§ÙÙÙÙ
+Ø§Øª  Ø§Ù Ø¬Ù
+Ù Ø§ÙØªÙ  ØªØµÙ Ù
+ÙØ¶ÙØ¹ Ø§Ù Ù
+Ø­ØªÙÙ Ø§ÙÙ
+ØµØ¯Ø± , Ù ÙØ³ØªØ­Ø³Ù Ø§Ø³ØªØ®Ø¯Ø§Ù
+ Ù
+ÙØ±Ø¯Ø§Øª Ù
+Ø®Ø·Ø·Ø©Ù Ù
+Ø­ÙÙ
+Ø©  ÙØ§Ø¯ÙØ© ØªØµÙÙÙ ØŽÙÙÙØ©</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">äž»é¢åå
+³é®è¯</Attribute>
+            <Attribute name="definition">èµæºå
+å®¹çäž»é¢æè¿°ã</Attribute>
+            <Attribute name="comment">åŠæèŠæè¿°ç¹å®èµæºçæäžäž»é¢ïŒäžè¬éçšå
+³é®è¯ãå
+³é®å­ç­è¯­æåç±»å·ïŒæå¥œäž»é¢åå
+³é®è¯ä»åæ§    è¯è¡šæè§èçåç±»äœç³»äž­ååŒã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">PÅedmÄt a klÃ­ÄovÃ¡ slova</Attribute>
+            <Attribute name="definition">TÃ©ma obsahu zdroje.</Attribute>
+            <Attribute name="comment">PÅedmÄt bude typicky vyjÃ¡dÅen pomocÃ­ klÃ­ÄovÃœch slov, klÃ­ÄovÃœch frÃ¡zÃ­ nebo klasifikaÄnÃ­ch znakÅ¯ popisujÃ­cÃ­ch tÃ©ma zdroje. DoporuÄuje se vybÃ­rat hodnotu prvku z ÅÃ­zenÃ©ho slovnÃ­ku nebo formÃ¡lnÃ­ho klasifikaÄnÃ­ho schÃ©matu.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Onderwerp en trefwoorden</Attribute>
+            <Attribute name="definition">Het onderwerp van de Internetbron. Het onderwerp wordt beschreven in korte zinnen of door het gebruik van trefwoorden. Het gebruik van gecontroleerde trefwoorden of classificatie schema&apos;s wordt aanbevolen.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Subjecto e parolas-clave</Attribute>
+            <Attribute name="definition">Le topico del contento del ressource.</Attribute>
+            <Attribute name="comment">Typicamente le subjecto es expresse per medio de parolas-clave, phrases-clave, o codices de classification que describe le topico del ressource. Le melior practica recommendate es selectionar un valor a partir de un vocabulario controlate o un schema formal de classification.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€µà€¿à€·à€¯</Attribute>
+            <Attribute name="definition">à€µà€¿à€·à€¯</Attribute>
+            <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ, à€à¥à€à€Ÿà€šà€žà€Ÿà€§à€šà¥ à€¯à€Ÿà€€à¥à€² à€à€¶à€¯ à€žà¥à€ªà€·à¥à€ à€à€°à€£à€Ÿà€°à¥ à€¶à€¬à¥à€Š, à€µà€¿à€·à€¯à€Ÿà€à¥ à€µà€°à¥à€à¥à€à€°à€£ à€à€°à€€à€Ÿà€šà€Ÿ à€¶à€¬à¥à€Šà€žà€à€à¥à€°à€¹ à€
+à€¥à€µà€Ÿ à€¶à€¬à¥à€Š à€à¥à€·à€Ÿà€à€Ÿ à€µà€Ÿà€ªà€° à€à€°à€Ÿà€µà€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Description" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Description</Attribute>
+            <Attribute name="definition">An account of the content of the resource.</Attribute>
+            <Attribute name="comment">Description may include but is not limited to: an abstract, table of contents, reference to a graphical representation of content or a free-text account of the content.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Whakaaturanga</Attribute>
+            <Attribute name="definition">He whakaaturanga o nga kaupapa o te rauemi.</Attribute>
+            <Attribute name="comment">Ka uru atu, engari ehara noa ko: te whakarapopototanga korero, te ihirangi, te tohutanga o te kaupapa ma te whakaahua, te whakaaturanga kore kupu ranei, o te kauapapa.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Description</Attribute>
+            <Attribute name="definition">Une description du contenu de la ressource.</Attribute>
+            <Attribute name="comment">Une Description peut contenir, mais ce n&apos;est pas limitatif: un rÃ©sumÃ©, une table des matiÃšres, une rÃ©fÃ©rence Ã  une reprÃ©sentation graphique du contenu, ou un texte libre sur le contenu.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÐ¿ÐžÑÐ°ÐœÐžÐµ</Attribute>
+            <Attribute name="definition">Ð¡ÐŸÐŸÐ±ÑÐµÐœÐžÐµ ÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐž ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ¿ÐžÑÐ°ÐœÐžÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐŸ (Ð¿ÐŸ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÑÑÐž) Ð² Ð²ÐžÐŽÐµ: ÑÐµÑÐµÑÐ°ÑÐ°, ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÑ, ÑÑÑÐ»ÐºÐž ÐœÐ° Ð³ÑÐ°ÑÐžÑÐµÑÐºÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÐžÐ»Ðž Ð¿ÑÐŸÑÑÐŸÐ³ÐŸ ÑÐµÐºÑÑÐŸÐ²ÐŸÐ³ÐŸ ÐžÐ·Ð»ÐŸÐ¶ÐµÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">DescripciÃ³n</Attribute>
+            <Attribute name="definition">Una descripciÃ³n textual del recurso, tal como un resumen en el caso de un documento o una descripciÃ³n del contenido en el caso de un documento visual.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙØµÙ</Attribute>
+            <Attribute name="definition">ÙÙ ÙØµÙ ÙØµÙ  ÙÙ
+Ø­ØªÙÙ Ø§ÙÙ
+ØµØ¯Ø±, ÙÙØ¶Ù
+ Ø§ÙÙ
+ÙØ®ØµØ§Øª ÙÙ Ø­Ø§ÙØ© Ø§ÙÙØ«Ø§ØŠÙ Ù
+Ø«Ù Ø§ÙØ§ØŽÙØ§Ø¡ Ø§ÙÙ
+ÙØªÙØšØ© Ø§Ù ØªÙØµÙÙ Ø§ÙÙ
+Ø­ØªÙÙ ÙÙ Ø­Ø§ÙØ© Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙÙ
+Ø±ØŠÙØ©</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">è¯Žæ</Attribute>
+            <Attribute name="definition">èµæºå
+å®¹çè§£é</Attribute>
+            <Attribute name="comment">è¯Žæå¯ä»¥å
+æ¬äœäžéäºä»¥äžå
+å®¹ïŒææãç®åœãå¯¹ä»¥åŸåœ¢æ¥æ­ç€ºå
+å®¹çèµæºèèšçæå­è¯Žæãæè
+äž    äžªæå
+³èµæºå
+å®¹çèªç±ææ¬æè¿°ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Popis</Attribute>
+            <Attribute name="definition">VysvÄtlenÃ­ obsahu zdroje.</Attribute>
+            <Attribute name="comment">Popis mÅ¯ÅŸe obsahovat (mimo jinÃ©): abstrakt, obsah, odkaz na grafickÃ© nebo volnÃ© textovÃ© vyjÃ¡dÅenÃ­ obsahu.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Omschrijving</Attribute>
+            <Attribute name="definition">Een omschrijving van de inhoud van de Internetbron. Abstracts of inhoudsomschrijvingen.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Description</Attribute>
+            <Attribute name="definition">Un description del contento del ressource.</Attribute>
+            <Attribute name="comment">Le description pote includer, ma non se limita a: summario, indice, referentia a un representation graphic del contento o un texto libere a proposito del contento.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€µà€°à¥à€£à€š</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥, à€à¥à€à€Ÿà€šà€žà€Ÿà€§à€šà€Ÿà€à¥à€µà€°à¥à€£à€š</Attribute>
+            <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€šà€¿à€µà¥à€Šà€š, à€à€²à¥à€, à€à€¿à€€à¥à€°à€°à¥à€ª</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Publisher" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Publisher</Attribute>
+            <Attribute name="definition">An entity responsible for making the resource available.</Attribute>
+            <Attribute name="comment">Examples of a Publisher include a person, an organisation, or a service. Typically, the name of a Publisher should be used to indicate the entity.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Kaiwhakaputa</Attribute>
+            <Attribute name="definition">Te putahi nana i whakaputa te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tangata, he putahitanga, he ratonga ranei etahi tauira Kaiwhakaputa. Ko te tikanga, ka whakamahia te ingoa o te Kaiwhakaputa hei tohu i te putahi.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Editeur</Attribute>
+            <Attribute name="definition">L&apos;entitÃ© responsable de la diffusion de la ressource, dans sa forme actuelle, tels, un dÃ©partement universitaire, une entreprise.</Attribute>
+            <Attribute name="comment">Exemples d&apos;Editeurs incluent une personne, une organisation, ou un service. Typiquement, le nom d&apos;une maison d&apos;Ã©dition devrait Ãªtre utilisÃ© ici.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÐ·ÐŽÐ°ÑÐµÐ»Ñ</Attribute>
+            <Attribute name="definition">ÐÐžÑÐŸ, ÐŸÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÐŸÐµ Ð·Ð° Ð²Ð²ÐŸÐŽ ÑÐµÑÑÑÑÐ° Ð² ÐŸÐ±ÑÐ°ÑÐµÐœÐžÐµ.</Attribute>
+            <Attribute name="comment">ÐÑÐžÐŒÐµÑÑ ÐÐ·ÐŽÐ°ÑÐµÐ»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð¿ÐµÑÑÐŸÐœÑ, ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ ÐžÐ»Ðž ÑÐ»ÑÐ¶Ð±Ñ. ÐÐ±ÑÑÐœÐŸ ÐžÐŒÑ ÐÐ·ÐŽÐ°ÑÐµÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐžÐž ÐŸÐ±ÑÐµÐºÑÐ°.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Editor</Attribute>
+            <Attribute name="definition">&gt;La entidad responsable de hacer que el recurso se encuentre disponible en la red en su formato actual, por ejemplo la empresa editora, un departamento universitario u otro tipo de organizaciÃ³n.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙØ§ØŽØ±</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙÙÙØŠØ© Ø§ÙÙ
+Ø³Ø€ÙÙØ© Ø¹Ù ØµÙØ§Ø¹Ø© Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙÙ
+ØªÙÙØ± ÙÙ Ø­Ø§ÙØªÙ Ø§ÙØ­Ø§Ø¶Ø±Ø©, Ù
+Ø«Ù Ø¯Ø§Ø± Ø§ÙÙØŽØ±, ÙØ³Ù
+ Ø¬Ø§Ù
+Ø¹Ù Ø§Ù Ù
+Ø€Ø³Ø³Ø© Ø§Ø¹Ù
+Ø§Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">åºçè
+</Attribute>
+            <Attribute name="definition">äœ¿èµæºæäžºå¯ä»¥è·åŸå¹¶å¯çšçèŽ£ä»»è
+ã</Attribute>
+            <Attribute name="comment">åºçè
+çå®äŸå
+æ¬äžªäœïŒç»ç»ïŒææå¡ãäžè¬èèšïŒåºè¯¥çšåºçè
+çåç§°æ¥æ è¯è¿äžæ¡ç®ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Vydavatel</Attribute>
+            <Attribute name="definition">Entita odpovÄdnÃ¡ za zpÅÃ­stupnÄnÃ­ zdroje.</Attribute>
+            <Attribute name="comment">PÅÃ­klady Vydavatele zahrnujÃ­ osobu, organizaci nebo sluÅŸbu. K oznaÄenÃ­ entity se typicky pouÅŸÃ­vÃ¡ jmÃ©no vydavatele.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Uitgever</Attribute>
+            <Attribute name="definition">De entiteit die verantwoordelijk is voor het beschikbaarstellen van de Internetbron in de huidig vorm. Bijvoorbeeld een uitgeversbedrijf, een universiteitsafdeling.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Editor</Attribute>
+            <Attribute name="definition">Un entitate responsabile pro disponibilizar le ressource.</Attribute>
+            <Attribute name="comment">Exemplos de editor include un persona, un organization, o un servicio. Typicamente se utiliza un nomine de editor pro indicar le entitate.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€ªà¥à€°à€à€Ÿà€¶à€</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ  à€à€ªà€²à€¬à¥à€§ à€à€°à¥à€š à€Šà¥à€£à€Ÿà€°à€Ÿ</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ.à€ à€ªà¥à€°à€à€Ÿà€¶à€ , à€ªà¥à€°à€à€Ÿà€¶à€š  à€žà€à€žà¥à€¥à€Ÿ, à€žà¥à€µà€Ÿ    à€®à€Ÿà€¹à€¿à€€à¥ à€à€Ÿà€ªà¥à€² à€°à¥à€ªà€Ÿà€€  à€
+à€¥à€µà€Ÿ à€à€à€à€°à€šà¥à€ à€µà€° à€à€ªà€²à€¬à¥à€§ à€à€°à¥à€š à€Šà¥à€£à€Ÿà€°à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Mandate">
+        <Attribute language="en" name="identifier">Mandate</Attribute>
+        <Attribute language="en" name="obligation">Recommended</Attribute>
+        <Attribute language="en" name="definition">A specific warrant which requires the resource to be created or provided.</Attribute>
+        <Attribute language="en" name="comment">The element is useful to indicate the specific legal mandate that requires the resource being described to be created or provided to the public. The content of this element will usually be a reference to a specific Act, Regulation or Case, but may be a URI pointing to the legal instrument in question.</Attribute>
+        <Element name="act">
+            <Attribute language="en" name="identifier">Act</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">A reference to a specific Act of Parliament which requires the creation or provision of the resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="regulation">
+            <Attribute language="en" name="identifier">Regulation</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">A reference to a specific regulation which requires the creation or provision of the resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="rules">
+            <Attribute language="en" name="identifier">Rules</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The specific rule or bylaw which requires the creation or provision of the resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="case">
+            <Attribute language="en" name="identifier">Case Law</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">A reference to a specific case which requires the creation or provision of the resource.</Attribute>
+            </Language>
+        </Element>
+    </Element>
+    <Element name="Contributor" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Contributor</Attribute>
+            <Attribute name="definition">An entity responsible for making contributions to the content of the resource.</Attribute>
+            <Attribute name="comment">Examples of a Contributor include a person, an organisation, or a service. Typically, the name of a Contributor should be used to indicate the entity.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Kaiwhakaaro</Attribute>
+            <Attribute name="definition">Te putahi nana, na ratou ranei nga whakakaupapatanga whakaaro o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tangata, he putahitanga, he ratonga ranei etahi tauira Kaiwhakaaro. Ko te tikanga ka whakamahia te ingoa o te Kaiwhakaaro hei tohu i te putahi.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Contributeur</Attribute>
+            <Attribute name="definition">Une entitÃ© qui a contribuÃ© Ã  la crÃ©ation du contenu de la ressource.</Attribute>
+            <Attribute name="comment">Exemples de Contributeur incluent une personne, une organisation, ou un service. Typiquement, le nom d&apos;un contributeur devrait Ãªtre utilisÃ© ici pour dÃ©signer l&apos;entitÃ©.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">Ð¡ÐŸÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ</Attribute>
+            <Attribute name="definition">ÐÐžÑÐŸ, Ð²ÐœÐµÑÑÐµÐµ Ð²ÐºÐ»Ð°ÐŽ Ð² ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÑÐžÐŒÐµÑÑ Ð¡ÐŸÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð¿ÐµÑÑÐŸÐœÑ, ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ ÐžÐ»Ðž ÑÐ»ÑÐ¶Ð±Ñ. ÐÐ±ÑÑÐœÐŸ ÐžÐŒÑ Ð¡ÐŸÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐžÐž ÐŸÐ±ÑÐµÐºÑÐ°.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Otros Colaboradores</Attribute>
+            <Attribute name="definition">Una persona u organizacion que haya tenido una contribuciÃ³n intelectual significativa en la creaciÃ³n del recurso pero cuyas contribuciones son secundarias en comparaciÃ³n a las de las personas u organizaciones especificadas en el elementeo Creator (por ejemplo, editor, ilustrador y traductor).</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙ
+Ø³Ø§ÙÙ
+ Ø§ÙØ§Ø®Ø±</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙØŽØ®Øµ Ø§Ù Ø§ÙÙ
+Ø€Ø³Ø³Ø© Ø§ÙØºÙØ± Ù
+Ø°ÙÙØ± ØµØ±Ø§Ø­Ø© ÙÙ Ø¹Ø§Ù
+Ù &quot; Ø§ÙÙ
+ØšØ¯Ø¹ &quot; Ù Ø§ÙØ°Ù ÙØ¯Ù
+ Ù
+Ø³Ø§ÙÙ
+Ø§Øª ÙÙØ±ÙØ© ÙØ§Ù
+Ø© ÙÙÙ
+ØµØ¯Ø±, ÙÙÙ Ù
+Ø³Ø§ÙÙ
+ØªÙØªØšÙÙ    Ø«Ø§ÙÙÙØ© Ù
+ÙØ§Ø±ÙØ© Ù
+Ø¹ Ø§ÙØŽØ®Øµ Ø£Ù Ø§ÙÙ
+Ø€Ø³Ø³Ø© Ø§ÙÙ
+Ø°ÙÙØ±Ø© ÙØµØ§ ÙÙ Ø¹Ø§Ù
+Ù &quot; Ø§ÙÙ
+ÙØŽØŠ &quot; Ù
+Ø«ÙØ§Ù Ù
+ØµØ­Ø­, Ø§ÙÙ
+ØªØ±Ø¬Ù
+, Ø§Ù Ø§ÙÙ
+ÙØ³Ø±</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">å
+¶ä»èŽ£ä»»è
+</Attribute>
+            <Attribute name="definition">å¯¹èµæºçå
+å®¹äœåºèŽ¡ç®çå
+¶ä»å®äœã</Attribute>
+            <Attribute name="comment">å
+¶ä»èŽ£ä»»è
+çå®äŸå¯å
+æ¬äžªäººãç»ç»ææé¡¹æå¡ãäžè¬èèšïŒçšå
+¶ä»èŽ£ä»»è
+çåå­æ¥æ è¯è¿äžæ¡ç®ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">PÅispÄvatel</Attribute>
+            <Attribute name="definition">Entita, kterÃ¡ pÅispÄla k vytvoÅenÃ­ obsahu zdroje.</Attribute>
+            <Attribute name="comment">PÅÃ­klady PÅispÄvatele zahrnujÃ­ osobu, organizaci nebo sluÅŸbu. K oznaÄenÃ­ entity se typicky pouÅŸÃ­vÃ¡ jmÃ©no pÅispÄvatele.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Andere medewerkers</Attribute>
+            <Attribute name="definition">Een persoon of organisatie die een belangrijke bijdrage heeft geleverd, maar die secondair is aan de persoon of organisatie die bij &quot;Creator&quot; genoemd wordt. Gedacht kan worden aan editors, vertalers en illustrators.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Contribuente</Attribute>
+            <Attribute name="definition">Un entitate responsabile pro facer contributiones al contento del ressource.</Attribute>
+            <Attribute name="comment">Exemplos de contribuente include un persona, un organization, o un servicio. Typicamente se utiliza un nomine de contribuente pro indicar le entitate.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier"> à€žà€¹à€¯à¥à€à€, à€žà€¹à€¯à¥à€à¥, à€žà€¹à€Ÿà€¯à¥à€¯à€</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ à€žà€à€à€²à¥à€€ à€à€°à€£à¥à¥à€Ÿà€ž  à€®à€Šà€€ à€à€°à€£à€Ÿà€°à¥ à€µà¥à€¯à€à¥à€€à¥</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ.à€ à€µà¥à€¯à€à¥à€€à¥, à€žà¥à€µà€Ÿ, à€žà€à€žà¥à€¥à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Date" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Date</Attribute>
+            <Attribute name="definition">A date associated with an event in the life cycle of the resource.</Attribute>
+            <Attribute name="comment">Typically, Date will be associated with the creation or availability of the resource.  Recommended best practice for encoding the date value is defined in a profile of ISO 8601 and follows the YYYY-MM-DD format.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Ra</Attribute>
+            <Attribute name="definition">He ra e whai panga ana ki te huringa ora o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, ka whai panga te ra ki te hanganga, te wateatanga ranei, o te rauemi. Ko te huarahi tino pai hei tohu i te uara o te ra (date value) kua whakaritea i roto i te whakaritenga IS0 8601 [W3CDTF], a, e whai atu ana ki te whakatakotoranga YYYY-MM-DD.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Date</Attribute>
+            <Attribute name="definition">Une date associÃ©e avec un Ã©vÃ©nement dans le cycle de vie de la ressource.</Attribute>
+            <Attribute name="comment">Typiquement, une date sera associÃ©e Ã  la crÃ©ation ou Ã  la publication d&apos;une ressource. Il est fortement recommandÃ© d&apos;encoder la valeur de la date en utilisant le format dÃ©fini par l&apos;ISO 8601 [W3CDTF] sous la forme AAAA-MM-JJ.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÐ°ÑÐ°</Attribute>
+            <Attribute name="definition">ÐÐ°ÑÐ°, ÑÐ²ÑÐ·Ð°ÐœÐœÐ°Ñ Ñ ÑÐŸÐ±ÑÑÐžÐµÐŒ Ð² Ð¶ÐžÐ·ÐœÐµÐœÐœÐŸÐŒ ÑÐžÐºÐ»Ðµ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÐÐ°ÑÐ° Ð°ÑÑÐŸÑÐžÐžÑÑÐµÑÑÑ Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµÐŒ ÐžÐ»Ðž ÐŽÐŸÑÑÑÐ¿ÐœÐŸÑÑÑÑ ÑÐµÑÑÑÑÐ°. ÐÐ° Ð¿ÑÐ°ÐºÑÐžÐºÐµ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐŽÐ»Ñ ÐºÐŸÐŽÐžÑÐŸÐ²ÐºÐž Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŽÐ°ÑÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÐµ Ð¿ÑÐŸÑÐžÐ»Ñ ISO 8601 (Ð€ÐŸÑÐŒÐ°ÑÑ ÐŽÐ°ÑÑ Ðž Ð²ÑÐµÐŒÐµÐœÐž W3C), ÐºÐŸÑÐŸÑÐŸÐµ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÐµÑ ÑÐŸÑÐŒÐ°Ñ ÐÐÐÐ-ÐÐ-ÐÐ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Fecha</Attribute>
+            <Attribute name="definition">Una fecha en la que el recurso se puso a disposiciÃ³n del usuario en su forma actual. Esta fecha no ha de confundirse con la que pertenece al elemento Coverage, que serÃ­a asociada con el recurso sÃ³lo en la medida en que el contenido intelectual estÃ¡ de algÃºn modo relacionado con esa fecha. Recomendamos la utiliazaciÃ³n de uno de los formatos definidos en el documento &quot;Date and Time Formats&quot;, http://www.w3.org/TR/NOTE-datetime basado en la norma ISO 8601 que incluye, entre otras, fechas en el formato AAAA y AAAA-MM-DD. De esta forma la fecha 1994-11-05 corresponderÃ­a al 5 de Noviembre de 1994.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙØªØ§Ø±Ø®</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙØªØ§Ø±ÙØ® Ø§ÙÙ
+ØªØ¹ÙÙ ØšÙÙØª ÙØŽØŠ Ø£Ù ØªÙÙØ± Ø§ÙÙ
+ØµØ¯Ø± . Ù ÙØ¬Øš Ø£Ù ÙØ§ ÙØ®ÙØ· ÙØ°Ø§ Ø§ÙØªØ§Ø±ÙØ® Ø§ÙØ¹Ø§ØŠØ¯ ÙØ¹Ø§Ù
+Ù Ø§ÙØªØºØ·ÙØ© , Ù Ø§ÙØ° Ù ÙØ¬Øš Ø£Ù    ÙÙØ­Ù ØšØ§ÙÙ
+ØµØ¯Ø± ÙÙØ· Ù
+Ù ÙØ§Ø­ÙØ© Ø§ÙÙ
+Ø­ØªÙÙØ§ÙÙÙØ±Ù ÙÙÙÙÙ ÙÙØ¹Ø§ Ù
+Ø§ ÙÙ ÙØ°Ø§ Ø§ÙØªØ§Ø±ÙØ®. Ø§ÙØµÙØºØ© Ø§ÙÙ
+Ø³Ø«Ø­Ø³ÙØ© ÙÙØ§Ø­Ø³Ù Ø§ÙÙ
+ØªØ¹Ø§Ø±Ù Ø¹ÙÙÙ    Ø¹ÙØ¯ Ø§ÙØªØ·ØšÙÙ ÙÙ Ø§ÙØµÙØºØ© Ø§ÙÙ
+Ø¹ØªÙ
+Ø¯Ø© ÙÙ ØªØŽÙÙÙ (ISO 8601) ØµÙØºØ© ØªØ§Ø±ÙØ® Ø§ÙÙÙÙ
+ Ù Ø§ÙÙÙØª ) Ø§Ø¹ØªÙ
+Ø§Ø¯Ø§ Ø¹ÙÙ (ISO 8601) Ø§ÙÙ
+ÙØ§Ø­ØžØ© Ø§ÙÙÙÙØ© http://www.w3.org/TR/NOTE-datetime, W3C. ÙÙÙ    ÙØ°Ø§ Ø§ÙÙØ³Ù , Ù
+Ø«ÙØ§, ØªØ§Ø±ÙØ® Ø§ÙÙÙÙ
+ 1994-11-04 ÙÙØ§ØžØ± ÙÙÙ
+ 5 ÙÙÙÙ
+ØšØ± 1994</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">æ¥æ</Attribute>
+            <Attribute name="definition">äžèµæºçåœåšæäž­çäžäžªäºä»¶çžå
+³çæ¶éŽã</Attribute>
+            <Attribute name="comment">äžè¬èèšïŒæ¥æåºäžèµæºçåå»ºæåºçæ¥æçžå
+³ãå»ºè®®éçšçæ¥ææ ŒåŒåºç¬ŠåISO 8601 [W3CDTF]è§    èïŒå¹¶äœ¿çšYYYY-MM-DDçæ ŒåŒã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Datum</Attribute>
+            <Attribute name="definition">Datum spojenÃ© s urÄitou udÃ¡lostÃ­ bÄhem existence zdroje.</Attribute>
+            <Attribute name="comment">Datum bude typicky spojeno s vytvoÅenÃ­m nebo zpÅÃ­stupnÄnÃ­m zdroje. DoporuÄenÃœ postup pro kÃ³dovÃ¡nÃ­ hodnoty data je definovÃ¡n v ISO 8601 [W3CDTF]: formÃ¡t RRRR-MM-DD.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Datum</Attribute>
+            <Attribute name="definition">De datum van de totstandkoming of beschikbaarstelling van een Internetbron. Deze datum moet niet verward worden met de datum in &quot;Coverage&quot;. De datum in &quot;Coverage&quot; geeft de tijdsperiode van de inhoud van de Internetbron aan. Voorgeschreven wordt de ISO 8601 standaard voor datum, zoals beschreven in W3C Technical Note http://www.w3.org/TR/NOTE-datetime. Hierin wordt het formaat YYYY-MM-DD beschreven. Het formaat YYYY-MM-DD wordt de voorgeschreven standaard. 3 September 1998 wordt in dit geval 1998-09-03.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Data</Attribute>
+            <Attribute name="definition">Un data associate a un evento in le cyclo vital del ressource.</Attribute>
+            <Attribute name="comment">Typicamente le data es associate al creation o disponibilization del ressource. Le practica recommendate pro codificar le valor del datas es definite in un profilo de ISO 8601 [W3CDTF] e seque le formato AAAA-MM-DD.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€€à€Ÿà€°à¥à€,  à€Šà€¿à€šà€Ÿà€à€</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ à€€à€¯à€Ÿà€° à€à¥à€²à¥à€¯à€Ÿà€à¥ à€€à€Ÿà€°à¥à€</Attribute>
+            <Attribute name="comment">à€€à€Ÿà€°à¥à€  à€²à€¿à€¹à¥à€£à¥à€¯à€Ÿà€à¥ à€žà¥à€µà€°à¥à€ª à€ à€µà€°à¥à€·. à€®à€¹à€¿à€šà€Ÿ. à€Šà€¿à€µà€ž à¥§à¥¯à¥«à¥Š. à¥Šà¥ª. à¥Šà¥ª</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="created">
+            <Attribute language="en" name="identifier">Created</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">Date of creation of the resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="modified">
+            <Attribute language="en" name="identifier">Modified</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">Date on which the resource was changed.</Attribute>
+            </Language>
+        </Element>
+        <Element name="valid">
+            <Attribute language="en" name="identifier">Valid</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">Date (often a range) of validity of a resource.</Attribute>
+                <Attribute name="comment">Typically, a date the resource becomes valid or ceases to be valid, or the date range for which the resource is valid.</Attribute>
+            </Language>
+        </Element>
+        <Element name="issued">
+            <Attribute language="en" name="identifier">Issued</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">Date of formal issuance (e.g. publication) of the resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="available">
+            <Attribute language="en" name="identifier">Available</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">Date (often a range) that the resource will become or did become available.</Attribute>
+            </Language>
+        </Element>
+    </Element>
+    <Element name="Type" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Resource Type</Attribute>
+            <Attribute name="definition">The nature or genre of the content of the resource.</Attribute>
+            <Attribute name="comment">Type includes terms describing general categories, functions, genres, or aggregation levels for content. Recommended best practice is to select a value from a controlled vocabulary (for example, the working draft list of Dublin Core Types). To describe the physical or digital manifestation of the resource, use the FORMAT element.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Tumomo</Attribute>
+            <Attribute name="definition">Te ahua, te tu-ahuatanga ranei o nga kaupapa o te rauemi.</Attribute>
+            <Attribute name="comment">Kei roto i te Tumomo nga kupu whakaatu i nga wehewehenga whanui, nga aheinga, nga tu-ahuatanga, te whakaritenga ranei o nga taumata o te/ nga kaupapa. Ko te huarahi tino pai kua tohua, ko te tipako i tetahi uara mai i nga kupu kua whakaritea (hei tauira, ko te tauira rarangi e whakamahia ana o nga Dublin Core Types [DCT1]. Hei whakaatu i te whakatinanatanga o te rauemi, whakamahia ko te huanga WHAKATAKOTORANGA (FORMAT).</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Type</Attribute>
+            <Attribute name="definition">La nature ou le genre du contenu de la ressource.</Attribute>
+            <Attribute name="comment">Type inclut des termes dÃ©crivant des catÃ©gories, fonctions ou genres gÃ©nÃ©raux pour le contenu, ou des niveaux d&apos;agrÃ©gation. Il est recommandÃ© de choisir la valeur du type dans une liste de vocabulaire contrÃŽlÃ© (par exemple, la liste provisoire de Types du Dublin Core[DCT1]). Pour dÃ©crire la matÃ©rialisation physique ou digitale de la ressource, il faut utiliser l&apos;Ã©lÃ©ment Format.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">Ð¢ÐžÐ¿ ÑÐµÑÑÑÑÐ°</Attribute>
+            <Attribute name="definition">ÐÑÐžÑÐŸÐŽÐ° ÐžÐ»Ðž Ð¶Ð°ÐœÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">Ð¢ÐžÐ¿ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÑÐµÑÐŒÐžÐœÑ, ÐŸÐ¿ÐžÑÑÐ²Ð°ÑÑÐžÐµ ÐŸÐ±ÑÐžÐµ ÐºÐ°ÑÐµÐ³ÐŸÑÐžÐž, ÑÑÐœÐºÑÐžÐž, Ð¶Ð°ÐœÑÑ ÐžÐ»Ðž ÐŸÐ±ÑÐµÐŽÐžÐœÐµÐœÐœÑÐµ ÑÑÐŸÐ²ÐœÐž ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐ°Ð±ÐŸÑÐµÐ³ÐŸ Ð¿ÑÐŸÐµÐºÑÐ° ÑÐ¿ÐžÑÐºÐ° Ð¢ÐžÐ¿ÐŸÐ² Dublin Core DCT1). ÐÐ»Ñ ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ ÑÐžÐ·ÐžÑÐµÑ-ÐºÐŸÐ³ÐŸ ÐžÐ»Ðž ÑÐžÑÑÐŸÐ²ÐŸÐ³ÐŸ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÑÐµÑÑÑÑÐ° ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÑÐ»ÐµÐŒÐµÐœÑ Ð€ÐŸÑÐŒÐ°Ñ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Tipo del Recurso</Attribute>
+            <Attribute name="definition">La categorÃ­a del recurso, por ejemplo pÃ¡gina personal, romance, poema, minuta, diccionario. Para asegurar la interoperabilidad, Type deberÃ­a ser seleccionado de entre una lista de valores que actualmente se encuentra bajo desarrollo en un grupo de trabajo. En http://sunsite.berkeley.edu/Metadata/types.html se puede consultar el estado actual de la discusiÃ³n en torno a este tema.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">ÙÙØ¹ Ø§ÙÙ
+ØµØ¯Ø±</Attribute>
+            <Attribute name="definition">ÙÙ ÙØŠØ© Ø§ÙÙ
+ØµØ¯Ø± , Ù
+Ø«ÙØ§ Ø§ÙØµÙØ­Ø© Ø§ÙØ§Ù
+, Ø±ÙØ§ÙØ© , ÙØ·Ø¹Ø© ØŽØ¹Ø±ÙØ© , ÙØ±ÙØ© Ø¹Ù
+Ù , ØªÙØ±ÙØ± ÙÙÙ , Ù
+ÙØ§Ù , ÙØ§Ù
+ÙØ³ . Ù Ù
+Ù Ø£Ø¬Ù Ø§ÙØªØ¹Ø§Ù
+Ù Ø§ÙÙ
+ØŽØªØ±Ù    ÙØ¬Øš Ø£Ù ÙØ®ØªØ§Ø± Ø§ÙÙÙØ¹ Ù
+Ù Ø§ÙÙØ§ØŠÙ
+Ø© Ø§ÙÙ
+Ø±ÙÙ
+Ø© ÙØ§ÙØªÙ ÙÙÙ
+ Ø§Ø¹Ø¯Ø§Ø¯ÙØ§ Ø­Ø§ÙÙØ§ Ø¶Ù
+Ù Ø­ÙÙØ§Øª ÙØ±ØŽØ© Ø¹Ù
+Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">èµæºç±»å</Attribute>
+            <Attribute name="definition">èµæºå
+å®¹çç¹åŸæç±»åã</Attribute>
+            <Attribute name="comment">èµæºç±»åå
+æ¬æè¿°èµæºå
+å®¹çäžè¬èçŽïŒåèœïŒç§å±ïŒæèç±»å±æ¬¡çæ¯è¯­ãå»ºè®®éçšæ¥èªäºåæ§è¯è¡š    äž­çåŒïŒäŸåŠDCMIç±»åè¯æ±è¡š[DCMITYPE]ïŒãèŠæè¿°èµæºçç©çææ°å­åè¡šç°åœ¢åŒïŒè¯·äœ¿çšâæ ŒåŒïŒFORMATïŒâå
+çŽ ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Typ zdroje</Attribute>
+            <Attribute name="definition">Povaha nebo druh obsahu zdroje.</Attribute>
+            <Attribute name="comment">Typ obsahuje termÃ­ny popisujÃ­cÃ­ obecnÃ© kategorie, funkce, druhy nebo agregaÄnÃ­ ÃºrovnÄ obsahu. DoporuÄuje se vybÃ­rat hodnotu z ÅÃ­zenÃ©ho slovnÃ­ku (napÅ. pracovnÃ­ nÃ¡vrh seznamu TypÅ¯ Dublin Core [DCT1]). K popisu fyzickÃ© nebo digitÃ¡lnÃ­ reprezentace zdroje uÅŸijte prvek FormÃ¡t.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Bestands type</Attribute>
+            <Attribute name="definition">Het soort Internetbron, bijvoorbeeld home page, gedicht, working paper, technical report, essay, woordenboek etc. De DC working groups zijn momenteel bezig met twee voorstellen; een minimalist draft: http://sunsite.berkeley.edu/Metadata/minimalist.html en een structuralist draft: http://sunsite.berkely.edu/Metadata/structuralist.html. Het wordt sterk aanbevolen om &quot;Type&quot; van deze lijsten te selecteren.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Typo del ressource</Attribute>
+            <Attribute name="definition">Le natura o genere del contento del ressource.</Attribute>
+            <Attribute name="comment">Le typo del ressource include terminos que describe categorias general, functiones, generes, o nivellos de aggregation pro le contento. Le practica recommendate es selectionar un valor a partir de un vocabulario controlate (per exemplo, le lista de schizzos de travalio de typos de Dublin Core [DCT1]). Pro describer le manifestation physic o digital del ressource, utiliza le elemento Formato.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€ªà¥à€°à€à€Ÿà€°</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à€Ÿà€ªà¥à€°à€à€Ÿà€°</Attribute>
+            <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€µà€°à¥à€à¥à€à€°à€£, à€µà€°à¥à€à€µà€Ÿà€°à¥à€®à€§à¥à€¯à¥ à€à€à€Ÿà€Šà¥à€¯à€Ÿ à€šà¥à€à€Šà¥à€à€Ÿ à€®à¥à€à¥à€¯ à€à€à€ªà¥à€°à€à€Ÿà€°</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="category">
+            <Attribute language="en" name="identifier">Category</Attribute>
+            <Attribute language="en" name="type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The generic type of the resource being described.</Attribute>
+                <Attribute name="comment">The value for this qualifier must be one of service, document, or agency.</Attribute>
+            </Language>
+            <Attribute language="en" name="source">AGLS</Attribute>
+            <Attribute language="en" name="service">used when describing a service directly, not a document about a service.</Attribute>
+            <Attribute language="en" name="document">used for all resources which are not services or agencies, even if they are no traditional &amp;quot;documents&amp;quot; - for example, a sculpture;</Attribute>
+            <Attribute language="en" name="agency">used to describe an organisation</Attribute>
+        </Element>
+        <Element name="aggregationLevel">
+            <Attribute language="en" name="identifier">Aggregation Level</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The level of aggregation of the resource being described.</Attribute>
+                <Attribute name="comment">There are only two values possible for this qualifier, either item or collection.</Attribute>
+            </Language>
+        </Element>
+    </Element>
+    <Element name="Format" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Format</Attribute>
+            <Attribute name="definition">The physical or digital manifestation of the resource.</Attribute>
+            <Attribute name="comment">Typically, Format may include the media-type or dimensions of the resource. Format may be used to determine the software, hardware or other equipment needed to display or operate the resource. Examples of dimensions include size and duration. Recommended best practice is to select a value from a controlled vocabulary (for example, the list of Internet Media Types [MIME] defining computer media formats).</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Whakatakotoranga</Attribute>
+            <Attribute name="definition">Te whakatinanatanga, te whakaputanga a-mati o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, ka taea te Whakatakotoranga te whakamahi hei whakarite i te rawa-ngohe (software), te rawa-maro (hardware), ma etahi taputapu ranei me matua whiwhi, hei whakahaere i te rauemi. Ko te rahi me te roanga etahi tauira hanga. Ko te tino huarahi kua tohua ko te tipako uara mai i tetahi whakaritenga kupu (hei tauira, te rarangi o nga Tumomo Papaho Ipurangi (Internet Media Types [MIME]) e whakaatu ana i nga whakatakotoranga papaho rorohiko.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Format</Attribute>
+            <Attribute name="definition">La matÃ©rialisation physique ou digitale de la ressource.</Attribute>
+            <Attribute name="comment">Typiquement, Format peut inclure le media ou les dimensions de la ressource. Format peut Ãªtre utilisÃ© pour prÃ©ciser le logiciel, le matÃ©riel ou autre Ã©quipement nÃ©cessaire pour afficher ou faire fonctionner la ressource. Exemples de dimensions incluent la taille et la durÃ©e. Il est recommandÃ© de choisir la valeur du format dans une liste de vocabulaire contrÃŽlÃ©(par exemple, la liste des types de media dÃ©finis sur Internet [MIME]).</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">Ð€ÐŸÑÐŒÐ°Ñ</Attribute>
+            <Attribute name="definition">Ð€ÐžÐ·ÐžÑÐµÑÐºÐŸÐµ ÐžÐ»Ðž ÑÐžÑÑÐŸÐ²ÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ Ð€ÐŸÑÐŒÐ°Ñ ÐŒÐŸÐ¶ÐµÑ Ð²ÐºÐ»ÑÑÐ°ÑÑ ÑÐžÐ¿ Ð°ÑÐŽÐžÐŸÐ²ÐžÐ·ÑÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž (ÐŒÐµÐŽÐžÐ°-ÑÐžÐ¿) ÐžÐ»Ðž Ð²ÐµÐ»ÐžÑÐžÐœÑ ÑÐµÑÑÑÑÐ°. Ð€ÐŸÑÐŒÐ°Ñ ÐŒÐŸÐ¶ÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ ÐŽÐ»Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ Ð°Ð¿Ð¿Ð°ÑÐ°ÑÐœÐŸÐ³ÐŸ, Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐ³ÐŸ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ ÐžÐ»Ðž ÐŽÑÑÐ³ÐŸÐ³ÐŸ ÐŸÐ±ÐŸÑÑÐŽÐŸÐ²Ð°ÐœÐžÑ, ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÐ³ÐŸ ÐŽÐ»Ñ Ð²ÐŸÑÐ¿ÑÐŸÐžÐ·Ð²ÐµÐŽÐµÐœÐžÑ ÐžÐ»Ðž ÑÐ°Ð±ÐŸÑÑ Ñ ÑÐµÑÑÑÑÐŸÐŒ. ÐÑÐžÐŒÐµÑÑ Ð²ÐµÐ»ÐžÑÐžÐœÑ Ð²ÐºÐ»ÑÑÐ°ÑÑ ÑÐ°Ð·ÐŒÐµÑ Ðž Ð¿ÑÐŸÐŽÐŸÐ»Ð¶ÐžÑÐµÐ»ÑÐœÐŸÑÑÑ. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐ¿ÐžÑÐºÐ° ÐÐµÐŽÐžÐ°-ÑÐžÐ¿ÐŸÐ² ÐÐœÑÐµÑÐœÐµÑ MIME, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÑÑÐµÐ³ÐŸ ÐºÐŸÐŒÐ¿ÑÑÑÐµÑÐœÑÐµ ÑÐŸÑÐŒÐ°ÑÑ Ð°ÑÐŽÐžÐŸÐ²ÐžÐ·ÑÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž).</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Formato</Attribute>
+            <Attribute name="definition">El formato de datos de un recurso, usado para identificar el software y posiblemente, el hardware que se necesitarÃ­a para mostrar el recurso. Para asegurar la interoperabilidad, los valores de Format deberÃ­an ser seleccionados de entre una lista de valores que actualmente se encuentra bajo desarrollo en un grupo de trabajo.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙØµÙØºØ©</Attribute>
+            <Attribute name="definition">ÙØ°Ù ØµÙØºØ© Ø§ÙÙ
+Ø¹ÙÙÙ
+Ø© Ø§ÙØ®Ø§ØµØ© ØšØ§ÙÙ
+ØµØ¯Ø± , Ù ØªØ³ØªØ®Ø¯Ù
+ ÙÙØªØ¹Ø±ÙÙ ØšØ§ÙØšØ±Ù
+Ø¬ÙØ§Øª ÙØ±ØšÙ
+Ø§ Ø§ÙØµÙØš ÙÙØ­Ø§Ø³ÙØš Ù Ø§ÙØªÙ ÙÙ
+ÙÙ Ø£Ù ÙØ­ØªØ§Ø¬    ÙÙØ§ ÙØ¹Ø±Ø¶ Ø£Ù ØªØŽØºÙÙ Ø§ÙÙ
+ØµØ¯Ø± . Ù
+Ù Ø£Ø¬Ù Ø§ÙØªØ¹Ø§Ù
+Ù Ø§ÙÙ
+ØŽØªØ±Ù, ÙØ¬Øš Ø£Ù ØªØ®ØªØ§Ø± Ø§ÙØµÙØºØ© Ù
+Ù Ø§ÙÙØ§ØŠÙ
+Ø© Ø§ÙÙ
+Ø±ÙÙ
+Ø© Ù Ø§ÙØªÙ ÙØªÙ
+ Ø§Ø¹Ø¯Ø§Ø¯ÙØ§    Ø­Ø§ÙÙØ§ Ø¶Ù
+Ù Ø­ÙÙØ§Øª ÙØ±ØŽØ© Ø¹Ù
+Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">æ ŒåŒ</Attribute>
+            <Attribute name="definition">èµæºçç©çææ°å­è¡šç°åœ¢åŒã</Attribute>
+            <Attribute name="comment">äžè¬èèšïŒæ ŒåŒå¯èœå
+æ¬èµæºçåªäœç±»åæèµæºçå€§å°ïŒæ ŒåŒå
+çŽ å¯ä»¥çšæ¥å³å®å±ç€ºææäœèµæºæé    çèœ¯ç¡¬ä»¶æå
+¶ä»çžåºè®Ÿå€ïŒäŸåŠå€§å°å
+æ¬èµæºæå çå­åšç©ºéŽåæç»­æ¶éŽãå»ºè®®éçšæ¥èªäºåæ§è¯è¡š    äž­çåŒïŒïŒäŸåŠInternetåªäœç±»å[MIME]å®ä¹è®¡ç®æºåªäœæ ŒåŒïŒã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">FormÃ¡t</Attribute>
+            <Attribute name="definition">FyzickÃ¡ nebo digitÃ¡lnÃ­ reprezentace zdroje.</Attribute>
+            <Attribute name="comment">Typicky mÅ¯ÅŸe FormÃ¡t obsahovat typ mÃ©dia nebo rozmÄry zdroje. FormÃ¡t lze pouÅŸÃ­vat k urÄenÃ­ softwaru, hardwaru nebo dalÅ¡Ã­ho zaÅÃ­zenÃ­ potÅebnÃ©ho k zobrazenÃ­ nebo k manipulaci se zdrojem. PÅÃ­klady rozmÄrÅ¯ zahrnujÃ­ velikost a dobu trvÃ¡nÃ­. DoporuÄuje se vybÃ­rat hodnotu z ÅÃ­zenÃ©ho slovnÃ­ku (napÅ. seznam typÅ¯ internetovÃœch mÃ©diÃ­ [MIME] definujÃ­cÃ­ formÃ¡ty poÄÃ­taÄovÃœch mÃ©diÃ­).</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Format</Attribute>
+            <Attribute name="definition">Het data formaat van het Internetbestand. Dit gegeven kan gebruikt worden om systeemvereisten (hard- en software) te identificeren die nodig zijn voor raadpleging of bediening van de Internetbron. &quot;Format&quot; is nog in ontwikkeling bij de DC workshop. Uit compatibiliteitsoverwegingen wordt aanbevolen formaatgegevens te selecteren uit een gecontroleerde lijst. Formaten kunnen van de Internet Media Types (MIME types) lijst gekozen worden: http://www.isi.edu/in-notes/iana/assignments/media-types/media-types</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Formato</Attribute>
+            <Attribute name="definition">Le manifestation physic o digital del ressource.</Attribute>
+            <Attribute name="comment">Typicamente le formato pote includer le typo de medio o dimensiones del ressource. Le formato pote esser utilizate pro determinar le software o le equipamento necessari pro exhibir o operar le ressource. Exemplos de dimensiones include grandessa e duration. Le practica recommendate es selectionar un valor de un vocabulario controlate (per exemplo, le lista de typos de medios de Internet [MIME] que defini formatos de medios).</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€°à€à€šà€Ÿ</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€°à€à€šà€Ÿ, à€šà€®à¥à€šà€Ÿà€¬à¥à€Š à€°à€à€šà€Ÿ</Attribute>
+            <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€žà¥à€µà€°à¥à€ª, à€°à€à€šà€Ÿà€à€Šà€Ÿ. à€€à¥à€¯à€Ÿà€à¥ à€°à¥à€ª à€à€žà¥ à€ªà¥à€žà¥à€€à€à€°à¥à€ª, à€žà€à€à€£à€à¥à€¯ à€°à¥à€ª, à€µà€¿à€Šà¥à€¯à¥à€€ à€ªà€°à€®à€Ÿà€£à¥à€à€à¥à€¯à€Ÿ à€žà€¹à€Ÿà€¯à¥à€¯à€Ÿà€šà¥ à€žà€à€à€£à€à¥à€à¥à€€ à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="extent">
+            <Attribute language="en" name="identifier">Extent</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The size or duration of the resource.</Attribute>
+                <Attribute name="comment">The extent qualifier allows the description of the physical dimensions, file size or duration of the resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="medium">
+            <Attribute language="en" name="identifier">Medium</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The material or physical carrier of the resource.</Attribute>
+            </Language>
+        </Element>
+    </Element>
+    <Element name="Availability">
+        <Attribute language="en" name="identifier">Availability</Attribute>
+        <Attribute language="en" name="obligation">Conditional - mandatory when adding an agency, service, or off-line document; optional when adding an on-line document.</Attribute>
+        <Attribute language="en" name="definition">How the resource can be obtained or contact information for obtaining the resource.</Attribute>
+        <Attribute language="en" name="comment">The Availability element is primarily used for non-electronic resources to provide information on how to obtain physical access to the resource. The Availability element should be repeated to show multiple access points - for example, a service where someone could pay a bill at two separate organisations. Generally, full details of how any service can be obtained, or contact information, should be provided. If a structured value is to be given (including for example name and address information) it is recommended that the NZGLS Agent Encoding scheme be used. Alternatively, a link to a directory, authority file or similar set of identity information may be provided.</Attribute>
+    </Element>
+    <Element name="Identifier" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Resource Identifier</Attribute>
+            <Attribute name="definition">An unambiguous reference to the resource within a given context.</Attribute>
+            <Attribute name="comment">Recommended best practice is to identify the resource by means of a string or number conforming to a formal identification system. Example formal identification systems include the Uniform Resource Identifier (URI) (including the Uniform Resource Locator (URL)), the Digital Object Identifier (DOI) and the International Standard Book Number (ISBN).</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Taututanga</Attribute>
+            <Attribute name="definition">He tohutoro e hangai ana ki te rauemi i roto i tetahi horopaki.</Attribute>
+            <Attribute name="comment">Ko te tino huarahi kua tohua, ko te tautu i te rauemi ma tetahi aho (string), tau ranei, e hangai ana ki tetahi punaha taututanga okawa. Ko etahi punaha taututanga okawa ko te Taututanga Rauemi Orite (Uniform Resource Identifier - URI), te Taututanga Rauemi Tohu-wahi (Uniform Resource Locator - URL), Te Mea A-mati (Digital Object Identifier - DOI) me te Tau Pukapuka Aro Whanui o te Ao (International Standard Book Number - ISBN).</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Identifiant</Attribute>
+            <Attribute name="definition">Une rÃ©fÃ©rence non ambiguÃ« Ã  la ressource dans un contexte donnÃ©</Attribute>
+            <Attribute name="comment">Il est recommandÃ© d&apos;identifier la ressource par une chaÃ®ne de caractÃšre ou un nombre conforme Ã  un sytÃšme formel d&apos;identification. Exemples de systemes formels d&apos;identification incluent le &quot;Uniform Resource Identifier&quot; (URI) (qui inclut le &quot;Uniform Resource Locator&quot; (URL)), le &quot;Digital Object Identifier&quot;(DOI) et le &quot;International Standard Book Number&quot;(ISBN).</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ ÑÐµÑÑÑÑÐ°</Attribute>
+            <Attribute name="definition">ÐÐŽÐœÐŸÐ·ÐœÐ°ÑÐœÐ°Ñ ÑÑÑÐ»ÐºÐ° ÐœÐ° ÑÐµÑÑÑÑ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÐŽÐ°ÐœÐœÐŸÐ³ÐŸ ÐºÐŸÐœÑÐµÐºÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÑÑÑÑ Ð¿ÐŸÑÑÐµÐŽÑÑÐ²ÐŸÐŒ ÑÑÑÐŸÐºÐž ÐžÐ»Ðž ÑÐžÑÐ»Ð°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÐžÑÑÐµÐŒÐµ. ÐÑÐžÐŒÐµÑÑ ÑÐŸÑÐŒÐ°Ð»ÑÐœÑÑ
+ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÑÑ
+ ÑÐžÑÑÐµÐŒ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð£ÐœÐžÑÐžÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ Ð ÐµÑÑÑÑÐ° (URI), (Ð²ÐºÐ»ÑÑÐ°Ñ Ð£ÐœÐžÑÐžÑÐžÑÐŸÐ²Ð°ÐœÐœÑÑÐ¹ ÐÐŸÐºÐ°ÑÐŸÑ Ð ÐµÑÑÑÑÐ° URL), ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ ÐŠÐžÑÑÐŸÐ²ÐŸÐ³ÐŸ ÐÐ±ÑÐµÐºÑÐ° (DOI) Ðž ÐÐµÐ¶ÐŽÑÐœÐ°ÑÐŸÐŽÐœÑÐ¹ Ð¡ÑÐ°ÐœÐŽÐ°ÑÑÐœÑÐ¹ ÐÐœÐžÐ¶ÐœÑÐ¹ ÐÐŸÐŒÐµÑ (ISBN).</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Identificador del Recurso</Attribute>
+            <Attribute name="definition">Secuencia de caracteres usados para identificar unÃ­vocamente un recurso. Ejemplos para recursos en lÃ­nea pueden ser URLs y URNs (cuando estÃ©n implementados). Para otros recursos pueden ser usados otros formatos de identificadores, como por ejemplo ISBN (&quot;International Standard Book Number&quot; - NÃºmero Internacional Normalizado para Libros)</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ù
+Ø¹Ø±Ù Ø§ÙÙ
+ØµØ¯Ø±</Attribute>
+            <Attribute name="definition">ÙÙ Ù
+Ø¬Ù
+ÙØ¹Ø© Ø­Ø±ÙÙØ© Ø£Ù Ø±ÙÙ
+ ÙØ³ØªØ®Ø¯Ù
+ ÙØªØ¹Ø±ÙÙ Ø§ÙÙ
+ØµØ¯Ø± Ø§Ø­Ø¯ÙØ§ : Ø§ÙØ§Ù
+Ø«ÙØ© ÙØ°Ø§ÙÙ ÙÙ Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙØŽØšÙÙØ©ØªØ¶Ù
+ ) URNs, URLs Ø¹ÙØ¯ ØšÙØ§ØŠÙØ§ (    ÙØ°ÙÙ ÙÙ
+ÙÙ Ø§Ø¹ØªØšØ§Ø± Ø§ÙÙ
+Ø¹Ø±ÙØ§Øª Ø§ÙØ¹Ø§ÙÙ
+ÙØ© Ø§ÙØ§Ø­Ø§Ø¯ÙØ© Ù
+Ø«Ù Ø§ÙØ±ÙÙ
+ Ø§ÙØ¯ÙÙÙ ÙØªØµÙÙÙ Ø§ÙÙØ§ØªØš (ISBN) Ù
+Ø±ØŽØ­Ø© ÙÙØ°Ø§ Ø§ÙØ¹Ø§Ù
+Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">èµæºæ è¯ç¬Š</Attribute>
+            <Attribute name="definition">åšç¹å®çèåŽå
+ç»äºèµæºçäžäžªæç¡®çæ è¯ã</Attribute>
+            <Attribute name="comment">å»ºè®®å¯¹èµæºçæ è¯éçšç¬Šåæäžæ­£åŒæ è¯äœç³»çå­ç¬Šäž²åæ°å­ç»åãäŸåŠæ­£åŒçæ è¯äœç³»å
+æ¬ç»äžèµ    æºæ è¯ç¬Š(URI) (å
+æ¬åäžèµæºå®äœç¬ŠURL)ãæ°å­å¯¹è±¡æ è¯ç¬Š(DOI)ååœé
+æ åä¹Šå·(ISBN)ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">IdentifikÃ¡tor zdroje</Attribute>
+            <Attribute name="definition">JednoznaÄnÃœ odkaz na zdroj v rÃ¡mci danÃ©ho kontextu.</Attribute>
+            <Attribute name="comment">DoporuÄuje se identifikovat zdroj znakovÃœm ÅetÄzcem nebo ÄÃ­slem odpovÃ­dajÃ­cÃ­m nÄkterÃ©mu z formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯. PÅÃ­klady formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯ zahrnujÃ­ Uniform Resource Identifier (URI) (vÄetnÄ Uniform Resource Locator (URL)), Digital Object Identifier (DOI) a MezinÃ¡rodnÃ­ standardnÃ­ ÄÃ­slo knihy (ISBN).</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Bestandsidentificatie</Attribute>
+            <Attribute name="definition">Een unieke string of nummer ter identificatie van de Internetbron. Voorbeelden zijn URL&apos;s of URN&apos;s Andere voorbeelden zijn International Standard Book Number (ISBN) of International Standard Serial Number (ISSN)</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Identificator del ressource</Attribute>
+            <Attribute name="definition">Un referentia inambigue al ressource intra un date contexto.</Attribute>
+            <Attribute name="comment">Se recommenda identificar le ressource per medio de un catena de characteres o numero conforme a un systema formal de identification. Exemplos de systemas formal de identification include le Uniform Resource Identifier (URI) (includente le Uniform Resource Locator (URL)), le Digital Object Identifier (DOI) e le International Standard Book Number (ISBN).</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€à€³à€</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à€Ÿ à€à€ à€
+à€°à¥à€¥à¥ à€žà€à€Šà€°à¥à€­</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ. à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿà€³à¥à€¯à€Ÿà€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿ, à€µà€¿à€¶à€¿à€·à¥à€  à€žà¥à€¥à€³,  à€ªà¥à€žà¥à€€à€à€Ÿà€à€Ÿ à€à€à€€à€°à€°à€Ÿà€·à¥à€à¥à€°à¥à€¯  à€®à€Ÿà€šà€ à€à¥à€°à€®à€Ÿà€à€,  à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€à€³à€ à€ªà€à€µà€¿à€£à€Ÿà€°à€Ÿ à€à€à€à€°à€šà¥à€ à€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Source" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Source</Attribute>
+            <Attribute name="definition">A Reference to a resource from which the present resource is derived.</Attribute>
+            <Attribute name="comment">The present resource may be derived from the Source resource in whole or in part.  Recommended best practice is to reference the resource by means of a string or number conforming to a formal identification system.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Matapuna</Attribute>
+            <Attribute name="definition">He tohutoro ki tetahi rauemi koira te matapuna o te rauemi e tirohia ana.</Attribute>
+            <Attribute name="comment">Tera pea i puta te katoa, tetahi wahanga ranei o te rauemi, e tirohia ana, mai i te Matapuna rauemi. Ko te tino huarahi kua tohua ko te tohutoro ki te rauemi ma te aho, ma te tau ranei e hangai ana ki tetahi punaha taututanga okawa.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Source</Attribute>
+            <Attribute name="definition">Une rÃ©fÃ©rence Ã  une ressource Ã  partir de laquelle la ressource actuelle a Ã©tÃ© dÃ©rivÃ©e.</Attribute>
+            <Attribute name="comment">La ressource actuelle peut avoir Ã©tÃ© dÃ©rivÃ©e d&apos;une autre ressource source, en totalitÃ© ou en partie. Il est recommandÃ© de refÃ©rencer cette source par une chaÃ®ne de caractÃšre ou un nombre conforme Ã  un systÃšme formel d&apos;identification.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÑÑÐŸÑÐœÐžÐº</Attribute>
+            <Attribute name="definition">Ð¡ÑÑÐ»ÐºÐ° ÐœÐ° ÑÐµÑÑÑÑ, ÐžÐ· ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ ÐžÐ·Ð²Ð»ÐµÑÐµÐœ ÐœÐ°ÑÑÐŸÑÑÐžÐ¹.</Attribute>
+            <Attribute name="comment">ÐÐ°ÑÑÐŸÑÑÐžÐ¹ ÑÐµÑÑÑÑ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐžÐ·Ð²Ð»ÐµÑÐµÐœ ÐžÐ· ÐÑÑÐŸÑÐœÐžÐºÐ° ÑÐµÐ»ÐžÐºÐŸÐŒ ÐžÐ»Ðž ÑÐ°ÑÑÐžÑÐœÐŸ. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÑÑÑÑ Ð¿ÐŸÑÑÐµÐŽÑÑÐ²ÐŸÐŒ ÑÑÑÐŸÐºÐž ÐžÐ»Ðž ÑÐžÑÐ»Ð°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÐžÑÑÐµÐŒÐµ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Fuente</Attribute>
+            <Attribute name="definition">Secuencia de caracteres utilizado para identificar unÃ­vocamente un trabajo a partir del cual proviene el recurso actual. Por ejemplo, es posible usar Source con la fecha de 1603 como descripciÃ³n de una pelÃ­cula basada en una obra de Shakespeare, pero es preferible, en ese caso, usar Relation &quot;IsBasedOn&quot; con una referencia a un recurso distinto cuya descripciÃ³n contenga el elemento Date con valor 1603.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙ
+ØµØ¯Ø±</Attribute>
+            <Attribute name="definition">Ø§ÙÙ
+Ø¹ÙÙÙ
+Ø§Øª Ø§ÙØ®Ø§ØµØ© ØšÙ
+ØµØ¯Ø± Ø«Ø§ÙÙ Ù Ø§ÙØ°Ù Ø§Ø³ØªÙ
+Ø¯ Ù
+ÙÙ Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ. Ù
+Ø¹ Ø£ÙÙ Ù
+Ù Ø§ÙÙ
+ÙØµÙ ØšÙ Ø£Ù ØªÙØ¯Ù
+ Ø§ÙØ¹ÙØ§Ù
+Ù    Ù
+Ø¹ÙÙÙ
+Ø§Øª Ø¹Ù Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ ÙÙØ· , ÙÙÙ
+ÙÙ Ø£Ù ÙØ­ÙÙ ÙØ°Ø§ Ø§ÙØ¹Ø§Ù
+Ù Ø§ÙØªØ§Ø±ÙØ®, Ø§ÙÙ
+ÙØŽØŠ , Ø§ÙØµÙØºØ© , Ø§ÙÙ
+Ø¹Ø±Ù , Ø§Ù Ø§ÙØ© Ù
+ÙØ© - Ù
+Ø¹ÙÙÙ
+Ø§Øª Ø§Ø®Ø±Ù ÙÙÙ
+ØµØ¯Ø± Ø§ÙØ«Ø§ÙÙ Ø¹ÙØ¯Ù
+Ø§ ØªØ¹ØªØšØ± Ù
+ÙÙ
+Ø© ÙØ§ÙØªØŽØ§Ù Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ , Ù ÙØ°Ø§ÙÙ ÙÙØµÙ Ø¹ÙØ¯ Ø§ÙØªØ·ØšÙÙÙÙ Ø§Ø­Ø³Ù     Ø§ÙÙ
+ØªØ¹Ø§Ø±Ù Ø¹ÙÙÙ ØšØ§Ø³ØªØ®Ø¯Ø§Ù
+ Ø¹Ø§Ù
+Ù Ø§ÙØ¹ÙØ§ÙØ©</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">æ¥æº</Attribute>
+            <Attribute name="definition">ç°æèµæºæ¥æºçåç
+§ã</Attribute>
+            <Attribute name="comment">åœåèµæºå¯èœéšåæå
+šéšæºèªè¯¥å
+çŽ ææ è¯çèµæºïŒå»ºè®®å¯¹è¿äžèµæºçæ è¯éçšäžäžªç¬Šåæ­£åŒæ è¯ç³»    ç»çå­äž²åæ°å­ç»å ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Zdroj</Attribute>
+            <Attribute name="definition">Odkaz na zdroj, z nÄhoÅŸ je popisovanÃœ zdroj odvozen.</Attribute>
+            <Attribute name="comment">PopisovanÃœ zdroj mÅ¯ÅŸe bÃœt zcela nebo zÄÃ¡sti odvozen ze zdroje uvedenÃ©ho v prvku Zdroj. DoporuÄuje se odkazovat zdroj znakovÃœm ÅetÄzcem nebo ÄÃ­slem odpovÃ­dajÃ­cÃ­m nÄkterÃ©mu z formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Bron</Attribute>
+            <Attribute name="definition">Informatie over een tweede bron waar de huidige Internetbron is van afgeleid. Bij &quot;Source&quot; mag een datum, auteur of maker, formaat, identificatie of andere metadata voor de tweede bron worden ingevuld. Voorbeeld: het is mogelijk om een &quot;Source&quot; datum 1603 in een omschrijving van een 1996 film bewerking van een Shakespeare stuk te gebruiken. &quot;Source&quot; is niet bruikbaar wanneer de huidige bron de orginele is.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Fonte</Attribute>
+            <Attribute name="definition">Un referentia a un ressource del qual se deriva le ressource presente.</Attribute>
+            <Attribute name="comment">Le ressource presente pote derivar se del ressource-fonte in toto o in parte. Le practica recommendate es facer referentia al ressource per medio de un catena de characteres o un numero conforme a un systema formal de identification.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€à€à€®</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿ à€à€à€® à€žà€Ÿà€à€à€£à€Ÿà€°à€Ÿ à€à€à€
+à€°à¥à€¥à¥ à€žà€à€Šà€°à¥à€­</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ. à€ªà¥à€žà¥à€€à€, à€®à€Ÿà€žà€¿à€,  à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿà€³à¥à€¯à€Ÿà€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿà€¯à€Ÿà€à€à€Ÿ à€žà€à€Šà€°à¥à€­</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Language" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Language</Attribute>
+            <Attribute name="definition">A language of the intellectual content of the resource.</Attribute>
+            <Attribute language="en" name="comment">Recommended best practice for the values of the Language element is defined by RFC 1766 which includes a two-letter Language Code (taken from the ISO 639 standard, followed optionally, by a two-letter Country Code (taken from the ISO 3166 standard). For example, &apos;en&apos; for English, &apos;fr&apos; for French, or &apos;en-uk&apos; for English used in the United Kingdom.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Reo</Attribute>
+            <Attribute name="definition">Te reo o te whakakaupapatanga o nga matauranga o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tino huarahi kua tohua mo nga uara o te huanga Reo kua whakaritea ki te RFC 1766 [RFC1766] kei roto te Tohu Reo kupu-rua (two-letter Language Code) (no te aro whanui ISO 639 [ISO639], ka taea e tetahi tohu kupu-rua te whai atu (no te aro whanui ISO 3166) [ISO366]). Hei tauira, te &apos;en&apos; mo te English, te &apos;fr&apos; mo te French, &apos;te en-uk&apos; mo te English e whakamahia ana i Ingarangi (UK).</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Langue</Attribute>
+            <Attribute name="definition">La langue du contenu intellectuel de la ressource.</Attribute>
+            <Attribute name="comment">Il est recommandÃ© d&apos;utiliser comme valeur de l&apos;Ã©lÃ©ment Langue celles definies par la RFC 1766 [RFC1766] qui comprend un code de langage Ã  deux caractÃšres(venant du standard ISO 639 [ISO639]), Ã©ventuellement suivi d&apos;un code Ã  deux lettres pour le pays (venant du standard ISO 3166 [ISO3166] ou en franÃ§ais [ISO3166]). Par exemple, &apos;en&apos; pour l&apos;anglais, &apos;fr&apos; pour le franÃ§ais, ou &apos;en-uk&apos; pour l&apos;anglais utilisÃ© au Royaume-Uni.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">Ð¯Ð·ÑÐº</Attribute>
+            <Attribute name="definition">Ð¯Ð·ÑÐº ÐžÐœÑÐµÐ»Ð»ÐµÐºÑÑÐ°Ð»ÑÐœÐŸÐ³ÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÐ»ÐµÐŒÐµÐœÑÐ° Ð¯Ð·ÑÐº, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÐŒÐŸÐµ RFC 1766 (Ð¢ÑÐ³Ðž ÐŽÐ»Ñ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐž ÑÐ·ÑÐºÐ°), Ð²ÐºÐ»ÑÑÐ°ÑÑÐžÐŒ ÐŽÐ²ÑÑ
+Ð±ÑÐºÐ²ÐµÐœÐœÑÐ¹ ÐºÐŸÐŽ ÑÐ·ÑÐºÐ° (Ð²Ð·ÑÑÑÐ¹ ÐžÐ· ÑÑÐ°ÐœÐŽÐ°ÑÑÐ° ISO 639 (ÐÐŸÐŽÑ ÐŽÐ»Ñ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ ÑÐ·ÑÐºÐŸÐ²)), Ð·Ð° ÐºÐŸÑÐŸÑÑÐŒ ÑÐ»ÐµÐŽÑÐµÑ (Ð¿ÑÐž ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÑÑÐž) ÐŽÐ²ÑÑ
+Ð±ÑÐºÐ²ÐµÐœÐœÑÐ¹ ÐºÐŸÐŽ ÑÑÑÐ°ÐœÑ (Ð²Ð·ÑÑÑÐŒÐž ÐžÐ· ÑÑÐ°ÐœÐŽÐ°ÑÑÐ° ISO 3166 (ÐÐŸÐŽÑ ÐŽÐ»Ñ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ ÑÑÑÐ°Ðœ)). ÐÐ°Ð¿ÑÐžÐŒÐµÑ, &quot;en&quot; - ÐŽÐ»Ñ Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐŸÐ³ÐŸ, &quot;fr&quot; - ÐŽÐ»Ñ ÑÑÐ°ÐœÑÑÐ·ÑÐºÐŸÐ³ÐŸ, &quot;en-uk&quot; - ÐŽÐ»Ñ Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐŸÐ³ÐŸ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐŸÐ³ÐŸ Ð² ÐÐµÐ»ÐžÐºÐŸÐ±ÑÐžÑÐ°ÐœÐžÐž.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Lengua</Attribute>
+            <Attribute name="definition">Lengua/s del contenido intelectual del recurso. Practicamente el contenido de este campo deberÃ­a coincidir con los de la RFC 1766 (Tags para la identificaciÃ³n de lenguas, http://ds.internic.net/rfc/rfc1766.txt); por ejemplo: en, es, de, fi, ja y zh.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙØºØ©</Attribute>
+            <Attribute name="definition">ÙØ°Ù ÙÙ ÙØºØ© Ø§ÙÙ
+Ø­ØªÙÙ Ø§ÙÙÙØ±Ù ÙÙÙ
+ØµØ¯Ø± . ÙÙÙ
+Ø§ ÙØ§Ù  Ø¹Ù
+ÙÙØ§ , Ù
+Ø­ØªÙÙ ÙØžØ§ Ø§ÙØ­ÙÙ ÙØ¬Øš Ø£Ù ÙØªØ·Ø§ØšÙ Ù
+Ø¹ RFC 1766    ] Ø§ÙØ§Ù
+Ø«ÙØ© ØªØ¶Ù
+ th, ja, fr, es, fi, de, en Ù zh ÙØ±Ù
+ÙØ² ÙÙØªØ¹Ø±ÙÙ ØšØ§ÙÙØºØ© [</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">è¯­ç§</Attribute>
+            <Attribute name="definition">æè¿°èµæºç¥è¯å
+å®¹çè¯­ç§ã</Attribute>
+            <Attribute name="comment">å»ºè®®æ¬å
+çŽ çåŒéçšRFC 3066[RFC3066]ïŒè¯¥æ åäžISO 639 [ISO639]äžèµ·å®ä¹äºç±äž€äžªåäžäžªè±    æå­æ¯ç»æçäž»è¯­èšæ ç­Ÿåå­æ ç­ŸäŸåŠå
+æ¬âenâæâengâæ¥è¡šç€ºEnglish, &quot;akk&quot; æ¥è¡šç€º    &quot;en-GB&quot;è¡šç€ºè±åœè±è¯­ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Jazyk</Attribute>
+            <Attribute name="definition">Jazyk intelektuÃ¡lnÃ­ho obsahu zdroje.</Attribute>
+            <Attribute name="comment">DoporuÄenÃœ postup pro hodnoty prvku Jazyk je definovÃ¡n v RFC 1766 [RFC1766]: dvouznakovÃœ kÃ³d jazyka (pÅevzatÃœ z normy ISO 639 [ISO639]) volitelnÄ nÃ¡sledovanÃœ dvouznakovÃœm kÃ³dem zemÄ (pÅevzatÃœm z normy ISO 3166 [ISO3166]). NapÅÃ­klad &apos;en&apos; pro angliÄtinu, &apos;fr&apos; pro francouzÅ¡tinu, &apos;cs&apos; pro ÄeÅ¡tinu, nebo &apos;en-uk&apos; pro angliÄtinu uÅŸÃ­vanou ve SpojenÃ©m krÃ¡lovstvÃ­.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Taal</Attribute>
+            <Attribute name="definition">De taal waarin het document is beschreven. Voorgeschreven wordt de ISO639-1 norm, een twee karakter taalcode van de ISO 639(639-1 en 639-2) norm. Taalcodes kunnen van een lijst worden gekozen: http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt, Eventueel kan ISO3166 (landencodes) gebruikt worden om aan te geven in welk gebied de taal wordt gesproken. Deze kunnen ook van een lijst worden gekozen:  http://www.ics.uci.edu/pub/ietf/http/related/iso3166.txt.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Lingua</Attribute>
+            <Attribute name="definition">Le lingua del contento intellectual del ressource.</Attribute>
+            <Attribute name="comment">Le practica recommendate pro le valores del elemento lingua es definite per RFC 1766 [RFC1766], que include un codice de lingua de duo litteras (prendite del standard ISO 639 [ISO639]), sequite optionalmente per un codice de pais de duo litteras (prendite del standard ISO 3166 [ISO3166]). Per exemplo, &apos;ia&apos; pro interlingua, &apos;fr&apos; pro francese, o &apos;en-uk&apos; pro le anglese del Regno Unite.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€­à€Ÿà€·à€Ÿ</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€­à€Ÿà€·à€Ÿ</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ. à€®à€°à€Ÿà€ à¥ - à€­à€Ÿà€°à€€à¥à€¯ à€­à€Ÿà€·à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Relation" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Relation</Attribute>
+            <Attribute name="definition">A reference to a related resource.</Attribute>
+            <Attribute name="comment">Recommended best practice is to reference the resource by means of a string or number conforming to a formal identification system.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Whai Panga</Attribute>
+            <Attribute name="definition">He tohutoro ki tetahi rauemi whai panga.</Attribute>
+            <Attribute name="comment">Ko te tino huarahi kua tohua, ko te tohutoro ki te rauemi ma te aho, te tau ranei, e hangai ana ki te punaha taututanga okawa.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Relation</Attribute>
+            <Attribute name="definition">Une rÃ©fÃ©rence Ã  une autre ressource qui a un rapport avec cette ressource.</Attribute>
+            <Attribute name="comment">Il est recommandÃ© de rÃ©fÃ©rencer cette ressource par une chaÃ®ne de caractÃšres ou un numÃ©ro conforme Ã  un systÃšme formel d&apos;identification.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÑÐœÐŸÑÐµÐœÐžÐµ</Attribute>
+            <Attribute name="definition">ï¿œÐµÐœÐœÑÐ¹ ÑÐµÑÑÑÑ.</Attribute>
+            <Attribute name="comment">ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÑÑÑÑ Ð¿ÐŸÑÑÐµÐŽÑÑÐ²ÐŸÐŒ ÑÑÑÐŸÐºÐž ÐžÐ»Ðž ÑÐžÑÐ»Ð°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÐžÑÑÐµÐŒÐµ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">RelaciÃ³n</Attribute>
+            <Attribute name="definition">Un identificador de un segundo recurso y su relaciÃ³n con el recurso actual. Este elemento permite enlazar los recursos relacionados y las descripciones de los recursos. Por ejemplo: IsVersionOf - Incluye la ediciÃ³n de un trabajo, IsBasedOn - La traducciÃ³n de un trabajo, IsPartOf - Un capÃ­tulo de un libro, IsFormatOf - Un mecanismo de transformaciÃ³n de un conjunto de datos en una imagen. Para asegurar la interoperabilidad, las relaciones deberÃ­an ser seleccionadas de una lista de elementos que actualmente se encuentra bajo desarrollo en un grupo de trabajo.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙØ¹ÙØ§ÙØ©</Attribute>
+            <Attribute name="definition">ÙØ°Ø§ Ù
+Ø¹Ø±Ù ÙÙÙ
+ØµØ¯Ø± Ø§ÙØ«Ø§ÙÙ Ù Ø¹ÙØ§ÙØªÙ ØšØ§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ . ÙØ³Ù
+Ø­ ÙØ°Ø§ Ø§ÙØ¹Ø§Ù
+Ù ØšØªÙØ¶ÙØ­ Ø§ÙØ±ÙØ§ØšØ· ØšÙÙ Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙÙ
+ØªØ¹ÙÙØ©     ØšØšØ¹Ø¶ÙØ§ Ù ØªÙØµÙÙ Ø§ÙÙ
+ØµØ¯Ø± . Ø§ÙØ§Ù
+Ø«ÙØ© ØªØ¶Ù
+ Ø·ØšØ¹Ø© Ø§ÙØ¹Ù
+Ù ) ÙØ³Ø®Ø© Ù
+Ù ( ØªØ±Ø¬Ù
+Ø© Ø¹Ù
+Ù ) Ø§Ø¹ØªÙ
+Ø§Ø¯Ø§ Ø¹ÙÙ ( ÙØµÙ Ù
+Ù ÙØªØ§Øš ) Ø¬Ø²Ø¡ Ù
+Ù (    Ù ØªØ­ÙÙÙÙ Ù
+ÙÙØ§ÙÙÙÙØ© ÙÙ
+Ø¬Ù
+ÙØ¹Ø© Ù
+Ø¹ÙÙÙ
+Ø§ØªÙØ© Ø§ÙÙ ØµÙØ±Ø© ) ØµÙØºØ© Ù
+Ù ( Ù
+Ù Ø£Ø¬Ù Ø§ÙØªØ¹Ø§Ù
+Ù Ø§ÙÙ
+ØŽØªØ±Ù , ÙØ¬Øš Ø§Ø®ØªÙØ§Ø± Ø§ÙØ¹ÙØ§ÙØ§Øª Ù
+Ù    Ø§ÙÙØ§ØŠÙ
+Ø© Ø§ÙÙ
+Ø±ÙÙ
+Ø© Ù Ø§ÙØªÙ ÙØªÙ
+ Ø§Ø¹Ø¯Ø§Ø¯ÙØ§ Ø­Ø§ÙÙØ§ Ø¶Ù
+Ù Ø­ÙÙØ§Øª ÙØ±ØŽØ© Ø¹Ù
+Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">å
+³è</Attribute>
+            <Attribute name="definition">æ¶åççžå
+³èµæºã</Attribute>
+            <Attribute name="comment">èåœçžå
+³èµæºæ¶ïŒå»ºè®®äœ¿çšç¬Šåæ­£åŒæ è¯ç³»ç»çå­ç¬Šäž²æè
+æ°å­ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Vztah</Attribute>
+            <Attribute name="definition">Odkaz na pÅÃ­buznÃœ zdroj.</Attribute>
+            <Attribute name="comment">DoporuÄuje se odkazovat zdroj znakovÃœm ÅetÄzcem nebo ÄÃ­slem odpovÃ­dajÃ­cÃ­m nÄkterÃ©mu z formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Relatie</Attribute>
+            <Attribute name="definition">Een identificatie van een tweede bron en de relatie met de huide Internetbron. Voorbeelden zijn een editie van een werk (IsVersionOf), een vertaling van een werk (IsBasedOn), een hoofdstuk van een boek (IsPartOf) en een mechanische transformatie van een dataset in een plaatje (IsFormatOf). De DC Working Groups zijn bezig met een lijst met de meest verwachte relaties. Aanbevolen wordt om de relaties van deze lijst te gebruiken: http://purl.oclc.org/metadata/dublin_core/wrelationdraft.html.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="definition">Relation</Attribute>
+            <Attribute name="definition">Un referentia a un ressource correlate.</Attribute>
+            <Attribute name="comment">Le practica recommendate es facer referentia al ressource per medio de un catena de characteres o numero conforme a un systema de identification formal.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€šà€Ÿà€€à¥ , à€žà€à€¬à€à€§</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€¶à¥ à€žà€à€¬à€à€§ à€Šà€Ÿà€à€µà€£à€Ÿà€°à€Ÿ à€žà€à€Šà€°à¥à€­</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ.  à€®à€Ÿà€¹à€¿à€€à¥ à€à€Ÿà€³à¥à€¯à€Ÿà€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿ(URL)</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="isVersionOf">
+            <Attribute language="en" name="identifier">Is Version Of</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource is a version, edition, or adaptation of the referenced resource. Changes in version imply substantive changes in content rather than differences in format.</Attribute>
+            </Language>
+        </Element>
+        <Element name="hasVersion">
+            <Attribute language="en" name="identifier">Has Version</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource has a version, edition, or adaptation, namely, the referenced resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="isReplacedBy">
+            <Attribute language="en" name="identifier">Is Replaced By</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource is supplanted, displaced, or superseded by the referenced resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="replaces">
+            <Attribute language="en" name="identifier">Replaces</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource supplants, displaces, or supersedes the referenced resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="isRequiredBy">
+            <Attribute language="en" name="identifier">Is Required By</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource is required by the referenced resource, either physically or logically.</Attribute>
+            </Language>
+        </Element>
+        <Element name="requires">
+            <Attribute language="en" name="identifier">Requires</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource requires the referenced resource to support its function, delivery, or coherence of content.</Attribute>
+            </Language>
+        </Element>
+        <Element name="isPartOf">
+            <Attribute language="en" name="identifier">Is Part Of</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource is a physical or logical part of the referenced resource.</Attribute>
+                <Attribute name="comment">Used to describe the relationship between a service and relevant documents (e.g. web pages and forms)</Attribute>
+            </Language>
+        </Element>
+        <Element name="hasPart">
+            <Attribute language="en" name="identifier">Has Part</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource includes the referenced resource either physically or logically.</Attribute>
+            </Language>
+        </Element>
+        <Element name="isReferencedBy">
+            <Attribute language="en" name="identifier">Is Referenced By</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource is referenced, cited, or otherwise pointed to by the referenced resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="references">
+            <Attribute language="en" name="identifier">References</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource references, cites, or otherwise points to the referenced resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="isFormatOf">
+            <Attribute language="en" name="identifier">Is Format Of</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource is the same intellectual content of the referenced resource, but presented in another format.</Attribute>
+            </Language>
+        </Element>
+        <Element name="hasFormat">
+            <Attribute language="en" name="identifier">Has Format</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource pre-existed the referenced resource, which is essentially the same intellectual content presented in another format.</Attribute>
+            </Language>
+        </Element>
+        <Element name="isBasisFor">
+            <Attribute language="en" name="identifier">Is Basis For</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource pre-existed the referenced resource, which is a performance, production, derivation, translation, or interpretation of the described resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="isBasedOn">
+            <Attribute language="en" name="identifier">Is Based On</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The described resource is a performance, production, derivation, translation, or interpretation of the referenced resource.</Attribute>
+            </Language>
+        </Element>
+    </Element>
+    <Element name="Coverage" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Coverage</Attribute>
+            <Attribute name="definition">The extent or scope of the content of the resource.</Attribute>
+            <Attribute name="comment">Coverage will typically include spatial location (a place name or geographic coordinates), temporal period (a period label, date, or date range) or jurisdiction (such as a named administrative entity). Recommended best practice is to select a value from a controlled vocabulary (for example, the Thesaurus of Geographic Names [TGN]) and that, where appropriate, named places or time periods be used in preference to numeric identifiers such as sets of coordinates or date ranges.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Kapitanga</Attribute>
+            <Attribute name="definition">Te roanga, te whanuitanga ranei o te whakakaupapatanga o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, ka uru atu te wahi mokowa (te ingoa o tetahi wahi, whakapiritanga matawhenua ranei), whakaritenga wa (he tapatanga wa (period label, ra, whakatakotoranga whanui o nga ra), te whakaritenga ture (penei i te putahi whakahaere). Ko te tino huarahi kua tohua, ko te tipako uara mai i tetahi whakaritenga kupu (hei tauira, i tetahi Puna Kupu Ingoa Matawhenua (Geographic Names [TGN] i nga wahi tika, ko nga wahi me nga whakaritenga wa ka whakamahia i mua i te whakamahitanga o nga taututanga tau penei i nga huinga whakapiritanga me nga whakatakotoranga whanui o nga ra.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Couverture</Attribute>
+            <Attribute name="definition">La portÃ©e ou la couverture spatio-temporelle de la ressource.</Attribute>
+            <Attribute name="comment">La couverture typiquement inclut une position gÃ©ographique (le nom d&apos;un lieu ou ses coordonnÃ©es), une pÃ©riode de temps (un nom de pÃ©riode, une date, ou un intervalle de temps) ou une juridiction (telle que le nom d&apos;une entitÃ© administrative). Il est recommandÃ© de choisir la  valeur de Couverture dans un vocabulaire contrÃŽlÃ© (par exemple, un thÃ©saurus de noms gÃ©ographiques, comme[TGN]) et, quand cela est appropriÃ©, des noms de lieux ou de pÃ©riodes plutÃŽt que des identifiants numÃ©riques tels que des coordonnÃ©es ou des intervalles de dates. </Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÑ
+Ð²Ð°Ñ</Attribute>
+            <Attribute name="definition">ÐÑÐŸÑÑÐ¶ÐµÐœÐœÐŸÑÑÑ Ðž Ð³ÑÐ°ÐœÐžÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÑ
+Ð²Ð°Ñ ÐŸÐ±ÑÐºÐœÐŸÐ²ÐµÐœÐœÐŸ Ð²ÐºÐ»ÑÑÐ°ÐµÑ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²ÐµÐœÐœÐŸÐµ ÐŒÐµÑÑÐŸÐœÐ°Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÐµ (ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐŒÐµÑÑÐœÐŸÑÑÐž ÐžÐ»Ðž Ð³ÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÐµ ÐºÐŸÐŸÑÐŽÐžÐœÐ°ÑÑ), Ð²ÑÐµÐŒÐµÐœÐœÐŸÐ¹ Ð¿ÑÐŸÐŒÐµÐ¶ÑÑÐŸÐº (ÑÐºÐ°Ð·Ð°ÐœÐžÐµ Ð¿ÐµÑÐžÐŸÐŽÐ°, ÐŽÐ°ÑÐ° ÐžÐ»Ðž ÑÑÐŽ ÐŽÐ°Ñ) ÐžÐ»Ðž ÑÑÐžÑÐŽÐžÐºÑÐžÑ (ÑÐºÐ°Ð·Ð°ÐœÐžÐµ ÐµÐŽÐžÐœÐžÑÑ Ð°ÐŽÐŒÐžÐœÐžÑÑÑÐ°ÑÐžÐ²ÐœÐŸÐ³ÐŸ ÐŽÐµÐ»ÐµÐœÐžÑ). ÐÐ° Ð¿ÑÐ°ÐºÑÐžÐºÐµ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, Ð¢ÐµÐ·Ð°ÑÑÑÑÐ° Ð³ÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÑ
+ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ TGN), Ðž, ÐµÑÐ»Ðž ÑÑÐŸ ÑÐŒÐµÑÑÐœÐŸ, Ð¿ÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÐµ ÐŸÑÐŽÐ°ÐµÑÑÑ ÑÐºÐ°Ð·Ð°ÐœÐžÑÐŒ ÐŒÐµÑÑÐœÐŸÑÑÐµÐ¹ ÐžÐ»Ðž Ð²ÑÐµÐŒÐµÐœÐœÑÑ
+ Ð¿ÑÐŸÐŒÐµÐ¶ÑÑÐºÐŸÐ² Ð²ÐŒÐµÑÑÐŸ ÑÐžÑÑÐŸÐ²ÑÑ
+ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ², ÐºÐ°Ðº, ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐžÑÑÐµÐŒ ÐºÐŸÐŸÑÐŽÐžÐœÐ°Ñ ÐžÐ»Ðž Ð²ÑÐµÐŒÐµÐœÐœÑÑ
+ ÑÑÐŽÐŸÐ².</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Cobertura</Attribute>
+            <Attribute name="definition">La caracterÃ­stica de cobertura espacial y/o temporal del contenido intelectual del recurso. La cobertura espacial se refiere a una regiÃ³n fÃ­sica (por ejemplo, sector celestial); uso de coordenadas (por ejemplo, longitud y latitud) o nombres de lugares extraidos de una lista controlada. La cobertura temporal se refiere al contenido del recurso en vez de a cuando fue creado o puesto accesible ya que este Ãºltimo pertenece al elemento Date. Se usa el mismo formato basado en http://www.w3.org/TR/NOTE-datetime.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙØªØºØ·ÙØ©</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙØ®ØµØ§ØŠØµ Ø§ÙÙ
+ÙØ§ÙÙØ© Ø§Ù Ø§ÙØ²Ù
+ÙÙØ© ÙÙÙ
+Ø­ØªÙÙ Ø§ÙÙÙØ±Ù ÙÙÙ
+ØµØ¯Ø± . Ø§ÙØªØºØ·ÙØ© Ø§ÙÙ
+ÙØ§ÙÙØ© ØªØŽÙØ± Ø§ÙÙ Ø¬ÙØ© Ø·ØšÙØ¹ÙØ© )Ù
+Ø«Ù , ÙØ·Ø§Ø¹ Ø³Ù
+Ø§ÙÙ (    Ø§Ø³ØªØ®Ø¯Ø§Ù
+ Ø§ÙØ§Ø­Ø¯Ø§Ø«ÙØ§Øª ) Ù
+Ø«Ù  Ø®Ø· Ø§ÙØ·ÙÙ Ù Ø®Ø· Ø§ÙØ¹Ø±Ø¶ ( ÙÙ Ø£Ø³Ù
+Ø§Ø¡ Ø§Ù
+ÙÙØ© Ù
+Ø³ØªØ­ÙÙ
+Ø© Ø§Ù Ù
+ØªØ¬ÙØ§Øª ØšØ§ÙÙØ§Ù
+Ù . Ø§ÙØªØºØ·ÙØ© Ø§ÙØ²Ù
+ÙÙØ©    Ø«Ø¹ÙØ¯ Ø§ÙÙ Ù
+Ø§ ÙØ±Ø¬Ø¹ Ø§ÙÙÙ Ø§ÙÙ
+ØµØ¯Ø± Ù ÙÙØ³ Ø§Ù Ù
+ØªÙ ØªÙ
+ ØªÙÙÙØ±Ù ) Ø§ÙØ§Ø®ÙØ± ÙØªØ¹ÙÙ ØšØ¹Ø§Ù
+Ù Ø§ÙØªØ§Ø±ÙØ® ( Ø§Ø³ØªØ®Ø¯Ø§Ù
+ ÙÙØ³ ØµÙØºØ© Ø§ÙØªØ§Ø±ÙØ®  Ø§Ù Ø§ÙÙÙØª    ) Ø¹Ø§Ø¯Ø© Ù
+Ø¯Ù ] ( ØµÙØ§ØºØ§Øª Ø§ÙÙÙÙ
+ Ù Ø§ÙÙÙØª ) Ø§Ø¹ØªÙ
+Ø§Ø¯Ø§ Ø¹ÙÙ (ISO 8601 Ø§ÙÙ
+ÙØ§Ø­ØžØ© Ø§ÙÙÙÙØ© [http://www.w3.org/TR/NOTE-datetime, W3C    ÙÙ
+Ø§ ÙÙ Ù
+ÙØµÙ ØšÙ ÙØ¹Ø§Ù
+Ù Ø§ÙØªØ§Ø±ÙØ® Ø§Ù ÙØªØ±Ø§Øª Ø²Ù
+ÙÙØ© Ù
+Ù ÙØ§ØŠÙ
+Ø© Ù
+Ø³ØªØ­ÙÙ
+Ø© Ø§Ù Ù
+ØªØ¬ÙØ§Øª ØšØ§ÙÙØ§Ù
+Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">èŠçèåŽ</Attribute>
+            <Attribute name="definition">èµæºå
+å®¹ææ¶åçå€å»¶äžèŠçèåŽ</Attribute>
+            <Attribute name="comment">èŠçèåŽäžè¬å
+æ¬ç©ºéŽäœçœ®ïŒäžäžªå°åæå°çåæ ïŒãæ¶éŽåºéŽïŒäžäžªæ¶éŽæ è¯ïŒæ¥ææäžäžªæ¥æè    åŽïŒãæè
+æéïŒæ¯åŠåœåçææå®äœïŒæšèèŠçèåŽæå¥œæ¯åèªäºäžäžªåæ§è¯è¡šïŒäŸåŠå°åè¯åº    [TGN]ïŒïŒå¹¶åºå°œå¯èœå°äœ¿çšç±æ°å­è¡šç€ºçåæ ææ¥æåºéŽæ¥æè¿°å°åäžæ¶éŽæ®µã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">PokrytÃ­</Attribute>
+            <Attribute name="definition">Rozsah nebo zÃ¡bÄr obsahu zdroje.</Attribute>
+            <Attribute name="comment">PokrytÃ­ bude typicky obsahovat prostorovÃ© umÃ­stÄnÃ­ (jmÃ©no mÃ­sta nebo zemÄpisnÃ© souÅadnice), ÄasovÃ© obdobÃ­ (oznaÄenÃ­ obdobÃ­, datum nebo ÄasovÃœ interval) nebo jurisdikci (napÅ. jmÃ©no administrativnÃ­ jednotky). DoporuÄuje se vybÃ­rat hodnotu z ÅÃ­zenÃ©ho slovnÃ­ku (napÅ. Thesaurus of Geographic Names [TGN]) a tam, kde je to vhodnÃ©, uvÃ¡dÄt mÃ­sta nebo ÄasovÃ© Ãºseky spÃ­Å¡e jmÃ©nem neÅŸ ÄÃ­selnÃœmi identifikÃ¡tory jako jsou soubory souÅadnic nebo ÄasovÃ© intervaly.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Dekking</Attribute>
+            <Attribute name="definition">De ruimtelijke of tijdelijke karakteristieken van de intellectuele inhoud van de Internetbron. Ruimtelijke dekking verwijst naar een geografisch gebied. Gebruik coordinaten (longitude (lengtegraad) en latitude (breedtegraad)) of plaatsnamen die van een gecontroleerde lijst komen of volledig uitgeschreven zijn. Dekking in de tijd geeft de tijdsperiode aan waarop de inhoud van de Internetbron betrekking heeft en niet wanneer de Internetbron is gemaakt of beschikbaar is gesteld (dit laatste hoort ingevult te worden bij &quot;Date&quot;). Gebruik dezelfde datum/tijd formaat als bij &quot;Date&quot;; W3C Technical Note http://www.w3.org/TR/NOTE-datetime of tijdsperioden die van een gecontroleerde lijst komen of volledig uitgeschreven zijn. Coverage is in ontwikkeling bij de Dublin Core Working group http://www.alexandria.ucsb.edu/docs/metadata/dc_coverage.html.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Copertura</Attribute>
+            <Attribute name="definition">Le extension physic o abstracte del contento del ressource.</Attribute>
+            <Attribute name="comment">Le copertura typicamente include un location spatial (un nomine de localitate o coordinatas geographic), un periodo de tempore (un etiquetta de periodo, data, o gamma de datas), o un jurisdiction (tal como un entitate administrative nominate). Le practica recommendate es selectionar un valor a partir de un vocabulario controlate (per exemplo, le Thesaurus of Geographical Names [TGN]) e que, quando appropriate, localitates o periodos de tempore nominate sia utilizate in preferentia a identificatores numeric tales como collectiones de coordinatas o gammas de datas.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€µà¥à€¯à€Ÿà€ªà¥à€€à¥</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€­à¥à€à¥à€²à€¿à€  à€®à€Ÿà€¹à€¿à€€à¥</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ. à€­à¥à€à¥à€²à€¿à€ à€µà¥à€¯à€Ÿà€ªà¥à€€à¥</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="jurisdiction">
+            <Attribute language="en" name="identifier">Jurisdiction</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">The name of the political/administrative entity covered by the content of the resource.</Attribute>
+                <Attribute name="comment">Jurisdiction is a description of the territory over which a particular government exercises its authority or a particular business transacts its operations, to which the resource content is applicable.</Attribute>
+            </Language>
+        </Element>
+        <Element name="spatial">
+            <Attribute language="en" name="identifier">Spatial</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">Spatial characteristics of the intellectual content of the resource.</Attribute>
+                <Attribute name="comment">Spatial (geographic) coverage or locations or areas covered in the content of a resource. Use of the New Zealand Geographic Place Names Database (LINZ) may be appropriate. In some cases the DCMI Box Encoding Scheme may be suitable. Refer: http//dublincore.org.documents/2000/07/28/dcmi-box/</Attribute>
+            </Language>
+        </Element>
+        <Element name="temporal">
+            <Attribute language="en" name="identifier">Temporal</Attribute>
+            <Attribute language="en" name="qualifier type">element refinement</Attribute>
+            <Language code="en">
+                <Attribute name="definition">Temporal characteristics of the intellectual content of the resource.</Attribute>
+                <Attribute name="comment">The refinement &amp;quot;temporal&amp;quot; refers to time periods that are covered by or discussed in the content of resource. Time periods will generally be best expressed as date ranges, although named periods may be appropriate. The recommended encoding schemes for dates and date ranges are noted in the section on Date.</Attribute>
+            </Language>
+        </Element>
+    </Element>
+    <Element name="Rights" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Rights Management</Attribute>
+            <Attribute name="definition">Information about rights held in and over the resource.</Attribute>
+            <Attribute name="comment">Typically, a Rights element will contain a rights management statement for the resource, or reference a service providing such information. Rights information often encompasses Intellectual Property Rights (IPR), Copyright, and various Property Rights. If the Rights element is absent, no assumptions can be made about the status of these and other rights with respect to the resource.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Motika</Attribute>
+            <Attribute name="definition">Ko nga mohiohio ki nga motika o tetahi rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, kei te huanga Motika e pupuri ana he korero mo te whakaritenga motika mo te rauemi, he ratonga tohutoro e whakarato ana ranei i enei tumomo mohiohio. He nui nga wa, puta ai i roto i te mohiohio Motika te Mana Whakairo Hinegaro (Intellectual Property Rights - (IPR)), te Manatarua me nga Tuahua Mana Taonga (Property Rights). Ki te kore te huanga Motika, kaore e taea te pohehe noa ki te mana o enei, nga motika ranei e pa ana ki te rauemi.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Droits</Attribute>
+            <Attribute name="definition">Information sur les droits sur et au sujet de la ressource.</Attribute>
+            <Attribute name="comment">Typiquement, un Ã©lÃ©ment Droits contiendra un Ã©tat du droit Ã  gÃ©rer une ressource, ou la refÃ©rence Ã  un service fournissant cette information. Ces droits souvent couvrent les droits de propriÃ©tÃ© intellectuelle (IPR), Copyright, et divers droits de propriÃ©tÃ©. Si l&apos;Ã©lÃ©ment Droits est absent, aucune hypothÃšse ne peut Ãªtre faite sur l&apos;Ã©tat de ces droits, ou de tout autre, par rapport Ã  la ressource.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÑÐ°Ð²ÐŸÐ²ÐŸÐµ ÑÐµÐ³ÑÐ»ÐžÑÐŸÐ²Ð°ÐœÐžÐµ</Attribute>
+            <Attribute name="definition">ÐÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ Ð¿ÑÐ°Ð²Ð°Ñ
+ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐ°ÑÑÑ Ð²ÐœÑÑÑÐž Ðž Ð²ÐœÐµ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÑÐ»ÐµÐŒÐµÐœÑ ÐÑÐ°Ð²Ð° ÑÐŸÐŽÐµÑÐ¶ÐžÑ Ð¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐžÐµ ÐŸ Ð¿ÑÐ°Ð²ÐŸÐ²ÑÑ
+ ÐœÐŸÑÐŒÐ°Ñ
+, ÑÐµÐ³ÑÐ»ÐžÑÑÑÑÐžÑ
+ ÑÑÐœÐºÑÐžÐŸÐœÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÑÐµÑÑÑÑÐ° ÐžÐ»Ðž ÑÑÑÐ»ÐºÑ ÐœÐ° ÑÐ»ÑÐ¶Ð±Ñ, Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÑÑÑÑ ÑÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ. ÐÑÐ°Ð²ÐŸÐ²Ð°Ñ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸÐ±ÑÑÐœÐŸ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÑÐ²ÐµÐŽÐµÐœÐžÑ ÐŸ ÐÑÐ°Ð²Ð°Ñ
+ ÐžÐœÑÐµÐ»Ð»ÐµÐºÑÑÐ°Ð»ÑÐœÐŸÐ¹ ÑÐŸÐ±ÑÑÐ²ÐµÐœÐœÐŸÑÑÐž, ÐÐ²ÑÐŸÑÑÐºÐŸÐŒ Ð¿ÑÐ°Ð²Ðµ Ðž ÐŽÑÑÐ³ÐžÑ
+ ÐÐŒÑÑÐµÑÑÐ²ÐµÐœÐœÑÑ
+ Ð¿ÑÐ°Ð²Ð°Ñ
+. ÐÑÑÑÑÑÑÐ²ÐžÐµ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐÑÐ°Ð²Ð° ÐœÐµ ÐŒÐŸÐ¶ÐµÑ ÑÐ²Ð»ÑÑÑÑÑ ÐŸÑÐœÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐŽÐ»Ñ ÐºÐ°ÐºÐžÑ
+-Ð»ÐžÐ±ÐŸ Ð¿ÑÐµÐŽÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐžÐ¹ ÐŸ Ð¿ÑÐ°Ð²ÐŸÐ²ÐŸÐŒ ÑÑÐ°ÑÑÑÐµ Ðž ÐŽÑÑÐ³ÐžÑ
+ Ð¿ÑÐ°Ð²Ð°Ñ
+, ÐºÐ°ÑÐ°ÑÑÐžÑ
+ÑÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Derechos</Attribute>
+            <Attribute name="definition">Una referencia (URL, por ejemplo) para una nota sobre derechos de autor, para un servicio de gestiÃ³n de derechos o para un servicio que darÃ¡ informaciÃ³n sobre tÃ©rminos y condiciones de acceso a un recurso. Una especificaciÃ³n formal del elemento Rights se encuentra catualmente en discusiÃ³n y por lo tanto su uso se considera experimental.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø­ÙÙÙ Ø§ÙØ§Ø¯Ø§Ø±Ø©</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙØ§Ø¯Ø© Ø­ÙÙÙ Ø§ÙØ§Ø¯Ø§Ø±Ø© , Ù
+Ø¹Ø±Ù Ù
+Ø±ØªØšØ· ØšØ§ÙØ§Ø¯Ø© Ø­ÙÙÙ Ø§ ÙØ§Ø¯Ø§Ø±Ø© , Ù
+Ø¹Ø±Ù Ù
+Ø±ØªØšØ· ØšØ®Ø¯Ù
+Ø© ØªÙØ¯Ù
+ Ù
+Ø¹ÙÙÙ
+Ø§Øª Ø¹Ù Ø­ÙÙÙ Ø§ÙØ§Ø¯Ø§Ø±Ø© Ø§ÙØ®Ø§ØµØ© ØšØ§ÙÙ
+ØµØ¯Ø±</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">æé</Attribute>
+            <Attribute name="definition">æå
+³èµæºæ¬èº«ææçæè¢«èµäºçæéä¿¡æ¯</Attribute>
+            <Attribute name="comment">äžè¬èèšïŒæéå
+çŽ åºå
+æ¬äžäžªå¯¹èµæºçæéå£°æïŒæè
+æ¯å¯¹æäŸè¿äžä¿¡æ¯çæå¡çåç
+§ãæéäžè¬    å
+æ¬ç¥è¯äº§æ(IPR)ïŒçææå
+¶ä»åç§åæ ·çäº§æãåŠææ²¡ææéå
+çŽ çæ æ³šïŒäžå¯ä»¥å¯¹äžèµæºçžå
+³    çäžè¿°æå
+¶ä»æå©çæ
+åµäœåºä»»äœåå®ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">PrÃ¡va</Attribute>
+            <Attribute name="definition">Informace o prÃ¡vech vztahujÃ­cÃ­ch se k popisovanÃ©mu zdroji.</Attribute>
+            <Attribute name="comment">Prvek PrÃ¡va bude typicky obsahovat ustanovenÃ­ o sprÃ¡vÄ autorskÃœch/vlastnickÃœch prÃ¡v ke zdroji nebo odkaz na sluÅŸbu poskytujÃ­cÃ­ takovÃ©to informace. Informace o prÃ¡vech Äasto zahrnujÃ­ prÃ¡va duÅ¡evnÃ­ho vlastnictvÃ­ (IPR), autorskÃ© prÃ¡vo a rÅ¯znÃ¡ vlastnickÃ¡ prÃ¡va. JestliÅŸe prvek PrÃ¡va chybÃ­, nelze odvozovat ÅŸÃ¡dnÃ© pÅedpoklady o stavu tÄchto a jinÃœch prÃ¡v vztahujÃ­cÃ­ch se k popisovanÃ©mu zdroji.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Copyright</Attribute>
+            <Attribute name="definition">Een copyright verklaring of een link naar een copyright verklaring of een link naar een service die informatie geeft over de copyright van de Internetbron.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Gestion de derectos</Attribute>
+            <Attribute name="definition">Information super derectos detenite super e a proposito del ressource.</Attribute>
+            <Attribute name="comment">Typicamente le elemento derectos continera un declaration de gestion de derectos pro le ressource, o un referentia a un servicio que provide tal information. Information de derectos frequentemente involve derectos de proprietate intellectual (IPR), copyright e varie derectos de proprietate. Si le elemento Derectos es absente, necun hypothese pote esser facite quanto al stato de iste e altere derectos concernente ressource.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€¹à€à¥à€</Attribute>
+            <Attribute name="definition">à€¬à¥à€§à¥à€Šà€¿à€ à€žà€à€ªà€Šà¥à€à€Ÿà€¹à€à¥à€</Attribute>
+            <Attribute name="comment">à€žà¥à€µà€€à€à€¹à€Ÿà€à¥ à€²à¥à€à€š à€à€Ÿà€ªà¥à€š à€
+à€¥à€µà€Ÿ à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿà€³à¥à€¯à€Ÿà€µà€° à€ªà¥à€°à€à€Ÿà€¶à€¿à€€ à€à€°à€£à¥à€¯à€Ÿà€à€Ÿ à€²à¥à€à€ à€
+à€¥à€µà€Ÿ à€²à¥à€à€¿à€à¥à€à€Ÿ à€¬à¥à€§à¥à€Šà€¿à€ à€žà€à€ªà€Šà¥à€à€Ÿà€¹à€à¥à€</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+</MetadataSet>
Index: /tags/gsdl-2_61-distribution/gli/metadata/qdublin.mds
===================================================================
--- /tags/gsdl-2_61-distribution/gli/metadata/qdublin.mds	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/metadata/qdublin.mds	(revision 10506)
@@ -0,0 +1,1966 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param family      The name of this sets family.                                 -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param namespace   The namespace of this metadata set.                           -->
+  <!ELEMENT MetadataSet ((Name|Description|SetLanguage|Element)+)>
+  <!ATTLIST MetadataSet
+	    contact            CDATA #REQUIRED
+	    creator            CDATA #REQUIRED
+	    description        CDATA #REQUIRED
+            family             CDATA #REQUIRED
+	    lastchanged        CDATA #REQUIRED
+            name               CDATA #REQUIRED
+	    namespace          CDATA #REQUIRED
+	    language_dependent CDATA "">
+
+  <!-- The name of a metadata set. Is language specific. -->
+  <!ELEMENT Name (#PCDATA)>
+  <!ATTLIST Name
+            language CDATA "en">
+
+  <!-- The description of a metadata set. Is language specific. -->
+  <!ELEMENT Description (#PCDATA)>
+  <!ATTLIST Description
+            language CDATA "en">
+
+  <!-- When used in conjuction with defer-node-expansion, allows for better memory use when dealing with several or more languages. -->
+  <!ELEMENT SetLanguage (Name, Description?)>
+  <!ATTLIST Language
+	    code CDATA #REQUIRED>
+
+  <!-- An element in the metadata set. -->
+  <!-- Note that the name attribute isn't really Dublin Core compliant - it was just the first thing I came up with. -->
+  <!ELEMENT Element (Attribute*,Language*,OptionList?)>
+  <!ATTLIST Element
+            name       CDATA #REQUIRED
+	    occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->	
+  <!-- Given that name was already used for an Element, I decided to use identifier for the language specific 'name', which I've been told isn't really compliant with Dublin Core. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA "">
+
+  <!-- When used in conjuction with defer-node-expansion, allows for better memory use when dealing with several or more languages. -->
+  <!ELEMENT Language (Attribute*)>
+  <!ATTLIST Language
+	    code CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+]>
+<MetadataSet contact="dcmi-feedback@dublincore.org" creator="Dublin Core Metadata Initiative" family="Dublin Core" language_dependent="identifier, definition, comment" lastchanged="Tue Jun 04 10:35:30 2002 - jmt12 on blackbird" namespace="dc">
+    <!-- English Version sourced from http://www.dublincore.org/documents/dces/ -->
+    <SetLanguage code="en">
+        <Name language="en">Qualified Dublin Core Metadata Element Set, Version 1.1: Reference Description</Name>
+        <Description language="en">This document is the reference description, version 1.1 of the Dublin Core Metadata Element Set. This document supersedes the Dublin Core Metadata Element Set, version 1.0. See the Dublin Core Home Page (http://dublincore.org) for further information about the workshops, reports, working group papers, projects, and new developments concerning the Dublin Core Metadata Element set</Description>
+    </SetLanguage>
+    <!-- Maori Version sourced from http://www.tki.org.nz/r/maori/pedagogy/dc_elements_m.php -->
+    <SetLanguage code="mi">
+        <Name>Dublin Core Huanga - Maori (He Tauira)</Name>
+    </SetLanguage>
+    <!-- French Version sourced from http://www-rocq.inria.fr/%7Evercoust/METADATA/DC-fr.1.1.html -->
+    <!--  by Anne-Marie Vercoustre, Inria -->
+    <SetLanguage code="fr">
+        <Name language="fr">ElÃ©ments de mÃ©tadonnÃ©es du Dublin Core, Version 1.1: Description de RÃ©ference</Name>
+        <Description language="fr">Ce document rÃ©sume les derniÃšres dÃ©finitions des Ã©lÃ©ments demÃ©tadonnÃ©es du Dublin Core originellement dÃ©finis dans le document[RFC2413]. Ces nouvelles dÃ©finitions seront officiellement connues comme la Version 1.1. Elles utilisent un standard dÃ©fini formellement pour la description d&apos;Ã©lÃ©ments de mÃ©tadonnÃ©es. Cette formalisation contribue Ã  amÃ©liorer la cohÃ©rence avec d&apos;autres communautÃ©s dÃ©crivant des mÃ©tadonnÃ©es et Ã  augmenter la prÃ©cision, la portÃ©e et la cohÃ©rence interne de la dÃ©finition des Ã©lÃ©ments du Dublin Core.</Description>
+    </SetLanguage>
+    <!-- Russian Version sourced from -->
+    <!-- by Olga Barysheva, National Library of Russia -->
+    <SetLanguage code="ru">
+        <Name language="ru">ÐÐ°Ð±ÐŸÑ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Dublin Core (ÐÑÐ±Ð»ÐžÐœÑÐºÐŸÐ³ÐŸ ÑÐŽÑÐ°) ÐÐµÑÑÐžÑ 1.1: Ð¡Ð¿ÑÐ°Ð²ÐŸÑÐœÐŸÐµ ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ</Name>
+        <Description language="ru">ÐÐ°ÑÑÐŸÑÑÐžÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ ÐŸÐ±ÐŸÐ±ÑÐ°ÐµÑ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐœÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ² ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Dublin Core (ÐÑÐ±Ð»ÐžÐœÑÐºÐŸÐ³ÐŸ ÑÐŽÑÐ°), Ð¿ÐµÑÐ²ÐŸÐœÐ°ÑÐ°Ð»ÑÐœÐŸ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÑ
+ Ð² RFC2413 (ÐÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Dublin Core ÐŽÐ»Ñ ÐœÐ°Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÑ ÑÐµÑÑÑÑÐŸÐ²). Ð­ÑÐž ÐœÐŸÐ²ÑÐµ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÐŸÑÐžÑÐžÐ°Ð»ÑÐœÐŸ ÐžÐ·Ð²ÐµÑÑÐœÑ ÐºÐ°Ðº ÐÐµÑÑÐžÑ 1.1.</Description>
+    </SetLanguage>
+    <!-- Spanish Version sourced from http://www.rediris.es/metadata/. Please note that this is a translation for Dublin Core v1.0 -->
+    <!-- by Javi Masa, RedIRIS -->
+    <SetLanguage code="es">
+        <Name language="es">Elementos del conjunto de metadatas de Dublin Core: DescripciÃ³n de Referencia</Name>
+        <Description language="es">Este documento corresponde a una traducciÃ³n del original en lengua inglesa, con fecha 02/11/1997 que se encuentra en http://purl.org/metadata/dublin_core_elements. Este documento es una descripciÃ³n de referencia de los elementos del conjunto de &quot;Dublin Core&quot;. Para mÃ¡s informaciÃ³n sobre reuniones de trabajo, documentos de trabajo, proyectos y nuevos desarrollos relacionados con el conjunto de elementos que aquÃ­ se describen consultar la &quot;Home Page&quot; de &quot;Dublin Core&quot; (http://purl.org/metadata/dublin_core). Los elementos poseen nombres descriptivos que pretenden transmitir un significado semÃ¡ntico a los mismos. Para promover una interoperabilidad global, una descripciÃ³n del valor de algunos elementos prodrÃ¡ ser asociada a vocabularios controlados. Se asume que otros vocabularios controlados serÃ¡n desarrollados para asegurar esta interoperabilidad en dominios especÃ­ficos. Cada elemento es opcional y puede repetirse. AdemÃ¡s, los elementos pueden aparecer en cualquier orden. Aunque algunos entornos, como HTML, no diferencian entre mayÃºsculas y minÃºsculas, es recomendable escribir correctamente cada metadata segÃºn su definiciÃ³n para evitar conflictos con otros entornos, como XML (Extensible Markup Language) http://www.w3.org/TR/PR-xml</Description>
+    </SetLanguage>
+    <!-- Arabic Version sourced from http://haddouti.de/DC_arabic.html -->
+    <!-- maintained by Hachim Haddouti. -->
+    <SetLanguage code="ar">
+        <Name>Ø¯ØšÙÙÙ ÙÙØ±</Name>
+        <Description>ÙØ±Ø­Øš ØšÙÙ
+ ÙÙ ØµÙØ­Ø©  Ø¯ ØšÙÙÙ ÙÙ  Ø± ØšØ§ÙØ¹Ø±ØšÙ    ÙÙ  ÙØ°Ù Ø§ÙØµÙØ­Ø©  Ù ØšØ§ÙØªØ¹Ø§ÙÙ Ù
+Ø¹ Ø§ÙØ§Ø®ÙØ§Ù Ø§ÙØ¹Ø±Øš Ù
+Ù Ø§ÙÙ
+ÙØªØšØ§ØªØ Ø¯Ø§Ø± Ø§ÙÙØŽØ±Ø Ø§ÙØšØ­ÙØ« Ø§ÙØ¹ÙÙ
+ÙØ© Ù    ÙØ±ØŽØ© Ø¹Ù
+ÙWorking Group On Multilingual Dublin Core (DC-International) Ø</Description>
+    </SetLanguage>
+    <!-- Chinese - Simplified Version from http://dc.library.sh.cn/DC/1-1.htm -->
+    <!-- by Liu Wei, Shanghai Library -->
+    <SetLanguage code="cn">
+        <Name>éœæææ žå¿å
+æ°æ®å
+çŽ é1.1çïŒåèæè¿°</Name>
+        <Description>æ¬ææ¡£å
+³äºéœæææ žå¿å
+æ°æ®å
+çŽ é1.1çæ¬çåèæè¿°ãæ­€æè¿°äžå·²ç»æäº€ç»ISOçšäºåœé
+æç¥šçNISOå®æ¹æ åä¿æäžèŽã    éœæææ žå¿å
+æ°æ®éæ¯äžç§è·šé¢åçä¿¡æ¯èµæºæè¿°æ åãè¿éçä¿¡æ¯èµæºè¢«å®ä¹äžºâä»»äœå
+·ææ è¯çäžè¥¿âãæ­€å®ä¹æ¥èªäºTim Berners-Leeç­äººæèçInternet RFC2396 &quot;Uniform Resource Identifiers (URI): Generic Syntax&quot;æä»¶ãéœæææ žå¿å
+æ°æ®çåºçšé¢åæ²¡ææ ¹æ¬çéå¶ã</Description>
+    </SetLanguage>
+    <!-- Czech Version from http://www.ics.muni.cz/dublin_core/DC-czech-1.1.html -->
+    <!-- Ustav vypocetni techniky Masarykovy univerzity v Brne -->
+    <SetLanguage code="cs">
+        <Name>Soubor metadatovÃœch prvkÅ¯ Dublin Core, verze 1.1: referenÄnÃ­ popis</Name>
+        <Description>Tento dokument je ÄeskÃœm pÅekladem anglickÃ© verze referenÄnÃ­ho popisu souboru metadatovÃœch prvkÅ¯  Dublin Core, verze 1.1 [DCEN1.1]. Tento dokument nahrazuje ÄeskÃœ pÅeklad souboru metadatovÃœch prvkÅ¯ Dublin Core, verze 1.0 [DCCS1.0]. DalÅ¡Ã­ informace o pracovnÃ­ch seminÃ¡ÅÃ­ch (workshopech), zprÃ¡vÃ¡ch, studiÃ­ch pracovnÃ­ch skupin, projektech a dalÅ¡Ã­m vÃœvoji souboru metadatovÃœch prvkÅ¯ Dublin Core najdete na domovskÃ© strÃ¡nce Dublin Core (http://purl.org/dc)</Description>
+    </SetLanguage>
+    <!-- Dutch Version from http://www.kb.nl/coop/donor/project-nl-index.html?/coop/donor/rapporten/DCsimpleformat.html -->
+    <!-- by ... -->
+    <SetLanguage code="nl">
+        <Name>Rapporten Dublin Core Simple Format</Name>
+        <Description>Dit document beschrijft welke Dublin Core metadata elementen er zijn en geeft een korte definitie van elk element. Voor uitgebreide uitleg en gebruik van de Dublin Core elementen wordt u verwezen naar de gebruikershandleiding. Deze vertaling geeft ook de keuzes aan voor standaarden (taalcodes, datum codes) die wij in DONOR verband gaan hanteren. In zoverre kan deze vertaling afwijken van het oorspronkelijke document &quot;Description of Dublin Core Elements&quot; http://purl.org/metadata/dublin_core_elements&quot;</Description>
+    </SetLanguage>
+    <!-- Finnish Version from http://www.lib.helsinki.fi/dublin_core/dcref-fin.html -->
+    <!-- by Jani Stenvall and Juha Hakala, Helsinki University Library -->
+    <SetLanguage code="fi">
+        <Name/>
+        <Description/>
+    </SetLanguage>
+    <!-- Interlingua Version sourced from http://www.nautilus.com.br/%7Eensjo/ia/purl.org/dc/documents/rec-dces-19990702.htm -->
+    <!-- by Emerson Jose` Silveira da Costa -->
+    <SetLanguage code="ia">
+        <Name>Collection de elementos de metadatos de Dublin Core, version 1.1: Description de referentia</Name>
+        <Description>Isto es un traduction de un Recommendation del Dublin Core Metadata Initiative. Le publication como un recommendation significa que le specificationes es stabile e su adoption es supportate per le communitate Dublin Core (http://purl.org/dc/).</Description>
+    </SetLanguage>
+    <!-- Marathi Version sourced from http://bioinfo.ernet.in/library/dc/ele.txt -->
+    <!-- by by Shubhada Nagarkar, Bioinformatics Centre, University of Pune -->
+    <SetLanguage code="mr">
+        <Name>à€¡à€¬à¥à€²à€¿à€š à€à¥à€° à€®à¥à€à€Ÿà€¡à¥à€à€Ÿ à€žà¥à€ à€à€µà¥à€€à¥à€€à¥ à¥§.à¥§ à€žà€à€Šà€°à¥à€­ à€žà¥à€ªà€·à¥à€à¥à€à€°à€£ à¥§.à¥§ à€¡à€¬à¥à€²à€¿à€š à€à¥à€° à€®à¥à€à€Ÿà€¡à¥à€à€Ÿà€à€µà¥à€€à¥à€€à¥ à¥§.à¥§.</Name>
+        <Description>à¥§.à¥§ à€¡à€¬à¥à€²à€¿à€š à€à¥à€° à€®à¥à€à€Ÿà€¡à¥à€à€Ÿ à€¹à¥ à€µà¥à€à€µà¥à€à€³à¥à€¯à€Ÿ à€µà€¿à€·à€¯à€Ÿà€€à¥à€² à€®à€Ÿà€¹à¥à€€à¥ à€žà€Ÿà€ à¥à€¯à€Ÿà€à€µà€Šà¥à€Šà€²à€à¥ à€®à€Ÿà€¹à¥à€€à¥ à€Šà¥à€£à¥à€¯à€Ÿà€à¥ à€®à€Ÿà€šà€ à€à€¹à¥.  à€¯à€Ÿà€€ à€®à€Ÿà€¹à¥à€€à¥à€žà€Ÿà€ à€Ÿ à€®à¥à€¹à€£à€à¥ à€à¥à€¯à€Ÿà€²à€Ÿ à€à€³à€ à€à€¹à¥ à€
+à€žà€Ÿ à€à€žà€€à¥.  à€
+à€¶à€Ÿ à€ªà¥à€°à€à€Ÿà€°à€à¥ à€µà¥à€¯à€Ÿà€à¥à€¯à€Ÿ à€®à€Ÿà€¹à¥à€€à¥ à€à€Ÿà€³à¥à€¯à€µà€°à¥à€² à€. à€à€«.à€žà¥. à¥šà¥©à¥¯à¥¬URI: Generic Syntax -- Tim Berners Lee et al. à€¡à€¬à¥à€²à€¿à€š à€à¥à€° à€®à€Ÿà€šà€ à€à¥à€£à€€à¥à€¯à€Ÿà€¹à¥ à€ªà¥à€°à€à€Ÿà€°à€à¥à€¯à€Ÿ à€®à€Ÿà€¹à¥à€€à¥ à€žà€Ÿà€ à¥à€¯à€Ÿà€à€žà€Ÿà€ à¥ à€µà€Ÿà€ªà€°à€€à€Ÿ à€¯à¥à€€à¥.  à€€à¥à€¯à€Ÿà€žà€Ÿà€ à¥ à€à¥à€£à€€à€Ÿà€¹à¥ à€®à€à¥à€à€Ÿà€µ à€šà€Ÿà€¹à¥.</Description>
+    </SetLanguage>
+    <Element name="Title" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Title</Attribute>
+            <Attribute name="definition">A name given to the resource.</Attribute>
+            <Attribute name="comment">Typically, a Title will be a name by which the resource is formally known.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Taitara</Attribute>
+            <Attribute name="definition">Te ingoa ka tapaina tetahi rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, ko te Taitara te ingoa ka mohio whanuitia te ingoa.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Titre</Attribute>
+            <Attribute name="definition">Le nom donnÃ© Ã  la ressource.</Attribute>
+            <Attribute name="comment">Typiquement, un titre sera le nom par lequel la ressource est officiellement connue.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ</Attribute>
+            <Attribute name="definition">ÐÐŒÑ, ÐŽÐ°ÐœÐœÐŸÐµ ÑÐµÑÑÑÑÑ.</Attribute>
+            <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµÐŒ ÑÐ²Ð»ÑÐµÑÑÑ ÐžÐŒÑ, Ð¿ÐŸÐŽ ÐºÐŸÑÐŸÑÑÐŒ ÑÐµÑÑÑÑ ÐŸÑÐžÑÐžÐ°Ð»ÑÐœÐŸ ÐžÐ·Ð²ÐµÑÑÐµÐœ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">TÃ­tulo</Attribute>
+            <Attribute name="definition">El nombre dado a un recurso, usualmente por el autor.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙØ¹ÙÙØ§Ù</Attribute>
+            <Attribute name="definition">ÙØ°Ø§ Ø§ÙØ§Ø³Ù
+ ÙØ¹Ø·Ù ÙÙÙ
+ØµØ¯Ø±, Ù
+Ù ÙØšÙ Ø§ÙÙ
+ØšØ¯Ø¹ Ø§Ù Ø§ÙÙØ§ØŽØ±</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">èµæºå</Attribute>
+            <Attribute name="definition">èµäºèµæºçåç§°ã</Attribute>
+            <Attribute name="comment">èµæºåäžè¬æèµæºå¯¹è±¡æ­£åŒå
+¬åŒçåç§°ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">NÃ¡zev</Attribute>
+            <Attribute name="definition">JmÃ©no danÃ© zdroji.</Attribute>
+            <Attribute name="comment">NÃ¡zev bude typicky jmÃ©no, pod nÃ­mÅŸ je zdroj oficiÃ¡lnÄ znÃ¡m.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Titel</Attribute>
+            <Attribute name="definition">De naam van de Internetbron. Meestal gegeven door de auteur, maker of uitgever</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Titulo</Attribute>
+            <Attribute name="definition">Un nomine date al ressource.</Attribute>
+            <Attribute name="comment">Typicamente se utiliza un nomine per le qual le ressource es formalmente cognite.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€¶à¥à€°à¥à€·à€</Attribute>
+            <Attribute name="definition">à€ªà€°à¥à€¯à€Ÿà€¯à¥ à€¶à¥à€°à¥à€·à€</Attribute>
+            <Attribute name="comment">à€žà€à€à¥à€·à€¿à€ªà¥à€€ ,  à€­à€Ÿà€·à€Ÿà€à€€à€°à¥à€€  à€¶à¥à€°à¥à€·à€</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="alternative">
+            <Attribute language="en" name="status">recommended</Attribute>
+            <Language code="en">
+                <Attribute name="identifier">Alternative</Attribute>
+                <Attribute name="definition">Any form of the title used as a substitute or alternative to the formal title of the resource.</Attribute>
+                <Attribute name="comment">This qualifier can include Title abbreviations as well as translations.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+        </Element>
+    </Element>
+    <Element name="Creator" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Creator</Attribute>
+            <Attribute name="definition">An entity primarily responsible for making the content of the resource.</Attribute>
+            <Attribute name="comment">Examples of a Creator include a person, an organisation, or a service. Typically, the name of a Creator should be used to indicate the entity.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Kaihanga</Attribute>
+            <Attribute name="definition">Te putahi, nana, na ratou ranei i matua oti ai te hanganga o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tangata, he putahitanga, he ratonga ranei etahi tauira Kaihanga. Ko te tikanga, ko te Kaihanga te ingoa ka whakamahia hei tohu i te putahi na ratou te hanganga.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">CrÃ©ateur</Attribute>
+            <Attribute name="definition">L&apos;entitÃ© principalement responsable de la crÃ©ation du contenu de la ressource.</Attribute>
+            <Attribute name="comment">Exemples de CrÃ©ateur incluent une personne, une organisation, ou un service. Typiquement, un nom du CrÃ©ateur devrait Ãªtre utilisÃ© pour dÃ©signer cette entitÃ©.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ</Attribute>
+            <Attribute name="definition">ÐÐžÑÐŸ, ÐœÐµÑÑÑÐµÐµ Ð¿ÐµÑÐ²ÐžÑÐœÑÑ ÐŸÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÐŸÑÑÑ Ð·Ð° ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÑÐžÐŒÐµÑÑ Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð¿ÐµÑÑÐŸÐœÑ, ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ ÐžÐ»Ðž ÑÐ»ÑÐ¶Ð±Ñ. ÐÐ±ÑÑÐœÐŸ ÐžÐŒÑ Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐžÐž ÐŸÐ±ÑÐµÐºÑÐ°.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Autor o Creador</Attribute>
+            <Attribute name="definition">La persona u organizaciÃ³n responsable de la creaciÃ³n del contenido intelectual del recurso. Por ejemplo, los autores en el caso de documentos escritos, artistas, fotografos e ilustradores en el caso de recursos visuales.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙØ§ØªØš Ø§Ù Ø§ÙÙ
+ØšØ¯Ø¹</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙØŽØ®Øµ Ø§Ù Ø§ÙÙ
+Ø€Ø³Ø³Ø© Ø£ÙÙØ§  Ø¹Ù ÙØŽØŠ Ø§ÙÙ
+Ø­ØªÙÙ Ø§ÙÙÙØ± Ù ÙÙÙ
+ØµØ¯Ø± , Ø¹ÙÙ Ø³ØšÙÙ Ø§ÙÙ
+Ø«Ø§Ù , Ø§ÙÙ
+Ø€ÙÙÙÙ ÙÙ Ø­Ø§ÙØ© Ø§ÙØ«Ø§ØŠÙ Ø§ÙÙ
+ÙØªÙØšØ© , Ù Ø§ÙÙÙØ§ÙÙÙ , Ø§ÙÙ
+ØµÙØ±ÙÙ ÙÙ Ø­Ø§ÙØ© Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙÙ
+Ø±ØŠÙØ©</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">åå»ºè
+</Attribute>
+            <Attribute name="definition">åå»ºèµæºå
+å®¹çäž»èŠèŽ£ä»»è
+ã</Attribute>
+            <Attribute name="comment">åå»ºè
+çå®äŸå
+æ¬äžªäººïŒç»ç»ææé¡¹æå¡ãäžè¬èèšïŒçšåå»ºè
+çåç§°æ¥æ è¯è¿äžæ¡ç®ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">TvÅ¯rce</Attribute>
+            <Attribute name="definition">Entita primÃ¡rnÄ odpovÄdnÃ¡ za vytvoÅenÃ­ obsahu zdroje.</Attribute>
+            <Attribute name="comment">PÅÃ­klady TvÅ¯rce zahrnujÃ­ osobu, organizaci nebo sluÅŸbu. K oznaÄenÃ­ entity se typicky pouÅŸÃ­vÃ¡ jmÃ©no tvÅ¯rce.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Auteur of maker</Attribute>
+            <Attribute name="definition">De auteur, maker of organisatie die primair verantwoordelijk is voor de intellectuele inhoud van het werk. Bijvoorbeeld auteurs in geval van geschreven documenten, artiesten, fotografen of illustrators in geval van visuele bronnen.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Creator</Attribute>
+            <Attribute name="definition">Le entitate primarimente responsabile pro producer le contento del ressource.</Attribute>
+            <Attribute name="comment">Exemplos de creator include un persona, un organization, o un servicio. Typicamente se utiliza un nomine de creator pro indicar iste entitate.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€šà€¿à€°à¥à€®à€Ÿà€€à€Ÿ, à€à€šà€</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ à€šà€¿à€°à¥à€®à€Ÿà€£  à€à€°à€£à€Ÿà€°à€Ÿ</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ.  à€²à¥à€à€, à€²à¥à€à€¿à€à€Ÿ,  à€µà¥à€¯à€à¥à€€à¥, à€žà€à€žà¥à€¥à€Ÿ,  à€žà€à€ªà€Ÿà€Šà€, à€žà€à€ªà€Ÿà€Šà€¿à€à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Subject" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Subject and Keywords</Attribute>
+            <Attribute name="definition">The topic of the content of the resource.</Attribute>
+            <Attribute name="comment">Typically, a Subject will be expressed as keywords, key phrases or classification codes that describe a topic of the resource. Recommended best practice is to select a value from a controlled vocabulary or formal classification scheme.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Kaupapa</Attribute>
+            <Attribute name="definition">Te take/ nga take o te kaupapa, o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, ka whakaaturia te kaupapa o te rauemi e nga kupu matua, nga kimahi matua, nga tohu wehewehenga whakaahua ranei.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Sujet</Attribute>
+            <Attribute name="definition">Le sujet du contenu de la ressource.</Attribute>
+            <Attribute name="comment">Typiquement, le sujet sera dÃ©crit par un ensemble de mots-clefs ou de phrases ou un code de classification qui prÃ©cisent le sujet de la ressource. L&apos;utilisation de vocabulaires contrÃŽlÃ©s et de schÃ©mas formels de classification est encouragÃ©e.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÑÐµÐŽÐŒÐµÑ Ðž ÐºÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð°</Attribute>
+            <Attribute name="definition">Ð¢ÐµÐŒÐ° ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÐÑÐµÐŽÐŒÐµÑ Ð²ÑÑÐ°Ð¶Ð°ÐµÑÑÑ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐºÐ»ÑÑÐµÐ²ÑÑ
+ ÑÐ»ÐŸÐ², ÐºÐ»ÑÑÐµÐ²ÑÑ
+ ÑÑÐ°Ð· ÐžÐ»Ðž  ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÑÑ
+ ÐºÐŸÐŽÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐŸÐ¿ÐžÑÑÐ²Ð°ÑÑ ÑÐµÐŒÑ ÑÐµÑÑÑÑÐ°. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ ÐžÐ»Ðž ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÑ
+ÐµÐŒÑ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Claves</Attribute>
+            <Attribute name="definition">Los tÃ³picos del recurso. TÃ­picamente, Subject expresarÃ¡ las claves o frases que describen el tÃ­tulo o el contenido del recurso. Se fomentarÃ¡ el uso de vocabularios controlados y de sistemas de clasificaciÃ³n formales. Se pueden ver ejemplos de vocabularios controlados en: Controlled vocabularies, thesauri and classification systems available in the WWW. DC Subject</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙ
+ÙØ¶ÙØ¹ Ù Ø§ÙÙÙÙ
+Ø§Øª Ø§ÙØ±ØŠÙØ³ÙØ©</Attribute>
+            <Attribute name="definition">ÙÙ Ù
+ÙØ¶ÙØ¹ Ø§ÙÙ
+ØµØ¯Ø±. ÙÙ
+ÙØ°Ø¬ÙØ§  ÙØ¹ØšØ± Ø¹Ù Ø§ÙÙ
+ÙØ¶ÙØ¹ ØšØ§Ø³ØªØ®Ø¯Ø§Ù
+Ù
+ÙØªØ§Ø­  Ø§ÙÙÙÙ
+Ø§Øª  Ø§Ù Ø¬Ù
+Ù Ø§ÙØªÙ  ØªØµÙ Ù
+ÙØ¶ÙØ¹ Ø§Ù Ù
+Ø­ØªÙÙ Ø§ÙÙ
+ØµØ¯Ø± , Ù ÙØ³ØªØ­Ø³Ù Ø§Ø³ØªØ®Ø¯Ø§Ù
+ Ù
+ÙØ±Ø¯Ø§Øª Ù
+Ø®Ø·Ø·Ø©Ù Ù
+Ø­ÙÙ
+Ø©  ÙØ§Ø¯ÙØ© ØªØµÙÙÙ ØŽÙÙÙØ©</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">äž»é¢åå
+³é®è¯</Attribute>
+            <Attribute name="definition">èµæºå
+å®¹çäž»é¢æè¿°ã</Attribute>
+            <Attribute name="comment">åŠæèŠæè¿°ç¹å®èµæºçæäžäž»é¢ïŒäžè¬éçšå
+³é®è¯ãå
+³é®å­ç­è¯­æåç±»å·ïŒæå¥œäž»é¢åå
+³é®è¯ä»åæ§    è¯è¡šæè§èçåç±»äœç³»äž­ååŒã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">PÅedmÄt a klÃ­ÄovÃ¡ slova</Attribute>
+            <Attribute name="definition">TÃ©ma obsahu zdroje.</Attribute>
+            <Attribute name="comment">PÅedmÄt bude typicky vyjÃ¡dÅen pomocÃ­ klÃ­ÄovÃœch slov, klÃ­ÄovÃœch frÃ¡zÃ­ nebo klasifikaÄnÃ­ch znakÅ¯ popisujÃ­cÃ­ch tÃ©ma zdroje. DoporuÄuje se vybÃ­rat hodnotu prvku z ÅÃ­zenÃ©ho slovnÃ­ku nebo formÃ¡lnÃ­ho klasifikaÄnÃ­ho schÃ©matu.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Onderwerp en trefwoorden</Attribute>
+            <Attribute name="definition">Het onderwerp van de Internetbron. Het onderwerp wordt beschreven in korte zinnen of door het gebruik van trefwoorden. Het gebruik van gecontroleerde trefwoorden of classificatie schema&apos;s wordt aanbevolen.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Subjecto e parolas-clave</Attribute>
+            <Attribute name="definition">Le topico del contento del ressource.</Attribute>
+            <Attribute name="comment">Typicamente le subjecto es expresse per medio de parolas-clave, phrases-clave, o codices de classification que describe le topico del ressource. Le melior practica recommendate es selectionar un valor a partir de un vocabulario controlate o un schema formal de classification.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€µà€¿à€·à€¯</Attribute>
+            <Attribute name="definition">à€µà€¿à€·à€¯</Attribute>
+            <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ, à€à¥à€à€Ÿà€šà€žà€Ÿà€§à€šà¥ à€¯à€Ÿà€€à¥à€² à€à€¶à€¯ à€žà¥à€ªà€·à¥à€ à€à€°à€£à€Ÿà€°à¥ à€¶à€¬à¥à€Š, à€µà€¿à€·à€¯à€Ÿà€à¥ à€µà€°à¥à€à¥à€à€°à€£ à€à€°à€€à€Ÿà€šà€Ÿ à€¶à€¬à¥à€Šà€žà€à€à¥à€°à€¹ à€
+à€¥à€µà€Ÿ à€¶à€¬à¥à€Š à€à¥à€·à€Ÿà€à€Ÿ à€µà€Ÿà€ªà€° à€à€°à€Ÿà€µà€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Description" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Description</Attribute>
+            <Attribute name="definition">An account of the content of the resource.</Attribute>
+            <Attribute name="comment">Description may include but is not limited to: an abstract, table of contents, reference to a graphical representation of content or a free-text account of the content.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Whakaaturanga</Attribute>
+            <Attribute name="definition">He whakaaturanga o nga kaupapa o te rauemi.</Attribute>
+            <Attribute name="comment">Ka uru atu, engari ehara noa ko: te whakarapopototanga korero, te ihirangi, te tohutanga o te kaupapa ma te whakaahua, te whakaaturanga kore kupu ranei, o te kauapapa.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Description</Attribute>
+            <Attribute name="definition">Une description du contenu de la ressource.</Attribute>
+            <Attribute name="comment">Une Description peut contenir, mais ce n&apos;est pas limitatif: un rÃ©sumÃ©, une table des matiÃšres, une rÃ©fÃ©rence Ã  une reprÃ©sentation graphique du contenu, ou un texte libre sur le contenu.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÐ¿ÐžÑÐ°ÐœÐžÐµ</Attribute>
+            <Attribute name="definition">Ð¡ÐŸÐŸÐ±ÑÐµÐœÐžÐµ ÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐž ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ¿ÐžÑÐ°ÐœÐžÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐŸ (Ð¿ÐŸ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÑÑÐž) Ð² Ð²ÐžÐŽÐµ: ÑÐµÑÐµÑÐ°ÑÐ°, ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÑ, ÑÑÑÐ»ÐºÐž ÐœÐ° Ð³ÑÐ°ÑÐžÑÐµÑÐºÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÐžÐ»Ðž Ð¿ÑÐŸÑÑÐŸÐ³ÐŸ ÑÐµÐºÑÑÐŸÐ²ÐŸÐ³ÐŸ ÐžÐ·Ð»ÐŸÐ¶ÐµÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">DescripciÃ³n</Attribute>
+            <Attribute name="definition">Una descripciÃ³n textual del recurso, tal como un resumen en el caso de un documento o una descripciÃ³n del contenido en el caso de un documento visual.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙØµÙ</Attribute>
+            <Attribute name="definition">ÙÙ ÙØµÙ ÙØµÙ  ÙÙ
+Ø­ØªÙÙ Ø§ÙÙ
+ØµØ¯Ø±, ÙÙØ¶Ù
+ Ø§ÙÙ
+ÙØ®ØµØ§Øª ÙÙ Ø­Ø§ÙØ© Ø§ÙÙØ«Ø§ØŠÙ Ù
+Ø«Ù Ø§ÙØ§ØŽÙØ§Ø¡ Ø§ÙÙ
+ÙØªÙØšØ© Ø§Ù ØªÙØµÙÙ Ø§ÙÙ
+Ø­ØªÙÙ ÙÙ Ø­Ø§ÙØ© Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙÙ
+Ø±ØŠÙØ©</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">è¯Žæ</Attribute>
+            <Attribute name="definition">èµæºå
+å®¹çè§£é</Attribute>
+            <Attribute name="comment">è¯Žæå¯ä»¥å
+æ¬äœäžéäºä»¥äžå
+å®¹ïŒææãç®åœãå¯¹ä»¥åŸåœ¢æ¥æ­ç€ºå
+å®¹çèµæºèèšçæå­è¯Žæãæè
+äž    äžªæå
+³èµæºå
+å®¹çèªç±ææ¬æè¿°ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Popis</Attribute>
+            <Attribute name="definition">VysvÄtlenÃ­ obsahu zdroje.</Attribute>
+            <Attribute name="comment">Popis mÅ¯ÅŸe obsahovat (mimo jinÃ©): abstrakt, obsah, odkaz na grafickÃ© nebo volnÃ© textovÃ© vyjÃ¡dÅenÃ­ obsahu.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Omschrijving</Attribute>
+            <Attribute name="definition">Een omschrijving van de inhoud van de Internetbron. Abstracts of inhoudsomschrijvingen.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Description</Attribute>
+            <Attribute name="definition">Un description del contento del ressource.</Attribute>
+            <Attribute name="comment">Le description pote includer, ma non se limita a: summario, indice, referentia a un representation graphic del contento o un texto libere a proposito del contento.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€µà€°à¥à€£à€š</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥, à€à¥à€à€Ÿà€šà€žà€Ÿà€§à€šà€Ÿà€à¥à€µà€°à¥à€£à€š</Attribute>
+            <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€šà€¿à€µà¥à€Šà€š, à€à€²à¥à€, à€à€¿à€€à¥à€°à€°à¥à€ª</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="abstract">
+            <Language code="en">
+                <Attribute name="identifier">Abstract</Attribute>
+                <Attribute name="definition">A summary of the content of the resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="tableOfContents">
+            <Language code="en">
+                <Attribute name="identifier">Table Of Contents</Attribute>
+                <Attribute name="definition">A list of subunits of the content of the resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+    </Element>
+    <Element name="Publisher" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Publisher</Attribute>
+            <Attribute name="definition">An entity responsible for making the resource available.</Attribute>
+            <Attribute name="comment">Examples of a Publisher include a person, an organisation, or a service. Typically, the name of a Publisher should be used to indicate the entity.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Kaiwhakaputa</Attribute>
+            <Attribute name="definition">Te putahi nana i whakaputa te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tangata, he putahitanga, he ratonga ranei etahi tauira Kaiwhakaputa. Ko te tikanga, ka whakamahia te ingoa o te Kaiwhakaputa hei tohu i te putahi.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Editeur</Attribute>
+            <Attribute name="definition">L&apos;entitÃ© responsable de la diffusion de la ressource, dans sa forme actuelle, tels, un dÃ©partement universitaire, une entreprise.</Attribute>
+            <Attribute name="comment">Exemples d&apos;Editeurs incluent une personne, une organisation, ou un service. Typiquement, le nom d&apos;une maison d&apos;Ã©dition devrait Ãªtre utilisÃ© ici.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÐ·ÐŽÐ°ÑÐµÐ»Ñ</Attribute>
+            <Attribute name="definition">ÐÐžÑÐŸ, ÐŸÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÐŸÐµ Ð·Ð° Ð²Ð²ÐŸÐŽ ÑÐµÑÑÑÑÐ° Ð² ÐŸÐ±ÑÐ°ÑÐµÐœÐžÐµ.</Attribute>
+            <Attribute name="comment">ÐÑÐžÐŒÐµÑÑ ÐÐ·ÐŽÐ°ÑÐµÐ»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð¿ÐµÑÑÐŸÐœÑ, ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ ÐžÐ»Ðž ÑÐ»ÑÐ¶Ð±Ñ. ÐÐ±ÑÑÐœÐŸ ÐžÐŒÑ ÐÐ·ÐŽÐ°ÑÐµÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐžÐž ÐŸÐ±ÑÐµÐºÑÐ°.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Editor</Attribute>
+            <Attribute name="definition">&gt;La entidad responsable de hacer que el recurso se encuentre disponible en la red en su formato actual, por ejemplo la empresa editora, un departamento universitario u otro tipo de organizaciÃ³n.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙØ§ØŽØ±</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙÙÙØŠØ© Ø§ÙÙ
+Ø³Ø€ÙÙØ© Ø¹Ù ØµÙØ§Ø¹Ø© Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙÙ
+ØªÙÙØ± ÙÙ Ø­Ø§ÙØªÙ Ø§ÙØ­Ø§Ø¶Ø±Ø©, Ù
+Ø«Ù Ø¯Ø§Ø± Ø§ÙÙØŽØ±, ÙØ³Ù
+ Ø¬Ø§Ù
+Ø¹Ù Ø§Ù Ù
+Ø€Ø³Ø³Ø© Ø§Ø¹Ù
+Ø§Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">åºçè
+</Attribute>
+            <Attribute name="definition">äœ¿èµæºæäžºå¯ä»¥è·åŸå¹¶å¯çšçèŽ£ä»»è
+ã</Attribute>
+            <Attribute name="comment">åºçè
+çå®äŸå
+æ¬äžªäœïŒç»ç»ïŒææå¡ãäžè¬èèšïŒåºè¯¥çšåºçè
+çåç§°æ¥æ è¯è¿äžæ¡ç®ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Vydavatel</Attribute>
+            <Attribute name="definition">Entita odpovÄdnÃ¡ za zpÅÃ­stupnÄnÃ­ zdroje.</Attribute>
+            <Attribute name="comment">PÅÃ­klady Vydavatele zahrnujÃ­ osobu, organizaci nebo sluÅŸbu. K oznaÄenÃ­ entity se typicky pouÅŸÃ­vÃ¡ jmÃ©no vydavatele.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Uitgever</Attribute>
+            <Attribute name="definition">De entiteit die verantwoordelijk is voor het beschikbaarstellen van de Internetbron in de huidig vorm. Bijvoorbeeld een uitgeversbedrijf, een universiteitsafdeling.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Editor</Attribute>
+            <Attribute name="definition">Un entitate responsabile pro disponibilizar le ressource.</Attribute>
+            <Attribute name="comment">Exemplos de editor include un persona, un organization, o un servicio. Typicamente se utiliza un nomine de editor pro indicar le entitate.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€ªà¥à€°à€à€Ÿà€¶à€</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ  à€à€ªà€²à€¬à¥à€§ à€à€°à¥à€š à€Šà¥à€£à€Ÿà€°à€Ÿ</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ.à€ à€ªà¥à€°à€à€Ÿà€¶à€ , à€ªà¥à€°à€à€Ÿà€¶à€š  à€žà€à€žà¥à€¥à€Ÿ, à€žà¥à€µà€Ÿ    à€®à€Ÿà€¹à€¿à€€à¥ à€à€Ÿà€ªà¥à€² à€°à¥à€ªà€Ÿà€€  à€
+à€¥à€µà€Ÿ à€à€à€à€°à€šà¥à€ à€µà€° à€à€ªà€²à€¬à¥à€§ à€à€°à¥à€š à€Šà¥à€£à€Ÿà€°à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Contributor" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Contributor</Attribute>
+            <Attribute name="definition">An entity responsible for making contributions to the content of the resource.</Attribute>
+            <Attribute name="comment">Examples of a Contributor include a person, an organisation, or a service. Typically, the name of a Contributor should be used to indicate the entity.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Kaiwhakaaro</Attribute>
+            <Attribute name="definition">Te putahi nana, na ratou ranei nga whakakaupapatanga whakaaro o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tangata, he putahitanga, he ratonga ranei etahi tauira Kaiwhakaaro. Ko te tikanga ka whakamahia te ingoa o te Kaiwhakaaro hei tohu i te putahi.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Contributeur</Attribute>
+            <Attribute name="definition">Une entitÃ© qui a contribuÃ© Ã  la crÃ©ation du contenu de la ressource.</Attribute>
+            <Attribute name="comment">Exemples de Contributeur incluent une personne, une organisation, ou un service. Typiquement, le nom d&apos;un contributeur devrait Ãªtre utilisÃ© ici pour dÃ©signer l&apos;entitÃ©.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">Ð¡ÐŸÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ</Attribute>
+            <Attribute name="definition">ÐÐžÑÐŸ, Ð²ÐœÐµÑÑÐµÐµ Ð²ÐºÐ»Ð°ÐŽ Ð² ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÑÐžÐŒÐµÑÑ Ð¡ÐŸÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð¿ÐµÑÑÐŸÐœÑ, ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ ÐžÐ»Ðž ÑÐ»ÑÐ¶Ð±Ñ. ÐÐ±ÑÑÐœÐŸ ÐžÐŒÑ Ð¡ÐŸÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐžÐœÐŽÐžÐºÐ°ÑÐžÐž ÐŸÐ±ÑÐµÐºÑÐ°.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Otros Colaboradores</Attribute>
+            <Attribute name="definition">Una persona u organizacion que haya tenido una contribuciÃ³n intelectual significativa en la creaciÃ³n del recurso pero cuyas contribuciones son secundarias en comparaciÃ³n a las de las personas u organizaciones especificadas en el elementeo Creator (por ejemplo, editor, ilustrador y traductor).</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙ
+Ø³Ø§ÙÙ
+ Ø§ÙØ§Ø®Ø±</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙØŽØ®Øµ Ø§Ù Ø§ÙÙ
+Ø€Ø³Ø³Ø© Ø§ÙØºÙØ± Ù
+Ø°ÙÙØ± ØµØ±Ø§Ø­Ø© ÙÙ Ø¹Ø§Ù
+Ù &quot; Ø§ÙÙ
+ØšØ¯Ø¹ &quot; Ù Ø§ÙØ°Ù ÙØ¯Ù
+ Ù
+Ø³Ø§ÙÙ
+Ø§Øª ÙÙØ±ÙØ© ÙØ§Ù
+Ø© ÙÙÙ
+ØµØ¯Ø±, ÙÙÙ Ù
+Ø³Ø§ÙÙ
+ØªÙØªØšÙÙ    Ø«Ø§ÙÙÙØ© Ù
+ÙØ§Ø±ÙØ© Ù
+Ø¹ Ø§ÙØŽØ®Øµ Ø£Ù Ø§ÙÙ
+Ø€Ø³Ø³Ø© Ø§ÙÙ
+Ø°ÙÙØ±Ø© ÙØµØ§ ÙÙ Ø¹Ø§Ù
+Ù &quot; Ø§ÙÙ
+ÙØŽØŠ &quot; Ù
+Ø«ÙØ§Ù Ù
+ØµØ­Ø­, Ø§ÙÙ
+ØªØ±Ø¬Ù
+, Ø§Ù Ø§ÙÙ
+ÙØ³Ø±</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">å
+¶ä»èŽ£ä»»è
+</Attribute>
+            <Attribute name="definition">å¯¹èµæºçå
+å®¹äœåºèŽ¡ç®çå
+¶ä»å®äœã</Attribute>
+            <Attribute name="comment">å
+¶ä»èŽ£ä»»è
+çå®äŸå¯å
+æ¬äžªäººãç»ç»ææé¡¹æå¡ãäžè¬èèšïŒçšå
+¶ä»èŽ£ä»»è
+çåå­æ¥æ è¯è¿äžæ¡ç®ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">PÅispÄvatel</Attribute>
+            <Attribute name="definition">Entita, kterÃ¡ pÅispÄla k vytvoÅenÃ­ obsahu zdroje.</Attribute>
+            <Attribute name="comment">PÅÃ­klady PÅispÄvatele zahrnujÃ­ osobu, organizaci nebo sluÅŸbu. K oznaÄenÃ­ entity se typicky pouÅŸÃ­vÃ¡ jmÃ©no pÅispÄvatele.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Andere medewerkers</Attribute>
+            <Attribute name="definition">Een persoon of organisatie die een belangrijke bijdrage heeft geleverd, maar die secondair is aan de persoon of organisatie die bij &quot;Creator&quot; genoemd wordt. Gedacht kan worden aan editors, vertalers en illustrators.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Contribuente</Attribute>
+            <Attribute name="definition">Un entitate responsabile pro facer contributiones al contento del ressource.</Attribute>
+            <Attribute name="comment">Exemplos de contribuente include un persona, un organization, o un servicio. Typicamente se utiliza un nomine de contribuente pro indicar le entitate.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier"> à€žà€¹à€¯à¥à€à€, à€žà€¹à€¯à¥à€à¥, à€žà€¹à€Ÿà€¯à¥à€¯à€</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ à€žà€à€à€²à¥à€€ à€à€°à€£à¥à¥à€Ÿà€ž  à€®à€Šà€€ à€à€°à€£à€Ÿà€°à¥ à€µà¥à€¯à€à¥à€€à¥</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ.à€ à€µà¥à€¯à€à¥à€€à¥, à€žà¥à€µà€Ÿ, à€žà€à€žà¥à€¥à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Date" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Date</Attribute>
+            <Attribute name="definition">A date associated with an event in the life cycle of the resource.</Attribute>
+            <Attribute name="comment">Typically, Date will be associated with the creation or availability of the resource.  Recommended best practice for encoding the date value is defined in a profile of ISO 8601 and follows the YYYY-MM-DD format.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Ra</Attribute>
+            <Attribute name="definition">He ra e whai panga ana ki te huringa ora o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, ka whai panga te ra ki te hanganga, te wateatanga ranei, o te rauemi. Ko te huarahi tino pai hei tohu i te uara o te ra (date value) kua whakaritea i roto i te whakaritenga IS0 8601 [W3CDTF], a, e whai atu ana ki te whakatakotoranga YYYY-MM-DD.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Date</Attribute>
+            <Attribute name="definition">Une date associÃ©e avec un Ã©vÃ©nement dans le cycle de vie de la ressource.</Attribute>
+            <Attribute name="comment">Typiquement, une date sera associÃ©e Ã  la crÃ©ation ou Ã  la publication d&apos;une ressource. Il est fortement recommandÃ© d&apos;encoder la valeur de la date en utilisant le format dÃ©fini par l&apos;ISO 8601 [W3CDTF] sous la forme AAAA-MM-JJ.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÐ°ÑÐ°</Attribute>
+            <Attribute name="definition">ÐÐ°ÑÐ°, ÑÐ²ÑÐ·Ð°ÐœÐœÐ°Ñ Ñ ÑÐŸÐ±ÑÑÐžÐµÐŒ Ð² Ð¶ÐžÐ·ÐœÐµÐœÐœÐŸÐŒ ÑÐžÐºÐ»Ðµ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÐÐ°ÑÐ° Ð°ÑÑÐŸÑÐžÐžÑÑÐµÑÑÑ Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµÐŒ ÐžÐ»Ðž ÐŽÐŸÑÑÑÐ¿ÐœÐŸÑÑÑÑ ÑÐµÑÑÑÑÐ°. ÐÐ° Ð¿ÑÐ°ÐºÑÐžÐºÐµ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐŽÐ»Ñ ÐºÐŸÐŽÐžÑÐŸÐ²ÐºÐž Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŽÐ°ÑÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÐµ Ð¿ÑÐŸÑÐžÐ»Ñ ISO 8601 (Ð€ÐŸÑÐŒÐ°ÑÑ ÐŽÐ°ÑÑ Ðž Ð²ÑÐµÐŒÐµÐœÐž W3C), ÐºÐŸÑÐŸÑÐŸÐµ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÐµÑ ÑÐŸÑÐŒÐ°Ñ ÐÐÐÐ-ÐÐ-ÐÐ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Fecha</Attribute>
+            <Attribute name="definition">Una fecha en la que el recurso se puso a disposiciÃ³n del usuario en su forma actual. Esta fecha no ha de confundirse con la que pertenece al elemento Coverage, que serÃ­a asociada con el recurso sÃ³lo en la medida en que el contenido intelectual estÃ¡ de algÃºn modo relacionado con esa fecha. Recomendamos la utiliazaciÃ³n de uno de los formatos definidos en el documento &quot;Date and Time Formats&quot;, http://www.w3.org/TR/NOTE-datetime basado en la norma ISO 8601 que incluye, entre otras, fechas en el formato AAAA y AAAA-MM-DD. De esta forma la fecha 1994-11-05 corresponderÃ­a al 5 de Noviembre de 1994.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙØªØ§Ø±Ø®</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙØªØ§Ø±ÙØ® Ø§ÙÙ
+ØªØ¹ÙÙ ØšÙÙØª ÙØŽØŠ Ø£Ù ØªÙÙØ± Ø§ÙÙ
+ØµØ¯Ø± . Ù ÙØ¬Øš Ø£Ù ÙØ§ ÙØ®ÙØ· ÙØ°Ø§ Ø§ÙØªØ§Ø±ÙØ® Ø§ÙØ¹Ø§ØŠØ¯ ÙØ¹Ø§Ù
+Ù Ø§ÙØªØºØ·ÙØ© , Ù Ø§ÙØ° Ù ÙØ¬Øš Ø£Ù    ÙÙØ­Ù ØšØ§ÙÙ
+ØµØ¯Ø± ÙÙØ· Ù
+Ù ÙØ§Ø­ÙØ© Ø§ÙÙ
+Ø­ØªÙÙØ§ÙÙÙØ±Ù ÙÙÙÙÙ ÙÙØ¹Ø§ Ù
+Ø§ ÙÙ ÙØ°Ø§ Ø§ÙØªØ§Ø±ÙØ®. Ø§ÙØµÙØºØ© Ø§ÙÙ
+Ø³Ø«Ø­Ø³ÙØ© ÙÙØ§Ø­Ø³Ù Ø§ÙÙ
+ØªØ¹Ø§Ø±Ù Ø¹ÙÙÙ    Ø¹ÙØ¯ Ø§ÙØªØ·ØšÙÙ ÙÙ Ø§ÙØµÙØºØ© Ø§ÙÙ
+Ø¹ØªÙ
+Ø¯Ø© ÙÙ ØªØŽÙÙÙ (ISO 8601) ØµÙØºØ© ØªØ§Ø±ÙØ® Ø§ÙÙÙÙ
+ Ù Ø§ÙÙÙØª ) Ø§Ø¹ØªÙ
+Ø§Ø¯Ø§ Ø¹ÙÙ (ISO 8601) Ø§ÙÙ
+ÙØ§Ø­ØžØ© Ø§ÙÙÙÙØ© http://www.w3.org/TR/NOTE-datetime, W3C. ÙÙÙ    ÙØ°Ø§ Ø§ÙÙØ³Ù , Ù
+Ø«ÙØ§, ØªØ§Ø±ÙØ® Ø§ÙÙÙÙ
+ 1994-11-04 ÙÙØ§ØžØ± ÙÙÙ
+ 5 ÙÙÙÙ
+ØšØ± 1994</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">æ¥æ</Attribute>
+            <Attribute name="definition">äžèµæºçåœåšæäž­çäžäžªäºä»¶çžå
+³çæ¶éŽã</Attribute>
+            <Attribute name="comment">äžè¬èèšïŒæ¥æåºäžèµæºçåå»ºæåºçæ¥æçžå
+³ãå»ºè®®éçšçæ¥ææ ŒåŒåºç¬ŠåISO 8601 [W3CDTF]è§    èïŒå¹¶äœ¿çšYYYY-MM-DDçæ ŒåŒã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Datum</Attribute>
+            <Attribute name="definition">Datum spojenÃ© s urÄitou udÃ¡lostÃ­ bÄhem existence zdroje.</Attribute>
+            <Attribute name="comment">Datum bude typicky spojeno s vytvoÅenÃ­m nebo zpÅÃ­stupnÄnÃ­m zdroje. DoporuÄenÃœ postup pro kÃ³dovÃ¡nÃ­ hodnoty data je definovÃ¡n v ISO 8601 [W3CDTF]: formÃ¡t RRRR-MM-DD.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Datum</Attribute>
+            <Attribute name="definition">De datum van de totstandkoming of beschikbaarstelling van een Internetbron. Deze datum moet niet verward worden met de datum in &quot;Coverage&quot;. De datum in &quot;Coverage&quot; geeft de tijdsperiode van de inhoud van de Internetbron aan. Voorgeschreven wordt de ISO 8601 standaard voor datum, zoals beschreven in W3C Technical Note http://www.w3.org/TR/NOTE-datetime. Hierin wordt het formaat YYYY-MM-DD beschreven. Het formaat YYYY-MM-DD wordt de voorgeschreven standaard. 3 September 1998 wordt in dit geval 1998-09-03.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Data</Attribute>
+            <Attribute name="definition">Un data associate a un evento in le cyclo vital del ressource.</Attribute>
+            <Attribute name="comment">Typicamente le data es associate al creation o disponibilization del ressource. Le practica recommendate pro codificar le valor del datas es definite in un profilo de ISO 8601 [W3CDTF] e seque le formato AAAA-MM-DD.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€€à€Ÿà€°à¥à€,  à€Šà€¿à€šà€Ÿà€à€</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ à€€à€¯à€Ÿà€° à€à¥à€²à¥à€¯à€Ÿà€à¥ à€€à€Ÿà€°à¥à€</Attribute>
+            <Attribute name="comment">à€€à€Ÿà€°à¥à€  à€²à€¿à€¹à¥à€£à¥à€¯à€Ÿà€à¥ à€žà¥à€µà€°à¥à€ª à€ à€µà€°à¥à€·. à€®à€¹à€¿à€šà€Ÿ. à€Šà€¿à€µà€ž à¥§à¥¯à¥«à¥Š. à¥Šà¥ª. à¥Šà¥ª</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="available">
+            <Language code="en">
+                <Attribute name="identifier">Available</Attribute>
+                <Attribute name="definition">Date (often a range) that the resource will become or did become available.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="created">
+            <Language code="en">
+                <Attribute name="identifier">Created</Attribute>
+                <Attribute name="definition">Date of creation of the resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="dateAccepted">
+            <Language code="en">
+                <Attribute name="identifier">Date Accepted</Attribute>
+                <Attribute name="definition">Date of acceptance of the resource (e.g. of thesis by university department, of article by journal, etc.).</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">conforming</Attribute>
+        </Element>
+        <Element name="dateCopyrighted">
+            <Language code="en">
+                <Attribute name="identifier">Date Copyrighted</Attribute>
+                <Attribute name="definition">Date of a statement of copyright.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">conforming</Attribute>
+        </Element>
+        <Element name="dateSubmitted">
+            <Language code="en">
+                <Attribute name="identifier">Date Submitted</Attribute>
+                <Attribute name="definition">Date of submission of the resource (e.g. thesis, articles, etc.).</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">conforming</Attribute>
+        </Element>
+        <Element name="issued">
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Language code="en">
+                <Attribute name="identifier">Issued</Attribute>
+                <Attribute name="definition">Date of formal issuance (e.g., publication) of the resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="modified">
+            <Language code="en">
+                <Attribute name="identifier">Modified</Attribute>
+                <Attribute name="definition">Date on which the resource was changed.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="valid">
+            <Attribute language="en" name="status">recommended</Attribute>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Language code="en">
+                <Attribute name="identifier">Valid</Attribute>
+                <Attribute name="definition">Date (often a range) of validity of a resource.</Attribute>
+            </Language>
+        </Element>
+    </Element>
+    <Element name="Type" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Resource Type</Attribute>
+            <Attribute name="definition">The nature or genre of the content of the resource.</Attribute>
+            <Attribute name="comment">Type includes terms describing general categories, functions, genres, or aggregation levels for content. Recommended best practice is to select a value from a controlled vocabulary (for example, the working draft list of Dublin Core Types). To describe the physical or digital manifestation of the resource, use the FORMAT element.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Tumomo</Attribute>
+            <Attribute name="definition">Te ahua, te tu-ahuatanga ranei o nga kaupapa o te rauemi.</Attribute>
+            <Attribute name="comment">Kei roto i te Tumomo nga kupu whakaatu i nga wehewehenga whanui, nga aheinga, nga tu-ahuatanga, te whakaritenga ranei o nga taumata o te/ nga kaupapa. Ko te huarahi tino pai kua tohua, ko te tipako i tetahi uara mai i nga kupu kua whakaritea (hei tauira, ko te tauira rarangi e whakamahia ana o nga Dublin Core Types [DCT1]. Hei whakaatu i te whakatinanatanga o te rauemi, whakamahia ko te huanga WHAKATAKOTORANGA (FORMAT).</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Type</Attribute>
+            <Attribute name="definition">La nature ou le genre du contenu de la ressource.</Attribute>
+            <Attribute name="comment">Type inclut des termes dÃ©crivant des catÃ©gories, fonctions ou genres gÃ©nÃ©raux pour le contenu, ou des niveaux d&apos;agrÃ©gation. Il est recommandÃ© de choisir la valeur du type dans une liste de vocabulaire contrÃŽlÃ© (par exemple, la liste provisoire de Types du Dublin Core[DCT1]). Pour dÃ©crire la matÃ©rialisation physique ou digitale de la ressource, il faut utiliser l&apos;Ã©lÃ©ment Format.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">Ð¢ÐžÐ¿ ÑÐµÑÑÑÑÐ°</Attribute>
+            <Attribute name="definition">ÐÑÐžÑÐŸÐŽÐ° ÐžÐ»Ðž Ð¶Ð°ÐœÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">Ð¢ÐžÐ¿ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÑÐµÑÐŒÐžÐœÑ, ÐŸÐ¿ÐžÑÑÐ²Ð°ÑÑÐžÐµ ÐŸÐ±ÑÐžÐµ ÐºÐ°ÑÐµÐ³ÐŸÑÐžÐž, ÑÑÐœÐºÑÐžÐž, Ð¶Ð°ÐœÑÑ ÐžÐ»Ðž ÐŸÐ±ÑÐµÐŽÐžÐœÐµÐœÐœÑÐµ ÑÑÐŸÐ²ÐœÐž ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐ°Ð±ÐŸÑÐµÐ³ÐŸ Ð¿ÑÐŸÐµÐºÑÐ° ÑÐ¿ÐžÑÐºÐ° Ð¢ÐžÐ¿ÐŸÐ² Dublin Core DCT1). ÐÐ»Ñ ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ ÑÐžÐ·ÐžÑÐµÑ-ÐºÐŸÐ³ÐŸ ÐžÐ»Ðž ÑÐžÑÑÐŸÐ²ÐŸÐ³ÐŸ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÑÐµÑÑÑÑÐ° ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÑÐ»ÐµÐŒÐµÐœÑ Ð€ÐŸÑÐŒÐ°Ñ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Tipo del Recurso</Attribute>
+            <Attribute name="definition">La categorÃ­a del recurso, por ejemplo pÃ¡gina personal, romance, poema, minuta, diccionario. Para asegurar la interoperabilidad, Type deberÃ­a ser seleccionado de entre una lista de valores que actualmente se encuentra bajo desarrollo en un grupo de trabajo. En http://sunsite.berkeley.edu/Metadata/types.html se puede consultar el estado actual de la discusiÃ³n en torno a este tema.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">ÙÙØ¹ Ø§ÙÙ
+ØµØ¯Ø±</Attribute>
+            <Attribute name="definition">ÙÙ ÙØŠØ© Ø§ÙÙ
+ØµØ¯Ø± , Ù
+Ø«ÙØ§ Ø§ÙØµÙØ­Ø© Ø§ÙØ§Ù
+, Ø±ÙØ§ÙØ© , ÙØ·Ø¹Ø© ØŽØ¹Ø±ÙØ© , ÙØ±ÙØ© Ø¹Ù
+Ù , ØªÙØ±ÙØ± ÙÙÙ , Ù
+ÙØ§Ù , ÙØ§Ù
+ÙØ³ . Ù Ù
+Ù Ø£Ø¬Ù Ø§ÙØªØ¹Ø§Ù
+Ù Ø§ÙÙ
+ØŽØªØ±Ù    ÙØ¬Øš Ø£Ù ÙØ®ØªØ§Ø± Ø§ÙÙÙØ¹ Ù
+Ù Ø§ÙÙØ§ØŠÙ
+Ø© Ø§ÙÙ
+Ø±ÙÙ
+Ø© ÙØ§ÙØªÙ ÙÙÙ
+ Ø§Ø¹Ø¯Ø§Ø¯ÙØ§ Ø­Ø§ÙÙØ§ Ø¶Ù
+Ù Ø­ÙÙØ§Øª ÙØ±ØŽØ© Ø¹Ù
+Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">èµæºç±»å</Attribute>
+            <Attribute name="definition">èµæºå
+å®¹çç¹åŸæç±»åã</Attribute>
+            <Attribute name="comment">èµæºç±»åå
+æ¬æè¿°èµæºå
+å®¹çäžè¬èçŽïŒåèœïŒç§å±ïŒæèç±»å±æ¬¡çæ¯è¯­ãå»ºè®®éçšæ¥èªäºåæ§è¯è¡š    äž­çåŒïŒäŸåŠDCMIç±»åè¯æ±è¡š[DCMITYPE]ïŒãèŠæè¿°èµæºçç©çææ°å­åè¡šç°åœ¢åŒïŒè¯·äœ¿çšâæ ŒåŒïŒFORMATïŒâå
+çŽ ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Typ zdroje</Attribute>
+            <Attribute name="definition">Povaha nebo druh obsahu zdroje.</Attribute>
+            <Attribute name="comment">Typ obsahuje termÃ­ny popisujÃ­cÃ­ obecnÃ© kategorie, funkce, druhy nebo agregaÄnÃ­ ÃºrovnÄ obsahu. DoporuÄuje se vybÃ­rat hodnotu z ÅÃ­zenÃ©ho slovnÃ­ku (napÅ. pracovnÃ­ nÃ¡vrh seznamu TypÅ¯ Dublin Core [DCT1]). K popisu fyzickÃ© nebo digitÃ¡lnÃ­ reprezentace zdroje uÅŸijte prvek FormÃ¡t.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Bestands type</Attribute>
+            <Attribute name="definition">Het soort Internetbron, bijvoorbeeld home page, gedicht, working paper, technical report, essay, woordenboek etc. De DC working groups zijn momenteel bezig met twee voorstellen; een minimalist draft: http://sunsite.berkeley.edu/Metadata/minimalist.html en een structuralist draft: http://sunsite.berkely.edu/Metadata/structuralist.html. Het wordt sterk aanbevolen om &quot;Type&quot; van deze lijsten te selecteren.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Typo del ressource</Attribute>
+            <Attribute name="definition">Le natura o genere del contento del ressource.</Attribute>
+            <Attribute name="comment">Le typo del ressource include terminos que describe categorias general, functiones, generes, o nivellos de aggregation pro le contento. Le practica recommendate es selectionar un valor a partir de un vocabulario controlate (per exemplo, le lista de schizzos de travalio de typos de Dublin Core [DCT1]). Pro describer le manifestation physic o digital del ressource, utiliza le elemento Formato.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€ªà¥à€°à€à€Ÿà€°</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à€Ÿà€ªà¥à€°à€à€Ÿà€°</Attribute>
+            <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€µà€°à¥à€à¥à€à€°à€£, à€µà€°à¥à€à€µà€Ÿà€°à¥à€®à€§à¥à€¯à¥ à€à€à€Ÿà€Šà¥à€¯à€Ÿ à€šà¥à€à€Šà¥à€à€Ÿ à€®à¥à€à¥à€¯ à€à€à€ªà¥à€°à€à€Ÿà€°</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Format" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Format</Attribute>
+            <Attribute name="definition">The physical or digital manifestation of the resource.</Attribute>
+            <Attribute name="comment">Typically, Format may include the media-type or dimensions of the resource. Format may be used to determine the software, hardware or other equipment needed to display or operate the resource. Examples of dimensions include size and duration. Recommended best practice is to select a value from a controlled vocabulary (for example, the list of Internet Media Types [MIME] defining computer media formats).</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Whakatakotoranga</Attribute>
+            <Attribute name="definition">Te whakatinanatanga, te whakaputanga a-mati o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, ka taea te Whakatakotoranga te whakamahi hei whakarite i te rawa-ngohe (software), te rawa-maro (hardware), ma etahi taputapu ranei me matua whiwhi, hei whakahaere i te rauemi. Ko te rahi me te roanga etahi tauira hanga. Ko te tino huarahi kua tohua ko te tipako uara mai i tetahi whakaritenga kupu (hei tauira, te rarangi o nga Tumomo Papaho Ipurangi (Internet Media Types [MIME]) e whakaatu ana i nga whakatakotoranga papaho rorohiko.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Format</Attribute>
+            <Attribute name="definition">La matÃ©rialisation physique ou digitale de la ressource.</Attribute>
+            <Attribute name="comment">Typiquement, Format peut inclure le media ou les dimensions de la ressource. Format peut Ãªtre utilisÃ© pour prÃ©ciser le logiciel, le matÃ©riel ou autre Ã©quipement nÃ©cessaire pour afficher ou faire fonctionner la ressource. Exemples de dimensions incluent la taille et la durÃ©e. Il est recommandÃ© de choisir la valeur du format dans une liste de vocabulaire contrÃŽlÃ©(par exemple, la liste des types de media dÃ©finis sur Internet [MIME]).</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">Ð€ÐŸÑÐŒÐ°Ñ</Attribute>
+            <Attribute name="definition">Ð€ÐžÐ·ÐžÑÐµÑÐºÐŸÐµ ÐžÐ»Ðž ÑÐžÑÑÐŸÐ²ÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ Ð€ÐŸÑÐŒÐ°Ñ ÐŒÐŸÐ¶ÐµÑ Ð²ÐºÐ»ÑÑÐ°ÑÑ ÑÐžÐ¿ Ð°ÑÐŽÐžÐŸÐ²ÐžÐ·ÑÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž (ÐŒÐµÐŽÐžÐ°-ÑÐžÐ¿) ÐžÐ»Ðž Ð²ÐµÐ»ÐžÑÐžÐœÑ ÑÐµÑÑÑÑÐ°. Ð€ÐŸÑÐŒÐ°Ñ ÐŒÐŸÐ¶ÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ ÐŽÐ»Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ Ð°Ð¿Ð¿Ð°ÑÐ°ÑÐœÐŸÐ³ÐŸ, Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐ³ÐŸ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ ÐžÐ»Ðž ÐŽÑÑÐ³ÐŸÐ³ÐŸ ÐŸÐ±ÐŸÑÑÐŽÐŸÐ²Ð°ÐœÐžÑ, ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÐ³ÐŸ ÐŽÐ»Ñ Ð²ÐŸÑÐ¿ÑÐŸÐžÐ·Ð²ÐµÐŽÐµÐœÐžÑ ÐžÐ»Ðž ÑÐ°Ð±ÐŸÑÑ Ñ ÑÐµÑÑÑÑÐŸÐŒ. ÐÑÐžÐŒÐµÑÑ Ð²ÐµÐ»ÐžÑÐžÐœÑ Ð²ÐºÐ»ÑÑÐ°ÑÑ ÑÐ°Ð·ÐŒÐµÑ Ðž Ð¿ÑÐŸÐŽÐŸÐ»Ð¶ÐžÑÐµÐ»ÑÐœÐŸÑÑÑ. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐ¿ÐžÑÐºÐ° ÐÐµÐŽÐžÐ°-ÑÐžÐ¿ÐŸÐ² ÐÐœÑÐµÑÐœÐµÑ MIME, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÑÑÐµÐ³ÐŸ ÐºÐŸÐŒÐ¿ÑÑÑÐµÑÐœÑÐµ ÑÐŸÑÐŒÐ°ÑÑ Ð°ÑÐŽÐžÐŸÐ²ÐžÐ·ÑÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž).</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Formato</Attribute>
+            <Attribute name="definition">El formato de datos de un recurso, usado para identificar el software y posiblemente, el hardware que se necesitarÃ­a para mostrar el recurso. Para asegurar la interoperabilidad, los valores de Format deberÃ­an ser seleccionados de entre una lista de valores que actualmente se encuentra bajo desarrollo en un grupo de trabajo.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙØµÙØºØ©</Attribute>
+            <Attribute name="definition">ÙØ°Ù ØµÙØºØ© Ø§ÙÙ
+Ø¹ÙÙÙ
+Ø© Ø§ÙØ®Ø§ØµØ© ØšØ§ÙÙ
+ØµØ¯Ø± , Ù ØªØ³ØªØ®Ø¯Ù
+ ÙÙØªØ¹Ø±ÙÙ ØšØ§ÙØšØ±Ù
+Ø¬ÙØ§Øª ÙØ±ØšÙ
+Ø§ Ø§ÙØµÙØš ÙÙØ­Ø§Ø³ÙØš Ù Ø§ÙØªÙ ÙÙ
+ÙÙ Ø£Ù ÙØ­ØªØ§Ø¬    ÙÙØ§ ÙØ¹Ø±Ø¶ Ø£Ù ØªØŽØºÙÙ Ø§ÙÙ
+ØµØ¯Ø± . Ù
+Ù Ø£Ø¬Ù Ø§ÙØªØ¹Ø§Ù
+Ù Ø§ÙÙ
+ØŽØªØ±Ù, ÙØ¬Øš Ø£Ù ØªØ®ØªØ§Ø± Ø§ÙØµÙØºØ© Ù
+Ù Ø§ÙÙØ§ØŠÙ
+Ø© Ø§ÙÙ
+Ø±ÙÙ
+Ø© Ù Ø§ÙØªÙ ÙØªÙ
+ Ø§Ø¹Ø¯Ø§Ø¯ÙØ§    Ø­Ø§ÙÙØ§ Ø¶Ù
+Ù Ø­ÙÙØ§Øª ÙØ±ØŽØ© Ø¹Ù
+Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">æ ŒåŒ</Attribute>
+            <Attribute name="definition">èµæºçç©çææ°å­è¡šç°åœ¢åŒã</Attribute>
+            <Attribute name="comment">äžè¬èèšïŒæ ŒåŒå¯èœå
+æ¬èµæºçåªäœç±»åæèµæºçå€§å°ïŒæ ŒåŒå
+çŽ å¯ä»¥çšæ¥å³å®å±ç€ºææäœèµæºæé    çèœ¯ç¡¬ä»¶æå
+¶ä»çžåºè®Ÿå€ïŒäŸåŠå€§å°å
+æ¬èµæºæå çå­åšç©ºéŽåæç»­æ¶éŽãå»ºè®®éçšæ¥èªäºåæ§è¯è¡š    äž­çåŒïŒïŒäŸåŠInternetåªäœç±»å[MIME]å®ä¹è®¡ç®æºåªäœæ ŒåŒïŒã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">FormÃ¡t</Attribute>
+            <Attribute name="definition">FyzickÃ¡ nebo digitÃ¡lnÃ­ reprezentace zdroje.</Attribute>
+            <Attribute name="comment">Typicky mÅ¯ÅŸe FormÃ¡t obsahovat typ mÃ©dia nebo rozmÄry zdroje. FormÃ¡t lze pouÅŸÃ­vat k urÄenÃ­ softwaru, hardwaru nebo dalÅ¡Ã­ho zaÅÃ­zenÃ­ potÅebnÃ©ho k zobrazenÃ­ nebo k manipulaci se zdrojem. PÅÃ­klady rozmÄrÅ¯ zahrnujÃ­ velikost a dobu trvÃ¡nÃ­. DoporuÄuje se vybÃ­rat hodnotu z ÅÃ­zenÃ©ho slovnÃ­ku (napÅ. seznam typÅ¯ internetovÃœch mÃ©diÃ­ [MIME] definujÃ­cÃ­ formÃ¡ty poÄÃ­taÄovÃœch mÃ©diÃ­).</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Format</Attribute>
+            <Attribute name="definition">Het data formaat van het Internetbestand. Dit gegeven kan gebruikt worden om systeemvereisten (hard- en software) te identificeren die nodig zijn voor raadpleging of bediening van de Internetbron. &quot;Format&quot; is nog in ontwikkeling bij de DC workshop. Uit compatibiliteitsoverwegingen wordt aanbevolen formaatgegevens te selecteren uit een gecontroleerde lijst. Formaten kunnen van de Internet Media Types (MIME types) lijst gekozen worden: http://www.isi.edu/in-notes/iana/assignments/media-types/media-types</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Formato</Attribute>
+            <Attribute name="definition">Le manifestation physic o digital del ressource.</Attribute>
+            <Attribute name="comment">Typicamente le formato pote includer le typo de medio o dimensiones del ressource. Le formato pote esser utilizate pro determinar le software o le equipamento necessari pro exhibir o operar le ressource. Exemplos de dimensiones include grandessa e duration. Le practica recommendate es selectionar un valor de un vocabulario controlate (per exemplo, le lista de typos de medios de Internet [MIME] que defini formatos de medios).</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€°à€à€šà€Ÿ</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€°à€à€šà€Ÿ, à€šà€®à¥à€šà€Ÿà€¬à¥à€Š à€°à€à€šà€Ÿ</Attribute>
+            <Attribute name="comment">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€žà¥à€µà€°à¥à€ª, à€°à€à€šà€Ÿà€à€Šà€Ÿ. à€€à¥à€¯à€Ÿà€à¥ à€°à¥à€ª à€à€žà¥ à€ªà¥à€žà¥à€€à€à€°à¥à€ª, à€žà€à€à€£à€à¥à€¯ à€°à¥à€ª, à€µà€¿à€Šà¥à€¯à¥à€€ à€ªà€°à€®à€Ÿà€£à¥à€à€à¥à€¯à€Ÿ à€žà€¹à€Ÿà€¯à¥à€¯à€Ÿà€šà¥ à€žà€à€à€£à€à¥à€à¥à€€ à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="extent">
+            <Language code="en">
+                <Attribute name="identifier">Extent</Attribute>
+                <Attribute name="definition">The size or duration of the resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="medium">
+            <Language code="en">
+                <Attribute name="identifier">Medium</Attribute>
+                <Attribute name="definition">The material or physical carrier of the resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="status">recommended</Attribute>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+        </Element>
+    </Element>
+    <Element name="Identifier" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Resource Identifier</Attribute>
+            <Attribute name="definition">An unambiguous reference to the resource within a given context.</Attribute>
+            <Attribute name="comment">Recommended best practice is to identify the resource by means of a string or number conforming to a formal identification system. Example formal identification systems include the Uniform Resource Identifier (URI) (including the Uniform Resource Locator (URL)), the Digital Object Identifier (DOI) and the International Standard Book Number (ISBN).</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Taututanga</Attribute>
+            <Attribute name="definition">He tohutoro e hangai ana ki te rauemi i roto i tetahi horopaki.</Attribute>
+            <Attribute name="comment">Ko te tino huarahi kua tohua, ko te tautu i te rauemi ma tetahi aho (string), tau ranei, e hangai ana ki tetahi punaha taututanga okawa. Ko etahi punaha taututanga okawa ko te Taututanga Rauemi Orite (Uniform Resource Identifier - URI), te Taututanga Rauemi Tohu-wahi (Uniform Resource Locator - URL), Te Mea A-mati (Digital Object Identifier - DOI) me te Tau Pukapuka Aro Whanui o te Ao (International Standard Book Number - ISBN).</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Identifiant</Attribute>
+            <Attribute name="definition">Une rÃ©fÃ©rence non ambiguÃ« Ã  la ressource dans un contexte donnÃ©</Attribute>
+            <Attribute name="comment">Il est recommandÃ© d&apos;identifier la ressource par une chaÃ®ne de caractÃšre ou un nombre conforme Ã  un sytÃšme formel d&apos;identification. Exemples de systemes formels d&apos;identification incluent le &quot;Uniform Resource Identifier&quot; (URI) (qui inclut le &quot;Uniform Resource Locator&quot; (URL)), le &quot;Digital Object Identifier&quot;(DOI) et le &quot;International Standard Book Number&quot;(ISBN).</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ ÑÐµÑÑÑÑÐ°</Attribute>
+            <Attribute name="definition">ÐÐŽÐœÐŸÐ·ÐœÐ°ÑÐœÐ°Ñ ÑÑÑÐ»ÐºÐ° ÐœÐ° ÑÐµÑÑÑÑ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÐŽÐ°ÐœÐœÐŸÐ³ÐŸ ÐºÐŸÐœÑÐµÐºÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÑÑÑÑ Ð¿ÐŸÑÑÐµÐŽÑÑÐ²ÐŸÐŒ ÑÑÑÐŸÐºÐž ÐžÐ»Ðž ÑÐžÑÐ»Ð°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÐžÑÑÐµÐŒÐµ. ÐÑÐžÐŒÐµÑÑ ÑÐŸÑÐŒÐ°Ð»ÑÐœÑÑ
+ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÑÑ
+ ÑÐžÑÑÐµÐŒ Ð²ÐºÐ»ÑÑÐ°ÑÑ Ð£ÐœÐžÑÐžÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ Ð ÐµÑÑÑÑÐ° (URI), (Ð²ÐºÐ»ÑÑÐ°Ñ Ð£ÐœÐžÑÐžÑÐžÑÐŸÐ²Ð°ÐœÐœÑÑÐ¹ ÐÐŸÐºÐ°ÑÐŸÑ Ð ÐµÑÑÑÑÐ° URL), ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ ÐŠÐžÑÑÐŸÐ²ÐŸÐ³ÐŸ ÐÐ±ÑÐµÐºÑÐ° (DOI) Ðž ÐÐµÐ¶ÐŽÑÐœÐ°ÑÐŸÐŽÐœÑÐ¹ Ð¡ÑÐ°ÐœÐŽÐ°ÑÑÐœÑÐ¹ ÐÐœÐžÐ¶ÐœÑÐ¹ ÐÐŸÐŒÐµÑ (ISBN).</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Identificador del Recurso</Attribute>
+            <Attribute name="definition">Secuencia de caracteres usados para identificar unÃ­vocamente un recurso. Ejemplos para recursos en lÃ­nea pueden ser URLs y URNs (cuando estÃ©n implementados). Para otros recursos pueden ser usados otros formatos de identificadores, como por ejemplo ISBN (&quot;International Standard Book Number&quot; - NÃºmero Internacional Normalizado para Libros)</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ù
+Ø¹Ø±Ù Ø§ÙÙ
+ØµØ¯Ø±</Attribute>
+            <Attribute name="definition">ÙÙ Ù
+Ø¬Ù
+ÙØ¹Ø© Ø­Ø±ÙÙØ© Ø£Ù Ø±ÙÙ
+ ÙØ³ØªØ®Ø¯Ù
+ ÙØªØ¹Ø±ÙÙ Ø§ÙÙ
+ØµØ¯Ø± Ø§Ø­Ø¯ÙØ§ : Ø§ÙØ§Ù
+Ø«ÙØ© ÙØ°Ø§ÙÙ ÙÙ Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙØŽØšÙÙØ©ØªØ¶Ù
+ ) URNs, URLs Ø¹ÙØ¯ ØšÙØ§ØŠÙØ§ (    ÙØ°ÙÙ ÙÙ
+ÙÙ Ø§Ø¹ØªØšØ§Ø± Ø§ÙÙ
+Ø¹Ø±ÙØ§Øª Ø§ÙØ¹Ø§ÙÙ
+ÙØ© Ø§ÙØ§Ø­Ø§Ø¯ÙØ© Ù
+Ø«Ù Ø§ÙØ±ÙÙ
+ Ø§ÙØ¯ÙÙÙ ÙØªØµÙÙÙ Ø§ÙÙØ§ØªØš (ISBN) Ù
+Ø±ØŽØ­Ø© ÙÙØ°Ø§ Ø§ÙØ¹Ø§Ù
+Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">èµæºæ è¯ç¬Š</Attribute>
+            <Attribute name="definition">åšç¹å®çèåŽå
+ç»äºèµæºçäžäžªæç¡®çæ è¯ã</Attribute>
+            <Attribute name="comment">å»ºè®®å¯¹èµæºçæ è¯éçšç¬Šåæäžæ­£åŒæ è¯äœç³»çå­ç¬Šäž²åæ°å­ç»åãäŸåŠæ­£åŒçæ è¯äœç³»å
+æ¬ç»äžèµ    æºæ è¯ç¬Š(URI) (å
+æ¬åäžèµæºå®äœç¬ŠURL)ãæ°å­å¯¹è±¡æ è¯ç¬Š(DOI)ååœé
+æ åä¹Šå·(ISBN)ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">IdentifikÃ¡tor zdroje</Attribute>
+            <Attribute name="definition">JednoznaÄnÃœ odkaz na zdroj v rÃ¡mci danÃ©ho kontextu.</Attribute>
+            <Attribute name="comment">DoporuÄuje se identifikovat zdroj znakovÃœm ÅetÄzcem nebo ÄÃ­slem odpovÃ­dajÃ­cÃ­m nÄkterÃ©mu z formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯. PÅÃ­klady formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯ zahrnujÃ­ Uniform Resource Identifier (URI) (vÄetnÄ Uniform Resource Locator (URL)), Digital Object Identifier (DOI) a MezinÃ¡rodnÃ­ standardnÃ­ ÄÃ­slo knihy (ISBN).</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Bestandsidentificatie</Attribute>
+            <Attribute name="definition">Een unieke string of nummer ter identificatie van de Internetbron. Voorbeelden zijn URL&apos;s of URN&apos;s Andere voorbeelden zijn International Standard Book Number (ISBN) of International Standard Serial Number (ISSN)</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Identificator del ressource</Attribute>
+            <Attribute name="definition">Un referentia inambigue al ressource intra un date contexto.</Attribute>
+            <Attribute name="comment">Se recommenda identificar le ressource per medio de un catena de characteres o numero conforme a un systema formal de identification. Exemplos de systemas formal de identification include le Uniform Resource Identifier (URI) (includente le Uniform Resource Locator (URL)), le Digital Object Identifier (DOI) e le International Standard Book Number (ISBN).</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€à€³à€</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à€Ÿ à€à€ à€
+à€°à¥à€¥à¥ à€žà€à€Šà€°à¥à€­</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ. à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿà€³à¥à€¯à€Ÿà€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿ, à€µà€¿à€¶à€¿à€·à¥à€  à€žà¥à€¥à€³,  à€ªà¥à€žà¥à€€à€à€Ÿà€à€Ÿ à€à€à€€à€°à€°à€Ÿà€·à¥à€à¥à€°à¥à€¯  à€®à€Ÿà€šà€ à€à¥à€°à€®à€Ÿà€à€,  à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€à€³à€ à€ªà€à€µà€¿à€£à€Ÿà€°à€Ÿ à€à€à€à€°à€šà¥à€ à€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="bibliographicCitation">
+            <Attribute language="en" name="status">conforming</Attribute>
+            <Language code="en">
+                <Attribute name="identifier">Bibliographic Citation</Attribute>
+                <Attribute name="definition">A bibliographic reference for the resource. </Attribute>
+                <Attribute name="comment">Recommended practice is to include sufficient bibliographic detail to identify the resource as unambiguously as possible, whether or not the citation is in a standard form.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+        </Element>
+    </Element>
+    <Element name="Source" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Source</Attribute>
+            <Attribute name="definition">A Reference to a resource from which the present resource is derived.</Attribute>
+            <Attribute name="comment">The present resource may be derived from the Source resource in whole or in part.  Recommended best practice is to reference the resource by means of a string or number conforming to a formal identification system.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Matapuna</Attribute>
+            <Attribute name="definition">He tohutoro ki tetahi rauemi koira te matapuna o te rauemi e tirohia ana.</Attribute>
+            <Attribute name="comment">Tera pea i puta te katoa, tetahi wahanga ranei o te rauemi, e tirohia ana, mai i te Matapuna rauemi. Ko te tino huarahi kua tohua ko te tohutoro ki te rauemi ma te aho, ma te tau ranei e hangai ana ki tetahi punaha taututanga okawa.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Source</Attribute>
+            <Attribute name="definition">Une rÃ©fÃ©rence Ã  une ressource Ã  partir de laquelle la ressource actuelle a Ã©tÃ© dÃ©rivÃ©e.</Attribute>
+            <Attribute name="comment">La ressource actuelle peut avoir Ã©tÃ© dÃ©rivÃ©e d&apos;une autre ressource source, en totalitÃ© ou en partie. Il est recommandÃ© de refÃ©rencer cette source par une chaÃ®ne de caractÃšre ou un nombre conforme Ã  un systÃšme formel d&apos;identification.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÑÑÐŸÑÐœÐžÐº</Attribute>
+            <Attribute name="definition">Ð¡ÑÑÐ»ÐºÐ° ÐœÐ° ÑÐµÑÑÑÑ, ÐžÐ· ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ ÐžÐ·Ð²Ð»ÐµÑÐµÐœ ÐœÐ°ÑÑÐŸÑÑÐžÐ¹.</Attribute>
+            <Attribute name="comment">ÐÐ°ÑÑÐŸÑÑÐžÐ¹ ÑÐµÑÑÑÑ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐžÐ·Ð²Ð»ÐµÑÐµÐœ ÐžÐ· ÐÑÑÐŸÑÐœÐžÐºÐ° ÑÐµÐ»ÐžÐºÐŸÐŒ ÐžÐ»Ðž ÑÐ°ÑÑÐžÑÐœÐŸ. ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÑÑÑÑ Ð¿ÐŸÑÑÐµÐŽÑÑÐ²ÐŸÐŒ ÑÑÑÐŸÐºÐž ÐžÐ»Ðž ÑÐžÑÐ»Ð°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÐžÑÑÐµÐŒÐµ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Fuente</Attribute>
+            <Attribute name="definition">Secuencia de caracteres utilizado para identificar unÃ­vocamente un trabajo a partir del cual proviene el recurso actual. Por ejemplo, es posible usar Source con la fecha de 1603 como descripciÃ³n de una pelÃ­cula basada en una obra de Shakespeare, pero es preferible, en ese caso, usar Relation &quot;IsBasedOn&quot; con una referencia a un recurso distinto cuya descripciÃ³n contenga el elemento Date con valor 1603.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙ
+ØµØ¯Ø±</Attribute>
+            <Attribute name="definition">Ø§ÙÙ
+Ø¹ÙÙÙ
+Ø§Øª Ø§ÙØ®Ø§ØµØ© ØšÙ
+ØµØ¯Ø± Ø«Ø§ÙÙ Ù Ø§ÙØ°Ù Ø§Ø³ØªÙ
+Ø¯ Ù
+ÙÙ Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ. Ù
+Ø¹ Ø£ÙÙ Ù
+Ù Ø§ÙÙ
+ÙØµÙ ØšÙ Ø£Ù ØªÙØ¯Ù
+ Ø§ÙØ¹ÙØ§Ù
+Ù    Ù
+Ø¹ÙÙÙ
+Ø§Øª Ø¹Ù Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ ÙÙØ· , ÙÙÙ
+ÙÙ Ø£Ù ÙØ­ÙÙ ÙØ°Ø§ Ø§ÙØ¹Ø§Ù
+Ù Ø§ÙØªØ§Ø±ÙØ®, Ø§ÙÙ
+ÙØŽØŠ , Ø§ÙØµÙØºØ© , Ø§ÙÙ
+Ø¹Ø±Ù , Ø§Ù Ø§ÙØ© Ù
+ÙØ© - Ù
+Ø¹ÙÙÙ
+Ø§Øª Ø§Ø®Ø±Ù ÙÙÙ
+ØµØ¯Ø± Ø§ÙØ«Ø§ÙÙ Ø¹ÙØ¯Ù
+Ø§ ØªØ¹ØªØšØ± Ù
+ÙÙ
+Ø© ÙØ§ÙØªØŽØ§Ù Ø§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ , Ù ÙØ°Ø§ÙÙ ÙÙØµÙ Ø¹ÙØ¯ Ø§ÙØªØ·ØšÙÙÙÙ Ø§Ø­Ø³Ù     Ø§ÙÙ
+ØªØ¹Ø§Ø±Ù Ø¹ÙÙÙ ØšØ§Ø³ØªØ®Ø¯Ø§Ù
+ Ø¹Ø§Ù
+Ù Ø§ÙØ¹ÙØ§ÙØ©</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">æ¥æº</Attribute>
+            <Attribute name="definition">ç°æèµæºæ¥æºçåç
+§ã</Attribute>
+            <Attribute name="comment">åœåèµæºå¯èœéšåæå
+šéšæºèªè¯¥å
+çŽ ææ è¯çèµæºïŒå»ºè®®å¯¹è¿äžèµæºçæ è¯éçšäžäžªç¬Šåæ­£åŒæ è¯ç³»    ç»çå­äž²åæ°å­ç»å ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Zdroj</Attribute>
+            <Attribute name="definition">Odkaz na zdroj, z nÄhoÅŸ je popisovanÃœ zdroj odvozen.</Attribute>
+            <Attribute name="comment">PopisovanÃœ zdroj mÅ¯ÅŸe bÃœt zcela nebo zÄÃ¡sti odvozen ze zdroje uvedenÃ©ho v prvku Zdroj. DoporuÄuje se odkazovat zdroj znakovÃœm ÅetÄzcem nebo ÄÃ­slem odpovÃ­dajÃ­cÃ­m nÄkterÃ©mu z formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Bron</Attribute>
+            <Attribute name="definition">Informatie over een tweede bron waar de huidige Internetbron is van afgeleid. Bij &quot;Source&quot; mag een datum, auteur of maker, formaat, identificatie of andere metadata voor de tweede bron worden ingevuld. Voorbeeld: het is mogelijk om een &quot;Source&quot; datum 1603 in een omschrijving van een 1996 film bewerking van een Shakespeare stuk te gebruiken. &quot;Source&quot; is niet bruikbaar wanneer de huidige bron de orginele is.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Fonte</Attribute>
+            <Attribute name="definition">Un referentia a un ressource del qual se deriva le ressource presente.</Attribute>
+            <Attribute name="comment">Le ressource presente pote derivar se del ressource-fonte in toto o in parte. Le practica recommendate es facer referentia al ressource per medio de un catena de characteres o un numero conforme a un systema formal de identification.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€à€à€®</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿ à€à€à€® à€žà€Ÿà€à€à€£à€Ÿà€°à€Ÿ à€à€à€
+à€°à¥à€¥à¥ à€žà€à€Šà€°à¥à€­</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ. à€ªà¥à€žà¥à€€à€, à€®à€Ÿà€žà€¿à€,  à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿà€³à¥à€¯à€Ÿà€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿà€¯à€Ÿà€à€à€Ÿ à€žà€à€Šà€°à¥à€­</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Language" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Language</Attribute>
+            <Attribute name="definition">A language of the intellectual content of the resource.</Attribute>
+            <Attribute language="en" name="comment">Recommended best practice for the values of the Language element is defined by RFC 1766 which includes a two-letter Language Code (taken from the ISO 639 standard, followed optionally, by a two-letter Country Code (taken from the ISO 3166 standard). For example, &apos;en&apos; for English, &apos;fr&apos; for French, or &apos;en-uk&apos; for English used in the United Kingdom.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Reo</Attribute>
+            <Attribute name="definition">Te reo o te whakakaupapatanga o nga matauranga o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tino huarahi kua tohua mo nga uara o te huanga Reo kua whakaritea ki te RFC 1766 [RFC1766] kei roto te Tohu Reo kupu-rua (two-letter Language Code) (no te aro whanui ISO 639 [ISO639], ka taea e tetahi tohu kupu-rua te whai atu (no te aro whanui ISO 3166) [ISO366]). Hei tauira, te &apos;en&apos; mo te English, te &apos;fr&apos; mo te French, &apos;te en-uk&apos; mo te English e whakamahia ana i Ingarangi (UK).</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Langue</Attribute>
+            <Attribute name="definition">La langue du contenu intellectuel de la ressource.</Attribute>
+            <Attribute name="comment">Il est recommandÃ© d&apos;utiliser comme valeur de l&apos;Ã©lÃ©ment Langue celles definies par la RFC 1766 [RFC1766] qui comprend un code de langage Ã  deux caractÃšres(venant du standard ISO 639 [ISO639]), Ã©ventuellement suivi d&apos;un code Ã  deux lettres pour le pays (venant du standard ISO 3166 [ISO3166] ou en franÃ§ais [ISO3166]). Par exemple, &apos;en&apos; pour l&apos;anglais, &apos;fr&apos; pour le franÃ§ais, ou &apos;en-uk&apos; pour l&apos;anglais utilisÃ© au Royaume-Uni.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">Ð¯Ð·ÑÐº</Attribute>
+            <Attribute name="definition">Ð¯Ð·ÑÐº ÐžÐœÑÐµÐ»Ð»ÐµÐºÑÑÐ°Ð»ÑÐœÐŸÐ³ÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÐ»ÐµÐŒÐµÐœÑÐ° Ð¯Ð·ÑÐº, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÐŒÐŸÐµ RFC 1766 (Ð¢ÑÐ³Ðž ÐŽÐ»Ñ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐž ÑÐ·ÑÐºÐ°), Ð²ÐºÐ»ÑÑÐ°ÑÑÐžÐŒ ÐŽÐ²ÑÑ
+Ð±ÑÐºÐ²ÐµÐœÐœÑÐ¹ ÐºÐŸÐŽ ÑÐ·ÑÐºÐ° (Ð²Ð·ÑÑÑÐ¹ ÐžÐ· ÑÑÐ°ÐœÐŽÐ°ÑÑÐ° ISO 639 (ÐÐŸÐŽÑ ÐŽÐ»Ñ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ ÑÐ·ÑÐºÐŸÐ²)), Ð·Ð° ÐºÐŸÑÐŸÑÑÐŒ ÑÐ»ÐµÐŽÑÐµÑ (Ð¿ÑÐž ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸÑÑÐž) ÐŽÐ²ÑÑ
+Ð±ÑÐºÐ²ÐµÐœÐœÑÐ¹ ÐºÐŸÐŽ ÑÑÑÐ°ÐœÑ (Ð²Ð·ÑÑÑÐŒÐž ÐžÐ· ÑÑÐ°ÐœÐŽÐ°ÑÑÐ° ISO 3166 (ÐÐŸÐŽÑ ÐŽÐ»Ñ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ ÑÑÑÐ°Ðœ)). ÐÐ°Ð¿ÑÐžÐŒÐµÑ, &quot;en&quot; - ÐŽÐ»Ñ Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐŸÐ³ÐŸ, &quot;fr&quot; - ÐŽÐ»Ñ ÑÑÐ°ÐœÑÑÐ·ÑÐºÐŸÐ³ÐŸ, &quot;en-uk&quot; - ÐŽÐ»Ñ Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐŸÐ³ÐŸ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐŸÐ³ÐŸ Ð² ÐÐµÐ»ÐžÐºÐŸÐ±ÑÐžÑÐ°ÐœÐžÐž.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Lengua</Attribute>
+            <Attribute name="definition">Lengua/s del contenido intelectual del recurso. Practicamente el contenido de este campo deberÃ­a coincidir con los de la RFC 1766 (Tags para la identificaciÃ³n de lenguas, http://ds.internic.net/rfc/rfc1766.txt); por ejemplo: en, es, de, fi, ja y zh.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙÙØºØ©</Attribute>
+            <Attribute name="definition">ÙØ°Ù ÙÙ ÙØºØ© Ø§ÙÙ
+Ø­ØªÙÙ Ø§ÙÙÙØ±Ù ÙÙÙ
+ØµØ¯Ø± . ÙÙÙ
+Ø§ ÙØ§Ù  Ø¹Ù
+ÙÙØ§ , Ù
+Ø­ØªÙÙ ÙØžØ§ Ø§ÙØ­ÙÙ ÙØ¬Øš Ø£Ù ÙØªØ·Ø§ØšÙ Ù
+Ø¹ RFC 1766    ] Ø§ÙØ§Ù
+Ø«ÙØ© ØªØ¶Ù
+ th, ja, fr, es, fi, de, en Ù zh ÙØ±Ù
+ÙØ² ÙÙØªØ¹Ø±ÙÙ ØšØ§ÙÙØºØ© [</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">è¯­ç§</Attribute>
+            <Attribute name="definition">æè¿°èµæºç¥è¯å
+å®¹çè¯­ç§ã</Attribute>
+            <Attribute name="comment">å»ºè®®æ¬å
+çŽ çåŒéçšRFC 3066[RFC3066]ïŒè¯¥æ åäžISO 639 [ISO639]äžèµ·å®ä¹äºç±äž€äžªåäžäžªè±    æå­æ¯ç»æçäž»è¯­èšæ ç­Ÿåå­æ ç­ŸäŸåŠå
+æ¬âenâæâengâæ¥è¡šç€ºEnglish, &quot;akk&quot; æ¥è¡šç€º    &quot;en-GB&quot;è¡šç€ºè±åœè±è¯­ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Jazyk</Attribute>
+            <Attribute name="definition">Jazyk intelektuÃ¡lnÃ­ho obsahu zdroje.</Attribute>
+            <Attribute name="comment">DoporuÄenÃœ postup pro hodnoty prvku Jazyk je definovÃ¡n v RFC 1766 [RFC1766]: dvouznakovÃœ kÃ³d jazyka (pÅevzatÃœ z normy ISO 639 [ISO639]) volitelnÄ nÃ¡sledovanÃœ dvouznakovÃœm kÃ³dem zemÄ (pÅevzatÃœm z normy ISO 3166 [ISO3166]). NapÅÃ­klad &apos;en&apos; pro angliÄtinu, &apos;fr&apos; pro francouzÅ¡tinu, &apos;cs&apos; pro ÄeÅ¡tinu, nebo &apos;en-uk&apos; pro angliÄtinu uÅŸÃ­vanou ve SpojenÃ©m krÃ¡lovstvÃ­.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Taal</Attribute>
+            <Attribute name="definition">De taal waarin het document is beschreven. Voorgeschreven wordt de ISO639-1 norm, een twee karakter taalcode van de ISO 639(639-1 en 639-2) norm. Taalcodes kunnen van een lijst worden gekozen: http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt, Eventueel kan ISO3166 (landencodes) gebruikt worden om aan te geven in welk gebied de taal wordt gesproken. Deze kunnen ook van een lijst worden gekozen:  http://www.ics.uci.edu/pub/ietf/http/related/iso3166.txt.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Lingua</Attribute>
+            <Attribute name="definition">Le lingua del contento intellectual del ressource.</Attribute>
+            <Attribute name="comment">Le practica recommendate pro le valores del elemento lingua es definite per RFC 1766 [RFC1766], que include un codice de lingua de duo litteras (prendite del standard ISO 639 [ISO639]), sequite optionalmente per un codice de pais de duo litteras (prendite del standard ISO 3166 [ISO3166]). Per exemplo, &apos;ia&apos; pro interlingua, &apos;fr&apos; pro francese, o &apos;en-uk&apos; pro le anglese del Regno Unite.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€­à€Ÿà€·à€Ÿ</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€­à€Ÿà€·à€Ÿ</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ. à€®à€°à€Ÿà€ à¥ - à€­à€Ÿà€°à€€à¥à€¯ à€­à€Ÿà€·à€Ÿ</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="Relation" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Relation</Attribute>
+            <Attribute name="definition">A reference to a related resource.</Attribute>
+            <Attribute name="comment">Recommended best practice is to reference the resource by means of a string or number conforming to a formal identification system.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Whai Panga</Attribute>
+            <Attribute name="definition">He tohutoro ki tetahi rauemi whai panga.</Attribute>
+            <Attribute name="comment">Ko te tino huarahi kua tohua, ko te tohutoro ki te rauemi ma te aho, te tau ranei, e hangai ana ki te punaha taututanga okawa.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Relation</Attribute>
+            <Attribute name="definition">Une rÃ©fÃ©rence Ã  une autre ressource qui a un rapport avec cette ressource.</Attribute>
+            <Attribute name="comment">Il est recommandÃ© de rÃ©fÃ©rencer cette ressource par une chaÃ®ne de caractÃšres ou un numÃ©ro conforme Ã  un systÃšme formel d&apos;identification.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÑÐœÐŸÑÐµÐœÐžÐµ</Attribute>
+            <Attribute name="definition">ï¿œÐµÐœÐœÑÐ¹ ÑÐµÑÑÑÑ.</Attribute>
+            <Attribute name="comment">ÐÐ»Ñ Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÑÑÑÑ Ð¿ÐŸÑÑÐµÐŽÑÑÐ²ÐŸÐŒ ÑÑÑÐŸÐºÐž ÐžÐ»Ðž ÑÐžÑÐ»Ð°, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐ³ÐŸ ÑÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ ÑÐžÑÑÐµÐŒÐµ.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">RelaciÃ³n</Attribute>
+            <Attribute name="definition">Un identificador de un segundo recurso y su relaciÃ³n con el recurso actual. Este elemento permite enlazar los recursos relacionados y las descripciones de los recursos. Por ejemplo: IsVersionOf - Incluye la ediciÃ³n de un trabajo, IsBasedOn - La traducciÃ³n de un trabajo, IsPartOf - Un capÃ­tulo de un libro, IsFormatOf - Un mecanismo de transformaciÃ³n de un conjunto de datos en una imagen. Para asegurar la interoperabilidad, las relaciones deberÃ­an ser seleccionadas de una lista de elementos que actualmente se encuentra bajo desarrollo en un grupo de trabajo.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙØ¹ÙØ§ÙØ©</Attribute>
+            <Attribute name="definition">ÙØ°Ø§ Ù
+Ø¹Ø±Ù ÙÙÙ
+ØµØ¯Ø± Ø§ÙØ«Ø§ÙÙ Ù Ø¹ÙØ§ÙØªÙ ØšØ§ÙÙ
+ØµØ¯Ø± Ø§ÙØ­Ø§ÙÙ . ÙØ³Ù
+Ø­ ÙØ°Ø§ Ø§ÙØ¹Ø§Ù
+Ù ØšØªÙØ¶ÙØ­ Ø§ÙØ±ÙØ§ØšØ· ØšÙÙ Ø§ÙÙ
+ØµØ§Ø¯Ø± Ø§ÙÙ
+ØªØ¹ÙÙØ©     ØšØšØ¹Ø¶ÙØ§ Ù ØªÙØµÙÙ Ø§ÙÙ
+ØµØ¯Ø± . Ø§ÙØ§Ù
+Ø«ÙØ© ØªØ¶Ù
+ Ø·ØšØ¹Ø© Ø§ÙØ¹Ù
+Ù ) ÙØ³Ø®Ø© Ù
+Ù ( ØªØ±Ø¬Ù
+Ø© Ø¹Ù
+Ù ) Ø§Ø¹ØªÙ
+Ø§Ø¯Ø§ Ø¹ÙÙ ( ÙØµÙ Ù
+Ù ÙØªØ§Øš ) Ø¬Ø²Ø¡ Ù
+Ù (    Ù ØªØ­ÙÙÙÙ Ù
+ÙÙØ§ÙÙÙÙØ© ÙÙ
+Ø¬Ù
+ÙØ¹Ø© Ù
+Ø¹ÙÙÙ
+Ø§ØªÙØ© Ø§ÙÙ ØµÙØ±Ø© ) ØµÙØºØ© Ù
+Ù ( Ù
+Ù Ø£Ø¬Ù Ø§ÙØªØ¹Ø§Ù
+Ù Ø§ÙÙ
+ØŽØªØ±Ù , ÙØ¬Øš Ø§Ø®ØªÙØ§Ø± Ø§ÙØ¹ÙØ§ÙØ§Øª Ù
+Ù    Ø§ÙÙØ§ØŠÙ
+Ø© Ø§ÙÙ
+Ø±ÙÙ
+Ø© Ù Ø§ÙØªÙ ÙØªÙ
+ Ø§Ø¹Ø¯Ø§Ø¯ÙØ§ Ø­Ø§ÙÙØ§ Ø¶Ù
+Ù Ø­ÙÙØ§Øª ÙØ±ØŽØ© Ø¹Ù
+Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">å
+³è</Attribute>
+            <Attribute name="definition">æ¶åççžå
+³èµæºã</Attribute>
+            <Attribute name="comment">èåœçžå
+³èµæºæ¶ïŒå»ºè®®äœ¿çšç¬Šåæ­£åŒæ è¯ç³»ç»çå­ç¬Šäž²æè
+æ°å­ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">Vztah</Attribute>
+            <Attribute name="definition">Odkaz na pÅÃ­buznÃœ zdroj.</Attribute>
+            <Attribute name="comment">DoporuÄuje se odkazovat zdroj znakovÃœm ÅetÄzcem nebo ÄÃ­slem odpovÃ­dajÃ­cÃ­m nÄkterÃ©mu z formÃ¡lnÃ­ch identifikaÄnÃ­ch systÃ©mÅ¯.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Relatie</Attribute>
+            <Attribute name="definition">Een identificatie van een tweede bron en de relatie met de huide Internetbron. Voorbeelden zijn een editie van een werk (IsVersionOf), een vertaling van een werk (IsBasedOn), een hoofdstuk van een boek (IsPartOf) en een mechanische transformatie van een dataset in een plaatje (IsFormatOf). De DC Working Groups zijn bezig met een lijst met de meest verwachte relaties. Aanbevolen wordt om de relaties van deze lijst te gebruiken: http://purl.oclc.org/metadata/dublin_core/wrelationdraft.html.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="definition">Relation</Attribute>
+            <Attribute name="definition">Un referentia a un ressource correlate.</Attribute>
+            <Attribute name="comment">Le practica recommendate es facer referentia al ressource per medio de un catena de characteres o numero conforme a un systema de identification formal.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€šà€Ÿà€€à¥ , à€žà€à€¬à€à€§</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€¶à¥ à€žà€à€¬à€à€§ à€Šà€Ÿà€à€µà€£à€Ÿà€°à€Ÿ à€žà€à€Šà€°à¥à€­</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ.  à€®à€Ÿà€¹à€¿à€€à¥ à€à€Ÿà€³à¥à€¯à€Ÿà€µà€°à¥à€² à€ªà€€à¥à€€à€Ÿ(URL)</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="conformsTo">
+            <Language code="en">
+                <Attribute name="identifier">Conforms To</Attribute>
+                <Attribute name="definition">A reference to an established standard to which the resource conforms.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="hasFormat">
+            <Language code="en">
+                <Attribute name="identifier">Has Format</Attribute>
+                <Attribute name="definition">The described resource pre-existed the referenced resource, which is essentially the same intellectual content presented in another format.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="hasPart">
+            <Language code="en">
+                <Attribute name="identifier">Has Part</Attribute>
+                <Attribute name="definition">The described resource includes the referenced resource either physically or logically.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="hasVersion">
+            <Language code="en">
+                <Attribute name="identifier">Has Version</Attribute>
+                <Attribute name="definition">The described resource has a version, edition, or adaptation, namely, the referenced resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="isFormatOf">
+            <Language code="en">
+                <Attribute name="identifier">Is Format Of</Attribute>
+                <Attribute name="definition">The described resource is the same intellectual content of the referenced resource, but presented in another format.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="isPartOf">
+            <Language code="en">
+                <Attribute name="identifier">Is Part Of</Attribute>
+                <Attribute name="definition">The described resource is a physical or logical part of the referenced resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="isReferencedBy">
+            <Language code="en">
+                <Attribute name="identifier">Is Referenced By</Attribute>
+                <Attribute name="definition">The described resource is referenced, cited, or otherwise pointed to by the referenced resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="isReplacedBy">
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+            <Language code="en">
+                <Attribute name="identifier">Is Replaced By</Attribute>
+                <Attribute name="definition">The described resource is supplanted, displaced, or superseded by the referenced resource.</Attribute>
+            </Language>
+        </Element>
+        <Element name="isRequiredBy">
+            <Attribute language="en" name="status">recommended</Attribute>
+            <Language code="en">
+                <Attribute name="identifier">Is Required By</Attribute>
+                <Attribute name="definition">The described resource is required by the referenced resource, either physically or logically.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+        </Element>
+        <Element name="isVersionOf">
+            <Language code="en">
+                <Attribute name="identifier">Is Version Of</Attribute>
+                <Attribute name="definition">The described resource is a version, edition, or adaptation of the referenced resource. Changes in version imply substantive changes in content rather than differences in format.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="references">
+            <Language code="en">
+                <Attribute name="identifier">References</Attribute>
+                <Attribute name="definition">The described resource references, cites, or otherwise points to the referenced resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+        <Element name="replaces">
+            <Language code="en">
+                <Attribute name="status">recommended</Attribute>
+                <Attribute name="identifier">Replaces</Attribute>
+                <Attribute name="definition">The described resource supplants, displaces, or supersedes the referenced resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+        </Element>
+        <Element name="requires">
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Language code="en">
+                <Attribute name="identifier">Requires</Attribute>
+                <Attribute name="definition">The described resource requires the referenced resource to support its function, delivery, or coherence of content.</Attribute>
+            </Language>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+    </Element>
+    <Element name="Coverage" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Coverage</Attribute>
+            <Attribute name="definition">The extent or scope of the content of the resource.</Attribute>
+            <Attribute name="comment">Coverage will typically include spatial location (a place name or geographic coordinates), temporal period (a period label, date, or date range) or jurisdiction (such as a named administrative entity). Recommended best practice is to select a value from a controlled vocabulary (for example, the Thesaurus of Geographic Names [TGN]) and that, where appropriate, named places or time periods be used in preference to numeric identifiers such as sets of coordinates or date ranges.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Kapitanga</Attribute>
+            <Attribute name="definition">Te roanga, te whanuitanga ranei o te whakakaupapatanga o te rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, ka uru atu te wahi mokowa (te ingoa o tetahi wahi, whakapiritanga matawhenua ranei), whakaritenga wa (he tapatanga wa (period label, ra, whakatakotoranga whanui o nga ra), te whakaritenga ture (penei i te putahi whakahaere). Ko te tino huarahi kua tohua, ko te tipako uara mai i tetahi whakaritenga kupu (hei tauira, i tetahi Puna Kupu Ingoa Matawhenua (Geographic Names [TGN] i nga wahi tika, ko nga wahi me nga whakaritenga wa ka whakamahia i mua i te whakamahitanga o nga taututanga tau penei i nga huinga whakapiritanga me nga whakatakotoranga whanui o nga ra.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Couverture</Attribute>
+            <Attribute name="definition">La portÃ©e ou la couverture spatio-temporelle de la ressource.</Attribute>
+            <Attribute name="comment">La couverture typiquement inclut une position gÃ©ographique (le nom d&apos;un lieu ou ses coordonnÃ©es), une pÃ©riode de temps (un nom de pÃ©riode, une date, ou un intervalle de temps) ou une juridiction (telle que le nom d&apos;une entitÃ© administrative). Il est recommandÃ© de choisir la  valeur de Couverture dans un vocabulaire contrÃŽlÃ© (par exemple, un thÃ©saurus de noms gÃ©ographiques, comme[TGN]) et, quand cela est appropriÃ©, des noms de lieux ou de pÃ©riodes plutÃŽt que des identifiants numÃ©riques tels que des coordonnÃ©es ou des intervalles de dates. </Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÑ
+Ð²Ð°Ñ</Attribute>
+            <Attribute name="definition">ÐÑÐŸÑÑÐ¶ÐµÐœÐœÐŸÑÑÑ Ðž Ð³ÑÐ°ÐœÐžÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÑ
+Ð²Ð°Ñ ÐŸÐ±ÑÐºÐœÐŸÐ²ÐµÐœÐœÐŸ Ð²ÐºÐ»ÑÑÐ°ÐµÑ Ð¿ÑÐŸÑÑÑÐ°ÐœÑÑÐ²ÐµÐœÐœÐŸÐµ ÐŒÐµÑÑÐŸÐœÐ°Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÐµ (ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐŒÐµÑÑÐœÐŸÑÑÐž ÐžÐ»Ðž Ð³ÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÐµ ÐºÐŸÐŸÑÐŽÐžÐœÐ°ÑÑ), Ð²ÑÐµÐŒÐµÐœÐœÐŸÐ¹ Ð¿ÑÐŸÐŒÐµÐ¶ÑÑÐŸÐº (ÑÐºÐ°Ð·Ð°ÐœÐžÐµ Ð¿ÐµÑÐžÐŸÐŽÐ°, ÐŽÐ°ÑÐ° ÐžÐ»Ðž ÑÑÐŽ ÐŽÐ°Ñ) ÐžÐ»Ðž ÑÑÐžÑÐŽÐžÐºÑÐžÑ (ÑÐºÐ°Ð·Ð°ÐœÐžÐµ ÐµÐŽÐžÐœÐžÑÑ Ð°ÐŽÐŒÐžÐœÐžÑÑÑÐ°ÑÐžÐ²ÐœÐŸÐ³ÐŸ ÐŽÐµÐ»ÐµÐœÐžÑ). ÐÐ° Ð¿ÑÐ°ÐºÑÐžÐºÐµ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð²ÑÐ±ÐžÑÐ°ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐžÐ· ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÐŒÐŸÐ³ÐŸ ÑÐ»ÐŸÐ²Ð°ÑÑ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, Ð¢ÐµÐ·Ð°ÑÑÑÑÐ° Ð³ÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÑ
+ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ TGN), Ðž, ÐµÑÐ»Ðž ÑÑÐŸ ÑÐŒÐµÑÑÐœÐŸ, Ð¿ÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÐµ ÐŸÑÐŽÐ°ÐµÑÑÑ ÑÐºÐ°Ð·Ð°ÐœÐžÑÐŒ ÐŒÐµÑÑÐœÐŸÑÑÐµÐ¹ ÐžÐ»Ðž Ð²ÑÐµÐŒÐµÐœÐœÑÑ
+ Ð¿ÑÐŸÐŒÐµÐ¶ÑÑÐºÐŸÐ² Ð²ÐŒÐµÑÑÐŸ ÑÐžÑÑÐŸÐ²ÑÑ
+ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ², ÐºÐ°Ðº, ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐžÑÑÐµÐŒ ÐºÐŸÐŸÑÐŽÐžÐœÐ°Ñ ÐžÐ»Ðž Ð²ÑÐµÐŒÐµÐœÐœÑÑ
+ ÑÑÐŽÐŸÐ².</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Cobertura</Attribute>
+            <Attribute name="definition">La caracterÃ­stica de cobertura espacial y/o temporal del contenido intelectual del recurso. La cobertura espacial se refiere a una regiÃ³n fÃ­sica (por ejemplo, sector celestial); uso de coordenadas (por ejemplo, longitud y latitud) o nombres de lugares extraidos de una lista controlada. La cobertura temporal se refiere al contenido del recurso en vez de a cuando fue creado o puesto accesible ya que este Ãºltimo pertenece al elemento Date. Se usa el mismo formato basado en http://www.w3.org/TR/NOTE-datetime.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø§ÙØªØºØ·ÙØ©</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙØ®ØµØ§ØŠØµ Ø§ÙÙ
+ÙØ§ÙÙØ© Ø§Ù Ø§ÙØ²Ù
+ÙÙØ© ÙÙÙ
+Ø­ØªÙÙ Ø§ÙÙÙØ±Ù ÙÙÙ
+ØµØ¯Ø± . Ø§ÙØªØºØ·ÙØ© Ø§ÙÙ
+ÙØ§ÙÙØ© ØªØŽÙØ± Ø§ÙÙ Ø¬ÙØ© Ø·ØšÙØ¹ÙØ© )Ù
+Ø«Ù , ÙØ·Ø§Ø¹ Ø³Ù
+Ø§ÙÙ (    Ø§Ø³ØªØ®Ø¯Ø§Ù
+ Ø§ÙØ§Ø­Ø¯Ø§Ø«ÙØ§Øª ) Ù
+Ø«Ù  Ø®Ø· Ø§ÙØ·ÙÙ Ù Ø®Ø· Ø§ÙØ¹Ø±Ø¶ ( ÙÙ Ø£Ø³Ù
+Ø§Ø¡ Ø§Ù
+ÙÙØ© Ù
+Ø³ØªØ­ÙÙ
+Ø© Ø§Ù Ù
+ØªØ¬ÙØ§Øª ØšØ§ÙÙØ§Ù
+Ù . Ø§ÙØªØºØ·ÙØ© Ø§ÙØ²Ù
+ÙÙØ©    Ø«Ø¹ÙØ¯ Ø§ÙÙ Ù
+Ø§ ÙØ±Ø¬Ø¹ Ø§ÙÙÙ Ø§ÙÙ
+ØµØ¯Ø± Ù ÙÙØ³ Ø§Ù Ù
+ØªÙ ØªÙ
+ ØªÙÙÙØ±Ù ) Ø§ÙØ§Ø®ÙØ± ÙØªØ¹ÙÙ ØšØ¹Ø§Ù
+Ù Ø§ÙØªØ§Ø±ÙØ® ( Ø§Ø³ØªØ®Ø¯Ø§Ù
+ ÙÙØ³ ØµÙØºØ© Ø§ÙØªØ§Ø±ÙØ®  Ø§Ù Ø§ÙÙÙØª    ) Ø¹Ø§Ø¯Ø© Ù
+Ø¯Ù ] ( ØµÙØ§ØºØ§Øª Ø§ÙÙÙÙ
+ Ù Ø§ÙÙÙØª ) Ø§Ø¹ØªÙ
+Ø§Ø¯Ø§ Ø¹ÙÙ (ISO 8601 Ø§ÙÙ
+ÙØ§Ø­ØžØ© Ø§ÙÙÙÙØ© [http://www.w3.org/TR/NOTE-datetime, W3C    ÙÙ
+Ø§ ÙÙ Ù
+ÙØµÙ ØšÙ ÙØ¹Ø§Ù
+Ù Ø§ÙØªØ§Ø±ÙØ® Ø§Ù ÙØªØ±Ø§Øª Ø²Ù
+ÙÙØ© Ù
+Ù ÙØ§ØŠÙ
+Ø© Ù
+Ø³ØªØ­ÙÙ
+Ø© Ø§Ù Ù
+ØªØ¬ÙØ§Øª ØšØ§ÙÙØ§Ù
+Ù</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">èŠçèåŽ</Attribute>
+            <Attribute name="definition">èµæºå
+å®¹ææ¶åçå€å»¶äžèŠçèåŽ</Attribute>
+            <Attribute name="comment">èŠçèåŽäžè¬å
+æ¬ç©ºéŽäœçœ®ïŒäžäžªå°åæå°çåæ ïŒãæ¶éŽåºéŽïŒäžäžªæ¶éŽæ è¯ïŒæ¥ææäžäžªæ¥æè    åŽïŒãæè
+æéïŒæ¯åŠåœåçææå®äœïŒæšèèŠçèåŽæå¥œæ¯åèªäºäžäžªåæ§è¯è¡šïŒäŸåŠå°åè¯åº    [TGN]ïŒïŒå¹¶åºå°œå¯èœå°äœ¿çšç±æ°å­è¡šç€ºçåæ ææ¥æåºéŽæ¥æè¿°å°åäžæ¶éŽæ®µã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">PokrytÃ­</Attribute>
+            <Attribute name="definition">Rozsah nebo zÃ¡bÄr obsahu zdroje.</Attribute>
+            <Attribute name="comment">PokrytÃ­ bude typicky obsahovat prostorovÃ© umÃ­stÄnÃ­ (jmÃ©no mÃ­sta nebo zemÄpisnÃ© souÅadnice), ÄasovÃ© obdobÃ­ (oznaÄenÃ­ obdobÃ­, datum nebo ÄasovÃœ interval) nebo jurisdikci (napÅ. jmÃ©no administrativnÃ­ jednotky). DoporuÄuje se vybÃ­rat hodnotu z ÅÃ­zenÃ©ho slovnÃ­ku (napÅ. Thesaurus of Geographic Names [TGN]) a tam, kde je to vhodnÃ©, uvÃ¡dÄt mÃ­sta nebo ÄasovÃ© Ãºseky spÃ­Å¡e jmÃ©nem neÅŸ ÄÃ­selnÃœmi identifikÃ¡tory jako jsou soubory souÅadnic nebo ÄasovÃ© intervaly.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Dekking</Attribute>
+            <Attribute name="definition">De ruimtelijke of tijdelijke karakteristieken van de intellectuele inhoud van de Internetbron. Ruimtelijke dekking verwijst naar een geografisch gebied. Gebruik coordinaten (longitude (lengtegraad) en latitude (breedtegraad)) of plaatsnamen die van een gecontroleerde lijst komen of volledig uitgeschreven zijn. Dekking in de tijd geeft de tijdsperiode aan waarop de inhoud van de Internetbron betrekking heeft en niet wanneer de Internetbron is gemaakt of beschikbaar is gesteld (dit laatste hoort ingevult te worden bij &quot;Date&quot;). Gebruik dezelfde datum/tijd formaat als bij &quot;Date&quot;; W3C Technical Note http://www.w3.org/TR/NOTE-datetime of tijdsperioden die van een gecontroleerde lijst komen of volledig uitgeschreven zijn. Coverage is in ontwikkeling bij de Dublin Core Working group http://www.alexandria.ucsb.edu/docs/metadata/dc_coverage.html.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Copertura</Attribute>
+            <Attribute name="definition">Le extension physic o abstracte del contento del ressource.</Attribute>
+            <Attribute name="comment">Le copertura typicamente include un location spatial (un nomine de localitate o coordinatas geographic), un periodo de tempore (un etiquetta de periodo, data, o gamma de datas), o un jurisdiction (tal como un entitate administrative nominate). Le practica recommendate es selectionar un valor a partir de un vocabulario controlate (per exemplo, le Thesaurus of Geographical Names [TGN]) e que, quando appropriate, localitates o periodos de tempore nominate sia utilizate in preferentia a identificatores numeric tales como collectiones de coordinatas o gammas de datas.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€µà¥à€¯à€Ÿà€ªà¥à€€à¥</Attribute>
+            <Attribute name="definition">à€®à€Ÿà€¹à€¿à€€à¥à€žà€Ÿà€ à¥à€¯à€Ÿà€à¥ à€­à¥à€à¥à€²à€¿à€  à€®à€Ÿà€¹à€¿à€€à¥</Attribute>
+            <Attribute name="comment">à€à€Šà€Ÿ. à€­à¥à€à¥à€²à€¿à€ à€µà¥à€¯à€Ÿà€ªà¥à€€à¥</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="spatial">
+            <Attribute language="en" name="status">recommended</Attribute>
+            <Language code="en">
+                <Attribute name="identifier">Spatial</Attribute>
+                <Attribute name="definition">Spatial characteristics of the intellectual content of the resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+        </Element>
+        <Element name="temporal">
+            <Language code="en">
+                <Attribute name="identifier">Temporal</Attribute>
+                <Attribute name="definition">Temporal characteristics of the intellectual content of the resource.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+    </Element>
+    <Element name="Rights" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Rights Management</Attribute>
+            <Attribute name="definition">Information about rights held in and over the resource.</Attribute>
+            <Attribute name="comment">Typically, a Rights element will contain a rights management statement for the resource, or reference a service providing such information. Rights information often encompasses Intellectual Property Rights (IPR), Copyright, and various Property Rights. If the Rights element is absent, no assumptions can be made about the status of these and other rights with respect to the resource.</Attribute>
+        </Language>
+        <!-- Maori -->
+        <Language code="mi">
+            <Attribute name="identifier">Motika</Attribute>
+            <Attribute name="definition">Ko nga mohiohio ki nga motika o tetahi rauemi.</Attribute>
+            <Attribute name="comment">Ko te tikanga, kei te huanga Motika e pupuri ana he korero mo te whakaritenga motika mo te rauemi, he ratonga tohutoro e whakarato ana ranei i enei tumomo mohiohio. He nui nga wa, puta ai i roto i te mohiohio Motika te Mana Whakairo Hinegaro (Intellectual Property Rights - (IPR)), te Manatarua me nga Tuahua Mana Taonga (Property Rights). Ki te kore te huanga Motika, kaore e taea te pohehe noa ki te mana o enei, nga motika ranei e pa ana ki te rauemi.</Attribute>
+        </Language>
+        <!-- French -->
+        <Language code="fr">
+            <Attribute name="identifier">Droits</Attribute>
+            <Attribute name="definition">Information sur les droits sur et au sujet de la ressource.</Attribute>
+            <Attribute name="comment">Typiquement, un Ã©lÃ©ment Droits contiendra un Ã©tat du droit Ã  gÃ©rer une ressource, ou la refÃ©rence Ã  un service fournissant cette information. Ces droits souvent couvrent les droits de propriÃ©tÃ© intellectuelle (IPR), Copyright, et divers droits de propriÃ©tÃ©. Si l&apos;Ã©lÃ©ment Droits est absent, aucune hypothÃšse ne peut Ãªtre faite sur l&apos;Ã©tat de ces droits, ou de tout autre, par rapport Ã  la ressource.</Attribute>
+        </Language>
+        <!-- Russian -->
+        <Language code="ru">
+            <Attribute name="identifier">ÐÑÐ°Ð²ÐŸÐ²ÐŸÐµ ÑÐµÐ³ÑÐ»ÐžÑÐŸÐ²Ð°ÐœÐžÐµ</Attribute>
+            <Attribute name="definition">ÐÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ Ð¿ÑÐ°Ð²Ð°Ñ
+ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐ°ÑÑÑ Ð²ÐœÑÑÑÐž Ðž Ð²ÐœÐµ ÑÐµÑÑÑÑÐ°.</Attribute>
+            <Attribute name="comment">ÐÐ±ÑÑÐœÐŸ ÑÐ»ÐµÐŒÐµÐœÑ ÐÑÐ°Ð²Ð° ÑÐŸÐŽÐµÑÐ¶ÐžÑ Ð¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐžÐµ ÐŸ Ð¿ÑÐ°Ð²ÐŸÐ²ÑÑ
+ ÐœÐŸÑÐŒÐ°Ñ
+, ÑÐµÐ³ÑÐ»ÐžÑÑÑÑÐžÑ
+ ÑÑÐœÐºÑÐžÐŸÐœÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÑÐµÑÑÑÑÐ° ÐžÐ»Ðž ÑÑÑÐ»ÐºÑ ÐœÐ° ÑÐ»ÑÐ¶Ð±Ñ, Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÑÑÑÑ ÑÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ. ÐÑÐ°Ð²ÐŸÐ²Ð°Ñ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸÐ±ÑÑÐœÐŸ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÑÐ²ÐµÐŽÐµÐœÐžÑ ÐŸ ÐÑÐ°Ð²Ð°Ñ
+ ÐžÐœÑÐµÐ»Ð»ÐµÐºÑÑÐ°Ð»ÑÐœÐŸÐ¹ ÑÐŸÐ±ÑÑÐ²ÐµÐœÐœÐŸÑÑÐž, ÐÐ²ÑÐŸÑÑÐºÐŸÐŒ Ð¿ÑÐ°Ð²Ðµ Ðž ÐŽÑÑÐ³ÐžÑ
+ ÐÐŒÑÑÐµÑÑÐ²ÐµÐœÐœÑÑ
+ Ð¿ÑÐ°Ð²Ð°Ñ
+. ÐÑÑÑÑÑÑÐ²ÐžÐµ ÑÐ»ÐµÐŒÐµÐœÑÐ° ÐÑÐ°Ð²Ð° ÐœÐµ ÐŒÐŸÐ¶ÐµÑ ÑÐ²Ð»ÑÑÑÑÑ ÐŸÑÐœÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐŽÐ»Ñ ÐºÐ°ÐºÐžÑ
+-Ð»ÐžÐ±ÐŸ Ð¿ÑÐµÐŽÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐžÐ¹ ÐŸ Ð¿ÑÐ°Ð²ÐŸÐ²ÐŸÐŒ ÑÑÐ°ÑÑÑÐµ Ðž ÐŽÑÑÐ³ÐžÑ
+ Ð¿ÑÐ°Ð²Ð°Ñ
+, ÐºÐ°ÑÐ°ÑÑÐžÑ
+ÑÑ ÑÐµÑÑÑÑÐ°.</Attribute>
+        </Language>
+        <!-- Spanish -->
+        <Language code="es">
+            <Attribute name="identifier">Derechos</Attribute>
+            <Attribute name="definition">Una referencia (URL, por ejemplo) para una nota sobre derechos de autor, para un servicio de gestiÃ³n de derechos o para un servicio que darÃ¡ informaciÃ³n sobre tÃ©rminos y condiciones de acceso a un recurso. Una especificaciÃ³n formal del elemento Rights se encuentra catualmente en discusiÃ³n y por lo tanto su uso se considera experimental.</Attribute>
+        </Language>
+        <!-- Arabic -->
+        <Language code="ar">
+            <Attribute name="identifier">Ø­ÙÙÙ Ø§ÙØ§Ø¯Ø§Ø±Ø©</Attribute>
+            <Attribute name="definition">ÙÙ Ø§ÙØ§Ø¯Ø© Ø­ÙÙÙ Ø§ÙØ§Ø¯Ø§Ø±Ø© , Ù
+Ø¹Ø±Ù Ù
+Ø±ØªØšØ· ØšØ§ÙØ§Ø¯Ø© Ø­ÙÙÙ Ø§ ÙØ§Ø¯Ø§Ø±Ø© , Ù
+Ø¹Ø±Ù Ù
+Ø±ØªØšØ· ØšØ®Ø¯Ù
+Ø© ØªÙØ¯Ù
+ Ù
+Ø¹ÙÙÙ
+Ø§Øª Ø¹Ù Ø­ÙÙÙ Ø§ÙØ§Ø¯Ø§Ø±Ø© Ø§ÙØ®Ø§ØµØ© ØšØ§ÙÙ
+ØµØ¯Ø±</Attribute>
+        </Language>
+        <!-- Chinese - Simplified -->
+        <Language code="cn">
+            <Attribute name="identifier">æé</Attribute>
+            <Attribute name="definition">æå
+³èµæºæ¬èº«ææçæè¢«èµäºçæéä¿¡æ¯</Attribute>
+            <Attribute name="comment">äžè¬èèšïŒæéå
+çŽ åºå
+æ¬äžäžªå¯¹èµæºçæéå£°æïŒæè
+æ¯å¯¹æäŸè¿äžä¿¡æ¯çæå¡çåç
+§ãæéäžè¬    å
+æ¬ç¥è¯äº§æ(IPR)ïŒçææå
+¶ä»åç§åæ ·çäº§æãåŠææ²¡ææéå
+çŽ çæ æ³šïŒäžå¯ä»¥å¯¹äžèµæºçžå
+³    çäžè¿°æå
+¶ä»æå©çæ
+åµäœåºä»»äœåå®ã</Attribute>
+        </Language>
+        <!-- Czech -->
+        <Language code="cs">
+            <Attribute name="identifier">PrÃ¡va</Attribute>
+            <Attribute name="definition">Informace o prÃ¡vech vztahujÃ­cÃ­ch se k popisovanÃ©mu zdroji.</Attribute>
+            <Attribute name="comment">Prvek PrÃ¡va bude typicky obsahovat ustanovenÃ­ o sprÃ¡vÄ autorskÃœch/vlastnickÃœch prÃ¡v ke zdroji nebo odkaz na sluÅŸbu poskytujÃ­cÃ­ takovÃ©to informace. Informace o prÃ¡vech Äasto zahrnujÃ­ prÃ¡va duÅ¡evnÃ­ho vlastnictvÃ­ (IPR), autorskÃ© prÃ¡vo a rÅ¯znÃ¡ vlastnickÃ¡ prÃ¡va. JestliÅŸe prvek PrÃ¡va chybÃ­, nelze odvozovat ÅŸÃ¡dnÃ© pÅedpoklady o stavu tÄchto a jinÃœch prÃ¡v vztahujÃ­cÃ­ch se k popisovanÃ©mu zdroji.</Attribute>
+        </Language>
+        <!-- Dutch -->
+        <Language code="nl">
+            <Attribute name="identifier">Copyright</Attribute>
+            <Attribute name="definition">Een copyright verklaring of een link naar een copyright verklaring of een link naar een service die informatie geeft over de copyright van de Internetbron.</Attribute>
+        </Language>
+        <!-- Finnish -->
+        <Language code="fi">
+            <Attribute name="identifier"/>
+            <Attribute name="definition"/>
+            <Attribute name="comment"/>
+        </Language>
+        <!-- Interlingua -->
+        <Language code="ia">
+            <Attribute name="identifier">Gestion de derectos</Attribute>
+            <Attribute name="definition">Information super derectos detenite super e a proposito del ressource.</Attribute>
+            <Attribute name="comment">Typicamente le elemento derectos continera un declaration de gestion de derectos pro le ressource, o un referentia a un servicio que provide tal information. Information de derectos frequentemente involve derectos de proprietate intellectual (IPR), copyright e varie derectos de proprietate. Si le elemento Derectos es absente, necun hypothese pote esser facite quanto al stato de iste e altere derectos concernente ressource.</Attribute>
+        </Language>
+        <!-- Marathi -->
+        <Language code="mr">
+            <Attribute name="identifier">à€¹à€à¥à€</Attribute>
+            <Attribute name="definition">à€¬à¥à€§à¥à€Šà€¿à€ à€žà€à€ªà€Šà¥à€à€Ÿà€¹à€à¥à€</Attribute>
+            <Attribute name="comment">à€žà¥à€µà€€à€à€¹à€Ÿà€à¥ à€²à¥à€à€š à€à€Ÿà€ªà¥à€š à€
+à€¥à€µà€Ÿ à€®à€Ÿà€¹à€¿à€€à¥à€à€Ÿà€³à¥à€¯à€Ÿà€µà€° à€ªà¥à€°à€à€Ÿà€¶à€¿à€€ à€à€°à€£à¥à€¯à€Ÿà€à€Ÿ à€²à¥à€à€ à€
+à€¥à€µà€Ÿ à€²à¥à€à€¿à€à¥à€à€Ÿ à€¬à¥à€§à¥à€Šà€¿à€ à€žà€à€ªà€Šà¥à€à€Ÿà€¹à€à¥à€</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.1</Attribute>
+        <Attribute language="en" name="registration_authority">Dublin Core Metadata Initiative</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Charater String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+        <Element name="accessRights">
+            <Language code="en">
+                <Attribute name="identifier">Access Rights</Attribute>
+                <Attribute name="definition">Information about who can access the resource or an indication of its security status.</Attribute>
+                <Attribute name="comment">Access Rights may include information regarding access or restrictions based on privacy, security or other regulations.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">conforming</Attribute>
+        </Element>
+        <Element name="license">
+            <Language code="en">
+                <Attribute name="identifier">License</Attribute>
+                <Attribute name="definition">A legal document giving official permission to do something with the resource.</Attribute>
+                <Attribute name="comment">Recommended best practice is to identify the license using a URI. Examples of such licenses can be found at http://creativecommons.org/licenses/.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">conforming</Attribute>
+        </Element>
+    </Element>
+    <Element name="Audience">
+        <Language code="en">
+            <Attribute name="identifier">Audience</Attribute>
+            <Attribute name="definition">A class of entity for whom the resource is intended or useful.</Attribute>
+            <Attribute name="comment">A class of entity may be determined by the creator or the publisher or by a third party.</Attribute>
+        </Language>
+        <Element name="educationLevel">
+            <Language code="en">
+                <Attribute name="identifier">Audience Education Level</Attribute>
+                <Attribute name="definition">A general statement describing the education or training context. Alternatively, a more specific statement of the location of the audience in terms of its progression through an education or training context.</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">conforming</Attribute>
+        </Element>
+        <Element name="mediator">
+            <Language code="en">
+                <Attribute name="definition">A class of entity that mediates access to the resource and for whom the resource is intended or useful.</Attribute>
+                <Attribute name="comment">The audiences for a resource are of two basic classes: (1) an ultimate beneficiary of the resource, and (2) frequently, an entity that mediates access to the resource. The mediator element refinement represents the second of these two classes.</Attribute>
+                <Attribute name="identifier">Mediator</Attribute>
+            </Language>
+            <Attribute language="en" name="type">element-refinement</Attribute>
+            <Attribute language="en" name="status">recommended</Attribute>
+        </Element>
+    </Element>
+    <Element name="Provenance">
+        <Language code="en">
+            <Attribute name="identifier">Provenance</Attribute>
+            <Attribute name="definition">A statement of any changes in ownership and custody of the resource since its creation that are significant for its authenticity, integrity and interpretation.</Attribute>
+            <Attribute name="comment">The statement may include a description of any changes successive custodians made to the resource.</Attribute>
+        </Language>
+    </Element>
+    <Element name="RightsHolder">
+        <Language code="en">
+            <Attribute name="definition">A person or organization owning or managing rights over the resource.</Attribute>
+            <Attribute name="comment">Recommended best practice is to use the URI or name of the Rights Holder to indicate the entity.</Attribute>
+            <Attribute name="identifier">Rights Holder</Attribute>
+        </Language>
+        <Attribute language="en" name="status">conforming</Attribute>
+    </Element>
+</MetadataSet>
Index: /tags/gsdl-2_61-distribution/gli/metadata/rfc1807.mds
===================================================================
--- /tags/gsdl-2_61-distribution/gli/metadata/rfc1807.mds	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/metadata/rfc1807.mds	(revision 10506)
@@ -0,0 +1,462 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param family      The name of this sets family.                                 -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param namespace   The namespace of this metadata set.                           -->
+  <!ELEMENT MetadataSet ((Name|Description|SetLanguage|Element)+)>
+  <!ATTLIST MetadataSet
+	    contact            CDATA #REQUIRED
+	    creator            CDATA #REQUIRED
+	    description        CDATA #REQUIRED
+            family             CDATA #REQUIRED
+	    lastchanged        CDATA #REQUIRED
+            name               CDATA #REQUIRED
+	    namespace          CDATA #REQUIRED
+	    language_dependent CDATA "">
+
+  <!-- The name of a metadata set. Is language specific. -->
+  <!ELEMENT Name (#PCDATA)>
+  <!ATTLIST Name
+            language CDATA "en">
+
+  <!-- The description of a metadata set. Is language specific. -->
+  <!ELEMENT Description (#PCDATA)>
+  <!ATTLIST Description
+            language CDATA "en">
+
+  <!-- When used in conjuction with defer-node-expansion, allows for better memory use when dealing with several or more languages. -->
+  <!ELEMENT SetLanguage (Name, Description?)>
+  <!ATTLIST Language
+	    code CDATA #REQUIRED>
+
+  <!-- An element in the metadata set. -->
+  <!-- Note that the name attribute isn't really Dublin Core compliant - it was just the first thing I came up with. -->
+  <!ELEMENT Element (Attribute*,Language*,OptionList?)>
+  <!ATTLIST Element
+            name       CDATA #REQUIRED
+	    occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->	
+  <!-- Given that name was already used for an Element, I decided to use identifier for the language specific 'name', which I've been told isn't really compliant with Dublin Core. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA "">
+
+  <!-- When used in conjuction with defer-node-expansion, allows for better memory use when dealing with several or more languages. -->
+  <!ELEMENT Language (Attribute*)>
+  <!ATTLIST Language
+	    code CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+]>
+<MetadataSet contact="rlasher@forsythe.stanford.edu" creator="The Internet Engineering Task Force" family="RFC 1807" language_dependent="identifier, definition, comment" lastchanged="Fri Dec 3 14:10 NZST 2004 - mgw5 on narya" namespace="rfc1807">
+    <SetLanguage code="en">
+        <Name language="en">RFC 1807 Metadata Element Set, Version TR-v2.1</Name>
+        <Description language="en">    This document is the reference description for Internet Engineering Task Force (IETF) Request for Comments (RFC) 1807 metadata standard for bibliographic records, expressed as a metadata set for Greenstone.  </Description>
+    </SetLanguage>
+    <Element name="bib-version" occurances="1" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Bib-version</Attribute>
+            <Attribute name="definition">The format version of RFC-1807 record.</Attribute>
+            <Attribute name="comment">This is the first field of any record. It is a mandatory field. It identifies the version of the format used to create this bibliographic record. This RFC defines BIB-Version TR-v2.1 BIB-VERSIONs that start with the letter X (case independent) are considered experimental. Bib-records sent with such a BIB-VERSION should NOT be incorporated in the permanent database of the recipient. Using this version of this format, this field is always: Format: BIB-VERSION:: CS-TR-v2.1  </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Compulsory</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="minimum_occurance">1</Attribute>
+        <Attribute name="maximum_occurance">1</Attribute>
+    </Element>
+    <Element name="id" occurances="1" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Id</Attribute>
+            <Attribute name="definition">The identifier for the RFC-1807 record.</Attribute>
+            <Attribute name="comment">This is the second field of any record. It is also a mandatory field. The ID field identifies the bibliographic record and is used in management of these records. Its format is &quot;ID:: XXX//YYY&quot;, where XXX is the publisher-ID (the controlled symbol of the publisher) and YYY is the ID (e.g., report number) of the publication as assigned by the publisher. This ID is typically printed on the cover, and may contain slashes. The organization symbols &quot;DUMMY&quot; and &quot;TEST&quot; (case independent) are reserved for test records that should NOT be incorporated in the permanent database of the recipients. Format: ID:: &lt;publisher-ID&gt;//&lt;free-text&gt; Example: ID:: OUKS//CS-TR-91-123 </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Compulsory</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="minimum_occurance">1</Attribute>
+        <Attribute name="maximum_occurance">1</Attribute>
+    </Element>
+    <Element name="entry" occurances="1" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Entry</Attribute>
+            <Attribute name="definition">The date RFC-1807 record was created.</Attribute>
+            <Attribute name="comment">This is a mandatory field. It is the date of creating this bibliographic record. The format for ENTRY date is &quot;Month Day, Year&quot;. The month must be alphabetic (spelled out). The &quot;Day&quot; is a 1- or 2-digit number. The &quot;Year&quot; is a 4-digit number. Format: ENTRY:: &lt;date&gt; Example: ENTRY:: January 15, 1992 </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Compulsory</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="minimum_occurance">1</Attribute>
+        <Attribute name="maximum_occurance">1</Attribute>
+    </Element>
+    <Element name="organization" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Organization</Attribute>
+            <Attribute name="definition">The full name of the publishing organization</Attribute>
+            <Attribute name="comment">It is the full name spelled out (no acronyms, please) of the publishing organization. The use of this name is controlled together with the controlled symbol of the publisher (as discussed above for the ID field). Avoid acronyms because there are many common acronyms, such as ISI and USC. Please provide it in ascending order, such as &quot;X University, Y Department&quot; (not &quot;Y Department, X University&quot;) Format:  ORGANIZATION:: &lt;free-text&gt; Example:  ORGANIZATION:: Stanford University, Department of Computer Science  </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="title" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Title</Attribute>
+            <Attribute name="definition">The title of the work</Attribute>
+            <Attribute name="comment">This is the title of the work as assigned by the author. This field should include the complete title with all the subtitles, if any. Format:  TITLE:: &lt;free-text&gt;  Example:  TITLE:: The Computerization of Oceanview with High Speed Fiber Optics Communication </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="type" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Type</Attribute>
+            <Attribute name="definition">The type of publication</Attribute>
+            <Attribute name="comment">Indicates the type of publication (summary, final project report, etc.) as assigned by the issuing organization. Format:  TYPE:: &lt;free-text&gt; Example:  TYPE:: Technical Report  </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="revision" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Revision</Attribute>
+            <Attribute name="definition">If the record is a revision of a previously issued record</Attribute>
+            <Attribute name="comment">Indicates that the current bibliographic record is a revision of a previously issued record and is intended to replace it. Revision information consists of a date and/or followed by a semicolon and by text in an open ended format. The revised bibliographic record should contain a complete record for the publication, not just a list of changes to the old record. If revision is omitted, the record is assumed to be a new record and not a revision.  If the revision date is specified as 0, this is assumed to be January 1, 1900 (the previous RFC, used revision data of 0, 1, 2, 3, etc. this specification is for programs that might process records from RFC1357). The text before the semicolon in this field is a date of the form month day, year. Any record with a more recent revision date replaces completely any record with an earlier revision date (supplied either explicitly or by default). Use the text to describe the revision. Reasons to send out a revised record include an error in the original, or change in the access information. Format:  REVISION:: January 1, 1995; &lt;free-text&gt; Example: REVISION:: January 1, 1995; FTP information added </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="withdraw" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Withdraw</Attribute>
+            <Attribute name="definition">Withdraw means the document is no longer available.</Attribute>
+            <Attribute name="comment">Withdraw means the document is no longer available. Some Institutions choose to delete the record others remove some of the fields. It is up to each institution to decide how to process withdraw records. A withdraw record has all of the mandatory fields plus the withdraw field and a mandatory revision field. The Withdraw field should indicate the reason for the withdraw in free text. Example for withdrawing a bibliographic record:: BIB-VERSION::  CS-TR-v2.1 ID:: OUKS//CS-TR-91-123 ENTRY:: January 21, 1995 ORGANIZATION:: Oceanview University, Kansas, Computer Science TITLE:: The Computerization of Oceanview with High Speed Fiber Optics Communication REVISION:: January 21, 1995 WITHDRAW:: Withdrawn, found to be irrelevant END::  OUKS//CS-TR-91-123  </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="author" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Author</Attribute>
+            <Attribute name="definition">The author</Attribute>
+            <Attribute name="comment">Personal names only. Normal last name first inversion. Editors should be listed here as well, identified with the usual &quot;(ed.)&quot; as shown below in the last example. If the report was not authored by a person (e.g., it was authored by a committee or a panel) use CORP-AUTHOR (see below) instead of AUTHOR. Multiple authors are entered by using multiple lines, each in the form of &quot;AUTHOR:: &lt;free-text&gt;&quot;. The system preserves the order of the authors. Format: AUTHOR:: &lt;free-text&gt; Example:  AUTHOR:: Finnegan, James A. AUTHOR:: Pooh, Winnie The AUTHOR:: Lastname, Firstname (ed.) </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="corp-author" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Corp-author</Attribute>
+            <Attribute name="definition">The corporate author</Attribute>
+            <Attribute name="comment">The corporate author (e.g., a committee or a panel) that authored the report, which may be different from the ORGANIZATION issuing the report. In entering the corporate name please omit initial &quot;the&quot; or &quot;a&quot;.  If it is really part of the name, please invert it. Format: CORP-AUTHOR:: &lt;free-text&gt; Example: CORP-AUTHOR:: Committee on long-range computing </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="contact" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Contact</Attribute>
+            <Attribute name="definition">The contact for the author(s)</Attribute>
+            <Attribute name="comment">The contact for the author(s). Open-ended, most likely E-mail and postal addresses. A CONTACT field for each author should be provided, separately, or for all the AUTHOR fields. E-mail addresses should always be in &quot;pointy brackets&quot; (as in the example below). Format: CONTACT:: &lt;free-text&gt; Example: CONTACT:: Prof. J. A. Finnegan, CS Dept, Oceanview Univ., Oceanview, Kansas, 54321 Tel: 913-456-7890 &lt;Finnegan@cs.ouks.edu&gt; </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="date" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Date</Attribute>
+            <Attribute name="definition">The publication date</Attribute>
+            <Attribute name="comment">The publication date. The formats are &quot;Month Year&quot; and &quot;Month Day, Year&quot;. The month must be alphabetic (spelled out). The &quot;Day&quot; is a 1- or 2-digit number. The &quot;Year&quot; is a 4- digit number. Format:  DATE:: &lt;date&gt; Example: DATE:: January 1992 Example:  DATE:: January 15, 1992  </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="pages" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Pages</Attribute>
+            <Attribute name="definition">Total number of pages</Attribute>
+            <Attribute name="comment">Total number of pages, without being too picky about it. Final numbered page is actually preferred, if it is a reasonable approximation to the total number of pages. Format: PAGES:: &lt;number&gt; Example:  PAGES:: 48 </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="copyright" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Copyright</Attribute>
+            <Attribute name="definition">Copyright information</Attribute>
+            <Attribute name="comment">Copyright information. Open ended format. The COPYRIGHT field applies to the cited report, rather than to the current bibliographic record. Format:  COPYRIGHT:: &lt;free-text&gt; Example: COPYRIGHT:: Copyright for the report (c) 1991, by J. A. Finnegan. All rights reserved. Permission is granted for any academic use of the report. </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="handle" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Handle</Attribute>
+            <Attribute name="definition">Handles are unique identifiers that are used to rerieve location data.</Attribute>
+            <Attribute name="comment">Handles are unique permanent identifiers that are  used in the Handle Management System to retrieve location data. A handle is a printable string which when given to a handle server returns the location of the data. Handles are used to identify digital objects stored within a digital library. If the technical report is available in electronic form, the Handle MUST be supplied in the bibliographic record. Format is &quot;HANDLE:: hdl:&lt;naming authority&gt;/string  of characters&quot;. The string of characters can be the report number of the technical report as assigned by the publisher. For more information on handles and handle servers see the CNRI WEB page at http://www.cnri.reston.va.us. NOTE: White space in HANDLE due to line wrap is ignored. Format: HANDLE:: hdl:&lt;naming authority&gt;/string of characters Example: HANDLE:: hdl:oceanview.electr/CS-TR-91-123</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="other_access" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Other_access</Attribute>
+            <Attribute name="definition">Other access information like URLs and URNs</Attribute>
+            <Attribute name="comment">For URLs, URNs, and other yet to be invented  formatted retrieval systems. Only one URL or URN per occurrence of the field. URL and URN information is available in the internet drafts from the IETF (Internet Engineering Task Force). The most recent drafts can be found on the CNRI WEB page at http://www.cnri.reston.va.us. NOTE: White space in a URL or URN due to line wrap is ignored. Format: OTHER_ACCESS:: URL:&lt;URL&gt; OTHER_ACCESS:: URN:&lt;URN&gt; Example: OTHER_ACCESS:: URL:http://elib.stanford.edu/Document/STANFORD.CS:CS-TN-94-1 Example: OTHER_ACCESS:: URL:ftp://JUPITER.CS.OUKS.EDU/PUBS/computerization.txt. When the URN standard is finalized naming authorities will be registered and URNs will be viable unique identifiers. Until then this is a place holder. For the latest URN drafts see CNRI WEB page at http://www.cnri.reston.va.us </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="retrieval" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Retrieval</Attribute>
+            <Attribute name="definition">Describes how to get a copy of the full text</Attribute>
+            <Attribute name="comment">Open-ended format describing how to get a copy of the full text. This is an optional, repeatable field. No limitations are placed on the dissemination of the bibliographic records. If there are limitations on the dissemination of the publication, it should be protected by some means such as passwords. This format does not address this protection. Format:  RETRIEVAL:: &lt;free-text&gt; RETRIEVAL:: for full text with color pictures send a self-addressed stamped envelope to Prof. J.A. Finnegan, CS Dept, Oceanview University, Oceanview, KS 54321 </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="keyword" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Keyword</Attribute>
+            <Attribute name="definition">Keywords</Attribute>
+            <Attribute name="comment">Specify any keywords, controlled or uncontrolled. This is an optional, repeatable field. Multiple keywords are entered using multiple lines in the form of  &quot;KEYWORD::  &lt;free-text&gt;.  Format: KEYWORD:: &lt;free-text&gt; Example: KEYWORD:: Scientific Communication KEYWORD:: Communication Theory </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="cr-category" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Cr-category</Attribute>
+            <Attribute name="definition">The Computer Reviews Category index</Attribute>
+            <Attribute name="comment">Specify the CR-category.  The CR-category (the Computer Reviews Category) index (e.g., &quot;B.3&quot;) should always be included, optionally followed by the name of that category. If the name is specified it should be fully specified with parent levels as needed to clarify it, as in the second example below. Use multiple lines for multiple categories. Every year, the January issue of CR has the full list of these categories, with a detailed discussion of the CR Classification System, and a full index. Typically the full index appears in every January issue, and the top two levels in every issue. Format: CR-CATEGORY:: &lt;free-text&gt; Example: CR-CATEGORY:: D.1 Example: CR-CATEGORY:: B.3 Hardware, Memory Structures </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="period" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Period</Attribute>
+            <Attribute name="definition">Time period covered</Attribute>
+            <Attribute name="comment">Time period covered (date range). Applicable primarily to progress reports, etc. Any format is acceptable, as long as the two dates are separated with &quot; to &quot; (the word &quot;to&quot; surrounded by spaces) and each date is in the format allowed for dates, as described above for the date field. Format: PERIOD:: &lt;date&gt; to &lt;date&gt;  Example:  PERIOD:: January 1990 to March 1990</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="series" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Series</Attribute>
+            <Attribute name="definition">Series title</Attribute>
+            <Attribute name="comment">Series title, including volume number within series. Open-ended format, with producing institution strongly  encouraged to be internally consistent. Format: SERIES:: &lt;free-text&gt;  Example: SERIES:: Communication </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="monitoring" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Monitoring</Attribute>
+            <Attribute name="definition">The monitoring organization(s)</Attribute>
+            <Attribute name="comment">The name(s) of the monitoring organization(s). Format: MONITORING:: &lt;free-text&gt; Example: MONITORING:: ONR </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="funding" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Funding</Attribute>
+            <Attribute name="definition">The funding organization(s)</Attribute>
+            <Attribute name="comment">The name(s) of the funding organization(s). Format: FUNDING:: &lt;free-text&gt; Example: FUNDING:: ARPA </Attribute>
+            <Attribute name="comment">The name(s) of the funding organization(s). Format: FUNDING:: &lt;free-text&gt; Example: FUNDING:: ARPA </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="contract" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Contract</Attribute>
+            <Attribute name="definition">The contract number(s)</Attribute>
+            <Attribute name="comment">The contract number(s). Format: CONTRACT:: &lt; free-text&gt;  Example: CONTRACT:: MMA-90-23-456 </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="grant" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Grant</Attribute>
+            <Attribute name="definition">The grant number(s)</Attribute>
+            <Attribute name="comment">The grant number(s). Format: GRANT:: &lt;free-text&gt; Example:  GRANT:: NASA-91-2345</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="language" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Language</Attribute>
+            <Attribute name="definition">The language in which the report is written</Attribute>
+            <Attribute name="comment">The language in which the report is written. Please use the full English name of that language. Please include the Abstract in English, if possible. If the language is not specified, English is assumed. Format: LANGUAGE:: &lt;free-text&gt; Example: LANGUAGE:: English  Example: LANGUAGE:: French</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="notes" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Notes</Attribute>
+            <Attribute name="definition">Miscellaneous free text</Attribute>
+            <Attribute name="comment">Miscellaneous free text. Format: NOTES:: &lt;free-text&gt; Example: NOTES:: This report is the full version of the paper with the same title in IEEE Trans ASSP Dec 1976 </Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+    <Element name="abstract" occurances="58" remember_values="true">
+        <!-- English -->
+        <Language code="en">
+            <Attribute name="identifier">Abstract</Attribute>
+            <Attribute name="definition">The abstract of the report</Attribute>
+            <Attribute name="comment">Highly recommended, but not mandatory. Even though no limit is defined for its length, it is suggested not to expect applications to be able to handle more than 10,000 characters. The ABSTRACT is expected to be used for subject searching since titles are not enough. Even if the report is not in English, an English ABSTRACT is preferable. If no formal abstract appears on document, the producers of the bibliographic records are encouraged to use pieces of the introduction, first paragraph, etc. Format:  ABSTRACT:: xxxx .............. xxxxxxxx</Attribute>
+        </Language>
+        <!-- Non-language specific -->
+        <Attribute name="version">1.0</Attribute>
+        <Attribute language="en" name="registration_authority">The Internet Engineering Task Force</Attribute>
+        <Attribute name="obligation">Optional</Attribute>
+        <Attribute name="datatype">Character String</Attribute>
+        <Attribute name="maximum_occurance">Unlimited</Attribute>
+    </Element>
+</MetadataSet>
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/Configuration.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/Configuration.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/Configuration.java	(revision 10506)
@@ -0,0 +1,989 @@
+/**
+ *#########################################################################
+ * Configuration
+ * 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: 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.gatherer;
+
+import java.awt.*;
+import java.io.*;
+import java.lang.ref.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.plaf.*;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/** This class stores the various configurable settings inside the Gatherer, both during a session, and between sessions in the form of XML. However not all data members are retained during xml serialization. To further improve efficiency, the property-name -> DOM Element pairs are stored in a SoftReferenced Hashtable.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class Configuration
+    extends Hashtable {
+
+    static final public boolean COLLECTION_SPECIFIC = true;
+    static final public boolean GENERAL_SETTING = true;
+
+    static final public int ASSISTANT_MODE = 1;
+    static final public int LIBRARIAN_MODE = 2;
+    static final public int SYSTEMS_MODE   = 3;
+    static final public int EXPERT_MODE    = 4; 
+
+    /** The string identifying an argument's name attribute. */
+    static final private String ARGUMENT_NAME = "name";
+    /** The name of the general Gatherer configuration file. */
+    static public String CONFIG_XML = "config.xml";
+    /** The name of the general Gatherer configuration file for running with GS3. */
+    static public String GS3_CONFIG_XML = "config3.xml";
+
+    /** The name of the root element of the subtree containing gatherer configuration options. This is required as the document itself may contain several other subtrees of settings (such as in the case of a '.col' file). */
+    static final private String GATHERER_CONFIG = "GathererConfig";
+    /** The string identifying an argument element. */
+    static final private String GATHERER_CONFIG_ARGUMENT = "Argument";
+
+    static final private String GENERAL_EMAIL_SETTING = "general.email";
+    /** the lang attribute of the other element */
+    static final private String LANGUAGE = "lang";
+    /** The name of a Name Element. */
+    static final private String NAME = "Name";
+    /** The name of the other arguments element. */
+    static final private String OTHER = "Other";
+    /** The name of an information Element within the Other subtree. */
+    static final private String OTHER_INFO = "Info";
+    /** The name of the general Gatherer configuration template. */
+    static public String TEMPLATE_CONFIG_XML = "xml/config.xml";
+    /** 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";
+
+    static public Configuration self = null;
+    static private String gli_user_directory_path = null;
+
+    static public boolean just_updated_config_xml_file = false;
+    /** The path to the Greenstone Suite installation directory. */
+    static public String gsdl_path = "";
+    /** If we are using GLI in Greenstone 3, the path to gsdl3 home (== web dir) */
+    static public String gsdl3_path = "";
+    /** If we are using GLI in Greenstone 3, the path to gsdl3 src directory (== gsdl3 dir)*/
+    static public String gsdl3_src_path = "";
+    /** The path to the PERL executable, up to and including Perl.exe. */
+    static public String perl_path = "";
+    /** The password for the proxy server indicated above. */
+    static public String proxy_pass = null;
+    /** The username for the proxy server indicated above. */
+    static public String proxy_user = null;
+    /** The screen size of the desktop the Gatherer will be displayed on. */
+    static public Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+    /** The site name if we are using GS3 */
+    static public String site_name = "";
+    /** The servlet path if we are using GS3 */
+    static public String servlet_path = "";
+    /** Collection level configuration (which in some cases overrides general configuration. */
+    static private Document collection_config;
+    /** The general configuration settings. */
+    static private Document general_config;
+
+    /** The element, from glis config file, that contains the various directory mappings. */
+    static private Element directory_mappings_element;
+
+    static private int cache_hit = 0;
+    static private int cache_miss = 0;
+
+    static private String wget_path = null;
+    static private String wget_version_str = StaticStrings.NO_WGET_STR;
+
+    static public URL library_url = null;
+
+
+    /** Constructor.
+     * @param gsdl_path The path to the Greenstone directory as a <strong>String</strong>.
+     * @param gsdl3_path The path to the Greenstone 3 home (web) directory as a <strong>String</strong>.
+     * @param gsdl3_src_path The path to the Greenstone 3 src directory as a <strong>String</strong>.
+     * @param site_name The name of the Greenstone 3 site currently in use.
+     */
+    public Configuration(String gli_user_directory_path, String gsdl_path, String gsdl3_path, String gsdl3_src_path, String site_name)
+    {
+	super();
+	self = this;
+
+	this.gli_user_directory_path = gli_user_directory_path;
+	this.gsdl_path = gsdl_path;
+	this.gsdl3_path = gsdl3_path;
+	this.gsdl3_src_path = gsdl3_src_path;
+	this.site_name = site_name;
+
+	// Try to load the configuration file from the user specific location
+	String config_xml_file_name = CONFIG_XML;
+	if (gsdl3_path != null) {
+	    config_xml_file_name = GS3_CONFIG_XML;
+	}
+
+	// If the existing user config.xml file isn't recent enough, backup the old version and update it
+	File config_xml_file = new File(gli_user_directory_path + config_xml_file_name);
+	if (config_xml_file != null && config_xml_file.exists()) {
+	    just_updated_config_xml_file = updateUserConfigXMLFileIfNecessary(config_xml_file);
+	    general_config = XMLTools.parseXMLFile(config_xml_file);
+	}
+
+	// Create a new config from the default configuration file from our xml library
+	if (general_config == null) {
+	    general_config = XMLTools.parseXMLFile(TEMPLATE_CONFIG_XML, true);
+	    just_updated_config_xml_file = true;
+	}
+
+	// Determine the Directory Mappings element
+	directory_mappings_element = (Element) XMLTools.getNodeFromNamed(general_config.getDocumentElement(), StaticStrings.DIRECTORY_MAPPINGS_ELEMENT);
+
+	// Re-establish the color settings.
+	updateUI();
+
+	// Read the Greenstone library URL from the config file
+	String library_url_string = getString("general.library_url", true);
+	if (!library_url_string.equals("")) {
+	    try {
+		library_url = new URL(library_url_string);
+	    }
+	    catch (MalformedURLException exception) {
+		DebugStream.printStackTrace(exception);
+	    }
+	}
+
+	if (gsdl3_path != null) {
+	    if (this.site_name == null || this.site_name.equals("")) {
+		this.site_name = getString("general.site_name", true);
+		this.servlet_path = getString("general.servlet_path", true);
+		if (this.site_name.equals("")) {
+		    this.site_name = "localsite"; // can we assume these??
+		    this.servlet_path = "/library";
+		    setString("general.site_name", true, this.site_name);
+		    setString("general.servlet_path", true, this.servlet_path);
+		}
+		
+	    } else {
+		// we set the current one in the config
+		setString("general.site_name", true, this.site_name);
+		if (this.servlet_path != null && !this.servlet_path.equals("")) {
+		    setString("general.servlet_path", true, this.servlet_path);
+		}
+	    }
+	}
+    }
+
+
+    static private boolean updateUserConfigXMLFileIfNecessary(File config_xml_file)
+    {
+	// Check if the configuration file actually needs updating by looking at the version numbers
+	Document new_document = XMLTools.parseXMLFile(TEMPLATE_CONFIG_XML, true);
+	Document old_document = XMLTools.parseXMLFile(config_xml_file);
+
+	String new_version = new_document.getDocumentElement().getAttribute(StaticStrings.VERSION_ATTRIBUTE);
+	String old_version = old_document.getDocumentElement().getAttribute(StaticStrings.VERSION_ATTRIBUTE);
+	if (new_version.compareTo(old_version) <= 0) {
+	    // Don't need to update file
+	    return false;
+	}
+
+	System.err.println("Updating user config.xml from version " + old_version + " to version " + new_version + "...");
+
+	// Build up the new user config.xml file from the template config.xml with the user's preferences added
+	// Make a backup of the old config.xml file first
+	config_xml_file.renameTo(new File(config_xml_file.getAbsolutePath() + ".old"));
+
+	// Check all of the Argument elements in the new config.xml file
+	NodeList new_argument_elements_nodelist = new_document.getElementsByTagName("Argument");
+	NodeList old_argument_elements_nodelist = old_document.getElementsByTagName("Argument");
+	for (int i = 0; i < new_argument_elements_nodelist.getLength(); i++) {
+	    Element new_argument_element = (Element) new_argument_elements_nodelist.item(i);
+	    String new_argument_element_name = new_argument_element.getAttribute("name");
+	    String new_argument_element_value = XMLTools.getElementTextValue(new_argument_element);
+
+	    // Did this Argument have a non-default value set?
+	    for (int j = old_argument_elements_nodelist.getLength() - 1; j >= 0; j--) {
+		Element old_argument_element = (Element) old_argument_elements_nodelist.item(j);
+		String old_argument_element_name = old_argument_element.getAttribute("name");
+
+		// Argument found
+		if (old_argument_element_name.equals(new_argument_element_name)) {
+		    String old_argument_element_value = XMLTools.getElementTextValue(old_argument_element);
+		    if (!old_argument_element_value.equals(new_argument_element_value)) {
+			XMLTools.setElementTextValue(new_argument_element, old_argument_element_value);
+		    }
+
+		    // We don't care about this option any more
+		    old_argument_element.getParentNode().removeChild(old_argument_element);
+		    break;
+		}
+	    }
+	}
+
+	// Are there any old Argument elements left over? Keep these around for old time's sake
+	old_argument_elements_nodelist = old_document.getElementsByTagName("Argument");
+	if (old_argument_elements_nodelist.getLength() > 0) {
+	    NodeList new_gathererconfig_elements_nodelist = new_document.getElementsByTagName("GathererConfig");
+	    if (new_gathererconfig_elements_nodelist.getLength() > 0) {
+		Element new_gathererconfig_element = (Element) new_gathererconfig_elements_nodelist.item(0);
+		new_gathererconfig_element.appendChild(new_document.createComment(" Legacy options "));
+
+		// Add the legacy Arguments to the GathererConfig element
+		for (int i = 0; i < old_argument_elements_nodelist.getLength(); i++) {
+		    Element old_argument_element = (Element) old_argument_elements_nodelist.item(i);
+		    new_gathererconfig_element.appendChild(new_document.importNode(old_argument_element, true));
+		}
+	    }
+	}
+
+	// Keep all the Mapping elements
+	NodeList new_directorymappings_elements_nodelist = new_document.getElementsByTagName("DirectoryMappings");
+	if (new_directorymappings_elements_nodelist.getLength() > 0) {
+	    Element new_directorymappings_element = (Element) new_directorymappings_elements_nodelist.item(0);
+
+	    NodeList old_mapping_elements_nodelist = old_document.getElementsByTagName("Mapping");
+	    for (int i = 0; i < old_mapping_elements_nodelist.getLength(); i++) {
+		Element old_mapping_element = (Element) old_mapping_elements_nodelist.item(i);
+		new_directorymappings_element.appendChild(new_document.importNode(old_mapping_element, true));
+	    }
+	}
+
+	// Check all of the Associations elements in the new config.xml file
+	NodeList new_entry_elements_nodelist = new_document.getElementsByTagName("Entry");
+	NodeList old_entry_elements_nodelist = old_document.getElementsByTagName("Entry");
+	for (int i = 0; i < new_entry_elements_nodelist.getLength(); i++) {
+	    Element new_entry_element = (Element) new_entry_elements_nodelist.item(i);
+	    String new_entry_element_name = new_entry_element.getAttribute("extension");
+	    String new_entry_element_value = XMLTools.getElementTextValue(new_entry_element);
+
+	    // Did this Entry have a non-default value set?
+	    for (int j = old_entry_elements_nodelist.getLength() - 1; j >= 0; j--) {
+		Element old_entry_element = (Element) old_entry_elements_nodelist.item(j);
+		String old_entry_element_name = old_entry_element.getAttribute("extension");
+
+		// Entry found
+		if (old_entry_element_name.equals(new_entry_element_name)) {
+		    String old_entry_element_value = XMLTools.getElementTextValue(old_entry_element);
+		    if (!old_entry_element_value.equals(new_entry_element_value)) {
+			XMLTools.setElementTextValue(new_entry_element, old_entry_element_value);
+		    }
+
+		    // We don't care about this option any more
+		    old_entry_element.getParentNode().removeChild(old_entry_element);
+		    break;
+		}
+	    }
+	}
+
+	// Are there any old Entry elements left over? We want to keep these
+	old_entry_elements_nodelist = old_document.getElementsByTagName("Entry");
+	if (old_entry_elements_nodelist.getLength() > 0) {
+	    NodeList new_associations_elements_nodelist = new_document.getElementsByTagName("Associations");
+	    if (new_associations_elements_nodelist.getLength() > 0) {
+		Element new_associations_element = (Element) new_associations_elements_nodelist.item(0);
+
+		// Add the legacy Entries to the Associations element
+		for (int i = 0; i < old_entry_elements_nodelist.getLength(); i++) {
+		    Element old_entry_element = (Element) old_entry_elements_nodelist.item(i);
+		    new_associations_element.appendChild(new_document.importNode(old_entry_element, true));
+		}
+	    }
+	}
+
+	// Write out the updated config.xml file
+	XMLTools.writeXMLFile(config_xml_file, new_document);
+	return true;
+    }
+
+
+    /** Add a special directory mapping. */
+    static public boolean addDirectoryMapping(String name, File file) {
+	boolean result = false;
+	try {
+	    // Ensure the name isn't already in use.
+	    boolean found = false;
+	    NodeList mappings = directory_mappings_element.getElementsByTagName(StaticStrings.MAPPING_ELEMENT);
+	    for(int i = 0; !found && i < mappings.getLength(); i++) {
+		Element mapping_element = (Element) mappings.item(i);
+		if(mapping_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equalsIgnoreCase(name)) {
+		    found = true;
+		}
+		mapping_element = null;
+	    }
+	    // Otherwise add the mapping.
+	    if(!found) {
+		Element mapping_element = general_config.createElement(StaticStrings.MAPPING_ELEMENT);
+		mapping_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name);
+		mapping_element.setAttribute(StaticStrings.FILE_ATTRIBUTE, file.toString());
+		directory_mappings_element.appendChild(mapping_element);
+		result = true;
+		mapping_element = null;
+	    }
+	    mappings = null;
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return result;
+    } /** addDirectoryMapping(String name, String file) **/
+
+    /** The default get action retrieves the named property from the desired configuration, and returns a true or false. */
+    static public boolean get(String property, boolean general) {
+	String raw = getString(property, general);
+	return (raw != null && raw.equalsIgnoreCase("true"));
+    }
+
+    /** Retrieve all of the configuration preferences which match a certain string. They are returned as a hash map of property names to String objects. */
+    static public HashMap getAll(String property_pattern, boolean general) {
+	HashMap properties = new HashMap();
+	try {
+	    // Locate the appropriate element
+	    Element document_element = null;
+	    if(general) {
+		document_element = general_config.getDocumentElement();
+	    }
+	    else if(collection_config != null) {
+		document_element = collection_config.getDocumentElement();
+	    }
+	    if(document_element != null) {
+		// Retrieve the Gatherer element
+		Element gatherer_element = (Element) XMLTools.getNodeFromNamed(document_element, GATHERER_CONFIG);
+		NodeList arguments = gatherer_element.getElementsByTagName(GATHERER_CONFIG_ARGUMENT);
+		for(int i = 0; i < arguments.getLength(); i++) {
+		    Element argument_element = (Element) arguments.item(i);
+		    if(argument_element.getAttribute(ARGUMENT_NAME).matches(property_pattern)) {
+			String result = XMLTools.getValue(argument_element);
+			// Store a mapping in the cache. Sometimes we will overwrite an existing value (say for collection and general level workflow options) but the processing overhead of detecting these clashes far exceeds any savings.
+			self.put(argument_element.getAttribute(ARGUMENT_NAME) + general, new SoftReference(argument_element));
+			// Add mapping to the properties we're going to return
+			properties.put(argument_element.getAttribute(ARGUMENT_NAME), result);
+		    }
+		}
+	    }
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return properties;
+    }
+
+    /** Retrieve the information subtree containing the arguments for the desired external program. If the program has marked superclasses append their arguments as well. */
+    static public Element getArguments(String filename) {
+	Element argument_element = null;
+	try {
+	    // Retrieve the other information subtree.
+	    Element document_element = general_config.getDocumentElement();
+	    Element other_element = (Element) XMLTools.getNodeFromNamed(document_element, OTHER);
+	    NodeList argument_elements = other_element.getElementsByTagName(OTHER_INFO);
+	    for(int i = 0; argument_element == null && i < argument_elements.getLength(); i++) {
+		Element possible_element = (Element) argument_elements.item(i);
+		Element possible_name_element = (Element) XMLTools.getNodeFromNamed(possible_element, NAME);
+		String possible_name = XMLTools.getValue(possible_name_element);
+		///ystem.err.println("Does " + possible_name + " equal " + filename);
+		if(possible_name.equalsIgnoreCase(filename)) {
+		    argument_element = possible_element;
+		}
+		possible_name = null;
+		possible_name_element = null;
+		possible_element = null;
+	    }
+	    argument_elements = null;
+	    other_element = null;
+	    document_element = null;
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return argument_element;
+    }
+
+    /** Gets the language for the other arguments subtree 
+     @return empty string if no language specified */
+    static public String getArgumentsLanguage() {
+	Element document_element = general_config.getDocumentElement();
+	Element other_element = (Element) XMLTools.getNodeFromNamed(document_element, OTHER);
+	String lang = other_element.getAttribute(LANGUAGE);
+	if (lang == null) {
+	    lang = "en";
+	}
+	return lang;
+    }
+
+    /** Retrieve the value of the named property as a Rectangle. */
+    static public Rectangle getBounds(String property, boolean general) {
+	Rectangle result = null;
+	try {
+	    String raw = getString(property, general);
+	    // Rectangle is (x, y, width, height)
+	    StringTokenizer tokenizer = new StringTokenizer(raw, TOKENIZER_PATTERN1);
+	    int x = Integer.parseInt(tokenizer.nextToken());
+	    int y = Integer.parseInt(tokenizer.nextToken());
+	    int width = Integer.parseInt(tokenizer.nextToken());
+	    int height = Integer.parseInt(tokenizer.nextToken());
+	    result = new Rectangle(x, y, width, height);
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return result;
+    }
+
+    /** Retrieve the value of the named property as a Color. */
+    static public Color getColor(String property, boolean general) {
+	Color result = Color.white; // Default
+	try {
+	    String raw = getString(property, general);
+	    // 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 exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return result;
+    }
+
+
+    /** Retrieve the special directory mappings associated with this collection.
+     * @return A <strong>HashMap</strong> containing mappings from names to directories.
+     */
+    static public HashMap getDirectoryMappings() {
+	HashMap special_directories = new HashMap();
+	try {
+	    // Ensure the name isn't already in use.
+	    boolean found = false;
+	    NodeList mappings = directory_mappings_element.getElementsByTagName(StaticStrings.MAPPING_ELEMENT);
+	    for(int i = 0; !found && i < mappings.getLength(); i++) {
+		Element mapping_element = (Element) mappings.item(i);
+		String name = mapping_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+		File file = new File(mapping_element.getAttribute(StaticStrings.FILE_ATTRIBUTE));
+		special_directories.put(name, file);
+		file = null;
+		name = null;
+		mapping_element = null;
+	    }
+	    mappings = null;
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return special_directories;
+    } /** getDirectoryMappings() */
+
+    /** Retrieve the current users email. These are always stored in the general settings.
+     * @return the email address, if it is set, as a String
+     */
+    static public String getEmail() {
+	String email = getString(GENERAL_EMAIL_SETTING, true);
+	return (email.length() > 0 ? email : null);
+    }
+
+    static public Element getFileAssociations() {
+	NodeList file_association_elements = general_config.getDocumentElement().getElementsByTagName(StaticStrings.ASSOCIATIONS_ELEMENT);
+	return (Element) file_association_elements.item(0);
+    }
+
+    /** Retrieve the value of the named property as a FontUIResource. */
+    static public FontUIResource getFont(String property, boolean general) {
+	FontUIResource result = new FontUIResource("Times New Roman", Font.PLAIN, 10);
+	try {
+	    String raw = getString(property, general);
+	    // Font is a face, style, size triplet.
+	    StringTokenizer tokenizer = new StringTokenizer(raw, TOKENIZER_PATTERN3);
+	    String face = tokenizer.nextToken().trim();
+	    ///ystem.err.println("Face:  " + face);
+	    int style = Font.PLAIN;
+	    String temp = tokenizer.nextToken().toUpperCase().trim();
+	    ///ystem.err.println("Style: " + temp);
+	    if(temp.equals("BOLD")) {
+		style = Font.BOLD;
+	    }
+	    else if(temp.equals("ITALIC")) {
+		style = Font.ITALIC;
+	    }
+	    int size = Integer.parseInt(tokenizer.nextToken().trim());
+	    ///ystem.err.println("Size:  " + size);
+	    result = new FontUIResource(face, style, size);
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return result;
+    }
+
+    /** Retrieve the value of the named property as an integer. */
+    static public int getInt(String property, boolean general) {
+	int result = 0;
+	try {
+	    String raw = getString(property, general);
+	    result = Integer.parseInt(raw);
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return result;
+    }
+
+    /** Retrieves the current interface language two letter code. */
+    static public String getLanguage() {
+	Locale locale = getLocale("general.locale", GENERAL_SETTING);
+	String code = "en"; // Default
+	if(locale != null) {
+	    code = locale.getLanguage();
+	}
+	return code;
+    }
+
+    /** Retrieve the value of the named property as a Locale. */
+    static public Locale getLocale(String property, boolean general) {
+	Locale result = Locale.getDefault();
+	try {
+	    String raw = getString(property, general);
+	    // 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 exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return result;
+    }
+
+    /** Because modes will soon be an integral part of GLI, they get their own easy to remember methods such as this one to get the mode.
+     * @return an int representing the mode
+     */
+    static public int getMode() {
+	return getInt("general.mode", GENERAL_SETTING);
+    }
+
+    /** Return the current mode as a string for use in title bar etc
+     * @return the mode as a String
+     */
+    static public String getModeAsString() {
+	String result;
+	switch(getInt("general.mode", GENERAL_SETTING)) {
+	case ASSISTANT_MODE:
+	    result = Dictionary.get("Preferences.Mode.Assistant");
+	    break;
+	case SYSTEMS_MODE:
+	    result = Dictionary.get("Preferences.Mode.Systems");
+	    break;
+	case EXPERT_MODE:
+	    result = Dictionary.get("Preferences.Mode.Expert");
+	    break;
+	default:
+	    result = Dictionary.get("Preferences.Mode.Librarian");
+	}
+	return result;
+    }
+
+    static public String getPreviewCommand() {
+	return getString("general.preview_program", GENERAL_SETTING);
+    }
+
+    static public String getServletPath() {
+	return servlet_path;
+    }
+
+    /** Retrieve the value of the named property, and noting whether we consult the general or collection specific configuration. */
+    static public String getString(String property, boolean general) {
+	// Its up to this method to find the appropriate node and retrieve the data itself.
+	String result = "";
+	try {
+	    // First of all we look in the cache to see if we have a match.
+	    SoftReference reference = (SoftReference) self.get(property + general);
+	    if(reference != null) {
+		Element argument_element = (Element) reference.get();
+		if(argument_element != null) {
+		    cache_hit++;
+		    result = XMLTools.getValue(argument_element);
+		}
+	    }
+	    // We may have missed in the cache, or the reference may have been consumed.
+	    if(result.length() == 0) {
+		cache_miss++;
+		// Locate the appropriate element
+		Element document_element = null;
+		if(general) {
+		    document_element = general_config.getDocumentElement();
+		}
+		else if(collection_config != null) {
+		    document_element = collection_config.getDocumentElement();
+		}
+		if(document_element != null) {
+		    // Retrieve the Gatherer element
+		    Element gatherer_element = (Element) XMLTools.getNodeFromNamed(document_element, GATHERER_CONFIG);
+		    NodeList arguments = gatherer_element.getElementsByTagName(GATHERER_CONFIG_ARGUMENT);
+		    for(int i = 0; result.length() == 0 && i < arguments.getLength(); i++) {
+			Element argument_element = (Element) arguments.item(i);
+			if(argument_element.getAttribute(ARGUMENT_NAME).equalsIgnoreCase(property)) {
+			    result = XMLTools.getValue(argument_element);
+			    // Store a mapping in the cache. Sometimes we will overwrite an existing value (say for collection and general level workflow options) but the processing overhead of detecting these clashes far exceeds any savings.
+			    self.put(property + general, new SoftReference(argument_element));
+			}
+		    }
+		}
+	    }
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	// If we still have no result, and the search was made in the collection configuration, retrieve the general one instead.
+	if(result.length() == 0 && !general) {
+	    result = getString(property, true);
+	}
+	return result;
+    }
+
+    static public String getGS3ScriptPath() {
+	return gsdl3_src_path + "bin" + File.separator + "script" + File.separator;
+    }
+
+    static public String getWGetPath() {
+	return (wget_path != null ? wget_path : "");
+    }
+
+    static public String getWGetVersion() {
+	return (wget_version_str != null ? wget_version_str : StaticStrings.NO_WGET_STR);
+    }
+
+    /** Remove a previously defined special directory mapping.
+     * @param name The name of the mapping to remove as a <strong>String</strong>.
+     * @return The <strong>File</strong> of the mapping removed.
+     */
+    static public File removeDirectoryMapping(String name) {
+	File file = null;
+	try {
+	    // Ensure the name isn't already in use.
+	    boolean found = false;
+	    NodeList mappings = directory_mappings_element.getElementsByTagName(StaticStrings.MAPPING_ELEMENT);
+	    for(int i = 0; !found && i < mappings.getLength(); i++) {
+		Element mapping_element = (Element) mappings.item(i);
+		if(mapping_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equalsIgnoreCase(name)) {
+		    file = new File(XMLTools.getValue(mapping_element));
+		    directory_mappings_element.removeChild(mapping_element);
+		    found = true;
+		}
+		mapping_element = null;
+	    }
+	    mappings = null;
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return file;
+    } /** removeDirectoryMapping(String name) */
+
+    /** Export the general configuration to file. */
+    static public void save() {
+	///ystem.err.println("Hits " + cache_hit + " vs Misses " + cache_miss);
+	// We first try exporting to a user specific place
+	File user_config_xml = null;
+	String config_xml_name = CONFIG_XML;
+	if (gsdl3_path!=null) {
+	    config_xml_name = GS3_CONFIG_XML;
+	}
+	try {
+	    user_config_xml = new File(gli_user_directory_path + config_xml_name);
+	    ///ystem.err.println("Trying to save to: " + user_config_xml.getAbsolutePath());
+	    ///ystem.err.println("Writing.");
+	    user_config_xml.getParentFile().mkdirs();
+	    XMLTools.writeXMLFile(new File(user_config_xml.getAbsolutePath()), general_config);
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	    user_config_xml = null;
+	}
+    }
+
+    /** Set the named property, from the specified configuration, using the given boolean value. */
+    static public void set(String property, boolean general, boolean value) {
+	if(property.startsWith("workflow")) {
+	    DebugStream.println("Set property: " + property + ", general=" + general + ", value=" + value);
+	}
+	setString(property, general, (value ? "true" : "false"));
+    }
+
+    /** Add a subtree of argument information to the other arguments part of the general configuration. This overwrites any such existing subtree. */
+    static public void setArguments(Element arguments_element) {
+	try {
+	    Element document_element = general_config.getDocumentElement();
+	    Element other_element = (Element) XMLTools.getNodeFromNamed(document_element, OTHER);
+	    // Retrieve the name of the information
+	    Element arguments_name_element = (Element)XMLTools.getNodeFromNamed(arguments_element, NAME);
+	    String filename = XMLTools.getValue(arguments_element);
+	    // Find any argument information subtree starting with the same name
+	    Element obsolete_arguments_element = getArguments(filename);
+	    // Create a copy of the arguments_element within our tree (import).
+	    Element our_arguments_element = (Element) general_config.importNode(arguments_element, true);
+	    // Now we insert this new node into the tree. If a previous node exists we replace it instead.
+	    if(obsolete_arguments_element == null) {
+		other_element.appendChild(our_arguments_element);
+	    }
+	    else {
+		other_element.replaceChild(our_arguments_element, obsolete_arguments_element);
+	    }
+	    our_arguments_element = null;
+	    obsolete_arguments_element = null;
+	    filename = null;
+	    arguments_name_element = null;
+	    other_element = null;
+	    document_element = null;
+	}
+	catch (Exception exception) {
+	    DebugStream.println("Error in Configuration.setArguments(): " + exception);
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+
+    /** Sets the language for the other arguments subtree */
+    static public void setArgumentsLanguage(String lang) {
+	Element document_element = general_config.getDocumentElement();
+	Element other_element = (Element) XMLTools.getNodeFromNamed(document_element, OTHER);
+	other_element.setAttribute(LANGUAGE, lang);
+    }
+
+	
+    /** Set the collection configuration. */
+    static public void setCollectionConfiguration(Document collection_config) {
+	// clear the cached values
+	self.clear();
+	collection_config = collection_config;
+	updateUI();
+	///atherer.println("Collection configuration set.");
+    }
+
+    /** Set the named property, from the specified configuration, using the given Rectangle value. */
+    static public void setBounds(String property, boolean general, Rectangle value) {
+	StringBuffer text = new StringBuffer("");
+	text.append(value.x);
+	text.append(", ");
+	text.append(value.y);
+	text.append(", ");
+	text.append(value.width);
+	text.append(", ");
+	text.append(value.height);
+	setString(property, general, text.toString());
+    }
+
+    /** Set the named property, from the specified configuration, using the given Color value. */
+    static public void setColor(String property, boolean general, Color value) {
+	StringBuffer text = new StringBuffer("");
+	text.append(value.getRed());
+	text.append(", ");
+	text.append(value.getGreen());
+	text.append(", ");
+	text.append(value.getBlue());
+	setString(property, general, text.toString());
+    }
+
+    /** Establish the current users email.
+     * @param email the email as a String
+     */
+    static public void setEmail(String email) {
+	setString(GENERAL_EMAIL_SETTING, true, email);
+    }
+
+    /** Set the named property, from the specified configuration, using the given Font value. */
+    static public void setFont(String property, boolean general, Font value) {
+	StringBuffer text = new StringBuffer("");
+	text.append(value.getName());
+	text.append(", ");
+	switch(value.getStyle()) {
+	case Font.BOLD:
+	    text.append("BOLD");
+	    break;
+	case Font.ITALIC:
+	    text.append("ITALIC");
+	    break;
+	default:
+	    text.append("PLAIN");
+	}
+	text.append(", ");
+	text.append(value.getSize());
+	setString(property, general, text.toString());
+    }
+
+    /** Set the named property, from the specified configuration, using the given integer value. */
+    static public void setInt(String property, boolean general, int value) {
+        setString(property, general, String.valueOf(value));
+    } 
+
+    /** Set the named property, from the specified configuration, using the given Locale value. */
+    static public void setLocale(String property, boolean general, Locale value) {
+	StringBuffer text = new StringBuffer("");
+	text.append(value.getLanguage());
+	String country = value.getCountry();
+	if(country != null && country.length() > 0) {
+	    text.append("_");
+	    text.append(country);
+	}
+	country = null;
+	setString(property, general, text.toString());
+    }
+
+    /** Because modes will soon be an integral part of GLI, they get their own easy to remember methods such as this one to set the mode.
+     * @param value the new value for mode
+     */
+    static public void setMode(int value) {
+	setInt("general.mode", GENERAL_SETTING, value);
+    }
+
+    static public void setPreviewCommand(String value) {
+	setString("general.preview_program", GENERAL_SETTING, value);
+    }
+
+    static public void setSiteAndServlet(String site, String servlet) {
+	site_name = site;
+	servlet_path = servlet;
+	setString("general.site_name", GENERAL_SETTING, site);
+	setString("general.servlet_path", GENERAL_SETTING, servlet);
+	
+    }
+    /** Sets the value of the named property argument using the given string. */
+    static public void setString(String property, boolean general, String value) {
+	DebugStream.println("Set configuration property: " + property + " = " + value + (general ? "" : " [Collection]"));
+	try {
+	    Document document = general_config;
+	    if(!general && collection_config != null) {
+		document = collection_config;
+	    }
+	    if(document != null) {
+		Element argument_element = null;
+		// Try to retrieve from cache
+		SoftReference reference = (SoftReference) self.get(property + general);
+		if(reference != null) {
+		    argument_element = (Element) reference.get();
+		}
+		if(argument_element == null) {
+		    Element document_element = document.getDocumentElement();
+		    Element gatherer_element = (Element) XMLTools.getNodeFromNamed(document_element, GATHERER_CONFIG);
+		    NodeList arguments = document_element.getElementsByTagName(GATHERER_CONFIG_ARGUMENT);
+		    boolean found = false;
+		    for(int i = 0; argument_element == null && i < arguments.getLength(); i++) {
+			Element possible_element = (Element) arguments.item(i);
+			if(possible_element.getAttribute(ARGUMENT_NAME).equalsIgnoreCase(property)) {
+			    argument_element = possible_element;
+			}
+		    }
+		    // If argument element is still null, create it in the target document.
+		    if(argument_element == null) {
+			argument_element = document.createElement(GATHERER_CONFIG_ARGUMENT);
+			argument_element.setAttribute(ARGUMENT_NAME, property);
+			gatherer_element.appendChild(argument_element);
+		    }
+		    // Update cache
+		    self.put(property + general, new SoftReference(argument_element));
+
+		}
+		if(value == null) {
+		    value = "";
+		}
+		// Now remove any current text node children.
+		NodeList children = argument_element.getChildNodes();
+		for(int i = 0; i < children.getLength(); i++) {
+		    argument_element.removeChild(children.item(i));
+		}
+		// Add a new text node child with the new value
+		argument_element.appendChild(document.createTextNode(value));
+	    }
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+
+    static public void setWGetPath(String path) {
+	wget_path  = path;
+    }
+
+    static public void setWGetVersion(String version) {
+	wget_version_str = version;
+    }
+
+    static private void updateUI() {
+	// Buttons
+	UIManager.put("Button.select", new ColorUIResource(getColor("coloring.button_selected_background", false)));
+	UIManager.put("Button.background", new ColorUIResource(getColor("coloring.button_background", false)));
+	UIManager.put("Button.foreground", new ColorUIResource(getColor("coloring.button_foreground", false)));
+
+	UIManager.put("ToggleButton.background", new ColorUIResource(getColor("coloring.button_background", false)));
+	UIManager.put("ToggleButton.foreground", new ColorUIResource(getColor("coloring.button_foreground", false)));
+	UIManager.put("ToggleButton.select", new ColorUIResource(getColor("coloring.button_selected_background", false)));
+
+	// All the things with a lovely Collection green background
+	UIManager.put("OptionPane.background", new ColorUIResource(getColor("coloring.collection_heading_background", false)));
+	UIManager.put("Panel.background", new ColorUIResource(getColor("coloring.collection_heading_background", false)));
+	UIManager.put("Label.background", new ColorUIResource(getColor("coloring.collection_heading_background", false)));
+	UIManager.put("TabbedPane.background", new ColorUIResource(getColor("coloring.collection_heading_background", false)));
+	UIManager.put("SplitPane.background", new ColorUIResource(getColor("coloring.collection_heading_background", false)));
+	UIManager.put("CheckBox.background", new ColorUIResource(getColor("coloring.collection_heading_background", false)));
+
+
+	// Editable coloring
+	UIManager.put("ComboBox.background", new ColorUIResource(getColor("coloring.collection_tree_background", false))); // Indicate clickable
+	UIManager.put("Tree.background", new ColorUIResource(getColor("coloring.collection_tree_background", false)));
+	UIManager.put("Tree.textBackground", new ColorUIResource(getColor("coloring.collection_tree_background", false)));
+	UIManager.put("ProgressBar.background", new ColorUIResource(getColor("coloring.collection_tree_background", false)));
+	UIManager.put("TextArea.background", new ColorUIResource(getColor("coloring.collection_tree_background", false)));
+	UIManager.put("TextField.background", new ColorUIResource(getColor("coloring.editable_background", false)));
+	UIManager.put("Table.background", new ColorUIResource(getColor("coloring.collection_tree_background", false)));
+	UIManager.put("List.background", new ColorUIResource(getColor("coloring.collection_tree_background", false)));
+	UIManager.put("RadioButton.background", new ColorUIResource(getColor("coloring.collection_tree_background", false)));
+
+	// Selection color
+	UIManager.put("TabbedPane.selected", new ColorUIResource(getColor("coloring.collection_selection_background", false)));
+	UIManager.put("Tree.selectionBackground", new ColorUIResource(getColor("coloring.collection_selection_background", false)));
+	UIManager.put("ComboBox.selectionBackground", new ColorUIResource(getColor("coloring.collection_selection_background", false)));
+	UIManager.put("ProgressBar.selectionBackground", new ColorUIResource(getColor("coloring.collection_selection_background", false)));
+	UIManager.put("TextArea.selectionBackground", new ColorUIResource(getColor("coloring.collection_selection_background", false)));
+	UIManager.put("TextField.selectionBackground", new ColorUIResource(getColor("coloring.collection_selection_background", false)));
+	UIManager.put("List.selectionBackground", new ColorUIResource(getColor("coloring.collection_selection_background", false)));
+
+	// Scroll bar stuff
+	UIManager.put("ScrollBar.background", new ColorUIResource(getColor("coloring.scrollbar_background", false)));
+	UIManager.put("ScrollBar.thumb", new ColorUIResource(getColor("coloring.scrollbar_foreground", false)));
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/DebugStream.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/DebugStream.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/DebugStream.java	(revision 10506)
@@ -0,0 +1,120 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer;
+
+
+import java.io.*;
+import java.util.*;
+
+
+public class DebugStream
+{
+    static private boolean debugging_enabled = false;
+    static private PrintStream debug_stream = null;
+
+
+    static public void closeDebugStream()
+    {
+	if (debug_stream != null) {
+	    try {
+		debug_stream.flush();
+		debug_stream.close();
+	    }
+	    catch (Exception exception) {
+		exception.printStackTrace();
+	    }
+	}
+    }
+
+
+    static public void enableDebugging()
+    {
+	debugging_enabled = true;
+    }
+
+
+    static public boolean isDebuggingEnabled()
+    {
+	return debugging_enabled;
+    }
+
+
+    static synchronized public void print(Properties properties)
+    {
+	if (debugging_enabled) {
+	    if (debug_stream != null) {
+		properties.list(debug_stream);
+	    }
+	    properties.list(System.err);
+	}
+    }
+
+
+    /** Print a message to the debug stream. */
+    static synchronized public void print(String message)
+    {
+	if (debugging_enabled) {
+	    if (debug_stream != null) {
+		debug_stream.print(message);
+	    }
+	    System.err.print(message);
+	}
+    }
+
+
+    /** Print a message to the debug stream. */
+    static synchronized public void println(String message)
+    {
+	if (debugging_enabled) {
+	    if (debug_stream != null) {
+		debug_stream.println(message);
+	    }
+	    System.err.println(message);
+	}
+    }
+
+
+    /** Print a stack trace to the debug stream. */
+    static synchronized public void printStackTrace(Exception exception)
+    {
+	if (debugging_enabled && debug_stream != null) {
+	    exception.printStackTrace(debug_stream);
+	}
+	exception.printStackTrace();
+    }
+
+
+    static public void setDebugFile(String debug_file_path)
+    {
+	try {
+	    debug_stream = new PrintStream(new FileOutputStream(debug_file_path));
+	}
+	catch (Exception exception) {
+	    exception.printStackTrace();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/Dictionary.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/Dictionary.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/Dictionary.java	(revision 10506)
@@ -0,0 +1,360 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.plaf.*;
+import javax.swing.text.*;
+import javax.swing.tree.*;
+
+/** Extends the ResourceBundle class to allow for the automatic insertion of arguments.<BR>
+ * <BR>
+ * Property files usable by this class have the Backus-Naur form: <BR>
+ * <BR>
+ * FileLine ::= Comment | Mapping <BR>
+ * Comment  ::= '#' SString <BR>
+ * Mapping  ::= NZString ':' SString ( Argument SString )* <BR>
+ * NZString ::= ( Char | Int ) SString <BR>
+ * Argument ::= '{' Int '}' <BR>
+ * SString  ::= String . ['"','#',...] -> ['\"','\#',...] <BR>
+ * <BR>
+ * In order to add a new dictionary Locale, simply copy the existing dictionary.properties files, replace the values (Strings after the ':') with the new language specific ones being careful to maintain formatting and Gatherer placed arguments, then save the new dictionary as: <br>
+ * <BR>
+ * dictionary_<I>locale</I>.properties<BR>
+ * <BR>
+ * where locale is made of two two-letter codes seperated by an underscore. The first code is in lower-case and defines the language. The second is in upper-case and defines the country. For example the default dictionary could also correctly be called:
+ * <BR>
+ * dictionary_en_NZ.properties<BR>
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class Dictionary
+    extends HashMap {
+
+    /** The font used when displaying various html text. */
+    static private FontUIResource font = null;
+    /** A reference to remind us of the current locale. */
+    static private Locale locale = null;
+    /** The ResourceBundle which contains the raw key-value mappings.
+	Loaded from a file named "dictionary<I>locale</I>.properties. */
+    static private ResourceBundle dictionary = null;
+
+
+    public Dictionary(Locale locale, FontUIResource font)
+    {
+	super();
+
+	// Initialize
+	this.font = font;
+	this.locale = ((locale == null) ? Locale.getDefault() : locale);
+	this.dictionary = ResourceBundle.getBundle("dictionary", this.locale);
+    }
+
+
+    /** Retrieve the two letter code of the current language we are using, according to the stored locale.
+     * @return A <strong>String</strong> containing the two letter ISO639 language code.
+     */
+    static public String getLanguage()
+    {
+	return locale.getLanguage();
+    }
+
+
+    static public String get(String key)
+    {
+	return get(key, (String[]) null);
+    }
+
+
+    static public String get(String key, String arg)
+    {
+	String[] args = new String[1];
+	args[0] = arg;
+	return get(key, args);
+    }
+
+
+    /** 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 automatiically populated with formatting Strings of with argument String provided in the get call.
+     */
+    static public String get(String key, String[] args)
+    {
+	try {
+	    String initial_raw = dictionary.getString(key);
+
+	    // Convert into Unicode
+	    String initial = "";
+	    try {
+		// This "ISO-8859-1" looks out of place, but it is very important.
+		// It is essential to call getBytes with an 8-bit encoding, otherwise
+		// Java kindly deems some characters "undisplayable", and replaces
+		// them with question marks. This is NOT good.
+		initial = new String(initial_raw.getBytes("ISO-8859-1"), "UTF-8");
+	    }
+	    catch (Exception ex) {
+		System.err.println("Exception: " + ex);
+		ex.printStackTrace();
+		return initial_raw;
+	    }
+
+	    // 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('}');
+		int comment_mark = initial.indexOf('-', opening); // May not exist
+		if (comment_mark > closing) { // May also be detecting a later comment
+		    comment_mark = -1;
+		}
+		complete = complete + initial.substring(0, opening);
+
+		// Parse arg_num
+		String arg_str = null;
+		if (comment_mark != -1) {
+		    arg_str = initial.substring(opening + 1, comment_mark);
+		}
+		else {
+		    arg_str = initial.substring(opening + 1, closing);
+		}
+
+		if (closing + 1 < initial.length()) {
+		    initial = initial.substring(closing + 1);
+		}
+		else {
+		    initial = "";
+		}
+
+		// Insert argument
+		if (arg_str.equals("FONT")) {
+		    complete = complete + (font != null ? font.getFontName() : "Arial");
+		}
+		else {
+		    int arg_num = Integer.parseInt(arg_str);
+		    if (args != null && 0 <= arg_num && arg_num < args.length) {
+			complete = complete + args[arg_num];
+		    }
+		}
+	    }
+	    complete = complete + initial;
+
+	    return complete;
+	}
+	catch (Exception e) {
+	    System.err.println("Missing value for key: " + key);
+	    // DebugStream.printStackTrace(e);
+	    return key;
+	}
+    }
+
+
+    static public void registerBoth(Component component, String text_key, String tooltip_key)
+    {
+	setText(component, text_key);
+	setTooltip(component, tooltip_key);
+    }
+
+
+    static public void registerText(Component component, String text_key)
+    {
+	setText(component, text_key);
+    }
+
+
+    static public void registerText(Component component, String text_key, String[] args)
+    {
+	setText(component, text_key, args);
+    }
+
+
+    static public void registerTooltip(Component component, String tooltip_key)
+    {
+	setTooltip(component, tooltip_key);
+    }
+
+
+    static public void registerTooltipText(Component component, String tooltip)
+    {
+	setTooltipText(component, tooltip);
+    }
+
+
+    static public void setBoth(Component component, String text_key, String tooltip_key)
+    {
+	setText(component, text_key);
+	setTooltip(component, tooltip_key);
+    }
+
+
+    static public void setText(Component component, String text_key)
+    {
+	setText(component, text_key, null);
+    }
+
+
+    static public void setText(Component component, String text_key, String[] args)
+    {
+	if (component != null) {
+	    // Update the component using the AWTEvent queue
+	    SwingUtilities.invokeLater(new ComponentUpdateTask(component, get(text_key, args), null));
+	}
+    }
+
+
+    static public void setTooltip(Component component, String tooltip_key)
+    {
+	if (component != null) {
+	    // Update the component using the AWTEvent queue
+	    SwingUtilities.invokeLater(new ComponentUpdateTask(component, null, get(tooltip_key)));
+	}
+    }
+
+
+    static public void setTooltipText(Component component, String tooltip)
+    {
+	if (component != null) {
+	    // Update the component using the AWTEvent queue
+	    SwingUtilities.invokeLater(new ComponentUpdateTask(component, null, tooltip));
+	}
+    }
+
+
+    static private class ComponentUpdateTask
+	implements Runnable {
+
+	private Component component = null;
+	private String text = null;
+	private String tooltip = null;
+
+
+	public ComponentUpdateTask(Component component, String text, String tooltip)
+	{
+	    this.component = component;
+	    this.text = text;
+	    this.tooltip = tooltip;
+	}
+
+
+	public void run()
+	{
+	    // If the component has text
+	    if (text != null) {
+		if (component instanceof AbstractButton) {
+		    ((AbstractButton) component).setText(text);
+		}
+		else if (component instanceof Frame) {
+		    ((Frame) component).setTitle(text);
+		}
+		else if (component instanceof JDialog) {
+		    ((JDialog) component).setTitle(text);
+		}
+		else if (component instanceof JLabel) {
+		    ((JLabel) component).setText(text);
+		}
+		else if (component instanceof JProgressBar) {
+		    ((JProgressBar) component).setString(text);
+		}
+		else if (component instanceof JTextComponent) {
+		    ((JTextComponent) component).setText(text);
+		    ((JTextComponent) component).setCaretPosition(0);
+		}
+		else {
+		    System.err.println("Unhandled component: " + component.getClass());
+		}
+	    }
+
+	    // If the component has a tooltip
+	    if (tooltip != null) {
+		if (component instanceof JComponent) {
+		    ((JComponent) component).setToolTipText(tooltip);
+		}
+	    }
+	}
+    }
+
+
+    /**
+     * Register a tab pane component. This will be deprecated eventually. */
+    static public void register(JTabbedPane component)
+    {
+	if (component != null) {
+  	    String[] args = new String[component.getTabCount()];
+
+  	    // Iterate through the tabbed panes tabs, updating values and recording the original key of each item in args.
+	    for (int i = 0; i < args.length; i++) {
+  		if (args[i] == null) {
+  		    args[i] = component.getTitleAt(i);
+  		}
+  		String value = get(args[i], (String[]) null);
+  		String tooltip = get(args[i] + "_Tooltip", (String[]) null);
+  		JTabbedPaneChangeTask task = new JTabbedPaneChangeTask(component, i, value, tooltip);
+  		SwingUtilities.invokeLater(task);
+  	    }
+  	}
+    }
+
+
+    /** Updates a tabbed panes tab title and tooltip. */
+    static private class JTabbedPaneChangeTask
+    	implements Runnable {
+
+    	private JTabbedPane component;
+    	private int index;
+    	private String value;
+    	private String tooltip;
+
+    	public JTabbedPaneChangeTask(JTabbedPane component, int index, String value, String tooltip) {
+  	    this.component = component;
+    	    this.index = index;
+  	    this.value = value;
+   	    this.tooltip = tooltip;
+    	}
+
+   	public void run() {
+    	    component.setTitleAt(index, value);
+  	    component.setToolTipTextAt(index, tooltip);
+    	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GAuthenticator.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GAuthenticator.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GAuthenticator.java	(revision 10506)
@@ -0,0 +1,181 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import org.greenstone.gatherer.gui.GLIButton;
+
+/** Provides a graphic authenticator for network password requests.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class GAuthenticator
+    extends Authenticator
+{
+    static public Hashtable authentications = new Hashtable();
+
+    /** Indicates if this authentication prompt been cancelled, and if so rolls-back authentication. */
+    private boolean authentication_cancelled = false;
+    /** The button used to cancel a prompt. */
+    private JButton cancel_button = null;
+    /** The button used to submit the login/password. */
+    private JButton ok_button = null;
+    /** A reference to the dialog prompt created so inner classes can dispose of it. */
+    private JDialog dialog = null;
+    /** The password is a special starred out password field. */
+    private JPasswordField password = null;
+    /** The default size of this dialog. */
+    static final private Dimension SIZE = new Dimension(410,140);
+
+    /** Constructor. */
+    public GAuthenticator() {
+    }
+
+    /** Prompt the user for authentication using a pretty dialog box.
+     * @return A <strong>PasswordAuthentication</strong> object containing the login and password valuees the user has submitted.
+     * @see org.greenstone.gatherer.GAuthenticator.AuthenticationActionListener
+     * @see org.greenstone.gatherer.GAuthenticator.RequestFocusListener
+     */
+    protected PasswordAuthentication getPasswordAuthentication() {
+	// Component definition.
+	dialog = new JDialog (Gatherer.g_man, Dictionary.get("GAuthenticator.Title"), true);
+	dialog.setModal(true);
+	dialog.setSize(SIZE);
+	JPanel content_pane = (JPanel) dialog.getContentPane();
+	JLabel title_label = new JLabel(getRequestingPrompt());
+	JPanel user_panel = new JPanel();
+	JLabel username_label = new JLabel();
+	Dictionary.setText(username_label, "GAuthenticator.Username");
+	JTextField username = new JTextField();
+	Dictionary.setTooltip(username, "GAuthenticator.Username_Tooltip");
+	JPanel password_panel = new JPanel();
+	JLabel password_label = new JLabel();
+	Dictionary.setText(password_label, "GAuthenticator.Password");
+	password = new JPasswordField();
+	password.setEchoChar('*');
+	Dictionary.setTooltip(password, "GAuthenticator.Password_Tooltip");
+	JPanel button_panel = new JPanel();
+	ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_O);
+	Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Cancel", "General.Cancel_Tooltip");
+
+	// Connection
+	cancel_button.addActionListener(new AuthenticationActionListener(true));
+	ok_button.addActionListener(new AuthenticationActionListener(false));
+	password.addActionListener(new AuthenticationActionListener(false));
+	username.addActionListener(new RequestFocusListener(password));
+
+	// Layout
+	user_panel.setLayout(new GridLayout(1,2));
+	user_panel.add(username_label);
+	user_panel.add(username);
+
+	password_panel.setLayout(new GridLayout(1,2));
+	password_panel.add(password_label);
+	password_panel.add(password);
+
+	button_panel.setLayout(new GridLayout(1,2));
+	button_panel.add(ok_button);
+	button_panel.add(cancel_button);
+
+	content_pane.setLayout(new GridLayout(4,1,0,2));
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.add(title_label);
+	content_pane.add(user_panel);
+	content_pane.add(password_panel);
+	content_pane.add(button_panel);
+
+	// Position the window
+	Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+	dialog.setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	dialog.setVisible(true);
+	if(!authentication_cancelled) {
+	    // Store the authentication
+	    authentications.put(getRequestingHost() + ":" + getRequestingPort(), username.getText() + "@" + new String(password.getPassword()));
+	    return new PasswordAuthentication(username.getText(), password.getPassword());
+	} else {
+	    return null;
+	}
+    }
+
+
+    /** Detects actions upon any control that attempt to submit the current details for authentication. */
+    private class AuthenticationActionListener
+	implements ActionListener {
+	/** <i>true</i> if this authentication action cancels the authentication, <i>false</i> otherwise. */
+	private boolean cancel_action = false;
+	/** Constructor.
+	 * @param cancel_action <i>true</i> if this authentication action cancels the authentication, <i>false</i> otherwise.
+	 */
+	public AuthenticationActionListener(boolean cancel_action) {
+	    this.cancel_action = cancel_action;
+	}
+	/** Any implementation of an ActionListener must include this method so that we can be informed when an action has been performed on our registered controls, allowing us to dispose of the authentication dialog after determining if this is a submit action or a cancel one.
+	 * @param event An <strong>ActionEvent</strong> with information about the event that fired this method.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    authentication_cancelled = cancel_action;
+	    dialog.dispose();
+	}
+    }
+
+    /** This listener detects actions on registered controls, and when they occur ensures the focus is moved to some targetted component. */
+    private class RequestFocusListener
+	implements ActionListener {
+	/*The <strong>Component</strong> you wish to gain focus when an action is performed on a registered control. */
+	private Component target = null;
+	/** Constructor.
+	 * @param target The <strong>Component</strong> you wish to gain focus when an action is performed on a registered control.
+	 */
+	public RequestFocusListener(Component target) {
+	    this.target = target;
+	}
+	/** Any implementation of an ActionListener must include this method so that we can be informed when an action has been performed on our registered controls, allowing us to request focus in the target control.
+	 * @param event An <strong>ActionEvent</strong> with information about the event that fired this method.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    target.requestFocus();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/Gatherer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/Gatherer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/Gatherer.java	(revision 10506)
@@ -0,0 +1,962 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer;
+
+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.gatherer.Configuration;
+import org.greenstone.gatherer.GAuthenticator;
+import org.greenstone.gatherer.cdm.ClassifierManager;
+import org.greenstone.gatherer.cdm.PluginManager;
+import org.greenstone.gatherer.collection.CollectionManager;
+import org.greenstone.gatherer.feedback.ActionRecorderDialog;
+import org.greenstone.gatherer.file.FileManager;
+import org.greenstone.gatherer.file.FileAssociationManager;
+import org.greenstone.gatherer.gui.GUIManager;
+import org.greenstone.gatherer.gui.URLField;
+import org.greenstone.gatherer.gui.WarningDialog;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.ZipTools;
+
+
+/** Containing the top-level "core" for the Gatherer, this class is the
+ * common core for the GLI 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 John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class Gatherer
+{
+    static private Dimension size = new Dimension(800, 540);
+
+    /** Has the exit flag been set? */
+    static public boolean exit = false;
+
+    static private String gli_directory_path = null;
+    static private String gli_user_directory_path = null;
+
+    /** All of the external applications that must exit before we close the Gatherer. */
+    public Vector apps = new Vector();
+    static private String non_standard_collect_directory_path = null;
+    static public String open_collection_file_path = null;
+    /** A public reference to the FileAssociationManager. */
+    static public FileAssociationManager assoc_man;
+    /** A public reference to the CollectionManager. */
+    static public CollectionManager c_man;
+    /** a reference to the Servlet Configuration is GS3 */
+    static public ServletConfiguration servlet_config;
+    /** A public reference to the FileManager. */
+    static public FileManager f_man;
+    /** A public reference to the GUIManager. */
+    static public GUIManager g_man = null;
+    static private boolean g_man_built = false;
+
+    /** A static reference to ourselves. */
+    static public Gatherer self;
+    /** We are using the GLI for GS3 */
+    static public boolean GS3 = false;
+
+    static public boolean isApplet = false;
+    static public boolean isGsdlRemote = false;
+    static public String cgiBase = "";
+
+    // feedback stuff
+    /** is the feedback feature enabled? */
+    static public boolean feedback_enabled = true;
+    /** the action recorder dialog */
+    static public ActionRecorderDialog feedback_dialog = null;
+
+    // Refresh reasons
+    static public final int COLLECTION_OPENED   = 0;
+    static public final int COLLECTION_CLOSED   = 1;
+    static public final int COLLECTION_REBUILT  = 2;
+    static public final int PREFERENCES_CHANGED = 3;
+
+
+    /** Magic to allow Enter to fire the default button. */
+    static {
+      KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
+      Keymap map = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
+      map.removeKeyStrokeBinding(enter);
+    }
+
+
+    public Gatherer(String[] args) 
+    {
+	this.self = this;
+	JarTools.initialise(this); 
+
+	GetOpt go = new GetOpt(args);
+
+	// If feedback is enabled, set up the recorder dialog
+	if (go.feedback_enabled) {
+	    // Use the default locale for now - this will be changed by the Gatherer run method
+	    feedback_enabled = true;
+	    feedback_dialog = new ActionRecorderDialog(Locale.getDefault());
+	}
+
+	// If a gliserver URL has been specified, we're using remote building
+	if (go.gliserver_url_string != null) {
+	    isGsdlRemote = true;
+	    cgiBase = go.gliserver_url_string.substring(0, go.gliserver_url_string.lastIndexOf('/') + 1);
+
+	    // With remote building we use our own collect directory, since we can't use the Greenstone one
+	    setCollectDirectoryPath(getGLIUserDirectoryPath() + "collect" + File.separator);
+
+	    // We don't have a local Greenstone!
+	    go.gsdl_path = null;
+	}
+
+	// We have a local Greenstone
+	if (!isGsdlRemote) {
+	    LocalGreenstone.setDirectoryPath(go.gsdl_path);
+	}
+
+	// Users may specify a non-standard collect directory (eg. when running one GLI in a network environment)
+	if (go.collect_directory_path != null) {
+	    setCollectDirectoryPath(go.collect_directory_path);
+	}
+
+	// Special code for running with a remote Greenstone
+	if (isGsdlRemote) {
+	    Configuration.TEMPLATE_CONFIG_XML = "xml/configRemote.xml";
+	    Configuration.CONFIG_XML = "configRemote.xml";
+	    Configuration.GS3_CONFIG_XML = "config3Remote.xml";
+
+	    File collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	    if (!collect_directory.exists() && !collect_directory.mkdir()) {
+		System.err.println("Warning: Unable to make directory: " + collect_directory);
+	    }
+
+	    File plugins_dat_file = new File(getGLIUserDirectoryPath() + "plugins.dat");
+	    if (!plugins_dat_file.exists()) {
+		JarTools.extractFromJar("plugins.dat", getGLIUserDirectoryPath(), false);
+	    }
+
+	    File classifiers_dat_file = new File(getGLIUserDirectoryPath() + "classifiers.dat");
+	    if (!classifiers_dat_file.exists()) {
+		JarTools.extractFromJar("classifiers.dat", getGLIUserDirectoryPath(), false);
+	    }
+	}
+
+	init(go.gsdl_path, go.gsdl3_path, go.gsdl3_src_path, go.local_library_path, go.library_url_string, go.debug,
+	     go.perl_path, go.no_load, go.filename, go.site_name, go.servlet_path, go.wget_path);
+    }
+
+
+    public void init(String gsdl_path, String gsdl3_path, String gsdl3_src_path, String local_library_path,
+		     String library_url_string, boolean debug_enabled, String perl_path, 
+		     boolean no_load, String open_collection, 
+		     String site_name, String servlet_path, String wget_path) 
+    {
+	if (gsdl3_path != null && !gsdl3_path.equals("")) {
+	    this.GS3 = true;
+	} else {
+	    gsdl3_path = null;
+	    gsdl3_src_path = null;
+	}
+
+	// Create the debug stream if required
+	if (debug_enabled) {
+	    DebugStream.enableDebugging();
+
+	    Calendar now = Calendar.getInstance();
+	    String debug_file_path = "debug" + now.get(Calendar.DATE) + "-" + now.get(Calendar.MONTH) + "-" + now.get(Calendar.YEAR) + ".txt";
+
+	    // Debug file is created in the user's GLI directory
+	    debug_file_path = getGLIUserDirectoryPath() + debug_file_path;
+	    DebugStream.println("Debug file path: " + debug_file_path);
+	    DebugStream.setDebugFile(debug_file_path);
+	    DebugStream.print(System.getProperties());
+	}
+
+	try {
+	    // Load GLI config file
+	    new Configuration(getGLIUserDirectoryPath(), gsdl_path, gsdl3_path, gsdl3_src_path, site_name);
+	    if (Configuration.just_updated_config_xml_file) {
+		// Delete the plugins.dat and classifiers.dat files
+		PluginManager.clearPluginCache();
+		ClassifierManager.clearClassifierCache();
+	    }
+
+	    if (GS3) {
+		// Load Greenstone 3 servelt configuration
+		servlet_config = new ServletConfiguration(gsdl3_path);
+	    }
+
+	    // Check we know where Perl is
+	    Configuration.perl_path = perl_path;
+	    if (isGsdlRemote && Utility.isWindows() && Configuration.perl_path != null) {
+		if (Configuration.perl_path.toLowerCase().endsWith("perl.exe")) {
+		    Configuration.perl_path = Configuration.perl_path.substring(0, Configuration.perl_path.length() - "perl.exe".length());
+		}
+		if (Configuration.perl_path.endsWith(File.separator)) {
+		    Configuration.perl_path = Configuration.perl_path.substring(0, Configuration.perl_path.length() - File.separator.length());
+		}
+	    }
+
+	    if (GS3 && Configuration.servlet_path == null) {
+		Configuration.servlet_path = servlet_config.getServletPath(Configuration.site_name);
+	    }
+
+	    // the feedback dialog has been loaded with a default locale, 
+	    // now set the user specified one
+	    if (feedback_enabled && feedback_dialog != null) {
+		feedback_dialog.setLocale(Configuration.getLocale("general.locale", true));
+	    }
+
+	    // Read Dictionary
+	    new Dictionary(Configuration.getLocale("general.locale", true), Configuration.getFont("general.font", true));
+
+	    // check that we are using Sun Java
+	    String java_vendor = System.getProperty("java.vendor");
+	    if (!java_vendor.equals("Sun Microsystems Inc.")) {
+		System.err.println(Dictionary.get("General.NotSunJava", java_vendor));
+	    }
+
+	    // Unless we're using remote building, we need to know where the local Greenstone is
+	    if (!isGsdlRemote && gsdl_path == null) {
+		missingGSDL();
+	    }
+
+	    // Start up the local library server, if that's what we want
+	    if (Utility.isWindows() && local_library_path != null && !isGsdlRemote && !GS3) {
+		LocalLibraryServer.start(gsdl_path, local_library_path);
+	    }
+
+	    // The "-library_url" option overwrites anything in the config files
+	    if (library_url_string != null && library_url_string.length() > 0) {
+		try {
+		    System.err.println("Setting library_url to " + library_url_string + "...");
+		    Configuration.library_url = new URL(library_url_string);
+		}
+		catch (MalformedURLException error) {
+		    DebugStream.printStackTrace(error);
+		}
+	    }
+
+	    // Check that we now know the Greenstone library URL, since we need this for previewing collections
+	    DebugStream.println("Configuration.library_url = " + Configuration.library_url);
+	    if (Configuration.library_url == null) {
+		missingEXEC();
+	    }
+
+	    // Check for ImageMagick
+	    if (Gatherer.isGsdlRemote) {
+		DebugStream.println("Not checking for ImageMagick.");
+	    }
+	    else if (!(new ImageMagickTest()).found()) {
+		// Time for a warning message
+		missingImageMagick();
+	    }
+
+	    if (Gatherer.isGsdlRemote) {
+		DebugStream.println("Not checking for perl path/exe");
+	    }
+	    else {
+		// Perl path is a little different as it is perfectly ok to
+		// start the GLI without providing a perl path
+		boolean found_perl = false;
+		if (Configuration.perl_path != null) {
+		    // See if the file pointed to actually exists
+		    File perl_file = new File(Configuration.perl_path);
+		    found_perl = perl_file.exists();
+		    perl_file = null;
+		}
+		if (Configuration.perl_path == null || !found_perl) {
+		    // Run test to see if we can run perl as is.
+		    PerlTest perl_test = new PerlTest();
+		    if (perl_test.found()) {
+			// If so replace the perl path with the system
+			// default (or null for unix).
+			Configuration.perl_path = perl_test.toString();
+			found_perl = true;
+		    }
+		}
+		if (!found_perl) {
+		    // Time for an error message.
+		    missingPERL();
+		}
+	    }
+
+	    boolean download_workflow = Configuration.get("workflow.download", false);
+	    if (download_workflow) {
+		// If the WGet path hasn't been specified by the user, try the Greenstone one
+		if (wget_path == null) {
+		    String wget_file_path = gsdl_path + "bin" + File.separator;
+		    if (Utility.isWindows()) {
+			wget_file_path += "windows" + File.separator + "wget.exe";
+		    }
+		    else if (Utility.isMac()) {
+			wget_file_path += "darwin" + File.separator + "wget";
+		    }
+		    else {
+			wget_file_path += "linux" + File.separator + "wget";
+		    }
+		    if (new File(wget_file_path).exists()) {
+			wget_path = wget_file_path;
+		    }
+		}
+
+		// If we still don't have a WGet path, give up (there isn't anything else we can do)
+		String wget_version_str = null;
+		if (wget_path == null) {
+		    wget_version_str = StaticStrings.NO_WGET_STR;
+		    missingWGET();
+		}
+		// Otherwise check the version of WGet
+		else {
+		    wget_version_str = testWGetVersion(wget_path);
+		    if (wget_version_str.equals(StaticStrings.WGET_OLD_STR)) {
+			oldWGET();
+		    }
+		}
+
+		// Store the new values in the configuration
+		DebugStream.println("WGet path: " + wget_path);
+		Configuration.setWGetPath(wget_path);
+		Configuration.setWGetVersion(wget_version_str);
+	    }
+
+	    // Set the default font for all Swing components.
+	    FontUIResource default_font = Configuration.getFont("general.font", true);
+	    Enumeration keys = UIManager.getDefaults().keys();
+	    while (keys.hasMoreElements()) {
+		Object key = keys.nextElement();
+		Object value = UIManager.get(key);
+		if (value instanceof FontUIResource) {
+		    UIManager.put(key, default_font);
+		}
+	    }
+
+	    // Set up proxy
+	    setProxy();
+	    // Now we set up an Authenticator
+	    Authenticator.setDefault(new GAuthenticator());
+
+	    assoc_man = new FileAssociationManager();
+	    // Create File Manager
+	    f_man = new FileManager();
+	    // Create Collection Manager
+	    c_man = new CollectionManager();
+
+	    if (GS3) {
+		if (site_name==null) {
+		    site_name = Configuration.site_name;
+		    servlet_path = null; // need to reset this
+		}
+		if (servlet_path == null) {
+		    servlet_path = Configuration.getServletPath();
+		}
+	    }
+
+	    open_collection_file_path = open_collection;
+	    if (open_collection_file_path == null) {
+		open_collection_file_path = Configuration.getString("general.open_collection", true);
+	    }
+	    if (no_load || open_collection_file_path.equals("")) {
+		open_collection_file_path = null;
+	    }
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+
+	// Create GUI Manager (last) or else suffer the death of a thousand NPE's
+	g_man = new GUIManager(size);
+    }
+
+
+    public void openGUI()
+    {
+	// Size and place the frame on the screen
+	Rectangle bounds = Configuration.getBounds("general.bounds", true);
+	if (bounds == null) {
+	    // Choose a sensible default value
+	    bounds = new Rectangle(0, 0, 640, 480);
+	}
+	
+	// Ensure width and height are reasonable
+	size = bounds.getSize();
+	if (size.width < 640) {
+	    size.width = 640;
+	}
+	else if (size.width > Configuration.screen_size.width) {
+	    size.width = Configuration.screen_size.width;
+	}
+	if (size.height < 480) {
+	    size.height = 480;
+	}
+	else if (size.height > Configuration.screen_size.height) {
+	    size.height = Configuration.screen_size.height;
+	}
+
+	if (!g_man_built) {
+
+	    g_man.display();
+
+	    // Place the window in the desired location on the screen, if this is do-able (not under most linux window managers apparently. In fact you're lucky if they listen to any of your screen size requests).
+	    g_man.setLocation(bounds.x, bounds.y);
+	    g_man.setVisible(true);
+
+	    // After the window has been made visible, check that it is in the correct place
+	    // sometimes java places a window not in the correct place, 
+	    // but with an offset. If so, we work out what the offset is
+	    // and change the desired location to take that into account 
+	    Point location = g_man.getLocation();
+	    int x_offset = bounds.x - location.x;
+	    int y_offset = bounds.y - location.y;
+	    // If not, offset the window to move it into the correct location
+	    if (x_offset > 0 || y_offset > 0) {
+		///ystem.err.println("changing the location to "+(bounds.x + x_offset)+" "+ (bounds.y + y_offset));
+		g_man.setLocation(bounds.x + x_offset, bounds.y + y_offset);
+	    }
+
+	    // The 'after-display' triggers several events which don't occur until after the visual components are actually available on screen. Examples of these would be the various html renderings, as they can't happen offscreen.
+	    g_man.afterDisplay();
+	    g_man_built = true;
+	}
+	else {
+	    g_man.setVisible(true);
+	}
+    }
+
+
+    /** Exits the Gatherer after ensuring that things needing saving are saved.
+     * @see java.io.FileOutputStream
+     * @see java.io.PrintStream
+     * @see java.lang.Exception
+     * @see javax.swing.JOptionPane
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     * @see org.greenstone.gatherer.gui.GUIManager
+     */
+    public void exit()
+    {
+	System.err.println("In Gatherer.exit()...");
+	exit = true;
+
+	// Save the file associations
+	if (assoc_man != null) {
+	    assoc_man.save();
+	    assoc_man = null;
+	}
+
+	// Get the gui to deallocate
+	g_man.destroy();
+	g_man_built = false;
+
+	// Flush debug
+	DebugStream.closeDebugStream();
+
+	// If we started a server, we should try to stop it.
+	if (LocalLibraryServer.isRunning() == true) {
+	    LocalLibraryServer.stop();
+	}
+
+	// Make sure we haven't started up any processes that are still running
+	if (apps.size() == 0) {
+	    // If we're running as an applet we don't actually quit (just hide the main GLI window)
+	    if (!Gatherer.isApplet) {
+		// This is the end...
+		System.exit(0);
+	    }
+	}
+	else {
+	    JOptionPane.showMessageDialog(g_man, Dictionary.get("General.Outstanding_Processes"), Dictionary.get("General.Outstanding_Processes_Title"), JOptionPane.ERROR_MESSAGE);
+	    g_man.setVisible(false);
+	}
+    }
+
+
+    /** Returns the path of the Greenstone "collect" directory. */
+    static public String getCollectDirectoryPath()
+    {
+	if (non_standard_collect_directory_path != null) {
+	    return non_standard_collect_directory_path;
+	}
+
+	if (!GS3) {
+	    return Configuration.gsdl_path + "collect" + File.separator;
+	}
+	else {
+	    return getSitesDirectoryPath() + Configuration.site_name + File.separator + "collect" + File.separator;
+	}
+    }
+
+
+    /** Returns the path of the GLI directory. */
+    static public String getGLIDirectoryPath()
+    {
+	return gli_directory_path;
+    }
+
+
+    /** Returns the path of the GLI "metadata" directory. */
+    static public String getGLIMetadataDirectoryPath()
+    {
+	return getGLIDirectoryPath() + "metadata" + File.separator;
+    }
+
+
+    /** Returns the path of the GLI user directory. */
+    static public String getGLIUserDirectoryPath()
+    {
+	return gli_user_directory_path;
+    }
+
+
+    /** Returns the path of the GLI user "cache" directory. */
+    static public String getGLIUserCacheDirectoryPath()
+    {
+	return getGLIUserDirectoryPath() + "cache" + File.separator;
+    }
+
+
+    /** Returns the path of the GLI user "log" directory. */
+    static public String getGLIUserLogDirectoryPath()
+    {
+	return getGLIUserDirectoryPath() + "log" + File.separator;
+    }
+
+
+    static public String getSitesDirectoryPath()
+    {
+	return Configuration.gsdl3_path + "sites" + File.separator;
+    }
+
+
+    static public void setCollectDirectoryPath(String collect_directory_path)
+    {
+	non_standard_collect_directory_path = collect_directory_path;
+	if (!non_standard_collect_directory_path.endsWith(File.separator)) {
+	    non_standard_collect_directory_path = non_standard_collect_directory_path + File.separator;
+	}
+    }
+
+
+    static public void setGLIDirectoryPath(String gli_directory_path_arg)
+    {
+	gli_directory_path = gli_directory_path_arg;
+    }
+
+
+    static public void setGLIUserDirectoryPath(String gli_user_directory_path_arg)
+    {
+	gli_user_directory_path = gli_user_directory_path_arg;
+
+	// Ensure the GLI user directory exists
+	File gli_user_directory = new File(gli_user_directory_path);
+	if (!gli_user_directory.exists() && !gli_user_directory.mkdirs()) {
+	    System.err.println("Error: Unable to make directory: " + gli_user_directory);
+	}
+    }
+
+
+    static public void refresh(int refresh_reason)
+    {
+	if (g_man != null) {
+	    g_man.refresh(refresh_reason, c_man.ready());
+	}
+
+	// Now is a good time to force a garbage collect
+	System.gc();
+    }
+
+
+    // used to send reload coll messages to the tomcat server
+    static public void configGS3Server(String site, String command) {
+
+	try {
+	    // need to add the servlet name to the exec address
+	    String raw_url = Configuration.library_url.toString() + Configuration.getServletPath() + command;
+	    URL url = new URL(raw_url);
+	    DebugStream.println("Action: " + raw_url);
+	    HttpURLConnection library_connection = (HttpURLConnection) url.openConnection();
+	    int response_code = library_connection.getResponseCode();
+	    if(HttpURLConnection.HTTP_OK <= response_code && response_code < HttpURLConnection.HTTP_MULT_CHOICE) {
+		DebugStream.println("200 - Complete.");
+	    }
+	    else {
+		DebugStream.println("404 - Failed.");
+	    }
+	    url = null;
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+
+
+    /** Used to 'spawn' a new child application when a file is double clicked.
+     * @param file The file to open 
+     * @see org.greenstone.gatherer.Gatherer.ExternalApplication
+     */
+    public void spawnApplication(File file) {
+	String [] commands = assoc_man.getCommand(file);
+	if(commands != null) {
+	    ExternalApplication app = new ExternalApplication(commands);
+	    apps.add(app);
+	    app.start();
+	}
+	else {
+	    ///ystem.err.println("No open command available.");
+	}
+    }
+
+
+    public void spawnApplication(String command)
+    {
+	ExternalApplication app = new ExternalApplication(command);
+	apps.add(app);
+	app.start();
+    }
+
+
+    /** Used to 'spawn' a new  browser application or reset an existing one when the preview button is clicked 
+     * @param url The url to open the browser at
+     * @see org.greenstone.gatherer.Gatherer.BrowserApplication
+     */    
+    public void spawnBrowser(String url) {
+	String command = assoc_man.getBrowserCommand(url);
+	if (command != null) {
+	    BrowserApplication app = new BrowserApplication(command, url);
+	    apps.add(app);
+	    app.start();
+	}
+	else {
+	    ///ystem.err.println("No browser command available."); 
+	}
+    }
+
+
+    /** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
+     */
+    static public void missingEXEC() {
+	WarningDialog dialog;
+	if (GS3) {
+	    dialog = new WarningDialog("warning.MissingEXEC_GS3", "MissingEXEC_GS3.Title", Dictionary.get("MissingEXEC_GS3.Message"), "general.library_url", false);
+	}
+	else {
+	    dialog = new WarningDialog("warning.MissingEXEC", "MissingEXEC.Title", Dictionary.get("MissingEXEC.Message"), "general.library_url", false);
+	}
+	dialog.setValueField(new URLField(Configuration.getColor("coloring.editable_foreground", false), Configuration.getColor("coloring.editable_background", false), Configuration.getColor("coloring.error_foreground", false), Configuration.getColor("coloring.error_background", false)));
+	dialog.display();
+	dialog.dispose();
+	dialog = null;
+
+	String library_url_string = Configuration.getString("general.library_url", true);
+	if (!library_url_string.equals("")) {
+	    try {
+		Configuration.library_url = new URL(library_url_string);
+	    }
+	    catch (MalformedURLException exception) {
+		DebugStream.printStackTrace(exception);
+	    }
+	}
+    }
+
+
+    /** Prints a warning message about a missing GSDL path, which although not fatal pretty much ensures nothing will work properly in the GLI.
+     */
+    static public void missingGSDL() {
+	WarningDialog dialog = new WarningDialog("warning.MissingGSDL", "MissingGSDL.Title", Dictionary.get("MissingGSDL.Message"), null, false);
+	dialog.display();
+	dialog.dispose();
+	dialog = null;
+    }
+
+    /** Prints a warning message about missing a valid ImageMagick path, which although not fatal means building image collections won't work */
+    static public void missingImageMagick() {
+	WarningDialog dialog = new WarningDialog("warning.MissingImageMagick", "MissingImageMagick.Title", Dictionary.get("MissingImageMagick.Message"), null, false);
+	dialog.display();
+	dialog.dispose();
+	dialog = null;
+    }
+
+    /** Prints a warning message about missing a valid PERL path, which although not fatal pretty much ensures no collection creation/building will work properly in the GLI. */
+    static public void missingPERL() {
+	WarningDialog dialog = new WarningDialog("warning.MissingPERL", "MissingPERL.Title", Dictionary.get("MissingPERL.Message"), null, false);
+	dialog.display();
+	dialog.dispose();
+	dialog = null;
+    }
+
+    /** Prints a warning message about missing a valid WGet path, which although not fatal means mirroring won't work */
+    static public void missingWGET() {
+	WarningDialog dialog = new WarningDialog("warning.MissingWGET", "MissingWGET.Title", Dictionary.get("MissingWGET.Message"), null, false);
+	dialog.display();
+	dialog.dispose();
+	dialog = null;
+    }
+
+    /** Prints a warning message about having an old version of WGet. not fatal, but mirroring may not work properly */
+    static public void oldWGET() {
+	WarningDialog dialog = new WarningDialog("warning.OldWGET", "OldWGET.Title", Dictionary.get("OldWGET.Message"), null, false);
+	dialog.display();
+	dialog.dispose();
+	dialog = null;
+    }
+
+
+    /** Sets up the proxy connection by setting JVM Environment flags and creating a new Authenticator.
+     * @see java.lang.Exception
+     * @see java.lang.System
+     * @see java.net.Authenticator
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.GAuthenticator
+     */
+    static public void setProxy() {
+	try {// Can throw several exceptions
+	    if(Configuration.get("general.use_proxy", true)) {
+		System.setProperty("http.proxyType", "4");
+		System.setProperty("http.proxyHost", Configuration.getString("general.proxy_host", true));
+		System.setProperty("http.proxyPort", Configuration.getString("general.proxy_port", true));
+		System.setProperty("http.proxySet", "true");
+	    } else {
+		System.setProperty("http.proxySet", "false");
+	    }
+	} catch (Exception error) {
+	    DebugStream.println("Error in Gatherer.initProxy(): " + error);
+	    DebugStream.printStackTrace(error);
+	}
+    }
+
+
+    // TODO fill this in
+    private String testWGetVersion(String wget_path) {
+	return StaticStrings.WGET_STR;
+    }
+    
+    /** This private class contains an instance of an external application running within a JVM shell. It is important that this process sits in its own thread, but its more important that when we exit the Gatherer we don't actually System.exit(0) the Gatherer object until the user has volunteerily ended all of these child processes. Otherwise when we quit the Gatherer any changes the users may have made in external programs will be lost and the child processes are automatically deallocated. */
+    private class ExternalApplication
+	extends Thread {
+	private Process process = null;
+	/** The initial command string given to this sub-process. */
+	private String command = null;
+	private String[] commands = null;
+	/** Constructor.
+	 * @param command The initial command <strong>String</strong>.
+	 */
+	public ExternalApplication(String command) {
+	    this.command = command;
+	}
+
+	public ExternalApplication(String[] commands) {
+	    this.commands = commands;
+	}
+	/** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
+	 * @see java.lang.Exception
+	 * @see java.lang.Process
+	 * @see java.lang.Runtime
+	 * @see java.lang.System
+	 * @see java.util.Vector
+	 */
+	public void run() {
+	    // Call an external process using the args.
+	    try {
+		if(commands != null) {
+		    StringBuffer whole_command = new StringBuffer();
+		    for(int i = 0; i < commands.length; i++) {
+			whole_command.append(commands[i]);
+			whole_command.append(" ");
+		    }
+		    DebugStream.println("Running " + whole_command.toString());
+		    Runtime rt = Runtime.getRuntime();
+		    process = rt.exec(commands);
+		    process.waitFor();
+		}
+		else {
+		    DebugStream.println("Running " + command);
+		    Runtime rt = Runtime.getRuntime();
+		    process = rt.exec(command);
+		    process.waitFor();
+		}
+	    }
+	    catch (Exception exception) {
+		DebugStream.printStackTrace(exception);
+	    }
+	    // Remove ourself from Gatherer list of threads.
+	    apps.remove(this);
+	    // Call exit if we were the last outstanding child process thread.
+	    if (apps.size() == 0 && exit == true) {
+		System.exit(0);
+	    }
+	}
+	public void stopExternalApplication() {
+	    if(process != null) {
+		process.destroy();
+	    }
+	}
+    }
+    /** This private class contains an instance of an external application running within a JVM shell. It is important that this process sits in its own thread, but its more important that when we exit the Gatherer we don't actually System.exit(0) the Gatherer object until the user has volunteerily ended all of these child processes. Otherwise when we quit the Gatherer any changes the users may have made in external programs will be lost and the child processes are automatically deallocated. */
+    private class BrowserApplication
+	extends Thread {
+	private Process process = null;
+	/** The initial command string given to this sub-process. */
+	private String command = null;
+	private String url = null;
+	private String[] commands = null;
+
+	public BrowserApplication(String command, String url) {
+	    StringTokenizer st = new StringTokenizer(command);
+	    int num_tokens = st.countTokens();
+	    this.commands = new String [num_tokens];
+	    int i=0;
+	    while (st.hasMoreTokens()) {
+		commands[i] = st.nextToken();
+		i++;
+	    }
+	    //this.commands = commands;
+	    this.url = url;
+	}
+	/** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
+	 * @see java.lang.Exception
+	 * @see java.lang.Process
+	 * @see java.lang.Runtime
+	 * @see java.lang.System
+	 * @see java.util.Vector
+	 */
+	public void run() {
+	    // Call an external process using the args.
+	    if(commands == null) {
+		apps.remove(this);
+		return;
+	    }
+	    try {
+		String prog_name = commands[0];
+		String lower_name = prog_name.toLowerCase();
+		if (lower_name.indexOf("mozilla") != -1 || lower_name.indexOf("netscape") != -1) { 
+		    DebugStream.println("found mozilla or netscape, trying remote it");
+		    // mozilla and netscape, try using a remote command to get things in the same window
+		    String [] new_commands = new String[] {prog_name, "-raise", "-remote", "openURL("+url+",new-tab)"};
+		    printArray(new_commands);
+
+		    Runtime rt = Runtime.getRuntime();
+		    process = rt.exec(new_commands);
+		    int exitCode = process.waitFor();
+		    if (exitCode != 0) { // if Netscape or mozilla was not open
+			DebugStream.println("couldn't do remote, trying original command");
+			printArray(commands);
+			process = rt.exec(commands); // try the original command
+		    }
+		} else {
+		    // just run what we have been given
+		    StringBuffer whole_command = new StringBuffer();
+		    for(int i = 0; i < commands.length; i++) {
+			whole_command.append(commands[i]);
+			whole_command.append(" ");
+		    }
+		    DebugStream.println("Running " + whole_command.toString());
+		    Runtime rt = Runtime.getRuntime();
+		    process = rt.exec(commands);
+		    process.waitFor();
+		}
+	    }
+	    
+	    catch (Exception exception) {
+		DebugStream.printStackTrace(exception);
+	    }
+	    // Remove ourself from Gatherer list of threads.
+	    apps.remove(this);
+	    // Call exit if we were the last outstanding child process thread.
+	    if (apps.size() == 0 && exit == true) {
+		System.exit(0);
+	    }
+	}
+	public void printArray(String [] array) {
+	    for(int i = 0; i < array.length; i++) {
+		DebugStream.print(array[i]+" ");
+		System.err.println(array[i]+" ");
+	    }
+	}
+	public void stopBrowserApplication() {
+	    if(process != null) {
+		process.destroy();
+	    }
+	}
+    }
+
+
+    private class ImageMagickTest
+    {
+	public boolean found()
+	{
+	    try {
+		String[] command = new String[2];
+		command[0] = (Utility.isWindows() ? "identify.exe" : "identify");
+		command[1] = "-version";
+		Process image_magick_process = Runtime.getRuntime().exec(command);
+		image_magick_process.waitFor();
+		return (image_magick_process.exitValue() == 0);
+	    }
+	    catch (Exception exception) {
+		return false;
+	    }
+	}
+    }
+
+
+    private class PerlTest
+    {
+	private String[] command = new String[2];
+
+	public PerlTest()
+	{
+	    command[0] = (Utility.isWindows() ? Utility.PERL_EXECUTABLE_WINDOWS : Utility.PERL_EXECUTABLE_UNIX);
+	    command[1] = "-version";
+	}
+
+	public boolean found()
+	{
+	    try {
+		Process perl_process = Runtime.getRuntime().exec(command);
+		perl_process.waitFor();
+		return (perl_process.exitValue() == 0);
+	    }
+	    catch (Exception exception) {
+		return false;
+	    }
+	}
+
+	public String toString() {
+	    return command[0];
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GathererApplet.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GathererApplet.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GathererApplet.java	(revision 10506)
@@ -0,0 +1,192 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer;
+
+import java.applet.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.*;
+import javax.swing.JApplet;
+
+import java.io.*;
+import javax.swing.*;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.ZipTools;
+
+
+public class GathererApplet extends JApplet implements ActionListener
+{
+    private Gatherer gatherer = null;
+
+
+    protected String fullLibraryURL(String address) 
+    {
+	String full_address = "";
+
+        // make sure the URL has protocol, host, and file
+        if (address.startsWith("http:")) {
+            // the address has all the necessary components
+	    full_address = address;
+        } 
+	else if (address.startsWith("/")) {
+            // there is not protocol and host
+            URL document = getDocumentBase();
+	    int port_no = document.getPort();
+
+            String port = (port_no>0) ? ":" + port_no : "";
+            full_address = "http://" + document.getHost() + port  + address;
+	}
+
+	return full_address;
+    }
+
+
+    /* This is the entry point for the GLI applet */
+    public void init()
+    {
+	// Check if the user has agreed to the requested security settings
+	try {
+	    // Work-around to reduce number of 
+	    // 'Could not lock user prefs' error messages.
+	    // Thanks to Walter Schatz from the java forums.
+	    System.setProperty("java.util.prefs.syncInterval","2000000");
+	}
+	catch (Exception exception) {
+	    getContentPane().add(new JLabel("Greenstone Librarian Interface Applet deactivated", JLabel.CENTER));
+	    return;
+	}
+
+	// Ensure platform specific LAF
+	try {
+	    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+	}
+	catch (Exception exception) {
+	    exception.printStackTrace();
+	}
+
+	// Determine the GLI user directory path
+	String gli_user_directory_path = System.getProperty("user.home") + File.separator;
+        if (Utility.isWindows()) {
+	    String windows_home_parameter = getParameter("windowsHome");
+	    if (windows_home_parameter != null && !windows_home_parameter.equals("")) {
+		gli_user_directory_path = windows_home_parameter + File.separator + "GLI" + File.separator;
+	    }
+	    else {
+		gli_user_directory_path += "Application Data" + File.separator + "Greenstone" + File.separator + "GLI" + File.separator;
+	    }
+	}
+        else {
+            gli_user_directory_path += ".gli" + File.separator;
+        }
+	Gatherer.setGLIUserDirectoryPath(gli_user_directory_path);
+
+	// If we're running as an applet we don't have a local GLI, so use the user directory path as the GLI path
+	Gatherer.setGLIDirectoryPath(gli_user_directory_path);
+
+	// Set some global variables so we know how we're running
+	Gatherer.isApplet = true;
+	String library_url_string = fullLibraryURL(getParameter("gwcgi"));
+	String gliserver_url_string = library_url_string.substring(0, library_url_string.lastIndexOf('/') + 1) + "gliserver";
+
+        // String debug_param = getParameter("debug");
+        // if ((debug_param != null) && (debug_param.matches("true"))) {
+        //     go.debug = true;
+        // }
+
+	String[] args = { "-gliserver_url", gliserver_url_string,
+			  "-library_url", library_url_string,
+	                };
+
+	File collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	if (!collect_directory.exists()) {
+	    if (JarTools.isInJar("collect.zip")) {
+		// Dig out collect.zip from JAR file and unzip it (thereby
+		// creating collect directory and descendants.
+		//   This is done to seed gsdl home folder with config files
+		//   for documented example collections so "base this on
+		//   existing collection" works
+		ZipTools.unzipFromJar("collect.zip", Gatherer.getGLIUserDirectoryPath());
+	    }
+	    else {
+		// Prepare an empty collect dir for use
+		if (!collect_directory.mkdir()) {
+		    System.err.println("Warning: Unable to make directory: " + collect_directory);
+		}
+	    }
+	}
+
+	File metadata_directory = new File(Gatherer.getGLIMetadataDirectoryPath());
+	if (!metadata_directory.exists()) {
+	    // dig out metadata.zip from JAR file and unzip it
+	    ZipTools.unzipFromJar("metadata.zip", Gatherer.getGLIDirectoryPath());
+	}
+
+	// Create an instance of the Gatherer class, which will parse the args and prepare the rest of the GLI
+	gatherer = new Gatherer(args);
+
+	// Create a button for the user to press to open the GLI GUI
+	JButton launch_GLI_button = new JButton("Launch Greenstone Librarian Interface ...");
+	launch_GLI_button.addActionListener(this);
+	getContentPane().add(launch_GLI_button);
+    }
+
+
+
+    public void start() 
+    {
+	System.err.println("Start called");
+    }
+
+
+
+    public void stop()
+    {
+	System.err.println("Stop called");
+
+    }
+
+    public void destroy()
+    {
+	System.err.println("Destroy called");
+	gatherer.exit();
+	System.err.println("Done gatherer exit.");
+    }
+
+
+    public void actionPerformed(ActionEvent e)
+    {
+	gatherer.openGUI();
+
+	// If there was an open collection last session, reopen it
+	Gatherer.open_collection_file_path = Configuration.getString("general.open_collection", true);
+	if (Gatherer.open_collection_file_path != null && !Gatherer.open_collection_file_path.equals("")) {
+	    Gatherer.c_man.loadCollection(Gatherer.open_collection_file_path);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GathererProg.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GathererProg.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GathererProg.java	(revision 10506)
@@ -0,0 +1,87 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, NZDL Project, University of Waikato
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *########################################################################
+ */
+package org.greenstone.gatherer;
+
+
+import java.io.*;
+import javax.swing.*;
+import org.greenstone.gatherer.util.Utility;
+
+
+/**
+ * Containing the main() method, this class is the entry point for the
+ * stand-alone (non-Applet) GLI. The main point of this class is to set
+ * some stand-alone specific properties and then create an instance of the
+ * Gatherer class.
+ * @author John Thompson, NZDL Project, University of Waikato
+ */
+public class GathererProg
+{
+    /** The entry point into the stand-alone GLI.
+     * @param args A collection of arguments that may include: initial screen size, dictionary, path to the GSDL etc.
+     */
+    static public 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"); 
+	// => results in one message every 600 hours!
+
+	// Ensure platform specific LAF
+	try {
+	    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+	}
+	catch (Exception exception) {
+	    exception.printStackTrace();
+	}
+
+	// Determine the GLI user directory path
+	String gli_user_directory_path = System.getProperty("user.home") + File.separator;
+        if (Utility.isWindows()) {
+	    gli_user_directory_path += "Application Data" + File.separator + "Greenstone" + File.separator + "GLI" + File.separator;
+        }
+        else {
+            gli_user_directory_path += ".gli" + File.separator;
+        }
+	Gatherer.setGLIUserDirectoryPath(gli_user_directory_path);
+
+	// We have a local GLI
+	Gatherer.setGLIDirectoryPath(System.getProperty("user.dir") + File.separator);
+
+	// Create an instance of the Gatherer class, which will parse the args and prepare the rest of the GLI
+	Gatherer gatherer = new Gatherer(args);
+
+	// Display the GUI immediately
+	gatherer.openGUI();
+
+	// If there was an open collection last session, reopen it
+	if (Gatherer.open_collection_file_path != null) {
+	    Gatherer.c_man.loadCollection(Gatherer.open_collection_file_path);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GetOpt.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GetOpt.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/GetOpt.java	(revision 10506)
@@ -0,0 +1,235 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson and David Bainbridge, 
+ *         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.gatherer;
+
+import java.io.*;
+import org.greenstone.gatherer.util.StaticStrings; 
+import org.greenstone.gatherer.util.Utility;
+
+public class GetOpt
+{
+    public boolean debug = false; 
+    public boolean feedback_enabled = false;
+    public boolean no_load = false;
+
+    public String collect_directory_path = null;
+    public String filename = null;
+    public String gliserver_url_string = null;
+    public String gsdl_path = null;
+    public String gsdl3_path = null;
+    public String gsdl3_src_path = null;
+    public String library_url_string = null;
+    public String local_library_path = null;
+    public String perl_path = null;
+    public String site_name = null; // for GS3
+    public String servlet_path = null;
+    public String wget_path = null;
+
+
+    public GetOpt(String[] args)
+    {
+	// Default dictionary. Only used for starting error messages.
+	Dictionary dictionary = new Dictionary(null, null); 
+
+	// Parse arguments
+	int argument_index = 0;
+	String next_token = null;
+
+	while(argument_index < args.length || next_token != null) {
+	    // 1. We start by attempting to parse an argument name. An argument
+	    //    must start with a '-', and should not contain spaces. If
+	    //    anything else is encountered it is ignored.
+
+	    String argument_name = null;
+	    if(next_token == null) {
+		next_token = args[argument_index];
+		argument_index++;
+	    }
+
+	    if(next_token.startsWith(StaticStrings.MINUS_CHARACTER)) {
+		// Trim second '-' just to be kind to Unixy-type people
+		if(next_token.startsWith(StaticStrings.MINUS_CHARACTER + StaticStrings.MINUS_CHARACTER)) {
+		    argument_name = next_token.substring(1);
+		}
+		else {
+		    argument_name = next_token;
+		}
+	    }
+	    next_token = null;
+	    // 2. If we now have an argument name we continue by attempting
+	    //    to parse a value. A value is taken to be the sequence of
+	    //    space seperated Strings between the last argument name
+	    //    and up to but not including the next argument name. Of
+	    //    course an argument needn't have any value (ie -debug,
+	    //    -help), in which case value will be null.
+	    if(argument_name != null) {
+		String argument_value = null;
+		StringBuffer argument_value_buffer = new StringBuffer("");
+		while(argument_index < args.length && next_token == null) {
+		    next_token = args[argument_index];
+		    argument_index++;
+		    // If we just parsed an arbitary String then append it to value, followed by a single space
+		    if(!next_token.startsWith(StaticStrings.MINUS_CHARACTER)) {
+			argument_value_buffer.append(next_token);
+			argument_value_buffer.append(StaticStrings.SPACE_CHARACTER);
+			next_token = null;
+		    }
+		    // If the argument token retrieved is an argument name,
+		    // then leave it in next_token, which will cause the
+		    // argument parsing process to move onto the next step.
+		}
+		// If a value now exists in argument buffer, retrieve
+		// it. Remove the last character as it will be an erroneous
+		// space.
+		if(argument_value_buffer.length() > 0) {
+		    argument_value = argument_value_buffer.substring(0, argument_value_buffer.length() - 1);
+		}
+		
+		// 3. We now have the argument name, and any associated
+		//    value. We are ready to store the data in the
+		//    appropriate variables.
+		DebugStream.println("Parsed Argument: name=" + argument_name + (argument_value != null ? (", value=" + argument_value) : ", no value"));
+		// 3a. First those arguments that have no associated value
+		if(argument_value == null) {
+		    if(argument_name.equals(StaticStrings.HELP_ARGUMENT)) {
+			System.out.println(Dictionary.get("General.Usage"));
+			System.exit(0);
+		    }
+		    // Run GLI in debug mode. Produces debug log plus extra
+		    // messages.
+		    else if(argument_name.equals(StaticStrings.DEBUG_ARGUMENT)) {
+			debug = true;
+		    }
+		    // Run GLI with feedback enabled. 
+		    else if(argument_name.equals(StaticStrings.FEEDBACK_ARGUMENT)) {
+			feedback_enabled = true;
+		    }
+		    // Forces no loading on previous collection.
+		    else if(argument_name.equals(StaticStrings.NO_LOAD_ARGUMENT)) {
+			no_load = true;
+			filename = null;
+		    }
+		}
+		// 3b. Now for those that do
+		else {
+		    // Parse the path to the GSDL. Required argument.
+		    if(argument_name.equals(StaticStrings.GSDL_ARGUMENT)) {
+			if(argument_value.endsWith(File.separator)) {
+			    gsdl_path = argument_value;
+			}
+			else {
+			    gsdl_path = argument_value + File.separator;
+			}
+		    }
+		    // GSDL3 path
+		    if(argument_name.equals(StaticStrings.GSDL3_ARGUMENT)) {
+			if(argument_value.endsWith(File.separator)) {
+			    gsdl3_path = argument_value;
+			}
+			else {
+			    gsdl3_path = argument_value + File.separator;
+			}
+		    }
+		    // GSDL3 src path
+		    if(argument_name.equals(StaticStrings.GSDL3_SRC_ARGUMENT)) {
+			if(argument_value.endsWith(File.separator)) {
+			    gsdl3_src_path = argument_value;
+			}
+			else {
+			    gsdl3_src_path = argument_value + File.separator;
+			}
+		    }
+		    
+		    else if (argument_name.equals(StaticStrings.SITE_ARGUMENT)) {
+			site_name = argument_value;
+		    }
+		    else if (argument_name.equals(StaticStrings.SERVLET_ARGUMENT)) {
+			servlet_path = argument_value;
+		    }
+		    // Specify a non-standard collect directory to use (for running one GLI in a network environment)
+		    else if (argument_name.equals(StaticStrings.COLLECTDIR_ARGUMENT)) {
+			collect_directory_path = argument_value;
+			System.err.println("Non standard collect directory specified: " + collect_directory_path);
+		    }
+		    // Specify a collection to load initially. Could be used for file associations.
+		    else if(argument_name.equals(StaticStrings.LOAD_ARGUMENT)) {
+			filename = argument_value;
+			no_load = false;
+		    }
+		    // Parse the file path of the local library server
+		    else if (argument_name.equals(StaticStrings.LOCAL_LIBRARY_ARGUMENT)) {
+			local_library_path = argument_value;
+		    }
+		    // Manually specify the Greenstone library URL
+		    else if (argument_name.equals(StaticStrings.LIBRARY_URL_ARGUMENT)) {
+			library_url_string = argument_value;
+		    }
+		    // Specify the URL to the gliserver CGI script for remote collection building
+		    else if (argument_name.equals(StaticStrings.GLISERVER_URL_ARGUMENT)) {
+			gliserver_url_string = argument_value;
+		    }
+		    // Parse the path to PERL. If not provided it assumes
+		    // perl should be availble on the PATH.
+		    else if(argument_name.equals(StaticStrings.PERL_ARGUMENT)) {
+			perl_path = argument_value;
+			// Test whether this points to the Perl bin
+			// directory or the Perl executable itself.
+			File perl_file = new File(perl_path);
+			if(perl_file.isDirectory()) {
+			    // If this is windows we create a child file
+			    // perl.exe, otherwise we create perl
+			    if(Utility.isWindows()) {
+				perl_file = new File(perl_file, Utility.PERL_EXECUTABLE_WINDOWS);
+			    }
+			    else {
+				perl_file = new File(perl_file, Utility.PERL_EXECUTABLE_UNIX);
+			    }
+			    // And store this new path.
+			    perl_path = perl_file.getAbsolutePath();
+			    perl_file = null;
+			}
+			// Otherwise it is fine as it is
+		    }
+		    // Parse the path to WGet
+		    else if (argument_name.equals(StaticStrings.WGET_ARGUMENT)) {
+			// Check the specified WGet file exists
+			if (argument_value != null && !argument_value.equals("")) {
+			    File wget_file = new File(argument_value);
+			    if (wget_file.exists()) {
+				wget_path = argument_value;
+			    } 
+			}
+		    }
+		}
+	    }
+	    // Argument name was null, nothing to be done.
+	}
+	next_token = null;
+	// Arguments all parsed.
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/LocalGreenstone.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/LocalGreenstone.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/LocalGreenstone.java	(revision 10506)
@@ -0,0 +1,64 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer;
+
+
+import java.io.*;
+
+
+/**
+ * This class contains static functions that only make sense when running with a local Greenstone.
+ * None of these functions should be called if the GLI is using a remote Greenstone.
+ */
+public class LocalGreenstone
+{
+    static private String gsdl_directory_path = null;
+
+
+    static public String getBinScriptDirectoryPath()
+    {
+	return gsdl_directory_path + "bin" + File.separator + "script" + File.separator;
+    }
+
+
+    static public String getDirectoryPath()
+    {
+	return gsdl_directory_path;
+    }
+
+
+    static public String getTmpDirectoryPath()
+    {
+	return gsdl_directory_path + "tmp" + File.separator;
+    }
+
+
+    static public void setDirectoryPath(String gsdl_directory_path_arg)
+    {
+	gsdl_directory_path = gsdl_directory_path_arg;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/LocalLibraryServer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/LocalLibraryServer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/LocalLibraryServer.java	(revision 10506)
@@ -0,0 +1,240 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer;
+
+
+import java.io.*;
+import java.lang.*;
+import java.net.*;
+import javax.swing.*;
+import org.greenstone.gatherer.util.GSDLSiteConfig;
+
+
+public class LocalLibraryServer
+{
+    static final private String ADD_COMMAND = "?a=config&cmd=add-collection&c=";
+    static final private String RELEASE_COMMAND = "?a=config&cmd=release-collection&c=";
+    static final private String QUIT_COMMAND = "?a=config&cmd=kill";
+
+    static private GSDLSiteConfig gsdlsite_cfg_file = null;
+    static private boolean running = false;
+
+
+    static public void addCollection(String collection_name)
+    {
+	config(ADD_COMMAND + collection_name);
+	// This is very important -- it ensures that the above command has finished
+	config("");
+    }
+
+
+    // Used to send messages to the local library
+    // Warning: this has a lot of potential for nasty race conditions
+    // The response code is returned immediately -- but this does not mean the local
+    //   library action has finished!
+    static private void config(String command)
+    {
+	if (Configuration.library_url == null) {
+	    System.err.println("Error: Trying to configure local library with null Configuration.library_url!");
+	    return;
+	}
+
+	try {
+	    URL url = new URL(Configuration.library_url.toString() + command);
+	    HttpURLConnection library_connection = (HttpURLConnection) url.openConnection();
+	    int response_code = library_connection.getResponseCode();
+	    if (response_code >= HttpURLConnection.HTTP_OK && response_code < HttpURLConnection.HTTP_MULT_CHOICE) {
+		DebugStream.println("200 - Complete.");
+	    }
+	    else {
+		DebugStream.println("404 - Failed.");
+	    }
+	}
+	catch (Exception ex) {
+	    DebugStream.printStackTrace(ex);
+	}
+    }
+
+
+    static public boolean isRunning()
+    {
+	return running;
+    }
+
+
+    static public void releaseCollection(String collection_name)
+    {
+	config(RELEASE_COMMAND + collection_name);
+	// This is very important -- it ensures that the above command has finished
+	config("");
+    }
+
+
+    static public void start(String gsdl_path, String local_library_server_file_path)
+    {
+	// Check the local library server.exe file exists
+	File local_library_server_file = new File(local_library_server_file_path);
+	if (!local_library_server_file.exists()) {
+	    DebugStream.println("No local library at given file path.");
+
+	    local_library_server_file = new File(gsdl_path + "server.exe");
+	    if (!local_library_server_file.exists()) {
+		DebugStream.println("No local library at all.");
+		return;
+	    }
+	}
+
+	// Check if the server is already running
+	gsdlsite_cfg_file = new GSDLSiteConfig(local_library_server_file);
+	String url = gsdlsite_cfg_file.getURL();
+	if (url != null) {
+	    // If it is already running then set the Greenstone web server address and we're done
+	    try {
+		Configuration.library_url = new URL(url);
+		running = true;
+		return;
+	    }
+	    catch (MalformedURLException exception) {
+		DebugStream.printStackTrace(exception);
+	    }
+	}
+
+	// Configure the server for immediate entry
+	gsdlsite_cfg_file.set();
+
+	// Spawn local library server process
+	String local_library_server_command = local_library_server_file.getAbsolutePath() + " " + gsdlsite_cfg_file.getSiteConfigFilename();
+	Gatherer.self.spawnApplication(local_library_server_command);
+
+	// Wait until program has started, by reloading and checking the URL field
+	gsdlsite_cfg_file.load();
+	int attempt_count = 0;
+	while (gsdlsite_cfg_file.getURL() == null) {
+	    new OneSecondWait();  // Wait one second (give or take)
+	    gsdlsite_cfg_file.load();
+	    attempt_count++;
+
+	    // After waiting a minute ask the user whether they want to wait another minute
+	    if (attempt_count == 60) {
+		int try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("Server.QuitTimeOut"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
+		if (try_again == JOptionPane.NO_OPTION) {
+		    return;
+		}
+		attempt_count = 0;
+	    }
+	}
+
+	// Ta-da. Now the url should be available
+	try {
+	    Configuration.library_url = new URL(gsdlsite_cfg_file.getURL());
+	}
+	catch (MalformedURLException exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+
+	// A quick test involves opening a connection to get the home page for this collection
+	try {
+	    DebugStream.println("Try connecting to server on config url: '" + Configuration.library_url+ "'");
+	    URLConnection connection = Configuration.library_url.openConnection();
+	    connection.getContent();
+	}
+	catch (IOException bad_url_connection) {
+	    try {
+		// If this fails then we try changing the url to be localhost
+		Configuration.library_url = new URL(gsdlsite_cfg_file.getLocalHostURL());
+		DebugStream.println("Try connecting to server on local host: '" + Configuration.library_url + "'");
+		URLConnection connection = Configuration.library_url.openConnection();
+		connection.getContent();
+	    }
+	    catch (IOException worse_url_connection) {
+		DebugStream.println("Can't connect to server on either address.");
+		Configuration.library_url = null;
+		return;
+	    }
+	}
+
+	running = true;
+    }
+
+
+    static public void stop()
+    {
+	if (running == false) {
+	    return;
+	}
+
+	// Send the command for it to exit.
+	config(QUIT_COMMAND);
+
+	// Wait until program has stopped, by reloading and checking the URL field
+	gsdlsite_cfg_file.load();
+	int attempt_count = 0;
+	while (gsdlsite_cfg_file.getURL() != null) {
+	    new OneSecondWait();  // Wait one second (give or take)
+	    gsdlsite_cfg_file.load();
+	    attempt_count++;
+
+	    // After waiting a minute ask the user whether they want to wait another minute
+	    if (attempt_count == 60) {
+		int try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("Server.QuitTimeOut"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
+		if (try_again == JOptionPane.NO_OPTION) {
+		    return;
+		}
+		attempt_count = 0;
+	    }
+	}
+
+	//if(gsdlsite_cfg_file.getURL() != null) {
+	//JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Server.QuitManual"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	//}
+
+	// Restore the gsdlsite_cfg.
+	gsdlsite_cfg_file.restore();
+
+	// If the local server is still running then our changed values will get overwritten.
+	if (gsdlsite_cfg_file.getURL() != null) {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Server.QuitFailed"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	}
+
+	running = false;
+    }
+
+
+    static private class OneSecondWait
+    {
+	public OneSecondWait()
+	{
+	    synchronized(this) {
+		try {
+		    wait(1000);
+		}
+		catch (InterruptedException exception) {
+		}
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/ServletConfiguration.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/ServletConfiguration.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/ServletConfiguration.java	(revision 10506)
@@ -0,0 +1,157 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer;
+
+import java.awt.*;
+import java.io.*;
+import java.lang.ref.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.plaf.*;
+import org.greenstone.gatherer.util.ArrayTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/** This class stores the mapping between sites and servlets available for them. The info is read in from the web.xml file.
+ * @author Katherine Don, New Zealand Digital Library, University of Waikato
+ * @version 
+ */
+public class ServletConfiguration {
+    
+    static public String ADD_COMMAND = "?a=s&sa=a&st=collection&sn=";
+    static public String DEACTIVATE_COMMAND = "?a=s&sa=d&st=collection&sn=";
+    private String gsdl3_path = "";
+    private ArrayList sites = null;
+    private HashMap mappings = null;
+
+    public ServletConfiguration(String gsdl3_path) {
+	
+	this.gsdl3_path = gsdl3_path;
+	
+	//String web_xml_path = gsdl3_path + File.separator + "web" + File.separator + "WEB-INF"+ File.separator + "web.xml";
+	File web_xml = new File(gsdl3_path + "WEB-INF"+ File.separator + "web.xml");
+
+	if (!web_xml.exists()) {
+	    DebugStream.println("Error: no web.xml found at "+web_xml.toString());
+	    return;
+	}
+
+	this.sites = new ArrayList();
+	// find the sites
+	File start = new File(Utility.getSitesDir(gsdl3_path));
+	File possible_sites[] = start.listFiles();
+	ArrayTools.sort(possible_sites);
+	for (int i=0; possible_sites != null && i < possible_sites.length; i++) {
+	    File site_config = new File(possible_sites[i], "siteConfig.xml");
+	    if (site_config.exists()) {
+		this.sites.add(possible_sites[i].getName());
+	    }
+	}
+	
+	this.mappings = new HashMap();
+	Document web_config = XMLTools.parseXMLFile(web_xml.getAbsolutePath(), false);
+       
+	NodeList servlet_mappings = web_config.getElementsByTagName("servlet-mapping");
+	// make a little map class
+	HashMap url_mappings = new HashMap();
+	for (int i=0; i<servlet_mappings.getLength(); i++) {
+	    Element map = (Element)servlet_mappings.item(i);
+	    String name = XMLTools.getValue(XMLTools.getNodeFromNamed(map, "servlet-name"));
+	    String pattern = XMLTools.getValue(XMLTools.getNodeFromNamed(map, "url-pattern"));
+	    url_mappings.put(name, pattern);
+
+	}
+
+	NodeList servlets = web_config.getElementsByTagName("servlet");
+	for (int i=0; i<servlets.getLength(); i++) {
+	    Element servlet = (Element)servlets.item(i);
+	    String name = XMLTools.getValue(XMLTools.getNodeFromNamed(servlet, "servlet-name"));
+	    String description = XMLTools.getValue(XMLTools.getNodeFromNamed(servlet, "description"));
+	    String site = getServletSite(servlet);
+	       
+	    if (site != null) {
+		ArrayList this_site = (ArrayList)mappings.get(site);
+		if (this_site == null) {
+		    this_site = new ArrayList();
+		}
+		String url = (String)url_mappings.get(name);
+		this_site.add(url);
+		mappings.put(site, this_site);
+	    }
+	    
+	}
+
+	web_config = null;
+	url_mappings = null;
+    }
+    
+    public ArrayList getSites() {
+	return this.sites;
+    }
+
+    public ArrayList getServletsForSite(String site) {
+	return (ArrayList)this.mappings.get(site);
+    }
+    public String getServletPath(String site) {
+	
+	// for now, get the first one
+	ArrayList servlets = (ArrayList)mappings.get(site);
+	if(servlets == null) {
+	    return null;
+	}
+	return (String)servlets.get(0);
+    }
+
+    private String getServletSite(Element servlet) {
+	
+	NodeList params = servlet.getElementsByTagName("init-param");
+	if ( params == null || params.getLength() == 0) {
+	    return null;
+	}
+	String site = null;
+	for (int i=0; i<params.getLength()&& site == null; i++) {
+	    String p_name = XMLTools.getValue(XMLTools.getNodeFromNamed(params.item(i), "param-name"));
+	    if (p_name.equals("site_name")) {
+		site = XMLTools.getValue(XMLTools.getNodeFromNamed(params.item(i), "param-value"));
+	    }
+	}
+	return site;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/WGet.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/WGet.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/WGet.java	(revision 10506)
@@ -0,0 +1,325 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer;
+
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.collection.DownloadJob;
+
+/** This class provides access to the functionality of the WGet program, either by calling it via a shell script or by the JNI. It maintains a queue of pending jobs, and the component for showing these tasks to the user.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class WGet
+    extends Thread {
+
+    /** <i>true</i> if there is a task currently being carried out, <i>false</i> otherwise. */
+    private boolean busy = false;
+    /** <i>true</i> if verbose debug messages should be displayed, <i>false</i> otherwise. */
+    private boolean debug = false;
+    /** <i>true</i> if successfully completed tasks should be automatically removed from the job queue. */
+    private boolean remove_complete_jobs = true;
+
+    private JPanel filler_pane = null;
+    /** The panel that the task list will be shown in. */
+    private JPanel list_pane;
+    /** The job currently underway. */
+    private DownloadJob job;
+    /** A scroll pane which will be used to display the list of pending tasks. */
+    private JScrollPane list_scroll;
+    /** A queue of download tasks. */
+    private Vector job_queue;
+    /** A static flag used to switch between simple and advanced modes. If <i>true</i> the Process object is used to externally call the Wget program. If <i>false</i> the native WGet libraries are statically loaded and the JNI used to download directly. */
+    static final private boolean simple = true;
+    /** Load the WGet native library. */
+    static {
+	if(!simple) {
+	    System.load(System.getProperty("user.dir") + File.separator + "libgatherer.so");
+	}
+    }
+
+    /** Constructor. Nothing special. */
+    public WGet() {
+	job = null;
+	job_queue = new Vector();
+	filler_pane = new JPanel();
+	list_pane = new JPanel();
+	list_pane.setLayout(new BoxLayout(list_pane, BoxLayout.Y_AXIS));
+	//list_pane.setLayout(new GridLayout(height_count,1));
+	list_scroll = new JScrollPane(list_pane);
+	//list_scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+    }
+
+    /** Called by the WGet native code to inform us of a new download starting within the given job.
+     * @param url The url that is being downloaded, as a <strong>String</strong>.
+     * @see org.greenstone.gatherer.collection.DownloadJob
+     */
+    public synchronized void addDownload(String url) {
+	job.addDownload(url);
+    }
+
+    /* Used to advise the DownloadJob of a newly parsed link. Its up to DownloadJob to decide if it already knows about this url, and if not to update its progress bar.
+     * @param url The url in question as a <strong>String</strong>.
+     * @param type <i>true</i> if this is an internal link, <i>false</i> for and external one.
+     * @return A <i>boolean</i> with a value of <i>true</i> indicating if the url was added, <i>false</i> otherwise.
+     * @see org.greenstone.gatherer.collection.DownloadJob
+     */
+    public synchronized boolean addLink(String url, int type) {
+	return job.addLink(url, type);
+    }
+
+
+    /** This method is called to delete a certain job from the queue.
+     * This job may be pending, complete or even in progress. However
+     * if it is currently downloading then the delete method must
+     * wait until the native job has cleanly exited before removing
+     * the job.
+     * @param delete_me The <strong>DownloadJob</strong> that is to be deleted.
+     */
+    public void deleteDownloadJob(DownloadJob delete_me) {
+	if (delete_me == job) {
+	    // While this seems wasteful its only for the briefest moment.
+	    while(busy) {
+	    }
+	    job = null;
+	}
+	if (delete_me.hasSignalledStop()) {
+	    list_pane.remove(delete_me.getProgressBar());
+	    job_queue.remove(delete_me);
+	    // Unfortunately removing a task gets a bit more complicated as we have to resize the filler
+	    list_pane.remove(filler_pane);
+	    if(job_queue.size() > 0) {
+		Dimension progress_bar_size = delete_me.getProgressBar().getPreferredSize();
+		Dimension list_pane_size = list_pane.getSize();
+		int height = list_pane_size.height - (job_queue.size() * progress_bar_size.height);
+		progress_bar_size = null;
+		if(height > 0) {
+		    filler_pane.setPreferredSize(new Dimension(list_pane_size.width, height));
+		    list_pane.add(filler_pane);
+		}
+		list_pane_size = null;
+	    }
+	    list_pane.updateUI();
+	}
+	else {
+	    DebugStream.println("Somehow we're trying to delete a job that is still running.");
+	}
+    }
+
+    /** Called by the WGet native code when the current download,
+     * for the indicated job, is completed. In turn all download
+     * listeners are informed.
+     * @see org.greenstone.gatherer.collection.DownloadJob
+     */
+    public synchronized void downloadComplete() {
+	job.downloadComplete();
+    }
+
+    /** Called by the WGet native code when the requested download returns
+     * a status code other than 200-399 for the specified download job.
+     * for.
+     * @see org.greenstone.gatherer.collection.DownloadJob
+     */
+    public synchronized void downloadFailed() {
+	// Add the failed download as a new job if the user so requests.
+	job.downloadFailed();
+    }
+
+    /** Called by the WGet native code when some non-fatal error has caused
+     * a download to fail. An example of a warning would be if a file can't
+     * be downloaded as doing so would clobber an existing file and the -nc
+     * flag is set.
+     * @see org.greenstone.gatherer.collection.DownloadJob
+     */
+    public synchronized void downloadWarning() {
+	job.downloadWarning();
+    }
+
+    /** Used by other graphic functions to get a reference to the
+     * scroll pane containing the current list of jobs.
+     */
+    public JScrollPane getDownloadJobList() {
+	return list_scroll;
+    }
+
+    /** Returns the current state of the stop flag for the job indicated.
+     * @return A boolean representing whether the user has requested to
+     * stop.
+     * @see org.greenstone.gatherer.collection.DownloadJob
+     */
+    public synchronized boolean hasSignalledStop() {
+	return job.hasSignalledStop();
+    }
+
+    /** Creates a new mirroring job on the queue given the target url and the destination (private, public). All other details are harvested from the config file, but these two must be  captured from the GUI's current state.
+     * @param no_parents
+     * @param other_hosts
+     * @param page_requisites
+     * @param url a URL which points to the root url for the mirroring
+     * @param depth
+     * @param destination the destination file as a String
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.collection.DownloadJob
+     * @see org.greenstone.gatherer.gui.DownloadProgressBar
+     * @see org.greenstone.gatherer.util.GURL
+     */
+    public void newDownloadJob(boolean no_parents, boolean other_hosts, boolean page_requisites, URL url, int depth, String destination) {
+	// Create the job and fill in the details from gatherer.config.
+	DebugStream.println("About to create a new job");
+
+	DownloadJob new_job = new DownloadJob(Configuration.get("mirroring.debug", false), no_parents, other_hosts, page_requisites, Configuration.get("mirroring.quiet", false), url, depth, destination, Configuration.proxy_pass, Configuration.proxy_user, this, simple);
+
+	// Tell it to run as soon as possible
+	new_job.setState(DownloadJob.RUNNING);
+
+	// Add to job_queue job list.
+	job_queue.add(new_job);
+	// Now add it to the visual component, job list.
+	list_pane.remove(filler_pane);
+	Dimension progress_bar_size = new_job.getProgressBar().getPreferredSize();
+	Dimension list_pane_size = list_pane.getSize();
+	int height = list_pane_size.height - (job_queue.size() * progress_bar_size.height);
+	progress_bar_size = null;
+	list_pane.add(new_job.getProgressBar());
+	if(height > 0) {
+	    filler_pane.setPreferredSize(new Dimension(list_pane_size.width, height));
+	    list_pane.add(filler_pane);
+	}
+	list_pane_size = null;
+	//list_pane.setAlignmentX(Component.LEFT_ALIGNMENT);
+	list_pane.updateUI();
+	new_job = null;
+	synchronized(this) {
+	    notify(); // Just incase its sleeping.
+	}
+    }
+
+    /** Called by the WGet native code to signal the current progress of
+     * downloading for the specified job.
+     * @param current A long representing the number of bytes that have
+     * been downloaded since the last update.
+     * @param expected A long representing the total number of bytes
+     * expected for this download.
+     * @see org.greenstone.gatherer.collection.DownloadJob
+     */
+    public synchronized void updateProgress(long current, long expected) {
+	job.updateProgress(current, expected);
+    }
+
+    /* There may be times when the download thread is sleeping, but the
+     * user has indicated that a previously paused job should now begin
+     * again. The flag within the job will change, so we tell the thread
+     * to start again.
+     */
+    public void resumeThread() {
+	synchronized(this) {
+	    notify(); // Just incase its sleeping.
+	}
+    }
+
+    /* This begins the WGet thread, which simply iterates through the waiting
+     * jobs attempting each one. Successful downloads are removed from the
+     * waiting list.
+     * @see org.greenstone.gatherer.collection.DownloadJob
+     */
+    public void run() {
+	while(true) {
+	    // If there are jobs job_queue and we have more room.
+	    if(job_queue.size() > 0) {
+		int index = 0;
+		while(job_queue.size() > 0 && index < job_queue.size()) {
+		    // Get the first job that isn't stopped.
+		    job = (DownloadJob) job_queue.get(index);
+		    if(job.getState() == DownloadJob.RUNNING) {
+			DebugStream.println("DownloadJob " + job.toString() + " Begun.");
+			// A lock to prevent us deleting this job while its being
+			// run, unless you want things to go really wrong.
+			busy = true;
+			if(simple) {
+			    job.callWGet();
+			}
+			else {
+			    job.callWGetNative();
+			}
+			busy = false;
+			DebugStream.println("DownloadJob " + job.toString() + " complete.");
+			// And if the user has requested that complete jobs
+		       	// be removed, then remove it from the list.
+			//deleteDownloadJob(job);
+			job = null;
+		    }
+		    index++;
+		}
+	    }
+	    // In order to save processor time, I'll suspend the thread
+	    // if theres no advantage to it running. Actions such as
+	    // new or complete jobs will resume the thread.
+	    else {
+		try {
+		    synchronized(this) {
+			DebugStream.println("WGet thread is waiting for DownloadJobs.");
+			wait();
+		    }
+		} catch (InterruptedException e) {
+		    // Time to get going again.
+		}
+	    }
+	} // End While.
+    }
+    
+    /* Link to the call to the WGet Native method for downloading.
+     * @param argc An int representing the number of elements in argv.
+     * @param argv An array of objects passed as arguments to wget.
+     * @param debug Whether the native code should show java-only debug
+     * messages.
+     */
+    public native int wget(int argc, Object argv[], boolean debug);
+
+    /* Link to the call to the WGet Native method for converting url links.
+     * @param argc An int representing the number of object elements in argv.
+     * @param argv An array of objects passed as arguments to wget.
+     * @param urlc An int representing the number of url string elements in urlv.
+     * @param urlv An array of strings representing urls.
+     * @param filec An int representing the number of file string elements in filev.
+     * @param filev An array of strings representing files.
+     */
+    public native void wren(int argc, Object argv[], int urlc, Object urlv[], int filec, Object filev[]);
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Argument.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Argument.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Argument.java	(revision 10506)
@@ -0,0 +1,621 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Greenstone Librarian Interface (GLI) application, 
+ * part of the Greenstone digital library software suite from the New 
+ * Zealand Digital Library Project at the University of Waikato, 
+ * New Zealand.
+ *
+ * Author: John Thompson 
+ *         Greenstone Project, New Zealand Digital Library
+ *         University of Waikato
+ *         http://www.nzdl.org
+ *
+ * Copyright (C) 2004 New Zealand Digital Library, University of Waikato
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the 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.gatherer.cdm;
+
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.Collection;
+import org.greenstone.gatherer.collection.CollectionManager;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/** This class contains all the details about a single argument that can be passed to this plugin, including option lists if the parameters are restricted.
+ * @author John Thompson, Greenstone Project, New Zealand Digital Library, University of Waikato
+ * @version 2.41 final
+ */
+public class Argument
+    implements Comparable, Serializable {
+    /** An element of the argument type enumeration specifying a combobox control. */
+    static final public byte ENUM = 0;
+    /** An element of the argument type enumeration specifying a checkbox control. */
+    static final public byte FLAG = 1;
+    /** An element of the argument type enumeration specifying a tree control. */
+    static final public byte HIERARCHY = 2;
+    /** An element of the argument type enumeration specifying a spinner control. */
+    static final public byte INTEGER = 3;
+    /** An element of the argument type enumeration specifying a language combobox control. */
+    static final public byte LANGUAGE = 4;
+    /** An element of the argument type enumeration specifying a list control. */
+    static final public byte METADATA = 5;
+    /** An element of the argument type enumeration specifying a metadata combobox control. */
+    static final public byte METADATUM = 6;
+    /** An element of the argument type enumeration specifying a text field. */
+    static final public byte STRING = 7;
+    /** An element of the argument type enumeration specifying a regular expression text field. */
+    static final public byte REGEXP = 8;
+    /** true if this argument should actually be hidden within the GLI. This is iportant for arguments such as import dir or other location critical arguments. */
+    private boolean hidden_gli = false;
+    /** <i>true</i> if this argument is required for the applicable script to work properly, <i>false</i> otherwise. */
+    private boolean required = false;
+    /** The type of this argument. Used to be an int, but bytes are cheaper. */
+    private byte type = STRING;
+    /** The maximum value an integer based control can have. */
+    private int maximum = Integer.MAX_VALUE;
+    /** The minimum value an integer based control can have. */
+    private int minimum = Integer.MIN_VALUE;
+    /** Every argument has a detail mode level at which it becomes available to the user to edit. 
+     * @see org.greenstone.gatherer.Configuration
+     */
+    private int mode_level = Configuration.LIBRARIAN_MODE;
+    /** The DOM element this argument is built around, if any. */
+    private Element element;
+    /** If the argument is of type ENUM then this map holds all the various options. Each entry is an &lt;option value&gt; -&gt; &lt;description&gt; mapping. */
+    private HashMap list = null;
+    /** A default value for parameter-type arguments. May be a Perl pattern. */
+    private String default_value = null;
+    /** The text description of this argument parsed from the pluginfo output. */
+    private String description = null;
+    /** The argument flag as it appears in the command. Also used as the unique identifier of an argument. */
+    private String name = null;
+    /** The plugin that owns this argument, for the purposes of visualising inheritance. */
+    private String owner = null;
+
+    /** Default Constructor. */
+    public Argument() {
+    }
+
+    /** Another constructor but this one is a little more interesting as it takes a DOM element.
+     * @param element the Element this argument is based around
+     */
+    public Argument(Element element) {
+	this.element = element;
+    }
+
+    /** Method to add an element to the option list.
+     * @param name the name value of the option as a String
+     * @param desc the description of this options as a String
+     */
+    public void addOption(String name, String desc) {
+	if(type == ENUM && name != null) {
+	    if(desc == null) {
+		desc = "";
+	    }
+	    if(list == null) {
+		list = new HashMap();
+	    }
+	    list.put(name, desc);
+	}
+    }
+
+    /** Method to compare two arguments for ordering.
+     * @param object the argument we are comparing to, as an Object
+     * @return an int specifying the argument order, using values as set out in String
+     * @see org.greenstone.gatherer.cdm.Argument
+     */
+    public int compareTo(Object object) {
+	if(object instanceof Argument) {
+	    return getName().compareTo(((Argument)object).getName());
+	}
+	else {
+	    return toString().compareTo(object.toString());
+	}
+    }
+
+    /** Create a copy of this argument.
+     * @return a newly created Argument with the same details as this one
+     */
+    public Argument copy() {
+	Argument copy = new Argument();
+	copy.setDefaultValue(default_value);
+	copy.setDescription(description);
+	copy.setOptions(list);
+	copy.setOwner(owner);
+	copy.setName(name);
+	copy.setRequired(required);
+	copy.setType(type);
+	copy.setMinimum(minimum);
+	copy.setMaximum(maximum);
+	copy.setModeLevel(mode_level);
+	return copy;
+    }
+
+    /** Method to determine if two arguments are equal.
+     * @param object the argument to test against, as an Object
+     * @return true if the arguments names match, false otherwise
+     */
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+
+    /** Method to retrieve the value of default_value.
+     * @return a String containing the default value
+     */
+    public String getDefaultValue() {
+	return default_value;
+    }
+
+    /** Method to retrieve this arguments description.
+     * @return a String containing the description
+     */
+    public String getDescription() {
+	return description;
+    }
+
+    /** Method to retrieve the description of a certain list option value.
+     * @param key the String whose description we are searching for
+     * @return the description of the desired key as a String which may be empty if no such key exists
+     */
+    public String getDescription(String key) {
+	if(list.containsKey(key)) {
+	    return (String)list.get(key);
+	}
+	return "";
+    }
+
+    /** Retrieve the upper bound of a range based argument.
+     * @return the maximum as an int
+     */
+    public int getMaximum() {
+	return maximum;
+    }
+
+    /** Retrieve the lower bound of a range based argument.
+     * @return the minimum as an int
+     */
+    public int getMinimum() {
+	return minimum;
+    }
+
+    /** Retrieves the mode level at which this argument should become available. Any higher levels should also see this argument.
+     * @return the mode level as an int
+     */
+    public int getModeLevel() {
+	return mode_level;
+    }
+
+    /** Method to retrieve the value of name.
+     * @return a String containing the argument name
+     * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
+     */
+    public String getName() {
+	if(name == null && element != null) {
+	    name = element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+	}
+	return name;
+    }
+
+    /** Method to retrieve the option list for this argument.
+     * @return a HashMap containing &lt;option value&gt; -&gt; &lt;description&gt; entries
+     */
+    public HashMap getOptions() {
+	return list;
+    }
+
+    /** Retrieve the name of the owner of this argument.
+     * @return the owners name as a String
+     */
+    public String getOwner() {
+	return owner;
+    }
+    
+    /** Method to determine the type of this argument.
+     * @return a byte specifying the type
+     */
+    public byte getType() {
+	return type;
+    }
+
+    /** Method to retrieve the value of value.
+     * @return the value of value as a String
+     * @see org.greenstone.gatherer.Gatherer#c_man
+     * @see org.greenstone.gatherer.collection.CollectionManager#getCollection
+     */
+    public String getValue()
+    {
+	// Only assigned arguments have values.
+	if (element == null) {
+	    return null;
+	}
+
+	return XMLTools.getValue(element);
+    }
+
+
+    /** Method to determine if this argument has been assigned.
+     * @return true if it has, false otherwise
+     * @see org.greenstone.gatherer.util.StaticStrings#ASSIGNED_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#TRUE_STR
+     */
+    public boolean isAssigned() {
+	return (element != null && element.getAttribute(StaticStrings.ASSIGNED_ATTRIBUTE).equals(StaticStrings.TRUE_STR));
+    }
+
+    /** Determine if this is a custom argument ie one that has been parsed from the config file but doesn't have a matching entry in the argument library.
+     * @return true if this argument is a custom, false otherwise
+     * @see org.greenstone.gatherer.util.StaticStrings#CUSTOM_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#TRUE_STR
+     */
+    public boolean isCustomArgument() {
+	return (element != null && element.getAttribute(StaticStrings.CUSTOM_ATTRIBUTE).equals(StaticStrings.TRUE_STR));
+    }
+
+    /** Determine if this argument is hidden in GLI
+     * @return true if the argument is hidden, false otherwise
+     */
+    public boolean isHiddenGLI() {
+	return hidden_gli;
+    }
+
+    /** Method to determine of this argument is required for the associated script to work.
+     * @return true if this argument is required, false otherwise
+     */
+    public boolean isRequired() {
+	return required;
+    }
+
+    /** Method to allow for the activation of arguments that might never have their setValue() method called.
+     * @param assigned the desired state as a boolean
+     * @see org.greenstone.gatherer.util.StaticStrings#ASSIGNED_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#FALSE_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#TRUE_STR
+     */
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, (assigned ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
+	}
+    }
+
+    /** Set the custom argument flag.
+     * @param custom true to make this argument custom, false otherwise
+     * @see org.greenstone.gatherer.util.StaticStrings#CUSTOM_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#FALSE_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#TRUE_STR
+     */
+    public void setCustomArgument(boolean custom) {
+	if(element != null) {
+	    element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, (custom ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
+	}
+    }
+
+    /** Sets the value of default_value.
+     * @param default_value The new value for default_value as a <strong>String</strong>.
+     */
+    public void setDefaultValue(String default_value) {
+	this.default_value = default_value;
+    }
+
+    /** Set the value of desc.
+     * @param description the new value of desc as a String
+     */
+    public void setDescription(String description) {
+	this.description = description;
+    }
+
+    /** Set the element this argument should be based upon.
+     * @param element the Element
+     */
+    public void setElement(Element element) {
+	this.element = element;
+    }
+
+    /** Mark this argument as being hidden in GLI. */
+    public void setHiddenGLI() {
+	hidden_gli = true;
+    }
+
+    /** Set the upper bound for a range type argument.
+     * @param maximum the maximum as an int
+     */
+    public void setMaximum(int maximum) {
+	this.maximum = maximum;
+    }
+
+    /** Set the lower bound for a range type argument.
+     * @param minimum the minimum as an int
+     */
+    public void setMinimum(int minimum) {
+	this.minimum = minimum;
+    }
+
+    /** Set the detail mode level where this argument will become available.
+     * @param mode_level the mode level as an int
+     */
+    public void setModeLevel(int mode_level) {
+	this.mode_level = mode_level;
+    }
+
+    /** Set the value of name.
+     * @param name the new value of name as a String
+     */
+    public void setName(String name) {
+	this.name = name;
+    }
+
+    /** Sets the value of the options list.
+     * @param list the new options list as a HashMap
+     */
+    public void setOptions(HashMap list) {
+	this.list = list;
+    }
+
+    /** Set the owner of this argument.
+     * @param owner the name of the owner of this argument as a String
+     */
+    public void setOwner(String owner) {
+	this.owner = owner;
+    }
+
+    /** Set the value of required.
+     * @param required the new value of required as a boolean
+     */
+    public void setRequired(boolean required) {
+	this.required = required;
+    }
+
+    /** Set the value of type.
+     * @param type the new value of type as an byte
+     */
+    public void setType(byte type) {
+	this.type = type;
+    }
+
+    /** Set the value of type, by matching a type to the given string.
+     * @param new_type a String which contains the name of a certain argument type
+     * @see org.greenstone.gatherer.util.StaticStrings#ENUM_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#FLAG_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#HIERARCHY_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#INT_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#METADATA_TYPE_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#METADATUM_TYPE_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#REGEXP_STR
+     */
+    public void setType(String new_type) {
+	if(new_type.equalsIgnoreCase(StaticStrings.ENUM_STR)) {
+	    this.type = ENUM;
+	    list = new HashMap();
+	}
+	else if(new_type.equalsIgnoreCase(StaticStrings.FLAG_STR)) {
+	    this.type = FLAG;
+	}
+	else if(new_type.equalsIgnoreCase(StaticStrings.HIERARCHY_STR)) {
+	    this.type = HIERARCHY;
+	}
+	else if(new_type.equalsIgnoreCase(StaticStrings.INT_STR)) {
+	    this.type = INTEGER;
+	}
+	else if(new_type.equalsIgnoreCase(StaticStrings.LANGUAGE_STR)) {
+	    this.type = LANGUAGE;
+	}
+	else if(new_type.equalsIgnoreCase(StaticStrings.METADATA_TYPE_STR)) {
+	    this.type = METADATA;
+	}
+	else if(new_type.equalsIgnoreCase(StaticStrings.METADATUM_TYPE_STR)) {
+	    this.type = METADATUM;
+	}
+	else if(new_type.equalsIgnoreCase(StaticStrings.REGEXP_STR)) {
+	    this.type = REGEXP;
+	}
+	else {
+	    this.type = STRING;
+	}
+    }
+
+    /** Method to set the value of this argument.
+     * @param value the new value for the argument
+     * @see org.greenstone.gatherer.Gatherer#println
+     */
+    public void setValue(String value) {
+	if(element != null) {
+	    XMLTools.setValue(element, value);
+	}
+	else {
+	    DebugStream.println("Argument.setValue(" + value + ") called on a base Argument.");
+	}
+    }
+
+    /** Set the values vector to the given values. Currently I just assign the new values, whereas I may later want to implement a deep clone.
+     * @param values an ArrayList of values
+     * @see org.greenstone.gatherer.Gatherer#println
+     */
+    public void setValues(ArrayList values) {
+	if(element != null) {
+	    StringBuffer value = new StringBuffer();
+	    int value_length = values.size();
+	    for(int i = 0; i < value_length; i++) {
+		value.append(values.get(i));
+		value.append(StaticStrings.COMMA_CHARACTER);
+	    }
+	    value.deleteCharAt(value.length() - 1); // Remove last ','
+	    XMLTools.setValue(element, value.toString());
+	}
+	else {
+	    DebugStream.println("Argument.setValues([" + values.size() + " items]) called on a base Argument.");
+	}
+    }
+
+    /** Method for translating the data of this class into a string.
+     * @return a String containing a fragment of the total arguments string
+     * @see org.greenstone.gatherer.Gatherer#c_man
+     * @see org.greenstone.gatherer.collection.CollectionManager#getCollection
+     * @see org.greenstone.gatherer.util.StaticStrings#COMMA_CHARACTER
+     * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#SPACE_CHARACTER
+     * @see org.greenstone.gatherer.util.StaticStrings#SPEECH_CHARACTER
+     */
+    public String toString()
+    {
+	StringBuffer text = new StringBuffer("-");
+
+	if (element == null) {
+	    return text.toString();
+	}
+
+	if (name == null) {
+	    name = element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+	}
+	text.append(name);
+
+	String value = XMLTools.getValue(element);
+	if (value.length() == 0) {
+	    return text.toString();
+	}
+
+	text.append(StaticStrings.SPACE_CHARACTER);
+
+// 	// Handle metadata elements specially
+// 	if (type == METADATA || type == METADATUM) {
+// 	    // Tokenize the string
+// 	    StringTokenizer tokenizer = new StringTokenizer(value, ",");
+// 	    while (tokenizer.hasMoreTokens()) {
+// 		String token = tokenizer.nextToken();
+
+// 		MetadataElement metadata_element = MetadataTools.getMetadataElementWithDisplayName(token);
+// 		if (metadata_element != null) {
+// 		    text.append(metadata_element.getFullName());
+// 		}
+// 		else {
+// 		    text.append(token);
+// 		}
+
+// 		if (tokenizer.hasMoreTokens()) {
+// 		    text.append(StaticStrings.COMMA_CHARACTER);
+// 		}
+// 	    }
+// 	    return text.toString();
+// 	}
+
+	// If the value contains a space, add speech marks
+	//   (Except for metadata elements, which won't have spaces when written out to collect.cfg)
+	if (value.indexOf(StaticStrings.SPACE_CHARACTER) != -1 && !(type == METADATUM || type == METADATA)) {
+	    value = StaticStrings.SPEECH_CHARACTER + value + StaticStrings.SPEECH_CHARACTER;
+	}
+
+	text.append(value);
+	return text.toString();
+    } 
+
+    /** parse the <Option> XML from eg import.pl -xml or pluginfo.pl -xml */
+    public void parseXML(Element option) {
+
+	for(Node node = option.getFirstChild(); node != null; node = node.getNextSibling()) {
+	    String node_name = node.getNodeName();
+	    if(node_name.equals("Name")) {
+		setName(XMLTools.getValue(node));
+	    }
+	    else if(node_name.equals("Desc")) {
+		setDescription(XMLTools.getValue(node));
+	    }
+	    else if(node_name.equals("Type")) {
+		setType(XMLTools.getValue(node));
+	    }
+	    else if(node_name.equals("Default")) {
+		setDefaultValue(XMLTools.getValue(node));
+	    }
+	    else if(node_name.equals("Required")) {
+		String v = XMLTools.getValue(node);
+		if(v != null && v.equals("yes")) {
+		    setRequired(true);
+		}
+	    }
+	    else if(node_name.equals("List")) {
+		// Two final loops are required to parse lists.
+		for(Node value = node.getFirstChild(); value != null; value = value.getNextSibling()) {
+		    if(value.getNodeName().equals("Value")) {
+			String key = null;
+			String desc = "";
+			for(Node subvalue = value.getFirstChild(); subvalue != null; subvalue = subvalue.getNextSibling()) {
+			    node_name = subvalue.getNodeName();
+			    if(node_name.equals("Name")) {
+				key = XMLTools.getValue(subvalue);
+			    }
+			    else if(node_name.equals("Desc")) {
+				desc = XMLTools.getValue(subvalue);
+			    }
+			}
+			if(key != null) {
+			    addOption(key, desc);
+			}
+		    }
+		}
+	    }
+	    else if(node_name.equals("Range")) {
+		String range_raw = XMLTools.getValue(node);
+		int index = -1;
+		if((index = range_raw.indexOf(StaticStrings.COMMA_CHARACTER)) != -1) {
+		    if(index > 0) {
+			try {
+			    String first_number = range_raw.substring(0, index);
+			    setMinimum(Integer.parseInt(first_number));
+			    first_number = null;
+			}
+			catch(Exception exception) {
+			}
+		    }
+		    
+		    if(index + 1 < range_raw.length()) {
+			try {
+			    String second_number = range_raw.substring(index + 1);
+			    setMaximum(Integer.parseInt(second_number));
+			    second_number = null;    
+			}
+			catch(Exception exception) {
+			}
+		    }
+		}
+		// Else it wasn't a valid range anyway, so ignore it
+	    }
+	    else if(node_name.equals("HiddenGLI")) {
+		setHiddenGLI();
+	    }
+	    else if(node_name.equals("ModeGLI")) {
+		String mode_level_str = XMLTools.getValue(node);
+		try {
+		    int mode_level = Integer.parseInt(mode_level_str);
+		    setModeLevel(mode_level);
+		}
+		catch(Exception exception) {
+		    DebugStream.println("Exception in Argument.parseXML() - Unexpected but non-fatal");
+		    DebugStream.printStackTrace(exception);
+		}
+	    }
+	    
+	} // for each option
+	
+    } // parseXML
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ArgumentConfiguration.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ArgumentConfiguration.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ArgumentConfiguration.java	(revision 10506)
@@ -0,0 +1,1033 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.GComboBox;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.gui.ModalDialog;
+import org.greenstone.gatherer.gui.SimpleMenuBar;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+/** This class provides us with a dialog box which allows us to edit the arguments of either a PlugIn or a Classifier.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ * @see org.greenstone.gatherer.cdm.Classifier
+ * @see org.greenstone.gatherer.cdm.PlugIn
+ */
+public class ArgumentConfiguration
+    extends ModalDialog
+    implements ActionListener {
+    /** The data whose arguments we are editing. */
+    private ArgumentContainer data = null;
+    /** Argument these argument controls coloured or uncoloured (alternates to indicate inheritance). */
+    private boolean coloured = false;
+    /** Whether we have successfully edited the arguments associated with the ArgumentContainer or if we have failed to enter required arguments and have instead cancelled (which would cause argument additions to roll back). */
+    private boolean success = false;
+    /** A button to cancel this dialog. */
+    private JButton cancel = null;
+    /** A button to accept the changes and close the dialog. */
+    private JButton ok = null;
+    /** A reference to the ourselves so our inner classes can dispose us like a dialog. */
+    private ArgumentConfiguration self = null;
+    /** The central pane where a list of known arguments is displayed. */
+    private JPanel central_pane = null;
+    /** The field for entering custom arguments. */
+    private JTextField custom = null;
+    /** The panel for the custom arguments */
+    private JPanel custom_pane = null;
+    /** The name of the owner of the last argument control. */
+    private String previous_owner = null;
+    /** The size used for an argument label. */
+    static final private Dimension LABEL_SIZE = new Dimension(225, 25);
+    /** Size of a list. */
+    static final private Dimension LIST_SIZE = new Dimension(380, 50);
+    /** The size used for the dialog. */
+    static final private Dimension SIZE = new Dimension(800, 425);
+
+    /** Constructor.
+     * @param data The plugin or classifier whose arguments we are configuring, in the form of its supported <strong>ArgumentContainer</strong> interface.
+     * @see org.greenstone.gatherer.Configuration
+     */
+    public ArgumentConfiguration(ArgumentContainer data) {
+	super(Gatherer.g_man);
+	this.data = data;
+	this.self = this;
+
+	// Create
+	setModal(true);
+	setSize(SIZE);
+	setJMenuBar(new SimpleMenuBar("designingacollection")); // can we tell whether we are doing a classifier or plugin, to make the help more specific??
+	Dictionary.setText(this, "CDM.ArgumentConfiguration.Title");
+
+	central_pane = new JPanel();
+	JPanel content_pane = (JPanel) getContentPane();
+
+	custom_pane = new JPanel();
+	String custom_str = data.getCustom();
+	if (custom_str != null) {
+	    custom = new JTextField(custom_str);
+	}
+	else {
+	    custom = new JTextField();
+	}
+	JLabel custom_label = new JLabel();
+	custom_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.setText(custom_label, "CDM.ArgumentConfiguration.Custom");
+
+	JPanel header_pane = new JPanel();
+	JLabel header = new JLabel();
+	header.setHorizontalAlignment(JLabel.CENTER);
+	header.setOpaque(true);
+	String args[] = new String[1];
+	args[0] = data.getName();
+	Dictionary.setText(header, "CDM.ArgumentConfiguration.Header", args);
+
+	JPanel button_pane = new JPanel();
+	cancel = new GLIButton();
+	cancel.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel, "General.Cancel", "General.Pure_Cancel_Tooltip");
+	ok = new GLIButton();
+	ok.setMnemonic(KeyEvent.VK_O);
+	Dictionary.setBoth(ok, "General.OK", "General.OK_Tooltip");
+
+	// Listeners
+	cancel.addActionListener(this);
+	ok.addActionListener(this);
+	ok.addActionListener(CollectionDesignManager.all_change_listener);
+
+	// Layout
+	custom_pane.setLayout(new BorderLayout());
+	custom_pane.add(custom_label, BorderLayout.WEST);
+	custom_pane.add(custom, BorderLayout.CENTER);
+
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	button_pane.setLayout(new GridLayout(1,2));
+	button_pane.add(ok);
+	button_pane.add(cancel);
+
+	central_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	central_pane.setLayout(new BoxLayout(central_pane, BoxLayout.Y_AXIS));
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(header, BorderLayout.NORTH);
+	content_pane.add(new JScrollPane(central_pane), BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	// Now generate a set of controls for each of the arguments.
+	generateControls();
+
+	// Display on screen.
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	screen_size = null;
+    }
+
+    /** Any implementation of ActionListener must include this method so that we can be informed when an action has occured on one of the controls we are listening to.
+     * @param event An <strong>ActionEvent</strong> containing pertinant information about the event that fired this call.
+     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl
+     * @see org.greenstone.gatherer.cdm.ArgumentContainer
+     */
+    public void actionPerformed(ActionEvent event) {
+	boolean cont = true;
+	if (event.getSource() == ok) {
+	    // Clear the current focus to ensure components such as combobox have correctly updated
+	    custom.requestFocus();
+	    // Update the details stored in the data objects arguments.
+	    data.setCustom(custom.getText());
+	    // Loop through each of the controls in the central pane, updating the matching argument as necessary.
+	    for(int i = 0; i < central_pane.getComponentCount(); i++) {
+		Component component = central_pane.getComponent(i);
+		if(component instanceof ArgumentControl) {
+		   cont = cont && ((ArgumentControl)component).updateArgument();
+		}
+	    }
+	    if(cont) {
+		success = true;
+	    }
+	}
+	if(cont) {
+	    dispose();
+	}
+    }
+
+    /** Destructor. */
+    public void destroy() {
+	cancel = null;
+	central_pane = null;
+	custom_pane = null;
+	custom = null;
+	data = null;
+	ok = null;
+	self = null;
+    }
+
+    /** Method which actually forces the dialog to be shown on screen.
+     * @return <i>true</i> if the user completed configuration and pressed ok, <i>false</i> otherwise.
+     */
+    public boolean display() {
+	setVisible(true);
+	return success;
+    }
+
+    private void addHeader(String name, Color color) {
+	JPanel header = new JPanel();
+	header.setBackground(color);
+	JPanel inner_pane = new JPanel();
+	inner_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()));
+	inner_pane.setBackground(color);
+	JLabel header_label = new JLabel("<html><strong>" + name + "</strong></html>");
+	header_label.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+	header_label.setHorizontalAlignment(JLabel.CENTER);
+	header_label.setOpaque(true);
+
+	// Layout
+	inner_pane.setLayout(new BorderLayout());
+	inner_pane.add(header_label, BorderLayout.CENTER);
+
+	header.setLayout(new BorderLayout());
+	header.add(inner_pane, BorderLayout.CENTER);
+	central_pane.add(header);
+    }
+
+    /** Method to iterate through the arguments associated with whatever argument container we are building an argument control view for, creating the appropriate controls for each.
+     * @see org.greenstone.gatherer.cdm.Argument
+     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl
+     */
+    private void generateControls() {
+	ArrayList arguments = data.getArguments(true, false);
+	int total_height = 250;
+	int mode = Configuration.getMode();
+	for(int i = 0; i < arguments.size(); i++) {
+	    Argument argument = (Argument) arguments.get(i);
+	    if(mode > Configuration.LIBRARIAN_MODE || !(argument.getType() == Argument.REGEXP)) {
+		ArgumentControl argument_control = new ArgumentControl(argument);
+		total_height = total_height - argument_control.getPreferredSize().height;
+		central_pane.add(argument_control);
+	    }
+	}
+	// now add in the custom args bit
+	coloured = !coloured;
+	Color color = (coloured ? Configuration.getColor("coloring.collection_heading_background", false) : Configuration.getColor("coloring.collection_tree_background", false));
+	addHeader(Dictionary.get("CDM.ArgumentConfiguration.Custom_Header"), color);
+	custom_pane.setBackground(color);
+	central_pane.add(custom_pane);
+	if(total_height > 0) {
+	    JPanel filler = new JPanel();
+	    filler.setPreferredSize(new Dimension(100, total_height));
+	    filler.setSize(new Dimension(100, total_height));
+	    central_pane.add(filler);
+	}
+    }
+
+    /** This class encapsulates all the technical difficulty of creating a specific control based on an Argument. */
+    private class ArgumentControl
+	extends JPanel {
+	/** The Argument this control will be based on. */
+	private Argument argument = null;
+
+	private Color colour_one = Configuration.getColor("coloring.collection_heading_background", false);
+	private Color colour_two = Configuration.getColor("coloring.collection_tree_background", false);
+	/** One of a possible two buttons available for adding to this control. */
+	private JButton one = null;
+	/** The second of two buttons available for adding to this control. */
+	private JButton two = null;
+	/** A checkbox to allow enabling or diabling of this Argument. */
+	private JCheckBox enabled = null;
+	/** Some form of editor component, such as a JComboBox or JTextField, used to set parameters to an Argument. */
+	private JComponent value = null;
+	/** Can be used in place of the other editor components if a list is required. */
+	private JList list = null;
+	/** Constructor.
+	 * @param argument The <strong>Argument</strong> this control will be built around.
+	 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.AddListener
+	 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.EnabledListener
+	 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.HierarchyListener
+	 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.ListOption
+	 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.RemoveListener
+	 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.ToolTipUpdater
+	 */
+	public ArgumentControl(Argument argument) {
+	    this.argument = argument;
+	    ///ystem.err.println("generating controls for arg "+argument.getName());
+	    String tip = "<html>" + argument.getDescription() + "</html>";
+	    tip = Utility.formatHTMLWidth(tip, 60);
+
+	    // If this is the first control, there is no history.
+	    if(previous_owner == null) {
+		///ystem.err.println("previous owner is null");
+		previous_owner = argument.getOwner();
+		addHeader(previous_owner, colour_two);
+	    }
+	    // Otherwise if the owner of the control has changed since the last argument, toggle the colouring of the control.
+	    else if(previous_owner != argument.getOwner()) {
+		///ystem.err.println("previous owner is different from current owner");
+		coloured = !coloured;
+		previous_owner = argument.getOwner();
+		addHeader(previous_owner, (coloured ? colour_one : colour_two));
+	    }
+	    // Create
+	    if(coloured) {
+		setBackground(colour_one);
+	    }
+	    else {
+		setBackground(colour_two);
+	    }
+	    JLabel owner_label = new JLabel(argument.getOwner());
+	    owner_label.setOpaque(false);
+	    JLabel label = new JLabel(argument.getName());
+	    label.setOpaque(false);
+	    label.setPreferredSize(LABEL_SIZE);
+	    label.setToolTipText(tip);
+	    enabled = new JCheckBox(argument.getName());
+	    enabled.setOpaque(false);
+	    enabled.setPreferredSize(LABEL_SIZE);
+	    enabled.setToolTipText(tip);
+	    JPanel inner_pane = new JPanel();
+	    inner_pane.setOpaque(false);
+	    String existing_value = argument.getValue();
+	    String default_value = argument.getDefaultValue();
+
+	    switch(argument.getType()) {
+	    case Argument.ENUM:
+		// Build an option model, wrapping each entry of the list table.
+		HashMap arg_list = argument.getOptions();
+		ArrayList options_model = new ArrayList();
+		Iterator it = arg_list.keySet().iterator();
+		while(it.hasNext()) {
+		    String key = (String) it.next();
+		    options_model.add(new ListOption(key, (String)arg_list.get(key)));
+		}
+		Collections.sort(options_model);
+		value = new GComboBox(options_model.toArray(), false);
+		((JComboBox)value).addActionListener(new ToolTipUpdater());
+		if(existing_value != null && existing_value.length() > 0) {
+		    // Select the correct value. Since they're all text strings we better iterate to be safe.
+		    selectValue((JComboBox)value, existing_value);
+		}
+		else if(default_value != null) {
+		    ///ystem.err.println("Default for argument: " + argument.getName());
+		    // Same as above except for default value.
+		    selectValue((JComboBox)value, default_value);
+		}
+		break;
+
+	    case Argument.FLAG:
+		// Only need the check box.
+		break;
+
+	    case Argument.HIERARCHY:
+		// I don't think these are used any more...
+		break;
+
+	    case Argument.INTEGER:
+		// Build a spinner
+		int initial_value=0;
+		// If there was an original value, set it.
+		if(existing_value != null && !existing_value.equals("")) {
+		    try {
+			initial_value = Integer.parseInt(existing_value);
+			//spinner.setValue(new Integer(existing_value));
+		    }
+		    catch (Exception error) {
+			DebugStream.println("ArgumentConfiguration Error: "+error);
+		    }
+		} else if (default_value != null && !default_value.equals("")) {
+		    try {
+			initial_value = Integer.parseInt(default_value);
+			//spinner.setValue(new Integer(default_value));
+		    }
+		    catch (Exception error) {
+			DebugStream.println("ArgumentConfiguration Error: "+error);
+		    }
+		}
+		if (initial_value < argument.getMinimum()) {
+		    initial_value = argument.getMinimum();
+		} else if (initial_value > argument.getMaximum()) {
+		    initial_value = argument.getMaximum();
+		}
+
+		JSpinner spinner = new JSpinner(new SpinnerNumberModel(initial_value, argument.getMinimum(), argument.getMaximum(), 1));
+
+		// And remember it
+		value = spinner;
+		break;
+
+	    case Argument.REGEXP:
+	    case Argument.STRING:
+		// If there is already a value set for this argument, use it
+		if (existing_value != null && !existing_value.equals("")) {
+		    value = new JTextField(existing_value);
+		    break;
+		}
+
+		// Use the default value, if there is one
+		if (default_value != null && !default_value.equals("")) {
+		    value = new JTextField(default_value);
+		    break;
+		}
+
+// 		// Special test just for the hfile field.
+// 		if (argument.getName().equals("hfile")) {
+// 		    // Work through previous controls looking for the metadata one.
+// 		    for (int i = 0; i < central_pane.getComponentCount(); i++) {
+// 			Object object = central_pane.getComponent(i);
+// 			if (object instanceof ArgumentControl) {
+// 			    ArgumentControl control = (ArgumentControl) object;
+// 			    if (control.toString().equals("metadata")) {
+// 				Object temp = control.getValue();
+// 				if (temp != null) {
+// 				    value = new JTextField(temp.toString() + ".txt");
+//                                  break;
+// 				}
+// 			    }
+// 			}
+// 		    }
+// 		}
+
+		// Blank field
+		value = new JTextField();
+		break;
+
+	    case Argument.LANGUAGE:
+		value = new GComboBox(CollectionDesignManager.language_manager.getLanguageCodes().toArray(), false);
+		// we want to display the language name not the code
+		((JComboBox)value).setRenderer(new LanguageListCellRenderer());
+		// Now ensure we have the existing value or default value selected if either exist in our known languages
+		String lang_name = null;
+		String selected_code = existing_value;
+		if(existing_value != null && !existing_value.equals("")) {
+		    lang_name = CollectionDesignManager.language_manager.getLanguageName(existing_value);
+		}
+		if(lang_name == null && default_value != null) {
+		    lang_name = CollectionDesignManager.language_manager.getLanguageName(default_value);
+		    selected_code = default_value;
+		}
+		if (lang_name != null) {
+		    ((JComboBox)value).setSelectedItem(selected_code);
+		}
+		break;
+
+	    case Argument.METADATUM:
+	    case Argument.METADATA:
+		value = new GComboBox(MetadataSetManager.getEveryMetadataSetElement(), false);
+
+		// Editable for advanced modes (allows things like dc.Title,ex.Title)
+		if (Configuration.getMode() > Configuration.ASSISTANT_MODE) {
+		    ((JComboBox) value).setEditable(true);
+		}
+
+		// Now ensure we have the existing value or default value selected if either exist.
+		if (existing_value != null && existing_value.length() > 0) {
+		    boolean found = selectValue((JComboBox) value, existing_value);
+		    // It's possible that this is a custom value and so doesn't exist in the combobox
+		    if (!found) {
+			// If so, add it then select it
+			((JComboBox) value).addItem(existing_value);
+			((JComboBox) value).setSelectedItem(existing_value);
+		    }
+		}
+		else if (default_value != null) {
+		    selectValue((JComboBox) value, default_value);
+		}
+		break;
+
+// ---- Special interface for adding and ordering multiple metadata items ----
+// Turned off at Ian's request!
+//  	    case Argument.METADATA:
+//  		// Comma separated metadata values.
+//  		ArrayList values = argument.getValues();
+//  		value = new GComboBox(MetadataSetManager.getEveryMetadataSetElement(), false);
+//  		//((JComboBox)value).setEditable(false);
+//  		DefaultListModel model = new DefaultListModel();
+//  		list = new JList(model);
+//  		list.setVisibleRowCount(3);
+//  		for(int i = 0; i < values.size(); i++) {
+//  		    model.addElement(values.get(i));
+//  		}
+
+//  		one = new GLIButton();
+//  		one.addActionListener(new AddListener((JComboBox)value, list));
+//  		one.setMnemonic(KeyEvent.VK_A);
+//  		Dictionary.setBoth(one, "CDM.ArgumentConfiguration.Add", "CDM.ArgumentConfiguration.Add_Tooltip");
+//  		two = new GLIButton();
+//  		two.addActionListener(new RemoveListener(list));
+//  		two.setMnemonic(KeyEvent.VK_R);
+//  		Dictionary.setBoth(two, "CDM.ArgumentConfiguration.Remove", "CDM.ArgumentConfiguration.Remove_Tooltip");
+
+//  		if(argument.getValues().size() > 0 || argument.isRequired()) {
+//  		    enabled.setSelected(true);
+//  		    list.setBackground(Color.white);
+//  		    list.setEnabled(true);
+//  		    one.setEnabled(true);
+//  		    two.setEnabled(true);
+//  		    value.setEnabled(true);
+//  		}
+//  		else {
+//  		    enabled.setSelected(false);
+//  		    list.setBackground(Color.lightGray);
+//  		    list.setEnabled(false);
+//  		    one.setEnabled(false);
+//  		    two.setEnabled(false);
+//  		    value.setEnabled(false);
+//  		}
+//  		break;
+	    } // end of switch
+
+	    // Enable or disable as necessary.
+	    if(argument.isRequired() || argument.isAssigned()) {
+		enabled.setSelected(true);
+		if(value != null) {
+		    value.setOpaque(true);
+		    value.setBackground(Color.white);
+		    value.setEnabled(true);
+		    if(value instanceof JSpinner) {
+			// Set enabled
+			JComponent c = ((JSpinner)value).getEditor();
+			if ( c instanceof JSpinner.DefaultEditor ) {
+			    JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
+			    JFormattedTextField field = editor.getTextField();
+			    field.setEditable(true);
+			    field.setBackground(Color.white);
+			}
+		    }
+		}
+	    }
+	    else {
+		enabled.setSelected(false);
+		if(value != null) {
+		    value.setOpaque(true);
+		    value.setBackground(Color.lightGray);
+		    value.setEnabled(false);
+		    if(value instanceof JSpinner) {
+			// Set enabled
+			JComponent c = ((JSpinner)value).getEditor();
+			if ( c instanceof JSpinner.DefaultEditor ) {
+			    JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
+			    JFormattedTextField field = editor.getTextField();
+			    field.setEditable(false);
+			    field.setBackground(Color.lightGray);
+			}
+		    }
+		}
+	    }
+	    // Listener
+	    if(value != null && !argument.isRequired()) {
+		enabled.addActionListener(new EnabledListener(one, two, list, value));
+	    }
+
+	    // Layout
+	    inner_pane.setLayout(new BorderLayout());
+	    if (argument.isRequired()) {
+		inner_pane.add(label, BorderLayout.WEST);
+	    }
+	    else {
+		inner_pane.add(enabled, BorderLayout.WEST);
+	    }
+
+	    if (list == null) {
+		enabled.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+		if (value != null) {
+		    inner_pane.add(value, BorderLayout.CENTER);
+		}
+	    }
+	    else {
+		JPanel left_pane = new JPanel(new BorderLayout());
+		left_pane.add(new JLabel(""), BorderLayout.NORTH);
+		left_pane.add(value, BorderLayout.CENTER);
+		left_pane.add(one, BorderLayout.SOUTH);
+		left_pane.setOpaque(false);
+
+		JPanel right_pane = new JPanel(new BorderLayout());
+		right_pane.add(new JScrollPane(list), BorderLayout.CENTER);
+		right_pane.add(two, BorderLayout.SOUTH);
+		right_pane.setOpaque(false);
+
+		JPanel control_pane = new JPanel(new GridLayout(1, 2));
+		control_pane.add(left_pane);
+		control_pane.add(right_pane);
+
+		inner_pane.add(control_pane, BorderLayout.CENTER);
+	    }
+
+	    setLayout(new BorderLayout());
+	    add(inner_pane, BorderLayout.CENTER);
+	}
+
+       public Argument getArgument() {
+	  return argument;
+       }
+
+	public Object getValue() {
+	    if(value instanceof JComboBox) {
+		return ((JComboBox)value).getSelectedItem();
+	    }
+	    else if(value instanceof JTextField) {
+		return ((JTextField)value).getText();
+	    }
+	    return null;
+	}
+	/** Identifies this control by returning the name of the Argument it is based on.
+	 * @return The name of the Argument as a <strong>String</strong>.
+	 * @see org.greenstone.gatherer.cdm.Argument
+	 */
+	public String toString() {
+	    return argument.getName();
+	}
+	/** Updates the enwrapped Argument using the values provided by the controls.
+	 * @return <i>true</i> if the update was successful, <i>false</i> otherwise.
+	 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.ListOption
+	 * @see org.greenstone.gatherer.cdm.Language
+	 */
+	public boolean updateArgument() {
+	    if(enabled.isSelected() || argument.isRequired()) {
+		argument.setAssigned(false);
+		String result = null;
+		switch(argument.getType()) {
+		case Argument.ENUM:
+		    ListOption option = (ListOption)((JComboBox)value).getSelectedItem();
+		    if(option != null && option.getValue().length() > 0) {
+			argument.setValue(option.getValue());
+		    }
+		    else {
+			String args[] = new String[1];
+			args[0] = argument.getName();
+			if(argument.isRequired()) {
+			    JOptionPane.showMessageDialog(self, Dictionary.get("CDM.ArgumentConfiguration.Required_Argument", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+			}
+			// They've left the field blank
+			else {
+			    JOptionPane.showMessageDialog(self, Dictionary.get("CDM.ArgumentConfiguration.No_Value", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+			    argument.setValue(null);
+			}
+			args = null;
+			return false;
+		    }
+		    argument.setAssigned(true);
+		    return true;
+		case Argument.FLAG:
+		    // Should have already been handled above.
+		    argument.setAssigned(true);
+		    return true;
+		case Argument.INTEGER:
+		    result = ((JSpinner)value).getValue().toString();
+		    if(result.length() > 0) {
+			// Test if the value entered is a valid int.
+			try {
+			    int x = Integer.parseInt(result);
+			}
+			catch(NumberFormatException nfe) {
+			    String args[] = new String[2];
+			    args[0] = argument.getName();
+			    args[1] = result;
+			    JOptionPane.showMessageDialog(self, Dictionary.get("CDM.ArgumentConfiguration.Bad_Integer", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+			    args = null;
+			    return false;
+			}
+			argument.setValue(result);
+		    }
+		    else {
+			String args[] = new String[1];
+			args[0] = argument.getName();
+			if(argument.isRequired()) {
+			    JOptionPane.showMessageDialog(self, Dictionary.get("CDM.ArgumentConfiguration.Required_Argument", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+			}
+			// They've left the field blank
+			else {
+			    JOptionPane.showMessageDialog(self, Dictionary.get("CDM.ArgumentConfiguration.No_Value", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+			    argument.setValue(null);
+			}
+			args = null;
+			return false;
+		    }
+		    argument.setAssigned(true);
+		    return true;
+		case Argument.LANGUAGE:
+		    String language = (((JComboBox)value).getSelectedItem()).toString();
+		    argument.setValue(language);
+		    // Kinda lucked out here. Its impossible not to choose an entry from these comboboxes as they are restricted.
+		    argument.setAssigned(true);
+		    return true;
+		case Argument.METADATUM:
+		case Argument.METADATA:
+		    Object new_value_raw = ((JComboBox) value).getSelectedItem();
+		    if (new_value_raw instanceof MetadataElement) {
+			argument.setValue(((MetadataElement) new_value_raw).getFullName());
+		    }
+		    else {
+			// But we have to be careful as an arbitary string object could be zero length
+			String new_value = new_value_raw.toString();
+			///ystem.err.println("The current value is: " + new_value);
+			if(new_value.length() > 0) {
+			    argument.setValue(new_value);
+			}
+			else {
+			    String args[] = new String[1];
+			    args[0] = argument.getName();
+			    if(argument.isRequired()) {
+				JOptionPane.showMessageDialog(self, Dictionary.get("CDM.ArgumentConfiguration.Required_Argument", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+			    }
+			    // They've left the field blank
+			    else {
+				JOptionPane.showMessageDialog(self, Dictionary.get("CDM.ArgumentConfiguration.No_Value", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+				argument.setValue(null);
+			    }
+			    args = null;
+			    return false;
+			}
+		    }
+		    argument.setAssigned(true);
+		    return true;
+//  		case Argument.METADATA:
+//  		    DefaultListModel model = (DefaultListModel)list.getModel();
+//  		    ArrayList values = new ArrayList();
+//  		    for(int i = 0; i < model.size(); i++) {
+//  			values.add(model.get(i));
+//  		    }
+//  		    argument.setValues(values);
+//  		    argument.setAssigned(true);
+//  		    return true;
+		case Argument.HIERARCHY:
+// 		    argument.setValue(((JComboBox)value).getSelectedItem().toString());
+// 		    // Kinda lucked out here. Its impossible not to choose an entry from these comboboxes as they are restricted.
+// 		    argument.setAssigned(true);
+		    return true;
+		case Argument.REGEXP:
+		case Argument.STRING:
+		    result = ((JTextField)value).getText();
+		    if(result.length() > 0) {
+			argument.setValue(result);
+		    }
+		    else {
+			String args[] = new String[1];
+			args[0] = argument.getName();
+			if(argument.isRequired()) {
+			    JOptionPane.showMessageDialog(self, Dictionary.get("CDM.ArgumentConfiguration.Required_Argument", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+			}
+			// They've left the field blank
+			else {
+			    JOptionPane.showMessageDialog(self, Dictionary.get("CDM.ArgumentConfiguration.No_Value", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+			    argument.setValue(null);
+			}
+			args = null;
+			return false;
+		    }
+		    argument.setAssigned(true);
+		    return true;
+		}
+		return false;
+	    }
+	    else {
+		argument.setAssigned(false);
+		return true;
+	    }
+	}
+	/** Method to ensure that a certain value is selected, if it exists within that combobox to begin with.
+	 * @param combobox The <strong>JComboBox</strong> whose selection we are trying to preset.
+	 * @param target The desired value of the selection as a <strong>String</strong>.
+	 * @return true if the item was found and selected, false otherwise
+	 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl.ListOption
+	 */
+	public boolean selectValue(JComboBox combobox, String target) {
+	    ///ystem.err.println("Searching for the target string: " + target);
+	    for(int i = 0; i < combobox.getItemCount(); i++) {
+		Object object = combobox.getItemAt(i);
+		if(object instanceof ListOption) {
+		    ListOption lo = (ListOption) object;
+		    ///ystem.err.print("/tChecking: " + lo.getValue() + "... ");
+		    if(lo.getValue().startsWith(target)) {
+			///ystem.err.println("Match!");
+			combobox.setSelectedIndex(i);
+			return true;
+		    }
+		    /*
+		    else {
+			System.err.println("No Match.");
+		    }
+		    */
+		}
+		else if (object instanceof MetadataElement) {
+		    if(object.toString().equals(target)) {
+			combobox.setSelectedIndex(i);
+			return true;
+		    }
+		}
+	    }
+	    return false;
+	}
+	/** Forces the control into an 'enabled' mode. */
+	public void setEnabled() {
+	    enabled.setSelected(true);
+	}
+	/** Explicitly sets the value of a JTextField type control to the given String.
+	 * @param value_str The new value of the control as a <strong>String</strong>.
+	 */
+	public void setValue(String value_str) {
+	    ((JTextField)value).setText(value_str);
+	}
+// 	/** Listener which adds entries to a list from a combobox when fired. */
+// 	private class AddListener
+// 	    implements ActionListener {
+// 	    /** The model behind the target list. */
+// 	    private DefaultListModel model = null;
+//       	    /** The source for data to be added to the list. */
+// 	    private JComboBox source = null;
+// 	    /** The list to add data to. */
+// 	    private JList target = null;
+// 	    /** Constructor.
+// 	     * @param source A <strong>JComboBox</strong> which serves as the source for data.
+// 	     * @param target A <strong>JList</strong> which serves as the target for data.
+// 	     */
+// 	    public AddListener(JComboBox source, JList target) {
+// 		this.model = (DefaultListModel) target.getModel();
+// 		this.source = source;
+// 		this.target = target;
+// 	    }
+// 	    /** When the add button is clicked, we attempt to add the selected metadata from the source into the target.
+// 	     * @param event An <strong>ActionEvent</strong> containing information about the event.
+// 	     */
+// 	    public void actionPerformed(ActionEvent event) {
+// 		ElementWrapper element = (ElementWrapper) source.getSelectedItem();
+// 		String name = element.toString();
+// 		if (!model.contains(name)) {
+// 		    model.addElement(name);
+// 		}
+// 	    }
+// 	}
+	/** Listens for actions apon the enable checkbox, and if detected enables or diables control appropriately. */
+	private class EnabledListener
+	    implements ActionListener {
+	    /** One of two possible buttons that might have their enabled state changed by this listener. */
+	    private JButton one = null;
+	    /** One of two possible buttons that might have their enabled state changed by this listener. */
+	    private JButton two = null;
+	    /** An editor component, such as a JComboBox or JTextField, that might have its enabled state changed by this listener. */
+	    private JComponent target = null;
+	    /** A list which might have its enabled state changed by this listener. */
+	    private JList list = null;
+	    /** Constructor.
+	     * @param one A <strong>JButton</strong> whose enabled state is determined by the listener, or <i>null</i> if no button.
+	     * @param two A <strong>JButton</strong> whose enabled state is determined by the listener, or <i>null</i> if no button.
+	     * @param list A <strong>JList</strong> whose enabled state is determined by the listener, or <i>null</i> if no list.
+	     * @param target A <strong>JComponent</strong> whose enabled state is determined by the listener, or <i>null</i> if no component.
+	     */
+	    public EnabledListener(JButton one, JButton two, JList list, JComponent target) {
+		this.list = list;
+		this.one = one;
+		this.target = target;
+		this.two = two;
+	    }
+	    /** Any implementation of ActionListener must include this method so that we can be informed when an action has been performed on or registered check box, prompting us to change the state of the other controls as per the users request.
+	     * @param event An <strong>ActionEvent</strong> containing information about the click.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		JCheckBox source = (JCheckBox)event.getSource();
+		if(source.isSelected()) {
+		    target.setBackground(Color.white);
+		    target.setEnabled(true);
+		    if(target instanceof JSpinner) {
+			// Set enabled
+			JComponent c = ((JSpinner)target).getEditor();
+			if ( c instanceof JSpinner.DefaultEditor ) {
+			    JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
+			    JFormattedTextField field = editor.getTextField();
+			    field.setEditable(true);
+			    field.setBackground(Color.white);
+			}
+		    }
+		    if(one != null && two != null && list != null) {
+			one.setEnabled(true);
+			two.setEnabled(true);
+			list.setBackground(Color.white);
+			list.setEnabled(true);
+		    }
+		}
+		else {
+		    target.setBackground(Color.lightGray);
+		    target.setEnabled(false);
+		    if(target instanceof JSpinner) {
+			// Set enabled
+			JComponent c = ((JSpinner)target).getEditor();
+			if ( c instanceof JSpinner.DefaultEditor ) {
+			    JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
+			    JFormattedTextField field = editor.getTextField();
+			    field.setEditable(false);
+			    field.setBackground(Color.lightGray);
+			}
+		    }
+		    if(one != null && two != null && list != null) {
+			one.setEnabled(false);
+			two.setEnabled(false);
+			list.setBackground(Color.lightGray);
+			list.setEnabled(false);
+		    }
+		}
+	    }
+	}
+	/** If a metadata element is selected that requires an hfile, then this listener defaults that hfile. */
+// 	private class HierarchyListener
+// 	    implements ItemListener {
+// 	    /** Any implementation of ItemListener must include this method so that we can be informed when an item from the list is selected, and generate a predetermined hfile for that selection.
+// 	     * @param event An <strong>ItemEvent</strong> containing information about the selection.
+// 	     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl
+// 	     */
+// 	    public void itemStateChanged(ItemEvent event) {
+// 		// Determine if the selected element represents a hierarchy.
+// 		Object temp = ((JComboBox)value).getSelectedItem();
+// 		String filename = temp.toString();
+// 		// Search for a argument control called hfile and enable and set value.
+// 		for(int i = 0; i < central_pane.getComponentCount(); i++) {
+// 		    Object object = central_pane.getComponent(i);
+// 		    if(object instanceof ArgumentControl) {
+// 			ArgumentControl control = (ArgumentControl) object;
+// 			if(control.toString().equals("hfile")) {
+// 			    control.setValue(filename + ".txt");
+// 			    control.setEnabled(true);
+// 			}
+// 		    }
+// 		}
+// 	    }
+// 	}
+	/** A ListOption is a compound item which is constructed from several Strings. That magic part is that the length of screen real-estate used by the text version of this item is limited. */
+	private class ListOption
+	    implements Comparable {
+	    /** The maximum length of this String version of this item. */
+	    private int MAX_DESC = 65;
+	    /** The description of the value for this item. */
+	    private String description = null;
+	    /** A cached value for the text value of this option, as it never changes after the first call to toString(). */
+	    private String text = null;
+	    /** The value for this item. */
+	    private String value = null;
+	    /** Constructor.
+	     * @param value The value for this item as a <strong>String</strong>.
+	     * @param description The description of the value as a <strong>String</strong>.
+	     */
+	    public ListOption(String value, String description) {
+		this.description = description;
+		this.value = value;
+	    }
+	    /** Compare two possible ListOption objects for ordering.
+	     * @param object The <strong>Object</strong> to compare to.
+	     * @return An <i>int</i> indicating order as explained in String.
+	     * @see java.lang.String#compareTo
+	     */
+	    public int compareTo(Object object) {
+		return toString().compareTo(object.toString());
+	    }
+	    /** Tests two possible ListOption objects for equality. Uses the result from compareTo().
+	     * @param object The <strong>Object</strong> which may be equal.
+	     * @return <i>true</i> if the objects are equal, <i>false</i> otherwise.
+	     */
+	    public boolean equals(Object object) {
+		return (compareTo(object) == 0);
+	    }
+	    /** Retrieve the description of this list item.
+	     * @return The description as a <strong>String</strong>.
+	     */
+	    public String getDesc() {
+		return description;
+	    }
+	    /** Retrieve the value of this list item.
+	     * @return The value as a <strong>String</strong>.
+	     */
+	    public String getValue() {
+		return value;
+	    }
+       	    /** Convert this object into a nice readable String.
+	     * @return A <strong>String</strong> representing this object.
+	     */
+	    public String toString() {
+		if(text == null) {
+		    if(description.length() >= MAX_DESC) {
+		    	text = value + StaticStrings.MINUS_CHARACTER + description.substring(0, MAX_DESC) + StaticStrings.TRUNCATED_STRING;
+		    }
+		    else {
+		       text = value + StaticStrings.MINUS_CHARACTER + description;
+		    }
+		}
+		return text;
+	    }
+	}
+	/** Listener which removes entries from a list from a combobox when fired. */
+	private class RemoveListener
+	    implements ActionListener {
+	    /** The model behind the target list. */
+	    private DefaultListModel model = null;
+	    /** The list to remove data from. */
+	    private JList target = null;
+	    /** Constructor.
+	     * @param target A <strong>JList</strong>.
+	     */
+	    public RemoveListener(JList target) {
+		this.model = (DefaultListModel) target.getModel();
+		this.target = target;
+	    }
+	    /** When the remove button is clicked, we attempt to remove the selected metadata from the target.
+	     * @param event An <strong>ActionEvent</strong> containing information about the event.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		if(!target.isSelectionEmpty()) {
+		    int index = target.getSelectedIndex();
+		    model.remove(index);
+		}
+	    }
+	}
+	/** Listener that sets the tooltip associated to a combobox to the tooltip relevant to the selected item. */
+	private class ToolTipUpdater
+	    implements ActionListener {
+	    /** Any implementation of an ActionListener must include this method so that we can be informed when the selection in a combobox has changed and update the tooltip accordingly.
+	     * @param event An <strong>ActionEvent</strong> containing information about the action that fired this call.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		JComboBox source = (JComboBox)event.getSource();
+		Object object = source.getSelectedItem();
+		if(object instanceof ListOption) {
+		    ListOption lo = (ListOption)object;
+		    if(lo != null) {
+			String description = Utility.formatHTMLWidth(lo.getDesc(), 60);
+			source.setToolTipText(description);
+		    }
+		    else {
+			source.setToolTipText(StaticStrings.EMPTY_STR);
+		    }
+		}
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ArgumentContainer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ArgumentContainer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ArgumentContainer.java	(revision 10506)
@@ -0,0 +1,58 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+/**************************************************************************************
+ * Written:      20/05/02
+ * Revised:      03/07/03
+ **************************************************************************************/
+import java.util.ArrayList;
+
+/** This class provides an interface to any class that contains a list of Arguments.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public interface ArgumentContainer {
+    /** Method to retrieve the list of arguments from this container. Note that this method returns both the containers arguments plus its 'supers' arguments if any, and alphabetically orders them.
+     * @param include_normal true to filter so normal arguments are returned
+     * @param include_custom true to filter so custom arguments are returned
+     * @return the arguments within a ArrayList
+     */
+    public ArrayList getArguments(boolean include_normal, boolean include_custom);
+    /** Method to retrieve this containers custom argument string.
+     * @return the custom arguments as a String
+     */
+    public String getCustom();
+    /** Method to retrieve the name associated with this argument container.
+     * @return the name as a String
+     */
+    public String getName();
+    /** Method to set the custom arguments string.
+     * @param custom the new custom argument String
+     */
+    public void setCustom(String custom);
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Classifier.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Classifier.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Classifier.java	(revision 10506)
@@ -0,0 +1,412 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+/**************************************************************************************
+ * Written:      01/05/02
+ * Revised:      16/08/02 Optimized and Commented.
+ *               11/07/03 DOM support
+ **************************************************************************************/
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.w3c.dom.*;
+
+/** This class is responsible for storing information from a parsed classinfo.pl call in such a way that it allows easy access to parsed details for the purposes of user design and specification of classifiers.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class Classifier
+    extends ArrayList
+    implements ArgumentContainer, Comparable, DOMProxyListEntry, Serializable {
+
+    static final public String CLASSIFIER_PREFIX = "CL";
+
+    private boolean is_abstract = false;
+
+    /** A reference to the classifier that this one inherits from. */
+    private Classifier super_classifier = null;
+    /** The element this classifier is based upon. */
+    private Element element;
+    /** A description of this classifier. */
+    private String description = null;
+    /** The name of the classifier as it would appear in the collect.cfg file. */
+    private String name = null;
+    /** This string is filled out the first time this classifier is created, and remains unchanged there-after. It is used to match up with Format commands that may not yet have been instantiated (and thus only have offline references along the lines of 'CL1' to figure out what Classifier they want.) */
+    private String old_position_string = null;
+
+    /** Constructor used only in DOMProxyListModel initializations.
+     */
+    public Classifier() {
+    }
+
+    public Classifier(Element element, Classifier base_classifier) {
+	super();
+	this.element = element;
+	this.name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
+	///atherer.println("Establishing Classifier: " + name);
+	// Parse in any argument options for this classifier, keeping a list of the ones found
+	HashMap known_arguments = new HashMap();
+	NodeList option_elements = element.getElementsByTagName(StaticStrings.OPTION_ELEMENT);
+	int option_elements_length = option_elements.getLength();
+	for(int i = 0; i < option_elements_length; i++) {
+	    Element option_element = (Element) option_elements.item(i);
+	    Argument argument = new Argument(option_element);
+	    ///atherer.println("Rebuilding existing argument: " + argument.getName());
+	    argument.setOwner(name);
+	    add(argument);
+	    known_arguments.put(argument.getName(), argument);
+	}
+	// If a base classifier was given
+	if(base_classifier != null) {
+	    // Copy the details, and add a reference to whatever base_classifiers super classifier is.
+	    description = base_classifier.getDescription();
+	    // Now search through the 'dummy' arguments belonging to the base classifier. For each found, if it is already assigned, fill out further details such as type. If any are found that are not already assigned for this classifier, copy them and add them, but without a value.
+	    ArrayList all_arguments = base_classifier.getArguments(true, true);
+	    int argument_count = all_arguments.size();
+	    for(int j = 0; j < argument_count; j++) {
+		Argument base_argument = (Argument) all_arguments.get(j);
+		String base_argument_name = base_argument.getName();
+		///atherer.println("Library indicates this classifier should have an argument: " + base_argument_name);
+		Argument existing_argument = (Argument) known_arguments.get(base_argument_name);
+		// Found an existing argument. Complete its details
+		if(existing_argument != null) {
+		    ///atherer.println("Found existing argument. Filling out details.");
+		    existing_argument.setCustomArgument(false);
+		    existing_argument.setDefaultValue(base_argument.getDefaultValue());
+		    existing_argument.setDescription(base_argument.getDescription());
+		    existing_argument.setOptions(base_argument.getOptions());
+		    existing_argument.setRequired(base_argument.isRequired());
+		    existing_argument.setType(base_argument.getType());
+		}
+		// No existing argument. Copy base_argument and add it, but do not set its assigned flag. That should be set the first time its changed by the user.
+		else {
+		    ///atherer.println("No such argument. Adding new, unassigned, argument.");
+		    // The trick thing is that we have to create a new element in the DOM as well.
+		    Argument new_argument = base_argument.copy();
+		    new_argument.setOwner(name);
+		    Element argument_element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.OPTION_ELEMENT);
+		    argument_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, base_argument_name);
+		    argument_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
+		    argument_element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, StaticStrings.FALSE_STR);
+		    new_argument.setElement(argument_element);
+		    // All done. Add it.
+		    element.appendChild(argument_element);
+		    add(new_argument);
+		}
+	    }
+	}
+	old_position_string = getPositionString();
+    }
+
+    /** Constructor.
+     * @param name The name of this classifier as a <strong>String</strong>.
+     * @param description A description of this classifier as a <strong>String</strong>.
+     * @param super_classifier The super class of this classifier, as a <strong>Classifier</strong>.
+     */
+    public Classifier(String name, String description, Classifier super_classifier) {
+	super();
+	this.description = description;
+	this.name = name;
+	this.super_classifier = super_classifier;
+    }
+
+    /** Method to add an argument to this classifier. Only adds the argument if it isn't already present.
+     * @param argument The <strong>Argument</strong> to add.
+     */
+    public void addArgument(Argument argument) {
+	if(element == null && !contains(argument)) {
+	    add(argument);
+	    argument.setOwner(name);
+	}
+    }
+
+    /** Method to compare two classifiers for ordering.
+     * @param object The classifier we are comparing to, as an <strong>Object</strong>.
+     * @return An <i>int</i> specifying the classifier order, using values as set out in String.
+     * @see java.lang.String#compareTo
+     */
+    public int compareTo(Object object) {
+	if(object == null) {
+	    return -1;
+	}
+	return toString().compareTo(object.toString());
+    }
+
+    /** The assigned classifier constructor.
+     * @param element the DOM Element this classifier is based upon
+     */
+    public DOMProxyListEntry create(Element element) {
+	String classifier_name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
+	// Determine the base classifier from the classifier name
+	Classifier base_classifier = CollectionDesignManager.classifier_manager.getBaseClassifier(classifier_name);
+	Classifier classifier = new Classifier(element, base_classifier);
+	base_classifier = null;
+	classifier_name = null;
+	return classifier;
+    }
+
+    /** Method to determine if two classifiers are equal.
+     * @param object The classifier to test against, as an <strong>Object</strong>.
+     * @return <i>true</i> if the classifier names match, <i>false</i> otherwise.
+     */
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+
+    /** Method to retrieve an argument by its name.
+     * @param name The name of the argument as a <strong>String</strong>.
+     * @return The <strong>Argument</strong> requested, or <i>null</i> if no such argument.
+     */
+    public Argument getArgument(String name) {
+	// The name given may still include the '-'
+	if(name.startsWith("-")) {
+	    name = name.substring(1);
+	}
+	ArrayList arguments = getArguments(true, true);
+	for(int i = 0; i < arguments.size(); i++) {
+	    Argument argument = (Argument)arguments.get(i);
+	    if(argument.getName().equals(name)) {
+		return argument;
+	    }
+	}
+	return null;
+    }
+
+     /** Retrieve all of the arguments available to this base classifier, including its super classifiers arguments. Some complexity is added by allowing the caller to choose whether they want normal arguments, custom arguments, or both.
+      * @return an ArrayList of all of the arguments, starting with those for this classifier and ending with the arguments for basplug or similiar root classifier
+      */
+    public ArrayList getArguments(boolean include_normal, boolean include_custom) {
+	ArrayList arguments = new ArrayList();
+	if(include_normal && include_custom) {
+	    arguments.addAll(this);
+	}
+	else {
+	    int size = size();
+	    for(int i = 0; i < size; i++) {
+		Argument argument = (Argument) get(i);
+		if(argument.isCustomArgument()) {
+		    if(include_custom && !arguments.contains(argument)) {
+			arguments.add(argument);
+		    }
+		}
+		else {
+		    if(include_normal && !arguments.contains(argument)) {
+			arguments.add(argument);
+		    }
+		}
+		argument = null;
+	    }
+	}
+	if(super_classifier != null) {
+	    ArrayList remainder = super_classifier.getArguments(include_normal, include_custom);
+	    remainder.removeAll(arguments);
+	    arguments.addAll(remainder);
+	}
+	return arguments;
+    }
+
+    /** Method to retrieve a classifiers custom argument information. Custom arguments are defined to be those that have not got matching arguments in the base reference classifier from the library. Of course if there is no base classifier then all arguments are considered to be custom.
+     * @return the custom arguments as a String
+     */
+    public String getCustom() {
+	StringBuffer custom_text = new StringBuffer();
+	// Retrieve all of the arguments, and append any that are custom into one long string
+	ArrayList arguments = getArguments(false, true);
+	int arguments_size = arguments.size();
+	boolean first = true;
+	for(int i = 0; i < arguments_size; i++) {
+	    Argument argument = (Argument) arguments.get(i);
+	    if(argument.isAssigned()) {
+		if(!first) {
+		    custom_text.append(" ");
+		}
+		custom_text.append(argument.toString());
+		first = false;
+	    }
+	}
+	return custom_text.toString();
+    }
+
+    public String getDescription() {
+	return description;
+    }
+
+    public Element getElement() {
+	return element;
+    }
+
+    /** Method to retrieve a classifiers name.
+     * @return A <strong>String</strong> containing the classifiers name.
+     */
+    public String getName() {
+	if(name == null && element != null) {
+	    name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
+	}
+	return name;
+    }
+
+    /* private String getOldPositionString() {
+	return old_position_string;
+	} */
+
+    /** Generate the string showing this classifiers position. */
+    public String getPositionString() {
+	String position_string = CLASSIFIER_PREFIX;
+	if(element != null) {
+	    // Determine our place in the collect.cfg file
+	    int position_int = CollectionDesignManager.classifier_manager.indexOf(this) + 1;
+	    if(position_int != -1) {
+		position_string = position_string + position_int;
+	    }
+	}
+	return position_string;
+    }
+
+    public boolean isAbstract() {
+	return is_abstract;
+    }
+
+    public boolean isAssigned() {
+	return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
+    }
+
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    /** Set the custom arguments. This turns out to be quite tricky. We must parse in the string, searching for arguments (for that we use a handy method in CollectionConfiguration). Next, for each argument, we check if we already know about it. If so we update its value, otherwise we create a new argument and assign it (must assign!).
+     * @param custom_str the custom arguments all splodged together in one String
+     */
+    public void setCustom(String custom_str) {
+	HashMap raw_arguments = CollectionConfiguration.parseArguments(new CommandTokenizer(custom_str));
+	ArrayList custom_arguments = getArguments(false, true);
+	int size = custom_arguments.size();
+	for(int i = 0; i < size; i++) {
+	    Argument argument = (Argument) custom_arguments.get(i);
+	    String original_argument_name = StaticStrings.MINUS_CHARACTER + argument.getName();
+	    if(raw_arguments.containsKey(original_argument_name)) {
+		// Set as assigned
+		argument.setAssigned(true);
+		String argument_value = (String)raw_arguments.remove(original_argument_name);
+		if(argument_value != null) {
+		    argument.setValue(argument_value);
+		    argument_value = null;
+		}
+	    }
+	    // We've removed it from our custom statement, so unassign
+	    else {
+		argument.setAssigned(false);
+	    }
+	    argument = null;
+	}
+	// Any left over, add to the classifier
+	Iterator argument_names = raw_arguments.keySet().iterator();
+	while(argument_names.hasNext()) {
+	    String argument_name = (String) argument_names.next();
+	    String argument_value = (String) raw_arguments.get(argument_name);
+	    // The tricky thing is that we have to create a new element in the DOM as well.
+	    Element argument_element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.OPTION_ELEMENT);
+	    argument_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, argument_name.substring(1));
+	    argument_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
+	    argument_element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, StaticStrings.TRUE_STR);
+	    Argument argument = new Argument(argument_element);
+	    argument_name = null;
+	    if(argument_value != null) {
+		argument.setValue(argument_value);
+		argument_value = null;
+	    }
+	    // All done. Add it.
+	    element.appendChild(argument_element);
+	    add(argument);
+	    argument_element = null;
+	}
+	raw_arguments = null;
+    }
+
+    /** Method to set the value of desc.
+     * @param description The new value of desc as a <strong>String</strong>.
+     */
+    public void setDescription(String description) {
+	this.description = description;
+    }
+
+    public void setElement(Element element) {
+	this.element = element;
+    }
+
+    public void setIsAbstract(boolean is_abstract) {
+	this.is_abstract = is_abstract;
+    }
+
+    /** Method to set the value of name.
+     * @param name The new value of name as a <strong>String</strong>.
+     */
+    public void setName(String name) {
+	this.name = name;
+    }
+
+    /** Method to set the value of the super_classifier.
+     * @param super_classifier The new value of super_classifier as a <strong>Classifier</strong>, or <i>null</i> if this class has no inheritance.
+     */
+    public void setSuper(Classifier super_classifier) {
+	this.super_classifier = super_classifier;
+    }
+
+
+    /** Method to print out this classifier as it would appear to the user in the interface
+     * @return A <strong>String</strong> containing a single classifier command.
+     */
+    public String toString()
+    {
+	if (element == null) {
+	    return name;
+	}
+
+	if (name == null) {
+	    name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
+	}
+
+	StringBuffer text = new StringBuffer(StaticStrings.CLASSIFY_STR);
+	text.append(" ");
+	text.append(name);
+
+	ArrayList arguments = getArguments(true, true);
+	for (int i = 0; i < arguments.size(); i++) {
+	    Argument argument = (Argument) arguments.get(i);
+	    if (argument.isAssigned()) {
+		text.append(" ");
+		text.append(argument.toString());
+	    }
+	}
+
+	return text.toString();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ClassifierManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ClassifierManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ClassifierManager.java	(revision 10506)
@@ -0,0 +1,926 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.jar.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.apache.xerces.parsers.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.LocalGreenstone;
+import org.greenstone.gatherer.gui.GComboBox;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+/** This class is responsible for keeping track of all the classifiers assigned to this collection, and providing methods for adding and removing them.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class ClassifierManager
+    extends DOMProxyListModel {
+
+    /** A list of known, but currently unassigned, classifiers. */
+    private ArrayList library = null;
+    /** The controls for editing the contents of this manager. */
+    private Control controls = null;
+
+    private DOMProxyListModel model;
+
+    /** Constructor.
+     * @see org.greenstone.gatherer.cdm.DynamicListModel
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     */
+    public ClassifierManager() {
+	super(CollectionDesignManager.collect_config.getDocumentElement(), CollectionConfiguration.CLASSIFY_ELEMENT, new Classifier());
+	this.model = this;
+	DebugStream.println("ClassifierManager: " + getSize() + " classifiers parsed.");
+	// Reload/Create the library
+	loadClassifiers();
+	saveClassifiers();
+    }
+
+    /** Method to add a new classifier to library.
+     * @param classifier The new <strong>Classifier</strong>.
+     * @see org.greenstone.gatherer.cdm.DynamicListModel
+     */
+    private void addClassifier(Classifier classifier) {
+	if(!library.contains(classifier)) {
+	    library.add(classifier);
+	}
+    }
+
+    /** Method to assign a classifier.
+     * @param classifier The base <strong>Classifier</strong> to assign.
+     * @see org.greenstone.gatherer.cdm.DynamicListModel
+     */
+    private void assignClassifier(Classifier classifier) {
+	if(!contains(classifier)) {
+	    Element element = classifier.getElement();
+	    // Locate where we should insert this new classifier.
+	    Node target_node = CollectionConfiguration.findInsertionPoint(element);
+	    add(root, classifier, target_node);
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+
+    public static boolean clearClassifierCache() {
+
+	DebugStream.println("deleting classifiers.dat");
+	File class_file = new File(Gatherer.getGLIUserDirectoryPath() + "classifiers.dat");
+	if (class_file.exists()) {
+	    return Utility.delete(class_file);
+	}
+	return true;
+    }
+    /** Destructor.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.cdm.CollectionDesignManager
+     * @see org.greenstone.gatherer.cdm.DynamicListModel
+     */
+    public void destroy() {
+	if(controls != null) {
+	    controls.destroy();
+	    controls = null;
+	}
+	library.clear();
+	library = null;
+    }
+
+    public Classifier getBaseClassifier(String name) {
+	int library_size = library.size();
+	for(int i = 0; i < library_size; i++) {
+	    Classifier classifier = (Classifier) library.get(i);
+	    if(classifier.getName().equals(name)) {
+		return classifier;
+	    }
+	}
+	// No success.
+	return null;
+    }
+
+    /** Method to retrieve the classifier with the given index.
+     * @param index The index of the desired classifier as an <i>int</i>.
+     * @return The requested Classifier or <i>null</i> if no such classifier exists.
+     */
+    public Classifier getClassifier(int index) {
+	if(0 <= index && index < getSize()) {
+	    return (Classifier) getElementAt(index);
+	}
+	return null;
+    }
+
+    /** Method to retrieve the control for this manager.
+     * @return the Control for editing classifiers
+     */
+    public Control getControls() {
+	if(controls == null) {
+	    // Build controls
+	    this.controls = new ClassifierControl();
+	}
+	return controls;
+    }
+
+    public ArrayList getHierarchyClassifiers() {
+	ArrayList result = new ArrayList();
+	for(int i = 0; i < getSize(); i++) {
+	    Classifier classifier = (Classifier) getElementAt(i);
+	    if(classifier.getName().equalsIgnoreCase(StaticStrings.HIERARCHY_CLASSIFIER)) {
+		result.add(classifier);
+	    }
+	    classifier = null;
+	}
+	return result;
+
+    }
+
+    /** Determine if the Phind classifier has been assigned.
+     * @return true if it has, false otherwise
+     */
+    public boolean isPhindClassifierAssigned() {
+	for(int i = 0; i < getSize(); i++) {
+	    Classifier classifier = (Classifier) getElementAt(i);
+	    if(classifier.getName().equalsIgnoreCase(StaticStrings.PHIND_CLASSIFIER)) {
+		return true;
+	    }
+	    classifier = null;
+	}
+	return false;
+    }
+
+    /** Method to move a classifier in the list order.
+     * @param classifier the Classifier you want to move.
+     * @param direction true to move the classifier up, false to move it down.
+     * @param all true to move to move all the way, false for a single step.
+     */
+    private void moveClassifier(Classifier classifier, boolean direction, boolean all) {
+	if(getSize() < 2) {
+	    DebugStream.println("Not enough classifiers to allow moving.");
+	    return;
+	}
+	if(all) {
+	    // Move to top
+	    if(direction) {
+		// Remove the moving classifier
+		remove(classifier);
+		// Retrieve the first classifier
+		Classifier first_classifier = (Classifier) getElementAt(0);
+		// Add the moving classifier before the first classifier
+		addBefore(classifier, first_classifier);
+		first_classifier = null;
+	    }
+	    else {
+		// Remove the moving classifier
+		remove(classifier);
+		// And add after last classifier
+		add(getSize(), classifier);
+	    }
+	}
+	else {
+	    // Try to move the classifier one step in the desired direction.
+	    int index = indexOf(classifier);
+	    ///ystem.err.println("Index of " + classifier + " = " + index);
+	    if(direction) {
+		index--;
+		if(index < 0) {
+		    String args[] = new String[2];
+		    args[0] = Dictionary.get("CDM.ClassifierManager.Classifier");
+		    args[1] = classifier.getName();
+		    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.At_Top", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
+		    return;
+		}
+		remove(classifier);
+		add(index, classifier);
+	    }
+	    else {
+		index++;
+		if(index >= getSize()) {
+		    String args[] = new String[2];
+		    args[0] = Dictionary.get("CDM.ClassifierManager.Classifier_Str");
+		    args[1] = classifier.getName();
+		    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.At_Bottom", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
+		    return;
+		}
+		remove(classifier);
+		add(index, classifier);
+	    }
+	}
+	
+	Gatherer.c_man.configurationChanged();
+	// tell the format manager to update the names of its format statements
+	Gatherer.c_man.getCollection().cdm.format_manager.refresh();
+    }
+    
+    /** This method removes an assigned classifier. I was tempted to call it unassign, but remove is more consistant. Note that there is no way to remove a classifier from the library.
+     * @param classifier The Classifier to remove
+     * @see org.greenstone.gatherer.cdm.DynamicListModel
+     */
+    private void removeClassifier(Classifier classifier) {
+	remove(classifier);
+	Gatherer.c_man.configurationChanged();
+    }
+
+    /** Method to cache the current contents of library (known classifiers) to file.
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    private void saveClassifiers() {
+	try {
+	    File classifiers_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "classifiers.dat");
+	    FileOutputStream file = new FileOutputStream(classifiers_dat_file);
+	    ObjectOutputStream out = new ObjectOutputStream(file);
+	    out.writeObject(library);
+	    out.close();
+	}
+	catch (Exception error) {
+	}
+    }
+
+    private Object[] getAvailable() {
+	ArrayList available = new ArrayList();
+	int library_size = library.size();
+	for(int i = 0; i < library_size; i++) {
+	    Classifier classifier = (Classifier) library.get(i);
+	    if(!classifier.isAbstract()) {
+		available.add(classifier);
+	    }
+	    classifier = null;
+	}
+	return available.toArray();
+    }
+
+    /** Method to extract just the classifiers name from a file object.
+     * @param classifier The <strong>File</strong> which references a certain classifier.
+     * @return A <strong>String</strong> containing just the classifiers name, without extension.
+     */
+    private String getClassifierName(String filename) {
+	String name = filename;
+	if(name.indexOf(".") != -1) {
+	    name = name.substring(0, name.indexOf("."));
+	}
+	return name;
+    }
+
+    /** Method to load the details of a single plug-in.
+     * @param classifier The classifier <strong>File</strong> you wish to load.
+     */
+    private void loadClassifier(String classifier, String lang) {
+	///ystem.err.println("Attempting to parse " + classifier);
+	Document document = null;
+	InputStream input_stream = null;
+
+	long start;
+	long end;
+	// Run classinfo on this classifier, and then send the results for parsing.
+	try {
+	    if (Gatherer.isGsdlRemote) {
+		String launch  = Gatherer.cgiBase + "launch";
+		launch += "?cmd=classinfo.pl";
+		launch += "&xml=&language="+lang;
+		launch += "&class=" + getClassifierName(classifier);
+		
+		System.err.println("*** launch = " + launch);
+		
+		URL launch_url = new URL(launch);
+		URLConnection launch_connection = launch_url.openConnection();
+		input_stream = launch_connection.getInputStream();
+	    }
+	    else {
+		String args[] = null;
+		if(Utility.isWindows()) {
+		    args = new String[6];
+		    if(Configuration.perl_path != null) {
+			args[0] = Configuration.perl_path;
+		    }
+		    else {
+			args[0] = "Perl.exe";
+		    }
+		    args[1] = LocalGreenstone.getBinScriptDirectoryPath() + "classinfo.pl";
+		    args[2] = "-xml";
+		    args[3] = "-language";
+		    args[4] = lang;
+		    args[5] = getClassifierName(classifier);
+		}
+		else {
+		    args = new String[5];
+		    args[0] = "classinfo.pl";
+		    args[1] = "-xml";
+		    args[2] = "-language";
+		    args[3] = lang;
+		    args[4] = getClassifierName(classifier);
+		}
+
+		// Create the process.
+		Runtime runtime = Runtime.getRuntime();
+		Process process = runtime.exec(args);
+
+		input_stream = process.getErrorStream();
+	    }
+
+	    StringBuffer xml = Utility.readXMLStream(input_stream);
+	    document = CollectionDesignManager.XMLStringToDOM(xml,classifier);
+	}
+	catch (Exception error) {
+	    error.printStackTrace();
+	    ///ystem.err.println("Error: Cannot parse " + getClassifierName(classifier));
+	}
+	if(document != null) {
+	    parseXML(document.getDocumentElement());
+	}
+    }
+
+    /** Method to initially load information from the standard classifiers within the gsdl Perl library.
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    private void loadClassifiers() {
+	// Attempt to restore the cached file.
+	File classifiers_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "classifiers.dat");
+	try {
+	    FileInputStream file = new FileInputStream(classifiers_dat_file);
+	    ObjectInputStream input = new ObjectInputStream(file);
+	    library = (ArrayList) input.readObject();
+	}
+	catch (Exception error) {
+	    DebugStream.println("Unable to open " + classifiers_dat_file);
+	}
+
+	if(library == null) {
+	    library = new ArrayList();
+
+	    if (Gatherer.isGsdlRemote) {
+
+		String lang = Configuration.getLanguage();
+
+		String launch  = Gatherer.cgiBase + "launch";
+		launch += "?cmd=classinfo.pl";
+		launch += "&xml=&language="+lang;
+		launch += "&listall=";
+
+		System.err.println("*** launch = " + launch);
+
+		try {
+		    URL launch_url = new URL(launch);
+		    URLConnection launch_connection = launch_url.openConnection();
+		    InputStream input_stream = launch_connection.getInputStream();
+		    loadClassifiers(input_stream);
+		}
+		catch (Exception error) {
+		    System.err.println("Failed when trying to connect to : " + launch);
+		    error.printStackTrace();
+		}
+
+	    }
+	    else {
+
+		// Retrieve the gsdl home directory...
+		String directory = LocalGreenstone.getDirectoryPath();
+		directory = directory + "perllib" + File.separator + "classify" + File.separator;
+
+		String current_lang = Configuration.getLanguage();
+		File files[] = (new File(directory)).listFiles();
+		if(files != null) {
+		    // Create a progress indicator.
+		    ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.ClassifierManager.Parsing.Title"), Dictionary.get("CDM.ClassifierManager.Parsing.Message"), files.length);
+		    for(int i = 0; i < files.length; i++) {
+			// We only want to check Perl Modules.
+			if(files[i].getName().endsWith(".pm")) {
+			    loadClassifier(files[i].getName(), current_lang);
+			}
+			progress.inc();
+		    }
+		    progress.dispose();
+		    progress.destroy();
+		    progress = null;
+		}
+	    }
+	}
+    }
+
+
+
+    /** Method to load classifier information from a specified input stream (could be local or through URL). Of course no classifiers may be found at this location.
+     * @param input_stream An <strong>InputStream</strong> indicating the where list of classifiers -- encoded in XML -- can be read from
+     */
+    private void loadClassifiers(InputStream input_stream) 
+    {
+	StringBuffer xml  = Utility.readXMLStream(input_stream);
+	Document document = CollectionDesignManager.XMLStringToDOM(xml, "-listall");
+
+	// Parse XML to build up list of classifier names
+	Node root = document.getDocumentElement();
+
+	NamedNodeMap attributes = root.getAttributes();
+	Node length_node = attributes.getNamedItem("length");
+	String num_classifiers_str = length_node.getNodeValue();
+	int num_classifiers = Integer.parseInt(num_classifiers_str);
+	String class_list[] = new String[num_classifiers];
+
+	Node node = root.getFirstChild();
+	int i = 0;
+	while (node != null) {
+	    String node_name = node.getNodeName();
+	    if (node_name.equalsIgnoreCase("ClassifyName")) {
+		String name = XMLTools.getValue(node);
+		class_list[i] = name;
+		i++;		
+	    }
+
+	    node = node.getNextSibling();
+	}
+
+	String current_lang = Configuration.getLanguage();
+	if (num_classifiers>0) {
+	    // Create a progress indicator.
+	    ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.ClassifierManager.Parsing.Title"), Dictionary.get("CDM.ClassifierManager.Parsing.Message"), num_classifiers);
+
+	    for (i=0; i<num_classifiers; i++) {
+		String classifier = class_list[i];
+		loadClassifier(classifier, current_lang);
+		progress.inc();
+	    }
+	    progress.dispose();
+	    progress.destroy();
+	    progress = null;
+	}
+    }
+
+
+    /** Parses a DOM tree model turning it into a Classifier and its associated arguments.
+     * @param root The <strong>Node</strong> at the root of the DOM model.
+     * @return A newly created <strong>Classifier</strong> based on the information parsed from the DOM model.
+     * @see org.greenstone.gatherer.cdm.Argument
+     */
+    private Classifier parseXML(Node root) {
+	Classifier classifier = new Classifier();
+	String node_name = null;
+	for(Node node = root.getFirstChild(); node != null;
+	    node = node.getNextSibling()) {
+	    node_name = node.getNodeName();
+	    if(node_name.equals("Name")) {
+		String name = XMLTools.getValue(node);
+		// We can save ourselves some processing time if a classifier with this name already exists in our manager. If so retrieve it and return it.
+		Classifier existing = getBaseClassifier(name);
+		if(existing != null) {
+		    return existing;
+		}
+		classifier.setName(name);
+	    }
+	    else if(node_name.equals("Desc")) {
+		classifier.setDescription(XMLTools.getValue(node));
+	    }
+	    else if(node_name.equals("Abstract")) {
+		classifier.setIsAbstract(XMLTools.getValue(node).equalsIgnoreCase(CollectionConfiguration.YES_STR));
+	    }
+	    // Parse the multitude of arguments.
+	    else if(node_name.equals("Arguments")) {
+		for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
+		    node_name = arg.getNodeName();
+		    // An option.
+		    if(node_name.equals("Option")) {
+			Argument argument = new Argument();
+			argument.parseXML((Element)arg);
+			classifier.addArgument(argument);
+		    }
+		    // A super classifier class.
+		    else if(node_name.equals("ClassInfo")) {
+			Classifier super_classifier = parseXML(arg);
+			classifier.setSuper(super_classifier);
+		    }
+		}
+	    }
+	}
+	if(classifier.getName() != null) {
+	    addClassifier(classifier);
+	    return classifier;
+	}
+	return null;
+    }
+
+    /** A class which provides controls for assigned and editing classifiers. */
+    private class ClassifierControl
+	extends JPanel
+	implements Control {
+	/** A combobox containing all of the known classifiers, including those that may have already been assigned. */
+	private GComboBox classifier = null;
+	/** Button for adding classifiers. */
+	private JButton add = null;
+	/** Button for configuring the selected classifier. */
+	private JButton configure = null;
+
+	//private JButton move_bottom_button;
+
+	private JButton move_down_button;
+
+	//private JButton move_top_button;
+
+	private JButton move_up_button;
+
+	/** Button to remove the selected classifier. */
+	private JButton remove = null;
+
+	/** A list of assigned classifiers. */
+	private JList classifier_list = null;
+	/** The text area containing instructions on the use of this control. */
+	private JTextArea instructions = null;
+
+	/** Constructor.
+	 * @see org.greenstone.gatherer.cdm.ClassifierManager.ClassifierControl.AddListener
+	 * @see org.greenstone.gatherer.cdm.ClassifierManager.ClassifierControl.ConfigureListener
+	 * @see org.greenstone.gatherer.cdm.ClassifierManager.ClassifierControl.RemoveListener
+	 */
+	public ClassifierControl() {
+	    Collections.sort(library);
+	    // Create
+	    add = new GLIButton();
+	    add.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add, "CDM.ClassifierManager.Add", "CDM.ClassifierManager.Add_Tooltip");
+	    JPanel button_pane = new JPanel();
+	    JPanel central_pane = new JPanel();
+	    configure = new GLIButton();
+	    configure.setEnabled(false);
+	    configure.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.registerBoth(configure, "CDM.ClassifierManager.Configure", "CDM.ClassifierManager.Configure_Tooltip");
+	    JPanel header_pane = new JPanel();
+	    instructions = new JTextArea();
+	    instructions.setEditable(false);
+	    instructions.setLineWrap(true);
+	    instructions.setRows(6);
+	    instructions.setWrapStyleWord(true);
+	    Dictionary.registerText(instructions, "CDM.ClassifierManager.Instructions");
+
+	    ClassifierComboboxListener ccl = new ClassifierComboboxListener();
+	    classifier = new GComboBox(getAvailable());
+	    classifier.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
+	    classifier.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
+	    classifier.setEditable(true);
+	    classifier.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
+	    classifier.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
+	    if(classifier.getItemCount() > 0) {
+		classifier.setSelectedIndex(0);
+		ccl.itemStateChanged(new ItemEvent(classifier, 0, null, ItemEvent.SELECTED));
+	    }
+
+	    JLabel classifier_label = new JLabel();
+	    Dictionary.registerText(classifier_label, "CDM.ClassifierManager.Classifier");
+	    classifier_list = new JList(model);
+	    classifier_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	    JLabel classifier_list_label = new JLabel();
+	    classifier_list_label.setHorizontalAlignment(JLabel.CENTER);
+	    classifier_list_label.setOpaque(true);
+	    Dictionary.registerText(classifier_list_label, "CDM.ClassifierManager.Assigned");
+	    JPanel classifier_list_pane = new JPanel();
+	    JPanel classifier_pane = new JPanel();
+	    remove = new GLIButton();
+	    remove.setEnabled(false);
+	    remove.setMnemonic(KeyEvent.VK_R);
+	    Dictionary.registerBoth(remove, "CDM.ClassifierManager.Remove", "CDM.ClassifierManager.Remove_Tooltip");
+
+	    JLabel title = new JLabel();
+	    title.setHorizontalAlignment(JLabel.CENTER);
+	    title.setOpaque(true);
+	    Dictionary.registerText(title, "CDM.ClassifierManager.Title");
+
+	    JPanel temp = new JPanel(new BorderLayout());
+
+	    JPanel move_button_pane = new JPanel();
+
+	    move_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
+	    move_up_button.setEnabled(false);
+	    move_up_button.setMnemonic(KeyEvent.VK_U);
+	    Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
+
+	    move_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
+	    move_down_button.setEnabled(false);
+	    move_down_button.setMnemonic(KeyEvent.VK_D);
+	    Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
+
+	    // Listeners
+	    add.addActionListener(new AddListener());
+	    add.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    classifier.addItemListener(ccl);
+	    configure.addActionListener(new ConfigureListener());
+	    configure.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    remove.addActionListener(new RemoveListener());
+	    remove.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    classifier_list.addMouseListener(new ClickListener());
+	    classifier_list.addListSelectionListener(new ListListener());
+	    ccl = null;
+
+	    MoveListener ml = new MoveListener();
+	    //move_bottom_button.addActionListener(ml);
+	    move_down_button.addActionListener(ml);
+	    move_down_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    //move_top_button.addActionListener(ml);
+	    move_up_button.addActionListener(ml);
+	    move_up_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+
+	    // Layout
+	    title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
+
+	    instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
+
+	    header_pane.setLayout(new BorderLayout());
+	    header_pane.add(title, BorderLayout.NORTH);
+	    header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
+
+	    move_button_pane.setLayout(new GridLayout(4,1));
+	    move_button_pane.add(move_up_button);
+	    move_button_pane.add(new JPanel());
+	    move_button_pane.add(new JPanel());
+	    move_button_pane.add(move_down_button);
+
+	    classifier_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
+
+	    classifier_list_pane.setLayout(new BorderLayout());
+	    classifier_list_pane.add(classifier_list_label, BorderLayout.NORTH);
+	    classifier_list_pane.add(new JScrollPane(classifier_list), BorderLayout.CENTER);
+	    classifier_list_pane.add(move_button_pane, BorderLayout.EAST);
+
+	    classifier_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+
+	    classifier_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
+	    classifier_pane.setLayout(new BorderLayout(5,0));
+	    classifier_pane.add(classifier_label, BorderLayout.WEST);
+	    classifier_pane.add(classifier, BorderLayout.CENTER);
+
+	    button_pane.setLayout(new GridLayout(1, 3));
+	    button_pane.add(add);
+	    button_pane.add(configure);
+	    button_pane.add(remove);
+
+	    // Scope these mad bordering skillz.
+	    temp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,0,5,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(Dictionary.get("CDM.ClassifierManager.Controls")), BorderFactory.createEmptyBorder(2,2,2,2))));
+	    temp.add(classifier_pane, BorderLayout.NORTH);
+	    temp.add(button_pane, BorderLayout.SOUTH);
+
+	    central_pane.setLayout(new BorderLayout());
+	    central_pane.add(classifier_list_pane, BorderLayout.CENTER);
+	    central_pane.add(temp, BorderLayout.SOUTH);
+
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    add(header_pane, BorderLayout.NORTH);
+	    add(central_pane, BorderLayout.CENTER);
+	}
+
+	/** Method which acts like a destructor, tidying up references to persistant objects.
+	 */
+	public void destroy() {
+	    add = null;
+	    classifier = null;
+	    classifier_list = null;
+	    configure = null;
+	    instructions = null;
+	    remove = null;
+	}
+
+	/** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
+	 */
+	public void gainFocus() {
+	    if(instructions != null) {
+		instructions.setCaretPosition(0);
+	    }
+	}
+
+	public void loseFocus() {
+	}
+
+	/** This class listens for actions upon the add button in the controls, and if detected calls the assignClassifier() method.
+	 */
+	private class AddListener
+	    implements ActionListener {
+	    /** Any implementation of ActionListener must include this method so that we can be informed when an action has occured on one of our target controls, so that we can add the selected Classifier.
+	     * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
+	     * @see org.greenstone.gatherer.Gatherer
+	     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
+	     * @see org.greenstone.gatherer.cdm.Classifier
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		Object selected_object = classifier.getSelectedItem();
+		// If there is something in the combobox, but we haven't registered a selection, then add the object and select it!
+		if(selected_object != null) {
+		    // Retrieve the base classifier
+		    Classifier base_classifier = getBaseClassifier(selected_object.toString());
+
+		    // Create a new element in the DOM
+		    Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.CLASSIFY_ELEMENT);
+		    Classifier new_classifier = null;
+		    if(base_classifier != null) {
+			DebugStream.println("Creating Classifier based on existing Classifer.");
+			element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_classifier.getName());
+			new_classifier = new Classifier(element, base_classifier);
+		    }
+		    else {
+			DebugStream.println("Creating new custom Classifier.");
+			element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
+			new_classifier = new Classifier(element, null);
+			// Also we add the custom classifier name to the combobox for convienence.
+			classifier.addItem(selected_object);
+		    }
+		    element = null;
+		    // Automatically chain to configuration. This ensures required arguments are filled out.
+		    ArgumentConfiguration ac = new ArgumentConfiguration(new_classifier);
+		    if(ac.display()) {
+			if(!model.contains(new_classifier)) {
+			    assignClassifier(new_classifier);
+			    classifier_list.setSelectedValue(new_classifier, true);
+			}
+			else {
+			    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.ClassifierManager.Classifier_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+			}
+		    }
+		    ac = null;
+		    new_classifier = null;
+		}
+	    }
+	}
+
+    /** This listener reacts to changes in the current selection of the classifier combobox. */
+    private class ClassifierComboboxListener
+        implements ItemListener {
+        /** When a user selects a certain plugin, update the tooltip to show the plugin description. */
+        public void itemStateChanged(ItemEvent event) {
+            if(event.getStateChange() == ItemEvent.SELECTED) {
+                // Retrieve the selected plugin
+                Object current_selection = classifier.getSelectedItem();
+                // And reset the tooltip. If the plugin is null or is a string, then go back to the default message
+                if(current_selection == null || current_selection instanceof String) {
+                    Dictionary.registerTooltip(classifier, "CDM.ClassifierManager.Classifier_Tooltip");
+                }
+                else {
+                    Classifier current_classifier = (Classifier) current_selection;
+                    Dictionary.registerTooltipText(classifier, Utility.formatHTMLWidth(current_classifier.getDescription(), 40));
+                    current_classifier = null;
+                }
+                current_selection = null;
+            }
+        }
+    }
+
+	/** Listens for double clicks apon the list and react as if the configure button was pushed. */
+	private class ClickListener
+	    extends MouseAdapter {
+	    /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
+	     * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
+	     */
+	    public void mouseClicked(MouseEvent event) {
+		if(event.getClickCount() == 2 ) {
+		    if(!classifier_list.isSelectionEmpty()) {
+			Classifier classifier = (Classifier) classifier_list.getSelectedValue();
+			ArgumentConfiguration ac = new ArgumentConfiguration(classifier);
+			if(ac.display()) {
+			    refresh(classifier);
+			}
+			ac.destroy();
+			ac = null;
+		    }
+		}
+	    }
+	}
+
+	/** This class listens for actions upon the configure button in the controls, and if detected creates a new ArgumentConfiguration dialog box to allow for configuration.
+	 */
+	private class ConfigureListener
+	    implements ActionListener {
+	    /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
+	     * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
+	     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
+	     * @see org.greenstone.gatherer.cdm.Classifier
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		if(!classifier_list.isSelectionEmpty()) {
+		   Classifier classifier = (Classifier) classifier_list.getSelectedValue();
+		   ArgumentConfiguration ac = new ArgumentConfiguration(classifier);
+		   if(ac.display()) {
+		       refresh(classifier);
+		   }
+		   ac.destroy();
+		   ac = null;
+		}
+	    }
+	}
+
+	/** listens for changes in the list selection and enables the configure and remove buttons if there is a selection, disables them if there is no selection */
+	private class ListListener
+	    implements ListSelectionListener {
+
+	    public void valueChanged(ListSelectionEvent e) {
+		if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
+		    if (classifier_list.isSelectionEmpty()) {
+			move_up_button.setEnabled(false);
+			move_down_button.setEnabled(false);
+			configure.setEnabled(false);
+			remove.setEnabled(false);
+		    }
+		    else {
+			configure.setEnabled(true);
+			remove.setEnabled(true);
+			int selected_index = classifier_list.getSelectedIndex();
+			move_up_button.setEnabled(selected_index !=0);
+			move_down_button.setEnabled(selected_index != model.getSize()-1);
+		    }
+		}
+	    }
+	}
+
+	/** Listens for actions apon the move buttons in the manager controls, and if detected calls the <i>moveClassifier()</i> method of the manager with the appropriate details. */
+	private class MoveListener
+	    implements ActionListener {
+	    /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
+	     * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		if(!classifier_list.isSelectionEmpty()) {
+		    Object object = classifier_list.getSelectedValue();
+		    if(object instanceof Classifier) {
+			Classifier classifier = (Classifier) object;
+			//if(event.getSource() == move_top_button) {
+			//    moveClassifier(classifier, true, true);
+			//}
+			//else 
+			if(event.getSource() == move_up_button) {
+			    moveClassifier(classifier, true, false);
+			}
+			else if(event.getSource() == move_down_button) {
+			    moveClassifier(classifier, false, false);
+			}
+			//else {
+			//    moveClassifier(classifier, false, true);
+			//}
+			classifier_list.setSelectedValue(classifier, true);
+		    }
+		}
+	    }
+	}
+
+	/** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removeClassifier()</i> method.
+	 */
+	private class RemoveListener
+	    implements ActionListener {
+	    /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
+	     * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		if(classifier_list.isSelectionEmpty()) {
+		    remove.setEnabled(false);
+		    return;
+		}
+		int selected_index = classifier_list.getSelectedIndex();
+		Object selected_classifier = classifier_list.getSelectedValue();
+		if (!(selected_classifier instanceof Classifier)) {
+		    return; // what else could we have here???
+		}
+		removeClassifier((Classifier)selected_classifier);
+
+		if (selected_index >= classifier_list.getModel().getSize()) {
+		    selected_index--;
+		}
+		if (selected_index >=0) {
+		    classifier_list.setSelectedIndex(selected_index);
+		} else {
+		    // no more classifiers in the list
+		    remove.setEnabled(false);
+		}
+		
+	    }
+	}
+    }
+    
+
+    
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionConfiguration.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionConfiguration.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionConfiguration.java	(revision 10506)
@@ -0,0 +1,1695 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.metadata.MetadataTools;
+import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
+import org.greenstone.gatherer.util.DOMTree;
+import org.greenstone.gatherer.util.Codec;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.greenstone.gatherer.util.ZipTools;
+import org.w3c.dom.*;
+
+/** This class provides either access to a pseudo-G3 document, or parses a collect.cfg file in such a way as to provide an xml-type view of its content. This later version is useful as it allows the manipulation and free form editing of a legacy collect.cfg file while still allowing the various CDM data managers to base themselves directly on this model (whereas they used to be independant ListModels which clobbered the ordering of unparsed commands).
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3d
+ */
+public class CollectionConfiguration
+    extends StaticStrings {
+    
+    static final public String ENCODING = "UTF-8";
+
+    static public Document document;
+
+    static public void main(String[] args) {
+	if(args.length >= 1) {
+	    File file = new File(args[0]);
+	    CollectionConfiguration collect_cfg = new CollectionConfiguration(file);
+	    collect_cfg.save(true);
+	    collect_cfg.save(false);
+	    collect_cfg = null;
+	}
+	else {
+	    System.out.println("Usage: CollectionConfiguration <filename>");
+	}
+    }
+
+    /** Find the best insertion position for the given DOM Element. This should try to match command tag, and if found should then try to group by name or type (eg CollectionMeta), or append to end is no such grouping exists (eg PlugIns). Failing a command match it will check against the command order for the best insertion location.
+     * @param target_element the command Element to be inserted
+     * @return the Element which the given command should be inserted before, or null to append to end of list
+     */
+    static public Node findInsertionPoint(Element target_element) {
+	///ystem.err.println("Find insertion point: " + target_element.getNodeName());
+	String target_element_name = target_element.getNodeName();
+	Element document_element = document.getDocumentElement();
+	// Try to find commands with the same tag.
+	NodeList matching_elements = document_element.getElementsByTagName(target_element_name);
+	// If we found matching elements, then we have our most likely insertion location, so check within for groupings
+	if(matching_elements.getLength() != 0) {
+	    ///ystem.err.println("Found matching elements.");
+	    // Only CollectionMeta are grouped.
+	    if(target_element_name.equals(COLLECTIONMETADATA_ELEMENT)) {
+		///ystem.err.println("Dealing with collection metadata");
+		// Special case: CollectionMeta can be added at either the start or end of a collection configuration file. However the start position is reserved for special metadata, so if no non-special metadata can be found we must append to the end.
+		// So if the command to be added is special add it immediately after any other special command
+		if(target_element.getAttribute(SPECIAL_ATTRIBUTE).equals(TRUE_STR)) {
+		    int index = 0;
+		    Element matched_element = (Element) matching_elements.item(index);
+		    Element sibling_element = (Element) matched_element.getNextSibling();
+		    while(sibling_element.getAttribute(SPECIAL_ATTRIBUTE).equals(TRUE_STR)) {
+			index++;
+			matched_element = (Element) matching_elements.item(index);
+			sibling_element = (Element) matched_element.getNextSibling();
+		    }
+		    if(sibling_element.getNodeName().equals(NEWLINE_ELEMENT)) {
+			Element newline_element = document.createElement(NEWLINE_ELEMENT);
+			document_element.insertBefore(newline_element, sibling_element);
+		    }
+		    return sibling_element;
+		}
+		// Otherwise try to find a matching 'name' and add after the last one in that group.
+		else {
+		    int index = 0;
+		    target_element_name = target_element.getAttribute(NAME_ATTRIBUTE);
+		    boolean found = false;
+		    // Skip all of the special metadata
+		    Element matched_element = (Element) matching_elements.item(index);
+		    while(matched_element.getAttribute(SPECIAL_ATTRIBUTE).equals(TRUE_STR)) {
+			index++;
+			matched_element = (Element) matching_elements.item(index);
+		    }
+		    // Begin search
+		    while(!found && matched_element != null) {
+			if(matched_element.getAttribute(NAME_ATTRIBUTE).equals(target_element_name)) {
+			    found = true;
+			}
+			else {
+			    index++;
+			    matched_element = (Element) matching_elements.item(index);
+			}
+		    }
+		    // If we found a match, we need to continue checking until we find the last name match.
+		    if(found) {
+			index++;
+			Element previous_sibling = matched_element;
+			Element sibling_element = (Element) matching_elements.item(index);
+			while(sibling_element != null && sibling_element.getAttribute(NAME_ATTRIBUTE).equals(target_element_name)) {
+			    previous_sibling = sibling_element;
+			    index++;
+			    sibling_element = (Element) matching_elements.item(index);
+			}
+			// Previous sibling now holds the command immediately before where we want to add, so find its next sibling and add to that. In this one case we can ignore new lines!
+			return previous_sibling.getNextSibling();
+		    }
+		    // If not found we just add after last metadata element
+		    else {
+			Element last_element = (Element) matching_elements.item(matching_elements.getLength() - 1);
+			return last_element.getNextSibling();
+		    }
+		}
+
+	    }
+	    else {
+		///ystem.err.println("Not dealing with collection meta.");
+		Element matched_element = (Element) matching_elements.item(matching_elements.getLength() - 1);
+		// One final quick test. If the matched element is immediately followed by a NewLine command, then we insert another NewLine after the matched command, then return the NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
+		Node sibling_element = matched_element.getNextSibling();
+		if(sibling_element != null && sibling_element.getNodeName().equals(NEWLINE_ELEMENT)) {
+		    Element newline_element = document.createElement(NEWLINE_ELEMENT);
+		    document_element.insertBefore(newline_element, sibling_element);
+		}
+		return sibling_element; // Note that this may be null
+	    }
+	}
+	///ystem.err.println("No matching elements found.");
+	// Locate where this command is in the ordering
+	int command_index = -1;
+	for(int i = 0; command_index == -1 && i < COMMAND_ORDER.length; i++) {
+	    if(COMMAND_ORDER[i].equals(target_element_name)) {
+		command_index = i;
+	    }
+	}
+	///ystem.err.println("Command index is: " + command_index);
+	// Now move forward, checking for existing elements in each of the preceeding command orders.
+	int preceeding_index = command_index - 1;
+	///ystem.err.println("Searching before the target command.");
+	while(preceeding_index >= 0) {
+	    matching_elements = document_element.getElementsByTagName(COMMAND_ORDER[preceeding_index]);
+	    // If we've found a match
+	    if(matching_elements.getLength() > 0) {
+		// We add after the last element
+		Element matched_element = (Element) matching_elements.item(matching_elements.getLength() - 1);
+		// One final quick test. If the matched element is immediately followed by a NewLine command, then we insert another NewLine after the matched command, then return the NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
+		Node sibling_element = matched_element.getNextSibling();
+		if(sibling_element != null && sibling_element.getNodeName().equals(NEWLINE_ELEMENT)) {
+		    Element newline_element = document.createElement(NEWLINE_ELEMENT);
+		    document_element.insertBefore(newline_element, sibling_element);
+		}
+		return sibling_element; // Note that this may be null
+	    }
+	    preceeding_index--;
+	}
+	// If all that fails, we now move backwards through the commands
+	int susceeding_index = command_index + 1;
+	///ystem.err.println("Searching after the target command.");
+	while(susceeding_index < COMMAND_ORDER.length) {
+	    matching_elements = document_element.getElementsByTagName(COMMAND_ORDER[susceeding_index]);
+	    // If we've found a match
+	    if(matching_elements.getLength() > 0) {
+		// We add before the first element
+		Element matched_element = (Element) matching_elements.item(0);
+		// One final quick test. If the matched element is immediately preceeded by a NewLine command, then we insert another NewLine before the matched command, then return this new NewLine instead (thus the about to be inserted command will be placed between the two NewLines)
+		Node sibling_element = matched_element.getPreviousSibling();
+		if(sibling_element != null && sibling_element.getNodeName().equals(NEWLINE_ELEMENT)) {
+		    Element newline_element = document.createElement(NEWLINE_ELEMENT);
+		    document_element.insertBefore(newline_element, sibling_element);
+		}
+		return sibling_element; // Note that this may be null
+	    }
+	    susceeding_index++;
+	}
+	// Well. Apparently there are no other commands in this collection configuration. So append away...
+	return null;
+    }
+
+    static public String toString(Element command_element, boolean show_extracted_namespace) {
+	String command_element_name = command_element.getNodeName();
+	if(command_element_name.equals(CLASSIFY_ELEMENT)) {
+	    return self.classifyToString(command_element, show_extracted_namespace);
+	}
+	else if(command_element_name.equals(FORMAT_ELEMENT)) {
+	    return self.formatToString(command_element, show_extracted_namespace);
+	}
+	else if(command_element_name.equals(INDEXES_ELEMENT)) {
+	    return self.indexesToString(command_element, show_extracted_namespace);
+	}
+	else if(command_element_name.equals(INDEX_DEFAULT_ELEMENT)) {
+	    return self.indexDefaultToString(command_element, show_extracted_namespace);
+	}
+	else if(command_element_name.equals(LANGUAGES_ELEMENT)) {
+	    return self.languagesToString(command_element);
+	}
+	else if(command_element_name.equals(LANGUAGE_DEFAULT_ELEMENT)) {
+	    return self.languageDefaultToString(command_element);
+	}
+	else if(command_element_name.equals(LEVELS_ELEMENT)) {
+	    return self.levelsToString(command_element);
+	}
+	else if(command_element_name.equals(COLLECTIONMETADATA_ELEMENT)) {
+	    return self.metadataToString(command_element, show_extracted_namespace);
+	}
+	else if(command_element_name.equals(COLLECTIONMETADATA_CREATOR_ELEMENT)) {
+	    return self.metadataToString(command_element, show_extracted_namespace);
+	}
+	else if(command_element_name.equals(COLLECTIONMETADATA_MAINTAINER_ELEMENT)) {
+	    return self.metadataToString(command_element, show_extracted_namespace);
+	}
+	else if(command_element_name.equals(COLLECTIONMETADATA_PUBLIC_ELEMENT)) {
+	    return self.metadataToString(command_element, show_extracted_namespace);
+	}
+	else if (command_element_name.equals(BUILDTYPE_ELEMENT)) {
+	    return self.metadataToString(command_element, show_extracted_namespace);
+	}
+	else if(command_element_name.equals(PLUGIN_ELEMENT)) {
+	    return self.pluginToString(command_element, show_extracted_namespace);
+	}
+	else if(command_element_name.equals(SEARCHTYPE_ELEMENT)) {
+	    return self.searchtypeToString(command_element);
+	}
+	else if(command_element_name.equals(SUBCOLLECTION_ELEMENT)) {
+	    return self.subcollectionToString(command_element, show_extracted_namespace);
+	}
+	else if(command_element_name.equals(SUBCOLLECTION_DEFAULT_INDEX_ELEMENT)) {
+	    return self.subcollectionDefaultIndexToString(command_element);
+	}
+	else if(command_element_name.equals(SUBCOLLECTION_INDEXES_ELEMENT)) {
+	    return self.subcollectionIndexesToString(command_element);
+	}
+	else if(command_element_name.equals(SUPERCOLLECTION_ELEMENT)) {
+	    return self.supercollectionToString(command_element);
+	}
+	else if(command_element_name.equals(UNKNOWN_ELEMENT)) {
+	    return self.unknownToString(command_element);
+	}
+	return "";
+    }
+
+    /** Parses arguments from a tokenizer and returns a HashMap of mappings. The tricky bit here is that not all entries in the HashMap are name->value pairs, as some arguments are boolean and are turned on by their presence. Arguments are denoted by a '-' prefix.
+     * @param tokenizer a CommandTokenizer based on the unconsumed portion of a command string
+     * @return a HashMap containing the arguments parsed
+     */
+    static public HashMap parseArguments(CommandTokenizer tokenizer) {
+	HashMap arguments = new HashMap();
+	String name = null;
+	String value = null;
+	while(tokenizer.hasMoreTokens() || name != null) {
+	    // First we retrieve a name if we need one.
+	    if(name == null) {
+		name = tokenizer.nextToken();
+	    }
+	    // Now we attempt to retrieve a value
+	    if(tokenizer.hasMoreTokens()) {
+		value = tokenizer.nextToken();
+		// Test if the value is actually a name, and if so add the name by itself, then put value into name so that it is parsed correctly during the next loop.
+		if(value.startsWith(StaticStrings.MINUS_CHARACTER)) {
+		    arguments.put(name, null);
+		    name = value;
+		}
+		// Otherwise we have a typical name->value pair ready to go
+		else {
+		    arguments.put(name, value);
+		    name = null;
+		}
+	    }
+	    // Otherwise its a binary flag
+	    else {
+		arguments.put(name, null);
+		name = null;
+	    }
+	}
+	return arguments;
+    }
+
+    static private ArrayList known_metadata;
+
+    static private CollectionConfiguration self;
+
+    /** Gives the preferred ordering of commands */
+    static final private String[] COMMAND_ORDER = {StaticStrings.COLLECTIONMETADATA_CREATOR_ELEMENT, StaticStrings.COLLECTIONMETADATA_MAINTAINER_ELEMENT, StaticStrings.COLLECTIONMETADATA_PUBLIC_ELEMENT,  StaticStrings.SEARCHTYPE_ELEMENT, StaticStrings.BUILDTYPE_ELEMENT, StaticStrings.PLUGIN_ELEMENT, StaticStrings.INDEXES_ELEMENT, StaticStrings.LEVELS_ELEMENT, StaticStrings.INDEX_DEFAULT_ELEMENT, StaticStrings.LANGUAGES_ELEMENT, StaticStrings.LANGUAGE_DEFAULT_ELEMENT, StaticStrings.SUBCOLLECTION_ELEMENT, StaticStrings.SUBCOLLECTION_INDEXES_ELEMENT, StaticStrings.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT, StaticStrings.SUPERCOLLECTION_ELEMENT, StaticStrings.CLASSIFY_ELEMENT, StaticStrings.FORMAT_ELEMENT, StaticStrings.COLLECTIONMETADATA_ELEMENT};
+
+    /** ************************** Public Data Members ***************************/
+
+    /** ************************** Private Data Members ***************************/
+    
+    private File collect_cfg_file;
+
+    /** ************************** Public Methods ***************************/
+
+    public CollectionConfiguration(File collect_cfg_file) {
+	this.self = this;
+	this.collect_cfg_file = collect_cfg_file;
+	// If collect_cfg is xml we can load it straight away
+	String collect_config_name = collect_cfg_file.getName();
+	if(collect_config_name.equals(COLLECTCONFIGURATION_XML)) {
+	    document = XMLTools.parseXMLFile(collect_cfg_file);
+	}
+	// Otherwise if this is a legacy collect.cfg file then read in the template and send to magic parser
+	else if(collect_config_name.equals(COLLECT_CFG)) {
+	    document = XMLTools.parseXMLFile("xml/CollectionConfig.xml", true);
+	    parse(collect_cfg_file);
+	}
+    }
+
+    /** This debug facility shows the currently loaded collect.cfg or CollectConfig.xml file as a DOM tree. */
+    public void display() {
+	JDialog dialog = new JDialog(Gatherer.g_man, "Collection Configuration", false);
+	dialog.setSize(400,400);
+	JPanel content_pane = (JPanel) dialog.getContentPane();
+	final DOMTree tree = new DOMTree(document);
+	JButton refresh_button = new GLIButton("Refresh Tree");
+	refresh_button.setMnemonic(KeyEvent.VK_R);
+	refresh_button.addActionListener(new ActionListener() {
+		public void actionPerformed(ActionEvent event) {
+		    tree.setDocument(document);
+		}
+	    });
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(new JScrollPane(tree), BorderLayout.CENTER);
+	content_pane.add(refresh_button, BorderLayout.SOUTH);
+	dialog.setVisible(true);
+    }
+
+
+    public Element getCreator() {
+	Element element = getOrCreateElementByTagName(COLLECTIONMETADATA_CREATOR_ELEMENT, null, null);
+	element.setAttribute(NAME_ATTRIBUTE, COLLECTIONMETADATA_CREATOR_STR);
+	element.setAttribute(SPECIAL_ATTRIBUTE, TRUE_STR);
+	return element;
+    }
+
+    public Element getDocumentElement() {
+	return document.getDocumentElement();
+    }
+
+    public File getFile() {
+	return collect_cfg_file;
+    }
+
+    /** Retrieve or create the languages Element. */
+    public Element getLanguages() {
+	return getOrCreateElementByTagName(LANGUAGES_ELEMENT, null, null);
+    }
+
+    public Element getLevels() {
+	return getOrCreateElementByTagName(LEVELS_ELEMENT, null, null);
+    }
+
+    public Element getMaintainer() {
+	Element element = getOrCreateElementByTagName(COLLECTIONMETADATA_MAINTAINER_ELEMENT, null, null);
+	element.setAttribute(NAME_ATTRIBUTE, COLLECTIONMETADATA_MAINTAINER_STR);
+	element.setAttribute(SPECIAL_ATTRIBUTE, TRUE_STR);
+	return element;
+    }
+
+    /** Retrieve or create the indexes Element. Note that this method behaves differently from the other getBlah methods, in that it also has to keep in mind that indexes come in two flavours, MG and MGPP. */
+    public Element getMGIndexes() {
+	return getOrCreateElementByTagName(INDEXES_ELEMENT, MGPP_ATTRIBUTE, FALSE_STR);
+    }
+
+    public Element getMGPPIndexes() {
+	return getOrCreateElementByTagName(INDEXES_ELEMENT, MGPP_ATTRIBUTE, TRUE_STR);
+    }
+
+    public Element getPublic() {
+	Element element = getOrCreateElementByTagName(COLLECTIONMETADATA_PUBLIC_ELEMENT, null, null);
+	element.setAttribute(NAME_ATTRIBUTE, COLLECTIONMETADATA_PUBLIC_STR);
+	element.setAttribute(SPECIAL_ATTRIBUTE, TRUE_STR);
+	return element;
+    }
+
+    public Element getBuildType() {
+	Element element = getOrCreateElementByTagName(BUILDTYPE_ELEMENT, null, null);
+	element.setAttribute(NAME_ATTRIBUTE, BUILDTYPE_STR);
+	element.setAttribute(SPECIAL_ATTRIBUTE, TRUE_STR);
+	return element;
+
+    }
+    /** Retrieve or create the searchtype element. */
+    public Element getSearchType() {
+	///ystem.err.println("Get or create element by tag name: " + name);
+	Element document_element = document.getDocumentElement();
+	NodeList elements = document_element.getElementsByTagName(SEARCHTYPE_ELEMENT);
+	int elements_length = elements.getLength();
+	if(elements_length > 0) {
+	    document_element = null;
+	    return (Element) elements.item(0);
+	}
+	// Create the element
+	Element element = document.createElement(SEARCHTYPE_ELEMENT);
+	Node target_node = findInsertionPoint(element);
+	if(target_node != null) {
+	    document_element.insertBefore(element, target_node);
+	}
+	else {
+	    document_element.appendChild(element);
+	}
+	document_element = null;
+	// Append a default search type node - form
+	Element a_searchtype_element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.CONTENT_ELEMENT);
+	a_searchtype_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, SearchTypeManager.SEARCH_TYPES[0]);
+	element.appendChild(a_searchtype_element);
+	return element;
+    }
+
+    /** Retrieve or create the subindexes Element. */
+    public Element getSubIndexes() {
+	return getOrCreateElementByTagName(SUBCOLLECTION_INDEXES_ELEMENT, null, null);
+    }
+
+    /** Retrieve or create the supercollections Element. */
+    public Element getSuperCollection() {
+	return getOrCreateElementByTagName(SUPERCOLLECTION_ELEMENT, null, null);
+    }
+
+    public boolean ready() {
+	return document != null;
+    }
+
+    public void save() {
+	save(false);
+    }
+
+    public void save(boolean force_xml) {
+	if(collect_cfg_file.exists()) {
+	    File original_file = new File(collect_cfg_file.getParentFile(), COLLECT_CFG);
+	    File backup_file = new File(collect_cfg_file.getParentFile(), "collect.bak");
+	    if(backup_file.exists()) {
+		backup_file.delete();
+	    }
+	    if(!original_file.renameTo(backup_file)) {
+		DebugStream.println("Can't rename collect.cfg");
+	    }
+	}
+	if(force_xml || collect_cfg_file.getName().equals(COLLECTCONFIGURATION_XML)) {
+	    ///ystem.err.println("Writing XML");
+	    XMLTools.writeXMLFile(new File(collect_cfg_file.getParentFile(), COLLECTCONFIGURATION_XML), document);
+	}
+	else {
+	    ///ystem.err.println("Writing text");
+	    try {		
+		OutputStream ostream = new FileOutputStream(collect_cfg_file);
+		Writer file_writer = new OutputStreamWriter(ostream, ENCODING);
+		//FileWriter file_writer = new FileWriter(collect_cfg_file, false);
+		BufferedWriter buffered_writer = new BufferedWriter(file_writer);
+		Element collect_config_element = document.getDocumentElement();
+		NodeList command_elements = collect_config_element.getChildNodes();
+		boolean just_wrote_newline = false; // Prevent two or more newlines in a row
+		for(int i = 0; i < command_elements.getLength(); i++) {
+		    Node command_node = command_elements.item(i);
+		    if(command_node instanceof Element) {
+			Element command_element = (Element) command_node;
+			// The only thing left are NewLine elements
+			if(command_element.getNodeName().equals(NEWLINE_ELEMENT) && !just_wrote_newline) {
+			    buffered_writer.newLine();
+			    just_wrote_newline = true;
+			}
+			// Anything else we write to file, but only if it has been assigned, the exception being the Indexes element which just get commented if unassigned (a side effect of MG && MGPP compatibility)
+			else if(!command_element.getAttribute(ASSIGNED_ATTRIBUTE).equals(FALSE_STR) || command_element.getNodeName().equals(INDEXES_ELEMENT) || command_element.getNodeName().equals(INDEX_DEFAULT_ELEMENT) || command_element.getNodeName().equals(LEVELS_ELEMENT)){
+			    String command;
+			    // format statements we write out with ex. still present
+			    if (command_element.getNodeName().equals(FORMAT_ELEMENT)) {
+				command = toString(command_element, true);
+			    } else {
+				command = toString(command_element, false);
+			    }
+			    if(command != null && command.length()> 0 ) {
+				/* if command contains buildtype only, it means that the none of
+				 * buildtype has been selected, so we don't want to write into
+				 * collect.cfg file*/
+				if (!command.matches("^buildtype\\s*")){
+				    write(buffered_writer, command);
+				    buffered_writer.newLine();
+				    just_wrote_newline = false;
+				}
+			    }
+			}
+		    }
+		}
+		buffered_writer.close();
+
+		// If we're using a remote Greenstone server, upload the new collect.cfg file
+		if (Gatherer.isGsdlRemote) {
+		    String collection_name = Gatherer.c_man.getCollection().getName();
+		    ZipTools.zipup(Gatherer.getCollectDirectoryPath(), collection_name, "collect.cfg", null, "", "");
+		    RemoteGreenstoneServer.upload_url_zip(collection_name, "etc", "", null);
+		}
+	    }
+	    catch (Exception exception) {
+		DebugStream.println("Error in CollectionConfiguration.save(boolean): " + exception);
+		DebugStream.printStackTrace(exception);
+	    }
+	}
+    }
+
+    /** ************************** Private Methods ***************************/
+
+    private String classifyToString(Element command_element, boolean show_extracted_namespace)
+    {
+	StringBuffer text = new StringBuffer(CLASSIFY_STR);
+	text.append(TAB_CHARACTER);
+	text.append(command_element.getAttribute(TYPE_ATTRIBUTE));
+	text.append(SPACE_CHARACTER);
+	NodeList option_elements = command_element.getElementsByTagName(OPTION_ELEMENT);
+	int option_elements_length = option_elements.getLength();
+	for(int j = 0; j < option_elements_length; j++) {
+	    Element option_element = (Element) option_elements.item(j);
+	    if(option_element.getAttribute(ASSIGNED_ATTRIBUTE).equals(TRUE_STR)) {
+		text.append(StaticStrings.MINUS_CHARACTER);
+		text.append(option_element.getAttribute(NAME_ATTRIBUTE));
+		String value_str = XMLTools.getValue(option_element);
+
+		// Remove the extracted metadata namespaces if required
+		if (value_str.length() > 0) {
+		    StringTokenizer string_tokenizer = new StringTokenizer(value_str, ",");
+		    value_str = "";
+		    while (string_tokenizer.hasMoreElements()) {
+			String raw_token = (String) string_tokenizer.nextElement();
+			String token = raw_token.trim();
+			MetadataElement metadata_element = MetadataTools.getMetadataElementWithDisplayName(token);
+			if (metadata_element != null) {
+			    token = metadata_element.getFullName();
+			}
+
+			if (token.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
+			    token = token.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
+			}
+
+			value_str = value_str + token;
+			if (string_tokenizer.hasMoreElements()) {
+			    value_str = value_str + ",";
+			}
+		    }
+		}
+
+		text.append(SPACE_CHARACTER);
+		if (value_str.indexOf(SPACE_CHARACTER) == -1) {
+		    text.append(value_str);
+		}
+		else {
+		    text.append(SPEECH_CHARACTER);
+		    text.append(value_str);
+		    text.append(SPEECH_CHARACTER);
+		}
+		value_str = null;
+		if(j < option_elements_length - 1) {
+		    text.append(SPACE_CHARACTER);
+		}
+	    }
+	    option_element = null;
+	}
+	option_elements = null;
+	return text.toString();
+    }
+
+    private String formatToString(Element command_element, boolean show_extracted_namespace) {
+	StringBuffer text = new StringBuffer(FORMAT_STR);
+	text.append(SPACE_CHARACTER);
+	text.append(command_element.getAttribute(NAME_ATTRIBUTE));
+	text.append(SPACE_CHARACTER);
+	String value_str = command_element.getAttribute(VALUE_ATTRIBUTE);
+	if(value_str.length() != 0) {
+	    text.append(value_str);
+	}
+	else {
+	    // Remember to encode format string to Greenstone specification
+	    value_str = Codec.transform(XMLTools.getValue(command_element), Codec.DOM_TO_GREENSTONE);
+	    // Remove any references to a namespace for extracted metadata
+	    if (!show_extracted_namespace) {
+		String match_string = "\\[" + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + "\\.";
+		value_str = value_str.replaceAll(match_string, "[");
+	    }
+
+	    text.append(SPEECH_CHARACTER);
+	    text.append(value_str);
+	    text.append(SPEECH_CHARACTER);
+	}
+	value_str = null;
+	return text.toString();
+    }
+
+    /** Retrieve or create the indexes Element. */
+    private Element getOrCreateElementByTagName(String name, String conditional_attribute, String required_value) {
+	Element document_element = document.getDocumentElement();
+	NodeList elements = document_element.getElementsByTagName(name);
+	int elements_length = elements.getLength();
+	if(elements_length > 0) {
+	    if(conditional_attribute == null) {
+		document_element = null;
+		return (Element) elements.item(0);
+	    }
+	    else {
+		for(int i = 0; i < elements_length; i++) {
+		    Element element = (Element) elements.item(i);
+		    if(element.getAttribute(conditional_attribute).equals(required_value)) {
+			document_element = null;
+			return element;
+		    }
+		    element = null;
+		}
+	    }
+	}
+	// Create the element
+	Element element = document.createElement(name);
+	// If there was a property set it
+	if(conditional_attribute != null) {
+	    element.setAttribute(conditional_attribute, required_value);
+	}
+	Node target_node = findInsertionPoint(element);
+	if(target_node != null) {
+	    document_element.insertBefore(element, target_node);
+	}
+	else {
+	    document_element.appendChild(element);
+	}
+	document_element = null;
+	return element;
+    }
+
+    private String indexesToString(Element command_element, boolean show_extracted_namespace) {
+	boolean comment_only = false;
+	StringBuffer text = new StringBuffer("");
+	if(command_element.getAttribute(ASSIGNED_ATTRIBUTE).equals(FALSE_STR)) {
+	    text.append("#");
+	    comment_only = true;
+	}
+	text.append(INDEX_STR);
+	text.append(TAB_CHARACTER);
+	if(!comment_only) {
+	    text.append(TAB_CHARACTER);
+	}
+	NodeList index_elements = command_element.getElementsByTagName(INDEX_ELEMENT);
+	if (index_elements.getLength() == 0) { // no indexes
+	    return "";
+	}
+	// For each index, write its level, a colon, then concatenate its child content elements into a single comma separated list
+	int index_elements_length = index_elements.getLength();
+	for(int j = 0; j < index_elements_length; j++) {
+	    Element index_element = (Element) index_elements.item(j);
+	    String level_str = index_element.getAttribute(LEVEL_ATTRIBUTE);
+	    if(level_str.length() > 0) {
+		text.append(level_str);
+		text.append(StaticStrings.COLON_CHARACTER);
+	    }
+	    NodeList content_elements = index_element.getElementsByTagName(CONTENT_ELEMENT);
+	    int content_elements_length = content_elements.getLength();
+	    // Don't output anything if no indexes are set
+	    if(content_elements_length == 0) {
+		return null;
+	    }
+	    for(int k = 0; k < content_elements_length; k++) {
+		Element content_element = (Element) content_elements.item(k);
+		String name_str = content_element.getAttribute(NAME_ATTRIBUTE);
+		if(!show_extracted_namespace && name_str.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
+		    name_str = name_str.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
+		}
+		text.append(name_str);
+		name_str = null;
+		if(k < content_elements_length - 1) {
+		    text.append(StaticStrings.COMMA_CHARACTER);
+		}
+		content_element = null;
+	    }
+	    if(j < index_elements_length - 1) {
+		text.append(SPACE_CHARACTER);
+	    }
+	    content_elements = null;
+	    index_element = null;
+	}
+	index_elements = null;
+	return text.toString();
+    }
+
+    private String indexDefaultToString(Element command_element, boolean show_extracted_namespace) {
+	StringBuffer text = new StringBuffer("");
+	if(command_element.getAttribute(ASSIGNED_ATTRIBUTE).equals(FALSE_STR)) {
+	    text.append("#");
+	}
+	text.append(INDEX_DEFAULT_STR);
+	text.append(TAB_CHARACTER);
+	text.append(command_element.getAttribute(LEVEL_ATTRIBUTE));
+	text.append(StaticStrings.COLON_CHARACTER);
+	NodeList content_elements = command_element.getElementsByTagName(CONTENT_ELEMENT);
+	int content_elements_length = content_elements.getLength();
+	for(int j = 0; j < content_elements_length; j++) {
+	    Element content_element = (Element) content_elements.item(j);
+	    String name_str = content_element.getAttribute(NAME_ATTRIBUTE);
+	    if(!show_extracted_namespace && name_str.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
+		name_str = name_str.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
+	    }
+	    text.append(name_str);
+	    name_str = null;
+	    if(j < content_elements_length - 1) {
+		text.append(StaticStrings.COMMA_CHARACTER);
+	    }
+	    content_element = null;
+	}
+	content_elements = null;
+	return text.toString();
+    }
+
+    private String languagesToString(Element command_element) {
+	StringBuffer text = new StringBuffer(LANGUAGES_STR);
+	text.append(TAB_CHARACTER);
+	// Retrieve all the languages and write them out in a space separated list
+	NodeList language_elements = command_element.getElementsByTagName(LANGUAGE_ELEMENT);
+	int language_elements_length = language_elements.getLength();
+	if(language_elements_length == 0) {
+	    return null;
+	}
+	for(int j = 0; j < language_elements_length; j++) {
+	    Element language_element = (Element) language_elements.item(j);
+	    text.append(language_element.getAttribute(NAME_ATTRIBUTE));
+	    if(j < language_elements_length - 1) {
+		text.append(SPACE_CHARACTER);
+	    }
+	}
+	return text.toString();
+    }
+
+    private String languageDefaultToString(Element command_element) {
+	StringBuffer text = new StringBuffer(LANGUAGE_DEFAULT_STR);
+	text.append(TAB_CHARACTER);
+	text.append(command_element.getAttribute(NAME_ATTRIBUTE));
+	return text.toString();
+    }
+
+    private String levelsToString(Element command_element) {
+	StringBuffer text = new StringBuffer("");
+	if(!command_element.getAttribute(ASSIGNED_ATTRIBUTE).equals(TRUE_STR)) {
+	    text.append("#");
+	}
+	text.append(LEVELS_STR);
+	text.append(TAB_CHARACTER);
+	text.append(TAB_CHARACTER);
+	NodeList content_elements = command_element.getElementsByTagName(CONTENT_ELEMENT);
+	int content_elements_length = content_elements.getLength();
+	// Don't output anything if no levels are set.
+	if(content_elements_length == 0) {
+	    return null;
+	}
+	for(int i = 0; i < content_elements_length; i++) {
+	    Element content_element = (Element) content_elements.item(i);
+	    text.append(content_element.getAttribute(NAME_ATTRIBUTE));
+	    text.append(SPACE_CHARACTER);
+	}
+	return text.substring(0, text.length() - 1);
+    }
+
+    static public String metadataToString(Element command_element, boolean text_value) {
+	boolean special = false;
+	// If there is no value attribute, then we don't write anything
+	StringBuffer text = new StringBuffer("");
+	String name_str = command_element.getAttribute(NAME_ATTRIBUTE);
+	// If the name is one of the special four, we don't write the collectionmeta first. Note the maintainer collectionmeta is singled out for 'prittying' reasons.
+	if(name_str.equals(COLLECTIONMETADATA_MAINTAINER_STR)|| name_str.equals(BUILDTYPE_STR) ) {
+	    text.append(name_str);
+	    text.append(TAB_CHARACTER);
+	    special = true;
+	}
+	else if (name_str.equals(COLLECTIONMETADATA_CREATOR_STR) || name_str.equals(COLLECTIONMETADATA_PUBLIC_STR) ) {
+	    text.append(name_str);
+	    text.append(TAB_CHARACTER);
+	    text.append(TAB_CHARACTER);
+	    special = true;
+	}
+	else {
+	    text.append(COLLECTIONMETADATA_STR);
+	    text.append(TAB_CHARACTER);
+	    text.append(name_str);
+	    text.append(SPACE_CHARACTER);
+	    String language_str = command_element.getAttribute(LANGUAGE_ATTRIBUTE);
+	    text.append(LBRACKET_CHARACTER);
+	    text.append(LANGUAGE_ARGUMENT);
+	    text.append(language_str);
+	    text.append(RBRACKET_CHARACTER);
+	    text.append(SPACE_CHARACTER);
+
+	    if(known_metadata != null) {
+		known_metadata.add(name_str);
+	    }
+	    language_str = null;
+	}
+	name_str = null;
+
+	String value_str = XMLTools.getValue(command_element);
+	// The value string we retrieved will be encoded for xml, so we now decode it - to text if text_value set. This parameter was originally show_extracted_namespace, but sincethis is only true for 'toString()' commands from within the CDM, its good enough to determine if this toString() will be used to display on screen, or write to collect.cfg
+	if(text_value == CollectionMeta.TEXT) {
+	    value_str = Codec.transform(value_str, Codec.DOM_TO_TEXT);
+	}
+	else {
+	    value_str = Codec.transform(value_str, Codec.DOM_TO_GREENSTONE);
+	}
+
+	// We don't wrap the email addresses in quotes, nor the other special metadata
+	if(special) {
+	    text.append(value_str);
+	}
+	else {
+	    text.append(SPEECH_CHARACTER);
+	    text.append(value_str);
+	    text.append(SPEECH_CHARACTER);
+	}
+	value_str = null;
+	return text.toString();
+    }
+
+    /** Parse a collect.cfg into a DOM model representation. 
+     * note we are ignoring 2.39 compatibility now. */
+    private void parse(File collect_cfg_file) {
+	try {
+
+	    Element collect_cfg_element = document.getDocumentElement();
+	    // Read in the file one command at a time.
+	    InputStream istream = new FileInputStream(collect_cfg_file);
+	    Reader in_reader = new InputStreamReader(istream, ENCODING);
+	    BufferedReader in = new BufferedReader(in_reader);
+	    String command_str = null;
+	    while((command_str = in.readLine()) != null) {
+		boolean append_element = true;
+		Element command_element = null;
+		// A command may be broken over several lines.
+		command_str = command_str.trim();
+		boolean eof = false;
+		while(!eof && command_str.endsWith(NEWLINE_CHARACTER)) {
+		    String next_line = in.readLine();
+		    if(next_line != null) {
+			next_line = next_line.trim();
+			if(next_line.length() > 0) {
+			    // Remove the new line character
+			    command_str = command_str.substring(0, command_str.lastIndexOf(NEWLINE_CHARACTER));
+			    // And append the next line, which due to the test above must be non-zero length
+			    command_str = command_str + next_line;
+			}
+			next_line = null;
+		    }
+		    // If we've reached the end of the file theres nothing more we can do
+		    else {
+			eof = true;
+		    }
+		}
+		// If there is still a new line character, then we remove it and hope for the best
+		if(command_str.endsWith(NEWLINE_CHARACTER)) {
+		    command_str = command_str.substring(0, command_str.lastIndexOf(NEWLINE_CHARACTER));
+		}
+		// Now we've either got a command to parse...
+		if(command_str.length() != 0) {
+		    // Start trying to figure out what it is
+		    //StringTokenizer tokenizer = new StringTokenizer(command_str);
+		    // Instead of a standard string tokenizer I'm going to use the new version of CommandTokenizer, which is not only smart enough to correctly notice speech marks and correctly parse them out, but now also takes the input stream so it can rebuild tokens that stretch over several lines.
+		    CommandTokenizer tokenizer = new CommandTokenizer(command_str, in);
+		    String command_type = tokenizer.nextToken().toLowerCase();
+		    // Why can't you switch on strings eh? We pass it to the various subparsers who each have a bash at parsing the command. If none can parse the command, an unknown element is created
+		    if(command_element == null && command_type.equals(CLASSIFY_STR)) {
+			command_element = parseClassify(command_str);
+		    }
+		    if(command_element == null && command_type.equals(FORMAT_STR)) {
+			command_element = parseFormat(tokenizer); // Revised to handle multiple lines
+		    }
+		    if(command_element == null && (command_type.equals(INDEX_STR)  || command_type.equals(COMMENTED_INDEXES_STR))) {
+			command_element = parseIndex(command_str);
+		    }
+		    if(command_element == null && (command_type.equals(INDEX_DEFAULT_STR) || command_type.equals(COMMENTED_INDEX_DEFAULT_STR))) {
+			
+			command_element = parseIndexDefault(command_str);
+		    }
+		    if(command_element == null && command_type.equals(LANGUAGES_STR)) {
+			command_element = parseLanguage(command_str);
+		    }
+		    if(command_element == null && command_type.equals(LANGUAGE_DEFAULT_STR)) {
+			command_element = parseLanguageDefault(command_str);
+		    }
+		    if(command_element == null && (command_type.equals(LEVELS_STR) || command_type.equals(COMMENTED_LEVELS_STR))) {
+			command_element = parseLevels(command_str);
+		    }
+		    if(command_element == null && command_type.equals(COLLECTIONMETADATA_STR)) {
+			command_element = parseMetadata(tokenizer); // Revised to handle multiple lines
+		    }
+		    if(command_element == null && (command_type.equals(COLLECTIONMETADATA_PUBLIC_STR) || command_type.equals(COLLECTIONMETADATA_CREATOR_STR) || command_type.equals(COLLECTIONMETADATA_MAINTAINER_STR) || command_type.equals(BUILDTYPE_STR))) {
+			command_element = parseMetadataSpecial(command_str);
+		    }
+		    if(command_element == null && command_type.equals(PLUGIN_STR)) {
+			command_element = parsePlugIn(command_str);
+		    }
+		    if(command_element == null && command_type.equals(SEARCHTYPE_STR)) {
+			command_element = parseSearchType(command_str);
+		    }
+		    if(command_element == null && command_type.equals(SUBCOLLECTION_STR)) {
+			command_element = parseSubCollection(command_str);
+		    }
+		    if(command_element == null && command_type.equals(SUBCOLLECTION_DEFAULT_INDEX_STR)) {
+			command_element = parseSubCollectionDefaultIndex(command_str);
+		    }
+		    if(command_element == null && command_type.equals(SUBCOLLECTION_INDEX_STR)) {
+			command_element = parseSubCollectionIndex(command_str);
+		    }
+		    if(command_element == null && (command_type.equals(SUPERCOLLECTION_STR) || command_type.equals(CCS_STR))) {
+			command_element = parseSuperCollection(command_str);
+		    }
+		    // Doesn't match any known type
+		    command_type = null;
+		    if(command_element == null) {
+			// No-one knows what to do with this command, so we create an Unknown command element
+			command_element = document.createElement(UNKNOWN_ELEMENT);
+			XMLTools.setValue(command_element, command_str);
+		    }
+		}
+		// Or an empty line to remember for later
+		else {
+		    command_element = document.createElement(NEWLINE_ELEMENT);
+		}
+		// Now command element shouldn't be null so we append it to the collection config DOM, but only if we haven't been told not to add it
+		//if(append_element) {
+		    collect_cfg_element.appendChild(command_element);
+		    //}
+	    }
+
+	}
+	catch(Exception exception) {
+	    DebugStream.println("Error in CollectionConfiguration.parse(java.io.File): " + exception);
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+    
+    private Element parseClassify(String command_str) {
+	Element command_element = null;
+	try {
+	    CommandTokenizer tokenizer = new CommandTokenizer(command_str);
+	    // Check the token count. The token count from a command tokenizer isn't guarenteed to be correct, but it does give the maximum number of available tokens according to the underlying StringTokenizer (some of which may actually be append together by the CommandTokenizer as being a single argument).
+	    if(tokenizer.countTokens() >= 2) {  // Must support "classify Phind" (no args)
+		command_element = document.createElement(CLASSIFY_ELEMENT);
+		// First token is classify
+		tokenizer.nextToken();
+		// The next token is the classifier type
+		command_element.setAttribute(TYPE_ATTRIBUTE, tokenizer.nextToken());
+		// Now we parse out the remaining arguments into a hashmapping from name to value
+		HashMap arguments = parseArguments(tokenizer);
+		// Assign the arguments as Option elements, but watch out for the metadata argument as we treat that differently
+		Iterator names = arguments.keySet().iterator();
+		while(names.hasNext()) {
+		    String name = (String) names.next();
+		    String value = (String) arguments.get(name); // Can be null
+		    // The metadata argument gets added as the content attribute
+		    if (name.equals(METADATA_ARGUMENT) && value != null) {
+			// Add the extracted namespace onto un-namespaced metadata names
+			StringTokenizer string_tokenizer = new StringTokenizer(value, ",");
+			value = "";
+			while (string_tokenizer.hasMoreElements()) {
+			    String token = (String) string_tokenizer.nextElement();
+
+			    if (token.indexOf(StaticStrings.NS_SEP) == -1) {
+				token = StaticStrings.EXTRACTED_NAMESPACE + token;
+			    }
+			    else {
+				MetadataElement metadata_element = MetadataTools.getMetadataElementWithName(token);
+				if (metadata_element != null) {
+				    token = metadata_element.getDisplayName();
+				}
+			    }
+
+			    if (!value.equals("")) {
+				value = value + ",";
+			    }
+			    value = value + token;
+			}
+		    }
+		    // Everything else is an Option Element
+		    Element option_element = document.createElement(OPTION_ELEMENT);
+		    option_element.setAttribute(NAME_ATTRIBUTE, name.substring(1));
+		    if(value != null) {
+			// Remove any speech marks appended in strings containing whitespace
+			if(value.startsWith(SPEECH_CHARACTER) && value.endsWith(SPEECH_CHARACTER)) {
+			    value = value.substring(1, value.length() - 1);
+			}
+			XMLTools.setValue(option_element, value);
+		    }
+		    option_element.setAttribute(ASSIGNED_ATTRIBUTE, TRUE_STR);
+		    option_element.setAttribute(CUSTOM_ATTRIBUTE, TRUE_STR);
+		    command_element.appendChild(option_element);
+		    option_element = null;
+		    name = null;
+		    value = null;
+		}
+		names = null;
+		arguments = null;
+	    }
+	    tokenizer = null;
+	}
+	catch(Exception error) {
+	}
+	return command_element;
+    }
+
+    private Element parseFormat(CommandTokenizer tokenizer) {
+	Element command_element = null;
+	try {
+	    command_element = document.createElement(FORMAT_ELEMENT);
+	    String name_str = tokenizer.nextToken();
+	    String value_str = tokenizer.nextToken();
+	    if(name_str != null && value_str != null) {
+		command_element.setAttribute(NAME_ATTRIBUTE, name_str);
+		// If the value is true or false we add it as an attribute
+		if(value_str.equalsIgnoreCase(TRUE_STR) || value_str.equalsIgnoreCase(FALSE_STR)) {
+		    command_element.setAttribute(VALUE_ATTRIBUTE, value_str.toLowerCase());
+		}
+		// Otherwise it gets added as a text node
+		else {
+		    // Ready the value str (which can contain all sorts of funky characters) for writing as a DOM value
+		    value_str = Codec.transform(value_str, Codec.GREENSTONE_TO_DOM);
+		    XMLTools.setValue(command_element, value_str);
+		}
+	    }
+	    else {
+		command_element = null;
+	    }
+	    name_str = null;
+	    value_str = null;
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	    command_element = null;
+	}
+	return command_element;
+    }
+
+    private Element parseIndex(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    String command = tokenizer.nextToken();
+	    command_element = document.createElement(INDEXES_ELEMENT);
+	    command_element.setAttribute(ASSIGNED_ATTRIBUTE, (command.equals(INDEX_STR) ? TRUE_STR : FALSE_STR));
+	    command = null;
+	    if(!tokenizer.hasMoreTokens()) {
+
+		// there are no indexes
+		command_element.setAttribute(ASSIGNED_ATTRIBUTE, FALSE_STR);
+		command_element.setAttribute(MGPP_ATTRIBUTE, FALSE_STR); // for now
+		tokenizer = null;
+		return command_element;
+	    }
+
+	    while(tokenizer.hasMoreTokens()) {
+		Element index_element = document.createElement(INDEX_ELEMENT);
+		String index_str = tokenizer.nextToken();
+		// There are two types of index we have to consider. Old G2.38 and earlier use level:source tuplets while G2.39+ have just a single, non-comma separated list where order is important.
+		boolean old_index;
+		if(index_str.indexOf(COLON_CHARACTER) != -1) {
+		    old_index = true;
+		    index_element.setAttribute(LEVEL_ATTRIBUTE, index_str.substring(0, index_str.indexOf(StaticStrings.COLON_CHARACTER)));
+		    index_str = index_str.substring(index_str.indexOf(StaticStrings.COLON_CHARACTER) + 1);
+		    command_element.setAttribute(MGPP_ATTRIBUTE, FALSE_STR);
+		}
+		else {
+		    command_element.setAttribute(MGPP_ATTRIBUTE, TRUE_STR);
+		    old_index = false;
+		}
+		StringTokenizer content_tokenizer = new StringTokenizer(index_str, StaticStrings.COMMA_CHARACTER);
+		while(content_tokenizer.hasMoreTokens()) {
+		    Element content_element = document.createElement(CONTENT_ELEMENT);
+		    String content_str = content_tokenizer.nextToken();
+		    // Since the contents of indexes have to be certain keywords, or metadata elements, if the content isn't a keyword and doesn't yet have a namespace, append the extracted metadata namespace.
+		    if(content_str.indexOf(StaticStrings.NS_SEP) == -1) {
+			if(content_str.equals(StaticStrings.TEXT_STR) || (!old_index && content_str.equals(StaticStrings.ALLFIELDS_STR))) {
+				// Our special strings are OK.
+			}
+			else {
+			    content_str = StaticStrings.EXTRACTED_NAMESPACE + content_str;
+			}
+		    }
+		    content_element.setAttribute(NAME_ATTRIBUTE, content_str);
+		    index_element.appendChild(content_element);
+		    content_element = null;
+		}
+		content_tokenizer = null;
+		index_str = null;
+		command_element.appendChild(index_element);
+		index_element = null;
+	    }
+	    tokenizer = null;
+	}
+	catch (Exception exception) {
+	    exception.printStackTrace();
+	}
+	return command_element;
+    }
+
+    private Element parseIndexDefault(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    if(tokenizer.countTokens() >= 2) {
+		command_element = document.createElement(INDEX_DEFAULT_ELEMENT);
+		command_element.setAttribute(ASSIGNED_ATTRIBUTE, ((tokenizer.nextToken()).equals(INDEX_DEFAULT_STR) ? TRUE_STR : FALSE_STR));
+		String index_str = tokenizer.nextToken();
+		command_element.setAttribute(LEVEL_ATTRIBUTE, index_str.substring(0, index_str.indexOf(StaticStrings.COLON_CHARACTER)));
+		String content_str = index_str.substring(index_str.indexOf(StaticStrings.COLON_CHARACTER) + 1);
+		StringTokenizer content_tokenizer = new StringTokenizer(content_str, StaticStrings.COMMA_CHARACTER);
+		while(content_tokenizer.hasMoreTokens()) {
+		    Element content_element = document.createElement(CONTENT_ELEMENT);
+		    content_element.setAttribute(NAME_ATTRIBUTE, content_tokenizer.nextToken());
+		    command_element.appendChild(content_element);
+		    content_element = null;
+		}
+		content_tokenizer = null;
+		content_str = null;
+		content_str = null;
+		index_str = null;
+	    }
+	    tokenizer = null;
+	}
+	catch (Exception exception) {
+	}
+	return command_element;
+    }
+    private Element parseBuildType(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    if(tokenizer.countTokens() >= 2) {
+		command_element = document.createElement(INDEX_DEFAULT_ELEMENT);
+		command_element.setAttribute(ASSIGNED_ATTRIBUTE, ((tokenizer.nextToken()).equals(INDEX_DEFAULT_STR) ? TRUE_STR : FALSE_STR));
+		String index_str = tokenizer.nextToken();
+		command_element.setAttribute(LEVEL_ATTRIBUTE, index_str.substring(0, index_str.indexOf(StaticStrings.COLON_CHARACTER)));
+		String content_str = index_str.substring(index_str.indexOf(StaticStrings.COLON_CHARACTER) + 1);
+		StringTokenizer content_tokenizer = new StringTokenizer(content_str, StaticStrings.COMMA_CHARACTER);
+		while(content_tokenizer.hasMoreTokens()) {
+		    Element content_element = document.createElement(CONTENT_ELEMENT);
+		    content_element.setAttribute(NAME_ATTRIBUTE, content_tokenizer.nextToken());
+		    command_element.appendChild(content_element);
+		    content_element = null;
+		}
+		content_tokenizer = null;
+		content_str = null;
+		content_str = null;
+		index_str = null;
+	    }
+	    tokenizer = null;
+	}
+	catch (Exception exception) {
+	}
+	return command_element;
+    }
+
+    private Element parseLanguage(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    tokenizer.nextToken();
+	    if(tokenizer.hasMoreTokens()) {
+		command_element = document.createElement(LANGUAGES_ELEMENT);
+		while(tokenizer.hasMoreTokens()) {
+		    Element language_element = document.createElement(LANGUAGE_ELEMENT);
+		    language_element.setAttribute(NAME_ATTRIBUTE, tokenizer.nextToken());
+		    command_element.appendChild(language_element);
+		    language_element = null;
+		}
+	    }
+	    tokenizer = null;
+	}
+	catch (Exception exception) {
+	}
+	return command_element;
+    }
+
+    private Element parseLanguageDefault(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    if(tokenizer.countTokens() >= 2) {
+		command_element = document.createElement(LANGUAGE_DEFAULT_ELEMENT);
+		tokenizer.nextToken();
+		String default_language_str = tokenizer.nextToken();
+		command_element.setAttribute(NAME_ATTRIBUTE, default_language_str);
+		command_element.setAttribute(ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
+		default_language_str = null;
+	    }
+	    tokenizer = null;
+	}
+	catch (Exception exception) {
+	}
+	return command_element;
+    }
+
+    private Element parseLevels(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    // First token is command type (levels)
+	    String command = tokenizer.nextToken();
+	    if(tokenizer.hasMoreTokens()) {
+		command_element = document.createElement(LEVELS_ELEMENT);
+		command_element.setAttribute(ASSIGNED_ATTRIBUTE, (command.equals(LEVELS_STR) ? TRUE_STR : FALSE_STR));
+		while(tokenizer.hasMoreTokens()) {
+		    Element level_element = document.createElement(CONTENT_ELEMENT);
+		    level_element.setAttribute(NAME_ATTRIBUTE, tokenizer.nextToken());
+		    command_element.appendChild(level_element);
+		    level_element = null;
+		}
+	    }
+	    command = null;
+	}
+	catch(Exception exception) {
+	}
+	return command_element;
+    }
+
+    private Element parseMetadata(CommandTokenizer tokenizer) {
+	Element command_element = null;
+	try {
+	    command_element = document.createElement(COLLECTIONMETADATA_ELEMENT);
+	    String name_str = tokenizer.nextToken();
+	    String value_str = tokenizer.nextToken();
+	    if(name_str != null && value_str != null) {
+		String language_str = Configuration.getLanguage();
+		// Check if the value string is actually a language string
+		if(value_str.startsWith(LBRACKET_CHARACTER) && value_str.endsWith(RBRACKET_CHARACTER)) {
+		    language_str = value_str.substring(value_str.indexOf(LANGUAGE_ARGUMENT) + 2, value_str.length() - 1);
+		    value_str = tokenizer.nextToken();
+		}
+		if(value_str != null) {
+		    // Ready the value str (which can contain all sorts of funky characters) for writing as a DOM value
+		    value_str = Codec.transform(value_str, Codec.GREENSTONE_TO_DOM);
+		    command_element.setAttribute(NAME_ATTRIBUTE, name_str);
+		    command_element.setAttribute(LANGUAGE_ATTRIBUTE, language_str);
+		    command_element.setAttribute(ASSIGNED_ATTRIBUTE, TRUE_STR);
+		    XMLTools.setValue(command_element, value_str);
+		}
+		else {
+		    command_element = null;
+		}
+		language_str = null;
+	    }
+	    else {
+		command_element = null;
+	    }
+	    name_str = null;
+	    value_str = null;
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	    command_element = null;
+	}
+	return command_element;
+    }
+
+    private Element parseMetadataSpecial(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    if(tokenizer.countTokens() >= 2) {
+		String name_str = tokenizer.nextToken();
+		String value_str = tokenizer.nextToken();
+		if (name_str.equals(COLLECTIONMETADATA_CREATOR_STR)) {
+		    command_element = document.createElement(COLLECTIONMETADATA_CREATOR_ELEMENT);
+		}
+		else if(name_str.equals(COLLECTIONMETADATA_MAINTAINER_STR)) {
+		    command_element = document.createElement(COLLECTIONMETADATA_MAINTAINER_ELEMENT);
+		}
+		else if(name_str.equals(COLLECTIONMETADATA_PUBLIC_STR)) {
+		    command_element = document.createElement(COLLECTIONMETADATA_PUBLIC_ELEMENT);
+		}
+		else if (name_str.equals(BUILDTYPE_STR)) {
+		    command_element = document.createElement(BUILDTYPE_ELEMENT);
+		}
+		if(command_element != null) {
+		    command_element.setAttribute(NAME_ATTRIBUTE, name_str);
+		    command_element.setAttribute(LANGUAGE_ATTRIBUTE, ENGLISH_LANGUAGE_STR);
+		    command_element.setAttribute(SPECIAL_ATTRIBUTE, TRUE_STR);
+		    command_element.setAttribute(ASSIGNED_ATTRIBUTE, TRUE_STR);
+		    if(value_str.startsWith(SPEECH_CHARACTER) && value_str.endsWith(SPEECH_CHARACTER)) {
+			value_str = value_str.substring(1, value_str.length() - 1);
+		    }
+		    XMLTools.setValue(command_element, value_str);
+		}
+		value_str = null;
+		name_str = null;
+	    }
+	    tokenizer = null;
+	}
+	catch (Exception exception) {
+	}
+	return command_element;
+    }
+
+    private Element parsePlugIn(String command_str) {
+	Element command_element = null;
+	boolean use_metadata_files = false;
+	try {
+	    CommandTokenizer tokenizer = new CommandTokenizer(command_str);
+	    // Check the token count. The token count from a command tokenizer isn't guarenteed to be correct, but it does give the maximum number of available tokens according to the underlying StringTokenizer (some of which may actually be append together by the CommandTokenizer as being a single argument).
+	    if(tokenizer.countTokens() >= 2) {
+		command_element = document.createElement(PLUGIN_ELEMENT);
+		// First token is plugin
+		tokenizer.nextToken();
+		// The next token is the type
+		String type = tokenizer.nextToken();
+		command_element.setAttribute(TYPE_ATTRIBUTE, type);
+		// Now we parse out the remaining arguments into a hashmapping from name to value
+		HashMap arguments = parseArguments(tokenizer);
+		// Assign the arguments as Option elements, but watch out for the metadata argument as we treat that differently
+		Iterator names = arguments.keySet().iterator();
+		while(names.hasNext()) {
+		    String name = (String) names.next();
+		    String value = (String) arguments.get(name); // Can be null
+		    Element option_element = document.createElement(OPTION_ELEMENT);
+		    if(name.substring(1).equals(USE_METADATA_FILES_ARGUMENT)) {
+			use_metadata_files = true;
+		    }
+		    option_element.setAttribute(NAME_ATTRIBUTE, name.substring(1));
+		    option_element.setAttribute(ASSIGNED_ATTRIBUTE, TRUE_STR);
+		    option_element.setAttribute(CUSTOM_ATTRIBUTE, TRUE_STR); // All arguments are considered to be custom until matched against base plugins arguments
+		    if(value != null) {
+			// Remove any speech marks appended in strings containing whitespace
+			if(value.startsWith(SPEECH_CHARACTER) && value.endsWith(SPEECH_CHARACTER)) {
+			    value = value.substring(1, value.length() - 1);
+			}
+			if(name.equals(METADATA_ARGUMENT)) {
+			    // The metadata argument must be the fully qualified name of a metadata element, so if it doesn't yet have a namespace, append the extracted metadata namespace.
+			    if(value.indexOf(StaticStrings.NS_SEP) == -1) {
+				value = StaticStrings.EXTRACTED_NAMESPACE + value;
+			    }
+			}
+			XMLTools.setValue(option_element, value);
+		    }
+		    command_element.appendChild(option_element);
+		    option_element = null;
+		    name = null;
+		    value = null;
+		}
+
+		// We must have some RecPlug options: use_metadata_files, and show_progress
+		if (type.equals(RECPLUG_STR)) {
+		    if (!use_metadata_files) {
+			Element option_element = document.createElement(OPTION_ELEMENT);
+			option_element.setAttribute(NAME_ATTRIBUTE, USE_METADATA_FILES_ARGUMENT);
+			option_element.setAttribute(ASSIGNED_ATTRIBUTE, TRUE_STR);
+			option_element.setAttribute(CUSTOM_ATTRIBUTE, TRUE_STR);
+			command_element.appendChild(option_element);
+			option_element = null;
+		    }
+		}
+		type = null;
+		names = null;
+		arguments = null;
+	    }
+	    tokenizer = null;
+	}
+	catch(Exception exception) {
+	}
+	return command_element;
+    }
+
+    private Element parseSearchType(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    // First token is command type (levels)
+	    tokenizer.nextToken();
+	    if(tokenizer.hasMoreTokens()) {
+		command_element = document.createElement(SEARCHTYPE_ELEMENT);
+		command_element.setAttribute(ASSIGNED_ATTRIBUTE, TRUE_STR);
+		while(tokenizer.hasMoreTokens()) {
+		    Element search_element = document.createElement(CONTENT_ELEMENT);
+		    search_element.setAttribute(NAME_ATTRIBUTE, tokenizer.nextToken());
+		    command_element.appendChild(search_element);
+		    search_element = null;
+		}
+	    }
+	}
+	catch(Exception exception) {
+	}
+	return command_element;
+    }
+
+    private Element parseSubCollection(String command_str) {
+	Element command_element = null;
+	try {
+	    CommandTokenizer tokenizer = new CommandTokenizer(command_str);
+	    if(tokenizer.countTokens() >= 3) {
+		command_element = document.createElement(SUBCOLLECTION_ELEMENT);
+		// First token is command type
+		tokenizer.nextToken();
+		// Then subcollection identifier
+		command_element.setAttribute(NAME_ATTRIBUTE, tokenizer.nextToken());
+		// Then finally the pattern used to build the subcollection partition
+		String full_pattern_str = tokenizer.nextToken();
+		// Set inclusion/exclusion flag and remove any exclamation mark
+		boolean exclusion = full_pattern_str.startsWith(EXCLAMATION_CHARACTER);
+		if (exclusion) {
+		    full_pattern_str = full_pattern_str.substring(1, full_pattern_str.length());
+		    command_element.setAttribute(TYPE_ATTRIBUTE, EXCLUDE_STR);
+		}
+		else {
+		    command_element.setAttribute(TYPE_ATTRIBUTE, INCLUDE_STR);
+		}
+		StringTokenizer pattern_tokenizer = new StringTokenizer(full_pattern_str, SEPARATOR_CHARACTER);
+		if(pattern_tokenizer.countTokens() >= 2) {
+		    String content_str = pattern_tokenizer.nextToken();
+		    // Since the contents of indexes have to be certain keywords, or metadata elements, if the content isn't a keyword and doesn't yet have a namespace, append the extracted metadata namespace.
+		    if(!content_str.equals(StaticStrings.FILENAME_STR) && content_str.indexOf(StaticStrings.NS_SEP) == -1) {
+			content_str = StaticStrings.EXTRACTED_NAMESPACE + content_str;
+		    }
+		    command_element.setAttribute(CONTENT_ATTRIBUTE, content_str);
+		    XMLTools.setValue(command_element, pattern_tokenizer.nextToken());
+		    if(pattern_tokenizer.hasMoreTokens()) {
+			command_element.setAttribute(OPTIONS_ATTRIBUTE, pattern_tokenizer.nextToken());
+		    }
+		}
+		pattern_tokenizer = null;
+	    }
+	}
+	catch(Exception exception) {
+	    exception.printStackTrace();
+	}
+	return command_element;
+    }
+
+    private Element parseSubCollectionDefaultIndex(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    if(tokenizer.countTokens() == 2) {
+		command_element = document.createElement(SUBCOLLECTION_DEFAULT_INDEX_ELEMENT);
+		tokenizer.nextToken();
+		//command_element.setAttribute(CONTENT_ATTRIBUTE, tokenizer.nextToken());
+		String content_str = tokenizer.nextToken();
+		StringTokenizer content_tokenizer = new StringTokenizer(content_str, StaticStrings.COMMA_CHARACTER);
+		while(content_tokenizer.hasMoreTokens()) {
+		    Element content_element = document.createElement(CONTENT_ELEMENT);
+		    content_element.setAttribute(NAME_ATTRIBUTE, content_tokenizer.nextToken());
+		    command_element.appendChild(content_element);
+		    content_element = null;
+		}
+		content_tokenizer = null;
+		content_str = null;
+	    }
+	    tokenizer = null;
+	}
+	catch(Exception exception) {
+	}
+	return command_element;
+    }
+
+    private Element parseSubCollectionIndex(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    tokenizer.nextToken();
+	    if(tokenizer.hasMoreTokens()) {
+		command_element = document.createElement(SUBCOLLECTION_INDEXES_ELEMENT);
+	    }
+	    while(tokenizer.hasMoreTokens()) {
+		Element subcollectionindex_element = document.createElement(INDEX_ELEMENT);
+		//command_element.setAttribute(CONTENT_ATTRIBUTE, tokenizer.nextToken());
+		String content_str = tokenizer.nextToken();
+		StringTokenizer content_tokenizer = new StringTokenizer(content_str, StaticStrings.COMMA_CHARACTER);
+		while(content_tokenizer.hasMoreTokens()) {
+		    Element content_element = document.createElement(CONTENT_ELEMENT);
+		    content_element.setAttribute(NAME_ATTRIBUTE, content_tokenizer.nextToken());
+		    subcollectionindex_element.appendChild(content_element);
+		    content_element = null;
+		}
+		content_tokenizer = null;
+		content_str = null;
+		command_element.appendChild(subcollectionindex_element);
+		subcollectionindex_element = null;
+	    }
+	    tokenizer = null;
+	}
+	catch (Exception exception) {
+	}
+	return command_element;
+    }
+
+    private Element parseSuperCollection(String command_str) {
+	Element command_element = null;
+	try {
+	    StringTokenizer tokenizer = new StringTokenizer(command_str);
+	    if(tokenizer.countTokens() >= 3) {
+		command_element = document.createElement(SUPERCOLLECTION_ELEMENT);
+		tokenizer.nextToken();
+		while(tokenizer.hasMoreTokens()) {
+		    Element collection_element = document.createElement(COLLECTION_ELEMENT);
+		    collection_element.setAttribute(NAME_ATTRIBUTE, tokenizer.nextToken());
+		    command_element.appendChild(collection_element);
+		    collection_element = null;
+		}
+	    }
+	    tokenizer = null;
+	}
+	catch(Exception exception) {
+	}
+	return command_element;
+    }
+
+    private String pluginToString(Element command_element, boolean show_extracted_namespace) {
+	StringBuffer text = new StringBuffer();
+	if(!command_element.getAttribute(SEPARATOR_ATTRIBUTE).equals(TRUE_STR)) {
+	    text.append(PLUGIN_STR);
+	    text.append(TAB_CHARACTER);
+	    text.append(TAB_CHARACTER);
+	    text.append(command_element.getAttribute(TYPE_ATTRIBUTE));
+	    // Retrieve, and output, the arguments
+	    NodeList option_elements = command_element.getElementsByTagName(OPTION_ELEMENT);
+	    int option_elements_length = option_elements.getLength();
+	    if(option_elements_length > 0) {
+		text.append(SPACE_CHARACTER);
+		for(int j = 0; j < option_elements_length; j++) {
+		    Element option_element = (Element) option_elements.item(j);
+		    if(option_element.getAttribute(ASSIGNED_ATTRIBUTE).equals(TRUE_STR)) {
+			text.append(StaticStrings.MINUS_CHARACTER);
+			text.append(option_element.getAttribute(NAME_ATTRIBUTE));
+			String value_str = XMLTools.getValue(option_element);
+			if(!show_extracted_namespace && value_str.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
+			    value_str = value_str.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
+			}
+			if(value_str.length() > 0) {
+			    text.append(SPACE_CHARACTER);
+			    if(value_str.indexOf(SPACE_CHARACTER) == -1) {
+				text.append(value_str);
+			    }
+			    else {
+				text.append(SPEECH_CHARACTER);
+				text.append(value_str);
+				text.append(SPEECH_CHARACTER);
+			    }
+			}
+			value_str = null;
+			if(j < option_elements_length - 1) {
+			    text.append(SPACE_CHARACTER);
+			}
+		    }
+		    option_element = null;
+		}
+	    }
+	    option_elements = null;
+	}
+	return text.toString();
+    }
+
+    private String searchtypeToString(Element command_element) {
+	if(command_element.getAttribute(ASSIGNED_ATTRIBUTE).equals(TRUE_STR)) {
+	    StringBuffer text = new StringBuffer(SEARCHTYPE_STR);
+	    text.append(TAB_CHARACTER);
+	    NodeList search_elements = command_element.getElementsByTagName(CONTENT_ELEMENT);
+	    int search_elements_length = search_elements.getLength();
+	    for(int i = 0; i < search_elements_length; i++) {
+		Element search_element = (Element) search_elements.item(i);
+		text.append(search_element.getAttribute(NAME_ATTRIBUTE));
+		text.append(SPACE_CHARACTER);
+	    }
+	    return text.substring(0, text.length() - 1);
+	}
+	else {
+	    return null;
+	}
+    }
+
+    private String subcollectionToString(Element command_element, boolean show_extracted_namespace) {
+	StringBuffer text = new StringBuffer(SUBCOLLECTION_STR);
+	text.append(SPACE_CHARACTER);
+	text.append(command_element.getAttribute(NAME_ATTRIBUTE));
+	text.append(SPACE_CHARACTER);
+	text.append(TAB_CHARACTER);
+	text.append(SPEECH_CHARACTER);
+	if(command_element.getAttribute(TYPE_ATTRIBUTE).equals(EXCLUDE_STR)) {
+	    text.append(EXCLAMATION_CHARACTER);
+	}
+	String content_str = command_element.getAttribute(CONTENT_ATTRIBUTE);
+	if(!show_extracted_namespace && content_str.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
+	    content_str = content_str.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
+	}
+	text.append(content_str);
+	content_str = null;
+	text.append(SEPARATOR_CHARACTER);
+	text.append(XMLTools.getValue(command_element));
+	text.append(SEPARATOR_CHARACTER);
+	String options_str = command_element.getAttribute(OPTIONS_ATTRIBUTE);
+	if(options_str.length() > 0) {
+	    text.append(options_str);
+	}
+	options_str = null;
+	text.append(SPEECH_CHARACTER);
+	return text.toString();
+    }
+
+    private String subcollectionDefaultIndexToString(Element command_element) {
+	StringBuffer text = new StringBuffer(SUBCOLLECTION_DEFAULT_INDEX_STR);
+	text.append(TAB_CHARACTER);
+	NodeList content_elements = command_element.getElementsByTagName(CONTENT_ELEMENT);
+	int content_elements_length = content_elements.getLength();
+	for(int j = 0; j < content_elements_length; j++) {
+	    Element content_element = (Element) content_elements.item(j);
+	    text.append(content_element.getAttribute(NAME_ATTRIBUTE));
+	    if(j < content_elements_length - 1) {
+		text.append(StaticStrings.COMMA_CHARACTER);
+	    }
+	}
+	return text.toString();
+    }
+
+    private String subcollectionIndexesToString(Element command_element) {
+	StringBuffer text = new StringBuffer(SUBCOLLECTION_INDEX_STR);
+	text.append(TAB_CHARACTER);
+	// Retrieve all of the subcollection index partitions
+	NodeList subcollectionindex_elements = command_element.getElementsByTagName(INDEX_ELEMENT);
+	int subcollectionindex_elements_length = subcollectionindex_elements.getLength();
+	if(subcollectionindex_elements_length == 0) {
+	    return null;
+	}
+	for(int j = 0; j < subcollectionindex_elements_length; j++) {
+	    Element subcollectionindex_element = (Element) subcollectionindex_elements.item(j);
+	    NodeList content_elements = subcollectionindex_element.getElementsByTagName(CONTENT_ELEMENT);
+	    int content_elements_length = content_elements.getLength();
+	    for(int k = 0; k < content_elements_length; k++) {
+		Element content_element = (Element) content_elements.item(k);
+		text.append(content_element.getAttribute(NAME_ATTRIBUTE));
+		if(k < content_elements_length - 1) {
+		    text.append(StaticStrings.COMMA_CHARACTER);
+		}
+	    }
+	    if(j < subcollectionindex_elements_length - 1) {
+		text.append(SPACE_CHARACTER);
+	    }
+	}
+	return text.toString();
+    }
+
+    private String supercollectionToString(Element command_element) {
+	NodeList content_elements = command_element.getElementsByTagName(COLLECTION_ELEMENT);
+	int content_elements_length = content_elements.getLength();
+	if(content_elements_length > 1) {
+	    StringBuffer text = new StringBuffer(SUPERCOLLECTION_STR);
+	    text.append(TAB_CHARACTER);
+	    for(int j = 0; j < content_elements_length; j++) {
+		Element content_element = (Element) content_elements.item(j);
+		text.append(content_element.getAttribute(NAME_ATTRIBUTE));
+		if(j < content_elements_length - 1) {
+		    text.append(SPACE_CHARACTER);
+		}
+	    }
+	    return text.toString();
+	}
+	return null;
+    }
+
+    private String unknownToString(Element command_element) {
+	return XMLTools.getValue(command_element);
+    }
+
+    /** Write the text to the buffer. This is used so we don't have to worry about storing intermediate String values just so we can calaulate length and offset.
+     * @param writer the BufferedWriter to which the str will be written
+     * @param str the String to be written
+     */
+    private void write(BufferedWriter writer, String str)
+	throws IOException {
+	writer.write(str, 0, str.length());
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionDesignManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionDesignManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionDesignManager.java	(revision 10506)
@@ -0,0 +1,310 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.apache.xerces.parsers.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.LocalLibraryServer;
+import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.ZipTools;
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+/** This manager provides access to submanagers, which in turn provide tools for the designing of Greenstone collections via the information stored in etc/collect.cfg. This class acts as a hub for the managers that handle specific parts of the configuration such as classifiers, format strings and language settings.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3d
+ */
+public class CollectionDesignManager {
+    /** This listener listens for any event on any of the components in any of the sub-views, and marks the collection as needing saving if any change occurs. */
+    static public CDMChangeListener change_listener;
+    /** These listeners listen to changes in the Design mode so as to allow incremental building */
+    static public DesignChangeListener all_change_listener;
+    static public DesignChangeListener buildcol_change_listener;
+    static public DesignChangeListener collect_cfg_change_listener;
+    /** A list of classifiers to use at build time. */
+    static public ClassifierManager classifier_manager;
+    /** The CollectionConfiguration object on which this CDM will be based. */
+    static public CollectionConfiguration collect_config;
+    /** A manager of collection level metadata. */
+    static public CollectionMetaManager collectionmeta_manager;
+    /** A list of formating strings to use at build time. */
+    static public FormatManager format_manager;
+    /** The manager in charge of displaying this manager and the controls for other managers. */
+    static public GeneralManager general_manager;
+    /** List of indexes to be built, and the default index. */
+    static public IndexManager index_manager;
+    /** Contains instructions dealing with the collection language. */
+    static public LanguageManager language_manager;
+    /** A simple manager for the visual review of metadata sets. */
+    static public MetadataSetView metadataset_view;
+    /** A list of plugins to use at build time. */
+    static public PluginManager plugin_manager;
+    /** The manager in charge of all aspects of searchtypes. We also ask this manager whether we are MG or MGPP enabled. */
+    static public SearchTypeManager searchtype_manager;
+    /** Contains: A list of subcollections, (defined on metadatadata), a list of which subcollection indexes to build and the default subcollection index. */
+    static public SubcollectionManager subcollection_manager;
+
+    static public SubcollectionIndexManager subcollectionindex_manager;
+    /** A supercollection command allows a single search to be conducted across several collections. It is a very basic command and so avoids all the crazy model stuff that exists in most of the design managers. */
+    static public SuperCollectionManager supercollection_manager; // Just cause I could ;p
+    /** The text translation manager. */
+    static public TranslationView translation_view;
+    /** These mark what needs to happen when building a collection where ONLY design options have been changed.
+        The build requirements of the higher numbers must include doing everything from the lower numbers. */
+    static final public int ALL = 3;
+    static final public int BUILDCOL = 2;
+    static final public int UPDATE_COLLECT_CFG = 1;
+    static final public int NOTHING = 0;
+    static private int rebuildTypeRequired = NOTHING; //Rebuild type required if only design options have changed
+    static protected boolean update_collect_cfg_required = false;
+
+    /** Constructor. Loads a certain collection configuration file, which is parsed into a DOM. This model is then registered with the command information managers, each of whom knows how to, and provides controls to, alter certain commands.
+     * @param collect_config_file the File representing a collection configuration file either in its text (G2) or xml (G3) form
+     */
+    public CollectionDesignManager(File collect_config_file) {
+	DebugStream.println("Initializaing CollectionDesignModule.");
+	change_listener = new CDMChangeListener();
+	all_change_listener = new DesignChangeListener(ALL);
+	buildcol_change_listener = new DesignChangeListener(BUILDCOL);
+	collect_cfg_change_listener = new DesignChangeListener(UPDATE_COLLECT_CFG);
+	// Parse the collection configuration
+	collect_config = new CollectionConfiguration(collect_config_file);
+	if (DebugStream.isDebuggingEnabled()) {
+	    collect_config.display();
+	}
+	loadDesignDetails();
+	DebugStream.println("CollectionDesignModule loaded.");
+    }
+
+    /** Reloads the various managers to ensure they have built themselves from the latest details available in the collection configuration class
+     * @see org.greenstone.gatherer.cdm.ClassifierManager
+     * @see org.greenstone.gatherer.cdm.CollectionMetaManager
+     * @see org.greenstone.gatherer.cdm.FormatManager
+     * @see org.greenstone.gatherer.cdm.GeneralManager
+     * @see org.greenstone.gatherer.cdm.IndexManager
+     * @see org.greenstone.gatherer.cdm.LanguageManager
+     * @see org.greenstone.gatherer.cdm.MetadataSetView
+     * @see org.greenstone.gatherer.cdm.PluginManager
+     * @see org.greenstone.gatherer.cdm.SearchTypeManager
+     * @see org.greenstone.gatherer.cdm.SubcollectionIndexManager
+     * @see org.greenstone.gatherer.cdm.SubcollectionManager
+     * @see org.greenstone.gatherer.cdm.SuperCollectionManager
+     * @see org.greenstone.gatherer.cdm.TranslationView
+     */
+    private void loadDesignDetails() {
+	// Create the command information managers, registering the config file with each as necessary
+	language_manager = new LanguageManager(collect_config.getLanguages());
+	collectionmeta_manager = new CollectionMetaManager();
+	classifier_manager = new ClassifierManager();
+	general_manager = new GeneralManager();
+
+	searchtype_manager = new SearchTypeManager(collect_config.getSearchType());
+	if(searchtype_manager.isMGPPEnabled()) {
+	    index_manager = new IndexManager(collect_config.getMGPPIndexes());
+	}
+	else {
+	    index_manager = new IndexManager(collect_config.getMGIndexes());
+	}
+
+	metadataset_view = new MetadataSetView();
+	plugin_manager = new PluginManager();
+	plugin_manager.placeSeparator();
+	subcollection_manager = new SubcollectionManager();
+	subcollectionindex_manager = new SubcollectionIndexManager(collect_config.getSubIndexes());
+	supercollection_manager = new SuperCollectionManager(collect_config.getSuperCollection());
+	translation_view = new TranslationView();
+	format_manager = new FormatManager(); // Parse formats at the very end, given that they depend upon several other managers to appear properly.
+    }
+
+    /** This method deconstructs each of the managers, causing them to dispose of their controls.
+     */
+    public void destroy() {
+	// Remove visual the component from its parent.
+	if(general_manager.getParent() != null) {
+	    general_manager.getParent().remove(general_manager);
+	}
+	// Remove references from persistant listeners.
+	classifier_manager.destroy();
+	classifier_manager = null;
+	format_manager.destroy();
+	format_manager = null;
+	general_manager.destroy();
+	general_manager = null;
+	index_manager.destroy();
+	index_manager = null;
+	language_manager.destroy();
+	language_manager = null;
+	metadataset_view.destroy();
+	metadataset_view = null;
+	plugin_manager.destroy();
+	plugin_manager = null;
+	subcollection_manager.destroy();
+	subcollection_manager = null;
+	supercollection_manager.destroy();
+	supercollection_manager = null;
+	translation_view.destroy();
+	translation_view = null;
+    }
+
+    /** Display the GUI interface for the CollectionDesignManager in the centre of the indicated panel.
+     * @param target the JPanel you wish to display the gui on
+     */
+    public void display(JPanel target) {
+	target.add(general_manager, BorderLayout.CENTER);
+    }
+    /** When the tab on the JTabbedPane that contains the GUI is selected, this method is called to ensure that the controls are all up to date, in terms of references to metadata etc.
+     */
+    public void gainFocus() {
+	general_manager.gainFocus();
+    }
+
+    /** Called when the detail mode has changed which in turn may cause several design elements to be available/hidden
+     * @param mode the new mode as an int
+     */
+    public void modeChanged(int mode) {
+	plugin_manager.modeChanged(mode);
+	subcollection_manager.modeChanged(mode);
+    }
+
+    /** The cdm is considered to be ready if the collect.cfg file was found and parsed and the collection title is not error.
+     * @return true if the collection is ready, false otherwise
+     */
+    public boolean ready() {
+	return collect_config.ready();
+    }
+
+    /** Ensure that saving will actually work. This can return false if there is a collection filename clash for instance. */
+    public boolean canSave() {
+	return (general_manager == null || general_manager.canSave());
+    }
+
+
+    /** Cause the current collection configuration to be written out to disk.
+     */
+    public void save()
+    {
+	// Release collection as necessary
+	String collection_name = Gatherer.c_man.getCollection().getName();
+	boolean collection_released = false;
+
+	if (update_collect_cfg_required && Gatherer.c_man.built() && LocalLibraryServer.isRunning() == true) {
+	    // Release the collection
+	    LocalLibraryServer.releaseCollection(collection_name);
+	    collection_released = true;
+	}
+
+	general_manager.loseFocus();
+	collect_config.save();
+
+	// Read collection
+	if (collection_released) {
+	    // Now re-add collection to server to force format commands to be processed
+	    LocalLibraryServer.addCollection(collection_name);
+	}
+
+	if (update_collect_cfg_required) {
+	    // Unset formats changed
+	    update_collect_cfg_required = false;
+	}
+    }
+
+
+    static public Document XMLStringToDOM(StringBuffer xml, String form) 
+    {
+	Document document = null;
+
+	// If something has gone horribly wrong then xml will be empty.
+	if(xml.length() > 0) {
+	    try {
+		// Then read the xml from the piped input stream.
+		StringReader xml_sr = new StringReader(xml.toString());
+		InputSource source = new InputSource(xml_sr);
+		DOMParser parser = new DOMParser();
+		parser.parse(source);
+		document = parser.getDocument();
+	    }
+	    catch (Exception error) {
+		System.err.println("Failed when trying to parse XML stream ");
+		error.printStackTrace();
+	    }
+	}
+	else {
+	    //DebugStream.println("Zero length argument xml detected for: " + form);
+	    String[] margs = new String[1];
+	    margs[0] = form;
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.PlugInManager.PlugIn_XML_Parse_Failed", margs), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);  // !! TO DO: This is bad -- this function is used for more than just plugins
+	}
+
+	return document;
+    }
+
+    public static int getRebuildTypeRequired() {
+	return rebuildTypeRequired;
+    }
+    public static void resetRebuildTypeRequired() {
+	setRebuildTypeRequired(NOTHING);
+    }
+    public static void setRebuildTypeRequired(int number) {
+	rebuildTypeRequired = number;
+    }
+
+    /**
+     * What exactly does this do?
+     */
+    private class CDMChangeListener
+	implements ActionListener, DocumentListener {
+
+	/** Gives notification that an event has happened */
+	public void actionPerformed(ActionEvent event) {
+	    Gatherer.c_man.getCollection().setSaved(false);
+	}
+
+	/** Gives notification that an attribute or set of attributes changed. */
+	public void changedUpdate(DocumentEvent e) {
+	    Gatherer.c_man.getCollection().setSaved(false);
+	}
+
+	/** Gives notification that there was an insert into the document. */
+	public void insertUpdate(DocumentEvent e) {
+	    Gatherer.c_man.getCollection().setSaved(false);
+	}
+
+	/** Gives notification that a portion of the document has been removed. */
+	public void removeUpdate(DocumentEvent e) {
+	    Gatherer.c_man.getCollection().setSaved(false);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionMeta.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionMeta.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionMeta.java	(revision 10506)
@@ -0,0 +1,179 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.util.Codec;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+
+/** This class encapsulates a single collection level metadata assignment, which constitutes a name, language and value.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.4
+ */
+public class CollectionMeta
+    implements DOMProxyListEntry {
+
+    static final public boolean TEXT = true;
+    static final public boolean GREENSTONE = false;
+
+    private boolean dummy = false;
+    private Element element = null;
+    private String text = null;
+
+    /** Constructor.
+     * @param element the Element from which we will determine metadata details
+     */
+    public CollectionMeta(Element element) {
+	this.element = element;
+    }
+
+    /** Constructor to create a new piece of metadata given its name. */
+    public CollectionMeta(String name) {
+	element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.COLLECTIONMETADATA_ELEMENT);
+	element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name);
+	element.setAttribute(StaticStrings.LANGUAGE_ATTRIBUTE, Configuration.getLanguage());
+	element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
+    }
+
+    /** Constructor to create a new piece of metadata given its name. */
+    public CollectionMeta(String name, String language) {
+	element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.COLLECTIONMETADATA_ELEMENT);
+	element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name);
+	element.setAttribute(StaticStrings.LANGUAGE_ATTRIBUTE, language);
+	element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
+    }
+
+    /** Constructor to create a new piece of metadata given its name. */
+    public CollectionMeta(String name, String language, boolean dummy) {
+	this(name, language);
+	this.dummy = dummy;
+    }
+
+    /** Method to compare two collection metadata objects to calculate their respective ordering.
+     * @param object the other metadata to compare to, as an Object
+     * @return an int which is less than 0 if this object proceeds the given object, 0 if they are equal and greater than 0 otherwise.
+     * @see org.greenstone.gatherer.cdm.Language
+     */
+    public int compareTo(Object object) {
+	return toString().compareTo(object.toString());
+    }
+
+    /** Factory constructor. */
+    public DOMProxyListEntry create(Element element) {
+	return new CollectionMeta(element);
+    }
+
+    /** Method to compare two collection metadata objects for equality.
+     * @param object The other metadata to compare to, as an <strong>Object</strong>.
+     * @return A <i>boolean</i> value of <i>true</i> if the object are equal, <i>false</i> otherwise.
+     */
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+
+    public Element getElement() {
+	return element;
+    }
+
+    /** Method to retrieve the value of language.
+     * @return the value of language as a <strong>String</strong>.
+     */
+    public String getLanguage() {
+	// Retrieve the language string
+	return element.getAttribute(StaticStrings.LANGUAGE_ATTRIBUTE);
+    }
+
+    /** Method to retrieve the value of name.
+     * @return the name attribute of the collection meta as a String 
+     */
+    public String getName() {
+	return element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+    }
+    /** Method to retrieve the value of value (well great choice of name there).
+     * @return The value of value as a <strong>String</strong>.
+     */
+    public String getValue(boolean text_value) {
+	String raw_value = XMLTools.getValue(element);
+	// Decode the raw value depending on whether the user asked for the TEXT or GREENSTONE version
+	if(text_value == TEXT) {
+	    return Codec.transform(raw_value, Codec.DOM_TO_TEXT);
+	}
+	else {
+	    return Codec.transform(raw_value, Codec.DOM_TO_GREENSTONE);
+	}
+    }
+
+    public boolean isAssigned() {
+	return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
+    }
+
+    public boolean isDummy() {
+	return dummy;
+    }
+
+    /** Determine if this metadata is one of the four special pieces of metadata.
+     * @return true if this metadata is special, false otherwise.
+     */
+    public boolean isSpecial() {
+	return (element != null && element.getAttribute(StaticStrings.SPECIAL_ATTRIBUTE).equals(StaticStrings.TRUE_STR));
+    }
+
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    public void setElement(Element element) {
+	this.element = element;
+	text = null;
+    }
+
+    /** Change the value of value. 
+     * @param raw_value the new value as a String.
+     */
+    public void setValue(String raw_value) {
+	// Only raw html text can be given to setValue so we need to encode it
+	XMLTools.setValue(element, Codec.transform(raw_value, Codec.TEXT_TO_DOM));
+	text = null; // Reset text
+	// And determine if this makes the metadata assigned
+	setAssigned(raw_value != null && raw_value.length() > 0);
+    }
+
+    /** Method to print out this class as it would appear within the collection configuration file.
+     * @return A <strong>String</strong> containing the text value of this class.
+     */
+    public String toString() {
+	if(text == null) {
+	    text = CollectionConfiguration.toString(element, true);
+	}
+	return text;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionMetaManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionMetaManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CollectionMetaManager.java	(revision 10506)
@@ -0,0 +1,208 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.w3c.dom.*;
+
+/** This class is responsible for maintaining a list of assigned collection level metadata, and for allows manipulations on the aforementioned data.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3d
+ */
+public class CollectionMetaManager 
+    extends DOMProxyListModel {
+    
+    /** Constructor. */
+    public CollectionMetaManager() {
+	super(CollectionDesignManager.collect_config.getDocumentElement(), StaticStrings.COLLECTIONMETADATA_ELEMENT, new CollectionMeta(""));
+	DebugStream.println("CollectionMetaManager: " + getSize() + " metadata parsed.");
+    }
+    /** Method to add a new piece of metadata.
+     * @param metadata the new CollectionMeta
+     */
+    public void addMetadatum(CollectionMeta metadata) {
+	if(!contains(metadata)) {
+	    Element element = metadata.getElement();
+	    // Locate where we should insert this new subcollection. 
+	    Node target_node = CollectionConfiguration.findInsertionPoint(element);
+	    add(root, metadata, target_node);
+	    Gatherer.c_man.configurationChanged();
+	}
+	Gatherer.c_man.configurationChanged();
+    }
+
+    public CollectionMeta get(int i) {
+	return (CollectionMeta) getElementAt(i);
+    }
+
+    /** Retrieve the languages in use for the metadata assigned to this collection
+     * @return an TreeSet containing the languages used
+     */
+    public TreeSet getLanguages() {
+	TreeSet result = new TreeSet();
+	int size = getSize();
+	for(int i = 0; i < size; i++) {
+	    CollectionMeta metadata = (CollectionMeta) getElementAt(i);
+	    String language = metadata.getLanguage();
+	    result.add(language);
+	}
+	return result;
+    }
+
+    /** Retrieve all of the general metadata. */
+    public ArrayList getMetadata() {
+	ArrayList result = new ArrayList();
+	int size = getSize();
+	for(int i = 0; i < size; i++) {
+	    CollectionMeta metadata = (CollectionMeta) getElementAt(i);
+	    if(!metadata.getName().startsWith(StaticStrings.STOP_CHARACTER)) {
+		result.add(metadata);
+	    }
+	}
+	return result;
+    }
+	 
+    /** Retrieve all of the metadata for the given feature, regardless of language. */
+    public ArrayList getMetadata(String name) {
+	ArrayList result = new ArrayList();
+	int size = getSize(); // Refresh DOM Model
+	for(int i = 0; i < size; i++) {
+	    CollectionMeta metadata = (CollectionMeta) getElementAt(i);
+	    if(metadata.getName().equals(name)) {
+		result.add(metadata);
+	    }
+	}
+	return result;
+    }
+
+    /** Retrieve the named piece of metadata, in the default language, if available. If no such metadata is available then it is created.
+     * @param name the name of the metadatum to retrieve as a String
+     * @return the dom Element containing the specified metadatum
+     */
+    public CollectionMeta getMetadatum(String name) {
+	return getMetadatum(name, true);
+    }
+
+    public CollectionMeta getMetadatum(String name, boolean add_if_not_found) {
+	//DebugStream.println("Get the metadata for " + name + " in the default language.");
+	int size = getSize();
+	for(int i = 0; i < size; i++) {
+	    CollectionMeta metadatum = (CollectionMeta) getElementAt(i);
+	    if(metadatum.getName().equals(name) && metadatum.getLanguage().equals(Configuration.getLanguage())) {
+		DebugStream.println("Found '" + metadatum + "'");
+		return metadatum;
+	    }
+	    else {
+		//DebugStream.println("No match with: " + metadatum.getName() + " [l=" + metadatum.getLanguage() + "] \"" + metadatum.getValue() + "\"");
+	    }
+	    metadatum = null;
+	}
+	if(add_if_not_found) {
+	    CollectionMeta result = new CollectionMeta(name);
+	    addMetadatum(result);
+	    DebugStream.println("Added new metadata: " + name);
+	    return result;
+	}
+	else {
+	    return null;
+	}
+    }
+
+    /** Method to retrieve a certain piece of metadata based on its name and language.
+     * @param name the name of the metadata as an Object (as it may actually be a refernce to an Index or SubIndex)
+     * @param language the language of the metadata.
+     * @param partial <i>true</i> to return the first partial match (ie matches name but not language).
+     * @return The <strong>CollectionMeta</strong> requested, or <i>null</i> if no such metadata.
+     */
+    public CollectionMeta getMetadata(String name, String language, boolean partial) { 
+	CollectionMeta partial_match = null;
+	for(int i = 0; i < getSize(); i++) {
+	    CollectionMeta metadata = (CollectionMeta) getElementAt(i);
+	    Object metadata_name = metadata.getName();
+	    // We test the case of an object match (ie Index to Index)...
+	    if(metadata_name.equals(name)) {
+		if (metadata.getLanguage().equals(language)) {
+		    return metadata;
+		}
+		partial_match = metadata;
+	    }
+	}
+	if(partial) {
+	    return partial_match;
+	}
+	return null;
+    }
+
+    /** Method to remove a piece of metadata.
+     * @param metadata metadata
+     */
+    public void removeMetadata(CollectionMeta metadata) {
+	if(metadata != null) {
+	    String name = metadata.getName();
+	    String language = metadata.getLanguage();
+	    for(int i = 0; i < getSize(); i++) {
+		CollectionMeta other = (CollectionMeta) getElementAt(i);
+		if(name.equals(other.getName()) && language.equals(other.getLanguage())) {
+		    remove(i);
+		    Gatherer.c_man.configurationChanged();
+		    return;
+		}
+		other = null;
+	    }	
+	    language = null;
+	    name = null;
+	}
+    }
+
+    /** Removes all of the metadata with a certain name, regardless of language or value. */
+    public void removeMetadata(String name) {
+	boolean removed_entry = false;
+	for(int i = getSize(); i != 0; i--) {
+	    CollectionMeta other = (CollectionMeta) getElementAt(i - 1);
+	    if(name.equals(other.getName())) {
+		remove(i - 1);
+		removed_entry = true;
+	    }
+	    other = null;
+	}	
+	if(removed_entry) {
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+
+    public int size() {
+	return getSize();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CommandTokenizer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CommandTokenizer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/CommandTokenizer.java	(revision 10506)
@@ -0,0 +1,225 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.cdm;
+
+/**************************************************************************************
+ * Title:		Gatherer
+ * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
+ * Company:	  The University of Waikato
+ * Written:	  07/05/02
+ * Revised:	  03/10/02 - Commented
+ **************************************************************************************/
+import java.io.BufferedReader;
+import java.util.StringTokenizer;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.util.StaticStrings;
+
+/** This class provides an extension to the standard StringTokenizer in that it recognizes quotes (or some form of bracketting) enclose a single token so in something like: <br>format Search '&lt;table&gt;&lt;img src=... &lt;/table&gt;'<br> the formatting string is parsed as a single token. Unfortunately this makes countTokens() unreliable for exact measurement of tokens remaining, and only useful for determining if there are tokens left to be processed (includes any that have already been read into command buffer).
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class CommandTokenizer {
+    
+    static final public int BRACKET_ENCLOSED		= 0;
+    static final public int DOUBLE_QUOTE_ENCLOSED	= 1;
+    static final public int NORMAL			= 2;
+    static final public int QUOTE_ENCLOSED		= 3;
+    
+    private BufferedReader in_stream;
+    private int count = -1;
+    private StringTokenizer internal_tokenizer;
+    private boolean strip_quotes = true;
+    /** Basic Constructor. Used to parse tokens from a string keeping tokens surrounded by speechmarks or square brackets intact. Thus something like:<br>
+     * collectionmeta collectionextra [l = en] "Hello World"<br>
+     * is tokenized thus<br>
+     * {'collectionmeta', 'collectionextra', 'l = en', 'Hello World'}
+     * @param command the command String you wish to tokenize
+     */
+    public CommandTokenizer(String command) {
+	this.internal_tokenizer = new StringTokenizer(command);
+	this.in_stream = null;
+    }
+    
+    /** Advanced Constructor. As above but with one major difference. Since it is provided an input stream (presumably where the command string originated from), it is able to parse a quote enclosed command token that stretches over several lines. Each newline is preserved in the resulting token. There is an extra bitchslap here as comething like a collection extra might have html code in them that contain escaped speechmarks, so extra care must be taken not to break at them. Thus something like:<br>
+     * collectionmeta collectionextra [l = en] "<br>
+     *     an example of the crazy as description we sometimes get which includes of all things something like <a href=\"this.html\"<br>
+     *     >this</a> which you could easily see might be a problem if I parse this niavely."<br>
+     * is tokenized thus<br>
+     * {'collectionmeta', 'collectionextra', 'l = en', '\nan example of the crazy as description we sometimes get which includes of all things something like <a href=\"this.html\"\n>this</a> which you could easily see might be a problem if I parse this niavely.'}
+     * @param command the command String you wish to tokenize
+     * @param in_stream a BufferedReader from which the tokenizer can draw further lines as necessary
+     */
+    public CommandTokenizer(String command, BufferedReader in_stream) {
+	///atherer.println("***** CommandTokenizer *****\nparse:\t" + command + "\n****************************");
+	this.internal_tokenizer = new StringTokenizer(command);
+	this.in_stream = in_stream;
+    }
+    
+    public CommandTokenizer(String command, BufferedReader in_stream, boolean strip_quotes) {
+	this.internal_tokenizer = new StringTokenizer(command);
+	this.in_stream = in_stream;
+	this.strip_quotes = strip_quotes;
+    }
+	
+    /** Returns the minumum number of remaining tokens before the tokenizer runs out of string. There may be more tokens than this count, but never less. The discrepancy is due to internal functionality and the fact we can't read ahead in the string or associated stream without risking the need for unpredictable push-back
+     * @return the minumum number of tokens available as an int
+     */
+    public int countTokens() {
+	if(count == 0 && internal_tokenizer.countTokens() > 1) {
+	    return 1;
+	}
+	if(count == -1) {
+	    count = internal_tokenizer.countTokens();
+	}
+	return count;
+    }
+    
+    /** Determine if there are still tokens available.
+     * @return true if there are more tokens, false otherwise
+     */
+    public boolean hasMoreTokens() {
+	return internal_tokenizer.hasMoreTokens();
+    }
+    
+    /** Method to retrieve the next token from the command, taking care to group tokens enclosed in speech marks.
+     * @return a String containing the next token from the command
+     */
+    public String nextToken() {
+	String result = null;
+	if(internal_tokenizer.hasMoreTokens()) {
+	    StringBuffer buffer = new StringBuffer(internal_tokenizer.nextToken());
+	    switch(buffer.charAt(0)) {
+	    case StaticStrings.DOUBLEQUOTE_CHAR:
+		///ystem.err.println("Building token wrapped by double quotes.");
+		result = buildToken(buffer, StaticStrings.DOUBLEQUOTE_CHAR, this.strip_quotes);
+		break;
+	    case StaticStrings.SINGLEQUOTE_CHAR:
+		///ystem.err.println("Building token wrapped by single quotes.");
+		result = buildToken(buffer, StaticStrings.SINGLEQUOTE_CHAR, this.strip_quotes);
+		break;
+	    case StaticStrings.OPENBRACKET_CHAR:
+		///ystem.err.println("Building token wrapped by brackets.");
+		result = buildToken(buffer, StaticStrings.CLOSEBRACKET_CHAR, false);
+		break;
+	    default:
+		///ystem.err.println("Returning plain string.");
+		result = buffer.toString();
+	    }
+	    buffer = null;
+	}
+	// Because of our tricky counting system we never want to have negative tokens remaining. In fact, unless the internal string buffer is empty, we will return a count of 1 anyway
+	if(count > 0) {
+	    count = count - 1;
+	}
+	///ystem.err.println("----- CommandTokenizer -----\ntoken:\t" + result + "\n----------------------------");
+	return result;
+    }
+    
+    /** Parse in the next token. paying heed to enclosing characters demands, escaped characters, newlines and empty buffers and consequential unexpected end of tokens
+     * @param buffer the StringBuffer in which the partial token is stored (at the first bit that caused this method to be called)
+     * @param end_char the sentinel char we are watching for as it encloses a token
+     * @param strip_characters a boolean denoting whether the enclosing characters should be stripped off
+     * @return the token, either in its entirity less the enclosing characters if required or, if an unexpected end occured, whatever we parsed without its starting enclosing character, again only if required. In fact if we weren't asked to strip characters then we add the enclosing character back in
+     */
+    private String buildToken(StringBuffer buffer, char end_char, boolean strip_characters) {
+	while(buffer.length() == 1 || buffer.charAt(buffer.length() - 1) != end_char || (buffer.length() > 3 && buffer.charAt(buffer.length() - 2) == StaticStrings.BACKSLASH_CHAR)) {
+	    try {
+		// The first version is for the basic tokenizer which has no idea of an input stream, so runs out tokens at the same time as the internal tokenizer does
+		if(internal_tokenizer.hasMoreTokens()) {
+		    buffer.append(StaticStrings.SPACE_CHAR);
+		    buffer.append(internal_tokenizer.nextToken());
+		}
+		// While the second version can draw more lines from the stream until eof occurs
+		else if(in_stream != null) {
+		    String line_str = null;
+		    while(!internal_tokenizer.hasMoreTokens() && (line_str = in_stream.readLine()) != null) {
+			///atherer.println("+++++ CommandTokenizer +++++\nappend:\t" + line_str + "\n+++++++++++++++++++++++++++++");
+			// Its at this stage the our token count becomes completely putu
+			internal_tokenizer = new StringTokenizer(line_str);
+			buffer.append(StaticStrings.NEW_LINE_CHAR); // A new line in the final token
+		    }
+		    line_str = null;
+		    if(internal_tokenizer.hasMoreTokens()) {
+			// Don't add a space if we just added a newline
+			if(buffer.charAt(buffer.length() - 1) != StaticStrings.NEW_LINE_CHAR) {
+			    buffer.append(StaticStrings.SPACE_CHAR);
+			}
+			buffer.append(internal_tokenizer.nextToken());
+		    }
+		    // We've prematurely run out of content, so throw the dummy, or at least return whatever we managed to parse sans its opening character
+		    else {
+			if(strip_characters) {
+			    return buffer.substring(1);
+			}
+			else {
+			    buffer.append(end_char);
+			    return buffer.toString();
+			}
+		    }
+		}
+		// We've prematurely run out of content, so throw the dummy, or at least return whatever we managed to parse sans its opening character
+		else {
+		    if(strip_characters) {
+			return buffer.substring(1);
+		    }
+		    else {
+			buffer.append(end_char);
+			return buffer.toString();
+		    }
+		}
+	    }
+	    // Exception thrown when we attempted reading from the input stream, so throw the dummy, or at least return whatever we managed to parse sans its opening character
+	    catch(Exception exception) {
+		DebugStream.printStackTrace(exception);
+		if(strip_characters) {
+		    return buffer.substring(1);
+		}
+		else {
+		    buffer.append(end_char);
+		    return buffer.toString();
+		}
+	    }
+	}
+	// Return the string sans enclosing characters
+	if(buffer.length() >= 2 && strip_characters) {
+	    return buffer.substring(1, buffer.length() - 1);
+	}
+	else {
+	    return buffer.toString();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Control.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Control.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Control.java	(revision 10506)
@@ -0,0 +1,36 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+/**
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3d
+ */
+public interface Control {
+    public void destroy();
+    public void gainFocus();
+    public void loseFocus();
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DOMProxyListEntry.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DOMProxyListEntry.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DOMProxyListEntry.java	(revision 10506)
@@ -0,0 +1,38 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import org.w3c.dom.*;
+
+public interface DOMProxyListEntry 
+    extends Comparable {
+    public DOMProxyListEntry create(Element element);
+    public Element getElement();
+    public boolean isAssigned();
+    public void setAssigned(boolean assigned);
+    public void setElement(Element element);
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DOMProxyListModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DOMProxyListModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DOMProxyListModel.java	(revision 10506)
@@ -0,0 +1,265 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.util.*;
+import javax.swing.*;
+import org.greenstone.gatherer.DebugStream;
+import org.w3c.dom.*;
+
+/** This class provides ListModel like access to a list of nodes within a DOM model.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3d
+ */
+public class DOMProxyListModel
+    extends AbstractListModel {
+    protected Element root;
+    private DOMProxyListEntry class_type;
+    private HashMap cache = new HashMap();
+    private NodeList children = null;
+    private String tag_name;
+
+    /** Constructor.
+     * @param root the Element at the root of the subtree to be searched for appropriate child elements
+     * @param tag_name the name of appropriate elements as a String
+     * @param class_type the type of object to wrap the elements returned in, as a DOMProxyListEntry
+     */
+    public DOMProxyListModel(Element root, String tag_name, DOMProxyListEntry class_type) {
+	this.class_type = class_type;
+	this.root = root;
+	this.tag_name = tag_name;
+	this.children = this.root.getElementsByTagName(this.tag_name);
+    }
+
+    /** Used to add an element into the underlying dom, and fire the appropriate repaint events. This version always adds the new element at the very head of the DOM. */
+    public synchronized void add(DOMProxyListEntry entry) {
+	Element element = entry.getElement();
+	if(root.hasChildNodes()) {
+	    Node sibling = root.getFirstChild();
+	    root.insertBefore(element, sibling);
+	    sibling = null;
+	}
+	else {
+	    root.appendChild(element);
+	}
+	element = null;
+	// Regardless fire update event
+	cache.clear();
+	fireIntervalAdded(this, 0, 0);
+    }
+
+    /** Used to add an element into the underlying dom, and fire the appropriate repaint events.
+     * @param index the index where the element should be inserted (relative of the other elements in this proxy list)
+     * @param entry the <strong>DOMProxyListEntry</strong> to be inserted
+     */
+    public synchronized void add(int index, DOMProxyListEntry entry) {
+	///atherer.println("Add entry at " + index + " where size = " + getSize());
+	Element element = entry.getElement();
+	// retrieve the node where we want to insert
+	if(index < children.getLength()) {
+	    Node sibling = children.item(index);
+	    // Find the parent node
+	    Node parent_node = sibling.getParentNode();
+	    parent_node.insertBefore(element, sibling);
+	    sibling = null;
+	}
+	// If the index is too large, we are adding to the end of our list of entries. However you have to remember that this list is only a viewport on the entire DOM so there might be entries following this group that we actually want to insert before (not append at the very end!)
+	else {
+	    // Retrieve the currently last entry
+	    index = children.getLength() - 1;
+	    Node sibling = null;
+	    Node parent_node = null;
+	    if(index >= 0) {
+		sibling = children.item(index);
+		parent_node = sibling.getParentNode();
+		sibling = sibling.getNextSibling();
+	    }
+	    if(sibling != null && parent_node != null) {
+		parent_node.insertBefore(element, sibling);
+	    }
+	    // Add to the root node
+	    else {
+		index = 0;
+		root.appendChild(element);
+	    }
+	}
+	// Regardless fire update event
+	cache.clear();
+	fireIntervalAdded(this, index, index);
+    }
+
+    /** Used to add an element into the underlying dom, and fire the appropriate repaint events. This version inserts the new entry immediately -after- the given entry in the DOM.
+     * @param entry the DOMProxyListEntry to be inserted
+     * @param preceeding_entry the DOMProxyListEntry immediately before where we want the new entry
+     */
+    public synchronized void addAfter(DOMProxyListEntry entry, DOMProxyListEntry preceeding_entry) {
+	Element element = entry.getElement();
+	Element preceeding_sibling = preceeding_entry.getElement();
+	Node parent_node = preceeding_sibling.getParentNode();
+	Node following_sibling = preceeding_sibling.getNextSibling();
+	if(following_sibling != null) {
+	    parent_node.insertBefore(element, following_sibling);
+	}
+	else {
+	    parent_node.appendChild(element);
+	}
+	// Regardless fire update event
+	cache.clear();
+	int index = indexOf(entry);
+	fireIntervalAdded(this, index, index);
+    }
+
+    /** Used to add an element into the underlying dom, and fire the appropriate repaint events. This version inserts the new entry immediately -before- the given entry in the DOM.
+     * @param entry the DOMProxyListEntry to be inserted
+     * @param following_entry the DOMProxyListEntry immediately after where we want the new entry
+     */
+    public synchronized void addBefore(DOMProxyListEntry entry, DOMProxyListEntry following_entry) {
+	Element element = entry.getElement();
+	Element following_sibling = following_entry.getElement();
+	Node parent_node = following_sibling.getParentNode();
+	parent_node.insertBefore(element, following_sibling);
+	// Regardless fire update event
+	cache.clear();
+	int index = indexOf(entry);
+	fireIntervalAdded(this, index, index);
+    }
+
+    public synchronized void add(Node parent, DOMProxyListEntry entry, Node sibling) {
+	Element child = entry.getElement();
+	if(sibling != null) {
+	    parent.insertBefore(child, sibling);
+	}
+	else {
+	    parent.appendChild(child);
+	}
+	cache.clear();
+	int index = indexOf(entry);
+	fireIntervalAdded(this, index, index);
+    }
+
+    /** Used to add an element into the underlying dom, and fire the appropriate repaint events. This version always adds the new element at the end of the children. */
+    public synchronized void append(DOMProxyListEntry entry) {
+	Element element = entry.getElement();
+	root.appendChild(element);
+	element = null;
+	// Regardless fire update event
+	cache.clear();
+	fireIntervalAdded(this, 0, 0);
+    }
+   
+    public synchronized ArrayList children() {
+	ArrayList child_list = new ArrayList();
+	int child_count = children.getLength();
+	for(int i = 0; i < child_count; i++) {
+	    child_list.add(getElementAt(i));
+	}
+	return child_list;
+    }
+
+    public synchronized boolean contains(Object entry) {
+	boolean found = false;
+	int size = getSize();
+	for(int i = 0; !found && i < size; i++) {
+	    DOMProxyListEntry sibling = (DOMProxyListEntry) getElementAt(i);
+	    if(sibling.equals(entry)) {
+		found = true;
+	    }
+	}
+	return found;
+    }
+
+    public synchronized Object getElementAt(int index)
+    {
+	Object object = cache.get(new Integer(index));
+	if (object != null) {
+	    return object;
+	}
+
+	// Retrieve the required element
+	Element element = (Element) children.item(index);
+	DebugStream.println("Element at index " + index + " not in cache: " + element);
+
+	// Now wrap it in the object of the users choice
+	object = class_type.create(element);
+	cache.put(new Integer(index), object);
+	return object;
+    }
+
+    public synchronized int indexOf(DOMProxyListEntry entry) {
+	Element element = entry.getElement();
+	int children_length = children.getLength();
+	for(int i = 0; i < children_length; i++) {
+	    Node node = children.item(i);
+	    if(element == node) {
+		return i;
+	    }
+	}
+	return -1;
+    }
+
+    public synchronized int getSize() {
+	if(children == null) {
+	    children = root.getElementsByTagName(tag_name);
+	}
+	return children.getLength();
+    }
+
+    public synchronized void refresh() {
+	fireContentsChanged(this, 0, getSize());
+    }
+
+    public synchronized void refresh(DOMProxyListEntry entry) {
+	int index = indexOf(entry);
+	fireContentsChanged(this, index, index);
+    }
+
+    public synchronized void remove(DOMProxyListEntry entry) {
+	remove(indexOf(entry));
+    } 
+
+    public synchronized void remove(int index) {
+	// Retrieve the required element
+	Node node = children.item(index);
+	// Find its parent
+	Node parent_node = node.getParentNode();
+	// Now remove it
+	parent_node.removeChild(node);
+	// Refresh model
+	cache.clear();
+	fireIntervalRemoved(this, index, index);
+    }
+
+    /** Changes the 'root' element that this list sources its information from. 
+     * @param  root the new root Element
+     */
+    public synchronized void setRoot(Element root) {
+	this.children = null;
+	cache.clear();
+	this.root = root;
+	this.children = this.root.getElementsByTagName(this.tag_name);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DesignChangeListener.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DesignChangeListener.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DesignChangeListener.java	(revision 10506)
@@ -0,0 +1,85 @@
+/**
+ *#########################################################################
+ *
+ * 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: Matthew Whyte, 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.gatherer.cdm;
+
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.DebugStream;
+import javax.swing.event.*;
+import java.awt.event.*;
+
+/**
+ * This handles events generated by changing design options.
+ * The rebuildTypeRequired is updated if the rebuild type associated with this
+ * listener requires more 'work' than what is currently set in the {@link CollectionDesignManager}.
+ * @author Matthew Whyte
+ */
+public class DesignChangeListener implements ActionListener, DocumentListener {
+    
+    /** The rebuild type required associated with this listener */
+    private final int rebuildType;
+    
+    /** Constructor. Sets the build type required. */
+    public DesignChangeListener(int type) {
+	rebuildType = type;
+    }
+
+    public void maybeSetRebuildRequired() {
+	if(rebuildType > CollectionDesignManager.getRebuildTypeRequired()) {
+	    CollectionDesignManager.setRebuildTypeRequired(rebuildType);
+	}
+	//We need to keep track of this seperately, as collect.cfg is uploaded if needed, when the collect.cfg is saved.
+	if(rebuildType == CollectionDesignManager.UPDATE_COLLECT_CFG) {
+	    CollectionDesignManager.update_collect_cfg_required = true;
+	}
+    }
+    
+    /** Gives notification that an event has happened */
+    public void actionPerformed(ActionEvent event) {
+	//DebugStream.println("ActionEvent in Design from: " + event.getSource());
+	maybeSetRebuildRequired();
+    }
+
+    /** Gives notification that an attribute or set of attributes changed. */
+    public void changedUpdate(DocumentEvent e) {
+	maybeSetRebuildRequired();
+	//DebugStream.println("changedUpdate in Design.");
+    }
+    
+    /** Gives notification that there was an insert into the document. */
+    public void insertUpdate(DocumentEvent e) {
+	maybeSetRebuildRequired();
+	//DebugStream.println("insertUpdate in Design."); //debug
+    }
+    
+    /** Gives notification that a portion of the document has been removed. */
+    public void removeUpdate(DocumentEvent e) {
+	maybeSetRebuildRequired();
+	//DebugStream.println("removeUpdate in Design."); //debug
+    }
+    
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DynamicListModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DynamicListModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/DynamicListModel.java	(revision 10506)
@@ -0,0 +1,119 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.cdm;
+
+/**************************************************************************************
+ * Title:        Gatherer
+ * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
+ * Company:      The University of Waikato
+ * Written:      20/05/02
+ * Revised:      03/10/02 - Commented
+ **************************************************************************************/
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultListModel;
+
+/** This class extends the functionality of the DefaultListModel to include simple methods for refreshing the contents of this model if one of its elements changes.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class DynamicListModel
+    extends DefaultListModel
+    implements ComboBoxModel {
+
+    private boolean auto_order = false;
+
+    private Object object = null;
+
+    public void addElement(Object element) {
+	if(auto_order) {
+	    // Insert the object in its alphabetically correct place.
+	    int position = 0;
+	    boolean found = false;
+	    while(!found && position < size()) {
+		///ystem.err.print("Compare " + element.toString() + " to " + get(position).toString() + ": ");
+		int order = element.toString().compareTo(get(position).toString());
+		if(order < 0) {
+		    add(position, element);
+		    found = true;
+		    ///ystem.err.println("Greater than. Insert");
+		}
+		else if(order == 0) {
+		    found = true;
+		    ///ystem.err.println("Equal. End.");
+		}
+		else {
+		    position++;
+		    ///ystem.err.println("Less than. Carry on.");
+		}
+	    }
+	    if(!found) {
+		super.addElement(element);
+		///ystem.err.println("Out of elements. Insert");
+	    }
+	}
+	else {
+	    super.addElement(element);
+	}
+    }
+
+    /* private DynamicListModel shallowCopy() {
+	DynamicListModel copy = new DynamicListModel();
+	copy.setAutoOrder(auto_order);
+	for(int i = 0; i < size(); i++) {
+	    copy.addElement(get(i));
+	}
+	return copy;
+	} */
+
+    public Object getSelectedItem() {
+	///ystem.err.println("Get item: " + object);
+	return object;
+    }
+    /** Notify all controls that are based on this list model that its contents have changed, and they should repaint themselves. */
+    public void refresh() {
+	fireContentsChanged(this, 0, size());
+    }
+
+    public void setAutoOrder(boolean auto_order) {
+	this.auto_order = auto_order;
+    }
+
+    public void setSelectedItem(Object object) {
+	///ystem.err.println("Set item: " + object);
+	this.object = object;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Format.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Format.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Format.java	(revision 10506)
@@ -0,0 +1,349 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.util.Codec;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+
+/** This class encapsulates all the information about a format command from the collection configuration. This includes both the 'general' formatting commands, and the commands targetted at specific classifiers or classification component types. This class is, unfortunately, the most complex in terms of DOM model support, since we have to maintain a live reference to any classifier this format applies to. We temporarily use the feature name as the format name attribute but since the order of classifiers can change, this of course gets horribly out of date. Before the CollectionDesignManager saves the CollectionConfiguration it calls a method in the FormatManager to force all of the Formats to update their name attributes.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class Format 
+    implements DOMProxyListEntry {
+
+    /** The default features (not all of these are in the Greenstone Developer's Guide). */
+    static final public String DEFAULT_FEATURES[] = { "", "AllowExtendedOptions", "Document", "DocumentArrowsBottom", "DocumentArrowsTop", "DocumentButtons", "DocumentContents", "DocumentHeading", "DocumentImages", "DocumentText", "DocumentTitles", "DocumentUseHTML", "RelatedDocuments", "Search" };
+    /** The list of known feature parts. */
+    static final public String DEFAULT_PARTS[] = { "", "DateList", "HList", "VList" };
+
+    /** Only "" and "Search" can have parts */
+    static public boolean canHavePart(String name) {
+	return (name.equalsIgnoreCase("") || name.equalsIgnoreCase("Search") || name.equalsIgnoreCase("Document"));
+    }
+	
+    static public String generateName(Object feature, String part) {
+	if(feature instanceof Classifier) {
+	    return ((Classifier)feature).getPositionString() + part;
+	}
+	else {
+	    return feature.toString() + part;
+	}
+    }
+
+    /** Returns true if the parameter is a boolean type, false otherwise. */
+    static public boolean isParamType(String name)
+    {
+	if (name.equalsIgnoreCase("AllowExtendedOptions") || name.equalsIgnoreCase("DocumentArrowsBottom") || name.equalsIgnoreCase("DocumentArrowsTop") || name.equalsIgnoreCase("DocumentContents") || name.equalsIgnoreCase("DocumentImages") || name.equalsIgnoreCase("DocumentTitles") || name.equalsIgnoreCase("DocumentUseHTML")) {
+	    return true;
+	}
+	else {
+	    return false;
+	}
+    }
+
+    /** If this format is altering a Classifier then this is the classifier in question. */
+    private Classifier classifier = null;
+    /** The element this format is based on. */
+    private Element element = null;
+    /** We keep a copy of the part because its slightly more computationally tricky to calculate. */
+    private String part = null;
+    /** Cached result of toString. */
+    private String text = null;
+
+    /** Constructor only to be used during DOMProxyListModel initialization. */
+    public Format() {
+    }
+
+    public Format(Element element) {
+	this.element = element;
+	// Immediately check if we are dealing with a classifier, by retrieving the feature name. If it is a classifier, then restore the live reference immediately before anything changes it.
+	Object object = getFeature();
+
+	// There may be format statements for no-longer-existing classifiers
+	if (object == null) {
+	    DebugStream.println("No matching classifier for format statement!");
+	    return;
+	}
+
+	if(object instanceof Classifier) {
+	    classifier = (Classifier) object;
+	}
+	else {
+	    String feature = (String) object;
+	    if(feature.toUpperCase().startsWith(Classifier.CLASSIFIER_PREFIX)) {
+		// Extract the integer index
+		int index = Integer.parseInt(feature.substring(Classifier.CLASSIFIER_PREFIX.length()));
+		// Subtract one (as java is 0-2 where G2 is 1-3)
+		index = index - 1;
+		// Retrieve the appropriate classifier
+		classifier = CollectionDesignManager.classifier_manager.getClassifier(index);
+	    }
+	}
+    }
+
+    /** Constructor for a flag format command.
+     * @param feature The <Strong>Object</strong> this format affects.
+     * @param part The specific part of the control to format as a <strong>String</strong>.
+     * @param state A <i>boolean</i> indicating this formats state.
+     */
+    public Format(Object feature, String part, boolean state) {
+	element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.FORMAT_ELEMENT);
+	setName(feature, part);
+	setState(state);
+    }
+
+    /** Constructor for a format-string format command.
+     * @param feature The <Strong>Object</strong> this format affects.
+     * @param part The specific part of the control to format as a <strong>String</strong>.
+     * @param value The format <strong>String</strong> which may be a label name, or a piece of HTML formatting.
+     */
+    public Format(Object feature, String part, String value) {
+	element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.FORMAT_ELEMENT);
+	setName(feature, part);
+	setValue(value);
+    }
+
+    public boolean canHavePart() {
+	return canHavePart(getName());
+    }
+
+    public int compareTo(Object object) {
+	if(object == null) { // It seems that occasionally compareTo is called and somehow null ends up in comparison.
+	    return -1;
+	}
+	if(object instanceof Format && element != null) {
+	    return element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE).compareTo(((Format)object).getName());
+	}
+	return toString().compareTo(object.toString());
+    }
+
+    public DOMProxyListEntry create(Element element) {
+	return new Format(element);
+    }
+
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+
+    public Element getElement() {
+	return element;
+    }
+
+    /** Method to retrieve the value of feature, which may either be a String or a Classifier.
+     * @return The value of feature as an <strong>Object</strong>.
+     */
+    public Object getFeature() {
+	if(classifier != null) {
+	    return classifier;
+	}
+	else if(element != null) {
+	    String name = element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
+	    // Remove part
+	    String part = getPart();
+	    String feature;
+	    if(part != null) {
+		feature = name.substring(0, name.length() - part.length());
+	    }
+	    else {
+		feature = name;
+	    }
+	    part = null;
+	    name = null;
+	    // If the feature now refers to a classifier, retrieve it.
+	    if(feature.toUpperCase().startsWith(Classifier.CLASSIFIER_PREFIX)) {
+		// Extract the integer index
+		int index = Integer.parseInt(feature.substring(Classifier.CLASSIFIER_PREFIX.length()));
+		// Subtract one (as java is 0-2 where G2 is 1-3)
+		index = index - 1;
+		// Retrieve the appropriate classifier
+		classifier = CollectionDesignManager.classifier_manager.getClassifier(index);
+		return classifier;
+	    }
+	    else {
+		return feature;
+	    }
+	}
+	else {
+	    return "Error";
+	}
+    }
+
+    public String getName() {
+	if(element != null) {
+	    return element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
+	}
+	return "Error";
+    }
+
+    /** Method to retrieve the value of part. Of course there may not be one, in which case return ""
+     * @return The value of part as a <Strong>String</strong>.
+     */
+    public String getPart() {
+	if(part == null && element != null) {
+	    // To determine a part, we retrieve the Format name, then look for one of our recognized parts
+	    String name = element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
+	    // DEFAULT_PARTS[0] is an empty string to correctly enable comboboxes.
+	    name = name.toLowerCase();
+	    for(int i = 1; part == null && i < DEFAULT_PARTS.length; i++) {
+		if(name.endsWith(DEFAULT_PARTS[i].toLowerCase())) {
+		    part = DEFAULT_PARTS[i];
+		}
+	    }
+	    if(part == null) {
+		part = DEFAULT_PARTS[0];
+	    }
+	}
+	return part;
+    }
+
+    /** Method to retrieve the value of state.
+     * @return value of state as a <i>boolean</i>.
+     */
+    public boolean getState() {
+	return (element != null && element.getAttribute(CollectionConfiguration.VALUE_ATTRIBUTE).equals(CollectionConfiguration.TRUE_STR));
+    }
+
+    /** Retrieve the value of value.
+     * @return A <strong>String</strong> which is the value of value.
+     */
+    public String getValue() {
+	String value = "Error";
+	if(element != null) {
+	   value = XMLTools.getValue(element);
+	   // Decode into text
+	   value = Codec.transform(value, Codec.DOM_TO_TEXT);
+	}
+	return value;
+    }
+
+    public boolean isAssigned() {
+	return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
+    }
+
+    public boolean isParamType() {
+	return (element != null && element.getAttribute(CollectionConfiguration.VALUE_ATTRIBUTE).length() > 0);
+    }
+
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    public void setElement(Element element) {
+	this.element = element;
+	part = null;
+	text = null;
+	// Establish the classifier reference, if necessary
+	getFeature();
+    }
+
+    public void setName(Object feature, String part) {
+	// Can't do anything unless an element exists.
+	if(element != null) {
+	    this.part = part; // Easier for later on.
+	    if(feature instanceof Classifier) {
+		classifier = (Classifier) feature;
+		element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, classifier.getPositionString() + part);
+	    }
+	    else {
+		element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, feature.toString() + part);
+	    }
+	    text = null;
+	}
+    }
+
+    /** Set the value of state.
+     * @param state The new value for state as a <i>boolean</i>.
+     */
+    public void setState(boolean state) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.VALUE_ATTRIBUTE, (state ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	    text = null;
+	}
+    }
+
+    /** Set the value of value. Hmmm.
+     * @param value The new value from value as a <strong>String</strong>.
+     */
+    public void setValue(String value) {
+	if(element != null) {
+	    // Strip off any enclosing speech marks
+	    if(value.startsWith(CollectionConfiguration.SPEECH_CHARACTER) && value.startsWith(CollectionConfiguration.SPEECH_CHARACTER)) {
+		value = value.substring(1, value.length() - 1);
+	    }
+	    // Encode
+	    value = Codec.transform(value, Codec.TEXT_TO_DOM);
+	    // Store in DOM
+	    XMLTools.setValue(element, value);
+	    text = null;
+	}
+    }
+
+    /** Method to translate this classes information into a line of text as you would expect in the collection configuration file.
+     * @return A <strong>String</strong> containing the format command.
+     */
+    public String toString() {
+	if(text == null && element != null) {
+	    StringBuffer temp = new StringBuffer(CollectionConfiguration.FORMAT_STR);
+	    temp.append(" ");
+	    temp.append(element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE));
+	    temp.append(" ");
+	    String value = element.getAttribute(CollectionConfiguration.VALUE_ATTRIBUTE);
+	    if(value.length() > 0) {
+		temp.append(value);
+	    }
+	    else {
+		value = XMLTools.getValue(element);
+		if(value.equalsIgnoreCase(CollectionConfiguration.TRUE_STR) || value.equalsIgnoreCase(CollectionConfiguration.FALSE_STR)) {
+		    temp.append(value);
+		}
+		else {
+		    temp.append("\"");
+		    // Retrieve the DOM encoded value, decode and then append
+		    value = Codec.transform(value, Codec.DOM_TO_TEXT);
+		    temp.append(value);
+		    temp.append("\"");
+		}
+	    }
+	    text = temp.toString();
+	    temp = null;
+	}
+	return text;
+    }
+
+    public void update() {
+	if(classifier != null) {
+	    element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, classifier.getPositionString() + getPart());
+	    text = null;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/FormatManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/FormatManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/FormatManager.java	(revision 10506)
@@ -0,0 +1,1011 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.w3c.dom.*;
+
+/** This class maintains a list of format statements, and allows the addition and removal of these statements.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class FormatManager
+    extends DOMProxyListModel {
+
+    static final private String BLANK = "blank";
+    static final private String FLAG  = "flag";
+    static final private String VALUE = "value";
+
+    static final private String DATELIST = "DateList";
+    static final private String DATELIST_DEFAULT_FORMAT = "<td>[link][icon][/link]</td>\n<td>[highlight]{Or}{[dls.Title],[dc.Title],[ex.Title],Untitled}[/highlight]</td>\n<td>[ex.Date]</td>";
+    static final private String HLIST = "HList";
+    static final private String HLIST_DEFAULT_FORMAT = "[link][highlight][ex.Title][/highlight][/link]";
+    static final private String VLIST = "VList";
+    static final private String VLIST_DEFAULT_FORMAT = "<td valign=top>[link][icon][/link]</td>\n<td valign=top>[ex.srclink]{Or}{[ex.thumbicon],[ex.srcicon]}[ex./srclink]</td>\n<td valign=top>[highlight]\n{Or}{[dls.Title],[dc.Title],[ex.Title],Untitled}\n[/highlight]{If}{[ex.Source],<br><i>([ex.Source])</i>}</td>";
+    //    static final private String INVISIBLE = "Invisible";
+    //static final private String INVISIBLE_DEFAULT_FORMAT = "";
+
+    static final private String DOCUMENTHEADING = "DocumentHeading";
+    static final private String DOCUMENTHEADING_DEFAULT_FORMAT = "{Or}{[parent(Top):Title],[Title],untitled}<br>";
+
+    static final private String DOCUMENTTEXT = "DocumentText";
+    static final private String DOCUMENTTEXT_DEFAULT_FORMAT = "<center><table width=_pagewidth_><tr><td>[Text]</td></tr></table></center>";
+
+    static final private String DOCUMENTBUTTONS = "DocumentButtons";
+    static final private String DOCUMENTBUTTONS_DEFAULT_FORMAT = "Detach|Highlight";
+    
+    /** The controls used to edit the format commands. */
+    private Control controls = null;
+    /** A reference to ourselves so inner classes can get at the model. */
+    private DOMProxyListModel model = null;
+
+    /** Constructor. */
+    public FormatManager() {
+	super(CollectionDesignManager.collect_config.getDocumentElement(), CollectionConfiguration.FORMAT_ELEMENT, new Format());
+	this.model = this;
+	DebugStream.println("FormatManager: parsed " + getSize() + " format statements.");
+	// Establish all of the format objects, so that classifier indexes are initially correct (subsequent refreshes of the model will be sufficient to keep these up to date, as long as we start with a live reference to a classifier.
+	int size = getSize();
+	for(int i = 0; i < size; i++) {
+	    getElementAt(i);
+	}
+
+	// Ensure the default formats for DateList, HList and VList are assigned
+	if (getFormat(DATELIST) == null) {
+	    addFormat(new Format("",DATELIST,DATELIST_DEFAULT_FORMAT));
+	}
+
+	if (getFormat(HLIST) == null) {
+	    addFormat(new Format("",HLIST,HLIST_DEFAULT_FORMAT));
+	}
+
+	if (getFormat(VLIST) == null) {
+	    addFormat(new Format("",VLIST,VLIST_DEFAULT_FORMAT));
+	}
+
+	if (getFormat(DOCUMENTHEADING) == null) {
+	    addFormat(new Format(DOCUMENTHEADING, "", DOCUMENTHEADING_DEFAULT_FORMAT));
+	}
+	if (getFormat(DOCUMENTTEXT) == null) {
+	    addFormat(new Format(DOCUMENTTEXT,"",DOCUMENTTEXT_DEFAULT_FORMAT));
+	}
+	if (getFormat(DOCUMENTBUTTONS) == null) {
+	    addFormat(new Format(DOCUMENTBUTTONS,"",DOCUMENTBUTTONS_DEFAULT_FORMAT));
+	}
+	
+    }
+
+    /** Method to add a new format to this manager.
+     * @param format The <strong>Format</strong> to add.
+     */
+    private void addFormat(Format format) {
+	if(!contains(format)) {
+	    Element element = format.getElement();
+	    // Locate where we should insert this new classifier. 
+	    Node target_node = CollectionConfiguration.findInsertionPoint(element);
+	    add(root, format, target_node);
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+
+    public void destroy() {
+	if(controls != null) {
+	    controls.destroy();
+	    controls = null;
+	}
+    }
+
+    /** Gets the format indicated by the index.
+     * @param index The location of the desired format, as an <i>int</i>.
+     */
+    private Format getFormat(int index) {
+	Format result = null;
+	if(0 < index && index < getSize()) {
+	    result = (Format) getElementAt(index);
+	}
+	return result;
+    }
+
+    private Format getFormat(String name) {
+	int model_size = getSize();
+	for(int index = 0; index < model_size; index++) {
+	    Format format = (Format) getElementAt(index);
+	    if(format.getName().equals(name)) {
+		return format;
+	    }
+	}
+	return null;
+    }
+    
+    /** Method to retrieve this managers controls.
+     * @return the Control for this collection.
+     */
+    public Control getControls() {
+	if(controls == null) {
+	    controls = new FormatControl();
+	}
+	return controls;
+    }
+
+    /** updates the format model */
+    public synchronized void refresh() {
+	for(int i = 0; i < getSize(); i++) {
+	    Format format = (Format) getElementAt(i);
+	    format.update();
+	    format = null;
+	}
+	super.refresh();
+    }
+    /** Method to remove a format.
+     * @param format The <strong>Format</strong> to remove.
+     */
+    private void removeFormat(Format format) {
+	remove(format);
+	Gatherer.c_man.configurationChanged();
+    }
+
+    private HashMap buildDefaultMappings(ArrayList features_model, ArrayList parts_model) {
+	DebugStream.println("buildDefaultMappings(): replace me with something that reads in a data xml file.");
+	return new HashMap();
+    }
+
+    private ArrayList buildFeatureModel() {
+	// Rebuild feature model.
+	ArrayList feature_model = new ArrayList();
+	// Add the set options
+	for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
+	    feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
+	}
+	// Now the classifiers.
+	for(int j = 0; j < CollectionDesignManager.classifier_manager.getSize(); j++) {
+	    feature_model.add(new Entry(CollectionDesignManager.classifier_manager.getClassifier(j)));
+	}
+	Collections.sort(feature_model);
+	return feature_model;
+    }
+
+    private ArrayList buildPartModel() {
+	DebugStream.println("buildPartModel(): replace me with something that reads in a data xml file.");
+	ArrayList part_model = new ArrayList();
+	part_model.add(new Part("", ""));
+	part_model.add(new Part(DATELIST, DATELIST_DEFAULT_FORMAT));
+	part_model.add(new Part(HLIST, HLIST_DEFAULT_FORMAT));
+	//part_model.add(new Part(INVISIBLE, INVISIBLE_DEFAULT_FORMAT));
+	part_model.add(new Part(VLIST, VLIST_DEFAULT_FORMAT));
+	return part_model;
+    }
+
+    private ArrayList buildVariableModel() {
+	DebugStream.println("buildVariableModel(): replace me with something that reads in a data xml file.");
+	ArrayList variable_model = new ArrayList();
+	variable_model.add("[Text]");
+	ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+	for (int i = 0; i < every_metadata_set_element.size(); i++) {
+	    variable_model.add("[" + ((MetadataElement) every_metadata_set_element.get(i)).getFullName() + "]");
+	}
+	variable_model.add("[link]");
+	variable_model.add("[/link]");
+	variable_model.add("[icon]");
+	variable_model.add("[numleafdocs]");
+	variable_model.add("[num]");
+	variable_model.add("[parent():_]");
+	variable_model.add("[parent(Top):_]");
+	variable_model.add("[parent(All'_'):_]");
+	return variable_model;
+    }
+
+    private class FormatControl
+	extends JPanel 
+	implements Control {
+	
+	private ArrayList feature_model;
+	private ArrayList part_model;
+	private ArrayList variable_model;
+	private boolean ignore_event = false;
+	private boolean ready = false; // Are these controls available to be refreshed
+	private CardLayout card_layout;
+	private HashMap default_mappings;
+	private JButton add_button;
+	private JButton insert_button;
+	private JButton remove_button;
+	private JButton replace_button;
+	private JCheckBox enabled_checkbox;
+	private JComboBox feature_combobox;
+	private JComboBox part_combobox;
+	private JComboBox variable_combobox;
+	private JList format_list;
+	private JTextArea instructions_textarea;
+	private JTextArea editor_textarea;
+	private JPanel blank_pane;
+	private JPanel control_pane;
+	private JPanel part_pane;
+	private JPanel selection_pane;
+	private String view_type;
+
+	private final Dimension FIELD_SIZE = new Dimension(200, 30);
+	public FormatControl() {
+	    feature_model = buildFeatureModel();
+	    part_model = buildPartModel();
+	    variable_model = buildVariableModel();
+	    default_mappings = buildDefaultMappings(feature_model, part_model);
+
+	    // Create
+	    JPanel instructions_pane = new JPanel();
+	    JLabel title_label = new JLabel();
+	    title_label.setHorizontalAlignment(JLabel.CENTER);
+	    title_label.setOpaque(true);
+	    Dictionary.registerText(title_label, "CDM.FormatManager.Title");
+
+	    instructions_textarea = new JTextArea();
+	    instructions_textarea.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    instructions_textarea.setEditable(false);
+	    instructions_textarea.setLineWrap(true);
+	    instructions_textarea.setRows(6);
+	    instructions_textarea.setWrapStyleWord(true);
+	    Dictionary.registerText(instructions_textarea, "CDM.FormatManager.Instructions");
+
+	    JLabel format_label = new JLabel();
+	    Dictionary.registerText(format_label, "CDM.FormatManager.Assigned_Formats");
+	    format_list = new JList(model);
+
+	    selection_pane = new JPanel();
+	    JPanel feature_pane = new JPanel();
+	    JLabel feature_label = new JLabel();
+	    Dictionary.registerText(feature_label, "CDM.FormatManager.Feature");
+	    feature_combobox = new JComboBox(feature_model.toArray());
+	    feature_combobox.setPreferredSize(FIELD_SIZE);
+	    feature_combobox.setEditable(false);
+	    Dictionary.registerTooltip(feature_combobox, "CDM.FormatManager.Feature_Tooltip");
+
+	    part_pane = new JPanel();
+	    JLabel part_label = new JLabel();
+	    Dictionary.registerText(part_label, "CDM.FormatManager.Part");
+
+	    part_combobox = new JComboBox(part_model.toArray());
+	    part_combobox.setPreferredSize(FIELD_SIZE);
+	    part_combobox.setEditable(false);
+	    Dictionary.registerTooltip(part_combobox, "CDM.FormatManager.Part_Tooltip");
+
+	    blank_pane = new JPanel();
+	    
+	    JPanel center_pane = new JPanel();
+
+	    card_layout = new CardLayout();
+	    control_pane = new JPanel();
+
+	    JPanel blank_pane = new JPanel();
+
+	    JPanel editor_pane = new JPanel();
+	    JPanel editor_header_pane = new JPanel();
+	    JLabel editor_label = new JLabel();
+	    Dictionary.registerText(editor_label, "CDM.FormatManager.Editor");
+
+	    editor_textarea = new JTextArea();
+	    editor_textarea.setBackground(Configuration.getColor("coloring.editable_background", false));
+	    editor_textarea.setCaretPosition(0);
+	    editor_textarea.setLineWrap(true);
+	    editor_textarea.setRows(6);
+	    editor_textarea.setWrapStyleWord(false);
+	    Dictionary.registerTooltip(editor_textarea, "CDM.FormatManager.Editor_Tooltip");
+
+	    JPanel variable_pane = new JPanel();
+	    JLabel variable_label = new JLabel();
+	    Dictionary.registerText(variable_label, "CDM.FormatManager.Variable");
+	    variable_combobox = new JComboBox(variable_model.toArray());
+	    Dictionary.registerTooltip(variable_combobox, "CDM.FormatManager.Variable_Tooltip");
+
+	    insert_button = new GLIButton();
+	    insert_button.setMnemonic(KeyEvent.VK_I);
+	    Dictionary.registerBoth(insert_button, "CDM.FormatManager.Insert", "CDM.FormatManager.Insert_Tooltip");
+
+	    JPanel flag_pane = new JPanel();
+	    enabled_checkbox = new JCheckBox();
+	    Dictionary.registerText(enabled_checkbox, "CDM.FormatManager.Enabled");
+
+	    JPanel button_pane = new JPanel();
+	    add_button = new GLIButton();
+	    add_button.setEnabled(false);
+	    add_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add_button, "CDM.FormatManager.Add", "CDM.FormatManager.Add_Tooltip");
+	    replace_button = new GLIButton();
+	    replace_button.setEnabled(false);
+	    replace_button.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.registerBoth(replace_button, "CDM.FormatManager.Replace", "CDM.FormatManager.Replace_Tooltip");
+	    remove_button = new GLIButton();
+	    remove_button.setEnabled(false);
+	    remove_button.setMnemonic(KeyEvent.VK_R);
+	    Dictionary.registerBoth(remove_button, "CDM.FormatManager.Remove", "CDM.FormatManager.Remove_Tooltip");
+
+	    // Connect
+	    add_button.addActionListener(new AddListener());
+	    add_button.addActionListener(CollectionDesignManager.collect_cfg_change_listener);
+	    insert_button.addActionListener(new InsertListener());
+	    insert_button.addActionListener(CollectionDesignManager.collect_cfg_change_listener);
+	    remove_button.addActionListener(new RemoveListener());
+	    remove_button.addActionListener(CollectionDesignManager.collect_cfg_change_listener);
+	    replace_button.addActionListener(new ReplaceListener());
+	    replace_button.addActionListener(CollectionDesignManager.collect_cfg_change_listener);
+	    enabled_checkbox.addActionListener(new EnabledListener());
+	    enabled_checkbox.addActionListener(CollectionDesignManager.collect_cfg_change_listener);
+	    feature_combobox.addActionListener(new FeatureListener());
+	    part_combobox.addActionListener(new PartListener());
+	    editor_textarea.getDocument().addDocumentListener(new EditorListener());
+	    format_list.addListSelectionListener(new FormatListListener());
+
+	    // Layout
+	    instructions_pane.setLayout(new BorderLayout());
+	    instructions_pane.add(title_label, BorderLayout.NORTH);
+	    instructions_pane.add(new JScrollPane(instructions_textarea), BorderLayout.CENTER);
+	    instructions_pane.add(format_label, BorderLayout.SOUTH);
+
+	    feature_pane.setLayout(new BorderLayout(5,0));
+	    feature_pane.add(feature_label, BorderLayout.WEST);
+	    feature_pane.add(feature_combobox, BorderLayout.CENTER);
+
+	    part_pane.setLayout(new BorderLayout(5, 0));
+	    part_pane.add(part_label, BorderLayout.WEST);
+	    part_pane.add(part_combobox, BorderLayout.CENTER);
+
+	    //selection_pane.setLayout(new GridLayout(2,1,0,2));
+	    //selection_pane.add(feature_pane);
+	    //selection_pane.add(part_pane);
+
+	    flag_pane.add(enabled_checkbox);
+
+	    editor_header_pane.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
+	    editor_header_pane.setLayout(new GridLayout(1,3));
+	    editor_header_pane.add(editor_label);
+
+	    variable_pane.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
+	    variable_pane.setLayout(new GridLayout(1,3));
+	    variable_pane.add(variable_label);
+	    variable_pane.add(variable_combobox);
+	    variable_pane.add(insert_button);
+
+	    editor_pane.setLayout(new BorderLayout());
+	    editor_pane.add(editor_header_pane, BorderLayout.NORTH);
+	    editor_pane.add(new JScrollPane(editor_textarea), BorderLayout.CENTER);
+	    //editor_pane.add(variable_pane, BorderLayout.SOUTH);
+
+	    selection_pane.setLayout(new BorderLayout());
+	    selection_pane.add(part_pane, BorderLayout.NORTH);
+	    selection_pane.add(editor_pane, BorderLayout.CENTER);
+	    selection_pane.add(variable_pane, BorderLayout.SOUTH);
+
+	    control_pane.setLayout(card_layout);
+	    control_pane.add(flag_pane, FLAG);
+	    control_pane.add(selection_pane, VALUE);
+	    control_pane.add(blank_pane, BLANK);
+
+	    button_pane.setLayout(new GridLayout(1,3));
+	    button_pane.add(add_button);
+	    button_pane.add(replace_button);
+	    button_pane.add(remove_button);
+
+	    center_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(Dictionary.get("CDM.FormatManager.Editing_Controls")), BorderFactory.createEmptyBorder(2,2,2,2)));
+	    center_pane.setLayout(new BorderLayout());
+	    center_pane.add(feature_pane, BorderLayout.NORTH);
+	    center_pane.add(control_pane, BorderLayout.CENTER);
+	    center_pane.add(button_pane, BorderLayout.SOUTH);
+
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    add(instructions_pane, BorderLayout.NORTH);
+	    add(new JScrollPane(format_list), BorderLayout.CENTER);
+	    add(center_pane, BorderLayout.SOUTH);
+	    ready = true;
+	}
+
+	public void destroy() {
+	}
+       
+	/** Overriden to ensure that the instructions pane is scrolled to the top.
+	 */
+	public void gainFocus() {
+	    // This is only necessary if the components have been realized
+	    if(ready) {
+		model.refresh();
+		feature_model = buildFeatureModel();
+		// Remember the current selection
+		Object selected_object = feature_combobox.getSelectedItem();
+		feature_combobox.setModel(new DefaultComboBoxModel(feature_model.toArray()));
+		// Now restore the selected object as best as possible
+		feature_combobox.setSelectedItem(selected_object);
+		selected_object = null;
+		if(instructions_textarea != null) {
+		    instructions_textarea.setCaretPosition(0);
+		}
+	    }   
+	}
+
+	public void loseFocus() {
+	    // Force all of the Formats to update their names with the correct values.
+	    // do we need to do this on loseFocus???
+	    model.refresh();
+	}
+
+	/** Listens for clicks on the add button, and if the relevant details are provided adds a new format. Note that formats are responsible for codecing the values into something that can be a) stored in a DOM and b) written to file */
+	private class AddListener
+	    implements ActionListener {
+
+	    public void actionPerformed(ActionEvent event)
+	    {
+		ignore_event = true; // Prevent format_list excetera propagating events
+
+		Entry entry = (Entry) feature_combobox.getSelectedItem();
+		Object f = entry.getFeature();
+		String p = "";
+		if (entry.canHavePart()) {
+		    p = part_combobox.getSelectedItem().toString();
+		}
+
+		// Add a new format string of the appropriate type
+		Format format = null;
+		if (view_type.equals(FLAG)) {
+		    format = new Format(f, p, enabled_checkbox.isSelected());
+		}
+		else {
+		    format = new Format(f, p, editor_textarea.getText());
+		}
+		addFormat(format);
+
+		// Save the collection configuration file immediately
+		Gatherer.g_man.design_pane.saveConfiguration();
+
+		add_button.setEnabled(false);
+		replace_button.setEnabled(false);
+		remove_button.setEnabled(true);
+
+		// Update list selection
+		format_list.setSelectedValue(format, true);
+		format = null;
+		p = null;
+		f = null;
+		entry = null;
+		ignore_event = false;
+	    }
+	}
+    
+	private class EditorListener
+	    implements DocumentListener {
+ 
+	    public void changedUpdate(DocumentEvent e) {
+		update();
+	    }
+          
+	    public void insertUpdate(DocumentEvent e) {
+		update();
+	    }
+          
+	    public void removeUpdate(DocumentEvent e) {
+		update();
+	    }
+
+	    public void update() {
+		// Determine if replace should be enabled
+		if(!format_list.isSelectionEmpty()) {
+		    Format format = (Format)format_list.getSelectedValue();
+		    replace_button.setEnabled(!format.isParamType() && editor_textarea.getText() != format.getValue());
+		}
+		else {
+		    replace_button.setEnabled(false);
+		}
+	    }
+	}
+
+	private class EnabledListener
+	    implements ActionListener {
+	    
+	    public void actionPerformed(ActionEvent event) {
+		// If there is a current format selected, and the value of enable_checkbox is now different than to value in it, then enable to replace button.
+		if(!format_list.isSelectionEmpty()) {
+		    Format format = (Format)format_list.getSelectedValue();
+		    replace_button.setEnabled(format.isParamType() && enabled_checkbox.isSelected() != format.getState());
+		}
+		// Thats it. Add would have been enabled upon feature/part selection depending if no existing format, um, existed.
+	    }
+	}
+
+	private class FeatureListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		if(!ignore_event) {
+		    ignore_event = true;
+		    Entry entry = (Entry) feature_combobox.getSelectedItem();
+		    // Step one: reset part
+		    if (entry.canHavePart()) {
+			part_combobox.setEnabled(true);
+			part_combobox.setSelectedIndex(part_combobox.getModel().getSize()-1);
+
+		    } else {
+			part_combobox.setEnabled(false);
+			part_combobox.setSelectedIndex(0);
+		    }
+		    // Step two: the rest
+		    
+		    String name = entry.toString();
+		    // Add is only enabled if there isn't already a format for the choosen feature and part. Create a dummy format and test if itsa already in the model
+		    Object f = entry.getFeature();
+		    Part part = (Part)part_combobox.getSelectedItem();
+		    String pname = part.getName();
+		    // You can never add anything to blank-blank
+		    if(f.toString().length() == 0 && pname.length() == 0) {
+			add_button.setEnabled(false);
+			replace_button.setEnabled(false);
+			remove_button.setEnabled(false);
+		    }
+		    else {
+		       Format format = getFormat(Format.generateName(f, pname));
+		       // If there is an existing feature, select it, and use it to determine what controls are visible
+		       if(format != null) {
+			  ///ystem.err.println("There is an existing format!");
+			    format_list.setSelectedValue(format, true);
+			    // Now use type to determine what controls are visible, and what have initial values.
+			    if(format.isParamType()) {
+			       ///ystem.err.println("Flag type");
+				// Flags first.
+				///election_pane.remove(part_pane);
+				card_layout.show(control_pane, FLAG);
+				view_type = FLAG;
+				// Initial value
+				enabled_checkbox.setSelected(format.getState());
+			    }
+			    else {
+				///ystem.err.println("Value type");
+				///election_pane.add(part_pane);
+				card_layout.show(control_pane, VALUE);
+				view_type = VALUE;
+				// Initial value
+				editor_textarea.setText(format.getValue());
+			    }
+			    control_pane.updateUI();
+			    remove_button.setEnabled(true);
+		       }
+		       // Otherwise there is no existing format, so we proceed by checking against the feature name
+			else {
+			   ///ystem.err.println("No existing format");
+			    format_list.clearSelection();
+			    if(Format.isParamType(name)) {
+			       ///ystem.err.println("Flag type");
+				// Flags first.
+				///election_pane.remove(part_pane);
+				card_layout.show(control_pane, FLAG);
+				view_type = FLAG;
+				// Initial value
+				enabled_checkbox.setSelected(false);
+			    }
+			    else {
+			       ///ystem.err.println("Value type");
+				///election_pane.add(part_pane);
+				card_layout.show(control_pane, VALUE);
+				view_type = VALUE;
+				// Initial value
+				editor_textarea.setText(part.getDefaultFormat());
+			    }
+			    add_button.setEnabled(true);
+			}
+			format = null;
+			name = null;
+		    }
+		    part = null;
+		    pname = null;
+		    f = null;
+		    replace_button.setEnabled(false);
+		    name = null;
+		    entry = null;
+		    ignore_event = false;
+		}
+	    }
+	}
+
+	private class FormatListListener
+	    implements ListSelectionListener {
+	    public void valueChanged(ListSelectionEvent event) {
+		if(!ignore_event && !event.getValueIsAdjusting()) {
+		    if(!format_list.isSelectionEmpty()) {
+			ignore_event = true;
+			Format format = (Format)format_list.getSelectedValue();
+			// Try to match the target, remembering the entries within are Entry's
+			Entry an_entry = new Entry(format.getFeature());
+			feature_combobox.setSelectedItem(an_entry);
+			// If we didn't match anything, add it and select it again
+			Entry result_entry = (Entry) feature_combobox.getSelectedItem();
+			if(!an_entry.equals(result_entry)) {
+			    feature_combobox.insertItemAt(an_entry, feature_combobox.getItemCount());
+			    feature_combobox.setSelectedItem(an_entry);
+			}
+
+			// Now use type to determine what controls are visible, and what have initial values.
+			///ystem.err.println("Determine the correct type.");
+			if(format.isParamType()) {
+			    ///ystem.err.println("Flag type - remove part");
+			    // Flags first.
+			    ///SwingUtilities.invokeLater(new GUIChangeTask(/election_pane, part_pane, blank_pane, false));
+			   card_layout.show(control_pane, FLAG);
+			   view_type = FLAG;
+			   // Initial value
+			   enabled_checkbox.setSelected(format.getState());
+			}
+			else {
+			   ///ystem.err.println("Value type - show part");
+			    ///SwingUtilities.invokeLater(new GUIChangeTask(/election_pane, part_pane, blank_pane, true));
+			   card_layout.show(control_pane, VALUE);
+			   view_type = VALUE;
+			   // Initial values
+			   
+			   // Try to match the part.
+			   String part_entry = format.getPart();
+			   // Set Selected Item doesn't work so I'll do this manually
+			   boolean found = false;
+			   for(int i=0; i < part_combobox.getItemCount(); i++) {
+			      Part a_part = (Part) part_combobox.getItemAt(i);
+			      if(a_part.equals(part_entry)) {
+				 part_combobox.setSelectedItem(a_part);
+				 found = true;
+			      }
+			      a_part = null;
+			   }
+			   // If we didn't match anything, add it and select it again
+			   if(!found) {
+			      Part a_part = new Part(part_entry, "");
+			      part_combobox.insertItemAt(a_part, part_combobox.getItemCount());
+			      part_combobox.setSelectedItem(a_part);
+			   }
+			   
+			   editor_textarea.setText(format.getValue());
+			}
+			//control_pane.updateUI();
+			remove_button.setEnabled(true);
+			ignore_event = false;
+		    }
+		    else {
+			remove_button.setEnabled(false);
+		    }
+		    add_button.setEnabled(false);
+		    replace_button.setEnabled(false);
+		}
+	    }
+	}
+
+	private class InsertListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		editor_textarea.insert((String)variable_combobox.getSelectedItem(), editor_textarea.getCaretPosition());
+	    }
+	}
+       
+	private class PartListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		if(!ignore_event) {
+		    // Add is only enabled if there isn't already a format for the choosen feature and part. Create a dummy format and test if its already in the model
+		    Entry entry = (Entry) feature_combobox.getSelectedItem();
+		    Object f = entry.getFeature();
+		    Part part = (Part) part_combobox.getSelectedItem();
+		    String pname = part.getName();
+		    // You can never add anything to blank-blank
+		    if(f.toString().length() == 0 && pname.length() == 0) {
+			add_button.setEnabled(false);
+			replace_button.setEnabled(false);
+			remove_button.setEnabled(false);
+		    }
+		    else {
+			String name = Format.generateName(f, pname);
+			Format format = getFormat(name);
+			// If there is an existing feature, select it.
+			if(format != null) {
+			    format_list.setSelectedValue(format, true);
+			    // Now use type to determine what controls are visible, and what have initial values.
+			    if(format.isParamType()) {
+				// Flags first.
+				///election_pane.remove(part_pane);
+				card_layout.show(control_pane, FLAG);
+				view_type = FLAG;
+				// Initial value
+				enabled_checkbox.setSelected(format.getState());
+			    }
+			    else {
+				///election_pane.add(part_pane);
+				card_layout.show(control_pane, VALUE);
+				view_type = VALUE;
+				// Initial value
+				editor_textarea.setText(format.getValue());
+			    }
+			    control_pane.updateUI();
+			    remove_button.setEnabled(true);
+			}
+			else {
+			    format_list.clearSelection();
+			    if(Format.isParamType(name)) {
+				// Flags first.
+				///election_pane.remove(part_pane);
+				card_layout.show(control_pane, FLAG);
+				view_type = FLAG;
+				// Initial value
+				enabled_checkbox.setSelected(false);
+			    }
+			    else {
+				///election_pane.add(part_pane);
+				card_layout.show(control_pane, VALUE);
+				view_type = VALUE;
+				// Initial value
+				editor_textarea.setText(part.getDefaultFormat());
+			    }
+			    add_button.setEnabled(true);
+			}
+			format = null;
+			name = null;
+		    }
+		    
+		    pname = null;
+		    part = null;
+		    f = null;
+		    entry = null;
+		    replace_button.setEnabled(false);
+		}
+	    }
+	}
+
+	private class RemoveListener
+	    implements ActionListener {
+
+	    public void actionPerformed(ActionEvent event)
+	    {
+		if (!format_list.isSelectionEmpty()) {
+		    // Remove the current format
+		    removeFormat((Format)format_list.getSelectedValue());
+
+		    // Save the collection configuration file immediately
+		    Gatherer.g_man.design_pane.saveConfiguration();
+
+		    // Change buttons
+		    add_button.setEnabled(true);
+		    replace_button.setEnabled(false);
+		}
+
+		remove_button.setEnabled(false);
+	    }
+	}
+
+	private class ReplaceListener
+	    implements ActionListener {
+
+	    public void actionPerformed(ActionEvent event)
+	    {
+		ignore_event = true; // Prevent format_list excetera propagating events
+
+		if (!format_list.isSelectionEmpty()) {
+		    // Remove the current format
+		    removeFormat((Format) format_list.getSelectedValue());
+
+		    Entry entry = (Entry) feature_combobox.getSelectedItem();
+		    Object f = entry.getFeature();
+		    String p = "";
+		    if (entry.canHavePart()) {
+			p = part_combobox.getSelectedItem().toString();
+		    }
+
+		    // Add a new format string of the appropriate type
+		    Format format = null;
+		    if (view_type.equals(FLAG)) {
+			format = new Format(f, p, enabled_checkbox.isSelected());
+		    }
+		    else {
+			format = new Format(f, p, editor_textarea.getText());
+		    }
+		    addFormat(format);
+
+		    // Save the collection configuration file immediately
+		    Gatherer.g_man.design_pane.saveConfiguration();
+
+		    add_button.setEnabled(false);
+		    remove_button.setEnabled(true);
+		    // Update list selection
+		    format_list.setSelectedValue(format, true);
+		    format = null;
+		    p = null;
+		    f = null;
+		    entry = null;
+		}
+
+		replace_button.setEnabled(false);
+		ignore_event = false;
+	    }
+	}
+    }
+
+    /** This object provides a wrapping around an entry in the format target control, which is tranparent as to whether it is backed by a String or a Classifier. */
+    private class Entry
+	implements Comparable {
+	private Classifier classifier = null;
+	private String text = null;
+	
+	public Entry(Object object) {
+	    if(object instanceof Classifier) {
+		classifier = (Classifier)object;
+	    }
+	    else if(object instanceof String) {
+		text = (String)object;
+	    }
+	    else {
+		text = "";
+	    }
+	}
+	
+	public Entry(String text) {
+	    this.text = text;
+	}
+	
+	public boolean canHavePart() {
+	    if (classifier !=null) return true;
+	    return Format.canHavePart(text);
+	}
+
+	public int compareTo(Object object) {
+	    if(object == null) {
+		return 1;
+	    }
+	    if(toString() == null) {
+		return -1;
+	    }
+	    else {
+		String object_str = object.toString();
+		if(object_str == null) {
+		    return 1;
+		}
+		return toString().compareTo(object_str);
+	    }
+	}
+	
+	public boolean equals(Object object) {
+	    if(compareTo(object) == 0) {
+		return true;
+	    }
+	    return false;
+	}
+	
+	public Classifier getClassifier() {
+	    return classifier;
+	}
+	
+	public Object getFeature() {
+	    if(classifier != null) {
+		return classifier;
+	    }
+	    return text;
+	}
+	
+	public String toString() {
+	    if(classifier != null) {
+		// Return the classifier - less the 'classify ' prefix and with its CL index shown
+		return classifier.getPositionString() + StaticStrings.COLON_CHARACTER + StaticStrings.SPACE_CHARACTER + classifier.toString().substring(9);
+	    }
+	    return text;
+	}
+    }
+
+    /*
+      private class GUIChangeTask
+      implements Runnable {
+      private boolean to_add;
+      private JPanel child;
+      private JPanel parent;
+      private JPanel replacement;
+      
+      public GUIChangeTask(JPanel parent, JPanel child, JPanel replacement, boolean to_add) {
+      this.child = child;
+      this.parent = parent;
+      this.replacement = replacement;
+      this.to_add = to_add;
+      }
+      
+      public void run() {
+      if(to_add) {
+      parent.remove(replacement);
+      parent.add(child);
+      parent.updateUI();
+      }
+      else {
+      parent.remove(child);
+      parent.add(replacement);
+      parent.updateUI();
+      }
+      }
+      }
+    */
+
+   /** This class encapsulates all of the information associated with a certain component part of a feature within a html page returned from the receptioninst. */
+   private class Part
+      implements Comparable {
+      /** The default format string for this part */
+      private String default_format = null;
+      /** The name of this part */
+      private String name = null;
+      /** Constructor - must be provided with all of the details of a part as there are no other setter methods.
+       * @param name the name of this part
+       * @param default_format the default format string for this part
+       */
+      public Part(String name, String default_format) {
+	 this.default_format = default_format;
+	 this.name = name;
+      }
+      /** Compare this part to another object in terms of ordering
+       * @param obj the other Object
+       * @return <0 if the object is before, 0 if equal to, and >0 if the object is after this part
+       */
+      public int compareTo(Object obj) {
+	 return name.compareTo(obj.toString());
+      }
+      
+      /** Determine if the part is equivelent to some other object
+       * @param obj the other Object
+       * @return true is the two objects are equal
+       */
+      public boolean equals(Object obj) {
+	 return name.equals(obj.toString());
+      }
+      
+      /** Retrieve the default format string for this part
+       * @return the default format String
+       */
+      public String getDefaultFormat() {
+	 // Retrieve the format for the super format - either VList or HList
+	 Format default_format_object = getFormat(name);
+	 if(default_format_object != null) {
+	    return default_format_object.getValue();
+	 }
+	 else {
+	    return this.default_format;
+	 }
+      }
+      /** Retrieve the name of this part
+       * @return the name as a String
+       */
+      public String getName() {
+	 return name;
+      }
+      /** Produce a string representation of this part, which in this case is simply the name again
+       * @return the name as a String
+       */
+      public String toString() {
+	 return name;
+      }
+   }  
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/GeneralManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/GeneralManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/GeneralManager.java	(revision 10506)
@@ -0,0 +1,707 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.regex.*;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.EmailField;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.gui.NewCollectionDetailsPrompt;
+import org.greenstone.gatherer.gui.OpenCollectionDialog;
+import org.greenstone.gatherer.gui.WarningDialog;
+import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
+import org.greenstone.gatherer.util.StaticStrings;
+
+/** This class is responsible for generating the necessary GUI components. It does this by calling the getEditControls() method of the appropriate class (i.e. IndexManager for index related edits). It also is in charge of correctly adding (and removing) listeners, using phrases from the <strong>Dictionary</strong> rather than the text keys inserted in the component classes, and several other aspects of the design page, including the config file section tree.
+* @author John Thompson, Greenstone Digital Library, University of Waikato
+* @version 2.3d
+*/
+public class GeneralManager
+    extends JPanel {
+    /** The available subscreens. */
+    static final private String CONTENTS[] = { "CDM.GUI.General", "CDM.GUI.Plugins", "CDM.GUI.SearchTypes", "CDM.GUI.Indexes", "CDM.GUI.Subcollections", "CDM.GUI.SuperCollection", "CDM.GUI.Classifiers", "CDM.GUI.Formats", "CDM.GUI.Translation",  "CDM.GUI.MetadataSets" };
+    /** The preferred size of the contents tree. */
+    static final private Dimension TREE_SIZE = new Dimension(200, 500);
+    /** The controls used to modify the general options. */
+    private Control controls;
+    /** The panel apon which is rendered the currently selected section screen. */
+    private Control view = null;
+    /** A tree to serve as a 'table of contents' for this design tool. We decided on a tree rather than a list, as it allows us to break sections into subsections if they become to complicated. */
+    private DesignTree tree;
+    /** Constructor. */
+    public GeneralManager() {
+	super();
+	DebugStream.println("GeneralManager: Main GUI components created.");
+	// Assignments
+	this.controls = new GeneralControl();
+
+	// Creation
+	JPanel tree_pane = new JPanel();
+	JLabel title = new JLabel();
+	Dictionary.registerText(title, "CDM.GUI.Design_Topics");
+	tree = new DesignTree();
+	view = controls;
+
+	// Connect
+	tree.addTreeSelectionListener(new TreeListener());
+
+	// Layout
+	tree_pane.setLayout(new BorderLayout());
+	tree_pane.setPreferredSize(TREE_SIZE);
+	tree_pane.add(title, BorderLayout.NORTH);
+	tree_pane.add(new JScrollPane(tree), BorderLayout.CENTER);
+
+	setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
+	setLayout(new BorderLayout());
+	add(tree_pane, BorderLayout.WEST);
+	add((JPanel)view, BorderLayout.CENTER);
+    }
+
+    public boolean canSave() {
+	return (controls == null || ((GeneralControl)controls).canSave());
+    }
+
+    /** Destructor. */
+    public void destroy() {
+	controls.destroy();
+	controls = null;
+	tree = null;
+	view = null;
+    }
+
+    /** Called whenever the detail mode changes to ensure the contents tree is at an appropriate level (ie with Partitions disabled in lower levels)
+     * Written 1543-07-01-2004, and made obsolete by a new list of requirements 1611-07-01-2004. *sigh* 
+     * @param mode the mode level as an int
+     */
+    /* public void modeChanged(int mode) {
+	tree.resetModel(mode);
+    } */
+
+    /** Force the display to show a certain pane of controls.
+     * @param type a String giving the name of the information manager or view we wish to display
+     */
+    public void setSelectedView(String type) {
+	tree.setSelectedView(type);
+    }
+
+    /** Refresh the values on our controls that could be stale due to changes in other components. */
+    public void gainFocus() {
+	if (view != null) {
+	    view.gainFocus();
+	}
+    }
+
+    /** Saves the state of the controls in the current view. */
+   public void loseFocus() {
+      if (view != null) {
+	 view.loseFocus();
+      }
+    }
+
+    /** This class is resposible for generating the controls for the editing of general options.
+     * @return the Control for editing the general options
+     */
+    private Control getControls() {
+	return controls;
+    }
+
+    /** This class represents the visual component of the general options stored in the CollectionDesignManager. */
+    private class GeneralControl
+	extends JPanel
+	implements Control {
+
+	private boolean has_been_warned = false;
+	private boolean ready = false;
+	//private CollectionMeta beta_collectionmeta;
+	private CollectionMeta collection_extra_collectionmeta;
+	private CollectionMeta collection_name_collectionmeta;
+	private CollectionMeta creator_collectionmeta;
+	private CollectionMeta icon_collection_collectionmeta;
+	private CollectionMeta icon_collection_small_collectionmeta;
+	private CollectionMeta maintainer_collectionmeta;
+	private CollectionMeta public_collectionmeta;
+	/** The creators email. */
+	private EmailField creator_emailfield;
+	/** The maintainers email. */
+	private EmailField maintainer_emailfield;
+	/** Button to browse for the collection about page icon. */
+	private JButton browse_about_icon_button;
+	/** Button to browse for the collection home page icon. */
+	private JButton browse_home_icon_button;
+	/** The checkbox controlling the state of the collection. */
+	//private JCheckBox beta_checkbox;
+	/** The checkbox controlling public access to the collection. */
+	private JCheckBox public_checkbox;
+	private JLabel creator_label;
+	private JLabel description_label;
+	private JLabel icon_label;
+	private JLabel maintainer_label;
+	private JLabel name_label;
+	private JLabel small_icon_label;
+	private JLabel title_label;
+	/** The text field used to edit the file name of the collections icon. */
+	private JTextField icon_textfield;
+	/** The text field used to edit the collections title. */
+	private JTextField name_textfield;
+	/** The text field used to edit the file name of the collections small icon. */
+	private JTextField small_icon_textfield;
+	/** A text area used to modify the collection description. */
+	private JTextArea description_textarea;
+	private JTextArea instructions_textarea;
+	/** Constructor. */
+	public GeneralControl() {
+	    super();
+	    // Retrieve some of the model elements, those we know aren't language dependant
+	    //beta_collectionmeta = new CollectionMeta(CollectionDesignManager.collect_config.getBeta());
+	    public_collectionmeta = new CollectionMeta(CollectionDesignManager.collect_config.getPublic());
+
+	    // Creation
+	    JPanel instruction_panel = new JPanel();
+	    title_label = new JLabel();
+	    title_label.setHorizontalAlignment(JLabel.CENTER);
+	    Dictionary.registerText(title_label, "CDM.General.Title");
+
+	    instructions_textarea = new JTextArea();
+	    instructions_textarea.setCaretPosition(0);
+	    instructions_textarea.setEditable(false);
+	    instructions_textarea.setLineWrap(true);
+	    instructions_textarea.setRows(6);
+	    instructions_textarea.setWrapStyleWord(true);
+	    Dictionary.registerText(instructions_textarea, "CDM.General.Instructions");
+
+	    JPanel all_details_panel = new JPanel();
+	    JPanel details_panel = new JPanel();
+	    JPanel fields_panel = new JPanel();
+
+	    creator_label = new JLabel();
+	    Dictionary.registerText(creator_label, "CDM.General.Email.Creator");
+
+	    creator_emailfield = new EmailField(Configuration.getColor("coloring.error_background", false));
+	    Dictionary.registerTooltip(creator_emailfield, "CDM.General.Email.Creator_Tooltip");
+
+	    maintainer_label = new JLabel();
+	    Dictionary.registerText(maintainer_label, "CDM.General.Email.Maintainer");
+
+	    maintainer_emailfield = new EmailField(Configuration.getColor("coloring.error_background", false));
+	    Dictionary.registerTooltip(maintainer_emailfield, "CDM.General.Email.Maintainer_Tooltip");
+
+	    name_label = new JLabel();
+	    Dictionary.registerText(name_label, "CDM.General.Collection_Name");
+	    name_textfield = new JTextField("CDM.General.Collection_Name");
+	    Dictionary.registerTooltip(name_textfield, "CDM.General.Collection_Name_Tooltip");
+	    JLabel short_name_label = new JLabel();
+	    Dictionary.registerText(short_name_label, "NewCollectionPrompt.Collection_Name");
+	    JTextField short_name_textfield = new JTextField(Gatherer.c_man.getCollection().getName());
+	    short_name_textfield.setEditable(false);
+	    short_name_textfield.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    JPanel icon_panel = new JPanel();
+	    icon_label = new JLabel();
+	    Dictionary.registerText(icon_label, "CDM.General.Icon_Collection");
+	    icon_textfield = new JTextField("CDM.General.Icon_Collection");
+	    Dictionary.registerTooltip(icon_textfield, "CDM.General.Icon_Collection_Tooltip");
+	    browse_about_icon_button = new GLIButton();
+	    browse_about_icon_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerText(browse_about_icon_button, "General.Browse");
+	    JPanel small_icon_panel = new JPanel();
+	    small_icon_label = new JLabel("CDM.General.Icon_Collection_Small");
+	    Dictionary.registerText(small_icon_label, "CDM.General.Icon_Collection_Small");
+	    small_icon_textfield = new JTextField("CDM.General.Icon_Collection_Small");
+	    Dictionary.registerTooltip(small_icon_textfield, "CDM.General.Icon_Collection_Small_Tooltip");
+	    browse_home_icon_button = new GLIButton();
+	    browse_home_icon_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerText(browse_home_icon_button, "General.Browse");
+
+	    // public and beta
+	    JPanel box_panel = new JPanel();
+	    public_checkbox = new JCheckBox("", public_collectionmeta.getValue(CollectionMeta.TEXT).equals(CollectionConfiguration.TRUE_STR));
+	    Dictionary.registerText(public_checkbox, "CDM.General.Access");
+	    //beta_checkbox = new JCheckBox("", beta_collectionmeta.getValue(CollectionMeta.TEXT).equals(CollectionConfiguration.TRUE_STR));
+	    //Dictionary.registerText(beta_checkbox, "CDM.General.Beta");
+
+	    JPanel description_panel = new JPanel();
+	    description_label = new JLabel();
+	    Dictionary.registerText(description_label, "CDM.General.Collection_Extra");
+	    description_textarea = new JTextArea();
+	    description_textarea.setBackground(Configuration.getColor("coloring.editable_background", false));
+	    Dictionary.registerTooltip(description_textarea, "CDM.General.Collection_Extra_Tooltip");
+	    // Connection
+	    //beta_checkbox.addActionListener(CollectionDesignManager.change_listener);
+	    BrowseListener browse_listener = new BrowseListener(StaticStrings.IMAGES_PATH_RELATIVE_TO_GSDL_PREFIX);
+	    browse_about_icon_button.addActionListener(browse_listener);
+	    browse_home_icon_button.addActionListener(browse_listener);
+	    browse_listener = null;
+	    public_checkbox.addActionListener(CollectionDesignManager.change_listener);
+	    public_checkbox.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    creator_emailfield.getDocument().addDocumentListener(CollectionDesignManager.change_listener);
+	    creator_emailfield.getDocument().addDocumentListener(CollectionDesignManager.buildcol_change_listener);
+	    description_textarea.getDocument().addDocumentListener(CollectionDesignManager.change_listener);
+	    description_textarea.getDocument().addDocumentListener(CollectionDesignManager.buildcol_change_listener);
+	    icon_textfield.getDocument().addDocumentListener(CollectionDesignManager.change_listener);
+	    icon_textfield.getDocument().addDocumentListener(CollectionDesignManager.buildcol_change_listener);
+	    maintainer_emailfield.getDocument().addDocumentListener(CollectionDesignManager.change_listener);
+	    maintainer_emailfield.getDocument().addDocumentListener(CollectionDesignManager.buildcol_change_listener);
+	    name_textfield.getDocument().addDocumentListener(CollectionDesignManager.change_listener);
+	    name_textfield.getDocument().addDocumentListener(new CollectionTitleUpdater());
+	    name_textfield.getDocument().addDocumentListener(CollectionDesignManager.buildcol_change_listener);
+	    small_icon_textfield.getDocument().addDocumentListener(CollectionDesignManager.change_listener);
+	    small_icon_textfield.getDocument().addDocumentListener(CollectionDesignManager.buildcol_change_listener);
+	    //Note: unfortunately just loading the General Design panel fires the buildcol_change_listener (even if nothing is changed).
+
+	    // Layout
+	    instruction_panel.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    instruction_panel.setLayout(new BorderLayout());
+	    instruction_panel.add(title_label, BorderLayout.NORTH);
+	    instruction_panel.add(new JScrollPane(instructions_textarea), BorderLayout.CENTER);
+
+	    fields_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    fields_panel.setLayout(new BorderLayout(5,2));
+	    
+	    JPanel fields_label_panel = new JPanel();
+	    fields_label_panel.setLayout(new GridLayout(6,1));
+
+	    JPanel fields_box_panel = new JPanel();
+	    fields_box_panel.setLayout(new GridLayout(6,1));
+    
+	    // creator
+	    fields_label_panel.add(creator_label);
+	    fields_box_panel.add(creator_emailfield);
+
+	    // maintainer
+	    fields_label_panel.add(maintainer_label);
+	    fields_box_panel.add(maintainer_emailfield);
+
+	    // title
+	    fields_label_panel.add(name_label);
+	    fields_box_panel.add(name_textfield);
+
+	    // collection short name
+	    fields_label_panel.add(short_name_label);
+	    fields_box_panel.add(short_name_textfield);
+
+	    // icon
+	    fields_label_panel.add(icon_label);
+	    fields_box_panel.add(icon_panel);
+
+	    // small icon
+	    fields_label_panel.add(small_icon_label);
+	    fields_box_panel.add(small_icon_panel);
+
+	    fields_panel.add(fields_label_panel, BorderLayout.WEST);
+	    fields_panel.add(fields_box_panel, BorderLayout.CENTER);
+
+	    icon_panel.setLayout(new BorderLayout());
+	    icon_panel.add(icon_textfield, BorderLayout.CENTER);
+	    icon_panel.add(browse_about_icon_button, BorderLayout.EAST);
+
+	    small_icon_panel.setLayout(new BorderLayout());
+	    small_icon_panel.add(small_icon_textfield, BorderLayout.CENTER);
+	    small_icon_panel.add(browse_home_icon_button, BorderLayout.EAST);
+
+	    box_panel.setLayout(new GridLayout(1,1,5,2));
+	    box_panel.add(public_checkbox);
+	    //box_panel.add(beta_checkbox);
+
+	    description_panel.setLayout(new BorderLayout());
+	    description_panel.add(description_label, BorderLayout.NORTH);
+	    description_panel.add(new JScrollPane(description_textarea), BorderLayout.CENTER);
+	    
+	    details_panel.setLayout(new BorderLayout());
+	    details_panel.add(fields_panel, BorderLayout.NORTH);
+	    details_panel.add(box_panel, BorderLayout.CENTER);
+
+	    all_details_panel.setLayout(new BorderLayout());
+	    all_details_panel.add(details_panel, BorderLayout.NORTH);
+	    all_details_panel.add(description_panel, BorderLayout.CENTER);
+
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    add(instruction_panel, BorderLayout.NORTH);
+	    add(all_details_panel, BorderLayout.CENTER);
+	}
+
+	/** Destructor. */
+	public void destroy() {
+	}
+
+	/** Called to refresh the components. */
+	public void gainFocus() {
+	    // Retrieve all of the elements that are dependant on default language.
+	    collection_extra_collectionmeta = CollectionDesignManager.collectionmeta_manager.getMetadatum(CollectionConfiguration.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
+	    collection_name_collectionmeta = CollectionDesignManager.collectionmeta_manager.getMetadatum(CollectionConfiguration.COLLECTIONMETADATA_COLLECTIONNAME_STR);
+	    creator_collectionmeta = new CollectionMeta(CollectionDesignManager.collect_config.getCreator());
+	    icon_collection_collectionmeta = CollectionDesignManager.collectionmeta_manager.getMetadatum(CollectionConfiguration.COLLECTIONMETADATA_ICONCOLLECTION_STR);
+	    icon_collection_small_collectionmeta = CollectionDesignManager.collectionmeta_manager.getMetadatum(CollectionConfiguration.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
+	    maintainer_collectionmeta = new CollectionMeta(CollectionDesignManager.collect_config.getMaintainer());
+	    // Make sure the components are up to date
+	    creator_emailfield.setText(creator_collectionmeta.getValue(CollectionMeta.TEXT));
+	    creator_emailfield.setCaretPosition(0);
+	    description_textarea.setText(collection_extra_collectionmeta.getValue(CollectionMeta.TEXT));
+	    description_textarea.setCaretPosition(0);
+	    icon_textfield.setText(icon_collection_collectionmeta.getValue(CollectionMeta.TEXT));
+	    icon_textfield.setCaretPosition(0);
+	    maintainer_emailfield.setText(maintainer_collectionmeta.getValue(CollectionMeta.TEXT));
+	    maintainer_emailfield.setCaretPosition(0);
+	    name_textfield.setText(collection_name_collectionmeta.getValue(CollectionMeta.TEXT));
+	    name_textfield.setCaretPosition(0);
+	    small_icon_textfield.setText(icon_collection_small_collectionmeta.getValue(CollectionMeta.TEXT));
+	    small_icon_textfield.setCaretPosition(0);
+	    // I forgot to keep the checkboxes up to date. Why hasn't this caused problems before today?
+	    public_checkbox.setSelected(public_collectionmeta.getValue(CollectionMeta.TEXT).equals(CollectionConfiguration.TRUE_STR));
+	    //beta_checkbox.setSelected(beta_collectionmeta.getValue(CollectionMeta.TEXT).equals(CollectionConfiguration.TRUE_STR));
+	    ready = true;
+	}
+
+	public boolean canSave() {
+	    boolean title_clash_warning = true;
+	    // Oh, and if the collection title is already in use warn them about it
+	    String title = name_textfield.getText();
+	    // I just happen to have a handy method in the new details prompt to detect this very thing
+	    if(NewCollectionDetailsPrompt.titleClashes(title, CollectionDesignManager.collect_config.getFile())) {
+		// Determine if the user wants to be warned about this
+		WarningDialog dialog = new WarningDialog("warning.TitleClashes", "TitleClashes.Title", Dictionary.get("TitleClashes.Message"), null, true);
+		if(dialog.display() == JOptionPane.OK_OPTION) {
+		    // If they have said yes, then carry on with the assignement
+		    collection_name_collectionmeta.setValue(title);
+		    has_been_warned = true;
+		}
+		// Otherwise we don't assign anything. In fact we have to restore the frame title back to its original value
+		else {
+		    title_clash_warning = false;
+		    String collection_title = collection_name_collectionmeta.getValue(CollectionMeta.TEXT);
+		    String collection_name = Gatherer.c_man.getCollection().getName();
+		    Gatherer.g_man.setTitle(collection_title, collection_name);
+		    collection_name = null;
+		    collection_title = null;
+		}
+		dialog.dispose();
+		dialog = null;
+	    }
+	    // No clash, no worries.
+	    else if(collection_name_collectionmeta != null) {
+		collection_name_collectionmeta.setValue(title);
+	    }
+	    return title_clash_warning;
+	}
+
+	/** Called to store the current value of the components. */
+	public void loseFocus() {
+	    
+	    // String values. Have to test if this component has actually ever recieved focus anyway.
+	    if(ready) {
+		// Boolean values
+		//beta_collectionmeta.setValue((beta_checkbox.isSelected() ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+		public_collectionmeta.setValue((public_checkbox.isSelected() ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+		String creator_email_str = creator_emailfield.getText();
+		creator_collectionmeta.setValue(creator_email_str);
+		// If the email is currently empty, store this email
+		if(Configuration.getEmail() == null) {
+		    Configuration.setEmail(creator_email_str); // Store the email address in the configuration
+		}
+		collection_extra_collectionmeta.setValue(description_textarea.getText());
+		icon_collection_collectionmeta.setValue(icon_textfield.getText());
+		maintainer_collectionmeta.setValue(maintainer_emailfield.getText());
+		icon_collection_small_collectionmeta.setValue(small_icon_textfield.getText());
+
+		// Oh, and if the collection title is already in use warn them about it
+		String title = name_textfield.getText();
+		// I just happen to have a handy method in the new details prompt to detect this very thing
+		if(!has_been_warned && NewCollectionDetailsPrompt.titleClashes(title, CollectionDesignManager.collect_config.getFile())) {
+		    // Determine if the user wants to be warned about this
+		    WarningDialog dialog = new WarningDialog("warning.TitleClashes", "TitleClashes.Title", Dictionary.get("TitleClashes.Message"), null, true);
+		    if(dialog.display() == JOptionPane.OK_OPTION) {
+			// If they have said yes, then carry on with the assignement
+			collection_name_collectionmeta.setValue(title);
+		    }
+		    // Otherwise we don't assign anything. In fact we have to restore the frame title back to its original value
+		    else {
+			String collection_title = collection_name_collectionmeta.getValue(CollectionMeta.TEXT);
+			String collection_name = Gatherer.c_man.getCollection().getName();
+			Gatherer.g_man.setTitle(collection_title, collection_name);
+			collection_name = null;
+			collection_title = null;
+		    }
+		    dialog.dispose();
+		    dialog = null;
+		}
+		// No clash, no worries.
+		else {
+		    collection_name_collectionmeta.setValue(title);
+		}
+		title = null;
+
+		ready = false;
+		has_been_warned = false;
+	    }  
+	}
+
+	/** Listens for a click on either browse button, and when detected opens a file browser window initially pointed at the images folder of the collection. Once a user has selected a path, does it's best to construct the best address to the resource, such as _httpcollection_/images/about.gif */
+	private class BrowseListener
+	    implements ActionListener {
+
+	    private String prefix;
+
+	    public BrowseListener(String prefix_raw) {
+		this.prefix = prefix_raw.replaceAll(StaticStrings.COLNAME_PATTERN, Gatherer.c_man.getCollection().getName());
+	    }
+
+	    public void actionPerformed(ActionEvent event) {
+		// Open an almost standard file browser to the images folder of the current collection
+		File images_folder = new File(Gatherer.c_man.getCollectionImagesDirectoryPath());
+		// If images isn't already there, create it
+		if(!images_folder.exists()) {
+		    images_folder.mkdirs();
+		}
+		JFileChooser file_chooser = new JFileChooser(images_folder);
+		file_chooser.setAcceptAllFileFilterUsed(false);
+		file_chooser.setDialogTitle(Dictionary.get("CDM.General.Browser_Title"));
+		file_chooser.setFileFilter(new ImageFilter());
+		file_chooser.setSize(400,300);
+		OpenCollectionDialog.disableRename(file_chooser);
+		int value = file_chooser.showOpenDialog(Gatherer.g_man);
+		// If the user hasn't cancelled, retrieve the file path selected
+		if(value == JFileChooser.APPROVE_OPTION) {
+		    // If the file isn't in the images folder, then ask the user if they want to copy it there
+		    File file = file_chooser.getSelectedFile();
+		    if(!file.getParentFile().equals(images_folder)) {
+			if(true) { //JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("CDM.General.Copy_Image"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
+			    // Copy the file
+			    try {
+				File collection_image_file = new File(images_folder, file.getName());
+				Gatherer.f_man.getQueue().copyFile(file, collection_image_file, null);
+
+				// If we're using a remote Greenstone server, upload the image
+				if (Gatherer.isGsdlRemote) {
+				    RemoteGreenstoneServer.uploadCollectionFile(collection_image_file);
+				}
+			    }
+			    catch(Exception exception) {
+				DebugStream.printStackTrace(exception);
+				// Show warning
+				JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.General.Image_Copy_Failed"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+				// Nothing else we can do.
+				return;
+			    }
+			}
+			else {
+			    // Nothing we can safely do
+			    return;
+			}
+		    }
+		    // Create the path starting _httpcollection_/images/<filename>
+		    String path = prefix + file.getName();
+		    if(event.getSource() == browse_about_icon_button) {
+			icon_textfield.setText(path);
+		    }
+		    else {
+			small_icon_textfield.setText(path);
+		    }
+		    path = null;
+		}
+	    }
+
+	    /** ImageFilter.java is a 1.4 example used by FileChooserDemo2.java. */
+	    private class ImageFilter
+		extends javax.swing.filechooser.FileFilter {
+
+		private Pattern pattern = null;
+
+		public ImageFilter() {
+		    pattern = Pattern.compile(".*\\.(gif|png|jpe?g)");
+		}
+
+		// Accept all directories and all .col files
+		public boolean accept(File f) {
+		    String filename = f.getName().toLowerCase();
+		    Matcher matcher = pattern.matcher(filename);
+		    return f.isDirectory() || matcher.matches();
+		}
+
+		// The description of this filter
+		public String getDescription() {
+		    return Dictionary.get("CDM.General.Image_Filter");
+		}
+	    }
+	}
+
+	private class CollectionTitleUpdater
+	    implements DocumentListener {
+	    /** Gives notification that an attribute or set of attributes changed. */
+	    public void changedUpdate(DocumentEvent e) {
+		setTitle();
+	    }
+	    /** Gives notification that there was an insert into the document. */
+	    public void insertUpdate(DocumentEvent e) {
+		setTitle();
+	    }
+	    /** Gives notification that a portion of the document has been removed. */
+	    public void removeUpdate(DocumentEvent e) {
+		setTitle();
+	    }
+	    
+	    private void setTitle() {
+		// Set the title
+		String collection_title = name_textfield.getText();
+		String collection_name = Gatherer.c_man.getCollection().getName();
+		Gatherer.g_man.setTitle(collection_title, collection_name);
+		collection_title = null;
+		collection_name = null;
+	    }
+	}
+    }
+
+    /** This tree provides a 'table of contents' for the various components of the design process (collection configuration in more technical terms). */
+    private class DesignTree
+	extends JTree {
+	private DesignNode root = null;
+	/** Constructor. Automatically generates all of the nodes, in the order of CONTENTS. */
+	public DesignTree() {
+	    super();
+	    resetModel(Configuration.getMode());
+	    expandRow(0);
+	    setRootVisible(false);
+	    setSelectionRow(0);
+	}
+
+	/** Reset the model used by the design page contents tree. This is necessary to hide the partitions entry when in lower detail modes
+	 * @param mode the current detail mode as an int
+	 */
+	public void resetModel(int mode) {
+	    root = new DesignNode("CDM.GUI.Root");
+	    // Now add the design categories.
+	    for(int i = 0; i < CONTENTS.length; i++) {
+		root.add(new DesignNode(CONTENTS[i]));
+	    }
+	    this.setModel(new DefaultTreeModel(root));
+	    updateUI();
+	}
+	/** Set the current view to the one specified.
+	 * @param type the name of the desired view as a String
+	 */
+	public void setSelectedView(String type) {
+	    type = Dictionary.get(type);
+	    for(int i = 0; i < root.getChildCount(); i++) {
+		DesignNode child = (DesignNode) root.getChildAt(i);
+		if(child.toString().equals(type)) {
+		    TreePath path = new TreePath(child.getPath());
+		    setSelectionPath(path);
+		}
+	    }
+	}
+    }
+    /** A tree node that retains a reference to one of the possible design sub-views relating to the different sub-managers. */
+    private class DesignNode
+	extends DefaultMutableTreeNode {
+	/** Constructor.
+	 * @param object The <strong>Object</strong> assigned to this node.
+	 */
+	public DesignNode(String object) {
+	    super(object);
+	}
+	/** Retrieve a textual representation of the object.
+	 * @return a String
+	 */
+	public String toString() {
+	    // return Dictionary.get("CDM.GUI." + (String)getUserObject());
+	    return Dictionary.get((String) getUserObject());
+	}
+    }
+    /** Listens for selection changes in the 'contents' tree, and switches to the appropriate view. */
+    private class TreeListener
+	implements TreeSelectionListener {
+	/** Called whenever the selection changes, we must update the view so it matches the node selected.
+	 * @param event A <strong>TreeSelectionEvent</strong> containing more information about the tree selection.
+	 * @see org.greenstone.gatherer.cdm.ClassifierManager
+	 * @see org.greenstone.gatherer.cdm.CollectionDesignManager
+	 * @see org.greenstone.gatherer.cdm.CollectionMetaManager
+	 * @see org.greenstone.gatherer.cdm.FormatManager
+	 * @see org.greenstone.gatherer.cdm.LanguageManager
+	 * @see org.greenstone.gatherer.cdm.MetadataSetView
+	 * @see org.greenstone.gatherer.cdm.SubcollectionManager
+	 * @see org.greenstone.gatherer.cdm.TranslationView
+	 * @see org.greenstone.gatherer.cdm.PlugInManager
+	 */
+	public void valueChanged(TreeSelectionEvent event) {
+	    if(!tree.isSelectionEmpty()) {
+		TreePath path = tree.getSelectionPath();
+		DesignNode node = (DesignNode)path.getLastPathComponent();
+		String type = (String)node.getUserObject();
+		// Wait begins
+		Gatherer.g_man.wait(true);
+		// Save information in current view
+		view.loseFocus();
+		remove((JPanel)view);
+		// Change panes.
+		if(type == CONTENTS[0]) {
+		    view = getControls();
+		}
+		else if(type == CONTENTS[1]) {
+		    view = CollectionDesignManager.plugin_manager.getControls();
+		}
+		else if(type == CONTENTS[2]) {
+		    view = CollectionDesignManager.searchtype_manager.getControls();
+		}
+		else if(type == CONTENTS[3]) {
+		    view = CollectionDesignManager.index_manager.getControls();
+		}
+		else if(type == CONTENTS[4]) {
+		    view = CollectionDesignManager.subcollection_manager.getControls();
+		}
+		else if(type == CONTENTS[5]) {
+		    view = CollectionDesignManager.supercollection_manager.getControls();
+		}
+		else if(type == CONTENTS[6]) {
+		    view = CollectionDesignManager.classifier_manager.getControls();
+		}
+		else if(type == CONTENTS[7]) {
+		    view = CollectionDesignManager.format_manager.getControls();
+		}
+		else if(type == CONTENTS[8]) {
+		    view = CollectionDesignManager.translation_view.getControls();
+		}
+		else if(type == CONTENTS[9]) {
+		    view = CollectionDesignManager.metadataset_view.getControls();
+		}
+		add((JPanel)view, BorderLayout.CENTER);
+		// Update information on visible pane
+		view.gainFocus();
+		repaint();
+		// Wait ends
+		Gatherer.g_man.wait(false);
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Index.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Index.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Index.java	(revision 10506)
@@ -0,0 +1,319 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.util.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.metadata.MetadataTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/** This class encapsulates a single indexing pair.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3d
+ */
+public class Index
+    implements Comparable, DOMProxyListEntry {
+    /** An values of items in the index level enumeration. */
+    static public final String LEVEL[] = {CollectionConfiguration.DOCUMENT_STR, CollectionConfiguration.PARAGRAPH_STR, CollectionConfiguration.SECTION_STR};
+
+    private ArrayList sources = null;
+    /** The level of this index (if old sckool MG). */
+    private int level = -1;
+    /** The element this index is based upon. */
+    private Element element = null;
+    /** The unique, if cryptic, identifier of an index. */
+    private String id = null;
+
+    /** Default constructor, which should only be used during DOMProxyListModel creation. */
+    public Index() {
+    }
+
+    /** Constructor. */
+    public Index(Element element) {
+	this.element = element;
+    }
+
+    /** Constructor for a newly assigned index. */
+    public Index(ArrayList sources) {
+	this.sources = sources;
+	// Create a new element
+	Document document = CollectionDesignManager.collect_config.document;
+	this.element = document.createElement(CollectionConfiguration.INDEX_ELEMENT);
+	// For each source add a content element
+	int size = sources.size();
+	for(int i = 0; i < size; i++) {
+	    Element content_element = document.createElement(CollectionConfiguration.CONTENT_ELEMENT);
+	    Object source_object = sources.get(i);
+	    if (source_object instanceof MetadataElement) {
+		// System.err.println("Constructing new Index with MetadataElement source...");
+		content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, ((MetadataElement) source_object).getFullName());
+	    }
+	    else {
+		// System.err.println("Constructing new Index with String source...");
+		content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, source_object.toString());
+	    }
+	    element.appendChild(content_element);
+	    content_element = null;
+	}
+	document = null;
+    }
+
+    /** Constructor for a newly assigned index with specified level (old skool). */
+    public Index(int level, ArrayList sources) {
+	this(sources);
+	this.level = level;
+	element.setAttribute(CollectionConfiguration.LEVEL_ATTRIBUTE, LEVEL[level]);
+    }
+
+    public Index(String level, ArrayList sources) {
+	this(sources);
+	for(int i = 0; i < LEVEL.length; i++) {
+	    if(LEVEL[i].equalsIgnoreCase(level)) {
+		this.level = i;
+	    }
+	}
+	element.setAttribute(CollectionConfiguration.LEVEL_ATTRIBUTE, LEVEL[this.level]);
+    }
+
+    /** Method to compare two indexes.
+     * @param object The other index as an <strong>Object</strong>.
+     * @return An <i>int</i> which indicates how the indexes compare.
+     * @see java.lang.String
+     */
+    public int compareTo(Object object) {
+	if(object == null) {
+	    return -1;
+	}
+	String id = getID();
+	return id.compareTo(((Index)object).getID());
+    }
+    
+    public DOMProxyListEntry create(Element element) {
+	return new Index(element);
+    }
+
+    /** Method to test for the equality of two indexes.
+     * @param object The other index as an <strong>Object</strong>.
+     * @return A <i>boolean</i> which is <i>true</i> if the two indexes are equal, <i>false</i> otherwise.
+     */
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+    
+    public Element getElement() {
+	return element;
+    }
+    
+    /** Method to get the value of level.
+     * @return the level as a int
+     */
+    public int getLevel() {
+	if(level == -1 && element != null) {
+	    String level_str = element.getAttribute(CollectionConfiguration.LEVEL_ATTRIBUTE);
+	    for(int i = 0; level == -1 && i < LEVEL.length; i++) {
+		if(level_str.equals(LEVEL[i])) {
+		    level = i;
+		}
+	    }
+	    level_str = null;
+	}
+	return level;
+    }
+
+    public String getID() {
+	if(element == null) {
+	    id="";
+	}
+	else if(id == null) {
+	    StringBuffer id_buffer = new StringBuffer();
+	    // Write level information, if any.
+	    int level = getLevel();
+	    if(0 <= level && level < 3) {
+		id_buffer.append(LEVEL[level]);
+		id_buffer.append(StaticStrings.COLON_CHARACTER);
+	    }
+	    // Write data information. Retrieve each of the content sources and add them in a comma separated list.
+	    ArrayList sources = getSources();
+	    int sources_size = sources.size();
+	    for(int i = 0; i < sources_size; i++) {
+		Object source_object = sources.get(i);
+		if (source_object instanceof MetadataElement) {
+		    String full_element_name = ((MetadataElement)source_object).getFullName();
+		    if(full_element_name.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
+		       id_buffer.append(full_element_name.substring(StaticStrings.EXTRACTED_NAMESPACE.length()));
+		    }
+		    else {
+			id_buffer.append(full_element_name);
+		    }
+		}
+		else {
+		    id_buffer.append(source_object.toString());
+		}
+		id_buffer.append(StaticStrings.COMMA_CHARACTER);
+	    }
+	    sources = null;
+	    id = id_buffer.substring(0, id_buffer.length() - 1);
+	}
+	return id;
+    }
+
+    /** Tries to retrieve this indexes name according to the CollectionMetaManager. */
+    public String getName() {
+	CollectionMeta metadatum = CollectionDesignManager.collectionmeta_manager.getMetadatum(StaticStrings.STOP_CHARACTER + getID(), false);
+	if(metadatum != null) {
+	    return metadatum.getValue(CollectionMeta.TEXT);
+	}
+	return "";
+    }
+
+    /** Retrieve the sources of this index.
+     * @return the sources as an ArrayList
+     */
+    public ArrayList getSources() {
+	if(sources == null) {
+	    sources = new ArrayList();
+	    NodeList content_elements = element.getElementsByTagName(CollectionConfiguration.CONTENT_ELEMENT);
+	    int content_elements_length = content_elements.getLength();
+	    for(int i = 0; i < content_elements_length; i++) {
+		Element content_element = (Element) content_elements.item(i);
+		String metadata_element_name_full = (String) content_element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
+		MetadataElement metadata_element = MetadataTools.getMetadataElementWithDisplayName(metadata_element_name_full);
+		if (metadata_element != null) {
+		    sources.add(metadata_element);
+		}
+		else {
+		    sources.add(metadata_element_name_full);
+		}
+	    }
+	    content_elements = null;
+	}
+	return sources;
+    }
+
+    public boolean isAssigned() {
+	return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
+    }
+
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    public void setElement(Element element) {
+	this.element = element;
+	this.level = -1;
+	this.id = null;
+	this.sources = null;
+    }
+
+    /** Method to set the level of this index which can only be used for the default index. 
+     * @param new_level the new level as an int
+     */
+    public void setLevel(int new_level) {
+	// System.err.println("SetLevel(" + new_level + ")");
+	if(element != null && element.getNodeName().equals(CollectionConfiguration.INDEX_DEFAULT_ELEMENT)) {
+	    element.setAttribute(CollectionConfiguration.LEVEL_ATTRIBUTE, LEVEL[new_level]);
+	    this.id = null; // Regenerate ID.
+	    this.level = new_level;
+	}
+	else {
+	    DebugStream.println("Error! Called setLevel() of index other than the default.");
+	}
+    }
+
+    /** Method to set the sources for this index which can only be used for the default index.
+     * @param sources an ArrayList of source names
+     */
+    public void setSources(ArrayList sources) {
+	if(element != null && element.getNodeName().equals(CollectionConfiguration.INDEX_DEFAULT_ELEMENT)) {
+	    // Erase old sources
+	    XMLTools.clear(element);
+	    // For each entry in the sources array add a new content element.
+	    int size = sources.size();
+	    for(int i = 0; i < size; i++) {
+		Element content_element = element.getOwnerDocument().createElement(CollectionConfiguration.CONTENT_ELEMENT);
+		Object source_object = sources.get(i);
+		if (source_object instanceof MetadataElement) {
+		    String name = ((MetadataElement) source_object).getFullName();
+		    content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, name);
+		    name = null;
+		}
+		else {
+		    //DebugStream.println("Found String as source: " + source_object.toString());
+		    content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, source_object.toString());
+		}
+		source_object = null;
+		element.appendChild(content_element);
+		content_element = null;
+	    }
+	    this.id = null; // Regenerate ID.
+	    this.sources = sources;
+	}
+	else {
+	    DebugStream.println("Error! Called setSource() of index other than the default.");
+	}
+    }
+
+    /** Method to turn this object into a string representation ready to be placed in the collection configuration file.
+     * @return A <strong>String</strong> containing the information of this class.
+     */
+    public String toString() {
+	StringBuffer text_buffer = new StringBuffer("");
+	// Generate language dependant id (include extracted metadata namespace)
+	// Write level information, if any.
+	int level = getLevel();
+	if(0 <= level && level < 3) {
+	    text_buffer.append(LEVEL[level]);
+	    text_buffer.append(StaticStrings.COLON_CHARACTER);
+	}
+	// Write data information. Retrieve each of the content sources and add them in a comma separated list.
+	ArrayList sources = getSources();
+	int sources_size = sources.size();
+	for(int i = 0; i < sources_size; i++) {
+	    String source_name = (sources.get(i)).toString();
+	    text_buffer.append(source_name);
+	    if(i < sources_size - 1) {
+		text_buffer.append(StaticStrings.COMMA_CHARACTER);
+	    }
+	}
+	sources = null;
+	CollectionMeta metadatum = CollectionDesignManager.collectionmeta_manager.getMetadatum(StaticStrings.STOP_CHARACTER + getID(), false);
+	if(metadatum != null) {
+	    text_buffer.append(" \"");
+	    text_buffer.append(metadatum.getValue(CollectionMeta.TEXT));
+	    text_buffer.append("\"");
+	}
+	return text_buffer.toString();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/IndexManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/IndexManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/IndexManager.java	(revision 10506)
@@ -0,0 +1,1832 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.GComboBox;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.util.CheckList;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.w3c.dom.*;
+/** This class is resposible for storing the indexes which have been assigned to this collection and the default index, and providing methods for interacting with both these data pools. It also knows how to turn itself into a String as it would be displayed in the collection configuration file.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class IndexManager
+    extends DOMProxyListModel {
+
+    static final private Dimension FIELD_SIZE = new Dimension(200,30);
+    static final private String MGINDEXES = "mg indexes";
+    static final private String MGPPINDEXES = "mgpp indexes";
+
+    /** The controls for editing the indexes. */
+    private Control controls = null;
+    /** A model of the levels, also based on the DOM. */
+    private DOMProxyListModel levels_model = null;
+    /** A reference to ourselves so our inner methods have access. */
+    private DOMProxyListModel model = null;
+    /** The default index. */
+    private Index default_index = null;
+
+    /** Constructor. */
+    public IndexManager(Element indexes) {
+	super(indexes, CollectionConfiguration.INDEX_ELEMENT, new Index());
+	DebugStream.println("IndexManager: " + getSize() + " indexes parsed.");
+	model = this;
+	// Parse and retrieve the default index
+	NodeList default_index_elements = CollectionDesignManager.collect_config.getDocumentElement().getElementsByTagName(CollectionConfiguration.INDEX_DEFAULT_ELEMENT);
+	if(default_index_elements.getLength() > 0) {
+	    default_index = new Index((Element)default_index_elements.item(0));
+	}
+	// Parse and retrieve the levels element
+	Element levels_element = CollectionDesignManager.collect_config.getLevels();
+	levels_model = new DOMProxyListModel(levels_element, CollectionConfiguration.CONTENT_ELEMENT, new Level());
+	DebugStream.println(" + " + levels_model.getSize() + " levels parsed.");
+    }
+
+    /** Method to add a new index.
+     * @param index The <strong>Index</strong> to add.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     */
+    private void addIndex(Index index, CollectionMeta metadatum) {
+	///ystem.err.println("Adding an index: " + index.toString());
+	if(!contains(index)) {
+	    CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
+	    // Retrieve the currently last index
+	    if(getSize() > 0) {
+		Index last_index = (Index)getElementAt(getSize() - 1);
+		addAfter(index, last_index);
+		
+	    }
+	    else {
+		add(index);
+		// Also set this index as the default one, but only if there are levels available (ie mg only)
+		if(index.getLevel() != -1) {
+		    setDefault(index);
+		}
+	    }
+	    Gatherer.c_man.configurationChanged();
+	}
+	else {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.IndexManager.Index_Exists"), Dictionary.get("General.Warning"), JOptionPane.WARNING_MESSAGE);
+	}
+    }
+
+    private void addLevel(Level level, CollectionMeta metadatum) {
+	if(!levels_model.contains(level)) {
+	    CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
+	    // Retrieve the currently last level
+	    if(levels_model.getSize() > 0) {
+		Level last_level = (Level)levels_model.getElementAt(levels_model.getSize() - 1);
+		levels_model.addAfter(level, last_level);
+	    }
+	    else {
+		levels_model.add(level);
+	    }
+	    Gatherer.c_man.configurationChanged();
+	}
+	else {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.IndexManager.Level_Exists"), Dictionary.get("General.Warning"), JOptionPane.WARNING_MESSAGE);
+	}
+    }
+
+    public void destroy() {
+	if(controls != null) {
+	    controls.destroy();
+	    controls = null;
+	}
+	default_index = null;
+	model = null;
+    }
+
+    /** Method to acquire the controls for editing the indexes.
+     * @return the Control
+     */
+    public Control getControls() {
+	if(controls == null) {
+	    // Build controls
+	    controls = new IndexControl();
+	}
+	return controls;
+    }
+
+    /** Method to get the default index.
+     * @return The default <strong>Index</strong>.
+     */
+    public Index getDefault() {
+	if(default_index != null && default_index.isAssigned()) {
+	    return default_index;
+	}
+	else {
+	    return null;
+	}
+    }
+
+    /** Method to retrieve a certain index, as referenced by an index number.
+     * @param index An <i>int</i> which indicates the position of the desired index.
+     * @return The <strong>Index</strong> at the given index, or <i>null</i> if no such index exists.
+     */
+    public Index getIndex(int index) {
+	if(0 <= index && index < getSize()) {
+	    return (Index)getElementAt(index);
+	}
+	return null;
+    }
+
+    /** Method to retrieve a certain index, given its id.
+     * @param id the id of the index as a String
+     * @return the Index that matches id, or null if no such index exists
+     */
+    public Index getIndex(String id) {
+	int size = getSize();
+	for(int i = 0; i < size; i++) {
+	    Index index = (Index) getElementAt(i);
+	    if(index.getID().equals(id)) {
+		return index;
+	    }
+	}
+	return null;
+    }
+
+    public ArrayList getIndexes() {
+	return children();
+    }
+
+    public Level getLevel(String name) {
+	int levels_model_size = levels_model.getSize();
+	for(int i = 0; i < levels_model_size; i++) {
+	    Level level = (Level) levels_model.getElementAt(i);
+	    if(level.getLevel().equals(name)) {
+		return level;
+	    }
+	}
+	return null;
+    }
+
+
+    private void moveIndex(Index index, boolean move_up)
+    {
+	// Determine the current position of the index
+	int position = indexOf(index);
+	// Determine if it can be moved, ie if its not already at the top trying to move up, or at the bottom trying to move down.
+	if(position == -1) {
+	    return;
+	}
+	if(position == 0 && move_up) {
+	    return;
+	}
+	if(position == (getSize()) - 1 && !move_up) {
+	    return;
+	}
+	
+	// Ok, move up
+	if (move_up) {
+	    position--;
+	    remove(index);
+	    add(position, index);
+	}
+
+	// Or move down
+	else {
+	    position++;
+	    remove(index);
+	    add(position, index);
+	}
+
+	// Schedule the collection for saving
+	Gatherer.c_man.configurationChanged();
+    }
+
+
+    private void moveLevel(Level level, boolean move_up) {
+	// Determine the leveles current position
+	int position = levels_model.indexOf(level);
+	// Determine if it can be moved, ie if its not already at the top trying to move up, or at the bottom trying to move down.
+	if(position == -1) {
+	    return;
+	}
+	if(position == 0 && move_up) {
+	    return;
+	}
+	if(position == (levels_model.getSize()) - 1 && !move_up) {
+	    return;
+	}
+	// Ok, move up
+	if(move_up) {
+	    position--;
+	    levels_model.remove(level);
+	    levels_model.add(position, level);
+	}
+	// Or move down
+	else {
+	    position++;
+	    levels_model.remove(level);
+	    levels_model.add(position, level);
+	}
+	// Schedule the collection for saving
+	Gatherer.c_man.configurationChanged();
+    }
+    
+    /** Method to remove a certain index.
+     * @param index the Index to remove.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.cdm.CollectionDesignManager
+     * @see org.greenstone.gatherer.cdm.CollectionMetaManager
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     */
+    private void removeIndex(Index index) {
+	if(index != null) {
+	    // Remove any current metadata from this index
+	    CollectionDesignManager.collectionmeta_manager.removeMetadata(CollectionConfiguration.STOP_CHARACTER + index.getID());
+	    // Check if the index removed happens to be the default index
+	    if(default_index != null && default_index.equals(index)) {
+		// If so our first solution is to set the first index to be default
+		if(getSize() > 0) {
+		    Index another_index = (Index) getElementAt(0);
+		    setDefault(another_index);
+		    another_index = null;
+		}
+		else {
+		    default_index.setAssigned(false);
+		}
+	    }
+	    // Remove the index
+	    remove(index);
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+
+    private void removeLevel(Level level) {
+	if(level != null) {
+	    // Remove any current metadata from this level
+	    CollectionDesignManager.collectionmeta_manager.removeMetadata(CollectionConfiguration.STOP_CHARACTER + level.getLevel());
+	    // Remove the level
+	    levels_model.remove(level);
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+
+    /** Method to set the default index.
+     * @param index the new default Index
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     */
+    public void setDefault(Index index) {
+	if(index != null) {
+	    if(default_index == null) {
+		// Create the default index element, and place immediately after indexes element.
+		Element default_index_element = root.getOwnerDocument().createElement(CollectionConfiguration.INDEX_DEFAULT_ELEMENT);
+		default_index = new Index(default_index_element);
+		Node target_node = CollectionConfiguration.findInsertionPoint(default_index_element);
+		if(target_node != null) {
+		    root.getOwnerDocument().getDocumentElement().insertBefore(default_index_element, target_node);
+		}
+		else {
+		    root.getOwnerDocument().getDocumentElement().appendChild(default_index_element);
+		}
+	    }
+	    default_index.setAssigned(true);
+	    default_index.setLevel(index.getLevel());
+	    default_index.setSources(index.getSources());
+	}
+	else {
+	    if(default_index != null) {
+		default_index.setAssigned(false);
+	    }
+	}
+	Gatherer.c_man.configurationChanged();
+    }
+
+    /** This method is reponsible for changing the underlying Index commands from MG to MGPP and back again. This turns out to be easyish for MG->MGPP and very hard for the reverse. For the former we remove the level fragment and make sure the same levels are set, then we produce a list of the sources involved, breaking down comma seperated lists and making sure each item it unique. Changing back the other way turns out to be impossible, so we don't (beyond generating document:text, section:text and paragraph:text if text is an index and the respective levels are present). In either case we start by creating a comment containing the old index information.
+     * @param  state true to enable MGPP indexes, false to use standard MG style ones
+     */
+    public void setMGPPEnabled(boolean state) {
+	if(state == root.getAttribute(CollectionConfiguration.MGPP_ATTRIBUTE).equals(CollectionConfiguration.TRUE_STR)) {
+	    // we are not changing state
+	    return;
+	    
+	}
+	// change MG -> MGPP
+	if(state) {
+	    Element mg_element = root;
+	    // Retrieve and assign the MGPP indexes element.
+	    Element mgpp_element = CollectionDesignManager.collect_config.getMGPPIndexes();
+	    mgpp_element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, CollectionConfiguration.TRUE_STR);
+	    levels_model.root.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, CollectionConfiguration.TRUE_STR);
+	    // If the MGPP indexes element is empty (ie was created by CollectionConfiguration), generate new MGPP index from the existing index
+	    NodeList indexes = mgpp_element.getElementsByTagName(CollectionConfiguration.INDEX_ELEMENT);
+	    if(indexes.getLength() == 0) {
+		ArrayList levels_list = new ArrayList();
+		ArrayList sources_list = new ArrayList();
+		// We first use details from the default index if any
+		if(default_index != null) {
+		    int level_int = default_index.getLevel();
+		    if(0 <= level_int && level_int < 3) {
+			String level = Index.LEVEL[level_int];
+			if(!levels_list.contains(level)) {
+			    levels_list.add(level);
+			}
+			level = null;
+		    }
+		    ArrayList sources = default_index.getSources();
+		    sources.removeAll(sources_list);
+		    sources_list.addAll(sources);
+		}
+		int size = getSize();
+		for(int i = 0; i < size; i++) {
+		    Index index = (Index) getElementAt(i);
+		    int level_int = index.getLevel();
+		    if(0 <= level_int && level_int < 3) {
+			String level = Index.LEVEL[level_int];
+			if(!levels_list.contains(level)) {
+			    levels_list.add(level);
+			}
+			level = null;
+		    }
+		    ArrayList sources = index.getSources();
+		    sources.removeAll(sources_list);
+		    sources_list.addAll(sources);
+		    index = null;
+		}
+		// Replace mg element with mgpp element
+		setRoot(mgpp_element);
+		
+		// We now have a list of sources and a list of levels, so create new indexes and levels based on these
+		int sources_list_size = sources_list.size();
+		for(int j = 0; j < sources_list_size; j++) {
+		    Object source_object = sources_list.get(j);
+		    String source_str = null;
+		    if(source_object instanceof MetadataElement) {
+			source_str = ((MetadataElement) source_object).getFullName();
+		    }
+		    else {
+			source_str = source_object.toString();
+		    }
+		    ArrayList new_sources = new ArrayList();
+		    new_sources.add(source_object);
+		    source_object = null;
+		    Index new_index = new Index(new_sources);
+		    // Try to retrieve existing metadatum
+		    source_str = new_index.getID();
+		    CollectionMeta metadatum = CollectionDesignManager.collectionmeta_manager.getMetadatum(CollectionConfiguration.STOP_CHARACTER + source_str, false);
+		    // If no metadata was found, add new pseudo metadata using the id
+		    if(metadatum == null) {
+			metadatum = new CollectionMeta(CollectionConfiguration.STOP_CHARACTER + source_str);
+			metadatum.setAssigned(true);
+			metadatum.setValue(source_str);
+		    }
+		    // If it was found, ensure it is assigned
+		    else {
+			metadatum.setAssigned(true);
+		    }
+		    source_str = null;
+		    addIndex(new_index, metadatum);
+		    metadatum = null;
+		    new_index = null;
+		    new_sources = null;
+		    source_str = null;
+		}
+		int levels_list_size = levels_list.size();
+		for(int k = 0; k < levels_list_size; k++) {
+		    Level new_level = new Level((String)levels_list.get(k));
+		    if(!levels_model.contains(new_level)) {
+			levels_model.add(levels_model.getSize(), new_level);
+		    }
+		    new_level = null;
+		}
+	    }
+	    else {
+		// Replace mg element with mgpp element
+		setRoot(mgpp_element);
+	    }
+	    // Unassign MG element and default index
+	    mg_element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, CollectionConfiguration.FALSE_STR);
+	    mg_element = null;
+	    if(default_index != null) {
+		default_index.setAssigned(false);
+	    }
+	}
+	// change MGPP -> MG
+	else {
+	    Element mgpp_element = root;
+	    // Retrieve and assign MG element and default index element
+	    Element mg_element = CollectionDesignManager.collect_config.getMGIndexes();
+	    mg_element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, CollectionConfiguration.TRUE_STR);
+	    if(default_index != null) {
+		default_index.setAssigned(true);
+	    }
+	    // If mg element has no indexes, and the current mgpp index include a text one, then generate text indexes for each of the registered levels.
+	    NodeList indexes = mgpp_element.getElementsByTagName(CollectionConfiguration.INDEX_ELEMENT);
+	    if(indexes.getLength() == 0) {
+		Index index = getIndex(CollectionConfiguration.TEXT_STR);
+		if(index != null) {
+		    // Replace mgpp element with mg element
+		    setRoot(mg_element);
+		    int level_size = levels_model.getSize();
+		    for(int i = 0; i < level_size; i++) {
+			Level level = (Level) levels_model.getElementAt(i);
+			Index new_index = new Index(level.getLevel(), index.getSources());
+			// Try to retrieve existing metadatum
+			String source_str = new_index.getID();
+			CollectionMeta metadatum = CollectionDesignManager.collectionmeta_manager.getMetadatum(CollectionConfiguration.STOP_CHARACTER + source_str, false);
+			// If no metadata was found, add new pseudo metadata using the id
+			if(metadatum == null) {
+			    metadatum = new CollectionMeta(CollectionConfiguration.STOP_CHARACTER + source_str);
+			    metadatum.setAssigned(true);
+			    metadatum.setValue(source_str);
+			}
+			// If it was found, ensure it is assigned
+			else {
+			    metadatum.setAssigned(true);
+			}
+			source_str = null;
+			addIndex(new_index, metadatum);
+			new_index = null;
+			level = null;
+		    }
+		}
+	    }
+	    else {
+		// Replace mgpp element with mg element
+		setRoot(mg_element);
+	    }
+	    // Unassign mgpp element and levels
+	    mgpp_element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, CollectionConfiguration.FALSE_STR);
+	    levels_model.root.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, CollectionConfiguration.FALSE_STR);
+	}
+	
+    }
+    
+
+    /** This class creates a set of controls for editing the indexes. */
+    private class IndexControl
+	extends JPanel
+	implements Control {
+
+	private CardLayout card_layout;
+	private CheckList source_list;
+	private JButton add_button;
+	private JButton move_down_button;
+	private JButton move_up_button;
+	private JButton remove_button;
+	private JButton replace_button;
+	private JButton set_default_button;
+	private JComboBox level_combobox;
+	private JList index_list;
+	private JTextArea instruction_textarea;
+	private JTextField name_textfield ;
+	// when we are in mgpp mode, we want to remove the mg listener 
+	// the underlying model is the same between the two JLists, and
+	// both listeners get notified when the model changes, but the mg
+	// listener doesn't care about mgpp events
+	private ListSelectionListener index_list_listener;
+ 	
+	private MGPPControl mgppindexes_control;
+
+	/** Constructor.
+	 * @see org.greenstone.gatherer.Configuration
+	 * @see org.greenstone.gatherer.Gatherer
+	 * @see org.greenstone.gatherer.cdm.IndexManager.IndexControl.AddListener
+	 * @see org.greenstone.gatherer.cdm.IndexManager.IndexControl.NameListener
+	 * @see org.greenstone.gatherer.cdm.IndexManager.IndexControl.RemoveListener
+	 * @see org.greenstone.gatherer.cdm.IndexManager.IndexControl.SetDefaultListener
+	 * @see org.greenstone.gatherer.collection.CollectionManager
+	 */
+	public IndexControl() {
+	    super();
+
+	    ArrayList new_data = new ArrayList();
+	    new_data.add(CollectionConfiguration.TEXT_STR);
+	    new_data.addAll(MetadataSetManager.getEveryMetadataSetElement());
+	    // Creation
+	    JPanel mgindexes_panel = new JPanel();
+	    card_layout = new CardLayout();
+
+	    // MG Index Controls
+
+	    JPanel mg_indexes_pane = new JPanel();
+
+	    JPanel instruction_pane = new JPanel();
+	    JLabel title_label = new JLabel();
+	    title_label.setHorizontalAlignment(JLabel.CENTER);
+	    Dictionary.registerText(title_label, "CDM.IndexManager.Title");
+
+	    instruction_textarea = new JTextArea();
+	    instruction_textarea.setEditable(false);
+	    instruction_textarea.setLineWrap(true);
+	    instruction_textarea.setRows(6);
+	    instruction_textarea.setWrapStyleWord(true);
+	    Dictionary.registerText(instruction_textarea, "CDM.IndexManager.Instructions");
+
+	    JPanel assigned_indexes_pane = new JPanel();
+	    JLabel index_label = new JLabel();
+	    Dictionary.registerText(index_label, "CDM.IndexManager.Indexes");
+	    index_list = new JList(model);
+	    index_list.setCellRenderer(new IndexListRenderer());
+	    index_list.setVisibleRowCount(2);
+	    JPanel movement_pane = new JPanel();
+
+	    move_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
+	    move_up_button.setEnabled(false);
+	    move_up_button.setMnemonic(KeyEvent.VK_U);
+	    Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
+
+	    move_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
+	    move_down_button.setEnabled(false);
+	    move_down_button.setMnemonic(KeyEvent.VK_D);
+	    Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
+
+	    set_default_button = new GLIButton();
+	    set_default_button.setEnabled(false);
+	    set_default_button.setMnemonic(KeyEvent.VK_S);
+	    Dictionary.registerBoth(set_default_button, "CDM.IndexManager.Set_Default", "CDM.IndexManager.Set_Default_Tooltip");
+
+	    JPanel index_pane = new JPanel();
+	    JPanel details_pane = new JPanel();
+	    JPanel labels_pane = new JPanel();
+	    JPanel boxes_pane = new JPanel();
+	    JPanel content_pane = new JPanel();
+
+	    JLabel name_label = new JLabel();
+	    Dictionary.registerText(name_label, "CDM.IndexManager.Index_Name");
+	    name_textfield = new JTextField();
+	    name_textfield.setPreferredSize(FIELD_SIZE);
+	    Dictionary.registerTooltip(name_textfield, "CDM.IndexManager.Index_Name_Tooltip");
+
+	    JLabel source_label = new JLabel();
+	    Dictionary.registerText(source_label, "CDM.IndexManager.Source");
+	    source_list = new CheckList(false);
+	    source_list.setListData(new_data);
+	    Dictionary.registerTooltip(source_list, "CDM.IndexManager.Source_Tooltip");
+
+	    JLabel level_label = new JLabel();
+	    Dictionary.registerText(level_label, "CDM.IndexManager.Level");
+	    level_combobox = new JComboBox();
+	    level_combobox.setPreferredSize(FIELD_SIZE);
+	    level_combobox.addItem(CollectionConfiguration.DOCUMENT_STR);//Dictionary.get("CDM.IndexManager.Document"));
+	    level_combobox.addItem(CollectionConfiguration.PARAGRAPH_STR);//Dictionary.get("CDM.IndexManager.Paragraph"));
+	    level_combobox.addItem(CollectionConfiguration.SECTION_STR);//Dictionary.get("CDM.IndexManager.Section"));
+	    level_combobox.setEditable(false);
+	    Dictionary.registerTooltip(level_combobox, "CDM.IndexManager.Level_Tooltip");
+
+	    JPanel button_pane = new JPanel();
+	    add_button = new GLIButton();
+	    add_button.setEnabled(false);
+	    add_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add_button, "CDM.IndexManager.Add_Index", "CDM.IndexManager.Add_Index_Tooltip");
+
+	    remove_button = new GLIButton();
+	    remove_button.setEnabled(false);
+	    remove_button.setMnemonic(KeyEvent.VK_R);
+	    Dictionary.registerBoth(remove_button, "CDM.IndexManager.Remove_Index", "CDM.IndexManager.Remove_Index_Tooltip");
+	    replace_button = new GLIButton();
+	    replace_button.setEnabled(false);
+	    replace_button.setMnemonic(KeyEvent.VK_P);
+	    Dictionary.registerBoth(replace_button, "CDM.IndexManager.MGPP.Replace_Index", "CDM.IndexManager.MGPP.Replace_Index_Tooltip");
+
+	    // This class is getting a little crowded, so I'll generate the many mgpp controls in a inner class.
+	    mgppindexes_control = new MGPPControl();
+
+	    // Listeners
+	    add_button.addActionListener(new AddListener());
+	    add_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    move_down_button.addActionListener(new MoveListener(false));
+	    move_down_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    move_up_button.addActionListener(new MoveListener(true));
+	    move_up_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    remove_button.addActionListener(new RemoveListener());
+	    remove_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    replace_button.addActionListener(new ReplaceListener());
+	    replace_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    set_default_button.addActionListener(new SetDefaultListener());
+	    set_default_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    name_textfield.getDocument().addDocumentListener(new NameListener());
+	    level_combobox.addItemListener(new LevelListener());
+	    // Create the index_list_listener but don't add in to the list - this gets done in gainFocus, we don't want it twice.
+	    index_list_listener = new IndexListListener();
+	    source_list.addListSelectionListener(new SourceListListener());
+
+	    // Layout
+	    instruction_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    instruction_pane.setLayout(new BorderLayout());
+	    instruction_pane.add(title_label, BorderLayout.NORTH);
+	    instruction_pane.add(new JScrollPane(instruction_textarea), BorderLayout.CENTER);
+
+	    movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
+	    movement_pane.setLayout(new GridLayout(3,1));
+	    movement_pane.add(move_up_button);
+	    movement_pane.add(move_down_button);
+	    movement_pane.add(set_default_button);
+
+	    assigned_indexes_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    assigned_indexes_pane.setLayout(new BorderLayout());
+	    assigned_indexes_pane.add(index_label, BorderLayout.NORTH);
+	    assigned_indexes_pane.add(new JScrollPane(index_list), BorderLayout.CENTER);
+	    assigned_indexes_pane.add(movement_pane, BorderLayout.EAST);
+
+	    labels_pane.setLayout(new BorderLayout());
+	    labels_pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 10, 5));
+	    labels_pane.add(name_label, BorderLayout.NORTH);
+	    labels_pane.add(source_label, BorderLayout.CENTER);
+	    labels_pane.add(level_label, BorderLayout.SOUTH);
+	    
+	    boxes_pane.setLayout(new BorderLayout());
+	    boxes_pane.add(name_textfield, BorderLayout.NORTH);
+	    boxes_pane.add(new JScrollPane(source_list), BorderLayout.CENTER);
+	    boxes_pane.add(level_combobox, BorderLayout.SOUTH);
+	    
+	    details_pane.setLayout(new BorderLayout());
+	    details_pane.add(labels_pane, BorderLayout.WEST);
+	    details_pane.add(boxes_pane, BorderLayout.CENTER);
+
+	    button_pane.setLayout(new GridLayout(1,3));
+	    button_pane.add(add_button);
+	    button_pane.add(replace_button);
+	    button_pane.add(remove_button);
+
+	    index_pane.setLayout(new BorderLayout());
+	    index_pane.add(details_pane, BorderLayout.CENTER);
+	    index_pane.add(button_pane, BorderLayout.SOUTH);
+
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(assigned_indexes_pane, BorderLayout.NORTH);
+	    content_pane.add(index_pane, BorderLayout.CENTER);
+
+	    mgindexes_panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    mgindexes_panel.setLayout(new BorderLayout());
+	    mgindexes_panel.add(instruction_pane, BorderLayout.NORTH);
+	    mgindexes_panel.add(content_pane, BorderLayout.CENTER);
+
+	    setLayout(card_layout);
+	    add(mgindexes_panel, MGINDEXES);
+	    add(mgppindexes_control, MGPPINDEXES);
+	}
+
+	
+	/* Destructor, removes persistant listeners from the Dictionary.
+	 */
+	public void destroy() {
+	    mgppindexes_control.destroy();
+	    mgppindexes_control = null;
+	}
+
+	public void gainFocus() {
+	    boolean mgpp_enabled = CollectionDesignManager.searchtype_manager.isMGPPEnabled();
+	    if(instruction_textarea != null) {
+		instruction_textarea.setCaretPosition(0);
+	    }
+	    if(mgpp_enabled) {
+		// remove the mg index list listener first
+		index_list.removeListSelectionListener(index_list_listener);
+		mgppindexes_control.gainFocus();
+	    }
+	    else {
+		// remove the mgpp listener first
+		mgppindexes_control.removeIndexListListener();
+		// add the mg listener back in
+		index_list.addListSelectionListener(index_list_listener);
+		// Reload the assigned indexes list.
+		ArrayList new_data = new ArrayList();
+		new_data.add(CollectionConfiguration.TEXT_STR);
+		new_data.addAll(MetadataSetManager.getEveryMetadataSetElement());
+		// reset the model in the list and combobox
+		source_list.setListData(new_data);
+		new_data = null;
+		// refresh the indexList
+		index_list.updateUI();
+		// if there is one selected, fill in the controls
+		updateControlsWithSelectedIndex();
+	    }
+	    // Bring the appropriate card to the front
+	    if(mgpp_enabled) {
+		card_layout.show(this, MGPPINDEXES);
+	    }
+	    else {
+		card_layout.show(this, MGINDEXES);
+	    }
+	}
+
+	public void loseFocus() {
+	}
+
+	private void updateControlsWithSelectedIndex() {
+	    
+	    Index selected_index = (Index)index_list.getSelectedValue();
+	    if (selected_index == null) {
+		return;
+	    }
+	    String id = selected_index.getID();
+	    if (id == null || id.equals("")) {
+		return;
+	    }
+	    String name = CollectionDesignManager.collectionmeta_manager.getMetadatum("." + id).getValue(true);
+	    name_textfield.setText(name);
+	    level_combobox.setSelectedIndex(selected_index.getLevel());
+	    source_list.clearTicked();
+	    ArrayList sources = selected_index.getSources();
+	    source_list.setTickedObjects(sources.toArray());
+	   
+	}
+	
+	private void validateAddButton()
+	{
+	    boolean add_enabled = false;
+	    boolean replace_enabled = false;
+
+	    // Indexes must have a name
+	    if (name_textfield.getText().length() == 0) {
+		add_enabled = false;
+	    }
+	    // Can't add a new index if no sources are selected
+	    else if (source_list.isNothingTicked()) {
+		add_enabled = false;
+	    }
+	    // If we get this far, create a dummy index and see if it's already assigned in the collection
+	    else {
+		Object object[] = source_list.getTicked().toArray();
+		ArrayList sources = new ArrayList();
+		for(int i = 0; i < object.length; i++) {
+		    sources.add(object[i]);
+		}
+		object = null;
+		Index index = new Index(level_combobox.getSelectedIndex(), sources);
+		sources = null;
+		if (model.contains(index)) {
+		    add_enabled = false;
+
+		    // Here we need to check if we have changed the name - if so, we can enable the replace button
+		    if (index_list.getSelectedIndex() != -1) {
+			Index selected_index = (Index)index_list.getSelectedValue();
+			String name = name_textfield.getText();
+			String index_name = CollectionDesignManager.collectionmeta_manager.getMetadatum(CollectionConfiguration.STOP_CHARACTER+selected_index.getID()).getValue(true);
+			if (!index_name.equals(name)){
+			    replace_enabled = true;
+			}
+		    }
+		}
+		else {
+		    add_enabled = true;
+
+		    // We have a new index, do we have something selected in the index list? if so, enable the replace button
+		    if (index_list.getSelectedIndex() != -1) {
+			replace_enabled = true;
+		    }
+		}
+	    }
+
+	    // We should now know the add_button state
+	    add_button.setEnabled(add_enabled);
+	    replace_button.setEnabled(replace_enabled);
+	}
+
+
+	private class AddListener
+	    implements ActionListener
+	{
+	    public void actionPerformed(ActionEvent event)
+	    {
+		String name = name_textfield.getText();
+		if (!source_list.isNothingTicked() && name.length() != 0) {
+		    ArrayList sources = source_list.getTicked();
+		    Index index = new Index(level_combobox.getSelectedIndex(), sources);
+
+		    // Before we add the index to the model, we have to add the collection metadata for this
+		    CollectionMeta metadatum = new CollectionMeta(CollectionConfiguration.STOP_CHARACTER + index.getID());
+		    metadatum.setValue(name);
+
+		    // Finally, add the index
+		    addIndex(index, metadatum);
+		    index_list.setSelectedValue(index, true);
+		}
+	    }
+	}
+
+
+	/** Listens for selections within the list on the IndexManager controls, and if a change is detected enables, or disables, controls appropriately. */
+	private class IndexListListener
+	    implements ListSelectionListener
+	{
+	    /** This method is called whenever the source list selection changes. When it does we need to fill in the various parts of the list description panel
+	     * @param event A <strong>ListSelectionEvent</strong> containing further information about the list selection.
+	     */
+	    public void valueChanged(ListSelectionEvent event)
+	    {
+		if (event.getValueIsAdjusting()) {
+		    return;
+		}
+
+		Object value = index_list.getSelectedValue();
+		if (value == null) {
+		    move_down_button.setEnabled(false);
+		    move_up_button.setEnabled(false);
+		    remove_button.setEnabled(false);
+		    replace_button.setEnabled(false);
+		    set_default_button.setEnabled(false);
+		    return;
+		}
+
+		// Enable the buttons appropriately
+		remove_button.setEnabled(true);
+		set_default_button.setEnabled(default_index == null || !default_index.equals(value));
+		int i = index_list.getSelectedIndex();
+		int size = index_list.getModel().getSize();
+		if (i > 0) {
+		    move_up_button.setEnabled(true);
+		}
+		else {
+		    move_up_button.setEnabled(false);
+		}
+		if (i < size-1){
+		    move_down_button.setEnabled(true);
+		}
+		else {
+		    move_down_button.setEnabled(false);
+		}
+
+		// Need to fill in the rest of the bits
+		updateControlsWithSelectedIndex();		
+	    }
+	}
+
+	private class IndexListRenderer
+	    extends DefaultListCellRenderer {
+
+	    /** Return a component that has been configured to display the specified value. */
+	    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+		JLabel component = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+		if(default_index != null && default_index.equals(value)) {
+		    component.setText(component.getText() + " " + Dictionary.get("CDM.IndexManager.Default_Index_Indicator"));
+		}
+		return component;
+	    }
+
+	}
+
+	private class LevelListener
+	    implements ItemListener {
+	    public void itemStateChanged(ItemEvent event) {
+		if(event.getStateChange() == ItemEvent.SELECTED) {
+		    // just want to validate the add button
+		    validateAddButton();
+
+		}
+	    }
+	}
+
+	private class MoveListener
+	    implements ActionListener {
+
+	    private boolean move_up;
+
+	    public MoveListener(boolean move_up) {
+		this.move_up = move_up;
+	    }
+
+	    public void actionPerformed(ActionEvent event) {
+		// Retrieve the selected index
+		Index index = (Index) index_list.getSelectedValue();
+		if(index != null) {
+		    moveIndex(index, move_up);
+		    // Ensure the index that moved is still selected
+		    index_list.setSelectedValue(index, true);
+		    index = null;
+		}
+	    }
+	}
+
+
+	/** Listens for key presses within the name field, and enabled or disables controls as appropriate. */
+	private class NameListener
+	    implements DocumentListener
+	{
+	    public void changedUpdate(DocumentEvent e)
+	    {
+		validateAddButton();
+	    }
+
+	    public void insertUpdate(DocumentEvent e)
+	    {
+		validateAddButton();
+	    }
+
+	    public void removeUpdate(DocumentEvent e)
+	    {
+		validateAddButton();
+	    }
+	}
+
+
+	private class RemoveListener
+	    implements ActionListener
+	{
+	    public void actionPerformed(ActionEvent event)
+	    {
+		int i = index_list.getSelectedIndex();
+		if (i != -1) {
+		    removeIndex((Index) index_list.getSelectedValue());
+		}
+		int size = index_list.getModel().getSize();
+		if (i == size) {
+		    i--;
+		}
+		index_list.setSelectedIndex(i);
+
+		// This will produce an event on the list, updating the other buttons
+		if (size == 0) {
+		    // We have removed the last index, should be able to add what's filled in currently, if valid
+		    validateAddButton();
+		}
+	    }
+	}
+
+
+	private class ReplaceListener
+	    implements ActionListener
+	{
+	    public void actionPerformed(ActionEvent event)
+	    {
+		if (index_list.isSelectionEmpty()) {
+		    // This should never happen, but just in case...
+		    replace_button.setEnabled(false);
+		    return;
+		}
+
+		// We'll just remove the old one and add the new one
+		removeIndex((Index) index_list.getSelectedValue());
+		replace_button.setEnabled(false);
+		add_button.setEnabled(true);
+		add_button.doClick();
+		add_button.setEnabled(false);
+	    }
+	}
+
+
+	private class SetDefaultListener
+	    implements ActionListener {
+
+	    public void actionPerformed(ActionEvent event) {
+		Index index = (Index) index_list.getSelectedValue();
+		if(index != null) {
+		    setDefault(index);
+		    // This should cause a repaint of just the desired row
+		    index_list.setSelectedValue(index, true);
+		}
+		set_default_button.setEnabled(false);
+	    }
+	}
+
+
+	private class SourceListListener
+	    implements ListSelectionListener
+	{
+	    public void valueChanged(ListSelectionEvent event)
+	    {
+		validateAddButton();
+	    }
+	}
+    }
+
+    private class MGPPControl
+	extends JPanel {
+
+	private GComboBox index_combobox;
+	private GComboBox level_combobox;
+	private JButton add_index_button;
+	private JButton add_all_button;
+	private JButton add_level_button;
+	private JButton move_index_down_button;
+	private JButton move_level_down_button;
+	private JButton move_index_up_button;
+	private JButton move_level_up_button;
+	private JButton replace_index_button;
+	private JButton remove_index_button;
+	private JButton remove_level_button;
+	private JLabel current_levels_label;
+	private JLabel current_indexes_label;
+	private JLabel index_label;
+	private JLabel index_name_label;
+	private JLabel level_label;
+	private JLabel level_name_label;
+	private JLabel move_index_down_label;
+	private JLabel move_level_down_label;
+	private JLabel move_index_up_label;
+	private JLabel move_level_up_label;
+	private JLabel title_label;
+	private JList current_levels_list;
+	private JList current_indexes_list;
+	private JTabbedPane tabbed_pane;
+	private JTextArea instructions_textarea;
+	private JTextField index_name_field;
+	private JTextField level_name_field;
+	
+	// when we are in mg mode, we want to remove the mgpp listener 
+	// the underlying model is the same between the two JLists, and
+	// both listeners get notified when the model changes, but the mgpp
+	// listener doesn't care about mg events
+	private ListSelectionListener mgpp_index_list_listener;
+	
+	public MGPPControl() {
+	    // Create Indexes
+	    JPanel indexes_panel = new JPanel();
+
+	    JPanel current_indexes_panel = new JPanel();
+
+	    current_indexes_label = new JLabel();
+	    Dictionary.registerText(current_indexes_label, "CDM.IndexManager.MGPP.Current_Indexes");
+	    current_indexes_list = new JList(model);
+	    current_indexes_list.setVisibleRowCount(5);
+	    current_indexes_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+	    JPanel index_movement_panel = new JPanel();
+
+	    move_index_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
+	    move_index_up_button.setEnabled(false);
+	    move_index_up_button.setMnemonic(KeyEvent.VK_U);
+	    Dictionary.registerBoth(move_index_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
+
+	    move_index_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
+	    move_index_down_button.setEnabled(false);
+	    move_index_down_button.setMnemonic(KeyEvent.VK_D);
+	    Dictionary.registerBoth(move_index_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
+
+	    JPanel index_spacer_panel = new JPanel();
+	    JPanel index_body_panel = new JPanel();
+	    JPanel index_details_panel = new JPanel();
+	    JPanel index_labels_panel = new JPanel();
+
+	    index_name_label = new JLabel();
+	    Dictionary.registerText(index_name_label, "CDM.IndexManager.Index_Name");
+
+	    index_name_field = new JTextField();
+	    index_name_field.setPreferredSize(FIELD_SIZE);
+	    Dictionary.registerTooltip(index_name_field, "CDM.IndexManager.Index_Name_Tooltip");
+
+	    JPanel index_boxes_panel = new JPanel();
+
+	    index_label = new JLabel("CDM.IndexManager.MGPP.Index");
+	    Dictionary.registerText(index_label, "CDM.IndexManager.MGPP.Index");
+
+	    index_combobox = new GComboBox();
+	    index_combobox.setPreferredSize(FIELD_SIZE);
+	    index_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
+	    index_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
+	    index_combobox.setEditable(false);  // Warning: setting this to true opens a big can of worms
+	    index_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
+	    index_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.registerTooltip(index_combobox, "CDM.IndexManager.MGPP.Index_Tooltip");
+
+	    JPanel index_button_panel = new JPanel();
+
+	    add_index_button = new GLIButton();
+	    add_index_button.setEnabled(false);
+	    add_index_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add_index_button, "CDM.IndexManager.Add_Index", "CDM.IndexManager.Add_Index_Tooltip");
+
+	    add_all_button = new GLIButton();
+	    add_all_button.setEnabled(true);
+	    add_all_button.setMnemonic(KeyEvent.VK_L);
+	    Dictionary.registerBoth(add_all_button, "CDM.IndexManager.MGPP.Add_All_Metadata", "CDM.IndexManager.MGPP.Add_All_Metadata_Tooltip");
+
+	    replace_index_button = new GLIButton();
+	    replace_index_button.setEnabled(false);
+	    replace_index_button.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.registerBoth(replace_index_button, "CDM.IndexManager.MGPP.Replace_Index", "CDM.IndexManager.MGPP.Replace_Index_Tooltip");
+
+	    remove_index_button = new GLIButton();
+	    remove_index_button.setEnabled(false);
+	    remove_index_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(remove_index_button, "CDM.IndexManager.Remove_Index", "CDM.IndexManager.Remove_Index_Tooltip");
+
+	    JPanel index_empty_panel = new JPanel();
+
+	    // Connect Indexes
+	    EnableAddIndexListener index_eal = new EnableAddIndexListener();
+	    add_index_button.addActionListener(new AddIndexActionListener());
+	    add_all_button.addActionListener(new AddAllActionListener());
+	    
+	    // Create the index_list_listener but don't add in to the list - this gets done in gainFocus, we don't want it twice.
+	    mgpp_index_list_listener = new CurrentIndexesListSelectionListener();
+	    index_combobox.addActionListener(index_eal);
+	    ((JTextField)index_combobox.getEditor().getEditorComponent()).getDocument().addDocumentListener(index_eal);
+	    index_name_field.getDocument().addDocumentListener(index_eal);
+	    move_index_down_button.addActionListener(new MoveIndexDownListener());
+	    move_index_up_button.addActionListener(new MoveIndexUpListener());
+	    replace_index_button.addActionListener(new ReplaceIndexActionListener());
+	    remove_index_button.addActionListener(new RemoveIndexActionListener(index_eal));
+
+	    // Layout Indexes
+	    index_movement_panel.setLayout(new GridLayout(2,1));
+	    index_movement_panel.add(move_index_up_button);
+	    index_movement_panel.add(move_index_down_button);
+
+	    current_indexes_panel.setLayout(new BorderLayout());
+	    current_indexes_panel.add(current_indexes_label, BorderLayout.NORTH);
+	    current_indexes_panel.add(new JScrollPane(current_indexes_list), BorderLayout.CENTER);
+	    current_indexes_panel.add(index_movement_panel, BorderLayout.EAST);
+
+
+	    index_labels_panel.setLayout(new GridLayout(2,1));
+	    index_labels_panel.add(index_name_label);
+	    index_labels_panel.add(index_label);
+
+	    index_boxes_panel.setLayout(new GridLayout(2,1));
+	    index_boxes_panel.add(index_name_field);
+	    index_boxes_panel.add(index_combobox);
+
+	    index_details_panel.setLayout(new BorderLayout(5,0));
+	    index_details_panel.add(index_labels_panel, BorderLayout.WEST);
+	    index_details_panel.add(index_boxes_panel, BorderLayout.CENTER);
+
+	    index_button_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    index_button_panel.setLayout(new GridLayout(2,2,5,0));
+	    index_button_panel.add(add_index_button);
+	    index_button_panel.add(add_all_button);
+	    index_button_panel.add(replace_index_button);
+	    index_button_panel.add(remove_index_button);
+
+	    index_body_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    index_body_panel.setLayout(new BorderLayout());
+	    index_body_panel.add(index_details_panel, BorderLayout.CENTER);
+	    index_body_panel.add(index_button_panel, BorderLayout.SOUTH);
+
+	    index_spacer_panel.setLayout(new BorderLayout());
+	    index_spacer_panel.add(index_body_panel, BorderLayout.NORTH);
+	    index_spacer_panel.add(index_empty_panel, BorderLayout.CENTER);
+
+	    indexes_panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    indexes_panel.setLayout(new BorderLayout());
+	    indexes_panel.add(current_indexes_panel, BorderLayout.NORTH);
+	    indexes_panel.add(index_spacer_panel, BorderLayout.CENTER);
+
+	    // Create Levels
+	    JPanel levels_panel = new JPanel();
+
+	    JPanel current_levels_panel = new JPanel();
+
+	    current_levels_label = new JLabel();
+	    Dictionary.registerText(current_levels_label, "CDM.IndexManager.MGPP.Current_Levels");
+
+	    current_levels_list = new JList(levels_model);
+	    current_levels_list.setVisibleRowCount(5);
+	    current_levels_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	    JPanel level_movement_panel = new JPanel();
+
+	    move_level_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
+	    move_level_up_button.setEnabled(false);
+	    move_level_up_button.setMnemonic(KeyEvent.VK_U);
+	    Dictionary.registerBoth(move_level_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
+
+	    move_level_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
+	    move_level_down_button.setEnabled(false);
+	    move_level_down_button.setMnemonic(KeyEvent.VK_D);
+	    Dictionary.registerBoth(move_level_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
+
+	    JPanel level_spacer_panel = new JPanel();
+	    JPanel level_body_panel = new JPanel();
+	    JPanel level_details_panel = new JPanel();
+	    JPanel level_labels_panel = new JPanel();
+	    JPanel level_boxes_panel = new JPanel();
+
+	    level_name_label = new JLabel();
+	    Dictionary.registerText(level_name_label, "CDM.IndexManager.MGPP.Level_Name");
+
+	    level_name_field = new JTextField();
+	    level_name_field.setPreferredSize(FIELD_SIZE);
+	    Dictionary.registerTooltip(level_name_field, "CDM.IndexManager.MGPP.Level_Name_Tooltip");
+
+
+	    level_label = new JLabel();
+	    Dictionary.registerText(level_label, "CDM.IndexManager.MGPP.Level");
+
+	    level_combobox = new GComboBox(Index.LEVEL);
+	    level_combobox.setPreferredSize(FIELD_SIZE);
+	    level_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
+	    level_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
+	    level_combobox.setEditable(false);
+	    level_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
+	    level_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.registerTooltip(level_combobox, "CDM.IndexManager.Level_Tooltip");
+
+	    JPanel level_button_panel = new JPanel();
+
+	    add_level_button = new GLIButton("CDM.IndexManager.MGPP.Add_Level");
+	    add_level_button.setEnabled(false);
+	    add_level_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add_level_button, "CDM.IndexManager.MGPP.Add_Level", "CDM.IndexManager.MGPP.Add_Level_Tooltip");
+
+	    remove_level_button = new GLIButton("CDM.IndexManager.MGPP.Remove_Level");
+	    remove_level_button.setEnabled(false);
+	    remove_level_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(remove_level_button, "CDM.IndexManager.MGPP.Remove_Level", "CDM.IndexManager.MGPP.Remove_Level_Tooltip");
+
+	    JPanel level_empty_panel = new JPanel();
+
+	    // Connect Levels
+	    EnableAddLevelListener level_eal = new EnableAddLevelListener();
+	    add_level_button.addActionListener(new AddLevelActionListener());
+	    current_levels_list.addListSelectionListener(new CurrentLevelsListSelectionListener());
+	    level_combobox.addActionListener(level_eal);
+	    ((JTextField)level_combobox.getEditor().getEditorComponent()).getDocument().addDocumentListener(level_eal);
+	    level_name_field.getDocument().addDocumentListener(level_eal);
+	    move_level_down_button.addActionListener(new MoveLevelDownListener());
+	    move_level_up_button.addActionListener(new MoveLevelUpListener());
+	    remove_level_button.addActionListener(new RemoveLevelActionListener(level_eal));
+	    // Layout Levels
+
+	    level_movement_panel.setLayout(new GridLayout(2,1));
+	    level_movement_panel.add(move_level_up_button);
+	    level_movement_panel.add(move_level_down_button);
+
+	    current_levels_panel.setLayout(new BorderLayout());
+	    current_levels_panel.add(current_levels_label, BorderLayout.NORTH);
+	    current_levels_panel.add(new JScrollPane(current_levels_list), BorderLayout.CENTER);
+	    current_levels_panel.add(level_movement_panel, BorderLayout.EAST);
+
+	    level_labels_panel.setLayout(new GridLayout(2,1));
+	    level_labels_panel.add(level_name_label);
+	    level_labels_panel.add(level_label);
+
+	    level_boxes_panel.setLayout(new GridLayout(2,1));
+	    level_boxes_panel.add(level_name_field);
+	    level_boxes_panel.add(level_combobox);
+
+	    level_details_panel.setLayout(new BorderLayout(5,0));
+	    level_details_panel.add(level_labels_panel, BorderLayout.WEST);
+	    level_details_panel.add(level_boxes_panel, BorderLayout.CENTER);
+
+	    level_button_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    level_button_panel.setLayout(new GridLayout(1,2,5,0));
+	    level_button_panel.add(add_level_button);
+	    level_button_panel.add(remove_level_button);
+
+	    level_body_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    level_body_panel.setLayout(new BorderLayout());
+	    level_body_panel.add(level_details_panel, BorderLayout.CENTER);
+	    level_body_panel.add(level_button_panel, BorderLayout.SOUTH);
+
+	    level_spacer_panel.setLayout(new BorderLayout());
+	    level_spacer_panel.add(level_body_panel, BorderLayout.NORTH);
+	    level_spacer_panel.add(level_empty_panel, BorderLayout.CENTER);
+
+	    levels_panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    levels_panel.setLayout(new BorderLayout());
+	    levels_panel.add(current_levels_panel, BorderLayout.NORTH);
+	    levels_panel.add(level_spacer_panel, BorderLayout.CENTER);
+
+	    // Create General
+	    JPanel header_panel = new JPanel();
+
+	    title_label = new JLabel();
+	    title_label.setHorizontalAlignment(JLabel.CENTER);
+	    Dictionary.registerText(title_label, "CDM.IndexManager.MGPP.Title");
+
+	    instructions_textarea = new JTextArea();
+	    instructions_textarea.setEditable(false);
+	    instructions_textarea.setLineWrap(true);
+	    instructions_textarea.setRows(6);
+	    instructions_textarea.setWrapStyleWord(true);
+	    Dictionary.registerText(instructions_textarea, "CDM.IndexManager.MGPP.Instructions");
+
+	    tabbed_pane = new JTabbedPane();
+
+	    // Layout General
+	    header_panel.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
+	    header_panel.setLayout(new BorderLayout());
+	    header_panel.add(title_label, BorderLayout.NORTH);
+	    header_panel.add(new JScrollPane(instructions_textarea), BorderLayout.CENTER);
+
+	    tabbed_pane.add(Dictionary.get("CDM.IndexManager.MGPP.Indexes"), indexes_panel);
+	    tabbed_pane.add(Dictionary.get("CDM.IndexManager.MGPP.Levels"), levels_panel);
+
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    add(header_panel, BorderLayout.NORTH);
+	    add(tabbed_pane, BorderLayout.CENTER);
+	}
+
+	public void destroy() {
+	}
+
+	public void gainFocus() {
+	    // add in the mgpp listener
+	    current_indexes_list.addListSelectionListener(mgpp_index_list_listener);
+	    // Reload the assigned indexes list.
+	    index_combobox.removeAllItems();
+	    index_combobox.addItem(CollectionConfiguration.ALLFIELDS_STR);
+	    index_combobox.addItem(CollectionConfiguration.METADATA_STR);
+	    index_combobox.addItem(CollectionConfiguration.TEXT_STR);
+	    ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+	    for(int i = 0; i < every_metadata_set_element.size(); i++) {
+		index_combobox.addItem(every_metadata_set_element.get(i));
+	    }
+	    // Ensure the level manager has at least documents assigned
+	    if(levels_model.getSize() == 0) {
+		Level level = new Level(CollectionConfiguration.DOCUMENT_STR);
+		// Create new metadatum
+		CollectionMeta metadatum = new CollectionMeta(CollectionConfiguration.STOP_CHARACTER + CollectionConfiguration.DOCUMENT_STR);
+		metadatum.setValue(CollectionConfiguration.DOCUMENT_STR);
+		// Assign new level
+		addLevel(level, metadatum);	    
+		level = null;
+	    }
+
+	    // refresh
+	    current_indexes_list.updateUI();
+	}
+	
+	public void removeIndexListListener() {
+
+	    current_indexes_list.removeListSelectionListener(mgpp_index_list_listener);
+	}
+	
+	private class AddIndexActionListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		// Retrieve the name
+		String name = index_name_field.getText();
+		// Retrieve the source
+		Object source = index_combobox.getSelectedItem();
+
+		// If this object isn't yet in the combobox add it.
+		if(index_combobox.getSelectedIndex() == -1) {
+		    index_combobox.insertItemAt(source, index_combobox.getItemCount());
+		}
+		// Create new index
+		ArrayList sources = new ArrayList();
+		sources.add(source);
+		Index index = new Index(sources);
+		if(!model.contains(index)) {
+		    // Create new metadatum
+		    CollectionMeta metadatum = new CollectionMeta(CollectionConfiguration.STOP_CHARACTER + index.getID());
+		    metadatum.setValue(name);
+		    // Assign new index
+		    addIndex(index, metadatum);
+		    current_indexes_list.setSelectedValue(index, true);
+		}
+		// Done. Disable add
+		add_index_button.setEnabled(false);
+	    }
+	}
+
+	private class AddAllActionListener
+	    implements ActionListener {
+
+	    public void actionPerformed(ActionEvent event) {
+		for(int i = 0; i < index_combobox.getItemCount(); i++) {
+		    Object source = index_combobox.getItemAt(i);
+		    // Create new index
+		    ArrayList sources = new ArrayList();
+		    sources.add(source);
+		    Index index = new Index(sources);
+		    sources = null;
+		    if(!model.contains(index)) {
+			// Determine the metadatum value
+			String name = source.toString();
+			if(name.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
+			    name = name.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
+			}
+			// Create new metadatum
+			CollectionMeta metadatum = new CollectionMeta(CollectionConfiguration.STOP_CHARACTER + index.getID());
+			metadatum.setValue(name);
+			name = null;
+			// Assign new index
+			addIndex(index, metadatum);
+		    }
+		    source = null;
+		    index = null;
+		}
+		// Done. Disable add
+		add_index_button.setEnabled(false);
+	    }
+	}
+
+	private class AddLevelActionListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		// Retrieve the name
+		String name = level_name_field.getText();
+		// Retrieve the source
+		String source = (String)level_combobox.getSelectedItem();
+		Level level = new Level(source);
+		// Create new metadatum
+		CollectionMeta metadatum = new CollectionMeta(CollectionConfiguration.STOP_CHARACTER + source);
+		metadatum.setValue(name);
+		// Assign new level
+		int size = levels_model.getSize();
+		addLevel(level, metadatum);
+		current_levels_list.setSelectedValue(level, true);
+		add_level_button.setEnabled(false);
+	    }
+	}
+
+	private class CurrentIndexesListSelectionListener
+	    implements ListSelectionListener {
+	    public void valueChanged(ListSelectionEvent event) {
+		if(event.getValueIsAdjusting()) {
+		    return;
+		}
+		
+		Index index = (Index)current_indexes_list.getSelectedValue();
+		if(index != null) {
+		    String full_text = index.toString();
+		    if(full_text.indexOf("\"") != -1) {
+			index_name_field.setText(index.getName());
+		    }
+		    ArrayList sources = index.getSources();
+		    index_combobox.setSelectedItem(sources.get(0));
+		    
+		    
+		    move_index_down_button.setEnabled((model.indexOf(index) < model.getSize() - 1));
+		    move_index_up_button.setEnabled((model.indexOf(index) > 0));
+		    remove_index_button.setEnabled(true);
+		}
+		else {
+		    move_index_down_button.setEnabled(false);
+		    move_index_up_button.setEnabled(false);
+		    remove_index_button.setEnabled(false);
+		}
+	    }	    
+	}
+
+	private class CurrentLevelsListSelectionListener
+	    implements ListSelectionListener {
+	    public void valueChanged(ListSelectionEvent event) {
+		
+		if(event.getValueIsAdjusting()) {
+		    return;
+		}
+		
+		Level level = (Level)current_levels_list.getSelectedValue();
+		if(level != null) {
+		    String full_text = level.toString();
+		    if(full_text.indexOf("\"") != -1) {
+			level_name_field.setText(level.getName());
+		    }
+		    String level_id = level.getLevel();
+		    level_combobox.setSelectedItem(level_id);
+		    move_level_down_button.setEnabled((levels_model.indexOf(level) < levels_model.getSize() - 1));
+		    move_level_up_button.setEnabled((levels_model.indexOf(level) > 0));
+		    remove_level_button.setEnabled(true);
+		}
+		else {
+		    move_level_down_button.setEnabled(false);
+		    move_level_up_button.setEnabled(false);
+		    remove_level_button.setEnabled(false);
+		}
+	    }
+	}
+
+	private class EnableAddIndexListener
+	    implements ActionListener, DocumentListener {
+	    /** Called whenever a selection action occurs on the combobox.
+	     * @param  event an ActionEvent containing information about the selection event
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		validateAddButtonIndex();
+	    }
+
+	    /** Gives notification that an attribute or set of attributes changed.
+	     * @param  event a DocumentEvent containing information about the text changed
+	     */
+	    public void changedUpdate(DocumentEvent event) {
+		validateAddButtonIndex();
+	    }
+
+	    /** Gives notification that there was an insert into the document.
+	     * @param  event a DocumentEvent containing information about the text added
+	     */
+	    public void insertUpdate(DocumentEvent event) {
+		validateAddButtonIndex();
+	    }
+
+	    /** Gives notification that a portion of the document has been removed.
+	     * @param  event a DocumentEvent containing information about the text removed
+	     */
+	    public void removeUpdate(DocumentEvent event) {
+		validateAddButtonIndex();
+	    }
+
+	    /** Change the enable state of the add button depending on the current value in the search type combobox. */
+	    public void validateAddButtonIndex() {
+		String name = index_name_field.getText();
+		Object selected_object = index_combobox.getSelectedItem();
+		boolean add_enabled = false;
+		boolean replace_enabled = false;
+
+		if(name.length() > 0 && selected_object != null) {
+		    // Unfortunately we have to generate a valid id
+		    String id = null;
+		    // Special cases
+		    if (selected_object instanceof String && (selected_object.equals(CollectionConfiguration.ALLFIELDS_STR) || selected_object.equals(CollectionConfiguration.METADATA_STR) || selected_object.equals(CollectionConfiguration.TEXT_STR))) {
+			id = (String) selected_object;
+		    }
+		    else if (selected_object instanceof MetadataElement) {
+			id = ((MetadataElement) selected_object).getFullName();
+		    }
+		    else {
+			System.err.println("Internal Error: Unexpected selected_object in IndexManager.");
+			return;
+		    }
+		    if(id.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
+			id = id.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
+		    }
+		    
+		    Index index = getIndex(id);
+		    if(index == null) {
+			add_enabled = true;
+			// we have a new index. is something selected? if so, we can replace
+			if (current_indexes_list.getSelectedIndex() != -1) {
+			    replace_enabled = true;
+			}
+		    }
+		    else {
+			// the index is already there
+			add_enabled = false;
+			// but if the name is changed, we can do a replace
+			if(!name.equals(index.getName())) {
+			    replace_enabled = true;
+			}
+			
+		    }
+		}
+		else {
+		    add_enabled = false;
+		    replace_enabled = false;
+		    
+		}
+
+		// We should now know the button state
+		add_index_button.setEnabled(add_enabled);
+		replace_index_button.setEnabled(replace_enabled);
+		
+	    }
+	}
+
+	private class EnableAddLevelListener
+	    implements ActionListener, DocumentListener {
+	    /** Called whenever a selection action occurs on the combobox.
+	     * @param  event an ActionEvent containing information about the selection event
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		validateAddButtonLevel();
+	    }
+
+	    /** Gives notification that an attribute or set of attributes changed.
+	     * @param  event a DocumentEvent containing information about the text changed
+	     */
+	    public void changedUpdate(DocumentEvent event) {
+		validateAddButtonLevel();
+	    }
+
+	    /** Gives notification that there was an insert into the document.
+	     * @param  event a DocumentEvent containing information about the text added
+	     */
+	    public void insertUpdate(DocumentEvent event) {
+		validateAddButtonLevel();
+	    }
+
+	    /** Gives notification that a portion of the document has been removed.
+	     * @param  event a DocumentEvent containing information about the text removed
+	     */
+	    public void removeUpdate(DocumentEvent event) {
+		validateAddButtonLevel();
+	    }
+    
+	    /** Change the enable state of the add button depending on the current value in the search type combobox. */
+	    public void validateAddButtonLevel() {
+		String name = level_name_field.getText();
+		Object selected_object = level_combobox.getSelectedItem();
+		if(name.length() > 0 && selected_object != null) {
+		    add_level_button.setEnabled(getLevel((String)selected_object) == null);
+		}
+		else {
+		    add_level_button.setEnabled(false);
+		}
+	    }
+	}
+
+	private class MoveIndexDownListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		// Retrieve the first selected item
+		Index index = (Index) current_indexes_list.getSelectedValue();
+		moveIndex(index, false);
+		current_indexes_list.setSelectedValue(index, true);
+	    }
+	}
+
+	private class MoveLevelDownListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		// Retrieve the first selected item
+		Level level = (Level) current_levels_list.getSelectedValue();
+		moveLevel(level, false);
+		current_levels_list.setSelectedValue(level, true);
+	    }
+	}
+
+	private class MoveIndexUpListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		// Retrieve the first selected item
+		Index index = (Index) current_indexes_list.getSelectedValue();
+		moveIndex(index, true);
+		current_indexes_list.setSelectedValue(index, true);
+	    }
+	}
+
+	private class MoveLevelUpListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		// Retrieve the first selected item
+		Level level = (Level) current_levels_list.getSelectedValue();
+		moveLevel(level, true);
+		current_levels_list.setSelectedValue(level, true);
+	    }
+	}
+
+	/** Replace really only replaces the string. */
+	private class ReplaceIndexActionListener
+	    implements ActionListener {
+
+	    public void actionPerformed(ActionEvent event) {
+		// We'll just remove the old one and add the new one
+		removeIndex((Index) current_indexes_list.getSelectedValue());
+		replace_index_button.setEnabled(false);
+		add_index_button.setEnabled(true);
+		add_index_button.doClick(); // this adds the new one
+		add_index_button.setEnabled(false);
+		
+		//Object[] selected_objects = current_indexes_list.getSelectedValues();
+		//if(selected_objects.length == 1) {
+		Index index = (Index)current_indexes_list.getSelectedValue();
+		if (index != null) {
+		//Index index = (Index) selected_objects[0];
+		    // Remove old name
+		    CollectionDesignManager.collectionmeta_manager.removeMetadata(CollectionConfiguration.STOP_CHARACTER + index.getID());
+		    // Enter new name
+		    String name = index_name_field.getText();
+		    // Create new metadatum
+		    CollectionMeta metadatum = new CollectionMeta(CollectionConfiguration.STOP_CHARACTER + index.getID());
+		    //index = null;
+		    metadatum.setValue(name);
+		    name = null;
+		    // Assign new index
+		    CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
+		    metadatum = null;
+		}
+		//current_indexes_list.setSelectedValue(selected_objects[0], true);
+		current_indexes_list.setSelectedValue(index, true);
+		// Done. Disable add
+		add_index_button.setEnabled(false);
+		replace_index_button.setEnabled(false);
+	    }
+	}
+
+	private class RemoveIndexActionListener
+	    implements ActionListener {
+
+	    private EnableAddIndexListener eal = null;
+
+	    public RemoveIndexActionListener(EnableAddIndexListener eal) {
+		this.eal = eal;
+	    }
+
+	    public void actionPerformed(ActionEvent event) {
+		// Retrieve the selected items
+		//Object[] selected_objects = current_indexes_list.getSelectedValues();
+		// Clear selection
+		//current_indexes_list.clearSelection();
+		//for(int i = 0; i < selected_objects.length; i++) {
+		//    Index index = (Index) selected_objects[i];
+		    // Remove any related metadata
+		//    CollectionDesignManager.collectionmeta_manager.removeMetadata(CollectionConfiguration.STOP_CHARACTER + index.getID());
+		    // Remove the index
+		//    removeIndex(index);
+		//}
+		// Disable remove button
+		//remove_index_button.setEnabled(false);
+		// Check if add should be reenabled
+		//eal.validateAddButtonIndex();
+		int i = current_indexes_list.getSelectedIndex();
+		if (i != -1) {
+		    Index index = (Index) current_indexes_list.getSelectedValue();
+		    // Remove any related metadata
+		    CollectionDesignManager.collectionmeta_manager.removeMetadata(CollectionConfiguration.STOP_CHARACTER + index.getID());
+		    removeIndex(index);
+		    
+		//if (i != -1) {
+		//removeIndex((Index) index_list.getSelectedValue());
+		    //}
+		    int size = current_indexes_list.getModel().getSize();
+		    if (i == size) {
+			i--;
+		    }
+		    current_indexes_list.setSelectedIndex(i);
+		}
+		if (i==-1) {
+		    // empty list, disable remove button
+		    remove_index_button.setEnabled(false);
+		}
+		// Check if add should be reenabled
+		eal.validateAddButtonIndex();
+
+		// This will produce an event on the list, updating the other buttons
+		//if (size == 0) {
+		    // We have removed the last index, should be able to add what's filled in currently, if valid
+		// validateAddButton();
+		//	}
+	    }
+	}
+
+	private class RemoveLevelActionListener
+	    implements ActionListener {
+
+	    private EnableAddLevelListener eal = null;
+
+	    public RemoveLevelActionListener(EnableAddLevelListener eal) {
+		this.eal = eal;
+	    }
+
+	    public void actionPerformed(ActionEvent event) {
+		
+		int i = current_levels_list.getSelectedIndex();
+		if (i != -1) {
+		    Level level = (Level) current_levels_list.getSelectedValue();
+		    CollectionDesignManager.collectionmeta_manager.removeMetadata(CollectionConfiguration.STOP_CHARACTER + level.getLevel());
+		    removeLevel(level);
+		    if (i == current_levels_list.getModel().getSize()) {
+			i--;
+		    }
+		    current_levels_list.setSelectedIndex(i);
+		}
+		// Retrieve the selected items
+		//Object[] selected_objects = current_levels_list.getSelectedValues();
+		// Clear selection
+		//current_levels_list.clearSelection();
+		//for(int i = 0; i < selected_objects.length; i++) {
+		
+		    //Level level = (Level) selected_objects[i];
+		    // Remove any related metadata
+		    //CollectionDesignManager.collectionmeta_manager.removeMetadata(CollectionConfiguration.STOP_CHARACTER + level.getLevel());
+		    // Remove the index
+		    //removeLevel(level);
+		//}
+		
+		if (i==-1) {
+		    // Disable remove button
+		    remove_level_button.setEnabled(false);
+		}
+		// If there are no levels left, put document back in
+// 		if(levels_model.getSize() == 0) {
+// 			Level level = new Level(CollectionConfiguration.DOCUMENT_STR);
+// 			// Create new metadatum
+// 			CollectionMeta metadatum = new CollectionMeta(CollectionConfiguration.STOP_CHARACTER + CollectionConfiguration.DOCUMENT_STR);
+// 			metadatum.setValue(CollectionConfiguration.DOCUMENT_STR);
+// 			// Assign new level
+// 			addLevel(level, metadatum);	    
+// 			level = null;
+// 		}
+		// Check if add should be reenabled
+		eal.validateAddButtonLevel();
+	    }
+	}
+    } // MGPPControls
+
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Language.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Language.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Language.java	(revision 10506)
@@ -0,0 +1,140 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+
+import org.w3c.dom.*;
+
+/** A pretty unexciting extension of a two character string, in that it has a field which details if its the default language.
+* @author John Thompson, Greenstone Digital Library, University of Waikato
+* @version 2.1
+*/
+public class Language
+    implements Comparable, DOMProxyListEntry {
+    /** The Element this language entry is based upon. */
+    private Element element = null;
+    /** The two character code for this language. */
+    private String code = null;
+    /** The name of this language. */
+    private String name = null;
+ 
+    public Language() {
+    }
+
+    public Language(Element element) {
+	this.element = element;
+    }
+
+    /** Constructor for a brand new language. */
+    public Language(String code) {
+	this.code = code;
+	// Create the new element
+	element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.LANGUAGE_ELEMENT);
+	element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, code);
+	element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, CollectionConfiguration.TRUE_STR);
+    }
+
+    /** Method to compare two languages for ordering purposes.
+     * @param object the other language as an Object
+     * @return an int which indicates the order between this language and the given one: < 0, 0 or > 0 for before, equal to or after respectively
+     */
+    public int compareTo(Object object) {
+	return toString().compareTo(object.toString());
+    }
+
+    public DOMProxyListEntry create(Element element) {
+	return new Language(element);
+    }
+
+    /** Method to test for the equality of two languages.
+     * @param object The other language as an <strong>Object</strong>.
+     * @return <i>true</i> if the languages are equal, <i>false</i> otherwise.
+     */
+    public boolean equals(Object object) {
+	//return (compareTo(object) == 0);
+	// two langs are equal if their codes are equal
+	if (object instanceof Language) {
+	    return getCode().equals(((Language)object).getCode());
+	}
+	return false;
+    }
+
+    /** Method to retrieve the code of this language.
+     * @return A <strong>String</strong> representing the two letter code.
+     */
+    public String getCode() {
+	if(code == null && element != null) {
+	    code = element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
+	}
+	return code;
+    }
+
+    public Element getElement() {
+	return element;
+    }
+
+    public String getName() {
+	if(name == null) {
+	    String code = getCode();
+	    name = CollectionDesignManager.language_manager.getLanguageName(code);
+	}
+	return name;
+    }
+
+    public boolean isAssigned() {
+	return (element != null && element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.TRUE_STR));
+    }
+
+    public void setAssigned(boolean value) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (value ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    public void setCode(String new_code) {
+	code = new_code;
+	// Set element
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, new_code);
+	}
+	// Reset name
+	name = null;
+    }
+
+    public void setElement(Element new_element) {
+	element = new_element;
+	code = null;
+	name = null;
+    }
+
+    /** Method to display the language code.
+     * @return A <strong>String</strong> representing the language code.
+     */
+    public String toString() {
+	return getName();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/LanguageListCellRenderer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/LanguageListCellRenderer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/LanguageListCellRenderer.java	(revision 10506)
@@ -0,0 +1,43 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+/**************************************************************************************
+ * Written:      11/07/03
+ * Revised:      
+ **************************************************************************************/
+import java.awt.*;
+import javax.swing.*;
+
+/** Provides a renderer which transforms a language code (such as en or fr) into its appropriate name (English and French respectively) before generating the rubberstamping component. */
+public class LanguageListCellRenderer
+    extends DefaultListCellRenderer {
+    
+    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+	return super.getListCellRendererComponent(list, CollectionDesignManager.language_manager.getLanguageName((String)value), index, isSelected, cellHasFocus);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/LanguageManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/LanguageManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/LanguageManager.java	(revision 10506)
@@ -0,0 +1,570 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/** This class manages the language commands, remembering both a list of languages to build indexes in, plus the default language.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class LanguageManager
+    extends DOMProxyListModel {
+
+    static public Document LANGUAGES_DOCUMENT = XMLTools.parseXMLFile("xml/languages.xml", true);
+
+    static final private Dimension COMPONENT_SIZE = new Dimension(125,25);
+
+    /** The visual controls for this manager. */
+    private Control controls = null;
+    /** A reference to this class as a model, for the inner controls class. */
+    private DOMProxyListModel model = null;
+    /** A hashtable of code->name mappings of known languages. */
+    private LinkedHashMap known_languages = null;
+    /** The default language object. */
+    private Language default_language = null;
+ 
+   /** Constructor. */
+    public LanguageManager(Element languages_element) {
+	super(languages_element, CollectionConfiguration.LANGUAGE_ELEMENT, new Language());
+	
+	DebugStream.println("LanguageManager: " + getSize() + " languages parsed.");
+
+	this.model = this;
+	// Retrieve the default language
+	NodeList default_language_elements = CollectionDesignManager.collect_config.getDocumentElement().getElementsByTagName(CollectionConfiguration.LANGUAGE_DEFAULT_ELEMENT);
+	if(default_language_elements.getLength() > 0) {
+	    default_language = new Language((Element)default_language_elements.item(0));
+	}
+	// Load a series of code->language mappings into known_languages, by reading from the 'languages.xml' file, which is essentially a subset of the ISO 639 Standard.
+	known_languages = new LinkedHashMap();
+	/*
+	  try {
+	    File in_file = new File("languages.dat");
+	    FileReader in_reader = new FileReader(in_file);
+	    BufferedReader in = new BufferedReader(in_reader);
+	    String entry = null;
+	    while((entry = in.readLine()) != null) {
+		if(!entry.startsWith("#")) {
+		    StringTokenizer tokenizer = new StringTokenizer(entry);
+		    if(tokenizer.countTokens() >= 2) {
+			String name = tokenizer.nextToken();
+			String code = tokenizer.nextToken().toLowerCase();
+			known_languages.put(code, name);
+		    }
+		}
+	    }
+	    in.close();
+	    in_reader.close();
+	    in = null;
+	    in_reader = null;
+	    in_file = null;
+	}
+	catch (Exception error) {
+	    error.printStackTrace();
+	}
+	*/
+	NodeList language_elements = LANGUAGES_DOCUMENT.getDocumentElement().getElementsByTagName(CollectionConfiguration.LANGUAGE_ELEMENT);
+	for(int i = 0; i < language_elements.getLength(); i++) {
+	    Element language_element = (Element) language_elements.item(i);
+	    String code = language_element.getAttribute(CollectionConfiguration.CODE_ATTRIBUTE);
+	    String name = language_element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
+	    known_languages.put(code.toLowerCase(), name);
+	    name = null;
+	    code = null;
+	    language_element = null;
+	}
+    }
+
+    /** Method to add a new language.
+     * @param language The <strong>Language</strong> to add.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     */
+    private void addLanguage(Language language) {
+	if(!contains(language)) {
+	    Element element = language.getElement();
+	    append(language);
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+
+    public void destroy() {
+	if(controls != null) {
+	    controls.destroy();
+	    controls = null;
+	}
+	known_languages.clear();
+	known_languages = null;
+	default_language = null;
+    }
+
+    /** Method to retrieve the control for this manager.
+     * @return the Control for editing the language partitions
+     */
+    public Control getControls() {
+	if(controls == null) {
+	    // Build controls
+	    controls = new LanguageControl();
+	}
+	return controls;
+    }
+
+    /** Method to retrieve the default language code.
+     * @return A <strong>Language</strong> containing a two letter code.
+     */
+    /* private Language getDefaultLanguage() {
+	// If no default is set...
+	if(default_language != null && default_language.isAssigned()) {
+	    return default_language;
+	}
+	return null;
+	} */
+
+    /** Method to retrieve a certain language object by its code.
+     * @param code The two letter code of a language, as a <strong>String</strong>.
+     * @return The <strong>Language</strong> that matches the given code, or <i>null</i> if no such language exists.
+     */
+    public Language getLanguage(String code) {
+	int size = getSize();
+	for(int i = 0; i < size; i++) {
+	    Language language = (Language) getElementAt(i);
+	    if(language.getCode().equals(code)) {
+		return language;
+	    }
+	}
+	return null;
+    }
+
+    public ArrayList getLanguages() {
+	return children();
+    }
+
+    /** Method to return a list of the known language codes.
+     * @return an ArrayList containing the series of known language codes as per the languages.dat file
+     */
+    public ArrayList getLanguageCodes() {
+	return new ArrayList(known_languages.keySet());
+    }
+
+    public String getLanguageName(String code) {
+	return (String) known_languages.get(code);
+    }
+
+   private int moveLanguage(Language lang, boolean move_up)
+    {
+	// Determine the current position of the language
+	int position = indexOf(lang);
+	int new_position;
+
+	// Attempt to move the language up
+	if (move_up) {
+	    // Check it's not already at the top
+	    if (position == 0) {
+		return position;
+	    }
+
+	    // This automatically removes the language first, as an Element can only exist once in a particular document
+	    new_position = position - 1;
+	    addBefore(lang, (Language) getElementAt(new_position));
+	}
+
+	// Attempt to move the language down
+	else {
+	    // Check it's not already at the bottom
+	    if (position == (getSize()) - 1) {
+		return position;
+	    }
+
+	    // This automatically removes the language first, as an Element can only exist once in a particular document
+	    new_position = position + 1;
+	    addAfter(lang, (Language) getElementAt(new_position));
+	}
+
+	// Schedule the collection for saving
+	Gatherer.c_man.configurationChanged();
+	return new_position;
+    }
+
+    /** Method to remove a certain language.
+     * @param language The <strong>Language</strong> to remove.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     */
+    private void removeLanguage(Language language) {
+	remove(language);
+	if(default_language != null && default_language.equals(language)) {
+	    default_language = null;
+	}
+	Gatherer.c_man.configurationChanged();
+    }
+
+    /** Method to set the default language.
+     * @param language The <strong>Language</strong> to use as a default, or <i>null</i> for no default.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     */
+    public void setDefault(Language language) {
+	if(language != null) {
+	    if(default_language == null) {
+		// Create the default index element, and place immediately after indexes element.
+		Element default_language_element = root.getOwnerDocument().createElement(CollectionConfiguration.LANGUAGE_DEFAULT_ELEMENT);
+		default_language = new Language(default_language_element);
+		Node target_node = CollectionConfiguration.findInsertionPoint(default_language_element);
+		if(target_node != null) {
+		    root.getOwnerDocument().getDocumentElement().insertBefore(default_language_element, target_node);
+		}
+		else {
+		    root.getOwnerDocument().getDocumentElement().appendChild(default_language_element);
+		}
+	    }
+	    default_language.setAssigned(true);
+	    default_language.setCode(language.getCode());
+	}
+	else {
+	    if(default_language != null) {
+		default_language.setAssigned(false);
+	    }
+	}
+	Gatherer.c_man.configurationChanged();
+    }
+
+
+    /** This class represents the visual component of the Language Manager. */
+    private class LanguageControl
+	extends JPanel 
+	implements Control {
+	/** The button to add a new language support. */
+	private JButton add_button = null;
+	/** The button to remove a supported language. */
+	private JButton remove_button = null;
+	/** button to move a language up in the list */
+	private JButton move_down_button;
+	/** button to move a language down in the list */
+	private JButton move_up_button;
+	/** The button to set the current language as the default one. */
+	private JButton set_default_button = null;
+	/** A combobox listing the available supported languages. */
+	private JComboBox language_combobox = null;
+	/** A list of currently supported languages. */
+	private JList selected_languages_list = null;
+	/** Constructor.
+	 * @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.AddListener
+	 * @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.ClearDefaultListener
+	 * @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.ListListener
+	 * @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.RemoveListener
+	 * @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.SelectorListener
+	 * @see org.greenstone.gatherer.cdm.LanguageManager.LanguageControl.SetDefaultListener
+	 */
+	public LanguageControl() {
+	    super();
+	    // Creation.
+	    JPanel center_panel = new JPanel();
+
+	    JLabel selected_languages_list_label = new JLabel();
+	    Dictionary.registerText(selected_languages_list_label, "CDM.LanguageManager.Assigned_Languages");
+	    selected_languages_list = new JList(model);
+	    selected_languages_list.setCellRenderer(new MyLanguageListCellRenderer());
+	    selected_languages_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	    selected_languages_list.setVisibleRowCount(5);
+	    JPanel details_panel = new JPanel();
+
+	    JPanel control_panel = new JPanel();
+	    JLabel selector_label = new JLabel();
+	    Dictionary.registerText(selector_label, "CDM.LanguageManager.Selector");
+
+	    language_combobox = new JComboBox(getLanguageCodes().toArray());
+	    language_combobox.setPreferredSize(COMPONENT_SIZE);
+	    language_combobox.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    language_combobox.setRenderer(new LanguageListCellRenderer());
+	    Dictionary.registerTooltip(language_combobox, "CDM.LanguageManager.Selector_Tooltip");
+
+	    JPanel movement_pane = new JPanel();
+	    move_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
+	    move_up_button.setEnabled(false);
+	    move_up_button.setMnemonic(KeyEvent.VK_U);
+	    Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
+
+	    move_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
+	    move_down_button.setEnabled(false);
+	    move_down_button.setMnemonic(KeyEvent.VK_D);
+	    Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
+
+	    set_default_button = new GLIButton();
+	    set_default_button.setEnabled(false);
+	    set_default_button.setMnemonic(KeyEvent.VK_S);
+	    Dictionary.registerBoth(set_default_button, "CDM.LanguageManager.Set_Default", "CDM.LanguageManager.Set_Default_Tooltip");
+
+	    JPanel button_panel = new JPanel();
+
+	    add_button = new GLIButton();
+	    add_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add_button, "CDM.LanguageManager.Add", "CDM.LanguageManager.Add_Tooltip");
+	    if (getLanguage((String)language_combobox.getItemAt(0))==null) {
+		add_button.setEnabled(true);
+	    } else {
+		add_button.setEnabled(false);
+	    }
+	    remove_button = new GLIButton();
+	    remove_button.setMnemonic(KeyEvent.VK_R);
+	    remove_button.setEnabled(false);
+	    Dictionary.registerBoth(remove_button, "CDM.LanguageManager.Remove", "CDM.LanguageManager.Remove_Tooltip");
+
+	    // Set up and connect listeners.
+	    add_button.addActionListener(new AddListener());
+	    add_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    move_down_button.addActionListener(new MoveListener(false));
+	    move_down_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    move_up_button.addActionListener(new MoveListener(true));
+	    move_up_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    remove_button.addActionListener(new RemoveListener());
+	    remove_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    language_combobox.addActionListener(new SelectorListener());
+	    set_default_button.addActionListener(new SetDefaultListener());
+	    set_default_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    selected_languages_list.addListSelectionListener(new ListListener());
+
+	    // Layout components
+	    movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
+	    movement_pane.setLayout(new GridLayout(3,1));
+	    movement_pane.add(move_up_button);
+	    movement_pane.add(move_down_button);
+	    movement_pane.add(set_default_button);
+
+	    control_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    control_panel.setLayout(new BorderLayout());
+	    control_panel.add(selector_label, BorderLayout.WEST);
+	    control_panel.add(language_combobox, BorderLayout.CENTER);
+
+	    center_panel.setLayout(new BorderLayout());
+	    center_panel.add(selected_languages_list_label, BorderLayout.NORTH);
+	    center_panel.add(new JScrollPane(selected_languages_list), BorderLayout.CENTER);
+	    center_panel.add(movement_pane, BorderLayout.EAST);
+	    center_panel.add(control_panel, BorderLayout.SOUTH);
+
+	    button_panel.setLayout(new GridLayout(1,2));
+	    button_panel.add(add_button);
+	    button_panel.add(remove_button);
+// 	    button_panel.add(set_button);
+// 	    button_panel.add(clear_button);
+
+	    //when we go to a multi list, remove inner_panel and empty_panel
+	    JPanel empty_panel = new JPanel();
+	    JPanel inner_panel = new JPanel();
+
+	    inner_panel.setLayout(new BorderLayout());
+	    inner_panel.add(center_panel, BorderLayout.CENTER);
+	    inner_panel.add(button_panel, BorderLayout.SOUTH);
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    //add(center_panel, BorderLayout.CENTER);
+	    //add(button_panel, BorderLayout.SOUTH);
+	    add(inner_panel, BorderLayout.NORTH);
+	    add(empty_panel, BorderLayout.CENTER);
+	}
+	
+	/** Destructor.	*/
+	public void destroy() {
+	}
+
+	public void gainFocus() {
+	}
+
+	public void loseFocus() {
+	}
+
+	/** Listens for actions apon the 'add' button in the LanguageManager controls, and if detected calls the add method of the manager with a newly created language. */
+	private class AddListener
+	    implements ActionListener {
+	    /** Add a new language support.
+	     * @param event an ActionEvent
+	     * @see org.greenstone.gatherer.cdm.Language
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		String language_code = (String) language_combobox.getSelectedItem();
+		if(language_code != null) {
+		    addLanguage(new Language(language_code));
+		}
+		// add some collectionmeta
+		String lang_name = getLanguageName(language_code);
+		CollectionMeta metadatum = new CollectionMeta("." + language_code);
+		metadatum.setValue(lang_name);
+		CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
+
+		add_button.setEnabled(false);
+	    }
+	}
+
+	/** Listens for actions apon the 'remove' button in the LanguageManager controls, and if detected calls the remove method of the manager with the language selected for removal. */
+	private class RemoveListener
+	    implements ActionListener {
+	    /** Remove the currently selected language, if any.
+	     * @param event An <strong>ActionEvent</strong>.
+	     * @see org.greenstone.gatherer.cdm.Language
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		Language delete_me = (Language)selected_languages_list.getSelectedValue();
+		if(delete_me != null) {
+		    // Remove any current metadata for this language
+		    CollectionDesignManager.collectionmeta_manager.removeMetadata("." + delete_me.getCode());
+		    removeLanguage(delete_me);
+		    if(default_language != null && default_language.equals(delete_me)) {
+			setDefault(null);
+			//clear_button.setEnabled(false);
+			//default_language_field.setText("");
+		    }
+		}
+		remove_button.setEnabled(false);
+	    }
+	}
+
+	/** Listens for selections within the combobox on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
+	private class SelectorListener
+	    implements ActionListener {
+	    /** Enable or disable controls depeding on selection.
+	     * @param event An <strong>ActionEvent</strong>.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		String language_code = (String) language_combobox.getSelectedItem();
+		if(language_code != null && getLanguage(language_code) == null) {
+		    add_button.setEnabled(true);
+		}
+		else {
+		    add_button.setEnabled(false);
+		}
+	    }
+	}
+
+	/** Listens for actions apon the 'set default' button in the LanguageManager controls, and if detected calls the <i>setDefault()</i> method of the manager with the language selected for default. */
+	private class SetDefaultListener
+	    implements ActionListener {
+	    /** Set the default index to the one currently selected, if any.
+	     * @param event An <strong>ActionEvent</strong>.
+	     * @see org.greenstone.gatherer.cdm.Language
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		Language selected_language = (Language) selected_languages_list.getSelectedValue();
+		if(selected_language != null) {
+		    setDefault(selected_language);
+		    //clear_button.setEnabled(true);
+		    // This should cause a repaint of just the desired row
+		    selected_languages_list.setSelectedValue(selected_language, true);
+		}
+		set_default_button.setEnabled(false);
+	    }
+	}
+
+	private class MoveListener
+	    implements ActionListener
+	{
+	    private boolean move_up;
+
+	    public MoveListener(boolean move_up)
+	    {
+		this.move_up = move_up;
+	    }
+
+	    public void actionPerformed(ActionEvent event)
+	    {
+		// Retrieve the selected language
+		Language language = (Language) selected_languages_list.getSelectedValue();
+		if (language != null) {
+		    int new_position = moveLanguage(language, move_up);
+		    // Ensure the language that moved is still selected
+		    selected_languages_list.setSelectedIndex(new_position);
+		}
+	    }
+	}
+
+
+	/** Listens for selections within the list on the LanguageManager controls, and if a change is detected enables, or disables, controls appropriately. */
+	private class ListListener
+	    implements ListSelectionListener {
+	    /** Enable or disable controls depending on the current list selection.
+	     * @param event A <strong>ListSelectionEvent</strong>.
+	     */
+	    public void valueChanged(ListSelectionEvent event) {
+		if (event.getValueIsAdjusting()) {
+		    return;
+		}
+		if(selected_languages_list.isSelectionEmpty()) {
+		    remove_button.setEnabled(false);
+		    set_default_button.setEnabled(false);
+		    move_down_button.setEnabled(false);
+ 		    move_up_button.setEnabled(false);
+		    return;
+		}
+		
+		int i = selected_languages_list.getSelectedIndex();
+ 		int size = selected_languages_list.getModel().getSize();
+		Language selected_lang = (Language)selected_languages_list.getSelectedValue();
+		remove_button.setEnabled(true);
+		set_default_button.setEnabled(default_language == null || !default_language.equals(selected_lang));
+		
+		if (i > 0) {
+ 		    move_up_button.setEnabled(true);
+ 		}
+ 		else {
+ 		    move_up_button.setEnabled(false);
+ 		}
+ 		if (i < size-1){
+ 		    move_down_button.setEnabled(true);
+ 		}
+ 		else {
+ 		    move_down_button.setEnabled(false);
+ 		}
+	    }
+	}
+
+	private class MyLanguageListCellRenderer
+	    extends DefaultListCellRenderer
+	{
+	    /** Return a component that has been configured to display the specified value. */
+	    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+		JLabel component = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+		if (default_language != null && default_language.equals(value)) {
+		    component.setText(component.getText() + " [" + Dictionary.get("CDM.LanguageManager.Default_Language")+"]");
+		}
+		return component;
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Level.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Level.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Level.java	(revision 10506)
@@ -0,0 +1,174 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+/**************************************************************************************
+ * Written:      16/07/03
+ * Revised:      
+ **************************************************************************************/
+import org.w3c.dom.*;
+
+/** This class represents a single search type setting which means that, at the moment, it is either based on an Content element containing the string 'plain' or one on the string 'form'. The ordering of these elements within the Level element is important.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.4
+ */
+public class Level
+    implements DOMProxyListEntry {
+
+    /** The Element this level object will source its information from. */
+    private Element element;
+
+    /** Constructor used only during DOMProxyListModel initialization. */
+    public Level() {
+    }
+
+    /** Normal constructor.
+     * @param  element the Element this object will find its data from
+     */
+    public Level(Element element) {
+	this.element = element;
+    }
+
+    /** Creation of a brand new Level 
+     * @param  name the name of this type as a String
+     */
+    public Level(String level) {
+	this.element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.CONTENT_ELEMENT);
+	this.element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, level);
+    }
+
+    /** Compare two objects for ordering. 
+     * @param  object the other Object to compare to
+     * @return <0 if this level should be before the given object, 0 if they are equal, and >0 if it should be after
+     * since we can only have one instance of a particular level, we don't need to look at the name when comparing.
+     */
+    public int compareTo(Object object) {
+	if(object == null) {
+	    return -1;
+	}
+	// hope we never compare a Level with something that is not a Level!
+	return getLevel().compareTo(((Level)object).getLevel());
+    }
+
+    /** Factory-like method to allow DOMProxyListModel to generate new entries.
+     * @param  element the Element the new level should be based on
+     * @return a newly created DOMProxyListEntry for the given element
+     */
+    public DOMProxyListEntry create(Element element) {
+	return new Level(element);
+    }
+
+    /** Determine if this level is equavilent to another object.
+     * @param  object the other Other to match against
+     * @return true if the two are equal, false otherwise
+     */
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+
+    /** Retrieve the element this DOMProxyListEntry is based upon. Specified by the interface.
+     * @return the Element in question
+     */
+    public Element getElement() {
+	return element;
+    }
+
+    /** Retrieve the level.
+     * @return the level as a String
+     */
+    public String getLevel() {
+	return element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
+    }
+
+    /** Retrieve the display name
+     */
+    public String getName() {
+	CollectionMeta metadatum = CollectionDesignManager.collectionmeta_manager.getMetadatum(CollectionConfiguration.STOP_CHARACTER + getLevel(), false);
+	if(metadatum != null) {
+	    return metadatum.getValue(CollectionMeta.TEXT);
+	}
+	return "";
+    }
+    
+   /** Determine is this command has been assigned, either because it already existed in the collection configuration, or because it has been explicitly set by the user. Non-assigned entries imply they have been added by the GLI to ensure consistancy (and avoid NPE's!)
+     * @return true if this command has been assigned, false otherwise
+     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
+     */
+    public boolean isAssigned() {
+	return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
+    }
+    
+    /** Set the assigned state.
+     * @param  assigned the desired state of assigned as a boolean
+     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
+     */
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    /** Set the element that this DOMProxyListEntry is base on.
+     * @param  element the new Element that this entry should source informatin from
+     */
+    public void setElement(Element element) {
+	this.element = element;
+    }
+
+    /** Set the name of this level.
+     * @param  name the new name for this level, as a String
+     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
+     */
+    public void setLevel(String level) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, level);
+	}
+    }
+
+    /** Produce a text representation of this level.
+     * @return a String showing this level
+     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
+     */
+    public String toString() {
+	String text ="";
+	if(element == null) {
+	    text = "#Error";
+	}
+	else {
+	    String level = getLevel();
+	    StringBuffer text_buffer = new StringBuffer(level);
+	    text_buffer.append(" \"");
+	    text_buffer.append(getName());
+	    text_buffer.append("\"");
+	
+	    text = text_buffer.toString();
+	    text_buffer = null;
+	}
+	
+	return text;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/MetadataSetView.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/MetadataSetView.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/MetadataSetView.java	(revision 10506)
@@ -0,0 +1,391 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.filechooser.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.gui.MetadataElementListCellRenderer;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.metadata.MetadataTools;
+import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
+
+
+/** This class only knows how to produce a simple visual representation of the currently imported metadata sets. It is also read-only, so should be fairly straight forward.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3d
+ */
+public class MetadataSetView
+    extends DynamicListModel {
+
+    /** The visual contols used to review the metadata sets. */
+    private Control controls = null;
+    /** A reference to ourselves so our inner classes can refer to us. */
+    private DynamicListModel model = null;
+
+
+    public MetadataSetView()
+    {
+	model = this;
+
+	// Initialise the model
+	refreshModel();
+
+	// Build the controls
+	controls = new MetadataSetViewControls();
+    }
+
+
+    public void destroy()
+    {
+	controls.destroy();
+	controls = null;
+	model = null;
+    }
+
+
+    /** A method for retrieve the controls for this manager.
+     */
+    public Control getControls() {
+	return controls;
+    }
+
+
+    public void refreshModel()
+    {
+	// Remove any metadata sets from the model that are no longer loaded
+	ArrayList loaded_metadata_sets = MetadataSetManager.getMetadataSets();
+	for (int i = size() - 1; i >= 0; i--) {
+	    MetadataSet metadata_set = (MetadataSet) get(i);
+	    if (loaded_metadata_sets.contains(metadata_set) == false) {
+		// System.err.println("Metadata set in list no longer loaded...removing.");
+		remove(i);
+	    }
+	}
+
+	// Add any metadata sets that are loaded but not in the model
+	for (int i = 0; i < loaded_metadata_sets.size(); i++) {
+	    MetadataSet loaded_metadata_set = (MetadataSet) loaded_metadata_sets.get(i);
+	    boolean in_model = false;
+	    for (int j = 0; j < size(); j++) {
+		MetadataSet metadata_set = (MetadataSet) get(j);
+		if (metadata_set.equals(loaded_metadata_set)) {
+		    in_model = true;
+		    break;
+		}
+	    }
+
+	    if (in_model == false) {
+		// System.err.println("Metadata set loaded but not in list...adding.");
+		addElement(loaded_metadata_set);
+	    }
+	}
+    }
+
+
+    /** This class creates and lays-out the various controls for reviewing the metadata sets, and their commands as they would appear in the collection configuration file. */
+    private class MetadataSetViewControls
+	extends JPanel
+	implements Control {
+	/** Adds a new set to the collection*/
+	private JButton add_button;
+	/** Will eventually launch GEMS for editing the selected set, for now just gives a message */
+	private JButton edit_button;
+	/** REmoves a set from the collection */
+	private JButton remove_button;
+	/** The label denoting the element list. */
+	private JLabel element_label = null;
+	/** The label denoting the set list. */
+	private JLabel set_label = null;
+	/** The title of these controls. */
+	private JLabel title = null;
+	/** The list of elements for the choosen set. */
+	private JList element_list = null;
+	/** The list of sets in this collection. */
+	private JList set_list = null;
+	/** The panel onto which all other panels will be placed. */
+	private JPanel central_pane = null;
+	/** The panel onto which the element list will be placed. */
+	private JPanel element_pane = null;
+	/** The panel containing the title and instructions. */
+	private JPanel header_pane = null;
+	/** The panel containing the set list. */
+	private JPanel set_pane = null;
+
+	private JScrollPane element_list_scroll_pane;
+	/** The text area of inline instructions. */
+	private JTextArea instructions = null;
+
+	private MetadataElementListCellRenderer element_list_cell_renderer;
+	private MetadataSetListSelectionListener list_listener;
+
+	/* Constructor.
+	 * @see org.greenstone.gatherer.Dictionary
+	 * @see org.greenstone.gatherer.cdm.MetadataSetView.ListListener
+	 */
+	public MetadataSetViewControls()
+	{
+	    // Create visual components
+	    central_pane = new JPanel();
+	    element_label = new JLabel();
+	    element_label.setHorizontalAlignment(JLabel.CENTER);
+	    element_label.setOpaque(true);
+	    Dictionary.registerText(element_label, "CDM.MetadataSetManager.Elements");
+	    element_list = new JList();
+	    element_list_scroll_pane = new JScrollPane();
+	    element_list_scroll_pane.setViewportView(element_list);
+	    element_list_cell_renderer = new MetadataElementListCellRenderer();
+	    element_list.setCellRenderer(element_list_cell_renderer);
+	    element_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	    element_pane = new JPanel();
+	    header_pane = new JPanel();
+	    instructions = new JTextArea();
+	    instructions.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    instructions.setEditable(false);
+	    instructions.setLineWrap(true);
+	    instructions.setRows(6);
+	    instructions.setWrapStyleWord(true);
+	    Dictionary.registerText(instructions, "CDM.MetadataSetManager.Instructions");
+	    set_label = new JLabel();
+	    set_label.setHorizontalAlignment(JLabel.CENTER);
+	    set_label.setOpaque(true);
+	    Dictionary.registerText(set_label, "CDM.MetadataSetManager.Sets");
+	    set_list = new JList(model);
+	    set_list.setCellRenderer(new MetadataSetListCellRenderer());
+	    set_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+	    set_pane = new JPanel();
+	    title = new JLabel();
+	    title.setHorizontalAlignment(JLabel.CENTER);
+	    title.setOpaque(true);
+	    Dictionary.registerText(title, "CDM.MetadataSetManager.Title");
+
+	    JPanel button_pane = new JPanel();
+	    add_button = new GLIButton();
+	    add_button.setEnabled(true);
+	    add_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add_button, "CDM.MetadataSetManager.Add", "CDM.MetadataSetManager.Add_Tooltip");
+	    edit_button = new GLIButton();
+	    edit_button.setEnabled(false);
+	    edit_button.setMnemonic(KeyEvent.VK_E);
+	    Dictionary.registerBoth(edit_button, "CDM.MetadataSetManager.Edit", "CDM.MetadataSetManager.Edit_Tooltip");
+	    
+	    remove_button = new GLIButton();
+	    remove_button.setEnabled(false);
+	    remove_button.setMnemonic(KeyEvent.VK_R);
+	    Dictionary.registerBoth(remove_button, "CDM.MetadataSetManager.Remove", "CDM.MetadataSetManager.Remove_Tooltip");
+	    list_listener = new MetadataSetListSelectionListener();
+
+	    // Add listeners
+	    add_button.addActionListener(new AddButtonListener());
+	    edit_button.addActionListener(new EditButtonListener());
+	    remove_button.addActionListener(new RemoveButtonListener());
+	    set_list.addListSelectionListener(list_listener);
+	    // Layout
+	    instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
+
+	    header_pane.setLayout(new BorderLayout());
+	    header_pane.add(title, BorderLayout.NORTH);
+	    header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
+
+	    set_pane.setLayout(new BorderLayout());
+	    set_pane.add(set_label, BorderLayout.NORTH);
+	    set_pane.add(new JScrollPane(set_list), BorderLayout.CENTER);
+
+	    element_pane.setLayout(new BorderLayout());
+	    element_pane.add(element_label, BorderLayout.NORTH);
+	    element_pane.add(element_list_scroll_pane, BorderLayout.CENTER);
+
+	    central_pane.setLayout(new GridLayout(2,1));
+	    central_pane.add(set_pane);
+	    central_pane.add(element_pane);
+	    
+	    button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    button_pane.setLayout(new GridLayout(1,3,0,0));
+	    button_pane.add(add_button);
+	    button_pane.add(edit_button);
+	    button_pane.add(remove_button);
+
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    add(header_pane, BorderLayout.NORTH);
+	    add(central_pane, BorderLayout.CENTER);
+	    add(button_pane, BorderLayout.SOUTH);
+	}
+
+
+	public void destroy() { }
+
+
+	public void gainFocus()
+	{
+	    // Ensure the instructions area is scrolled to the top
+	    if (instructions != null) {
+		instructions.setCaretPosition(0);
+	    }
+
+	    // If no current selection, select first available set
+	    if (set_list.isSelectionEmpty() && set_list.getModel().getSize() > 0) {
+		set_list.setSelectedIndex(0);
+		list_listener.valueChanged(new ListSelectionEvent(set_list, 0, 0, true));
+	    }
+	    if (!set_list.isSelectionEmpty()) {
+		edit_button.setEnabled(true);
+		remove_button.setEnabled(true);
+	    } else {
+		edit_button.setEnabled(false);
+		remove_button.setEnabled(false);
+	    }
+		
+	}
+
+
+	public void loseFocus() { }
+
+
+	/** Listens for clicks on the add button. */
+	private class AddButtonListener
+	    implements ActionListener {
+
+	    /** Called when the add button is clicked.
+	     * @param event an ActionEvent containing information about the mouse click
+	     */
+	    public void actionPerformed(ActionEvent event)
+	    {
+		JFileChooser chooser = new JFileChooser(new File(Gatherer.getGLIMetadataDirectoryPath()));
+		chooser.setFileFilter(new MetadataSet.MetadataSetFileFilter());
+		int return_val = chooser.showDialog(Gatherer.g_man, Dictionary.get("CDM.MetadataSetManager.Add"));
+		if (return_val == JFileChooser.APPROVE_OPTION) {
+		    Gatherer.c_man.importMetadataSet(new MetadataSet(chooser.getSelectedFile()));
+		    refreshModel();
+
+		    // The metadata.xml files may possibly contain metadata for this newly added metadata set
+		    // Re-read all the metadata.xml files to account for this case
+		    MetadataXMLFileManager.clearMetadataXMLFiles();
+		    MetadataXMLFileManager.loadMetadataXMLFiles(new File(Gatherer.c_man.getCollectionImportDirectoryPath()));
+		}
+	    }
+	}
+
+
+	/** Listens for clicks on the edit button. */
+	private class EditButtonListener
+	    implements ActionListener {
+
+	    /** Called when the edit button is clicked.
+	     * @param event an ActionEvent containing information about the mouse click
+	     */
+	    public void actionPerformed(ActionEvent event)
+	    {
+		// do a pop up message
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.MetadataSetManager.Edit_Message"), Dictionary.get("CDM.MetadataSetManager.Edit_Message_Title"), JOptionPane.INFORMATION_MESSAGE);
+
+	    }
+	}
+
+
+	private class MetadataSetListCellRenderer
+	    implements ListCellRenderer
+	{
+	    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
+	    {
+		DefaultListCellRenderer default_list_cell_renderer = new DefaultListCellRenderer();
+		JLabel list_cell_label = (JLabel) default_list_cell_renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+
+		if (value instanceof MetadataSet) {
+		    MetadataSet metadata_set = (MetadataSet) value;
+		    String metadata_set_name = MetadataTools.getMetadataSetAttribute(metadata_set, "Name", Configuration.getLanguage(), "en");
+		    list_cell_label.setText("metadataset " + metadata_set.getNamespace() + " \"" + metadata_set_name + "\"");
+		}
+
+		return list_cell_label;
+	    }
+	}
+
+
+	private class MetadataSetListSelectionListener
+	    implements ListSelectionListener {
+
+	    public void valueChanged(ListSelectionEvent event)
+	    {
+		// Wait until we get a stable event
+		if (event.getValueIsAdjusting()) {
+		    return;
+		}
+
+		// Now we can process it
+		if (!set_list.isSelectionEmpty()) {
+		    MetadataSet metadata_set = (MetadataSet) set_list.getSelectedValue();
+		    element_list.setListData(new Vector(metadata_set.getMetadataSetElements()));
+  		    remove_button.setEnabled(true);
+		    edit_button.setEnabled(true);
+
+  		    // Finally check the directionality and scroll as necessary
+  		    JScrollBar scroll_bar = element_list_scroll_pane.getHorizontalScrollBar();
+  		    if (element_list_cell_renderer.getDirectionality() == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
+			scroll_bar.setValue(scroll_bar.getMaximum());
+  		    }
+  		    else {
+			scroll_bar.setValue(scroll_bar.getMinimum());
+		    }
+		}
+		else {
+		    remove_button.setEnabled(false);
+		    edit_button.setEnabled(false);
+		}
+	    }
+	}
+
+
+	/** Listens for clicks on the remove button. */
+	private class RemoveButtonListener
+	    implements ActionListener {
+
+	    /** Called when the remove button is clicked.
+	     * @param event an ActionEvent containing information about the mouse click
+	     */
+	    public void actionPerformed(ActionEvent event)
+	    {
+		MetadataSet metadata_set = (MetadataSet) set_list.getSelectedValue();
+		Gatherer.c_man.removeMetadataSet(metadata_set);
+		refreshModel();
+		element_list.setListData(new Vector());
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ParsingProgress.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ParsingProgress.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/ParsingProgress.java	(revision 10506)
@@ -0,0 +1,101 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.cdm;
+
+/**************************************************************************************
+ * Title:        Gatherer
+ * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
+ * Copyright:    Copyright (c) 2001
+ * Company:      The University of Waikato
+ * Written:      03/05/02
+ * Revised:      20/05/02
+ *               17/11/02 - Commented
+ **************************************************************************************/
+import java.awt.*;
+import javax.swing.*;
+
+/** This class provides a progress bar to be displayed whenever the module must reload the plugin and classifier information, either automatically or if the user indicates a reload is needed.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class ParsingProgress
+    extends JDialog {
+    /** The content pane within the dialog box. */
+    private JPanel content_pane = null;
+    /** The progress bar itself. */
+    private JProgressBar progress = null;
+    /** The default size of the progress dialog. */
+    static final Dimension SIZE = new Dimension(600,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 number of plugins/classifiers that have to be parsed before the progress bar can be disposed of, as an <i>int</i>.
+     */
+    public ParsingProgress(String title, String message, int max) {
+	super();
+	this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+	this.setSize(SIZE);
+	this.setTitle(title);
+
+	// Creation
+	this.content_pane = (JPanel) getContentPane();
+	this.progress = new JProgressBar();
+	this.progress.setMaximum(max);
+
+	// 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(progress, BorderLayout.CENTER);
+
+	// 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() {
+	progress.setValue(progress.getValue() + 1);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Plugin.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Plugin.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Plugin.java	(revision 10506)
@@ -0,0 +1,440 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.w3c.dom.*;
+
+/** This class is responsible for storing information from a parsed pluginfo call in such a way that it allows easy access to parsed details for the purposes of user design and specification of plugins. */
+public class Plugin
+    extends ArrayList
+    implements ArgumentContainer, Comparable, DOMProxyListEntry, Serializable {
+    /** The DOM Element this assigned Plugin is modelled on. */
+    private Element element;
+    private boolean does_explode_metadata_databases = false; // Only for Base
+    private boolean is_abstract = false; // Only for Base
+    /** The parent Plugin this one inherits from, if any. */
+    private Plugin super_plugin; // Only for Base
+    private String description; // Only for Base
+    private String name; // Only for Base
+
+    /** Constructor used in DOMProxyListModel initializations, and Library Level. Used for Base plugins (those in the list of available plugins, not ones that are in the DOMProxyList)
+     */
+    public Plugin() {
+    }
+    
+    /** Constructor used for the plugins that are in the DOMProxyList */
+    // Every time the list of plugins in the assigned plugins box changes, (eg plugin added or removed, not when plugin configured), the plugins seem to be regenerated, using the element from the old plugin. All known args get added to the element the first time this happens - we need to add them to the arguments list in the order they are found in the base plugins though, not this order.
+    public Plugin(Element element, Plugin base_plugin) {
+	super();
+	this.element = element;
+	this.name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
+	//DebugStream.println("Establishing Plugin: " + name);
+	// Parse in any argument options for this plugin, keeping a list of the ones found
+	HashMap known_arguments = new HashMap();
+	NodeList option_elements = element.getElementsByTagName(StaticStrings.OPTION_ELEMENT);
+	int option_elements_length = option_elements.getLength();
+	for(int i = 0; i < option_elements_length; i++) {
+	    Element option_element = (Element) option_elements.item(i);
+	    Argument argument = new Argument(option_element);
+	    //DebugStream.println("Rebuilding existing argument: " + argument.getName());
+	    known_arguments.put(argument.getName(), argument);
+	    if (base_plugin == null) {
+		// otherwise they will all be added in the next step
+		argument.setOwner(name);
+		add(argument);
+	    } 
+	}
+	// If a base plugin was given
+	if(base_plugin != null) {
+	    //DebugStream.println("Based on previous plugin.");
+	    // Copy the details, and add a reference to whatever base_plugins super plugin is. ?? 
+	    description = base_plugin.getDescription();
+	    // Now search through the 'dummy' arguments belonging to the base plugin. For each found, if it is already assigned, fill out further details such as type. If any are found that are not already assigned for this plugin, copy them and add them, but without a value.
+	    ArrayList all_arguments = base_plugin.getArguments(true, true);
+	    int argument_count = all_arguments.size();
+	    for(int j = 0; j < argument_count; j++) {
+		Argument base_argument = (Argument) all_arguments.get(j);
+		String base_argument_name = base_argument.getName();
+		//DebugStream.println("Library indicates this plugin should have an argument: " + base_argument_name);
+		Argument existing_argument = (Argument) known_arguments.get(base_argument_name);
+		// Found an existing argument. Complete its details
+		if(existing_argument != null) {
+		    //DebugStream.println("Found existing argument. Filling out details.");
+		    existing_argument.setCustomArgument(false);
+		    existing_argument.setDefaultValue(base_argument.getDefaultValue());
+		    existing_argument.setDescription(base_argument.getDescription());
+		    existing_argument.setOptions(base_argument.getOptions());
+		    existing_argument.setRequired(base_argument.isRequired());
+		    existing_argument.setType(base_argument.getType());
+		    existing_argument.setMinimum(base_argument.getMinimum());
+		    existing_argument.setMaximum(base_argument.getMaximum());
+		    existing_argument.setOwner(base_argument.getOwner());
+		    add(existing_argument); 
+		    
+		}
+		// No existing argument. Copy base_argument and add it, but do not set its assigned flag. That should be set the first time its changed by the user.
+		else {
+		    //DebugStream.println("No such argument. Adding new, unassigned, argument.");
+		    // The trick thing is that we have to create a new element in the DOM as well.
+		    Argument new_argument = base_argument.copy();
+		    Element argument_element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.OPTION_ELEMENT);
+		    argument_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, base_argument_name);
+		    argument_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.FALSE_STR);
+		    argument_element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, StaticStrings.FALSE_STR);
+		    // All done. Add it.
+		    // if we are not in the first collection opened, then this 
+		    /// will belong to a different document, so need to import 
+		    // it.
+		    Node new_element = element.getOwnerDocument().importNode(argument_element, true);
+		    new_argument.setElement((Element) new_element);
+		    element.appendChild(new_element);
+		    add(new_argument);
+		}
+	    }
+	}
+    }
+
+    /** Method to add an argument to this base plugin. Only adds the argument if it isn't already present, and only if this is a base plugin (ie not based on DOM).
+     * @param argument the Argument to add
+     */
+    public void addArgument(Argument argument) {
+	if(element == null && !contains(argument)) {
+	    add(argument);
+	    argument.setOwner(name);
+	}
+    }
+
+    /** Method to compare two plugins for ordering.
+     * @param object The plugin we are comparing to, as an <strong>Object</strong>.
+     * @return An <i>int</i> specifying the plugin order, using values as set out in <strong>String</strong>.
+     * @see java.lang.String#compareTo
+     */
+    public int compareTo(Object object) {
+	if(object instanceof Plugin) {
+	    return name.compareTo(((Plugin)object).getName());
+	}
+	return -1;
+    }
+
+    /** The assigned plugin constructor.
+     * @param element the DOM Element this plugin is based upon
+     */
+    public DOMProxyListEntry create(Element element) {
+	String plugin_name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
+	// Determine the base plugin from the plugin name
+	Plugin base_plugin = CollectionDesignManager.plugin_manager.getBasePlugin(plugin_name);
+	Plugin plugin = new Plugin(element, base_plugin);
+	base_plugin = null;
+	plugin_name = null;
+	return plugin;
+    }
+
+
+    /** Checks whether the plugin this instance is based on processes metadata databases that can be exploded. */
+    public boolean doesExplodeMetadataDatabases()
+    {
+	Plugin base_plugin = CollectionDesignManager.plugin_manager.getBasePlugin(getName());
+	if (base_plugin == null) {
+	    return false;
+	}
+	return base_plugin.does_explode_metadata_databases;
+    }
+
+
+    /** Checks whether this plugin instance will process the specified file (given its process_exp). */
+    public boolean doesProcessFile(File file)
+    {
+	// Check the filename against the plugin's process_exp value
+	ArrayList arguments = getArguments(true, true);
+	for (int i = 0; i < arguments.size(); i++) {
+	    Argument argument = (Argument) arguments.get(i);
+	    if (argument.getName().equals("process_exp")) {
+		// Try the assigned value first, for when the user has manually set the value
+		String regular_expression = argument.getValue();
+		if (regular_expression == null || regular_expression.equals("")) {
+		    // Not set, so use the default value
+		    regular_expression = argument.getDefaultValue();
+		    if (regular_expression.equals("")) {
+			continue;
+		    }
+		}
+
+		// The $ at the end doesn't seem to work in Java, so need to add ".*" at the start
+		if (regular_expression.startsWith("(?i)")) {
+		    // Don't mess up case-insensitive matching though
+		    regular_expression = "(?i)" + ".*" + regular_expression.substring("(?i)".length());
+		}
+		else {
+		    regular_expression = ".*" + regular_expression;
+		}
+
+		// If the filename matches the regular expression, this plugin will deal with the file in some way
+		if (file.getName().matches(regular_expression)) {
+		    return true;
+		}
+	    }
+	}
+
+	// This plugin will (probably) not deal with the specified file
+	return false;
+    }
+
+
+    /** Method to determine if two plugins are equal.
+     * @param object The plugin to test against, as an <strong>Object</strong>.
+     * @return <i>true</i> if the plugin names match, <i>false</i> otherwise.
+     */
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+
+    /** Method to retrieve an argument by its name.
+     * @param name The name of the argument as a <strong>String</strong>.
+     * @return The <strong>Argument</strong> requested, or <i>null</i> if no such argument.
+     */
+    public Argument getArgument(String name) {
+	// The name given may still include the '-'
+	if(name.startsWith("-")) {
+	    name = name.substring(1);
+	}
+	ArrayList arguments = getArguments(true, true);
+	for(int i = 0; i < arguments.size(); i++) {
+	    Argument argument = (Argument)arguments.get(i);
+	    if(argument.getName().equals(name)) {
+		return argument;
+	    }
+	}
+	return null;
+    }
+
+    /** Retrieve all of the arguments available to this base plugin, including its super plugins arguments. Some complexity is added by allowing the caller to choose whether they want normal arguments, custom arguments, or both.
+     * @return an ArrayList of all of the arguments, starting with those for this plugin and ending with the arguments for basplug or similiar root plugin
+     */
+    public ArrayList getArguments(boolean include_normal, boolean include_custom) {
+	ArrayList arguments = new ArrayList();
+	if(include_normal && include_custom) {
+	    arguments.addAll(this);
+	}
+	else {
+	    int size = size();
+	    for(int i = 0; i < size; i++) {
+		Argument argument = (Argument) get(i);
+		if(argument.isCustomArgument()) {
+		    if(include_custom && !arguments.contains(argument)) {
+			arguments.add(argument);
+		    }
+		}
+		else {
+		    if(include_normal && !arguments.contains(argument)) {
+			arguments.add(argument);
+		    }
+		}
+		argument = null;
+	    }
+	}
+	if(super_plugin != null) {
+	    ArrayList remainder = super_plugin.getArguments(include_normal, include_custom);
+	    remainder.removeAll(arguments);
+	    arguments.addAll(remainder);
+	}
+	return arguments;
+    }
+
+    /** Method to retrieve a plugins custom argument information. Custom arguments are defined to be those that have not got matching arguments in the base reference plugin from the library. Of course if there is no base plugin then all arguments are considered to be custom.
+     * @return the custom arguments as a String
+     */
+    public String getCustom() {
+	StringBuffer custom_text = new StringBuffer();
+	// Retrieve all of the arguments, and append any that are custom into one long string
+	ArrayList arguments = getArguments(false, true);
+	int arguments_size = arguments.size();
+	boolean first = true;
+	for(int i = 0; i < arguments_size; i++) {
+	    Argument argument = (Argument) arguments.get(i);
+	    if(argument.isAssigned()) {
+		if(!first) {
+		    custom_text.append(" ");
+		}
+		custom_text.append(argument.toString());
+		first = false;
+	    }
+	}
+	return custom_text.toString();
+    }
+
+    public String getDescription() {
+	return description;
+    }
+
+    public Element getElement() {
+	return element;
+    }
+
+    /** Method to retrieve a plugins name.
+     * @return A <strong>String</strong> containing the plugins name.
+     */
+    public String getName() {
+	if(name == null && element != null) {
+	    name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
+	}
+	return name;
+    }
+
+    public boolean isAbstract() {
+	return is_abstract;
+    }
+
+    public boolean isAssigned() {
+	return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
+    }
+
+    public boolean isSeparator() {
+	return (element != null && element.getAttribute(StaticStrings.SEPARATOR_ATTRIBUTE).equals(StaticStrings.TRUE_STR));
+    }
+
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    /** Set the custom arguments. This turns out to be quite tricky. We must parse in the string, searching for arguments (for that we use a handy method in CollectionConfiguration). Next, for each argument, we check if we already know about it. If so we update its value, otherwise we create a new argument and assign it (must assign!).
+     * @param custom_str the custom arguments all splodged together in one String
+     */
+    public void setCustom(String custom_str) {
+	HashMap raw_arguments = CollectionConfiguration.parseArguments(new CommandTokenizer(custom_str));
+	ArrayList custom_arguments = getArguments(false, true);
+	int size = custom_arguments.size();
+	for(int i = 0; i < size; i++) {
+	    Argument argument = (Argument) custom_arguments.get(i);
+	    String original_argument_name = StaticStrings.MINUS_CHARACTER + argument.getName();
+	    if(raw_arguments.containsKey(original_argument_name)) {
+		// Set as assigned
+		argument.setAssigned(true);
+		String argument_value = (String)raw_arguments.remove(original_argument_name);
+		if(argument_value != null) {
+		    argument.setValue(argument_value);
+		    argument_value = null;
+		}
+	    }
+	    // We've removed it from our custom statement, so unassign
+	    else {
+		argument.setAssigned(false);
+	    }
+	    argument = null;
+	}
+	// Any left over, add to the plugin
+	Iterator argument_names = raw_arguments.keySet().iterator();
+	while(argument_names.hasNext()) {
+	    String argument_name = (String) argument_names.next();
+	    String argument_value = (String) raw_arguments.get(argument_name);
+	    // The tricky thing is that we have to create a new element in the DOM as well.
+	    Element argument_element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.OPTION_ELEMENT);
+	    argument_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, argument_name.substring(1));
+	    argument_element.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, StaticStrings.TRUE_STR);
+	    argument_element.setAttribute(StaticStrings.CUSTOM_ATTRIBUTE, StaticStrings.TRUE_STR);
+	    Argument argument = new Argument(argument_element);
+	    argument_name = null;
+	    if(argument_value != null) {
+		argument.setValue(argument_value);
+		argument_value = null;
+	    }
+	    // All done. Add it.
+	    element.appendChild(argument_element);
+	    add(argument);
+	    argument_element = null;
+	}
+	raw_arguments = null;
+    }
+
+    /** Method to set the value of desc.
+     * @param description The new value of desc as a <strong>String</strong>.
+     */
+    public void setDescription(String description) {
+	this.description = description;
+    }
+
+    public void setDoesExplodeMetadataDatabases(boolean does_explode_metadata_databases) {
+	this.does_explode_metadata_databases = does_explode_metadata_databases;
+    }
+
+    public void setElement(Element element) {
+	this.element = element;
+    }
+
+    public void setIsAbstract(boolean is_abstract) {
+	this.is_abstract = is_abstract;
+    }
+
+    /** Method to set the value of name.
+     * @param name The new value of name as a <strong>String</strong>.
+     */
+    public void setName(String name) {
+	this.name = name;
+    }
+
+    /** Method to set the value of the super_plugin.
+     * @param super_plugin The new value of super_plugin as a <strong>Plugin</strong>, or <i>null</i> if this class has no inheritance.
+     */
+    public void setSuper(Plugin super_plugin) {
+	this.super_plugin = super_plugin;
+    }
+
+    /** Method to print out this plugin as it would appear as a command within the collection configuration file.
+     * @return A <strong>String</strong> containing a single plugin command.
+     */
+    public String toString() {
+	if(element != null) {
+	    if(name == null) {
+		name = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE);
+	    }
+	    StringBuffer text = new StringBuffer(StaticStrings.PLUGIN_STR);
+	    text.append(" ");
+	    text.append(name);
+	    text.append(" ");
+	    ArrayList arguments = getArguments(true, true);
+	    int arguments_size = arguments.size();
+	    for(int i = 0; i < arguments_size; i++) {
+		Argument argument = (Argument)arguments.get(i);
+		if(argument.isAssigned()) {
+		    text.append(argument.toString());
+		    text.append(" ");
+		}
+		argument = null;
+	    }
+	    return text.substring(0, text.length() - 1);
+	}
+	// Basic Plugin
+	else {
+	    return name;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/PluginManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/PluginManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/PluginManager.java	(revision 10506)
@@ -0,0 +1,1353 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+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.*;
+import javax.swing.plaf.basic.*;
+import org.apache.xerces.parsers.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.LocalGreenstone;
+import org.greenstone.gatherer.collection.CollectionContentsChangedListener;
+import org.greenstone.gatherer.gui.GComboBox;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.gui.ModalDialog;
+import org.greenstone.gatherer.gui.WarningDialog;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+/** This class is for maintaining a list of known plug-ins, and importing new plugins using the parser. */
+public class PluginManager
+    extends DOMProxyListModel
+    implements CollectionContentsChangedListener
+{
+    /** The library 'reserve' of base plugins. */
+    private ArrayList library = null;
+    /** When asking how many rows are in the model, and if this variables value is true, then this modifier alters the number returned. This funtionality is used to hide the last three rows of the list in low detail modes. */
+    private boolean modify_row_count = false;
+    /** The controls for editing the contents of this manager. */
+    private Control controls = null;
+    private DOMProxyListModel model;
+    private JPanel separator;
+    private Plugin separator_plugin;
+    /** Constructor.
+     */
+    public PluginManager() {
+	super(CollectionDesignManager.collect_config.getDocumentElement(), CollectionConfiguration.PLUGIN_ELEMENT, new Plugin());
+	DebugStream.println("PluginManager: " + super.getSize() + " plugins parsed.");
+	model = this;
+	// Reload/Create the library
+	loadPlugins(); // adds all the plugins to the library
+	savePlugins();
+	// Create the separator, cause we can reuse it.
+	separator = getSeparator();
+
+	// Listen for CollectionContentsChanged events, so we can give plugin hints when new files are added
+	Gatherer.c_man.addCollectionContentsChangedListener(this);
+    }
+
+    /** Method to add a new plugin to the library
+     * @param plugin the new base Plugin
+     */
+    private void addPlugin(Plugin plugin) {
+  	if(!library.contains(plugin)) {
+  	    library.add(plugin);
+  	}
+    }
+
+    /** Method to assign a plugin
+     * @param plugin the Plugin to assign
+     */
+    private void assignPlugin(Plugin plugin) {
+	if(plugin.getName().equals(StaticStrings.RECPLUG_STR) || plugin.getName().equals(StaticStrings.ARCPLUG_STR)) {
+	    addAfter(plugin, separator_plugin); // Adds after separator
+	} else {
+	    addBefore(plugin, separator_plugin);
+	}
+	Gatherer.c_man.configurationChanged();
+    }
+
+    public static boolean clearPluginCache() {
+
+	DebugStream.println("deleting plugins.dat");
+	File plugin_file = new File(Gatherer.getGLIUserDirectoryPath() + "plugins.dat");
+	if (plugin_file.exists()) {
+	    return Utility.delete(plugin_file);
+	}
+	return true;
+    }
+
+
+    /** Destructor. */
+    public void destroy()
+    {
+	Gatherer.c_man.removeCollectionContentsChangedListener(this);
+
+	if (controls != null) {
+	    controls.destroy();
+	    controls = null;
+	}
+
+	library.clear();
+	library = null;
+    }
+
+
+    /** This function listens for new files being added to the collection and hints about suitable plugins. */
+    public void fileAddedToCollection(File file)
+    {
+	// First check the plugins already assigned in the collection
+	for (int i = 0; i < super.getSize(); i++) {
+	    Plugin assigned_plugin = (Plugin) getElementAt(i);
+	    if (assigned_plugin.isSeparator() == false && assigned_plugin.doesProcessFile(file) == true) {
+		// This file will be processed by an assigned plugin, so no suggestion is necessary
+		DebugStream.println("Processed by assigned plugin: " + assigned_plugin);
+		return;
+	    }
+	}
+
+	// Next try the plugins NOT already assigned in the collection
+	ArrayList suitable_plugins = new ArrayList();
+	Object[] unassigned_plugins = getAvailable();
+	for (int i = 0; i < unassigned_plugins.length; i++) {
+	    Plugin unassigned_plugin = (Plugin) unassigned_plugins[i];
+	    if (unassigned_plugin.doesProcessFile(file) == true) {
+		DebugStream.println("Processed by unassigned plugin: " + unassigned_plugin);
+		suitable_plugins.add(unassigned_plugin);
+	    }
+	}
+
+	// If there appear to be no suitable plugins, warn the user about this and be done
+	if (suitable_plugins.size() == 0) {
+	    String[] args = new String[1];
+	    args[0] = file.getName();
+	    WarningDialog warning_dialog = new WarningDialog("warning.NoPluginExpectedToProcessFile", "NoPluginExpectedToProcessFile.Title", Dictionary.get("NoPluginExpectedToProcessFile.Message", args), null, false);
+	    warning_dialog.display();
+	    warning_dialog.dispose();
+	    return;
+	}
+
+	// Generate a dialog 
+	new PluginSuggestionPrompt(file.getName(), suitable_plugins);
+    }
+
+
+    public boolean isFileExplodable(File file)
+    {
+
+	for (int i = 0; i < library.size(); i++) {
+	    Plugin plugin = (Plugin) library.get(i);
+	    if (plugin.doesExplodeMetadataDatabases() == true && plugin.doesProcessFile(file) == true) { 
+		return true;
+	    }
+	}
+
+	return false;
+    }
+
+    public Plugin getExploderPlugin(File file)
+    {
+	for (int i = 0; i < library.size(); i++) {
+	    Plugin plugin = (Plugin) library.get(i);
+	    if (plugin.doesProcessFile(file) == true && plugin.doesExplodeMetadataDatabases() == true) {
+		return plugin;
+	    }
+	}
+	return null;
+	
+    }
+
+    /** Method to retrieve the control for this manager.
+     * @return the Control
+     */
+    public Control getControls() {
+	if(controls == null) {
+	    // Build controls
+	    controls = new PluginControl();
+	}
+	return controls;
+    }
+
+    /** Retrieve the base pluging of the given name, or null if no such plugin.
+     * @param name the name of the base plugin to retrieve as a String
+     * @return the Plugin requested or null if no such plugin
+     */
+    public Plugin getBasePlugin(String name) {
+	int library_size = library.size();
+	for(int i = 0; i < library_size; i++) {
+	    Plugin plugin = (Plugin) library.get(i);
+	    if(plugin.getName().equals(name)) {
+		return plugin;
+	    }
+	}
+	// No success.
+	return null;
+    }
+
+    /** Overrides getSize in DOMProxyListModel to take into account the row count modifier used to hide the last three rows in lower detail modes
+     * @return an int indicating the number of rows in the model, or more correctly the desired number of rows to display
+     */
+    public int getSize() {
+	int result = super.getSize();
+	if(modify_row_count) {
+	    result = result-3;
+	}
+	return result;
+    }
+
+    /** Called when the detail mode has changed which in turn may cause several design elements to be available/hidden
+     * @param mode the new mode as an int
+     */
+    public void modeChanged(int mode) {
+	if(controls != null) {
+	    ((PluginControl)controls).modeChanged(mode);
+	}
+    }    
+
+    /** Method to move a plugin in the list order.
+     * @param plugin the Plugin you want to move.
+     * @param direction true to move the plugin up, false to move it down.
+     * @param all true to move to move all the way, false for a single step.
+     */
+    // why are all the error notices there when the buttons are disabled is you cant move???
+    private void movePlugin(Plugin plugin, boolean direction, boolean all) {
+	// Can't ever move RecPlug or ArcPlug
+	if(super.getSize() < 4) {
+	    //DebugStream.println("Not enough plugins to allow moving.");
+	    return;
+	}
+	if(plugin.getName().equals(StaticStrings.ARCPLUG_STR) || plugin.getName().equals(StaticStrings.RECPLUG_STR)) {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.Fixed"), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
+	    return;
+	}
+	if(all) {
+	    // Move to top
+	    if(direction) {
+		// Remove the moving plugin
+		remove(plugin);
+		// Retrieve the first plugin
+		Plugin first_plugin = (Plugin) getElementAt(0);
+		// Add the moving plugin before the first plugin
+		addBefore(plugin, first_plugin);
+		first_plugin = null;
+		Gatherer.c_man.configurationChanged();
+	    }
+	    else {
+		// Remove the moving plugin
+		remove(plugin);
+		// Add the moving plugin before the separator
+		addBefore(plugin, separator_plugin);
+		Gatherer.c_man.configurationChanged();
+	    }
+	}
+	else {
+	    // Try to move the plugin one step in the desired direction.
+	    int index = indexOf(plugin);
+	    ///ystem.err.println("Index of " + plugin + " = " + index);
+	    if(direction) {
+		index--;
+		if(index < 0) {
+		    String args[] = new String[2];
+		    args[0] = Dictionary.get("CDM.PlugInManager.PlugIn_Str");
+		    args[1] = plugin.getName();
+		    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.At_Top", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
+		    return;
+		}
+		remove(plugin);
+		add(index, plugin);
+		Gatherer.c_man.configurationChanged();
+	    }
+	    else {
+		index++;
+		Plugin next_plugin = (Plugin) getElementAt(index);
+		if(next_plugin.isSeparator()) {
+		    String args[] = new String[1];
+		    args[0] = plugin.getName();
+		    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.Move.Cannot", args), Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
+		    // Still not going to move RecPlug or ArcPlug.
+		    return;
+		}
+		remove(plugin);
+		add(index, plugin);
+		Gatherer.c_man.configurationChanged();
+	    }
+	}
+    }
+
+    /** We attempt to place the separator between the unfixed and the fixed plugins. Since we only know of two fixed plugins, we search for either of them, and place the separator before them.
+     */
+    public void placeSeparator() {
+	///ystem.err.println("Placing separator.");
+	int separator_index = super.getSize();
+	if(separator_index > 0) { 
+	    boolean found_fixed = false;
+	    int index = separator_index - 1;
+	    while(index > 0) {
+		Plugin plugin = (Plugin) getElementAt(index);
+		String name = plugin.getName();
+		if(name.equals(StaticStrings.RECPLUG_STR) || name.equals(StaticStrings.ARCPLUG_STR)) {
+		    found_fixed = true;
+		    index--;
+		}
+		else {
+		    if(found_fixed) {
+			separator_index = index + 1;
+			index = -1;
+		    }
+		    else {
+			index--;
+		    }
+		}
+		name = null;
+		plugin = null;
+	    }
+	}
+	Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
+	element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, CollectionConfiguration.SEPARATOR_ATTRIBUTE);
+	element.setAttribute(CollectionConfiguration.SEPARATOR_ATTRIBUTE, CollectionConfiguration.TRUE_STR);
+	separator_plugin = new Plugin(element, null);
+	///atherer.println("Adding plugin separator at: " + separator_index);
+	add(separator_index, separator_plugin);
+    }
+
+    /** This method removes an assigned plugin. I was tempted to call it unassign, but remove is more consistant. Note that there is no way to remove a plugin from the library.
+     * @param plugin The <strong>Plugin</strong> to remove.
+     */
+    private void removePlugin(Plugin plugin) {
+	remove(plugin);
+	Gatherer.c_man.configurationChanged();
+    }
+
+    /** Method to cache the current contents of library (known plugins) to file.
+     */
+    private void savePlugins() {
+	try {
+	    File plugins_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "plugins.dat");
+	    FileOutputStream file = new FileOutputStream(plugins_dat_file);
+	    ObjectOutputStream out = new ObjectOutputStream(file);
+	    out.writeObject(library);
+	    out.close();
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+    }
+
+    /** Inform the model to hide/show the last three lines on the list.
+     * @param modify_row_count true to hide the last three lines, false otherwise
+     */
+    private void setHideLines(boolean modify_row_count) {
+	this.modify_row_count = modify_row_count;
+	int original_size = super.getSize();
+	if(modify_row_count) {
+	    fireIntervalRemoved(this, original_size - 4, original_size - 1);
+	}
+	else {
+	    fireIntervalAdded(this, original_size - 4, original_size - 1);
+	}
+    }
+
+    /** Determine the current separator index. */
+    private int findSeparatorIndex() {
+	int separator_index = super.getSize() - 1;
+	while(separator_index >= 0) {
+	    Plugin search = (Plugin) getElementAt(separator_index);
+	    if(search.isSeparator()) {
+		return separator_index;
+	    }
+	    separator_index--;
+	}
+	return separator_index;
+    }
+
+
+    /** Retrieve a list of those plugins that are in library but not in the assigned plugins. */
+    private Object[] getAvailable() {
+	ArrayList available = new ArrayList();
+	int library_size = library.size();
+	for(int i = 0; i < library_size; i++) {
+	    Plugin plugin = (Plugin) library.get(i);
+	    if(!plugin.isAbstract()) {
+		available.add(plugin);
+	    }
+	    plugin = null;
+	}
+	// Now go through the assigned plugins, and remove any that match.
+	available.removeAll(children());
+	//DebugStream.println("There are a total of " + library.size() + " plugins in the library.");
+	//DebugStream.println("However " + children().size() + " are in use,");
+	//DebugStream.println("So only " + available.size() + " remain.");
+	Collections.sort(available);
+	return available.toArray();
+    }
+
+    /** Method to extract just the plugins name from a file object.
+     * @param plugin The <strong>File</strong> which references a certain plugin.
+     * @return A <strong>String</strong> containing just the plugins name, without extension.
+     */
+    private String getPluginName(String filename) {
+	String name = filename;
+	if(name.indexOf(".") != -1) {
+	    name = name.substring(0, name.indexOf("."));
+	}
+	return name;
+    }
+
+
+    /** Method to load the details of a single plug-in.
+     * @param plugin The plugin <strong>File</strong> you wish to load.
+     */
+    private void loadPlugin(String plugin, String lang) {
+	Document document = null;
+	InputStream input_stream = null;
+	
+	// Run pluginfo on this plugin, and then send the results for parsing.
+	try {
+	    if (Gatherer.isGsdlRemote) {
+		String launch  = Gatherer.cgiBase + "launch";
+		launch += "?cmd=pluginfo.pl";
+		launch += "&xml=&language="+lang;
+		launch += "&plug=" + getPluginName(plugin);
+		
+		System.err.println("*** launch = " + launch);
+		
+		URL launch_url = new URL(launch);
+		URLConnection launch_connection = launch_url.openConnection();
+		input_stream = launch_connection.getInputStream();
+	    }
+	    else {
+		String args[] = null;
+		if(Utility.isWindows()) {
+		    args = new String[6];
+		    if(Configuration.perl_path != null) {
+			args[0] = Configuration.perl_path;
+		    }
+		    else {
+			args[0] = "Perl.exe";
+		    }
+		    args[1] = LocalGreenstone.getBinScriptDirectoryPath() + "pluginfo.pl";
+		    args[2] = "-xml";
+		    args[3] = "-language";
+		    args[4] = lang;
+		    args[5] = getPluginName(plugin);
+		}
+		else {
+		    args = new String[5];
+		    args[0] = "pluginfo.pl";
+		    args[1] = "-xml";
+		    args[2] = "-language";
+		    args[3] = lang;
+		    args[4] = getPluginName(plugin);
+		}
+
+		// Create the process.
+		Runtime runtime = Runtime.getRuntime();
+		Process process = runtime.exec(args);
+		input_stream = process.getErrorStream();
+	    }
+
+	    StringBuffer xml = Utility.readXMLStream(input_stream);
+	    document = CollectionDesignManager.XMLStringToDOM(xml,plugin);
+	}
+	catch (Exception error) {
+	    System.err.println("Failed when trying to parse: " + plugin);
+	    error.printStackTrace();
+	}
+	if(document != null) {
+	    parseXML(document.getDocumentElement());
+	}
+    }
+
+    /** Method to initially load information from the standard plug-ins within the gsdl Perl library.
+     */
+    private void loadPlugins() {
+	// Attempt to restore the cached file.
+	File plugins_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "plugins.dat");
+	try {
+	    FileInputStream file = new FileInputStream(plugins_dat_file);
+	    ObjectInputStream input = new ObjectInputStream(file);
+	    library = (ArrayList) input.readObject();
+	}
+	catch (Exception error) {
+	    DebugStream.println("Unable to open " + plugins_dat_file);
+	}
+
+	if(library == null) {
+	    library = new ArrayList();
+	    if (Gatherer.isGsdlRemote) {
+
+		String lang = Configuration.getLanguage();
+
+		String launch  = Gatherer.cgiBase + "launch";
+		launch += "?cmd=pluginfo.pl";
+		launch += "&xml=&language="+lang;
+		launch += "&listall=";
+
+		System.err.println("*** launch = " + launch);
+
+		try {
+		    URL launch_url = new URL(launch);
+		    URLConnection launch_connection = launch_url.openConnection();
+		    InputStream input_stream = launch_connection.getInputStream();
+		    loadPlugins(input_stream);
+		}
+		catch (Exception error) {
+		    System.err.println("Failed when trying to connect to : " + launch);
+		    error.printStackTrace();
+		}
+
+	    }
+	    else {
+		// Retrieve the gsdl home directory...
+		String directory = LocalGreenstone.getDirectoryPath();
+		directory = directory + "perllib" + File.separator + "plugins" + File.separator;
+		loadPlugins(new File(directory));
+	    }
+	}
+    }
+
+
+
+
+    /** Method to load plug-in information from a specified input stream (could be local or through URL). Of course no plug-ins may be found at this location.
+     * @param input_stream An <strong>InputStream</strong> indicating the where list of plugins -- encoded in XML -- can be read from
+     */
+    private void loadPlugins(InputStream input_stream) 
+    {
+	StringBuffer xml  = Utility.readXMLStream(input_stream);
+	Document document = CollectionDesignManager.XMLStringToDOM(xml, "-listall");
+
+	// Parse XML to build up list of plugin names
+	Node root = document.getDocumentElement();
+
+	NamedNodeMap attributes = root.getAttributes();
+	Node length_node = attributes.getNamedItem("length");
+	String num_plugins_str = length_node.getNodeValue();
+	int num_plugins = Integer.parseInt(num_plugins_str);
+	String plugin_list[] = new String[num_plugins];
+
+	Node node = root.getFirstChild();
+	int i = 0;
+	while (node != null) {
+	    String node_name = node.getNodeName();
+	    if (node_name.equalsIgnoreCase("PluginName")) {
+		String name = XMLTools.getValue(node);
+		plugin_list[i] = name;
+		i++;		
+	    }
+
+	    node = node.getNextSibling();
+	}
+
+
+	boolean is_windows = Utility.isWindows();
+	boolean is_mac = Utility.isMac();
+
+	String current_lang = Configuration.getLanguage();
+	if (num_plugins>0) {
+	    // Create a progress indicator.
+	    ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.PlugInManager.Parsing.Title"), Dictionary.get("CDM.PlugInManager.Parsing.Message"), num_plugins);
+
+	    for (i=0; i<num_plugins; i++) {
+		String plugin = plugin_list[i];
+		if (plugin.equals("GMLPlug.pm") || ((is_windows || is_mac) && plugin.equals("DBPlug.pm"))) {
+		    // don't load GMLPlug or DBPlug for windows
+		} else {
+		    loadPlugin(plugin, current_lang);
+		}
+		
+		progress.inc();
+	    }
+	    progress.dispose();
+	    progress.destroy();
+	    progress = null;
+	}
+    }
+
+
+    /** Method to load plug-in information from a specified directory. Of course no plug-ins may be found at this location.
+     * @param directory A <strong>File</strong> indicating the directory to be scanned for plug-ins.
+     */
+    private void loadPlugins(File directory) {
+	File files[] = directory.listFiles();
+	boolean is_windows = Utility.isWindows();
+	boolean is_mac = Utility.isMac();
+	String current_lang = Configuration.getLanguage();
+	if(files != null) {
+	    // Create a progress indicator.
+	    ParsingProgress progress = new ParsingProgress(Dictionary.get("CDM.PlugInManager.Parsing.Title"), Dictionary.get("CDM.PlugInManager.Parsing.Message"), files.length);
+	    for(int i = 0; i < files.length; i++) {
+		// We only want to check Perl Modules.
+		if(files[i].getName().endsWith(".pm")) {
+		    if (files[i].getName().equals("GMLPlug.pm") || ((is_windows || is_mac) && files[i].getName().equals("DBPlug.pm"))) {
+			// don't load GMLPlug or DBPlug for windows
+		    } else {
+			loadPlugin(files[i].getName(), current_lang);
+		    }
+		}
+		progress.inc();
+	    }
+	    progress.dispose();
+	    progress.destroy();
+	    progress = null;
+	}
+    }
+
+    private Plugin parseXML(Node root) {
+	Plugin plugin = new Plugin();
+	String node_name = null;
+	for (Node node = root.getFirstChild(); node != null; node = node.getNextSibling()) {
+	    node_name = node.getNodeName();
+	    if(node_name.equalsIgnoreCase("Name")) {
+		String name = XMLTools.getValue(node);
+		// We can save ourselves some processing time if a plugin with this name already exists in our manager. If so retrieve it and return it.
+		Plugin existing = getBasePlugin(name);
+		if(existing != null) {
+		    return existing;
+		}
+		plugin.setName(name);
+	    }
+	    else if (node_name.equalsIgnoreCase("Desc")) {
+		plugin.setDescription(XMLTools.getValue(node));
+	    }
+	    else if (node_name.equalsIgnoreCase("Abstract")) {
+		plugin.setIsAbstract(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
+	    }
+	    else if (node_name.equalsIgnoreCase("Explodes")) {
+		plugin.setDoesExplodeMetadataDatabases(XMLTools.getValue(node).equalsIgnoreCase(StaticStrings.YES_STR));
+		//System.err.println("Plugin " + plugin.getName() + " explodes metadata databases: " + plugin.doesExplodeMetadataDatabases());
+	    }
+	    // Parse the multitude of arguments
+	    else if(node_name.equalsIgnoreCase("Arguments")) {
+		for(Node arg = node.getFirstChild(); arg != null; arg = arg.getNextSibling()) {
+		    node_name = arg.getNodeName();
+		    // An option.
+		    if(node_name.equalsIgnoreCase("Option")) {
+			Argument argument = new Argument();
+			argument.parseXML((Element)arg);
+			plugin.addArgument(argument);
+		    }
+		    // A super plugin class.
+		    else if(node_name.equalsIgnoreCase("PlugInfo")) {
+			Plugin super_plugin = parseXML(arg);
+			plugin.setSuper(super_plugin);
+		    }
+		}
+	    }
+	}
+	if(plugin.getName() != null) {
+	    addPlugin(plugin);
+	    return plugin;
+	}
+	return null;
+    }
+
+    /** A class which provodes controls for assigned and editing plugins. */
+    private class PluginControl
+	extends JPanel
+	implements Control {
+	/** Button for adding plugins. */
+	private JButton add = null;
+	/** Button for configuring the selected plugin. */
+	private JButton configure = null;
+	/** Buttom to move an assinged plugin as low in the order as possible. */
+	//private JButton move_bottom_button = null;
+	/** Button to move an assigned plugin one position lower in the order. */
+	private JButton move_down_button = null;
+	/** Button to move an assigned plugin as high in the order as possible. */
+	//private JButton move_top_button = null;
+	/** Button to move an assigned plugin one position higher in the order. */
+	private JButton move_up_button = null;
+	/** Button to remove the selected plugin. */
+	private JButton remove = null;
+	/** A combobox containing all of the known plugins, including those that may have already been assigned. */
+	private GComboBox plugin = null;
+	/** The label next to the plugin combobox. */
+	private JLabel plugin_label = null;
+	/** The label above the assigned plugin list. */
+	private JLabel plugin_list_label = null;
+	/** The title of this view. */
+	private JLabel title = null;
+	/** A list of assigned plugins. */
+	private JList plugin_list = null;
+	/** The area where the add, configure and remove buttons are placed. */
+	private JPanel button_pane = null;
+	/** The region which divides the central portion of the view into list and controls */
+	private JPanel central_pane = null;
+	/** The area where title label and instructions sit. */
+	private JPanel header_pane = null;
+	/** The area where movement buttons are placed. */
+	private JPanel movement_pane = null;
+	/** The small region containing the plugin combobox and its label. */
+	private JPanel plugin_pane = null;
+	/** The pane containing the assigned plugin list and its label. */
+	private JPanel plugin_list_pane = null;
+	/** The text area containing instructions on the use of this control. */
+	private JTextArea instructions = null;
+
+	/** Constructor.
+	 */
+	public PluginControl() {
+	    // Create
+	    add = new GLIButton();
+	    add.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add, "CDM.PlugInManager.Add", "CDM.PlugInManager.Add_Tooltip");
+
+	    button_pane = new JPanel();
+	    central_pane = new JPanel();
+
+	    configure = new GLIButton();
+	    configure.setEnabled(false);
+	    configure.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.registerBoth(configure, "CDM.PlugInManager.Configure", "CDM.PlugInManager.Configure_Tooltip");
+
+	    header_pane = new JPanel();
+
+	    instructions = new JTextArea();
+	    instructions.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    instructions.setEditable(false);
+	    instructions.setLineWrap(true);
+	    instructions.setRows(6);
+	    instructions.setWrapStyleWord(true);
+	    Dictionary.registerText(instructions, "CDM.PlugInManager.Instructions");
+
+	    move_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
+	    move_up_button.setEnabled(false);
+	    move_up_button.setMnemonic(KeyEvent.VK_U);
+	    Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
+
+	    move_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
+	    move_down_button.setEnabled(false);
+	    move_down_button.setMnemonic(KeyEvent.VK_D);
+	    Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
+
+	    movement_pane = new JPanel();
+
+	    PluginComboboxListener picl = new PluginComboboxListener();
+	    plugin = new GComboBox(getAvailable());
+	    plugin.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
+	    plugin.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
+	    plugin.setEditable(true);
+	    plugin.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
+	    plugin.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
+	    picl.itemStateChanged(new ItemEvent(plugin, 0, null, ItemEvent.SELECTED));
+
+	    plugin_label = new JLabel();
+	    Dictionary.registerText(plugin_label, "CDM.PlugInManager.PlugIn");
+
+	    plugin_list = new JList(model);
+	    plugin_list.setCellRenderer(new ListRenderer());
+	    plugin_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	    plugin_list_label = new JLabel();
+	    plugin_list_label.setHorizontalAlignment(JLabel.CENTER);
+	    plugin_list_label.setOpaque(true);
+	    Dictionary.registerText(plugin_list_label, "CDM.PlugInManager.Assigned");
+
+	    plugin_list_pane = new JPanel();
+	    plugin_pane = new JPanel();
+
+	    remove = new GLIButton();
+	    remove.setEnabled(false);
+	    remove.setMnemonic(KeyEvent.VK_R);
+	    Dictionary.registerBoth(remove, "CDM.PlugInManager.Remove", "CDM.PlugInManager.Remove_Tooltip");
+
+	    title = new JLabel();
+	    title.setHorizontalAlignment(JLabel.CENTER);
+	    title.setOpaque(true);
+	    Dictionary.registerText(title, "CDM.PlugInManager.Title");
+
+	    // Listeners
+	    add.addActionListener(new AddListener()); //all_change_listener is listening to the ArgumentConfiguration
+	    configure.addActionListener(new ConfigureListener());
+	    MoveListener ml = new MoveListener();
+	    //move_bottom_button.addActionListener(ml);
+	    move_down_button.addActionListener(ml);
+	    move_down_button.addActionListener(CollectionDesignManager.all_change_listener);
+	    //move_top_button.addActionListener(ml);
+	    move_up_button.addActionListener(ml);
+	    move_up_button.addActionListener(CollectionDesignManager.all_change_listener);
+	    plugin.addItemListener(picl);
+	    remove.addActionListener(new RemoveListener());
+	    remove.addActionListener(CollectionDesignManager.all_change_listener);
+	    plugin_list.addMouseListener(new ClickListener());
+	    plugin_list.addListSelectionListener(new ListListener());
+	    picl = null;
+
+	    // Layout
+	    title.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
+
+	    instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
+
+	    header_pane.setLayout(new BorderLayout());
+	    header_pane.add(title, BorderLayout.NORTH);
+	    header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
+
+	    plugin_list_label.setBorder(BorderFactory.createEmptyBorder(0,2,0,2));
+
+	    movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
+	    movement_pane.setLayout(new GridLayout(4,1));
+	    movement_pane.add(move_up_button);
+	    movement_pane.add(new JPanel());
+	    movement_pane.add(new JPanel());
+	    movement_pane.add(move_down_button);
+
+	    plugin_list_pane.setLayout(new BorderLayout());
+	    plugin_list_pane.add(plugin_list_label, BorderLayout.NORTH);
+	    plugin_list_pane.add(new JScrollPane(plugin_list), BorderLayout.CENTER);
+	    modeChanged(Configuration.getMode()); // Whether the movement buttons are visible is mode dependant
+
+	    plugin_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+
+	    plugin_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
+	    plugin_pane.setLayout(new BorderLayout(5,0));
+	    plugin_pane.add(plugin_label, BorderLayout.WEST);
+	    plugin_pane.add(plugin, BorderLayout.CENTER);
+
+	    button_pane.setLayout(new GridLayout(1,3));
+	    button_pane.add(add);
+	    button_pane.add(configure);
+	    button_pane.add(remove);
+
+	    // Scope these mad bordering skillz.
+	    JPanel temp = new JPanel(new BorderLayout());
+	    temp.setBorder
+		(BorderFactory.createCompoundBorder
+		 (BorderFactory.createEmptyBorder(5,0,5,0),
+		  BorderFactory.createCompoundBorder
+		  (BorderFactory.createTitledBorder(Dictionary.get("CDM.PlugInManager.Controls")),
+		   BorderFactory.createEmptyBorder(2,2,2,2))));
+
+	    temp.add(plugin_pane, BorderLayout.NORTH);
+	    temp.add(button_pane, BorderLayout.SOUTH);
+
+	    central_pane.setLayout(new BorderLayout());
+	    central_pane.add(plugin_list_pane, BorderLayout.CENTER);
+	    central_pane.add(temp, BorderLayout.SOUTH);
+
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    add(header_pane, BorderLayout.NORTH);
+	    add(central_pane, BorderLayout.CENTER);
+	}
+
+	/** Method which acts like a destructor, tidying up references to persistant objects.
+	 */
+	public void destroy() {
+	}
+
+	/** This method is overridden to ensure the instructions are scrolled to top, before the super classes updateUI() is called.
+	 */
+	public void gainFocus() {
+	    if(instructions != null) {
+		instructions.setCaretPosition(0);
+	    }
+	    super.updateUI();
+	}
+
+	public void loseFocus() {
+	}
+
+	/** The current detail mode controls two aspects of plugin manager: whether the movement buttons are visible and whether the fixed position plugins Arc and RecPlug are in the list
+	 * @param mode the current mode as an int, which can be matched against static ints in the Configuration class
+	 */
+	public void modeChanged(int mode) {
+	    // First of all we clear the current selection, as there can be some serious problems if the user selects the plugins we're hiding, or had the last plugin selected before we unhid the last three
+	    plugin_list.clearSelection();
+	    // The first change is dependant on whether the user is systems mode or higher
+	    if(mode >= Configuration.SYSTEMS_MODE) {
+		// Show movement buttons
+		plugin_list_pane.add(movement_pane, BorderLayout.EAST);
+		// Do we show Arc and RecPlugs or hide them and the separator line
+		setHideLines(!(mode >= Configuration.EXPERT_MODE));
+	    }
+	    // Otherwise hide the movement buttons and fixed plugins
+	    else {
+		plugin_list_pane.remove(movement_pane);
+		setHideLines(true);
+	    }
+	    plugin_list_pane.updateUI();
+	}
+
+	/** This class listens for actions upon the add button in the controls, and if detected calls the <i>assignPlugin()</i> method. */
+	private class AddListener
+	    implements ActionListener {
+	    /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
+	     * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		Object selected_object = plugin.getSelectedItem();
+		if(selected_object != null) {
+		    // Retrieve the base plugin if any
+		    Plugin base_plugin = getBasePlugin(selected_object.toString());
+
+		    // Create a new element in the DOM
+		    Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
+		    // Remember that the plugin supplied might be a custom string rather than a base plugin
+		    Plugin new_plugin = null;
+		    if(base_plugin != null) {
+			//DebugStream.println("New Plugin based on existing Plugin");
+			element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
+			new_plugin = new Plugin(element, base_plugin);
+		    }
+		    else {
+			//DebugStream.println("New Custom Plugin");
+			element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
+			new_plugin = new Plugin(element, null);
+		    }
+		    if(!model.contains(new_plugin) || new_plugin.getName().equals(StaticStrings.UNKNOWNPLUG_STR)) {
+			// Automatically chain to configuration. This ensures required arguments are filled out.
+			ArgumentConfiguration ac = new ArgumentConfiguration(new_plugin);
+			if(ac.display()) {
+			    assignPlugin(new_plugin);
+			    plugin_list.setSelectedValue(new_plugin, true);
+			    // Since we weren't cancelled, and if there was a base plugin, ensure it no longer is shown as available, unless it is the UnknownPlugin which can be added several times
+			    if(base_plugin != null && !base_plugin.getName().equals(StaticStrings.UNKNOWNPLUG_STR)) {
+				plugin.removeItem(base_plugin);
+			    }
+			}
+			ac = null;
+			new_plugin = null;
+			plugin.setSelectedIndex(0);
+		    }
+		    else {
+			JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CDM.PlugInManager.PlugIn_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		    }
+		    base_plugin = null;
+		}
+	    }
+	}
+
+	/** Listens for double clicks apon the list and react as if the configure button was pushed. */
+	private class ClickListener
+	    extends MouseAdapter {
+	    /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
+	     * @param event A <strong>MouseEvent</strong> containing information about the mouse click.
+	    */
+	    public void mouseClicked(MouseEvent event) {
+		if(event.getClickCount() == 2 ) {
+		    if(!plugin_list.isSelectionEmpty()) {
+			Plugin plugin = (Plugin) plugin_list.getSelectedValue();
+			if(!plugin.isSeparator()) {
+			    ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
+			    if(ac.display()) {
+				refresh(plugin);
+			    }
+			    ac.destroy();
+			    ac = null;
+			}
+		    }
+		}
+	    }
+	}
+
+	/** This class listens for actions upon the configure button in the controls, and if detected creates a new <strong>ArgumentConfiguration</strong> dialog box to allow for configuration.
+	 * @see org.greenstone.gatherer.cdm.ArgumentConfiguration
+	 */
+	private class ConfigureListener
+	    implements ActionListener {
+	    /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
+	     * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		if(!plugin_list.isSelectionEmpty()) {
+		    Plugin plugin = (Plugin) plugin_list.getSelectedValue();
+		    if(!plugin.isSeparator()) {
+			ArgumentConfiguration ac = new ArgumentConfiguration(plugin);
+			if(ac.display()) {
+			    refresh(plugin);
+			}
+			ac.destroy();
+			ac = null;
+		    }
+		}
+	    }
+	}
+
+	/** listens for changes in the list selection and enables the configure and remove buttons if there is a selection, disables them if there is no selection */
+	private class ListListener
+	    implements ListSelectionListener {
+
+	    public void valueChanged(ListSelectionEvent e) {
+		if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one (the second one)
+		    if (plugin_list.isSelectionEmpty()) {
+			//move_top_button.setEnabled(false);
+			move_up_button.setEnabled(false);
+			move_down_button.setEnabled(false);
+			//move_bottom_button.setEnabled(false);
+			configure.setEnabled(false);
+			remove.setEnabled(false);
+		    }
+		    else {
+			Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
+			if(selected_plugin.isSeparator()) {
+			    //move_top_button.setEnabled(false);
+			    move_up_button.setEnabled(false);
+			    move_down_button.setEnabled(false);
+			    //move_bottom_button.setEnabled(false);
+			    configure.setEnabled(false);
+			    remove.setEnabled(false);
+			}
+			else {
+			    configure.setEnabled(true);
+			    String plugin_name = selected_plugin.getName();
+			    // Some buttons are only available for plugins other than ArcPlug and RecPlug 
+			    if(plugin_name.equals(StaticStrings.ARCPLUG_STR) || plugin_name.equals(StaticStrings.RECPLUG_STR) ) {
+				//move_top_button.setEnabled(false);
+				move_up_button.setEnabled(false);
+				move_down_button.setEnabled(false);
+				//move_bottom_button.setEnabled(false);
+				remove.setEnabled(false);
+			    }
+			    else {
+				// don't let people remove special plugins such GAPlug an METSPlug,
+				// unless they are in systems mode or above
+				int mode = Configuration.getMode();
+				for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
+				    if ((plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
+					(mode < Configuration.SYSTEMS_MODE)) {
+					remove.setEnabled(false); 
+					break;
+				    } else {
+					remove.setEnabled(true);
+				    }
+				}
+				    
+				// Move ups are only enabled if the selected plugin isn't already at the top 
+				Plugin first_plugin = (Plugin) getElementAt(0);
+				if(!first_plugin.equals(selected_plugin)) {
+				    //move_top_button.setEnabled(true);
+				    move_up_button.setEnabled(true);
+				}
+				else {
+				    //move_top_button.setEnabled(false);
+				    move_up_button.setEnabled(false);
+				}
+				// And move downs are only allowed when the selected plugin isn't at an index one less than the separator line.
+				int separator_index = findSeparatorIndex();
+				int selected_index = plugin_list.getSelectedIndex();
+				if(selected_index < separator_index - 1) {
+				    move_down_button.setEnabled(true);
+				    //move_bottom_button.setEnabled(true);
+				}
+				else {
+				    move_down_button.setEnabled(false);
+				    //move_bottom_button.setEnabled(false);
+				}
+			    }
+			    selected_plugin = null;
+			    plugin_name = null;
+			}
+		    }
+		}
+	    }
+	}
+
+	/** A special list renderer which is able to render separating lines as well. */
+	private class ListRenderer
+	    extends DefaultListCellRenderer {
+	    /** Return a component that has been configured to display the specified value. That component's paint method is then called to "render" the cell. If it is necessary to compute the dimensions of a list because the list cells do not have a fixed size, this method is called to generate a component on which getPreferredSize  can be invoked.
+	     * @param list - The <strong>JList</strong> we're painting.
+	     * @param value - The value returned by list.getModel().getElementAt(index) as an <strong>Object</strong>.
+	     * @param index - The cells index as an <i>int</i>.
+	     * @param isSelected - <i>true</i> if the specified cell was selected.
+	     * @param cellHasFocus - <i>true</i> if the specified cell has the focus.
+	     * @return A <strong>Component</strong> whose paint() method will render the specified value.
+	     * @see javax.swing.JList
+	     * @see javax.swing.JSeparator
+	     * @see javax.swing.ListModel
+	     * @see javax.swing.ListSelectionModel
+	     */
+	    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+		Plugin plugin = (Plugin) value;
+		if(plugin.isSeparator()) {
+		    return separator;
+		}
+		else {
+		    return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+		}
+	    }
+	}
+
+
+	/** Listens for actions apon the move buttons in the manager controls, and if detected calls the <i>movePlugin()</i> method of the manager with the appropriate details. */
+	private class MoveListener
+	    implements ActionListener {
+	    /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
+	     * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		if (!plugin_list.isSelectionEmpty()) {
+		    Object object = plugin_list.getSelectedValue();
+		    if (object instanceof Plugin) {
+			Plugin plugin = (Plugin) object;
+			//if (event.getSource() == move_top_button) {
+			//    movePlugin(plugin, true, true);
+			//}
+			//else 
+			if (event.getSource() == move_up_button) {
+			    movePlugin(plugin, true, false);
+			}
+			else if (event.getSource() == move_down_button) {
+			    movePlugin(plugin, false, false);
+			}
+			//else if (event.getSource() == move_bottom_button) {
+			//    movePlugin(plugin, false, true);
+			//}
+			plugin_list.setSelectedValue(plugin, true);
+		    }
+		}
+	    }
+	}
+
+	/** This listener reacts to changes in the current selection of the plugin combobox. */
+	private class PluginComboboxListener
+        implements ItemListener {
+        /** When a user selects a certain plugin, update the tooltip to show the plugin description. */
+        public void itemStateChanged(ItemEvent event) {
+            if(event.getStateChange() == ItemEvent.SELECTED) {
+                // Retrieve the selected plugin
+                Object current_selection = plugin.getSelectedItem();
+                // And reset the tooltip. If the plugin is null or is a string, then go back to the default message
+                if(current_selection == null || current_selection instanceof String) {
+                    Dictionary.registerTooltip(plugin, "CDM.PlugInManager.PlugIn_Tooltip");
+                }
+                else {
+                    Plugin current_plugin = (Plugin) current_selection;
+                    Dictionary.registerTooltipText(plugin, Utility.formatHTMLWidth(current_plugin.getDescription(), 40));
+                    current_plugin = null;
+                }
+                current_selection = null;
+            }
+        }
+    }
+	
+	/** This class listens for actions upon the remove button in the controls, and if detected calls the <i>removePlugin()</i> method.
+	 */
+	private class RemoveListener
+	    implements ActionListener {
+	    /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured on one of our target controls.
+	     * @param event An <strong>ActionEvent</strong> containing information garnered from the control action.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		int selected_index = plugin_list.getSelectedIndex();
+		if(selected_index != -1) {
+		    Plugin selected_plugin = (Plugin) plugin_list.getSelectedValue();
+		    removePlugin(selected_plugin);
+		    selected_plugin = null;
+		    // Select the next plugin if available
+		    if(selected_index < plugin_list.getModel().getSize()) {
+			// If the new selection is above the separator we can remove it
+			if(selected_index < findSeparatorIndex()) {
+			    plugin_list.setSelectedIndex(selected_index);
+			    
+			    // don't let people remove special plugins such GAPlug an METSPlug,
+			    // unless they are in systems mode or above
+			    int mode = Configuration.getMode();
+			    for (int i=0; i<StaticStrings.KEEP_PLUG.length; i++) {
+				String selected_plugin_name
+				    = ((Plugin)plugin_list.getSelectedValue()).getName();
+				if ((selected_plugin_name.equals(StaticStrings.KEEP_PLUG[i])) &&
+				    (mode < Configuration.SYSTEMS_MODE)) {
+				    remove.setEnabled(false); 
+				    break;
+				} else {
+				    remove.setEnabled(true);
+				}
+			    }					
+			}
+			// Otherwise select the first non-removable plugin
+			else {
+			    plugin_list.setSelectedIndex(selected_index + 1);
+			    remove.setEnabled(false);
+			}
+		    }
+		    else {
+			remove.setEnabled(false);
+		    }
+		    // Refresh the available plugins
+		    plugin.setModel(new DefaultComboBoxModel(getAvailable()));
+		}
+		else {
+		    remove.setEnabled(false);
+		}
+	    }
+	}
+    }
+    
+
+    private class PluginSuggestionPrompt
+	extends ModalDialog
+	implements ActionListener
+    {
+	private Dimension size = new Dimension(480, 240);
+	private GComboBox suitable_plugins_combobox = null;
+	private GLIButton add_button = null;
+	private GLIButton ignore_button = null;
+
+	public PluginSuggestionPrompt(String filename, ArrayList suitable_plugins)
+	{
+	    super(Gatherer.g_man, true);
+	    setModal(true);
+	    setSize(size);
+	    Dictionary.setText(this, "CDM.PluginManager.SuggestedPluginListTitle");
+
+	    String[] args = new String[1];
+	    args[0] = filename;
+
+	    JTextArea instructions_textarea = new JTextArea();
+	    instructions_textarea.setCaretPosition(0);
+	    instructions_textarea.setEditable(false);
+	    instructions_textarea.setLineWrap(true);
+	    instructions_textarea.setRows(5);
+	    instructions_textarea.setWrapStyleWord(true);
+	    Dictionary.setText(instructions_textarea, "CDM.PluginManager.Plugin_Suggestion_Prompt", args);
+
+	    JLabel suitable_plugins_label = new JLabel();
+	    Dictionary.registerText(suitable_plugins_label, "CDM.PlugInManager.PlugIn");
+	    suitable_plugins_label.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+
+	    suitable_plugins_combobox = new GComboBox(suitable_plugins);
+	    suitable_plugins_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
+	    suitable_plugins_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
+	    suitable_plugins_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
+	    suitable_plugins_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
+
+	    JPanel suitable_plugins_pane = new JPanel();
+	    //suitable_plugins_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
+	    suitable_plugins_pane.setLayout(new BorderLayout(5,0));
+	    suitable_plugins_pane.add(suitable_plugins_label, BorderLayout.WEST);
+	    suitable_plugins_pane.add(suitable_plugins_combobox, BorderLayout.CENTER);
+
+	    add_button = new GLIButton();
+	    Dictionary.setBoth(add_button, "CDM.PlugInManager.Add", "CDM.PlugInManager.Add_Tooltip");
+	    ignore_button = new GLIButton();
+	    Dictionary.setBoth(ignore_button, "CDM.PlugInManager.Ignore","CDM.PlugInManager.Ignore_Tooltip" );
+
+	    add_button.addActionListener(this);
+	    ignore_button.addActionListener(this);
+
+	    JPanel button_pane = new JPanel();
+	    button_pane.setLayout(new GridLayout(1,2,5,0));
+	    button_pane.add(add_button);
+	    button_pane.add(ignore_button);
+
+	    JPanel controls_pane = new JPanel();
+	    controls_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    controls_pane.setLayout(new GridLayout(2,1,0,5));
+	    controls_pane.add(suitable_plugins_pane);
+	    controls_pane.add(button_pane);
+
+	    JPanel content_pane = (JPanel) getContentPane();
+	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(instructions_textarea, BorderLayout.CENTER);
+	    content_pane.add(controls_pane, BorderLayout.SOUTH);
+
+	    // Show
+	    Dimension screen_size = Configuration.screen_size;
+	    setLocation((screen_size.width - size.width) / 2, (screen_size.height - size.height) / 2);
+	    setVisible(true);
+	}
+
+	public void actionPerformed(ActionEvent event) {
+	    
+	    if(event.getSource() == add_button) {
+		// add the selected plugin to the list
+		Object selected_object = suitable_plugins_combobox.getSelectedItem();
+		Plugin base_plugin = getBasePlugin(selected_object.toString());
+
+		// Create a new element in the DOM
+		Element element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.PLUGIN_ELEMENT);
+		// Remember that the plugin supplied might be a custom string rather than a base plugin
+		Plugin new_plugin = null;
+		if(base_plugin != null) {
+		    //DebugStream.println("New Plugin based on existing Plugin");
+		    element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, base_plugin.getName());
+		    new_plugin = new Plugin(element, base_plugin);
+		}
+		else {
+			//DebugStream.println("New Custom Plugin");
+		    element.setAttribute(CollectionConfiguration.TYPE_ATTRIBUTE, selected_object.toString());
+		    new_plugin = new Plugin(element, null);
+		}
+		assignPlugin(new_plugin);
+	    } // else do nothing
+	    
+	    // close the dialog
+	    setVisible(false);
+	}
+
+    }
+
+
+    /** Creates a list separator.
+     * Found on Google Groups. Code courtesy of Paul Farwell.
+     */
+    private JPanel getSeparator() {
+	// We put the separator inside a panel to control its appearance
+	JPanel _sepPanel = new JPanel();
+	_sepPanel.setOpaque(false);
+	_sepPanel.setBorder(BorderFactory.createEmptyBorder(1, 3, 1, 3));
+	_sepPanel.setLayout(new BoxLayout(_sepPanel, BoxLayout.Y_AXIS));
+	_sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
+	// We have to be a little careful here, as the default UI for separators under MacOS is a blank box. Instead we force a BasicUI look
+	_sepPanel.add(new BasicSeparator());
+	_sepPanel.add(Box.createRigidArea(new Dimension(0, 4)));
+	return _sepPanel;
+    }
+
+    /** This class behaves just like a normal JSeparator except that, no matter what the current settings in the UIManager are, it always paints itself with BasicSeparatorUI. */
+    private class BasicSeparator
+	extends JSeparator {
+
+	private ComponentUI basic_ui;
+
+	public BasicSeparator() {
+	    super();
+	    basic_ui = new BasicSeparatorUI();
+	}
+
+	public void paintComponent(Graphics g) {
+	    if (basic_ui != null) {
+		basic_ui.update(g, this);
+	    }   
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SearchType.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SearchType.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SearchType.java	(revision 10506)
@@ -0,0 +1,159 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+/**************************************************************************************
+ * Written:      16/07/03
+ * Revised:      
+ **************************************************************************************/
+import org.w3c.dom.*;
+
+/** This class represents a single search type setting which means that, at the moment, it is either based on an Content element containing the string 'plain' or one on the string 'form'. The ordering of these elements within the SearchType element is important.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.4
+ */
+public class SearchType
+    implements DOMProxyListEntry {
+
+    /** The Element this searchtype object will source its information from. */
+    private Element element;
+    /** A cached version of the string representation, for speed of painting (given toString() might be called several times during a list repaint). */
+    private String text;
+
+    /** Constructor used only during DOMProxyListModel initialization. */
+    public SearchType() {
+    }
+
+    /** Normal constructor.
+     * @param  element the Element this object will find its data from
+     */
+    public SearchType(Element element) {
+	this.element = element;
+    }
+
+    /** Creation of a brand new SearchType 
+     * @param  name the name of this type as a String
+     */
+    public SearchType(String name) {
+	element = CollectionDesignManager.collect_config.document.createElement(CollectionConfiguration.CONTENT_ELEMENT);
+	element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, name);
+	text = null;
+    }
+
+    /** Compare two objects for ordering. 
+     * @param  object the other Object to compare to
+     * @return <0 if this searchtype should be before the given object, 0 if they are equal, and >0 if it should be after
+     */
+    public int compareTo(Object object) {
+	if(object == null) {
+	    return -1;
+	}
+	return toString().compareTo(object.toString());
+    }
+
+    /** Factory-like method to allow DOMProxyListModel to generate new entries.
+     * @param  element the Element the new searchtype should be based on
+     * @return a newly created DOMProxyListEntry for the given element
+     */
+    public DOMProxyListEntry create(Element element) {
+	return new SearchType(element);
+    }
+
+    /** Determine if this searchtype is equavilent to another object.
+     * @param  object the other Other to match against
+     * @return true if the two are equal, false otherwise
+     */
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+
+    /** Retrieve the element this DOMProxyListEntry is based upon. Specified by the interface.
+     * @return the Element in question
+     */
+    public Element getElement() {
+	return element;
+    }
+
+    /** Retrieve the name of this searchtype.
+     * @return the name as a String
+     */
+    public String getName() {
+	return toString();
+    }
+
+    /** Determine is this command has been assigned, either because it already existed in the collection configuration, or because it has been explicitly set by the user. Non-assigned entries imply they have been added by the GLI to ensure consistancy (and avoid NPE's!)
+     * @return true if this command has been assigned, false otherwise
+     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
+     * @see org.greenstone.gatherer.util.StaticStrings
+     */
+    public boolean isAssigned() {
+	return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
+    }
+    
+    /** Set the assigned state.
+     * @param  assigned the desired state of assigned as a boolean
+     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
+     * @see org.greenstone.gatherer.util.StaticStrings
+     */
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    /** Set the element that this DOMProxyListEntry is base on.
+     * @param  element the new Element that this entry should source informatin from
+     */
+    public void setElement(Element element) {
+	this.element = element;
+	this.text = null;
+    }
+
+    /** Set the name of this searchtype.
+     * @param  name the new name for this searchtype, as a String
+     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
+     * @see org.greenstone.gatherer.util.StaticStrings
+     */
+    public void setName(String name) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, name);
+	    this.text = null;
+	}
+    }
+
+    /** Produce a text representation of this searchtype.
+     * @return a String showing this searchtype
+     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
+     * @see org.greenstone.gatherer.util.StaticStrings
+     */
+    public String toString() {
+	if(text == null && element != null) {
+	    text = element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
+	}
+	return text;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SearchTypeManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SearchTypeManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SearchTypeManager.java	(revision 10506)
@@ -0,0 +1,523 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+/**************************************************************************************
+ * Written:      16/07/03
+ * Revised:
+ **************************************************************************************/
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.GComboBox;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.util.JarTools;
+import org.w3c.dom.*;
+
+/** This class maintains an ordered list of the search types available in the collection (MGPP/lucene command available in G2.39 or later). Currently only 'form' and 'plain' are valid.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.4
+ */
+public class SearchTypeManager
+    extends DOMProxyListModel
+{
+    static final private Dimension LABEL_SIZE = new Dimension(150, 25);
+
+    static final public String[] SEARCH_TYPES = {  "plain" , "form"};
+    static final public String[] BUILD_TYPES = {  "lucene", "mgpp" };
+    
+    /** the buildtype element in the config file  - searchtypemanager looks 
+     * after this now */
+    public CollectionMeta build_type = null;
+    /** The controls used to edit the search types. */
+    private Control controls = null;
+    /** A reference to ourselves so our inner classes have access. */
+    private DOMProxyListModel model;
+
+    public SearchTypeManager(Element searchtypes_element) {
+	super(searchtypes_element, CollectionConfiguration.CONTENT_ELEMENT, new SearchType());
+	this.model = this;
+	DebugStream.println("SearchTypeManager: parsed " + getSize() + " search types.");
+	build_type = new CollectionMeta(CollectionDesignManager.collect_config.getBuildType());
+
+    }
+
+    private void addSearchType(SearchType searchtype) {
+	if(!contains(searchtype)) {
+	    add(getSize(), searchtype);
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+    
+    public Control getControls() {
+	if(controls == null) {
+	    controls = new SearchTypeControl();
+	}
+	return controls;
+    }
+
+    /** Return a list of the currently assigned search types as a comma separated string.
+     * @return a String
+     */
+    public String getSearchTypes() {
+	StringBuffer search_types = new StringBuffer();
+	ArrayList types = children();
+	for (int i = 0; i < types.size(); i++) {
+	    if (i>0) {
+		search_types.append(",");
+	    }
+	    search_types.append(((SearchType)types.get(i)).getName());
+	}
+	return search_types.toString();
+    }
+    
+    /** By examining the SearchType 'root' we were created with, determine if mgpp is enabled.
+     * @return true if MGPP is enabled, false otherwise
+     */
+    public boolean isMGPPEnabled() {
+	return root.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.TRUE_STR);
+    }
+    
+    private void moveSearchType(SearchType search_type, boolean direction) {
+	// Try to move the classifier one step in the desired direction.
+	int index = indexOf(search_type);
+	if(direction) {
+	    index--;
+	}
+	else {
+	    index++;
+	}
+	// Check we aren't at an edge
+	if((direction && index < 0) || (!direction && index >= getSize())) {
+	    String args[] = new String[2];
+	    args[0] = Dictionary.get("CDM.SearchTypeManager.SearchType");
+	    args[1] = search_type.toString();
+	    String message = null;
+	    if (direction) {
+		message = Dictionary.get("CDM.Move.At_Top", args);
+	    }
+	    else {
+		message = Dictionary.get("CDM.Move.At_Bottom", args);
+	    }
+	    JOptionPane.showMessageDialog(Gatherer.g_man, message, Dictionary.get("CDM.Move.Title"), JOptionPane.ERROR_MESSAGE);
+	    return;
+	}
+	remove(search_type);
+	add(index, search_type);
+	Gatherer.c_man.configurationChanged();
+    }
+
+    private void removeSearchType(SearchType searchtype) {
+	if(contains(searchtype)) {
+	    remove(searchtype);
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+
+    private class SearchTypeControl
+	extends JPanel
+	implements Control {
+
+	private GComboBox search_type_combobox;
+	private GComboBox build_type_combobox;
+
+	private JButton add_button;
+	private JButton move_down_button;
+	private JButton move_up_button;
+	private JButton remove_button;
+
+	private JCheckBox enable_advanced_searches_checkbox;
+
+	private JLabel current_search_types_label;
+	private JLabel search_type_label;
+	private JLabel title_label;
+
+	private JList current_search_types_list;
+
+	private JTextArea instructions_textarea;
+
+	public SearchTypeControl() {
+	
+	    // Creation
+	    title_label = new JLabel();
+	    title_label.setHorizontalAlignment(JLabel.CENTER);
+	    Dictionary.registerText(title_label, "CDM.SearchTypeManager.Title");
+
+	    JPanel instructions_panel = new JPanel();
+	    instructions_textarea = new JTextArea();
+	    instructions_textarea.setCaretPosition(0);
+	    instructions_textarea.setEditable(false);
+	    instructions_textarea.setLineWrap(true);
+	    instructions_textarea.setRows(6);
+	    instructions_textarea.setWrapStyleWord(true);
+	    Dictionary.registerText(instructions_textarea, "CDM.SearchTypeManager.Instructions");
+
+	    JPanel spacer_panel = new JPanel();
+
+	    JPanel empty_panel = new JPanel();
+
+	    JPanel inner_panel = new JPanel();
+
+	    JPanel indexer_type_panel = new JPanel();
+	    JPanel build_type_panel = new JPanel();
+
+	    enable_advanced_searches_checkbox = new JCheckBox();
+	    Dictionary.registerText(enable_advanced_searches_checkbox, "CDM.SearchTypeManager.Enable");
+
+	    build_type_combobox = new GComboBox(BUILD_TYPES);
+	    build_type_combobox.setPreferredSize(LABEL_SIZE);
+	    build_type_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
+	    build_type_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
+	    build_type_combobox.setEditable(true);
+	    build_type_combobox.setSelectedIndex(1);// mgpp is at 1
+	    String selected_value = build_type.getValue(CollectionMeta.TEXT);
+	    if (!selected_value.equals("")) {
+		for (int i=0; i<build_type_combobox.getItemCount();i++) {
+		    String item = (String)build_type_combobox.getItemAt(i);
+		    if (item.equals(selected_value)) {
+			build_type_combobox.setSelectedIndex(i);
+			break;
+		    }
+		}
+	    } else {
+		build_type.setValue((String)build_type_combobox.getSelectedItem());
+		build_type.setAssigned(isMGPPEnabled());
+
+	    }
+	    build_type_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
+	    build_type_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.registerTooltip(build_type_combobox, "CDM.SearchTypeManager.BuildType_Selection_Tooltip");
+
+	    JLabel build_type_label = new JLabel();
+	    Dictionary.registerText(build_type_label, "CDM.SearchTypeManager.BuildType_Selection");
+	    JPanel current_search_types_panel = new JPanel();
+	    current_search_types_label = new JLabel();
+	    Dictionary.registerText(current_search_types_label, "CDM.SearchTypeManager.Assigned");
+	    current_search_types_list = new JList(model);
+	    current_search_types_list.setVisibleRowCount(3);
+
+	    JPanel movement_panel = new JPanel();
+
+	    move_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
+	    move_up_button.setEnabled(false);
+	    move_up_button.setMnemonic(KeyEvent.VK_U);
+
+	    Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
+
+	    move_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
+	    move_down_button.setEnabled(false);
+	    move_down_button.setMnemonic(KeyEvent.VK_D);
+
+	    Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
+
+	    JPanel search_type_panel = new JPanel();
+	    search_type_label = new JLabel();
+	    Dictionary.registerText(search_type_label, "CDM.SearchTypeManager.SearchType_Selection");
+	    search_type_combobox = new GComboBox(SEARCH_TYPES);
+	    search_type_combobox.setPreferredSize(LABEL_SIZE);
+	    search_type_combobox.setBackgroundNonSelectionColor(Configuration.getColor("coloring.editable_background", false));
+	    search_type_combobox.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
+	    search_type_combobox.setEditable(true);
+	    search_type_combobox.setSelectedIndex(0); 
+	    search_type_combobox.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
+	    search_type_combobox.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.registerTooltip(search_type_combobox, "CDM.SearchTypeManager.SearchType_Selection_Tooltip");
+
+	    JPanel button_panel = new JPanel();
+	    add_button = new GLIButton();
+	    add_button.setEnabled(false);
+	    add_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add_button, "CDM.SearchTypeManager.Add", "CDM.SearchTypeManager.Add_Tooltip");
+
+	    remove_button = new GLIButton();
+	    remove_button.setEnabled(false);
+	    remove_button.setMnemonic(KeyEvent.VK_R);
+	    Dictionary.registerBoth(remove_button, "CDM.SearchTypeManager.Remove", "CDM.SearchTypeManager.Remove_Tooltip");
+	    
+	  
+	    // Connection
+	    add_button.addActionListener(new AddActionListener());
+	    add_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    build_type_combobox.addActionListener(new BuildTypeActionListener());
+	    build_type_combobox.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    current_search_types_list.addListSelectionListener(new CurrentSearchTypesListSelectionListener());
+	    enable_advanced_searches_checkbox.addActionListener(new EnableAdvancedSearchesActionListener());
+	    enable_advanced_searches_checkbox.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    move_up_button.addActionListener(new MoveListener(true));
+	    move_up_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    move_down_button.addActionListener(new MoveListener(false));
+	    move_down_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    remove_button.addActionListener(new RemoveActionListener());
+	    remove_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    SearchTypesActionDocumentListener stadl = new SearchTypesActionDocumentListener();
+	    search_type_combobox.addActionListener(stadl);
+	    search_type_combobox.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    ((JTextField)search_type_combobox.getEditor().getEditorComponent()).getDocument().addDocumentListener(stadl);
+
+	    // Layout
+	    instructions_panel.setBorder(BorderFactory.createEmptyBorder(0,0,2,0));
+	    instructions_panel.setLayout(new BorderLayout());
+	    instructions_panel.add(title_label, BorderLayout.NORTH);
+	    instructions_panel.add(new JScrollPane(instructions_textarea), BorderLayout.CENTER);
+
+	    movement_panel.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
+	    movement_panel.setLayout(new GridLayout(2,1,5,0));
+	    movement_panel.add(move_up_button);
+	    movement_panel.add(move_down_button);
+
+	    current_search_types_panel.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
+	    current_search_types_panel.setLayout(new BorderLayout());
+	    current_search_types_panel.add(current_search_types_label, BorderLayout.NORTH);
+	    current_search_types_panel.add(new JScrollPane(current_search_types_list), BorderLayout.CENTER);
+	    current_search_types_panel.add(movement_panel, BorderLayout.EAST);
+
+	    build_type_panel.setLayout(new BorderLayout());
+	    build_type_panel.add(build_type_label, BorderLayout.WEST);
+	    build_type_panel.add(build_type_combobox, BorderLayout.CENTER);
+
+	    indexer_type_panel.setLayout(new GridLayout(1,2,0,5));
+	    indexer_type_panel.add(enable_advanced_searches_checkbox);
+	    indexer_type_panel.add(build_type_panel);
+	    
+	    button_panel.setBorder(BorderFactory.createEmptyBorder(2,0,0,0));
+	    button_panel.setLayout(new GridLayout(1,2,0,5));
+	    button_panel.add(add_button);
+	    button_panel.add(remove_button);
+
+	    search_type_panel.setLayout(new BorderLayout(5,3));
+	    search_type_panel.add(search_type_label, BorderLayout.WEST);
+	    search_type_panel.add(search_type_combobox, BorderLayout.CENTER);
+	    search_type_panel.add(button_panel, BorderLayout.SOUTH);
+
+	    inner_panel.setLayout(new BorderLayout());
+	    inner_panel.add(indexer_type_panel, BorderLayout.NORTH);
+	    inner_panel.add(current_search_types_panel, BorderLayout.CENTER);
+	    inner_panel.add(search_type_panel, BorderLayout.SOUTH);
+
+	    spacer_panel.setLayout(new BorderLayout());
+	    spacer_panel.add(inner_panel, BorderLayout.NORTH);
+	    spacer_panel.add(empty_panel, BorderLayout.CENTER);
+
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    add(instructions_panel, BorderLayout.NORTH);
+	    add(spacer_panel, BorderLayout.CENTER);
+	}
+
+	public void destroy() {
+	}
+
+	public void gainFocus() {
+	    instructions_textarea.setCaretPosition(0);
+	    validateControls(isMGPPEnabled());
+	}
+
+	public void loseFocus() {
+
+	}
+
+	private void validateControls(boolean advanced_search_enabled) {
+	    // Enable or disable controls based on whether MGPP is enabled
+	    // validate add button, which depends on the current combobox selection and the contents of the assigned search types list
+	    Object selected_item = search_type_combobox.getSelectedItem();
+	    add_button.setEnabled(advanced_search_enabled && selected_item != null && !model.contains(selected_item));
+	    // validate other controls.
+	    current_search_types_list.setEnabled(advanced_search_enabled);
+	    build_type_combobox.setEnabled(advanced_search_enabled);
+	    enable_advanced_searches_checkbox.setSelected(advanced_search_enabled);
+	    search_type_combobox.setEnabled(advanced_search_enabled);
+	    remove_button.setEnabled(current_search_types_list.getModel().getSize() > 1 && !current_search_types_list.isSelectionEmpty() && advanced_search_enabled);
+	}
+
+	/** Listenes for actions on the Add button, and if detected adds a new search type. */
+	private class AddActionListener
+	    implements ActionListener {
+	    /** Called when someone actions the Add button.
+	     * @param  event an ActionEvent containing information about the add button click
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		Object selected_item = search_type_combobox.getSelectedItem();
+		if(selected_item != null) {
+		    if(search_type_combobox.getSelectedIndex() == -1) {
+			search_type_combobox.insertItemAt(selected_item, search_type_combobox.getItemCount());
+		    }
+		    // Add the search type
+		    SearchType new_searchtype = new SearchType((String)selected_item);
+		    addSearchType(new_searchtype);
+		}
+		add_button.setEnabled(false);
+	    }
+	}
+
+	/** Listens for selections within the search types list and updates the remove button appropriately. */
+	private class CurrentSearchTypesListSelectionListener
+	    implements ListSelectionListener {
+	    /** Called when the selection in the list changes.
+	     * @param  event a ListSelectionEvent containing information about the selection change
+	     */
+	    public void valueChanged(ListSelectionEvent event) {
+		if(!event.getValueIsAdjusting()) {
+		    SearchType search_type = null;
+		    if ((search_type = (SearchType) current_search_types_list.getSelectedValue()) != null) {
+			int index = model.indexOf(search_type);
+			// Move up is only enabled if the current selection isn't at index 0
+			move_up_button.setEnabled(index != 0);
+			// Move down is only enabled if the current selection isn't at index getSize() - 1
+			move_down_button.setEnabled(index != model.getSize() - 1);
+			// Remove is only enabled if this isn't the last search type
+			remove_button.setEnabled(current_search_types_list.getModel().getSize() > 1);
+		    }
+		    else {
+			move_up_button.setEnabled(false);
+			move_down_button.setEnabled(false);
+			remove_button.setEnabled(false);
+		    }
+		}
+	    }
+	}
+
+	/** The most complex listener in this class, this listens for changes to the enable advanced searches checkbox, and when they occur it not only updates the controls on this page, but asks the IndexManager to action the appropriate changes to the underlying DOM so as to support either MG or MGPP styles of indexes. */
+	private class EnableAdvancedSearchesActionListener
+	    implements ActionListener {
+	    /** Called whenever the checkbox is checked or unchecked.
+	     * @param  event an ActionEvent containing information about the checking action
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		Gatherer.g_man.wait(true);
+		boolean advanced_search_enabled = enable_advanced_searches_checkbox.isSelected();
+		model.root.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (advanced_search_enabled ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+		CollectionDesignManager.index_manager.setMGPPEnabled(advanced_search_enabled);
+		validateControls(advanced_search_enabled);
+		build_type.setAssigned(advanced_search_enabled);
+		Gatherer.g_man.wait(false);
+	    }
+	}
+
+	private class BuildTypeActionListener
+	    implements	ActionListener {
+
+	    public void actionPerformed(ActionEvent event) {
+		build_type.setValue((String)build_type_combobox.getSelectedItem());
+	    }
+
+	}
+	/** Listenes for actions on the Remove button, and if detected removes the currently selected search types. */
+	private class RemoveActionListener
+	    implements ActionListener {
+	    /** Called when someone actions the Remove button.
+	     * @param  event an ActionEvent containing information about the remove button click
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		if(!current_search_types_list.isSelectionEmpty()) {
+		    Object[] selected_items = current_search_types_list.getSelectedValues();
+		    for(int i = 0; model.getSize() > 1 && i < selected_items.length; i++) {
+			removeSearchType((SearchType)selected_items[i]);
+		    }
+		}
+		Object selected_object = search_type_combobox.getSelectedItem();
+		if(selected_object != null) {
+		    add_button.setEnabled(!model.contains(selected_object));
+		}
+		else {
+		    add_button.setEnabled(false);
+		}
+		remove_button.setEnabled(false);
+	    }
+	}
+
+	private class MoveListener
+	    implements ActionListener {
+	    private boolean move_up;
+	    public MoveListener(boolean move_up) {
+		this.move_up = move_up;
+	    }
+	    public void actionPerformed(ActionEvent event) {
+		// Retrieve the first selected search type (if any)
+		SearchType search_type = null;
+		if((search_type = (SearchType) current_search_types_list.getSelectedValue()) != null) {
+		    // Move search type
+		    moveSearchType(search_type, move_up);
+		    // Reselect the moved search type
+		    current_search_types_list.setSelectedValue(search_type, true);
+		}
+		// No selection - no movement
+		else {
+		    move_up_button.setEnabled(false);
+		    move_down_button.setEnabled(false);
+		}
+	    }
+	}
+
+	/** Listens for changes in the search types combobox, and enabled add button appropriately. */
+	private class SearchTypesActionDocumentListener
+	    implements ActionListener, DocumentListener {
+	    /** Called whenever a selection action occurs on the combobox.
+	     * @param  event an ActionEvent containing information about the selection event
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		validateAddButton();
+	    }
+
+	    /** Gives notification that an attribute or set of attributes changed.
+	     * @param  event a DocumentEvent containing information about the text changed
+	     */
+	    public void changedUpdate(DocumentEvent event) {
+		validateAddButton();
+	    }
+	    /** Gives notification that there was an insert into the document.
+	     * @param  event a DocumentEvent containing information about the text added
+	     */
+	    public void insertUpdate(DocumentEvent event) {
+		validateAddButton();
+	    }
+
+	    /** Gives notification that a portion of the document has been removed.
+	     * @param  event a DocumentEvent containing information about the text removed
+	     */
+	    public void removeUpdate(DocumentEvent event) {
+		validateAddButton();
+	    }
+
+	    /** Change the enable state of the add button depending on the current value in the search type combobox. */
+	    private void validateAddButton() {
+		Object selected_object = search_type_combobox.getSelectedItem();
+		if(selected_object != null) {
+		    add_button.setEnabled(!model.contains(selected_object));
+		}
+		else {
+		    add_button.setEnabled(false);
+		}
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Subcollection.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Subcollection.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/Subcollection.java	(revision 10506)
@@ -0,0 +1,256 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+
+/** This class encapsulates one subcollection entry in the collection configuration file.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.4
+ */
+public class Subcollection
+    implements Comparable, DOMProxyListEntry {
+    /** A <i>boolean</i> which is <i>true</i> if the condition is an include one, <i>false</i> otherwise. */
+    private boolean include = true;
+    /** The DOM Element this Subcollection is based upon. */
+    private Element element = null;
+    /** A String containing a Perl expression which is used as the pattern by which to filter this subcollection. */
+    private String pattern = null;
+    /** A series of flags to be used when matching the expression. */
+    private String flags = null;
+    /** A String which is a unique identifier of a subcollection. */
+    private String name = null;
+    /** Either the fully qualified name of the metadata whose value should be matched against the given expression, or <i>null</i> if you wish to match against the file name. */
+    private String source = null;
+    private String text = null;
+
+    /** Default constructor which should only be used during DOMProxyListModel initialization. */
+    public Subcollection() {
+    }
+
+    /** Constructor for representing an existing assigned Subcollection.
+     * @param element the Element this subcollection is based upon
+     */
+    public Subcollection(Element element) {
+	this.element = element;
+    }
+
+    /** Constructor for assigning a brand new Subcollection.
+     * @param name a unique identifier for this collection as a String
+     * @param include true if this the pattern should be an inclusion filter, false for exclusion
+     * @param source either the fully qualified name of an element as a String, or null to filter filenames
+     * @param pattern the matching pattern as a String
+     * @param flags any flags to use while matching, as a String
+     */
+    public Subcollection(String name, boolean include, String source, String pattern, String flags) {
+	// Cache the details
+	this.flags = flags;
+	this.include = include;
+	this.name = name;
+	this.pattern = pattern;
+	if(source != null) {
+	    this.source = source;
+	}
+	else {
+	    this.source = StaticStrings.FILENAME_STR;
+	}
+	// Create a new DOM Element with the appropriate attributes and text value
+	element = CollectionDesignManager.collect_config.document.createElement(StaticStrings.SUBCOLLECTION_ELEMENT);
+	element.setAttribute(StaticStrings.CONTENT_ATTRIBUTE, source);
+	element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name);
+	element.setAttribute(StaticStrings.OPTIONS_ATTRIBUTE, flags);
+	element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, (include ? StaticStrings.INCLUDE_STR : StaticStrings.EXCLUDE_STR));
+	XMLTools.setValue(element, pattern);
+    }
+
+    /** Method to compare two subcollections.
+     * @param object he other subcollection to compare to, as an Object
+     * @return an int which is &gt;0, 0, or &lt;0 if this subcollection is before, equal to, or after the target object respectively.
+     */
+    public int compareTo(Object object)
+    {
+	if (object == null) {
+	    return -1;
+	}
+
+	// Object may be a String
+	if (object instanceof String) {
+	    return getName().compareTo((String) object);
+	}
+
+	// Otherwise assume it is a Subcollection object
+	return getName().compareTo(((Subcollection) object).getName());
+    }
+
+
+    public DOMProxyListEntry create(Element element) {
+	return new Subcollection(element);
+    }
+
+    /** Method to check two subcollections for equality.
+     * @param object the other subcollection to compare to, as an Object
+     * @return true if the subcollections are equal, false otherwise.
+     */
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+
+    /** Retrieve the DOM Element this Subcollection is based upon.
+     * @return an Element
+     */
+    public Element getElement() {
+	return element;
+    }
+
+    /** Method to get the value of flags.
+     * @return the value of flags as a String
+     */
+    public String getFlags() {
+	if(flags == null && element != null) {
+	    flags = element.getAttribute(StaticStrings.OPTIONS_ATTRIBUTE);
+	}
+	return flags;
+    }
+
+    /** Method to get the value of name.
+     * @return String The value of name as a <strong>String</string>.
+     */
+    public String getName() {
+	if(name == null && element != null) {
+	    name = element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+	}
+	return name;
+    }
+
+    public String getPattern() {
+	if(pattern == null && element != null) {
+	    pattern = XMLTools.getValue(element);
+	}
+	return pattern;
+    }
+
+    /** Method to get the name of the source of the strings used in pattern matching.
+     * @return a String which is either the fully qualified name of a metadata element, or filename
+     */
+    public String getSource()
+    {
+	if (source == null && element != null) {
+	    source = element.getAttribute(StaticStrings.CONTENT_ATTRIBUTE);
+	}
+
+	return source;
+    }
+
+    public boolean isAssigned() {
+	return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
+    }
+
+    /** Method to get the value of include.
+     * @return boolean true if this is an inclusion filter, false otherwise
+     */
+    public boolean isInclusive() {
+	if (element != null) {
+	    include = element.getAttribute(StaticStrings.TYPE_ATTRIBUTE).equals(StaticStrings.INCLUDE_STR);
+	}
+
+	return include;
+    }
+
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    public void setElement(Element element) {
+	this.element = element;
+	include = true;
+	flags = null;
+	name = null;
+	pattern = null;
+	source = null;
+	text = null;
+    }
+
+    public void setFlags(String new_flags) {
+	if(element != null) {
+	    // Change element
+	    element.setAttribute(StaticStrings.OPTIONS_ATTRIBUTE, new_flags);
+	    flags = new_flags;
+	    text = null;
+	}
+    }
+
+    public void setInclusive(boolean new_include) {
+	if(element != null) {
+	    // Change element
+	    include = new_include;
+	    element.setAttribute(StaticStrings.TYPE_ATTRIBUTE, (include ? StaticStrings.INCLUDE_STR : StaticStrings.EXCLUDE_STR));
+	    text = null;
+	}
+    }
+
+    public void setName(String new_name) {
+	if(element != null) {
+	    // Change element
+	    element.setAttribute(StaticStrings.NAME_ATTRIBUTE, new_name);
+	    name = new_name;
+	    text = null;
+	}
+    }
+
+    public void setPattern(String new_pattern) {
+	if(element != null) {
+	    // Change element
+	    XMLTools.setValue(element, new_pattern);
+	    pattern = new_pattern;
+	    text = null;
+	}
+    }
+
+    public void setSource(String new_source) {
+	if(element != null) {
+	    // Change element
+	    element.setAttribute(StaticStrings.CONTENT_ATTRIBUTE, new_source);
+	    source = new_source;
+	    text = null;
+	}
+    }
+
+    /** Method to display the contents of this class as it would appear in the collection configuration file.
+     * @return a String representing this subcollection
+     */
+    public String toString() {
+	if(text == null && element != null) {
+	    text = CollectionConfiguration.toString(element, true);
+	}
+	return text;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SubcollectionIndex.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SubcollectionIndex.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SubcollectionIndex.java	(revision 10506)
@@ -0,0 +1,185 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.util.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/** This class encapsulates a single indexing pair.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.4
+ */
+public class SubcollectionIndex
+    implements Comparable, DOMProxyListEntry {
+
+    private ArrayList sources = null;
+    /** The element this index is based upon. */
+    private Element element = null;
+    /** The unique, if cryptic, identifier of an index. */
+    private String id = null;
+
+    /** Default constructor, which should only be used during DOMProxyListModel creation. */
+    public SubcollectionIndex() {
+    }
+
+    /** Constructor. */
+    public SubcollectionIndex(Element element) {
+	this.element = element;
+    }
+
+    public SubcollectionIndex(Object[] raw_sources) {
+	this.sources = new ArrayList();
+	// Create a new element
+	Document document = CollectionDesignManager.collect_config.document;
+	element = document.createElement(CollectionConfiguration.INDEX_ELEMENT);
+	// For each source add a content element
+	int size = raw_sources.length;
+	for(int i = 0; i < size; i++) {
+	    Subcollection subcollection = (Subcollection) raw_sources[i];
+	    String subcollection_name = subcollection.getName();
+	    sources.add(subcollection_name);
+	    Element content_element = document.createElement(CollectionConfiguration.CONTENT_ELEMENT);
+	    content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, subcollection_name);
+	    element.appendChild(content_element);
+	    content_element = null;
+	}
+	document = null;
+    }
+
+    /** Method to compare two indexes.
+     * @param object The other index as an <strong>Object</strong>.
+     * @return An <i>int</i> which indicates how the indexes compare.
+     * @see java.lang.String
+     */
+    public int compareTo(Object object) {
+	return getID().compareTo(((SubcollectionIndex)object).getID());
+    }
+    
+    public DOMProxyListEntry create(Element element) {
+	return new SubcollectionIndex(element);
+    }
+
+    /** Method to test for the equality of two indexes.
+     * @param object The other index as an <strong>Object</strong>.
+     * @return A <i>boolean</i> which is <i>true</i> if the two indexes are equal, <i>false</i> otherwise.
+     */
+    public boolean equals(Object object) {
+	return (compareTo(object) == 0);
+    }
+    
+    public Element getElement() {
+	return element;
+    }
+
+    public String getID() {
+	if(id == null) {
+	    StringBuffer id_buffer = new StringBuffer();
+	    // Write data information. Retrieve each of the content sources and add them in a comma separated list.
+	    ArrayList sources = getSources();
+	    int sources_size = sources.size();
+	    for(int i = 0; i < sources_size; i++) {
+		id_buffer.append((String)sources.get(i));
+		id_buffer.append(StaticStrings.COMMA_CHARACTER);
+	    }
+	    sources = null;
+	    id = id_buffer.substring(0, id_buffer.length() - 1);
+	}
+	return id;
+    }
+
+    /** Retrieve the sources of this index.
+     * @return the sources as an ArrayList
+     */
+    public ArrayList getSources() {
+	if(sources == null) {
+	    sources = new ArrayList();
+	    NodeList content_elements = element.getElementsByTagName(CollectionConfiguration.CONTENT_ELEMENT);
+	    int content_elements_length = content_elements.getLength();
+	    for(int i = 0; i < content_elements_length; i++) {
+		Element content_element = (Element) content_elements.item(i);
+		sources.add(content_element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE));
+	    }
+	    content_elements = null;
+	    Collections.sort(sources);
+	}
+	return sources;
+    }
+
+    public boolean isAssigned() {
+	return (element != null && !element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.FALSE_STR));
+    }
+
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    public void setElement(Element element) {
+	this.element = element;
+	this.id = null;
+	this.sources = null;
+    }
+
+    /** Method to set the sources for this index which can only be used for the default index.
+     * @param sources an ArrayList of source names
+     */
+    public void setSources(ArrayList sources) {
+	if(element != null) {
+	    // Erase old sources
+	    XMLTools.clear(element);
+	    // For each entry in the sources array add a new content element.
+	    int size = sources.size();
+	    for(int i = 0; i < size; i++) {
+		Element content_element = element.getOwnerDocument().createElement(CollectionConfiguration.CONTENT_ELEMENT);
+		content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, (String) sources.get(i));
+		element.appendChild(content_element);
+		content_element = null;
+	    }
+	    this.id = null; // Regenerate ID.
+	    this.sources = sources;
+	}
+    }
+
+    /** Method to turn this object into a string representation ready to be placed in the collection configuration file.
+     * @return A <strong>String</strong> containing the information of this class.
+     */
+    public String toString() {
+	String id = getID();
+	StringBuffer text = new StringBuffer(id);
+	CollectionMeta metadatum = CollectionDesignManager.collectionmeta_manager.getMetadatum(StaticStrings.STOP_CHARACTER + id, false);
+	if(metadatum != null) {
+	    text.append(" \"");
+	    text.append(metadatum.getValue(CollectionMeta.TEXT));
+	    text.append("\"");
+	}
+	return text.toString();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SubcollectionIndexManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SubcollectionIndexManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SubcollectionIndexManager.java	(revision 10506)
@@ -0,0 +1,664 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.util.CheckList;
+import org.greenstone.gatherer.util.JarTools;
+import org.w3c.dom.*;
+
+
+/** This class maintains a list of indexes partitions for the purpose of defining subcollections.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.4
+ */
+public class SubcollectionIndexManager
+    extends DOMProxyListModel
+{
+    static final private Dimension FIELD_SIZE = new Dimension(200, 30);
+
+    private Control controls;
+    private DOMProxyListModel model;
+    private SubcollectionIndex default_index;
+
+
+    /** Constructor. */
+    public SubcollectionIndexManager(Element subindexes)
+    {
+	super(subindexes, CollectionConfiguration.INDEX_ELEMENT, new SubcollectionIndex());
+	DebugStream.println("SubcollectionIndexManager: " + getSize() + " subcollection indexes parsed.");
+	model = this;
+
+	// Parse and retrieve the default index
+	NodeList default_index_elements = CollectionDesignManager.collect_config.getDocumentElement().getElementsByTagName(CollectionConfiguration.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT);
+	if (default_index_elements.getLength() > 0) {
+	    default_index = new SubcollectionIndex((Element) default_index_elements.item(0));
+	}
+    }
+
+
+    /** Method to add a subindex.
+     * @param subindex a SubcollectionIndex
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     */
+    private void addSubcollectionIndex(SubcollectionIndex subcollection_index)
+    {
+	if (!contains(subcollection_index)) {
+	    add(getSize(), subcollection_index);
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+
+
+    public void destroy()
+    {
+	if (controls != null) {
+	    controls.destroy();
+	    controls = null;
+	}
+	default_index = null;
+	model = null;
+    }
+
+
+    public Control getControls()
+    {
+	if (controls == null) {
+	    controls = new SubcollectionIndexControls();
+	}
+	return controls;
+    }
+
+
+    /** Method to get all of the subindexes set.
+     * @return an ArrayList containing all the defined indexes
+     */
+    public ArrayList getSubcollectionIndexes()
+    {
+	return children();
+    }
+
+
+    private int moveSubcollectionIndex(SubcollectionIndex subcollection_index, boolean move_up)
+    {
+	// Determine the current position of the subcollection index
+	int position = indexOf(subcollection_index);
+	int new_position;
+
+	// Attempt to move the subcollection index up
+	if (move_up) {
+	    // Check it's not already at the top
+	    if (position == 0) {
+		return position;
+	    }
+
+	    // This automatically removes the index first, as an Element can only exist once in a particular document
+	    new_position = position - 1;
+	    addBefore(subcollection_index, (SubcollectionIndex) getElementAt(new_position));
+	}
+
+	// Attempt to move the subcollection index down
+	else {
+	    // Check it's not already at the bottom
+	    if (position == (getSize()) - 1) {
+		return position;
+	    }
+
+	    // This automatically removes the index first, as an Element can only exist once in a particular document
+	    new_position = position + 1;
+	    addAfter(subcollection_index, (SubcollectionIndex) getElementAt(new_position));
+	}
+
+	// Schedule the collection for saving
+	Gatherer.c_man.configurationChanged();
+	return new_position;
+    }
+
+
+    /** Method to remove a certain subcollection index. */
+    private void removeSubcollectionIndex(SubcollectionIndex subcollection_index)
+    {
+	if (subcollection_index != null) {
+	    // Remove any current metadata from this index
+	    CollectionDesignManager.collectionmeta_manager.removeMetadata("." + subcollection_index.getID());
+
+	    // Check if the index removed happens to be the default index
+	    if (default_index != null && default_index.equals(subcollection_index)) {
+		// If so our first solution is to set the first subcollection index to be the default
+		if (getSize() > 0) {
+		    setDefaultSubcollectionIndex((SubcollectionIndex) getElementAt(0));
+		}
+		else {
+		    default_index.setAssigned(false);
+		}
+	    }
+
+	    // Remove the index
+	    remove(subcollection_index);
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+
+
+    /** Method to remove all of the subindexes that contain a certain subcollection.
+     * @param subcollection the Subcollection that has been removed
+     * @see org.greenstone.gatherer.cdm.Subcollection
+     * @see org.greenstone.gatherer.cdm.SubcollectionIndex
+     */
+    public void removeSubcollectionIndexes(Subcollection subcollection)
+    {
+	String subcollection_name = subcollection.getName();
+	int size = getSize();
+	for(int i = size - 1; i >= 0; i--) {
+	    SubcollectionIndex subcollection_index = (SubcollectionIndex) getElementAt(i);
+	    if (subcollection_index.getSources().contains(subcollection_name)) {
+		removeSubcollectionIndex(subcollection_index);
+	    }
+	}
+    }
+
+
+    /** Method to set the default subcollection index.
+     * @param index The <strong>SubcollectionIndex</strong> to use as the default index.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     * @see org.greenstone.gatherer.cdm.SubcollectionIndex
+     */
+    private void setDefaultSubcollectionIndex(SubcollectionIndex subcollection_index)
+    {
+ 	if (subcollection_index != null) {
+ 	    if (default_index == null) {
+		// Create the default index element, and place immediately after indexes element.
+		Element default_index_element = root.getOwnerDocument().createElement(CollectionConfiguration.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT);
+		default_index = new SubcollectionIndex(default_index_element);
+		Node target_node = CollectionConfiguration.findInsertionPoint(default_index_element);
+		if (target_node != null) {
+		    root.getOwnerDocument().getDocumentElement().insertBefore(default_index_element, target_node);
+		}
+		else {
+		    root.getOwnerDocument().getDocumentElement().appendChild(default_index_element);
+		}
+ 	    }
+ 	    default_index.setAssigned(true);
+ 	    default_index.setSources(subcollection_index.getSources());
+ 	}
+ 	else {
+ 	    if (default_index != null) {
+ 		default_index.setAssigned(false);
+ 	    }
+ 	}
+ 	Gatherer.c_man.configurationChanged();
+    }
+
+
+    /** This class creates a set of controls for editing the indexes. */
+    private class SubcollectionIndexControls
+	extends JPanel
+	implements Control
+    {
+	private CheckList source_list;
+	private JButton add_button;
+	private JButton move_down_button;
+	private JButton move_up_button;
+	private JButton remove_button;
+	private JButton replace_button;
+	private JButton set_default_button;
+	private JList subcollection_index_list;
+	private JTextField subcollection_index_name_textfield;
+
+
+	/** Constructor.
+	 */
+	public SubcollectionIndexControls()
+	{
+	    super();
+
+	    ArrayList sources = new ArrayList();
+	    ListModel source_model = CollectionDesignManager.subcollection_manager;
+	    for (int i = 0; i < source_model.getSize(); i++) {
+		sources.add(source_model.getElementAt(i));
+	    }
+
+	    // Creation
+	    JPanel assigned_indexes_pane = new JPanel();
+	    JLabel index_label = new JLabel();
+	    Dictionary.registerText(index_label, "CDM.SubcollectionIndexManager.Subindexes");
+ 	    subcollection_index_list = new JList(model);
+	    subcollection_index_list.setCellRenderer(new SubcollectionIndexListCellRenderer());
+ 	    subcollection_index_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	    subcollection_index_list.setVisibleRowCount(2);
+
+	    JPanel movement_pane = new JPanel();
+	    move_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
+	    move_up_button.setEnabled(false);
+	    move_up_button.setMnemonic(KeyEvent.VK_U);
+	    Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
+
+	    move_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
+	    move_down_button.setEnabled(false);
+	    move_down_button.setMnemonic(KeyEvent.VK_D);
+	    Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
+
+	    set_default_button = new GLIButton();
+	    set_default_button.setEnabled(false);
+	    set_default_button.setMnemonic(KeyEvent.VK_S);
+	    Dictionary.registerBoth(set_default_button, "CDM.SubcollectionIndexManager.Set_Default_Subindex", "CDM.SubcollectionIndexManager.Set_Default_Subindex_Tooltip");
+
+	    JPanel index_pane = new JPanel();
+	    JPanel details_pane = new JPanel();
+	    JPanel labels_pane = new JPanel();
+	    JPanel boxes_pane = new JPanel();
+	    JPanel content_pane = new JPanel();
+
+	    JLabel name_label = new JLabel();
+	    Dictionary.registerText(name_label, "CDM.SubcollectionIndexManager.PartitionName");
+	    subcollection_index_name_textfield = new JTextField();
+	    subcollection_index_name_textfield.setPreferredSize(FIELD_SIZE);
+	    Dictionary.registerTooltip(subcollection_index_name_textfield, "CDM.SubcollectionIndexManager.PartitionName_Tooltip");
+
+	    JLabel source_label = new JLabel();
+	    Dictionary.registerText(source_label, "CDM.SubcollectionIndexManager.Source");
+	    source_list = new CheckList(false);
+	    source_list.setListData(sources);
+	    Dictionary.registerTooltip(source_list, "CDM.SubcollectionIndexManager.Source_Tooltip");
+
+	    JPanel button_pane = new JPanel();
+	    add_button = new GLIButton();
+	    add_button.setEnabled(false);
+	    add_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add_button, "CDM.SubcollectionIndexManager.Add_Subindex", "CDM.SubcollectionIndexManager.Add_Subindex_Tooltip");
+
+	    remove_button = new GLIButton();
+	    remove_button.setEnabled(false);
+	    remove_button.setMnemonic(KeyEvent.VK_R);
+	    Dictionary.registerBoth(remove_button, "CDM.SubcollectionIndexManager.Remove_Subindex", "CDM.SubcollectionIndexManager.Remove_Subindex_Tooltip");
+
+	    replace_button = new GLIButton();
+	    replace_button.setEnabled(false);
+	    replace_button.setMnemonic(KeyEvent.VK_P);
+	    Dictionary.registerBoth(replace_button, "CDM.SubcollectionIndexManager.Replace_Subindex", "CDM.SubcollectionIndexManager.Replace_Subindex_Tooltip");
+
+	    // Listeners
+	    add_button.addActionListener(new AddListener());
+	    add_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    move_down_button.addActionListener(new MoveListener(false));
+	    move_down_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    move_up_button.addActionListener(new MoveListener(true));
+	    move_up_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    remove_button.addActionListener(new RemoveListener());
+	    remove_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    replace_button.addActionListener(new ReplaceListener());
+	    replace_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    set_default_button.addActionListener(new SetDefaultListener());
+	    set_default_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    subcollection_index_name_textfield.getDocument().addDocumentListener(new NameListener());
+	    subcollection_index_list.addListSelectionListener(new SubcollectionIndexListListener());
+	    source_list.addListSelectionListener(new SourceListListener());
+
+	    // Layout
+	    movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
+	    movement_pane.setLayout(new GridLayout(3,1));
+	    movement_pane.add(move_up_button);
+	    movement_pane.add(move_down_button);
+	    movement_pane.add(set_default_button);
+
+	    assigned_indexes_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    assigned_indexes_pane.setLayout(new BorderLayout());
+	    assigned_indexes_pane.add(index_label, BorderLayout.NORTH);
+	    assigned_indexes_pane.add(new JScrollPane(subcollection_index_list), BorderLayout.CENTER);
+	    assigned_indexes_pane.add(movement_pane, BorderLayout.EAST);
+
+	    labels_pane.setLayout(new BorderLayout());
+	    labels_pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 10, 5));
+	    labels_pane.add(name_label, BorderLayout.NORTH);
+	    labels_pane.add(source_label, BorderLayout.CENTER);
+	    
+	    boxes_pane.setLayout(new BorderLayout());
+	    boxes_pane.add(subcollection_index_name_textfield, BorderLayout.NORTH);
+	    boxes_pane.add(new JScrollPane(source_list), BorderLayout.CENTER);
+	    
+	    details_pane.setLayout(new BorderLayout());
+	    details_pane.add(labels_pane, BorderLayout.WEST);
+	    details_pane.add(boxes_pane, BorderLayout.CENTER);
+
+	    button_pane.setLayout(new GridLayout(1,3));
+	    button_pane.add(add_button);
+	    button_pane.add(replace_button);
+	    button_pane.add(remove_button);
+
+	    index_pane.setLayout(new BorderLayout());
+	    index_pane.add(details_pane, BorderLayout.CENTER);
+	    index_pane.add(button_pane, BorderLayout.SOUTH);
+
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(assigned_indexes_pane, BorderLayout.NORTH);
+	    content_pane.add(index_pane, BorderLayout.CENTER);
+
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    add(content_pane, BorderLayout.CENTER);
+	}
+
+
+	public void destroy()
+	{
+	}
+
+
+	public void gainFocus()
+	{
+ 	    // Reload the source list
+ 	    ArrayList sources = new ArrayList();
+ 	    ListModel source_model = CollectionDesignManager.subcollection_manager;
+ 	    for (int i = 0; i < source_model.getSize(); i++) {
+ 		sources.add(source_model.getElementAt(i));
+ 	    }
+ 	    source_list.setListData(sources);
+
+ 	    // Refresh the subcollection index list
+ 	    subcollection_index_list.updateUI();
+
+ 	    // If there is one selected, fill in the controls
+ 	    updateControlsWithSelectedIndex();
+	}
+
+
+	public void loseFocus()
+	{
+	}
+
+
+	private void updateControlsWithSelectedIndex()
+	{
+	    SubcollectionIndex selected_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
+	    if (selected_index == null) {
+		return;
+	    }
+
+	    // Display the selected subcollection index's name
+	    String id = selected_index.getID();
+	    String name = CollectionDesignManager.collectionmeta_manager.getMetadatum("." + id).getValue(true);
+	    subcollection_index_name_textfield.setText(name);
+
+	    // Display the selected subcollection index's sources
+	    source_list.clearTicked();
+	    source_list.setTickedObjects(selected_index.getSources().toArray());
+	}
+
+
+	private void validateControls()
+	{
+	    boolean add_enabled = false;
+	    boolean replace_enabled = false;
+
+	    // Indexes must have a name
+	    if (subcollection_index_name_textfield.getText().length() == 0) {
+		add_enabled = false;
+	    }
+	    // Can't add a new index if no sources are selected
+	    else if (source_list.isNothingTicked()) {
+		add_enabled = false;
+	    }
+	    // If we get this far, create a dummy index and see if it's already assigned in the collection
+	    else {
+ 		ArrayList sources = source_list.getTicked();
+ 		SubcollectionIndex subcollection_index = new SubcollectionIndex(sources.toArray());
+
+		// Subcollection index already exists: can't add, but can replace if the name has changed
+ 		if (model.contains(subcollection_index)) {
+ 		    add_enabled = false;
+
+ 		    // Here we need to check if we have changed the name - if so, we can enable the replace button
+		    if (subcollection_index_list.getSelectedIndex() != -1) {
+			String name = subcollection_index_name_textfield.getText();
+ 			SubcollectionIndex selected_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
+ 			String selected_name = CollectionDesignManager.collectionmeta_manager.getMetadatum("." + selected_index.getID()).getValue(true);
+ 			if (!name.equals(selected_name)) {
+ 			    replace_enabled = true;
+ 			}
+ 		    }
+		}
+
+		// Subcollection index doesn't already exist: can add, or replace if there is something selected
+		else {
+ 		    add_enabled = true;
+ 		    if (subcollection_index_list.getSelectedIndex() != -1) {
+ 			replace_enabled = true;
+ 		    }
+ 		}
+	    }
+
+	    // We should now know the add_button state
+	    add_button.setEnabled(add_enabled);
+	    replace_button.setEnabled(replace_enabled);
+	}
+
+
+	private class AddListener
+	    implements ActionListener
+	{
+	    public void actionPerformed(ActionEvent event)
+	    {
+		String name = subcollection_index_name_textfield.getText();
+		if (!source_list.isNothingTicked() && name.length() != 0) {
+		    ArrayList sources = source_list.getTicked();
+		    SubcollectionIndex subcollection_index = new SubcollectionIndex(sources.toArray());
+
+		    // Before we add the index to the model, we have to add the collection metadata for this
+		    CollectionMeta metadatum = new CollectionMeta("." + subcollection_index.getID());
+		    metadatum.setValue(name);
+ 		    CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
+
+		    // Finally, add the subcollection index
+		    addSubcollectionIndex(subcollection_index);
+		    subcollection_index_list.setSelectedIndex(model.getSize() - 1);
+		}
+	    }
+	}
+
+
+	private class MoveListener
+	    implements ActionListener
+	{
+	    private boolean move_up;
+
+	    public MoveListener(boolean move_up)
+	    {
+		this.move_up = move_up;
+	    }
+
+	    public void actionPerformed(ActionEvent event)
+	    {
+		// Retrieve the selected subcollection index
+		SubcollectionIndex subcollection_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
+		if (subcollection_index != null) {
+		    int new_position = moveSubcollectionIndex(subcollection_index, move_up);
+		    // Ensure the subcollection index that moved is still selected
+		    subcollection_index_list.setSelectedIndex(new_position);
+		}
+	    }
+	}
+
+
+	/** Listens for key presses within the name field, and enabled or disables controls as appropriate. */
+	private class NameListener
+	    implements DocumentListener
+	{
+	    public void changedUpdate(DocumentEvent e)
+	    {
+		validateControls();
+	    }
+
+	    public void insertUpdate(DocumentEvent e)
+	    {
+		validateControls();
+	    }
+
+	    public void removeUpdate(DocumentEvent e)
+	    {
+		validateControls();
+	    }
+	}
+
+
+	private class RemoveListener
+	    implements ActionListener
+	{
+	    public void actionPerformed(ActionEvent event)
+	    {
+		int i = subcollection_index_list.getSelectedIndex();
+		if (i != -1) {
+		    removeSubcollectionIndex((SubcollectionIndex) subcollection_index_list.getSelectedValue());
+		}
+
+		int size = subcollection_index_list.getModel().getSize();
+		if (i == size) {
+		    i--;
+		}
+		subcollection_index_list.setSelectedIndex(i);
+		validateControls();
+	    }
+	}
+
+
+	private class ReplaceListener
+	    implements ActionListener
+	{
+	    public void actionPerformed(ActionEvent event)
+	    {
+		if (subcollection_index_list.isSelectionEmpty()) {
+		    // This should never happen, but just in case...
+		    replace_button.setEnabled(false);
+		    return;
+		}
+
+		// We'll just remove the old one and add the new one
+		removeSubcollectionIndex((SubcollectionIndex) subcollection_index_list.getSelectedValue());
+		replace_button.setEnabled(false);
+		add_button.setEnabled(true);
+		add_button.doClick();
+		add_button.setEnabled(false);
+	    }
+	}
+
+
+	private class SetDefaultListener
+	    implements ActionListener
+	{
+	    public void actionPerformed(ActionEvent event)
+	    {
+		SubcollectionIndex subcollection_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
+		if (subcollection_index != null) {
+		    setDefaultSubcollectionIndex(subcollection_index);
+		    // This should cause a repaint of just the desired row
+		    subcollection_index_list.setSelectedValue(subcollection_index, true);
+		}
+		set_default_button.setEnabled(false);
+	    }
+	}
+
+
+	private class SourceListListener
+	    implements ListSelectionListener
+	{
+	    public void valueChanged(ListSelectionEvent event)
+	    {
+		validateControls();
+	    }
+	}
+
+
+	/** Listens for selections within the list on the SubcollectionIndexManager controls, and if a change is detected enables, or disables, controls appropriately. */
+	private class SubcollectionIndexListListener
+	    implements ListSelectionListener
+	{
+	    /** This method is called whenever the source list selection changes. When it does we need to fill in the various parts of the list description panel
+	     * @param event A <strong>ListSelectionEvent</strong> containing further information about the list selection.
+	     */
+	    public void valueChanged(ListSelectionEvent event)
+	    {
+		if (event.getValueIsAdjusting()) {
+		    return;
+		}
+
+ 		int i = subcollection_index_list.getSelectedIndex();
+ 		int size = subcollection_index_list.getModel().getSize();
+ 		if (i < 0 || i >= size) {
+ 		    move_down_button.setEnabled(false);
+ 		    move_up_button.setEnabled(false);
+ 		    remove_button.setEnabled(false);
+ 		    replace_button.setEnabled(false);
+ 		    set_default_button.setEnabled(false);
+ 		    return;
+ 		}
+
+ 		// Enable the buttons appropriately
+ 		remove_button.setEnabled(true);
+ 		SubcollectionIndex selected_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
+ 		set_default_button.setEnabled(default_index == null || !default_index.equals(selected_index));
+ 		if (i > 0) {
+ 		    move_up_button.setEnabled(true);
+ 		}
+ 		else {
+ 		    move_up_button.setEnabled(false);
+ 		}
+ 		if (i < size-1){
+ 		    move_down_button.setEnabled(true);
+ 		}
+ 		else {
+ 		    move_down_button.setEnabled(false);
+ 		}
+
+ 		// Need to fill in the rest of the bits
+		updateControlsWithSelectedIndex();
+	    }
+	}
+
+
+	private class SubcollectionIndexListCellRenderer
+	    extends DefaultListCellRenderer
+	{
+	    /** Return a component that has been configured to display the specified value. */
+	    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+		JLabel component = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+		if (default_index != null && default_index.equals(value)) {
+		    component.setText(component.getText() + " " + Dictionary.get("CDM.SubcollectionIndexManager.Default_Partition_Indicator"));
+		}
+		return component;
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SubcollectionManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SubcollectionManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SubcollectionManager.java	(revision 10506)
@@ -0,0 +1,575 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.gui.NonWhitespaceField;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.w3c.dom.*;
+
+/** This class maintains a list of subcollections within our collection.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.4
+ */
+public class SubcollectionManager
+    extends DOMProxyListModel {
+
+    static final private String DISABLED_CONTROLS = "Disabled";
+    static final private String ENABLED_CONTROLS  = "Normal";
+    static final private String CLASS_DICTIONARY_NAME = "CDM.SubcollectionManager.";
+
+    /** The controls used to edit the settings of this manager. */
+    private Control controls = null;
+
+    private DOMProxyListModel model;
+
+    /** Constructor. 
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
+     * @see org.greenstone.gatherer.cdm.CollectionDesignManager
+     * @see org.greenstone.gatherer.cdm.DOMProxyListModel
+     * @see org.greenstone.gatherer.cdm.Subcollection
+     */
+    public SubcollectionManager() {
+	super(CollectionDesignManager.collect_config.getDocumentElement(), StaticStrings.SUBCOLLECTION_ELEMENT, new Subcollection());
+	DebugStream.println("SubcollectionManager: " + getSize() + " subcollections parsed.");
+	this.model = this;
+    }
+
+    /** Method to add a new subcollection.
+     * @param subcollection the Subcollection to add
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.cdm.CollectionConfiguration
+     * @see org.greenstone.gatherer.cdm.DOMProxyListModel
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     */
+    private void addSubcollection(Subcollection subcollection) {
+	if(!contains(subcollection)) {
+	    Element element = subcollection.getElement();
+	    // Locate where we should insert this new subcollection. 
+	    Node target_node = CollectionConfiguration.findInsertionPoint(element);
+	    // Failing that we insert immediately after a language string
+	    add(root, subcollection, target_node);
+	    Gatherer.c_man.configurationChanged();
+	}
+    }
+
+    public void destroy() {
+	if(controls != null) {
+	    controls.destroy();
+	    controls = null;
+	}
+    }
+
+    /** Method to retrieve the controls for this manager.
+     * @return the Control used to edit the subcollection data
+     */
+    public Control getControls() {
+	if(controls == null) {
+	    controls = new SubcollectionControl();
+	}
+	return controls;
+    }
+
+    /** Method to retrieve a certain subcollection by its name.
+     * @param name a String which is used as the key for finding the matching subcollection
+     * @return the requested Subcollection or null if no such subcollection exists.
+     */
+    private Subcollection getSubcollection(String name) {
+	Subcollection result = null;
+	int size = getSize();
+	for(int i = 0; i < size; i++) {
+	    Subcollection subcollection = (Subcollection) getElementAt(i);
+	    if(subcollection.getName().equals(name)) {
+		result = subcollection;
+	    }
+	}
+	return result;
+    }
+
+
+    /** Called when the detail mode has changed which in turn may cause several design elements to be available/hidden
+     * @param mode the new mode as an int
+     */
+    public void modeChanged(int mode) {
+	if(controls != null) {
+	    ((SubcollectionControl)controls).modeChanged(mode);
+	}
+    }    
+
+    /** Method to remove the given subcollection.
+     * @param subcollection the Subcollection you want to remove
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     */
+    private void removeSubcollection(Subcollection subcollection) {
+	remove(subcollection);
+	Gatherer.c_man.configurationChanged();
+    }
+
+    private void updateSubcollection(Subcollection subcollection, String name, boolean include, String source, String pattern, String flags) {
+	subcollection.setFlags(flags);
+	subcollection.setInclusive(include);
+	subcollection.setName(name);
+	subcollection.setPattern(pattern);
+	subcollection.setSource(source);
+	refresh(subcollection);
+	Gatherer.c_man.configurationChanged();
+    }
+
+    /** This class creates a JPanel containing serveral more controls used for editing subcollection information. */
+    private class SubcollectionControl
+	extends JPanel 
+	implements Control, ChangeListener
+    {
+	private CardLayout card_layout;
+	private JButton add_button;
+	private JButton remove_button;
+	private JButton update_button;
+	private JComboBox source_combobox;
+	private JList subcollection_list;
+	private JPanel border_pane;
+	private JTabbedPane tabbed_pane;
+	private JTextArea instructions_area;
+	private JTextField flags_field;
+	private JTextField match_field;
+	private JTextField name_field;
+	private JRadioButton exclude_button;
+	private JRadioButton include_button;
+
+	/** Constructor */
+	public SubcollectionControl() {
+	    // Create
+	    JPanel header_pane = new JPanel();
+	    instructions_area = new JTextArea();
+	    instructions_area.setEditable(false);
+	    instructions_area.setLineWrap(true);
+	    instructions_area.setRows(6);
+	    instructions_area.setWrapStyleWord(true);
+	    Dictionary.registerText(instructions_area, "CDM.SubcollectionManager.Instructions");
+
+	    border_pane = new JPanel();
+	    card_layout = new CardLayout();
+
+	    tabbed_pane = new JTabbedPane();
+	    tabbed_pane.addChangeListener(this);
+	    JLabel title = new JLabel();
+	    title.setHorizontalAlignment(JLabel.CENTER);
+	    Dictionary.registerText(title, "CDM.SubcollectionManager.Title");
+
+	    JPanel button_pane_3 = new JPanel();
+	    add_button = new GLIButton();
+	    add_button.setMnemonic(KeyEvent.VK_A);
+	    add_button.setEnabled(false);
+	    Dictionary.registerBoth(add_button, "CDM.SubcollectionManager.Add", "CDM.SubcollectionManager.Add_Tooltip");
+	    remove_button = new GLIButton();
+	    remove_button.setMnemonic(KeyEvent.VK_R);
+	    remove_button.setEnabled(false);
+	    Dictionary.registerBoth(remove_button, "CDM.SubcollectionManager.Remove", "CDM.SubcollectionManager.Remove_Tooltip");
+	    update_button = new GLIButton();
+	    update_button.setMnemonic(KeyEvent.VK_C);
+	    update_button.setEnabled(false);
+	    Dictionary.registerBoth(update_button, "CDM.SubcollectionManager.Replace", "CDM.SubcollectionManager.Replace_Tooltip");
+
+	    JPanel button_pane = new JPanel();
+	    JPanel button_pane_1 = new JPanel();
+	    include_button = new JRadioButton();
+	    include_button.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    include_button.setMnemonic(KeyEvent.VK_I);
+	    include_button.setOpaque(false);
+	    Dictionary.registerText(include_button, "CDM.SubcollectionManager.Include");
+	    exclude_button = new JRadioButton();
+	    exclude_button.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    exclude_button.setMnemonic(KeyEvent.VK_X);
+	    exclude_button.setOpaque(false);
+	    Dictionary.registerText(exclude_button, "CDM.SubcollectionManager.Exclude");
+
+	    JLabel flags_label = new JLabel();
+	    Dictionary.registerText(flags_label, "CDM.SubcollectionManager.Flags");
+	    flags_field = new NonWhitespaceField();
+	    Dictionary.registerTooltip(flags_field, "CDM.SubcollectionManager.Flags_Tooltip");
+
+	    JPanel inclusive_pane = new JPanel();
+	    JLabel inclusive_label = new JLabel();
+	    Dictionary.registerText(inclusive_label, "CDM.SubcollectionManager.Inclusive");
+
+	    JLabel match_label = new JLabel();
+	    Dictionary.registerText(match_label, "CDM.SubcollectionManager.Match");
+	    match_field = new JTextField();
+	    Dictionary.registerTooltip(match_field, "CDM.SubcollectionManager.Match_Tooltip");
+
+	    JLabel name_label = new JLabel();
+	    Dictionary.registerText(name_label, "CDM.SubcollectionManager.Name");
+	    name_field = new NonWhitespaceField();
+	    Dictionary.registerTooltip(name_field, "CDM.SubcollectionManager.Name_Tooltip");
+
+	    JLabel source_label = new JLabel();
+	    Dictionary.registerText(source_label, "CDM.SubcollectionManager.Source");
+	    ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+	    Vector source_model = new Vector(every_metadata_set_element);
+	    source_model.add(0, StaticStrings.FILENAME_STR);
+	    source_combobox = new JComboBox(source_model);
+	    Dictionary.registerTooltip(source_combobox, "CDM.SubcollectionManager.Source_Tooltip");
+
+	    subcollection_list = new JList(model);
+	    subcollection_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	    JPanel subcollection_pane = new JPanel();
+	    ButtonGroup bg = new ButtonGroup();
+	    bg.add(include_button);
+	    bg.add(exclude_button);
+	    include_button.setSelected(true);
+	    JPanel subcollection_list_pane = new JPanel();
+	    JLabel subcollection_list_label = new JLabel();
+	    Dictionary.registerText(subcollection_list_label, "CDM.SubcollectionManager.Assigned");
+
+	    // Create a message pane which explains why these controls are not currently active
+	    JPanel message_pane = new JPanel();
+	    String args[] = new String[3];
+	    args[0] = Configuration.getModeAsString();
+	    args[1] = Dictionary.get("Preferences.Mode.Systems");
+	    args[2] = Dictionary.get("Preferences.Mode.Expert");
+	    JTextArea message_textarea = new JTextArea();
+	    Dictionary.registerText(message_textarea, "CDM.SubcollectionManager.Partitions_Disabled", args);
+	    message_textarea.setEditable(false);
+	    message_textarea.setHighlighter(null); // Prevent highlighting
+	    message_textarea.setLineWrap(true);
+	    message_textarea.setOpaque(false); // Make it transparent
+	    message_textarea.setWrapStyleWord(true);
+
+	    // Add listeners
+	    SubCollectionChangeListener cl = new SubCollectionChangeListener();
+	    add_button.addActionListener(new AddSubCollectionListener());
+	    add_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    remove_button.addActionListener(new RemoveSubCollectionListener());
+	    remove_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    update_button.addActionListener(new UpdateSubCollectionListener());
+	    update_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    exclude_button.addActionListener(cl);
+	    include_button.addActionListener(cl);
+	    source_combobox.addActionListener(cl);
+	    flags_field.getDocument().addDocumentListener(cl);
+	    match_field.getDocument().addDocumentListener(cl);
+	    name_field.getDocument().addDocumentListener(cl);
+	    subcollection_list.addListSelectionListener(new SubCollectionListListener());
+
+	    // Layout
+	    instructions_area.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
+
+	    header_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    header_pane.setLayout(new BorderLayout());
+	    header_pane.add(title, BorderLayout.NORTH);
+	    header_pane.add(new JScrollPane(instructions_area), BorderLayout.CENTER);
+
+	    inclusive_pane.setLayout(new GridLayout());
+	    inclusive_pane.add(include_button);
+	    inclusive_pane.add(exclude_button);
+
+	    button_pane_1.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    button_pane_1.setLayout(new GridLayout(5, 2));
+	    button_pane_1.add(name_label);
+	    button_pane_1.add(name_field);
+	    button_pane_1.add(source_label);
+	    button_pane_1.add(source_combobox);
+	    button_pane_1.add(match_label);
+	    button_pane_1.add(match_field);
+	    button_pane_1.add(inclusive_label);
+	    button_pane_1.add(inclusive_pane);
+	    button_pane_1.add(flags_label);
+	    button_pane_1.add(flags_field);
+
+	    button_pane_3.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    button_pane_3.setLayout(new GridLayout(1,3));
+	    button_pane_3.add(add_button);
+	    button_pane_3.add(update_button);
+	    button_pane_3.add(remove_button);
+
+	    button_pane.setLayout(new BorderLayout());
+	    button_pane.add(button_pane_1, BorderLayout.CENTER);
+	    button_pane.add(button_pane_3, BorderLayout.SOUTH);
+
+	    subcollection_list_pane.setLayout(new BorderLayout());
+	    subcollection_list_pane.add(subcollection_list_label, BorderLayout.NORTH);
+	    subcollection_list_pane.add(new JScrollPane(subcollection_list), BorderLayout.CENTER);
+	    subcollection_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    subcollection_pane.setLayout(new BorderLayout());
+	    subcollection_pane.add(subcollection_list_pane, BorderLayout.CENTER);
+	    subcollection_pane.add(button_pane, BorderLayout.SOUTH);
+
+	    tabbed_pane.addTab(Dictionary.get("CDM.SubcollectionManager.Subcollection_Controls"), subcollection_pane);
+	    tabbed_pane.addTab(Dictionary.get("CDM.SubcollectionManager.Subindex_Controls"), (JPanel) CollectionDesignManager.subcollectionindex_manager.getControls());
+	    tabbed_pane.addTab(Dictionary.get("CDM.SubcollectionManager.Language_Controls"), (JPanel) CollectionDesignManager.language_manager.getControls());
+
+	    message_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
+	    message_pane.setLayout(new GridLayout(3,1,0,0));
+	    message_pane.add(new JPanel());
+	    message_pane.add(message_textarea);
+	    message_pane.add(new JPanel());
+
+	    border_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
+	    border_pane.setLayout(card_layout);
+	    if(Configuration.getMode() > Configuration.LIBRARIAN_MODE) {
+		border_pane.add(tabbed_pane, ENABLED_CONTROLS);
+		border_pane.add(message_pane, DISABLED_CONTROLS);
+	    }
+	    else {
+		border_pane.add(message_pane, DISABLED_CONTROLS);
+		border_pane.add(tabbed_pane, ENABLED_CONTROLS);
+	    }
+
+	    setLayout(new BorderLayout());
+	    add(header_pane, BorderLayout.NORTH);
+	    add(border_pane, BorderLayout.CENTER);
+	}
+       	
+	/** Method to unregister any listeners to avoid memory leaks.
+	 */
+	public void destroy() {
+	}
+
+	public void gainFocus() {
+	    // Rebuild the sources combobox
+	    ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+	    Vector source_model = new Vector(every_metadata_set_element);
+	    source_model.add(0, "Filename"); // Add filename as a possible source.
+	    source_combobox.setModel(new DefaultComboBoxModel(source_model));
+	}
+
+	public void loseFocus() {
+	}
+	
+	/** Called when the detail mode has changed which in turn controls if any of the partition controls are visible, or if they are instead replaced with a message explaining why they are not.
+	 * @param mode the new mode as an int
+	 */
+	public void modeChanged(int mode) {
+	    if(mode > Configuration.LIBRARIAN_MODE) {
+		card_layout.show(border_pane, ENABLED_CONTROLS);
+	    }
+	    else {
+		card_layout.show(border_pane, DISABLED_CONTROLS);
+	    }
+	}
+
+	public void stateChanged(ChangeEvent event)
+	{
+	    if (tabbed_pane.getSelectedIndex() == 1) {
+		CollectionDesignManager.subcollectionindex_manager.getControls().gainFocus();
+	    }
+	    if (tabbed_pane.getSelectedIndex() == 2) {
+		CollectionDesignManager.language_manager.getControls().gainFocus();
+	    }
+	}
+
+	/** Listens for actions apon the 'add' button in the SubcollectionManager controls, and if detected calls the addSubcollection method of the manager with a newly created subcollection. */
+	private class AddSubCollectionListener
+	    implements ActionListener {
+	    /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we wish to retrieve information from the various edit controls, and if we have sufficient data to build a new subcollection do so.
+	     * @param event An <strong>ActionEvent</strong> containing information about the event.
+	     * @see org.greenstone.gatherer.cdm.Subcollection
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		String name = name_field.getText();
+		String source = null;
+		Object object = source_combobox.getSelectedItem();
+		if (object instanceof MetadataElement) {
+		    MetadataElement metadata_element = (MetadataElement) object;
+		    source = metadata_element.getFullName();
+		}
+		else {
+		    source = object.toString();
+		}
+		String pattern = match_field.getText();
+		String flags = flags_field.getText();
+		if(name.length() > 0 && (source == null || source.length() > 0) && pattern.length() > 0) {
+		    Subcollection subcollection = new Subcollection(name, include_button.isSelected(), source, pattern, flags);
+		    addSubcollection(subcollection);
+		    // Change the selection to the new subcollection
+		    subcollection_list.setSelectedValue(subcollection, true);
+		}
+		add_button.setEnabled(false);
+	    }
+	}
+
+	/** This class listens for any key entry in a text field, selection change in a combobox or button click, and updates a subcollection as appropriate. Its also convenient to use this class to test if the add button should be active yet. */
+	private class SubCollectionChangeListener
+	    implements DocumentListener, ActionListener {
+	    /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to record that somethings changed, then validate the controls.
+	     * @param event An <strong>ActionEvent</strong> containing information about the event.
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		validateAdd();
+	    }
+
+	    public void changedUpdate(DocumentEvent event) {
+		validateAdd();
+	    }
+
+	    public void insertUpdate(DocumentEvent event) {
+		validateAdd();
+
+	    }
+
+	    public void removeUpdate(DocumentEvent event) {
+		validateAdd();
+	    }
+
+	    /** Method to validate the current subcollection editor values, and enable or disable controls (add button) based on said values. */
+	    private void validateAdd() {
+		if(name_field.getText().length() > 0 && match_field.getText().length() > 0) {
+		    if (getSubcollection(name_field.getText()) == null) {
+			add_button.setEnabled(true);
+		    } else {
+			add_button.setEnabled(false);
+		    }
+		}
+		else {
+		    add_button.setEnabled(false);
+		}
+	    }
+	}
+
+	/** Listens for actions apon the 'remove' button in the SubcollectionManager controls, and if detected calls the remove method of the manager with the SubIndex selected for removal. */
+	private class RemoveSubCollectionListener
+	    implements ActionListener {
+	    /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to check if they have a subcolleciton selected, and if so remove both it and any subindexes based on it.
+	     * @param event An <strong>ActionEvent</strong> containing information about the event.
+	     * @see org.greenstone.gatherer.cdm.Subcollection
+	     */
+	    public void actionPerformed(ActionEvent event) {
+		if(!subcollection_list.isSelectionEmpty()) {
+		    Subcollection subcollection = (Subcollection)subcollection_list.getSelectedValue();
+		    removeSubcollection(subcollection);
+		    // And remove subcollection indexes dependant on this subcollection
+		    CollectionDesignManager.subcollectionindex_manager.removeSubcollectionIndexes(subcollection);
+		}
+		remove_button.setEnabled(false);
+	    }
+	}
+
+	private class UpdateSubCollectionListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		if(!subcollection_list.isSelectionEmpty()) {
+		    Subcollection subcollection = (Subcollection)subcollection_list.getSelectedValue();
+		    String name = name_field.getText();
+		    String source = null;
+		    Object object = source_combobox.getSelectedItem();
+		    if (object instanceof MetadataElement) {
+			MetadataElement metadata_element = (MetadataElement) object;
+			source = metadata_element.getFullName();
+		    }
+		    else {
+			source = object.toString();
+		    }
+		    String pattern = match_field.getText();
+		    String flags = flags_field.getText();
+		    if(name.length() > 0 && (source == null || source.length() > 0) && pattern.length() > 0) {
+			updateSubcollection(subcollection, name, include_button.isSelected(), source, pattern, flags);
+		    }
+		}
+	    }
+	}
+
+	/** This class listens for selections in the list on the subcollections pane of the SubcollectionManager, and updates the controls as necessary to reflect selection. */
+	private class SubCollectionListListener
+	    implements ListSelectionListener {
+	    /** Any implementation of ListSelectionListener must include this method so we can be informed when the selection changes. In this case we want to execute any changes the users made to the entry, then update the controls with details of the new selection.
+	     * @param event A <strong>ListSelectionEvent</strong> containing information related to this event.
+	     * @see org.greenstone.gatherer.cdm.Subcollection
+	     */
+	    public void valueChanged(ListSelectionEvent event) {
+		// Wait until the event stabilises to avoid processing it multiple times
+		if (event.getValueIsAdjusting() == true) {
+		    return;
+		}
+		// Now the entry
+		if(!subcollection_list.isSelectionEmpty()) {
+		    Subcollection subcollection = (Subcollection) subcollection_list.getSelectedValue();
+		    flags_field.setText(subcollection.getFlags());
+		    include_button.setSelected(subcollection.isInclusive());
+		    exclude_button.setSelected(!subcollection.isInclusive());
+		    match_field.setText(subcollection.getPattern());
+		    name_field.setText(subcollection.getName());
+		    String s = subcollection.getSource();
+		    int pos = 0;
+		    Object value = source_combobox.getItemAt(pos);
+		    //ystem.err.println("Search for: " + s);
+		    while (value != null) {
+			if (value instanceof MetadataElement) {
+			    MetadataElement metadata_element = (MetadataElement) value;
+			    String metadata_element_name = metadata_element.getFullName();
+			    //ystem.err.print("Compare to: " + e_name);
+			    if (metadata_element_name.equals(s)) {
+				source_combobox.setSelectedIndex(pos);
+				value = null;
+				//ystem.err.println(" - Match");
+			    }
+			    else {
+				pos++;
+				value = source_combobox.getItemAt(pos);
+				//ystem.err.println(" - Fail");
+			    }
+			}
+			else if(value.toString().equals(s)) {
+			    source_combobox.setSelectedIndex(pos);
+			    value = null;
+			}
+			else {
+			    pos++;
+			    value = source_combobox.getItemAt(pos);
+			}
+		    }
+		    // Can't add one thats already there.
+		    add_button.setEnabled(false);
+		    // You can update or remove it though...
+		    remove_button.setEnabled(true);
+		    update_button.setEnabled(true);
+		}
+		else {
+		    flags_field.setText("");
+		    include_button.setSelected(true);
+		    match_field.setText("");
+		    name_field.setText("");
+		    source_combobox.setSelectedIndex(0);
+		    remove_button.setEnabled(false);
+		    update_button.setEnabled(false);
+		}
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SuperCollection.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SuperCollection.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SuperCollection.java	(revision 10506)
@@ -0,0 +1,99 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+/**************************************************************************************
+ * Written:     02/07/03
+ * Revised:     
+ **************************************************************************************/
+import org.w3c.dom.Element;
+
+public class SuperCollection
+    implements DOMProxyListEntry {
+
+    private Element element;
+    private String name;
+
+    public SuperCollection() {
+	element = null;
+	name = null;
+    }
+
+    public SuperCollection(Element element) {
+	this.element = element;
+	name = null;
+    }
+
+    public int compareTo(Object other) {
+	return this.getName().compareTo(other.toString());
+    }
+
+    public DOMProxyListEntry create(Element element) {
+	return new SuperCollection(element);
+    } 
+
+    public boolean equals(Object other) {
+	return (compareTo(other) == 0);
+    }
+
+    public Element getElement() {
+	return element;
+    }
+
+    public String getName() {
+	if(name == null && element != null) {
+	    name = element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
+	}
+	return name;
+    }
+
+    public boolean isAssigned() {
+	return (element != null && element.getAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE).equals(CollectionConfiguration.TRUE_STR));
+    }
+
+    public void setAssigned(boolean assigned) {
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.ASSIGNED_ATTRIBUTE, (assigned ? CollectionConfiguration.TRUE_STR : CollectionConfiguration.FALSE_STR));
+	}
+    }
+
+    public void setElement(Element element) {
+	this.element = element;
+	name = null;
+    }
+
+    public void setName(String name) {
+	this.name = name;
+	if(element != null) {
+	    element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, name);
+	}
+    }
+
+    public String toString() {
+	return getName();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SuperCollectionManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SuperCollectionManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/SuperCollectionManager.java	(revision 10506)
@@ -0,0 +1,229 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
+import org.greenstone.gatherer.util.CheckList;
+import org.greenstone.gatherer.util.CheckListEntry;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.w3c.dom.*;
+
+/** This class contains the information about what supercollection has been specified (if any) and methods for changing this information. Note that there is a major difference between this manager and the others in that its DOM model is never used directly in any list component. It is only used to decide whether a certain entry in the actual checklist is checked. */
+public class SuperCollectionManager
+    extends DOMProxyListModel {
+
+    static final public String SUPERCOLLECTION_COMMAND = "supercollection";
+    static final public String CCS_COMMAND = "ccs";
+    private ArrayList collection_checklist_model = null; // Model used to actually populate list
+    private Control controls = null;
+    private DOMProxyListModel model = null;
+    private String current_coll_name = null;
+    private boolean superCollectionChanged = false;
+
+    public SuperCollectionManager(Element supercollections_element) {
+	super(supercollections_element, StaticStrings.COLLECTION_ELEMENT, new SuperCollection());
+	DebugStream.println("SuperCollectionManager: " + getSize() + " supercollection members parsed.");
+	this.model = this;
+    }
+
+    public void destroy() {
+	if(controls != null) {
+	    controls.destroy();
+	    controls = null;
+	}
+	if(collection_checklist_model != null) {
+	    collection_checklist_model.clear();
+	    collection_checklist_model = null;
+	}
+    }
+
+    private void addSuperCollection(SuperCollection supercollection) {
+	if(!contains(supercollection)) {
+	    add(getSize(), supercollection);
+	}
+    }
+
+    /** Method to retrieve the control for this manager.
+     * @return the Control for editing supercollection settings
+     */
+    public Control getControls() {
+	if(controls == null) {
+	    // Build controls
+	    this.controls = new SuperCollectionControl();
+	}
+	return controls;
+    }
+
+    public SuperCollection getSuperCollection(String collection_name) {
+	SuperCollection result = null;
+	int size = getSize();
+	for(int i = 0; result == null && i < size; i++) {
+	    SuperCollection supercollection = (SuperCollection) getElementAt(i);
+	    if(supercollection.getName().equals(collection_name)) {
+		result = supercollection;
+	    }
+	    supercollection = null;
+	}
+	return result;
+    }
+
+    private void removeSuperCollection(SuperCollection supercollection) {
+	remove(supercollection);
+    }
+
+    /** Provides controls for altering the SuperCollection settings. */
+    private class SuperCollectionControl
+	extends JPanel
+	implements Control {
+
+	private boolean init = true;
+	private CheckList collection_checklist = null;
+
+	SuperCollectionControl() {
+	    super();
+
+	    // Creation
+	    JPanel header_panel = new JPanel();
+
+	    JLabel title_label = new JLabel();
+	    title_label.setHorizontalAlignment(JLabel.CENTER);
+	    title_label.setOpaque(true);
+	    Dictionary.registerText(title_label, "CDM.SuperCollectionManager.Title");
+
+	    JTextArea instructions = new JTextArea();
+	    instructions.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    instructions.setCaretPosition(0);
+	    instructions.setEditable(false);
+	    instructions.setLineWrap(true);
+	    instructions.setRows(6);
+	    instructions.setWrapStyleWord(true);
+	    Dictionary.registerText(instructions, "CDM.SuperCollectionManager.Instructions");
+
+	    collection_checklist = new CheckList(false);
+	    buildModel();
+	    collection_checklist.setListData(collection_checklist_model);
+
+	    // Layout
+	    header_panel.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    header_panel.setLayout(new BorderLayout());
+	    header_panel.add(title_label, BorderLayout.NORTH);
+	    header_panel.add(new JScrollPane(instructions), BorderLayout.CENTER);
+
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    add(header_panel, BorderLayout.NORTH);
+	    add(new JScrollPane(collection_checklist), BorderLayout.CENTER);
+	}
+
+	public void destroy() {
+	}
+
+	public void gainFocus() {
+	}
+
+	public void loseFocus() {
+	    CollectionDesignManager.collect_cfg_change_listener.maybeSetRebuildRequired(); // !! TO DO: This is crap
+	    int super_collections_count = 0;
+	    // Retrieve the current supercollections
+	    ArrayList supercollections = children();
+	    // Now iterate through the checklist, and for each checked box found ensure the Supercollection exists, and ensure its assigned. Remove any supercollections altered in this way from the temporary array list
+	    int size = collection_checklist_model.size();
+	    for(int i = 0; i < size; i++) {
+		CheckListEntry entry = (CheckListEntry) collection_checklist_model.get(i);
+		if(entry.isSelected()) {
+		    String collection_name = (String) entry.getProperty();
+		    SuperCollection supercollection = getSuperCollection(collection_name);
+		    // Create the supercollection element if necessary
+		    if(supercollection == null) {
+			Element supercollection_element = root.getOwnerDocument().createElement(StaticStrings.COLLECTION_ELEMENT);
+			supercollection = new SuperCollection(supercollection_element);
+			supercollection.setName(collection_name);
+			addSuperCollection(supercollection);
+		    }
+		    else {
+			supercollections.remove(supercollection);
+		    }
+		    supercollection.setAssigned(true);
+		    super_collections_count++;
+		}
+	    }
+	    // Any collections left in the temporary list have been unselected, so delete them
+	    for(int j = supercollections.size(); j > 0; j--) {
+		SuperCollection supercollection = (SuperCollection) supercollections.get(j - 1);
+		removeSuperCollection(supercollection);
+	    }
+	    // Now we only assign supercollections if more than one is selected
+	    model.root.setAttribute(StaticStrings.ASSIGNED_ATTRIBUTE, (super_collections_count > 1 ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
+	}
+
+
+	private void buildModel()
+	{
+	    collection_checklist_model = new ArrayList();
+	    current_coll_name = Gatherer.c_man.getCollection().getName();
+
+	    File collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	    File[] possible_collections = collect_directory.listFiles();
+	    for(int i = 0; possible_collections != null && i < possible_collections.length; i++) {
+		File collect_cfg_file = new File(possible_collections[i], Utility.CONFIG_FILE);
+		if (collect_cfg_file.exists()) {
+		    BasicCollectionConfiguration collect_cfg = new BasicCollectionConfiguration(collect_cfg_file);
+		    StringBuffer title_buffer = new StringBuffer(collect_cfg.getName());
+		    title_buffer.append(StaticStrings.SPACE_CHARACTER);
+		    title_buffer.append(StaticStrings.OPEN_PARENTHESIS_CHARACTER);
+		    title_buffer.append(possible_collections[i].getName());
+		    title_buffer.append(StaticStrings.CLOSE_PARENTHESIS_CHARACTER);
+		    String collection_title = title_buffer.toString();
+		    title_buffer = null;
+		    String collection_name = possible_collections[i].getName();
+
+		    // We have to block the model collection.
+		    if (collect_cfg.getName().equals("**title**")) {
+			continue;
+		    }
+
+		    // The current collection is always selected.
+		    CheckListEntry entry = new CheckListEntry(collection_title);
+		    entry.setProperty(collection_name);
+		    entry.setSelected(getSuperCollection(collection_name) != null || collection_name.equals(current_coll_name));
+		    entry.setFixed(collection_name.equals(current_coll_name));
+		    collection_checklist_model.add(entry);
+		}
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/TranslationView.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/TranslationView.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/cdm/TranslationView.java	(revision 10506)
@@ -0,0 +1,722 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.cdm;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.gui.GLIButton;
+
+/** This class provides a graphical interface to allow a user to quickly and conviently (ie all in one place) translate the text fragments associated with general metadata and indexes into each of the assigned languages in the collection. It should provide clear controls for the editing of these text fragments, plus clear indicate what languages still need further translation, which it will do through a combination of coloring and other visual indicators.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class TranslationView {
+
+    private Control controls;
+
+    static final private Dimension COMPONENT_SIZE = new Dimension(225,25);
+    static final private int LANGUAGE_WIDTH = 75;
+    static final private String GENERAL_STR = "General:";
+    static final private String INDEX_STR = "Index:";
+    static final private String PARTITION_STR = "Partitions:";
+
+    public TranslationView() {
+	DebugStream.println("TranslationView: Initialized.");
+    }
+
+    public void destroy() {
+	if(controls != null) {
+	    controls.destroy();
+	    controls = null;
+	}
+    }
+
+    public Control getControls() {
+	if(controls == null) {
+	    controls = new TranslationControl();
+	}
+	return controls;
+    }
+
+    private Object[] getFeaturesList() {
+	ArrayList features_model = new ArrayList();
+
+	// Add the indexes
+	ArrayList indexes = CollectionDesignManager.index_manager.getIndexes();
+	int indexes_size = indexes.size();
+	for(int j = 0; j < indexes_size; j++) {
+	    Object bob = new BobTheMagicalComparableWrapper(indexes.get(j));
+	    if(!features_model.contains(bob)) {
+		features_model.add(bob);
+	    }
+	}
+
+	// We also add subindexes.
+	ArrayList subindexes = CollectionDesignManager.subcollectionindex_manager.getSubcollectionIndexes();
+	int subindexes_size = subindexes.size();
+	for(int j = 0; j < subindexes_size; j++) {
+	    Object bob = new BobTheMagicalComparableWrapper(subindexes.get(j));
+	    if(!features_model.contains(bob)) {
+		features_model.add(bob);
+	    }
+	}
+
+	// Finally we add any remaining metadata as general
+	ArrayList general_metadata = CollectionDesignManager.collectionmeta_manager.getMetadata();
+	for(int i = 0; i < general_metadata.size(); i++) {
+	    CollectionMeta metadata = (CollectionMeta) general_metadata.get(i);
+	    if(!metadata.isSpecial()) {
+		Object bob = new BobTheMagicalComparableWrapper(metadata.getName());
+		if(!features_model.contains(bob)) {
+		    features_model.add(bob);
+		}
+	    }
+	}
+
+	Collections.sort(features_model);
+
+	return features_model.toArray();
+    }
+
+    private class BobTheMagicalComparableWrapper
+	implements Comparable {
+	private Object content;
+	private String text;
+	BobTheMagicalComparableWrapper(Object content) {
+	    this.content = content;
+	}
+	public int compareTo(Object object) {
+	    if(object == null) {
+		object = "";
+	    }
+	    if(text == null) {
+		toString();
+	    }
+	    return text.compareTo(object.toString());
+	}
+
+	/** Equals is used by contains and since we want to prevent double up of metadata we compare differently than in compareTo. */
+	public boolean equals(Object object) {
+	    return (object != null && content.toString().equals(((BobTheMagicalComparableWrapper)object).getContent().toString()));
+	}
+
+	public Object getContent() {
+	    return content;
+	}
+
+	public String getName() {
+	    if(content instanceof Index) {
+		return CollectionConfiguration.STOP_CHARACTER + ((Index)content).getID();
+	    }
+	    else if (content instanceof SubcollectionIndex) {
+	    	return CollectionConfiguration.STOP_CHARACTER + ((SubcollectionIndex)content).getID();
+	    }
+	    else {
+		return content.toString();
+	    }
+	}
+
+	public String toString() {
+	    if(text == null) {
+		String temp = content.toString();
+		if(temp.indexOf(CollectionConfiguration.SPACE_CHARACTER) != -1) {
+		    temp = temp.substring(0, temp.indexOf(CollectionConfiguration.SPACE_CHARACTER));
+		}
+		if(content instanceof Index) {
+		    text = INDEX_STR + temp;
+		}
+		else if(content instanceof SubcollectionIndex) {
+		    text = PARTITION_STR + temp;
+		}
+		else {
+		    text = GENERAL_STR + temp;
+		}
+	    }
+	    return text;
+	}
+    }
+
+    private class TranslationControl
+	extends JPanel 
+	implements Control {
+
+	private boolean ignore_event = false;
+	private FragmentTableModel fragment_table_model;
+	private JButton add_button;
+	private JButton remove_button;
+	private JButton replace_button;
+	private JComboBox language_combobox;
+	private JList features_list;
+	private JTable fragment_table;
+	private JTextArea default_area;
+	private JTextArea translation_area;
+
+	TranslationControl() {
+	    fragment_table_model = new FragmentTableModel("", new TreeSet(), new ArrayList());
+	    // Creation
+	    JPanel header_panel = new JPanel();
+	    JLabel title_label = new JLabel();
+	    title_label.setHorizontalAlignment(JLabel.CENTER);
+	    Dictionary.registerText(title_label, "CDM.TranslationManager.Title");
+
+	    JTextArea instruction_area = new JTextArea();
+	    instruction_area.setEditable(false);
+	    instruction_area.setLineWrap(true);
+	    instruction_area.setRows(6);
+	    instruction_area.setWrapStyleWord(true);
+	    Dictionary.registerText(instruction_area, "CDM.TranslationManager.Instructions");
+
+	    JPanel center_panel = new JPanel();
+
+	    JPanel selection_panel = new JPanel();
+
+	    JPanel component_selection_panel = new JPanel();
+	    JLabel component_label = new JLabel();
+	    Dictionary.registerText(component_label, "CDM.TranslationManager.Affected_Features");
+	    features_list = new JList(getFeaturesList());
+	    features_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+	    JPanel fragment_selection_panel = new JPanel();
+	    JLabel fragment_label = new JLabel();
+	    Dictionary.registerText(fragment_label, "CDM.TranslationManager.Assigned_Fragments");
+
+	    fragment_table = new JTable(fragment_table_model);
+	    fragment_table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
+	    fragment_table.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    fragment_table.setColumnSelectionAllowed(false);
+	    fragment_table.setDefaultRenderer(Object.class, new FragmentTableRenderer());
+	    fragment_table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+	    JScrollPane table_scroll = new JScrollPane(fragment_table);
+	    table_scroll.getViewport().setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    table_scroll.setOpaque(true);
+
+	    JPanel south_panel = new JPanel();
+
+	    JPanel text_panel = new JPanel();
+
+	    JPanel language_panel = new JPanel();
+	    JLabel language_label = new JLabel();
+	    Dictionary.registerText(language_label, "CDM.TranslationManager.Language");
+	    language_combobox = new JComboBox(CollectionDesignManager.language_manager.getLanguageCodes().toArray());
+	    language_combobox.setPreferredSize(COMPONENT_SIZE);
+	    language_combobox.setRenderer(new LanguageListCellRenderer());
+	    Dictionary.registerTooltip(language_combobox, "CDM.TranslationManager.Language_Tooltip");
+
+	    JPanel default_text_panel = new JPanel();
+	    JLabel default_label = new JLabel();
+	    Dictionary.registerText(default_label, "CDM.TranslationManager.Default_Text");
+	    default_area = new JTextArea();
+	    default_area.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    default_area.setEditable(false);
+	    default_area.setLineWrap(true);
+	    default_area.setWrapStyleWord(true);
+
+	    JPanel translated_text_panel = new JPanel();
+	    JLabel translation_label = new JLabel();
+	    Dictionary.registerText(translation_label, "CDM.TranslationManager.Translation");
+	    translation_area = new JTextArea();
+	    translation_area.setBackground(Configuration.getColor("coloring.disabled", false));
+	    translation_area.setEnabled(false);
+	    translation_area.setLineWrap(true);
+	    translation_area.setWrapStyleWord(true);
+	    Dictionary.registerTooltip(translation_area, "CDM.TranslationManager.Translation_Tooltip");
+
+	    JPanel button_pane = new JPanel();
+	    add_button = new GLIButton();
+	    add_button.setEnabled(false);
+	    add_button.setMnemonic(KeyEvent.VK_A);
+	    Dictionary.registerBoth(add_button, "CDM.TranslationManager.Add", "CDM.TranslationManager.Add_Tooltip");
+	    replace_button = new GLIButton();
+	    replace_button.setEnabled(false);
+	    replace_button.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.registerBoth(replace_button, "CDM.TranslationManager.Replace", "CDM.TranslationManager.Replace_Tooltip");
+	    remove_button = new GLIButton();
+	    remove_button.setEnabled(false);
+	    remove_button.setMnemonic(KeyEvent.VK_R);
+	    Dictionary.registerBoth(remove_button, "CDM.TranslationManager.Remove", "CDM.TranslationManager.Remove_Tooltip");
+
+	    // Connection
+	    add_button.addActionListener(new AddListener());
+	    add_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    remove_button.addActionListener(new RemoveListener());
+	    remove_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    replace_button.addActionListener(new ReplaceListener());
+	    replace_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
+	    language_combobox.addActionListener(new LanguageActionListener());
+	    translation_area.getDocument().addDocumentListener(new TranslationDocumentListener());
+	    features_list.addListSelectionListener(new FeaturesListSelectionListener());
+	    fragment_table.getSelectionModel().addListSelectionListener(new FragmentListSelectionListener());
+
+	    // Layout
+	    header_panel.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    header_panel.setLayout(new BorderLayout());
+	    header_panel.add(title_label, BorderLayout.NORTH);
+	    header_panel.add(new JScrollPane(instruction_area), BorderLayout.CENTER);
+
+	    component_selection_panel.setLayout(new BorderLayout());
+	    component_selection_panel.add(component_label, BorderLayout.NORTH);
+	    component_selection_panel.add(new JScrollPane(features_list), BorderLayout.CENTER);
+
+	    fragment_selection_panel.setLayout(new BorderLayout());
+	    fragment_selection_panel.add(fragment_label, BorderLayout.NORTH);
+	    fragment_selection_panel.add(table_scroll, BorderLayout.CENTER);
+
+	    selection_panel.setLayout(new GridLayout(2,1,0,5));
+	    selection_panel.add(component_selection_panel);
+	    selection_panel.add(fragment_selection_panel);
+
+	    default_text_panel.setLayout(new BorderLayout());
+	    default_text_panel.add(default_label, BorderLayout.NORTH);
+	    default_text_panel.add(new JScrollPane(default_area), BorderLayout.CENTER);
+
+	    translated_text_panel.setLayout(new BorderLayout());
+	    translated_text_panel.add(translation_label, BorderLayout.NORTH);
+	    translated_text_panel.add(new JScrollPane(translation_area), BorderLayout.CENTER);
+
+	    text_panel.setLayout(new GridLayout(1,2,5,0));
+	    text_panel.add(default_text_panel);
+	    text_panel.add(translated_text_panel);
+
+	    language_panel.setLayout(new BorderLayout(5,0));
+	    language_panel.add(language_label, BorderLayout.WEST);
+	    language_panel.add(language_combobox, BorderLayout.CENTER);
+
+	    south_panel.setLayout(new BorderLayout());
+	    south_panel.add(language_panel, BorderLayout.NORTH);
+	    south_panel.add(text_panel, BorderLayout.CENTER);
+
+	    center_panel.setLayout(new GridLayout(2,1,0,5));
+	    center_panel.add(selection_panel);
+	    center_panel.add(south_panel);
+
+	    button_pane.setBorder(BorderFactory.createEmptyBorder(2,0,0,0));
+	    button_pane.setLayout(new GridLayout(1,3));
+	    button_pane.add(add_button);
+	    button_pane.add(replace_button);
+	    button_pane.add(remove_button);
+
+	    setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    setLayout(new BorderLayout());
+	    add(header_panel, BorderLayout.NORTH);
+	    add(center_panel, BorderLayout.CENTER);
+	    add(button_pane, BorderLayout.SOUTH);
+	}
+
+	public void destroy() {
+	}
+
+	public void gainFocus() {
+	    // Rebuild the features model, just incase features have been added or removed.
+	    if(features_list != null) {
+		Object selected_feature = features_list.getSelectedValue();
+		features_list.setListData(getFeaturesList());
+		if(selected_feature != null) {
+		    features_list.setSelectedValue(selected_feature, true);
+		}
+	    }
+	}
+
+	public void loseFocus() {
+	}
+
+
+	private class AddListener
+	    implements ActionListener {
+	    
+	    public void actionPerformed(ActionEvent event) {
+		ignore_event = true;
+		String translation_text = translation_area.getText();
+		if(translation_text.length() > 0) {
+		    // If there is no current fragment table selection, but translation text is not an empty string, then this is a new fragment. Create new collection metadata, refresh the fragment table, then ensure that the new metadata is selected. Remember that it is the selected metadata to which changes will be applied.
+		    BobTheMagicalComparableWrapper selected_feature = (BobTheMagicalComparableWrapper)features_list.getSelectedValue();
+		    String language = (String) language_combobox.getSelectedItem();
+		    CollectionMeta metadatum = new CollectionMeta(selected_feature.getName(), language);
+		    metadatum.setValue(translation_text);
+		    CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
+		    fragment_table.clearSelection();
+		    ArrayList metadata = CollectionDesignManager.collectionmeta_manager.getMetadata(selected_feature.getName());
+		    fragment_table_model.setData(selected_feature.getName(), CollectionDesignManager.collectionmeta_manager.getLanguages(), metadata);
+		    int index = fragment_table_model.getMetadataIndexByLanguage(language);
+		    ///ystem.err.println("I want to select the row " + index + " out of " + metadata.size());
+		    fragment_table.setRowSelectionInterval(index, index);
+		    metadatum = null;
+		    language = null;
+		    selected_feature = null;
+		    translation_text = null;
+		    remove_button.setEnabled(true);
+		}
+		add_button.setEnabled(false);
+		replace_button.setEnabled(false);
+		ignore_event = false;
+	    }
+	}
+
+	private class RemoveListener
+	    implements ActionListener {
+	    
+	    public void actionPerformed(ActionEvent event) {
+		ignore_event = true;
+		int index = -1;
+		if((index = fragment_table.getSelectedRow()) != -1) {
+		    CollectionMeta metadata = fragment_table_model.getMetadata(index);
+		    CollectionDesignManager.collectionmeta_manager.removeMetadata(metadata);
+		    fragment_table_model.remove(index);
+		    // If a remove occured then enable add
+		    add_button.setEnabled(true);
+		}
+		// Either way disable replace and remove
+		replace_button.setEnabled(false);
+		remove_button.setEnabled(false);
+		ignore_event = false;
+	    }
+	}
+
+	private class ReplaceListener 
+	    implements ActionListener {
+
+	    public void actionPerformed(ActionEvent event) {
+		ignore_event = true;
+		int index = -1;
+		if((index = fragment_table.getSelectedRow()) != -1) {
+		    String translation_text = translation_area.getText();
+		    // Get the selected collection metadata
+		    CollectionMeta metadata = fragment_table_model.getMetadata(index);
+		    // Update the fragment metadata and ask the table to repaint the appropriate row
+		    metadata.setValue(translation_text);
+		    fragment_table_model.fireTableRowsUpdated(index, index);
+		    metadata = null;
+		    remove_button.setEnabled(true);
+		}
+		// Either way disable replace
+		add_button.setEnabled(false);
+		replace_button.setEnabled(false);
+		ignore_event = false;
+	    }
+	}
+
+	private class FeaturesListSelectionListener
+	    implements ListSelectionListener {
+	    public void valueChanged(ListSelectionEvent event) {
+		if(!event.getValueIsAdjusting() && !ignore_event) {
+		    ///ystem.err.println("FeaturesListSelectionListener");
+		    if(!features_list.isSelectionEmpty()) {
+			// Determine the features name. Remember to remove our helpful source prefix (delimited by ':').
+			BobTheMagicalComparableWrapper selected_feature = (BobTheMagicalComparableWrapper)features_list.getSelectedValue();
+			// Retrieve the default language translation, or otherwise the first match, to be default text.
+			CollectionMeta default_metadata = CollectionDesignManager.collectionmeta_manager.getMetadatum(selected_feature.getName());
+			if(default_metadata != null) {
+			    default_area.setText(default_metadata.getValue(CollectionMeta.TEXT));
+			}
+			// Update the text fragment table.
+			fragment_table.clearSelection();
+			fragment_table_model.setData(selected_feature.getName(), CollectionDesignManager.collectionmeta_manager.getLanguages(), CollectionDesignManager.collectionmeta_manager.getMetadata(selected_feature.getName()));
+			selected_feature = null;
+			// Now we check whatever value is currently selected in the combobox to see if it is valid to add.
+			String language_name = (String) language_combobox.getSelectedItem();
+			int index = fragment_table_model.getMetadataIndexByLanguage(language_name);
+			if(index != -1) {
+			    CollectionMeta metadata = fragment_table_model.getMetadata(index);
+			    fragment_table.setRowSelectionInterval(index, index);
+			    if(metadata != null) {
+				translation_area.setText(metadata.getValue(CollectionMeta.TEXT));
+			    }
+			    else {
+				translation_area.setText("");
+			    }
+			    metadata = null;
+			}
+			else {
+			    translation_area.setText("");
+			}
+			// Update and enable the text area
+			translation_area.setEnabled(true);
+			translation_area.setBackground(Configuration.getColor("coloring.editable_background", false));
+		    }
+		    else {
+			default_area.setText("");
+			fragment_table.clearSelection();
+			fragment_table_model.setData("", new TreeSet(), new ArrayList());
+			translation_area.setText("");
+			// Update and disable the text area
+			translation_area.setText("");
+			translation_area.setEnabled(false);
+			translation_area.setBackground(Configuration.getColor("coloring.disabled", false));
+		    }
+		}
+	    }
+	}
+
+	private class FragmentListSelectionListener
+	    implements ListSelectionListener {
+	    public void valueChanged(ListSelectionEvent event) {
+		if(!event.getValueIsAdjusting() && !ignore_event) {
+		    ignore_event = true;
+		    ///ystem.err.println("FragmentListSelectionListener");
+		    int index = -1;
+		    if((index = fragment_table.getSelectedRow()) != -1) {
+			// A row has been selected. Retrieve the collection metadata.
+			CollectionMeta metadatum = fragment_table_model.getMetadata(index);
+			if(metadatum != null) {
+			    // Update the combobox to show the current language.
+			    String language = metadatum.getLanguage();
+			    ///ystem.err.println("Searching for the language: " + language_name);
+			    for(int i = 0; i < language_combobox.getItemCount(); i++) {
+				if(language_combobox.getItemAt(i).toString().equals(language)) {
+				    language_combobox.setSelectedIndex(i);
+				}
+			    }
+			    translation_area.setText(metadatum.getValue(CollectionMeta.TEXT));
+			    remove_button.setEnabled(!metadatum.isDummy());
+			}
+			else {
+			    remove_button.setEnabled(false);
+			}
+		    }
+		    else {
+			translation_area.setText("");
+			remove_button.setEnabled(false);
+		    }
+		    ignore_event = false;
+		}
+	    }
+	}
+
+	private class FragmentTableModel
+	    extends AbstractTableModel {
+
+	    private ArrayList metadata;
+	    private String feature_name;
+	    private TreeSet languages;
+
+	    FragmentTableModel(String feature_name, TreeSet languages, ArrayList metadata) {
+		this.feature_name = feature_name;
+		this.languages = languages;
+		this.metadata = metadata;
+	    }
+	    public int getRowCount() {
+	       // The row count is equal to the maximum number of languages currently assigned in the collection.
+		return languages.size();
+	    }
+	    public int getColumnCount() {
+		return 2;
+	    }
+
+	    public String getColumnName(int column) {
+		if (column == 0) {
+		    return Dictionary.get("CDM.TranslationManager.Language_Column");
+		}
+		if (column == 1) {
+		    return Dictionary.get("CDM.TranslationManager.Fragment_Column");
+		}
+		return "";
+	    }
+
+	    /** Attempt to retrieve the metadata associated with a certain row - however not all rows actually have metadata with them (say the French row where no metadata has been set).
+	     * @param row the row number as an int
+	     * @return the CollectionMeta requested, which may be a dummy metadata pair
+	     */
+	    public CollectionMeta getMetadata(int row) {
+		// Determine what language we are talking about
+		String language = null;
+		Iterator language_iterator = languages.iterator();
+		int current_row = 0;
+		while(current_row != row && language_iterator.hasNext()) {
+		    language_iterator.next();
+		    current_row++;
+		}
+		if(current_row == row) {
+		    language = (String) language_iterator.next();
+		    return getMetadata(language);
+		}
+		language_iterator = null;
+		return null;
+	    }
+
+	    public CollectionMeta getMetadata(String language) {
+		// Attempt to retrieve metadata with that language
+		for(int i = 0; i < metadata.size(); i++) {
+		    CollectionMeta metadatum = (CollectionMeta) metadata.get(i);
+		    if(metadatum.getLanguage().equals(language)) {
+			return metadatum;
+		    }
+		}
+		return new CollectionMeta(feature_name, language, true);
+	    }
+
+	    public int getMetadataIndexByLanguage(String language) {
+		///ystem.err.println("Find the index for the language " + language + " (out of " + languages.size() + ")");
+		// First we have to iterate to the correct place
+		Iterator language_iterator = languages.iterator();
+		int current_row = 0;
+		while(language_iterator.hasNext()) {
+		    String target = (String)language_iterator.next();
+		    if(language.equals(target)) {
+			///ystem.err.println("Matches " + target);
+			return current_row;
+		    }
+		    else {
+			///ystem.err.println("Doesn't match " + target);
+			current_row++;
+		    }
+		}
+		///ystem.err.println("No such language in model: -1");
+		return -1;
+	    }
+
+	    public Object getValueAt(int row, int column) {
+		if(0 <= row && row < languages.size()) {
+		    // First we have to iterate to the correct place
+		    Iterator language_iterator = languages.iterator();
+		    int current_row = 0;
+		    while(current_row != row && language_iterator.hasNext()) {
+			language_iterator.next();
+			current_row++;
+		    }
+		    if(current_row == row) {
+			String language = (String)language_iterator.next();
+			if(column == 0) {
+			    return CollectionDesignManager.language_manager.getLanguageName(language);
+			}
+			else {
+			    CollectionMeta metadatum = getMetadata(language);
+			    return metadatum.getValue(CollectionMeta.TEXT);
+			}
+		    }
+		    language_iterator = null;
+		}
+		return "#Error";
+	    }
+
+	    public void remove(int index) {
+		metadata.remove(index);
+		fireTableRowsDeleted(index, index);
+	    }
+
+	    public void setData(String feature_name, TreeSet languages, ArrayList metadata) {
+		this.feature_name = feature_name;
+		this.languages = languages;
+		this.metadata = metadata;
+		fireTableDataChanged();
+	    }
+
+	    public int size() {
+		return metadata.size();
+	    }
+	}
+
+	private class FragmentTableRenderer
+	    extends DefaultTableCellRenderer {
+	    /** Retrieve the component used to rubberstamp the table based on the given parameters.
+	     * @param table The <strong>JTable</strong> to rendered.
+	     * @param value The <strong>Object</strong> whose representation will be shown in the table row.
+	     * @param isSelected <i>true</i> iff the column/row is selected.
+	     * @param hasFocus <i>true</i> iff the column/row is in focus.
+	     * @param row An <i>int</i> specifying the target row.
+	     * @param column An <i>int</i> specifying the target column.
+	     * @see org.greenstone.gatherer.cdm.Language
+	     */
+	    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+		JComponent component = (JComponent) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+		if(isSelected) {
+		    component.setBackground(Configuration.getColor("coloring.workspace_heading_background", false));
+		}
+		else {
+		    component.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+		}
+		return component;
+	    }
+	}
+
+	private class LanguageActionListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		if(!ignore_event) {
+		    ignore_event = true;
+		    ///ystem.err.println("LanguageActionListener");
+		    // If the newly selected language value already exists in the fragment table, and that row isn't the one selected, then select that row the text area.
+		    String language_name = language_combobox.getSelectedItem().toString();
+		    int index = fragment_table_model.getMetadataIndexByLanguage(language_name);
+		    if(index != -1) {
+			CollectionMeta metadata = fragment_table_model.getMetadata(index);
+			fragment_table.setRowSelectionInterval(index, index);
+			translation_area.setText(metadata.getValue(CollectionMeta.TEXT));
+		    }
+		    else {
+			fragment_table.clearSelection();
+			translation_area.setText("");
+		    }
+		    // Ready the text area
+		    translation_area.setEnabled(true);
+		    translation_area.setBackground(Configuration.getColor("coloring.editable_background", false));
+		    ignore_event = false;
+		}
+	    }
+	}
+
+	private class TranslationDocumentListener
+	    implements DocumentListener {
+	    /** Gives notification that an attribute or set of attributes changed. */
+	    public void changedUpdate(DocumentEvent e) {
+		update();
+	    }
+	    /** Gives notification that there was an insert into the document. */
+	    public void insertUpdate(DocumentEvent e) {
+		update();
+	    }
+	    /** Gives notification that a portion of the document has been removed. */
+	    public void removeUpdate(DocumentEvent e) {
+		update();
+	    }
+	    /** The text area has changed in some way. Given that this can only happed when we are editing or adding a text fragment we better respond appropriately. */
+	    private void update() {
+		String translation_text = translation_area.getText();
+		// Determine if add should be enabled. You can only add if the current text fragment doesn't already exist in the fragment table for the given language
+		String language = (String) language_combobox.getSelectedItem();
+		CollectionMeta metadatum = fragment_table_model.getMetadata(language);
+		add_button.setEnabled(translation_text.length() > 0 && (metadatum.isDummy() || fragment_table_model.getMetadataIndexByLanguage(language) == -1));
+		language = null;
+		// Determine if replace should be enabled. Replace is only enabled it the text fragment is different from the one in the current fragment table selection.
+		if(fragment_table.getSelectedRowCount() > 0) {
+		    replace_button.setEnabled(!metadatum.isDummy() && !translation_text.equals(fragment_table.getValueAt(fragment_table.getSelectedRow(), 1)));
+		}
+		// Nothing selected, nothing to replace
+		else {
+		    replace_button.setEnabled(false);
+		}
+		translation_text = null;
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/BasicCollectionConfiguration.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/BasicCollectionConfiguration.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/BasicCollectionConfiguration.java	(revision 10506)
@@ -0,0 +1,213 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.collection;
+
+import java.io.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.cdm.CommandTokenizer;
+import org.greenstone.gatherer.util.Codec;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.w3c.dom.*;
+
+/** This class provides access to a collection configuration file. This version accepts either a valid xml document or a historical collect.cfg file. */
+public class BasicCollectionConfiguration
+    implements Comparable {
+    
+    private File file;
+    private String creator = "";
+    private String description = "";
+    private String maintainer = "";
+    private String name = "";
+    
+    private String site = null; // used for gs3 colls
+    
+    public BasicCollectionConfiguration(File file) {
+	this.file = file;
+	try {
+	    String filename = file.getName().toLowerCase();
+	    if(!file.exists()) {
+		return;
+	    }
+	    if(filename.endsWith(".cfg")) {
+		FileInputStream fis = new FileInputStream(file);
+		InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
+		BufferedReader br = new BufferedReader(isr);
+		String command = null;
+		while((command = br.readLine()) != null) {
+		    if(command.length() > 0) {
+			// We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
+			while(command.trim().endsWith("\\")) {
+			    command = command.substring(0, command.lastIndexOf("\\"));
+			    String next_line = br.readLine();
+			    if (next_line != null) {
+				command = command + "\n" + next_line;
+			    }
+			    next_line = null;
+			}
+			CommandTokenizer tokenizer = new CommandTokenizer(command, br);
+			String command_type_str = tokenizer.nextToken();
+			if (command_type_str == null) {
+			    // Bad command. Do nothing
+			    continue;
+			}
+
+			command_type_str = command_type_str.toLowerCase();
+			if(command_type_str.equals(StaticStrings.COLLECTIONMETADATA_CREATOR_STR)) {
+			    creator = tokenizer.nextToken();
+			}
+			else if(command_type_str.equals(StaticStrings.COLLECTIONMETADATA_MAINTAINER_STR)) {
+			    maintainer = tokenizer.nextToken();
+			}
+			else if(command_type_str.equalsIgnoreCase(StaticStrings.COLLECTIONMETADATA_STR)) {
+			    String meta_type_str = tokenizer.nextToken();
+			    String value_str = tokenizer.nextToken();
+			    // check for language
+			    String language_str = StaticStrings.ENGLISH_LANGUAGE_STR; // assume the no-lang ones are english, but we shouldn't really do this.
+			    if(meta_type_str != null && value_str != null) {
+				meta_type_str = meta_type_str.toLowerCase();
+				if(value_str.startsWith(StaticStrings.LBRACKET_CHARACTER) && value_str.endsWith(StaticStrings.RBRACKET_CHARACTER)) {
+				    language_str = value_str.substring(value_str.indexOf(StaticStrings.EQUALS_CHARACTER) + 1, value_str.length() - 1);
+				    language_str = language_str.toLowerCase();
+				    value_str = tokenizer.nextToken();
+				}
+				// now we can work out which coll meta we are dealing with
+				if (meta_type_str.equals(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR)) {
+				    // If this is the first collection title found, then use it, otherwise search for one that more closely matches our choosen interface language
+				    if (name == null || language_str.equals(Dictionary.getLanguage())) {
+					name = Codec.transform(value_str, Codec.GREENSTONE_TO_TEXT);
+				    }
+				}
+				else if (meta_type_str.equals(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR)) {
+				    // Again we are either looking for the first description, then after that a language specific one
+				    if (description == null || language_str.equals(Dictionary.getLanguage())) {
+					description = Codec.transform(value_str, Codec.GREENSTONE_TO_TEXT);
+				    }
+				}
+			    }
+			    language_str = null;
+			    value_str = null;
+			    meta_type_str = null;
+			} else {
+			    // we want to process all the tokens to make sure we get rid of multi line commands before trying to find the next one
+			    while (tokenizer.hasMoreTokens()) {
+			    	tokenizer.nextToken();
+			    }
+
+			} // end of coll meta bit
+			command_type_str = null;
+			tokenizer = null;
+		    } // if command.length > 0
+		} // while
+		command = null;
+		br.close();
+		isr.close();
+		br = null;
+		isr = null;
+	    } // cfg file
+	    ///ystem.err.println("Parsed collect.cfg");
+	    ///ystem.err.println("name		= " + name);
+	    ///ystem.err.println("creator	 = " + creator);
+	    ///ystem.err.println("maintainer  = " + maintainer);
+	    ///ystem.err.println("description = " + description);
+	}
+	catch(Exception error) {
+	    DebugStream.println("Error in CollectionConfiguration.<init>(): " + error);
+	    DebugStream.printStackTrace(error);
+	}
+    }
+
+    /** Compare this configuration to another for ordering, which essentially compares two strings for ordering.
+     * @param other the other Object which is presumably another basic collection configuration
+     * @return an integer which is either <0, 0 or >0 if this configuration is naturally less than, equal to or greater than the target object
+     */
+    public int compareTo(Object other) {
+	if(other == null) {
+	    return -1;
+	}
+	return toString().compareTo(other.toString());
+    }
+
+    public boolean equals(Object other) {
+	return (compareTo(other) == 0);
+    }
+
+    /** Retrieve the creators email for this collection.
+     * @return a String
+     */
+    public String getCreator() {
+	return creator;
+    }
+
+    public String getDescription() {
+	return description;
+    }
+
+    public File getFile() {
+	return file;
+    }
+    
+    public String getMaintainer() {
+	return maintainer;
+    }
+
+    public String getName() {
+	return name;
+    }
+    
+    /** Retrieve the short name for this collection which, given this current file is in <col_name>/etc/collect.cfg, is the name of this file's parent file's parent.
+     * @return the short name of this collection as a String
+     */
+    public String getShortName() {
+	return file.getParentFile().getParentFile().getName();
+    }
+    
+    /** set the site for this coll */
+    public void setSite(String site) {
+	this.site = site;
+    }
+	
+    
+    /** Display the title for this collection. */
+    public String toString() {
+	if (this.site == null) {
+	    return getName() + StaticStrings.SPACE_CHARACTER + StaticStrings.OPEN_PARENTHESIS_CHARACTER + getShortName() + StaticStrings.CLOSE_PARENTHESIS_CHARACTER;
+	} else {
+	    return getName() + StaticStrings.SPACE_CHARACTER + StaticStrings.OPEN_PARENTHESIS_CHARACTER + getShortName()+", "+this.site + StaticStrings.CLOSE_PARENTHESIS_CHARACTER;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/Collection.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/Collection.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/Collection.java	(revision 10506)
@@ -0,0 +1,406 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.collection;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.cdm.CollectionDesignManager;
+import org.greenstone.gatherer.cdm.CollectionMeta;
+import org.greenstone.gatherer.cdm.CollectionMetaManager;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/** Collection provides a common collection point for all the information about a certain collection build session. It keeps a record of several other managers that actually handle the content of the collection, such as metadata sets and metadata itself.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3c
+ */
+public class Collection {
+    /** A reference to the Collection Design Manager. */
+    public CollectionDesignManager cdm;
+    /** A reference to the build ScriptOptions. */
+    public ScriptOptions build_options;
+    /** A reference to the import ScriptOptions. */
+    public ScriptOptions import_options;
+    /** true if an error has occurred during construction */
+    public boolean error = false;
+    /** <i>true</i> if the currently loaded collection has been saved since the last significant change, <i>false</i> otherwise. */
+    private boolean saved = false;
+    /*<i>true</i> if the currently loaded collection has had files added since its last build */
+    private boolean filesChanged = false;
+    /*<i>true</i> if the currently loaded collection has had metadata added since its last build */
+    private boolean metadataChanged = false;
+    /** The document around which this collection class is based. */
+    private Document document;
+    /** The file the collection is in (the file may not actually exist, such in the case of a legacy collection)! */
+    private File file;
+    /** The name of the argument element. */
+    static final private String ARGUMENT = "Argument";
+    static final private String BASE_COLLECTION = "base_collection";
+    /** The name of the build element. */
+    static final private String BUILD = "Build";
+    /** The name of the build config element. */
+    static final private String BUILD_CONFIG = "BuildConfig";
+    /** The name of the collection xml template. */
+    static final private String COLLECTION_XML_TEMPLATE = "xml/template.col";
+    /** The name of the import element. */
+    static final private String IMPORT = "Import";
+    /** The name of the imported attribute. */
+    static final private String IMPORTED = "imported";
+
+    /** Constructor. */
+    public Collection(File collection_xml) {
+	this.file = collection_xml;
+	// Try to load this collections details.
+	document = XMLTools.parseXMLFile(collection_xml);
+	// If that fails load the default settings for a collection.
+	if(document == null) {
+	    document = XMLTools.parseXMLFile(COLLECTION_XML_TEMPLATE, true);
+	}
+	if (document == null) {
+	    error = true;
+	    return;
+	}
+	// Point the Configuration class at our gatherer config arguments.
+	Configuration.setCollectionConfiguration(document);
+	if (Gatherer.g_man != null) {
+	    Gatherer.g_man.updateUI();
+	}
+	// Finally create all of the child managers that are directly dependant on a collection
+	build_options = new ScriptOptions(getBuildValues(), "buildcol.pl", true);
+	import_options = new ScriptOptions(getImportValues(), "import.pl", true);
+    }
+    
+    /** Destructor.
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.cdm.CollectionDesignManager
+     */
+    public void destroy() {
+	cdm.destroy();
+	Configuration.setCollectionConfiguration(null);
+	if (Gatherer.g_man != null) {
+	    Gatherer.g_man.updateUI();
+	}
+	cdm = null;
+	document = null;
+    }
+    
+    /** Determine the path to the base collection.
+     * @return the path as a String
+     */
+    public String getBaseCollection() {
+	return getString(BASE_COLLECTION);
+    }
+    
+    /** Determine the number of documents and folders in this collection. */
+    public int getCount() {
+	return getCount((TreeNode)Gatherer.c_man.getCollectionTreeModel().getRoot(), true, true);
+    }
+    
+    /** Calculates the number of documents in this collection. */
+    public int getDocumentCount() {
+	return getCount((TreeNode)Gatherer.c_man.getCollectionTreeModel().getRoot(), false, true);
+    }
+    
+    /** Retrieve the description of this collection.
+     * @return a String
+     */
+    public String getDescription() {
+	if(cdm == null) {
+	    return StaticStrings.EMPTY_STR;
+	}
+	CollectionMeta collection_extra_collectionmeta = cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
+	return collection_extra_collectionmeta.getValue(CollectionMeta.TEXT);
+    }
+    
+    /** Retrieve the authors email for this collection.
+     * @return The email as a <strong>String</strong>.
+     */
+    public String getEmail() {
+	if(cdm == null) {
+	    return StaticStrings.EMPTY_STR;
+	}
+	CollectionMeta creator_collectionmeta = new CollectionMeta(CollectionDesignManager.collect_config.getCreator());
+	return creator_collectionmeta.getValue(CollectionMeta.TEXT);
+    }
+
+    /** Retrieve the short name for this collection.
+     * @return The name as a <strong>String</strong>.
+     */
+    public String getName() {
+	return file.getParentFile().getName();
+    }
+    
+    /** Determine if this collection has been saved since the last major change.
+     * @return <i>true</i> if it has been saved recently, <i>false</i> otherwise.
+     */
+    public boolean getSaved() {
+	return saved;
+    }
+
+    /** Determine if this collection has had its collection files changed since the last build.
+     * @return <i>true</i> if they have been saved, <i>false</i> otherwise.
+     */
+    public boolean getFilesChanged() {
+	return filesChanged;
+    }
+    
+    /** Set the flag that marks weather or not the files has been changed since the last build.
+	@param changed if files has been added/removed, as a <strong>boolean</strong>
+    */
+    public void setFilesChanged(boolean changed) {
+	filesChanged = changed;
+    }
+
+    /** Determine if this collection has had metadata changed since the last build.
+     * @return <i>true</i> if it has been changed, <i>false</i> otherwise.
+     */
+    public boolean getMetadataChanged() {
+	return metadataChanged;
+    }
+    
+    /** Set the flag that marks weather or not the metadata has been changed since the last build.
+	@param changed if metadata has been added/changed/removed, as a <strong>boolean</strong>
+    */
+    public void setMetadataChanged(boolean changed) {
+	metadataChanged = changed;
+    }
+
+    /** Retrieve the title of this collection.
+     * @return The title as a <strong>String</strong>.
+     */
+    public String getTitle() {
+	if(cdm == null) {
+	    return StaticStrings.EMPTY_STR;
+	}
+	CollectionMeta collection_name_collectionmeta = cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
+	return collection_name_collectionmeta.getValue(CollectionMeta.TEXT);
+    }
+
+    /** Save this xml document to the given file. */
+    public void save() {
+	XMLTools.writeXMLFile(file, document);
+	saved = true;
+    }
+
+    public void setBaseCollection(String base_collection) {
+	set(BASE_COLLECTION, base_collection);
+    }
+    
+    /** Set the value of imported to the given value.
+     * @param value The new value for imported, <i>true</i> if the collection has been imported successfully, <i>false</i> otherwise.
+     */
+    public void setImported(boolean value) {
+	set(IMPORTED, value);
+	saved = false;
+    }
+
+    /** Set the value of saved to the given value.
+     * @param value The new value for saved, <i>true</i> if the collection has been saved recently, <i>false</i> otherwise.
+     */
+    public void setSaved(boolean value) {
+	saved = value;
+    }
+
+    /** Set the value of title to the given value.
+     * @param title The new <strong>String</strong> title.
+     */
+    public void setTitle(String title) {
+	if(cdm != null) {
+	    CollectionMeta collection_name_collectionmeta = cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
+	    collection_name_collectionmeta.setValue(title);
+	}
+    }
+
+    /** Method called to return a textual representation of a class, which in this case is the collections title.
+     * @return A <strong>String</strong> containing the collections title.
+     */
+    public String toString() {
+	return getTitle();
+    }
+    
+    /** Get the value of a collection argument. */
+    private boolean get(String name) {
+	boolean result = false;
+	try {
+	    Element document_element = document.getDocumentElement();
+	    NodeList arguments = document_element.getElementsByTagName(ARGUMENT);
+	    boolean found = false;
+	    for(int i = 0; !found && i < arguments.getLength(); i++) {
+		Element argument_element = (Element) arguments.item(i);
+		if(argument_element.getParentNode() == document_element) {
+		    if(argument_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equalsIgnoreCase(name)) {
+			String value = XMLTools.getValue(argument_element);
+			if(value.equalsIgnoreCase(StaticStrings.TRUE_STR)) {
+			    result = true;
+			}
+			found = true;
+			value = null;
+		    }
+		}
+		argument_element = null;
+	    }
+	    arguments = null;
+	    document_element = null;
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+	return result;
+    }
+    
+    /** Get the value of a collection argument. */
+    private String getString(String name) {
+	String result = "";
+	try {
+	    Element document_element = document.getDocumentElement();
+	    NodeList arguments = document_element.getElementsByTagName(ARGUMENT);
+	    boolean found = false;
+	    for(int i = 0; !found && i < arguments.getLength(); i++) {
+		Element argument_element = (Element) arguments.item(i);
+		if(argument_element.getParentNode() == document_element) {
+		    if(argument_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equalsIgnoreCase(name)) {
+			result = XMLTools.getValue(argument_element);
+			found = true;
+		    }
+		}
+		argument_element = null;
+	    }
+	    arguments = null;
+	    document_element = null;
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+	return result;
+    }
+    
+    /** Method to retrieve the current build options associated with this Collection. */
+    private Element getBuildValues() {
+	Element build_values_element = null;
+	try {
+	    Element document_element = document.getDocumentElement();
+	    Element build_config_element = (Element) XMLTools.getNodeFromNamed(document_element, BUILD_CONFIG);
+	    build_values_element = (Element) XMLTools.getNodeFromNamed(build_config_element, BUILD);
+	    build_config_element = null;
+	    document_element = null;
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+	return build_values_element;
+    }
+    
+    /** Count either documents or folders, depending on the state of the given boolean. */
+    private int getCount(TreeNode node, boolean count_folders, boolean count_files) {
+	int count = 0;
+	File file = ((CollectionTreeNode)node).getFile();
+	if(file.isFile() && count_files) {
+	    count++;
+	}
+	else if(file.isDirectory() && count_folders) {
+	    count++;
+	}
+	for(int i = 0; !file.getName().equals("CVS") && i < node.getChildCount(); i++) {
+	    count = count + getCount(node.getChildAt(i), count_folders, count_files);
+	}
+	return count;
+    }
+    
+    /** Method to retrieve the current import options associated with this Collection. */
+    public Element getImportValues() {
+	Element import_values_element = null;
+	try {
+	    Element document_element = document.getDocumentElement();
+	    Element build_config_element = (Element) XMLTools.getNodeFromNamed(document_element, BUILD_CONFIG);
+	    import_values_element = (Element) XMLTools.getNodeFromNamed(build_config_element, IMPORT);
+	    build_config_element = null;
+	    document_element = null;
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+	return import_values_element;
+    }
+    
+    /** Set the value of a collection argument. */
+    private void set(String name, boolean value) {
+	set(name, (value ? StaticStrings.TRUE_STR : StaticStrings.FALSE_STR));
+    }
+    
+    private void set(String name, String value) {
+	try {
+	    Element document_element = document.getDocumentElement();
+	    NodeList arguments = document_element.getElementsByTagName(ARGUMENT);
+	    boolean found = false;
+	    for(int i = 0; !found && i < arguments.getLength(); i++) {
+		Element argument_element = (Element) arguments.item(i);
+		if(argument_element.getParentNode() == document_element) {
+		    if(argument_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equalsIgnoreCase(name)) {
+			// Strip any current value nodes.
+			while(argument_element.hasChildNodes()) {
+			    argument_element.removeChild(argument_element.getFirstChild());
+			}
+			// Append new value
+			argument_element.appendChild(document.createTextNode(value));
+			found = true;
+		    }
+		}
+		argument_element = null;
+	    }
+	    // Append it
+	    if(!found) {
+		Element argument_element = document.createElement(ARGUMENT);
+		argument_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, name);
+		argument_element.appendChild(document.createTextNode(value));
+		document_element.appendChild(argument_element);
+		argument_element = null;
+	    }
+	    arguments = null;
+	    document_element = null;
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionContentsChangedListener.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionContentsChangedListener.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionContentsChangedListener.java	(revision 10506)
@@ -0,0 +1,37 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.collection;
+
+
+import java.io.File;
+
+
+public interface CollectionContentsChangedListener
+{
+    /** Notification that a new file has been added to the collection. */
+    public void fileAddedToCollection(File file);
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionManager.java	(revision 10506)
@@ -0,0 +1,1503 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.collection;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.filechooser.FileSystemView;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.LocalGreenstone;
+import org.greenstone.gatherer.LocalLibraryServer;
+import org.greenstone.gatherer.ServletConfiguration;
+import org.greenstone.gatherer.cdm.CollectionDesignManager;
+import org.greenstone.gatherer.cdm.CollectionMeta;
+import org.greenstone.gatherer.cdm.CollectionMetaManager;
+import org.greenstone.gatherer.cdm.CommandTokenizer;
+import org.greenstone.gatherer.gui.ExternalCollectionPrompt;
+import org.greenstone.gatherer.gui.LockFileDialog;
+import org.greenstone.gatherer.gui.ModalProgressPopup;
+import org.greenstone.gatherer.gui.NewCollectionMetadataPrompt;
+import org.greenstone.gatherer.gui.WarningDialog;
+import org.greenstone.gatherer.metadata.DocXMLFileManager;
+import org.greenstone.gatherer.metadata.MetadataChangedListener;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
+import org.greenstone.gatherer.metadata.ProfileXMLFileManager;
+import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
+import org.greenstone.gatherer.shell.GShell;
+import org.greenstone.gatherer.shell.GShellEvent;
+import org.greenstone.gatherer.shell.GShellListener;
+import org.greenstone.gatherer.shell.GShellProgressMonitor;
+import org.greenstone.gatherer.util.Codec;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/** This class manages many aspects of the collection, from its creation via scripts, data access via methods and its importing and building into the final collection. It is also resposible for firing appropriate event when significant changes have occured within the collection, and for creating a new metadata set manager as necessary.
+ * @author John Thompson
+ * @version 2.3
+ */
+public class CollectionManager
+    implements GShellListener, MetadataChangedListener
+{
+    /** Are we currently in the process of building? */
+    private boolean building = false;
+    /** Are we currently in the process of importing? */
+    private boolean importing = false;
+    /** The objects listening for CollectionContentsChanged events. */
+    private ArrayList collection_contents_changed_listeners = new ArrayList();
+    /** The collection this manager is managing! */
+    static private Collection collection = null;
+    /** The collection_model. */
+    private CollectionTreeModel collection_model = null;
+    /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
+    private FMTreeModelListener fm_tree_model_listener = null;
+    /** The monitor resposible for parsing the build process. */
+    private GShellProgressMonitor build_monitor = null;
+    /** The monitor resposible for parsing the import process. */
+    private GShellProgressMonitor import_monitor = null;
+
+    /** The name of the standard lock file. */
+    static final public String LOCK_FILE = "gli.lck";
+
+    /** Used to indicate the source of the message is the file collection methods. */
+    static final public int COLLECT   = 3;
+    /** Used to indicate the source of the message is the building methods. */
+    static final public int BUILDING  = 5;
+
+    /** Constructor. */
+    public CollectionManager() {
+	// Initialisation.
+	this.building = false;
+	this.importing = false;
+	this.collection = null;
+
+	MetadataXMLFileManager.addMetadataChangedListener(this);
+
+	// If using a remote Greenstone server, download the collection configurations
+	if (Gatherer.isGsdlRemote) {
+	    RemoteGreenstoneServer.downloadCollectionConfigurations();
+	}
+    }
+
+
+    public void addCollectionContentsChangedListener(CollectionContentsChangedListener listener)
+    {
+	collection_contents_changed_listeners.add(listener);
+    }
+
+
+    /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.Collection
+     * @see org.greenstone.gatherer.gui.BuildOptions
+     * @see org.greenstone.gatherer.shell.GShell
+     * @see org.greenstone.gatherer.shell.GShellListener
+     * @see org.greenstone.gatherer.shell.GShellProgressMonitor
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    public void buildCollection(boolean incremental_build)
+    {
+	DebugStream.println("In CollectionManager.buildCollection(), incremental_build: " + incremental_build);
+	building = true;
+
+	// Generate the buildcol.pl command
+	ArrayList command_parts_list = new ArrayList();
+	if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
+	    command_parts_list.add(Configuration.perl_path);
+	    command_parts_list.add("-S");
+	}
+	command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "buildcol.pl");
+	command_parts_list.add("-gli");
+	command_parts_list.add("-language");
+	command_parts_list.add(Configuration.getLanguage());
+	command_parts_list.add("-collectdir");
+	command_parts_list.add(getCollectDirectory());
+
+	// If the user hasn't manually specified "-keepold" or "-removeold" then pick one based on incremental_build
+	if (!collection.build_options.getValueEnabled("keepold") && !collection.build_options.getValueEnabled("removeold")) {
+	    command_parts_list.add(incremental_build ? "-keepold" : "-removeold");
+	}
+
+	String[] build_options = collection.build_options.getValues();
+	for (int i = 0; i < build_options.length; i++) {
+	    command_parts_list.add(build_options[i]);
+	}
+
+	command_parts_list.add(collection.getName());
+
+	// Run the buildcol.pl command
+	String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
+	GShell shell = new GShell(command_parts, GShell.BUILD, BUILDING, this, build_monitor, GShell.GSHELL_BUILD);
+	shell.addGShellListener(Gatherer.g_man.create_pane);
+	shell.start();
+	DebugStream.println("CollectionManager.buildCollection().return");
+    }
+
+
+    /** Used to determine whether the currently active collection has been built.
+     * @return A boolean indicating the built status of the collection.
+     */
+    public boolean built() {
+	if(collection != null) {
+	    // Determine if the collection has been built by looking for the build.cfg file
+	    File build_cfg_file = new File(getCollectionIndexDirectoryPath() + "build.cfg");
+	    return build_cfg_file.exists();
+	}
+	return false;
+    }
+
+    /** a test method to see if we can delete a directory/file - returns false is the file or any of the contents of a directory cannot be deleted */
+    public boolean canDelete(File file) {
+	if (!file.isDirectory()) {
+	    return file.canWrite();
+	}
+	File [] file_list = file.listFiles();
+	for (int i=0; i<file_list.length; i++) {
+	    if (!canDelete(file_list[i])) {
+		return false;
+	    }
+	}
+	return true;
+    }
+    /** Called to close the current collection and remove its lock file.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.Collection
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    public void closeCollection() {
+	DebugStream.println("Close collection: " + collection.getName());
+
+	// Remove the lock on this file, then remove the collection.
+	String collection_directory_path = getCollectionDirectoryPath(collection.getName());
+	File lock_file = new File(collection_directory_path + LOCK_FILE);
+	lock_file.delete();
+	if (lock_file.exists()) {
+	    System.err.println("Warning: Lockfile was not successfully deleted.");
+	}
+
+	MetadataSetManager.clearMetadataSets();
+	MetadataXMLFileManager.clearMetadataXMLFiles();
+	DocXMLFileManager.clearDocXMLFiles();
+	ProfileXMLFileManager.clearProfileXMLFile();
+
+	collection = null;
+	collection_model = null;
+	Configuration.setCollectionConfiguration(null);
+	Gatherer.refresh(Gatherer.COLLECTION_CLOSED);
+	if (Gatherer.g_man != null) {
+	    Gatherer.g_man.updateUI();  // !!! Necessary?
+	}
+    }
+
+    /** Method that is called whenever something has changed in the configuration of this collection. */
+    public void configurationChanged() {
+	if(collection != null) {
+	    collection.setSaved(false);
+	}
+    }
+
+    public void convertToGS3Collection() {
+	// Generate the convert_coll_from_gs2.pl command
+	ArrayList command_parts_list = new ArrayList();
+	if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
+	    command_parts_list.add(Configuration.perl_path);
+	    command_parts_list.add("-S");
+	}
+	command_parts_list.add(Configuration.getGS3ScriptPath() + "convert_coll_from_gs2.pl");
+	command_parts_list.add("-collectdir");
+	command_parts_list.add(getCollectDirectory());
+    	command_parts_list.add(collection.getName());
+
+	// Run the convert_coll_from_gs2.pl command
+	String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
+	GShell process = new GShell(command_parts, GShell.CONVERT, COLLECT, this, null, GShell.GSHELL_CONVERT);
+	process.addGShellListener(this);
+	process.run(); // Don't bother threading this... yet
+       
+    }
+
+    /** When basing a new collection on an existing one, we need to copy 
+     *	over some extra directories: images and macros  
+     */
+    private boolean copyExtraBaseCollStuff(File new_coll_dir, File base_coll_dir) {
+	if (!new_coll_dir.isDirectory() || !base_coll_dir.isDirectory()) {
+	    return false;
+	}
+	DebugStream.println("Copying images and macros dirs from the base collection");
+	try {
+	    // do the images dir
+	    File base_coll_images = new File(base_coll_dir, "images");
+	    if (base_coll_images.isDirectory()) {
+		// copy all the images over
+		File new_coll_images = new File(new_coll_dir, "images");
+		new_coll_images.mkdirs();
+		
+		// copy the contents over
+		Gatherer.f_man.getQueue().copyDirectoryContents(base_coll_images, new_coll_images, null);
+	    }
+	}
+	catch (Exception e) {
+	    DebugStream.println("Couldn't copy over the images dir from the base collection: "+e.toString());
+	}
+	try {
+	    // do the macros dir
+	    File base_coll_macros = new File(base_coll_dir, Utility.MACROS_DIR);
+	    if (base_coll_macros.isDirectory()) {
+		// copy all the macros over
+		File new_coll_macros = new File(new_coll_dir, Utility.MACROS_DIR);
+		new_coll_macros.mkdirs();
+		
+		// copy the contents over
+		Gatherer.f_man.getQueue().copyDirectoryContents(base_coll_macros, new_coll_macros, null);
+	    } 
+	}
+	catch (Exception e) {
+	    DebugStream.println("Couldn't copy over the macros dir from the base collection: "+e.toString());
+	}
+	return true;
+    }
+
+    /** Used to set the current collection to the given collection. Note that this call should -always- be proceeded by a ready call, and if the colection is ready and the saved flag is unset then the user should be prompted to save. Also note that this method creates yet another GShell to run buildcol.pl.
+     * @param description a description of the collection as a String
+     * @param email the email address of the author/maintainer as a String
+     * @param name the short name of the collection, which will subsequently be used to refer to this particular collection, as a String
+     * @param title the longer title of the collection as a String
+     * @param base_collection_directory if the user has chosen to base their new collection on an existing one, this is the directory where this base collection can be found, as a File, otherwise its null
+     * @param metadata_sets if the user has decided to select several metadata sets with which to initially populate the GLI then this is an ArrayList of metadata set file names, otherwise its null
+     */
+    public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
+    {
+	try {
+	    // first make sure that the collect directory exists
+	    File collect_dir = new File(getCollectDirectory());
+	    if (!collect_dir.exists()) {
+		collect_dir.mkdirs();
+	    }
+
+	    // Create a progress monitor
+	    ProgressMonitor progress = new ProgressMonitor(Gatherer.g_man, Dictionary.get("CollectionManager.Creating_New"), "mkcol.pl", 0, 4);
+
+	    // Create the new collection.
+	    makeCollection(name, email);
+	    progress.setProgress(1);
+	    
+	    // *******************
+	    //check that this creation has worked - simply by checking for the existence of the collect.cfg file
+	    String collection_directory_path = getCollectionDirectoryPath(name);
+	    File collect_cfg_file = new File(collection_directory_path + "etc" + File.separator + "collect.cfg");
+	    if (!collect_cfg_file.exists()) {
+		// no point continuing
+		System.err.println("Error: no collect.cfg file has been created!");
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Create_Collection_With_Reason", Dictionary.get("CollectionManager.No_Config_File")), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE); 
+		progress.close();
+		return;
+	    }
+ 	    
+	    // ACTIVE_DIR/log/
+	    File log_dir = new File(collection_directory_path + "log");
+	    log_dir.mkdirs();
+	    progress.setNote(Dictionary.get("CollectionManager.Log_Created"));
+
+	    // Make sure an import folder exists
+	    File import_directory = new File(collection_directory_path + "import");
+	    if (!import_directory.exists()) {
+		import_directory.mkdirs();
+	    }
+
+	    progress.setProgress(2);
+
+	    // Now create the collection object around the directory.
+	    collection = new Collection(new File(collection_directory_path, name + ".col"));
+
+	    // "-removeold" is on by default for import.pl
+	    collection.import_options.setValue("removeold", true, null);
+
+	    MetadataSetManager.clearMetadataSets();
+	    MetadataXMLFileManager.clearMetadataXMLFiles();
+	    DocXMLFileManager.clearDocXMLFiles();
+
+	    // Import default metadata sets, if any
+	    for (int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
+		importMetadataSet((MetadataSet) metadata_sets.get(i));
+	    }
+
+	    ProfileXMLFileManager.loadProfileXMLFile(new File(collection_directory_path + "metadata"));
+
+	    // Before creating the CollectionDesignManager check if we are basing it upon some other collection
+	    if (base_collection_directory != null) {
+		DebugStream.println("Basing new collection on existing one: " + base_collection_directory);
+
+		// If we're using a remote Greenstone server, download the collection shell to get the files needed
+		if (Gatherer.isGsdlRemote) {
+		    String base_collection_name = base_collection_directory.getName();
+		    RemoteGreenstoneServer.downloadCollection(base_collection_name);
+		}
+
+		collection.setBaseCollection(base_collection_directory.getAbsolutePath());
+		// copy over other needed directories
+		copyExtraBaseCollStuff(new File(collection_directory_path), base_collection_directory);
+
+		// Try to import any existing metadata sets for this collection
+		// Look in base_collection_directory/metadata and import any metadata sets found.
+		File base_metadata_directory = new File(base_collection_directory, "metadata");
+		ArrayList base_metadata_sets = MetadataSetManager.listMetadataSets(base_metadata_directory);
+		if (base_metadata_sets != null) {
+		    for (int i = 0; i < base_metadata_sets.size(); i++) {
+			importMetadataSet((MetadataSet) base_metadata_sets.get(i));
+		    }
+		}
+		else {
+		    DebugStream.println("This base collection has no metadata directory.");
+		}
+
+		// If no sets were imported...
+		if (MetadataSetManager.getMetadataSets().size() == 0) {
+		    // Prompt the user so that they can choose at least one initial metadata set. We're sneaky here and just create a ncm_prompt
+		    DebugStream.println("This collection has no metadata sets. Present the user with the metadata set selection prompt.");
+		    NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt();
+		    // If cancelled then they really do mean to start a collection with no metadata sets.
+		    if (!ncm_prompt.isCancelled()) {
+			ArrayList initial_sets = ncm_prompt.getSets();
+			for (int i = 0; initial_sets != null && i < initial_sets.size(); i++) {
+			    importMetadataSet((MetadataSet) initial_sets.get(i));
+			}
+		    }
+		    ncm_prompt.dispose();
+		    ncm_prompt = null;
+		}
+
+		// Now we update our collect.cfg
+		DebugStream.println("Copy and update collect.cfg from base collection.");
+		updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_FILE), new File(collection_directory_path, Utility.CONFIG_FILE), description, email, title);
+	    }
+
+	    // Always import the extracted metadata set if we didn't already
+	    if (MetadataSetManager.getMetadataSet(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE) == null) {
+		File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
+		importMetadataSet(new MetadataSet(extracted_metadata_set_file));
+	    }
+
+	    collection.cdm = new CollectionDesignManager(new File(getCollectionConfigFilePath()));
+
+	    // We always set title and description here rather than calling mkcol.pl with Unicode arguments
+	    CollectionMeta collection_name_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
+	    collection_name_collectionmeta.setValue(title);
+	    CollectionMeta collection_extra_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
+	    collection_extra_collectionmeta.setValue(description);
+
+	    // Now that we have a CDM, update several settings, such as if we created this collection by basing it on another, set it as public automatically
+	    if (base_collection_directory != null) {
+		// Update the creator and maintainer
+		CollectionMeta creator_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getCreator());
+		creator_collectionmeta.setValue(email);
+		creator_collectionmeta = null;
+		CollectionMeta maintainer_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getMaintainer());
+		maintainer_collectionmeta.setValue(email);
+		maintainer_collectionmeta = null;
+
+		// All collections based on others are automatically public
+		CollectionMeta public_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getPublic());
+		public_collectionmeta.setValue(StaticStrings.TRUE_STR);
+		public_collectionmeta = null;
+
+		// Finally reset the icons
+		CollectionMeta icon_collection_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR);
+		icon_collection_collectionmeta.setValue(StaticStrings.EMPTY_STR);
+		icon_collection_collectionmeta = null;
+		CollectionMeta icon_collection_small_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
+		icon_collection_small_collectionmeta.setValue(StaticStrings.EMPTY_STR);
+		icon_collection_small_collectionmeta = null;
+	    }
+
+	    collection.cdm.save();
+	    progress.setProgress(3);
+
+	    // Create a lock file
+	    createLockFile(new File(collection_directory_path, LOCK_FILE));
+
+	    progress.setProgress(4);
+	    progress.setNote(Dictionary.get("CollectionManager.Session_Ready", name));
+	    progress.close();
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+    }
+
+
+    private void createLockFile(File lock_file)
+    {
+	try {
+	    Document default_lockfile = XMLTools.parseXMLFile("xml/" + LOCK_FILE, true);
+	    String user_name = System.getProperty("user.name");
+	    Element person_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "User");
+	    person_element.appendChild(default_lockfile.createTextNode(user_name));
+	    person_element = null;
+	    user_name = null;
+	    String machine_name = Utility.getMachineName();
+	    Element machine_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Machine");
+	    machine_element.appendChild(default_lockfile.createTextNode(machine_name));
+	    machine_element = null;
+	    machine_name = null;
+	    String date_time = Utility.getDateString();
+	    Element date_element = (Element) XMLTools.getNodeFromNamed(default_lockfile.getDocumentElement(), "Date");
+	    date_element.appendChild(default_lockfile.createTextNode(date_time));
+	    date_element = null;
+	    date_time = null;
+	    XMLTools.writeXMLFile(lock_file, default_lockfile);
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+
+
+    public boolean deleteCollection(String collection_name)
+    {
+	return Utility.delete(new File(getCollectionDirectoryPath(collection_name)));
+    }
+
+
+    public void fireFileAddedToCollection(File file)
+    {
+	// Send the event off to all the CollectionContentsChangedListeners
+	for (int i = 0; i < collection_contents_changed_listeners.size(); i++) {
+	    ((CollectionContentsChangedListener) collection_contents_changed_listeners.get(i)).fileAddedToCollection(file);
+	}
+    }
+
+
+    /** Retrieve the current collection.
+     * @return The <strong>Collection</strong> itself.
+     */
+    public Collection getCollection() {
+	return collection;
+    }
+
+
+    /** Constructs the absolute filename of the collection's directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;"
+     * @return A <strong>String</strong> containing the directory name.
+     */
+    static public String getCollectionDirectoryPath(String collection_name)
+    {
+	return Gatherer.getCollectDirectoryPath() + collection_name + File.separator;
+    }
+
+
+    /** Constructs the absolute filename of the collection's .col file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/&lt;col_name&gt;.col"
+     * @return A <strong>String</strong> containing the filename.
+     */
+    public String getCollectionFilePath()
+    {
+	return getCollectionDirectoryPath(collection.getName()) + collection.getName() + ".col";
+    }
+
+
+    /** Constructs the absolute filename of the collection's archives directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/archives/"
+     * @return A <strong>String</strong> containing the filename.
+     */
+    public String getCollectionArchivesDirectoryPath()
+    {
+	return getCollectionDirectoryPath(collection.getName()) + "archives" + File.separator;
+    }
+
+
+    /** Constructs the absolute filename of the collection's building directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/building/"
+     * @return A <strong>String</strong> containing the filename.
+     */
+    public String getCollectionBuildingDirectoryPath()
+    {
+	return getCollectionDirectoryPath(collection.getName()) + "building" + File.separator;
+    }
+
+
+    /** Constructs the absolute filename of the collection's collect.cfg file, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/collect.cfg"
+     * @return A <strong>String</strong> containing the filename.
+     */
+    public String getCollectionConfigFilePath()
+    {
+	return getCollectionEtcDirectoryPath() + "collect.cfg";
+    }
+
+
+    /** Constructs the absolute filename of the collection's etc directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/etc/"
+     * @return A <strong>String</strong> containing the filename.
+     */
+    public String getCollectionEtcDirectoryPath()
+    {
+	return getCollectionDirectoryPath(collection.getName()) + "etc" + File.separator;
+    }
+
+
+    /** Constructs the absolute filename of the collection's images directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/images/"
+     * @return A <strong>String</strong> containing the filename.
+     */
+    public String getCollectionImagesDirectoryPath()
+    {
+	return getCollectionDirectoryPath(collection.getName()) + "images" + File.separator;
+    }
+
+
+    /** Constructs the absolute filename of the collection's import directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/import/"
+     * @return A <strong>String</strong> containing the filename.
+     */
+    public String getCollectionImportDirectoryPath()
+    {
+	return getCollectionDirectoryPath(collection.getName()) + "import" + File.separator;
+    }
+
+
+    /** Constructs the absolute filename of the collection's index directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/index/"
+     * @return A <strong>String</strong> containing the filename.
+     */
+    public String getCollectionIndexDirectoryPath()
+    {
+	return getCollectionDirectoryPath(collection.getName()) + "index" + File.separator;
+    }
+
+
+    /** Constructs the absolute filename of the collection's log directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/log/"
+     * @return A <strong>String</strong> containing the filename.
+     */
+    public String getCollectionLogDirectoryPath()
+    {
+	return getCollectionDirectoryPath(collection.getName()) + "log" + File.separator;
+    }
+
+
+    /** Constructs the absolute filename of the collection's metadata directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/metadata/"
+     * @return A <strong>String</strong> containing the filename.
+     */
+    public String getCollectionMetadataDirectoryPath()
+    {
+	return getCollectionDirectoryPath(collection.getName()) + "metadata" + File.separator;
+    }
+
+
+    /** Retrieve the tree model associated with the current collection. */
+    public CollectionTreeModel getCollectionTreeModel()
+    {
+	if (collection_model == null && collection != null) {
+	    // Use the import directory to generate a new CollectionTreeModel
+	    collection_model = new CollectionTreeModel(new CollectionTreeNode(new File(getCollectionImportDirectoryPath())));
+	    // Ensure that the manager is a change listener for the tree.
+	    if (fm_tree_model_listener == null) {
+		fm_tree_model_listener = new FMTreeModelListener();
+	    }
+	    collection_model.addTreeModelListener(fm_tree_model_listener);
+	}
+	return collection_model;
+    }
+
+
+    /** This method when called, creates a new GShell in order to run the import.pl script.
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.gui.BuildOptions
+     * @see org.greenstone.gatherer.shell.GShell
+     * @see org.greenstone.gatherer.shell.GShellListener
+     * @see org.greenstone.gatherer.shell.GShellProgressMonitor
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    public void importCollection() {
+	importing = true;
+
+	if (!saved()) {
+	    DebugStream.println("CollectionManager.importCollection().forcesave");
+	    import_monitor.saving();
+	    saveCollection();
+	}
+
+	DebugStream.println("CollectionManager.importCollection()");
+	//check that we can remove the old index before starting import
+	File index_dir = new File(getCollectionIndexDirectoryPath());
+	if (index_dir.exists()) {
+	    DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
+	    if (!canDelete(index_dir)) {
+		// tell the user
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE); 
+		// tell the gui manager
+		// a message for the building log 
+		GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
+		Gatherer.g_man.create_pane.message(event);
+		event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
+		Gatherer.g_man.create_pane.processComplete(event);
+		importing = false;
+		return;
+	    }
+	}
+
+	// Generate the import.pl command
+	ArrayList command_parts_list = new ArrayList();
+	if ((Utility.isWindows()) && (!Gatherer.isGsdlRemote)) {
+	    command_parts_list.add(Configuration.perl_path);
+	    command_parts_list.add("-S");
+	}
+	command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "import.pl");
+	command_parts_list.add("-gli");
+	command_parts_list.add("-language");
+	command_parts_list.add(Configuration.getLanguage());
+	command_parts_list.add("-collectdir");
+	command_parts_list.add(getCollectDirectory());
+
+	String[] import_options = collection.import_options.getValues();
+	for (int i = 0; i < import_options.length; i++) {
+	    command_parts_list.add(import_options[i]);
+	}
+
+	command_parts_list.add(collection.getName());
+
+	// Run the import.pl command
+	String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
+	GShell shell = new GShell(command_parts, GShell.IMPORT, BUILDING, this, import_monitor, GShell.GSHELL_IMPORT);
+	shell.addGShellListener(Gatherer.g_man.create_pane);
+	shell.start();
+	DebugStream.println("CollectionManager.importCollection().return");
+
+	importing = false;
+    }
+
+
+    public void importMetadataSet(MetadataSet external_metadata_set)
+    {
+	// Copy the .mds file into the collection's "metadata" folder...
+	File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
+
+	// ...but not if it is the redundant "hidden.mds" file
+	if (external_metadata_set_file.getName().equals("hidden.mds")) {
+	    return;
+	}
+
+	// ...and only if it doesn't already exist
+	File metadata_set_file = new File(getCollectionMetadataDirectoryPath(), external_metadata_set_file.getName());
+	if (!metadata_set_file.exists()) {
+	    try {
+		Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, null);
+
+		// If we're using a remote Greenstone server, upload the metadata file
+		if (Gatherer.isGsdlRemote) {
+		    RemoteGreenstoneServer.uploadCollectionFile(metadata_set_file);
+		}
+	    }
+	    catch (Exception ex) {
+		ex.printStackTrace();
+	    }
+
+	    // Load it into the MetadataSetManager
+	    MetadataSetManager.loadMetadataSet(metadata_set_file);
+	}
+    }
+
+
+    /** Determine if we are currently in the middle of importing (and thus, in this case, we can't allow the log writer to exit). Boy was this a mission to track down. The cascade of crap rolls out something like this: Joe Schmo clicks 'Build Collection', which calls the importCollection() method above, which in turn saves the collection with a saveTask, which fires a collectionChanged message once its finished, which drives the list of logs shown on the create pane to update, which fires a itemChanged() event to the OptionsPane who dutifully tells the current log writer thread to finish up writing (all zero lines its been asked to write) and then die. Wereapon Joe Schmo gets a pretty log to look at, but it isn't actually being written to file so the next time he tries to view it faeces hits the air motion cooling device. Joy.
+     * @return true if the gli is currently importing
+     */
+    public boolean isImporting() {
+	return importing;
+    }
+
+
+    public void loadCollection(String collection_file_path)
+    {
+	// Display a modal progress popup to indicate that the collection is being loaded
+	ModalProgressPopup load_collection_progress_popup = new ModalProgressPopup(Dictionary.get("CollectionManager.Loading_Collection"), Dictionary.get("CollectionManager.Loading_Collection_Please_Wait"));
+	load_collection_progress_popup.display();
+
+	// Load the collection on a separate thread so the progress bar updates correctly
+	(new LoadCollectionTask(collection_file_path, load_collection_progress_popup)).start();
+    }
+
+
+    private class LoadCollectionTask
+	extends Thread
+    {
+	private String collection_file_path = null;
+	private ModalProgressPopup load_collection_progress_popup = null;
+
+	public LoadCollectionTask(String collection_file_path, ModalProgressPopup load_collection_progress_popup)
+	{
+	    this.collection_file_path = collection_file_path;
+	    this.load_collection_progress_popup = load_collection_progress_popup;
+	}
+
+	public void run()
+	{
+	    loadCollectionInternal(collection_file_path);
+	    load_collection_progress_popup.close();
+	}
+    }
+
+
+    /** Attempts to load the given collection. Currently uses simple serialization of the collection class.
+     * @param location The path to the collection as a <strong>String</strong>.
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.Collection
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    private void loadCollectionInternal(String location)
+    {
+	DebugStream.println("Loading collection " + location + "...");
+
+	if (Gatherer.isGsdlRemote) {
+	    String collection_name = location.substring(location.lastIndexOf(File.separator) + 1, location.length() - ".col".length());
+	    RemoteGreenstoneServer.downloadCollection(collection_name);
+	}
+
+	boolean non_gli_collection = false;
+
+	// Check we have actually been given a .col file.
+	if (!location.endsWith(".col")) {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	    DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
+	    return;
+	}
+
+	// Check that the collection configuration file is available
+	File collection_file = new File(location);
+
+	// Ensure that the directory exists
+	File collection_directory = collection_file.getParentFile();
+	if (collection_directory == null || !collection_directory.exists()) {
+	    // We can't open this
+	    System.err.println("CollectionManager.loadCollection: No collection directory.");
+	    return;
+	}
+
+	File collection_config_file = new File(collection_directory, Utility.CONFIG_FILE);
+	if (!collection_config_file.exists()) {
+	    System.err.println("CollectionManager.loadCollection: No config file.");
+	    collection_directory = null;
+	    collection_config_file = null;
+	    return;
+	}
+
+	// Ensure that an import directory exists for this collection
+	File collection_import_directory = new File(collection_directory, Utility.IMPORT_DIR);
+	if (!collection_import_directory.exists()) {
+	    collection_import_directory.mkdir();
+	}
+
+	// Special case of a user trying to open an old greenstone collection.
+	File collection_metadata_directory = new File(collection_directory, Utility.META_DIR);
+	if (!collection_metadata_directory.exists()) {
+	    DebugStream.println("Loading non-gatherer collection...");
+	    non_gli_collection = true;
+	}
+
+	// Now determine if a lock already exists on this collection.
+	String name = collection_directory.getName();
+	File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
+	if (lock_file.exists()) {
+	    LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, name, lock_file);
+	    int choice = dialog.getChoice();
+	    dialog.dispose();
+	    dialog = null;
+
+	    if (choice != LockFileDialog.YES_OPTION) {
+		// user has cancelled
+		lock_file = null;
+		collection_directory = null;
+		collection_config_file = null;
+		return;
+	    }
+
+	    lock_file.delete();
+	}
+
+	try {
+	    // Create a lock file.
+	    createLockFile(lock_file);
+	    // This lock file may not have been created so check
+	    if(!lock_file.canWrite()) {
+		// The lock file cannot be written to. Most likely cause incorrect file permissions.
+		System.err.println("Cannot write lock file!");
+		String args[] = new String[2];
+		args[0] = location;
+		args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Title");
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		args = null;
+		return;
+	    }
+
+	    // Open the collection file
+	    this.collection = new Collection(collection_file);
+	    if (collection.error) {
+		collection = null;
+		// Remove lock file
+		if (lock_file.exists()) {
+		    lock_file.delete();
+		}
+		throw(new Exception(Dictionary.get("CollectionManager.Missing_Config"))); // this error message does not agree with the error
+	    }
+
+	    MetadataSetManager.clearMetadataSets();
+	    MetadataSetManager.loadMetadataSets(collection_metadata_directory);
+
+	    ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
+ 
+	    // If this is a non-GLI (legacy) collection, ask the user to choose some metadata sets
+	    if (non_gli_collection) {
+		if (!addSomeMetadataSets(collection_directory)) {
+		    lock_file = null;
+		    collection_directory = null;
+		    closeCollection();
+		    return;
+		}
+
+		// Recurse the import folder tree, backing up the metadata.xml files before they are edited
+		LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
+	    }
+
+	    // Read through the metadata.xml files in the import directory, building up the metadata value trees
+	    MetadataXMLFileManager.clearMetadataXMLFiles();
+	    MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory);
+
+	    // Read through the doc.xml files in the archives directory
+	    File collection_archives_directory = new File(getCollectionArchivesDirectoryPath());
+	    DocXMLFileManager.clearDocXMLFiles();
+	    DocXMLFileManager.loadDocXMLFiles(collection_archives_directory);
+
+	    collection.cdm = new CollectionDesignManager(collection_config_file);
+	    if (non_gli_collection) {
+		// Change the classifiers to use the namespaced element names
+		LegacyCollectionImporter.updateClassifiers(collection.cdm);
+	    }
+
+	    // We're done. Let everyone know.
+	    DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", name));
+	    Gatherer.refresh(Gatherer.COLLECTION_OPENED);
+	}
+	catch (Exception error) {
+	    // There is obviously no existing collection present.
+	    DebugStream.printStackTrace(error);
+	    if(error.getMessage() != null) {
+		String[] args = new String[2];
+		args[0] = location;
+		args[1] = error.getMessage();
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	    }
+	    else {
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	    }
+	}
+
+	lock_file = null;
+	collection_directory = null;
+	collection_config_file = null;
+    }
+
+
+    private void makeCollection(String name, String email)
+    {
+	// Generate the mkcol.pl command
+	ArrayList command_parts_list = new ArrayList();
+	if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
+	    command_parts_list.add(Configuration.perl_path);
+	    command_parts_list.add("-S");
+	}
+	command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "mkcol.pl");
+
+	command_parts_list.add("-collectdir");
+	command_parts_list.add(getCollectDirectory());
+	command_parts_list.add("-win31compat");
+	command_parts_list.add((Gatherer.isGsdlRemote) ? "false" : "true");
+
+	if (email != null && !email.equals("")) {
+	    command_parts_list.add("-creator");
+	    command_parts_list.add(email);
+	}
+
+	command_parts_list.add(name);
+
+	// Run the mkcol.pl command
+	String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
+	GShell process = new GShell(command_parts, GShell.NEW, COLLECT, this, null, GShell.GSHELL_NEW);
+	process.run(); // Don't bother threading this... yet
+    }
+
+
+    /** Any implementation of GShellListener must include this method to allow the GShell to send messages to listeners. However in this case the CollectionManager is in no way interested in what the messages are, just the import events which have a specific type and are handled elsewhere. Thus we can safely ignore this event.
+     * @param event A <strong>GShellEvent</strong> which contains a the message.
+     */
+    public synchronized void message(GShellEvent event) {
+    }
+
+
+    public void metadataChanged(CollectionTreeNode[] file_nodes)
+    {
+	if (collection != null) {
+	    collection.setMetadataChanged(true);
+	}
+    }
+
+
+    /** This call is fired whenever a process within a GShell created by this class begins.
+     * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.gui.GUIManager
+     * @see org.greenstone.gatherer.shell.GShell
+     */
+    public synchronized void processBegun(GShellEvent event) {
+	DebugStream.println("CollectionManager.processBegun(" + event.getType() + ")");
+	///ystem.err.println("ProcessBegun " + event.getType());
+	// If this is one of the types where we wish to lock user control
+	Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), true);
+    }
+    /** This call is fired whenever a process within a GShell created by this class ends.
+     * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.gui.GUIManager
+     * @see org.greenstone.gatherer.shell.GShell
+     */
+    public synchronized void processComplete(GShellEvent event) {
+	DebugStream.println("CollectionManager.processComplete(" + event.getType() + ")");
+	Gatherer.g_man.lockCollection((event.getType() == GShell.IMPORT), false);
+	///ystem.err.println("Recieved process complete event - " + event);
+	// If we were running an import, now run a build.
+	if(event.getType() == GShell.IMPORT && event.getStatus() == GShell.OK) {
+	    // Finish import.
+	    collection.setImported(true);
+	    buildCollection(false);
+	}
+	// If we were running a build, now is when we move files across.
+	else if(event.getType() == GShell.BUILD && event.getStatus() == GShell.OK) {
+	    if(installCollection()) {
+		// If we have a local library running then ask it to add our newly create collection
+		if (LocalLibraryServer.isRunning() == true) {
+		    LocalLibraryServer.addCollection(collection.getName());
+		}
+		else if (Gatherer.GS3) {
+		    convertToGS3Collection();
+		    Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.ADD_COMMAND + collection.getName());
+		}  
+
+		// Fire a collection changed first to update the preview etc buttons
+		Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
+
+  		// Now display a message dialog saying its all built
+  		WarningDialog collection_built_warning_dialog = new WarningDialog("warning.CollectionBuilt", "CollectionBuilt.Title", Dictionary.get("CollectionBuilt.Message"), null, false);
+  		collection_built_warning_dialog.setMessageOnly(true); // Not a warning
+  		collection_built_warning_dialog.display();
+  		collection_built_warning_dialog.dispose();
+  		collection_built_warning_dialog = null;
+
+		//Set nothing as needing rebuilding, as a build has just finished :-)
+		CollectionDesignManager.resetRebuildTypeRequired();
+	    }
+	    else {
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
+		Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
+		DebugStream.println("Status is ok but !installCollection()");
+	    }
+	}
+	else if (event.getStatus() == GShell.CANCELLED) {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Build_Cancelled"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	    Gatherer.g_man.repaint();
+	}
+	else if (event.getStatus() == GShell.ERROR) {
+	    DebugStream.println("There was an error in the gshell:"+ event.getMessage());
+	    if (event.getType() == GShell.NEW) {
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Create_Collection"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	    } else {
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Preview_Ready_Failed"), Dictionary.get("CollectionManager.Preview_Ready_Title"), JOptionPane.ERROR_MESSAGE);
+		Gatherer.refresh(Gatherer.COLLECTION_REBUILT);
+	    }
+	    
+	    Gatherer.g_man.repaint(); // It appears Java's own dialogs have the same not always painting correct area bug that I suffer from. Well I don't suffer from it personally, but my ModalDialog components do.
+	}
+    }
+
+
+    /** Determine if the manager is ready for actions apon its collection.
+     * @return A <i>boolean</i> which is <i>true</i> to indicate a collection has been loaded and thus the collection is ready for editing, <i>false</i> otherwise.
+     */
+    static public synchronized boolean ready() {
+	if(collection != null) {
+	    return true;
+	}
+	else {
+	    return false;
+	}
+    }
+
+
+    /** This method associates the collection build monitor with the build monitor created in CreatePane.
+     * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the build monitor.
+     */
+    public void registerBuildMonitor(GShellProgressMonitor monitor) {
+	build_monitor = monitor;
+    }
+    /** This method associates the collection import monitor with the import monitor created in CreatePane.
+     * @param monitor A <strong>GShellProgressMonitor</strong> which we will use as the import monitor.
+     */
+    public void registerImportMonitor(GShellProgressMonitor monitor) {
+	import_monitor = monitor;
+    }
+
+
+    public void removeCollectionContentsChangedListener(CollectionContentsChangedListener listener)
+    {
+	collection_contents_changed_listeners.remove(listener);
+    }
+
+
+    public void removeMetadataSet(MetadataSet metadata_set)
+    {
+	System.err.println("Removing metadata set...");
+
+	// Delete the .mds file from the collection's "metadata" folder...
+	File metadata_set_file = metadata_set.getMetadataSetFile();
+
+	// ...but not if it is the "ex.mds" file
+	if (metadata_set_file.getName().equals("ex.mds")) {
+	    return;
+	}
+
+	// ...and only if it exists
+	if (metadata_set_file.exists()) {
+	    metadata_set_file.delete();
+
+	    // Unload it from the MetadataSetManager
+	    MetadataSetManager.unloadMetadataSet(metadata_set);
+
+	    // If we're using a remote Greenstone server, delete the metadata file on the server
+	    if (Gatherer.isGsdlRemote) {
+		String relative_metadata_set_file_path = RemoteGreenstoneServer.getPathRelativeToDirectory(metadata_set_file.getAbsolutePath(), Gatherer.getGLIUserDirectoryPath());
+		RemoteGreenstoneServer.sendDeleteFileCommand(relative_metadata_set_file_path);
+	    }
+	}
+    }
+
+
+    /** Used to check whether all open collections have a 'saved' state.
+     * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
+     * @see org.greenstone.gatherer.collection.Collection
+     */
+    public boolean saved() {
+	boolean result = true;
+	if(collection != null) {
+	    result = collection.getSaved();
+	}
+	return result;
+    }
+
+
+    /** Saves the currently loaded collection. */
+    public void saveCollection()
+    {
+	DebugStream.println("Saving collection " + collection.getName() + "...");
+
+	// Change cursor to hourglass
+	Gatherer.g_man.wait(true);
+
+	// Create a backup of the collection file, just in case anything goes wrong
+	File collection_file = new File(getCollectionFilePath());
+	if (collection_file.exists()) {
+	    File collection_file_backup = new File(collection_file.getAbsolutePath() + "~");
+	    if (!collection_file.renameTo(collection_file_backup)) {
+		DebugStream.println("Error in CollectionManager.saveCollection(): could not create backup file.");
+	    }
+	    collection_file_backup.deleteOnExit();
+	}
+
+	// Write out the collection file
+	collection.save();
+
+	// Write out the collection configuration file
+	Gatherer.g_man.design_pane.saveConfiguration();
+
+	// Change cursor back to normal
+	Gatherer.g_man.wait(false);
+    }
+
+
+    /** I started giving the user the choice of using an existing meta set or creating a new one. The second option being so that they didn't have to add/merge/ignore each element, they could all be added automatically. However, I am not sure where the merge prompt gets called from, and it is not essential, so I am leaving it for now - it should be added back in and finished. [kjdon] */
+    private boolean addSomeMetadataSets(File collection_dir) {
+
+
+	ExternalCollectionPrompt external_prompt = new ExternalCollectionPrompt();
+	int meta_choice = external_prompt.getMetadataChoice();
+	boolean cancelled = external_prompt.isCancelled();
+	if (cancelled) {
+	    return false;
+	}
+
+	// now we reuse the newcoll metadata prompt for the user to select metadata sets
+	NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt(true);
+	if (ncm_prompt.isCancelled()) {
+	    return false;
+	}
+	ArrayList metadata_sets = ncm_prompt.getSets();
+	// Import default metadata sets if any.
+	for(int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
+	    importMetadataSet((MetadataSet) metadata_sets.get(i));
+	}
+
+	// Always import the extracted metadata set
+	File extracted_metadata_set_file = new File(Gatherer.getGLIMetadataDirectoryPath() + MetadataSetManager.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
+	importMetadataSet(new MetadataSet(extracted_metadata_set_file));
+
+	return true;
+    }
+
+
+    // used as arg in the perl scripts
+    private String getCollectDirectory() {
+	String collect_dir = Gatherer.getCollectDirectoryPath();
+
+	// Remove erroneous file windows file separator as it causes problems when running import.pl
+	if(collect_dir.length() > 2 && collect_dir.endsWith("\\")) {
+	    collect_dir = collect_dir.substring(0, collect_dir.length() - 1);
+	}
+
+	return collect_dir;
+    }
+
+
+    /** Install collection by moving its files from building to index after a successful build.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    private boolean installCollection()
+    {
+	DebugStream.println("Build complete. Moving files.");
+
+	try {
+	    // Ensure that the local library has released this collection so we can delete the index directory
+	    if (LocalLibraryServer.isRunning() == true) {
+		LocalLibraryServer.releaseCollection(collection.getName());
+	    }
+	    // deactivate it in tomcat so that windows will release the index files
+	    if (Gatherer.GS3) {
+		Gatherer.configGS3Server(Configuration.site_name, ServletConfiguration.DEACTIVATE_COMMAND + collection.getName());
+	    }
+	    File index_dir = new File(getCollectionIndexDirectoryPath());
+	    DebugStream.println("Index = " + index_dir.getAbsolutePath());
+
+	    File building_dir = new File(getCollectionBuildingDirectoryPath());
+	    DebugStream.println("Building = " + building_dir.getAbsolutePath());
+
+	    // Get the build mode from the build options
+	    String build_mode = collection.build_options.getValue("mode");
+
+	    // Special case for build mode "all": replace index dir with building dir
+	    if (build_mode == null || build_mode.equals(Dictionary.get("CreatePane.Mode_All"))) {
+		// Remove the old index directory
+		if (index_dir.exists()) {
+		    Utility.delete(index_dir);
+
+		    // Wait for a couple of seconds, just for luck
+		    wait(2000);
+
+		    // Check the delete worked
+		    if (index_dir.exists()) {
+			throw new Exception("Index directory could not be removed.");
+		    }
+		}
+
+		// Move the building directory to become the new index directory
+		if (building_dir.renameTo(index_dir) == false) {
+		    throw new Exception("Build directory could not be moved.");
+		}
+	    }
+
+	    // Otherwise copy everything in the building dir into the index dir
+	    else {
+		moveContentsInto(building_dir, index_dir);
+	    }
+	}
+	catch (Exception exception) {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, "Exception detected during collection install.\nMost likely caused by Windows or Local Library holding locks on files:\n" + exception.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
+	    return false;
+	}
+	return true;
+    }
+
+
+    /** Moves all the files in one directory into another, overwriting existing files */
+    private void moveContentsInto(File source_directory, File target_directory)
+    {
+	File[] source_files = source_directory.listFiles();
+	for (int i = 0; i < source_files.length; i++) {
+	    File source_file = source_files[i];
+	    File target_file = new File(target_directory, source_file.getName());
+
+	    if (source_file.isDirectory()) {
+		moveContentsInto(source_file, target_file);
+		source_file.delete();
+	    }
+	    else {
+		if (target_file.exists()) {
+		    target_file.delete();
+		}
+
+		source_file.renameTo(target_file);
+	    }
+	}
+    }
+
+
+    private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
+    {
+	boolean first_name = true;
+	boolean first_extra = true;
+	String collection_path = (base_cfg.getParentFile().getParentFile()).getAbsolutePath();
+
+	// Now read in base_cfg line by line, parsing important onces and/or replacing them with information pertinent to our collection. Each line is then written back out to the new collect.cfg file.
+	try {
+	    BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(base_cfg), "UTF-8"));
+	    BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new_cfg), "UTF-8"));
+	    String command = null;
+	    while((command = in.readLine()) != null) {
+		if (command.length()==0) {
+		    // output a new line
+		    out.newLine();
+		    continue;
+		}
+		// We have to test the end of command for the special character '\'. If found, remove it and append the next line, then repeat.
+		while(command.trim().endsWith("\\")) {
+		    command = command.substring(0, command.lastIndexOf("\\"));
+		    String next_line = in.readLine();
+		    if(next_line != null) {
+			command = command + next_line;
+		    }
+		}
+		// commands can extend over more than one line so use the CommandTokenizer which takes care of that
+		CommandTokenizer tokenizer = new CommandTokenizer(command, in, false);
+		String command_type_str = tokenizer.nextToken().toLowerCase();
+
+		if (command_type_str.equals(StaticStrings.COLLECTIONMETADATA_STR)) {
+		    // read the whole thing in, but for collectionname, collectionextra, iconcollection, iconcollectionsmall we will ignore them
+		    StringBuffer new_command = new StringBuffer(command_type_str);
+		    String meta_name = tokenizer.nextToken();
+		    new_command.append(' ');
+		    new_command.append(meta_name);
+		    while (tokenizer.hasMoreTokens()) {
+			new_command.append(' ');
+			new_command.append(tokenizer.nextToken());
+		    }
+		    if (meta_name.equals(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR) || meta_name.equals(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR) || meta_name.equals(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR) || meta_name.equals(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR)) {
+			// dont save
+		    } else {
+			write(out, new_command.toString());
+		    }
+		    new_command = null;
+		    continue;
+		} // if collectionmeta
+
+		if(command_type_str.equals(Utility.CFG_CLASSIFY)) {
+		    StringBuffer text = new StringBuffer(command_type_str);
+		    // Read in the classifier command watching for hfile, metadata and sort arguments.
+		    String buttonname = null;
+		    String hfile = null;
+		    String new_metadata = null;
+		    String old_metadata = null;
+		
+		    while(tokenizer.hasMoreTokens()) {
+			String token = tokenizer.nextToken();
+			if(token.equals(Utility.CFG_CLASSIFY_HFILE)) {
+			    if(tokenizer.hasMoreTokens()) {
+				text.append(" ");
+				text.append(token);
+				token = tokenizer.nextToken();
+				hfile = token;
+			    }
+			}
+			else if(token.equals(Utility.CFG_CLASSIFY_METADATA)) {
+			    if(tokenizer.hasMoreTokens()) {
+				text.append(" ");
+				text.append(token);
+				String temp_metadata = tokenizer.nextToken();
+				String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
+				if (replacement != null && !replacement.equals("")) {
+				    token = replacement;
+				    old_metadata = temp_metadata;
+				    new_metadata = replacement;
+				}
+				else {
+				    token = temp_metadata;
+				}
+				temp_metadata = null;
+				replacement = null;
+			    }
+			}
+			else if(token.equals(Utility.CFG_CLASSIFY_SORT)) {
+			    if(tokenizer.hasMoreTokens()) {
+				text.append(" ");
+				text.append(token);
+				String temp_metadata = tokenizer.nextToken();
+				String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
+				if (replacement != null && !replacement.equals("")) {
+				    token = replacement;
+				}
+				else {
+				    token = temp_metadata;
+				}
+				temp_metadata = null;
+				replacement = null;
+			    }
+			}
+			else if(token.equals(Utility.CFG_CLASSIFY_BUTTONNAME)) {
+			    buttonname = token;
+			}
+			text.append(' ');
+			text.append(token);
+			token = null;
+		    }
+		   
+		    // If we replaced the metadata argument and didn't encounter a buttonname, then add one now pointing back to the old metadata name in order to accomodate macro files which required such names (buttonname is metadata name by default)!
+		    if(old_metadata != null && new_metadata != null && buttonname == null) {
+			text.append(' ');
+			text.append(Utility.CFG_CLASSIFY_BUTTONNAME);
+			text.append(' ');
+			text.append(old_metadata);
+		    }
+		    command = text.toString();
+		    // Replace the hfile if we found it
+		    if(hfile != null && new_metadata != null) {
+			command = command.replaceAll(hfile, new_metadata + ".txt");
+		    }
+		
+		    buttonname = null;
+		    hfile = null;
+		    new_metadata = null;
+		    old_metadata = null;
+		    write(out, command);
+		} else {
+		    // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
+		    StringBuffer new_command = new StringBuffer(command_type_str);
+		    while (tokenizer.hasMoreTokens()) {
+			new_command.append(' ');
+			new_command.append(tokenizer.nextToken());
+		    }
+
+		    command = new_command.toString();
+		    
+		    // There is still one special case, that of the format command. In such a command we have to search for [<target>] to ensure we don't change parts of the format which have nothing to do with the metadata elements.
+		    // we really want to build up the whole command here
+		    boolean format_command = command_type_str.equals(Utility.CFG_FORMAT);
+		    HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
+		    if (metadata_mapping != null) {
+			Iterator keys = metadata_mapping.keySet().iterator();
+			while (keys.hasNext()) {
+			    String target = (String) keys.next();
+			    String replacement = (String) metadata_mapping.get(target);
+			    if (replacement != null && !replacement.equals("")) {
+				if (format_command) {
+				    target = "\\[" + target + "\\]";
+				    replacement = "{Or}{[" + replacement + "]," + target + "}";
+				}
+				command = command.replaceAll(target, replacement);
+			    }
+			}
+		    }
+
+		    write(out, command);
+		}
+		tokenizer = null;
+	    }
+	    in.close();
+	    in = null;
+	    out.flush();
+	    out.close();
+	    out = null;
+	}
+	catch(Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+	// All done, I hope.
+    }
+    
+    private void write(BufferedWriter out, String message)
+	throws Exception {
+	out.write(message, 0, message.length());
+	out.newLine();
+    }
+
+
+    /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
+    private class FMTreeModelListener
+	implements TreeModelListener {
+	/** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
+	 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
+	 */
+	public void treeNodesChanged(TreeModelEvent event) {
+	    if(collection != null) {
+		collection.setSaved(false);
+		collection.setFilesChanged(true);
+	    }
+	}
+	/** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
+	 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
+	 */
+	public void treeNodesInserted(TreeModelEvent event) {
+	    if(collection != null) {
+		collection.setSaved(false);
+		collection.setFilesChanged(true);
+	    }
+	}
+	/** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
+	 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
+	 */
+	public void treeNodesRemoved(TreeModelEvent event) {
+	    if(collection != null) {
+		collection.setSaved(false);
+		collection.setFilesChanged(true);
+
+	    }
+	}
+	/** Any action that changes one of the tree models within a collection, which are the only models we listen to, mean the collections contents have changed and so saved should be set to false.
+	 * @param event A <strong>TreeModelEvent</strong> encompassing all the information about the event which has changed the tree.
+	 */
+	public void treeStructureChanged(TreeModelEvent event) {
+	    if(collection != null) {
+		collection.setSaved(false);
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionTree.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionTree.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionTree.java	(revision 10506)
@@ -0,0 +1,60 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.collection;
+
+import java.awt.*;
+import javax.swing.*;
+import org.greenstone.gatherer.gui.tree.DragTree;
+import org.greenstone.gatherer.gui.tree.DragTreeCellRenderer;
+
+
+public class CollectionTree
+    extends DragTree
+{
+    public CollectionTree(String name, CollectionTreeModel collection_tree_model, boolean mixed_selection)
+    {
+	super(name, collection_tree_model, mixed_selection);
+	setCellRenderer(new CollectionTreeCellRenderer());
+    }
+
+
+    private class CollectionTreeCellRenderer
+	extends DragTreeCellRenderer
+    {
+	public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)
+	{
+	    JLabel tree_cell = (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
+
+	    // Mark explodable files with a different icon
+	    if (value instanceof CollectionTreeNode && ((CollectionTreeNode) value).isExplodable()) {
+		tree_cell.setIcon(CollectionTreeNode.GREEN_FILE_ICON);
+	    }
+
+	    return tree_cell;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionTreeModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionTreeModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionTreeModel.java	(revision 10506)
@@ -0,0 +1,41 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.collection;
+
+
+import org.greenstone.gatherer.file.FileSystemModel;
+
+
+/** This class represents ... */
+public class CollectionTreeModel
+    extends FileSystemModel
+{
+    public CollectionTreeModel(CollectionTreeNode root_node)
+    {
+	super(root_node);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionTreeNode.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionTreeNode.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/CollectionTreeNode.java	(revision 10506)
@@ -0,0 +1,68 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.collection;
+
+
+import java.io.*;
+import javax.swing.*;
+import org.greenstone.gatherer.cdm.CollectionDesignManager;
+import org.greenstone.gatherer.file.FileNode;
+import org.greenstone.gatherer.util.JarTools;
+
+
+/** This class represents one node in the collection tree. */
+public class CollectionTreeNode
+    extends FileNode
+{
+    static final public ImageIcon GREEN_FILE_ICON = JarTools.getImage("greenfile.gif", true);
+
+    /** Is this file a metadata database that is explodable with the explode_metadata_databases.pl script? */
+    private boolean is_explodable = false;
+
+
+    public CollectionTreeNode(File file)
+    {
+	super(file);
+
+	this.is_explodable = CollectionDesignManager.plugin_manager.isFileExplodable(file);
+    }
+
+
+    public FileNode addChildNode(File file)
+    {
+	CollectionTreeNode child_node = new CollectionTreeNode(file);
+	child_node.setModel(model);
+	child_node.setParent(this);
+	return child_node;
+    }
+
+
+    public boolean isExplodable()
+    {
+	return is_explodable;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/DownloadJob.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/DownloadJob.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/DownloadJob.java	(revision 10506)
@@ -0,0 +1,574 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.collection;
+
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.GAuthenticator;
+import org.greenstone.gatherer.WGet;
+import org.greenstone.gatherer.file.WorkspaceTree;
+import org.greenstone.gatherer.gui.DownloadProgressBar;
+import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
+import org.greenstone.gatherer.util.GURL;
+import org.greenstone.gatherer.util.SynchronizedTreeModelTools;
+import org.greenstone.gatherer.util.Utility;
+/**
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.0
+ */
+public class DownloadJob
+    implements ActionListener {
+	 
+    private boolean debug;
+    private boolean higher_directories;
+    private boolean no_parents;
+    private boolean other_hosts; 
+    private boolean page_requisites; 
+    private boolean quiet;
+
+    private AppendLineOnlyFileDocument download_log;
+
+    private DownloadProgressBar progress;
+
+    private GURL initial = null;
+    private GURL url = null;
+
+    // private TreeModel model;
+
+    private int depth;
+    private int previous_state;
+    private int state;
+
+    private String current_url;
+    private String destination;
+    private String proxy_pass;
+    private String proxy_user;
+
+    private Vector encountered_urls;
+    private Vector failed_urls;
+
+    private WGet mummy;
+
+    public static int COMPLETE = 0;
+    public static int PAUSED   = 1;
+    public static int RUNNING  = 2;
+    public static int STOPPED  = 3;
+
+    /**
+     */
+    public DownloadJob(boolean debug, boolean no_parents, boolean other_hosts, boolean page_requisites, boolean quiet, URL initial, int depth, String destination, String proxy_pass, String proxy_user, WGet mummy, boolean simple) {
+	// this.model = model;
+
+	String log_filename = Gatherer.getGLIUserLogDirectoryPath() + "wget" + initial.hashCode() + ".log";
+	File log_file = new File(log_filename);
+	if(log_file.exists()) {
+	    log_file.delete();
+	}
+	File parent_log_file = log_file.getParentFile();
+	parent_log_file.mkdirs();
+	parent_log_file = null;
+	log_file = null;
+
+	this.debug = debug;
+	this.download_log = new AppendLineOnlyFileDocument(log_filename, false);
+	this.no_parents = no_parents;
+	this.other_hosts = other_hosts;
+	this.page_requisites = page_requisites;
+	this.quiet = quiet;
+	this.initial = new GURL(initial);
+	this.depth = depth;
+	this.destination = destination;
+	this.proxy_pass = proxy_pass;
+	this.proxy_user = proxy_user;
+	this.mummy = mummy;
+
+	progress = new DownloadProgressBar(this, initial.toString(), simple);
+
+	encountered_urls = new Vector();
+	failed_urls = new Vector();
+
+	previous_state = STOPPED;
+	state = STOPPED;
+    }
+
+    /** Depending on which button on the progress bar was pushed,
+     * this method will affect the state of the DownloadJob and perhaps make
+     * calls to wget.class if necessary.
+     * @param event The ActionEvent fired from within the DownloadProgressBar
+     * which we must respond to.
+     */
+    public void actionPerformed(ActionEvent event) {
+	// The stop_start_button is used to alternately start or stop the
+	// job. If the current state of the job is paused then this
+	// restart is logically equivelent to a resume.
+	if(event.getSource() == progress.stop_start_button) {
+	    previous_state = state;
+	    if (state == RUNNING) {
+		state = STOPPED;
+	    } else {
+		//previous_state = state;
+		state = RUNNING;
+		mummy.resumeThread();
+	    }
+	}
+	else if (event.getSource() == progress.close_button) {
+	    if(state == RUNNING) {
+		previous_state = state;
+		state = STOPPED; // do we need to do anything else to stop this?
+	    }
+	    // else {
+	    mummy.deleteDownloadJob(this);
+		// }
+	}
+    }
+
+    /** Called by the WGet native code to inform us of a new download starting.
+     * @param raw_url The url that is being downloaded, as a String.
+     */
+    public void addDownload(String raw_url) {
+	if(!encountered_urls.contains(raw_url)) {
+	    encountered_urls.add(raw_url);
+	}
+	// Regardless create a new GURL
+	current_url = raw_url;
+	url = new GURL(raw_url);
+	progress.addDownload(raw_url);
+    }
+
+    /** Used to advise the DownloadJob of a newly parsed link. Its up to DownloadJob
+     * to decide if it already knows about this url, and if not to
+     * update its progress bar.
+     * @param raw_url The url in question as a String.
+     * @param type Whether the link is an internal or external link.
+     * @return A boolean indicating if the url was added.
+     */
+    public boolean addLink(String raw_url, int type) {
+	///ystem.out.println("addLink("+url+", "+type+")");
+	if(!encountered_urls.contains(raw_url)) {
+	    // Add it to the urls we've seen.
+	    encountered_urls.add(raw_url);
+	    // Add it the to links for the current GURL.
+
+	    // Add it to the progress file count.
+	    progress.increaseFileCount();
+	    return true;
+	}
+	// Regardless add it to the children links of the current GURL
+	initial.addLink(raw_url);
+
+	// We've seen it before. Don't count it again.
+	return false;
+    }
+
+    public void callWGet() {
+	// Build parameter string. Note that we never clobber, and we continue if possible
+
+	// want to always download newer files,  convert non-relative links to relative, always use directories, and only try twice to get a file before giving up
+	String command = Configuration.getWGetPath() + " -N -k -x -t 2 "; // + " -nc -c "; 
+
+	if (no_parents) {
+	    command = command + "-np ";
+	}
+	if(depth < 0) {
+	    // Infinite recursion
+	    command = command + "-r ";
+	}
+	else if (depth == 0) {
+	    // Just this page.
+	}
+	else if (depth > 0) {
+	    // Recursion to the specified depth.
+	    command = command + "-r -l" + depth + " ";
+	}
+
+	String proxy_url = "";
+	// Determine if we have to use a proxy.
+	if(Configuration.get("general.use_proxy", true)) {
+	    String proxy_host = Configuration.getString("general.proxy_host", true);
+	    String proxy_port = Configuration.getString("general.proxy_port", true);
+	    // Find out whether the user has already authenticated themselves
+	    String user_pass = null;
+	    String address = proxy_host + ":" + proxy_port;
+	    int count = 0;
+	    while(count < 3 && (user_pass = (String) GAuthenticator.authentications.get(address)) == null) {
+		Authenticator.requestPasswordAuthentication(proxy_host, null, Integer.parseInt(proxy_port), "http://", Dictionary.get("WGet.Prompt"), "HTTP");
+		count++;
+	    }
+	    if(count >= 3) {
+		state = STOPPED;
+		return;
+	    }
+	    if(user_pass.indexOf("@") != -1) {
+		
+		// Write the use proxy command - we don't do this anymore, instead we set environment variables - hopefully these can't be spied on like the follwoing can (using ps) - actually the environment stuff didn't work for windows, so lets go back to this
+		if (Utility.isWindows()) {
+		    command = command + "-e httpproxy=" + proxy_host + ":" + proxy_port + "/ --proxy-user=" + user_pass.substring(0, user_pass.indexOf("@")) + " --proxy-passwd=" + user_pass.substring(user_pass.indexOf("@") + 1) + " -Y on ";
+		} else {
+		    String user_name = user_pass.substring(0, user_pass.indexOf("@"));
+		    String user_pwd = user_pass.substring(user_pass.indexOf("@") + 1);
+		    proxy_url = user_name+":"+user_pwd+"@"+proxy_host+":"+proxy_port+"/";
+		}
+
+	    }
+	    else {
+		DebugStream.println("Unknown user/pass");
+	    }
+	}
+		
+	// The user can choose to mirror all of the page requisites...
+ 	if(page_requisites) {
+ 	    command = command + "-p ";
+ 	}
+
+	// Download files from other hosts
+	if(other_hosts) {
+	    command = command + "-H ";
+	}
+
+	// Finally tell it the site to download.
+	command = command + initial.toString();
+
+	if(previous_state == DownloadJob.COMPLETE) {
+	    progress.mirrorBegun(true, true);
+	}
+	else {
+	    progress.mirrorBegun(false, true);
+	}		  
+
+	File dest_file = new File(destination);
+	if (!dest_file.exists()) {
+	    dest_file.mkdirs();
+	}
+	// Run it
+	try {
+	    //DebugStream.println("Cmd: " + command); // don't print it out cos it may have the password in it
+	    Runtime rt = Runtime.getRuntime();
+	    String [] env = null;
+	    if (!proxy_url.equals("")) {
+		env = new String[2];
+		env[0] = "http_proxy=http://"+proxy_url;
+		env[1] = "ftp_proxy=ftp://"+proxy_url;
+	    }
+	    Process prcs = rt.exec(command, env, dest_file);
+	    InputStreamReader isr = new InputStreamReader(prcs.getErrorStream());
+	    BufferedReader br = new BufferedReader(isr);
+	    // Capture the standard error stream and seach for two particular occurances.
+	    String line;
+	    boolean ignore_for_robots = false;
+	    while ((line = br.readLine()) != null && state != STOPPED) {
+		
+		DebugStream.println(line);
+		download_log.appendLine(line);
+		// The first magic special test is to see if we've just
+		// asked for the robots.txt file. If so we ignore
+		// the next add and then the next complete/error.
+		if(line.lastIndexOf("robots.txt;") != -1) {
+		    DebugStream.println("***** Requesting robot.txt");
+		    ignore_for_robots = true;
+		}
+		// If line contains "=> `" display text as the 
+		// currently downloading url. Unique to add download.
+		else if(line.lastIndexOf("=> `") != -1) {
+		    if(!ignore_for_robots) {
+			// Add download
+			String new_url = line.substring(line.indexOf("`") + 1, line.lastIndexOf("'"));
+			addDownload("http:/" + new_url);
+		    }
+		}
+		// If line contains "/s) - `" set currently 
+		// downloading url to "Download Complete".
+		else if(line.lastIndexOf("/s) - `") != -1) {
+		    String current_file_downloading = line.substring(line.indexOf("`") + 1, line.lastIndexOf("'"));
+		    if(!ignore_for_robots) {
+			DebugStream.println("Not ignore for robots");
+			// Download complete
+			downloadComplete(current_file_downloading);
+		    }
+		    else {
+			DebugStream.println("Ignore for robots");
+			ignore_for_robots = false;
+		    }
+		}
+		// The already there line begins "File `..." However this
+		// is only true in english, so instead I looked and there
+		// are few (if any at all) other messages than those above
+		// and not overwriting messages that use " `" so we'll 
+		// look for that. Note this method is not guarenteed to be
+		// unique like the previous two.
+		else if(line.lastIndexOf(" `") != -1) {
+		    // Not Overwriting
+		    DebugStream.println("Already there.");
+		    String new_url = 
+			line.substring(line.indexOf("`") + 1, line.lastIndexOf("'"));
+		    addDownload("http:/" + new_url);
+		    downloadWarning();
+		}
+		// Any other important message starts with the time in the form hh:mm:ss
+		else if(line.length() > 7) {
+		    if(line.charAt(2) == ':' && line.charAt(5) == ':') {
+			if(!ignore_for_robots) {
+			    DebugStream.println("Error.");
+			    downloadFailed();
+			}
+			else {
+			    ignore_for_robots = false;
+			}
+		    }
+		}
+	    }
+	    if(state == STOPPED) {
+		isr.close();
+		prcs.destroy(); // This doesn't always work, but it's worth a try
+	    }
+	    else {
+		// Now display final message based on exit value
+		prcs.waitFor();
+	    }
+	}
+	catch (Exception ioe) {
+	    //message(Utility.ERROR, ioe.toString());
+	    DebugStream.printStackTrace(ioe);
+	}
+	// If we've got to here and the state isn't STOPPED then the
+	// job is complete.
+	if(state == DownloadJob.RUNNING) {
+	    progress.mirrorComplete();
+	    previous_state = state;
+	    state = DownloadJob.COMPLETE;
+	    
+	}
+	// refresh the workspace tree
+	Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.DOWNLOADED_FILES_CHANGED);
+    }
+    
+	
+    /** The most important part of the DownloadJob class, this method is
+     * responsible for calling the WGet native methods used to 
+     * mirror the indicated url. By this stage all the variables
+     * necessary should be set and we need only build up the
+     * parameter string and make the call.
+     */
+    public void callWGetNative() {
+	Vector args = new Vector();
+
+	// Let the DownloadProgressBar know we're starting, just in case
+	// the user hasn't told us to. If this is the second time the
+	// urls downloaded and the first attempt was successful (ie 
+	// the previous job was complete), then we have the case where 
+	// the user is forcing us to remirror. Reset all the values etc
+	// if this is the case then reset the variables.
+	// Note that this can cause the result line to look something 
+	// like this.
+	// Downloaded 12 of 12 files (8 warnings, 0 errors).
+	// The warnings would be something like, 'File already downloaded'
+	// but the total number of files and the file successfully 
+	// downloaded will be correct.
+	if(previous_state == DownloadJob.COMPLETE) {
+	    progress.mirrorBegun(true, false);
+	}
+	else {
+	    progress.mirrorBegun(false, false);
+	}
+
+	// Parse arguments into array.
+	args.add(Configuration.getWGetPath());
+	args.add("-d");
+	args.add("-o");
+	args.add("debug.txt");
+		  
+	if(destination != null) {
+	    args.add("-P");
+	    args.add(destination);
+	}
+
+	if(depth < 0) {
+	    // Infinite recursion
+	    args.add("-r");
+	}
+	else if (depth == 0) {
+	    // Just this page.
+	}
+	else if (depth > 0) {
+	    // Recursion to the specified depth.
+	    args.add("-r");
+	    args.add("-l");
+	    args.add("" + depth + ""); // Hacky
+	}
+
+	if(previous_state == PAUSED) {
+	    args.add("-nc");
+	    args.add("-c");
+	}
+
+	if(proxy_user != null) {
+	    args.add("--proxy-user=" + proxy_user);
+	    args.add("--proxy-passwd=" + proxy_pass);
+	}
+		  
+	if(page_requisites) {
+	    args.add("-p");
+	}
+
+	if(quiet) {
+	    args.add("-q");
+	}
+
+	if(other_hosts) {
+	    args.add("-H");
+	}
+
+	args.add(initial.toString());
+
+	DebugStream.println("Calling wget ");
+	for(Enumeration e = args.elements(); e.hasMoreElements();) {
+	    DebugStream.println(e.nextElement() + " ");
+	}
+	DebugStream.println("");
+
+	// Run home to mummy.
+	int value = mummy.wget(args.size(), args.toArray(), debug);
+
+	// If we've got to here and the state isn't STOPPED then the job is complete.
+	if(state == RUNNING) {
+	    progress.mirrorComplete();
+	    previous_state = state;
+	    state = COMPLETE;
+	}
+    }
+
+    /** Called by the WGet native code when the current download is 
+     * completed. In turn all download listeners are informed.
+     */
+    public void downloadComplete() {
+	progress.downloadComplete();
+	url = null;
+	current_url = null;
+    }
+
+
+    public void downloadComplete(String current_file_downloading)
+    {
+	progress.downloadComplete();
+	DebugStream.println("Download complete: " + current_file_downloading);
+    }
+
+
+    /** Called by the WGet native code when the requested download returns
+     * a status code other than 200.
+     */
+    public void downloadFailed() {
+	failed_urls.add(current_url); // It is the current url that failed
+	progress.downloadFailed();
+	DebugStream.println("Download failed: " + current_url);
+    } 
+	 
+    /**
+     */
+    public void downloadWarning() {
+	progress.downloadWarning();
+    }
+
+
+    /** 
+     * @return A String representing the initial urls host (root node
+     * of tree that we are mirroring).
+     */
+    public String getHost() {
+	return url.getHost();
+    }
+
+    public AppendLineOnlyFileDocument getLogDocument() {
+	return download_log;
+    }
+
+    /**
+     * @return Returns the progress bar associated with this job.
+     */
+    public DownloadProgressBar getProgressBar() {
+	return progress;
+    }
+
+    /** Called to discover if the user wanted this thread to run or if
+     * it is paused.
+     * @return An int representing the current DownloadJob state.
+     */
+    public int getState() {
+	return state;
+    }
+
+    /** Returns the current state of the stop flag for this job.
+     * @return A boolean representing whether the user has requested to
+     * stop.
+     */
+    public boolean hasSignalledStop() {
+	if(state == DownloadJob.STOPPED || state == DownloadJob.PAUSED || 
+	   state == DownloadJob.COMPLETE) {
+	    return true;
+	}
+	return false;
+    }
+
+    public void setState(int state) {
+	previous_state = this.state;
+	this.state = state;
+    }
+
+    /** A convinence call.
+     * @return A String representing the url of the initial url (root node of the mirrored tree).
+     */
+    public String toString() {
+	return initial.toString();
+    }
+
+    /** Called by the WGet native code to signal the current progress of 
+     * downloading.
+     * @param current A long representing the number of bytes that have 
+     * been downloaded since the last update. 
+     * @param expected A long representing the total number of bytes
+     * expected for this download.
+     */
+    public void updateProgress(long current, long expected) {
+	progress.updateProgress(current, expected);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/LegacyCollectionImporter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/LegacyCollectionImporter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/LegacyCollectionImporter.java	(revision 10506)
@@ -0,0 +1,138 @@
+package org.greenstone.gatherer.collection;
+
+
+import java.io.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.cdm.Argument;
+import org.greenstone.gatherer.cdm.Classifier;
+import org.greenstone.gatherer.cdm.CollectionDesignManager;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataTools;
+import org.greenstone.gatherer.metadata.ProfileXMLFileManager;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+
+/**
+ * Importing legacy collections involves two main steps:
+ *
+ * 1. Read the existing metadata.xml files and namespace them, usually by prompting the user
+ *    to specify the mapping between old metadata elements and new elements.
+ *
+ * 2. Fix up the classify commands in the collect.cfg file to specify the new element names.
+ *
+ * @author Michael Dewsnip
+ */
+public class LegacyCollectionImporter 
+{
+    // This copies all the existing metadata.xml files into a backup directory
+    static public void backupMetadataXMLFiles(File collection_dir)
+    {
+	File import_dir = new File(collection_dir, Utility.IMPORT_DIR);
+	File import_bak_dir = new File(collection_dir, Utility.IMPORT_BAK_DIR);
+	import_bak_dir.mkdir();
+	copyMetadataXMLFiles(import_dir, import_bak_dir);
+    }
+
+
+    static private void copyMetadataXMLFiles(File source_dir, File backup_dir)
+    {
+	if (source_dir == null || !source_dir.exists()) {
+	    return;
+	}
+
+	// Find the metadata file in this dir
+	File metadata_xml_file_file = new File(source_dir, "metadata.xml");
+	if (metadata_xml_file_file.exists()) {
+	    File new_metadata_xml_file_file = new File(backup_dir, "metadata.xml");
+	    try {
+		backup_dir.mkdirs();
+		Gatherer.f_man.getQueue().copyFile(metadata_xml_file_file, new_metadata_xml_file_file, null);
+		if (!new_metadata_xml_file_file.exists()) {
+		    throw new Exception("");
+		}
+	    }
+	    catch (Exception e) {
+		DebugStream.println("Exception: couldn't copy the file " + metadata_xml_file_file.getPath() + e.getMessage());
+	    }
+	}
+
+	// Now go through child directories
+	File [] children = source_dir.listFiles();
+	for (int i = 0; i < children.length; i++) {
+	    File child = children[i];
+	    if (child.isDirectory()) {
+		copyMetadataXMLFiles(child, new File(backup_dir, child.getName()));
+	    }
+	}
+    }
+
+
+    static public void updateClassifiers(CollectionDesignManager cdm)
+    {
+	// Update the metadata elements in each of the classifiers
+	for (int i = 0; i < cdm.classifier_manager.getSize(); i++) {
+	    Classifier classifier = cdm.classifier_manager.getClassifier(i);
+	    // System.err.println("Classifier: " + classifier);
+
+	    // Update the "-metadata" value
+	    Argument metadata_argument = classifier.getArgument("-metadata");
+	    String metadata_argument_value = metadata_argument.getValue();
+	    String metadata_element_name_full = mapLegacyMetadataElementName(metadata_argument_value);
+	    if (metadata_element_name_full != null && !metadata_element_name_full.equals("")) {
+		String metadata_element_display_name_full = MetadataTools.getDisplayNameForMetadataElementWithName(metadata_element_name_full);
+		if (metadata_element_display_name_full != null) {
+		    metadata_argument_value = metadata_element_display_name_full;
+		    metadata_argument.setValue(metadata_argument_value);
+		}
+	    }
+
+  	    // Update the "-sort" value
+	    Argument sort_argument = classifier.getArgument("-sort");
+	    if (sort_argument != null) {
+		String sort_element_name_full = mapLegacyMetadataElementName(sort_argument.getValue());
+		if (sort_element_name_full != null && !sort_element_name_full.equals("")) {
+		    String sort_element_display_name_full = MetadataTools.getDisplayNameForMetadataElementWithName(sort_element_name_full);
+		    if (sort_element_display_name_full != null) {
+			sort_argument.setValue(sort_element_display_name_full);
+		    }
+		}
+	    }
+
+	    // Set the "-buttonname" value if it isn't already set
+	    Argument buttonname_argument = classifier.getArgument("-buttonname");
+	    if (buttonname_argument != null && buttonname_argument.getValue().equals("")) {
+		int namespace_index = metadata_argument_value.indexOf(".");
+		if (namespace_index != -1) {
+		    buttonname_argument.setValue(metadata_argument_value.substring(namespace_index + 1));
+		}
+		else {
+		    buttonname_argument.setValue(metadata_argument_value);
+		}
+		buttonname_argument.setAssigned(true);
+	    }
+
+	    // With Hierarchy classifiers, update the hfile arguments
+  	    if (classifier.getName().equalsIgnoreCase(StaticStrings.HIERARCHY_CLASSIFIER)) {
+		// Update the "-hfile" value
+		Argument hfile_argument = classifier.getArgument(StaticStrings.HFILE_ARGUMENT);
+		hfile_argument.setValue(metadata_element_name_full + ".txt");
+  	    }
+
+	    // System.err.println("Classifier (after): " + classifier);
+	}
+    }
+
+
+    static private String mapLegacyMetadataElementName(String metadata_element_name)
+    {
+ 	// Remove the extracted namespace if it has been added
+ 	if (metadata_element_name.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
+ 	    metadata_element_name = metadata_element_name.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
+ 	}
+
+ 	// Update the metadata value to the new (namespaced) one
+	return ProfileXMLFileManager.getMetadataElementFor(metadata_element_name);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/ScriptOptions.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/ScriptOptions.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/collection/ScriptOptions.java	(revision 10506)
@@ -0,0 +1,338 @@
+package org.greenstone.gatherer.collection;
+
+import java.io.*;
+import java.lang.ref.*;
+import java.net.*;
+import java.util.*;
+import org.apache.xerces.parsers.DOMParser;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.LocalGreenstone;
+import org.greenstone.gatherer.cdm.Argument;
+import org.greenstone.gatherer.util.ArrayTools;
+import org.greenstone.gatherer.util.Codec;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+import org.xml.sax.InputSource;
+
+/** Build options uses the argument list found in config.xml and the current settings from the loaded collection configuration to represent the options the user wants to use during import and build. If there are no arguments stored in config.xml, or if the user indicates the argument are out of date, this class tries to parse new ones. */
+public class ScriptOptions {
+    /** The root element of the argument tree. */
+    private Element arguments_element;
+    /** The root element of the values tree. */
+    private Element values_element;
+    /** A cache of previously created arguments. */
+    private Hashtable arguments_cache = new Hashtable();
+    /** whether the values should be saved or not */
+    /** The name of an argument element. */
+    static final private String ARGUMENT = "Argument";
+    /** The name of the enabled attribute. */
+    static final private String ENABLED = "enabled";
+    /** The name of the 'false' value. */
+    static final private String FALSE = "false";
+    /** The name of a name attribute. */
+    static final private String NAME = "name";
+    /** The name of an option element. */
+    static final private String OPTION = "Option";
+    /** The name of the 'true' value. */
+    static final private String TRUE = "true";
+    /** When constructing a ScriptOptions object we first try to retrieve the valid arguments from config.xml - if saved is true. If that fails we then try to parse the arguments noticed when calling script_name -xml. If that also fails, we try to load the default arguments from the xml template library. */
+    public ScriptOptions(Element values_element, String script_name, boolean saved) {
+	// first check the saved arguments language
+	String interface_lang = Configuration.getLanguage();
+	String args_lang = Configuration.getArgumentsLanguage();
+	if (saved && interface_lang.equals(args_lang)) {
+	    // Try to retrieve the arguments for import and build.
+	    arguments_element = Configuration.getArguments(script_name);
+	}
+	// If that fails try to reconstruct the arguments
+	if(arguments_element == null) {
+	    boolean used_defaults = false;
+	    arguments_element = loadArguments(script_name, interface_lang);
+	   
+	    // And if that too fails, load the default argument templates
+	    if(arguments_element == null) {
+		// replace .pl with .xml to get the template name
+		String template_name = script_name.replaceAll("\\.pl$", "\\.xml");
+		Document document = XMLTools.parseXMLFile("xml/" + template_name, true);
+		if (document != null) {
+		    arguments_element = document.getDocumentElement();
+		    document = null;
+		    used_defaults = true;
+
+		} else {
+		    return;
+		}
+		///atherer.println("Loaded default BO arguments from templates.");
+	    }
+	    else {
+		///atherer.println("Loaded BO arguments from scripts.");
+	    }
+	    // By now we should definately have the arguments. However the reason we are here is because they are not stored in the config.xml file, to make sure they are stored now.
+	    if (saved) {
+		if (used_defaults) {
+		    Configuration.setArgumentsLanguage("en");
+		} else {
+		    Configuration.setArgumentsLanguage(interface_lang);
+		}
+		Configuration.setArguments(arguments_element);
+	    }
+	}
+	else {
+	    DebugStream.println("Loaded BO arguments from config.xml");
+	}
+	// Now take a note of the values too.
+	this.values_element = values_element;
+    }
+
+    /** Retrieve the indexth argument */
+    public Argument getArgument(int index) {
+	Argument argument = null;
+	// Try to find the argument in the cache.
+	SoftReference reference = (SoftReference) arguments_cache.get(new Integer(index));
+	if(reference != null) {
+	    argument = (Argument) reference.get();
+	}
+	// Otherwise generate a new argument.
+	if(argument == null) {
+	    NodeList option_list = arguments_element.getElementsByTagName(OPTION);
+	    if(0 <= index && index < option_list.getLength()) {
+		argument = new Argument();
+		argument.parseXML((Element) option_list.item(index));
+	    }
+	}
+	return argument;
+    }
+
+
+    /** Retrieve the number of arguments.
+     */
+    public int getArgumentCount() {
+	// Determining the total count is easy.
+	NodeList argument_elements = arguments_element.getElementsByTagName(OPTION);
+	return argument_elements.getLength();
+    }
+
+    /** Retrieve all the argument names and values  */
+    public String[] getArguments() {
+	String arguments[] = null;
+	NodeList argument_list = null;
+	argument_list = values_element.getElementsByTagName(ARGUMENT);
+	for(int i = 0; i < argument_list.getLength(); i++) {
+	    String[] temp = new String[2];
+	    Element argument = (Element) argument_list.item(i);
+	    ArrayTools.add(arguments, argument.getAttribute(NAME));
+	    String value = XMLTools.getValue(argument);
+	    if(value != null && value.length() > 0) {
+		ArrayTools.add(arguments, value);
+	    }
+	}
+	return arguments;
+    }
+
+    /** Retrieve the value of a certain argument. */
+    public String getValue(String name) {
+	return getValue(name, false);
+    }
+
+    /** Determine if the named argument value is enabled or disabled. */
+    public boolean getValueEnabled(String name) {
+	boolean result = false;
+	String value = getValue(name, true);
+	if(value != null && value.length() > 0) {
+	    result = (value.equalsIgnoreCase(TRUE));
+	}
+	return result;
+    }
+
+    /** Retrieve all of the values as a String array ready to added to the script call. */
+    public String[] getValues() {
+	ArrayList values = new ArrayList();
+	try {
+	    NodeList arguments = values_element.getElementsByTagName(ARGUMENT);
+	    for(int i = 0; i < arguments.getLength(); i++) {
+		Element argument_element = (Element) arguments.item(i);
+		// Determine if this argument is enabled.
+		if(argument_element.getAttribute(ENABLED).equalsIgnoreCase(TRUE)) {
+		    // First store the name of the argument prefixed with a '-'
+		    values.add("-" + argument_element.getAttribute(NAME));
+		    // Now retrieve the value.
+		    String argument_value = Codec.transform(XMLTools.getValue(argument_element), Codec.DOM_TO_TEXT);
+		    // If there is a value, tokenize it by commas only.
+		    if(argument_value != null && argument_value.length() > 0) {
+			values.add(argument_value);
+		    }
+		    argument_value = null;
+		}
+		argument_element = null;
+	    }
+	    arguments = null;
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+	return ArrayTools.arrayListToStringArray(values);
+    }
+
+   /** Remove the named value from the arguments */
+    public void removeValue(String name) {
+	try {
+	    NodeList arguments = values_element.getElementsByTagName(ARGUMENT);
+	    boolean found = false;
+	    for(int i = 0; !found && i < arguments.getLength(); i++) {
+		Element argument_element = (Element) arguments.item(i);
+		// Is this the argument we want.
+		if(argument_element.getAttribute(NAME).equalsIgnoreCase(name)) {
+		    values_element.removeChild(argument_element);
+		    found = true;
+		}
+		argument_element = null;
+	    }
+	    arguments = null;
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+    }
+
+    /** Set the state of some argument. Note that value may be either a single String, an ArrayList of Strings or null. If enable is false then any existing argument for the named argument is disabled. */
+    public void setValue(String name, boolean enable, String value) {
+	///ystem.err.println("Set value: " + (arguments_element == build_values_element ? "Build" : "Import") + ", " + name + ", " + enable + ", " + value);
+	try {
+	    Document document = values_element.getOwnerDocument();
+	    NodeList arguments = values_element.getElementsByTagName(ARGUMENT);
+	    boolean found = false;
+	    for(int i = 0; i < arguments.getLength(); i++) {
+		Element argument_element = (Element) arguments.item(i);
+		// If this the argument named.
+		if(argument_element.getAttribute(NAME).equalsIgnoreCase(name)) {
+		    found = true;
+		    // Set whether this argument is enabled
+		    argument_element.setAttribute(ENABLED, (enable ? TRUE : FALSE));
+		    // Now we set the value, depending or what it is.
+		    if(value == null) {
+			// Nothing to do.
+		    }
+		    else {
+			// Remove existing text nodes.
+			while(argument_element.hasChildNodes()) {
+			    argument_element.removeChild(argument_element.getFirstChild());
+			}
+			argument_element.appendChild(document.createTextNode((String)value));
+		    }
+		}
+		argument_element = null;
+	    }
+	    // If we haven't found an instance of this argument, but should have, then add it.
+	    if(!found && (enable || value != null)) {
+		Element argument_element = document.createElement(ARGUMENT);
+		argument_element.setAttribute(NAME, name);
+		argument_element.setAttribute(ENABLED, (enable ? TRUE : FALSE));
+		// Now we set the value, depending or what it is.
+		if(value == null) {
+		    // Nothing to do.
+		}
+		else {
+		    argument_element.appendChild(document.createTextNode((String)value));
+		}
+		values_element.appendChild(argument_element);
+	    }
+	    arguments = null;
+	    document = null;
+	    // Make sure the collection knows to save.
+	    Gatherer.c_man.getCollection().setSaved(false);
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+    }
+
+ 
+    private String getValue(String name, boolean is_enabled) {
+	String result = null;
+	try {
+	    NodeList arguments = values_element.getElementsByTagName(ARGUMENT);
+	    for(int i = 0; result == null && i < arguments.getLength(); i++) {
+		Element argument_element = (Element) arguments.item(i);
+		// Is this the argument we want.
+		if(argument_element.getAttribute(NAME).equalsIgnoreCase(name)) {
+		    // Are we simply determining if this argument is enabled
+		    if(is_enabled) {
+			result = argument_element.getAttribute(ENABLED);
+		    }
+		    else {
+			String argument_value = XMLTools.getValue(argument_element);
+			if(argument_value != null) {
+			    result = argument_value;
+			}
+			argument_value = null;
+		    }
+		}
+		argument_element = null;
+	    }
+	    arguments = null;
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+	return result;
+    }
+
+
+    private Element loadArguments(String filename, String lang) {
+	Element arguments_element = null;
+	InputStream input_stream = null;
+
+	// Run the required program.
+	try {
+	    String args[];
+	    if (Gatherer.isGsdlRemote) {
+		    String launch  = Gatherer.cgiBase + "launch";
+		    launch += "?cmd=" + filename;
+		    launch += "&xml=&language="+lang;
+
+		    System.err.println("*** launch = " + launch);
+
+		    URL launch_url = new URL(launch);
+		    URLConnection launch_connection = launch_url.openConnection();
+		    input_stream = launch_connection.getInputStream();
+	    }
+	    else {
+		if(Utility.isWindows()) {
+		    args = new String[6];
+		    args[0] = Configuration.perl_path;
+		    args[1] = "-S";
+		    args[2] = LocalGreenstone.getBinScriptDirectoryPath() + filename;
+		    args[3] = "-xml";
+		    args[4] = "-language";
+		    args[5] = lang;
+		}
+		else {
+		    args = new String[4];
+		    args[0] = LocalGreenstone.getBinScriptDirectoryPath() + filename;
+		    args[1] = "-xml";
+		    args[2] = "-language";
+		    args[3] = lang;
+		}
+
+		// Create the process.
+		Runtime runtime = Runtime.getRuntime();
+		Process process = runtime.exec(args);
+
+		input_stream = process.getErrorStream();
+	    }
+
+	    Document document = XMLTools.parseXML(input_stream);
+	    arguments_element = document.getDocumentElement();
+	}
+	catch (Exception error) {
+	    DebugStream.println("Error in ScriptOptions.loadArguments(): " + error);
+	    DebugStream.printStackTrace(error);
+	}
+	return arguments_element;
+    }
+
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ActionRecorderDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ActionRecorderDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ActionRecorderDialog.java	(revision 10506)
@@ -0,0 +1,2135 @@
+package org.greenstone.gatherer.feedback;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.tree.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import java.io.*;
+import java.awt.image.*;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+import javax.swing.border.*;
+import java.text.*;
+
+import org.greenstone.gatherer.util.JarTools;
+
+/**
+ * This is the special class listener. 
+ * <p>This class will record all the action did to any of the
+ * component inside the window that were open by the application. 
+ * <br> This listener will start listening since the beginning of the application 
+ * until the user quits from the application. It will record :
+ * <br>1. All the information about the window and its components where the action occured.
+ * <br>2. All the information about all windows and its components that were open when the action occured.
+ * <br>Note : point 1 and 2 only start when user wants to send feedback.
+ * <br>3. The action's command the user did.
+ * <br>4. The date of when the action occured.
+ * <br><br>The history of the action will be stored in history.log file, which then will be compressed
+ * to a zip file called MyZipFile.zip.</p>
+ * <p>The listener this class implements are only the listener interface that a javax.swing.* component
+ * could have as stated in API.Some of the listener however is not implemented here as it is considered the event
+ * listened by those listener are not essential to be recorded as they not making any major changes
+ * to the application.</p> 
+ * <p>This listener will only record maximum last 60 instructions user did to the application.</p>
+ * <p>In this class also we can add some stuff globally through out all the window open by
+ * the application.
+ * <br>This is the class will add a menu called Feedback through out all the window of type JFrame or JDialog
+ * open by the application.This menu will allow user to either sending feedback or viewing the history
+ * of all the action user did so far.
+ * @author Veronica Liesaputra
+ */
+public class ActionRecorderDialog
+    implements ActionListener,TreeModelListener,ItemListener,ListDataListener,ChangeListener,
+	       ListSelectionListener,MenuListener,TableColumnModelListener,TreeSelectionListener
+{
+    /**
+     * This hold the title of the window where the action occured.
+     */
+    private String myframe;
+
+    /**
+     * This hold the title of the window where user called send feedback.
+     */
+    private String feedbackframe;
+
+    /**
+     * This hold the instance of ComponentInformation to get all the information inside a window.
+     */
+    private ComponentInformation compInfo;
+    
+    /**
+     * This will hold a record of the action that user just did at the moment.
+     */
+    private History log;
+
+    /**
+     * This will reference to the window where the action occured.
+     */
+    private Window point;
+   
+    /**
+     * This hold the vector of all the History instances of all the record of action user did
+     * so far.
+     * This vector will hold the history of all the 30 actions user just did.
+     * There are 2 situation for this vector :
+     * <br>1. Before user choose to send feedback.
+     * <br>Here, If we want to add another record to the vector when the vector size already 30 then,
+     * all the 30 records inside the vector will be saved in the temp_history.log file. The vector will
+     * be cleared and then added with the new record.
+     * <br>If the user quits the application, then whats in the vector will be saved to history.log file.
+     * <br>2. After user choose to send feedback.
+     * <br>When user choose to send feedback,then what happen is what ever inside the vector at the moment
+     * will be saved to history.log file and then vector will be cleared and it will add the new instruction.
+     * <br> If we want to add another record to the vector when the vector size already 30 then,
+     * all the 30 records inside the vector will be saved in the temp_feedbackhist.log file. The vector will
+     * be cleared and then added with the new record.
+     * <br> If the user finished with the feedback then it will cleared all the vector and load the vector
+     * inside the history.log to it and add the new record to the vector.
+     * <br> If the user quits the application, then whats in the vector will not be saved.
+     */
+    private static Vector vector;
+
+    /**
+     * This is the flag to tell whether or not the image for the window where the action occured is
+     * finished being added properly to the appropriate record.
+     * If savefinish = true then it means that the thread of adding image to the record stop, otherwise
+     * it means its not yet finished so don't stop the thread.
+     */
+    private static boolean savefinish = true;
+
+    /**
+     * This is the thread that contains all the code that the application should be when the user exiting
+     * the application.
+     */
+    private Thread writeThread;
+
+    /**
+     * This is the thread that contains all the code to add the image of the window where the action
+     * occured to the proper record.
+     * This thread will stop if savefinish = true.
+     */
+    private Thread saveThread;
+
+    /**
+     * This is the runtime of this application.
+     */
+    private Runtime run;
+
+    /**
+     * This variable will hold the resource of the words that is stored in feedback.properties file.
+     * The calling using messages.getString(someString) will caused someString to be translated
+     * into some other string that is hold in that file.usually it will caused it to be translated
+     * to the language that the user use or choose to have as stated in Locale.
+     */
+    private static ResourceBundle messages;
+
+    /**
+     * This is an instance of ScreenShot that will allow this application to take screen shot of the whole
+     * screen or just the screen shot of the window where the actions occured.
+     */
+    private ScreenShot sh;
+
+    /**
+     * This HashMap stored the pair of model and its component.
+     * This will allow this listener to know which component the model where the actions occured belongs to.
+     */
+    private HashMap modelHash;
+
+    /**
+     * This is the flag variable to sign that the user start the Reporting Feedback sequence.
+     * If start_rec = false means that the user did not start reporting feedback sequence.
+     * Otherwise, it means the user start reporting feedback sequence, here there will be changes in the
+     * content of the vector used to save all the records.This also will change the appearance of the
+     * window that are currently open by the application. it will make toolbar value = true, rec = true and
+     * stop_rec = false.
+     */
+    private boolean start_rec = false;
+
+    /**
+     * This is the flag variable to sign that the user are now recording the Reporting Feedback sequence.
+     * If rec = true, it means its recording, otherwise its false.It also will decide
+     * the GUI appearance of the window that are currently open by the application.
+     */
+    private boolean rec = false;
+
+    /**
+     * This is the flag variable to sign that user are finished the Reporting Feedback sequence.
+     * If stop_rec = false, then it means user stop the Reporting Feedback sequence.So here, there will
+     * be changes in the vector's content. If rec = true then it will also delete the added toolbar on the currently open
+     * window by the application and its also will delete all the history and file taken when user doing the
+     * Reporting Feedback sequence.
+     */
+    private boolean stop_rec = true;
+
+    /**
+     * This is the thread do task to take history of the actions.
+     */
+    private Thread saveallThread;
+
+    /**
+     * This is the flag to say whether or not the send feedback button been pushed by user.
+     */
+    private boolean start_fd = false;
+
+    /**
+     * This is a blocker to say that user cannot do anything while we taking history.
+     */
+    private MouseListener mouse_blocker_listener = new MouseAdapter() {};
+
+    /**
+     * This is the feedback interface window.
+     */
+    private FeedbackInterface frame;
+
+    /**
+     * This is an instance of CompListener that will add listener to all the components inside it.
+     */
+    private CompListener compList;
+
+    /**
+     * This is the accelerator key (shortcuts key) for taking screenshot.
+     */
+    private KeyStroke shKey;
+
+    /**
+     * This is the accelerator key (shortcuts key) for reporting feedback.
+     */
+    private KeyStroke fdKey;
+
+    /**
+     * This is the accelerator key (shortcuts key) for viewing history.
+     */
+    private KeyStroke histKey;
+
+    /**
+     * This is the accelerator key (shortcuts key) for sending feedback straight away.
+     */
+    private KeyStroke sndfdKey;
+
+    /**
+     * This is the window that is active at the moment.
+     */
+    private Window activeWindow;
+
+    /**
+     * This is the modal window where user wants to take the screeshot or sending feedback.
+     */
+    private Window modalWindow;
+
+    /**
+     * This constructor will seeting up the data member to its appropriate value.
+     * It will get the vector that are stored in the history.log file and also it will
+     * setup the writeThread.
+     * @param currentLocale is the locale user choose all the text to be displayed as.
+     */
+    public ActionRecorderDialog (Locale currentLocale)
+    {
+	messages = ResourceBundle.getBundle("feedback",currentLocale);
+	setup_UIManager();
+
+	fdKey = KeyStroke.getKeyStroke("F2");
+	histKey = KeyStroke.getKeyStroke("F3");
+	shKey = KeyStroke.getKeyStroke("F5");
+	sndfdKey = KeyStroke.getKeyStroke("F12");
+	/*shKey = KeyStroke.getKeyStroke(KeyEvent.VK_SLASH,InputEvent.CTRL_MASK|
+	  InputEvent.SHIFT_MASK);*/
+
+	final ZipFile zip;
+	zip = new ZipFile();
+	zip.unZipFile();
+	vector = getPrev_log("history.log");
+	sh = new ScreenShot();
+	modelHash = new HashMap();
+	compInfo = new ComponentInformation(this,currentLocale,modelHash);
+        compList = new CompListener(this,modelHash);
+	EventQueue eq;
+	eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
+	eq.push(new MyEventQueue());
+	run = Runtime.getRuntime();
+	Runnable writeRun;
+	writeRun = new Runnable()
+	    {
+		public void run()
+		{
+		    try
+			{
+			    if (stop_rec == true)
+				{
+				    File f;
+				    f = new File("history.log");
+				    FileOutputStream fos;
+				    fos = new FileOutputStream("history.log");
+				    ObjectOutputStream oos;
+				    oos = new ObjectOutputStream(fos);
+				    oos.writeObject(vector);
+				    vector.removeAllElements();
+				    vector = getPrev_log("temp_history.log");
+				    oos.writeObject(vector);
+				    oos.close();
+				    f = new File("temp_history.log");
+				    f.delete();
+				}
+
+			    File f2;
+			    f2 = new File("feedbackhist.log");
+			    f2.delete();
+			    f2 = new File("temp_feedbackhist.log");
+			    f2.delete();
+
+			    zip.sendZipFile();
+			    writeThread = null;
+			}
+		    catch (IOException exp) {}
+		}
+	    };
+
+	writeThread = new Thread(writeRun);
+	run.addShutdownHook(writeThread);
+    }
+
+    /** change the locale for the resource bundle*/
+    public void setLocale(Locale loc) {
+	messages = ResourceBundle.getBundle("feedback",loc);
+    }
+    /**
+     * This method will setup some of the GUI appearance that window should have when the user
+     * choose to start the Reporting Feedback sequence.
+     */
+    public void setup_UIManager ()
+    {
+	// why do you do all this???
+	//UIManager.put("TabbedPane.selected",(new Color(224,240,224)));
+	//UIManager.put("Button.select",(new Color(224,240,224)));
+	//UIManager.put("ScrollBar.background",(new Color(176,208,176)));
+	//UIManager.put("ScrollBar.highlight",(new Color(224,240,224)));
+	//UIManager.put("ScrollBar.thumb",(new Color(224,240,224)));
+	//UIManager.put("ScrollBar.track",(new Color(224,240,224)));
+	//UIManager.put("Tree.textBackground",new Color(224,240,224));
+	//UIManager.put("Label.font",new Font("Dialog",Font.PLAIN,12));
+	//UIManager.put("ComboBox.font",new Font("Dialog",Font.PLAIN,12));
+	//UIManager.put("TextArea.font",new Font("Dialog",Font.PLAIN,12));
+    }
+
+    /**
+     * This method will get the information about all the components inside the window that are
+     * open by the application when the action occured and save it to vector.
+     * @param comp its the component where the user did the action.
+     * @param command its the action's command the user did.
+     */
+    private void saving (final Component comp,final String command)
+    {
+	if ((command.equals(messages.getString("SendFeedback"))) ||
+	    ((command.equals("FastSend")) && (stop_rec == false)))
+	    {
+		start_fd = true;
+	    }
+
+	Runnable saveall;
+	saveall = new Runnable ()
+	    {
+		public void run ()
+		{
+		    try
+			{
+			    Runnable savework;
+			    savework = new Runnable ()
+				{
+				    public void run ()
+				    {
+					Date curr_date;
+					curr_date = new Date();
+					log = new History(curr_date,command);
+
+					if ((start_fd == true)&&(command.equals(messages.getString("WindowOpened"))))
+					    {
+						start_rec = true;
+						rec = true;
+						start_fd = false;
+					    }
+
+					getFrame(comp,command);
+					saveState(command);
+					saveLog();
+
+					if ((point != null) && (rec == true))
+					    {
+						if (command.equals(messages.getString("WindowClosed")))
+						    {
+							if (point instanceof JDialog)
+							    if (((JDialog)point).isModal() == true)
+								if (point == modalWindow)
+								    frame.setComment(false);
+						    }
+					    }
+				    }
+				};
+
+			    SwingUtilities.invokeAndWait(savework);
+			}
+		    catch (Exception ex) {ex.printStackTrace();}
+		}
+	    };
+
+	saveallThread = new Thread(saveall);
+	saveallThread.start();
+    }
+
+    /**
+     * This method will get the screen shot of the window where the actions occured and
+     * add the image also its dimension to the passed record.
+     * It will caused the saveThread to start so it can allows other stuff to be run concurrently
+     * and this thread will be stopped when the screen shot of the window alreadyfinished taken.
+     * @param hst is the record where the image and its dimension should be stored to.
+     */
+    public void saveImage (final History hst)
+    {
+	Runnable saveRun;
+	saveRun = new Runnable()
+	    {
+		History hist = hst;
+		public void run()
+		{
+		    String img,width,height;
+		    Rectangle rect;
+		    int w, h,dimwidth,dimheight;
+		 
+		    if (point != null)
+			{
+			    dimwidth = sh.getWidth();
+			    dimheight = sh.getHeight();
+
+			    w = point.getWidth();
+			    h = point.getHeight();
+
+			    try
+				{
+				    rect = new Rectangle(point.getLocationOnScreen(),
+							 new Dimension(w,h));
+			    
+				    if (w >= dimwidth)
+					w = dimwidth - 50;
+				    
+				    width = "" +  w;
+				    
+				    if (h >= dimheight)
+					h = dimheight - 50;
+				    
+				    height = "" + h;
+				}
+			    catch (IllegalComponentStateException exp)
+				{
+				    rect = null;
+				    width = null;
+				    height = null;
+				}
+			}
+		    else
+			{
+			    rect = null;
+			    width = null;
+			    height = null;
+			}
+		    
+		    if (rect != null)
+			{
+			    img = sh.getImage(rect);
+			    if (savefinish == true)
+				{
+				    hist.setImage(img,height,width);
+				}
+			}
+		}
+	    };
+	
+	Thread saveThread;
+	saveThread = new Thread(saveRun);
+	saveThread.start();
+    }
+
+    /**
+     * This method will setup the savefinish value.
+     * (Precondition: (save != null))
+     * @param save the value savefinish should have.
+     */
+    public static void setSavefinish (boolean save)
+    {
+	savefinish = save;
+    }
+
+
+    /**
+     * This method will make the JMenu that is should be added to all the
+     * window opened by the application.
+     * <br>If rec = false then the JMenu will give user option to start the Reporting Feedback sequence
+     * or Sending feedback or to view the history of actions they have done so far.
+     * <br>If rec = true then the JMenu will only give user option to view the history of actions
+     * they have done so far or sending feedback or taking screenshot.
+     * @return JMenu that should be added to all window open.
+     */
+    public JMenu makeMenu ()
+    {
+	JMenu menu;
+	JMenuItem item,item2,item3;
+	ImageIcon icon,icon2,icon3;
+
+	icon3 = JarTools.getImage("fastsend.gif");
+	item3 = new JMenuItem(messages.getString("SendFeedback"), 
+			      new ImageIcon(icon3.getImage().getScaledInstance
+					    (20,20,Image.SCALE_SMOOTH)));
+	item3.setActionCommand("FastSend");
+	item3.addActionListener(this);
+	item3.setMnemonic(KeyEvent.VK_N);
+	item3.setAccelerator(sndfdKey);
+	item3.setToolTipText("Send feedback now");
+
+	item = null;
+
+	if (rec == false)
+	    {
+		icon = JarTools.getImage("feedback.gif");
+		item = new JMenuItem("Report Feedback",
+				     new ImageIcon(icon.getImage().getScaledInstance
+						   (20,20,Image.SCALE_SMOOTH)));
+		item.setActionCommand(messages.getString("SendFeedback"));
+		item.addActionListener(this);
+		item.setMnemonic(KeyEvent.VK_F);
+		item.setAccelerator(fdKey);
+		item.setToolTipText("Report feedback");
+	    }
+	else
+	    {
+		icon = JarTools.getImage("camera.gif");
+		item = new JMenuItem(messages.getString("ScreenShot"),
+				     new ImageIcon(icon.getImage().getScaledInstance
+						   (20,20,Image.SCALE_SMOOTH)));
+		item.setActionCommand("ScreenShot");
+		item.setMnemonic(KeyEvent.VK_S);
+		item.addActionListener(this);
+		item.setAccelerator(shKey);
+		item.setToolTipText("Take screenshot of the whole screen.");
+	    }
+
+	icon2 = JarTools.getImage("history.gif");
+	item2 = new JMenuItem(messages.getString("LookHistory"),
+			      new ImageIcon(icon2.getImage().getScaledInstance
+					    (20,20,Image.SCALE_SMOOTH)));
+	item2.setActionCommand(messages.getString("LookHistory"));
+	item2.addActionListener(this);
+	item2.setMnemonic(KeyEvent.VK_H);
+	item2.setAccelerator(histKey);
+	item2.setToolTipText(messages.getString("LookHistoryButton"));
+
+	menu = new JMenu (messages.getString("Feedback"));
+	menu.setMnemonic(KeyEvent.VK_D);
+
+
+	if (item != null)
+	    menu.add(item);
+
+	menu.add(item3);
+
+	menu.add(item2);
+
+	if (rec == true)
+	    menu.setBackground(new Color(176,209,217));
+	else
+	    menu.setBackground(new Color(204,204,204));
+
+	return menu;
+    }
+
+    public void refreshLocationAndSize(Window window) {
+
+	window.setLocation(window.getX(),window.getY());
+	
+	Toolkit kit;
+	kit = Toolkit.getDefaultToolkit();
+	Dimension screenSize;
+	screenSize = kit.getScreenSize();
+	int screenHeight;
+	screenHeight = screenSize.height;
+	int screenWidth;
+	screenWidth = screenSize.width;
+	
+	if ((window.getSize().width > screenWidth) &&
+	    (window.getSize().height > screenHeight)) {
+	    window.setSize(window.getPreferredSize());
+	}
+    }
+
+
+    /**
+     * This method will setup the GUI that this window should have at the moment.
+     * If start_rec is true then JMenu don't have the option to start Reporting Feedback sequence in it.
+     * If stop_rec is true and rec is true then JMenu there should be an option to start Reporting Feedback sequence in it.
+     * The JMenu will only be affected window of type JDialog and JFrame only.
+     * (Precondition: (window != null))
+     * @param window its the window that we want to set the GUI
+     */
+    public void setUI (Window window)
+    {	
+	if (start_rec == true) {
+	    if (window instanceof JFrame) {
+		JFrame a;
+		a = (JFrame) window;
+		
+		JMenuBar menuBar;
+		menuBar = a.getJMenuBar();
+		
+		if (menuBar != null) {
+		    
+		    JMenu temp_menu;
+		    temp_menu = menuBar.getMenu(menuBar.getMenuCount() - 1);
+		    temp_menu.setBackground(new Color(176,209,217));
+		    temp_menu.remove(0);
+		    
+		    JMenuItem item;
+		    ImageIcon icon;
+		    icon = JarTools.getImage("camera.gif");
+		    item = new JMenuItem(messages.getString("ScreenShot"),
+					 new ImageIcon(icon.getImage().getScaledInstance
+						       (20,20,Image.SCALE_SMOOTH)));
+		    item.setActionCommand("ScreenShot");
+		    item.setMnemonic(KeyEvent.VK_S);
+		    item.addActionListener(this);
+		    item.setAccelerator(shKey);
+		    item.setToolTipText("Take screenshot of this window");
+		    
+		    temp_menu.insert(item,0);
+		}
+		
+		refreshLocationAndSize(a);
+		a.validate();
+		a.repaint();
+	    }
+	    else if (window instanceof JDialog) {
+		
+		JDialog a;
+		a = (JDialog) window;
+		JMenuBar menuBar;
+		menuBar = a.getJMenuBar();
+		
+		if (menuBar != null) {
+		    
+		    JMenu temp_menu;
+		    temp_menu = menuBar.getMenu(menuBar.getMenuCount() - 1);
+		    temp_menu.setBackground(new Color(176,209,217));
+		    temp_menu.remove(0);
+		    
+		    JMenuItem item;
+		    ImageIcon icon;
+		    icon = JarTools.getImage("camera.gif");
+		    item = new JMenuItem(messages.getString("ScreenShot"),
+					 new ImageIcon(icon.getImage().getScaledInstance
+						       (20,20,Image.SCALE_SMOOTH)));
+		    item.setActionCommand("ScreenShot");
+		    item.setMnemonic(KeyEvent.VK_S);
+		    item.addActionListener(this);
+		    item.setAccelerator(shKey);
+		    item.setToolTipText("Take screenshot of this window");
+		    
+		    temp_menu.insert(item,0);
+		}
+		refreshLocationAndSize(a);
+		a.validate();
+		a.repaint();	
+	    }
+	    else if (window instanceof JWindow) {
+		JWindow a;
+		a = (JWindow) window;
+		
+		((JComponent) a.getContentPane()).unregisterKeyboardAction(fdKey);
+		
+		((JComponent) a.getContentPane()).registerKeyboardAction(this, "ScreenShot", shKey,JComponent.WHEN_IN_FOCUSED_WINDOW);
+	    }
+	    else
+		return;
+	}
+	else {
+	    
+	    if ((stop_rec == true) && (rec == true)) {
+		
+		if (window instanceof JFrame) {
+		    JFrame a;
+		    a = (JFrame) window;
+		    
+		    JMenuBar menuBar;
+		    menuBar = a.getJMenuBar();
+		    
+		    if (menuBar != null) {
+			
+			JMenu temp_menu;
+			temp_menu = menuBar.getMenu(menuBar.getMenuCount() - 1);
+			temp_menu.setBackground(new Color(204,204,204));
+			temp_menu.remove(0);
+			
+			ImageIcon icon;
+			JMenuItem item;
+			
+			icon = JarTools.getImage("feedback.gif");
+			item = new JMenuItem("Report Feedback", new ImageIcon(icon.getImage().getScaledInstance(20,20,Image.SCALE_SMOOTH)));
+			item.setActionCommand(messages.getString("SendFeedback"));
+			item.addActionListener(this);
+			item.setMnemonic(KeyEvent.VK_F);
+			item.setAccelerator(fdKey);
+			item.setToolTipText(messages.getString("SendFeedbackButton"));
+			
+			temp_menu.insert(item,0);
+		    }
+		    a.setSize(a.getPreferredSize());
+		    a.validate();
+		    a.repaint();
+		}
+		else if (window instanceof JDialog) {
+		    JDialog a;
+		    a = (JDialog) window;
+		    
+		    JMenuBar menuBar;
+		    menuBar = a.getJMenuBar();
+		    
+		    if (menuBar != null) {
+			
+			JMenu temp_menu;
+			temp_menu = menuBar.getMenu(menuBar.getMenuCount() - 1);
+			temp_menu.setBackground(new Color(204,204,204));
+			temp_menu.remove(0);
+			
+			ImageIcon icon;
+			JMenuItem item;
+			
+			icon = JarTools.getImage("feedback.gif");
+			item = new JMenuItem("Report Feedback", new ImageIcon(icon.getImage().getScaledInstance(20,20,Image.SCALE_SMOOTH)));
+			item.setActionCommand(messages.getString("SendFeedback"));
+			item.addActionListener(this);
+			item.setMnemonic(KeyEvent.VK_F);
+			item.setAccelerator(fdKey);
+			item.setToolTipText(messages.getString("SendFeedbackButton"));
+			
+			temp_menu.insert(item,0);
+		    }
+		    a.setSize(a.getPreferredSize());
+		    a.validate();
+		    a.repaint();
+		}
+		else if (window instanceof JWindow) {
+		    JWindow a;
+		    a = (JWindow) window;
+		    
+		    ((JComponent) a.getContentPane()).registerKeyboardAction(this, messages.getString("SendFeedback"), fdKey, JComponent.WHEN_IN_FOCUSED_WINDOW);
+		    
+		    ((JComponent) a.getContentPane()).unregisterKeyboardAction(shKey);
+		    
+		}
+		else
+		    return;
+	    }
+	    else
+		return;
+	}
+    }
+    
+    /**
+     * This will make an Window[] convert to ArrayList that contain list of Window.
+     * (Precondition: (windows != null))
+     * @param windows the array that we want to convert to ArrayList
+     * @return        the array list that contains all object in array windows.
+     */
+    public ArrayList addToArrayList (Window[] windows,ArrayList arr)
+    {
+	int i;
+
+	for (i = 0 ; i < windows.length ; i++)
+	    {
+		arr.add(windows[i]);
+	    }
+	
+	return arr;
+    }
+
+    /**
+     * This method will get all the information of the window that are currently open when the action
+     * occured and these windows are not the window where the action occured.
+     * It will add these windows information to the current record and it will also setting up the 
+     * GUI for each of these windows.
+     * @param command the action's command user did.
+     */
+    public void saveState(String command)
+    {
+	Window[] frame_windows;
+	ArrayList windows;
+	Frame[] frames;
+	int i,j;
+
+	if (log == null)
+	    return;
+	
+	windows = new ArrayList();
+
+	frames = Frame.getFrames();
+	for (i = 0 ; i<frames.length;i++) 
+	    {
+		frame_windows = frames[i].getOwnedWindows();
+		windows = addToArrayList(frame_windows,windows);
+		
+		for (j = 0;j < frame_windows.length ; j++)
+		    {
+			Window window;
+			window = frame_windows[j];
+
+			if (window == point)
+			    {
+				Container cont;
+				cont = window.getParent();
+
+				if ((cont != null) && (cont instanceof Window) &&
+				    (windows.contains(cont) == false)&&(cont != point))
+				    {
+					if (cont instanceof ReportDetails.View) {}
+					else if (cont instanceof Movie) {}
+					else
+					    {
+						setUI((Window) cont);
+						
+						/*if (rec == true)
+						    {
+							log.addComponent(compInfo.getInside((Window) cont),
+									 messages.getString("CurrentlyOpenWindow"));
+						    }
+						    else*/
+						    compList.getInside((Window) cont);
+						
+						windows.add(cont);
+					    }
+				    }	
+				else
+				    {}
+			    }
+			else
+			    {
+				if (window instanceof ReportDetails.View) {}
+				else if (window instanceof Movie) {}
+				else
+				    {
+					if ((window != null) && (window != point))
+					    {
+						setUI(window);
+						
+						if (rec == true)
+						    {
+							log.addComponent(compInfo.getInside((Window) window),
+									 messages.getString("CurrentlyOpenWindow"));
+						    }
+						else
+						    compList.getInside((Window) window);
+						
+						Container cont;
+						cont = window.getParent();
+						
+						if ((cont != null) && (cont instanceof Window) &&
+						    (cont != point) && (windows.contains(cont) == false))
+						    {
+							if (cont instanceof ReportDetails.View) {}
+							else if (cont instanceof Movie) {}
+							else
+							    {
+								setUI((Window)cont);
+								
+								/*if (rec == true)
+								    {
+									log.addComponent(compInfo.getInside((Window) cont),
+											 messages.getString("CurrentlyOpenWindow"));
+								    }
+								    else*/
+								    compList.getInside((Window) cont);
+
+								windows.add(cont);
+							    }
+						    }
+						else {}
+					    }
+				    }
+			    }
+		    }
+	    }
+    }
+
+    /**
+     * This method will get all the information about the window where the actions occured and it also will setting up
+     * how hthe GUI should look like in this window and it will also take the image of this window.
+     * @param comp is the component where the actions happened.
+     * @param command is the command of user's action
+     */
+    public void getFrame (Component comp,String command)
+    {
+	boolean cls;
+	
+	cls = false;
+	point = null;
+	
+	Container frame; 
+	myframe = null;
+	
+	if (comp == null)
+	    return;
+	else if (comp instanceof Window)
+	    frame = (Container) comp;
+	else
+	    frame = SwingUtilities.getWindowAncestor(comp);
+	
+	if (frame instanceof Window)
+	    {
+		JMenu menu;
+		point = (Window) frame;
+
+		point.addMouseListener(mouse_blocker_listener);
+		point.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+
+		
+		if ((frame instanceof ReportDetails.View)||
+		    (frame instanceof Movie))
+		    {
+			log = null;
+			return;
+		    }
+		
+		if (command.equals(messages.getString("WindowClosed")))
+		    {
+			cls = true;
+			if (frame instanceof FeedbackInterface)
+			    {
+				stop_rec = true;
+			    }
+			else
+			    {}
+		    }
+		
+		if  (command.equals(messages.getString("WindowOpened")))
+		    {
+			menu = makeMenu();
+		    }
+		else
+		    {
+			menu = null;
+		    }
+		
+		if (frame instanceof JFrame)
+		    {
+			JFrame a;
+			a = (JFrame) frame;
+			
+			myframe = a.getTitle();
+			
+			if (menu != null)
+			    {
+				JMenuBar menuBar;
+				menuBar = a.getJMenuBar();
+				
+				if (menuBar == null)
+				    {
+					menuBar = new JMenuBar();
+					menuBar.add(menu);
+					a.setJMenuBar(menuBar);
+				    }
+				else
+				    menuBar.add(menu);
+			    }
+			
+			if ((menu != null))
+			    {
+				refreshLocationAndSize(a);
+				a.validate();
+				a.repaint();
+			    }
+		    }
+		else if (frame instanceof JDialog)
+		    {   
+			JDialog a;
+			a = (JDialog) frame;
+			
+			myframe = a.getTitle();
+			
+			if (menu != null)
+			    {
+				JMenuBar menuBar;
+				menuBar = a.getJMenuBar();
+				
+				if (menuBar == null)
+				    {
+					menuBar = new JMenuBar();
+					menuBar.add(menu);
+					a.setJMenuBar(menuBar);
+				    }
+				else
+				    menuBar.add(menu);
+			    }
+		    
+			if ((menu != null))
+			    {
+				refreshLocationAndSize(a);
+				a.validate();
+				a.repaint();
+			    }
+		    }
+		else if (frame instanceof JWindow)
+		    {
+			JWindow a;
+			a = (JWindow) frame;
+			
+			if (menu != null)
+			    {
+				((JComponent) a.getContentPane()).registerKeyboardAction(this,
+											 messages.getString("LookHistory"),
+											 histKey,
+											 JComponent.WHEN_IN_FOCUSED_WINDOW);
+				
+				if (rec == false)
+				    {
+					((JComponent) a.getContentPane()).registerKeyboardAction(this,
+												 messages.getString("SendFeedback"),
+												 fdKey,
+												 JComponent.WHEN_IN_FOCUSED_WINDOW);
+					
+					((JComponent) a.getContentPane()).unregisterKeyboardAction(shKey);
+				    }
+				else
+				    {
+					((JComponent) a.getContentPane()).unregisterKeyboardAction(fdKey);
+					
+					((JComponent) a.getContentPane()).registerKeyboardAction(this,
+												 "ScreenShot",
+												shKey,
+												 JComponent.WHEN_IN_FOCUSED_WINDOW);
+				    }
+			    }
+
+			if (cls == true)
+			    {
+				((JComponent) a.getContentPane()).unregisterKeyboardAction(fdKey);
+				
+				((JComponent) a.getContentPane()).unregisterKeyboardAction(shKey);
+			    }
+		    }
+		
+		/*if ((command.equals(messages.getString("WindowClosed")))||
+		  (log == null))
+		  {}
+		  else
+		  saveImage(log);*/
+
+		/*if (rec == true)
+		    log.addComponent(compInfo.getInside(point),command);
+		    else*/
+		    compList.getInside(point);
+
+		if (myframe == null)
+		    myframe = " ";
+		
+		log.setTitle(myframe);
+		
+		return;
+	    }
+	else
+	    return;
+    }
+
+    /**
+     * This method will add the current record to the vector.
+     */
+    public void saveLog()
+    {
+	if (start_rec == true)
+	    {
+		save_HistLog("history.log");
+		vector.removeAllElements();
+		System.gc();
+		start_rec = false;
+		stop_rec = false;
+		rec = true;
+	    }
+	
+	if (log != null)
+	    vector.add(0,log);
+
+	if (vector.size() > 30)
+	    {
+		if (rec == false)
+		    {
+			save_tempHistLog("history.log");
+		    }
+		else
+		    save_tempHistLog("feedbackhist.log");
+		vector.removeAllElements();
+		//vector.removeElementAt(vector.size() - 1);
+		System.gc();
+	    }
+
+	if ((rec == true) && (stop_rec == true))
+	    {
+		save_HistLog("feedbackhist.log");
+		vector.removeAllElements();
+		System.gc();
+		vector = getPrev_log("history.log");
+		File f2;
+		f2 = new File("feedbackhist.log");
+		f2.delete();
+		f2 = new File("temp_feedbackhist.log");
+		f2.delete();
+		start_rec = false;
+		stop_rec = true;
+		rec = false;
+	    }
+
+	if (point != null)
+	    {
+		point.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+		point.removeMouseListener(mouse_blocker_listener);
+	    }
+    }
+
+    /**
+     * This method will save whatever in the vector at the moment to a file
+     * with the specified filename.
+     * Then it will also save the vector inside the file with the name "temp_"
+     * concatenated with the specified filename into it.
+     * (Precondition : (filename != null))
+     * @param filename its the name of the file where the vector should be saved.
+     */
+    public void save_HistLog(String filename)
+    {
+	 try 
+	     {
+		 File f;
+		 f = new File(filename);
+		 FileOutputStream fos;
+		 fos = new FileOutputStream(f);
+		 ObjectOutputStream oos;
+		 oos = new ObjectOutputStream(fos);
+		 oos.writeObject(vector);
+		 vector.removeAllElements();
+		 System.gc();
+		 vector = getPrev_log("temp_"+ filename);
+		 oos.writeObject(vector);
+		 oos.close();
+		 f = new File("temp_" + filename);
+		 f.delete();
+		 writeThread = null;
+	     }
+	 catch (IOException exp) {}
+    }
+   
+    /**
+     * This method will save whatever in the vector at the moment to a file with a 
+     * name "temp_" concatenated with the specified filename into it.
+     * (Precondition : (filename != null))
+     * @param filename its part of the name of the file where the vector should be saved.
+     */
+    public void save_tempHistLog(String filename)
+    {
+	try
+	    {
+		File f;
+		f = new File("temp_"+ filename);
+		FileOutputStream fos;
+		fos = new FileOutputStream(f);
+		ObjectOutputStream oos;
+		oos = new ObjectOutputStream(fos);
+		oos.writeObject(vector);
+		oos.close();
+	    }
+	catch (IOException exp) {}
+    }
+
+    /**
+     * This method will get vector that is stored in a file with the specified filename and
+     * it will also save the second vector in that file to a file with a name
+     * temp_history.log.
+     * If file with the specified filename does not exist then it will return a new vector.
+     * (Precondition : (filename != null))
+     * @param filename is the name of the file where we want to get the vector.
+     * @return         the first vector saved in the file with the specified filename.
+     */
+    public Vector getPrev_log(String filename)
+    {
+	Vector stack;
+	ObjectInputStream ois;
+	stack = null;
+	try
+	    {
+		File f;
+		f = new File(filename);
+		if (f.exists() == true)
+		    {
+			FileInputStream fis;
+			fis = new FileInputStream(f);
+			ois = new ObjectInputStream(fis);
+			stack = (Vector) ois.readObject();
+
+			Vector stack2;
+			stack2 = null;
+
+			try
+			    {
+				stack2 = (Vector) ois.readObject();
+			    }
+			catch (EOFException e) {stack2 = null;}
+			
+			if (stack2 != null)
+			    {
+				File f2;
+				f2 = new File("temp_history.log");
+				FileOutputStream fos;
+				fos = new FileOutputStream(f2);
+				ObjectOutputStream oos;
+				oos = new ObjectOutputStream(fos);
+				oos.writeObject(stack2);
+				oos.close();
+				stack2.removeAllElements();
+				stack2 = null;
+				System.gc();
+			    }
+
+			ois.close();
+			return stack;
+		    }
+		else
+		    stack = new Vector(); 
+	    }
+	catch (IOException exp) {exp.printStackTrace();}
+	catch (ClassNotFoundException exp2) {System.out.println("class exp");}
+	
+	return stack;
+    }
+ 
+    /**
+     * This method will make sure that there is something running at the moment.
+     */
+    private static void ensureEventThread()
+    {
+	if (SwingUtilities.isEventDispatchThread())
+	    {
+		return;
+	    }
+	throw new RuntimeException("something running");
+    }
+    
+    /**
+     * This method will called the Conformation window to show up.
+     * @param err_array this is the array containing all the information taken when user doing the Feedback form.
+     * @param imgFile this is the array conataining the String representation of the images taken when user doing the 
+     *                Feedback form.
+     */
+    /*public void getVector(String[] err_array,String[] imgFile)
+    {
+	Conformation rd;
+	rd = new Conformation(vector,err_array,imgFile,messages);
+	return;
+	}*/
+
+    /**
+     * This method will get the vector that hold the history.
+     * @return the vector that hold the history stored so far.
+     */
+    public Vector getVector()
+    {
+	return vector;
+    }
+
+    /**
+     * This class will catch the window opened and window closed event.
+     * If an application open or close a window it will be listened by this class so the information
+     * about that window and all the other open window can be took.
+     */
+    class MyEventQueue extends EventQueue
+    { 
+	/**
+	 * This method  will catch the window opened and window closed event.
+	 * If an application open or close a window it will be listened by this class so the information
+	 * about that window and all the other open window can be took.
+	 * @param evt its the event.
+	 */
+	protected void dispatchEvent(AWTEvent evt) 
+	{
+	    super.dispatchEvent(evt);
+	    int id;
+	    id = evt.getID();
+	
+	    if ((id == WindowEvent.WINDOW_OPENED)||(id == WindowEvent.WINDOW_CLOSED))
+		{   
+		    String command;
+		    command = " ";
+		    
+		    if (id == WindowEvent.WINDOW_OPENED) command = messages.getString("WindowOpened");
+		    else if (id == WindowEvent.WINDOW_CLOSED) command = messages.getString("WindowClosed");
+		   
+		    WindowEvent e;
+		    e = (WindowEvent) evt;
+		    Window comp;
+		    comp =  e.getWindow();
+		 
+		    if ((comp instanceof ReportDetails.View)||
+			(comp instanceof Movie))
+			return;
+
+		    saving(comp,command);
+		}
+	}
+    }
+
+    /**
+     * This method will take the screenshot of the whole screen.
+     * @param p the window where user select to take screenshot.
+     * @return  the screenshot image.
+     */
+    //public byte[] recreateEvent (final Window p)
+    public BufferedImage recreateEvent (final Window p)
+    {
+	setup_UIManager();
+	Rectangle rect;
+	int w, h;
+	
+	if (p != null)
+	    {
+		w = p.getWidth();
+		h = p.getHeight();
+		
+		try
+		    {
+			rect = new Rectangle(p.getLocationOnScreen(),
+				 	     new Dimension(w,h));
+		    }
+		catch (IllegalComponentStateException exp)
+		    {
+			rect = null;
+		    }
+	    }
+	else
+	    {
+		rect = null;
+	    }
+	
+	if (rect != null)
+	    {
+		//byte[] img;
+		BufferedImage img;
+		img = sh.captureScreen();
+		
+		return img;
+	    }
+	else
+	    return null;
+    }
+
+    /**
+     * This method will listen to any action event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the ActionEvent.
+     */
+    public void actionPerformed(ActionEvent e)
+    {
+	String command;
+	command = e.getActionCommand();
+	Component comp;
+	comp = (Component)e.getSource();
+	
+	saving(comp,command);
+
+	if (myframe == null)
+	    myframe = " ";
+	
+	if("FastSend".equals(e.getActionCommand()))
+	    {
+		point.addMouseListener(mouse_blocker_listener);
+		point.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+
+		BufferedImage img;
+		boolean modal;
+			
+		modal = false;
+
+		img = recreateEvent(point);
+		
+		if (stop_rec == true)
+		    {
+			feedbackframe = myframe;
+			
+			JDialog.setDefaultLookAndFeelDecorated(true);
+			stop_rec = false;
+			frame = null;
+			frame = new FeedbackInterface(sh,feedbackframe,messages,this);
+			if ((img != null) && (savefinish == true))
+			    {
+				int x,y,w,h,iw,ih;
+				double wrat,hrat;
+				Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
+				
+				iw = (int) (dim.getWidth() - 60);
+				ih = (int) (dim.getHeight() * 0.75) - 50;
+				
+				wrat = iw/((double)dim.getWidth());
+				hrat = ih/((double)dim.getHeight());
+				
+				w = (int) (point.getWidth() * wrat);
+				h = (int) (point.getHeight() * hrat);
+				x = (int) (point.getLocationOnScreen().x * wrat);
+				y = (int) (point.getLocationOnScreen().y * hrat);
+
+				//frame.addScreenPanel(feedbackframe,sh.getBuffImage(),img);
+				frame.addScreenPanel(feedbackframe,img,x,y,w,h);
+			    }
+			frame.setVisible(false);
+		    }
+		else
+		    {
+			if ((img != null) &&(savefinish == true))
+			    {
+				int x,y,w,h,iw,ih;
+				double wrat,hrat;
+				Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
+				
+				iw = (int) (dim.getWidth() - 60);
+				ih = (int) (dim.getHeight() * 0.75) - 50;
+				
+				wrat = iw/((double)dim.getWidth());
+				hrat = ih/((double)dim.getHeight());
+				
+				w = (int) (point.getWidth() * wrat);
+				h = (int) (point.getHeight() * hrat);
+				x = (int) (point.getLocationOnScreen().x * wrat);
+				y = (int) (point.getLocationOnScreen().y * hrat);
+				
+				//frame.addScreenPanel(feedbackframe,sh.getBuffImage(),img);
+				if (point instanceof JDialog)
+				    modal = ((JDialog) point).isModal();
+				
+				feedbackframe = myframe;
+				frame.addScreenPanel(feedbackframe,img,x,y,w,h);
+			    }
+		    }
+		
+		ActionEvent evt;
+		evt = new ActionEvent(frame.send_button,ActionEvent.ACTION_PERFORMED,messages.getString("Send"));
+		
+		frame.actionPerformed(evt);
+
+		point.removeMouseListener(mouse_blocker_listener);
+		point.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));		 
+	    }
+
+	if(messages.getString("SendFeedback").equals(e.getActionCommand()))
+	    {
+		setup_UIManager();
+		//byte[] img;
+		BufferedImage img;
+		boolean modal;
+
+		point.addMouseListener(mouse_blocker_listener);
+		point.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+
+		modal = false;
+		
+		img = recreateEvent(point);
+		feedbackframe = myframe;
+		if (point instanceof JDialog)
+		    modal = ((JDialog)point).isModal();
+			
+		JDialog.setDefaultLookAndFeelDecorated(true);
+		stop_rec = false;
+		frame = null;
+		frame = new FeedbackInterface(sh,feedbackframe,messages,this);
+		if ((img != null) && (savefinish == true))
+		    {
+			int x,y,w,h,iw,ih;
+			double wrat,hrat;
+			Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
+
+			iw = (int) (dim.getWidth() - 60);
+			ih = (int) (dim.getHeight() * 0.75) - 50;
+			
+			wrat = iw/((double)dim.getWidth());
+			hrat = ih/((double)dim.getHeight());
+			
+			w = (int) (point.getWidth() * wrat);
+			h = (int) (point.getHeight() * hrat);
+			x = (int) (point.getLocationOnScreen().x * wrat);
+			y = (int) (point.getLocationOnScreen().y * hrat);
+		
+			//frame.addScreenPanel(feedbackframe,sh.getBuffImage(),img);
+			frame.addScreenPanel(feedbackframe,img,x,y,w,h);
+			frame.setComment(modal);
+			
+			if (modal = true)
+			    {
+				modalWindow = point;
+			    }
+		    }
+
+		point.removeMouseListener(mouse_blocker_listener);
+		point.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));	
+	    }
+	
+	if ("ScreenShot".equals(e.getActionCommand()))
+	    {
+		point.addMouseListener(mouse_blocker_listener);
+		point.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+
+		//byte[] img;
+		BufferedImage img;
+		boolean modal;
+		modal = false;
+		img = recreateEvent(point);
+		
+		if ((img != null) &&(savefinish == true))
+		    {
+			int x,y,w,h,iw,ih;
+			double wrat,hrat;
+			Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
+
+			iw = (int) (dim.getWidth() - 60);
+			ih = (int) (dim.getHeight() * 0.75) - 50;
+			
+			wrat = iw/((double)dim.getWidth());
+			hrat = ih/((double)dim.getHeight());
+			
+			w = (int) (point.getWidth() * wrat);
+			h = (int) (point.getHeight() * hrat);
+			x = (int) (point.getLocationOnScreen().x * wrat);
+			y = (int) (point.getLocationOnScreen().y * hrat);
+
+			//frame.addScreenPanel(feedbackframe,sh.getBuffImage(),img);
+			if (point instanceof JDialog)
+			    modal = ((JDialog) point).isModal();
+
+			feedbackframe = myframe;
+			frame.addScreenPanel(feedbackframe,img,x,y,w,h);
+			frame.setComment(modal);
+
+			if (modal == true)
+			    modalWindow = point;
+		    }
+
+		point.removeMouseListener(mouse_blocker_listener);
+		point.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));	
+	    }
+
+	if (messages.getString("LookHistory").equals(e.getActionCommand()))
+	    {
+		point.addMouseListener(mouse_blocker_listener);
+		point.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+
+		setup_UIManager();
+		ReportDetails rd;
+		rd = new ReportDetails(vector,null,null,messages,rec);
+
+		point.removeMouseListener(mouse_blocker_listener);
+		point.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));	
+	    }
+    }
+   
+
+    /**
+     * This method will listen to any Change event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the ChangeEvent.
+     */
+    public void stateChanged(ChangeEvent e)
+    {
+	String command;
+	command = messages.getString("ChangeState");
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+	
+	saving(comp,command);
+    }
+
+    /**
+     * This method will listen to any tree selection event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the TreeSelectionEvent.
+     */
+    public void valueChanged(TreeSelectionEvent e)
+    {
+	MutableTreeNode node;
+        node = (MutableTreeNode)
+	    (e.getPath().getLastPathComponent());
+	
+	if (node == null) return;
+
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+	
+	String command;
+	command = messages.getString("Node") + " ";
+	if (node instanceof DefaultMutableTreeNode)
+	    command = command + ((DefaultMutableTreeNode)node).getUserObject() + " ";
+	command = command + messages.getString("ValueChanged");
+	
+	saving(comp,command);
+    }
+
+    /**
+     * This method will listen to any tree nodes change in the tree model event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the TreeModelEvent.
+     */
+    public void treeNodesChanged(TreeModelEvent e)
+    {
+	MutableTreeNode node;
+        node = (MutableTreeNode)
+                 (e.getTreePath().getLastPathComponent());
+
+	try {
+            int index;
+	    index = e.getChildIndices()[0];
+            node = (MutableTreeNode)(node.getChildAt(index));
+        } catch (NullPointerException exc) {}
+
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+
+	String command;
+	command = messages.getString("Node");
+
+	if (node instanceof DefaultMutableTreeNode)
+	    command = command + " "  + ((DefaultMutableTreeNode)node).getUserObject();
+
+	command = command + " " + messages.getString("Change");
+	
+	saving(comp,command);
+    }
+
+    /**
+     * This method will listen to any tree nodes inserted in the tree model event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the TreeModelEvent.
+     */
+    public void treeNodesInserted(TreeModelEvent e)
+    {
+	MutableTreeNode node;
+        node = (MutableTreeNode)
+                 (e.getTreePath().getLastPathComponent());
+
+	try {
+            int index;
+	    index = e.getChildIndices()[0];
+            node = (MutableTreeNode)(node.getChildAt(index));
+        } catch (NullPointerException exc) {}
+	
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+	
+	String command;
+	command = messages.getString("Node");
+	if (node instanceof DefaultMutableTreeNode)
+	    command = command + " "  + ((DefaultMutableTreeNode)node).getUserObject();
+
+	command = command + " " + messages.getString("Inserted");
+	
+	saving(comp,command);
+    }
+    
+    /**
+     * This method will listen to any tree nodes removed in the tree model event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the TreeModelEvent.
+     */
+    public void treeNodesRemoved(TreeModelEvent e)
+    {
+	MutableTreeNode node;
+        node = (MutableTreeNode)
+                 (e.getTreePath().getLastPathComponent());
+
+	try {
+            int index;
+	    index = e.getChildIndices()[0];
+            node = (MutableTreeNode)(node.getChildAt(index));
+        } catch (NullPointerException exc) {}
+
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+
+	String command;
+	command = messages.getString("Node");
+	if (node instanceof DefaultMutableTreeNode)
+	    command = command + " "  + ((DefaultMutableTreeNode)node).getUserObject();
+	command = command + " " + messages.getString("Removed");
+	
+	saving(comp,command);
+    }
+ 
+    /**
+     * This method will listen to any tree structure change in the tree model event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the TreeModelEvent.
+     */
+    public void treeStructureChanged(TreeModelEvent e)
+    {
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+	
+	String command;
+	command = messages.getString("TreeStructuredChanged");
+	
+	saving(comp,command);
+    }
+
+    /**
+     * This method will listen to any item state change in the item  event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the ItemEvent.
+     */
+    public void itemStateChanged(ItemEvent e)
+    {
+	Component comp;
+	comp = (Component) e.getSource();
+	String command;
+	command = ((String) e.getItem()) + " " + 
+	    messages.getString("ItemStateChanged");
+
+	saving(comp,command);
+    } 
+
+    /**
+     * This method will listen to any contents change in the list data event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the ListDataEvent.
+     */
+    public void contentsChanged (ListDataEvent e)
+    {
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+	
+	String command;
+	command = messages.getString("ListChanged");
+
+	saving(comp,command);
+    } 
+
+    /**
+     * This method will listen to any interval added in the list data event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the ListDataEvent.
+     */
+    public void intervalAdded (ListDataEvent e)
+    {
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+	
+	String command;
+	command = messages.getString("ListContentsAdded");
+
+	saving(comp,command);
+    } 
+
+    /**
+     * This method will listen to any interval removed in the list data event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the ListDataEvent.
+     */
+    public void intervalRemoved (ListDataEvent e)
+    {
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+
+	String command;
+	command = messages.getString("ListContentRemoved");
+
+	saving(comp,command);
+    }
+
+    /**
+     * This method will listen to any value changed in the list data event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the ListDataEvent.
+     */
+    public void valueChanged (ListSelectionEvent e)
+    {
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+
+	String command;
+	command = messages.getString("ListValueChanged");
+
+	saving(comp,command);
+    }
+
+    /**
+     * This method will listen to any menu canceled in the menu event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the MenuEvent.
+     */
+    public void menuCanceled (MenuEvent e)
+    {
+	Component comp;
+	comp = (Component) e.getSource();
+	String command;
+	command = messages.getString("MenuCanceled");
+
+	saving(comp,command);
+    }
+
+    /**
+     * This method will listen to any menu deselected in the menu event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the MenuEvent.
+     */
+    public void menuDeselected (MenuEvent e)
+     {
+	Component comp;
+	comp = (Component) e.getSource();
+	String command;
+	command = messages.getString("MenuDeselected");
+
+	saving(comp,command);
+    }
+
+    /**
+     * This method will listen to any menu selected in the menu event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the MenuEvent.
+     */
+    public void menuSelected(MenuEvent e)
+    {
+	Component comp;
+	comp = (Component) e.getSource();
+	String command;
+	command = messages.getString("MenuSelected");
+
+	saving(comp,command);
+    }
+
+    /**
+     * This method will listen to any column added in the table column model event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the TableColumnModelEvent.
+     */
+    public void columnAdded (TableColumnModelEvent e)
+    {
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+
+	String command;
+	command = messages.getString("ColumnIndex") + " "  + e.getToIndex() 
+	    + messages.getString("AddedToTable");
+
+	saving(comp,command);
+    }
+
+    public void columnMarginChanged(ChangeEvent e) {}
+
+    /**
+     * This method will listen to any column moved in the table column model event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the TableColumnModelEvent.
+     */
+    public void columnMoved(TableColumnModelEvent e)
+    {
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+
+	String command;
+	command = messages.getString("ColumnIndexFrom") + " " + 
+	    e.getFromIndex() + " " + 
+	    messages.getString("MovedToColumnIndex") + " "  + e.getToIndex() +
+	    " " + messages.getString("InTheTable");
+
+	saving(comp,command);
+    }
+
+    /**
+     * This method will listen to any column removed in the table column model event that occured.
+     * It will allow this special listener class to record all the information inside all the
+     * window open when the action occured.
+     * @param e the TableColumnModelEvent.
+     */
+    public void columnRemoved(TableColumnModelEvent e)
+    {
+	Object obj;
+	obj = e.getSource();
+	
+	Component comp;
+
+	if (obj instanceof Component)
+	    {
+		comp = (Component)e.getSource();
+	    }
+	else
+	    {
+		if (modelHash.containsKey(obj) == true)
+		    {
+			comp = (Component) modelHash.get(obj);
+		    }
+		else
+		    {
+			comp = null;
+			System.out.println("weird" + obj.toString());
+		    }
+	    }
+
+	String command;
+	command = messages.getString("ColumnIndex") + " "  + e.getFromIndex() +
+	    " " + messages.getString("RemovedFromTheTable");
+
+	saving(comp,command);
+    }
+
+    public void columnSelectionChanged(ListSelectionEvent e) {}
+}
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Base64.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Base64.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Base64.java	(revision 10506)
@@ -0,0 +1,1281 @@
+package org.greenstone.gatherer.feedback;
+
+import java.io.*;
+/**
+ * Encodes and decodes to and from Base64 notation.
+ *
+ * <p>
+ * Change Log:
+ * </p>
+ * <ul>
+ *  <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
+ *   encoded data was a single byte.</li>
+ *  <li>v2.0 - I got rid of methods that used booleans to set options. 
+ *   Now everything is more consolidated and cleaner. The code now detects
+ *   when data that's being decoded is gzip-compressed and will decompress it
+ *   automatically. Generally things are cleaner. You'll probably have to
+ *   change some method calls that you were making to support the new
+ *   options format (<tt>int</tt>s that you "OR" together).</li>
+ *  <li>v1.5.1 - Fixed bug when decompressing and decoding to a             
+ *   byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.      
+ *   Added the ability to "suspend" encoding in the Output Stream so        
+ *   you can turn on and off the encoding if you need to embed base64       
+ *   data in an otherwise "normal" stream (like an XML file).</li>  
+ *  <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.
+ *      This helps when using GZIP streams.
+ *      Added the ability to GZip-compress objects before encoding them.</li>
+ *  <li>v1.4 - Added helper methods to read/write files.</li>
+ *  <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
+ *  <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
+ *      where last buffer being read, if not completely full, was not returned.</li>
+ *  <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
+ *  <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
+ * </ul>
+ *
+ * <p>
+ * I am placing this code in the Public Domain. Do with it as you will.
+ * This software comes with no guarantees or warranties but with
+ * plenty of well-wishing instead!
+ * Please visit <a href="http://iharder.net/xmlizable">http://iharder.net/base64</a>
+ * periodically to check for updates or to contribute improvements.
+ * </p>
+ *
+ * @author Robert Harder
+ * @author rob@iharder.net
+ * @version 2.0
+ */
+public class Base64
+{
+    
+/* ********  P U B L I C   F I E L D S  ******** */   
+    
+    
+    /** No options specified. Value is zero. */
+    public final static int NO_OPTIONS = 0;
+    
+    /** Specify encoding. */
+    public final static int ENCODE = 1;
+    
+    
+    /** Specify decoding. */
+    public final static int DECODE = 0;
+    
+    
+    /** Specify that data should be gzip-compressed. */
+    public final static int GZIP = 2;
+    
+    
+    /** Don't break lines when encoding (violates strict Base64 specification) */
+    public final static int DONT_BREAK_LINES = 8;
+    
+    
+/* ********  P R I V A T E   F I E L D S  ******** */  
+    
+    
+    /** Maximum line length (76) of Base64 output. */
+    private final static int MAX_LINE_LENGTH = 76;
+    
+    
+    /** The equals sign (=) as a byte. */
+    private final static byte EQUALS_SIGN = (byte)'=';
+    
+    
+    /** The new line character (\n) as a byte. */
+    private final static byte NEW_LINE = (byte)'\n';
+    
+    
+    /** The 64 valid Base64 values. */
+    private final static byte[] ALPHABET =
+    {
+        (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+        (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+        (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', 
+        (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+        (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+        (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+        (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', 
+        (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+        (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', 
+        (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
+    };
+    
+    /** 
+     * Translates a Base64 value to either its 6-bit reconstruction value
+     * or a negative number indicating some other meaning.
+     **/
+    private final static byte[] DECODABET =
+    {   
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
+        -5,-5,                                      // Whitespace: Tab and Linefeed
+        -9,-9,                                      // Decimal 11 - 12
+        -5,                                         // Whitespace: Carriage Return
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
+        -9,-9,-9,-9,-9,                             // Decimal 27 - 31
+        -5,                                         // Whitespace: Space
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
+        62,                                         // Plus sign at decimal 43
+        -9,-9,-9,                                   // Decimal 44 - 46
+        63,                                         // Slash at decimal 47
+        52,53,54,55,56,57,58,59,60,61,              // Numbers zero through nine
+        -9,-9,-9,                                   // Decimal 58 - 60
+        -1,                                         // Equals sign at decimal 61
+        -9,-9,-9,                                      // Decimal 62 - 64
+        0,1,2,3,4,5,6,7,8,9,10,11,12,13,            // Letters 'A' through 'N'
+        14,15,16,17,18,19,20,21,22,23,24,25,        // Letters 'O' through 'Z'
+        -9,-9,-9,-9,-9,-9,                          // Decimal 91 - 96
+        26,27,28,29,30,31,32,33,34,35,36,37,38,     // Letters 'a' through 'm'
+        39,40,41,42,43,44,45,46,47,48,49,50,51,     // Letters 'n' through 'z'
+        -9,-9,-9,-9                                 // Decimal 123 - 126
+        /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
+    };
+    
+    private final static byte BAD_ENCODING    = -9; // Indicates error in encoding
+    private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
+    private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
+
+    
+    /** Defeats instantiation. */
+    private Base64(){}
+    
+    
+    
+/* ********  E N C O D I N G   M E T H O D S  ******** */    
+    
+    
+    /**
+     * Encodes the first three bytes of array <var>threeBytes</var>
+     * and returns a four-byte array in Base64 notation.
+     *
+     * @param threeBytes the array to convert
+     * @return four byte array in Base64 notation.
+     * @since 1.3
+     */
+    private static byte[] encode3to4( byte[] threeBytes )
+    {   
+        return encode3to4( threeBytes, 3 );
+    }   // end encodeToBytes
+    
+    
+    
+    /**
+     * Encodes up to the first three bytes of array <var>threeBytes</var>
+     * and returns a four-byte array in Base64 notation.
+     * The actual number of significant bytes in your array is
+     * given by <var>numSigBytes</var>.
+     * The array <var>threeBytes</var> needs only be as big as
+     * <var>numSigBytes</var>.
+     *
+     * @param threeBytes the array to convert
+     * @param numSigBytes the number of significant bytes in your array
+     * @return four byte array in Base64 notation.
+     * @since 1.3
+     */
+    private static byte[] encode3to4( byte[] threeBytes, int numSigBytes )
+    {  
+        byte[] dest = new byte[4];
+        encode3to4( threeBytes, 0, numSigBytes, dest, 0 );
+        return dest;
+    }
+    
+     /**
+     * Encodes up to the first three bytes of array <var>threeBytes</var>
+     * and returns a four-byte array in Base64 notation.
+     * The actual number of significant bytes in your array is
+     * given by <var>numSigBytes</var>.
+     * The array <var>threeBytes</var> needs only be as big as
+     * <var>numSigBytes</var>.
+     * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
+     *
+     * @param b4 A reusable byte array to reduce array instantiation
+     * @param threeBytes the array to convert
+     * @param numSigBytes the number of significant bytes in your array
+     * @return four byte array in Base64 notation.
+     * @since 1.5.1
+     */
+    private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes )
+    {
+        encode3to4( threeBytes, 0, numSigBytes, b4, 0 );
+        return b4;
+    }   // end encode3to4
+
+    
+    /**
+     * Encodes up to three bytes of the array <var>source</var>
+     * and writes the resulting four Base64 bytes to <var>destination</var>.
+     * The source and destination arrays can be manipulated
+     * anywhere along their length by specifying 
+     * <var>srcOffset</var> and <var>destOffset</var>.
+     * This method does not check to make sure your arrays
+     * are large enough to accomodate <var>srcOffset</var> + 3 for
+     * the <var>source</var> array or <var>destOffset</var> + 4 for
+     * the <var>destination</var> array.
+     * The actual number of significant bytes in your array is
+     * given by <var>numSigBytes</var>.
+     *
+     * @param source the array to convert
+     * @param srcOffset the index where conversion begins
+     * @param numSigBytes the number of significant bytes in your array
+     * @param destination the array to hold the conversion
+     * @param destOffset the index where output will be put
+     * @return the <var>destination</var> array
+     * @since 1.3
+     */
+    private static byte[] encode3to4( 
+     byte[] source, int srcOffset, int numSigBytes,
+     byte[] destination, int destOffset )
+    {
+        //           1         2         3  
+        // 01234567890123456789012345678901 Bit position
+        // --------000000001111111122222222 Array position from threeBytes
+        // --------|    ||    ||    ||    | Six bit groups to index ALPHABET
+        //          >>18  >>12  >> 6  >> 0  Right shift necessary
+        //                0x3f  0x3f  0x3f  Additional AND
+        
+        // Create buffer with zero-padding if there are only one or two
+        // significant bytes passed in the array.
+        // We have to shift left 24 in order to flush out the 1's that appear
+        // when Java treats a value as negative that is cast from a byte to an int.
+        int inBuff =   ( numSigBytes > 0 ? ((source[ srcOffset     ] << 24) >>>  8) : 0 )
+                     | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
+                     | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
+
+        switch( numSigBytes )
+        {
+            case 3:
+                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
+                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+                destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>>  6) & 0x3f ];
+                destination[ destOffset + 3 ] = ALPHABET[ (inBuff       ) & 0x3f ];
+                return destination;
+                
+            case 2:
+                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
+                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+                destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>>  6) & 0x3f ];
+                destination[ destOffset + 3 ] = EQUALS_SIGN;
+                return destination;
+                
+            case 1:
+                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
+                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+                destination[ destOffset + 2 ] = EQUALS_SIGN;
+                destination[ destOffset + 3 ] = EQUALS_SIGN;
+                return destination;
+                
+            default:
+                return destination;
+        }   // end switch
+    }   // end encode3to4
+    
+    
+    
+    /**
+     * Serializes an object and returns the Base64-encoded
+     * version of that serialized object. If the object
+     * cannot be serialized or there is another error,
+     * the method will return <tt>null</tt>.
+     * The object is not GZip-compressed before being encoded.
+     *
+     * @param serializableObject The object to encode
+     * @return The Base64-encoded object
+     * @since 1.4
+     */
+    public static String encodeObject( java.io.Serializable serializableObject )
+    {
+        return encodeObject( serializableObject, NO_OPTIONS );
+    }   // end encodeObject
+    
+
+
+    /**
+     * Serializes an object and returns the Base64-encoded
+     * version of that serialized object. If the object
+     * cannot be serialized or there is another error,
+     * the method will return <tt>null</tt>.
+     * <p>
+     * Valid options:<pre>
+     *   GZIP: gzip-compresses object before encoding it.
+     *   DONT_BREAK_LINES: don't break lines at 76 characters
+     *     <i>Note: Technically, this makes your encoding non-compliant.</i>
+     * </pre>
+     * <p>
+     * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
+     * <p>
+     * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
+     *
+     * @param serializableObject The object to encode
+     * @param options Specified options
+     * @return The Base64-encoded object
+     * @see Base64#GZIP
+     * @see Base64#DONT_BREAK_LINES
+     * @since 2.0
+     */
+    public static String encodeObject( java.io.Serializable serializableObject, int options )
+    {
+        // Streams
+        java.io.ByteArrayOutputStream  baos  = null; 
+        java.io.OutputStream           b64os = null; 
+        java.io.ObjectOutputStream     oos   = null; 
+        java.util.zip.GZIPOutputStream gzos  = null;
+        
+        // Isolate options
+        int gzip           = (options & GZIP);
+        int dontBreakLines = (options & DONT_BREAK_LINES);
+        
+        try
+        {
+            // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
+            baos  = new java.io.ByteArrayOutputStream();
+            b64os = new Base64.OutputStream( baos, ENCODE | dontBreakLines );
+    
+            // GZip?
+            if( gzip == GZIP )
+            {
+                gzos = new java.util.zip.GZIPOutputStream( b64os );
+                oos  = new java.io.ObjectOutputStream( gzos );
+            }   // end if: gzip
+            else
+                oos   = new java.io.ObjectOutputStream( b64os );
+            
+            oos.writeObject( serializableObject );
+        }   // end try
+        catch( java.io.IOException e )
+        {
+            e.printStackTrace();
+            return null;
+        }   // end catch
+        finally
+        {
+            try{ oos.close();   } catch( Exception e ){}
+            try{ gzos.close();  } catch( Exception e ){}
+            try{ b64os.close(); } catch( Exception e ){}
+            try{ baos.close();  } catch( Exception e ){}
+        }   // end finally
+        
+        return new String( baos.toByteArray() );
+    }   // end encode
+    
+    
+
+    /**
+     * Encodes a byte array into Base64 notation.
+     * Does not GZip-compress data.
+     *
+     * @param source The data to convert
+     * @since 1.4
+     */
+    public static String encodeBytes( byte[] source )
+    {
+        return encodeBytes( source, 0, source.length, NO_OPTIONS );
+    }   // end encodeBytes
+    
+
+
+    /**
+     * Encodes a byte array into Base64 notation.
+     * <p>
+     * Valid options:<pre>
+     *   GZIP: gzip-compresses object before encoding it.
+     *   DONT_BREAK_LINES: don't break lines at 76 characters
+     *     <i>Note: Technically, this makes your encoding non-compliant.</i>
+     * </pre>
+     * <p>
+     * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
+     * <p>
+     * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
+     *
+     *
+     * @param source The data to convert
+     * @param options Specified options
+     * @see Base64#GZIP
+     * @see Base64#DONT_BREAK_LINES
+     * @since 2.0
+     */
+    public static String encodeBytes( byte[] source, int options )
+    {   
+        return encodeBytes( source, 0, source.length, options );
+    }   // end encodeBytes
+    
+    
+    /**
+     * Encodes a byte array into Base64 notation.
+     * Does not GZip-compress data.
+     *
+     * @param source The data to convert
+     * @param off Offset in array where conversion should begin
+     * @param len Length of data to convert
+     * @since 1.4
+     */
+    public static String encodeBytes( byte[] source, int off, int len )
+    {
+        return encodeBytes( source, off, len, NO_OPTIONS );
+    }   // end encodeBytes
+    
+    
+
+    /**
+     * Encodes a byte array into Base64 notation.
+     * <p>
+     * Valid options:<pre>
+     *   GZIP: gzip-compresses object before encoding it.
+     *   DONT_BREAK_LINES: don't break lines at 76 characters
+     *     <i>Note: Technically, this makes your encoding non-compliant.</i>
+     * </pre>
+     * <p>
+     * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
+     * <p>
+     * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
+     *
+     *
+     * @param source The data to convert
+     * @param off Offset in array where conversion should begin
+     * @param len Length of data to convert
+     * @param options Specified options
+     * @see Base64#GZIP
+     * @see Base64#DONT_BREAK_LINES
+     * @since 2.0
+     */
+    public static String encodeBytes( byte[] source, int off, int len, int options )
+    {
+        // Isolate options
+        int dontBreakLines = ( options & DONT_BREAK_LINES );
+        int gzip           = ( options & GZIP   );
+        
+        // Compress?
+        if( gzip == GZIP )
+        {
+            java.io.ByteArrayOutputStream  baos  = null;
+            java.util.zip.GZIPOutputStream gzos  = null;
+            Base64.OutputStream            b64os = null;
+            
+    
+            try
+            {
+                // GZip -> Base64 -> ByteArray
+                baos = new java.io.ByteArrayOutputStream();
+                b64os = new Base64.OutputStream( baos, ENCODE | dontBreakLines );
+                gzos  = new java.util.zip.GZIPOutputStream( b64os ); 
+            
+                gzos.write( source, off, len );
+                gzos.close();
+            }   // end try
+            catch( java.io.IOException e )
+            {
+                e.printStackTrace();
+                return null;
+            }   // end catch
+            finally
+            {
+                try{ gzos.close();  } catch( Exception e ){}
+                try{ b64os.close(); } catch( Exception e ){}
+                try{ baos.close();  } catch( Exception e ){}
+            }   // end finally
+
+            return new String( baos.toByteArray() );
+        }   // end if: compress
+        
+        // Else, don't compress. Better not to use streams at all then.
+        else
+        {
+            // Convert option to boolean in way that code likes it.
+            boolean breakLines = dontBreakLines == 0;
+            
+            int    len43   = len * 4 / 3;
+            byte[] outBuff = new byte[   ( len43 )                      // Main 4:3
+                                       + ( (len % 3) > 0 ? 4 : 0 )      // Account for padding
+                                       + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines      
+            int d = 0;
+            int e = 0;
+            int len2 = len - 2;
+            int lineLength = 0;
+            for( ; d < len2; d+=3, e+=4 )
+            {
+                encode3to4( source, d+off, 3, outBuff, e );
+
+                lineLength += 4;
+                if( breakLines && lineLength == MAX_LINE_LENGTH )
+                {   
+                    outBuff[e+4] = NEW_LINE;
+                    e++;
+                    lineLength = 0;
+                }   // end if: end of line
+            }   // en dfor: each piece of array
+
+            if( d < len )
+            {
+                encode3to4( source, d+off, len - d, outBuff, e );
+                e += 4;
+            }   // end if: some padding needed
+
+            return new String( outBuff, 0, e );
+        }   // end else: don't compress
+        
+    }   // end encodeBytes
+    
+
+    
+    
+    
+/* ********  D E C O D I N G   M E T H O D S  ******** */
+    
+    
+    /**
+     * Decodes the first four bytes of array <var>fourBytes</var>
+     * and returns an array up to three bytes long with the
+     * decoded values.
+     *
+     * @param fourBytes the array with Base64 content
+     * @return array with decoded values
+     * @since 1.3
+     */
+    private static byte[] decode4to3( byte[] fourBytes )
+    {
+        byte[] outBuff1 = new byte[3];
+        int    count    = decode4to3( fourBytes, 0, outBuff1, 0 );
+        byte[] outBuff2 = new byte[ count ];
+        
+        for( int i = 0; i < count; i++ )
+            outBuff2[i] = outBuff1[i];
+        
+        return outBuff2;
+    }
+    
+    
+    
+    
+    /**
+     * Decodes four bytes from array <var>source</var>
+     * and writes the resulting bytes (up to three of them)
+     * to <var>destination</var>.
+     * The source and destination arrays can be manipulated
+     * anywhere along their length by specifying 
+     * <var>srcOffset</var> and <var>destOffset</var>.
+     * This method does not check to make sure your arrays
+     * are large enough to accomodate <var>srcOffset</var> + 4 for
+     * the <var>source</var> array or <var>destOffset</var> + 3 for
+     * the <var>destination</var> array.
+     * This method returns the actual number of bytes that 
+     * were converted from the Base64 encoding.
+     * 
+     *
+     * @param source the array to convert
+     * @param srcOffset the index where conversion begins
+     * @param destination the array to hold the conversion
+     * @param destOffset the index where output will be put
+     * @return the number of decoded bytes converted
+     * @since 1.3
+     */
+    private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset )
+    {
+        // Example: Dk==
+        if( source[ srcOffset + 2] == EQUALS_SIGN )
+        {
+            // Two ways to do the same thing. Don't know which way I like best.
+            //int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] << 24 ) >>>  6 )
+            //              | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
+            int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] & 0xFF ) << 18 )
+                          | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
+            
+            destination[ destOffset ] = (byte)( outBuff >>> 16 );
+            return 1;
+        }
+        
+        // Example: DkL=
+        else if( source[ srcOffset + 3 ] == EQUALS_SIGN )
+        {
+            // Two ways to do the same thing. Don't know which way I like best.
+            //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
+            //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
+            //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
+            int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] & 0xFF ) << 18 )
+                          | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
+                          | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) <<  6 );
+            
+            destination[ destOffset     ] = (byte)( outBuff >>> 16 );
+            destination[ destOffset + 1 ] = (byte)( outBuff >>>  8 );
+            return 2;
+        }
+        
+        // Example: DkLE
+        else
+        {
+            try{
+            // Two ways to do the same thing. Don't know which way I like best.
+            //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
+            //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
+            //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
+            //              | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
+            int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] & 0xFF ) << 18 )
+                          | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
+                          | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) <<  6)
+                          | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF )      );
+
+            
+            destination[ destOffset     ] = (byte)( outBuff >> 16 );
+            destination[ destOffset + 1 ] = (byte)( outBuff >>  8 );
+            destination[ destOffset + 2 ] = (byte)( outBuff       );
+
+            return 3;
+            }catch( Exception e){
+                System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset     ] ]  ) );
+                System.out.println(""+source[srcOffset+1]+  ": " + ( DECODABET[ source[ srcOffset + 1 ] ]  ) );
+                System.out.println(""+source[srcOffset+2]+  ": " + ( DECODABET[ source[ srcOffset + 2 ] ]  ) );
+                System.out.println(""+source[srcOffset+3]+  ": " + ( DECODABET[ source[ srcOffset + 3 ] ]  ) );
+                return -1;
+            }   //e nd catch
+        }
+    }   // end decodeToBytes
+    
+    
+    
+    
+    /**
+     * Very low-level access to decoding ASCII characters in
+     * the form of a byte array. Does not support automatically
+     * gunzipping or any other "fancy" features.
+     *
+     * @param source The Base64 encoded data
+     * @param off    The offset of where to begin decoding
+     * @param len    The length of characters to decode
+     * @return decoded data
+     * @since 1.3
+     */
+    public static byte[] decode( byte[] source, int off, int len )
+    {
+        int    len34   = len * 3 / 4;
+        byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output
+        int    outBuffPosn = 0;
+        
+        byte[] b4        = new byte[4];
+        int    b4Posn    = 0;
+        int    i         = 0;
+        byte   sbiCrop   = 0;
+        byte   sbiDecode = 0;
+        for( i = off; i < off+len; i++ )
+        {
+            sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
+            sbiDecode = DECODABET[ sbiCrop ];
+            
+            if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better
+            {
+                if( sbiDecode >= EQUALS_SIGN_ENC )
+                {
+                    b4[ b4Posn++ ] = sbiCrop;
+                    if( b4Posn > 3 )
+                    {
+                        outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn );
+                        b4Posn = 0;
+                        
+                        // If that was the equals sign, break out of 'for' loop
+                        if( sbiCrop == EQUALS_SIGN )
+                            break;
+                    }   // end if: quartet built
+                    
+                }   // end if: equals sign or better
+                
+            }   // end if: white space, equals sign or better
+            else
+            {
+                System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" );
+                return null;
+            }   // end else: 
+        }   // each input character
+                                   
+        byte[] out = new byte[ outBuffPosn ];
+        System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); 
+        return out;
+    }   // end decode
+    
+    
+    
+    
+    /**
+     * Decodes data from Base64 notation, automatically
+     * detecting gzip-compressed data and decompressing it.
+     *
+     * @param s the string to decode
+     * @return the decoded data
+     * @since 1.4
+     */
+    public static byte[] decode( String s )
+    {   
+        byte[] bytes = s.getBytes();
+        bytes = decode( bytes, 0, bytes.length );
+        
+        // Check to see if it's gzip-compressed
+        // GZIP Magic Two-Byte Number: 0x8b1f (35615)
+        if( bytes.length >= 2 )
+        {
+            
+            int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);       
+            if(
+            bytes != null &&      // In case decoding returned null
+            bytes.length >= 4  && // Don't want to get ArrayIndexOutOfBounds exception
+            java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) 
+            {
+                java.io.ByteArrayInputStream  bais = null;
+                java.util.zip.GZIPInputStream gzis = null;
+                java.io.ByteArrayOutputStream baos = null;
+                byte[] buffer = new byte[2048];
+                int    length = 0;
+
+                try
+                {
+                    baos = new java.io.ByteArrayOutputStream();
+                    bais = new java.io.ByteArrayInputStream( bytes );
+                    gzis = new java.util.zip.GZIPInputStream( bais );
+
+                    while( ( length = gzis.read( buffer ) ) >= 0 )
+                    {
+                        baos.write(buffer,0,length);
+                    }   // end while: reading input
+
+                    // No error? Get new bytes.
+                    bytes = baos.toByteArray();
+
+                }   // end try
+                catch( java.io.IOException e )
+                {
+                    // Just return originally-decoded bytes
+                }   // end catch
+                finally
+                {
+                    try{ baos.close(); } catch( Exception e ){}
+                    try{ gzis.close(); } catch( Exception e ){}
+                    try{ bais.close(); } catch( Exception e ){}
+                }   // end finally
+
+            }   // end if: gzipped
+        }   // end if: bytes.length >= 2
+        
+        return bytes;
+    }   // end decode
+
+
+    
+
+    /**
+     * Attempts to decode Base64 data and deserialize a Java
+     * Object within. Returns <tt>null</tt> if there was an error.
+     *
+     * @param encodedObject The Base64 data to decode
+     * @return The decoded and deserialized object
+     * @since 1.5
+     */
+    public static Object decodeToObject( String encodedObject )
+    {
+        // Decode and gunzip if necessary
+        byte[] objBytes = decode( encodedObject );
+        
+        java.io.ByteArrayInputStream  bais = null;
+        java.io.ObjectInputStream     ois  = null;
+        Object obj = null;
+        
+        try
+        {
+            bais = new java.io.ByteArrayInputStream( objBytes );
+            ois  = new java.io.ObjectInputStream( bais );
+        
+            obj = ois.readObject();
+        }   // end try
+        catch( java.io.IOException e )
+        {
+            e.printStackTrace();
+            obj = null;
+        }   // end catch
+        catch( java.lang.ClassNotFoundException e )
+        {
+            e.printStackTrace();
+            obj = null;
+        }   // end catch
+        finally
+        {
+            try{ bais.close(); } catch( Exception e ){}
+            try{ ois.close();  } catch( Exception e ){}
+        }   // end finally
+        
+        return obj;
+    }   // end decodeObject
+    
+    
+    /* ********  I N N E R   C L A S S   I N P U T S T R E A M  ******** */
+    
+    
+    
+    /**
+     * It will read data from another
+     * {@link java.io.InputStream}, given in the constructor,
+     * and encode/decode to/from Base64 notation on the fly.
+     *
+     * @see Base64
+     * @see java.io.FilterInputStream
+     * @since 1.3
+     */
+    public static class InputStream extends java.io.FilterInputStream
+    {
+        private int     options;        // Options specified
+        private boolean encode;         // Encoding or decoding
+        private int     position;       // Current position in the buffer
+        private byte[]  buffer;         // Small buffer holding converted data
+        private int     bufferLength;   // Length of buffer (3 or 4)
+        private int     numSigBytes;    // Number of meaningful bytes in the buffer
+        private int     lineLength;
+        private boolean breakLines;     // Break lines at less than 80 characters
+        
+        
+        /**
+         * Constructs a InputStream in DECODE mode.
+         *
+         * @param in the {@link java.io.InputStream} from which to read data.
+         * @since 1.3
+         */
+        public InputStream( java.io.InputStream in )
+        {   
+            this( in, DECODE );
+        }   // end constructor
+        
+        
+        /**
+         * Constructs a InputStream in
+         * either ENCODE or DECODE mode.
+         * <p>
+         * Valid options:<pre>
+         *   ENCODE or DECODE: Encode or Decode as data is read.
+         *   DONT_BREAK_LINES: don't break lines at 76 characters
+         *     (only meaningful when encoding)
+         *     <i>Note: Technically, this makes your encoding non-compliant.</i>
+         * </pre>
+         * <p>
+         * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
+         *
+         *
+         * @param in the {@link java.io.InputStream} from which to read data.
+         * @param options Specified options
+         * @see Base64#ENCODE
+         * @see Base64#DECODE
+         * @see Base64#DONT_BREAK_LINES
+         * @since 2.0
+         */
+        public InputStream( java.io.InputStream in, int options )
+        {   
+            super( in );
+            this.options      = options;
+            this.breakLines   = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
+            this.encode       = (options & ENCODE) == ENCODE;
+            this.breakLines = breakLines;
+            this.encode = encode;
+            this.bufferLength = encode ? 4 : 3;
+            this.buffer   = new byte[ bufferLength ];
+            this.position = -1;
+            this.lineLength = 0;
+        }   // end constructor
+        
+        /**
+         * Reads enough of the input stream to convert
+         * to/from Base64 and returns the next byte.
+         *
+         * @return next byte
+         * @since 1.3
+         */
+        public int read() throws java.io.IOException 
+        { 
+            // Do we need to get data?
+            if( position < 0 )
+            {
+                if( encode )
+                {
+                    byte[] b3 = new byte[3];
+                    int numBinaryBytes = 0;
+                    for( int i = 0; i < 3; i++ )
+                    {
+                        try
+                        { 
+                            int b = in.read();
+                            
+                            // If end of stream, b is -1.
+                            if( b >= 0 )
+                            {
+                                b3[i] = (byte)b;
+                                numBinaryBytes++;
+                            }   // end if: not end of stream
+                            
+                        }   // end try: read
+                        catch( java.io.IOException e )
+                        {   
+                            // Only a problem if we got no data at all.
+                            if( i == 0 )
+                                throw e;
+                            
+                        }   // end catch
+                    }   // end for: each needed input byte
+                    
+                    if( numBinaryBytes > 0 )
+                    {
+                        encode3to4( b3, 0, numBinaryBytes, buffer, 0 );
+                        position = 0;
+                        numSigBytes = 4;
+                    }   // end if: got data
+                    else
+                    {
+                        return -1;
+                    }   // end else
+                }   // end if: encoding
+                
+                // Else decoding
+                else
+                {
+                    byte[] b4 = new byte[4];
+                    int i = 0;
+                    for( i = 0; i < 4; i++ )
+                    {
+                        // Read four "meaningful" bytes:
+                        int b = 0;
+                        do{ b = in.read(); }
+                        while( b >= 0 && DECODABET[ b & 0x7f ] <= WHITE_SPACE_ENC );
+                        
+                        if( b < 0 )
+                            break; // Reads a -1 if end of stream
+                        
+                        b4[i] = (byte)b;
+                    }   // end for: each needed input byte
+                    
+                    if( i == 4 )
+                    {
+                        numSigBytes = decode4to3( b4, 0, buffer, 0 );
+                        position = 0;
+                    }   // end if: got four characters
+                    else if( i == 0 ){
+                        return -1;
+                    }   // end else if: also padded correctly
+                    else
+                    {
+                        // Must have broken out from above.
+                        throw new java.io.IOException( "Improperly padded Base64 input." );
+                    }   // end 
+                    
+                }   // end else: decode
+            }   // end else: get data
+            
+            // Got data?
+            if( position >= 0 )
+            {
+                // End of relevant data?
+                if( /*!encode &&*/ position >= numSigBytes )
+                    return -1;
+                
+                if( encode && breakLines && lineLength >= MAX_LINE_LENGTH )
+                {
+                    lineLength = 0;
+                    return '\n';
+                }   // end if
+                else
+                {
+                    lineLength++;   // This isn't important when decoding
+                                    // but throwing an extra "if" seems
+                                    // just as wasteful.
+                    
+                    int b = buffer[ position++ ];
+
+                    if( position >= bufferLength )
+                        position = -1;
+
+                    return b & 0xFF; // This is how you "cast" a byte that's
+                                     // intended to be unsigned.
+                }   // end else
+            }   // end if: position >= 0
+            
+            // Else error
+            else
+            {   
+                // When JDK1.4 is more accepted, use an assertion here.
+                throw new java.io.IOException( "Error in Base64 code reading stream." );
+            }   // end else
+        }   // end read
+        
+        
+        /**
+         * Calls {@link #read} repeatedly until the end of stream
+         * is reached or <var>len</var> bytes are read.
+         * Returns number of bytes read into array or -1 if
+         * end of stream is encountered.
+         *
+         * @param dest array to hold values
+         * @param off offset for array
+         * @param len max number of bytes to read into array
+         * @return bytes read into array or -1 if end of stream is encountered.
+         * @since 1.3
+         */
+        public int read( byte[] dest, int off, int len ) throws java.io.IOException
+        {
+            int i;
+            int b;
+            for( i = 0; i < len; i++ )
+            {
+                b = read();
+                
+                //if( b < 0 && i == 0 )
+                //    return -1;
+                
+                if( b >= 0 )
+                    dest[off + i] = (byte)b;
+                else if( i == 0 )
+                    return -1;
+                else
+                    break; // Out of 'for' loop
+            }   // end for: each byte read
+            return i;
+        }   // end read
+        
+    }   // end inner class InputStream
+    
+    
+    
+    
+    
+    
+    /* ********  I N N E R   C L A S S   O U T P U T S T R E A M  ******** */
+    
+    
+    
+    /**
+     * A OutputStream will write data to another
+     * {@link java.io.OutputStream}, given in the constructor,
+     * and encode/decode to/from Base64 notation on the fly.
+     *
+     * @see Base64
+     * @see java.io.FilterOutputStream
+     * @since 1.3
+     */
+    public static class OutputStream extends java.io.FilterOutputStream
+    {
+        private int     options;
+        private boolean encode;
+        private int     position;
+        private byte[]  buffer;
+        private int     bufferLength;
+        private int     lineLength;
+        private boolean breakLines;
+        private byte[]  b4; // Scratch used in a few places
+        private boolean suspendEncoding;
+        
+        /**
+         * Constructs a OutputStream in ENCODE mode.
+         *
+         * @param out the {@link java.io.OutputStream} to which data will be written.
+         * @since 1.3
+         */
+        public OutputStream( java.io.OutputStream out )
+        {   
+            this( out, ENCODE );
+        }   // end constructor
+        
+        
+        /**
+         * Constructs a OutputStream in
+         * either ENCODE or DECODE mode.
+         * <p>
+         * Valid options:<pre>
+         *   ENCODE or DECODE: Encode or Decode as data is read.
+         *   DONT_BREAK_LINES: don't break lines at 76 characters
+         *     (only meaningful when encoding)
+         *     <i>Note: Technically, this makes your encoding non-compliant.</i>
+         * </pre>
+         * <p>
+         * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
+         *
+         * @param out the {@link java.io.OutputStream} to which data will be written.
+         * @param options Specified options.
+         * @see Base64#ENCODE
+         * @see Base64#DECODE
+         * @see Base64#DONT_BREAK_LINES
+         * @since 1.3
+         */
+        public OutputStream( java.io.OutputStream out, int options )
+        {   
+            super( out );
+            this.options      = options;
+            this.breakLines   = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
+            this.encode       = (options & ENCODE) == ENCODE;
+            this.bufferLength = encode ? 3 : 4;
+            this.buffer       = new byte[ bufferLength ];
+            this.position     = 0;
+            this.lineLength   = 0;
+            this.suspendEncoding = false;
+            this.b4           = new byte[4];
+        }   // end constructor
+        
+        
+        /**
+         * Writes the byte to the output stream after
+         * converting to/from Base64 notation.
+         * When encoding, bytes are buffered three
+         * at a time before the output stream actually
+         * gets a write() call.
+         * When decoding, bytes are buffered four
+         * at a time.
+         *
+         * @param theByte the byte to write
+         * @since 1.3
+         */
+        public void write(int theByte) throws java.io.IOException
+        {
+            // Encoding suspended?
+            if( suspendEncoding )
+            {
+                super.out.write( theByte );
+                return;
+            }   // end if: supsended
+            
+            // Encode?
+            if( encode )
+            {
+                buffer[ position++ ] = (byte)theByte;
+                if( position >= bufferLength )  // Enough to encode.
+                {
+                    out.write( encode3to4( b4, buffer, bufferLength ) );
+
+                    lineLength += 4;
+                    if( breakLines && lineLength >= MAX_LINE_LENGTH )
+                    {
+                        out.write( NEW_LINE );
+                        lineLength = 0;
+                    }   // end if: end of line
+
+                    position = 0;
+                }   // end if: enough to output
+            }   // end if: encoding
+
+            // Else, Decoding
+            else
+            {
+                // Meaningful Base64 character?
+                if( DECODABET[ theByte & 0x7f ] > WHITE_SPACE_ENC )
+                {
+                    buffer[ position++ ] = (byte)theByte;
+                    if( position >= bufferLength )  // Enough to output.
+                    {
+                        int len = Base64.decode4to3( buffer, 0, b4, 0 );
+                        out.write( b4, 0, len );
+                        //out.write( Base64.decode4to3( buffer ) );
+                        position = 0;
+                    }   // end if: enough to output
+                }   // end if: meaningful base64 character
+                else if( DECODABET[ theByte & 0x7f ] != WHITE_SPACE_ENC )
+                {
+                    throw new java.io.IOException( "Invalid character in Base64 data." );
+                }   // end else: not white space either
+            }   // end else: decoding
+        }   // end write
+        
+        
+        
+        /**
+         * Calls {@link #write} repeatedly until <var>len</var> 
+         * bytes are written.
+         *
+         * @param theBytes array from which to read bytes
+         * @param off offset for array
+         * @param len max number of bytes to read into array
+         * @since 1.3
+         */
+        public void write( byte[] theBytes, int off, int len ) throws java.io.IOException
+        {
+            // Encoding suspended?
+            if( suspendEncoding )
+            {
+                super.out.write( theBytes, off, len );
+                return;
+            }   // end if: supsended
+            
+            for( int i = 0; i < len; i++ )
+            {
+                write( theBytes[ off + i ] );
+            }   // end for: each byte written
+            
+        }   // end write
+        
+        
+        
+        /**
+         * Method added by PHIL. [Thanks, PHIL. -Rob]
+         * This pads the buffer without closing the stream.
+         */
+        public void flushBase64() throws java.io.IOException 
+        {
+            if( position > 0 )
+            {
+                if( encode )
+                {
+                    out.write( encode3to4( b4, buffer, position ) );
+                    position = 0;
+                }   // end if: encoding
+                else
+                {
+                    throw new java.io.IOException( "Base64 input not properly padded." );
+                }   // end else: decoding
+            }   // end if: buffer partially full
+
+        }   // end flush
+
+        
+        /** 
+         * Flushes and closes (I think, in the superclass) the stream. 
+         *
+         * @since 1.3
+         */
+        public void close() throws java.io.IOException
+        {
+            // 1. Ensure that pending characters are written
+            flushBase64();
+
+            // 2. Actually close the stream
+            // Base class both flushes and closes.
+            super.close();
+            
+            buffer = null;
+            out    = null;
+        }   // end close
+        
+        
+        
+        /**
+         * Suspends encoding of the stream.
+         * May be helpful if you need to embed a piece of
+         * base640-encoded data in a stream.
+         *
+         * @since 1.5.1
+         */
+        public void suspendEncoding() throws java.io.IOException 
+        {
+            flushBase64();
+            this.suspendEncoding = true;
+        }   // end suspendEncoding
+        
+        
+        /**
+         * Resumes encoding of the stream.
+         * May be helpful if you need to embed a piece of
+         * base640-encoded data in a stream.
+         *
+         * @since 1.5.1
+         */
+        public void resumeEncoding()
+        {
+            this.suspendEncoding = false;
+        }   // end resumeEncoding
+        
+        
+        
+    }   // end inner class OutputStream
+    
+    
+}   // end class Base64
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/CombineGraphs.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/CombineGraphs.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/CombineGraphs.java	(revision 10506)
@@ -0,0 +1,138 @@
+/** This class is not currently used and therefore will not be compiled by makegli. */
+
+package org.greenstone.gatherer.feedback;
+
+import java.io.*;
+import javax.imageio.*;
+import java.awt.*;
+import java.awt.image.*;
+import com.sun.image.codec.jpeg.*;
+import javax.swing.*;
+
+/**
+ *  CombineGraphs class is a class to combine 2 images file into 1 jpeg file
+ *  called test.jpg using point by point comparison.
+ *  <p>User need to supplied the valid exist filenames of the 2 images that 
+ *  they want to combine.If in any one point in 2nd image file is not transparent
+ *  then that point will be drawn to the 1st image file.</p>  
+ *  <p>To run this class properly the format is :
+ *  <br><i>java CombineGraphs filename1 filename2</i>
+ *  <br>where filename1 is the names of the first image file.
+ *  <br>and filename2 is the names of the second image file. This file must
+ *  contains transparent.</p>
+ *  <p>For example: If user wants to combine the screenshot image file with the
+ *  image file of the scribble lines, then
+ *  <br>filename1 will be the filename of the screenshot image file, and
+ *  <br>filename2 will be the filename of the scribble lines image file.</p>
+ *
+ *  @author Veronica Liesaputra
+ */
+
+public class CombineGraphs extends JPanel
+{
+    /**
+     * This is a variable to stored the image that is stored inside f1.
+     * After the combine method called this variable will store the resulted image of
+     * combining 2 images together.
+     */
+    private BufferedImage bi1;
+
+    /**
+     * This is a variable to stored the image that is stored inside f2.
+     */
+    private BufferedImage bi2;
+
+    /**
+     * This is a variable to stored the first image file that the user supplied.
+     */
+    private File f1;
+
+    /**
+     * This is a variable to stored the second image file that the user supplied.
+     */
+    private File f2;
+    
+    /**
+     * It will read the image files user supplied and stored the image
+     * to the appropriate bufferedimage variable.
+     * (Precondition: (file1 != null) && (file2 != null))
+     * @param file1   the name of the first image file.
+     * @param file2   the name of the second image file.
+     */
+    public CombineGraphs(String file1,String file2)
+    {
+	try
+	    {
+		f1 = new File(file1);
+		f2 = new File(file2);
+		bi1 = ImageIO.read(f1);
+		bi2 = ImageIO.read(f2);	
+	    }
+	catch(IOException exp) {}
+    }   
+
+    /**
+     * This method will combine the 2 buffered images into 1 buffered image and 
+     * saved it to an output file in jpeg format.
+     * (Precondition: (filename != null))
+     * @param filename the name of the output file.
+     * (Postcondition: the combined image is stored in a jpeg file with the name
+     *                 as specified in filename.)
+     */
+    public void combine(String filename)
+    {
+
+	/*using bi1 as the base layer that we use to compare point by point with bi2. 
+	  if in one point in bi2 its not transparent then we draw that point to bi1.*/ 
+	Graphics2D G1;
+	
+	G1 = bi1.createGraphics();
+	
+	int width = bi2.getWidth();
+	int height = bi2.getHeight();
+
+	for (int y = 0 ; y < height ; y++) 
+	    {
+		for (int x = 0 ; x < width ; x++)
+		    {
+			int rgb = bi2.getRGB(x,y);
+			if (rgb != 0)
+			    {
+				G1.setColor(new Color(rgb,true));
+				G1.drawLine(x,y,x,y);
+			    }
+		    }
+	    }
+	
+	// Save the combined bufferedimage into a jpeg output file.
+	try {
+	    File file = new File(filename);
+	    FileOutputStream out = new FileOutputStream(file);
+	    
+	    JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
+	    JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi1);
+	    param.setQuality(1.0f, false);
+	    encoder.setJPEGEncodeParam(param);
+	    encoder.encode(bi1);
+	    
+	} catch (Exception ex) {}
+    }
+
+    /**
+     * This the main method that need 2 inputs from the user for it to
+     * work properly. 
+     * The inputs are the 2 image filenames that user want to combine.
+     */
+    public static void main (String[] args)
+    {
+	CombineGraphs cb = new CombineGraphs(args[0],args[1]);
+	cb.combine("test.jpg");
+    }
+}
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/CompGroup.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/CompGroup.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/CompGroup.java	(revision 10506)
@@ -0,0 +1,60 @@
+package org.greenstone.gatherer.feedback;
+
+import java.io.*;
+
+/**
+ * The instance of this class will hold a UserComponent and the status of the UserComponent.
+ * For each of the CompGroup instance will contains all the information and the status of
+ * a window that is opened by the application the user used.
+ * @author Veronica Liesaputra
+ */
+public class CompGroup implements Serializable
+{
+    /**
+     *  This variable will hold the status of the window that is opened by the application.
+     */
+    private String comp_status;
+
+    /**
+     *  This variable will hold the information about the window that is opened by the
+     *  application.
+     */
+    private UserComponent comp;
+
+    public CompGroup ()
+    {
+
+    }
+    
+    /**
+     *  It will make CompGroup instance that hold the information and status of the window
+     *  thats is opened by the application.
+     *  @param curr_comp  information about the window opened by the application.
+     *  @param curr_status status of the window opened by the application.
+     */
+    public CompGroup (UserComponent curr_comp,String curr_status)
+    {
+	comp_status = curr_status;
+	comp = curr_comp;
+    }
+    
+    /**
+     * This method will return the status of the window opened by the application.
+     * @return the status of the window.
+     */
+    public String getStatus ()
+    {
+	return comp_status;
+    }
+    
+    /**
+     * This method will return the information about the window opened by the application.
+     * @return the information about the window.
+     */
+    public UserComponent getComponent()
+    {
+	return comp;
+    }
+}
+
+  
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/CompListener.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/CompListener.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/CompListener.java	(revision 10506)
@@ -0,0 +1,944 @@
+package org.greenstone.gatherer.feedback;
+
+import org.omg.IOP.ComponentIdHelper;
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+import javax.swing.table.*;
+import javax.swing.text.*;
+import java.awt.image.*;
+import javax.imageio.ImageIO;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+import javax.swing.colorchooser.*;
+import java.awt.event.*;
+import javax.swing.event.*;
+import java.text.MessageFormat;
+import javax.swing.plaf.metal.MetalIconFactory.*;
+import javax.swing.plaf.metal.MetalIconFactory;
+import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
+import javax.swing.plaf.metal.MetalInternalFrameTitlePane;
+
+/**
+ *  In general, this class will get add special listener 
+ *  to a Container and of all the components inside it.
+ *  <p>This class will also add special listener to the Container and each of the components inside 
+ *  the Container. So, it will allows special listener  to record and listen each of the actions 
+ *  the user do to the Container or any of the components inside it. The special listener
+ *  is an instance of ActionRecorderDialog.</p>
+ *  <p>This class will only recognized all the components that is belongs to the javax.swing package
+ *  which are all the implementing classes of RootPaneContainer interface and all the direct known
+ *  subclasses of JComponent. All the other components will be stated simply as Container 
+ *  and user cannot really get much information out of it.</p>
+ *  <p>The added special listener to this component is as what its allowed in API, if the component
+ *  have some modified listener added to it then that action will not be known and recorded by
+ *  the special listener.</p>
+ *  
+ *  @author Veronica Liesaputra
+ */
+public class CompListener
+{
+    /**
+     *  This variable will hold the special listener that will listen and record any of the 
+     *  actions user do to the Container and any of the components inside it.
+     */
+    private ActionRecorderDialog m;
+   
+    /**
+     *  This variable will hold the pair of the component and the model of the component.
+     *  With this variable allows ActionRecorderDialog listener to know which component the model that fires an action
+     *  belongs to. In this HashMap the model is the key and the component where the model belongs to is
+     *  the value. 
+     */
+    private HashMap hash;
+    
+    /**
+     *  This constructor will set the special listener, the locale and the hashmap to be used in
+     *  this Container.
+     *  (Precondition: dialog != null)
+     *  @param dialog  its the special listener that will listen and record all the action
+     *                 user do to any of the component inside the Container.
+     *  @param h       its the HashMap that will hold the pair of model with the component it belongs.
+     */
+    public CompListener 
+	(ActionRecorderDialog dialog,HashMap h)
+    {
+	m = dialog;
+	hash = h;
+    }
+	
+    /**
+     *  If the JTextComponent is a JTextField then it will add the special action listener to it.
+     *  (Precondition: txt != null)
+     *  @param txt its the JTextComponent we want to get all the information from.
+     */
+    public void getTextAreaInfo(JTextComponent txt)
+    {
+	if (txt instanceof JTextField)
+	    {
+		((JTextField)txt).removeActionListener(m);
+		((JTextField)txt).addActionListener(m);
+	    }
+    }
+
+    /**
+     *  This method will add the special action listener to the JButton.
+     *  (Precondition: button != null)
+     *  @param button its the JButton we want to get the information from.
+     */
+    public void getButtonInfo (JButton button)
+    {
+	button.removeActionListener(m);
+	button.addActionListener(m);
+    }
+
+     /**
+     *  This method will get add the special change listener to the JProgressBar.
+     *  (Precondition: bar != null)
+     *  @param  bar   its the JProgressBar we want to get information from.
+     */
+    public void getProgressBarInfo (JProgressBar bar)
+    {
+	bar.removeChangeListener(m);
+	bar.addChangeListener(m);
+    }
+    
+    /**
+     *  This method will add the special change listener to the JSlider.
+     *  (Precondition: slider != null)
+     *  @param  slider its the JSlider we want to get information from.
+     */
+    public void getSliderInfo (JSlider slider)
+    {
+	slider.removeChangeListener(m);
+	slider.addChangeListener(m);
+    }
+
+    /**
+     *  This method will add the special change listener to the JSpinner.
+     *  (Precondition: spinner != null)
+     *  @param spinner its the JSpinner we want to the information from.
+     */
+    public void getSpinnerInfo (JSpinner spinner)
+    {
+	spinner.removeChangeListener(m);
+	spinner.addChangeListener(m);
+    }
+    
+    /**
+     * Dummy method to get JLabel.
+     */
+    public void getLabelInfo(JLabel lbl)
+    {}
+    
+    /**
+     *  This method will add the special action listener to the JComboBox.
+     *  (Precondition: box != null)
+     *  @param box    its the JComboBox we want to get information from.
+     */
+    public void getComboBoxInfo(JComboBox box)
+    {
+	ComboBoxModel cm;
+	cm = box.getModel();
+
+	box.removeActionListener(m);
+	box.addActionListener(m);
+    }
+
+    /**
+     *  This method will add the special action listener to the JToggleButton.
+     *  (Precondition: button != null)
+     *  @param button its a JToggleButton inside the window.
+     */
+    public void getToggleButtonInfo (JToggleButton button)
+    {
+	button.removeActionListener(m);
+	button.addActionListener(m);
+    }
+
+    /**
+     *  This method will add the special action listener to the JMenuItem.
+     *  (Precondition: menuitem != null)
+     *  @param menuitem its the JMenuItem we want to get the information from.
+     */
+    public void getMenuItemInfo (JMenuItem menuitem)
+    {
+	menuitem.removeActionListener(m);
+	menuitem.addActionListener(m);
+    }
+
+    /**
+     *  This method will get all the components inside JMenuBar.
+     *  (Precondition: menubar != null)
+     *  @param menubar its the JMenuBar we want to get the information from.
+     */
+    public void getMenuBarInfo (JMenuBar menubar)
+    {
+	int i;
+	for (i= 0 ; i < menubar.getMenuCount() ; i++)
+	    {
+		getInside(menubar.getMenu(i));
+	    }
+    }
+
+    /**
+     *  This method will add the special action and menu listener to the JMenu and
+     *  get the components inside JMenu.
+     *  (Precondition: menu != null)
+     *  @param menu   its the JMenu we want to the the information from.
+     */
+    public void getMenuInfo (JMenu menu)
+    {
+	menu.removeActionListener(m);
+	menu.removeMenuListener(m);
+	menu.addActionListener(m);
+	menu.addMenuListener(m);
+
+	int i;
+	for (i= 0 ; i < menu.getMenuComponentCount() ; i++)
+	    {
+		getInside((Container)menu.getMenuComponent(i));
+	    }
+    }
+    
+    /**
+     *  This method will get all the components inside the JApplet.
+     *  (Precondition: applet != null)
+     *  @param applet its the JApplet we want to get the information from.
+     */
+    public void getAppletInfo (JApplet applet)
+    {
+	Component[] group;
+	group = applet.getComponents();
+	int i;
+
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)applet.getComponent(i));
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get all the components inside the JWindow.
+     *  (Precondition: window != null)
+     *  @param window its the JWindow we want to get the information from.
+     */
+    public void getWindowInfo (JWindow window)
+    {
+	Component[] group;
+	group = window.getComponents();
+	int i;
+
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)window.getComponent(i));
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get all the components inside the JDialog.
+     *  (Precondition: dialog != null)
+     *  @param dialog its the JDialog we want to get the information from.
+     */
+    public void getDialogInfo (JDialog dialog)
+    {
+	Component[] group;
+	group = dialog.getComponents();
+	int i;
+
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)dialog.getComponent(i));
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get all the components inside the JInternalFrame.
+     *  (Precondition: frame != null)
+     *  @param frame  its the JInternalFrame we want to get the information from.
+     */
+    public void getInternalFrameInfo (JInternalFrame frame)
+    {
+	Component[] group;
+	group = frame.getComponents();
+	int i;
+
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)frame.getComponent(i));
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get all the components inside the JFrame.
+     *  (Precondition: frame != null)
+     *  @param frame  its the JFrame we want to get the information from.
+     */
+    public void getFrameInfo (JFrame frame)
+    {
+	Component[] group;
+	group = frame.getComponents();
+	int i;
+	
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)frame.getComponent(i));
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get all the components inside the JPanel.
+     *  (Precondition: pane != null)
+     *  @param pane   its the JPanel we want to get the information from.
+     */
+    public void getPanelInfo (JPanel pane)
+    {
+	Component[] group;
+	group = pane.getComponents();
+	int i;
+
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)pane.getComponent(i));
+		    }
+	    }
+    }
+    
+    /**
+     *  This method will get all the components inside the JScrollPane.
+     *  (Precondition: scroll != null)
+     *  @param scroll its the JScrollPane we want to get the information from.
+     */
+    public void getScrollInfo (JScrollPane scroll)
+    {
+	Component[] group;
+	group = scroll.getComponents();
+	int i;
+	
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)group[i]);
+		    }
+	    }
+    }
+
+    /**
+     *  This method will add special change listener to the JTabbedPane and get all
+     *  the components inside it.
+     *  (Precondition: tab != null)
+     *  @param tab   its the JTabbedPane we want to get the information from.
+     */
+    public void getTabbedPaneInfo (JTabbedPane tab)
+    {
+	int j;
+	
+	tab.removeChangeListener(m);
+	tab.addChangeListener(m);
+
+	for (j = 0 ; j < tab.getTabCount(); j++)
+	    {	
+		
+		Component group = tab.getComponentAt(j);
+		getInside((Container)group);
+		
+	    }
+    }
+    
+    /**
+     *  This is the dummy method to ge the option pane info.
+     */
+    public void getOptionPaneInfo (JOptionPane op)
+    {}
+
+    /**
+     *  This method will get components inside the JViewPort.
+     *  (Precondition: vp != null)
+     *  @param vp   its the JViewPort we want to get the information from.
+     */
+    public void getViewPortInfo (JViewport vp)
+    {
+	Component[] group;
+	group = vp.getComponents();
+	int i;
+
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)group[i]);
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get components inside the Box.
+     *  (Precondition: box != null)
+     *  @param box  its the Box we want to get the information from.
+     */
+    public void getBoxInfo (Box box)
+    {
+	Component[] group;
+	group = box.getComponents();
+	int i;
+
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)group[i]);
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get components inside the JSplitPane.
+     *  (Precondition: split != null)
+     *  @param split  its the JSplitPane we want to get the information from.
+     */
+    public void getSplitPaneInfo (JSplitPane split)
+    {
+	Component[] group;
+	group = split.getComponents();
+	int i;
+
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)group[i]);
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get add special list selection listener to the JList.
+     *  (Precondition: list != null)
+     *  @param list  its the JList we want to get the information from.
+     */
+    public void getListInfo (JList list)
+    {
+	ListModel ls;
+	ls = list.getModel();
+	
+	list.removeListSelectionListener(m);
+	list.addListSelectionListener(m);
+	
+	if (ls != null)
+	    {
+		if (hash.containsKey(ls) == false)
+		    hash.put(ls,list);
+		ls.removeListDataListener(m);
+		ls.addListDataListener(m);
+	    }
+    }
+
+    /**
+     *  This method will add special change listener to the JColorChooser.
+     *  (Precondition: color != null)
+     *  @param color  its the JColorChooser we want to get the information from.
+     */
+    public void getColorInfo (JColorChooser color)
+    {
+	ColorSelectionModel cm;
+	cm = color.getSelectionModel();
+	
+	if (cm != null)
+	    {
+		if (hash.containsKey(cm) == false)
+		    hash.put(cm,color);
+		cm.removeChangeListener(m);
+		cm.addChangeListener(m);
+	    }
+
+	getInside((Container) color.getPreviewPanel());
+    }
+
+    /**
+     *  This method will add special action listener to the JFileChooser.
+     *  (Precondition: fc != null)
+     *  @param fc  its the JFileChooser we want to get the information from.
+     */
+    public void getFileChooserInfo (JFileChooser fc)
+    {
+	fc.removeActionListener(m);
+	fc.addActionListener(m);
+    }		
+
+    /**
+     *  This method will add special list selection and column model listener 
+     *  to the JTable.
+     *  (Precondition: table != null)
+     *  @param table  its the JTable we want to get the information from.
+     */
+    public void getTableInfo (JTable table)
+    {
+	TableModel tm;
+	tm = table.getModel();
+	
+	TableColumnModel tcm;
+	tcm = table.getColumnModel();
+	ListSelectionModel lm;
+	lm = table.getSelectionModel(); 
+
+	if (lm != null)
+	    {
+		if (hash.containsKey(lm) == false)
+		    hash.put(lm,table);
+		lm.removeListSelectionListener(m);
+		lm.addListSelectionListener(m);
+	    }
+	
+	if (tcm != null)
+	    {
+		if (hash.containsKey(tcm) == false)
+		    hash.put(tcm,table);
+		tcm.removeColumnModelListener(m);
+		tcm.addColumnModelListener(m);
+	    }
+    }
+
+    /**
+     *  This is a dummy method to get the JScrollBar.
+     */
+    public void getScrollBarInfo (JScrollBar scroll)
+    {
+    }
+
+    /**
+     *  This method will add special tree selection listener to the JTree.
+     *  (Precondition: tree != null)
+     *  @param tree  its the JTree we want to get the information from.
+     */
+    public void getTreeInfo (JTree tree)
+    {
+	TreeModel tm;
+	tm = tree.getModel();
+	
+	tree.removeTreeSelectionListener(m);
+	tree.addTreeSelectionListener(m);
+	
+	if (tm != null)
+	    {
+		if (hash.containsKey(tm) == false)
+		    hash.put(tm,tree);
+		tm.removeTreeModelListener(m);
+		tm.addTreeModelListener(m);
+	    }
+    }
+       
+    /**
+     *  This method is a dummy method to get Container.
+     */
+    public void getCompInfo (Container pane)
+    {
+    }
+
+    /**
+     *  This method will get all components inside the JPopupMenu.
+     *  (Precondition: popup != null)
+     *  @param popup  its the JPopUpMenu we want to get the information from.
+     */
+    public void getPopUpMenuInfo (JPopupMenu popup)
+    {
+	Component[] group;
+	group = popup.getComponents();
+	SingleSelectionModel sm;
+	sm = popup.getSelectionModel();
+	int i;
+
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)popup.getComponent(i));
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get all the components inside the JRootPane.
+     *  (Precondition: pane != null)
+     *  @param pane  its the JRootPane we want to get the information from.
+     */
+    public void getRootPaneInfo (JRootPane pane)
+    {
+	Component[] group;
+	group = pane.getComponents();
+	int i;
+	
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			
+			getInside((Container)pane.getComponent(i));
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get all the components inside the JLayeredPane.
+     *  (Precondition: pane != null)
+     *  @param pane  its the JLayeredPane we want to get the information from.
+     */
+    public void getLayeredPaneInfo (JLayeredPane pane)
+    {
+	Component[] group;
+	group = pane.getComponents();
+	int i;
+	
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)pane.getComponent(i));
+		    }
+	    }
+    }
+
+    /**
+     * This is a dummy method to get BasicInternalFrameTitlePane.
+     */
+    public void getInternalFrameTitleInfo (BasicInternalFrameTitlePane pane)
+    {
+    }
+
+    /**
+     *  This method will add special column model and list selection
+     *  listener to JTableHeader.
+     *  (Precondition: header != null)
+     *  @param header  its the JTableHeader we want to get the information from.
+     */
+    public void getTableHeaderInfo (JTableHeader header)
+    {
+	TableColumnModel tcm;
+	tcm = header.getColumnModel();
+	ListSelectionModel lm;
+	lm = tcm.getSelectionModel();
+
+	if (tcm != null)
+	    {
+		if (hash.containsKey(tcm) == false)
+		    hash.put(tcm,header);
+		tcm.removeColumnModelListener(m);
+		tcm.addColumnModelListener(m);
+	    }
+
+	if (lm != null)
+	    {
+		if (hash.containsKey(lm) == false)
+		    hash.put(lm,header);
+		lm.removeListSelectionListener(m);
+		lm.addListSelectionListener(m);
+	    }
+    }
+
+    /**
+     *  This method will get all components inside the JToolBar.
+     *  (Precondition: tool != null)
+     *  @param tool  its the JToolBar we want to get the information from.
+     */
+    public void getToolBarInfo (JToolBar tool)
+    {
+	Component[] group;
+	group = tool.getComponents();
+	int i;
+	
+	if (group != null)
+	    {
+		for (i = 0; i < group.length ; i++)
+		    {
+			getInside((Container)tool.getComponent(i));
+		    }
+	    }
+    }
+
+    /**
+     *  This method will get all the components inside the JToolTip.
+     *  (Precondition: tip != null)
+     *  @param tip  its the JToolTip we want to get the information from.
+     */
+    public void getToolTipInfo (JToolTip tip)
+    {
+	Component group;
+	group = tip.getComponent();
+	int i;
+	
+	if (group != null)
+	    {
+		getInside((Container) group);
+	    }
+    }
+
+    /**
+     *  This is the dummy method to get JSeparator.
+     */
+    public void getSeparatorInfo (JSeparator sept)
+    {
+    }
+
+    /**
+     *  This method will get all the components inside the JDesktopPane.
+     *  (Precondition: pane != null)
+     *  @param pane  its the JDesktopPane we want to get the information from.
+     */
+    public void getDesktopPaneInfo (JDesktopPane pane)
+    {
+	JInternalFrame[]  group;
+	group = pane.getAllFrames();
+
+	if (group != null)
+	    {
+		int i;
+		
+		for ( i = 0 ; i < group.length ; i++ )
+		    {
+			getInside((Container) group[i]);
+		    }
+	    }
+    }
+
+    /**
+     *  This is a dummy method to catch null components.
+     */
+    public void getNullInfo ()
+    {
+    }
+
+    /**
+     *  This method will add a special listener to a container and components inside it.
+     *  This method is the gateway to all other methods in this class.
+     *  @param comp its the Container we want to get the information from.
+     */
+    public void getInside(Container comp)
+    {
+	if (comp == null)
+	    {
+		getNullInfo();
+		return;
+	    }
+	else if (comp instanceof JApplet)
+	    {
+		getAppletInfo ((JApplet) comp);
+		return;
+	    }
+	else if (comp instanceof JSeparator)
+	    {
+		getSeparatorInfo ((JSeparator) comp);
+		return;
+	    }
+	else if (comp instanceof JWindow)
+	    {
+		getWindowInfo((JWindow) comp);
+		return;
+	    }
+	else if (comp instanceof JDialog)
+	    {
+		getDialogInfo((JDialog) comp);
+		return;
+	    }
+	else if (comp instanceof JComboBox)
+	    {
+		getComboBoxInfo((JComboBox) comp);
+		return;
+	    }
+	else if (comp instanceof JLabel)
+	    {
+		getLabelInfo((JLabel) comp);
+		return;
+	    }
+	else if (comp instanceof JTextComponent)
+	    {
+		getTextAreaInfo((JTextComponent) comp);
+		return;
+	    }
+	else if (comp instanceof JFrame)
+	    {
+		getFrameInfo((JFrame) comp);
+		return;
+	    }
+	else if (comp instanceof JPanel)
+	    {
+		getPanelInfo((JPanel) comp);
+		return;
+	    }
+	else if (comp instanceof JScrollPane)
+	    {
+		getScrollInfo((JScrollPane) comp);
+		return;
+	    }
+	else if (comp instanceof JScrollBar)
+	    {
+		getScrollBarInfo ((JScrollBar) comp);
+		return;
+	    }
+	else if (comp instanceof JViewport)
+	    {
+		getViewPortInfo((JViewport) comp);
+		return;
+	    }
+	else if (comp instanceof JTabbedPane)
+	    {
+		getTabbedPaneInfo((JTabbedPane) comp);
+		return;
+	    }
+	else if (comp instanceof Box)
+	    {
+		getBoxInfo((Box) comp);
+		return;
+	    }
+	else if (comp instanceof JToggleButton)
+	    {
+		getToggleButtonInfo((JToggleButton) comp);
+		return;
+	    }
+	else if (comp instanceof JSplitPane)
+	    {
+		getSplitPaneInfo ((JSplitPane) comp);
+		return;
+	    }
+	else if (comp instanceof JList)
+	    {
+		getListInfo ((JList) comp);
+		return;
+	    }
+	else if (comp instanceof JTree)
+	    {
+		getTreeInfo ((JTree) comp);
+		return;
+	    }
+	else if (comp instanceof JTable)
+	    {
+		getTableInfo ((JTable) comp);
+		return;
+	    }
+	else if (comp instanceof JSlider)
+	    {
+		getSliderInfo ((JSlider) comp);
+		return;
+	    }
+	else if (comp instanceof JSpinner)
+	    {
+		getSpinnerInfo ((JSpinner) comp);
+		return;
+	    }
+	else if (comp instanceof JProgressBar)
+	    {
+		getProgressBarInfo ((JProgressBar) comp);
+		return;
+	    }
+	else if (comp instanceof JButton)
+	    {
+		getButtonInfo ((JButton) comp);
+		return;
+	    }
+	else if (comp instanceof JMenu)
+	    {
+		getMenuInfo ((JMenu) comp);
+		return;
+	    }
+	else if (comp instanceof JMenuBar)
+	    {
+		getMenuBarInfo ((JMenuBar) comp);
+		return;
+	    }
+	else if (comp instanceof JMenuItem)
+	    {
+		getMenuItemInfo ((JMenuItem) comp);
+		return;
+	    }
+	else if (comp instanceof JOptionPane)
+	    {
+		getOptionPaneInfo ((JOptionPane) comp);
+		return;
+	    }
+	else if (comp instanceof BasicInternalFrameTitlePane)
+	    {
+		getInternalFrameTitleInfo ((BasicInternalFrameTitlePane) comp);
+		return;
+	    }
+	else if (comp instanceof JColorChooser)
+	    {
+		getColorInfo ((JColorChooser) comp);
+		return;
+	    }
+	else if (comp instanceof JFileChooser)
+	    {
+		getFileChooserInfo ((JFileChooser) comp);
+		return;
+	    }
+	else if (comp instanceof JDesktopPane)
+	    {
+		getDesktopPaneInfo ((JDesktopPane) comp);
+		return;
+	    }
+	else if (comp instanceof JInternalFrame)
+	    {
+		getInternalFrameInfo ((JInternalFrame) comp);
+		return;
+	    }
+	else if (comp instanceof JLayeredPane)
+	    {
+		getLayeredPaneInfo ((JLayeredPane) comp);
+		return;
+	    }
+	else if (comp instanceof JPopupMenu)
+	    {
+		getPopUpMenuInfo ((JPopupMenu) comp);
+		return;
+	    }
+	else if (comp instanceof JRootPane)
+	    {
+		getRootPaneInfo ((JRootPane) comp);
+		return;
+	    }
+	else if (comp instanceof JTableHeader)
+	    {
+		getTableHeaderInfo ((JTableHeader) comp);
+		return;
+	    }
+	else if (comp instanceof JToolBar)
+	    {
+		getToolBarInfo ((JToolBar) comp);
+		return;
+	    }
+	else if (comp instanceof JToolTip)
+	    {
+		getToolTipInfo ((JToolTip) comp);
+		return;
+	    }
+	else
+	    {
+		getCompInfo (comp);
+		return;
+	    }
+    }
+}
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ComponentInformation.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ComponentInformation.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ComponentInformation.java	(revision 10506)
@@ -0,0 +1,2261 @@
+package org.greenstone.gatherer.feedback;
+
+import org.omg.IOP.ComponentIdHelper;
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+import javax.swing.table.*;
+import javax.swing.text.*;
+import java.awt.image.*;
+import javax.imageio.ImageIO;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+import javax.swing.colorchooser.*;
+import java.awt.event.*;
+import javax.swing.event.*;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+import javax.swing.plaf.metal.MetalIconFactory.*;
+import javax.swing.plaf.metal.MetalIconFactory;
+import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
+import javax.swing.plaf.metal.MetalInternalFrameTitlePane;
+
+/**
+ *  In general, this class will get all information and add special listener 
+ *  to a Container and of all the components inside it.
+ *  <p>This class will get the information about the Container and all the components inside it.
+ *  The information we get is like whether or not the component is visible and the contents of it.
+ *  This class will also add special listener to the Container and each of the components inside 
+ *  the Container. So, it will allows special listener  to record and listen each of the actions 
+ *  the user do to the Container or any of the components inside it. The special listener
+ *  is an instance of ActionRecorderDialog.</p>
+ *  <p>This class will only recognized all the components that is belongs to the javax.swing package
+ *  which are all the implementing classes of RootPaneContainer interface and all the direct known
+ *  subclasses of JComponent. All the other components will be stated simply as Container 
+ *  and user cannot really get much information out of it.</p>
+ *  <p>The added special listener to this component is as what its allowed in API, if the component
+ *  have some modified listener added to it then that action will not be known and recorded by
+ *  the special listener.</p>
+ *  
+ *  @author Veronica Liesaputra
+ */
+public class ComponentInformation
+{
+    /**
+     *  This variable will hold the special listener that will listen and record any of the 
+     *  actions user do to the Container and any of the components inside it.
+     */
+    private ActionRecorderDialog m;
+    
+    /**
+     *  This variable will hold the resource of the words that is stored in Messages.properties file. 
+     *  The calling using messages.getString(someString) will caused someString to be translated
+     *  into some other string that is hold in that file.usually it will caused it to be translated
+     *  to the language that the user use or choose to have as stated in Locale.
+     */
+    private static ResourceBundle messages;
+
+    /**
+     *  This variable will hold the pair of the component and the model of the component.
+     *  With this variable allows ActionRecorderDialog listener to know which component the model that fires an action
+     *  belongs to. In this HashMap the model is the key and the component where the model belongs to is
+     *  the value. 
+     */
+    private HashMap hash;
+    
+    /**
+     *  This constructor will set the special listener, the locale and the hashmap to be used in
+     *  this Container.
+     *  (Precondition: dialog != null)
+     *  @param dialog  its the special listener that will listen and record all the action
+     *                 user do to any of the component inside the Container.
+     *  @param currentLocale its the locale that the user choose all the information to be displayed as.
+     *  @param h       its the HashMap that will hold the pair of model with the component it belongs.
+     */
+    public ComponentInformation 
+	(ActionRecorderDialog dialog,Locale currentLocale,HashMap h)
+    {
+	m = dialog;
+	hash = h;
+	messages = ResourceBundle.getBundle("feedback", currentLocale);
+    }
+	
+    /**
+     *  This method will get all information about the JTextComponent.
+     *  If the JTextComponent is a JTextField then it will add the special action listener to it.
+     *  (Precondition: txt != null)
+     *  @param txt its the JTextComponent we want to get all the information from.
+     *  @return    a UserComponent that hold the information about this
+     *             JTextComponent.
+     */
+    public  UserComponent getTextAreaInfo(JTextComponent txt)
+    {
+	UserComponent file;
+	file = new UserComponent(); 
+	String text;
+	text = txt.getText();
+
+	file.startContent(1);
+	if (txt instanceof JTextArea)
+	    file.saveContent("JTextArea");
+	else if (txt instanceof JTextPane)
+	    file.saveContent("JTextPane");
+	else if (txt instanceof JEditorPane)
+	    file.saveContent("JEditorPane");
+	else if (txt instanceof JTextField)
+	    {
+		((JTextField)txt).removeActionListener(m);
+		((JTextField)txt).addActionListener(m);
+		
+		if (txt instanceof JFormattedTextField)
+		    {
+			file.saveContent("JFormattedTextField");
+		    }
+		else if (txt instanceof JPasswordField)
+		    {
+			file.saveContent("JPasswordField");
+		    }
+		else
+		    {
+			file.saveContent("JTextField");
+		    }
+	    }
+
+	file.startContent(2);
+	file.saveContent(messages.getString("TextComponent"));
+	
+	file.startContent(3);
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+	
+	file.startContent(4);
+	file.saveContent(txt.getSelectedText());
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + txt.isVisible()));
+
+	file.startContent(7);
+	file.saveContent(txt.getToolTipText());
+	
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add the special action listener to the JButton.
+     *  (Precondition: button != null)
+     *  @param button its the JButton we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JButton.
+     */
+    public UserComponent getButtonInfo (JButton button)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	String text;
+	text = button.getText();
+
+	button.removeActionListener(m);
+	button.addActionListener(m);
+
+	file.startContent(1);
+	file.saveContent("JButton");
+
+	file.startContent(2);
+	file.saveContent(messages.getString("Button"));
+	
+	file.startContent(3);
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+
+	file.startContent(4);
+	file.saveContent(messages.getString("" + button.isSelected()));
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + button.isVisible()));
+	
+	file.startContent(6);
+	Icon img = button.getIcon();
+	if (img != null)
+	    {
+		file.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+	    }
+	else
+	    {
+		file.saveContent(messages.getString("NoImage"));
+	    }
+
+	file.startContent(7);
+	file.saveContent(button.getToolTipText());
+
+	return file;
+    }
+
+     /**
+     *  This method will get all the information and add the special change listener to the JProgressBar.
+     *  (Precondition: bar != null)
+     *  @param  bar   its the JProgressBar we want to get information from.
+     *  @return       a UserComponent that will hold the information about this JProgressBar.
+     */
+    public UserComponent getProgressBarInfo (JProgressBar bar)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	String text;
+	text = bar.getString();
+
+	bar.removeChangeListener(m);
+	bar.addChangeListener(m);
+	
+	file.startContent(1);
+	file.saveContent("JProgressBar");
+
+	file.startContent(2);
+	file.saveContent(messages.getString("ProgressBar"));
+	
+	file.startContent(3);
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + bar.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(bar.getToolTipText());
+
+	return file;
+    }
+    
+    /**
+     *  This method will get all the information and add the special change listener to the JSlider.
+     *  (Precondition: slider != null)
+     *  @param  slider its the JSlider we want to get information from.
+     *  @return        a UserComponent that will hold the information about this JSlider.
+     */
+    public UserComponent getSliderInfo (JSlider slider)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	String text;
+	text = "" + slider.getValue();
+	
+	slider.removeChangeListener(m);
+	slider.addChangeListener(m);
+
+	file.startContent(1);
+	file.saveContent("JSlider");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Slider"));
+	
+	file.startContent(3);
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + slider.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(slider.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add the special change listener to the JSpinner.
+     *  (Precondition: spinner != null)
+     *  @param spinner its the JSpinner we want to the information from.
+     *  @return        a UserComponent that will hold the information about this JSpinner.
+     */
+    public UserComponent getSpinnerInfo (JSpinner spinner)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	String text;
+	text = "" + spinner.getValue();
+	
+	spinner.removeChangeListener(m);
+	spinner.addChangeListener(m);
+
+	file.startContent(1);
+	file.saveContent("JSpinner");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Spinner"));
+	
+	file.startContent(3);
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + spinner.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(spinner.getToolTipText());
+
+	return file;
+    }
+    
+    /**
+     *  This method will get all the information of  the JLabel.
+     *  (Precondition: lbl != null)
+     *  @param lbl    its the JLabel we want to get information from.
+     *  @return       a UserComponent that will hold the information about this JLabel.
+     */
+    public UserComponent getLabelInfo(JLabel lbl)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	String text;
+	text = lbl.getText();
+
+	file.startContent(1);
+	file.saveContent("JLabel");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Label"));
+	
+	file.startContent(3);
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + lbl.isVisible()));
+
+	file.startContent(6);
+	Icon img = lbl.getIcon();
+	if (img != null)
+	    {
+		file.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+	    }
+	else
+	    {
+		file.saveContent(messages.getString("NoImage"));
+	    }
+	
+	file.startContent(7);
+	file.saveContent(lbl.getToolTipText());
+
+	return file;
+    }
+    
+    /**
+     *  This method will get all the information and add the special action listener to the JComboBox.
+     *  (Precondition: box != null)
+     *  @param box    its the JComboBox we want to get information from.
+     *  @return       a UserComponent that will hold the information about this JComboBox.
+     */
+    public  UserComponent getComboBoxInfo(JComboBox box)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	ComboBoxModel cm;
+	cm = box.getModel();
+
+	box.removeActionListener(m);
+	box.addActionListener(m);
+	
+	file.startContent(1);
+	file.saveContent("JComboBox");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("ComboBox"));
+	
+	file.startContent(3);
+	int i;
+	for (i = 0; i < box.getItemCount() ; i++)
+	    {
+		UserComponent file2;
+		file2 = new UserComponent();
+		//Assuming that they don't put any picture or images
+		String text;
+		Object objmsg;
+
+		objmsg = box.getItemAt(i);
+
+		if (objmsg instanceof String)
+		    text = (String) objmsg + "\n";
+		else
+		    text = objmsg.toString() + "\n" ;
+		
+		file2.startContent(3);
+		if (text != null)
+		    file2.saveContent(text);
+		else
+		    file2.saveContent(" ");
+		
+		file2.startContent(4);
+		if (i == box.getSelectedIndex())
+		    file2.saveContent(messages.getString("Selected"));
+		else
+		    file2.saveContent(messages.getString("NotSelected"));
+		
+		file.saveContent(file2);
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + box.isVisible()));
+
+	file.startContent(7);
+	file.saveContent(box.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add the special action listener to the JToggleButton.
+     *  (Precondition: button != null)
+     *  @param button its a JToggleButton inside the window
+     *  @return       a UserComponent that will hold the information about this JToggleButton.
+     */
+    public UserComponent getToggleButtonInfo (JToggleButton button)
+    {
+	UserComponent file;
+	file = new UserComponent();
+
+	button.removeActionListener(m);
+	button.addActionListener(m);
+
+	file.startContent(1);
+	if (button instanceof JCheckBox)
+	    file.saveContent("JCheckBox");
+	else
+	    file.saveContent("JRadioButton");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("ToggleButton"));
+	
+	file.startContent(3);
+	String text;
+	text = button.getText();
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+	
+	file.startContent(4);
+	if (button.isSelected() == true)
+	    {
+		file.saveContent(messages.getString("Selected"));
+	    }
+	else
+	    file.saveContent(messages.getString("NotSelected"));
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + button.isVisible()));
+	
+	file.startContent(6);
+	Icon img = button.getIcon();
+	if (img != null)
+	    {
+		file.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+	    }
+	else
+	    {
+		file.saveContent(messages.getString("NoImage"));
+	    }
+	
+	file.startContent(7);
+	file.saveContent(button.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add the special action listener to the JMenuItem.
+     *  (Precondition: menuitem != null)
+     *  @param menuitem its the JMenuItem we want to get the information from.
+     *  @return         a UserComponent that will hold the information about this JMenuItem.
+     */
+    public UserComponent getMenuItemInfo (JMenuItem menuitem)
+    {
+	UserComponent file;
+	file = new UserComponent();
+
+	menuitem.removeActionListener(m);
+	menuitem.addActionListener(m);
+	
+	file.startContent(1);
+	file.saveContent("JMenuItem");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("MenuItem"));
+	
+	file.startContent(3);
+	String text;
+	text = menuitem.getText();
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+	
+	file.startContent(4);
+	if (menuitem.isSelected() == true)
+	    {
+		file.saveContent(messages.getString("Selected"));
+	    }
+	else
+	    file.saveContent(messages.getString("NotSelected"));
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" +  menuitem.isVisible()));
+	
+	file.startContent(6);
+	Icon img = menuitem.getIcon();
+	if (img  != null)
+	    {
+		file.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+	    }
+	else
+	    {
+		file.saveContent(messages.getString("NoImage"));
+	    }
+	
+	file.startContent(7);
+	file.saveContent(menuitem.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JMenuBar.
+     *  (Precondition: menubar != null)
+     *  @param menubar its the JMenuBar we want to get the information from.
+     *  @return        a UserComponent that will hold the information about this JMenuBar.
+     */
+    public  UserComponent getMenuBarInfo (JMenuBar menubar)
+    {
+	UserComponent file;
+	file = new UserComponent();
+
+	file.startContent(1);
+	file.saveContent("JMenuBar");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("MenuBar"));
+	
+	file.startContent(3);
+	int i;
+	for (i= 0 ; i < menubar.getMenuCount() ; i++)
+	    {
+		file.saveContent(getInside(menubar.getMenu(i)));
+	    }
+	
+	file.startContent(4);
+	if (menubar.isSelected() == true)
+	    {
+		file.saveContent(messages.getString("Selected"));
+	    }
+	else
+	    file.saveContent(messages.getString("NotSelected"));
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" +  menubar.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(menubar.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add the special action and menu listener to the JMenu.
+     *  (Precondition: menu != null)
+     *  @param menu   its the JMenu we want to the the information from.
+     *  @return       a UserComponent that will hold the information about this JMenu.
+     */
+    public  UserComponent getMenuInfo (JMenu menu)
+    {
+	UserComponent file;
+	file = new UserComponent();
+
+	menu.removeActionListener(m);
+	menu.removeMenuListener(m);
+	menu.addActionListener(m);
+	menu.addMenuListener(m);
+
+	file.startContent(1);
+	file.saveContent("JMenu");
+	
+	file.startContent(2);
+	String text;
+	text = menu.getText();
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+	
+	file.startContent(3);
+	int i;
+	for (i= 0 ; i < menu.getMenuComponentCount() ; i++)
+	    {
+		file.saveContent(getInside((Container)menu.getMenuComponent(i)));
+	    }
+	
+	file.startContent(4);
+	if (menu.isSelected() == true)
+	    {
+		file.saveContent(messages.getString("Selected"));
+	    }
+	else
+	    file.saveContent(messages.getString("NotSelected"));
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" +  menu.isVisible()));
+	
+	file.startContent(6);
+	Icon img = menu.getIcon();
+	if (img  != null)
+	    {
+		file.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+	    }
+	else
+	    {
+		file.saveContent(messages.getString("NoImage"));
+	    }
+	
+	file.startContent(7);
+	file.saveContent(menu.getToolTipText());
+
+	return file;
+    }
+    
+    /**
+     *  This method will get all the information of the JApplet.
+     *  (Precondition: applet != null)
+     *  @param applet its the JApplet we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JApplet.
+     */
+    public  UserComponent getAppletInfo (JApplet applet)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = applet.getComponents();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("JApplet");
+	
+	file.startContent(2);
+	String text;
+	text = applet.getAppletInfo();
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)applet.getComponent(i)));
+		    }
+	    }
+	
+	file.startContent(4);
+	file.saveContent(messages.getString("" + applet.isActive()));
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + applet.isVisible()));
+	
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JWindow.
+     *  (Precondition: window != null)
+     *  @param window its the JWindow we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JWindow.
+     */
+    public  UserComponent getWindowInfo (JWindow window)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = window.getComponents();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("JWindow");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Window"));
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)window.getComponent(i)));
+		    }
+	    }
+	
+	file.startContent(4);
+	file.saveContent(messages.getString("" + window.isActive()));
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + window.isVisible()));
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JDialog.
+     *  (Precondition: dialog != null)
+     *  @param dialog its the JDialog we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JDialog.
+     */
+    public UserComponent getDialogInfo (JDialog dialog)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = dialog.getComponents();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("JDialog");
+	
+	file.startContent(2);
+	String text = dialog.getTitle();
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)dialog.getComponent(i)));
+		    }
+	    }
+	
+	file.startContent(4);
+	file.saveContent(messages.getString("" + dialog.isActive()));
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + dialog.isVisible()));
+	
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JInternalFrame.
+     *  (Precondition: frame != null)
+     *  @param frame  its the JInternalFrame we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JInternalFrame.
+     */
+    public UserComponent getInternalFrameInfo (JInternalFrame frame)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = frame.getComponents();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("JInternalFrame");
+	
+	file.startContent(2);
+	String text;
+	text = frame.getTitle();
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)frame.getComponent(i)));
+		    }
+	    }
+	
+	file.startContent(4);
+	file.saveContent(messages.getString("" + frame.isSelected()));
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + frame.isVisible()));
+	
+	file.startContent(6);
+	Icon img = frame.getFrameIcon();
+	if (img != null)
+	    {
+		file.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+	    }
+	else
+	    {
+		file.saveContent(messages.getString("NoImage"));
+	    }
+	
+	file.startContent(7);
+	file.saveContent(frame.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JFrame.
+     *  (Precondition: frame != null)
+     *  @param frame  its the JFrame we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JFrame.
+     */
+    public UserComponent getFrameInfo (JFrame frame)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = frame.getComponents();
+	int i;
+	
+	file.startContent(1);
+	file.saveContent("JFrame");
+	
+	file.startContent(2);
+	String text;
+	text = frame.getTitle();
+	if (text != null)
+	    file.saveContent(text);
+	else
+	    file.saveContent(" ");
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)frame.getComponent(i)));
+		    }
+	    }
+	
+	file.startContent(4);
+	file.saveContent(messages.getString("" + frame.isActive()));
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + frame.isVisible()));
+	
+	file.startContent(6);
+	Image image;
+	image = frame.getIconImage();
+	if (image != null)
+	    {
+		ImageIcon img;
+		img = new ImageIcon(image);
+		file.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+	    }
+	else
+	    {
+		file.saveContent(messages.getString("NoImage"));
+	    }
+	
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JPanel.
+     *  (Precondition: pane != null)
+     *  @param pane   its the JPanel we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JPanel.
+     */
+    public UserComponent getPanelInfo (JPanel pane)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = pane.getComponents();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("JPanel");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Panel"));
+
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)pane.getComponent(i)));
+		    }
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + pane.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(pane.getToolTipText());
+
+	return file;
+    }
+    
+    /**
+     *  This method will get all the information of the JScrollPane.
+     *  (Precondition: scroll != null)
+     *  @param scroll its the JScrollPane we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JScrollPane.
+     */
+    public UserComponent getScrollInfo (JScrollPane scroll)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = scroll.getComponents();
+	int i;
+	
+	file.startContent(1);
+	file.saveContent("JScrollPane");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Scroller"));
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)group[i]));
+		    }
+	    }
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + scroll.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(scroll.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add special change listener to the JTabbedPane.
+     *  (Precondition: tab != null)
+     *  @param tab   its the JTabbedPane we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this JTabbedPane.
+     */
+    public UserComponent getTabbedPaneInfo (JTabbedPane tab)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	int j;
+	
+	tab.removeChangeListener(m);
+	tab.addChangeListener(m);
+
+	file.startContent(1);
+	file.saveContent("JTabbedPane");
+	
+	file.startContent(3);
+	for (j = 0 ; j < tab.getTabCount(); j++)
+	    {	
+		UserComponent file2;
+		file2 = new UserComponent();
+
+		file2.startContent(2);
+		String title;
+		title = tab.getTitleAt(j);
+		if (title != null)
+		    file2.saveContent(title);
+		else
+		    file2.saveContent(" ");
+		
+		file2.startContent(6);
+		Icon img;
+		img = tab.getIconAt(j);
+		if (img != null)
+		    {
+			file2.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+		    }
+		else
+		    {
+			file2.saveContent(messages.getString("NoImage"));
+		    }
+		
+		file2.startContent(3);
+		Component group = tab.getComponentAt(j);
+		file2.saveContent(getInside((Container)group));
+		
+		file2.startContent(4);
+		if (j == tab.getSelectedIndex())
+		    file2.saveContent(messages.getString("Selected"));
+		else
+		    file2.saveContent(messages.getString("NotSelected"));
+		
+		file.saveContent(file2);
+	    }
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + tab.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(tab.getToolTipText());
+
+	return file;
+    }
+    
+    /**
+     *  This method will get all the information of the JOptionPane.
+     *  (Precondition: op != null)
+     *  @param op   its the JOptionPane we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this JOptionPane.
+     */
+    public UserComponent getOptionPaneInfo (JOptionPane op)
+    {
+	UserComponent file;
+	file = new UserComponent();
+
+	file.startContent(1);
+	file.saveContent("JOptionPane");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("OptionPane"));
+	
+	file.startContent(3);
+	Object objmsg;
+	objmsg = op.getMessage();
+
+	if (objmsg != null)
+	    {
+		String text;
+		if (objmsg instanceof String)
+		    text = (String) objmsg + "\n";
+		else
+		    text = objmsg.toString() + "\n" ;
+		file.saveContent(text);
+	    }
+	else
+	    file.saveContent(" ");
+	
+	Object[] obj;
+	int i;
+	obj = op.getOptions();
+	if (obj != null)
+	    {
+		for (i = 0; i < obj.length ; i++)
+		    {
+			if (obj[i] instanceof String)
+			    file.saveContent((String) obj[i]);
+			else
+			    file.saveContent(obj[i].toString());
+		    }
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + op.isVisible()));
+	
+	file.startContent(6);
+	Icon img = op.getIcon();
+	if (img != null)
+	    {
+		file.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+	    }
+	else
+	    {
+		file.saveContent(messages.getString("NoImage"));
+	    }
+	
+	file.startContent(7);
+	file.saveContent(op.getToolTipText());
+
+	return file;
+	
+    }
+
+    /**
+     *  This method will get all the information of the JViewPort.
+     *  (Precondition: vp != null)
+     *  @param vp   its the JViewPort we want to get the information from.
+     *  @return     a UserComponent that will hold the information about this JViewPort.
+     */
+    public  UserComponent getViewPortInfo (JViewport vp)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = vp.getComponents();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("JViewPort");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("ViewPort"));
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)group[i]));
+		    }
+	    }
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + vp.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(vp.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the Box.
+     *  (Precondition: box != null)
+     *  @param box  its the Box we want to get the information from.
+     *  @return     a UserComponent that will hold the information about this Box.
+     */
+    public UserComponent getBoxInfo (Box box)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = box.getComponents();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("Box");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Box"));
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)group[i]));
+		    }
+	    }
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + box.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(box.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JSplitPane.
+     *  (Precondition: split != null)
+     *  @param split  its the JSplitPane we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JSplitPane.
+     */
+    public  UserComponent getSplitPaneInfo (JSplitPane split)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = split.getComponents();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("JSplitPane");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Splitters"));
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)group[i]));
+		    }
+	    }
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + split.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(split.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add special list selection listener to the JList.
+     *  (Precondition: list != null)
+     *  @param list  its the JList we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this JList.
+     */
+    public UserComponent getListInfo (JList list)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	ListModel ls;
+	ls = list.getModel();
+	int i;
+	
+	list.removeListSelectionListener(m);
+	list.addListSelectionListener(m);
+	
+	if (ls != null)
+	    {
+		if (hash.containsKey(ls) == false)
+		    hash.put(ls,list);
+		ls.removeListDataListener(m);
+		ls.addListDataListener(m);
+	    }
+
+	file.startContent(1);
+	file.saveContent("JList");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("List"));
+	
+	if (ls != null)
+	    {
+		file.startContent(3);
+		for ( i = 0 ; i < ls.getSize() ; i++)
+		    {
+			UserComponent file2;
+			file2 = new UserComponent();
+			//Assume that its all a text
+			file2.startContent(3);
+			String text;
+			Object obj;
+			obj = ls.getElementAt(i);
+			
+			if (obj instanceof String)
+			    text = (String) obj;
+			else
+			    text = obj.toString();
+			
+			if (text != null)
+			    file2.saveContent(text);
+			else
+			    file2.saveContent(" ");
+			
+			file2.startContent(4);
+			if ( i == list.getSelectedIndex())
+			    {
+				file2.saveContent(messages.getString("Selected"));
+			    }
+			else
+			    file2.saveContent(messages.getString("NotSelected"));
+			
+			file.saveContent(file2);
+		    }
+	    }
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + list.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(list.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add special change listener to the JColorChooser.
+     *  (Precondition: color != null)
+     *  @param color  its the JColorChooser we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JColorChooser.
+     */
+    public UserComponent getColorInfo (JColorChooser color)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	ColorSelectionModel cm;
+	cm = color.getSelectionModel();
+	int i;
+	
+	if (cm != null)
+	    {
+		if (hash.containsKey(cm) == false)
+		    hash.put(cm,color);
+		cm.removeChangeListener(m);
+		cm.addChangeListener(m);
+	    }
+	
+	file.startContent(1);
+	file.saveContent("JColorChooser");
+
+	file.startContent(2);
+	file.saveContent(messages.getString("ColorChooser"));
+
+	file.startContent(3);
+	UserComponent file2;
+	file2 = new UserComponent();
+	file2.startContent(2);
+	file2.saveContent(messages.getString("PreviewPanel"));
+
+	file2.startContent(3);
+	file2.saveContent(getInside((Container) color.getPreviewPanel()));
+	
+	file.saveContent(file2);
+
+	file2 = new UserComponent();
+	file2.startContent(2);
+	file2.saveContent(messages.getString("ChooserPanels"));
+
+	AbstractColorChooserPanel[] cp;
+	cp = color.getChooserPanels();
+	if ((cp != null) && (cp.length != 0))
+	    {
+		file2.startContent(3);
+		for (i = 0 ; i < cp.length ; i++)
+		    {
+			UserComponent file3;
+			file3 = new UserComponent();
+			file3.startContent(2);
+			file3.saveContent(cp[i].getDisplayName());
+			
+			ColorSelectionModel cpsm;
+			cpsm = cp[i].getColorSelectionModel();
+
+			if (cpsm != null)
+			    {
+				file3.startContent(3);
+				file3.saveContent("" + 
+						  cpsm.getSelectedColor());
+			    }
+
+			file3.startContent(6);
+			Icon img = cp[i].getSmallDisplayIcon();
+			if (img  != null)
+			    {
+				file3.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+			    }
+			else
+			    {
+				file3.saveContent(messages.getString("NoImage"));
+			    }
+			
+			file3.startContent(6);
+			img = cp[i].getLargeDisplayIcon();
+			if (img  != null)
+			    {
+				file3.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+			    }
+			else
+			    {
+				file3.saveContent(messages.getString("NoImage"));
+			    }
+			file2.saveContent(file3);
+		    }
+	    }
+		
+	file.saveContent(file2);    
+	
+	file.startContent(4);
+	file.saveContent("" + cm.getSelectedColor().toString());
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" +  color.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(color.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add special action listener to the JFileChooser.
+     *  (Precondition: fc != null)
+     *  @param fc  its the JFileChooser we want to get the information from.
+     *  @return    a UserComponent that will hold the information about this JFileChooser.
+     */
+    public UserComponent getFileChooserInfo (JFileChooser fc)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	int i;
+
+	fc.removeActionListener(m);
+	fc.addActionListener(m);
+
+	file.startContent(1);
+	file.saveContent("JFileChooser");
+	
+	file.startContent(2);
+	file.saveContent(fc.getDialogTitle());
+
+	File[] f;
+	f = fc.getSelectedFiles();
+	
+	if (f != null)
+	    {
+		file.startContent(3);
+		
+		for ( i = 0 ; i < f.length ; i++)
+		    {
+			UserComponent file2;
+			file2 = new UserComponent();
+			file2.startContent(1);
+			file2.saveContent(fc.getTypeDescription(f[i]));
+			
+			file2.startContent(2);
+			file2.saveContent(fc.getName(f[i]));
+			
+			file2.startContent(6);
+			Icon img = fc.getIcon(f[i]);
+			if (img  != null)
+			    {
+				file2.saveImage(img,messages.getString("icon")+img.hashCode()+".jpg");
+			    }
+			else
+			    {
+				file2.saveContent(messages.getString("NoImage"));
+			    }
+			file.saveContent(file2);
+		    }
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" +  fc.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(fc.getToolTipText());
+
+	return file;
+    }		
+
+    /**
+     *  This method will get all the information and add special list selection and column model listener 
+     *  to the JTable.
+     *  (Precondition: table != null)
+     *  @param table  its the JTable we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JTable.
+     */
+    public UserComponent getTableInfo (JTable table)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	TableModel tm;
+	tm = table.getModel();
+	int i,j;
+	String text;
+
+	TableColumnModel tcm;
+	tcm = table.getColumnModel();
+	ListSelectionModel lm;
+	lm = table.getSelectionModel(); 
+
+	if (lm != null)
+	    {
+		if (hash.containsKey(lm) == false)
+		    hash.put(lm,table);
+		lm.removeListSelectionListener(m);
+		lm.addListSelectionListener(m);
+	    }
+	
+	if (tcm != null)
+	    {
+		if (hash.containsKey(tcm) == false)
+		    hash.put(tcm,table);
+		tcm.removeColumnModelListener(m);
+		tcm.addColumnModelListener(m);
+	    }
+
+	file.startContent(1);
+	file.saveContent("JTable");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Table"));
+	
+	if (tm != null)
+	    {
+		file.startContent(3);
+		for ( i = 0 ; i < tm.getRowCount() ; i++)
+		    {
+			UserComponent file2;
+			file2 = new UserComponent();
+			
+			file2.startContent(2);
+			text = messages.getString("row") +" " + (i + 1);
+			file2.saveContent(text);
+			
+			file2.startContent(3);
+			for ( j = 0 ; j < tm.getColumnCount() ; j++)
+			    {
+				UserComponent file3;
+				file3 = new UserComponent();
+				
+				file3.startContent(2);
+				file3.saveContent(tm.getColumnName(j));
+				
+				file3.startContent(3);
+				
+				Object obj;
+				obj = tm.getValueAt(i,j);
+				
+				if (obj instanceof String)
+				    file3.saveContent((String)obj);
+				else
+				    file3.saveContent(obj.toString());
+				
+				file3.startContent(4);
+				if (table.isCellSelected(i,j) == true)
+				    {
+					file3.saveContent(messages.getString("Selected"));
+				    }
+				else
+				    file3.saveContent(messages.getString("NotSelected"));
+				
+				file2.saveContent(file3);
+			    }
+			
+			file.saveContent(file2);
+		    }
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" +  table.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(table.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JScrollBar.
+     *  (Precondition: scroll != null)
+     *  @param scroll  its the JScrollBar we want to get the information from.
+     *  @return         a UserComponent that will hold the information about this JScrollBar.
+     */
+    public  UserComponent getScrollBarInfo (JScrollBar scroll)
+    {
+	UserComponent file;
+	file = new UserComponent();
+
+	file.startContent(1);
+	file.saveContent("JScrollBar");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("ScrollerBar"));
+	
+	file.startContent(3);
+	file.saveContent(""+ scroll.getOrientation()+ " :"+ scroll.getValue());
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + scroll.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(scroll.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add special tree selection listener to the JTree.
+     *  (Precondition: tree != null)
+     *  @param tree  its the JTree we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this JTree.
+     */
+    public UserComponent getTreeInfo (JTree tree)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	TreeModel tm;
+	tm = tree.getModel();
+	int i;
+	
+	tree.removeTreeSelectionListener(m);
+	tree.addTreeSelectionListener(m);
+	
+	if (tm != null)
+	    {
+		if (hash.containsKey(tm) == false)
+		    hash.put(tm,tree);
+		tm.removeTreeModelListener(m);
+		tm.addTreeModelListener(m);
+	    }
+	
+	file.startContent(1);
+	file.saveContent("JTree");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Tree"));
+	
+	file.startContent(3);
+	Object root;
+	root = tm.getRoot();
+	file.saveContent(getChildInfo(tm,root,tree));
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" +  tree.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(tree.getToolTipText());
+
+	return file;
+    }
+       
+    /**
+     *  This method will get all the information about the parent node and all the childs of it inside the JTree.
+     *  (Precondition: (tree != null) && (tm != null) && (parent != null))
+     *  @param tm      its the tree model of the JTree.
+     *  @param parent  its the parent node that we want to get all the child information from.
+     *  @param tree    its the JTree where the parent node belongs to.
+     *  @return        a UserComponent that will hold the information about this parent node.  
+     */
+    private UserComponent getChildInfo (TreeModel tm,Object parent,JTree tree)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	if (tm.isLeaf(parent) == false)
+	    {
+		file.startContent(2);
+		String text;
+		text = parent.toString();
+		if (text != null)
+		    file.saveContent(text);
+		else
+		    file.saveContent(" ");
+		
+		int j;
+		for (j = 0 ; j < tm.getChildCount(parent) ; j++)
+		    {
+			file.startContent(3);
+			Object child;
+			child = tm.getChild(parent,j);
+			file.saveContent(getChildInfo(tm,child,tree));
+		    }
+	    }
+	else
+	    {
+		file.startContent(2);
+		String text;
+		text = parent.toString();
+		if (text != null)
+		    file.saveContent(text);
+		else
+		    file.saveContent(" ");
+	    }
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of a Container that is not belongs to any of the more specified
+     *  method stated in this class.
+     *  (Precondition: pane != null)
+     *  @param pane  its the Container component we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this Container.
+     */
+    public UserComponent getCompInfo (Container pane)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = pane.getComponents();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("Container");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Container"));
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		file.saveContent(messages.getString("TitlePane"));
+		file.saveContent(getInside(null));
+		/*for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)pane.getComponent(i)));
+			}*/
+	    }
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + pane.isVisible()));
+	
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JPopupMenu.
+     *  (Precondition: popup != null)
+     *  @param popup  its the JPopUpMenu we want to get the information from.
+     *  @return       a UserComponent that will hold the information about this JPopupMenu.
+     */
+    public UserComponent getPopUpMenuInfo (JPopupMenu popup)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = popup.getComponents();
+	SingleSelectionModel sm;
+	sm = popup.getSelectionModel();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("JPopUpMenu");
+
+	file.startContent(2);
+	String text;
+	text = popup.getLabel();
+	if (text != null)
+	    file.saveContent(popup.getLabel());
+	else
+	    file.saveContent(" ");
+
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)popup.getComponent(i)));
+		    }
+	    }
+
+	if (sm != null)
+	    {
+		file.startContent(4);
+		file.saveContent("" + sm.getSelectedIndex());
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + popup.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(popup.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JRootPane.
+     *  (Precondition: pane != null)
+     *  @param pane  its the JRootPane we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this JRootPane.
+     */
+    public UserComponent getRootPaneInfo (JRootPane pane)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = pane.getComponents();
+	int i;
+	
+	file.startContent(1);
+	file.saveContent("JRootPane");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("RootPane"));
+
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			
+			file.saveContent(getInside((Container)pane.getComponent(i)));
+		    }
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + pane.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(pane.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JLayeredPane.
+     *  (Precondition: pane != null)
+     *  @param pane  its the JLayeredPane we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this JLayeredPane.
+     */
+    public UserComponent getLayeredPaneInfo (JLayeredPane pane)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = pane.getComponents();
+	int i;
+	
+	file.startContent(1);
+	file.saveContent("JLayeredPane");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("LayeredPane"));
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)pane.getComponent(i)));
+		    }
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + pane.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(pane.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the BasicInternalFrameTitlePane.
+     *  (Precondition: pane != null)
+     *  @param pane  its the BasicInternalFrameTitlePane we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this BasicInternalFrameTitlePane.
+     */
+    public UserComponent getInternalFrameTitleInfo (BasicInternalFrameTitlePane pane)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = pane.getComponents();
+	int i;
+
+	file.startContent(1);
+	file.saveContent("BasicInternalFrameTitlePane");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("InternalFrameTitlePane"));
+	
+	/*if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			Component c;
+			c = pane.getComponent(i);
+			
+			else
+			    file.saveContent(getInside((Container)pane.getComponent(i)));
+		    }
+		    }*/
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + pane.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(pane.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information and add special column model and list selection
+     *  listener to JTableHeader.
+     *  (Precondition: header != null)
+     *  @param header  its the JTableHeader we want to get the information from.
+     *  @return        a UserComponent that will hold the information about this JTableHeader.
+     */
+    public UserComponent getTableHeaderInfo (JTableHeader header)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	TableColumnModel tcm;
+	tcm = header.getColumnModel();
+	ListSelectionModel lm;
+	lm = tcm.getSelectionModel();
+
+	if (tcm != null)
+	    {
+		if (hash.containsKey(tcm) == false)
+		    hash.put(tcm,header);
+		tcm.removeColumnModelListener(m);
+		tcm.addColumnModelListener(m);
+	    }
+
+	if (lm != null)
+	    {
+		if (hash.containsKey(lm) == false)
+		    hash.put(lm,header);
+		lm.removeListSelectionListener(m);
+		lm.addListSelectionListener(m);
+	    }
+
+	file.startContent(1);
+	file.saveContent("JTableHeader");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("TableHeader"));
+
+	if (tcm != null)
+	    {
+		int[] select = tcm.getSelectedColumns();
+
+		if (select != null)
+		    {
+			file.startContent(3);
+			for (int i = 0 ; i < select.length ; i++)
+			    {
+				UserComponent file2;
+				file2 = new UserComponent();
+				file2.startContent(4);
+				file2.saveContent("" + select[i]);
+				
+				file.saveContent(file2);
+			    }
+		    }
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + header.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(header.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JToolBar.
+     *  (Precondition: tool != null)
+     *  @param tool  its the JToolBar we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this JToolBar.
+     */
+    public UserComponent getToolBarInfo (JToolBar tool)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component[] group;
+	group = tool.getComponents();
+	int i;
+	
+	file.startContent(1);
+	file.saveContent("JToolBar");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("ToolBar"));
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		for (i = 0; i < group.length ; i++)
+		    {
+			file.saveContent(getInside((Container)tool.getComponent(i)));
+		    }
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + tool.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(tool.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JToolTip.
+     *  (Precondition: tip != null)
+     *  @param tip  its the JToolTip we want to get the information from.
+     *  @return     a UserComponent that will hold the information about this JToolTip.
+     */
+    public UserComponent getToolTipInfo (JToolTip tip)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	Component group;
+	group = tip.getComponent();
+	int i;
+	
+	file.startContent(1);
+	file.saveContent("JToolTip");
+	
+	file.startContent(2);
+	String text;
+	text = tip.getTipText();
+	if (text != null)
+	    file.saveContent(tip.getTipText());
+	else
+	    file.saveContent(" ");
+	
+	if (group != null)
+	    {
+		file.startContent(3);
+		file.saveContent(getInside((Container) group));
+	    }
+	
+	file.startContent(5);
+	file.saveContent(messages.getString("" + tip.isVisible()));
+	
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JSeparator.
+     *  (Precondition: sept != null)
+     *  @param sept  its the JSeparator we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this JSeparator.
+     */
+    public UserComponent getSeparatorInfo (JSeparator sept)
+    {
+	UserComponent file;
+	file = new UserComponent();
+
+	file.startContent(1);
+	file.saveContent("JSeparator");
+	
+	file.startContent(2);
+	file.saveContent(messages.getString("Separator"));
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + sept.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(sept.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will get all the information of the JDesktopPane.
+     *  (Precondition: pane != null)
+     *  @param pane  its the JDesktopPane we want to get the information from.
+     *  @return      a UserComponent that will hold the information about this JDesktopPane.
+     */
+    public UserComponent getDesktopPaneInfo (JDesktopPane pane)
+    {
+	UserComponent file;
+	file = new UserComponent();
+	JInternalFrame[]  group;
+	group = pane.getAllFrames();
+
+	file.startContent(1);
+	file.saveContent("JDesktopPane");
+
+	file.startContent(2);
+	file.saveContent(messages.getString("DesktopPane"));
+
+	if (group != null)
+	    {
+		int i;
+		file.startContent(3);
+		for ( i = 0 ; i < group.length ; i++ )
+		    {
+			file.saveContent (getInside((Container) group[i]));
+		    }
+	    }
+
+	file.startContent(5);
+	file.saveContent(messages.getString("" + pane.isVisible()));
+	
+	file.startContent(7);
+	file.saveContent(pane.getToolTipText());
+
+	return file;
+    }
+
+    /**
+     *  This method will give you a UserComponent that hold the information saying
+     *  the component is null (no component).
+     *  @return  a UserComponent that will hold the information saying its a null component.
+     */
+    public UserComponent getNullInfo ()
+    {
+	UserComponent file;
+	file = new UserComponent();
+
+	file.startContent(1);
+	file.saveContent(messages.getString("NoComponent"));
+
+	return file;
+    }
+
+    /**
+     *  This method will get all information about any kind of Container.
+     *  This method is the gateway to all other methods in this class and will give you all
+     *  information about the Container and whats inside it.If you dont know what the specific class
+     *  of your container then you go here and it will sort which appropriate method 
+     *  this container should go to in this class.
+     *  @param comp its the Container we want to get the information from.
+     *  @return     a UserComponent that hold the information about this Container.
+     */
+    public  UserComponent getInside(Container comp)
+    {
+	if (comp == null)
+	    {
+		return getNullInfo();
+	    }
+	else if (comp instanceof JApplet)
+	    {
+		return getAppletInfo ((JApplet) comp);
+	    }
+	else if (comp instanceof JSeparator)
+	    {
+		return getSeparatorInfo ((JSeparator) comp);
+	    }
+	else if (comp instanceof JWindow)
+	    {
+		return getWindowInfo((JWindow) comp);
+	    }
+	else if (comp instanceof JDialog)
+	    {
+		return getDialogInfo((JDialog) comp);
+	    }
+	else if (comp instanceof JComboBox)
+	    {
+		return getComboBoxInfo((JComboBox) comp);
+	    }
+	else if (comp instanceof JLabel)
+	    {
+		return getLabelInfo((JLabel) comp);
+	    }
+	else if (comp instanceof JTextComponent)
+	    {
+		return getTextAreaInfo((JTextComponent) comp);
+	    }
+	else if (comp instanceof JFrame)
+	    {
+		return getFrameInfo((JFrame) comp);
+	    }
+	else if (comp instanceof JPanel)
+	    {
+		return getPanelInfo((JPanel) comp);
+	    }
+	else if (comp instanceof JScrollPane)
+	    {
+		return getScrollInfo((JScrollPane) comp);
+	    }
+	else if (comp instanceof JScrollBar)
+	    {
+		return getScrollBarInfo ((JScrollBar) comp);
+	    }
+	else if (comp instanceof JViewport)
+	    {
+		return getViewPortInfo((JViewport) comp);
+	    }
+	else if (comp instanceof JTabbedPane)
+	    {
+		return getTabbedPaneInfo((JTabbedPane) comp);
+	    }
+	else if (comp instanceof Box)
+	    {
+		return getBoxInfo((Box) comp);
+	    }
+	else if (comp instanceof JToggleButton)
+	    {
+		return getToggleButtonInfo((JToggleButton) comp);
+	    }
+	else if (comp instanceof JSplitPane)
+	    {
+		return getSplitPaneInfo ((JSplitPane) comp);
+	    }
+	else if (comp instanceof JList)
+	    {
+		return getListInfo ((JList) comp);
+	    }
+	else if (comp instanceof JTree)
+	    {
+		return getTreeInfo ((JTree) comp);
+	    }
+	else if (comp instanceof JTable)
+	    {
+		return getTableInfo ((JTable) comp);
+	    }
+	else if (comp instanceof JSlider)
+	    {
+		return getSliderInfo ((JSlider) comp);
+	    }
+	else if (comp instanceof JSpinner)
+	    {
+		return getSpinnerInfo ((JSpinner) comp);
+	    }
+	else if (comp instanceof JProgressBar)
+	    {
+		return getProgressBarInfo ((JProgressBar) comp);
+	    }
+	else if (comp instanceof JButton)
+	    {
+		return getButtonInfo ((JButton) comp);
+	    }
+	else if (comp instanceof JMenu)
+	    {
+		return getMenuInfo ((JMenu) comp);
+	    }
+	else if (comp instanceof JMenuBar)
+	    {
+		return getMenuBarInfo ((JMenuBar) comp);
+	    }
+	else if (comp instanceof JMenuItem)
+	    {
+		return getMenuItemInfo ((JMenuItem) comp);
+	    }
+	else if (comp instanceof JOptionPane)
+	    {
+		return getOptionPaneInfo ((JOptionPane) comp);
+	    }
+	else if (comp instanceof BasicInternalFrameTitlePane)
+	    {
+		return getInternalFrameTitleInfo ((BasicInternalFrameTitlePane) comp);
+	    }
+	else if (comp instanceof JColorChooser)
+	    {
+		return getColorInfo ((JColorChooser) comp);
+	    }
+	else if (comp instanceof JFileChooser)
+	    {
+		return getFileChooserInfo ((JFileChooser) comp);
+	    }
+	else if (comp instanceof JDesktopPane)
+	    {
+		return getDesktopPaneInfo ((JDesktopPane) comp);
+	    }
+	else if (comp instanceof JInternalFrame)
+	    {
+		return getInternalFrameInfo ((JInternalFrame) comp);
+	    }
+	else if (comp instanceof JLayeredPane)
+	    {
+		return getLayeredPaneInfo ((JLayeredPane) comp);
+	    }
+	else if (comp instanceof JPopupMenu)
+	    {
+		return getPopUpMenuInfo ((JPopupMenu) comp);
+	    }
+	else if (comp instanceof JRootPane)
+	    {
+		return getRootPaneInfo ((JRootPane) comp);
+	    }
+	else if (comp instanceof JTableHeader)
+	    {
+		return getTableHeaderInfo ((JTableHeader) comp);
+	    }
+	else if (comp instanceof JToolBar)
+	    {
+		return getToolBarInfo ((JToolBar) comp);
+	    }
+	else if (comp instanceof JToolTip)
+	    {
+		return getToolTipInfo ((JToolTip) comp);
+	    }
+	else
+	    {
+		return getCompInfo (comp);
+	    }
+    }
+}
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/FeedbackInterface.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/FeedbackInterface.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/FeedbackInterface.java	(revision 10506)
@@ -0,0 +1,1654 @@
+package org.greenstone.gatherer.feedback;
+
+import java.io.*;
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import java.util.*;
+import java.net.*;
+import java.rmi.server.*;
+import javax.imageio.*;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+import com.sun.image.codec.jpeg.*;
+import javax.swing.Timer;
+import org.greenstone.gatherer.util.Utility;
+
+/**
+ * This class will show the FeedbackInterface form.
+ * It will allow user to described about the problem better.Here we will also take some more information available
+ * in the system such as the size of the memory available and the screen size.User also could take more screenshot
+ * so they will be able to say the sequence of events that lead up to the problem.
+ * <br>If the user don't want to send this form, then all the information taken from this form will be deleted 
+ * and user will be quitted from the Reporting Feedback sequence.
+ *
+ * @author Veronica Liesaputra
+ */
+public class FeedbackInterface extends JDialog
+    implements ActionListener
+{
+    /**
+     * This is the button user need to pressed if they want to view the files.
+     * This button will be disabled when the timer is running and finish = false.
+     */
+    private JButton view_button;
+    
+    /**
+     * This button means that the user finished give the information and
+     * want to send it.
+     */
+    public JButton send_button;
+
+    /**
+     * This button means that the user don't want to send information and
+     * back to normal application.
+     * All the data taken start from user choose to start doing the Feedback sequence 
+     * up to this point will be delete.
+     */
+    private JButton notsend_button; 
+
+    /**
+     * This is the text area where user can explain more about the problem.
+     */
+    private JTextArea problem_details;
+
+    /**
+     * This is the combo box that allow user to specify the poblem type.
+     */
+    private JComboBox problem_type;
+
+    /**
+     * This is the combo box that allow user to specify the urgency of the problem.
+     */
+    private JComboBox problem_urgency;
+
+    /**
+     * This combo box will ask whether or not user want to send the screenshot.
+     */
+    private JComboBox problem_screenshot;
+
+    /**
+     * This text field allow user to type the smtp address of their email that
+     * they want this application to use to send all the data.
+     * If they don't fill this field then it will set to the same
+     * smtp adress of where the data will be send to.
+     */
+    private JTextField smtp_address;
+
+    /**
+     * This text field allow user to type the email adress that they want this
+     * application to use to send all the data.
+     * If they don't fill this field then it will set to the same email
+     * adress of where the data will be send to.
+     */
+    private JTextField email_address;
+
+    /**
+     * This is the name of the window the user lastly used.
+     * This is the name of the window where the user called to start the Feedback
+     * sequence.
+     */
+    private String frameName;
+
+    /**
+     * This is the unique code generated for each time user start doing the Feedback
+     * sequence.
+     * This code will be used as reference to which feedback that the user send.
+     */
+    private static String code;
+
+    /**
+     * This is the date when the user start open this FeedbackInterface form.
+     */
+    private Date curr_date;
+    
+    /**
+     * This is the special listener class that record all the action user did in application.
+     */
+    private static ActionRecorderDialog dialog;
+
+    /**
+     * This variable will hold the resource of the words that is stored in Messages.properties file.
+     * The calling using messages.getString(someString) will caused someString to be translated
+     * into some other string that is hold in that file.usually it will caused it to be translated
+     * to the language that the user use or choose to have as stated in Locale.
+     */
+    private static ResourceBundle messages;
+
+    /**
+     * This is the screen shot instance that will allow the application to take screen shot of the whole
+     * screen or only the window that the user currently doing their action.
+     */
+    private ScreenShot screen;
+
+    /**
+     * This is the thread that allows the encoding of the image file to String and the saving of image to
+     * a jpeg file happens concurrently.
+     */
+    private Thread save;
+
+    /**
+     * This is the hashmap that hold the screen shot and the panel where the screenshot is held.
+     */
+    private HashMap picAndPane;
+
+    /**
+     * This is the panel that hold all the panels containing the screenshots taken.
+     */
+    private JPanel picture_scroll;
+
+    /**
+     * This is how many rows of screenshots panel displayed at the moment.
+     */
+    private int row;
+
+    /**
+     * This is the array list that hold all the screenshots panel displayed.
+     */
+    private ArrayList paneArray;
+
+    /**
+     * This button will remove the last screenshot panels.
+     */
+    private JButton remove;
+
+    /**
+     * This is a reference to feedback interface displayed at the moment.
+     */
+    private FeedbackInterface frame;
+
+    /**
+     * This is the thread to send all the xml files back to the developer.
+     */
+    private Thread sendThread;
+
+    /**
+     * This is the flag to tell whether or not the sending files finished or not.
+     * It is also flag to tell whether or not the viewing files finished or not.
+     */
+    private static boolean finish;
+
+    /**
+     * This is the timer to displayed the progress bar to tell user to wait while
+     * we sending the files or while we generate the xml files to be viewed.
+     * If finish = false then wait cursor,progress bar and wait label will be displayed.
+     * If finish = true then default cursor will be displayed.
+     */
+    private Timer timer;
+
+    /**
+     * Progress bar displayed when user sending or want to view details.
+     */
+    private JProgressBar progressBar;
+
+    /**
+     * Label displayed to tell user to wait for a while.
+     */
+    private JLabel wait_lbl;
+
+    /**
+     * This is the background colour for the window.
+     */
+    private Color bckcolor;
+    
+    /**
+     * This is the panel to displayed all descriptions panel.
+     */
+    private JPanel tempPane;
+
+    /**
+     * This is the thread that will be running when user pressed the preview button.
+     * This thread will show the 6 xml files that are going to be send. It will run concurrently
+     * with the timer, if value of finish = true, this thread will be null-ed.
+     */
+    private Thread prevThread;
+    
+    /**
+     * This is the flag to say whether or not this window should be dispose when timer is stop
+     * and finish = true.
+     * If selected = true then this window should be dispose, otherwise don't dispose it.
+     */
+    private boolean selected = false;
+    
+    /**
+     * This is a blocker to say that user cannot do anything while waiting.
+     */
+    private MouseListener mouse_blocker_listener = new MouseAdapter() {};
+ 
+    /**
+     * Will make a dialog window that allows people to write more about the problem that want
+     * to send.
+     * This is the GUI for user to write on Feedback form. It is also setting the up the appropriate 
+     * data member with the value passed on to this constructor.
+     * (Precondition: (sh != null) && (dlg != null) && (msg != null))
+     * @param sh  an instance of ScreenShot that will allow application to take screenshot.
+     * @param frame_name name of the window where user called Feedback form from.
+     * @param msg holding the resource of the words that is stored in Messages.properties file.
+     * @param dlg holding the special listener.
+     */
+    public FeedbackInterface(ScreenShot sh,String frame_name,
+			     ResourceBundle msg,ActionRecorderDialog dlg)
+    {
+	super();
+
+	frame = this;
+
+	bckcolor = new Color(176,209,217);
+
+	picAndPane = new HashMap();
+
+	messages = msg;
+	frameName = frame_name;
+	dialog = dlg;
+
+	FeedbackInterface.setDefaultLookAndFeelDecorated(true);
+	setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+	setTitle(messages.getString("SendFeedbackForm"));
+	
+	screen = sh;
+	Container container;
+	container = getContentPane();
+	createUI(container);
+	curr_date = new Date();
+	
+	Toolkit kit;
+	kit = Toolkit.getDefaultToolkit();
+	Dimension screenSize;
+	screenSize = kit.getScreenSize();
+	int screenHeight;
+	screenHeight = screenSize.height;
+	int screenWidth;
+	screenWidth = screenSize.width;
+	Dimension size;
+	size = this.getSize();
+	setLocation((screenWidth - size.width - 500) , 
+		    (screenHeight - size.height - 700));
+	
+	setBackground(bckcolor);
+	pack();
+	setModal(false);
+	setVisible(true);
+    }
+
+    /**
+     * This method is setting up the content pane for the Feedback form window.
+     * (Precondition: (window != null))
+     * @param window the content pane of Feedback form window. 
+     */
+    public void createUI(Container window)
+    {
+	JPanel container;
+	container = new JPanel();
+	container.setBackground(bckcolor);
+	container.setLayout(new BoxLayout(container,BoxLayout.PAGE_AXIS));
+	
+	String opening_text;
+	opening_text = messages.getString("FeedbackOpeningText");
+	JTextArea textArea;
+	textArea = new JTextArea(opening_text);
+	textArea.setMinimumSize(new Dimension(100,100));
+	textArea.setOpaque(false);
+	textArea.setEditable(false);
+	textArea.setLineWrap(true);
+	textArea.setWrapStyleWord(true);
+	textArea.setBorder(new EmptyBorder(10,10,0,10));
+	textArea.setBackground(bckcolor);
+	container.add(textArea);
+
+	tempPane = new JPanel();
+	tempPane.setLayout(new BorderLayout());
+	tempPane.setBackground(new Color(176,208,176));
+
+	paneArray = new ArrayList();
+	picture_scroll = new JPanel();
+	row = 1;
+	picture_scroll.setLayout(new GridLayout(0,1));
+	picture_scroll.setBackground(new Color(176,208,176));
+	tempPane.add(picture_scroll,BorderLayout.PAGE_START);
+
+	JPanel btnPanel;
+	btnPanel = new JPanel();
+	btnPanel.setBackground(new Color(176,208,176));
+	remove = new JButton("Remove");
+	remove.setActionCommand("Remove");
+	remove.addActionListener(new ActionListener ()
+	    {
+		public void actionPerformed(ActionEvent e)
+		{
+		    Object obj;
+		    JPanel pane;
+
+		    if (paneArray.size() == 0)
+			System.out.println("There is no panel here!");
+		    else
+			{
+			    pane = (JPanel) paneArray.get((row - 2));
+			    obj = picAndPane.get(pane);
+			    obj = null;
+			    picAndPane.remove(pane);
+			    paneArray.remove((row - 2));
+			    
+			    if (paneArray.size() == 0)
+				remove.setVisible(false);
+
+			    picture_scroll.remove(pane);
+			
+			    row--;
+			    
+			    picture_scroll.setSize(picture_scroll.getPreferredSize());
+			    picture_scroll.revalidate();
+			    picture_scroll.repaint();
+			    tempPane.setSize(tempPane.getPreferredSize());
+			    tempPane.revalidate();
+			    tempPane.repaint();
+			}
+		}
+	    });
+	remove.setToolTipText("Remove last thumbnail");
+	remove.setBackground(new Color(176,208,176));
+	remove.setVisible(false);
+	btnPanel.add(remove);
+	tempPane.add(btnPanel,BorderLayout.PAGE_END);
+   
+	JScrollPane pict_scroll;
+	pict_scroll = new JScrollPane(tempPane);
+	pict_scroll.setBackground(bckcolor);
+	pict_scroll.setPreferredSize(new Dimension(300,300));
+	pict_scroll.setBorder(new EmptyBorder(0,10,10,10));
+	container.add(pict_scroll);
+
+	JPanel pane;
+	pane = new JPanel();
+	pane.setBackground(bckcolor);
+	pane.setLayout(new GridLayout(0,2));
+	pane.setBorder(new EmptyBorder(10,10,10,10));
+		
+	JLabel txt_type;
+	txt_type = new JLabel(messages.getString("Whatkindofproblemisit") + "?    ");
+	txt_type.setBackground(bckcolor);
+	pane.add(txt_type);
+	
+	String [] type = {" ",messages.getString("ContentError"),
+			  messages.getString("ImageNotShow"),
+			  messages.getString("StrangeBehaviour"),
+			  messages.getString("SomethingUnexpectedHappen"),
+			  messages.getString("HardToUse"),
+			  messages.getString("Other")};
+	problem_type = new JComboBox(type);
+	problem_type.addActionListener(this);
+	problem_type.setBackground(bckcolor);
+	pane.add(problem_type);
+
+	JLabel txt_urgent;
+	txt_urgent = new JLabel(messages.getString("Howbadistheproblem")+"?  ");
+	txt_urgent.setBackground(bckcolor);
+	pane.add(txt_urgent);
+
+	String[] urgent = {" ",messages.getString("Critical"),
+		  messages.getString("Serious"),
+		  messages.getString("Medium"),messages.getString("Minor"),
+		  messages.getString("Trivial")};
+	problem_urgency = new JComboBox(urgent);
+	problem_urgency.addActionListener(this);
+	problem_urgency.setBackground(bckcolor);
+	pane.add(problem_urgency);
+
+	/*JLabel txt_screenshot;
+	txt_screenshot= new JLabel(messages.getString("Doyouwanttosendthescreenshot") + "?  ");
+	txt_screenshot.setBackground(new Color(108,168,108));
+	pane.add(txt_screenshot);
+
+	String[] screenshot = {messages.getString("Yes"),
+			       messages.getString("No")};
+	problem_screenshot = new JComboBox(screenshot);
+	problem_screenshot.addActionListener(this);
+	problem_screenshot.setBackground(new Color(108,168,108));
+	pane.add(problem_screenshot);*/
+	
+	
+	/*JLabel txt_smtp;
+	txt_smtp = new JLabel(messages.getString("SMTPaddress") + "?  ");
+	txt_smtp.setBackground(new Color(176,208,176));
+	pane.add(txt_smtp);
+
+	smtp_address = new JTextField();
+	smtp_address.setBackground(new Color(224,240,224));
+	pane.add(smtp_address);*/
+	
+
+	/*JLabel txt_email;
+	txt_email = new JLabel(messages.getString("Emailaddress") + "?  ");
+	txt_email.setBackground(new Color(176,208,176));
+	pane.add(txt_email);
+
+	email_address = new JTextField();
+	email_address.setBackground(new Color(224,240,224));
+	pane.add(email_address);*/
+	
+	JLabel empty;
+	empty = new JLabel ("   ");
+	empty.setBackground(bckcolor);
+	pane.add(empty);
+	JLabel empty2;
+	empty2 = new JLabel ("   ");
+	empty2.setBackground(bckcolor);
+	pane.add(empty2);
+	container.add(pane);
+
+	JPanel panely;
+	panely = new JPanel();
+	panely.setLayout(new GridLayout(0,3));
+	panely.setBackground(bckcolor);
+	panely.setBorder(new EmptyBorder(new Insets(10,10,10,10)));
+	
+	view_button = new JButton("Details . . .");
+	view_button.setActionCommand(messages.getString("Preview"));
+	view_button.addActionListener(this);
+	view_button.setToolTipText(messages.getString("ConformationPreview"));
+	view_button.setBackground(bckcolor);
+	panely.add(view_button); 
+
+	send_button = new JButton(messages.getString("Send"));
+	send_button.setActionCommand(messages.getString("Send"));
+	send_button.addActionListener(this);
+	send_button.setDefaultCapable(true);
+	send_button.setToolTipText(messages.getString("FeedbackSendButton"));
+	send_button.setBackground(bckcolor);
+	panely.add(send_button);
+	
+	notsend_button = new JButton("Cancel");
+	notsend_button.setActionCommand(messages.getString("NotSend"));
+	notsend_button.addActionListener(this);
+	notsend_button.setToolTipText(messages.getString("FeedbackNotSendButton"));
+	notsend_button.setBackground(bckcolor);
+	panely.add(notsend_button);
+	container.add(panely);
+
+	//Align the left edges of the components.
+	textArea.setAlignmentX(Component.LEFT_ALIGNMENT);
+	pict_scroll.setAlignmentX(Component.LEFT_ALIGNMENT);
+	pane.setAlignmentX(Component.LEFT_ALIGNMENT);
+	panely.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+	String about;
+	about = messages.getString("FeedbackAboutText");
+	JTextArea about_txt;
+	about_txt = new JTextArea(about);
+	about_txt.setEditable(false);
+	about_txt.setLineWrap(true);
+	about_txt.setWrapStyleWord(true);
+	about_txt.setBackground(bckcolor);
+	about_txt.setBorder(new EmptyBorder(10,10,10,10));
+
+	String privacy;
+	privacy = messages.getString("FeedbackPrivacyText");
+	JTextArea privacy_txt;
+	privacy_txt = new JTextArea(privacy);
+	privacy_txt.setEditable(false);
+	privacy_txt.setLineWrap(true);
+	privacy_txt.setWrapStyleWord(true);
+	privacy_txt.setBackground(bckcolor);
+	privacy_txt.setBorder(new EmptyBorder(10,10,10,10));
+ 
+	JTabbedPane tab;
+	tab = new JTabbedPane();
+	tab.setBackground(bckcolor);
+	tab.addTab(messages.getString("Form"),container);
+	tab.addTab(messages.getString("About"),about_txt);
+	tab.addTab(messages.getString("Privacy"),privacy_txt);
+	tab.setBorder(new EmptyBorder(5,5,5,5));
+	
+	JPanel panelx;
+	panelx = new JPanel();
+	panelx.setLayout(new BoxLayout(panelx,BoxLayout.PAGE_AXIS));
+	panelx.setBackground(bckcolor);
+	panelx.setBorder(new EmptyBorder(new Insets(10,10,10,10)));
+	
+	wait_lbl = new JLabel(messages.getString("Pleasewait"));
+	wait_lbl.setBackground(bckcolor);
+	wait_lbl.setVisible(false);
+	panelx.add(wait_lbl);
+	
+	progressBar = new JProgressBar ();
+	progressBar.setBackground(bckcolor);
+	progressBar.setVisible(false);
+	panelx.add(progressBar);
+
+	JLabel emp2;
+	emp2 = new JLabel ("   ");
+	emp2.setBackground(bckcolor);
+	panelx.add(emp2);
+
+	wait_lbl.setAlignmentX(Component.CENTER_ALIGNMENT);
+	progressBar.setAlignmentX(Component.CENTER_ALIGNMENT);
+	emp2.setAlignmentX(Component.CENTER_ALIGNMENT);
+
+	final String p1;
+	final String p2;
+	p1 = "Tab";
+	p2 = "ProgressBar";
+
+	final JPanel cards;
+	cards = new JPanel(new CardLayout());
+	cards.setBackground(bckcolor);
+	cards.add(tab,p1);
+	cards.add(panelx,p2);
+
+	window.add(cards);
+
+	
+	timer = new Timer(1000, new ActionListener()
+	    {
+		public void actionPerformed(ActionEvent evt)
+		{
+		    if (finish == true)
+			{
+			    if (sendThread != null)
+				{
+				    sendThread.interrupt();
+				    sendThread = null;
+				}
+
+			    if (prevThread != null)
+				{
+				    prevThread.interrupt();
+				    prevThread = null;
+				}
+			    
+			    Component glass_pane;
+			    glass_pane = frame.getGlassPane();
+			    
+			    glass_pane.setVisible(false);
+			    glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+			    glass_pane.removeMouseListener(mouse_blocker_listener);
+			    
+			    wait_lbl.setVisible(false);
+			    progressBar.setIndeterminate(false);
+			    progressBar.setVisible(false);
+			    
+			    frame.setTitle(messages.getString("SendFeedbackForm"));
+			    
+			    CardLayout cl = (CardLayout)(cards.getLayout());
+			    cl.show(cards,p1);
+			    
+			    if (selected == true)
+				frame.dispose();
+
+			    timer.stop();
+			}
+		    else
+			{
+			    Component glass_pane;
+			    glass_pane = frame.getGlassPane();
+			    
+			    glass_pane.addMouseListener(mouse_blocker_listener);
+			    glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+			    glass_pane.setVisible(true);
+
+			    frame.setTitle("Please wait...");
+
+			    CardLayout cl = (CardLayout)(cards.getLayout());
+			    cl.show(cards,p2);
+
+			    wait_lbl.setVisible(true);
+			    progressBar.setIndeterminate(true);
+			    progressBar.setVisible(true);
+			}
+		}
+	    });
+    }
+
+    /**
+     * This method will set the finish variable values.
+     * When the sending files is finished, the sending application  will set the finish value to true.
+     * @param fin whether or not the send files is finished.
+     */
+    public static void setFinish (boolean fin)
+    {
+	finish = fin;
+    }
+
+    /**
+     * This is the class to represent the whole panel that hold the screenshot and the comments
+     * about the screenshot.
+     */
+    private class ThumbnailPic implements Serializable
+    {
+	/**
+	 * This is the panel that hold a thumbnail for a screenshot and a comments text area.
+	 */
+	private JPanel picpane;
+
+	/**
+	 * This hold the BufferedImages for the whole screen version of screenshot.
+	 */
+	private BufferedImage[] screenimages;
+
+	/**
+	 * This hold the BufferedImages for the window version only.
+	 */
+	private BufferedImage[] windowimages;
+
+	/**
+	 * This is the text area where user can enter their comments.
+	 */
+	private JTextArea problem_details;
+
+	/**
+	 * This is a flag to tell us which image user wants to send.Its defaults value is false.
+	 * If iswindow = true then it means user wants to send the window version only.
+	 * If iswindow = false then it means user wants to send the whole screen version.
+	 */
+	private boolean iswindow;
+
+	/**
+	 * This is the titles for the panel.
+	 * Usually this is the title of the window where user wants to do the screenshot.
+	 * If the title is more than 40 characters then we will trim it and add ... at the back of it.
+	 */
+	private String titles;
+
+	/**
+	 * This is the width of the image user wants to send.
+	 */
+	private String iw;
+
+	/**
+	 * This is the height of the image user wants to send.
+	 */
+	private String ih;
+
+	/**
+	 * This is the x-coordinate where the window located inside the whole screen image.
+	 */
+	private int xcoord;
+
+	/**
+	 * This is the y-coordinate where the window located inside the whole screen image.
+	 */
+	private int ycoord;
+
+	/**
+	 * This is the width of the window inside the whole screen image.
+	 */
+	private int width;
+
+	/**
+	 * This is the height of the window inside the whole screen image.
+	 */
+	private int height;
+
+	/**
+	 * This is the constructor that will setup the panel that contains
+	 * a thumbnail screenshot and a comments text area.
+	 * @param image the whole screen screenshot image.
+	 * @param text  the title for this pane.
+	 * @param x     the x-coordinate of the window inside the whole screen image.
+	 * @param y     the y-coordinate of the window inside the whole screen image.
+	 * @param w     the width of the window inside the whole screen image.
+	 * @param h     the height of the window inside the whole screen  image. 
+	 */
+	//public ThumbnailPic (BufferedImage screen,byte[] image,String text)
+	public ThumbnailPic (BufferedImage image,String text,int x,int y,int w,int h)
+	{
+	    xcoord = x;
+	    ycoord = y;
+	    width = w;
+	    height = h;
+	    iswindow = false;
+	    titles = text;
+	    screenimages = new BufferedImage[3];
+	    windowimages = new BufferedImage[3];
+	    //screenimages[0] = screen;
+	    screenimages[0] = image;
+	    screenimages[1] = null;
+	    screenimages[2] = null;
+	    windowimages[0] = null;
+	    windowimages[1] = null;
+	    windowimages[2] = null;
+	    addPanel(image);
+	}
+
+	/**
+	 * This method will setup the components inside the panel properly.
+	 * @param image the whole screen screenshot image.
+	 */
+	//public void addPanel (byte[] image)
+	public void addPanel (BufferedImage image)
+	{
+	    picpane = new JPanel();
+	    picpane.setLayout(new BorderLayout());
+	    
+	    final JButton picture;
+	    picture = new JButton();
+
+	    int w;
+	    int h;
+
+	    w = (int) (150/2);
+	    h = (int) (150/2);
+	    
+	    iw = "" + image.getWidth();
+	    ih = "" + image.getHeight();
+
+	    ImageIcon thumbnail;
+	    thumbnail = new ImageIcon(image.getScaledInstance(w,h,Image.SCALE_SMOOTH));
+
+	    picture.setIcon(thumbnail);
+	    picture.setText("Draw . . .");
+	    picture.setActionCommand("Scribble");
+	    picture.addActionListener(new ActionListener()
+		{
+		    public void actionPerformed (ActionEvent e)
+		    {
+			frame.addMouseListener(mouse_blocker_listener);
+			frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+			SelectPicture select;
+			select = new SelectPicture(screenimages,windowimages,iswindow,problem_details.getText(),messages);
+			frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+			frame.removeMouseListener(mouse_blocker_listener);	
+			select.setWindowBounds(xcoord,ycoord,width,height);
+			
+			iswindow = select.getIsWindow();
+
+			screenimages[0] = select.getImage3();
+			screenimages[1] = select.getImage();
+			screenimages[2] = select.getImage2();
+
+			if (iswindow == true)
+			    {
+				windowimages[0] = select.getWindowImage3();
+				windowimages[1] = select.getWindowImage();
+				windowimages[2] = select.getWindowImage2();
+			    }
+			else
+			    {
+				windowimages[0] = null;
+				windowimages[1] = null;
+				windowimages[2] = null;
+			    }
+			
+			problem_details.setText(select.getDetails());
+
+			int w,h;
+			w = (int) (150/2);
+			h = (int) (150/2);
+			
+			ImageIcon thumbnail;
+
+			if (iswindow == false)
+			    thumbnail = new ImageIcon(screenimages[1].getScaledInstance(w,h,Image.SCALE_SMOOTH));
+			else
+			    thumbnail = new ImageIcon(windowimages[1].getScaledInstance(w,h,Image.SCALE_SMOOTH));
+
+			picture.setIcon(thumbnail);
+			
+			if (select.getSendNow() == true)
+			    {
+				ActionEvent evt;
+				evt = new ActionEvent(send_button,ActionEvent.ACTION_PERFORMED,messages.getString("Send"));
+
+				frame.actionPerformed(evt);
+			    }
+		    }
+		});
+	    picture.setToolTipText("Click if you want to draw on it");
+	    picture.setMargin(new Insets(5,5,5,5));
+	    picture.setVerticalTextPosition(AbstractButton.BOTTOM);
+	    picture.setHorizontalTextPosition(AbstractButton.CENTER);
+	    picture.setBackground(new Color(176,208,176));
+	    picpane.add(picture,BorderLayout.LINE_START);
+	    
+	    JPanel txtPane;
+	    txtPane = new JPanel(new BorderLayout());
+	    txtPane.setBackground(new Color(176,208,176));
+	    txtPane.setBorder(new EmptyBorder(5,5,5,5));
+
+	    JLabel lbldesc = new JLabel("Comments :");
+	    lbldesc.setBackground(new Color(176,208,176));
+	    txtPane.add(lbldesc,BorderLayout.PAGE_START);
+
+	    problem_details = new JTextArea();
+	    problem_details.setWrapStyleWord(true);
+	    problem_details.setEditable(true);
+	    problem_details.setBackground(new Color(224,240,224));
+	   
+	    JScrollPane scroll;
+	    scroll = new JScrollPane(problem_details);
+	    scroll.setBackground(new Color(176,208,176));
+	    scroll.setPreferredSize(new Dimension(300,150));
+	    txtPane.add(scroll,BorderLayout.LINE_START);
+	   
+	    picpane.setSize(new Dimension(150,150));
+	    picpane.add(txtPane,BorderLayout.CENTER);
+	}
+
+	/**
+	 * This method will get the width of the image user wants to send.
+	 * @return the width of the image.
+	 */
+	public String getWidth()
+	{
+	    if (iswindow == false)
+		return "" + screenimages[0].getWidth();
+	    else
+		{
+		    return "" + windowimages[0].getWidth();
+		}
+	}
+
+	/**
+	 * This method will get the height of the image user wants to send.
+	 * @return the height of the image.
+	 */
+	public String getHeight()
+	{
+	    if (iswindow == false)
+		return "" + screenimages[0].getHeight();
+	    else
+		{
+		    return "" + windowimages[0].getHeight();
+		}  
+	}
+
+	/**
+	 * This method will get the titles of this panel.
+	 * @return the panel's title.
+	 */
+	public String getTitles()
+	{
+	    return titles;
+	}
+
+	/**
+	 * This method will get user comments inside the text area.
+	 * @return the user's comments.
+	 */
+	public String getProblemDetails ()
+	{
+	    String txt;
+	    txt = problem_details.getText();
+	    
+	    if (txt == null)
+		return " ";
+	    else
+		return txt;
+	}
+
+	/**
+	 * This method will setting up the text inside the text area.
+	 * @param comments the text set to the text area.
+	 */
+	public void setComments (String comments)
+	{
+	    problem_details.setText(comments);
+	}
+
+	/**
+	 * This method will get the image that user wants to send.
+	 * @return image going to be send.
+	 */
+	public BufferedImage[] getImages ()
+	{
+	    if (iswindow == false)
+		return screenimages;
+	    else
+		return windowimages;
+	}
+
+	/**
+	 * This method will get the non-scribble lines image that user wants to send.
+	 * @return the string representation of the non-scribble lines image.
+	 */
+	public String getScreenImage ()
+	{
+	    if (iswindow == false)
+		return convert(screenimages[0]);
+	    else
+		return convert(windowimages[1]);
+	}
+
+	/**
+	 * This method will get the scribble lines image that user wants to send.
+	 * @return the string representation of the scribble lines image.
+	 */
+	public String getScreenAndLineImage ()
+	{
+	    if (iswindow == false)
+		{
+		    if (screenimages[1]!= null)
+			return convert(screenimages[1]);
+		    else
+			return convert(screenimages[0]);
+		}
+	    else
+		{
+		    if (windowimages[1]!= null)
+			return convert(windowimages[1]);
+		    else
+			return convert(windowimages[0]);
+		}
+	}
+
+	/**
+	 * This method will get only scribble lines image that user wants to send.
+	 * @return the string representation of the only scribble lines image.
+	 */
+	public String getLineForScreenImage ()
+	{
+	    if (iswindow == false)
+		{
+		    if (screenimages[2] != null)
+			return convert(screenimages[2]);
+		    else
+			return "";
+		}
+	    else
+		{
+		    if (windowimages[2] != null)
+			return convert(windowimages[2]);
+		    else
+			return "";
+		}
+	}
+
+	/**
+	 * This method will get the panel that hold a thumbnail and a text area.
+	 * @return panel that represent the thumbnail and the text area.
+	 */
+	public JPanel getPanel()
+	{
+	    return picpane;
+	}
+    }
+
+    /**
+     * This method will setting up the comments to be displayed inside the latest added panel.
+     * So if the window where user wants to take the screenshot at the moment is a modal window
+     * then it will setting the comments to ask user to close the window before they can enter
+     * their comments there.
+     * @param modal the modality of the window where user wants to take the screenshot.
+     */
+    public void setComment (boolean modal)
+    {
+	if (paneArray.size() == 0)
+	    System.out.println("There is no panel here!");
+	else
+	    {
+		JPanel pane;
+		pane = (JPanel) paneArray.get((row - 2));
+		ThumbnailPic obj;
+		obj = (ThumbnailPic) picAndPane.get(pane);
+		String text;
+		if (modal == true)
+		    text = "Please close '" + obj.getTitles() + "' window \nbefore you can enter comments here.";
+		else
+		    text = " ";
+		obj.setComments(text);
+	    }
+    }
+
+    /**
+     * This method will add a panel that contains the thumbnail button and the text area.
+     * @param title the window's title.
+     * @param image the whole screen image.
+     * @param x     the window's x-coordinate in the image.
+     * @param y     the window's y-coordinate in the image.
+     * @param width the window's width in the image.
+     * @param height the window's height in the image.
+     */
+    //public void addScreenPanel (String title,BufferedImage screen,byte[] image)
+    public void addScreenPanel (String title,BufferedImage image,int x,int y,int width,int height)
+    {
+	final JPanel pane;
+	pane = new JPanel();
+	pane.setLayout(new BorderLayout());
+	pane.setBackground(new Color(176,208,176));
+
+	Border loweredetched;
+	loweredetched = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
+
+	String ttl;
+	if (title.length() > 41)
+	    ttl = title.substring(0,40) + "  . . . ";
+	else
+	    ttl = title;
+
+	TitledBorder border;
+	border = BorderFactory.createTitledBorder(loweredetched, title);
+	border.setTitleJustification(TitledBorder.LEFT);
+	
+	pane.setBorder(BorderFactory.createCompoundBorder(new EmptyBorder(5,5,5,5),border));
+	
+	ThumbnailPic pic;
+	//pic = new ThumbnailPic(screen,image,title);
+	pic = new ThumbnailPic(image,title,x,y,width,height);
+	picAndPane.put(pane,pic);
+	pane.add(pic.getPanel(),BorderLayout.LINE_START);
+
+	remove.setVisible(true);
+	picture_scroll.add(pane);
+	paneArray.add(pane);
+	row++;
+	picture_scroll.setSize(picture_scroll.getPreferredSize());
+	picture_scroll.revalidate();
+	picture_scroll.repaint();
+	tempPane.setSize(tempPane.getPreferredSize());
+	tempPane.revalidate();
+	tempPane.repaint();
+    }
+
+    /**
+     * This method will generate the unique code that will be used as the 
+     * reference number of the feedback that user are about to send.
+     * @return the unique code.
+     */
+    public String getPrevData ()
+    {
+	try
+	    {
+		UID id = new UID();
+		code =  "" + InetAddress.getLocalHost().hashCode() + id.hashCode();
+	    }
+	catch (UnknownHostException exp) {}
+	return code;
+    }
+
+    /**
+     * This method allows another class to get the unique code that can be used as 
+     * the reference number of the feedback that user are about to send.
+     * This method should be called only if 
+     * getPrevData() method already been called before.Otherwise it will return null. 
+     * @return the unique code
+     */
+    public static String getCode()
+    {
+	return code;
+    }
+
+    /**
+     * This method will encode BufferedImage into their String representation using
+     * Base64 encoder.
+     * (Precondition: (image != null))
+     * @param image is the image that we want to encode to String.
+     */
+    public String convert (BufferedImage image)
+    {
+	String txt;
+	txt = null;
+
+	try
+	    {
+		ByteArrayOutputStream stream = new ByteArrayOutputStream();
+		ImageIO.write(image,"jpeg",stream);
+		byte[] bytes = stream.toByteArray();
+
+		txt = Base64.encodeBytes(bytes);
+		
+	    }
+	catch(IOException ex) {}
+
+	return txt;
+    }
+
+    /**
+     * This method is to make sure that there is no thread running at the moment.
+     */
+    private void ensureEventThread()
+    {
+	if(SwingUtilities.isEventDispatchThread())
+	    {
+		return;
+	    }
+	throw new RuntimeException(messages.getString("file"));
+    }
+
+    /**
+     * This method will create all 6 xml files, jarred them into one file, deletes all xml files and
+     * sending it.
+     * The xml files for:
+     * <br> 1.The history & information of all the actions done and windows opened by the application
+     *        after user choose to start the sequence of sending feedback.
+     * <br> 2.The history of all the commands (actions) done by the user before choosing
+     *        after start the sequence of sending feedback.
+     * <br> 3.The informations we get from the feedback interface form period.
+     * <br> will be getting from vector and the temp_feedbackhist.log file.
+     * (Precondition: (sx != null) && (vector != null) && (err_array != null))
+     * @param sx the xml parser.
+     * @param vector the vector that hold the history and information.
+     * @param err_array the arrays of information we take from the feedback interface period.
+     * @param imgFile   the arrays of information we take from the panels inside feedback interface form.
+     */
+    private void sendState (SaveToXML sx,Vector vector,String[] err_array,String[] imgFile)
+    {
+	String dirname;
+	dirname = "xmlfeedback/";
+	
+	File dir = new File("xmlfeedback");
+	if (dir.isDirectory() == false)
+	    dir.mkdir();
+
+	sx.saveFeedback(err_array,imgFile);
+	
+	sx.open(dirname + "feedbackcontent" + FeedbackInterface.getCode() + ".xml",
+		"HISTORY");
+	SaveToXML sx2;
+	sx2 = new SaveToXML(messages);
+	sx2.open(dirname + "feedbackcommand" + FeedbackInterface.getCode() + ".xml",
+		 "COMMANDS");
+	
+	for (int i = 0 ; i < vector.size() ; i++)
+	    {
+		History log;
+		log = (History) vector.get(i);
+		log.sendXML(sx);
+		log.sendXMLComm(sx2);
+	    }
+	
+	Vector stack;
+	stack = getPrev_log();
+	if (stack != null)
+	    {
+		for (int i = 0 ; i < stack.size() ; i++)
+		    {
+			History log;
+			log = (History) stack.get(i);
+			log.sendXML(sx);
+			log.sendXMLComm(sx2);
+		    }
+		stack.removeAllElements();
+		System.gc();
+		stack = null;
+	    }
+	
+	sx2.close("COMMANDS");
+	sx.close("HISTORY");
+	
+	getHistPrev_log(sx,sx2);
+	
+	ZipFile zip;
+	zip = new ZipFile();
+	zip.sendZipXMLFile();
+
+	File f;
+	f = new File (dirname + "feedback" + FeedbackInterface.getCode() + ".xml");
+	f.delete();
+	f = new File (dirname + "feedbackcontent" + FeedbackInterface.getCode() + ".xml");
+	f.delete();
+	f = new File (dirname + "feedbackcommand" + FeedbackInterface.getCode() + ".xml");
+	f.delete();
+	/*f = new File (dirname + "content" + FeedbackInterface.getCode() + ".xml");
+	  f.delete();*/
+	f = new File (dirname + "command" + FeedbackInterface.getCode() + ".xml");
+	f.delete();
+	
+	String[] args = new String[5];
+	args[0] = "vl6@cs.waikato.ac.nz";
+	args[1] = dirname + "Jar" + FeedbackInterface.getCode() + "File.jar";
+	args[4] = "lib/parser.jar";
+	args[2] = err_array[19];
+	args[3] = err_array[20];
+	SendHTTP sm = new SendHTTP();
+	//SendMail sm = new SendMail();
+	sm.sendMail(args,messages,FeedbackInterface.getCode());
+    }
+	
+    /**
+     * This method will create the 2 xml files.
+     * The xml files are:
+     * <br> 1.The history & information of all the actions done and windows opened by the application
+     *         before user choose to start the sequence of sending feedback.
+     * <br> 2.The history of all the commands (actions) done by the user before choosing
+     *         to start the sequence of sending feedback.
+     * <br> The information will be getting from history.log file and the temp_history.log file.
+     * (Precondition: (sx != null) && (sx2 != null))
+     * @param sx the xml parser for the history xml file.
+     * @param sx2 the xml parser for the command xml file.
+     */
+    private void getHistPrev_log(SaveToXML sx,SaveToXML sx2)
+    {
+	Vector stack = null;
+	try
+	    {
+		File f = new File("history.log");
+		if (f.exists() == true)
+		    {
+			FileInputStream fis = new FileInputStream(f);
+			ObjectInputStream ois = new ObjectInputStream(fis);
+			
+			stack = (Vector) ois.readObject();
+			
+			String dirname;
+			dirname = "xmlfeedback/";
+
+			/*sx.open(dirname + "content" + FeedbackInterface.getCode() + ".xml",
+			  "HISTORY");*/
+			sx2.open(dirname + "command" + FeedbackInterface.getCode() + ".xml",
+				 "COMMANDS");
+			
+			if (stack != null)
+			    {
+				for (int i = 0 ; i < stack.size() ; i++)
+				    {
+					History log;
+					log = (History) stack.get(i);
+				        //log.sendXML(sx);
+					log.sendXMLComm(sx2);
+				    }
+				stack.removeAllElements();
+				System.gc();
+				stack = null;
+			    }
+			
+			stack = (Vector) ois.readObject();
+			
+			if (stack != null)
+			    {
+				for (int i = 0 ; i < stack.size() ; i++)
+				    {
+					History log;
+					log = (History) stack.get(i);
+				        //log.sendXML(sx);
+					log.sendXMLComm(sx2);
+				    }
+				stack.removeAllElements();
+				System.gc();
+				stack = null;
+			    }
+			
+			sx2.close("COMMANDS");
+			//sx.close("HISTORY");
+			
+			ois.close();
+		    }
+	    }
+	catch (IOException exp) {exp.printStackTrace();}
+	catch (ClassNotFoundException exp2)
+	    {
+		System.out.println("class exp");}
+    }
+
+    /**
+     * This method will get the Vector stored in temp_feedbackhist.log file.
+     * @return the vector stored in temp_feedbackhist.log file.
+     */
+    public Vector getPrev_log()
+    {
+	Vector stack = null;
+	try
+	    {
+		File f = new File("temp_feedbackhist.log");
+		if (f.exists() == true)
+		    {
+			FileInputStream fis = new FileInputStream(f);
+			ObjectInputStream ois = new ObjectInputStream(fis);
+			stack = (Vector) ois.readObject();
+			ois.close();
+			return stack;
+		    }
+		else
+		    stack = null;
+	    }
+	catch (IOException exp) {exp.printStackTrace();}
+	catch (ClassNotFoundException exp2)
+	    {
+		System.out.println("class exp");}
+	
+	return stack;
+    }
+
+    /**
+     * This is the thread that will start when user click send button and it will
+     * make 6 xml files,jarred them together into 1 jar file, deletes the 6 xml files and send it.
+     * @param vector the vector stored the current actions history.
+     * @param err_array the array that stored all the information took during feedback interface period.
+     * @param imgFile the array of that stored all the information from all the panels inside feedback interface form.
+     */
+    public void sendMethod (final Vector vector,final String err_array[], final String imgFile[])
+    {
+	ensureEventThread();
+	Runnable sendRun;
+	sendRun = new Runnable()
+	    {
+		public void run ()
+		{
+		    finish = false;
+		    selected = true;
+		    SaveToXML sx;
+		    sx = new SaveToXML(messages);
+		    sendState(sx,vector,err_array,imgFile);
+		    finish = true;
+		}
+	    };
+	sendThread = new Thread(sendRun);
+	sendThread.start();
+    }
+
+    /**
+     * This method will called the window that will display the preview of all
+     * the file going to be send.
+     * @param vector the vector stored the current actions history.
+     * @param err_array the array that stored all the information took during feedback interface period.
+     * @param imgFile the array of that stored all the information from all the panels inside feedback interface form.
+     */
+    public void viewMethod (final Vector vector,final String err_array[], final String imgFile[])
+    {
+	ensureEventThread();
+	Runnable prevRun;
+	prevRun = new Runnable()
+	    {
+		public void run ()
+		{
+		    finish = false;
+		    selected = false;
+		    ReportDetails rd;
+		    rd = new ReportDetails(vector,err_array,imgFile,messages,true);
+		    finish = true;
+		}
+	    };
+	
+	prevThread = new Thread(prevRun);
+	prevThread.start();
+    }
+
+    /**
+     * This method will save a BufferedImage to a jpeg file with the specified filename.
+     * This method is a thread that will caused the thread save to be started and stop
+     * if the saving process is finished.
+     * (Precondition: (I != null))
+     * @param I is the BufferedImage that we want to save.
+     * @param picScreen name of the jpeg file where we want to store the BufferedImage
+     */
+    public void saveGraph(final BufferedImage I,final String picScreen)
+    {
+	ensureEventThread();
+	Runnable saveRun;
+	saveRun = new Runnable ()
+	    {
+		public void run()
+		{
+		    try 
+			{
+			    File file;
+			    file = new File(picScreen);
+			    FileOutputStream out;
+			    out = new FileOutputStream(file);
+			    
+			    JPEGImageEncoder encoder;
+			    encoder = JPEGCodec.createJPEGEncoder(out);
+			    JPEGEncodeParam param;
+			    param = encoder.getDefaultJPEGEncodeParam(I);
+			    param.setQuality(1.0f, false);
+			    encoder.setJPEGEncodeParam(param);
+			    encoder.encode(I);
+			    out.close();
+			    save = null;
+			} 
+		    catch (Exception ex) {}
+		}
+	    };
+	
+	save = new Thread(saveRun);
+	save.start();
+    }
+
+    /**
+     * This method will get all the informations from the all the panels inside the feedback interface form.
+     * @return the arrays of information from all the panels.
+     */
+    public String[] getimgFile()
+    {
+	String[] imgFile;	
+	imgFile = null;
+
+	/*String answer;
+	  answer = (String) problem_screenshot.getSelectedItem();
+	  if(answer == messages.getString("Yes"))
+	  {*/
+	
+	if (paneArray.size() > 0)
+	    {
+		imgFile = new String[(paneArray.size() * 10)];
+		
+		int step;
+		for (step = 0 ; step < (paneArray.size()*10) ; step=step+10)
+		    {
+			JPanel pane;
+			ThumbnailPic obj;
+			pane = (JPanel) paneArray.get((step/10));
+			obj = (ThumbnailPic) picAndPane.get(pane);
+			
+			//obj.setSize();
+			
+			String title;
+			title = obj.getTitles();
+			
+			imgFile[step+0] = title;
+			imgFile[step+1] = obj.getScreenImage();
+			title = "Window" + pane.hashCode() + "File";
+			imgFile[step+2] = messages.getString("screen")+title+step+".jpg";
+			imgFile[step+3] = obj.getScreenAndLineImage();
+			imgFile[step+4] = messages.getString("ErrorLineAnd")+imgFile[step+2];
+			imgFile[step+5] = obj.getLineForScreenImage();
+			imgFile[step+6] = messages.getString("ErrorLineFor")+imgFile[step+2];
+			imgFile[step+7] = obj.getWidth();
+			imgFile[step+8] = obj.getHeight();
+			imgFile[step+9] = obj.getProblemDetails();
+		    }
+	    }
+		
+	return imgFile;
+    }
+
+    /**
+     * This method will get all the informations taken during feedback interface period, such as os version.
+     * @return then arrays of informations.
+     */
+    public String[] geterr_array()
+    {
+	String[] err_array;
+	err_array = null;
+
+	String os_name;
+	os_name = System.getProperty("os.name") + " " + System.getProperty("os.version") 
+	    + " " + System.getProperty("os.arch");
+	
+	Date problem_date;
+	String err_date,java_info,screen_res;
+	problem_date = new Date();
+	err_date = problem_date.toString();
+	java_info = System.getProperty("java.vendor")+ " " + System.getProperty("java.class.version");
+	Dimension dim;
+	dim = Toolkit.getDefaultToolkit().getScreenSize();
+	screen_res = "" + dim.width + "x" + dim.height;
+	
+	try
+	    {
+		err_array = new String[24];
+
+		err_array[0] = code;
+		err_array[1] = frameName;
+		err_array[2] = "";
+		err_array[3] = (String) problem_type.getSelectedItem();
+		err_array[4] = (String) problem_urgency.getSelectedItem();
+		err_array[5] = System.getProperty("user.name");
+		err_array[6] = System.getProperty("user.home");
+		err_array[7] = System.getProperty("user.dir");
+		err_array[8] = curr_date.toString();
+		err_array[9] = err_date;
+		err_array[10] = os_name;
+		err_array[11] = java_info;
+		err_array[12] = "" + Locale.getDefault();
+		err_array[13] = Utility.PROGRAM_NAME + " " + Utility.PROGRAM_VERSION; 
+		err_array[14] = InetAddress.getLocalHost().getHostName();
+		err_array[15] = InetAddress.getLocalHost().getHostAddress();
+		err_array[16] = screen_res;
+		err_array[17] = "";
+		
+		/*String test_txt;
+		  test_txt = smtp_address.getText();
+		  if ((test_txt == null)||(test_txt.length() < 5))*/
+		err_array[19] = "mail.waikato.ac.nz";
+		/*else
+		  err_array[19] = test_txt;
+		  
+		  test_txt = email_address.getText();
+		  if ((test_txt == null)||(test_txt.length() < 5))*/
+		err_array[20] = "vl6@cs.waikato.ac.nz";
+		//else
+		//err_array[20] = test_txt;
+		
+		Runtime run;
+		run = Runtime.getRuntime();
+		err_array[21] = formatFileSize(run.totalMemory());
+		err_array[22] = formatFileSize(run.maxMemory());
+		err_array[23] = formatFileSize(run.freeMemory());
+	    }
+	catch(UnknownHostException exp) {}
+
+	return err_array;
+    }
+
+    /**
+     * This method will format the file size given into more elegant form,e.g. 2KB
+     * @param length the file size.
+     * @return the more elegant string representations of the file size.
+     */
+    public String formatFileSize(long length) 
+    {
+	String BYTE_SUFFIX;
+	BYTE_SUFFIX = " B";
+	long GIGABYTE;
+	GIGABYTE = 1024000000l;
+	String GIGABYTE_SUFFIX;
+	GIGABYTE_SUFFIX = " GB";
+	long KILOBYTE;
+	KILOBYTE = 1024l;
+	String KILOBYTE_SUFFIX;
+	KILOBYTE_SUFFIX = " KB";
+	long MEGABYTE;
+	MEGABYTE = 1024000l;
+	String MEGABYTE_SUFFIX;
+	MEGABYTE_SUFFIX = " MB";
+
+	StringBuffer result;
+	result = new StringBuffer("");
+	float number;
+	number = 0f;
+	String suffix;
+	suffix = null;
+	
+	if(length >= GIGABYTE) 
+	    {
+		number = (float) length / (float) GIGABYTE;
+		suffix = GIGABYTE_SUFFIX;
+	    }
+	else if(length >= MEGABYTE) 
+	    {
+		number = (float) length / (float) MEGABYTE;
+		suffix = MEGABYTE_SUFFIX;
+	    }
+	else if(length >= KILOBYTE) 
+	    {
+		number = (float) length / (float) KILOBYTE;
+		suffix = KILOBYTE_SUFFIX;
+	    }
+	else 
+	    {
+		return length + BYTE_SUFFIX;
+	    }
+	
+	String number_str;
+	number_str = Float.toString(number);
+	char number_char[] = number_str.toCharArray();
+	int pos,i;
+	pos = 0;
+	
+	while(number_char != null && pos < number_char.length && number_char[pos] != '.')
+	    {
+		result.append(number_char[pos]);
+		pos++;
+	    }
+
+	if(pos < number_char.length) 
+	    {
+		result.append(number_char[pos]);
+		pos++;
+		
+		for(i = 0; i < 2 && pos < number_char.length; i++, pos++)
+		    result.append(number_char[pos]);
+	   
+		while(pos < number_char.length && number_char[pos] != 'E') 
+		    pos++;
+	   
+		while(pos < number_char.length) 
+		    {
+			result.append(number_char[pos]);
+			pos++;
+		    }
+	    }
+	
+	result.append(suffix);
+	
+	return result.toString();
+    }
+
+    /**
+     * This method will decide what action should be done if the user entered a button in
+     * the Feedback form.
+     * <br>If user click cancel button then all the information taken in this form will be deleted
+     * and user will be quitted from the Reporting Feedback sequence.
+     * <br>If user click the send button then all the information taken will be stored in array which
+     * then will be saved into xml files and sent when user confirm to send all the files.
+     * <br>If user click the details button then they can view all the xml files that are going to be send.
+     * @param e the button that user clicked
+     */
+    public void actionPerformed (ActionEvent e)
+    {
+	getPrevData();
+
+	if(messages.getString("Send").equals(e.getActionCommand()))
+	    {
+		String[] imgFile;
+		String[] err_array;
+
+		imgFile = getimgFile();
+		err_array = geterr_array();
+
+		timer.start();
+		
+		sendMethod(dialog.getVector(),err_array,imgFile);
+	    }
+
+	if(messages.getString("Preview").equals(e.getActionCommand()))
+	    {
+		String[] imgFile;
+		String[] err_array;
+
+		imgFile = getimgFile();
+		err_array = geterr_array();
+
+		timer.start();
+		
+		viewMethod(dialog.getVector(),err_array,imgFile); 
+	    }
+
+	if(messages.getString("NotSend").equals(e.getActionCommand()))
+	    {
+		dispose();
+	    }
+    }
+}
+	
+	
+
+	
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Graphs.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Graphs.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Graphs.java	(revision 10506)
@@ -0,0 +1,360 @@
+package org.greenstone.gatherer.feedback;
+
+import java.awt.image.*;
+import java.awt.geom.*;
+import java.awt.geom.Line2D.*;
+import java.awt.geom.Line2D.Double;
+import java.io.*;
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * This is the class that will allow user to draw a same line to 2 different BufferedImage
+ * at the same time.
+ * The first BufferedImage is BufferedImage with some Image as the based and then
+ * we draw a line on it, and the second BufferedImage is just a transparent Image and then we 
+ * draw a line on it. The line drawn in first BufferedImage is exactly the same with the line
+ * drawn in second BufferedImage.The Image drawn in the first bufferedimage is the
+ * screen shot image of the whole screen.
+ * @author Veronica Liesaputra
+ */
+public class Graphs
+{ 
+    /**
+     * This is the first buffered image.
+     * It will drawn with an image first to be its based, and a line  
+     * that are identical to line drawn the second BufferedImage, will be drawn on it.
+     */
+    private BufferedImage I = null;
+
+    /**
+     * This is the second buffered image.
+     * Its a transaparent buffered image and a line that are indetical to line
+     * drawn in the first BufferedImage, will be drawn on it. 
+     */
+    private BufferedImage I2;
+
+    /**
+     * This is the Graphics for the first BufferedImage.
+     * This will allow user to draw a line and an image on the first buffered image.
+     */
+    private Graphics2D G;
+    
+    /**
+     * This is the Graphics for the second BufferedImage.
+     * This will allow user to draw a line on the second buffered image.
+     */
+    private Graphics2D G2;
+
+    /**
+     * This is the arrays of the 3 BufferedImage.
+     */
+    private BufferedImage[] screen;
+
+    /**
+     * This is the graphics for screen[0] BufferedImage.
+     * This will allow user to draw something on the screen[0] image.
+     */
+    private Graphics2D G3;
+  
+    /**
+     * This is the width of the image.
+     */
+    private double imwidth;
+
+    /**
+     * This is the height of the image.
+     */
+    private double imheight;
+
+    /**
+     * This is the constructor that will initialised the BufferedImage and
+     * its Graphics.
+     * (Precondition: (sh != null))
+     * @param sh is the images.
+     */
+    public Graphs (BufferedImage[] sh)
+    {
+	screen = sh;
+
+	if (screen[0] != null)
+	    { 
+		imwidth = screen[0].getWidth();
+		imheight = screen[0].getHeight();
+
+
+		if((screen[1] == null)&& (screen[2] == null))
+		    {
+			I = new BufferedImage(screen[0].getWidth(),screen[0].getHeight(),
+					      BufferedImage.TYPE_INT_RGB);
+			I2 = new BufferedImage(I.getWidth(),I.getHeight(),
+					       BufferedImage.TYPE_INT_ARGB);
+		    }
+		else
+		    {
+			I = screen[1];
+			I2 = screen[2];
+		    }
+		start();
+	    }
+	else
+	    System.out.println("weird");
+    }
+
+    /**
+     * This method will make sure that everything is null-ed and dispose properly.
+     */
+    public void flush()
+    {
+	G.dispose();
+	G = null;
+	G3.dispose();
+	G3 = null;
+	G2.dispose();
+	G2 = null;
+
+	int i;
+	for ( i = 0 ; i < 3; i++)
+	    {
+		if (screen[i] != null)
+		    {
+			screen[i].flush();
+			screen[i] = null;
+		    }
+	    }
+
+	I.flush();
+	I = null;
+	I2.flush();
+	I2 = null;
+	System.gc();
+    }
+
+    /**
+     * This method will cleared the scribble lines in the images.
+     */
+    public void reset()
+    {
+	I.flush();
+	I = null;
+	System.gc();
+	I2.flush();
+	I2 = null;
+	G.dispose();
+	System.gc();
+	G2.dispose();
+	G = null;
+	G2 = null;
+	System.gc();
+
+	I = new BufferedImage(screen[0].getWidth(),
+			      screen[0].getHeight(),
+			      BufferedImage.TYPE_INT_RGB);
+	I2 = new BufferedImage(I.getWidth(),I.getHeight(),
+			       BufferedImage.TYPE_INT_ARGB);
+
+	screen[1] = null;
+	screen[2] = null;
+
+	start();
+    }
+    /**
+     * This method will setup the 3 Graphics for the 3 BufferedImage.
+     * Here the graphics for the bufferedimage will be created and the appropriate image
+     * will be drawn to the first bufferedimage.  
+     */
+    public void start ()
+    {
+	G3 = screen[0].createGraphics();
+	G3.drawImage((Image) screen[0],0,0,new JLabel());
+
+	G = I.createGraphics();
+	if (screen[1] == null)
+	    G.drawImage((Image) screen[0],0,0,new JLabel());
+	else
+	    G.drawImage ((Image) screen[1],0,0,new JLabel());
+	G2 = I2.createGraphics();
+    }
+ 
+    /**
+     * This method will draw a red line on both BufferedImage from the source point
+     * to the destination point.
+     * @param x1 is the x-coordinate of the source point.
+     * @param y1 is the y-coordinate of the source point.
+     * @param x2 is the x-coordinate of the destination point.
+     * @param y2 is the y-coordinate of the destination point. 
+     */
+    public void drawLines(int x1,int y1,int x2,int y2)
+    {
+	G2.setColor(Color.red);
+	G.setColor(Color.red);
+
+	G.setStroke(new BasicStroke(2.5f));
+	G2.setStroke(new BasicStroke(2.5f));
+
+	G2.drawLine(x1,y1,x2,y2);
+	G.drawLine(x1,y1,x2,y2);
+    }
+
+    
+    /**
+     * This method will draw a white line on all 3 BufferedImage from the source point
+     * to the destination point.
+     * @param x1 is the x-coordinate of the source point.
+     * @param y1 is the y-coordinate of the source point.
+     * @param x2 is the x-coordinate of the destination point.
+     * @param y2 is the y-coordinate of the destination point. 
+     */
+    public void eraseLines(int x1,int y1,int x2,int y2)
+    {
+	G3.setColor(Color.white);
+	G2.setColor(Color.white);
+	G.setColor(Color.white);
+
+	G.setStroke(new BasicStroke(25.5f));
+	G2.setStroke(new BasicStroke(25.5f));
+	G3.setStroke(new BasicStroke(25.5f));
+	
+	G3.drawLine(x1,y1,x2,y2);
+	G2.drawLine(x1,y1,x2,y2);
+	G.drawLine(x1,y1,x2,y2);
+    }
+
+    /**
+     * This method will get the first BufferedImage.
+     * This is the BufferedImage where it will already be drawn with the
+     * screen shot image and the lines.
+     * @return the first BufferedImage.
+     */
+    public BufferedImage getImage ()
+    {
+	return I;
+    }
+
+    /**
+     * This method will get the second BufferedImage.
+     * This is the BufferedImage where its base is transparent and it will
+     * already be drawn with the lines.
+     * @return the second BufferedImage.
+     */
+    public BufferedImage getImage2()
+    {
+	return I2;
+    }
+
+    /**
+     * This method will get the image without scribble lines only the white lines.
+     * @return the image without scribble lines.
+     */
+    public BufferedImage getScreenImage()
+    {
+	return screen[0];
+    }
+
+    /**
+     * This method will get the window out of the whole screen image.
+     * @param xcoord the xcoordinate of the window in the image.
+     * @param ycoord the ycoordinate of the window in the image.
+     * @param width  the width of the window in the image.
+     * @param height the height of the window in the image.
+     * @return the BufferedImage of the window only from the 3 buffered image.
+     */
+    public BufferedImage[] getWindowVersion(int xcoord,int ycoord,int width,int height)
+    {
+	BufferedImage[] window;
+	window = new BufferedImage[3];
+
+	Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
+	
+	if (xcoord < 0 ) 
+	    xcoord = 0;
+	if (ycoord < 0)
+	    ycoord = 0;
+
+	if (xcoord >= imwidth)
+	    xcoord = (int)(imwidth - 1);
+	if (ycoord >= imheight)
+	    ycoord = (int)(imheight - 1);
+	if ((xcoord + width) > imwidth)
+	    width = (int)(imwidth - xcoord);
+	if ((ycoord + height) > imheight)
+	    height = (int)(imheight - ycoord);
+
+	if (width <= 0)
+	    width = 1;
+	if (height <= 0)
+	    height = 1;
+
+	window[0] = getClipVersion(screen[0],xcoord,ycoord,width,height);
+	
+	window[1] = getClipVersion(I,xcoord,ycoord,width,height);
+	
+	window[2] = getClipVersion(I2,xcoord,ycoord,width,height);
+	
+	return window;
+    }
+    
+    /**
+     * This method will return the subimage of the big buffered image.
+     * @param tag the original buffered image.
+     * @param x   the x location of subimage.
+     * @param y   the y location of subimage.
+     * @param w   the width of the subimage.
+     * @param h   the height of the subimage.
+     * @return    the subimage.
+     */
+    public BufferedImage getClipVersion (BufferedImage tag,int x, int y, int w, int h) 
+    {
+	BufferedImage sub;
+	sub = tag.getSubimage(x,y,w,h);
+	
+	return sub;
+    }
+
+    /**
+     * This method will return the screen image version of the give buffered image.
+     * @param sh the buffered image that we going to draw in the screen image version.
+     * @param xcoord   the x location of subimage.
+     * @param ycoord   the y location of subimage.
+     * @param w   the width of the subimage.
+     * @param h   the height of the subimage.
+     */
+    public void setScreenVersion(BufferedImage[] sh,int xcoord,int ycoord,int w, int h)
+    {
+	if (xcoord < 0 ) 
+	    xcoord = 0;
+	if (ycoord < 0)
+	    ycoord = 0;
+
+	if (xcoord >= imwidth)
+	    xcoord = (int) (imwidth - 1);
+	if (ycoord >= imheight)
+	    ycoord = (int) (imheight - 1);
+	if ((xcoord + w) > imwidth)
+	    w = (int) (imwidth - xcoord);
+	if ((ycoord + h) > imheight)
+	    h = (int) (imheight - ycoord);
+
+	if (w <= 0)
+	    w = 1;
+	if (h <= 0)
+	    h = 1;
+       
+	G3.drawImage(sh[0], xcoord,ycoord,new JLabel());
+
+        
+        G.drawImage(sh[1], xcoord,ycoord,new JLabel());
+	
+	
+	G2.drawImage(sh[2], xcoord,ycoord,new JLabel());
+    }
+}
+    
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/History.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/History.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/History.java	(revision 10506)
@@ -0,0 +1,284 @@
+package org.greenstone.gatherer.feedback;
+
+import java.util.*;
+import java.awt.image.*;
+import java.io.*;
+import javax.imageio.*;
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * This class is one record of the action user did to any of the component
+ * inside the window that the application open that is recorded by the 
+ * special listener class.
+ * An instance of this class will hold all the information about the action
+ * user did at that moment,all information about all the components inside the
+ * window where the action occured and all information about all the components
+ * inside all the windows that were opened when the action occured.
+ * @author Veronica Liesaputra
+ */
+public class History implements Serializable
+{
+    /**
+     * This is the date of when the action is done by the user.
+     */
+    private String date;
+    
+    /**
+     * This is the command that user did.
+     */
+    private String command;
+    
+    /**
+     * This is the title of the window where the action occured.
+     */
+    private String title;
+
+    /**
+     * This hold all information about all the components inside the
+     * window where the action occured and all information about all the components
+     * inside all the windows that were open when the action occured.
+     */
+    private ArrayList component;
+
+    /**
+     * This hold the image of the window where the action occured.
+     */
+    private String image = null;
+
+    /**
+     * This is the image file name, if then user decide to save the image to a jpeg file.
+     */
+    private String imageName = "";
+
+    /**
+     * This is the height of image of the window where the action occured. 
+     */
+    private String height;
+
+    /**
+     * This is the width of image of the window where the action occured.
+     */
+    private String width;
+
+    /**
+     * This constructor will be initializing the date,command and component value.
+     * (Precondition: (curr_date != null))
+     * @param curr_date is the date when the action occured.
+     * @param curr_command is the command the user did.
+     */
+    public History (Date curr_date,String curr_command)
+    {
+	date = curr_date.toString();
+	command = curr_command;
+	component = new ArrayList();
+    }
+
+    /**
+     * This method will be setting up the image attributes to the passed values.
+     * It will setting the image of the window where the action occured and its height 
+     * and width.It will also generate the supposed file name for this image.
+     * (Precondition: (imag != null) && (h != null) && (w != null))
+     * @param img the image of the window where the action occured.
+     * @param h   image's height.
+     * @param w   image's width.
+     */
+    public void setImage(String img,String h,String w)
+    {
+	image = img;
+	height = h;
+	width = w;
+	StringTokenizer st;
+	st = new StringTokenizer(date,": ");
+	while (st.hasMoreTokens()) 
+	    {
+		imageName += st.nextToken();
+	    }
+	imageName += ".jpg";
+    }
+
+    /**
+     * This method will add a new CompGroup instance that hold information and
+     * the status of a window that were open when the action occured.
+     * @param comp UserComponent instance that hold information about all
+     *             components inside the window.
+     * @param curr_status The current status of the window.
+     */
+    public void addComponent (UserComponent comp,String curr_status)
+    {
+	component.add(new CompGroup(comp,curr_status));
+    }
+
+    /**
+     * This method will get the image's height of the window where the action
+     * occured.
+     * @return image's height.
+     */
+    public String getHeight ()
+    {
+	return height;
+    }
+
+    /**
+     * This method will get the image's width of the window where the action
+     * occured.
+     * @return image's width.
+     */
+    public String getWidth ()
+    {
+	return width;
+    }
+
+    /**
+     * This method will set the title of the window where the action occured.
+     * @param name window's title.
+     */
+    public void setTitle (String name)
+    {
+	title = name;
+    }
+
+    /**
+     * This method will get the title of the window where the action occured.
+     * @return the window's title.
+     */
+    public String getTitle ()
+    {
+	return title;
+    }
+
+    /**
+     * This method will get the date when the action occured.
+     * @return the date when the action occured.
+     */
+    public String getDate()
+    {
+	return date;
+    }
+
+    /**
+     * This method will get the command that user did.
+     * @return the command user did.
+     */
+    public String getCommand()
+    {
+	return command;
+    }
+
+    /**
+     * This method will get the array of CompGroup instances that hold
+     * all the information and status of all the window that were open when 
+     * the action occured.
+     * @return the array list of the CompGroup instances.
+     */
+    public ArrayList getArray()
+    {
+	return component;
+    }
+
+    /**
+     * This method will get the image of the window where the action occured.
+     * @return image the window's image.
+     */
+    public String getImage()
+    {
+	return image;
+    }
+    
+    /**
+     * This method will get the supposed image's file name.
+     * @return image's file name.
+     */
+    public String getImageName()
+    {
+	return imageName;
+    }
+ 
+    /**
+     * This method will stored this instance to an xml file.
+     * It will only store the date,title,command,image and all
+     * image attributes of this instance to the xml file.
+     * @param sx is the xml file where we want to store.
+     */
+    public void sendXMLComm (SaveToXML sx)
+    {
+	sx.startContent(10);
+	
+	sx.startContent(7);
+	sx.saveContent(date);
+	sx.closeContent(7);
+	
+	sx.startContent(2);
+	sx.saveContent(title);
+	sx.closeContent(2);
+	
+	sx.startContent(8);
+	sx.saveContent(command);
+	sx.closeContent(8);
+
+	if (image != null)
+	    {
+		sx.startContent(6);
+		sx.saveImage(image,imageName,width,height);
+		sx.closeContent(6);
+	    }
+	
+	sx.closeContent(10);
+    }
+
+    /**
+     * This method will stored this instance to an xml file.
+     * It will store all the data members of this instance to
+     * the xml file.
+     * @param sx is the xml file where we want to store.
+     */
+    public void sendXML (SaveToXML sx)
+    {
+	sx.startContent(10);
+
+	sx.startContent(7);
+	sx.saveContent(date);
+	sx.closeContent(7);
+
+	sx.startContent(2);
+	sx.saveContent(title);
+	sx.closeContent(2);
+
+	sx.startContent(8);
+	sx.saveContent(command);
+	sx.closeContent(8);
+
+	if (image != null)
+	    {
+		sx.startContent(6);
+		sx.saveImage(image,imageName,width,height);
+		sx.closeContent(6);
+	    }
+	
+	int j;
+	for (j = 0 ; j < component.size() ; j++)
+	    {
+		sx.startContent(9);
+		CompGroup comp;
+		comp = (CompGroup) component.get(j);
+		
+		sx.startContent(8);
+		sx.saveContent(comp.getStatus());
+		sx.closeContent(8);
+
+		sx.startContent(0);
+		comp.getComponent().sendingXML(sx);
+		sx.closeContent(0);
+		
+		sx.closeContent(9);
+	    }
+	sx.closeContent(10);
+    }
+}
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Movie.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Movie.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Movie.java	(revision 10506)
@@ -0,0 +1,376 @@
+package org.greenstone.gatherer.feedback;
+
+import java.awt.image.*;
+import com.sun.image.codec.jpeg.*;
+import javax.swing.*;
+import java.awt.event.*;
+import java.awt.*;
+import javax.swing.event.*;
+import java.io.*;
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+import javax.swing.text.NumberFormatter;
+import java.text.NumberFormat;
+import java.beans.*;
+import java.util.ArrayList;
+
+/**
+ * This is the class to generate a animation type from a list of ImageIcon.
+ * It will display a JDialog window and then user can specify the frames
+ * per second rate that the user want to use to view the list of the ImageIcon.
+ * @author Veronica Liesaputra
+ */
+public class Movie extends JDialog
+    implements ActionListener,ChangeListener,PropertyChangeListener
+{
+    /**
+     * This variable will hold the resource of the words that is stored in Messages.properties file.
+     * The calling using messages.getString(someString) will caused someString to be translated
+     * into some other string that is hold in that file.usually it will caused it to be translated
+     * to the language that the user use or choose to have as stated in Locale.
+     */
+    private static ResourceBundle messages;
+
+    /**
+     * This is the label that we use to display the ImageIcon.
+     */
+    private JLabel picture;
+
+    /**
+     * This is a textField where user can set how many frames per second they want to view the
+     * ImageIcon.If user enter value that is bigger than the FPS_MAX then it will beep and user
+     * will need to enter new valid value or it will stay as the previous valid value.
+     * If user enter 0 then it will stop the animation.
+     */
+    private JFormattedTextField textField;
+
+    /**
+     * This is a slider where user can set how many frames per second they want to view the
+     * ImageIcon.If user slide to 0 then animation stop.
+     */
+    private JSlider framesPerSecond;
+    
+    /**
+     * This is the minimum frame per second value.
+     */
+    private int FPS_MIN = 0;
+
+    /**
+     * This is the maximum frame per second value. The value is the twice the amount of 
+     * ImageIcon in the list.
+     */
+    private int FPS_MAX;
+
+    /**
+     * This is the initial frame per second value to view the ImageIcon.
+     */
+    private int FPS_INIT = 1;
+
+    /**
+     * This is the ImageIcon index that are currently showing in the label.
+     */
+    private int frameNumber;
+
+    /**
+     * This is the total number of ImageIcon in the list.
+     */
+    private int NUM_FRAMES;
+
+    /**
+     * This hold the list of the ImageIcon that are to be displayed.
+     */
+    private ArrayList images;
+
+    /**
+     * This is telling how long is the delay for each frame to be refreshed.
+     */
+    private int delay;
+
+    /**
+     * This is the timer that generate the animation of the list of ImageIcon.
+     * The animation will be paused twice per cycle by restarting the timer.
+     * If the the prame per second chosen by the user is 0 then the timer
+     * will be stop.
+     */
+    private Timer timer;
+
+    /**
+     * This the flag to say when the animation should stop.
+     * If frozen = true then the animation should stop otherwise the animation
+     * should keep running.
+     */
+    private boolean frozen = false;
+
+    /**
+     * This will sho a modal-dialog and set up the value for the animation to run properly 
+     * according to the list of ImageIcon passed in.
+     * @param msg  hold the resource of the words that is stored in Messages.properties file.
+     * @param img  hold the list of ImageIcon to be displayed.
+     */
+    public Movie (ResourceBundle msg,ArrayList img)
+    {
+	super();
+
+	images = img;
+	NUM_FRAMES = img.size(); 
+	FPS_MAX = img.size() * 2;
+
+	messages = msg; 
+	setTitle(messages.getString("GenerateMovie"));
+	setModal(true);
+	setBackground(new Color (176,208,176));
+    }
+
+    /**
+     * This method will seeting up the content pane of the dialog window.
+     * It also setting up the timer and the delay.
+     * @return the content pane of the window.
+     */
+    public JPanel create_UI()
+    {
+	JPanel cont;
+	cont = new JPanel();
+	cont.setOpaque(true);
+	cont.setBackground(new Color (176,208,176));
+
+	JButton cls;
+	cls = new JButton(messages.getString("Close"));
+	cls.addActionListener(new ActionListener ()
+	    {
+		public void actionPerformed (ActionEvent e)
+		{
+		    dispose();
+		    if (timer != null)
+			timer.stop();
+		}
+	    });
+	cls.setDefaultCapable(true);
+	cls.setActionCommand(messages.getString("Close"));
+	cls.setBackground(new Color(176,208,176));
+
+
+	if (images.size() <= 0)
+	    {
+		JLabel empty_lbl;
+		empty_lbl = new JLabel ("No Image to be displayed   ");
+		cont.add(empty_lbl);
+		cont.add(cls);
+		return cont;
+	    }
+
+	cont.setLayout(new BoxLayout(cont, BoxLayout.PAGE_AXIS));
+
+	delay = 1000 / FPS_INIT;
+
+	JLabel sliderLabel;
+	sliderLabel = new JLabel(messages.getString("FramesPerSecond") + ": ", JLabel.CENTER);
+	sliderLabel.setBackground(new Color(176,208,176));
+        sliderLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
+
+        NumberFormat numberFormat;
+	numberFormat = NumberFormat.getIntegerInstance();
+        NumberFormatter formatter;
+	formatter = new NumberFormatter(numberFormat);
+        formatter.setMinimum(new Integer(FPS_MIN));
+        formatter.setMaximum(new Integer(FPS_MAX));
+
+        textField = new JFormattedTextField(formatter);
+	textField.setBackground(new Color(224,240,224));
+        textField.setValue(new Integer(FPS_INIT));
+        textField.setColumns(5);
+        textField.addPropertyChangeListener(this);
+
+        textField.getInputMap().put(KeyStroke.getKeyStroke(
+                                        KeyEvent.VK_ENTER, 0),
+                                        "check");
+        textField.getActionMap().put("check", new AbstractAction() 
+	    {
+		public void actionPerformed(ActionEvent e) 
+		{
+		    if (!textField.isEditValid()) 
+			{ 
+			    Toolkit.getDefaultToolkit().beep();
+			    textField.selectAll();
+			} 
+		    else
+			{ 
+			    try 
+				{                  
+				    textField.commitEdit();
+				} 
+			    catch (java.text.ParseException exc) { }
+			}
+		}
+	    });
+
+        framesPerSecond = new JSlider(JSlider.HORIZONTAL,
+                                      FPS_MIN, FPS_MAX, FPS_INIT);
+        framesPerSecond.addChangeListener(this);
+	framesPerSecond.setBackground(new Color(176,208,176));
+	framesPerSecond.setMajorTickSpacing(10);
+        framesPerSecond.setMinorTickSpacing(1);
+        framesPerSecond.setPaintTicks(true);
+        framesPerSecond.setPaintLabels(true);
+        framesPerSecond.setBorder(BorderFactory.createEmptyBorder(0,0,10,0));
+	
+        picture = new JLabel();
+	Dimension dim;
+	int iw,ih;
+	dim = Toolkit.getDefaultToolkit().getScreenSize();
+	iw = (int) (dim.width - 30);
+	ih = (int) (dim.height * 0.75);
+	picture.setPreferredSize(new Dimension(iw,ih));
+        picture.setHorizontalAlignment(JLabel.CENTER);
+        picture.setAlignmentX(Component.CENTER_ALIGNMENT);
+        picture.setBorder(BorderFactory.createCompoundBorder(
+                BorderFactory.createLoweredBevelBorder(),
+                BorderFactory.createEmptyBorder(10,10,10,10)));
+	picture.setBackground(new Color(176,208,176));
+        updatePicture(0);
+
+	
+        JPanel labelAndTextField;
+	labelAndTextField = new JPanel();
+        labelAndTextField.add(sliderLabel);
+        labelAndTextField.add(textField);
+	labelAndTextField.add(cls);
+	labelAndTextField.setBackground(new Color(176,208,176));
+
+	cont.add(picture);
+	cont.add(framesPerSecond);
+        cont.add(labelAndTextField);
+       
+        cont.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
+
+        timer = new Timer(delay, this);
+        timer.setInitialDelay(delay * 7); 
+        timer.setCoalesce(true);
+	timer.start();
+	
+	return cont;
+    }
+
+    /**
+     * This method will tell what should happen when the slider's arrow
+     * change its position.
+     * <br>If user adjusting the frame per second value using the slider
+     * then it will set the Textfield to have the value that slider point 
+     * to at the moment.If the value is 0 then it will stop the animation
+     * otherwise it will keep animate with the new frame per second value.
+     * @param e is the slider when the slider's arrow change its position.
+     */
+    public void stateChanged(ChangeEvent e) 
+    {
+        JSlider source;
+	source = (JSlider)e.getSource();
+        int fps;
+	fps = (int)source.getValue();
+        if (!source.getValueIsAdjusting()) 
+	    { 
+		textField.setValue(new Integer(fps));
+		if (fps == 0) 
+		    {
+			if (!frozen) 
+			    stopAnimation();
+		    } 
+		else 
+		    {
+			delay = 1000 / fps;
+			timer.setDelay(delay);
+			timer.setInitialDelay(delay * 10);
+			if (frozen) 
+			    startAnimation();
+		    }
+	    } 
+	else 
+	    { 
+		textField.setText(String.valueOf(fps));
+	    }
+    }
+   
+    /**
+     * This method will set the slider value when the user adjusting
+     * the frame per second value using the textfield.
+     * <br>If user adjusting the frame per second value using text field, the
+     * slider's arrow position will be changed into that value.
+     * @param e the text field
+     */
+    public void propertyChange(PropertyChangeEvent e) 
+    {
+        if ("value".equals(e.getPropertyName())) 
+	    {
+		Number value;
+		value = (Number)e.getNewValue();
+		if (framesPerSecond != null && value != null) 
+		    {
+			framesPerSecond.setValue(value.intValue());
+		    }
+	    }
+    }
+
+    /**
+     * This method will start the timer.
+     */
+    public void startAnimation() 
+    {
+        timer.start();
+        frozen = false;
+    }
+
+    /**
+     * This method will stop the timer.
+     */
+    public void stopAnimation() 
+    {
+        timer.stop();
+        frozen = true;
+    }
+
+    /**
+     * This method will tell what should happen when the timer is start.
+     * When the timer start it will increase the framenumber and will
+     * update the label with the new image icon.
+     * If the timer already display all the image icon in the list, it 
+     * will restart the timer and reanimate the image icon again.
+     * @param e fires when the timer start.
+     */
+    public void actionPerformed(ActionEvent e) 
+    {
+        if (frameNumber == (NUM_FRAMES - 1))
+            frameNumber = 0;
+        else 
+            frameNumber++;
+        
+        updatePicture(frameNumber);
+
+        if ((frameNumber == (NUM_FRAMES - 1)) ||
+	    (frameNumber==(NUM_FRAMES/2 - 1)))
+            timer.restart();
+    }
+
+    /**
+     * This will update the label with the new ImageIcon.
+     * If the ImageIcon is null then the label will display an error message
+     * instead of the picture.
+     * @param frameNum this is the index of the ImageIcon to be displayed. 
+     */
+    protected void updatePicture(int frameNum) 
+    {
+        if (images.get(frameNumber) != null) 
+	    {
+		picture.setIcon((ImageIcon) images.get(frameNumber));
+	    } 
+	else 
+	    {
+		picture.setText(messages.getString("image")+" #"
+				+ frameNumber + " " +
+				messages.getString("notfound"));
+	    }
+    }
+}
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/MyTextArea.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/MyTextArea.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/MyTextArea.java	(revision 10506)
@@ -0,0 +1,85 @@
+/** This class is not currently used and therefore will not be compiled by makegli. */
+
+package org.greenstone.gatherer.feedback;
+
+import javax.swing.*;
+import javax.swing.text.*;
+import java.util.Date;
+import java.awt.Color;
+
+/**
+ * This class will allow us to changed what should be inputted to the 
+ * text area as the user inputted the text to the text area.
+ * @author Veronica Liesaputra
+ */
+public class MyTextArea extends JTextArea 
+{
+    /**
+     * Creating an empty JTextArea.
+     */
+    public MyTextArea ()
+    {
+	super();
+    }
+
+    /**
+     * Creating a JTextArea already appended with cols.
+     * (Precondition: (cols != null))
+     * @param cols the text to be appended.
+     */
+    public MyTextArea(String cols) 
+    {
+	super(cols);
+    }
+ 
+    /**
+     * It will give the default model this text area should use.
+     * @return the default model this text area used.
+     */
+    protected Document createDefaultModel() 
+    {
+	return new UpperCaseDocument();
+    }
+ 
+    /**
+     * This class will be used as the default model of MyTextArea.
+     * Here we can control and modified the string that is going to be inserted to 
+     * the document.
+     */
+    static class UpperCaseDocument extends PlainDocument 
+    {
+	/**
+	 * This method will caused the document to be appended with the date followed by newline
+	 * everytime user trying to insert a new line to the document.
+	 * (Precondition : (offs >= 0) && (str != null))
+	 * @param offs is the offset placted to insert the string.
+	 * @param str is the string to be inserted.
+	 * @param a is the attribute set to be used.
+	 */
+	public void insertString(int offs, String str, AttributeSet a) 
+	    throws BadLocationException 
+	{
+	    if (str == null) 
+		{
+		    return;
+		}
+	    
+	    char[] upper;
+	    upper = str.toCharArray();
+
+	    if (str.endsWith("\n") == true)
+		{
+		    String str2;
+		    str2 = str + ((new Date()).toString()) + "\n\n>";
+		    upper = str2.toCharArray();
+		}
+	   
+	    super.insertString(offs, new String(upper), a);
+	}
+    }
+}
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ReportDetails.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ReportDetails.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ReportDetails.java	(revision 10506)
@@ -0,0 +1,1304 @@
+package org.greenstone.gatherer.feedback;
+
+import java.io.*;
+import java.awt.image.*;
+import javax.swing.*;
+import java.awt.*;
+import java.util.*;
+import javax.swing.event.MouseInputAdapter;
+import java.awt.event.*;
+import javax.swing.border.*;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+import javax.swing.tree.*;
+
+/**
+ * This class can give preview of all the history of actions user did or give preview of all the
+ * xml files that are ready to be send and it also can give preview of all the screen shot of
+ * all window taken when user did the actions.
+ * If user select Details button then they will view all xml files that are going to be send.
+ * If user select View History then they will see the history record that we took so far.
+ * @author Veronica Liesaputra
+ */
+public class ReportDetails extends WindowAdapter 
+{
+    /**
+     * This is the tree that will be used to hold the feedback form,the history stored inside the vector 
+     * at the moment, and hold the comment user did when they recreating the event.
+     * This tree's data partly will be supplied from whats inside vector. 
+     */
+    private JTree tree;
+    /**
+     * This is the root node for tree.
+     */
+    private DefaultMutableTreeNode rootNode;
+    /**
+     * This hold the parent node of the current node that is currently just being added to tree.
+     */
+    private DefaultMutableTreeNode parentNode;
+    /**
+     * This hold the current node that is currently just being added to tree.
+     */
+    private DefaultMutableTreeNode currNode;
+    /**
+     * This is the tree model for tree.
+     */
+    private DefaultTreeModel treeModel;
+
+    /**
+     * This is the tree that will be used to hold the commands (actions) done by the user inside the vector
+     * at the moment.This tree builds from partial data of tree and which data entered to this tree
+     * is signed by the value of comm_bool and comm_start. 
+     */
+    private JTree tree2;
+    /**
+     * This is the root node for tree2.
+     */
+    private DefaultMutableTreeNode rootNode2;
+    /**
+     * This is the parent node of the current node that is currently just being added to tree2.
+     */
+    private DefaultMutableTreeNode parentNode2;
+    /**
+     * This is the current node that is currently just being added to tree2.
+     */
+    private DefaultMutableTreeNode currNode2;
+    /**
+     * This is the tree model for tree2.
+     */
+    private DefaultTreeModel treeModel2;
+
+    /**
+     * This is the tree that will be used to hold the history of all the actions
+     * done by the user before they choose to do the Reporting Feedback sequence.
+     */
+    private JTree tree3;
+    /**
+     * This is the root node for tree3.
+     */
+    private DefaultMutableTreeNode rootNode3;
+    /**
+     * This is the parent node for the current node that is currently just being added to tree3.
+     */
+    private DefaultMutableTreeNode parentNode3;
+    /**
+     * This is the current node that is currently just being added to tree3.
+     */
+    private DefaultMutableTreeNode currNode3;
+    /**
+     * This is the tree model for tree3.
+     */
+    private DefaultTreeModel treeModel3;
+
+    /**
+     * This is the tree that will be used to hold the commands (actions) done by the user 
+     * before they choose to do the Reporting Feedback sequence.This tree builds from partial data of tree3 
+     * and which data entered to this tree2 is signed by the value of comm_bool and comm_start. 
+     */
+    private JTree tree4;
+    /**
+     * This is the root node for tree4.
+     */
+    private DefaultMutableTreeNode rootNode4;
+    /**
+     * This is the parent node for the current node that is currently just being added to tree4.
+     */
+    private DefaultMutableTreeNode parentNode4;
+    /**
+     * This is the current node that is currently just being added to tree4.
+     */
+    private DefaultMutableTreeNode currNode4;
+    /**
+     * This is the tree model for tree4.
+     */
+    private DefaultTreeModel treeModel4;
+
+    /**
+     * This is the panel to display tree4.
+     */
+    private JPanel pane4;
+    /**
+     * This is the scroll pane for displaying tree3, so it is scrollable.
+     */
+    private JScrollPane scroll3;
+    /**
+     * This is the scroll pane for displaying tree4, so it is scrollable.
+     */
+    private JScrollPane scroll4;
+
+    /**
+     * This is the panel to display tree2.
+     */
+    private JPanel pane2;
+    /**
+     * This is the scroll pane for displaying tree2, so it is scrollable.
+     */
+    private JScrollPane scroll2;
+    /**
+     * This is the scroll pane for displaying tree, so it is scrollable.
+     */
+    private JScrollPane scroll;
+   
+    /**
+     * This is all the information taken from the Feedback form and information that
+     * was taken from the system.
+     */
+    private String[] err_details;
+    
+    /**
+     * This is the vector that hold all information about the history of all
+     * the actions user did.
+     * If rec = true, it means it hold the history of all the actions and information
+     * of all the windows were open when user did the actions during reporting feedback
+     * sequence.
+     * If rec = false, it means it hold the history of all the actions and information
+     * of all the windows were open when user did the actions before and after
+     * reporting feedback sequence.
+     */
+    private Vector vector;
+    
+    /**
+     * This is a variable to know which tag xml data that wants to be added to the JTree. 
+     */
+    private int count;
+    
+    /**
+     * This is a flag variable to sign whether or not the next data is to be added to
+     * the command JTree. 
+     */
+    private boolean comm_bool = false;
+    /**
+     * This is a flag variable to sign whether or not the next history is to be added to
+     * the command JTree.
+     */
+    private boolean comm_start = false;
+    /**
+     * This is a flag variable to sign whether or not at the moment we building a new tree
+     * or build from the existing tree.
+     */
+    private boolean new_tree = false;
+    
+    /**
+     * This is a flag variable to sign which type of preview that user wants at the moment.
+     * If its true, then its means user will view all the 6 xml files that will be send.
+     * If its false, then its means user only wants to view the history and command user just did
+     * before and after the reporting feedback sequence.
+     */
+    private boolean rec = false;
+   
+    /**
+     * This is array list of all the image icons that are inside all the command JTree.
+     */
+    private ArrayList movie;
+
+    /**
+     * This variable will hold the resource of the words that is stored in Messages.properties file.
+     * The calling using messages.getString(someString) will caused someString to be translated
+     * into some other string that is hold in that file.usually it will caused it to be translated
+     * to the language that the user use or choose to have as stated in Locale.
+     */
+    private static ResourceBundle messages;
+
+    private String[] img;
+   
+    /**
+     * This constructor will be seeting up the data member to its appropriate value.
+     * (Precondition : (msg != null) && (bool != null))
+     * @param stack this is all vector to be supplied to tree.
+     * @param err_array holding all the information taken when user doing the FeedbackInterface form.
+     * @param imgFile holding all the information inside all the panels in the FeedbackInterface form.
+     * @param msg hold the resource of the words that is stored in Messages.properties file.
+     * @param bool hold the falg value of rec.
+     */
+    public ReportDetails(Vector stack,String[] err_array,String[] imgFile,ResourceBundle msg,boolean bool)
+    {
+	img = imgFile;
+	vector = stack;
+	err_details = err_array;
+	messages = msg;
+	rec = bool;
+	movie = new ArrayList();
+	makeNewWindow();
+    }
+
+    /**
+     * This method will make a modal-dialog window that will display all the preview.
+     */
+    public void makeNewWindow()
+    {
+	JDialog frame;
+	frame = new View (this);
+	frame.setModal(true);
+	frame.setVisible(true);
+    }
+
+    /**
+     * This class is the dialog window that will give the preview.
+     */
+    class View extends JDialog implements ActionListener
+    {
+	/**
+	 * This variable is holding the current window that display the preview.
+	 */
+	private JDialog frame;
+	/**
+	 * This variable holding the owner of this window.
+	 */
+	private ReportDetails framework = null;
+
+	/**
+	 * This constructor will make the dialog window for previewing and setting up the
+	 * content pane of this window.
+	 * @param controller is the owner of this window.
+	 */
+	public View (ReportDetails controller)
+	{
+	    super();
+	    framework = controller;
+	    frame = this;
+
+	    setTitle(messages.getString("ViewReport"));  
+	    setBackground(new Color(176,208,176));
+	    setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+	    setDefaultLookAndFeelDecorated(true);
+	 
+	    JPanel cont;
+	    cont = new JPanel();
+	    cont.setLayout(new BoxLayout(cont,BoxLayout.PAGE_AXIS));
+	    cont.setBackground(new Color(176,208,176));
+	
+	    JTabbedPane tab;
+	    tab = new JTabbedPane();
+	    tab.setBackground(new Color(176,208,176));
+
+	    new_tree = false;
+
+	    if (err_details != null)
+		{
+		    tab.addTab(messages.getString("ViewFeedbackForm"), 
+			       createFeedback_UI(err_details,img));
+		}
+	    
+	    if (rec == true)
+		{
+		    tab.addTab(messages.getString("ViewFeedbackHistoryState"),
+			       createFeedbackHistory_UI(vector));
+		    tab.addTab(messages.getString("ViewFeedbackCommandState"),pane2);
+		    /*tab.addTab(messages.getString("ViewHistoryState"),
+		      createHistory_UI());*/
+		    createHistory_UI();
+		    tab.addTab(messages.getString("ViewCommandState"),pane4);
+		}
+	    else
+		{
+		    /*tab.addTab(messages.getString("ViewHistoryState"),
+		      createFeedbackHistory_UI(vector));*/
+		    createFeedbackHistory_UI(vector);
+		    tab.addTab(messages.getString("ViewCommandState"),pane2);
+		}
+
+	    cont.add(tab);
+
+	    JLabel lbl;
+	    lbl = new JLabel("   ");
+	    lbl.setBackground(new Color(176,208,176));
+
+	    cont.add(lbl);
+
+	    JPanel pane3;
+	    pane3 = new JPanel();
+	    pane3.setBackground(new Color(176,208,176));
+	    JButton button;
+	    button = new JButton(messages.getString("Close"));
+	    button.setActionCommand(messages.getString("Close"));
+	    button.addActionListener(this);
+	    button.setDefaultCapable(true);
+	    button.setToolTipText(messages.getString("ClosePreview"));
+	    button.setBackground(new Color(176,208,176));
+	   
+	    /*JButton button2;
+	    button2 = new JButton(messages.getString("ViewMovie"));
+	    button2.setActionCommand(messages.getString("ViewMovie"));
+	    button2.addActionListener(new ActionListener()
+		{
+		    public void actionPerformed (ActionEvent e)
+		    {
+			JDialog.setDefaultLookAndFeelDecorated(true);
+			JDialog frame;
+			frame = new Movie(messages,movie);
+
+			frame.setContentPane(((Movie)frame).create_UI());
+			frame.pack();
+			frame.setVisible(true);
+		    }
+		});
+	    button2.setToolTipText(messages.getString("ViewMovieText"));
+	    button2.setBackground(new Color(176,208,176));
+	    pane3.add(button2);*/
+	    pane3.add(button);
+	    pane3.setBorder(new EmptyBorder(new Insets(0,10,10,10)));
+
+	    cont.add(pane3);
+
+	    cont.setBorder(new EmptyBorder(new Insets(5,5,5,5)));
+	    getContentPane().add(cont);
+
+	    tab.setAlignmentX(Component.LEFT_ALIGNMENT);
+	    lbl.setAlignmentX(Component.LEFT_ALIGNMENT);
+	    pane3.setAlignmentX(Component.LEFT_ALIGNMENT);
+	    
+	    addWindowListener(framework);
+	    Toolkit kit;
+	    kit = Toolkit.getDefaultToolkit();
+	    Dimension screenSize;
+	    screenSize = kit.getScreenSize();
+	    int screenHeight;
+	    screenHeight = screenSize.height;
+	    int screenWidth;
+	    screenWidth = screenSize.width;
+	    Dimension size;
+	    size = this.getSize();
+	    setLocation((screenWidth -size.width)/ 4, 
+			(screenHeight - size.height)/ 4);
+
+	    pack();
+	    setResizable(false);
+	}
+	
+	/**
+	 * This method will get the vector that is stored inside temp_feedbackhist.log
+	 * if rec is true, and will get the vector that is stored inside temp_history.log
+	 * if rec is false. If file is not exist then it will return null. 
+	 * @return vector that is stored in the file.
+	 */
+	public Vector getPrev_log()
+	{
+	    Vector stack = null;
+	    try
+		{
+		    File f;
+		    if (rec == true)
+			{
+			    f = new File("temp_feedbackhist.log");
+			}
+		    else
+			{
+			    f = new File("temp_history.log");
+			}
+
+		    if (f.exists() == true)
+		    {
+			FileInputStream fis = new FileInputStream(f);
+			ObjectInputStream ois = new ObjectInputStream(fis);
+			stack = (Vector) ois.readObject();
+			ois.close();
+			return stack;
+		    }
+		    else
+			stack = null; 
+		}
+	    catch (IOException exp) {exp.printStackTrace();}
+	    catch (ClassNotFoundException exp2) 
+		{
+		    System.out.println("class exp");}
+	    
+	    return stack;
+	}
+
+	/**
+	 * This method will update the graphics of this window and it will
+	 * set variable finish in Conformation to true.
+	 * @param g is the graphics for this window.
+	 */
+	public void paint (Graphics g)
+	{
+	    super.paint(g); 
+	    FeedbackInterface.setFinish(true);
+	}
+
+	/**
+	 * This method will close the preview window if user select close button.
+	 * @param e action event user did.
+	 */
+	public void actionPerformed (ActionEvent e)
+	{   
+	    if(messages.getString("Close").equals(e.getActionCommand()))
+		{ 
+		    dispose();
+		}
+	}
+
+	/**
+	 * This method will add a record to history tree and the command tree.
+	 * @param log is the record to be added.
+	 */
+	public void getHist(History log)
+	{
+	    comm_bool = true;
+	    startContent(10);
+
+	    startContent(7);
+	    saveContent(log.getDate());
+	    closeContent(7);
+	    
+	    startContent(2);
+	    saveContent(log.getTitle());
+	    closeContent(2);
+	    
+	    startContent(8);
+	    saveContent(log.getCommand());
+	    closeContent(8);
+	  
+	    String image;
+	    image = log.getImage();
+
+	    if (image != null)
+		{
+		    byte[] img;
+		    img = Base64.decode(image);
+		    
+		    String width,height;
+		    width = log.getWidth();
+		    height = log.getHeight();
+		    
+		    int w,h;
+		    w = Integer.parseInt(width);
+		    h = Integer.parseInt(height);
+
+		    ImageIcon icon,small_icon;
+		    small_icon = new ImageIcon(img);
+		    icon = new ImageIcon
+			(small_icon.getImage().getScaledInstance(w,h,Image.SCALE_SMOOTH));
+
+		    movie.add(0,icon);
+
+		    startContent(6);
+		    saveImage(log.getImageName(),width,height);
+		    closeContent(6);
+		}
+	    comm_bool = false;
+	    
+	    ArrayList component;
+	    component = log.getArray();
+	    int j;
+	    for (j = 0 ; j < component.size() ; j++)
+		{
+		    startContent(9);
+		    CompGroup comp;
+		    comp = (CompGroup) component.get(j);
+		    
+		    startContent(8);
+		    saveContent(comp.getStatus());
+		    closeContent(8);
+		    
+		    startContent(0);
+		    UserComponent cmp;
+		    cmp = comp.getComponent();
+		    showReport(cmp);
+		    closeContent(0);
+		    
+		    closeContent(9);
+		}
+	    
+	    comm_bool = true;
+	    closeContent(10);
+	    comm_bool = false;
+	}
+    
+	/**
+	 * This method will make the tree that contains the history and the commands of all the actions and window 
+	 * open when user did the action that stored in vector.
+	 * @param vector the vector that contains the information need to be display in tree.
+	 * @return       the panel that display tree and tree2.
+	 */
+	public JPanel createFeedbackHistory_UI(Vector vector)
+	{
+	    scroll = null;
+	    int k;
+
+	    tree = null;
+	    rootNode = null;
+	    currNode = null;
+	    parentNode =  null; 
+	    treeModel = null;
+
+	    tree2 = null;
+	    rootNode2 = null;
+	    currNode2 = null;
+	    parentNode2 =  null; 
+	    treeModel2 = null;
+	    
+	    comm_bool = true;
+	    comm_start = true;
+	    new_tree = false;
+
+	    startElement(messages.getString("HISTORY"));
+ 
+	    for (k = 0 ; k < vector.size() ; k++)
+		{
+		    History log;
+		    log = (History) vector.get(k);
+		    getHist(log);
+		}
+
+	    Vector stack;
+	    stack = getPrev_log();
+	    if (stack != null)
+		{
+		    for (k = 0 ; k < stack.size() ; k++)
+			{
+			    History log;
+			    log = (History) stack.get(k);
+			    getHist(log);
+			}
+		    stack.removeAllElements();
+		    System.gc();
+		    stack = null;
+		}
+
+	    comm_bool = true;
+	    endElement(messages.getString("HISTORY"));
+	    comm_bool = false;
+	    
+	    comm_start = false;
+	
+	    pane2 = new JPanel();
+	    pane2.add(scroll2);
+	    pane2.setBackground(new Color(176,208,176));
+	    pane2.setBorder(new EmptyBorder(new Insets(10,10,10,10)));
+
+	    JPanel pane;
+	    pane = new JPanel();
+	    pane.add(scroll);
+	    pane.setBackground(new Color(176,208,176));
+	    pane.setBorder(new EmptyBorder(new Insets(10,10,10,10)));
+	    
+	    return pane;
+	}
+
+	/**
+	 * This method will make the tree that contains the history and the commands of all the actions and window 
+	 * open when user did the action before user choose the reporting feedback sequence.
+	 * @return the panel contains the preview of this history and commands before user choose to start
+	 *         the reporting feedback sequence.
+	 */
+	public JPanel createHistory_UI()
+	{
+	    scroll3 = null;
+	    int k;
+
+	    tree3 = null;
+	    rootNode3 = null;
+	    currNode3 = null;
+	    parentNode3 =  null; 
+	    treeModel3 = null;
+
+	    tree4 = null;
+	    rootNode4 = null;
+	    currNode4 = null;
+	    parentNode4 =  null; 
+	    treeModel4 = null;
+	    
+	    comm_bool = true;
+	    comm_start = true;
+	    new_tree = true;
+
+	    startElement(messages.getString("HISTORY"));
+ 
+	    try
+		{
+		    File f = new File("history.log");
+		    FileInputStream fis = new FileInputStream(f);
+		    ObjectInputStream ois = new ObjectInputStream(fis);
+		    
+		    Vector stack;
+		    stack = (Vector) ois.readObject();
+
+		    if (stack != null)
+			{
+			    for (k = 0 ; k < stack.size() ; k++)
+				{
+				    History log;
+				    log = (History) stack.get(k);
+				    getHist(log);
+				}
+			    stack.removeAllElements();
+			    System.gc();
+			    stack = null;
+			}
+		    
+		    stack = (Vector) ois.readObject();
+		    
+		    if (stack != null)
+			{
+			    for (k = 0 ; k < stack.size() ; k++)
+				{
+				    History log;
+				    log = (History) stack.get(k);
+				    getHist(log);
+				}
+			    stack.removeAllElements();
+			    System.gc();
+			    stack = null;
+			}
+		
+		    ois.close();
+		}
+	    catch (IOException exp) {exp.printStackTrace();}
+	    catch (ClassNotFoundException exp2) 
+		{
+		    System.out.println("class exp");}
+	    
+	    comm_bool = true;
+	    endElement(messages.getString("HISTORY"));
+	    comm_bool = false;
+	    
+	    comm_start = false;
+	
+	    pane4 = new JPanel();
+	    pane4.add(scroll4);
+	    pane4.setBackground(new Color(176,208,176));
+	    pane4.setBorder(new EmptyBorder(new Insets(10,10,10,10)));
+
+	    JPanel pane;
+	    pane = new JPanel();
+	    pane.add(scroll3);
+	    pane.setBackground(new Color(176,208,176));
+	    pane.setBorder(new EmptyBorder(new Insets(10,10,10,10)));
+	    
+	    return pane;
+	}
+
+	/**
+	 * This method display all the information taken when user did the Feedback form.
+	 * @param err_details is the information taken when user did the Feedback form.
+	 * @param img         is the information from all the panels inside the Feedback form.
+	 * @return            panel displaying the information.
+	 */
+	public JPanel createFeedback_UI(String[] err_details,String[] img)
+	{
+	    scroll = null;
+	 
+	    tree = null;
+	    rootNode = null;
+	    currNode = null;
+	    parentNode =  null; 
+	    treeModel = null;
+
+	    tree2 = null;
+	    rootNode2 = null;
+	    currNode2 = null;
+	    parentNode2 =  null; 
+	    treeModel2 = null;
+
+	    startElement(messages.getString("BUGS"));
+	    
+	    startElement(messages.getString("IDCode"));
+	    characters(err_details[0].toCharArray(),0,err_details[0].length());
+	    endElement(messages.getString("IDCode"));
+	
+	    startElement(messages.getString("LastViewedWindow"));
+	    characters(err_details[1].toCharArray(),0,err_details[1].length());
+	    endElement(messages.getString("LastViewedWindow"));
+	    
+	    startElement(messages.getString("Optionals"));
+	   
+	    startElement(messages.getString("Type"));
+	    characters(err_details[3].toCharArray(),0,err_details[3].length());
+	    endElement(messages.getString("Type"));
+		
+	    startElement(messages.getString("Urgency"));
+	    characters(err_details[4].toCharArray(),0,err_details[4].length());
+	    endElement(messages.getString("Urgency"));
+	    
+	    endElement(messages.getString("Optionals"));
+	
+	    startElement(messages.getString("User"));
+	    
+	    startElement(messages.getString("Name"));
+	    characters(err_details[5].toCharArray(),0,err_details[5].length());
+	    endElement(messages.getString("Name"));
+	    
+	    startElement(messages.getString("HomeDirectory"));
+	    characters(err_details[6].toCharArray(),0,err_details[6].length());
+	    endElement(messages.getString("HomeDirectory"));
+	    
+	    startElement(messages.getString("WorkingDirectory"));
+	    characters(err_details[7].toCharArray(),0,err_details[7].length());
+	    endElement(messages.getString("WorkingDirectory"));
+	    
+	    startElement(messages.getString("SMTP"));
+	    characters(err_details[19].toCharArray(),0,err_details[19].length());
+	    endElement(messages.getString("SMTP"));
+	    
+	    startElement(messages.getString("Email"));
+	    characters(err_details[20].toCharArray(),0,err_details[20].length());
+	    endElement(messages.getString("Email"));
+
+	    endElement(messages.getString("User"));
+	    
+	    startElement(messages.getString("OpenFormTime"));
+	    characters(err_details[8].toCharArray(),0,err_details[8].length());
+	    endElement(messages.getString("OpenFormTime"));
+
+	    startElement(messages.getString("SendFormTime"));
+	    characters(err_details[9].toCharArray(),0,err_details[9].length());
+	    endElement(messages.getString("SendFormTime"));
+	    
+	    startElement(messages.getString("OperatingSystem"));
+	    characters(err_details[10].toCharArray(),0,err_details[10].length());
+	    endElement(messages.getString("OperatingSystem"));
+
+	    startElement(messages.getString("Java"));
+	    
+	    startElement(messages.getString("JavaInformation"));
+	    characters(err_details[11].toCharArray(),0,err_details[11].length());
+	    endElement(messages.getString("JavaInformation"));
+	    
+	    startElement(messages.getString("TotalMemory"));
+	    characters(err_details[21].toCharArray(),0,err_details[21].length());
+	    endElement(messages.getString("TotalMemory"));
+
+	    startElement(messages.getString("MaxMemory"));
+	    characters(err_details[22].toCharArray(),0,err_details[22].length());
+	    endElement(messages.getString("MaxMemory"));
+
+	    startElement(messages.getString("FreeMemory"));
+	    characters(err_details[23].toCharArray(),0,err_details[23].length());
+	    endElement(messages.getString("FreeMemory"));
+
+	    startElement(messages.getString("DefaultLocale"));
+	    characters(err_details[12].toCharArray(),0,err_details[12].length());
+	    endElement(messages.getString("DefaultLocale"));
+	
+
+	    endElement(messages.getString("Java"));
+	    
+	    startElement(messages.getString("Browser"));
+	    characters(err_details[13].toCharArray(),0,err_details[13].length());
+	    endElement(messages.getString("Browser"));
+	
+	    startElement(messages.getString("LocalHostName"));
+	    characters(err_details[14].toCharArray(),0,err_details[14].length());
+	    endElement(messages.getString("LocalHostName"));
+	
+	    startElement(messages.getString("LocalHostAddress"));
+	    characters(err_details[15].toCharArray(),0,err_details[15].length());
+	    endElement(messages.getString("LocalHostAddress"));
+	    
+	    startElement(messages.getString("ScreenResolution"));
+	    characters(err_details[16].toCharArray(),0,err_details[16].length());
+	    endElement(messages.getString("ScreenResolution"));
+
+	    if (img!=null)
+		{
+		    startElement("Sequences");
+		    int i;
+		    for ( i = 0 ; i < img.length ; i= i + 10)
+			{
+			    startElement("Sequence");
+			    
+			    startElement("Title");
+			    characters(img[i].toCharArray(),0,img[i].length());
+			    endElement("Title");
+			    
+			    startElement("Details");
+			    characters(img[i+9].toCharArray(),0,img[i+9].length());
+			    endElement("Details");
+			    
+			    startElement("ImageDescription");
+			    
+			    startElement("ScreenShot");
+			    startElement("Image");
+			    saveImage(img[i+2],img[i+7],img[i+8]);
+			    endElement("Image");
+			    endElement("ScreenShot");
+			    
+			    startElement("ErrorLineAndScreenShot");
+			    startElement("Image");
+			    saveImage(img[i+4],img[i+7],img[i+8]);
+			    endElement("Image");
+			    endElement("ErrorLineAndScreenShot");
+			    
+			    startElement("ErrorLineForScreenShot");
+			    startElement("Image");
+			    saveImage(img[i+6],img[i+7],img[i+8]); 
+			    endElement("Image");
+			    endElement("ErrorLineForScreenShot");
+			  
+			    endElement("ImageDescription");
+			    
+			    endElement("Sequence");
+			}
+		    endElement("Sequences");
+		}
+
+	    endElement(messages.getString("BUGS"));
+	    
+	    JPanel pane;
+	    pane = new JPanel();
+	    pane.add(scroll);
+	    pane.setBackground(new Color(176,208,176));
+	    pane.setBorder(new EmptyBorder(new Insets(10,10,10,10)));
+
+	    return pane;
+	}
+	
+	/**
+	 * This will add the UserComponent to the tree.
+	 * @param sx is the UserComponent to be added. 
+	 */
+	public void showReport (UserComponent sx)
+	{
+	    String type;
+	    type = sx.getType();
+	    String title;
+	    title = sx.getTitle();
+	    ArrayList content;
+	    content = sx.getContent();
+	    String selected;
+	    selected = sx.getSelected();
+	    String visible;
+	    visible = sx.getVisible();
+	    String image;
+	    image = sx.getImage();
+	    String img;
+	    img = sx.getImageFileName();
+	    String width;
+	    width = sx.getWidth();
+	    String height;
+	    height = sx.getHeight();
+	    String tooltip;
+	    tooltip = sx.getToolTip();
+	    
+	    if (type != null)
+		{
+		    startContent(1);
+		    saveContent(type);
+		    closeContent(1);
+		}
+	    
+	    if (title != null)
+		{
+		    startContent(2);
+		    saveContent(title);
+		    closeContent(2);
+		}
+	    
+	    if (content != null)
+		{
+		    startContent(3);
+		    int j;
+		    for ( j = 0 ; j < content.size() ; j++)
+			{
+			    if (content.get(j) instanceof String)
+				saveContent((String) content.get(j));
+			    else if (content.get(j) instanceof UserComponent)
+				{
+				    startContent(0);
+				    UserComponent cmp;
+				    cmp = (UserComponent) content.get(j);
+				    showReport(cmp);
+				    closeContent(0);
+				}
+			}
+		    closeContent(3);
+		}
+	    
+	    if (selected != null)
+		{
+		    startContent(4);
+		    saveContent(selected);
+		    closeContent(4);
+		}
+	    
+	    if (visible != null)
+		{
+		    startContent(5);
+		    saveContent(visible);
+		    closeContent(5);
+		}
+	
+	    if (img != null)
+		{
+		    startContent(6);
+		    saveImage(img,width,height);
+		    closeContent(6);
+		}
+	    else
+		{
+		    if (image != null)
+			{ 
+			    startContent(11);
+			    saveContent(image);
+			    closeContent(11);
+			} 
+		}
+
+	    if (tooltip != null)
+		{
+		    startContent(12);
+		    saveContent(tooltip);
+		    closeContent(12);
+		}
+	}
+	
+	/**
+	 * This method will give what type of information this node hold according the number
+	 * @param num the number that describe what type of information it hold.
+	 */
+	public void startContent (int num)
+	{
+	    switch(num)
+		{
+		case 0: startElement(messages.getString("COMPONENT"));
+		    break;
+		case 1: startElement(messages.getString("Type"));
+		    break;
+		case 2: startElement(messages.getString("Title"));
+		    break;
+		case 3: startElement(messages.getString("Content"));
+		    break;
+		case 4: startElement(messages.getString("Selected"));
+		    break;
+		case 5: startElement(messages.getString("Visible"));  
+		    break;
+		case 6: startElement(messages.getString("Image"));
+		    break;
+		case 7: startElement(messages.getString("Date"));
+		    break;
+		case 8: startElement(messages.getString("Command"));
+		    break;
+		case 9: startElement(messages.getString("COMPONENTS"));
+		    break;
+		case 10:startElement(messages.getString("LOG"));
+		    break;
+		case 11:startElement(messages.getString("Icon"));
+		    break;
+		case 12:startElement(messages.getString("ToolTipText"));
+		    break;
+		case 13:startElement(messages.getString("Comment"));
+		    break;
+		}
+	}
+	
+	/**
+	 * This will add the text content to the current node.
+	 * @param text is the text content of the current node.
+	 */
+	public void saveContent (String text)
+	{
+	    if (text == null)
+		text = "\t";
+	    characters(text.toCharArray(),0,text.length());
+	}
+	
+	/**
+	 * This will say that what type of information that has been finished added
+	 * accroding its number.
+	 * @param num  the number that describe what type of information it hold.
+	 */
+	public void closeContent (int num)
+	{
+	    switch(num)
+		{
+		case 0: endElement(messages.getString("COMPONENT"));
+		    break;
+		case 1: endElement(messages.getString("Type"));
+		    break;
+		case 2: endElement(messages.getString("Title"));
+		    break;
+		case 3: endElement(messages.getString("Content"));
+		    break;
+		case 4: endElement(messages.getString("Selected"));
+		    break;
+		case 5: endElement(messages.getString("Visible"));
+		    break;
+		case 6: endElement(messages.getString("Image"));
+		    break;
+		case 7: endElement(messages.getString("Date"));
+		    break;
+		case 8: endElement(messages.getString("Command"));
+		    break;
+		case 9: endElement(messages.getString("COMPONENTS"));
+		    break;
+		case 10:endElement(messages.getString("LOG"));
+		    break;
+		case 11:endElement(messages.getString("Icon"));
+		    break;
+		case 12:endElement(messages.getString("ToolTipText"));
+		    break;
+		case 13:endElement(messages.getString("Comment"));
+		    break;
+		}
+	}
+	
+	/**
+	 * This method will add the this string to the appropriate place in the tree.
+	 * @param type its the type to be added to the tree.
+	 */
+	public void startElement (String type)
+	{
+	   
+	    if ((comm_bool == true)&&(comm_start == true))
+		{
+		    if (new_tree == true)
+			{
+			    if (type == messages.getString("HISTORY"))
+				{
+				    rootNode4 = new DefaultMutableTreeNode(messages.getString("HISTORYCOMMANDS"));
+				    treeModel4 = new DefaultTreeModel(rootNode4);
+				    
+				    parentNode4 = rootNode4;
+				    tree4 = new JTree(treeModel4);
+				    tree4.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+				    tree4.setBackground(new Color(224,240,224));
+				    tree4.setEditable(false);
+				    tree4.setShowsRootHandles(true);
+				}  
+			    else
+				{
+				    currNode4 = new DefaultMutableTreeNode(type + " : ");
+				    treeModel4.insertNodeInto(currNode4,parentNode4,parentNode4.getChildCount());
+				    parentNode4 = currNode4;
+				} 
+			}
+		    else
+			{
+			    if (type == messages.getString("HISTORY"))
+				{
+				    rootNode2 = new DefaultMutableTreeNode(messages.getString("HISTORYCOMMANDS"));
+				    treeModel2 = new DefaultTreeModel(rootNode2);
+				    
+				    parentNode2 = rootNode2;
+				    tree2 = new JTree(treeModel2);
+				    tree2.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+				    tree2.setBackground(new Color(224,240,224));
+				    tree2.setEditable(false);
+				    tree2.setShowsRootHandles(true);
+				}  
+			    else
+				{
+				    currNode2 = new DefaultMutableTreeNode(type + " : ");
+				    treeModel2.insertNodeInto(currNode2,parentNode2,parentNode2.getChildCount());
+				    parentNode2 = currNode2;
+				} 
+			}
+		}
+		
+	    if ((type == messages.getString("COMMENTS"))||(type == messages.getString("BUGS"))||
+		(type == messages.getString("HISTORY")))
+		{
+		    if (new_tree == true)
+			{
+			    rootNode3 = new DefaultMutableTreeNode(type);
+			    treeModel3 = new DefaultTreeModel(rootNode3);
+			    
+			    parentNode3 = rootNode3;
+			    tree3 = new JTree(treeModel3);
+			    tree3.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+			    
+			    tree3.setBackground(new Color(224,240,224));
+			    tree3.setEditable(false);
+			    tree3.setShowsRootHandles(true);
+			}
+		    else
+			{
+			    rootNode = new DefaultMutableTreeNode(type);
+			    treeModel = new DefaultTreeModel(rootNode);
+			    
+			    parentNode = rootNode;
+			    tree = new JTree(treeModel);
+			    tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+			    
+			    tree.setBackground(new Color(224,240,224));
+			    tree.setEditable(false);
+			    tree.setShowsRootHandles(true);
+			}
+		}
+	    else
+		 {
+		     if (new_tree == true)
+			 {
+			     currNode3 = new DefaultMutableTreeNode(type + " : ");
+			     treeModel3.insertNodeInto(currNode3,parentNode3,parentNode3.getChildCount());
+			     parentNode3 = currNode3;
+			 }
+		     else
+			 {
+			     currNode = new DefaultMutableTreeNode(type + " : ");
+			     treeModel.insertNodeInto(currNode,parentNode,parentNode.getChildCount());
+			     parentNode = currNode;
+			 }
+		 }
+	}
+	
+	/**
+	 * This method is to mark that we finished adding the type to the tree.
+	 * @param type type that finished added to the tree.
+	 */
+	public void endElement (String type)
+	{
+	    if ((type == messages.getString("HISTORY"))||(type == messages.getString("BUGS"))||
+		(type == messages.getString("COMMENTS")))
+		{
+		    if (new_tree == true)
+			{
+			    scroll3 = new JScrollPane(tree3);
+			    scroll3.setPreferredSize(new Dimension(600,600));
+			    if (comm_bool == true)
+				{
+				    scroll4 = new JScrollPane(tree4);
+				    scroll4.setPreferredSize(new Dimension(600,600));
+				}
+			}
+		    else
+			{
+			    scroll = new JScrollPane(tree);
+			    scroll.setPreferredSize(new Dimension(600,600));
+			    if (comm_bool == true)
+				{
+				    scroll2 = new JScrollPane(tree2);
+				    scroll2.setPreferredSize(new Dimension(600,600));
+				}
+			}
+		}
+	    else
+		{
+		    if (new_tree == true)
+			{
+			    parentNode3 = (DefaultMutableTreeNode) parentNode3.getParent();
+			    
+			    if ((comm_bool == true)&&(comm_start == true))
+				{
+				    if (parentNode4 == null)  return;
+				    parentNode4 = (DefaultMutableTreeNode) parentNode4.getParent();
+				}  
+			}
+		    else
+			{
+			    parentNode = (DefaultMutableTreeNode) parentNode.getParent();
+			    
+			    if ((comm_bool == true)&&(comm_start == true))
+				{
+				    if (parentNode2 == null)  return;
+				    parentNode2 = (DefaultMutableTreeNode) parentNode2.getParent();
+				}  
+			}
+		}
+	}
+	
+	/*public BufferedImage iconToImage(Icon icon, Component targetComponent) 
+	{
+	    int w = icon.getIconWidth();
+	    int h = icon.getIconHeight();
+	    GraphicsConfiguration gc = targetComponent.getGraphicsConfiguration();
+	    BufferedImage image = gc.createCompatibleImage(w, h);
+	    Graphics2D g = image.createGraphics();
+	    icon.paintIcon(targetComponent,g,0,0);
+	    g.dispose();
+	    return image;
+	}
+	
+	public BufferedImage savingImage (ImageIcon img)
+	{
+	    JFrame f = new JFrame();
+	    f.setVisible(false);
+	    BufferedImage image = iconToImage(img,f);
+	    f.dispose();
+	    return image;
+	    }*/
+	
+	/**
+	 * This will add the image filename,width and height to the tree.
+	 * @param filename image's filename
+	 * @param width    image's width
+	 * @param height   image's height
+	 */
+	public void saveImage (String filename,String width,String height)
+	{
+	    startElement(messages.getString("Title"));
+	    characters(filename.toCharArray(),0,filename.length());
+	    endElement(messages.getString("Title"));
+	
+	    startElement(messages.getString("Size"));
+	    
+	    startElement(messages.getString("Width"));
+	    characters(width.toCharArray(),0,width.length());
+	    endElement(messages.getString("Width"));
+	    
+	    startElement(messages.getString("Height"));
+	    characters(height.toCharArray(),0,height.length());
+	    endElement(messages.getString("Height"));
+
+	    endElement(messages.getString("Size"));
+
+	    /*JFrame f = new JFrame();
+	    f.setVisible(false);
+	    BufferedImage image = savingImage(img);
+	    BufferedImage bi = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB);
+	    Graphics2D big = bi.createGraphics();
+	    big.drawImage(image.getScaledInstance(400,400,Image.SCALE_SMOOTH),0,0,f);
+	    f.dispose();
+	    
+	
+	    JLabel label = new JLabel(new ImageIcon(bi));
+	    label.setPreferredSize(new Dimension(400,400));
+	    currNode = new DefaultMutableTreeNode(label);
+	    treeModel.insertNodeInto(currNode,parentNode,parentNode.getChildCount());*/
+	}
+	
+	/**
+	 * This method will add the characters to the current node's type.
+	 * @param ch is the char[] that is need to be added to the current node's type.
+	 * @param start is where we should start taking from ch.
+	 * @param len is the length of charcacters we should take from ch
+	 */
+	public void characters (char[] ch, int start, int len)
+	{
+	    String text;
+	    text = new String(ch,start,len);
+	    String text1;
+	    text1 = text.trim();
+	    if (text1.length() > 0)
+		{
+		    if ((comm_bool == true)&&(comm_start == true))
+			{
+			    if (new_tree == true)
+				{
+				    String txt2;
+				    txt2 = (String) currNode4.getUserObject();
+				    currNode4.setUserObject(txt2 + text1);
+				}
+			    else 
+				{
+				    String txt2;
+				    txt2 = (String) currNode2.getUserObject();
+				    currNode2.setUserObject(txt2 + text1);
+				}
+			}
+
+		    if (new_tree == true)
+			{
+			    String txt;
+			    txt = (String) currNode3.getUserObject();
+			    currNode3.setUserObject(txt + text1);
+			}
+		    else
+			{
+			    String txt;
+			    txt = (String) currNode.getUserObject();
+			    currNode.setUserObject(txt + text1);
+			}
+		}
+	}
+    }
+ 
+}
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SaveToXML.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SaveToXML.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SaveToXML.java	(revision 10506)
@@ -0,0 +1,482 @@
+package org.greenstone.gatherer.feedback;
+
+import java.awt.image.*;
+import java.io.*;// SAX classes.
+import javax.imageio.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;//JAXP 1.1
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.stream.*;
+import javax.xml.transform.sax.*; 
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+import java.util.*;
+
+/**
+ * This class will make xml files from the information given.
+ * @author Veronica Liesaputra
+ */
+public class SaveToXML
+{
+    /**
+     * This is the file where the xml file will be saved.
+     */
+    private FileOutputStream fos;
+    /**
+     * This is the transformer handler for the xml file.
+     */
+    private TransformerHandler hd;
+    /**
+     * This is the attribute implementation for the xml file.
+     */
+    private AttributesImpl atts;
+     /**
+     * This variable will hold the resource of the words that is stored in Messages.properties file.
+     * The calling using messages.getString(someString) will caused someString to be translated
+     * into some other string that is hold in that file.usually it will caused it to be translated
+     * to the language that the user use or choose to have as stated in Locale.
+     */
+    private static ResourceBundle messages;
+
+    /**
+     * This constructor will setup what languange should be use.
+     * @param msg will hold the resource of the words that is stored in Messages.properties file.
+     */
+    public SaveToXML(ResourceBundle msg)
+    {
+	messages = msg;
+    }
+
+    /**
+     * This will save the image, image filename,width and height to the xml file.
+     * @param image    image
+     * @param filename image's filename
+     * @param width    image's width
+     * @param height   image's height
+     */
+    public void saveImage (String image,String filename,String width,String height)
+    {
+	try
+	    {
+		hd.startElement("","","Title",atts);
+		hd.characters(filename.toCharArray(),0,filename.length());
+		hd.endElement("","","Title");
+		hd.startElement("","","Size",atts);
+		hd.startElement("","","Width",atts);
+		hd.characters(width.toCharArray(),0,width.length());
+		hd.endElement("","","Width");
+		hd.startElement("","","Height",atts);
+		hd.characters(height.toCharArray(),0,height.length());
+		hd.endElement("","","Height");
+		hd.endElement("","","Size");
+		hd.startElement("","","View",atts);
+		hd.characters(image.toCharArray(),0,image.length());
+		hd.endElement("","","View");
+	    }
+	catch(SAXException sax) {}
+    }
+
+    /**
+     * This method will create and setup the xml file.
+     * @param xmlname this is the file name for the xml file.
+     * @param type    this is the first tag that open the xml file.
+     */
+    public void open (String xmlname,String type)
+    {
+	try
+	    {
+		File f;
+		f = new File(xmlname);
+		fos = new FileOutputStream(f);
+		PrintWriter out;
+		out = new PrintWriter(fos);
+		StreamResult streamResult;
+		streamResult = new StreamResult(out);
+		SAXTransformerFactory tf;
+		tf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
+		hd = tf.newTransformerHandler();
+		Transformer serializer;
+		serializer = hd.getTransformer();
+		
+		serializer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
+		//serializer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,dtdname);
+		serializer.setOutputProperty(OutputKeys.INDENT,"yes");
+			
+		hd.setResult(streamResult);
+		atts = new AttributesImpl();
+		
+		hd.startDocument();
+		
+		hd.startElement("","",type,atts);   
+	    }
+	catch (IOException e){
+	    System.err.println ("Unable to write to file");
+	    System.exit(-1);
+	}catch (TransformerConfigurationException tce){
+	    System.err.println("Error in: TransformerConfigurationException");
+	}catch (SAXException spe) {
+	    // Error generated by the parser
+	    System.err.println("Error in: (SAXException");
+	    // Use the contained exception, if any
+	    Exception  x = spe;
+	    if (spe.getException() != null)
+		x = spe.getException();
+	    x.printStackTrace();
+	}
+    }
+
+    /**
+     * This method will setup to close the xml file.
+     * @param type    this is the last tag that close the xml file.
+     */
+    public void close(String type)
+    {
+	try
+	    {
+		hd.endElement("","",type);
+		hd.endDocument();
+		fos.close(); 
+	    }
+	catch (IOException e){
+	    System.err.println ("Unable to write to file");
+	    System.exit(-1);
+	}catch (SAXException spe) {
+	    // Error generated by the parser
+	    System.err.println("Error in: (SAXException");
+	    // Use the contained exception, if any
+	    Exception  x = spe;
+	    if (spe.getException() != null)
+		x = spe.getException();
+	    x.printStackTrace();
+	}
+    }
+
+    /**
+     * This method will add the open tag according to the number.
+     * @param num the number to say which type of tag it is.
+     */
+    public void startContent (int num)
+    {
+	try
+	    {
+		switch(num)
+		    {
+		    case 0: hd.startElement("","","COMPONENT",atts);
+			break;
+		    case 1: hd.startElement("","","Type",atts);
+			break;
+		    case 2: hd.startElement("","","Title",atts);
+			break;
+		    case 3: hd.startElement("","","Content",atts);
+			break;
+		    case 4: hd.startElement("","","Selected",atts);
+			break;
+		    case 5: hd.startElement("","","Visible",atts);  
+			break;
+		    case 6: hd.startElement("","","Image",atts);
+			break;
+		    case 7: hd.startElement("","","Date",atts);
+			break;
+		    case 8: hd.startElement("","","Command",atts);
+			break;
+		    case 9: hd.startElement("","","COMPONENTS",atts);
+			break;
+		    case 10:hd.startElement("","","LOG",atts);
+			break;
+		    case 11:hd.startElement("","","Icon",atts);
+			break;
+		    case 12:hd.startElement("","","ToolTipText",atts);
+			break;
+		    case 13:hd.startElement("","","Comment",atts);
+			break;
+		    }
+	    }
+	catch (SAXException spe) {
+	    // Error generated by the parser
+	    System.err.println("Error in: (SAXException");
+	    // Use the contained exception, if any
+	    Exception  x;
+	    x = spe;
+	    if (spe.getException() != null)
+		x = spe.getException();
+	    x.printStackTrace();
+	}
+    }
+
+    /**
+     * This method will add the text to the tag.
+     * @param text is the text to be saved in xml files.
+     */
+    public void saveContent (String text)
+    {
+	try
+	    {
+		if (text == null)
+		    text = "\t";
+		hd.characters(text.toCharArray(),0,text.length());
+	    }
+	catch (SAXException spe) {
+	    // Error generated by the parser
+	    System.err.println("Error in: (SAXException");
+	    // Use the contained exception, if any
+	    Exception  x;
+	    x = spe;
+	    if (spe.getException() != null)
+		x = spe.getException();
+	    x.printStackTrace();
+	}
+    }
+
+    /**
+     * This method will add the close tag according to the number.
+     * @param num the number to say which type of tag it is.
+     */
+    public void closeContent (int num)
+    {
+	try
+	    {
+		switch(num)
+		    {
+		    case 0: hd.endElement("","","COMPONENT");
+			break;
+		    case 1: hd.endElement("","","Type");
+			break;
+		    case 2: hd.endElement("","","Title");
+			break;
+		    case 3: hd.endElement("","","Content");
+			break;
+		    case 4: hd.endElement("","","Selected");
+			break;
+		    case 5: hd.endElement("","","Visible");
+			break;
+		    case 6: hd.endElement("","","Image");
+			break;
+		    case 7: hd.endElement("","","Date");
+			break;
+		    case 8: hd.endElement("","","Command");
+			break;
+		    case 9: hd.endElement("","","COMPONENTS");
+			break;
+		    case 10:hd.endElement("","","LOG");
+			break;
+		    case 11:hd.endElement("","","Icon");
+			break;
+		    case 12:hd.endElement("","","ToolTipText");
+			break;
+		    case 13:hd.endElement("","","Comment");
+			break;
+		    }
+	    }
+	catch (SAXException spe) {
+	    // Error generated by the parser
+	    System.err.println("Error in: (SAXException");
+	    // Use the contained exception, if any
+	    Exception  x;
+	    x = spe;
+	    if (spe.getException() != null)
+		x = spe.getException();
+	    x.printStackTrace();
+	}
+    }
+
+    /**
+     * This method save to xml all the information taken when user did the Feedback form.
+     * @param err_details is the information taken when user did the Feedback form.
+     * @param img         is the images taken when user did the Feedback form
+     */ 
+    public void saveFeedback (String[] err_details,String[] img)
+    {
+	try
+	    {
+		String dirname;
+		dirname = "xmlfeedback/";
+		FileOutputStream fos;
+		fos = new FileOutputStream(dirname + "feedback" + err_details[0] + 
+					   ".xml");
+		PrintWriter out;
+		out = new PrintWriter(fos);
+		StreamResult streamResult;
+		streamResult = new StreamResult(out);
+		SAXTransformerFactory tf;
+		tf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
+		hd = tf.newTransformerHandler();
+		Transformer serializer;
+		serializer = hd.getTransformer();
+		serializer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
+		serializer.setOutputProperty(OutputKeys.INDENT,"yes");
+		hd.setResult(streamResult);
+		
+		
+		hd.startDocument();
+		atts = new AttributesImpl();
+		hd.startElement("","","BUGS",atts);
+		
+		hd.startElement("","","IDCode",atts);
+		hd.characters(err_details[0].toCharArray(),0,err_details[0].length());
+		hd.endElement("","","IDCode");
+		
+		hd.startElement("","","LastViewedWindow",atts);
+		hd.characters(err_details[1].toCharArray(),0,err_details[1].length());
+		hd.endElement("","","LastViewedWindow");
+
+		hd.startElement("","","Optionals",atts);
+		
+		hd.startElement("","","Type",atts);
+		hd.characters(err_details[3].toCharArray(),0,err_details[3].length());
+		hd.endElement("","","Type");
+		
+		hd.startElement("","","Urgency",atts);
+		hd.characters(err_details[4].toCharArray(),0,err_details[4].length());
+		hd.endElement("","","Urgency");
+		hd.endElement("","","Optionals");
+
+		hd.startElement("","","User",atts);
+		hd.startElement("","","Name",atts);
+		hd.characters(err_details[5].toCharArray(),0,err_details[5].length());
+		hd.endElement("","","Name");
+
+		hd.startElement("","","HomeDirectory",atts);
+		hd.characters(err_details[6].toCharArray(),0,err_details[6].length());
+		hd.endElement("","","HomeDirectory");
+
+		hd.startElement("","","WorkingDirectory",atts);
+		hd.characters(err_details[7].toCharArray(),0,err_details[7].length());
+		hd.endElement("","","WorkingDirectory");
+
+		hd.startElement("","","SMTP",atts);
+		hd.characters(err_details[19].toCharArray(),0,err_details[19].length());
+		hd.endElement("","","SMTP");
+
+		hd.startElement("","","Email",atts);
+		hd.characters(err_details[20].toCharArray(),0,err_details[20].length());
+		hd.endElement("","","Email");
+
+		hd.endElement("","","User");
+
+		hd.startElement("","","OpenFormTime",atts);
+		hd.characters(err_details[8].toCharArray(),0,err_details[8].length());
+		hd.endElement("","","OpenFormTime");
+
+		hd.startElement("","","SendFormTime",atts);
+		hd.characters(err_details[9].toCharArray(),0,err_details[9].length());
+		hd.endElement("","","SendFormTime");
+
+		hd.startElement("","","OperatingSystem",atts);
+		hd.characters(err_details[10].toCharArray(),0,err_details[10].length());
+		hd.endElement("","","OperatingSystem");
+
+		hd.startElement("","","Java",atts);
+
+		hd.startElement("","","JavaInformation",atts);
+		hd.characters(err_details[11].toCharArray(),0,err_details[11].length());
+		hd.endElement("","","JavaInformation");
+
+		hd.startElement("","","TotalMemory",atts);
+		hd.characters(err_details[21].toCharArray(),0,err_details[21].length());
+		hd.endElement("","","TotalMemory");
+
+		hd.startElement("","","MaxMemory",atts);
+		hd.characters(err_details[22].toCharArray(),0,err_details[22].length());
+		hd.endElement("","","MaxMemory");
+
+		hd.startElement("","","FreeMemory",atts);
+		hd.characters(err_details[23].toCharArray(),0,err_details[23].length());
+		hd.endElement("","","FreeMemory");
+
+		hd.startElement("","","DefaultLocale",atts);
+		hd.characters(err_details[12].toCharArray(),0,err_details[12].length());
+		hd.endElement("","","DefaultLocale");
+		
+		hd.endElement("","","Java");
+
+		hd.startElement("","","Browser",atts);
+		hd.characters(err_details[13].toCharArray(),0,err_details[13].length());
+		hd.endElement("","","Browser");
+
+		hd.startElement("","","LocalHostName",atts);
+		hd.characters(err_details[14].toCharArray(),0,err_details[14].length());
+		hd.endElement("","","LocalHostName");
+
+		hd.startElement("","","LocalHostAddress",atts);
+		hd.characters(err_details[15].toCharArray(),0,err_details[15].length());
+		hd.endElement("","","LocalHostAddress");
+
+		hd.startElement("","","ScreenResolution",atts);
+		hd.characters(err_details[16].toCharArray(),0,err_details[16].length());
+		hd.endElement("","","ScreenResolution");
+
+		if (img!= null)
+		    {
+			hd.startElement("","","Sequences",atts);
+			int i;
+			for ( i = 0 ; i < img.length ; i= i + 10)
+			    {
+				hd.startElement("","","Sequence",atts);
+				
+				hd.startElement("","","Title",atts);
+				hd.characters(img[i].toCharArray(),0,img[i].length());
+				hd.endElement("","","Title");
+				
+				hd.startElement("","","Details",atts);
+				hd.characters(img[i+9].toCharArray(),0,img[i+9].length());
+				hd.endElement("","","Details");
+				
+				hd.startElement("","","ImageDescription",atts);
+				
+				hd.startElement("","","ScreenShot",atts);
+				hd.startElement("","","Image",atts);
+				saveImage(img[i+1],img[i+2],img[i+7],img[i+8]);
+				hd.endElement("","","Image");
+				hd.endElement("","","ScreenShot");
+				
+				hd.startElement("","","ErrorLineAndScreenShot",atts);
+				hd.startElement("","","Image",atts);
+				saveImage(img[i+3],img[i+4],img[i+7],img[i+8]);
+				hd.endElement("","","Image");
+				hd.endElement("","","ErrorLineAndScreenShot");
+				
+				hd.startElement("","","ErrorLineForScreenShot",atts);
+				hd.startElement("","","Image",atts);
+				saveImage(img[i+5],img[i+6],img[i+7],img[i+8]); 
+				hd.endElement("","","Image");
+				hd.endElement("","","ErrorLineForScreenShot");
+				
+				hd.endElement("","","ImageDescription");
+				
+				hd.endElement("","","Sequence");
+			    }
+			hd.endElement("","","Sequences");
+		    }
+
+		hd.endElement("","","BUGS");
+		hd.endDocument();
+		fos.close();
+	    }
+	catch (IOException e){
+	    System.err.println ("Unable to write to file");
+	    System.exit(-1);
+	}catch (TransformerConfigurationException tce){
+	    System.err.println("Error in: TransformerConfigurationException");
+	}catch (SAXException spe) {
+	    // Error generated by the parser
+	    System.err.println("Error in: (SAXException");
+	    // Use the contained exception, if any
+	    Exception  x;
+	    x = spe;
+	    if (spe.getException() != null)
+		x = spe.getException();
+	    x.printStackTrace();
+	}
+    }
+}
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ScreenShot.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ScreenShot.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ScreenShot.java	(revision 10506)
@@ -0,0 +1,273 @@
+package org.greenstone.gatherer.feedback;
+
+import java.awt.*;
+import java.applet.Applet;
+import java.awt.image.*;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.geom.GeneralPath;
+import java.io.*;
+import javax.imageio.*;
+import javax.swing.*; 
+import com.sun.image.codec.jpeg.*;
+import java.awt.geom.*;
+
+/**
+ * This class can take screen shot of the whole screen size or screen shot of a specified
+ * rectangle only.
+ * @author Veronica Liesaputra
+ */
+public class ScreenShot
+{
+    /**
+     * This is the buffered image that hold the screen shot.
+     */
+    private BufferedImage img;
+    
+    /**
+     * The dimension of the whole screen size.
+     */
+    private final static Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
+    
+    /**
+     * Rectangle with a dimension of a whole screen size.
+     */
+    private Rectangle mRect = new Rectangle(dim);
+    
+    /**
+     * The desired width of the image.
+     */
+    private int iw;
+
+    /**
+     * The desired height of the image.
+     */
+    private int ih;
+
+    /**
+     * BufferedImage that hold the screen shot image with the desired height and width.
+     */
+    private BufferedImage bi;
+    
+    /**
+     * This is the robot that allows to take screen shot.
+     */
+    private Robot mRobot;
+  
+    /**
+     * This constructor will setup the robot to alow taking a screen shot.
+     */
+    public ScreenShot () 
+    {
+	try
+	    {
+		mRobot = new Robot();
+		iw = (int) (dim.getWidth() - 60);
+		ih = (int) (dim.getHeight() * 0.75) - 50;
+	    }
+	catch (AWTException exp) {}
+    }
+
+    /**
+     * This method will only take screen shot of the particular rectangle.
+     * @param rect is the specified rectangle that we want to take the screen shot of.
+     * @return     the image taken.
+     */
+    //public byte[] getImageIcon (Rectangle rect)
+    public BufferedImage getImageIcon (Rectangle rect)
+    {
+	BufferedImage image;
+	image = null;
+	
+	//try
+	//  {
+		img = mRobot.createScreenCapture(rect);
+		
+		int w,h;
+		boolean rescale;
+
+		rescale = false;
+		w = rect.width;
+		
+		if (w >= iw)
+		    {
+			w = iw - 50;
+			rescale = true;
+		    }
+		
+		h = rect.height;
+		
+		if ( h >= ih)
+		    {
+			h = ih  - 50;
+			rescale = true;
+		    }
+		
+		Graphics2D big;
+		big = null;
+		
+		if (rescale == true)
+		    {
+			image = new BufferedImage(w,h, BufferedImage.TYPE_INT_RGB);
+			big = image.createGraphics();
+			big.drawImage(img.getScaledInstance(w,h,Image.SCALE_SMOOTH),0,0,null);
+		    }
+		else
+		    {
+			image = img;
+		    }
+
+		
+		/*ByteArrayOutputStream stream;
+		stream = new ByteArrayOutputStream();
+		ImageIO.write(image,"jpeg",stream);
+		byte[] bytes;
+		bytes = stream.toByteArray();*/
+		
+		if (big != null)
+		    big.dispose();
+		//image = null;
+		//img = null;
+		ActionRecorderDialog.setSavefinish(true);
+		return image;
+		//return bytes;
+		//  }
+		//catch(IOException ex) {ex.printStackTrace();}
+	
+	//return null;
+    }
+
+    /**
+     * This method will only take screen shot of the particular rectangle and encode
+     * the image to its string representation.
+     * @param rect is the specified rectangle that we want to take the screen shot of.
+     * @return     the string representation of the image taken.
+     */
+    public String getImage (Rectangle rect)
+    {
+	String txt;
+	txt = null;
+
+	BufferedImage image;
+	image = null;
+	
+	try
+	    {
+		img = mRobot.createScreenCapture(rect);
+		
+		int w,h;
+		boolean rescale;
+
+		rescale = false;
+		w = rect.width;
+		
+		if (w >= iw)
+		    {
+			w = iw - 50;
+			rescale = true;
+		    }
+		
+		h = rect.height;
+		
+		if ( h >= ih)
+		    {
+			h = ih  - 50;
+			rescale = true;
+		    }
+	
+		Graphics2D big;
+		big = null;
+
+		if (rescale == true)
+		    {
+			image = new BufferedImage(w,h, BufferedImage.TYPE_INT_RGB);
+			big = image.createGraphics();
+			big.drawImage(img.getScaledInstance(w,h,Image.SCALE_SMOOTH),0,0,null);
+		    }
+		else
+		    {
+			image = img;
+		    }
+
+		ByteArrayOutputStream stream;
+		stream = new ByteArrayOutputStream();
+		ImageIO.write(image,"gif",stream);
+		byte[] bytes;
+		bytes = stream.toByteArray();
+		txt = Base64.encodeBytes(bytes);
+		
+		bytes = null;
+		if (big != null)
+		    big.dispose();
+		image = null;
+		img = null;
+	    }
+	catch(IOException ex) {ex.printStackTrace();}
+	
+	ActionRecorderDialog.setSavefinish(true);
+	
+	return txt;
+    }
+
+    /**
+     * This method will return the buffered image of the whole screen size screen shot
+     * with the desired width and height.
+     * @return the buffered image with the desired height and width.
+     */
+    public BufferedImage getBuffImage()
+    {
+	return bi;
+    }
+
+    /**
+     * This method will take screen shot of the whole screen and resize it to the
+     * desired width and height.
+     */
+    public BufferedImage captureScreen()
+    {
+	img = mRobot.createScreenCapture(mRect);
+	
+	Graphics2D big;
+	bi = new BufferedImage(iw,ih, BufferedImage.TYPE_INT_RGB);
+	big = bi.createGraphics();
+	big.drawImage(img.getScaledInstance(iw,ih,Image.SCALE_SMOOTH),0,0,null);
+	big.dispose();
+	big = null;
+
+	return bi;
+    }
+
+    /**
+     * This method will return the desired width.
+     * @return the desired width.
+     */
+    public int getWidth()
+    {
+	return iw;
+    }
+
+    /**
+     * This method will return the desired height.
+     * @return the desired height.
+     */
+    public int getHeight()
+    {
+	return ih;
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SelectPicture.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SelectPicture.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SelectPicture.java	(revision 10506)
@@ -0,0 +1,819 @@
+package org.greenstone.gatherer.feedback;
+
+import java.awt.image.*;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.*;
+import javax.swing.event.MouseInputAdapter;
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.geom.Line2D.*;
+import java.awt.geom.Line2D.Double;
+import java.awt.event.*;
+import java.awt.event.MouseEvent;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+import javax.swing.border.*;
+import javax.swing.BorderFactory;
+
+import org.greenstone.gatherer.util.JarTools;
+
+/**
+ * This class allows user to make scribble lines in the image.
+ * This class will display an image to a label and if the user drag inside the label
+ * then it will draw coloured line as the user drag the mouse.
+ * Image here is the screen shot of the whole screen size.
+ * @author Veronica Liesaputra
+ */
+public class SelectPicture extends WindowAdapter
+{
+    /**
+     * This is the images that stored all the images for the whole screen size image.
+     */
+    private BufferedImage[] screen;
+  
+    /**
+     * This is the images that stored all the images for the window image.
+     */
+    private BufferedImage[] window;
+
+    /**
+     * This is the buffered image that contains the line that are drawn all
+     * over the screen image.
+     */
+    private BufferedImage bi;
+    
+    /**
+     * This is the buffered image of the line that are drawn all over the screen image.
+     */
+    private BufferedImage bi2;
+
+    /**
+     * This is the buffered image of the screen image.
+     */
+    private BufferedImage bi3;
+
+    /**
+     * This is the buffered image that contains the line that are drawn all over the window image.
+     */
+    private BufferedImage bi4;
+
+    /**
+     * This is the buffered image of the line that are drawn all over the window image.
+     */
+    private BufferedImage bi5;
+
+    /**
+     * This is the buffered image of the window image.
+     */
+    private BufferedImage bi6;
+
+    /**
+     * This is the window's x-coord in the screen image.
+     */
+    private int xcoord;
+
+    /**
+     * This is the window's y-coord in the screen image.
+     */
+    private int ycoord;
+
+    /**
+     * This is the window's width in the screen image.
+     */
+    private int width;
+
+    /**
+     * This is the window's height in the screen image.
+     */
+    private int height;
+    
+    /**
+     * This is to block all the input in this window while waiting.
+     */
+    private MouseListener mouse_blocker_listener = new MouseAdapter() {};
+    
+    /**
+     * This variable will hold the resource of the words that is stored in Messages.properties file.
+     * The calling using messages.getString(someString) will caused someString to be translated
+     * into some other string that is hold in that file.usually it will caused it to be translated
+     * to the language that the user use or choose to have as stated in Locale.
+     */
+    private static ResourceBundle messages;
+    
+    /**
+     * This variable hold the comments that user entered when they are drawing lines into the image.
+     */
+    private String details;
+    
+    /**
+     * This variable is a flag to say whether or not user wants to send the feedback straight away.
+     */
+    private boolean sendNow;
+
+    /**
+     * This variable is a flag to say whether the user wants to draw the scribble lines or
+     * to erase the image.
+     */
+    private boolean drawNow;
+
+    /**
+     * This variable is a flag to say whether or not the image user wants to send is window
+     * or the whole screen image.
+     */
+    private boolean windowNow;
+
+    /**
+     * This method will make a modal-dialog that will allow user to draw a line all over the image.
+     * @param sh the buffered images of the screen image.
+     * @param wh the buffered images of the window image.
+     * @param iswindow the flag to say whether user wants to send window or whole screen image.
+     * @param screen_details the comments that user typed for this screenshot.
+     * @param msg hold the resource of the words that is stored in Messages.properties file.
+     */
+    public SelectPicture(BufferedImage[] sh,BufferedImage[] wh,boolean iswindow,String screen_details,ResourceBundle msg)
+    {
+	windowNow = iswindow;
+	drawNow = true;
+	details = screen_details;
+	messages = msg;
+	window = wh;
+	screen = sh;
+    }
+    
+    /**
+     * This method setting up the window's bounds inside the screen image.
+     * @param x the window's x-coordinate in the screen image.
+     * @param y the window's y-coordniate in the screen image.
+     * @param w the window's width in the screen image.
+     * @param h the window's height in the screen image.
+     */
+    public void setWindowBounds (int x,int y,int w,int h)
+    {
+	xcoord = x;
+	ycoord = y;
+	width = w;
+	height = h;
+	makeNewWindow();
+    }
+
+    /**
+     * This method will get which one user wants to send the window or screen image.
+     * @return the flag whether user wants to send window or screen image. 
+     */
+    public boolean getIsWindow()
+    {
+	return windowNow;
+    }
+
+    /**
+     * This method will get the screen image of the screenshot with the line drawn all over it.
+     * @return  this is the screen image with the line drawn all over it.
+     */
+    public BufferedImage getImage()
+    {
+	return bi;
+    }
+
+    /**
+     * This method will get the screen image of the screenshot.
+     * @return  this is the screen image.
+     */
+    public BufferedImage getImage3()
+    {
+	return bi5;
+    }
+
+    /**
+     * This method will get the screen image of only the line that drawn all over the image of
+     * the screenshot.
+     * @return  this is the screen image of only the line.
+     */
+    public BufferedImage getImage2()
+    {
+	return bi2;
+    }
+
+    /**
+     * This method will get the window image of the screenshot with the line drawn all over it.
+     * @return  this is the image with the line drawn all over it.
+     */
+    public BufferedImage getWindowImage()
+    {
+	return bi3;
+    }
+
+    /**
+     * This method will get the window image of the screenshot.
+     * @return  this is the window image.
+     */
+    public BufferedImage getWindowImage3()
+    {
+	return bi6;
+    }
+
+    /**
+     * This method will get the window image of only the line that drawn all over the image of
+     * the screenshot.
+     * @return  this is the window image of only the line.
+     */
+    public BufferedImage getWindowImage2()
+    {
+	return bi4;
+    }
+
+    /**
+     * This method will give the comments user made when they are drawing line over the picture.
+     * @return this is the comment user made.
+     */
+    public String getDetails ()
+    {
+	return details;
+    }
+
+    public boolean getSendNow()
+    {
+	return sendNow;
+    }
+
+    /**
+     * This method will make a modal-dialog that will have the image of the screen shot in the label,
+     * allow user to draw a line all over the image and comments it as well. 
+     */
+    public void makeNewWindow()
+    {
+	JDialog f;
+	f = new Selecting(this);
+	f.setLocation(0,0);
+    }
+
+    /**
+     * This class will make a modal-dialog that will have the image of the screen shot in the label,
+     * allow user to draw a line all over the image and comments it as well. 
+     */
+    class Selecting extends JDialog implements ActionListener
+    {
+	/**
+	 * This is the modal-dialog.
+	 */
+	private JDialog frame;
+	
+	/**
+	 * This is the special label that allows user to draw a line all over the icon set in the label.
+	 */
+	private SelectionArea area;
+	
+	/**
+	 * This is the text area where user can enter the comments they want to add.
+	 */
+	private JTextArea problem_details;
+	
+	/**
+	 * This is the owner of this modal-dialog.
+	 */
+	private SelectPicture framework = null;
+	
+	/**
+	 * This is the graphs that will allow to draw the line all over the screen image in the label and getting
+	 * the image of it.
+	 */
+	private Graphs gp;
+
+	/**
+	 * This is the graphs that will allow to draw the line all over the window image in the label and getting
+	 * the image of it.
+	 */
+	private Graphs gp2;
+
+	/**
+	 * This constructor will make  a modal-dialog that will have the image of the screen shot in the label,
+	 * allow user to draw a line all over the image and comments it as well. 
+	 * @param controller this is the owner of the modal-dialog.
+	 */
+	public Selecting(SelectPicture controller)
+	{
+	    Container contentPane;
+   
+	    contentPane = getContentPane();
+
+	    gp = new Graphs(screen);
+	    
+	    window = gp.getWindowVersion(xcoord,ycoord,width,height);
+	  
+	    gp2 = new Graphs(window);
+
+	    buildUI(contentPane);
+	
+	    framework = controller;
+	   
+	    setTitle(messages.getString("Showwhereistheproblem"));
+	    setDefaultLookAndFeelDecorated(true);
+	    setModal(true);
+
+	    frame = this;
+	    addWindowListener(framework);
+	    setBackground(new Color(176,208,176)); 
+	    
+	    setLocation(0,0);
+	  
+	    pack();
+	    setVisible(true);
+	}
+
+	/**
+	 * This method will setup the contentpane of the modal-dialog.It will set the cursor for
+	 * the label to be from the file pen.gif and set the image icon for the label.
+	 * @param content this is the contentPane of the modal-dialog.
+	 */
+	private void buildUI(Container content) 
+	{
+	    final JPanel container;
+	    container = new JPanel();
+	    container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
+	    container.setBackground(new Color(176,208,176));
+	    container.setBorder(new EmptyBorder(5,5,5,5));
+
+	   
+	    ImageIcon image = createImageIcon(windowNow);
+	    area = new SelectionArea(image, this);
+	    area.setBackground(new Color(224,240,224));
+	    area.setBorder(BorderFactory.createCompoundBorder
+			   (BorderFactory.createLineBorder(Color.blue,4),
+			    new EmptyBorder(10,10,10,10)));
+	   
+	    ImageIcon imgicon,imgicon2;
+	    Image img,img2;
+	    imgicon = JarTools.getImage("pen.gif");
+	    img = imgicon.getImage();
+	    img = img.getScaledInstance(24,24,Image.SCALE_SMOOTH);
+	    imgicon2 = JarTools.getImage("eraserpen.gif");
+	    img2 = imgicon2.getImage();
+	    final Cursor cursor;
+	    final Cursor cursor2;
+	    cursor = Toolkit.getDefaultToolkit().createCustomCursor(img,new Point(0,0),"crayon");
+	    cursor2 = Toolkit.getDefaultToolkit().createCustomCursor(img2,new Point(0,0),"eraser");
+	    
+	    area.setCursor(cursor);
+
+	    Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
+	    final JPanel iconarea = new JPanel();
+	    iconarea.setBackground(new Color(176,208,176));
+	    iconarea.add(area);
+	    container.add(iconarea);
+	    
+	    String screen_label;
+	    screen_label = " " + messages.getString("ScreenShotLabel");
+	    JLabel label;
+	    label = new JLabel(screen_label);
+	    label.setBackground(new Color(176,208,176));
+	    container.add(label);
+
+	    JPanel panes;
+	    panes = new JPanel();
+	    panes.setLayout(new GridLayout(0,2));
+	    panes.setBackground(new Color(176,208,176));
+
+	    problem_details = new JTextArea(details);
+	    problem_details.setWrapStyleWord(true);
+	    problem_details.setEditable(true);
+	    problem_details.setBackground(new Color(224,240,224));
+	    JScrollPane scroll;
+	    scroll = new JScrollPane(problem_details);
+	    scroll.setBackground(new Color(176,208,176));
+	    scroll.setPreferredSize(new Dimension(50,100));
+	    scroll.setBorder(BorderFactory.createTitledBorder(
+							      new EmptyBorder(0,0,0,0),
+							      "Screen shot " + 
+							      messages.getString("ProblemDetails")));
+
+	    panes.add(scroll);
+
+	    JPanel pane;
+	    pane = new JPanel();
+	    pane.setLayout(new GridLayout(2,3));
+	    pane.setBackground(new Color(176,208,176));
+	    pane.setBorder(new EmptyBorder(15,15,15,15));
+
+	    if ((window == null) || (screen == null)) {System.out.println("How come!");}
+	    else
+		{
+		    final JButton toggle;
+		    
+		    if (windowNow == false)
+			{
+			    toggle = new JButton("GLI window."); 
+			    toggle.setToolTipText("Showing only GLI window.");
+			}
+		    else
+			{
+			    toggle = new JButton("Whole screen.");
+			    toggle.setToolTipText("Showing whole screen.");
+			}
+		    toggle.setActionCommand("Toggle");
+		    toggle.addActionListener(new ActionListener ()
+			{
+			    public void actionPerformed (ActionEvent e)
+			    {
+				frame.addMouseListener(mouse_blocker_listener);
+				frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+				if (windowNow == true)
+				    {
+					windowNow = false;
+					toggle.setText("GLI window.");
+					toggle.setToolTipText("Showing only GLI window.");
+					window[0] = gp2.getScreenImage();
+					window[1] = gp2.getImage();
+					window[2] = gp2.getImage2();
+					gp.setScreenVersion(window,xcoord,ycoord,width,height);
+					area.setIcon(new ImageIcon(gp.getImage()));
+				    }
+				else
+				    {
+					windowNow = true;
+					toggle.setText("Whole screen.");
+					toggle.setToolTipText("Showing whole screen.");
+					
+					window[0].flush();
+					window[0] = null;
+					window[1].flush();
+					window[1] = null;
+					window[2].flush();
+					window[2] = null;
+					window = null;
+					BufferedImage tmp;
+					gp2.getImage().flush();
+					tmp = gp2.getImage();
+					tmp.flush();
+					tmp = null;
+					gp2.getImage2().flush();
+					tmp = gp2.getImage2();
+					tmp.flush();
+					tmp = null;
+					gp2.flush();
+					gp2 = null;
+					System.gc();
+
+					window = gp.getWindowVersion(xcoord,ycoord,width,height);
+					gp2 = new Graphs(window);
+					area.setIcon(new ImageIcon(gp2.getImage()));
+				    }
+
+				frame.pack();
+				frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+				frame.removeMouseListener(mouse_blocker_listener);	
+			    }
+			});
+		    toggle.setBackground(new Color(176,208,176));
+		    pane.add(toggle);
+		}
+				     
+
+	    JButton pen;
+	    pen = new JButton(JarTools.getImage("penicon.gif"));
+	    pen.setText("Pen");
+	    pen.setPreferredSize(new Dimension(30,20));
+	    pen.setActionCommand("Pen");
+	    pen.setToolTipText("Draw.");
+	    pen.addActionListener(new ActionListener ()
+		{
+		    public void actionPerformed (ActionEvent e)
+		    {
+			area.setCursor(cursor);
+			drawNow = true;
+		    }
+		});
+	    pen.setBackground(new Color(176,208,176));
+	    pane.add(pen);
+
+	    JButton eraser;
+	    eraser = new JButton(JarTools.getImage("eraser.gif"));
+	    eraser.setText("Eraser");
+	    eraser.setActionCommand("Eraser");
+	    eraser.setPreferredSize(new Dimension(30,20));
+	    eraser.setToolTipText("Erase.");
+	    eraser.addActionListener(new ActionListener ()
+		{
+		    public void actionPerformed (ActionEvent e)
+		    {
+			area.setCursor(cursor2);
+			drawNow = false;
+		    }
+		});
+	    eraser.setBackground(new Color(176,208,176));
+	    pane.add(eraser);
+
+	    if ((window == null) || (screen == null)) 
+		{
+		    JLabel empty = new JLabel(" ");
+		    empty.setBackground(new Color(176,208,176));
+		    pane.add(empty);
+		}
+
+	    JButton button;
+	    button = new JButton("Clear Scribble");
+	    button.setActionCommand("Clear");
+	    button.setToolTipText("Clear all the scribble lines.");
+	    button.addActionListener(this);
+	    button.setBackground(new Color(176,208,176));
+	    pane.add(button);
+
+	    JButton button2;
+	    button2 = new JButton("Finish Scribble");
+	    button2.setActionCommand(messages.getString("Send"));
+	    button2.setToolTipText("Back to Feedback form.");
+	    button2.addActionListener(this);
+	    button2.setBackground(new Color(176,208,176));
+	    pane.add(button2);
+
+	    JButton button3;
+	    button3 = new JButton("Send");
+	    button3.setActionCommand("SendNow");
+	    button3.setToolTipText("Finish reporting feedback and send all information now.");
+	    button3.addActionListener(this);
+	    button3.setBackground(new Color(176,208,176));
+	    pane.add(button3);
+
+	    panes.add(pane);
+
+	    container.add(panes);
+	    
+	    panes.setAlignmentX(Component.LEFT_ALIGNMENT);
+	    label.setAlignmentX(Component.LEFT_ALIGNMENT);
+	    iconarea.setAlignmentX(Component.LEFT_ALIGNMENT);
+	   
+	    container.setSize(container.getPreferredSize());
+	    content.add(container);
+	}
+
+	/**
+	 * This method will tell what the program should do when user click the buttons.
+	 * @param e this is the event when user click button.
+	 */
+	public void actionPerformed (ActionEvent e)
+	{
+	    if(messages.getString("Send").equals(e.getActionCommand()))
+		{
+		    frame.addMouseListener(mouse_blocker_listener);
+		    frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+		    sendNow = false;
+		    if (windowNow == false)
+			{
+			    window = gp.getWindowVersion(xcoord,ycoord,width,height);
+			}
+		    else
+			{
+			    window[0] = gp2.getScreenImage();
+			    window[1] = gp2.getImage();
+			    window[2] = gp2.getImage2();
+			    gp.setScreenVersion(window,xcoord,ycoord,width,height);
+			}
+ 
+		    bi5 = gp.getScreenImage();
+		    bi = gp.getImage();
+		    bi2 = gp.getImage2();
+		    bi3 = window[1];
+		    bi4 = window[2];
+		    bi6 = window[0];
+
+		    details = problem_details.getText();
+		    frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+		    frame.removeMouseListener(mouse_blocker_listener);	
+		    dispose();
+		}
+	    if ("Clear".equals(e.getActionCommand()))
+		{
+		    if (windowNow == false)
+			{
+			    gp.reset();
+			    area.setIcon(new ImageIcon(gp.getScreenImage()));
+			}
+		    else
+			{
+			    gp2.reset();
+			    area.setIcon(new ImageIcon(gp2.getScreenImage()));
+			}
+		}
+
+	    if ("SendNow".equals(e.getActionCommand()))
+		{
+		    frame.addMouseListener(mouse_blocker_listener);
+		    frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+		    sendNow = true;
+
+		    if (windowNow == false)
+			{
+			    window = gp.getWindowVersion(xcoord,ycoord,width,height);
+			}
+		    else
+			{
+			    window[0] = gp2.getScreenImage();
+			    window[1] = gp2.getImage();
+			    window[2] = gp2.getImage2();
+			    gp.setScreenVersion(window,xcoord,ycoord,width,height);
+			}
+ 
+		    bi5 = gp.getScreenImage();
+		    bi = gp.getImage();
+		    bi2 = gp.getImage2();
+		    bi3 = window[1];
+		    bi4 = window[2];
+		    bi6 = window[0];
+
+		    details = problem_details.getText();
+		    frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+		    frame.removeMouseListener(mouse_blocker_listener);	
+		    dispose();
+		}
+	}
+
+	/**
+	 * This method will create ImageIcon of the buffered image get from the screen shot instance.
+	 * The image is screen shot whole screen size image.
+	 * @return ImageIcon of the screen shot image.
+	 */
+	protected ImageIcon createImageIcon(boolean iswindow)
+	{
+	    if (iswindow == false)
+		{
+		    if (screen[1] == null)
+			return new ImageIcon(screen[0]);
+		    else
+			return new ImageIcon(screen[1]);
+		}
+	    else
+		{
+		    if (window[1] == null)
+			return new ImageIcon(window[0]);
+		    else
+			return new ImageIcon(window[1]);
+		}
+	}
+	
+	/**
+	 * This is the special class, that will allows user to draw a line all over the label when 
+	 * user dragged the mouse inside the area.
+	 */
+      	private class SelectionArea extends JLabel 
+	{
+	    /**
+	     * This is the owner of this label.
+	     */
+	    private Selecting controller;
+	    /**
+	     * This is the x coordinate of the first point.
+	     */
+	    private int x1;
+	    /**
+	     * This is the x coordinate of the second point.
+	     */
+	    private int x2;
+	    /**
+	     * This is the y coordinate of the first point.
+	     */
+	    private int y1;
+	    /**
+	     * This is the y coordinate of the second point.
+	     */
+	    private int y2;
+	    /**
+	     * This is the flag to say that user is over the label of the screen image 
+	     * and they are doing the mouse input from there.
+	     */
+	    private boolean ismouse;
+
+	    /**
+	     * This method will create a label with the specified image 
+	     * icon and it will added with mouse listener that will
+	     * allow user to draw a line all over the image.
+	     * @param image image icon to be added to the label.
+	     * @param controller this is the owner of this label.
+	     */
+	    public SelectionArea(ImageIcon image, Selecting controller) 
+	    {
+		super(image);
+		this.controller = controller;
+		setOpaque(true);
+		
+		MyListener myListener;
+		myListener = new MyListener();
+		addMouseListener(myListener);
+		addMouseMotionListener(myListener);
+	    } 
+	    
+	    /**
+	     * This is the modified mouse listener that will allow user to draw
+	     * a line all over the label while user dragging the mouse.
+	     */
+	    private class MyListener extends MouseInputAdapter 
+	    {
+		/**
+		 * This method will make a red dot in the place where user pressed the mouse.
+		 * @param e the mouse event
+		 */
+		public void mousePressed(MouseEvent e) 
+		{
+		    int x;
+		    x = e.getX();
+		    int y;
+		    y = e.getY();
+		
+		    x2 = x;
+		    y2 = y;
+		    
+		    x1 = x2;
+		    y1 = y2;
+		}
+
+		/**
+		 * This method will make a red line from (x1,y1) to the coordinate where
+		 * the mouse is located now.
+		 * @param e the mouse event.
+		 */
+		public void mouseDragged(MouseEvent e) 
+		{
+		    ismouse = true;
+		    updateSize(e);
+		}
+
+		
+		/**
+		 * This method will make a red line from (x1,y1) to the coordinate where
+		 * the mouse is located now.
+		 * @param e the mouse event.
+		 */
+		public void updateSize(MouseEvent e) 
+		{
+		    int x;
+		    x = e.getX();
+		    int y;
+		    y = e.getY();
+		
+		    x2 = x;
+		    y2 = y;
+	
+		    repaint();    
+		}
+	    }
+	    
+	    /**
+	     * This method will repaint all the component inside the dialog-window.
+	     * It will draw a red line from (x1,y1) to (x2,y2) coordinates and
+	     * updates the value of x1,y1 and the icon for the label. 
+	     * @param g the graphics of this dialog-window.
+	     */
+	    public void paintComponent(Graphics g) 
+	    {
+		super.paintComponent(g);
+
+		if (ismouse == true)
+		    {
+			if (windowNow == false)
+			    {
+				if (drawNow == true)
+				    gp.drawLines(x1,y1,x2,y2);
+				else
+				    gp.eraseLines(x1,y1,x2,y2);
+			    }
+			else
+			    {
+				if (drawNow == true)
+				    gp2.drawLines(x1,y1,x2,y2);
+				else
+				    gp2.eraseLines(x1,y1,x2,y2);
+			    }
+			
+			x1 = x2;
+			y1 = y2;
+
+			if (windowNow == false)
+			    {
+				area.setIcon(new ImageIcon(gp.getImage()));
+			    }
+			else
+			    {
+				area.setIcon(new ImageIcon(gp2.getImage()));
+			    }
+			
+			ismouse = false;
+		    }
+	    }
+	}
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SendHTTP.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SendHTTP.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SendHTTP.java	(revision 10506)
@@ -0,0 +1,421 @@
+package org.greenstone.gatherer.feedback;
+
+import java.util.Properties;
+import java.net.*;
+import java.io.*;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+import javax.swing.*;
+import java.awt.Dimension;
+
+/**
+ * This class will send the 2 jar files to the server using HTTP Post.
+ */
+public class SendHTTP
+{
+    /**
+     * This is variable will hold the arguments provided by user in order to send 
+     */
+    private String[] argument;
+    /**
+     * This variable will hold the resource of the words that is stored in Messages.properties file.
+     * The calling using messages.getString(someString) will caused someString to be translated
+     * into some other string that is hold in that file.usually it will caused it to be translated
+     * to the language that the user use or choose to have as stated in Locale.
+     */
+    private static ResourceBundle msg;
+    /**
+     * This variable will hold the jar file unique code.
+     * For example: Jar123File.jar then file_code = 123
+     */
+    private String file_code;
+    /**
+     * This is the flag that will say whether or not the sending is successful.
+     * If failed = false means its succesful otherwise its failed.
+     */
+    private boolean failed = false;
+
+    /**
+     * Crates instance of SendHTTP
+     */
+    public SendHTTP () {}
+  
+    /**
+     * This method will send 2 files back to the server.
+     * It will also send  the code if the sending is failed then it will give user a message saying whats
+     * the possible error of it, and it will make the jar file changed into
+     * Unsend_Jar123File.jar file.
+     * If the sending is succesful then it will try to send all the other jar files
+     * that were failed to send before.And then it will deletes all the jar files
+     * that are send successfully.
+     * @param args the argument provided to send the email.
+     * @param messages hold the resource of the words that is stored in Messages.properties file.
+     * @param code the code of the email to be send.
+     */
+    public void  sendMail(String[] args,ResourceBundle messages,String code) 
+    {
+	argument = args;
+	msg = messages;
+	file_code = code;
+
+	try
+	    {
+		String BND = "---------------------------7d021a37605f0";
+		String hostURL =  "http://kanuka.cs.waikato.ac.nz:8090/glifeedback/Upload";
+
+		URL mURL = new URL(hostURL+"?name=posting");
+		URLConnection conn = mURL.openConnection();
+		
+		if (conn instanceof HttpURLConnection)
+		    ((HttpURLConnection) conn).setRequestMethod("POST");
+		 
+		conn.setDoInput(true);
+		conn.setDoOutput(true);
+		conn.setUseCaches(false);
+		conn.setDefaultUseCaches(false);
+		conn.setRequestProperty("Accept","*/*");
+		conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BND);
+		conn.setRequestProperty("Connection","Keep-Alive");
+		conn.setRequestProperty("Cache-Control","no-cache");
+
+		DataOutputStream out;
+		out = new DataOutputStream(conn.getOutputStream());
+
+		//--- Sending subject -------
+		String txt;
+		txt = "--" + BND + "\r\n";
+		out.writeBytes(txt);
+
+		txt = "Content-Disposition: form-data; ";
+		out.writeBytes(txt);
+
+		String subject;
+		subject = "Send Feedback" + code;
+		txt = "name=\"" + "Subject" + "\"\r\n"; 
+		out.writeBytes(txt);
+		
+		txt = "\r\n";
+		out.writeBytes(txt);
+
+		txt = subject + "\r\n";
+		out.writeBytes(txt);
+		
+		out.flush();
+
+		//--- Sending text ------
+		txt = "--" + BND + "\r\n";
+		out.writeBytes(txt);
+
+		txt = "Content-Disposition: form-data; ";
+		out.writeBytes(txt);
+
+		String attmnt;
+		attmnt = "We have succesfully received your feedback report.\n" +
+		    "To check what files we have received go to this link: " + hostURL +
+		    "/?name=" + code + "\n" + 
+		    "Please keep referencing to this ID Code for this feedback report.\n" +
+		    "ID Code: " + code;
+
+		txt = "name=\"" + "Text" + "\"\r\n";
+		out.writeBytes(txt);
+		
+		txt = "\r\n";
+		out.writeBytes(txt);
+		
+		txt = attmnt + "\r\n";
+		out.writeBytes(txt);
+
+		out.flush();
+
+		//--------- Sending xml-jar file
+		FileInputStream fis;
+		File f;
+		String name,path;
+		
+		f = new File(args[1]);
+		
+		txt = "--" + BND + "\r\n";
+		out.writeBytes(txt);
+
+		txt = "Content-Disposition: form-data; ";
+		out.writeBytes(txt);
+		
+		name = f.getName();
+		txt = "name=\"" + name + "\"; ";
+		out.writeBytes(txt);
+		
+		path = f.getAbsolutePath();
+		txt = "filename=\"" + path + "\"\r\n";
+		out.writeBytes(txt);
+
+		txt = "Content-Type: aplication/octet-stream\r\n";
+		out.writeBytes(txt);
+
+		txt = "\r\n";
+		out.writeBytes(txt);
+
+		fis = new FileInputStream(f);
+		byte[] data = new byte[1024];		
+		int r = 0;
+		while((r = fis.read(data, 0, data.length)) != -1) 
+		    {			
+			out.write(data, 0, r);		
+		    }
+		fis.close();
+
+		txt = "\r\n";
+		out.writeBytes(txt);
+
+		out.flush();
+
+		//--- Sending parser.jar ----
+		txt = "--" + BND + "\r\n";
+		out.writeBytes(txt);
+		
+		txt = "Content-Disposition: form-data; ";
+		out.writeBytes(txt);
+		
+		f = new File(args[4]);
+		
+		name = f.getName();
+		txt = "name=\"" + name + "\"; ";
+		out.writeBytes(txt);
+		
+		path = f.getAbsolutePath();
+		txt = "filename=\"" + path + "\"\r\n";
+		out.writeBytes(txt);
+
+		txt = "Content-Type: application/octet-stream\r\n";
+		out.writeBytes(txt);
+
+		txt = "\r\n";
+		out.writeBytes(txt);
+
+		fis = new FileInputStream(f);
+	        data = new byte[1024];		
+		r = 0;
+		while((r = fis.read(data, 0, data.length)) != -1) 
+		    {			
+			out.write(data, 0, r);		
+		    }
+		fis.close();
+		
+		txt = "\r\n";
+		out.writeBytes(txt);
+
+		out.flush();
+
+		//----- finished sending -----
+		txt = "--" + BND + "--";
+		out.writeBytes(txt);
+
+		out.flush();
+		out.close();
+
+		//----- getting the response ------
+		BufferedReader reader;
+		reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+		String responseLine;
+		responseLine = null;
+
+		StringBuffer response;
+		response = new StringBuffer();
+		while ((responseLine = reader.readLine()) != null)
+		    response.append(responseLine+"\n");
+
+		reader.close();
+	 
+
+		//------ our application's response to server's response
+		/*if (response.equals("failed"))
+		    {
+			failed = true;
+		
+			JOptionPane.showMessageDialog(null,messages.getString("InternalError")+ "\n" + 
+						      messages.getString("Emaillater"),messages.getString("Error"),
+						      JOptionPane.ERROR_MESSAGE);
+			//Conformation.setFinish(true);
+		    }
+		else if (response.equals("success"))
+		    failed = false;
+		else
+		{*/
+			failed = false;
+			JDialog.setDefaultLookAndFeelDecorated(false);
+			JDialog dlg = new JDialog();
+			JLabel lbl = new JLabel (response.toString());
+			
+			dlg.getContentPane().add(lbl);
+			dlg.pack();
+			dlg.setVisible(true);
+			// }
+
+		//Conformation.setFinish(true);
+	    }
+	catch (MalformedURLException exp) 
+	    {
+		failed = true;
+		
+		JOptionPane.showMessageDialog(null,"malformed URL" + "\n" + 
+					      messages.getString("Emaillater"),messages.getString("Error"),
+					      JOptionPane.ERROR_MESSAGE); 
+		System.out.println("malformed URL"); 
+	    }
+	catch (IOException e) 
+	    { 
+		failed = true;
+		
+		JOptionPane.showMessageDialog(null,messages.getString("InternalError")+ "\n" + 
+					      messages.getString("Emaillater"),messages.getString("Error"),
+					      JOptionPane.ERROR_MESSAGE);e.printStackTrace();
+	    }
+
+	String dirname;
+	dirname = "xmlfeedback/";
+	
+	if (failed == false)
+	    {
+		File f;
+		f = new File(dirname + "Jar" + file_code + "File.jar");
+		f.delete();
+		
+		File file;
+		file = new File(dirname + ".");
+		File[] fileList;
+		fileList = file.listFiles();
+		
+		int y;
+		for (y = 0 ; y < fileList.length ; y++)
+		    {
+			String filename;
+			filename = isRightJarFile(fileList[y]);
+			if (filename != null)
+			    {
+				renameTo(fileList[y],new File(filename));
+				argument[1] = filename;
+				sendMail(argument,msg,getCode(filename));
+			    }
+		    }
+	    }
+	else
+	    {
+		File f2;
+		f2 = new File(dirname + "Jar" + file_code + "File.jar");
+		renameTo(f2,new File(dirname + "Unsend_Jar" + file_code + "File.jar"));
+	    }
+	
+    }
+    
+    /**
+     * This method will rename file.
+     * @param src is the name of the file to be renamed.
+     * @param dest is the desired file name.
+     */
+    private void renameTo (File src, File dest)
+    {
+	if (src.renameTo(dest) == false)
+	    {
+		try
+		    {
+			FileInputStream in;
+			in = new FileInputStream(src);
+			FileOutputStream out;
+			out = new FileOutputStream(dest);
+			int next;
+			
+			while (true)
+			    {
+				next = in.read();
+				if (next == -1)
+				    break;
+				else
+				    out.write((byte) next);
+			    }
+			
+			in.close();
+			out.close();
+		    }
+		catch (IOException exp) {exp.printStackTrace();}
+	    }
+    }
+
+    /**
+     * This method will get the extension of the file.
+     * @param f is the file that we want to get the extension.
+     * @return  the file extension
+     */
+    private String getExtension(File f)
+    {
+	String ext;
+	ext = null;
+	String s;
+	s = f.getName();
+	int i;
+	i = s.lastIndexOf('.');
+	
+	if (i > 0 &&  i < s.length() - 1)
+	    {
+		ext = s.substring(i+1).toLowerCase();
+	    }
+	return ext;
+    }
+    
+    /**
+     * This method will get all the name of the file after "_" if the file its a jar file.
+     * For example Unsend_Jar123File.jar then this method will return Jar123File, otherwise
+     * file with any other format will return null.
+     * @param f is the file that we want to get the name.
+     */
+    private String isRightJarFile(File f)
+    {
+	String ext;
+	ext = null;
+	
+	if (f.isDirectory() == true)
+	    return null;
+	
+	if (getExtension(f).compareTo("jar") == 0)
+	    {
+		String s;
+		s = f.getName();
+		int i;
+		i = s.lastIndexOf("_");
+
+		if (i > 0 &&  i < s.length() - 1)
+		    {
+			ext = s.substring(i+1,s.length());
+		    }
+		else
+		    ext = null;
+		
+		return ext;
+	    }
+	else
+	    return null;
+    }
+    
+    /**
+     * This method will getting the code that inside the Jar filename.
+     * For example Jar123File then this method will return 123. 
+     */
+    private String getCode (String s)
+	{
+	    int i;
+	    i = s.lastIndexOf("Jar");
+	    int j;
+	    j = s.indexOf("File");
+	    String code;
+	    code = s.substring((i+3),j);
+	    return code;
+	}
+}
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SendMail.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SendMail.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SendMail.java	(revision 10506)
@@ -0,0 +1,388 @@
+/** This class is not currently used and therefore will not be compiled by makegli. */
+
+package org.greenstone.gatherer.feedback;
+
+import java.util.Properties;
+import javax.mail.*;
+import javax.mail.internet.*;
+import javax.activation.*;
+import java.io.*;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.text.MessageFormat;
+import javax.swing.*;
+
+/**
+ * This is class will provides the ability to send email that contains 2 attachment file.
+ * The arguments that user need to provide are email address of the recepient,first file
+ * to be attached, SMTP address of sender email address, email adress of the sender and
+ * second file to be attached and the code. It has to be in this order.
+ * Here we will expect the 2 file to be attached were parser.jar and jar file of all the
+ * 6 xml files made in the Reporting Feedback sequence.
+ * <br>The email send will have subject = Send Feedback followed with the code.
+ * <br>The message will be : 
+ * <br>Hereby attached 2 jar files.Please download them at the same place and parser.jar is an executable jar file.
+ * <br>Please keep referencing to this ID Code.
+ * <br>ID Code: code
+ * This email will only can be send to one recepient only.
+ * @author Veronica Liesaputra
+ */
+public class SendMail 
+{
+    /**
+     * This is variable will hold the arguments provided by user in order to send 
+     * 2 attachment files through email.
+     */
+    private String[] argument;
+    /**
+     * This variable will hold the resource of the words that is stored in Messages.properties file.
+     * The calling using messages.getString(someString) will caused someString to be translated
+     * into some other string that is hold in that file.usually it will caused it to be translated
+     * to the language that the user use or choose to have as stated in Locale.
+     */
+    private static ResourceBundle msg;
+    /**
+     * This variable will hold the jar file unique code.
+     * For example: Jar123File.jar then file_code = 123
+     */
+    private String file_code;
+    /**
+     * This is the flag that will say whether or not the sending is successful.
+     * If failed = false means its succesful otherwise its failed.
+     */
+    private boolean failed = false;
+
+    /**
+     * Crates instance of SendMail
+     */
+    public SendMail () {}
+  
+    /**
+     * This method will be send an email with 2 file attachment to a recepient
+     * email address using the to email address and to smpt adress as given in
+     * the arguments. This email will also have the code as specified code. 
+     * If the sending is failed then it will give user a message saying whats
+     * the possible error of it, and it will make the jar file changed into
+     * Unsend_Jar123File.jar file.
+     * If the sending is succesful then it will try to send all the other jar files
+     * that were failed to send before.And then it will deletes all the jar files
+     * that are send successfully.
+     * @param args the argument provided to send the email.
+     * @param messages hold the resource of the words that is stored in Messages.properties file.
+     * @param code the code of the email to be send.
+     */
+    public void  sendMail(String[] args,ResourceBundle messages,String code) 
+    {
+	
+	argument = args;
+	msg = messages;
+	file_code = code;
+
+	if(args.length<5) 
+	    {
+		System.out.println("Args for example:");
+		System.out.println("String[] args = new String(5);");
+		System.out.println("args[0] = " + "recepient@maildomain.com;");
+		System.out.println("args[1] = " + "Jar123.jar;");
+		System.out.println("args[2] = " + "mail.waikato.ac.nz;");
+		System.out.println("args[3] = " + "to@cs.waikato.ac.nz;");
+		System.out.println("args[4] = " + "parser.jar;");
+		return;
+	    }
+	
+	File attachment;
+	attachment =new File(args[1]);
+	
+	if(attachment.isDirectory()) 
+	    {
+		System.out.println("Attachment should not be a directory.\n It should be a file.");
+		return;
+	    }
+	if(!attachment.exists()) 
+	    {
+		System.out.println("Attachment file not found.");
+		return;
+	    }
+	
+	Properties p;
+	p = System.getProperties();
+	
+	p.put("mail.smtp.host",args[2]);
+	
+	Session session;
+	session =Session.getInstance(p);
+	
+	Message mail;
+	mail =new MimeMessage(session);
+	
+	Transport t;
+
+	try 
+	    {
+     
+		Address [] addresses;
+		addresses = new Address[]{new InternetAddress(args[0])};
+	    
+		mail.setFrom(new InternetAddress(args[3]));
+	    
+		mail.setSubject("Send Feedback" + code);
+	    
+		MimeBodyPart part1;
+		part1 =new MimeBodyPart();
+		String attmnt;
+		attmnt = "Hereby attached 2 jar files.Please download them at the same place and parser.jar " +
+		    "is an executable jar file.\n" + "Please keep referencing to this ID Code.\n" +
+		    "ID Code:";
+		part1.setText(attmnt+" " + code);
+			
+		MimeBodyPart part2;
+		part2 =new MimeBodyPart();				
+		FileDataSource source;
+		source =new FileDataSource(args[1]);
+		part2.setDataHandler(new DataHandler(source));
+		part2.setFileName(source.getName());
+	    
+		MimeBodyPart part3;
+		part3 = new MimeBodyPart();
+		FileDataSource source2;
+		source2 = new FileDataSource(args[4]);
+		part3.setDataHandler(new DataHandler(source2));
+		part3.setFileName(source2.getName());
+
+		Multipart part;
+		part =new MimeMultipart();
+	    
+		part.addBodyPart(part1);
+		part.addBodyPart(part2);
+		part.addBodyPart(part3);
+	    
+		mail.setContent(part);	
+	    
+		t = session.getTransport(addresses[0]);
+	    
+		t.addTransportListener(new javax.mail.event.TransportAdapter()
+		    {
+			public void messageNotDelivered(javax.mail.event.TransportEvent te) 
+			{
+			    Address a[];
+			    a =te.getInvalidAddresses();
+			    failed = true;
+			    System.out.println("Message not delivered for the following addresses:");
+			    int i;
+			    for(i=0;i<a.length;i++)
+				{
+				    System.out.println(a[i]);
+				}
+			}
+		    });
+		
+		t.connect();
+	  
+	   
+		t.sendMessage(mail,addresses);
+	    
+		
+		t.close();
+		
+	    }
+	catch (NoSuchProviderException e) 
+	    {
+		failed = true;
+		System.out.println("Provider not found.");
+		String s;
+		s = (String)JOptionPane.showInputDialog(messages.getString("NotFoundProvider"));
+		
+		if ((s != null) && (s.length() > 0))
+		    {
+			argument[2] = s;
+			
+			String s2;
+			s2 = (String)JOptionPane.showInputDialog(messages.getString("NotFoundProvider2"));
+			
+			if ((s2 != null) && (s2.length() > 0))
+			    argument[3] = s2;
+
+			sendMail(argument,msg,file_code);
+			//Conformation.setFinish(true);
+			return;
+		    }
+		else
+		    JOptionPane.showMessageDialog(null,messages.getString("Emaillater"),messages.getString("Error"),
+						  JOptionPane.INFORMATION_MESSAGE);
+		
+	    }
+	catch (SendFailedException nspe) 
+	    {
+		failed = true;
+		int ans;
+		ans = JOptionPane.showConfirmDialog(null,messages.getString("SendFailed"),
+							messages.getString("Error"),JOptionPane.YES_NO_OPTION,
+							JOptionPane.INFORMATION_MESSAGE);
+		if (ans == JOptionPane.YES_OPTION)
+		    {
+			sendMail(argument,msg,file_code);
+			//Conformation.setFinish(true);
+			return;
+		    }
+		else
+		    JOptionPane.showMessageDialog(null,messages.getString("Emaillater"),messages.getString("Error"),
+						  JOptionPane.INFORMATION_MESSAGE);
+	    }
+	catch (Exception nspe) 
+	    {
+		failed = true;
+		JOptionPane.showMessageDialog(null,messages.getString("InternalError")+ "\n" + 
+					      messages.getString("Emaillater"),messages.getString("Error"),
+					      JOptionPane.ERROR_MESSAGE);
+		//Conformation.setFinish(true);
+	    }
+
+	String dirname;
+	dirname = "xmlfeedback/";
+
+	if (failed == false)
+	    {
+		File f;
+		f = new File(dirname + "Jar" + file_code + "File.jar");
+		f.delete();
+
+		File file;
+		file = new File(dirname + ".");
+		File[] fileList;
+		fileList = file.listFiles();
+		
+		int y;
+		for (y = 0 ; y < fileList.length ; y++)
+		    {
+			String filename;
+			filename = isRightJarFile(fileList[y]);
+			if (filename != null)
+			    {
+				renameTo(fileList[y],new File(filename));
+				argument[1] = filename;
+				sendMail(argument,msg,getCode(filename));
+			    }
+		    }
+	    }
+	else
+	    {
+		File f2;
+		f2 = new File(dirname + "Jar" + file_code + "File.jar");
+		renameTo(f2,new File(dirname + "Unsend_Jar" + file_code + "File.jar"));
+	    }
+
+	//Conformation.setFinish(true);
+    }
+
+    /**
+     * This method will rename file.
+     * @param src is the name of the file to be renamed.
+     * @param dest is the desired file name.
+     */
+    private void renameTo (File src, File dest)
+    {
+	if (src.renameTo(dest) == false)
+	    {
+		try
+		    {
+			FileInputStream in;
+			in = new FileInputStream(src);
+			FileOutputStream out;
+			out = new FileOutputStream(dest);
+			int next;
+			
+			while (true)
+			    {
+				next = in.read();
+				if (next == -1)
+				    break;
+				else
+				    out.write((byte) next);
+			    }
+			
+			in.close();
+			out.close();
+		    }
+		catch (IOException exp) {exp.printStackTrace();}
+	    }
+    }
+
+    /**
+     * This method will get the extension of the file.
+     * @param f is the file that we want to get the extension.
+     * @return  the file extension
+     */
+    private String getExtension(File f)
+    {
+	String ext;
+	ext = null;
+	String s;
+	s = f.getName();
+	int i;
+	i = s.lastIndexOf('.');
+	
+	if (i > 0 &&  i < s.length() - 1)
+	    {
+		ext = s.substring(i+1).toLowerCase();
+	    }
+	return ext;
+    }
+    
+    /**
+     * This method will get all the name of the file after "_" if the file its a jar file.
+     * For example Unsend_Jar123File.jar then this method will return Jar123File, otherwise
+     * file with any other format will return null.
+     * @param f is the file that we want to get the name.
+     */
+    private String isRightJarFile(File f)
+    {
+	String ext;
+	ext = null;
+	
+	if (f.isDirectory() == true)
+	    return null;
+	
+	if (getExtension(f).compareTo("jar") == 0)
+	    {
+		String s;
+		s = f.getName();
+		int i;
+		i = s.lastIndexOf("_");
+
+		if (i > 0 &&  i < s.length() - 1)
+		    {
+			ext = s.substring(i+1,s.length());
+		    }
+		else
+		    ext = null;
+		
+		return ext;
+	    }
+	else
+	    return null;
+    }
+    
+    /**
+     * This method will getting the code that inside the Jar filename.
+     * For example Jar123File then this method will return 123. 
+     */
+    private String getCode (String s)
+	{
+	    int i;
+	    i = s.lastIndexOf("Jar");
+	    int j;
+	    j = s.indexOf("File");
+	    String code;
+	    code = s.substring((i+3),j);
+	    return code;
+	}
+}
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SeparateGraphs.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SeparateGraphs.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/SeparateGraphs.java	(revision 10506)
@@ -0,0 +1,105 @@
+/** This class is not currently used and therefore will not be compiled by makegli. */
+
+package org.greenstone.gatherer.feedback;
+
+import java.io.*;
+import javax.imageio.*;
+import java.awt.*;
+import java.awt.image.*;
+import com.sun.image.codec.jpeg.*;
+import javax.swing.*;
+
+/**
+ * This class will separate a image file into 2 jpeg image files by taking
+ * all the point in that image file that has the color red and save all that
+ * points to another image file, while all the other point to another image
+ * file.
+ * @author Veronica Liesaputra
+ */
+public class SeparateGraphs
+{
+    /**
+     * This is the BufferedImage that we want to separate.
+     */
+    private BufferedImage bi;
+
+    /**
+     * This constructor will save the image inside the file with the specified 
+     * filename to the BufferedImage.
+     */
+    public SeparateGraphs(String filename)
+    {
+	try
+	    {
+		File f = new File(filename);
+		bi = ImageIO.read(f);
+	    }
+	catch(IOException exp) {}
+    }
+
+    /**
+     * This method will separate bi into 2 image and save it to
+     * jpeg files with the specified filename.
+     * The 2 image separated will be, 1 image is the image of all the points in bi that
+     * have the color red and another image is the image of all other points in bi that
+     * do not have the color red.
+     * @param file1 this is the filename for the image of all other points that do not have color red.
+     * @param file2 this is the filename for the image of all points that have the color red.
+     */
+    public void separate(String file1,String file2)
+    {
+	BufferedImage bi1,bi2;
+	
+	int width = bi.getWidth();
+	int height = bi.getHeight();
+	
+	bi1 = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
+	bi2 = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
+
+	for (int y = 0 ; y < height ; y++) 
+	    {
+		for (int x = 0 ; x < width ; x++)
+		    {
+			int rgb = bi.getRGB(x,y);
+			Color c = new Color(rgb,true);
+			if (c != Color.RED)
+			    {
+				bi1.setRGB(x,y,rgb);
+			    }
+			else
+			    {
+				bi2.setRGB(x,y,rgb);
+			    }
+		    }
+	    }
+
+	save(bi1,file1);
+	save(bi2,file2);
+    }
+
+    /**
+     * This method will save the BufferedImage into a jpeg file with the specified filenames.
+     * @param b is the BufferedImage to be saved.
+     * @param filename is the name of the jpeg files.
+     */
+    public void save(BufferedImage b,String filename)
+    {
+	try 
+	    {
+		File file = new File(filename);
+		FileOutputStream out = new FileOutputStream(file);
+	    
+		JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
+		JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(b);
+		param.setQuality(1.0f, false);
+		encoder.setJPEGEncodeParam(param);
+		encoder.encode(b);
+		
+	    } catch (Exception ex) {}
+    }
+}
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Separating.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Separating.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/Separating.java	(revision 10506)
@@ -0,0 +1,108 @@
+/** This class is not currently used and therefore will not be compiled by makegli. */
+
+package org.greenstone.gatherer.feedback;
+
+import java.io.*;
+import javax.imageio.*;
+import java.awt.*;
+import java.awt.image.*;
+import com.sun.image.codec.jpeg.*;
+import javax.swing.*;
+
+/**
+ * This method will separate 1 image file into 2 image  with the help of
+ * another file and sace the difference into a jpeg files.
+ * For example : We have 1 image file which is a screen shot and another image file
+ *               is the screenshot with some line in it.
+ *               This class will separate the screen shot and the line into 2 separates 
+ *               images.And then it will save the line into a jpeg files.
+ * 
+ * @author Veronica Liesaputra
+ */
+public class Separating
+{
+    /**
+     * This is the BufferedImage of image inside the reference image file.
+     */
+    private BufferedImage bi;
+    /**
+     * This is the BufferedImage of image that we want to separate into
+     * 2 different image using the reference file.
+     */
+    private BufferedImage src_bi;
+
+    /**
+     * It will read whats inside the 2 given filenames and put it in the
+     * right BufferedImage.
+     * @param filename1 this is the file name of the reference image file.
+     * @param filename2 this is the file name of the file we want to separate into 2.
+     */
+    public Separating(String filename1,String filename2)
+    {
+	try
+	    {
+		File f1 = new File(filename1);
+		File f2 = new File(filename2);
+		bi = ImageIO.read(f1);
+		src_bi = ImageIO.read(f2);
+	    }
+	catch(IOException exp) {}
+    }
+
+    /**
+     * This method will get the difference that exist between bi and src_bi and
+     * will save the difference inside a jpeg file with the specified file name.
+     * @param file1 is the name of the file where we want to save the image.
+     */
+    public void separate(String file1)
+    {
+	BufferedImage bi1;
+	
+	int width = bi.getWidth();
+	int height = bi.getHeight();
+	
+	bi1 = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
+
+	for (int y = 0 ; y < height ; y++) 
+	    {
+		for (int x = 0 ; x < width ; x++)
+		    {
+			int rgb = bi.getRGB(x,y);
+			int src_rgb = src_bi.getRGB(x,y);
+			
+			if (src_rgb != rgb)
+			    {
+				bi1.setRGB(x,y,rgb);
+			    }
+		    }
+	    }
+
+	save(bi1,file1);
+    }
+
+    /**
+     * This method will save a BufferedImage to a jpeg file with the specified filename.
+     * @param b is the BufferedImage to be saved.
+     * @param filename is the name of the jpeg file.
+     */
+    public void save(BufferedImage b,String filename)
+    {
+	try 
+	    {
+		File file = new File(filename);
+		FileOutputStream out = new FileOutputStream(file);
+	    
+		JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
+		JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(b);
+		param.setQuality(1.0f, false);
+		encoder.setJPEGEncodeParam(param);
+		encoder.encode(b);
+		
+	    } catch (Exception ex) {}
+    }
+}
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/UserComponent.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/UserComponent.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/UserComponent.java	(revision 10506)
@@ -0,0 +1,439 @@
+package org.greenstone.gatherer.feedback;
+
+import java.util.*;
+import java.awt.image.*;
+import java.io.*;
+import javax.imageio.*;
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * This class willl hold the information about a component and the contents inside the component.
+ * @author Veronica Liesaputra
+ */
+public class UserComponent implements Serializable
+{
+    /**
+     * This variable will hold what is the type of instance this component is.
+     */
+    private String type = null;
+
+    /**
+     * This variable will store the title of this component.
+     */
+    private String title = null;
+
+    /**
+     * This varaible will store the array list of the contents of this component.
+     */
+    private ArrayList content = null;
+
+    /**
+     * This variable will store the status of this component, whether or not
+     * this component is selected by the user.
+     */
+    private String selected = null;
+
+    /**
+     * This variable will store the status of this component, whether or not
+     * this component is visible.
+     */
+    private String visible = null;
+
+    /**
+     * This variable will hold the descrption text saying that there is no
+     * image in this component.
+     */
+    private String image = null;
+
+    /**
+     * This is the supposed filename of the image that is in this component should use if 
+     * we want to save it to a jpeg file.
+     */
+    private String img = null;
+
+    /**
+     * This is the string representation of the image that is in this component.
+     */
+    private String imgFile = null;
+
+    /**
+     * This is the index that will help storing the data to the correct data member.
+     */
+    private int index;
+
+    /**
+     * This is the height of the image that is in this component.
+     */
+    private String height;
+
+    /**
+     * This is the width of the image that is in this component.
+     */
+    private String width;
+
+    /**
+     * This variable will hold the tooltiptext set for this component.
+     */
+    private String tooltip;
+
+    /**
+     * This will initialized content to a new empty Arrray list.
+     */
+    public UserComponent()
+    {
+	content = new ArrayList();
+    }
+
+    /**
+     * This method will get the width of the image that is inside this component.
+     * @return image's width.
+     */
+    public String getWidth()
+    {
+	return width;
+    }
+
+    /**
+     * This method will get the height of the image that is inside this component.
+     * @return image's height.
+     */
+    public String getHeight()
+    {
+	return height;
+    }
+
+    /**
+     * This method will get the type of instance this component is.
+     * @return component's type.
+     */
+    public String getType()
+    {
+	return type;
+    }
+
+    /**
+     * This method will get the tooltiptext set for this component.
+     * @return component's tooltiptext.
+     */
+    public String getToolTip()
+    {
+	return tooltip;
+    }
+
+    /**
+     * This method will get the title for this component.
+     * @return component's title.
+     */
+    public String getTitle()
+    {
+	return title;
+    }
+
+    /**
+     * This method will get the content inside this component.
+     * @return component's content.
+     */
+    public ArrayList getContent()
+    {
+	return content;
+    }
+
+    /**
+     * This method will get whether or not this component is 
+     * selected by the user.
+     * @return component selected or not.
+     */
+    public String getSelected()
+    {
+	return selected;
+    }
+
+    /**
+     * This method will get whether or not this component is 
+     * visible.
+     * @return component visible or not.
+     */
+    public String getVisible()
+    {
+	return visible;
+    }
+
+    /**
+     * This method will get the descrption text saying that there is no
+     * image in this component.
+     * @return the description text.
+     */
+    public String getImage()
+    {
+	return image;
+    }
+
+    /**
+     * This method will get the supposed filename of the image that is in this component should use if 
+     * we want to save it to a jpeg file.
+     * @return the image file name.
+     */
+    public String getImageFileName()
+    {
+	return img;
+    }
+
+    /**
+     * This method will get the string representation of the image that is in this component.
+     * @return the image.
+     */
+    public String getImageFile()
+    {
+	return imgFile;
+    }
+
+    /**
+     * This method will set the index value.
+     * (Precondition: (num > 0))
+     * @param num the new index value.
+     */
+    public void startContent (int num)
+    {
+	index = num;
+    }
+    
+    /**
+     * This method will add the UserComponent to the content array list.
+     * @param comp the content of the component.
+     */
+    public void saveContent (UserComponent comp)
+    {
+	content.add(comp);
+    }
+
+    /**
+     * This method will set the data member value to the text passed
+     * to this method depending on the index value.
+     * @param text the value to be set to the data member.
+     */
+    public void saveContent (String text)
+    {
+	if (text == null)
+	    text = " ";
+
+	switch (index)
+	    {
+	    case 1 : type = text; break;
+	    case 2 : title = text; break;
+	    case 3 : content.add(text); break;
+	    case 4 : selected = text;break;
+            case 5 : visible = text;break;
+	    case 6 : image = text; break;
+	    case 7 : tooltip = text;break;
+            }
+    }
+
+    /**
+     * This method will encode the ImageIcon into its String representation using Based64encoder and
+     * it will also set the image's filename,height and width.
+     * @param image is the image to be converted.
+     * @param filename is the file name of the image.
+     */
+    public void saveImage (ImageIcon image,String filename) 
+    {
+	/*int w;
+	w = image.getIconWidth();
+	int h;
+	h = image.getIconHeight();
+
+	height = "" + h;
+	width = "" + w;
+	img = filename;
+	
+	if (w > 50)
+	    w = w - 50;
+	
+	if (h > 50)
+	    h = h - 50;
+	
+	ImageIcon icon;
+	icon = new ImageIcon(image.getImage().getScaledInstance(w,h,Image.SCALE_SMOOTH));
+   
+	if ( w < 0 || h < 0)
+	    {
+		System.out.println(img);
+		return;
+	    }
+
+	BufferedImage bi;
+	bi =new BufferedImage(w,h, BufferedImage.TYPE_INT_RGB);
+	Graphics2D big;
+	big = bi.createGraphics();
+	
+	big.drawImage(icon.getImage(),0,0,null);
+	
+	try	
+	    {
+		ByteArrayOutputStream stream;
+		stream = new ByteArrayOutputStream();
+		ImageIO.write(bi,"jpeg",stream);
+		byte[] bytes;
+		bytes = stream.toByteArray();
+		imgFile = Base64.encodeBytes(bytes);
+	    }
+	catch (IOException exp) {}
+	
+	big.dispose();
+	image = null;
+	bi = null;
+	icon = null;*/
+    }
+
+    /**
+     * This method will encode the Icon into its String representation using Based64encoder and
+     * it will also set the image's filename,height and width.
+     * @param image is the image to be converted.
+     * @param filename is the file name of the image
+     */
+    public void saveImage (Icon image,String filename)
+    {
+	if (image == null)
+	    System.out.println("null image??");
+	else if (image instanceof ImageIcon)
+	    saveImage((ImageIcon)image, filename);
+	else
+	    System.out.println("Its a icon");
+	    //saveIcon (image,filename);
+    }
+
+    /**
+     * This method will encode the Icon into its String representation using Based64encoder and
+     * it will also set the image's filename,height and width.
+     * @param image is the image to be converted.
+     * @param filename is the file name of the image.
+     */
+    private void saveIcon (Icon image,String filename)
+    {
+	JFrame lbl = new JFrame();
+	lbl.setVisible(false);
+
+	ImageIcon icon;
+	Image img;
+	img = iconToImage(image,lbl);
+	icon = new ImageIcon(img);
+	lbl.dispose();
+	lbl = null;
+	saveImage(icon,filename);
+    }
+
+    /**
+     * This method will save to content of this UserComponent to an xml file.
+     * The xml file should already have an opening tag and closing tag first before calling
+     * this method or it wont make a valid xml file.
+     * @param sx this is the xml file where we want to save it.
+     */
+    public void sendingXML (SaveToXML sx)
+    {
+	if (type != null)
+	    {
+		sx.startContent(1);
+		sx.saveContent(type);
+		sx.closeContent(1);
+	    }
+
+	if (title != null)
+	    {
+		sx.startContent(2);
+		sx.saveContent(title);
+		sx.closeContent(2);
+	    }
+
+	if (content != null)
+	    {
+		sx.startContent(3);
+		for (int j = 0 ; j < content.size() ; j++)
+		    {
+			if (content.get(j) instanceof String)
+			    sx.saveContent((String) content.get(j));
+			else
+			    {
+				sx.startContent(0);
+				UserComponent cmp;
+				cmp = (UserComponent) content.get(j);
+				cmp.sendingXML(sx);
+				sx.closeContent(0);
+			    }
+		    }
+		sx.closeContent(3);
+	    }
+
+	if (selected != null)
+	    {
+		sx.startContent(4);
+		sx.saveContent(selected);
+		sx.closeContent(4);
+	    }
+
+	if (visible != null)
+	    {
+		sx.startContent(5);
+		sx.saveContent(visible);
+		sx.closeContent(5);
+	    }
+
+	if (img != null)
+	    {
+		sx.startContent(6);
+		sx.saveImage(imgFile,img,width,height);
+		sx.closeContent(6);
+	    }
+	else
+	    {
+		if (image != null)
+		    {
+			sx.startContent(11);
+			sx.saveContent(image);
+			sx.closeContent(11);
+		    }
+	    }
+
+	if (tooltip != null)
+	    {
+		sx.startContent(12);
+		sx.saveContent(tooltip);
+		sx.closeContent(12);
+	    }
+    }
+
+    /**
+     * This method will convert an Icon to a BufferedImage.
+     * @param icon icon to be converted.
+     * @param targetComponent is the component where we want to draw this BufferedImage.
+     * @return is the BufferedImage of the icon.
+     */
+    public BufferedImage iconToImage(Icon icon, Component targetComponent) 
+    {
+	int w,h;
+	w = icon.getIconWidth();
+	h = icon.getIconHeight();
+	GraphicsConfiguration gc;
+	gc = targetComponent.getGraphicsConfiguration();
+	BufferedImage image;
+	image = gc.createCompatibleImage(w, h,Transparency.TRANSLUCENT);
+	
+	Graphics2D g;
+	g = image.createGraphics();
+	icon.paintIcon(targetComponent,g,0,0);
+	g.dispose();
+	return image;
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ZipFile.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ZipFile.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/feedback/ZipFile.java	(revision 10506)
@@ -0,0 +1,266 @@
+package org.greenstone.gatherer.feedback;
+
+import java.io.*;
+import java.util.jar.*;
+import java.util.zip.*;
+
+/**
+ * This class will help to zip and unzip files.
+ * @author Veronica Liesaputra
+ */
+public class ZipFile 
+{
+    /**
+     * This is the specified buffer size.
+     */
+    private static final int BUFFER = 2048;
+    
+    public ZipFile ()
+    {}
+
+    /**
+     * This method will unzip the MyZipFile.zip file and delete the file.
+     */
+    public void unZipFile ()
+    {
+	try
+	    {
+		BufferedOutputStream dest;
+		dest = null;
+		FileInputStream fis;
+		fis = new FileInputStream("MyZipFile.zip");
+		ZipInputStream zis;
+		zis = new ZipInputStream(new BufferedInputStream(fis));
+		ZipEntry entry;
+		while((entry = zis.getNextEntry()) != null) 
+		    {
+			int count;
+			byte data[];
+			data = new byte[BUFFER];
+			// write the files to the disk
+			File f;
+			f = new File(entry.getName());
+			if (isRightLogExtension(f) == true)
+			    {
+				FileOutputStream fos;
+				fos = new FileOutputStream(entry.getName());
+				dest = new BufferedOutputStream(fos, BUFFER);
+				while ((count = zis.read(data, 0, BUFFER)) != -1) 
+				    {
+					dest.write(data, 0, count);
+				    }
+				dest.flush();
+				dest.close();
+			    }
+		    }
+		zis.close();
+		File f3;
+		f3 = new File("MyZipFile.zip");
+		f3.delete();
+	    } 
+	catch (FileNotFoundException fexp) {}
+	catch(Exception e) 
+	    {
+		e.printStackTrace();
+	    }
+    } 
+
+    /**
+     * This method will zip all the xml files into one Jar file.
+     */
+    public void sendZipXMLFile ()
+     {
+	try 
+	    {
+		String dirname;
+		dirname = "xmlfeedback/";
+		BufferedInputStream origin;
+		origin = null;
+		FileOutputStream dest;
+		dest = new FileOutputStream(dirname + "Jar" + 
+					    FeedbackInterface.getCode() + 
+					    "File.jar");
+		JarOutputStream out;
+		out = new JarOutputStream(new BufferedOutputStream(dest));
+		out.setMethod(ZipOutputStream.DEFLATED);
+		byte data[];
+		data = new byte[BUFFER];
+		
+		File f;
+		f = new File(dirname + ".");
+		File[] fileList;
+		fileList = f.listFiles();
+		File[] files;
+		files = new File[fileList.length + 8];
+		
+		int index,j,i;
+		index = 0;
+		for (j = 0 ; j < fileList.length ; j++)
+		    {
+			String name;
+			name = fileList[j].getName();
+			
+			if (isRightXMLExtension(fileList[j]) == true)
+			    {
+				files[index] = fileList[j];
+				index++;
+			    }
+		    }
+		
+		for ( i = 0; i < index; i++) 
+		    {
+			FileInputStream fi;
+			fi = new FileInputStream(files[i]);
+			origin = new BufferedInputStream(fi, BUFFER);
+			ZipEntry entry;
+			entry = new ZipEntry(files[i].getName());
+			out.putNextEntry(entry);
+			int count;
+			while((count = origin.read(data, 0,BUFFER)) != -1) 
+			    {
+				out.write(data, 0, count);
+			    }
+			origin.close();
+		    }	
+
+		out.close();
+	    } 
+	catch(Exception e) 
+	    {
+		e.printStackTrace();
+	    }
+    }
+
+    /**
+     * This method will zip all .log file to MyZipFile.zip file and it will
+     * delete the history.log file.
+     */
+    public void sendZipFile ()
+    {
+	try 
+	    {
+		BufferedInputStream origin;
+		origin = null;
+		FileOutputStream dest;
+		dest = new FileOutputStream("MyZipFile.zip");
+		ZipOutputStream out;
+		out = new ZipOutputStream(new BufferedOutputStream(dest));
+		out.setMethod(ZipOutputStream.DEFLATED);
+		byte data[];
+		data = new byte[BUFFER];
+		
+		File f;
+		f = new File(".");
+		File[] fileList;
+		fileList = f.listFiles();
+		File[] files;
+		files = new File[fileList.length];
+		
+		int index,i,j;
+		index = 0;
+		for ( j = 0 ; j < fileList.length ; j++)
+		    {
+			if (isRightLogExtension(fileList[j]) == true)
+			    {
+				files[index] = fileList[j];
+				index++;
+			    }
+		    }
+		
+		for (i = 0; i < index; i++) 
+		    {
+			FileInputStream fi;
+			fi = new FileInputStream(files[i]);
+			origin = new BufferedInputStream(fi, BUFFER);
+			ZipEntry entry;
+			entry = new ZipEntry(files[i].getName());
+			out.putNextEntry(entry);
+			int count;
+			while((count = origin.read(data, 0,BUFFER)) != -1) 
+			    {
+				out.write(data, 0, count);
+			    }
+			origin.close();
+		    }
+		out.close();
+		File f2;
+		f2 = new File("history.log");
+		f2.delete();
+	    } 
+	catch(Exception e) 
+	    {
+		e.printStackTrace();
+	    }
+    }
+    
+    /**
+     * This method will get the extension of the given file.
+     * @param f the file we want to know the extension.
+     * @return  the file extension.
+     */
+    public String getExtension(File f)
+    {
+        String ext;
+	ext = null;
+        String s;
+	s = f.getName();
+        int i;
+	i = s.lastIndexOf('.');
+	
+        if (i > 0 &&  i < s.length() - 1)
+	    {
+		ext = s.substring(i+1).toLowerCase();
+	    }
+        return ext;
+    }
+   
+    /**
+     * This method will check whether or not the give file has
+     * an .xml extension.
+     * @param f the file we want to check the extension.
+     * @return  whether or not the file has xml as its file extension.
+     */
+    public boolean isRightXMLExtension(File f)
+    {
+	if (f.isDirectory() == true)
+	    {
+		return false;
+	    }
+	String ext;
+	ext = getExtension(f);
+	if ((ext != null) && (ext.compareTo("xml") == 0))
+	    return true;
+	else
+	    return false;
+    }
+
+    /**
+     * This method will check whether or not the give file has
+     * an .log extension.
+     * @param f the file we want to check the extension.
+     * @return  whether or not the file has log as its file extension.
+     */
+    public boolean isRightLogExtension(File f)
+    {
+	if (f.isDirectory() == true)
+	    return false;
+	
+	String ext;
+	ext = getExtension(f);
+	
+	if ((ext != null) && (ext.compareTo("log") == 0))
+	    return true;
+	else
+	    return false;
+    }
+}
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileAlreadyExistsException.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileAlreadyExistsException.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileAlreadyExistsException.java	(revision 10506)
@@ -0,0 +1,11 @@
+package org.greenstone.gatherer.file;
+
+import java.lang.Exception;
+
+public class FileAlreadyExistsException
+    extends Exception {
+
+    public FileAlreadyExistsException() {
+	super();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileAssociationManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileAssociationManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileAssociationManager.java	(revision 10506)
@@ -0,0 +1,333 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.file;
+
+import java.io.*;
+import java.util.regex.*;
+import javax.swing.table.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.gui.FileAssociationDialog;
+import org.greenstone.gatherer.gui.PreviewCommandDialog;
+import org.greenstone.gatherer.util.ExternalProgram;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+public class FileAssociationManager 
+    extends AbstractTableModel {
+    static final public String FILENAME_ARG = "%1";
+    static final private String ESCAPE = "\\\\"; // '\'
+    static final private String ESCAPED_ESCAPE = "\\\\\\\\"; // '\\'
+    static final private String SPACE = " ";
+    static final private String ESCAPED_SPACE = "\\\\ ";
+    private Element associations_element;
+    private File data_file;   
+
+    public FileAssociationManager() {
+	// Retrieve the associations_element from the config
+	associations_element = Configuration.getFileAssociations();
+	// Initialize the associations. This involves looking through all current associations searching for those with a command of "".
+	if(associations_element != null) {
+	    NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
+	    for(int i = 0; i < entries.getLength(); i++) {
+		Element entry = (Element) entries.item(i);
+		String command = XMLTools.getValue(entry);
+		// If we encounter a command of ""...
+		if(command.length() == 0) {
+		    // if we are on windows, we default to the start command
+		    if(Utility.isWindows()) {
+			if (Utility.isWindows9x()) {
+			    XMLTools.setValue(entry, StaticStrings.WIN_9X_OPEN_COMMAND);
+			} else {
+			    XMLTools.setValue(entry, StaticStrings.WIN_OPEN_COMMAND);
+			}
+		    }
+		    // and if we are on mac, we default to the open program
+		    else if(Utility.isMac()) {
+			XMLTools.setValue(entry, StaticStrings.MAC_OPEN_COMMAND);
+		    }
+		}
+		command = null;
+		entry = null;
+	    }
+	    entries = null;
+	}
+	else {
+	    DebugStream.println("Didn't parse anything. About to crash.");
+	}
+    }
+    
+    public void edit() {
+	FileAssociationDialog dialog = new FileAssociationDialog(this);
+	dialog.display(null);
+	dialog = null;		  
+    }
+
+    public String getBrowserCommand(String url) {
+	DebugStream.println("Get browser command: " + url);
+	// First off we try to retrieve one from the configuration
+	String command = Configuration.getPreviewCommand();
+	// If that worked, substitute in the url and return
+	if(command != null && command.length() > 0) {
+	    command = command.replaceAll("%1", url);
+	    DebugStream.println("Result = " + command);
+	    return command;
+	}
+	command = null;
+	// Failing that we have a guess at a sensible default 
+	if(Utility.isWindows()) {
+	    // we use cmd and start
+	    if (Utility.isWindows9x()) {
+		command = StaticStrings.WIN_9X_OPEN_COMMAND;//"command.com /c start \""+url+"\"";
+	    } else {
+		command = StaticStrings.WIN_OPEN_COMMAND;//"cmd.exe /c start \"\" \""+url+"\"";
+	    }
+	} else if (Utility.isMac()) {
+	    command = StaticStrings.MAC_OPEN_COMMAND; // "open %1"
+	} else {
+	    // we try to look for a browser
+	    String [] browsers = new String [] {"mozilla", "netscape"};
+	    for (int i=0; i<browsers.length; i++) {
+		if (isAvailable(browsers[i])) {
+		    command = browsers[i]+ " %1";
+		    break;
+		}
+	    }
+	}
+
+	// if we still haven't found something, prompt the user
+	if (command == null) {
+	    PreviewCommandDialog dialog = new PreviewCommandDialog();
+	    command = dialog.display();
+	    dialog.dispose();
+	    dialog = null;
+	}
+
+	// Store the result if any
+	if(command != null && !command.equals("")) {
+	    Configuration.setPreviewCommand(command);
+	    command = command.replaceAll(FILENAME_ARG, url);
+	    DebugStream.println("Result = " + command);
+	    return command;
+	}
+	// if we haven't got a command by now, we'll never get one
+	DebugStream.println("Result = null");
+	return null;
+	
+    }
+
+    public int getColumnCount() {
+	return 2;
+    }
+
+    public String getColumnName(int column) {
+	String name;
+	switch(column) {
+	case 0:
+	    name = Dictionary.get("FileAssociationDialog.Table.Extension");
+	    break;
+	default:
+	    name = Dictionary.get("FileAssociationDialog.Table.Command");
+	}
+	return name;
+    }
+   
+    public String [] getCommand(File file) {
+	String command = null;
+	String [] commands = null;
+	if(file.isFile()) {
+	    // Determine extension
+	    String filename = file.getAbsolutePath();
+	    String extension = filename.substring(filename.lastIndexOf(".") + 1);
+	    // Try to retrieve a value from cache
+	    Element entry = getCommand(extension);
+	    if(entry != null) {
+		///ystem.err.println("Retrieved Value From Cache");
+		command = XMLTools.getValue(entry); 
+	    }
+	    if(command == null || command.length() == 0) {
+		///ystem.err.println("No Existing Command");
+		// If command is null, and we are on windows try searching the registry.
+		if(Utility.isWindows()) {
+		    //try the start command
+		    if (Utility.isWindows9x()) {
+			command = StaticStrings.WIN_9X_OPEN_COMMAND;
+		    } else {
+			command = StaticStrings.WIN_OPEN_COMMAND;
+		    }
+		    
+		}
+		
+		// If we are on a mac, default to using the open program
+		else if(Utility.isMac()) {
+		    command = StaticStrings.MAC_OPEN_COMMAND;
+		}
+
+		// Otherwise display the dialog and ask the user to enter launching command.
+		if(command == null || command.length() == 0) {
+		    ///ystem.err.println("Show Dialog");
+		    // Show the dialog which forces a user to select the launch command for a certain file.
+		    FileAssociationDialog dialog = new FileAssociationDialog(this);
+		    command = dialog.display(extension);
+		    dialog = null;
+		}
+
+		// Hopefully by now we have a command, or else we're never going to get one. Add the association.
+		if (command != null && !command.equals("")) {
+		    // If no previous entry existed create one.
+		    if(entry == null) {
+			entry = associations_element.getOwnerDocument().createElement(StaticStrings.ENTRY_ELEMENT);
+			entry.setAttribute(StaticStrings.EXTENSION_ATTRIBUTE, extension);
+			associations_element.appendChild(entry);
+		    }
+		    // Replace the text in this node. Remember to replace the dummy filename with %1 - I dont think the filename will ever be in the comand now
+		    //XMLTools.setValue(entry, command.replaceAll(filename, FILENAME_ARG));
+		    XMLTools.setValue(entry, command);
+		}
+	    }
+
+	    if (command != null && !command.equals("")) {
+		// Make the command into a string []		
+		commands = command.split(" ");
+
+		// Now substitute any occurrences of %1 with its filename
+		// Note this is done after the split on spaces to avoid
+		// any conflict with filenames with spaces in them.
+
+		// We have to fix filename under windows to escape the backslashes
+		filename = filename.replaceAll(ESCAPE, ESCAPED_ESCAPE);
+
+		for (int i=0; i<commands.length; i++) {
+		    // Replace %1 with the appropriate filename
+		    commands[i] = commands[i].replaceAll(FILENAME_ARG, filename);
+		}
+	    }
+	    
+	    entry = null;
+	    extension = null;
+	    filename = null;
+	}
+	return commands;
+    }
+
+    public Element getCommand(String target_extension) {
+	NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
+	for(int i = 0; i < entries.getLength(); i++) { 
+	    Element entry = (Element) entries.item(i);
+	    String extension = entry.getAttribute(StaticStrings.EXTENSION_ATTRIBUTE);
+	    if(extension.equalsIgnoreCase(target_extension)) {
+		entries = null;
+		extension = null;
+		return entry;
+	    }
+	}
+	entries = null;
+	return null;
+    }
+
+    public String getCommandString(String target_extension) {
+	Element entry = getCommand(target_extension);
+	if(entry != null) {
+	    return XMLTools.getValue(entry);
+	}
+	else {
+	    return "";
+	}
+    }
+
+    public String getExtension(int index) {
+	NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
+	if(0 <= index && index < entries.getLength()) {
+	    Element entry = (Element) entries.item(index);
+	    return entry.getAttribute(StaticStrings.EXTENSION_ATTRIBUTE);
+	}
+	return "";
+    }
+
+    public int getRowCount() {
+	return size();
+    }
+
+    public Object getValueAt(int row, int column) {
+	String extension = getExtension(row);
+	switch(column) {
+	case 0:
+	    return extension;
+	default:
+	    return getCommandString(extension);
+	}
+    }
+
+    public void save() {
+    }
+
+    public void setCommand(String extension, String command) {
+	DebugStream.println("Set Launch: " + extension + " with " + command);
+	// Retrieve any existing entry for this extension
+	Element entry = getCommand(extension);
+	// If no previous entry existed create one.
+	if(entry == null && command != null) {
+	    entry = associations_element.getOwnerDocument().createElement(StaticStrings.ENTRY_ELEMENT);
+	    entry.setAttribute(StaticStrings.EXTENSION_ATTRIBUTE, extension);
+	    associations_element.appendChild(entry);
+	}
+
+	if(command != null) {
+	    // Replace the text in this node. If the user has used filename instead of %1 then too bad.
+	    XMLTools.setValue(entry, command);
+	}
+	else {
+	    // Remove the entry
+	    associations_element.removeChild(entry);
+	}
+	entry = null;
+	fireTableDataChanged(); // Can't be anymore efficient as DOM does not gareuntee ordering of new child nodes is consistant
+    }
+
+    public int size() {
+	NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
+	return entries.getLength();
+    }
+
+
+    protected boolean isAvailable(String program) {
+	try {
+	    ExternalProgram e = new ExternalProgram("which", program);
+	    e.exitProgram();
+	    String out = e.getLineOfProgramOutput();
+	    if (out == null) {
+		return false;
+	    }
+	    return true;
+	} catch (Exception exc) {
+	    return false;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileFilter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileFilter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileFilter.java	(revision 10506)
@@ -0,0 +1,10 @@
+package org.greenstone.gatherer.file;
+
+public class FileFilter {
+    public boolean exclude;
+    public String filter;
+    public FileFilter(String filter, boolean exclude) {
+	this.exclude = exclude;
+	this.filter = filter;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileJob.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileJob.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileJob.java	(revision 10506)
@@ -0,0 +1,156 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.file;
+
+import javax.swing.tree.*;
+import org.greenstone.gatherer.util.DragComponent;
+
+/** This object encapsulates all the information about a certain file movement job. This job be to create a copy of a file from one place to another, or to simply delete a file. 
+ * @author John Thompson
+ * @version 2.3c
+ */
+public class FileJob {
+    /** true to mark that this file has already been copied, false otherwise. */
+    public boolean done = false;
+
+    public boolean folder_level = false;
+    /** The type of this movement as an byte. */
+    public byte type = 0;
+    /** The DragComponent source of this file, most likely a GTree. */
+    public DragComponent source       = null;
+    /** The DragComponent to move the file to, again most likely a GTree. */
+    public DragComponent target       = null;
+    /** The unique identifier shared by all jobs created by the same action. */
+    private long id = 0;
+    /** The path to the destination node as a string. Used because any reference based path or variables quickly becomes obsolete. */
+    private TreePath destination_path = null;
+    /** The path to the origin node as a string. Used because any reference based path or variables quickly becomes obsolete. */
+    private TreePath origin_path = null;
+    /** An element of the job type enumeration indicating a copy action. */
+    static final public byte COPY   = 1;
+    /** An element of the job type enumeration indicating a delete action. */
+    static final public byte DELETE = 2;
+    /** An element of the job type enumeration indicating a move action. */
+    static final public byte MOVE   = 3;
+    /** An element of the job type enumeration indicating a new folder action. */
+    static final public byte NEW_FOLDER = 4;
+
+    /** Constructor.
+     * @param id A unique identifier for this job (and others created with a single gesture) as a long.
+     * @param source The DragComponent source of this file, most likely a GTree.
+     * @param orig The FileNode you wish to mode.
+     * @param target The DragComponent to move the file to, again most likely a GTree.
+     * @param dest The files new FileNode parent within the target.
+     * @param type The type of this movement as an int, either COPY or DELETE.
+     */
+    public FileJob(long id, DragComponent source, FileNode orig, DragComponent target, FileNode dest, byte type) {
+	this.id = id;
+	this.source = source;
+	this.target = target;
+	this.type = type;
+	///ystem.err.println("New Job: " + type + ", " + source + ", " + target);
+	// Dont store FileNodes which can go stale. Store paths instead, which are used to locate current 'fresh' versions of nodes.
+	if(dest != null) {
+	    this.destination_path = new TreePath(dest.getPath());
+	    ///ystem.err.println("Destination Path: " + destination_path);
+	}
+	if(orig != null) {
+	    this.origin_path = new TreePath(orig.getPath());
+	    ///atherer.println("Origin Path: " + origin_path);
+	}
+    }
+
+    /** Retrieve the destination node. Watch out for stale versions by always attempting to load the node at destination_path first. */
+    public FileNode getDestination() {
+	FileNode destination = null;
+	if(destination_path != null) {
+	    if(target != null) {
+		FileSystemModel model = (FileSystemModel)target.getTreeModel();
+		destination = model.getNode(destination_path);
+	    }
+	    // If the above fails, a stale copy may be better than nothing.
+	    else {
+		destination = (FileNode) destination_path.getLastPathComponent();
+	    }
+	}
+	return destination;
+    }
+
+    /** Retrieve the origin node. Watch out for stale versions by always attempting to load the node at origin_path first. */
+    public FileNode getOrigin() {
+	FileNode origin = null;
+	if(origin_path != null) {
+	    if(source != null) {
+		FileSystemModel model = (FileSystemModel)source.getTreeModel();
+		origin = model.getNode(origin_path);
+	    }
+	    // If the above fails, a stale copy may be better than nothing.
+	    else {
+		origin = (FileNode) origin_path.getLastPathComponent();
+	    }
+	}
+	return origin;
+    }
+
+    /** Retrieve the id for this job. */
+    public long ID() {
+	return id;
+    }
+
+    public String toString() {
+	StringBuffer text = new StringBuffer("");
+	switch(type) {
+	case COPY:
+	    text.append("copy ");
+	    break;
+	case DELETE:
+	    text.append("delete ");
+	    break;
+	case MOVE:
+	    text.append("move ");
+	    break;
+	default:
+	    text.append("unknown ");
+	}
+	FileNode origin = getOrigin();
+	if(origin != null) {
+	    text.append(origin.getFile().getAbsolutePath());
+	}
+	else {
+	    text.append("ERROR!");
+	}
+	text.append(" -> ");
+	FileNode destination = getDestination();
+	if(destination != null) {
+	    text.append(destination.getFile().getAbsolutePath());
+	}  
+	else {
+	    text.append("Recycle Bin");
+	}
+	return text.toString();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileManager.java	(revision 10506)
@@ -0,0 +1,267 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, NZDL Project, University of Waikato
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 2005 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.gatherer.file;
+
+import java.io.File;
+import javax.swing.*;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+import org.greenstone.gatherer.gui.LongProgressBar;
+import org.greenstone.gatherer.gui.NewFolderOrFilePrompt;
+import org.greenstone.gatherer.gui.tree.DragTree;
+import org.greenstone.gatherer.remote.RemoteFileQueue;
+import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
+import org.greenstone.gatherer.util.DragComponent;
+import org.greenstone.gatherer.util.Utility;
+
+
+/** Manages the moving of files within a separate thread.
+ * @author John Thompson, NZDL Project, University of Waikato
+ */
+public class FileManager
+{
+    /** Not only the queue of files to be moved, but also the object that moves them. */
+    static private FileQueue file_queue = null;
+    static private RemoteFileQueue remote_file_queue = null;
+
+    public static int FILE_TYPE = 0;
+    public static int FOLDER_TYPE = 1;
+
+
+    /** Constructor.
+     * @see org.greenstone.gatherer.file.FileQueue
+     */
+    public FileManager()
+    {
+	file_queue = new FileQueue();
+	file_queue.start();
+
+	if (Gatherer.isGsdlRemote) {
+	    remote_file_queue = new RemoteFileQueue();
+	    remote_file_queue.start();
+	}
+    }
+
+
+    /** Determine what action should be carried out by the file queue, and add all of the necessary file jobs. */
+    public void action(DragComponent source, FileNode[] source_nodes, DragComponent target, FileNode target_node)
+    {
+	// Check there is something to do
+	if (source_nodes == null || source_nodes.length == 0) {
+	    return;
+	}
+
+	// We need a unique ID for each file task
+	long id = System.currentTimeMillis();
+
+	// If source and target are the same we're moving
+	if (source == target) {
+	    // Start a new move FileTask and we're done
+	    (new FileTask(id, source, source_nodes, target, target_node, FileJob.MOVE)).start();
+	    return;
+	}
+
+	// If target isn't the RecycleBin, we're copying
+	if (!(target instanceof RecycleBin)) {
+	    // Start a new copy FileTask and we're done
+	    (new FileTask(id, source, source_nodes, target, target_node, FileJob.COPY)).start();
+	    return;
+	}
+
+	// We're deleting... but first make sure source isn't read-only
+	boolean read_only_source = false;
+
+	// The workspace tree is read-only...
+	if (source.toString().equals("Workspace")) {
+	    read_only_source = true;
+
+	    // ...except for files from the "Downloaded Files" folder
+	    String downloaded_files_folder_path = Gatherer.getGLIUserCacheDirectoryPath();
+	    for (int i = 0; i < source_nodes.length; i++) {
+		// Is this the "Downloaded Files" folder?
+		if (source_nodes[i].getFile().getAbsolutePath().startsWith(downloaded_files_folder_path)) {
+		    // Can only delete from the "Downloaded Files" folder if a collection is open
+		    if (Gatherer.c_man.ready() == false) {
+			return;
+		    }
+		    read_only_source = false;
+		}
+	    }
+	}
+
+	// The source is read-only, so tell the user and abort
+	if (read_only_source) {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Read_Only"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	    return;
+	}
+
+	// Start a new delete FileTask and we're done
+	(new FileTask(id, source, source_nodes, target, target_node, FileJob.DELETE)).start();
+    }
+
+
+    /** Retrieves the file queue object. */
+    public FileQueue getQueue()
+    {
+	return file_queue;
+    }
+
+
+    public void openFileInExternalApplication(File file)
+    {
+	// If we're using a remote Greenstone server, we need to download the file before viewing it...
+	if (Gatherer.isGsdlRemote) {
+	    // ... but only if it is inside the collection and we haven't already downloaded it
+	    if (file.getAbsolutePath().startsWith(Gatherer.getCollectDirectoryPath()) && file.length() == 0) {
+		RemoteGreenstoneServer.downloadCollectionFile(file);
+	    }
+	}
+
+	Gatherer.self.spawnApplication(file);
+    }
+
+
+    private class FileTask
+	extends Thread
+    {
+	private long id;
+	private DragComponent source;
+	private FileNode[] source_nodes;
+	private DragComponent target;
+	private FileNode target_node;
+	private byte type;
+
+
+	public FileTask(long id, DragComponent source, FileNode[] source_nodes, DragComponent target, FileNode target_node, byte type)
+	{
+	    this.id = id;
+	    this.source = source;
+	    this.source_nodes = source_nodes;
+	    this.target = target;
+	    this.target_node = target_node;
+	    this.type = type;
+	}
+
+
+	public void run()
+	{
+	    // Reset the progress bar and set it to indeterminate while calculating its size
+	    LongProgressBar progress_bar = file_queue.getProgressBar();
+	    progress_bar.reset();
+	    progress_bar.setIndeterminate(true);
+
+	    // Calculate the progress bar size
+	    boolean cancelled = file_queue.calculateSize(source_nodes);
+	    if (!cancelled) {
+		file_queue.addJob(id, source, source_nodes, target, target_node, type, true);
+		if (Gatherer.isGsdlRemote) {
+		    remote_file_queue.addJob(id, source_nodes, target_node, type);
+		}
+	    }
+
+	    progress_bar.setIndeterminate(false);
+	    progress_bar.clear();
+	}
+    }
+
+
+    public void newDummyDoc(DragTree tree, CollectionTreeNode parent_node){
+	newFolderOrDummyDoc(tree, parent_node, FILE_TYPE);
+    }
+
+
+    public void newFolder(DragTree tree, CollectionTreeNode parent_node) {
+	newFolderOrDummyDoc(tree, parent_node, FOLDER_TYPE);
+    }
+
+
+    protected void newFolderOrDummyDoc(DragTree tree, CollectionTreeNode parent_node, int type) {
+	// Ask the user for the directories name.
+	String extension = "";
+	if (type == FILE_TYPE) {
+	    extension = ".nul";
+	}
+	NewFolderOrFilePrompt new_folder_prompt = new NewFolderOrFilePrompt(parent_node, type, extension);
+	String name = new_folder_prompt.display();
+	new_folder_prompt.dispose();
+	new_folder_prompt = null;
+	// And if the name is non-null...
+	if(name != null) {
+	    FileSystemModel model = (FileSystemModel) tree.getModel();
+	    File folder_file = new File(parent_node.getFile(), name);
+	    //... check if it already exists.
+	    if(folder_file.exists()) { 
+		if (type == FILE_TYPE) {
+		    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Already_Exists_No_Create", name), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		} else {
+		    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Folder_Already_Exists", name), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		}
+	    }
+	    // Otherwise create it.
+	    else {
+		try {
+		    if (type == FILE_TYPE) {
+			folder_file.createNewFile();
+		    } else {
+			folder_file.mkdirs();
+			if (Gatherer.isGsdlRemote) {
+			    long id = System.currentTimeMillis();
+			    CollectionTreeNode new_folder_node = new CollectionTreeNode(folder_file);
+			    remote_file_queue.addJob(id, new FileNode[] { new_folder_node }, null, FileJob.NEW_FOLDER);
+			}
+		    }
+		    // Update the parent node to show the new folder
+		    parent_node.refresh();
+		    
+		    // Refresh workspace tree (collection tree is done automatically)
+		    Gatherer.g_man.refreshWorkspaceTree(DragTree.COLLECTION_CONTENTS_CHANGED);
+		} catch (Exception e) {
+		    if (type == FILE_TYPE) {
+			JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Create_Error", name), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		    } else {
+			JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Folder_Create_Error", name), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		    }
+		}
+	    }
+		
+	    folder_file = null;
+	    model = null;
+	}
+	name = null;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileNode.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileNode.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileNode.java	(revision 10506)
@@ -0,0 +1,357 @@
+package org.greenstone.gatherer.file;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.util.ArrayTools;
+
+
+public abstract class FileNode
+    implements MutableTreeNode
+{
+    protected boolean allows_children = true;
+    protected ArrayList child_nodes = null;
+    protected ArrayList child_nodes_unfiltered = null;
+    protected File file = null;
+    protected FileSystemModel model = null;
+    protected MutableTreeNode parent = null;
+
+
+    public FileNode(File file)
+    {
+	this.file = file;
+
+	// Files cannot have children
+	if (file != null && file.isFile()) {
+	    // Cache this result to prevent unceasing missing disk messages being thrown if the
+	    // removable media was, um, removed after directory mapped
+	    this.allows_children = false;
+	}
+    }
+
+
+    /** Returns the children of the node as an Enumeration. */
+    public Enumeration children()
+    {
+	return new FileEnumeration();
+    }
+
+
+    /** Returns true if the receiver allows children.  */
+    public boolean getAllowsChildren()
+    {
+	return allows_children;
+    }
+
+
+    /** Returns the child TreeNode at index childIndex. */
+    public TreeNode getChildAt(int index)
+    {
+	return (TreeNode) child_nodes.get(index);
+    }
+
+
+    /** Returns the number of children TreeNodes the receiver contains. */
+    public int getChildCount()
+    {
+	int size = 0;
+
+	// We don't map if this is a system root, or we risk the 50,000 Disk not found error messages of death
+	if (isFileSystemRoot()) {
+	    size = 1;  // Size is always non-zero for a system root
+	}
+	else {
+	    map();
+	}
+
+	// Use the number of (filtered) child nodes
+	if (child_nodes != null) {
+	    size = child_nodes.size();
+	}
+
+	return size;
+    }
+
+
+    /** Returns the index of node in the receivers children. */
+    public int getIndex(TreeNode node)
+    {
+	if (child_nodes != null) {
+	    return child_nodes.indexOf(node);
+	}
+
+	return -1;
+    }
+
+
+    /** Returns the parent TreeNode of the receiver. */
+    public TreeNode getParent()
+    {
+	return parent;
+    }
+
+
+    /** Adds child to the receiver at index. */
+    public void insert(MutableTreeNode child, int index)
+    {
+	DebugStream.println("Insert " + child + " in " + this + " at index " + index + " [Model: " + model + "]");
+	if (child == null) {
+	    return;
+	}
+
+	try {
+	    FileNode child_node = (FileNode) child;
+	    child_nodes.add(index, child_node);
+	    child_node.model = model;
+	    child_node.parent = this;
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+
+
+    /** Returns true if the receiver is a leaf. */
+    public boolean isLeaf()
+    {
+	return (allows_children == false);
+    }
+
+
+    /** Removes the child at index from the receiver. */
+    public void remove(int index)
+    {
+	if (index >= 0 && index < child_nodes.size()) {
+	    child_nodes.remove(index);
+	}
+    }
+
+
+    /** Removes node from the receiver. */
+    public void remove(MutableTreeNode node)
+    {
+	remove(getIndex(node));
+    }
+
+
+    /** Removes the receiver from its parent. */
+    public void removeFromParent()
+    {
+	parent.remove(this);
+	parent = null;
+    }
+
+
+    /** Resets the user object of the receiver to object. */
+    public void setUserObject(Object object) {
+	try {
+	    file = (File) object;
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+
+
+    // -------------------------------------------------------------------------------
+
+
+    public void add(MutableTreeNode child)
+    {
+	insert(child, child_nodes.size());
+    }
+
+
+    protected abstract FileNode addChildNode(File file);
+
+
+    /** Compare two FileNodes for equality. */
+    public boolean equals(FileNode node)
+    {
+	if (node == null) {
+	    // Definitely not a match
+	    return false;
+	}
+
+	if (file != null) {
+	    return file.equals(node.getFile());
+	}
+	else {
+	    return toString().equals(node.toString());
+	}
+    }
+
+
+    /** Retrieve the file node at the given index, regardless of filters set. */
+    public FileNode getChildAtUnfiltered(int index)
+    {
+ 	if (index >= 0 && index < size()) {
+ 	    return (FileNode) child_nodes_unfiltered.get(index);
+ 	}
+ 	return null;
+    }
+
+
+    public File getFile() {
+	return file;
+    }
+
+
+    /** Retrieves the tree path from the root node to this node. */
+    public TreeNode[] getPath() {
+	int count = 0;
+	TreeNode current = this;
+	while(current != null) {
+	    count++;
+	    current = current.getParent();
+	}
+	TreeNode[] path = new TreeNode[count];
+	current = this;
+	while(current != null) {
+	    path[count - 1] = current;
+	    count--;
+	    current = current.getParent();
+	}
+	return path;
+    }
+
+
+    public boolean isFileSystemRoot() {
+	if (file != null) {
+	    return FileSystemView.getFileSystemView().isFileSystemRoot(file);
+	}
+	else {
+	    return false;
+	}
+    }
+
+
+    /** Overridden if necessary by subclasses. */
+    public boolean isInLoadedCollection()
+    {
+	return false;
+    }
+
+
+    /** Overridden if necessary by subclasses. */
+    public boolean isReadOnly()
+    {
+	return false;
+    }
+
+
+    public void map()
+    {
+	// If this node has already been mapped, don't bother doing it again
+	if (child_nodes != null) {
+	    return;
+	}
+	child_nodes = new ArrayList();
+
+	// General case, only map if children are allowed
+	if (file != null && getAllowsChildren()) {
+	    File[] files = file.listFiles();
+	    if (files != null && files.length > 0) {
+		// Sort the child files
+		ArrayTools.sort(files);
+
+		// Now add them to child_nodes_unfiltered
+		child_nodes_unfiltered = new ArrayList();
+		for (int i = 0; i < files.length; i++) {
+		    FileNode child_node = this.addChildNode(files[i]);
+		    child_nodes_unfiltered.add(child_node);
+		}
+
+		// Apply the filters set in the model
+		FileFilter[] filters = model.getFilters();
+		for (int i = 0; filters != null && i < filters.length; i++) {
+		    files = ArrayTools.filter(files, filters[i].filter, filters[i].exclude);
+		}
+
+		// Add the files left after filtering to child_nodes
+		for (int i = 0; i < files.length; i++) {
+		    // Use the FileNode object in child_nodes_unfiltered rather than creating another
+		    for (int j = 0; j < child_nodes_unfiltered.size(); j++) {
+			if (((FileNode) child_nodes_unfiltered.get(j)).getFile().equals(files[i])) {
+			    child_nodes.add(child_nodes_unfiltered.get(j));
+			    break;
+			}
+		    }
+		}
+	    }
+
+	    model.nodeStructureChanged(this);
+	}
+    }
+
+
+    public void refresh()
+    {
+  	unmap();
+  	map();
+    }
+
+
+    public void setModel(FileSystemModel model) {
+	this.model = model;
+    }
+
+    public void setParent(MutableTreeNode parent) {
+	this.parent = parent;
+    }
+
+
+    /** Return the total number of child files for the file this node represents, irrespective of filters set. */
+    public int size() {
+	if (child_nodes_unfiltered != null) {
+	    return child_nodes_unfiltered.size();
+	}
+	return 0;
+    }
+
+
+    public String toString()
+    {
+	if (isFileSystemRoot()) {
+	    return file.getAbsolutePath();
+	}
+	else {
+	    return file.getName();
+	}
+    }
+
+
+    /** Unmap this node's children. */
+    public void unmap()
+    {
+	DebugStream.println("Unmapping " + this + "...");
+	child_nodes_unfiltered = null;
+	child_nodes = null;
+    }
+
+
+    private class FileEnumeration
+	implements Enumeration
+    {
+	private int index = 0;
+
+	/** Tests if this enumeration contains more elements. */
+	public boolean hasMoreElements() {
+	    return (index < child_nodes.size());
+	}
+
+	/** Returns the next element of this enumeration if this enumeration object has at least one more element to provide. */
+	public Object nextElement() {
+	    Object result = null;
+	    if (index < child_nodes.size()) {
+		result = child_nodes.get(index);
+		index++;
+	    }
+	    return result;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileOpenActionListener.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileOpenActionListener.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileOpenActionListener.java	(revision 10506)
@@ -0,0 +1,101 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.file;
+
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Gatherer;
+
+/** This class listens for mouse clicks and responds to double-clicks (spawn a new application to view the selected file) and right mouse button clicks (popup menu). 
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3b
+ */
+public class FileOpenActionListener
+    extends MouseAdapter 
+    implements TreeExpansionListener {
+    /** This flag gets toggled to <i>true</i> if the listener determines that the next mouse clicked event it will recieve is actually caused by the tree expanding or collapsing. */
+    private boolean ignore = false;
+    /** The constructor. */
+    public FileOpenActionListener() {
+    }
+    /** Any subclass of MouseAdapter can override this method to respond to mouse click events. In this case we want to start an external application if someone double clicks on an appropriate file record. 
+     * @param event A <strong>MouseEvent</strong> containing further information about the mouse click performed.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.file.FileNode
+     * @see org.greenstone.gatherer.gui.tree.DragTree
+     */ 
+    public void mouseClicked(MouseEvent event) {
+	///ystem.err.println("Mouse clicked");
+	if(!ignore) {
+	    if(event.getClickCount() >= 2) {
+		// Find the file we're clicking on.
+		JTree tree = (JTree)event.getSource();
+		TreePath path = tree.getClosestPathForLocation(event.getX(), event.getY());
+		if(path != null) {
+		    FileNode record = (FileNode)path.getLastPathComponent();
+		    ///ystem.err.println("Double clicked on " + record);
+		    File file = record.getFile();
+		    if (file != null && file.isFile()) {
+			///ystem.err.println("Running " + file);
+			Gatherer.f_man.openFileInExternalApplication(file);
+		    }
+		}
+	    }
+	}
+	else {
+	    ///ystem.err.println("Caused by tree expansion / collapse. Ignoring.");
+	    ignore = false;
+	}
+    }
+    /** Any implementation of TreeExpansionListener must include this method so that we can be informed when a tree node has been collapsed, thus indicating that any mouse click events about to be recieved are most likely related to this event.
+     * @param event A <strong>TreeExpansionEvent</strong> containing information about the node collapsed.
+     */
+    public void treeCollapsed(TreeExpansionEvent event) {
+	///ystem.err.println("Tree Collapsed");
+	ignore = true;
+    }
+    /** Any implementation of TreeExpansionListener must include this method so that we can be informed when a tree node has been expanded, thus indicating that any mouse click events about to be recieved are most likely related to this event.
+     * @param event A <strong>TreeExpansionEvent</strong> containing information about the node expanded.
+     */
+    public void treeExpanded(TreeExpansionEvent event) {
+	///ystem.err.println("Tree Expanded");
+	ignore = true;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileQueue.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileQueue.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileQueue.java	(revision 10506)
@@ -0,0 +1,690 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.file;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+import org.greenstone.gatherer.gui.LongProgressBar;
+import org.greenstone.gatherer.gui.tree.DragTree;
+import org.greenstone.gatherer.metadata.MetadataValue;
+import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
+import org.greenstone.gatherer.util.DragComponent;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.SynchronizedTreeModelTools;
+import org.greenstone.gatherer.util.Utility;
+
+/** A threaded object which processes a queue of file actions such as copying and movement. It also handles updating the various trees involved so they are an accurate representation of the file system they are meant to match.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class FileQueue
+    extends Thread
+{
+    /** When someone requests the movement queue to be dumped this cancel flag is set to true. */
+    private boolean cancel_action = false;
+    /** The button which controls the stopping of the file queue. */
+    private JButton stop_button = null;
+    /** true if the user has selected yes to all from a file 'clash' dialog. */
+    private boolean yes_to_all = false;
+    /** A label explaining the current moving files status. */
+    private JLabel file_status = null;
+    /** A list containing a queue of waiting movement jobs. */
+    private ArrayList queue = null;
+    /** A progress bar which shows how many bytes, out of the total size of bytes, has been moved. */
+    private LongProgressBar progress = null;
+
+
+    /** Constructor.
+     */
+    public FileQueue() {
+	DebugStream.println("FileQueue started.");
+	this.queue = new ArrayList();
+	file_status = new JLabel();
+	Dictionary.setText(file_status, "FileActions.No_Activity");
+	progress = new LongProgressBar();
+	progress.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	progress.setForeground(Configuration.getColor("coloring.collection_tree_foreground", false));
+	progress.setString(Dictionary.get("FileActions.No_Activity"));
+	progress.setStringPainted(true);
+    }
+
+    /** Requeue an existing job into the queue.
+     * @param job A previously created FileJob.
+     */
+    synchronized private void addJob(FileJob job, int position) {
+	job.done = true; // Ensure that the requeued job is marked as done.
+	queue.add(position, job);
+	notify();
+    }
+
+    /** Add a new job to the queue, specifiying as many arguments as is necessary to complete this type of job (ie delete needs no target information).
+     * @param id A long id unique to all jobs created by a single action.
+     * @param source The DragComponent source of this file, most likely a DragTree.
+     * @param child The FileNode you wish to mode.
+     * @param target The DragComponent to move the file to, again most likely a DragTree.
+     * @param parent The files new FileNode parent within the target.
+     * @param type The type of this movement as an int, either COPY or DELETE.
+     */
+    public void addJob(long id, DragComponent source, FileNode[] children, DragComponent target, FileNode parent, byte type, boolean folder_level)
+    {
+	// Queue the sub-job(s) (this may fail if we are asked to delete a read only file)
+	for (int i = 0; i < children.length; i++) {
+	    addJob(id, source, children[i], target, parent, type, folder_level, -1);
+	}
+    }
+    
+    synchronized private void addJob(long id, DragComponent source, FileNode child, DragComponent target, FileNode parent, byte type, boolean folder_level, int position) {
+	FileJob job = new FileJob(id, source, child, target, parent, type);
+	job.folder_level = folder_level;
+        DebugStream.println("Adding job: " + job);
+	if(position != -1 && position <= queue.size() + 1) {
+	    queue.add(position, job);
+	}
+	else {
+	    queue.add(job);
+	}
+	notify();
+    }
+
+    /** Calculates the total deep file size of the selected file nodes.
+     * @param files a FileNode[] of selected files
+     * @return true if a cancel was signalled, false otherwise
+     * @see org.greenstone.gatherer.file.FileManager.Task#run()
+     */
+    public boolean calculateSize(FileNode[] files)
+    {
+	file_status.setText(Dictionary.get("FileActions.Calculating_Size"));
+	progress.setString(Dictionary.get("FileActions.Calculating_Size"));
+
+	// Calculate the total file size of all the selected file nodes
+	Vector remaining = new Vector();
+	for (int i = 0; !cancel_action && i < files.length; i++) {
+	    remaining.add(files[i]);
+	}
+	while (!cancel_action && remaining.size() > 0) {
+	    FileNode node = (FileNode) remaining.remove(0);
+	    if (node.isLeaf()) {
+		progress.addMaximum(node.getFile().length());
+	    }
+	    else {
+		for (int i = 0; !cancel_action && i < node.getChildCount(); i++) {
+		    remaining.add(node.getChildAt(i));
+		}
+	    }
+	}
+
+	// Now we return if calculation was cancelled so that the FileManagers Task can skip the addJob phase correctly.
+	if (cancel_action) {
+	    cancel_action = false; // reset
+	    return true;
+	}
+	else {
+	    return false;
+	}
+    }
+
+    /** This method is called to cancel the job queue at the next available moment. */
+    public void cancelAction() {
+	cancel_action = true;
+    }
+
+
+    private int countFolderDepth(File file)
+    {
+	int depth = 0;
+	while (file != null) {
+	    depth++;
+	    file = file.getParentFile();
+	}
+	return depth;
+    }
+
+
+    /** Format the given filename path string so that it is no longer than the given width. If it is wider replace starting directories with ...
+     * @param key The key <strong>String</Strong> used to retrieve a phrase from the dictionary for this item.
+     * @param raw The raw filename path <strong>String</strong>.
+     * @param width The maximum width as an <i>int</i>.
+     * @return A path <strong>String</strong> no longer than width.
+     */
+    private String formatPath(String key, String raw, int width)
+    {
+	JLabel label = new JLabel(Dictionary.get(key, raw));
+	int position = -1;
+	while(label.getPreferredSize().width > width && (position = raw.indexOf(File.separator)) != -1) {
+	    raw = "..." + raw.substring(position + 1);
+	    label.setText(Dictionary.get(key, raw));
+	}
+	if(raw.indexOf(File.separator) == -1 && raw.startsWith("...")) {
+	    raw = raw.substring(3);
+	}
+	return raw;
+    }
+
+
+    /** Access to the file state label. */
+    public JLabel getFileStatus() {
+	return file_status;
+    }
+
+    /** Access to the progress bar. */
+    public LongProgressBar getProgressBar() {
+	return progress;
+    }
+
+
+    /** The run method exists in every thread, and here it is used to work its way through the queue of Jobs. If no jobs are waiting and it cans, it waits until a job arrives. If a job is present then it is either COPIED or DELETED, with the records being copied or removed as necessary, and directories being recursed through. Finally the user can press cancel to cause the loop to prematurely dump the job queue then wait.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     * @see org.greenstone.gatherer.file.FileJob
+     * @see org.greenstone.gatherer.file.FileNode
+     * @see org.greenstone.gatherer.gui.LongProgressBar
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    public void run()
+    {
+	super.setName("FileQueue");
+
+	while (!Gatherer.exit) {
+	    try {
+		// Retrieve the next job
+		int position = queue.size() - 1;
+		FileJob job = null;
+		if (position >= 0) {
+		    job = (FileJob) queue.remove(position);
+		}
+
+		if (job != null) {
+		    ///ystem.err.println("Found job: " + job);
+		    // Enabled stop button
+		    stop_button.setEnabled(true);
+		    // The user can cancel this individual action at several places, so keep track if the state is 'ready' for the next step.
+		    boolean ready = true;
+		    FileNode origin_node = job.getOrigin();
+		    FileNode destination_node = job.getDestination();
+		    FileSystemModel source_model = (FileSystemModel)job.source.getTreeModel();
+		    FileSystemModel target_model = (FileSystemModel)job.target.getTreeModel();
+		    if(destination_node == null) {
+			// Retrieve the root node of the target model instead. A delete, or course, has no target file so all deleted files are added to the root of the Recycle Bin model.
+			destination_node = (FileNode) target_model.getRoot();
+		    }
+
+		    // Extract common job details.
+		    File source_file = origin_node.getFile();
+		    File target_file = null;
+		    // Determine the target file for a copy or move.
+		    if (job.type == FileJob.COPY || job.type == FileJob.MOVE) {
+			// use the name of the filenode instead of the name of the file - these should be the same except for the collection directories where we want the collection name to be used, not 'import' which is the underlying name
+			target_file = new File(destination_node.getFile(), origin_node.toString());
+		    }
+		    // To copy a file, copy it then add any metadata found at the source. If this file was already in our collection then we must ensure the lastest version of its metadata.xml has been saved to disk. To copy a directory simply create the directory at the destination, then add all of its children files as new jobs.
+		    if((job.type == FileJob.COPY || job.type == FileJob.MOVE) && !job.done) {
+			///ystem.err.println("Copy/Move: " + origin_node);
+
+			// The number one thing to check is whether we are in a cyclic loop. The easiest way is just to check how deep we are
+			int max_folder_depth = Configuration.getInt("general.max_folder_depth", Configuration.COLLECTION_SPECIFIC);
+			boolean continue_over_depth = false;
+			if (countFolderDepth(source_file) > max_folder_depth) {
+			    Object[] options = { Dictionary.get("General.Yes"), Dictionary.get("General.No"), Dictionary.get("FileActions.Increase_Depth") };
+			    String args[] = { String.valueOf(max_folder_depth), source_file.getAbsolutePath() };
+			    int result = JOptionPane.showOptionDialog(Gatherer.g_man, Utility.formatHTMLWidth(Dictionary.get("FileActions.Possible_Cyclic_Path", args), 80), Dictionary.get("General.Warning"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[1]);
+			    args = null;
+			    options = null;
+			    switch(result) {
+			    case 0: // Yes
+				continue_over_depth = true;
+				break;
+			    case 2: // Continue and increase depth
+				continue_over_depth = true;
+				Configuration.setInt("general.max_folder_depth", Configuration.COLLECTION_SPECIFIC, (max_folder_depth + 1));
+				break;
+			    }
+			}
+			else {
+			    continue_over_depth = true;
+			}
+			   
+			if(continue_over_depth) {
+			    FileNode new_node = null;
+			    // Check if file exists, and action as necessary. Be aware the user can choose to cancel the action all together (where upon ready becomes false).
+			    if(target_file.exists()) {
+				// We've previously been told
+				if(yes_to_all) {
+				    // Remove the old file and tree entry.
+				    target_file.delete();
+				    ready = true;
+				}
+				else {
+				    ///atherer.println("Opps! This filename already exists. Give the user some options.");
+				    Object[] options = { Dictionary.get("General.Yes"), Dictionary.get("FileActions.Yes_To_All"), Dictionary.get("General.No"), Dictionary.get("General.Cancel") };
+				    int result = JOptionPane.showOptionDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Exists", target_file.getName()), Dictionary.get("General.Warning"), JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]);
+				    switch(result) {
+				    case 1: // Yes To All
+					yes_to_all = true;
+				    case 0: // Yes
+					// Remove the old file and tree entry.
+					if(destination_node != null) {
+					    TreePath destination_path = new TreePath(destination_node.getPath());
+					    CollectionTreeNode temp_target_node = new CollectionTreeNode(target_file);  // !!! , target_model, true);
+					    TreePath target_path = destination_path.pathByAddingChild(temp_target_node);
+					    SynchronizedTreeModelTools.removeNodeFromParent(target_model, target_model.getNode(target_path));
+					    target_path = null;
+					    temp_target_node = null;
+					    destination_path = null;
+					}
+					target_file.delete();
+					ready = true;
+					break;
+				    case 3: // No To All
+					cancel_action = true;
+				    case 2: // No
+				    default:
+					ready = false;
+					// Increment progress by size of potentially copied file
+					progress.addValue(origin_node.getFile().length());
+				    }
+				}
+			    }
+			    // We proceed with the copy/move if the ready flag is still set. If it is that means there is no longer any existing file of the same name.
+			    if(ready) {
+				// update status area
+				String args[] = new String[1];
+				args[0] = "" + (queue.size() + 1) + "";
+				if(job.type == FileJob.COPY) {
+				    args[0] = formatPath("FileActions.Copying", source_file.getAbsolutePath(), file_status.getSize().width);
+				    file_status.setText(Dictionary.get("FileActions.Copying", args));
+				}
+				else {
+				    args[0] = formatPath("FileActions.Moving", source_file.getAbsolutePath(), file_status.getSize().width);
+				    file_status.setText(Dictionary.get("FileActions.Moving", args));
+				}
+				args = null;
+				
+				// If source is a file
+				if(source_file.isFile()) {
+				    // copy the file. If anything goes wrong the copy file should throw the appropriate exception. No matter what exception is thrown (bar an IOException) we display some message, perhaps take some action, then cancel the remainder of the pending file jobs. No point in being told your out of hard drive space for each one of six thousand files eh?
+				    try {
+					copyFile(source_file, target_file, progress);
+				    }
+				    // If we can't find the source file, then the most likely reason is that the file system has changed since the last time it was mapped. Warn the user that the requested file can't be found, then force a refresh of the source folder involved.
+				    catch(FileNotFoundException fnf_exception) {
+					DebugStream.printStackTrace(fnf_exception);
+					cancel_action = true;
+					// Show warning.
+					JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Not_Found_Message", source_file.getName()), Dictionary.get("FileActions.File_Not_Found_Title"), JOptionPane.ERROR_MESSAGE);
+					// Force refresh of source folder.
+					source_model.refresh(new TreePath(((FileNode)origin_node.getParent()).getPath()));
+				    }
+				    catch(FileAlreadyExistsException fae_exception) {
+					DebugStream.printStackTrace(fae_exception);
+					cancel_action = true;
+					// Show warning.
+					JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Already_Exists_Message", target_file.getName()), Dictionary.get("FileActions.File_Already_Exists_Title"), JOptionPane.ERROR_MESSAGE);
+					// Nothing else can be done by the Gatherer.
+				    }
+				    catch(InsufficientSpaceException is_exception) {
+					DebugStream.printStackTrace(is_exception);
+					cancel_action = true;
+					// Show warning. The message body of the expection explains how much more space is required for this file copy.
+					JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Insufficient_Space_Message", is_exception.getMessage()), Dictionary.get("FileActions.Insufficient_Space_Title"), JOptionPane.ERROR_MESSAGE);
+					// Nothing else can be done by the Gatherer. In fact if we are really out of space I'm not even sure we can quit safely.
+				    }
+				    catch (ReadNotPermittedException rnp_exception) {
+					if (DebugStream.isDebuggingEnabled()) {
+					    DebugStream.printStackTrace(rnp_exception);
+					}
+					cancel_action = true;
+					// Show warning
+					JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Read_Not_Permitted_Message", source_file.getAbsolutePath()), Dictionary.get("FileActions.Write_Not_Permitted_Title"), JOptionPane.ERROR_MESSAGE);
+					// Nothing else we can do.
+				    }
+				    catch(UnknownFileErrorException ufe_exception) {
+					DebugStream.printStackTrace(ufe_exception);
+					cancel_action = true;
+					// Show warning
+					JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Unknown_File_Error_Message"), Dictionary.get("FileActions.Unknown_File_Error_Title"), JOptionPane.ERROR_MESSAGE);
+					// Nothing else we can do.
+				    }
+				    catch(WriteNotPermittedException wnp_exception) {
+					if (DebugStream.isDebuggingEnabled()) {
+					    DebugStream.printStackTrace(wnp_exception);
+					}
+					cancel_action = true;
+					// Show warning
+					JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.Write_Not_Permitted_Message", target_file.getAbsolutePath()), Dictionary.get("FileActions.Write_Not_Permitted_Title"), JOptionPane.ERROR_MESSAGE);
+					// Nothing else we can do.
+				    }
+				    catch(IOException exception) {
+					// Can't really do much about this.
+					DebugStream.printStackTrace(exception);
+				    }
+				    // If not cancelled
+				    if (!cancel_action) {
+					// Create a dummy FileNode with the correct structure (so getPath works)
+					new_node = new CollectionTreeNode(target_file);
+					SynchronizedTreeModelTools.insertNodeInto(target_model, destination_node, new_node);
+				    }
+				}
+				// Else
+				else if(source_file.isDirectory()) {
+				    // create new record
+				    CollectionTreeNode directory_record = new CollectionTreeNode(target_file);
+				    SynchronizedTreeModelTools.insertNodeInto(target_model, destination_node, directory_record);
+				    // Why is this not happening eh?
+				    directory_record.setParent(destination_node);
+				    if(!target_file.exists()) {
+					// make the directory
+					target_file.mkdirs();
+					new_node = directory_record;
+				    }
+				    // Else inform the users that a directory already exists and files will be copied into it
+				    //else {
+				    //    JOptionPane.showMessageDialog(null, Dictionary.get("FileActions.Directory_Exists", target_file.toString()), Dictionary.get("General.Warning"), JOptionPane.WARNING_MESSAGE);
+				    //}
+				    // Queue non-filtered child files for copying. If this directory already existed, the child records will have to generate the undo jobs, as we don't want to entirely delete this directory if it already existed.
+				    FileNode child_record = null;
+				    // In order to have a sane copy proceedure (rather than always copying last file first as it used to) we always add the child node at the position the parent was removed from. Consider the file job 'a' at the end of the queue which generates three new jobs 'b', 'c' and 'd'. The resulting flow should look like this.
+				    // -- Starting queue                   ...[a]
+				    // remove(position) = 'a'              ...
+				    // add(position, 'b')                  ...[b]
+				    // add(position, 'c')                  ...[c][b]
+				    // add(position, 'd')                  ...[d][c][b]
+				    // Next loop
+				    // remove(position) = 'b'              ...[d][c]
+				    for(int i = 0; i < origin_node.getChildCount(); i++) {
+					child_record = (FileNode) origin_node.getChildAt(i);
+					addJob(job.ID(), job.source, child_record, job.target, directory_record, job.type, false, position);
+				    }
+				    child_record = null;
+				    directory_record = null;
+				}
+				// The file wasn't found!
+				else {
+				    cancel_action = true;
+				    // Show warning.
+				    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Not_Found_Message", source_file.getName()), Dictionary.get("FileActions.File_Not_Found_Title"), JOptionPane.ERROR_MESSAGE);
+				    // Force refresh of source folder.
+				    source_model.refresh(new TreePath(((FileNode)origin_node.getParent()).getPath()));
+				}
+
+				// If we haven't been cancelled and we created a new FileNode during the above phase, now is the time to deal with metadata
+				if (!cancel_action && new_node != null) {
+				    // If the file came from inside our collection...
+				    if (job.source.toString().equals("Collection")) {
+					// Get the non-folder level metadata assigned to the origin node...
+					ArrayList assigned_metadata = MetadataXMLFileManager.getMetadataAssignedDirectlyToFile(source_file);
+					// ...and remove it from the original node and assign it to the new folder
+					MetadataXMLFileManager.removeMetadata((CollectionTreeNode) origin_node, assigned_metadata);
+					MetadataXMLFileManager.addMetadata((CollectionTreeNode) new_node, assigned_metadata);
+				    }
+				    // If it came from the workspace search for metadata assigned to the file
+				    else if (job.source.toString().equals("Workspace")) {
+					ArrayList assigned_metadata = MetadataXMLFileManager.getMetadataAssignedDirectlyToExternalFile(origin_node.getFile());
+					MetadataXMLFileManager.addMetadata((CollectionTreeNode) new_node, assigned_metadata);
+				    }
+
+				    if (job.type == FileJob.COPY && new_node.getFile().isFile()) {
+					Gatherer.c_man.fireFileAddedToCollection(new_node.getFile());
+				    }
+				}
+				new_node = null;
+			    }
+			}
+		    }
+		    // If we haven't been cancelled, and we've been asked to delete a directory/file, or perhaps as part of a move, we delete the file. This involves removing any existing metadata and then copying the file to the recycled bin (for a delete only), then deleting the file. When deleting a directory record from the tree (or from the filesystem for that matter) we must ensure that all of the descendant records have already been removed. If we fail to do this the delete will fail, or you will be bombarded with hundreds of 'Parent node of null not allowed' error messages. Also be aware that if the user has cancelled just this action, because of say a name clash, then we shouldn't do any deleting of any sort dammit.
+		    if(!cancel_action && ready && (job.type == FileJob.DELETE || job.type == FileJob.MOVE)) {
+			// Update the progress bar for this job
+			if (source_file.isFile()) {
+			    progress.addValue(source_file.length());
+			}
+
+			// If the source is a file or an empty directory (but not the root node of a tree)
+			File[] child_list = source_file.listFiles();
+			if (source_file.isFile() || (child_list != null && child_list.length == 0 && origin_node.getParent() != null)) {
+			    // Update status area
+			    String args[] = new String[1];
+			    args[0] = formatPath("FileActions.Deleting", source_file.getAbsolutePath(), file_status.getSize().width);
+			    file_status.setText(Dictionary.get("FileActions.Deleting", args));
+
+			    // If it is a metadata.xml file, we must unload it
+			    if (source_file.getName().equals(StaticStrings.METADATA_XML)) {
+				MetadataXMLFileManager.unloadMetadataXMLFile(source_file);
+			    }
+
+			    // Remove the metadata assigned directly to the file
+			    ArrayList assigned_metadata = MetadataXMLFileManager.getMetadataAssignedDirectlyToFile(origin_node.getFile());
+			    MetadataXMLFileManager.removeMetadata((CollectionTreeNode) origin_node, assigned_metadata);
+
+			    // Remove from model
+			    FileNode parent_record = (FileNode) origin_node.getParent();
+			    if (parent_record != null) {
+				SynchronizedTreeModelTools.removeNodeFromParent(source_model, origin_node);
+			    }
+
+			    // Delete the source file
+			    Utility.delete(source_file);
+			}
+			// Else the source is a directory and it has children remaining
+			else if(child_list != null && child_list.length > 0) {
+			    // Don't worry about all this for true file move actions.
+			    if(job.type == FileJob.DELETE) {
+				// queue all of its children, (both filtered and non-filtered), but for deleting only. Don't queue jobs for a current move event, as they would be queued as part of copying. I have no idea way, per sec, however the children within the origin node are always invalid during deletion (there are several copies of some nodes?!?). I'll check that each child is only added once.
+				origin_node.refresh();
+				for(int i = 0; i < origin_node.size(); i++) {
+				    FileNode child_record = (FileNode) origin_node.getChildAtUnfiltered(i);
+				    ///atherer.println("Queuing: " + child_record);
+				    addJob(job.ID(), job.source, child_record, job.target, destination_node, FileJob.DELETE, false, position);
+				}  
+			    }
+			    // Requeue a delete job -after- the children have been dealt with. Remember I've reversed the direction of the queue so sooner is later. Te-he. Also have to remember that we have have followed this path to get here for a move job: Copy Directory -> Queue Child Files -> Delete Directory (must occur after child files) -> Queue Directory.
+			    // One special case. Do not requeue root nodes. Don't requeue jobs marked as done.
+			    if(origin_node.getParent() != null && !job.done) {
+				///atherer.println("Requeuing: " + origin_node.getFile().getAbsolutePath());
+				job.type = FileJob.DELETE; // You only requeue jobs that are deletes, as directories must be inspected before children, but deleted after.
+				addJob(job, position);
+			    }
+			    else {
+				DebugStream.println("I've already done this job twice. I refuse to requeue it again!");
+			    }
+			}
+		    }
+		    job = null;
+		    source_file = null;
+		    target_file = null;
+		    origin_node = null;
+
+		    // We only break out of the while loop if we are out of files or the action was cancelled
+		    if (cancel_action) {
+			// Empty queue
+			clearJobs();
+			cancel_action = false;
+		    }
+		}
+		else { // job == null
+		    // Disable stop button
+		    if (stop_button != null) {
+			stop_button.setEnabled(false);
+		    }
+		    synchronized(this) {
+			// Force both workspace and collection trees to refresh
+			if (Gatherer.g_man != null) {
+			    Gatherer.g_man.refreshWorkspaceTree(DragTree.COLLECTION_CONTENTS_CHANGED);
+			    Gatherer.g_man.refreshCollectionTree(DragTree.COLLECTION_CONTENTS_CHANGED);
+			}
+
+			// Reset status area
+			file_status.setText(Dictionary.get("FileActions.No_Activity"));
+			progress.reset();
+			progress.setString(Dictionary.get("FileActions.No_Activity"));
+			yes_to_all = false;
+			try {
+			    wait();
+			}
+			catch (InterruptedException exception) {}
+		    }
+		}
+	    }
+	    catch (Exception error) {
+		DebugStream.printStackTrace(error);
+	    }
+	}
+    }
+
+
+    /** Register the button that will be responsible for stopping executing file actions. 
+     * @param stop_button a JButton
+     */
+    public void registerStopButton(JButton stop_button) {
+	this.stop_button = stop_button;
+    }
+
+
+    synchronized private void clearJobs() {
+	queue.clear();
+    }
+    
+    /** Copy the contents from the source directory to the destination 
+     * directory.
+     * @param source The source directory
+     * @param destination The destination directory
+     * @param progress A progress bar to monitor copying progress
+     * @see org.greenstone.gatherer.Gatherer
+     */
+    public void copyDirectoryContents(File source, File destination, LongProgressBar progress) 
+	throws FileAlreadyExistsException, FileNotFoundException, InsufficientSpaceException, IOException, ReadNotPermittedException, UnknownFileErrorException, WriteNotPermittedException
+    {
+	if (!source.isDirectory()) return;
+	// check that dest dirs exist
+	destination.mkdirs();
+	
+	File [] src_files = source.listFiles();
+	if (src_files.length == 0) return; // nothing to copy
+	for (int i=0; i<src_files.length; i++) {
+	    File f = src_files[i];
+	    String f_name = f.getName();
+	    File new_file = new File(destination, f_name);
+	    if (f.isDirectory()) {
+		copyDirectoryContents(f, new_file, progress);
+	    } else if (f.isFile()) {
+		copyFile(f, new_file, progress);
+	    }
+	}
+	
+    }
+    
+    /** Copy a file from the source location to the destination location.
+     * @param source The source File.
+     * @param destination The destination File.
+     * @see org.greenstone.gatherer.Gatherer
+     */
+    public void copyFile(File source, File destination, LongProgressBar progress)
+	throws FileAlreadyExistsException, FileNotFoundException, InsufficientSpaceException, IOException, ReadNotPermittedException, UnknownFileErrorException, WriteNotPermittedException {
+	if(source.isDirectory()) {
+	    destination.mkdirs();
+	}
+	else {
+	    // Check if the origin file exists.
+	    if (!source.exists()) {
+		DebugStream.println("Couldn't find the source file.");
+		throw(new FileNotFoundException());
+	    }
+
+	    // Make sure the destination file does not exist.
+	    if (destination.exists()) {
+		throw(new FileAlreadyExistsException());
+	    }
+
+	    // Open an input stream to the source file
+	    FileInputStream f_in = null;
+	    try {
+		f_in = new FileInputStream(source);
+	    }
+	    catch (FileNotFoundException exception) {
+		// A FileNotFoundException translates into a ReadNotPermittedException in this case
+		throw new ReadNotPermittedException(exception.toString());		
+	    }
+
+	    // Create an necessary directories for the target file
+	    File dirs = destination.getParentFile();
+	    dirs.mkdirs();
+
+	    // Open an output stream to the target file
+	    FileOutputStream f_out = null;
+	    try {
+		f_out = new FileOutputStream(destination);
+	    }
+	    catch (FileNotFoundException exception) {
+		// A FileNotFoundException translates into a WriteNotPermittedException in this case
+		throw new WriteNotPermittedException(exception.toString());
+	    }
+
+	    // Copy the file
+	    byte data[] = new byte[Utility.BUFFER_SIZE];
+	    int data_size = 0;
+	    while((data_size = f_in.read(data, 0, Utility.BUFFER_SIZE)) != -1 && !cancel_action) {
+		long destination_size = destination.length();
+		try {
+		    f_out.write(data, 0, data_size);
+		}
+		// If an IO exception occurs, we can do some maths to determine if the number of bytes written to the file was less than expected. If so we assume a InsufficientSpace exception. If not we just throw the exception again.
+		catch (IOException io_exception) {
+		    if(destination_size + (long) data_size > destination.length()) {
+			// Determine the difference (which I guess is in bytes).
+			long difference = (destination_size + (long) data_size) - destination.length();
+			// Transform that into a human readable string.
+			String message = Utility.formatFileLength(difference);
+			throw(new InsufficientSpaceException(message));
+		    }
+		    else {
+			throw(io_exception);
+		    }
+		}
+		if(progress != null) {
+		    progress.addValue(data_size);
+		}
+	    }
+	    // Flush and close the streams to ensure all bytes are written.
+	    f_in.close();
+	    f_out.close();
+	    // We have now, in theory, produced an exact copy of the source file. Check this by comparing sizes.
+	    if(!destination.exists() || (!cancel_action && source.length() != destination.length())) {
+		throw(new UnknownFileErrorException());
+	    }
+	    // If we were cancelled, ensure that none of the destination file exists.
+	    if(cancel_action) {
+		destination.delete();
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileSystem.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileSystem.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileSystem.java	(revision 10506)
@@ -0,0 +1,63 @@
+package org.greenstone.gatherer.file;
+
+import java.io.File;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+
+
+public class FileSystem
+{
+    static public WorkspaceTreeNode getLocalFilespaceNode(FileSystemModel model)
+    {
+	// Get all the available roots mounted on the filesystem
+	File[] roots = File.listRoots();
+	if (roots == null) {
+	    return null;
+	}
+
+	// If there is just one root use it as the tree root (Unix)
+	if (roots.length == 1) {
+	    return new WorkspaceTreeNode(roots[0], Dictionary.get("Tree.Root"));
+	}
+
+	// Otherwise build a dummy node which has the roots as children (Windows)
+	else {
+	    return new WorkspaceTreeNode(null, Dictionary.get("Tree.Root"));
+	}
+    }
+
+
+    static public WorkspaceTreeNode getHomeFolderNode()
+    {
+	// Get the name of the OS we're running on
+	String os_name = System.getProperty("os.name");
+	if (os_name == null) {
+	    return null;
+	}
+
+	// Make sure we're running on a multiuser OS where the idea of a "user home" is valid
+	DebugStream.println("Property os.name: " + os_name);
+	String os_name_lc = os_name.toLowerCase();
+	if (os_name_lc.equals("windows 95") || os_name_lc.equals("windows 98") || os_name_lc.equals("windows me")) {
+	    return null;
+	}
+
+	// Get the user's home folder
+ 	String home_folder_str = System.getProperty("user.home");
+	if (home_folder_str == null || home_folder_str.length() == 0) {
+	    return null;
+	}
+
+	// Generate a special mapping to the user home folder
+	File home_folder = new File(home_folder_str);
+	return new WorkspaceTreeNode(home_folder, Dictionary.get("Tree.Home", home_folder.getName()));
+    }
+
+
+    static public WorkspaceTreeNode getDownloadedFilesNode()
+    {
+	// Return a mapping to the downloaded files folder
+	return new WorkspaceTreeNode(new File(Gatherer.getGLIUserCacheDirectoryPath()), Dictionary.get("Tree.DownloadedFiles"));
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileSystemModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileSystemModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/FileSystemModel.java	(revision 10506)
@@ -0,0 +1,261 @@
+package org.greenstone.gatherer.file;
+
+import java.io.File;
+import java.util.*;
+import java.util.regex.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.tree.DragTree;
+import org.greenstone.gatherer.util.SynchronizedTreeModelTools;
+
+public class FileSystemModel
+    extends DefaultTreeModel 
+    implements TreeExpansionListener, TreeWillExpandListener
+{
+    private DragTree tree = null;
+    private FileFilter current_filter = null;
+    private FileFilter[] filters = null;
+    /** The filters in place for any file system model. */
+    private FileFilter[] default_filters = { new FileFilter("\\..*", true), new FileFilter("metadata\\.xml", true) };
+
+    public FileSystemModel(FileNode root) {
+	super(root);
+	root.setModel(this);
+	root.map();
+    }
+
+    public int getChildCount(Object parent) {
+	return ((TreeNode)parent).getChildCount();
+    }
+
+    public FileFilter[] getFilters() {
+	if(filters == null) {
+	    if(current_filter != null) {
+		filters = new FileFilter[default_filters.length + 1];
+		filters[default_filters.length] = current_filter;
+	    }
+	    else {
+		filters = new FileFilter[default_filters.length];
+	    }
+	    System.arraycopy(default_filters, 0, filters, 0, default_filters.length);
+	}
+	return filters;
+    }
+	 
+    /** Retrieve the node denoted by the given tree path. Note that this isn't equivelent to saying path.lastPathComponent, as the references within the path may be stale. */
+    public FileNode getNode(TreePath path) {
+	///atherer.println("**** getNode(" + path + ") ****");
+	FileNode current = (FileNode)root;
+	// Special case for the root node. Check the first path component is the root node.
+	FileNode first_node = (FileNode)path.getPathComponent(0);
+	if(current.equals(first_node)) {
+	    DebugStream.println("First path component matches root node.");
+	    // For each path with this tree path
+	    for(int i = 1; current != null && i < path.getPathCount(); i++) {
+		// Retrieve the stale path
+		Object stale_object = path.getPathComponent(i);
+		FileNode stale_node = null;
+		if(stale_object instanceof FileNode) {
+		    stale_node = (FileNode) stale_object;
+		}
+		DebugStream.print("Searching for '" + stale_object + "': ");
+		// Locate the fresh node by searching current's children. Remember to ensure that current is mapped.
+		boolean found = false;
+
+		// First we search through the mapped children
+		for(int j = 0; !found && j < current.getChildCount(); j++) {
+		    FileNode child_node = (FileNode) current.getChildAt(j);
+		    DebugStream.print(child_node + " ");
+		    if((stale_node != null && stale_node.equals(child_node)) || stale_object.toString().equals(child_node.toString())) {
+			found = true;
+			current = child_node;
+			DebugStream.println("Found!");
+		    }
+		    child_node = null;
+		}
+		// Failing that we search through all the children, including filtered files
+		for(int j = 0; !found && j < current.size(); j++) {
+		    FileNode child_node = (FileNode) current.getChildAtUnfiltered(j);
+		    DebugStream.print(child_node + " ");
+		    if((stale_node != null && stale_node.equals(child_node)) || stale_object.toString().equals(child_node.toString())) {
+			found = true;
+			current = child_node;
+			DebugStream.println("Found!");
+		    }
+		    child_node = null;
+		}
+		// If no match is found, then set current to null and exit.
+		if(!found) {
+		    current = null;
+		    DebugStream.println("Not Found!");
+		}
+		else {
+		    DebugStream.println("Returning node: " + new TreePath(current.getPath()));
+		}
+		// Repeat as necessary
+	    }
+	}
+	return current;
+    }
+
+    public void insertNodeInto(MutableTreeNode newChild, MutableTreeNode parent, int index) {
+	///ystem.err.println("insertNodeInto(" + newChild + ", " + parent + ", " + index + ")");
+	super.insertNodeInto(newChild, parent, index);
+    }
+
+
+    public void refresh(TreePath path)
+    {
+	// Can only refresh if the model is currently being displayed in a tree
+	if (tree == null) {
+	    return;
+	}
+
+	// If no path is set, take the path to the root node (ie. update the whole tree)
+	if (path == null) {
+	    // System.err.println("\nFileSystemModel.refresh(entire tree).");
+	    path = new TreePath(((FileNode) root).getPath());
+
+	    // Make sure the root node is expanded
+	    tree.expandPath(path);
+	}
+	// else {
+	//     System.err.println("\nFileSystemModel.refresh(" + path + ").");
+	// }
+
+	// Record all the expanded paths under this node
+	Enumeration old_expanded_paths_enumeration = tree.getExpandedDescendants(path);
+	if (old_expanded_paths_enumeration == null) {
+	    return;
+	}
+
+	// Map and unmap the node to refresh its contents
+	FileNode node = (FileNode) path.getLastPathComponent();
+	node.refresh();
+
+	// Fire the appropriate event
+	nodeStructureChanged(node);
+
+	// Sort the old expanded paths by length, smallest first
+	ArrayList old_expanded_paths_list = Collections.list(old_expanded_paths_enumeration);
+	Collections.sort(old_expanded_paths_list, new TreePathComparator());
+
+	// Restore each of the expanded paths
+	for (int i = 0; i < old_expanded_paths_list.size(); i++) {
+  	    TreePath old_expanded_path = (TreePath) old_expanded_paths_list.get(i);
+	    // System.err.println("Expanded path: " + old_expanded_path);
+
+	    // Build up the new path in the tree
+	    TreePath current_path = new TreePath(path.getPath());
+  	    FileNode current_node = node;
+
+	    // Traverse the tree to find the node to expand (or find it no longer exists)
+	    while (!current_path.toString().equals(old_expanded_path.toString())) {
+		// System.err.println("Current path: " + current_path);
+
+		FileNode old_expanded_node =
+		    (FileNode) old_expanded_path.getPathComponent(current_path.getPathCount());
+		// System.err.println("Looking for: " + old_expanded_node);
+
+		// Find the child node that matches the next element in the path
+		boolean found = false;
+		for (int j = 0; j < current_node.getChildCount(); j++) {
+		    FileNode child_node = (FileNode) current_node.getChildAt(j);
+		    // System.err.println("Child node: " + child_node);
+		    if (child_node.equals(old_expanded_node)) {
+			// System.err.println("Found!");
+			current_path = current_path.pathByAddingChild(child_node);
+			current_node = child_node;
+			found = true;
+			break;
+		    }
+		}
+
+		// The node was not found, so we cannot expand this path
+		if (!found) {
+		    // System.err.println("Not found...");
+		    break;
+		}
+	    }
+
+	    // If we have built up the correct path, expand it
+	    if (current_path.toString().equals(old_expanded_path.toString())) {
+		tree.expandPath(current_path);
+	    }
+	}
+    }
+
+
+    private class TreePathComparator
+	implements Comparator {
+
+	public int compare(Object o1, Object o2)
+	{
+	    return (((TreePath) o1).getPathCount() - ((TreePath) o2).getPathCount());
+	}
+    }
+
+
+    public void setFilter(String pattern) {
+  	if(pattern != null) {
+  	    current_filter = new FileFilter(pattern, false);
+  	}
+  	else {
+  	    current_filter = null;
+  	}
+  	filters = null;
+    }
+
+    public void setTree(DragTree tree) {
+	this.tree = tree;
+    }
+
+    public String toString() {
+	if(tree != null) {
+	    return tree.toString();
+	}
+	return "FileSystemModel";
+    }
+
+    /** Called whenever an item in the tree has been collapsed. */
+    public void treeCollapsed(TreeExpansionEvent event) {
+	// Deallocate the affected nodes children. Don't need to do this in a swing worker, as the nodes children are currently not visable.
+	TreePath path = event.getPath();
+	FileNode node = (FileNode) path.getLastPathComponent();
+	node.unmap();
+	// Fire the appropriate event.
+	nodeStructureChanged(node);
+    }
+
+    /** Called whenever an item in the tree has been expanded. */
+    public void treeExpanded(TreeExpansionEvent event) {
+    }
+
+    /** Invoked whenever a node in the tree is about to be collapsed. */
+    public void treeWillCollapse(TreeExpansionEvent event) 
+	throws ExpandVetoException {
+	// Veto the event if the user is attempting to collapse the root node (regardless of whether it is visible).
+	TreePath path = event.getPath();
+	if(path.getPathCount() == 1) {
+	    throw new ExpandVetoException(event, "Cannot collapse root node!");
+	}
+    }
+
+    /** Invoked whenever a node in the tree is about to be expanded. */
+    public void treeWillExpand(TreeExpansionEvent event) 
+	throws ExpandVetoException {
+	// Set the wait cursor.
+	Gatherer.g_man.wait(true);
+	// Allocate the children. Don't need to do this in a swing worker, as the nodes children are currently not visable.
+	TreePath path = event.getPath();
+	FileNode node = (FileNode) path.getLastPathComponent();
+	///ystem.err.println("Mapping: " + node);
+	node.map();
+	///ystem.err.println(" -> node has " + node.getChildCount() + " children");
+	nodeStructureChanged(node);
+	// Restore the cursor.
+	Gatherer.g_man.wait(false);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/InsufficientSpaceException.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/InsufficientSpaceException.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/InsufficientSpaceException.java	(revision 10506)
@@ -0,0 +1,11 @@
+package org.greenstone.gatherer.file;
+
+import java.lang.Exception;
+
+public class InsufficientSpaceException
+    extends Exception {
+
+    public InsufficientSpaceException(String message) {
+	super(message);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/ReadNotPermittedException.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/ReadNotPermittedException.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/ReadNotPermittedException.java	(revision 10506)
@@ -0,0 +1,11 @@
+package org.greenstone.gatherer.file;
+
+import java.lang.Exception;
+
+public class ReadNotPermittedException
+    extends Exception
+{
+    public ReadNotPermittedException(String message) {
+	super(message);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/RecycleBin.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/RecycleBin.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/RecycleBin.java	(revision 10506)
@@ -0,0 +1,188 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.file;
+
+import java.awt.*;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.*;
+import java.awt.event.*;
+import java.awt.geom.AffineTransform;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.util.DragComponent;
+import org.greenstone.gatherer.util.DragGroup;
+import org.greenstone.gatherer.util.JarTools;
+
+
+public class RecycleBin
+    extends JButton
+    implements DragComponent, DropTargetListener {
+
+    private boolean ignore = false;
+    /** The group encompasses all of the objects you plan to drag and drop within, and ensures that only one has focus (as clearly identified by the colour of the selection field or, in this particular case, the background) and that actions only occur between components in the same group. */
+    private DragGroup group;
+    /** In order to make this button a drop target we have to create a DropTarget instance with the button as its target. */
+    private DropTarget drop_target;
+    private FileSystemModel model;
+    /** What sort of action should a drag resemble. Not really used as we override with custom drag icon. */
+    private int drag_action = DnDConstants.ACTION_MOVE;
+    /** The last point the mouse was at. Used to repaint 'spoilt' area. */
+    private Point pt_last = null;
+    /** The area covered by the drag ghost, our custom drag icon. */
+    private Rectangle ra_ghost = new Rectangle();
+
+
+    public RecycleBin()
+    {
+	super(JarTools.getImage("bin.gif"));
+	this.drop_target = new DropTarget(this, drag_action, this, true);
+
+	setBackground(Configuration.getColor("coloring.button_background", true));
+	setForeground(Configuration.getColor("coloring.button_foreground", true));
+	setOpaque(true);
+
+	this.model = new FileSystemModel(new RecycleBinNode(new File(Gatherer.getGLIUserDirectoryPath() + "recycle")));
+    }
+
+
+    /** In order for the appearance to be consistant, given we may be in the situation where the pointer has left our focus but the ghost remains, this method allows other members of the GGroup to tell this component to repair the 'spoilt' region left by its ghost. */
+    public void clearGhost(){
+    }
+
+
+    /** Any implementation of DropTargetListener must include this method so we can be notified when the drag focus enters this component. We want to provide some sort of indication whether the current component is an acceptable drop target as well as indicating focus. */
+    public void dragEnter(DropTargetDragEvent event) {
+	group.grabFocus(this);
+	setBackground(Configuration.getColor("coloring.button_selected_background", true));
+	setForeground(Configuration.getColor("coloring.button_selected_foreground", true));
+    }
+
+    /** Any implementation of DropTargetListener must include this method so we can be notified when the drag focus leaves this component. We need to indicate that we have lost focus. */
+    public void dragExit(DropTargetEvent event) {
+	setBackground(Configuration.getColor("coloring.button_background", true));
+	setForeground(Configuration.getColor("coloring.button_foreground", true));
+    }
+
+    /** Any implementation of DropTargetListener must include this method so we can be notified when the drag moves in this component. This is where we repaint our ghost icon at the tip of the mouse pointer. */
+    public void dragOver(DropTargetDragEvent event) {
+	Graphics2D g2 = (Graphics2D) getGraphics();
+	Point pt = event.getLocation();
+	if(pt_last != null && pt.equals(pt_last)) {
+	    return;
+	}
+	pt_last = pt;
+	if(!DragSource.isDragImageSupported()) {
+	    // Erase the last ghost image and or cue line
+	    paintImmediately(ra_ghost.getBounds());
+	    // Remember where you are about to draw the new ghost image
+	    ra_ghost.setRect(pt.x - group.mouse_offset.x, pt.y - group.mouse_offset.y, group.image_ghost.getWidth(), group.image_ghost.getHeight());
+	    // Draw the ghost image
+	    g2.drawImage(group.image_ghost, AffineTransform.getTranslateInstance(ra_ghost.getX(), ra_ghost.getY()), null);
+	}
+    }
+
+    /** Any implementation of DropTargetListener must include this method so we can be notified when the drag ends, ie the transferable is dropped. This in turn triggers a series of add events preceded by a pre() and followed by a post(). */
+    public void drop(DropTargetDropEvent event) {
+	ignore = true;
+	group.grabFocus(this);
+	setBackground(Configuration.getColor("coloring.button_background", true));
+	setForeground(Configuration.getColor("coloring.button_foreground", true));
+	Transferable transferable = event.getTransferable();
+	try {
+	    DragComponent source = group.getSource();
+	    TreePath[] selection = group.getSelection();
+	    FileNode[] source_nodes = new FileNode[selection.length];
+	    for(int i = 0; i < source_nodes.length; i++) {
+		source_nodes[i] = (FileNode) selection[i].getLastPathComponent();
+	    }
+	    event.acceptDrop(drag_action);
+	    // Action delete
+	    Gatherer.f_man.action(source, source_nodes, this, null);
+	    group.setSource(null);
+	    group.setSelection(null);
+	}
+	catch(Exception error) {
+	    error.printStackTrace();
+	    event.rejectDrop();
+	}
+	ignore = false;
+	// Clear up the group.image_ghost
+	paintImmediately(ra_ghost.getBounds());
+	event.getDropTargetContext().dropComplete(true);
+    }
+
+    /** Any implementation of DropTargetListener must include this method so we can be notified when the action to be taken upon drop changes. We never change so we don't do anything here. */
+    public void dropActionChanged(DropTargetDragEvent event) {
+    }
+
+    /** Used to notify this component that it has gained focus by some method other that mouse focus. */
+    public void gainFocus() {
+    }
+
+    /** Any implementation of DragComponent must include this method so that a outsider can get at the underlying tree model behind the component. */
+    public FileSystemModel getTreeModel(){
+  	return (FileSystemModel) model;
+    }
+
+    public boolean ignore() {
+	return ignore;
+    }
+
+    /** This method is used to inform this component when it loses focus by means other than a drag mouse event, and should indicate this somehow. */
+    public void loseFocus() {
+    }
+
+    public void setGroup(DragGroup group) {
+	this.group = group;
+    }
+
+
+    public class RecycleBinNode
+	extends FileNode
+    {
+	public RecycleBinNode(File file)
+	{
+	    super(file);
+	}
+
+	public FileNode addChildNode(File file) { return null; }
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/UnknownFileErrorException.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/UnknownFileErrorException.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/UnknownFileErrorException.java	(revision 10506)
@@ -0,0 +1,11 @@
+package org.greenstone.gatherer.file;
+
+import java.lang.Exception;
+
+public class UnknownFileErrorException
+    extends Exception {
+
+    public UnknownFileErrorException() {
+	super();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WorkspaceTree.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WorkspaceTree.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WorkspaceTree.java	(revision 10506)
@@ -0,0 +1,143 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.file;
+
+import java.io.File;
+import java.util.Enumeration;
+import javax.swing.tree.TreePath;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.tree.DragTree;
+
+
+public class WorkspaceTree
+    extends DragTree
+{
+    static public final int LIBRARY_CONTENTS_CHANGED = 10;
+    static public final int DOWNLOADED_FILES_CHANGED = 11;
+    static public final int FOLDER_SHORTCUTS_CHANGED = 12;
+
+
+    public WorkspaceTree(String name)
+    {
+	super(name, WorkspaceTreeModel.getWorkspaceTreeModel(), true);
+    }
+
+
+    public void addDirectoryMapping(String name, File file)
+    {
+	// Update the information stored in the user's configuration
+	Configuration.addDirectoryMapping(name, file);
+
+	// Now update the tree
+	refresh(FOLDER_SHORTCUTS_CHANGED);
+    }
+
+
+    public void refresh(int refresh_reason)
+    {
+	DebugStream.println("WorkspaceTree::refresh()... ");
+
+	// The method for displaying the tree has changed - redraw the tree
+  	if (refresh_reason == DragTree.TREE_DISPLAY_CHANGED) {
+  	    DebugStream.println("...Reason: tree display changed.");
+  	    updateUI();
+  	}
+
+	// The loaded collection has changed - currently do nothing
+	if (refresh_reason == DragTree.LOADED_COLLECTION_CHANGED) {
+	    DebugStream.println("...Reason: loaded collection changed.");
+	}
+
+	// The collection's contents have changed - refresh collection's import folder
+	if (refresh_reason == DragTree.COLLECTION_CONTENTS_CHANGED) {
+	    DebugStream.println("...Reason: collection contents changed.");
+	    String collection_import_directory_path = Gatherer.c_man.getCollectionImportDirectoryPath();
+	    refreshEveryNodeShowingFolder(collection_import_directory_path);
+	}
+
+	// The collections in the library have changed - refresh the collect directory
+	if (refresh_reason == WorkspaceTree.LIBRARY_CONTENTS_CHANGED) {
+	    DebugStream.println("...Reason: library contents changed.");
+	    String collect_directory_path = Gatherer.getCollectDirectoryPath();
+	    refreshEveryNodeShowingFolder(collect_directory_path);
+	    WorkspaceTreeModel.refreshGreenstoneCollectionsNode();
+	}
+
+	// The downloaded files have changed - refresh that node
+	if (refresh_reason == WorkspaceTree.DOWNLOADED_FILES_CHANGED) {
+	    DebugStream.println("...Reason: downloaded files changed.");
+	    WorkspaceTreeModel.refreshDownloadedFilesNode();
+	}
+
+	// The folder shortcuts have changed - refresh only them
+	if (refresh_reason == WorkspaceTree.FOLDER_SHORTCUTS_CHANGED) {
+	    DebugStream.println("...Reason: folder shortcuts changed.");
+	    WorkspaceTreeModel.refreshFolderShortcuts();
+	}
+    }
+
+
+    private void refreshEveryNodeShowingFolder(String folder_path_str)
+    {
+	// Search through the expanded tree paths, checking if any show the given folder
+	TreePath tree_root_path = new TreePath(getModel().getRoot());
+	Enumeration expanded_tree_paths = getExpandedDescendants(tree_root_path);
+	while (expanded_tree_paths.hasMoreElements()) {
+	    TreePath expanded_tree_path = (TreePath) expanded_tree_paths.nextElement();
+	    WorkspaceTreeNode tree_node = (WorkspaceTreeNode) expanded_tree_path.getLastPathComponent();
+
+	    File tree_node_file = tree_node.getFile();
+	    if (tree_node_file == null) {
+		continue;
+	    }
+
+	    // Get the path of the open tree node
+	    String tree_node_path_str = tree_node_file.toString();
+	    if (!tree_node_path_str.endsWith(File.separator)) {
+		tree_node_path_str = tree_node_path_str + File.separator;
+	    }
+
+	    // If the specified folder is open, it must be refreshed
+	    if (tree_node_path_str.equals(folder_path_str)) {
+		System.err.println("Must refresh node " + tree_node_path_str + "!");
+		((WorkspaceTreeModel) getModel()).refresh(expanded_tree_path);
+	    }
+	}
+    }
+
+
+    public void removeDirectoryMapping(WorkspaceTreeNode target)
+    {
+	// Update the information stored in the user's configuration
+	Configuration.removeDirectoryMapping(target.toString());
+
+	// Update tree
+	refresh(FOLDER_SHORTCUTS_CHANGED);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WorkspaceTreeModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WorkspaceTreeModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WorkspaceTreeModel.java	(revision 10506)
@@ -0,0 +1,179 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.file;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.tree.TreePath;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.util.SynchronizedTreeModelTools;
+
+
+public class WorkspaceTreeModel
+    extends FileSystemModel
+{
+    static private WorkspaceTreeModel workspace_tree_model = null;
+    static private WorkspaceTreeNode workspace_tree_root = null;
+
+    static private WorkspaceTreeNode greenstone_collections_node = null;
+    static private WorkspaceTreeNode local_filespace_node = null;
+    static private WorkspaceTreeNode downloaded_files_node = null;
+    static private WorkspaceTreeNode[] folder_shortcuts = null;
+
+
+    public WorkspaceTreeModel(WorkspaceTreeNode root_node)
+    {
+	super(root_node);
+    }
+
+
+    static public WorkspaceTreeNode[] getFolderShortcuts()
+    {
+	// Return any predefined special directories
+	HashMap mappings = Configuration.getDirectoryMappings();
+	WorkspaceTreeNode[] mapping_nodes = new WorkspaceTreeNode[mappings.size()];
+	Iterator mappings_iterator = mappings.keySet().iterator();
+	for (int i = 0; mappings_iterator.hasNext(); i++) {
+	    String mapping_name = (String) mappings_iterator.next();
+	    File mapping_file = (File) mappings.get(mapping_name);
+	    mapping_nodes[i] = new WorkspaceTreeNode(mapping_file, mapping_name);
+	}
+	return mapping_nodes;
+    }
+
+
+    static public WorkspaceTreeModel getWorkspaceTreeModel()
+    {
+	// Create a root node to contain the various nodes in the workspace tree
+ 	workspace_tree_root = new WorkspaceTreeNode(null, "ABS_ROOT");
+	workspace_tree_model = new WorkspaceTreeModel(workspace_tree_root);
+
+	// Add the "Documents in Greenstone Collections" node
+	greenstone_collections_node = new WorkspaceTreeNode(null, Dictionary.get("Tree.World"));
+	workspace_tree_root.add(greenstone_collections_node);
+
+	// Add the "Local Filespace" node
+	local_filespace_node = FileSystem.getLocalFilespaceNode(workspace_tree_model);
+	workspace_tree_root.add(local_filespace_node);
+
+	// Add the "Home Folder" node
+	workspace_tree_root.add(FileSystem.getHomeFolderNode());
+
+	// Add the "Downloaded Files" node, if the Download pane is enabled
+	if (Gatherer.g_man.download_pane != null) {
+	    downloaded_files_node = FileSystem.getDownloadedFilesNode();
+	    workspace_tree_root.add(downloaded_files_node);
+	}
+
+	// Add any folder shortcuts the user has created
+	refreshFolderShortcuts();
+
+ 	return workspace_tree_model;
+    }
+
+
+    static public void refreshGreenstoneCollectionsNode()
+    {
+	greenstone_collections_node.refresh();
+    }
+
+
+    static public void refreshDownloadedFilesNode()
+    {
+	downloaded_files_node.refresh();
+    }
+
+
+    static public void refreshFolderShortcuts()
+    {
+	// Check for new/deleted folder shortcuts
+	WorkspaceTreeNode[] old_folder_shortcuts = folder_shortcuts;
+	folder_shortcuts = getFolderShortcuts();
+
+	// Remove any deleted shortcuts from the tree
+	if (old_folder_shortcuts != null) {
+	    for (int i = 0; i < old_folder_shortcuts.length; i++) {
+		if (!doesArrayContain(folder_shortcuts, old_folder_shortcuts[i])) {
+		    DebugStream.println("Deleted shortcut: " + old_folder_shortcuts[i]);
+		    SynchronizedTreeModelTools.removeNodeFromParent(workspace_tree_model, old_folder_shortcuts[i]);
+		}
+	    }
+	}
+
+	// Add any new shortcuts to the tree
+	if (folder_shortcuts != null) {
+	    for (int i = 0; i < folder_shortcuts.length; i++) {
+		if (!doesArrayContain(old_folder_shortcuts, folder_shortcuts[i])) {
+		    DebugStream.println("Added shortcut: " + folder_shortcuts[i]);
+		    SynchronizedTreeModelTools.insertNodeInto(workspace_tree_model, workspace_tree_root, folder_shortcuts[i], false);
+		}
+	    }
+	}
+    }
+
+
+    // -- This code is necessary to support the workspace tree file filter --
+    public void refresh(TreePath path)
+    {
+	// If we're not refreshing the whole tree just refresh a certain path
+	if (path != null) {
+	    super.refresh(path);
+	    return;
+	}
+
+	// Refresh each of the nodes in the workspace tree
+	for (int i = 0; i < workspace_tree_root.getChildCount(); i++) {
+	    WorkspaceTreeNode child_node = (WorkspaceTreeNode) workspace_tree_root.getChildAt(i);
+	    super.refresh(new TreePath(child_node.getPath()));
+	}
+
+	// Refresh the local filespace tree specially (it is not unmapped so not refreshed)
+	for (int i = 0; i < local_filespace_node.getChildCount(); i++) {
+	    WorkspaceTreeNode child_node = (WorkspaceTreeNode) local_filespace_node.getChildAt(i);
+	    super.refresh(new TreePath(child_node.getPath()));
+	}
+    }
+
+
+    static private boolean doesArrayContain(Object[] array, Object item)
+    {
+	if (array == null) {
+	    return false;
+	}
+
+	for (int i = 0; i < array.length; i++) {
+	    if (item.toString().equals(array[i].toString())) {
+		return true;
+	    }
+	}
+
+	return false;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WorkspaceTreeNode.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WorkspaceTreeNode.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WorkspaceTreeNode.java	(revision 10506)
@@ -0,0 +1,195 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.file;
+
+
+import java.io.*;
+import java.util.*;
+import javax.swing.filechooser.FileSystemView;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.BasicCollectionConfiguration;  // !!! Don't like this here
+import org.greenstone.gatherer.collection.Collection;  // !!! Don't like this here
+import org.greenstone.gatherer.util.ArrayTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+
+/** This class represents one node in the workspace tree. */
+public class WorkspaceTreeNode
+    extends FileNode
+{
+    private boolean is_gs3_site_node = false;
+    private boolean is_in_loaded_collection = false;
+    private String title = null;
+
+
+    public WorkspaceTreeNode(File file)
+    {
+	super(file);
+    }
+
+
+    public WorkspaceTreeNode(File file, String title)
+    {
+	this(file);
+	this.title = title;
+    }
+
+
+    public FileNode addChildNode(File file)
+    {
+	WorkspaceTreeNode child_node = new WorkspaceTreeNode(file);
+	child_node.setModel(model);
+	child_node.setParent(this);
+	return child_node;
+    }
+
+
+    /** Is this file node within the currently loaded collection? */
+    public boolean isInLoadedCollection()
+    {
+	if (is_in_loaded_collection) {
+	    return true;
+	}
+	else {
+	    FileNode parent = (FileNode) getParent();
+	    if (parent != null) {
+		return parent.isInLoadedCollection();
+	    }
+	}
+	return false;
+    }
+
+
+    public boolean isReadOnly()
+    {
+	// The workspace tree is read only
+	return true;
+    }
+
+
+    public void map()
+    {
+	// Special Case: "Documents in Greenstone Collections" -- map the collections installed in Greenstone
+	if (file == null) { // a special mapping folder
+	    if (child_nodes != null) {
+		// don't bother mapping again if we already have children
+		return;
+	    }
+	    child_nodes = new ArrayList();
+	    if (title.equals(Dictionary.get("Tree.World")) && Gatherer.GS3) {
+		// the Greenstone collections folder for GS3 - this contains a 
+		// folder for each site
+
+		File start = new File(Utility.getSitesDir(Configuration.gsdl3_path));
+		File sites[] = start.listFiles();
+		ArrayTools.sort(sites);
+		for (int i = 0; sites != null && i < sites.length; i++) {
+		    File collect_dir = new File(sites[i], "collect");
+		    if (!collect_dir.exists()) {
+			continue;
+		    }
+
+		    WorkspaceTreeNode child = new WorkspaceTreeNode(null, sites[i].getName());
+		    child.is_gs3_site_node = true;
+		    child.unmap();
+		    child.setModel(model);
+		    child.setParent(this);
+		    child.map();
+		    child_nodes.add(child);
+		}
+		model.nodeStructureChanged(this);
+		
+	    } else if (title.equals(Dictionary.get("Tree.World")) || is_gs3_site_node) {
+		// For each of the children directories, which are collections...
+		File start;
+		if (is_gs3_site_node) {
+		    start = new File(Gatherer.getSitesDirectoryPath() + title + File.separator + "collect" + File.separator);
+		} else {
+		    start = new File(Gatherer.getCollectDirectoryPath());
+		}
+		File cols[] = start.listFiles();
+		ArrayTools.sort(cols);
+
+		// We add their import directories, except for the model collection
+		for (int i = 0; cols != null && i < cols.length; i++) {
+		    if (!cols[i].getName().equals(StaticStrings.MODEL_COLLECTION_NAME)) {
+			File import_dir = new File(cols[i], StaticStrings.IMPORT_FOLDER);
+			if (!import_dir.exists()) {
+			    continue;
+			}
+
+			// we don't care if there is no config file
+			BasicCollectionConfiguration collect_cfg = new BasicCollectionConfiguration(new File(cols[i], Utility.CONFIG_FILE));
+			WorkspaceTreeNode collection_root = new WorkspaceTreeNode(import_dir, collect_cfg.toString());
+			collection_root.setParent(this);
+			collection_root.setModel(model);
+
+			// One last piece of magic so we can determine the current collection
+			Collection collection = Gatherer.c_man.getCollection();
+			if (collection != null) {
+			    collection_root.is_in_loaded_collection = cols[i].getName().equals(collection.getName());
+			}
+			child_nodes.add(collection_root);
+		    }
+		}
+		model.nodeStructureChanged(this);
+	    }
+	    else if (title.equals(Dictionary.get("Tree.Root"))) {
+		// Special Case: "Local Filespace" on Windows -- create a node for each filesystem root (drive letter)
+		
+		// Sort the roots into alphabetical order
+		File[] roots = File.listRoots();
+		ArrayTools.sort(roots);
+		for (int i = 0; i < roots.length; i++) {
+		    // Only add root if it isn't a floppy drive
+		    if (!FileSystemView.getFileSystemView().isFloppyDrive(roots[i])) {
+			child_nodes.add(addChildNode(roots[i]));
+		    }
+		}
+	    }
+	} // if file == null
+	
+	// General case
+	else {
+	    super.map();
+	}
+    }
+
+
+    public String toString()
+    {
+	if (title != null) {
+	    return title;
+	}
+
+	return super.toString();
+    }
+
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WriteNotPermittedException.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WriteNotPermittedException.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/file/WriteNotPermittedException.java	(revision 10506)
@@ -0,0 +1,11 @@
+package org.greenstone.gatherer.file;
+
+import java.lang.Exception;
+
+public class WriteNotPermittedException
+    extends Exception {
+
+    public WriteNotPermittedException(String message) {
+	super(message);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/Attribute.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/Attribute.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/Attribute.java	(revision 10506)
@@ -0,0 +1,85 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+public class Attribute 
+    implements Comparable {
+    public String language = null;
+    public String name = null;
+    public String value = null;
+    public String text = null;
+    private boolean language_specific = false;
+    public Attribute(String name, String value) {
+	this.name = name;
+	this.value = value;
+    }
+    public Attribute(String name, String language, String value) {
+	this.language = language;
+	this.language_specific = true;
+	this.name = name;
+	this.value = value;
+    }
+    public int compareTo(Object other) {
+	return toString().compareTo(other.toString());
+    }
+    public boolean equals(Object other) {
+	return toString().equals(other.toString());
+    }
+    public String get(int column) {
+	switch(column) {
+	case 0:
+	    return name;
+	case 1:
+	    if(language_specific) {
+		return language;
+	    }
+	default:
+	    return value;
+	}
+    }
+    public String toString() {
+	if(text == null) {
+	    if(language_specific) {
+		text = name + " [" + language + "] = " + value;
+	    }
+	    else {
+		text = name + " = " + value;
+	    }
+	}
+	return text;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/AttributeTableModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/AttributeTableModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/AttributeTableModel.java	(revision 10506)
@@ -0,0 +1,244 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.*;
+import org.greenstone.gatherer.util.Utility;
+
+
+/**
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class AttributeTableModel 
+    extends AbstractTableModel {
+    private Attribute last_attribute = null;
+    private int last_index = -1;
+    private int longest[] = null;
+    private int column_zero_width = 0;
+    private JScrollPane scroll_pane = null;
+    private JTable table = null;
+    private String default_value = null;
+    private String names[] = null;
+    private TreeSet attributes = null;
+    static final private int table_width = 550;
+    public AttributeTableModel(TreeSet attributes, String one, String two, String default_value) {
+	super();
+	this.attributes = attributes;
+	this.default_value = default_value;
+	this.longest = new int[2];
+	this.names = new String[2];
+	names[0] = one;
+	names[1] = two;
+    }
+
+    public AttributeTableModel(TreeSet attributes, String one, String two, String three, String default_value) {
+	super();
+	this.attributes = attributes;
+	this.default_value = default_value;
+	this.longest = new int[3];
+	this.names = new String[3];
+	names[0] = one;
+	names[1] = two;
+	names[2] = three;
+    }
+    public int add(Attribute attribute) {
+	attributes.add(attribute);
+	// Determine the row index
+	boolean found = false;
+	int index = 0;
+	Iterator iterator = attributes.iterator();
+	for(int i = 0; !found && iterator.hasNext(); i++) {
+	    if(attribute == iterator.next()) {
+		found = true;
+		index = i;
+	    }
+	}
+	// Fire event
+	fireTableRowsInserted(index, index);
+	return index;
+    }
+
+    /**
+     * Checks to see if the table contains a given value in a given column
+     *
+     * @param value the <strong>String</strong> to check for
+     * @param column the column number to check in, as an <strong>int</strong>
+     * @return boolean - true if the table contains the value.
+     */
+    public boolean contains(String value, int column) {
+	boolean result = false;
+	Iterator iterator = attributes.iterator();
+	while(iterator.hasNext() && !result) {
+	    Attribute attribute = (Attribute) iterator.next();
+	    if(value.equals(attribute.get(column))) {
+		result = true;
+	    }
+	}  
+	return result;
+    }
+
+    /**
+     * Checks to see if the table contains a given value in a given language
+     *
+     * @param value the <strong>String</strong> to check for
+     * @param language_code the language code to check for, as a <strong>String</strong>
+     * @return boolean - true if the table contains the value.
+     */
+    public boolean contains(String value, String language_code) {
+	Iterator iterator = attributes.iterator();
+	while(iterator.hasNext()) {
+	    Attribute attribute = (Attribute) iterator.next();
+	    String attributeLanguage = attribute.language;
+	    if(attributeLanguage == null) {
+		attributeLanguage = "";
+	    }	    
+	    if(language_code == null) {
+		language_code = "";
+	    }
+	  
+	    if(value.equals(attribute.name) && language_code.equalsIgnoreCase(attribute.language)) {
+		return true;
+	    }
+	}
+	return false;
+    }
+
+    public Attribute getAttribute(int row) {
+	if(row != last_index) {
+	    last_index = row;
+	    last_attribute = null;
+				// Retrieve the value from the set using its iterator
+	    Iterator iterator = attributes.iterator();
+	    for(int i = 0; i < row && iterator.hasNext(); i++) {
+		iterator.next();
+	    }
+	    if(iterator.hasNext()) {
+		last_attribute = (Attribute) iterator.next();
+	    }
+	    iterator = null;
+	}
+	return last_attribute;
+    }
+
+    public int getColumnCount() {
+	return names.length;
+    }
+
+    public String getColumnName(int col) {
+	return names[col];
+    }
+
+    public int getRowCount() {
+	int count = 0;
+	if(attributes != null) {
+	    count = attributes.size();
+	}
+	return count;
+    }
+
+    public Object getValueAt(int row, int col) {
+	String value = null;
+	Attribute attribute = getAttribute(row);
+	if(attribute != null) {
+	    value = attribute.get(col);
+	}
+	if(value == null) {
+	    value = default_value;
+	}
+	// Update table column width if necessary
+	if(value.length() > longest[col]) {
+	    Component component = table.getCellRenderer(row, col).getTableCellRendererComponent(table, value, false, false, 0, 0);
+	    int width = component.getPreferredSize().width + 10;
+	    TableColumn column = table.getColumnModel().getColumn(col);
+	    if(width > column.getPreferredWidth()) {
+		// Calculate default column width
+		int default_width = 0;
+		int total_width = scroll_pane.getSize().width;
+		if(names.length == 2) {
+		    if(col == 0) {
+			default_width = total_width / 3;
+		    }
+		    else {
+			default_width = 2 * (total_width / 3);
+		    }
+		}
+		else {
+		    switch(col) {
+		    case 0:
+			default_width = (2 * total_width) / 9;
+			break;
+		    case 1:
+			default_width = total_width / 9;
+			break;
+		    default:
+			default_width = 2 * (total_width / 3);
+			break;
+		    }
+		}
+		if(width > default_width) {
+		    column.setPreferredWidth(width);
+		}
+		else {
+		    column.setPreferredWidth(default_width);
+		}
+	    }
+	    longest[col] = value.length();
+	}
+	return Utility.stripNL(value);
+    }
+    public void removeRow(final int row) {
+	///ystem.err.println("Remove row " + row);
+	Attribute attribute = getAttribute(row);
+	if(attribute != null) {
+	    attributes.remove(attribute);
+				// Arg... this caused me a headache for hours.
+	    last_index = -1;
+	    fireTableRowsDeleted(row, row);
+	}
+    }
+    public void setScrollPane(JScrollPane scroll_pane) {
+	this.scroll_pane = scroll_pane;
+    }
+    public void setTable(JTable table) {
+	this.table = table;
+	this.longest = new int[getColumnCount()];
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/ComboArea.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/ComboArea.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/ComboArea.java	(revision 10506)
@@ -0,0 +1,202 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import org.greenstone.gatherer.gui.GComboBox;
+import org.greenstone.gatherer.util.Utility;
+
+/** Combines the idea of a combobox with a text area so that multiline entries can be displayed properly. Basically takes a GCombobox, butchers out the JTextField editor while retaining the button and the data model, then uses a JTextArea for the editor instead. 
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class ComboArea
+    extends JPanel {
+    /** Should the listener ignore any change events fired (most likely as a result of the listener in the first place). */
+    private boolean ignore = false;
+    /** The combobox we are going to utilize. */
+    private GComboBox combobox = null;
+    /** The text area involved. Not quite a JTextArea, the smarter part is that is allows coloring contrary to the UIManager settings. */
+    private SmarterTextArea text_area = null;
+    /** Create a new ComboArea demarked by a particular label. The label is given here so that it fits nicely with the text area and button.
+     * @param text The label text to be shown above text area as a <strong>String</strong>.
+     * @param label_size The <strong>Dimension</strong> to use for the label.
+     * @see org.greenstone.gatherer.gui.ComboArea.ComboAreaListener
+     * @see org.greenstone.gatherer.gui.ComboArea.Renderer
+     */
+    public ComboArea(String text, Dimension label_size) {
+	// Creation
+	JPanel title_pane = new JPanel();
+	title_pane.setOpaque(false);
+	JLabel label = new JLabel(text);
+	label.setOpaque(false);
+	label.setPreferredSize(label_size);
+	JPanel text_pane = new JPanel();
+	text_area = new SmarterTextArea();
+	text_area.setRows(3);
+	JPanel button_pane = new JPanel();
+	Dimension button_size = new Dimension(label_size.height, label_size.height);
+	button_pane.setMaximumSize(button_size);
+	button_pane.setMinimumSize(button_size);
+	button_pane.setPreferredSize(button_size);
+	button_pane.setSize(button_size);
+	combobox = new GComboBox();
+	combobox.setPreferredSize(label_size);
+	combobox.setRenderer(new Renderer());
+	// Connection
+	combobox.addActionListener(new ComboAreaListener());
+	// Layout
+	title_pane.setLayout(new BorderLayout());
+	title_pane.add(label, BorderLayout.WEST);
+
+	text_pane.setLayout(new BorderLayout());
+	text_pane.add(new JScrollPane(text_area), BorderLayout.CENTER);
+
+	setLayout(new BorderLayout());
+	add(title_pane, BorderLayout.NORTH);
+	add(text_pane, BorderLayout.CENTER);
+    }
+
+    /** Add an element to our combobox model. Remember to tell the listeners to ignore this action unless you want an infinite loop.
+     * @param item The <strong>Object</strong> to add.
+     */
+    public void add(Object item) {
+	ignore = true;
+	combobox.add(item.toString());
+	ignore = false;
+    }
+
+    /** Clear the combobox model.
+     */
+    public void clear() {
+	combobox.clear();
+    }
+
+    /** Retrieve the text currently displayed in the text area.
+     * @return A <strong>String</strong> containing the required text.
+     */
+    public String getText() {
+	return text_area.getText();
+    }
+
+    /** Retrieve a reference to the text area.
+     * @return A <strong>JTextComponent</strong> reference.
+     */
+    public JTextComponent getTextComponent() {
+	return text_area;
+    }
+
+    /** Change the selected item in the combobox to the one given. If such an object doesn't exist in the model, ignore it. Notice that this time we don't ignore, as we want a selection to update the text field.
+     * @param item The <strong>Object</strong> that we want to select from the combobox.
+     */
+    public void setSelectedItem(Object item) {
+	combobox.setSelectedItem(item);
+    }
+
+    /** Set the text shown in the text area to the value provided. Note that this has no effect on the combobox, nor will this value be stored in the model.
+     * @param text The <strong>String</strong> to display.
+     */
+    public void setText(String text) {
+	text_area.setText(text);
+    }
+
+    /** This clas listens for changes in the selected item in the combobox and if applicable updates the text area to match. */
+    private class ComboAreaListener
+	implements ActionListener {
+	/** Whenever a new object is selected from the combobox list, determine if this is an appropriate time to update the text area and if so do so.
+	 * @param event An <strong>ActionEvent</strong> encompassing all the relevant data about an action having been performed.
+			*/
+	public void actionPerformed(ActionEvent event) {
+	    Object object = combobox.getSelectedItem();
+	    if(object != null && !ignore) {
+		text_area.setText(object.toString());
+	    }
+	}
+    }
+    /** This renderer is used to ensure that the labels shown in the combobox drop-down list are both correct in colouring and legible. The later is important as the entry itself may actually span several lines. */
+    private class Renderer
+	extends DefaultListCellRenderer {
+	/** Retrieve the component used to 'rubberstamp' the desired entry in the combobox.
+	 * @param list The <strong>JList</strong> this component will be renderer in.
+	 * @param value The <strong>Object</strong> whose value should be represented by the component returned.
+	 * @param index An <i>int</i> giving the objects index in the list of objects.
+	 * @param isSelected <i>true</i> if this object is currently selected, <i>false</i> otherwise.
+	 * @param cellHasFocus <i>true</i> if this object is currently in focus, <i>false</i> otherwise.
+	 * @see org.greenstone.gatherer.util.Utility
+	 */
+	public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+	    JLabel temp = null;
+	    if(value != null) {
+		// Only show a single line by removing new lines.
+		StringBuffer text = new StringBuffer(Utility.stripNL((String)value));
+		// Generate prototype label
+		temp = (JLabel) super.getListCellRendererComponent(list, text.toString(), index, isSelected, cellHasFocus);
+		// Trim down the value string so it fits nicely. Start by shortening it to the number of characters determined from the smarter text area.
+		int preferred_characters = text_area.calculateColumnCount();
+		if(preferred_characters > 3 && text.length() > preferred_characters) {
+		    text.delete(preferred_characters - 3, text.length());
+		    text.append("...");
+		}
+		temp.setText(text.toString());
+		// If we are still too long, shorten by one character at a time until it fits
+		while(temp.getPreferredSize().width > text_area.getSize().width && text.length() > 4) {
+		    // Remove the last four characters and mark as being chopped
+		    text.delete(text.length() - 4, text.length());
+		    text.append("...");
+		    // Assign new string, rinse and repeat.
+		    temp.setText(text.toString());
+		}
+	    }
+	    else {
+		temp = (JLabel) super.getListCellRendererComponent(list, "", index, isSelected, cellHasFocus);
+	    }
+				// Colouring should be the same as the dependent we are based on.
+	    if(isSelected) {
+		temp.setBackground(text_area.getSelectionColor());
+		temp.setForeground(text_area.getSelectedTextColor());
+	    }
+	    else {
+		temp.setBackground(text_area.getBackground());
+		temp.setForeground(text_area.getForeground());
+	    }
+	    return temp;
+	} 
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/ElementWrapper.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/ElementWrapper.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/ElementWrapper.java	(revision 10506)
@@ -0,0 +1,292 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+/**************************************************************************************
+ * Title:        Gatherer
+ * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
+ * Company:      The University of Waikato
+ * Written:        /  /01
+ * Revised:      03/10/02 - Commented
+ **************************************************************************************/
+import java.util.TreeSet;
+import java.util.ArrayList;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/** This class provides a convience wrapper around a DOM model Element to allow Components such as the MetadataTable to display this information properly.
+ * @author John Thompson
+ * @version 2.3
+ */
+public class ElementWrapper
+    implements Comparable {
+    /** The DOM element this wrapper is wrapped around. */
+    private Element element = null;
+    /** A string prefix identifying the metadata set namespace. */
+    private String namespace = "";
+    private ArrayList subelements = null; //The list of subelements
+
+    /** Constructor for elements with no namespace necessary.
+     * @param element The DOM <strong>Element</strong> this is to be based on.
+     */
+    public ElementWrapper(Element element) {
+	this.element = element;
+	Element parent =  (Element)element.getParentNode();
+	if (parent != null)
+	    {
+		this.namespace = parent.getAttribute("namespace");
+	    }
+	
+	subelements = XMLTools.getChildElementsByTagName(element, "Element");
+	//Should read in each subelement's value tree?
+    }
+
+    public void addAttribute(String name, String value) {
+	MSMUtils.addElementAttribute(element, name, "en", value);
+    }
+
+    public void addAttribute(String name, String language, String value) {
+	MSMUtils.addElementAttribute(element, name, language, value);
+    }
+
+
+    /**
+       Check to see if the element contains a particular subelement
+       @return true if element already contains a subelement of name name.
+       @param name the name of the subelement to check for, as a <strong>String</strong> 
+       @author Matthew Whyte
+       Date last modified: 19/01/04
+    */
+    public boolean containsSubelement(String name)
+    {
+	//System.err.println("Want to see if subelement: " + name + " exists."); //debug
+	for(int i = 0; i < subelements.size(); i++)
+	    {
+		Element sibling = (Element)subelements.get(i);
+		String sibling_name = sibling.getAttribute("name");
+		if(sibling_name.equals(name))
+		    {
+			return true;
+		    }
+	    }
+       
+	return false;
+    }
+
+    /*
+      Check to see if the element contains any subelements
+      @return tree if element contains subelements
+      @author Matthew Whyte
+      Date last modified: 2/02/05
+     */
+    public boolean containsSubelements()
+    {
+	return(subelements.size() != 0);
+    }
+
+    /**
+       Method to add a subelement to the list of subelements.
+       @param element the subelement to add to the list, as a <strong>Element</strong>
+       @author Matthew Whyte
+       Date last modified: 27/01/05
+     */
+    public void addSubelementToList(Element element)
+    {
+	subelements.add(element);
+    }
+
+    /**
+       Method to remove a subelement from the list of subelements.
+       @param element the subelement to remove from the list, as a <strong>Element</strong>
+       @author Matthew Whyte
+       Date last modified: 27/01/05
+     */
+    public void removeSubelementFromList(Element element)
+    {
+	subelements.remove(element);
+    }
+
+    /**
+       Method to acquire a list of all the subelements in the element.
+       @return A <strong>NodeList</strong> containing all of this element's subelements.
+
+       @author: Matthew Whyte
+       @date last modified: 19/01/04
+     */
+    public ArrayList getSubelements()
+    {
+	return subelements;
+    }
+
+
+    /** Create a copy of this element wrapper.
+     * @return A new <strong>ElementWrapper</strong> based on the same element as this one.
+     */
+    public ElementWrapper copy() {
+	Element element_copy = (Element) element.cloneNode(true);
+	return new ElementWrapper(element_copy);
+    }
+    /** Compare two element wrappers for ordering.
+     * @param object An <strong>Object</strong> which is most likely another element wrapper to be compared with.
+     * @return An <i>int</i> indicating order, -1, 0, 1 if this element wrapper is less than, equal to or greater than the given object.
+     */
+    public int compareTo(Object object) {
+	return toString().compareTo(object.toString());
+    }
+    /** Decrement the number of occurances of this metadata element.
+     * @see org.greenstone.gatherer.msm.MSMUtils
+     */
+    public void dec() {
+	MSMUtils.setOccurance(element, -1);
+    }
+    /** Test if two ElementWrappers are equal.
+     * @param object The <strong>Object</strong> to test against.
+     */
+   public boolean equals(Object object) {
+      if(object == null) {
+	 return false;
+      }
+      if(object instanceof ElementWrapper) {
+	 String our_full_name = MSMUtils.getFullName(element, namespace);
+	 String their_full_name = MSMUtils.getFullName(((ElementWrapper)object).getElement());
+	 return our_full_name.equals(their_full_name);
+      }
+      return toString().equals(object.toString());
+    }
+    /** Retrieve the attributes associated with the element this element wrapper is built around.
+     * @return A <strong>TreeSet</strong> of the attributes.
+     * @see org.greenstone.gatherer.msm.MSMUtils
+     */
+    public TreeSet getAttributes() {
+	return MSMUtils.getAttributes(element);
+    }
+    /** Retrieve the element this is wrapped around.
+     * @return A DOM <strong>Element</strong> which represents a metadata element.
+     */
+    public Element getElement() {
+	return element;
+    }
+    /** Retrieve the identity of this element (not necessary the same as this elements name). Identity is language and locale dependent.
+     * @return The identity as a <strong>String</strong>.
+     * @see org.greenstone.gatherer.msm.MSMUtils
+     */
+    public String getIdentity() {
+	return MSMUtils.getIdentifier(element);
+    }
+
+    /** Retrieve the name of this element. Name is unique.
+	@return The name (without the namespace) as a <strong>String</strong>.
+	@see org.greenstone.gatherer.msm.MSMUtils
+	@author Matthew Whyte
+	@date last modified: 21/01/04
+     */
+    public String getNameOnly() {
+	return MSMUtils.getNameOnly(element);
+    }
+
+    /** Retrieve the name of this element. Name is unique.
+     * @return The name as a <strong>String</strong>.
+     * @see org.greenstone.gatherer.msm.MSMUtils
+     */
+    public String getName() {
+		return MSMUtils.getFullName(element, namespace);
+    }
+
+
+    /** Retrieve the namespace prefix for this element wrapper.
+     * @return A <strong>String</strong> containing the namespace or "" if there is no namespace for this element.
+     * @see org.greenstone.gatherer.msm.MSMUtils
+     */
+    public String getNamespace() {
+	if (!namespace.equals("")) {
+	    return namespace;
+	}
+	String name = getName();
+	int pos;
+	if((pos = name.indexOf(MSMUtils.NS_SEP)) != -1) {
+	    return name.substring(0, pos);
+	}
+	else {
+	    return "";
+	}
+    }
+    /** Look for the occurances 'field' of the element and return it if found.
+     * @return An <i>int</i> which matches the number in the occurances attribute of the element, or 0 if no such attribute.
+     * @see org.greenstone.gatherer.msm.MSMUtils
+     */
+    public int getOccurances() {
+	return MSMUtils.getOccurances(element);
+    }
+    /** This method is essentially the same as getDescription() in that it does indeed return this metaelements description. However this method uses the Utility function formatHTMLWidth() to ensure the String can be displayed in a tool-tip window using html markup.
+     * @return A String containing the HTML formatted versions of definition and content (comment).
+     * @see org.greenstone.gatherer.msm.MSMUtils
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    public String getToolTip() {
+	// Add HTML formatting
+	return Utility.formatHTMLWidth(MSMUtils.getDescription(element), 60);
+    }
+
+    /** Increment the number of occurances of this metadata element.
+     * @see org.greenstone.gatherer.msm.MSMUtils
+     */
+    public void inc() {
+	MSMUtils.setOccurance(element, 1);
+    }
+
+    public boolean isHierarchy() {
+	return element.getAttribute(StaticStrings.HIERARCHY_ATTRIBUTE).equalsIgnoreCase(StaticStrings.TRUE_STR);
+    }
+
+    /** Removes an Attribute node from the element. */
+    public boolean removeAttribute(String name, String language, String value) {
+	boolean sucess = MSMUtils.removeElementAttribute(element, name, language, value);
+	if(!sucess)
+	    {
+		//This should not happen.
+		System.err.println("Error removing attribute \'" + name + "\' with value \'" + value +"\'"); 
+	    }
+	return sucess;
+    }
+
+    public String toString() {
+	return getNamespace() + MSMUtils.NS_SEP + getIdentity();
+    }
+
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMS.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMS.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMS.java	(revision 10506)
@@ -0,0 +1,2594 @@
+ /**
+ *#########################################################################
+ *
+ * A component of the Gatherer application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at th * 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.gatherer.gems;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.io.PrintStream;
+import java.io.FileInputStream;
+import java.io.BufferedReader;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.*;
+import javax.swing.*;
+import java.lang.String;
+import javax.swing.event.*;
+import javax.swing.filechooser.*;
+import javax.swing.text.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.GetOpt;
+import org.greenstone.gatherer.gui.GComboBox;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.gui.HelpFrame;
+import org.greenstone.gatherer.gui.ModalDialog;
+import org.greenstone.gatherer.gui.NonWhitespaceField;
+import org.greenstone.gatherer.util.Codec;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+
+
+/** Provides a GUI and relevant suite of tools for the editing of the metadata set associated with this collection. Again I have tried to capture a file manager type feel, with a tree showing the various set-element relations to the left of the dialog, and the right side showing details on the current tree selection. When a set is selected these details include a list of attributes, while when an element is selected this list is joined by another showing assigned values. In order for the editor to be stable and consistant with the rest of the tool, care must be taken for fire appropriate events whenever the sets are changed. There is also the addded complexity of determining what actions have to occur in order for a users edit of an assigned value to be completed, i.e. if the user chooses to remove a value then a call must be made to record_set.root.removeMetadata() to ensure all such values are actually removed, so it is not enough just to remove the value from the value model. 
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3b
+ */ 
+public class GEMS
+    extends JFrame
+{
+    static final public int ADD_SET    = 0;
+    static final public int NORMAL     = 1;
+    static final public int REMOVE_SET = 2;
+
+    /** The default size of the editor dialog. */
+    static final private Dimension ADD_ELEMENT_SIZE = new Dimension(400,125);
+    static final private Dimension RENAME_ELEMENT_SIZE = new Dimension(400, 95);
+    static final private Dimension ADD_SET_SIZE = new Dimension(400,150);
+    static final private Dimension RENAME_SET_SIZE = new Dimension(400,120);
+    static final private Dimension OPEN_SETS_SIZE = new Dimension(400,135);
+    static final private Dimension ADD_OR_EDIT_ATTRIBUTE_SIZE = new Dimension(600,325);
+    static final private Dimension COMPONENT_SIZE = new Dimension(300,30);
+    static final private Dimension SIZE = new Dimension(800,480);
+    static final private String BLANK = "blank";
+    static final private String ELEMENT = "element";
+    static final private String SET = "set";
+
+    static final public String METADATA_SET_TEMPLATE = "xml" + File.separator + "template.mds";
+
+    //all of our popup menu items
+    static final public int T_COLLECTION = 0;
+    static final public int T_ELEMENT    = 1;
+    static final public int T_SET        = 4;
+
+    //static final public String MAX_LOADED_SETS = 64;
+    static public Configuration config = null;
+    private MetadataSetManager msm = new MetadataSetManager(this);
+
+    public AddElementActionListener add_element_action_listener = null;
+    public  AddSetActionListener add_set_action_listener = null;
+    /** The class used to handle add or edit attribute actions has to be globally available so that we can dispose of its dialog properly. */
+    public AddOrEditAttributeActionListener add_or_edit_attribute_action_listener = null;
+    private boolean ignore = false;
+    /** A card layout is used to switch between the two differing detail views. */ 
+    private CardLayout card_layout = null;
+
+    /** Um, the size of the screen I'd guess. */
+    private Dimension screen_size = null;
+    private ElementWrapper current_element = null;
+    /** A reference to ourselves so our inner classes can dispose of us. */
+    private GEMS self = null;
+    private int current_attribute = -1;
+    private int current_attribute_type = -1;
+
+    //private JLabel element_name = null;
+    private JLabel set_name = null;
+    private JScrollPane element_attributes_scroll = null;
+    private JScrollPane set_attributes_scroll = null;
+    private JPanel details_pane = null;
+    private GEMSModel model = null;
+    private GEMSNode current_node = null;
+    private MetadataSet current_set = null;
+    public RemoveSetActionListener remove_set_action_listener;
+    private SmarterTable element_attributes = null;
+    private SmarterTable set_attributes = null;
+    public org.w3c.dom.Element rootelement;
+   
+    //PopupListener provides right-click functionality to any component that needs it
+    //It is a centralized manager for all popups, then we use evt.Source() and determine where the
+    //event was performed
+    private PopupListener popupListener = null;
+ 
+    /** A tree that represents the current metadata sets associated with this collection. */
+    private SmarterTree mds_tree = null;
+    private String dialog_options[] = null;
+    private boolean atLeastOneSetChanged = false;
+
+    static public void main(String[] args)
+    {
+	// Parse arguments
+	GetOpt go = new GetOpt(args);
+
+	if (go.debug) {
+	    DebugStream.enableDebugging();
+
+	    Calendar now = Calendar.getInstance();
+	    String debug_file_path = "debug" + now.get(Calendar.DATE) + "-" + now.get(Calendar.MONTH) + "-" + now.get(Calendar.YEAR) + ".txt";
+
+	    // Debug file is created in the GLI directory
+	    DebugStream.println("Debug file path: " + debug_file_path);
+	    DebugStream.setDebugFile(debug_file_path);
+	}
+
+        GEMS GEMS;
+	GEMS = new GEMS(go.gsdl_path);
+    }
+
+
+    /** Constructor.
+     * @param set a MetadataSet that should be initially selected
+     * @param action a systematic action that should be performed
+     */
+    public GEMS(String gsdl_path)
+    {
+	// Determine the GLI user directory path
+	String gli_user_directory_path = System.getProperty("user.home") + File.separator;
+        if (Utility.isWindows()) {
+	    gli_user_directory_path += "Application Data" + File.separator + "Greenstone" + File.separator + "GLI" + File.separator;
+        }
+        else {
+            gli_user_directory_path += ".gli" + File.separator;
+        }
+
+	//Load configuration file
+	this.self = this;
+	JarTools.initialise(this);
+	config = new Configuration(gli_user_directory_path, gsdl_path, null, null, null);
+
+	// Read Dictionary
+	new Dictionary(Configuration.getLocale("general.locale", true), Configuration.getFont("general.font", true));
+
+	this.dialog_options = new String[2];
+	this.screen_size = config.screen_size;
+        
+	// Initialise some common images
+	popupListener = new PopupListener(this);
+
+	// Load help
+	HelpFrame help = new HelpFrame();
+
+	dialog_options[0] = Dictionary.get("General.OK");
+	dialog_options[1] = Dictionary.get("General.Cancel");
+
+	// Load all the core metadata sets (in the GLI "metadata" directory)
+	model = new GEMSModel();
+	File metadata_directory = new File(getGLIMetadataDirectoryPath());
+	if (metadata_directory.exists()) {
+	    // Load just those .mds files in this directory, and return them
+	    File[] directory_files = metadata_directory.listFiles();
+	    for (int i = 0; i < directory_files.length; i++) {
+		File child_file = directory_files[i];
+		if (!child_file.isDirectory() && child_file.getName().endsWith(".mds")) {
+		    MetadataSet metadata_set = msm.loadMetadataSet(child_file);
+		    model.add(null, metadata_set, GEMSNode.SET);
+		}
+	    }
+	}
+
+	// Creation
+	setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+	setSize(SIZE);
+	setJMenuBar(new GEMSMenuBar());
+	Dictionary.setText(this, "GEMS.Title");
+
+	JPanel content_pane = (JPanel) getContentPane();
+	content_pane.setBackground(config.getColor("coloring.collection_heading_background", false));	  
+	JPanel upper_pane = new JPanel();
+	upper_pane.setOpaque(false);
+	JPanel set_details_pane = new JPanel();
+	set_details_pane.setOpaque(false);
+	JPanel set_name_pane = new JPanel();
+	set_name_pane.setOpaque(false);
+	JLabel set_name_label = new JLabel();
+	set_name_label.setOpaque(false);
+	JPanel element_details_pane = new JPanel();
+	element_details_pane.setOpaque(false);	  
+	JPanel element_inner_pane = new JPanel();
+	element_inner_pane.setOpaque(false);
+	JPanel blank_pane = new JPanel(); // Some blank panel
+	blank_pane.setOpaque(false);
+
+	details_pane = new JPanel();
+	details_pane.setOpaque(false);
+	card_layout = new CardLayout();
+	set_name = new JLabel();
+	
+	JPanel mds_tree_pane = new JPanel();
+	mds_tree_pane.setOpaque(false);
+	mds_tree_pane.setPreferredSize(new Dimension(300,500));
+
+	mds_tree = new SmarterTree(model);
+	mds_tree.setCellRenderer(new GEMSTreeCellRenderer());
+	mds_tree.setRootVisible(false);
+	mds_tree.setBackground(config.getColor("coloring.collection_tree_background", false));
+	mds_tree.setForeground(config.getColor("coloring.collection_tree_foreground", false));
+	mds_tree.setSelectionColor(config.getColor("coloring.collection_selection_background", false));
+	mds_tree.setSelectedTextColor(config.getColor("coloring.collection_selection_foreground", false));
+        //add popupevent handler for tree items
+        mds_tree.addMouseListener(popupListener);
+	mds_tree.addKeyListener(new KeyPressedHandler());
+	mds_tree.addTreeSelectionListener(new MDSTreeSelectionListener());
+		  
+	JPanel set_attributes_pane = new JPanel();
+	set_attributes_pane.setOpaque(false);
+	set_attributes_scroll = new JScrollPane();
+	set_attributes_scroll.getViewport().setBackground(config.getColor("coloring.collection_tree_background", false));
+	set_attributes_scroll.setOpaque(true);
+	set_attributes = new SmarterTable();
+	set_attributes.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+	set_attributes.setBackground(config.getColor("coloring.collection_tree_background", false));
+	set_attributes.setForeground(config.getColor("coloring.collection_tree_foreground", false));
+	set_attributes.setHeadingBackground(config.getColor("coloring.collection_heading_background", false));
+	set_attributes.setHeadingForeground(config.getColor("coloring.collection_heading_foreground", false));
+	set_attributes.setOpaque(false);
+	set_attributes.setSelectionColor(config.getColor("coloring.collection_selection_background", false));
+	set_attributes.setSelectedTextColor(config.getColor("coloring.collection_selection_foreground", false));
+	set_attributes.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	set_attributes.addMouseListener(popupListener);	
+	set_attributes.addMouseListener(new AddOrEditAttributeActionListener());
+	set_attributes.addKeyListener(new RemoveAttributeActionListener()); //Listen for DELETE key
+	set_attributes.getSelectionModel().addListSelectionListener(new AttributesListSelectionListener(set_attributes));
+		  
+	JPanel element_attributes_pane = new JPanel();
+	element_attributes_pane.setOpaque(false);
+	element_attributes_scroll = new JScrollPane();
+	element_attributes_scroll.getViewport().setBackground(config.getColor("coloring.collection_tree_background", false));
+	element_attributes_scroll.setOpaque(true);
+	element_attributes = new SmarterTable();
+	element_attributes.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+	element_attributes.setBackground(config.getColor("coloring.collection_tree_background", false));
+	element_attributes.setForeground(config.getColor("coloring.collection_tree_foreground", false));
+	element_attributes.setHeadingBackground(config.getColor("coloring.collection_heading_background", false));
+	element_attributes.setHeadingForeground(config.getColor("coloring.collection_heading_foreground", false));
+	element_attributes.setSelectionColor(config.getColor("coloring.collection_selection_background", false));
+	element_attributes.setSelectedTextColor(config.getColor("coloring.collection_selection_foreground", false));
+	element_attributes.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        element_attributes.addMouseListener(popupListener);
+	element_attributes.addMouseListener(new AddOrEditAttributeActionListener());
+	element_attributes.addKeyListener(new RemoveAttributeActionListener()); //For the DELETE key
+	element_attributes.getSelectionModel().addListSelectionListener(new AttributesListSelectionListener(element_attributes));
+
+	add_element_action_listener = new AddElementActionListener();
+	add_set_action_listener = new AddSetActionListener();
+	add_or_edit_attribute_action_listener = new AddOrEditAttributeActionListener();
+	remove_set_action_listener = new RemoveSetActionListener();
+
+	// Layout
+	mds_tree_pane.setLayout(new BorderLayout());
+	mds_tree_pane.add(new JScrollPane(mds_tree), BorderLayout.CENTER);
+		  
+	//Set panes
+	set_name_pane.setLayout(new BorderLayout());
+	set_name_pane.add(set_name_label, BorderLayout.WEST);
+	set_name_pane.add(set_name, BorderLayout.CENTER);
+				
+	set_attributes_scroll.setViewportView(set_attributes);
+	set_attributes_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(Dictionary.get("GEMS.Attributes")), BorderFactory.createEmptyBorder(2,2,2,2)));
+	set_attributes_pane.setLayout(new BorderLayout());
+	set_attributes_pane.add(set_attributes_scroll, BorderLayout.CENTER);
+		
+	set_details_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(Dictionary.get("GEMS.Set_Details")), BorderFactory.createEmptyBorder(2,2,2,2)));
+	set_details_pane.setLayout(new BorderLayout());
+	set_details_pane.add(set_name_pane, BorderLayout.NORTH);
+	set_details_pane.add(set_attributes_pane, BorderLayout.CENTER);
+		
+	//Element panes
+	element_attributes_scroll.setViewportView(element_attributes);
+	element_attributes_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(Dictionary.get("GEMS.Attributes")), BorderFactory.createEmptyBorder(2,2,2,2)));
+	element_attributes_pane.setLayout(new BorderLayout());
+	element_attributes_pane.add(element_attributes_scroll, BorderLayout.CENTER);
+		  
+	element_inner_pane.setLayout(new BorderLayout());
+	element_inner_pane.add(element_attributes_pane);
+		  
+	element_details_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(Dictionary.get("GEMS.Element_Details")), BorderFactory.createEmptyBorder(2,2,2,2)));
+	element_details_pane.setLayout(new BorderLayout());
+	element_details_pane.add(element_inner_pane, BorderLayout.CENTER);
+
+	//General panes
+	details_pane.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
+	details_pane.setLayout(card_layout);
+	details_pane.add(blank_pane, BLANK);
+	details_pane.add(set_details_pane, SET);
+	details_pane.add(element_details_pane, ELEMENT);
+
+	upper_pane.setLayout(new BorderLayout());
+	upper_pane.add(mds_tree_pane, BorderLayout.WEST);
+	upper_pane.add(details_pane, BorderLayout.CENTER);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(upper_pane, BorderLayout.CENTER);
+
+	// initialise the selection
+	mds_tree.setSelectionRow(0);
+	// Display
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	setVisible(true);
+    }
+
+
+    private void exit()
+    {
+        if(atLeastOneSetChanged == true)
+	    {
+		int result = JOptionPane.showConfirmDialog(self, Dictionary.get("GEMS.Confirm_Exit_Save", Dictionary.get("GEMS.Element")), Dictionary.get("GEMS.Confirm_Exit_Save_Title"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
+
+		if(result == 0)
+		    {
+			DebugStream.closeDebugStream();
+			msm.save();
+			System.exit(0);
+		    }
+		else if(result == 1)
+		    {
+			DebugStream.closeDebugStream();
+			System.exit(0);
+		    }
+		else if(result == 2)
+		    {
+			//do nothing
+		    }
+	    }
+	else
+	    {
+		//Just exit
+		DebugStream.closeDebugStream();
+		System.exit(0);
+	    }
+    }
+
+
+    static public String getGLIDirectoryPath()
+    {
+	return System.getProperty("user.dir") + File.separator;
+    }
+
+
+    static public String getGLIMetadataDirectoryPath()
+    {
+	return getGLIDirectoryPath() + "metadata" + File.separator;
+    }
+
+    
+    private class GEMSMenuBar
+	extends JMenuBar
+	implements ActionListener
+    {
+	private JMenu file = null;
+	private JMenu edit = null;
+	private JMenu help = null;
+
+	public JMenuItem file_exit   = null;
+	public JMenuItem file_new    = null;
+	public JMenuItem file_open   = null;
+	public JMenuItem file_save   = null;
+	public JMenuItem edit_copy   = null;
+	public JMenuItem edit_cut    = null;
+	public JMenuItem edit_paste  = null;
+	public JMenuItem help_help   = null;
+        public JMenuItem file_delete = null;
+        public JMenuItem file_preferences = null;
+	public GEMSMenuBar()
+	{
+	    file = new JMenu();
+	    file.setMnemonic(KeyEvent.VK_F);
+	    Dictionary.registerText(file, "Menu.File");
+
+	    file_exit = new JMenuItem();
+	    file_exit.addActionListener(this);
+	    file_exit.setMnemonic(KeyEvent.VK_X);
+	    Dictionary.registerText(file_exit, "Menu.File_Exit");
+
+	    file_new = new JMenuItem();
+	    file_new.addActionListener(this);
+	    file_new.setMnemonic(KeyEvent.VK_N);
+	    Dictionary.registerText(file_new, "Menu.File_New");
+
+	    file_open = new JMenuItem();
+	    file_open.addActionListener(this);
+	    file_open.setMnemonic(KeyEvent.VK_O);
+	    Dictionary.registerText(file_open, "Menu.File_Open");
+
+	    file_save = new JMenuItem();
+	    file_save.addActionListener(this);
+	    file_save.setMnemonic(KeyEvent.VK_S);
+            Dictionary.registerText(file_save, "Menu.File_Save");
+            
+            file_delete = new JMenuItem();
+	    file_delete.addActionListener(new KeyPressedHandler()); //KeyPressedHandler handles deleting stuff.
+	    file_delete.setMnemonic(KeyEvent.VK_S);
+            Dictionary.registerText(file_delete, "Menu.File_Delete");
+            
+            file_preferences = new JMenuItem();
+	    file_preferences.addActionListener(this);
+	    file_preferences.setMnemonic(KeyEvent.VK_S);
+            Dictionary.registerText(file_preferences, "Menu.File_Options");
+
+	    // Layout (file menu)
+	    file.add(file_new);
+	    file.add(file_open);
+	    file.add(file_save);
+            file.add(file_delete);
+	    file.add(new JSeparator());
+            file.add(file_preferences);
+            file.add(new JSeparator());
+	    file.add(file_exit);
+            
+	    // Edit menu
+	    edit = new JMenu();
+	    edit.setMnemonic(KeyEvent.VK_E);
+	    Dictionary.registerText(edit, "Menu.Edit");
+
+	    edit_cut = new JMenuItem();
+	    edit_cut.addActionListener(this);
+	    edit_cut.setMnemonic(KeyEvent.VK_X);
+	    Dictionary.registerText(edit_cut, "Menu.Edit_Cut");
+
+	    edit_copy = new JMenuItem();
+	    edit_copy.addActionListener(this);
+	    edit_copy.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.registerText(edit_copy, "Menu.Edit_Copy");
+
+	    edit_paste = new JMenuItem();
+	    edit_paste.addActionListener(this);
+	    edit_paste.setMnemonic(KeyEvent.VK_V);
+	    Dictionary.registerText(edit_paste, "Menu.Edit_Paste");
+
+	    // Layout (edit menu)
+	    edit.add(edit_cut);
+	    edit.add(edit_copy);
+	    edit.add(edit_paste);
+
+	    // Help menu. Is not used! --Matthew
+	    // help = new JMenu();
+	    // help.setIcon(JarTools.getImage("help.gif"));
+	    // Dictionary.setText(help, "Menu.Help");
+
+	    //help_help = new JMenuItem();
+	    //help_help.addActionListener(this);
+	    //Dictionary.registerText(help_help, "Menu.Help");
+
+	    // Layout (help menu)
+	    //help.add(help_help);
+
+	    // Layout (menu bar)
+	    this.add(file);
+	    this.add(Box.createHorizontalStrut(15));
+	    this.add(edit);
+	    this.add(Box.createHorizontalGlue());
+	    //this.add(help);
+	}
+
+
+	public void actionPerformed(ActionEvent event)
+	{
+	    Object event_source = event.getSource();
+
+	    // File -> New
+	    if (event_source == file_new) {
+		AddSetActionListener rah = new AddSetActionListener();
+		rah.setVisible(true);
+		// rah.show();
+	 
+		return;
+	    }
+
+	    // File -> Open
+	    if (event_source == file_open) {
+                
+                //we first launch the dialog to determine where the jfilechooser should be opened
+                //ie: for collection specific sets - attila dec10-04
+                String set_directory = getGLIMetadataDirectoryPath();
+                
+                SetSelectionDialog m = new SetSelectionDialog();
+		m.setVisible(true);
+                // m.show();
+                    
+                //once we have clicked 'ok' on the jdialog above, then we should have
+                //the directory pointer in string set_directory...and pass it to the jfilechoose constru
+		return;
+	    }
+
+	    // File -> Save
+	    if (event_source == file_save) {
+		msm.save();
+                atLeastOneSetChanged = false;
+		return;
+	    }
+
+	    // File -> Exit
+	    if (event_source == file_exit) {
+                exit(); //The exit() method checks if data needs saving.
+	    }
+
+	    // File -> Preferences
+            if(event_source == file_preferences){
+              GEMSPreferences GemsPreferences = new GEMSPreferences();  
+            }
+
+	    // Edit -> Cut
+	    if (event_source == edit_cut) {
+		try {
+		    KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+		    // Get the component with selected text as a JTextComponent
+		    JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
+		    // Cut the text to the clipboard
+		    text.cut();
+		}
+		catch (ClassCastException cce) {
+		    // If the component is not a text component ignore the cut command
+		    DebugStream.println(cce.toString());
+		}
+		return;
+	    }
+
+	    // Edit -> Copy
+	    if (event_source == edit_copy) {
+		try {
+		    KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+		    // Get the component with selected text as a JTextComponent
+		    JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();//getFocusOwner();
+		    text.copy();
+		}
+		catch (Exception cce) {
+		    // If the component is not a text component ignore the copy command
+		    DebugStream.println(cce.toString());
+		}
+		return;
+	    }
+
+	    // Edit -> Paste
+	    if (event_source == edit_paste) {
+		try {
+		    KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+		    // Get the component with selected text as a JTextComponent
+		    JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
+		    // Cut the text to the clipboard
+		    text.paste();
+		}
+		catch (ClassCastException cce) {
+		    // If the component is not a text component ignore the paste command
+		    DebugStream.println(cce.toString());
+		}
+		return;
+	    }
+
+	    // Help -> Help
+	    if (event_source == help_help) {
+		HelpFrame.setView("editingmetadatasets");
+		return;
+	    }
+	}
+    }
+
+
+    private class MetadataSetFileFilter
+	extends FileFilter
+    {
+	public boolean accept(File file)
+	{
+	    String file_name = file.getName().toLowerCase();
+	    return(file_name.endsWith(".mds") || file_name.indexOf(".") == -1);
+	}
+
+	public String getDescription()
+	{
+	    return Dictionary.get("MetadataSet.Files");
+	}
+    }
+
+
+    private class ActionTask
+	extends Thread {
+	private int action;
+	public ActionTask(int action) {
+	    this.action = action;
+	}
+	public void run() {
+	    boolean complete = false;
+	    while(!complete) {
+		if(self.isVisible()) {
+		    switch(action) {
+		    case ADD_SET:
+			add_set_action_listener.actionPerformed(new ActionEvent(this, 0, "Blarg!"));
+			break;
+		    case REMOVE_SET:
+			if(!mds_tree.isSelectionEmpty()) {
+			    remove_set_action_listener.actionPerformed(new ActionEvent(this, 0, "Blarg!"));
+			}
+			break;
+		    }
+		    complete = true;
+		}
+		else {
+		    try {
+			synchronized(this) {
+			    wait(100);
+			}
+		    }
+		    catch(Exception exception) {
+		    }
+		}
+	    }
+	}
+    }
+    //callback method
+     protected void processWindowEvent(WindowEvent evt){
+       
+       if(evt.getID() == WindowEvent.WINDOW_CLOSING){
+           
+          exit();
+       }
+   }
+   //called from MetadataSetManager...I don't think it should be here anymore, but for now it's ok
+ 
+   public void warn_cant_load_set(){
+            JOptionPane.showMessageDialog(self, Dictionary.get("GEMS.Already_Loaded_Set_Error"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+        }
+    public void dispose() {
+        
+        
+         //if anything has changed, warn user that they should save
+        if(atLeastOneSetChanged == true) {
+            
+            int result = JOptionPane.showOptionDialog(self, Dictionary.get("GEMS.Confirm_Exit_Save", Dictionary.get("GEMS.Element")), Dictionary.get("GEMS.Confirm_Exit_Save_Title"), JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, dialog_options, dialog_options[0]);
+         //   System.out.println("Exit: "+result);
+            if(result == 0) {
+                msm.save();
+            }
+        }
+        atLeastOneSetChanged = false;
+	// Destructor
+	card_layout = null;
+	screen_size = null;
+	self = null;
+	details_pane = null;
+	element_attributes = null;
+	set_attributes = null;
+	set_name = null;
+	mds_tree = null;
+        
+        popupListener = null;
+	// Dispose of inner dialogs
+	if (add_element_action_listener != null) {
+	    add_element_action_listener.dispose();
+	    add_element_action_listener = null;
+	}
+	if (add_or_edit_attribute_action_listener != null) {
+	    add_or_edit_attribute_action_listener.dispose();
+	    add_or_edit_attribute_action_listener = null;
+	}
+	remove_set_action_listener = null;
+
+        //close
+	super.dispose();
+    }
+
+
+    /**
+       Class to handle adding or modifying element attributes.
+     */
+    private class AddOrEditAttributeActionListener
+	extends ModalDialog
+	implements ActionListener, MouseListener {
+	private boolean add_type = true;
+	private ComboArea value = null;
+	private JButton cancel_button = null;
+	private JButton ok_button = null;
+	private JComboBox language_box = null;
+	private GComboBox name = null;
+	private HashMap name_to_values = null;
+	private JLabel target = null;
+	private JLabel target_label = null;
+	private Vector attributeLists = null;      
+
+	org.w3c.dom.Document lang = XMLTools.parseXMLFile(getGLIDirectoryPath() + "classes" + File.separator + "xml" + File.separator + "languages.xml", false);
+	
+	/** Constructor. */
+	public AddOrEditAttributeActionListener() {
+	    super(self);
+	    setModal(true);
+            attributeLists = new Vector();
+            attributeLists.add("identifier");
+            attributeLists.add("comment");
+            attributeLists.add("definition");
+            attributeLists.add("name");
+
+            attributeLists.add("creator");
+            attributeLists.add("date");
+            attributeLists.add("contact");
+            attributeLists.add("family");
+            
+            attributeLists.add("lastchanged");
+            attributeLists.add("language_dependant");
+            attributeLists.add("version");
+            attributeLists.add("datatype");
+            
+            attributeLists.add("obligation");
+            attributeLists.add("maximum_occurence");
+            attributeLists.add("registration_authority");
+            
+	    setSize(ADD_OR_EDIT_ATTRIBUTE_SIZE);
+	    name_to_values = new HashMap();
+
+	    // Creation
+	    JPanel content_pane = (JPanel) getContentPane();
+	    content_pane.setBackground(config.getColor("coloring.collection_heading_background", false));
+	    JPanel upper_pane = new JPanel();
+	    upper_pane.setOpaque(false);
+
+	    JPanel labels_pane = new JPanel();
+	    JPanel boxes_pane = new JPanel();
+
+	    target_label = new JLabel();
+	    target_label.setOpaque(false);
+	    target = new JLabel();
+	    target.setOpaque(false);
+
+	    JLabel name_label = new JLabel();
+	    name_label.setOpaque(false);
+	    Dictionary.setText(name_label, "GEMS.Name");
+	    name = new GComboBox();
+	    name.setEditable(true);
+	    Dictionary.setTooltip(name, "GEMS.Attribute_Name_Tooltip");
+
+	    JLabel language_label = new JLabel();
+	    language_label.setOpaque(false);
+	    Dictionary.setText(language_label, "GEMS.Language");
+	    language_box = new JComboBox();
+            
+            for(int n = 0; n < attributeLists.size(); n++){
+                name.add(attributeLists.get(n));
+            }
+ 
+	    Dictionary.setTooltip(language_box, "GEMS.Attribute_Language_Tooltip");
+
+	    JPanel center_pane = new JPanel();
+	    center_pane.setOpaque(false);
+	    value = new ComboArea(Dictionary.get("GEMS.Values"), COMPONENT_SIZE);
+	    value.setOpaque(false);
+
+	    JTextArea v_text_area = (JTextArea) value.getTextComponent();
+	    v_text_area.setBackground(config.getColor("coloring.collection_tree_background", false));
+	    v_text_area.setForeground(config.getColor("coloring.collection_tree_foreground", false));
+	    v_text_area.setSelectionColor(config.getColor("coloring.collection_selection_background", false));
+	    v_text_area.setSelectedTextColor(config.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.setTooltip(v_text_area, "GEMS.Attribute_Value_Tooltip");
+
+	    JPanel button_pane = new JPanel();
+	    button_pane.setOpaque(false);
+	    ok_button = new GLIButton();
+	    ok_button.setMnemonic(KeyEvent.VK_O);
+	    getRootPane().setDefaultButton(ok_button);
+	    Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	    cancel_button = new GLIButton();
+	    cancel_button.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+
+	    // Connection
+	    TextFieldEnabler ok_button_enabler = new TextFieldEnabler(ok_button);
+	    cancel_button.addActionListener(this);
+	    name.addActionListener(this);
+	    ok_button.addActionListener(this);
+	    ok_button_enabler.add((JTextComponent)name.getEditor()); // Assuming the default editor is a JTextField!
+
+	    // Layout
+	    labels_pane.setLayout(new GridLayout(3,1,0,5));
+	    labels_pane.add(target_label);
+	    labels_pane.add(name_label);
+	    labels_pane.add(language_label);
+
+	    boxes_pane.setLayout(new GridLayout(3,1,0,5));
+	    boxes_pane.add(target);
+	    boxes_pane.add(name);
+	    boxes_pane.add(language_box);
+	    
+	    upper_pane.setLayout(new BorderLayout(5,0));
+	    upper_pane.add(labels_pane, BorderLayout.WEST);
+	    upper_pane.add(boxes_pane, BorderLayout.CENTER);
+
+	    value.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+
+	    button_pane.setLayout(new GridLayout(1,2,5,0));
+	    button_pane.add(ok_button);
+	    button_pane.add(cancel_button);
+
+	    center_pane.setLayout(new BorderLayout());
+	    center_pane.add(value, BorderLayout.CENTER);
+	    center_pane.add(button_pane, BorderLayout.SOUTH);
+
+	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(upper_pane, BorderLayout.NORTH);
+	    content_pane.add(center_pane, BorderLayout.CENTER);
+
+	    setLocation((config.screen_size.width - ADD_OR_EDIT_ATTRIBUTE_SIZE.width) / 2, (config.screen_size.height - ADD_OR_EDIT_ATTRIBUTE_SIZE.height) / 2);
+
+	    GEMSLanguageManager GemsLangManager = new GEMSLanguageManager(getGLIDirectoryPath() + "classes" + File.separator + "xml" + File.separator + "languages.xml");
+        
+            Vector languagecodes = GemsLangManager.getLanguageCodes();
+            
+            for(int p = 0; p < languagecodes.size(); p++){
+             
+                language_box.addItem(languagecodes.get(p).toString());
+            }
+           
+           String code = Configuration.getLanguage();
+           language_box.setSelectedItem(code);
+        }
+
+       //Handle double clicks in the table.
+       public void mouseClicked(MouseEvent e)
+	{
+	    if(e.getSource() == element_attributes || e.getSource() == set_attributes)
+		{
+		    if(e.getClickCount() == 2) //Double click
+			{
+			    //Show the Edit Attribute dialog
+			    this.menuEditValue();
+			    this.editAttribute();
+			}
+		}
+	}
+	//These methods are required by interface MouseListener
+	public void mouseEntered(MouseEvent e){}
+	public void mouseExited(MouseEvent e){}
+	public void mousePressed(MouseEvent e){}
+	public void mouseReleased(MouseEvent e){}
+
+	/** Any implementation of ActionListener must include this method so that we can be informed when an action as occured on our registered component, allowing us to add a new attribute to the selected set or element.
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    Object source = event.getSource();
+	    AttributeTableModel model = null;
+           
+	    if(current_element != null)
+		{
+		    target.setText(current_element.getName());
+		    Dictionary.setText(target_label, "GEMS.Target");
+		}
+	    else if(current_set != null)
+		{
+		    Dictionary.setText(target_label, "GEMS.Set");
+		    target.setText(current_set.toString());
+		    Dictionary.setText(target_label, "GEMS.Target");
+		}
+	    
+	     if (source == popupListener.menuEditValue)
+		 {
+		     this.menuEditValue();              
+		 }
+ 
+            if(source == ok_button) {
+		boolean success = true;
+
+		// Add or edit a set/element attribute
+		switch(current_attribute_type) {
+		case GEMSNode.SET:
+		    model = (AttributeTableModel) set_attributes.getModel();
+		    success = addOrEditSetAttribute(model);
+		    break;
+		case GEMSNode.ELEMENT:
+		    model = (AttributeTableModel) element_attributes.getModel();
+		    success = addOrEditElementAttribute(model);
+		    break;
+		}
+                 
+		if (success) {
+		    // Hide dialog
+		    atLeastOneSetChanged = true;
+		    setVisible(false);
+                    return;
+		}
+		else
+		    {
+			//If no success (an attribute with that name already exists), do nothing.
+		    }
+	    }
+	    else if(source == cancel_button) {
+		// Hide dialog
+		setVisible(false);
+                return;
+	    }
+	    else if(source == name) {
+		//System.err.println("source is name");
+                Object object = name.getSelectedItem();
+		if(object != null) {
+		    java.util.List values = (java.util.List) name_to_values.get(object.toString());
+                    
+                    if(value != null && values != null){
+                        value.clear();
+                        for(int i = 0; i < values.size(); i++) {
+                            value.add(values.get(i));
+                        }
+                    }
+		}
+	    }
+	    else if (source == popupListener.menuAddAttributeAttribute || source == popupListener.menuAddAttributeSet || source == popupListener.menuAddAttributeElement){
+
+		Dictionary.setText(this, "GEMS.Add_Attribute");
+		for(int i = 0; i < attributeLists.size(); i++) {
+		    name.add(attributeLists.get(i).toString());    
+                    
+		}
+		name.setEnabled(true);
+		setVisible(true);
+            }
+           
+		else if(current_attribute != -1) {
+		    this.editAttribute();
+		}
+
+	    source = null;
+	}
+
+       private void menuEditValue()
+       {
+	   AttributeTableModel tablemodel = null;
+	  
+	   String prevLang = new String("");
+	   String prevValue = new String("");
+
+	   add_type = false;
+	   //grab the table model based on what is currently selected
+	   switch(current_attribute_type) {
+	   case GEMSNode.SET:
+	       tablemodel = (AttributeTableModel) set_attributes.getModel();
+	       //grab value in table
+	       prevLang =  tablemodel.getValueAt(current_attribute,0).toString();
+	       prevValue = tablemodel.getValueAt(current_attribute,1).toString();
+	       
+	       break;
+	   case GEMSNode.ELEMENT:
+	       tablemodel = (AttributeTableModel) element_attributes.getModel();
+	       //grab values in table( lang and value)
+	       prevLang =  tablemodel.getValueAt(current_attribute,1).toString();
+	       prevValue = tablemodel.getValueAt(current_attribute,2).toString();
+	       
+	       break;
+	   default:
+	       //by default grab element_attr's
+	       tablemodel = (AttributeTableModel) element_attributes.getModel();
+	       prevLang =  tablemodel.getValueAt(current_attribute,1).toString();
+	       prevValue = tablemodel.getValueAt(current_attribute,2).toString();
+	       
+	       break;
+	   }         
+	   language_box.setEnabled(false);
+	   
+           //if a set attr is selected, then do not do any lang operations, other than setting index to -1
+	   if(current_attribute_type != GEMSNode.SET) {
+	       
+	       //set the current language to show up in language_box(no lang if no lang specified)
+	       if(prevLang == null || prevLang.compareTo(" ")==0 || prevLang.compareTo("") == 0 || prevLang.compareTo("  ")==0) {
+		   language_box.setSelectedIndex(-1);
+		   
+	       }
+	       else {
+		   language_box.setSelectedItem(prevLang.toLowerCase());
+	       }
+	   }// end currattr != GEMSnode.set
+	   else {
+	       
+	       language_box.setSelectedIndex(-1);
+	       
+	   }// end currattr == GEMSnode.set
+	   value.setText(prevValue);
+       }
+
+       private void editAttribute()
+       {
+	   //System.err.println("just entered editAttribute"); //debug
+	   AttributeTableModel model = null;
+	   Dictionary.setText(this, "GEMS.Edit_Attribute");
+	   
+	   switch(current_attribute_type) {
+	   case GEMSNode.ELEMENT:
+	       model = (AttributeTableModel) element_attributes.getModel();
+	       break;
+	   case GEMSNode.SET:
+	       model = (AttributeTableModel) set_attributes.getModel();
+	       break;
+	   }
+	   add_type = false;
+	   String name_str = (String) model.getValueAt(current_attribute, 0);
+	   String value_str = (String) model.getValueAt(current_attribute, model.getColumnCount() - 1);
+	   model = null;
+	   // Retrieve the appropriate value model
+	   java.util.List values = (java.util.List) name_to_values.get(name_str);
+	   // Only possible for collection file selections.
+	   if(values == null) {
+	       values = msm.getElements();
+	   }
+	   name.setSelectedItem(name_str);
+	   name_str = null;
+	   for(int i = 0; i < values.size(); i++) {
+	       Object temp_value = values.get(i);
+	       if(temp_value instanceof ElementWrapper) {
+		   value.add(new NameElementWrapperEntry(temp_value));
+	       }
+	       else {
+		   value.add(temp_value);
+	       }
+	   }
+	   values = null;
+	   value.setSelectedItem(value_str);
+	   value_str = null;
+	   setVisible(true);   
+       }
+
+	private boolean addOrEditSetAttribute(AttributeTableModel model)
+	{
+	    String new_name_str = name.getSelectedItem().toString();
+	    String value_str = Codec.transform(Codec.transformUnicode(value.getText()), Codec.TEXT_TO_DOM);
+	    String language_code = (String) language_box.getSelectedItem();
+	    String old_name_str = null;
+	    boolean cont = false;
+	    boolean edit = false;
+
+	    if(!add_type && current_attribute != -1) //If edit, grab the attribute's old name
+		{
+		    old_name_str = (String) set_attributes.getValueAt(current_attribute, 0);
+		    edit = true;
+		}
+
+	    // Check that there isn't already an entry for this attribute
+	    if (!model.contains(new_name_str, language_code) || (edit && new_name_str.equals(old_name_str)))
+		{
+		    if(edit) //If edit, remove old attribute
+			{ 
+			    current_set.removeAttribute(old_name_str);
+			    model.removeRow(current_attribute);
+			}
+		    
+		    // Add the new attribute
+		    current_set.addAttribute(new_name_str, value_str);
+		    // Update the attribute table
+		    model.add(new Attribute(new_name_str, value_str));
+		    cont = true;
+		}
+	    // Otherwise show an error message and do not proceed
+	    else
+		{
+		    cont = false;
+		    JOptionPane.showMessageDialog(self,
+						  Dictionary.get("GEMS.Attribute_Already_Exists"),
+						  Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		}
+       
+	    value_str = null;
+	    new_name_str = null;
+	    return cont;
+	}
+
+
+	private boolean addOrEditElementAttribute(AttributeTableModel model)
+	{
+	    String new_name_str = name.getSelectedItem().toString();
+	    String old_name_str = null;
+	    String language_code = (String) language_box.getSelectedItem();
+	    String value_str = Codec.transform(Codec.transformUnicode(value.getText()), Codec.TEXT_TO_DOM);
+	    String old_value_str = null;
+	    String old_lang_code = null;
+	    boolean cont = false;
+	    boolean edit = false;
+
+	    if(!add_type && current_attribute != -1) //An edit
+		{
+		    Attribute old_attribute = model.getAttribute(current_attribute);
+		    old_value_str = old_attribute.value;
+		    old_lang_code = old_attribute.language;
+		    old_name_str = (String) element_attributes.getValueAt(current_attribute, 0); //get the old name.
+		    edit = true;
+		}
+
+	    //Check that there isn't already an entry for this attribute
+	    if (!model.contains(new_name_str, language_code) || (edit && new_name_str.equals(old_name_str)))
+		{
+		    if(edit) //If this is an edit, remove the old attribute
+			{
+			    current_element.removeAttribute(old_name_str, old_lang_code, old_value_str);
+			    model.removeRow(current_attribute);
+			}
+
+		    // Add the new attribute
+		    //System.err.println("current_element is: " + current_element.toString()); //debug
+		    current_element.addAttribute(new_name_str, language_code, value_str);
+		    // Update the attribute table
+		    int row = model.add(new Attribute(new_name_str, language_code, value_str));
+		    element_attributes.setRowSelectionInterval(row, row);
+		    cont = true;
+		}
+	    // Otherwise show an error message and do not proceed
+	    else
+		{
+		    cont = false;
+		    JOptionPane.showMessageDialog(self,
+						  Dictionary.get("GEMS.Attribute_Already_Exists"),
+						  Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		} 
+	
+	    value_str = null;
+	    language_code = null;
+	    new_name_str = null;
+	    return cont;
+	}
+    }
+
+   
+    private class AddSubelementActionListener extends AddElementActionListener implements ActionListener {
+
+	public AddSubelementActionListener() {
+	    Dictionary.setText(this, "GEMS.Add_Subelement");
+	    Dictionary.setTooltip(name_field, "GEMS.Subelement_Name_Tooltip");
+	}
+
+	public void actionPerformed(ActionEvent event)
+	{
+	    Object source = event.getSource();
+	    current_element = current_node.getElement(); //current_element here is used generically for a element or subelement.
+
+	    if(source == ok_button) //Add then dispose
+		{
+		    String name_str = Codec.transform(Codec.transformUnicode(name_field.getText()), Codec.TEXT_TO_DOM);
+		    current_set = msm.getSet(current_element.getNamespace());
+		    if(current_set != null)
+			{
+			     // If this subelement doesn't already exist.
+			    if(!current_element.containsSubelement(name_str))
+				{
+				    // Add it,
+				    String language_code = config.getLanguage();
+				    ElementWrapper subelement = current_set.addElement(name_str, language_code, current_node);
+
+				    final GEMSNode new_node = model.add(current_node, subelement, GEMSNode.ELEMENT); //Then update the tree.
+				   
+				    //SwingUtilities.invokeLater is used so that expandPath works on new parents.
+				    SwingUtilities.invokeLater(new Runnable() {
+					    public void run() {
+						mds_tree.expandPath(new TreePath(current_node.getPath())); //Expand element so can see subelement.
+						mds_tree.getSelectionModel().setSelectionPath(new TreePath(new_node)); //works, but node on tree doesn't look hilighted!
+					    }
+					});
+
+				    //Done. Finish up.
+				    subelement = null;
+				    setVisible(false);
+				    atLeastOneSetChanged = true; //mark as changed
+				}
+			    else
+				{
+				    //A subelement with the same name exists. Display an error message.
+				    JOptionPane.showMessageDialog(self, Dictionary.get("GEMS.Subelement_Already_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+				}
+			}
+		    else
+			{
+			    //This should not happen.
+			    System.err.println("Error: current_set is null in AddSubelementActionListener");
+			}
+		}
+	    else if(source == cancel_button)
+		{
+		    setVisible(false);
+		}
+	    else
+		{
+		    set_field.setText(current_node.toString()); //set to the name of the subelement
+		    name_field.setText("");
+		    setVisible(true);
+		}
+	}
+
+	public void dispose()
+	{
+	    cancel_button = null;
+	    ok_button = null;
+	    name_field = null;
+	    set_field = null;
+	    super.dispose();
+	}
+    }
+
+
+    private class AddElementActionListener
+	extends ModalDialog
+	implements ActionListener {
+	protected JButton cancel_button = null;
+	protected JButton ok_button = null;
+	protected JLabel set_field = null;
+	protected NonWhitespaceField name_field = null;
+	public AddElementActionListener() {
+	    super(self);
+	    setModal(true);
+	    setSize(ADD_ELEMENT_SIZE);
+	    // Creation
+	    JPanel content_pane = (JPanel) getContentPane();
+	    content_pane.setBackground(config.getColor("coloring.collection_heading_background", false));
+	    JPanel center_pane = new JPanel();
+	    center_pane.setOpaque(false);
+	    Dictionary.setText(this, "GEMS.Add_Element");
+
+	    JPanel labels_pane = new JPanel();
+	    labels_pane.setOpaque(false);
+	    JLabel set_label = new JLabel();
+	    set_label.setOpaque(false);
+	    Dictionary.setText(set_label, "GEMS.Set");
+	    set_field = new JLabel();
+	    set_field.setOpaque(false);
+
+	    JPanel values_pane = new JPanel();
+	    values_pane.setOpaque(false);
+	    JLabel name_label = new JLabel();
+	    name_label.setOpaque(false);
+	    Dictionary.setText(name_label, "GEMS.Name");
+	    name_field = new NonWhitespaceField();
+	    name_field.setBackground(config.getColor("coloring.collection_tree_background", false));
+	    name_field.setForeground(config.getColor("coloring.collection_tree_foreground", false));
+	    name_field.setSelectionColor(config.getColor("coloring.collection_selection_background", false));
+	    name_field.setSelectedTextColor(config.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.setTooltip(name_field, "GEMS.Element_Name_Tooltip");
+
+	    JPanel button_pane = new JPanel();
+	    button_pane.setOpaque(false);
+
+	    ok_button = new GLIButton();
+	    ok_button.setMnemonic(KeyEvent.VK_O);
+	    getRootPane().setDefaultButton(ok_button);
+	    Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	    cancel_button = new GLIButton();
+	    cancel_button.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+
+	    TextFieldEnabler ok_button_enabler = new TextFieldEnabler(ok_button);
+
+	    // Connection
+	    cancel_button.addActionListener(this);
+	    ok_button.addActionListener(this);
+	    ok_button_enabler.add(name_field);
+
+	    // Layout
+	    labels_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    labels_pane.setLayout(new GridLayout(2,1));
+	    labels_pane.add(set_label);
+	    labels_pane.add(name_label);
+
+	    values_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    values_pane.setLayout(new GridLayout(2,1));
+	    values_pane.add(set_field);
+	    values_pane.add(name_field);
+
+	    center_pane.setLayout(new BorderLayout(5,5));
+	    center_pane.add(labels_pane, BorderLayout.WEST);
+	    center_pane.add(values_pane, BorderLayout.CENTER);
+
+	    button_pane.setLayout(new GridLayout(1,2,0,5));
+	    button_pane.add(ok_button);
+	    button_pane.add(cancel_button);
+
+	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(center_pane, BorderLayout.CENTER);
+	    content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	    setLocation((config.screen_size.width - ADD_ELEMENT_SIZE.width) / 2, (config.screen_size.height - ADD_ELEMENT_SIZE.height) / 2);
+	}
+
+	/** Any implementation of ActionListener must include this method so that we can be informed when an action as occured on our registered component, allowing us to
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    Object source = event.getSource();
+	    if(source == ok_button) {
+		// Add then dispose
+		String name_str = Codec.transform(Codec.transformUnicode(name_field.getText()), Codec.TEXT_TO_DOM);
+		// If this element doesn't already exist.
+		if(!current_set.containsElement(name_str)) {
+		    // Add it,
+		    String language_code = config.getLanguage();
+		    ElementWrapper element = current_set.addElement(name_str, language_code, null);
+
+		    // Then update the tree
+		    model.add(current_node, element, GEMSNode.ELEMENT);
+		    //SwingUtilities.invokeLater is used so that expandPath works on new parents.
+		    SwingUtilities.invokeLater(new Runnable() {
+			    public void run() {
+				mds_tree.expandPath(new TreePath(current_node.getPath())); //expand set.
+			    }
+			});
+		    
+		    // Done
+		    element = null;
+		    setVisible(false);
+                    
+                    //mark as changed
+                    atLeastOneSetChanged = true;
+                    current_set.setSetChanged(true);
+                 
+		}
+		// Otherwise show an error message and do not proceed.
+		else {
+		    JOptionPane.showMessageDialog(self, Dictionary.get("GEMS.Element_Already_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		}
+		name_str = null;
+	    }
+	    else if(source == cancel_button) {
+		// Dispose
+		setVisible(false);
+	    }
+	    else {
+		if(current_set != null) { //Does this ever happen? --Matthew
+		    // You can't manually add elements to the Greenstone metadata set.
+		    if(!current_set.getNamespace().equals("")) {
+			set_field.setText(current_set.toString());
+			name_field.setText("");
+			// Display
+			setVisible(true);
+		    }
+		    // Warn the user that they can't do that dave. 
+		    else {
+                        
+			JOptionPane.showMessageDialog(self, Dictionary.get("GEMS.Cannot_Add_Elements_To_Greenstone_MDS"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		    }
+		}
+	    }
+	    source = null;
+	}
+ 
+	public void dispose() {
+	    cancel_button = null;
+	    ok_button = null;
+	    name_field = null;
+	    set_field = null;
+	    super.dispose();
+	}
+    }
+	 
+   
+    private class AddSetActionListener
+	extends ModalDialog
+	implements ActionListener {
+	private JButton cancel_button = null;
+	private JButton ok_button = null;
+	private JTextField name_field = null;
+	private JTextField namespace_field = null;
+        private JComboBox existingSetJComboBox = new JComboBox();
+            
+	public AddSetActionListener() {
+	    super(self);
+	    setModal(true);
+	    setSize(ADD_SET_SIZE);
+	    Dictionary.setText(this, "GEMS.Add_Set");
+
+	    // Creation
+	    JPanel content_pane = (JPanel) getContentPane();
+	    content_pane.setBackground(config.getColor("coloring.collection_heading_background", false));
+	    JPanel center_pane = new JPanel();
+	    center_pane.setOpaque(false);
+
+	    JPanel label_pane = new JPanel();
+	    JPanel boxes_pane = new JPanel();
+
+	    JLabel namespace_label = new JLabel();
+	    namespace_label.setOpaque(false);
+	    Dictionary.setText(namespace_label, "GEMS.Namespace");
+	    namespace_field = TransformCharacterTextField.createNamespaceTextField();
+	    namespace_field.setBackground(config.getColor("coloring.collection_tree_background", false));
+	    namespace_field.setForeground(config.getColor("coloring.collection_tree_foreground", false));
+	    namespace_field.setSelectionColor(config.getColor("coloring.collection_selection_background", false));
+	    namespace_field.setSelectedTextColor(config.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.setTooltip(namespace_field, "GEMS.Set_Namespace_Tooltip");
+
+	    JLabel name_label = new JLabel();
+	    name_label.setOpaque(false);
+	    Dictionary.setText(name_label, "GEMS.Name");
+	    name_field = new JTextField();
+	    name_field.setBackground(config.getColor("coloring.collection_tree_background", false));
+	    name_field.setForeground(config.getColor("coloring.collection_tree_foreground", false));
+	    name_field.setSelectionColor(config.getColor("coloring.collection_selection_background", false));
+	    name_field.setSelectedTextColor(config.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.setTooltip(name_field, "GEMS.Set_Name_Tooltip");
+
+	    JPanel button_pane = new JPanel();
+	    button_pane.setOpaque(false);
+
+	    ok_button = new GLIButton();
+	    ok_button.setMnemonic(KeyEvent.VK_O);
+	    getRootPane().setDefaultButton(ok_button);
+	    Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	    cancel_button = new GLIButton();
+	    cancel_button.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+	    TextFieldEnabler ok_button_enabler = new TextFieldEnabler(ok_button);
+
+	    // Connection
+	    cancel_button.addActionListener(this);
+	    ok_button.addActionListener(this);
+	    ok_button_enabler.add(name_field);
+	    ok_button_enabler.add(namespace_field);
+
+	    // Layout
+	    label_pane.setLayout(new GridLayout(3,1));
+	    label_pane.add(name_label);
+	    label_pane.add(namespace_label);
+            boxes_pane.setLayout(new GridLayout(3,1));
+	    boxes_pane.add(name_field);
+	    boxes_pane.add(namespace_field);
+            
+            JLabel inheritJLabel = new JLabel(); 
+            Dictionary.setText(inheritJLabel, "GEMS.inheritMetadataSet");
+	   
+            label_pane.add(inheritJLabel);
+	    
+            int getSetsLen = msm.getSets().toArray().length;
+            Vector theSets = msm.getSets();
+            
+            for(int k = 0; k < theSets.size(); k++){
+                MetadataSet ms = (MetadataSet)theSets.elementAt(k);
+                
+                existingSetJComboBox.addItem(new String(ms.getName() + "                                                                             #% " + ms.getFile().toString()));
+                
+            }
+            //add sets to existingSetJComboBox
+            
+            JLabel dummyl = new JLabel();
+            Dictionary.setText(dummyl, "GEMS.Add_Set.No_Inherit");
+            
+            existingSetJComboBox.addItem("Do not inherit");
+            existingSetJComboBox.setSelectedIndex(getSetsLen);
+            boxes_pane.add(existingSetJComboBox);
+             
+	    center_pane.setLayout(new BorderLayout(5,0));
+	    center_pane.add(label_pane, BorderLayout.WEST);
+	    center_pane.add(boxes_pane, BorderLayout.CENTER);
+
+	    button_pane.setLayout(new GridLayout(1,2,0,5));
+	    button_pane.add(ok_button);
+	    button_pane.add(cancel_button);
+
+	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(center_pane, BorderLayout.CENTER);
+	    content_pane.add(button_pane, BorderLayout.SOUTH);
+         
+	    setLocation((config.screen_size.width - ADD_SET_SIZE.width) / 2, (config.screen_size.height - ADD_SET_SIZE.height) / 2);
+	}
+
+        private boolean a_set_exists_with_this_namespace(String namespace){
+            Vector p = msm.getSets();
+            boolean flag = false;
+            for(int k = 0; k < p.size(); k++){
+                MetadataSet s = (MetadataSet)p.get(k);
+                
+                if(s.getNamespace().compareTo(namespace) == 0){
+                    flag = true;     
+                }
+            }
+            
+            return flag;
+        }
+
+
+	/** Any implementation of ActionListener must include this method so that we can be informed when an action as occured on our registered component, allowing us to
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    Object source = event.getSource();
+            
+	    if(source == ok_button) {
+                //this code below handles whether we inherit from an existing set or not
+             
+                String namespace_str = namespace_field.getText();
+		String name_str = Codec.transform(Codec.transformUnicode(name_field.getText()), Codec.TEXT_TO_DOM);
+		
+                if (existingSetJComboBox.getSelectedItem().toString().trim().compareTo("Do not inherit") == 0){
+
+		// Ensure the set doesn't already exist
+                if(a_set_exists_with_this_namespace(namespace_str) == false){
+	   
+		    MetadataSet set = msm.addSet(namespace_str, name_str);
+                    
+                    //mark as set changed = true
+                    set.setSetChanged(true);
+                    atLeastOneSetChanged = true;
+                    
+		    // Update tree.
+		    model.add(null, set, GEMSNode.SET);
+		    // Done
+		    set = null;
+		    setVisible(false);
+                    
+		}
+                else{
+                       JOptionPane.showMessageDialog(self, Dictionary.get("GEMS.Set_Already_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+                }
+                
+		name_str = null;
+		namespace_str = null;
+                }//end do not inherit
+                else {
+		    //Should change this to use XML parsing utilites --Matthew
+                    //lets grab the metadata we want to inherit from...
+                    String anitem = existingSetJComboBox.getSelectedItem().toString();
+                   
+                    if(a_set_exists_with_this_namespace(namespace_field.getText()) == false){
+                        //setup to read the filename from mds file
+			String [] items = anitem.split("#%");
+                        try {
+			    FileInputStream fstream = new FileInputStream(items[1].trim());
+			    BufferedReader in = new BufferedReader(new InputStreamReader(fstream, "UTF8"));
+			    
+			    FileOutputStream out;
+			    PrintWriter p;
+			    //setup to write to filename from existing file
+			    try {
+				out = new FileOutputStream(getGLIMetadataDirectoryPath() + namespace_str + ".mds");
+				OutputStreamWriter pout = new OutputStreamWriter(out, "UTF8");
+				p = new PrintWriter(pout);
+				
+				while(in.ready()){
+				    String nextline = in.readLine();
+				    
+				    if(nextline.matches(".+namespace=\".+\".*") == true) {
+					nextline = nextline.replaceFirst("namespace=\".+\"","namespace=\"" + namespace_str+ "\"");                          
+				    }
+				    else {
+					nextline = nextline.replaceFirst(">.+</Name>",">" + name_str + "</Name>");
+				    }
+				    p.print(nextline + "\n");
+				}
+				p.close();
+				
+				MetadataSet loadedset = msm.loadMetadataSet(new File(getGLIMetadataDirectoryPath() + namespace_str + ".mds"));
+				model.add(null, loadedset, GEMSNode.SET);
+			    }
+			    catch(Exception e){
+				System.out.println("Print file error");
+			    }
+                        }
+                        catch(Exception e){
+                            System.out.println("File Input error");
+                        }
+                   
+                    }//msm.getset(namespacE) == null
+                    else{
+			JOptionPane.showMessageDialog(self, Dictionary.get("GEMS.Set_Already_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+                    }
+		    setVisible(false);
+                }
+	    } //if(source == ok_button)
+	    else if(source == cancel_button) {
+		setVisible(false);
+	    }
+	    else {
+		name_field.setText("");
+		setVisible(true);
+	    }
+	} //actionPerformed
+		  
+	public void dispose() {
+	    cancel_button = null;
+	    ok_button = null;
+	    name_field = null;
+	    super.dispose();
+	}
+    }
+
+	////
+    private class SetSelectionDialog
+	extends ModalDialog
+	implements ActionListener {
+	private JButton cancel_button = null;
+	private JButton ok_button = null;
+        private JComboBox existingSetJComboBox = new JComboBox();
+            
+	public SetSelectionDialog() {
+	    super(self);
+	    setModal(true);
+	    setSize(OPEN_SETS_SIZE);
+	    Dictionary.setText(this, "GEMS.Open_Set");
+
+	    // Creation
+	    JPanel content_pane = (JPanel) getContentPane();
+	    content_pane.setBackground(config.getColor("coloring.collection_heading_background", false));
+	    JPanel center_pane = new JPanel();
+	    center_pane.setOpaque(false);
+
+	    JPanel boxes_pane = new JPanel();
+
+	    JPanel button_pane = new JPanel();
+	    button_pane.setOpaque(false);
+
+	    ok_button = new GLIButton();
+	    ok_button.setMnemonic(KeyEvent.VK_O);
+	    getRootPane().setDefaultButton(ok_button);
+	    Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	    cancel_button = new GLIButton();
+	    cancel_button.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+
+	    // Connection
+	    cancel_button.addActionListener(this);
+	    ok_button.addActionListener(this);
+
+	    // Layout
+            boxes_pane.setLayout(new GridLayout(4,1));
+
+            JLabel inheritJLabel = new JLabel(); 
+            Dictionary.setText(inheritJLabel, "GEMS.inheritMetadataSet");
+	   
+            File[] col_dir = new File(Configuration.gsdl_path + File.separator + "collect").listFiles();
+            
+            existingSetJComboBox.addItem("Default Metadata Sets                                                                                        #% " + getGLIMetadataDirectoryPath());
+                
+            for(int k = 0; k < col_dir.length; k++){
+                  if(col_dir[k].isDirectory() && col_dir[k].getName().compareTo("CVS") != 0) {
+                    
+                       File metadir = new File(col_dir[k].toString() + File.separator + "metadata");
+                    if(metadir.exists())   
+                        existingSetJComboBox.addItem(new String(col_dir[k].getName() + " Collection Sets                                                                                                     #% " + col_dir[k].toString() + File.separator + "metadata"));
+                 
+                  }
+                
+            }
+            //add sets to existingSetJComboBox
+            
+            existingSetJComboBox.setSelectedIndex(0);
+            JLabel dummyl = new JLabel();
+            Dictionary.setText(dummyl, "GEMS.Add_Set.No_Inherit");
+            
+            boxes_pane.add(new JLabel("Select which group of metadata sets you wish to edit:\n\n\n\n"));
+            boxes_pane.add(new JLabel("\n"));
+            boxes_pane.add(existingSetJComboBox);
+            boxes_pane.add(new JLabel("\n"));
+
+            button_pane.setLayout(new GridLayout(1,3,0,5));
+	    button_pane.add(ok_button);
+	    button_pane.add(cancel_button);
+            
+	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(boxes_pane, BorderLayout.CENTER);
+	    content_pane.add(button_pane, BorderLayout.SOUTH);
+         
+	    setLocation((config.screen_size.width - ADD_SET_SIZE.width) / 2, (config.screen_size.height - ADD_SET_SIZE.height) / 2);
+	}
+	/** Any implementation of ActionListener must include this method so that we can be informed when an action as occured on our registered component, allowing us to
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+	 */
+   
+	public void actionPerformed(ActionEvent event) {
+	    Object source = event.getSource();
+            
+	    if(source == ok_button) {
+                //this code below handles whether we inherit from an existing set or not
+             
+               // String namespace_str = namespace_field.getText();
+		//String name_str = Codec.transform(Codec.transformUnicode(name_field.getText()), Codec.TEXT_TO_DOM);
+                String loc = (String) existingSetJComboBox.getSelectedItem();
+                
+                String [] whereto = loc.split("#%");
+                String set_directory = whereto[1].trim();
+                
+                //load the jfilechooser:
+                 
+		JFileChooser metadata_set_file_chooser = new JFileChooser(new File(set_directory));
+		metadata_set_file_chooser.setFileFilter(new MetadataSetFileFilter());
+		if (metadata_set_file_chooser.showDialog(this, Dictionary.get("General.Open")) == JFileChooser.APPROVE_OPTION) {
+		    MetadataSet metadata_set = msm.loadMetadataSet(metadata_set_file_chooser.getSelectedFile());
+		    // Update tree
+                    //only update tree if the metadata_set return is not null(it will be null if set is already
+                    //opened-Attila - oct 19 0 4
+                    if(metadata_set != null) {
+                        model.add(null, metadata_set, GEMSNode.SET);
+                    }
+		}
+                
+         
+                setVisible(false);
+            }
+	    else if(source == cancel_button) {
+		setVisible(false);
+	    }
+	    else {
+		setVisible(true);
+	    }
+	}
+		  
+	public void dispose() {
+	    cancel_button = null;
+	    ok_button = null;
+	    super.dispose();
+	}
+    }
+
+    /*
+      Class to handle removing set or element attributes.
+    */
+    private class RemoveAttributeActionListener
+	implements ActionListener, KeyListener {
+
+	/**
+	   Any implementation of KeyListener must include these mothods.
+	   When the DELETE key is pressed, fire the actionPerformed event.
+	   @param e A <strong>KeyEvent</strong> containing information about the event.
+	*/
+	public void keyTyped(KeyEvent e){
+	    //Do nothing
+	}
+	    public void keyPressed(KeyEvent e)
+		{
+		    if(e.getKeyCode() == java.awt.event.KeyEvent.VK_DELETE)
+			{
+			    //DELETE key pressed
+			    actionPerformed((ActionEvent)null); //is there a better way?
+			}
+		}
+	    public void keyReleased(KeyEvent e) {
+		//Do nothing
+	    }
+		    
+	/** Any implementation of ActionListener must include this method so that we can be informed when an action as occured on our registered component, allowing us to
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    if(current_attribute != -1) {
+		int result = JOptionPane.showOptionDialog(self, Dictionary.get("GEMS.Confirm_Removal", Dictionary.get("GEMS.Attribute")), Dictionary.get("GEMS.Confirm_Removal_Title"), JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, dialog_options, dialog_options[0]);
+		// Remove this attribute
+		if(result == 0) {
+		    ignore = true;
+		    //Attributes are tricky little beasties, as they can come from several different places and depend upon what other little beasties have been selected
+		    //Has an element been selected
+		    if(current_element != null) {
+			// Remove element attribute
+			String name = (String) element_attributes.getValueAt(current_attribute, 0);
+			String language = (String) element_attributes.getValueAt(current_attribute, 1);
+			String value = (String) element_attributes.getValueAt(current_attribute, 2);
+			current_element.removeAttribute(name, language, value);
+
+			// Refresh table
+			((AttributeTableModel)element_attributes.getModel()).removeRow(current_attribute);
+		    }
+		    else if(current_set != null) {
+			String name = (String) set_attributes.getValueAt(current_attribute, 0);
+			// Remove set attribute
+			current_set.removeAttribute(name);
+			// Refresh table
+			((AttributeTableModel)set_attributes.getModel()).removeRow(current_attribute);
+		    }
+		    ignore = false;
+		    atLeastOneSetChanged= true;
+		}
+	    }
+	    else
+		{
+		    System.err.println("Tried to remove attribute, but current_attribute == -1!"); //This should not happen
+		}
+	}
+    }
+
+    /*
+      Class to handle deletion of elements (including subelements).
+
+      Last modified 2/02/05 by Matthew Whyte
+     */
+    private class RemoveElementActionListener
+	implements ActionListener {
+
+	/** Any implementation of ActionListener must include this method so that we can be informed when an action as occured on our registered component, allowing us to provide an editing prompt.
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+	 */
+	public void actionPerformed(ActionEvent event) {
+         
+	    if(current_element != null) {
+		int result = JOptionPane.showOptionDialog(self, Dictionary.get("GEMS.Confirm_Removal", Dictionary.get("GEMS.Element")), Dictionary.get("GEMS.Confirm_Removal_Title"), JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, dialog_options, dialog_options[0]);
+		// Remove this attribute
+		if(result == 0) {
+		    //Get the parent element
+		    GEMSNode parent_node = (GEMSNode)current_node.getParent();
+		    ElementWrapper parent_wrapped = parent_node.getElement();
+
+		    ignore = true;
+		    msm.removeElement(current_element, parent_wrapped);
+		    // Clear selection
+		    mds_tree.clearSelection();
+		    model.remove(current_node);
+
+		    // Show a blank panel.
+		    card_layout.show(details_pane, BLANK);
+		    ignore = false;
+                    
+                     atLeastOneSetChanged = true;
+		}
+	    }
+	    else {
+		System.err.println("No element currently selected."); //This should not happen!
+	    }
+	}
+    }
+
+
+    /**
+       Class to handle renaming of a set and/or it's namespace.
+
+       @author: Matthew Whyte
+       Date last modified: 10/01/05
+    */
+    private class RenameSetActionListener extends ModalDialog implements ActionListener {
+
+	private JButton cancel_button = null;
+	private JButton ok_button = null;
+	private JTextField name_field = null;
+	private JTextField namespace_field = null;
+            
+	public RenameSetActionListener() {
+	    super(self);
+	    setModal(true);
+	    setSize(RENAME_SET_SIZE);
+	    Dictionary.setText(this, "GEMS.Rename_Set");
+
+	    // Creation
+	    JPanel content_pane = (JPanel) getContentPane();
+	    content_pane.setBackground(config.getColor("coloring.collection_heading_background", false));
+	    JPanel center_pane = new JPanel();
+	    center_pane.setOpaque(false);
+
+	    JPanel label_pane = new JPanel();
+	    JPanel boxes_pane = new JPanel();
+
+	    JLabel namespace_label = new JLabel();
+	    namespace_label.setOpaque(false);
+	    Dictionary.setText(namespace_label, "GEMS.Namespace");
+	    namespace_field = TransformCharacterTextField.createNamespaceTextField();
+	    namespace_field.setBackground(config.getColor("coloring.collection_tree_background", false));
+	    namespace_field.setForeground(config.getColor("coloring.collection_tree_foreground", false));
+	    namespace_field.setSelectionColor(config.getColor("coloring.collection_selection_background", false));
+	    namespace_field.setSelectedTextColor(config.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.setTooltip(namespace_field, "GEMS.Rename_Namespace_Tooltip");
+
+	    JLabel name_label = new JLabel();
+	    name_label.setOpaque(false);
+	    Dictionary.setText(name_label, "GEMS.Name");
+	    name_field = new JTextField();
+	    name_field.setBackground(config.getColor("coloring.collection_tree_background", false));
+	    name_field.setForeground(config.getColor("coloring.collection_tree_foreground", false));
+	    name_field.setSelectionColor(config.getColor("coloring.collection_selection_background", false));
+	    name_field.setSelectedTextColor(config.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.setTooltip(name_field, "GEMS.Rename_Name_Tooltip");
+
+	    JPanel button_pane = new JPanel();
+	    button_pane.setOpaque(false);
+
+	    ok_button = new GLIButton();
+	    ok_button.setMnemonic(KeyEvent.VK_O);
+	    getRootPane().setDefaultButton(ok_button);
+	    Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	    cancel_button = new GLIButton();
+	    cancel_button.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+	    TextFieldEnabler ok_button_enabler = new TextFieldEnabler(ok_button);
+
+	    // Connection
+	    cancel_button.addActionListener(this);
+	    ok_button.addActionListener(this);
+	    ok_button_enabler.add(name_field);
+	    ok_button_enabler.add(namespace_field);
+
+	    // Layout
+	    label_pane.setLayout(new GridLayout(2,1));
+	    label_pane.add(name_label);
+	    label_pane.add(namespace_label);
+            boxes_pane.setLayout(new GridLayout(2,1));
+	    boxes_pane.add(name_field);
+	    boxes_pane.add(namespace_field);
+            
+	    center_pane.setLayout(new BorderLayout(5,0));
+	    center_pane.add(label_pane, BorderLayout.WEST);
+	    center_pane.add(boxes_pane, BorderLayout.CENTER);
+
+	    button_pane.setLayout(new GridLayout(1,2,0,5));
+	    button_pane.add(ok_button);
+	    button_pane.add(cancel_button);
+
+	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(center_pane, BorderLayout.CENTER);
+	    content_pane.add(button_pane, BorderLayout.SOUTH);
+         
+	    setLocation((config.screen_size.width - RENAME_SET_SIZE.width) / 2, (config.screen_size.height - RENAME_SET_SIZE.height) / 2);
+	}
+
+        private boolean a_set_exists_with_this_namespace(String namespace){
+            Vector p = msm.getSets();
+            boolean flag = false;
+            for(int k = 0; k < p.size(); k++){
+                MetadataSet s = (MetadataSet)p.get(k);
+                
+                if(s.getNamespace().compareTo(namespace) == 0){
+                    flag = true;     
+                }
+            }
+            return flag;
+        }
+
+
+	/** 
+	    Any implementation of ActionListener must include this method so that we can be informed when an action as occured on our registered component,
+	    allowing us to
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+         */
+	public void actionPerformed(ActionEvent event) {
+	    Object source = event.getSource();
+            
+	    if(source == ok_button)
+		{
+		    String namespace_str = namespace_field.getText();
+		    String name_str = Codec.transform(Codec.transformUnicode(name_field.getText()), Codec.TEXT_TO_DOM);
+		    //Note: The name in name_str is language dependent. However, currently GEMS does not create new sets with different names for different languages(?).
+		    String current_set_namespace = current_set.getNamespace();
+
+		    //Ensure that the namespace is unique. 
+			if(!(a_set_exists_with_this_namespace(namespace_str)) || (namespace_str.equals(current_set_namespace)))
+			{
+			    //Hide the set that are about to rename
+			    mds_tree.clearSelection();
+			    model.remove(current_node);
+
+			    //Rename set & namespace
+			    msm.renameSet(current_set, namespace_str, name_str);
+			    //Add (renamed) set back to tree
+			    model.add(null, current_set, GEMSNode.SET);
+
+			    //Clean up
+			    card_layout.show(details_pane, BLANK); // Show a blank panel.
+			    ignore = false;
+			    atLeastOneSetChanged = true;
+			    setVisible(false);
+			}
+			    
+		    // Otherwise show an error message and do not proceed.
+		    else
+			{
+			    JOptionPane.showMessageDialog(self, Dictionary.get("GEMS.Set_Already_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+			}
+		    name_str = null;
+		    
+		}
+
+	    else if(source == cancel_button)
+		{
+		    setVisible(false); //hide dialog
+		}
+	    else
+		{
+		    name_field.setText(current_set.getName());
+		    namespace_field.setText(current_set.getNamespace());
+		    setVisible(true); //Show the dialog
+		}   
+	    source = null;
+	}
+	
+	public void dispose() {
+	    cancel_button = null;
+	    ok_button = null;
+	    name_field = null;
+	    super.dispose();
+	}
+    }
+
+   
+
+ /**
+       Class to handle renaming of an element.
+
+       @author: Matthew Whyte
+       Date last modified: 10/01/05
+    */
+    private class RenameElementActionListener extends ModalDialog implements ActionListener {
+
+	protected JButton cancel_button = null;
+	protected JButton ok_button = null;
+	//private JLabel label = null;
+	protected NonWhitespaceField name_field = null;
+
+	public RenameElementActionListener() {
+	    super(self);
+	    setModal(true);
+	    setSize(RENAME_ELEMENT_SIZE);
+	    // Creation
+	    JPanel content_pane = (JPanel) getContentPane();
+	    content_pane.setBackground(config.getColor("coloring.collection_heading_background", false));
+	    JPanel center_pane = new JPanel();
+	    center_pane.setOpaque(false);
+
+	    JPanel labels_pane = new JPanel();
+	    labels_pane.setOpaque(false);
+
+	    JPanel values_pane = new JPanel();
+	    values_pane.setOpaque(false);
+	    JLabel name_label = new JLabel();
+	    name_label.setOpaque(false);
+	    Dictionary.setText(name_label, "GEMS.New_Name");
+	    name_field = new NonWhitespaceField();
+	    name_field.setBackground(config.getColor("coloring.collection_tree_background", false));
+	    name_field.setForeground(config.getColor("coloring.collection_tree_foreground", false));
+	    name_field.setSelectionColor(config.getColor("coloring.collection_selection_background", false));
+	    name_field.setSelectedTextColor(config.getColor("coloring.collection_selection_foreground", false));
+	    Dictionary.setTooltip(name_field, "GEMS.Rename_Element_Tooltip");
+
+	    JPanel button_pane = new JPanel();
+	    button_pane.setOpaque(false);
+
+	    ok_button = new GLIButton();
+	    ok_button.setMnemonic(KeyEvent.VK_O);
+	    getRootPane().setDefaultButton(ok_button);
+	    Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	    cancel_button = new GLIButton();
+	    cancel_button.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+
+	    TextFieldEnabler ok_button_enabler = new TextFieldEnabler(ok_button);
+
+	    Dictionary.setText(this, "GEMS.Rename_Element");
+	    
+	    // Connection
+	    cancel_button.addActionListener(this);
+	    ok_button.addActionListener(this);
+	    ok_button_enabler.add(name_field);
+
+	    // Layout
+	    labels_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    labels_pane.setLayout(new GridLayout(1,1));
+	    //labels_pane.add(set_label);
+	    labels_pane.add(name_label);
+
+	    values_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    values_pane.setLayout(new GridLayout(1,1));
+	    //values_pane.add(label);
+	    values_pane.add(name_field);
+
+	    center_pane.setLayout(new BorderLayout(5,5));
+	    center_pane.add(labels_pane, BorderLayout.WEST);
+	    center_pane.add(values_pane, BorderLayout.CENTER);
+
+	    button_pane.setLayout(new GridLayout(1,2,0,5));
+	    button_pane.add(ok_button);
+	    button_pane.add(cancel_button);
+
+	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(center_pane, BorderLayout.CENTER);
+	    content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	    setLocation((config.screen_size.width - ADD_ELEMENT_SIZE.width) / 2, (config.screen_size.height - ADD_ELEMENT_SIZE.height) / 2);
+	}
+
+
+	/**
+	   Any implementation of ActionListener must include this method so that we can be informed when an action has occured.
+	   @param event An <string>ActionEvent</strong> containing information about the event.
+	*/
+	public void actionPerformed(ActionEvent event)
+	{
+	    Object source = event.getSource();
+
+	    if(source == ok_button)
+		{
+		    TreeNode selPath = current_node.getParent();
+		    GEMSNode parent = (GEMSNode)selPath;
+		    MetadataSet currentSet = msm.getSet(current_element.getNamespace());
+		    String name_str = Codec.transform(Codec.transformUnicode(name_field.getText()), Codec.TEXT_TO_DOM);
+		    GEMSNode new_node = null;
+
+		    // If this element doesn't already exist.
+		    if(!currentSet.containsElement(name_str)) //Do the renaming!
+			{   
+			    model.remove(current_node); //Hide the element that are about to rename
+			    msm.renameElement(current_element, name_str); //rename the element
+			    //Add the new element
+			    new_node = model.add(parent, current_element, GEMSNode.ELEMENT);
+			    
+			    //mds_tree.setSelectionPath(new_node_path); //would like to do this but doesn't hilight tree :-(
+			    card_layout.show(details_pane, BLANK); // Show a blank panel.
+			    
+			    //finish up
+			    currentSet.setSetChanged(true);
+			    atLeastOneSetChanged = true;
+			    setVisible(false);
+			}
+			    
+		    // Otherwise show an error message and do not proceed.
+		    else
+			{
+			    JOptionPane.showMessageDialog(self, Dictionary.get("GEMS.Element_Already_Exists"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+			}
+		    name_str = null;
+		    
+		}
+
+	    else if(source == cancel_button)
+		{
+		    setVisible(false); //hide dialog
+		}
+	    else
+		{
+		    name_field.setText(current_element.getNameOnly()); //show old name (without namespace)
+		    setVisible(true); //Show the dialog
+		}
+		    
+	    source = null;
+	}
+	
+	public void dispose() {
+	    cancel_button = null;
+	    ok_button = null;
+	    name_field = null;
+	    super.dispose();
+	}
+    }
+
+
+    /**
+       Class to handle DELETE key presses on the tree.
+       The class then fires the appropriate event to remove that element/set.
+       Attributes in the table are handled directly by the RemoveAttributeActionListener
+
+       Author: Matthew Whyte
+       Date last modified: 25/01/05
+    */
+    private class KeyPressedHandler implements KeyListener, ActionListener {	
+
+	// All implementations of KeyListener requires these methods
+	public void keyTyped(KeyEvent e){
+	    //Do nothing
+	}
+	public void keyPressed(KeyEvent e)
+	{
+
+	    if(e.getKeyCode() == java.awt.event.KeyEvent.VK_DELETE) //DELETE key pressed
+	    {
+		this.removeItem();
+	    }
+	}
+	public void keyReleased(KeyEvent e)
+	    {
+		//Do nothing
+	    }
+
+	public void actionPerformed(ActionEvent event)
+	{
+	    this.removeItem();
+	}
+
+	public void removeItem()
+	{
+	    boolean cont = true;
+	    
+	    /**
+	       Check to see if more than one tree node/leaf is selected. If so don't continue.
+	       
+	       This could be updated to delete multiple nodes/leaves in the futere.
+	       But not me and not today!
+	    */
+	    TreePath[] multiSelectionCheck = mds_tree.getSelectionPaths();
+	    if(multiSelectionCheck.length > 1)
+		{
+		    cont = false;
+		    Toolkit.getDefaultToolkit().beep();
+		}
+	    
+	    if(cont)
+		{
+		    //Check to see if pressed on Set or Element.
+		    TreePath selPath = mds_tree.getSelectionPath();
+		    GEMSNode t = (GEMSNode)selPath.getLastPathComponent();
+		    
+		    if(t.type == T_ELEMENT) //Remove the element
+			{
+			    RemoveElementActionListener removeElement = new RemoveElementActionListener();
+			    removeElement.actionPerformed((ActionEvent)null);
+			}
+		    else if(t.type == T_SET) //Remove the whole set
+			{
+			    RemoveSetActionListener removeSet = new RemoveSetActionListener();
+			    removeSet.actionPerformed((ActionEvent)null);
+			}
+		}
+	}
+    }
+    
+
+    private class RemoveSetActionListener
+	implements ActionListener {
+
+	/** Any implementation of ActionListener must include this method so that we can be informed when an action as occured on our registered component, allowing us to
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    if(current_set != null) {
+                
+                //If the current_set_filename is dls or dublin or ex and in the GLI metadata directory, then do
+                //not let anyone remove them --Attila
+                File current_set_filename = current_set.getFile();
+                if(current_set_filename.toString().compareTo(new String(getGLIMetadataDirectoryPath() + "dls.mds")) == 0 ||
+                    current_set_filename.toString().compareTo(new String(getGLIMetadataDirectoryPath() + "dublin.mds")) == 0 ||
+                    current_set_filename.toString().compareTo(new String(getGLIMetadataDirectoryPath() + "ex.mds")) == 0){
+                  
+                    JOptionPane.showMessageDialog(self, Dictionary.get("GEMS.Cannot_Delete_Core_Sets_Error"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+                    return;
+                }
+                
+                
+		int result = JOptionPane.showOptionDialog(self, Dictionary.get("GEMS.Confirm_Removal", Dictionary.get("GEMS.Set") + " " +  Dictionary.get("GEMS.Cannot_Undo")), Dictionary.get("GEMS.Confirm_Removal_Title"), JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, dialog_options, dialog_options[0]);
+		// Remove the currently selected set
+		if(result == 0) {
+                    
+		    ignore = true;
+		    msm.removeSet(current_set);
+		    // Clear selection
+		    mds_tree.clearSelection();
+		    model.remove(current_node);
+		    card_layout.show(details_pane, BLANK); //Show a blank panel.
+		    ignore = false;
+ 
+		}
+	    }
+	}
+    }
+	 
+    /** Used to enable a certain target component if and only if all the registered text fields contain non-zero length strings. */
+    private class TextFieldEnabler
+	implements DocumentListener {
+	private boolean ignore = false;
+	private Component target = null;
+	private JTextComponent[] fields = null;
+	public TextFieldEnabler(Component target) {
+	    super();
+	    this.target = target;
+	}
+	public void add(JTextComponent field) {
+	    // Record this field as being one we depend upon
+	    if(fields == null) {
+		fields = new JTextComponent[1];
+		fields[0] = field;
+	    }
+	    else {
+		JTextComponent[] temp = new JTextComponent[fields.length + 1];
+		System.arraycopy(fields, 0, temp, 0, fields.length);
+		temp[fields.length] = field;
+		fields = temp;
+		temp = null;
+	    }
+	    // Add the appropriate listener
+	    field.getDocument().addDocumentListener(this);
+	}
+	/** Gives notification that an attribute or set of attributes changed. */
+	public void changedUpdate(DocumentEvent e) {
+	    canEnable();
+	}
+	/** Gives notification that there was an insert into the document. */
+	public void insertUpdate(DocumentEvent e) {
+	    canEnable();
+	}
+        /** Gives notification that a portion of the document has been removed. */
+	public void removeUpdate(DocumentEvent e) {
+	    canEnable();
+	}
+	private void canEnable() {
+	    if(!ignore) {
+		ignore = true;
+		boolean can_enable = true;
+		for(int i = 0; can_enable && i < fields.length; i++) {
+		    can_enable = can_enable && (fields[i].getText().length() > 0);
+		}
+		target.setEnabled(can_enable);
+		ignore = false;
+	    }
+	}
+    }
+
+    private class AttributesListSelectionListener
+	implements ListSelectionListener
+    {
+	private JTable table = null;
+	public AttributesListSelectionListener(JTable table)
+	{
+	    this.table = table;
+	}
+
+	public void valueChanged(ListSelectionEvent event)
+	{
+	    if(!event.getValueIsAdjusting())
+		{
+		    current_attribute = table.getSelectedRow();
+		}
+	}
+    }
+
+    private class MDSTreeSelectionListener
+	implements TreeSelectionListener {
+	public void valueChanged(TreeSelectionEvent event) {
+	    if(!ignore) {
+		// Clear all variables based on previous tree selection
+		current_element = null;
+		current_set = null;
+		// Now process the node selected
+		TreePath path = event.getPath();
+		current_node = (GEMSNode)path.getLastPathComponent();
+		// What we show depends on the node type...
+		AttributeTableModel atm = null;
+		TreeSet attributes = null;
+		current_attribute_type = current_node.getType();
+		switch(current_attribute_type) {
+
+		case GEMSNode.ELEMENT:
+		    current_element = current_node.getElement();
+		    atm = current_node.getModel();
+		    if(atm == null) {
+			atm = new AttributeTableModel(current_element.getAttributes(), Dictionary.get("GEMS.Name"), Dictionary.get("GEMS.Language_Code"), Dictionary.get("GEMS.Value"), "");
+			//current_node.setModel(atm);
+		    }
+		    element_attributes.setModel(atm);
+		    atm.setScrollPane(element_attributes_scroll);
+		    atm.setTable(element_attributes);
+
+		    card_layout.show(details_pane, ELEMENT);
+		    break;
+		case GEMSNode.SET:
+		    current_set = current_node.getSet();
+		    atm = current_node.getModel();
+		    if(atm == null) {
+			NamedNodeMap temp = current_set.getAttributes();
+			attributes = new TreeSet();
+			for(int i = 0; i < temp.getLength(); i++) {
+			    Attr attribute = (Attr) temp.item(i);
+			    // We don't show the namespace attribute, as it is used as a unique primary key and should never be changed or removed in itself.
+			    if(!attribute.getName().equals("namespace")) {
+				attributes.add(new Attribute(attribute.getName(), attribute.getValue()));
+			    }
+			    attribute = null;
+			}
+			atm = new AttributeTableModel(attributes, Dictionary.get("GEMS.Name"), Dictionary.get("GEMS.Value"), "");
+			temp = null;
+		    }
+		    set_attributes.setModel(atm);
+		    atm.setScrollPane(set_attributes_scroll);
+		    atm.setTable(set_attributes);
+						 
+		    card_layout.show(details_pane, SET);
+		    attributes = null;
+		    break;
+
+		default:
+		    // Show a blank panel.
+		    card_layout.show(details_pane, BLANK);
+		}
+		attributes = null;
+		path = null;
+		atm = null;
+	    }
+	}
+    }
+
+    private class GEMSTreeCellRenderer
+	extends DefaultTreeCellRenderer {
+	public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+	    super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
+	    setToolTipText(value.toString());
+	    return this;
+	}
+    }
+    
+
+    //PopupListener is our main manager for all right-click popups
+    class PopupListener extends MouseAdapter implements ActionListener{
+	JPopupMenu setPopup;
+	JPopupMenu elementPopup;
+	JPopupMenu attributePopup;
+
+	//all of our popup menu items EVER!
+	JMenuItem menuAddAttributeSet;
+	JMenuItem menuAddElement;
+	JMenuItem menuRenameSet;
+	JMenuItem menuRemoveSet;
+
+	JMenuItem menuAddAttributeElement;
+	JMenuItem menuAddSubelement;
+	JMenuItem menuRenameElement;
+	JMenuItem menuDeleteElement;
+
+	JMenuItem menuAddAttributeAttribute;
+	JMenuItem menuEditValue;
+	JMenuItem menuDeleteAttribute;
+	
+        GEMS GEMSRef = null;
+        PopupListener(GEMS g) {
+	    setPopup = new JPopupMenu();
+	    elementPopup = new JPopupMenu();
+	    attributePopup = new JPopupMenu();
+            
+            //reference to our parent(GEMS), because some of the actionlisteners would not
+            //work unless they were declared in GEMS, and I need a way to reference GEMS
+	    GEMSRef = g;
+	    
+	    //Create the menu items
+	    menuAddAttributeSet = new JMenuItem();
+	    Dictionary.setBoth(menuAddAttributeSet, "GEMS.Add_Attribute", "GEMS.Add_Attribute_Tooltip");
+	    menuAddElement =new JMenuItem();
+	    Dictionary.setBoth(menuAddElement,"GEMS.Add_Element","GEMS.Add_Element_Tooltip");
+	    menuRenameSet = new JMenuItem();
+	    Dictionary.setBoth(menuRenameSet,"GEMS.Rename_Set", "GEMS.Rename_Set_Tooltip");
+            menuRemoveSet = new JMenuItem();
+	    Dictionary.setBoth(menuRemoveSet, "GEMS.Remove_Set","GEMS.Remove_Set_Tooltip");
+            
+            menuAddAttributeElement=new JMenuItem();
+            Dictionary.setBoth(menuAddAttributeElement,"GEMS.Add_Attribute", "GEMS.Add_Attribute_Tooltip");
+	    menuAddSubelement=new JMenuItem();
+            Dictionary.setBoth(menuAddSubelement,"GEMS.Add_Subelement", "GEMS.Add_Subelement_Tooltip");
+            menuRenameElement=new JMenuItem();
+            Dictionary.setBoth(menuRenameElement,"GEMS.Rename_Element", "GEMS.Rename_Element_Tooltip");
+            menuDeleteElement=new JMenuItem();
+	    Dictionary.setBoth(menuDeleteElement,"GEMS.Remove_Element", "GEMS.Remove_Element_Tooltip" );
+
+	    menuAddAttributeAttribute=new JMenuItem();
+	    Dictionary.setBoth(menuAddAttributeAttribute,"GEMS.Add_Attribute", "GEMS.Add_Attribute_Tooltip");
+            menuEditValue=new JMenuItem();
+            Dictionary.setBoth(menuEditValue,"GEMS.Edit_Value", "GEMS.Edit_Value_Tooltip");
+            menuDeleteAttribute=new JMenuItem();
+	    Dictionary.setBoth(menuDeleteAttribute,"GEMS.Remove_Attribute", "GEMS.Remove_Attribute_Tooltip");
+             
+	    //Associate the menu items with the appropriate popups:
+	    setPopup.add(menuAddAttributeSet);
+	    setPopup.add(menuAddElement);
+	    setPopup.add(menuRenameSet);
+	    setPopup.add(menuRemoveSet);
+            
+	    elementPopup.add(menuAddAttributeElement);
+	    elementPopup.add(menuAddSubelement);
+	    elementPopup.add(menuRenameElement);
+	    elementPopup.add(menuDeleteElement);
+            
+	    attributePopup.add(menuAddAttributeAttribute);
+	    attributePopup.add(menuEditValue);
+	    attributePopup.add(menuDeleteAttribute);
+	    
+	    //Add appropriate action listeners to the menu items.
+	    menuAddAttributeSet.addActionListener(new AddOrEditAttributeActionListener());
+	    menuAddElement.addActionListener(new AddElementActionListener());
+	    menuRenameSet.addActionListener(new RenameSetActionListener());
+	    menuRemoveSet.addActionListener(new RemoveSetActionListener());
+	    
+	    menuAddAttributeElement.addActionListener(new AddOrEditAttributeActionListener());
+	    menuAddSubelement.addActionListener(new AddSubelementActionListener());
+	    menuRenameElement.addActionListener(new RenameElementActionListener());
+	    menuDeleteElement.addActionListener(new RemoveElementActionListener());
+	   
+	    menuEditValue.addActionListener(new AddOrEditAttributeActionListener());
+	    menuDeleteAttribute.addActionListener(new RemoveAttributeActionListener());
+	    menuAddAttributeAttribute.addActionListener(new AddOrEditAttributeActionListener());            
+        }
+
+        public void mouseClicked(MouseEvent e) {
+            maybeShowPopup(e);
+        }
+        public void mousePressed(MouseEvent e){
+        maybeShowPopup(e);
+	}
+        public void mouseReleased(MouseEvent e) {
+            maybeShowPopup(e);
+        }
+
+        private void maybeShowPopup(MouseEvent e) {
+	    TreePath selPath = mds_tree.getPathForLocation(e.getX(), e.getY());
+	    Point p = null;
+            if (e.isPopupTrigger()) {
+		
+		if(e.getSource() == mds_tree) {
+		    try {
+			GEMSNode t = (GEMSNode)selPath.getLastPathComponent();
+			
+			mds_tree.setSelectionPath(selPath); //Select node right-clicked on
+			
+			if(t.type == T_ELEMENT){
+			    elementPopup.show(e.getComponent(), e.getX(), e.getY());
+			}
+			else if(t.type == T_SET){
+			    setPopup.show(e.getComponent(), e.getX(), e.getY());
+			}
+		    }
+		    catch(Exception NullPointerException) {
+			//Right-clicked in tree area, but no item to select. Do nothing.
+		    }
+		}
+		else if(e.getSource() == set_attributes){ //When right-click on table of set attributes
+		    //Select the table row that was right-clicked on.
+		    p = e.getPoint();
+		    set_attributes.changeSelection(set_attributes.rowAtPoint(p), set_attributes.columnAtPoint(p), false, false);
+		    attributePopup.show(e.getComponent(), e.getX(), e.getY());  
+		}
+		else if(e.getSource() == element_attributes)  { //When right-click on table of element attributes
+		    //Select the table row that was right-clicked on.
+		    p = e.getPoint();
+		    element_attributes.changeSelection(element_attributes.rowAtPoint(p), element_attributes.columnAtPoint(p), false, false);
+		    attributePopup.show(e.getComponent(), e.getX(), e.getY());
+		}
+            }  
+        }
+      
+      public void actionPerformed(ActionEvent e) {
+	  //This should never happen!
+	  System.err.println("Error: actionPerformed was called in class PopupListener. This should never happen!");
+      }
+    }
+  
+    /** Wrap a ElementWrapper so we get its name when we ask for toString(), not its identifier. */
+    private class NameElementWrapperEntry 
+	implements Comparable {
+	private ElementWrapper element_wrapper = null;
+	public NameElementWrapperEntry(Object object) {
+	    this.element_wrapper = (ElementWrapper) object;
+	}
+	public int compareTo(Object object) {
+	    return element_wrapper.compareTo(object);
+	}
+	public boolean equals(Object object) {
+	    return element_wrapper.equals(object);
+	}
+	public String toString() {
+	    return element_wrapper.getName();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSLanguageManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSLanguageManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSLanguageManager.java	(revision 10506)
@@ -0,0 +1,149 @@
+ /**
+ *#########################################################################
+ *
+ * A component of the Gatherer application, part of the Greenstone digital
+ * library suite from the New Zealand Digital Library Project at th * 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.gatherer.gems;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.cdm.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.w3c.dom.*;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMException;
+
+/** This class manages the language commands, remembering both a list of languages to build indexes in, plus the default language.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ * Created on October 27, 2004, 3:31 PM
+ * Modified 1/02/05 by Matthew Whyte
+ */
+ public class GEMSLanguageManager {
+     private Document document;
+     private DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+     private Vector languageCodes;
+     private Vector languageCodesAndNames;
+     public GEMSLanguageManager(String languagexml_location) {
+	 
+	 this.languageCodes = new Vector();
+	 this.languageCodesAndNames = new Vector();
+
+	 try {
+	     
+	     File f = new File(languagexml_location);
+	     
+	     DocumentBuilder builder = factory.newDocumentBuilder();
+	     document = builder.parse(f);
+	     org.w3c.dom.Element docelement = document.getDocumentElement();
+	     
+	     //get all language nodes
+	     NodeList mynodelist = docelement.getChildNodes();
+	     
+	     //get a single language text
+	     //System.out.println(mynodelist.item(1).getChildNodes().item(0).getNodeValue()); //debug
+	     
+	     for(int j = 1; j < mynodelist.getLength(); j++){
+		 
+		 //read text value for the element
+		 NodeList childnodesofelement = mynodelist.item(j).getChildNodes();
+		 NamedNodeMap nnm = mynodelist.item(j).getAttributes();
+		 
+		 if(childnodesofelement.getLength() == 1)
+		     {
+			 String code = nnm.item(0).getNodeValue();
+			 String name = nnm.item(4).getNodeValue();
+			 String name_value = childnodesofelement.item(0).getNodeValue();
+			 //language_box.addItem(code.toLowerCase());
+			 this.languageCodes.add(code.toLowerCase());
+			 this.languageCodesAndNames.add(name.toLowerCase() + "               \t(" + code.toLowerCase() + ")");
+		     } //end if
+	     }//end for
+	 } //end try
+	 catch(SAXException sxe) {
+	     System.out.println("sxe exception\n");
+	 }
+	 catch(ParserConfigurationException pce) {
+             System.out.println("pce exception\n");
+	 }
+	 catch(IOException ioe){
+	     System.out.println("ioe exception\n");
+	 }
+	 
+	 //end create dom object for language_box
+	 
+     }
+     public Vector getLanguageCodesAndNames() {
+	 return languageCodesAndNames;
+     }
+
+     public Vector getLanguageCodes() { 
+	 return languageCodes;
+     }
+     public Object[] getLanguageCodesToArray() { 
+	 return languageCodes.toArray();
+     }
+     public String getEnabledLanguageCodes() {
+	 String enabled_languages =  Configuration.getString("Gems.Preferences.Selected_Languages", true);
+	 return enabled_languages;   
+     }
+     public String[] getEnabledLanguageCodesToArray() {
+	 String enabled_languages =  Configuration.getString("Gems.Preferences.Selected_Languages", true); 
+	 String [] enabled_languages_split = enabled_languages.split(",");
+	 // String [] trimmed_enabled_lang_split = null;
+	 
+	 //  for(int p = 0; p < enabled_languages_split.length; p++) {
+	 //trimmed_enabled_lang_split[p] = enabled_languages_split[p].trim(); 
+	 //  System.out.println("gemslang: trimm: " + trimmed_enabled_lang_split[p] + " orig: "+ enabled_languages_split[p].trim());
+	 // }//for p < enabled lang split
+	 
+	 return enabled_languages_split;
+     }  
+ }
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSModel.java	(revision 10506)
@@ -0,0 +1,79 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+import javax.swing.tree.DefaultTreeModel;
+import org.greenstone.gatherer.util.SynchronizedTreeModelTools;
+/**
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class GEMSModel 
+    extends DefaultTreeModel {
+
+    public GEMSModel() {
+	super(new GEMSNode());
+    }
+
+    public GEMSNode add(GEMSNode parent, Object object, int type) {
+	if(parent == null) {
+	    parent = (GEMSNode) root;
+	}
+
+	GEMSNode new_node = new GEMSNode(type, object, null);
+	SynchronizedTreeModelTools.insertNodeInto(this, parent, new_node);
+
+	return new GEMSNode(type, object, parent);
+    }
+
+    public GEMSNode getProfileNode() {
+	GEMSNode node = (GEMSNode) root;
+	return (GEMSNode) node.getChildAt(node.getChildCount() - 1);
+    }
+
+    /**
+       Remove a node from the tree.
+       @param node the node to remove, as a <strong>GEMSNode</strong>
+       @author Matthew Whyte
+       @date last modified: 21/01/04
+     */
+    public void remove(GEMSNode node)
+    {
+	SynchronizedTreeModelTools.removeNodeFromParent(this, node);
+	return;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSNode.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSNode.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSNode.java	(revision 10506)
@@ -0,0 +1,221 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+import java.io.*;
+import java.util.*;
+import javax.swing.tree.*;
+import javax.swing.JPopupMenu;
+import java.awt.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
+import org.w3c.dom.*;
+/**
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ * Modified 2/02/05 by Matthew Whyte
+ */
+public class GEMSNode
+    extends DefaultMutableTreeNode{
+    private AttributeTableModel model = null;
+    public int type = 0;
+    private String text = null;
+    static final public int COLLECTION = 0;
+    static final public int ELEMENT    = 1;
+    static final public int PROFILER   = 2;
+    static final public int ROOT       = 3; 
+    static final public int SET        = 4;
+    //static final public int SUBELEMENT = 5; 
+
+    public GEMSNode() {
+	this.type = ROOT;
+    }
+
+    public GEMSNode(int type, Object object, GEMSNode parent) {
+	this.userObject = object;
+	this.parent = parent;
+	this.type = type;
+	this.text = null;
+    }
+
+    public Enumeration children() {
+	if(children == null) {
+	    mapChildren();
+	}		  
+	return children.elements();
+    }
+
+    public boolean getAllowsChildren() {
+	return true;
+    }
+
+    public TreeNode getChildAt(int index) {
+	if(children == null) {
+	    mapChildren();
+	}
+	return (TreeNode) children.get(index);
+    }
+    public int getChildCount() {
+	if(children == null) {
+	    mapChildren();
+	}
+	return children.size();
+    }
+    public ElementWrapper getElement() {
+	ElementWrapper result = null;
+	if(type == ELEMENT) {
+	    result = (ElementWrapper) userObject;
+	}
+	return result;	
+    }
+
+    public int getIndex(TreeNode node) {
+	if(children == null) {
+	    mapChildren();
+	}
+	return children.indexOf(node);
+    }
+    public AttributeTableModel getModel() {
+	return model;
+    }
+    public TreeNode getParent() {
+	return parent;
+    }
+    public MetadataSet getSet() {
+	MetadataSet result = null;
+	if(type == SET) {
+	    result = (MetadataSet) userObject;
+	}
+	return result;
+    }
+    public int getType() {
+	return type;
+    }
+    public boolean isLeaf() {
+	if(children == null) {
+	    mapChildren();
+	}
+	return children.size() == 0;
+    }
+    public void setModel(AttributeTableModel model) {
+	this.model = model;
+    }
+
+    public String toString()
+    {
+	if(text == null)
+	    {
+		if(userObject != null)
+		    {
+			if(userObject instanceof ElementWrapper)
+			    {
+				text = ((ElementWrapper)userObject).getName();
+			    }
+			else
+			    {
+				text = userObject.toString();
+			    }
+		    }
+		else
+		    {
+			text = "error";
+		    }
+	    }
+	return text;
+    }
+
+    public void mapChildren()
+    {
+	children = new Vector();
+
+	// How we build children depends on the node type
+	if (type == SET)
+	    {
+		// Add the elements as children
+		MetadataSet set = (MetadataSet) userObject;
+		ArrayList elements = set.getElements();
+		for (int i = 0; i < elements.size(); i++)
+		    {
+			children.add(new GEMSNode(ELEMENT, new ElementWrapper((Element) elements.get(i)), this));
+		    }
+	    }
+	if (type == ELEMENT) //Add subelements. As elements and subelements are identical, this process continues.
+	    {
+		ArrayList subelements = this.getElement().getSubelements();
+		for(int j = 0; j < subelements.size(); j++)
+		    {
+			children.add(new GEMSNode(ELEMENT, new ElementWrapper((Element)subelements.get(j)), this));
+		    }
+	    }
+    }
+    
+   class GemsNodeMouseAdapter
+    extends MouseAdapter {
+       
+      public void mouseClicked(MouseEvent e) {
+        JPopupMenu setPopup = new JPopupMenu("asdf");
+         if (e.isPopupTrigger()) {       
+	     setPopup.show(e.getComponent(),
+                           e.getX(), e.getY());
+	 }
+    }    
+    
+    public void mouseEntered(MouseEvent e) {
+    }    
+  
+    public void mouseExited(MouseEvent e) {
+    }
+    
+    public void mousePressed(MouseEvent e) {
+         JPopupMenu setPopup = new JPopupMenu("asdf");
+         if (e.isPopupTrigger()) {               
+	     setPopup.show(e.getComponent(),
+                           e.getX(), e.getY());
+	 }
+    }
+       
+    public void mouseReleased(MouseEvent e) {
+         JPopupMenu setPopup = new JPopupMenu("asdf");
+         if (e.isPopupTrigger()) {                  
+	     setPopup.show(e.getComponent(),
+                           e.getX(), e.getY());     
+	 }
+    }  
+   }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSPreferences.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSPreferences.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/GEMSPreferences.java	(revision 10506)
@@ -0,0 +1,406 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.gems;
+
+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.border.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.cdm.LanguageManager;
+import org.greenstone.gatherer.gui.*;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.w3c.dom.*;
+
+public class GEMSPreferences extends ModalDialog {
+
+    static final public String CONNECTION_PREFS = "connection";
+    static final public String GENERAL_PREFS = "general";
+    static final private Dimension LABEL_SIZE = new Dimension(280, 25);
+    static final private Dimension SIZE = new Dimension(640, 345);
+
+    private JButton apply_button;
+    private JButton cancel_button;
+    private JButton ok_button;
+
+    private JComboBox language_combobox;
+    private JList language_limited_jlist;  
+    private JList language_code_jlist;
+    private JLabel interface_language_label;
+    private JLabel language_label;
+
+    private JTabbedPane tab_pane;
+    private GEMSPreferences self;
+
+    public GEMSPreferences() {
+	// Initialize
+	super((JFrame) null, true);
+	this.self = this;
+	setSize(SIZE);
+	Dictionary.registerText(this, "Preferences");
+	setJMenuBar(new SimpleMenuBar("preferences"));
+
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+	tab_pane = new JTabbedPane();
+	JPanel general_preferences = createGeneralPreferences();
+	tab_pane.add("Preferences.General", general_preferences);
+        
+	Dictionary.register(tab_pane);
+
+	JPanel button_pane = new JPanel();
+	ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_O);
+    
+	Dictionary.registerBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	apply_button = new GLIButton();
+	apply_button.setMnemonic(KeyEvent.VK_A);
+	Dictionary.registerBoth(apply_button, "General.Apply", "General.Apply_Tooltip");
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.registerBoth(cancel_button, "General.Cancel", "General.Cancel_Tooltip");
+
+	// Connection
+	ok_button.addActionListener(new OKButtonListener(true));
+	apply_button.addActionListener(new OKButtonListener(false));
+	cancel_button.addActionListener(new CancelButtonListener());
+
+	// Layout
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,2,2,2));
+	button_pane.setLayout(new GridLayout(1,3,0,5));
+	button_pane.add(ok_button);
+	button_pane.add(apply_button);
+	button_pane.add(cancel_button);
+
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(tab_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+        setLocation(400, 300);
+	tab_pane.setSelectedComponent(general_preferences);
+	
+	// Clean up
+	general_preferences = null;
+	cancel_button = null;
+	ok_button = null;
+	button_pane = null;
+	tab_pane = null;
+	content_pane = null;
+
+	setVisible(true);
+    }
+
+    private JPanel createGeneralPreferences() {
+	JPanel general_pane = new JPanel();
+
+	// Build the model of available languages
+	ArrayList dictionary_model = new ArrayList();
+
+	// The new method makes use of the successor to the languages.dat file, classes/xml/languages.xml
+	// Should update to also give the full name of the language --Matthew
+	NodeList language_elements = LanguageManager.LANGUAGES_DOCUMENT.getDocumentElement().getElementsByTagName(StaticStrings.LANGUAGE_ELEMENT);
+	for(int i = 0; i < language_elements.getLength(); i++) {
+	    Element language_element = (Element) language_elements.item(i);
+	    if((language_element.getAttribute(StaticStrings.GLI_ATTRIBUTE)).equalsIgnoreCase(StaticStrings.TRUE_STR) || (language_element.getAttribute(StaticStrings.MDS_ATTRIBUTE)).equalsIgnoreCase(StaticStrings.TRUE_STR)) {
+		Locale locale = new Locale(language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE));
+		String description = language_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+		DictionaryEntry entry = new DictionaryEntry(description, locale);
+		if(!dictionary_model.contains(entry)) {
+		    dictionary_model.add(entry);
+		}
+		entry = null;
+		description = null;
+		locale = null;
+	    }
+	    language_element = null;
+	}
+	language_elements = null;
+
+	// Users email
+	JPanel lang_limited_pane = new JPanel();
+	interface_language_label = new JLabel();
+	interface_language_label.setPreferredSize(LABEL_SIZE);
+        
+	Dictionary.registerText(interface_language_label, "GEMS.Preferences.Selected_Languages_Tooltip");
+
+	// Language
+	JPanel language_pane = new JPanel();
+	language_label = new JLabel();
+	language_label.setPreferredSize(LABEL_SIZE);
+   
+	Dictionary.registerText(language_label, "Preferences.General.Interface_Language");
+	language_combobox = new JComboBox(dictionary_model.toArray());
+	Dictionary.registerTooltip(language_combobox, "Preferences.General.Interface_Language_Tooltip");
+	// Try to locate and select the current language
+	String language_code = Configuration.getLanguage();
+	for(int b = 0; b < language_combobox.getItemCount(); b++) {
+	    DictionaryEntry entry = (DictionaryEntry) language_combobox.getItemAt(b);
+	    if(language_code.equalsIgnoreCase(entry.getLocale().getLanguage())) {
+		language_combobox.setSelectedIndex(b);
+	    }
+	}
+        
+        //create language selected box, and high light the apprpropate ones
+	int [] selectedLanguages = new int[300];
+	int selectedLanguagesLength = 0;
+                 
+        GEMSLanguageManager gemsLangManager = new GEMSLanguageManager(GEMS.getGLIDirectoryPath() + "classes" + File.separator + "xml" + File.separator + "languages.xml");
+
+	//Create the visible JList, and then another one with just the language codes. 
+	language_code_jlist = new JList(gemsLangManager.getLanguageCodesToArray());  
+	language_limited_jlist = new JList(gemsLangManager.getLanguageCodesAndNames());
+
+	//Set the list up to display tabs properly
+  	TabListCellRenderer renderer = new TabListCellRenderer();
+	renderer.setTabs(new int[] {50, 200, 300});
+	language_limited_jlist.setCellRenderer(renderer);
+
+        String enabled_languages =  Configuration.getString("GEMS.Preferences.Selected_Languages", true);
+	//we have a string: enabled_languages that contains an array of strings delimited by comma's
+        String []enabled_languages_split = enabled_languages.split(",");
+        Object []language_codes_array = gemsLangManager.getLanguageCodesToArray();
+        
+        //for each enabled_languages_split, check which languages match, and store the index in selectedLanguages
+        for(int k = 0; k < enabled_languages_split.length; k++) {
+            
+            for(int p =0; p < language_codes_array.length; p++){
+                
+                //if the codes  match, then include the index p into the vector selectedLanguages
+                if (language_codes_array[p].toString().toLowerCase().trim().compareTo(enabled_languages_split[k].toLowerCase().trim()) == 0)
+		    {
+			selectedLanguages[selectedLanguagesLength] = p;
+			selectedLanguagesLength++;
+			language_limited_jlist.addSelectionInterval(p,p);
+		    }   
+            }   
+        }
+
+	// Layout
+        JScrollPane langScrollPane = new JScrollPane(language_limited_jlist);
+        langScrollPane.setPreferredSize(new Dimension(100, 100));
+	lang_limited_pane.setLayout(new GridLayout(1,3));
+	lang_limited_pane.add(interface_language_label);
+	lang_limited_pane.add(langScrollPane);
+        
+	language_pane.setLayout(new BorderLayout());
+	language_pane.add(language_label, BorderLayout.WEST);
+	language_pane.add(language_combobox, BorderLayout.CENTER);
+        
+	general_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	general_pane.setLayout(null);
+	general_pane.add(lang_limited_pane);
+	general_pane.add(language_pane);
+	//general_pane.add(view_extracted_metadata_checkbox);
+        Insets general_pane_insets = general_pane.getInsets();
+        
+        lang_limited_pane.setBounds(20+general_pane_insets.left, 20+general_pane_insets.top, 
+                           lang_limited_pane.getPreferredSize().width, lang_limited_pane.getPreferredSize().height);
+        
+        language_pane.setBounds(20+general_pane_insets.left, 130+general_pane_insets.top, 
+                            language_pane.getPreferredSize().width, language_pane.getPreferredSize().height);
+       
+	return general_pane;
+    }
+
+
+    private class OKButtonListener
+	implements ActionListener {
+	private boolean close;
+	public OKButtonListener(boolean close) {
+	    this.close = close;
+	}
+	public void actionPerformed(ActionEvent event) {
+	    // Submit the various changes
+
+            //save interface language
+	    String current_lang = Configuration.getLanguage();
+	    String new_lang = ((DictionaryEntry)language_combobox.getSelectedItem()).getLocale().getLanguage();
+	    if (!current_lang.equals(new_lang)) {
+		Configuration.setLocale("general.locale", Configuration.GENERAL_SETTING, ((DictionaryEntry)language_combobox.getSelectedItem()).getLocale());
+		JOptionPane.showMessageDialog(null, Dictionary.get("Preferences.General.Restart_Required"), Dictionary.get("General.Warning"), JOptionPane.WARNING_MESSAGE);
+	    }
+            
+	    //Set language_code_jlist to have the same selections as the language_limited_jlist.
+	    //(before, there was only one JList, and it only contained the language codes).
+	    int[] selection = language_limited_jlist.getSelectedIndices();
+	    language_code_jlist.setSelectedIndices(selection);
+	    Object[] selectedValues = language_code_jlist.getSelectedValues();
+	    String concatString = new String();
+	    
+	    for(int k = 0; k < selectedValues.length; k++) { 
+		if(selectedValues.length-k > 1) 
+		    concatString = concatString.concat(selectedValues[k].toString() +",");
+		else
+		    concatString = concatString.concat(selectedValues[k].toString());
+             }
+            
+            Configuration.setString("GEMS.Preferences.Selected_Languages",true, concatString);
+            
+	    // Always save configuration changes immediately (in case the GLI crashes)
+	    Configuration.save();
+
+	    // Hide dialog
+	    if(close) {
+		self.dispose();
+	    }
+	}
+    }
+
+    private class CancelButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    self.dispose();
+	}
+    }
+
+    private class DictionaryEntry
+	implements Comparable {
+	private Locale locale;
+	private String description;
+	public DictionaryEntry(Locale locale) {
+	    this.description = null;
+	    this.locale = locale;
+	}
+	public DictionaryEntry(String description, Locale locale) {
+	    this.description = description;
+	    this.locale = locale;
+	}
+	public int compareTo(Object object) {
+	    return toString().compareTo(object.toString());
+	}
+	public boolean equals(Object object) {
+	    return toString().equals(object.toString());
+	}
+	public Locale getLocale() {
+	    return locale;
+	}
+	public String toString() {
+	    if(description != null) {
+		return description;
+	    }
+	    else {
+		return locale.getDisplayName();
+	    }
+	}
+    }
+}
+
+
+/**
+   A custom list renderer, to display tabs in the JList properly.
+
+   @see http://manning.com/sbe/files/uts2/Chapter10html/Chapter10.htm
+   Added by Matthew Whyte
+   Date last modified: 1/02/05
+ */
+class TabListCellRenderer extends JLabel implements ListCellRenderer
+{
+    protected static Border m_noFocusBorder;
+    protected FontMetrics m_fm = null;
+    protected Insets m_insets = new Insets(0, 0, 0, 0);
+    
+    protected int m_defaultTab = 50;
+    protected int[] m_tabs = null;
+    
+    public TabListCellRenderer()
+    {
+	super();
+	m_noFocusBorder = new EmptyBorder(1, 1, 1, 1);
+	setOpaque(true);
+	setBorder(m_noFocusBorder);
+    }
+
+    public Component getListCellRendererComponent(JList list,
+						  Object value, int index, boolean isSelected, boolean cellHasFocus)     
+    {         
+	setText(value.toString());
+	
+	setBackground(isSelected ? list.getSelectionBackground() : list.getBackground());
+	setForeground(isSelected ? list.getSelectionForeground() : list.getForeground());
+	
+	setFont(list.getFont());
+	setBorder((cellHasFocus) ? UIManager.getBorder("List.focusCellHighlightBorder") : m_noFocusBorder);
+	
+	return this;
+    }
+    
+    public void setDefaultTab(int defaultTab) { m_defaultTab = defaultTab; }
+    
+    public int getDefaultTab() { return m_defaultTab; }
+
+    public void setTabs(int[] tabs) { m_tabs = tabs; }
+
+    public int[] getTabs() { return m_tabs; }
+
+    public int getTab(int index)
+    {
+	if (m_tabs == null)
+	    return m_defaultTab*index;
+		
+	int len = m_tabs.length;
+	if (index >= 0 && index < len)
+	    return m_tabs[index];
+
+	return m_tabs[len-1] + m_defaultTab*(index-len+1);
+    }
+
+
+    public void paint(Graphics g)
+    {
+	m_fm = g.getFontMetrics();
+	
+	g.setColor(getBackground());
+	g.fillRect(0, 0, getWidth(), getHeight());
+	getBorder().paintBorder(this, g, 0, 0, getWidth(), getHeight());
+
+	g.setColor(getForeground());
+	g.setFont(getFont());
+	m_insets = getInsets();
+	int x = m_insets.left;
+	int y = m_insets.top + m_fm.getAscent();
+
+	StringTokenizer	st = new StringTokenizer(getText(), "\t");
+	while (st.hasMoreTokens()) 
+	{
+	      String sNext = st.nextToken();
+	      g.drawString(sNext, x, y);
+		x += m_fm.stringWidth(sNext);
+
+		if (!st.hasMoreTokens())
+		    break;
+		int index = 0;
+		while (x >= getTab(index))
+		    index++;
+		x = getTab(index);
+	}
+    }   
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/MSMUtils.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/MSMUtils.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/MSMUtils.java	(revision 10506)
@@ -0,0 +1,639 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.gems;
+
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.cdm.CommandTokenizer;
+import org.greenstone.gatherer.util.ArrayTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+/** This class contains a plethora of methods associated with handling the content of <strong>MetadataSet</strong>s and the <strong>Element</strong>s within. For example this is where you will find methods for comparing various parts of two <strong>MetadataSet</strong>s for equality. It also has methods for extracting common and useful data from <strong>Element</strong>s such as the AssignedValue nodes.
+ * @author John Thompson, Greenstone Digital Libraries
+ * @version 2.3
+ */
+public class MSMUtils {
+    static public int NONE = 0;     //An element of the enumeration of type filter.
+    static public int VALUES = 1;   //An element of the enumeration of type filter.
+    static public int ALIASES = 2;  //An element of the enumeration of type filter.
+    static public int BOTH = 3;     //An element of the enumeration of type filter.
+    static public char NS_SEP= '.'; //The character used to separate name space from metadata element.
+    static public char SF_SEP= '^'; //The character used to separate subfields from metadata element.
+
+
+    /** Method to add an attribute element to the given element. This method makes use of the language_dependent attribute of the document to not only determine if the attribute is language dependent, but also to see whether a Language element should be created if doesn't already exist.
+     * @param element_element the Element to add the attribute element to
+     * @param attribute_name_str the name of the new attribute to add as a String
+     * @param language_code_str the two letter code String of the language this attribute is to be added as
+     * @param value_str the String to be assigned as the attribute elements value
+     * @see org.greenstone.gatherer.msm.MSMUtils#isAttributeLanguageDependent
+     * @see org.greenstone.gatherer.msm.MSMUtils#setValue(Element, String)
+     * @see org.greenstone.gatherer.util.StaticStrings#ATTRIBUTE_ELEMENT
+     * @see org.greenstone.gatherer.util.StaticStrings#CODE_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ELEMENT
+     * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
+     */ 
+    static public void addElementAttribute(Element element_element, String attribute_name_str, String language_code_str, String value_str) {
+	Document document = element_element.getOwnerDocument();
+	// Create the basic new attribute (everything except language attribute)
+	Element attribute_element = document.createElement(StaticStrings.ATTRIBUTE_ELEMENT);
+	attribute_element.setAttribute(StaticStrings.NAME_ATTRIBUTE, attribute_name_str);
+	MSMUtils.setValue(attribute_element, value_str);
+
+	// Start off by determining if we have to add this node in the new multilingual optimized way
+	if(isAttributeLanguageDependent(document, attribute_name_str)) {
+	    boolean found = false;
+	    // Try to retrieve a language element for the given language code
+	    //NodeList language_elements = element_element.getElementsByTagName(StaticStrings.LANGUAGE_ELEMENT);
+	    ArrayList language_elements = XMLTools.getChildElementsByTagName(element_element, StaticStrings.LANGUAGE_ELEMENT);
+	    for(int i = 0; i < language_elements.size(); i++) {
+		Element language_element = (Element) language_elements.get(i);
+		if(language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE).equals(language_code_str)) {
+		    found = true;
+		    // Add attribute
+		    language_element.appendChild(attribute_element);
+		}
+		language_element = null;
+	    }
+	    language_elements = null;
+	    // If it still hasn't been found, then add it
+	    if(!found) {
+		Element language_element = document.createElement(StaticStrings.LANGUAGE_ELEMENT);
+		language_element.setAttribute(StaticStrings.CODE_ATTRIBUTE, language_code_str);
+		element_element.appendChild(language_element);
+		// Add attribute
+		language_element.appendChild(attribute_element);
+		language_element = null;
+	    }
+	}
+	// Just add the attribute the old fashioned way
+	else {
+	    attribute_element.setAttribute(StaticStrings.LANGUAGE_ATTRIBUTE, language_code_str);
+	    element_element.appendChild(attribute_element);
+	}
+	// Clean up
+	attribute_element = null;
+	document = null;
+    }
+
+
+    /** Retrieve all of the attributes for the given element as a tree set. Note that this requires significant manipulation if the source is a multilingual optimized metadata set.
+     * @param element the Element whose attributes we wish to catalog
+     * @return a TreeSet of the attributes sorted by their natural ordering
+     * @see org.greenstone.gatherer.msm.MSMUtils#getValue(Node)
+     * @see org.greenstone.gatherer.util.StaticStrings#ATTRIBUTE_ELEMENT
+     * @see org.greenstone.gatherer.util.StaticStrings#CODE_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ELEMENT
+     * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
+     */
+    static public TreeSet getAttributes(Element element) {
+	TreeSet attribute_tree = new TreeSet();
+
+        GEMSLanguageManager gemsLangManager = new GEMSLanguageManager(GEMS.getGLIDirectoryPath() + "classes" + File.separator + "xml" + File.separator + "languages.xml");
+        
+        String[] enabled_langs = gemsLangManager.getEnabledLanguageCodesToArray();
+                       
+	for(Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) {
+	    if(node instanceof Element) {
+		Element some_element = (Element) node;
+		String some_element_name = some_element.getNodeName();
+		if(some_element_name.equals(StaticStrings.ATTRIBUTE_ELEMENT)) {
+		    attribute_tree.add(new Attribute(some_element.getAttribute(StaticStrings.NAME_ATTRIBUTE), some_element.getAttribute(StaticStrings.LANGUAGE_ATTRIBUTE), MSMUtils.getValue(some_element)));
+                    // System.out.println(some_element_name +  "<- some_element nodes' value");
+                }
+		else if(some_element_name.equals(StaticStrings.LANGUAGE_ELEMENT)) {
+		    String language_code = some_element.getAttribute(StaticStrings.CODE_ATTRIBUTE);
+		    NodeList attribute_elements = some_element.getElementsByTagName(StaticStrings.ATTRIBUTE_ELEMENT);
+                    
+		    for(int i = 0; i < attribute_elements.getLength(); i++) {
+			Element attribute_element = (Element) attribute_elements.item(i);
+                     
+                            for(int k = 0; k < enabled_langs.length; k++){
+                                
+                               if(enabled_langs[k].trim().compareTo(some_element.getAttributes().item(0).getNodeValue().toString()) == 0){
+				   attribute_tree.add(new Attribute(attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE), language_code, MSMUtils.getValue(attribute_element)));
+				   attribute_element = null;
+				   
+				   break;
+                               }
+                            }
+			    attribute_element = null;
+		   } 
+		    attribute_elements = null;
+		    language_code = null;
+		}
+		some_element_name = null;
+		some_element = null;
+	    }
+	}
+	return attribute_tree;
+    }
+
+
+    /** Method to construct an elements description by retrieving the correct attribute.
+     * @param element the Element whose name we wish to retrieve
+     * @return a String which is the elements description, or an empty string if no description exists
+     * @see org.greenstone.gatherer.msm.MSMUtils#getElementAttribute
+     * @see org.greenstone.gatherer.util.StaticStrings#COMMENT_VALUE
+     * @see org.greenstone.gatherer.util.StaticStrings#DEFINITION_VALUE
+     * @see org.greenstone.gatherer.util.StaticStrings#EMPTY_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#SPACE_CHARACTER
+     */
+    static public String getDescription(Element element) {
+	String language_code_str = Configuration.getLanguage();
+	StringBuffer description = new StringBuffer(StaticStrings.EMPTY_STR);
+	description.append(getElementAttribute(element, StaticStrings.DEFINITION_VALUE, language_code_str));
+	if(description.length() > 0) {
+	    description.append(StaticStrings.SPACE_CHARACTER);
+	}
+	description.append(getElementAttribute(element, StaticStrings.COMMENT_VALUE, language_code_str));
+	language_code_str = null;
+	return description.toString();
+    }
+
+
+    /** Retrieve the value for the requested attribute in the required language. Once again this method must be aware of the differences between the old metadata sets and the new multilingual optimized ones.
+     * @param element_element the Element whose attributes we are searching through
+     * @param attribute_name_str the name of the desired attribute as a String
+     * @param language_code_str the two letter code String indicating the desired language
+     * @see org.greenstone.gatherer.msm.MSMUtils#getValue
+     * @see org.greenstone.gatherer.msm.MSMUtils#isAttributeLanguageDependent
+     * @see org.greenstone.gatherer.util.StaticStrings#ATTRIBUTE_ELEMENT
+     * @see org.greenstone.gatherer.util.StaticStrings#CODE_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#EMPTY_STR
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ELEMENT
+     * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
+     */
+    static private String getElementAttribute(Element element_element, String attribute_name_str, String language_code_str) {
+	boolean found = false;
+	String result = StaticStrings.EMPTY_STR;
+	Document document = element_element.getOwnerDocument();
+	// Determine if the attribute is language specific
+	if(isAttributeLanguageDependent(document, attribute_name_str)) {
+	    NodeList language_elements = element_element.getElementsByTagName(StaticStrings.LANGUAGE_ELEMENT);
+	    for(int i = 0; !found && i < language_elements.getLength(); i++) {
+		Element language_element = (Element) language_elements.item(i);
+		if(language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE).equals(language_code_str)) {
+		    NodeList attribute_elements = language_element.getElementsByTagName(StaticStrings.ATTRIBUTE_ELEMENT);
+		    for(int j = 0; !found && j < attribute_elements.getLength(); j++) {
+			Element attribute_element = (Element) attribute_elements.item(j);
+			if(attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equals(attribute_name_str)) {
+			    found = true;
+			    result = MSMUtils.getValue(attribute_element);
+			}
+			attribute_element = null;
+		    }
+		    attribute_elements = null;
+		}
+		language_element = null;
+	    }
+	    language_elements = null;
+	}
+	else {
+	    boolean first_match = false;
+	    NodeList attribute_elements = element_element.getElementsByTagName(StaticStrings.ATTRIBUTE_ELEMENT);
+	    for(int k = 0; !found && k < attribute_elements.getLength(); k++) {
+		Element attribute_element = (Element) attribute_elements.item(k);
+		// We don't want to consider those attributes found inside language elements
+		if(attribute_element.getParentNode() == element_element) {
+		    ///ystem.err.println("First level");
+		    String target_name_str = attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+		    String target_language_str = attribute_element.getAttribute(StaticStrings.LANGUAGE_ATTRIBUTE);
+		    ///ystem.err.println("Does " + target_name_str + " equal " + attribute_name_str + "?");
+		    if(attribute_name_str.equals(target_name_str)) {
+			///ystem.err.println("Does " + target_language_str + " equal " + language_code_str + "?");
+			if(language_code_str.equals(target_language_str)) {
+			    ///ystem.err.println("Perfect match!");
+			    found = true;
+			    result = MSMUtils.getValue(attribute_element);
+			}
+			else if((result == StaticStrings.EMPTY_STR || first_match) && isLegacyMDS(document)) {
+			    ///ystem.err.println("Legacy MDS");
+			    // Special case for old style documents, where the english match is good enough
+			    if(target_language_str.equals(StaticStrings.ENGLISH_LANGUAGE_STR)) {
+				///ystem.err.println("English plate.");
+				result = MSMUtils.getValue(attribute_element);
+			    }
+			    // Super special case where the first match is better than nothing
+			    else if(result == StaticStrings.EMPTY_STR && !first_match) {
+				///ystem.err.println("First match.");
+				first_match = true;
+				result = MSMUtils.getValue(attribute_element);
+			    }
+			}
+		    }
+		    target_language_str = null;
+		    target_name_str = null;
+		}
+		attribute_element = null;
+	    }
+	    attribute_elements = null;
+	}
+	document = null;
+	return result;
+    }
+
+
+
+    /** Method to construct an elements fully qualified name. Note that this is different from a nodes identifier. Think of name as a short, unique reference to a metadata element, whereas identifier can be much longer, language specific and non-unique.
+     * @param element An <strong>Element</strong> whose name we are interested in.
+     * @return A <strong>String</strong> representing this given elements fully namespace qualified name.
+     */
+    static final public String getFullName(Element element) {
+	return getFullName(element, "");
+
+    }
+
+
+    /** Method to construct an elements fully qualified name. Note that this is different from a nodes identifier. Think of name as a short, unique reference to a metadata element, whereas identifier can be much longer, language specific and non-unique.
+     * @param element An <strong>Element</strong> whose name we are interested in.
+     * @return A <strong>String</strong> representing this given elements fully namespace qualified name.
+     */
+    static final public String getFullName(Element element, String namespace) {
+	StringBuffer name_buffer = new StringBuffer();
+	if(element == null) {
+	    return "Error";
+	}
+	// First get the root node.
+	Document document = element.getOwnerDocument();
+	Element root = document.getDocumentElement();
+	document = null;
+	// Retrieve this elements name
+	name_buffer.append(element.getAttribute("name"));
+
+	// Now we check if element has a parent node, other than root. If so we begin building up the full name
+	//For some reason this doesn't work in specific cases of subelements.
+	Element parent_element = (Element) element.getParentNode();
+	while(parent_element != null && parent_element != root) { 
+	    name_buffer.insert(0, SF_SEP);
+	    name_buffer.insert(0, parent_element.getAttribute("name"));
+	    parent_element = (Element)parent_element.getParentNode();
+	}
+	parent_element = null;
+	// Finally insert the namespace and we are all done.
+	if(root != null) {
+	    namespace = root.getAttribute("namespace");
+	} 
+	root = null;
+	// If no root, or no namespace found, assume its extracted (at least then they can't edit it)
+	if(namespace == null || namespace.equals("")) {
+	    namespace = MetadataSetManager.EXTRACTED_METADATA_NAMESPACE;
+	}
+	name_buffer.insert(0, NS_SEP);
+	name_buffer.insert(0, namespace);
+	namespace = null;
+	return name_buffer.toString();
+    } // static public String getFullName(Element element)
+
+
+    /**
+       Method to get an element's name, not including its namespace.
+       @param element an <strong>Element</strong> whose name we are interested in.
+       @return A <strong>Strong</strong> representing the given elements name
+       @author Matthew Whyte
+       @date last modified: 21/01/04
+     */
+    static final public String getNameOnly(Element element)
+    {
+	StringBuffer name_buffer = new StringBuffer();
+	if(element == null) {
+	    return "Error";
+	}
+	// Retrieve this elements name
+	name_buffer.append(element.getAttribute("name"));
+
+	return name_buffer.toString();
+    }
+
+
+    /** Method to construct an elements name (sic identifier) by retrieving the correct attribute, language specific.
+     * @param element the Element whose name we wish to retrieve
+     * @return a String which is the elements identifier, or an empty string if no identifier exists
+     * @see org.greenstone.gatherer.msm.MSMUtils#getElementAttribute
+     * @see org.greenstone.gatherer.util.StaticStrings#IDENTIFIER_VALUE
+     * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
+     */
+    static final public String getIdentifier(Element element) {
+	String identifier = getElementAttribute(element, StaticStrings.IDENTIFIER_VALUE, Configuration.getLanguage());
+	// Failing the above we return the nodes name instead.
+	if(identifier == null || identifier.length() == 0) {
+	    identifier = element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+	}
+
+	return identifier;
+    }
+
+
+    /** Method to retrieve from the node given, a certain child node with the specified name.
+     * @param parent The <strong>Node</strong> whose children should be searched.
+     * @param name The required nodes name as a <strong>String</strong>.
+     * @return The requested <strong>Node</strong> if it is found, <i>null</i> otherwise.
+     */ 
+    static final public Node getNodeFromNamed(Node parent, String name) {
+	Node child = null;
+	for(Node i = parent.getFirstChild(); i != null && child == null; 
+	    i = i.getNextSibling()) {
+	    if(i.getNodeName().equals(name)) {
+		child = i;
+	    }
+	}
+	return child;
+    }
+
+
+    /** Look for the occurances 'field' of the element and return it if found.
+     * @return An <i>int</i> which matches the number in the occurances attribute of the element, or 0 if no such attribute.
+     */
+    static final public int getOccurances(Element element) {
+	int count = 0;
+	String number = null;
+	if((number = element.getAttribute("occurances")) != null) {
+	    try {
+		count = Integer.parseInt(number);
+	    }
+	    catch(Exception error) {
+		count = 0;
+	    }
+	}
+	return count;
+    }	 
+
+
+    /** Method to retrieve the value of a given node (not the assigned values tree!).
+     * @param element The <strong>Element</strong> whose value we wish to find.
+     * @return The value found as a <strong>String</strong>, or <i>null</i> if this element has no value.
+     */
+    static final public String getValue(Node element) {
+	// If we've been given a subject node first retrieve its value node.
+	if(element.getNodeName().equals("Subject")) {
+	    element = getNodeFromNamed(element, "Value");
+	}
+	// If we've got a value node, then reconstruct the text. Remember that DOM will split text over 256 characters into several text nodes
+	if(element != null && element.hasChildNodes()) {
+	   StringBuffer text_buffer = new StringBuffer();
+	   NodeList text_nodes = element.getChildNodes();
+	   for(int i = 0; i < text_nodes.getLength(); i++) {
+	      Node possible_text = text_nodes.item(i);
+	      if(possible_text.getNodeName().equals(StaticStrings.TEXT_NODE)) {
+		 text_buffer.append(possible_text.getNodeValue());
+	      }
+	   }
+	   return text_buffer.toString();
+	}
+	return "";
+    }
+
+
+    /** Determine if the named attribute is language specific for this collection. This information is found in a DOM attribute of the document element, as a comma separated list of attribute names.
+     * @param document the Document for which we wish to check the language requirements
+     * @param attribute_name_str the name of the attribute we a testing as a String
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGEDEPENDENT_ATTRIBUTE
+     * Modified by Matthew Whyte 4/02/05
+     */
+    static private boolean isAttributeLanguageDependent(Document document, String attribute_name_str)
+    {
+	//gives a list of comma seperated language specific attributes.
+	String language_specific_attributes = document.getDocumentElement().getAttribute(StaticStrings.LANGUAGEDEPENDENT_ATTRIBUTE).toLowerCase();
+	//System.err.println("lang_specific: " + language_specific_attributes); //debug
+
+	//Seperate out language_specific_attributes
+	String[] attributes_split = language_specific_attributes.split(",");
+
+	//Compare each to attribute_name_str
+	for(int i = 0; i < attributes_split.length; i++)
+	    {
+		if(attributes_split[i].trim().compareTo(attribute_name_str.toLowerCase()) == 0)
+		    return true;
+	    }
+	return false;
+    }
+
+
+    /** A method to remove a specific attribute element from an element. This attribute must match in name, language and in value before being removed. Note that this method supports both legacy and multilingual optimized versions of the mds.
+     * @param element_element the Element which represent the metadata element we are altering
+     * @param attribute_name_str the name of the attribute to remove as a String
+     * @param language_code_str the language code we must match as a String
+     * @param value_str the value String which also must match before we remove anything
+     * @return true if the desired attribute was successfully found and removed, false otherwise
+     * @see org.greenstone.gatherer.msm.MSMUtils#isAttributeLanguageDependent
+     * @see org.greenstone.gatherer.msm.MSMUtils#getValue(Node)
+     * @see org.greenstone.gatherer.util.StaticStrings#ATTRIBUTE_ELEMENT
+     * @see org.greenstone.gatherer.util.StaticStrings#CODE_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGE_ELEMENT
+     * @see org.greenstone.gatherer.util.StaticStrings#NAME_ATTRIBUTE
+     */
+    static public boolean removeElementAttribute(Element element_element, String attribute_name_str, String language_code_str, String value_str) {
+	//Determine the if this is one of the language specific attributes.
+	//This can sometimes give a false result, if an attribute is made language specific half way through creation of a metadata set (or vice versa).
+	if(isAttributeLanguageDependent(element_element.getOwnerDocument(), attribute_name_str))
+	    {
+		/*
+		Multilingual Optimized version, eg:
+		<Language code="en">
+		    <Attribute name="identifier">second</Attribute>
+		</Language>
+		*/
+		return removeElementAttributeNew(element_element, attribute_name_str, language_code_str, value_str, false);
+	    }
+	else
+	    {
+		/*
+		The old way, eg:
+		<Attribute language="en" name="identifier">second</Attribute>
+		*/
+		return removeElementAttributeOld(element_element, attribute_name_str, language_code_str, value_str, false);
+	    }
+	
+    }
+    static final private boolean removeElementAttributeNew(Element element_element, String attribute_name_str, String language_code_str, String value_str, boolean run_once)
+    {
+	// Retrieve the language elements, and determine the correct one
+	NodeList language_elements = element_element.getElementsByTagName(StaticStrings.LANGUAGE_ELEMENT);
+	for(int i = 0; i < language_elements.getLength(); i++) {
+	    Element language_element = (Element) language_elements.item(i);
+	    if(language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE).equalsIgnoreCase(language_code_str)) {
+		NodeList attribute_elements = language_element.getElementsByTagName(StaticStrings.ATTRIBUTE_ELEMENT);
+		for(int j = 0; j < attribute_elements.getLength(); j++) {
+		    Element attribute_element = (Element) attribute_elements.item(j);
+		    String target_name_str = attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+		    String target_value_str = MSMUtils.getValue(attribute_element);
+		    if(attribute_name_str.equals(target_name_str) && value_str.equals(target_value_str)) {
+			language_element.removeChild(attribute_element);
+			if(attribute_elements.getLength() == 0) {
+			    element_element.removeChild(language_element);
+			}
+			target_value_str = null;
+			target_name_str = null;
+			attribute_element = null;
+			attribute_elements = null;
+			language_element = null;
+			language_elements = null;
+			return true;
+		    }
+		    target_value_str = null;
+		    target_name_str = null;
+		    attribute_element = null;			
+		}
+		attribute_elements = null;
+	    }
+	    language_element = null;
+	}
+	language_elements = null;
+	// Not found. Try the old way before failing.
+	if(!run_once)
+	    return removeElementAttributeOld(element_element, attribute_name_str, language_code_str, value_str, true);
+	return false;
+    }
+    static final private boolean removeElementAttributeOld(Element element_element, String attribute_name_str, String language_code_str, String value_str, boolean run_once)
+    {
+	// Find the attribute to remove
+	NodeList attribute_elements = element_element.getElementsByTagName(StaticStrings.ATTRIBUTE_ELEMENT);
+	for (int k = 0; k < attribute_elements.getLength(); k++) {
+	    Element attribute_element = (Element) attribute_elements.item(k);
+	    // Remember to ignore any attributes that live within nested language elements
+	    if (attribute_element.getParentNode() == element_element && attribute_element.getAttribute(StaticStrings.NAME_ATTRIBUTE).equals(attribute_name_str) && attribute_element.getAttribute(StaticStrings.LANGUAGE_ATTRIBUTE).equalsIgnoreCase(language_code_str) && MSMUtils.getValue(attribute_element).equals(value_str)) {
+		// Match found, so remove the attribute node and return
+		element_element.removeChild(attribute_element);
+		attribute_element = null;
+		attribute_elements = null;
+		return true;
+	    }
+	    attribute_element = null;
+	}
+	attribute_elements = null;
+	// No match found. Try the new way before failing.
+	if(!run_once)
+	    return removeElementAttributeNew(element_element, attribute_name_str, language_code_str, value_str, true);
+	return false;
+    }
+
+
+    /** can only be used to set the english value */
+    static final public void setIdentifier(Node element, String value) {
+	// Get the 'identifier' Element
+	for(Node node = element.getFirstChild(); node != null;
+	    node = node.getNextSibling()) {
+	    if(node.getNodeName().equals("Attribute")) {
+		Element target = (Element)node;
+		if(target.getAttribute("name").equals("identifier") && target.getAttribute("language").equals("en")) {
+		    Node text = target.getFirstChild();
+		    text.setNodeValue(value);
+		    break;
+		}
+	    }
+	}
+    }
+
+
+    /** Set the value of the element attribute occurances.
+     * @param element The <strong>Element</strong> to change.
+     * @param value The value to change by as an <i>int</i>.
+     */
+    static final public void setOccurance(Element element, int value) {
+	Integer new_value = new Integer(getOccurances(element) + value);
+	element.setAttribute("occurances", new_value.toString());
+    }
+
+
+    /** Set the #text node value of some element.
+     * @param element the Element whose value we wish to set
+     * @param value the new value for the element as a String
+     */
+    static final public void setValue(Element element, String value) {
+	// Remove any existing child node(s)
+	clear(element);
+	// Add new text node.
+	if (value != null) {
+	    element.appendChild(element.getOwnerDocument().createTextNode(value));
+	}
+    }
+
+
+    /** This method also traverses the tree, but this one is used to gather all the values and aliases at once, and to 'prune' the tree if necessary.
+     * @param current The current root <strong>Node</strong> of this AssignedValues tree subtree.
+     * @param return_filter This <i>int</i> specifies what nodes from the tree should be returned, where;<br>VALUES  = return values only<br>ALIASES = return aliases only<br>BOTH    = return both values and aliases<br>NONE    = return nothing.
+     * @param remove_leaves A leaf node is a subject that contains no child subjects. If this <i>boolean</i> is set to <i>true</i> then the leaf nodes will be removed from the tree. 
+     * @return A <strong>Node[]</strong> containing whatever values or aliases have been found during the trees traversal.
+     */
+    static final public Node[] traverseTree(Node current, int return_filter, boolean remove_leaves) {
+	Node leaves[] = null;
+	String name = current.getNodeName();
+	if(name.equals("Value") && (return_filter == VALUES || return_filter == BOTH)) {
+	    leaves = ArrayTools.add(leaves, current);
+	}
+	else if(name.equals("Alias") && (return_filter == ALIASES || return_filter == BOTH)) {
+	    leaves = ArrayTools.add(leaves, current);
+	}
+	else if(name.equals("Subject")) {
+	    boolean has_subject_child = false;
+	    Node children[] = ArrayTools.nodeListToNodeArray(current.getChildNodes());
+	    for(int i = 0; i < children.length; i++) {
+		if(children[i].getNodeName().equals("Subject")) {
+		    has_subject_child = true;
+		}
+		leaves = ArrayTools.add(leaves, traverseTree(children[i], return_filter, remove_leaves));
+	    }
+	    if(!has_subject_child && remove_leaves) {
+		Node parent = current.getParentNode();
+		parent.removeChild(current);
+	    }
+	}
+	else if(name.equals("AssignedValues")) {
+	    Node children[] = ArrayTools.nodeListToNodeArray(current.getChildNodes());
+	    for(int i = 0; i < children.length; i++) {
+		leaves = ArrayTools.add(leaves, traverseTree(children[i], return_filter, remove_leaves));
+	    }
+	}															  
+	return leaves;
+    }
+
+
+    /** Determine if the given document is a legacy MDS or a new multilingual one. The easiest way to tell is whether there is a language_dependant attribute in the document element.
+     * @param document the Document to test
+     * @return true if this is an old mds, false otherwise
+     * @see org.greenstone.gatherer.util.StaticStrings#LANGUAGEDEPENDANT_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#EMPTY_STR
+     */
+    static private boolean isLegacyMDS(Document document) {
+	///ystem.err.println("isLegacyMDS(): l_d = " + document.getDocumentElement().getAttribute(StaticStrings.LANGUAGEDEPENDANT_ATTRIBUTE));
+	return (document.getDocumentElement().getAttribute(StaticStrings.LANGUAGEDEPENDENT_ATTRIBUTE)).equals(StaticStrings.EMPTY_STR);
+    }
+
+
+    /** Remove all of the child nodes from a certain node. */
+    static final public void clear(Node parent) {
+	while(parent.hasChildNodes()) {
+	    parent.removeChild(parent.getFirstChild());
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/MetadataSet.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/MetadataSet.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/MetadataSet.java	(revision 10506)
@@ -0,0 +1,549 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import org.apache.xerces.dom.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+/** An semi-data class to hold details about a loaded metadata set, it also provides some methods to manipulating the data within. 
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3b
+ */
+public class MetadataSet {
+    /** The <Strong>Document</strong> of the DOM model. */
+    private Document document = null;
+    /** The document <strong>Element</strong> of the DOM model. */
+    private Element  root     = null;
+    /** The <strong>File</strong> this metadata set was loaded from. */
+    public String old_filename = null;
+    private File     file     = null;
+    /** The list of metadata elements which are, of course, children of the root node. */
+    private ArrayList elements = null;
+    
+    // the nmae of the collection if this set is collection-specific
+    private String collection = null;
+    //set_changed is check in msm(metadatasetmanager).save() and if this is true then we save
+    //the collection, otherwise we leave it as is
+    private boolean setChanged = false;
+    private String current_language_code;
+    /** The description of this metadata set. Cached as it takes more computation time. */
+    private String description = null;
+    /** The name of this metadata set. Cached as it takes more computation time. */
+    private String name = null;
+    /** An element of the tree pruning filter enumeration, that indicates all nodes in the tree should be retained. */
+    static final int ALL_VALUES    = 1;
+    /** An element of the tree pruning filter enumeration, that indicates only metadata Subject nodes or higher should remain after pruning. */
+    static final int SUBJECTS_ONLY = 2;
+    /** An element of the tree pruning filter enumeration, that indicates no value nodes i.e. the entire AssignedValues subtree, should remain after pruning. */
+    static final int NO_VALUES     = 3;
+
+    public MetadataSet(String metadata_template) {
+	
+	this.file = new File(metadata_template);
+	this.document = XMLTools.parseXMLFile(metadata_template, true);
+
+	init(true); // use class loader
+    }
+
+    /** Constructor.
+     * @param file The file the metadata set should be loaded from. 
+     */
+    public MetadataSet(File file) {
+	this.file = file;
+	this.document = XMLTools.parseXMLFile(file);
+
+	init(false); // don't use class loader
+    }
+
+    /** Copy constructor. 
+     * @param original The original metadata set to copy from.
+     */
+    public MetadataSet(MetadataSet original) {
+	// We have to create a new document.
+	document = new DocumentImpl(original.getDocument().getDoctype());
+	root = (Element) document.importNode(original.getDocument().getDocumentElement(), true);
+	document.appendChild(root);
+	elements = XMLTools.getChildElementsByTagName(root, "Element");
+	//elements = root.getElementsByTagName("Element");
+	file = original.getFile();
+    }
+  
+    public boolean getSetChanged() {
+        
+        return setChanged;    
+    }
+    public void setSetChanged(boolean val) {
+         
+        setChanged = val;
+    }
+
+
+    public void setCollection(String coll) {
+	collection = coll;
+
+    }
+    /** Add a mds level attribute.
+     * @param name The name of the attribute to add as a <Strong>String</strong>.
+     * @param value The value as a <strong>String</strong>.
+     */
+    public void addAttribute(String name, String value) {
+	root.setAttribute(name, value);
+    }
+
+
+    /** Add a new default metadata element with the given name to this metadata set.
+	This method also handles the addtion of 'subelements'
+     * @param name The name of this element as a <strong>String</strong>.
+     * @param parent The parent element as an <strong>GEMSNode</strong>. If null, the parent is the metadataset root.
+     * @return An <strong>ElementWrapper</strong> around the newly created element or null if the element was not created.
+     */
+    public ElementWrapper addElement(String name, String language, GEMSNode parent)
+    {
+	Element parent_element = null;
+
+	//The element that we are creating
+	Element element = document.createElementNS("","Element");
+	element.setAttribute("name",name);
+
+	//Add identifier attribute. This handles if we use the new or old language identification
+	MSMUtils.addElementAttribute(element, "identifier", language, name);
+	
+	if(parent == null) //A element
+	    {
+		parent_element = root;
+		elements.add(element); //Add the new element to the list of 'em
+	    }
+	else //A subelement!
+	    {
+		//Add the new subelement to the list of 'em
+		parent.getElement().addSubelementToList(element);
+		parent_element = parent.getElement().getElement(); //get the parent as an Element
+	    }
+
+	parent_element.appendChild(element);
+
+	return new ElementWrapper(element);
+    }
+
+
+    public int compare(Element e1, Element e2) {
+	int result = 0;
+	// Check that they're not the same element.
+	if(e1 != e2) {
+	    int index_e1 = -1;
+	    int index_e2 = -1;
+	    // Locate the indexes for each element.
+	    for(int i = 0; i < elements.size(); i++) {
+		Node element = (Node)elements.get(i);
+		if(element == e1) {
+		    index_e1 = i;
+		}
+		if(element == e2) {
+		    index_e2 = i;
+		}
+	    }
+	    if(index_e1 < index_e2) {
+		result = -1;
+	    }
+	    else {
+		result = 1;
+	    }
+	}
+	return result;
+    }
+
+    /** A method to determine if this metadata set contains an element with a certain name (case sensitive).
+     * @param name A <strong>String</strong> which is the name of the element whose presence we are checking.
+     * @return A <i>boolean</i> which is <i>true</i> if the named element exists, <i>false</i> otherwise.
+     */
+    public boolean containsElement(String name) {
+	for(int i = 0; i < elements.size(); i++) {
+	    Element sibling = (Element) elements.get(i);
+	    String sibling_name = sibling.getAttribute("name");
+	    if(sibling_name.equals(name)) {
+		return true;
+	    }
+	}
+	return false;
+    }
+
+    public NamedNodeMap getAttributes() {
+	return root.getAttributes();
+    }
+
+    /** Method to retrieve the contact address of the metadata set creator.
+     * @return A <strong>String</strong> containing the address. 
+     */
+    /* private String getContact() {
+	return root.getAttribute("contact");
+	} */
+    /** Method to retrieve the name of the creator of this metadata set. 
+     * @return A <strong>String</strong> containing the name.
+     */
+    public String getCreator() {
+	return root.getAttribute("creator");
+    }
+    /** Method to retrieve the description of this metadata set. Note that this is language specific, so we determine the desired language from the Dictionary. If no such entry exists, first try returning the english version and failing that the first description found.
+     * @return The description as a <strong>String</strong>.
+     */
+    public String getDescription() {
+	if(current_language_code != null && !Configuration.getLanguage().equals(current_language_code)) {
+	    description = null;
+	}
+	if(description == null) {
+	    description = getAttribute(StaticStrings.DESCRIPTION_ELEMENT, Dictionary.get("GEMS.No_Description"));
+	}
+	return description;
+    }
+
+    /** Method to retrieve the <strong>Document</strong> associated with this metadata set.
+     * @return The <strong>Document</strong> representing this metadata set.
+     */
+    public Document getDocument() {
+	return document;
+    }
+    /** Method to retrieve the metadata element indicated by an index.
+     * @param index An <i>int</i> specifying the required element.
+     * @return The <strong>Element</strong> at the index.
+     */
+    public Element getElement(int index) {
+	return (Element)elements.get(index);
+    }
+    /** This method is used to acquire a reference to the element which matches the given metadata. Note that this is not the same as <i>metadata.getElement()</i> as the reference returned by it may now be obsolete.
+     * @param metadata A <strong>Metadata</strong> object representing an element and value assignment.
+     * @return A 'live' reference to an <strong>Element</strong> which is the same as that referenced by the given metadata, or <i>null</i> if there is no such element.
+     */
+//     public Element getElement(Metadata metadata) {
+// 	return metadata.getElement().getElement();
+//     }
+    /** This method is used to acquire a reference to the element which has the name specified. Note that this is not the same as <i>metadata.getElement()</i> as the reference returned by it may now be obsolete.
+     * @param name A <strong>String</strong> stating the desired objects name.
+     * @return A 'live' reference to an <strong>Element</strong> which is the same as that referenced by the given metadata, or <i>null</i> if there is no such element.
+     */
+    public Element getElement(String name) {
+	// Strip any namespace.
+	while(name.indexOf(".") != -1 && !name.equals(".")) {
+	    name = name.substring(name.indexOf(".") + 1);
+	}
+	///ystem.err.println("Get element named " + name);
+	for(int i = 0; i < elements.size(); i++) {
+	    Element element = (Element) elements.get(i);
+	    ///ystem.err.println("Compare to: " + element.getAttribute("name"));
+	    if(element.getAttribute("name").equals(name)) {
+		return element;
+	    }
+	}
+	return null;
+    }
+
+    public Element getElement(Element parent_element, String name) {
+	DebugStream.println("Get element named " + name + " from " + parent_element.getAttribute("name"));
+	ArrayList elements = XMLTools.getChildElementsByTagName(parent_element, "Element");
+	for(int i = 0; i < elements.size(); i++) {
+	    Element element = (Element) elements.get(i);
+	    if(element.getAttribute("name").equals(name) && element.getParentNode() == parent_element) {
+		elements = null;
+		return element;
+	    }
+	}
+	elements = null;
+	return null;
+    }
+    /** Method to acquire a list of all the elements in this metadata set. 
+     * @return A <strong>NodeList</strong> containing all of this sets elements.
+     */
+    public ArrayList getElements() {
+	return elements;
+    }
+
+    /** Method to retrieve a list of all the elements in this metadata set, sorted.
+     * @return A <strong>Vector</strong> containing all of the elements of this sets, sorted.
+     */
+//     public Vector getElementsSorted() {
+// 	Vector elements_list = new Vector();
+// 	for (int i = 0; i < elements.size(); i++) {
+// 	    elements_list.add(new ElementWrapper((Element) elements.get(i)));
+// 	}
+// 	Collections.sort(elements_list, MSMUtils.METADATA_COMPARATOR);
+// 	return elements_list;
+//     }
+
+    /** Method to retrieve the original file this metadata set was created from.
+     * @return A <strong>File</strong>.
+     */
+    public File getFile() {
+	return file;
+    }
+    /** Get the last changed attribute.
+     * @return Last changed as a <strong>String</strong>.
+     */
+    public String getLastChanged() {
+	return root.getAttribute("lastchanged");
+    }
+
+    /** Method to get this metadata sets name. Note that this is language specific, so we determine the desired language from the Dictionary.
+	If no such entry exists, first try returning the english version and failing that the first name found.
+     * @return A <strong>String</strong> which contains its name.
+     */
+    public String getName() {
+	if(current_language_code != null && !Configuration.getLanguage().equals(current_language_code)) {
+	   // name = null;
+            return null;
+	}
+	if(name == null) {
+            
+	    //name = getAttribute(StaticStrings.NAME_ELEMENT, Dictionary.get("MSM.No_Name"));
+	   return getAttribute(StaticStrings.NAME_ELEMENT, Dictionary.get("GEMS.No_Name"));
+	
+        }
+     
+	return name;
+    }
+    /** Method to retrieve this metadata sets namespace.
+     * @return The namespace as a <strong>String</strong>.
+     */
+    public String getNamespace() {
+	return root.getAttribute("namespace");
+    }
+
+    /**
+       Method to change this metadata set's namespace
+       @param: The new namespace as a <strong>String</strong>
+     */
+    public void setNamespace(String new_namespace)
+    {
+	root.setAttribute("namespace", new_namespace);
+    }
+
+    /** Method to retrieve the root element, i.e. the Document Element, of the DOM model behind this metadata set.
+     * @return An <strong>Element</strong> which is at the root of the modal.
+     */ 
+    public Element getRoot() {
+	return root;
+    }
+
+    /** Remove a mds level attribute.
+     * @param name The name of the attribute to remove.
+     */
+    public void removeAttribute(String name) {
+	root.removeAttribute(name);
+    }
+
+    /** Method to remove the given element from this metadata set.
+     * @param element The <strong>Element</strong> to be removed.
+     * @param parent The parent element (wrapped, so can access its subelement list), as an <strong>ElementWrapper</strong>. If null, the parent is root.
+     */
+    public void removeElement(Element element, ElementWrapper parent) {
+	try {
+	    ElementWrapper element_wrapped = new ElementWrapper(element);
+
+	    if(parent == null)
+		{
+		    elements.remove(element);
+		    root.removeChild(element);
+		}
+	    else
+		{
+		    parent.removeSubelementFromList(element);
+		    parent.getElement().removeChild(element);
+		}
+	    
+	} catch(Exception DOMException) { //The element does not exist!
+	    System.err.println("Exception: '"+ DOMException + "' occured. Cannot remove element because it does not exist.");
+	}
+    }
+
+ /**
+       Rename the metadata element.
+       @param oldElement An <strong>Element</strong> we wish to rename
+       @param newName A <strong>String</strong> which contains the new name of the element.
+       @return An <strong>ElementWrapper</strong> around the newly named element
+    */
+    public void renameElement(Element oldElement, String newName)
+    {
+	oldElement.setAttribute("name", newName); //Rename the element
+    }
+	
+
+    /** Set one of the mds level attributes.
+     * @param name The attribute to change.
+     * @param value its new value.
+     */
+    public void setAttribute(String name, String value) {
+	root.setAttribute(name, value);
+    }
+    /** Once the metadata set has been saved to a different location, this is used to update the file parameter.
+     * @param file The new location of this metadata set <strong>File</strong>.
+     */
+    public void setFile(File file) {
+	this.file = file;
+    }
+
+    public void setName(String name) {
+	// Retrieve the name element. We look for the first english one.
+	boolean found_it = false;
+	Element name_element = null;
+	Element metadataset_element = document.getDocumentElement();
+	NodeList name_elements = metadataset_element.getElementsByTagName(StaticStrings.NAME_ELEMENT);
+	for(int i = 0; (i < name_elements.getLength() && !found_it); i++) {
+	    Element possible_name_element = (Element) name_elements.item(i);
+	    if(possible_name_element.getAttribute(StaticStrings.LANGUAGE_ATTRIBUTE).equals("en")) {
+		// Found it.
+		found_it = true;
+		name_element = possible_name_element;
+		//System.out.println("Found english name: " + name_element); //debug
+	    }
+	}
+	// If there is none add one. Note that we can only add english metadata sets. Although others can edit them to add further names as necessary.
+	if(name_element == null) {
+	    name_element = document.createElement(StaticStrings.NAME_ELEMENT);
+	    name_element.setAttribute(StaticStrings.LANGUAGE_ATTRIBUTE, "en");
+	    metadataset_element.insertBefore(name_element, metadataset_element.getFirstChild());
+	}
+	// Replace the text node
+	while(name_element.hasChildNodes()) {
+	    name_element.removeChild(name_element.getFirstChild());
+	}
+	name_element.appendChild(document.createTextNode(name));
+    }
+
+    /** Method to determine the number of elements in this set.
+     * @return An <i>int</i> specifying the element count.
+     */
+    public int size() {
+	return elements.size();
+    }
+    /** Method to translate this class into a meaningful string, which in this case is the metadata sets name.
+     * @return The metadata sets name as a <strong>String</strong>.
+     */
+    public String toString() {
+       
+	String name = getName();
+	// If there is no given name, then use the namespace as there is garaunteed to be one of them.
+	if(name == null || name.length() == 0) {
+	    name = root.getAttribute("namespace");
+	}
+	// Append namespace
+	String namespace = root.getAttribute("namespace");
+	if(namespace == null || namespace.equals("")) {
+	    namespace = MetadataSetManager.EXTRACTED_METADATA_NAMESPACE;
+	}
+	name = name + " (" + namespace + ")";
+	if (collection == null) 
+	    return name;
+	return "["+collection+"] "+name;
+    }
+
+    /** This method retrieves the required attribute from the Metadata Set, typically it's name or it's description. Note that this method is language dependent, and moreover supports both legacy metadata sets and the new sets optimized for multiple languages.
+     * @param element_name the name of the type of element the required information is in as a String
+     * @param default_string the value to return if no such element is found also as a String
+     * @see org.greenstone.gatherer.Configuration#getLanguage()
+     * @see org.greenstone.gatherer.msm.MSMUtils#getValue(Node)
+     * @see org.greenstone.gatherer.util.StaticStrings#CODE_ATTRIBUTE
+     * @see org.greenstone.gatherer.util.StaticStrings#SETLANGUAGE_ELEMENT
+     */
+    private String getAttribute(String element_name, String default_string) {
+	String result = null;
+
+	// Determine the language code.
+	current_language_code = Configuration.getLanguage();
+
+	///ystem.err.println("Searching for the " + element_name + " in " + current_language_code);
+
+	// New Metadata Set Format makes use of deferred-node-expansion to save memory - rather than create nodes for a name and description in each language, nodes which have potentially huge strings, we instead create simplier SETLANGUAGE nodes, and then only expand the one in the desired language. Of course if a user happens to change to every available language slightly more memory will be used than in the old method. For instance consider the DLS with 25 languages, each with a name node of 50 bytes and an descriptions of 500. Thus old style > 13750 bytes while new style < 600.
+	NodeList set_language_elements = document.getElementsByTagName(StaticStrings.SETLANGUAGE_ELEMENT);
+	for(int b = 0; b < set_language_elements.getLength(); b++) {
+	    Element set_language_element = (Element) set_language_elements.item(b);
+	    String code = set_language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE).toLowerCase();
+	    if(code.equals(current_language_code)) {
+		NodeList specific_elements = set_language_element.getElementsByTagName(element_name);
+		if(specific_elements.getLength() > 0) {
+		    Element specific_element = (Element) specific_elements.item(0);
+		    result = MSMUtils.getValue(specific_element);
+		    specific_element = null;
+		}
+		specific_elements = null;
+	    }
+	    code = null;
+	    set_language_element = null;
+	}
+	set_language_elements = null;
+	// And we may be all done
+	if(result != null) {
+	    return result;
+	}
+
+	// Failing that we move on to an older style search - start by recovering all Name elements
+	NodeList possible_elements = document.getElementsByTagName(element_name);
+	// Iterate through the available names looking for the appropriate one. Also make note of the first name, then overwrite it with any english one.
+	boolean found = false;
+	for(int i = 0; !found && i < possible_elements.getLength(); i++) {
+	    Element possible_element = (Element) possible_elements.item(i);
+	    String possible_element_code = possible_element.getAttribute("language").toLowerCase();
+	    if(possible_element_code.equals(current_language_code) || name == null) {
+		result = MSMUtils.getValue(possible_element);
+		found = true;
+	    }
+	    possible_element_code = null;
+	    possible_element = null;
+	}
+	possible_elements = null;
+	// Failing all that set an error message
+	if(result == null) {
+	    result = default_string;
+	}
+	return result;
+    }
+
+    private void init(boolean use_classloader) {
+
+	if(this.document != null) {
+	    this.root = document.getDocumentElement();
+	    this.elements = XMLTools.getChildElementsByTagName(root, "Element");
+	}
+	else {
+	    DebugStream.println("Error! Missing mds file: " + file.getAbsolutePath());
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/MetadataSetManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/MetadataSetManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/MetadataSetManager.java	(revision 10506)
@@ -0,0 +1,435 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+import java.io.*;
+import java.util.*;
+import java.util.StringTokenizer;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+import javax.swing.tree.TreePath;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.collection.CollectionManager;
+import org.greenstone.gatherer.file.*;
+import org.greenstone.gatherer.util.XMLTools;
+import org.apache.xerces.parsers.*;
+import org.apache.xml.serialize.*;
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+/** This class is responsible for managing all the metadata sets in the collection and for providing methods for manipulating the aforementioned sets contents. 
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3b
+ */
+public class MetadataSetManager
+{
+    static public final String EXTRACTED_METADATA_NAMESPACE = "ex";
+
+    static final public String HIDDEN = "hidden"; //The name of the hidden, or system, metadata set.
+    static final public int MAX_LOADED_SETS = 64;
+    static public CollectionManager col_man = null;
+    static private Hashtable mds_hashtable = new Hashtable(); //A mapping from metadata namespace to metadata set.
+    public GEMS gemsptr;
+    
+
+    /** Constructor. */
+    public MetadataSetManager(GEMS gemscopy) {
+        gemsptr = gemscopy;
+        col_man = new CollectionManager();
+    }
+
+
+    public MetadataSet addSet(String namespace, String name) {
+	MetadataSet mds = new MetadataSet(GEMS.METADATA_SET_TEMPLATE);
+	mds.setAttribute("creator", "The Greenstone Librarian Interface");
+	// Calculate lastchanged to right now on this machine by this user
+	String user_name = System.getProperty("user.name");
+	String machine_name = Utility.getMachineName();
+	mds.setAttribute("lastchanged", Utility.getDateString() + " - " + user_name + " on " + machine_name);
+	// And the remaining attributes.
+	mds.setAttribute("namespace", namespace);
+	// Add the name element.
+	mds.setName(name);
+	// this is the location for a global metadata set
+	File mds_file = new File(GEMS.getGLIMetadataDirectoryPath() + namespace + ".mds");
+	mds.setFile(mds_file);
+	mds_hashtable.put(namespace, mds);
+	// fireSetChanged(mds);
+	return mds;
+    }
+
+
+    /**
+       Method to rename a metadata set.
+       @param: current_set: The metadata set to rename
+       @param: new_namspace: The new namespace for the current_set
+       @param: new_name: The new (language-dependent) name for the current_set. Multiple names in different languages is not yet implemented in GEMS, but when it is, this method will need to be updated.
+
+       @pre: There is not another metadata set with namespace new_namespace. Ie namespaces are unique.
+       @post: The Name and namespace in the metadata file will have been updated. The filename will stay the same.
+
+       @author Matthew Whyte
+       Date last modified: 10/01/12
+    */
+    public void renameSet(MetadataSet current_set, String new_namespace, String new_name)
+    {
+	if(current_set != null)
+	    {
+		String old_namespace = current_set.getNamespace();
+		current_set.setNamespace(new_namespace); //Update the namespace
+		current_set.setName(new_name); //Update the name
+		mds_hashtable.remove(old_namespace); //Remove the old set from the hashtable
+		mds_hashtable.put(new_namespace, current_set); //Add the new set to the hashtable
+	    }
+	else
+	    {
+		//This should not happen.
+		System.err.println("Error: no such set \'" + current_set + "\'");
+	    }
+    }
+
+
+    /** Destructor. 
+     */
+    public void destroy() {
+	mds_hashtable.clear();
+    }
+
+
+    /** Used to get all the (non-hidden) elements in this manager.
+     * @return A Vector of ElementWrappers.
+     */
+    public Vector getElements() {
+	return getElements(false);
+    }
+
+    public Vector getElements(boolean all) {
+	return getElements(all, false);
+    }
+
+
+    /** Used to get all the elements in this manager.
+     * @param all <i>true</i> if all elements, including hidden, should be returned.
+     * @return A Vector of ElementWrappers.
+     */
+    public Vector getElements(boolean all, boolean force_extracted) {
+	Vector all_elements = new Vector();
+	for(Enumeration keys = mds_hashtable.keys(); keys.hasMoreElements(); ) {
+	    MetadataSet mds = (MetadataSet)mds_hashtable.get(keys.nextElement());
+	    if((!mds.getNamespace().equals(EXTRACTED_METADATA_NAMESPACE) && !mds.getNamespace().equals(HIDDEN)) 
+	       || (mds.getNamespace().equals(EXTRACTED_METADATA_NAMESPACE) && (Configuration.get("general.view_extracted_metadata", Configuration.COLLECTION_SPECIFIC) || force_extracted)) 
+	       || (mds.getNamespace().equals(EXTRACTED_METADATA_NAMESPACE) && mds.getNamespace().equals(HIDDEN) && all)) {
+		ArrayList set_elements = mds.getElements();
+		///ystem.err.println("The set " + mds + " has " + set_elements.getLength() + " elements.");
+		for(int i = 0; i < set_elements.size(); i++) {
+		    Element raw_element = (Element)set_elements.get(i);
+		    ElementWrapper element = new ElementWrapper(raw_element);
+		    // For now we do not add subfield elements and their parents, just the subfields.
+		    NodeList child_elements = raw_element.getElementsByTagName("Element");
+		    if(child_elements.getLength() == 0) {
+			all_elements.add(element);
+		    }
+		}
+	    }
+	}
+	Collections.sort(all_elements);
+	return all_elements;
+    }
+
+
+    /** Retrieve a metadata element by its index.
+     * @param index The specified index as an int.
+     * @return An ElementWrapper containing the specied element, or <i>null</i> is no such element exists.
+     */
+    public ElementWrapper getElement(int index) {
+	Vector elements = getElements(false);
+	ElementWrapper result = null;
+	if(0 <= index && index < elements.size()) {
+	    result = (ElementWrapper) elements.get(index);
+	}
+	return result;
+    }
+
+    /** Retrieve a metadata element by looking at the current metadata element. Note that this 'index' element may now be disconnected from the DOM model, so we have to reload the target element by the string method.
+     * @param element The possibly out-of-data MetadataElement.
+     * @return An ElementWrapper containing the specied element, or <i>null</i> is no such element exists.
+     */
+    public ElementWrapper getElement(ElementWrapper element) {
+	return getElement(element.toString());
+    }
+
+    /** Retrieve a metadata element by its fully qualified name.
+     * @param name The elements name as a String.
+     * @return An ElementWrapper containing the specied element, or <i>null</i> is no such element exists.
+     */
+
+    public ElementWrapper getElement(String name) {
+	return getElement(name, false);
+    }
+
+    public ElementWrapper getElement(String name, boolean perfect) {
+	///ystem.err.println("Retrieve element " + name);
+	if(name == null) {
+	    ///ystem.err.println("No name!");
+	    return null;
+	}
+	ElementWrapper result = null;
+ 	MetadataSet set = null;
+	String element = null;
+	// First we seperate off what set it is in, where we have '<set><namespace_separator><element>'.
+	if(name.indexOf(MSMUtils.NS_SEP) != -1) {
+	    String namespace = name.substring(0, name.indexOf(MSMUtils.NS_SEP));
+	    // Retrieve the correct set if possible.
+	    set = (MetadataSet)mds_hashtable.get(namespace);
+	    namespace = null;
+	    // Now retrieve the element name.
+	    element = name.substring(name.indexOf(MSMUtils.NS_SEP) + 1);
+	}
+	// If we are looking for a perfect match, we can assume that no namespace means extracted metadata
+	else if(!perfect) {
+	    // No namespace so assume that its extracted metadata.
+	    set = (MetadataSet)mds_hashtable.get(EXTRACTED_METADATA_NAMESPACE);
+	    element = name;
+	}
+	if(set != null) {
+	    // Now we have a set we are ready to locate the requested element. Break the remaining element name down by the subfield separator, attempting to retrieve the element indicated by each step.
+	    if(element.indexOf(MSMUtils.SF_SEP) != -1) {
+		StringTokenizer tokenizer = new StringTokenizer(element, new Character(MSMUtils.SF_SEP).toString());
+		// Has to be at least two tokens
+		if(tokenizer.countTokens() >= 2) {
+		    Element current_element = set.getElement(tokenizer.nextToken());
+		    while(current_element != null && tokenizer.hasMoreTokens()) {
+			current_element = set.getElement(current_element, tokenizer.nextToken());
+		    }
+		    if(current_element != null) {
+			result = new ElementWrapper(current_element);
+			current_element = null;
+		    }
+		}
+		tokenizer = null;
+	    }
+	    // No subelements - much easier.
+	    if(result == null) {
+		///ystem.err.print("Trying to match element " + element +"?");
+		Element temp = set.getElement(element);
+		if(temp != null) {
+		    result = new ElementWrapper(temp);
+		}
+		temp = null;
+	    }
+	    set = null;
+	}
+	element = null;
+	return result;
+    }
+
+    /** Retrieve a certain named element from a certain named set.
+     * @param set The metadata set whose element you want.
+     * @param name The name of the element.
+     * @return An ElementWrapper around the requested element, or null if no such set or element.
+     */
+    public ElementWrapper getElement(String set, String name) {
+	if(mds_hashtable.containsKey(set)) {
+	    MetadataSet temp = (MetadataSet)mds_hashtable.get(set);
+	    return new ElementWrapper(temp.getElement(name));
+	}
+	return null;
+    }
+
+
+    /** Retrieve the named metadata set.
+     * @param name The sets name as a String.
+     * @return The MetadataSet as named, or null if no such set.
+     */
+    public MetadataSet getSet(String namespace) {
+	if(mds_hashtable.containsKey(namespace)) {
+	    return (MetadataSet) mds_hashtable.get(namespace);
+	}
+	return null;
+    }
+
+    /** Method to retrieve all of the metadata sets loaded in this collection. 
+     * @return A Vector of metadata sets.
+     */
+    public Vector getSets() {
+	return getSets(true);
+    }
+
+    public Vector getSets(boolean include_greenstone_extracted) {
+	Vector result = new Vector();
+	for(Enumeration keys = mds_hashtable.keys(); keys.hasMoreElements(); ) {
+	    MetadataSet set = (MetadataSet)mds_hashtable.get(keys.nextElement());
+	    if(!set.getNamespace().equals(HIDDEN) && (include_greenstone_extracted || !set.getNamespace().equals(EXTRACTED_METADATA_NAMESPACE))) {
+		result.add(set);
+	    }
+	}
+	return result;
+    }
+  
+
+    public MetadataSet loadMetadataSet(File metadata_set_file)
+    {
+        File[] all_sets = new File[MAX_LOADED_SETS];
+        MetadataSet tempSet;
+        int i = 0;
+        System.err.println("Loading metadata set file " + metadata_set_file + "...");
+	MetadataSet metadata_set = new MetadataSet(metadata_set_file);
+        
+        //write out existing namespaces to all_sets[]...we use this to determine if a set is
+        //already loaded-Attila 
+        for(Enumeration keys = mds_hashtable.keys(); keys.hasMoreElements(); ) {
+	    //System.err.println("keys: " + keys.nextElement() + "\n"); //debug
+	    tempSet = (MetadataSet)mds_hashtable.get(keys.nextElement());        
+            all_sets[i] = tempSet.getFile();
+            i++;
+	}
+        
+        //Now check our metadata.set's namespace to see if it is already loaded in all_sets
+        for(int p = 0 ; p < i; p++) {
+	    if(metadata_set.getFile().compareTo(all_sets[p]) == 0) {
+		gemsptr.warn_cant_load_set();
+		return null; 
+	    }
+        }
+    
+        //check if this metadata set belongs to a collection
+        //if so, then change the metadata set's name in the interface to (collection) dublin core...
+	String sep = new String(metadata_set.getFile().separator);
+	StringTokenizer st = new StringTokenizer(metadata_set.getFile().toString(), sep);
+	String colName = new String("");
+	
+        while ( st.hasMoreTokens() )
+        {
+           if(st.nextToken().compareTo("collect") == 0) {
+	       colName = st.nextToken();  
+	       break;
+           }   
+        }
+
+	if (colName.equals("")) {
+	    mds_hashtable.put(metadata_set.getNamespace(), metadata_set);
+	} else {
+	    metadata_set.setCollection(colName);
+	    mds_hashtable.put(metadata_set.getNamespace(), metadata_set);
+	}
+	return metadata_set;
+    }
+
+
+    /**
+       Method to remove an element or subelement from a metadata set
+       @param element the element to remove, as an <strong>ElementWrapper</strong>
+       @param parent the parent of the element, as an <strong>ElementWrapper</strong> This is required if removing a subelement (can be null - this means the parent is the metadataset root.)
+       @return void
+       Modified by Matthew Whyte 19/01/04
+
+       This should really be totally replaced by MetadataSet.removeElement --Matthew
+     */
+    public void removeElement(ElementWrapper element, ElementWrapper parent) {
+	// Retrieve the metadata set this element belongs to.
+	String namespace = element.getNamespace();
+	//System.err.println("namespace is: " + namespace); //debug
+	MetadataSet set = (MetadataSet) mds_hashtable.get(namespace);
+	if(set != null) {
+	    //Remove the element
+	    set.removeElement(element.getElement(), parent);
+	}
+	else {
+	    //This should not happen - no such set, no such element.
+	    System.err.println("Cannot remove element \'" + element + "\' because there is no such set \'" + namespace + "\'");
+	}
+    }
+
+
+    /**
+       Rename the metadata element.
+       @param oldElement An <strong>ElementWrapper</strong> we wish to rename
+       @param newName A <strong>String</strong> which contains the new name of the element.
+       @return An <strong>ElementWrapper</strong> around the newly named element
+    */
+    public void renameElement(ElementWrapper oldElement, String newName)
+    {
+	//Retrive the metadata set this element belongs to.
+	String namespace = oldElement.getNamespace();
+	MetadataSet set = (MetadataSet)mds_hashtable.get(namespace);
+	if(set != null)
+	    {
+		//System.err.println("newName is: " + newName); //debug
+		set.renameElement(oldElement.getElement(), newName); //Rename the element
+	    }
+	else
+	    {
+		System.err.println("No such set " + namespace);
+	    }
+    }
+
+
+    public void save() {
+	File file = new File(GEMS.getGLIMetadataDirectoryPath());
+       
+	if (!file.exists()) {
+	    System.out.println("trying to save a collection and the metadata directory does not exist - creating it!");
+	    
+	    file.mkdir();
+	}
+	// And make back ups of all existing metadata set files.
+	File temp[] = file.listFiles();
+	
+	// Now save the latest versions of the metadata sets.
+	for(Enumeration keys = mds_hashtable.keys(); keys.hasMoreElements(); ) {
+	    String namespace = (String) keys.nextElement();
+	    MetadataSet set = (MetadataSet) mds_hashtable.get(namespace);
+	    try {
+		// just use the existing file path
+		File mds_file = set.getFile();
+		XMLTools.writeXMLFile(mds_file, set.getDocument());
+		set.setSetChanged(false);
+	    }
+	    catch (Exception error) {
+		error.printStackTrace();
+	    }
+	}
+    }
+    
+    public void removeSet(MetadataSet set) {
+	mds_hashtable.remove(set.getNamespace());
+        File f =  set.getFile();
+        f.delete();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/SmarterTable.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/SmarterTable.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/SmarterTable.java	(revision 10506)
@@ -0,0 +1,76 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+import java.awt.*;
+import javax.swing.JTable;
+import javax.swing.table.*;
+
+/** An extension of a JTable that allows for the background, foreground, heading and selection colors to be set in single actions. */
+public class SmarterTable
+    extends JTable {
+
+    public void setBackground(Color color) {
+	super.setBackground(color);
+	TableCellRenderer renderer = getDefaultRenderer(String.class);
+	((DefaultTableCellRenderer)renderer).setBackground(color);
+    }
+
+    public void setForeground(Color color) {
+	super.setForeground(color);
+	TableCellRenderer renderer = getDefaultRenderer(String.class);
+	((DefaultTableCellRenderer)renderer).setForeground(color);
+    }
+
+    public void setHeadingBackground(Color color) {
+	JTableHeader header = getTableHeader();
+	header.setBackground(color);
+    }
+
+    public void setHeadingForeground(Color color) {
+	JTableHeader header = getTableHeader();
+	header.setForeground(color);
+    }
+
+    public void setSelectionColor(Color color) {
+	super.setSelectionBackground(color);
+    }
+	 
+    public void setSelectedTextColor(Color color) {
+	super.setSelectionForeground(color);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/SmarterTextArea.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/SmarterTextArea.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/SmarterTextArea.java	(revision 10506)
@@ -0,0 +1,79 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+import javax.swing.JTextArea;
+import javax.swing.text.*;
+
+public class SmarterTextArea
+    extends JTextArea {
+
+    private boolean init = true;
+
+    public SmarterTextArea() {
+	super();
+    }
+
+    public SmarterTextArea(String text, boolean editable) {
+	super();
+	if(!editable) {
+	    setDocument(new UnchangingDocument());
+	}
+	setText(text);
+	init = false;
+    }
+
+    public int calculateColumnCount() {
+	return (getWidth() / getColumnWidth());
+    }
+
+    private class UnchangingDocument 
+	extends PlainDocument {
+	public void insertString(int offs, String str, AttributeSet a) 
+	    throws BadLocationException {
+	    if(init) {
+		super.insertString(offs, str, a);
+	    }
+	}
+	public void remove(int offs, int len)  
+	    throws BadLocationException {
+	    if (init) {
+		super.remove(offs, len);
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/SmarterTree.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/SmarterTree.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/SmarterTree.java	(revision 10506)
@@ -0,0 +1,85 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gems;
+
+import java.awt.Color;
+import javax.swing.JTree;
+import javax.swing.tree.*;
+import java.awt.event.*;
+
+/** An extension of a JTree that allows for the background, foreground and selection colors to be set in single actions. */
+public class SmarterTree extends JTree implements ActionListener{
+
+    public SmarterTree() {
+	super();
+    }
+
+    public SmarterTree(TreeModel model) {
+	super(model);
+    }
+
+    public boolean isSelectionEmpty() {
+	return super.isSelectionEmpty();
+    }
+
+    public void setBackground(Color color) {
+	super.setBackground(color);
+	if(cellRenderer != null) {
+	    ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(color);
+	}
+    }
+
+    public void setForeground(Color color) {
+	super.setForeground(color);
+	if(cellRenderer != null) {
+	    ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(color);
+	}
+    }
+
+    public void setSelectionColor(Color color) {
+	((DefaultTreeCellRenderer)cellRenderer).setBackgroundSelectionColor(color);
+    }
+	 
+    public void setSelectedTextColor(Color color) {
+	((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(color);
+    }
+    
+    public void actionPerformed(ActionEvent e) {
+        System.out.println("Action!");
+    }
+    
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/TransformCharacterTextField.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/TransformCharacterTextField.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gems/TransformCharacterTextField.java	(revision 10506)
@@ -0,0 +1,105 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.gems;
+
+import java.util.*;
+import javax.swing.*;
+import javax.swing.text.*;
+
+
+/** A JTextField that doesn't allow certain characters, either blocking or replacing them
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.4
+ */
+public class TransformCharacterTextField 
+    extends JTextField {
+    
+    private boolean block_all_except_mappings = false;
+    static private HashMap mappings = new HashMap();
+
+    static public TransformCharacterTextField createNamespaceTextField() {
+	TransformCharacterTextField text = new TransformCharacterTextField();
+	text.setBlockAllExceptMappings(true);
+	int i = 'a';
+	int j = 'A';
+	for( ; i <= 'z'; i++, j++) {
+	    text.replaceCharacter((char)i, (char)i);
+	    text.replaceCharacter((char)j, (char)i);
+	}
+	return text;
+    }
+
+    public TransformCharacterTextField() {
+	super();
+    }
+
+    public TransformCharacterTextField(String text) {
+	super(text);
+    }
+
+    public void replaceCharacter(char x, char y) {
+	mappings.put(new Character(x), new Character(y));
+    }
+
+    public void setBlockAllExceptMappings(boolean block_all_except_mappings) {
+	this.block_all_except_mappings = block_all_except_mappings;
+	setText(""); // Have to reset
+    }
+
+    protected Document createDefaultModel() {
+  	return new TransformCharacterTextDocument();
+    }
+
+    private class TransformCharacterTextDocument 
+	extends PlainDocument {
+		  
+	public void insertString(int offs, String str, AttributeSet a) 
+	    throws BadLocationException {
+				
+	    if (str == null) {
+		return;
+	    }
+	    char[] raw = str.toCharArray();
+	    StringBuffer result = new StringBuffer("");
+	    for (int i = 0; i < raw.length; i++) {
+		Character key = new Character(raw[i]);
+		if(mappings.containsKey(key)) {
+		    Character replacement = (Character) mappings.get(key);
+		    if(replacement != null) {
+			result.append(replacement.charValue());
+			replacement = null;
+		    }
+		}
+		else if(!block_all_except_mappings) {
+		    result.append(raw[i]);
+		}
+		key = null;
+	    }
+	    super.insertString(offs, result.toString(), a);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/AboutDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/AboutDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/AboutDialog.java	(revision 10506)
@@ -0,0 +1,167 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Greenstone Librarian Interface (GLI) application, 
+ * part of the Greenstone digital library software suite from the New 
+ * Zealand Digital Library Project at the University of Waikato, 
+ * New Zealand.
+ *
+ * Author: John Thompson
+ *         Greenstone Project, New Zealand Digital Library
+ *         University of Waikato
+ *         http://www.nzdl.org
+ *
+ * Copyright (C) 2004 New Zealand Digital Library, University of Waikato
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.Utility;
+
+/** Generates a pretty about dialog which not only thanks those for their contributions but also meets our legal requirements if we wish to ship the JVM with GLI.
+ * @author John Thompson, Greenstone Project, New Zealand Digital Library, University of Waikato
+ * @version 2.41 final
+ */
+// RICOH SOURCE CODE PUBLIC LICENSE - http://www.risource.org/RPL/RPL-1.0A.shtml
+public class AboutDialog
+    extends JDialog {
+    /** The default size of the about dialog. */
+    static final private Dimension SIZE = new Dimension(600, 325);
+    /** The size of the GLI icon to display on dialog. */
+    static final private int ICON_SIZE = 65;
+    /** A reference to ourself so that our inner classes can dismiss us. */
+    private AboutDialog self;
+    /** The button used for dismissing the about dialog. */
+    private JButton close_button;
+    /** The constructor not only builds, but displays the about dialog. This method doesn't return until the dialog is dismissed.
+     * @param parent the JFrame which owns this dialog for use in centering the dialog
+     * @see org.greenstone.gatherer.Dictionary#get
+     * @see org.greenstone.gatherer.Dictionary#setBoth
+     * @see org.greenstone.gatherer.Dictionary#setText
+     * @see org.greenstone.gatherer.gui.AboutDialog.CloseButtonListener
+     * @see org.greenstone.gatherer.gui.GLIButton
+     * @see org.greenstone.gatherer.util.Utility#PROGRAM_NAME
+     * @see org.greenstone.gatherer.util.Utility#PROGRAM_VERSION
+     */
+    public AboutDialog(JFrame parent) {
+	super(parent, Dictionary.get("AboutDialog.Title"), true);
+	this.self = this;
+	setSize(SIZE);
+		  
+	JPanel content_pane = (JPanel) getContentPane();
+	JPanel upper_pane = new JPanel();
+	ImageIcon icon = JarTools.getImage("gatherer_medium.gif");
+	ImageIcon scaled_icon = new ImageIcon(icon.getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_DEFAULT));
+	JLabel icon_label = new JLabel(scaled_icon);
+	JPanel title_pane = new JPanel();
+	JLabel title_one_label = new JLabel();
+	Dictionary.setText(title_one_label, "AboutDialog.Title_One");
+	JLabel title_two_label = new JLabel(Utility.PROGRAM_NAME + " " + Utility.PROGRAM_VERSION + " " + Dictionary.get("AboutDialog.Date"));
+	JLabel title_three_label = new JLabel();
+	Dictionary.setText(title_three_label, "AboutDialog.Title_Two");
+	JLabel copyright_label = new JLabel();
+	Dictionary.setText(copyright_label, "AboutDialog.Copyright");
+	JLabel gpl_label = new JLabel();
+	Dictionary.setText(gpl_label, "AboutDialog.Copyright_Two");
+
+	JTextArea text = new JTextArea();
+	text.setLineWrap(true);
+	text.setWrapStyleWord(true);
+
+	JPanel button_pane = new JPanel();
+	close_button = new GLIButton();
+	close_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(close_button, "General.Close", "General.Close_Tooltip");
+
+	// Connection
+	close_button.addActionListener(new CloseButtonListener());
+
+	// Layout
+	icon_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,10));
+
+	title_pane.setLayout(new GridLayout(5,1,0,2));
+	title_pane.add(title_one_label);
+	title_pane.add(title_two_label);
+	title_pane.add(title_three_label);
+	title_pane.add(copyright_label);
+	title_pane.add(gpl_label);
+		  
+	upper_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	upper_pane.setLayout(new BorderLayout());
+	upper_pane.add(icon_label, BorderLayout.WEST);
+	upper_pane.add(title_pane, BorderLayout.CENTER);
+
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	button_pane.setLayout(new BorderLayout());
+	button_pane.add(close_button, BorderLayout.EAST);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(upper_pane, BorderLayout.NORTH);
+	content_pane.add(new JScrollPane(text), BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	// Build text content
+	text.append(Dictionary.get("AboutDialog.Java_Req"));
+	text.append("\n");
+	text.append(Dictionary.get("AboutDialog.Java_Req_One"));
+	text.append("\n");
+	text.append(Dictionary.get("AboutDialog.Java_Req_Two"));
+	text.append("\n\n");
+	text.append("*****" + Dictionary.get("AboutDialog.Acknowledgement") + "*****");
+	text.append("\n\n");
+	text.append(Dictionary.get("AboutDialog.Item0"));
+	text.append("\n\n");
+	text.append(Dictionary.get("AboutDialog.Item2"));
+	text.append("\n\n");
+	text.append(Dictionary.get("AboutDialog.Item3"));
+	text.append("\n\n");
+	text.append("*****" + Dictionary.get("AboutDialog.Thanks") + "*****");
+	text.append("\n\n");
+	text.append(Dictionary.get("AboutDialog.Item4"));
+	text.append("\n\n");
+	text.append(Dictionary.get("AboutDialog.Item5"));
+	text.append("\n\n");
+	text.append(Dictionary.get("AboutDialog.Item6"));
+	text.append("\n\n");
+	text.append(Dictionary.get("AboutDialog.Item7"));
+	text.append("\n\n");
+	text.append(Dictionary.get("AboutDialog.Item8"));
+	text.setCaretPosition(0);
+
+	// Show
+	Rectangle frame_bounds = parent.getBounds();
+	setLocation(frame_bounds.x + (frame_bounds.width - SIZE.width) / 2, frame_bounds.y + (frame_bounds.height - SIZE.height) / 2);
+	setVisible(true);
+    }
+    /** Listens for actions upon the close button, and when detected closes the dialog. */
+    private class CloseButtonListener
+	implements ActionListener {
+	/** Called whenever an action occurs on the close button, thus asking the dialog to close.
+	 * @param event an ActionEvent containing information about the button press
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    self.setVisible(false);
+	    self.dispose();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ArgumentControl.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ArgumentControl.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ArgumentControl.java	(revision 10506)
@@ -0,0 +1,322 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.cdm.Argument;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+
+public class ArgumentControl
+    extends JPanel {
+    static protected Dimension LABEL_SIZE = new Dimension(180, 25);
+    static protected Dimension ROW_SIZE = new Dimension(610, 30);
+    static protected Dimension SPINNER_SIZE = new Dimension(100, 25);
+    static protected String DESCRIPTION_SEP = " + ";
+
+    protected Argument argument;
+    protected JComponent value_control;
+    protected JCheckBox enabled;
+
+    public ArgumentControl(Argument argument, boolean enable, String value) {
+	super();
+	this.argument = argument;
+	String tooltip = Utility.formatHTMLWidth("<html>" + argument.getDescription() + "</html>", 60);
+	setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
+	setLayout(new BorderLayout());
+	setPreferredSize(ROW_SIZE);
+	setMaximumSize(ROW_SIZE);
+	
+	// Try to determine what the value_controls value should be.
+	if(value == null) {
+	    value = argument.getDefaultValue();
+	}
+	// Create a correct value control based on the argument provided.
+	switch(argument.getType()) {
+	case Argument.ENUM:
+	case Argument.METADATUM:
+	    JComboBox combobox = new JComboBox();
+	    combobox.setEnabled(enable);
+	    combobox.setToolTipText(tooltip);
+	    combobox.setBackground(enable ? Color.white : Color.lightGray);
+	    
+	    // Build an option model, wrapping each entry of the list table
+	    if (argument.getType() == Argument.ENUM) {
+		HashMap arg_list = argument.getOptions();
+		Iterator it = arg_list.keySet().iterator();
+		ArrayList options = new ArrayList();
+		while (it.hasNext()) {
+		    options.add((String) it.next());
+		}
+		Collections.sort(options);
+		for (int i=0; i<options.size(); i++) {
+		    combobox.addItem(options.get(i));
+		}
+		// Connect this so if a value is selected the tooltip updates accordingly
+		combobox.addActionListener(new ToolTipUpdater(arg_list));
+	    }
+	    if (argument.getType() == Argument.METADATUM) {
+		ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+		for (int i = 0; i < every_metadata_set_element.size(); i++) {
+		    combobox.addItem(every_metadata_set_element.get(i));
+		}
+	    }
+
+	    if (value != null) {
+		// Set the selected string
+		for (int i = 0; i < combobox.getItemCount(); i++) {
+		    if (combobox.getItemAt(i).toString().equals(value)) {
+			combobox.setSelectedIndex(i);
+		    }
+		}
+	    }
+	    // Layout
+	    add(combobox, BorderLayout.CENTER);
+	    // And remember
+	    value_control = combobox;
+	    break;
+	case Argument.FLAG:
+	    // Only need the check box.
+	    value_control = null;
+	    break;
+	case Argument.INTEGER:
+	    // Build a spinner
+	    int initial_value=0;
+	    if (value != null) {
+		try {
+		    initial_value = Integer.parseInt(value);
+		} catch (Exception exception) {
+		}
+	    }
+	    if (initial_value < argument.getMinimum()) {
+		initial_value = argument.getMinimum();
+	    } else if (initial_value > argument.getMaximum()) {
+		initial_value = argument.getMaximum();
+	    }
+	    JSpinner spinner = new JSpinner(new SpinnerNumberModel(initial_value, argument.getMinimum(), argument.getMaximum(), 1));		
+	    spinner.setEnabled(enable);
+	    spinner.setPreferredSize(SPINNER_SIZE);
+	    spinner.setToolTipText(tooltip);
+	    // Set enabled
+	    JComponent c = spinner.getEditor();
+	    if ( c instanceof JSpinner.DefaultEditor ) {
+		JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
+		JFormattedTextField field = editor.getTextField();
+		field.setEditable(enable);
+		if(enable) {
+		    field.setBackground(Color.white);
+		}
+		else {
+		    field.setBackground(Color.lightGray);
+		}
+	    }
+	    // Layout
+	    add(new JLabel(), BorderLayout.CENTER);
+	    add(spinner, BorderLayout.EAST);
+	    // And remember it
+	    value_control = spinner;
+	    break;
+	case Argument.REGEXP:
+	case Argument.STRING:
+	    // Use a standard text field
+	    JTextField textfield = new JTextField();
+	    textfield.setEnabled(enable);
+	    textfield.setToolTipText(tooltip);
+	    // Set enabled
+	    if(enable) {
+		textfield.setBackground(Color.white);
+	    }
+	    else {
+		textfield.setBackground(Color.lightGray);
+	    }
+	    // If there was an original value, set it.
+	    if(value != null) {
+		textfield.setText(value);
+	    }
+	    // Layout
+	    add(textfield, BorderLayout.CENTER);
+	    // And remember it
+	    value_control = textfield;
+	    break;
+	}
+
+	// If the argument is required, then you don't get a choice of whether it is enabled.
+	if(argument.isRequired()) {
+	    JLabel label = new JLabel(argument.getName());
+	    label.setOpaque(false);
+	    label.setPreferredSize(LABEL_SIZE);
+	    label.setToolTipText(tooltip);
+	    add(label, BorderLayout.WEST);
+	}
+	else {
+	    enabled = new JCheckBox(argument.getName(), enable);
+	    enabled.setOpaque(false);
+	    enabled.setPreferredSize(LABEL_SIZE);
+	    enabled.setToolTipText(tooltip);
+	    // Connect
+	    enabled.addActionListener(new EnabledListener(value_control));
+	    // Layout
+	    add(enabled, BorderLayout.WEST);
+	}
+    }
+
+    public String getName() {
+	return argument.getName();
+    }
+
+    public String getValue() {
+	String value = null;
+	if(value_control == null) {
+	    // Flag value, nothing to do.
+	}
+	else if(value_control instanceof JTextField) {
+	    value = ((JTextField)value_control).getText();
+	}
+	else if(value_control instanceof JSpinner) {
+	    value = ((JSpinner)value_control).getValue().toString();
+	}
+	else if(value_control instanceof JComboBox) {
+	    Object selected_item = ((JComboBox)value_control).getSelectedItem();
+	    if (selected_item != null) {
+		value = selected_item.toString();
+	    }
+	}
+	return value;
+    }
+    /** Retrieve the control used for storing values.
+     * @return JComponent
+     */
+    public JComponent getValueControl() {
+	return value_control;
+    }
+
+    public boolean isEnabled() {
+	if (enabled == null) {
+	    return true; // always enabled
+	} 
+	return enabled.isSelected();
+    }
+
+    /** Method to ensure that a certain value is selected, if it exists within that combobox to begin with.
+     * @param combobox the JComboBox whose selection we are trying to preset
+     * @param target The desired value of the selection as a String
+     * @return true if the item was found and selected, false otherwise
+     */
+    public boolean selectValue(JComboBox combobox, String target) {
+	for(int i = 0; i < combobox.getItemCount(); i++) {
+	    if(combobox.getItemAt(i).toString().equals(target)) {
+		combobox.setSelectedIndex(i);
+		return true;
+	    }
+	}
+	return false;
+    }
+
+    /** Listens for actions apon the enable checkbox, and if detected enables or diables control appropriately. */
+    private class EnabledListener
+	implements ActionListener {
+	/** An editor component, such as a JComboBox or JTextField, that might have its enabled state changed by this listener. */
+	private JComponent target = null;
+	/** Constructor. */
+	public EnabledListener(JComponent target) {
+	    this.target = target;
+	}
+	/** Any implementation of ActionListener must include this method so that we can be informed when an action has been performed on or registered check box, prompting us to change the state of the other controls as per the users request.
+	 * @param event An <strong>ActionEvent</strong> containing information about the click.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    JCheckBox source = (JCheckBox)event.getSource();
+	    if(target != null) {
+		if(source.isSelected()) {
+		    target.setBackground(Color.white);
+		    target.setEnabled(true);
+		}
+		else {
+		    target.setBackground(Color.lightGray);
+		    target.setEnabled(false);
+		}
+		// Special case of stupid JSpinners who don't let their backgrounds change properly.
+		if(target instanceof JSpinner) {
+		    JSpinner spinner = (JSpinner) target;
+		    JComponent c = spinner.getEditor();
+		    if ( c instanceof JSpinner.DefaultEditor ) {
+			JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) c;
+			JFormattedTextField field = editor.getTextField();
+			field.setEditable(source.isSelected());
+			if(source.isSelected()) {
+			    field.setBackground(Color.white);
+			}
+			else {
+			    field.setBackground(Color.lightGray);
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+   /** Listener that sets the tooltip associated to a combobox to the tooltip relevant to the selected item. */
+    private class ToolTipUpdater
+	implements ActionListener {
+	private HashMap arg_list;
+	public ToolTipUpdater(HashMap arg_list) {
+	    this.arg_list = arg_list;
+	}
+	/** Any implementation of an ActionListener must include this method so that we can be informed when the selection in a combobox has changed and update the tooltip accordingly.
+	 * @param event An <strong>ActionEvent</strong> containing information about the action that fired this call.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    JComboBox source = (JComboBox)event.getSource();
+	    String key = (String) source.getSelectedItem();
+	    if(arg_list != null) {
+		String description = (String) arg_list.get(key);
+		if(description != null) {
+		    description = Utility.formatHTMLWidth(description, 60);
+		    source.setToolTipText(description);
+		}
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/CreatePane.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/CreatePane.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/CreatePane.java	(revision 10506)
@@ -0,0 +1,980 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.cdm.SearchTypeManager;
+import org.greenstone.gatherer.cdm.CollectionDesignManager;
+import org.greenstone.gatherer.collection.Collection;
+import org.greenstone.gatherer.shell.GBasicProgressMonitor;
+import org.greenstone.gatherer.shell.GBuildProgressMonitor;
+import org.greenstone.gatherer.shell.GImportProgressMonitor;
+import org.greenstone.gatherer.shell.GShell;
+import org.greenstone.gatherer.shell.GShellEvent;
+import org.greenstone.gatherer.shell.GShellListener;
+import org.greenstone.gatherer.shell.GShellProgressMonitor;
+import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.ZipTools;
+
+/** This class provides a GUI view showing some statistics on your current collection, and options for building it. As the collection is built this initial view is replaced with one showing progress bars and a message log of the creation process. This log can be later accessed via the options tree located in the center of the initial pane. This class is also responsible for creating the GShellProgressMonitors that are then attatched to external shell processes, and calling the methods in the CollectionManager for actually importing and building the collection. <br><BR>
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class CreatePane
+    extends JPanel
+    implements GShellListener {
+
+    static private Dimension ARGUMENT_SIZE = new Dimension(800,90);
+    /** The threshold for when the simple view is replaced by the complex one. */
+    static private final int THRESHOLD = Configuration.EXPERT_MODE;
+    /** An identifier for the control panel within the card layout. */
+    static private String CONTROL  = "Control";
+    /** An identifier for the progress panel within the card layout. */
+    static private String PROGRESS = "Progress";
+    /** An identifier for the simple panel within the card layout. */
+    static private String SIMPLE   = "Simple";
+
+    /** Determines the current view that should be shown for this pane. */
+    public boolean processing = false;
+    /** The options pane generates all the various option sheet configuations. */
+    public OptionsPane options_pane = null;
+    private AppendLineOnlyFileDocument document;
+    /** A card layout is used to store the separate configuration and progress panes. */
+    private CardLayout card_layout = null;
+    /** Stores a reference to the current collection. */
+    private Collection previous_collection = null;
+    /** This monitor tracks the build processes progress. */
+    private GShellProgressMonitor build_monitor = null;
+    /** This monitor tracks the import processes progress. */
+    private GShellProgressMonitor import_monitor = null;
+    /** The button for begining the building processes. */
+    private JButton build_button = null;
+    /** The button for stopping the building processes. */
+    private JButton cancel_button = null;
+    /** The button for viewing the collection. */
+    private JButton preview_button = null;
+    private JButton simple_build_button;
+    private JButton simple_cancel_button;
+    private JButton simple_preview_button;
+    /** The radio buttons for chnaging the build type (incremental/full) */
+    private JRadioButton full_build_radio_button;
+    private JRadioButton incremental_build_radio_button;
+    private JRadioButton sfull_build_radio_button;
+    private JRadioButton sincremental_build_radio_button;
+    /** The label displaying the number of documents in this collection. */
+    private JLabel document_count = null;
+    /** The label alongside the build progress bar gets some special treatment so... */
+    private JLabel progress_build_label = null;
+    /** The label alongside the import progress bar gets some special treatment so... */
+    private JLabel progress_import_label = null;
+    private JPanel bar_area;
+    /** The panel on which buttons are rendered on higher detail modes. */
+    private JPanel button_pane;
+    /** The pane which contains the controls for configuration. */
+    private JPanel control_pane = null;
+    /** The pane which has the card layout as its manager. */
+    private JPanel main_pane = null;
+    /** The pane which contains the progress information. */
+    private JPanel progress_pane = null;
+    /** The pane on the right-hand side - shows the requested options view */
+    private JPanel right = null;
+    /** The simple panel on which all of the available arguments are rendered. */
+    private JPanel sargument_configuration_panel;
+    /** The panel on which buttons are rendered on lower details modes. */
+    private JPanel sbutton_panel;
+    /** A simplified version for lower detail modes containing both the control and progress panes smooshed together. */
+    private JPanel simple_panel;
+    /** The inner panel of the simple pane which is global so that the bar_area can be added and removed from it. */
+    private JPanel sinner_panel;
+    /** The outer panel of the simple pane which is global so that the arguments pane can be added and removed from it. */
+    private JPanel souter_panel;
+    /** The scrolling pane for the log. */
+    private JScrollPane log_scroll;
+    /** The scrolling pane the simple arguments are rendered within. */
+    private JScrollPane sargument_configuration_scroll;
+    /** the scrolling pane the righthand side is inside - only used for import and build options. the log and log list are not inside a scrollpane */
+    private JScrollPane scroll_pane;
+    /** The message log for the entire session. */
+    private JTextArea log_textarea;
+    /** A tree used to display the currently available option views. */
+    private OptionTree tree = null;
+    /** An array used to pass arguments with dictionary calls. */
+    private String args[] = null;
+    /** The homepage address of the current collection */
+    private String homepage = null;
+
+
+    /** The constructor creates important helper classes, and initializes all the components.
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     * @see org.greenstone.gatherer.gui.BuildOptions
+     * @see org.greenstone.gatherer.gui.CreatePane.BuildButtonListener
+     * @see org.greenstone.gatherer.gui.CreatePane.CancelButtonListener
+     * @see org.greenstone.gatherer.gui.CreatePane.OptionTree
+     * @see org.greenstone.gatherer.gui.OptionsPane
+     * @see org.greenstone.gatherer.shell.GBasicProgressMonitor
+     * @see org.greenstone.gatherer.shell.GBuildProgressMonitor
+     * @see org.greenstone.gatherer.shell.GImportProgressMonitor
+     * @see org.greenstone.gatherer.shell.GShellProgressMonitor
+     */
+    public CreatePane() {
+	Collection collection = Gatherer.c_man.getCollection();
+	log_textarea = new JTextArea();
+	log_scroll = new JScrollPane(log_textarea);
+
+	// Create components
+	card_layout = new CardLayout();
+	// Control Pane
+	control_pane = new JPanel();
+	tree = new OptionTree();
+	button_pane = new JPanel();
+
+	// Progress Pane
+	progress_pane = new JPanel(); // One owner of the bar component
+	bar_area = new JPanel(); // This component will be shared about
+
+	progress_import_label = new JLabel();
+	Dictionary.registerText(progress_import_label, "CreatePane.Import_Progress");
+
+	import_monitor = new GImportProgressMonitor(); //GBasicProgressMonitor();
+	Gatherer.c_man.registerImportMonitor(import_monitor);
+
+	progress_build_label = new JLabel();
+	Dictionary.registerText(progress_build_label, "CreatePane.Build_Progress");
+
+	build_monitor = new GBuildProgressMonitor(import_monitor.getSharedProgress()); //GBasicProgressMonitor();
+	Gatherer.c_man.registerBuildMonitor(build_monitor);
+
+	// And the simple panel
+	simple_panel = new JPanel();
+	sbutton_panel = new JPanel();
+	sinner_panel = new JPanel();
+
+	//Radio buttons
+	incremental_build_radio_button = new JRadioButton();
+	Dictionary.registerBoth(incremental_build_radio_button, "CreatePane.Incremental_Build", "CreatePane.Incremental_Build_Tooltip");
+	full_build_radio_button = new JRadioButton();
+	Dictionary.registerBoth(full_build_radio_button, "CreatePane.Full_Build", "CreatePane.Full_Build_Tooltip");
+	sincremental_build_radio_button = new JRadioButton();
+	Dictionary.registerBoth(sincremental_build_radio_button, "CreatePane.Incremental_Build", "CreatePane.Incremental_Build_Tooltip");
+	sfull_build_radio_button = new JRadioButton();
+	Dictionary.registerBoth(sfull_build_radio_button, "CreatePane.Full_Build", "CreatePane.Full_Build_Tooltip");
+
+	// Buttons
+	BuildButtonListener bbl = new BuildButtonListener();
+	CancelButtonListener cbl = new CancelButtonListener();
+	PreviewButtonListener pbl = new PreviewButtonListener();
+
+	build_button = new GLIButton();
+	build_button.addActionListener(bbl);
+	build_button.setMnemonic(KeyEvent.VK_B);
+	Dictionary.registerBoth(build_button, "CreatePane.Build_Collection", "CreatePane.Build_Collection_Tooltip");
+
+	cancel_button = new GLIButton();
+	cancel_button.addActionListener(cbl);
+	cancel_button.setEnabled(false);
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.registerBoth(cancel_button, "CreatePane.Cancel_Build", "CreatePane.Cancel_Build_Tooltip");
+
+	preview_button = new GLIButton();
+	preview_button.addActionListener(pbl);
+	if(Gatherer.c_man != null) {
+	    preview_button.setEnabled(Gatherer.c_man.built());
+	}
+	else {
+	    preview_button.setEnabled(false);
+	}
+	preview_button.setMnemonic(KeyEvent.VK_P);
+	Dictionary.registerBoth(preview_button, "CreatePane.Preview_Collection", "CreatePane.Preview_Collection_Tooltip");
+
+	simple_build_button = new GLIButton();
+	simple_build_button.addActionListener(bbl);
+	simple_build_button.setMnemonic(KeyEvent.VK_B);
+	Dictionary.registerBoth(simple_build_button, "CreatePane.Build_Collection", "CreatePane.Build_Collection_Tooltip");
+
+	simple_cancel_button = new GLIButton();
+	simple_cancel_button.addActionListener(cbl);
+	simple_cancel_button.setEnabled(false);
+	simple_cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.registerBoth(simple_cancel_button, "CreatePane.Cancel_Build", "CreatePane.Cancel_Build_Tooltip");
+
+	simple_preview_button = new GLIButton();
+	simple_preview_button.addActionListener(pbl);
+	if(Gatherer.c_man != null) {
+	    simple_preview_button.setEnabled(Gatherer.c_man.built());
+	}
+	else {
+	    simple_preview_button.setEnabled(false);
+	}
+	simple_preview_button.setMnemonic(KeyEvent.VK_P);
+	Dictionary.registerBoth(simple_preview_button, "CreatePane.Preview_Collection", "CreatePane.Preview_Collection_Tooltip");
+
+	bbl = null;
+	cbl = null;
+	pbl = null;
+    }
+
+
+    public void destroy() {
+	if(document != null) {
+	    document.destroy();
+	}
+    }
+    
+    /** This method is called to actually layout the components.
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.Gatherer
+     */
+    public void display() {
+
+	int current_mode = Configuration.getMode();
+
+	//Complete/incremental build options panel
+	//For some reason I need to create seperate objects for each mode. Is there a better way??
+	ButtonGroup build_type_group = new ButtonGroup();
+	build_type_group.add(incremental_build_radio_button);
+	full_build_radio_button.setSelected(true);
+	build_type_group.add(full_build_radio_button);
+	ButtonGroup sbuild_type_group = new ButtonGroup();
+	sbuild_type_group.add(sincremental_build_radio_button);
+	sfull_build_radio_button.setSelected(true);
+	sbuild_type_group.add(sfull_build_radio_button);
+	JPanel build_type_pane = new JPanel(new GridLayout(2,1));
+	build_type_pane.add(full_build_radio_button);
+	build_type_pane.add(incremental_build_radio_button);
+	JPanel sbuild_type_pane = new JPanel(new GridLayout(2,1));
+	sbuild_type_pane.add(sfull_build_radio_button);
+	sbuild_type_pane.add(sincremental_build_radio_button);
+	
+	
+
+	// Build control_pane
+	JPanel left = new JPanel();
+	left.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
+	left.setLayout(new BorderLayout());
+	left.add(tree, BorderLayout.CENTER);
+	left.add(build_type_pane, BorderLayout.SOUTH);
+	//left.add(full_build_radio_button, BorderLayout.SOUTH);
+
+	right = new JPanel();
+	right.setBorder(BorderFactory.createEmptyBorder(0,0,5,5));
+	right.setLayout(new BorderLayout());
+
+	JPanel options_area = new JPanel();
+	options_area.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createTitledBorder(Dictionary.get("CreatePane.Options_Title"))));
+	options_area.setLayout(new BorderLayout());
+	options_area.add(left, BorderLayout.WEST);
+	options_area.add(right, BorderLayout.CENTER);
+
+	button_pane = new JPanel();
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,10,10,10));
+	button_pane.setLayout(new GridLayout(1,4));
+	button_pane.add(build_button);
+	button_pane.add(cancel_button);
+	button_pane.add(preview_button);
+
+	control_pane.setLayout(new BorderLayout());
+	control_pane.add(options_area, BorderLayout.CENTER);
+	control_pane.add(button_pane, BorderLayout.SOUTH);
+
+	// Build progress_pane
+	JPanel labels_pane = new JPanel();
+	labels_pane.setLayout(new GridLayout(2,1,0,5));
+	labels_pane.add(progress_import_label);
+	labels_pane.add(progress_build_label);
+
+	JPanel monitors_pane = new JPanel();
+	monitors_pane.setLayout(new GridLayout(2,1,0,5));
+	monitors_pane.add(import_monitor.getProgress());
+	monitors_pane.add(build_monitor.getProgress());
+
+	bar_area.setBorder(BorderFactory.createEmptyBorder(10,10,5,10));
+	bar_area.setLayout(new BorderLayout(5,5));
+	bar_area.add(labels_pane, BorderLayout.WEST);
+	bar_area.add(monitors_pane, BorderLayout.CENTER);
+
+	progress_pane.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
+	progress_pane.setLayout(new BorderLayout());
+	progress_pane.add(bar_area, BorderLayout.NORTH);
+	if(current_mode >= THRESHOLD) {
+	    progress_pane.add(log_scroll, BorderLayout.CENTER);
+	}
+
+	// Simple panel
+	sbutton_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	sbutton_panel.setLayout(new GridLayout(1,3));
+	sbutton_panel.add(simple_build_button);
+	sbutton_panel.add(simple_cancel_button);
+	sbutton_panel.add(simple_preview_button);
+
+	JPanel simple_bar_area = new JPanel(new GridLayout(2,1));
+	simple_bar_area.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
+	simple_bar_area.add(import_monitor.getSharedProgress());
+	simple_bar_area.add(sbutton_panel);
+
+	sinner_panel.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
+	sinner_panel.setLayout(new BorderLayout());
+	sinner_panel.add(sbuild_type_pane, BorderLayout.WEST);
+	//sinner_panel.add(full_build_radio_button, BorderLayout.WEST);
+	sinner_panel.add(simple_bar_area, BorderLayout.CENTER);
+	
+	if(options_pane != null) {
+	    sargument_configuration_panel = options_pane.buildImport(null);
+	    sargument_configuration_panel = options_pane.buildBuild(sargument_configuration_panel);
+	}
+	else {
+	    sargument_configuration_panel = new JPanel();
+	}
+	sargument_configuration_scroll = new JScrollPane(sargument_configuration_panel);
+	sargument_configuration_scroll.setPreferredSize(ARGUMENT_SIZE);
+	souter_panel = new JPanel();
+	souter_panel.setSize(new Dimension(400,800));
+	souter_panel.setLayout(new GridLayout(2,1));
+	souter_panel.add(sargument_configuration_scroll);
+	souter_panel.add(sinner_panel);
+
+	simple_panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	simple_panel.setLayout(new BorderLayout());
+	simple_panel.add(souter_panel, BorderLayout.NORTH);
+	if(current_mode < THRESHOLD) {
+	    simple_panel.add(log_scroll, BorderLayout.CENTER);
+	}
+
+	// Main pane
+	main_pane = new JPanel(card_layout);
+	if(current_mode < THRESHOLD) { // Simple mode - add first
+	    main_pane.add(simple_panel, SIMPLE);
+	}
+	main_pane.add(control_pane, CONTROL);
+	main_pane.add(progress_pane, PROGRESS);
+	if(current_mode >= THRESHOLD) { // Expert mode - add last
+	    main_pane.add(simple_panel, SIMPLE);
+	}
+
+	this.setLayout(new BorderLayout());
+	this.add(main_pane, BorderLayout.CENTER);
+    }
+
+    /** This method is called whenever the 'Create' tab is selected from the view bar. It allows this view to perform any preactions required prior to display. In this case this entails gathering up to date information about the status of the collection including number of documents etc.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     * @see org.greenstone.gatherer.gui.CreatePane.OptionTree
+     */
+    public void gainFocus() {
+	if(Configuration.getMode() < THRESHOLD) {
+	    card_layout.show(main_pane, SIMPLE);
+	}
+	else if(!processing) {
+	    // Move the buttons to control
+	    control_pane.add(button_pane, BorderLayout.SOUTH);
+	    card_layout.show(main_pane, CONTROL);
+	}
+	else {
+	    // Move the buttons to progress
+	    progress_pane.add(button_pane, BorderLayout.SOUTH);
+	    card_layout.show(main_pane, PROGRESS);
+	}
+	// Refresh the set of controls.
+	TreePath path = tree.getSelectionPath();
+	tree.clearSelection();
+	tree.setSelectionPath(path);
+
+	//Disable the full/incremental buttons if the collection has not been built.
+	if(Gatherer.c_man.built()) {
+	    full_build_radio_button.setEnabled(true);
+	    incremental_build_radio_button.setEnabled(true);
+	    sfull_build_radio_button.setEnabled(true);
+	    sincremental_build_radio_button.setEnabled(true);
+	}
+	else {
+	    full_build_radio_button.setEnabled(false);
+	    incremental_build_radio_button.setEnabled(false);
+	    sfull_build_radio_button.setEnabled(false);
+	    sincremental_build_radio_button.setEnabled(false);
+	}
+    }
+
+    /** We are informed when this view pane loses focus so we can update build options. */
+    public void loseFocus() {
+	tree.valueChanged(null);
+    }
+
+    /**
+     * Check to see if doing an incremental build is chosen.
+     * If not, the full rebuild option must be chosen.
+     * @return boolean - true if the collection should be rebuilt incrementally.
+     */
+    public boolean isIncremental() {
+	boolean incremental = false;
+
+	//This is horrible. What if the mode is changed, and different options are chosen on different modes??
+	if(Gatherer.c_man.built()) {
+	    if(Configuration.getMode() >= THRESHOLD) {
+		incremental = incremental_build_radio_button.isSelected();
+	    }
+	    else {
+		incremental = sincremental_build_radio_button.isSelected();
+	    }
+	}
+	else {
+	    incremental = false; //The collection has not yet been built
+	}
+	return incremental;
+    }
+
+    /** All implementation of GShellListener must include this method so the listener can be informed of messages from the GShell.
+     * @param event A <strong>GShellEvent</strong> that contains, amoung other things, the message.
+     */
+    public synchronized void message(GShellEvent event) {
+	// Ignore the messages from RecPlug with 'show_progress' set (used for progress bars)
+	if (event.getMessage().startsWith("import.pl> RecPlug - ")) {
+	    return;
+	}
+	document.appendLine(event.getMessage());
+	log_textarea.setCaretPosition(document.getLengthToNearestLine());
+    }
+
+    /** Called when the detail mode has changed which in turn may cause several import/build configuration arguments to be available/hidden
+     * @param mode the new mode as an int
+     */
+    public void modeChanged(int mode) {
+	// If we are below the complexity threshold ensure the simple controls are being shown
+	if(Configuration.getMode() < THRESHOLD) {
+	    // Update the arguments
+	    souter_panel.remove(sargument_configuration_scroll);
+	    souter_panel.remove(sinner_panel);
+	    if(options_pane != null) {
+		sargument_configuration_panel = options_pane.buildImport(null);
+		sargument_configuration_panel = options_pane.buildBuild(sargument_configuration_panel);
+	    }
+	    else {
+		sargument_configuration_panel = new JPanel();
+	    }
+	    sargument_configuration_scroll = new JScrollPane(sargument_configuration_panel);
+	    sargument_configuration_scroll.setPreferredSize(ARGUMENT_SIZE);
+	    souter_panel.add(sargument_configuration_scroll);
+	    souter_panel.add(sinner_panel);
+	    // Remove the shared components from the expert panels
+	    progress_pane.remove(log_scroll);
+	    // And add to simple one
+	    simple_panel.add(log_scroll, BorderLayout.CENTER);
+	    // And bring the card to the front
+	    card_layout.show(main_pane, SIMPLE);
+	}
+	// And if we are above the threshold change to the complex controls
+	else {
+	    // Remove the shared components from the simple panel
+	    simple_panel.remove(log_scroll);
+	    // And add then to the expert ones
+	    progress_pane.add(log_scroll, BorderLayout.CENTER);
+	    // And bring the appropriate card to the front
+	    if(!processing) {
+		control_pane.add(button_pane, BorderLayout.SOUTH);
+		card_layout.show(main_pane, CONTROL);
+	    }
+	    else {
+		progress_pane.add(button_pane, BorderLayout.SOUTH);
+		card_layout.show(main_pane, PROGRESS);
+	    }
+	}
+	tree.valueChanged(null); // Ensure tree argument panels are rebuilt
+    }
+
+    /** All implementation of GShellListener must include this method so the listener can be informed when a GShell begins its task. Implementation side-effect, not actually used.
+     * @param event A <strong>GShellEvent</strong> that contains details of the initial state of the <strong>GShell</strong> before task comencement.
+     */
+    public synchronized void processBegun(GShellEvent event) {
+	// We don't care. We'll get a more acurate start from the progress monitors.
+    }
+    /** All implementation of GShellListener must include this method so the listener can be informed when a GShell completes its task.
+     * @param event A <strong>GShellEvent</strong> that contains details of the final state of the <strong>GShell</strong> after task completion.
+     */
+    public synchronized void processComplete(GShellEvent event) {
+	if(event.getStatus() == GShell.OK) {
+	    if(event.getType() == GShell.BUILD) {
+		processing = false;
+		build_button.setEnabled(true);
+		cancel_button.setEnabled(false);
+		//preview_button.setEnabled(true);
+		simple_build_button.setEnabled(true);
+		simple_cancel_button.setEnabled(false);
+		//simple_preview_button.setEnabled(true);
+		int status = event.getStatus();
+		document.setSpecialCharacter(OptionsPane.SUCCESSFUL);
+		options_pane.resetFileEntry();
+		build_monitor.reset();
+		import_monitor.reset();
+		if(Configuration.getMode() >= THRESHOLD) {
+		    control_pane.add(button_pane, BorderLayout.SOUTH);
+		    card_layout.show(main_pane, CONTROL);
+		}
+	    }
+	    // Otherwise its completed import but still got build to go
+	}
+	else {
+	    processing = false;
+	    cancel_button.setEnabled(false);
+	    build_button.setEnabled(true);
+	    // The build may have failed, but a previous index may still be in place
+	    //preview_button.setEnabled(Gatherer.c_man.built());
+
+	    simple_build_button.setEnabled(true);
+	    simple_cancel_button.setEnabled(false);
+	    //simple_preview_button.setEnabled(Gatherer.c_man.built());
+	    if(event.getStatus() == GShell.CANCELLED) {
+		document.setSpecialCharacter(OptionsPane.CANCELLED);
+	    }
+	    else {
+		document.setSpecialCharacter(OptionsPane.UNSUCCESSFUL);
+	    }
+	    options_pane.resetFileEntry();
+	    if(Configuration.getMode() >= THRESHOLD) {
+		control_pane.add(button_pane, BorderLayout.SOUTH);
+		card_layout.show(main_pane, CONTROL);
+	    }
+	}
+    }
+
+
+    /** This method is invoked at any time there has been a significant change in the collection, such as saving, loading or creating.
+     * @param ready A <strong>boolean</strong> indicating if a collection is currently available.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.CollectionManager
+     * @see org.greenstone.gatherer.gui.BuildOptions
+     * @see org.greenstone.gatherer.gui.OptionsPane
+     */
+    public void refresh(int refresh_reason, boolean ready)
+    {
+	if (Gatherer.c_man == null || !ready) {
+	    return;
+	}
+	Collection current_collection = Gatherer.c_man.getCollection();
+	if (current_collection != previous_collection && !Gatherer.c_man.isImporting()) {
+	    this.options_pane = new OptionsPane(current_collection.import_options, current_collection.build_options);
+	    if (previous_collection != null) {
+		// clear the log
+		Document log_document = log_textarea.getDocument();
+		if (log_document instanceof AppendLineOnlyFileDocument) {
+		    ((AppendLineOnlyFileDocument) log_document).destroy();
+		}
+	    }
+	    previous_collection = current_collection;
+	   
+	} 
+	// If we are in simple mode, we have to rebuild the simple arguments list
+	if(Configuration.getMode() < THRESHOLD) {
+	    souter_panel.remove(sargument_configuration_scroll);
+	    souter_panel.remove(sinner_panel);
+	    sargument_configuration_panel = options_pane.buildImport(null);
+	    sargument_configuration_panel = options_pane.buildBuild(sargument_configuration_panel);
+	    sargument_configuration_scroll = new JScrollPane(sargument_configuration_panel);
+	    sargument_configuration_scroll.setPreferredSize(ARGUMENT_SIZE);
+	    souter_panel.add(sargument_configuration_scroll);
+	    souter_panel.add(sinner_panel);
+	}
+	tree.valueChanged(null);
+
+	// Validate the preview button
+	if (Gatherer.c_man.built() && Configuration.library_url != null) {
+	    preview_button.setEnabled(true);
+	    simple_preview_button.setEnabled(true);
+	}
+	else {
+	    preview_button.setEnabled(false);
+	    simple_preview_button.setEnabled(false);
+	}
+    }
+
+
+    private void configureHomeURL() {	
+	// set up the home page for the current collection
+	Collection current_collection = Gatherer.c_man.getCollection();
+	String site = Configuration.site_name; // for GS3 colls
+	String extra_args = "";
+	SearchTypeManager st_man = current_collection.cdm.searchtype_manager;
+	if (!Gatherer.GS3 && st_man.isMGPPEnabled()) {
+	    // we need some more args on the url
+	    String search_types = st_man.getSearchTypes();
+	    if (search_types.equals("")) {
+		extra_args = "&ct=1&qt=0&qto=3";
+	    } else if (search_types.equals("plain")) {
+		extra_args = "&ct=1&qt=0&qto=1";
+	    } else if (search_types.equals("form")) {
+		extra_args = "&ct=1&qt=1&qto=2";
+	    } else if (search_types.equals("plain,form")) {
+		extra_args = "&ct=1&qt=0&qto=3";
+	    } else if (search_types.equals("form,plain")) {
+		extra_args = "&ct=1&qt=1&qto=3";
+	    }
+	}
+	// Remember to add unique timestamp
+	if (Gatherer.GS3) {
+	    homepage = Configuration.library_url.toString() + Configuration.getServletPath()+ "?a=p&sa=about&c=" + current_collection.getName()+"&l="+Configuration.getLanguage(); //+extra_args + StaticStrings.TIMESTAMP_ARGUMENT + System.currentTimeMillis();
+	} else {
+	    homepage = Configuration.library_url.toString() + "?a=p&p=about&c=" + current_collection.getName()+"&l="+Configuration.getLanguage()+extra_args + StaticStrings.TIMESTAMP_ARGUMENT + System.currentTimeMillis();
+	}
+    }
+    
+
+    /** This class serves as the listener for actions on the build button. */
+    private class BuildButtonListener
+	implements ActionListener {
+	/**
+	 * This method checks to see what needs to be done for a build, and starts the process off.
+	 * A complete build proccess is started by {@link CollectionManager.importCollection()}, which then imports and builds the collection.
+	 * However, this doesn't always happen, as sometimes an incremental build will do :-)
+	 * @param event An <strong>ActionEvent</strong> who, thanks to the power of object oriented programming, we don't give two hoots about.
+	 * @see org.greenstone.gatherer.Gatherer
+	 * @see org.greenstone.gatherer.collection.CollectionManager
+	 * @see org.greenstone.gatherer.gui.BuildOptions
+	 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    Collection collection = Gatherer.c_man.getCollection();
+	    String collection_name = collection.getName();
+	    if(!collection.getMetadataChanged() && !collection.getFilesChanged() && isIncremental()) {
+		//Only design options have changes, and we want to be smart in the way we handle them.
+		int rebuildTypeRequired = CollectionDesignManager.getRebuildTypeRequired();
+
+		if(rebuildTypeRequired == CollectionDesignManager.UPDATE_COLLECT_CFG && Gatherer.isGsdlRemote) {
+		    //Special case when the GLI is an applet: Upload the collect.cfg to server 
+		    //This is already handled by CollectionDesignManager.save()
+		    DebugStream.println("Just want to upload collect.cfg, but this has already been done");
+		}
+		else if(rebuildTypeRequired == CollectionDesignManager.BUILDCOL) {
+		    //Just run the buildcol command.
+		    DebugStream.println("Just want to run buildcol.pl");
+		    prepareForBuild();
+		    Gatherer.c_man.buildCollection(isIncremental());
+		}
+		else if(rebuildTypeRequired == CollectionDesignManager.ALL) {
+		    //Do a usual build.
+		    DebugStream.println("Want to do a complete build");
+		    prepareForBuild();
+		    Gatherer.c_man.importCollection(); //This starts the building process.
+		}
+		else {
+		    //Nothing at all needs doing.
+		    //This is bad HCI. Maybe should disable the build button in this situation?
+		    System.err.println("Want to build the collection but nothing needs doing.");
+		}
+	    }
+	    else {
+		//Do a complete build.
+		prepareForBuild();
+		Gatherer.c_man.importCollection(); //This starts the building process.
+	    }
+	    //Re-setting the rebuildTypeRequired is handled by CollectionManager.processComplete(GShellEvent)
+	}
+
+	/**
+	 * This does some stuff that is needed before a collection can be built.
+	 * For example, buttons are enabled/disabled, and certain flags are set.
+	 * This is called from {@link actionPerformed(ActionEvent)}
+	 */
+	private void prepareForBuild() {
+	    // First we force the build options to be updated if we haven't already.
+	    tree.valueChanged(null);
+	    
+	    // Remember that for lower thresholds the above doesn't work, so try this instead
+	    if(Configuration.getMode() < THRESHOLD) {
+		options_pane.update(sargument_configuration_panel);
+	    }
+	    
+	    // Now go about building.
+	    build_button.setEnabled(false);
+	    cancel_button.setEnabled(true);
+	    preview_button.setEnabled(false);
+	    
+	    simple_build_button.setEnabled(false);
+	    simple_cancel_button.setEnabled(true);
+	    simple_preview_button.setEnabled(false);
+	    
+	    document = options_pane.createNewLogDocument();
+	    log_textarea.setDocument(document);
+	    options_pane.log_textarea.setDocument(document);
+	    // Change the view.
+	    processing = true;
+	    if(Configuration.getMode() >= THRESHOLD) {
+		progress_pane.add(button_pane, BorderLayout.SOUTH);
+		card_layout.show(main_pane, PROGRESS);
+	    }
+	    // Reset the stop flag in all the process monitors, just incase.
+	    ((GBuildProgressMonitor)build_monitor).reset();
+	    import_monitor.setStop(false);
+	}
+    }
+    
+    
+    /** This class serves as the listener for actions on the cancel button. */
+    private class CancelButtonListener
+	implements ActionListener {
+	/** This method attempts to cancel the current GShell task. It does this by first telling CollectionManager not to carry out any further action. This it turn tells the GShell to break from the current job immediately, without waiting for the processEnded message, and then kills the thread in an attempt to stop the process. The results of such an action are debatable.
+	 * @param event An <strong>ActionEvent</strong> who, thanks to the power of object oriented programming, we don't give two hoots about.
+	 * @see org.greenstone.gatherer.Gatherer
+	 * @see org.greenstone.gatherer.collection.CollectionManager
+	 * @see org.greenstone.gatherer.gui.BuildOptions
+	 * @see org.greenstone.gatherer.shell.GShellProgressMonitor
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    build_button.setEnabled(false);
+	    cancel_button.setEnabled(false);
+	    preview_button.setEnabled(false);
+
+	    simple_build_button.setEnabled(false);
+	    simple_cancel_button.setEnabled(false);
+	    simple_preview_button.setEnabled(false);
+
+	    processing = false;
+	    document.setSpecialCharacter(OptionsPane.CANCELLED);
+	    if(Configuration.getMode() >= THRESHOLD) {
+		control_pane.add(button_pane, BorderLayout.SOUTH);
+		card_layout.show(main_pane, CONTROL);
+	    }
+	    // Set the stop flag in all the process monitor.
+	    import_monitor.setStop(true);
+	    import_monitor.reset();
+	    build_monitor.setStop(true);
+	    build_monitor.reset();
+
+	    // Remove the collection lock.
+	    //Gatherer.g_man.lockCollection(false, false);
+	}
+    }
+
+    private class PreviewButtonListener
+	implements ActionListener {
+	
+	public void actionPerformed(ActionEvent event) {
+	    Gatherer.c_man.getCollection().cdm.save(); // save the config file just in case
+	    configureHomeURL();
+	    Gatherer.self.spawnBrowser(homepage);
+
+	}
+    }
+    
+    /** The OptionTree is simply a tree structure that has a root node labelled "Options" and then has a child node for each available options screen. These screens are either combinations of the available import and build arguments, or a message log detailing the shell processes progress. */
+    private class OptionTree
+	extends JTree
+	implements TreeSelectionListener {
+	/** The model behind the tree. */
+	private DefaultTreeModel model = null;
+	/** The previous options view displayed, which is sometimes needed to refresh properly. */
+	private JPanel previous_pane = null;
+	/** The node corresponding to the building options view. */
+	private OptionTreeNode building  = null;
+	/** The node corresponding to the importing options view. */
+	private OptionTreeNode importing = null;
+	/** The node corresponding to the log view. */
+	private OptionTreeNode log       = null;
+	/** The root node of the options tree, which has no associated options view. */
+	private OptionTreeNode options   = null;
+	/** Constructor.
+	 * @see org.greenstone.gatherer.gui.CreatePane.OptionTreeNode
+	 */
+	public OptionTree() {
+	    super();
+
+	    ToolTipManager.sharedInstance().registerComponent(this);
+	    addTreeSelectionListener(this);
+	    getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+	    setCellRenderer(new ToolTipTreeCellRenderer());
+	    setRootVisible(false);
+	    setToggleClickCount(1);
+
+	    // Create tree.
+	    building = new OptionTreeNode(Dictionary.get("CreatePane.Build"));
+	    building.setToolTipText(Dictionary.get("CreatePane.Build_Tooltip"));
+	    importing = new OptionTreeNode(Dictionary.get("CreatePane.Import"));
+	    importing.setToolTipText(Dictionary.get("CreatePane.Import_Tooltip"));
+	    log = new OptionTreeNode(Dictionary.get("CreatePane.Log"));
+	    log.setToolTipText(Dictionary.get("CreatePane.Log_Tooltip"));
+	    options = new OptionTreeNode(Dictionary.get("CreatePane.Options"));
+
+	    model = new DefaultTreeModel(options);
+	    setModel(model);
+	    model.insertNodeInto(importing, options, 0);
+	    model.insertNodeInto(building, options, 1);
+	    model.insertNodeInto(log, options, 2);
+	    // Expand the root node
+	    expandPath(new TreePath(options));
+	}
+	/** Any implementation of TreeSelectionListener must include this method to allow this listener to know when the selection has changed. Here we swap the options view depending on the selected OptionTreeNode.
+	 * @param event A <Strong>TreeSelectionEvent</strong> which contains all the information garnered when the event occured.
+	 * @see org.greenstone.gatherer.gui.CreatePane.OptionTreeNode
+	 */
+	public void valueChanged(TreeSelectionEvent event) {
+	    TreePath path = null;
+	    OptionTreeNode node = null;
+	    //if(event != null) {
+	    //path = event.getPath();
+	    path = getSelectionPath();
+	    if(path != null) {
+		node = (OptionTreeNode)path.getLastPathComponent();
+	    }
+				//}
+	    if(previous_pane != null) {
+		//target_pane.remove(previous_pane);
+		options_pane.update(previous_pane);
+		if(scroll_pane != null) {
+		    right.remove(scroll_pane);
+		}
+		else {
+		    right.remove(previous_pane);
+		}
+		previous_pane = null;
+		scroll_pane = null;
+	    }
+	    if(node != null && node.equals(building)) {
+		previous_pane = options_pane.buildBuild(null);
+		scroll_pane = new JScrollPane(previous_pane);
+		right.add(scroll_pane, BorderLayout.CENTER);
+		//target_pane.add(previous_pane, BorderLayout.CENTER);
+	    }
+	    else if(node != null && node.equals(importing)) {
+		previous_pane = options_pane.buildImport(null);
+		scroll_pane = new JScrollPane(previous_pane);
+		right.add(scroll_pane, BorderLayout.CENTER);
+		//target_pane.add(previous_pane, BorderLayout.CENTER);
+	    }
+	    else {
+		if (options_pane != null) {
+		    previous_pane = options_pane.buildLog();
+		    right.add(previous_pane, BorderLayout.CENTER);
+		    right.updateUI(); // we need to repaint the log pane, cos it hasn't changed since last time
+		    ///ystem.err.println("I've added the log back to the right pane again.");
+		    //target_pane.add(previous_pane, BorderLayout.CENTER);
+		}
+	    }
+				//scroll_pane.setViewportView(previous_pane);
+	    //previous_pane.validate();
+	    right.validate();
+	    //System.err.println("Current pane size: " + previous_pane.getSize());
+	    //System.err.println("While its preferred size is: " + previous_pane.getPreferredSize());
+	}
+    }
+
+    /** The <strong>OptionTree</strong> is built from these nodes, each of which has several methods used in creating the option panes.
+     */
+    private class OptionTreeNode
+	extends DefaultMutableTreeNode
+	implements Comparable {
+	/** The text label given to this node in the tree. */
+	private String title = null;
+	/** a tool tip to be used for this node in the tree */
+	private String tool_tip = null;
+	/** Constructor.
+	 * @param title The <strong>String</strong> which serves as this nodes title.
+	 */
+	public OptionTreeNode(String title) {
+	    super();
+	    this.title = title;
+	}
+
+	/** This method compares two nodes for ordering.
+	 * @param obj The <strong>Object</strong> to compare to.
+	 * @return An <strong>int</strong> of one of the possible values -1, 0 or 1 indicating if this node is less than, equal to or greater than the target node respectively.
+	 */
+	public int compareTo(Object obj) {
+	    return title.compareTo(obj.toString());
+	}
+
+	/** This method checks if two nodes are equivalent.
+	 * @param obj The <strong>Object</strong> to be tested against.
+	 * @return A <strong>boolean</strong> which is <i>true</i> if the objects are equal, <i>false</i> otherwise.
+	 */
+	public boolean equals(Object obj) {
+	    if(compareTo(obj) == 0) {
+		return true;
+	    }
+	    return false;
+	}
+
+	/** get the tool tip */
+	public String getToolTipText() {
+	    return tool_tip;
+	}
+
+	/** set the tool tip */
+	public void setToolTipText(String tip) {
+	    tool_tip = tip;
+	}
+	
+	/** Method to translate this node into a textual representation.
+	 * @return A <strong>String</strong> which in this case is the title.
+	 */
+	public String toString() {
+	    return title;
+	}
+    }
+
+    // Adds tooltips to the tree nodes
+    private class ToolTipTreeCellRenderer
+	extends DefaultTreeCellRenderer {
+
+	public Component getTreeCellRendererComponent(JTree tree,
+						      Object value,
+						      boolean sel,
+						      boolean expanded,
+						      boolean leaf,
+						      int row,
+						      boolean hasFocus) {
+
+	    super.getTreeCellRendererComponent(tree, value, sel,
+					       expanded, leaf, row,
+					       hasFocus);
+	    if (value instanceof OptionTreeNode) {
+		String tip = ((OptionTreeNode) value).getToolTipText();
+		if (tip != null) {
+		    setToolTipText(tip);
+		}
+	    }
+	    return this;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DeleteCollectionPrompt.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DeleteCollectionPrompt.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DeleteCollectionPrompt.java	(revision 10506)
@@ -0,0 +1,360 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.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.Configuration;
+import org.greenstone.gatherer.DebugStream;
+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;
+import org.greenstone.gatherer.util.Utility;
+
+/** 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 John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class DeleteCollectionPrompt
+    extends ModalDialog {
+    /** The currently selected collection for deletion. */
+    private BasicCollectionConfiguration collection = null;
+    /** The model behind the list. */
+    private DefaultListModel list_model = null;
+    /** A reference to ourself so any inner-classes can dispose of us. */
+    private DeleteCollectionPrompt prompt = null;
+    /** The close button, which exits the prompt without deleting anything. */
+    private JButton close_button = null;
+    /** The ok button which causes the selected collection to be deleted. */
+    private JButton ok_button = null;
+    /** The confirmation check box. */
+    private JCheckBox confirmation = null;
+    /** The label above details. */
+    private JLabel details_label = null;
+    /** The label above the list. */
+    private JLabel list_label = null;
+    /** The list of available collections. */
+    private JList list = null;
+    /** The text area used to display details about the collection selected. */
+    private JTextArea details = null;
+    /** A string array used to pass arguments to the phrase retrieval method. */
+    private String args[] = null;
+
+    private boolean current_coll_deleted = false;
+    /** The size of the delete prompt screen. */
+    public static final Dimension SIZE = new Dimension(500, 500);
+
+    /** Constructor.
+     */
+    public DeleteCollectionPrompt() {
+	super(Gatherer.g_man);
+	close_button = new GLIButton();
+	close_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(close_button, "General.Close", "General.Close_Tooltip");
+	confirmation = new JCheckBox();
+	Dictionary.setText(confirmation, "DeleteCollectionPrompt.Confirm_Delete");
+	details = new JTextArea();
+	details.setEditable(false);
+	Dictionary.setText(details, "DeleteCollectionPrompt.No_Collection");
+	details_label = new JLabel();
+	Dictionary.setText(details_label, "DeleteCollectionPrompt.Collection_Details");
+	list = new JList();
+	list_label = new JLabel();
+	Dictionary.setText(list_label, "DeleteCollectionPrompt.Collection_List");
+	list_model = new DefaultListModel();
+	ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_D);
+	Dictionary.setBoth(ok_button, "DeleteCollectionPrompt.Delete", "DeleteCollectionPrompt.Delete_Tooltip");
+	prompt = this;
+	setModal(true);
+	setSize(SIZE);
+	Dictionary.setText(this, "DeleteCollectionPrompt.Title");
+
+	setJMenuBar(new SimpleMenuBar("0")); // need to find an appropriate help page to open at
+	close_button.addActionListener(new CloseButtonListener());
+	confirmation.addActionListener(new ConfirmationCheckBoxListener());
+	confirmation.setEnabled(false);
+	confirmation.setSelected(false);
+	list.addListSelectionListener(new CollectionListListener());
+	list.clearSelection();
+	list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	list.setModel(list_model);
+	ok_button.addActionListener(new OKButtonListener());
+	ok_button.setEnabled(false);
+	scanForCollections();
+    }
+
+    /** Destructor. */
+    public void destroy() {
+	list_model.clear();
+	list_model = null;
+	close_button = null;
+	confirmation = null;
+	details = null;
+	details_label = null;
+	list = null;
+	ok_button = null;
+	prompt = null;
+    }
+
+    /** This method causes the modal prompt to be displayed. 
+     * returns true if it has deleted the collection that is currently open */
+    public boolean display() {
+	// Central pane
+	JPanel list_pane = new JPanel(new BorderLayout());
+	list_pane.add(list_label, BorderLayout.NORTH);
+	list_pane.add(new JScrollPane(list), BorderLayout.CENTER);
+	list_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
+
+	JPanel details_pane = new JPanel(new BorderLayout());
+	details_pane.add(details_label, BorderLayout.NORTH);
+	details_pane.add(new JScrollPane(details), BorderLayout.CENTER);
+	details_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+
+	JPanel central_pane = new JPanel(new GridLayout(2, 1));
+	central_pane.add(list_pane);
+	central_pane.add(details_pane);
+	central_pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+	// Lower pane
+	JPanel confirmation_pane = new JPanel(new BorderLayout());
+	confirmation_pane.add(confirmation, BorderLayout.CENTER);
+	confirmation_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+
+	JPanel button_pane = new JPanel(new GridLayout(1, 2));
+	button_pane.add(ok_button);
+	button_pane.add(close_button);
+	button_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+
+	JPanel lower_pane = new JPanel(new BorderLayout());
+	lower_pane.add(confirmation_pane, BorderLayout.NORTH);
+	lower_pane.add(button_pane, BorderLayout.SOUTH);
+	lower_pane.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
+
+	// Final.
+	JPanel content_pane = (JPanel)this.getContentPane();
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(central_pane, BorderLayout.CENTER);
+	content_pane.add(lower_pane, BorderLayout.SOUTH);
+
+	// Center and display.
+	Dimension screen_size = Configuration.screen_size;
+	this.setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	this.setVisible(true); // blocks until the dialog is killed
+	return current_coll_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) {
+	args = new String[1];
+	args[0] = collection.getName();
+	if (success) {
+	    JOptionPane.showMessageDialog(prompt,Dictionary.get("DeleteCollectionPrompt.Successful_Delete", args),Dictionary.get("DeleteCollectionPrompt.Successful_Title"),JOptionPane.INFORMATION_MESSAGE);
+	}
+	else {
+	    JOptionPane.showMessageDialog(prompt,Dictionary.get("DeleteCollectionPrompt.Failed_Delete", args),Dictionary.get("DeleteCollectionPrompt.Failed_Title"),JOptionPane.WARNING_MESSAGE);
+	}
+    }
+
+    /** Method to scan the collect directory retrieving and reloading each collection it finds, while building the list of known collections.
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.util.ArrayTools
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    private void scanForCollections() {
+	// Start at the collect dir.
+	File collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	if (collect_directory.exists()) {
+	    // Now for each child directory see if it contains a .col file and
+	    // if so try to load it..
+	    File collections[] = collect_directory.listFiles();
+	    ArrayTools.sort(collections);
+	    for(int i = 0; collections != null && i < collections.length; i++) {
+		if(collections[i].isDirectory() && !collections[i].getName().equals(StaticStrings.MODEL_COLLECTION_NAME)) {
+		    File config_file = new File(collections[i], Utility.CONFIG_FILE);
+		    if (config_file.exists()) {
+			BasicCollectionConfiguration config = new BasicCollectionConfiguration(config_file);
+			list_model.addElement(config);
+			config = null;
+		    }
+		}
+	    }
+	}
+	// Otherwise the collect directory doesn't actually exist, so there ain't much we can do.
+    }
+
+    /** A button listener implementation, which listens for actions on the close button and disposes of the dialog when detected. */
+    private class CloseButtonListener 
+	implements ActionListener {
+	/** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
+	 * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    // Done
+	    prompt.dispose();
+	}
+    }
+
+    /** This private class listens for selection events in from the list and then displays the appropriate details for that collection.
+     */
+    private class CollectionListListener 
+	implements ListSelectionListener {
+	/** Any implementation of ListSelectionListener must include this method so we can be informed when the list selection changes.
+	 * @param  event a <strong>ListSelectionEvent</strong> containing all the relevant information garnered from the event itself
+	 */
+	public void valueChanged(ListSelectionEvent event) {
+	    ok_button.setEnabled(false);
+	    confirmation.setSelected(false);
+	    if(!list.isSelectionEmpty()) {
+		confirmation.setEnabled(true);
+		collection = (BasicCollectionConfiguration) list.getSelectedValue();
+		args = new String[3];
+		args[0] = collection.getCreator();
+		args[1] = collection.getMaintainer();
+		args[2] = collection.getDescription();
+		Dictionary.setText(details, "DeleteCollectionPrompt.Details", args);
+		details.setCaretPosition(0);
+	    }
+	    else {
+		confirmation.setEnabled(false);
+		Dictionary.setText(details, "DeleteCollectionPrompt.No_Collection");
+	    }
+	}
+    }
+
+    /** A check box listener so we can tell if the user has confirmed the deletion */
+    private class ConfirmationCheckBoxListener
+	implements ActionListener {
+	/** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
+	 * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    // OK button is only enabled if the confirmation check box is ticked
+	    ok_button.setEnabled(confirmation.isSelected());
+	}
+    }
+
+    /** The OK button listener implementation. */
+    private class OKButtonListener 
+	implements ActionListener {
+	/** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
+	 * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
+	 * @see org.greenstone.gatherer.Configuration
+	 * @see org.greenstone.gatherer.Gatherer
+	 * @see org.greenstone.gatherer.util.Utility
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    // Delete the selected collection.
+
+	    // First we must release it from the local library
+	    if (LocalLibraryServer.isRunning() == true) {
+		LocalLibraryServer.releaseCollection(collection.getShortName());
+	    }
+
+	    if (Gatherer.isGsdlRemote) {
+				
+		String launch_cgi  = Gatherer.cgiBase + "launch?cmd=deldir";
+
+		String col_name = collection.getShortName();
+		String dir = ".";
+
+		try {
+
+		    String col_name_encoded = URLEncoder.encode(col_name,"UTF-8");
+		    String dir_encoded = URLEncoder.encode(dir,"UTF-8");
+
+		    launch_cgi += "&c=" + col_name_encoded;
+		    launch_cgi += "&dir=" + dir_encoded;
+		
+		    URL launch_url = new URL(launch_cgi);
+		    URLConnection launch_connection = launch_url.openConnection();
+		    InputStream stdis = launch_connection.getInputStream();
+		    InputStreamReader stdisr = new InputStreamReader(stdis, "UTF-8"  );
+		    
+		    BufferedReader stdbr = new BufferedReader(stdisr);
+		    
+		    while(true) {
+			String line = stdbr.readLine();
+			// ignore output of running lauch command
+			
+			if (line == null) { break; }
+		    }		
+		    
+		    stdbr.close();
+		}
+		// Exception
+		catch (Exception exception) {
+		    DebugStream.println("Exception in GShell.runRemove() - unexpected");
+		    DebugStream.printStackTrace(exception);
+		}
+	    }
+
+	    if (Gatherer.c_man.deleteCollection(collection.getShortName())) {
+		// Refresh the collections shown in the workspace tree
+		Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.LIBRARY_CONTENTS_CHANGED);
+
+		if (Gatherer.c_man.getCollection() != null && collection.getShortName().equals(Gatherer.c_man.getCollection().getName())) {
+		    current_coll_deleted = true;
+		}
+		list_model.removeElement(collection);
+
+		resultPrompt(true);
+		Dictionary.setText(details, "DeleteCollectionPrompt.No_Collection");
+		confirmation.setEnabled(false);
+		confirmation.setSelected(false);
+		ok_button.setEnabled(false);
+		collection = null;
+	    }
+	    else {
+		resultPrompt(false);
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DesignPane.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DesignPane.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DesignPane.java	(revision 10506)
@@ -0,0 +1,125 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.cdm.CollectionDesignManager;
+/** This serves as the Collection configuration pane and came in two flavors.<BR>
+ * The lower tech version has now been made redundant.<BR>
+ * The higher tech, and finally implemented, version uses a tree to allow a user to navigate through the various regions of the config file and further allows them to interactively design and modify such gsdl elements as classifiers and plugins.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.2
+ */
+public class DesignPane 
+    extends JPanel {
+    /** The collection manager is responsible for parsing in, and allowing the editing of, a single collections configuration file. */
+    private CollectionDesignManager cdm = null;
+
+    /** The constructor. */
+    public DesignPane() {
+    }
+
+    /** Called to cause the components to lay themselves out and be displayed.
+     */
+    public void display() {
+	// Layout
+	this.setLayout(new BorderLayout());
+    }
+
+    public void gainFocus() {
+	if (cdm == null && Gatherer.c_man.ready()) {
+	    // Retrieve the new config manager.
+	    cdm = Gatherer.c_man.getCollection().cdm;
+	    // Display it.
+	    cdm.display(this);
+	}
+	if (cdm != null) {
+	    cdm.gainFocus();
+	}
+    }
+
+    public ArrayList getLanguageCodes() {
+	return cdm.language_manager.getLanguageCodes();
+    }
+
+    public boolean canSave() {
+	return cdm.canSave();
+    }
+
+    public void loseFocus() {
+	if (cdm != null) {
+	    cdm.save();
+	}
+    }
+
+    /** 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) {
+	if (cdm != null) {
+	    cdm.modeChanged(mode);
+	}
+    }
+
+    /** This method is called whenever the state of the current collection changes.
+     */
+    public void refresh(int refresh_reason, boolean ready)
+    {
+	if (ready) {
+	    // Retrieve the new config manager.
+	    cdm = Gatherer.c_man.getCollection().cdm;
+	    // Display it.
+	    cdm.display(this);
+	}
+	else {
+	    if (cdm != null) {
+		cdm.destroy();
+		cdm = null;
+	    }
+	}
+    }
+
+    public void saveConfiguration() {
+	if (cdm != null) {
+	    cdm.save();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DownloadPane.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DownloadPane.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DownloadPane.java	(revision 10506)
@@ -0,0 +1,386 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.WGet;
+import org.greenstone.gatherer.file.WorkspaceTree;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+/**
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.1
+ */
+public class DownloadPane
+    extends JPanel {
+
+    /** The threshold for when the advanced options get added */
+    static private final int THRESHOLD = Configuration.SYSTEMS_MODE;
+
+    private boolean download_button_enabled = false;
+    private boolean ready = false;
+    private int current_mode;
+    private JButton clear_cache_button;
+    private JButton download_button;
+    private JCheckBox higher_checkbox;
+    private JCheckBox requisite_checkbox;
+    private JCheckBox same_host_checkbox;
+    private JScrollPane list_scroll;
+    private JComboBox depth_combobox;
+    private JPanel options_pane;
+    private JTextField url_field;
+    private Vector depth_model;
+    private WGet getter;
+
+    public DownloadPane() {
+	super();
+	// Create a new wget thread
+        getter = new WGet();
+        getter.start();
+	// And retrieve its list of pending jobs
+	list_scroll = getter.getDownloadJobList();
+
+	current_mode = Configuration.getMode();
+	// String user_dir = System.getProperty("user.dir"); // ****
+	// System.err.println("**** user dir = "+user_dir);
+	// Create
+	JPanel edit_pane = new JPanel();
+	JPanel details_pane = new JPanel();
+	options_pane = new JPanel();
+
+	JPanel url_pane = new JPanel();
+	JLabel url_label = new JLabel();
+	Dictionary.registerText(url_label, "Mirroring.Source_URL");
+	url_field = new JTextField();
+	Dictionary.registerTooltip(url_field, "Mirroring.Source_URL_Tooltip");
+
+	depth_model = new Vector();
+	depth_model.add(new DepthEntry(0, Dictionary.get("Mirroring.Download_Depth.Zero")));
+	/* @todo - add to dictionary */
+	depth_model.add(new DepthEntry(1, String.valueOf(1)));
+	/* @todo - add to dictionary */
+	depth_model.add(new DepthEntry(2, String.valueOf(2)));
+	/* @todo - add to dictionary */
+	depth_model.add(new DepthEntry(3, String.valueOf(3)));
+	/* @todo - add to dictionary */
+	depth_model.add(new DepthEntry(4, String.valueOf(4)));
+	/* @todo - add to dictionary */
+	depth_model.add(new DepthEntry(5, String.valueOf(5)));
+	depth_model.add(new DepthEntry(-1, Dictionary.get("Mirroring.Download_Depth.Unlimited")));
+	JPanel depth_pane = new JPanel();
+	JLabel depth_label = new JLabel();
+	Dictionary.registerText(depth_label, "Mirroring.Download_Depth");
+	depth_combobox = new JComboBox(depth_model);
+	Dictionary.registerTooltip(depth_combobox, "Mirroring.Download_Depth_Tooltip");
+
+	requisite_checkbox = new JCheckBox();
+	Dictionary.registerText(requisite_checkbox, "Mirroring.Download_Embedded");
+	
+
+	higher_checkbox = new JCheckBox();
+	Dictionary.registerText(higher_checkbox, "Mirroring.Higher_Directories");
+	higher_checkbox.addActionListener(new CheckboxClickListener());
+	
+	same_host_checkbox = new JCheckBox();
+	same_host_checkbox.setSelected(true);
+	Dictionary.registerText(same_host_checkbox, "Mirroring.Same_Host");
+
+	JPanel button_pane = new JPanel();
+
+	JButton preferences_button = new GLIButton();
+	preferences_button.setEnabled(true);
+	preferences_button.setMnemonic(KeyEvent.VK_P);
+	Dictionary.registerBoth(preferences_button, "Mirroring.Preferences", "Mirroring.Preferences_Tooltip");
+	
+	clear_cache_button = new GLIButton();
+	clear_cache_button.setEnabled(true);
+	clear_cache_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.registerBoth(clear_cache_button, "Mirroring.ClearCache", "Mirroring.ClearCache_Tooltip");
+
+	download_button = new GLIButton();
+	download_button.setEnabled(true);
+	download_button.setMnemonic(KeyEvent.VK_D);
+	Dictionary.registerBoth(download_button, "Mirroring.Download", "Mirroring.Download_Tooltip");
+	// Connect
+	clear_cache_button.addActionListener(new ClearCacheListener());
+	download_button.addActionListener(new DownloadButtonListener());
+	preferences_button.addActionListener(new PreferencesButtonActionListener());
+
+	// Layout
+	url_pane.setLayout(new BorderLayout(5,0));
+	url_pane.add(url_label, BorderLayout.WEST);
+	url_pane.add(url_field, BorderLayout.CENTER);
+
+	depth_pane.setLayout(new GridLayout(1,3));
+	depth_pane.add(depth_label);
+	depth_pane.add(new JPanel());
+	depth_pane.add(depth_combobox);
+
+	details_pane.setLayout(new GridLayout(2,1,0,5));
+	details_pane.setBorder(BorderFactory.createEmptyBorder(2,2,5,2));
+	details_pane.add(url_pane);
+	details_pane.add(depth_pane);
+
+	options_pane.setLayout(new GridLayout(3,1,0,5));
+	
+	options_pane.add(higher_checkbox);
+	options_pane.add(same_host_checkbox);
+	if (current_mode >= THRESHOLD) {
+	    options_pane.add(requisite_checkbox);
+	}
+
+	button_pane.setLayout(new GridLayout(3,1));
+	button_pane.add(preferences_button);
+	button_pane.add(clear_cache_button);
+	button_pane.add(download_button);
+
+	edit_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(2,0,0,0), BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(Dictionary.get("Mirroring.Download_Controls")), BorderFactory.createEmptyBorder(2,2,2,2))));
+	edit_pane.setLayout(new BorderLayout());
+	edit_pane.add(details_pane, BorderLayout.NORTH);
+	edit_pane.add(button_pane, BorderLayout.EAST);
+	edit_pane.add(options_pane, BorderLayout.CENTER);
+
+	setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	setLayout(new BorderLayout());
+	add(edit_pane, BorderLayout.NORTH);
+	add(list_scroll, BorderLayout.CENTER);
+    }
+
+    public void afterDisplay() {
+	ready = true;
+    }
+
+
+    /** This method is called whenever the Download pane is brought into focus and is a good time to display a warning message if WGet is not available or of an older, problematic, version.
+     */
+    public void gainFocus() {
+	if(!ready) {
+	    return;
+	}
+	// Lets see what warning message we should display, if any.
+	String wget_version_str = Configuration.getWGetVersion();
+	if(wget_version_str.equals(StaticStrings.NO_WGET_STR)) {
+	    // If there was no WGet available then downloading is disabled entirely
+	    download_button_enabled = false;
+	    // And we tell the user why.
+	    Gatherer.missingWGET();
+	}
+	else if(wget_version_str.equals(StaticStrings.WGET_OLD_STR)) {
+	    // Downloading is enabled
+	    download_button_enabled = true;
+	    // But we display a preventable warning message about the path problems.
+	    Gatherer.oldWGET();
+	}
+	// Otherwise version must be ok
+	else {
+	    download_button_enabled = true;
+	}
+	// It is also a good time to determine if the download should be enabled - ie if its allowed to be enabled and a valid URL is present in the field.
+	download_button.setEnabled(download_button_enabled);
+    }
+
+    public void modeChanged(int mode) {
+	int old_mode = current_mode;
+	current_mode = mode;
+	if (old_mode >= THRESHOLD && current_mode >= THRESHOLD) {
+	    return;
+	}
+	if (old_mode < THRESHOLD && current_mode < THRESHOLD) {
+	    return;
+	}
+	if (current_mode >= THRESHOLD) {
+	    options_pane.add(requisite_checkbox);
+	}
+	else {
+	    options_pane.remove(requisite_checkbox);
+	    requisite_checkbox.setSelected(false);
+	}
+    }
+
+
+    public void refresh(int refresh_reason, boolean ready)
+    {
+    }
+
+
+    /** A DepthEntry contains a depth value, as an int, and a representitive text string. This allows for a more meaningful appearance than '0' for instance. */
+    private class DepthEntry 
+	implements Comparable {
+	private int value;
+	private String text;
+	/** Default constructor. 
+	 * @param value the depth value as an int
+	 * @param text how this entry show represent itself as a String
+	 */
+	public DepthEntry(int value, String text) {
+	    this.text = text;
+	    this.value = value;
+	}
+	/** Determines the natural ordering of this DepthEntry and some other object
+	 * @param object the Object to test for ordering
+	 * @return >0 if the object is before this one, 0 if they are equal, or <0 if the object is after this one
+	 */
+	public int compareTo(Object object) {
+	    // If the object is a DepthEntry then this is easy pesy.
+	    if(object instanceof DepthEntry) {
+		int target_value = ((DepthEntry) object).getValue();
+		return value - target_value;
+	    }
+	    // If the object is a String, then we should try parsing an int from it
+	    if(object instanceof String) {
+		try {
+		    int target_value = Integer.parseInt((String)object);
+		    return value - target_value;
+		}
+		catch(Exception exception) {
+		}
+	    }
+	    // Otherwise we'll try a string comparison between our text and the toString of the object
+	    return text.compareTo(object.toString());
+	}
+
+	/** Determine if this DepthEntry is equal to some other object. Given that there is significant processing involved we push the resposiblility for this onto compareTo, so we only have the complex code once.
+	 * @param object the Object to test for equality
+	 * @return true if the object is equal to this depth entry, false otherwise
+	 */
+	public boolean equals(Object object) {
+	    return (compareTo(object) == 0);
+	}
+
+	public int getValue() {
+	    return value;
+	}
+
+	public String toString() {
+	    return text;
+	}
+    }
+
+    private class ClearCacheListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    // Retrieve the cache folder and delete it.
+	    Utility.delete(Gatherer.getGLIUserCacheDirectoryPath());
+	    // ...and refresh the node in the workspace tree to show it's all gone
+	    Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.DOWNLOADED_FILES_CHANGED);
+	}
+    }
+
+    private class CheckboxClickListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    if (higher_checkbox.isSelected()) {
+		same_host_checkbox.setEnabled(false);
+	    } else {
+		same_host_checkbox.setEnabled(true);
+	    }
+	}
+    }
+    
+    private class DownloadButtonListener
+	implements ActionListener {
+
+	public void actionPerformed(ActionEvent event) {
+	    // Retrieve the current url and confirm it is valid
+	    String url_str = url_field.getText();
+	    URL url = null;
+	    try {
+		url = new URL(url_str);
+	    }
+	    catch(MalformedURLException error) {
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Mirroring.Invalid_URL"), Dictionary.get("Mirroring.Invalid_URL_Title"), JOptionPane.ERROR_MESSAGE);
+	    }
+
+	    // Otherwise construct a new download job
+	    Object depth_object = depth_combobox.getSelectedItem();
+	    int depth_value = 0;
+	    if(depth_object instanceof DepthEntry) {
+		depth_value = ((DepthEntry)depth_object).getValue();
+	    }
+	    else if(depth_object instanceof String) {
+		String depth_string = (String) depth_object;
+		try {
+		    depth_value = Integer.parseInt(depth_string);
+		    // Create a new entry for the purposes of comparison, and if needs be, addition
+		    DepthEntry new_entry = new DepthEntry(depth_value, depth_string);
+		    // Try to select the correct item from the combobox
+		    depth_combobox.setSelectedItem(null);
+		    depth_combobox.setSelectedItem(new_entry);
+		    // We can see if that worked, and if it didn't add the entry
+		    if(depth_combobox.getSelectedItem() == null) {
+			depth_combobox.addItem(new_entry);
+			depth_combobox.setSelectedItem(new_entry);
+		    }
+		    new_entry = null;
+		}
+		catch(Exception exception) {
+		    /* @todo - add to dictionary */
+		    JOptionPane.showMessageDialog(Gatherer.g_man, "Mirroring.Mirror_Depth.Invalid_Depth", "Mirroring.Mirror_Depth.Invalid_Depth_Title", JOptionPane.ERROR_MESSAGE);
+		    return;
+		}
+		depth_string = null;
+	    }
+	    depth_object = null;
+    
+	    String destination_file_path = Gatherer.getGLIUserCacheDirectoryPath();
+	    (new File(destination_file_path)).mkdirs(); // If they aren't already
+
+	    if(url != null) {
+		getter.newDownloadJob(higher_checkbox.isSelected(), (higher_checkbox.isSelected()? false : !same_host_checkbox.isSelected()), !requisite_checkbox.isSelected(), url, depth_value, destination_file_path);
+	    }
+	}
+    }
+
+    private class PreferencesButtonActionListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    new Preferences(Preferences.CONNECTION_PREFS);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DownloadProgressBar.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DownloadProgressBar.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/DownloadProgressBar.java	(revision 10506)
@@ -0,0 +1,402 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.DownloadJob;
+import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
+
+
+public class DownloadProgressBar
+    extends JPanel 
+    implements ActionListener {
+
+    static final private Dimension MINIMUM_BUTTON_SIZE = new Dimension(100, 25);
+    static final private Dimension PROGRESS_BAR_SIZE = new Dimension(580,65);
+
+    private boolean simple = false;
+
+    private Dimension bar_size = new Dimension(520, 15);
+
+    private int current_action;
+    private int err_count;
+    private int file_count;
+    private int total_count;
+    private int warning_count;
+
+    private JLabel current_status;
+    private JLabel main_status;
+    private JLabel results_status;
+	 
+    private JPanel center_pane;
+    private JPanel inner_pane;
+
+    private JProgressBar progress;
+
+    private long file_size;
+    private long total_size;
+
+    private String current_url;
+    private String initial_url;
+
+    private DownloadJob owner;
+
+    public JButton stop_start_button;
+    public JButton log_button;
+    public JButton close_button;
+
+    public DownloadProgressBar(DownloadJob owner, String initial_url, boolean simple) {
+	this.owner = owner;
+	this.current_url = null;
+	this.err_count = 0;
+	this.initial_url = initial_url;
+	this.file_count = 0;
+	this.file_size = 0;
+	this.simple = simple;
+	this.total_count = 0;
+	this.total_size = 0;
+	this.warning_count = 0;
+
+	this.setLayout(new BorderLayout());
+	this.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
+
+	this.current_action = DownloadJob.STOPPED;
+
+	inner_pane = new JPanel(new BorderLayout());
+	inner_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
+
+	center_pane = new JPanel(new GridLayout(3,1));
+
+	main_status = new JLabel();
+
+	current_status = new JLabel();
+		  
+	results_status = new JLabel();
+
+	progress = new JProgressBar();
+	progress.setStringPainted(true);
+	progress.setMinimum(0);
+	progress.setMaximum(0);
+	progress.setEnabled(false);
+	Dictionary.setText(progress, "Mirroring.DownloadJob.Waiting");
+	inner_pane.add(progress, BorderLayout.CENTER);
+
+	center_pane.add(main_status);
+	center_pane.add(current_status);
+	center_pane.add(results_status);
+
+	JPanel button_pane = new JPanel();
+
+	stop_start_button = new GLIButton();
+	stop_start_button.addActionListener(this);
+	stop_start_button.addActionListener(owner);
+	stop_start_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
+	stop_start_button.setMnemonic(KeyEvent.VK_P);
+	stop_start_button.setEnabled(true);
+	Dictionary.registerBoth(stop_start_button, "Mirroring.DownloadJob.Pause", "Mirroring.DownloadJob.Pause_Tooltip");
+
+	log_button = new GLIButton();
+	log_button.addActionListener(owner);
+	log_button.addActionListener(this);
+	log_button.setEnabled(false);
+	log_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
+	log_button.setMnemonic(KeyEvent.VK_L);
+	Dictionary.registerBoth(log_button, "Mirroring.DownloadJob.Log", "Mirroring.DownloadJob.Log_Tooltip");
+
+	close_button = new GLIButton();
+	close_button.addActionListener(owner);
+	close_button.addActionListener(this);
+	close_button.setMinimumSize(MINIMUM_BUTTON_SIZE);
+	close_button.setMnemonic(KeyEvent.VK_C);
+	close_button.setEnabled(true);
+	Dictionary.registerBoth(close_button, "Mirroring.DownloadJob.Close", "Mirroring.DownloadJob.Close_Tooltip");
+
+	// Layout - or at least some of it
+
+	inner_pane.add(center_pane, BorderLayout.NORTH);
+
+	button_pane.setLayout(new GridLayout(3,1));
+	button_pane.add(stop_start_button);
+	button_pane.add(log_button);
+	button_pane.add(close_button);
+
+	this.add(inner_pane, BorderLayout.CENTER);
+	this.add(button_pane, BorderLayout.EAST);
+
+	// Make the labels, etc update.
+	refresh();
+    }
+
+    public void actionPerformed(ActionEvent event) {
+	Object source = event.getSource();
+	if(source == stop_start_button) {
+	    // If we are running, stop.
+	    if (current_action == DownloadJob.RUNNING) {
+		current_action = DownloadJob.STOPPED;
+		Dictionary.registerBoth(stop_start_button, "Mirroring.DownloadJob.Resume", "Mirroring.DownloadJob.Resume_Tooltip");
+		Dictionary.setText(progress, "Mirroring.DownloadJob.Download_Stopped");
+		progress.setIndeterminate(false);
+	    } else {
+		current_action = DownloadJob.RUNNING;
+		// we are stopped, so restart
+		Dictionary.registerBoth(stop_start_button, "Mirroring.DownloadJob.Pause", "Mirroring.DownloadJob.Pause_Tooltip");
+		Dictionary.setText(progress, "Mirroring.DownloadJob.Download_Progress");
+		progress.setIndeterminate(true);
+	    }
+	}
+	else if(source == close_button) {
+	    // If we are running, stop.
+	    if (current_action == DownloadJob.RUNNING) {
+		current_action = DownloadJob.STOPPED;
+		Dictionary.setText(progress, "Mirroring.DownloadJob.Download_Stopped");
+		progress.setIndeterminate(false);
+	    }
+	}
+	else if(source == log_button) {
+	    LogDialog dialog = new LogDialog(owner.getLogDocument());
+	    dialog.setVisible(true);
+	    dialog = null;
+	}
+    }
+
+    /** This method is called when a new download is begun. The
+     * details of the download are updated and a new JProgressBar
+     * assigned to track the download.
+     * @param url The url String of the file that is being downloaded.
+     */
+    public void addDownload(String url) {
+	current_url = url;
+	file_size = 0;
+	refresh();
+    }
+
+    /** When the download of the current url is completed, this method
+     * is called to enlighten the DownloadProgressBar of this fact.
+     */
+    public void downloadComplete() {
+	current_url = null;
+	file_count++;
+	if(total_count < (file_count + err_count + warning_count)) {
+	    total_count = (file_count + err_count + warning_count);
+	}
+	progress.setValue(progress.getMaximum());
+	//Dictionary.setText(progress, "Mirroring.DownloadJob.Download_Complete");
+	refresh();
+    }
+
+    public void downloadFailed() {
+	err_count++;
+	if(total_count < (file_count + err_count + warning_count)) {
+	    total_count = (file_count + err_count + warning_count);
+	}
+	refresh();
+    }
+
+    public void downloadWarning() {
+	warning_count++;
+	if(total_count < (file_count + err_count + warning_count)) {
+	    total_count = (file_count + err_count + warning_count);
+	}
+	refresh();
+    }
+
+    public Dimension getPreferredSize() {
+	return PROGRESS_BAR_SIZE;
+    }
+
+    /** When a link to be downloaded is located, the increaseTotalCount
+     * method is called. In this way the total count shows the most
+     * accurate remaining number of files to be downloaded.
+     */
+    public void increaseFileCount() {
+	total_count++;
+	refresh();
+    }
+
+    /** When a mirroring task is first initiated this function is called
+     * to set initial values for the variables if necessary and to 
+     * fiddle visual components such as the tool tip etc.
+     * @param reset A Boolean specifying whether the variables should be
+     * reset to zero.
+     */
+    public void mirrorBegun(boolean reset, boolean simple) {
+	if(reset) {
+	    this.file_count = 0;
+	    this.file_size = 0;
+	    this.total_count = 0;
+	    this.total_size = 0;
+	    this.err_count = 0;
+	    this.warning_count = 0;
+	}
+	current_action = DownloadJob.RUNNING;
+	stop_start_button.setEnabled(true);
+	log_button.setEnabled(true);
+	if(simple) {
+	    progress.setIndeterminate(true);
+	    Dictionary.setText(progress, "Mirroring.DownloadJob.Download_Progress");
+	}
+    }	
+
+    /** Once a mirroring task is complete, is the DownloadJob returns from the
+     * native call but the status is still running, then this method
+     * is called to once again tinker with the pritty visual 
+     * components.
+     */
+    public void mirrorComplete() {
+	current_action = DownloadJob.COMPLETE;
+	current_url = null;
+	if(simple) {
+	    progress.setIndeterminate(false);
+	}
+	progress.setValue(progress.getMaximum());
+	Dictionary.setText(progress, "Mirroring.DownloadJob.Download_Complete");
+
+	stop_start_button.setEnabled(false);
+	this.updateUI();
+    }
+
+    /** When called this method updates the DownloadProgressBar to reflect
+     * the ammount of the current file downloaded.
+     */
+    public void updateProgress(long current, long expected) {
+	file_size = file_size + current;
+	if(!progress.isIndeterminate()) {
+	    // If current is zero, then this is the 'precall' before the
+	    // downloading actually starts.
+	    if(current == 0) {
+		// Remove the old progress bar, then deallocate it.
+		inner_pane.remove(progress);
+		progress = null;
+		if(expected == 0) {
+		    // We don't have a content length. This bar will go from 0 to 100 only!
+		    progress = new JProgressBar(0, 100);
+		}
+		else {
+		    // Assign a new progress bar of length expected content length.
+		    progress = new JProgressBar(0, (new Long(expected)).intValue());
+		}
+		progress.setEnabled(true);
+		// Add the new progress bar.
+		inner_pane.add(progress, BorderLayout.CENTER);
+		inner_pane.updateUI();
+	    }
+	    // Otherwise if expected is not zero move the progress bar and
+	    // update percent complete.
+	    else if (expected != 0) {
+		progress.setValue((new Long(file_size)).intValue());
+		int p_c = (new Double(progress.getPercentComplete() * 100)).intValue();
+		progress.setString(p_c + "%");
+		progress.setStringPainted(true);
+	    }
+	    // Finally, in the case we have no content length, we'll instead
+	    // write the current number of bytes downloaded again.
+	    else {
+		progress.setString(file_size + " b");
+		progress.setStringPainted(true);
+	    }
+	}
+	refresh();
+    }
+
+    /** Causes the two labels associated with this DownloadProgressBar object to
+     * update, thus reflecting the progression of the download. This 
+     * method is called by any of the other public setter methods in this 
+     * class.
+     */
+    private void refresh() {
+	// Refresh the contents of main label.
+	String args1[] = new String[1];
+	args1[0] = initial_url.toString();
+	Dictionary.setText(main_status, "Mirroring.DownloadJob.Downloading", args1);
+
+	if (current_url != null) {
+	    // Refresh the current label contents.
+	    String args2[] = new String[1];
+	    args2[0] = current_url;
+	    Dictionary.setText(current_status, "Mirroring.DownloadJob.Downloading", args2);
+	}
+	else if (current_action == DownloadJob.STOPPED || current_action == DownloadJob.PAUSED) {
+	    Dictionary.setText(current_status, "Mirroring.DownloadJob.Waiting_User");
+	}
+	else {
+	    Dictionary.setText(current_status, "Mirroring.DownloadJob.Download_Complete");
+	}
+
+	// Refresh the contents of results label
+	String args3[] = new String[4]; 
+	args3[0] = file_count + "";
+	args3[1] = total_count + "";
+	args3[2] = warning_count + "";
+	args3[3] = err_count + "";
+	Dictionary.setText(results_status, "Mirroring.DownloadJob.Status", args3);
+
+	this.updateUI();
+    }
+
+    static final private Dimension DIALOG_SIZE = new Dimension(640,480);
+
+    private class LogDialog
+	extends JDialog {
+	
+	public LogDialog(AppendLineOnlyFileDocument document) {
+	    super(Gatherer.g_man, "Mirroring.DownloadJob.Download_Log_Dialog_Title");
+	    setSize(DIALOG_SIZE);
+	    JPanel content_pane = (JPanel) getContentPane();
+	    JTextArea text_area = new JTextArea(document);
+	    JButton button = new GLIButton(Dictionary.get("General.Close"));
+	    // Connection
+	    button.addActionListener(new CloseActionListener());
+	    // Layout
+	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(new JScrollPane(text_area), BorderLayout.CENTER);
+	    content_pane.add(button, BorderLayout.SOUTH);
+	}
+
+	private class CloseActionListener
+	    implements ActionListener {
+	    public void actionPerformed(ActionEvent event) {
+		LogDialog.this.dispose();
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/EditorDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/EditorDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/EditorDialog.java	(revision 10506)
@@ -0,0 +1,151 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+
+/** A class that extends a JDialog into a editor for editing large block of text for the metadata value.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+final public class EditorDialog
+    extends ModalDialog 
+    implements ActionListener {
+   /** Is this dialog editable? */
+   private boolean editable = true;
+   /** The cancel, and I don't want the text I've typed, button. */
+    private JButton cancel = null;
+    /** The ok, I'll save what I've just typed in, button. */
+    private JButton ok = null;
+    /** The area in which we type. */
+    private JTextArea text = null;
+    /** And what result should be passed back to our caller. */
+    private String result = null;
+    /** The size of the edit pop-up. */
+    final static private Dimension SIZE = new Dimension(400, 300);
+
+    /** Constructor */
+    public EditorDialog() {
+	super(Gatherer.g_man);
+    }
+
+    /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we generate a pop-up window to edit in.
+     * @param event An <strong>ActionEvent</strong> containing information about the event.
+     */
+    public void actionPerformed(ActionEvent event) {
+	if (event.getSource() == ok) {
+	    result = text.getText();
+	}
+	dispose();
+    }
+
+    /** Method to display the editing box on screen.
+     * @param value The initial text to be displayed in the editing area, as a <strong>String</strong>.
+     * @return The new value for the metadata value as a <strong>String</strong> or <i>null</i> if the user has pressed cancel.
+     */
+    public String display(String value) {
+	setModal(true);
+	setSize(SIZE);
+	setJMenuBar(new SimpleMenuBar("theenrichview"));
+	if (editable) {
+	    Dictionary.setText(this, "General.Edit");
+	} else {
+	    Dictionary.setText(this, "General.View");
+	}
+	// Create
+	text = new JTextArea(value);
+	text.setCaretPosition(value.length());
+	text.setEditable(editable);
+	text.setLineWrap(true);
+	text.setWrapStyleWord(false);
+	if (editable) {
+	    Dictionary.setTooltip(text, "EnrichPane.Value_Field_Tooltip");
+	} else {
+	    Dictionary.setTooltip(text, "EnrichPane.Value_Field_Tooltip_Uneditable");
+	}
+
+	cancel = new GLIButton();
+	cancel.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel, "General.Cancel", "General.Pure_Cancel_Tooltip");
+	ok = new GLIButton();
+	ok.setMnemonic(KeyEvent.VK_O);
+	Dictionary.setBoth(ok, "General.OK", "General.OK_Tooltip");
+
+	// Listeners
+	cancel.addActionListener(this);
+	ok.addActionListener(this);
+
+	// Layout
+	JPanel button_pane = new JPanel();
+	button_pane.setLayout(new GridLayout(1,2));
+	if(editable) {
+	   button_pane.add(ok);
+	   button_pane.add(cancel);
+	}
+	else {
+	   button_pane.add(new JPanel());
+	   button_pane.add(ok);
+	}
+		  
+	JPanel content_pane = (JPanel) getContentPane();
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(new JScrollPane(text), BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+		  
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	setVisible(true);
+	return result;
+    }
+
+    /** Specify if this text dialog should be editable or readonly
+     * @param editable true to allow editing, false otherwise
+     */
+    public void setEditable(boolean editable) {
+      if(text == null) {
+	 this.editable = editable;
+      }
+      else {
+	 text.setEditable(editable);
+      }
+   }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/EmailField.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/EmailField.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/EmailField.java	(revision 10506)
@@ -0,0 +1,67 @@
+package org.greenstone.gatherer.gui;
+
+import java.awt.*;
+import java.util.regex.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+
+public class EmailField
+    extends JTextField 
+    implements DocumentListener {
+
+    static final public Pattern EMAIL_PATTERN = Pattern.compile("([^()\\-<> @,;:\"][^()<> @,;:\"]*|\"[^()<>@,;:\"]+\")@([A-Za-z](-*[A-Za-z0-9])*(\\.[A-Za-z](-*[A-Za-z0-9])*)*)");
+
+    private boolean invalid = false;
+    private Color background;
+    private Color invalid_background;
+
+    public EmailField(Color invalid_background) {
+	super();
+	this.invalid_background = invalid_background;
+    }
+
+    public EmailField(String email, Color invalid_background) {
+	super(email);
+	this.invalid_background = invalid_background;
+    }
+
+    /** Gives notification that an attribute or set of attributes changed.
+     * @param e
+     */
+    public void changedUpdate(DocumentEvent e) {
+	validateEmail();
+    }
+          
+    /** Gives notification that there was an insert into the document.
+     * @param e
+     */
+    public void insertUpdate(DocumentEvent e) {
+	validateEmail();
+    }
+          
+    /** Gives notification that a portion of the document has been removed. 
+     * @param e
+     */
+    public void removeUpdate(DocumentEvent e) {
+	validateEmail();
+    }
+
+    private void validateEmail() {
+	Matcher m = EMAIL_PATTERN.matcher(getText());
+	if(m.matches()) {
+	    // It was invalid, but now its valid again
+	    if(invalid) {
+		setBackground(background);
+		invalid = false;
+	    }
+	    // Otherwise nothings changed so why do anything
+	}
+	else {
+	    background = getBackground();
+	    setBackground(invalid_background);
+	    invalid = true;
+	}
+	m = null;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/EnrichPane.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/EnrichPane.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/EnrichPane.java	(revision 10506)
@@ -0,0 +1,630 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ * Based on code by John Thompson
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer.gui;
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.CollectionTree;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+import org.greenstone.gatherer.gui.tree.DragTree;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataValue;
+import org.greenstone.gatherer.metadata.MetadataValueTableEntry;
+import org.greenstone.gatherer.metadata.MetadataValueTreeNode;
+import org.greenstone.gatherer.util.DragGroup;
+import org.greenstone.gatherer.util.TreeSynchronizer;
+
+
+/** Provides a view of controls for the editing of metadata.
+ */
+public class EnrichPane
+    extends JPanel
+    implements TreeSelectionListener
+{
+    static private Dimension MINIMUM_SIZE = new Dimension(100, 100);
+    static private Dimension COLLECTION_TREE_SIZE = new Dimension(250, 500);
+
+    /** The collection tree. */
+    private CollectionTree collection_tree = null;
+    /** The currently reported selection. */
+    private CollectionTreeNode[] file_nodes = null;
+    /** Used to dynamically filter the collection tree. Synchronized with the same filter in the Gather view. */
+    private Filter collection_filter = null;
+    /** The label at the top of the collection tree, which shows the collection name. */
+    private JLabel collection_label;
+    /** The splitpane dividing the collection tree and the metadata editing controls. */
+    private JSplitPane external_split;
+    /** The metadata value table shows the metadata values that are currently assigned to a file. */
+    private MetadataValueTablePane metadata_value_table_pane = null;
+    /** The metadata value tree shows the metadata values that are currently assigned to a metadata element. */
+    private MetadataValueTreePane metadata_value_tree_pane = null;
+    /** Provide synchronization between the collection trees in this view and the collection pane view. */
+    private TreeSynchronizer collection_tree_sync = null;
+
+
+    /** Constructor.
+     * @param tree_sync The <strong>TreeSynchronizer</strong> to be used on the collection tree
+     */
+    public EnrichPane(TreeSynchronizer collection_tree_sync)
+    {
+	this.collection_tree_sync = collection_tree_sync;
+
+	// Create the metadata value tree pane
+	metadata_value_tree_pane = new MetadataValueTreePane();
+	metadata_value_tree_pane.addMetadataValueTreeSelectionListener(new MetadataValueTreeSelectionListener());
+
+	// Create metadata value table pane
+	metadata_value_table_pane = new MetadataValueTablePane();
+	metadata_value_table_pane.addMetadataValueTableListSelectionListener(new MetadataValueTableListSelectionListener());
+	metadata_value_table_pane.addMetadataValueTableMouseListener(new MetadataValueTableMouseListener());
+	metadata_value_table_pane.addMetadataValueTextFieldDocumentListener(new MetadataValueTextFieldDocumentListener());
+	metadata_value_table_pane.addMetadataValueTextFieldKeyListener(new MetadataValueTextFieldKeyListener());
+    }
+
+
+    /** Some actions can only occur after this panel has been displayed on-screen, so this method is provided to do exactly that. Such actions include the proportioning of the split panes and the setting of table column widths.
+     */
+    public void afterDisplay()
+    {
+	external_split.setDividerLocation(0.3);
+    }
+
+
+    /** Used to create, connect and layout the components to be shown on this control panel.
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.file.FileOpenActionListener
+     * @see org.greenstone.gatherer.gui.Filter
+     */
+    public void display()
+    {
+	// Creation
+	JPanel collection_pane = new JPanel(new BorderLayout());
+	collection_pane.setMinimumSize(MINIMUM_SIZE);
+	collection_pane.setPreferredSize(COLLECTION_TREE_SIZE);
+
+	external_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+
+	collection_label = new JLabel();
+	Dictionary.registerText(collection_label, "Collection.No_Collection");
+	collection_label.setOpaque(true);
+
+	DragGroup group = new DragGroup();
+	collection_tree = new CollectionTree("Enrich", Gatherer.c_man.getCollectionTreeModel(), false);
+	group.add(collection_tree);
+	collection_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
+	collection_tree.putClientProperty("JTree.lineStyle", "Angled");
+	collection_tree.addMouseListener(Gatherer.g_man.foa_listener);
+	collection_tree.addMouseListener(new RightButtonListener());
+	collection_tree.addTreeSelectionListener(this);
+	collection_tree.addTreeExpansionListener(Gatherer.g_man.foa_listener);
+	collection_tree.setBackgroundNonSelectionColor(Configuration.getColor("coloring.collection_tree_background", false));
+	collection_tree.setTextNonSelectionColor(Configuration.getColor("coloring.collection_tree_foreground", false));
+	collection_tree.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
+	collection_tree.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
+	collection_tree.setRootVisible(false);
+
+	KeyListenerImpl key_listener = new KeyListenerImpl();
+	collection_tree.addKeyListener(key_listener);
+	JScrollPane collection_scroll = new JScrollPane(collection_tree);
+
+	collection_filter = Gatherer.g_man.getFilter(collection_tree);
+	collection_filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+	collection_filter.setEditable(Configuration.getMode() > Configuration.LIBRARIAN_MODE);
+	Dictionary.registerTooltip(collection_filter.getComboBox(), "Collection.Filter_Tooltip");
+
+	// Layout
+	collection_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(3,3,3,3), BorderFactory.createLoweredBevelBorder()));
+	collection_pane.setMinimumSize(MINIMUM_SIZE);
+	collection_pane.setPreferredSize(new Dimension(Gatherer.g_man.getSize().width / 3, Gatherer.g_man.getSize().height));
+
+	// Collection Pane
+	collection_pane.add(collection_label, BorderLayout.NORTH);
+	collection_pane.add(collection_scroll, BorderLayout.CENTER);
+	collection_pane.add(collection_filter, BorderLayout.SOUTH);
+
+	JSplitPane metadata_editing_pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+	metadata_editing_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
+	metadata_editing_pane.setDividerSize(8);
+
+	metadata_editing_pane.add(metadata_value_table_pane, JSplitPane.TOP);
+	metadata_editing_pane.add(metadata_value_tree_pane, JSplitPane.BOTTOM);
+	metadata_editing_pane.setDividerLocation(250);
+
+	external_split.add(collection_pane, JSplitPane.LEFT);
+	external_split.add(metadata_editing_pane, JSplitPane.RIGHT);
+
+	this.setLayout(new BorderLayout());
+	this.add(external_split, BorderLayout.CENTER);
+    }
+
+
+    /** Called to inform this pane that it has just gained focus as an effect of the user clicking on its tab
+     */
+    public void gainFocus()
+    {
+	// If there is nothing in the collection tree there is nothing to do
+	if (collection_tree == null || collection_tree.getRowCount() == 0) {
+	    return;
+	}
+
+	// Select the first node in the tree if nothing is already selected
+	if (collection_tree.getSelectionPaths() == null) {
+ 	    collection_tree.setImmediate(true);
+ 	    collection_tree.setSelectionRow(0);
+ 	    collection_tree.setImmediate(false);
+	    return;
+	}
+
+	// Force all of the controls to be updated
+	valueChanged(null);
+    }
+
+
+    /** Called to inform this pane that it has just lost focus as an effect of the user clicking on another tab
+     */
+    public void loseFocus()
+    {
+	// Nothing to do
+    }
+
+
+    /** 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);
+    }
+
+
+    /** Refresh this pane, depending on what has just happened (refresh_reason). */
+    public void refresh(int refresh_reason, boolean collection_loaded)
+    {
+	if (collection_loaded) {
+	    // Update collection label
+	    Dictionary.registerText(collection_label, "Collection.Collection");
+	    collection_label.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+	    collection_label.setForeground(Configuration.getColor("coloring.collection_heading_foreground", false));
+
+	    // Update collection tree
+	    if (refresh_reason == Gatherer.COLLECTION_OPENED) {
+		collection_tree.setModel(Gatherer.c_man.getCollectionTreeModel());
+	    }
+
+	    // Update collection filter
+	    collection_filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+	}
+	else {
+	    // Update collection label
+	    Dictionary.registerText(collection_label, "Collection.No_Collection");
+	    collection_label.setBackground(Color.lightGray);
+	    collection_label.setForeground(Color.black);
+
+	    // Update collection tree
+	    collection_tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("Error")));
+
+	    // Update collection filter
+	    collection_filter.setBackground(Color.lightGray);
+	}
+
+	// Enable or disable the controls
+	collection_tree.setEnabled(collection_loaded);
+	collection_filter.setEnabled(collection_loaded);
+
+	// Ensure that this collection tree view is synchronized with all others
+	collection_tree_sync.add(collection_tree);
+
+	// Force the metadata table to be rebuilt (for switching extracted metadata on or off)
+	if (refresh_reason == Gatherer.PREFERENCES_CHANGED) {
+	    metadata_value_table_pane.stopEditingAndRebuild(file_nodes);
+	}
+    }
+
+
+    /** Called whenever the collection tree selection changes. This causes the metadata value table to be rebuilt. */
+    public void valueChanged(TreeSelectionEvent event)
+    {
+	// Nothing selected in the collection tree
+	if (collection_tree.getSelectionCount() == 0) {
+	    file_nodes = null;
+	}
+
+	// Some files selected in the collection tree
+	else {
+	    TreePath paths[] = collection_tree.getSelectionPaths();
+	    file_nodes = new CollectionTreeNode[paths.length];
+	    for (int i = 0; i < paths.length; i++) {
+		file_nodes[i] = (CollectionTreeNode) paths[i].getLastPathComponent();
+	    }
+	}
+
+	// Update the metadata value table (and consequently, the metadata value tree)
+	metadata_value_table_pane.stopEditingAndRebuild(file_nodes);
+    }
+
+
+    private class MetadataValueTableListSelectionListener
+	implements ListSelectionListener
+    {
+	public void valueChanged(ListSelectionEvent list_selection_event)
+	{
+	    // We only want to handle one event per selection, so wait for the value to stabilise
+	    if (list_selection_event.getValueIsAdjusting()) {
+		return;
+	    }
+
+	    // Update the metadata value tree for the current table selection
+	    metadata_value_tree_pane.rebuild(metadata_value_table_pane.getSelectedMetadataValueTableEntry());
+	}
+    }
+
+
+    private class MetadataValueTableMouseListener
+	extends MouseAdapter
+    {
+	public void mouseClicked(MouseEvent mouse_event)
+	{
+	    // We're only interested in clicks on the inherited column
+	    if (metadata_value_table_pane.isMouseEventForInheritedMetadataValueTableColumn(mouse_event) == false) {
+		return;
+	    }
+
+	    // If the selected metadata is inherited, switch to the folder it came from
+	    MetadataValueTableEntry selected_metadata_value_table_entry = metadata_value_table_pane.getSelectedMetadataValueTableEntry();
+	    if (selected_metadata_value_table_entry.isInheritedMetadata()) {
+		collection_tree.setSelection(selected_metadata_value_table_entry.getFolderMetadataInheritedFrom());
+	    }
+	}
+    }
+
+
+    private class MetadataValueTextFieldDocumentListener
+	implements DocumentListener
+    {
+	/** Gives notification that an attribute or set of attributes changed */
+	public void changedUpdate(DocumentEvent document_event) {
+	    validate(document_event);
+	}
+
+	/** Gives notification that there was an insert into the document */
+	public void insertUpdate(DocumentEvent document_event) {
+	    validate(document_event);
+	}
+
+	/** Gives notification that a portion of the document has been removed */
+	public void removeUpdate(DocumentEvent document_event) {
+	    validate(document_event);
+	}
+
+
+	/** Ensures that the value tree is updated in response to changes in the value text field */
+	private void validate(DocumentEvent document_event)
+	{
+	    try {
+		Document document = document_event.getDocument();
+		String metadata_value_string = document.getText(0, document.getLength());
+		metadata_value_tree_pane.selectBestPathForMetadataValue(metadata_value_string);
+	    }
+	    catch (Exception exception) {
+		DebugStream.printStackTrace(exception);
+	    }
+	}
+    }
+
+
+    private class MetadataValueTextFieldKeyListener
+	extends KeyAdapter
+    {
+	/** Gives notification of key events on the text field */
+	public void keyPressed(KeyEvent key_event)
+	{
+	    // Tab: Auto-complete what is selected in the metadata value tree
+	    if (key_event.getKeyCode() == KeyEvent.VK_TAB) {
+		MetadataValueTreeNode selected_metadata_value_tree_node = metadata_value_tree_pane.getSelectedMetadataValueTreeNode();
+		if (selected_metadata_value_tree_node != null) {
+		    metadata_value_table_pane.setMetadataValueTextFieldValue(selected_metadata_value_tree_node.getFullValue());
+		}
+
+		// We do not want this event to be processed by the table also
+		key_event.consume();
+	    }
+
+	    // Enter: save the current value then add a blank row for the selected metadata element
+	    if (key_event.getKeyCode() == KeyEvent.VK_ENTER) {
+		metadata_value_table_pane.stopEditingAndAddBlankRowForSelectedMetadataElement();
+	    }
+	}
+    }
+
+
+    private class MetadataValueTreeSelectionListener
+	implements TreeSelectionListener
+    {
+	public void valueChanged(TreeSelectionEvent tree_selection_event)
+	{
+	    // When a node is selected in the tree, fill the metadata value text field with the selected node's value
+	    MetadataValueTreeNode selected_metadata_value_tree_node = metadata_value_tree_pane.getSelectedMetadataValueTreeNode();
+	    if (selected_metadata_value_tree_node != null) {
+		metadata_value_table_pane.setMetadataValueTextFieldValue(selected_metadata_value_tree_node.getFullValue());
+	    }
+	}
+    }
+
+
+    /** This class listens for certain key presses, such as [Up] or [Down], -copied from Gather Pane */
+    private class KeyListenerImpl
+	extends KeyAdapter {
+	private boolean vk_left_pressed = false;
+	/** Called whenever a key that was pressed is released, it is this action that will cause the desired effects (this allows for the key event itself to be processed prior to this listener dealing with it). */
+	public void keyReleased(KeyEvent event) {
+	    ///ystem.err.println("Key Release detected. " + event.getKeyCode());
+	    if (event.getKeyCode() == KeyEvent.VK_UP || event.getKeyCode() == KeyEvent.VK_DOWN) {
+		DragTree tree = (DragTree)event.getSource();
+		// we need to manually do the up and down selections
+		boolean up = (event.getKeyCode() == KeyEvent.VK_UP);
+		int current_row = tree.getLeadSelectionRow();
+		tree.setImmediate(true);
+		if (up) {
+		    if (current_row > 0) {
+			tree.clearSelection();
+			tree.setSelectionRow(current_row-1);
+		    }
+		} else {
+		    if (current_row < tree.getRowCount()-1){
+			tree.clearSelection();
+			tree.setSelectionRow(current_row+1);
+		    }
+		}
+		tree.setImmediate(false);
+	    }
+	    else if (event.getKeyCode() == KeyEvent.VK_LEFT) {
+		// left key on a file shifts the selection to the parent folder
+		DragTree tree = (DragTree)event.getSource();
+		TreePath path = tree.getLeadSelectionPath();
+		if(path != null) {
+		    File file = ((CollectionTreeNode) path.getLastPathComponent()).getFile();
+		    if(file != null) {
+			if (file.isFile() || vk_left_pressed) {
+			    vk_left_pressed = false;
+			    TreePath parent_path = path.getParentPath();
+			    if (parent_path != null && parent_path.getParentPath() != null) {
+				// if this file is in the top level folder, don't move the focus 
+				tree.setImmediate(true);
+				tree.clearSelection();
+				tree.setSelectionPath(parent_path);
+				tree.setImmediate(false);
+			    }
+			}
+		    }
+		}
+	    }	    
+	}
+
+	// we need to watch for left clicks on an unopened folder - should shift the focus to teh 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) {
+		// left key on  closed directory shifts the selection to the parent folder
+		DragTree tree = (DragTree)event.getSource();
+		TreePath path = tree.getLeadSelectionPath();
+		if(path == null) return; 
+		File file = ((CollectionTreeNode) path.getLastPathComponent()).getFile();
+		if(file == null) return;
+		
+		if (file.isDirectory() && tree.isCollapsed(path)) {
+		    vk_left_pressed = true;
+		}		
+	    }
+	}
+    }
+
+
+    /** A listener for right mouse button clicks over the collection tree. */
+    private class RightButtonListener
+	extends MouseAdapter {
+	/** Called whenever a mouse click occurs (right or left) over a target component.
+	 * @param event A <strong>MouseEvent</strong> containing further information about the mouse click action.
+	 * @see org.greenstone.gatherer.gui.EnrichPane.RightButtonMenu
+	 */
+	public void mouseClicked(MouseEvent event) {
+	    if (SwingUtilities.isRightMouseButton(event)) {
+		new RightButtonMenu(event);
+	    }
+	}
+    }
+
+
+    /** When a user right-clicks within the collection tree they are presented with a small popup menu of context based options. This class provides such functionality.
+     */
+    private class RightButtonMenu
+	extends JPopupMenu
+	implements ActionListener {
+
+	/** The tree over which the right click action occurred. */
+	private DragTree tree = null;
+	/** The tree nodes selected when the right click action occurred. */
+	private TreePath[] selection_paths = null;
+	/** The file record over which the right click action occurred. */
+	private CollectionTreeNode node = null;
+
+	private JMenuItem collapse_folder = null;
+	private JMenuItem expand_folder = null;
+	private JMenuItem metaaudit = null;
+	private JMenuItem open_externally = null;
+
+
+	private RightButtonMenu(MouseEvent event)
+	{
+	    super();
+	    this.tree = collection_tree;
+
+	    // Note we have to use setImmediate() with the set selction paths
+	    // otherwise the selection doesn't get updated until after the 
+	    // popup comes up.
+
+	    // the right click position
+	    TreePath right_click_path = tree.getPathForLocation(event.getX(), event.getY());
+	    if (right_click_path == null) {
+		// user has clicked outside of the tree, clear the selection
+		selection_paths = null;
+		tree.setImmediate(true);
+		tree.clearSelection();
+		tree.setImmediate(false);
+	    } else {
+		// Get the paths currently selected in the tree
+		selection_paths = tree.getSelectionPaths();
+		if (selection_paths == null) {
+		    // nothing currently selected - we shift the selection to 
+		    // the node that was right clicked on
+		    selection_paths = new TreePath[1];
+		    selection_paths[0] = right_click_path;
+		    tree.setImmediate(true);
+		    tree.setSelectionPath(right_click_path);
+		    tree.setImmediate(false);
+		} else if (selection_paths.length == 1 && ! selection_paths[0].equals( right_click_path)) {
+		    tree.setImmediate(true);
+		    tree.clearSelection();
+		    tree.setSelectionPath(right_click_path);
+		    tree.setImmediate(false);
+		    selection_paths[0] = right_click_path;
+		} else {
+		    // we had multiply selected paths in the tree.
+		    // if we clicked on one of those paths, then use all the 
+		    // current selection, otherwise clear the selection and 
+		    // select the one we right clicked on
+		    boolean clicked_in_selection = false;
+		    for (int i=0; i<selection_paths.length; i++) {
+			if (selection_paths[i].equals(right_click_path)) {
+			    clicked_in_selection = true;
+			    break;
+			}
+		    }
+		    if (!clicked_in_selection) {
+			// want the tree to update right away
+			tree.setImmediate(true);
+			tree.clearSelection();
+			tree.setSelectionPath(right_click_path);
+			tree.setImmediate(false);
+			selection_paths = new TreePath[1];
+			selection_paths[0] = right_click_path;
+		    }
+		}
+	    }
+	    // finally we have the correct selection paths!
+
+	    // Create an appropriate context menu, based on what is selected
+	    buildContextMenu(selection_paths);
+
+	    // Show the popup menu on screen
+	    show(tree, event.getX(), event.getY());
+	}
+
+
+	private void buildContextMenu(TreePath[] selection_paths)
+	{
+	    // If nothing is selected, no options are available
+	    if (selection_paths == null) {
+		return;
+	    }
+
+	    DebugStream.println("Number of files/folders selected: " + selection_paths.length);
+
+	    // Always have meta-audit option
+	    metaaudit = new JMenuItem(Dictionary.get("Menu.Metadata_View", collection_tree.getSelectionDetails()), KeyEvent.VK_A);
+	    metaaudit.addActionListener(this);
+	    add(metaaudit);
+
+	    // Only meta-audit is available if multiple items are selected...
+	    if (selection_paths.length > 1) {
+		return;
+	    }
+
+	    TreePath path = selection_paths[0];
+	    node = (CollectionTreeNode) path.getLastPathComponent();
+
+	    // ---- Options for file nodes ----
+	    if (node.isLeaf()) {
+		// Open the file in an external program
+		open_externally = new JMenuItem(Dictionary.get("Menu.Open_Externally"), KeyEvent.VK_O);
+		open_externally.addActionListener(this);
+		add(open_externally);
+		return;
+	    }
+
+	    // ---- Options for folder nodes ----
+	    // Collapse or expand, depending on current status
+	    if (tree.isExpanded(path)) {
+		collapse_folder = new JMenuItem(Dictionary.get("Menu.Collapse"), KeyEvent.VK_C);
+		collapse_folder.addActionListener(this);
+		add(collapse_folder);
+	    }
+	    else {
+		expand_folder = new JMenuItem(Dictionary.get("Menu.Expand"), KeyEvent.VK_O);
+		expand_folder.addActionListener(this);
+		add(expand_folder);
+	    }
+	}
+
+
+	/** Called whenever one of the menu items is clicked, this method then causes the appropriate effect. */
+	public void actionPerformed(ActionEvent event)
+	{
+	    Object source = event.getSource();
+
+	    // Collapse folder
+	    if (source == collapse_folder) {
+		tree.collapsePath(selection_paths[0]);
+	    }
+
+	    // Expand folder
+	    else if (source == expand_folder) {
+		tree.expandPath(selection_paths[0]);
+	    }
+
+	    // Meta-audit
+	    else if (source == metaaudit) {
+		Gatherer.g_man.showMetaAuditBox();
+	    }
+
+	    // Open in external program
+	    else if (source == open_externally) {
+		Gatherer.f_man.openFileInExternalApplication(node.getFile());
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ExplodeMetadataPrompt.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ExplodeMetadataPrompt.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ExplodeMetadataPrompt.java	(revision 10506)
@@ -0,0 +1,311 @@
+/**
+ *#########################################################################
+ *
+ * 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: Katherine Don, Greenstone Digital Library, University of Waikato
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *########################################################################
+ */
+package org.greenstone.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import java.io.*;
+import java.util.ArrayList;
+
+import org.w3c.dom.Document;
+
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.LocalGreenstone;
+import org.greenstone.gatherer.cdm.Argument;
+import org.greenstone.gatherer.cdm.CollectionDesignManager;
+import org.greenstone.gatherer.cdm.Plugin;
+import org.greenstone.gatherer.collection.ScriptOptions;
+import org.greenstone.gatherer.gui.tree.DragTree;
+import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.metadata.MetadataTools;
+import org.greenstone.gatherer.shell.GShell;
+import org.greenstone.gatherer.shell.GShellEvent;
+import org.greenstone.gatherer.shell.GShellListener;
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.XMLTools;
+
+public class ExplodeMetadataPrompt	
+    extends ModalDialog
+    implements GShellListener
+{
+    /** The size of this new collection dialog box. */
+    static private Dimension SIZE = new Dimension(600, 350);
+    private JDialog self;
+    
+    /** the file we wil be exploding */
+    private File metadata_file = null;
+    /** the name of the plugin to be used */
+    private String plugin_name = null;
+    /** holds all the available options for the exploding script */
+    private ScriptOptions options = null;
+    /** the pane containing the options */
+    private JPanel options_pane = null;
+    /** the error message if any */
+    private StringBuffer error_message = null;
+    /** whether we were successful or not */
+    private boolean successful;
+
+
+    public ExplodeMetadataPrompt(File source_file) {
+	super(Gatherer.g_man, true);
+	this.self = this;
+	this.metadata_file = source_file;
+
+	// check that we actually have an explodable file
+	Plugin plugin = CollectionDesignManager.plugin_manager.getExploderPlugin(source_file);
+	if (plugin==null) {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("ExplodeMetadataPrompt.NotExplodable"), Dictionary.get("ExplodeMetadataPrompt.Title"), JOptionPane.ERROR_MESSAGE);
+	    return;
+	}
+	plugin_name = plugin.getName();
+	setJMenuBar(new SimpleMenuBar("explodingmetadata"));
+	setSize(SIZE);
+	Dictionary.setText(this, "ExplodeMetadataPrompt.Title");
+
+	// set up the script options
+	// we have empty initial values
+	String dom_string = "<Options/>";
+	Document doc = XMLTools.parseXML(new StringReader(dom_string));
+	options = new ScriptOptions(doc.getDocumentElement(), "explode_metadata_database.pl", false);
+	
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+	content_pane.setOpaque(true);
+	
+	options_pane = new JPanel();
+	addScriptOptions(options_pane);
+	JScrollPane middle_pane = new JScrollPane(options_pane);
+
+	JTextArea instructions_area = new JTextArea();
+	instructions_area.setEditable(false);
+	instructions_area.setLineWrap(true);
+	instructions_area.setRows(5);
+	instructions_area.setWrapStyleWord(true);
+	Dictionary.setText(instructions_area, "ExplodeMetadataPrompt.Instructions");
+
+	JPanel button_pane = new JPanel();
+	JButton explode_button = new GLIButton();
+	Dictionary.setBoth(explode_button, "ExplodeMetadataPrompt.Explode", "ExplodeMetadataPrompt.Explode_Tooltip");
+	JButton cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Cancel", "General.Cancel_Tooltip");
+	
+	// Connection
+	cancel_button.addActionListener(new CancelListener());
+	explode_button.addActionListener(new ExplodeListener());
+
+	// Layout
+
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	button_pane.setLayout(new GridLayout(1,2));
+	button_pane.add(explode_button);
+	button_pane.add(cancel_button);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(instructions_area, BorderLayout.NORTH);
+	content_pane.add(middle_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	// Final dialog setup & positioning.
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	setVisible(true);
+    }
+
+    public void destroy() 
+    {
+       	
+    }
+
+    /** All implementation of GShellListener must include this method so the listener can be informed of messages from the GShell.
+     * @param event A <strong>GShellEvent</strong> that contains, amoung other things, the message.
+     */
+    public synchronized void message(GShellEvent event) {
+	String message = event.getMessage();
+	if (message.startsWith("explode_metadata_database.pl>")) {
+	    message = message.substring(6);
+	    error_message.append(message);
+	    error_message.append("\n");
+	}
+    }
+
+    /** All implementation of GShellListener must include this method so the listener can be informed when a GShell begins its task. Implementation side-effect, not actually used.
+     * @param event A <strong>GShellEvent</strong> that contains details of the initial state of the <strong>GShell</strong> before task comencement.
+     */
+    public synchronized void processBegun(GShellEvent event) {
+	// We don't care. 
+    }
+    
+    /** All implementation of GShellListener must include this method so the listener can be informed when a GShell completes its task.
+     * @param event A <strong>GShellEvent</strong> that contains details of the final state of the <strong>GShell</strong> after task completion.
+     */
+    public synchronized void processComplete(GShellEvent event) {
+	successful = false;
+	if(event.getStatus() == GShell.OK) {
+	    successful = true;
+	}
+    }
+
+    private void addScriptOptions(JPanel options_pane) {
+
+	options_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	options_pane.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+	options_pane.setLayout(new BoxLayout(options_pane, BoxLayout.Y_AXIS));
+
+	int current_mode = Configuration.getMode();
+	int total_argument_count = options.getArgumentCount();
+       
+	for(int i = 0; i < total_argument_count; i++) {
+	    // Retrieve the argument so we know how to format the control.
+	    Argument argument = options.getArgument(i);
+	    if(!argument.isHiddenGLI() && argument.getModeLevel() <= current_mode) {
+		// by default, all args are disabled, and no value
+		ArgumentControl argument_control = new ArgumentControl(argument,false, null);
+		// make sure they are coloured the way we want - this is not the standard arg control coloring
+		argument_control.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+		options_pane.add((JComponent)argument_control);
+	    }
+	}
+    }
+
+    private void updateScriptOptions() {
+	for(int i = 0; i < options_pane.getComponentCount(); i++) {
+	    Component component = options_pane.getComponent(i);
+	    if(component instanceof ArgumentControl) {
+		ArgumentControl ac = (ArgumentControl)component;
+		String name = ac.getName();
+		String value = ac.getValue();
+		boolean enabled = ac.isEnabled();
+		if (!enabled && value==null) {
+		    // flag type, remove from options altogether
+		    options.removeValue(name);
+		} else {
+		    if (value.equals("")) {
+			// if the value is empty, we don't want it to be passed to the script
+			options.setValue(name, false, value);
+		    } else {
+			options.setValue(name, enabled, value);
+		    }
+		}
+
+	    }
+	}
+    }
+
+    private int explodeMetadata()
+    {
+	if (Gatherer.isGsdlRemote) {
+	    // !! TO DO
+	    return -1;
+	}
+
+	// Generate the explode_metadata_database.pl command
+	ArrayList command_parts_list = new ArrayList();
+	if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
+	    command_parts_list.add(Configuration.perl_path);
+	    command_parts_list.add("-S");
+	}
+	command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "explode_metadata_database.pl");
+	command_parts_list.add("-plugin");
+	command_parts_list.add(plugin_name);
+
+	// Add in all the options from the user
+	String[] explode_options = options.getValues();
+	for (int i = 0; i < explode_options.length; i++) {
+	    command_parts_list.add(explode_options[i]);
+	}
+
+	// Add in the filename
+	command_parts_list.add(metadata_file.getPath());
+
+	// Run the explode_metadata_database.pl command
+	String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
+	this.error_message = new StringBuffer();
+	GShell process = new GShell(command_parts, GShell.EXPLODE, 3, this, null, GShell.GSHELL_EXPLODE);
+	//process.start();
+	process.run();
+	
+	if (successful) {
+	    return 0;
+	} 
+	return -1;
+    }
+
+    private void resultPrompt(boolean success, String message)
+    {
+	if (success) {
+	    // !!! TO DO: Get explode_metadata_database.pl strings translated and use SimpleResultDialog below
+	    JOptionPane.showMessageDialog(null, Dictionary.get("ExplodeMetadataPrompt.Successful_Explode", metadata_file.getName()), Dictionary.get("ExplodeMetadataPrompt.Successful_Title"), JOptionPane.INFORMATION_MESSAGE);
+	}
+	else {
+	    String title = Dictionary.get("ExplodeMetadataPrompt.Failed_Title");
+	    String label = Dictionary.get("ExplodeMetadataPrompt.Failed_Explode", metadata_file.getName());
+	    SimpleResultDialog result_dialog = new SimpleResultDialog(title, label, message);
+	    result_dialog.setVisible(true); // Blocks
+	    result_dialog.dispose();
+	    result_dialog = null;
+	}
+    }
+
+    private class CancelListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    self.dispose();
+	}
+    }
+    
+    private class ExplodeListener
+	implements ActionListener {
+	
+	public void actionPerformed(ActionEvent event) {
+	    // update the options
+	    updateScriptOptions();
+	    int exit_value = explodeMetadata();
+	    if (exit_value == 0) { // success
+		String new_dir = metadata_file.getPath();
+		// remove the extension to get the directory name
+		new_dir = new_dir.substring(0, new_dir.lastIndexOf('.'));
+		MetadataXMLFileManager.loadMetadataXMLFiles(new File(new_dir));
+		Gatherer.g_man.refreshCollectionTree(DragTree.COLLECTION_CONTENTS_CHANGED);
+		resultPrompt(true, error_message.toString());
+	    } else { // failure
+		resultPrompt(false, error_message.toString());
+	    }
+	    error_message = null;
+	    self.dispose();  
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ExportAsPrompt.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ExportAsPrompt.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ExportAsPrompt.java	(revision 10506)
@@ -0,0 +1,575 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.LocalGreenstone;
+import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
+import org.greenstone.gatherer.shell.GShell;
+import org.greenstone.gatherer.shell.GShellEvent;
+import org.greenstone.gatherer.shell.GShellListener;
+import org.greenstone.gatherer.util.ArrayTools;
+import org.greenstone.gatherer.util.CheckList;
+import org.greenstone.gatherer.util.CheckListEntry;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+/** This class provides the functionality to export a set of current
+ * collections from the GSDLHOME/collect/ directory to various formats
+ * (hence ExportAs) using export.pl. 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.  
+ * Copied from WriteCDImagePrompt
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class ExportAsPrompt
+    extends ModalDialog 
+    implements GShellListener {
+
+    static final private Dimension LABEL_SIZE = new Dimension(120, 25);
+    
+    private OKButtonListener ok_button_listener;
+
+    private JLabel saveas_label = null;
+    private JComboBox saveas_combobox = null;
+
+    private ArrayList all_collections = null;
+    private ArrayList selected_collections = null;
+    /** The list of collections to include in exported cd-rom/dvd image */
+    private CheckList list = null;
+    /** The currently selected collection for deletion. */
+    private BasicCollectionConfiguration collection = null;
+    /** A reference to ourself so any inner-classes can dispose of us. */
+    private ExportAsPrompt prompt = null;
+    /** The close button, which exits the prompt without deleting anything. */
+    private JButton cancel_button = null;
+    /** The ok button which causes the selected collection to be deleted. */
+    private JButton ok_button = null;
+    /** The label above details. */
+    private JLabel details_label = null;
+    /** The label above the list. */
+    private JLabel list_label = null;
+    /** The text area used to display details about the collection selected. */
+    private JTextArea details_textarea = null;
+    /** The text area used to display instructions for the cd-rom/dvd export */
+    private JTextArea instructions_textarea;
+    /** A string array used to pass arguments to the phrase retrieval method. */
+    private JTextField title_field = null;
+    private JLabel title_label = null;
+    private String args[] = null;
+    private String cd_title = null;
+    /** whether the exporting was successful or not */
+    private boolean successful = false;
+    /** whether we are trying to export or not */
+    private boolean exporting = false;
+    /** the error message if any */
+    private StringBuffer error_message = null;
+    /** The size of the export prompt screen. */
+    public static final Dimension SIZE = new Dimension(500, 500);
+
+    /** Constructor.
+     * @see org.greenstone.gatherer.collection.ExportAsPrompt.CancelButtonListener
+     * @see org.greenstone.gatherer.collection.ExportAsPrompt.CollectionListListener
+     * @see org.greenstone.gatherer.collection.ExportAsPrompt.OKButtonListener
+     */
+    public ExportAsPrompt() {
+	super(Gatherer.g_man, true);
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Close", "General.Close_Tooltip");
+	details_textarea = new JTextArea();
+	details_textarea.setEditable(false);
+	Dictionary.setText(details_textarea, "DeleteCollectionPrompt.No_Collection");
+	details_label = new JLabel();
+	Dictionary.setText(details_label, "DeleteCollectionPrompt.Collection_Details");
+
+	instructions_textarea = new JTextArea();
+	instructions_textarea.setCaretPosition(0);
+	instructions_textarea.setEditable(false);
+	instructions_textarea.setLineWrap(true);
+	instructions_textarea.setRows(4);
+	instructions_textarea.setWrapStyleWord(true);
+	Dictionary.registerText(instructions_textarea, "ExportAsPrompt.Instructions");
+
+        // Save As
+	ArrayList saveas_formats = new ArrayList();
+	saveas_formats.add("METS");
+	saveas_formats.add("DSpace");
+
+        saveas_label = new JLabel();
+        //saveas_label.setPreferredSize(LABEL_SIZE);
+        Dictionary.registerText(saveas_label, "ExportAsPrompt.SaveAs");
+        saveas_combobox = new JComboBox(saveas_formats.toArray());
+        Dictionary.registerTooltip(saveas_combobox, "ExportAsPrompt.SaveAs_Tooltip");
+
+	all_collections = new ArrayList();
+	list = new CheckList(true);
+	list_label = new JLabel();
+	Dictionary.setText(list_label, "DeleteCollectionPrompt.Collection_List");
+	ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_D);
+	Dictionary.setBoth(ok_button, "ExportAsPrompt.Export", "ExportAsPrompt.Export_Tooltip");
+
+	title_field = new JTextField();
+	// Dictionary.setTooltip(title_field, "ExportAsPrompt.Export_Name_Tooltip");
+	title_label = new JLabel();
+	Dictionary.setText(title_label, "ExportAsPrompt.Export_Name");
+	scanForCollections();
+	list.setListData(all_collections);
+
+	prompt = this;
+	setSize(SIZE);
+	Dictionary.setText(this, "ExportAsPrompt.Title");
+
+	setJMenuBar(new SimpleMenuBar("0")); // need to find an appropriate help page to open at
+	cancel_button.addActionListener(new CancelButtonListener());
+	list.addListSelectionListener(new CollectionListListener());
+	list.clearSelection();
+	list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	ok_button_listener = new OKButtonListener();
+	ok_button.addActionListener(ok_button_listener);
+	ok_button.setEnabled(false);
+	//title.getDocument().addDocumentListener(new DocumentListener());
+    }
+
+    /** Destructor. */
+    public void destroy() {
+        saveas_label = null;
+	saveas_combobox = null;
+	all_collections.clear();
+	all_collections = null;
+	cancel_button = null;
+	details_textarea = null;
+	details_label = null;
+	list = null;
+	ok_button = null;
+	prompt = null;
+	if (selected_collections!=null) {
+	    selected_collections.clear();
+	    selected_collections = null;
+	}
+	title_field = null;
+	title_label = null;
+    }
+
+    /** This method causes the modal prompt to be displayed. 
+     * returns true if it has exported the collections that are currently selected */
+    public boolean display() {
+	// Top pane
+	JPanel instructions_pane = new JPanel(new BorderLayout());
+	instructions_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	instructions_pane.add(new JScrollPane(instructions_textarea), BorderLayout.CENTER);
+	
+	title_label.setBorder(BorderFactory.createEmptyBorder(0,5,0,15));
+
+	JPanel title_pane = new JPanel(new BorderLayout());
+	title_pane.add(title_label, BorderLayout.WEST);
+	title_pane.add(title_field, BorderLayout.CENTER);
+	instructions_pane.add(title_pane, BorderLayout.CENTER);
+
+	// Save as pane
+	JPanel saveas_pane = new JPanel(new BorderLayout());
+	saveas_pane.setLayout(new BorderLayout());
+	saveas_pane.add(saveas_label, BorderLayout.WEST);
+	saveas_pane.add(saveas_combobox, BorderLayout.CENTER);
+	instructions_pane.add(saveas_pane, BorderLayout.SOUTH);
+
+	// Central pane
+	JPanel list_pane = new JPanel(new BorderLayout());
+	list_pane.add(list_label, BorderLayout.NORTH);
+	list_pane.add(new JScrollPane(list), BorderLayout.CENTER);
+	list_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
+
+	JPanel details_pane = new JPanel(new BorderLayout());
+	details_pane.add(details_label, BorderLayout.NORTH);
+	details_pane.add(new JScrollPane(details_textarea), BorderLayout.CENTER);
+	details_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+
+	JPanel central_pane = new JPanel(new GridLayout(2, 1));
+	central_pane.add(list_pane);
+	central_pane.add(details_pane);
+	central_pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+	// Lower pane
+	JPanel button_pane = new JPanel(new GridLayout(1, 2));
+	button_pane.add(ok_button);
+	button_pane.add(cancel_button);
+	button_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+
+	JPanel lower_pane = new JPanel(new BorderLayout());
+	lower_pane.add(button_pane, BorderLayout.SOUTH);
+	lower_pane.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
+
+	// Final.
+	JPanel content_pane = (JPanel)this.getContentPane();
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(instructions_pane, BorderLayout.NORTH);
+	content_pane.add(central_pane, BorderLayout.CENTER);
+	content_pane.add(lower_pane, BorderLayout.SOUTH);
+
+	// Center and display.
+	Dimension screen_size = Configuration.screen_size;
+	this.setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	this.setVisible(true); // blocks until the dialog is killed
+	return true;
+	
+    }
+
+    
+    /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.Collection
+     * @see org.greenstone.gatherer.gui.BuildOptions
+     * @see org.greenstone.gatherer.shell.GShell
+     * @see org.greenstone.gatherer.shell.GShellListener
+     * @see org.greenstone.gatherer.shell.GShellProgressMonitor
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    public void exportAsCollections() {
+	DebugStream.println("ExportAsPrompt.exportAsCollections()");
+
+	int num_collections = selected_collections.size();
+	if (num_collections == 0) return;
+	cd_title = title_field.getText();
+	cd_title = cd_title.trim();
+	cd_title = cd_title.replaceAll("\"", "");
+
+	String export_type = (String) saveas_combobox.getSelectedItem();
+
+	// Generate the export.pl command
+	ArrayList command_parts_list = new ArrayList();
+	if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
+	    command_parts_list.add(Configuration.perl_path);
+	    command_parts_list.add("-S");
+	}
+	command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "export.pl");
+	command_parts_list.add("-gli");
+	command_parts_list.add("-language");
+	command_parts_list.add(Configuration.getLanguage());
+	command_parts_list.add("-removeold");
+	command_parts_list.add("-saveas");
+	command_parts_list.add(export_type);
+	command_parts_list.add("-exportdir");
+	command_parts_list.add(LocalGreenstone.getTmpDirectoryPath());
+
+	if (cd_title.equals("")) {
+	    command_parts_list.add("exported_" + export_type);
+	}
+	else {
+	    command_parts_list.add("exported_" + cd_title.replaceAll("\\s", ""));
+	}
+	
+	for (int i = 0; i < num_collections; i++) {
+	    command_parts_list.add(((BasicCollectionConfiguration) selected_collections.get(i)).getShortName());
+	}
+
+	DebugStream.print("export command = ");
+	for (int i = 0; i < command_parts_list.size(); i++) {
+	    DebugStream.print(command_parts_list.get(i) + " ");
+	    System.err.print(command_parts_list.get(i) + " ");
+	}
+	DebugStream.println("");
+	System.err.println("");
+
+	// Run the export.pl command
+	String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
+	GShell process = new GShell(command_parts, GShell.EXPORTAS, 3, this, null, GShell.GSHELL_EXPORTAS);
+	process.start();
+	//process.run();
+	DebugStream.println("ExportAsPrompt.exportAsCollections().return");
+	
+    }
+
+    /** Shows an export 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, String extra) {
+	args = new String[2];
+	StringBuffer coll_names = new StringBuffer();
+	for (int i=0; i<selected_collections.size();i++) {
+	    if (i>0) {
+		coll_names.append(", ");
+	    }
+	    BasicCollectionConfiguration complete_collection = (BasicCollectionConfiguration)selected_collections.get(i);
+	    coll_names.append(complete_collection.getName() + StaticStrings.SPACE_CHARACTER + StaticStrings.OPEN_PARENTHESIS_CHARACTER + complete_collection.getShortName() + StaticStrings.CLOSE_PARENTHESIS_CHARACTER);
+	    complete_collection = null;
+	}
+	
+	args[0] = coll_names.toString();
+
+	args[1] = LocalGreenstone.getTmpDirectoryPath();
+	if(cd_title.equals("")) {
+	    String export_type = (String)saveas_combobox.getSelectedItem();
+	    args[1] += "exported_" + export_type;
+	} else {
+	    args[1] += "exported_"+cd_title.replaceAll("\\s","");
+	}
+
+	String title;
+	String label;
+	String details;
+
+	if (success) {
+	    String successMessage
+		= (selected_collections.size()==1) 
+		? "ExportAsPrompt.Successful_ExportOne"
+		: "ExportAsPrompt.Successful_ExportMany";
+
+	    title = Dictionary.get("ExportAsPrompt.Successful_Title");
+	    label = Dictionary.get(successMessage, args);
+	    details = Dictionary.get("ExportAsPrompt.Successful_Details", args);
+	} else {
+	    String failedMessage
+		= (selected_collections.size()==1) 
+		? "ExportAsPrompt.Failed_ExportOne"
+		: "ExportAsPrompt.Failed_ExportMany";
+
+	    title = Dictionary.get("ExportAsPrompt.Failed_Title");
+	    label = Dictionary.get(failedMessage, args);
+	    details = Dictionary.get("ExportAsPrompt.Failed_Details", args);
+	}
+	SimpleResultDialog result_dialog = new SimpleResultDialog(title, label, details);
+	result_dialog.setVisible(true); // Blocks
+	result_dialog.dispose();
+	result_dialog = null;
+    }
+
+    /** Method to scan the collect directory retrieving and reloading each collection it finds, while building the list of known collections.
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.util.ArrayTools
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    private void scanForCollections() {
+	// Start at the collect dir.
+	File collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	if (collect_directory.exists()) {
+	    // Now for each child directory see if it contains a .col file and
+	    // if so try to load it..
+	    File collections[] = collect_directory.listFiles();
+	    ArrayTools.sort(collections);
+	    for(int i = 0; collections != null && i < collections.length; i++) {
+		if(collections[i].isDirectory() && !collections[i].getName().equals(StaticStrings.MODEL_COLLECTION_NAME)) {
+		    File config_file = new File(collections[i], Utility.CONFIG_FILE);
+		    if (config_file.exists()) {
+			BasicCollectionConfiguration config = new BasicCollectionConfiguration(config_file);
+			all_collections.add(config);		        
+			config = null;
+		    }
+		}
+	    }
+	}
+	// Otherwise the collect directory doesn't actually exist, so there ain't much we can do.
+    }
+
+
+    /** All implementation of GShellListener must include this method so the listener can be informed of messages from the GShell.
+     * @param event A <strong>GShellEvent</strong> that contains, amoung other things, the message.
+     */
+    public synchronized void message(GShellEvent event) {
+	// Ignore the messages from RecPlug with 'show_progress' set (used for progress bars)
+	String message = event.getMessage();
+	if (message.startsWith("export.pl>")) {
+	    message = message.substring(13);
+	    //DebugStream.println("message = "+event.getMessage());
+	    error_message.append(message);
+	    error_message.append("\n");
+	}
+    }
+
+    /** All implementation of GShellListener must include this method so the listener can be informed when a GShell begins its task. Implementation side-effect, not actually used.
+     * @param event A <strong>GShellEvent</strong> that contains details of the initial state of the <strong>GShell</strong> before task comencement.
+     */
+    public synchronized void processBegun(GShellEvent event) {
+	// We don't care. 
+    }
+    /** All implementation of GShellListener must include this method so the listener can be informed when a GShell completes its task.
+     * @param event A <strong>GShellEvent</strong> that contains details of the final state of the <strong>GShell</strong> after task completion.
+     */
+    public synchronized void processComplete(GShellEvent event) {
+	successful = false;
+	if(event.getStatus() == GShell.OK) {
+	    if(event.getType() == GShell.EXPORTAS) {
+		successful = true;
+	    }
+	}
+	ok_button_listener.processComplete();
+    }
+
+    /** A button listener implementation, which listens for actions on the close button and disposes of the dialog when detected. */
+    private class CancelButtonListener 
+	implements ActionListener {
+	/** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
+	 * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    prompt.dispose();
+	}
+    }
+
+    /** This private class listens for selection events in from the list and then displays the appropriate details for that collection.
+     */
+    private class CollectionListListener 
+	implements ListSelectionListener
+    {
+	/** Any implementation of ListSelectionListener must include this method so we can be informed when the list selection changes.
+	 * @param  event a <strong>ListSelectionEvent</strong> containing all the relevant information garnered from the event itself
+	 */
+	public void valueChanged(ListSelectionEvent event)
+	{
+	    // Can only export when something is ticked
+	    ok_button.setEnabled(!list.isNothingTicked());
+
+	    if (list.isSelectionEmpty()) {
+		// This only happens when the dialog is first entered
+		Dictionary.setText(details_textarea, "DeleteCollectionPrompt.No_Collection");
+		return;
+	    }
+
+	    collection = (BasicCollectionConfiguration) ((CheckListEntry) list.getSelectedValue()).getObject();
+	    args = new String[3];
+	    args[0] = collection.getCreator();
+	    args[1] = collection.getMaintainer();
+	    args[2] = collection.getDescription();
+	    Dictionary.setText(details_textarea, "DeleteCollectionPrompt.Details", args);
+	    details_textarea.setCaretPosition(0);
+	}
+    }
+
+
+    /** The OK button listener implementation. */
+    private class OKButtonListener 
+	implements ActionListener {
+	private Component glass_pane;
+	private MouseListener mouse_blocker_listener;
+	private ProgressDialog progress_dialog;
+
+	/** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
+	 * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
+	 * @see org.greenstone.gatherer.Configuration
+	 * @see org.greenstone.gatherer.Gatherer
+	 * @see org.greenstone.gatherer.util.Utility
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    ///ystem.err.println("OK Clicked");
+	    // Make sure there are some colls specified
+	    selected_collections = list.getTicked();
+	    error_message = new StringBuffer();
+	    
+	    // Set the cursor to hourglass
+	    glass_pane = getGlassPane();
+	    mouse_blocker_listener = new MouseAdapter() {};
+	    glass_pane.addMouseListener(mouse_blocker_listener);
+	    glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+	    glass_pane.setVisible(true);
+
+	    // Export the selected collection.
+	    ///ystem.err.println("Exporting As for named collections");
+	    exportAsCollections();
+
+	    // Show progress dialog
+	    ///ystem.err.println("Showing progress dialog");
+	    progress_dialog = new ProgressDialog();
+	    progress_dialog.setVisible(true);
+	}
+
+	public void processComplete() {
+	    ///ystem.err.println("Process complete");
+	    // Dispose of progress dialog
+	    progress_dialog.setVisible(false);
+	    progress_dialog.dispose();
+	    progress_dialog = null;
+
+	    // unset the cursor
+	    glass_pane.setVisible(false);
+	    glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+	    glass_pane.removeMouseListener(mouse_blocker_listener);
+	    glass_pane = null;
+	    mouse_blocker_listener= null;
+	    
+	    if (successful) {
+		resultPrompt(true, error_message.toString());
+	    } else {
+		resultPrompt(false, error_message.toString());
+	    }
+	    error_message = null;
+	}
+
+	private class ProgressDialog 
+	    extends ModalDialog {
+	    
+	    private Dimension size = new Dimension(400,65);
+	    
+	    public ProgressDialog() {
+		super(Gatherer.g_man, Dictionary.get("ExportAsPrompt.Title"), true);
+		setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+		setSize(size);
+		JPanel content_pane = (JPanel) getContentPane();
+		JLabel progress_label = new JLabel();
+		Dictionary.setText(progress_label, "ExportAsPrompt.Progress_Label");
+		JProgressBar progress_bar = new JProgressBar();
+		progress_bar.setIndeterminate(true);
+		content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+		content_pane.setLayout(new BorderLayout());
+		content_pane.add(progress_label, BorderLayout.NORTH);
+		content_pane.add(progress_bar, BorderLayout.CENTER);
+		// Position
+		Rectangle frame_bounds = Gatherer.g_man.getBounds();
+		setLocation(frame_bounds.x + (frame_bounds.width - size.width) / 2, frame_bounds.y + (frame_bounds.height - size.height) / 2);
+	    }
+	}
+    }
+
+
+}
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ExternalCollectionPrompt.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ExternalCollectionPrompt.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ExternalCollectionPrompt.java	(revision 10506)
@@ -0,0 +1,178 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, Greenstone Project, NZDL, University of Waikato
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 2003 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+
+// this has been changed to not offer the choice of a new metadata set, cos I haven't made this work properly.
+/** Prompt used when opening a non-gatherer built collection. We tell the user that they need to select metadata sets, and (in future) give them a choice between selecting an existing set or creating a new one */
+public class ExternalCollectionPrompt
+    extends ModalDialog {
+
+    public static int ERROR = 0;
+    public static int NEW_META_SET = 1;
+    public static int EXISTING_META_SET = 2;
+
+    private boolean cancelled = true;
+    private JDialog self;
+    private JRadioButton new_mds_button;
+    private JRadioButton existing_mds_button;
+    
+
+    static private Dimension size = new Dimension(600, 250);
+
+    public ExternalCollectionPrompt() {
+	super(Gatherer.g_man, true);
+	this.self = this;
+	setJMenuBar(new SimpleMenuBar("loadinganexternalcollection"));
+	setModal(true);
+	setSize(size);
+	Dictionary.setText(this, "ExternalCollectionPrompt.Title");
+
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+	JPanel center_pane = new JPanel();
+
+	JPanel instructions_panel = new JPanel();
+	JTextArea instructions_textarea;
+	instructions_textarea = new JTextArea();
+	instructions_textarea.setCaretPosition(0);
+	instructions_textarea.setEditable(false);
+	instructions_textarea.setLineWrap(true);
+	instructions_textarea.setRows(6);
+	instructions_textarea.setWrapStyleWord(true);
+	Dictionary.registerText(instructions_textarea, "ExternalCollectionPrompt.Instructions_1"); // change to "ExternalCollectionPrompt.Instructions_2" when add the other choice back in
+
+	/*	new_mds_button = new JRadioButton();
+	new_mds_button.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	//new_mds_button.setMnemonic(KeyEvent.VK_I);
+	new_mds_button.setOpaque(false);
+	Dictionary.registerText(new_mds_button, "ExternalCollectionPrompt.NewMDS");
+	existing_mds_button = new JRadioButton();
+	existing_mds_button.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	//existing_mds_button.setMnemonic(KeyEvent.VK_X);
+	existing_mds_button.setOpaque(false);
+	Dictionary.registerText(existing_mds_button, "ExternalCollectionPrompt.ExistingMDS");
+
+	ButtonGroup bg = new ButtonGroup();
+	bg.add(new_mds_button);
+	bg.add(existing_mds_button);
+	new_mds_button.setSelected(true);
+
+	JPanel selection_pane = new JPanel();
+	selection_pane.setLayout(new GridLayout(2,1));
+	selection_pane.add(new_mds_button);
+	selection_pane.add(existing_mds_button);
+	*/
+	JPanel button_pane = new JPanel();
+	JButton ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_O);
+	Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	JButton cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+
+	// Connection
+	ok_button.addActionListener(new OKButtonListener());
+	cancel_button.addActionListener(new CancelButtonListener());
+	//sets_list.addListSelectionListener(new MetadataListSelectionListener());
+
+	// Display
+	instructions_panel.setLayout(new GridLayout(1,1));
+	instructions_panel.add(instructions_textarea);
+
+
+	//center_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	//center_pane.setLayout(new GridLayout(2,1,0,5));
+	//center_pane.add(selection_pane);
+	
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	button_pane.setLayout(new GridLayout(1,2,5,0));
+	button_pane.add(ok_button);
+	button_pane.add(cancel_button);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(instructions_panel, BorderLayout.NORTH);
+	//content_pane.add(center_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	// Show
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - size.width) / 2, (screen_size.height - size.height) / 2);
+	setVisible(true);
+    }
+
+    public int getMetadataChoice() {
+	return NEW_META_SET;
+	
+	/*if (existing_mds_button.isSelected()) {
+	    return EXISTING_META_SET;
+	}
+	if (new_mds_button.isSelected()) {
+	    return NEW_META_SET;
+	}
+	// something wrong
+	return ERROR;*/
+    }
+    public boolean isCancelled() {
+	return cancelled;
+    }
+    private class CancelButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    cancelled = true;
+	    self.dispose();
+	}
+    }
+    public class OKButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    cancelled = false;
+	    self.dispose();
+		
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/FileAssociationDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/FileAssociationDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/FileAssociationDialog.java	(revision 10506)
@@ -0,0 +1,490 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.filechooser.*;
+import javax.swing.table.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.file.FileAssociationManager;
+import org.greenstone.gatherer.util.TableUtils;
+import org.greenstone.gatherer.util.Utility;
+
+/** The file association allows the entry of new file associations and the modification of existing ones.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class FileAssociationDialog
+    extends ModalDialog {
+
+    /** The default size for the dialog. */
+    static final private Dimension SIZE = new Dimension(600, 450);
+
+    private boolean ignore = false;
+    private FileAssociationDialog self;
+    private FileAssociationManager file_association_manager;
+    private JButton add_button;
+    private JButton browse_button;
+    private JButton close_button;
+    private JButton remove_button;
+    private JButton replace_button;
+    private JTable existing_associations_table;
+    private JTextField command_field;
+    private JTextField extension_field;
+
+    /** Create a new file association dialog.
+     * @param file_association_manager A reference to the <strong>FileAssociationManager</strong> so we can determine what extensions are already associated.
+     */
+    public FileAssociationDialog(FileAssociationManager file_association_manager) {
+	super(Gatherer.g_man);
+	this.file_association_manager = file_association_manager;
+	this.self = this;
+		  
+	// Creation
+	setModal(true);
+	setSize(SIZE);
+	setJMenuBar(new SimpleMenuBar("fileassociations"));
+
+	JPanel content_pane = (JPanel) getContentPane();
+	content_pane.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+
+	JTextArea instructions_area = new JTextArea();
+	instructions_area.setEditable(false);
+	instructions_area.setLineWrap(true);
+	instructions_area.setRows(5);
+	instructions_area.setWrapStyleWord(true);
+	Dictionary.setText(instructions_area, "FileAssociationDialog.Instructions");
+
+	JPanel control_pane = new JPanel();
+	JLabel existing_associations_label = new JLabel();
+	existing_associations_table = new JTable(file_association_manager);
+	existing_associations_table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
+	existing_associations_table.setColumnSelectionAllowed(false);
+	existing_associations_table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	JPanel lower_pane = new JPanel();
+	JPanel details_pane = new JPanel();
+
+	JPanel extension_pane = new JPanel();
+	JLabel extension_label = new JLabel();
+	extension_field = new NonWhitespaceField();
+
+	JLabel command_label = new JLabel();
+	JPanel command_pane = new JPanel();
+	command_field = new JTextField();
+	browse_button = new GLIButton();
+	browse_button.setEnabled(!Utility.isMac());
+	browse_button.setMnemonic(KeyEvent.VK_B);
+
+	JPanel button_pane = new JPanel();
+	
+	add_button = new GLIButton();
+	add_button.setEnabled(false);
+	add_button.setMnemonic(KeyEvent.VK_A);
+
+	replace_button = new GLIButton();
+	replace_button.setEnabled(false);
+	replace_button.setMnemonic(KeyEvent.VK_P);
+
+	remove_button = new GLIButton();
+	remove_button.setEnabled(false);
+	remove_button.setMnemonic(KeyEvent.VK_R);
+
+	close_button = new GLIButton();
+	close_button.setMnemonic(KeyEvent.VK_C);
+
+	// Connection
+	add_button.addActionListener(new AddButtonListener());
+	browse_button.addActionListener(new BrowseButtonListener());
+	close_button.addActionListener(new CloseButtonListener());
+	remove_button.addActionListener(new RemoveButtonListener());
+	replace_button.addActionListener(new ReplaceButtonListener());
+	CommandOrExtensionFieldListener coefl = new CommandOrExtensionFieldListener();
+	command_field.getDocument().addDocumentListener(coefl);
+	extension_field.getDocument().addDocumentListener(coefl);
+	coefl = null;
+	existing_associations_table.getSelectionModel().addListSelectionListener(new ExistingAssociationsTableListener());
+	Dictionary.setBoth(add_button, "FileAssociationDialog.Add", "FileAssociationDialog.Add_Tooltip");
+	if(Utility.isMac()) {
+	    Dictionary.setBoth(browse_button, "FileAssociationDialog.Browse", "FileAssociationDialog.Browse_Tooltip_Mac");
+	}
+	else {
+	    Dictionary.setBoth(browse_button, "FileAssociationDialog.Browse", "FileAssociationDialog.Browse_Tooltip");
+	}
+	Dictionary.setBoth(close_button, "FileAssociationDialog.Close", "FileAssociationDialog.Close_Tooltip");
+	Dictionary.setBoth(remove_button, "FileAssociationDialog.Remove", "FileAssociationDialog.Remove_Tooltip");
+	Dictionary.setBoth(replace_button, "FileAssociationDialog.Replace", "FileAssociationDialog.Replace_Tooltip");
+	Dictionary.setText(command_label, "FileAssociationDialog.Command");
+	Dictionary.setTooltip(command_field, "FileAssociationDialog.Command_Tooltip");
+	Dictionary.setText(extension_label, "FileAssociationDialog.Extension");
+	Dictionary.setTooltip(extension_field, "FileAssociationDialog.Extension_Tooltip");
+	Dictionary.setText(existing_associations_label, "FileAssociationDialog.Existing_Associations");
+	Dictionary.setText(this, "FileAssociationDialog.Title");
+
+	// Layout
+	extension_pane.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
+	extension_pane.setLayout(new BorderLayout(5,0));
+	extension_pane.add(extension_label, BorderLayout.WEST);
+	extension_pane.add(extension_field, BorderLayout.CENTER);
+
+	command_pane.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
+	command_pane.setLayout(new BorderLayout());
+	command_pane.add(command_field, BorderLayout.CENTER);
+	command_pane.add(browse_button, BorderLayout.EAST);
+
+	details_pane.setBorder(BorderFactory.createTitledBorder(Dictionary.get("FileAssociationDialog.Details")));
+	details_pane.setLayout(new GridLayout(3,1));
+	details_pane.add(extension_pane);
+	details_pane.add(command_label);
+	details_pane.add(command_pane);
+
+	lower_pane.setBorder(BorderFactory.createEmptyBorder(2,0,0,0));
+	button_pane.setLayout(new GridLayout(2,3));
+	button_pane.add(add_button);
+	button_pane.add(replace_button);
+	button_pane.add(remove_button);
+	button_pane.add(new JPanel());
+	button_pane.add(new JPanel());
+	button_pane.add(close_button);
+
+	lower_pane.setBorder(BorderFactory.createEmptyBorder(2,0,0,0));
+	lower_pane.setLayout(new BorderLayout());
+	lower_pane.add(details_pane, BorderLayout.CENTER);
+	lower_pane.add(button_pane, BorderLayout.SOUTH);
+
+	control_pane.setBorder(BorderFactory.createEmptyBorder(2,0,0,0));
+	control_pane.setLayout(new BorderLayout());
+	control_pane.add(existing_associations_label, BorderLayout.NORTH);
+	control_pane.add(new JScrollPane(existing_associations_table), BorderLayout.CENTER);
+	control_pane.add(lower_pane, BorderLayout.SOUTH);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(new JScrollPane(instructions_area), BorderLayout.NORTH);
+	content_pane.add(control_pane, BorderLayout.CENTER);
+
+	Rectangle screen = Gatherer.g_man.getBounds(null);
+	setLocation((int)(screen.getX() + (screen.getWidth() - SIZE.width) / 2), (int)(screen.getY() + (screen.getHeight() - SIZE.height) / 2));
+	screen = null;
+    }
+
+    public void destroy() {
+	// Disconnect
+	// Clean up
+	file_association_manager = null;
+	self = null;
+    }
+
+    /** Redisplay the dialog, ensuring that the details (or lack thereof) for a certain extension is apparent. In fact if an extension is provided force the user to add it or cancel.
+     * @param new_extension The extension code as a <strong>String</strong>.
+     */
+    public String display(String new_extension) {
+	// Clear the current selection
+	existing_associations_table.clearSelection();
+	if(new_extension != null) {
+	    extension_field.setText(new_extension);
+	}
+	setVisible(true);
+	if(new_extension != null) {
+	    return file_association_manager.getCommandString(new_extension);
+	}
+	return null;
+    }
+
+    protected void processWindowEvent(WindowEvent event) {
+	if(event.getID() == WindowEvent.WINDOW_ACTIVATED) {
+	    TableUtils.fixColumnToPreferredWidth(existing_associations_table, 0); 
+	}
+	else {
+	    super.processWindowEvent(event);
+	}
+    }
+
+    private class AddButtonListener
+	implements ActionListener {
+	
+	public void actionPerformed(ActionEvent event) {
+	    String extension_str = extension_field.getText();
+	    file_association_manager.setCommand(extension_str, command_field.getText());
+	    // Select the appropriate entry in the table
+	    int index = -1;
+	    for(int i = 0; index == -1 && i < file_association_manager.size(); i++) {
+		if(file_association_manager.getExtension(i).equals(extension_str)) {
+		    index = i;
+		}
+	    }
+	    if(index > -1) {
+		existing_associations_table.setRowSelectionInterval(index, index);
+	    }
+	    // And update buttons
+	    add_button.setEnabled(false);
+	    remove_button.setEnabled(true);
+	}
+    }
+
+    /** Batch filter shows only files ending in bat. Based on ImageFilter.java which is a 1.4 example used by FileChooserDemo2.java. */
+    private class BatchFileFilter
+	extends FileFilter {
+
+	/** Accept all .exe files
+	 * @param file a File
+	 * @return true is this file should be shown, false otherwise
+	 */
+	public boolean accept(File file) {
+	    return file.getName().toLowerCase().endsWith(".bat");
+	}
+
+	/** The description of this filter
+	 * @return a String
+	 */
+	public String getDescription() {
+	    return Dictionary.get("FileAssociationDialog.Batch_File");
+	}
+    }
+
+    /** Whenever the user clicks the browse button, we should open up a file browser to allow them to select an executable file from somewhere in the file system. */
+    private class BrowseButtonListener 
+	implements ActionListener {
+	/** Open up a simple JFileChooser when the user clicks the button. 
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    JFileChooser chooser = new JFileChooser(new File(Gatherer.getGLIUserDirectoryPath()));
+	    OpenCollectionDialog.disableRename(chooser);
+	    chooser.setDialogTitle(Dictionary.get("FileAssociationDialog.Browse_Title"));
+	    chooser.setFileFilter(new BatchFileFilter());
+	    chooser.setFileFilter(new CoreObjectModelFileFilter());
+	    chooser.setFileFilter(new ExecutableFileFilter());
+	    chooser.setAcceptAllFileFilterUsed(true);
+	    if(chooser.showOpenDialog(Gatherer.g_man) == JFileChooser.APPROVE_OPTION) {
+		command_field.setText(chooser.getSelectedFile().getAbsolutePath());
+	    }
+	}
+    }
+
+    private class CloseButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    existing_associations_table.clearSelection();
+	    add_button.setEnabled(false);
+	    remove_button.setEnabled(false);
+	    replace_button.setEnabled(false);
+	    self.dispose();
+	}
+    }
+
+    /** Command filter shows only files ending in com. Based on ImageFilter.java which is a 1.4 example used by FileChooserDemo2.java. */
+    private class CoreObjectModelFileFilter
+	extends FileFilter {
+
+	/** Accept all .exe files
+	 * @param file a File
+	 * @return true is this file should be shown, false otherwise
+	 */
+	public boolean accept(File file) {
+	    return file.getName().toLowerCase().endsWith(".com");
+	}
+
+	/** The description of this filter
+	 * @return a String
+	 */
+	public String getDescription() {
+	    return Dictionary.get("FileAssociationDialog.Command_File");
+	}
+    }
+
+    private class CommandOrExtensionFieldListener
+	implements DocumentListener {
+	/** Gives notification that an attribute or set of attributes changed. */
+	public void changedUpdate(DocumentEvent e) {
+	    changed();
+	}
+	/** Gives notification that there was an insert into the document. */
+	public void insertUpdate(DocumentEvent e) {
+	    changed();
+	}
+	/** Gives notification that a portion of the document has been removed. */
+	public void removeUpdate(DocumentEvent e) {
+	    changed();
+	} 
+
+	private void changed() {
+	    ignore = true;
+	    String extension_str = extension_field.getText();
+	    String command_str = command_field.getText();
+	    // Determine if there is currently an association selected
+	    int selected_index = -1;
+	    if((selected_index = existing_associations_table.getSelectionModel().getMinSelectionIndex()) != -1) {
+		String current_extension_str = file_association_manager.getExtension(selected_index);
+		String current_command_str = file_association_manager.getCommandString(current_extension_str);
+		// What buttons are enabled depends a lot on the file extension, taken to be the 'key'
+		if(extension_str.equals(current_extension_str)) {
+		    // If the extensions are the same then remove is enabled
+		    remove_button.setEnabled(true);
+		    // But if the command is different, then enable replace
+		    if(current_command_str.length() == 0) {
+			add_button.setEnabled(true);
+			replace_button.setEnabled(false);
+		    }
+		    else if(!command_str.equals(current_command_str)) {
+			add_button.setEnabled(false);
+			replace_button.setEnabled(true);
+		    }
+		    else {
+			add_button.setEnabled(false);
+			replace_button.setEnabled(false);
+		    }
+		}
+		// We can add it, but we first clear the selection
+		else {
+		    existing_associations_table.clearSelection();
+		    add_button.setEnabled(true);
+		    remove_button.setEnabled(false);
+		    replace_button.setEnabled(false);
+		}
+	    }
+	    // If not, we must first test if the extension is in use
+	    else {
+		int index = -1;
+		for(int i = 0; index == -1 && i < file_association_manager.size(); i++) {
+		    String existing_extension_str = file_association_manager.getExtension(i);
+		    if(existing_extension_str.equals(extension_str)) {
+			index = i;
+		    }
+		}
+		if(index != -1) {
+		    // Selection that index
+		    existing_associations_table.setRowSelectionInterval(index, index);
+		    // Set replace and remove enabled
+		    add_button.setEnabled(false);
+		    remove_button.setEnabled(true);
+		    replace_button.setEnabled(true);
+		}
+		// Otherwise if there is some text in both extension and command, enable add only
+		else if(extension_str.length() > 0 && command_str.length() > 0) {
+		    add_button.setEnabled(true);
+		    remove_button.setEnabled(false);
+		    replace_button.setEnabled(false);
+		}
+		// Otherwise disable everything
+		else {
+		    add_button.setEnabled(false);
+		    remove_button.setEnabled(false);
+		    replace_button.setEnabled(false);
+		}
+	    }
+	    ignore = false;
+	}
+    }
+
+    /** Executable filter shows only files ending in exe. Based on ImageFilter.java which is a 1.4 example used by FileChooserDemo2.java. */
+    private class ExecutableFileFilter
+	extends FileFilter {
+
+	/** Accept all .exe files
+	 * @param file a File
+	 * @return true is this file should be shown, false otherwise
+	 */
+	public boolean accept(File file) {
+	    return file.getName().toLowerCase().endsWith(".exe");
+	}
+
+	/** The description of this filter
+	 * @return a String
+	 */
+	public String getDescription() {
+	    return Dictionary.get("FileAssociationDialog.Executable_File");
+	}
+    }
+
+    private class ExistingAssociationsTableListener
+	implements ListSelectionListener {
+
+	public void valueChanged(ListSelectionEvent event) {
+	    if(!event.getValueIsAdjusting() && !ignore) {
+		int selected_index = -1;
+		if((selected_index = existing_associations_table.getSelectionModel().getMinSelectionIndex()) != -1) {
+		    // Propagate the details of the selection down into the fields
+		    String extension_str = file_association_manager.getExtension(selected_index);
+		    extension_field.setText(extension_str);
+		    command_field.setText(file_association_manager.getCommandString(extension_str));
+		    extension_str = null;
+		    remove_button.setEnabled(true);
+		}
+		else {
+		    // Clear the fields
+		    extension_field.setText("");
+		    command_field.setText("");
+		    remove_button.setEnabled(false);
+		}
+		add_button.setEnabled(false);
+		replace_button.setEnabled(false);
+	    }
+	}
+    }
+
+    private class RemoveButtonListener 
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    file_association_manager.setCommand(extension_field.getText(), null);
+	    // And update buttons
+	    add_button.setEnabled(true);
+	    remove_button.setEnabled(false);
+	}
+    }
+
+    private class ReplaceButtonListener 
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    file_association_manager.setCommand(extension_field.getText(), command_field.getText());
+	    // And update buttons
+	    replace_button.setEnabled(false);
+	}
+    }
+}
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/Filter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/Filter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/Filter.java	(revision 10506)
@@ -0,0 +1,335 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.regex.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.file.FileSystemModel;
+import org.greenstone.gatherer.gui.tree.DragTree;
+
+/** <p>This object allows the user to set a filter on one of the workspace trees, specifying a preset type, or a regular expression that a files must match to be in the tree. Note that all directories are included. This class includes the controls for editing the filter. The trick is that several instances of the Filter class can share the same internal data (termed a 'run' of filters), so that the filter set on the GatherPane and the EnrichPane are virtually the same.</p>
+ * <p>The regular expression typed uses '*' as a wildcard character (equivalent to '.*'), and does not use '.' to match any single character (use '?' instead).</p>
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class Filter
+    extends JPanel {
+    /** The other filters in this run of filters, used to ensure they all show the same thing. */
+    private ArrayList others = null;
+    /** Is this the first filter of this run of filters created (later filters will share the same information). */
+    private boolean first = true;
+    /** Prevent any changes we make in the class from causing events which we then process causing events... */
+    private boolean ignore = false;
+    /** A reference to ourselves so inner classes can refer to us. */
+    private Filter this_filter = null;
+    /** The check box to enable/disable filter. */
+    private JCheckBox checkbox = null;
+    /** The editable combobox where you either choose a predefined filter, or type a new pseudo-regular expression. */
+    private GComboBox combobox = null;
+    /** The label shown on the filter controls. */
+    private JLabel label = null;
+    /** A reference to the tree this filter is being applied to. */
+    private DragTree tree = null;
+    /** The default size for the label. */
+    static final private Dimension SIZE = new Dimension(100,30);
+    /** Preprogrammed default filters. */
+    static final private String DEFAULTS[] = {"^.*\\.html?$", "^.*\\.xml$", "^.*\\.txt$", "(^.*\\.jpe?g$)|(^.*\\.png$)|(^.*\\.gif$)|(^.*\\.bmp$)|(^.*\\.tiff?$)"};
+
+    /** Constructor.
+     * @param tree A reference to the <strong>JTree</strong> being affected.
+     */
+    public Filter(DragTree tree) {
+	this(tree, null);
+    }
+
+    /** Constructor.
+     * @param tree A reference to the <strong>JTree</strong> being affected.
+     * @param others An <strong>ArrayList</strong> of the other Filters already in this run.
+     */
+    public Filter(DragTree tree, ArrayList others) {
+	super();
+	if (others == null) {
+	    others = new ArrayList();
+	}
+	this.others = others;
+	this.others.add(this);
+	this.this_filter = this;
+	this.tree = tree;
+	// Create components.
+	combobox = new GComboBox(true);
+	combobox.add(new Entry());
+	for(int i = 0; i < DEFAULTS.length; i++) {
+	    try {
+		Entry entry = new Entry(Dictionary.get("Filter." + i), Pattern.compile(DEFAULTS[i]));
+		combobox.add(entry);
+	    }
+	    catch (Exception error) {
+		error.printStackTrace();
+	    }
+	}
+	label = new JLabel();
+	Dictionary.setText(label, "Filter.Filter_Tree");
+	// Add listeners.
+	combobox.addActionListener(new ComboBoxListener());
+	// Layout.
+	label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
+
+	setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
+	setLayout(new BorderLayout());
+	add(label, BorderLayout.WEST);
+	add(combobox, BorderLayout.CENTER);
+    }
+    /** Retrieve the combobox associated with this filter.
+     * @return A <strong>GComboBox</strong>.
+     */
+    public GComboBox getComboBox() {
+	return combobox;
+    }
+
+    /** Used to restore the filter state to enabled, the normal state during collection editing.
+     * @param state The new state for the filter. <i>true</i> for enabled, <i>false</i> otherwise.
+     */
+    public void setEnabled(boolean state) {
+	ignore = true;
+	combobox.setEnabled(state);
+	ignore = false;
+    }
+
+    /** Set the combobox model for this filter.
+     * @param model The new <strong>ComboBoxModel</strong> to use.
+     */
+    public void setComboBoxModel(ComboBoxModel model) {
+	combobox.setModel(model);
+    }
+
+    /** Ensure that a certain entry is selected from the combobox.
+     * @param selection The <strong>Entry</strong> that should be selected.
+     */
+    public void setComboBoxSelection(Entry selection) {
+	ignore = true;
+	combobox.setSelectedItem(selection);
+	ignore = false;
+    }
+
+    /** Sets whether this combobox is editable or not
+     * @param value true to make the control editable, false otherwise
+     */
+    public void setEditable(boolean value) {
+	combobox.setEditable(value);	    
+    }
+
+    /** Set to signify that this filter is the first in a new run of filters.
+     * @param first <i>true</i> if this is the first filter in a run, <i>false</i> if it will just be added to the current run.
+     */
+    public void setFirst(boolean first) {
+	this.first = first;
+    }
+
+    /** Spawn produces a copy of this filter, which has new controls, but shares listeners with this filter, and vice versa. Thus we can have two synchronized, but differing sets of controls.
+     * @param tree_spawn The <strong>JTree</strong> this filter will affect.
+     * @return A new <strong>Filter</strong> which is in the same run as this filter.
+     */
+    public Filter spawn(DragTree tree_spawn) {
+	Filter filter = new Filter(tree_spawn, others);
+	filter.setFirst(false); // No spawned copies should generate error messages, but fail silently.
+	filter.setComboBoxModel(combobox.getModel());
+	filter.setComboBoxSelection((Entry)combobox.getSelectedItem());
+	return filter;
+    }
+
+    /** Encode an expression in pseudo-regular expression into regular expression.
+     * @param raw The pseudo-regular expression <strong>String</strong> which includes several characters which differ in meaning from regular expression queries.
+     * @return A proper regular expression as a <strong>String</strong>.
+     */
+    private String encode(String raw) {
+	StringBuffer working = new StringBuffer();
+	for(int i = 0; i < raw.length(); i++) {
+	    char c = raw.charAt(i);
+	    switch(c) {
+	    case '.':
+		working.append("\\.");
+		break;
+	    case '*':
+		working.append(".*");
+		break;
+	    case '?':
+		working.append(".");
+		break;
+	    default:
+		working.append(Character.toLowerCase(c));
+	    }
+	}
+	return working.toString();
+    }
+    /** This method applies the given pattern to the tree registered as belonging to this filter.*/
+    private void setFilter(Pattern pattern) {
+	// Show busy cursor.
+	Gatherer.g_man.wait(true);
+	FileSystemModel model = (FileSystemModel) tree.getModel();
+	// Apply filter
+	if(pattern != null) {
+	    model.setFilter(pattern.pattern());
+	}
+	else {
+	    model.setFilter(null);
+	}
+	// Ask tree to completely refresh
+	tree.refresh(null);
+	// Restore cursor
+	Gatherer.g_man.wait(false);
+    }
+
+    /** Listens for changes in the combobox as when one is detected attempts to compile a regular expression from whatever text was entered. If successful, or if the item chosen was a predefined filter, it then applies the filter to the target tree. */
+    private class ComboBoxListener
+	implements ActionListener {
+	/** Called when a new item is selected from the filter combobox, we treat the new entry as a pseudo-regular expression, compile it and then apply it to the tree.
+	 * @param event An <strong>ActionEvent</strong> containing more information about the change performed.
+	 * @see org.greenstone.gatherer.gui.Filter.Entry
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    try {
+		Object temp = combobox.getSelectedItem();
+		Entry entry = null;
+		if(temp instanceof String) {
+		    String temp_str = (String) temp;
+		    ///ystem.err.println("Filter = " + temp_str);
+
+		    // Ignore any string which matches a predefined filter
+		    if(temp_str.equals(Dictionary.get("Filter.All_Files"))) {
+		    }
+		    // HTM & HTML
+		    else if(temp_str.equals(Dictionary.get("Filter.0"))) {
+		    }
+		    // XML
+		    else if(temp_str.equals(Dictionary.get("Filter.1"))) {
+		    }
+		    // Text files
+		    else if(temp_str.equals(Dictionary.get("Filter.2"))) {
+		    }
+		    // Images
+		    else if(temp_str.equals(Dictionary.get("Filter.3"))) {
+		    }
+		    else {
+			// Make sure the filter isn't already in the list
+			boolean already_exists = false;
+			for (int i = 0; i < combobox.getItemCount(); i++) {
+			    if (temp_str.equals(combobox.getItemAt(i).toString())) {
+				already_exists = true;
+				entry = (Entry) combobox.getItemAt(i);
+				break;
+			    }
+			}
+
+			if (already_exists == false) {
+			    entry = new Entry(temp_str, Pattern.compile(encode(temp_str)));
+			    int position = combobox.getItemCount();
+			    combobox.insertItemAt(entry, position);
+			    combobox.setSelectedIndex(position);
+			}
+		    }
+		}
+		else {
+		    ///ystem.err.println("Custom Filter");
+		    entry = (Entry) temp;
+		}
+		if(entry != null) {
+		    setFilter(entry.getPattern());
+		}
+		// Else we ignore this event as being one of the painfully erroneous events we receive because we've been silly enough to have an editable combobox.
+	    }
+	    catch (PatternSyntaxException error) {
+		if(first) {
+		    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Filter.Invalid_Pattern"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		}
+	    }
+	}
+    }
+    /** An object that holds a filter entry. This is string used for the filter pattern and, if not custom built, its name. */
+    private class Entry
+	implements Comparable {
+	/** The compiled pattern created from a regular expression. */
+	private Pattern pattern = null;
+	/** The name of this filter entry. */
+	private String name = null;
+	/** Constructor. */
+	public Entry() {
+	}
+	/** Constructor.
+	 * @param name The name of this entry as a <strong>String</strong>.
+	 * @param pattern The compiled regular expression as a <strong>Pattern</strong>.
+	 */
+	public Entry(String name, Pattern pattern) {
+	    this.name = name;
+	    this.pattern = pattern;
+	}
+	/** Compare two Entrys for ordering.
+	 * @param object The other Entry to compare to, as an <strong>Object</strong>.
+	 * @return An <i>int</i> indicating the respective ordering, as defined in java.lang.String#compareTo
+	 */
+	public int compareTo(Object object) {
+	    return toString().compareTo(object.toString());
+	}
+	/** Retrieve the pattern associated with this entry.
+	 * @return The <strong>Pattern</strong>.
+	 */
+	public Pattern getPattern() {
+	    return pattern;
+	}
+	/** Translate this entry into a textual representation.
+	 * @return A <strong>String</strong> containing the representation.
+	 */
+	public String toString() {
+	    String result = null;
+	    if (name != null) {
+		result = name;
+	    }
+	    else if (pattern == null) {
+		result = Dictionary.get("Filter.All_Files");
+	    }
+	    else {
+		result = pattern.pattern();
+	    }
+	    return result;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GComboBox.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GComboBox.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GComboBox.java	(revision 10506)
@@ -0,0 +1,351 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.plaf.basic.*;
+import org.greenstone.gatherer.Configuration;
+
+/**
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class GComboBox
+    extends JComboBox {
+
+    private Color background = null;
+    private Color foreground = null;
+    private Color editable_background = null;
+    private Color editable_foreground = null;
+    private Color selection_background = null;
+    private Color selection_foreground = null;
+
+    public GComboBox() {
+	super();
+	init();
+    }
+
+    public GComboBox(boolean editable) {
+	super();
+	setEditable(editable);
+	init();
+    }
+
+    public GComboBox(ArrayList data) {
+	super(data.toArray());
+	init();
+    }
+
+    public GComboBox(ArrayList data, boolean editable) {
+	super(data.toArray());
+	setEditable(editable);
+	init();
+    }
+
+    public GComboBox(ComboBoxModel model) {
+	super(model);
+	init();
+    }
+
+    public GComboBox(ComboBoxModel model, boolean editable) {
+	super(model);
+	setEditable(editable);
+	init();
+    }
+
+    public GComboBox(Object data[]) {
+	super(data);
+	init();
+    }
+
+    public GComboBox(Object data[], boolean editable) {
+	super(data);
+	setEditable(editable);
+	init();
+    }
+
+    public GComboBox(Vector data) {
+	super(data);
+	init();
+    }
+
+    public GComboBox(Vector data, boolean editable) {
+	super(data);
+	setEditable(editable);
+	init();
+    }
+
+    public int add(Object object) {
+	if (dataModel instanceof Model) {
+	    return ((Model) dataModel).add(object);
+	}
+	else {
+	    return -1;
+	}
+    }
+
+    public Object get(int index) {
+	return dataModel.getElementAt(index);
+    }
+
+    public void clear() {
+	if (dataModel instanceof Model) {
+	    ((Model) dataModel).clear();
+	}
+    }
+
+    public void init() {
+	Model model = new Model();
+	ComboBoxModel old_model = (ComboBoxModel) getModel();
+	setModel(model);
+	setOpaque(true);
+
+	// Restore any data given into our model
+	for(int i = 0; i < old_model.getSize(); i++) {
+	    model.add(old_model.getElementAt(i));
+	}
+
+	// Change component
+	UI ui = new UI();
+	setUI(ui);
+	ui.setButtonBackground();
+
+	// Initialization
+	this.background = Configuration.getColor("coloring.collection_tree_background", false);
+	this.foreground = Configuration.getColor("coloring.collection_tree_foreground", false);
+	this.editable_background = Configuration.getColor("coloring.editable_background", false);
+	this.editable_foreground = Configuration.getColor("coloring.editable_foreground", false);
+	this.selection_background = Configuration.getColor("coloring.collection_selection_background", false);
+	this.selection_foreground = Configuration.getColor("coloring.collection_selection_foreground", false);
+	if (isEditable()) {
+	    this.setBackground(editable_background);
+	    this.setForeground(editable_foreground);
+	}
+	else {
+	    this.setBackground(background);
+	    this.setForeground(foreground);
+	}
+	setBorder(BorderFactory.createLoweredBevelBorder());
+	setRenderer(new Renderer());
+    }
+
+    /** Overridden to do nothing. 
+     * @param background
+     */
+    public void setBackground(Color background) {
+    }
+
+    public void setBackgroundEditableColor(Color editable_background) {
+	this.editable_background = editable_background;
+    }
+
+    public void setBackgroundNonSelectionColor(Color background) {
+	this.background = background;
+    }
+
+    public void setBackgroundSelectionColor(Color selection_background) {
+	this.selection_background = selection_background;
+    }
+
+    public void setEditable(boolean editable) {
+	setEditor(new Editor());
+	super.setEditable(editable);
+	if (isEditable()) {
+	    this.setBackground(editable_background);
+	    this.setForeground(editable_foreground);
+	}
+	else {
+	    this.setBackground(background);
+	    this.setForeground(foreground);
+	}
+    }
+
+    public void setTextEditableColor(Color editable_foreground) {
+	this.editable_foreground = editable_foreground;
+    }
+
+    public void setTextNonSelectionColor(Color foreground) {
+	this.foreground = foreground;
+    }
+
+    public void setTextSelectionColor(Color selection_foreground) {
+	this.selection_foreground = selection_foreground;
+    }
+
+
+    private class Editor
+	extends JTextField
+	implements ComboBoxEditor {
+	public Editor() {
+	    setOpaque(true);
+	    if (isEditable()) {
+		setBackground(editable_background);
+		setForeground(editable_foreground);
+	    }
+	    else {
+		setBackground(background);
+		setForeground(foreground);
+	    }
+	    setSelectionColor(selection_background);
+	    setSelectedTextColor(selection_foreground);
+	}
+
+	public Component getEditorComponent() {
+	    return this;
+	}
+
+	public Object getItem() {
+	    return getText();
+	}
+
+	public void setItem(Object item) {
+	    if(item != null) {
+		setText(item.toString());
+	    }
+	    else {
+		setText("");
+	    }
+	}
+    }
+
+    private class Model
+	extends DefaultComboBoxModel {
+
+	public int add(Object extension) {
+	    int position = 0;
+	    String extension_str = extension.toString().toLowerCase();
+	    while(extension != null && position < getSize()) {
+		String sibling = getElementAt(position).toString().toLowerCase();
+		int order = extension_str.compareTo(sibling);
+		// If we are now less than the sibling, insert here.
+		if(order < 0) {
+		    insertElementAt(extension, position);
+		    extension = null;
+		}
+		// We are equal to the sibling, thus we already exist in list. Done.
+		else if(order == 0) {
+		    extension = null;
+		}
+		// Continue searching.
+		else {
+		    position++;
+		}
+	    }
+	    if(extension != null) {
+		position = getSize();
+		addElement(extension);
+	    }
+	    return position;
+	}
+
+	public void clear() {
+	    removeAllElements();
+	}
+    }
+
+    private class Renderer
+	extends JLabel
+	implements ListCellRenderer {
+	public Renderer() {
+	    super("");
+	    this.setOpaque(true);
+	}
+	public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+	    if(value != null) {
+		this.setText(value.toString());
+	    }
+	    else {
+		this.setText("");
+	    }
+	    if(isSelected) {
+		this.setBackground(selection_background);
+		this.setForeground(selection_foreground);
+	    }
+	    else if (isEditable()) {
+		this.setBackground(editable_background);
+		this.setForeground(editable_foreground);
+	    }
+	    else {
+		this.setBackground(background);
+		this.setForeground(foreground);
+	    }
+	    return this;
+	}
+    }
+
+    private class UI
+	extends BasicComboBoxUI {
+	public UI() {
+	    super();
+	}
+
+	protected ComboPopup createPopup() {
+	    BasicComboPopup popup = new BasicComboPopup(comboBox);
+	    // ---- I don't know why this code is here... maybe it is needed for the Mac? ----
+// 	    {
+// 		    public void show() {
+// 			if(comboBox.getMaximumRowCount() > 0) {
+// 			    Dimension popupSize = new Dimension( comboBox.getWidth(), getPopupHeightForRowCount( comboBox.getMaximumRowCount()));
+// 			    Rectangle popupBounds = new Rectangle( 0, 0, popupSize.width, popupSize.height);
+// 			    scroller.setMaximumSize( popupBounds.getSize() );
+// 			    scroller.setPreferredSize( popupBounds.getSize() );
+// 			    scroller.setMinimumSize( popupBounds.getSize() );
+// 			    list.invalidate();
+// 			    int selectedIndex = comboBox.getSelectedIndex();
+// 			    if ( selectedIndex == -1 ) {
+// 				list.clearSelection();
+// 			    }
+// 			    else {
+// 				list.setSelectedIndex( selectedIndex );
+// 			    }
+// 			    list.ensureIndexIsVisible( list.getSelectedIndex() );
+// 			    setLightWeightPopupEnabled( comboBox.isLightWeightPopupEnabled() );
+// 			    show(arrowButton, arrowButton.getSize().width - (popupSize.width + 4), arrowButton.getSize().height);
+// 			}
+// 		    }
+// 		};
+	    popup.getAccessibleContext().setAccessibleParent(comboBox);
+	    return popup;
+	}
+
+	public void setButtonBackground() {
+		arrowButton.setBackground(Configuration.getColor("coloring.button_background", false));
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GLIButton.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GLIButton.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GLIButton.java	(revision 10506)
@@ -0,0 +1,62 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import org.greenstone.gatherer.util.Utility;
+
+/** A button that knows whether it should paint itself as opaque or otherwise. */
+public class GLIButton
+    extends JButton {
+
+    public GLIButton() {
+	super();
+	setOpaque(!Utility.isMac());
+    }
+
+    public GLIButton(ImageIcon icon) {
+	super(icon);
+	setOpaque(!Utility.isMac());
+    }
+
+    public GLIButton(String title) {
+	super(title);
+	setOpaque(!Utility.isMac());
+    }
+}
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GUIManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GUIManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GUIManager.java	(revision 10506)
@@ -0,0 +1,920 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.event.*;
+import java.io.File;
+import java.lang.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.filechooser.*;
+import javax.swing.plaf.*;
+import javax.swing.text.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.Collection;
+import org.greenstone.gatherer.file.FileOpenActionListener;
+import org.greenstone.gatherer.file.WorkspaceTree;
+import org.greenstone.gatherer.gui.metaaudit.MetaAuditFrame;
+import org.greenstone.gatherer.gui.tree.DragTree;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.TreeSynchronizer;
+import org.greenstone.gatherer.util.Utility;
+
+/** The GUIManager is in charge of creating the Gatherer window frame then filling it with the goodness of the view panes. GUIManager not only creates these panes, but allows some messaging between them. Furthermore GUIManager includes functionality from menu driven choices, simply as it was easier to put it here once and have it accessible from all pane children. */
+public class GUIManager
+    extends JFrame
+    implements ActionListener, ChangeListener {
+    /** The download pane contains controls for downloading internet sites. */
+    public DownloadPane download_pane = null;
+    /** The gather pane is more like a file manager where you drag files from one tree to another. */
+    private GatherPane gather_pane = null;
+    /** The enrich pane is used to assign, edit and remove metadata from files within the collection. */
+    public EnrichPane enrich_pane = null;
+    /** The design pane allows you to edit the design of the library in terms of the collection configuration file. */
+    public DesignPane design_pane = null;
+    /** The create pane contains scripting options for importing and building collections into libraries. */
+    public CreatePane create_pane = null;
+
+    public FileOpenActionListener foa_listener = new FileOpenActionListener();
+
+    /** A reference to the currently instantiated help window, if any. */
+    private HelpFrame help = null;
+    /** The menu bar. */
+    public MenuBar menu_bar = null;
+    public MetaAuditFrame meta_audit;
+    /** Are certain panes currently locked? */
+    private boolean locked = false;
+    /** The size of the Gatherer window. */
+    private Dimension size = null;
+    /** The filters used to dynamically filter the trees at user request. */
+    private HashMap filters = new HashMap();
+    /** The panel within the window that other components are placed on. */
+    private JPanel content_pane = null;
+    /** The last view pane selected. */
+    private JPanel previous_pane;
+    /** The main tab pane containing the different views, available here to trap view change events. */
+    private JTabbedPane tab_pane = null;
+    /** A threaded tab changer to try and avoid NPE on exit. */
+    private TabUpdater tab_updater = null;
+    /** Ensures that expansion events between like collection trees are synchronized. */
+    private TreeSynchronizer collection_tree_sync = null;
+
+
+    /**Constructor. Enable window events and arranges all other components.
+     * @param size The intial <strong>Dimension</strong> of the screen.
+     */
+    public GUIManager(Dimension size) {
+	super();
+	// Initialization
+	this.help = new HelpFrame();
+	this.size = size;
+	this.collection_tree_sync = new TreeSynchronizer();
+	this.meta_audit = new MetaAuditFrame(collection_tree_sync, null);
+	
+	this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+
+	// 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 fore.
+	this.addFocusListener(new GLIGUIFocusListener());
+
+	// Make the Tool tip hang around for a rediculous amount of time.
+	ToolTipManager.sharedInstance().setDismissDelay(10000);
+
+	// Set up some other UI stuff. (fonts handled in Gatherer.main())
+	UIManager.put("FileChooser.lookInLabelText", Dictionary.get("SaveCollectionBox.Look_In"));
+	UIManager.put("FileChooser.filesOfTypeLabelText", Dictionary.get("SaveCollectionBox.Files_Of_Type"));
+	UIManager.put("FileChooser.fileNameLabelText", Dictionary.get("SaveCollectionBox.File_Name"));
+    }
+
+    private class GLIGUIFocusListener
+	extends FocusAdapter {
+	public void focusGained(FocusEvent e) {
+	    if (ModalDialog.current_modal != null) {
+		ModalDialog.current_modal.makeVisible();
+		ModalDialog.current_modal.toFront();
+	    }
+	}
+    }
+
+    /** 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();
+	// *************
+	// File Options.
+	// *************
+	if (esrc == menu_bar.file_associations) {
+	    Gatherer.assoc_man.edit();
+	}
+	else if (esrc == menu_bar.file_close) {
+	    saveThenCloseCurrentCollection();
+	}
+	else if (esrc == menu_bar.file_delete) {
+	    DeleteCollectionPrompt dcp = new DeleteCollectionPrompt();
+	    if (dcp.display()) {
+		saveThenCloseCurrentCollection();
+	    }
+	    dcp.destroy();
+	    dcp = null;
+	    System.gc();
+	}
+	else if (esrc == menu_bar.file_cdimage) {
+	    WriteCDImagePrompt wcdip = new WriteCDImagePrompt();
+	    wcdip.display();
+	    wcdip.destroy();
+	    wcdip = null;
+	}
+	else if (esrc == menu_bar.file_exportas) {
+	    ExportAsPrompt eap = new ExportAsPrompt();
+	    eap.display();
+	    eap.destroy();
+	    eap = null;
+	}
+	else if (esrc == menu_bar.file_exit) {
+	    exit();
+	}
+        else if (esrc == menu_bar.file_new) {
+	    showNewCollectionPrompt();
+	}
+	else if (esrc == menu_bar.file_open) {
+	    String collection_file_path = showOpenCollectionDialog();
+
+	    // User has selected a collection to open
+	    if (collection_file_path != null) {
+		// If there is already a collection open, save and close it
+		if (Gatherer.c_man.ready()) {
+		    saveThenCloseCurrentCollection();
+		}
+
+		// Open the selected collection
+		Gatherer.c_man.loadCollection(collection_file_path);
+	    }
+	}
+	else if (esrc == menu_bar.file_options) {
+	    // Just incase the user has edited the GeneralSettings of a collection without losing focus afterwards. Well I'm forever losing foc... ooh shiney.
+	    design_pane.loseFocus();
+	    // And spawn a new preferences.
+	    new Preferences();
+	}
+	else if (esrc == menu_bar.file_save) {
+	    Gatherer.c_man.saveCollection();
+	}
+
+	// *************
+	// Edit Options.
+	// *************
+	else if(esrc == menu_bar.edit_copy) {
+	    try {
+		KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+		// Get the component with selected text as a JTextComponent
+		JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();//getFocusOwner();
+		text.copy();
+	    }
+	    catch (Exception cce) {
+		// If the component is not a text component ignore the copy command
+		DebugStream.println(cce.toString());
+	    }
+	}
+	else if(esrc == menu_bar.edit_cut) {
+	    try {
+		KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+		// Get the component with selected text as a JTextComponent
+		JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
+		// Cut the text to the clipboard
+		text.cut();
+	    }
+	    catch (ClassCastException cce) {
+		// If the component is not a text component ignore the cut command
+		DebugStream.println(cce.toString());
+	    }
+	}
+	else if(esrc == menu_bar.edit_paste) {
+	    try {
+		KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+		// Get the component with selected text as a JTextComponent
+		JTextComponent text = (JTextComponent) kfm.getPermanentFocusOwner();
+		// Cut the text to the clipboard
+		text.paste();
+	    }
+	    catch (ClassCastException cce) {
+		// If the component is not a text component ignore the paste command
+		DebugStream.println(cce.toString());
+	    }
+	}
+
+	// *************
+	// Help Options.
+	// *************
+	else if (esrc == menu_bar.help_general) {
+	    HelpFrame.setView("introduction");
+	}
+	else if (esrc == menu_bar.help_download) {
+	    HelpFrame.setView("downloadingfiles");
+	}
+	else if (esrc == menu_bar.help_gather) {
+	    HelpFrame.setView("collectingfiles");
+	}
+	else if (esrc == menu_bar.help_enrich) {
+	    HelpFrame.setView("enrichingacollection");
+	}
+	else if (esrc == menu_bar.help_design) {
+	    HelpFrame.setView("designingacollection");
+	}
+	else if (esrc == menu_bar.help_create) {
+	    HelpFrame.setView("producingthecollection");
+	}
+	else if (esrc == menu_bar.help_about) {
+	    new AboutDialog(this);
+	}
+    }
+
+
+    /** Any actions that should happen after the display of the Gatherer window can be called here. Currently only updates the browser pane if it is active to work around bug in Mozilla renderer implementation.
+     */
+    public void afterDisplay() {
+	if (download_pane != null) {
+	    download_pane.afterDisplay();
+	}
+	enrich_pane.afterDisplay();
+    }
+
+
+    public void saveThenCloseCurrentCollection()
+    {
+	tab_pane.setSelectedComponent(gather_pane);
+	Gatherer.c_man.saveCollection();
+	Gatherer.c_man.closeCollection();
+    }
+
+
+    /** This is called when we're absolutely finished with the GLI. It is *not* called when the applet is suspended.
+     */
+    public void destroy()
+    {
+	// Destroying create pane ensures the latest log has been closed
+	if (create_pane != null) {
+	    create_pane.destroy();
+	}
+
+	// Deal to help
+	if (help != null) {
+	    help.destroy();
+	    help = null;
+	}
+    }
+
+
+    /** Enabled events on the window to be trapped, creates all the visual components, then builds the tab and other layouts.
+     */
+    public void display() {
+	content_pane = (JPanel) this.getContentPane();
+	// Enable window-type events to be fired.
+	enableEvents(AWTEvent.WINDOW_EVENT_MASK);
+	// Initialise and layout sub-components, plus other window dressing.
+	try {
+	    this.setSize(size);
+
+	    // Set the title
+	    String collection_title = null;
+	    String collection_name = null;
+	    if (Gatherer.c_man.ready()) {
+		Collection collection = Gatherer.c_man.getCollection();
+		collection_title = collection.getTitle();
+		collection_name = collection.getName();
+		collection = null;
+	    }
+	    setTitle(collection_title, collection_name);
+	    collection_title = null;
+	    collection_name = null;
+
+	    // Pretty corner icon
+	    this.setIconImage(JarTools.getImage("gatherer_small.gif").getImage());
+	    // BorderLayout for the main screen. I'll try my best to avoid these in subcomponents as they're space greedy.
+	    content_pane.setLayout(new BorderLayout());
+	    // Create the menu-bar and stick it up the top.
+	    menu_bar = new MenuBar(new MenuListenerImpl());
+
+	    //feedback changes
+	    //content_pane.add(menu_bar, BorderLayout.NORTH);
+	    this.setJMenuBar(menu_bar);
+	    // end feedback changes
+
+	    // Create the tabbed pane and plop it in the center where it will
+	    // expand to consume all available space like any good gas would.
+	    tab_pane = new JTabbedPane();
+	    tab_pane.addChangeListener(this);
+	    tab_pane.setFont(Configuration.getFont("general.font", false));
+
+	    if (Configuration.get("workflow.download", true)) {
+		download_pane = new DownloadPane();
+		// "GUI.Download_Tooltip" is used automatically
+		tab_pane.addTab("GUI.Download", JarTools.getImage("download.gif"), download_pane);
+		tab_pane.setEnabledAt(tab_pane.indexOfComponent(download_pane), Configuration.get("workflow.download", false));
+	    }
+
+	    gather_pane = new GatherPane(collection_tree_sync);
+	    gather_pane.display();
+	    if (Configuration.get("workflow.gather", true)) {
+		// "GUI.Gather_Tooltip" is used automatically
+		tab_pane.addTab("GUI.Gather", JarTools.getImage("gather.gif"), gather_pane);
+		tab_pane.setEnabledAt(tab_pane.indexOfComponent(gather_pane), Configuration.get("workflow.gather", false));
+	    }
+
+	    enrich_pane = new EnrichPane(collection_tree_sync);
+	    enrich_pane.display();
+	    if (Configuration.get("workflow.enrich", true)) {
+		// "GUI.Enrich_Tooltip" is used automatically
+		tab_pane.addTab("GUI.Enrich", JarTools.getImage("enrich.gif"), enrich_pane);
+		tab_pane.setEnabledAt(tab_pane.indexOfComponent(enrich_pane), false);
+	    }
+
+	    design_pane = new DesignPane();
+	    design_pane.display();
+	    if (Configuration.get("workflow.design", true)) {
+		// "GUI.Design_Tooltip" is used automatically
+		tab_pane.addTab("GUI.Design", JarTools.getImage("design.gif"), design_pane);
+		tab_pane.setEnabledAt(tab_pane.indexOfComponent(design_pane), false);
+	    }
+
+	    create_pane = new CreatePane();
+	    create_pane.display();
+	    if (Configuration.get("workflow.create", true)) {
+		// "GUI.Create_Tooltip" is used automatically
+		tab_pane.addTab("GUI.Create", JarTools.getImage("create.gif"), create_pane);
+		tab_pane.setEnabledAt(tab_pane.indexOfComponent(create_pane), false);
+	    }
+
+	    // Select the collect pane if it is available
+	    if (tab_pane.indexOfComponent(gather_pane) != -1) {
+		tab_pane.setSelectedComponent(gather_pane);
+	    }
+	    // Otherwise find the first tab that is enabled and select that.
+	    else {
+		for (int i = 0; i < tab_pane.getTabCount(); i++) {
+		    if (tab_pane.isEnabledAt(i)) {
+			tab_pane.setSelectedIndex(i);
+			break;
+		    }
+		}
+	    }
+
+	    Dictionary.register(tab_pane);
+	    content_pane.add(tab_pane, BorderLayout.CENTER);
+	    // Call refresh to update all controls to reflect current collection status.
+	    refresh(-1, Gatherer.c_man.ready());
+	}
+	catch (Exception e) {
+	    DebugStream.printStackTrace(e);
+	    // The GUI failing to build is an app killer
+	    e.printStackTrace();
+	    System.exit(1);
+	}
+    }
+
+
+    /** This method ensures that all the things needing saving are saved before Gatherer.exit() is called.
+     */
+    public void exit()
+    {
+	// If we have a collection open remember it for next time, then save it and close it
+	if (Gatherer.c_man.ready()) {
+	    Configuration.setString("general.open_collection", true, Gatherer.c_man.getCollectionFilePath());
+	    saveThenCloseCurrentCollection();
+	}
+	else {
+	    Configuration.setString("general.open_collection", true, null);
+	}
+
+	// Store the current position and size of the GLI for next time
+	Configuration.setBounds("general.bounds", true, getBounds());
+
+	// Save configuration
+	Configuration.save();
+
+	// Hide the main window
+	setVisible(false);
+
+	// If we're running as an applet we don't quit here (we quit when the browser calls GathererApplet.destroy())
+	if (!Gatherer.isApplet) {
+	    Gatherer.self.exit();
+	}
+    }
+
+
+    /** Retrieve the filter, or if one already exists, spawn a linked copy. */
+    public Filter getFilter(DragTree tree) {
+	Filter filter = (Filter) filters.get(tree.getModel());
+	if (filter == null) {
+	    filter = new Filter(tree, null);
+	    filters.put(tree.getModel(), filter);
+	    return filter;
+	}
+	return filter.spawn(tree);
+    }
+
+
+    /** This method is called when the collection is being built, and is used to disable all controls in all pane which could change the state of the collection.
+     */
+    public void lockCollection(boolean import_stage, boolean lock)
+    {
+	locked = lock;
+
+	if (import_stage) {
+	    int gather_pos = tab_pane.indexOfComponent(gather_pane);
+	    if (gather_pos != -1) {
+		tab_pane.setEnabledAt(gather_pos, !lock);
+	    }
+	    int enrich_pos = tab_pane.indexOfComponent(enrich_pane);
+	    if (enrich_pos != -1) {
+		tab_pane.setEnabledAt(enrich_pos, !lock);
+	    }
+	}
+
+	int design_pos = tab_pane.indexOfComponent(design_pane);
+	if (design_pos != -1) {
+	    tab_pane.setEnabledAt(design_pos, !lock);
+	}
+    }
+
+
+    public void modeChanged(int mode) {
+	// Set the title
+	String collection_title = null;
+	String collection_name = null;
+	if (Gatherer.c_man.ready()) {
+	    Collection collection = Gatherer.c_man.getCollection();
+	    collection_title = collection.getTitle();
+	    collection_name = collection.getName();
+	    collection = null;
+	}
+	setTitle(collection_title, collection_name);
+	collection_title = null;
+	collection_name = null;
+	// Now pass on the message to anyone who cares
+	if (download_pane != null) {
+	    download_pane.modeChanged(mode);
+	}
+	if (gather_pane != null) {
+	    gather_pane.modeChanged(mode);
+	}
+	if (enrich_pane != null) {
+	    enrich_pane.modeChanged(mode);
+	}
+	if (design_pane != null) {
+	    design_pane.modeChanged(mode);
+	}
+	if (create_pane != null) {
+	    create_pane.modeChanged(mode);
+	}
+    }
+
+
+    public void refresh(int refresh_reason, boolean collection_loaded)
+    {
+	// Set the collection information in the title bar
+	if (collection_loaded) {
+	    Collection collection = Gatherer.c_man.getCollection();
+	    setTitle(collection.getTitle(), collection.getName());
+	}
+	else {
+	    setTitle(null, null);
+	}
+
+	// Update the menu bar
+	menu_bar.refresh(refresh_reason, collection_loaded);
+
+	// Update the loaded panes
+	if (download_pane != null) {
+	    download_pane.refresh(refresh_reason, collection_loaded);
+	}
+	if (gather_pane != null) {
+	    gather_pane.refresh(refresh_reason, collection_loaded);
+	}
+	if (enrich_pane != null) {
+	    enrich_pane.refresh(refresh_reason, collection_loaded);
+	}
+	if (design_pane != null) {
+	    design_pane.refresh(refresh_reason, collection_loaded);
+	}
+	if (create_pane != null) {
+	    create_pane.refresh(refresh_reason, collection_loaded);
+	}
+
+	// Now enable tabs as necessary. Do this on event queue to prevent crazy NPEs
+	if (!locked) {
+	    if (tab_updater == null) {
+		tab_updater = new TabUpdater(tab_pane, collection_loaded);
+	    }
+	    else {
+		tab_updater.setReady(collection_loaded);
+	    }
+	    SwingUtilities.invokeLater(tab_updater);
+	}
+    }
+
+
+    public void refreshCollectionTree(int refresh_reason)
+    {
+	if (gather_pane != null) {
+	    gather_pane.refreshCollectionTree(refresh_reason);
+	}
+    }
+
+
+    public void refreshWorkspaceTree(int refresh_reason)
+    {
+	if (gather_pane != null) {
+	    gather_pane.refreshWorkspaceTree(refresh_reason);
+	}
+    }
+
+
+    /** Returns to some "initial" pane (when no collection is loaded) */
+    public void returnToInitialPane()
+    {
+	if (gather_pane != null) {
+	    tab_pane.setSelectedComponent(gather_pane);
+	}
+    }
+
+
+    /** Specifies whether a certain tab is enabled or not. */
+    private void setTabEnabled(String rawname, boolean state) {
+	// Retrieve the dictionary based name.
+	String name = Dictionary.get("GUI." + rawname);
+	int index = tab_pane.indexOfTab(name);
+	// Of course we may not have this tab available.
+	if(index != -1) {
+	    // Some tabs are also dependant on if a collection is ready
+	    Component component = tab_pane.getComponentAt(index);
+	    if(component == enrich_pane || component == design_pane || component == create_pane) {
+		tab_pane.setEnabledAt(index, state && Gatherer.c_man != null && Gatherer.c_man.ready());
+	    }
+	    else {
+		tab_pane.setEnabledAt(index, state);
+	    }
+	    // If this was the currently selected tab and it is now disabled, change the view to the first enabled tab.
+	    if(tab_pane.getSelectedIndex() == index && !state) {
+		boolean found = false;
+		for(int i = 0; !found && i < tab_pane.getTabCount(); i++) {
+		    if(tab_pane.isEnabledAt(i)) {
+			tab_pane.setSelectedIndex(i);
+			found = true;
+		    }
+		}
+		// If there are no tabs enabled, which should be impossible, then select the first tab
+		if(!found) {
+		    tab_pane.setSelectedIndex(0);
+		}
+	    }
+	}
+    }
+
+    /** Change the string shown in the title bar of the main gui frame. If either value is null, the 'No Collection' string is shown instead.
+     * @param title
+     * @param name
+     */
+    public void setTitle(String title, String name) {
+	// Finally display the collection name in the title bar.
+	StringBuffer title_buffer = new StringBuffer(Utility.PROGRAM_NAME);
+	title_buffer.append(StaticStrings.SPACE_CHARACTER);
+	title_buffer.append(StaticStrings.SPACE_CHARACTER);
+	// Describe the current user mode
+	title_buffer.append(StaticStrings.MODE_STR);
+	title_buffer.append(Configuration.getModeAsString());
+	title_buffer.append(StaticStrings.SPACE_CHARACTER);
+	title_buffer.append(StaticStrings.SPACE_CHARACTER);
+	// Now for the current collection
+	title_buffer.append(StaticStrings.COLLECTION_STR);
+	if (title != null && name != null) {
+	    title_buffer.append(title);
+	    title_buffer.append(StaticStrings.SPACE_CHARACTER);
+	    title_buffer.append(StaticStrings.OPEN_PARENTHESIS_CHARACTER);
+	    title_buffer.append(name);
+	    title_buffer.append(StaticStrings.CLOSE_PARENTHESIS_CHARACTER);
+	}
+	else {
+	    title_buffer.append(Dictionary.get("Collection.No_Collection"));
+	}
+	this.setTitle(title_buffer.toString());
+	title_buffer = null;
+    }
+
+
+    /** When the load collection option is choosen this method is called to produce the modal file load prompt.
+     */
+    private String showOpenCollectionDialog()
+    {
+	// We first try the simple open collection dialog
+	SimpleOpenCollectionDialog dialog = new SimpleOpenCollectionDialog();
+	int user_choice = dialog.display();
+
+	// Used simple collection list
+	if (user_choice == SimpleOpenCollectionDialog.OK_OPTION) {
+	    return dialog.getFileName();
+	}
+
+	// Chosen to use the advanced 'browse' dialog
+	if (user_choice == SimpleOpenCollectionDialog.BROWSE_OPTION) {
+	    File collect_directory;
+	    if (Gatherer.GS3) {
+		collect_directory = new File(Utility.getSitesDir(Configuration.gsdl3_path));
+	    }
+	    else {
+		collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	    }
+	    OpenCollectionDialog chooser = new OpenCollectionDialog(collect_directory);
+	    return chooser.getFileName();
+	}
+
+	// User must have cancelled the action
+	return null;
+    }
+
+
+    /** When called this method causes the MetadataAuditTable to display a nice dialog box which contains all the metadata assigned in the collection.
+     */
+    public void showMetaAuditBox() {
+	wait(true);
+	meta_audit.display();
+	wait(false);
+    }
+    /** This method is used to open the new collection box on the screen.
+     */
+    private void showNewCollectionPrompt() {
+	NewCollectionMetadataPrompt ncm_prompt = null;
+	// Create the collection details prompt from new collection prompt
+	NewCollectionDetailsPrompt ncd_prompt = new NewCollectionDetailsPrompt();
+	// If no previous collection was indicated as a model design, then show the metadata selection prompt from new collection prompt
+	if(!ncd_prompt.isCancelled() && (ncd_prompt.getBase() == null)) {
+	    ncm_prompt = new NewCollectionMetadataPrompt();
+	}
+	// Create the new collection (if not cancelled) in a new thread.
+	if (!ncd_prompt.isCancelled() && (ncm_prompt == null || !ncm_prompt.isCancelled())) {
+	    // If there is already a collection open, save and close it.
+	    if (Gatherer.c_man.ready()) {
+		saveThenCloseCurrentCollection();
+	    }
+
+	    // Create new collection.
+	    NewCollectionTask new_collection_task = new NewCollectionTask(ncd_prompt, ncm_prompt);
+	    new_collection_task.start();
+	}
+	// Done
+	ncd_prompt = null;
+	ncm_prompt = null;
+    }
+
+
+    private class NewCollectionTask
+        extends Thread
+    {
+	private NewCollectionDetailsPrompt ncd_prompt = null;
+	private NewCollectionMetadataPrompt ncm_prompt = null;
+
+	public NewCollectionTask(NewCollectionDetailsPrompt ncd_prompt, NewCollectionMetadataPrompt ncm_prompt)
+	{
+	    this.ncd_prompt = ncd_prompt;
+	    this.ncm_prompt = ncm_prompt;
+	}
+
+	public void run()
+	{
+	    if (ncm_prompt == null) {
+		Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Configuration.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), ncd_prompt.getBase(), null);
+	    }
+	    else {
+		Gatherer.c_man.createCollection(ncd_prompt.getDescription(), Configuration.getEmail(), ncd_prompt.getName(), ncd_prompt.getTitle(), null, ncm_prompt.getSets());
+		ncm_prompt.dispose();
+		ncm_prompt = null;
+	    }
+
+	    ncd_prompt.dispose();
+	    ncd_prompt = null;
+
+	    // Return to some initial pane (Gather)
+	    returnToInitialPane();
+
+	    // Refresh the workspace tree to allow for the new collection
+	    refreshWorkspaceTree(WorkspaceTree.LIBRARY_CONTENTS_CHANGED);
+
+	    // Refresh the rest of the GLI
+	    Gatherer.refresh(Gatherer.COLLECTION_OPENED);
+	}
+    }
+
+
+    /** 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)
+    {
+	// Tell the previous pane that it has lost focus
+	if (previous_pane != null) {
+	    if (previous_pane == enrich_pane) {
+		enrich_pane.loseFocus();
+	    }
+	    else if (previous_pane == design_pane) {
+		design_pane.loseFocus();
+	    }
+	    else if (previous_pane == create_pane) {
+		create_pane.loseFocus();
+	    }
+	}
+
+	menu_bar.tabSelected(tab_pane.getSelectedIndex());
+	int selected_index = tab_pane.getSelectedIndex();
+	if (selected_index == tab_pane.indexOfComponent(download_pane)) {
+	    download_pane.gainFocus();
+	}
+	else if (selected_index == tab_pane.indexOfComponent(gather_pane)) {
+	    gather_pane.gainFocus();
+	}
+	else if (selected_index == tab_pane.indexOfComponent(enrich_pane)) {
+	    enrich_pane.gainFocus();
+	}
+	else if (selected_index == tab_pane.indexOfComponent(design_pane)) {
+	    design_pane.gainFocus();
+	}
+	else if (selected_index == tab_pane.indexOfComponent(create_pane)) {
+	    create_pane.gainFocus();
+	}
+
+	previous_pane = (JPanel) tab_pane.getSelectedComponent();
+    }
+
+
+    private MouseListener mouse_blocker_listener = new MouseAdapter() {};
+
+    public void updateUI()
+    {
+	JPanel pane = (JPanel) getContentPane();
+	pane.updateUI();
+	// Also update all of the tabs according to workflow.
+	workflowUpdate("Download", Configuration.get("workflow.download", false));
+	workflowUpdate("Gather", Configuration.get("workflow.gather", false));
+	workflowUpdate("Enrich", Configuration.get("workflow.enrich", false));
+	workflowUpdate("Design", Configuration.get("workflow.design", false));
+	workflowUpdate("Create", Configuration.get("workflow.create", false));
+    }
+
+    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;
+    }
+
+    public void workflowUpdate(String raw, boolean state) {
+	WorkflowUpdater task = new WorkflowUpdater(raw, state);
+	SwingUtilities.invokeLater(task);
+	task = 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 {
+	/** Called whenever a popup menu is hidden, but we don't care.
+	 * @param e Some <strong>MenuEvent</strong> that we could care less about.
+	 */
+	public void menuCanceled(MenuEvent e) {
+	}
+	/** Called whenever a menu header (ie button) becomes unselected, but we don't care.
+	 * @param e Some <strong>MenuEvent</strong> that we could care less about.
+	 */
+	public void menuDeselected(MenuEvent e) {
+	}
+	/** This method, when a menu is first opened, is the only one we respond to by bringing the help window to the front if possible, but only if there is a help window and the help menu is the one opening.
+	 * @param e The <strong>MenuEvent</strong> whose source is checked.
+	 */
+	public void menuSelected(MenuEvent e) {
+	    if(e.getSource() == menu_bar.help) {
+		if(menu_bar.help.isSelected()) {
+		    menu_bar.help.doClick(10);
+		}
+	    }
+	}
+    }
+
+    private class TabUpdater
+	implements Runnable {
+	private boolean ready = false;
+	private int download_pos = -1;
+	private int enrich_pos = -1;
+	private int design_pos = -1;
+	private int create_pos = -1;
+	private int export_pos = -1;
+	private JTabbedPane tab_pane = null;
+
+	public TabUpdater(JTabbedPane tab_pane, boolean ready) {
+	    this.ready = ready;
+	    this.tab_pane = tab_pane;
+	    download_pos = tab_pane.indexOfComponent(download_pane);
+	    enrich_pos = tab_pane.indexOfComponent(enrich_pane);
+	    design_pos = tab_pane.indexOfComponent(design_pane);
+	    create_pos = tab_pane.indexOfComponent(create_pane);
+	}
+
+	public void run()
+	{
+	    if (download_pos != -1) {
+		if (ready) {
+		    tab_pane.setEnabledAt(download_pos, Configuration.get("workflow.download", false));
+		}
+		else {
+		    tab_pane.setEnabledAt(download_pos, Configuration.get("workflow.download", true));
+		}
+	    }
+	    if (enrich_pos != -1) {
+		tab_pane.setEnabledAt(enrich_pos, ready && Configuration.get("workflow.enrich", false));
+	    }
+	    if (design_pos != -1) {
+		tab_pane.setEnabledAt(design_pos, ready && Configuration.get("workflow.design", false) && Configuration.getMode() > Configuration.ASSISTANT_MODE);
+	    }
+	    if (create_pos != -1) {
+		tab_pane.setEnabledAt(create_pos, ready && Configuration.get("workflow.create", false));
+	    }
+	}
+
+	public void setReady(boolean ready) {
+	    this.ready = ready;
+	}
+    }
+
+    private class WorkflowUpdater
+	implements Runnable {
+	private boolean state;
+	private String raw;
+	public WorkflowUpdater(String raw, boolean state) {
+	    this.raw = raw;
+	    this.state = state;
+	}
+	public void run() {
+	    setTabEnabled(raw, state);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GatherPane.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GatherPane.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/GatherPane.java	(revision 10506)
@@ -0,0 +1,932 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.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.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.CollectionTree;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+import org.greenstone.gatherer.file.FileNode;
+import org.greenstone.gatherer.file.FileOpenActionListener;
+import org.greenstone.gatherer.file.FileQueue;
+import org.greenstone.gatherer.file.FileSystemModel;
+import org.greenstone.gatherer.file.RecycleBin;
+import org.greenstone.gatherer.file.WorkspaceTree;
+import org.greenstone.gatherer.file.WorkspaceTreeNode;
+import org.greenstone.gatherer.gui.tree.DragTree;
+import org.greenstone.gatherer.gui.ExplodeMetadataPrompt;
+import org.greenstone.gatherer.util.DragComponent;
+import org.greenstone.gatherer.util.DragGroup;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.TreeSynchronizer;
+import org.greenstone.gatherer.util.Utility;
+
+/** The collection pane is analogous with a file manager. It is there that the user chooses which files to include in their collection and what structure the file hierarchy should take. The later aspect is not important for the Greenstone Suite, but is usefull for grouping files for ease of metadata markup. The view essentially consists of two file trees, one denoting the entire source workspace and the other the files within your collection. The trees themselves have a title bar at the top, a filter control at the bottom, and are coloured to indicate activity (grey for disabled). The remainder of the screen is taken by a status area, to indicate current file job progress during copying etc, and three buttons for controlling features of the view.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class GatherPane
+    extends JPanel
+    implements ActionListener, FocusListener {
+    /** The group encompassing all of the components available as drop targets for drag and drop actions. Required so that only one component renders the ghost and higlights itself as a target, which the other members are restored to their original, pristine, condition. */
+    private DragGroup group				  =  null;
+    /** The tree showing the files within the collection. */
+    private CollectionTree collection_tree = null;
+    /** The threaded queue that handles the actually movement of files, so that the gui remains responsive. */
+    private FileQueue file_queue		  =  null;
+    /** The filter currently applied to the collection tree. */
+    private Filter collection_filter = null;
+    /** The filter currently applied to the workspace tree. */
+    private Filter workspace_filter = null;
+    /** The button used to cancel all pending file queue jobs. */
+    private JButton stop_action		   =  null;
+    /** The button used to create a new folder in the collection tree. */
+    private JButton new_folder			=  null;
+    /** The label shown at the top of the collection tree. */
+    private JLabel collection_label	   =  null;
+    /** The label shown in the status area explaining the file apon which action is taking place. */
+    private JLabel filename_label		 =  null;
+    /** The label shown explaining the current state of the file queue thread. */
+    private JLabel status_label		   =  null;
+    /** The label at the top of the workspace tree. */
+    private JLabel workspace_label		=  null;
+    /** The panel that contains the collection tree. */
+    private JPanel collection_pane		=  null;
+    /** The panel that contains the various controls including the status area. */
+    private JPanel control_pane		   =  null;
+    /** The panel that contains the workspace tree. */
+    private JPanel workspace_pane		 =  null;
+    /** The scrollable area into which the collection tree is placed. */
+    private JScrollPane collection_scroll =  null;
+    /** The scrollable area into which the workspace tree is placed. */
+    private JScrollPane workspace_scroll  =  null;
+    /** A split pane seperating the two trees, allowing for the screen real-estate for each to be changed. */
+    private JSplitPane tree_pane		  =  null;
+    /** Text fragment arguments used to fill in phrases returned from the dictionary. */
+    private String args[]				 =  null;
+    /** Ensures that expansion and selection events between collection trees based on the same model are synchronized. */
+    private TreeSynchronizer collection_tree_sync = null;
+    /** The button used to delete files, which also doubles as a drop target for files from the Trees. */
+    private RecycleBin bin_button			=  null;
+    /** The default size of a special mapping dialog. */
+    static final Dimension DIALOG_SIZE = new Dimension(400, 120);
+    /** The minimum size a gui component can become. */
+    static private Dimension MIN_SIZE	= new Dimension( 90,  90);
+    /** The default size of the status area. */
+    static private Dimension STATUS_SIZE = new Dimension(450, 120);
+    /** The initial size of the trees. */
+    static private Dimension TREE_SIZE   = new Dimension(400, 430);
+
+    /** The tree showing the available source workspace. */
+    private WorkspaceTree workspace_tree = null;
+
+
+    /* Constructor.
+     * @param tree_sync Ensures that expansion events between like trees are synchronized.
+     * @see org.greenstone.gatherer.file.FileManager
+     * @see org.greenstone.gatherer.file.FileQueue
+     */
+    public GatherPane(TreeSynchronizer collection_tree_sync) {
+	this.group = new DragGroup();
+	this.file_queue = Gatherer.f_man.getQueue();
+	this.collection_tree_sync = collection_tree_sync;
+
+	// Create components.
+	stop_action = new GLIButton();
+	stop_action.addActionListener(this);
+	stop_action.setEnabled(false);
+	stop_action.setMnemonic(KeyEvent.VK_S);
+	file_queue.registerStopButton(stop_action);
+	Dictionary.registerBoth(stop_action, "Collection.Stop", "Collection.Stop_Tooltip");
+	
+	new_folder = new GLIButton(JarTools.getImage("folder.gif"));
+	new_folder.addActionListener(this);
+	new_folder.setEnabled(false);
+	new_folder.setMinimumSize(MIN_SIZE);
+	new_folder.setMnemonic(KeyEvent.VK_N);
+	new_folder.setPreferredSize(MIN_SIZE);
+	Dictionary.registerTooltip(new_folder, "Collection.New_Folder_Tooltip");
+    }
+
+    /** Any implementation of ActionListener requires this method so that when an action is performed the appropriate effect can occur. In this case there are three valid possibilities. If the action occured on the recycle bin, then delete the current selection from the collection tree. If the action instead occured on the new folder button, then create a new folder under the current (single) selection in the collection tree. And finally if the cancel button was pressed, cancel the current, and remaining, jobs on the file queue. */
+    public void actionPerformed(ActionEvent event) {
+	// If a user has clicked on the bin button directly remove whatever
+	// files are selected in the active tree.
+	if(event.getSource() == bin_button) {
+	    if(!bin_button.ignore()) {
+		// Find the active tree (you've made selections in).
+		DragTree tree = (DragTree) group.getActive();
+		// Fudge things a bit
+		group.setSource(tree);
+		// Determine the selection.
+		TreePath paths[] = tree.getSelectionPaths();
+		if(paths != null) {
+		    FileNode[] source_nodes = new FileNode[paths.length];
+		    for(int i = 0; i < paths.length; i++) {
+			source_nodes[i] = (FileNode)(paths[i].getLastPathComponent());
+		    }
+		    Gatherer.f_man.action(tree, source_nodes, bin_button, null);
+		}
+	    }
+	}
+	// If a user has clicked on new_folder create a new folder under
+	// whatever node is selected.
+	else if(event.getSource() == new_folder && collection_tree != null) {
+	    int count = collection_tree.getSelectionCount();
+	    boolean error = false;
+	    if(count == 1) {
+		TreePath path = collection_tree.getSelectionPath();
+		CollectionTreeNode node = (CollectionTreeNode) path.getLastPathComponent();
+		if (node.getAllowsChildren()) {
+		    Gatherer.f_man.newFolder(collection_tree, node);
+		}
+		else {
+		    // try the parent
+		    CollectionTreeNode parent = (CollectionTreeNode) node.getParent();
+		    if (parent!=null && parent.getAllowsChildren()) {
+			Gatherer.f_man.newFolder(collection_tree, parent);
+		    } else {
+			error = true;
+		    }
+		}
+	    }
+	    else {
+		error = true;
+	    }
+	    if(error) {
+		// instead of an error, we now create a new folder at the root
+		CollectionTreeNode node = (CollectionTreeNode) collection_tree.getModel().getRoot();
+		Gatherer.f_man.newFolder(collection_tree, node);
+	    }
+	}
+	else if(event.getSource() == stop_action) {
+	    file_queue.cancelAction();
+	}
+    }
+
+
+    /** Generates the pane on controls used to 'collect' files into the collection. Resposible for creating, connecting and laying out these controls. */
+    public void display() {
+	// Create Components.
+	KeyListenerImpl key_listener = new KeyListenerImpl();
+	MouseListenerImpl mouse_listener = new MouseListenerImpl();
+	this.addKeyListener(key_listener);
+
+	// Workspace Tree
+	workspace_pane = new JPanel();
+	workspace_pane.setMinimumSize(MIN_SIZE);
+	workspace_pane.setPreferredSize(TREE_SIZE);
+	workspace_pane.setSize(TREE_SIZE);
+
+	workspace_label = new JLabel();
+	workspace_label.setOpaque(true);
+	workspace_label.setBackground(Configuration.getColor("coloring.workspace_heading_background", false));
+	workspace_label.setForeground(Configuration.getColor("coloring.workspace_heading_foreground", false));
+	Dictionary.registerText(workspace_label, "Collection.Workspace");
+
+	workspace_tree = new WorkspaceTree(Utility.WORKSPACE_TREE);
+	group.add(workspace_tree);
+	workspace_tree.addFocusListener(this);
+	workspace_tree.addKeyListener(key_listener);
+	workspace_tree.addMouseListener(mouse_listener);
+	workspace_tree.addMouseListener(Gatherer.g_man.foa_listener);
+	workspace_tree.addTreeExpansionListener(Gatherer.g_man.foa_listener);
+	workspace_tree.putClientProperty("JTree.lineStyle", "Angled");
+	workspace_tree.setBackgroundNonSelectionColor(Configuration.getColor("coloring.workspace_tree_background", false));
+	workspace_tree.setTextNonSelectionColor(Configuration.getColor("coloring.workspace_tree_foreground", false));
+	workspace_tree.setBackgroundSelectionColor(Configuration.getColor("coloring.workspace_selection_background", false));
+	workspace_tree.setTextSelectionColor(Configuration.getColor("coloring.workspace_selection_foreground", false));
+	workspace_tree.setRootVisible(false);
+
+	workspace_scroll = new JScrollPane(workspace_tree);
+
+	workspace_filter = Gatherer.g_man.getFilter(workspace_tree);
+	workspace_filter.setBackground(Configuration.getColor("coloring.workspace_heading_background", false));
+	workspace_filter.setEditable(Configuration.getMode() > Configuration.LIBRARIAN_MODE);
+	Dictionary.registerTooltip(workspace_filter.getComboBox(), "Collection.Filter_Tooltip");
+
+	// Collection Tree
+	collection_pane = new JPanel();
+	collection_pane.setMinimumSize(MIN_SIZE);
+	collection_pane.setPreferredSize(TREE_SIZE);
+	collection_pane.setSize(TREE_SIZE);
+
+	collection_label = new JLabel();
+	collection_label.setOpaque(true);
+	Dictionary.registerText(collection_label, "Collection.No_Collection");
+
+	collection_tree = new CollectionTree(Utility.COLLECTION_TREE, Gatherer.c_man.getCollectionTreeModel(), true);
+	collection_tree.setEnabled(Gatherer.c_man.getCollectionTreeModel() != null);
+	group.add(collection_tree);
+	collection_tree.addFocusListener(this);
+	collection_tree.addKeyListener(key_listener);
+	collection_tree.addMouseListener(mouse_listener);
+	collection_tree.addMouseListener(Gatherer.g_man.foa_listener);
+	collection_tree.addTreeExpansionListener(Gatherer.g_man.foa_listener);
+	collection_tree.putClientProperty("JTree.lineStyle", "Angled");
+	collection_tree.setBackgroundNonSelectionColor(Configuration.getColor("coloring.collection_tree_background", false));
+	collection_tree.setTextNonSelectionColor(Configuration.getColor("coloring.collection_tree_foreground", false));
+	collection_tree.setBackgroundSelectionColor(Configuration.getColor("coloring.collection_selection_background", false));
+	collection_tree.setTextSelectionColor(Configuration.getColor("coloring.collection_selection_foreground", false));
+	collection_tree.setRootVisible(false);
+
+	collection_scroll = new JScrollPane(collection_tree);
+
+	collection_filter = Gatherer.g_man.getFilter(collection_tree);
+	collection_filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+	collection_filter.setEditable(Configuration.getMode() > Configuration.LIBRARIAN_MODE);
+	Dictionary.registerTooltip(collection_filter.getComboBox(), "Collection.Filter_Tooltip");
+
+	tree_pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+
+	// Status pane
+	control_pane = new JPanel();
+
+	JPanel inner_pane = new JPanel();
+	inner_pane.setSize(STATUS_SIZE);
+
+	JPanel file_pane = new JPanel();
+	JPanel progress_pane = new JPanel();
+	JLabel file_status = file_queue.getFileStatus();
+
+	JProgressBar progress_bar = file_queue.getProgressBar();
+
+	JPanel button_pane = new JPanel();
+
+	bin_button = new RecycleBin();
+	bin_button.addActionListener(this);
+	bin_button.setEnabled(false);
+	bin_button.setMinimumSize(MIN_SIZE);
+	bin_button.setPreferredSize(MIN_SIZE);
+	Dictionary.registerTooltip(bin_button, "Collection.Delete_Tooltip");
+	group.add(bin_button);
+
+	// Layout Components.
+	workspace_pane.setLayout(new BorderLayout());
+	workspace_pane.add(workspace_label, BorderLayout.NORTH);
+	workspace_pane.add(workspace_scroll, BorderLayout.CENTER);
+	workspace_pane.add(workspace_filter, BorderLayout.SOUTH);
+
+	collection_pane.setLayout(new BorderLayout());
+	collection_pane.add(collection_label, BorderLayout.NORTH);
+	collection_pane.add(collection_scroll, BorderLayout.CENTER);
+	collection_pane.add(collection_filter, BorderLayout.SOUTH);
+
+	tree_pane.add(workspace_pane, JSplitPane.LEFT);
+	tree_pane.add(collection_pane, JSplitPane.RIGHT);
+	tree_pane.setDividerLocation(TREE_SIZE.width - 10);
+
+	file_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
+	file_pane.setLayout(new BorderLayout());
+	file_pane.add(file_status, BorderLayout.CENTER);
+	file_pane.add(stop_action, BorderLayout.EAST);
+
+	progress_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
+	progress_pane.setLayout(new BorderLayout());
+	progress_pane.add(progress_bar, BorderLayout.CENTER);
+
+	inner_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(10,10,10,10), BorderFactory.createLoweredBevelBorder()));
+	inner_pane.setLayout(new GridLayout(2,1));
+	inner_pane.add(file_pane);
+	inner_pane.add(progress_pane);
+
+	button_pane.add(new_folder);
+	button_pane.add(bin_button);
+
+	control_pane.setLayout(new BorderLayout());
+	control_pane.add(inner_pane, BorderLayout.CENTER);
+	control_pane.add(button_pane, BorderLayout.EAST);
+
+	this.setLayout(new BorderLayout());
+	this.add(tree_pane, BorderLayout.CENTER);
+	this.add(control_pane, BorderLayout.SOUTH);
+    }
+    /** This method ensures that a certain tree path is visible and selected within the collection tree, expanding nodes if necessary. If the method is successful the bounds of the new selection are returned. */
+    public Rectangle expandPath(TreePath path) {
+	collection_tree.setImmediate(true);
+	collection_tree.scrollPathToVisible(path);
+	collection_tree.setSelectionPath(path);
+	collection_tree.setImmediate(false);
+	return collection_tree.getRowBounds(collection_tree.getRowForPath(path));
+    }
+    /** 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());
+    }
+
+    /** Retrieve a list of the currently selected file records in the collection tree. */
+    private CollectionTreeNode[] getCollectionTreeSelection()
+    {
+	TreePath paths[] = collection_tree.getSelectionPaths();
+	CollectionTreeNode records[] = null;
+	if (paths != null) {
+	    records = new CollectionTreeNode[paths.length];
+	    for (int i = 0; i < records.length; i++) {
+		records[i] = (CollectionTreeNode) paths[i].getLastPathComponent();
+	    }
+	}
+	return records;
+    }
+
+    
+    /** 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);
+    }
+
+
+    /** Refresh this pane, depending on what has just happened (refresh_reason). */
+    public void refresh(int refresh_reason, boolean collection_loaded)
+    {
+	if (collection_loaded) {
+	    // Update collection label
+	    Dictionary.registerText(collection_label, "Collection.Collection");
+	    collection_label.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+	    collection_label.setForeground(Configuration.getColor("coloring.collection_heading_foreground", false));
+
+	    // Update collection tree
+	    if (refresh_reason == Gatherer.COLLECTION_OPENED) {
+		collection_tree.setModel(Gatherer.c_man.getCollectionTreeModel());
+	    }
+
+	    // Update collection filter
+	    collection_filter.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+	}
+	else {
+	    // Update collection label
+	    String[] args = new String[1];
+	    args[0] = Dictionary.get("Collection.No_Collection");
+	    Dictionary.registerText(collection_label, "Collection.Collection", args);
+	    collection_label.setBackground(Color.lightGray);
+	    collection_label.setForeground(Color.black);
+
+	    // Update collection tree
+	    collection_tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("Error")));
+
+	    // Update collection filter
+	    collection_filter.setBackground(Color.lightGray);
+	}
+
+	// Enable or disable the controls
+	workspace_tree.setEnabled(true);
+	collection_tree.setEnabled(collection_loaded);
+	collection_filter.setEnabled(collection_loaded);
+	bin_button.setEnabled(collection_loaded);
+	new_folder.setEnabled(collection_loaded);
+
+	// Ensure that this collection tree view is synchronized with all others
+	collection_tree_sync.add(collection_tree);
+    }
+
+
+    public void refreshCollectionTree(int refresh_reason) {
+	collection_tree.refresh(null);
+    }
+
+
+    public void refreshWorkspaceTree(int refresh_reason) {
+	workspace_tree.refresh(refresh_reason);
+    }
+    
+
+    /** When a user right-clicks within the workspace and collection trees they are presented with a small popup menu of context based options. This class provides such functionality.
+     */
+    private class RightClickMenu
+	extends JPopupMenu
+	implements ActionListener {
+
+	/** The tree over which the right click action occurred. */
+	private DragTree tree = null;
+	/** The tree nodes selected when the right click action occurred. */
+	private TreePath[] selection_paths = null;
+	/** The file record over which the right click action occurred. */
+	private FileNode node = null;
+
+	private JMenuItem create_shortcut = null;
+	private JMenuItem delete_shortcut = null;
+	private JMenuItem collapse_folder = null;
+	private JMenuItem expand_folder = null;
+	private JMenuItem explode_metadata_database = null;
+	private JMenuItem delete = null;
+	private JMenuItem metaaudit = null;
+	private JMenuItem new_folder = null;
+	private JMenuItem new_dummy_doc = null;
+	private JMenuItem open_externally = null;
+
+
+	private RightClickMenu(DragTree tree, MouseEvent event)
+	{
+	    super();
+	    this.tree = tree;
+
+	    // Note we have to use setImmediate() with the set selction paths
+	    // otherwise the selection doesn't get updated until after the 
+	    // popup comes up.
+
+	    // the right click position
+	    TreePath right_click_path = tree.getPathForLocation(event.getX(), event.getY());
+	    if (right_click_path == null) {
+		// user has clicked outside of the tree, clear the selection
+		selection_paths = null;
+		tree.setImmediate(true);
+		tree.clearSelection();
+		tree.setImmediate(false);
+	    } else {
+		// Get the paths currently selected in the tree
+		selection_paths = tree.getSelectionPaths();
+		if (selection_paths == null) {
+		    // nothing currently selected - we shift the selection to 
+		    // the node that was right clicked on
+		    selection_paths = new TreePath[1];
+		    selection_paths[0] = right_click_path;
+		    tree.setImmediate(true);
+		    tree.setSelectionPath(right_click_path);
+		    tree.setImmediate(false);
+		} else if (selection_paths.length == 1 && ! selection_paths[0].equals( right_click_path)) {
+		    tree.setImmediate(true);
+		    tree.clearSelection();
+		    tree.setSelectionPath(right_click_path);
+		    tree.setImmediate(false);
+		    selection_paths[0] = right_click_path;
+		} else {
+		    // we had multiply selected paths in the tree.
+		    // if we clicked on one of those paths, then use all the 
+		    // current selection, otherwise clear the selection and 
+		    // select the one we right clicked on
+		    boolean clicked_in_selection = false;
+		    for (int i=0; i<selection_paths.length; i++) {
+			if (selection_paths[i].equals(right_click_path)) {
+			    clicked_in_selection = true;
+			    break;
+			}
+		    }
+		    if (!clicked_in_selection) {
+			// want the tree to update right away
+			tree.setImmediate(true);
+			tree.clearSelection();
+			tree.setSelectionPath(right_click_path);
+			tree.setImmediate(false);
+			selection_paths = new TreePath[1];
+			selection_paths[0] = right_click_path;
+		    }
+		}
+	    }
+	    // finally we have the correct selection paths!
+	    
+	    // Create an appropriate context menu, based on what is selected
+	    buildContextMenu(selection_paths);
+
+	    // Show the popup menu on screen
+	    show(tree, event.getX(), event.getY());
+	}
+
+
+	private void buildContextMenu(TreePath[] selection_paths)
+	{
+	    // If nothing is selected, only the new folder/dummy doc options are available...
+	    if (selection_paths == null) {
+		// ... but only in the collection tree!
+		if (tree == collection_tree) {
+		    new_folder = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Folder"), KeyEvent.VK_N);
+		    new_folder.addActionListener(this);
+		    add(new_folder);
+
+		    new_dummy_doc = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Dummy_Doc"));
+		    new_dummy_doc.addActionListener(this);
+		    add(new_dummy_doc);
+
+		    node = (CollectionTreeNode) tree.getModel().getRoot();
+		}
+
+		return;
+	    }
+
+	    DebugStream.println("Number of files/folders selected: " + selection_paths.length);
+
+	    // Collection tree: display meta-audit option and delete options
+	    if (tree == collection_tree) {
+		String[] args = new String[1];
+		args[0] = collection_tree.getSelectionDetails();
+		metaaudit = new JMenuItem(Dictionary.get("Menu.Metadata_View", args), KeyEvent.VK_A);
+		metaaudit.addActionListener(this);
+		add(metaaudit);
+
+		delete = new JMenuItem(Dictionary.get("CollectionPopupMenu.Delete"), KeyEvent.VK_D);
+		delete.addActionListener(this);
+		add(delete);
+	    }
+
+	    // Only meta-audit and delete are available if multiple items are selected...
+	    if (selection_paths.length > 1) {
+		return;
+	    }
+
+	    TreePath path = selection_paths[0];
+	    node = (FileNode) path.getLastPathComponent();
+
+	    // ---- Options for file nodes ----
+	    if (node.isLeaf()) {
+		// Explode metadata databases, for collection tree only, and for explodable files only
+		if (tree == collection_tree && ((CollectionTreeNode) node).isExplodable()) {
+		    explode_metadata_database = new JMenuItem(Dictionary.get("Menu.Explode_Metadata_Database"), KeyEvent.VK_E);
+		    explode_metadata_database.addActionListener(this);
+		    add(explode_metadata_database);
+		}
+
+		// Open the file in an external program
+		open_externally = new JMenuItem(Dictionary.get("Menu.Open_Externally"), KeyEvent.VK_O);
+		open_externally.addActionListener(this);
+		add(open_externally);
+
+		return;
+	    }
+
+	    // ---- Options for folder nodes ----
+	    // Collapse or expand, depending on current status
+	    if (tree.isExpanded(path)) {
+		collapse_folder = new JMenuItem(Dictionary.get("Menu.Collapse"), KeyEvent.VK_C);
+		collapse_folder.addActionListener(this);
+		add(collapse_folder);
+	    }
+	    else {
+		expand_folder = new JMenuItem(Dictionary.get("Menu.Expand"), KeyEvent.VK_O);
+		expand_folder.addActionListener(this);
+		add(expand_folder);
+	    }
+
+	    // New folder/dummy doc options, for collection tree only
+	    if (tree == collection_tree && !node.isReadOnly()) {
+		new_folder = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Folder"), KeyEvent.VK_N);
+		new_folder.addActionListener(this);
+		add(new_folder);
+		new_dummy_doc = new JMenuItem(Dictionary.get("CollectionPopupMenu.New_Dummy_Doc"));
+		new_dummy_doc.addActionListener(this);
+		add(new_dummy_doc);
+	    }
+
+	    // Create/remove shortcut option, for workspace tree only
+	    if (tree == workspace_tree) {
+		// The "built-in" folders can't be modified
+		String node_name = node.toString();
+		if (node_name.equals(Dictionary.get("Tree.World")) || node_name.equals(Dictionary.get("Tree.Root")) || node_name.equals(Dictionary.get("Tree.DownloadedFiles"))) {
+		    return;
+		}
+
+		// You can unmap 1st level nodes
+		WorkspaceTreeNode root = (WorkspaceTreeNode) tree.getModel().getRoot();
+		if (root.getIndex(node) != -1) {
+		    delete_shortcut = new JMenuItem(Dictionary.get("MappingPrompt.Unmap"), KeyEvent.VK_R);
+		    delete_shortcut.addActionListener(this);
+		    add(delete_shortcut);
+		}
+		// Or map any other level directories
+		else {
+		    create_shortcut = new JMenuItem(Dictionary.get("MappingPrompt.Map"), KeyEvent.VK_S);
+		    create_shortcut.addActionListener(this);
+		    add(create_shortcut);
+		}
+	    }
+	}
+
+
+	/** Called whenever one of the menu items is clicked, this method then causes the appropriate effect. */
+	public void actionPerformed(ActionEvent event)
+	{
+  	    Object source = event.getSource();
+
+	    // Create shortcut
+	    if (source == create_shortcut) {
+ 		MappingPrompt mp = new MappingPrompt(node.getFile());
+ 		mp.destroy();
+	    }
+
+	    // Delete shortcut
+  	    else if (source == delete_shortcut) {
+  		workspace_tree.removeDirectoryMapping((WorkspaceTreeNode) node);
+  	    }
+
+	    // Collapse folder
+	    else if (source == collapse_folder) {
+		tree.collapsePath(selection_paths[0]);
+	    }
+
+	    // Expand folder
+	    else if (source == expand_folder) {
+		tree.expandPath(selection_paths[0]);
+	    }
+
+	    // Explode metadata database
+	    else if (source == explode_metadata_database) {
+		ExplodeMetadataPrompt emp = new ExplodeMetadataPrompt(node.getFile());
+		//emp.destroy();
+	    }
+
+	    // Delete
+	    else if (source == delete) {
+		FileNode[] source_nodes = new FileNode[selection_paths.length];
+		for (int i = 0; i < selection_paths.length; i++) {
+		    source_nodes[i] = (FileNode) selection_paths[i].getLastPathComponent();
+		}
+
+		// Fire a delete action
+		Gatherer.f_man.action(tree, source_nodes, bin_button, null);
+	    }
+
+	    // Meta-audit
+	    else if (source == metaaudit) {
+ 		Gatherer.g_man.showMetaAuditBox();
+ 	    }
+
+	    // New folder
+  	    else if (source == new_folder) {
+ 		Gatherer.f_man.newFolder(tree, (CollectionTreeNode) node);
+ 	    }
+	    // New dummy doc
+	    else if (source == new_dummy_doc) {
+		Gatherer.f_man.newDummyDoc(tree, (CollectionTreeNode) node);
+	    }
+	    // Open in external program
+	    else if (source == open_externally) {
+		Gatherer.f_man.openFileInExternalApplication(node.getFile());
+	    }
+  	}
+    }
+
+
+    /** This class listens for certain key presses, such as [Enter] or [Delete], and responds appropriately. */
+    private class KeyListenerImpl
+	extends KeyAdapter {
+	private boolean vk_left_pressed = false;
+	/** Called whenever a key that was pressed is released, it is this action that will cause the desired effects (this allows for the key event itself to be processed prior to this listener dealing with it). */
+	public void keyReleased(KeyEvent event) {
+	    ///ystem.err.println("Key Release detected. " + event.getKeyCode());
+	    if(event.getKeyCode() == KeyEvent.VK_DELETE) {
+		// Get the selected files from the tree and removal them using the default dnd removal method.
+		// Find the active tree (you've made selections in).
+		DragTree tree = (DragTree) group.getActive();
+		// Fudge things a bit
+		group.setSource(tree);
+		// Determine the selection.
+		TreePath paths[] = tree.getSelectionPaths();
+		if(paths != null) {
+		    FileNode[] source_nodes = new FileNode[paths.length];
+		    for(int i = 0; i < source_nodes.length; i++) {
+			source_nodes[i] = (FileNode) paths[i].getLastPathComponent();
+		    }
+		    Gatherer.f_man.action(tree, source_nodes, bin_button, null);
+		    source_nodes = null;
+		}
+	    }
+	    else if(event.getKeyCode() == KeyEvent.VK_ENTER) {
+		// Get the first selected file.
+		DragTree tree = (DragTree)event.getSource();
+		TreePath path = tree.getSelectionPath();
+		if(path != null) {
+		    File file = ((FileNode)path.getLastPathComponent()).getFile();
+		    if (file != null && file.isFile()) {
+			Gatherer.f_man.openFileInExternalApplication(file);
+		    }
+		    else {
+			if(!tree.isExpanded(path)) {
+			    tree.expandPath(path);
+			}
+			else {
+			    tree.collapsePath(path);
+			}
+		    }
+		}
+	    } else if (event.getKeyCode() == KeyEvent.VK_UP || event.getKeyCode() == KeyEvent.VK_DOWN) {
+		DragTree tree = (DragTree)event.getSource();
+		// we need to manually do the up and down selections
+		boolean up = (event.getKeyCode() == KeyEvent.VK_UP);
+		int current_row = tree.getLeadSelectionRow();
+		tree.setImmediate(true);
+		if (up) {
+		    if (current_row > 0) {
+			tree.clearSelection();
+			tree.setSelectionRow(current_row-1);
+		    }
+		} else {
+		    if (current_row < tree.getRowCount()-1){
+			tree.clearSelection();
+			tree.setSelectionRow(current_row+1);
+		    }
+		}
+		tree.setImmediate(false);
+	    } else if (event.getKeyCode() == KeyEvent.VK_LEFT) {
+		// left key on a file shifts the selection to the parent folder
+		DragTree tree = (DragTree)event.getSource();
+		TreePath path = tree.getLeadSelectionPath();
+		if(path != null) {
+		    File file = ((FileNode)path.getLastPathComponent()).getFile();
+		    if(file != null) {
+			if (file.isFile() || vk_left_pressed) {
+			    vk_left_pressed = false;
+			    TreePath parent_path = path.getParentPath();
+			    if (parent_path != null && parent_path.getParentPath() != null) {
+				// if this file is in the top level folder, don't move the focus 
+				tree.setImmediate(true);
+				tree.clearSelection();
+				tree.setSelectionPath(parent_path);
+				tree.setImmediate(false);
+			    }
+			}
+		    }
+		}
+	    }
+	}
+	
+	// we need to watch for left clicks on an unopened folder - should shift the focus to teh 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) {
+		// left key on  closed directory shifts the selection to the parent folder
+		DragTree tree = (DragTree)event.getSource();
+		TreePath path = tree.getLeadSelectionPath();
+		if(path == null) return; 
+		File file = ((FileNode)path.getLastPathComponent()).getFile();
+		if(file == null) return;
+		
+		if (file.isDirectory() && tree.isCollapsed(path)) {
+		    vk_left_pressed = true;
+		}
+	    }
+	}	
+    }
+    
+    /** This provides a small prompt for gathering addition details about a special directory mapping such as its symbolic name. 
+     * Used when creating a new shortcut to a folder */
+    private class MappingPrompt
+	extends JDialog
+	implements ActionListener, KeyListener {
+	private boolean cancelled = false;
+	private JButton cancel_button = null;
+	private JButton ok_button = null;
+	private JTextField name_field = null;
+	public MappingPrompt(File file) {
+	    super(Gatherer.g_man);
+	    setModal(true);
+	    setSize(DIALOG_SIZE);
+	    Dictionary.setText(this, "MappingPrompt.Title");
+
+	    // Creation
+	    JPanel content_pane = (JPanel) getContentPane();
+	    JPanel center_pane = new JPanel();
+	    JPanel labels_pane = new JPanel();
+	    JPanel fields_pane = new JPanel();
+
+	    JLabel file_label = new JLabel();
+	    Dictionary.setText(file_label, "MappingPrompt.File");
+	    JLabel file_field = new JLabel(file.getAbsolutePath());
+
+	    JLabel name_label = new JLabel();
+	    Dictionary.setText(name_label, "MappingPrompt.Name");
+	    name_field = new JTextField(file.getName());
+
+	    JPanel button_pane = new JPanel();
+	    ok_button = new GLIButton();
+	    ok_button.setEnabled(name_field.getText().length() > 0);
+	    ok_button.setMnemonic(KeyEvent.VK_O);
+	    Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	    cancel_button = new GLIButton();
+	    cancel_button.setMnemonic(KeyEvent.VK_C);
+	    Dictionary.setBoth(cancel_button, "General.Cancel", "General.Cancel_Tooltip");
+
+	    // Connection
+	    cancel_button.addActionListener(this);
+	    ok_button.addActionListener(this);
+	    name_field.addKeyListener(this);
+
+	    // Layout
+	    labels_pane.setLayout(new GridLayout(2,1,5,0));
+	    labels_pane.add(file_label);
+	    labels_pane.add(name_label);
+	    
+	    fields_pane.setLayout(new GridLayout(2,1,5,0));
+	    fields_pane.add(file_field);
+	    fields_pane.add(name_field);
+
+	    center_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    center_pane.setLayout(new BorderLayout(5,0));
+	    center_pane.add(labels_pane, BorderLayout.WEST);
+	    center_pane.add(fields_pane, BorderLayout.CENTER);
+
+	    button_pane.setLayout(new GridLayout(1,2,5,5));
+	    button_pane.add(ok_button);
+	    button_pane.add(cancel_button);
+
+	    content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    content_pane.setLayout(new BorderLayout());
+	    content_pane.add(center_pane, BorderLayout.CENTER);
+	    content_pane.add(button_pane, BorderLayout.SOUTH);
+	    // Display
+	    Dimension screen_size = Configuration.screen_size;
+	    setLocation((screen_size.width - DIALOG_SIZE.width) / 2, (screen_size.height - DIALOG_SIZE.height) / 2);
+	    setVisible(true);
+	    // If not cancelled create mapping.
+	    if (!cancelled) {
+		workspace_tree.addDirectoryMapping(name_field.getText(), file);
+	    }
+	}
+	public void actionPerformed(ActionEvent event) {
+	    if(event.getSource() == cancel_button) {
+		cancelled = true;
+	    }
+	    dispose();
+	}
+	public void destroy() {
+	    cancel_button = null;
+	    ok_button = null;
+	    name_field = null;
+	}
+	public void keyPressed(KeyEvent event) {
+	}
+	public void keyReleased(KeyEvent event) {
+	    ok_button.setEnabled(name_field.getText().length() > 0);
+
+	}
+	public void keyTyped(KeyEvent event) {
+	}
+    }
+
+    /** This class listens for mouse clicks and responds right mouse button clicks (popup menu). */
+    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 mouseClicked(MouseEvent event) {
+	    if (SwingUtilities.isRightMouseButton(event)) {
+		new RightClickMenu((DragTree) event.getSource(), event);
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/HelpFrame.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/HelpFrame.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/HelpFrame.java	(revision 10506)
@@ -0,0 +1,358 @@
+/**
+ *#########################################################################
+ *
+ * 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>
+ *
+ * Principal Author: John Thompson, NZDL Project, 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.gatherer.gui;
+
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/**
+ * This class provides a nice help facility. It is a separate frame that can be positioned
+ * as the user wishes, and provides a contents page and the help information.
+ * @author Michael Dewsnip, NZDL Project
+ */
+public class HelpFrame 
+    extends JFrame {
+
+    static private final String NULL_STRING = "<null>";
+    /** The size of the frame */
+    static private final Dimension SIZE = new Dimension(760, 560);
+
+    static private HelpFrame self = null;
+
+    /** The HTML rendering pane */
+    private JEditorPane view = null;
+    /** The contents tree model */
+    private ContentsModel model = null;
+    /** A contents tree for the top of the frame */
+    private JTree contents = null;
+
+    private JSplitPane split_pane = null;
+
+
+    public HelpFrame()
+    {
+	setDefaultCloseOperation(HIDE_ON_CLOSE);
+	setSize(SIZE);
+	Dictionary.registerText(this, "Help.Title");
+
+	view = new JEditorPane();
+	view.setEditable(false);
+	view.addHyperlinkListener(new ViewHyperlinkListener());
+
+	HelpItem rootNode = new HelpItem(Dictionary.get("Help.Contents"), NULL_STRING);
+	model = new ContentsModel(rootNode);
+	contents = new JTree((DefaultTreeModel) model);
+	contents.addTreeSelectionListener(new ContentsListener());
+	contents.setExpandsSelectedPaths(true);
+
+	// Creation
+	JPanel content_pane = (JPanel) this.getContentPane();
+	split_pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+	JScrollPane index_scroll = new JScrollPane(contents);
+	JScrollPane view_scroll = new JScrollPane(view);
+
+	// Layout
+	split_pane.add(index_scroll, JSplitPane.LEFT);
+	split_pane.add(view_scroll, JSplitPane.RIGHT);
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(split_pane, BorderLayout.CENTER);
+
+	// Center
+	Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+
+	// Pretty corner icon
+	this.setIconImage(JarTools.getImage("gatherer_small.gif").getImage());
+
+	self = this;
+    }
+
+
+    public void destroy()
+    {
+	view = null;
+	contents = null;
+    }
+
+
+    /** Retrieve the full file path to the help index xml file.
+     * @return the full path as a String
+     */
+    private String getHelpFolder()
+    {
+	String help_folder = "help/" + Configuration.getLanguage() + "/";
+
+	// Try in the JAR/classes directory first
+	URL help_folder_url = JarTools.getResource("/" + help_folder);
+	if (help_folder_url != null) {
+	    return help_folder;
+	}
+
+	// Look in the base directory next
+	File help_folder_file = new File(help_folder);
+	if (help_folder_file.exists()) {
+	    return help_folder;
+	}
+
+	// Resort to English
+	return "help/" + StaticStrings.ENGLISH_LANGUAGE_STR  + "/";
+    }
+
+
+    static public void setView(String section_name)
+    {
+	self.setViewInternal(section_name);
+    }
+
+
+    public void setViewInternal(String sectionName)
+    {
+	// Find the node in the tree with the specified sectionName
+	HelpItem node = model.getHelpItemNamed(sectionName);
+
+	// Ensure the node is selected and visible
+	TreePath path = new TreePath(node.getPath());
+	contents.setSelectionPath(path);
+	contents.scrollPathToVisible(path);
+
+	// Display the selected page
+	URL url = node.getURL();
+	if (url != null) {
+	    try {
+		view.setPage(url);
+	    }
+	    catch (Exception exception) {
+		DebugStream.printStackTrace(exception);
+	    }
+	}
+
+	// Make the help frame visible
+	setVisible(true);
+	split_pane.setDividerLocation(0.2);
+    }
+
+
+    private class ContentsModel
+	extends DefaultTreeModel {
+
+	public ContentsModel(MutableTreeNode rootNode) {
+	    super(rootNode);
+
+	    // Load the XML help file and build the contents structure from it
+	    try {
+		String help_index = getHelpFolder() + StaticStrings.HELP_INDEX_FILENAME;
+		Document document = XMLTools.parseXMLFile(help_index, true);
+
+		// Traverse the document hierarchy, building a tree representing its structure
+		Node documentNode = document.getFirstChild();
+
+		int sectionNum = 0;
+		NodeList children = documentNode.getChildNodes();
+		for (int i = 0; i < children.getLength(); i++) {
+		    Node child = children.item(i);
+		    if (child.getNodeName().equals(StaticStrings.SECTION_ELEMENT)) {
+			sectionNum++;
+			buildContentsHierarchy(rootNode, sectionNum + StaticStrings.EMPTY_STR, child);
+		    }
+		}
+	    }
+	    catch (Exception ex) {
+		ex.printStackTrace();
+	    }
+	}
+
+
+	public void buildContentsHierarchy(MutableTreeNode parent, String pos, Node node)
+	{
+	    // Determine the section name
+	    String sectionName = ((Element) node).getAttribute(StaticStrings.NAME_ATTRIBUTE);
+
+	    // Determine the section title
+	    String sectionTitle = "";
+	    NodeList children = node.getChildNodes();
+	    for (int i = 0; i < children.getLength(); i++) {
+		Node child = children.item(i);
+		if (child.getNodeName().equals(StaticStrings.TITLE_ELEMENT)) {
+		    sectionTitle = pos + ": ";
+		    if (child.getFirstChild() != null) {
+			sectionTitle = sectionTitle + child.getFirstChild().getNodeValue();
+		    }
+		}
+	    }
+
+	    // Add the node into the tree
+	    HelpItem item = new HelpItem(sectionTitle, sectionName);
+	    insertNodeInto(item, parent, parent.getChildCount());
+
+	    // Apply recursively to the children of this node
+	    int sectionNum = 0;
+	    for (int i = 0; i < children.getLength(); i++) {
+		Node child = children.item(i);
+		if (child.getNodeName().equals(StaticStrings.SECTION_ELEMENT)) {
+		    sectionNum++;
+		    buildContentsHierarchy(item, pos + StaticStrings.STOP_CHARACTER + sectionNum, child);
+		}
+	    }
+	}
+
+
+	public HelpItem getHelpItemNamed(String sectionName)
+	{
+	    // Find the node with name matching sectionName, somewhere in the tree
+	    Enumeration descendants = ((DefaultMutableTreeNode) root).preorderEnumeration();
+	    while (descendants.hasMoreElements()) {
+		HelpItem node = (HelpItem) descendants.nextElement();
+		if (node.name.equals(sectionName)) {
+		    return node;
+		}
+	    }
+
+	    // Couldn't be found, so just return the root (Contents) node
+	    return (HelpItem) root;
+	}
+    }
+
+
+    /** This listener is used to listen for selection changes in the contents tree, and
+     * to show the appropriate page as required.
+     */
+    private class ContentsListener
+	implements TreeSelectionListener {
+
+	/** Any implementation of <i>TreeSelectionListener</i> must include this method so we can be informed when the tree selection changes.
+	 * @param event A <strong>TreeSelectionEvent</strong> containing al the relevant information about the event itself.
+	 */
+	public void valueChanged(TreeSelectionEvent event)
+	{
+	    TreePath path = event.getPath();
+	    HelpItem node = (HelpItem) path.getLastPathComponent();
+	    URL url = node.getURL();
+	    if (url != null) {
+		try {
+		    view.setPage(url);
+		}
+		catch (Exception exception) {
+		    DebugStream.printStackTrace(exception);
+		}
+	    }
+	}
+    }
+
+
+    /** This class provides a wrapper around a <strong>DefaultMutableTreeNode</strong> which
+     * provides the ability to set an html page to be loaded when this node is selected.
+     */
+    private class HelpItem 
+	extends DefaultMutableTreeNode {
+
+	/** The unique name of the section (matches the HTML filename) */
+	public String name = null;
+	/** The title to be displayed for this tree node. */
+	public String title = null;
+
+
+	/** Constructor.
+	 * @param title The title to be shown for this node as a <strong>String</strong>.
+	 * @param name The name of the section as a <strong>String</strong>.
+	 */
+	public HelpItem(String title, String name)
+	{
+	    this.name = name;
+	    this.title = title;
+	}
+
+
+	/** Method to create a url from the file name.
+	 * @return A <strong>URL</strong> that points to the file's location.
+	 */
+	public URL getURL()
+	{
+	    URL url = null;
+
+	    String help_file = getHelpFolder() + name + StaticStrings.HTM_FILE_EXTENSION;
+
+	    if (name != null && !name.equals(NULL_STRING)) {
+		url = JarTools.getResource("/" + help_file);
+		if (url == null) {
+		    File file = new File(Gatherer.getGLIUserDirectoryPath() + help_file);
+		    try {
+			url = file.toURL();
+		    }
+		    catch (Exception ex) {
+			ex.printStackTrace();
+		    }
+		}
+	    }
+
+	    return url;
+	}
+
+
+	public String toString()
+	{
+	    return title;
+	}
+    }
+
+
+    private class ViewHyperlinkListener
+	implements HyperlinkListener {
+	public void hyperlinkUpdate(HyperlinkEvent e) {
+	    if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+		try {
+		    view.setPage(e.getURL());
+		}
+		catch(Exception exception) {
+		    DebugStream.printStackTrace(exception);
+		}
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/LockFileDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/LockFileDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/LockFileDialog.java	(revision 10506)
@@ -0,0 +1,227 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+/** A lock file dialog is shown whenever GLI detects an existing lock on a collection it is trying to open. The user can look at the details provided with the dialog, and decide whether to 'steal' the lock or to cancel the loading. */
+public class LockFileDialog
+    extends ModalDialog {
+
+    private int choice;
+    private Document document;
+    private JButton cancel_button;
+    private JButton ok_button;
+    private LockFileDialog self;
+
+    static final public int NO_OPTION  = 0;
+    static final public int YES_OPTION = 1;
+
+    static final private Dimension LABEL_SIZE = new Dimension(100, 25);
+    static final private Dimension SIZE = new Dimension(500, 250);
+    static final private int ICON_SIZE = 30;
+
+    public LockFileDialog(JFrame parent, String name, File lock_file) {
+	super(parent, Dictionary.get("LockFileDialog.Title"), true);
+	setSize(SIZE);
+	setJMenuBar(new SimpleMenuBar("openingacollection"));
+	this.self = this;
+
+	// Parse the lock file
+	document = XMLTools.parseXMLFile(lock_file);
+
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+	JPanel upper_pane = new JPanel();
+	ImageIcon icon = JarTools.getImage("lcolicn.gif");
+	ImageIcon scaled_icon = new ImageIcon(icon.getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_DEFAULT));
+	JLabel icon_label = new JLabel(scaled_icon);
+	JPanel title_pane = new JPanel();
+	JLabel title_one_label = new JLabel();
+	Dictionary.setText(title_one_label, "General.Warning"); 
+	JTextArea title_two_textarea = new JTextArea();
+	title_two_textarea.setEditable(false);
+	title_two_textarea.setLineWrap(true);
+	title_two_textarea.setOpaque(false);
+	title_two_textarea.setRows(3);
+	title_two_textarea.setWrapStyleWord(true);
+	Dictionary.setText(title_two_textarea, "LockFileDialog.Lockfile_Message_One");
+	JPanel central_pane = new JPanel();
+
+	JPanel name_pane = new JPanel();
+	JLabel name_label = new JLabel();
+	name_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.setText(name_label, "LockFileDialog.Name");
+	JTextField name_field = new JTextField(name);
+	name_field.setEditable(false);
+	name_field.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+
+	JPanel person_pane = new JPanel();
+	JLabel person_label = new JLabel();
+	person_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.setText(person_label, "LockFileDialog.User");
+	JTextField person_field = new JTextField(getValue("User"));
+	person_field.setEditable(false);
+	person_field.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+
+	JPanel machine_pane = new JPanel();
+	JLabel machine_label = new JLabel();
+	machine_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.setText(machine_label, "LockFileDialog.Machine");
+	JTextField machine_field = new JTextField(getValue("Machine"));
+	machine_field.setEditable(false);
+	machine_field.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+
+	JPanel created_pane = new JPanel();
+	JLabel created_label = new JLabel();
+	created_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.setText(created_label, "LockFileDialog.Date");
+	JTextField created_field = new JTextField(getValue("Date"));
+	created_field.setEditable(false);
+	created_field.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+
+	JLabel central_label = new JLabel();
+	Dictionary.setText(central_label, "LockFileDialog.Lockfile_Message_Two");
+	JPanel button_pane = new JPanel();
+	ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_O);
+	Dictionary.setBoth(ok_button, "General.OK", "LockFileDialog.OK_Tooltip");
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Cancel", "LockFileDialog.Cancel_Tooltip");
+
+	// Connection
+	ok_button.addActionListener(new MyActionListener());
+	cancel_button.addActionListener(new MyActionListener());
+
+	// Layout
+	icon_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,10));
+
+	title_pane.setLayout(new BorderLayout());
+	title_pane.add(title_one_label, BorderLayout.NORTH);
+	title_pane.add(title_two_textarea, BorderLayout.CENTER);
+
+	upper_pane.setLayout(new BorderLayout());
+	upper_pane.add(icon_label, BorderLayout.WEST);
+	upper_pane.add(title_pane, BorderLayout.CENTER);
+
+	name_pane.setLayout(new BorderLayout());
+	name_pane.add(name_label, BorderLayout.WEST);
+	name_pane.add(name_field, BorderLayout.CENTER);
+
+	person_pane.setLayout(new BorderLayout());
+	person_pane.add(person_label, BorderLayout.WEST);
+	person_pane.add(person_field, BorderLayout.CENTER);
+
+	machine_pane.setLayout(new BorderLayout());
+	machine_pane.add(machine_label, BorderLayout.WEST);
+	machine_pane.add(machine_field, BorderLayout.CENTER);
+
+	created_pane.setLayout(new BorderLayout());
+	created_pane.add(created_label, BorderLayout.WEST);
+	created_pane.add(created_field, BorderLayout.CENTER);
+
+	central_pane.setLayout(new GridLayout(5,1,0,5));
+	central_pane.add(name_pane);
+	central_pane.add(person_pane);
+	central_pane.add(machine_pane);
+	central_pane.add(created_pane);
+	central_pane.add(central_label);
+
+	button_pane.setLayout(new GridLayout(1,2,5,0));
+	button_pane.add(ok_button);
+	button_pane.add(cancel_button);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(upper_pane, BorderLayout.NORTH);
+	content_pane.add(central_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	// Display
+	if (parent != null) {
+	    Rectangle frame_bounds = parent.getBounds();
+	    setLocation(frame_bounds.x + (frame_bounds.width - SIZE.width) / 2, frame_bounds.y + (frame_bounds.height - SIZE.height) / 2);
+	}
+	else {
+	    Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+	    setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	}
+    }
+
+    public int getChoice() {
+	setVisible(true);
+	return choice;
+    }
+
+    private String getValue(String name) {
+	String value = "";
+	if(document != null) {
+	    try {
+		Element value_element = (Element) XMLTools.getNodeFromNamed(document.getDocumentElement(), name);
+		value = XMLTools.getValue(value_element);
+	    }
+	    catch (Exception error) {
+	    }
+	}
+	else {
+	    value = Dictionary.get("LockFileDialog.Error");
+	}
+	return value;
+    }
+
+    private class MyActionListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    if(event.getSource() == ok_button) {
+		choice = YES_OPTION;
+	    }
+	    else {
+		choice = NO_OPTION;
+	    }
+	    self.dispose();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/LongProgressBar.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/LongProgressBar.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/LongProgressBar.java	(revision 10506)
@@ -0,0 +1,245 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, Greenstone Digital Library, University of Waikato
+ *
+ * Copyright (C) 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.gatherer.gui;
+
+import java.math.BigInteger;
+import javax.swing.JProgressBar;
+import javax.swing.SwingUtilities;
+
+/** A progress bar that doesn't pack a sad when you feed it longs (such as the sizes of files) which get mangled into negative numbers. I know how it feels, as I often have negative progress. Also tries to be efficent when updating the JProgressBar, so only updates when the value actually changes, which become necessary when you move a large number of files with millions of bytes (where upon shifting a file of a thousand bytes would be pretty insignificant, maybe not even a percent, but would fire several progress updates). 
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3c
+ */
+final public class LongProgressBar
+    extends JProgressBar {
+    private BigInteger cur_value = null;
+    private BigInteger max_value = null;
+    private BigInteger min_value = null;
+    /** The previous percentage value. */
+    private int previous = -1;
+    private SafeSetIndeterminate safe_set_indeterminate = null;
+    private SafeSetString safe_set_string = null;
+    private SafeSetValue safe_set_value = null;
+
+    public LongProgressBar() {
+	super(0, 100);
+	cur_value = BigInteger.ZERO;
+	min_value = BigInteger.ZERO;
+	max_value = BigInteger.ZERO;
+    }
+
+    public void addMaximum(int size) {
+	///ystem.err.println("Add maximum " + size);
+	if(size > 0) {
+	    max_value = max_value.add(new BigInteger((new Integer(size)).toString()));
+	    update();
+	}
+    }
+
+    public void addMaximum(long size) {
+	///ystem.err.println("Add maximum " + size);
+	if(size > 0) {
+	    max_value = max_value.add(new BigInteger((new Long(size)).toString()));
+	    update();
+	}
+    }
+
+    public void addValue(int size) {
+	///ystem.err.println("Add value " + size);
+	if(size > 0) {
+	    cur_value = cur_value.add(new BigInteger((new Integer(size)).toString()));
+	    update();
+	}
+    }
+
+    public void addValue(long size) {
+	///ystem.err.println("Add value " + size);
+	if(size > 0) {
+	    cur_value = cur_value.add(new BigInteger((new Long(size)).toString()));
+	    update();
+	}
+    }
+
+    public void clear()
+    {
+	previous = -1;
+	update();
+    }
+
+    public void reset() {
+	cur_value = BigInteger.ZERO;
+	max_value = BigInteger.ZERO;
+	previous = -1;
+	update();
+    }
+
+    public void setIndeterminate(boolean state) {
+	if(safe_set_indeterminate == null) {
+	    safe_set_indeterminate = new SafeSetIndeterminate(state);
+	}
+	else {
+	    safe_set_indeterminate.setState(state);
+	}
+	SwingUtilities.invokeLater(safe_set_indeterminate);		  
+    }
+
+    public void setMaximum(int size) {
+	///ystem.err.println("Add maximum " + size);
+	if(size > 0) {
+	    max_value = new BigInteger((new Integer(size)).toString());
+	    update();
+	}
+    }
+
+    public void setMaximum(long size) {
+	///ystem.err.println("Add maximum " + size);
+	if(size > 0) {
+	    max_value = new BigInteger((new Long(size)).toString());
+	    update();
+	}
+    }
+
+    public void setString(String label) {
+	safeSetString(label);
+    }
+	 
+    public void setValue(int size) {
+	///ystem.err.println("Set value " + size);
+	cur_value = new BigInteger((new Integer(size)).toString());
+	update();
+    }
+
+    public void setValue(long size) {
+	///ystem.err.println("Set value " + size);
+	cur_value = new BigInteger((new Long(size)).toString());
+	update();
+    }
+
+    /** This method is an unsafe way to set the progress bar to be indeterminate, -unless- it is called from the Event Queue. */
+    private void unsafeSetIndeterminate(boolean state) {
+	super.setIndeterminate(state);
+    }
+
+    private void unsafeSetString(String label) {
+	super.setString(label);
+    }
+
+    private void unsafeSetValue(int value) {
+	super.setValue(value);
+    }
+
+    private void update() {
+	int percentage = -1;
+	if(cur_value.equals(BigInteger.ZERO) || max_value.equals(BigInteger.ZERO)) {
+	    percentage = 0;
+	}
+	else {
+	    BigInteger tmp_value = cur_value.multiply(new BigInteger("100"));
+	    BigInteger per_value = tmp_value.divide(max_value);
+	    percentage = per_value.intValue();
+	    if(percentage > 100) {
+		percentage = 100;
+	    }
+	}
+	if(percentage != previous) {
+	    ///ystem.err.println("Progress bar status: value = " + getValue());
+	    previous = percentage;
+	    safeSetValue(percentage);
+	    safeSetString(percentage + "%");
+	}
+    }
+    /** Change the string displayed on the progress bar.
+     * @param label The name progress bar label as a <strong>String</strong>.
+     * Original code: Tad Frysinger (TeamB)
+     */
+    private void safeSetString(String label) {
+	if(safe_set_string == null) {
+	    safe_set_string = new SafeSetString(label);
+	}
+	else {
+	    safe_set_string.setLabel(label);
+	}
+	SwingUtilities.invokeLater(safe_set_string);  
+    }
+	 
+    /** Increase the value of the progress bar.
+     * @param ammount The ammount to increase as an <i>int</i>.
+     * Original code: Tad Frysinger (TeamB)
+     */
+    private void safeSetValue(final int ammount) {
+	// Update progress bar,
+	if(safe_set_value == null) {
+	    safe_set_value = new SafeSetValue(ammount);
+	}
+	else {
+	    safe_set_value.setValue(ammount);
+	}
+	SwingUtilities.invokeLater(safe_set_value);  
+    }
+
+    private class SafeSetIndeterminate 
+	implements Runnable {
+	private boolean value;
+	public SafeSetIndeterminate(boolean value) {
+	    this.value = value;
+	}
+	public void run() {
+	    unsafeSetIndeterminate(value);
+	}
+	synchronized public void setState(boolean value) {
+	    this.value = value;
+	}
+    }
+
+    private class SafeSetString 
+	implements Runnable {
+	private String label = null;
+	public SafeSetString(String label) {
+	    this.label = label;
+	}
+	public void run() {
+	    unsafeSetString(label);
+	}
+	synchronized public void setLabel(String label) {
+	    this.label = label;
+	}
+    }
+
+    private class SafeSetValue 
+	implements Runnable {
+	private int value = -1;
+	public SafeSetValue(int value) {
+	    this.value = value;
+	}
+	public void run() {
+	    unsafeSetValue(value);
+	}
+	synchronized public void setValue(int value) {
+	    this.value = value;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MenuBar.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MenuBar.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MenuBar.java	(revision 10506)
@@ -0,0 +1,281 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.util.JarTools;
+
+/** The menu bar for the Gatherer main GUI. 
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.2
+ */
+public class MenuBar
+    extends JMenuBar
+{
+    static public ImageIcon BLANK_ICON = JarTools.getImage("blank.gif");
+    static public ImageIcon HELP_ICON = JarTools.getImage("help.gif");
+
+    /** 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_associations;
+    public JMenuItem file_cdimage    = null;
+    public JMenuItem file_close      = null;
+    public JMenuItem file_delete     = null;
+    public JMenuItem file_exit       = null;
+    public JMenuItem file_exportas   = null;
+    public JMenuItem file_new        = null;
+    public JMenuItem file_open       = null;
+    public JMenuItem file_options    = null;
+    public JMenuItem file_save       = null;
+    public JMenuItem edit_copy;
+    public JMenuItem edit_cut;
+    public JMenuItem edit_paste;
+    public JMenuItem help_general;
+    public JMenuItem help_download;
+    public JMenuItem help_gather;
+    public JMenuItem help_enrich;
+    public JMenuItem help_design;
+    public JMenuItem help_create;
+    public JMenuItem help_about;
+
+
+    public MenuBar(MenuListener menu_listener)
+    {
+	file = new JMenu();
+	file.setMnemonic(KeyEvent.VK_F);
+	Dictionary.registerText(file, "Menu.File");
+
+	file_associations = new JMenuItem();
+	file_associations.addActionListener(Gatherer.g_man);	  
+	file_associations.setMnemonic(KeyEvent.VK_A);
+	Dictionary.registerText(file_associations, "Menu.File_Associations");
+
+	file_cdimage = new JMenuItem();
+	file_cdimage.addActionListener(Gatherer.g_man);
+	file_cdimage.setMnemonic(KeyEvent.VK_I);
+	Dictionary.registerText(file_cdimage, "Menu.File_CDimage");
+
+	file_close = new JMenuItem();
+	file_close.addActionListener(Gatherer.g_man);
+	file_close.setEnabled(false);
+	file_close.setMnemonic(KeyEvent.VK_C);
+	Dictionary.registerText(file_close, "Menu.File_Close");
+
+	file_delete = new JMenuItem();
+	file_delete.addActionListener(Gatherer.g_man);
+	file_delete.setMnemonic(KeyEvent.VK_D);
+	Dictionary.registerText(file_delete, "Menu.File_Delete");
+
+	file_exit = new JMenuItem();
+	file_exit.addActionListener(Gatherer.g_man);
+	file_exit.setMnemonic(KeyEvent.VK_X);
+	Dictionary.registerText(file_exit, "Menu.File_Exit");
+
+	file_exportas = new JMenuItem();
+	file_exportas.addActionListener(Gatherer.g_man);
+	file_exportas.setMnemonic(KeyEvent.VK_E);
+	Dictionary.registerText(file_exportas, "Menu.File_ExportAs");
+
+	file_new = new JMenuItem();
+	file_new.addActionListener(Gatherer.g_man);
+	file_new.setMnemonic(KeyEvent.VK_N);
+	Dictionary.registerText(file_new, "Menu.File_New");
+
+	file_open = new JMenuItem();
+	file_open.addActionListener(Gatherer.g_man);
+	file_open.setMnemonic(KeyEvent.VK_O);
+	Dictionary.registerText(file_open, "Menu.File_Open");
+
+	file_options = new JMenuItem();
+	file_options.addActionListener(Gatherer.g_man);
+	file_options.setMnemonic(KeyEvent.VK_P);
+	Dictionary.registerText(file_options, "Menu.File_Options");
+
+	file_save = new JMenuItem();
+	file_save.addActionListener(Gatherer.g_man);
+	file_save.setEnabled(false);
+	file_save.setMnemonic(KeyEvent.VK_S);
+	Dictionary.registerText(file_save, "Menu.File_Save");
+
+	// Layout (file menu)
+	file.add(file_new);
+	file.add(file_open);
+	file.add(file_save);
+	file.add(file_close);
+	file.add(new JSeparator());
+	file.add(file_delete);
+	file.add(file_exportas);
+	file.add(file_cdimage);
+	file.add(new JSeparator());
+	file.add(file_associations);
+	file.add(file_options);
+	file.add(new JSeparator());
+	file.add(file_exit);
+
+	// Edit menu
+	edit = new JMenu();
+	edit.setMnemonic(KeyEvent.VK_E);
+	Dictionary.registerText(edit, "Menu.Edit");
+		  
+	edit_cut = new JMenuItem();
+	edit_cut.addActionListener(Gatherer.g_man);
+	edit_cut.setMnemonic(KeyEvent.VK_X);
+	Dictionary.registerText(edit_cut, "Menu.Edit_Cut");
+
+	edit_copy = new JMenuItem();
+	edit_copy.addActionListener(Gatherer.g_man);
+	edit_copy.setMnemonic(KeyEvent.VK_C);
+	Dictionary.registerText(edit_copy, "Menu.Edit_Copy");
+
+	edit_paste = new JMenuItem();
+	edit_paste.addActionListener(Gatherer.g_man);
+	edit_paste.setMnemonic(KeyEvent.VK_V);
+	Dictionary.registerText(edit_paste, "Menu.Edit_Paste");
+
+	// Layout (edit menu)
+	edit.add(edit_cut);
+	edit.add(edit_copy);
+	edit.add(edit_paste);
+
+	// Help menu
+	help = new JMenu();
+	help.setIcon(HELP_ICON);
+	Dictionary.setText(help, "Menu.Help");
+
+	help_general = new JMenuItem();
+	help_general.addActionListener(Gatherer.g_man);
+	Dictionary.registerText(help_general, "Source.General");
+
+	help_download = new JMenuItem(BLANK_ICON);
+	help_download.addActionListener(Gatherer.g_man);
+	Dictionary.registerText(help_download, "GUI.Download");
+
+	help_gather = new JMenuItem(BLANK_ICON);
+	help_gather.addActionListener(Gatherer.g_man);
+	Dictionary.registerText(help_gather, "GUI.Gather");
+
+	help_enrich = new JMenuItem(BLANK_ICON);
+	help_enrich.addActionListener(Gatherer.g_man);
+	Dictionary.registerText(help_enrich, "GUI.Enrich");
+
+	help_design = new JMenuItem(BLANK_ICON);
+	help_design.addActionListener(Gatherer.g_man);
+	Dictionary.registerText(help_design, "GUI.Design");
+
+	help_create = new JMenuItem(BLANK_ICON);
+	help_create.addActionListener(Gatherer.g_man);
+	Dictionary.registerText(help_create, "GUI.Create");
+
+	help_about = new JMenuItem();
+	help_about.addActionListener(Gatherer.g_man);
+	Dictionary.registerText(help_about, "Menu.Help_About");
+
+	// Layout (help menu)
+	help.add(help_general);
+	help.add(new JSeparator());
+	if (Configuration.get("workflow.download", true)) {
+	    help.add(help_download);
+	}
+	if (Configuration.get("workflow.gather", true)) {
+	    help.add(help_gather);
+	}
+	if (Configuration.get("workflow.enrich", true)) {
+	    help.add(help_enrich);
+	}
+	if (Configuration.get("workflow.design", true)) {
+	    help.add(help_design);
+	}
+	if (Configuration.get("workflow.create", true)) {
+	    help.add(help_create);
+	}
+	help.add(new JSeparator());
+	help.add(help_about);
+
+	// Layout (menu bar)
+	this.add(file);
+	this.add(Box.createHorizontalStrut(15));
+	this.add(edit);
+	this.add(Box.createHorizontalGlue());
+	this.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: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataElementListCellRenderer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataElementListCellRenderer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataElementListCellRenderer.java	(revision 10506)
@@ -0,0 +1,82 @@
+package org.greenstone.gatherer.gui;
+
+
+import java.awt.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataTools;
+
+
+public class MetadataElementListCellRenderer
+    extends JLabel
+    implements ListCellRenderer
+{
+    private byte previous_directionality = Character.DIRECTIONALITY_UNDEFINED;
+
+
+    public byte getDirectionality()
+    {
+	if (previous_directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT || previous_directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC || previous_directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING || previous_directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE) {
+	    return Character.DIRECTIONALITY_RIGHT_TO_LEFT;
+	}
+	else {
+	    return Character.DIRECTIONALITY_LEFT_TO_RIGHT;
+	}
+    }
+
+
+    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
+    {
+	if (value instanceof MetadataElement) {
+	    MetadataElement metadata_element = (MetadataElement) value;
+
+	    String interface_language_code = Configuration.getLanguage();
+	    String metadata_element_display = "";
+
+	    String metadata_element_display_name = metadata_element.getDisplayName();
+	    if (metadata_element_display_name != null) {
+		metadata_element_display += metadata_element_display_name + ":";
+	    }
+	    else {
+		metadata_element_display += metadata_element.getName() + ":";
+	    }
+
+	    String metadata_element_definition = MetadataTools.getMetadataElementAttribute(metadata_element, "definition", interface_language_code, "en");
+	    if (metadata_element_definition != null) {
+		metadata_element_display += " " + metadata_element_definition;
+	    }
+
+	    String metadata_element_comment = MetadataTools.getMetadataElementAttribute(metadata_element, "comment", interface_language_code, "en");
+	    if (metadata_element_comment != null) {
+		metadata_element_display += " " + metadata_element_comment;
+	    }
+
+	    setText(metadata_element_display);
+
+// 	    // Determine if the text should be left aligned or right aligned
+// 	    String text = metadata_element_display;
+// 	    int text_index = 0;
+// 	    byte directionality = Character.DIRECTIONALITY_UNDEFINED;
+// 	    while (directionality == Character.DIRECTIONALITY_UNDEFINED && text_index < text.length()) {
+// 		directionality = Character.getDirectionality(text.charAt(text_index));
+// 		text_index++;
+// 	    }
+// 	    if (directionality != previous_directionality) {
+// 		previous_directionality = directionality;
+// 		if (directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT || directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC || directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING || directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE) {
+// 		    setHorizontalAlignment(JLabel.TRAILING);
+// 		    setHorizontalTextPosition(JLabel.TRAILING);
+// 		    setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
+// 		}
+// 		else {
+// 		    setHorizontalAlignment(JLabel.LEADING);
+// 		    setHorizontalTextPosition(JLabel.LEADING);
+// 		    setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
+// 		}
+// 	    }
+	}
+
+	return this;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataImportMappingPrompt.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataImportMappingPrompt.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataImportMappingPrompt.java	(revision 10506)
@@ -0,0 +1,178 @@
+package org.greenstone.gatherer.gui;
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.metadata.MetadataTools;
+
+
+public class MetadataImportMappingPrompt
+    implements ActionListener
+{
+    final static public int ADD_BUTTON_PRESSED = 0;
+    final static public int MERGE_BUTTON_PRESSED = 1;
+    final static public int IGNORE_BUTTON_PRESSED = 2;
+    final static private Dimension DIALOG_SIZE = new Dimension(640, 180);
+
+    private int result;
+    private String metadata_element_name_full = null;
+    private GComboBox metadata_sets_combobox = null;
+    private GComboBox metadata_elements_combobox = null;
+    private JButton add_button = null;
+    private JButton merge_button = null;
+    private JButton ignore_button = null;
+    private JDialog on_screen = null;
+
+
+    public MetadataImportMappingPrompt(String metadata_element_name_full)
+    {
+	this.metadata_element_name_full = metadata_element_name_full;
+
+	// Construction and configuration
+	JDialog dialog = new ModalDialog(Gatherer.g_man);
+	dialog.setModal(true);
+	dialog.setSize(DIALOG_SIZE);
+	dialog.setJMenuBar(new SimpleMenuBar("importingpreviouslyassignedmetadata"));
+	Dictionary.setText(dialog, "MIMP.Title");
+
+	// All the loaded metadata sets except the extracted metadata set are applicable
+	ArrayList metadata_sets = MetadataSetManager.getMetadataSets();
+	for (int i = metadata_sets.size() - 1; i >= 0; i--) {
+	    if (((MetadataSet) metadata_sets.get(i)).getNamespace().equals(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE)) {
+		metadata_sets.remove(i);
+	    }
+	}
+
+  	add_button = new GLIButton();
+ 	add_button.addActionListener(this);
+  	add_button.setMnemonic(KeyEvent.VK_A);
+  	Dictionary.registerBoth(add_button, "MIMP.Add", "MIMP.Add_Tooltip");
+
+  	merge_button = new GLIButton();
+  	merge_button.addActionListener(this);
+  	merge_button.setEnabled(true);
+  	merge_button.setMnemonic(KeyEvent.VK_M);
+  	Dictionary.registerBoth(merge_button, "MIMP.Merge", "MIMP.Merge_Tooltip");
+
+  	ignore_button = new GLIButton();
+  	ignore_button.addActionListener(this);
+  	ignore_button.setEnabled(true);
+  	ignore_button.setMnemonic(KeyEvent.VK_S);
+  	Dictionary.registerBoth(ignore_button, "MIMP.Ignore", "MIMP.Ignore_Tooltip");
+
+	// !! Need to add instructions: "MIMP.Instructions", args: source elem
+	metadata_elements_combobox = new GComboBox();
+
+	metadata_sets_combobox = new GComboBox(metadata_sets);
+	metadata_sets_combobox.addActionListener(new MetadataSetListSelectionListener());
+	metadata_sets_combobox.setSelectedIndex(0);
+
+	// Layout
+	JPanel left_pane = new JPanel();
+	left_pane.setLayout(new GridLayout(3,1));
+	left_pane.add(new JLabel(Dictionary.get("MIMP.Source_Element")));
+	left_pane.add(new JLabel(Dictionary.get("MIMP.Target_Set")));
+	left_pane.add(new JLabel(Dictionary.get("MIMP.Target_Element")));
+
+	JPanel right_pane = new JPanel();
+	right_pane.setLayout(new GridLayout(3,1));
+	right_pane.add(new JLabel(metadata_element_name_full));
+	right_pane.add(metadata_sets_combobox);
+	right_pane.add(metadata_elements_combobox);
+
+	JPanel button_pane = new JPanel();
+	button_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
+	button_pane.setLayout(new GridLayout(1,3));
+	button_pane.add(add_button);
+	button_pane.add(merge_button);
+	button_pane.add(ignore_button);
+
+	JPanel content_pane = (JPanel) dialog.getContentPane();
+	content_pane.setLayout(new BorderLayout());
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.add(left_pane, BorderLayout.WEST);
+	content_pane.add(right_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	// Display
+	Dimension screen_size = Configuration.screen_size;
+	dialog.setLocation((screen_size.width - DIALOG_SIZE.width) / 2, (screen_size.height - DIALOG_SIZE.height) / 2);
+	on_screen = dialog;
+	on_screen.setVisible(true); // Blocks until hidden.
+	on_screen.dispose();
+	on_screen = null;
+    }
+
+
+    /** Any implementation of <i>ActionListener</i> must include this method so that we can be informed when an action has occured.
+     * @param event An <strong>ActionEvent</strong> containing information gatherer when this event occured.
+     */
+    public void actionPerformed(ActionEvent event)
+    {
+	Object esrc = event.getSource();
+
+	if (esrc == add_button) {
+	    result = ADD_BUTTON_PRESSED;
+	}
+	if (esrc == merge_button) {
+	    result = MERGE_BUTTON_PRESSED;
+	}
+	if (esrc == ignore_button) {
+	    result = IGNORE_BUTTON_PRESSED;
+	}
+
+	on_screen.setVisible(false);
+    }
+
+
+    public MetadataElement getSelectedMetadataElement()
+    {
+	return (MetadataElement) metadata_elements_combobox.getSelectedItem();
+    }
+
+
+    public MetadataSet getSelectedMetadataSet()
+    {
+	return (MetadataSet) metadata_sets_combobox.getSelectedItem();
+    }
+
+
+    public int getResult()
+    {
+	return result;
+    }
+
+
+    private class MetadataSetListSelectionListener
+	implements ActionListener
+    {
+	public void actionPerformed(ActionEvent event)
+	{
+	    boolean enable_add_button = true;
+	    String metadata_element_name = MetadataTools.getMetadataElementName(metadata_element_name_full);
+
+	    MetadataSet metadata_set = (MetadataSet) metadata_sets_combobox.getSelectedItem();
+	    ArrayList metadata_elements = metadata_set.getMetadataSetElements();
+
+	    metadata_elements_combobox.removeAllItems();
+	    for (int i = 0; i < metadata_elements.size(); i++) {
+		MetadataElement metadata_element = (MetadataElement) metadata_elements.get(i);
+		metadata_elements_combobox.addItem(metadata_element);
+		if (metadata_element.getName().equals(metadata_element_name)) {
+		    metadata_elements_combobox.setSelectedIndex(i);
+		    enable_add_button = false;
+		}
+	    }
+
+	    add_button.setEnabled(enable_add_button);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataValueTablePane.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataValueTablePane.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataValueTablePane.java	(revision 10506)
@@ -0,0 +1,416 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer.gui;
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+import org.greenstone.gatherer.metadata.MetadataChangedListener;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataTools;
+import org.greenstone.gatherer.metadata.MetadataValue;
+import org.greenstone.gatherer.metadata.MetadataValueTableEntry;
+import org.greenstone.gatherer.metadata.MetadataValueTableModel;
+import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.Utility;
+
+
+public class MetadataValueTablePane
+    extends JPanel
+{
+    private MetadataValueTable metadata_value_table = null;
+    /** Used to display either the MetadataValueTable (when files are selected) or a placeholder panel */
+    private CardLayout card_layout = null;
+    /** The name of the panel containing the metadata value table */
+    private String METADATA_VALUE_TABLE_CARD = "";
+    /** The name of the panel containing the "no metadata available" placeholder */
+    private String NO_METADATA_AVAILABLE_CARD = "No metadata available";
+    /** The name of the panel containing the "no files selected" placeholder */
+    private String NO_FILES_SELECTED_CARD = "No files selected";
+
+
+    public MetadataValueTablePane()
+    {
+	super();
+
+	metadata_value_table = new MetadataValueTable();
+
+	JScrollPane metadata_value_table_scroll = new JScrollPane(metadata_value_table);
+	metadata_value_table_scroll.getViewport().setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	metadata_value_table_scroll.setOpaque(true);
+
+	JPanel metadata_value_table_pane = new JPanel();
+	metadata_value_table_pane.setLayout(new BorderLayout());
+	metadata_value_table_pane.add(metadata_value_table_scroll, BorderLayout.CENTER);
+
+	JLabel no_metadata_available_label = new JLabel();
+	no_metadata_available_label.setHorizontalAlignment(JLabel.CENTER);
+	no_metadata_available_label.setOpaque(false);
+	no_metadata_available_label.setVerticalAlignment(JLabel.CENTER);
+	Dictionary.registerText(no_metadata_available_label, "EnrichPane.No_Metadata");
+
+	JPanel no_metadata_available_pane = new JPanel();
+	no_metadata_available_pane.setLayout(new BorderLayout());
+	no_metadata_available_pane.add(no_metadata_available_label, BorderLayout.CENTER);
+
+	JLabel no_files_selected_label = new JLabel();
+	no_files_selected_label.setHorizontalAlignment(JLabel.CENTER);
+	no_files_selected_label.setOpaque(false);
+	no_files_selected_label.setVerticalAlignment(JLabel.CENTER);
+	Dictionary.registerText(no_files_selected_label, "EnrichPane.No_File");
+
+	JPanel no_files_selected_pane = new JPanel();
+	no_files_selected_pane.setLayout(new BorderLayout());
+	no_files_selected_pane.add(no_files_selected_label, BorderLayout.CENTER);
+
+	card_layout = new CardLayout();
+
+	this.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
+	this.setFont(Configuration.getFont("general.font", false));
+	this.setLayout(card_layout);
+	this.add(metadata_value_table_pane, METADATA_VALUE_TABLE_CARD);
+	this.add(no_metadata_available_pane, NO_METADATA_AVAILABLE_CARD);
+	this.add(no_files_selected_pane, NO_FILES_SELECTED_CARD);
+    }
+
+
+    public void addMetadataValueTableListSelectionListener(ListSelectionListener list_selection_listener)
+    {
+	metadata_value_table.getSelectionModel().addListSelectionListener(list_selection_listener);
+    }
+
+
+    public void addMetadataValueTableMouseListener(MouseListener mouse_listener)
+    {
+	metadata_value_table.addMouseListener(mouse_listener);
+    }
+
+
+    public void addMetadataValueTextFieldDocumentListener(DocumentListener document_listener)
+    {
+	metadata_value_table.getMetadataValueTextField().getDocument().addDocumentListener(document_listener);
+    }
+
+
+    public void addMetadataValueTextFieldKeyListener(KeyListener key_listener)
+    {
+	metadata_value_table.getMetadataValueTextField().addKeyListener(key_listener);
+    }
+
+
+    public MetadataValueTableEntry getSelectedMetadataValueTableEntry()
+    {
+	return metadata_value_table.getSelectedMetadataValueTableEntry();
+    }
+
+
+    public boolean isMouseEventForInheritedMetadataValueTableColumn(MouseEvent mouse_event)
+    {
+	return metadata_value_table.isMouseEventForInheritedMetadataValueTableColumn(mouse_event);
+    }
+
+
+    public void setMetadataValueTextFieldValue(String metadata_value_string)
+    {
+	metadata_value_table.setMetadataValueTextFieldValue(metadata_value_string);
+    }
+
+
+    public void stopEditingAndAddBlankRowForSelectedMetadataElement()
+    {
+	metadata_value_table.stopEditing();
+	metadata_value_table.addBlankRowForSelectedMetadataElement();
+    }
+
+
+    public void stopEditingAndRebuild(CollectionTreeNode[] file_nodes)
+    {
+	metadata_value_table.stopEditing();
+	metadata_value_table.rebuild(file_nodes);
+
+	// If no files are selected display the "no file selected" card
+	if (file_nodes == null) {
+	    card_layout.show(this, NO_FILES_SELECTED_CARD);
+	}
+	// If the metadata value table is empty display the "no metadata available" card
+	else if (metadata_value_table.getRowCount() == 0) {
+	    card_layout.show(this, NO_METADATA_AVAILABLE_CARD);
+	}
+	// Otherwise display the card with the metadata value table
+	else {
+	    card_layout.show(this, METADATA_VALUE_TABLE_CARD);
+	}
+    }
+
+
+    private class MetadataValueTable
+	extends JTable
+	implements MetadataChangedListener
+    {
+	private int MINIMUM_TABLE_HEADER_SIZE = 15;
+
+	private MetadataValueTableModel metadata_value_table_model = null;
+	private JTextField metadata_value_text_field = new JTextField();
+
+
+	public MetadataValueTable()
+	{
+	    // Create the model for the table
+	    metadata_value_table_model = new MetadataValueTableModel();
+	    setModel(metadata_value_table_model);
+
+	    // We allow only one row in the table to be selected at a time
+	    setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+	    // We use our own editor for the value column so we have easy access to the underlying text field
+	    setDefaultEditor(String.class, new DefaultCellEditor(metadata_value_text_field));
+
+	    // We need to listen for double clicks on the text field to open the editor dialog
+	    metadata_value_text_field.addMouseListener(new MetadataValueTextFieldMouseListener());
+
+	    // We need to listen for key presses so we can catch Enter presses
+	    addKeyListener(new MetadataValueTableKeyListener());
+
+	    // We need to listen for metadata changes so we can rebuild the table
+	    MetadataXMLFileManager.addMetadataChangedListener(this);
+
+	    // We also have to ensure that the table column header hasn't gone on a severe Jenny Craig binge and has somehow lost 7/8th of its component size
+	    JTableHeader table_header = 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);
+	    }
+
+	    // Set the size of the table columns: 2/7 for element, 5/7 for value (actual numbers don't matter) 
+	    TableColumnModel column_model = getColumnModel();
+	    TableColumn inherited_column = column_model.getColumn(0);
+	    inherited_column.setMinWidth(25);
+	    inherited_column.setPreferredWidth(25);
+	    inherited_column.setMaxWidth(25);
+	    TableColumn element_column = column_model.getColumn(1);
+	    element_column.setPreferredWidth(200);
+	    TableColumn value_column = column_model.getColumn(2);
+	    value_column.setPreferredWidth(500);
+
+	    // Use our own renderer for the table cells
+	    MetadataValueTableCellRenderer metadata_value_table_cell_renderer = new MetadataValueTableCellRenderer();
+	    inherited_column.setCellRenderer(metadata_value_table_cell_renderer);
+	    element_column.setCellRenderer(metadata_value_table_cell_renderer);
+	    value_column.setCellRenderer(metadata_value_table_cell_renderer);
+	}
+
+
+	private void addBlankRowForSelectedMetadataElement()
+	{
+	    // Add a blank entry for the selected metadata element, then switch to it
+	    MetadataElement selected_metadata_element = getSelectedMetadataValueTableEntry().getMetadataElement();
+	    int blank_row = metadata_value_table_model.addBlankRowForMetadataElement(selected_metadata_element);
+	    changeSelection(blank_row, 2, false, false);
+	}
+
+
+	private JTextField getMetadataValueTextField()
+	{
+	    return metadata_value_text_field;
+	}
+
+
+	private MetadataValueTableEntry getSelectedMetadataValueTableEntry()
+	{
+	    return metadata_value_table_model.getMetadataValueTableEntry(getSelectedRow());
+	}
+
+
+	private boolean isMouseEventForInheritedMetadataValueTableColumn(MouseEvent mouse_event)
+	{
+	    return (columnAtPoint(mouse_event.getPoint()) == 0);
+	}
+
+
+	public void metadataChanged(CollectionTreeNode[] file_nodes)
+	{
+	    rebuild(file_nodes);
+	}
+
+
+	private void rebuild(CollectionTreeNode[] file_nodes)
+	{
+	    // Note the metadata value table entry currently selected
+	    MetadataValueTableEntry selected_metadata_value_table_entry = getSelectedMetadataValueTableEntry();
+
+	    // We don't want a lot of ListSelectionEvents while the table is rebuilding
+	    clearSelection();
+
+	    // Rebuild the metadata value table model
+	    metadata_value_table_model.rebuild(file_nodes);
+
+	    // Restore the metadata value table entry selection
+	    if (selected_metadata_value_table_entry != null) {
+		int row_to_select = metadata_value_table_model.findMetadataValueTableEntryToSelect(selected_metadata_value_table_entry);
+		changeSelection(row_to_select, 2, false, false);
+	    }
+	}
+
+
+	private void setMetadataValueTextFieldValue(String metadata_value_string)
+	{
+	    metadata_value_text_field.setText(metadata_value_string);
+	    metadata_value_text_field.requestFocus();
+	}
+
+
+	private void stopEditing()
+	{
+	    // Save the current value in the text field, then remove the editor so it doesn't get saved again
+	    TableCellEditor table_cell_editor = getCellEditor();
+	    if (table_cell_editor != null) {
+		Object new_metadata_value = table_cell_editor.getCellEditorValue();
+		setValueAt(new_metadata_value, editingRow, editingColumn);
+		removeEditor();
+	    }
+	}
+
+
+	private class MetadataValueTableCellRenderer
+	    extends DefaultTableCellRenderer
+	{
+	    /** Returns the default table cell renderer.
+	     * @param table The <strong>JTable</strong>.
+	     * @param value The value to assign to the cell at [row, column] as an <strong>Object</strong>.
+	     * @param isSelected <i>true</i> if cell is selected.
+	     * @param hasFocus <i>true</i> if cell has focus.
+	     * @param row The row of the cell to render as an <i>int</i>.
+	     * @param column The column of the cell to render as an <i>int</i>.
+	     * @return The default table cell renderer <strong>Component</strong>.
+	     */
+	    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
+	    {
+		JComponent component = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+
+		// First column: inherited metadata icon
+		if (column == 0 && value != null) {
+		    component = new JLabel(JarTools.getImage("upfolder.gif"));
+		}
+
+		// Make sure the focus always stay in the value cell of the selected row
+		if (column == 2 && isSelected) {
+		    table.editCellAt(row, column);
+		    if (table.isEditing()) {
+			table.getEditorComponent().requestFocus();
+		    }
+		}
+
+		// Set up the component
+		component.setOpaque(true);
+
+		// Foreground
+		if (metadata_value_table_model.isCommon(row)) {
+		    component.setForeground(Color.black);
+		}
+		else {
+		    component.setForeground(Color.gray);
+		}
+
+		// Background
+		if (isSelected) {
+		    component.setBackground(Configuration.getColor("coloring.workspace_heading_background", true));
+		}
+		else {
+		    if (column < 2) {
+			component.setBackground(Configuration.getColor("coloring.collection_heading_background", true));
+		    }
+		    else {
+			component.setBackground(Configuration.getColor("coloring.collection_tree_background", true));
+		    }
+		}
+
+		// The value column of cells never paints focus
+		if (column == 2) {
+		    component.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
+		}
+
+		// We set a tooltip over the element column containing the definition of the element
+		if (value instanceof MetadataElement) {
+		    String interface_language_code = Configuration.getLanguage();
+		    String metadata_element_definition = MetadataTools.getMetadataElementAttribute((MetadataElement) value, "definition", interface_language_code, "en");
+		    if (metadata_element_definition != null) {
+			component.setToolTipText(Utility.formatHTMLWidth(metadata_element_definition, 60));
+		    }
+		}
+
+		return component;
+	    }
+	}
+
+
+	private class MetadataValueTableKeyListener
+	    extends KeyAdapter
+	{
+	    /** Gives notification of key events on the text field */
+	    public void keyPressed(KeyEvent key_event)
+	    {
+		// Enter: save the current value then add a blank row for the selected metadata element
+		if (key_event.getKeyCode() == KeyEvent.VK_ENTER) {
+		    // ...but not for extracted metadata elements of course
+		    MetadataValueTableEntry metadata_value_table_entry = getSelectedMetadataValueTableEntry();
+		    if (!metadata_value_table_entry.getMetadataElement().isExtractedMetadataElement()) {
+			addBlankRowForSelectedMetadataElement();
+		    }
+
+		    // We do not want this event to be processed by the table also
+		    key_event.consume();
+		}
+	    }
+	}
+
+
+	private class MetadataValueTextFieldMouseListener
+	    extends MouseAdapter
+	{
+	    public void mouseClicked(MouseEvent mouse_event)
+	    {
+		// Double-click: pop up an editor dialog for large metadata values
+		if (mouse_event.getClickCount() == 2) {
+ 		    EditorDialog editor_dialog = new EditorDialog();
+ 		    String new_metadata_value_string = editor_dialog.display(metadata_value_text_field.getText());
+ 		    if (new_metadata_value_string != null) {
+ 			setMetadataValueTextFieldValue(new_metadata_value_string);
+ 		    }
+		}
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataValueTreePane.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataValueTreePane.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/MetadataValueTreePane.java	(revision 10506)
@@ -0,0 +1,298 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer.gui;
+
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataValue;
+import org.greenstone.gatherer.metadata.MetadataValueTreeNode;
+import org.greenstone.gatherer.util.PatternTokenizer;
+
+
+/**
+ * This class is a little bit complex, a little bit subtle, and a little bit odd.
+ * The strange interaction model is due to the fact that it is very tightly
+ * coupled to the EnrichPane.
+ *
+ * The interaction is complex because there are three separate controls that the
+ * user may interact with, each of which can affect the other two. The three
+ * controls are:
+ *   - The "assigned metadata" table, at the top right of the meta edit pane.
+ *   - The "metadata value" text field, where users can type in new values.
+ *   - The "metadata value tree", which shows other values that have been
+ *     assigned to the selected metadata element.
+ *
+ * The interactions are:
+ *   - The "assigned metadata" table
+ *     Users may select one (and only one) row in this table. Selecting a row
+ *     chooses one metadata element. The text field will be set to the current
+ *     value of the metadata element. This value will also be selected in the
+ *     metadata value tree.
+ *
+ *   - The "metadata value" text field
+ *     If the value the user has typed in this is a prefix of an entry in the
+ *     value tree, this value will be selected in the value tree. In this case,
+ *     pressing "Tab" will complete the value (ie. make the value in the text
+ *     field the same as the value in the tree). This is to allow users to
+ *     quickly and easily assign existing metadata values to new documents.
+ *
+ *   - The "metadata value tree"
+ *     Selecting a value in the tree will set the text field to this value.
+ */
+public class MetadataValueTreePane
+    extends JPanel
+{
+    private boolean ignore_tree_selection_event = false;
+    /** The metadata value that the tree pane is built on */
+    private MetadataValue metadata_value = null;
+
+    /** Used to display either the MetadataValueTree (when metadata is selected) or a placeholder panel */
+    private CardLayout card_layout = null;
+    /** The name of the panel containing the metadata value tree */
+    private String METADATA_VALUE_TREE_CARD = "";
+    /** The name of the panel containing the "extracted metadata element selected" placeholder */
+    private String EXTRACTED_METADATA_ELEMENT_SELECTED_CARD = "Extracted metadata element selected";
+    /** The name of the panel containing the "inherited metadata selected" placeholder */
+    private String INHERITED_METADATA_SELECTED_CARD = "Inherited metadata selected";
+    /** The name of the panel containing the "no metadata element selected" placeholder */
+    private String NO_METADATA_ELEMENT_SELECTED_CARD = "No metadata element selected";
+
+    private JLabel metadata_value_tree_label = new JLabel();
+    private JTextArea extracted_metadata_element_selected_message;
+    private JTree metadata_value_tree;
+
+
+    public MetadataValueTreePane()
+    {
+	super();
+
+	// Card containing the metadata value tree
+	metadata_value_tree = new JTree();
+	metadata_value_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+	metadata_value_tree.setModel(null);
+	metadata_value_tree.setRootVisible(false);
+	metadata_value_tree.putClientProperty("JTree.lineStyle", "Angled");
+
+	JPanel metadata_value_tree_pane = new JPanel();
+	metadata_value_tree_pane.setLayout(new BorderLayout());
+	metadata_value_tree_pane.add(metadata_value_tree_label, BorderLayout.NORTH);
+	metadata_value_tree_pane.add(new JScrollPane(metadata_value_tree), BorderLayout.CENTER);
+
+	// Card containing the "extracted metadata element selected" message
+	extracted_metadata_element_selected_message = new JTextArea("");
+	extracted_metadata_element_selected_message.setEditable(false);
+	extracted_metadata_element_selected_message.setLineWrap(true);
+	extracted_metadata_element_selected_message.setOpaque(false);
+	extracted_metadata_element_selected_message.setWrapStyleWord(true);
+
+	JPanel extracted_metadata_element_selected_pane = new JPanel();
+	extracted_metadata_element_selected_pane.setBorder(BorderFactory.createEmptyBorder(25,0,0,0));
+	extracted_metadata_element_selected_pane.setLayout(new BorderLayout());
+	extracted_metadata_element_selected_pane.add(extracted_metadata_element_selected_message, BorderLayout.CENTER);
+
+	// Card containing the "inherited metadata selected" message
+	JTextArea inherited_metadata_selected_message = new JTextArea("");
+	inherited_metadata_selected_message.setEditable(false);
+	inherited_metadata_selected_message.setLineWrap(true);
+	inherited_metadata_selected_message.setOpaque(false);
+	inherited_metadata_selected_message.setWrapStyleWord(true);
+	Dictionary.registerText(inherited_metadata_selected_message, "EnrichPane.InheritedMetadataSelected");
+
+	JPanel inherited_metadata_selected_pane = new JPanel();
+	inherited_metadata_selected_pane.setBorder(BorderFactory.createEmptyBorder(25,0,0,0));
+	inherited_metadata_selected_pane.setLayout(new BorderLayout());
+	inherited_metadata_selected_pane.add(inherited_metadata_selected_message, BorderLayout.CENTER);
+
+	// Card containing the "no metadata element selected" message
+	JLabel no_metadata_element_selected_label = new JLabel();
+	no_metadata_element_selected_label.setHorizontalAlignment(JLabel.CENTER);
+	no_metadata_element_selected_label.setOpaque(false);
+	no_metadata_element_selected_label.setVerticalAlignment(JLabel.CENTER);
+	Dictionary.registerText(no_metadata_element_selected_label, "EnrichPane.No_Metadata_Element");
+
+	JPanel no_metadata_element_selected_pane = new JPanel();
+	no_metadata_element_selected_pane.setLayout(new BorderLayout());
+	no_metadata_element_selected_pane.add(no_metadata_element_selected_label, BorderLayout.CENTER);
+
+	card_layout = new CardLayout();
+
+	this.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	this.setFont(Configuration.getFont("general.font", false));
+	this.setLayout(card_layout);
+	this.add(no_metadata_element_selected_pane, NO_METADATA_ELEMENT_SELECTED_CARD);
+	this.add(extracted_metadata_element_selected_pane, EXTRACTED_METADATA_ELEMENT_SELECTED_CARD);
+	this.add(inherited_metadata_selected_pane, INHERITED_METADATA_SELECTED_CARD);
+	this.add(metadata_value_tree_pane, METADATA_VALUE_TREE_CARD);
+    }
+
+
+    public void addMetadataValueTreeSelectionListener(TreeSelectionListener tree_selection_listener)
+    {
+	metadata_value_tree.addTreeSelectionListener(tree_selection_listener);
+    }
+
+
+    /** Returns a TreePath for the node most closely matching the metadata value. */
+    private TreePath getClosestPath(String metadata_value_string)
+    {
+	if (metadata_value_tree.getModel() == null) {
+	    return null;
+	}
+
+	// Start at the root of the tree
+	MetadataValueTreeNode tree_node = (MetadataValueTreeNode) metadata_value_tree.getModel().getRoot();
+
+	// Separate hierarchical values
+	PatternTokenizer tokenizer = new PatternTokenizer(metadata_value_string, MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN);
+	while (tokenizer.hasMoreTokens()) {
+	    String token = tokenizer.nextToken();
+
+	    // All components except the last must match exactly
+	    if (tokenizer.hasMoreTokens()) {
+		for (int i = 0; i < tree_node.getChildCount(); i++) {
+		    MetadataValueTreeNode child_node = (MetadataValueTreeNode) tree_node.getChildAt(i);
+		    if (child_node.getValue().equals(token)) {
+			// The matching node has been found, so move onto the next token
+			tree_node = child_node;
+			break;
+		    }
+		}
+	    }
+
+	    // The last component may match partially
+	    else {
+		for (int i = 0; i < tree_node.getChildCount(); i++) {
+		    MetadataValueTreeNode child_node = (MetadataValueTreeNode) tree_node.getChildAt(i);
+		    if (child_node.getFullValue().startsWith(metadata_value_string)) {
+			// The closest node has been found, so return its path
+			return new TreePath(child_node.getPath());
+		    }
+		}
+
+		// Not even a partial match
+		return null;
+	    }
+	}
+
+	// If nothing else, return the path of the root node
+	return new TreePath(tree_node.getPath());
+    }
+
+
+    public MetadataValueTreeNode getSelectedMetadataValueTreeNode()
+    {
+	if (metadata_value_tree.getSelectionCount() == 0 || ignore_tree_selection_event) {
+	    return null;
+	}
+
+	return (MetadataValueTreeNode) metadata_value_tree.getSelectionPath().getLastPathComponent();
+    }
+
+
+    public void rebuild(MetadataValue new_metadata_value)
+    {
+	// If the metadata value hasn't changed there is nothing to do
+	if (new_metadata_value == metadata_value) {
+	    return;
+	}
+
+	MetadataElement metadata_element = ((metadata_value != null) ? metadata_value.getMetadataElement() : null);
+	metadata_value = new_metadata_value;
+
+	// Selection cleared, so display "no metadata element selected" card and we're done
+	if (new_metadata_value == null) {
+	    metadata_value_tree.setModel(null);
+	    card_layout.show(this, NO_METADATA_ELEMENT_SELECTED_CARD);
+	    return;
+	}
+
+	// If a piece of inherited metadata is selected, display "inherited metadata selected" card and we're done
+	if (new_metadata_value.isInheritedMetadata()) {
+	    card_layout.show(this, INHERITED_METADATA_SELECTED_CARD);
+	    return;
+	}
+
+	// If an extracted metadata element is selected, display "extracted metadata element selected" card
+	MetadataElement new_metadata_element = new_metadata_value.getMetadataElement();
+	if (new_metadata_element.isExtractedMetadataElement()) {
+	    String[] args = new String[1];
+	    args[0] = new_metadata_element.getDisplayName();
+	    Dictionary.registerText(extracted_metadata_element_selected_message, "EnrichPane.AutoMessage", args);
+	    card_layout.show(this, EXTRACTED_METADATA_ELEMENT_SELECTED_CARD);
+	    return;
+	}
+
+	// Display the value tree for the selected metadata element
+	String[] args = new String[1];
+	args[0] = new_metadata_element.getDisplayName();
+	Dictionary.registerText(metadata_value_tree_label, "EnrichPane.ExistingValues", args);
+
+	metadata_value_tree.setModel(new_metadata_element.getMetadataValueTreeModel());
+	card_layout.show(this, METADATA_VALUE_TREE_CARD);
+	selectBestPathForMetadataValue(new_metadata_value.getFullValue());
+    }
+
+
+    public void selectBestPathForMetadataValue(String metadata_value_string)
+    {
+	TreePath best_path = getClosestPath(metadata_value_string);
+
+	// Select the new path in the tree
+	// The tree selection event this causes must be ignored, since it alters the metadata text field value
+	ignore_tree_selection_event = true;
+	metadata_value_tree.setSelectionPath(best_path);
+	ignore_tree_selection_event = false;
+
+	// If a folder has been specified, make sure it is expanded
+	if (metadata_value_string.endsWith(MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN) && !metadata_value_tree.isExpanded(best_path)) {
+	    metadata_value_tree.expandPath(best_path);
+	}
+
+	// Make sure the tree path is expanded
+	metadata_value_tree.makeVisible(best_path);
+
+	// Make sure the tree path is visible on screen
+	final Rectangle bounds = metadata_value_tree.getPathBounds(best_path);
+	if (bounds != null) {
+	    bounds.x = 0;  // Want the tree to be always flushed left
+
+	    // Scrolling the path to be visible must be done on the GUI thread
+	    Runnable task = new Runnable() {
+		    public void run() {
+			metadata_value_tree.scrollRectToVisible(bounds);
+		    }
+		};
+	    SwingUtilities.invokeLater(task);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ModalDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ModalDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ModalDialog.java	(revision 10506)
@@ -0,0 +1,208 @@
+/*#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.greenstone.gatherer.DebugStream;
+
+
+/** An extension of the JDialog that overrides the JVM's typical modal behaviour. This typical behaviour is that when a modal dialog is opened, all other windows cease to respond to user events until the modal dialog is disposed. However this prevents us opening the help documents property whenever a modal dialog is open. Thus we override the modal behaviour so that only the owner frame or dialog is blocked. 
+ * Note that because we always call the super constructor with modal set to false, this should be made visible with setVisible(true) rather than show() which will return straight away. */
+// feedback note: veronika had changed all the super constructor calls to 
+// use modal instead of false - not sure if this is needed so I have not 
+// put that in. --kjdon
+public class ModalDialog
+    extends JDialog {
+
+    /** The current modal dialog being shown on screen, if any. */
+    static public ModalDialog current_modal = null;
+
+    /** true if this dialog should be modal, ie block user actions to its owner window, false otherwise. */
+    protected boolean modal = false;
+    /** true if this dialog is currently waiting some thread. */
+    protected boolean waiting = false;
+
+    /** Constructor.
+     */
+    public ModalDialog() {
+	super((Frame)null, "", false);
+    }
+
+    /** Constructor.
+     * @param parent the Dialog which is the owener of this dialog.
+    */
+    public ModalDialog(Dialog parent) {
+	super(parent, "", false);
+    }
+
+    /** Constructor.
+     * @param parent the Dialog which is the owener of this dialog.
+     * @param modal true if this dialog should be modal, ie block user actions to its owner window, false otherwise.
+     */
+    public ModalDialog(Dialog parent, boolean modal) {
+	super(parent, "", false);
+	this.modal = modal;
+    }
+    
+    /** Constructor.
+     * @param parent the Dialog which is the owner of this dialog.
+     * @param title the String to use as the title for this dialog.
+     */
+    public ModalDialog(Dialog parent, String title) {
+	super (parent, title, false);
+	this.modal = false;
+    }
+
+    /** Constructor.
+     * @param parent the Dialog which is the owener of this dialog.
+     * @param title the String to use as the title for this dialog.
+     * @param modal true if this dialog should be modal, ie block user actions to its owner window, false otherwise.
+     */
+    public ModalDialog(Dialog parent, String title, boolean modal) {
+	super (parent, title, false);
+	this.modal = modal;
+    }
+
+   /** Constructor.
+     * @param parent the Frame which is the owener of this dialog.
+     */
+    public ModalDialog(Frame parent) {
+	super(parent, "", false);
+    }
+
+    /** Constructor.
+     * @param parent the Frame which is the owener of this dialog.
+     * @param modal whether this dialog is modal or not
+     */
+    public ModalDialog(Frame parent, boolean modal) {
+	super(parent, "", false);
+	this.modal = modal;
+    }
+    
+    /** Constructor.
+     * @param parent the Frame which is the owner of this dialog.
+     * @param title the String to use as the title for this dialog.
+     */
+    public ModalDialog(Frame parent, String title) {
+	super (parent, title, false);
+    }
+
+    /** Constructor.
+     * @param parent the Frame which is the owener of this dialog.
+     * @param title the String to use as the title for this dialog.
+     * @param modal true if this dialog should be modal, ie block user actions to its owner window, false otherwise.
+     */
+    public ModalDialog(Frame parent, String title, boolean modal) {
+	super (parent, title, false);
+	this.modal = modal;
+    }
+
+    public void dispose() {
+	super.dispose();
+    }
+
+    /** Ensures the current dialog is visible. */
+    public void makeVisible() {
+	super.setVisible(true);
+    }
+
+    /** The set visible method is overriden to provide modal functionality. It essentially hijacks control of the event dispatch thread while the dialog is open, only allowing non-user events to be passed to the parent dialog. Furthermore it only has this effect within the current AWT component tree by utilitizing the TreeLock.
+     * @param visible true if this dialog should be painted on-screen, false otherwise.
+     */
+    public void setVisible(boolean visible)
+    {
+	if (visible) {
+	    current_modal = this;
+	}
+	else {
+	    current_modal = null;
+	}
+
+	// If we are in the AWT Dispatch thread then it is all good.
+ 	if (SwingUtilities.isEventDispatchThread()) {
+ 	    super.setVisible(visible);
+	    if (modal && visible) {
+		EventQueue theQueue = getToolkit().getSystemEventQueue();
+		while (isVisible()) {
+		    try {
+			AWTEvent event = theQueue.getNextEvent();
+			Object src = event.getSource();
+
+			// Block all keyboard and mouse events to the parent component
+			if (src.equals(getParent())) {
+			    if (event instanceof KeyEvent || event instanceof MouseEvent) {
+				// System.err.println("Event to parent component blocked.");
+				continue;
+			    }
+			}
+
+			// Re-dispatch other events
+			if (event instanceof ActiveEvent) {
+  			    ((ActiveEvent) event).dispatch();
+  			}			    
+			else if (src instanceof Component) {
+			    ((Component) src).dispatchEvent(event);
+			}
+		    }
+		    catch (Exception exception) {
+			DebugStream.printStackTrace(exception);
+		    }
+		}
+	    }
+ 	}
+ 	else {
+ 	    try {
+ 		SwingUtilities.invokeAndWait(new MakeDialogVisibleTask(this, visible));
+ 	    }
+ 	    catch (Exception exception) {
+ 		DebugStream.printStackTrace(exception);
+ 	    }
+ 	}
+    }
+    
+    private class MakeDialogVisibleTask
+	implements Runnable {
+	private boolean make_visible;
+	private ModalDialog dialog;
+	public MakeDialogVisibleTask(ModalDialog dialog, boolean make_visible) {
+	    this.dialog = dialog;
+	    this.make_visible = make_visible;
+	}
+	public void run() {
+	    // Blocks until the user dismisses the dialog
+	    dialog.setVisible(make_visible);
+	}
+    }
+
+    /** Overridden method so we can control modality and not rely on the Dialog default.
+     * @param modal true if this dialog should be modal, ie block user actions to its owner window, false otherwise.
+     */
+    public void setModal (boolean modal) {
+	this.modal = modal;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ModalProgressPopup.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ModalProgressPopup.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/ModalProgressPopup.java	(revision 10506)
@@ -0,0 +1,84 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer.gui;
+
+
+import java.awt.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Gatherer;
+
+
+public class ModalProgressPopup
+    extends ModalDialog
+{
+    /** The size of the popup */
+    final static private Dimension SIZE = new Dimension(300, 75);
+
+    private String message = null;
+
+
+    public ModalProgressPopup(String title, String message)
+    {
+	super(Gatherer.g_man, title);
+	this.message = message;
+    }
+
+
+    /** Method to close the popup. */
+    public void close()
+    {
+	setVisible(false);
+	Gatherer.g_man.wait(false);
+    }
+
+
+    /** Method to display the popup on screen. */
+    public void display()
+    {
+	setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+	setSize(SIZE);
+
+	// Create
+	JProgressBar progress_bar = new JProgressBar();
+	progress_bar.setIndeterminate(true);
+
+	// Layout
+	JPanel content_pane = (JPanel) getContentPane();
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(new JLabel(message), BorderLayout.NORTH);
+	content_pane.add(progress_bar, BorderLayout.CENTER);
+
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	setVisible(true);
+
+	// Lock the rest of the GLI interface until close() is called
+	Gatherer.g_man.wait(true);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NewCollectionDetailsPrompt.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NewCollectionDetailsPrompt.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NewCollectionDetailsPrompt.java	(revision 10506)
@@ -0,0 +1,408 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, Greenstone Project, NZDL, University of Waikato
+ *
+ * Copyright (C) 2003 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+public class NewCollectionDetailsPrompt
+    extends ModalDialog {
+
+    static public boolean titleClashes(String title, File current_config_file) {
+	// An empty collection title never clashes with anything. It may look ugly in the final collection but there is nothing wrong with having no title for a particular language.
+	if(title == null || title.length() == 0) {
+	    return false;
+	}
+	File collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	File children[] = collect_directory.listFiles();
+	for(int i = 0; children != null && i < children.length; i++) {
+	    if(children[i].isDirectory()) {
+		File config_file = new File(children[i], Utility.CONFIG_FILE);
+		if(current_config_file == null || !config_file.equals(current_config_file)) {
+		    BasicCollectionConfiguration other_collection = new BasicCollectionConfiguration(config_file);
+		    if(other_collection.getName().equalsIgnoreCase(title)) {  
+			return true;
+		    }
+		    other_collection = null;
+		}
+		config_file = null;
+	    }
+	}
+	return false;
+    }
+
+    private boolean cancelled;
+    private File base_final;
+    private JButton create_button;
+    private JComboBox base_collection;
+    private JDialog self;
+    private JTextArea description;
+    private JTextField title;
+    private String description_final;
+    private String title_final;
+    static private Dimension COMPONENT_SIZE = new Dimension(230, 25);
+    /** The size of this new collection dialog box. */
+    static private Dimension SIZE = new Dimension(600, 280);
+    static private int FILENAME_SIZE = 8;
+
+    /** Constructor.
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    public NewCollectionDetailsPrompt() {
+	super(Gatherer.g_man, true);
+	this.cancelled = true;
+	this.self = this;
+	// Setup
+	setJMenuBar(new SimpleMenuBar("creatingacollection"));
+	setSize(SIZE);
+	Dictionary.setText(this, "NewCollectionPrompt.Title");
+
+	// Model building. Build a model of all of the collections in the gsdl collect directory with the appropriate directories.
+	Vector base_collection_model = new Vector();
+	// need to modify this to base a coll on any collection from any site
+	if (Gatherer.GS3) {
+	    File sites_dir = new File(Gatherer.getSitesDirectoryPath());
+	    File [] sites = sites_dir.listFiles();
+	    for (int i=0; i<sites.length; i++) {
+		File collect_directory = new File(sites_dir + sites[i].getName() + File.separator + "collect");
+		if (collect_directory.exists()) {
+		    addCollectionsToModel(base_collection_model, collect_directory, sites[i].getName());
+		}
+	    }
+	} else {
+	   File collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	   addCollectionsToModel(base_collection_model, collect_directory, null);
+	}
+
+	// Sort the result.
+	Collections.sort(base_collection_model);
+	base_collection_model.add(0, new Item(null, Dictionary.get("NewCollectionPrompt.NewCollection")));
+
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+	content_pane.setOpaque(true);
+	JPanel upper_pane = new JPanel();
+	JLabel instructions_label = new JLabel();
+	Dictionary.setText(instructions_label, "NewCollectionPrompt.Instructions");
+	JPanel title_pane = new JPanel();
+	JLabel title_label = new JLabel();
+	Dictionary.setText(title_label, "CDM.General.Collection_Name");
+	title = new JTextField();
+	title.setPreferredSize(COMPONENT_SIZE);
+	Dictionary.setTooltip(title, "CDM.General.Collection_Name_Tooltip");
+	JPanel name_pane = new JPanel();
+	JLabel name_label = new JLabel();
+	Dictionary.setText(name_label, "NewCollectionPrompt.Collection_Name");
+
+	JPanel center_pane = new JPanel();
+	JPanel description_pane = new JPanel();
+	JLabel description_label = new JLabel();
+	Dictionary.setText(description_label, "NewCollectionPrompt.Collection_Description");
+	description = new JTextArea();
+	description.setBackground(Configuration.getColor("coloring.editable_background", false));
+	description.setForeground(Configuration.getColor("coloring.editable_foreground", false));
+	description.setRows(5);
+	Dictionary.setTooltip(description, "CDM.General.Collection_Extra_Tooltip");
+
+	JPanel bottom_pane = new JPanel();
+	// Base Collection
+	JPanel base_collection_pane = new JPanel();
+	JLabel base_collection_label = new JLabel();
+	Dictionary.setText(base_collection_label, "NewCollectionPrompt.Base_Collection");
+	base_collection = new JComboBox(base_collection_model);
+	Dictionary.setTooltip(base_collection, "NewCollectionPrompt.Base_Collection_Tooltip");
+
+	JPanel button_pane = new JPanel();
+	create_button = new GLIButton();
+	create_button.setMnemonic(KeyEvent.VK_O);
+	Dictionary.setBoth(create_button, "General.OK", "General.OK_Tooltip");
+	JButton cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Cancel", "General.Cancel_Tooltip");
+	// Connection
+	cancel_button.addActionListener(new CancelListener());
+	create_button.addActionListener(new CreateListener());
+	description.addKeyListener(new ColorListener(description));
+	description.addKeyListener(new DescriptionListener());
+	title.addKeyListener(new ColorListener(title));
+
+	// Layout
+	title_pane.setLayout(new BorderLayout(5,0));
+	title_pane.add(title_label, BorderLayout.WEST);
+	title_pane.add(title, BorderLayout.CENTER);
+
+	upper_pane.setLayout(new GridLayout(2,1));
+	upper_pane.add(instructions_label);
+	upper_pane.add(title_pane);
+
+	description_pane.setLayout(new BorderLayout());
+	description_pane.add(description_label, BorderLayout.NORTH);
+	description_pane.add(new JScrollPane(description), BorderLayout.CENTER);
+
+	base_collection_pane.setLayout(new BorderLayout(5,0));
+	base_collection_pane.add(base_collection_label, BorderLayout.WEST);
+	base_collection_pane.add(base_collection, BorderLayout.CENTER);
+
+	center_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
+	center_pane.setLayout(new BorderLayout());
+	center_pane.add(description_pane, BorderLayout.CENTER);
+
+	bottom_pane.setLayout(new BorderLayout());
+	bottom_pane.add(base_collection_pane, BorderLayout.CENTER);
+	bottom_pane.add(button_pane, BorderLayout.SOUTH);
+
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	button_pane.setLayout(new GridLayout(1,2));
+	button_pane.add(create_button);
+	button_pane.add(cancel_button);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(upper_pane, BorderLayout.NORTH);
+	content_pane.add(center_pane, BorderLayout.CENTER);
+	content_pane.add(bottom_pane, BorderLayout.SOUTH);
+	// Final dialog setup & positioning.
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	setVisible(true);
+    }
+
+    public boolean isCancelled() {
+	return cancelled;
+    }
+
+    public File getBase() {
+	return base_final;
+    }
+
+    public String getDescription() {
+	return description_final;
+    }
+ 
+    /** Generates the collection short filename by taking the first eight characters of the title (spaces removed) and then adjusting by further truncating and then adding an unique suffix as necessary.
+     * @return the filename as a String
+     */
+    public String getName() {
+	// Retrieve the first 8 non-whitespace characters of title_final.
+	StringBuffer name_buffer = new StringBuffer("");
+
+	if (Gatherer.isGsdlRemote) {
+	    String username = System.getProperty("user.name");
+	    if ((username != null) && (username != "")) {
+		name_buffer.append(username + "-");
+	    }
+	}
+
+	int i = 0;
+	int u = 0;
+	while(i < title_final.length() && u < 8) {
+	    char c = title_final.charAt(i);
+	    // Arg. We need a few more tests than just whitespace
+	    if(Character.isLetterOrDigit(c)) {
+		name_buffer.append(Character.toLowerCase(c));
+		u++;
+	    }
+	    i++;
+	}
+	// We need to ensure the filename is unique
+	int counter = 0;
+	StringBuffer new_name_buffer = new StringBuffer(name_buffer.toString());
+	while(filenameClashes(new_name_buffer.toString())) {
+	    new_name_buffer = new StringBuffer(name_buffer.toString());
+	    counter++;
+	    String suffix = String.valueOf(counter);
+	    // If we have to truncate the namestring so as to fit the suffix
+	    if(suffix.length() + new_name_buffer.length() > 8) {
+		new_name_buffer.replace(new_name_buffer.length() - suffix.length(), new_name_buffer.length(), suffix);
+	    }
+	    // Or just append it if that isn't necessary
+	    else {
+		new_name_buffer.append(suffix);
+	    }
+	    
+	}
+	// All done
+	return new_name_buffer.toString();
+    }
+    
+    private boolean filenameClashes(String filename)
+    {
+	File collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	File children[] = collect_directory.listFiles();
+	for(int i = 0; children != null && i < children.length; i++) {
+	    if(children[i].getName().equals(filename)) {
+		return true;
+	    }
+	}
+	return false;
+    }
+
+    public String getTitle() {
+	return title_final;
+    }
+
+    private void addCollectionsToModel(Vector base_collection_model, File collect_directory, String site) {
+	File[] possible_collections = collect_directory.listFiles();
+	for (int i = 0; possible_collections != null && i < possible_collections.length; i++) {
+	    // If the directory has a etc/collect.cfg file then it looks like a collection
+	    File collect_cfg_file = new File(possible_collections[i], Utility.CONFIG_FILE);
+	    if (collect_cfg_file.exists()) {
+		// If the directory has a metadata/ then the collection can be used as a base
+		File metadata_directory = new File(possible_collections[i], Utility.META_DIR);
+		if (metadata_directory.exists()) {
+		    // Add to model
+		    BasicCollectionConfiguration collect_cfg = new BasicCollectionConfiguration(collect_cfg_file);
+		    if (Gatherer.GS3 && site != null) {
+			collect_cfg.setSite(site);
+		    }
+		    Item item = new Item(possible_collections[i], collect_cfg);
+		    if (!base_collection_model.contains(item)) {
+			base_collection_model.add(item);
+		    }
+		}
+	    }
+	}
+       
+    }
+
+    private class CancelListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    cancelled = true;
+	    self.dispose();
+	}
+    }
+
+    private class ColorListener
+	extends KeyAdapter {
+	private JTextComponent component1;
+	private JTextComponent component2;
+	public ColorListener(JTextComponent component) {
+	    this.component1 = component;
+	    this.component2 = null;
+	}
+	public ColorListener(JTextComponent component1, JTextComponent component2) {
+	    this.component1 = component1;
+	    this.component2 = component2;
+	}
+	public void keyPressed(KeyEvent event) {
+	    component1.setForeground(Configuration.getColor("coloring.editable_foreground", false));
+	    component1.setBackground(Configuration.getColor("coloring.editable_background", false));
+	    if(component2 != null) {
+		component2.setForeground(Configuration.getColor("coloring.editable_foreground", false));
+		component2.setBackground(Configuration.getColor("coloring.editable_background", false));
+	    }
+	}
+    }
+    
+    private class CreateListener
+	implements ActionListener {
+	
+	public void actionPerformed(ActionEvent event) {
+	    // Validate.
+	    title_final = title.getText();
+	    if(title_final.length() == 0) {
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("NewCollectionPrompt.Title_Error"), Dictionary.get("NewCollectionPrompt.Error"), JOptionPane.ERROR_MESSAGE);
+		return;
+	    }
+	    // We must ensure that the collection title is unique. This is a pain in the nether regions as we are forced to load the collect.cfg of each other collection in turn looking for a conflicting title
+	    else {
+		if(titleClashes(title_final, null)) {
+		    if (JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("NewCollectionPrompt.Title_Clash"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) {
+			return;
+		    }
+		}
+	    }
+
+	    description_final = description.getText();
+
+	    // If we got this far there are no errors.
+	    Item item_final = (Item) base_collection.getSelectedItem();
+	    base_final = item_final.getFile();
+	    
+	    cancelled = false;
+	    
+	    self.dispose();
+	}
+    }
+    
+    private class DescriptionListener
+	extends KeyAdapter {
+	public void keyPressed(KeyEvent event) {
+	    if(event.getKeyCode() == KeyEvent.VK_TAB) {
+		event.consume();
+		base_collection.grabFocus();
+	    }
+	}
+    }
+
+    private class Item
+	implements Comparable {
+	private BasicCollectionConfiguration config;
+	private File file;
+	private String name;
+	public Item(File file, BasicCollectionConfiguration config) {
+	    this.config = config;
+	    this.file = file;
+	    this.name = null;
+	}
+	public Item(File file, String name) {
+	    this.config = null;
+	    this.file = file;
+	    this.name = name;
+	}
+	public int compareTo(Object other) {
+	    return toString().toLowerCase().compareTo(other.toString().toLowerCase());
+	}
+	public boolean equals(Object other) {
+	    return compareTo(other) == 0;
+	}
+	public File getFile() {
+	    return file;
+	}
+	public String toString() {
+	    if(name == null && config != null) {
+		name = config.toString();
+	    }
+	    return name;
+	}
+    }
+}
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NewCollectionMetadataPrompt.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NewCollectionMetadataPrompt.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NewCollectionMetadataPrompt.java	(revision 10506)
@@ -0,0 +1,225 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.util.CheckList;
+import org.greenstone.gatherer.util.CheckListEntry;
+
+
+public class NewCollectionMetadataPrompt
+    extends ModalDialog
+{
+    private boolean cancelled = true;
+    private JDialog self;
+    private JList elements_list;
+    private CheckList metadata_sets_list;
+    static private Dimension size = new Dimension(700, 380);
+
+    public NewCollectionMetadataPrompt() {
+	this(false);
+    }
+    public NewCollectionMetadataPrompt(boolean existing_coll) {
+	super(Gatherer.g_man, true);
+	this.self = this;
+	if (existing_coll) {
+	    setJMenuBar(new SimpleMenuBar("openingacollection"));
+	    Dictionary.setText(this, "NewCollectionPrompt.Metadata_Title_Existing");
+	} else {
+	    setJMenuBar(new SimpleMenuBar("creatingacollection"));
+	    Dictionary.setText(this, "NewCollectionPrompt.Title");
+	}
+	setModal(true);
+	setSize(size);
+
+	// Show the metadata sets (except extracted!) available in the GLI "metadata" folder 
+	ArrayList metadata_sets = MetadataSetManager.listMetadataSets(new File(Gatherer.getGLIMetadataDirectoryPath()));
+	ArrayList metadata_set_list_entries = new ArrayList();
+	for (int i = 0; i < metadata_sets.size(); i++) {
+	    MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
+
+	    // Don't show the extracted metadata set
+	    if (metadata_set.getNamespace().equals(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE)) {
+		continue;
+	    }
+
+	    metadata_set_list_entries.add(metadata_set);
+	}
+
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+
+	JPanel instructions_panel = new JPanel();
+	JLabel instructions_label1 = new JLabel();
+	Dictionary.setText(instructions_label1, "NewCollectionPrompt.Metadata_Instructions1");
+	JLabel instructions_label2 = new JLabel();
+	Dictionary.setText(instructions_label2, "NewCollectionPrompt.Metadata_Instructions2");
+
+	JPanel center_pane = new JPanel();
+
+	JPanel sets_list_pane = new JPanel();
+	JLabel sets_list_label = new JLabel();
+	sets_list_label.setOpaque(false);
+	Dictionary.setText(sets_list_label, "NewCollectionPrompt.Select_MDS");
+	metadata_sets_list = new CheckList(true);
+	metadata_sets_list.addListSelectionListener(new MetadataSetListSelectionListener());
+	metadata_sets_list.setListData(metadata_set_list_entries);
+	metadata_sets_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+	JPanel elements_list_pane = new JPanel();
+	JLabel elements_list_label = new JLabel();
+	Dictionary.setText(elements_list_label, "NewCollectionPrompt.Metadata_Elements");
+	elements_list = new JList();
+	elements_list.setCellRenderer(new MetadataElementListCellRenderer());
+	elements_list.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	elements_list.setForeground(Configuration.getColor("coloring.collection_tree_foreground", false));
+	elements_list.setSelectionBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	elements_list.setSelectionForeground(Configuration.getColor("coloring.collection_tree_foreground", false));
+
+	// Set Dublin Core to be ticked initially, at Ian's request
+	for (int i = 0; i < metadata_set_list_entries.size(); i++) {
+	    MetadataSet metadata_set = (MetadataSet) metadata_set_list_entries.get(i);
+	    if (metadata_set.getMetadataSetFile().getName().equals("dublin.mds")) {
+		metadata_sets_list.setTickedObjects(new Object[] { metadata_set });
+	    }
+	}
+
+	JPanel button_pane = new JPanel();
+	JButton ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_O);
+	Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	JButton cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+
+	// Connection
+	ok_button.addActionListener(new OKButtonListener());
+	cancel_button.addActionListener(new CancelButtonListener());
+
+	// Display
+	instructions_panel.setLayout(new GridLayout(2,1));
+	instructions_panel.add(instructions_label1);
+	instructions_panel.add(instructions_label2);
+
+	sets_list_pane.setLayout(new BorderLayout());
+	sets_list_pane.add(sets_list_label, BorderLayout.NORTH);
+	sets_list_pane.add(new JScrollPane(metadata_sets_list), BorderLayout.CENTER);
+
+	elements_list_pane.setLayout(new BorderLayout());
+	elements_list_pane.add(elements_list_label, BorderLayout.NORTH);
+	elements_list_pane.add(new JScrollPane(elements_list), BorderLayout.CENTER);
+
+	center_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	center_pane.setLayout(new GridLayout(2,1,0,5));
+	center_pane.add(sets_list_pane);
+	center_pane.add(elements_list_pane);
+
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	button_pane.setLayout(new GridLayout(1,2,5,0));
+	button_pane.add(ok_button);
+	button_pane.add(cancel_button);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(instructions_panel, BorderLayout.NORTH);
+	content_pane.add(center_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	// Show
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - size.width) / 2, (screen_size.height - size.height) / 2);
+	setVisible(true);
+    }
+
+    public ArrayList getSets() {
+	return metadata_sets_list.getTicked();
+    }
+
+    public boolean isCancelled() {
+	return cancelled;
+    }
+
+
+    private class CancelButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    cancelled = true;
+	    self.dispose();
+	}
+    }
+
+
+    private class MetadataSetListSelectionListener 
+	implements ListSelectionListener
+    {
+	public void valueChanged(ListSelectionEvent event)
+	{
+	    if (!metadata_sets_list.isSelectionEmpty()) {
+		// Retrieve the selected set
+		MetadataSet metadata_set = (MetadataSet) ((CheckListEntry) metadata_sets_list.getSelectedValue()).getObject();
+		elements_list.setListData(new Vector(metadata_set.getMetadataSetElements()));
+	    }
+	    else {
+		elements_list.setListData(new String[0]);
+	    }
+	}
+    }
+
+
+    private class OKButtonListener
+	implements ActionListener
+    {
+	public void actionPerformed(ActionEvent event)
+	{
+	    // See if the user has selected no metadata sets, and if so confirm thats what they really want.
+	    cancelled = false;
+	    if (metadata_sets_list.isNothingTicked()) {
+		WarningDialog dialog = new WarningDialog("warning.NoMetadataSetsSelected", "NoMetadataSetsSelected.Title", Dictionary.get("NoMetadataSetsSelected.Message"), null, true);
+		if (dialog.display() == JOptionPane.OK_OPTION) {
+		    // Otherwise we are free to go
+		    self.dispose();
+		}
+		dialog.dispose();
+		dialog = null;
+	    }
+	    else {
+		self.dispose();
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NewFolderOrFilePrompt.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NewFolderOrFilePrompt.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NewFolderOrFilePrompt.java	(revision 10506)
@@ -0,0 +1,175 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+import org.greenstone.gatherer.file.FileManager;
+
+public class NewFolderOrFilePrompt
+    extends JDialog 
+    implements ActionListener {
+    private CollectionTreeNode node;
+    private JButton cancel_button;
+    private JButton ok_button;
+    private JTextField name_field;
+    private String name;
+
+    private int type;
+    private String extension="";
+    static final private Dimension SIZE = new Dimension(350,115);
+
+    public NewFolderOrFilePrompt(CollectionTreeNode node, int type, String extension) {
+	super(Gatherer.g_man, true);
+	if (type == FileManager.FILE_TYPE) {
+	    setTitle(Dictionary.get("NewFolderOrFilePrompt.Title_File"));
+	} else {
+	    setTitle(Dictionary.get("NewFolderOrFilePrompt.Title_Folder"));
+	}
+	this.type = type;
+	if (extension != null) {
+	    this.extension = extension;
+	}
+	this.node = node;
+    }
+
+    public void actionPerformed(ActionEvent event) {
+	if (event.getSource() == ok_button) {
+	    name = name_field.getText()+extension;
+	}
+	else if(event.getSource() == cancel_button) {
+	    name = null;
+	}
+	dispose();
+    }
+
+    public String display() {
+	setSize(SIZE);
+	JPanel content_pane = (JPanel) getContentPane();
+
+	JPanel labels_pane = new JPanel();
+	JPanel fields_pane = new JPanel();
+	JPanel info_pane = new JPanel();
+
+	JLabel destination_label = new JLabel();
+	Dictionary.setText(destination_label, "NewFolderOrFilePrompt.Destination_Name");
+	JTextField destination_textfield = new JTextField(node.getFile().getName());
+	destination_textfield.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	destination_textfield.setEditable(false);
+	
+	JLabel name_label = new JLabel();
+	name_field = new JTextField(getAutomaticName());
+	if (type == FileManager.FILE_TYPE) {
+	    Dictionary.setText(name_label, "NewFolderOrFilePrompt.File_Name");
+	    Dictionary.setTooltip(name_field, "NewFolderOrFilePrompt.File_Name_Tooltip");
+	} else {
+	    Dictionary.setText(name_label, "NewFolderOrFilePrompt.Folder_Name");
+	    Dictionary.setTooltip(name_field, "NewFolderOrFilePrompt.Folder_Name_Tooltip");
+	}
+	JPanel button_pane = new JPanel();
+	ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_O);
+	Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+
+	// Connection
+	cancel_button.addActionListener(this);
+	ok_button.addActionListener(this);
+
+	// Layout
+	labels_pane.setLayout(new GridLayout(2,1, 5,0));
+	labels_pane.add(destination_label);
+	labels_pane.add(name_label);
+
+	fields_pane.setLayout(new GridLayout(2,1,0,5));
+	fields_pane.add(destination_textfield);
+	fields_pane.add(name_field);
+	
+	info_pane.setLayout(new BorderLayout(5,0));
+	info_pane.add(labels_pane, BorderLayout.WEST);
+	info_pane.add(fields_pane, BorderLayout.CENTER);
+
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	button_pane.setLayout(new GridLayout(1,2,0,5));
+	button_pane.add(ok_button);
+	button_pane.add(cancel_button);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(info_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	// Display
+	Rectangle frame_bounds = Gatherer.g_man.getBounds();
+	setLocation(frame_bounds.x + (frame_bounds.width - SIZE.width) / 2, frame_bounds.y + (frame_bounds.height - SIZE.height) / 2);
+	setVisible(true);
+	return name;
+    }
+
+    private String getAutomaticName()
+    {
+	File file = node.getFile();
+	String default_name;
+	if (type == FileManager.FILE_TYPE) {
+	    default_name = Dictionary.get("NewFolderOrFilePrompt.Default_File_Name");
+	} else {
+	    default_name = Dictionary.get("NewFolderOrFilePrompt.Default_Folder_Name");
+	}
+	
+	File temp_file = new File(file, default_name+extension);
+	int count = 1;
+	while (temp_file.exists()) {
+	    temp_file = new File(file, default_name + " " + count+extension);
+	    count++;
+	}
+	if (extension.equals("")) {
+	    return temp_file.getName();
+	} 
+	String name = temp_file.getName();
+	// remove the extension
+	return name.substring(0, name.length()-extension.length());
+	
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NonWhitespaceField.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NonWhitespaceField.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/NonWhitespaceField.java	(revision 10506)
@@ -0,0 +1,73 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.gui;
+
+/**************************************************************************************
+ * Written:     04/07/03
+ * Revised:     
+ **************************************************************************************/
+import javax.swing.*;
+import javax.swing.text.*;
+/** A JTextField that doesn't allow whitespace characters. 
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.4
+ */
+public class NonWhitespaceField 
+    extends JTextField {
+ 
+    public NonWhitespaceField() {
+	super();
+    }
+
+    public NonWhitespaceField(String text) {
+	super(text);
+    }
+ 
+    protected Document createDefaultModel() {
+	return new NonWhitespaceDocument();
+    }
+ 
+    static class NonWhitespaceDocument 
+	extends PlainDocument {
+		  
+	public void insertString(int offs, String str, AttributeSet a) 
+	    throws BadLocationException {
+				
+	    if (str == null) {
+		return;
+	    }
+	    char[] raw = str.toCharArray();
+	    StringBuffer result = new StringBuffer("");
+	    for (int i = 0; i < raw.length; i++) {
+		if(!Character.isWhitespace(raw[i])) {
+		    result.append(raw[i]);
+		}
+	    }
+	    super.insertString(offs, result.toString(), a);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/OpenCollectionDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/OpenCollectionDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/OpenCollectionDialog.java	(revision 10506)
@@ -0,0 +1,273 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.beans.*;
+import java.io.File;
+import java.io.IOException;
+import java.text.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
+import org.greenstone.gatherer.collection.CollectionManager;
+import org.greenstone.gatherer.util.JarTools;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+public class OpenCollectionDialog
+    extends JFileChooser {
+    static final private ImageIcon LOCKED_COLLECTION_ICON = JarTools.getImage("lcolicn.gif");
+    static final private ImageIcon NORMAL_COLLECTION_ICON = JarTools.getImage("ncolicn.gif");
+    /** The name of the mouse listener that initiates editing on a double click. */
+    static final private String SINGLE_CLICK_LISTENER = "SingleClickListener";
+
+    /** Constructor */
+    public OpenCollectionDialog(File file) {
+	super(file);
+	///ystem.err.println("Size = " + getSize());
+	// Other initialization
+	setAcceptAllFileFilterUsed(false);
+	setDialogTitle(Dictionary.get("OpenCollectionDialog.Title"));
+	setFileFilter(new GathererFilter());
+	setFileSystemView(new GathererFileSystemView());
+	setFileView(new GathererFileView());
+	setSize(400,300);
+	// Stop the annoying renaming
+	disableRename(this);
+	// Description accessory
+	DescriptionPreview accessory = new DescriptionPreview(this);
+	setAccessory(accessory);
+	// Move accessory
+	JPanel accessory_pane = (JPanel) accessory.getParent();
+	JPanel center_pane = (JPanel) accessory_pane.getParent();
+	center_pane.add(accessory_pane, BorderLayout.SOUTH);
+    }
+
+    public void destroy() {
+    }
+
+    public String getFileName() {
+	// Continually loop until the use chooses an appropriate file or cancels.
+	while(true) {
+	    int return_val = showOpenDialog(null);
+	    if(return_val == JFileChooser.APPROVE_OPTION) {
+		File file = getSelectedFile();
+		if(file != null && file.getName().endsWith(".col")) {
+		    return file.getAbsolutePath();
+		}
+	    }
+	    else {
+		return null;
+	    }
+	}
+    }
+
+    /** Neat method to disable file renaming in filechooser.
+     * Thanks to: vladi21 from www.experts-exchange.com
+     */
+    static public void disableRename(Component c) {
+	if (c instanceof JList){
+	    EventListener[] listeners=c.getListeners(MouseListener.class);
+	    for(int i=0; listeners != null && i < listeners.length; i++) {
+		if (listeners[i].toString().indexOf(SINGLE_CLICK_LISTENER) != -1) {
+		    c.removeMouseListener((MouseListener)listeners[i]);
+		}
+	    }
+	    return;
+	}
+	if (c instanceof Container) {
+	    Component[] children = null;
+	    children = ((Container)c).getComponents();
+	    if (children != null) {
+		for(int i = 0; children != null && i < children.length; i++) {
+		    disableRename(children[i]);
+		}
+	    }
+	}
+    }
+
+
+    /* The DescriptionPreview accessory is adapted from the ImagePreview.java (an example used by FileChooserDemo2.java). */
+    private class DescriptionPreview
+	extends JPanel
+	implements PropertyChangeListener {
+	private File file = null;
+	private JTextArea text;
+
+	public DescriptionPreview(JFileChooser fc) {
+	    setName("Description Preview");
+	    setPreferredSize(new Dimension(100, 75)); // About three rows.
+
+	    text = new JTextArea();
+	    Dictionary.setText(text, "OpenCollectionDialog.No_Description");
+
+	    setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    setLayout(new BorderLayout());
+	    add(new JScrollPane(text), BorderLayout.CENTER);
+
+	    fc.addPropertyChangeListener(this);
+	}
+
+	/** Whenever a new file or folder is selected we determine what description should be displayed. */
+	public void propertyChange(PropertyChangeEvent e) {
+	    boolean update = false;
+	    String prop = e.getPropertyName();
+	    // If the directory changed, don't show an image.
+	    if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(prop)) {
+		file = null;
+		update = true;
+	    }
+	    // If a file became selected, find out which one.
+	    else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals(prop)) {
+		file = (File) e.getNewValue();
+		update = true;
+	    }
+
+	    // Update the description accordingly.
+	    if (update) {
+		if(file == null) {
+		    Dictionary.setText(text, "OpenCollectionDialog.No_Description");
+		}
+		else {
+		    // Build a wrapper around the collection configuration file.
+		    File config_file = new File(file.getParentFile(), Utility.CONFIG_FILE);
+		    if(config_file.exists()) {
+			BasicCollectionConfiguration collect_cfg = new BasicCollectionConfiguration(config_file);
+			text.setText(StaticStrings.SPEECH_CHARACTER + collect_cfg.getName() + StaticStrings.SPEECH_CHARACTER + StaticStrings.NEW_LINE_CHAR);
+			text.setText(collect_cfg.getDescription());
+			text.setCaretPosition(0);
+		    }
+		}
+	    }
+	}
+    }
+
+    /** ImageFilter.java is a 1.4 example used by FileChooserDemo2.java. */
+    private class GathererFilter
+	extends FileFilter {
+
+	// Accept all directories and all .col files
+	public boolean accept(File f) {
+	    return (f.isDirectory() || f.getName().toLowerCase().endsWith(".col"));
+	}
+
+	// The description of this filter
+	public String getDescription() {
+	    return Dictionary.get("OpenCollectionDialog.Collection");
+	}
+    }
+
+    private class GathererFileSystemView
+	extends FileSystemView {
+
+	private FileSystemView default_system_view = FileSystemView.getFileSystemView();
+
+	/** Creates a new folder with a default folder name. */
+	public File createNewFolder(File containingDir)
+	    throws IOException {
+	    return default_system_view.createNewFolder(containingDir);
+	}
+
+	/** Gets the list of shown (i.e. */
+	public File[] getFiles(File dir, boolean useFileHiding) {
+	    // Retrieve the files usually returned by the platform specific file system view.
+	    File[] files = default_system_view.getFiles(dir, useFileHiding);
+	    // Determine if the current dir actually contains a valid greenstone collection. To do this we check for the presence of the file <dir>/etc/collect.cfg and a directory named import.
+	    File collect_cfg_file = new File(dir, Utility.CONFIG_FILE);
+	    File import_dir_file = new File(dir, Utility.IMPORT_DIR);
+	    if(collect_cfg_file.exists() && import_dir_file.exists()) {
+		// Create a new dummy collection file.
+		String name = dir.getName();
+		File collection_file = new File(dir, name + ".col");
+		// If this file doesn't already exist.
+		if(!collection_file.exists()) {
+		    File[] temp = new File[files.length + 1];
+		    System.arraycopy(files, 0, temp, 0, files.length);
+		    temp[files.length] = collection_file;
+		    files = temp;
+		    temp = null;
+		}
+		collection_file = null;
+		name = null;
+	    }
+	    import_dir_file = null;
+	    collect_cfg_file = null;
+	    return files;
+	}
+    }
+
+    /** A FileView which returns differing icons depending on whether a lock file is present within the collection folder. */
+    private class GathererFileView
+	extends FileView {
+
+	public String getDescription(File file) {
+	    String description = null;
+	    if (file.getName().endsWith(".col")) {
+		if (!lockExists(file)) {
+		    description = Dictionary.get("OpenCollectionDialog.Normal_Collection");
+		}
+		else {
+		    description = Dictionary.get("OpenCollectionDialog.Locked_Collection");
+		}
+	    }
+	    return description;
+	}
+
+	public Icon getIcon(File file) {
+	    Icon icon = null;
+	    if (file.getName().endsWith(".col")) {
+		if (!lockExists(file)) {
+		    icon = NORMAL_COLLECTION_ICON;
+		}
+		else {
+		    icon = LOCKED_COLLECTION_ICON;
+		}
+	    }
+	    return icon;
+	}
+
+	/** Determine if a lock file exists. */
+	private boolean lockExists(File file) {
+	    File lock_file = new File(file.getParentFile(), CollectionManager.LOCK_FILE);
+	    return lock_file.exists();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/OptionsPane.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/OptionsPane.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/OptionsPane.java	(revision 10506)
@@ -0,0 +1,544 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.cdm.Argument;
+import org.greenstone.gatherer.collection.ScriptOptions;
+import org.greenstone.gatherer.collection.Collection;
+import org.greenstone.gatherer.collection.CollectionManager;
+import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
+import org.greenstone.gatherer.util.AppendLineOnlyFileDocumentOwner;
+
+/** This class serves as the data holder for all subclasses of option panes, such as Import options or All options. It also contains methods for creating each of the option lines as they would appear in the subpane. Futhermore it has a method for considering all the arguments and generating a <strong>String[]</strong> to allow you to pass them to the <strong>GShell</strong>.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.2
+ */
+public class OptionsPane
+    extends JPanel 
+    implements AppendLineOnlyFileDocumentOwner, MouseListener {
+
+    static final public char SUCCESSFUL = 's';
+    static final public char UNSUCCESSFUL = 'u';
+    static final public char CANCELLED = 'c';
+    static final public char UNKNOWN = 'x';
+
+    static private int BUILD = 0;
+    static private int IMPORT = 1;
+    static private int MINIMUM_ROWS = 11;
+ 
+    /** All process messages are written to this log text area. */
+    public JTextArea log_textarea = null;
+
+    private ArrayList current_controls;
+
+    /** The <strong>ScriptOptions</strong> data object contains all the option settings we wish to persist between Gatherer sessions (and thus is stored in <strong>Collection</strong>). */
+    private ScriptOptions build_options = null;
+    private ScriptOptions import_options = null;
+
+    private FileEntry file_entry = null;
+
+    /** the log pane - we only create it once now, not each time */
+    private JPanel log_pane = null;
+    /** the list of previous log messages */
+    private JList log_list = null;
+    private Vector writing_documents;
+
+
+    /** The default constructor creates the few session length options, but either retrieves the rest from the current collection, or creates a default set of options. */
+    public OptionsPane(ScriptOptions import_options, ScriptOptions build_options) {
+	this.build_options = build_options;
+	this.import_options = import_options;
+	this.current_controls = new ArrayList();
+	this.writing_documents = new Vector();
+
+	// Have to do this here, not in display, as the message log view may not have been displayed yet.
+	log_textarea = new JTextArea();
+	log_textarea.setEditable(false);
+    }
+
+    /** This method creates the panel with all the build only options on it.
+     * @param pane a JPanel which already has previous arguments available on it, to allow for lower moes to concatenate all of the arguments together
+     * @return a JPanel which can be used to display all the build only options
+     * @see org.greenstone.gatherer.Configuration#EXPERT_MODE
+     * @see org.greenstone.gatherer.Configuration#getColor
+     * @see org.greenstone.gatherer.Configuration#getMode
+     * @see org.greenstone.gatherer.Gatherer#config
+     * @see org.greenstone.gatherer.cdm.Argument
+     * @see org.greenstone.gatherer.collection.BuildOptions#getBuildArgument
+     * @see org.greenstone.gatherer.collection.BuildOptions#getBuildArgumentCount
+     * @see org.greenstone.gatherer.collection.BuildOptions#getBuildValue
+     * @see org.greenstone.gatherer.collection.BuildOptions#getBuildValueEnabled
+     * @see org.greenstone.gatherer.gui.OptionsPane.MyArgumentControl
+     */
+    public JPanel buildBuild(JPanel pane) {
+	// Reset the arguments
+	if(pane == null) {
+	    current_controls.clear();
+	}
+	ArrayList build_arguments = new ArrayList();
+	int current_mode = Configuration.getMode();
+	int total_build_argument_count = build_options.getArgumentCount();
+       
+	for(int i = 0; i < total_build_argument_count; i++) {
+	    // Retrieve the argument so we know how to format the control.
+	    Argument argument = build_options.getArgument(i);
+	    if(!argument.isHiddenGLI() && argument.getModeLevel() <= current_mode) {
+		// Now attempt to retrieve any existing value for this argument.
+		boolean enabled = build_options.getValueEnabled(argument.getName());
+		String value = build_options.getValue(argument.getName());
+		MyArgumentControl argument_control = new MyArgumentControl(BUILD, argument, enabled, value);
+		build_arguments.add(argument_control);
+	    }
+	}
+	current_controls.addAll(build_arguments);
+	// Now that we know how many arguments there are we can build the pane to view them on. Modes lower than EXPERT can provide a previous pane on which to add the arguments.
+	if(pane == null || current_mode >= Configuration.EXPERT_MODE) {
+	    pane = new JPanel();
+	    pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    pane.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    int argument_count = build_arguments.size();
+	    // If in any of the higher detail modes, and assuming we don't want super phat argument controls, we better ensure there is a minimum number or lines in the grid layout
+	    if(current_mode >= Configuration.EXPERT_MODE) {
+		if(argument_count < MINIMUM_ROWS) {
+		    argument_count = MINIMUM_ROWS;
+		}
+		pane.setLayout(new GridLayout(argument_count, 1, 5, 5));
+	    }
+	    // Otherwise we're just going to throw them on one after another and chuck it in a scroll pane anyway
+	    else {
+		pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
+	    }
+	}
+	for(int j = 0; j < build_arguments.size(); j++) {
+	    pane.add((JComponent)build_arguments.get(j));
+	}
+	pane.addMouseListener(this);
+	build_arguments = null;
+	return pane;
+    }
+
+    /** This method creates the panel with all the import only options on it.
+     * @param pane a JPanel which already has previous arguments available on it, to allow for lower moes to concatenate all of the arguments together
+     * @return a JPanel which can be used to display all the build only options
+     * @see org.greenstone.gatherer.Configuration#EXPERT_MODE
+     * @see org.greenstone.gatherer.Configuration#getColor
+     * @see org.greenstone.gatherer.Configuration#getMode
+     * @see org.greenstone.gatherer.Gatherer#config
+     * @see org.greenstone.gatherer.cdm.Argument
+     * @see org.greenstone.gatherer.collection.BuildOptions#getImportArgument
+     * @see org.greenstone.gatherer.collection.BuildOptions#getImportArgumentCount
+     * @see org.greenstone.gatherer.collection.BuildOptions#getImportValue
+     * @see org.greenstone.gatherer.collection.BuildOptions#getImportValueEnabled
+     * @see org.greenstone.gatherer.gui.OptionsPane.ArgumentControl
+     */
+    public JPanel buildImport(JPanel pane) {
+	// Reset the arguments
+	if(pane == null) {
+	    current_controls.clear();
+	}
+	ArrayList import_arguments = new ArrayList();
+	int current_mode = Configuration.getMode();
+	int total_import_argument_count = import_options.getArgumentCount();       
+	for(int i = 0; i < total_import_argument_count; i++) {
+	    // Retrieve the argument so we know how to format the control.
+	    Argument argument = import_options.getArgument(i);
+	    if(!argument.isHiddenGLI() && argument.getModeLevel() <= current_mode) {
+		// Now attempt to retrieve any existing value for this argument.
+		boolean enabled = import_options.getValueEnabled(argument.getName());
+		String value = import_options.getValue(argument.getName());
+		MyArgumentControl argument_control = new MyArgumentControl(IMPORT, argument, enabled, value);
+		import_arguments.add(argument_control);
+	    }
+	}
+	current_controls.addAll(import_arguments);
+	// Now that we know how many arguments there are we can build the pane to view them on. Modes lower than EXPERT can provide a previous pane on which to add the arguments.
+	if(pane == null || current_mode >= Configuration.EXPERT_MODE) {
+	    pane = new JPanel();
+	    pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    pane.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
+	    int argument_count = import_arguments.size();
+	    // If in any of the higher detail modes, and assuming we don't want super phat argument controls, we better ensure there is a minimum number or lines in the grid layout
+	    if(current_mode >= Configuration.EXPERT_MODE) {
+		if(argument_count < MINIMUM_ROWS) {
+		    argument_count = MINIMUM_ROWS;
+		}
+		pane.setLayout(new GridLayout(argument_count, 1, 5, 5));
+	    }
+	    // Otherwise we're just going to throw them on one after another and chuck it in a scroll pane anyway
+	    else {
+		pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
+	    }
+	}
+	for(int j = 0; j < import_arguments.size(); j++) {
+	    pane.add((JComponent)import_arguments.get(j));
+	}
+	pane.addMouseListener(this);
+	import_arguments = null;
+	return pane;
+    }
+
+    /** This method is used to build a panel based on the message log, which is nothing like any of the other panels.
+     * @return A <strong>JPanel</strong> containing a scrollable text area which represents the shell process message log.
+     */
+    public JPanel buildLog() {
+	// we now save the log pane
+	if (log_pane == null) {
+	    log_pane = new JPanel(new BorderLayout());
+
+	    // Build a list of the log files available, ordering by last modified. Log files are like build_log.date.txt
+	    DefaultListModel contents = new DefaultListModel();
+	    File log_directory = new File(Gatherer.c_man.getCollectionLogDirectoryPath());
+	    File children[] = log_directory.listFiles();
+	    for(int i = 0; children != null && i < children.length; i++) {
+		String filename = children[i].getName();
+		if(filename.startsWith("build_log.") && filename.endsWith(".txt") ) {
+		    String datestamp = filename.substring(filename.indexOf(".") + 1, filename.lastIndexOf(".")).toLowerCase();
+		    if(datestamp.indexOf("s") == -1 && datestamp.indexOf("u") == -1 && datestamp.indexOf("c") == -1 && datestamp.indexOf("x") == -1) {
+			FileEntry entry = new FileEntry(children[i].getName(), children[i].getAbsolutePath());
+			// We are about to insert it. But where.
+			boolean found = false;
+			for(int j = 0; !found && j < contents.size(); j++) {
+			    FileEntry sibling = (FileEntry) contents.getElementAt(j);
+			    int order = entry.compareTo(sibling);
+			    if(order > 0) {
+				contents.insertElementAt(entry, j);
+				found = true;
+			    }
+			}
+			if(!found) {
+			    contents.addElement(entry);
+			}
+		    }
+		}
+	    }
+
+	    log_list = new JList(contents);
+	    log_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	    log_list.setLayoutOrientation(JList.VERTICAL);
+	    log_list.setPreferredSize(new Dimension(600, 100));
+	    log_list.setVisibleRowCount(3);
+	    log_list.addListSelectionListener(new LogListListener());
+
+	    JLabel log_history_label = new JLabel();
+	    Dictionary.registerText(log_history_label, "OptionsPane.LogHistory");
+	    JPanel log_history_pane = new JPanel();
+	    log_history_pane.setPreferredSize(new Dimension(600, 100));
+	    log_history_pane.setLayout(new BorderLayout());
+	    log_history_pane.add(log_history_label, BorderLayout.NORTH);
+	    log_history_pane.add(new JScrollPane(log_list), BorderLayout.CENTER);
+	    
+	    log_pane.add(new JScrollPane(log_textarea), BorderLayout.CENTER);
+	    log_pane.add(log_history_pane, BorderLayout.SOUTH);
+	}
+	return log_pane;
+    }
+
+    public AppendLineOnlyFileDocument createNewLogDocument() {
+	long time = System.currentTimeMillis();
+	StringBuffer name = new StringBuffer();
+	name.append("build_log.");
+	name.append(time);
+	name.append(".txt");
+	// just in case there is no log directory
+	File file = new File(Gatherer.c_man.getCollectionLogDirectoryPath() + name.toString());
+	File parent_file = file.getParentFile();
+	parent_file.mkdirs();
+	parent_file = null;
+	// create the file entry and add it to the list at pos 0 - it will always be the newest one created
+	file_entry = new FileEntry(name.toString(), file.getAbsolutePath());
+	((DefaultListModel)log_list.getModel()).add(0, file_entry);
+	log_list.setSelectedIndex(0);
+	// Finally retrieve and return the document associated with this file entry
+	return file_entry.getDocument();
+    }
+
+
+    /** Attempts to discover the latest document count.
+     * @return An <strong>int</strong> detailing the number of documents in this collection.
+     */
+    public int getDocumentCount() {
+	if(Gatherer.c_man.ready()) {
+	    int count = Gatherer.c_man.getCollection().getDocumentCount();
+	    if(count != 0) {
+		return count;
+	    }
+	}
+	return 1;
+    }
+
+    /** Called by our magic log documents after they have finished writing themselves to file, whereapon it is no longer necessary to hold a reference to them. */
+    public void remove(AppendLineOnlyFileDocument document) {
+	writing_documents.remove(document);
+    }
+
+    public void resetFileEntry() {
+	if(file_entry != null) {
+	    file_entry.reset();
+	}
+    }
+
+    /** Given a panel containing ArgumentControls, update the values associated with them. */
+    public void update(JPanel panel) {
+	if(panel == log_pane) {
+	    return;
+	}
+
+	for(int i = 0; i < panel.getComponentCount(); i++) {
+	    Component component = panel.getComponent(i);
+	    if(component instanceof MyArgumentControl) {
+		((MyArgumentControl)component).update();
+	    }
+	}
+    }
+
+    /** Implementation side-effect
+     * @param e a MouseEvent
+     */
+    public void mouseClicked(MouseEvent e) {}
+
+    /** Implementation side-effect
+     * @param e a MouseEvent
+     */
+    public void mouseEntered(MouseEvent e) {}
+
+    /** Implemented to ensure that, by the time the mouse pointer leaves the current build options screen, ang changes to the value the JSpinners have been commited
+     * @param e a MouseEvent
+     */
+    public void mouseExited(MouseEvent e) {
+	// Loop through the controls, and if the current control is a JSpinner, commit its current editing
+	for(int i = 0; i < current_controls.size(); i++) {
+	    MyArgumentControl control = (MyArgumentControl) current_controls.get(i);
+	    JComponent value_control = control.getValueControl();
+	    if(value_control instanceof JSpinner) {
+		try {
+		    ((JSpinner)value_control).commitEdit();
+		}
+		catch(Exception exception) {
+		    DebugStream.println("Exception in OptionsPane.mouseExited() - unexpected");
+		    DebugStream.printStackTrace(exception);
+		}
+	    }
+	    value_control = null;
+	    control = null;
+	}
+    }
+
+    /** Implementation side-effect
+     * @param e a MouseEvent
+     */
+    public void mousePressed(MouseEvent e) {}
+
+    /** Implementation side-effect
+     * @param e a MouseEvent
+     */
+    public void mouseReleased(MouseEvent e) {}
+
+    private class MyArgumentControl
+	extends ArgumentControl {
+	private int type;
+
+	public MyArgumentControl(int type, Argument argument, boolean enable, String value) {
+	    super(argument, enable, value);
+	    this.type = type;
+	}
+
+	/** Update the values stored in the collection so as to remember the current state of this argument. */
+	public void update() {
+	    String name = getName();
+	    boolean enable = isEnabled();
+	    String value = getValue();
+	    // If this argument was a flag, but is now disabled, remove from the build options altogether
+	    if(!enable && value == null) {
+		if(type == BUILD) {
+		    build_options.removeValue(name);
+		}
+		else {
+		    import_options.removeValue(name);
+		}
+	    }
+	    // Otherwise update the argument value
+	    else {
+		if(type == BUILD) {
+		    build_options.setValue(name, enable, value);
+		}
+		else {
+		    import_options.setValue(name, enable, value);
+		}
+	    }
+	}
+    }
+
+    /** Holds a File which has a particular naming convention build_log.date.txt also keeps a Date corresponding to the date in its name*/
+    private class FileEntry {
+
+       private AppendLineOnlyFileDocument current_document;
+       private Date date;
+       private long last_modified;
+       private String display;
+       private String filename;
+       private String filepath;
+       
+       public FileEntry(String filename, String filepath) {
+	  this.date = null;
+	  this.display = null;
+	  this.filename = filename;
+	  this.filepath = filepath;
+	  this.last_modified = 0L;
+       }
+
+	/** returns 0 if the dates are the same, -ve number if the current FileEntry is earlier than the fe FileEntry ...*/
+	public int compareTo(FileEntry file_entry) {
+	    Date our_date = getDate();
+	    Date other_date = file_entry.getDate();
+	    return our_date.compareTo(other_date);
+	}
+
+	public Date getDate() {
+	    if(date == null) {
+		// Need to exclude first '.'
+		int first_index = filename.indexOf(".") + 1;
+		// Need to exclude the last '.'
+		int last_index = filename.lastIndexOf(".");
+		if(first_index > 0 && last_index > 0 && first_index < last_index) {
+		    String date_string = filename.substring(first_index, last_index);
+		    date = new Date(Long.parseLong(date_string));
+		}
+		else {
+		    date = new Date(); // Current date
+		}
+	    }
+	    return date;
+	}
+
+       public AppendLineOnlyFileDocument getDocument() {
+	  if(current_document == null) {
+	     current_document = new AppendLineOnlyFileDocument(filepath);
+	  }
+	  return current_document;
+	}
+
+	public void reset() {
+	    display = null;
+	}
+
+	/** we only want the date out of the file name, not the whole path */
+	public String toString() {
+	    File file = new File(filename);
+	    if(display == null) {
+		last_modified = file.lastModified();
+		StringBuffer d = new StringBuffer();
+		Date date = getDate();
+		d.append(date.toString());
+		char success = UNKNOWN;
+		File the_file = new File(filepath);
+		if(the_file.exists()) {
+		   try {
+		      FileInputStream in = new FileInputStream(the_file);
+		      success = (char) in.read();
+		      in.close();
+		      in = null;
+		   }
+		   catch(Exception error) {
+		      ///ystem.err.println("Log '" + filepath + "' not found!");
+		      ///atherer.printStackTrace(error);
+		   }
+		}
+		the_file = null;
+		switch (success) {
+		case SUCCESSFUL:
+		    d.append(Dictionary.get("OptionsPane.Successful"));
+		    break;
+		case UNSUCCESSFUL:
+		    d.append(Dictionary.get("OptionsPane.Unsuccessful"));
+		    break;
+		case CANCELLED:
+		    d.append(Dictionary.get("OptionsPane.Cancelled"));
+		    break;
+		default:
+		    d.append(Dictionary.get("OptionsPane.Unknown"));
+		}
+		display = d.toString();
+	    }
+	    return display;
+	}
+    }
+
+    /** a ListSelectionListener that triggers the load of a newly selected log */
+    private class LogListListener implements ListSelectionListener {
+
+	public void valueChanged(ListSelectionEvent e) {
+	    if (!e.getValueIsAdjusting()) { // we get two events for one change in list selection - use the false one ( the second one)
+		///ystem.err.println("Log change detected.");
+		JList source  = (JList)e.getSource();
+		file_entry = (FileEntry) source.getSelectedValue();
+		// First we determine if the old log has been completely written to file
+		Document document = log_textarea.getDocument();
+		///ystem.err.println(" * current document: " + document);
+		///ystem.err.println(" * new document:     " + file_entry.getDocument());
+		// If we are dealing with the same document don't do anything.
+		if(document != file_entry.getDocument()) {
+		    if(document instanceof AppendLineOnlyFileDocument) {
+			AppendLineOnlyFileDocument append_line_only_file_document = (AppendLineOnlyFileDocument) document;
+			if(append_line_only_file_document.isStillWriting()) {
+			    ///ystem.err.println("Current log is still active... finishing.");
+			    writing_documents.add(append_line_only_file_document); // We have to maintain a reference until they are all done.
+			    append_line_only_file_document.setOwner(OptionsPane.this);
+			    append_line_only_file_document.setExit();
+			}
+			else {
+			    ///ystem.err.println("Current log is complete. Nothing to do.");
+			}
+		    }
+		    // Load the new log
+		    log_textarea.setDocument(file_entry.getDocument());
+		}
+	    }
+	}
+    }
+
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/Preferences.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/Preferences.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/Preferences.java	(revision 10506)
@@ -0,0 +1,891 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.gui;
+
+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.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.cdm.ClassifierManager;
+import org.greenstone.gatherer.cdm.LanguageManager;
+import org.greenstone.gatherer.cdm.PluginManager;
+import org.greenstone.gatherer.collection.Collection;
+import org.greenstone.gatherer.gui.tree.DragTree;
+import org.greenstone.gatherer.util.ArrayTools; // just for debug
+import org.greenstone.gatherer.util.CheckList;
+import org.greenstone.gatherer.util.CheckListEntry;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+public class Preferences
+    extends ModalDialog
+{
+    static final public String CONNECTION_PREFS = "connection";
+    static final public String GENERAL_PREFS = "general";
+
+    static final private Dimension LABEL_SIZE = new Dimension(280, 25);
+    static final private Dimension ROW_SIZE = new Dimension(640, 25);
+    static final private Dimension SIZE = new Dimension(640, 345);
+    static final private String TRUE = "true";
+
+    private CheckList warning_preferences_check_list;
+    private EmailField email_field;
+    private JButton apply_button;
+    private JButton cancel_button;
+    private JButton ok_button;
+    private JCheckBox show_file_size_checkbox;
+    private JCheckBox use_proxy_checkbox;
+    private JCheckBox view_extracted_metadata_checkbox;
+    private JCheckBox workflow_download;
+    private JCheckBox workflow_gather;
+    private JCheckBox workflow_enrich;
+    private JCheckBox workflow_design;
+    private JCheckBox workflow_create;
+    private JComboBox language_combobox;
+    private JComboBox servlet_combobox; // GS3
+    private JComboBox site_combobox; // GS3
+    private JRadioButton assistant_mode_radio_button;
+    private JRadioButton expert_mode_radio_button;
+    private JRadioButton librarian_mode_radio_button;
+    private JRadioButton systems_mode_radio_button;
+    private JSpinner proxy_port_field;
+    private JTabbedPane tab_pane;
+    private JTextArea mode_description_textarea;
+    private JTextField font_field;
+    private JTextField library_path_field;
+    private JTextField program_field;
+    private JTextField proxy_host_field;
+    private Preferences self;
+
+    private String current_site_selection;
+
+    public Preferences() {
+	this(GENERAL_PREFS);
+    }
+
+    public Preferences(String initial_view) {
+	// Initialize
+	super(Gatherer.g_man, true);
+	this.self = this;
+	setSize(SIZE);
+	Dictionary.registerText(this, "Preferences");
+	setJMenuBar(new SimpleMenuBar("preferences"));
+
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+	tab_pane = new JTabbedPane();
+	JPanel general_preferences = createGeneralPreferences();
+	tab_pane.add("Preferences.General", general_preferences); // Also uses "Preferences.General_Tooltip"
+	tab_pane.add("Preferences.Mode", createModePreferences()); // Also uses "Preferences.Mode_Tooltip"
+	tab_pane.add("Preferences.Workflow", createWorkflowPreferences()); // Also uses "Preferences.Workflow_Tooltip"
+	JPanel connection_preferences = createConnectionPreferences();
+	tab_pane.add("Preferences.Connection", connection_preferences); // Also uses "Preferences.Connection_Tooltip"
+	tab_pane.add("Preferences.Warnings", createWarningPreferences()); // Also uses "Preferences.Warnings_Tooltip"
+	Dictionary.register(tab_pane);
+
+	JPanel button_pane = new JPanel();
+	ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_O);
+	Dictionary.registerBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	apply_button = new GLIButton();
+	apply_button.setMnemonic(KeyEvent.VK_A);
+	Dictionary.registerBoth(apply_button, "General.Apply", "General.Apply_Tooltip");
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.registerBoth(cancel_button, "General.Cancel", "General.Cancel_Tooltip");
+
+	// Connection
+	ok_button.addActionListener(new OKButtonListener(true));
+	apply_button.addActionListener(new OKButtonListener(false));
+	cancel_button.addActionListener(new CancelButtonListener());
+
+	// Layout
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,2,2,2));
+	button_pane.setLayout(new GridLayout(1,3,0,5));
+	button_pane.add(ok_button);
+	button_pane.add(apply_button);
+	button_pane.add(cancel_button);
+
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(tab_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	Dimension frame_size = Gatherer.g_man.getSize();
+	Point frame_location = Gatherer.g_man.getLocation();
+	setLocation(((frame_size.width - SIZE.width) / 2), ((frame_size.height - SIZE.height)));
+
+	// Bring the desired pane to the fore
+	if (initial_view.equals(CONNECTION_PREFS)) {
+	    tab_pane.setSelectedComponent(connection_preferences);
+	}
+	else {
+	    tab_pane.setSelectedComponent(general_preferences);
+	}
+	
+	// Clean up
+	general_preferences = null;
+	connection_preferences = null;
+	frame_location = null;
+	frame_size = null;
+	cancel_button = null;
+	ok_button = null;
+	button_pane = null;
+	tab_pane = null;
+	content_pane = null;
+
+	setVisible(true);
+    }
+
+    private JPanel createConnectionPreferences() {
+	JPanel program_pane = new JPanel();
+	program_pane.setPreferredSize(ROW_SIZE);
+	JLabel program_label = new JLabel();
+	program_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.registerText(program_label, "Preferences.Connection.ProgramCommand");
+	program_field = new JTextField(Configuration.getPreviewCommand());
+	program_field.setCaretPosition(0);
+	Dictionary.registerTooltip(program_field, "Preferences.Connection.ProgramCommand_Tooltip");
+
+	JPanel library_path_pane = new JPanel();
+	library_path_pane.setPreferredSize(ROW_SIZE);
+	JLabel library_path_label = new JLabel();
+	library_path_label.setPreferredSize(LABEL_SIZE);
+	String library_url_string = "";
+	if (Configuration.library_url != null) {
+	    library_url_string = Configuration.library_url.toString();
+	}
+	library_path_field = new JTextField(library_url_string);
+	library_path_field.setCaretPosition(0);
+	if (Gatherer.GS3) {
+	    Dictionary.registerText(library_path_label, "Preferences.Connection.Library_Path_GS3");
+	    Dictionary.registerTooltip(library_path_field, "Preferences.Connection.Library_Path_Tooltip_GS3");
+	} else {
+	    Dictionary.registerText(library_path_label, "Preferences.Connection.Library_Path");
+	    Dictionary.registerTooltip(library_path_field, "Preferences.Connection.Library_Path_Tooltip");
+	}
+	
+
+	JPanel site_pane = null;
+	JLabel site_label = null;
+	JPanel servlet_pane = null;
+	JLabel servlet_label = null;
+	if (Gatherer.GS3) {
+	    site_pane = new JPanel();
+	    site_pane.setPreferredSize(ROW_SIZE);
+	    site_label = new JLabel();
+	    Dictionary.registerText(site_label, "Preferences.Connection.Site");
+	    site_label.setPreferredSize(LABEL_SIZE);
+	    // what should we do if Gatherer.servlet_config.getSites() is null?
+	    site_combobox = new JComboBox(Gatherer.servlet_config.getSites().toArray());
+	    Dictionary.registerTooltip(site_combobox, "Preferences.Connection.Site_Tooltip");
+	    servlet_pane = new JPanel();
+	    servlet_pane.setPreferredSize(ROW_SIZE);
+	    servlet_label = new JLabel();
+	    Dictionary.registerText(servlet_label, "Preferences.Connection.Servlet");
+	    servlet_label.setPreferredSize(LABEL_SIZE);
+	    servlet_combobox = new JComboBox();
+	    // try to locate and select the current site
+	    String this_site = Configuration.site_name;
+	    for(int b = 0; b < site_combobox.getItemCount(); b++) {
+		String entry = (String) site_combobox.getItemAt(b);
+		if(this_site.equals(entry)) {
+		    site_combobox.setSelectedIndex(b);
+		    break;
+		}
+	    }
+
+	    // just in case its not the current one?
+	    current_site_selection = (String)site_combobox.getSelectedItem();
+
+	    ArrayList servlet_options = Gatherer.servlet_config.getServletsForSite(current_site_selection);
+	    if (servlet_options == null) {
+		//servlet_combobox.setModel(new DefaultComboBoxModel());
+		Dictionary.registerTooltip(servlet_combobox, "Preferences.Connection.Servlet_Tooltip2");
+		servlet_combobox.setEnabled(false);
+	    } else {
+		System.err.println(ArrayTools.objectArrayToString(servlet_options.toArray()));
+
+		servlet_combobox.setModel(new DefaultComboBoxModel(servlet_options.toArray()));
+		Dictionary.registerTooltip(servlet_combobox, "Preferences.Connection.Servlet_Tooltip");
+		servlet_combobox.setEnabled(true);
+		// try to locate and select the current servlet
+		String this_servlet = Configuration.getServletPath();
+		for(int b = 0; b < servlet_combobox.getItemCount(); b++) {
+		    String entry = (String) servlet_combobox.getItemAt(b);
+		    if(this_servlet.equals(entry)) {
+			servlet_combobox.setSelectedIndex(b);
+			break;
+		    }
+		}
+		
+	    }
+	}
+	
+	boolean currently_enabled = Configuration.get("general.use_proxy", true);
+	// Creation
+	JPanel connection_pane = new JPanel();
+	use_proxy_checkbox = new JCheckBox();
+	use_proxy_checkbox.setSelected(currently_enabled);
+	Dictionary.registerText(use_proxy_checkbox, "Preferences.Connection.Use_Proxy");
+
+	use_proxy_checkbox.setPreferredSize(ROW_SIZE);
+	JPanel proxy_host_pane = new JPanel();
+	proxy_host_pane.setPreferredSize(ROW_SIZE);
+	JLabel proxy_host_label = new JLabel();
+	proxy_host_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.registerText(proxy_host_label, "Preferences.Connection.Proxy_Host");
+	proxy_host_field = new JTextField(Configuration.getString("general.proxy_host", true));
+	proxy_host_field.setEnabled(currently_enabled);
+	Dictionary.registerTooltip(proxy_host_field, "Preferences.Connection.Proxy_Host_Tooltip");
+	JPanel proxy_port_pane = new JPanel();
+	proxy_port_pane.setPreferredSize(ROW_SIZE);
+	JLabel proxy_port_label = new JLabel();
+	proxy_port_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.registerText(proxy_port_label, "Preferences.Connection.Proxy_Port");
+	String port_value = Configuration.getString("general.proxy_port", true);
+	if(port_value.length() > 0) {
+	   proxy_port_field = new JSpinner(new SpinnerNumberModel((new Integer(port_value)).intValue(), 0, 65535, 1));
+	}
+	else {
+	   proxy_port_field = new JSpinner(new SpinnerNumberModel(0, 0, 65535, 1));
+	}
+	proxy_port_field.setEnabled(currently_enabled);
+	Dictionary.registerTooltip(proxy_port_field, "Preferences.Connection.Proxy_Port_Tooltip");
+
+	// Connection
+	use_proxy_checkbox.addActionListener(new UseProxyListener());
+	if (Gatherer.GS3) {
+	    site_combobox.addActionListener(new SiteComboboxListener());
+	}
+	// Layout
+	program_pane.setLayout(new BorderLayout());
+	program_pane.add(program_label, BorderLayout.WEST);
+	program_pane.add(program_field, BorderLayout.CENTER);
+
+	library_path_pane.setLayout(new BorderLayout());
+	library_path_pane.add(library_path_label, BorderLayout.WEST);
+	library_path_pane.add(library_path_field, BorderLayout.CENTER);
+
+	if (Gatherer.GS3) {
+	    site_pane.setLayout(new BorderLayout());
+	    site_pane.add(site_label, BorderLayout.WEST);
+	    site_pane.add(site_combobox, BorderLayout.CENTER);
+
+	    servlet_pane.setLayout(new BorderLayout());
+	    servlet_pane.add(servlet_label, BorderLayout.WEST);
+	    servlet_pane.add(servlet_combobox, BorderLayout.CENTER);
+	}
+	proxy_host_pane.setLayout(new BorderLayout());
+	proxy_host_pane.add(proxy_host_label, BorderLayout.WEST);
+	proxy_host_pane.add(proxy_host_field, BorderLayout.CENTER);
+
+	proxy_port_pane.setLayout(new BorderLayout());
+	proxy_port_pane.add(proxy_port_label, BorderLayout.WEST);
+	proxy_port_pane.add(proxy_port_field, BorderLayout.CENTER);
+
+	connection_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	connection_pane.setLayout(new GridLayout(8,1,0,2));
+	connection_pane.add(program_pane);
+	connection_pane.add(library_path_pane);
+	if (Gatherer.GS3) {
+	    connection_pane.add(site_pane);
+	    connection_pane.add(servlet_pane);
+	}
+	connection_pane.add(use_proxy_checkbox);
+	connection_pane.add(proxy_host_pane);
+	connection_pane.add(proxy_port_pane);
+
+	return connection_pane;
+    }
+
+    private JPanel createGeneralPreferences() {
+	JPanel general_pane = new JPanel();
+
+	// Build the model of available languages
+	ArrayList dictionary_model = new ArrayList();
+
+	// The new method makes use of the successor to the languages.dat file, classes/xml/languages.xml
+	NodeList language_elements = LanguageManager.LANGUAGES_DOCUMENT.getDocumentElement().getElementsByTagName(StaticStrings.LANGUAGE_ELEMENT);
+	for(int i = 0; i < language_elements.getLength(); i++) {
+	    Element language_element = (Element) language_elements.item(i);
+	    if((language_element.getAttribute(StaticStrings.GLI_ATTRIBUTE)).equalsIgnoreCase(StaticStrings.TRUE_STR) || (language_element.getAttribute(StaticStrings.MDS_ATTRIBUTE)).equalsIgnoreCase(StaticStrings.TRUE_STR)) {
+		Locale locale = new Locale(language_element.getAttribute(StaticStrings.CODE_ATTRIBUTE));
+		String description = language_element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+		DictionaryEntry entry = new DictionaryEntry(description, locale);
+		if(!dictionary_model.contains(entry)) {
+		    dictionary_model.add(entry);
+		}
+		entry = null;
+		description = null;
+		locale = null;
+	    }
+	    language_element = null;
+	}
+	language_elements = null;
+
+	// Users email
+	JPanel email_pane = new JPanel();
+	JLabel email_label = new JLabel();
+	email_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.registerText(email_label, "Preferences.General.Email");
+	email_field = new EmailField(Configuration.getColor("coloring.error_background", false));
+	email_field.setText(Configuration.getEmail());
+	Dictionary.registerTooltip(email_field, "Preferences.General.Email_Tooltip");
+
+	// Font selection
+	JPanel font_pane = new JPanel();
+	JLabel font_label = new JLabel();
+	font_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.registerText(font_label, "Preferences.General.Font");
+	font_field = new JTextField(Configuration.getString("general.font", true));
+	Dictionary.registerTooltip(font_field, "Preferences.General.Font_Tooltip");
+
+	// Extracted metadata
+	view_extracted_metadata_checkbox = new JCheckBox();
+	view_extracted_metadata_checkbox.setSelected(false);
+	if (Configuration.get("general.view_extracted_metadata", Configuration.COLLECTION_SPECIFIC)) {
+	    view_extracted_metadata_checkbox.setSelected(true);
+	}
+	Dictionary.registerBoth(view_extracted_metadata_checkbox, "Preferences.General.View_Extracted_Metadata", "Preferences.General.View_Extracted_Metadata_Tooltip");
+
+	// Show file sizes
+	show_file_size_checkbox = new JCheckBox();
+	show_file_size_checkbox.setSelected(false);
+	if (Configuration.get("general.show_file_size", Configuration.COLLECTION_SPECIFIC)) {
+	    show_file_size_checkbox.setSelected(true);
+	}
+	Dictionary.registerBoth(show_file_size_checkbox, "Preferences.General.Show_File_Size", "Preferences.General.Show_File_Size_Tooltip");
+
+	// Language
+	JPanel language_pane = new JPanel();
+	JLabel language_label = new JLabel();
+	language_label.setPreferredSize(LABEL_SIZE);
+	Dictionary.registerText(language_label, "Preferences.General.Interface_Language");
+	language_combobox = new JComboBox(dictionary_model.toArray());
+	Dictionary.registerTooltip(language_combobox, "Preferences.General.Interface_Language_Tooltip");
+	// Try to locate and select the current language
+	String language_code = Configuration.getLanguage();
+	for (int b = 0; b < language_combobox.getItemCount(); b++) {
+	    DictionaryEntry entry = (DictionaryEntry) language_combobox.getItemAt(b);
+	    if (language_code.equalsIgnoreCase(entry.getLocale().getLanguage())) {
+		language_combobox.setSelectedIndex(b);
+		break;
+	    }
+	}
+
+	// Layout
+	email_pane.setLayout(new BorderLayout());
+	email_pane.add(email_label, BorderLayout.WEST);
+	email_pane.add(email_field, BorderLayout.CENTER);
+
+	language_pane.setLayout(new BorderLayout());
+	language_pane.add(language_label, BorderLayout.WEST);
+	language_pane.add(language_combobox, BorderLayout.CENTER);
+
+	font_pane.setLayout(new BorderLayout());
+	font_pane.add(font_label, BorderLayout.WEST);
+	font_pane.add(font_field, BorderLayout.CENTER);
+
+	general_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	general_pane.setLayout(new GridLayout(5,1,0,5));
+	general_pane.add(email_pane);
+	general_pane.add(language_pane);
+	general_pane.add(font_pane);
+	general_pane.add(view_extracted_metadata_checkbox);
+	general_pane.add(show_file_size_checkbox);
+
+	return general_pane;
+    }
+
+    /** Generate the controls for altering the detail mode.
+     * @return a JPanel of controls
+     */
+    private JPanel createModePreferences() {
+	// Create Controls
+	JPanel mode_panel = new JPanel();
+	JPanel button_panel = new JPanel();
+	ButtonGroup mode_button_group = new ButtonGroup();
+	assistant_mode_radio_button = new JRadioButton(Dictionary.get("Preferences.Mode.Assistant"));
+	assistant_mode_radio_button.setOpaque(false);
+	mode_button_group.add(assistant_mode_radio_button);
+	expert_mode_radio_button = new JRadioButton(Dictionary.get("Preferences.Mode.Expert"));
+	expert_mode_radio_button.setOpaque(false);
+	mode_button_group.add(expert_mode_radio_button);
+	librarian_mode_radio_button = new JRadioButton(Dictionary.get("Preferences.Mode.Librarian"));
+	librarian_mode_radio_button.setOpaque(false);
+	mode_button_group.add(librarian_mode_radio_button);
+	systems_mode_radio_button = new JRadioButton(Dictionary.get("Preferences.Mode.Systems"));
+	systems_mode_radio_button.setOpaque(false);
+	mode_button_group.add(systems_mode_radio_button);
+	mode_description_textarea = new JTextArea();
+	mode_description_textarea.setEditable(false);
+	mode_description_textarea.setLineWrap(true);
+	mode_description_textarea.setWrapStyleWord(true);
+	// Determine which value is already selected
+	switch(Configuration.getMode()) {
+	case Configuration.ASSISTANT_MODE:
+	    assistant_mode_radio_button.setSelected(true);
+	    mode_description_textarea.setText(Dictionary.get("Preferences.Mode.Assistant_Description"));
+	    break;
+	case Configuration.SYSTEMS_MODE:
+	    systems_mode_radio_button.setSelected(true);
+	    mode_description_textarea.setText(Dictionary.get("Preferences.Mode.Systems_Description"));
+	    break;
+	case Configuration.EXPERT_MODE:
+	    expert_mode_radio_button.setSelected(true);
+	    mode_description_textarea.setText(Dictionary.get("Preferences.Mode.Expert_Description"));
+	    break;
+	default:
+	    librarian_mode_radio_button.setSelected(true);
+	    mode_description_textarea.setText(Dictionary.get("Preferences.Mode.Librarian_Description"));
+	}
+	// Connection - when a radio button is selected we have to change the description
+	ModeRadioButtonListener listener = new ModeRadioButtonListener();
+	assistant_mode_radio_button.addActionListener(listener);
+	expert_mode_radio_button.addActionListener(listener);
+	librarian_mode_radio_button.addActionListener(listener);
+	systems_mode_radio_button.addActionListener(listener);
+	listener = null;
+	// Layout
+	button_panel.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	button_panel.setLayout(new GridLayout(4,1,2,2));
+	button_panel.add(assistant_mode_radio_button);
+	button_panel.add(librarian_mode_radio_button);
+	button_panel.add(systems_mode_radio_button);
+	button_panel.add(expert_mode_radio_button);
+
+	mode_panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	mode_panel.setLayout(new BorderLayout());
+	mode_panel.add(button_panel, BorderLayout.NORTH);
+	mode_panel.add(new JScrollPane(mode_description_textarea), BorderLayout.CENTER);
+
+	return mode_panel;
+    }
+
+
+    /** The warning preferences are controlled through a checklist. */
+    private JPanel createWarningPreferences()
+    {
+	warning_preferences_check_list = new CheckList(false);
+
+	// Read all the warnings from the general xml/config.xml file, and their values from the user config.xml file
+	Document general_config_xml_file_document = XMLTools.parseXMLFile("xml/config.xml", true);
+	NodeList argument_elements_nodelist = general_config_xml_file_document.getDocumentElement().getElementsByTagName("Argument");
+	for (int i = 0; i < argument_elements_nodelist.getLength(); i++) {
+	    Element argument_element = (Element) argument_elements_nodelist.item(i);
+	    String argument_element_name = argument_element.getAttribute("name");
+	    if (argument_element_name.startsWith("warning.")) {
+		String warning_title = Dictionary.get(argument_element_name.substring("warning.".length()) + ".Title");
+		boolean warning_enabled = Configuration.get(argument_element_name, true);
+		CheckListEntry warning_entry = new CheckListEntry(warning_title, warning_enabled);
+		warning_entry.setProperty(argument_element_name);
+		warning_preferences_check_list.addEntry(warning_entry);
+	    }
+	}
+
+	JPanel warning_preferences_pane = new JPanel();
+	warning_preferences_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	warning_preferences_pane.setLayout(new BorderLayout());
+	warning_preferences_pane.add(new JScrollPane(warning_preferences_check_list), BorderLayout.CENTER);
+	return warning_preferences_pane;
+    }
+
+
+    private JPanel createWorkflowPreferences() {
+	// Read in the predefined configurations file
+	Vector predefined = new Vector();
+	Document predefined_document = XMLTools.parseXMLFile("xml/workflows.xml", true);
+	Element predefined_element = predefined_document.getDocumentElement();
+	NodeList workflow_elements = predefined_element.getElementsByTagName("Workflow");
+	for(int i = 0; i < workflow_elements.getLength(); i++) {
+	    predefined.add(new WorkflowElementWrapper((Element)workflow_elements.item(i)));
+	}
+
+	// Creation
+	JPanel workflow_preferences_pane = new JPanel();
+	JPanel checklist_pane = new JPanel();
+	JLabel title_label = new JLabel();
+	title_label.setPreferredSize(ROW_SIZE);
+	Dictionary.registerText(title_label, "Preferences.Workflow.Title");
+
+	workflow_download = new JCheckBox();
+	workflow_download.setSelected(Configuration.get("workflow.download", false));
+	workflow_download.setPreferredSize(ROW_SIZE);
+	Dictionary.registerText(workflow_download, "Preferences.Workflow.Download");
+
+	workflow_gather = new JCheckBox();
+	workflow_gather.setSelected(Configuration.get("workflow.gather", false));
+	workflow_gather.setPreferredSize(ROW_SIZE);
+	Dictionary.registerText(workflow_gather, "Preferences.Workflow.Gather");
+
+	workflow_enrich = new JCheckBox();
+	workflow_enrich.setSelected(Configuration.get("workflow.enrich", false));
+	workflow_enrich.setPreferredSize(ROW_SIZE);
+	Dictionary.registerText(workflow_enrich, "Preferences.Workflow.Enrich");
+
+	workflow_design = new JCheckBox();
+	workflow_design.setSelected(Configuration.get("workflow.design", false));
+	workflow_design.setPreferredSize(ROW_SIZE);
+	Dictionary.registerText(workflow_design, "Preferences.Workflow.Design");
+
+	workflow_create = new JCheckBox();
+	workflow_create.setSelected(Configuration.get("workflow.create", false));
+	workflow_create.setPreferredSize(ROW_SIZE);
+	Dictionary.registerText(workflow_create, "Preferences.Workflow.Create");
+
+	JPanel predefined_pane = new JPanel();
+	JLabel predefined_label = new JLabel();
+	Dictionary.registerText(predefined_label, "Preferences.Workflow.Predefined.Label");
+	JComboBox predefined_combobox = new JComboBox(predefined);
+
+	// Connection
+	predefined_combobox.addActionListener(new PredefinedActionListener());
+
+	// Layout
+	checklist_pane.setLayout(new BoxLayout(checklist_pane, BoxLayout.Y_AXIS));
+	checklist_pane.add(title_label);
+	if (Configuration.get("workflow.download", true)) {
+	    checklist_pane.add(workflow_download);
+	}
+	if (Configuration.get("workflow.gather", true)) {
+	    checklist_pane.add(workflow_gather);
+	}
+	if (Configuration.get("workflow.enrich", true)) {
+	    checklist_pane.add(workflow_enrich);
+	}
+	if (Configuration.get("workflow.design", true)) {
+	    checklist_pane.add(workflow_design);
+	}
+	if (Configuration.get("workflow.create", true)) {
+	    checklist_pane.add(workflow_create);
+	}
+
+	predefined_pane.setLayout(new BorderLayout(5,0));
+	predefined_pane.add(predefined_label, BorderLayout.WEST);
+	predefined_pane.add(predefined_combobox, BorderLayout.CENTER);
+
+	workflow_preferences_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	workflow_preferences_pane.setLayout(new BorderLayout());
+	workflow_preferences_pane.add(checklist_pane, BorderLayout.CENTER);
+	workflow_preferences_pane.add(predefined_pane, BorderLayout.SOUTH);
+
+	return workflow_preferences_pane;
+    }
+
+
+    private class OKButtonListener
+	implements ActionListener {
+	private boolean close;
+	public OKButtonListener(boolean close) {
+	    this.close = close;
+	}
+	public void actionPerformed(ActionEvent event)
+	{
+	    // Connection preferences
+	    String program_str = program_field.getText();
+	    if (program_str.length() > 0 && program_str.indexOf("%1") == -1) {
+		program_str = program_str + " %1";
+	    }
+	    Configuration.setPreviewCommand(program_str);
+
+	    String library_url_string = library_path_field.getText();
+	    if (library_url_string.equals("")) {
+		Configuration.library_url = null;
+	    }
+	    else {
+		try {
+		    Configuration.library_url = new URL(library_url_string);
+		}
+		catch (MalformedURLException exception) {
+		    DebugStream.printStackTrace(exception);
+		}
+	    }
+	    Configuration.setString("general.library_url", true, library_url_string);
+
+	    boolean site_changed = false;
+	    if (Gatherer.GS3) {
+		String current_site = Configuration.site_name;
+		String new_site =(String)site_combobox.getSelectedItem() ;
+		if (!new_site.equals(current_site)) {
+		    site_changed = true;
+		}
+		Configuration.setSiteAndServlet(new_site, (String)servlet_combobox.getSelectedItem());
+	    }
+
+	    Configuration.set("general.use_proxy", true, use_proxy_checkbox.isSelected());
+	    Configuration.setString("general.proxy_host", true, proxy_host_field.getText());
+	    Configuration.setString("general.proxy_port", true, proxy_port_field.getValue() + "");
+	    Gatherer.setProxy();
+
+	    // General preferences
+	    Configuration.setEmail(email_field.getText());
+	    Configuration.set("general.show_file_size", Configuration.COLLECTION_SPECIFIC, show_file_size_checkbox.isSelected());
+	    Configuration.set("general.view_extracted_metadata", Configuration.COLLECTION_SPECIFIC, view_extracted_metadata_checkbox.isSelected());
+
+	    // Two options requiring restarting the GLI to apply: interface font, and interface language
+	    boolean restart_required = false;
+
+	    // GLI interface font
+	    String current_font = Configuration.getString("general.font", true);
+	    if (!current_font.equals(font_field.getText())) {
+		Configuration.setString("general.font", true, font_field.getText());
+		restart_required = true;
+	    }
+
+	    // GLI interface language
+	    String current_lang = Configuration.getLanguage();
+	    if (!current_lang.equals(((DictionaryEntry) language_combobox.getSelectedItem()).getLocale().getLanguage())) {
+		Configuration.setLocale("general.locale", Configuration.GENERAL_SETTING, ((DictionaryEntry) language_combobox.getSelectedItem()).getLocale());
+		restart_required = true;
+
+		// Delete the plugins.dat and classifiers.dat files
+		PluginManager.clearPluginCache();
+		ClassifierManager.clearClassifierCache();
+	    }
+
+	    // Inform the user that a restart is required, if necessary
+	    if (restart_required) {
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Preferences.General.Restart_Required"), Dictionary.get("General.Warning"), JOptionPane.WARNING_MESSAGE);
+	    }
+
+	    // Mode preferences
+	    int current_mode = Configuration.getMode();
+	    int new_mode;
+	    if (assistant_mode_radio_button.isSelected()) {
+		new_mode = Configuration.ASSISTANT_MODE;
+	    }
+	    else if (systems_mode_radio_button.isSelected()) {
+		new_mode = Configuration.SYSTEMS_MODE;
+	    }
+	    else if (expert_mode_radio_button.isSelected()) {
+		new_mode = Configuration.EXPERT_MODE;
+	    }
+	    else {
+		new_mode = Configuration.LIBRARIAN_MODE;
+	    }
+
+	    // If there has been a change in modes, update the config, and also inform the persistant gui views that have a need to know
+	    if (new_mode != current_mode) {
+		Configuration.setMode(new_mode);
+		Collection collection = Gatherer.c_man.getCollection();
+		if (collection != null) {
+		    collection.cdm.modeChanged(new_mode);
+		}
+		Gatherer.g_man.modeChanged(new_mode);
+	    }
+
+	    // Warning preferences
+	    ListModel warning_preferences_check_list_model = warning_preferences_check_list.getModel();
+	    for (int i = 0; i < warning_preferences_check_list_model.getSize(); i++) {
+		CheckListEntry entry = (CheckListEntry) warning_preferences_check_list_model.getElementAt(i);
+		Configuration.set(entry.getProperty(), true, entry.isSelected());
+	    }
+
+	    if (Gatherer.GS3 && site_changed && Gatherer.c_man.getCollection() != null) {
+		// shut down the collection
+		System.err.println("shutting down teh collection");
+		Gatherer.g_man.saveThenCloseCurrentCollection();
+	    }
+
+	    // Workflow preferences
+	    Configuration.set("workflow.download", false, workflow_download.isSelected());
+	    Configuration.set("workflow.gather", false, workflow_gather.isSelected());
+	    Configuration.set("workflow.enrich", false, workflow_enrich.isSelected());
+	    Configuration.set("workflow.design", false, workflow_design.isSelected());
+	    Configuration.set("workflow.create", false, workflow_create.isSelected());
+	    Gatherer.g_man.workflowUpdate("Download", workflow_download.isSelected());
+	    Gatherer.g_man.workflowUpdate("Gather", workflow_gather.isSelected());
+	    Gatherer.g_man.workflowUpdate("Enrich", workflow_enrich.isSelected());
+	    Gatherer.g_man.workflowUpdate("Design", (workflow_design.isSelected() && Configuration.getMode() > Configuration.ASSISTANT_MODE));
+	    Gatherer.g_man.workflowUpdate("Create", workflow_create.isSelected());
+
+	    // Always save configuration changes immediately (in case the GLI crashes)
+	    Configuration.save();
+
+	    // Refresh the GLI to account for the configuration changes
+	    Gatherer.refresh(Gatherer.PREFERENCES_CHANGED);
+
+	    // Hide dialog
+	    if (close) {
+		self.dispose();
+	    }
+	}
+    }
+
+    private class CancelButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    self.dispose();
+	}
+    }
+
+    private class DictionaryEntry
+	implements Comparable {
+	private Locale locale;
+	private String description;
+	public DictionaryEntry(Locale locale) {
+	    this.description = null;
+	    this.locale = locale;
+	}
+	public DictionaryEntry(String description, Locale locale) {
+	    this.description = description;
+	    this.locale = locale;
+	}
+	public int compareTo(Object object) {
+	    return toString().compareTo(object.toString());
+	}
+	public boolean equals(Object object) {
+	    return toString().equals(object.toString());
+	}
+	public Locale getLocale() {
+	    return locale;
+	}
+	public String toString() {
+	    if(description != null) {
+		return description;
+	    }
+	    else {
+		return locale.getDisplayName();
+	    }
+	}
+    }
+
+    /** This listener updates the mode description depending on what mode is selected. */
+    private class ModeRadioButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    Object source = event.getSource();
+	    if(source == assistant_mode_radio_button) {
+		mode_description_textarea.setText(Dictionary.get("Preferences.Mode.Assistant_Description"));
+	    }
+	    else if(source == expert_mode_radio_button) {
+		mode_description_textarea.setText(Dictionary.get("Preferences.Mode.Expert_Description"));
+	    }
+	    else if(source == systems_mode_radio_button) {
+		mode_description_textarea.setText(Dictionary.get("Preferences.Mode.Systems_Description"));
+	    }
+	    else {
+		mode_description_textarea.setText(Dictionary.get("Preferences.Mode.Librarian_Description"));
+	    }
+	    source = null;
+	}
+    }
+
+    private class PredefinedActionListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    JComboBox cb = (JComboBox) event.getSource();
+	    WorkflowElementWrapper element = (WorkflowElementWrapper) cb.getSelectedItem();
+	    CheckboxUpdater task = new CheckboxUpdater(element);
+	    SwingUtilities.invokeLater(task);
+	}
+
+	private class CheckboxUpdater
+	    implements Runnable {
+	    private WorkflowElementWrapper element;
+	    public CheckboxUpdater(WorkflowElementWrapper element) {
+		this.element = element;
+	    }
+	    public void run() {
+		workflow_download.setSelected(element.getEnabled("download"));
+		workflow_gather.setSelected(element.getEnabled("gather"));
+		workflow_enrich.setSelected(element.getEnabled("enrich"));
+		workflow_design.setSelected(element.getEnabled("design"));
+		workflow_create.setSelected(element.getEnabled("create"));
+	    }
+	}
+    }
+
+
+    private class SiteComboboxListener
+	implements ActionListener {
+	private boolean ignore_event=false;
+	public void actionPerformed(ActionEvent event) {
+	    System.err.println("event occurred "+event.paramString());
+	    String site = (String) site_combobox.getSelectedItem();
+	    System.err.println("new site = "+site);
+	    if (!site.equals(current_site_selection)) {
+		current_site_selection = site;
+		System.err.println("changed the current selection");
+		ArrayList servlet_options = Gatherer.servlet_config.getServletsForSite(current_site_selection);
+		if (servlet_options == null) {
+		    System.err.println("no servlets for this site");
+		    servlet_combobox.setModel(new DefaultComboBoxModel());
+		    Dictionary.registerTooltip(servlet_combobox, "Preferences.Connection.Servlet_Tooltip2");
+		    servlet_combobox.setEnabled(false);
+
+		} else {
+		    System.err.println(ArrayTools.objectArrayToString(servlet_options.toArray()));
+		    servlet_combobox.setModel(new DefaultComboBoxModel(servlet_options.toArray()));
+		    Dictionary.registerTooltip(servlet_combobox, "Preferences.Connection.Servlet_Tooltip");
+		    servlet_combobox.setEnabled(true);
+		}
+	    }
+	}    
+    }
+
+    private class UseProxyListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    boolean enabled = use_proxy_checkbox.isSelected();
+	    Configuration.set("general.use_proxy", true, enabled);
+	    // Fortunately this is already driven by the event thread.
+	    proxy_host_field.setEnabled(enabled);
+	    proxy_port_field.setEnabled(enabled);
+	}
+    }
+
+    private class WorkflowElementWrapper {
+	private Element element;
+	private String text;
+	public WorkflowElementWrapper(Element element) {
+	    this.element = element;
+	}
+	public boolean getEnabled(String name) {
+	    boolean result = true;
+	    if(element.getAttribute(name).equalsIgnoreCase("false")) {
+		result = false;
+	    }
+	    return result;
+	}
+	public String toString() {
+	    if (text == null) {
+		text = Dictionary.get(element.getFirstChild().getNodeValue());
+	    }
+	    return text;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/PreviewCommandDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/PreviewCommandDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/PreviewCommandDialog.java	(revision 10506)
@@ -0,0 +1,267 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.File;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.filechooser.*;
+import javax.swing.table.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.util.Utility;
+
+/** This dialog allows the user to choose which browser to use for the preview command 
+ * @author Katherine Don, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class PreviewCommandDialog
+    extends ModalDialog {
+
+    /** The default size for the dialog. */
+    static final private Dimension SIZE = new Dimension(500, 195);
+
+    private PreviewCommandDialog self;
+    private JButton browse_button;
+    private JButton cancel_button;
+    private JButton ok_button;
+    private JTextField command_field;
+    private String preview_command=null;
+    /** Create a new PreviewCommandDialog
+     */
+    public PreviewCommandDialog() {
+	super(Gatherer.g_man);
+	this.self = this;
+		  
+	// Creation
+	setModal(true);
+	setSize(SIZE);
+	setJMenuBar(new SimpleMenuBar("thepreviewview"));
+
+	JPanel content_pane = (JPanel) getContentPane();
+	content_pane.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
+
+	JTextArea instructions_area = new JTextArea();
+	instructions_area.setEditable(false);
+	instructions_area.setLineWrap(true);
+	instructions_area.setRows(5);
+	instructions_area.setWrapStyleWord(true);
+	Dictionary.setText(instructions_area, "PreviewCommandDialog.Instructions");
+
+	JPanel button_pane = new JPanel();
+	JPanel lower_pane = new JPanel();
+
+	JPanel command_pane = new JPanel();
+	command_field = new JTextField();
+	browse_button = new GLIButton();
+	browse_button.setEnabled(!Utility.isMac());
+	browse_button.setMnemonic(KeyEvent.VK_B);
+
+	ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_O);
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+
+	// Connection
+	browse_button.addActionListener(new BrowseButtonListener());
+	ok_button.addActionListener(new OkButtonListener());
+	cancel_button.addActionListener(new CancelButtonListener());
+	if(Utility.isMac()) {
+	    Dictionary.setBoth(browse_button, "FileAssociationDialog.Browse", "FileAssociationDialog.Browse_Tooltip_Mac");
+	}
+	else {
+	    Dictionary.setBoth(browse_button, "FileAssociationDialog.Browse", "FileAssociationDialog.Browse_Tooltip");
+	}
+
+	Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+	Dictionary.setBoth(ok_button, "General.OK", "FileAssociationDialog.Close_Tooltip");	
+	Dictionary.setText(this, "PreviewCommandDialog.Title");
+
+	// Layout
+	command_pane.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
+	command_pane.setLayout(new BorderLayout());
+	command_pane.add(command_field, BorderLayout.CENTER);
+	command_pane.add(browse_button, BorderLayout.EAST);
+
+	lower_pane.setBorder(BorderFactory.createEmptyBorder(2,0,0,0));
+
+	button_pane.setLayout(new GridLayout(1,2,5,0));
+	button_pane.add(ok_button);
+	button_pane.add(cancel_button);
+
+	lower_pane.setBorder(BorderFactory.createEmptyBorder(2,0,0,0));
+	lower_pane.setLayout(new BorderLayout());
+	lower_pane.add(command_pane, BorderLayout.CENTER);
+	lower_pane.add(button_pane, BorderLayout.SOUTH);
+
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(new JScrollPane(instructions_area), BorderLayout.NORTH);
+	content_pane.add(lower_pane, BorderLayout.CENTER);
+
+	Rectangle screen = Gatherer.g_man.getBounds(null);
+	setLocation((int)(screen.getX() + (screen.getWidth() - SIZE.width) / 2), (int)(screen.getY() + (screen.getHeight() - SIZE.height) / 2));
+	screen = null;
+    }
+
+    public void destroy() {
+	// Disconnect
+	// Clean up
+	self = null;
+    }
+
+    /** Redisplay the dialog
+     */
+    public String display() {
+	setVisible(true);
+	return preview_command;
+    }
+
+
+    private class OkButtonListener
+	implements ActionListener {
+	
+	public void actionPerformed(ActionEvent event) {
+	    preview_command = command_field.getText();
+	    self.dispose();
+	    
+	}
+    }
+
+
+    /** Whenever the user clicks the browse button, we should open up a file browser to allow them to select an executable file from somewhere in the file system. */
+    private class BrowseButtonListener 
+	implements ActionListener {
+	/** Open up a simple JFileChooser when the user clicks the button. 
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    JFileChooser chooser = new JFileChooser(new File(Gatherer.getGLIUserDirectoryPath()));
+	    OpenCollectionDialog.disableRename(chooser);
+	    chooser.setDialogTitle(Dictionary.get("FileAssociationDialog.Browse_Title"));
+	    chooser.setFileFilter(new BatchFileFilter());
+	    chooser.setFileFilter(new CoreObjectModelFileFilter());
+	    chooser.setFileFilter(new ExecutableFileFilter());
+	    chooser.setAcceptAllFileFilterUsed(true);
+	    if(chooser.showOpenDialog(Gatherer.g_man) == JFileChooser.APPROVE_OPTION) {
+		command_field.setText(chooser.getSelectedFile().getAbsolutePath());
+	    }
+	}
+    }
+
+    
+    private class CancelButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    self.dispose();
+	}
+    }
+
+    /** Batch filter shows only files ending in bat. Based on ImageFilter.java which is a 1.4 example used by FileChooserDemo2.java. */
+    private class BatchFileFilter
+	extends FileFilter {
+
+	/** Accept all .exe files
+	 * @param file a File
+	 * @return true is this file should be shown, false otherwise
+	 */
+	public boolean accept(File file) {
+	    return file.getName().toLowerCase().endsWith(".bat");
+	}
+
+	/** The description of this filter
+	 * @return a String
+	 */
+	public String getDescription() {
+	    return Dictionary.get("FileAssociationDialog.Batch_File");
+	}
+    }
+
+    /** Command filter shows only files ending in com. Based on ImageFilter.java which is a 1.4 example used by FileChooserDemo2.java. */
+    private class CoreObjectModelFileFilter
+	extends FileFilter {
+
+	/** Accept all .com files
+	 * @param file a File
+	 * @return true is this file should be shown, false otherwise
+	 */
+	public boolean accept(File file) {
+	    return file.getName().toLowerCase().endsWith(".com");
+	}
+
+	/** The description of this filter
+	 * @return a String
+	 */
+	public String getDescription() {
+	    return Dictionary.get("FileAssociationDialog.Command_File");
+	}
+    }
+
+
+    /** Executable filter shows only files ending in exe. Based on ImageFilter.java which is a 1.4 example used by FileChooserDemo2.java. */
+    private class ExecutableFileFilter
+	extends FileFilter {
+
+	/** Accept all .exe files
+	 * @param file a File
+	 * @return true is this file should be shown, false otherwise
+	 */
+	public boolean accept(File file) {
+	    return file.getName().toLowerCase().endsWith(".exe");
+	}
+
+	/** The description of this filter
+	 * @return a String
+	 */
+	public String getDescription() {
+	    return Dictionary.get("FileAssociationDialog.Executable_File");
+	}
+    }
+
+
+}
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/SimpleMenuBar.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/SimpleMenuBar.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/SimpleMenuBar.java	(revision 10506)
@@ -0,0 +1,34 @@
+package org.greenstone.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.util.JarTools;
+
+public class SimpleMenuBar
+    extends JMenuBar
+    implements ActionListener {
+
+    private String page_name;
+
+    public SimpleMenuBar(String page_name) {
+	this.page_name = page_name;
+	JMenu help = new JMenu();
+	help.setIcon(JarTools.getImage("help.gif"));
+	Dictionary.setText(help, "Menu.Help");
+
+	JMenuItem help_help = new JMenuItem();
+	help_help.addActionListener(this);
+	Dictionary.setText(help_help, "Menu.Help");
+
+	help.add(help_help);
+
+	add(Box.createHorizontalGlue());
+	add(help);
+    }
+
+    public void actionPerformed(ActionEvent event) {
+	HelpFrame.setView(page_name);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/SimpleOpenCollectionDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/SimpleOpenCollectionDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/SimpleOpenCollectionDialog.java	(revision 10506)
@@ -0,0 +1,330 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+/** A dialog which provides a straight-forward access to the currently installed collections. It also will contain the ability to continue through to the original OpenCollectionDialog if your source collection is located somewhere other than the gsdl collect folder. */
+public class SimpleOpenCollectionDialog
+    extends ModalDialog {
+
+    static final public int OK_OPTION = 0;
+    static final public int CANCEL_OPTION = 1;
+    static final public int BROWSE_OPTION = 2;
+
+    static final private Dimension SIZE = new Dimension(640,480);
+    static final private String BLANK = "b";
+    static final private String DESCRIPTION = "d";
+
+    private CardLayout card_layout;
+    private int result;
+    private JButton advanced_button;
+    private JButton cancel_button;
+    private JButton open_button;
+    private JList collection_list;
+    private JTextArea description_textarea;
+    private JPanel description_pane;
+    private String filename;
+
+    public SimpleOpenCollectionDialog() {
+	super(Gatherer.g_man, "", true);
+	setSize(SIZE);
+	Dictionary.setText(this, "OpenCollectionDialog.Title");
+
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+
+	JPanel center_pane = new JPanel();
+
+	JPanel collection_list_pane = new JPanel();
+	JLabel collection_list_label = new JLabel();
+	Dictionary.setText(collection_list_label, "OpenCollectionDialog.Available_Collections");
+	collection_list = new JList(new CollectionListModel());
+	description_pane = new JPanel();
+	card_layout = new CardLayout();
+
+	JPanel blank_pane = new JPanel();
+
+	JPanel description_textarea_pane = new JPanel();
+	JLabel description_textarea_label = new JLabel();
+	Dictionary.setText(description_textarea_label, "OpenCollectionDialog.Description");
+	description_textarea = new JTextArea();
+
+	JPanel button_pane = new JPanel();
+	open_button = new GLIButton();
+	open_button.setEnabled(false);
+	open_button.setMnemonic(KeyEvent.VK_O);
+	Dictionary.setBoth(open_button, "OpenCollectionDialog.Open", "OpenCollectionDialog.Open_Tooltip");
+	advanced_button = new GLIButton();
+	advanced_button.setMnemonic(KeyEvent.VK_B);
+	Dictionary.setBoth(advanced_button, "OpenCollectionDialog.Browse", "OpenCollectionDialog.Browse_Tooltip");
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+
+	// Connection
+	advanced_button.addActionListener(new AdvancedListener());
+	cancel_button.addActionListener(new CancelListener());
+	open_button.addActionListener(new OpenListener());
+	CollectionListSelectionListener clsl = new CollectionListSelectionListener();
+	collection_list.addListSelectionListener(clsl);
+	collection_list.addMouseListener(clsl);
+	clsl = null;
+
+	// Layout
+	collection_list_pane.setLayout(new BorderLayout());
+	collection_list_pane.add(collection_list_label, BorderLayout.NORTH);
+	collection_list_pane.add(new JScrollPane(collection_list), BorderLayout.CENTER);
+
+	description_textarea_pane.setLayout(new BorderLayout());
+	description_textarea_pane.add(description_textarea_label, BorderLayout.NORTH);
+	description_textarea_pane.add(new JScrollPane(description_textarea), BorderLayout.CENTER);
+
+	description_pane.setLayout(card_layout);
+	description_pane.add(description_textarea_pane, DESCRIPTION);
+	description_pane.add(blank_pane, BLANK);
+
+	center_pane.setLayout(new GridLayout(2,1,0,5));
+	center_pane.add(collection_list_pane);
+	center_pane.add(description_pane);
+
+	button_pane.setLayout(new GridLayout(1,4));
+	button_pane.add(new JPanel());
+	button_pane.add(open_button);
+	if (!Gatherer.GS3) { // Temporarily disable Browse for GS3
+	    button_pane.add(advanced_button);
+	}
+	button_pane.add(cancel_button);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(center_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	screen_size = null;
+    }
+
+    public void destroy() {
+    }
+
+    public int display() {
+	setVisible(true);
+	return result;
+    }
+
+    public String getFileName() {
+	return this.filename;
+    }
+    private class AdvancedListener
+	implements ActionListener {
+
+	public void actionPerformed(ActionEvent event) {
+	    result = BROWSE_OPTION;
+	    SimpleOpenCollectionDialog.this.dispose();
+	}
+    }
+
+    private class CancelListener
+	implements ActionListener {
+
+	public void actionPerformed(ActionEvent event) {
+	    result = CANCEL_OPTION;
+	    SimpleOpenCollectionDialog.this.dispose();
+	}
+    }
+
+    private class CollectionListSelectionListener
+	extends MouseAdapter
+	implements ListSelectionListener {
+
+	public void mouseClicked(MouseEvent event) {
+	    ///ystem.err.println("Mouse clicked");
+	    if(event.getClickCount() >= 2) {
+		Point location = event.getPoint();
+		int index = collection_list.locationToIndex(location);
+		collection_list.setSelectedIndex(index);
+		location = null;
+		open_button.doClick();
+	    }
+	}
+
+	public void valueChanged(ListSelectionEvent event) {
+	    if(collection_list.isSelectionEmpty()) {
+		card_layout.show(description_pane, BLANK);
+		open_button.setEnabled(false);
+	    }
+	    else {
+		BasicCollectionConfiguration collection_configuration = (BasicCollectionConfiguration) collection_list.getSelectedValue();
+		description_textarea.setText(collection_configuration.getDescription());
+		description_textarea.setCaretPosition(0);
+		card_layout.show(description_pane, DESCRIPTION);
+		open_button.setEnabled(true);
+	    }
+	}
+    }
+
+    // use this if we ever go back to viewing all colls at once
+    /*    private class GS3CollectionListModel
+	extends AbstractListModel {
+
+	private TreeSet data;
+
+	public GS3CollectionListModel() {
+	    data = new TreeSet();
+	    File sites_folder = new File(Utility.getSitesDir(Configuration.gsdl3_path));
+	    File sites[] = sites_folder.listFiles();
+	    for (int s=0; s<sites.length; s++) {
+		String site_name = sites[s].getName();
+		System.err.println("found site "+site_name);
+		File collect_folder = new File(Utility.getCollectDir(Configuration.gsdl3_path, site_name) );
+		if (!collect_folder.exists()) {
+		    continue;
+		}
+		File[] collection_folders = collect_folder.listFiles();
+		for(int i = 0; i < collection_folders.length; i++) {
+		    File collection_folder = collection_folders[i];
+		    String collection_foldername = collection_folder.getName();
+		    if(!collection_folder.isFile() && !collection_foldername.equals(StaticStrings.MODEL_COLLECTION_NAME)) {
+			BasicCollectionConfiguration collection_configuration = new BasicCollectionConfiguration(new File(collection_folder, Utility.CONFIG_FILE), site_name);
+			if(!collection_configuration.getName().equals(StaticStrings.ERROR_STR)) {
+			    data.add(collection_configuration);
+			}
+		    }
+		    collection_foldername = null;
+		    collection_folder = null;
+		} // for each collection
+		collection_folders = null;
+		collect_folder = null;
+	    } // for each site
+	    sites_folder = null;
+	    sites = null;
+	}
+
+	public Object getElementAt(int index) {
+	    Iterator iterator = data.iterator();
+	    for(int i = 0; iterator.hasNext(); i++) {
+		Object object = iterator.next();
+		if(i == index) {
+		    iterator = null;
+		    return object;
+		}
+		object = null;
+	    }
+	    iterator = null;
+	    return null;
+	}
+
+	public int getSize() {
+	    return data.size();
+	}
+    }
+    */	
+    private class CollectionListModel
+	extends AbstractListModel {
+
+	private TreeSet data;
+
+	public CollectionListModel() {
+	    data = new TreeSet();
+	    File collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	    if (!collect_directory.exists()) {
+		collect_directory = null;
+		return;
+	    }
+	    File[] collection_folders = collect_directory.listFiles();
+	    for(int i = 0; i < collection_folders.length; i++) {
+		File collection_folder = collection_folders[i];
+		String collection_foldername = collection_folder.getName();
+		if(collection_folder.isDirectory() && !collection_foldername.equals(StaticStrings.MODEL_COLLECTION_NAME)) {
+		    File config_file = new File(collection_folder, Utility.CONFIG_FILE);
+		    if (config_file.exists()) {
+			BasicCollectionConfiguration collection_configuration = new BasicCollectionConfiguration(config_file);
+			data.add(collection_configuration);
+		    }
+		    config_file = null;
+		}
+		collection_foldername = null;
+		collection_folder = null;
+	    }
+	    collection_folders = null;
+	    collect_directory = null;
+	}
+
+	public Object getElementAt(int index) {
+	    Iterator iterator = data.iterator();
+	    for(int i = 0; iterator.hasNext(); i++) {
+		Object object = iterator.next();
+		if(i == index) {
+		    iterator = null;
+		    return object;
+		}
+		object = null;
+	    }
+	    iterator = null;
+	    return null;
+	}
+
+	public int getSize() {
+	    return data.size();
+	}
+    }
+
+    private class OpenListener
+	implements ActionListener {
+
+	public void actionPerformed(ActionEvent event) {
+	    result = OK_OPTION;
+	    Object selected_object = collection_list.getSelectedValue();
+	    if (selected_object instanceof BasicCollectionConfiguration) {
+		BasicCollectionConfiguration collection_configuration = (BasicCollectionConfiguration)selected_object; //(BasicCollectionConfiguration) collection_list.getSelectedValue();
+		//*************888
+		File collect_cfg_file = collection_configuration.getFile(); // returns the collect.cfg file
+		File etc_folder = collect_cfg_file.getParentFile();
+		File collection_folder = etc_folder.getParentFile();
+		filename = collection_folder.getAbsolutePath() + File.separator + collection_folder.getName() + Utility.GLI_EXTENSION;
+		collection_folder = null;
+		etc_folder = null;
+		collect_cfg_file = null;
+		collection_configuration = null;
+		SimpleOpenCollectionDialog.this.dispose();
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/SimpleResultDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/SimpleResultDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/SimpleResultDialog.java	(revision 10506)
@@ -0,0 +1,104 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.event.*;
+
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.Dictionary;
+
+public class SimpleResultDialog
+    extends ModalDialog {
+    
+    private Dimension size = new Dimension(600,300);
+    private SimpleResultDialog self;
+    
+    public SimpleResultDialog(String title, String label, String results) {
+	super(Gatherer.g_man, title, true);
+	this.self = this;
+	
+	setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+	setSize(size);
+	
+	JPanel content_pane = (JPanel) getContentPane();
+	JLabel result_label = new JLabel(label);
+	
+	JPanel button_pane = new JPanel();
+	JButton close_button = new GLIButton(Dictionary.get("General.Close"));
+	close_button.addActionListener(new CloseButtonListener());
+	
+	JPanel output_pane = new JPanel();
+	JLabel output_label = new JLabel();
+	Dictionary.registerText(output_label, "General.Review_Output");
+	
+	JTextArea output_textarea = new JTextArea(results);
+	output_textarea.setCaretPosition(0);
+	output_textarea.setEditable(false);
+	output_textarea.setLineWrap(true);
+	output_textarea.setWrapStyleWord(true);
+	
+	button_pane.setLayout(new BorderLayout());
+	button_pane.add(close_button, BorderLayout.EAST);
+	
+	output_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
+	output_pane.setLayout(new BorderLayout());
+	output_pane.add(output_label, BorderLayout.NORTH);
+	output_pane.add(new JScrollPane(output_textarea), BorderLayout.CENTER);
+	
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(result_label, BorderLayout.NORTH);
+	content_pane.add(output_pane, BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+	
+	// Position
+	Rectangle frame_bounds = Gatherer.g_man.getBounds();
+	setLocation(frame_bounds.x + (frame_bounds.width - size.width) / 2, frame_bounds.y + (frame_bounds.height - size.height) / 2);
+    }
+    
+    private class CloseButtonListener
+	implements ActionListener {
+	public void actionPerformed(ActionEvent event) {
+	    self.setVisible(false);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/URLField.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/URLField.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/URLField.java	(revision 10506)
@@ -0,0 +1,93 @@
+package org.greenstone.gatherer.gui;
+
+import java.awt.*;
+import java.util.regex.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import org.greenstone.gatherer.DebugStream;
+
+
+public class URLField
+    extends JTextField 
+    implements DocumentListener {
+
+    static final public Pattern URL_PATTERN = Pattern.compile("(h|ht|htt|http|http:|http:/|http://|http://)(([a-zA-Z]([a-zA-Z]|[0-9]|[\\$\\-_\\&\\+]|[!\\*\"\'\\(\\)]|(%[0-9A-Fa-f][0-9A-Fa-f]))*(\\.[a-zA-Z]([a-zA-Z]|[0-9]|[\\$\\-_\\&\\+]|[!\\*\"\'\\(\\)]|(%[0-9A-Fa-f][0-9A-Fa-f]))*)*)|(([0-9])+\\.([0-9])+\\.([0-9])+\\.([0-9])+))(:([0-9])+)?(/([a-zA-Z]|[0-9]|[\\$\\-_\\.\\&\\+]|[!\\*\"\'\\(\\),]|(%[0-9A-Fa-f][0-9A-Fa-f]))*)*");
+
+    // Crap RegEx that matches everything dammit
+    //static final public Pattern URL_PATTERN = Pattern.compile("((.*?)://)?(([^:]*):([^@]*)@)?(([^/:]*)(:[^/]*))?([^\\?#]*/?)?(\\?([^?#]*))?(#(.*))?");
+
+    // Crap RegEx that demands URL starts with www
+    //static final public Pattern URL_PATTERN = Pattern.compile("(h|ht|htt|http|http:|http:/|http://|http://)?[\\w]+(\\.[\\w]+)([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?");
+
+    private Color background;
+    private Color foreground;
+    private Color invalid_background;
+    private Color invalid_foreground;
+
+    public URLField(Color foreground, Color background, Color invalid_foreground, Color invalid_background) {
+	super();
+	this.background = background;
+	this.foreground = foreground;
+	this.invalid_background = invalid_background;
+	this.invalid_foreground = invalid_foreground;
+	setBackground(background);
+	setForeground(foreground);
+	//getDocument().addDocumentListener(this);
+    }
+
+    public URLField(String email, Color foreground, Color background, Color invalid_foreground, Color invalid_background) {
+	super(email);
+	this.background = background;
+	this.foreground = foreground;
+	this.invalid_background = invalid_background;
+	this.invalid_foreground = invalid_foreground;
+	setBackground(background);
+	//getDocument().addDocumentListener(this);
+    }
+
+    /** Gives notification that an attribute or set of attributes changed.
+     * @param e
+     */
+    public void changedUpdate(DocumentEvent e) {
+	validateURL();
+    }
+          
+    /** Gives notification that there was an insert into the document.
+     * @param e
+     */
+    public void insertUpdate(DocumentEvent e) {
+	validateURL();
+    }
+
+    public boolean isEmpty() {
+	return (this.getText().length() == 0);
+    }
+          
+    /** Gives notification that a portion of the document has been removed. 
+     * @param e
+     */
+    public void removeUpdate(DocumentEvent e) {
+	validateURL();
+    }
+
+    public boolean validateURL() {
+	boolean result;
+	String text = getText();
+	Matcher m = URL_PATTERN.matcher(text);
+	if(text.length() == 0 || m.matches()) {
+	    setBackground(background);
+	    setForeground(foreground);
+	    result = true;
+	}
+	else {
+	    setBackground(invalid_background);
+	    setForeground(invalid_foreground);
+	    result = false;
+	}
+	m = null;
+	DebugStream.println("Validating: " + text + " -> " + (result ? "GOOD" : "BAD"));
+	text = null;
+	return result;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/WarningDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/WarningDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/WarningDialog.java	(revision 10506)
@@ -0,0 +1,259 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, Greenstone Project, NZDL, University of Waikato
+ *
+ * Copyright (C) 2003 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.util.JarTools;
+
+
+/** A dialog that warns about something, and allows the user to turn off the warning in the future. */
+public class WarningDialog
+    extends ModalDialog 
+    implements ActionListener, KeyListener
+{
+    static final private Dimension NORMAL_SIZE = new Dimension(450, 160);
+    static final private Dimension SETTING_SIZE = new Dimension(450, 200);
+
+    private int result = JOptionPane.CANCEL_OPTION;
+    private JButton cancel_button;
+    private JButton ok_button;
+    private JCheckBox show_check;
+    private JTextField value_field;
+    private JPanel value_panel;
+    private String affected_property;
+    private String full_property;
+
+
+    public WarningDialog(String warning_name, String warning_title_key, String warning_message, String affected_property, boolean can_cancel)
+    {
+	super(Gatherer.g_man, "Warning", true);
+
+	// Determine the name of this prompt.
+	this.affected_property = affected_property;
+	this.full_property = warning_name;
+
+	// Now build dialog.
+	if (affected_property != null) {
+	    setSize(SETTING_SIZE);
+	}
+	else {
+	    setSize(NORMAL_SIZE);
+	}
+	Dictionary.setText(this, warning_title_key);
+
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+	JPanel text_pane = new JPanel();
+	JLabel icon_label = new JLabel(JarTools.getImage("gatherer_medium.gif"));
+
+	JTextArea text_area = new JTextArea();
+	text_area.setCaretPosition(0);
+	text_area.setEditable(false);
+	text_area.setLineWrap(true);
+	text_area.setText(warning_message);
+	text_area.setWrapStyleWord(true);
+
+	value_panel = new JPanel();
+	JLabel value_label = new JLabel();
+	Dictionary.setText(value_label, "WarningDialog.Value");
+
+	value_field = new JTextField();
+	JPanel bottom_pane = new JPanel();
+	show_check = new JCheckBox();
+	Dictionary.setText(show_check, "WarningDialog.Dont_Show_Again");
+	JPanel control_pane = new JPanel();
+	ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_O);
+	Dictionary.setBoth(ok_button, "General.OK", "General.OK_Tooltip");
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+
+	// Connection
+	ok_button.addActionListener(this);
+	cancel_button.addActionListener(this);
+	ok_button.addKeyListener(this);
+	cancel_button.addKeyListener(this);
+	getRootPane().setDefaultButton(ok_button);
+
+	// Layout
+	icon_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
+
+	value_label.setBorder(BorderFactory.createEmptyBorder(0, icon_label.getPreferredSize().width, 0, 0));
+
+	value_panel.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	value_panel.setLayout(new BorderLayout(5,0));
+	value_panel.add(value_label, BorderLayout.WEST);
+	value_panel.add(value_field, BorderLayout.CENTER);
+
+	text_pane.setLayout(new BorderLayout());
+	text_pane.add(icon_label, BorderLayout.WEST);
+	text_pane.add(new JScrollPane(text_area), BorderLayout.CENTER);
+	if(affected_property != null) {
+	    text_pane.add(value_panel, BorderLayout.SOUTH);
+	}
+
+	if(can_cancel) {
+	    control_pane.setLayout(new GridLayout(1,2,5,0));
+	    control_pane.add(ok_button);
+	    control_pane.add(cancel_button);
+	}
+	else {
+	    control_pane.setLayout(new BorderLayout());
+	    control_pane.add(ok_button, BorderLayout.EAST);
+	}
+
+	bottom_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	bottom_pane.setLayout(new BorderLayout());
+	bottom_pane.add(show_check, BorderLayout.CENTER);
+	bottom_pane.add(control_pane, BorderLayout.EAST);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(text_pane, BorderLayout.CENTER);
+	content_pane.add(bottom_pane, BorderLayout.SOUTH);
+
+	// Position
+	Dimension size = getSize();
+	if (Gatherer.g_man != null) {
+	    Rectangle frame_bounds = Gatherer.g_man.getBounds();
+	    setLocation(frame_bounds.x + (frame_bounds.width - size.width) / 2, frame_bounds.y + (frame_bounds.height - size.height) / 2);
+	}
+	else {
+	    Dimension screen_size = Toolkit.getDefaultToolkit().getScreenSize();
+	    setLocation((screen_size.width - size.width) / 2, (screen_size.height - size.height) / 2);
+	}
+    }
+
+    public void actionPerformed(ActionEvent event) {
+	boolean bad_value = false;
+	if(event.getSource() == ok_button) {
+	    if(affected_property != null && Configuration.self != null) {
+		String value = value_field.getText();
+		if(value.length() > 0) {
+		   if(value_field instanceof URLField) {
+		      bad_value = !((URLField)value_field).validateURL();
+		   }
+		   if(!bad_value) {
+		      // Store the value of the property
+		      Configuration.setString(affected_property, true, value_field.getText());
+		   }
+		}
+	    }
+	    if(!bad_value) {
+		result = JOptionPane.OK_OPTION;
+	    }
+	}
+	if(!bad_value) {
+	    if (Configuration.self != null) {
+		// Store the state of the show message checkbox.
+		Configuration.set(full_property, true, !show_check.isSelected());
+	    }
+	    // Done.
+	    setVisible(false);
+	}
+	else {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("WarningDialog.Invalid_Value"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	}
+    }
+
+    /** Gives notification of key events on the buttons */
+    public void keyPressed(KeyEvent e) {
+	if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+	    // Enter: Click the button in focus
+	    Object source = e.getSource();
+	    if (source instanceof AbstractButton) {
+		((AbstractButton) source).doClick();
+	    }
+	}
+    }
+
+    public void keyReleased(KeyEvent e) { }
+
+    public void keyTyped(KeyEvent e) { }
+
+
+    public int display() {
+	if (Configuration.self == null || Configuration.get(full_property, false)) {
+	    setVisible(true);
+	}
+	// We are no longer showing this dialog, so result must always be true.
+	else {
+	    result = JOptionPane.OK_OPTION;
+	}
+	// Ask the parent to repaint, just to be sure
+	if(Gatherer.g_man != null) {
+	    Gatherer.g_man.repaint();
+	}
+	return result;
+    }
+
+    /** Allows you to specify whether this dialog is a warning dialog, or only a message dialog.
+     * @param message_only true if this dialog shows a message, false for a warning
+     */
+    public void setMessageOnly(boolean message_only) {
+	// If this is a message then change the checkbox
+	if(message_only) {
+	    Dictionary.setText(show_check, "WarningDialog.Dont_Show_Again_Message");
+	}
+	// And if its a warning, change them back
+	else {
+	    Dictionary.setText(show_check, "WarningDialog.Dont_Show_Again");
+	}
+    }
+
+    /** Allows you to replace the generic text field control with a JTextField subclass with further functionality. For instance you might provide a URLField to allow only valid URLs to be accepted.
+     * @param  control the JTextField subclass you want to use for the control
+     */
+    public void setValueField(JTextField control) {
+	// Remove the current control
+	value_panel.remove(value_field);
+	// Replace with the new one
+	value_field = control;
+	// Re-add
+	value_panel.add(value_field, BorderLayout.CENTER);
+    }
+
+    protected void processWindowEvent(WindowEvent event) {
+	if(event.getID() == WindowEvent.WINDOW_ACTIVATED) {
+	    if(affected_property != null) {
+		value_field.requestFocus();
+	    }
+	    else {
+		ok_button.requestFocus();
+	    }
+	}
+	else {
+	    super.processWindowEvent(event);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/WriteCDImagePrompt.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/WriteCDImagePrompt.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/WriteCDImagePrompt.java	(revision 10506)
@@ -0,0 +1,528 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.event.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.LocalGreenstone;
+import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
+import org.greenstone.gatherer.shell.GShell;
+import org.greenstone.gatherer.shell.GShellEvent;
+import org.greenstone.gatherer.shell.GShellListener;
+import org.greenstone.gatherer.util.ArrayTools;
+import org.greenstone.gatherer.util.CheckList;
+import org.greenstone.gatherer.util.CheckListEntry;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+/** This class provides the functionality to write a CD-ROM/DVD image of current collections from the GSDLHOME/collect/ directory to CDROM. 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.
+    Copied from DeleteCollectionPrompt
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class WriteCDImagePrompt
+    extends ModalDialog 
+    implements GShellListener {
+    
+    private OKButtonListener ok_button_listener;
+    private ArrayList all_collections = null;
+    private ArrayList selected_collections = null;
+    /** The list of collections to include in exported cd-rom/dvd image */
+    private CheckList list = null;
+    /** The currently selected collection for deletion. */
+    private BasicCollectionConfiguration collection = null;
+    /** A reference to ourself so any inner-classes can dispose of us. */
+    private WriteCDImagePrompt prompt = null;
+    /** The close button, which exits the prompt without deleting anything. */
+    private JButton cancel_button = null;
+    /** The ok button which causes the selected collection to be deleted. */
+    private JButton ok_button = null;
+    /** The label above details. */
+    private JLabel details_label = null;
+    /** The label above the list. */
+    private JLabel list_label = null;
+    /** The text area used to display details about the collection selected. */
+    private JTextArea details_textarea = null;
+    /** The text area used to display instructions for the cd-rom/dvd export */
+    private JTextArea instructions_textarea;
+    /** A string array used to pass arguments to the phrase retrieval method. */
+    private JTextField title_field = null;
+    private JLabel title_label = null;
+    private String args[] = null;
+    private String cd_title = null;
+    /** whether the exporting was successful or not */
+    private boolean successful = false;
+    /** whether we are trying to export or not */
+    private boolean exporting = false;
+    /** the error message if any */
+    private StringBuffer error_message = null;
+    /** The size of the export prompt screen. */
+    public static final Dimension SIZE = new Dimension(500, 500);
+
+    /** Constructor.
+     * @see org.greenstone.gatherer.collection.WriteCDImagePrompt.CancelButtonListener
+     * @see org.greenstone.gatherer.collection.WriteCDImagePrompt.CollectionListListener
+     * @see org.greenstone.gatherer.collection.WriteCDImagePrompt.OKButtonListener
+     */
+    public WriteCDImagePrompt() {
+	super(Gatherer.g_man, true);
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Close", "General.Close_Tooltip");
+	details_textarea = new JTextArea();
+	details_textarea.setEditable(false);
+	Dictionary.setText(details_textarea, "DeleteCollectionPrompt.No_Collection");
+	details_label = new JLabel();
+	Dictionary.setText(details_label, "DeleteCollectionPrompt.Collection_Details");
+
+	instructions_textarea = new JTextArea();
+	instructions_textarea.setCaretPosition(0);
+	instructions_textarea.setEditable(false);
+	instructions_textarea.setLineWrap(true);
+	instructions_textarea.setRows(4);
+	instructions_textarea.setWrapStyleWord(true);
+	Dictionary.registerText(instructions_textarea, "WriteCDImagePrompt.Instructions");
+
+	all_collections = new ArrayList();
+	list = new CheckList(true);
+	list_label = new JLabel();
+	Dictionary.setText(list_label, "DeleteCollectionPrompt.Collection_List");
+	ok_button = new GLIButton();
+	ok_button.setMnemonic(KeyEvent.VK_D);
+	Dictionary.setBoth(ok_button, "WriteCDImagePrompt.Export", "WriteCDImagePrompt.Export_Tooltip");
+
+	title_field = new JTextField();
+	// Dictionary.setTooltip(title_field, "WriteCDImagePrompt.CD_Name_Tooltip");
+	title_label = new JLabel();
+	Dictionary.setText(title_label, "WriteCDImagePrompt.CD_Name");
+	scanForCollections();
+	list.setListData(all_collections);
+
+	prompt = this;
+	setSize(SIZE);
+	Dictionary.setText(this, "WriteCDImagePrompt.Title");
+
+	setJMenuBar(new SimpleMenuBar("0")); // need to find an appropriate help page to open at
+	cancel_button.addActionListener(new CancelButtonListener());
+	list.addListSelectionListener(new CollectionListListener());
+	list.clearSelection();
+	list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	ok_button_listener = new OKButtonListener();
+	ok_button.addActionListener(ok_button_listener);
+	ok_button.setEnabled(false);
+	//title.getDocument().addDocumentListener(new DocumentListener());
+    }
+
+    /** Destructor. */
+    public void destroy() {
+	all_collections.clear();
+	all_collections = null;
+	cancel_button = null;
+	details_textarea = null;
+	details_label = null;
+	list = null;
+	ok_button = null;
+	prompt = null;
+	if (selected_collections!=null) {
+	    selected_collections.clear();
+	    selected_collections = null;
+	}
+	title_field = null;
+	title_label = null;
+    }
+
+    /** This method causes the modal prompt to be displayed. 
+     * returns true if it has exported the collections that are currently selected */
+    public boolean display() {
+	// Top pane
+	JPanel instructions_pane = new JPanel(new BorderLayout());
+	instructions_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	instructions_pane.add(new JScrollPane(instructions_textarea), BorderLayout.CENTER);
+	
+	title_label.setBorder(BorderFactory.createEmptyBorder(0,5,0,15));
+
+	JPanel title_pane = new JPanel(new BorderLayout());
+	title_pane.add(title_label, BorderLayout.WEST);
+	title_pane.add(title_field, BorderLayout.CENTER);
+	instructions_pane.add(title_pane, BorderLayout.SOUTH);
+
+	// Central pane
+	JPanel list_pane = new JPanel(new BorderLayout());
+	list_pane.add(list_label, BorderLayout.NORTH);
+	list_pane.add(new JScrollPane(list), BorderLayout.CENTER);
+	list_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
+
+	JPanel details_pane = new JPanel(new BorderLayout());
+	details_pane.add(details_label, BorderLayout.NORTH);
+	details_pane.add(new JScrollPane(details_textarea), BorderLayout.CENTER);
+	details_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+
+	JPanel central_pane = new JPanel(new GridLayout(2, 1));
+	central_pane.add(list_pane);
+	central_pane.add(details_pane);
+	central_pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+	// Lower pane
+	JPanel button_pane = new JPanel(new GridLayout(1, 2));
+	button_pane.add(ok_button);
+	button_pane.add(cancel_button);
+	button_pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
+
+	JPanel lower_pane = new JPanel(new BorderLayout());
+	lower_pane.add(button_pane, BorderLayout.SOUTH);
+	lower_pane.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
+
+	// Final.
+	JPanel content_pane = (JPanel)this.getContentPane();
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(instructions_pane, BorderLayout.NORTH);
+	content_pane.add(central_pane, BorderLayout.CENTER);
+	content_pane.add(lower_pane, BorderLayout.SOUTH);
+
+	// Center and display.
+	Dimension screen_size = Configuration.screen_size;
+	this.setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	this.setVisible(true); // blocks until the dialog is killed
+	return true;
+	
+    }
+
+    
+    /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.collection.Collection
+     * @see org.greenstone.gatherer.gui.BuildOptions
+     * @see org.greenstone.gatherer.shell.GShell
+     * @see org.greenstone.gatherer.shell.GShellListener
+     * @see org.greenstone.gatherer.shell.GShellProgressMonitor
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    public void writeCDImageCollections()
+    {
+	DebugStream.println("WriteCDImagePrompt.writeCDImageCollections()");
+
+	int num_collections = selected_collections.size();
+	if (num_collections == 0) return;
+	cd_title = title_field.getText();
+	cd_title = cd_title.trim();
+	cd_title = cd_title.replaceAll("\"","");
+
+	// Generate the exportcol.pl command
+	ArrayList command_parts_list = new ArrayList();
+	if (Utility.isWindows() && (!Gatherer.isGsdlRemote)) {
+	    command_parts_list.add(Configuration.perl_path);
+	    command_parts_list.add("-S");
+	}
+	command_parts_list.add(LocalGreenstone.getBinScriptDirectoryPath() + "exportcol.pl");
+
+	if (Gatherer.isGsdlRemote) {
+	    command_parts_list.add("-nonetscape");
+	}
+
+	command_parts_list.add("-gli");
+	command_parts_list.add("-language");
+	command_parts_list.add(Configuration.getLanguage());
+
+	if (cd_title.equals("")) {
+	    command_parts_list.add("-cdname");
+	    command_parts_list.add("Greenstone Collections");
+
+	    command_parts_list.add("-cddir");
+	    command_parts_list.add("exported_collections");
+	}
+	else {
+	    command_parts_list.add("-cdname");
+	    command_parts_list.add(cd_title);
+
+	    String cd_dir = "exported_"+cd_title.replaceAll("\\s","");
+	    command_parts_list.add("-cddir");
+	    command_parts_list.add(cd_dir);
+	}
+
+	for (int i = 0; i < num_collections; i++) {
+	    command_parts_list.add(((BasicCollectionConfiguration) selected_collections.get(i)).getShortName());
+	}
+
+	DebugStream.print("export command = ");
+	for (int i = 0; i < command_parts_list.size(); i++) {
+	    DebugStream.print(command_parts_list.get(i) + " ");
+	}
+	DebugStream.println("");
+
+	// Run the exportcol.pl command
+	String[] command_parts = (String[]) command_parts_list.toArray(new String[0]);
+	GShell process = new GShell(command_parts, GShell.CDIMAGE, 3, this, null, GShell.GSHELL_CDIMAGE);
+	process.start();
+	//process.run();
+	DebugStream.println("WriteCDImagePrompt.writeCDImageCollections().return");
+	
+    }
+
+    /** Shows an export 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, String extra) {
+	args = new String[2];
+	StringBuffer coll_names = new StringBuffer();
+	for (int i=0; i<selected_collections.size();i++) {
+	    if (i>0) {
+		coll_names.append(", ");
+	    }
+	    BasicCollectionConfiguration complete_collection = (BasicCollectionConfiguration)selected_collections.get(i);
+	    coll_names.append(complete_collection.getName() + StaticStrings.SPACE_CHARACTER + StaticStrings.OPEN_PARENTHESIS_CHARACTER + complete_collection.getShortName() + StaticStrings.CLOSE_PARENTHESIS_CHARACTER);
+	    complete_collection = null;
+	}
+	
+	args[0] = coll_names.toString();
+	args[1] = LocalGreenstone.getTmpDirectoryPath();
+	if(cd_title.equals("")) {
+	    args[1] += "exported_collections";
+	} else {
+	    args[1] += "exported_"+cd_title.replaceAll("\\s","");
+	}
+	String title;
+	String label;
+	if (success) {
+	    title = Dictionary.get("WriteCDImagePrompt.Successful_Title");
+	    label = Dictionary.get("WriteCDImagePrompt.Successful_Export", args);
+	} else {
+	    title = Dictionary.get("WriteCDImagePrompt.Failed_Title");
+	    label = Dictionary.get("WriteCDImagePrompt.Failed_Export", args);
+	}
+	SimpleResultDialog result_dialog = new SimpleResultDialog(title, label, extra);
+	result_dialog.setVisible(true); // Blocks
+	result_dialog.dispose();
+	result_dialog = null;
+    }
+
+    /** Method to scan the collect directory retrieving and reloading each collection it finds, while building the list of known collections.
+     * @see org.greenstone.gatherer.Configuration
+     * @see org.greenstone.gatherer.Gatherer
+     * @see org.greenstone.gatherer.util.ArrayTools
+     * @see org.greenstone.gatherer.util.Utility
+     */
+    private void scanForCollections() {
+	// Start at the collect dir.
+	File collect_directory = new File(Gatherer.getCollectDirectoryPath());
+	if (collect_directory.exists()) {
+	    // Now for each child directory see if it contains a .col file and
+	    // if so try to load it..
+	    File collections[] = collect_directory.listFiles();
+	    ArrayTools.sort(collections);
+	    for(int i = 0; collections != null && i < collections.length; i++) {
+		if(collections[i].isDirectory() && !collections[i].getName().equals(StaticStrings.MODEL_COLLECTION_NAME)) {
+		    File config_file = new File(collections[i], Utility.CONFIG_FILE);
+		    if (config_file.exists()) {
+			BasicCollectionConfiguration config = new BasicCollectionConfiguration(config_file);
+			all_collections.add(config);		        
+			config = null;
+		    }
+		}
+	    }
+	}
+	// Otherwise the collect directory doesn't actually exist, so there ain't much we can do.
+    }
+
+
+    /** All implementation of GShellListener must include this method so the listener can be informed of messages from the GShell.
+     * @param event A <strong>GShellEvent</strong> that contains, amoung other things, the message.
+     */
+    public synchronized void message(GShellEvent event) {
+	// Ignore the messages from RecPlug with 'show_progress' set (used for progress bars)
+	String message = event.getMessage();
+	if (message.startsWith("exportcol.pl>")) {
+	    message = message.substring(13);
+	    //DebugStream.println("message = "+event.getMessage());
+	    error_message.append(message);
+	    error_message.append("\n");
+	}
+    }
+
+    /** All implementation of GShellListener must include this method so the listener can be informed when a GShell begins its task. Implementation side-effect, not actually used.
+     * @param event A <strong>GShellEvent</strong> that contains details of the initial state of the <strong>GShell</strong> before task comencement.
+     */
+    public synchronized void processBegun(GShellEvent event) {
+	// We don't care. 
+    }
+    /** All implementation of GShellListener must include this method so the listener can be informed when a GShell completes its task.
+     * @param event A <strong>GShellEvent</strong> that contains details of the final state of the <strong>GShell</strong> after task completion.
+     */
+    public synchronized void processComplete(GShellEvent event) {
+	successful = false;
+	if(event.getStatus() == GShell.OK) {
+	    if(event.getType() == GShell.CDIMAGE) {
+		successful = true;
+	    }
+	}
+	ok_button_listener.processComplete();
+    }
+
+    /** A button listener implementation, which listens for actions on the close button and disposes of the dialog when detected. */
+    private class CancelButtonListener 
+	implements ActionListener {
+	/** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
+	 * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    prompt.dispose();
+	}
+    }
+
+
+    /** This private class listens for selection events in from the list and then displays the appropriate details for that collection.
+     */
+    private class CollectionListListener 
+	implements ListSelectionListener
+    {
+	/** Any implementation of ListSelectionListener must include this method so we can be informed when the list selection changes.
+	 * @param  event a <strong>ListSelectionEvent</strong> containing all the relevant information garnered from the event itself
+	 */
+	public void valueChanged(ListSelectionEvent event)
+	{
+	    // Can only export when something is ticked
+	    ok_button.setEnabled(!list.isNothingTicked());
+
+	    if (list.isSelectionEmpty()) {
+		// This only happens when the dialog is first entered
+		Dictionary.setText(details_textarea, "DeleteCollectionPrompt.No_Collection");
+		return;
+	    }
+
+	    collection = (BasicCollectionConfiguration) ((CheckListEntry) list.getSelectedValue()).getObject();
+	    args = new String[3];
+	    args[0] = collection.getCreator();
+	    args[1] = collection.getMaintainer();
+	    args[2] = collection.getDescription();
+	    Dictionary.setText(details_textarea, "DeleteCollectionPrompt.Details", args);
+	    details_textarea.setCaretPosition(0);
+	}
+    }
+
+
+    /** The OK button listener implementation. */
+    private class OKButtonListener 
+	implements ActionListener {
+	private Component glass_pane;
+	private MouseListener mouse_blocker_listener;
+	private ProgressDialog progress_dialog;
+
+	/** Any implementation of ActionListener must include this method so we can be informed when the button is actioned.
+	 * @param event An <strong>ActionEvent</strong> containing all the relevant information garnered from the event itself.
+	 * @see org.greenstone.gatherer.Configuration
+	 * @see org.greenstone.gatherer.Gatherer
+	 * @see org.greenstone.gatherer.util.Utility
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    ///ystem.err.println("OK Clicked");
+	    // Make sure there are some colls specified
+	    selected_collections = list.getTicked();
+	    error_message = new StringBuffer();
+	    
+	    // Set the cursor to hourglass
+	    glass_pane = getGlassPane();
+	    mouse_blocker_listener = new MouseAdapter() {};
+	    glass_pane.addMouseListener(mouse_blocker_listener);
+	    glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+	    glass_pane.setVisible(true);
+
+	    // Export the selected collection.
+	    ///ystem.err.println("Write CD-ROM/DVD image for named collections");
+	    writeCDImageCollections();
+
+	    // Show progress dialog
+	    ///ystem.err.println("Showing progress dialog");
+	    progress_dialog = new ProgressDialog();
+	    progress_dialog.setVisible(true);
+	}
+
+	public void processComplete() {
+	    ///ystem.err.println("Process complete");
+	    // Dispose of progress dialog
+	    progress_dialog.setVisible(false);
+	    progress_dialog.dispose();
+	    progress_dialog = null;
+
+	    // unset the cursor
+	    glass_pane.setVisible(false);
+	    glass_pane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+	    glass_pane.removeMouseListener(mouse_blocker_listener);
+	    glass_pane = null;
+	    mouse_blocker_listener= null;
+	    
+	    if (successful) {
+		resultPrompt(true, error_message.toString());
+	    } else {
+		resultPrompt(false, error_message.toString());
+	    }
+	    error_message = null;
+	}
+
+	private class ProgressDialog 
+	    extends ModalDialog {
+	    
+	    private Dimension size = new Dimension(400,65);
+	    
+	    public ProgressDialog() {
+		super(Gatherer.g_man, Dictionary.get("WriteCDImagePrompt.Title"), true);
+		setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+		setSize(size);
+		JPanel content_pane = (JPanel) getContentPane();
+		JLabel progress_label = new JLabel();
+		Dictionary.setText(progress_label, "WriteCDImagePrompt.Progress_Label");
+		JProgressBar progress_bar = new JProgressBar();
+		progress_bar.setIndeterminate(true);
+		content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+		content_pane.setLayout(new BorderLayout());
+		content_pane.add(progress_label, BorderLayout.NORTH);
+		content_pane.add(progress_bar, BorderLayout.CENTER);
+		// Position
+		Rectangle frame_bounds = Gatherer.g_man.getBounds();
+		setLocation(frame_bounds.x + (frame_bounds.width - size.width) / 2, frame_bounds.y + (frame_bounds.height - size.height) / 2);
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/Autofilter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/Autofilter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/Autofilter.java	(revision 10506)
@@ -0,0 +1,379 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.gui.metaaudit;
+
+
+import java.util.ArrayList;
+import org.greenstone.gatherer.util.StaticStrings;
+
+/** An Autofilter object stores the filters set on a single column, and provides a method for determining if a certain value passes the filter.
+ * @author John Thompson
+ * @version 2.3
+ */
+public class Autofilter {
+
+    static public void main(String[] args) {
+	if(args.length != 2) {
+	    System.err.println("Usage: java Autofilter <string> <pattern>");
+	}
+	else {
+	    switch(compareToPattern(args[0], args[1])) {
+	    case LESS_THAN:
+		System.err.print(args[0] + " is less than");
+		break;
+	    case GREATER_THAN:
+		System.err.print(args[0] + " is greater than");
+		break;
+	    case EQUAL:
+		System.err.print(args[0] + " is equal to");
+		break;
+	    default:
+		System.err.print(args[0] + " is something to");
+	    }
+	    System.err.println(" " + args[1]);
+	}
+    }
+
+    /** A String comparison which also recognises the WildCard character. The basic idea is that '*' matches zero or more of any characters, and if we limited patterns to be like "a*" then as soon as we hit the star we could return a match. The problem is that we want patterns like "b*y" which would match "boy" but not "bee" nor "bus" (but should return less than or greater than for each of these respectively). Thus our testing has to become non-deterministic so the matches are conducted like so: 
+     * Given p = [ b * y ]
+     * Test  s = [ b e e ]  Result: p0=s0,{(p2>s1=>ERROR),(p1=s1,{(p1>s2=>ERROR),(p2>s2=>LESS_THAN)})} => LESS_THAN
+     * Test  s = [ b o y ]  Result: p0=s0,{(p2>s1=>ERROR),(p1=s1,{(p1>s2=>ERROR),(p2=s2=>EQUAL)})} => EQUAL
+     * Test  s = [ b u s ]  Result: p0=s0,{(p2>s1=>ERROR),(p1=s1,{(p1>s2=>ERROR),(p2<s2=>GREATER_THAN)})} => GREATER_THAN
+     * where the two () phrases within a {} represent two different 'threads' of processing. Errors are generated when one string runs out of characters before the other. Only non-error results are propogated. I've decided to implement this non-deterministic matching as a recursive function call.
+     * If you analyse it you can see there are three possible actions when a '*' is detected.
+     * 1. * is an empty string, ignore it in pattern and try to compare the next character in p with the current character in s. This case only occurs if there are more characters in p (otherwise apple would be greater than a*)
+     * 2. * matches exactly the current character in s, try to match the next character in p with the next character in s
+     * 3. * matches some string of characters including the current character in s, try to match '*' against the next character in s
+     * @param  s the String being matched
+     * @param  p the Pattern to match it against
+     * @return -1 if s is less than p, 0 if they are equal, 1 if s is greater than p
+     */
+    static private int compareToPattern(String s, String p) {
+	if(p.indexOf(StaticStrings.STAR_CHAR) == -1) {
+	    return compareToPattern(s, p, 0, 0, false);
+	}
+	else {
+	    return compareToPattern(s, p, 0, 0, true);
+	}
+    }
+
+    static final private int LESS_THAN = -1;
+    static final private int EQUAL = 0;
+    static final private int GREATER_THAN = 1;
+    static final private int ERROR = 42;
+
+    static private int compareToPattern(String s, String p, int s_index, int p_index, boolean wildcard_matching) {
+	// Lets do the simple cases first.
+	// Both out of characters at the same time
+	if(s_index >= s.length() && p_index >= p.length()) {
+	    ///ystem.err.println("Both out of characters. Equal.");
+	    return EQUAL;
+	}
+	// s out of characters first
+	if(s_index >= s.length()) {
+	    // Not allowed to run out if matching wildcard
+	    if(wildcard_matching) {
+		return ERROR;
+	    }
+	    // Remember that wildcard matches the empty string too, so as long as there are only '*' characters left in the pattern we can say they are equal as well.
+	    else {
+		while(p_index < p.length()) {
+		    if(p.charAt(p_index) == StaticStrings.STAR_CHAR) {
+			p_index++;
+		    }
+		    else {
+			///ystem.err.println("S out of characters. Less Than.");
+			return LESS_THAN;
+		    }
+		}
+		// We've run out of pattern and it only contained '*' so we're still equal
+		///ystem.err.println("Both out of characters. Equal.");
+		return EQUAL;
+	    }
+	}
+	// p out of characters first
+	if(p_index >= p.length()) {
+	    // Not allowed to run out if matching wildcard
+	    if(wildcard_matching) {
+		return ERROR;
+	    }
+	    // so it is greater than
+	    else {
+		///ystem.err.println("P out of characters. Greater Than.");
+		return GREATER_THAN;
+	    }
+	}
+	char s_char = s.charAt(s_index);
+	char p_char = p.charAt(p_index);
+	///ystem.err.println("Comparing " + s_char + " against pattern character " + p_char);
+	// Equivelent characters
+	// Now the tricky-dicky bit - WildCard matching.
+	if(p_char == StaticStrings.STAR_CHAR) {
+	    int result;
+	    // Case 1
+	    ///ystem.err.println("WildCard Case 1");
+	    if(p_index + 1 < p.length()) {
+		if((result = compareToPattern(s, p, s_index, p_index + 1, wildcard_matching)) != ERROR) {
+		    return result;
+		}
+	    }
+	    // Case 2
+	    ///ystem.err.println("WildCard Case 2");
+	    if((result = compareToPattern(s, p, s_index + 1, p_index + 1, wildcard_matching)) != ERROR) {
+		return result;
+	    } 
+	    // Case 3
+	    ///ystem.err.println("WildCard Case 3");
+	    if((result = compareToPattern(s, p, s_index + 1, p_index, wildcard_matching)) != ERROR) {
+		return result;
+	    }
+	}
+	if(s_char == p_char) {
+	    return compareToPattern(s, p, s_index + 1, p_index + 1, wildcard_matching);
+	}
+	// A preceeding character
+	if(s_char < p_char) {
+	    ///ystem.err.println("s char is less than p char");
+	    if(wildcard_matching) {
+		///ystem.err.println("Because we are wildcard matching we still have to match the rest of s incase of errors.");
+		if(compareToPattern(s, p, s_index + 1, p_index + 1, wildcard_matching) != ERROR) {
+		    ///ystem.err.println("No error. Less than.");
+		    return LESS_THAN;
+		}
+		else {
+		    ///ystem.err.println("Error detected.");
+		    return ERROR;
+		}
+	    }
+	    else {
+		///ystem.err.println("Less than.");
+		return LESS_THAN;
+	    }
+	}
+	// A succeeding character
+	if(s_char > p_char) {
+	    ///ystem.err.println("s char is greater than p char");
+	    if(wildcard_matching) {
+		///ystem.err.println("Because we are wildcard matching we still have to match the rest of s incase of errors.");
+		if(compareToPattern(s, p, s_index + 1, p_index + 1, wildcard_matching) != ERROR) {
+		    ///ystem.err.println("No error. Greater than.");
+		    return GREATER_THAN;
+		}
+		else {
+		    ///ystem.err.println("Error detected.");
+		    return ERROR;
+		}
+	    }
+	    else {
+		///ystem.err.println("Greater than.");
+		return GREATER_THAN;
+	    }
+	}
+	// Oh-No. Well, we'll just assume that string is less than pattern
+	return LESS_THAN;
+    }
+
+    /** <i>true</i> if the filter should be applied, <i>false</i> to indicate the filter is turned off. */
+    public boolean active;
+    /** <i>true</i> if the matching for the first expression should be case sensitive, <i>false</i> otherwise. */
+    public boolean casesense_one;
+    /** <i>true</i> if the matching for the second expression should be case sensitive, <i>false</i> otherwise. */
+    public boolean casesense_two;
+    /** Used to determine the operation intended when applying two filters, and set using the values of the OPERATION_TYPE enumeration. */
+    public boolean operation;
+    /** Used to determine how the column this filter is applied to should be sorted, and set using the values of the SORT_TYPE enumeration. */
+    public boolean sort;
+    /** The method to be used for the first filter expression, set from the values of the METHOD_LIST enumeration. */
+    public int method_one;
+    /** The method to be used for the second filter expression, set from the values of the METHOD_LIST enumeration. */
+    public int method_two;
+    /** The value to be matched against for the first expression. */
+    public String value_one;
+    /** The value to be matched against for the second expression. */
+    public String value_two;
+    /** An element of the SORT_TYPE enumeration, indicates lowest to highest value column ordering. */
+    public static final boolean ASCENDING = true;
+    /** An element of the OPERATION_TYPE enumeration, indicates that both filter expressions must be met (conjunction). */
+    public static final boolean AND = true;
+    /** An element of the SORT_TYPE enumeration, indicates highest to lowest value column ordering. */
+    public static final boolean DESCENDING = false;
+    /** An element of the OPERATION_TYPE enumeration, indicates that either (or both) filter expressions must be met (disjunction). */
+    public static final boolean OR = false;
+    /** An enumeration of symbolic names of various matching methods. */
+    public static final String METHOD_LIST[] = { "Autofilter.eqeq", "Autofilter.!eq", "Autofilter.<", "Autofilter.<eq", "Autofilter.>", "Autofilter.>eq", "Autofilter.^", "Autofilter.!^", "Autofilter.$", "Autofilter.!$", "Autofilter.?", "Autofilter.!?" };
+
+    /** Default Constructor. */
+    public Autofilter() {
+	operation = OR;
+	sort = ASCENDING;
+    }
+    /** Determine if this filter is currently active.
+     * @return <i>true</i> if it is active, <i>false</i> otherwise.
+     */
+    public boolean active() {
+	return active;
+    }
+    /** Determine if this list of values (for a certain cell) passes the filter.
+     * @param values An <strong>ArrayList</strong> of values sourced from a single cell in the associated column.
+     * @return <i>true</i> if the values match and should be displayed, <i>false</i> otherwise.
+     */
+    public boolean filter(ArrayList values) {
+	boolean result = false;
+	if(value_one != null) {
+	    result = filter(values, method_one, value_one, casesense_one);
+	    if(result) {
+		if(operation == AND && value_two != null) {
+		    result = filter(values, method_two, value_two, casesense_two);
+		}
+	    }
+	    else if(operation == OR && value_two != null) {
+		result = filter(values, method_two, value_two, casesense_two);
+	    }
+	}
+	return result;
+    }
+    /** Set the current activity state of this filter.
+     * @param active The new state of this filter, <i>true</i> to activate, <i>false</i> otherwise.
+     */
+    public void setActive(boolean active) {
+	this.active = active;
+    }
+    /** Set one of the filter expressions using the given information.
+     * @param number The number of the filter you wish to set as an <i>int</i>. Either 1 or 2.
+     * @param method An <i>int</i> indicating the method to be used when matching.
+     * @param value The <strong>String</strong> to be matched against.
+     * @param casesense <i>true</i> if this expression should be case sensitive, <i>false</i> otherwise.
+     */
+    public void setFilter(int number, int method, String value, boolean casesense) {
+	if(!casesense && value != null) {
+	    value = value.toLowerCase();
+	}
+	if(number == 1) {
+	    casesense_one = casesense;
+	    method_one = method;
+	    value_one = value;
+	}
+	else {
+	    casesense_two = casesense;
+	    method_two = method;
+	    value_two = value;
+	}
+    }
+    /** Set the operation to be used to join the two filters (if a second filter is set).
+     * @param operation <i>true</i> for conjunct filters, <i>false</i> for disjunct.
+     */ 
+    public void setOperation(boolean operation) {
+	this.operation = operation;
+    }
+    /** Set the sort order of this column.
+     * @param sort <i>true</i> for ascending sort, <i>false</i> for descending.
+     */
+    public void setSort(boolean sort) {
+	this.sort = sort;
+    }
+    /** Decide whether a row should be displayed or filtered. The result depends on the selector set with setFilterType.
+     * @param values An <strong>ArrayList</strong> of values to be checked against the filter.
+     * @param method The method of matching to be used, as an <i>int</i>.
+     * @param target The <strong>String</Strong> to match against.
+     * @param casesense <i>true</i> if the match is to be case sensitive, <i>false</i> otherwise.
+     * @return <i>true</i> to display the row, <i>false</i> to hide it.
+     */
+    public boolean filter(ArrayList values, int method, String target, boolean casesense) {
+	boolean result = false;
+	// There are several special cases when the filter always returns turn, such as when the target is the wildcard character.
+	if(target == null || target.length() == 0 || target.equals("*")) {
+	    result = true;
+	}
+	else {
+	    // For each value in the list...
+	    for(int i = 0; i < values.size(); i++) {
+		boolean pass;
+		String source;
+		// Account for case sensitivity.
+		if(casesense) {
+		    source = values.get(i).toString();
+		}
+		else {
+		    source = values.get(i).toString().toLowerCase();
+		}
+		///ystem.err.println("Testing " + source + " against pattern " + target);
+		// Perform the match, based on the selected method.
+		switch(method) {
+		case 1: // !EQ
+		    pass = (compareToPattern(source, target) != 0);
+		    break;
+		case 2: // <
+		    pass = (compareToPattern(source, target) < 0);
+		    break;
+		case 3: // <eq
+		    pass = (compareToPattern(source, target) <= 0);
+		    break;
+		case 4: // >
+		    pass = (compareToPattern(source, target) > 0);
+		    break;
+		case 5: // >eq
+		    pass = (compareToPattern(source, target) >= 0);
+		    break;
+		case 6: // ^
+		    pass = source.startsWith(target);
+		    break;
+		case 7: // !^
+		    pass = !(source.startsWith(target));
+		    break;
+		case 8: // $
+		    pass = source.endsWith(target);
+		    break;
+		case 9: // !$
+		    pass = !(source.endsWith(target));
+		    break;
+		case 10: // ?
+		    pass = (source.indexOf(target) != -1);
+		    break;
+		case 11: // !?
+		    pass = (source.indexOf(target) == -1);
+		    break;
+		default: // EQEQ
+		    pass = (compareToPattern(source, target) == 0);
+		    break;
+		}
+		result = result || pass;
+	    }
+	}
+	return result;		 
+    }
+    /** Produce a textual representation of this autofilter.
+     * @return A <strong>String</strong> displaying details of this autofilter.
+     */
+    public String toString() {
+	String result = "One: " + method_one + " - " + value_one + " - " + casesense_one;
+	if(value_two != null) {
+	    result = result + "\n" + "Operation: " + (operation?"AND":"OR") + "\n";
+	    result = result + "Two: " + method_two + " - " + value_two + " - " + casesense_two;
+	}
+	return result;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/AutofilterDialog.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/AutofilterDialog.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/AutofilterDialog.java	(revision 10506)
@@ -0,0 +1,422 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui.metaaudit;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.gui.SimpleMenuBar;
+import org.greenstone.gatherer.gui.ModalDialog;
+
+/** The autofilter concept comes from Microsoft Excel spreadsheets that use autofilters to filter to the sheet. When you click on the heading of a column, a new prompt allows you to specify what filter should be acting apon the selected column. Any new filter is conjoined with any previous filters to provide a sheet containing only rows that match all current filters. Each column must also provide an indicator for determining if a filter is set (in this case a special icon) and and a method for removing a filter (use the clear filter button within the autofilter dialog). Having recently discovered that most JVMs aren't very good at recoving memory used by dialog and frame windows, special care must be made to deallocate all references properly, as a user may open several dozen autofilter prompts over the lifetime of a session.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public final class AutofilterDialog
+    extends ModalDialog {
+    /** The filter being edited. */
+    private Autofilter filter;
+    /** A reference to ourselves so our inner classes can reference us. */
+    private AutofilterDialog self;
+
+    private boolean cancelled;
+    /** The value returned from the filter dialog prompt. Used to determine if a prompt was set or unset, and what subsequent action to take. */
+    private byte return_value = 0;
+    /** The button used to cancel the prompt. */
+    private JButton cancel_button = null;
+    private JButton remove_button = null;
+    private JButton set_button = null;
+    /** Used to specify that the given filters should be applied conjunctly. */
+    private JRadioButton and_radiobutton = null;
+    /** The check box used to specify whether the first filter is case sensitive. */
+    private JCheckBox first_case = null;
+    /** Used to disable the second filter. */
+    private JRadioButton none_radiobutton = null;
+    /** Used to specify that the given filters should be applied disjunctly. */
+    private JRadioButton or_radiobutton = null;
+    /** The check box used to specify whether the second filter is case sensitive. */
+    private JCheckBox second_case = null;
+    /** Used to specify the order of the resulting set: Ascending or Descending. */
+    private JRadioButton ascending_radiobutton = null;
+    private JRadioButton descending_radiobutton = null;
+    /** The method used to match the first filter: Contains, Doesn't contain etc. */
+    private JComboBox first_method = null;
+    /** The value to be matched for the first filter. */
+    private JComboBox first_value = null;
+    /** The method used to match the first filter. Options as for the first method. */
+    private JComboBox second_method = null;
+    /** The value to be matched for the second filter. */
+    private JComboBox second_value = null;
+    /** Used for the most basic filter where an Equals, Case sensitive method is automatically used. */
+    private JComboBox value = null;
+    /** The label which displays the name of the currently selected column (the column that will be associated with the autofilter this dialog produces). */
+    private JLabel name;
+    /** The autofilter prompt contains two different panes, one for basic functionality and one for advanced. This containiner component is used to allow access to each via a 'tabbed' interface. */
+    private JTabbedPane control = null;
+    /** A reference back to the MetaAudit dialog that spawned this prompt. Used to make sure that any open dialog window is always in front of the audit pane. */
+    private MetaAuditFrame dialog;
+    /** The default size for the autofilter control. */
+    static final private Dimension SIZE = new Dimension(640, 245);
+
+    /** Constructor.
+     * @param dialog A reference to the <strong>MetaAuditFrame</strong> that spawned this dialog.
+     * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
+     * @see org.greenstone.gatherer.gui.metaaudit.AutofilterDialog.ButtonListener
+     * @see org.greenstone.gatherer.gui.metaaudit.AutofilterDialog.CheckListener
+     */
+    public AutofilterDialog(MetaAuditFrame dialog) {
+	super(Gatherer.g_man);
+	this.dialog = dialog;
+	this.self = this;
+	setModal(true);
+	setJMenuBar(new SimpleMenuBar("reviewingmetadata")); 
+	setSize(SIZE);
+	Dictionary.setText(this, "Autofilter.Title");
+
+	// Creation
+	JPanel content_pane = (JPanel) getContentPane();
+	JPanel name_pane = new JPanel();
+	JLabel name_label = new JLabel();
+	Dictionary.setText(name_label, "Autofilter.Name");
+	JTextField name_template = new JTextField();
+	name = new JLabel();
+	name.setBorder(name_template.getBorder());
+	control = new JTabbedPane();
+	JPanel value_pane = new JPanel();
+	JPanel inner_value_pane = new JPanel();
+	JLabel value_label = new JLabel();
+	Dictionary.setText(value_label, "Autofilter.eqeq"); 
+	value = new JComboBox();
+	value.setEditable(false);
+	JPanel custom_pane = new JPanel();
+
+	JPanel first_pane = new JPanel();
+	first_method = new JComboBox();
+	first_value = new JComboBox();
+	first_value.setEditable(true);
+	first_value.addItem("");
+	first_value.setSelectedItem("");
+	first_case = new JCheckBox();
+	Dictionary.setText(first_case, "Autofilter.Case_Sensitive");
+	JPanel operator_pane = new JPanel();
+	JLabel operator_label = new JLabel();
+	Dictionary.setText(operator_label, "Autofilter.Operator");
+	ButtonGroup operator_group = new ButtonGroup();
+	and_radiobutton = new JRadioButton();
+	and_radiobutton.setOpaque(false);
+	Dictionary.setText(and_radiobutton, "Autofilter.AND");
+	none_radiobutton = new JRadioButton();
+	none_radiobutton.setOpaque(false);
+	none_radiobutton.setSelected(true);
+	Dictionary.setText(none_radiobutton, "Autofilter.None");
+	or_radiobutton = new JRadioButton();
+	or_radiobutton.setOpaque(false);
+	Dictionary.setText(or_radiobutton, "Autofilter.OR");
+	operator_group.add(none_radiobutton);
+	operator_group.add(and_radiobutton);
+	operator_group.add(or_radiobutton);
+
+	JPanel second_pane = new JPanel();
+	second_method = new JComboBox();
+	second_method.setEnabled(false);
+	second_value = new JComboBox();
+	second_value.setEditable(true);
+	second_value.setEnabled(false);
+	second_value.addItem("");
+	second_value.setSelectedItem("");
+	second_case = new JCheckBox();
+	Dictionary.setText(second_case, "Autofilter.Case_Sensitive"); 
+	JPanel lower_pane = new JPanel();
+	JPanel order_pane = new JPanel();
+	Dictionary.setTooltip(order_pane, "Autofilter.Order_Tooltip");
+	JLabel order_label = new JLabel();
+	Dictionary.setText(order_label, "Autofilter.Order");
+
+	ButtonGroup order_group = new ButtonGroup();
+	ascending_radiobutton = new JRadioButton();
+	ascending_radiobutton.setOpaque(false);
+	ascending_radiobutton.setSelected(true);
+	Dictionary.setText(ascending_radiobutton, "Autofilter.Ascending");
+	descending_radiobutton = new JRadioButton();
+	descending_radiobutton.setOpaque(false);
+	Dictionary.setText(descending_radiobutton, "Autofilter.Descending");
+	order_group.add(ascending_radiobutton);
+	order_group.add(descending_radiobutton);
+
+	// Assign values to method comboboxes.
+	for(int i = 0; i < Autofilter.METHOD_LIST.length; i++) {
+	    first_method.addItem(Dictionary.get(Autofilter.METHOD_LIST[i]));
+	    second_method.addItem(Dictionary.get(Autofilter.METHOD_LIST[i]));
+	}
+	JPanel button_pane = new JPanel();
+	cancel_button = new GLIButton();
+	cancel_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.setBoth(cancel_button, "General.Cancel", "General.Pure_Cancel_Tooltip");
+	remove_button = new GLIButton();
+	remove_button.setMnemonic(KeyEvent.VK_R);
+	Dictionary.setBoth(remove_button, "Autofilter.Remove", "Autofilter.Remove_Tooltip");
+	set_button = new GLIButton();
+	set_button.setMnemonic(KeyEvent.VK_S);
+	Dictionary.setBoth(set_button, "Autofilter.Set", "Autofilter.Set_Tooltip");
+
+	// Connection
+	and_radiobutton.addActionListener(new CheckListener(true));
+	none_radiobutton.addActionListener(new CheckListener(false));
+	or_radiobutton.addActionListener(new CheckListener(true));
+	cancel_button.addActionListener(new ButtonListener()); // It returns any currently set filter
+	remove_button.addActionListener(new ButtonListener(false));
+	set_button.addActionListener(new ButtonListener(true));
+
+	// Layout		  
+	name_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
+
+	name_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	name_pane.setLayout(new BorderLayout());
+	name_pane.add(name_label, BorderLayout.WEST);
+	name_pane.add(name, BorderLayout.CENTER);
+
+	value_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
+
+	inner_value_pane.setLayout(new BorderLayout());
+	inner_value_pane.add(value_label, BorderLayout.WEST);
+	inner_value_pane.add(value, BorderLayout.CENTER);
+
+	value_pane.setBorder(BorderFactory.createEmptyBorder(5,10,5,10));
+	value_pane.setLayout(new BorderLayout());
+	value_pane.add(inner_value_pane, BorderLayout.NORTH);
+
+	first_pane.setLayout(new BorderLayout());
+	first_pane.add(first_method, BorderLayout.WEST);
+	first_pane.add(first_value, BorderLayout.CENTER);
+	first_pane.add(first_case, BorderLayout.EAST);
+
+	operator_pane.setLayout(new GridLayout(1,4));
+	operator_pane.add(operator_label);
+	operator_pane.add(none_radiobutton);
+	operator_pane.add(and_radiobutton);
+	operator_pane.add(or_radiobutton);
+
+	second_pane.setLayout(new BorderLayout());
+	second_pane.add(second_method, BorderLayout.WEST);
+	second_pane.add(second_value, BorderLayout.CENTER);
+	second_pane.add(second_case, BorderLayout.EAST);
+
+	order_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	order_pane.setLayout(new GridLayout(1,2));
+	order_pane.add(order_label);
+	order_pane.add(ascending_radiobutton);
+	order_pane.add(descending_radiobutton);
+
+	custom_pane.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
+	custom_pane.setLayout(new GridLayout(3,1));
+	custom_pane.add(first_pane);
+	custom_pane.add(operator_pane);
+	custom_pane.add(second_pane);
+
+	control.add(Dictionary.get("Autofilter.Filter_By_Value"), value_pane);
+	control.add(Dictionary.get("Autofilter.Custom_Filter"), custom_pane);
+
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	button_pane.setLayout(new GridLayout(1, 3));
+	button_pane.add(set_button);
+	button_pane.add(remove_button);
+	button_pane.add(cancel_button);
+
+	lower_pane.setLayout(new BorderLayout());
+	lower_pane.add(order_pane, BorderLayout.CENTER);
+	lower_pane.add(button_pane, BorderLayout.SOUTH);
+
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(name_pane, BorderLayout.NORTH);
+	content_pane.add(control, BorderLayout.CENTER);
+	content_pane.add(lower_pane, BorderLayout.SOUTH);
+
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	screen_size = null;
+    }
+
+    public boolean cancelled() {
+	return cancelled;
+    }
+
+    /** Destructor. */
+    public void destroy() {
+	dispose();
+	first_case = null;
+	second_case = null;
+	first_method = null;
+	first_value = null;
+	second_method = null;
+	second_value = null;
+	value = null;
+	control = null;
+	dialog = null;
+	self = null;
+	name = null;
+    }
+    /** Display the modal dialog box, allowing the user to define the filter. When the user presses one of the buttons, dispose and return to the caller providing an indication of which button was pressed.
+     * @return An <i>int</i> which indicates which button was pressed to dismiss the dialog.
+     */
+    public Autofilter display(Autofilter filter, ArrayList raw_values, String column_name) {
+	this.cancelled = false;
+	this.filter = filter;
+	name.setText(column_name);
+	// Prune values so it only contains unique entries, then order.
+	TreeSet values = new TreeSet(raw_values);
+	value.setModel(new DefaultComboBoxModel(values.toArray()));
+	String star = "*";
+	value.insertItemAt(star, 0);
+	value.setSelectedItem(star);
+	first_value.setModel(new DefaultComboBoxModel(values.toArray()));
+	second_value.setModel(new DefaultComboBoxModel(values.toArray()));
+	// Restore previous values.
+	if(filter != null && filter.value_one != null) {
+	    value.setSelectedItem(filter.value_one);
+	    first_method.setSelectedIndex(filter.method_one);
+	    first_value.setSelectedItem(filter.value_one);
+	    first_case.setSelected(filter.casesense_one);
+	    if (filter.value_two == null) {
+		none_radiobutton.setSelected(true);
+	    }
+	    else {
+		if (filter.operation) {
+		    and_radiobutton.setSelected(true);
+		}
+		else {
+		    or_radiobutton.setSelected(true);
+		}
+		second_method.setSelectedIndex(filter.method_two);
+		second_value.setSelectedItem(filter.value_two);
+		second_case.setSelected(filter.casesense_two);
+	    }
+	    if (filter.sort) {
+		ascending_radiobutton.setSelected(true);
+		// order.setSelectedIndex(0);
+	    }
+	    else {
+		descending_radiobutton.setSelected(true);
+		// order.setSelectedIndex(1);
+	    }
+	}
+	// Display	  
+	setVisible(true);
+	dialog.toFront();
+	return this.filter;
+    }
+
+    /** Listens for actions on the button it is attached to, and when notified sets the return_value and disposes of the dialog. */
+    private final class ButtonListener
+	implements ActionListener {
+	private boolean cancel_button;
+	private boolean return_filter;
+	
+	/** Default constructor. Returns any filter that was already set */
+	public ButtonListener() {
+	    this.cancel_button = true;
+	}
+
+	/** Does an action on this button cause a filter to be returned. */
+	/** Constructor takes an associated return value as an argument.
+	 * @param return_filter <i>true</i> if we update then return the filter, <i>false</i> to clear existing filter.
+	 */
+	public ButtonListener(boolean return_filter) {
+	    this.cancel_button = false;
+	    this.return_filter = return_filter;
+	}
+	/** When any registered component is actioned apon, set the value and hide the dialog. We hide rather than dispose, because hide assures the data values will be retained. 
+	 * @param event An <strong>ActionEvent</strong> containing information about the action that caused this method call.
+	 * @see org.greenstone.gatherer.gui.metaaudit.Autofilter
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    if(cancel_button) {
+		cancelled = true;
+	    }
+	    else if(return_filter) {
+		if(control.getSelectedIndex() == 0) {
+		    filter.setFilter(1, 0, (String)value.getSelectedItem(), true);
+		    filter.setFilter(2, 0, null, true);
+		}
+		else {
+		    filter.setFilter(1, first_method.getSelectedIndex(), (String)first_value.getSelectedItem(), first_case.isSelected());
+		    if(!none_radiobutton.isSelected()) {
+			if (and_radiobutton.isSelected()) {
+			    filter.setOperation(Autofilter.AND);
+			}
+			else {
+			    filter.setOperation(Autofilter.OR);
+			}
+			filter.setFilter(2, second_method.getSelectedIndex(), (String)second_value.getSelectedItem(), second_case.isSelected());
+		    }
+		}
+		if (ascending_radiobutton.isSelected()) {
+		    filter.setSort(Autofilter.ASCENDING);
+		}
+		else {
+		    filter.setSort(Autofilter.DESCENDING);
+		}
+	    }
+	    else {
+		filter = null;
+	    }
+	    setVisible(false);
+	}
+    }
+    /** Listens for actions on the check box it is attached to, and when notified sets the state of the second method and value to the specified state. */
+    private final class CheckListener
+	implements ActionListener {
+	/** The default desire state any check button this listens to. */
+	private boolean desired_state = false;
+	/** The constructor takes an associated desired state.
+	 * @param desired_state The state that should be set when this is actioned, as a <i>boolean</i>.
+			*/
+	public CheckListener(boolean desired_state) {
+	    this.desired_state = desired_state;
+	}
+	/** Whenever our registered components are actioned apon, set the state of the second method and value to the desired state. */
+	public void actionPerformed(ActionEvent event) {
+	    second_method.setEnabled(desired_state);
+	    second_value.setEnabled(desired_state);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/Filter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/Filter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/Filter.java	(revision 10506)
@@ -0,0 +1,151 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui.metaaudit;
+
+/**************************************************************************************
+ * Title:        Gatherer
+ * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
+ * Company:      The University of Waikato
+ * Written:      03/09/02
+ * Revised:      04/10/02 - Commented
+ **************************************************************************************/
+import de.qfs.lib.gui.TableModelFilter;
+import de.qfs.lib.gui.TableModelFilterEvent;
+import de.qfs.lib.gui.TableModelFilterListener;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Vector;
+import javax.swing.table.TableModel;
+
+/** This class essentially manages the autofilters applied to the metaaudit table.
+ * @author John Thompson
+ * @version 2.3
+ */
+public class Filter
+    implements TableModelFilter {
+    /** An array of autofilters. */
+    private Autofilter filters[];
+    /** The registered TableModelFilterListeners. */
+    private Vector listeners = new Vector ();
+    /** Constructor. 
+     * @param columns The number of columns this Filter will be expected to filter, as an <i>int</i>. 
+     */
+    public Filter(int columns) {
+	filters = new Autofilter[columns];
+    }
+    /** Add a TableModelFilterListener to the TableModelFilter. 
+     * @param listener The <strong>TableModelFilterListener</strong> to add, if it isn't already registered.
+     */
+    public synchronized void addTableModelFilterListener(TableModelFilterListener listener) {
+	if (!listeners.contains(listener)) {
+	    listeners.addElement(listener);
+	}
+    }
+    /** Remove a filter from a column.
+     * @param column The column number to remove the filter from, as an <i>int</i>.
+     */
+    public void clearFilter(int column) {
+	if(filters[column] != null) {
+	    filters[column].setActive(false);
+	}
+    }
+
+
+    /** Determine if a certain row should be shown in the table by checking it against all the current filters.
+     * @param model The <strong>TableModel</strong> the row is from.
+     * @param row The row number as an <i>int</i>
+     * @return <i>true</i> if the rows data matches all autofilters set and should be displayed, <i>false</i> otherwise.
+     */
+    public boolean filter(TableModel model, int row)
+    {
+	for (int i = 0; i < filters.length; i++) {
+	    if (filters[i] != null && filters[i].active()) {
+		ArrayList values = (ArrayList) model.getValueAt(row, i);
+		if (filters[i].filter(values) == false) {
+		    return false;
+		}
+	    }
+	}
+
+	return true;
+    }
+
+
+    /** Retrieve the autofilter associated with a certain column.
+     * @param column The column number as an <i>int</i>.
+     * @return The <strong>Autofilter</strong> assigned to that column.
+     */
+    public Autofilter getFilter(int column) {
+	Autofilter filter = filters[column];
+	if(filter == null) {
+	    filter = new Autofilter();
+	    filters[column] = filter;
+	}
+	return filter;
+    }
+    /** Determine if a certain column is filtered.
+     * @param column The column number as an <i>int</i>.
+     * @return <i>true</i> if there is an active autofilter assigned to this column, <i>false</i> otherwise.
+     */
+    public boolean isFiltered(int column) {
+	boolean result = false;
+	if(filters[column] != null) {
+	    result = filters[column].active();
+	}
+	return result;
+    }
+    /** Remove a TableModelFilterListener from the TableModelFilter.
+     * @param listener The <strong>TableModelFilterListener</strong> to remove.
+     */
+    public synchronized  void removeTableModelFilterListener(TableModelFilterListener listener) {
+	listeners.removeElement(listener);
+    }
+    /** Called whenever the filters assigned changes significantly, thus prompting a reload of the table model data. */
+    public void fireFilterChanged() {
+	///ystem.err.println("Filter Changed!");
+	Vector tmp;
+	synchronized(this) {
+	    tmp = (Vector) listeners.clone();
+	}
+		  
+	TableModelFilterEvent event = new TableModelFilterEvent (this);
+	Enumeration enumeration = tmp.elements();
+	while (enumeration.hasMoreElements()) {
+	    ((TableModelFilterListener) enumeration.nextElement()).filterChanged(event);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderListener.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderListener.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderListener.java	(revision 10506)
@@ -0,0 +1,79 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui.metaaudit;
+
+
+import de.qfs.lib.gui.TableModelSorter;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import org.greenstone.gatherer.metadata.MetadataAuditTableModel;
+
+public class HeaderListener
+    extends MouseAdapter {
+    private MetaAuditFrame parent_frame;
+    private MetaAuditTable table;
+    public HeaderListener(MetaAuditFrame parent_frame, MetaAuditTable table) {
+	this.parent_frame = parent_frame;
+	this.table = table;
+    }
+
+    public void mouseClicked(MouseEvent event) {
+	// Determine the column this was clicked on.
+	int column = table.getColumnModel().getColumnIndexAtX(event.getX());
+	int clicked_column = table.convertColumnIndexToModel(column);
+	// Display the currently assigned filter.
+	Filter filter_model = table.getFilter();
+	Autofilter filter = filter_model.getFilter(clicked_column);
+	MetadataAuditTableModel model = table.getOriginalModel();
+	ArrayList default_values = model.getColumnValues(clicked_column);
+	String column_name = model.getColumnName(clicked_column);
+	filter = parent_frame.autofilter_dialog.display(filter, default_values, column_name);
+	if(!parent_frame.autofilter_dialog.cancelled()) {
+	    if(filter == null) {
+		filter_model.clearFilter(clicked_column);
+	    }
+	    else {
+		filter.setActive(true);
+		TableModelSorter sorter = table.getSorter();
+		sorter.setSortColumn(clicked_column);
+		sorter.setSortAscending(filter.sort);
+	    }
+	    filter_model.fireFilterChanged();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderRenderer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderRenderer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderRenderer.java	(revision 10506)
@@ -0,0 +1,79 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui.metaaudit;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.table.TableCellRenderer;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.util.JarTools;
+
+/** This custom button renderer replaces the boring old column headers with clickable versions which are based on JToggleButtons.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class HeaderRenderer 
+    extends JToggleButton
+    implements TableCellRenderer {
+
+    /** The constructor sets up a margin around the button, and adds the filter icons.
+     */
+    public HeaderRenderer() {
+	setMargin(new Insets(0,0,0,0));
+	setIcon(JarTools.getImage("filter.gif"));
+	setSelectedIcon(JarTools.getImage("filter-on.gif")); 
+    }
+
+    /** Called to create the component to be used as the 'rubber-stamp' for the table cell given the follwing arguments.
+     * @param table The <strong>JTable</strong> that is asking the renderer to draw; can be <i>null</i>.
+     * @param value The value of the cell to be rendered as an <strong>Object</strong>. It is up to the specific renderer to interpret and draw the value. For example, if value is the string "true", it could be rendered as a string or it could be rendered as a check box that is checked. null is a valid value.
+     * @param isSelected <i>true</i> if the cell is to be rendered with the selection highlighted; otherwise <i>false</i>.
+     * @param hasFocus If <i>true</i>, render cell appropriately. For example, put a special border on the cell, if the cell can be edited, render in the color used to indicate editing.
+     * @param row The row index of the cell being drawn as an <i>int</i>. When drawing the header, the value of row is -1.
+     * @param column The column index of the cell being drawn as an <i>int</i>.
+     * @see org.greenstone.gatherer.gui.metaaudit.MetaAuditTable
+     */
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+	setText(value.toString());
+	setToolTipText(Dictionary.get("Autofilter.Table_Header_Tooltip", value.toString()));
+	MetaAuditTable temp = (MetaAuditTable) table;
+	if (temp != null) { // And it may if this is called during table init.
+	    setSelected(temp.isFiltered(column));
+	}
+	return this;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditFrame.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditFrame.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditFrame.java	(revision 10506)
@@ -0,0 +1,225 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui.metaaudit;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.gui.SimpleMenuBar;
+import org.greenstone.gatherer.gui.ModalDialog;
+import org.greenstone.gatherer.util.TreeSynchronizer;
+
+/** The MetaAuditFrame provides a table view of all of the metadata assigned to a selection of CollectionTreeNodes. All values for a certain file and a certain metadata element appear in the same cell. This table can be sorted by any column, and also has a MS Excel-like AutoFilter allowing you to restrict the rows visible to only those that match a certain set of criteria (applied to each column, and then 'ANDED', or cojoined, to determine the filter). Finally this dialog does not block the Gatherer tool, so the file selection can be changed and the dialog will just generate a new table dynamically.<BR>
+ * Much effort has gone into optimizing this table, as it quickly becomes slow and unresponsive to build/filter/sort when the number of records selected is high. However its performance is still nowhere as good as the Excel spreadsheet, and selections of 1000+ records can cause some serious waiting problems. Performance progression, shown in terms of time taken to perform action, are shown below. Note that building includes both the creation of the data model, and/or the time taken to lay out row and column sizes (due to this using multiple entry cells). Also all tables, by default, must be sorted by one column, which is initially the first column in ascending order:<BR><BR>
+ * <TABLE border=1 cellspacing=0 cellpadding=5>
+ * <TR><TD align=center colspan=5>Time Taken with 1000 records (ms)</TD></TR>
+ * <TR><TD>Action</TD><TD>Original</TD><TD>Revision 1</TD><TD>Revision 2</TD><TD>Revision 3</TD></TR>
+ * <TR><TD>Build</TD><TD align=right>113013</TD><TD align=right>1500</TD><TD align=right>1280</TD><TD align=right>665</TD></TR>
+ * <TR><TD>Sort</TD><TD align=right>34228</TD><TD align=right>353</TD><TD align=right>341</TD><TD align=right>338</TD></TR>
+ * <TR><TD>Filter</TD><TD align=right>57110</TD><TD align=right>485</TD><TD align=right>485</TD><TD align=right>485</TD></TR>
+ * </TABLE>
+ * <BR><BR>
+ * <TABLE border=1 cellspacing=0 cellpadding=5>
+ * <TR><TD align=center colspan=5>Time Taken with 10,000 records (ms) [hdlsub]</TD></TR>
+ * <TR><TD>Action</TD><TD>Original</TD><TD>Revision 1</TD><TD>Revision 2</TD><TD>Revision 3</TD></TR>
+ * <TR><TD>Build</TD><TD align=right>DNF</TD><TD align=right>8667</TD><TD align=right>6784</TD><TD align=right>3081</TD></TR>
+ * <TR><TD>Sort</TD><TD align=right>DNF</TD><TD align=right>236</TD><TD align=right>241</TD><TD align=right>228</TD></TR>
+ * <TR><TD>Filter</TD><TD align=right>DNF</TD><TD align=right>59272</TD><TD align=right>59767</TD><TD align=right>59614</TD></TR>
+ * </TABLE>
+ * <BR><BR>
+ * <TABLE border=1 cellspacing=0 cellpadding=5>
+ * <TR><TD align=center colspan=5>Time Taken with 30,000 records (ms) [hdl]</TD></TR>
+ * <TR><TD>Action</TD><TD>Original</TD><TD>Revision 1</TD><TD>Revision 2</TD><TD>Revision 3</TD></TR>
+ * <TR><TD>Build</TD><TD align=right>DNF</TD><TD align=right>19037</TD><TD align=right>16478</TD><TD align=right>8111</TD></TR>
+ * <TR><TD>Sort</TD><TD align=right>DNF</TD><TD align=right>314</TD><TD align=right>301</TD><TD align=right>385</TD></TR>
+ * <TR><TD>Filter</TD><TD align=right>DNF</TD><TD align=right>[300000]</TD><TD align=right>[300000]</TD><TD align=right>[300000]</TD></TR>
+ * </TABLE><BR><BR>
+ * It is easy to see that while building and sorting have become quite fast and reasonable, sorting is still unacceptable in terms of performance. The difficulty is this, that while sorting is easy (and fast) to implement via the Decorator pattern (making the overall table model a MDVC one) it requires the entire contents of a column to be available. Thus no matter the speed of your sort algorithm you will end up making N calls to getValueAt() in the table data model, for N records. This is not a problem for the initial model, hence the small sort times. However when you attempt to place another deocrator model (or modify the existing one) in order to filter only selected rows, even if the filtering itself takes little time, this little time quickly grows to unacceptable levels. In fact testing has shown it to grow much faster than linear time (though I'm not sure where). Doubling the number of records to filter increases the processing time by 5-7 times.<BR>
+ * In attempting to solve this problem, I have found many resources that mention a similar problem when trying to build visual representations of database tables, especially over networks or other temporally-non-deterministic connections. The common solution is to 'page' only those records necessary into memory on demand, thus making initial response significantly faster, while paying a small price for subsequent page seeks. There are even studies and algorithms for determining pages loads etc, I would imagine garnered from the memory management community. However none of these really help me usless I can get around the problem of having to have the entire columns population immeditaly accessable for sorting purposes.<BR>
+ * I believe with more time is would be possible to make a hybrid table model with properties such as you would require for the aforemenetioned database application, but which also provides fast methods for determining the highest and lowest records perhaps by building traversable heaps in the original model. Such a solution would incur a build penalty, and could consume significant memory, but would provide ordered and sequential access to the data within.<BR>
+ * The discussion aside, I have run out of time to do anything further on this, so will include as is, and provide a warning dialog whenever the number of records might suffer slow processing (1000+ records).
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class MetaAuditFrame
+    extends ModalDialog 
+    implements TreeSelectionListener {
+    public AutofilterDialog autofilter_dialog;
+    /** Whether the selection has changed since the last time we built the model (because it has been hidden and theres no point refreshing a model you can't see!). */
+    private boolean invalid = true;
+    /** An array holding the most recent list of paths selected (plus some nulls for those paths removed). */
+    private CollectionTreeNode records[];
+    /** A reference to ourselves so that inner classes can interact with us. */
+    private MetaAuditFrame self;
+    /** The table in which the metadata is shown. */
+    private MetaAuditTable table;
+    /** The default size for the metaaudit dialog. */
+    static final private Dimension SIZE = new Dimension(640,505);
+
+    /** Constructor.*/
+    public MetaAuditFrame(TreeSynchronizer tree_sync, CollectionTreeNode records[]) {
+	super(Gatherer.g_man);
+
+	// Arguments
+	this.autofilter_dialog = new AutofilterDialog(this);
+	this.records = records;
+	this.self = this;
+	this.table = new MetaAuditTable(this);
+
+	// Creation
+	setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
+	setSize(SIZE);
+	setJMenuBar(new SimpleMenuBar("reviewingmetadata")); 
+	Dictionary.registerText(this, "MetaAudit.Title");
+	JPanel content_pane = (JPanel) getContentPane();
+	JPanel button_pane = new JPanel();
+
+	JButton close_button = new GLIButton();
+	close_button.setMnemonic(KeyEvent.VK_C);
+	Dictionary.registerBoth(close_button, "MetaAudit.Close", "MetaAudit.Close_Tooltip");
+
+	// Connection
+	close_button.addActionListener(new CloseListener());
+	tree_sync.addTreeSelectionListener(this);
+
+	// Layout
+	button_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	button_pane.setLayout(new BorderLayout());
+	button_pane.add(close_button, BorderLayout.CENTER);
+		 
+	content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	content_pane.setLayout(new BorderLayout());
+	content_pane.add(new JScrollPane(table), BorderLayout.CENTER);
+	content_pane.add(button_pane, BorderLayout.SOUTH);
+		  
+	Dimension screen_size = Configuration.screen_size;
+	setLocation((screen_size.width - SIZE.width) / 2, (screen_size.height - SIZE.height) / 2);
+	screen_size = null;
+	close_button = null;
+	button_pane = null;
+	content_pane = null;
+    }
+
+    /** Destructor. */
+    public void destroy() {
+	records = null;
+	self = null;
+	table = null;
+    }
+
+    /** Display the dialog on screen. */
+    public void display() {
+	if(invalid) {
+	    rebuildModel();
+	}
+	setVisible(true);
+    }
+
+    public void setRecords(CollectionTreeNode[] records) {
+	this.records = records;
+	if(isVisible()) {
+	    rebuildModel();
+	}
+	else {
+	    invalid = true;
+	}
+    }
+
+    /** This method is called whenever the selection within the collection tree changes. This causes the table to be rebuilt with a new model.
+     * @param event A <strong>TreeSelectionEvent</strong> containing information about the event.
+     */
+    public void valueChanged(TreeSelectionEvent event) {
+	Object source = event.getSource();
+	if(source instanceof JTree) {
+	    TreePath paths[] = ((JTree)source).getSelectionPaths();
+	    if(paths != null) {
+		records = new CollectionTreeNode[paths.length];
+		for(int i = 0; i < paths.length; i++) {
+		    records[i] = (CollectionTreeNode) paths[i].getLastPathComponent();
+		}
+		if(isVisible()) {
+		    rebuildModel();
+		}
+		else {
+		    invalid = true;
+		}
+	    }
+	}
+    }
+
+    public void wait(boolean waiting) {
+	Component glass_pane = getGlassPane();
+	if(waiting) {
+	    // Show wait cursor.
+	    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 = null;
+    }
+
+    /** Rebuild the metaaudit table model using the current collection tree selection. 
+     */
+    private void rebuildModel() {
+	// Build and set model
+	table.newModel(records);
+	// Done.
+	invalid = false;
+    }
+
+    /** Listens for actions upon the close button, and if detected closes the dialog */
+    private class CloseListener
+	implements ActionListener {
+	/** Any implementation of ActionListener must include this method so that we can be informed when an action has been performed on our target control(s).
+	 * @param event An <strong>ActionEvent</strong> containing information about the event.
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    self.setVisible(false);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditRenderer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditRenderer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditRenderer.java	(revision 10506)
@@ -0,0 +1,63 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui.metaaudit;
+
+import java.awt.*;
+import java.util.ArrayList;
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+
+public class MetaAuditRenderer
+    extends DefaultTableCellRenderer {
+
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean is_selected, boolean has_focus, int row, int column) {
+	ArrayList array = (ArrayList) value;
+	JLabel label = (JLabel) super.getTableCellRendererComponent(table, "", is_selected, has_focus, row, column);
+	JPanel panel = new JPanel();
+	panel.setBackground(label.getBackground());
+	panel.setBorder(label.getBorder());
+	if(array != null) {
+	    panel.setLayout(new GridLayout(array.size(), 1));
+	    for(int i = 0; i < array.size(); i++) {
+		JLabel entry = new JLabel(array.get(i).toString());
+		entry.setFont(label.getFont());
+		panel.add(entry);
+	    }
+	}
+	return panel;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditTable.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditTable.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditTable.java	(revision 10506)
@@ -0,0 +1,198 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui.metaaudit;
+
+import de.qfs.lib.gui.*;
+import java.awt.*;
+import java.util.ArrayList;
+import javax.swing.JTable;
+import javax.swing.event.TableModelEvent;
+import javax.swing.table.*;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+import org.greenstone.gatherer.metadata.MetadataAuditTableModel;
+
+
+/**
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class MetaAuditTable
+    extends JTable 
+    implements TableModelSorterListener {
+
+    private boolean initial_state;
+
+    private Filter filter;
+
+    private HeaderRenderer header_renderer;
+
+    private MetaAuditFrame parent_frame;
+
+    private MetaAuditRenderer cell_renderer;
+
+    private MetadataAuditTableModel metadata_audit_table_model;
+
+    private SortedTableHelper helper;
+
+    static final private int MARGIN = 10;
+
+    public MetaAuditTable(MetaAuditFrame parent_frame) {
+	super();
+	this.cell_renderer = new MetaAuditRenderer();
+	this.header_renderer = new HeaderRenderer();
+	this.parent_frame = parent_frame;
+	getTableHeader().addMouseListener(new HeaderListener(parent_frame, this));
+	setAutoResizeMode(AUTO_RESIZE_OFF);
+    }
+
+    public Filter getFilter() {
+	return filter;
+    }
+
+
+   public MetadataAuditTableModel getOriginalModel()
+   {
+      return metadata_audit_table_model;
+   }
+
+
+    public TableModelSorter getSorter() {
+	return helper.getTableModelSorter();
+    }
+
+    public boolean isFiltered(int column) {
+	if(filter == null) {
+	    return false;
+	}
+	return filter.isFiltered(column);
+    }
+
+    public void newModel(CollectionTreeNode records[]) {
+	if(records == null || records.length == 0) {
+	    setModel(new DefaultTableModel());
+	    return;
+	}
+	wait(true);
+	initial_state = true;
+	// System.err.println("Build new Model - should only be called once per click!");
+	metadata_audit_table_model = new MetadataAuditTableModel();
+	metadata_audit_table_model.rebuild(records);
+	setModel(metadata_audit_table_model);
+	filter = new Filter(metadata_audit_table_model.getColumnCount());
+	helper = new SortedTableHelper (this, filter, new DefaultTableModelSorter(), header_renderer, null);
+	helper.prepareTable();
+	// Add renderer to columns.
+	TableColumnModel column_model = getColumnModel();
+	for(int i = 0; i < column_model.getColumnCount(); i++) {
+	    column_model.getColumn(i).setCellRenderer(cell_renderer);
+	    column_model.getColumn(i).setHeaderRenderer(header_renderer);
+	}
+	wait(false);
+	initial_state = false;
+    }
+
+    public void tableChanged(TableModelEvent e) {
+	wait(true);
+	super.tableChanged(e);
+
+	// Create storage area
+	ArrayList heights[] = new ArrayList[dataModel.getRowCount()];
+	int widths_value[] = new int[dataModel.getColumnCount()];
+	ArrayList widths[] = new ArrayList[dataModel.getColumnCount()];
+
+	// Iterate through cell values finding tallest and widest for each row and column respectively.
+	for (int j = 0; j < dataModel.getRowCount(); j++) {
+	    for (int k = 0; k < dataModel.getColumnCount(); k++) {
+		Object object = dataModel.getValueAt(j, k);
+		if (object instanceof ArrayList) {
+		    ArrayList data = (ArrayList) object;
+		    if (heights[j] == null || data.size() > heights[j].size()) {
+			heights[j] = data;
+		    }
+		    String longest = "";
+		    for (int i = 0; i < data.size(); i++) {
+			String temp = data.get(i).toString();
+			if (temp.length() > longest.length()) {
+			    longest = temp;
+			}
+		    }
+		    if (widths[k] == null || longest.length() > widths_value[k]) {
+			widths_value[k] = longest.length();
+			widths[k] = data;
+		    }
+		}
+	    }
+	}
+
+	// Now assign the dimensions we have determined to be the largest.
+	for (int l = 0; l < heights.length; l++) {
+	    if (heights[l] != null) {
+		Component component = cell_renderer.getTableCellRendererComponent(this, heights[l], false, false, 0, 0);
+		Dimension size = component.getPreferredSize();
+		setRowHeight(l, size.height);
+	    }
+	}
+	for (int m = 0; m < widths.length; m++) {
+	    if (widths[m] != null) {
+		Component component = cell_renderer.getTableCellRendererComponent(this, widths[m], false, false, 0, 0);
+		Dimension size = component.getPreferredSize();
+		int width = size.width + MARGIN;
+		if (width > (2 * parent_frame.getSize().width) / 3) {
+		    width = (2 * parent_frame.getSize().width) / 3;
+		}
+
+		Component header = header_renderer.getTableCellRendererComponent(this, dataModel.getColumnName(m), false, false, 0, 0);
+		if (header.getPreferredSize().width + MARGIN > width) {
+		    width = header.getPreferredSize().width + MARGIN;
+		}
+		columnModel.getColumn(m).setPreferredWidth(width);
+	    }
+	}
+
+	wait(initial_state);
+    }
+
+
+    public void sortOrderChanged(TableModelSorterEvent event) {
+    }
+
+    private void wait(boolean waiting) {
+	if(parent_frame != null) {
+	    parent_frame.wait(waiting);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/tree/DragTree.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/tree/DragTree.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/tree/DragTree.java	(revision 10506)
@@ -0,0 +1,682 @@
+package org.greenstone.gatherer.gui.tree;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.dnd.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.plaf.basic.BasicTreeUI;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.file.FileNode;
+import org.greenstone.gatherer.file.FileSystemModel;
+import org.greenstone.gatherer.util.DragComponent;
+import org.greenstone.gatherer.util.DragGroup;
+import org.greenstone.gatherer.util.DragTreeSelectionModel;
+import org.greenstone.gatherer.util.Utility;
+
+public abstract class DragTree
+    extends JTree
+    implements Autoscroll, DragGestureListener, DragSourceListener, DropTargetListener, DragComponent, TreeSelectionListener {
+    /** The normal background color. */
+    private Color background_color;
+    /** The normal foreground color. */
+    private Color foreground_color;
+    /** The Group this component belongs to. */
+    private DragGroup group;
+    /** The image to use for the disabled background. */
+    private ImageIcon disabled_background;
+    /** The image to use for a normal background. */
+    private ImageIcon normal_background;
+    /** The icon to use for multiple node drag'n'drops. We decided against using the windows paradigm or a block of x horizontal lines for x files. */
+    private ImageIcon multiple_icon = new ImageIcon("resource"+File.separator+"multiple.gif");
+    /** The default drag action, although its not that important as we provide custom icons during drags. */
+    private int drag_action = DnDConstants.ACTION_MOVE;
+    /** The location of the last ghost drawn, so that we can repair the 'spoilt' area. */
+    private Point pt_last = null;
+    /** The region borderer by the lower cue line. */
+    private Rectangle lower_cue_line;
+    /** The region covered by the drag ghost icon. */
+    private Rectangle ra_ghost = new Rectangle();
+    /** The region borderer by the upper cue line. */
+    private Rectangle upper_cue_line;
+    /** The identifying name of this Tree. */
+    private String name;
+    /** The last tree path the drag was hovered over. */
+    private TreePath previous_path = null;
+
+    static private Cursor NO_DRAG_CURSOR = null;
+
+    static private final Color TRANSPARENT_COLOR = new Color(0,0,0,0);
+    /** The distance from the edge of the current view within the scroll bar which if entered causes the view to scroll. */
+    static private final int AUTOSCROLL_MARGIN = 12;
+
+    static public final int TREE_DISPLAY_CHANGED        = 0;
+    static public final int LOADED_COLLECTION_CHANGED   = 1;
+    static public final int COLLECTION_CONTENTS_CHANGED = 2;
+
+
+    public DragTree(String name, TreeModel model, boolean mixed_selection)
+    {
+	super();
+	init(name, mixed_selection);
+	if (model != null) {
+	    setModel(model);
+	}
+    }
+
+    public void init(String name, boolean mixed_selection) {
+	if (NO_DRAG_CURSOR == null) {
+	    NO_DRAG_CURSOR = DragSource.DefaultMoveNoDrop;
+	}
+
+	// Init
+	this.name = name;
+
+	// Creation
+	this.putClientProperty("JTree.lineStyle", "Angled");
+	this.setAutoscrolls(true);
+	this.setEditable(false);
+	this.setLargeModel(true);
+	this.setOpaque(true);
+	this.setSelectionModel(new DragTreeSelectionModel(this, mixed_selection));
+	this.setShowsRootHandles(true);
+	this.setUI(new BasicTreeUI());
+	// Connection
+	addTreeSelectionListener(this);
+
+	DragTreeCellRenderer renderer = new DragTreeCellRenderer();
+	//make the renderer paint nodes as transparent when not selected
+	//renderer.setBackgroundNonSelectionColor(new Color(0,0,0,0));
+	setCellRenderer(renderer);
+	// It turns out VariableHeightLayoutCache is buggy under MacOS, so I'll force it to use FixedHeightLayoutCache. To do that I have to set a cell height, ala below, and set the large model property to true, ala above. And buggy VariableHeightLayoutCache goes away. Plus this actually provides a minor performance boost as the layout manager doesn't have to calculate new bounds each time (well... I suppose any gain is actually pretty much eclipsed by the time taken for file access while we determine what a certain nodes children are).
+	// And once we have the cell renderer, use it to determine a fixed height for the rows
+	Component prototype_row = renderer.getTreeCellRendererComponent(this, "Prototype", true, true, false, 0, true);
+	this.setRowHeight(prototype_row.getSize().height);
+	prototype_row = null;
+
+
+	// Drag'n'drop Setup
+	// Drag source setup.
+	DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(this, drag_action, this);
+	// Drop destination setup.
+	new DropTarget(this, drag_action, this, true);
+    }
+
+    // Autoscroll Interface - Scroll because the mouse cursor is in our scroll zone.<br>
+    // The following code was borrowed from the book:<br>
+    //              Java Swing<br>
+    //              By Robert Eckstein, Marc Loy & Dave Wood<br>
+    //              Paperback - 1221 pages 1 Ed edition (September 1998)<br>
+    //              O'Reilly & Associates; ISBN: 156592455X<br>
+    // The relevant chapter of which can be found at:<br>
+    //              http://www.oreilly.com/catalog/jswing/chapter/dnd.beta.pdf<br>
+    // But I've probably tortured it beyond all recognition anyway.
+    public void autoscroll(Point pt) {
+	// Figure out which row we're on.
+	int row = getRowForLocation(pt.x, pt.y);
+	// If we are not on a row then ignore this autoscroll request
+	if (row < 0) return;
+	Rectangle bounds = getBounds();// Yes, scroll up one row
+	// Now decide if the row is at the top of the screen or at the bottom. We do this to make the previous row (or the next row) visible as appropriate. If we're at the absolute top or bottom, just return the first or last row respectively.
+	// Is row at top of screen?
+	if(pt.y + bounds.y <= AUTOSCROLL_MARGIN) {
+	    // Yes, scroll up one row
+	    if(row <= 0) {
+		row = 0;
+	    }
+	    else {
+		row = row - 1;
+	    }
+	}
+	else {
+	    // No, scroll down one row
+	    if(row < getRowCount() - 1) {
+		row = row + 1;
+	    }
+	}
+	this.scrollRowToVisible(row);
+    }
+
+    /** In order for the appearance to be consistant, given we may be in the situation where the pointer has left our focus but the ghost remains, this method allows other members of the GGroup to tell this component to clear its ghost.
+     */
+    public void clearGhost() {
+	// Erase the last ghost image and cue line
+	paintImmediately(ra_ghost.getBounds());
+    }
+
+    /** Any implementation of DragSourceListener must include this method so we can be notified when the drag event ends (somewhere else), which will in turn remove actions.
+     * @param event A <strong>DragSourceDropEvent</strong> containing all the information about the end of the drag event.
+     */
+    public void dragDropEnd(DragSourceDropEvent event) {
+	if(event.getDropSuccess()) {
+	    // Do whatever I do when the drop is successful.
+	}
+    }
+    /** Any implementation of DragSourceListener must include this method so we can be notified when the drag focus enters this component.
+     * @param event A <strong>DragSourceDragEvent</strong> containing all the information
+     * about the drag event.
+     */
+    public void dragEnter(DragSourceDragEvent event) {
+	// Handled elsewhere.
+    }
+    /** Any implementation of DropTargetListener must include this method so we can be notified when the drag focus enters this component, which in this case is to grab focus from within our group.
+     * @param event A <strong>DropTargetDragEvent</strong> containing all the information about the drag event.
+     */
+    public void dragEnter(DropTargetDragEvent event) {
+	group.grabFocus(this);
+    }
+    /** Any implementation of DragSourceListener must include this method so we can be notified when the drag focus leaves this component.
+     * @param event A <strong>DragSourceEvent</strong> containing all the information about the drag event.
+     */
+    public void dragExit(DragSourceEvent event) {
+	clearGhost();
+    }
+
+    /** Any implementation of DropTargetListener must include this method
+     * so we can be notified when the drag focus leaves this component.
+     * @param event A DropTargetEvent containing all the information
+     * about the drag event.
+     */
+    public void dragExit(DropTargetEvent event) {
+	clearGhost();
+    }
+
+    /** Any implementation of DragGestureListener must include this method
+     * so we can be notified when a drag action has been noticed, thus a
+     * drag action has begun.
+     * @param event A DragGestureEvent containing all the information about
+     * the drag event.
+     */
+    public void dragGestureRecognized(DragGestureEvent event) {
+	// Can never drag from Enrich tree
+	if(name.equals("Enrich")) {
+	    return;
+	}
+	// Disable editing, unless you want to have the edit box pop-up part way through dragging.
+	this.setEditable(false);
+	// We need this to find one of the selected nodes.
+	Point origin = event.getDragOrigin();
+	TreePath path = this.getPathForLocation(origin.x, origin.y);
+	// Taking into account our delayed model of selection, it is possible the user has performed a select and drag in one click. Here we utilize the Windows paradigm like so: If the node at the origin of the drag and drop is already in our selection then we perform multiple drag and drop. Otherwise we recognise that this is a distinct drag-drop and move only the origin node.
+	if(!isPathSelected(path)) {
+	    ((DragTreeSelectionModel)selectionModel).setImmediate(true);
+	    setSelectionPath(path);
+	    ((DragTreeSelectionModel)selectionModel).setImmediate(false);
+	}
+	if(path == null) {
+	    return;
+	}
+	if (!isValidDrag()) {
+	    try {
+		event.startDrag(NO_DRAG_CURSOR, new StringSelection("dummy"), this);
+		//dragging = true;
+	    }
+	    catch(Exception error) {
+		error.printStackTrace();
+	    }
+	    return;
+	}
+	// Now update the selection stored as far as the group is concerned.
+	group.setSelection(getSelectionPaths());
+	group.setSource(this);
+	// First grab ghost.
+	group.grabFocus(this);
+	// Ghost Image stuff.
+	Rectangle rect = this.getPathBounds(path);
+	group.mouse_offset = new Point(origin.x - rect.x, origin.y - rect.y);
+	// Create the ghost image.
+	// Retrieve the selected files.
+	int selection_count = getSelectionCount();
+	if(selection_count > 0) {
+	    JLabel label;
+	    if(selection_count == 1) {
+		TreePath node_path = getSelectionPath();
+		FileNode node = (FileNode) path.getLastPathComponent();
+		label = new JLabel(node.toString(), ((DefaultTreeCellRenderer)getCellRenderer()).getLeafIcon(), JLabel.CENTER);
+	    }
+	    else {
+		String title = getSelectionCount() + Dictionary.get("Tree.Files");
+		label = new JLabel(title, ((DefaultTreeCellRenderer)getCellRenderer()).getClosedIcon(), JLabel.CENTER);
+		title = null;
+	    }
+	    // The layout manager normally does this.
+	    Dimension label_size = label.getPreferredSize();
+	    label.setSize(label_size);
+	    label.setBackground(TRANSPARENT_COLOR);
+	    label.setOpaque(true);
+	    // Get a buffered image of the selection for dragging a ghost image.
+	    group.image_ghost = new BufferedImage(label_size.width, label_size.height, BufferedImage.TYPE_INT_ARGB_PRE);
+	    label_size = null;
+	    // Get a graphics context for this image.
+	    Graphics2D g2 = group.image_ghost.createGraphics();
+	    // Make the image ghostlike
+	    g2.setComposite(AlphaComposite.getInstance (AlphaComposite.SRC, 0.5f));
+	    // Ask the cell renderer to paint itself into the BufferedImage
+	    label.paint(g2);
+	    g2 = null;
+	    label = null;
+	    try {
+		event.startDrag(new Cursor(Cursor.DEFAULT_CURSOR), group.image_ghost, group.mouse_offset, new StringSelection("dummy"), this);
+		//dragging = true;
+	    }
+	    catch(Exception error) {
+		error.printStackTrace();
+	    }
+	}
+
+    }
+
+    /** Implementation side-effect.
+     * @param event A DragSourceDragEvent containing all the information about the drag event.
+     */
+    public void dragOver(DragSourceDragEvent event) {
+    }
+
+    /** Any implementation of DropTargetListener must include this method
+     * so we can be notified when the drag moves in this component.
+     * @param event A DropTargetDragEvent containing all the information
+     * about the drag event.
+     */
+    public void dragOver(DropTargetDragEvent event) {
+	// Draw the mouse ghost
+	Graphics2D g2 = (Graphics2D) getGraphics();
+	Point pt = event.getLocation();
+	if(pt_last != null && pt.equals(pt_last)) {
+	    return;
+	}
+	pt_last = pt;
+	if(!DragSource.isDragImageSupported() && group.image_ghost != null) {
+	    // Erase the last ghost image and cue line
+	    paintImmediately(ra_ghost.getBounds());
+	    // Remember where you are about to draw the new ghost image
+	    ra_ghost.setRect(pt.x - group.mouse_offset.x, pt.y - group.mouse_offset.y, group.image_ghost.getWidth(), group.image_ghost.getHeight());
+	    // Draw the ghost image
+	    g2.drawImage(group.image_ghost, AffineTransform.getTranslateInstance(ra_ghost.getX(), ra_ghost.getY()), null);
+	}
+	// Now we highlight the target node if it is a valid drop target. Of course we don't bother if we are still over a node which has already been identified as to whether its a drop target.
+	TreePath target_path = this.getPathForLocation(pt.x, pt.y);
+	if(previous_path == null || target_path != null && !target_path.equals(previous_path)) {
+	    // Immediately clear the old cue lines.
+	    if(upper_cue_line != null && lower_cue_line != null) {
+		paintImmediately(upper_cue_line.getBounds());
+		paintImmediately(lower_cue_line.getBounds());
+	    }
+	    if(isValidDrop(target_path)) {
+		///ystem.err.println("Valid. Painting cues.");
+		// Get the drop target's bounding rectangle
+		Rectangle raPath = getPathBounds(target_path);
+		// Cue line bounds (2 pixels beneath the drop target)
+		upper_cue_line = new Rectangle(0,  raPath.y + (int)raPath.getHeight(), getWidth(), 2);
+		lower_cue_line = new Rectangle(0,  raPath.y, getWidth(), 2);
+		g2.setColor(((DefaultTreeCellRenderer)cellRenderer).getBackgroundSelectionColor()); // The cue line color
+		g2.fill(upper_cue_line);         // Draw the cue line
+		g2.fill(lower_cue_line);
+	    }
+	    else {
+		upper_cue_line = null;
+		lower_cue_line = null;
+	    }
+	}
+    }
+
+    /** Any implementation of DropTargetListener must include this method
+	  * so we can be notified when the drag ends, ie the transferable is
+	  * dropped.
+	  * @param event A DropTargetDropEvent containing all the information
+	  * about the end of the drag event.
+	  */
+    public void drop(DropTargetDropEvent event) {
+	///start = System.currentTimeMillis();
+	///ystem.err.println("Drop target drop: " + this);
+	event.acceptDrop(drag_action);
+	if(!name.equals(Utility.WORKSPACE_TREE)) {
+	    // Determine what node we dropped over.
+	    Point pt = event.getLocation();
+	    TreePath target_path = this.getPathForLocation(pt.x, pt.y);
+	    FileNode target = null;
+	    if(target_path != null) {
+		if(isValidDrop(target_path)) {
+		    target = (FileNode) target_path.getLastPathComponent();
+		} else if (isValidDropOntoFile(target_path)) {
+		    target = (FileNode) target_path.getParentPath().getLastPathComponent();
+		}
+	    }
+	    else {
+		TreeModel m = getModel();
+		// check that we have a model and is a FileSystemModel (ie check that a collection is loaded
+		if (m != null && m instanceof FileSystemModel) {
+		    target = (FileNode) m.getRoot();
+		}
+	    }
+	    target_path = null;
+	    pt = null;
+	    if(target != null) {
+		///ystem.err.println("Valid drop.");
+		TreePath[] selection = group.getSelection();
+		if(target != null && selection != null) {
+		    FileNode[] source_nodes = new FileNode[selection.length];
+		    for(int i = 0; i < source_nodes.length; i++) {
+			source_nodes[i] = (FileNode) selection[i].getLastPathComponent();
+		    }
+		    Gatherer.f_man.action(group.getSource(), source_nodes, this, target);
+		    source_nodes = null;
+		}
+		group.setSelection(null);
+		group.setSource(null);
+		selection = null;
+		target = null;
+	    }
+	}
+	// Clear up the group.image_ghost
+	paintImmediately(ra_ghost.getBounds());
+	event.getDropTargetContext().dropComplete(true);
+	group.image_ghost = null;
+    }
+
+
+    /** Any implementation of DragSourceListener must include this method
+     * so we can be notified when the action to be taken upon drop changes.
+     * @param event A DragSourceDragEvent containing all the information
+     * about the drag event.
+     */
+    public void dropActionChanged(DragSourceDragEvent event) {
+    }
+
+    /** Any implementation of DropTargetListener must include this method
+     * so we can be notified when the action to be taken upon drop changes.
+     * @param event A DropTargetDragEvent containing all the information
+     * about the drag event.
+     */
+    public void dropActionChanged(DropTargetDragEvent event) {
+    }
+
+    /** Used to notify this component that it has gained focus. It should
+     * make some effort to inform the user of this.
+     */
+    public void gainFocus() {
+	///ystem.err.println("Gained focus: " + this);
+	((DragTreeCellRenderer)cellRenderer).gainFocus();
+	repaint();
+    }
+
+    /** Autoscroll Interface...
+     * The following code was borrowed from the book:
+     *              Java Swing
+     *              By Robert Eckstein, Marc Loy & Dave Wood
+     *              Paperback - 1221 pages 1 Ed edition (September 1998)
+     *              O'Reilly & Associates; ISBN: 156592455X
+     *
+     * The relevant chapter of which can be found at:
+     *              http://www.oreilly.com/catalog/jswing/chapter/dnd.beta.pdf
+     * Calculate the insets for the *JTREE*, not the viewport
+     * the tree is in. This makes it a bit messy.
+     */
+    public Insets getAutoscrollInsets()
+    {
+	Rectangle raOuter = this.getBounds();
+	Rectangle raInner = this.getParent().getBounds();
+	return new Insets(raInner.y - raOuter.y + AUTOSCROLL_MARGIN,
+			  raInner.x - raOuter.x + AUTOSCROLL_MARGIN,
+			  raOuter.height - raInner.height - raInner.y + raOuter.y + AUTOSCROLL_MARGIN,
+			  raOuter.width - raInner.width - raInner.x + raOuter.x + AUTOSCROLL_MARGIN);
+    }
+
+    public String getSelectionDetails() {
+	return ((DragTreeSelectionModel)selectionModel).getDetails();
+    }
+
+    public FileSystemModel getTreeModel() {
+	return (FileSystemModel) getModel();
+    }
+
+    /** This method is used to inform this component when it loses focus,
+     * and should indicate this somehow.
+     */
+    public void loseFocus() {
+	///ystem.err.println("Lost focus: " + this);
+	((DragTreeCellRenderer)cellRenderer).loseFocus();
+	repaint();
+    }
+
+
+    public void paint(Graphics g) {
+	if(disabled_background != null) {
+	    int height = getSize().height;
+	    int offset = 0;
+	    ImageIcon background;
+	    if(isEnabled()) {
+		background = normal_background;
+	    }
+	    else {
+		background = disabled_background;
+	    }
+	    while((height - offset) > 0) {
+		g.drawImage(background.getImage(), 0, offset, null);
+		offset = offset + background.getIconHeight();
+	    }
+	    background = null;
+	}
+	super.paint(g);
+    }
+
+    public void refresh(TreePath path) {
+	if (treeModel instanceof FileSystemModel) {
+	    ((FileSystemModel)treeModel).refresh(path);
+	}
+	else {
+	    // System.err.println("DragTree::refresh - Tree model is " + treeModel);
+	}
+    }
+
+    public void setBackgroundNonSelectionColor(Color color) {
+	background_color = color;
+	if(isEnabled()) {
+	    setBackground(color);
+	    ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(color);
+	}
+	else {
+	    setBackground(Color.lightGray);
+	    ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(Color.lightGray);
+	}
+	repaint();
+    }
+
+    public void setBackgroundSelectionColor(Color color) {
+	((DefaultTreeCellRenderer)cellRenderer).setBackgroundSelectionColor(color);
+	repaint();
+    }
+
+    /** Override the normal setEnabled so the Tree exhibits a little more
+     * change, which in this instance is the background colour changing.
+     * @param state Whether this GTree should be in an enabled state.
+     */
+    public void setEnabled(boolean state) {
+	super.setEnabled(state);
+
+	// Change some colors
+	if(state) {
+	    setBackground(background_color);
+	    ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(background_color);
+	    ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(foreground_color);
+	}
+	else {
+	    setBackground(Color.lightGray);
+	    ((DefaultTreeCellRenderer)cellRenderer).setBackgroundNonSelectionColor(Color.lightGray);
+	    ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(Color.black);
+	}
+	repaint();
+    }
+
+    public void setGroup(DragGroup group) {
+	this.group = group;
+    }
+
+    /** Determines whether the following selection attempts should go through the normal delayed selection model, or should happen immediately.*/
+    public void setImmediate(boolean state) {
+	((DragTreeSelectionModel)selectionModel).setImmediate(state);
+    }
+
+    public void setModel(TreeModel model) {
+	super.setModel(model);
+	if(model instanceof FileSystemModel) {
+	    FileSystemModel file_system_model = (FileSystemModel) model;
+	    file_system_model.setTree(this);
+	    removeTreeExpansionListener(file_system_model);
+	    addTreeExpansionListener(file_system_model);
+	    removeTreeWillExpandListener(file_system_model);
+	    addTreeWillExpandListener(file_system_model);
+	    file_system_model = null;
+	}
+    }
+
+    /** Ensure that that file node denoted by the given file is selected. */
+    public void setSelection(File file) {
+	// We know the file exists, and thus that it must exists somewhere in our tree hierarchy.
+	// 1. Retrieve the root node of our tree.
+	FileNode current = (FileNode) getModel().getRoot();
+	// 2. Find that node in the file parents, keeping track of each intermediate file.
+	ArrayList files = new ArrayList();
+	while(file != null && !current.toString().equals(file.getName())) {
+	    files.add(0, file);
+	    file = file.getParentFile();
+	}
+	if(file == null) {
+	    return;
+	}
+	// 3. While there are still remaining intermediate files.
+	while(files.size() > 0) {
+	    file = (File) files.remove(0);
+				// 3a. Find the next file in the current nodes children.
+	    boolean found = false;
+	    current.map();
+	    for(int i = 0; !found && i < current.getChildCount(); i++) {
+		FileNode child = (FileNode) current.getChildAt(i);
+		if(child.toString().equals(file.getName())) {
+		    // 3b. Make the current node this node (if found) and continue.
+		    found = true;
+		    current = child;
+		}
+	    }
+	    // 3c. If not found then return as this node can't exists somehow.
+	    if(!found) {
+		return;
+	    }
+	}
+	// 4. We should now have the desired node. Remember to make the selection immediate.
+	TreePath path = new TreePath(current.getPath());
+	setImmediate(true);
+	setSelectionPath(path);
+	setImmediate(false);
+    }
+
+    public void setTextNonSelectionColor(Color color) {
+	foreground_color = color;
+	if(isEnabled()) {
+	    ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(color);
+	}
+	else {
+	    ((DefaultTreeCellRenderer)cellRenderer).setTextNonSelectionColor(Color.black);
+	}
+	repaint();
+    }
+
+    public void setTextSelectionColor(Color color) {
+	((DefaultTreeCellRenderer)cellRenderer).setTextSelectionColor(color);
+	repaint();
+    }
+
+    public String toString() {
+	return name;
+    }
+
+    public void valueChanged(TreeSelectionEvent event) {
+	if(group == null) {
+	    ///ystem.err.println("Oh my god, this tree has no group: " + this);
+	}
+	else {
+	    group.grabFocus(this);
+	}
+    }
+
+    /** returns false for dummy nodes (ones without files), and system root
+     * nodes */
+    private boolean isValidDrag() {
+	//because you cant select nodes that are children of another selection, and we use a contiguous selection model, we just test the first selection path
+	TreePath node_path = getSelectionPath();
+	FileNode node = (FileNode) node_path.getLastPathComponent();
+
+	if (node.getFile() == null) {
+	    return false;
+	}
+	if (node.isFileSystemRoot()) {
+	    return false;
+	}
+	// We also don't allow the user to select files that reside within the currently loaded collection
+	TreePath[] paths = getSelectionPaths();
+	for(int i = 0; i < paths.length; i++) {
+	    FileNode child = (FileNode) paths[i].getLastPathComponent();
+	    if (child.isInLoadedCollection()) {
+		return false;
+	    }
+	}
+	return true;
+    }
+
+    private boolean isValidDropOntoFile(TreePath target_path) {
+	boolean valid = false;
+	if(target_path != null) {
+	    FileNode target_node = (FileNode) target_path.getLastPathComponent();
+	    if (target_node.isLeaf()) {
+		// check the parent node for being a valid drop
+		return isValidDrop(target_path.getParentPath());
+	    }
+	}
+	return false;
+    }
+
+		
+    private boolean isValidDrop(TreePath target_path) {
+	boolean valid = false;
+	if(target_path != null) {
+	    FileNode target_node = (FileNode) target_path.getLastPathComponent();
+	    // We can only continue testing if the node is a folder.
+	    if(!target_node.isLeaf()) {
+		// Now we check if the node is readonly.
+		if(!target_node.isReadOnly()) {
+		    // Finally we check the target path against the paths in the selection to ensure we are not adding to our own ancestors!
+		    TreePath[] selection = group.getSelection();
+		    boolean failed = false;
+		    for(int i = 0; !failed && selection != null && i < selection.length; i++) {
+			failed = selection[i].isDescendant(target_path);
+		    }
+		    // Having finally completed all the tests, we can highlight the drop target.
+		    if(!failed) {
+			valid = true;
+		    }
+		    else {
+			///ystem.err.println("Invalid. Target is descendant of itself.");
+		    }
+		}
+		else {
+		    ///ystem.err.println("Read only.");
+		}
+	    }
+	    else {
+		///ystem.err.println("Leaf node. Children not allowed.");
+	    }
+	    previous_path = target_path;
+	}
+	else {
+	    if(target_path == null) {
+		previous_path = null;
+	    }
+	}
+	return valid;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/tree/DragTreeCellRenderer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/tree/DragTreeCellRenderer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/gui/tree/DragTreeCellRenderer.java	(revision 10506)
@@ -0,0 +1,89 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.gui.tree;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.file.FileNode;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+public class DragTreeCellRenderer
+    extends DefaultTreeCellRenderer
+{
+    private Color selection_background;
+    private Color selection_foreground;
+
+    public DragTreeCellRenderer() {
+	super();
+	// Have to wait until this image is loaded
+	selection_background = getBackgroundSelectionColor();
+	selection_foreground = getTextSelectionColor();
+    }
+
+    public void gainFocus() {
+	setBackgroundSelectionColor(selection_background);
+	setTextSelectionColor(selection_foreground);
+    }
+
+    /** Configures the renderer based on the passed in components. */
+    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus)
+    {
+	// Rendering FileNodes
+	if (value instanceof FileNode) {
+	    FileNode node = (FileNode) value;
+	    String node_text = node.toString();
+
+	    // Add file sizes if necessary
+	    if (Configuration.get("general.show_file_size", Configuration.COLLECTION_SPECIFIC) && node.getFile() != null && !node.getAllowsChildren()) {
+		node_text = node_text + StaticStrings.SPACE_CHARACTER + StaticStrings.LBRACKET_CHARACTER + Utility.formatFileLength(node.getFile().length()) + StaticStrings.RBRACKET_CHARACTER;
+	    }
+
+	    return (JLabel) super.getTreeCellRendererComponent(tree, node_text, sel, expanded, leaf, row, hasFocus);
+	}
+
+	// Use default renderer for anything else
+	return (JLabel) super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
+    }
+
+    public void loseFocus() {
+	setBackgroundSelectionColor(Color.lightGray);
+	setTextSelectionColor(Color.black);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/DocXMLFile.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/DocXMLFile.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/DocXMLFile.java	(revision 10506)
@@ -0,0 +1,275 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.util.Utility;
+
+
+/** This class represents one doc.xml file */
+public class DocXMLFile
+    extends File
+{
+    private HashMap source_file_name_to_description_elements_mapping = new HashMap();
+
+
+    public DocXMLFile(String doc_xml_file_path)
+    {
+	super(doc_xml_file_path);
+    }
+
+
+    public ArrayList getMetadataExtractedFromFile(File file)
+    {
+	// Build up a list of metadata extracted from this file
+	ArrayList metadata_values = new ArrayList();
+
+	String file_relative_path = file.getAbsolutePath();
+	int import_index = file_relative_path.indexOf("import");
+	if (import_index != -1) {
+	    file_relative_path = file_relative_path.substring(import_index + "import".length() + 1);
+	}
+
+	// Check whether this doc.xml file contains extracted metadata for the specified file
+	ArrayList description_elements_list = (ArrayList) source_file_name_to_description_elements_mapping.get(file_relative_path);
+	if (description_elements_list == null) {
+	    // ...it doesn't
+	    return metadata_values;
+	}
+
+ 	MetadataSet extracted_metadata_set = MetadataSetManager.getMetadataSet(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE);
+
+	// Parse the doc.xml file
+	DebugStream.println("Applicable doc.xml file: " + this);
+	try {
+	    BufferedReader buffered_reader = new BufferedReader(new FileReader(this));
+
+	    int description_element_num = 0;
+	    int next_description_element_start = ((Integer) description_elements_list.get(description_element_num)).intValue();
+	    boolean in_relevant_description_element = false;
+
+	    String line = null;
+	    for (int line_num = 0; (line = buffered_reader.readLine()) != null; line_num++) {
+		// Check if this line contains the start of a relevant Description element
+		if (line_num == next_description_element_start) {
+		    in_relevant_description_element = true;
+		    continue;
+		}
+
+		// If we're not in a relevant Description element we don't care about anything
+		if (in_relevant_description_element == false) {
+		    continue;
+		}
+
+		// Check if this line contains the end of the relevant Description element
+		if (line.indexOf("</Description>") != -1) {
+		    description_element_num++;
+		    if (description_element_num == description_elements_list.size()) {
+			break;
+		    }
+
+		    next_description_element_start = ((Integer) description_elements_list.get(description_element_num)).intValue();
+		    in_relevant_description_element = false;
+		    continue;
+		}
+
+		// If this line doesn't contain a complete Metadata element, we're not interested
+		if (line.indexOf("<Metadata ") == -1 || line.indexOf("</Metadata>") == -1) {
+		    continue;
+		}
+
+		// Extract the metadata element name
+		int name_index = line.indexOf(" name=\"") + " name=\"".length();
+		String metadata_element_name_full = line.substring(name_index, line.indexOf("\"", name_index));
+
+		// If the metadata has a namespace it isn't extracted metadata, so we're not interested
+		String metadata_set_namespace = MetadataTools.getMetadataSetNamespace(metadata_element_name_full);
+		if (!metadata_set_namespace.equals("")) {
+		    continue;
+		}
+
+		// Extracted metadata!
+		String metadata_element_name = metadata_element_name_full;
+
+		// We completely ignore bibliographic data
+		if (metadata_element_name.equals("SourceSegment")) {
+		    return new ArrayList();
+		}
+
+		// Ignore lower-case metadata elements (gsdlsourcefilename, gsdlassocfile etc.)
+		//   and those starting with '/' (/srclink)
+		char first_character = metadata_element_name.charAt(0);
+		if (Character.isLowerCase(first_character) || first_character == '/') {
+		    continue;
+		}
+
+		MetadataElement metadata_element = extracted_metadata_set.getMetadataElementWithName(metadata_element_name);
+
+		// Value trees are not stored for extracted metadata, so create a new value tree node now
+		int value_index = line.indexOf(">", name_index) + ">".length();
+		String metadata_element_value = line.substring(value_index, line.lastIndexOf("</Metadata>"));
+
+		metadata_element.addMetadataValue(metadata_element_value);
+		MetadataValueTreeNode metadata_value_tree_node = metadata_element.getMetadataValueTreeNode(metadata_element_value);
+
+		// Add the new metadata value to the list
+		MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node);
+		metadata_values.add(metadata_value);
+	    }
+	}
+	catch (Exception ex) {
+	    System.err.println("Exception: " + ex);
+	    ex.printStackTrace();
+	}
+
+	return metadata_values;
+    }
+
+
+    /**
+     * Every doc.xml file must be skimmed when a collection is opened, for two reasons:
+     *   - To build a mapping from source file to its corresponding doc.xml file
+     *   - To get a complete list of all extracted metadata elements
+     */
+    public void skimFile()
+    {
+	MetadataSet extracted_metadata_set = MetadataSetManager.getMetadataSet(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE);
+
+	// Skim the doc.xml file as quickly as possible (don't parse as XML), looking at the Metadata elements
+	DebugStream.println("Skimming doc.xml file " + this + "...");
+	try {
+	    BufferedReader buffered_reader = new BufferedReader(new FileReader(this));
+	    int description_element_start = -1;
+
+	    String line = null;
+	    for (int line_num = 0; (line = buffered_reader.readLine()) != null; line_num++) {
+		// This line contains the start of a Description element
+		if (line.indexOf("<Description>") != -1) {
+		    if (description_element_start != -1) {
+			System.err.println("Parse error: previous Description element unfinished!");
+		    }
+		    description_element_start = line_num;
+		    continue;
+		}
+
+		// This line contains the end of a Description element
+		if (line.indexOf("</Description>") != -1) {
+		    if (description_element_start == -1) {
+			System.err.println("Parse error: Description element unstarted!");
+		    }
+		    description_element_start = -1;
+		    continue;
+		}
+
+		// If we're not in a Description element there shouldn't be any Metadata elements
+		if (description_element_start == -1) {
+		    continue;
+		}
+
+		// This line doesn't contain a Metadata element, so we're not interested
+		if (line.indexOf("<Metadata ") == -1) {
+		    DebugStream.println("Warning: Description element line doesn't contain Metadata element.");
+		    continue;
+		}
+
+		// Extract the metadata element name
+		int name_index = line.indexOf(" name=\"") + " name=\"".length();
+		String metadata_element_name_full = line.substring(name_index, line.indexOf("\"", name_index));
+
+		// If the metadata has a namespace it isn't extracted metadata, so we're not interested
+		String metadata_set_namespace = MetadataTools.getMetadataSetNamespace(metadata_element_name_full);
+		if (!metadata_set_namespace.equals("")) {
+		    continue;
+		}
+
+		// Extracted metadata!
+		String metadata_element_name = metadata_element_name_full;
+
+		// Note which file this doc.xml is for
+		if (metadata_element_name.equals("gsdlsourcefilename")) {
+		    // Extract the gsdlsourcefilename element value
+		    int value_index = line.indexOf(">", name_index) + ">".length();
+		    String gsdlsourcefilename_value = line.substring(value_index, line.indexOf("<", value_index));
+
+		    // We're only interested in the path relative to the import folder
+		    int import_index = gsdlsourcefilename_value.indexOf("import");
+		    if (import_index != -1) {
+			gsdlsourcefilename_value = gsdlsourcefilename_value.substring(import_index + "import".length());
+
+			boolean is_unix_path = gsdlsourcefilename_value.startsWith("/");
+			gsdlsourcefilename_value = gsdlsourcefilename_value.substring(1);
+
+			// Make sure the path matches the OS that is running
+			if (is_unix_path && Utility.isWindows()) {
+			    // Convert path from Unix to Windows
+			    gsdlsourcefilename_value = gsdlsourcefilename_value.replaceAll("\\/", "\\\\");
+			}
+			else if (!is_unix_path && !Utility.isWindows()) {
+			    // Convert path from Windows to Unix
+			    gsdlsourcefilename_value = gsdlsourcefilename_value.replaceAll("\\\\", "/");
+			}
+
+			// Remember this for quick access later
+			if (source_file_name_to_description_elements_mapping.get(gsdlsourcefilename_value) == null) {
+			    source_file_name_to_description_elements_mapping.put(gsdlsourcefilename_value, new ArrayList());
+			}
+
+			((ArrayList) source_file_name_to_description_elements_mapping.get(gsdlsourcefilename_value)).add(new Integer(description_element_start));
+		    }
+
+		    // Warn about an odd gsdlsourcefilename, except if it is the Greenstone "tmp" directory
+		    // This is true when the source files come from a zip file processed by ZIPPlug, for example
+		    else if (gsdlsourcefilename_value.indexOf("tmp") == -1) {
+			// We don't really know what is going on...
+			System.err.println("Warning: Could not understand gsdlsourcefilename " + gsdlsourcefilename_value);
+		    }
+		}
+
+		// Ignore lower-case metadata elements (gsdlsourcefilename, gsdlassocfile etc.)
+		//   and those starting with '/' (/srclink)
+		char first_character = metadata_element_name.charAt(0);
+		if (Character.isLowerCase(first_character) || first_character == '/') {
+		    continue;
+		}
+
+		MetadataElement metadata_element = extracted_metadata_set.getMetadataElementWithName(metadata_element_name);
+		if (metadata_element == null) {
+		    // This element isn't defined in ex.mds, so create it for this session
+		    DebugStream.println("Extracted metadata element not defined: " + metadata_element_name);
+		    extracted_metadata_set.addMetadataElementForThisSession(metadata_element_name);
+		}
+	    }
+	}
+	catch (Exception ex) {
+	    System.err.println("Exception: " + ex);
+	    ex.printStackTrace();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/DocXMLFileManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/DocXMLFileManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/DocXMLFileManager.java	(revision 10506)
@@ -0,0 +1,88 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.io.*;
+import java.util.*;
+
+
+/** This class is a static class that manages the doc.xml files */
+public class DocXMLFileManager
+{
+    static private ArrayList doc_xml_files = new ArrayList();
+
+
+    static public void clearDocXMLFiles()
+    {
+	doc_xml_files.clear();
+    }
+
+
+    static public ArrayList getMetadataExtractedFromFile(File file)
+    {
+	// Build up a list of metadata values extracted from this file
+	ArrayList metadata_values = new ArrayList();
+
+	// Look at each loaded doc.xml file to see if any have extracted metadata for this file
+	for (int i = 0; i < doc_xml_files.size(); i++) {
+	    DocXMLFile doc_xml_file = (DocXMLFile) doc_xml_files.get(i);
+	    metadata_values.addAll(doc_xml_file.getMetadataExtractedFromFile(file));
+	}
+
+	return metadata_values;
+    }
+
+
+    static public void loadDocXMLFiles(File directory)
+    {
+	// Make sure the directory (archives) exists
+	if (directory.exists() == false) {
+	    return;
+	}
+
+	// Look recursively at each subfile of the directory for doc.xml files
+	File[] directory_files = directory.listFiles();
+	for (int i = 0; i < directory_files.length; i++) {
+	    File child_file = directory_files[i];
+	    if (child_file.isDirectory()) {
+		loadDocXMLFiles(child_file);
+	    }
+	    else if (child_file.getName().equals("doc.xml")) {
+		loadDocXMLFile(child_file);
+	    }
+	}
+    }
+
+
+    static private void loadDocXMLFile(File doc_xml_file_file)
+    {
+	DocXMLFile doc_xml_file = new DocXMLFile(doc_xml_file_file.getAbsolutePath());
+	doc_xml_file.skimFile();
+	doc_xml_files.add(doc_xml_file);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataAuditTableModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataAuditTableModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataAuditTableModel.java	(revision 10506)
@@ -0,0 +1,237 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+
+
+public class MetadataAuditTableModel
+    extends AbstractTableModel
+{
+    /** The CollectionTreeNodes this model is built for */
+    private CollectionTreeNode[] file_nodes = null;
+    /** The list of MetadataElements in the table (columns) */
+    private ArrayList metadata_elements = new ArrayList();
+    /** The list of MetadataAuditTableEntries in the table (rows) */
+    private ArrayList metadata_audit_table_entries = new ArrayList();
+
+
+    /** Returns the number of columns in this table. */
+    public int getColumnCount()
+    {
+	return 1 + metadata_elements.size();
+    }
+
+
+    /** Returns the name of the specified column. */
+    public String getColumnName(int col)
+    {
+	// First column: filename
+	if (col == 0) {
+	    return Dictionary.get("AuditTable.File");
+	}
+
+	int metadata_element_index = col - 1;
+	return metadata_elements.get(metadata_element_index).toString();
+    }
+
+
+    /** Returns the values in a particular column. */
+    public ArrayList getColumnValues(int col)
+    {
+	// First column: filename
+	if (col == 0) {
+	    ArrayList column_values = new ArrayList();
+	    for (int i = 0; i < metadata_audit_table_entries.size(); i++) {
+		MetadataAuditTableEntry metadata_audit_table_entry = (MetadataAuditTableEntry) metadata_audit_table_entries.get(i);
+		column_values.add(metadata_audit_table_entry.getFilename());
+	    }
+
+	    return column_values;
+	}
+
+	// Check values are reasonable
+	int metadata_element_index = col - 1;
+	if (metadata_element_index < 0 || metadata_element_index >= metadata_elements.size()) {
+	    return null;
+	}
+
+	ArrayList column_values = new ArrayList();
+	for (int i = 0; i < metadata_audit_table_entries.size(); i++) {
+	    MetadataAuditTableEntry metadata_audit_table_entry = (MetadataAuditTableEntry) metadata_audit_table_entries.get(i);
+	    MetadataValueTreeNode[] metadata_value_tree_nodes = metadata_audit_table_entry.getMetadataValueTreeNodes(metadata_element_index);
+	    if (metadata_value_tree_nodes != null) {
+		for (int j = 0; j < metadata_value_tree_nodes.length; j++) {
+		    column_values.add(metadata_value_tree_nodes[j].toString());
+		}
+	    }
+	}
+
+	return column_values;
+    }
+
+
+    /** Returns the number of rows in this table. */
+    public int getRowCount()
+    {
+	return metadata_audit_table_entries.size();
+    }
+
+
+    /** Returns the cell value at a given row and column as an Object. */
+    public Object getValueAt(int row, int col)
+    {
+	// Check values are reasonable
+	if (row < 0 || row >= metadata_audit_table_entries.size()) {
+	    return null;
+	}
+
+	// First column: filename
+	if (col == 0) {
+	    ArrayList cell_values = new ArrayList();
+	    cell_values.add(((MetadataAuditTableEntry) metadata_audit_table_entries.get(row)).getFilename());
+	    return cell_values;
+	}
+
+	// Check values are reasonable
+	int metadata_element_index = col - 1;
+	if (metadata_element_index < 0 || metadata_element_index >= metadata_elements.size()) {
+	    return null;
+	}
+
+	ArrayList cell_values = new ArrayList();
+	MetadataAuditTableEntry metadata_audit_table_entry = (MetadataAuditTableEntry) metadata_audit_table_entries.get(row);
+	MetadataValueTreeNode[] metadata_value_tree_nodes = metadata_audit_table_entry.getMetadataValueTreeNodes(metadata_element_index);
+	if (metadata_value_tree_nodes != null) {
+	    for (int j = 0; j < metadata_value_tree_nodes.length; j++) {
+		cell_values.add(metadata_value_tree_nodes[j].toString());
+	    }
+	}
+
+	return cell_values;
+    }
+
+
+    public void rebuild(CollectionTreeNode[] file_nodes)
+    {
+	metadata_elements = MetadataSetManager.getEveryMetadataSetElement();
+	metadata_audit_table_entries.clear();
+
+	this.file_nodes = file_nodes;
+	if (file_nodes != null && file_nodes.length > 0) {
+	    // Create model builder
+	    MetadataAuditTableModelBuilder builder = new MetadataAuditTableModelBuilder();
+	    builder.run();
+	}
+    }
+
+
+    private class MetadataAuditTableModelBuilder
+    {
+	// Build a list of MetadataAuditTableEntries that represent the metadata asssigned to the selected files
+	public void run()
+	{
+	    // Process each of the selected files in turn
+	    for (int i = 0; i < file_nodes.length; i++) {
+		File current_file = file_nodes[i].getFile();
+
+		// Get the metadata assigned to this file
+		ArrayList current_file_metadata = MetadataXMLFileManager.getMetadataAssignedToFile(current_file);
+
+		// Get the extracted metadata for this file, if desired
+		if (Configuration.get("general.view_extracted_metadata", Configuration.COLLECTION_SPECIFIC) == true) {
+		    current_file_metadata.addAll(DocXMLFileManager.getMetadataExtractedFromFile(current_file));
+		}
+
+		MetadataAuditTableEntry metadata_audit_table_entry = new MetadataAuditTableEntry(current_file, current_file_metadata);
+		metadata_audit_table_entries.add(metadata_audit_table_entry);
+	    }
+	}
+    }
+
+
+    /** This class represents one (file, metadata) pair */
+    private class MetadataAuditTableEntry
+    {
+	private File file = null;
+	private ArrayList[] metadata_values = null;
+
+
+	public MetadataAuditTableEntry(File file, ArrayList metadata_values_list)
+	{
+	    this.file = file;
+
+	    metadata_values = new ArrayList[metadata_elements.size()];
+	    for (int i = 0; i < metadata_values.length; i++) {
+		metadata_values[i] = new ArrayList();
+	    }
+
+	    for (int i = 0; i < metadata_values_list.size(); i++) {
+		MetadataValue metadata_value = (MetadataValue) metadata_values_list.get(i);
+		MetadataElement metadata_element = metadata_value.getMetadataElement();
+
+		// Find the right column to put the value in
+		for (int j = 0; j < metadata_elements.size(); j++) {
+		    if (metadata_element.equals(metadata_elements.get(j))) {
+			metadata_values[j].add(metadata_value);
+			break;
+		    }
+		}
+	    }
+	}
+
+
+	public String getFilename()
+	{
+	    return file.getName();
+	}
+
+
+ 	public MetadataValueTreeNode[] getMetadataValueTreeNodes(int metadata_element_index)
+ 	{
+	    ArrayList metadata_values_list = metadata_values[metadata_element_index];
+ 	    if (metadata_values_list == null) {
+ 		return null;
+ 	    }
+
+	    MetadataValueTreeNode[] metadata_value_tree_nodes = new MetadataValueTreeNode[metadata_values_list.size()];
+	    for (int i = 0; i < metadata_values_list.size(); i++) {
+		metadata_value_tree_nodes[i] = ((MetadataValue) metadata_values_list.get(i)).getMetadataValueTreeNode();
+	    }
+
+ 	    return metadata_value_tree_nodes;
+ 	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataChangedListener.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataChangedListener.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataChangedListener.java	(revision 10506)
@@ -0,0 +1,37 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer.metadata;
+
+
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+
+
+public interface MetadataChangedListener
+{
+    /** Notification that the metadata assigned to the collection has changed. */
+    public void metadataChanged(CollectionTreeNode[] file_nodes);
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataElement.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataElement.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataElement.java	(revision 10506)
@@ -0,0 +1,184 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.io.File;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+
+/** This class represents one Metadata element */
+public class MetadataElement
+{
+    // Language-independent metadata element name, with namespace (eg. dc.Subject)
+    private String metadata_element_name_full = null;
+    private Element metadata_element_element = null;
+    private MetadataValueTreeModel metadata_value_tree_model = null;
+
+
+    public MetadataElement(String metadata_element_name_full, Element metadata_element_element)
+    {
+	this.metadata_element_name_full = metadata_element_name_full;
+	this.metadata_element_element = metadata_element_element;
+	this.metadata_value_tree_model = new MetadataValueTreeModel(this);
+    }
+
+
+    public MetadataValueTreeNode addMetadataValue(String metadata_value)
+    {
+	return metadata_value_tree_model.addMetadataValue(metadata_value);
+    }
+
+
+    public String getAttribute(String attribute_name, String language_code)
+    {
+	// Some extracted metadata elements may not be in ex.mds, and so have no attributes
+	if (metadata_element_element == null) {
+	    return null;
+	}
+
+	Element parent_element = metadata_element_element;
+	boolean language_matches = false;
+
+	NodeList language_elements_nodelist = metadata_element_element.getElementsByTagName("Language");
+	for (int i = 0; i < language_elements_nodelist.getLength(); i++) {
+	    Element current_language_element = (Element) language_elements_nodelist.item(i);
+	    String current_language_element_code = current_language_element.getAttribute("code");
+	    if (current_language_element_code.equals(language_code)) {
+		// Found language; use it for the next step
+		parent_element = current_language_element;
+		language_matches = true;
+		break;
+	    }
+	}
+
+	NodeList attribute_elements_nodelist = parent_element.getElementsByTagName("Attribute");
+	for (int i = 0; i < attribute_elements_nodelist.getLength(); i++) {
+	    Element current_attribute_element = (Element) attribute_elements_nodelist.item(i);
+	    String current_attribute_element_name = current_attribute_element.getAttribute("name");
+	    if (!current_attribute_element_name.equals(attribute_name)) {
+		// Move on to the next Attribute element if the name doesn't match
+		continue;
+	    }
+
+	    // Check if the language matches
+	    String current_attribute_element_language = current_attribute_element.getAttribute("language");
+	    if (language_matches || current_attribute_element_language.equals(language_code)) {
+		// Found attribute; returns its value
+		return XMLTools.getElementTextValue(current_attribute_element);
+	    }
+	}
+
+	return null;
+    }
+
+
+    /** Returns language-dependent metadata element name, with namespace (eg. dc.Subject and Keywords) */ 
+    public String getDisplayName()
+    {
+	String metadata_element_display_name = MetadataTools.getMetadataElementAttribute(this, "identifier", Configuration.getLanguage(), "en");
+
+	// Root case (no subelements)
+	if (metadata_element_name_full.indexOf(MetadataTools.SUBELEMENT_SEPARATOR) == -1) {
+	    if (metadata_element_display_name != null) {
+		return getNamespace() + "." + metadata_element_display_name;
+	    }
+
+	    return metadata_element_name_full;
+	}
+
+	// Recursive case (hierarchical metadata elements)
+	else {
+	    String parent_metadata_element_name_full = metadata_element_name_full.substring(0, metadata_element_name_full.lastIndexOf(MetadataTools.SUBELEMENT_SEPARATOR));
+	    MetadataElement parent_metadata_element = MetadataTools.getMetadataElementWithName(parent_metadata_element_name_full);
+
+	    String parent_metadata_element_display_name = parent_metadata_element_name_full;
+	    if (parent_metadata_element != null) {
+		parent_metadata_element_display_name = parent_metadata_element.getDisplayName();
+	    }
+
+	    if (metadata_element_display_name != null) {
+		return parent_metadata_element_display_name + MetadataTools.SUBELEMENT_SEPARATOR + metadata_element_display_name;
+	    }
+
+	    return parent_metadata_element_display_name + metadata_element_name_full.substring(parent_metadata_element_name_full.length());
+	}
+    }
+
+
+    public MetadataValueTreeModel getMetadataValueTreeModel()
+    {
+	return metadata_value_tree_model;
+    }
+
+
+    public MetadataValueTreeNode getMetadataValueTreeNode(String metadata_value)
+    {
+	return metadata_value_tree_model.getMetadataValueTreeNode(metadata_value);
+    }
+
+
+    /** Returns language-independent metadata element name, with namespace (eg. dc.Subject) */
+    public String getFullName()
+    {
+	return metadata_element_name_full;
+    }
+
+
+    public String getNamespace()
+    {
+	return MetadataTools.getMetadataSetNamespace(metadata_element_name_full);
+    }
+
+
+    /** Returns language-independent metadata element name, *without* namespace (eg. Subject) */
+    public String getName()
+    {
+	return MetadataTools.getMetadataElementName(metadata_element_name_full);
+    }
+
+
+    public boolean isExtractedMetadataElement()
+    {
+	return getNamespace().equals(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE);
+    }
+
+
+    public boolean isSubelement()
+    {
+	return (metadata_element_name_full.indexOf(MetadataTools.SUBELEMENT_SEPARATOR) != -1);
+    }
+
+
+    /** This is used to display the element in the metadata value table */
+    public String toString()
+    {
+	return getDisplayName();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataSet.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataSet.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataSet.java	(revision 10506)
@@ -0,0 +1,218 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.io.File;
+import java.util.*;
+import javax.swing.filechooser.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+
+/** This class represents one metadata set */
+public class MetadataSet
+{
+    private File metadata_set_file = null;
+    private ArrayList metadata_set_elements = new ArrayList();
+    private String metadata_set_namespace = null;
+
+
+    public MetadataSet(File metadata_set_file)
+    {
+	this.metadata_set_file = metadata_set_file;
+
+	// Parse the specified metadata set file
+	Document document = XMLTools.parseXMLFile(metadata_set_file);
+	if (document == null) {
+	    System.err.println("Error: Could not parse metadata set file " + metadata_set_file.getAbsolutePath());
+	    return;
+	}
+
+	// Read the metadata set's namespace
+	metadata_set_namespace = document.getDocumentElement().getAttribute("namespace");
+
+	// Read the Element elements in the metadata set
+	NodeList element_elements_nodelist = document.getElementsByTagName("Element");
+	for (int i = 0; i < element_elements_nodelist.getLength(); i++) {
+	    Element metadata_element_element = (Element) element_elements_nodelist.item(i);
+	    String metadata_element_name = metadata_element_element.getAttribute("name");
+
+	    // Deal with hierarchical metadata elements
+	    Element parent_metadata_element_element = (Element) metadata_element_element.getParentNode();
+	    while (parent_metadata_element_element.getTagName().equals("Element")) {
+		String parent_metadata_element_name = parent_metadata_element_element.getAttribute("name");
+		metadata_element_name = parent_metadata_element_name + MetadataTools.SUBELEMENT_SEPARATOR + metadata_element_name;
+		parent_metadata_element_element = (Element) parent_metadata_element_element.getParentNode();
+	    }
+
+	    String metadata_element_name_full = metadata_set_namespace + MetadataTools.NAMESPACE_SEPARATOR + metadata_element_name;
+	    metadata_set_elements.add(new MetadataElement(metadata_element_name_full, metadata_element_element));
+	}
+    }
+
+
+    public MetadataElement addMetadataElementForThisSession(String metadata_element_name)
+    {
+	String metadata_element_name_full = metadata_set_namespace + MetadataTools.NAMESPACE_SEPARATOR + metadata_element_name;
+	MetadataElement metadata_element = new MetadataElement(metadata_element_name_full, null);
+	metadata_set_elements.add(metadata_element);
+	return metadata_element;
+    }
+
+
+    public int compareMetadataElements(MetadataElement metadata_element_a, MetadataElement metadata_element_b)
+    {
+	// Extracted metadata is sorted alphabetically
+	if (metadata_set_namespace.equals(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE)) {
+	    return metadata_element_a.getName().compareTo(metadata_element_b.getName());
+	}
+
+	// Elements in metadata sets are sorted according to the other they are specified in the .mds file
+	return metadata_set_elements.indexOf(metadata_element_a) - metadata_set_elements.indexOf(metadata_element_b);
+    }
+
+
+    public String getAttribute(String attribute_name, String language_code)
+    {
+	// Parse the specified metadata set file
+	Document document = XMLTools.parseXMLFile(metadata_set_file);
+	if (document == null) {
+	    System.err.println("Error: Could not parse metadata set file " + metadata_set_file.getAbsolutePath());
+	    return null;
+	}
+
+	Element document_element = document.getDocumentElement();
+	Element parent_element = document_element;
+	boolean language_matches = false;
+
+	NodeList setlanguage_elements_nodelist = document_element.getElementsByTagName("SetLanguage");
+	for (int i = 0; i < setlanguage_elements_nodelist.getLength(); i++) {
+	    Element current_setlanguage_element = (Element) setlanguage_elements_nodelist.item(i);
+	    String current_setlanguage_element_code = current_setlanguage_element.getAttribute("code");
+	    if (current_setlanguage_element_code.equals(language_code)) {
+		// Found language; use it for the next step
+		parent_element = current_setlanguage_element;
+		language_matches = true;
+		break;
+	    }
+	}
+
+	NodeList attribute_elements_nodelist = parent_element.getElementsByTagName(attribute_name);
+	for (int i = 0; i < attribute_elements_nodelist.getLength(); i++) {
+	    Element current_attribute_element = (Element) attribute_elements_nodelist.item(i);
+
+	    // Check if the language matches
+	    String current_attribute_element_language = current_attribute_element.getAttribute("language");
+	    if (language_matches || current_attribute_element_language.equals(language_code)) {
+		// Found attribute; returns its value
+		return XMLTools.getElementTextValue(current_attribute_element);
+	    }
+	}
+
+	return null;
+    }
+
+
+    public MetadataElement getMetadataElementWithDisplayName(String metadata_element_display_name_full)
+    {
+	// Find the desired metadata element in the list
+	for (int i = 0; i < metadata_set_elements.size(); i++) {
+	    MetadataElement metadata_element = (MetadataElement) metadata_set_elements.get(i);
+	    if (metadata_element.getDisplayName().equals(metadata_element_display_name_full)) {
+		return metadata_element;
+	    }
+	}
+
+	// Not found
+	return null;
+    }
+
+
+    public MetadataElement getMetadataElementWithName(String metadata_element_name)
+    {
+	// Find the desired metadata element in the list
+	for (int i = 0; i < metadata_set_elements.size(); i++) {
+	    MetadataElement metadata_element = (MetadataElement) metadata_set_elements.get(i);
+	    if (metadata_element.getName().equals(metadata_element_name)) {
+		return metadata_element;
+	    }
+	}
+
+	// Not found
+	return null;
+    }
+
+
+    public ArrayList getMetadataSetElements()
+    {
+	// We don't want anyone to modify the list, so return a copy of it
+	return (ArrayList) metadata_set_elements.clone();
+    }
+
+
+    public File getMetadataSetFile()
+    {
+	return metadata_set_file;
+    }
+
+
+    public String getNamespace()
+    {
+	return metadata_set_namespace;
+    }
+
+
+    /** This is used to display the metadata set in the metadata import mapping and explode metadata prompts */
+    public String toString()
+    {
+	return MetadataTools.getMetadataSetAttribute(this, "Name", Configuration.getLanguage(), "en") + " (" + metadata_set_namespace + ")";
+    }
+
+
+    static public class MetadataSetFileFilter
+	extends FileFilter
+    {
+	public boolean accept(File file)
+	{
+	    String file_name = file.getName().toLowerCase();
+	    if (file_name.endsWith(".mds") || file_name.indexOf(".") == -1) {
+		return true;
+	    }
+
+	    return false;
+	}
+
+
+	public String getDescription()
+	{
+	    return Dictionary.get("MetadataSet.Files");
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataSetManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataSetManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataSetManager.java	(revision 10506)
@@ -0,0 +1,207 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.gui.MetadataImportMappingPrompt;
+
+
+/** This class is a static class that manages the metadata sets */
+public class MetadataSetManager
+{
+    static public final String EXTRACTED_METADATA_NAMESPACE = "ex";
+
+    static private ArrayList metadata_sets = new ArrayList();
+
+
+    static public void clearMetadataSets()
+    {
+	metadata_sets.clear();
+    }
+
+
+    static public int compareMetadataElements(MetadataElement metadata_element_a, MetadataElement metadata_element_b)
+    {
+	// First compare the namespaces of the two metadata elements
+	if (!metadata_element_a.getNamespace().equals(metadata_element_b.getNamespace())) {
+	    return metadata_element_a.getNamespace().compareTo(metadata_element_b.getNamespace());
+	}
+
+	// Otherwise compare the two elements within the one set
+	MetadataSet metadata_set = getMetadataSet(metadata_element_a.getNamespace());
+	return metadata_set.compareMetadataElements(metadata_element_a, metadata_element_b);
+    }
+
+
+    static public ArrayList getEveryMetadataSetElement()
+    {
+	ArrayList every_metadata_set_element = new ArrayList();
+
+	for (int i = 0; i < metadata_sets.size(); i++) {
+	    MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
+	    every_metadata_set_element.addAll(metadata_set.getMetadataSetElements());
+	}
+
+	return every_metadata_set_element;
+    }
+
+
+    static public MetadataSet getMetadataSet(String metadata_set_namespace)
+    {
+	// Find the desired metadata set in the list
+	for (int i = 0; i < metadata_sets.size(); i++) {
+	    MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
+	    if (metadata_set.getNamespace().equals(metadata_set_namespace)) {
+		return metadata_set;
+	    }
+	}
+
+	// Not found
+	return null;
+    }
+
+
+    static public ArrayList getMetadataSets()
+    {
+	// We don't want anyone to modify the list, so return a copy of it
+	return (ArrayList) metadata_sets.clone();
+    }
+
+
+    static public ArrayList listMetadataSets(File directory)
+    {
+	// Make sure the directory (metadata) exists
+	if (directory.exists() == false) {
+	    return null;
+	}
+
+	// Load just those .mds files in this directory, and return them
+	ArrayList directory_metadata_sets = new ArrayList();
+	File[] directory_files = directory.listFiles();
+	for (int i = 0; i < directory_files.length; i++) {
+	    File child_file = directory_files[i];
+	    if (!child_file.isDirectory() && child_file.getName().endsWith(".mds")) {
+		MetadataSet metadata_set = new MetadataSet(child_file);
+		directory_metadata_sets.add(metadata_set);
+	    }
+	}
+
+	return directory_metadata_sets;
+    }
+
+
+    static public void loadMetadataSets(File directory)
+    {
+	// Make sure the directory (metadata) exists
+	if (directory.exists() == false) {
+	    return;
+	}
+
+	// Look recursively at each subfile of the directory for .mds files
+	File[] directory_files = directory.listFiles();
+	for (int i = 0; i < directory_files.length; i++) {
+	    File child_file = directory_files[i];
+	    if (child_file.isDirectory()) {
+		loadMetadataSets(child_file);
+	    }
+	    else if (child_file.getName().endsWith(".mds")) {
+		loadMetadataSet(child_file);
+	    }
+	}
+    }
+
+
+    static public void loadMetadataSet(File metadata_set_file)
+    {
+	MetadataSet metadata_set = new MetadataSet(metadata_set_file);
+
+	// Ignore legacy crap
+	if (metadata_set.getNamespace().equals("hidden")) {
+	    return;
+	}
+
+	metadata_sets.add(metadata_set);
+    }
+
+
+    static public String mapUnloadedMetadataElement(String metadata_element_name_full)
+    {
+	// Check if we have an import mapping for this metadata element
+	String target_metadata_element_name_full = ProfileXMLFileManager.getMetadataElementFor(metadata_element_name_full);
+	if (target_metadata_element_name_full != null) {
+	    // Yes, so return it
+	    return target_metadata_element_name_full;
+	}
+
+	// If there are no metadata sets (except extracted) loaded then there is nothing to map the element into
+	if (metadata_sets.size() <= 1) {
+	    return null;
+	}
+
+	// Ask the user how they want to deal with this element
+	MetadataImportMappingPrompt metadata_import_mapping_prompt = new MetadataImportMappingPrompt(metadata_element_name_full);
+	int result = metadata_import_mapping_prompt.getResult();
+
+	// Add the element into an existing metadata set
+	if (result == MetadataImportMappingPrompt.ADD_BUTTON_PRESSED) {
+	    MetadataSet target_metadata_set = metadata_import_mapping_prompt.getSelectedMetadataSet();
+	    String metadata_element_name = MetadataTools.getMetadataElementName(metadata_element_name_full);
+	    target_metadata_set.addMetadataElementForThisSession(metadata_element_name);
+	    target_metadata_element_name_full = target_metadata_set.getNamespace() + "." + metadata_element_name;
+	}
+
+	// Replace the element with an element in an existing metadata set
+	if (result == MetadataImportMappingPrompt.MERGE_BUTTON_PRESSED) {
+	    MetadataElement target_metadata_element = metadata_import_mapping_prompt.getSelectedMetadataElement();
+	    target_metadata_element_name_full = target_metadata_element.getFullName();
+	}
+
+	// Ignore the element
+	if (result == MetadataImportMappingPrompt.IGNORE_BUTTON_PRESSED) {
+	    target_metadata_element_name_full = "";
+	}
+
+	// Store this import mapping for future elements with the same name
+	ProfileXMLFileManager.mapElement(metadata_element_name_full, target_metadata_element_name_full);
+
+	return target_metadata_element_name_full;
+    }
+
+
+    static public void unloadMetadataSet(MetadataSet metadata_set)
+    {
+	// Find the metadata set in the list of loaded sets, and remove it
+	for (int i = 0; i < metadata_sets.size(); i++) {
+	    if (metadata_set == (MetadataSet) metadata_sets.get(i)) {
+		metadata_sets.remove(i);
+		break;
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataTools.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataTools.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataTools.java	(revision 10506)
@@ -0,0 +1,137 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+/** This class is a static class containing useful metadata functions */
+public class MetadataTools
+{
+    static final public String NAMESPACE_SEPARATOR = ".";
+    static final public String SUBELEMENT_SEPARATOR = "^";
+
+
+    static public String getDisplayNameForMetadataElementWithName(String metadata_element_name_full)
+    {
+	MetadataElement metadata_element = getMetadataElementWithName(metadata_element_name_full);
+	if (metadata_element != null) {
+	    return metadata_element.getDisplayName();
+	}
+
+	return metadata_element_name_full;
+    }
+
+
+    static public String getMetadataElementAttribute(MetadataElement metadata_element, String attribute_name, String language_code, String fallback_language_code)
+    {
+	String metadata_element_attribute = metadata_element.getAttribute(attribute_name, language_code);
+
+	// If the attribute isn't defined in the desired language, resort to the fallback
+	if (metadata_element_attribute == null && !language_code.equals(fallback_language_code)) {
+	    metadata_element_attribute = metadata_element.getAttribute(attribute_name, fallback_language_code);
+	}
+
+	return metadata_element_attribute;
+    }
+
+
+    static public String getMetadataElementName(String metadata_element_name_full)
+    {
+	// Full element name contains namespace
+	if (metadata_element_name_full.indexOf(NAMESPACE_SEPARATOR) != -1) {
+	    return metadata_element_name_full.substring(metadata_element_name_full.indexOf(NAMESPACE_SEPARATOR) + 1);
+	}
+
+	// No namespace
+	return metadata_element_name_full;      
+    }
+
+
+    static public MetadataElement getMetadataElementWithDisplayName(String metadata_element_display_name_full)
+    {
+	String metadata_set_namespace = getMetadataSetNamespace(metadata_element_display_name_full);
+	MetadataSet metadata_set = MetadataSetManager.getMetadataSet(metadata_set_namespace);
+	if (metadata_set == null) {
+	    return null;
+	}
+
+	return metadata_set.getMetadataElementWithDisplayName(metadata_element_display_name_full);
+    }
+
+
+    static public MetadataElement getMetadataElementWithName(String metadata_element_name_full)
+    {
+	String metadata_set_namespace = getMetadataSetNamespace(metadata_element_name_full);
+	MetadataSet metadata_set = MetadataSetManager.getMetadataSet(metadata_set_namespace);
+	if (metadata_set == null) {
+	    return null;
+	}
+
+	String metadata_element_name = getMetadataElementName(metadata_element_name_full);
+	return metadata_set.getMetadataElementWithName(metadata_element_name);
+    }
+
+
+    static public String getMetadataSetAttribute(MetadataSet metadata_set, String attribute_name, String language_code, String fallback_language_code)
+    {
+	String metadata_set_attribute = metadata_set.getAttribute(attribute_name, language_code);
+
+	// If the attribute isn't defined in the desired language, resort to the fallback
+	if (metadata_set_attribute == null && !language_code.equals(fallback_language_code)) {
+	    metadata_set_attribute = metadata_set.getAttribute(attribute_name, fallback_language_code);
+	}
+
+	return metadata_set_attribute;
+    }
+
+
+    static public String getMetadataSetNamespace(String metadata_element_name_full)
+    {
+	// Full element name contains namespace
+	if (metadata_element_name_full.indexOf(NAMESPACE_SEPARATOR) != -1) {
+	    return metadata_element_name_full.substring(0, metadata_element_name_full.indexOf(NAMESPACE_SEPARATOR));
+	}
+
+	// No namespace
+	return "";
+    }
+
+
+    static public String getRegularExpressionThatMatchesFilePath(String file_path)
+    {
+	// Convert the file path into a regular expression that will match it
+	String file_path_regexp = file_path;
+	file_path_regexp = file_path_regexp.replaceAll("\\.", "\\\\.");
+	file_path_regexp = file_path_regexp.replaceAll("\\(", "\\\\(");
+	file_path_regexp = file_path_regexp.replaceAll("\\)", "\\\\)");
+	file_path_regexp = file_path_regexp.replaceAll("\\[", "\\\\[");
+	file_path_regexp = file_path_regexp.replaceAll("\\]", "\\\\]");
+	file_path_regexp = file_path_regexp.replaceAll("\\{", "\\\\{");
+	file_path_regexp = file_path_regexp.replaceAll("\\}", "\\\\}");
+	file_path_regexp = file_path_regexp.replaceAll("\\+", "\\\\+");
+	return file_path_regexp;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValue.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValue.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValue.java	(revision 10506)
@@ -0,0 +1,118 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.io.*;
+
+
+/** This class represents one metadata (element, value) pair */
+public class MetadataValue
+    implements Comparable
+{
+    /** The folder that this piece of metadata was inherited from, if applicable */
+    private File folder_metadata_inherited_from = null;
+    private MetadataElement metadata_element = null;
+    private MetadataValueTreeNode metadata_value_tree_node = null;
+    private boolean is_accumulating_metadata = false;
+
+
+    public MetadataValue(MetadataElement metadata_element, MetadataValueTreeNode metadata_value_tree_node)
+    {
+	this.metadata_element = metadata_element;
+	this.metadata_value_tree_node = metadata_value_tree_node;
+    }
+
+
+    public int compareTo(Object metadata_value_object)
+    {
+	MetadataValue metadata_value = (MetadataValue) metadata_value_object;
+
+	// First compare the metadata elements
+	int c = MetadataSetManager.compareMetadataElements(this.getMetadataElement(), metadata_value.getMetadataElement());
+	if (c != 0) {
+	    return c;
+	}
+
+	// Then use the metadata values
+	return this.getFullValue().compareTo(metadata_value.getFullValue());
+    }
+
+
+    public File getFolderMetadataInheritedFrom()
+    {
+	return folder_metadata_inherited_from;
+    }
+
+
+    public MetadataElement getMetadataElement()
+    {
+	return metadata_element;
+    }
+
+
+    public String getFullValue()
+    {
+	return metadata_value_tree_node.getFullValue();
+    }
+
+
+    public String getValue()
+    {
+	return metadata_value_tree_node.getValue();
+    }
+
+
+    public MetadataValueTreeNode getMetadataValueTreeNode()
+    {
+	return metadata_value_tree_node;
+    }
+
+
+    public void inheritsMetadataFromFolder(File folder_metadata_inherited_from)
+    {
+	this.folder_metadata_inherited_from = folder_metadata_inherited_from;
+    }
+
+
+    public boolean isAccumulatingMetadata()
+    {
+	return is_accumulating_metadata;
+    }
+
+
+    public boolean isInheritedMetadata()
+    {
+	return (folder_metadata_inherited_from != null);
+    }
+
+
+    public void setIsAccumulatingMetadata(boolean is_accumulating_metadata)
+    {
+	this.is_accumulating_metadata = is_accumulating_metadata;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTableEntry.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTableEntry.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTableEntry.java	(revision 10506)
@@ -0,0 +1,68 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer.metadata;
+
+
+/** This class represents one entry in the metadata value table. */
+public class MetadataValueTableEntry
+    extends MetadataValue
+{
+    private int occurrences = 0;
+
+
+    public MetadataValueTableEntry(MetadataElement metadata_element, MetadataValueTreeNode metadata_value_tree_node)
+    {
+	super(metadata_element, metadata_value_tree_node);
+
+	occurrences = 1;
+    }
+
+
+    public MetadataValueTableEntry(MetadataValue metadata_value)
+    {
+	this(metadata_value.getMetadataElement(), metadata_value.getMetadataValueTreeNode());
+	inheritsMetadataFromFolder(metadata_value.getFolderMetadataInheritedFrom());
+    }
+
+
+    public void anotherOccurrence()
+    {
+	occurrences++;
+    }
+
+
+    public int getOccurrences()
+    {
+	return occurrences;
+    }
+
+
+    public void setOccurrences(int occurrences)
+    {
+	this.occurrences = occurrences;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTableModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTableModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTableModel.java	(revision 10506)
@@ -0,0 +1,462 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+import org.greenstone.gatherer.gui.WarningDialog;
+
+
+public class MetadataValueTableModel
+    extends AbstractTableModel
+{
+    /** The CollectionTreeNodes this model is built for */
+    private CollectionTreeNode[] file_nodes = null;
+    /** The list of MetadataValueTableEntries in the table */
+    private ArrayList metadata_value_table_entries = new ArrayList();
+
+    static final private String[] COLUMN_NAMES = { "", Dictionary.get("Metadata.Element"), Dictionary.get("Metadata.Value") };
+
+
+    public int addBlankRowForMetadataElement(MetadataElement metadata_element)
+    {
+	MetadataValueTableModelBuilder metadata_value_table_model_builder = new MetadataValueTableModelBuilder();
+	MetadataValue blank_metadata_value = new MetadataValue(metadata_element, new MetadataValueTreeNode(""));
+	return metadata_value_table_model_builder.insertMetadataValue(blank_metadata_value);
+    }
+
+
+    public int findMetadataValueTableEntryToSelect(MetadataValueTableEntry metadata_value_table_entry)
+    {
+	MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement();
+
+	// Find the correct entry to select
+	for (int i = 0; i < metadata_value_table_entries.size(); i++) {
+	    MetadataValueTableEntry current_metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(i);
+	    int element_comparison = MetadataSetManager.compareMetadataElements(current_metadata_value_table_entry.getMetadataElement(), metadata_element);
+
+	    // We've found the right element, so check if the value already exists
+	    if (element_comparison == 0) {
+		int value_comparison = current_metadata_value_table_entry.compareTo(metadata_value_table_entry);
+		if (value_comparison == 0) {
+		    // Entry found!
+		    return i;
+		}
+	    }
+
+	    // We've just gone past the correct entry to select
+	    if (element_comparison > 0) {
+		return i - 1;
+	    }
+	}
+
+	// Have to select the last entry
+	return metadata_value_table_entries.size() - 1;
+    }
+
+
+    public Class getColumnClass(int col)
+    {
+	return getValueAt(0, col).getClass();
+    }
+
+
+    /** Returns the number of columns in this table. */
+    public int getColumnCount()
+    {
+	return COLUMN_NAMES.length;
+    }
+
+
+    /** Retrieves the name of the specified column. */
+    public String getColumnName(int col)
+    {
+	return COLUMN_NAMES[col];
+    }
+
+
+    /* Called to retrieve the MetadataValueTableEntry at a certain row. Usually caused by the user selecting a row in the table. It is synchronized so that the model doesn't up and change while we're trying to retrieve the indicated element. */
+    public synchronized MetadataValueTableEntry getMetadataValueTableEntry(int row)
+    {
+	if (row >= 0 && row < metadata_value_table_entries.size()) {
+	    return (MetadataValueTableEntry) metadata_value_table_entries.get(row);
+	}
+
+	return null;
+    }
+
+
+    /** Returns the number of rows in this table. */
+    public int getRowCount()
+    {
+	return metadata_value_table_entries.size();
+    }
+
+
+    /** Returns the cell value at a given row and column as an Object. */
+    public Object getValueAt(int row, int col)
+    {
+	// Check values are reasonable
+	if (row < 0 || row >= metadata_value_table_entries.size() || col < 0 || col >= COLUMN_NAMES.length) {
+	    return null;
+	}
+
+	MetadataValueTableEntry metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(row);
+	if (col == 0 && metadata_value_table_entry.isInheritedMetadata()) {
+	    return metadata_value_table_entry.getFolderMetadataInheritedFrom();
+	}
+
+	if (col == 1) {
+	    return metadata_value_table_entry.getMetadataElement();
+	}
+
+	if (col == 2) {
+	    return metadata_value_table_entry.getFullValue();
+	}
+
+	return null;
+    }
+
+
+    public boolean isCellEditable(int row, int col)
+    {
+	// The inherited and element columns are never editable
+	if (col < 2) {
+	    return false;
+	}
+
+	// Extracted and inherited metadata is not editable
+	MetadataValueTableEntry metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(row);
+	if (metadata_value_table_entry.getMetadataElement().isExtractedMetadataElement() || metadata_value_table_entry.isInheritedMetadata()) {
+	    return false;
+	}
+
+	return true;
+    }
+
+
+    /** Determine if the given metadata is common to all selected file nodes. */
+    public boolean isCommon(MetadataValueTableEntry metadata_value_table_entry)
+    {
+	return (file_nodes != null && metadata_value_table_entry.getOccurrences() == file_nodes.length);
+    }
+
+
+    /** Determine if the given metadata is common to all selected file nodes. */
+    public boolean isCommon(int row)
+    {
+	if (row >= 0 && row < metadata_value_table_entries.size()) {
+	    return isCommon((MetadataValueTableEntry) metadata_value_table_entries.get(row));
+	}
+
+	return false;
+    }
+
+
+    public void rebuild(CollectionTreeNode[] file_nodes)
+    {
+	this.file_nodes = file_nodes;
+	metadata_value_table_entries.clear();
+
+	// Collection is in a state of flux
+	if (!Gatherer.c_man.ready()) {
+	    return;
+	}
+
+	if (file_nodes == null || file_nodes.length == 0) {
+	    return;
+	}
+
+	// Create model builder
+	MetadataValueTableModelBuilder builder = new MetadataValueTableModelBuilder();
+	builder.run();
+    }
+
+
+    public void setValueAt(Object new_metadata_value, int row, int col)
+    {
+	MetadataValueTableEntry metadata_value_table_entry = getMetadataValueTableEntry(row);
+
+	// If nothing has changed no action is necessary
+	String old_metadata_value = metadata_value_table_entry.getFullValue();
+	if (new_metadata_value.equals(old_metadata_value)) {
+	    return;
+	}
+
+	// Lock the interface so nothing can be changed while the metadata edit is being processed
+	Gatherer.g_man.wait(true);
+
+	// Metadata value added
+	if (old_metadata_value.equals("") && !new_metadata_value.equals("")) {
+ 	    // If we're adding metadata to folders display the warning
+ 	    if (!file_nodes[0].isLeaf()) {
+ 		WarningDialog dialog = new WarningDialog("warning.DirectoryLevelMetadata", "DirectoryLevelMetadata.Title", Dictionary.get("DirectoryLevelMetadata.Message"), null, true);
+ 		int dialog_result = dialog.display();
+ 		dialog.dispose();
+ 		if (dialog_result != JOptionPane.OK_OPTION) {
+ 		    return;
+ 		}
+ 	    }
+
+	    MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement();
+	    MetadataValueTreeNode metadata_value_tree_node = metadata_element.addMetadataValue((String) new_metadata_value);
+	    MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node);
+	    metadata_value.setIsAccumulatingMetadata(true);
+	    (new AppendMetadataTask(metadata_value)).run();
+	}
+
+	// Metadata value removed
+	else if (!old_metadata_value.equals("") && new_metadata_value.equals("")) {
+	    (new RemoveMetadataTask(metadata_value_table_entry)).run();
+	}
+
+	// Metadata value replaced
+	else {
+	    MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement();
+	    MetadataValueTreeNode metadata_value_tree_node = metadata_element.addMetadataValue((String) new_metadata_value);
+	    MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node);
+	    metadata_value.setIsAccumulatingMetadata(!metadata_value_table_entry.isInheritedMetadata());
+	    (new ReplaceMetadataTask(metadata_value_table_entry, metadata_value)).run();
+	}
+    }
+
+
+    private class AppendMetadataTask
+	// extends Thread
+    {
+	private MetadataValue metadata_value = null;
+
+	private AppendMetadataTask(MetadataValue metadata_value)
+	{
+	    this.metadata_value = metadata_value;
+	}
+
+	public void run()
+	{
+	    try {
+		// Edit metadata.xml files to add the metadata
+		MetadataXMLFileManager.addMetadata(file_nodes, metadata_value);
+	    }
+	    catch (Exception exception) {
+		// We need to catch any exceptions here so the interface is unlocked below
+		DebugStream.printStackTrace(exception);
+	    }
+
+	    // Operation finished, so turn busy cursor off and unlock interface
+	    Gatherer.g_man.wait(false);
+	}
+    }
+
+
+    private class ReplaceMetadataTask
+	// extends Thread
+    {
+	private MetadataValueTableEntry selected_metadata_value_table_entry = null;
+	private MetadataValue metadata_value = null;
+
+	private ReplaceMetadataTask(MetadataValueTableEntry selected_metadata_value_table_entry, MetadataValue metadata_value)
+	{
+	    this.selected_metadata_value_table_entry = selected_metadata_value_table_entry;
+	    this.metadata_value = metadata_value;
+	}
+
+	public void run()
+	{
+	    try {
+		// Edit metadata.xml files to replace the metadata
+		MetadataXMLFileManager.replaceMetadata(file_nodes, selected_metadata_value_table_entry, metadata_value);
+	    }
+	    catch (Exception exception) {
+		// We need to catch any exceptions here so the interface is unlocked below
+		DebugStream.printStackTrace(exception);
+	    }
+
+	    // Operation finished, so turn busy cursor off and unlock interface
+	    Gatherer.g_man.wait(false);
+	}
+    }
+
+
+    private class RemoveMetadataTask
+	// extends Thread
+    {
+	private MetadataValueTableEntry selected_metadata_value_table_entry = null;
+
+	private RemoveMetadataTask(MetadataValueTableEntry selected_metadata_value_table_entry)
+	{
+	    this.selected_metadata_value_table_entry = selected_metadata_value_table_entry;
+	}
+
+	public void run()
+	{
+	    try {
+		// Edit metadata.xml files to remove the metadata
+		MetadataXMLFileManager.removeMetadata(file_nodes, selected_metadata_value_table_entry);
+	    }
+	    catch (Exception exception) {
+		// We need to catch any exceptions here so the interface is unlocked below
+		DebugStream.printStackTrace(exception);
+	    }
+
+	    // Operation finished, so turn busy cursor off and unlock interface
+	    Gatherer.g_man.wait(false);
+	}
+    }
+
+
+    private class MetadataValueTableModelBuilder
+    {
+	public void run()
+	{
+	    // System.err.println("Building MetadataValueTableModel...");
+
+	    // Build a list of MetadataValueTableEntries that represent the metadata asssigned to the selected files
+	    boolean hid_extracted_metadata = false;
+	    ArrayList metadata_elements_seen = new ArrayList();
+
+	    // Process each of the selected files in turn
+	    for (int i = 0; i < file_nodes.length; i++) {
+		File current_file = file_nodes[i].getFile();
+
+		// Get the metadata assigned to this file
+		ArrayList assigned_metadata = MetadataXMLFileManager.getMetadataAssignedToFile(current_file);
+		for (int j = 0; j < assigned_metadata.size(); j++) {
+		    MetadataValue metadata_value = (MetadataValue) assigned_metadata.get(j);
+		    MetadataElement metadata_element = metadata_value.getMetadataElement();
+
+		    // Insert this metadata value into the table, unless it already exists (in which case increment its count)
+		    insertMetadataValue(metadata_value);
+
+		    // Remember we have seen this metadata element
+		    if (metadata_elements_seen.contains(metadata_element) == false) {
+			metadata_elements_seen.add(metadata_element);
+		    }
+		}
+
+		// Get the extracted metadata for this file, if desired
+		if (Configuration.get("general.view_extracted_metadata", Configuration.COLLECTION_SPECIFIC) == true) {
+		    ArrayList extracted_metadata = DocXMLFileManager.getMetadataExtractedFromFile(current_file);
+		    for (int k = 0; k < extracted_metadata.size(); k++) {
+			MetadataValue metadata_value = (MetadataValue) extracted_metadata.get(k);
+
+			// Insert this metadata value into the table, unless it already exists (in which case increment its count)
+			insertMetadataValue(metadata_value);
+		    }
+		}
+	    }
+
+	    // Make sure each non-extracted metadata element appears in the table (even if blank)
+	    ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+	    for (int i = 0; i < every_metadata_set_element.size(); i++) {
+		MetadataElement metadata_element = (MetadataElement) every_metadata_set_element.get(i);
+
+		// If we haven't seen this metadata element and it isn't extracted, add it now
+		if (!metadata_elements_seen.contains(metadata_element) && !metadata_element.isExtractedMetadataElement()) {
+		    MetadataValueTableEntry metadata_value_table_entry = new MetadataValueTableEntry(metadata_element, new MetadataValueTreeNode(""));
+
+		    // Blank metadata is common to all selected files (otherwise it wouldn't be blank!)
+		    metadata_value_table_entry.setOccurrences(file_nodes.length);
+
+		    // Add it to the table
+		    insertMetadataValueTableEntry(metadata_value_table_entry);
+		}
+	    }
+
+	    // If extracted metadata was hidden, display the warning
+	    if (hid_extracted_metadata) {
+		showExtractedMetadataWarning();
+	    }
+	}
+
+
+	/** Inserts the new metadata value into the table */
+	private int insertMetadataValue(MetadataValue metadata_value)
+	{
+	    return insertMetadataValueTableEntry(new MetadataValueTableEntry(metadata_value));
+	}
+
+
+	/** Inserts the new metadata value table entry into the table */
+	private int insertMetadataValueTableEntry(MetadataValueTableEntry metadata_value_table_entry)
+	{
+	    MetadataElement metadata_element = metadata_value_table_entry.getMetadataElement();
+
+	    // Find the correct place to insert the table entry
+	    for (int i = 0; i < metadata_value_table_entries.size(); i++) {
+		MetadataValueTableEntry current_metadata_value_table_entry = (MetadataValueTableEntry) metadata_value_table_entries.get(i);
+		int element_comparison = MetadataSetManager.compareMetadataElements(current_metadata_value_table_entry.getMetadataElement(), metadata_element);
+
+		// We've found the right element, so check if the value already exists
+		if (element_comparison == 0) {
+		    int value_comparison = current_metadata_value_table_entry.compareTo(metadata_value_table_entry);
+		    if (value_comparison == 0) {
+			// Entry already exists, so increment count (except for blank entries)
+			if (!metadata_value_table_entry.getFullValue().equals("")) {
+			    current_metadata_value_table_entry.anotherOccurrence();
+			}
+			return i;
+		    }
+		}
+
+		// Found insertion point
+		if (element_comparison > 0) {
+		    metadata_value_table_entries.add(i, metadata_value_table_entry);
+		    fireTableRowsInserted(i, i);
+		    return i;
+		}
+	    }
+
+	    // Must go at the end of the table
+	    metadata_value_table_entries.add(metadata_value_table_entry);
+	    fireTableRowsInserted(metadata_value_table_entries.size() - 1, metadata_value_table_entries.size() - 1);
+	    return metadata_value_table_entries.size() - 1;
+	}
+
+
+	private void showExtractedMetadataWarning()
+	{
+	    Runnable task = new Runnable() {
+		    public void run() {
+			WarningDialog dialog = new WarningDialog("warning.ExtractedMetadata", "ExtractedMetadata.Title", Dictionary.get("ExtractedMetadata.Message"), null, false);
+			dialog.display();
+			dialog.dispose();
+			dialog = null;
+		    }
+		};
+	    SwingUtilities.invokeLater(task);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTreeModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTreeModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTreeModel.java	(revision 10506)
@@ -0,0 +1,137 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.io.*;
+import java.util.*;
+import javax.swing.tree.*;
+
+
+/** This class represents all the metadata values for one metadata element */
+public class MetadataValueTreeModel
+    extends DefaultTreeModel
+{
+    public MetadataValueTreeModel(MetadataElement metadata_element)
+    {
+	// The root node of the value tree is the MetadataElement it represents
+	super(new MetadataValueTreeNode(metadata_element));
+    }
+
+
+    public MetadataValueTreeNode addMetadataValue(String metadata_value)
+    {
+	return addMetadataValueInternal((MetadataValueTreeNode) root, metadata_value);
+    }
+
+
+    private MetadataValueTreeNode addMetadataValueInternal(MetadataValueTreeNode parent_metadata_value_tree_node, String metadata_value_remaining)
+    {
+	// Split the metadata value into a hierarchy
+	int split_point = metadata_value_remaining.indexOf(MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN);
+	String metadata_value = ((split_point == -1) ? metadata_value_remaining : metadata_value_remaining.substring(0, split_point));
+	metadata_value_remaining = ((split_point == -1) ? "" : metadata_value_remaining.substring(split_point + 1));
+
+	// Add the value into the tree in the correct place (sorted)
+	MetadataValueTreeNode metadata_value_tree_node = null;
+	for (int i = 0; i < parent_metadata_value_tree_node.getChildCount(); i++) {
+	    MetadataValueTreeNode child_metadata_value_tree_node = (MetadataValueTreeNode) parent_metadata_value_tree_node.getChildAt(i);
+	    int c = metadata_value.compareTo(child_metadata_value_tree_node.getValue());
+
+	    // Insert node before existing value
+	    if (c < 0) {
+		metadata_value_tree_node = new MetadataValueTreeNode(metadata_value);
+		insertNodeInto(metadata_value_tree_node, parent_metadata_value_tree_node, i);
+		break;
+	    }
+
+	    // Node already exists (don't add again)
+	    if (c == 0) {
+		metadata_value_tree_node = child_metadata_value_tree_node;
+		break;
+	    }
+	}
+
+	// If no node has been added yet, it must go at the end of the list
+	if (metadata_value_tree_node == null) {
+	    metadata_value_tree_node = new MetadataValueTreeNode(metadata_value);
+	    insertNodeInto(metadata_value_tree_node, parent_metadata_value_tree_node, parent_metadata_value_tree_node.getChildCount());
+	}
+
+	// If there is some of the metadata value remaining, add that hierarchically
+	if (!metadata_value_remaining.equals("")) {
+	    metadata_value_tree_node = addMetadataValueInternal(metadata_value_tree_node, metadata_value_remaining);
+	}
+
+	return metadata_value_tree_node;
+    }
+
+
+    public MetadataValueTreeNode getMetadataValueTreeNode(String metadata_value)
+    {
+	return getMetadataValueTreeNodeInternal((MetadataValueTreeNode) root, metadata_value);
+    }
+
+
+    private MetadataValueTreeNode getMetadataValueTreeNodeInternal(MetadataValueTreeNode parent_metadata_value_tree_node, String metadata_value_remaining)
+    {
+	// Split the metadata value into a hierarchy
+	int split_point = metadata_value_remaining.indexOf(MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN);
+	String metadata_value = ((split_point == -1) ? metadata_value_remaining : metadata_value_remaining.substring(0, split_point));
+	metadata_value_remaining = ((split_point == -1) ? "" : metadata_value_remaining.substring(split_point + 1));
+
+	// Find the value in the tree in the correct place (sorted)
+	MetadataValueTreeNode metadata_value_tree_node = null;
+	for (int i = 0; i < parent_metadata_value_tree_node.getChildCount(); i++) {
+	    MetadataValueTreeNode child_metadata_value_tree_node = (MetadataValueTreeNode) parent_metadata_value_tree_node.getChildAt(i);
+	    int c = metadata_value.compareTo(child_metadata_value_tree_node.getValue());
+
+	    // Node doesn't exist in the tree
+	    if (c < 0) {
+		return null;
+	    }
+	 
+	    // Node exists
+	    if (c == 0) {
+		metadata_value_tree_node = child_metadata_value_tree_node;
+		break;
+	    }
+	}
+
+	// If no node has been found, it doesn't exist
+	if (metadata_value_tree_node == null) {
+	    return null;
+	}
+
+	// If there is some of the metadata value remaining, find that recursively
+	if (!metadata_value_remaining.equals("")) {
+	    metadata_value_tree_node = getMetadataValueTreeNodeInternal(metadata_value_tree_node, metadata_value_remaining);
+	}
+
+	return metadata_value_tree_node;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTreeNode.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTreeNode.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataValueTreeNode.java	(revision 10506)
@@ -0,0 +1,79 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import javax.swing.tree.*;
+
+
+/** This class represents one Metadata value */
+public class MetadataValueTreeNode
+    extends DefaultMutableTreeNode
+{
+    static public final String METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN = "|";
+
+    private String value = null;
+
+
+    public MetadataValueTreeNode(Object object)
+    {
+	super(object);
+    }
+
+
+    public MetadataValueTreeNode(String value)
+    {
+	this.value = value;
+    }
+
+
+    public String getFullValue()
+    {
+	if (parent == null) {
+	    return "";
+	}
+
+	if (((MetadataValueTreeNode) parent).isRoot()) {
+	    return value;
+	}
+
+	return ((MetadataValueTreeNode) parent).getFullValue() + METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN + value;
+    }
+
+
+    public String getValue()
+    {
+	return value;
+    }
+
+
+    /** This is used to display the node in the value tree */
+    public String toString()
+    {
+	return value;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFile.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFile.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFile.java	(revision 10506)
@@ -0,0 +1,556 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+
+/** This class represents one metadata.xml file */
+public class MetadataXMLFile
+    extends File
+{
+    static final private String DESCRIPTION_ELEMENT = "Description";
+    static final private String DIRECTORY_FILENAME = ".*";
+    static final private String FILENAME_ELEMENT = "FileName";
+    static final private String FILESET_ELEMENT = "FileSet";
+    static final private String METADATA_ELEMENT = "Metadata";
+
+
+    public MetadataXMLFile(String metadata_xml_file_path)
+    {
+	super(metadata_xml_file_path);
+    }
+
+
+    public void addMetadata(File file, ArrayList metadata_values)
+    {
+	// Parse the metadata.xml file
+	Document document = XMLTools.parseXMLFile(this);
+	if (document == null) {
+	    System.err.println("Error: Could not parse metadata.xml file " + getAbsolutePath());
+	    return;
+	}
+
+	// Determine the file's path relative to the location of the metadata.xml file
+	String metadata_xml_file_directory_path = getParentFile().getAbsolutePath();
+	String file_relative_path = file.getAbsolutePath().substring(metadata_xml_file_directory_path.length());
+	if (file_relative_path.startsWith(File.separator)) {
+	    file_relative_path = file_relative_path.substring(File.separator.length());
+	}
+
+	// Form a regular expression that specifies the scope of the metadata
+	String file_path_regexp;
+	if (file_relative_path.equals("")) {
+	    // Special case for matching all files in the directory
+	    file_path_regexp = DIRECTORY_FILENAME;
+	}
+	else {
+	    // Convert the file path into a regular expression that will match it
+	    file_path_regexp = MetadataTools.getRegularExpressionThatMatchesFilePath(file_relative_path);
+	}
+
+	// Find the appropriate FileSet element for this file
+	Element appropriate_fileset_element = null;
+
+	// Read all the FileSet elements in the file
+	NodeList fileset_elements_nodelist = document.getElementsByTagName(FILESET_ELEMENT);
+	for (int i = 0; i < fileset_elements_nodelist.getLength(); i++) {
+	    Element current_fileset_element = (Element) fileset_elements_nodelist.item(i);
+
+	    // Check the FileName elements of the FileSet to see if we have a match
+	    NodeList filename_elements_nodelist = current_fileset_element.getElementsByTagName(FILENAME_ELEMENT);
+	    for (int j = 0; j < filename_elements_nodelist.getLength(); j++) {
+		Element current_filename_element = (Element) filename_elements_nodelist.item(j);
+		String current_filename_element_value = XMLTools.getElementTextValue(current_filename_element);
+
+		// Only exact matches can be extended with new metadata
+		if (current_filename_element_value.equals(file_path_regexp)) {
+		    appropriate_fileset_element = current_fileset_element;
+		    break;
+		}
+	    }
+	}
+
+	// If no appropriate FileSet element exists create a new one for this file
+	if (appropriate_fileset_element == null) {
+	    DebugStream.println("Creating new FileSet element for file since none exists...");
+	    appropriate_fileset_element = document.createElement(FILESET_ELEMENT);
+
+	    Element new_filename_element = document.createElement(FILENAME_ELEMENT);
+	    new_filename_element.appendChild(document.createTextNode(file_path_regexp));
+	    appropriate_fileset_element.appendChild(new_filename_element);
+
+	    Element new_description_element = document.createElement(DESCRIPTION_ELEMENT);
+	    appropriate_fileset_element.appendChild(new_description_element);
+
+	    document.getDocumentElement().appendChild(appropriate_fileset_element);
+	}
+
+	// Add each of the metadata values to the FileSet's Description element
+	Element description_element = (Element) appropriate_fileset_element.getElementsByTagName(DESCRIPTION_ELEMENT).item(0);
+	for (int i = 0; i < metadata_values.size(); i++) {
+	    MetadataValue metadata_value = (MetadataValue) metadata_values.get(i);
+	    String metadata_element_name_full = metadata_value.getMetadataElement().getFullName();
+
+	    // Remove any characters that are invalid in XML
+	    String metadata_value_string = XMLTools.removeInvalidCharacters(metadata_value.getFullValue());
+
+	    // Square brackets need to be escaped because they are a special character in Greenstone
+	    metadata_value_string = metadata_value_string.replaceAll("\\[", "&#091;");
+	    metadata_value_string = metadata_value_string.replaceAll("\\]", "&#093;");
+
+	    // Check if this piece of metadata has already been assigned to this FileSet element
+	    boolean metadata_already_assigned = false;
+	    NodeList metadata_elements_nodelist = description_element.getElementsByTagName(METADATA_ELEMENT);
+	    for (int k = 0; k < metadata_elements_nodelist.getLength(); k++) {
+		Element current_metadata_element = (Element) metadata_elements_nodelist.item(k);
+
+		// Check if the metadata element name matches
+		String current_metadata_element_name_full = current_metadata_element.getAttribute("name");
+		if (current_metadata_element_name_full.equals(metadata_element_name_full)) {
+		    // Check if the metadata element value matches
+		    String current_metadata_value_string = XMLTools.getElementTextValue(current_metadata_element);
+		    if (current_metadata_value_string.equals(metadata_value_string)) {
+			// Metadata already assigned
+			metadata_already_assigned = true;
+			break;
+		    }
+		}
+	    }
+
+	    // If the piece of metadata hasn't already been assigned, add it now
+	    if (!metadata_already_assigned) {
+		// Create a new Metadata element to record this metadata
+		Element new_metadata_element = document.createElement(METADATA_ELEMENT);
+		new_metadata_element.setAttribute("name", metadata_value.getMetadataElement().getFullName());
+		new_metadata_element.setAttribute("mode", (metadata_value.isAccumulatingMetadata() ? "accumulate" : "override"));
+		new_metadata_element.appendChild(document.createTextNode(metadata_value_string));
+
+		// Accumulating metadata: add at the end
+		if (metadata_value.isAccumulatingMetadata()) {
+		    description_element.appendChild(new_metadata_element);
+		}
+		// Override metadata: add at the start (so it overrides inherited metadata without affecting other assigned metadata)
+		else {
+		    description_element.insertBefore(new_metadata_element, description_element.getFirstChild());
+		}
+	    }
+	}
+
+	// Rewrite the metadata.xml file
+	XMLTools.writeXMLFile(this, document);
+    }
+
+
+    public ArrayList getMetadataAssignedToFile(File file)
+    {
+	// Parse the metadata.xml file
+	Document document = XMLTools.parseXMLFile(this);
+	if (document == null) {
+	    System.err.println("Error: Could not parse metadata.xml file " + getAbsolutePath());
+	    return new ArrayList();
+	}
+
+	// Determine the file's path relative to the location of the metadata.xml file
+	File metadata_xml_file_directory = getParentFile();
+	String file_relative_path = file.getAbsolutePath().substring(metadata_xml_file_directory.getAbsolutePath().length());
+	if (file_relative_path.startsWith(File.separator)) {
+	    file_relative_path = file_relative_path.substring(File.separator.length());
+	}
+
+	// Build up a list of metadata assigned to this file
+	ArrayList metadata_values = new ArrayList();
+
+	// Read all the FileSet elements in the file
+	NodeList fileset_elements_nodelist = document.getElementsByTagName(FILESET_ELEMENT);
+	for (int i = 0; i < fileset_elements_nodelist.getLength(); i++) {
+	    Element current_fileset_element = (Element) fileset_elements_nodelist.item(i);
+	    boolean current_fileset_matches = false;
+	    File folder_metadata_inherited_from = null;
+
+	    // Check the FileName elements of the FileSet to see if we have a match
+	    NodeList filename_elements_nodelist = current_fileset_element.getElementsByTagName(FILENAME_ELEMENT);
+	    for (int j = 0; j < filename_elements_nodelist.getLength(); j++) {
+		Element current_filename_element = (Element) filename_elements_nodelist.item(j);
+		String current_filename_element_value = XMLTools.getElementTextValue(current_filename_element);
+
+		// This fileset specifies metadata for the file
+		if (file_relative_path.matches(current_filename_element_value)) {
+		    current_fileset_matches = true;
+		    if (!file_relative_path.equals("") && current_filename_element_value.equals(DIRECTORY_FILENAME)) {
+			folder_metadata_inherited_from = metadata_xml_file_directory;
+		    }
+		    break;
+		}
+
+		// This fileset specifies metadata for the folder the file is in
+		if (file_relative_path.startsWith(current_filename_element_value + File.separator)) {
+		    current_fileset_matches = true;
+		    folder_metadata_inherited_from = new File(metadata_xml_file_directory, current_filename_element_value);
+		    break;
+		}
+	    }
+
+	    // The FileSet doesn't apply, so move onto the next one
+	    if (current_fileset_matches == false) {
+		continue;
+	    }
+
+	    // Read all the Metadata elements in the fileset
+	    NodeList metadata_elements_nodelist = current_fileset_element.getElementsByTagName(METADATA_ELEMENT);
+	    for (int k = 0; k < metadata_elements_nodelist.getLength(); k++) {
+		Element current_metadata_element = (Element) metadata_elements_nodelist.item(k);
+		String metadata_element_name_full = current_metadata_element.getAttribute("name");
+		String metadata_set_namespace = MetadataTools.getMetadataSetNamespace(metadata_element_name_full);
+
+		// Ignore legacy crap
+		if (metadata_set_namespace.equals("hidden")) {
+		    continue;
+		}
+
+		MetadataSet metadata_set = MetadataSetManager.getMetadataSet(metadata_set_namespace);
+		if (metadata_set == null) {
+		    // The metadata set isn't loaded, so give the option of mapping the element into a loaded set
+		    String target_metadata_element_name_full = MetadataSetManager.mapUnloadedMetadataElement(metadata_element_name_full);
+		    if (target_metadata_element_name_full == null || target_metadata_element_name_full.equals("")) {
+			// Skip this element if we still don't have a loaded element for it
+			continue;
+		    }
+
+		    metadata_element_name_full = target_metadata_element_name_full;
+		    metadata_set_namespace = MetadataTools.getMetadataSetNamespace(metadata_element_name_full);
+		    metadata_set = MetadataSetManager.getMetadataSet(metadata_set_namespace);
+		}
+
+		MetadataElement metadata_element = MetadataTools.getMetadataElementWithName(metadata_element_name_full);
+
+		// If the element doesn't exist in the metadata set, we're not interested
+		if (metadata_element == null) {
+		    continue;
+		}
+
+		// Square brackets need to be escaped because they are a special character in Greenstone
+		String metadata_value_string = XMLTools.getElementTextValue(current_metadata_element);
+		metadata_value_string = metadata_value_string.replaceAll("&#091;", "[");
+		metadata_value_string = metadata_value_string.replaceAll("&#093;", "]");
+
+		MetadataValueTreeNode metadata_value_tree_node = metadata_element.getMetadataValueTreeNode(metadata_value_string);
+
+		// If there is no metadata value tree node for this value, create it
+		if (metadata_value_tree_node == null) {
+		    DebugStream.println("Note: No value tree node for metadata value \"" + metadata_value_string + "\"");
+		    metadata_element.addMetadataValue(metadata_value_string);
+		    metadata_value_tree_node = metadata_element.getMetadataValueTreeNode(metadata_value_string);
+		}
+
+		MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node);
+		metadata_value.inheritsMetadataFromFolder(folder_metadata_inherited_from);
+
+		// Is this accumulating metadata?
+		if (current_metadata_element.getAttribute("mode").equals("accumulate")) {
+		    metadata_value.setIsAccumulatingMetadata(true);
+		}
+
+		// Add the new metadata value to the list
+		metadata_values.add(metadata_value);
+	    }
+	}
+
+	return metadata_values;
+    }
+
+
+    public void removeMetadata(File file, ArrayList metadata_values)
+    {
+	// Parse the metadata.xml file
+	Document document = XMLTools.parseXMLFile(this);
+	if (document == null) {
+	    System.err.println("Error: Could not parse metadata.xml file " + getAbsolutePath());
+	    return;
+	}
+
+	// Determine the file's path relative to the location of the metadata.xml file
+	String metadata_xml_file_directory_path = getParentFile().getAbsolutePath();
+	String file_relative_path = file.getAbsolutePath().substring(metadata_xml_file_directory_path.length());
+	if (file_relative_path.startsWith(File.separator)) {
+	    file_relative_path = file_relative_path.substring(File.separator.length());
+	}
+
+	// Form a regular expression that specifies the scope of the metadata
+	String file_path_regexp;
+	if (file_relative_path.equals("")) {
+	    // Special case for matching all files in the directory
+	    file_path_regexp = DIRECTORY_FILENAME;
+	}
+	else {
+	    // Convert the file path into a regular expression that will match it
+	    file_path_regexp = MetadataTools.getRegularExpressionThatMatchesFilePath(file_relative_path);
+	}
+
+	// Find the appropriate FileSet element for this file
+	Element appropriate_fileset_element = null;
+
+	// Read all the FileSet elements in the file
+	NodeList fileset_elements_nodelist = document.getElementsByTagName(FILESET_ELEMENT);
+	for (int i = 0; i < fileset_elements_nodelist.getLength(); i++) {
+	    Element current_fileset_element = (Element) fileset_elements_nodelist.item(i);
+
+	    // Check the FileName elements of the FileSet to see if we have a match
+	    NodeList filename_elements_nodelist = current_fileset_element.getElementsByTagName(FILENAME_ELEMENT);
+	    for (int j = 0; j < filename_elements_nodelist.getLength(); j++) {
+		Element current_filename_element = (Element) filename_elements_nodelist.item(j);
+		String current_filename_element_value = XMLTools.getElementTextValue(current_filename_element);
+
+		// Only exact matches can be extended with new metadata
+		if (current_filename_element_value.equals(file_path_regexp)) {
+		    appropriate_fileset_element = current_fileset_element;
+		    break;
+		}
+	    }
+	}
+
+	// If no appropriate FileSet element exists we have no idea where the metadata is
+	if (appropriate_fileset_element == null) {
+	    System.err.println("Error: No appropriate FileSet element found when removing metadata...");
+	    return;
+	}
+
+	// Remove each of the metadata values from the FileSet's Description element
+	Element description_element = (Element) appropriate_fileset_element.getElementsByTagName(DESCRIPTION_ELEMENT).item(0);
+	for (int i = 0; i < metadata_values.size(); i++) {
+	    MetadataValue metadata_value = (MetadataValue) metadata_values.get(i);
+
+	    // Remove any characters that are invalid in XML
+	    String metadata_value_string = XMLTools.removeInvalidCharacters(metadata_value.getFullValue());
+
+	    // Square brackets need to be escaped because they are a special character in Greenstone
+	    metadata_value_string = metadata_value_string.replaceAll("\\[", "&#091;");
+	    metadata_value_string = metadata_value_string.replaceAll("\\]", "&#093;");
+
+	    // Find the Metadata element to delete from the fileset
+	    String metadata_element_name_full = metadata_value.getMetadataElement().getFullName();
+	    NodeList metadata_elements_nodelist = appropriate_fileset_element.getElementsByTagName(METADATA_ELEMENT);
+	    for (int k = 0; k < metadata_elements_nodelist.getLength(); k++) {
+		Element current_metadata_element = (Element) metadata_elements_nodelist.item(k);
+
+		// Check the metadata element name matches
+		String current_metadata_element_name_full = current_metadata_element.getAttribute("name");
+		if (current_metadata_element_name_full.equals(metadata_element_name_full)) {
+		    // Check the metadata element value matches
+		    String current_metadata_value_string = XMLTools.getElementTextValue(current_metadata_element);
+		    if (current_metadata_value_string.equals(metadata_value_string)) {
+			// Remove this Metadata element
+			current_metadata_element.getParentNode().removeChild(current_metadata_element);
+			break;
+		    }
+		}
+	    }
+	}
+
+	// Rewrite the metadata.xml file
+	XMLTools.writeXMLFile(this, document);
+    }
+
+
+    public void replaceMetadata(File file, MetadataValue old_metadata_value, MetadataValue new_metadata_value)
+    {
+	// Parse the metadata.xml file
+	Document document = XMLTools.parseXMLFile(this);
+	if (document == null) {
+	    System.err.println("Error: Could not parse metadata.xml file " + getAbsolutePath());
+	    return;
+	}
+
+	// Determine the file's path relative to the location of the metadata.xml file
+	String metadata_xml_file_directory_path = getParentFile().getAbsolutePath();
+	String file_relative_path = file.getAbsolutePath().substring(metadata_xml_file_directory_path.length());
+	if (file_relative_path.startsWith(File.separator)) {
+	    file_relative_path = file_relative_path.substring(File.separator.length());
+	}
+
+	// Form a regular expression that specifies the scope of the metadata
+	String file_path_regexp;
+	if (file_relative_path.equals("")) {
+	    // Special case for matching all files in the directory
+	    file_path_regexp = DIRECTORY_FILENAME;
+	}
+	else {
+	    // Convert the file path into a regular expression that will match it
+	    file_path_regexp = MetadataTools.getRegularExpressionThatMatchesFilePath(file_relative_path);
+	}
+
+	// Remove any characters that are invalid in XML
+	String old_metadata_value_string = XMLTools.removeInvalidCharacters(old_metadata_value.getFullValue());
+	String new_metadata_value_string = XMLTools.removeInvalidCharacters(new_metadata_value.getFullValue());
+
+	// Square brackets need to be escaped because they are a special character in Greenstone
+	old_metadata_value_string = old_metadata_value_string.replaceAll("\\[", "&#091;");
+	old_metadata_value_string = old_metadata_value_string.replaceAll("\\]", "&#093;");
+	new_metadata_value_string = new_metadata_value_string.replaceAll("\\[", "&#091;");
+	new_metadata_value_string = new_metadata_value_string.replaceAll("\\]", "&#093;");
+
+	// Read all the FileSet elements in the file
+	NodeList fileset_elements_nodelist = document.getElementsByTagName(FILESET_ELEMENT);
+	for (int i = 0; i < fileset_elements_nodelist.getLength(); i++) {
+	    Element current_fileset_element = (Element) fileset_elements_nodelist.item(i);
+	    boolean current_fileset_matches = false;
+
+	    // Check the FileName elements of the FileSet to see if we have a match
+	    NodeList filename_elements_nodelist = current_fileset_element.getElementsByTagName(FILENAME_ELEMENT);
+	    for (int j = 0; j < filename_elements_nodelist.getLength(); j++) {
+		Element current_filename_element = (Element) filename_elements_nodelist.item(j);
+		String current_filename_element_value = XMLTools.getElementTextValue(current_filename_element);
+
+		// Only exact matches can be edited
+		if (current_filename_element_value.equals(file_path_regexp)) {
+		    current_fileset_matches = true;
+		    break;
+		}
+	    }
+
+	    // The FileSet doesn't apply, so move onto the next one
+	    if (current_fileset_matches == false) {
+		continue;
+	    }
+
+	    // Each metadata value is only allowed to be assigned once
+	    boolean new_metadata_value_already_exists = false;
+	    Element metadata_element_to_edit = null;
+
+	    // Find the Metadata element to replace in the fileset
+	    String metadata_element_name_full = old_metadata_value.getMetadataElement().getFullName();
+	    NodeList metadata_elements_nodelist = current_fileset_element.getElementsByTagName(METADATA_ELEMENT);
+	    for (int k = 0; k < metadata_elements_nodelist.getLength(); k++) {
+		Element current_metadata_element = (Element) metadata_elements_nodelist.item(k);
+
+		// Check the metadata element name matches
+		String current_metadata_element_name_full = current_metadata_element.getAttribute("name");
+		if (!current_metadata_element_name_full.equals(metadata_element_name_full)) {
+		    continue;
+		}
+
+		// Check the new metadata value doesn't already exist
+		String current_metadata_value_string = XMLTools.getElementTextValue(current_metadata_element);
+		if (current_metadata_value_string.equals(new_metadata_value_string)) {
+		    new_metadata_value_already_exists = true;
+		}
+
+		// Check the metadata element value matches
+		if (current_metadata_value_string.equals(old_metadata_value_string)) {
+		    metadata_element_to_edit = current_metadata_element;
+		}
+	    }
+
+	    // If the new metadata value already existed, remove the original value
+	    if (new_metadata_value_already_exists) {
+		metadata_element_to_edit.getParentNode().removeChild(metadata_element_to_edit);
+	    }
+	    // Otherwise replace the old value with the new value
+	    else {
+		XMLTools.setElementTextValue(metadata_element_to_edit, new_metadata_value_string);
+	    }
+	}
+
+	// Rewrite the metadata.xml file
+	XMLTools.writeXMLFile(this, document);
+    }
+
+
+    /**
+     * Every metadata.xml file must be skimmed when a collection is opened, for two reasons:
+     *   - To build complete and accurate metadata value trees (needed for Enrich pane and hierarchy files)
+     *   - To handle any non-namespaced metadata in the file
+     */
+    public void skimFile()
+    {
+	boolean file_changed = false;
+
+	// Parse the metadata.xml file
+	DebugStream.println("Skimming metadata.xml file " + this + "...");
+	Document document = XMLTools.parseXMLFile(this);
+	if (document == null) {
+	    System.err.println("Error: Could not parse metadata.xml file " + getAbsolutePath());
+	    return;
+	}
+
+	// Read all the Metadata elements in the file
+	NodeList metadata_elements_nodelist = document.getElementsByTagName(METADATA_ELEMENT);
+	for (int i = 0; i < metadata_elements_nodelist.getLength(); i++) {
+	    Element current_metadata_element = (Element) metadata_elements_nodelist.item(i);
+	    String metadata_element_name_full = current_metadata_element.getAttribute("name");
+	    String metadata_set_namespace = MetadataTools.getMetadataSetNamespace(metadata_element_name_full);
+
+	    // Ignore legacy crap
+	    if (metadata_set_namespace.equals("hidden")) {
+		continue;
+	    }
+
+	    MetadataSet metadata_set = MetadataSetManager.getMetadataSet(metadata_set_namespace);
+	    if (metadata_set == null) {
+		// The metadata set isn't loaded, so give the option of mapping the element into a loaded set
+		String target_metadata_element_name_full = MetadataSetManager.mapUnloadedMetadataElement(metadata_element_name_full);
+		if (target_metadata_element_name_full == null || target_metadata_element_name_full.equals("")) {
+		    // Skip this element if we still don't have a loaded element for it
+		    continue;
+		}
+
+		// Update the metadata.xml file to have the new element name
+		current_metadata_element.setAttribute("name", target_metadata_element_name_full);
+		file_changed = true;
+
+		metadata_element_name_full = target_metadata_element_name_full;
+		metadata_set_namespace = MetadataTools.getMetadataSetNamespace(metadata_element_name_full);
+		metadata_set = MetadataSetManager.getMetadataSet(metadata_set_namespace);
+	    }
+
+	    String metadata_element_name = MetadataTools.getMetadataElementName(metadata_element_name_full);
+	    MetadataElement metadata_element = metadata_set.getMetadataElementWithName(metadata_element_name);
+
+	    // If the element doesn't exist in the metadata set, add it
+	    if (metadata_element == null) {
+		metadata_element = metadata_set.addMetadataElementForThisSession(metadata_element_name);
+	    }
+
+	    // Square brackets need to be escaped because they are a special character in Greenstone
+	    String metadata_value_string = XMLTools.getElementTextValue(current_metadata_element);
+	    metadata_value_string = metadata_value_string.replaceAll("&#091;", "[");
+	    metadata_value_string = metadata_value_string.replaceAll("&#093;", "]");
+
+	    metadata_element.addMetadataValue(metadata_value_string);
+	}
+
+	// Rewrite the metadata.xml file if it has changed
+	if (file_changed) {
+	    XMLTools.writeXMLFile(this, document);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFileManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFileManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/MetadataXMLFileManager.java	(revision 10506)
@@ -0,0 +1,390 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer.metadata;
+
+
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.collection.CollectionTreeNode;
+import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
+import org.greenstone.gatherer.util.XMLTools;
+
+
+/** This class is a static class that manages the metadata.xml files */
+public class MetadataXMLFileManager
+{
+    static private ArrayList metadata_xml_files = new ArrayList();
+    /** The objects listening for MetadataChanged events. */
+    static private ArrayList metadata_changed_listeners = new ArrayList();
+    /** Keep track of which metadata.xml files have been modified so we can upload them to the server */
+    static private ArrayList modified_metadata_xml_files = new ArrayList();
+
+
+    static public void addMetadata(CollectionTreeNode file_node, ArrayList metadata_values)
+    {
+	addMetadata(new CollectionTreeNode[] { file_node }, metadata_values);
+    }
+
+
+    static public void addMetadata(CollectionTreeNode[] file_nodes, MetadataValue metadata_value)
+    {
+	ArrayList metadata_values = new ArrayList();
+	metadata_values.add(metadata_value);
+	addMetadata(file_nodes, metadata_values);
+    }
+
+
+    static public void addMetadata(CollectionTreeNode[] file_nodes, ArrayList metadata_values)
+    {
+	// Check the list of metadata values is non-empty
+	if (metadata_values.isEmpty()) {
+	    return;
+	}
+
+	// Add the metadata to each file node in turn
+	for (int i = 0; i < file_nodes.length; i++) {
+	    File current_file = file_nodes[i].getFile();
+	    DebugStream.println("Adding metadata to " + current_file.getAbsolutePath());
+
+	    // Find which metadata.xml file needs editing
+	    boolean applicable_metadata_xml_file_found = false;
+	    File current_file_directory = (current_file.isDirectory() ? current_file : current_file.getParentFile());
+	    String current_file_directory_path = current_file_directory.getAbsolutePath();
+	    for (int j = 0; j < metadata_xml_files.size(); j++) {
+		MetadataXMLFile metadata_xml_file = (MetadataXMLFile) metadata_xml_files.get(j);
+
+		// This metadata.xml file is only applicable if it is at the same level as the file
+		if (current_file_directory_path.equals(metadata_xml_file.getParentFile().getAbsolutePath())) {
+		    applicable_metadata_xml_file_found = true;
+		    metadata_xml_file.addMetadata(current_file, metadata_values);
+		    if (!modified_metadata_xml_files.contains(metadata_xml_file)) {
+			modified_metadata_xml_files.add(metadata_xml_file);
+		    }
+		}
+	    }
+
+	    // If no applicable metadata.xml file exists, we have to create a new one
+	    if (!applicable_metadata_xml_file_found) {
+		// Create a new (empty) metadata.xml file in the file's directory...
+		File new_metadata_xml_file_file = new File(current_file_directory, "metadata.xml");
+		XMLTools.writeXMLFile(new_metadata_xml_file_file, XMLTools.parseXMLFile("xml/metadata.xml", true));
+
+		// ...load it...
+		MetadataXMLFile new_metadata_xml_file = loadMetadataXMLFile(new_metadata_xml_file_file);
+
+		// ...and add the metadata
+		new_metadata_xml_file.addMetadata(current_file, metadata_values);
+		if (!modified_metadata_xml_files.contains(new_metadata_xml_file)) {
+		    modified_metadata_xml_files.add(new_metadata_xml_file);
+		}
+	    }
+	}
+
+	// Let any listeners know that the metadata has changed
+	fireMetadataChangedEvent(file_nodes);
+
+	// Upload the modified metadata.xml files to the server, if we're using one
+	uploadModifiedMetadataXMLFiles();
+    }
+
+
+    static public void addMetadataChangedListener(MetadataChangedListener metadata_changed_listener)
+    {
+	metadata_changed_listeners.add(metadata_changed_listener);
+    }
+
+
+    static public void clearMetadataXMLFiles()
+    {
+	metadata_xml_files.clear();
+    }
+
+
+    static private void fireMetadataChangedEvent(CollectionTreeNode[] file_nodes)
+    {
+	// Send the event off to all the MetadataChangedListeners
+	for (int i = 0; i < metadata_changed_listeners.size(); i++) {
+	    ((MetadataChangedListener) metadata_changed_listeners.get(i)).metadataChanged(file_nodes);
+	}
+    }
+
+
+    /** Returns the metadata assigned to a file outside the collection, excluding folder-level/inherited metadata. */
+    static public ArrayList getMetadataAssignedDirectlyToExternalFile(File file)
+    {
+	DebugStream.println("Getting metadata assigned directly to external file " + file + "...");
+
+	// Build up a list of applicable metadata.xml files
+	ArrayList applicable_metadata_xml_files = new ArrayList();
+
+	File directory = (file.isDirectory() ? file : file.getParentFile());
+	while (directory != null) {
+	    File[] directory_files = directory.listFiles();
+	    for (int i = 0; i < directory_files.length; i++) {
+		File child_file = directory_files[i];
+		if (!child_file.isDirectory() && child_file.getName().equals("metadata.xml")) {
+		    // It is very important that shallower files come before deeper ones
+		    applicable_metadata_xml_files.add(0, new MetadataXMLFile(child_file.getAbsolutePath()));
+		}
+	    }
+
+	    directory = directory.getParentFile();
+	}
+
+	// Get the metadata assigned to the specified file from the applicable metadata.xml files
+	ArrayList assigned_metadata = getMetadataAssignedToFile(file, applicable_metadata_xml_files);
+
+	// Remove any folder-level metadata
+	for (int i = assigned_metadata.size() - 1; i >= 0; i--) {
+	    if (((MetadataValue) assigned_metadata.get(i)).isInheritedMetadata()) {
+		assigned_metadata.remove(i);
+	    }
+	}
+
+	return assigned_metadata;
+    }
+
+
+    /** Returns the metadata assigned to a file inside the collection, excluding folder-level/inherited metadata. */
+    static public ArrayList getMetadataAssignedDirectlyToFile(File file)
+    {
+	// Get all the metadata assigned to the specified file...
+	ArrayList assigned_metadata = getMetadataAssignedToFile(file);
+
+	// ...then remove any folder-level metadata
+	for (int i = assigned_metadata.size() - 1; i >= 0; i--) {
+	    if (((MetadataValue) assigned_metadata.get(i)).isInheritedMetadata()) {
+		assigned_metadata.remove(i);
+	    }
+	}
+
+	return assigned_metadata;
+    }
+
+
+    /** Returns all the metadata assigned to a file inside the collection. */
+    static public ArrayList getMetadataAssignedToFile(File file)
+    {
+	// Build up a list of applicable metadata.xml files
+	ArrayList applicable_metadata_xml_files = new ArrayList();
+
+	// Look at each loaded metadata.xml file to see if it is potentially applicable
+	String file_directory_path = (file.isDirectory() ? file : file.getParentFile()).getAbsolutePath() + File.separator;
+	for (int i = 0; i < metadata_xml_files.size(); i++) {
+	    MetadataXMLFile metadata_xml_file = (MetadataXMLFile) metadata_xml_files.get(i);
+
+	    // This metadata.xml file is only potentially applicable if it is above or at the same level as the file
+	    if (file_directory_path.startsWith(metadata_xml_file.getParentFile().getAbsolutePath() + File.separator)) {
+		applicable_metadata_xml_files.add(metadata_xml_file);
+	    }
+	}
+
+	// Return the metadata assigned to the specified file from the applicable metadata.xml files
+	return getMetadataAssignedToFile(file, applicable_metadata_xml_files);
+    }
+
+
+    static private ArrayList getMetadataAssignedToFile(File file, ArrayList applicable_metadata_xml_files)
+    {
+	// Build up a list of metadata values assigned to this file
+	ArrayList metadata_values_all = new ArrayList();
+
+	// Look at each applicable metadata.xml file to see if it assigns metadata to this file
+	for (int i = 0; i < applicable_metadata_xml_files.size(); i++) {
+	    MetadataXMLFile metadata_xml_file = (MetadataXMLFile) applicable_metadata_xml_files.get(i);
+	    DebugStream.println("Applicable metadata.xml file: " + metadata_xml_file);
+
+	    ArrayList metadata_values = metadata_xml_file.getMetadataAssignedToFile(file);
+	    for (int j = 0; j < metadata_values.size(); j++) {
+		MetadataValue metadata_value = (MetadataValue) metadata_values.get(j);
+
+		// Overriding metadata: remove any values with this metadata element
+		if (metadata_value.isAccumulatingMetadata() == false) {
+		    for (int k = metadata_values_all.size() - 1; k >= 0; k--) {
+			if (((MetadataValue) metadata_values_all.get(k)).getMetadataElement().equals(metadata_value.getMetadataElement())) {
+			    metadata_values_all.remove(k);
+			}
+		    }
+		}
+
+		metadata_values_all.add(metadata_value);
+	    }
+	}
+
+	return metadata_values_all;
+    }
+
+
+    static public void loadMetadataXMLFiles(File directory)
+    {
+	// Make sure the directory (import) exists
+	if (directory.exists() == false) {
+	    return;
+	}
+
+	// Look recursively at each subfile of the directory for metadata.xml files
+	File[] directory_files = directory.listFiles();
+	for (int i = 0; i < directory_files.length; i++) {
+	    File child_file = directory_files[i];
+	    if (child_file.isDirectory()) {
+		loadMetadataXMLFiles(child_file);
+	    }
+	    else if (child_file.getName().equals("metadata.xml")) {
+		loadMetadataXMLFile(child_file);
+	    }
+	}
+    }
+
+
+    static private MetadataXMLFile loadMetadataXMLFile(File metadata_xml_file_file)
+    {
+	MetadataXMLFile metadata_xml_file = new MetadataXMLFile(metadata_xml_file_file.getAbsolutePath());
+	metadata_xml_file.skimFile();
+	metadata_xml_files.add(metadata_xml_file);
+	return metadata_xml_file;
+    }
+
+
+    static public void removeMetadata(CollectionTreeNode file_node, ArrayList metadata_values)
+    {
+	removeMetadata(new CollectionTreeNode[] { file_node }, metadata_values);
+    }
+
+
+    static public void removeMetadata(CollectionTreeNode[] file_nodes, MetadataValue metadata_value)
+    {
+	ArrayList metadata_values = new ArrayList();
+	metadata_values.add(metadata_value);
+	removeMetadata(file_nodes, metadata_values);
+    }
+
+
+    static public void removeMetadata(CollectionTreeNode[] file_nodes, ArrayList metadata_values)
+    {
+	// Check the list of metadata values is non-empty
+	if (metadata_values.isEmpty()) {
+	    return;
+	}
+
+	// Remove the metadata from each file node in turn
+	for (int i = 0; i < file_nodes.length; i++) {
+	    File current_file = file_nodes[i].getFile();
+	    DebugStream.println("Removing metadata from " + current_file.getAbsolutePath());
+
+	    // Find which metadata.xml file needs editing
+	    File current_file_directory = (current_file.isDirectory() ? current_file : current_file.getParentFile());
+	    String current_file_directory_path = current_file_directory.getAbsolutePath();
+	    for (int j = 0; j < metadata_xml_files.size(); j++) {
+		MetadataXMLFile metadata_xml_file = (MetadataXMLFile) metadata_xml_files.get(j);
+
+		// This metadata.xml file is only potentially applicable if it is above or at the same level as the file
+		if (current_file_directory_path.startsWith(metadata_xml_file.getParentFile().getAbsolutePath())) {
+		    metadata_xml_file.removeMetadata(current_file, metadata_values);
+		    if (!modified_metadata_xml_files.contains(metadata_xml_file)) {
+			modified_metadata_xml_files.add(metadata_xml_file);
+		    }
+		}
+	    }
+	}
+
+	// Let any listeners know that the metadata has changed
+	fireMetadataChangedEvent(file_nodes);
+
+	// Upload the modified metadata.xml files to the server, if we're using one
+	uploadModifiedMetadataXMLFiles();
+    }
+
+
+    static public void removeMetadataChangedListener(MetadataChangedListener metadata_changed_listener)
+    {
+	metadata_changed_listeners.remove(metadata_changed_listener);
+    }
+
+
+    static public void replaceMetadata(CollectionTreeNode[] file_nodes, MetadataValue old_metadata_value, MetadataValue new_metadata_value)
+    {
+	// Replace the metadata in each file node in turn
+	for (int i = 0; i < file_nodes.length; i++) {
+	    File current_file = file_nodes[i].getFile();
+	    DebugStream.println("Replacing metadata in " + current_file.getAbsolutePath());
+
+	    // Find which metadata.xml file needs editing
+	    File current_file_directory = (current_file.isDirectory() ? current_file : current_file.getParentFile());
+	    String current_file_directory_path = current_file_directory.getAbsolutePath();
+	    for (int j = 0; j < metadata_xml_files.size(); j++) {
+		MetadataXMLFile metadata_xml_file = (MetadataXMLFile) metadata_xml_files.get(j);
+
+		// This metadata.xml file is only applicable if it is at the same level as the file
+		if (current_file_directory_path.equals(metadata_xml_file.getParentFile().getAbsolutePath())) {
+		    metadata_xml_file.replaceMetadata(current_file, old_metadata_value, new_metadata_value);
+		    if (!modified_metadata_xml_files.contains(metadata_xml_file)) {
+			modified_metadata_xml_files.add(metadata_xml_file);
+		    }
+		}
+	    }
+	}
+
+	// Let any listeners know that the metadata has changed
+	fireMetadataChangedEvent(file_nodes);
+
+	// Upload the modified metadata.xml files to the server, if we're using one
+	uploadModifiedMetadataXMLFiles();
+    }
+
+
+    static public void unloadMetadataXMLFile(File metadata_xml_file_file)
+    {
+	DebugStream.println("Unloading metadata.xml file " + metadata_xml_file_file);
+
+	// Find the metadata.xml file in the list of loaded files, and remove it
+	for (int i = 0; i < metadata_xml_files.size(); i++) {
+	    MetadataXMLFile metadata_xml_file = (MetadataXMLFile) metadata_xml_files.get(i);
+	    if (metadata_xml_file_file.getAbsolutePath().equals(metadata_xml_file.getAbsolutePath())) {
+		metadata_xml_files.remove(i);
+		break;
+	    }
+	}
+    }
+
+
+    static private void uploadModifiedMetadataXMLFiles()
+    {
+	// This is only necessary when the collection is stored on a remote server
+	if (Gatherer.isGsdlRemote) {
+	    if (modified_metadata_xml_files.isEmpty()) {
+		DebugStream.println("No modified metadata.xml files to upload.");
+		return;
+	    }
+
+	    // Upload the files modified since last time, then reset the list
+	    RemoteGreenstoneServer.uploadCollectionFiles((File[]) modified_metadata_xml_files.toArray(new File[0]));
+	    modified_metadata_xml_files.clear();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/ProfileXMLFile.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/ProfileXMLFile.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/ProfileXMLFile.java	(revision 10506)
@@ -0,0 +1,110 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.util.XMLTools;
+import org.w3c.dom.*;
+
+
+/** This class represents one profile.xml file */
+public class ProfileXMLFile
+    extends File
+{
+    private HashMap metadata_mapping = null;
+
+
+    public ProfileXMLFile(String profile_xml_file_path)
+    {
+	super(profile_xml_file_path);
+    }
+
+
+    public String getMetadataElementFor(String metadata_element_name_full)
+    {
+	if (getMetadataMapping() == null) {
+	    return null;
+	}
+
+	return (String) metadata_mapping.get(metadata_element_name_full);
+    }
+
+
+    public HashMap getMetadataMapping()
+    {
+	// If we have already loaded the metadata mapping, use it
+	if (metadata_mapping != null) {
+	    return metadata_mapping;
+	}
+
+	// Build the metadata mapping from the profile.xml file
+	metadata_mapping = new HashMap();
+
+	// Parse the profile.xml file
+	Document document = XMLTools.parseXMLFile(this);
+	if (document == null) {
+	    System.err.println("Error: Could not parse profile.xml file " + getAbsolutePath());
+	    return null;
+	}
+
+	// Read all the Action elements in the file
+	NodeList action_elements_nodelist = document.getElementsByTagName("Action");
+	for (int i = 0; i < action_elements_nodelist.getLength(); i++) {
+	    Element current_action_element = (Element) action_elements_nodelist.item(i);
+	    String source_metadata_element_name_full = current_action_element.getAttribute("source");
+	    String target_metadata_element_name_full = current_action_element.getAttribute("target");
+	    metadata_mapping.put(source_metadata_element_name_full, target_metadata_element_name_full);
+	}
+
+	return metadata_mapping;
+    }
+
+
+    public void mapElement(String source_metadata_element_name_full, String target_metadata_element_name_full)
+    {
+	// Parse the profile.xml file
+	Document document = XMLTools.parseXMLFile(this);
+	if (document == null) {
+	    System.err.println("Error: Could not parse profile.xml file " + getAbsolutePath());
+	    return;
+	}
+
+	// Create a new Action element to record this mapping
+	Element new_action_element = document.createElement("Action");
+	new_action_element.setAttribute("source", source_metadata_element_name_full);
+	new_action_element.setAttribute("target", target_metadata_element_name_full);
+	document.getDocumentElement().appendChild(new_action_element);
+
+	// Rewrite the profile.xml file
+	XMLTools.writeXMLFile(this, document);
+
+	// Invalidate the metadata mapping
+	metadata_mapping = null;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/ProfileXMLFileManager.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/ProfileXMLFileManager.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/metadata/ProfileXMLFileManager.java	(revision 10506)
@@ -0,0 +1,90 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2004 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.gatherer.metadata;
+
+
+import java.io.*;
+import java.util.*;
+import org.greenstone.gatherer.util.XMLTools;
+
+
+/** This class is a static class that manages the profile.xml file */
+public class ProfileXMLFileManager
+{
+    static private ProfileXMLFile profile_xml_file = null;
+
+
+    static public void clearProfileXMLFile()
+    {
+	profile_xml_file = null;
+    }
+
+
+    static public void loadProfileXMLFile(File directory)
+    {
+	// Make sure the directory (metadata) exists
+	if (directory.exists() == false) {
+	    directory.mkdir();
+	}
+
+	File profile_xml_file_file = new File(directory, "profile.xml");
+	if (!profile_xml_file_file.exists()) {
+	    // Create a new (empty) profile.xml file in this directory...
+	    XMLTools.writeXMLFile(profile_xml_file_file, XMLTools.parseXMLFile("xml/profile.xml", true));
+	}
+
+	profile_xml_file = new ProfileXMLFile(profile_xml_file_file.getAbsolutePath());
+    }
+
+
+    static public String getMetadataElementFor(String metadata_element_name_full)
+    {
+	if (profile_xml_file == null) {
+	    return null;
+	}
+
+	return profile_xml_file.getMetadataElementFor(metadata_element_name_full);
+    }
+
+
+    static public HashMap getMetadataMapping()
+    {
+	if (profile_xml_file == null) {
+	    return null;
+	}
+
+	return profile_xml_file.getMetadataMapping();
+    }
+
+
+    static public void mapElement(String metadata_element_name_full, String target_metadata_element_name_full)
+    {
+	if (profile_xml_file != null) {
+	    profile_xml_file.mapElement(metadata_element_name_full, target_metadata_element_name_full);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/remote/RemoteFileQueue.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/remote/RemoteFileQueue.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/remote/RemoteFileQueue.java	(revision 10506)
@@ -0,0 +1,55 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer.remote;
+
+
+import java.util.*;
+import org.greenstone.gatherer.file.FileNode;
+import org.greenstone.gatherer.util.DragComponent;
+
+
+public class RemoteFileQueue
+    extends Thread
+{
+    /** The queue of waiting jobs. */
+    private ArrayList queue = null;
+
+
+    public RemoteFileQueue()
+    {
+    }
+
+
+    synchronized public void addJob(long id, FileNode[] source_nodes, FileNode target_node, byte type)
+    {
+    }
+
+
+    public void run()
+    {
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/remote/RemoteGreenstoneServer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/remote/RemoteGreenstoneServer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/remote/RemoteGreenstoneServer.java	(revision 10506)
@@ -0,0 +1,275 @@
+/**
+ *#########################################################################
+ *
+ * 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: David Bainbridge, Greenstone Digital Library, University of Waikato
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *########################################################################
+ */
+
+package org.greenstone.gatherer.remote;
+
+import java.io.*;
+import java.net.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.shell.GShell;
+
+
+public class RemoteGreenstoneServer
+{
+    static public void downloadCollection(String collection_name)
+    {
+    }
+
+
+    static public void downloadCollectionConfigurations()
+    {
+    }
+
+
+    static public void downloadCollectionFile(File collection_file)
+    {
+    }
+
+
+    static public String getPathRelativeToDirectory(String file_path, String directory_path)
+    {
+	return "";
+    }
+
+
+    static public void sendDeleteFileCommand(String relative_file_path)
+    {
+    }
+
+
+    static public void uploadCollectionFile(File collection_file)
+    {
+    }
+
+
+    static public void uploadCollectionFiles(File[] collection_files)
+    {
+    }
+
+
+    static public void download_url_zip(String col_name, String dir, GShell source, String accept_expr, String reject_expr)
+    {
+	try {
+	    String download_cgi  = Gatherer.cgiBase + "download";
+
+	    // Send col_name and dir arguments to download cgi
+	    String col_name_encoded = URLEncoder.encode(col_name,"UTF-8");
+	    String dir_encoded = URLEncoder.encode(dir,"UTF-8");
+	    String cgi_args = "c=" + col_name_encoded;
+	    cgi_args += "&dir=" + dir_encoded + "&a=" + accept_expr + "&r=" + reject_expr;
+
+	    URL download_url = new URL(download_cgi);
+
+	    System.err.println("**** download cgi = '" + download_cgi + "'");
+	    System.err.println("**** cgi args = '" + cgi_args + "'");
+
+	    URLConnection dl_connection = download_url.openConnection();
+	    dl_connection.setDoOutput(true);	    
+	    OutputStream dl_os = dl_connection.getOutputStream();
+
+	    PrintWriter dl_out = new PrintWriter(dl_os);
+	    dl_out.println(cgi_args);
+	    dl_out.close();
+
+	    // Download result from running cgi script
+	    InputStream dl_is = dl_connection.getInputStream();
+	    BufferedInputStream dl_bis = new BufferedInputStream(dl_is); 
+	    DataInputStream dl_dbis = new DataInputStream(dl_bis);
+		    
+	    // set up output stream for zip download
+	    String col_dir;
+	    if (col_name.startsWith("/")) {
+		col_dir = Configuration.gsdl_path;
+	    }
+	    else {
+		col_dir = Gatherer.getCollectDirectoryPath();
+	    }
+
+	    String zip_fname = col_dir + col_name + ".zip";
+	    FileOutputStream zip_fos = new FileOutputStream(zip_fname);
+	    BufferedOutputStream zip_bfos = new BufferedOutputStream(zip_fos);
+	    
+	    byte[] buf = new byte[1024];
+	    int len;
+
+	    while ((len = dl_dbis.read(buf)) >= 0 && !source.hasSignalledStop()) {
+		zip_bfos.write(buf,0,len);
+	    }
+
+	    dl_dbis.close();
+	    dl_bis.close();
+	    dl_is.close();
+
+	    zip_bfos.close();
+	    zip_fos.close();
+
+	    if(source.hasSignalledStop()) {
+		//A cancel has been called. Delete the zip file.
+		DebugStream.println("download_url_zip() cancelled. Cleaning up.");
+		if(new File(zip_fname).delete()) {
+		    DebugStream.println("Zip file " + zip_fname + " deleted");
+		}
+		else {
+		    DebugStream.println("Zip file " + zip_fname + " NOT deleted (no big deal). Does it exist?");
+		}
+	    }
+	}
+	catch (Exception error) {
+	    error.printStackTrace();
+	}
+	DebugStream.println("Exited download_url_zip");
+    }
+
+
+    static public void upload_url_zip(String col_name, String dir, String delete_type, GShell source)
+    {
+	final String lineEnd = "\r\n";
+	final String twoHyphens = "--";
+	final String boundary =  "*****";
+	final int maxBufferSize = 1024;
+
+	String col_dir;
+	if (col_name.startsWith("/")) {
+	    col_dir = Configuration.gsdl_path;
+	}
+	else {
+	    col_dir = Gatherer.getCollectDirectoryPath();
+	}
+
+	String zip_fname = col_dir + col_name + ".zip";
+	String upload_cgi = Gatherer.cgiBase + "upload";
+
+	HttpURLConnection conn = null;
+
+	try {
+	    // Send zip file to server
+	    File file = new File(zip_fname);
+	    FileInputStream fileInputStream = new FileInputStream(file);
+
+	    // open a URL connection to the Servlet 
+	    URL url = new URL(upload_cgi);
+	    System.err.println("**** Uploading to: " + upload_cgi);
+
+	    // Open a HTTP connection to the URL
+	    conn = (HttpURLConnection) url.openConnection();
+
+	    conn.setDoInput(true);         // Allow Inputs
+	    conn.setDoOutput(true);        // Allow Outputs
+	    conn.setUseCaches(false);      // Don't use a cached copy.
+	    conn.setRequestMethod("POST"); // Use a post method.
+
+	    conn.setRequestProperty("Connection", "Keep-Alive");	    
+	    conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
+
+	    DataOutputStream dos = new DataOutputStream( conn.getOutputStream() );
+
+	    dos.writeBytes(twoHyphens + boundary + lineEnd);
+	    dos.writeBytes("Content-Disposition: form-data; name=\"c\"" + lineEnd + lineEnd);
+	    dos.writeBytes(col_name + lineEnd);
+	    System.err.println("**** c="+col_name);
+
+	    dos.writeBytes(twoHyphens + boundary + lineEnd);
+	    dos.writeBytes("Content-Disposition: form-data; name=\"dir\"" + lineEnd + lineEnd);
+	    dos.writeBytes(dir + lineEnd);	
+	    System.err.println("**** dir="+dir);
+    
+	    dos.writeBytes(twoHyphens + boundary + lineEnd);
+	    dos.writeBytes("Content-Disposition: form-data; name=\"del\"" + lineEnd + lineEnd);
+	    dos.writeBytes(delete_type + lineEnd);	
+	    System.err.println("**** del="+delete_type);
+
+	    dos.writeBytes(twoHyphens + boundary + lineEnd);
+	    dos.writeBytes("Content-Disposition: form-data; name=\"zip\";"
+			   + " filename=\"" + zip_fname +"\"" + lineEnd);
+	    dos.writeBytes(lineEnd);
+	    System.err.println("**** zip (filename)="+zip_fname);
+
+	    // create a buffer of maximum size	           	    
+	    int bytesAvailable = fileInputStream.available();
+	    int bufferSize = Math.min(bytesAvailable, maxBufferSize);
+	    byte[] buffer = new byte[bufferSize];
+	    
+	    // read file and write it into form...
+	    int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
+
+	    while (bytesRead > 0) {
+		// Check to see if action has been cancelled.
+		if (source != null && source.hasSignalledStop()) {
+		    break;
+		}
+		dos.write(buffer, 0, bufferSize);
+		bytesAvailable = fileInputStream.available();
+		bufferSize = Math.min(bytesAvailable, maxBufferSize);
+		bytesRead = fileInputStream.read(buffer, 0, bufferSize);
+	    }
+	    
+	    // send multipart form data necesssary after file data...
+	    
+	    dos.writeBytes(lineEnd);
+	    dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
+	    
+	    // close streams
+	    
+	    fileInputStream.close();
+	    dos.flush();
+	    dos.close();
+
+	    // delete zip file
+	    boolean file_deleted = file.delete();
+	    if (file_deleted) {
+		System.err.println("Zip file " + file.toString() + " deleted");
+	    }
+	    else {
+		System.err.println("Zip file " + file.toString() + " NOT deleted");
+	    }
+	}
+	catch (MalformedURLException ex) {
+	    System.err.println("Failed on: "+ex);
+	}
+	
+	catch (IOException ioe) {
+	    System.err.println("Failed on: "+ioe);
+	}
+	
+	// Read server response
+	try {
+	    InputStreamReader isr = new InputStreamReader(conn.getInputStream() );
+	    BufferedReader bisr = new BufferedReader (isr);
+	    String str;
+	    while (( str = bisr.readLine()) != null) {
+		System.err.println(str);
+	    }
+	    bisr.close();
+	    
+	}
+	catch (IOException ioex) {
+	    System.err.println("From (ServerResponse): "+ioex);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GBasicProgressMonitor.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GBasicProgressMonitor.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GBasicProgressMonitor.java	(revision 10506)
@@ -0,0 +1,128 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.shell;
+
+
+import java.awt.Component;
+import java.util.ArrayList;
+import javax.swing.JProgressBar;
+
+/** This is the most basic implementation of <i>GShellProgressMonitor</i> in that it doesn't even attempt to parse the process messages. Instead it has one graphic which is displayed once the start() method is called, and another which appears after the stop().
+ */
+public class GBasicProgressMonitor 
+    extends JProgressBar 
+    implements GShellProgressMonitor {
+    /** Whether the process has been asked to stop. */
+    private boolean stop = false;
+    /** Constructor **/
+    public GBasicProgressMonitor() {
+	super();
+    }
+    /** Don't do anything if we are given a progress bar, we have our own.
+     * @param progress_bar A JProgressBar
+     */
+    public void addProgressBar(JProgressBar progress_bar) {
+    }
+    /** Determine the script exit value according to the progress monitor. This gets around a problem where several script failures actually result with a successful exit value.
+     * @return A <i>int</i> with a value of zero if and only if the script was successful.
+     */
+    public int exitValue() {
+	// Always return true as we don't know any better.
+	return 0;
+    }
+    /** As we are probably accessing this via an interface we need to gain
+     * access to the component itself.
+     */
+    public Component getProgress() {
+	return this;
+    }
+
+    public JProgressBar getSharedProgress() {
+	return null;
+    }
+
+    public void messageOnProgressBar(String message)
+    {
+	if ((message!=null) & (message!="")) {
+	    setString(message);
+	}
+	else {
+	    setString(null);
+	}
+    }
+
+
+    /** Method to determine the state of the stop flag, which may be set by the visual component that created this monitor.
+     * @return A <strong>boolean</strong> indicating if the process has been asked to stop.
+     */
+    public boolean hasSignalledStop() {
+	return stop;
+    }
+    /** Inform the progress bar that it should programatically increment progress by one step. */
+    public void increment() {
+	// We can't do anything about this.
+    }
+    /** The parse method is how more complex progress bars figure out how far they have progressed. However we don't.
+     * @param queue a queue which at the moment should contain a single GShellEvent
+     */
+    public void process(ArrayList queue) {
+    }
+
+    public void reset() {};
+
+    public void saving() {
+    }
+
+    /** Since the creator of this process monitor is actually in the GUI, this class provides the simpliest way to send a cancel process message between the two.
+     * @param state The desired state of the stop flag as a <strong>boolean</strong>.
+     */
+    public void setStop(boolean state) {
+	stop = state;
+    }
+    /** This method tells this class that the job it is showing the progress
+     * for has begun.
+     */
+    public void start() {
+	setIndeterminate(true);
+    }
+    /** This method tells this class that the job it is showing the progress
+     * for has come to an end.
+     */
+    public void stop() {
+	setIndeterminate(false);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GBuildProgressMonitor.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GBuildProgressMonitor.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GBuildProgressMonitor.java	(revision 10506)
@@ -0,0 +1,545 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.shell;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import javax.swing.JProgressBar;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.cdm.CollectionDesignManager;
+import org.greenstone.gatherer.util.StaticStrings;
+/** This implementation of <i>GShellProgressMonitor</i> is designed to parse and translate the progress of a buildcol.pl call.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class GBuildProgressMonitor
+    implements GShellProgressMonitor {
+    /** The minimum value = 0 */
+    static final private int MIN = 0;
+    /** In order to get a smoothish progress bar, set the maximum to a large number = 1000000 */
+    static final private int MAX = 1000000;
+    /** The various states the build progress state machine can be in, starting at the base state. */
+    static final int BASE                          = -1;
+    static final int BUILD                         =  0;
+    static final int COMPRESSTEXT                  = 10;
+    static final int COMPRESSTEXT_COLLECTTEXTSTATS = 11;
+    static final int COMPRESSTEXT_CREATINGCOMPRESS = 12;
+    static final int COMPRESSTEXT_COMPRESSINGTEXT  = 13;
+    static final int INDEX                         = 20;
+    static final int INDEX_CREATINGINDEXDIC        = 21;
+    static final int INDEX_INVERTINGTEXT           = 22;
+    static final int INDEX_CREATETHEWEIGHTS        = 23;
+    static final int INDEX_CREATESTEMMEDDIC        = 24;
+    static final int INDEX_CREATINGSTEMINDX        = 25;
+    static final int CREATEINFODATA                = 30;
+    static final int PHIND                         = 40;
+    static final int PHIND_EXTRACTINGVOCAB         = 41;
+    static final int PHIND_EXTRACTINGPHRASE        = 42;
+    static final int PHIND_SORTANDRENUMBER         = 43;
+    static final int PHIND_PHRASEDATABASES         = 44;
+    static final int PHIND_WORDLEVELINDEXES        = 45;
+    static final int PHIND_DOCINFODATABASES        = 46;
+    static final int CREATINGAUXILARY              = 50;
+    /** Now the language independant sentinel strings. */
+    static final String BUILD_ELEMENT          = "Build";
+    static final String COLLECTTEXTSTATS_VALUE = "CollectTextStats";
+    static final String COMPRESSINGTEXT_VALUE  = "CompressingText";
+    static final String COMPRESSTEXT_VALUE     = "CompressText";
+    static final String CREATINGAUXILARY_VALUE = "CreatingAuxilary";
+    static final String CREATINGCOMPRESS_VALUE = "CreatingCompress";
+    static final String CREATINGINDEXDIC_VALUE = "CreatingIndexDic";
+    static final String CREATINGSTEMINDX_VALUE = "CreatingStemIndx";
+    static final String CREATEINFODATA_VALUE   = "CreateInfoData";
+    static final String CREATESTEMMEDDIC_VALUE = "CreateStemmedDic";
+    static final String CREATETHEWEIGHTS_VALUE = "CreateTheWeights";
+    static final String DOCINFODATABASES_VALUE = "DocInfoDatabases";
+    static final String EXTRACTINGPHRASE_VALUE = "ExtractingPhrase";
+    static final String EXTRACTINGVOCAB_VALUE  = "ExtractingVocab";
+    static final String FATALERROR_ELEMENT     = "FatalError";
+    static final String INDEX_VALUE            = "Index";
+    static final String INVERTINGTEXT_VALUE    = "InvertingText";
+    static final String NAME_ATTRIBUTE         = "name";
+    static final String PHASE_ELEMENT          = "Phase";
+    static final String PHIND_VALUE            = "Phind";
+    static final String PHRASEDATABASES_VALUE  = "PhraseDatabases";
+    static final String SKIPCREATINGCOMP_VALUE = "SkipCreatingComp";
+    static final String SORTANDRENUMBER_VALUE  = "SortAndRenumber";
+    static final String SOURCE_ATTRIBUTE       = "source";
+    static final String STAGE_ELEMENT          = "Stage";
+    static final String WARNING_ELEMENT        = "Warning";   
+    static final String WORDLEVELINDEXES_VALUE = "WordLevelIndexes";
+    /** Indicates if the GUI has asked the process this object monitors to stop. */
+    private boolean stop = false;
+    /** The current number of stages we have completed. */
+    private int current_stages = 0;
+    /** The number of stages we are expecting to complete. */
+    private int expected_stages = 0;
+
+    private int threshold = Configuration.SYSTEMS_MODE;
+    /** The current state we are in. The state will change depending on the next flag recieved. */
+    private int state = BASE;
+    /** The progress bar this monitor updates. */
+    private JProgressBar progress_bar;
+    /** A progress bar that is shared between this this listener and the Import monitor. */
+    private JProgressBar shared_progress_bar;
+
+    /** Construct a new GBuildProgressMonitor. */
+    public GBuildProgressMonitor(JProgressBar shared_progress_bar) {
+	this.shared_progress_bar = shared_progress_bar;
+	progress_bar = new JProgressBar();
+	progress_bar.setMaximum(MAX);
+	progress_bar.setMinimum(MIN);
+	progress_bar.setString(null);
+	progress_bar.setStringPainted(true);
+	setValue(MIN);
+    }
+
+    /** Method to register a new progress bar with this monitor.
+     * @param progress_bar The new <strong>JProgressBar</strong>.
+     */	 
+    public void addProgressBar(JProgressBar progress_bar) {
+	this.progress_bar = progress_bar;
+	progress_bar.setMaximum(MAX);
+	progress_bar.setMinimum(MIN);
+	progress_bar.setStringPainted(false);
+	progress_bar.setString(null);
+	setValue(MIN);
+    }
+
+    /** Determine the script exit value according to the progress monitor. This gets around a problem where several script failures actually result with a successful exit value.
+     * @return A <i>int</i> with a value of zero if and only if the script was successful.
+     */
+    public int exitValue() {
+	if(state == BASE) {
+	    return 0;
+	}
+	return 1;
+    }
+    /** Method to retrieve whatever control is being used as the progress indicator. Usually a <strong>JProgressBar</strong> but there may be others implemented later.
+     * @return A <strong>Component</strong> on which the progress of the process is being displayed.
+     */
+    public Component getProgress() {
+	return progress_bar;
+    }
+
+    public JProgressBar getSharedProgress() {
+	return shared_progress_bar;
+    }
+
+    public void messageOnProgressBar(String message)
+    {
+	if ((message!=null) & (message!="")) {
+	    progress_bar.setString(message);
+	    shared_progress_bar.setString(message);
+	}
+	else {
+	    progress_bar.setString(null);
+	    shared_progress_bar.setString(null);
+	}
+    }
+
+    /** Method to determine the state of the stop flag, which may be set by the visual component that created this monitor.
+     * @return A <strong>boolean</strong> indicating if the process has been asked to stop.
+     */
+    public synchronized boolean hasSignalledStop() {
+	return stop;
+    }
+    /** Inform the progress bar that it should programatically increment progress by one step. */
+    public void increment() {
+	// There is no reason this should be called for a build.
+    }
+
+    /** This method is used to 'feed in' a line of text captured from the process.
+     * @param queue a queue which at the moment should contain a single GShellEvent
+     */
+    public void process(ArrayList queue) {
+	GShellEvent event = (GShellEvent) queue.get(0);
+	// Remove 'build.pl> ' bit
+	String line = event.getMessage();
+	line = line.substring(line.indexOf(StaticStrings.GREATER_THAN_CHARACTER) + 1);
+	line = line.trim();
+	// We are only really interested in processing pseudo-XML tags
+	if(line.startsWith(StaticStrings.LESS_THAN_CHARACTER) && line.endsWith(StaticStrings.GREATER_THAN_CHARACTER)) {
+	    // All events are vetoed
+	    event.veto();
+	    
+	    // Create a new element from it
+	    GShellElement element = new GShellElement(line);
+	    // Now change states within the state machine as appropriate. A state change may subsequently incur a progress update.
+	    String name = null;
+	    String value = null;
+	    switch(state) {
+	    case BASE:
+		// The only thing we would expect is a build message
+		name = element.getElementName();
+		if(name.equals(BUILD_ELEMENT)) {
+		    progress_bar.setIndeterminate(false);
+		    state = BUILD;
+		    // Produce a lower detail message if required
+		    if(Configuration.getMode() <= threshold && !stop) {
+			queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Build.BuildBegun1"), event.getStatus()));
+		    }
+		}
+		else {
+		    // Unknown command, go indeterminate
+		    DebugStream.println("Unknown name: " + name);
+		    progress_bar.setIndeterminate(true);
+		}
+		name = null;
+		break;
+	    case BUILD:
+		// The only thing we would expect is a stage element
+		name = element.getElementName();
+		if(name.equals(STAGE_ELEMENT)) {
+		    progress_bar.setIndeterminate(false);
+		    // Now we determine what stage we are moving to
+		    value = element.getAttribute(NAME_ATTRIBUTE);
+		    if(value.equals(COMPRESSTEXT_VALUE)) {
+			state = COMPRESSTEXT;
+			if(Configuration.getMode() <= threshold) {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Build.CompressText"), event.getStatus()));
+			}
+		    }
+		    else if(value.equals(INDEX_VALUE)) {
+			state = INDEX;
+			if(Configuration.getMode() <= threshold) {
+			    String args[] = new String[1];
+			    args[0] = element.getAttribute(SOURCE_ATTRIBUTE);
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Build.Index", args), event.getStatus()));
+			    args = null;
+			}
+		    }
+		    else if(value.equals(CREATEINFODATA_VALUE)) {
+			state = CREATEINFODATA;
+			if(Configuration.getMode() <= threshold) {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Build.InfoDatabase"), event.getStatus()));
+			}
+		    }
+		    else if(value.equals(PHIND_VALUE)) {
+			state = PHIND;
+			if(Configuration.getMode() <= threshold) {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Build.Phind"), event.getStatus()));
+			}
+		    }
+		    else if(value.equals(CREATINGAUXILARY_VALUE)) {
+			state = CREATINGAUXILARY;
+			if(Configuration.getMode() <= threshold) {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Build.Auxilary"), event.getStatus()));
+			}
+		    }
+		    else {
+			// Unknown command, go indeterminate
+			DebugStream.println("Unknown value: " + value);
+			progress_bar.setIndeterminate(true);
+		    }
+		    value = null;
+		}
+		// The build end message indicates a successfulish build.
+		else if(name.equals(BUILD_ELEMENT) && element.isClosed()) {
+		    progress_bar.setIndeterminate(false);
+		    setValue(MAX);
+		    state = BASE;
+		    if(Configuration.getMode() <= threshold) {
+			queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Build.BuildComplete1"), event.getStatus()));
+		    }
+		}
+		else {
+		    // Unknown command, go indeterminate
+		    DebugStream.println("Unknown name: " + name);
+		    progress_bar.setIndeterminate(true);
+		}
+		name = null;
+		break;
+	    case COMPRESSTEXT:
+		// We are either dealing with a phase, aa fatal error or an end stage
+		name = element.getElementName();
+		if(name.equals(PHASE_ELEMENT)) {
+		    // There are three phases within compressing text (or of four possible ones)
+		    value = element.getAttribute(NAME_ATTRIBUTE);
+		    if(value.equals(COLLECTTEXTSTATS_VALUE)) {
+			// Nothing to do
+		    }
+		    else if(value.equals(CREATINGCOMPRESS_VALUE) || value.equals(SKIPCREATINGCOMP_VALUE)) {
+			// One third complete
+			progress_bar.setIndeterminate(false);
+			setValue((int)(((double)current_stages + 0.3d) * MAX) / expected_stages);
+		    }
+		    else if(value.equals(COMPRESSINGTEXT_VALUE)) {
+			// Two thirds complete
+			progress_bar.setIndeterminate(false);
+		        setValue((int)(((double)current_stages + 0.6d) * MAX) / expected_stages);
+		    }
+		    else {
+			// Unknown command, go indeterminate
+			DebugStream.println("Unknown value: " + value);
+			progress_bar.setIndeterminate(true);
+		    }
+		    value = null;
+		}
+		// Note that a fatal error is always followed by an end-stage, but not an end build. Thus the final state will be build (not base) and calls to exitValue() with indicate failure.
+		else if(name.equals(FATALERROR_ELEMENT)) {
+		    // On simplier modes produce a meaningful message
+		    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Build.FatalError"), event.getStatus()));
+		}
+		else if(name.equals(STAGE_ELEMENT) && element.isClosed()) {
+		    // Increase progress so that stage is complete.
+		    current_stages++;
+		    progress_bar.setIndeterminate(false);
+		    setValue((current_stages * MAX) / expected_stages);
+		    state = BUILD;
+		}
+		else {
+		    // Unknown command, go indeterminate
+		    DebugStream.println("Unknown name: " + name);
+		    progress_bar.setIndeterminate(true);
+		}
+		name = null;
+		break;
+	    case INDEX:
+		/** @todo - If on lower modes output a meaningful message. */
+		name = element.getElementName();
+		if(name.equals(PHASE_ELEMENT)) {
+		    value = element.getAttribute(NAME_ATTRIBUTE);
+		    if(value.equals(CREATINGINDEXDIC_VALUE)) {
+			// Nothing to do
+		    }
+		    else if(value.equals(INVERTINGTEXT_VALUE)) {
+			// One fifth complete
+			progress_bar.setIndeterminate(false);
+			setValue((int)(((double)current_stages + 0.2d) * MAX) / expected_stages);
+		    }
+		    else if(value.equals(CREATETHEWEIGHTS_VALUE)) {
+			// Two fifths complete
+			progress_bar.setIndeterminate(false);
+			setValue((int)(((double)current_stages + 0.4d) * MAX) / expected_stages);
+		    }
+		    else if(value.equals(CREATESTEMMEDDIC_VALUE)) {
+			// Three fifths complete
+			progress_bar.setIndeterminate(false);
+			setValue((int)(((double)current_stages + 0.6d) * MAX) / expected_stages);
+		    }
+		    else if(value.equals(CREATINGSTEMINDX_VALUE)) {
+			// Four fifths complete
+			progress_bar.setIndeterminate(false);
+			setValue((int)(((double)current_stages + 0.8d) * MAX) / expected_stages);
+		    }
+		    else {
+			// Unknown command, go indeterminate
+			DebugStream.println("Unknown value: " + value);
+			progress_bar.setIndeterminate(true); 
+		    }
+		    value = null;
+		}
+		else if(name.equals(WARNING_ELEMENT)) {
+		    /** @todo - If on lower modes output a meaningful message. */
+		}
+		// Note that a fatal error is always followed by an end-stage, but not an end build. Thus the final state will be build (not base) and calls to exitValue() with indicate failure.
+		else if(name.equals(FATALERROR_ELEMENT)) {
+		    // On lower modes output a meaningful message.
+		    
+		}
+		else if(name.equals(STAGE_ELEMENT) && element.isClosed()) {
+		    // Increase progress so that stage is complete.
+		    current_stages++;
+		    progress_bar.setIndeterminate(false);
+		    setValue((current_stages * MAX) / expected_stages);
+		    state = BUILD;
+		}
+		else {
+		    // Unknown command, go indeterminate
+		    DebugStream.println("Unknown name: " + name);
+		    progress_bar.setIndeterminate(true); 
+		}
+		name = null;
+		break;
+	    case PHIND:
+		name = element.getElementName();
+		if(name.equals(PHASE_ELEMENT)) {
+		    value = element.getAttribute(NAME_ATTRIBUTE);
+		    if(value.equals(EXTRACTINGVOCAB_VALUE)) {
+			// Nothing to do
+		    }
+		    else if(value.equals(EXTRACTINGPHRASE_VALUE)) {
+			// One sixth complete
+			progress_bar.setIndeterminate(false);
+			setValue((int)(((double)current_stages + 0.16d) * MAX) / expected_stages);
+		    }
+		    else if(value.equals(SORTANDRENUMBER_VALUE)) {
+			// Two sixths complete
+			progress_bar.setIndeterminate(false);
+		        setValue((int)(((double)current_stages + 0.33d) * MAX) / expected_stages);
+		    }
+		    else if(value.equals(PHRASEDATABASES_VALUE)) {
+			// Three sixths complete
+			progress_bar.setIndeterminate(false);
+		        setValue((int)(((double)current_stages + 0.5d) * MAX) / expected_stages);
+		    }
+		    else if(value.equals(WORDLEVELINDEXES_VALUE)) {
+			// Four sixths complete
+			progress_bar.setIndeterminate(false);
+			setValue((int)(((double)current_stages + 0.66d) * MAX) / expected_stages);
+		    }
+		    else if(value.equals(DOCINFODATABASES_VALUE)) {
+			// Five sixths complete
+			progress_bar.setIndeterminate(false);
+			setValue((int)(((double)current_stages + 0.83d) * MAX) / expected_stages);
+		    }
+		    else {
+			// Unknown command, go indeterminate
+			DebugStream.println("Unknown value: " + value);
+			progress_bar.setIndeterminate(true); 
+		    }
+		    value = null;
+		}
+		else if(name.equals(STAGE_ELEMENT) && element.isClosed()) {
+		    // Increase progress so that stage is complete.
+		    current_stages++;
+		    progress_bar.setIndeterminate(false);
+		    setValue((current_stages * MAX) / expected_stages);
+		    state = BUILD;
+		}
+		else {
+		    // Unknown command, go indeterminate
+		    DebugStream.println("Unknown name: " + name);
+		    progress_bar.setIndeterminate(true); 
+		}
+		name = null;
+		break;
+	    case CREATEINFODATA:
+	    case CREATINGAUXILARY:
+		name = element.getElementName();
+		if(name.equals(STAGE_ELEMENT) && element.isClosed()) {
+		    // Another stage complete
+		    current_stages++;
+		    progress_bar.setIndeterminate(false);
+		    setValue((current_stages * MAX) / expected_stages);
+		    state = BUILD;
+		}
+		else {
+		    // Unknown command, go indeterminate
+		    DebugStream.println("Unknown name: " + name);
+		    progress_bar.setIndeterminate(true);
+		}
+		name = null;
+		break;
+	    default:
+		// Unknown command, go indeterminate
+		DebugStream.println("Unknown name: " + name);
+		progress_bar.setIndeterminate(true);
+	    }
+	}
+	// If we are dealing with lower detail modes then veto any other messages. We do this here as the progress monitors are garuenteed to recieve this message before anything else
+	else if(Configuration.getMode() <= threshold) {
+	    event.veto();
+	}
+    }
+
+    public void reset() {
+	current_stages = 0;
+	expected_stages = 0;
+	progress_bar.setIndeterminate(false);
+	progress_bar.setString(null);
+	setValue(MIN);
+	state = BASE;
+	progress_bar.updateUI();
+    }
+
+    public void saving() {
+    }
+
+    public void setSharedProgressBar(JProgressBar shared_progress_bar) {
+	this.shared_progress_bar = shared_progress_bar;
+    }
+
+    /** Since the creator of this process monitor is actually in the GUI, this class provides the simpliest way to send a cancel process message between the two.
+     * @param state The desired state of the stop flag as a <strong>boolean</strong>.
+     */
+    public synchronized void setStop(boolean state) {
+	this.stop = state;
+	progress_bar.setIndeterminate(false);
+    }
+    /** This method resets this monitor to the start, reseting the process parsing and progress bar.
+     * TODO Everthing.
+     */
+    public void start() {
+	stop = false;
+	setValue(MIN);
+	expected_stages = 3; // Always compress text, create info database and auxiliary creation
+	// Retrieve cdm.
+	CollectionDesignManager cdm = Gatherer.c_man.getCollection().cdm;
+	// If we are using MGPP the number of indexes is always 1
+	if(cdm.searchtype_manager.isMGPPEnabled()) {
+	    expected_stages = expected_stages + 1;
+	}
+	else {
+	    int num_indexes = cdm.index_manager.getSize();
+	    int num_partitions = cdm.subcollectionindex_manager.getSize();
+	    if(num_partitions > 0) {
+		num_indexes = num_indexes * num_partitions;
+	    }
+	    int num_languages = cdm.language_manager.getSize();
+	    if(num_languages > 0) {
+		num_indexes = num_indexes * num_languages;
+	    }
+	    expected_stages = expected_stages + num_indexes;
+	}
+	// And if we have a phind classifier, we have one further index
+	if(cdm.classifier_manager.isPhindClassifierAssigned()) {
+	    expected_stages = expected_stages + 1;
+	}
+	cdm = null;
+    }
+    /** This method indicates the process is complete. 
+     * TODO Everthing.
+     */
+    public void stop() {
+	progress_bar.setIndeterminate(false);
+	setValue(MAX);
+    }
+
+    private void setValue(int value) {
+	progress_bar.setValue(value);
+	// Incrementing the shared progress bar is a little more problematic as we may very well be trying to set it to MIN but instead set it to halfway if we're not careful.
+	if(value > MIN) {
+	    shared_progress_bar.setValue(MAX + value);
+	}
+    }
+}
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GImportProgressMonitor.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GImportProgressMonitor.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GImportProgressMonitor.java	(revision 10506)
@@ -0,0 +1,421 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.shell;
+
+import java.awt.Component;
+import java.util.*;
+import javax.swing.JProgressBar;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.util.StaticStrings;
+
+/** This implementation of <i>GShellProgressMonitor</i> is designed to parse and translate the progress of a import.pl call.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.1
+ */
+public class GImportProgressMonitor
+    implements GShellProgressMonitor {
+    /** Indicates if the progress bar is currently showing a string. */
+    private boolean showing_string = false;
+    /** Indicates if the GUI has asked the process this object monitors to stop. */
+    private boolean stop = false;
+    /** A count of the extracted files processed so far. */
+    private int extracted_file_count;
+    /** The number of documents processed (or rejected) so far. */
+    private int file_count;
+    /** The next value to be set for the progress bar - I use this rather than a compounding progress measure to try to limit rounding inaccuracies (nothing looks worse than the progress bar having to jump the last 10-15%) */
+    private int next_progress_value;
+    /** The number of files expected to be scanned by this import process. */
+    private int num_expected_docs;
+    /** This holds the number of documents actually processed by the import command, as garnered from the final block of text output. */
+    private int num_docs;
+
+    private int threshold = Configuration.SYSTEMS_MODE;
+    /** The progress bar this monitor updates. */
+    private JProgressBar progress_bar;
+
+    /** The progress bar that is shared with build monitor. */
+    private JProgressBar shared_progress_bar;
+
+    /** */
+    static final private String BLOCKED_ATTRIBUTE = "blocked";
+    static final private String CONSIDERED_ATTRIBUTE = "considered";
+    static final private String FAILED_ATTRIBUTE = "failed";
+    static final private String IGNORED_ATTRIBUTE = "ignored";
+    static final private String IMPORT_ELEMENT = "Import";
+    static final private String PROCESSED_ATTRIBUTE = "processed";    
+    /** */
+    static final private String NAME_ATTRIBUTE = "n";
+    /** */
+    static final private String PLUGIN_ATTRIBUTE = "p";
+    static final private String REASON_ATTRIBUTE = "r";
+    /** The fixed portion of the progress bar used for the calculating of file size and other pre-import functions. */
+    static final private int CALCULATION = 50000;
+    /** The fixed portion of the progress bar used for extracted metadata. */
+    static final private int EXTRACTED = 200000;
+    /** The minimum value for this progress bar. */
+    static final private int MIN = 0;
+    /** The fixed portion of the progress bar used for processed documents. */
+    static final private int PROCESSED = 750000;
+    /** The element name of a file detected message. */
+    static final private String FILE_ELEMENT = "File";
+    /** The element name of a file processing message. */
+    static final private String PROCESSING_ELEMENT = "Processing";
+    /** The element name of a processing error message. */
+    static final private String PROCESSINGERROR_ELEMENT = "ProcessingError";
+    /** The element name of an import complete message. */
+    static final private String IMPORTCOMPLETE_ELEMENT = "ImportComplete";
+    /** The element name of a file not processed. */
+    static final private String NONPROCESSEDFILE_ELEMENT = "NonProcessedFile";
+    /** The element name of a file not recognised. */
+    static final private String NONRECOGNISEDFILE_ELEMENT = "NonRecognisedFile";
+    
+
+    public GImportProgressMonitor() {
+	progress_bar = new JProgressBar();
+	progress_bar.setIndeterminate(false);
+	progress_bar.setMaximum(CALCULATION + PROCESSED + EXTRACTED);
+	progress_bar.setMinimum(MIN);
+	progress_bar.setString(null);
+	progress_bar.setStringPainted(true);
+	next_progress_value = CALCULATION;
+	shared_progress_bar = new JProgressBar();
+	shared_progress_bar.setIndeterminate(false);
+	shared_progress_bar.setMaximum((CALCULATION + PROCESSED + EXTRACTED) * 2);
+	shared_progress_bar.setMinimum(MIN);
+	shared_progress_bar.setString(null); // Default string
+	shared_progress_bar.setStringPainted(true);
+	setValue(MIN);
+    }
+
+    /** Method to register a new progress bar with this monitor.
+     * @param progress_bar The new <strong>JProgressBar</strong>.
+     */
+    public void addProgressBar(JProgressBar progress_bar) {
+	this.progress_bar = progress_bar;
+	progress_bar.setMaximum(CALCULATION + PROCESSED + EXTRACTED);
+	progress_bar.setMinimum(MIN);
+	setValue(MIN);
+	next_progress_value = CALCULATION;
+    }
+
+    /** Determine the script exit value according to the progress monitor. This gets around a problem where several script failures actually result with a successful exit value.
+     * @return A <i>int</i> with a value of zero if and only if the script was successful.
+     */
+    public int exitValue() {
+	if(num_docs > 0) {
+	    return 0;
+	}
+	return 1;
+    }
+
+    /** Retrieve the number of documents recorded by the import monitor during the execution of the import scripts.
+     * @return An <i>int</i> giving the document number.
+     */
+    public int getNumberOfDocuments() {
+	return num_docs;
+    }
+
+    /** Method to retrieve whatever control is being used as the progress indicator. Usually a <strong>JProgressBar</strong> but there may be others implemented later.
+     * @return A <strong>Component</strong> on which the progress of the process is being displayed.
+     */
+    public Component getProgress() {
+	return progress_bar;
+    }
+
+    public JProgressBar getSharedProgress() {
+	return shared_progress_bar;
+    }
+
+    public void messageOnProgressBar(String message)
+    {
+	if ((message!=null) & (message!="")) {
+	    progress_bar.setString(message);
+	    shared_progress_bar.setString(message);
+	    showing_string = true;
+	}
+	else {
+	    progress_bar.setString(null);
+	    shared_progress_bar.setString(null);
+	    showing_string = false;
+	}
+    }
+
+    /** Method to determine the state of the stop flag, which may be set by the visual component that created this monitor.
+     * @return A <strong>boolean</strong> indicating if the process has been asked to stop.
+     */
+    public synchronized boolean hasSignalledStop() {
+	return stop;
+    }
+
+    /** Inform the progress bar that it should programatically increment progress by one step. This is only called during the metadata archive extraction so each step should be (1000000 / 5) / num_docs. */
+    public void increment() {
+	extracted_file_count++;
+	// The current progress is calculated to be:
+	// The fixed calculation value plus the fixed processed value plus some portion of the fixed extracted value. This portion is the extracted_file_count over the total number of documents available. Note that this breaks badly for bibliographical files (for now).
+	setValue(CALCULATION + PROCESSED + ((EXTRACTED * extracted_file_count) / num_docs));
+    }
+
+    /** This method is used to 'feed in' a line of text captured from the process.
+     * @param queue a queue which at the moment should contain a single GShellEvent
+     */
+    public void process(ArrayList queue) {
+	// Retrieve the first event.
+	GShellEvent event = (GShellEvent) queue.get(0);
+	// Remove 'import.pl> ' bit
+	String line = event.getMessage();
+	line = line.substring(line.indexOf(StaticStrings.GREATER_THAN_CHARACTER) + 1);
+	line = line.trim();
+	// System.err.println("**** line = " + line);
+
+	///ystem.err.println("Process: " + line);
+	if(line.startsWith(StaticStrings.LESS_THAN_CHARACTER) && line.endsWith(StaticStrings.GREATER_THAN_CHARACTER)) {
+	    // No original event is passed on, even in the lower modes
+	    event.veto();
+	    // Create a new element from it
+	    GShellElement element = new GShellElement(line);
+	    String name = element.getElementName();
+	    ///ystem.err.println("Gatherer tag: " + name);
+	    // We may be reading a file. Remember we have to offset process as we recieve this message 'before' a document is processed. Hence the use of 'next_progress_value'
+	    if(name.equals(IMPORT_ELEMENT)) {
+		///ystem.err.println("#Import");
+		// We're into parsing output, so we don't need the 'calculating file size' etc string.
+		if(showing_string) {
+		    progress_bar.setString(null);
+		    showing_string = false;
+		}
+		if(Configuration.getMode() <= threshold) {
+		    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.ImportBegun1"), event.getStatus()));
+		}
+	    }
+	    else if(name.equals(FILE_ELEMENT)) {
+		///ystem.err.println("#File");
+		file_count++;
+		// Set the next progress
+		if(next_progress_value > 0) {
+		    setValue(next_progress_value);
+		}
+		// Now we calculate the next progress value
+		next_progress_value = CALCULATION + ((PROCESSED * file_count) / num_expected_docs);
+		event.veto(); // Unconditional veto
+	    }
+	    // Or we're being told what plugin is actually processing the file
+	    else if(name.equals(PROCESSING_ELEMENT)) {
+		///ystem.err.println("#FileProcessing");
+		// If we are at lower mode settings fire a new 'dumbed down' event
+		if(Configuration.getMode() <= threshold) {
+		    String args[] = new String[2];
+		    args[0] = element.getAttribute(NAME_ATTRIBUTE);
+		    args[1] = element.getAttribute(PLUGIN_ATTRIBUTE);
+		    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.FileProcessing", args), event.getStatus()));
+		    args = null;
+		}
+	    }
+	    // processing error
+	    else if (name.equals(PROCESSINGERROR_ELEMENT)) {
+		if(Configuration.getMode() <= threshold) {
+		    String args[] = new String[1];
+		    args[0] = element.getAttribute(NAME_ATTRIBUTE);
+		    String reason = element.getAttribute(REASON_ATTRIBUTE);
+		    if (reason == null || reason.equals("")) {
+			queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.FileProcessingError", args), event.getStatus()));
+		    }
+		    else {
+			queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.FileProcessingError", args) + " (" + reason + ")", event.getStatus()));
+		    }
+		    args = null;
+		}
+	    }
+	    // unrecognised file
+	    else if (name.equals(NONRECOGNISEDFILE_ELEMENT)) {
+		if(Configuration.getMode() <= threshold) {
+		    String args[] = new String[1];
+		    args[0] =element.getAttribute(NAME_ATTRIBUTE);
+		    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.FileNotRecognised", args), event.getStatus()));
+		    args = null;
+		}
+	    }
+	    // unprocessed file
+	    else if (name.equals(NONPROCESSEDFILE_ELEMENT)) {
+		if(Configuration.getMode() <= threshold) {
+		    String args[] = new String[1];
+		    args[0] =element.getAttribute(NAME_ATTRIBUTE);		    
+		    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.FileNotProcessed", args), event.getStatus()));
+		    args = null;
+		}
+	    }
+	    // Or the import complete element
+	    else if(name.equals(IMPORTCOMPLETE_ELEMENT)) {
+		// Set the next progress
+		setValue(next_progress_value);
+		// If we are at lower mode settings fire a new 'dumbed down' event
+		if(Configuration.getMode() <= threshold) {
+		    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.ImportComplete1"), event.getStatus()));
+		    String considered_str = element.getAttribute(CONSIDERED_ATTRIBUTE);
+
+		    if (considered_str.equals(StaticStrings.ONE_CHARACTER)) {
+			queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.ImportComplete2.1"), event.getStatus()));	
+		    } else {
+			queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.ImportComplete2", considered_str), event.getStatus()));
+		    }
+		    considered_str = null;
+		    // The number of documents processed
+		    String processed_str = element.getAttribute(PROCESSED_ATTRIBUTE);
+		    if(!processed_str.equals(StaticStrings.ZERO_CHARACTER)) {
+			if(processed_str.equals(StaticStrings.ONE_CHARACTER)) {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), "    "+Dictionary.get("GShell.Import.ImportComplete.Processed.1"), event.getStatus()));
+			}
+			else {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), "    "+Dictionary.get("GShell.Import.ImportComplete.Processed", processed_str), event.getStatus()));
+			}
+		    }
+		    // Try to set num docs
+		    try {
+			num_docs = Integer.parseInt(processed_str);
+		    }
+		    catch(Exception exception) {
+			num_docs = 0;
+		    }  
+		    processed_str = null;
+
+		    // The number of documents blocked
+		    String blocked_str = element.getAttribute(BLOCKED_ATTRIBUTE);
+		    if(!blocked_str.equals(StaticStrings.ZERO_CHARACTER)) {
+			if (blocked_str.equals(StaticStrings.ONE_CHARACTER)) {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), "    "+Dictionary.get("GShell.Import.ImportComplete.Blocked.1"), event.getStatus()));
+			} else {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), "    "+Dictionary.get("GShell.Import.ImportComplete.Blocked", blocked_str), event.getStatus()));
+			}
+		    }
+		    blocked_str = null;
+		    
+		    // The number of documents ignored
+		    String ignored_str = element.getAttribute(IGNORED_ATTRIBUTE);
+		    if(!ignored_str.equals(StaticStrings.ZERO_CHARACTER)) {
+			if(ignored_str.equals(StaticStrings.ONE_CHARACTER)) {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), "    "+Dictionary.get("GShell.Import.ImportComplete.Ignored.1"), event.getStatus()));
+			} else {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), "    "+Dictionary.get("GShell.Import.ImportComplete.Ignored", ignored_str), event.getStatus()));
+			}
+		    }
+		    ignored_str = null;
+		    
+		    // The number of documents failed
+		    String failed_str = element.getAttribute(FAILED_ATTRIBUTE);
+		    if(!failed_str.equals(StaticStrings.ZERO_CHARACTER)) {
+			if(failed_str.equals(StaticStrings.ONE_CHARACTER)) {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), "    "+Dictionary.get("GShell.Import.ImportComplete.Failed.1"), event.getStatus()));
+			} else {
+			    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), "    "+Dictionary.get("GShell.Import.ImportComplete.Failed", failed_str), event.getStatus()));
+			}
+		    }
+		    failed_str = null;
+		    // Message is finally ready
+		    queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.ImportComplete3"), event.getStatus()));
+		} // if mode below threshhold
+		else {
+		    // Try to set num docs
+		    String processed_str = element.getAttribute(PROCESSED_ATTRIBUTE);
+		    try {
+			num_docs = Integer.parseInt(processed_str);
+		    }
+		    catch(Exception exception) {
+			num_docs = 0;
+		    }
+		}
+	    }
+	    else {
+		// Veto it
+		event.veto();
+	    }
+	} // GLI output
+	else if(Configuration.getMode() <= threshold) {
+	    event.veto();
+	}
+    }
+
+    public void reset() {
+	setValue(MIN);
+	progress_bar.setString(null);
+	progress_bar.updateUI();
+    }
+
+    public void saving() {
+	progress_bar.setString(Dictionary.get("SaveProgressDialog.Title"));
+	showing_string = true;
+    }
+
+    /** Since the creator of this process monitor is actually in the GUI, this class provides the simpliest way to send a cancel process message between the two.
+     * @param state The desired state of the stop flag as a <strong>boolean</strong>.
+     */
+    public synchronized void setStop(boolean state) {
+	this.stop = state;
+    }
+
+    /** This method resets this monitor to the start, reseting the process parsing and progress bar.
+     */
+    public void start() {
+	stop = false;
+	setValue(MIN);
+	progress_bar.setString(Dictionary.get("FileActions.Calculating_Size"));
+	showing_string = true;
+	extracted_file_count = 0;
+	file_count = 0;
+	next_progress_value = -1;
+	num_docs = -1;
+	num_expected_docs = Gatherer.c_man.getCollection().getCount();
+    }
+
+    /** This method indicates the process is complete. 
+     */
+    public void stop() {
+	setValue(CALCULATION + PROCESSED + EXTRACTED);
+    }
+
+    int previous_value = -1;
+    private void setValue(int value) {
+	progress_bar.setValue(value);
+	shared_progress_bar.setValue(value);
+	if(value != 0 && value < previous_value) {
+	    DebugStream.println("Progress is decreasing! " + previous_value + " -> " + value);
+	}
+	previous_value = value;
+    }
+}
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShell.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShell.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShell.java	(revision 10506)
@@ -0,0 +1,790 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.shell;
+
+import java.io.*;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.regex.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.cdm.CollectionConfiguration;
+import org.greenstone.gatherer.cdm.CollectionDesignManager;
+import org.greenstone.gatherer.cdm.CollectionMetaManager;
+import org.greenstone.gatherer.cdm.CollectionMeta;
+import org.greenstone.gatherer.metadata.DocXMLFileManager;
+import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
+import org.greenstone.gatherer.util.StaticStrings; 
+import org.greenstone.gatherer.util.Utility;
+import org.greenstone.gatherer.util.ZipTools;
+
+
+/** The <strong>GShell</strong> is reponsible for running a separately threaded process in the command shell. This is necessary for executing the Perl Scripts and also for other system related funcitonality.
+ */
+public class GShell
+    extends Thread {
+    /** A flag used to determine if this process has been asked to cancel. */
+    private boolean cancel = false;
+    /** The list of listeners associated with this class. */
+    private EventListenerList listeners = null;
+    /** The current status of this shell process. */
+    private int status = -1;
+    /** The type of message being sent. */
+    private int msg_type = -1;
+    /** The type of shell process. */
+    private int type = -1;
+    /** The caller of this process, and thus the class most interested in messages. */
+    private GShellListener caller = null;
+    /** The progress monitor associated with this process. */
+    private GShellProgressMonitor progress = null;
+    /** Arguments to be given to the process (including the executable you are calling. */
+    private String args[] = null;
+    /** Elements in process type enumeration. */
+    static final public int BUILD = 0;
+    static final public int IMPORT = 1;
+    static final public int NEW = 2;
+    static final public int EXPORTAS = 3;
+    static final public int CDIMAGE = 4;
+    static final public int CONVERT = 5;
+    static final public int EXPLODE = 6;
+
+    /** Elements in status type enumeration. */
+    static final public int ERROR = 0;
+    static final public int OK = 1;
+    static final public int CANCELLED = 2;
+
+    /** Elements in process type name enumeration. */
+    static public String GSHELL_BUILD = "gshell_build";
+    static public String GSHELL_IMPORT = "gshell_import";
+    static public String GSHELL_NEW = "gshell_new";
+    static public String GSHELL_EXPORTAS = "gshell_exportas";
+    static public String GSHELL_CDIMAGE = "gshell_cdimage";
+    static public String GSHELL_CONVERT = "gshell_convert";
+    static public String GSHELL_EXPLODE = "gshell_explode";
+
+    /** 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) {
+	    DebugStream.printStackTrace(exception);
+	}
+	return process_running;
+    }
+
+    /** Constructor gatherer all the data required to create a new process, and emit meaningfull messages.
+     * @param args A <strong>String[]</strong> containing the arguments to the process thread, including the name of the executable.
+     * @param type An <strong>int</strong> that indicates what group of processes this process belongs to, as some are treated slightly differently (i.e an IMPORT type process is always followed by a BUILD one).
+     * @param msg_type As process threads may be background (like a makecol.pl call) or important processes in their own right (such as an IMPORT-BUILD) we must be able to set what level messages posted by this class will have by usings this <strong>int</strong>.
+     * @param caller The default <i>GShellListener</i> that is interested in the progress of this process.
+     * @param progress The <i>GShellProgressMonitor</i> associated with this process.
+     * @param name A <strong>String</strong> identifier given to the process, for convience and debug reasons.
+     */
+    public GShell(String args[], int type, int msg_type, GShellListener caller, GShellProgressMonitor progress, String name) {
+	super(name);
+	this.args = args;
+	this.msg_type = msg_type;
+	this.type = type;
+	this.caller = caller;
+	this.progress = progress;
+	this.status = 0;
+	// Lower this jobs priority
+	this.setPriority(Thread.MIN_PRIORITY);
+	listeners = new EventListenerList();
+	listeners.add(GShellListener.class, caller);
+    }
+    /** This method adds another shell listener to this process.
+     * @param listener The new <i>GShellListener</i>.
+     */
+    public void addGShellListener(GShellListener listener) {
+	listeners.add(GShellListener.class, listener);
+    }
+    /** This method removes a certain shell listener from this process.
+     * @param listener The <i>GShellListener</i> to be removed.
+     */
+    /* private void removeGShellListener(GShellListener listener) {
+       listeners.remove(GShellListener.class, listener);
+       } */
+
+
+
+    protected boolean got_stream_char(InputStreamReader isr, StringBuffer line_buffer,
+				      BufferedOutputStream bos) throws IOException 
+    {
+	// Hopefully this doesn't block if the process is trying to write to STDOUT/STDERR.
+
+	boolean input_status = false;
+
+	if(isr.ready()) {
+	    input_status = true;
+	    int c = isr.read();
+	    if(c == '\n' || c == '\r') {
+		if(line_buffer.length() > 0) {
+		    String line = line_buffer.toString();
+		    DebugStream.println("* " + line + " *");
+		    fireMessage(type, typeAsString(type) + "> " + line, status, bos);
+		    line = null;
+		    line_buffer = new StringBuffer();
+		}
+	    }
+	    else {
+		line_buffer.append((char)c);
+	    }
+	}
+
+	return input_status;
+    }
+
+
+    protected StringBuffer get_stream_char(InputStreamReader isr, StringBuffer line_buffer,
+				   BufferedOutputStream bos) throws IOException 
+    {
+	int c = isr.read();
+	///atherer.println("isr: '" + (char) c + "'");
+	if(c == '\n' || c == '\r') {
+	    if(line_buffer.length() > 0) {
+		String line = line_buffer.toString();
+		// DebugStream.println("* " + line + " *");
+		fireMessage(type, typeAsString(type) + "> " + line, status, bos);
+		line_buffer = new StringBuffer();
+	    }
+	}
+	else {
+	    line_buffer.append((char)c);
+	}
+
+	return line_buffer;
+    }
+
+
+    protected int check_for_error(String line, StringBuffer error_list, 
+				  int error_count)
+    {
+	if (line.startsWith("ERROR:")) {
+	    error_count++;
+	    if (error_count<10) {
+		error_list.append(line);
+	    }
+	    else if (error_count==10) {
+		error_list.append("...\n");
+	    }
+	}
+	return error_count;
+    }
+	    
+
+    protected void runRemote(String[] args, BufferedOutputStream bos) 
+    {
+	System.err.println("The level of design processing needed is: " + CollectionDesignManager.getRebuildTypeRequired()); //Will add smart design processing
+	if(hasSignalledStop()) { return; }
+	int error_count = 0;
+	StringBuffer error_list = new StringBuffer();
+	try {
+	    if (type == IMPORT) {
+		String col_name = args[args.length-1];
+		if (progress!=null) {
+		    progress.messageOnProgressBar("Uploading data to server");
+		}
+
+		String collect_directory_path = Gatherer.getCollectDirectoryPath();
+		
+		//Only upload the parts of the import folder (files/metadata) that has been changed.
+		//Or upload the lot if we are doing a complete rebuild.
+		if(Gatherer.c_man.getCollection().getFilesChanged() || !Gatherer.g_man.create_pane.isIncremental()) {
+		    // zip up import folder, but exclude metadata
+		    ZipTools.zipup(collect_directory_path, col_name, "import", this, "", ".*metadata\\.xml");
+
+		    if(hasSignalledStop()) { return; }
+		    // upload it to gsdl server
+		    RemoteGreenstoneServer.upload_url_zip(col_name, "import", "files", this);
+
+		    Gatherer.c_man.getCollection().setFilesChanged(false);
+		    System.err.println("Finished uploading files");
+		}
+		if(Gatherer.c_man.getCollection().getMetadataChanged() || !Gatherer.g_man.create_pane.isIncremental()) {
+		    // zip up metadata from import folder
+		    ZipTools.zipup(collect_directory_path, col_name, "import", this, ".*metadata\\.xml", "");
+
+		    if(hasSignalledStop()) { return; }
+		    // upload it to gsdl server
+		    RemoteGreenstoneServer.upload_url_zip(col_name, "import", "metadata", this);
+		    Gatherer.c_man.getCollection().setMetadataChanged(false);
+		    System.err.println("Finished uploading metadata.");
+		}
+		
+		if(hasSignalledStop()) { return; }
+		// upload etc folder to server (need collect.cfg and any hfiles)
+		ZipTools.zipup(collect_directory_path, col_name, "etc", this, "", "");
+
+		if(hasSignalledStop()) { return; }
+		RemoteGreenstoneServer.upload_url_zip(col_name, "etc", "", this);
+
+		String collection_directory_path = Gatherer.c_man.getCollectionDirectoryPath(col_name);
+		File img_dir = new File(Gatherer.c_man.getCollectionImagesDirectoryPath());
+		if (img_dir.exists() && img_dir.list().length > 0) {
+		    // upload images/ directory to server
+		    if(hasSignalledStop()) { return; }
+		    ZipTools.zipup(collect_directory_path, col_name, "images", this, "", "");
+
+		    if(hasSignalledStop()) { return; }
+		    RemoteGreenstoneServer.upload_url_zip(col_name, "images", "", this);
+
+		    System.err.println("collect_directory_path: " + collect_directory_path);
+		    System.err.println("col_name: " + col_name);
+		}
+
+		if(hasSignalledStop()) { return; }
+		// see if collection specific image needs uploading
+		CollectionMetaManager cmm 
+		    = CollectionDesignManager.collectionmeta_manager;
+		
+		CollectionMeta icon_collection_collectionmeta 
+		    = cmm.getMetadatum(CollectionConfiguration.COLLECTIONMETADATA_ICONCOLLECTION_STR);
+		CollectionMeta icon_collection_small_collectionmeta 
+		    = cmm.getMetadatum(CollectionConfiguration.COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR);
+		
+		String ics_text = icon_collection_collectionmeta.getValue(CollectionMeta.TEXT);
+		String icsc_text = icon_collection_small_collectionmeta.getValue(CollectionMeta.TEXT);
+		if ((ics_text != null) && (ics_text != "")) {
+		    // Stub code for detecting when collectoin image changed
+		    // => need to upload images
+		    // System.err.println("**** ics_text = " + ics_text);
+		}
+		
+		if (progress!=null) {
+		    progress.messageOnProgressBar("");
+		}
+	    }
+	    
+	    if(hasSignalledStop()) { return; }
+	    String perl_cmd = args[0];
+	    int perl_cmd_root = perl_cmd.lastIndexOf(File.separator);
+	    
+	    if (perl_cmd_root > 0) {
+		String perl_cmd_cut = perl_cmd.substring(perl_cmd_root+1);
+		perl_cmd = perl_cmd_cut;
+	    }
+
+	    String cols_concat = null;
+	    String launch  = Gatherer.cgiBase + "launch";
+	    launch = launch + "?cmd=" + perl_cmd;
+	    
+	    for(int i = 1; i<args.length; i++) {
+		
+		String arg = args[i];
+		
+		if (arg.equals("-collectdir") || arg.equals("-importdir")
+		    || arg.equals("-builddir")) {
+		    // skip it
+		    i++;
+		    continue;
+		}
+				
+		if(arg.startsWith(StaticStrings.MINUS_CHARACTER)) {
+		    String name = arg.substring(1);
+		    launch = launch + "&" + name + "=";
+		    if (i+1<args.length-1) {
+			if (!args[i+1].startsWith(StaticStrings.MINUS_CHARACTER)) {
+			    i++;
+			    String val = URLEncoder.encode(args[i],"UTF-8");
+			    launch = launch + val;
+			}
+		    }
+		}
+		else {
+		    if (cols_concat==null) {
+			cols_concat = arg;
+		    }
+		    else {
+			cols_concat = cols_concat + ":" + arg;
+		    }
+		}
+	    }
+
+	    if (cols_concat!=null) {
+		launch = launch + "&c=" + cols_concat;
+	    }
+
+	    System.err.println("**** launch url = " + launch);
+	    // fireMessage(type, Dictionary.get("GShell.Command") + ": " + launch, status, null); // ****
+	    
+	    URL launch_url = new URL(launch);
+	    URLConnection launch_connection = launch_url.openConnection();
+	    InputStream stdis = launch_connection.getInputStream();
+	    InputStreamReader stdisr = new InputStreamReader(stdis, "UTF-8");
+	    
+	    BufferedReader stdbr = new BufferedReader(stdisr);
+	    
+	    if (type == GShell.NEW) {
+		while(true) {
+		    String line = stdbr.readLine();
+		    if (line == null) { break; }
+		    error_count = check_for_error(line,error_list,error_count);
+		}
+	    }
+	    else {
+		while(!hasSignalledStop()) {
+		    String line = stdbr.readLine();
+		    if (line == null) { break; }
+		    error_count = check_for_error(line,error_list,error_count);
+		    fireMessage(type, typeAsString(type) + "> " + line, status, bos);
+		}
+	    }
+	    stdbr.close();
+	    
+	    if (error_count>0) {
+		status = ERROR;
+		System.err.println(error_list);
+		if (type != GShell.NEW) {
+		    fireMessage(type, typeAsString(type) + "> " + error_list, status, null);
+		}
+	    }
+	    else if(hasSignalledStop()) {
+		//User pressed the cancel button.
+		//Status already set in hasSignalledStop method.
+	    }
+	    else {
+		status = OK;
+		fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Success"), status, null);
+	    }
+	}
+	// Exception
+	catch (Exception exception) {
+	    System.err.println("Exception in GShell.runRemote() - unexpected");
+	    DebugStream.printStackTrace(exception);
+	    status = ERROR;
+	}
+    }
+
+
+    protected void runLocal(String[] args, BufferedOutputStream bos) 
+    {
+	try {
+	    String command = "";
+	    for(int i = 0; i < args.length; i++) {
+		command = command + args[i] + " ";
+	    }
+	    
+	    DebugStream.println("Command: "+command);
+	    ///ystem.err.println("Command: " + command);
+	    fireMessage(type, Dictionary.get("GShell.Command") + ": " + command, status, null);
+	    
+	    Runtime rt = Runtime.getRuntime();
+	    Process prcs = rt.exec(args);
+	    
+	    InputStreamReader eisr = new InputStreamReader( prcs.getErrorStream(), "UTF-8" );
+	    InputStreamReader stdisr = new InputStreamReader( prcs.getInputStream(), "UTF-8"  );
+	
+	    StringBuffer eline_buffer = new StringBuffer();
+	    StringBuffer stdline_buffer = new StringBuffer();
+	
+	    while(type != GShell.NEW && processRunning(prcs) && !hasSignalledStop()) {
+		// Hopefully this doesn't block if the process is trying to write to STDOUT.
+		if((eisr!=null) && eisr.ready()) { 
+		    eline_buffer = get_stream_char(eisr,eline_buffer,bos);
+		}
+		// Hopefully this won't block if the process is trying to write to STDERR
+		else if(stdisr.ready()) {
+		    stdline_buffer = get_stream_char(stdisr,stdline_buffer,bos);
+		}
+		else {
+		    try {
+			sleep(100);
+		    }
+		    catch(Exception exception) {
+		    }
+		}
+	    }
+	
+	    if(!hasSignalledStop()) {
+		// 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(eisr.ready()) {
+		    eline_buffer = get_stream_char(eisr,eline_buffer,bos);
+		}
+	    
+		while(stdisr.ready()) {
+		    stdline_buffer = get_stream_char(stdisr,stdline_buffer,bos);
+		}
+	    
+		// Ensure that any messages still remaining in the string buffers are fired off.
+		if(eline_buffer.length() > 0) {
+		    String eline = eline_buffer.toString();
+		    //DebugStream.println("Last bit of eline: " + eline);
+		    fireMessage(type, typeAsString(type) + "> " + eline, status, bos);
+		    eline = null;
+		}
+	    
+		if(stdline_buffer.length() > 0) {
+		    String stdline = stdline_buffer.toString();
+		    //DebugStream.println("Last bit of stdline: " + stdline);
+		    fireMessage(type, typeAsString(type) + "> " + stdline, status, null);
+		    stdline = null;
+		}
+	    }
+	    else {
+		System.err.println("We've been asked to stop.");
+	    }
+	
+	
+	    if(!hasSignalledStop()) {
+		// Now display final message based on exit value
+	    
+		prcs.waitFor(); 
+
+		if(prcs.exitValue() == 0) {
+		    status = OK;
+		    fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Success"), status, null);
+		}
+		else {
+		    status = ERROR;
+		    fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Failure"), status, null);
+		}
+	    
+		eisr.close();
+		stdisr.close();
+	    }
+	    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 (no it doesn't!)
+		prcs.getInputStream().close();
+		prcs.getErrorStream().close();
+		prcs.getOutputStream().close();
+		prcs.destroy();
+		status = CANCELLED;
+	    }
+	}
+	// Exception
+	catch (Exception exception) {
+	    DebugStream.println("Exception in GShell.runLocal() - unexpected");
+	    DebugStream.printStackTrace(exception);
+	    status = ERROR;
+	}
+    }
+    
+    
+
+    /** Any threaded class must include this method to allow the thread body to be run. */
+    public void run() {
+	String col_name = args[args.length-1];		
+
+	// Determine if the user has asked for an outfile.
+	String out_name = null;
+	BufferedOutputStream bos = null;
+	if(type == IMPORT || type == BUILD) {
+	    if(type == IMPORT) {
+		out_name = (String) Gatherer.c_man.getCollection().import_options.getValue("out");
+	    }
+	    else {
+		out_name = (String) Gatherer.c_man.getCollection().build_options.getValue("out");
+	    }
+	    if(out_name != null && out_name.length() > 0) {
+		try {
+		    bos = new BufferedOutputStream(new FileOutputStream(new File(out_name), true));
+		}
+		catch (Exception error) {
+		    DebugStream.printStackTrace(error);
+		}
+	    }
+	}
+
+	// Issue a processBegun event
+	fireProcessBegun(type, status);
+	if (Gatherer.isGsdlRemote) {
+	    runRemote(args,bos);
+	}
+	else {
+	    runLocal(args,bos);
+	}
+
+	if(status == OK) {
+	    if (type == NEW) {
+		if (Gatherer.isGsdlRemote) {
+		    RemoteGreenstoneServer.download_url_zip(col_name, ".", this, "", "");
+		    if (!hasSignalledStop()) {
+			ZipTools.unzip(Gatherer.getCollectDirectoryPath(), col_name);
+		    }
+		}
+	    }
+	    else if(type == IMPORT) {
+		
+		// download the archives directory (if gsdl server is remote)			
+		if (Gatherer.isGsdlRemote) {
+
+		    if (progress!=null) {
+			progress.messageOnProgressBar("Downloading archive data from server");
+		    }
+
+		    Utility.delete(Gatherer.c_man.getCollectionArchivesDirectoryPath()); // remove current archives
+		    //new File(Gatherer.c_man.getCollectionArchivesDirectoryPath()).mkdir(); //Make a clean dir
+		    RemoteGreenstoneServer.download_url_zip(col_name, "archives", this, ".*doc\\.xml", "");
+		    if (hasSignalledStop()) {
+			// Clean up, then exit
+			fireProcessComplete(type, status);
+			// Close bos
+			if(bos != null) {
+			    try {
+				bos.close();
+				bos = null;
+			    }
+			    catch(Exception error) {
+				DebugStream.printStackTrace(error);
+			    }
+			}
+			return;
+		    }
+		    ZipTools.unzip(Gatherer.getCollectDirectoryPath(), col_name);
+		    
+		    if (progress!=null) {
+			progress.messageOnProgressBar("");
+		    }      
+		}
+
+		// Refresh the DocXMLFileManager
+		fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Parsing_Metadata_Start"), status, null);
+		DocXMLFileManager.clearDocXMLFiles();
+		DocXMLFileManager.loadDocXMLFiles(new File(Gatherer.c_man.getCollectionArchivesDirectoryPath()));
+		fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Parsing_Metadata_Complete"), status, null);
+	    }
+
+ 	    else if(type == BUILD) {
+ 		// download the building directory (if gsdl server is remote)
+ 		if (Gatherer.isGsdlRemote) {
+ 		    if (progress!=null) {
+ 			progress.messageOnProgressBar("Downloading index data from server");
+ 		    }
+
+		    File buildDir = new File(Gatherer.c_man.getCollectionBuildingDirectoryPath());
+ 		    Utility.delete(buildDir); // remove current build dir
+		    //Only need build.cfg
+		    RemoteGreenstoneServer.download_url_zip(col_name, "building", this, ".*build\\.cfg", "");
+		    if (!hasSignalledStop()) {
+			ZipTools.unzip(Gatherer.getCollectDirectoryPath(), col_name);
+		    }
+		    
+ 		    if (progress!=null) {
+ 			progress.messageOnProgressBar("");
+ 		    }
+ 		}
+ 	    }
+	    else if(type == CDIMAGE) {
+		// download exported files from tmp folder (if gsdl server is remote)			
+		if (Gatherer.isGsdlRemote) {
+		    if (progress!=null) {
+			progress.messageOnProgressBar("Downloading CD-ROM data from server");
+		    }
+
+		    // !! TO DO
+		    
+ 		    if (progress!=null) {
+ 			progress.messageOnProgressBar("");
+ 		    }
+		}
+	    }
+	}
+
+	// We're done.	
+	fireProcessComplete(type, status);
+	// Close bos
+	if(bos != null) {
+	    try {
+		bos.close();
+		bos = null;
+	    }
+	    catch(Exception error) {
+		DebugStream.printStackTrace(error);
+	    }
+	}
+    }
+    /** Method for firing a message to all interested listeners.
+     * @param type An <strong>int</strong> indicating the process type.
+     * @param message The message as a <strong>String</strong>.
+     * @param status An <strong>int</strong> specifying the current status of the process.
+     */
+    public void fireMessage(int type, String message, int status, BufferedOutputStream bos) {
+	GShellEvent event = new GShellEvent(this, 0, type, message, status);
+	// If there is a progress monitor attached, pass the event to it first. Note that we pass a queue of messages as the processing may cause one message to be split into several.
+	ArrayList message_queue = new ArrayList();
+	message_queue.add(event);
+	if(progress != null) {
+	    progress.process(message_queue);
+	}
+	for(int j = 0; j < message_queue.size(); j++) {
+	    GShellEvent current_event = (GShellEvent) message_queue.get(j);
+	    // If the event hasn't been vetoed, pass it on to other listeners
+	    if(!current_event.isVetoed()) {
+		Object[] concerned = listeners.getListenerList();
+		for(int i = 0; i < concerned.length ; i++) {
+		    if(concerned[i] == GShellListener.class) {
+			((GShellListener)concerned[i+1]).message(current_event);
+		    }
+		}
+		concerned = null;
+	    }
+	}
+	// And if we have a buffered output stream from error messages, send the message there
+	if(bos != null) {
+	    try {
+		bos.write(message.getBytes(), 0, message.length());
+	    }
+	    catch(Exception exception) {
+		DebugStream.println("Exception in GShell.fireMessage() - unexpected");
+		DebugStream.printStackTrace(exception);
+	    }
+	}
+	message_queue = null;
+	event = null;
+    }
+
+    /** Method for firing a process begun event which is called, strangly enough, when the process begins.
+     * @param type An <strong>int</strong> indicating the process type.
+     * @param status An <strong>int</strong> specifying the current status of the process.
+     */
+    protected void fireProcessBegun(int type, int status) {
+	// Start the progres monitor if available
+	if(progress != null) {
+	    progress.start();
+	}
+	// Fire an event
+	GShellEvent event = new GShellEvent(this, 0, type, "", status);
+	Object[] concerned = listeners.getListenerList();
+	for(int i = 0; i < concerned.length ; i++) {
+	    if(concerned[i] == GShellListener.class) {
+		((GShellListener)concerned[i+1]).processBegun(event);
+	    }
+	}
+    }
+
+
+    /** Method for firing a process complete event which is called, no surprise here, when the process ends.
+     * @param type An <strong>int</strong> indicating the process type.
+     * @param status An <strong>int</strong> specifying the current status of the process.
+     */
+    protected void fireProcessComplete(int type, int status) {
+	// Tidy up by stopping the progress bar. If it was cancelled then the cancel command has arrived via the progress bars and they don't need to be told again (it actually causes problems).
+	if(progress != null && status != CANCELLED) {
+	    progress.stop();
+	}
+	
+	// If we were cancelled, and we are lower details modes, fire off one last message.
+	if(status == CANCELLED && Configuration.getMode() <= Configuration.SYSTEMS_MODE) {
+	    GShellEvent current_event = new GShellEvent(this, 0, type, Dictionary.get("GShell.Build.BuildCancelled"), status);
+	    Object[] concerned = listeners.getListenerList();
+	    for(int i = 0; i < concerned.length ; i++) {
+		if(concerned[i] == GShellListener.class) {
+		    ((GShellListener)concerned[i+1]).message(current_event);
+		}
+	    }
+	    concerned = null;
+	}
+	// And firing off an event
+	GShellEvent event = new GShellEvent(this, 0, type, "", status);
+	Object[] concerned = listeners.getListenerList();
+	for(int i = 0; i < concerned.length ; i++) {
+	    if(concerned[i] == GShellListener.class) {
+		((GShellListener)concerned[i+1]).processComplete(event);
+	    }
+	}
+    }
+
+    /** Method to determine if the user, via the progress monitor, has signalled stop.
+     * @return A <strong>boolean</strong> indicating if the user wanted to stop.
+     */
+    public boolean hasSignalledStop() {
+	boolean has_signalled_stop = false;
+	if(progress != null) {
+	    has_signalled_stop = progress.hasSignalledStop();
+	}
+	if(has_signalled_stop) {
+	    status = CANCELLED;
+	}
+	return has_signalled_stop;
+    }
+
+    /** Converts a type into a text representation.
+     * @param type An <strong>int</strong> which maps to a shell process type.
+     * @return A <strong>String</strong> which is the thread process's text name.
+     */
+    public String typeAsString(int type) {
+	String name = null;
+	switch(type) {
+	case BUILD:
+	    name = "buildcol.pl";
+	    break;
+	case IMPORT:
+	    name = "import.pl";
+	    break;
+	case NEW:
+	    name = "mkcol.pl";
+	    break;
+	case EXPORTAS:
+	    name = "export.pl";
+	    break;
+	case CDIMAGE:
+	    name = "exportcol.pl";
+	    break;
+	case CONVERT:
+	    name = "convert_coll_from_gs2.pl";
+	    break;
+	case EXPLODE:
+	    name = "explode_metadata_database.pl";
+	    break;
+	default:
+	    name = "";
+	}
+	return name;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellElement.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellElement.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellElement.java	(revision 10506)
@@ -0,0 +1,106 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, New Zealand Digital Library, University of Waikato
+ *
+ * Copyright (C) 2004 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.gatherer.shell;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+import org.greenstone.gatherer.util.StaticStrings;
+
+/** This class wraps around a pseudo-XML message we have recieved from an external script, and allows access to the element name, attributes etc via method calls. */
+public class GShellElement {
+    private boolean is_closed = false;
+    private HashMap attributes;
+    private String element_name;
+    /** Create a new element around the message string. The string is expected to start with < and end with > */
+    /** this is a hack - why aren't we using proper XML parsing?? */
+    public GShellElement(String message) {
+	// Remove the angle brackets
+	message = message.substring(1, message.length() - 1);
+	// Tokenize the message
+	StringTokenizer tokenizer = new StringTokenizer(message);
+	// The first token is the element name - be aware it may start with the close tag indicator
+	element_name = tokenizer.nextToken();
+	if(element_name.startsWith(StaticStrings.URL_SEPARATOR_CHARACTER)) {
+	    element_name = element_name.substring(1);
+	    is_closed = true;
+	}
+	// Now while we have remaining tokens
+	while(tokenizer.hasMoreTokens()) {
+	    int index = -1;
+	    // The next token might be a attribute=value pair or it could be the close tag indicator
+	    String token = tokenizer.nextToken();
+	    if(token.equals(StaticStrings.URL_SEPARATOR_CHARACTER)) {
+		is_closed = true;
+	    }
+	    else if(token.length() > 3 && (index = token.indexOf(StaticStrings.EQUALS_CHARACTER)) != -1) {
+		String attribute_name = token.substring(0, index);
+		String attribute_value = token.substring(index + 1);
+		// Value may end in a /
+		if(attribute_value.endsWith(StaticStrings.URL_SEPARATOR_CHARACTER)) {
+		    is_closed = true;
+		    attribute_value = attribute_value.substring(0, attribute_value.length() - 1);
+		}
+		// We may have to strip ' marks off value - if it starts with ' and doesn't end with ' we read in more tokens until we get an ending '
+		if(attribute_value.startsWith(StaticStrings.SINGLE_QUOTE_CHARACTER)) {
+		    while (!attribute_value.endsWith(StaticStrings.SINGLE_QUOTE_CHARACTER) && tokenizer.hasMoreTokens()) {
+			attribute_value += " "+tokenizer.nextToken();
+		    }
+		    if (attribute_value.endsWith(StaticStrings.SINGLE_QUOTE_CHARACTER)) {
+			attribute_value = attribute_value.substring(1, attribute_value.length() - 1);
+		    }
+		}
+		if(attributes == null) {
+		    attributes = new HashMap();
+		}
+		attributes.put(attribute_name, attribute_value);
+		attribute_value = null;
+		attribute_name = null;
+	    }
+	    token = null;
+	}
+	tokenizer = null;
+    }
+
+    public String getAttribute(String attribute_name) {
+	String result = null;
+	if(attributes != null) {
+	    result = (String) attributes.get(attribute_name);
+	}
+	if(result == null) {
+	    result = "";
+	}
+	return result;
+    }
+
+    public String getElementName() {
+	return element_name;
+    }
+
+    public boolean isClosed() {
+	return is_closed;
+    }
+}
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellEvent.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellEvent.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellEvent.java	(revision 10506)
@@ -0,0 +1,120 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.shell;
+
+/** Title:        The Gatherer<br>
+ * Description:  The Gatherer: a tool for gathering and enriching digital collections.<br>
+ * Copyright:    Copyright (c) 2001<br>
+ * Company:      The University of Waikato<br>
+ * Written:        /  /01<br>
+ * Revised:      12/05/02 - Commented<br>
+ *               29/05/02 - Moved into correct package<br>
+ * @author John Thompson, Greenstone Digital Libraries
+ * @version 2.1 */
+import java.awt.AWTEvent;
+
+/** This class encapsulates all the information created by an event within a <strong>GShell</strong> process. */
+public class GShellEvent 
+    extends AWTEvent {
+    /** Allows some part of the program to prevent this message being processed by other parts. */
+    private boolean vetoed = false;
+    /** The status of the process at the completion of event. */
+    private int status = -1;
+    /** The process type (such as COPY, BUILD or IMPORT). */
+    private int type = -1;
+    /** Any message associated with this event. */
+    private String message = null;
+
+    /* Constructor.
+     * @param source The <strong>GShell</strong> that fired this message.
+     * @param id The event identifier as an <strong>int</strong>.
+     * @param type The process type as an <strong>int</strong>.
+     * @param message A <strong>String</strong> representing any message attatched with this event.
+     * @param status The status of the process post event, as an <strong>int</strong>.
+     */
+    public GShellEvent(Object source, int id, int type, String message, int status) {
+	super(source, id);
+	this.message = message;
+	this.status = status;
+	this.type = type;
+    }
+
+    /** Gets the message associated with this event.
+     * @return The message as a <strong>String</strong> or <i>null</i>.
+     */
+    public String getMessage() {
+	return 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 status;
+    }
+
+    /** Gets the type associated with this event. This type can then be matched back to the constants in <strong>GShell</strong>.
+     * @return An <strong>int</strong> signifying the process type.
+     */ 
+    public int getType() {
+	return type;
+    }
+
+    /** Determine if this event has been vetoed by some other part of the GLI
+     * @return true if the event has, and thus shouldn't be further processed, false otherwise.
+     */
+    public boolean isVetoed() {
+	return vetoed;
+    }
+
+    /** Change the message to be displayed by this event - usually from something technical so something easier to understand.
+     * @param message the new message as a String
+     */
+    public void setMessage(String message) {
+	this.message = message;
+    }
+
+    public String toString() {
+	return "org.greenstone.gatherer.shell.GShellEvent[" + message + "," + status + "," + type + "]";
+    }
+
+    /** Prevent this event being processed by other parts of the GLI.
+     */
+    public void veto() {
+	vetoed = true;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellListener.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellListener.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellListener.java	(revision 10506)
@@ -0,0 +1,70 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.shell;
+
+/**
+ * Title:        The Gatherer<br>
+ * Description:  The Gatherer: a tool for gathering and enriching digital collections.<br>
+ * Copyright:    Copyright (c) 2001<br>
+ * Company:      The University of Waikato<br>
+ * Written:        /  /01<br>
+ * Revised:      12/05/02 - Commented<br>
+ *               29/05/02 - Moved into correct package<br>
+ * @author John Thompson, Greenstone Digital Libraries
+ * @version 2.1
+ */
+import java.util.EventListener;
+
+/** This interface details the methods required of a class that wishes to listen to a <strong>GShell</strong>.
+ */
+public interface GShellListener 
+    extends EventListener {
+    /** All implementation of <i>GShellListener</i> must include this method so the listener can be informed of messages from the <strong>GShell</strong>.
+     * @param event A <strong>GShellEvent</strong> that contains, amoung other things, the message.
+     */
+    public void message(GShellEvent event);
+
+    /** All implementation of <i>GShellListener</i> must include this method so the listener can be informed when a <strong>GShell</strong> begins its task.
+     * @param event A <strong>GShellEvent</strong> that contains details of the initial state of the <strong>GShell</strong> before task comencement.
+     */
+    public void processBegun(GShellEvent event);
+
+    /** All implementation of <i>GShellListener</i> must include this method so the listener can be informed when a <strong>GShell</strong> completes its task.
+     * @param event A <strong>GShellEvent</strong> that contains details of the final state of the <strong>GShell</strong> after task completion.
+     */
+    public void processComplete(GShellEvent event);
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellProgressMonitor.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellProgressMonitor.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/shell/GShellProgressMonitor.java	(revision 10506)
@@ -0,0 +1,105 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.shell;
+
+/**
+ * Title:        The Gatherer<br>
+ * Description:  The Gatherer: a tool for gathering and enriching digital collections.<br>
+ * Copyright:    Copyright (c) 2001<br>
+ * Company:      The University of Waikato<br>
+ * Written:        /  /01<br>
+ * Revised:      12/05/02 - Commented<br>
+ *               29/05/02 - Moved into correct package<br>
+ * @author John Thompson, Greenstone Digital Libraries
+ * @version 2.1
+ */
+import java.awt.Component;
+import java.util.ArrayList;
+import javax.swing.JProgressBar;
+
+/** When implemented, this interface allows another class to monitor the progress of a <strong>GShell</strong> process. Specifically implementing classes should be designed to take the textual output from the process and then translate that message into some quanitive measure of progress which can then be shown on the progress bar.
+ */
+public interface GShellProgressMonitor {
+    /** Method to register a new progress bar with this monitor.
+     * @param progress_bar The new <strong>JProgressBar</strong>.
+     */
+    public void addProgressBar(JProgressBar progress_bar);
+
+    /** Determine the script exit value according to the progress monitor. This gets around a problem where several script failures actually result with a successful exit value.
+     * @return A <i>int</i> with a value of zero if and only if the script was successful.
+     */
+    public int exitValue();
+
+    public JProgressBar getSharedProgress();
+
+    /** Method to retrieve whatever control is being used as the progress indicator. Usually a <strong>JProgressBar</strong> but there may be others implemented later.
+     * @return A <strong>Component</strong> on which the progress of the process is being displayed.
+     */
+    public Component getProgress();
+
+    public void messageOnProgressBar(String message);
+
+    /** Method to determine the state of the stop flag, which may be set by the visual component that created this monitor.
+     * @return A <strong>boolean</strong> indicating if the process has been asked to stop.
+     */
+    public boolean hasSignalledStop();
+
+    /** Inform the progress bar that it should programatically increment progress by one step. */
+    public void increment();
+
+    /** This method is used to 'feed in' a line of text captured from the process.
+     * @param queue what will be used as a queue of events, but what, at the moment, should only have one event in it
+     */
+    public void process(ArrayList queue);
+
+    public void reset();
+
+    public void saving();
+
+    /** Since the creator of this process monitor is actually in the GUI, this class provides the simpliest way to send a cancel process message between the two.
+     * @param state The desired state of the stop flag as a <strong>boolean</strong>.
+     */
+    public void setStop(boolean state);
+
+    /** This method resets this monitor to the start, reseting the process parsing and progress bar.
+     */
+    public void start();
+
+    /** This method indicates the process is complete. 
+     */
+    public void stop();
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/AppendLineOnlyFileDocument.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/AppendLineOnlyFileDocument.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/AppendLineOnlyFileDocument.java	(revision 10506)
@@ -0,0 +1,987 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Greenstone Librarian Interface (GLI) application, 
+ * part of the Greenstone digital library software suite from the New 
+ * Zealand Digital Library Project at the University of Waikato, 
+ * New Zealand.
+ *
+ * Author: John Thompson, Greenstone Project, New Zealand Digital Library, 
+ *         University of Waikato
+ *         http://www.nzdl.org
+ *
+ * Copyright (C) 2004 New Zealand Digital Library, University of Waikato
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the 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.gatherer.util;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.gui.GLIButton;
+
+/** A Document whose underlying data is stored in a RandomAccessFile, and whose Element implementations lack the memory hogging problems associated with anything that extends the AbstractDocument class. This Document, for reasons of time constraints and sanity, only provides an editting ability of appending new lines to the end of the current document, perfect for our logging needs, completely useless for text editing purposes. Furthermore, since the append actions tend to somewhat swamp the IO, I'll temporarily store strings in the structure model, and write them out using a separate thread. 
+ * @author John Thompson, Greenstone Project, New Zealand Digital Library, University of Waikato
+ * @version 2.41 final
+ */
+public class AppendLineOnlyFileDocument
+    implements Document {
+    /** A default string to append at the start of each log file. Of special note is the beginning '.' character that will, upon completion of the import/build process, be replaced with a letter indicating the final status of this build attempt. */
+    static final private String GLI_HEADER_STR = ".";
+    /** The root element of the document model. */
+    private AppendLineOnlyFileDocumentElement root_element;
+    /** The current owner of this document, useful for callbacks when certain tasks are complete. */
+    private AppendLineOnlyFileDocumentOwner owner;
+    /** Is this document a build log, and hence has some extra functionality, of just a straight log. */
+    private boolean build_log = false;
+    /** A list of listeners attached to this document. */
+    private EventListenerList listeners_list;
+    /** This properties hash map allows you to store any metadata about this document for later review. */
+    private HashMap properties;
+    /** Indicates the current length of the underlying file (which may not equal the current number of characters in the document). */
+    private long length;
+    /** The random access file which will back this document model. */
+    private RandomAccessFile file;
+    /** The filename given to the underlying file. */
+    private String filename;
+    /** An independant thread responsible for writing the 'in memory' contents of the document model to the random access file as appropriate. This is done so IO lag does not effect the gui as much as it used to. */
+    private WriterThread writer;
+
+    
+    public AppendLineOnlyFileDocument(String filename) {
+	this(filename, true);
+    }
+
+    /** The constructor is responsible for creating several necessary data structures as well as opening the random access file. When it creates the new file, as it is wont to do, it will immediately add the special header line defined above.
+     * @param filename the absolute path name of the file as a String
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.AppendLineOnlyFileDocumentElement
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.WriterThread
+     * @see org.greenstone.gatherer.util.StaticStrings#NEW_LINE_CHAR
+     */
+    public AppendLineOnlyFileDocument(String filename, boolean build_log) {
+	DebugStream.println("Creating log: " + filename);
+	// Initialization 
+	this.build_log = build_log;
+	this.filename = filename;
+	this.listeners_list = new EventListenerList();
+	this.properties = new HashMap();
+	this.writer = new WriterThread();
+	writer.start();
+	// Open underlying file
+	try {
+	    file = new RandomAccessFile(filename, "rw");
+	    // Create the root element.
+	    length = file.length();
+	    root_element = new AppendLineOnlyFileDocumentElement();
+	    // Now quickly read through the underlying file, building an Element for each line.
+	    long start_offset = 0L;
+	    file.seek(start_offset);
+	    int character = -1;
+	    while((character = file.read()) != -1) {
+		if(character == StaticStrings.NEW_LINE_CHAR) {
+		    long end_offset = file.getFilePointer();
+		    Element child_element = new AppendLineOnlyFileDocumentElement(start_offset, end_offset);
+		    root_element.add(child_element);
+		    child_element = null;
+		    start_offset = end_offset;
+		}
+	    }
+	    // If there we no lines found, and we are a build log, then append the file header.
+	    if(build_log && root_element.getElementCount() == 0) {
+		appendLine(GLI_HEADER_STR);
+	    }
+	}
+	catch (Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+    }
+
+    /** Adds a document listener for notification of any changes. 
+     * @param listener the new DocumentListener to keep track of
+     */
+    public void addDocumentListener(DocumentListener listener) {
+	///ystem.err.println("addDocumentListener(" + listener + ")");
+	listeners_list.add(DocumentListener.class, listener);
+    }
+
+    /** Append some content after the document. 
+     * @param str the String to add as a new line in the document
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.AppendLineOnlyFileDocumentElement
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.AppendLineOnlyFileDocumentEvent
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.WriterThread#queue
+     */
+    public void appendLine(String str) {
+	// Ensure the string ends in a newline
+	try {
+	    if (!str.endsWith("\n")) {
+		str = str + "\n";
+	    }
+	    int str_length = str.getBytes("UTF-8").length;
+	    long start_offset = length;
+	    long end_offset = start_offset + (long) str_length;
+	    length = length + str_length;
+	    // Create a new element to represent this line
+	    AppendLineOnlyFileDocumentElement new_line_element = new AppendLineOnlyFileDocumentElement(start_offset, end_offset, str);
+	    root_element.add(new_line_element);
+	    // Queue the content to be written.
+	    writer.queue(new_line_element);
+	    // Now fire an event so everyone knows the content has changed.
+	    DocumentEvent event = new AppendLineOnlyFileDocumentEvent(new_line_element, (int)start_offset, str_length, DocumentEvent.EventType.INSERT);
+	    Object[] listeners = listeners_list.getListenerList();
+	    for (int i = listeners.length - 2; i >= 0; i = i - 2) {
+		if (listeners[i] == DocumentListener.class) {
+		    ((DocumentListener)listeners[i+1]).insertUpdate(event);
+		}
+	    }
+	    listeners = null;
+	    event = null;
+	    new_line_element = null;
+	}
+	catch(Exception error) {
+	    DebugStream.printStackTrace(error);
+	}
+    }
+
+    /** Returns a position that will track change as the document is altered. 
+     * @param offs the position offset as an int
+     * @return the Position to be monitored
+     *  @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.AppendLineOnlyFileDocumentPosition
+     */
+    public Position createPosition(int offs)  {
+	return new AppendLineOnlyFileDocumentPosition(offs);
+    }
+
+    /** The destructor is implemented to ensure the current log file has finished transferring from memory to disk, and that the random access file is properly closed, before GLI exits.
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.WriterThread#finish
+     */
+    public void destroy() {
+	try {
+	    writer.finish();
+	    file.close();
+	}
+	catch(Exception exception) {
+	    DebugStream.println("Exception in AppendLineOnlyFileDocument.destroy() - unexpected");
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+
+    /** Gets the default root element for the document model. 
+     * @return the root Element of this document
+     */
+    public Element getDefaultRootElement() {
+	return root_element;
+    }
+
+    /** Returns the length of the data. 
+     * @return the length as an int (not a long)
+     */
+    public int getLength() {
+	return (int) length;
+    }
+
+    /** A version of get length which returns the offset to the start of the last line in the document.
+     * @return the offset length as an int
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.AppendLineOnlyFileDocumentElement
+     */
+    public int getLengthToNearestLine() {
+	AppendLineOnlyFileDocumentElement last_element = (AppendLineOnlyFileDocumentElement)root_element.getElement(root_element.getElementCount() - 1);
+	if(last_element != null ) {
+	    return last_element.getStartOffset();
+	}
+	else {
+	    return (int) length; // The best we can do.
+	}
+    }
+	
+    /** Retrieve a property that has previously been set for this document.
+     * @param key the key String under which the vaue is stored
+     * @return the value which is also a String, or null if no such value
+     */
+    public Object getProperty(Object key) {
+	return properties.get(key);
+    }
+
+    /** Determine if the writer thread is still running, ie a log file which is currently open for writing
+     * @return true if the writer is still active, false otherwise
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.WriterThread#isStillWriting
+     */
+    public boolean isStillWriting() {
+	return writer.isStillWriting();
+    }
+
+    /** Gets a sequence of text from the document. 
+     * @param offset the starting offset for the fragment of text required, as an int
+     * @param l the length of the text, also as an int
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.AppendLineOnlyFileDocumentElement
+     * @see org.greenstone.gatherer.util.StaticStrings#EMPTY_STR
+     */
+    public String getText(int offset, int l) 
+	throws BadLocationException {
+
+	if (l == 0) {
+	    return "";
+	}
+
+	try {
+	    return read((long) offset, l);
+	}
+	catch (Exception ex) {
+	}
+
+	return "";
+
+//  	// System.err.println("AppendLineOnlyFileDocument::getText() request...");
+//  	String request = "getText(" + offset + ", " + l + ")";
+//  	///ystem.err.println(request);
+//  	String text = null;
+//  	if(text == null || text.length() < l) {
+//  	    try {
+//  		int file_length = (int) file.length();
+//  		///ystem.err.println("file_length = " + file_length + ", length = " + length);
+//  		if(l == 0) {
+//  		    text = StaticStrings.EMPTY_STR;
+//  		}
+//  		else if(0 <= offset && offset < length && (offset + l) <= length) {
+//  		    if(offset < file_length) {
+//  			text = read((long)offset, l);
+//  			if(text.length() != l) {
+//  			    ///ystem.err.println("Asked for " + l + " characters of text. But only read " + text.length());
+//  			    throw new BadLocationException("AppendLineOnlyDocument.getText(" + offset + ", " + l + ")", offset); 
+//  			}
+//  		    }
+//  		    else {
+//  			int index = root_element.getElementIndex(offset);
+//  			if(index < root_element.getElementCount()) {
+//  			    AppendLineOnlyFileDocumentElement element = (AppendLineOnlyFileDocumentElement) root_element.getElement(index);
+//  			    text = element.getContent();
+//  			}
+//  			else {
+//  			    ///ystem.err.println("Index is " + index + " but there are only " + root_element.getElementCount() + " children.");
+//  			    throw new BadLocationException("AppendLineOnlyDocument.getText(" + offset + ", " + l + ")", offset); 
+//  			}
+//  		    }
+		    
+//  		}
+//  	    }
+//  	    catch (IOException error) {
+//  		DebugStream.printStackTrace(error);
+//  	    }
+//  	    if(text == null) {
+//  		///ystem.err.println("Text is null.");
+//  		throw new BadLocationException("AppendLineOnlyDocument.getText(" + offset + ", " + l + ")", offset);
+//  	    }
+//  	}
+//  	request = null;
+//  	return text;
+    }
+
+    /** Fetches the text contained within the given portion of the document. 
+     * @param offset the starting offset of the desired text fragment, as an int
+     * @param length the length of the text also as an int
+     * @param txt the Segment into which the text fragment should be placed
+     */
+    public void getText(int offset, int length, Segment txt) 
+	throws javax.swing.text.BadLocationException  {
+	String str = getText(offset, length);
+	txt.array = str.toCharArray();
+	txt.count = str.length();
+	txt.offset = 0;
+	str = null;
+    }
+	
+    /** Set a property for this document.
+     * @param key the key to store the value under, as a String
+     * @param value the property value itself also as a String
+     */
+    public void putProperty(Object key, Object value) {
+	properties.put(key, value);
+    }
+
+    /** Determine if this document is ready by testing if it has an open descriptor to the random access file.
+     * @return true if the file exists thus the document is ready, false otherwise
+     */
+    public boolean ready() {
+	return (file != null);
+    }
+	
+    /** Removes a document listener.
+     * @param listener the Document we wish to remove
+     */
+    public void removeDocumentListener(DocumentListener listener) {
+	listeners_list.remove(DocumentListener.class, listener);
+    }
+
+    /** Whenever the user requests a change of the loaded log, this method is called to ensure the previous log has been completely written to file. Note that this only garuentees that text fragments currently queued for writing will be correctly written - while the behaviour is undefined for text fragments added after this call (some may write depending on several race conditions).
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.WriterThread#exit
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.WriterThread#finish
+     */
+    public void setExit() {
+	writer.exit();
+	writer.finish();
+    }
+
+    /** Establish the current owner of this document.
+     * @param owner the current AppendLineOnlyFileDocumentOwner
+     */
+    public void setOwner(AppendLineOnlyFileDocumentOwner owner) {
+	this.owner = owner;
+    }
+
+    /** To record the final state of the logging process we reserve a single character at the start of the file, and then replace it when the build process is complete.
+     * @param character the final status char to replace the X at the start of the log
+     */
+    public synchronized void setSpecialCharacter(char character) {
+	if(build_log) {
+	    try {
+		file.seek(0L);
+		file.write((int)character);
+	    }
+	    catch (Exception error) {
+		DebugStream.printStackTrace(error);
+	    }
+	}
+    }
+
+    /** Request a text representation of this document which currently returns the filename.
+     * @return the text as a String
+     */
+    public String toString() {
+	return filename;
+    }
+
+    /** This method reads a fragment of text from the underlying random access file. It is synchronized so that the file isn't being written to at the same time.
+     * @param start_offset the offset within the file to set the read pointer at, as a long
+     * @param l the number of characters to read as an int
+     */
+    private synchronized String read(long start_offset, int l) 
+	throws IOException {
+	//print("read(" + start_offset + ", " + l + ")... ");
+	byte[] buffer = new byte[l];
+	file.seek(start_offset);
+	int result = file.read(buffer, 0, l);
+	return new String(buffer, "UTF-8");
+	//print("read() complete");
+    }
+
+    /** This methods writes a fragment of text to the underlying random access file. It is synchronized so that the file isn't being read from at the same time.
+     * @param start_offset the offset within the file to set the write pointer at, as a long
+     * @param end_offset the final offset of the new text fragment within the file, as a long. This is used to extend the file to be the correct length
+     * @param str the String to be written
+     * @param l the number of characters from str to be written, as an int
+     */
+    private synchronized void write(long start_offset, long end_offset, String str, int l) 
+	throws IOException {	
+	//print("write(" + start_offset + ", " + end_offset + ", " + str + ", " + l + ")");
+	file.setLength(end_offset);
+	file.seek(start_offset);
+	file.write(str.getBytes("UTF-8"), 0, l);
+	//print("write() complete");
+    }
+
+    /** This class provides the building-block for the document model. Each element is a line in the document, or has no content but contains several child elements. Due to the basic nature of what we are modelling only the root node has children. */
+    private class AppendLineOnlyFileDocumentElement
+	extends ArrayList
+	implements Element {
+	/** Our parent Element. */
+	private Element parent;
+	/** The offset to the end of our fragment(s) of text, in respect to the entire document. */
+	private long end;
+	/** The offset to the start of our fragment(s) of text, in respect to the entire document. */
+	private long start;
+	/** If we haven't been written to file yet, this contains the text fragment itself. */
+	private String content;
+
+	/** Construct a new root element, which can have no content, but calculates its start and end from its children. */
+	public AppendLineOnlyFileDocumentElement() {
+	    super();
+	    this.end = 0L;
+	    this.parent = null;
+	    this.start = 0L;
+	}
+
+	/** Construct a new element, whose content is found in bytes start to end - 1 within the random access file backing this document.
+	 * @param start the starting offset as a long
+	 * @param end the ending offset as a long
+	 */
+	public AppendLineOnlyFileDocumentElement(long start, long end) {
+	    super();
+	    this.end = end;
+	    this.parent = null;
+	    this.start = start;
+	}
+
+	/** Construct a new element, whose content is provided, but should at some later time be written to bytes start to end - 1 in the random access file backing this document.
+	 * @param start the starting offset as a long
+	 * @param end the ending offset as a long
+	 * @param content the text fragment String which we represent in the model
+	 */
+	public AppendLineOnlyFileDocumentElement(long start, long end, String content) {
+	    super();
+	    this.content = content;
+	    this.end = end;
+	    this.parent = null;
+	    this.start = start;
+	}
+
+	/** Add the given node as one of our children.
+	 * @param child the new child Element
+	 */
+	public void add(Element child) {
+	    super.add(child);
+	    ((AppendLineOnlyFileDocumentElement)child).setParent(this);
+	}
+
+	/** Having written the content to file this method removes it from the element. */ 
+	public void clearContent() {
+	    content = null;
+	}
+
+	/** This document does not allow content markup. 
+	 * @return always returns null
+	 */
+	public AttributeSet getAttributes() {
+	    return null;
+	}
+
+	/** Retrieve the current content of this element, which may be the text fragment this element represents.
+	 * @return either the text fragment as a String, or null if the fragment has already been written to disk
+	 */
+	public String getContent() {
+	    return content;
+	}
+
+	/** Fetches the document associated with this element. 
+	 * @return the AppendLineOnlyDocument containing this element
+	 * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument
+	 */
+	public Document getDocument() {
+	    return AppendLineOnlyFileDocument.this;
+	}
+
+	/** Fetches the child element at the given index. 
+	 * @param index the int index of the element to retrieve
+	 * @return the requested Element
+	 */
+	public Element getElement(int index) {
+	    Element element;
+	    if(0 <= index && index < size()) {
+		element = (Element) get(index);
+	    }
+	    else {
+		throw new IndexOutOfBoundsException("AppendLineOnlyDocument.AppendLineOnlyFileDocumentElement.getElement(" + index + ")");
+	    }
+	    return element;
+	}
+          
+	/** Gets the number of child elements contained by this element. 
+	 * @return an int
+	 */
+	public int getElementCount() {
+	    return size();
+	}
+
+	/** Gets the child element index closest to the given offset.
+	 * @param offset the offset within the text of the document, which due to the way the model is built must fll within the bounds of one of our child nodes
+	 * @return the closest index as an int
+	 */
+	public int getElementIndex(int offset) {
+	    int index = -1;
+	    if(parent != null) {
+		index = -1;
+	    }
+	    else if(offset < 0) {
+		index = 0;
+	    }
+	    else if(offset >= length) {
+		index = size() - 1;
+	    }
+	    else {
+		int size = size();
+		for(int i = 0; index == -1 && i < size; i++) {
+		    Element child = (Element) get(i);
+		    if(child.getStartOffset() <= offset && offset < child.getEndOffset()) {
+			index = i;
+		    }
+		    child = null;
+		}
+	    }
+	    return index;
+	}
+          
+	/** Fetches the offset from the beginning of the document that this element ends at. 
+	 * @return the offset as an int
+	 */
+	public int getEndOffset() {
+	    if(parent != null) {
+		return (int) end;
+	    }
+	    // Return the Documents length.
+	    else {
+		return (int) length;
+	    }
+	}
+          
+	/** This method retrieves the name of the element, however names are not important in this document so the name is always an empty string.
+	 * @return an empty String
+	 * @see org.greenstone.gatherer.util.StaticStrings#EMPTY_STR
+	 */
+	public String getName() {
+	    return StaticStrings.EMPTY_STR;
+	}
+          
+	/** Fetches the parent element. 
+	 * @return the parent Element
+	 */
+	public Element getParentElement() {
+	    return parent;
+	}
+          
+	/** Fetches the offset from the beginning of the document that this element begins at. 
+	 * @return the offset as an int
+	 */
+	public int getStartOffset() {
+	    if(parent != null) {
+		return (int) start;
+	    }
+	    else {
+		return 0;
+	    }
+	}
+          
+	/** Since this is a very simple model, only the root node can have children. All the children are leaves. 
+	 * @return true if this is the root node, false otherwise
+	 */
+	public boolean isLeaf() {
+	    return (parent != null);
+	} 
+
+	/** Establish the parent of this element
+	 * @param parent the parent Element
+	 */
+	public void setParent(Element parent) {
+	    this.parent = parent;
+	}
+    }
+    // AppendLineOnlyFileDocumentElement
+
+    /** This event is created to encapsulate the details of some change to the document. */
+    private class AppendLineOnlyFileDocumentEvent
+	implements DocumentEvent {
+	/** The type of change event. */
+	private DocumentEvent.EventType type;
+	/** The element this change occured to, or in. */
+	private AppendLineOnlyFileDocumentElement element;
+	/** Another encapsulating class which contains further detail about the change itself. */
+	private AppendLineOnlyFileDocumentElementChange element_change;
+	/** The length of the text fragment affected by the change. */
+	private int len;
+	/** The offset within the document of the start of the change. */
+	private int offset;
+	
+	/** Construct a new AppendLineOnlyFileDocumentEvent given the pertinant details.
+	 * @param element the AppendLineOnlyFileDocumentElement affected by this change
+	 * @param offset the offset within the document of the start of the change
+	 * @param len the length of the text fragment affected by the change
+	 * @param type the type of change event
+	 */
+	public AppendLineOnlyFileDocumentEvent(AppendLineOnlyFileDocumentElement element, int offset, int len, DocumentEvent.EventType type) {
+	    this.element = element;
+	    this.element_change = null;
+	    this.len = len;
+	    this.offset = offset;
+	    this.type = type;
+	}
+
+	/** Retrieve the docment which generated this event.
+	 * @return the Document
+	 * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument
+	 */
+	public Document getDocument() {
+	    return AppendLineOnlyFileDocument.this;
+	}
+
+	/** Retrieve the length of the change.
+	 * @return the length as an int
+	 */
+	public int getLength() {
+	    return len;
+	}
+
+	/** Retrieve the start offset of the change.
+	 * @return the offset as an int
+	 */
+	public int getOffset() {
+	    return offset;
+	}
+
+	/** Retrieve the type of change.
+	 * @return the type as a DocumentEvent.EventType
+	 */
+	public DocumentEvent.EventType getType() {
+	    return type;
+	}
+
+	/** Retrieve the element change object which further describes the changes. Of course given that we only allow the appending of new lines there really is only one type of event.
+	 * @param elem implementation side-effect
+	 * @return a DocumentEvent.ElementChange
+	 * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.AppendLineOnlyFileDocumentEvent.AppendLineOnlyFileDocumentElementChange
+	 */
+	public DocumentEvent.ElementChange getChange(Element elem) {
+	    if(element_change == null) {
+		element_change = new AppendLineOnlyFileDocumentElementChange();
+	    }
+	    return element_change;
+	}
+
+	/** A pretty unexciting implementation of the document element change class. This usually describes the myriad of possible change events that can occur on a document. However we only allow line appends so there is really only one type of change. */
+	private class AppendLineOnlyFileDocumentElementChange
+	    implements DocumentEvent.ElementChange {
+	    /** This array always contains the one Element that was appended. */ 
+	    private Element[] children_added;
+	    /** This Element array is always empty. */
+	    private Element[] children_removed;
+	    /** The index of the affected element within its parents children. */
+	    private int index;
+	    /** Construct a new AppendLineOnlyFileDocumentElementChange with the default 'append line' details. */
+	    public AppendLineOnlyFileDocumentElementChange() {
+		children_added = new Element[1];
+		children_added[0] = element;
+		children_removed = new Element[0];
+		index = root_element.indexOf(element);
+	    }
+
+	    /** Gets the child element that was appended to the parent element. 
+	     * @return an Element[] containing the added element
+	     */
+	    public Element[] getChildrenAdded() {
+		return children_added;
+	    }
+
+	    /** This model does not allow elements to be removed.
+	     * @return an Element[] containing nothing
+	     */
+	    public Element[] getChildrenRemoved() {
+		return children_removed;
+	    }
+          
+	    /** Returns the root element, as our document structure is only two layers deep.
+	     * @return the root Element
+	     */
+	    public Element getElement() {
+		return root_element;
+	    }
+          
+	    /** Fetches the index within the element represented. 
+	     * @return an int specifying the index of change within the root element
+	     */
+	    public int getIndex() {
+		return index;
+	    }
+	}
+	// AppendLineOnlyFileDocumentElementChange
+    }
+    // AppendLineOnlyFileDocumentEvent
+    
+    /** This class denoted a position within our document by an offset. Quite possibly the last interesting class I've ever had to deal with, but you have to implement it so here goes... */
+    private class AppendLineOnlyFileDocumentPosition
+	implements Position {
+	/** The offset within our document. */
+	private int offset;
+	/** Construct a new position given an offset.
+	 * @param offset the offset as an int
+	 */
+	public AppendLineOnlyFileDocumentPosition(int offset) {
+	    this.offset = offset;
+	}
+	/** Retrieve the offset of this position.
+	 * @return the offset as an int
+	 */
+	public int getOffset() {
+	    return offset;
+	}
+    }
+    // AppendLineOnlyFileDocumentPosition
+    
+    /** This thread is responsible to writing the in memory text fragment contents of the document elements out to the random access file. The writing proceedure is implemented this way so that the gui doesn't take the performance hit of the IO. */
+    private class WriterThread
+	extends Thread {
+	/** When true was are being told to assume the contents of the queue are now static, and once completed the queue will be empty (and not expecting any new jobs). Used to finish the queue before the GLI exits. */
+	private boolean empty_queue;
+	/** Setting this flag to true tells the writer to stop regardless of whether there are items left on the queue. */
+	private boolean exit;
+	/** When the writer thread is busy writing content to the file this flag is set to true. */
+	private boolean running;
+	/** When the writer thread is running, but has emptied the current queue and so is waiting, this flag is set to true. */
+	private boolean waiting;
+	/** The fragment queue as a Vector (for thread reasons). */
+	private Vector queue;
+	/** Construct a new writer thread with an initially empty queue. */
+	public WriterThread() {
+	    super("WriterThread");
+	    empty_queue = false;
+	    exit = false;
+	    queue = new Vector();
+	    waiting = false;
+	}
+
+	/** This method is called to ask the writer thread to die after it finishes any current write proceceedure. */
+	public synchronized void exit() {
+	    //print("WriterThread.exit() start");
+	    exit = true;
+	    notify();
+	    //print("WriterThread.exit() complete");
+	}
+
+	/** When this returns there are no jobs waiting in the queue. */
+	public void finish() {
+	    if(!queue.isEmpty() && running) {
+		///ystem.err.println("Somethings gone wrong, as there are still " + queue.size() + " items to be written out and yet the thread seems to be waiting.");
+		empty_queue = true;
+		run();
+	    }
+	}
+
+	/** Determine if the writer is currently running.
+	 * @return true if it is, false if it has been exited or if it was never running in the first place (an old log)
+	 */
+	public boolean isStillWriting() {
+	    return running;
+	}
+
+	/** The run method of this thread checks if there are any document elements queued to be written to file, and then writes them as necessary.
+	 * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument
+	 * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.AppendLineOnlyFileDocumentElement
+	 */
+	public void run() {
+	    exit = false;
+	    running = true;
+	    while(!exit) {
+		if(!queue.isEmpty()) { 
+		    AppendLineOnlyFileDocumentElement element = (AppendLineOnlyFileDocumentElement) queue.remove(0);
+		    // Write the content to file.
+		    String content = element.getContent();
+		    if(content != null) {
+			try {
+			    write(element.getStartOffset(), element.getEndOffset(), content, content.getBytes("UTF-8").length);
+			}
+			catch(Exception error) {
+			    DebugStream.printStackTrace(error);
+			}
+			element.clearContent();
+		    }
+		}
+		else if(empty_queue) {
+		    exit = true;
+		}
+		else {
+		    synchronized(this) {
+			try {
+			    print("WriterThread.wait() start");
+			    waiting = true;
+			    wait();
+			}
+			catch(Exception exception) {
+			}
+			print("WriterThread.wait() complete");
+			waiting = false;
+		   }
+		}
+	    }
+	    print("WriterThread completely finished. Exiting.");
+	    running = false;
+	    if(owner != null) {
+		owner.remove(AppendLineOnlyFileDocument.this);
+	    }
+	}
+
+	/** Enqueue a document element to have its text content written to file.
+	 * @param element the Element needing its content written out
+	 * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.AppendLineOnlyFileDocumentElement#getContent
+	 */
+	public synchronized void queue(Element element) {
+	    print("WriterThread.queue(): " + ((AppendLineOnlyFileDocumentElement)element).getContent());
+	    queue.add(element);
+	    notify();
+	}
+    }
+    // WriterThread
+
+    // ***** METHODS WE ARE NOW IGNORING BECAUSE WE ARE VIRTUALLY READ-ONLY *****
+    
+    /** Not implemented. Add a new undo listener to this document.
+     * @param listener UndoableEditListener
+     */
+    public void addUndoableEditListener(UndoableEditListener listener) {}
+    	
+    /** Not implemented. Get the last position in the document.
+     * @return null
+     */
+    public Position getEndPosition() { return null; }
+
+    /** Not implemented. Gets all root elements defined.
+     * @return null
+     */
+    public Element[] getRootElements() { return null; }
+	
+    /** Not implemented. Retrieve the first position in the document.
+     * @return null
+     */
+    public Position getStartPosition() { return null; }
+    
+    /** Not implemented. Insert a text fragment into our document.
+     * @param offset int
+     * @param str String
+     * @param a AttributeSet
+     */
+    public void insertString(int offset, String str, AttributeSet a) {}
+
+    /** Not implemented. Removes some content from the document. 
+     * @param offs int
+     * @param len int
+     */
+    public void remove(int offs, int len) {}
+
+    /** Not implemented. Removes an undo listener. 
+     * @param listener UndoableEditListener
+     */
+    public void removeUndoableEditListener(UndoableEditListener listener) {}
+    
+    /** Not implemented. Renders a runnable apparently - whatever that means. 
+     * @param r Runnable
+     */
+    public void render(Runnable r) {}
+
+    // DEBUG ONLY
+
+    /** Print a message to the GLI debug file stream.
+     * @param message the message to be written as a String
+     */
+    static synchronized public void print(String message) {
+	if (message.endsWith("\n")) {
+	    DebugStream.print(message); 
+	}
+	else {
+	    DebugStream.println(message); 
+	}
+    }
+
+    /** Create a test document with the ability to add new lines of text as necessary.
+     * @param args the initial starting arguments as a String array
+     * @see org.greenstone.gatherer.gui.GLIButton
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument
+     * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.ReadButtonListener
+     */
+    static public void main(String[] args) {
+	JFrame frame = new JFrame("AppendLineOnlyFileDocument Test");
+	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+	frame.setSize(640,480);
+	JPanel content = (JPanel) frame.getContentPane();
+	
+	//PlainDocument document = new PlainDocument();
+	//document.setAsynchronousLoadPriority(-1);
+	final AppendLineOnlyFileDocument document = new AppendLineOnlyFileDocument("temp.txt");
+
+	final JTextArea text_area = new JTextArea(document);
+
+	JButton read_button = new GLIButton("Read Huge File");
+	read_button.setMnemonic(KeyEvent.VK_R);
+	read_button.addActionListener(new ReadButtonListener(document));
+	content.setLayout(new BorderLayout());
+	content.add(new JScrollPane(text_area), BorderLayout.CENTER);
+	content.add(read_button, BorderLayout.SOUTH);
+
+	frame.setVisible(true);
+    }
+
+    /** Listens for actions on the read button, and if detected creates a new ReadTask to test the document. 
+     * @author John Thompson, Greenstone Project, New Zealand Digital Library, University of Waikato
+     * @version 2.41 final
+     */
+    static private class ReadButtonListener
+	implements ActionListener {
+	/** The AppendLineOnlyFileDocument object we are testing. */
+	private AppendLineOnlyFileDocument document;
+
+	/** All the constructor does is take a copy of the document to test.
+	 * @param document the Document
+	 */
+	public ReadButtonListener(AppendLineOnlyFileDocument document) {
+	    this.document = document;
+	}
+
+	/** When the button is clicked this method is called to create the new task and run it.
+	 * @param event an ActionEvent containing further information about the button click
+	 * @see org.greenstone.gatherer.util.AppendLineOnlyFileDocument.ReadTask
+	 */
+	public void actionPerformed(ActionEvent event) {
+	    Thread task = new ReadTask(document);
+	    task.start();
+	}
+    }
+
+    /** This threaded task opens a large document, aptly named 'big.txt', and then bombards the document object we are testing with lines from the file. This file should be several megs (such as Alice or TREC) to fully test functionality, thread conditions etc. 
+     * @author John Thompson, Greenstone Project, New Zealand Digital Library, University of Waikato
+     * @version 2.41 final
+     */ 
+    static private class ReadTask
+	extends Thread {
+	/** The AppendLineOnlyFileDocument object we are testing. */
+	private AppendLineOnlyFileDocument document;
+
+	/** Construct a new task which will perform testing on the given document.
+	 * @param document the AppendLineOnlyFileDocument to append lines to
+	 */
+	public ReadTask(AppendLineOnlyFileDocument document) {
+	    super("LoadHugeFileThread");
+	    this.document = document;
+	}
+
+	/** The runable part of this class opens the file, then reads it in a line at a time, appending these lines to the ever growing document. */
+	public void run() {
+	    // Load the specified document
+	    try {
+		BufferedReader in = new BufferedReader(new FileReader(new File("big.txt")));
+		String line;
+		
+		while ((line = in.readLine()) != null) {
+		    document.appendLine(line);
+		    try {
+			// Wait a random ammount of time.
+			synchronized(this) {
+			    //print("LoadHugeFileThread.wait() start");
+			    wait(100);
+			    //print("LoadHugeFileThread.wait() complete");
+			}
+		    }
+		    catch(Exception error) {
+			error.printStackTrace();
+		    }
+		}
+		
+	    } catch (Exception error) {
+		error.printStackTrace();
+	    }
+	}
+    }
+    // ReadTask
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/AppendLineOnlyFileDocumentOwner.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/AppendLineOnlyFileDocumentOwner.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/AppendLineOnlyFileDocumentOwner.java	(revision 10506)
@@ -0,0 +1,46 @@
+/**
+ *#########################################################################
+ *
+ * A component of the Greenstone Librarian Interface (GLI) application, 
+ * part of the Greenstone digital library software suite from the New 
+ * Zealand Digital Library Project at the University of Waikato, 
+ * New Zealand.
+ *
+ * Author: John Thompson
+ *         Greenstone Project, New Zealand Digital Library
+ *         University of Waikato
+ *         http://www.nzdl.org
+ *
+ * Copyright (C) 2004 New Zealand Digital Library, University of Waikato
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the 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.gatherer.util;
+
+
+/** Any class that wants to act as the owner of an AppendLineOnlyFileDocument has to implement this.
+ * @author John Thompson, Greenstone Project, New Zealand Digital Library, University of Waikato
+ * @version 2.41 final
+ */
+public interface AppendLineOnlyFileDocumentOwner {
+    /** Remove the given document from the owner. The is called by the document itself when it no longer needs a hanging reference in the owner class.
+     * @param document the AppendLineOnlyFileDocument to remove
+     */
+    public void remove(AppendLineOnlyFileDocument document);
+}
+
+
+
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/ArrayTools.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/ArrayTools.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/ArrayTools.java	(revision 10506)
@@ -0,0 +1,353 @@
+/* GPL_HEADER */
+package org.greenstone.gatherer.util;
+
+/**************************************************************************************
+ * Title:        Gatherer
+ * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
+ * Company:      The University of Waikato
+ * Written:        /  /01
+ * Revised:      16/08/02 Improved
+ **************************************************************************************/
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.filechooser.*;
+import org.w3c.dom.*;
+
+/** This utility class contains a series of static methods for common array type manipulations including appending, casting and changing between containers.
+ * @author John Thompson
+ * @version 2.3
+ */
+public class ArrayTools {
+
+    /** Append a Component onto an array of Components. */
+    static public Component[] add(Component[] a, Component b) {
+	Component[] c = null;
+	if(a != null && b != null) {
+	    c = new Component[a.length + 1];
+	    System.arraycopy(a, 0, c, 0, a.length);
+	    c[c.length - 1] = b;
+	}
+	else if(a == null && b != null) {
+	    c = new Component[1];
+	    c[0] = b;
+	}
+	else if(a != null && b == null) {
+	    c = a;
+	}
+	return c;
+    }
+    /** This method efficiently appends a new element onto the end of a element array.
+     * @param a The initial <strong>Element[]</strong>.
+     * @param b The new <strong>Element</strong>.
+     * @return An <strong>Element[]</strong> containing a followed by b.
+     */
+    static public Element[] add(Element a[], Element b) {
+	Element[] c = null;
+	if(a != null && b != null) {
+	    c = new Element[a.length + 1];
+	    System.arraycopy(a, 0, c, 0, a.length);
+	    c[c.length - 1] = b;
+	}
+	else if(a == null && b != null) {
+	    c = new Element[1];
+	    c[0] = b;
+	}
+	else if(a != null && b == null) {
+	    c = a;
+	}
+	return c;
+    }
+    /** This method efficently appends one element array onto the end of another.
+     * @param a The initial <strong>Element[]</strong>.
+     * @param b The <strong>Element[]</strong> to append.
+     * @return An <strong>Element[]</strong> containing a followed by b.
+     */
+    static public Element[] add(Element a[], Element b[]) {
+	Element[] c = null;
+	if(a != null && b != null) {
+	    c = new Element[a.length + b.length];
+	    System.arraycopy(a, 0, c, 0, a.length);
+	    System.arraycopy(b, 0, c, a.length, b.length);
+	}
+	else if(a == null && b != null) {
+	    c = b;
+	}
+	else if(a != null && b == null) {
+	    c = a;
+	}
+	return c;
+    }
+    /** This method efficiently appends a new file onto the end of a file array.
+     * @param a The initial <strong>File[]</strong>.
+     * @param b The new <strong>File</strong>.
+     * @return A <strong>File[]</strong> containing a followed by b.
+     */
+    static public File[] add(File a[], File b) {
+	File[] c = null;
+	if(a != null && b != null) {
+	    c = new File[a.length + 1];
+	    System.arraycopy(a, 0, c, 0, a.length);
+	    c[c.length - 1] = b;
+	}
+	else if(a == null && b != null) {
+	    c = new File[1];
+	    c[0] = b;
+	}
+	else if(a != null && b == null) {
+	    c = a;
+	}
+	return c;
+    }
+    /** This method efficently appends one file array onto the end of another.
+     * @param a The initial <strong>File[]</strong>.
+     * @param b The <strong>File[]</strong> to append.
+     * @return A <strong>File[]</strong> containing a followed by b.
+     */
+    static public File[] add(File a[], File b[]) {
+	File[] c = null;
+	if(a != null && b != null) {
+	    c = new File[a.length + b.length];
+	    System.arraycopy(a, 0, c, 0, a.length);
+	    System.arraycopy(b, 0, c, a.length, b.length);
+	}
+	else if(a == null && b != null) {
+	    c = b;
+	}
+	else if(a != null && b == null) {
+	    c = a;
+	}
+	return c;
+    }
+
+
+    /** This method efficiently appends a new node onto the end of a node array.
+     * @param a The initial <strong>Node[]</strong>.
+     * @param b The new <strong>Node</strong>.
+     * @return A <strong>Node[]</strong> containing a followed by b.
+     */
+    static public Node[] add(Node a[], Node b) {
+	Node[] c = null;
+	if(a != null && b != null) {
+	    c = new Node[a.length + 1];
+	    System.arraycopy(a, 0, c, 0, a.length);
+	    c[c.length - 1] = b;
+	}
+	else if(a == null && b != null) {
+	    c = new Node[1];
+	    c[0] = b;
+	}
+	else if(a != null && b == null) {
+	    c = a;
+	}
+	return c;
+    }
+    /** This method efficently appends one node array onto the end of another.
+     * @param a The initial <strong>Node[]</strong>.
+     * @param b The <strong>Node[]</strong> to append.
+     * @return A <strong>Node[]</strong> containing a followed by b.
+     */
+    static public Node[] add(Node a[], Node b[]) {
+	Node[] c = null;
+	if(a != null && b != null) {
+	    c = new Node[a.length + b.length];
+	    System.arraycopy(a, 0, c, 0, a.length);
+	    System.arraycopy(b, 0, c, a.length, b.length);
+	}
+	else if(a == null && b != null) {
+	    c = b;
+	}
+	else if(a != null && b == null) {
+	    c = a;
+	}
+	return c;
+    }
+	 
+    /** This method efficiently appends a new string onto the end of a string array.
+     * @param a The initial <strong>String[]</strong>.
+     * @param b The new <strong>String</strong>.
+     * @return A <strong>String[]</strong> containing a followed by b.
+     */
+    static public String[] add(String a[], String b) {
+	String[] c = null;
+	if(a != null && b != null) {
+	    c = new String[a.length + 1];
+	    System.arraycopy(a, 0, c, 0, a.length);
+	    c[c.length - 1] = b;
+	}
+	else if(a == null && b != null) {
+	    c = new String[1];
+	    c[0] = b;
+	}
+	else if(a != null && b == null) {
+	    c = a;
+	}
+	return c;
+    }
+    /** This method efficently appends one string array onto the end of another.
+     * @param a The initial <strong>String[]</strong>.
+     * @param b The <strong>String[]</strong> to append.
+     * @return A <strong>String[]</strong> containing a followed by b.
+     */
+    static public String[] add(String a[], String b[]) {
+	String[] c = null;
+	if(a != null && b != null) {
+	    c = new String[a.length + b.length];
+	    System.arraycopy(a, 0, c, 0, a.length);
+	    System.arraycopy(b, 0, c, a.length, b.length);
+	}
+	else if(a == null && b != null) {
+	    c = b;
+	}
+	else if(a != null && b == null) {
+	    c = a;
+	}
+	return c;
+    }
+    /** This method takes an array list and creates a string array.
+     * @param a An <strong>ArrayList</strong> containing hopefully <strong>String</strong> or else this will fail.
+     * @return A <strong>String[]</strong> or <i>null</i> if the array could not be created.
+     */
+    static public String[] arrayListToStringArray(ArrayList a) {
+	String array[] = new String[a.size()];
+	for(int i = 0; i < array.length; i++) {
+	    array[i] = (String)a.get(i);
+	}
+	return array;
+    }
+
+    static public File[] filter(File[] files, String pattern, boolean exclude) {
+	int write_ptr = 0;
+	///ystem.err.println("Filtering by '" + pattern + "', Exclude? " + exclude + " :");
+	for(int read_ptr = 0; read_ptr < files.length; read_ptr++) {
+	    File current = files[read_ptr];
+	    files[write_ptr] = current;
+	    ///ystem.err.print("Testing " + current.getName() + " -> ");
+	    // Determine whether we move the write pointer or not.
+	    if(current.getName().toLowerCase().matches(pattern)) {
+		if(!exclude) {
+		    ///ystem.err.println("Match, Exclude.");
+		    write_ptr++;  
+		}
+		else {
+		    ///ystem.err.println("Match, Include.");
+		}
+	    }
+	    else {
+		// You can't exclude folders with an inclusion filter!
+		if(exclude || current.isDirectory()) {
+		    ///ystem.err.println("Nonmatch, Exclude.");
+		    write_ptr++;
+		}
+		else {
+		    ///ystem.err.println("Nonmatch, Include.");
+		}
+	    }
+	}
+	File[] result = new File[write_ptr];
+	System.arraycopy(files, 0, result, 0, result.length);
+	pattern = null;
+	files = null;
+	return result;
+    }
+
+    /** Method to convert a list of nodes from the DOM model into a node array. This is quite useful as using a <strong>NodeList</strong> is problematic if you wish to traverse the tree while editing. Because they are 'live' representations of the model you are editing, it is easy to drop out of for loops early or run off the ends of arrays.
+     * @param node_list A <strong>NodeList</strong> representing the <strong>Node</strong>s we want to iterate through.
+     * @return A brand new <strong>Node[]</strong> with the first <strong>Node</strong> in the <strong>NodeList</strong> at the head.
+     * @see org.w3c.dom.Node
+     * @see org.w3c.dom.NodeList
+     */
+    static public Node[] nodeListToNodeArray(NodeList node_list) {
+	Node nodes[] = null;
+	for(int i = 0; i < node_list.getLength(); i++) {
+	    nodes = add(nodes, node_list.item(i));
+	}
+	return nodes;
+    }
+    /** Transforms an Object array into a single string of the form '[o1,o2,...,on]'.
+     * @param objects An <strong>Object[]</strong>. Note that the objects in this array must support toString() reasonably.
+     * @return A <strong>String</strong> representing the given array.
+     */
+    static public String objectArrayToString(Object objects[]) {
+	StringBuffer result = new StringBuffer("[");
+	for(int i = 0; i < objects.length; i++) {
+	    result.append(objects[i].toString());
+	    if(i < objects.length - 1) {
+		result.append(",");
+	    }
+	}
+	result.append("]");
+	return result.toString();
+    }
+
+
+    /** Sorts an array of files, putting non-files first. Case insensitive.
+     * @param files_to_sort The File[] to be sorted.
+     */
+    static public void sort(File[] files_to_sort)
+    {
+	// Return if there is nothing to sort
+	if (files_to_sort == null || files_to_sort.length <= 1) {
+	    return;
+	}
+
+	FileSystemView fileSystemView = FileSystemView.getFileSystemView();
+	FileComparator comparator = new FileComparator();
+
+	// Separate the file system roots and directories from the files, and sort separately
+	ArrayList files_list = new ArrayList((files_to_sort.length * 3) / 4);
+	ArrayList non_files_list = new ArrayList((files_to_sort.length) / 4);
+	for (int i = 0; i < files_to_sort.length; i++) {
+	    File file = files_to_sort[i];
+
+	    // File is a system root
+	    if (fileSystemView.isFileSystemRoot(file)) {
+		non_files_list.add(file);
+	    }
+	    // File is a directory
+	    else if (file.isDirectory()) {
+		non_files_list.add(file);
+	    }
+	    // File is an actual file
+	    else {
+		files_list.add(file);
+	    }
+	}
+
+	// Sort files
+	Object[] files = files_list.toArray();
+	Arrays.sort(files, comparator);
+
+	// Sort non-files
+	Object[] non_files = non_files_list.toArray();
+	Arrays.sort(non_files, comparator);
+
+	// Merge the results, putting non-files before files
+	int j = 0;
+	for (int i = 0; i < non_files.length; i++) {
+	    files_to_sort[j++] = (File) non_files[i];
+	}
+	for (int i = 0; i < files.length; i++) {
+	    files_to_sort[j++] = (File) files[i];
+	}
+    }
+
+
+    /** Comparator used to order files. */
+    static private class FileComparator
+	implements Comparator {
+
+	/** Compare two files in terms of ordering of their paths.
+	 * @param o1 The <strong>Object</strong> that represents the first file.
+	 * @param o2 The other <strong>Object</strong>, also a file.
+	 * @return An <i>int</i> which is <1, 0 or >1 if o1 is <o2, =o2 or >o2 respectively.
+	 */
+	public int compare(Object o1, Object o2)
+	{
+	    File f1 = (File) o1;
+	    File f2 = (File) o2;
+
+	    return f1.getName().compareToIgnoreCase(f2.getName());
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/CheckList.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/CheckList.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/CheckList.java	(revision 10506)
@@ -0,0 +1,224 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.util;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+
+
+/** This class provides a visual component that has the form of a list, as provided by JList but uses JCheckBox for data selection. Thus several elements can be 'ticked' in the list, and this selection returned using the method getSelected().<BR>Parts of this code modified from Trevor Harmon's posting on www.dejanews.com.
+ * @author John Thompson
+ * @version 2.3
+ */ 
+public class CheckList
+    extends JList
+{
+    /** The border used when a list row is not in focus. */
+    static private Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
+
+    private boolean show_selected_row = true;
+
+
+    /** Constructor. */
+    public CheckList(boolean show_selected_row)
+    {
+	super();
+	this.show_selected_row = show_selected_row;
+
+	setCellRenderer(new CheckListCellRenderer());
+	setModel(new DefaultListModel());
+	setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	addMouseListener(new CheckListMouseListener());
+    }
+
+
+    public void addEntry(CheckListEntry entry)
+    {
+	DefaultListModel model = (DefaultListModel) getModel();
+
+	// Add the entry in alpabetical order
+	String name = entry.toString();
+	for (int i = 0; i < model.size(); i++) {
+	    Object sibling = model.getElementAt(i);
+	    if (name.compareTo(sibling.toString()) <= 0) {
+		model.add(i, entry);
+		return;
+	    }
+	}
+
+	model.addElement(entry);
+    }
+
+
+    public void clearTicked()
+    {
+	DefaultListModel model = (DefaultListModel) getModel();
+	for (int i = 0; i < model.size(); i++) {
+	    ((CheckListEntry) model.get(i)).setSelected(false);
+	}
+	updateUI();
+    }
+
+
+    /** Retrieve the currently ticked entries from this list.
+     * @return An <strong>ArrayList</strong> containing only those entries from the initial list that are checked.
+     * @see org.greenstone.gatherer.checklist.Entry
+     */
+    public ArrayList getTicked()
+    {
+	ArrayList result = new ArrayList();
+	DefaultListModel model = (DefaultListModel) getModel();
+	for (int i = 0; i < model.size(); i++) {
+	    CheckListEntry entry = (CheckListEntry) model.get(i);
+	    if (entry.isSelected()) {
+		result.add(entry.getObject());
+	    }
+	}
+	return result;
+    }
+
+
+    /** This is different from isSelectionEmpty! */
+    public boolean isNothingTicked()
+    {
+	DefaultListModel model = (DefaultListModel) getModel();
+	for (int i = 0; i < model.size(); i++) {
+	    if (((CheckListEntry) model.get(i)).isSelected()) {
+		return false;
+	    }
+	}
+
+	return true;
+    }
+
+
+    public void setListData(ArrayList list_data)
+    {
+ 	// Create a new model.
+	setModel(new DefaultListModel());
+
+	// Add the items from the list to the model
+ 	for (int i = 0; i < list_data.size(); i++) {
+ 	    Object list_object = list_data.get(i);
+ 	    if (list_object instanceof CheckListEntry) {
+ 		addEntry((CheckListEntry) list_object);
+ 	    }
+	    else {
+		addEntry(new CheckListEntry(list_object));
+	    }
+ 	}
+    }
+
+
+    public void setTickedObjects(Object[] objects)
+    {
+	if (objects == null) {
+	    return;
+	}
+
+	DefaultListModel model = (DefaultListModel) getModel();
+	for (int i = 0; i < model.size(); i++) {
+	    CheckListEntry entry = (CheckListEntry) model.get(i);
+	    for (int j = 0; j < objects.length; j++) {
+		if (entry.getObject().equals(objects[j])) {
+		    entry.setSelected(true);
+		}
+	    }
+	}
+	updateUI();
+    }
+
+
+    /** A custom list cell renderer for producing rows which contain clickable check boxes. */
+    protected class CheckListCellRenderer 
+	implements ListCellRenderer
+    {
+	/** Return a component that has been configured to display the specified value. That component's paint method is then called to "render" the cell. If it is necessary to compute the dimensions of a list because the list cells do not have a fixed size, this method is called to generate a component on which getPreferredSize  can be invoked.
+	 * @param list The </strong>JList</strong> we're painting.
+	 * @param value The value returned by list.getModel().getElementAt(index), as an <strong>Object</strong>.
+	 * @param index The cells index as an <i>int</i>.
+	 * @param is_selected <i>true</i> if the specified cell was selected, <i>false</i> otherwise.
+	 * @param cell_has_focus <i>true</i> if and only if the specified cell has the focus.
+	 * @return A <strong>Component</strong> whose paint() method will render the specified value.
+	 */
+	public Component getListCellRendererComponent(JList list, Object value, int index, boolean is_selected, boolean cell_has_focus) {
+	    JCheckBox checkbox = (JCheckBox) value;
+	    if (show_selected_row) {
+		checkbox.setBackground(is_selected ? list.getSelectionBackground() : list.getBackground());
+		checkbox.setForeground(is_selected ? list.getSelectionForeground() : list.getForeground());
+		checkbox.setBorderPainted(true);
+	    }
+	    else {
+		checkbox.setBackground(list.getBackground());
+		checkbox.setForeground(list.getForeground());
+		checkbox.setBorderPainted(false);
+	    }
+	    checkbox.setEnabled(list.isEnabled());
+	    checkbox.setFont(list.getFont());
+	    checkbox.setFocusPainted(false);
+	    checkbox.setBorder((is_selected) ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
+	    return checkbox;
+	}
+    }
+
+
+    /** Listens for clicks apon the checks within the list, and updates as necessary. */
+    private class CheckListMouseListener 
+	extends MouseAdapter
+    {
+	/** Called whenever the mouse is clicked over our list. We find the nearest checkbox and change its state.
+	 * @param e A <strong>MouseEvent</strong> containing everything you ever wanted to know about the mouse event but were afraid to ask.
+	 */
+	public void mousePressed(MouseEvent e)
+	{
+	    JList list = (JList) e.getSource();
+	    int index = list.locationToIndex(e.getPoint());
+	    CheckListEntry checkbox = (CheckListEntry) list.getModel().getElementAt(index);
+	    if (!checkbox.isFixed()) {
+		checkbox.setSelected(!checkbox.isSelected());
+	    }
+	    checkbox.grabFocus();
+
+	    // We need to cause a ListSelectionEvent -- this is ugly but I can't find a better way quickly
+	    list.removeSelectionInterval(0, 0);
+	    list.setSelectionInterval(index, index);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/CheckListEntry.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/CheckListEntry.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/CheckListEntry.java	(revision 10506)
@@ -0,0 +1,75 @@
+package org.greenstone.gatherer.util;
+
+import javax.swing.JCheckBox;
+
+/** A CheckListEntry encapsulates a single row of the list, both its check box and the object the row represents. */
+public class CheckListEntry
+    extends JCheckBox 
+    implements Comparable {
+
+    /** Is this checkboxes state fixed. */
+    private boolean fixed = false;
+    /** The original object this row is based on, and whose toString() is used to generate the check box label. */
+    private Object object = null;
+    /** A sundry string for storing original values (rather than strings retrieved from dictionary). */
+    private String property;
+    /** Constructor. */
+    public CheckListEntry(Object object) {
+	super(object.toString());
+	this.object = object;
+    }
+
+    /** Constructor. */
+    public CheckListEntry(String text, boolean is_selected) {
+	super(text);
+	setSelected(is_selected);
+    }
+
+    /** Test this CheckListEntry against an Object for ordering. 
+     * @param obj the other Object.
+     * @return <0, 0 or >0 if this CheckListEntry is before, equal to or after the given object.
+     */
+    public int compareTo(Object obj) {
+	return toString().toLowerCase().compareTo(obj.toString().toLowerCase());
+    }
+    /** Test this CheckListEntry against an Object for equality. 
+     * @param obj the other Object.
+     * @return true if the two are equal, false otherwise.
+     */
+    public boolean equals(Object obj) {
+	return toString().equalsIgnoreCase(obj.toString());
+    }
+
+    /** Retrieve the object associated with this entry.
+     * @return An <strong>Object</strong>.
+     */
+    public Object getObject() {
+	if(object == null) {
+	    return getText();
+	}
+	return object;
+    }
+
+    public String getProperty() {
+	return property;
+    }
+
+    public boolean isFixed() {
+	return fixed;
+    }
+
+    public void setFixed(boolean fixed) {
+	this.fixed = fixed;
+    }
+
+    public void setProperty(String property) {
+	this.property = property;
+    }
+
+    public String toString() {
+	if(object == null) {
+	    return getText();
+	}
+	return object.toString();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Codec.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Codec.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Codec.java	(revision 10506)
@@ -0,0 +1,379 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.util;
+
+import java.util.*;
+
+/** Provides a standard, extensible way to convert from one format of string to another (given that each format has differing requirements regarding legal characters and escaped characters)
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3d
+ */
+public class Codec {
+    
+    static final public String DECODE_PATH = "DECODE_PATH";
+    static final public String DECODE_SQUARE_BRACKETS = "DECODE_SQUARE_BRACKETS";
+    static final public String DOM_TO_GREENSTONE = "DOM_TO_GREENSTONE";
+    static final public String DOM_TO_TEXT = "DOM_TO_TEXT";
+    static final public String ENCODE_PATH = "ENCODE_PATH";
+    static final public String ENCODE_SQUARE_BRACKETS = "ENCODE_SQUARE_BRACKETS";
+    static final public String GREENSTONE_TO_DOM = "GREENSTONE_TO_DOM";
+    static final public String GREENSTONE_TO_TEXT = "GREENSTONE_TO_TEXT";
+    static final public String TEXT_TO_DOM = "TEXT_TO_DOM";
+    static final public String TEXT_TO_GREENSTONE = "TEXT_TO_GREENSTONE";
+    static final public String TEXT_TO_REGEXP = "TEXT_TO_REGEXP";
+    static final public String TEXT_TO_SHELL_UNIX = "TEXT_TO_SHELL_UNIX";
+    static final public String TEXT_TO_SHELL_WINDOWS = "TEXT_TO_SHELL_WINDOWS";
+    
+    static final private int MAX_CACHE_SIZE = 100;
+    
+    static private HashMap TRANSFORMS;
+    static private HashMap3D CACHE;
+    
+    /** Static function called to construct TRANSFORMS mappings */
+    static {
+	TRANSFORMS = new HashMap();
+
+	String[] decode_path = {
+	    "\\|",    "\\\\",
+	    "&#124;", "\\|"
+	};
+	TRANSFORMS.put(DECODE_PATH, decode_path);
+	decode_path = null;
+
+	// Transform text into text, but without [ and ]
+	String[] decode_square_brackets = {
+	    "&#091;", "\\[",
+	    "&#093;", "\\]" 
+	};
+	TRANSFORMS.put(DECODE_SQUARE_BRACKETS, decode_square_brackets);
+	decode_square_brackets = null;
+
+	// Translate DOM encoded text into Greenstone encoding
+	String[] dom_to_greenstone = {
+	    "&apos;", "\\\\\'",
+	    "&gt;", ">",
+	    "&lt;", "<",
+	    "&quot;", "\\\\\"",
+	    "&amp;", "&"
+	};
+	//  removed "\n", "\\\\n", - config files are allowed new lines
+	// added "\\|", "\\\\"
+
+	TRANSFORMS.put(DOM_TO_GREENSTONE, dom_to_greenstone);
+	dom_to_greenstone = null;
+
+	// Transform DOM encoded text into plain text
+	String[] dom_to_text = {
+	   "&amp;#091;", "\\[",
+	   "&amp;#093;", "\\]",
+	   "&apos;", "\'",
+	   "&gt;", ">",
+	   "&lt;", "<",
+	   "&quot;", "\"",
+	   "&amp;", "&"
+	};
+	TRANSFORMS.put(DOM_TO_TEXT, dom_to_text);
+	dom_to_text = null;
+
+	// Transform text into a regular expression that will match it
+	String[] text_to_regexp = {
+	    "\\\\", "\\\\\\\\",
+	    "\\(", "\\\\(",
+	    "\\)", "\\\\)",
+	    "\\[", "\\\\[",
+	    "\\]", "\\\\]",
+	    "\\{", "\\\\{",
+	    "\\}", "\\\\}",
+	    "\\.", "\\\\."
+	};
+	TRANSFORMS.put(TEXT_TO_REGEXP, text_to_regexp);
+	text_to_regexp = null;
+
+	String[] encode_path = {
+	    "\\|",  "&#124;",
+	    "\\\\", "\\|"
+	};
+	TRANSFORMS.put(ENCODE_PATH, encode_path);
+	encode_path = null;
+
+	// Transform text into text, but without [ and ]
+	String[] encode_square_brackets = {
+	    "\\[", "&#091;",
+	    "\\]", "&#093;"
+	};
+	TRANSFORMS.put(ENCODE_SQUARE_BRACKETS, encode_square_brackets);
+	encode_square_brackets = null;
+
+	// Transform Greenstone encoded text to DOM encoding
+	String[] greenstone_to_dom = {
+	    "&", "&amp;",
+	    "<", "&lt;",
+	    ">", "&gt;",
+	    "\\\\\"", "&quot;",
+	    "\\\\\'", "&apos;",
+	    "\"", "&quot;",
+	    "\'", "&apos;"
+	};
+	// removed"\\\\n", "\n", added "\\\\", "\\|"
+
+	TRANSFORMS.put(GREENSTONE_TO_DOM, greenstone_to_dom);
+	greenstone_to_dom = null;
+
+	// Transform Greenstone encoded text to plain text
+	String[] greenstone_to_text = {
+	    "\\\\\"", "\"",
+	    "\\\\\'", "\'",
+	    "&quot;", "\"",
+	    "&apos;", "\'",
+	    "&#091;", "\\[",
+	    "&#093;", "\\]"
+	};
+	// removed    "\\\\n", "\n", "\\|", "\\\\"
+
+	TRANSFORMS.put(GREENSTONE_TO_TEXT, greenstone_to_text);
+	greenstone_to_text = null;
+
+	// Transform plain html text into something that can be placed in a DOM
+	String[] text_to_dom = {
+	    "&", "&amp;",
+	    "<", "&lt;",
+	    ">", "&gt;",
+	    "\"", "&quot;",
+	    "\'", "&apos;"
+	};
+	TRANSFORMS.put(TEXT_TO_DOM, text_to_dom);
+	text_to_dom = null;
+
+	// Transform plain html text into greenstone encoding
+	String[] text_to_greenstone = {
+
+	    "\\[", "&#091;",
+	    "\\]", "&#093;",
+	    "\"", "&quot;",
+	    "\n", "\\\\n"
+	};
+	// 	    "\'", "&apos;",
+	// removed "\\\\", "\\|",
+	TRANSFORMS.put(TEXT_TO_GREENSTONE, text_to_greenstone);
+	text_to_greenstone = null;
+
+	// Transform plain html text into something that can be placed in a shell command
+	String[] text_to_shell_unix = {
+	    "\"", "\\\\\"",
+	    "\'", "\\\\\'",
+	    "\n", "\\\\n"
+	};
+	TRANSFORMS.put(TEXT_TO_SHELL_UNIX, text_to_shell_unix);
+	text_to_shell_unix = null;
+
+	// Transform plain html text into something that can be placed in a shell command. Windows requires twice as many escaped for speech marks to be passed to underlying processes
+	String[] text_to_shell_windows = {
+	    "\"", "\\\\\\\\\\\\\"",
+	    "\'", "\\\\\'",
+	    "\n", "\\\\n"
+	};
+	TRANSFORMS.put(TEXT_TO_SHELL_WINDOWS, text_to_shell_windows);
+	text_to_shell_windows = null;
+
+	CACHE = new HashMap3D();
+    }
+
+    static public String transform(String raw, String transform) {
+	if(raw == null) {
+	    return raw;
+	}
+	// System.err.println("Transforming by "+transform+":\n" + raw);
+	String processed = (String) CACHE.get(transform, raw);
+	if(processed == null) {
+	    processed = raw;
+	    String[] transforms = (String[]) TRANSFORMS.get(transform);
+	    if(transforms != null) {
+		for(int i = 0; i < transforms.length; i = i + 2) {
+		    String target = transforms[i];
+		    String result = transforms[i+1];
+		    processed = processed.replaceAll(target, result);
+		}
+	    }
+	    //DebugStream.println("\n*** Transform: " + transform + " ***");
+	    //DebugStream.println("*** Raw      : '" + raw + "'");
+	    //DebugStream.println("*** Processed: '" + processed + "'");
+	    // If cache is at maximum size, empty it and start again
+	    if(CACHE.size() == MAX_CACHE_SIZE) {
+		CACHE.clear();
+	    }
+	    CACHE.put(transform, raw, processed);
+	}
+	return processed;
+    }
+
+    /** Transform either of the accepted unicode escape sequences styles from in the string into single characters */
+    static final private char AND_CHAR = '&';
+    static final private char ESCAPE_CHAR = '\\';
+    static final private char HASH_CHAR = '#';
+    static final private char LOWER_U_CHAR = 'u';
+    static final private char UPPER_U_CHAR = 'U';
+    static final private char SEMICOLON_CHAR = ';';
+
+    static public String transformUnicode(String raw) {
+	StringBuffer processed = new StringBuffer();
+	int index = 0;
+	int raw_length = raw.length();
+	while(index < raw_length) {
+	    char c0 = raw.charAt(index);
+	    switch(c0) {
+	    case AND_CHAR:
+		if(index + 1 < raw_length) {
+		    // First the HTML &#231; type
+		    char c1 = raw.charAt(index + 1);
+		    if(c1 == HASH_CHAR) {
+			StringBuffer number_str = new StringBuffer();
+			char c2;
+			int offset = 2;
+			while(index + offset < raw_length && (c2 = raw.charAt(index + offset)) != SEMICOLON_CHAR) {
+			    number_str.append(c2);
+			    offset++;
+			}
+			// We've either run out of characters or have parsed a number
+			if(index + offset < raw_length && raw.charAt(index + offset) == SEMICOLON_CHAR) {
+			    int number = Integer.parseInt(number_str.toString());
+			    processed.append((char)number);
+			    index = index + offset;
+			    number_str = null;
+			    break;
+			}
+			number_str = null;
+		    }
+		}
+		processed.append(c0);
+		break;
+	    case ESCAPE_CHAR:
+		// Now the \u00e7 type
+		if(index + 1 < raw_length) {
+		    char c3 = raw.charAt(index + 1);
+		    if((c3 == UPPER_U_CHAR || c3 == LOWER_U_CHAR) && index + 5 < raw_length) {
+			// We read four digits
+			String hex_str = raw.substring(index + 2, index + 6);
+			int number = Integer.parseInt(hex_str, 16);
+			hex_str = null;
+			processed.append((char)number);
+			index = index + 5;
+			break;
+		    }
+		}
+		processed.append(c0);
+		break;
+	    default:
+		processed.append(c0);
+	    }
+	    index++;
+	}
+	return processed.toString();
+    }
+
+    static public void main(String[] args) {
+	if(args.length < 2) {
+	    String processed;
+	    String raw;
+	    String transform;
+
+	    System.err.println("Running Test Suite");
+
+	    transform = "DOM_TO_GREENSTONE";
+	    System.err.println("Test " + transform);
+	    raw = "A &amp;lt;\nand a &lt;a href=&quot;here.html&quot;&gt;&lt;font size=&apos;2&apos;&gt;URL&lt;/font&gt;&lt;/a&gt;";
+	    System.err.println("Raw:       '" + raw + "'");
+	    processed = transform(raw, transform);
+	    System.err.println("Processed: '" + processed + "'");
+
+	    transform = "DOM_TO_TEXT";
+	    System.err.println("Test " + transform);
+	    raw = "A &amp;lt;\nand a &lt;a href=&quot;here.html&quot;&gt;&lt;font size=&apos;2&apos;&gt;URL&lt;/font&gt;&lt;/a&gt;";
+	    System.err.println("Raw:       '" + raw + "'");
+	    processed = transform(raw, transform);
+	    System.err.println("Processed: '" + processed + "'");
+
+	    transform = "GREENSTONE_TO_DOM";
+	    System.err.println("Test " + transform);
+	    raw = "A &lt;\\nand a <a href=\\\"here.html\\\"><font size=\\\'2\\\'URL</font></a>";
+	    System.err.println("Raw:       '" + raw + "'");
+	    processed = transform(raw, transform);
+	    System.err.println("Processed: '" + processed + "'");
+
+	    transform = "GREENSTONE_TO_TEXT";
+	    System.err.println("Test " + transform);
+	    raw = "These \\[ \\] should be escaped, and so should \\\\ that. These &quot; &apos; \\n are encoded.";
+	    System.err.println("Raw:       '" + raw + "'");
+	    processed = transform(raw, transform);
+	    System.err.println("Processed: '" + processed + "'");
+
+	    transform = "TEXT_TO_DOM";
+	    System.err.println("Test " + transform);
+	    raw = "A &lt;\nand a <a href=\"here.html\"><font size='2'>URL</font></a>";
+	    System.err.println("Raw:       '" + raw + "'");
+	    processed = transform(raw, transform);
+	    System.err.println("Processed: '" + processed + "'");
+
+	    transform = "TEXT_TO_GREENSTONE";
+	    System.err.println("Test " + transform);
+	    raw = "These [ ] should be escaped, and so should \\ that. These \" \' \n are encoded.";
+	    System.err.println("Raw:       '" + raw + "'");
+	    processed = transform(raw, transform);
+	    System.err.println("Processed: '" + processed + "'");
+
+	    transform = "TEXT_TO_SHELL";
+	    System.err.println("Test " + transform);
+	    if(Utility.isWindows()) {
+		System.err.println("[Windows Version]");
+		transform = "TEXT_TO_SHELL_WINDOWS";
+	    }
+	    else {
+		System.err.println("[Unix Version]");
+		transform = "TEXT_TO_SHELL_UNIX";
+	    }
+	    raw = "A &lt;\nand a <a href=\"here.html\"><font size='2'>URL</font></a>";
+	    System.err.println("Raw:       '" + raw + "'");
+	    processed = transform(raw, transform);
+	    System.err.println("Processed: '" + processed + "'");
+
+	    System.err.println("***** UNICODE TEST *****");
+	    System.err.println("\\u0030 => " + transformUnicode("\\u0030"));
+	    System.err.println("\\u0041 => " + transformUnicode("\\u0041"));
+	    System.err.println("\\u007a => " + transformUnicode("\\u007a"));
+	    System.err.println("\\u00e7 => " + transformUnicode("\\u00e7"));
+	    System.err.println("&#48;   => " + transformUnicode("&#48;"));
+	    System.err.println("&#65;   => " + transformUnicode("&#65;"));
+	    System.err.println("&#122;  => " + transformUnicode("&#122;"));
+	    System.err.println("&#231;  => " + transformUnicode("&#231;"));
+	}
+	else {
+	    System.err.println("Raw:       '" + args[0] + "'");
+	    System.err.println("Transform: " + args[1]);
+	    String processed = transform(args[0], args[1]);
+	    System.err.println("Processed: '" + processed + "'");
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DOMTree.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DOMTree.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DOMTree.java	(revision 10506)
@@ -0,0 +1,149 @@
+package org.greenstone.gatherer.util;
+
+import java.util.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+import org.w3c.dom.*;
+
+public class DOMTree
+    extends JTree {
+
+    public DOMTree(Document document) {
+	super();
+	setDocument(document);
+    }
+
+    public void setDocument(Document document) {
+	setModel(new DefaultTreeModel(new DOMTreeNode(document.getDocumentElement(), null)));
+    }
+
+    private class DOMTreeNode 
+	implements TreeNode {
+
+	private Node node = null;
+	private NodeList children = null;
+	private String text = null;
+	private TreeNode parent = null;
+	private TreeNode self = null;
+
+	DOMTreeNode(Node node, TreeNode parent) {
+	    this.node = node;
+	    this.parent = parent;
+	    this.self = this;
+	}
+	
+	/** Returns the children of the receiver as an Enumeration. */
+	public Enumeration children() {
+	    if(children == null) {
+		children = node.getChildNodes();
+	    }
+	    return new NodeListEnumeration();
+	}
+          
+	/** Returns true if the receiver allows children. */
+	public boolean getAllowsChildren() {
+	    return true;
+	}
+          
+	/** Returns the child TreeNode at index childIndex. */
+	public TreeNode getChildAt(int childIndex) {
+	    if(children == null) {
+		children = node.getChildNodes();
+	    }
+	    return new DOMTreeNode(children.item(childIndex), this);
+	}
+          
+	/** Returns the number of children TreeNodes the receiver contains. */
+	public int getChildCount() {
+	    if(children == null) {
+		children = node.getChildNodes();
+	    }
+	    return children.getLength();
+	}
+          
+	/** Returns the index of node in the receivers children. */
+	public int getIndex(TreeNode find_node) {
+	    if(children == null) {
+		children = node.getChildNodes();
+	    }
+	    Node target_node = ((DOMTreeNode)find_node).getNode();
+	    int children_count = children.getLength();
+	    for(int i = 0; i < children_count; i++) {
+		Node test_node = children.item(i);
+		if(target_node == test_node) {
+		    test_node = null;
+		    target_node = null;
+		    return i;
+		}
+		test_node = null;
+	    }
+	    target_node = null;
+	    return -1;
+	}
+	    
+	public Node getNode() {
+	    return node;
+	}
+
+	/** Returns the parent TreeNode of the receiver. */
+	public TreeNode getParent() {
+	    return parent;
+	}
+	    
+	/** Returns true if the receiver is a leaf. */
+	public boolean isLeaf() {
+	    return !node.hasChildNodes();
+	}
+
+	public String toString() {
+	    if(text == null) {
+		StringBuffer temp = new StringBuffer(node.getNodeName());
+		String value = node.getNodeValue();
+		if(value != null && value.length() != 0) {
+		    temp.append("=\"");
+		    temp.append(value);
+		    temp.append("\"");
+		}
+		value = null;
+		if(node instanceof Element) {
+		    Element element = (Element) node;
+		    temp.append(": ");
+		    NamedNodeMap attributes = element.getAttributes();
+		    int attribute_count = attributes.getLength();
+		    for(int i = 0; i < attribute_count; i++) {
+			Node attribute = attributes.item(i);
+			temp.append(attribute.getNodeName());
+			temp.append("=\"");
+			temp.append(attribute.getNodeValue());
+			if(i < attribute_count - 1) {
+			    temp.append("\" ");
+			}
+			else {
+			    temp.append("\"");
+			}
+		    }
+		    attributes = null;
+		    element = null;
+		}
+		text = temp.toString();
+		temp = null;
+	    }
+	    return text;
+	}
+
+	private class NodeListEnumeration
+	    implements Enumeration {
+	    private int index = 0;
+	    /** Tests if this enumeration contains more elements. */
+	    public boolean hasMoreElements() {
+		return index < children.getLength();
+	    }
+	    /** Returns the next element of this enumeration if this enumeration object has at least one more element to provide. */
+	    public Object nextElement() {
+		int old_index = index;
+		index = index + 1;
+		return new DOMTreeNode(children.item(old_index), self);
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DragComponent.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DragComponent.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DragComponent.java	(revision 10506)
@@ -0,0 +1,65 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.util;
+/**
+ * Title:        Gatherer<br>
+ * Description:  The Gatherer: a tool for gathering and enriching a digital collection.<br>
+ * Copyright:    Copyright (c) 2001<br>
+ * Company:      The University of Waikato<br>
+ * Written:        /  /01<br>
+ * Revised:      21/06/02 - Moved into correct package and commented.<br>
+ * @author John Thompson, 9826509
+ * @version 2.1
+ */
+import java.awt.event.FocusListener;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.file.FileSystemModel;
+
+/** Any component that wants to act a GTree like drag'n'drop component must implement this. */
+public interface DragComponent {
+    public void addFocusListener(FocusListener listener);
+    /** In order for the appearance to be consistant, given we may be in the situation where the pointer has left our focus but the ghost remains, this method allows other members of the Group to tell this component to repair the 'spoilt' region left by its ghost. */
+    public void clearGhost();
+    /** Used to notify this component that it has gained focus by some method other that mouse focus. */
+    public void gainFocus();	 
+    /** Retrieve the model associated with this component. */
+    public FileSystemModel getTreeModel();
+    /** This method is used to inform this component when it loses focus by means other than a drag mouse event, and should indicate this somehow. */
+    public void loseFocus();
+    /** Set the components group. */
+    public void setGroup(DragGroup group);
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DragGroup.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DragGroup.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DragGroup.java	(revision 10506)
@@ -0,0 +1,136 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.util;
+
+import java.awt.Point;
+import java.awt.event.*;
+import java.awt.image.BufferedImage;
+import java.util.Vector;
+import javax.swing.JComponent;
+import javax.swing.tree.TreePath;
+import org.greenstone.gatherer.gui.tree.DragTree;
+
+
+/** This class acts as a linker between all the various drag and drop enabled DragComponent. It provides methods for ensuring only one component is the drop target, showing extra user feedback, and maintains a single point of focus. Moreover it provides a storage space for necessary shared variables such as mouse_offset of initial drag etc. */
+public class DragGroup 
+    implements FocusListener {
+    /** The image used for the ghost icon when dragging. */
+    public BufferedImage image_ghost = null;
+    /** The initial offset of the mouse from the selection within a DragComponent. Then as you drag the mouse, the ghost appears in a visually consistant place, and remains at the same offset throughout the dragging process. */
+    public Point mouse_offset = null;
+    /** The component currently in charge of drawing the ghost icon. Note that this isn't necessarily the only component that needs to repaint 'spoilt' screen real-estate as a side effect of the ghost. */
+    private DragComponent ghost_owner = null;
+    /** The component where the drag began, so that extra information necessary for the drag can be garnered by the drop target, or so that focus can return to the source component if the drop is rejected. */
+    private DragTree drag_source = null;
+    /** The selected nodes, as determined when the drag begun. */
+    private TreePath[] selection = null;
+    /** A list of DragComponents registered as being part of this group. */
+    private Vector registered = new Vector();
+
+    /** Register a DragComponent as begin part of this group.
+     * @param component The DragComponent to add.
+     */
+    public void add(DragComponent component) {
+	if(!registered.contains(component)) {
+	    registered.add(component);
+	    component.addFocusListener(this);
+	    component.setGroup(this);
+	}
+    }
+
+    /** Invoked when a component gains the keyboard focus. */
+    public void focusGained(FocusEvent event) {
+	((DragComponent)event.getComponent()).gainFocus();
+    }
+          
+    /** Invoked when a component loses the keyboard focus. */
+    public void focusLost(FocusEvent event) {
+	((DragComponent)event.getComponent()).loseFocus();
+    }          
+    /** Determines the current 'active' component, ie that component with focus.
+     * @return The DragComponent which is currently responsible for drawing the ghost, and thus is active.
+     */
+    public DragComponent getActive() {
+	return ghost_owner;
+    }
+    /** Retrieve the nodes selected at the beginning of this drag operation.
+     * @return A TreePath[].
+     */
+    public TreePath[] getSelection() {
+	return selection;
+    }
+    /** Retrieve the component which served as the source of this drag action.
+     * @return The DragComponent in question.
+     */
+    public DragTree getSource() {
+	return drag_source;
+    }
+    /** When called this method asserts that one of the registered GComponents just became the proud owner of focus, and is henceforth responsible for drawing the ghost, and acting like a component thats in focus.
+     * @param new_owner The DragComponent that has gained focus during a drag action.
+     */
+    public void grabFocus(DragComponent new_owner) {
+	// Tell the previous owner of ghost to clear itself.
+	if(ghost_owner != null) {
+	    ghost_owner.clearGhost();
+	}
+	// Assign new owner
+	ghost_owner = new_owner;
+	// Then tell all other GComponents to indicate they aren't in focus in whatever way they do that (ie selected items of a GTree go gray). Of course the new owners told it is in focus.
+	for(int i = 0; i < registered.size(); i++) {
+	    DragComponent comp = (DragComponent)registered.get(i);
+	    if(comp == new_owner) {
+		comp.gainFocus();
+	    }
+	    else {
+		comp.loseFocus();
+	    }
+	}
+    }
+    /** Sets the value of selected_nodes.
+     * @param selection The new value for selected_nodes as a TreePath[].
+     */
+    public void setSelection(TreePath[] selection) {
+	this.selection = selection;
+    }
+    /** Sets the value of drag_source.
+     * @param drag_source The new value for drag_source as a DragTree.
+     */
+    public void setSource(DragTree drag_source) {
+	this.drag_source = drag_source;
+	///ystem.err.println("The drag source is now " + drag_source);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DragTreeSelectionModel.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DragTreeSelectionModel.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/DragTreeSelectionModel.java	(revision 10506)
@@ -0,0 +1,278 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.util;
+
+import java.awt.Point;
+import java.awt.event.*;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.gui.tree.DragTree;
+
+public class DragTreeSelectionModel
+    extends DefaultTreeSelectionModel
+    implements MouseListener {
+
+    private boolean immediate = false;
+    private boolean mixed_selection = false;
+
+    private int type               = -1;
+
+    private TreePath temp_path     = null;
+    private TreePath temp_paths[]  = null;
+
+    static private final int NONE  = -1;
+    static private final int ADD   =  0;
+    static private final int SET   =  1;
+
+    /** Constructor.
+     * @param tree the DragTree which will use this selection model.
+     * @param mixed_selection true if this selection model allows selections to contain files and folders, false otherwise.
+     */
+    public DragTreeSelectionModel(DragTree tree, boolean mixed_selection) {
+	super();
+	this.mixed_selection = mixed_selection;
+	setSelectionMode(DISCONTIGUOUS_TREE_SELECTION);
+	tree.addMouseListener(this);
+    }
+
+    public void addSelectionPath(TreePath path) {
+	if(!immediate) {
+	    this.temp_path = path;
+	    this.type = this.ADD;
+	}
+	else if(isAppropriate(path)) {
+	    temp_path = null;
+	    super.addSelectionPath(path);
+	}
+    }
+
+    public void addSelectionPaths(TreePath paths[]) {
+	if(!immediate) {
+	    this.temp_paths = paths;
+	    this.type = this.ADD;
+	}
+	else if(isAppropriate(paths, true)) {
+	    temp_paths = null;
+	    super.setSelectionPaths(paths);
+	}
+    }
+
+    public String getDetails() {
+	String suffix = null;
+	int file_count = 0;
+	int folder_count = 0;
+	for(int i = 0; selection != null && i < selection.length; i++) {
+	    TreeNode node = (TreeNode) selection[i].getLastPathComponent();
+	    if(node.isLeaf()) {
+		file_count++;
+	    }
+	    else {
+		folder_count++;
+	    }
+	}
+
+	// Update the metaaudit_suffix
+	String args[] = null;
+	if(file_count > 0 && folder_count > 0) {
+	    if(file_count > 1 && folder_count > 1) {
+		args = new String[2];
+		args[0] = String.valueOf(file_count);
+		args[1] = String.valueOf(folder_count);
+		suffix = Dictionary.get("FileActions.Selected", args);
+	    }
+	    else if(file_count > 1) {
+		args = new String[1];
+		args[0] = String.valueOf(file_count);
+		suffix = Dictionary.get("FileActions.Files_And_Directory_Selected", args);
+	    }
+	    else if(folder_count > 1) {
+		args = new String[1];
+		args[0] = String.valueOf(folder_count);
+		suffix = Dictionary.get("FileActions.File_And_Directories_Selected", args);
+	    }
+	    else {
+		suffix = Dictionary.get("FileActions.File_And_Directory_Selected");
+	    }
+	}
+	else if(file_count > 0) {
+	    if(file_count > 1) {
+		args = new String[1];
+		args[0] = String.valueOf(file_count);
+		suffix = Dictionary.get("FileActions.Files_Selected", args);
+	    }
+	    else if(file_count == 1) {
+		suffix = Dictionary.get("FileActions.File_Selected");
+	    }
+	}
+	else if(folder_count > 0) {
+	    if(folder_count > 1) {
+		args = new String[1];
+		args[0] = String.valueOf(folder_count);
+		suffix = Dictionary.get("FileActions.Directories_Selected", args);
+	    }
+	    else {
+		suffix = Dictionary.get("FileActions.Directory_Selected");
+	    }
+	}
+	args = null;
+
+	return suffix;
+    }
+
+    /** Any implementation of MouseListener must include this method so
+     * we can be informed when the mouse is clicked.
+     * @param event A MouseEvent containing all the information about
+     * this mouse click.
+     */
+    public void mouseClicked(MouseEvent event) {
+    }
+
+    /** Any implementation of MouseListener must include this method so
+     * we can be informed when the mouse enters a component.
+     * @param event A MouseEvent containing all the information about
+     * this mouse action.
+     */
+    public void mouseEntered(MouseEvent event) {
+    }
+
+    /** Any implementation of MouseListener must include this method so
+     * we can be informed when the mouse exits a component.
+     * @param event A MouseEvent containing all the information about
+     * this mouse action.
+     */
+    public void mouseExited(MouseEvent event) {
+    }
+
+    /** Any implementation of MouseListener must include this method so
+     * we can be informed when the mouse is pressed (start of click).
+     * @param event A MouseEvent containing all the information about
+     * this mouse action.
+     */
+    public void mousePressed(MouseEvent event) {
+    }
+
+    /** Any implementation of MouseListener must include this method so
+     * we can be informed when the mouse is released (end of click).
+     * @param event A MouseEvent containing all the information about
+     * this mouse action.
+     */
+    public void mouseReleased(MouseEvent event) {
+	try {
+	switch(this.type) {
+	case 0: // this.ADD
+	    if(this.temp_path != null && isAppropriate(temp_path)) {
+		super.addSelectionPath(this.temp_path);
+		this.temp_path = null;
+	    }
+	    if(this.temp_paths != null && isAppropriate(temp_paths, true)) {
+		super.addSelectionPaths(this.temp_paths);
+		this.temp_paths = null;
+	    }
+	    this.type = this.NONE;
+	    break;
+	case 1: // this.SET
+	    if(this.temp_path != null) {
+		super.setSelectionPath(this.temp_path);
+		this.temp_path = null;
+	    }
+	    if(this.temp_paths != null && isAppropriate(temp_paths, false)) {
+		super.setSelectionPaths(this.temp_paths);
+		this.temp_paths = null;
+	    }
+	    this.type = this.NONE;
+	    break;
+	}
+	}
+	catch (Exception error) {
+		DebugStream.printStackTrace(error);
+	}
+    }
+
+    public void setImmediate(boolean value) {
+	immediate = value;
+    }
+
+    public void setSelectionPath(TreePath path) {
+	// Since this is only a single path we don't need to check whether its an appropriate selection.
+	if(!immediate) {
+	    this.temp_path = path;
+	    this.type = this.SET;
+	}
+	else {
+	    temp_path = null;
+	    super.setSelectionPath(path);
+	}
+    }
+
+    public void setSelectionPaths(TreePath paths[]) {
+	if(!immediate) {
+	    this.temp_paths = paths;
+	    this.type = this.SET;
+	}
+	else if(isAppropriate(paths, false)) {
+	    temp_paths = null;
+	    super.setSelectionPaths(paths);
+	}
+    }
+
+    /** Ensure that the given path is appropriate to add to the current selection, preventing mixed selections of files and folder if required. We also must check that no path is a ancestor/descendant of another.
+     */
+    private boolean isAppropriate(TreePath path) {
+	boolean appropriate = true;
+	TreeNode new_node = (TreeNode) path.getLastPathComponent();
+	// If there is a current selection
+	if(selection != null && selection.length > 0) {
+	    for(int i = 0; appropriate && i < selection.length; i++) {
+		TreeNode current_node = (TreeNode) selection[i].getLastPathComponent();
+		appropriate = appropriate && (mixed_selection || new_node.isLeaf() == current_node.isLeaf());
+		appropriate = appropriate && !path.isDescendant(selection[i]) && !selection[i].isDescendant(path);
+	    }
+	}
+	return appropriate;
+    }
+    /** Ensure that the given paths are appropriate to add to the current selection, preventing mixed selections of files and folder if required. We also must check that no path is a ancestor/descendant of another. One last detail to keep in mind is that adding selections depends upon the current selection, whereas set the selection paths doesn't (replaces them instead) and thus no check of the current paths is needed. */
+    private boolean isAppropriate(TreePath[] paths, boolean check_current) {
+	boolean appropriate = true;
+	if(check_current && paths != null && paths.length > 0) {
+	    for(int i = 0; appropriate && i < paths.length; i++) {
+		appropriate = appropriate && isAppropriate(paths[i]);
+	    }
+	}
+	return appropriate;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/ExternalProgram.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/ExternalProgram.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/ExternalProgram.java	(revision 10506)
@@ -0,0 +1,107 @@
+package org.greenstone.gatherer.util;
+
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import org.greenstone.gatherer.DebugStream;
+
+
+/**
+ * This class provides a convenient method of running external programs and viewing/analysing
+ * their output. The external programs may be run with or without arguments. 
+ */
+public class ExternalProgram
+{
+    private Process programProcess = null;
+
+    private BufferedReader programOut = null;
+    private BufferedReader programErr = null;
+
+
+    /**
+     * Prepares to run a specified external program with the specified arguments.
+     *
+     * @param programName The name (and path, if necessary) of the program to run.
+     * @param programArgs The arguments to provide to the program when run.
+     */
+    public ExternalProgram(String programName, String programArgs)
+	throws IOException
+    {
+	// Run the program
+	programProcess = Runtime.getRuntime().exec(programName + " " + programArgs);
+
+	// Grab the program output
+	programOut = new BufferedReader(new InputStreamReader(programProcess.getInputStream()));
+	programErr = new BufferedReader(new InputStreamReader(programProcess.getErrorStream()));
+
+    }
+
+
+
+    /**
+     */
+    public int exitProgram()
+	throws IOException
+    {
+	// Finished, thank you
+	//programIn.close();
+
+	// Wait for the process to finish
+	try {
+	    programProcess.waitFor();
+	}
+	catch (InterruptedException ex) {
+	    throw new Error("Internal Error: Process interrupted.\n" + ex);
+	}
+
+	// Return the program exit value
+	return programProcess.exitValue();
+    }
+
+
+    /**
+     * Returns a single line of output sent by the program to standard output.
+     *
+     * @return a single line of output sent by the program to standard output.
+     */
+    public String getLineOfProgramOutput()
+    {
+	// Read in a line from the program output
+	try {
+	    if (programOut.ready())
+		return programOut.readLine();
+	    else
+		return null;
+	}
+	catch (IOException ex) {
+	    DebugStream.println("Error: Exception occurred while reading program output.");
+	    DebugStream.println("Exception: " + ex);
+	    return null;
+	}
+    }
+
+
+    /**
+     * Returns a single line of output sent by the program to standard error.
+     *
+     * @return a single line of output sent by the program to standard error.
+     */
+    public String getLineOfProgramError()
+    {
+	// Read in a line from the program error
+	try {
+	    if (programErr.ready())
+		return programErr.readLine();
+	    else
+		return null;
+	}
+	catch (IOException ex) {
+	    DebugStream.println("Error: Exception occurred while reading program error.");
+	    DebugStream.println("Exception: " + ex);
+	    return null;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/GSDLSiteConfig.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/GSDLSiteConfig.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/GSDLSiteConfig.java	(revision 10506)
@@ -0,0 +1,205 @@
+package org.greenstone.gatherer.util;
+
+import java.io.*;
+import java.util.*;
+
+public class GSDLSiteConfig
+    extends LinkedHashMap {
+    private File gsdlsite_cfg;
+    private File glisite_cfg;
+    private String autoenter_initial;
+    private String start_browser_initial;
+    
+    static final private String AUTOENTER = "autoenter";
+    static final private String COLON = ":";
+    static final private String ENTERLIB = "enterlib";
+    static final private String FALSE = "0";
+    static final private String GLISITE_CFG = "glisite.cfg";
+    static final private String GSDL = "gsdl";
+    static final private String GSDLSITE_CFG = "gsdlsite.cfg";
+    static final private String LOCAL_HOST = "http://localhost"; 
+    static final private String PORTNUMBER = "portnumber";
+    static final private String SEPARATOR = "/";
+    static final private String SPECIFIC_CONFIG = "--config=";
+    static final private String STARTBROWSER = "start_browser";
+    static final private String TRUE = "1";
+    static final private String URL = "url";
+
+    public GSDLSiteConfig(File server_exe) {
+	debug("New GSDLSiteConfig for: " + server_exe.getAbsolutePath());
+	gsdlsite_cfg = new File(server_exe.getParentFile(), GSDLSITE_CFG);
+	glisite_cfg = new File(server_exe.getParentFile(), GLISITE_CFG);
+	autoenter_initial = null;
+	start_browser_initial = null;
+	if(gsdlsite_cfg.exists()) {
+	    debug("Load: " + gsdlsite_cfg.getAbsolutePath());
+	    clear();
+	    try {
+		BufferedReader in = new BufferedReader(new FileReader(gsdlsite_cfg));
+		String line = null;
+		while((line = in.readLine()) != null) {
+		    String key = null;
+		    String value = null;
+		    int index = -1;
+		    if((index = line.indexOf("=")) != -1 && line.length() >= index + 1) {
+			key = line.substring(0, index);
+			value = line.substring(index + 1);
+		    }
+		    else {
+			key = line;
+		    }
+		    put(key, value);
+		}
+	    }
+	    catch (Exception error) {
+		error.printStackTrace();
+	    }
+	}
+	else {
+	    debug("No GSDLsite.cfg file can be found!");
+	}
+    }
+
+    public boolean exists() {
+	return gsdlsite_cfg.exists();
+    }
+
+    public String getLocalHostURL() {
+	StringBuffer url = new StringBuffer(LOCAL_HOST);
+	url.append(COLON);
+	url.append((String)get(PORTNUMBER));
+	String enterlib = (String)get(ENTERLIB);
+	if(enterlib == null || enterlib.length() == 0) {
+	    // Use the default /gsdl and hope for the best.
+	    url.append(SEPARATOR);
+	    url.append(GSDL);
+	}
+	else {
+	    if(!enterlib.startsWith(SEPARATOR)) {
+		url.append(SEPARATOR);
+	    }
+	    url.append(enterlib);
+	}
+	enterlib = null;
+	debug("Found Local Library Address: " + url.toString());
+	return url.toString();
+    }
+
+    public String getSiteConfigFilename() {
+	return SPECIFIC_CONFIG + glisite_cfg.getAbsolutePath();
+    }
+
+    public String getURL() {
+	// URL is made from url and portnumber
+	String url = (String) get(URL);
+	if(url != null) {
+	    StringBuffer temp = new StringBuffer(url);
+	    temp.append(COLON);
+	    temp.append((String)get(PORTNUMBER));
+	    String enterlib = (String)get(ENTERLIB);
+	    if(enterlib == null || enterlib.length() == 0) {
+		// Use the default /gsdl and hope for the best.
+		temp.append(SEPARATOR);
+		temp.append(GSDL);
+	    }
+	    else {
+		if(!enterlib.startsWith(SEPARATOR)) {
+		    temp.append(SEPARATOR);
+		}
+		temp.append(enterlib);
+	    }
+	    enterlib = null;
+	    url = temp.toString();
+	}
+	debug("Found Local Library Address: " + url);
+	return url;
+    }
+
+    public void load() {
+	if(glisite_cfg.exists()) {
+	    debug("Load: " + glisite_cfg.getAbsolutePath());
+	    clear();
+	    try {
+		BufferedReader in = new BufferedReader(new FileReader(glisite_cfg));
+		String line = null;
+		while((line = in.readLine()) != null) {
+		    String key = null;
+		    String value = null;
+		    int index = -1;
+		    if((index = line.indexOf("=")) != -1 && line.length() >= index + 1) {
+			key = line.substring(0, index);
+			value = line.substring(index + 1);
+		    }
+		    else {
+			key = line;
+		    }
+		    put(key, value);
+		}
+	    }
+	    catch (Exception error) {
+		error.printStackTrace();
+	    }
+	}
+	else {
+	    debug("No GSDLsite.cfg file can be found!");
+	}
+    }
+
+    /** Restore the autoenter value to its initial value, and remove url if present. */
+    public void restore() {
+	if(glisite_cfg != null) {
+	    // Delete the file
+	    glisite_cfg.delete();
+	}
+	else {
+	    debug("Restore Initial Settings");
+	    put(AUTOENTER, autoenter_initial);
+	    put(STARTBROWSER, start_browser_initial);
+	    remove(URL);
+	    save();
+	}
+    }
+
+    public void set() {
+	debug("Set Session Settings");
+	if(autoenter_initial == null) {
+	    autoenter_initial = (String) get(AUTOENTER);
+	    debug("Remember autoenter was: " + autoenter_initial);
+	}
+	put(AUTOENTER, TRUE);
+	if(start_browser_initial == null) {
+	    start_browser_initial = (String) get(STARTBROWSER);
+	    debug("Remember start_browser was: " + start_browser_initial);
+	}
+	put(STARTBROWSER, FALSE);
+	save();
+    }
+
+    private void debug(String message) {
+	///ystem.err.println(message);
+    }
+
+    private void save() {
+	//debug("Save: " + gsdlsite_cfg.getAbsolutePath());
+	debug("Save: " + glisite_cfg.getAbsolutePath());
+	try {
+	    //BufferedWriter out = new BufferedWriter(new FileWriter(gsdlsite_cfg, false));
+	    BufferedWriter out = new BufferedWriter(new FileWriter(glisite_cfg, false));
+	    for(Iterator keys = keySet().iterator(); keys.hasNext(); ) {
+		String key = (String) keys.next();
+		String value = (String) get(key);
+		out.write(key, 0, key.length());
+		if(value != null) {
+		    out.write('=');
+		    out.write(value, 0, value.length());
+		}
+		out.newLine();
+	    }
+	    out.flush();
+	    out.close();
+	}
+	catch (Exception error) {
+	    error.printStackTrace();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/GURL.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/GURL.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/GURL.java	(revision 10506)
@@ -0,0 +1,183 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.util;
+
+import java.io.*;
+import java.lang.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * Extends the standard URL class to include several new data elements and
+ * the ability to take a string and parse a valid url.
+ */
+public class GURL
+    implements Cloneable, Serializable {
+
+    private Integer type;
+
+    private URL url;
+
+    private String file;
+    private String host;
+    private String path;
+    private String protocol;
+    private String title = "empty";
+
+    /** This Vector maintains a record of the url links from within
+     * this resource, and their type (EXTERNAL vs INTERNAL). Internal
+     * links can be 'hidden' from the user if desired, or a user can
+     * opt to have all internal links automatically moved into a
+     * collection if the page that depends upon them is moved. <BR>
+     * Each entry in the vector is of the form.
+     * links[i] = String url
+     * links[i+1] = int type
+     */
+    private Vector links;
+
+    /* Static Integer identifiers for ease of use. */
+    static public Integer INTERNAL = new Integer(0);
+    static public Integer EXTERNAL = new Integer(1);
+
+    public GURL(String url_str) {
+	this(url_str, GURL.EXTERNAL);
+    }
+
+    public GURL(URL url) {
+	this(url, GURL.EXTERNAL);
+    }
+
+    public GURL(URL url, Integer type) {
+	this.type = type;
+	this.url = url;
+    }
+
+    public GURL(String url_str, Integer type) {
+	this.type = type;
+
+	try {
+	    if(!url_str.startsWith("file:") && url_str.indexOf("://") == -1) {
+		url_str = "http://" + url_str;
+	    }
+	    url = new URL(url_str);
+	}
+	catch (MalformedURLException e) {
+	    // Fix it
+	}
+    }
+
+    public void addLink(String url) {
+	addLink(url, GURL.EXTERNAL);
+    }
+
+    public void addLink(String url, Integer type) {
+	if(links == null) {
+	    links = new Vector();
+	}
+	links.add(url);
+	links.add(type);
+    }
+
+    /** Used by tree renderer to display name. So we'll only return the
+     * filename.
+     */
+    public String getFile() {
+	return parseFile(url.getFile());
+    }
+
+    public String getHost() {
+	return url.getHost();
+    }
+
+    /* private String getLocalFile() {
+	String local_file = getPath() + File.separator + getFile();
+	// Strip msdos roots if they're still there.
+	while(local_file.indexOf(":") != -1) {
+	    local_file = local_file.substring(0, local_file.indexOf(":")) + local_file.substring(local_file.indexOf(":") + 1);
+	}
+	return local_file;
+	} */
+
+    public String getPath() {
+	return getHost() + parsePath(url.getFile());
+    }
+
+    public int getPort() {
+	return url.getPort();
+    }
+
+    public String getProtocol() {
+	String protocol = url.getProtocol();
+	if(protocol.equals("file")) {
+	    return protocol + ":";
+	}
+	return protocol + "://";
+    }
+
+    public URL getURL() {
+	return url;
+    }
+
+    public String toString() {
+	return url.toString();
+    }
+
+    public boolean valid() {
+	return (url != null);
+    }
+
+    private String parseFile(String raw) {
+	if(raw != null && !raw.equals("")) {
+	    // Remove everything upto and including the last '/'
+	    if(raw.indexOf("/") != -1) {
+		return raw.substring(raw.lastIndexOf("/") + 1);
+	    }
+	}
+	return raw;
+    }
+
+    private String parsePath(String raw) {
+	if(raw != null && !raw.equals("")) {
+	    // Remove everything after the last "/"
+	    if(raw.indexOf("/") != -1) {
+		return raw.substring(0, raw.lastIndexOf("/"));
+	    }
+	}
+	return raw;
+    }
+
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/HTMLStringTokenizer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/HTMLStringTokenizer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/HTMLStringTokenizer.java	(revision 10506)
@@ -0,0 +1,142 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.util;
+
+
+/** This class functions much like a <strong>StringTokenizer</strong> in that it tokenizes a long string into tokens, however this tokenizer cleverly notices HTML formatting tags. */
+public class HTMLStringTokenizer {
+    /** The current position in the source string. */
+    private int pos = 0;
+    /** The current token, usually created by the last nextToken call. */
+    private String current = null;
+    /** The previous token. */
+    private String previous = null;
+    /** The string to be tokenized, including any HTML markup. */
+    private String source = null;
+    /** Constructor.
+     * @param source The source <strong>String</strong> to be tokenized.
+     */
+    public HTMLStringTokenizer(String source) {
+	this.source = source;
+	// Parse the first token.
+	parseToken();
+    }
+
+    /** Determines if there are still tokens remaining unparsed in the source.
+     * @return A <strong>boolean</strong> which is <i>true</i> if there are more tokens.
+     */ 
+    public boolean hasMoreTokens() {
+	if(current != null && current.length() > 0) {
+	    return true;
+	}
+	return false;
+    } 
+
+    /** Determines if the tag currently being returned by sameToken is a tag.
+     * @return A <strong>boolean</strong> indicating if the token is a tag.
+     */
+    public boolean isTag() {
+	if(previous.startsWith("<") && previous.endsWith(">")) {
+	    return true;
+	}
+	return false;
+    }
+
+    /** Retrieves the next token. 
+     * @return A <strong>String</strong> representing the token.
+     */
+    public String nextToken() {
+	previous = current;
+	// Get the next token.
+	parseToken();
+	// Return previous.
+	return previous;
+    }
+
+    /** Parses the next token and stores it in current.
+     */
+    private void parseToken() {
+	boolean found = false;
+	boolean tag = false;
+	boolean text = false;
+	// Reset current
+	current = "";
+	// Parse away
+	dumpWhiteSpace();
+	while(pos < source.length() && !found) {
+	    char c = (char)source.charAt(pos);
+	    if(!tag && !text) {
+		if(c == '<') {
+		    tag = true;
+		}
+		else {
+		    text = true;
+		}
+		current = current + c;
+	    }
+				// Reading a tag. Watch only for '>'.
+	    else if(tag) {
+		if(c == '>') {
+		    found = true;
+		}
+		current = current + c;
+	    }
+				// Reading text. Watch for ' ' and '<'. Rollback '<'.
+	    else if(text) {
+		if(c == ' ') {
+		    found = true;
+		}
+		else if(c == '<') {
+		    found = true;
+		    pos--;
+		}
+		else {
+		    current = current + c;
+		}
+	    }
+	    pos++;
+	}
+    }
+
+    /** Method to ignore whitespace in the source.
+     */
+    private void dumpWhiteSpace() {
+	while(pos < source.length() && source.charAt(pos) == ' ') {
+	    pos++;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/HashMap3D.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/HashMap3D.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/HashMap3D.java	(revision 10506)
@@ -0,0 +1,138 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.util;
+
+/**************************************************************************************
+ * Written:      20/08/02
+ * Revised:      
+ **************************************************************************************/
+import java.util.HashMap;
+import java.util.Iterator;
+
+/** Provides a HashMap implementation that indexes by two keys. Perfect for the storage of metadata references based on their metadata element and assigned value. 
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3
+ */
+public class HashMap3D
+    extends HashMap {
+
+    private int capacity = 4;
+
+    private int size = 0;
+
+    private Object last_key_one = null;
+    private Object last_key_two = null;
+    private Object last_value = null;
+
+    /** Default constructor.
+     */
+    public HashMap3D() {
+	super();
+    }
+    /** Constructor with a specific initial capacity.
+     * @param capacity The initial capacity as an <i>int</i>.
+     */
+    public HashMap3D(int capacity) {
+	super(capacity);
+	this.capacity = capacity;
+    }
+    /** Completely remove the contents of this HashMap and its child HashMaps. */
+    public void clear() {
+	size = 0;
+	Iterator iterator = values().iterator();
+	while(iterator.hasNext()) {
+	    HashMap inner_mapping = (HashMap) iterator.next();
+	    inner_mapping.clear();
+	    inner_mapping = null;
+	}
+	iterator = null;
+	super.clear();
+    }
+    /** Determine if this hash map contains an entry for the given keys. Also cache this entry because theres a good chance the next get call will ask for this entry.
+     * @param key_one The first key as an <strong>Object</strong>.
+     * @param key_two The second key as an <strong>Object</strong>.
+     * @return <i>true</i> if such an entry exists, <i>false</i> otherwise.
+     */
+    public boolean contains(Object key_one, Object key_two) {
+	boolean result = false;
+	// Retrieve the hash mapping at key_one.
+	HashMap map = (HashMap) get(key_one);
+	// If there is such a map then retrieve the value at key_two.
+	if(map != null) {
+	    last_value = map.get(key_two);
+	    if(last_value != null) {
+		last_key_one = key_one;
+		last_key_two = key_two;
+		result = true;
+	    }
+	}
+	return result;
+    }
+
+    /** Retrieve an entry from this three dimensional hash mapping.
+     * @param key_one The first key as an <strong>Object</strong>.
+     * @param key_two The second key as an <strong>Object</strong>.
+     * @return The value <strong>Object</strong> located at (key_one, key_two), or <i>null</i> if no such value.
+     */
+    public Object get(Object key_one, Object key_two) {
+	Object result = null;
+	if(key_one.equals(last_key_one) && key_two.equals(last_key_two)) {
+	    result = last_value;
+	}
+	else {
+	    // Retrieve the hash mapping at key_one.
+	    HashMap map = (HashMap) get(key_one);
+	    // If there is such a map then retrieve the value at key_two.
+	    if(map != null) {
+		result = map.get(key_two);
+		if(result != null) {
+		    last_key_one = key_one;
+		    last_key_two = key_two;
+		    last_value = result;
+		}
+	    }
+	}
+	return result;
+    }
+
+    /** Put an entry into this three dimensional hash mapping.
+     * @param key_one The first key, to store this value under, as an <strong>Object</strong>.
+     * @param key_two The second key, to store this value under, as an <strong>Object</strong>.
+     * @param value The value <strong>Object</strong> itself.
+     */
+    public void put(Object key_one, Object key_two, Object value) {
+	// Retrieve the hash mapping at key_one, or if none exists create one.
+	HashMap map = (HashMap) get(key_one);
+	if(map == null) {
+	    map = new HashMap(capacity);
+	    put(key_one, map);
+	}
+	// Now add the value to this mapping.
+	map.put(key_two, value);
+	size++;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/JarTools.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/JarTools.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/JarTools.java	(revision 10506)
@@ -0,0 +1,132 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer.util;
+
+
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+import javax.swing.*;
+
+
+public class JarTools
+{
+    static private Class root_class = null;
+    static private ImageIcon ERROR_ICON = null; 
+
+
+    static public void initialise(Object root_object)
+    {
+	root_class = root_object.getClass();
+	ERROR_ICON = getImage("error.gif");
+    }
+
+
+    static public void extractFromJar(String filename, String dst_dir, boolean must_be_present) 
+    {
+	try {
+	    // setup input stream for slurping out file
+	    InputStream fis = root_class.getResourceAsStream("/"+filename);
+	    BufferedInputStream fbis = new BufferedInputStream(fis); 
+	    DataInputStream fdbis = new DataInputStream(fbis);
+
+	    // set up output stream for writing to disk
+	    String ofname = dst_dir + filename;
+	    FileOutputStream fos = new FileOutputStream(ofname);
+	    BufferedOutputStream bfos = new BufferedOutputStream(fos);
+
+	    byte[] buf = new byte[1024];
+	    int len;
+	    int total_bytes = 0;
+	    while ((len = fdbis.read(buf)) >= 0) {
+		bfos.write(buf,0,len);
+		total_bytes += len;
+	    }
+
+	    fdbis.close();
+	    bfos.close();
+	}
+	catch (Exception exception) {
+	    if (must_be_present) {
+		exception.printStackTrace();
+	    }
+	}
+    }
+
+
+    /** Method to retrieve an image icon with the given filename found in classpath or the resouces directory.
+     *  @return The specified <strong>ImageIcon</strong>, or an error image replacement if no such images exists.
+     */
+    static public ImageIcon getImage(String filename) {
+	return getImage(filename, false);
+    }
+
+    static public ImageIcon getImage(String filename, boolean wait_until_complete)
+    {
+	ImageIcon image = new ImageIcon(root_class.getResource("/images/" + filename));
+	if (image == null) {
+	    image = ERROR_ICON;
+	}
+
+	if (wait_until_complete) {
+	    int load_status;
+	    do {
+		load_status = image.getImageLoadStatus();
+	    }
+	    while (load_status != MediaTracker.ABORTED && load_status != MediaTracker.ERRORED && load_status != MediaTracker.COMPLETE);
+	}
+
+	return image;
+    }
+
+
+    static public URL getResource(String resource_name)
+    {
+	return root_class.getResource(resource_name);
+    }
+
+
+    static public InputStream getResourceAsStream(String resource_name)
+    {
+	return root_class.getResourceAsStream(resource_name);
+    }
+
+
+    static public boolean isInJar(String filename) 
+    {
+	try {
+	    InputStream fis = root_class.getResourceAsStream("/" + filename);		    
+	    fis.close();
+	}
+	catch (Exception exception) {
+	    exception.printStackTrace();
+	    return false;
+	}
+
+	return true;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/PatternTokenizer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/PatternTokenizer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/PatternTokenizer.java	(revision 10506)
@@ -0,0 +1,72 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.util;
+
+public class PatternTokenizer {
+    private int index;
+    private String content;
+    private String pattern;
+    public PatternTokenizer(String content, String pattern) {
+	this.content = content;
+	this.index = 0;
+	this.pattern = pattern;
+    }
+    public boolean hasMoreTokens() {
+	return (index != -1 && content.length() - index > 0);
+    }
+    public String nextToken() {
+	// Special case when index is zero
+	if(index == 0) {
+	    index = content.indexOf(pattern);
+	    // No occurance of pattern, return whole string
+	    if(index == -1) {
+		return content;
+	    }
+	    // Return the fragment from 0 to index
+	    else {
+		return content.substring(0, index);
+	    }
+	}
+	// Otherwise
+	else {
+	    // We must first skip the pattern, as it should be at the head of our current view into content
+	    index = index + pattern.length();
+	    int end_index = content.indexOf(pattern, index);
+	    String fragment;
+	    // No occurance of pattern, return fragment from index to length
+	    if(end_index == -1) {
+		fragment = content.substring(index);
+	    }
+	    // Return the fragment from index to end index, then set index to end index
+	    else {
+		fragment = content.substring(index, end_index);
+	    }
+	    index = end_index;
+	    return fragment;
+	}
+    }    
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/StaticStrings.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/StaticStrings.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/StaticStrings.java	(revision 10506)
@@ -0,0 +1,247 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.util;
+
+
+/** Were you to guess that this is a class object choc-a-block full of static stringy goodness, you'd be right. They come in several flavours: Those ending _STR are strings you might find as values in XML, _ELEMENT are element names, _ATTRIBUTE are attribute names, _CHAR are particular characters while _CHARACTER are also characters but expressed as strings (for regex purposes ie startsWith, endsWith, indexOf and replaceAll); _PATTERN are strings which require extra escaping to put them through regex. Finally anything else is just a static string used within GLI. */
+public class StaticStrings {
+    static final public char   CLOSEBRACKET_CHAR                          = ']';
+    static final public char   DOUBLEQUOTE_CHAR                           = '\"';
+    static final public char   BACKSLASH_CHAR                             = '\\';
+    static final public char   FORWARDSLASH_CHAR                          = '/';
+    static final public char   NEW_LINE_CHAR                              = '\n';
+    static final public char   NS_SEP                                     = '.';
+    static final public char   OPENBRACKET_CHAR                           = '[';
+    static final public char   PIPE_CHAR                                  = '|';
+    static final public char   SINGLEQUOTE_CHAR                           = '\'';
+    static final public char   SPACE_CHAR                                 = ' ';
+    static final public char   STAR_CHAR                                  = '*';
+    static final public String ALLFIELDS_STR                              = "allfields";
+    static final public String ARCPLUG_STR                                = "ArcPlug";
+    static final public String ASSIGNED_ATTRIBUTE                         = "assigned";
+    static final public String ASSOCIATIONS_ELEMENT                       = "Associations";
+    static final public String AT_CHARACTER                               = "@";
+    static final public String ATTRIBUTE_ELEMENT                          = "Attribute";
+    static final public String BUILDTYPE_ELEMENT                              = "BuildType";
+    static final public String BUILDTYPE_STR                              = "buildtype";
+    static final public String CACHE_FOLDER                               = "cache";
+    static final public String CCS_STR                                    = "ccs";
+    static final public String CLASSES_FOLDER                             = "classes";
+    static final public String CLASSIFY_ELEMENT                           = "Classify";
+    static final public String CLASSIFY_STR                               = "classify";
+    static final public String CLOSE_PARENTHESIS_CHARACTER                = ")";
+    static final public String CODE_ATTRIBUTE                             = "code";
+    static final public String COLNAME_PATTERN                            = "<col_name>";
+    static final public String COLLECT_CFG                                = "collect.cfg";
+    static final public String COLLECTCONFIGURATION_XML                   = "CollectionConfig.xml";
+    static final public String COLLECTDIR_ARGUMENT                        = "-collectdir";
+    static final public String COLLECTION_ELEMENT                         = "Collection";
+    static final public String COLLECTION_STR                             = "Collection: ";
+    static final public String COLLECTIONMETADATA_BETA_ELEMENT            = "Beta";
+    static final public String COLLECTIONMETADATA_BETA_STR                = "beta";
+    static final public String COLLECTIONMETADATA_COLLECTIONNAME_STR      = "collectionname";
+    static final public String COLLECTIONMETADATA_COLLECTIONEXTRA_STR     = "collectionextra";
+    static final public String COLLECTIONMETADATA_CREATOR_ELEMENT         = "Creator";
+    static final public String COLLECTIONMETADATA_CREATOR_STR             = "creator";
+    static final public String COLLECTIONMETADATA_ELEMENT                 = "CollectionMetadata";
+    static final public String COLLECTIONMETADATA_ICONCOLLECTION_STR      = "iconcollection";
+    static final public String COLLECTIONMETADATA_ICONCOLLECTIONSMALL_STR = "iconcollectionsmall";
+    static final public String COLLECTIONMETADATA_MAINTAINER_ELEMENT      = "Maintainer";
+    static final public String COLLECTIONMETADATA_MAINTAINER_STR          = "maintainer";
+    static final public String COLLECTIONMETADATA_PUBLIC_ELEMENT          = "Public";
+    static final public String COLLECTIONMETADATA_PUBLIC_STR              = "public";
+    static final public String COLLECTIONMETADATA_STR                     = "collectionmeta";
+    static final public String COLON_CHARACTER                            = ":";
+    static final public String COMMA_CHARACTER                            = ",";
+    static final public String COMMENT_VALUE                              = "comment";
+    static final public String COMMENTED_INDEXES_STR                      = "#indexes";
+    static final public String COMMENTED_INDEX_DEFAULT_STR                = "#defaultindex";
+    static final public String COMMENTED_LEVELS_STR                       = "#levels";
+    static final public String CONTENT_ATTRIBUTE                          = "content";
+    static final public String CONTENT_ELEMENT                            = "content";
+    static final public String CUSTOM_ATTRIBUTE                           = "custom";
+    static final public String DC_ATTRIBUTE                               = "dc";
+    static final public String DEBUG_ARGUMENT                             = "-debug";
+    static final public String DEFINITION_VALUE                           = "definition";
+    static final public String DESCRIPTION_ELEMENT                        = "Description";
+    static final public String DICTIONARY_FILENAME                        = "dictionary";
+    static final public String DIRECTORY_MAPPINGS_ELEMENT                 = "DirectoryMappings";
+    static final public String DOCUMENT_STR                               = "document";
+    static final public String ETC_FOLDER                                 = "etc";
+    static final public String EMPTY_STR                                  = "";
+    static final public String ENGLISH_LANGUAGE_STR                       = "en";
+    static final public String ENTRY_ELEMENT                              = "Entry";
+    static final public String ENUM_STR                                   = "enum";
+    static final public String EQUALS_CHARACTER                           = "=";
+    static final public String ESCAPE_PATTERN                             = "\\\\";
+    static final public String ESCAPE_STR                                 = "\\";
+    static final public String EXCLAMATION_CHARACTER                     = "!";
+    static final public String EXCLUDE_STR                                = "exclude";
+    static final public String EXTENSION_ATTRIBUTE                        = "extension";
+    static final public String EXTRACTED_METADATA_ELEMENT                 = "XMetadata";
+    static final public String EXTRACTED_NAMESPACE                        = "ex.";
+    static final public String FALSE_STR                                  = "false";
+    static final public String FEEDBACK_ARGUMENT                          = "-feedback";
+    static final public String FILE_ATTRIBUTE                             = "file";
+    static final public String FILENAME_STR                               = "Filename";
+    static final public String FLAG_STR                                   = "flag";
+    static final public String FORMAT_ELEMENT                             = "Format";
+    static final public String FORMAT_STR                                 = "format";
+    static final public String GLI_ATTRIBUTE                              = "gli";
+    static final public String GLISERVER_URL_ARGUMENT                     = "-gliserver_url";
+    static final public String GREATER_THAN_CHARACTER                     = ">";
+    static final public String GSDL_ARGUMENT                              = "-gsdl";
+    static final public String GSDL3_ARGUMENT                              = "-gsdl3";
+    static final public String GSDL3_SRC_ARGUMENT                         = "-gsdl3src";
+    static final public String HFILE_ARGUMENT                             = "-hfile";
+    static final public String HIDDENGLI_ELEMENT                          = "HiddenGLI";
+    static final public String HIERARCHY_ATTRIBUTE                        = "hierarchy";
+    static final public String HIERARCHY_CLASSIFIER                       = "Hierarchy";
+    static final public String HIERARCHY_STR                              = "hierarchy";
+    static final public String HTTP_PROTOCOL_STR                          = "http://";
+    static final public String HELP_ARGUMENT                              = "-help";
+    static final public String HELP_INDEX_FILENAME                        = "help_index.xml";
+    static final public String HTM_FILE_EXTENSION                         = ".htm";
+    static final public String IDENTIFIER_VALUE                           = "identifier";
+    static final public String IMAGES_PATH_RELATIVE_TO_GSDL_PREFIX        = "_httpprefix_/collect/<col_name>/images/";
+    static final public String IMPORT_FOLDER                              = "import";
+    static final public String INCLUDE_STR                                = "include";
+    static final public String INDEX_ELEMENT                              = "Index";
+    static final public String INDEX_DEFAULT_ELEMENT                      = "DefaultIndex";
+    static final public String INDEX_DEFAULT_STR                          = "defaultindex";
+    static final public String INDEX_STR                                  = "indexes";
+    static final public String INDEXES_ELEMENT                            = "Indexes";
+    static final public String INT_STR                                    = "int";
+    static final public String[] KEEP_PLUG                                = { "GAPlug", "METSPlug" };
+
+    static final public String LANGUAGE_ARGUMENT                          = "l=";
+    static final public String LANGUAGE_ATTRIBUTE                         = "language";
+    static final public String LANGUAGE_ELEMENT                           = "Language";
+    static final public String LANGUAGE_DEFAULT_ELEMENT                   = "DefaultLanguage";
+    static final public String LANGUAGE_DEFAULT_STR                       = "defaultlanguage";
+    static final public String LANGUAGE_STR                               = "language";
+    static final public String LANGUAGEDEPENDENT_ATTRIBUTE                = "language_dependent";
+    static final public String LANGUAGES_ELEMENT                          = "Languages";
+    static final public String LANGUAGES_STR                              = "languages";
+    static final public String LBRACKET_CHARACTER                         = "[";
+    static final public String LBRACKET_PATTERN                           = "\\[";
+    static final public String LESS_THAN_CHARACTER                        = "<";
+    static final public String LEVEL_ATTRIBUTE                            = "level";
+    static final public String LEVELS_ELEMENT                             = "Levels";
+    static final public String LEVELS_STR                                 = "levels";
+    static final public String LIBRARY_URL_ARGUMENT                       = "-library_url";
+    static final public String LOCAL_LIBRARY_ARGUMENT                     = "-local_library";
+    static final public String LOAD_ARGUMENT                              = "-load";
+    static final public String MAC_OPEN_COMMAND                           = "open %1";
+    static final public String MAPPING_ELEMENT                            = "Mapping";
+    static final public String MARC_EXTENSION                             = ".marc";
+    static final public String MDS_ATTRIBUTE                              = "mds";
+    static final public String METADATA_ARGUMENT                          = "-metadata";
+    static final public String METADATA_BAK                               = "~metadata.xml";
+    static final public String METADATA_ELEMENT                           = "Metadata";
+    static final public String METADATA_SET_EXTENSION                     = ".mds";
+    static final public String METADATA_STR                               = "metadata";
+    static final public String METADATA_TYPE_STR                          = "metadata";
+    static final public String METADATA_XML                               = "metadata.xml";
+    static final public String METADATUM_TYPE_STR                         = "metadatum";
+    static final public String MGPP_ATTRIBUTE                             = "mgpp_enabled";
+    static final public String MINUS_CHARACTER                            = "-";
+    static final public String MODE_STR                                   = "Mode: ";
+    static final public String MODEGLI_ELEMENT                            = "ModeGLI";
+    static final public String MODEL_COLLECTION_NAME                      = "modelcol";
+    static final public String NAME_ATTRIBUTE                             = "name";
+    static final public String NAME_ELEMENT                               = "Name";
+    static final public String NEWLINE_CHARACTER                          = "\\";
+    static final public String NEWLINE_ELEMENT                            = "NewLine";
+    static final public String NO_LOAD_ARGUMENT                           = "-no_load";
+    static final public String NO_WGET_STR                                = "NoWGet";
+    static final public String ONE_CHARACTER                              = "1";
+    static final public String OPEN_PARENTHESIS_CHARACTER                 = "(";
+    static final public String OPTION_ELEMENT                             = "Option";
+    static final public String OPTIONS_ATTRIBUTE                          = "options";
+    static final public String PARAGRAPH_STR                              = "paragraph";
+    static final public String PERL_ARGUMENT                              = "-perl";
+    static final public String PHIND_CLASSIFIER                           = "Phind";
+    static final public String PIPE_STR                                   = "|";
+    static final public String PLUGIN_ELEMENT                             = "Plugin";
+    static final public String PLUGIN_STR                                 = "plugin";
+    static final public String PROPERTIES_FILE_EXTENSION                  = ".properties";
+    static final public String RANGE_ELEMENT                              = "Range";
+    static final public String RBRACKET_CHARACTER                         = "]";
+    static final public String RBRACKET_PATTERN                           = "\\]";
+    static final public String RECPLUG_STR                                = "RecPlug";
+    static final public String REGEXP_STR                                 = "regexp";
+    static final public String SEARCHTYPE_ELEMENT                         = "SearchType";
+    static final public String SEARCHTYPE_STR                             = "searchtype";
+    static final public String SECTION_ELEMENT                            = "Section";
+    static final public String SECTION_STR                                = "section";
+    static final public String SEPARATOR_ATTRIBUTE                        = "separator";
+    static final public String SEPARATOR_CHARACTER                        = "/";
+    static final public String SERVLET_ARGUMENT                           ="-servlet";
+    static final public String SETLANGUAGE_ELEMENT                        = "SetLanguage";
+    static final public String SHOW_PROGRESS_ARGUMENT                     = "show_progress";
+    static final public String SINGLE_ESCAPE_ONLY_PATTERN                 = "[^\\\\]+\\\\[^\\\\]+";
+    static final public String SINGLE_QUOTE_CHARACTER                     = "'";
+    static final public String SITE_ARGUMENT                              = "-site";
+    static final public String SOURCESEGMENT_VALUE                        = "SourceSegment";
+    static final public String SPACE_CHARACTER                            = " ";
+    static final public String SPECIAL_ATTRIBUTE                          = "special";
+    static final public String SPEECH_CHARACTER                           = "\"";
+    static final public String STOP_CHARACTER                             = ".";
+    static final public String STRING_STR                                 = "string";
+    static final public String SUBCOLLECTION_ELEMENT                      = "Subcollection";
+    static final public String SUBCOLLECTION_STR                          = "subcollection";
+    static final public String SUBCOLLECTION_DEFAULT_INDEX_ELEMENT        = "DefaultSubcollection";
+    static final public String SUBCOLLECTION_DEFAULT_INDEX_STR            = "defaultsubcollection";
+    static final public String SUBCOLLECTION_INDEX_STR                    = "indexsubcollections";
+    static final public String SUBCOLLECTION_INDEXES_ELEMENT              = "SubcollectionIndexes";
+    static final public String SUPERCOLLECTION_ELEMENT                    = "Supercollection";
+    static final public String SUPERCOLLECTION_STR                        = "supercollection";
+    static final public String TAB_CHARACTER                              = "\t";
+    static final public String TEXT_NODE                                  = "#text";
+    static final public String TEXT_STR                                   = "text";
+    static final public String TIMESTAMP_ARGUMENT                         = "&uq=";
+    static final public String TITLE_ELEMENT                              = "Title";
+    static final public String TRUE_STR                                   = "true";
+    static final public String TRUNCATED_STRING                           = "...";
+    static final public String TYPE_ATTRIBUTE                             = "type";
+    static final public String UNDERSCORE_CHARACTER                       = "_";
+    static final public String UNKNOWN_ELEMENT                            = "Unknown";
+    static final public String UNKNOWNPLUG_STR                             = "UnknownPlug";
+    static final public String USE_METADATA_FILES_ARGUMENT                = "use_metadata_files";
+    static final public String URL_SEPARATOR_CHARACTER                    = "/";
+    static final public String VALUE_ATTRIBUTE                            = "value";
+    static final public String VALUE_TREE_ATTRIBUTE                       = "remember_values";
+    static final public String VERSION_ATTRIBUTE                          = "version";
+    static final public String WGET_ARGUMENT                              = "-wget";
+    static final public String WGET_OLD_STR                               = "<WGet1.9";
+    static final public String WGET_STR                                   = "WGet1.9";
+    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 YES_STR                                    = "yes";
+    static final public String ZERO_CHARACTER                             = "0";
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/SynchronizedTreeModelTools.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/SynchronizedTreeModelTools.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/SynchronizedTreeModelTools.java	(revision 10506)
@@ -0,0 +1,123 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.util;
+
+import java.lang.Runnable;
+import javax.swing.SwingUtilities;
+import javax.swing.tree.*;
+import org.greenstone.gatherer.DebugStream;
+
+/** Due to the TreeModel objects not having any synchronization, certain assumptions, such as the model state remaining constant during a repaint, don't always hold - especially given that I'm changing the tree model on a different thread. In order to get around this I will use the latest swing paradigm wherein you flag a section of code to be executed by the AWT GUI Event queue, as soon as other gui tasks have finished. This way I shouldn't have tree redraws throwing NPEs because the array size of the children of a certain node has changed -while- the repaint call was made, i.e. repaint() calls getChildCount() = 13, removeNodeFromParent() called, repaint calls getChildAt(12) = ArrayIndexOutOfBoundsException. 
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3c
+ */
+public class SynchronizedTreeModelTools {
+    /** Adds an insertNodeInto model update onto the AWT Event queue. This gets around the lack of synchronization illustrated above. */
+    static final public Runnable insertNodeInto(DefaultTreeModel model, MutableTreeNode parent, MutableTreeNode target_node) {
+	return insertNodeInto(model, parent, target_node, true);
+    }
+
+    static final public Runnable insertNodeInto(final DefaultTreeModel model, final MutableTreeNode parent, final MutableTreeNode target_node, final boolean wait_allowed) {
+	final Runnable doInsertNodeInto = new Runnable() {
+		public void run() {
+		    ///ystem.err.print("Running task... ");
+		    DebugStream.println("insertNodeInto(" + model + ", " + parent + ", " + target_node + ", " + wait_allowed);
+		    int index = -1;
+		    int pos = 0;
+		    while(index == -1 && pos < parent.getChildCount()) {
+			TreeNode node = parent.getChildAt(pos);
+			int result = 0;
+			///ystem.err.println("Compare " + target_node + " to " + node);
+			if((target_node.isLeaf() && node.isLeaf()) || (!target_node.isLeaf() && !node.isLeaf())) {
+			    result = target_node.toString().toLowerCase().compareTo(node.toString().toLowerCase());
+			}
+			else if(target_node.isLeaf()) {
+			    result = -1;
+			}
+			else {
+			    result = 1;
+			}
+			if(result > 0) {
+			    ///ystem.err.println("Keep searching...");
+			    pos++;
+			}
+			else {
+			    ///ystem.err.println("Found!");
+			    index = pos;
+			}
+		    }
+		    if(index == -1) {
+			index = parent.getChildCount();
+		    }
+		    model.insertNodeInto(target_node, parent, index);
+		}
+	    };
+	///ystem.err.print("Queuing Task... ");
+	try {
+	    if(wait_allowed && !SwingUtilities.isEventDispatchThread()) {
+		///ystem.err.print("In another thread - invoke and wait... ");
+		SwingUtilities.invokeAndWait(doInsertNodeInto);
+	    }
+	    else {
+		///ystem.err.print("In Event Thread or wait not allowed - invoke later... ");
+		SwingUtilities.invokeLater(doInsertNodeInto);
+	    }
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	///ystem.err.print("Added Task... ");
+	return doInsertNodeInto;
+    }
+
+
+    /** Adds a removeNodeFromParent model update onto the AWT Event queue. This gets around the lack of synchronization illustrated above.
+     * @param model The <strong>GTreeModel</strong> we want to remove the node from.
+     * @param target_node The <strong>GTreeNode</strong> to remove.
+     */
+    static final public void removeNodeFromParent(final DefaultTreeModel model, final MutableTreeNode target_node) {
+	///ystem.err.println("Remove " + target_node + " from parent in model " + model);
+	final Runnable doRemoveNodeFromParent = new Runnable() {
+		public void run() {
+		    model.removeNodeFromParent(target_node);
+		}
+	    };
+	try {
+	    //SwingUtilities.invokeLater(doRemoveNodeFromParent);
+	    SwingUtilities.invokeAndWait(doRemoveNodeFromParent);
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+	// If we've thrown an error because we tried to invoke the runnable task and wait, when we are in the AWTEvent thread already, then try agin but with an invoke later.
+	catch (java.lang.Error error) {
+	    if(error.toString().equals("java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread")) {
+		SwingUtilities.invokeLater(doRemoveNodeFromParent);
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/TableUtils.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/TableUtils.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/TableUtils.java	(revision 10506)
@@ -0,0 +1,92 @@
+package org.greenstone.gatherer.util;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.table.*;
+
+/**
+ * Utilites for manipulating JTables.
+ *
+ * @author Marc Hedlund
+ *   <a href="mailto:marc@precipice.org">&lt;marc@precipice.org&gt;</a>
+ * @version $Revision$
+ */
+
+public class TableUtils  {
+
+  // This is based on code found at
+  // <http://java.sun.com/docs/books/tutorial/ui/swingComponents/table.html>,
+  // somewhat modified.
+
+//    public static void setPreferredCellSizes(JTable table) {
+//      TableModel model = table.getModel();
+//      TableColumnModel colModel = table.getColumnModel();
+
+//      for (int i = 0; i < model.getColumnCount(); i++) {
+//        TableColumn column = colModel.getColumn(i);
+
+//        int longestCell = 0;
+//        int highestCell = 0;
+
+//        for (int j = 0; j < model.getRowCount(); j++) {
+//          Object value = model.getValueAt(j, i);
+//          if (value == null) continue;
+
+//          Component cell =
+//            table.getDefaultRenderer(model.getColumnClass(i)).
+//            getTableCellRendererComponent(table, value,
+//                                          false, false, j, i);
+
+//          int width = cell.getPreferredSize().width;
+//          int height = cell.getPreferredSize().height;
+
+//          if (width > longestCell) longestCell = width;         
+//          if (height > highestCell) highestCell = height;
+//        }
+
+//        Component headerComp = column.getHeaderRenderer().
+//          getTableCellRendererComponent(table, column.getHeaderValue(),
+//                                        false, false, 0, 0);
+
+//        int headerWidth = headerComp.getPreferredSize().width;
+//        int headerHeight = headerComp.getPreferredSize().height;
+
+//        column.setPreferredWidth(Math.max(headerWidth, longestCell));
+
+//        int currentHeight = table.getRowHeight();
+//        int preferredHeight = Math.max(headerHeight, highestCell);
+
+//        table.setRowHeight(Math.max(currentHeight, preferredHeight));
+//      }
+//    }                                                                   
+
+  /**
+   * Takes a column in an existing table and makes it fixed-width.
+   * Specifically, it sets the column's minimum and maximum widths to
+   * its preferred width, and disables auto-resize for the table as a
+   * whole.
+   *
+   * <p>
+   *
+   * Later on this should take a column array for efficiency.
+   *
+   * @param table JTable The table to modify
+   * @param colIndex int Which column to fix
+   * @return int The width of the column as it was fixed
+   */
+
+  public static int fixColumnToPreferredWidth(JTable table, int colIndex) {
+    table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
+
+    TableColumnModel tcm = table.getColumnModel();
+    TableColumn col = tcm.getColumn(colIndex);
+    int width = col.getPreferredWidth();
+
+    col.setMaxWidth(width);
+    col.setMinWidth(width);    
+
+    //table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+
+    return width;
+  }
+}  
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/TreeSynchronizer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/TreeSynchronizer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/TreeSynchronizer.java	(revision 10506)
@@ -0,0 +1,140 @@
+/**
+ *#########################################################################
+ *
+ * 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: John Thompson, 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.gatherer.util;
+
+import java.util.Vector;
+import javax.swing.JTree;
+import javax.swing.event.TreeExpansionEvent;
+import javax.swing.event.TreeExpansionListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+import org.greenstone.gatherer.gui.tree.DragTree;
+/** My latest diabolical class synchronizes the expansion state of two or more JTrees. Muh-hahahaha. Note that these tree should be based on the same model. If they aren't it won't work. So there.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.1
+ */
+final public class TreeSynchronizer 
+    extends Vector 
+    implements TreeExpansionListener, TreeSelectionListener {
+    /** <i>true</i> if we should temporarily ignore further events, most likely because we know our actions are causing them. */ 
+    private boolean ignore;
+    /** A list of tree selection listeners. */
+    private Vector selection_listeners = new Vector();
+    /** Add a new tree to the synchronization list of trees to be synchronized.
+     * @param tree The lastest victim, a <strong>JTree</strong>.
+     */
+    public void add(JTree tree) {
+	super.add(tree);
+	tree.addTreeExpansionListener(this);
+	tree.addTreeSelectionListener(this);
+    }
+
+    /** We allow the Gatherer to add tree listeners to this class, as it persists between collection changes transparently. Thus there is no need to reattach listeners everytime the collection changes. */
+    public void addTreeSelectionListener(TreeSelectionListener listener) {
+	if(!selection_listeners.contains(listener)) {
+	    selection_listeners.add(listener);
+	}
+    }
+
+    /** Called whenever an item in the tree has been collapsed.
+     * @param event A <strong>TreeExpansionEvent</strong> containing information about the event.
+     */
+    public void treeCollapsed(TreeExpansionEvent event) {
+	if(!ignore) {
+	    ignore = true;
+	    // Collapse that path in all registered trees.
+	    JTree tree = (JTree)event.getSource();
+	    TreePath path = event.getPath();
+	    for(int i = size(); i != 0; i--) {
+		JTree sibling = (JTree) get(i - 1);
+		if(!sibling.equals(tree)) {
+		    sibling.collapsePath(path);
+		}
+	    }
+	    ignore = false;
+	}
+    }
+    /** Called whenever an item in the tree has been expanded.
+     * @param event A <strong>TreeExpansionEvent</strong> containing information about the event.
+     */
+    public void treeExpanded(TreeExpansionEvent event) {
+	if(!ignore) {
+	    ignore = true;
+	    // Expand that path in all registered trees.
+	    JTree tree = (JTree)event.getSource();
+	    TreePath path = event.getPath();
+	    for(int i = size(); i != 0; i--) {
+		JTree sibling = (JTree) get(i - 1);
+		if(!sibling.equals(tree)) {
+		    sibling.expandPath(path);
+		}
+	    }
+	    ignore = false;
+	}
+    }
+    /** Called whenever the one of the trees selection changes.
+     * @param event A <strong>TreeSelectionEvent</strong> containing information about the event.
+     */
+    public void valueChanged(TreeSelectionEvent event) {
+	if(!ignore) {
+	    ignore = true;
+	    // Recover the tree that is the source.
+	    JTree tree = (JTree) event.getSource();
+	    // Brute Force approach.
+	    // Extract the currently selected paths.
+	    TreePath paths[] = tree.getSelectionPaths();
+	    // Then for every registered tree, that isn't this one, ensure those paths are selected.
+	    /*
+	    for(int i = size(); paths != null && i != 0; i--) {
+		JTree sibling = (JTree) get(i - 1);
+		if(!sibling.equals(tree)) {
+		    // One last thing to do. If this is actually a DragTree we are dealing with we have to tell it to set the selection values immediately, not wait for the clear until it is sure it is no the pre-cursor to a drag.
+		    if(sibling instanceof DragTree) {
+			DragTree gtree = (DragTree)sibling;
+			gtree.setImmediate(true);
+			gtree.setSelectionPaths(paths);
+			// I'm going to ensure that the last selected path is visible.
+			gtree.scrollPathToVisible(paths[paths.length - 1]);
+			gtree.setImmediate(false);
+		    }
+		    else {
+			sibling.setSelectionPaths(paths);
+			sibling.scrollPathToVisible(paths[paths.length - 1]);
+		    }
+		}
+	    }
+	    */
+	    // Pass on message to all listeners.
+	    for(int i = 0; i < selection_listeners.size(); i++) {
+		((TreeSelectionListener) selection_listeners.get(i)).valueChanged(event);
+	    }
+	    ignore = false;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Unzip.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Unzip.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Unzip.java	(revision 10506)
@@ -0,0 +1,122 @@
+/**
+ *#########################################################################
+ *
+ * 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: David Bainbridge, NZDL Project, University of Waikato
+ *
+ * <BR><BR>
+ *
+ * Copyright (C) 2005 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.gatherer.util;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+
+public class Unzip 
+{
+
+    public static final void copyInputStream(InputStream in, OutputStream out)
+	throws IOException
+    {
+	byte[] buffer = new byte[1024];
+	int len;
+
+	while((len = in.read(buffer)) >= 0)
+	    out.write(buffer, 0, len);
+
+	in.close();
+	out.close();
+    }
+
+
+    static public void main(String[] args) 
+    {
+	if (args.length != 2) {
+	    System.err.println("Usage: Unzip <zip-file> <destination-directory>");
+	    return;
+	}
+
+	String zip_file_path = args[0];
+	// System.err.println("Zip file path: " + zip_file_path);
+	String destination_directory_path = args[1];
+	if (!destination_directory_path.endsWith(File.separator)) {
+	    destination_directory_path += File.separator;
+	}
+	// System.err.println("Destination directory path: " + destination_directory_path);
+
+	try {
+	    ZipFile zipFile = new ZipFile(zip_file_path);
+
+	    Enumeration entries = zipFile.entries();
+	    while (entries.hasMoreElements()) {
+		ZipEntry entry = (ZipEntry) entries.nextElement();
+
+		if (entry.isDirectory()) {
+		    // Assume directories are stored parents first then children.
+		    // System.err.println("Extracting directory: " + entry.getName());
+		    // This is not robust, just for demonstration purposes.
+		    String dir_name = entry.getName();
+		    String full_dir_name = destination_directory_path + dir_name;
+		    // System.err.println("Full directory name: " + full_dir_name);
+		    File dirFile = new File(full_dir_name);
+		    dirFile.mkdir();
+		}
+		else {
+		    // System.err.println("Extracting file: " + entry.getName());
+		    String file_name = entry.getName();
+		    String full_file_name = destination_directory_path + file_name;
+		    File directory = (new File(full_file_name)).getParentFile();
+		    // System.err.println("Full file name: " + full_file_name);
+		    if (!directory.exists() && !directory.mkdirs()) {
+			System.err.println("Error: Could not create directory " + directory + "!");
+		    }
+
+		    FileOutputStream fos = new FileOutputStream(full_file_name);
+		    BufferedOutputStream bos = new BufferedOutputStream(fos);
+
+		    copyInputStream(zipFile.getInputStream(entry),bos);
+		}
+	    }
+
+	    zipFile.close();
+	}
+	catch (ZipException error) {
+	    System.err.println("Error: Unable to open '" + zip_file_path + "'");
+	    System.err.println("This may be caused by the zip file being empty.");
+	    error.printStackTrace();
+	}
+	catch (Exception exception) {
+	    exception.printStackTrace();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Utility.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Utility.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Utility.java	(revision 10506)
@@ -0,0 +1,454 @@
+/**
+ *#########################################################################
+ *
+ * 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: 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.gatherer.util;
+
+// Don't even think about adding import java.awt.* here!
+// The functions in this class should not use any graphical classes. Put your function somewhere else buster!
+import java.io.*;
+import java.net.*;
+import java.util.*;
+// Don't even think about adding import javax.swing.* here!
+// The functions in this class should not use any graphical classes. Put your function somewhere else buster!
+import org.apache.xerces.parsers.*;
+import org.apache.xerces.dom.DocumentImpl;
+import org.apache.xml.serialize.*;
+import org.greenstone.gatherer.Configuration;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Dictionary;
+import org.greenstone.gatherer.shell.GShell;
+// Don't even think about adding import org.greenstone.gatherer.Gatherer in here!
+// The functions in this class should be independent of the Gatherer class. Put your function somewhere else buster!
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+
+/** To provide a library of common methods, in a static context, for use in the Gatherer.
+ * @author John Thompson, Greenstone Digital Library, University of Waikato
+ * @version 2.3b
+ */
+public class Utility
+{
+    /** The size of the io buffer, in bytes. */
+    static final public int BUFFER_SIZE = 1024;
+    static final public String CFG_CLASSIFY = "classify";
+    static final public String CFG_CLASSIFY_BUTTONNAME = "-buttonname";
+    static final public String CFG_CLASSIFY_HFILE = "-hfile";
+    static final public String CFG_CLASSIFY_METADATA = "-metadata";
+    static final public String CFG_CLASSIFY_SORT = "-sort";
+    static final public String CFG_FORMAT = "format";
+    static final public String COLLECTION_TREE = "Collection";
+    /** Definition of an important directory name, in this case the file the collection configuration is expect to be in. */
+    static final public String CONFIG_FILE = "etc" + File.separator + "collect.cfg";
+    static final public String GLI_ARCHIVE = "GLI.jar";
+    static final public String GLI_EXTENSION = ".col";
+
+    /** Definition of an important directory name, in this case the import directory for the collection. */
+    static final public String IMPORT_DIR = "import" + File.separator;
+    /** Definition of an important directory name, in this case the backup import directory for the collection. */
+    static final public String IMPORT_BAK_DIR = "import.bak" + File.separator;
+    /** Definition of an important directory name, in this case the macros directory for the collection. */
+    static final public String MACROS_DIR = "macros" + File.separator;
+    /** Definition of an important directory name, in this case the location of the expected collection metadata sets.. */
+    static final public String META_DIR = "metadata" + File.separator; // Col. Copy
+    /** The default name of the perl executable under unix. */
+    static final public String PERL_EXECUTABLE_UNIX = "perl";
+    /** The default name of the perl executable under windows. */
+    static final public String PERL_EXECUTABLE_WINDOWS = "Perl.exe";
+    /** The name of the Gatherer. */
+    static final public String PROGRAM_NAME = "Greenstone Librarian Interface";
+    /** The current version of the Gatherer. */
+    static final public String PROGRAM_VERSION = "v2.61";
+    static final public String WORKSPACE_TREE = "Workspace";
+	
+
+    /**
+     * Delete a file or directory
+     * It turns out that in Java you have to make sure a directory is empty before you delete it (much like unix I suppose),
+     * and so just like unix I'll have to set up a recursive delete function.
+     *
+     * @param file The <strong>File</strong> you want to delete.
+     * @return A <i>boolean</i> which is <i>true</i> if the file specified was successfully deleted, <i>false</i> otherwise.
+     */
+    static public boolean delete(File file)
+    {
+	// Nothing to do if it doesn't exist
+	if (!file.exists()) {
+	    return true;
+	}
+
+	// If file is a directory, we have to recursively delete its contents first
+	if (file.isDirectory()) {
+	    File files[] = file.listFiles();
+	    for (int i = 0; i < files.length; i++) {
+		if (delete(files[i]) == false) {
+		    System.err.println("Error: Could not delete folder " + file);
+		    return false;
+		}
+	    }
+	}
+
+	// Delete file
+	if (file.delete() == false) {
+	    System.err.println("Error: Could not delete file " + file);
+	    return false;
+	}
+
+	return true;
+    }
+
+
+    static public boolean delete(String filename) {
+	return delete(new File(filename));
+    }
+
+
+    /** Convert a long, detailing the length of a file in bytes, into a nice human readable string using b, kb, Mb and Gb. */
+    static final public String BYTE_SUFFIX = " b";
+    static final public long GIGABYTE = 1024000000l;
+    static final public String GIGABYTE_SUFFIX = " Gb";
+    static final public long KILOBYTE =       1024l;
+    static final public String KILOBYTE_SUFFIX = " kb";
+    static final public long MEGABYTE =    1024000l;
+    static final public String MEGABYTE_SUFFIX = " mb";
+    static final public String formatFileLength(long length) {
+	StringBuffer result = new StringBuffer("");
+	float number = 0f;
+	String suffix = null;
+	// Determine the floating point number and the suffix (radix) used.
+	if(length >= GIGABYTE) {
+	    number = (float) length / (float) GIGABYTE;
+	    suffix = GIGABYTE_SUFFIX;
+	}
+	else if(length >= MEGABYTE) {
+	    number = (float) length / (float) MEGABYTE;
+	    suffix = MEGABYTE_SUFFIX;
+	}
+	else if(length >= KILOBYTE) {
+	    number = (float) length / (float) KILOBYTE;
+	    suffix = KILOBYTE_SUFFIX;
+	}
+	else {
+	    // Don't need to do anything fancy if the file is smaller than a kilobyte
+	    return length + BYTE_SUFFIX;
+	}
+	// Create the formatted string remembering to round the number to 2.d.p. To do this copy everything in the number string from the start to the first occurance of '.' then copy two more digits. Finally search for and print anything that appears after (and including) the optional 'E' delimter.
+	String number_str = Float.toString(number);
+	char number_char[] = number_str.toCharArray();
+	int pos = 0;
+	// Print the characters up to the '.'
+	while(number_char != null && pos < number_char.length && number_char[pos] != '.') {
+	    result.append(number_char[pos]);
+	    pos++;
+	}
+	if(pos < number_char.length) {
+	    // Print the '.' and at most two characters after it
+	    result.append(number_char[pos]);
+	    pos++;
+	    for(int i = 0; i < 2 && pos < number_char.length; i++, pos++) {
+		result.append(number_char[pos]);
+	    }
+	    // Search through the remaining string for 'E'
+	    while(pos < number_char.length && number_char[pos] != 'E') {
+		pos++;
+	    }
+	    // If we still have string then we found an E. Copy the remaining string.
+	    while(pos < number_char.length) {
+		result.append(number_char[pos]);
+		pos++;
+	    }
+	}
+	// Add suffix
+	result.append(suffix);
+	// Done
+	return result.toString();
+    }
+
+    /** This method formats a given string, using HTML markup, so its width does not exceed the given width and its appearance if justified.
+     * @param text The <strong>String</strong> requiring formatting.
+     * @param width The maximum width per line as an <i>int</i>.
+     * @return A <strong>String</strong> formatted so as to have no line longer than the specified width.
+     * TODO Currently HTML formatting tags are simply removed from the text, as the effects of spreading HTML tags over a break are undetermined. To solve this we need to associate tags with a certain text token so if it gets broken on to the next line the tags go with it, or if the tags cover a sequence of words that are broken we need to close then reopen the tags. However all this is a major task and well beyond anything I have time to 'muck-round' on.
+     */
+    static public String formatHTMLWidth(String text, int width) {
+	if(text == null) {
+	    return "Error";
+	}
+	HTMLStringTokenizer html = new HTMLStringTokenizer(text);
+	int current_width = 0;
+	int threshold = width / 2;
+	Stack lines = new Stack();
+	String line = "";
+	while(html.hasMoreTokens()) {
+	    String token = html.nextToken();
+	    while(token != null) {
+		if(html.isTag()) {
+		    // Insert smart HTML tag code here.
+		    token = null;
+		}
+		else {
+		    // If the token is bigger than two thirds width, before we've even started break it down.
+		    if(current_width + 1 + token.length() > width && token.length() > threshold) {
+			if(width == current_width) {
+			    lines.push(line);
+			    line = token;
+			    current_width = token.length();
+			}
+			else {
+			    String prefix = token.substring(0, width - 1 - current_width);
+			    token = token.substring(prefix.length());
+			    if(current_width == 0) {
+				line = line + prefix;
+			    }
+			    else {
+				line = line + " " + prefix;
+			    }
+			    lines.push(line);
+			    line = "";
+			    current_width = 0;
+			}
+		    }
+		    // If adding the next token would push us over the maximum line width.
+		    else if(current_width + 1 + token.length() > width) {
+			lines.push(line);
+			line = token;
+			current_width = token.length();
+			token = null;
+		    }
+		    // Otherwise we should be able to just add the token, give or take.
+		    else {
+			if(current_width == 0) {
+			    line = line + token;
+			    current_width = token.length();
+			}
+			else {
+			    // Special case for standard punctuation which may exist after a tag like so:
+			    // My name is <scratchy>Slim Shady</scratchy>.   <-- Annoying punctuation.
+			    if(token.equals(".") || token.equals(",") || token.equals("!") || token.equals("?")) {
+				line = line + token;
+				current_width = current_width + 1;
+			    }
+			    else {
+				line = line + " " + token;
+				current_width = current_width + 1 + token.length();
+			    }
+			}
+			token = null;
+		    }
+		}
+	    }
+	}
+	String result = line;
+	while(!lines.empty()) {
+	    result = (String)lines.pop() + "<BR>" + result;
+	}
+	// Replace ' ' with "&nbsp;"
+	boolean tag = false;
+	int pos = 0;
+	while(pos < result.length()) {
+	    if(result.charAt(pos) == '<') {
+		tag = true;
+	    }
+	    else if(result.charAt(pos) == '>') {
+		tag = false;
+	    }
+	    else if(result.charAt(pos) == ' ' && !tag) {
+		String prefix = result.substring(0, pos);
+		String suffix = result.substring(pos + 1);
+		result = prefix + "&nbsp;" + suffix;
+	    }
+	    pos++;
+	}
+	result = "<HTML>" + result + "</HTML>";
+	return result;
+    }
+
+
+    static public String getDateString() {
+	Calendar current = Calendar.getInstance();
+	String day_name = null;
+	switch(current.get(Calendar.DAY_OF_WEEK)) {
+	case Calendar.MONDAY: day_name = "Dates.Mon"; break;
+	case Calendar.TUESDAY: day_name = "Dates.Tue"; break;
+	case Calendar.WEDNESDAY: day_name = "Dates.Wed"; break;
+	case Calendar.THURSDAY: day_name = "Dates.Thu"; break;
+	case Calendar.FRIDAY: day_name = "Dates.Fri"; break;
+	case Calendar.SATURDAY: day_name = "Dates.Sat"; break;
+	case Calendar.SUNDAY: day_name = "Dates.Sun"; break;
+	default: day_name = "";
+	}
+	String month_name = null;
+	switch(current.get(Calendar.MONTH)) {
+	case Calendar.JANUARY: month_name = "Dates.Jan"; break;
+	case Calendar.FEBRUARY: month_name = "Dates.Feb"; break;
+	case Calendar.MARCH: month_name = "Dates.Mar"; break;
+	case Calendar.APRIL: month_name = "Dates.Apr"; break;
+	case Calendar.MAY: month_name = "Dates.May"; break;
+	case Calendar.JUNE: month_name = "Dates.Jun"; break;
+	case Calendar.JULY: month_name = "Dates.Jul"; break;
+	case Calendar.AUGUST: month_name = "Dates.Aug"; break;
+	case Calendar.SEPTEMBER: month_name = "Dates.Sep"; break;
+	case Calendar.OCTOBER: month_name = "Dates.Oct"; break;
+	case Calendar.NOVEMBER: month_name = "Dates.Nov"; break;
+	case Calendar.DECEMBER: month_name = "Dates.Dec"; break;
+	default: month_name = "";
+	}
+	int day = current.get(Calendar.DAY_OF_MONTH);
+	int hour = current.get(Calendar.HOUR_OF_DAY);
+	int minute = current.get(Calendar.MINUTE);
+	int second = current.get(Calendar.SECOND);
+	int year = current.get(Calendar.YEAR);
+
+	return Dictionary.get(day_name) + " " + Dictionary.get(month_name) + " " + day + " " + year + " " + Utility.pad(String.valueOf(hour), 2, '0', true) + ":" + Utility.pad(String.valueOf(minute), 2, '0', true) + ":" + Utility.pad(String.valueOf(second), 2, '0', true);
+    }
+
+
+    /** Determine this machines name.
+     * @return The name as a <strong>String</strong>.
+     */
+    static public String getMachineName() {
+	try {
+	    return InetAddress.getLocalHost().getHostName();
+	}
+	catch(UnknownHostException ex) {
+	}
+	return "Unknown Machine";
+    }
+
+
+    static public String getSitesDir(String gsdl3_path) {
+	return gsdl3_path + "sites" + File.separator;
+
+    }
+
+
+    /** 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;
+    }
+
+   
+    /** Method to determine if the host system is Microsoft Windows based.
+     * @return A <i>boolean</i> which is <i>true</i> if the platform is Windows, <i>false</i> 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;
+    }
+    /** Takes a string and a desired length and pads out the string to the length by adding spaces to the left.
+     * @param str The target <strong>String</strong> that needs to be padded.
+     * @param length The desired length of the string as an <i>int</i>.
+     * @return A <strong>String</strong> made from appending space characters with the string until it has a length equal to length.
+     */
+    static private String pad(String str_raw, int length, char fill, boolean end) {
+	StringBuffer str = new StringBuffer(str_raw);
+	while(str.length() < length) {
+	    if(end) {
+		str.insert(0, fill);
+	    }
+	    else {
+		str.append(fill);
+	    }
+	}
+	return str.toString();
+    }
+
+
+    static public StringBuffer readXMLStream(InputStream input_stream)
+    {
+	StringBuffer xml = new StringBuffer("");
+
+	try {
+	    InputStreamReader isr = new InputStreamReader(input_stream, "UTF-8");
+	    BufferedReader buffered_in = new BufferedReader(isr);
+	    
+	    String line = "";
+	    boolean xml_content = false;
+	    while((line = buffered_in.readLine()) != null) {
+		if(xml_content) {
+		    xml.append(line);
+		    xml.append("\n");
+		}
+		else if(line.trim().startsWith("<?xml")) {
+		    xml_content = true;
+		    xml.append(line);
+		    xml.append("\n");
+		}
+	    }
+	    buffered_in = null;
+	}
+	catch (Exception error) {
+	    System.err.println("Failed when trying to parse XML stream");
+	    error.printStackTrace();
+	}
+
+	return xml;
+    }
+
+
+    /** I think this works a bit better on Unicode strings. */
+    static public String stripNL(String raw_string)
+    {
+	String stripped_string = new String();
+	for (int i = 0; i < raw_string.length(); i++) {
+	    char raw_character = raw_string.charAt(i);
+	    if (raw_character != '\n' && raw_character != '\t') {
+		stripped_string = stripped_string + raw_character;
+	    }
+	}
+	return stripped_string;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/XMLTools.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/XMLTools.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/XMLTools.java	(revision 10506)
@@ -0,0 +1,260 @@
+package org.greenstone.gatherer.util;
+
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import org.apache.xerces.parsers.*;
+import org.apache.xml.serialize.*;
+import org.greenstone.gatherer.DebugStream;
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+
+/** This class is a static class containing useful XML functions */
+public class XMLTools
+{
+    /** Remove all of the child nodes from a certain node. */
+    static final public void clear(Node node)
+    {
+	while (node.hasChildNodes()) {
+	    node.removeChild(node.getFirstChild());
+	}
+    }
+
+
+    static public ArrayList getChildElementsByTagName(Element parent_element, String element_name)
+    {
+	ArrayList child_elements = new ArrayList();
+
+	NodeList children_nodelist = parent_element.getChildNodes();
+	for (int i = 0; i < children_nodelist.getLength(); i++) {
+	    Node child_node = children_nodelist.item(i);
+	    if (child_node.getNodeType() == Node.ELEMENT_NODE && child_node.getNodeName().equals(element_name)) {
+		child_elements.add(child_node);
+	    }
+	}
+
+	return child_elements;
+    }
+
+
+    static public String getElementTextValue(Element element)
+    {
+	// Find the first text node child
+	NodeList children_nodelist = element.getChildNodes();
+	for (int i = 0; i < children_nodelist.getLength(); i++) {
+	    Node child_node = children_nodelist.item(i);
+	    if (child_node.getNodeType() == Node.TEXT_NODE) {
+		return child_node.getNodeValue();
+	    }
+	}
+
+	// None found
+	return "";
+    }
+
+
+    /** Method to retrieve the value of a given node.
+     * @param element The <strong>Element</strong> whose value we wish to find.
+     * Soon to be deprecated!
+     */
+    static final public String getValue(Node element) {
+	if (element == null) {
+	    return "";
+	}
+	// If we've been given a subject node first retrieve its value node.
+	if(element.getNodeName().equals("Subject")) {
+	    element = getNodeFromNamed(element, "Value");
+	}
+	// If we've got a value node, then reconstruct the text. Remember that DOM will split text over 256 characters into several text nodes
+	if(element != null && element.hasChildNodes()) {
+	    StringBuffer text_buffer = new StringBuffer();
+	    NodeList text_nodes = element.getChildNodes();
+	    for(int i = 0; i < text_nodes.getLength(); i++) {
+		Node possible_text = text_nodes.item(i);
+		if(possible_text.getNodeName().equals(StaticStrings.TEXT_NODE)) {
+		    text_buffer.append(possible_text.getNodeValue());
+		}
+	    }
+	    return text_buffer.toString();
+	}
+	return "";
+    }
+
+
+    /** Method to retrieve from the node given, a certain child node with the specified name.
+     * @param parent The <strong>Node</strong> whose children should be searched.
+     * @param name The required nodes name as a <strong>String</strong>.
+     * @return The requested <strong>Node</strong> if it is found, <i>null</i> otherwise.
+     * Soon to be deprecated!
+     */ 
+    static final public Node getNodeFromNamed(Node parent, String name) {
+	Node child = null;
+	for(Node i = parent.getFirstChild(); i != null && child == null; 
+	    i = i.getNextSibling()) {
+	    if(i.getNodeName().equals(name)) {
+		child = i;
+	    }
+	}
+	return child;
+    }
+
+
+    /** Parse an XML document from a given file path */
+    static public Document parseXMLFile(String xml_file_path, boolean use_class_loader)
+    {
+	if (use_class_loader == true) {
+	    InputStream is = JarTools.getResourceAsStream("/" + xml_file_path);
+	    if (is != null) {
+		return parseXML(is);
+	    }
+	}
+
+ 	// Try the file outside the classes directory
+ 	return parseXMLFile(new File(xml_file_path));
+    }
+
+
+    /** Parse an XML document from a given file */
+    static public Document parseXMLFile(File xml_file)
+    {
+	// No file? No point trying!
+	if (xml_file.exists() == false) {
+	    return null;
+	}
+
+	try {
+	    return parseXML(new FileInputStream(xml_file));
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	    return null;
+	}
+    }
+
+
+    /** Parse an XML document from a given input stream */
+    static public Document parseXML(InputStream xml_input_stream)
+    {
+	Document document = null;
+
+	try {
+	    InputStreamReader isr = new InputStreamReader(xml_input_stream, "UTF-8");
+	    Reader xml_reader = new BufferedReader(isr);
+	    document = parseXML(xml_reader);
+	    isr.close();
+	    xml_input_stream.close();
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+
+	return document;
+    }
+
+
+    /** Parse an XML document from a given reader */
+    static public Document parseXML(Reader xml_reader)
+    {
+	Document document = null;
+
+	try {
+	    InputSource isc       = new InputSource(xml_reader);
+	    DOMParser parser      = new DOMParser();
+	    parser.setFeature("http://xml.org/sax/features/validation", false);
+	    parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+	    // May or may not be ignored, the documentation for Xerces is contradictory. If it works then parsing -should- be faster.
+	    parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", true);
+	    parser.setFeature("http://apache.org/xml/features/dom/include-ignorable-whitespace", false);
+	    parser.parse(isc);
+	    document = parser.getDocument();
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+
+	return document;
+    }
+
+
+    /** Removes characters that are invalid in XML (see http://www.w3.org/TR/2000/REC-xml-20001006#charsets) */
+    static public String removeInvalidCharacters(String text)
+    {
+	char[] safe_characters = new char[text.length()];
+	int j = 0;
+
+	char[] raw_characters = new char[text.length()];
+	text.getChars(0, text.length(), raw_characters, 0);
+	for (int i = 0; i < raw_characters.length; i++) {
+	    char character = raw_characters[i];
+	    if ((character >= 0x20 && character <= 0xD7FF) || character == 0x09 || character == 0x0A || character == 0x0D || (character >= 0xE000 && character <= 0xFFFD) || (character >= 0x10000 && character <= 0x10FFFF)) {
+		safe_characters[j] = character;
+		j++;
+	    }
+	}
+
+	return new String(safe_characters, 0, j);
+    }
+
+
+    static public void setElementTextValue(Element element, String text)
+    {
+	// Remove all text node children
+	NodeList children_nodelist = element.getChildNodes();
+	for (int i = children_nodelist.getLength() - 1; i >= 0; i--) {
+	    Node child_node = children_nodelist.item(i);
+	    if (child_node.getNodeType() == Node.TEXT_NODE) {
+		element.removeChild(child_node);
+	    }
+	}
+
+	// Add a new text node
+	if (text != null) {
+	    element.appendChild(element.getOwnerDocument().createTextNode(text));
+	}
+    }
+
+
+    /** Set the #text node value of some element.
+     * @param element the Element whose value we wish to set
+     * @param value the new value for the element as a String
+     * Soon to be deprecated!
+     */
+    static final public void setValue(Element element, String value) {
+	// Remove any existing child node(s)
+	clear(element);
+	// Add new text node.
+	if (value != null) {
+	    element.appendChild(element.getOwnerDocument().createTextNode(value));
+	}
+    }
+
+
+    /** Write an XML document to a given file */
+    static public void writeXMLFile(File xml_file, Document document)
+    {
+	try {
+	    OutputStream os = new FileOutputStream(xml_file);
+	    // Create an output format for our document.
+	    OutputFormat f = new OutputFormat(document);
+	    f.setEncoding("UTF-8");
+	    f.setIndenting(true);
+	    f.setLineWidth(0); // Why isn't this working!
+	    f.setPreserveSpace(false);
+	    // Create the necessary writer stream for serialization.
+	    OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
+	    Writer w               = new BufferedWriter(osw);
+	    // Generate a new serializer from the above.
+	    XMLSerializer s        = new XMLSerializer(w, f);
+	    s.asDOMSerializer();
+	    // Finally serialize the document to file.
+	    s.serialize(document);
+	    // And close.
+	    os.close();
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/ZipTools.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/ZipTools.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/ZipTools.java	(revision 10506)
@@ -0,0 +1,593 @@
+/**
+ *############################################################################
+ * A component of the Greenstone Librarian Interface, part of the Greenstone
+ * digital library suite from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Author: David Bainbridge, NZDL Project, University of Waikato, NZ
+ *
+ * Copyright (C) 2005 New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *############################################################################
+ */
+
+package org.greenstone.gatherer.util;
+
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.shell.GShell;
+import org.w3c.dom.*;
+
+
+public class ZipTools
+{
+    static public void unzipFile(String zip_file_path, String base_directory_path)
+    {
+	try {
+	    ZipFile zip_file = new ZipFile(new File(zip_file_path), ZipFile.OPEN_READ);
+	    
+	    Enumeration e = zip_file.entries(); 
+	    while (e.hasMoreElements()) {
+		ZipEntry zip_entry = (ZipEntry) e.nextElement();
+		File zip_entry_file = new File(base_directory_path + zip_entry.getName());
+		DebugStream.println("    Unzipping: " + zip_entry_file.getAbsolutePath());
+
+		// Directory case
+		if (zip_entry.isDirectory()) {
+		    // Create named directory, if it doesn't already exist
+		    if (!zip_entry_file.exists() && !zip_entry_file.mkdirs()) {
+			System.err.println("Error: unable to create directory " + zip_entry_file);
+		    }
+		}
+
+		// File case
+		else {
+		    // Write out file to disk
+
+		    // Make sure it's parent directory exists.
+		    File dir = new File(zip_entry_file.getParent());
+		    dir.mkdirs();
+
+		    // Set up input stream
+		    InputStream zis = zip_file.getInputStream(zip_entry); 
+		    BufferedInputStream bzis = new BufferedInputStream(zis); 
+		    DataInputStream dbzis = new DataInputStream(bzis);
+
+		    // Set up output stream
+		    FileOutputStream fzos = new FileOutputStream(zip_entry_file);
+		    BufferedOutputStream bfzos = new BufferedOutputStream(fzos);
+
+		    byte[] buf = new byte[1024];
+		    int len;
+		    while ((len = dbzis.read(buf)) >= 0) {
+			bfzos.write(buf,0,len);
+		    }
+
+		    dbzis.close();
+		    bzis.close();
+		    zis.close();
+
+		    bfzos.close();
+		    fzos.close();
+		}
+	    }
+
+	    zip_file.close();
+	} 
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+
+
+    static public void zipFiles(String zip_file_path, String base_directory_path, String[] relative_file_paths)
+    {
+	try {
+	    ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zip_file_path));
+	    ZipFilter null_zip_filter = new NullZipFilter();
+
+	    // Add each file/directory in turn to the zip file
+	    for (int i = 0; i < relative_file_paths.length; i++) {
+		String relative_file_path = relative_file_paths[i];
+		addFileToZip(zos, base_directory_path, relative_file_path, null_zip_filter);
+	    }
+
+	    zos.close();
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+
+
+    static public void addFileToZip(ZipOutputStream zos, String base_directory_path, String relative_file_path, ZipFilter zip_filter)
+    {
+	File file = new File(base_directory_path + File.separator + relative_file_path);
+
+	// Check that the file/directory exists
+	if (!file.exists()) {
+	    System.err.println("File " + file + " does not exist!");
+	    return;
+	}
+
+	try {
+	    // Directory case
+	    if (file.isDirectory()) {
+		// Add a zip entry for this directory
+		zos.putNextEntry(new ZipEntry(relative_file_path + File.separator));
+
+		// Apply recursively to each of the children of the directory
+		File[] child_files = file.listFiles();
+		for (int i = 0; i < child_files.length; i++) {
+		    addFileToZip(zos, base_directory_path, relative_file_path + File.separator + child_files[i].getName(), zip_filter);
+		}
+	    }
+
+	    // File case
+	    else {
+		// Add a zip entry for this file
+		if (zip_filter.shouldIncludeFile(relative_file_path)) {
+		    zos.putNextEntry(new ZipEntry(relative_file_path));
+
+		    if (zip_filter.shouldIncludeFileContent(relative_file_path)) {
+			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
+			byte[] data = new byte[1024];
+			int bytes_read;
+			while ((bytes_read = bis.read(data, 0, 1024)) > -1) {
+			    zos.write(data, 0, bytes_read);
+			}
+			bis.close();
+		    }
+		}
+	    }
+	}
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
+	}
+    }
+
+
+    public interface ZipFilter
+    {
+	public boolean shouldIncludeFile(String relative_file_path);
+
+	public boolean shouldIncludeFileContent(String relative_file_path);
+    }
+
+
+    static public class NullZipFilter
+	implements ZipFilter
+    {
+	public boolean shouldIncludeFile(String relative_file_path)
+	{
+	    // All files are included
+	    return true;
+	}
+
+
+	public boolean shouldIncludeFileContent(String relative_file_path)
+	{
+	    // Content for all files is included
+	    return true;
+	}
+    }
+
+
+    // ----------------------------------------------------------------------------------------------------
+
+
+    static private String unixStylePath(String path)
+    {
+	String unix_path = path.replace('\\','/');
+	return unix_path;
+    }
+
+
+    /**
+     * Method to handle zipping up of a file (not a directory).
+     * Called by {@link zipup(String, String, String, GShell, String, String)} and {@link dirFunc(ZipOutputStream, String, int, GShell, boolean, String, String)}
+     *
+     * @param zos the zip output stream, as a <strong>ZipOutputStream</strong>
+     * @param file_path the <strong>String</strong> containing the path to the file/directory tozip up
+     * @param prefix_strip the <strong>int</strong> used to substring the file_path
+     * @param source the <strong>GShell</strong> object that is calling this method, so that we can check to see if the process has been cancelled.
+     *               This is null if GShell is not the calling object.
+     * @param accept_expr a <strong>String</strong> containing a regular expression of files to include in the archive. All other files will be excluded.
+     *                    There is a special case of ".*doc.xml", where the doc.xml files will be parsed to only include their metadata.
+     * @param reject_expr a <strong>String</strong> containing a regular expression of files not to include in the archive.
+     * @return boolean - true if the zip was created successfully(?).
+     * @see dirFunc(ZipOutputStream, String, int, GShell, boolean, String, String) 
+     * @see zipup(String, String, String, GShell, String, String)
+     */
+    static private boolean zipFunc(ZipOutputStream zos, String file_path, int prefix_strip, GShell source, boolean encountered_file, String accept_expr, String reject_expr) 
+    {
+	String new_file_path = file_path;
+
+	if((reject_expr != "") && (file_path.matches(reject_expr))) {
+	    // matches reject expression
+	    //DebugStream.println("File \'" + file_path + "\' matches the reject expression \'" + reject_expr + "\'");
+	    return encountered_file;
+	}
+
+	if ((accept_expr != "") && (!file_path.matches(accept_expr))) {
+	    // does not match accept expression
+	    //DebugStream.println("File \'" + file_path + "\' doesn't match accept expression \'" + accept_expr + "\'");
+	    return encountered_file;
+	}
+
+	//Special case: we only want the metadata. Parse the xml files.
+	if(accept_expr.compareTo(".*doc.xml") == 0) {
+	    DebugStream.println("Only want to get metadata");
+	    Document old_document = XMLTools.parseXMLFile(new File(file_path));
+	    NodeList content = old_document.getElementsByTagName("Content");
+
+	    try {
+		for(int i=content.getLength()-1; i >= 0; i--) {
+		    //Remove all content - just leave the metadata.
+		    content.item(i).getParentNode().removeChild(content.item(i));
+		}
+	    }
+	    catch (Exception ex) {
+		ex.printStackTrace();
+	    }
+
+	    new_file_path = file_path.substring(0, file_path.lastIndexOf(File.separator) + 1) + "new.xml";
+	    //Is there any better way than writing out as a new file, then reading back in??
+	    XMLTools.writeXMLFile(new File(new_file_path), old_document);
+	}
+
+	// Using try is required because of file io.
+	try {
+	    // Exit if pressed cancel.
+	    if (source != null && source.hasSignalledStop()) {
+		return false;
+	    }
+
+	    // Create a Zip Entry and put it into the archive (no data yet).
+
+	    // Strip off col_dir prefix
+	    String zip_path = file_path.substring(prefix_strip);
+	    // Zip files use '/' for directory separator
+	    String unix_style_path = unixStylePath(zip_path);
+
+	    ZipEntry fileEntry = new ZipEntry(unix_style_path);
+	    zos.putNextEntry(fileEntry);
+
+	    // Create a file input stream and a buffered input stream.
+	    FileInputStream fis = new FileInputStream(new_file_path);
+	    BufferedInputStream bis = new BufferedInputStream(fis);
+	    
+	    // Create a byte array object named data and declare byte count variable.
+	    byte[] data = new byte[1024];
+	    int byteCount;
+	    // Create a loop that reads from the buffered input stream and writes
+	    // to the zip output stream until the bis has been entirely read.
+	    while ((byteCount = bis.read(data, 0, 1024)) > -1) {
+		//Check for cancell
+		if(source != null) {
+		    if(source.hasSignalledStop()) {
+			break;
+		    }
+		}
+		zos.write(data, 0, byteCount);
+	    }
+	    encountered_file = true;
+	} 
+	catch (IOException e) {
+	    e.printStackTrace();
+	}
+	
+	DebugStream.println("Zipping up: " + file_path);
+	return encountered_file;
+    }
+
+    /**
+     * Method to handle ziping up of a directory. This is called by {@link zipup(String, String, String, GShell, String, String)}
+     *
+     * @param zos the <strong>ZipOutputStream</strong> to output to.
+     * @param dir_name the directory name to zip, as a <strong>String</strong>
+     * @param prefix_strip the <strong>int</strong> used to substring the file_path
+     * @param source the <strong>GShell</strong> object that is calling this method, so that we can check to see if the process has been cancelled.
+     *               This is null if GShell is not the calling object.
+     * @param encountered_file ??What's this??
+     * @param accept_expr a <strong>String</strong> containing a regular expression of files to include in the archive. All other files will be excluded.
+     * @param reject_expr a <strong>String</strong> containing a regular expression of files not to include in the archive.
+     *
+     * @see zipup(String, String, String, GShell, String, String)
+     * @see zipFunc(ZipOutputStream, String, int, GShell, boolean, String, String) 
+     */
+    static private boolean dirFunc (ZipOutputStream zos, String dir_name, int prefix_strip, GShell source, boolean encountered_file, String accept_expr, String reject_expr) 
+    {
+	File dirObj = new File(dir_name);
+
+	if (dirObj.exists() == true) {
+	    if (dirObj.isDirectory() == true) {
+		// Create an array of File objects, one for each file or directory in dirObj.
+		File [] fileList = dirObj.listFiles();
+		
+		// Loop through File array and display.
+		for (int i = 0; i < fileList.length; i++) {
+		    if(source != null && source.hasSignalledStop()) { break; }
+		    File file = fileList[i];
+		    if (file.isDirectory()) {
+			String dir_path = file.getPath();
+			String zip_path = dir_path.substring(prefix_strip);
+			// Zip files use '/' for directory separator
+			String unix_style_path 
+			    = unixStylePath(zip_path+File.separator);
+			ZipEntry dirEntry = new ZipEntry(unix_style_path);
+
+			try {
+			    zos.putNextEntry(dirEntry);
+			} 
+			catch (IOException e) {
+			    e.printStackTrace();
+			}
+
+			encountered_file = dirFunc(zos, dir_path, prefix_strip, source, encountered_file, accept_expr, reject_expr);
+		    } else if (file.isFile()) {
+			// Call the zipFunc function
+			String file_path = fileList[i].getPath();
+			encountered_file = zipFunc(zos,file_path,prefix_strip, source, encountered_file, accept_expr, reject_expr);
+		    }
+		}
+	    } 
+	    else { 
+		System.err.println (dir_name+" is not a directory."); 
+	    }
+	} 
+	else { 
+	    System.err.println ("Directory "+dir_name+" does not exist."); 
+	}
+	return encountered_file;
+    }
+    
+    /**
+     * Method to zip up a given file or directory associated with a particular collection.
+     * This method mainly called from {@link GShell}, with a few exceptions. The zip files produced are used
+     * to pass files (new files to add, metadata, etc) between the GLI applet and the Greenstone server.
+     * The actual zipping of files and directories is handled by {@link zipFunc(ZipOutputStream, String, int, GShell, boolean, String, String) and
+     * {@link dirFunc(ZipOutputStream, String, int, GShell, boolean, String, String)} respectfully.
+     *
+     * @param col_dir the path to the collect directory, as a <strong>String</strong>
+     * @param col_name the collection name, as as <strong>String</strong>
+     * @param dir_or_file the directory or file within the collection to zip up, as a <strong>String</strong>
+     * @param source the <strong>GShell</strong> object that is calling this method, so that we can check to see if the process has been cancelled.
+     *               This is null if GShell is not the calling object.
+     * @param accept_expr a <strong>String</strong> containing a regular expression of files to include in the archive. All other files will be excluded.
+     * @param reject_expr a <strong>String</strong> containing a regular expression of files not to include in the archive.
+     *
+     * @see zipFunc(ZipOutputStream, String, int, GShell, boolean, String, String) 
+     * @see dirFunc(ZipOutputStream, String, int, GShell, boolean, String, String) 
+     */
+    static public boolean zipup(String col_dir, String col_name, String dir_or_file, GShell source, String accept_expr, String reject_expr)
+    {
+	if (!col_dir.endsWith(File.separator)) {
+	    col_dir += File.separator;
+	}
+
+	int prefix_strip = col_dir.length();
+	boolean encountered_file = false;
+
+	String zip_fname = col_dir + col_name + ".zip";
+	String zip_dir_or_file = col_dir + col_name + File.separator + dir_or_file;
+	File zip_dof = new File(zip_dir_or_file);
+
+	try {
+	    FileOutputStream fos = new FileOutputStream(zip_fname);
+	    ZipOutputStream zos = new ZipOutputStream(fos);
+	    
+	    if (zip_dof.exists()) {
+		if (zip_dof.isDirectory()) {
+		    String zip_dir = zip_dir_or_file;
+		    encountered_file = dirFunc(zos, zip_dir, prefix_strip, source, encountered_file, accept_expr, reject_expr);
+		}
+		else {
+		    String zip_full_file = zip_dir_or_file; 
+		    String zip_path = zip_full_file.substring(prefix_strip);
+
+		    for (int i=1; i<zip_path.length(); i++) {
+			String ch = String.valueOf(zip_path.charAt(i));
+
+			if (ch.equals(File.separator)) {
+			    String dir_path = zip_path.substring(0,i);
+			    // Zip files use '/' for directory separator
+			    String unix_style_path 
+				= unixStylePath(dir_path+File.separator);
+			    ZipEntry dirEntry = new ZipEntry(unix_style_path);
+			    zos.putNextEntry(dirEntry);
+			}
+		    }
+		    encountered_file = zipFunc(zos, zip_full_file, prefix_strip, source, encountered_file, accept_expr, reject_expr);
+		}
+	    }
+	    else {
+		System.err.println("Warning: " + zip_dir_or_file + " does not exist!");
+	    }
+	    
+	    // Close the file output streams for both the file and the zip.
+	    zos.flush();
+	    zos.close();
+	    fos.close();
+	} 
+	catch (IOException exception) {
+	    DebugStream.printStackTrace(exception);
+	    return false;
+	}
+	return encountered_file;
+    } 
+
+
+    /**
+     * Method to unzip a zip file associated with a particular collection.
+     * The location and name of the zip file should be derrived from the collection. Please see below for details.
+     *
+     * @param col_dir the path to the collection directory, as a <strong>String</strong>. This is where the zip file should be located.
+     * @param col_name the name of the collection, as a <strong>String</strong>. This should be the name of the zip file (with a  .zip extension).
+     */
+    static public void unzip(String col_dir, String col_name)
+    {
+	if (!col_dir.endsWith(File.separator)) {
+	    col_dir += File.separator;
+	}
+
+	String zip_fname = col_dir + col_name + ".zip";
+	// int zip_mode = ZipFile.OPEN_READ | ZipFile.OPEN_DELETE;
+	int zip_mode = ZipFile.OPEN_READ; 
+
+	try {
+	    File cfile = new File(zip_fname);
+	    ZipFile zipfile = new ZipFile(cfile, zip_mode);
+	    
+	    Enumeration e = zipfile.entries(); 
+	    while (e.hasMoreElements()) {
+		ZipEntry zipentry = (ZipEntry) e.nextElement();
+		String zentryname = col_dir + zipentry.getName();
+		File zfile = new File(zentryname);
+		DebugStream.println("    Unzipping: " + zentryname);
+
+		if (zipentry.isDirectory()) {
+		    // Create named directory, if it doesn't already exist
+		    if (!zfile.exists() && !zfile.mkdirs()) {
+			System.err.println("Error: unable to create directory " + zfile);
+		    }
+		}
+		else {
+		    // Write out file to disk
+
+		    //Make sure it's parent directory exists.
+		    File dir = new File(zfile.getParent());
+		    dir.mkdirs();
+
+		    // set up input stream
+		    InputStream zis = zipfile.getInputStream(zipentry); 
+		    BufferedInputStream bzis = new BufferedInputStream(zis); 
+		    DataInputStream dbzis = new DataInputStream(bzis);
+		    
+		    // set up output stream
+		    FileOutputStream fzos = new FileOutputStream(zentryname);
+		    BufferedOutputStream bfzos = new BufferedOutputStream(fzos);
+		    
+		    byte[] buf = new byte[1024];
+		    int len;
+		    while ((len = dbzis.read(buf)) >= 0) {
+			bfzos.write(buf,0,len);
+		    }
+		    
+		    dbzis.close();
+		    bzis.close();
+		    zis.close();
+
+		    bfzos.close();
+		    fzos.close();
+		}
+	    }
+
+	    zipfile.close();
+
+	    // delete zip file
+	    boolean file_deleted = cfile.delete();
+	    if (file_deleted) {
+		System.err.println("Zip file " + cfile.toString() + " deleted");
+	    }
+	    else {
+		System.err.println("Zip file " + cfile.toString() + " NOT deleted");
+	    }
+
+
+	} 
+	catch (ZipException error) {
+	    System.err.println("Error: Unable to open '"+zip_fname+"'");
+	    System.err.println("This maybe caused by the zip file being empty.");
+	    DebugStream.printStackTrace(error);
+	}
+
+	catch (Exception error) {
+	    error.printStackTrace();
+	}
+    }
+
+
+    /** 
+     * Method which unzips a given metadata resoure.
+     * @param jar_zip_fname The name of the jar file as a <strong>String</strong>.
+     * @param dst_dir The destination directory for unzipping, also as a <strong>String</strong>.
+     * @see JarTools.extractFromJar(String, String, boolean)
+     */
+    static public void unzipFromJar(String jar_zip_fname, String dst_dir) {
+
+	File file = null;
+	if (!dst_dir.endsWith(File.separator)) {
+	    dst_dir += File.separator;
+	}
+
+	JarTools.extractFromJar(jar_zip_fname,dst_dir,true);
+
+	String zip_ofname = dst_dir + jar_zip_fname;
+	File zip_file = new File(zip_ofname);
+
+	try {
+	    ZipFile zipfile = new ZipFile(zip_file);
+	    
+	    Enumeration e = zipfile.entries(); 
+	    while (e.hasMoreElements()) {
+		ZipEntry zipentry = (ZipEntry) e.nextElement();
+		String zentryname = dst_dir + zipentry.getName();
+		DebugStream.println("    Unzipping: " + zentryname);
+
+		if (zipentry.isDirectory()) {
+		    // Create named directory, if it doesn't already exist
+		    File zip_entry_file = new File(zentryname);
+		    if (!zip_entry_file.exists() && !zip_entry_file.mkdirs()) {
+			System.err.println("Error: unable to create directory " + zip_entry_file);
+		    }
+		}
+		else {
+		    // Write out file to disk
+
+		    // set up input stream
+		    InputStream zis = zipfile.getInputStream(zipentry); 
+		    BufferedInputStream bzis = new BufferedInputStream(zis); 
+		    DataInputStream dbzis = new DataInputStream(bzis);
+		    
+		    // set up output stream
+		    FileOutputStream fzos = new FileOutputStream(zentryname);
+		    BufferedOutputStream bfzos = new BufferedOutputStream(fzos);
+		    
+		    byte[] buf = new byte[1024];
+		    int len;
+		    while ((len = dbzis.read(buf)) >= 0) {
+			bfzos.write(buf,0,len);
+		    }
+		    
+		    dbzis.close();
+		    bfzos.close();
+		}
+	    }
+	} 
+	catch (ZipException error) {
+	    System.err.println("Error: Unable to open '"+zip_file.getAbsolutePath()+"'");
+	    DebugStream.printStackTrace(error);
+	}
+
+	catch (Exception error) {
+	    error.printStackTrace();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Zipup.java
===================================================================
--- /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Zipup.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gli/src/org/greenstone/gatherer/util/Zipup.java	(revision 10506)
@@ -0,0 +1,95 @@
+/**
+ *#########################################################################
+ *
+ * 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: Matthew Whyte, 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.gatherer.util;
+
+import java.io.File;
+
+/**
+ * Zip up a given directory of a given Greenstone collection.
+ * The actual zipping code is contained in {@link ZipTools.zipup(String, String, String, GShell, String, String)}.
+ * This class basically contains a main method that requires adequate arguments to call the zipup method.
+ *
+ * Arguments:
+ * <br>gsdlhome, the home of greensone, eg "/research/mgw5/gsdl/"
+ * <br>collecion, the name of the collection, eg "mgw5-test"
+ * <br>directory, the name of the directory to zip up, eg "archives"
+ * <br>[accept_expression], a regular expression of files to exclusively include in the archive. Optional.
+ * <br>[reject_expression], a regular expression of files to exclude from the archive. Optional.
+ *
+ * @see ZipTools.zipup(String, String, String, GShell, String, String)
+ */
+public class Zipup {
+
+    static public void main(String[] args)
+    {
+	if (args.length < 3 || args.length > 8) {
+	    System.err.println("Usage: Zipup gsdlhome collection directory [-accept accept_expression] [-reject reject_expression]");
+	    return;
+	}
+	
+	boolean metadata_only = false;
+	String base_dir = args[0];
+	String collection = args[1];
+	String directory = args[2];
+	String accept_expr = "";
+	String reject_expr = "";
+
+	for(int i=0; i < args.length; i++) {
+	    if(args[i].compareTo("-accept") == 0) {
+		if(args.length >= i+1) {
+		    accept_expr = args[++i];
+		}
+		else {
+		    System.err.println("Usage: Zipup gsdlhome collection directory [-accept accept_expression] [-reject reject_expression]");
+		    return;
+		}
+	    }
+	    else if(args[i].compareTo("-reject") == 0) {
+		if(args.length >= i+1) {
+		    reject_expr = args[++i];
+		}
+		else {
+		    System.err.println("Usage: Zipup gsdlhome collection directory [-accept accept_expression] [-reject reject_expression]");
+		    return;
+		}
+	    }
+	}     
+
+	ZipTools.zipup(base_dir, collection, directory, null, accept_expr, reject_expr);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/Install.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/Install.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/Install.txt	(revision 10506)
@@ -0,0 +1,66 @@
+Note: more up-to-date notes may be available on our website, at
+ http://www.greenstone.org/english/docs/compiling.html
+
+-- Compiling and installing on Unix --
+
+cd to the top level gsdl directory (i.e. the directory where this file
+lives) and perform the following three steps.
+
+1. ./configure
+2. make
+3. make install
+
+This will install the library executable to gsdl/cgi-bin. If you want to
+run Greenstone from a system cgi-bin directory you'll need to move the
+library executable and gsdlsite.cfg from gsdl/cgi-bin to your system
+cgi-bin.
+
+Note that the Greenstone directory structure is important to the operation
+of the software. Therefore the --prefix, --bindir etc. options to configure
+make no sense and will have no effect. If you want Greenstone to be
+installed somewhere specific (say /usr/local) you'll need to move the
+entire gsdl directory there.
+
+-- Compiling on Windows --
+
+Greenstone has been successfully compiled using Microsoft Visual C++
+versions 4.2 and 6.0. We have also heard that Greenstone can be compiled
+with Microsoft Visual Studio .NET 2002, but have not confirmed that
+ourselves. If anyone succeeds in compiling Greenstone with another
+compiler (or another version of VC++) we'd appreciate hearing about
+it at greenstone@cs.waikato.ac.nz.
+
+The major difference between compiling with VC++ 4.2 compared with VC++ 6.0
+is that 4.2 must use the STLport standard template library (packaged with
+Greenstone) while VC++ 6.0 may use its own built in STL implementation.
+
+Perform the following steps to compile and install Greenstone. Note that
+some parts of the process described are specific to one or other of the two
+compilation options mentioned above (STLport or non-STLport). These steps
+are marked as such.
+
+1. Unzip the following zip archives (into the directories in which the
+   zip files themselves are contained).
+
+   * gsdl\packages\windows\gdbm\gdbm.zip
+   * gsdl\packages\windows\crypt\crypt.zip
+   * gsdl\packages\windows\stlport\stlport.zip (STLport version only)
+
+2. To use VC++ command line tools you may need to execute the
+   MSDEV\BIN\VCVARS32.BAT batch file to set up your environment.
+
+3. cd to the top level gsdl directory (i.e. the directory where this file
+   lives).
+
+4. compile the web library (library.exe) with 
+   "nmake /f win32.mak USE_STLPORT=1" (STLport version) 
+   or 
+   "nmake /f win32.mak" (non-STLport version).
+
+5. compile the local library (server.exe) with
+   "nmake /f win32.mak USE_STLPORT=1 LOCAL_LIBRARY=1" (STLport version)
+   or
+   "nmake /f win32.mak LOCAL_LIBRARY=1" (non-STLport version)
+
+This will install library.exe to the gsdl\cgi-bin directory and server.exe
+to the top level gsdl directory.
Index: /tags/gsdl-2_61-distribution/gsdl/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/Makefile.in	(revision 10506)
@@ -0,0 +1,104 @@
+###########################################################################
+#
+# Makefile -- gsdl
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+srcdir = @srcdir@
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+@SET_MAKE@
+CC = @CC@
+CXX = @CXX@
+CFLAGS = @CFLAGS@
+CXXFLAGS = @CXXFLAGS@
+LIBS   = @LIBS@
+MDEFINES =
+
+GSDLOS = @gsdlos@
+
+COMPILE = $(CC) -c
+
+SOURCES = 
+
+OBJECTS = 
+
+ALLFILES = $(OBJECTS)
+
+INSTALLDIRS = src/recpt src/txt2db src/db2txt src/hashfile src/getpw packages/mg src/phind/generate packages src/mgpp src/oaiservr
+
+MODULEDIRS = @MODULEDIRS@
+
+OTHERDIRS = packages packages/mg lib src/mgpp src/colservr src/recpt src/txt2db src/db2txt src/hashfile src/getpw src/phind/generate src/oaiservr
+
+all:
+	for odir in $(OTHERDIRS) $(MODULEDIRS); do \
+	  echo making $@ in $$odir; \
+	  (cd $$odir && $(MAKE) $(MDEFINES) $@) || exit 1; \
+	done
+
+install: all
+
+	for idir in $(INSTALLDIRS); do \
+	  echo installing $$idir; \
+	  (cd $$idir && $(MAKE) install) || exit 1; \
+	done
+
+# added test to check existence of Makefile, as src/recpt is in
+# both INSTALLDIRS and OTHERDIRS - can't make distclean twice!
+distclean: clean
+	rm -f Makefile config.cache config.h config.log stamp-h config.status
+	for subdir in $(INSTALLDIRS) $(OTHERDIRS); do \
+	  echo cleaning $@ in $$subdir; \
+	  (cd $$subdir && if test -e Makefile; then $(MAKE) distclean;fi) || exit 1; \
+	done
+
+clean:
+	for subdir in $(INSTALLDIRS) $(OTHERDIRS); do \
+	  echo cleaning $@ in $$subdir; \
+	  (cd $$subdir && if test -e Makefile; then $(MAKE) clean; fi) || exit 1; \
+	done
+
+# commented out - jrm21 Dec 2004 - can get confused by cvs timestamps
+# (and might run the wrong version of autoconf)
+#
+## For an explanation of the following Makefile rules, see node
+## `Automatic Remaking' in GNU Autoconf documentation.
+#Makefile: Makefile.in config.status
+#	CONFIG_FILES=$@ CONFIG_HEADERS= ./config.status
+#config.status: configure
+#	./config.status --recheck
+#configure: configure.in aclocal.m4
+#	cd $(srcdir) && autoconf
+#
+#config.h: stamp-h
+#stamp-h: config.h.in config.status
+#	CONFIG_FILES= CONFIG_HEADERS=config.h ./config.status
+#config.h.in: stamp-h.in
+#stamp-h.in: configure.in aclocal.m4 acconfig.h
+#	cd $(srcdir) && autoheader
+#	$(TOUCH) $(srcdir)/stamp-h.in
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/WIN32cfg.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/WIN32cfg.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/WIN32cfg.h	(revision 10506)
@@ -0,0 +1,163 @@
+/* config.h.  Generated automatically by configure.  */
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+/* #undef _ALL_SOURCE */
+#endif
+
+/* Define if using alloca.c.  */
+/* #undef C_ALLOCA */
+
+/* Define to empty if the keyword does not work.  */
+/* #undef const */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define if you have alloca, as a function or macro.  */
+#define HAVE_ALLOCA 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+/* #define HAVE_ALLOCA_H 1 */
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+/* #undef HAVE_DOPRNT */
+
+/* Define if you have the vprintf function.  */
+#define HAVE_VPRINTF 1
+
+/* Define if on MINIX.  */
+/* #undef _MINIX */
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+/* #undef off_t */
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work.  */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void).  */
+#define RETSIGTYPE void
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+/* #undef size_t */
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+	STACK_DIRECTION > 0 => grows toward higher addresses
+	STACK_DIRECTION < 0 => grows toward lower addresses
+	STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+/* #define TIME_WITH_SYS_TIME 1 */
+
+/* Define if your <sys/time.h> declares struct tm.  */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to the name of the distribution.  */
+#define PACKAGE "mg"
+
+/* Define to the version of the distribution.  */
+#define VERSION "1.2"
+
+/* Define to 1 if you have the valloc function.  */
+/* #define HAVE_VALLOC 1 */
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#define PROTOTYPES 1
+
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+/* #undef WITH_DMALLOC */
+
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+/* #undef WITH_REGEX */
+
+/* Some braindead header files do not have the requ'd function declarations */
+#define HAVE_FGETC_DECL 1
+#define HAVE_FREAD_DECL 1
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+/* #define HAVE_PR_BRKSIZE 1 */
+
+/* Define if you have the ftime function.  */
+/* #undef HAVE_FTIME */
+
+/* Define if you have the getpagesize function.  */
+/* #undef HAVE_GETPAGESIZE */
+
+/* Define if you have the getrusage function.  */
+/* #undef HAVE_GETRUSAGE */
+
+/* Define if you have the mallinfo function.  */
+/* #undef HAVE_MALLINFO */
+
+/* Define if you have the select function.  */
+#define HAVE_SELECT 1
+
+/* Define if you have the setbuffer function.  */
+/* #undef HAVE_SETBUFFER */
+
+/* Define if you have the strftime function.  */
+#define HAVE_STRFTIME 1
+
+/* Define if you have the strtol function.  */
+#define HAVE_STRTOL 1
+
+/* Define if you have the times function.  */
+/* #define HAVE_TIMES 1 */
+
+/* Define if you have the valloc function.  */
+/* #define HAVE_VALLOC 1 */
+
+/* Define if you have the <dirent.h> header file.  */
+/* #define HAVE_DIRENT_H 1 */
+
+/* Define if you have the <fcntl.h> header file.  */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <limits.h> header file.  */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <memory.h> header file.  */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <ndir.h> header file.  */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <string.h> header file.  */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/dir.h> header file.  */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/ndir.h> header file.  */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/procfs.h> header file.  */
+/* #define HAVE_SYS_PROCFS_H 1 */
+
+/* Define if you have the <sys/time.h> header file.  */
+/* #define HAVE_SYS_TIME_H 1 */
+
+/* Define if you have the <unistd.h> header file.  */
+/* #define HAVE_UNISTD_H 1 */
+
+/* Define if you have the m library (-lm).  */
+#define HAVE_LIBM 1
Index: /tags/gsdl-2_61-distribution/gsdl/acconfig.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/acconfig.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/acconfig.h	(revision 10506)
@@ -0,0 +1,50 @@
+/* Special definitions for mg, processed by autoheader.
+   Created by [TS:Aug/95] 
+   by grepping for AC_DEFINE on configure.in and using the appropriate defs 
+   of acconfig.h used by GNU tar.
+*/
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define if `union wait' is the type of the first arg to wait functions.  */
+#undef HAVE_UNION_WAIT
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define FASTCGI if needsbe */
+#undef USE_FASTCGI
+
+/* Define USE_CORBA if needsbe */
+#undef USE_CORBA
+
+/* Define MICO_DIR if needsbe */
+#undef MICO_DIR
+
+/* Define MICO_VERSION if required */
+#undef MICO_VERSION
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/aclocal.m4
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/aclocal.m4	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/aclocal.m4	(revision 10506)
@@ -0,0 +1,140 @@
+# Local additions to Autoconf macros.
+# Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+# François Pinard <pinard@iro.umontreal.ca>, 1992.
+
+# [TS:Aug/95] - chopped out the NLS stuff which I don't support
+
+## ------------------------------- ##
+## Check for function prototypes.  ##
+## ------------------------------- ##
+
+AC_DEFUN(fp_C_PROTOTYPES,
+[AC_REQUIRE([fp_PROG_CC_STDC])
+AC_MSG_CHECKING([for function prototypes])
+if test "$ac_cv_prog_cc_stdc" != no; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(PROTOTYPES)
+  U= ANSI2KNR=
+else
+  AC_MSG_RESULT(no)
+  U=_ ANSI2KNR=ansi2knr
+fi
+AC_SUBST(U)dnl
+AC_SUBST(ANSI2KNR)dnl
+])
+
+## ----------------------------------------- ##
+## ANSIfy the C compiler whenever possible.  ##
+## ----------------------------------------- ##
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so.  This macro tries various
+# options that select ANSI C on some system or another.  It considers the
+# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and
+# handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{ac_cv_prog_cc_stdc} is set to @samp{no}.  If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN(fp_PROG_CC_STDC,
+[AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(ac_cv_prog_cc_stdc,
+[ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  AC_TRY_COMPILE(
+[#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+], [int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};],
+[ac_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CFLAGS="$ac_save_CFLAGS"
+])
+AC_MSG_RESULT($ac_cv_prog_cc_stdc)
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+])
+
+## --------------------------------------------------------- ##
+## Use AC_PROG_INSTALL, supplementing it with INSTALL_SCRIPT ##
+## substitution.					     ##
+## --------------------------------------------------------- ##
+
+AC_DEFUN(fp_PROG_INSTALL,
+[AC_PROG_INSTALL
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL} -m 755'
+AC_SUBST(INSTALL_SCRIPT)dnl
+])
+
+## ----------------------------------- ##
+## Check if --with-dmalloc was given.  ##
+## ----------------------------------- ##
+
+# I just checked, and GNU rx seems to work fine with a slightly
+# modified GNU m4.  So, I put out the test below in my aclocal.m4,
+# and will try to use it in my things.  The idea is to distribute
+# rx.[hc] and regex.[hc] together, for a while.  The WITH_REGEX symbol
+# (which should also be documented in acconfig.h) is used to decide
+# which of regex.h or rx.h should be included in the application.
+#
+# If `./configure --with-regex' is given, the package will use
+# the older regex.  Else, a check is made to see if rx is already
+# installed, as with newer Linux'es.  If not found, the package will
+# use the rx from the distribution.  If found, the package will use
+# the system's rx which, on Linux at least, will result in a smaller
+# executable file.
+
+AC_DEFUN(fp_WITH_DMALLOC,
+[AC_MSG_CHECKING(if malloc debugging is wanted)
+AC_ARG_WITH(dmalloc,
+[  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz],
+[if test "$withval" = yes; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(WITH_DMALLOC)
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  AC_MSG_RESULT(no)
+fi], [AC_MSG_RESULT(no)])
+])
+
+## --------------------------------- ##
+## Check if --with-regex was given.  ##
+## --------------------------------- ##
+
+AC_DEFUN(fp_WITH_REGEX,
+[AC_MSG_CHECKING(which of rx or regex is wanted)
+AC_ARG_WITH(regex,
+[  --with-regex            use older regex in lieu of GNU rx for matching],
+[if test "$withval" = yes; then
+  ac_with_regex=1
+  AC_MSG_RESULT(regex)
+  AC_DEFINE(WITH_REGEX)
+  AC_LIBOBJ([regex])
+fi])
+if test -z "$ac_with_regex"; then
+  AC_MSG_RESULT(rx)
+  AC_CHECK_FUNC(re_rx_search, , [AC_LIBOBJ([rx])])
+fi
+])
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/anonymiselog.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/anonymiselog.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/anonymiselog.pl	(revision 10506)
@@ -0,0 +1,120 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# anonymiselog.pl -- anonymise a log file by MD5 hashing all IP addresses
+#
+# 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.
+#
+###########################################################################
+
+
+use MD5;
+
+
+sub main
+{
+    # Get the name of the log file to process
+    local $logfilename = shift(@_);
+
+    # Check that the necessary arguments were supplied
+    if (!$logfilename) {
+	print STDERR "Usage: anonymiselog.pl <logfile-name>\n";
+	die "Error: Required argument missing.\n";
+    }
+
+    # Open the log file
+    open(LOG_FILE, "<$logfilename") or die "Error: Could not open log file $logfilename.\n";
+
+    # Open the output file
+    local $outfilename = $logfilename . ".anon";
+    open(OUT_FILE, ">$outfilename") or die "Error: Could not write file $outfilename.\n"; 
+
+    # Create a new MD5 (RSA Data Security Inc. MD5 Message Digest) object
+    local $md5 = new MD5;
+
+    # Process the log, one line at a time
+    local $entry = "";
+    while (<LOG_FILE>) {
+	local $line = $_;
+	# print "Line: $line";
+
+	# If this line starts a new entry, process the previous one
+	if ($line =~ /^\//) {
+	    print OUT_FILE &anonymise_log_entry($entry);
+	    $entry = "";
+	}
+
+	# Remove trailing whitespace, and skip blank lines
+	$line =~ s/(\s*)$//;
+	next if ($line =~ /^$/);
+
+	$entry = $entry . $line;
+    }
+
+    # Process the last entry
+    print OUT_FILE &anonymise_log_entry($entry);
+
+    # All done
+    close(LOG_FILE);
+    close(OUT_FILE);
+}
+
+
+sub anonymise_log_entry
+{
+    local $entry = shift(@_);
+    return "" if ($entry eq "");
+
+    # Parse the IP address from the entry
+    $entry =~ /^\S+\s((\w|-|\.)+)\s\[/;
+    if (!defined($1)) {
+	print STDERR "Could not extract IP address from entry: $entry\n";
+	return "";
+    }
+
+    # Casefold the IP address, hash using MD5, and take the last 16 characters
+    local $ipaddress = $1;
+    $ipaddress =~ tr/A-Z/a-z/;
+    local $hashedaddress = substr($md5->hexhash($ipaddress), -16);
+
+    # Replace the IP address with the hashed value
+    $entry =~ s/$ipaddress/$hashedaddress/ig;
+
+    # Parse the Greenstone user identifier (z variable) from the entry
+    $entry =~ /\sz=((\w|-|\.)+)/;
+    if (!defined($1)) {
+	print STDERR "No z variable in entry: $entry\n";
+	return "";
+    }
+
+    # Casefold the Greenstone user ID, hash using MD5, and take the last 16 characters
+    local $gsuserid = $1;
+    $gsuserid =~ tr/A-Z/a-z/;
+    local $hasheduserid = substr($md5->hexhash($gsuserid), -16);
+
+    # Replace the Greenstone user ID with the hashed value
+    $entry =~ s/$gsuserid/$hasheduserid/ig;
+    return $entry . "\n";
+}
+
+
+&main(@ARGV);
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/build
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/build	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/build	(revision 10506)
@@ -0,0 +1,625 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# build --
+# 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.
+#
+###########################################################################
+
+# This perl script may be called directly or by running build.bat on
+# windows (build.bat is in bin\windows)
+
+# Note that this script has grown over time and now has many options for
+# use when called from within the collector. If it appears to
+# over-complicate things a little, that's why.
+
+package build;
+
+use FileHandle;
+use File::Copy;
+
+BEGIN {
+
+    die "GSDLHOME not set - did you remember to source setup.bash (unix) or " .
+	"run setup.bat (windows)?\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set - did you remember to source setup.bash (unix) or " .
+	"run setup.bat (windows)?\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+
+    STDOUT->autoflush(1);
+    STDERR->autoflush(1);
+}
+
+use lib qq($ENV{'GSDLHOME'}/perllib/cpan);
+use Mail::Sendmail;
+use parsargv;
+use util;
+use cfgread;
+
+# set up path - this allows for paths not to be supplied to system calls
+# and overcomes problems when GSDLHOME contains spaces (double quoting
+# the call doesn't work on win2k and probably other variants of winnt)
+my $path_separator = ":";
+$path_separator = ";" if $ENV{'GSDLOS'} =~ /^windows$/;
+$ENV{'PATH'} = &util::filename_cat($ENV{'GSDLHOME'}, "bin", $ENV{'GSDLOS'}) .
+    $path_separator . &util::filename_cat($ENV{'GSDLHOME'}, "bin", "script") .
+    $path_separator . $ENV{'PATH'};
+
+&parse_args (\@ARGV);
+
+my ($collection) = @ARGV;
+
+if (!defined $collection || $collection !~ /\w/) {
+    print STDERR "You must specify a collection to build\n";
+    &print_usage();
+    die "\n";
+}
+
+if ($optionfile =~ /\w/) {
+    open (OPTIONS, $optionfile) || die "Couldn't open $optionfile\n";
+    my $line = [];
+    my $options = [];
+    while (defined ($line = &cfgread::read_cfg_line ('build::OPTIONS'))) {
+	push (@$options, @$line);
+    }
+    close OPTIONS;
+    &parse_args ($options);
+}
+
+if ($maxdocs == -1) {
+    $maxdocs = "";
+} else {
+    $maxdocs = "-maxdocs $maxdocs";
+}
+
+my $cdir = $collectdir;
+$cdir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect") unless $collectdir =~ /\w/;
+my $importdir = &util::filename_cat ($cdir, $collection, "import");
+my $archivedir = &util::filename_cat ($cdir, $collection, "archives");
+my $buildingdir = &util::filename_cat ($cdir, $collection, "building");
+my $indexdir = &util::filename_cat ($cdir, $collection, "index");
+my $bindir = &util::filename_cat ($ENV{'GSDLHOME'}, "bin");
+
+my $use_out = 0;
+my $outfile = $out;
+if ($out !~ /^(STDERR|STDOUT)$/i) {
+    open (OUT, ">$out") || die "Couldn't open output file $out\n";
+    $out = "OUT";
+    
+    # delete any existing .final file
+    &util::rm ("$outfile.final") if -e "$outfile.final";
+
+    $use_out = 1;
+}
+$out->autoflush(1);
+
+# delete any .kill file left laying around from a previously aborted build
+if (-e &util::filename_cat ($cdir, $collection, ".kill")) {
+    &util::rm (&util::filename_cat ($cdir, $collection, ".kill"));
+}
+
+# get maintainer email address from main.cfg
+my $maintainer = "NULL";
+my $main_cfg = &util::filename_cat ($ENV{'GSDLHOME'}, "etc", "main.cfg");
+my $cfgdata = &cfgread::read_cfg_file ($main_cfg, "maintainer");
+if (defined $cfgdata->{'maintainer'} && $cfgdata->{'maintainer'} =~ /\w/) {
+    $maintainer = $cfgdata->{'maintainer'};
+}
+# if maintainer is "NULL" email_events should be disabled
+if ($maintainer =~ /^NULL$/i) {
+    $email_events = "";
+}
+
+&main();
+
+if ($use_out) {
+    close OUT;
+
+    # if we've created a build log we'll copy it to the collection's etc
+    # directory
+    my ($etcdir);
+    if ($dontinstall) {
+	$etcdir = &util::filename_cat($collectdir, "etc", "build.log");
+    } else {
+	$etcdir = &util::filename_cat($ENV{'GSDLHOME'}, "collect", $collection, "etc", "build.log");
+    }
+    
+    &util::cp($outfile, $etcdir);
+}
+
+sub print_usage {
+    print STDOUT "\n";
+    print STDOUT "build: Builds a Greenstone collection (i.e. runs import.pl and buildcol.pl\n";
+    print STDOUT "       then copies the resulting indexes to the correct place).\n\n";
+    print STDOUT "  usage: $0 [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 "   -append                 Add new files to existing collection\n";
+    print STDOUT "   -remove_archives        Remove archives directory after successfully\n";
+    print STDOUT "                           building the collection.\n";
+    print STDOUT "   -remove_import          Remove import directory after successfully\n";
+    print STDOUT "                           importing the collection.\n";
+    print STDOUT "   -buildtype build|import If 'build' attempt to build directly\n";
+    print STDOUT "                           from archives directory (bypassing import\n";
+    print STDOUT "                           stage). Defaults to 'import'\n";
+    print STDOUT "   -maxdocs number         Maximum number of documents to build\n";
+    print STDOUT "   -download directory     Directory (or file) to get import documents from.\n";
+    print STDOUT "                           There may be multiple download directories and they\n";
+    print STDOUT "                           may be of type http://, ftp://, or file://\n";
+    print STDOUT "                           Note that any existing import directory will be\n";
+    print STDOUT "                           deleted to make way for the downloaded data if\n";
+    print STDOUT "                           a -download option is supplied\n";
+    print STDOUT "   -collectdir directory   Collection directory (defaults to " .
+	&util::filename_cat ($ENV{'GSDLHOME'}, "collect") . ")\n";
+    print STDOUT "   -dontinstall            Only applicable if -collectdir is set to something\n";
+    print STDOUT "                           other than the default. -dontinstall will suppress\n";
+    print STDOUT "                           the default behaviour which is to install the\n";
+    print STDOUT "                           collection to the gsdl/collect directory once it has\n";
+    print STDOUT "                           been built.\n";
+    print STDOUT "   -save_archives          Create a copy of the existing archives directory\n";
+    print STDOUT "                           called archives.org\n";
+    print STDOUT "   -out                    Filename or handle to print output status to.\n";
+    print STDOUT "                           The default is STDERR\n";
+    print STDOUT "   -statsfile name         Filename or handle to print import statistics to.\n";
+    print STDOUT "                           The default is STDERR\n";
+    print STDOUT "   -make_writable          If set build will make the collection and any\n";
+    print STDOUT "                           temporary files it created globally writable after\n";
+    print STDOUT "                           it finishes\n";
+    print STDOUT "   -log_events             Log important events (collection built successfully\n";
+    print STDOUT "                           etc.) to event_log_file\n";
+    print STDOUT "   -event_log_file file    File to append important events to (defaults to\n";
+    print STDOUT "                           " . &util::filename_cat ($ENV{'GSDLHOME'}, "etc", "events.txt") . "\n";
+    print STDOUT "   -email_events addr      Comma separated list of email addresses to mail\n";
+    print STDOUT "                           details of important collection building events\n";
+    print STDOUT "   -mail_server server     The outgoing (SMTP) mail server to be used by\n";
+    print STDOUT "                           email_events. email_events will be disabled if\n";
+    print STDOUT "                           mail_server isn't set\n";
+    print STDOUT "   -event_header file      File containing a header to go on any event\n";
+    print STDOUT "                           messages. If not specified build will create a\n";
+    print STDOUT "                           generic header\n\n";
+    print STDOUT "  [Type \"build | more\" if this help text scrolled off your screen]";
+    print STDOUT "\n" unless $ENV{'GSDLOS'} =~ /^windows$/i;
+}
+
+sub main {
+
+    if ($save_archives && -d $archivedir) {
+	print $out "caching original archives to ${archivedir}.org\n";
+	&util::cp_r ($archivedir, "${archivedir}.org");
+    }
+
+    # do the download thing if we have any -download options
+    if (scalar (@download)) {
+	# remove any existing import data
+	if (&has_content ($importdir)) {
+	    print $out "build: WARNING: removing contents of $importdir\n";
+	    &util::rm_r ($importdir);
+	}
+	
+	foreach $download_dir (@download) {
+
+	    # remove any leading or trailing whitespace from filenames (just in case)
+	    $download_dir =~ s/^\s+//;
+	    $download_dir =~ s/\s+$//;
+	    
+	    if ($download_dir =~ /^(http|ftp):\/\//) {
+		# use wget to mirror http or ftp urls
+		# options used are:
+		#  -P = the directory to download documents to
+		#  -np = don't ascend to parent directories. this means that only documents
+		#        that live in the same directory or below on the same server as
+		#        the given url will be downloaded
+		#  -nv = not too verbose
+		#  -r = recursively mirror
+		#  -N = use time-stamping to see if an up-to-date local copy of each 
+		#       file already exists. this may be useful if wget fails and 
+		#       is restarted
+		#  -l inf = infinite recursion depth
+		#  -R "*\?*" = don't download cgi based urls
+		#  -o = the output file to write download status to (only used if the -out
+		#       option was given to build)
+
+		my $download_cmd = "perl -S gsWget.pl -P \"$importdir\" -np -nv";
+		$download_cmd .= " -r -N -l inf -R \"*\\?*\"";
+		$download_cmd .= " -o \"$outfile.download\"" if $use_out;
+		$download_cmd .= " \"$download_dir\"";
+		system ($download_cmd);
+
+		# note that wget obeys the robot rules. this means that it will have
+		# downloaded a robots.txt file if one was present. since it's unlikely 
+		# anyone really wants to include it in a collection we'll delete it.
+		# robots.txt shouldn't be more than two directories deep (I think it will 
+		# always be exactly two deep but will look for it in the top directory too)
+		# so that's as far as we'll go looking for it.
+		if (opendir (DIR, $importdir)) {
+		    my @files = readdir DIR;
+		    closedir DIR;
+		    foreach my $file (@files) {
+			next if $file =~ /^\.\.?$/;
+			if ($file =~ /^robots.txt$/i) {
+			    &util::rm (&util::filename_cat ($importdir, $file));
+			    last;
+			} else {
+			    $file = &util::filename_cat ($importdir, $file);
+			    if (-d $file) {
+				if (opendir (DIR, $file)) {
+				    my @files2 = readdir DIR;
+				    closedir DIR;
+				    foreach my $file2 (@files2) {
+					if ($file2 =~ /^robots.txt$/i) {
+					    &util::rm (&util::filename_cat ($file, $file2));
+					    last;
+					}
+				    }
+				}
+			    }
+			}
+		    }
+		}
+
+		# if using output directory append the file download output to it
+		&append_file ($out, "$outfile.download");
+		
+	    } else {
+		# we assume anything not beginning with http:// or ftp://
+		# is a file or directory on the local file system.
+		$download_dir =~ s/^file:(\/\/)?//;
+		$download_dir =~ s/^\s+//; # may be whitespace between "file://" and the rest
+		
+		if (-e $download_dir) {
+		    # copy download_dir and all it contains to the import directory
+		    my $download_cmd = "perl -S filecopy.pl";
+		    $download_cmd .= " -collectdir \"$collectdir\"" if $collectdir =~ /\w/;
+		    $download_cmd .= " -out \"$outfile.download\"" if $use_out;
+		    $download_cmd .= " \"" . $download_dir . "\" " . $collection;
+		    system ($download_cmd);
+		    # if using output directory append the file download output to it
+		    &append_file ($out, "$outfile.download");
+		} else {
+		    print $out "WARNING: '$download_dir' does not exist\n";
+		}
+	    }
+	}
+    }
+
+    if (-e &util::filename_cat ($archivedir, "archives.inf")) {
+	if (&has_content ($importdir)) {
+	    if ($buildtype eq "build") {
+		&gsdl_build();
+	    } else {
+		&gsdl_import();
+		&gsdl_build();
+	    }
+	} else {
+	    # there are archives but no import, build directly from archives
+	    print $out "build: no import material was found, building directly\n";
+	    print $out "       from archives\n";
+	    &gsdl_build();
+	}
+    } else {
+	if (&has_content ($importdir)) {
+	    if ($buildtype eq "build") {
+		print $out "build: can't build directly from archives as no\n";
+		print $out "       imported archives exist (did you forget to\n";
+		print $out "       move the contents of $collection/import to\n";
+		print $out "       collection/archives?)\n";
+	    }
+	    &gsdl_import();
+	    if (&has_content ($archivedir, "^archives.inf\$")) {
+		&gsdl_build();
+	    } else {
+		my $msg = "build: ERROR: The collection could not be built as no\n";
+		$msg .=   "       valid data was imported. Are at least some of\n";
+		$msg .=   "       the files you imported in a format that can be\n";
+		$msg .=   "       processed by the specified Greenstone plugins?\n";
+		print $out $msg;
+		&log_event ($msg);
+		&final_out (6) if $use_out;
+		die "\n";
+	    }
+	} else {
+	    # no import or archives
+	    my $msg = "build: ERROR: The collection could not be built as it contains no data.\n";
+	    print $out $msg;
+	    &log_event ($msg);
+	    &final_out (1) if $use_out;
+	    die "\n";
+	}
+    }
+
+    if ($collectdir ne "" && !$dontinstall) {
+	my $install_collectdir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect");
+	if (!&util::filenames_equal ($collectdir, $install_collectdir)) {
+	    
+	    # install collection to gsdl/collect
+	    print $out "installing the $collection collection\n";
+	    my $newdir = &util::filename_cat ($install_collectdir, $collection);
+	    my $olddir = &util::filename_cat ($collectdir, $collection);
+	    if (-d $newdir) {
+		my $msg = "build: Could not install collection as $newdir\n" .
+		    "       already exists. Collection will remain at\n$olddir\n";
+
+		print $out $msg;
+		&log_event ($msg);
+		&final_out (4) if $use_out;
+		die "\n";
+	    }
+	    if (!&File::Copy::move ($olddir, $newdir)) {
+		my $msg = "build: Failed to install collection to $newdir\n" .
+		    "       Collection will remain at $olddir\n";
+		print $out $msg;
+		&log_event ($msg);
+		&final_out (5) if $use_out;
+		die "\n";
+	    }
+	}
+    }
+
+    &log_event ("The $collection collection was built successfully\n");
+    &final_out (0) if $use_out;
+}
+
+sub gsdl_import {
+
+    print $out "importing the $collection collection\n\n";
+
+    my $import_cmd = "perl -S import.pl";
+    $import_cmd .= " -out \"$outfile.import\"" if $use_out;
+    $import_cmd .= " -removeold" unless $append;
+    $import_cmd .= " -collectdir \"$collectdir\"" if $collectdir =~ /\w/;
+    $import_cmd .= " -statsfile \"$statsfile\"" if $statsfile =~ /\w/;
+    $import_cmd .= " $maxdocs $collection";
+
+    system ($import_cmd);
+    # if using output directory append the import output to it
+    &append_file ($out, "$outfile.import");
+
+    if (-e &util::filename_cat ($archivedir, "archives.inf")) {
+	print $out "$collection collection imported successfully\n\n";
+	if ($remove_import) {
+	    print $out "removing import directory ($importdir)\n";
+	    &util::rm_r ($importdir);
+	}
+    } else {
+	my $msg = "build: ERROR: import.pl failed\n";
+	print $out "\n$msg";
+	&log_event ($msg);
+	&final_out (2) if $use_out;
+	die "\n";
+    }
+}
+
+sub gsdl_build {
+
+    print $out "building the $collection collection\n\n";
+
+    my $build_cmd = "perl -S buildcol.pl";
+    $build_cmd .= " -out \"$outfile.build\"" if $use_out;
+    $build_cmd .= " -collectdir \"$collectdir\"" if $collectdir =~ /\w/;
+    $build_cmd .= " $maxdocs $collection";
+    system ($build_cmd);
+    # if using output directory append the buildcol output to it
+    &append_file ($out, "$outfile.build");
+
+    if (-e &util::filename_cat ($buildingdir, "text", "$collection.ldb") ||
+	-e &util::filename_cat ($buildingdir, "text", "$collection.bdb")) {
+	print $out "$collection collection built successfully\n\n";
+	if ($remove_archives) {
+	    print $out "removing archives directory ($archivedir)\n";
+	    &util::rm_r ($archivedir);
+	}
+    } else {
+	my $msg = "build: ERROR: buildcol.pl failed\n";
+	print $out "\n$msg";
+	&log_event ($msg);
+	&final_out (3) if $use_out;
+	die "\n";
+    }
+
+    # replace old indexes with new ones
+    if (&has_content ($indexdir)) {
+	print $out "removing old indexes\n";
+	&util::rm_r ($indexdir);
+    }
+    rmdir ($indexdir) if -d $indexdir;
+    &File::Copy::move ($buildingdir, $indexdir);
+
+    # remove the cached arhives
+    if ($save_archives && -d "${archivedir}.org") {
+	&util::rm_r ("${archivedir}.org");
+    }
+}
+
+# return 1 if $dir directory contains any files or sub-directories (other
+# than those specified in the $ignore regular expression)
+sub has_content {
+    my ($dir, $ignore) = @_;
+
+    if (!-d $dir) {return 0;}
+    
+    opendir (DIR, $dir) || return 0;
+    my @files = readdir DIR;
+    closedir DIR;
+    
+    foreach my $file (@files) {
+	if ($file !~ /^\.{1,2}$/) {
+	    return 1 unless (defined $ignore && $file =~ /$ignore/);
+	}
+    }
+    return 0;
+}
+
+sub append_file {
+    my ($handle, $file) = @_;
+
+    open (FILE, $file) || return;
+    undef $/;
+    print $handle <FILE>;
+    $/ = "\n";
+    close FILE;
+    &util::rm ($file);
+}
+
+# creates a file called $outfile.final and writes an output code to it.
+# An output code of 0 specifies that there was no error
+sub final_out {
+    my ($exit_code) = @_;
+
+    if ($use_out && (!-e "$outfile.final")) {
+
+	if (open (FINAL, ">$outfile.final")) {
+	    print FINAL $exit_code;
+	    close FINAL;
+	}
+    }
+}
+
+sub log_event {
+    my ($msg) = @_;
+
+    return unless ($log_events || $email_events);
+
+    # get the event header
+    my $eheader = "[Build Event]\n";
+    $eheader .= "Date: " . scalar localtime() . "\n";
+    if ($event_header ne "" && open (HEADER, $event_header)) {
+	undef $/;
+	$eheader .= <HEADER>;
+	$/ = "\n";
+	close HEADER;
+    } else {
+	$eheader .= "Collection: $collection\n";
+	$eheader .= "GSDLHOME: $ENV{'GSDLHOME'}\n";
+	$eheader .= "Build Location: $collectdir\n";
+    }
+    
+    if ($log_events) {
+	my $fail = 0;
+	# append the event to the event log file
+	if ($event_log_file eq "" || !open (LOG, ">>$event_log_file")) {
+	    # log file defaults to $GSDLHOME/etc/events.txt
+	    $event_log_file = &util::filename_cat ($ENV{'GSDLHOME'}, "etc", "events.txt");
+	    if (!open (LOG, ">>$event_log_file")) {
+		print $out "build: ERROR: Couldn't open event log file $event_log_file\n";
+		$fail = 1;
+	    }
+	}
+	if (!$fail) {
+	    print LOG $eheader;
+	    print LOG $msg;
+	    print LOG "\n";
+	    close LOG;
+	}
+    }
+    
+    if ($email_events) {
+	# if mail_server isn't set email_events does nothing
+	if ($mail_server eq "") {
+	    print $out "build: WARNING: mail_server was not set - email_events option was ignored\n";
+	    return;
+	}
+	
+	my %mail = ('SMTP' => $mail_server, 
+		    'To' => $email_events,
+		    'From' => $maintainer,
+		    'Subject' => 'Greenstone Build Event'
+		    );
+	$mail{'Message'} = $eheader . $msg;
+	
+	if (!sendmail %mail) {
+	    print $out "build: ERROR sending mail to $email_events\n";
+	    print $out "'$Mail::Sendmail::error'\n";
+	}
+    }
+}
+
+
+sub parse_args {
+    my ($argref) = @_;
+
+    if (!parsargv::parse($argref, 
+			 'optionfile/.*/', \$optionfile,
+			 'append', \$append,
+			 'remove_archives', \$remove_archives,
+			 'remove_import', \$remove_import,
+			 'buildtype/^(build|import)$/import', \$buildtype,
+			 'maxdocs/^\-?\d+/-1', \$maxdocs,
+			 'download/.+', \@download,
+			 'collectdir/.*/', \$collectdir,
+			 'dontinstall', \$dontinstall,
+			 'save_archives', \$save_archives,
+			 'out/.*/STDERR', \$out,
+			 'make_writable', \$make_writable,
+			 'log_events', \$log_events,
+			 'event_log_file/.*/', \$event_log_file,
+			 'email_events/.*/', \$email_events,
+			 'mail_server/.*/', \$mail_server,
+			 'statsfile/.*/STDERR', \$statsfile,
+			 'event_header/.*/', \$event_header)) {
+	
+	&print_usage();
+	die "\n";
+    }
+}
+
+
+END {
+
+    if ($make_writable) {
+	# chmod a+rw new collection
+	my $installed_collection = &util::filename_cat($ENV{'GSDLHOME'}, "collect", $collection);
+	&recursive_chmod($installed_collection);
+
+	# chmod a+rw anything we've left laying about in the tmp directory
+	if (($collectdir ne "") && 	
+	    (!&util::filenames_equal ($collectdir, &util::filename_cat($ENV{'GSDLHOME'}, "collect")))) {
+	    &recursive_chmod($collectdir);
+	}
+    }
+
+    # this will produce a .final file if one doesn't exist yet - that
+    # should only happen if there's been an error somewhere in the perl
+    # code
+    &final_out(7);
+
+    sub recursive_chmod {
+	my ($dir) = @_;
+	return unless -d $dir;
+
+	chmod (0777, $dir);
+
+	opendir (DIR, $dir) || die;
+	my @files = readdir DIR;
+	closedir DIR;
+	
+	foreach my $file (@files) {
+	    next if $file =~ /^\.\.?$/;
+	    $file = &util::filename_cat($dir, $file);
+	    if (-d $file) {
+		&recursive_chmod ($file);
+	    } else {
+		chmod (0777, $file);
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/buildcol.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/buildcol.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/buildcol.pl	(revision 10506)
@@ -0,0 +1,548 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# buildcol.pl -- This program will build a particular collection
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# 11/04/03 Added usage datastructure - John Thompson
+
+package buildcol;
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use colcfg;
+use util;
+use scriptutil;
+use FileHandle;
+use gsprintf;
+use printusage;
+use parse2;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and vice versa
+no strict 'subs'; # allow barewords (eg STDERR) as function arguments
+
+my $mode_list =
+    [ { 'name' => "all",
+        'desc' => "{buildcol.mode.all}" },
+      { 'name' => "compress_text",
+        'desc' => "{buildcol.mode.compress_text}" },
+      { 'name' => "build_index",
+        'desc' => "{buildcol.mode.build_index}" },
+      { 'name' => "infodb",
+        'desc' => "{buildcol.mode.infodb}" } ];
+
+my $sec_index_list = 
+    [ {'name' => "never",
+       'desc' => "{buildcol.sections_index_document_metadata.never}" },
+      {'name' => "always",
+       'desc' => "{buildcol.sections_index_document_metadata.always}" },
+      {'name' => "unless_section_metadata_exists",
+       'desc' => "{buildcol.sections_index_document_metadata.unless_section_metadata_exists}" }
+      ];
+
+my $arguments =
+    [ { 'name' => "remove_empty_classifications",
+	'desc' => "{buildcol.remove_empty_classifications}",
+	'type' => "flag",
+	'reqd' => "no",
+	'modegli' => "3" },
+      { 'name' => "archivedir",
+	'desc' => "{buildcol.archivedir}",
+	'type' => "string",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "builddir",
+	'desc' => "{buildcol.builddir}",
+	'type' => "string",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+#     { 'name' => "cachedir",
+#	'desc' => "{buildcol.cachedir}",
+#	'type' => "string",
+#	'reqd' => "no" },
+      { 'name' => "collectdir",
+	'desc' => "{buildcol.collectdir}",
+	'type' => "string",
+	# parsearg left "" as default
+	#'deft' => &util::filename_cat ($ENV{'GSDLHOME'}, "collect"),
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "create_images",
+	'desc' => "{buildcol.create_images}",
+	'type' => "flag",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "debug",
+	'desc' => "{buildcol.debug}",
+	'type' => "flag",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "faillog",
+	'desc' => "{buildcol.faillog}",
+	'type' => "string",
+	# parsearg left "" as default
+	#'deft' => &util::filename_cat("<collectdir>", "colname", "etc", "fail.log"),
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "index",
+	'desc' => "{buildcol.index}",
+	'type' => "string",
+	'reqd' => "no",
+	'modegli' => "3" },
+      { 'name' => "keepold",
+	'desc' => "{buildcol.keepold}",
+	'type' => "flag",
+	'reqd' => "no",
+        'modegli' => "3" },
+      { 'name' => "removeold",
+	'desc' => "{buildcol.removeold}",
+	'type' => "flag",
+	'reqd' => "no",
+	'modegli' => "3" },
+      { 'name' => "language",
+	'desc' => "{scripts.language}",
+	'type' => "string",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "maxdocs",
+	'desc' => "{buildcol.maxdocs}",
+	'type' => "int",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "mode",
+	'desc' => "{buildcol.mode}",
+	'type' => "enum",
+	'list' => $mode_list,
+	# parsearg left "" as default
+#	'deft' => "all",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "no_strip_html",
+	'desc' => "{buildcol.no_strip_html}",
+	'type' => "flag",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "no_text",
+	'desc' => "{buildcol.no_text}",
+	'type' => "flag",
+	'reqd' => "no",
+	'modegli' => "3" },
+      { 'name' => "sections_index_document_metadata",
+	'desc' => "{buildcol.sections_index_document_metadata}",
+	'type' => "enum",
+	'list' => $sec_index_list,
+	'reqd' => "no",
+	'modegli' => "3" },
+      { 'name' => "out",
+	'desc' => "{buildcol.out}",
+	'type' => "string",
+	'deft' => "STDERR",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "verbosity",
+	'desc' => "{buildcol.verbosity}",
+	'type' => "int",
+	# parsearg left "" as default
+	#'deft' => "2",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "gli",
+	'desc' => "",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" },
+      { 'name' => "xml",
+	'desc' => "{scripts.xml}",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" } ];
+
+my $options = { 'name' => "buildcol.pl",
+		'desc' => "{buildcol.desc}",
+		'args' => $arguments };
+
+
+# globals
+my $collection;
+my $configfilename;
+my $out;
+
+sub gsprintf
+{
+    return &gsprintf::gsprintf(@_);
+}
+
+
+
+&main();
+
+sub main
+{
+    # command line args
+    my ($verbosity, $archivedir, $cachedir, $builddir, $maxdocs, 
+	$debug, $mode, $indexname, $removeold, $keepold, $remove_empty_classifications,
+	$create_images, $collectdir, $build, $type, $textindex,
+	$no_strip_html, $no_text, $faillog, $gli, $index, $language,
+	$sections_index_document_metadata);
+
+    my $xml = 0;
+
+    my $hashParsingResult = {};
+    my $blnParseFailed = "false";
+    # general options available to all plugins
+    my $intArgLeftinAfterParsing = parse2::parse(\@ARGV,$arguments,$hashParsingResult,"allow_extra_options");
+    # If there are more than one argument left after parsing, it mean user input too many arguments.
+    # Error occoured  will return 0
+    if($intArgLeftinAfterParsing > 1)
+    {
+	$blnParseFailed = "true"; 
+    }
+    if($blnParseFailed eq "true")
+    {
+	print "";
+	&PrintUsage::print_txt_usage($options, "{buildcol.params}");
+	die "\n";
+    }
+    foreach my $strVariable (keys %$hashParsingResult)
+    {
+	eval "\$$strVariable = \$hashParsingResult->{\"\$strVariable\"}";
+    }
+
+    # If $language has been specified, load the appropriate resource bundle
+    # (Otherwise, the default resource bundle will be loaded automatically)
+    if ($language && $language =~ /\S/) {
+	&gsprintf::load_language_specific_resource_bundle($language);
+    }
+
+    if ($xml) {
+        &PrintUsage::print_xml_usage($options);
+	print "\n";
+	return;
+    }
+
+    if ($gli) { # the gli wants strings to be in UTF-8
+	&gsprintf::output_strings_in_UTF8; 
+    }
+
+    $textindex = "";
+    my $close_out = 0;
+    if ($out !~ /^(STDERR|STDOUT)$/i) {
+	open (OUT, ">$out") ||
+	    (&gsprintf(STDERR, "{common.cannot_open_output_file}\n", $out) && die);
+	$out = "buildcol::OUT";
+	$close_out = 1;
+    }
+    $out->autoflush(1);
+
+    # get and check the collection
+    if (($collection = &util::use_collection(@ARGV, $collectdir)) eq "") {
+	&PrintUsage::print_txt_usage($options, "{buildcol.params}");
+	die "\n";
+    }
+
+    if ($faillog eq "") {
+	$faillog = &util::filename_cat($ENV{'GSDLCOLLECTDIR'}, "etc", "fail.log");
+    }
+    # note that we're appending to the faillog here (import.pl clears it each time)
+    # this could potentially create a situation where the faillog keeps being added 
+    # to over multiple builds (if the import process is being skipped)
+    open (FAILLOG, ">>$faillog") ||
+	(&gsprintf(STDERR, "{common.cannot_open_fail_log}\n", $faillog) && die);
+    $faillog = 'buildcol::FAILLOG';
+    $faillog->autoflush(1);
+
+    unshift (@INC, "$ENV{'GSDLCOLLECTDIR'}/perllib");
+
+    # read the configuration file
+    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc", "collect.cfg");
+    my ($collectcfg, $buildtype); 
+
+    if (!-e $configfilename) {
+	&gsprintf($out, "{common.cannot_find_cfg_file}\n", $configfilename) && die;
+    }
+    
+    $collectcfg = &colcfg::read_collect_cfg ($configfilename);
+    
+    if ($verbosity !~ /\d+/) {
+	if (defined $collectcfg->{'verbosity'} && $collectcfg->{'verbosity'} =~ /\d+/) {
+	    $verbosity = $collectcfg->{'verbosity'};
+	} else {
+	    $verbosity = 2; # the default
+	}
+    }
+    # we use searchtype for determining buildtype, but for old versions, use buildtype
+    if (defined $collectcfg->{'buildtype'}) {
+	$buildtype = $collectcfg->{'buildtype'};
+    } elsif (defined $collectcfg->{'searchtypes'} || defined $collectcfg->{'searchtype'}) {
+	$buildtype = "mgpp";
+    } else {
+	$buildtype = "mg"; #mg is the default
+    }
+    if (defined $collectcfg->{'archivedir'} && $archivedir eq "") {
+	$archivedir = $collectcfg->{'archivedir'};
+    }
+    if (defined $collectcfg->{'cachedir'} && $cachedir eq "") {
+	$cachedir = $collectcfg->{'cachedir'};
+    }
+    if (defined $collectcfg->{'builddir'} && $builddir eq "") {
+	$builddir = $collectcfg->{'builddir'};
+    }
+    if ($maxdocs !~ /\-?\d+/) {
+	if (defined $collectcfg->{'maxdocs'} && $collectcfg->{'maxdocs'} =~ /\-?\d+/) {
+	    $maxdocs = $collectcfg->{'maxdocs'};
+	} else {
+	    $maxdocs = -1; # the default
+	}
+    }
+    if (defined $collectcfg->{'debug'} && $collectcfg->{'debug'} =~ /^true$/i) {
+	$debug = 1;
+    }
+    if ($mode !~ /^(all|compress_text|build_index|infodb)$/) {
+	if (defined $collectcfg->{'mode'} && $collectcfg->{'mode'} =~ /^(all|compress_text|build_index|infodb)$/) {
+	    $mode = $collectcfg->{'mode'};
+	} else {
+	    $mode = "all"; # the default
+	}
+    }
+    if (defined $collectcfg->{'index'} && $indexname eq "") {
+	$indexname = $collectcfg->{'index'};
+    }
+    if (defined $collectcfg->{'no_text'} && $no_text == 0) {
+	if ($collectcfg->{'no_text'} =~ /^true$/i) {
+	    $no_text = 1;
+	}
+    }
+    if (defined $collectcfg->{'no_strip_html'} && $no_strip_html == 0) {
+	if ($collectcfg->{'no_strip_html'} =~ /^true$/i) {
+	    $no_strip_html = 1;
+	}
+    }
+    if (defined $collectcfg->{'remove_empty_classifications'} && $remove_empty_classifications == 0) {
+	if ($collectcfg->{'remove_empty_classifications'} =~ /^true$/i) {
+	    $remove_empty_classifications = 1;
+	}
+    }
+    
+    if (defined $collectcfg->{'create_images'} && $collectcfg->{'create_images'} =~ /^true$/i) {
+	$create_images = 1;
+    }
+    if ($buildtype eq "mgpp" && defined $collectcfg->{'textcompress'}) {
+	$textindex = $collectcfg->{'textcompress'};
+    }
+    if (defined $collectcfg->{'gli'} && $collectcfg->{'gli'} =~ /^true$/i) {
+	$gli = 1;
+    }
+
+    if ($sections_index_document_metadata !~ /\S/ && defined $collectcfg->{'sections_index_document_metadata'}) {
+	$sections_index_document_metadata = $collectcfg->{'sections_index_document_metadata'};
+    }
+    
+    if ($sections_index_document_metadata !~ /^(never|always|unless_section_metadata_exists)$/) {
+	$sections_index_document_metadata = "never";
+    }
+    
+    ($removeold, $keepold) = &scriptutil::check_removeold_and_keepold($removeold, $keepold, "building", $collectcfg);
+ 
+    $gli = 0 unless defined $gli;
+
+    print STDERR "<Build>\n" if $gli;
+
+    #set the text index
+    if (($buildtype eq "mgpp") || ($buildtype eq "lucene")) {
+	if ($textindex eq "") {
+	    $textindex = "text";
+	}
+    }
+    else {
+	$textindex = "section:text";
+    }
+
+    # create default images if required
+    if ($create_images) {
+	my $collection_name = $collection;
+	$collection_name = $collectcfg->{'collectionmeta'}->{'collectionname'}->{'default'}
+	if defined $collectcfg->{'collectionmeta'}->{'collectionname'}->{'default'};
+	&create_images ($collection_name);
+    }
+
+    # fill in the default archives and building directories if none
+    # were supplied, turn all \ into / and remove trailing /
+
+    my ($realarchivedir, $realbuilddir);  
+    $archivedir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "archives") if $archivedir eq "";
+    $archivedir =~ s/[\\\/]+/\//g;
+    $archivedir =~ s/\/$//;
+    $builddir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "building") if $builddir eq "";
+    $builddir =~ s/[\\\/]+/\//g;
+    $builddir =~ s/\/$//;
+
+    # update the archive cache if needed
+    if ($cachedir) {
+	&gsprintf($out, "{buildcol.updating_archive_cache}\n")
+	    if ($verbosity >= 1);
+
+	$cachedir =~ s/[\\\/]+$//;
+	$cachedir .= "/collect/$collection" unless 
+	    $cachedir =~ /collect\/$collection/;
+
+	$realarchivedir = "$cachedir/archives";
+	$realbuilddir = "$cachedir/building";
+	&util::mk_all_dir ($realarchivedir);
+	&util::mk_all_dir ($realbuilddir);
+	&util::cachedir ($archivedir, $realarchivedir, $verbosity);
+
+    } else {
+	$realarchivedir = $archivedir;
+	$realbuilddir = $builddir;
+    }
+
+    # build it in realbuilddir
+    &util::mk_all_dir ($realbuilddir);
+
+    my ($buildertype, $builderdir,  $builder);
+    # if a builder class has been created for this collection, use it
+    # otherwise, use the mg or mgpp builder
+    if (-e "$ENV{'GSDLCOLLECTDIR'}/perllib/${collection}builder.pm") {
+	$builderdir = "$ENV{'GSDLCOLLECTDIR'}/perllib";
+	$buildertype = "${collection}builder";
+    } else {
+	$builderdir = "$ENV{'GSDLHOME'}/perllib";
+	if ($buildtype eq "lucene") {
+	    $buildertype = "lucenebuilder";
+	}
+	elsif ($buildtype eq "mgpp") {
+	    $buildertype = "mgppbuilder";
+	}
+	else {
+	    $buildertype = "mgbuilder";
+	}
+    }
+	
+    require "$builderdir/$buildertype.pm";
+
+    eval("\$builder = new $buildertype(\$collection, " .
+	 "\$realarchivedir, \$realbuilddir, \$verbosity, " .
+	 "\$maxdocs, \$debug, \$keepold, \$remove_empty_classifications, " .
+	 "\$out, \$no_text, \$faillog, \$gli)");
+    die "$@" if $@;
+
+    $builder->init();
+
+    if (($buildertype eq "mgppbuilder") && $no_strip_html) {
+	$builder->set_strip_html(0);
+    }
+    if ($sections_index_document_metadata ne "never") {
+	$builder->set_sections_index_document_metadata($sections_index_document_metadata);
+    }
+
+    if ($mode =~ /^all$/i) {
+	$builder->compress_text($textindex);
+	$builder->build_indexes($indexname);
+	$builder->make_infodatabase();
+	$builder->collect_specific();
+    } elsif ($mode =~ /^compress_text$/i) {
+	$builder->compress_text($textindex);
+    } elsif ($mode =~ /^build_index$/i) {
+	$builder->build_indexes($indexname);	
+    } elsif ($mode =~ /^infodb$/i) {
+	$builder->make_infodatabase();
+    } else {
+	(&gsprintf(STDERR, "{buildcol.unknown_mode}\n", $mode) && die);
+    }
+
+    $builder->make_auxiliary_files() if !$debug;
+    $builder->deinit();
+    
+    if (($realbuilddir ne $builddir) && !$debug) {
+	&gsprintf($out, "{buildcol.copying_back_cached_build}\n")
+	    if ($verbosity >= 1);
+	&util::rm_r ($builddir);
+	&util::cp_r ($realbuilddir, $builddir);
+    }
+
+    close OUT if $close_out;
+    close FAILLOG;
+
+    print STDERR "</Build>\n" if $gli;
+}
+
+sub create_images {
+    my ($collection_name) = @_;
+
+    my $image_script = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "script", "gimp", "title_icon-1.2.pl");
+    if (!-e $image_script) {
+	&gsprintf($out, "{buildcol.no_image_script}", $image_script);
+	&gsprintf($out, "{buildcol.no_default_images}\n\n");
+	return;
+    }
+
+    my $imagedir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "images");
+
+    &util::mk_all_dir ($imagedir);
+
+    # create the images
+    system ("$image_script -size 1.5 -image_dir \"$imagedir\" -filename $collection.gif -text \"$collection_name\"");
+    system ("$image_script -image_dir \"$imagedir\" -filename ${collection}sm.gif -text \"$collection_name\"");
+
+    # update the collect.cfg configuration file (this will need
+    # to be changed when the config file format changes)
+    if (!open (CFGFILE, $configfilename)) {
+	&gsprintf($out, "{buildcol.cannot_open_cfg_file}\n", $configfilename);
+	&gsprintf($out, "{buildcol.unlinked_col_images}\n");
+	return;
+    }
+
+    my $line = ""; my $file = "";
+    my $found = 0; my $foundsm = 0;
+    while (defined ($line = <CFGFILE>)) {
+	if ($line =~ /collectionmeta\s+iconcollection\s+/) {
+	    $line = "collectionmeta iconcollection _httpprefix_/collect/$collection/images/$collection.gif\n";
+	    $found = 1;
+	} elsif ($line =~ /collectionmeta\s+iconcollectionsmall\s+/) {
+	    $line = "collectionmeta iconcollectionsmall _httpprefix_/collect/$collection/images/${collection}sm.gif\n";
+	    $foundsm = 1;
+	}
+	$file .= $line;
+    }
+    close CFGFILE;
+
+    $file .= "collectionmeta iconcollection _httpprefix_/collect/$collection/images/$collection.gif\n" if !$found;
+    $file .= "collectionmeta iconcollectionsmall _httpprefix_/collect/$collection/images/${collection}sm.gif\n" if !$foundsm;
+
+    if (!open (CFGFILE, ">$configfilename")) {
+	&gsprintf($out, "{buildcol.cannot_open_cfg_file}\n", $configfilename);
+	&gsprintf($out, "{buildcol.unlinked_col_images}\n");
+	return;
+    }
+    print CFGFILE $file;
+    close CFGFILE;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/cancel_build.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/cancel_build.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/cancel_build.pl	(revision 10506)
@@ -0,0 +1,123 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# cancel_build.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 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.
+#
+###########################################################################
+
+
+# This program will create a .kill file within the GSDLCOLLECTDIR/collect-name
+# directory which will cause any import.pl or buildcol.pl processes running
+# on that collection to abort.
+# It then cleans any mess left laying around the collection (including the
+# import directory !!).
+# cancel_build.pl is really only intended to be called from within the 
+# library's collectoraction and isn't much use for anything else. As such it
+# should be rewritten in C++ one day and included in the collectoraction 
+# itself.
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use util;
+use parsargv;
+use File::Copy;
+
+sub print_usage {
+    print STDERR "\n";
+    print STDERR "cancel_build.pl: Cancel a build in progress. This script is\n";
+    print STDERR "                 called from the collector and is not intended\n";
+    print STDERR "                 for general use.\n\n";
+    print STDERR "  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -collectdir directory  Collection directory (defaults to " .
+	&util::filename_cat ($ENV{'GSDLHOME'}, "collect") . ")\n\n";
+}
+
+&main();
+
+sub main {
+    if (!parsargv::parse(\@ARGV, 'collectdir/.*/', \$collectdir)) {
+	&print_usage();
+	die "\n";
+    }
+
+    my $collection = pop @ARGV;
+    if (!defined $collection || $collection !~ /\w/) {
+	print STDERR "no collection specified\n";
+	&print_usage();
+	die "\n";
+    }
+
+    my $cdir = &util::filename_cat ($collectdir, $collection);
+    if ($collectdir eq "") {
+	$collectdir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect");
+	$cdir = &util::filename_cat ($collectdir, $collection);
+    } elsif (!-d $cdir) {
+	$cdir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect", $collection);
+    }
+
+    if (! -d $cdir) {
+	print STDERR "Collection does not exist ($cdir)\n";
+	exit (1);
+    }
+
+    # create .kill file
+    my $killfile = &util::filename_cat ($cdir, ".kill");
+    if (!open (KILLFILE, ">$killfile")) {
+	print STDERR "Couldn't create .kill file ($killfile)\n";
+	exit (1);
+    }
+    print KILLFILE "kill $collection\n";
+    close KILLFILE;
+
+    sleep (2); # just give it a chance to die gracefully;
+
+    # remove archives, building, and import directories
+    &util::rm_r (&util::filename_cat ($cdir, "import"));
+    &util::rm_r (&util::filename_cat ($cdir, "building"));
+    &util::rm_r (&util::filename_cat ($cdir, "archives"));
+
+    # remove any other temporary files that may have been left laying around
+    # by the build
+    my $buildfile = &util::filename_cat ($collectdir, ".build");
+    &util::rm ($buildfile) if -e $buildfile;
+    my $bldfile = &util::filename_cat ($collectdir, "$collection.bld");
+    &util::rm ($bldfile) if -e $bldfile;
+    my $bldfile_d = &util::filename_cat ($collectdir, "$collection.bld.download");
+    &util::rm ($bldfile_d) if -e $bldfile_d;
+    my $bldfile_i = &util::filename_cat ($collectdir, "$collection.bld.import");
+    &util::rm ($bldfile_i) if -e $bldfile_i;
+    my $bldfile_b = &util::filename_cat ($collectdir, "$collection.bld.build");
+    &util::rm ($bldfile_b) if -e $bldfile_b;
+    my $bldfile_f = &util::filename_cat ($collectdir, "$collection.bld.final");
+    &util::rm ($bldfile_f) if -e $bldfile_f;
+    
+    # if there's an archives.org directory, rename it back to archives
+    if (-d &util::filename_cat ($cdir, "archives.org")) {
+	&File::Copy::move (&util::filename_cat ($cdir, "archives.org"),
+			   &util::filename_cat ($cdir, "archives"));
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/classinfo.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/classinfo.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/classinfo.pl	(revision 10506)
@@ -0,0 +1,170 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# classinfo.pl -- provide information about classifiers
+#
+# 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.
+#
+###########################################################################
+
+use strict;
+no strict 'subs'; # allow barewords (eg STDERR) as function arguments
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use classify;
+use util;
+use gsprintf;
+use printusage;
+
+use parse2;
+
+my $arguments =
+    [ { 'name' => "collect",
+	'desc' => "{classinfo.collect}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "xml",
+	'desc' => "{scripts.xml}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "listall",
+	'desc' => "{scripts.listall}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "language",
+	'desc' => "{scripts.language}",
+	'type' => "string",
+	'reqd' => "no" } ];
+
+my $options = { 'name' => "classinfo.pl",
+		'desc' => "{classinfo.desc}",
+		'args' => $arguments };
+
+sub gsprintf
+{
+    return &gsprintf::gsprintf(@_);
+}
+
+sub main {
+    my $collect = "";
+    my $xml = 0;
+    my $listall = 0;
+    my $language;
+
+    my $hashParsingResult = {};
+    my $blnParseFailed = "false";
+    # general options available to all plugins
+    my $intArgLeftinAfterParsing = parse2::parse(\@ARGV,$arguments,$hashParsingResult,"allow_extra_options");
+    # If there are more than one argument left after parsing, it mean user input too many arguments.
+    # Error occoured  will return 0
+    if($intArgLeftinAfterParsing > 1)
+    {
+	&PrintUsage::print_txt_usage($options, "{classinfo.params}");
+	die "\n";
+    }
+
+    foreach my $strVariable (keys %$hashParsingResult)
+    {
+	eval "\$$strVariable = \$hashParsingResult->{\"\$strVariable\"}";
+    }
+    # If $language has been specified, load the appropriate resource bundle
+    # (Otherwise, the default resource bundle will be loaded automatically)
+    if ($language) {
+	&gsprintf::load_language_specific_resource_bundle($language);
+    }
+
+    # Get classifier
+    my $classifier = shift (@ARGV);
+    if (defined $classifier) {
+	$classifier =~ s/\.pm$//; # allow xxx.pm as the argument
+    }
+    if (($listall == 0) && (!defined $classifier || $classifier eq "")) {
+	&gsprintf(STDERR, "{classinfo.no_classifier_name}\n\n");
+	&PrintUsage::print_txt_usage($options, "{classinfo.params}", 1);
+	die "\n";
+    }
+
+    # make sure the classifier is loaded from the correct location - a hack.
+    if ($collect ne "") {
+	$ENV{'GSDLCOLLECTDIR'} = &util::filename_cat ($ENV{'GSDLHOME'}, "collect", $collect);
+    } else {
+	$ENV{'GSDLCOLLECTDIR'} = $ENV{'GSDLHOME'};
+    }
+ 
+    if ($listall) {
+	my $class_dir = &util::filename_cat($ENV{'GSDLCOLLECTDIR'},"perllib","classify");
+	
+	if (!opendir (INDIR, $class_dir)) {
+	    print STDERR "classinfo.pl: could not open directory $class_dir\n";
+	} else {
+	    my @class_list = grep (/\.pm$/, readdir (INDIR));
+	    closedir (INDIR);
+
+	    if ($xml) {
+		my $num_class = scalar(@class_list);
+
+		print STDERR "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+		print STDERR "<!DOCTYPE ClassifyList [\n";
+		print STDERR "  <!ELEMENT ClassifyList (ClassifyName*)>\n";
+		print STDERR "  <!ELEMENT ClassifyName (#PCDATA)>\n";
+		print STDERR "  <!ATTLIST ClassifyList\n";
+		print STDERR "            length CDATA #REQUIRED>\n";
+		print STDERR "]>\n";
+
+		print STDERR "<ClassifyList length=\"$num_class\">\n";
+		map { print STDERR "  <ClassifyName>$_</ClassifyName>\n"; } @class_list;
+		print STDERR "</ClassifyList>\n";
+
+	    }
+	    else {
+		print STDERR join(" ",@class_list), "\n";
+	    }
+	}
+
+    }
+    else {
+	my $classobj = &classify::load_classifier_for_info ($classifier);
+	if ($xml) {
+	    $classobj->print_xml_usage();
+	}
+	else {
+	    &gsprintf(STDERR, "\n{classinfo.passing_options}\n\n");
+	    &gsprintf(STDERR, "{classinfo.option_types}:\n\n");
+	    &gsprintf(STDERR, "{classinfo.specific_options}\n\n");
+	    &gsprintf(STDERR, "{classinfo.general_options}\n\n");
+	    &gsprintf(STDERR, "$classifier {classinfo.info}:\n\n");
+	    
+	    $classobj->print_txt_usage();
+	}
+    }
+}
+
+
+&main ();
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/cleantmp.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/cleantmp.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/cleantmp.pl	(revision 10506)
@@ -0,0 +1,80 @@
+#!/usr/bin/perl
+
+###########################################################################
+#
+# cleantmp.pl
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# cleantmp.pl cleans up the gsdl/tmp directory
+# it's intended mainly for use by the collectoraction
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use util;
+
+sub print_usage {
+    print STDERR "\n";
+    print STDERR "cleantmp.pl: Cleans up the Greenstone tmp directory by deleting anything\n";
+    print STDERR "             more than -expire_days days old.\n\n";
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -expire_days number   The number of days old information in the tmp\n";
+    print STDERR "                         directory must be before it is removed (defaults\n";
+    print STDERR "                         to 7 days)\n\n";
+}
+
+&main ();
+
+sub main {
+    
+    if (!parsargv::parse(\@ARGV, 'expire_days/\d/7', \$expire_days)) {
+	&print_usage();
+	die "\n";
+    }
+
+    my $current_time = time;
+    my $expire_time = ($current_time - ($expire_days*60*60*24));
+
+    my $tmpdir = &util::filename_cat ($ENV{'GSDLHOME'}, "tmp");
+
+    opendir (TMP, $tmpdir) || die "cleantmp.pl: couldn't open $tmpdir\n";
+    my @files = readdir TMP;
+    closedir TMP;
+
+    foreach $file (@files) {
+	next if ($file =~ /^\.\.$/);
+
+	if ($file =~ /^tbuild/) {
+	    my $thisfile = &util::filename_cat ($tmpdir, $file);
+	    my @stats = stat ($thisfile);
+	    if ($stats[9] < $expire_time) {
+		&util::rm_r ($thisfile);
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/convert_collection.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/convert_collection.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/convert_collection.pl	(revision 10506)
@@ -0,0 +1,112 @@
+#! /usr/bin/perl -w
+
+# converts an old style humanity collection which uses an index.txt file to
+# use a single metadata.xml file instead
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use util;
+use cfgread;
+
+my $collection = $ARGV[0];
+my $collectdir = &util::filename_cat($ENV{'GSDLHOME'}, "collect", $collection);
+my $importdir = &util::filename_cat($collectdir, "import");
+
+die unless -d $importdir;
+
+# new import structure will be created in "import.new" directory
+my $importnewdir = $importdir . ".new";
+`mkdir $importnewdir`;
+
+
+# read in index.txt file and generate metadata.xml, in the process
+# converting the html files and copying them across to the import.new
+# directory
+
+my $metadata_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
+$metadata_xml .= "<!DOCTYPE DirectoryMetadata SYSTEM " .
+    "\"http://greenstone.org/dtd/DirectoryMetadata/1.0/DirectoryMetadata.dtd\">\n";
+$metadata_xml .= "<DirectoryMetadata>\n\n";
+
+my $index_txt = &util::filename_cat($importdir, "index.txt");
+
+open (INDEXTXT, $index_txt) || die;
+
+my $line = [];
+my @fields = ();
+my $count = 0;
+while (defined ($line = cfgread::read_cfg_line("main::INDEXTXT"))) {
+
+#    last if $count > 10;
+
+    if ($line->[0] eq "key:") {
+	shift @$line;
+	@fields = @$line;
+    } else {
+	
+	my $jobnumber = shift @$line;
+	&new_document($jobnumber);
+	$count ++;
+
+	my $i = 0;
+	for ($i = 0; $i < scalar(@$line); $i++) {
+	    if ($line->[$i] =~ /^<([^>]+)>(.*)$/) {
+		&set_metadata($1, $2);
+	    } else {
+		if (defined ($fields[$i])) {
+		    &set_metadata($fields[$i], $line->[$i]);
+		} else {
+		    print STDERR "error 1\n";
+		}
+	    }
+	}
+
+	$metadata_xml .= "    </Description>\n";
+	$metadata_xml .= "  </FileSet>\n\n";
+    }
+}
+close INDEXTXT;
+
+$metadata_xml .= "</DirectoryMetadata>\n";
+
+my $metafile = &util::filename_cat($importnewdir, "metadata.xml");
+open (META, ">$metafile") || die;
+print META $metadata_xml;
+close META;
+
+
+sub new_document {
+    my ($jobnumber) = @_;
+
+    print STDERR "creating new document ($jobnumber)\n";
+
+    my $docdir = &util::filename_cat($importdir, $jobnumber);
+    die unless -d $docdir;
+
+    # copy whole directory across to import.new
+    $jobnumber =~ s/^.*?\///;
+    my $newdocdir = &util::filename_cat($importnewdir, $jobnumber);
+    die if -e $newdocdir;
+    `cp -r $docdir $newdocdir`;
+
+    # convert the htm file to use the new syntax
+    my $htmfile = &util::filename_cat($newdocdir, "$jobnumber.htm");
+    die unless -e $htmfile;
+    `convert_toc.pl < $htmfile > $htmfile.new`;
+    `mv $htmfile.new $htmfile`;
+
+    # update metadata.xml
+    $metadata_xml .= "  <FileSet>\n";
+    $metadata_xml .= "    <FileName>$jobnumber</FileName>\n";
+    $metadata_xml .= "    <Description>\n";
+}
+
+sub set_metadata {
+    my ($key, $value) = @_;
+
+    $metadata_xml .= "      <Metadata name=\"$key\" mode=\"accumulate\">$value</Metadata>\n";
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/convert_toc.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/convert_toc.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/convert_toc.pl	(revision 10506)
@@ -0,0 +1,124 @@
+#! /usr/bin/perl -w
+
+# convert_toc.pl converts old <<TOC>> marked up files to use the new
+# <Section> syntax (suitable for processing by HTMLPlug -description_tags
+
+use File::Basename;
+
+my $level = 0;
+
+sub main {
+  open STDIN, "<$ARGV[0]" or die "$ARGV[0]: $!\n";
+  open STDOUT, ">$ARGV[1]" or die "$ARGV[1]: $!\n";
+
+  my $dirname = &File::Basename::dirname($ARGV[0]);
+
+  my $content = "";
+  
+  while (<STDIN>) {
+    $_ =~ s/[\cJ\cM]+$/\n/;
+    $content .= $_;
+  }
+
+  # fix images
+  $content =~ s/&lt;&lt;I&gt;&gt;\s*(\w+\.(?:png|jpe?g|gif))\s*(.*?)<\/p>/rename_image_old($1, $2, $dirname)/iegs;
+  $content =~ s/<img\s+src=\"?(\w+\.(?:png|jpe?g|gif))\"?/rename_image($1, $dirname)/iegs;
+
+  # process section title
+  $content =~ s/(?:<P[^>]*>|<BR>)(?:\s*<\/?[^>]*>)*?&lt;&lt;TOC(\d+)&gt;&gt;(.*?)(?=<\/?P[^>]*>|<BR>)/
+      process_toc ($1, $2)/sige;
+
+  # close the remaining sections
+  my $section_ending = "<!--\n";
+  for (my $j = 0; $j < $level; $j++) {
+    $section_ending .= "</Section>\n";
+  }
+  $section_ending .= "-->\n";
+  $content =~ s/(<\/body>)/$section_ending.$1/sie;
+
+  print STDOUT $content;
+  close STDOUT; close STDIN;
+}
+
+sub process_toc {
+  my ($thislevel, $title) = @_;
+  my $toc = '';
+ 
+  $title =~ s/<[^>]+>//sg;
+  $title =~ s/^\s+//s;
+  $title =~ s/\s+$//s;
+  $title =~ s/\n/ /sg;
+
+  $toc .= "\n<!--\n";
+
+  if ($thislevel <= $level) {
+    for (my $i = 0; $i < ($level-$thislevel+1); $i++) {
+	$toc .= "</Section>\n";
+    }
+  }
+
+  $toc .= "<Section>\n".
+	"  <Description>\n".
+	"    <Metadata name=\"Title\">$title</Metadata>\n".
+	"  </Description>\n".
+	"-->\n";
+
+  $level = $thislevel;
+
+  return $toc;
+}
+
+sub rename_image_old {
+    my ($image_name, $following_text, $dirname) = @_;
+
+    &rename_image($image_name, $dirname);
+
+    return "<center><img src=\"$image_name\"><br>$following_text<\/center><\/p>\n";
+}
+
+
+# may need to rename image files if case isn't consistent
+# (i.e. collections prepared on windows may have images named
+# AAA.GIF which are linked into the HTML as aaa.gif)
+sub rename_image {
+    my ($image_name, $dirname) = @_;
+
+
+    if (!-e "$dirname/$image_name") {
+
+	my ($pre, $ext) = $image_name =~ /^([^\.]+)\.(.*)$/;
+	my $image_name_uc = uc($image_name);
+	my $image_name_lc = lc($image_name);
+	my $image_name_ul = uc($pre) . "." . lc($ext);
+	my $image_name_lu = lc($pre) . "." . uc($ext);
+
+	if (-e "$dirname/$image_name_uc") {
+	    print STDERR "renaming $dirname/$image_name_uc --> $dirname/$image_name\n";
+	    rename ("$dirname/$image_name_uc", "$dirname/$image_name");
+
+	} elsif (-e "$dirname/$image_name_lc") {
+	    print STDERR "renaming $dirname/$image_name_lc --> $dirname/$image_name\n";
+	    rename ("$dirname/$image_name_lc", "$dirname/$image_name");
+	
+	} elsif (-e "$dirname/$image_name_ul") {
+	    print STDERR "renaming $dirname/$image_name_ul --> $dirname/$image_name\n";
+	    rename ("$dirname/$image_name_ul", "$dirname/$image_name");
+	
+	} elsif (-e "$dirname/$image_name_lu") {
+	    print STDERR "renaming $dirname/$image_name_lu --> $dirname/$image_name\n";
+	    rename ("$dirname/$image_name_lu", "$dirname/$image_name");
+	
+	} else {
+	    print STDERR "ERROR**** $dirname/$image_name could not be found\n";
+	    if (open (ERROR, ">>error.txt")) {
+		print ERROR "ERROR**** $dirname/$image_name could not be found\n";
+		close ERROR;
+	    }
+	}
+    }
+    return "<img src=\"$image_name\"";
+}
+
+
+
+&main;
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/convert_toc_dir.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/convert_toc_dir.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/convert_toc_dir.pl	(revision 10506)
@@ -0,0 +1,41 @@
+#! /usr/bin/perl -w
+
+# run convert_toc.pl on any html files found in the directory passed in on
+# the command line (or any subdirs).
+
+die "\$GSDLOS not set !\n" if (!defined $ENV{GSDLOS});
+my ($move, $separator);
+if ($ENV{GSDLOS} eq "windows") {
+  $move = "move";
+  $separator = "\\";
+} else {
+  $move = "mv";
+  $separator = "/";
+}
+
+&recurse($ARGV[0]);
+
+sub recurse {
+    my ($dir) = @_;
+
+    if (!-d $dir) {
+	print STDERR "ERROR: $dir isn't a directory\n";
+	return;
+    }
+
+    opendir (DIR, $dir) || die;
+    my @files = readdir DIR;
+    closedir DIR;
+
+    foreach my $file (@files) {
+	next if $file =~ /^\.\.?$/;
+	my $fullpath = "$dir$separator$file";
+	if (-d $fullpath) {
+	    &recurse($fullpath);
+	} elsif ($file =~ /\.html?$/i) {
+	    print STDERR "converting $fullpath\n";
+	    `convert_toc.pl $fullpath $fullpath.new`;
+	    `$move $fullpath.new $fullpath`;
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/delcol.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/delcol.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/delcol.pl	(revision 10506)
@@ -0,0 +1,87 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# delcol.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use util;
+use parsargv;
+
+sub print_usage {
+    print STDERR "\n";
+    print STDERR "delcol.pl: Deletes (forever) a collection.\n\n";
+    print STDERR "  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -f                     Force deletion of collection without prompting\n\n";
+}
+
+&main();
+
+sub main {
+    my $force = 0;
+    if (!parsargv::parse(\@ARGV, 'f', \$force)) {
+	&print_usage();
+	die "\n";
+    }
+
+    # get and check the collection name
+    if (($collection = &util::use_collection(@ARGV)) eq "") {
+	&print_usage();
+	exit (1);
+    }
+
+    if (!$force) {
+	print STDOUT "Are you sure you want to completely remove the $collection collection?\n";
+	print STDOUT "(the $ENV{'GSDLCOLLECTDIR'} directory will be deleted). [y/n]\n";
+	my $in = <STDIN>;
+	if ($in !~ /^y(es)?$/i) {
+	    print STDOUT "Deletion of $collection collection cancelled\n";
+	    exit (0);
+	}
+    }
+    # delete any temporary files that are laying around
+    my $tmpdir = &util::filename_cat ($ENV{'GSDLHOME'}, "tmp");
+    if (opendir (TMPDIR, $tmpdir)) {
+	my @tmpfiles = readdir (TMPDIR);
+	closedir TMPDIR;
+	map { &util::rm(&util::filename_cat($tmpdir, $_)) if $_ =~ /^$collection/; } @tmpfiles;
+    }
+
+    &util::rm_r ($ENV{'GSDLCOLLECTDIR'});
+
+    # check if everything was deleted successfully
+    if (-d $ENV{'GSDLCOLLECTDIR'}) {
+	print STDERR "\ndelcol.pl WARNING: Not all files in $ENV{'GSDLCOLLECTDIR'} could\n";
+	print STDERR "be deleted\n";
+	exit (2);
+    }
+
+    print STDERR "$collection collection successfully deleted\n";
+    exit (0);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/explode_metadata_database.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/explode_metadata_database.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/explode_metadata_database.pl	(revision 10506)
@@ -0,0 +1,351 @@
+#!/usr/bin/perl
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+}
+
+use strict;
+no strict 'subs'; # allow barewords (eg STDERR) as function arguments
+no strict 'refs'; # allow filehandles to be variables and vice versa
+use printusage;
+use parse2;
+
+my $unicode_list =
+    [ { 'name' => "auto",
+	'desc' => "{BasPlug.input_encoding.auto}" },
+      { 'name' => "ascii",
+	'desc' => "{BasPlug.input_encoding.ascii}" },
+      { 'name' => "utf8",
+	'desc' => "{BasPlug.input_encoding.utf8}" },
+      { 'name' => "unicode",
+	'desc' => "{BasPlug.input_encoding.unicode}" } ];
+
+my $arguments = 
+    [ 
+      { 'name' => "language",
+	'desc' => "{scripts.language}",
+	'type' => "string",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "plugin",
+	'desc' => "{explode.plugin}",
+	'type' => "string",
+	'reqd' => "yes",
+	'hiddengli' => "yes"},
+      { 'name' => "input_encoding",
+	'desc' => "{explode.encoding}",
+	'type' => "enum",
+	'deft' => "auto",
+	'list' => $unicode_list,
+	'reqd' => "no" },
+      { 'name' => "metadata_set",
+	'desc' => "{explode.metadata_set}",
+	'type' => "string",
+	'reqd' => "no",
+	'hiddengli' => "yes"},
+      { 'name' => "document_field",
+	'desc' => "{explode.document_field}",
+	'type' => "string",
+	'reqd' => "no"},
+       { 'name' => "document_prefix",
+	'desc' => "{explode.document_prefix}",
+	'type' => "string",
+	'reqd' => "no"},
+      { 'name' => "document_suffix",
+	'desc' => "{explode.document_suffix}",
+	'type' => "string",
+	'reqd' => "no"},
+      { 'name' => "filename_field",
+	'desc' => "{explode.filename_field}",
+	'type' => "string",
+	'reqd' => "no"},
+      { 'name' => "verbosity",
+	'desc' => "{import.verbosity}",
+	'type' => "int",
+	'range' => "0,",
+	'deft' => "1",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "xml",
+	'desc' => "",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" }
+      ];
+	
+my $options = { 'name' => "explode_metadata_database.pl",
+		'desc' => "{explode.desc}",
+		'args' => $arguments };
+
+	    
+sub main
+{
+    my ($language, $input_encoding, $metadata_set, $plugin, $filename_field, 
+	$document_field, $document_prefix, $document_suffix, $verbosity);
+
+    my $xml = 0;
+
+    my $hashParsingResult = {};
+    my $blnParseFailed = "false";
+    # parse the options
+    my $intArgLeftinAfterParsing = parse2::parse(\@ARGV,$arguments,$hashParsingResult,"allow_extra_options");
+
+    foreach my $strVariable (keys %$hashParsingResult)
+    {
+	eval "\$$strVariable = \$hashParsingResult->{\"\$strVariable\"}";
+    }
+
+    # If $language has been specified, load the appropriate resource bundle
+    # (Otherwise, the default resource bundle will be loaded automatically)
+    if ($language && $language =~ /\S/) {
+	&gsprintf::load_language_specific_resource_bundle($language);
+    }
+
+    if ($xml) {
+        &PrintUsage::print_xml_usage($options);
+	print "\n";
+	return;
+    }
+
+    # There should one arg left after parsing
+    if($intArgLeftinAfterParsing > 1)
+    {
+	&PrintUsage::print_txt_usage($options, "{explode.params}");
+	die "\n";
+    }
+
+    # The metadata database filename is the first value that remains after the options have been parsed out
+    my $filename = $ARGV[0];
+    if (!defined $filename || $filename !~ /\w/) { 
+	&PrintUsage::print_txt_usage($options, "{explode.params}");
+	print STDERR "You need to specify a filename";
+	die "\n";
+    }
+    # check that file exists
+    if (!-e $filename) {
+	print STDERR "File $filename doesn't exist...\n";
+	die "\n";
+    }
+    # check required options
+    if (!defined $plugin || $plugin !~ /\w/) {
+	&PrintUsage::print_txt_usage($options, "{explode.params}");
+	print STDERR "You need to specify a plugin";
+	die "\n";
+    }
+    
+    # check metadata set
+    if (defined $metadata_set && $metadata_set =~ /\w/) {
+	$metadata_set .= ".";
+    } else {
+	$metadata_set = "";
+    }
+
+    #check filename field
+    if (defined $filename_field && $filename_field eq "") {
+	undef $filename_field;
+    }
+    my $plugobj;
+    require "$plugin.pm";
+    eval ("\$plugobj = new $plugin()");
+    die "$@" if $@;
+
+    # ...and initialize it
+    $plugobj->init(1, "STDERR", "STDERR");
+    
+    if ($input_encoding eq "auto") {
+	$plugobj->{'input_encoding'} = $input_encoding;   
+	($language, $input_encoding) = $plugobj->textcat_get_language_encoding ($filename);
+    }
+    my $text = "";
+    # Use the plugin's read_file function to avoid duplicating code
+    $plugobj->read_file($filename, $input_encoding, undef, \$text);
+
+    # Create a directory to store the document files...
+    my ($documents_directory) = ($filename =~ /(.*)\.[^\.]+$/);
+    if (-d $documents_directory) {
+	die "Error: document directory $documents_directory already exists (bailing).\n";
+    }
+    &util::mk_dir($documents_directory);
+
+    # ...and a metadata.xml file for the document metadata (extracted from the database)
+    my $documents_metadata_xml_file = &util::filename_cat($documents_directory, "metadata.xml");
+    if (-e $documents_metadata_xml_file) {
+	die "Error: document metadata.xml file $documents_metadata_xml_file already exists (bailing).\n";
+    }
+
+    # Start the metadata.xml file
+    open(METADATA_XML_FILE, ">$documents_metadata_xml_file");
+    print METADATA_XML_FILE
+	"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" .
+	"<!DOCTYPE DirectoryMetadata SYSTEM \"http://greenstone.org/dtd/DirectoryMetadata/1.0/DirectoryMetadata.dtd\">\n" .
+	"<DirectoryMetadata>\n";
+
+    # Split the text into records, using the plugin's split_exp
+    my $split_exp = $plugobj->{'split_exp'};
+    my @metadata_records = split(/$split_exp/, $text);
+    print STDERR "Number of records: " . @metadata_records . "\n";
+
+    # Write the metadata from each record to the metadata.xml file
+    my $record_number = 0;
+    foreach my $record_text (@metadata_records) {
+	
+	# Use the plugin's process function to avoid duplicating code
+	my $doc_obj = new doc($filename, "nonindexed_doc");
+	$plugobj->process(\$record_text, undef, undef, $filename, undef, $doc_obj, 0);
+	# Get all the metadata assigned to this record
+	my $record_metadata = $doc_obj->get_all_metadata($doc_obj->get_top_section());
+	my $document_file;
+	
+	# try to get a doc to attach the metadata to
+	if (defined $document_field) {
+	    foreach my $pair (@$record_metadata) {
+		my ($field, $value) = (@$pair);
+		
+		# Does this metadata element specify a document to obtain?
+		if ($field eq $document_field) {
+		    my $document_file_full = $document_prefix . $value . $document_suffix;
+		    $document_file = &obtain_document($document_file_full, $documents_directory, $verbosity);
+		}
+	    }
+	}
+	# do we need to create a dummy doc??
+	if (not defined $document_file) {
+	    # try to get a file name
+	    if (defined $filename_field) {
+		
+		my $meta = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $filename_field);
+		if (defined $meta) {
+		    $meta =~ s/&\w{1,10};//g; # remove entities
+		    $document_file = "$meta.nul";
+		    my $num = 0;
+		    while (-e "$documents_directory/$document_file") {
+			$num++;
+			$document_file = "$meta$num.nul";
+		    }
+		} else {
+		    $record_number = $record_number + 1;
+		    $document_file = sprintf("%4.4d", $record_number) . ".nul";
+		}
+	    } else {
+		$record_number = $record_number + 1;
+		$document_file = sprintf("%4.4d", $record_number) . ".nul";
+	    }
+	    open(DUMMY_FILE, ">$documents_directory/$document_file");
+	    close(DUMMY_FILE);
+
+	}
+	
+
+	&write_metadata_xml_file_entry(METADATA_XML_FILE, $document_file, $record_metadata, $metadata_set);
+    }
+
+    # Finish and close the metadata.xml file
+    print METADATA_XML_FILE "\n</DirectoryMetadata>\n";
+    close(METADATA_XML_FILE);
+
+    # Explode means just that: the original file is deleted
+    &util::rm($filename);
+}
+
+
+sub write_metadata_xml_file_entry
+{
+    my $metadata_xml_file = shift(@_);
+    my $file_name = shift(@_);
+    my $record_metadata = shift(@_);
+    my $meta_prefix = shift(@_);
+    
+    # Make $file_name XML-safe
+    $file_name =~ s/</&lt;/g;
+    $file_name =~ s/>/&gt;/g;
+
+    # Convert $file_name into a regular expression that matches it
+    $file_name =~ s/\./\\\./g;
+    $file_name =~ s/\(/\\\(/g;
+    $file_name =~ s/\)/\\\)/g;
+    $file_name =~ s/\{/\\\{/g;
+    $file_name =~ s/\}/\\\}/g;
+    $file_name =~ s/\[/\\\[/g;
+    $file_name =~ s/\]/\\\]/g;
+    
+    print $metadata_xml_file
+	"\n" .
+        "  <FileSet>\n" .
+	"    <FileName>$file_name</FileName>\n" .
+	"    <Description>\n";
+
+    foreach my $pair (@$record_metadata) {
+	my ($field, $value) = (@$pair);
+
+	# We're only interested in metadata from the database
+	next if ($field eq "lastmodified");
+	next if ($field eq "gsdlsourcefilename");
+	next if ($field eq "gsdldoctype");
+	next if ($field eq "FileFormat");
+
+	# Ignore the ^all metadata, since it will be invalid if the source metadata is changed
+	next if ($field =~ /\^all$/);  # ISISPlug specific!
+
+	# Make $value XML-safe
+	$value =~ s/</&lt;/g;
+	$value =~ s/>/&gt;/g;
+
+	# we are not allowed & in xml except in entities. 
+	# if there are undefined entities then parsing will also crap out.
+	# should we be checking for them too?
+	# this may not get all possibilities
+	$value =~ s/&([^;\s]*(\s|$))/&amp;$1/g;
+
+	print $metadata_xml_file "      <Metadata mode=\"accumulate\" name=\"$meta_prefix$field\">$value</Metadata>\n";
+    }
+
+    print $metadata_xml_file
+	"    </Description>\n" .
+	    "  </FileSet>\n";
+}
+
+sub obtain_document
+{
+    my $document_file_full = shift(@_);
+    my $documents_directory = shift(@_);
+    my $verbosity = shift(@_);
+    
+    print STDERR "Obtaining document file $document_file_full...\n" if ($verbosity > 1);
+
+    my $document_file_name;
+    my $local_document_file;
+
+    # Document specified is on the web
+    if ($document_file_full =~ /^http:/ || $document_file_full =~ /^ftp:/) {
+	$document_file_full =~ /([^\/]+)$/;
+	$document_file_name = $1;
+	$local_document_file = &util::filename_cat($documents_directory, $document_file_name);
+
+	my $wget_options = "--quiet";
+	$wget_options = "--verbose" if ($verbosity > 2);
+	$wget_options .= " --timestamping";  # Only re-download files if they're newer
+	`wget $wget_options $document_file_full --output-document $local_document_file`;
+    }
+    # Document specified is on the disk
+    else {
+	my $dir_sep = &util::get_os_dirsep();
+	$document_file_full =~ /(.+$dir_sep)?(.*)$/;
+	$document_file_name = $2;
+	$local_document_file = &util::filename_cat($documents_directory, $document_file_name);
+
+	&util::cp($document_file_full, $documents_directory);
+    }
+
+    # Check the document was obtained successfully
+    if (!-e $local_document_file) {
+	print STDERR "WARNING: Could not obtain document file $document_file_full\n";
+	return undef;
+    }
+
+    return $document_file_name;
+}
+
+&main(@ARGV);
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/export.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/export.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/export.pl	(revision 10506)
@@ -0,0 +1,489 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# export.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This program will export a particular collection into a specific Format (e.g. METS or DSpace)
+# Author: Chi-Yu Huang Date: 08-10-2004
+
+package export;
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and vice versa
+no strict 'subs'; # allow barewords (eg STDERR) as function arguments
+
+use arcinfo;
+use colcfg;
+use plugin;
+use docprint;
+use util;
+use scriptutil;
+use FileHandle;
+use gsprintf;
+use printusage;
+use parse2;
+
+
+my $oidtype_list = 
+    [ { 'name' => "hash",
+        'desc' => "{export.OIDtype.hash}" },
+      { 'name' => "incremental",
+        'desc' => "{export.OIDtype.incremental}" } ];
+
+#** define to use the METS format or DSpace format
+my $saveas_list = 
+    [ { 'name' => "DSpace",
+        'desc' => "{export.saveas.DSpace}" },
+      { 'name' => "METS",
+        'desc' => "{export.saveas.METS}" } ];
+
+
+# Possible attributes for each argument
+# name: The name of the argument
+# desc: A description (or more likely a reference to a description) for this argument
+# type: The type of control used to represent the argument. Options include: string, int, flag, regexp, metadata, metadatum, language, enum etc
+# reqd: Is this argument required?
+# hiddengli: Is this argument hidden in GLI?
+# modegli: The lowest detail mode this argument is visible at in GLI
+
+my $saveas_argument =       
+      { 'name' => "saveas",
+	'desc' => "{export.saveas}",
+	'type' => "enum",
+	'list' => $saveas_list,
+	'deft' => "METS",
+	'reqd' => "no",
+	'modegli' => "3" };
+
+
+my $arguments = 
+    [ 
+      $saveas_argument,
+      { 'name' => "saveas_version",
+	'desc' => "{export.saveas_version}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "exportdir",
+	'desc' => "{export.exportdir}",
+	'type' => "string",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "importdir",
+	'desc' => "{import.importdir}",
+	'type' => "string",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "collectdir",
+	'desc' => "{export.collectdir}",
+	'type' => "string",
+	'deft' => &util::filename_cat ($ENV{'GSDLHOME'}, "collect"),
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "listall",
+	'desc' => "{scripts.listall}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "debug",
+	'desc' => "{export.debug}",
+	'type' => "flag",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "faillog",
+	'desc' => "{export.faillog}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no",
+        'modegli' => "4" },
+      { 'name' => "keepold",
+	'desc' => "{export.keepold}",
+	'type' => "flag",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "removeold",
+	'desc' => "{export.removeold}",
+	'type' => "flag",
+	'reqd' => "no",
+	'modegli' => "3" },
+      { 'name' => "language",
+	'desc' => "{scripts.language}",
+	'type' => "string",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "maxdocs",
+	'desc' => "{export.maxdocs}",
+	'type' => "int",
+	'reqd' => "no",
+	'range' => "1,",
+	'modegli' => "1" },
+      { 'name' => "out",
+	'desc' => "{export.out}",
+	'type' => "string",
+	'deft' => "STDERR",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "statsfile",
+	'desc' => "{export.statsfile}",
+	'type' => "string",
+	'deft' => "STDERR",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "verbosity",
+	'desc' => "{export.verbosity}",
+	'type' => "int",
+	'range' => "0,3",
+	'deft' => "2",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "gli",
+	'desc' => "",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" },
+      { 'name' => "xml",
+	'desc' => "{scripts.xml}",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" }
+      ];
+
+my $options = { 'name' => "export.pl",
+		'desc' => "{export.desc}",
+		'args' => $arguments };
+
+my $listall_options = { 'name' => "export.pl",
+		        'desc' => "{export.desc}",
+		        'args' => [ $saveas_argument ] };
+
+sub gsprintf
+{
+    return &gsprintf::gsprintf(@_);
+}
+
+
+&main();
+
+sub main {
+    # params
+    my ($language, $verbosity, $importdir, $exportdir, $keepold, $listall,
+	$removeold, $saveas, $saveas_version, $debug, 
+	$maxdocs, $statsfile, $out, $faillog, $collectdir, $gli);
+    my $xml = 0;
+    
+    # other vars
+    my ($configfilename, $collection, $export_info_filename, $export_info, $processor, $pluginfo);
+    my $service = "export";
+
+    my $hashParsingResult = {};
+    my $blnParseFailed = "false";
+    # general options available to all plugins
+    my $intArgLeftinAfterParsing = parse2::parse(\@ARGV,$arguments,$hashParsingResult,"allow_extra_options");
+    # can have more than one collection name, so don't check num args left    
+    foreach my $strVariable (keys %$hashParsingResult)
+    {
+	eval "\$$strVariable = \$hashParsingResult->{\"\$strVariable\"}";
+    }
+
+    
+    # these are options used by other things - we just set default values
+    # undef means will be set from config file if there
+    my $gzip = undef; 
+    my $groupsize = 1;
+    my $OIDtype = undef;
+    my $sortmeta = undef;
+
+    my $explicit_exportdir = (defined $exportdir) ? 1 : 0;
+
+    # save these command line settings. don't want config file settings in one
+    # coll used for other colls
+    # does this apply to other vars???
+    my $global_removeold = $removeold;
+    my $global_keepold = $keepold;
+    # If $language has been specified, load the appropriate resource bundle
+    # (Otherwise, the default resource bundle will be loaded automatically)
+    if ($language) {
+	&gsprintf::load_language_specific_resource_bundle($language);
+    }
+
+    if ($listall) {
+	if ($xml) {
+	    &PrintUsage::print_xml_usage($listall_options);
+	}
+	else
+	{
+	    &PrintUsage::print_txt_usage($listall_options,"{export.params}");
+	}
+	die "\n";
+    }
+    elsif ($xml) {
+        &PrintUsage::print_xml_usage($options);
+	die "\n";
+    }
+
+    if (scalar(@ARGV) == 0) {
+	&PrintUsage::print_txt_usage($options, "{export.params}");
+	die "\n";
+    }
+
+    if ($gli) { # the gli wants strings to be in UTF-8
+	&gsprintf::output_strings_in_UTF8; 
+    }
+    my $close_out = 0;
+    if ($out !~ /^(STDERR|STDOUT)$/i) {
+	open (OUT, ">$out") ||
+	    (&gsprintf(STDERR, "{common.cannot_open_output_file}\n", $out) && die);
+	$out = 'export::OUT';
+	$close_out = 1;
+    }
+    $out->autoflush(1);
+
+    while (scalar(@ARGV)>0) {
+	my $collect_name = shift @ARGV;
+	$ENV{'GSDLCOLLECTION'} = $collect_name;
+
+	eval {
+	    # get and check the collection name
+	    if (($collection = &util::use_collection($collect_name, $collectdir)) eq "") {
+		&PrintUsage::print_txt_usage($options, "{export.params}");
+		die "\n";
+	    }
+
+	    if ($faillog eq "") {
+		$faillog = &util::filename_cat($ENV{'GSDLCOLLECTDIR'}, "etc", "fail.log");
+	    }
+	    open (FAILLOG, ">$faillog") ||
+		(&gsprintf(STDERR, "{export.cannot_open_fail_log}\n", $faillog) && die);
+	    my $faillogname = $faillog;
+	    $faillog = 'export::FAILLOG';
+	    $faillog->autoflush(1);
+	    
+	    # check sortmeta
+	    $sortmeta = undef unless defined $sortmeta && $sortmeta =~ /\S/;
+	    if (defined $sortmeta && $groupsize > 1) {
+		&gsprintf($out, "{export.cannot_sort}\n\n");
+		$sortmeta = undef;
+	    }
+
+	    # dynamically load 'docsave' module so it can pick up on a collection
+	    # specific docsave.pm is specified.
+	    
+	    unshift (@INC, "$ENV{'GSDLCOLLECTDIR'}/perllib");
+	    require docsave;
+	    
+	    # get the list of plugins for this collection and set any options that
+	    # were specified in the collect.cfg (all export.pl options except
+	    # -collectdir, -out and -faillog may be specified in the collect.cfg (these
+	    # options must be known before we read the collect.cfg))
+	    my $plugins = [];
+	    my @global_opts = ();
+	    
+	    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc", "collect.cfg");
+	    if (!-e $configfilename) {
+		(&gsprintf($out, "{common.cannot_find_cfg_file}\n", $configfilename) && die);
+	    }
+	    
+	    my $collectcfg = &colcfg::read_collect_cfg ($configfilename);
+	    if (defined $collectcfg->{'plugin'}) {
+		$plugins = $collectcfg->{'plugin'};
+	    }
+	    
+	    if ($verbosity !~ /\d+/) {
+		if (defined $collectcfg->{'verbosity'} && $collectcfg->{'verbosity'} =~ /\d+/) {
+		    $verbosity = $collectcfg->{'verbosity'};
+		} else {
+		    $verbosity = 2; # the default
+		}
+	    }
+	    if (defined $collectcfg->{'importdir'} && $importdir eq "") {
+		$importdir = $collectcfg->{'importdir'};
+	    }
+	    if (defined $collectcfg->{'exportdir'} && $exportdir eq "") {
+		$exportdir = $collectcfg->{'exportdir'};
+	    }
+
+	    if (defined $collectcfg->{'gzip'} && !$gzip) {
+		if ($collectcfg->{'gzip'} =~ /^true$/i) {
+		    $gzip = 1;
+		}
+	    }
+	    if ($maxdocs !~ /\-?\d+/) {
+		if (defined $collectcfg->{'maxdocs'} && $collectcfg->{'maxdocs'} =~ /\-?\d+/) {
+		    $maxdocs = $collectcfg->{'maxdocs'};
+		} else {
+		    $maxdocs = -1; # the default
+		}
+	    }
+	    if ($groupsize == 1) {
+		if (defined $collectcfg->{'groupsize'} && $collectcfg->{'groupsize'} =~ /\d+/) {
+		    $groupsize = $collectcfg->{'groupsize'};
+		}
+	    }
+	    if (!defined $OIDtype || ($OIDtype !~ /^(hash|incremental)$/)) {
+		if (defined $collectcfg->{'OIDtype'} && $collectcfg->{'OIDtype'} =~ /^(hash|incremental)$/) {
+		    $OIDtype = $collectcfg->{'OIDtype'};
+		} else {
+		    $OIDtype = "hash"; # the default
+		}
+	    }
+	    if (defined $collectcfg->{'sortmeta'} && $sortmeta eq "") {
+		$sortmeta = $collectcfg->{'sortmeta'};
+	    }
+	    if (defined $collectcfg->{'debug'} && $collectcfg->{'debug'} =~ /^true$/i) {
+		$debug = 1;
+	    }
+	    if (defined $collectcfg->{'gli'} && $collectcfg->{'gli'} =~ /^true$/i) {
+		$gli = 1;
+	    }
+	    
+	    # global plugin stuff
+	    if (defined $collectcfg->{'separate_cjk'}&& $collectcfg->{'separate_cjk'} =~ /^true$/i) {
+		push @global_opts, "-separate_cjk";
+	    }
+	    
+	    ($removeold, $keepold) = &scriptutil::check_removeold_and_keepold($global_removeold, $global_keepold, "export", $collectcfg);
+
+	    $gli = 0 unless defined $gli;
+
+	    print STDERR "<export>\n" if $gli;
+	    
+	    # fill in the default import and export directories if none
+	    # were supplied, turn all \ into / and remove trailing /
+	    $importdir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "import") if $importdir eq "";
+	    $importdir =~ s/[\\\/]+/\//g;
+	    $importdir =~ s/\/$//;
+	    $exportdir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "export") if $exportdir eq "";
+	    $exportdir =~ s/[\\\/]+/\//g;
+	    $exportdir =~ s/\/$//;
+	    
+	    # load all the plugins
+	    $pluginfo = &plugin::load_plugins ($plugins, $verbosity, $out, $faillog, \@global_opts);
+	    
+	    if (scalar(@$pluginfo) == 0) {
+		&gsprintf($out, "{import.no_plugins_loaded}\n");
+		die "\n";
+	    }
+	    
+	    # remove the old contents of the export directory if needed
+	    if ($removeold && -e $exportdir) {
+		&gsprintf($out, "{export.removing_export}\n");
+		&util::rm_r ($exportdir);
+	    }
+	    
+	    # read the export information file
+	    if (!$debug) {
+		# Export to DSpace Arhive format or METs format
+		# If saveas=DSpace, a "contents" file will be created, otherwise "export.inf"
+		
+		if ($saveas eq "DSpace"){
+		    $export_info_filename = &util::filename_cat ($exportdir, "contents");
+		} elsif ($saveas eq "METS") {
+		    $export_info_filename = &util::filename_cat ($exportdir, "export.inf");
+		}
+		
+		$export_info = new arcinfo();
+		$export_info -> load_info ($export_info_filename);	
+		
+		$processor = new docsave ($collection, $export_info, $verbosity, $gzip, $groupsize, $out, $service, $saveas);
+		
+		$processor->setoutputdir ($exportdir);
+		
+		$processor->set_sortmeta ($sortmeta) if defined $sortmeta;
+		$processor->set_OIDtype ($OIDtype);
+		$processor->set_saveas ($saveas);
+		$processor->set_saveas_version ($saveas_version);
+	    } else {
+		$processor = new docprint ();
+	    }
+	    
+	    &plugin::begin($pluginfo, $importdir, $processor, $maxdocs);
+	    
+	    # process the import directory
+	    &plugin::read ($pluginfo, $importdir, "", {}, $processor, $maxdocs,0, $gli);
+	    
+	    &plugin::end($pluginfo, $processor);
+
+ 	    &plugin::deinit($pluginfo, $processor);
+	    
+	    # write out the export information file
+	    if (!$debug) {
+		$processor->close_file_output() if $groupsize > 1;
+		if ($saveas eq "METS") {
+		    $export_info->save_info($export_info_filename);
+		}
+	    }
+	    
+	    # write out export stats
+	    my $close_stats = 0;
+	    if ($statsfile !~ /^(STDERR|STDOUT)$/i) {
+		if (open (STATS, ">$statsfile")) {
+		    $statsfile = 'import::STATS';
+		    $close_stats = 1;
+		} else {
+		    &gsprintf($out, "{import.cannot_open_stats_file}", $statsfile);
+		    &gsprintf($out, "{import.stats_backup}\n");
+		    $statsfile = 'STDERR';
+		}
+	    }
+
+	    &gsprintf($out, "\n");
+	    &gsprintf($out, "*********************************************\n");
+
+	    &plugin::write_stats($pluginfo, $statsfile, $faillogname, $gli);
+	    if ($close_stats) {
+		close STATS;
+	    }
+
+	    &gsprintf($out, "*********************************************\n");
+
+	    close OUT if $close_out;
+
+	    close FAILLOG;
+	};
+
+	if ($@) {
+	    print STDERR $@;
+	}
+
+##	$ENV{'GSDLCOLLECTION'} = undef;
+	$importdir = "";
+	$removeold = 0 if ($explicit_exportdir);
+
+    } # while processing ARGV
+    
+    &gsprintf($out, "\n");
+    &gsprintf($out, "*********************************************\n");
+    &gsprintf($out, "* {export.complete}\n");
+    &gsprintf($out, "*********************************************\n");    
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/exportcol.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/exportcol.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/exportcol.pl	(revision 10506)
@@ -0,0 +1,372 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# exportcol.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and vice versa
+no strict 'subs'; # allow barewords (eg STDERR) as function arguments
+
+use util;
+use parse2;
+use printusage;
+
+my $arguments = 
+    [ { 'name' => "language",
+	'desc' => "{scripts.language}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "out",
+	'desc' => "{exportcol.out}",
+	'type' => "string",
+	'deft' => "STDERR",
+	'reqd' => "no" },
+      { 'name' => "nonetscape",
+	'desc' => "{exportcol.nonetscape}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "cdname",
+	'desc' => "{exportcol.cdname}",
+	'type' => "string",
+	'deft' => "Greenstone Collections",
+	'reqd' => "no" }, 
+      { 'name' => "cddir",
+	'desc' => "{exportcol.cddir}",
+	'type' => "string",
+	'deft' => "exported_collections",
+	'reqd' => "no" },
+      { 'name' => "xml",
+	'desc' => "{scripts.xml}",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" },
+      { 'name' => "gli",
+	'desc' => "",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" },
+
+      ];
+
+my $options = { 'name' => "exportcol.pl",
+		'desc' => "{exportcol.desc}",
+		'args' => $arguments };
+
+sub gsprintf
+{
+    return &gsprintf::gsprintf(@_);
+}
+
+
+&main();
+
+sub main {
+    my ($language, $out, $cdname, $cddir, $gli);
+
+    my $xml = 0;
+    my $nonetscape = 0;
+
+    my $hashParsingResult = {};
+    my $blnParseFailed = "false";
+    # parse options
+    my $intArgLeftinAfterParsing = parse2::parse(\@ARGV,$arguments,$hashParsingResult,"allow_extra_options");
+    # don't care how many args are left - can have multiple collection names
+    foreach my $strVariable (keys %$hashParsingResult)
+    {
+	eval "\$$strVariable = \$hashParsingResult->{\"\$strVariable\"}";
+    }
+    
+    # If $language has been specified, load the appropriate resource bundle
+    # (Otherwise, the default resource bundle will be loaded automatically)
+    if ($language && $language =~ /\S/) {
+	&gsprintf::load_language_specific_resource_bundle($language);
+    }
+    
+    if ($xml) {
+        &PrintUsage::print_xml_usage($options);
+	print "\n";
+	return;
+    }
+    
+    if ($gli) { # the gli wants strings to be in UTF-8
+	&gsprintf::output_strings_in_UTF8; 
+    }
+    
+    my $use_netscape = ($nonetscape) ? 0 : 1;
+
+    # If $language has been specified, load the appropriate resource bundle
+    # (Otherwise, the default resource bundle will be loaded automatically)
+    if ($language) {
+	&gsprintf::load_language_specific_resource_bundle($language);
+    }
+
+    if ($xml) {
+        &PrintUsage::print_xml_usage($options);
+	die "\n";
+    }
+
+    if ($gli) { # the gli wants strings to be in UTF-8
+	&gsprintf::output_strings_in_UTF8; 
+    }
+
+    my @coll_list = @ARGV;
+    
+    if (not @coll_list) { # empty list
+	&PrintUsage::print_txt_usage($options, "{exportcol.params}");
+	exit(1);
+    }
+
+    my $close_out = 0;
+    if ($out !~ /^(STDERR|STDOUT)$/i) {
+	open (OUT, ">$out") || 
+	    (&gsprintf(STDERR, "{common.cannot_open_output_file}\n", $out) && die);
+	$out = 'main::OUT';
+	$close_out = 1;
+    }
+
+    # first we do a quick check to see if the export coll function has been 
+    # installed
+    my $gssetupexe = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "windows", "gssetup.exe"); 
+    if (!-e $gssetupexe) {
+	&gsprintf($out, "{exportcol.fail} {exportcol.export_coll_not_installed}\n");
+	die "\n";
+    }
+
+    # check each collection
+    my @valid_coll_list = ();
+    foreach my $c (@coll_list) {
+	my $colldir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect", $c);
+	if (! -d $colldir) {
+	    &gsprintf($out, "{exportcol.coll_not_found}\n", $c, $colldir);
+	    next;
+	}
+	my $colindexdir = &util::filename_cat ($colldir, "index");
+	my $coletcdir = &util::filename_cat ($colldir, "etc");
+	if ((!-d $colindexdir) || (!-d $coletcdir)) {
+	    &gsprintf($out, "{exportcol.coll_dirs_not_found}\n", $c);
+	    &gsprintf($out, "  $colindexdir\n");
+	    &gsprintf($out, "  $coletcdir\n");
+	    next;
+	}
+	# the collection seems ok, we add it to the valid coll list
+	push @valid_coll_list, $c;
+    }
+
+    if (not @valid_coll_list) {
+	# no valid colls left
+	&gsprintf($out, "{exportcol.fail} {exportcol.no_valid_colls}\n");
+	die "\n";
+    }
+
+    # create exported directory
+    my $topdir = &util::filename_cat ($ENV{'GSDLHOME'}, "tmp", $cddir);
+    &util::mk_all_dir ($topdir);
+    if (!-d $topdir) {
+	&gsprintf($out, "{exportcol.fail} {exportcol.couldnt_create_dir}\n", $topdir);
+	die "\n";
+    }
+
+    # make other directories (we'll assume that if we created topdir
+    # successfully there'll be no problems creating these)
+    my $gsdldir = &util::filename_cat ($topdir, "gsdl");
+    &util::mk_all_dir ($gsdldir);
+    my $collectdir = &util::filename_cat ($gsdldir, "collect");
+    &util::mk_all_dir ($collectdir);
+    my $etcdir = &util::filename_cat ($gsdldir, "etc");
+    &util::mk_all_dir ($etcdir);
+    my $binjavadir = &util::filename_cat ($gsdldir, "bin", "java");
+    &util::mk_all_dir ($binjavadir);
+
+    # create the install.cfg file
+    my $installcfg = &util::filename_cat ($topdir, "install.cfg");
+    if (!open (INSTALLCFG, ">$installcfg")) {
+	&gsprintf($out, "{exportcol.fail} {exportcol.couldnt_create_file}\n", $installcfg);
+	die "\n";
+    }
+    print INSTALLCFG "CompanyName:New Zealand Digital Library\n";
+    print INSTALLCFG "CollectionName:$cdname\n";
+    print INSTALLCFG "CollectionDirName:$cdname\n";
+    print INSTALLCFG "CollectionVersion:1.0\n";
+    print INSTALLCFG "CollectionVolume:1\n";
+    print INSTALLCFG "ProgramGroupName:Greenstone\n";
+    close INSTALLCFG;
+
+    # create the manifest.cfg file
+    my $manifestcfg = &util::filename_cat ($topdir, "manifest.cfg");
+    if (!open (MANIFESTCFG, ">$manifestcfg")) {
+	&gsprintf($out, "{exportcol.fail} {exportcol.couldnt_create_file}\n", $manifestcfg);
+	die "\n";
+    }
+    print MANIFESTCFG "all:\n";
+    print MANIFESTCFG "  {library} {collection}\n\n";
+    print MANIFESTCFG "library:\n";
+    print MANIFESTCFG "  net32 net16 server.exe\n\n";
+    print MANIFESTCFG "database:\n";
+    print MANIFESTCFG '  etc ';
+    foreach my $c (@valid_coll_list) {
+	print MANIFESTCFG "collect\\$c\\index\\text\\$c.ldb ";
+    }
+    print MANIFESTCFG "\n\n";
+    print MANIFESTCFG "collection:\n";
+    print MANIFESTCFG "  collect etc images macros mappings bin\n";
+    close MANIFESTCFG;
+
+    #create the autorun.inf file
+    my $autoruninf = &util::filename_cat ($topdir, "Autorun.inf");
+    if (!open (AUTORUNINF, ">$autoruninf")) {
+	&gsprintf($out, "{exportcol.fail} {exportcol.couldnt_create_file}\n", $autoruninf);
+	die "\n";
+    }
+
+    print AUTORUNINF "[autorun]\n";
+    print AUTORUNINF "OPEN=Setup.exe\n";
+    close AUTORUNINF;
+
+    # copy the necessary stuff from GSDLHOME
+    my $imagesdir = &util::filename_cat ($ENV{'GSDLHOME'}, "images");
+    my $macrosdir = &util::filename_cat ($ENV{'GSDLHOME'}, "macros");
+    my $mappingsdir = &util::filename_cat ($ENV{'GSDLHOME'}, "mappings");
+    my $maincfg = &util::filename_cat ($ENV{'GSDLHOME'}, "etc", "main.cfg");
+    my $serverexe = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "windows", "server.exe");
+    #my $gssetupexe = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "windows", "gssetup.exe"); - have checked this earlier
+    my $setupexe = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "windows", "Setup.exe");
+    my $net32dir = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "windows", "net32");
+    my $net16dir = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "windows", "net16");
+    my $netscapedir = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "windows", "netscape");
+    my $win32sdir = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "windows", "Win32s");
+    my $phindjar = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "java", "Phind.jar");
+    my $gsdlcollageappletjar = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", "java", "GsdlCollageApplet.jar");
+
+    if ((!-d $imagesdir) || (!-d $macrosdir) || (!-d $mappingsdir) || (!-e $maincfg) ||
+	(!-e $serverexe) || (!-e $gssetupexe) || (!-e $setupexe) || (!-d $net32dir) ||
+	(!-d $net16dir) || ($use_netscape && (!-d $netscapedir)) || (!-d $win32sdir) || (!-e $phindjar) ||
+	(!-e $gsdlcollageappletjar)) {
+	&gsprintf($out, "{exportcol.fail} {exportcol.non_exist_files}\n");
+	&gsprintf($out, "  $imagesdir\n");
+	&gsprintf($out, "  $macrosdir\n");
+	&gsprintf($out, "  $mappingsdir\n");
+	&gsprintf($out, "  $maincfg\n");
+	&gsprintf($out, "  $serverexe\n");
+	&gsprintf($out, "  $gssetupexe\n");
+	&gsprintf($out, "  $setupexe\n");
+	&gsprintf($out, "  $net32dir\n");
+	&gsprintf($out, "  $net16dir\n");
+	&gsprintf($out, "  $netscapedir\n") if ($use_netscape);
+	&gsprintf($out, "  $win32sdir\n");
+	&gsprintf($out, "  $phindjar\n");
+	&gsprintf($out, "  $gsdlcollageappletjar\n");
+	die "\n";
+    }
+
+    &util::cp_r ($imagesdir, $gsdldir);
+    &util::cp_r ($macrosdir, $gsdldir);
+    &util::cp_r ($mappingsdir, $gsdldir);
+    &util::cp ($maincfg, $etcdir);
+    &util::cp ($serverexe, $gsdldir);
+    &util::cp ($gssetupexe, $topdir);
+    &util::cp ($setupexe, $topdir);
+    &util::cp_r ($net32dir, $gsdldir);
+    &util::cp_r ($net16dir, $gsdldir);
+    &util::cp_r ($netscapedir, $topdir) if ($use_netscape);
+    &util::cp_r ($win32sdir, $topdir);
+    &util::cp ($phindjar, $binjavadir);
+    &util::cp ($gsdlcollageappletjar, $binjavadir);
+
+    # now change the home.dm macro file to a simple version
+    my $newmacrodir = &util::filename_cat ($gsdldir, "macros");
+    my $exporthome = &util::filename_cat ($newmacrodir, "exported_home.dm");
+    my $oldhome = &util::filename_cat ($newmacrodir, "home.dm");
+    if (-e $exporthome) {
+	&util::rm($oldhome);
+	&util::mv($exporthome, $oldhome);
+    }
+
+    # copy the collections over 
+    foreach my $c (@valid_coll_list) {
+	#old directories
+	my $colldir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect", $c);
+	my $colindexdir = &util::filename_cat ($colldir, "index");
+	my $coletcdir = &util::filename_cat ($colldir, "etc");
+	my $colimagesdir = &util::filename_cat ($colldir, "images");
+	my $colmacrosdir = &util::filename_cat ($colldir, "macros");
+	# new coll directory
+	my $newcoldir = &util::filename_cat ($collectdir, $c);
+
+	&util::mk_all_dir ($newcoldir);
+	&util::cp_r ($colindexdir, $newcoldir);
+	&util::cp_r ($coletcdir, $newcoldir);
+	&util::cp_r ($colimagesdir, $newcoldir) if (-e $colimagesdir);
+	&util::cp_r ($colmacrosdir, $newcoldir) if (-e $colmacrosdir);
+
+	# now we need to check the collect.cfg file to make sure it's public
+	my $collectcfg = &util::filename_cat ($newcoldir, "etc", "collect.cfg");
+	open INFILE, "<$collectcfg";
+	open OUTFILE, ">$collectcfg.tmp";
+	my $line;
+	while ($line = <INFILE>) {
+	    if ($line =~ /^\s*public\s+false/) {
+		print OUTFILE "public\ttrue\n";
+		last; # stop matching once we have found the line
+	    } else {
+		print OUTFILE "$line";
+	    }
+	}
+	# continue with no checking
+	while ($line = <INFILE>) {
+	    print OUTFILE "$line";
+	}
+	close INFILE;
+	close OUTFILE;
+	&util::mv("$collectcfg.tmp", $collectcfg);
+    }
+    &gsprintf($out, "{exportcol.success}");
+
+    my $successcolls = "";
+    my $first = 1;
+    foreach my $c (@valid_coll_list) {
+	if ($first) {
+	    $first=0;
+	} else {
+	    $successcolls .=", ";
+	}
+	$successcolls .= "$c";
+    }
+
+    my $gsdl_home = $ENV{'GSDLHOME'};
+    my $portable_topdir = $topdir;
+    # Disabled this because it isn't currently useful (the GLI applet doesn't do exporting)
+    # It doesn't work on Windows, either
+    # $portable_topdir =~ s/$gsdl_home/\$GSDLHOME/g;
+
+    &gsprintf($out, "{exportcol.output_dir}\n", $successcolls, $portable_topdir);
+    &gsprintf($out, "exportcol.pl succeeded:{exportcol.instructions}\n");
+    close OUT if $close_out;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/extract_text.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/extract_text.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/extract_text.pl	(revision 10506)
@@ -0,0 +1,147 @@
+#! /usr/bin/perl -w
+
+# extract_text.pl extracts the text from macro files, install scripts
+# etc. for translation.
+
+# output is currently to a tab separated list, suitable for importing into
+# excel.
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+}
+
+my $installsh = "$ENV{'GSDLHOME'}/Install.sh";
+my $macrosdir = "$ENV{'GSDLHOME'}/macros";
+my $installshield = 'C:/My Installations/is_gsdl_cdrom/String Tables/0009-English/value.shl';
+
+my $texthash = {};
+
+# first extract all the itextn variables from Install.sh
+open (INSTALLSH, $installsh) || die;
+undef $/;
+my $file = <INSTALLSH>;
+$/ = "\n";
+close INSTALLSH;
+
+$texthash->{'install_sh'} = {};
+while ($file =~ s/^(itext\d+)=\"(.*?)(?<!\\)\"//sm) {
+    my $key = $1;
+    my $value = $2;
+    $value =~ s/\n/\\n/gs;
+    $value =~ s/\t/\\t/gs;
+    if (defined ($texthash->{'install_sh'}->{$key})) {
+	print STDERR "ERROR: $1 already defined\n";
+    }
+    $texthash->{'install_sh'}->{$key} = $value;
+}
+
+
+# now grab the text from the macro files
+$texthash->{'macros'} = {};
+
+# english.dm
+&grab_macros("$macrosdir/english.dm");
+# english2.dm
+&grab_macros("$macrosdir/english2.dm");
+
+
+# text from installshield installation
+$texthash->{'installshield'} = {};
+open (ISHIELD, $installshield) || die;
+my $line = "";
+my $textserver = {};
+while (defined ($line = <ISHIELD>)) {
+    next unless ($line =~ /\w/);
+    last if $line =~ /^\[General\]/;
+    next if $line =~ /^\[/;
+
+    $line =~ s/\n/\\n/gs;
+    $line =~ s/\t/\\t/gs;
+
+    if ($line =~ /^(TEXT_SERVERTXT_\d+)=(.*)$/) {
+	$textserver->{$1} = $2;
+    } else {
+	$line =~ /^([^=]+)=(.*)$/;
+	$texthash->{'installshield'}->{$1} = $2;
+    }
+}
+close ISHIELD;
+my $tserver = "";
+foreach my $stext (sort keys %{$textserver}) {
+    $tserver .= $textserver->{$stext};
+}
+$texthash->{'installshield'}->{'TEXT_SERVERTXT'} = $tserver;
+
+# print out the result
+foreach my $type (keys (%$texthash)) {
+    print STDOUT "type:\t$type\n";
+    foreach my $key (sort keys (%{$texthash->{$type}})) {
+	print STDOUT "$key\t$texthash->{$type}->{$key}\n";
+    }
+}
+
+sub grab_macros {
+    my ($filename) = @_;
+
+    my $line = "";
+    my $pack = "Global";
+    my $macroname = "";
+    my $macrovalue = "";
+    open (FILE, $filename) || die;
+    while (defined ($line = <FILE>)) {
+	if ($line =~ /^package (\w+)/) {
+	    $pack = $1;
+	    $macroname = "";
+	    $macrovalue = "";
+	    next;
+	}
+
+	if ($line =~ /^_([^_\s]+)_\s*(?:\[[^\]]*\])?\s*\{(.*)$/s) {
+	    die "ERROR 1\n" if ($macroname ne "" || $macrovalue ne "");
+	    $macroname = $1;
+	    $macrovalue = $2 if defined $2;
+	    if ($macrovalue =~ s/^(.*?)(?<!\\)\}/$1/) {
+		&addmacro($pack, \$macroname, \$macrovalue);
+	    }		
+	} elsif ($macroname ne "") {
+	    if ($line =~ /^(.*?)(?<!\\)\}/) {
+		$macrovalue .= $1 if defined $1;
+		&addmacro($pack, \$macroname, \$macrovalue);
+	    } else {
+		$macrovalue .= $line;
+	    }
+	} elsif ($line =~ /^\#\# \"([^\"]+)\" \#\# \w+ \#\# (\w+) \#\#/) {
+	    my $imagename = "image:$2";
+	    my $imagetext = $1;
+	    &addmacro($pack, \$imagename, \$imagetext);
+	}
+    }
+    close FILE;
+}
+
+sub addmacro {
+    my ($pack, $nameref, $valref) = @_;
+
+    if ($$nameref !~ /^(httpicon|width|height)/) {
+
+	my $name = "$pack:$$nameref";
+	
+	if (defined ($texthash->{'macros'}->{$name})) {
+	    print STDERR "ERROR: $name already defined\n";	
+	}
+
+
+	$$valref =~ s/\n/\\n/gs;
+	$$valref =~ s/\t/\\t/gs;
+
+	$texthash->{'macros'}->{$name} = $$valref;
+    }
+
+    else {
+#	print STDERR "ignoring $$nameref\n";
+    }
+
+    $$nameref = "";
+    $$valref = "";
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/filecopy.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/filecopy.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/filecopy.pl	(revision 10506)
@@ -0,0 +1,184 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# filecopy.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This program will "download" the specified files/directories
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use util;
+use parsargv;
+use File::stat;
+use File::Basename;
+use FileHandle;
+
+sub print_usage {
+    print STDERR "\n";
+    print STDERR "filecopy.pl: Recursively copies files into a collections import directory.\n\n";
+    print STDERR "\n  usage: $0 [options] [directories] collection-name\n\n";
+
+    print STDERR "  options:\n";
+    print STDERR "   -follow_links           Follow symbolic links when recursing directory\n";
+    print STDERR "                           structure\n";
+    print STDERR "   -collectdir directory   Collection directory (defaults to " .
+	&util::filename_cat ($ENV{'GSDLHOME'}, "collect") . ")\n";
+    print STDERR "   -out                    Filename or handle to print output status to.\n";
+    print STDERR "                           The default is STDERR\n\n";
+}
+
+sub get_file_list {
+    my $dirhash = shift @_;
+    my $filehash = shift @_;
+    my $dirname = shift @_;
+
+    my $full_importname 
+	= &util::filename_cat($collectdir, $dirname, "import");
+
+    # check for .kill file
+    if (-e &util::filename_cat($collectdir, $dirname, ".kill")) {
+	print $out "filecopy.pl killed by .kill file\n";
+	die "\n";
+    }
+
+    foreach my $file (@_) {
+
+	$file =~ s/^\"//;
+	$file =~ s/\"$//;
+
+	if (!$follow_links && -l $file) {
+	    # do nothing as we don't want to follow symbolic links
+
+	} elsif (-d $file) {
+	    my $dst_dir = &get_dst_dir ($full_importname, $file);
+	    # add this directory to the list to be created
+	    $dirhash->{$dst_dir} = 1;
+
+	    # read in dir
+            if (!opendir (DIR, $file)) {
+                print $out "Error: Could not open directory $file\n";
+            } else {
+                my @sub_files = grep (!/^\.\.?$/, readdir (DIR));
+                closedir DIR;
+		map { $_ = &util::filename_cat($file, $_); } @sub_files;
+		&get_file_list($dirhash, $filehash, $dirname, @sub_files);
+	    }
+
+	} else {
+	    my $dst_file = &get_dst_dir ($full_importname, $file);
+
+	    # make sure files directory is included in dirhash
+	    $dirhash->{File::Basename::dirname($dst_file)} = 1;
+
+	    if (-e $dst_file) {
+		# if destination file exists already we'll only copy it if
+		# the source file is newer
+		my $src_stat = stat($file);
+		my $dst_stat = stat($dst_file);
+		$filehash->{$file} = $dst_file if ($src_stat->mtime > $dst_stat->mtime);
+	    } else {
+		$filehash->{$file} = $dst_file;
+	    }
+	}
+    }
+}
+
+
+sub main {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'follow_links', \$follow_links,
+			 'collectdir/.*/', \$collectdir,
+			 'out/.*/STDERR', \$out)) {
+	&print_usage();
+	die "\n";
+    }
+
+    if ($collectdir !~ /\w/) {
+	$collectdir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect");
+    }
+
+    my $collection = pop @ARGV;
+
+    my $close_out = 0;
+    if ($out !~ /^(STDERR|STDOUT)$/i) {
+	open (OUT, ">$out") || die "Couldn't open output file $out\n";
+	$out = OUT;
+	$close_out = 1;
+    }
+    $out->autoflush(1);
+
+    # first compile a list of all the files we want to copy (we do it this
+    # way rather than simply copying the files as we recurse the directory
+    # structure to avoid nasty infinite recursion if the directory we're
+    # copying to happens to be a subdirectory of one of the directories
+    # we're copying from)
+    my $dirhash = {};
+    my $filehash = {};
+    &get_file_list($dirhash, $filehash, $collection, @ARGV);
+
+    # create all the required destination directories
+    my $count = 0;
+    foreach my $dir (keys %$dirhash) {
+	# check for .kill file
+	if (($count ++ % 20 == 0) &&
+	    (-e &util::filename_cat($collectdir, $collection, ".kill"))) {
+	    print $out "filecopy.pl killed by .kill file\n";
+	    die "\n";
+	}
+	&util::mk_all_dir($dir);
+    }
+
+    # copy all the files
+    foreach my $file (keys %$filehash) {
+	# check for .kill file
+	if (($count ++ % 20 == 0) &&
+	    (-e &util::filename_cat($collectdir, $collection, ".kill"))) {
+	    print $out "filecopy.pl killed by .kill file\n";
+	    die "\n";
+	}
+	print $out "copying $file --> $filehash->{$file}\n";
+	&util::cp($file, $filehash->{$file});
+    }
+
+    close OUT if $close_out;
+    return 0;
+}
+
+sub get_dst_dir {
+    my ($full_importname, $dir) = @_;
+
+    if ($ENV{'GSDLOS'} eq "windows") {
+	# don't want windows filenames like c:\gsdl\...\import\c:\dir
+	$dir =~ s/^[a-z]:[\\\/]//i;
+    }
+    return &util::filename_cat($full_importname, $dir);
+}
+
+&main();
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/flash_button-1.2.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/flash_button-1.2.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/flash_button-1.2.pl	(revision 10506)
@@ -0,0 +1,382 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# flash_button.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# Modified by Rachid Ben Kaddour <qben@oce.nl> for gimp1.2
+
+# flash_button.pl generates all the flashy javascript type
+# buttons used by Greenstone
+# these are the buttons described in macro files as:
+# top_nav_button
+# nav_bar_button
+# document_button
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp qw/:auto :DEFAULT/;
+use parsargv;
+use util;
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_yellow = "#D2B464";
+my $black = "#000000";
+
+my ($cfg_file, $width, $height, $text, $filenamestem, $fixed_width,
+    $width_space, $whitespace, $dont_center, $bgcolor, $fontcolor, 
+    $fontsize, $fontfoundry, $fontname, $fontweight, $fontslant, $fontwidth, 
+    $fontspacing, $fontregistry, $fontencoding, $image_dir);
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -cfg_file file        configuration file containing one or more\n";
+    print STDERR "                         sets of the following options - use to create\n";
+    print STDERR "                         batches of images\n";
+    print STDERR "   -image_dir directory  directory to create images in [`pwd`]\n";
+    print STDERR "                         this should be full path to existing directory\n";
+    print STDERR "   -width number         width of button [65]\n";
+    print STDERR "   -height number        height of button [30]\n";
+    print STDERR "   -text string          button text\n";
+    print STDERR "   -filenamestem string  filename - two images will be produced -\n";
+    print STDERR "                         filenamestemon.gif and filenamestemof.gif\n";
+    print STDERR "   -fixed_width          fix width of image - if this isn't set\n";
+    print STDERR "                         image will be cropped with with width_space\n";
+    print STDERR "                         space at each side of text\n";
+    print STDERR "   -width_space number   width in pixels of blank space to leave at left\n";
+    print STDERR "                         and right edges of text [1]\n";
+    print STDERR "   -whitespace           add 1 pixel of white space at left and right edges\n";
+    print STDERR "                         of image\n";
+    print STDERR "   -dont_center          don't center text horizontally (only applicable if\n";
+    print STDERR "                         image is fixed width\n";
+    print STDERR "   -bgcolor hex_value    background color of button [$gsdl_yellow]\n";
+    print STDERR "   -fontcolor hex_value  text color [$black]\n";
+    print STDERR "   -fontsize number      font point size [10]\n";
+    print STDERR "   -foundry string       [*]\n";
+    print STDERR "   -fontname string      [lucida]\n";
+    print STDERR "   -fontweight string    [medium]\n";
+    print STDERR "   -fontslant            [r]\n";
+    print STDERR "   -fontwidth            [*]\n";
+    print STDERR "   -fontspacing          [*]\n\n";
+    print STDERR "   -fontregistry         [*]\n\n";
+    print STDERR "   -fontencoding         [*]\n\n";
+}
+
+sub reset_options {
+    $image_dir = "./";
+    $width = 65;
+    $height = 30;
+    $text = "";
+    $filenamestem = "";
+    $fixed_width = 0;
+    $width_space = 1;
+    $whitespace = 0;
+    $dont_center = 0;
+    $bgcolor = $gsdl_yellow;
+    $fontcolor = $black;
+    $fontsize = 10;
+    $fontfoundry = "*";
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+    $fontregistry = "*";
+    $fontencoding = "*";
+}
+
+sub gsdl_flash_button {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'cfg_file/.*/', \$cfg_file,
+			 'image_dir/.*/./', \$image_dir,
+			 'width/^\d+$/65', \$width,
+			 'height/^\d+$/30', \$height,
+			 'text/.*/', \$text,
+			 'filenamestem/.*', \$filenamestem,
+			 'fixed_width', \$fixed_width,
+			 'width_space/^\d+$/1', \$width_space,
+			 'whitespace', \$whitespace,
+			 'dont_center', \$dont_center,
+			 "bgcolor/#[0-9A-Fa-f]{6}/$gsdl_yellow", \$bgcolor,
+			 "fontcolor/#[0-9A-Fa-f]{6}/$black", \$fontcolor,
+			 'fontsize/^\d+$/10', \$fontsize,
+			 'foundry/.*/*', \$fontfoundry,
+			 'fontname/.*/lucida', \$fontname,
+			 'fontweight/.*/medium', \$fontweight,
+			 'fontslant/.*/r', \$fontslant,
+			 'fontwidth/.*/*', \$fontwidth,
+			 'fontspacing/.*/*', \$fontspacing,
+			 'fontregistry/.*/*', \$fontregistry,
+			 'fontencoding/.*/*', \$fontencoding)) {
+	&print_usage();
+	die "flash_button.pl: incorrect options\n";
+    }
+
+    # will create wherever gimp was started up from if we don't do this
+    if ($image_dir eq "./") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+    }
+
+    # replace any '\n' occurring in text with carriage return
+    $text =~ s/\\n/\n/gi;
+    
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filenamestem !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+
+	    &produce_images (0);
+	    if ($status) {last;}
+	}
+
+	close CONF;
+
+    } else {
+
+	&produce_images (0);
+
+    }
+}
+
+sub produce_images {
+    my ($off_img) = @_;
+    
+    # create image, set background color etc.
+    my ($image, $backlayer) = &create_image ($off_img);
+    
+    # set the text if there is any
+    if (length($text)) {
+
+	my $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				   $fontsize, PIXELS, $fontfoundry, $fontname, $fontweight, 
+				   $fontslant, $fontwidth, $fontspacing, $fontregistry, $fontencoding);
+
+	my $textwidth = gimp_drawable_width($textlayer);
+	my $textheight = gimp_drawable_height($textlayer);
+
+	# check that text fits within image
+	if ($textheight > $height) {
+	    die "'$text' at fontsize of $fontsize pixels does not fit within image\n" . 
+		"$height pixels high. Decrease fontsize or increase image height\n";
+	}
+
+	my $spacers = $width_space * 2;
+	$spacers += 2 if $whitespace;
+
+	if (!$fixed_width || $textwidth > $width) {
+
+	    if ($fixed_width) {
+		print STDERR "WARNING (flash_button.pl): '$text' does not fit within $width pixel fixed width ";
+		print STDERR "image. Image width was increased to ",$textwidth + $spacers, " pixels\n";
+	    }
+	    
+	    $width = $textwidth + $spacers;
+
+	    # recreate image in new size
+	    ($image, $backlayer) = &create_image ($off_img);
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				    $fontsize, PIXELS, $fontfoundry, $fontname, $fontweight, 
+				    $fontslant, $fontwidth, $fontspacing, $fontregistry, $fontencoding);
+	    
+	}
+
+	my $y_offset = ($height-$textheight)-int($fontsize/5);
+	my $halfdescenders = "";
+
+	# Russian half descenders (KOI8-R)
+	# -- Uncomment if generating Russian images using KOI8-R encoded text --
+	# $halfdescenders .= chr(195) . chr(253);  # Checked
+	# $halfdescenders .= chr(196) . chr(198) . chr(221) . chr(227) . chr(228); # Unchecked
+
+	# Kazakh (and Russian) half descenders (Helvetica Kazakh font)
+	# -- Uncomment if generating Kazakh or Russian images using text encoded to match
+	#      a Kazakh Helvetica font:
+        #        http://www.unesco.kz/ci/projects/greenstone/kazakh_fonts/helv_k.ttf
+	#    Mapping for this encoding is: mapping/from_uc/kazakh.ump --
+	# $halfdescenders .= chr(178) . chr(179) . chr(187);             # Kazakh specific
+	# $halfdescenders .= chr(196) . chr(214) . chr(217) . chr(228);  # Generic Russian
+	# $halfdescenders .= chr(244) . chr(246) . chr(249);
+
+	# -- Uncomment if generating images using a font with half descenders --
+	# if ($text =~ /[$halfdescenders]/) {
+	    # half descenders - put text at fontsize/10 pixels above bottom
+	    # $y_offset = ($height-$textheight)-int($fontsize/10);
+	# }
+
+	my $descenders = "";
+
+	# Russian descenders (KOI8-R)
+	# -- Uncomment if generating Russian images using KOI8-R encoded text --
+	# $descenders .= chr(210) . chr(213);
+
+	# Kazakh (and Russian) descenders (Helvetica Kazakh font)
+	# -- Uncomment if generating Kazakh or Russian images using text encoded to match
+	#      a Kazakh Helvetica font:
+        #        http://www.unesco.kz/ci/projects/greenstone/kazakh_fonts/helv_k.ttf
+	#    Mapping for this encoding is: mapping/from_uc/kazakh.ump --
+	# $descenders .= chr(189) . chr(190);  # Kazakh specific
+	# $descenders .= chr(240) . chr(243);  # Generic Russian
+
+	if ($text =~ /[gjpqyJ$descenders]/) { ## capital J is a descender in lucida font
+	    # descenders - put text at bottom of image, otherwise 
+	    # go for fontsize/5 pixels above bottom. This is kind of hacky 
+	    # and may need some playing with for different fonts/fontsizes
+	    $y_offset = $height-$textheight;
+	}
+
+	if ($fixed_width) {
+	    if ($dont_center) {
+		# don't center text horizontally (start it width_space pixels from left edge)
+		my $x_offset = $width_space;
+		$x_offset += 1 if $whitespace;
+		gimp_layer_set_offsets ($textlayer, $x_offset, $y_offset);
+	    } else {
+		gimp_layer_set_offsets ($textlayer, ($width-$textwidth)/2, $y_offset);
+	    }
+	} else {
+	    gimp_layer_set_offsets ($textlayer, $spacers / 2, $y_offset); 
+	}
+    }
+    
+    # add pixel of whitespace to each edge if required
+    if ($whitespace) {
+	gimp_rect_select ($image, 0, 0, 1, $height, 0, 0, 0);
+	gimp_edit_clear ($backlayer);
+	gimp_selection_none ($image);
+	gimp_rect_select ($image, $width-1, 0, 1, $height, 0, 0, 0);
+	gimp_edit_clear ($backlayer);
+	gimp_selection_none ($image);
+    }
+    
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+    
+    # make indexed colour 
+    gimp_convert_indexed ($image, NO_DITHER, MAKE_PALETTE, 256, 0, 1,"");
+    
+    # save image
+    my $filename = $filenamestem . "on.gif";
+    $filename = $filenamestem . "of.gif" if $off_img;
+    $filename = &util::filename_cat ($image_dir, $filename);
+
+    gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, $filename, $filename);
+
+    &produce_images (1) unless $off_img;    
+}
+
+sub create_image {
+    my ($off_img) = @_;
+
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+    
+    # background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+    
+    # add the background layer
+    gimp_image_add_layer ($image, $backlayer, 0);
+    
+    # set colour of background
+    gimp_palette_set_foreground ($bgcolor);
+    
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($backlayer);
+    gimp_selection_none ($image);
+    
+    # create the gradient background
+    gimp_blend ($backlayer, 0, NORMAL_MODE, LINEAR, 70, 0, REPEAT_NONE, 0, 0, 0, 5, $height-3, 5, 0);
+    
+    # adjust lightness of "off" gif
+    gimp_hue_saturation ($backlayer, 0, 0, 100, 0) if $off_img;
+
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+
+    return ($image, $backlayer);
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+    
+sub query {
+
+  gimp_install_procedure("gsdl_flash_button", "create flashy javascript buttons for gsdl",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-10",
+                        "<Toolbox>/Xtns/gsdl_flash_button", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+Gimp::on_net { gsdl_flash_button; };
+exit main;
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/flash_button.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/flash_button.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/flash_button.pl	(revision 10506)
@@ -0,0 +1,351 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# flash_button.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# flash_button.pl generates all the flashy javascript type
+# buttons used by Greenstone
+# these are the buttons described in macro files as:
+# top_nav_button
+# nav_bar_button
+# document_button
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp;
+use parsargv;
+use util;
+use unicode;
+
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_yellow = "#D2B464";
+my $black = "#000000";
+
+my ($cfg_file, $width, $height, $text, $filenamestem, $fixed_width,
+    $width_space, $whitespace, $dont_center, $bgcolor, $fontcolor, 
+    $fontsize, $foundry, $fontname, $fontweight, $fontslant, $fontwidth, 
+    $fontspacing, $image_dir);
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -cfg_file file        configuration file containing one or more\n";
+    print STDERR "                         sets of the following options - use to create\n";
+    print STDERR "                         batches of images\n";
+    print STDERR "   -image_dir directory  directory to create images in [`pwd`]\n";
+    print STDERR "                         this should be full path to existing directory\n";
+    print STDERR "   -width number         width of button [65]\n";
+    print STDERR "   -height number        height of button [30]\n";
+    print STDERR "   -text string          button text\n";
+    print STDERR "   -filenamestem string  filename - two images will be produced -\n";
+    print STDERR "                         filenamestemon.gif and filenamestemof.gif\n";
+    print STDERR "   -fixed_width          fix width of image - if this isn't set\n";
+    print STDERR "                         image will be cropped with with width_space\n";
+    print STDERR "                         space at each side of text\n";
+    print STDERR "   -width_space number   width in pixels of blank space to leave at left\n";
+    print STDERR "                         and right edges of text [1]\n";
+    print STDERR "   -whitespace           add 1 pixel of white space at left and right edges\n";
+    print STDERR "                         of image\n";
+    print STDERR "   -dont_center          don't center text horizontally (only applicable if\n";
+    print STDERR "                         image is fixed width\n";
+    print STDERR "   -bgcolor hex_value    background color of button [$gsdl_yellow]\n";
+    print STDERR "   -fontcolor hex_value  text color [$black]\n";
+    print STDERR "   -fontsize number      font point size [10]\n";
+    print STDERR "   -foundry string       [*]\n";
+    print STDERR "   -fontname string      [lucida]\n";
+    print STDERR "   -fontweight string    [medium]\n";
+    print STDERR "   -fontslant            [r]\n";
+    print STDERR "   -fontwidth            [*]\n";
+    print STDERR "   -fontspacing          [*]\n\n";
+}
+
+sub reset_options {
+    $image_dir = "./";
+    $width = 65;
+    $height = 30;
+    $text = "";
+    $filenamestem = "";
+    $fixed_width = 0;
+    $width_space = 1;
+    $whitespace = 0;
+    $dont_center = 0;
+    $bgcolor = $gsdl_yellow;
+    $fontcolor = $black;
+    $fontsize = 10;
+    $foundry = "*";
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+}
+
+sub gsdl_flash_button {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'cfg_file/.*/', \$cfg_file,
+			 'image_dir/.*/./', \$image_dir,
+			 'width/^\d+$/65', \$width,
+			 'height/^\d+$/30', \$height,
+			 'text/.*/', \$text,
+			 'filenamestem/.*', \$filenamestem,
+			 'fixed_width', \$fixed_width,
+			 'width_space/^\d+$/1', \$width_space,
+			 'whitespace', \$whitespace,
+			 'dont_center', \$dont_center,
+			 "bgcolor/#[0-9A-Fa-f]{6}/$gsdl_yellow", \$bgcolor,
+			 "fontcolor/#[0-9A-Fa-f]{6}/$black", \$fontcolor,
+			 'fontsize/^\d+$/10', \$fontsize,
+			 'foundry/.*/*', \$foundry,
+			 'fontname/.*/lucida', \$fontname,
+			 'fontweight/.*/medium', \$fontweight,
+			 'fontslant/.*/r', \$fontslant,
+			 'fontwidth/.*/*', \$fontwidth,
+			 'fontspacing/.*/*', \$fontspacing)) {
+	&print_usage();
+	die "flash_button.pl: incorrect options\n";
+    }
+
+    # will create wherever gimp was started up from if we don't do this
+    if ($image_dir eq "./") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+    }
+
+    # replace any '\n' occurring in text with carriage return
+    $text =~ s/\\n/\n/gi;
+
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filenamestem !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+
+	    &produce_images (0);
+	    if ($status) {last;}
+	}
+
+	close CONF;
+
+    } else {
+
+	&produce_images (0);
+
+    }
+}
+
+sub produce_images {
+    my ($off_img) = @_;
+    
+    # create image, set background color etc.
+    my ($image, $backlayer) = &create_image ($off_img);
+    
+    # set the text if there is any
+    if (length($text)) {
+
+	my $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				   $fontsize, PIXELS, $foundry, $fontname, $fontweight, 
+				   $fontslant, $fontwidth, $fontspacing);
+	
+
+	my $textwidth = gimp_drawable_width($textlayer);
+	my $textheight = gimp_drawable_height($textlayer);
+
+	# check that text fits within image
+	if ($textheight > $height) {
+	    die "'$text' at fontsize of $fontsize pixels does not fit within image\n" . 
+		"$height pixels high. Decrease fontsize or increase image height\n";
+	}
+
+	my $spacers = $width_space * 2;
+	$spacers += 2 if $whitespace;
+
+	if (!$fixed_width || $textwidth > $width) {
+
+	    if ($fixed_width) {
+		print STDERR "WARNING (flash_button.pl): '$text' does not fit within $width pixel fixed width ";
+		print STDERR "image. Image width was increased to ",$textwidth + $spacers, " pixels\n";
+	    }
+	    
+	    $width = $textwidth + $spacers;
+
+	    # recreate image in new size
+	    ($image, $backlayer) = &create_image ($off_img);
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				    $fontsize, PIXELS, $foundry, $fontname, $fontweight, 
+				    $fontslant, $fontwidth, $fontspacing);
+	    
+	}
+
+	my $y_offset = ($height-$textheight)-int($fontsize/5);
+
+	my $descenders = "";
+
+	# russian descenders (KOI8-R)
+	# $descenders .= chr(0xD2);
+	# $descenders .= chr(0xD5);
+
+	if ($text =~ /[gjpqyJ$descenders]/) { ## capital J is a descender in lucida font
+	    # descenders - put text at bottom of image, otherwise 
+	    # go for fontsize/5 pixels above bottom. This is kind of hacky 
+	    # and may need some playing with for different fonts/fontsizes
+	    $y_offset = $height-$textheight;
+	}
+
+	if ($fixed_width) {
+	    if ($dont_center) {
+		# don't center text horizontally (start it width_space pixels from left edge)
+		my $x_offset = $width_space;
+		$x_offset += 1 if $whitespace;
+		gimp_layer_set_offsets ($textlayer, $x_offset, $y_offset);
+	    } else {
+		gimp_layer_set_offsets ($textlayer, ($width-$textwidth)/2, $y_offset);
+	    }
+	} else {
+	    gimp_layer_set_offsets ($textlayer, $spacers / 2, $y_offset); 
+	}
+    }
+    
+    # add pixel of whitespace to each edge if required
+    if ($whitespace) {
+	gimp_rect_select ($image, 0, 0, 1, $height, 0, 0, 0);
+	gimp_edit_clear ($image, $backlayer);
+	gimp_selection_none ($image);
+	gimp_rect_select ($image, $width-1, 0, 1, $height, 0, 0, 0);
+	gimp_edit_clear ($image, $backlayer);
+	gimp_selection_none ($image);
+    }
+    
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+    
+    # make indexed colour 
+    gimp_convert_indexed ($image, 0, 256);
+    
+    # save image
+    my $filename = $filenamestem . "on.gif";
+    $filename = $filenamestem . "of.gif" if $off_img;
+    $filename = &util::filename_cat ($image_dir, $filename);
+
+    gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, $filename, $filename);
+
+    &produce_images (1) unless $off_img;    
+}
+
+sub create_image {
+    my ($off_img) = @_;
+
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+    
+    # background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+    
+    # add the background layer
+    gimp_image_add_layer ($image, $backlayer, 0);
+    
+    # set colour of background
+    gimp_palette_set_foreground ($bgcolor);
+    
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($image, $backlayer);
+    gimp_selection_none ($image);
+    
+    # create the gradient background
+    gimp_blend ($image, $backlayer, 0, NORMAL_MODE, LINEAR, 70, 0, REPEAT_NONE, 0, 0, 0, 5, $height-3, 5, 0);
+    
+    # adjust lightness of "off" gif
+    gimp_hue_saturation ($image, $backlayer, 0, 0, 100, 0) if $off_img;
+
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+
+    return ($image, $backlayer);
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+    
+sub query {
+
+  gimp_install_procedure("gsdl_flash_button", "create flashy javascript buttons for gsdl",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-10",
+                        "<Toolbox>/Xtns/gsdl_flash_button", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+sub net {
+  gsdl_flash_button;
+}
+
+exit main;
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/green_bar-1.2.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/green_bar-1.2.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/green_bar-1.2.pl	(revision 10506)
@@ -0,0 +1,342 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# green_bar.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# Modified by Rachid Ben Kaddour <qben@oce.nl> for gimp1.2
+
+# green_bar.pl generates all the black on green gradient background
+# images used by Greenstone. 
+# these are the icons described in macro files as:
+# green version of nav_bar_button
+# green_bar_left_aligned
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp qw/:auto :DEFAULT/;
+use parsargv;
+use util;
+use unicode;
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_green = "#96c19b";
+my $black = "#000000";
+
+my ($cfg_file, $width, $height, $text, $filename, $width_space, 
+    $dont_center, $bgcolor, $fontcolor, $fontsize, $foundry, $fontname, 
+    $fontweight, $fontslant, $fontwidth, $fontspacing, $fontregistry, $fontencoding, $image_dir);
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] macrofile\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -cfg_file file        configuration file containing one or more\n";
+    print STDERR "                         sets of the following options - use to create\n";
+    print STDERR "                         batches of images\n";
+    print STDERR "   -image_dir directory  directory to create images in [`pwd`]\n";
+    print STDERR "                         this should be full path to existing directory\n";
+    print STDERR "   -width number         width of bar [87]\n";
+    print STDERR "   -height number        height of bar [17]\n";
+    print STDERR "   -text string          icon text\n";
+    print STDERR "   -filename string      filename of resulting image\n";
+    print STDERR "   -width_space number   width in pixels of blank space to leave at left\n";
+    print STDERR "                         and right edges of text [1]\n";
+    print STDERR "   -dont_center          don't center text horizontally\n";
+    print STDERR "   -bgcolor hex_value    background color of bar [$gsdl_green]\n";
+    print STDERR "   -fontcolor hex_value  text color [$black]\n";
+    print STDERR "   -fontsize number      font point size [17]\n";
+    print STDERR "   -foundry string       [*]\n";
+    print STDERR "   -fontname string      [lucida]\n";
+    print STDERR "   -fontweight string    [medium]\n";
+    print STDERR "   -fontslant            [r]\n";
+    print STDERR "   -fontwidth            [*]\n";
+    print STDERR "   -fontspacing          [*]\n";
+    print STDERR "   -fontregistry         [*]\n";
+    print STDERR "   -fontencoding         [*]\n\n";
+}
+
+sub reset_options {
+    $image_dir = "./";
+    $width = 87;
+    $height = 17;
+    $text = "";
+    $filename = "";
+    $width_space = 1;
+    $dont_center = 0;
+    $bgcolor = $gsdl_green;
+    $fontcolor = $black;
+    $fontsize = 17;
+    $foundry = "*";
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+    $fontregistry = "*";
+    $fontencoding = "*";
+}
+
+sub gsdl_green_bar {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'cfg_file/.*/', \$cfg_file,
+			 'image_dir/.*/./', \$image_dir,
+			 'width/^\d+$/87', \$width,
+			 'height/^\d+$/17', \$height,
+			 'text/.*/', \$text,
+			 'filename/.*', \$filename,
+			 'width_space/^\d+$/1', \$width_space,
+			 'dont_center', \$dont_center,
+			 "bgcolor/#[0-9A-Fa-f]{6}/$gsdl_green", \$bgcolor,
+			 "fontcolor/#[0-9A-Fa-f]{6}/$black", \$fontcolor,
+			 'fontsize/^\d+$/17', \$fontsize,
+			 'foundry/.*/*', \$foundry,
+			 'fontname/.*/lucida', \$fontname,
+			 'fontweight/.*/medium', \$fontweight,
+			 'fontslant/.*/r', \$fontslant,
+			 'fontwidth/.*/*', \$fontwidth,
+			 'fontregistry/.*/*', \$fontregistry,
+			 'fontencoding/.*/*', \$fontencoding,
+			 'fontspacing/.*/*', \$fontspacing)) {
+	&print_usage();
+	die "green_bar.pl: incorrect options\n";
+    }
+
+    # will create wherever gimp was started up from if we don't do this
+    if ($image_dir eq "./") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+    }
+    
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filename !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+
+	    &produce_image ();
+	    if ($status) {last;}
+	}
+
+	close CONF;
+
+    } else {
+
+	&produce_image ();
+
+    }
+}
+
+sub produce_image {
+    
+    # create image, set background color etc.
+    my ($image, $backlayer) = &create_image ();
+    
+    # set the text if there is any
+    if (length($text)) {
+
+	my $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				   $fontsize, PIXELS, $foundry, $fontname, $fontweight, 
+				   $fontslant, $fontwidth, $fontspacing, $fontregistry, $fontencoding);
+	
+
+	my $textwidth = gimp_drawable_width($textlayer);
+	my $textheight = gimp_drawable_height($textlayer);
+
+	# check that text fits within image
+	if ($textheight > $height) {
+	    die "'$text' at fontsize of $fontsize pixels does not fit within image\n" . 
+		"$height pixels high. Decrease fontsize or increase image height\n";
+	}
+
+	my $spacers = $width_space * 2;
+
+	if ($textwidth > $width) {
+
+	    print STDERR "WARNING (green_bar.pl): '$text' does not fit within $width pixel fixed width ";
+	    print STDERR "image. Image width was increased to ",$textwidth + $spacers, " pixels\n";
+	    
+	    $width = $textwidth + $spacers;
+
+	    # recreate image in new size
+	    ($image, $backlayer) = &create_image ();
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				    $fontsize, PIXELS, $foundry, $fontname, $fontweight, 
+				    $fontslant, $fontwidth, $fontspacing, $fontregistry, $fontencoding);
+	    
+	}
+
+	my $y_offset = ($height-$textheight)-int($fontsize/5);
+
+	my $halfdescenders = "";
+
+	# Russian half descenders (KOI8-R)
+	# -- Uncomment if generating Russian images using KOI8-R encoded text --
+	# $halfdescenders .= chr(195) . chr(253);  # Checked
+	# $halfdescenders .= chr(196) . chr(198) . chr(221) . chr(227) . chr(228); # Unchecked
+
+	# Kazakh (and Russian) half descenders (Helvetica Kazakh font)
+	# -- Uncomment if generating Kazakh or Russian images using text encoded to match
+	#      a Kazakh Helvetica font:
+        #        http://www.unesco.kz/ci/projects/greenstone/kazakh_fonts/helv_k.ttf
+	#    Mapping for this encoding is: mapping/from_uc/kazakh.ump --
+	# $halfdescenders .= chr(178) . chr(179) . chr(187);             # Kazakh specific
+	# $halfdescenders .= chr(196) . chr(214) . chr(217) . chr(228);  # Generic Russian
+	# $halfdescenders .= chr(244) . chr(246) . chr(249);
+
+	# -- Uncomment if generating images using a font with half descenders --
+	# if ($text =~ /[$halfdescenders]/) {
+	    # half descenders - put text at fontsize/10 pixels above bottom
+	    # $y_offset = ($height-$textheight)-int($fontsize/10);
+	# }
+
+	my $descenders = "";
+
+	# Russian descenders (KOI8-R)
+	# -- Uncomment if generating Russian images using KOI8-R encoded text --
+	# $descenders .= chr(210) . chr(213);
+
+	# Kazakh (and Russian) descenders (Helvetica Kazakh font)
+	# -- Uncomment if generating Kazakh or Russian images using text encoded to match
+	#      a Kazakh Helvetica font:
+        #        http://www.unesco.kz/ci/projects/greenstone/kazakh_fonts/helv_k.ttf
+	#    Mapping for this encoding is: mapping/from_uc/kazakh.ump --
+	# $descenders .= chr(189) . chr(190);  # Kazakh specific
+	# $descenders .= chr(240) . chr(243);  # Generic Russian
+
+	if ($text =~ /[gjpqyJ$descenders]/) { ## capital J is a descender in lucida font
+	    # descenders - put text at bottom of image, otherwise 
+	    # go for fontsize/5 pixels above bottom. This is kind of hacky 
+	    # and may need some playing with for different fonts/fontsizes
+	    $y_offset = $height-$textheight;
+	}
+
+	if ($dont_center) {
+	    # don't center text horizontally (start it width_space pixels from left edge)
+	    my $x_offset = $width_space;
+	    gimp_layer_set_offsets ($textlayer, $x_offset, $y_offset);
+	} else {
+	    gimp_layer_set_offsets ($textlayer, ($width-$textwidth)/2, $y_offset);
+	}
+    }
+    
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+    
+    # make indexed colour 
+    gimp_convert_indexed ($image, NO_DITHER, MAKE_PALETTE, 256, 0, 1,"");
+    
+    # save image
+    $filename = &util::filename_cat ($image_dir, $filename);
+
+    gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, $filename, $filename);
+
+}
+
+sub create_image {
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+    
+    # background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+    
+    # add the background layer
+    gimp_image_add_layer ($image, $backlayer, 0);
+    
+    # set colour of background
+    gimp_palette_set_foreground ($bgcolor);
+    
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($backlayer);
+    gimp_selection_none ($image);
+    
+    # create the gradient background
+    gimp_blend ($backlayer, 0, NORMAL_MODE, LINEAR, 70, 0, REPEAT_NONE, 0, 0, 0, 5, $height-3, 5, 0);
+
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+
+    return ($image, $backlayer);
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+    
+sub query {
+
+  gimp_install_procedure("gsdl_green_bar", "create green bar icons for gsdl",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-10",
+                        "<Toolbox>/Xtns/gsdl_green_bar", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+Gimp::on_net { gsdl_green_bar; };
+exit main;
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/green_bar.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/green_bar.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/green_bar.pl	(revision 10506)
@@ -0,0 +1,307 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# green_bar.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# green_bar.pl generates all the black on green gradient background
+# images used by Greenstone. 
+# these are the icons described in macro files as:
+# green version of nav_bar_button
+# green_bar_left_aligned
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp;
+use parsargv;
+use util;
+use unicode;
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_green = "#96c19b";
+my $black = "#000000";
+
+my ($cfg_file, $width, $height, $text, $filename, $width_space, 
+    $dont_center, $bgcolor, $fontcolor, $fontsize, $foundry, $fontname, 
+    $fontweight, $fontslant, $fontwidth, $fontspacing, $image_dir);
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] macrofile\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -cfg_file file        configuration file containing one or more\n";
+    print STDERR "                         sets of the following options - use to create\n";
+    print STDERR "                         batches of images\n";
+    print STDERR "   -image_dir directory  directory to create images in [`pwd`]\n";
+    print STDERR "                         this should be full path to existing directory\n";
+    print STDERR "   -width number         width of bar [87]\n";
+    print STDERR "   -height number        height of bar [17]\n";
+    print STDERR "   -text string          icon text\n";
+    print STDERR "   -filename string      filename of resulting image\n";
+    print STDERR "   -width_space number   width in pixels of blank space to leave at left\n";
+    print STDERR "                         and right edges of text [1]\n";
+    print STDERR "   -dont_center          don't center text horizontally\n";
+    print STDERR "   -bgcolor hex_value    background color of bar [$gsdl_green]\n";
+    print STDERR "   -fontcolor hex_value  text color [$black]\n";
+    print STDERR "   -fontsize number      font point size [17]\n";
+    print STDERR "   -foundry string       [*]\n";
+    print STDERR "   -fontname string      [lucida]\n";
+    print STDERR "   -fontweight string    [medium]\n";
+    print STDERR "   -fontslant            [r]\n";
+    print STDERR "   -fontwidth            [*]\n";
+    print STDERR "   -fontspacing          [*]\n\n";
+}
+
+sub reset_options {
+    $image_dir = "./";
+    $width = 87;
+    $height = 17;
+    $text = "";
+    $filename = "";
+    $width_space = 1;
+    $dont_center = 0;
+    $bgcolor = $gsdl_green;
+    $fontcolor = $black;
+    $fontsize = 17;
+    $foundry = "*";
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+}
+
+sub gsdl_green_bar {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'cfg_file/.*/', \$cfg_file,
+			 'image_dir/.*/./', \$image_dir,
+			 'width/^\d+$/87', \$width,
+			 'height/^\d+$/17', \$height,
+			 'text/.*/', \$text,
+			 'filename/.*', \$filename,
+			 'width_space/^\d+$/1', \$width_space,
+			 'dont_center', \$dont_center,
+			 "bgcolor/#[0-9A-Fa-f]{6}/$gsdl_green", \$bgcolor,
+			 "fontcolor/#[0-9A-Fa-f]{6}/$black", \$fontcolor,
+			 'fontsize/^\d+$/17', \$fontsize,
+			 'foundry/.*/*', \$foundry,
+			 'fontname/.*/lucida', \$fontname,
+			 'fontweight/.*/medium', \$fontweight,
+			 'fontslant/.*/r', \$fontslant,
+			 'fontwidth/.*/*', \$fontwidth,
+			 'fontspacing/.*/*', \$fontspacing)) {
+	&print_usage();
+	die "green_bar.pl: incorrect options\n";
+    }
+
+    # will create wherever gimp was started up from if we don't do this
+    if ($image_dir eq "./") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+    }
+    
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filename !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+
+	    &produce_image ();
+	    if ($status) {last;}
+	}
+
+	close CONF;
+
+    } else {
+
+	&produce_image ();
+
+    }
+}
+
+sub produce_image {
+    
+    # create image, set background color etc.
+    my ($image, $backlayer) = &create_image ();
+    
+    # set the text if there is any
+    if (length($text)) {
+
+	my $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				   $fontsize, PIXELS, $foundry, $fontname, $fontweight, 
+				   $fontslant, $fontwidth, $fontspacing);
+	
+
+	my $textwidth = gimp_drawable_width($textlayer);
+	my $textheight = gimp_drawable_height($textlayer);
+
+	# check that text fits within image
+	if ($textheight > $height) {
+	    die "'$text' at fontsize of $fontsize pixels does not fit within image\n" . 
+		"$height pixels high. Decrease fontsize or increase image height\n";
+	}
+
+	my $spacers = $width_space * 2;
+
+	if ($textwidth > $width) {
+
+	    print STDERR "WARNING (green_bar.pl): '$text' does not fit within $width pixel fixed width ";
+	    print STDERR "image. Image width was increased to ",$textwidth + $spacers, " pixels\n";
+	    
+	    $width = $textwidth + $spacers;
+
+	    # recreate image in new size
+	    ($image, $backlayer) = &create_image ();
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				    $fontsize, PIXELS, $foundry, $fontname, $fontweight, 
+				    $fontslant, $fontwidth, $fontspacing);
+	    
+	}
+
+	my $y_offset = ($height-$textheight)-int($fontsize/5);
+
+	my $descenders = "";
+
+	# russian descenders (KOI8-R)
+	# $descenders .= chr(0xD2);
+	# $descenders .= chr(0xD5);
+
+	if ($text =~ /[gjpqyJ$descenders]/) { ## capital J is a descender in lucida font
+	    # descenders - put text at bottom of image, otherwise 
+	    # go for fontsize/5 pixels above bottom. This is kind of hacky 
+	    # and may need some playing with for different fonts/fontsizes
+	    $y_offset = $height-$textheight;
+	}
+
+	if ($dont_center) {
+	    # don't center text horizontally (start it width_space pixels from left edge)
+	    my $x_offset = $width_space;
+	    gimp_layer_set_offsets ($textlayer, $x_offset, $y_offset);
+	} else {
+	    gimp_layer_set_offsets ($textlayer, ($width-$textwidth)/2, $y_offset);
+	}
+    }
+    
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+    
+    # make indexed colour 
+    gimp_convert_indexed ($image, 0, 256);
+    
+    # save image
+    $filename = &util::filename_cat ($image_dir, $filename);
+
+    gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, $filename, $filename);
+
+}
+
+sub create_image {
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+    
+    # background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+    
+    # add the background layer
+    gimp_image_add_layer ($image, $backlayer, 0);
+    
+    # set colour of background
+    gimp_palette_set_foreground ($bgcolor);
+    
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($image, $backlayer);
+    gimp_selection_none ($image);
+    
+    # create the gradient background
+    gimp_blend ($image, $backlayer, 0, NORMAL_MODE, LINEAR, 70, 0, REPEAT_NONE, 0, 0, 0, 5, $height-3, 5, 0);
+
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+
+    return ($image, $backlayer);
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+    
+sub query {
+
+  gimp_install_procedure("gsdl_green_bar", "create green bar icons for gsdl",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-10",
+                        "<Toolbox>/Xtns/gsdl_green_bar", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+sub net {
+  gsdl_green_bar;
+}
+
+exit main;
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/green_bar_g12.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/green_bar_g12.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/green_bar_g12.pl	(revision 10506)
@@ -0,0 +1,309 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# green_bar.pl 
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# green_bar.pl 
+#
+# This script generates the black on green gradient background images
+# used by Greenstone.  these are the icons described in macro files as:
+# green version of nav_bar_button green_bar_left_aligned
+#
+# This version has been rewritten for the GIMP Version 1.2.  You
+# should be able to run it if you install gimp 1.2 with perl support.
+# In Debian this means running "apt-get install gimp1.2 gimp1.2perl"
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp ":auto";
+use Gimp::Fu; 
+
+use util;
+use unicode;
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_green = "#96c19b";
+my $black      = "#000000";
+my $white      = "#FFFFFF";
+
+my ($current_dir) = `pwd`;
+chomp($current_dir);
+
+my ($cfg_file, $width, $height, $text, $filename, $width_space, 
+    $alignment, $fgcolor, $bgcolor, $fontcolor, $fontsize, $foundry, $fontname, 
+    $fontweight, $fontslant, $fontwidth, $fontspacing, $image_dir);
+
+sub reset_options {
+    $image_dir = "./";
+    $width = 87;
+    $height = 17;
+    $text = "";
+    $filename = "";
+    $width_space = 1;
+    $alignment = "eft";
+    $fgcolor = $white;
+    $bgcolor = $gsdl_green;
+    $fontcolor = $black;
+    $fontsize = 17;
+    $foundry = "*";
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+}
+
+sub gsdl_green_bar {
+
+    ($text, $filename, $image_dir, $width, $height, $fgcolor, $bgcolor,
+    $fontcolor, $fontsize, $alignment, , $width_space, $foundry,
+    $fontname, $fontweight, $fontslant, $fontwidth, $fontspacing,
+    $cfg_file) = @_;
+
+    # Read a configuration file
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filename !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+
+	    &produce_image ();
+	    if ($status) {last;}
+	}
+
+	close CONF;
+
+    }
+
+    # Produce an image based onlyon command-line parameters
+    else {
+
+	&produce_image ();
+
+    }
+}
+
+
+sub produce_image {
+
+    # Create background image
+    my ($image, $backlayer) = &create_image ();
+
+    # set the text if there is any
+    if (length($text)) {
+
+	my $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, 
+				   $fontsize, PIXELS, $foundry, $fontname, $fontweight, 
+				   $fontslant, $fontwidth, $fontspacing, "*", "*");
+	
+
+	my $textwidth = gimp_drawable_width($textlayer);
+	my $textheight = gimp_drawable_height($textlayer);
+
+	# check that text fits within image
+	if ($textheight > $height) {
+	    die "'$text' at fontsize of $fontsize pixels does not fit within image\n" . 
+		"$height pixels high. Decrease fontsize or increase image height\n";
+	}
+
+	my $spacers = $width_space * 2;
+
+	if ($textwidth > $width) {
+
+	    print STDERR "WARNING (green_bar.pl): '$text' does not fit within $width pixel fixed width ";
+	    print STDERR "image. Image width was increased to ",$textwidth + $spacers, " pixels\n";
+	
+	    $width = $textwidth + $spacers;
+
+	    # recreate image in new size
+	    ($image, $backlayer) = &create_image ();
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1,
+				    $fontsize, PIXELS, $foundry, $fontname, $fontweight,
+				    $fontslant, $fontwidth, $fontspacing, "*", "*");
+	
+	}
+
+	my $y_offset = ($height-$textheight)-int($fontsize/5);
+
+	my $descenders = "";
+
+	# russian descenders (KOI8-R)
+	# $descenders .= chr(0xD2);
+	# $descenders .= chr(0xD5);
+
+	if ($text =~ /[gjpqyJ$descenders]/) { ## capital J is a descender in lucida font
+	    # descenders - put text at bottom of image, otherwise 
+	    # go for fontsize/5 pixels above bottom. This is kind of hacky 
+	    # and may need some playing with for different fonts/fontsizes
+	    $y_offset = $height-$textheight;
+	}
+
+	if ($alignment =~ /^l/i) {
+	    # align text to the left
+	    my $x_offset = $width_space;
+	    gimp_layer_set_offsets ($textlayer, $x_offset, $y_offset);
+	} elsif ($alignment =~ /^r/i) {
+	    # right alignment
+	    gimp_layer_set_offsets ($textlayer, ($width-($textwidth+$width_space)), $y_offset);
+	} else {
+	    # center alignment (the default)
+	    gimp_layer_set_offsets ($textlayer, ($width-$textwidth)/2, $y_offset);
+	}
+    }
+
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+
+    # make indexed colour 
+    if ($filename =~ /\.gif$/i) {
+        # make indexed colour (may need to do this for 
+        # other formats as well as gif)
+        gimp_convert_indexed ($image, 0, MAKE_PALETTE, 256, 0, 0, "");
+    }
+
+    # save image
+    $filename = &util::filename_cat ($image_dir, $filename);
+    gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, $filename, $filename);
+}
+
+
+sub create_image {
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+
+    # background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+
+    # add the background layer
+    gimp_image_add_layer ($image, $backlayer, 0);
+
+    # set colour of background
+    gimp_palette_set_foreground ($bgcolor);
+    gimp_palette_set_background ($fgcolor);
+
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($backlayer);
+    gimp_selection_none ($image);
+
+    # create the gradient background
+    gimp_blend ($backlayer, 0, NORMAL_MODE, LINEAR, 70, 0, REPEAT_NONE, 0, 0, 0, 5, $height-3, 5, 0);
+
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+
+    return ($image, $backlayer);
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+
+
+register("gsdl_green_bar", 
+	 "Create green bar icons for gsdl (gimp version 1.2)",
+	 "",
+	 "Stefan Boddie (1.0) and Gordon Paynter (1.2)",
+	 "Copyright 2000 Stefan Boddie and The New Zealand Digital Library Project",
+	 "2000-07-05",
+	 "<Toolbox>/Xtns/gsdl_green_bar", 
+	 "*",
+	 [
+           [PF_STRING, "text",        "Text appearing on bar", "greenstone"],
+
+           [PF_STRING, "filename",    "Output file", "green_bar.png"],
+           [PF_STRING, "image_dir",   "Directory to create images in", $current_dir],
+
+           [PF_INT,    "width",      "Width of the bar",  640],
+           [PF_INT,    "height",     "Height of the bar", 17],
+           [PF_STRING, "fgcolor",   "Foreground colour (top) of bar", $white],
+           [PF_STRING, "bgcolor",   "Background colour (bottom) of bar", $gsdl_green],
+           [PF_STRING, "fontcolor", "Colour of text on bar", $black],
+           [PF_INT,    "fontsize",  "Font size",    17],
+
+           [PF_STRING, "alignment",     "Alignment of text on the bar (left, center or right)", "left"],
+           [PF_INT,    "padding_space", "Space around the text",                   5],
+
+           [PF_STRING, "foundry",     "Font foundry", "*"],
+           [PF_STRING, "fontname",    "Font name",    "lucida"],
+           [PF_STRING, "fontweight",  "Font weight",  "medium"],
+           [PF_STRING, "fontslant",   "Font slant",   "r"],
+           [PF_STRING, "fontwidth",   "Font width",   "*"],
+           [PF_STRING, "fontspacing", "Font spacing", "*"],
+
+           [PF_STRING, "cfg_file",    "Configuration file", ""]
+
+         ], 
+         \&gsdl_green_bar);
+
+
+exit main;
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/title_icon-1.2.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/title_icon-1.2.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/title_icon-1.2.pl	(revision 10506)
@@ -0,0 +1,407 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# title_icon.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# Modified by Rachid Ben Kaddour <qben@oce.nl> for gimp1.2
+
+# title_icon.pl generates all the green_title type icons and 
+# collection icons for Greenstone
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp qw/:auto :DEFAULT/;
+use parsargv;
+use util;
+use unicode;
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_green = "#96c19b";
+my $black = "#000000";
+
+
+local ($cfg_file, $size, $imagefile, $width, $height, $imageheight, $stripecolor, $stripewidth, 
+       $stripe_alignment, $i_transparency, $text, $text_alignment, $filename, $textspace_x, 
+       $textspace_y, $bgcolor, $fontcolor, $fontsize, $minfontsize, $foundry, $fontname, 
+       $fontweight, $fontslant, $fontwidth, $fontspacing, $fontregistry, $fontencoding, $image_dir, $dont_wrap);
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] macrofile\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -cfg_file file         configuration file containing one or more\n";
+    print STDERR "                          sets of the following options - use to create\n";
+    print STDERR "                          batches of images\n";
+    print STDERR "   -size number           the overall size ratio of the image (i.e. a size\n";
+    print STDERR "                          of 2 will create an image twice the default size)\n";
+    print STDERR "   -image_dir directory   directory to create images in [`pwd`]\n";
+    print STDERR "                          this should be full path to existing directory\n";
+    print STDERR "   -imagefile             filename of image to embed within new icon\n";
+    print STDERR "   -width number          width of icon [150]\n";
+    print STDERR "   -height number         height of icon [44]\n";
+    print STDERR "   -imageheight number    this is the height of the image if the image contains\n";
+    print STDERR "                          an image (like collection icons) [110]\n";
+    print STDERR "   -stripecolor hex_value color of vertical stripe [$gsdl_green]\n";
+    print STDERR "   -stripewidth           width of vertical stripe [40]\n";
+    print STDERR "   -stripe_alignment      alignment of vertical stripe (left or right) [left]\n";
+    print STDERR "   -i_transparency number transparency of image within icon (0 > transparent > 100) [60]\n"; 
+    print STDERR "   -text string           image text\n";
+    print STDERR "   -text_alignment        alignment of text (left or right) [left]\n";
+    print STDERR "   -filename string       filename of resulting image\n";
+    print STDERR "   -textspace_x number    space in pixels between left/right edge of image and\n";
+    print STDERR "                          left/right edge of text [3]\n";
+    print STDERR "   -textspace_y number    space in pixels between top of image and top of\n";
+    print STDERR "                          text [3]\n";
+    print STDERR "   -bgcolor hex_value     background color of icon [$gsdl_green]\n";
+    print STDERR "   -fontcolor hex_value   text color [$black]\n";
+    print STDERR "   -fontsize number       font point size [17]\n";
+    print STDERR "   -minfontsize number    minimum point size font will be reduced to fit image [10]\n";
+    print STDERR "   -foundry string        [*]\n";
+    print STDERR "   -fontname string       [lucida]\n";
+    print STDERR "   -fontweight string     [medium]\n";
+    print STDERR "   -fontslant             [r]\n";
+    print STDERR "   -fontwidth             [*]\n";
+    print STDERR "   -fontspacing           [*]\n";
+    print STDERR "   -fontregistry          [*]\n";
+    print STDERR "   -fontencoding          [*]\n";
+    print STDERR "   -dont_wrap             don't attempt to wrap text\n\n";
+}
+
+sub reset_options {
+    $image_dir = "./";
+    $imagefile = "";
+    $width = int (150 * $size);
+    $height = int (44 * $size);
+    $imageheight = int (110 * $size);
+    $stripecolor = $gsdl_green;
+    $stripewidth = int (40 * $size);
+    $stripe_alignment = "left";
+    $i_transparency = 60;
+    $text = "";
+    $text_alignment = "left";
+    $filename = "";
+    $textspace_x = int (3 * $size);
+    $textspace_y = int (3 * $size);
+    $bgcolor = $gsdl_green;
+    $fontcolor = $black;
+    $fontsize = int (17 * $size);
+    $minfontsize = int (10 * $size);
+    $foundry = "*";
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+    $fontregistry = "*";
+    $fontencoding = "*";
+}
+
+sub gsdl_title_icon {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'cfg_file/.*/', \$cfg_file,
+			 'size/\d+/1', \$size,
+			 'image_dir/.*/./', \$image_dir,
+			 'imagefile/.*/', \$imagefile,
+			 'width/^\d+$/150', \$width,
+			 'height/^\d+$/44', \$height,
+			 'imageheight/^\d+$/110', \$imageheight,
+			 "stripecolor/#[0-9A-Fa-f]{6}/$gsdl_green", \$stripecolor,
+			 'stripewidth/^\d+$/40', \$stripewidth,
+			 'stripe_alignment/^(left|right)$/left', \$stripe_alignment,
+			 'i_transparency/^\d+$/60', \$i_transparency,
+			 'text/.*/', \$text,
+			 'text_alignment/^(left|right)$/left', \$text_alignment,
+			 'filename/.*', \$filename,
+			 'textspace_x/^\d+$/3', \$textspace_x,
+			 'textspace_y/^\d+$/3', \$textspace_y,
+			 "bgcolor/#[0-9A-Fa-f]{6}/$gsdl_green", \$bgcolor,
+			 "fontcolor/#[0-9A-Fa-f]{6}/$black", \$fontcolor,
+			 'fontsize/^\d+$/17', \$fontsize,
+			 'minfontsize/^\d+$/10', \$minfontsize,
+			 'foundry/.*/*', \$foundry,
+			 'fontname/.*/lucida', \$fontname,
+			 'fontweight/.*/medium', \$fontweight,
+			 'fontslant/.*/r', \$fontslant,
+			 'fontwidth/.*/*', \$fontwidth,
+			 'fontspacing/.*/*', \$fontspacing,
+			 'fontregistry/.*/*', \$fontregistry,
+			 'fontencoding/.*/*', \$fontencoding,
+			 'dont_wrap', \$dont_wrap)) {
+	&print_usage();
+	die "title_icon.pl: incorrect options\n";
+    }
+
+    # will create wherever gimp was started up from if we don't do this
+    if ($image_dir eq "./") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+    }
+
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filename !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+
+	    &produce_image ();
+	    if ($status) {last;}
+	}
+
+	close CONF;
+
+    } else {
+
+	&produce_image ();
+
+    }
+}
+
+sub produce_image {
+
+    &adjust_args ();
+    &wrap_text () unless $dont_wrap;
+
+    my $use_image = 0;
+    if ($imagefile =~ /\w/) {
+	if (!-r $imagefile) {
+	    print STDERR "WARNING (title_icon.pl): imagefile '$imagefile cannot be ";
+	    print STDERR "read - $filename will be created without the use of an image file\n";
+	} else {
+	    $use_image = 1;
+	    $height = $imageheight;
+	}
+    }
+
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+	
+    # background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+	
+    # add the background layer
+    gimp_image_add_layer ($image, $backlayer, 0);
+	
+    # set colour of stripe
+    gimp_palette_set_foreground ($stripecolor);
+	
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($backlayer);
+    gimp_selection_none ($image);
+	
+    # fill in stripe
+    if ($stripe_alignment eq "left") {
+	gimp_rect_select ($image, 0, 0, $stripewidth, $height, 0, 0, 0);
+    } else {
+	gimp_rect_select ($image, $width-$stripewidth, 0, $stripewidth, $height, 0, 0, 0);
+    }
+    gimp_bucket_fill ($backlayer, FG_BUCKET_FILL, NORMAL_MODE, 100, 0, 1, 0, 0);
+    gimp_selection_none ($image);
+
+    # get image file (image goes on opposite side to stripe)
+    if ($use_image) {
+	my $rimage = gimp_file_load (RUN_NONINTERACTIVE, $imagefile, $imagefile);
+	my $rdraw = gimp_image_active_drawable ($rimage);
+	gimp_scale ($rdraw, 1, 0, 0, $width-$stripewidth, $height);
+	gimp_edit_copy ($rdraw);
+	
+	my $imagelayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+					 "ImageLayer", $i_transparency, NORMAL_MODE);
+	
+	gimp_image_add_layer ($image, $imagelayer, 0);
+	
+	# clear the new layer
+	gimp_selection_all ($image);
+	gimp_edit_clear ($imagelayer);
+	gimp_selection_none ($image);
+	
+	my $flayer = gimp_edit_paste ($imagelayer, 1); 
+	if ($stripe_alignment eq "left") {
+	    gimp_layer_set_offsets($flayer, $stripewidth, 0);
+	    gimp_layer_set_offsets($imagelayer, $stripewidth, 0);
+	} else {
+	    gimp_layer_set_offsets($flayer, 0, 0);
+	    gimp_layer_set_offsets($imagelayer, 0, 0);
+	}
+
+	$backlayer = gimp_image_flatten ($image);
+    }
+	
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+	
+    # set the text if there is any
+    my ($textlayer, $textheight, $textwidth);
+    my $fsize = $fontsize;
+    if (length($text)) {
+	$text =~ s/\\n/\n/gi;
+
+	while (1) {
+
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, $fsize, 
+				    PIXELS, $foundry, $fontname, $fontweight, $fontslant, 
+				    $fontwidth, $fontspacing, $fontregistry, $fontencoding);
+	    
+	    # check that text fits within image
+	    $textwidth = gimp_drawable_width($textlayer);
+	    $textheight = gimp_drawable_height($textlayer);
+	    if ((($textwidth + $textspace_x) > $width) || 
+		(($textheight + $textspace_y) > $height)) {
+		if ($fsize < $minfontsize) {
+		    die "Error (title_icon.pl): text '$text' doesn't fit on ${width}x${height} image " .
+			"(minimum font size tried: $minfontsize\n";
+		} else {
+		    gimp_selection_all ($image);
+		    gimp_edit_clear ($textlayer);
+		    gimp_selection_none ($image);
+		    $fsize --;
+		    print STDERR "WARNING (title_icon.pl): '$text' doesn't fit: reducing font size to $fsize\n";
+		}
+	    } else {
+		last;
+	    }
+	}
+	
+	# align text
+	if ($text_alignment eq "left") {
+	    gimp_layer_set_offsets ($textlayer, $textspace_x, $textspace_y);
+	} else {
+	    gimp_layer_set_offsets ($textlayer, ($width-$textwidth)-$textspace_x, $textspace_y);
+	}
+    }
+    
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+	
+    if ($filename =~ /\.gif$/i) {
+	# make indexed colour (may need to do this for 
+	# other formats as well as gif)
+	gimp_convert_indexed ($image, NO_DITHER, MAKE_PALETTE, 256, 0, 1, "");
+    }
+	
+    # save image
+    my $filename = &util::filename_cat ($image_dir, $filename);
+    if ($filename =~ /\.jpe?g$/i) {
+	# gimp_file_save doesn't appear to work properly for jpegs
+	file_jpeg_save (RUN_NONINTERACTIVE, $image, $finishedlayer, 
+			$filename, $filename, 0.8, 0, 1);
+    } else {
+	gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, 
+			$filename, $filename);
+    }
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+
+# adjust arguments that are effected by the size argument
+sub adjust_args {    
+
+    if ($size != 1) {
+	my @size_args = ('width', 'height', 'imageheight', 'stripewidth',
+			 'textspace_x', 'textspace_y', 'fontsize', 'minfontsize');
+	foreach $arg (@size_args) {
+	    $$arg = int ($$arg * $size);
+	}
+    }
+}
+
+sub wrap_text {
+
+    # don't wrap text if it already contains carriage returns
+    return if $text =~ /\n/;
+
+    # the following assumes that all words are less than $wrap_length long
+    my $wrap_length = 14;
+
+    my $new_text = "";
+    while (length ($text) >= $wrap_length) {
+	my $line = substr ($text, 0, $wrap_length);
+	$text =~ s/^\Q$line\E//;
+	$line =~ s/\s([^\s]*)$/\n/;
+	$text = $1 . $text;
+	$new_text .= $line;
+    }
+    $new_text .= $text;
+    $text = $new_text;
+}
+    
+sub query {
+
+  gimp_install_procedure("gsdl_title_icon", "create title icons for gsdl",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-10",
+                        "<Toolbox>/Xtns/gsdl_title_icon", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+Gimp::on_net { gsdl_title_icon; };
+exit main;
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/title_icon.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/title_icon.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/title_icon.pl	(revision 10506)
@@ -0,0 +1,399 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# title_icon.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# title_icon.pl generates all the green_title type icons and 
+# collection icons for Greenstone
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp;
+use parsargv;
+use util;
+use unicode;
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_green = "#96c19b";
+my $black = "#000000";
+
+
+local ($cfg_file, $size, $imagefile, $width, $height, $imageheight, $stripecolor, $stripewidth, 
+       $stripe_alignment, $i_transparency, $text, $text_alignment, $filename, $textspace_x, 
+       $textspace_y, $bgcolor, $fontcolor, $fontsize, $minfontsize, $foundry, $fontname, 
+       $fontweight, $fontslant, $fontwidth, $fontspacing, $image_dir, $dont_wrap);
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] macrofile\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -cfg_file file         configuration file containing one or more\n";
+    print STDERR "                          sets of the following options - use to create\n";
+    print STDERR "                          batches of images\n";
+    print STDERR "   -size number           the overall size ratio of the image (i.e. a size\n";
+    print STDERR "                          of 2 will create an image twice the default size)\n";
+    print STDERR "   -image_dir directory   directory to create images in [`pwd`]\n";
+    print STDERR "                          this should be full path to existing directory\n";
+    print STDERR "   -imagefile             filename of image to embed within new icon\n";
+    print STDERR "   -width number          width of icon [150]\n";
+    print STDERR "   -height number         height of icon [44]\n";
+    print STDERR "   -imageheight number    this is the height of the image if the image contains\n";
+    print STDERR "                          an image (like collection icons) [110]\n";
+    print STDERR "   -stripecolor hex_value color of vertical stripe [$gsdl_green]\n";
+    print STDERR "   -stripewidth           width of vertical stripe [40]\n";
+    print STDERR "   -stripe_alignment      alignment of vertical stripe (left or right) [left]\n";
+    print STDERR "   -i_transparency number transparency of image within icon (0 > transparent > 100) [60]\n"; 
+    print STDERR "   -text string           image text\n";
+    print STDERR "   -text_alignment        alignment of text (left or right) [left]\n";
+    print STDERR "   -filename string       filename of resulting image\n";
+    print STDERR "   -textspace_x number    space in pixels between left/right edge of image and\n";
+    print STDERR "                          left/right edge of text [3]\n";
+    print STDERR "   -textspace_y number    space in pixels between top of image and top of\n";
+    print STDERR "                          text [3]\n";
+    print STDERR "   -bgcolor hex_value     background color of icon [$gsdl_green]\n";
+    print STDERR "   -fontcolor hex_value   text color [$black]\n";
+    print STDERR "   -fontsize number       font point size [17]\n";
+    print STDERR "   -minfontsize number    minimum point size font will be reduced to fit image [10]\n";
+    print STDERR "   -foundry string        [*]\n";
+    print STDERR "   -fontname string       [lucida]\n";
+    print STDERR "   -fontweight string     [medium]\n";
+    print STDERR "   -fontslant             [r]\n";
+    print STDERR "   -fontwidth             [*]\n";
+    print STDERR "   -fontspacing           [*]\n";
+    print STDERR "   -dont_wrap             don't attempt to wrap text\n\n";
+}
+
+sub reset_options {
+    $image_dir = "./";
+    $imagefile = "";
+    $width = int (150 * $size);
+    $height = int (44 * $size);
+    $imageheight = int (110 * $size);
+    $stripecolor = $gsdl_green;
+    $stripewidth = int (40 * $size);
+    $stripe_alignment = "left";
+    $i_transparency = 60;
+    $text = "";
+    $text_alignment = "left";
+    $filename = "";
+    $textspace_x = int (3 * $size);
+    $textspace_y = int (3 * $size);
+    $bgcolor = $gsdl_green;
+    $fontcolor = $black;
+    $fontsize = int (17 * $size);
+    $minfontsize = int (10 * $size);
+    $foundry = "*";
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+}
+
+sub gsdl_title_icon {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'cfg_file/.*/', \$cfg_file,
+			 'size/\d+/1', \$size,
+			 'image_dir/.*/./', \$image_dir,
+			 'imagefile/.*/', \$imagefile,
+			 'width/^\d+$/150', \$width,
+			 'height/^\d+$/44', \$height,
+			 'imageheight/^\d+$/110', \$imageheight,
+			 "stripecolor/#[0-9A-Fa-f]{6}/$gsdl_green", \$stripecolor,
+			 'stripewidth/^\d+$/40', \$stripewidth,
+			 'stripe_alignment/^(left|right)$/left', \$stripe_alignment,
+			 'i_transparency/^\d+$/60', \$i_transparency,
+			 'text/.*/', \$text,
+			 'text_alignment/^(left|right)$/left', \$text_alignment,
+			 'filename/.*', \$filename,
+			 'textspace_x/^\d+$/3', \$textspace_x,
+			 'textspace_y/^\d+$/3', \$textspace_y,
+			 "bgcolor/#[0-9A-Fa-f]{6}/$gsdl_green", \$bgcolor,
+			 "fontcolor/#[0-9A-Fa-f]{6}/$black", \$fontcolor,
+			 'fontsize/^\d+$/17', \$fontsize,
+			 'minfontsize/^\d+$/10', \$minfontsize,
+			 'foundry/.*/*', \$foundry,
+			 'fontname/.*/lucida', \$fontname,
+			 'fontweight/.*/medium', \$fontweight,
+			 'fontslant/.*/r', \$fontslant,
+			 'fontwidth/.*/*', \$fontwidth,
+			 'fontspacing/.*/*', \$fontspacing,
+			 'dont_wrap', \$dont_wrap)) {
+	&print_usage();
+	die "title_icon.pl: incorrect options\n";
+    }
+
+    # will create wherever gimp was started up from if we don't do this
+    if ($image_dir eq "./") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+    }
+
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filename !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+
+	    &produce_image ();
+	    if ($status) {last;}
+	}
+
+	close CONF;
+
+    } else {
+
+	&produce_image ();
+
+    }
+}
+
+sub produce_image {
+
+    &adjust_args ();
+    &wrap_text () unless $dont_wrap;
+
+    my $use_image = 0;
+    if ($imagefile =~ /\w/) {
+	if (!-r $imagefile) {
+	    print STDERR "WARNING (title_icon.pl): imagefile '$imagefile cannot be ";
+	    print STDERR "read - $filename will be created without the use of an image file\n";
+	} else {
+	    $use_image = 1;
+	    $height = $imageheight;
+	}
+    }
+
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+	
+    # background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+	
+    # add the background layer
+    gimp_image_add_layer ($image, $backlayer, 0);
+	
+    # set colour of stripe
+    gimp_palette_set_foreground ($stripecolor);
+	
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($image, $backlayer);
+    gimp_selection_none ($image);
+	
+    # fill in stripe
+    if ($stripe_alignment eq "left") {
+	gimp_rect_select ($image, 0, 0, $stripewidth, $height, 0, 0, 0);
+    } else {
+	gimp_rect_select ($image, $width-$stripewidth, 0, $stripewidth, $height, 0, 0, 0);
+    }
+    gimp_bucket_fill ($image, $backlayer, FG_BUCKET_FILL, NORMAL_MODE, 100, 0, 1, 0, 0);
+    gimp_selection_none ($image);
+	
+    # get image file (image goes on opposite side to stripe)
+    if ($use_image) {
+	my $rimage = gimp_file_load (RUN_NONINTERACTIVE, $imagefile, $imagefile);
+	my $rdraw = gimp_image_active_drawable ($rimage);
+	gimp_scale ($rimage, $rdraw, 1, 0, 0, $width-$stripewidth, $height);
+	gimp_edit_copy ($rimage, $rdraw);
+	
+	my $imagelayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+					 "ImageLayer", $i_transparency, NORMAL_MODE);
+	
+	gimp_image_add_layer ($image, $imagelayer, 0);
+	
+	# clear the new layer
+	gimp_selection_all ($image);
+	gimp_edit_clear ($image, $imagelayer);
+	gimp_selection_none ($image);
+	
+	my $flayer = gimp_edit_paste ($image, $imagelayer, 1); 
+	if ($stripe_alignment eq "left") {
+	    gimp_layer_set_offsets($flayer, $stripewidth, 0);
+	    gimp_layer_set_offsets($imagelayer, $stripewidth, 0);
+	} else {
+	    gimp_layer_set_offsets($flayer, 0, 0);
+	    gimp_layer_set_offsets($imagelayer, 0, 0);
+	}
+    }
+	
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+	
+    # set the text if there is any
+    my ($textlayer, $textheight, $textwidth);
+    my $fsize = $fontsize;
+    if (length($text)) {
+	$text =~ s/\\n/\n/gi;
+
+	while (1) {
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, $fsize, 
+				    PIXELS, $foundry, $fontname, $fontweight, $fontslant, 
+				    $fontwidth, $fontspacing);
+	    
+	    # check that text fits within image
+	    $textwidth = gimp_drawable_width($textlayer);
+	    $textheight = gimp_drawable_height($textlayer);
+	    if ((($textwidth + $textspace_x) > $width) || 
+		(($textheight + $textspace_y) > $height)) {
+		if ($fsize < $minfontsize) {
+		    die "Error (title_icon.pl): text '$text' doesn't fit on ${width}x${height} image " .
+			"(minimum font size tried: $minfontsize\n";
+		} else {
+		    gimp_selection_all ($image);
+		    gimp_edit_clear ($image, $textlayer);
+		    gimp_selection_none ($image);
+		    $fsize --;
+		    print STDERR "WARNING (title_icon.pl): '$text' doesn't fit: reducing font size to $fsize\n";
+		}
+	    } else {
+		last;
+	    }
+	}
+	
+	# align text
+	if ($text_alignment eq "left") {
+	    gimp_layer_set_offsets ($textlayer, $textspace_x, $textspace_y);
+	} else {
+	    gimp_layer_set_offsets ($textlayer, ($width-$textwidth)-$textspace_x, $textspace_y);
+	}
+    }
+    
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+	
+    if ($filename =~ /\.gif$/i) {
+	# make indexed colour (may need to do this for 
+	# other formats as well as gif)
+	gimp_convert_indexed ($image, 0, 256);
+    }
+	
+    # save image
+    my $filename = &util::filename_cat ($image_dir, $filename);
+    if ($filename =~ /\.jpe?g$/i) {
+	# gimp_file_save doesn't appear to work properly for jpegs
+	file_jpeg_save (RUN_NONINTERACTIVE, $image, $finishedlayer, 
+			$filename, $filename, 0.8, 0, 1);
+    } else {
+	gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, 
+			$filename, $filename);
+    }
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+
+# adjust arguments that are effected by the size argument
+sub adjust_args {    
+
+    if ($size != 1) {
+	my @size_args = ('width', 'height', 'imageheight', 'stripewidth',
+			 'textspace_x', 'textspace_y', 'fontsize', 'minfontsize');
+	foreach $arg (@size_args) {
+	    $$arg = int ($$arg * $size);
+	}
+    }
+}
+
+sub wrap_text {
+
+    # don't wrap text if it already contains carriage returns
+    return if $text =~ /\n/;
+
+    # the following assumes that all words are less than $wrap_length long
+    my $wrap_length = 14;
+
+    my $new_text = "";
+    while (length ($text) >= $wrap_length) {
+	my $line = substr ($text, 0, $wrap_length);
+	$text =~ s/^$line//;
+	$line =~ s/\s([^\s]*)$/\n/;
+	$text = $1 . $text;
+	$new_text .= $line;
+    }
+    $new_text .= $text;
+    $text = $new_text;
+}
+    
+sub query {
+
+  gimp_install_procedure("gsdl_title_icon", "create title icons for gsdl",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-10",
+                        "<Toolbox>/Xtns/gsdl_title_icon", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+sub net {
+  gsdl_title_icon;
+}
+
+exit main;
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/title_icon_g12.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/title_icon_g12.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gimp/title_icon_g12.pl	(revision 10506)
@@ -0,0 +1,380 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# title_icon.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999-2001 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# title_icon.pl
+#
+# This script generates collection title icons for greenstone.
+#
+# This version has been rewritten for the GIMP Version 1.2.  You
+# should be able to run it if you install gimp 1.2 with perl support.
+# In Debian this means running "apt-get install gimp1.2 gimp1.2perl"
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp ":auto";
+use Gimp::Fu; 
+
+use util;
+use unicode;
+
+# set trace level to watch functions as they are executed
+#Gimp::set_trace(TRACE_ALL);
+#Gimp::set_trace(TRACE_CALL);
+
+my $gsdl_green = "#96c19b";
+my $black = "#000000";
+my $white      = "#FFFFFF";
+
+my ($current_dir) = `pwd`;
+chomp($current_dir);
+
+
+my ($text, $filename, $image_dir, $size, $width, $height,
+    $stripecolor, $stripewidth, $stripe_alignment, $textspace_x,
+    $textspace_y, $dont_wrap, $imagefile, $imageheight, $i_transparency,
+    $bgcolor, $fontcolor, $fontsize, $minfontsize, $text_alignment,
+    $foundry, $fontname, $fontweight, $fontslant, $fontwidth,
+    $fontspacing, $cfg_file);
+
+sub reset_options {
+    $image_dir = "./";
+    $imagefile = "";
+    $width = int (150 * $size);
+    $height = int (44 * $size);
+    $imageheight = int (110 * $size);
+    $stripecolor = $gsdl_green;
+    $stripewidth = int (40 * $size);
+    $stripe_alignment = "left";
+    $i_transparency = 60;
+    $text = "";
+    $text_alignment = "left";
+    $filename = "";
+    $textspace_x = int (3 * $size);
+    $textspace_y = int (3 * $size);
+    $bgcolor = $gsdl_green;
+    $fontcolor = $black;
+    $fontsize = int (17 * $size);
+    $minfontsize = int (10 * $size);
+    $foundry = "*";
+    $fontname = "lucida";
+    $fontweight = "medium";
+    $fontslant = "r";
+    $fontwidth = "*";
+    $fontspacing = "*";
+}
+
+sub gsdl_title_icon {
+
+    ($text, $filename, $image_dir, $size, $width, $height,
+     $stripecolor, $stripewidth, $stripe_alignment, $textspace_x,
+     $textspace_y, $dont_wrap, $imagefile, $imageheight, $i_transparency,
+     $bgcolor, $fontcolor, $fontsize, $minfontsize, $text_alignment,
+     $foundry, $fontname, $fontweight, $fontslant, $fontwidth,
+     $fontspacing, $cfg_file) = @_;
+
+    # Create images using a configuration file
+    if ($cfg_file =~ /\w/) {
+	
+	open (CONF, $cfg_file) || die "couldn't open cfg_file $cfg_file\n";
+	while (1) {
+
+	    &reset_options ();
+	
+	    # read image configuration entry
+	    my $status = &read_config_entry (CONF);
+	    if ($filename !~ /\w/) {
+		if ($status) {last;}
+		else {next;}
+	    }
+	    &produce_image ();
+	    if ($status) {last;}
+	}
+	close CONF;
+    }
+
+    # Create a single image from the parameters we have
+    else {
+	&produce_image ();
+    }
+
+}
+
+sub produce_image {
+
+    &adjust_args ();
+    &wrap_text () unless $dont_wrap;
+
+    my $use_image = 0;
+    if ($imagefile =~ /\w/) {
+	if (!-r $imagefile) {
+	    print STDERR "WARNING (title_icon.pl): imagefile '$imagefile cannot be ";
+	    print STDERR "read - $filename will be created without the use of an image file\n";
+	} else {
+	    $use_image = 1;
+	    $height = $imageheight;
+	}
+    }
+
+    # create the image
+    my $image = gimp_image_new ($width, $height, RGB_IMAGE);
+	
+    # create and add the background layer
+    my $backlayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+				    "BGLayer", 100, NORMAL_MODE);
+    gimp_image_add_layer ($image, $backlayer, 0);
+	
+    # clear the background
+    gimp_selection_all ($image);
+    gimp_edit_clear ($backlayer);
+    gimp_selection_none ($image);
+	
+    # fill in stripe
+    if ($stripewidth > 0) {
+        gimp_palette_set_foreground ($stripecolor);
+	if ($stripe_alignment eq "left") {
+	  gimp_rect_select ($image, 0, 0, $stripewidth, $height, 0, 0, 0);
+	} else {
+	  gimp_rect_select ($image, $width-$stripewidth, 0, $stripewidth, $height, 0, 0, 0);
+	}
+	gimp_bucket_fill ($backlayer, FG_BUCKET_FILL, NORMAL_MODE, 100, 0, 1, 0, 0);
+	gimp_selection_none ($image);
+    }
+
+    # get image file (image goes on opposite side to stripe)
+    if ($use_image) {
+	my $rimage = gimp_file_load (RUN_NONINTERACTIVE, $imagefile, $imagefile);
+	my $rdraw = gimp_image_active_drawable ($rimage);
+	gimp_scale ($rdraw, 1, 0, 0, $width-$stripewidth, $height);
+	gimp_edit_copy ($rdraw);
+	
+	# add the background image layer
+	my $imagelayer = gimp_layer_new ($image, $width, $height, RGB_IMAGE, 
+					 "ImageLayer", $i_transparency, NORMAL_MODE);
+	gimp_image_add_layer ($image, $imagelayer, 0);
+	
+	# clear the new layer
+	gimp_selection_all ($image);
+	gimp_edit_clear ($imagelayer);
+	gimp_selection_none ($image);
+	
+	my $flayer = gimp_edit_paste ($imagelayer, 1); 
+	if ($stripe_alignment eq "left") {
+	    gimp_layer_set_offsets($flayer, $stripewidth, 0);
+	    gimp_layer_set_offsets($imagelayer, $stripewidth, 0);
+	} else {
+	    gimp_layer_set_offsets($flayer, 0, 0);
+	    gimp_layer_set_offsets($imagelayer, 0, 0);
+	}
+    }
+
+    # flatten the image (otherwise the text will be "behind" the image)
+    $backlayer = gimp_image_flatten ($image);
+
+    # set colour of text
+    gimp_palette_set_foreground ($fontcolor);
+	
+    # set the text if there is any
+    my ($textlayer, $textheight, $textwidth);
+    my $fsize = $fontsize;
+    if (length($text)) {
+	$text =~ s/\\n/\n/gi;
+
+	while (1) {
+	    $textlayer = gimp_text ($image, $backlayer, 0, 0, $text, 0, 1, $fsize, 
+				    PIXELS, $foundry, $fontname, $fontweight, $fontslant, 
+				    $fontwidth, $fontspacing, "*", "*");
+	
+	    # check that text fits within image
+	    $textwidth = gimp_drawable_width($textlayer);
+	    $textheight = gimp_drawable_height($textlayer);
+	    if ((($textwidth + $textspace_x) > $width) || 
+		(($textheight + $textspace_y) > $height)) {
+		if ($fsize < $minfontsize) {
+		    die "Error (title_icon.pl): text '$text' doesn't fit on ${width}x${height} image " .
+			"(minimum font size tried: $minfontsize\n";
+		} else {
+		    gimp_selection_all ($image);
+		    gimp_edit_clear ($image, $textlayer);
+		    gimp_selection_none ($image);
+		    $fsize --;
+		    print STDERR "WARNING (title_icon.pl): '$text' doesn't fit: reducing font size to $fsize\n";
+		}
+	    } else {
+		last;
+	    }
+	}
+	
+	# align text
+	if ($text_alignment eq "left") {
+	    gimp_layer_set_offsets ($textlayer, $textspace_x, $textspace_y);
+	} else {
+	    gimp_layer_set_offsets ($textlayer, ($width-$textwidth)-$textspace_x, $textspace_y);
+	}
+    }
+
+    # flatten the image
+    my $finishedlayer = gimp_image_flatten ($image);
+	
+    if ($filename =~ /\.gif$/i) {
+	# make indexed colour (may need to do this for 
+	# other formats as well as gif)
+	gimp_convert_indexed ($image, 0, 256);
+    }
+	
+    # save image
+    my $filename = &util::filename_cat ($image_dir, $filename);
+    gimp_file_save (RUN_NONINTERACTIVE, $image, $finishedlayer, $filename, $filename);
+}
+
+# returns 1 if this is the last entry,
+sub read_config_entry {
+    my ($handle) = @_;
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	next unless $line =~ /\w/;
+	my @line = ();
+	if ($line =~ /^\-+/) {return 0;}
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	while ($line =~ s/\s*(\"[^\"]*\"|\'[^\']*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute any environment variables
+		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+	if (scalar (@line) == 2 && defined ${$line[0]}) {
+	    ${$line[0]} = $line[1];
+	}
+    }
+    return 1;
+}
+
+# adjust arguments that are effected by the size argument
+sub adjust_args {
+
+    if ($size != 1) {
+        $width *= $size;
+        $height *= $size;
+	$imageheight *= $size;
+	$stripewidth *= $size;
+	$textspace_x *= $size;
+	$textspace_y *= $size;
+	$fontsize *= $size;
+	$minfontsize *= $size;
+    }
+}
+
+sub wrap_text {
+
+    # don't wrap text if it already contains carriage returns
+    return if $text =~ /\n/;
+
+    # the following assumes that all words are less than $wrap_length long
+    my $wrap_length = 14;
+
+    my $new_text = "";
+    while (length ($text) >= $wrap_length) {
+	my $line = substr ($text, 0, $wrap_length);
+	$text =~ s/^$line//;
+	$line =~ s/\s([^\s]*)$/\n/;
+	$text = $1 . $text;
+	$new_text .= $line;
+    }
+    $new_text .= $text;
+    $text = $new_text;
+}
+
+
+register("gsdl_title_icon", 
+	 "Create title icons for gsdl (gimp version 1.2)",
+	 "", 
+	 "Stefan Boddie (1.0) and Gordon Paynter (1.2)",
+	 "Copyright 1999-2001 The New Zealand Digital Library Project",
+	 "2000-03-10",
+	 "<Toolbox>/Xtns/gsdl_title_icon", 
+	 "*",
+	 [
+           [PF_STRING, "text",      "Text appearing on icon", "greenstone collection"],
+
+           [PF_STRING, "filename",  "Output file", "title_icon.png"],
+           [PF_STRING, "image_dir", "Directory to create images in", $current_dir],
+
+           [PF_INT,    "size_ratio", "Size factor: a factor of 2 doulbles image size",  1],
+           [PF_INT,    "width",      "Width of the icon",  150],
+           [PF_INT,    "height",     "Height of the icon", 44],
+
+           [PF_STRING, "stripecolor", "Colour of the stripe", $gsdl_green],
+           [PF_INT,    "stripewidth", "Width of the stripe",  40],
+           [PF_STRING, "stripealign", "Alignment of stripe (left or right)", "left"],
+
+           [PF_INT,    "text_x_offset",    "Distance from left of image to text", 3],
+           [PF_INT,    "text_y_offset",    "Distance from top of image to text",  3],
+           [PF_STRING, "dont_wrap",        "don't attempt to wrap text", ""],
+
+           [PF_STRING, "imagefile",   "Filename of background image", ""],
+           [PF_INT,    "imageheight", "Height of background image", 110],
+           [PF_INT,    "imagetransp", "Transparency of background image (1-100)", 60],
+
+#           [PF_STRING, "fgcolor",     "Foreground colour (top) of bar", $white],
+           [PF_STRING, "bgcolor",     "Background colour (bottom) of bar", $gsdl_green],
+           [PF_STRING, "fontcolor",   "Colour of text on bar", $black],
+           [PF_INT,    "fontsize",    "Font size",    17],
+           [PF_INT,    "minfontsize", "Minimum font size if scaling required",    10],
+
+           [PF_STRING, "alignment",     "Alignment of text on the icon (left or right)", "left"],
+
+           [PF_STRING, "foundry",     "Font foundry", "*"],
+           [PF_STRING, "fontname",    "Font name",    "lucida"],
+           [PF_STRING, "fontweight",  "Font weight",  "medium"],
+           [PF_STRING, "fontslant",   "Font slant",   "r"],
+           [PF_STRING, "fontwidth",   "Font width",   "*"],
+           [PF_STRING, "fontspacing", "Font spacing", "*"],
+
+           [PF_STRING, "cfg_file",    "Configuration file", ""]
+
+         ], 
+         \&gsdl_title_icon);
+
+
+exit main;
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/grab_collection.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/grab_collection.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/grab_collection.pl	(revision 10506)
@@ -0,0 +1,570 @@
+#!/usr/bin/perl -w
+
+
+# Both this script and its associated process_html.pl were written by
+# Marcel ?, while a student at Waikato University. Unfortunately he
+# was very new to perl at the time so the code is neither as clean nor
+# as fast as it could be (I've cleaned up a few of the more serious
+# bottlenecks -- it could do with alot more work though).  The code
+# does work though, if a little slowly. It's not ready for primetime
+# however and is included in the Greenstone source tree mostly so that
+# I don't lose it. -- Stefan - 24 Jul 2001
+
+
+# This script will download an entire collection (and its associated pictures and files) 
+# and store them in a temporary directory ($outputdir). 
+# A second script (process_html.pl) can be then be used to 'rebuild' the collection and link all the
+# downloaded pages and pictures together into a usable static collection.
+
+# This script will generate a number of text files required by the second script
+# and for possible recovery, namely:
+# - links.txt        - contains all the http links that were downloaded
+# - images.txt       - contains a list of all the images that were downloaded  
+# - image_dirs.txt   - contains a list of all the image-prefixes that need to be wiped from the html files
+#                      (otherwise you won't get to see any pictures)
+
+# Both this script and the html processing script have a recovery feature built in, they can continue from wherever
+# they left off, but this only works if $outputdir and $finaldir are set to different values.
+   
+# This is where all the downloaded html files end up, eg. 'temp_html/'
+my $outputdir  = 'temp_html/';
+# This is where all the processed html files (and the pictures) will end up eg. 'my_static_collection/'
+my $finaldir   = 'envl_collection/';
+
+# This is where we start our mirroring
+$address = 'http://nowhere.com/cgi-bin/library?a=p&p=about&c=demo&u=1';
+
+
+# whatever is specified in $option will be attached to the end of each html link before it is downloaded.
+# eg. "&u=1" to disable various features in the greenstone collections that are not needed with a static
+#            collection.
+# another example : "&l=nl" to set the entire collection to dutch (NetherLands :)  
+my $option = "&u=1";
+
+# Most OS have a limit on the maximum amount of files per directory (or folder).
+# A static collection can easily contain >3000 html files. Putting all those files
+# into one single directory is just asking for trouble. It's also very unwieldy ;^)
+# Hence...this value will set how much html files will be stored in one directory. 
+# These directories themselves will be numbered, 
+# so if $dir_entries = 500 then the directories will be "0/", "500/", "1000/", "1500/", "2000/", etc. 
+my $dir_entries = 250;
+
+# Occasionally a page occurs which contains no data (because &cl is not set) This option fixes that. 
+my $fix_empty_pages = "&cl=CL1";
+
+# These are the files that wget will download.
+# more can be added if necessary.
+my @graphic_formats = ('.gif','.jpg','.bmp','.png','.pdf','.mov','.mpeg','.jpeg','.rm');
+
+# ---------------------------------------[ System specific options ]----------------------------------------------------
+
+# The lynx variable specifies the command line for the lynx web browser
+# -- This is what I use under dos/win32
+# my $lynx = 'e:\lynx_w32\lynx -cfg=e:\lynx_w32\lynx.cfg';
+
+# -- This is what I use under linux
+my $lynx = 'lynx';
+
+# and the same for the wget utility
+my $wget = 'wget';
+
+# NB: There is one other linux specific command all the way at the end of this script, where I've used 'cp' to copy a file.       
+
+# Another NB: When saving the dl-ed html files to disk, I've set lynx to dump the html-source to the standard output,
+#             which I then simply redirect to a target file, BUT
+#             this does not work under DOS/win32. Redirecting standard output in a script causes it to be displayed on
+#             the screen instead. The easiest way to get around this I found was by doing the actual redirection in a simple
+#             batch file (say grab.bat), which contains the following line:
+#             @e:\lynx_w32\lynx -cfg=e:\lynx_w32\lynx.cfg -dump -source "%1" > %2 
+#
+#             Then replace line nr 326 -> 'system ("$kommand > $target");' with 'system("grab.bat $address $target");'
+#             Not a very elegant solution, but it works :) 
+
+#------------------------------------------------------------------------------------------------------------------------
+
+my %image_list;
+my $image_pointer = 0;
+
+my %linkz_list;
+my %short_linkz_list;
+my $linkz_pointer = 0;
+
+my %image_dirs_list;
+my $image_dirs_pointer = 0;
+
+my $numberdir = 0;
+
+my $start_time = (times)[0];
+
+# check if directories exist and create them if necessary..
+if ((-e $outputdir)&&(-d $outputdir)) 
+{ 
+    print " ** ",$outputdir," directory already exists..\n"; 
+}
+else
+{
+    print " ** Creating ",$outputdir," directory..\n";
+    mkdir($outputdir, 0777) or die " Cannot create output directory: $!\n";
+}
+
+if ((-e $finaldir)&&(-d $finaldir))
+{ 
+    print " ** ",$finaldir," directory already exists..\n";
+}
+else
+{
+    print " ** Creating ",$finaldir," directory..\n";
+    mkdir($finaldir, 0777) or die " Cannot create final directory: $!\n";
+}
+
+#-----------------------------------------------------------------------------------------------
+# No need to start from scratch everytime, we can recover/continue from wherever we left off
+# simply by checking which html files have been created
+#-----------------------------------------------------------------------------------------------
+
+$linknumber    = 0;                    # used to name/number the dl-ed html files
+
+my $failed     = 0;
+while ($failed == 0)
+{
+    if ($linknumber % $dir_entries == 0) 
+	{
+	    if (!((-e $outputdir.$linknumber)&&(-d $outputdir.$linknumber)))
+	    {
+		$failed++;
+		mkdir($outputdir.$linknumber, 0777) or print " ** Cannot create ",$outputdir.$linknumber, "!: $!\n";
+	    }
+	    $numberdir = $linknumber;
+	}
+
+    $check_file = $outputdir.$numberdir."/".$linknumber.".html";
+    if ((-e $check_file)&&($failed == 0)) 
+    { 
+	$linknumber++;
+    } 
+    else
+    {
+	$failed++;
+	# I'm subtracting 1 from the starting link, 
+	# just in case it only loaded half the page ;^)
+	if($linknumber>0) 
+	{ 
+	    $linknumber--; 
+	}
+	print " Will start downloading at number $linknumber \n";
+    }
+}
+
+# if we're starting from scratch, then we might as well nuke the links file
+#if ($linknumber == 0) 
+#{ 
+#    print " Starting from scratch - clobbering the old text files...\n";
+#    if (-e 'links.txt')
+#    {
+#	print "   Removing links.txt...\n";   
+#	unlink <links.txt> or print " ** Cannot delete links textfile: $!\n";
+#    }
+#    if (-e 'images.txt')
+#    {
+#	print "   Removing images.txt...\n";
+#	unlink <images.txt> or print " ** Cannot delete images textfile: $!\n";
+#    }
+#    if (-e 'image_dirs.txt')
+#    {
+#	print "   Removing image_dirs.txt...\n";
+#	unlink <image_dirs.txt> or print " ** Cannot delete image_dirs textfile: $!\n";
+#    }
+#}
+
+# if we're NOT starting from scratch, then read in old links from links text file
+# and grab the old image-links as well...
+if ($linknumber != 0)
+{
+    # load the old links from links.txt, if it doesn't exist, then give up :(
+    my $this = "";
+    my $that = "";
+    open (CHECK, "links.txt") or die " ** Cannot find/open links.txt file!: $! **\n";
+    while(eof CHECK == 0)
+    {
+	while($this ne "\n")
+	{
+	    read CHECK, $this ,1;
+	    $that = $that.$this;   
+	}
+	$linkz_list[$linkz_pointer] = $that;
+	
+	for my $search(0 .. (length($that) - 3))
+	{
+	    if((substr($that, $search, 3) eq '?a=')||(substr($that, $search, 3) eq '&a='))
+	    {
+		$short_linkz_list[$linkz_pointer] = substr($that, $search);
+		last;
+	    }
+	}
+	$linkz_pointer++;
+	$that = ""; $this = "";
+    }
+    close(CHECK);
+    print "- I found ",($#linkz_list + 1)," links in links.txt -\n";
+    
+    #make sure that we start dl-ing the correct first page 
+    $address = $linkz_list[$linknumber];
+
+    # load the old image links from image.txt (if it doesn't exist, no big deal ;)
+    my $im_this = "";
+    my $im_that = "";
+    open (IMAGES, "images.txt") || print " ** Cannot find/open images.txt file! : $! **\n";
+    while(eof IMAGES == 0)
+    {
+	while($im_this ne "\n")
+	{
+	    read IMAGES, $im_this ,1;
+	    $im_that = $im_that.$im_this;   
+	}
+	$image_list[$image_pointer] = $im_that;
+	$image_pointer++;
+	$im_that = ""; $im_this = "";
+    }
+    close(IMAGES);
+    print "- I found ",($#image_list + 1)," picture-links in images.txt -\n";
+
+    #..and last but not least, load any image_dirs from image_dirs.txt
+    # again, if its not there, no big deal :)
+    my $imd_this = "";
+    my $imd_that = "";
+    open (IMAGE_DIR, "image_dirs.txt") || print " ** Cannot find/open image_dirs.txt file!: $! **\n";
+    while(eof IMAGE_DIR == 0)
+    {
+	while($imd_this ne "\n")
+	{
+	    read IMAGE_DIR, $imd_this ,1;
+	    $imd_that = $imd_that.$imd_this;   
+	}
+	$image_dirs_list[$image_dirs_pointer] = $imd_that;
+	$image_dirs_pointer++;
+	$imd_that = ""; $imd_this = "";
+    }
+    close(IMAGE_DIR);
+    print "- I found ",($#image_dirs_list + 1)," picture directories in image_dirs.txt -\n";
+}
+
+#  Just keep going till we can find no more new links
+while(($#linkz_list < 0)||($#linkz_list+1 > $linknumber)) 
+{
+
+    # This line specifies the command line for the lynx web browser
+    my $kommand = $lynx.' -dump -image_links "'.$address.'"';
+
+    # dump page into text-array and find starting-point of the references/links
+    chomp(@data=`$kommand`);
+    for my $i(0 .. $#data)
+    {
+	if ($data[$i] eq "References") {
+	    $here = $i;}
+    }
+    $here = $here+2;
+
+    # process references/links
+    for $i($here .. $#data){
+
+	$its_an_image = 0;	     	
+    
+	#chop-off refs leading number&spaces (eg. '1. http://www.cs.waikato.ac.nz')
+	#                                          ^^^
+	
+#	$temp = substr($data[$i],3);
+#	@temp = split(/ /, $temp, 2);
+    
+	#check if the last 4 characters of the link equal .gif .jpg .png .bmp .pdf .mov .mpeg etc etc
+    
+#	for my $g(0 .. $#graphic_formats)
+#	{
+#	    if(substr($temp[1],(length($graphic_formats[$g]) * -1)) eq $graphic_formats[$g])
+#	    {
+#		$its_an_image = 1;
+#	    }
+#	}
+
+	$data[$i] =~ s/^\s*\d+\.\s+//;
+	if ($data[$i] =~ /\.(gif|jpe?g|png|bmp|pdf|mov|mpe?g|rm)$/i) {
+	    $its_an_image = 1;
+	}
+
+	# ignore mailto urls
+	if ($data[$i] !~ /mailto:/i) {
+	
+	    #----------- the link is NOT an image ----------------		
+	    if ($its_an_image == 0)
+	    { 
+		&its_a_link($data[$i], $outputdir);
+	    }
+
+	    #----------- the link IS an image ----------------
+	    if ($its_an_image != 0)
+	    { 
+		&its_an_image($data[$i], $finaldir); 
+	    }
+	}
+    }	
+
+    # save the web page to disk (in the appropriate numbered directory)
+    $kommand = $lynx.' -dump -source "'.$address.'"';
+
+    if ($linknumber % $dir_entries == 0) 
+    {
+	if ((-e $outputdir.$linknumber)&&(-d $outputdir.$linknumber))
+	{
+	    print " ** ",$outputdir.$linknumber, " - Directory allready exists.\n";
+	}
+	else
+	{
+	    mkdir($outputdir.$linknumber, 0777) or print " ** Cannot create ",$outputdir.$linknumber, "!: $!\n";
+	    mkdir($finaldir.$linknumber, 0777)  or print " ** Cannot create ",$outputdir.$linknumber, "!: $!\n";
+	}
+	$numberdir = $linknumber;
+    }
+    my $target = $outputdir.$numberdir."/".$linknumber.".html";
+
+    #---------------------------------------------------------------------------------------------------------------
+    # NOTE: This next command will NOT work under win32/dos, as redirecting standard output in a script causes it to
+    #       be dumped straight to the screen as opposed to into the target file.
+    #---------------------------------------------------------------------------------------------------------------
+    system ("$kommand > $target");
+    #---------------------------------------------------------------------------------------------------------------
+
+    print " Saved $target\n";
+
+    $linknumber++;
+
+    $address = $linkz_list[$linknumber];
+}
+
+my $end_time = (times)[0];
+
+print "\n\n\n *----------------------------*\n";
+print " |  Whew! Task completed! :-D |\n";
+print " *----------------------------*\n";
+printf"  Script took %.2f CPU seconds to complete ;^)\n", $end_time - $start_time;
+print "\n\n"; 
+print "  Now execute the  process_html.pl  script to link the downloaded collection together.\n";
+print "  Please do make sure that it is executed with the same options as this script ;-)\n";
+
+sub its_a_link 
+{
+    local($found) = @_;
+#    local($ok = 0, $kommand);
+    local($kommand);
+    local $short_link = "";
+
+    return if ($found =~ /\#.*$/);
+
+    # attach the custom options
+    $found .= $option;
+    
+    #little bit of trickery here - check if there is a &d= option present in the link
+    #if there is, then wipe the &cl= option!
+    #This should cut down multiple copies by 75%!!
+    
+    #but, if there is no &d option, and the &cl option is not set, then we have to set the &cl option to something
+    #otherwise we get pages which contain no data :\
+
+    if ($found =~ /[&\?]a=d/) {
+	if ($found =~ /[&\?]d=/) {
+	    $found =~ s/[&\?]cl=[^&]*//;
+	} elsif ($found !~ /[&\?]cl=/) {
+	    $found .= $fix_empty_pages;
+	}
+    }
+
+    # we also want to sort out any xxx.pr OIDs that we come across
+    $found =~ s/([&\?](cl|d)=.*?)\.\d+\.pr/$1/g;
+
+    # attach the EOL character.
+    $found = $found."\n";
+
+
+    # the hard way !!!
+#    for my $search(0 .. (length($found) - 3))
+#    {
+#	if((substr($found, $search, 3) eq '?d=')||(substr($found, $search, 3) eq '&d='))
+#	{
+#	    for my $second_search(0 .. (length($found) - 4))  
+#	    {
+#		if((substr($found, $second_search, 4) eq '?cl=')||(substr($found, $second_search, 4) eq '&cl='))
+#		{
+#		    for my $third_search(($second_search + 3) .. (length($found) - 1))
+#		    {
+#			if((substr($found, $third_search, 1)) eq '&')
+#			{
+#			    substr($found, $second_search, $third_search - $second_search) = ""; 
+#			    last;
+#			}
+#		    }
+#		    last;
+#		}
+#	    } 
+#	    last;
+#	}
+#	else
+#	{
+#	    if( $search == (length($found) - 3))
+#	    {
+#		for my $second_search(0 .. (length($found) - 4))  
+#		{
+#		    if((substr($found, $second_search, 4) eq '?cl=')||(substr($found, $second_search, 4) eq '&cl='))
+#		    {
+#			for my $third_search(($second_search + 3) .. (length($found) - 1))
+#			{
+#			    if((substr($found, $third_search, 1)) eq '&')
+#			    {
+#				if (substr($found, $second_search, $third_search - $second_search) eq '&cl=')
+#				{
+#				    substr($found, $second_search, $third_search - $second_search) = $fix_empty_pages;	
+#				}
+#				last;
+#			    }
+#			}
+#			last;
+#		    }
+#		} 
+#	    }
+#	}
+#    }
+    
+    # grab the last part of the link (ignoring the start and the &e option)
+#    for my $search(0 .. (length($found) - 3))
+#    {
+#	if((substr($found, $search, 3) eq '?a=')||(substr($found, $search, 3) eq '&a='))
+#	{
+#	    $short_link = substr($found, $search);
+#	    last;
+#	}
+#    }
+
+    ($short_link) = $found =~ /\?(.*)$/;
+    $short_link =~ s/(^|&)e=[^&]*/$1/;
+
+    
+    # this filters out multiple copies of for example the help page, which has #something at the end of its links
+    # now do this first with regular expression above -- Stefan
+
+#    for my $search(0 .. length($found))
+#    {
+#	if ((substr($found, $search, 1)) eq '#')
+#	{
+#	    $ok++;
+#	    last;
+#	}
+#    }
+ 
+
+   
+    # compare the found link to the links we've stored in the arrays (compares both full link and partial link)
+    for my $search(0 .. $#linkz_list)
+    {
+	return if ($found eq $linkz_list[$search]);
+	return if ($short_link eq $short_linkz_list[$search]);
+    }
+		    
+    # if found link is not in links array, add it
+    open (DUMP, ">>links.txt") or die " ** Can't open links.txt!: $!\n";
+    print DUMP $found;
+    close(DUMP);
+    
+    $linkz_list[$linkz_pointer] = $found;
+    $short_linkz_list[$linkz_pointer] = $short_link;
+    $linkz_pointer++;
+}
+
+sub do_image_dirs
+{
+    local($found) = @_;
+    my $count = 0;
+    my @br_index;
+    my $image_dir = "";
+    my $new_dir = 0;
+
+    for my $search(1 .. (length($found) - 1 ))
+    {
+	$bracket = substr($found, ($search * - 1), 1);
+	if ($bracket eq '/')
+	{
+	    $count++;
+	    $br_index[$count] = $search;
+	}
+	if($count == 2) 
+	{
+	    $image_dir = substr($found, ($br_index[2] * -1) , ($br_index[2] - $br_index[1]));
+	}
+    }
+    
+    my $dirs_to_wipe = substr($found, $br_index[$#br_index - 2] * - 1, $br_index[$#br_index - 2] - $br_index[2] + 1)."\n";
+    
+    for my $counter(0 .. $#image_dirs_list)
+    {
+	if($dirs_to_wipe eq $image_dirs_list[$counter])
+	{
+	    $new_dir++;
+	}
+    }
+    
+    if ($new_dir == 0)
+    {
+	open (IMAGE_DIRS, ">>image_dirs.txt") or die " ** Can't open image_dirs.txt!: $!\n";
+	print IMAGE_DIRS $dirs_to_wipe;
+	close(IMAGE_DIRS);
+	$image_dirs_list[$image_dirs_pointer] = $dirs_to_wipe;
+	$image_dirs_pointer++;
+    }
+
+    print "   ",substr($finaldir, 0 ,length($finaldir) - 1).$image_dir.substr($found, ($br_index[1] * - 1), length($found) - (length($found) - $br_index[1])),"\n";	    
+    
+    return $image_dir;
+}
+
+sub its_an_image 
+{
+    local($found, $outpdir) = @_;
+    local($kommand);
+    my $new = 0;
+    
+    my $temp_found = $found . "\n";
+
+    # check if the image is in the list
+    for my $counter(0 .. $#image_list)
+    {
+	if($temp_found eq $image_list[$counter])
+	{
+	    $new++;
+	}
+    }
+    
+    # only download the image if its not in the list..
+    if($new == 0)
+    {    
+	my $image_dir = &do_image_dirs;
+	my $temp_outputdir = $outpdir;
+	if (substr($temp_outputdir, -1, 1) eq "/")
+	{
+	    substr($temp_outputdir, -1, 1) = "";
+	}
+	
+	# wget is set to 'q - quiet' and 'nc - dont clobber existing files'
+	$kommand = $wget.' -qnc --directory-prefix='.$temp_outputdir.$image_dir.' "'.$found.'"';
+	system ("$kommand");
+        
+	open (IMAGES, ">>images.txt") or die " ** Can't open images.txt!: $!\n";
+	print IMAGES $temp_found;
+	close(IMAGES);
+	
+	$image_list[$image_pointer] = $temp_found;
+	$image_pointer++;
+	
+        # grab corresponding ON pictures for navigation bar if we've just dl-ed the OFF picture
+	if(substr($found , -6) eq "of.gif") 
+	{
+	    substr($found, -6, 6) = "on.gif";
+	    &its_an_image($found, $outpdir);
+	}
+    }    
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gsConvert.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gsConvert.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gsConvert.pl	(revision 10506)
@@ -0,0 +1,1212 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# gsConvert.pl -- convert documents to HTML or TEXT format
+#
+# 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-2002 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.
+#
+###########################################################################
+
+# gsConvert.pl converts documents in a range of formats to HTML or TEXT
+# by exploiting third-party programs.  The sources of these are usually found
+# in the $GSDLHOME/packages directory, and the executables should live in
+# $GSDLHOME/bin/$GSDLOS (which is on the search path).
+#
+# Currently, we can convert the following formats by using external
+# conversion utilities:
+# Microsoft Word (versions 2,6,7 [==95?], 8[==97?], 9[==2000?]), RTF,
+# Adobe PDF, PostScript, MS PowerPoint (95 and 97), and MS Excel (95 and 97).
+#
+# We can try to convert any file to text with a perl implementation of the
+# UNIX strings command.
+#
+# We try to convert Postscript files to text using "gs" which is often on
+# *nix machines. We fall back to performing weak text extraction by using
+# regular expressions.
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use util;
+use Cwd;
+use File::Basename;
+
+# Are we running on WinNT or Win2000 (or later)?
+my $is_winnt_2000=eval {require Win32; return (Win32::IsWinNT()); return 0;};
+if (!defined($is_winnt_2000)) {$is_winnt_2000=0;}
+
+my $use_strings;
+my $pdf_complex;
+my $pdf_nohidden;
+my $pdf_zoom;
+my $pdf_ignore_images;
+my $pdf_allow_images_only;
+my $windows_scripting;
+
+sub print_usage
+{
+    print STDERR "\n";
+    print STDERR "gsConvert.pl: Converts documents in a range of formats to html\n";
+    print STDERR "              or text using third-party programs.\n\n";
+    print STDERR "  usage: $0 [options] filename\n";
+    print STDERR "  options:\n\t-type\tdoc|dot|pdf|ps|ppt|rtf|xls\t(input file type)\n";
+    print STDERR "\t-errlog\t<filename>\t(append err messages)\n";
+    print STDERR "\t-output\tauto|html|text|pagedimg-jpg|pagedimg-gif|pagedimg-png\t(output file type)\n";
+    print STDERR "\t-timeout\t<max cpu seconds>\t(ulimit on unix systems)\n";
+    print STDERR "\t-use_strings\tuse strings to extract text if conversion fails\n";
+    print STDERR "\t-windows_scripting\tuse windows script when converting Microsoft Word and PPT via VB script\n";
+    print STDERR "\t-pdf_complex\tuse complex output when converting PDF to HTML\n";
+    print STDERR "\t-pdf_nohidden\tDon't attempt to extract hidden text from PDF files\n";
+    print STDERR "\t-pdf_ignore_images\tdon't attempt to extract images when\n";
+    print STDERR "\t\tconverting PDF to HTML\n";
+    print STDERR "\t-pdf_allow_images_only\tallow images only (continue even if no text is present when converting to HTML)\n";
+    print STDERR "\t-pdf_zoom\tfactor by which to zoom PDF (only useful if\n";
+    print STDERR "\t\t-pdf_complex is set\n";
+    exit(1);
+}
+
+my $faillogfile="";
+my $timeout=0;
+
+sub main
+{
+    my (@ARGV) = @_;
+    my ($input_type,$output_type,$verbose);
+
+    # read command-line arguments
+    if (!parsargv::parse(\@ARGV,
+			 'type/(doc|dot|pdf|ps|ppt|rtf|xls)/', \$input_type,
+			 '/errlog/.*/', \$faillogfile,
+			 'output/(auto|html|text|pagedimg).*/', \$output_type,
+			 'timeout/\d+/0',\$timeout,
+			 'verbose/\d+/0', \$verbose,
+			 'use_strings', \$use_strings,
+			 'windows_scripting',\$windows_scripting,
+			 'pdf_complex', \$pdf_complex,
+			 'pdf_ignore_images', \$pdf_ignore_images,
+			 'pdf_allow_images_only', \$pdf_allow_images_only,
+			 'pdf_nohidden', \$pdf_nohidden,
+			 'pdf_zoom/\d+/2', \$pdf_zoom
+			 ))
+    {
+	print_usage();
+    }
+    
+  
+    # Make sure the input file exists and can be opened for reading
+    if (scalar(@ARGV!=1)) {
+	print_usage();
+    }
+
+    my $input_filename = $ARGV[0];
+    if (!-r $input_filename) {
+	print STDERR "Error: unable to open $input_filename for reading\n";
+	exit(1);
+    }
+
+    # Deduce filenames
+    my ($tailname,$dirname,$suffix) 
+	= File::Basename::fileparse($input_filename, "\\.[^\\.]+\$");
+    my $output_filestem = &util::filename_cat($dirname, "$tailname");
+
+    if ($input_type eq "")
+    {
+	$input_type = lc (substr($suffix,1,length($suffix)-1));
+    }
+    
+    # Change to temporary working directory
+    my $stored_dir = cwd();
+    chdir ($dirname) || die "Unable to change to directory $dirname";
+
+    # Select convert utility
+    if (!defined $input_type) {
+	print STDERR "Error: No filename extension or input type defined\n";
+	exit(1);
+    } 
+    elsif ($input_type eq "doc" || $input_type eq "dot") {
+	print &convertDOC($input_filename, $output_filestem, $output_type);
+	print "\n";
+    } 
+    elsif ($input_type eq "rtf") {
+	print &convertRTF($input_filename, $output_filestem, $output_type);
+	print "\n";
+    } 
+    elsif ($input_type eq "pdf") {
+	print &convertPDF($dirname, $input_filename, $output_filestem, $output_type);
+	print "\n";
+    } 
+    elsif ($input_type eq "ps") {
+	print &convertPS($input_filename, $output_filestem, $output_type);
+	print "\n";
+    } 
+    elsif ($input_type eq "ppt") {
+	print &convertPPT($input_filename, $output_filestem, $output_type);
+	print "\n";
+    } 
+    elsif ($input_type eq "xls") {
+	print &convertXLS($input_filename, $output_filestem, $output_type);
+	print "\n";
+    } 
+    else {
+	print STDERR "Error: Unable to convert type '$input_type'\n";
+	exit(1);
+    }
+    
+    # restore to original working directory
+    chdir ($stored_dir) || die "Unable to return to directory $stored_dir";
+
+}
+
+&main(@ARGV);
+
+
+
+# Document-type conversion functions
+#
+# The following functions attempt to convert documents from their
+# input type to the specified output type.  If no output type was
+# given, then they first attempt HTML, and then TEXT.
+#
+# Each returns the output type ("html" or "text") or "fail" if no 
+# conversion is possible.
+
+# Convert a Microsoft word document
+
+sub convertDOC {
+    ($input_filename, $output_filestem, $output_type) = @_;
+
+    # Many .doc files are not in fact word documents!
+    my $realtype = &find_docfile_type($input_filename);
+
+    if ($realtype eq "word6" || $realtype eq "word7" || $realtype eq "word8") {
+	return &convertWord678($input_filename, $output_filestem, $output_type);
+    } elsif ($realtype eq "rtf") {
+	return &convertRTF($input_filename, $output_filestem, $output_type);
+    } else {
+	return &convertAnything($input_filename, $output_filestem, $output_type);
+    }
+}
+
+# Convert a Microsoft word 6/7/8 document
+
+sub convertWord678 {
+    ($input_filename, $output_filestem, $output_type) = @_;
+
+    my $success = 0;
+    if (!$output_type || ($output_type =~ /html/i)){
+	if ($windows_scripting) {
+	    $success = &native_doc_to_html($input_filename, $output_filestem);
+	}
+	else {
+	    $success = &doc_to_html($input_filename, $output_filestem);	   
+	}
+	if ($success) {
+	   return "html";
+	}
+    }
+
+    return &convertAnything($input_filename, $output_filestem, $output_type);
+}
+
+
+# Convert a Rich Text Format (RTF) file
+
+sub convertRTF {
+    ($input_filename, $output_filestem, $output_type) = @_;
+
+    my $success = 0;
+
+    # Attempt specialised conversion to HTML
+    if (!$output_type || ($output_type =~ /html/i)) {
+	$success = &rtf_to_html($input_filename, $output_filestem);
+	if ($success) {
+	    return "html";
+	}
+    }
+
+# rtf is so ugly that's it's not worth running strings over.
+# One day I'll write some quick'n'dirty regexps to try to extract text - jrm21
+#    return &convertAnything($input_filename, $output_filestem, $output_type);
+    return "fail";
+}
+
+
+# Convert an unidentified file
+
+sub convertAnything {
+    ($input_filename, $output_filestem, $output_type) = @_;
+    
+    my $success = 0;
+  
+    # Attempt simple conversion to HTML
+    if (!$output_type || ($output_type =~ /html/i)) {
+	$success = &any_to_html($input_filename, $output_filestem);
+	if ($success) {
+	    return "html";
+	}
+    }
+
+    # Convert to text
+    if (!$output_type || ($output_type =~ /text/i)) {
+	$success = &any_to_text($input_filename, $output_filestem);
+	if ($success) {
+	    return "text";
+	}
+    }
+    return "fail";
+}
+
+
+
+# Convert an Adobe PDF document
+
+sub convertPDF {
+    my ($dirname, $input_filename, $output_filestem, $output_type) = @_;
+
+    my $success = 0;
+    $output_type =~ s/.*\-(.*)/$1/i;
+    # Attempt coversion to Image
+    if ($output_type =~ /jp?g|gif|png/i) {
+	$success = &pdf_to_img($dirname, $input_filename, $output_filestem, $output_type);
+	if ($success){
+	    return "item";
+	}
+    }
+
+    # Attempt conversion to HTML
+    if (!$output_type || ($output_type =~ /html/i)) {
+	$success = &pdf_to_html($dirname, $input_filename, $output_filestem);
+	if ($success) {
+	    return "html";
+	}
+    }
+
+    # Attempt conversion to TEXT
+    if (!$output_type || ($output_type =~ /text/i)) {
+	$success = &pdf_to_text($dirname, $input_filename, $output_filestem);
+	if ($success) {
+	    return "text";
+	}
+    }
+
+    return "fail";
+
+}
+
+
+# Convert an Adobe PostScript document
+
+sub convertPS {
+    ($input_filename, $output_filestem, $output_type) = @_;
+
+    my $success = 0;
+
+    # Attempt conversion to TEXT
+    if (!$output_type || ($output_type =~ /text/i)) {
+	$success = &ps_to_text($input_filename, $output_filestem);
+	if ($success) {
+	    return "text";
+	}
+    }
+    return "fail";
+}
+
+
+sub convertPPT {
+    my ($input_filename, $output_filestem, $output_type) = @_;
+    my $success = 0;
+
+    my $ppt_convert_type = "";
+    #if (!$output_type || $windows_scripting ||($output_type !~ /html/i) ||($output_type !~ /text/i)){
+    if ($windows_scripting && ($output_type !~ /html/i) && ($output_type !~ /text/i)){
+	if ($output_type =~ /gif/i) {
+	    $ppt_convert_type = "-g";
+	} elsif ($output_type =~ /jp?g/i){
+	    $ppt_convert_type = "-j";
+	} elsif ($output_type =~ /png/i){
+	    $ppt_convert_type = "-p";
+	}
+	my $vbScript = &util::filename_cat($ENV{'GSDLHOME'}, "bin",
+					   $ENV{'GSDLOS'}, "pptextract");
+	$vbScript = "pptextract" if ($ENV{'GSDLOS'} =~ /^windows$/i);
+			
+	$cmd = "";
+	if ($timeout) {$cmd = "ulimit -t $timeout;";}
+	# if the converting directory has already existed
+	if (-d $output_filestem) {
+	    print STDERR "**The conversion directory has existed\n";
+	    return "item";
+	} else {
+	    $cmd .=  "$vbScript $ppt_convert_type $input_filename $output_filestem";
+	    $cmd .= " 2>\"$output_filestem.err\""
+		if ($ENV{'GSDLOS'} !~ /^windows$/i || $is_winnt_2000);
+	    if (system($cmd) !=0) {
+		print STDERR "Powerpoint VB Scripting convert failed\n";
+	    } else {
+		return "item";
+	    }
+	}
+    } elsif (!$output_type || ($output_type =~ /html/i)) {
+	# Attempt conversion to HTML
+	#if (!$output_type || ($output_type =~ /html/i)) {
+	# formulate the command
+	$cmd = "";
+	$cmd .= "perl -S ppttohtml.pl ";
+	$cmd .= " \"$input_filename\" \"$output_filestem.html\"";
+	$cmd .= " 2>\"$output_filestem.err\""
+	    if ($ENV{'GSDLOS'} !~ /^windows$/i || $is_winnt_2000);
+
+	# execute the command
+	$!=0;
+	if (system($cmd)!=0)
+	{
+	    print STDERR "Powerpoint 95/97 converter failed $!\n";
+	} else {
+	    return "html";
+	}
+    } 
+
+    $success = &any_to_text($input_filename, $output_filestem);
+    if ($success) {
+	return "text";
+    }
+    
+    return "fail";
+}
+
+
+sub convertXLS {
+    my ($input_filename, $output_filestem, $output_type) = @_;
+
+    my $success = 0;
+
+    # Attempt conversion to HTML
+    if (!$output_type || ($output_type =~ /html/i)) {
+	# formulate the command
+	$cmd = "";
+	$cmd .= "perl -S xlstohtml.pl ";
+	$cmd .= " \"$input_filename\" \"$output_filestem.html\"";
+	$cmd .= " 2>\"$output_filestem.err\""
+	    if ($ENV{'GSDLOS'} !~ /^windows$/i || $is_winnt_2000);
+	
+	
+	# execute the command
+	$!=0;
+	if (system($cmd)!=0)
+	{
+	    print STDERR "Excel 95/97 converter failed $!\n";
+	} else {
+	    return "html";
+	}
+    }
+
+    $success = &any_to_text($input_filename, $output_filestem);
+    if ($success) {
+	return "text";
+    }
+
+    return "fail";
+}
+
+
+
+# Find the real type of a .doc file
+#
+# We seem to have a lot of files with a .doc extension that are .rtf 
+# files or Word 5 files.  This function attempts to tell the difference.
+sub find_docfile_type {
+    ($input_filename) = @_;
+    
+    open(CHK, "<$input_filename");
+    binmode(CHK);
+    my $line = "";
+    my $first = 1;
+
+    while (<CHK>) {
+    
+	$line = $_;
+
+	if ($first) {
+	    # check to see if this is an rtf file
+	    if ($line =~ /^\{\\rtf/) {
+		close(CHK);
+		return "rtf";
+	    }
+	    $first = 0;
+	}
+	
+	# is this is a word 6/7/8 document?
+	if ($line =~ /Word\.Document\.([678])/) {
+	    close(CHK);
+	    return "word$1";
+	}
+
+    }
+
+    return "unknown";
+}
+
+
+# Specific type-to-type conversions
+#
+# Each of the following functions attempts to convert a document from 
+# a specific format to another.  If they succeed they return 1 and leave 
+# the output document(s) in the appropriate place; if they fail they 
+# return 0 and delete any working files.
+
+
+# Attempt to convert a word document to html with the wv program
+sub doc_to_html {
+    ($input_filename, $output_filestem) = @_;
+
+    my $wvWare = &util::filename_cat($ENV{'GSDLHOME'}, "bin", 
+				     $ENV{'GSDLOS'}, "wvWare");
+
+    # don't include path on windows (to avoid having to play about
+    # with quoting when GSDLHOME might contain spaces) but assume
+    # that the PATH is set up correctly
+    $wvWare = "wvWare" if ($ENV{'GSDLOS'} =~ /^windows$/i);
+
+    my $wv_conf = &util::filename_cat($ENV{'GSDLHOME'}, "etc", 
+				      "packages", "wv", "wvHtml.xml");
+    
+    my $cmd = "";
+    if ($timeout) {$cmd = "ulimit -t $timeout;";}
+    $cmd .= "$wvWare --charset utf-8 --config \"$wv_conf\"";
+    $cmd .= " \"$input_filename\" > \"$output_filestem.html\"";
+    
+    # redirecting STDERR is a bad idea on windows 95/98
+    $cmd .= " 2> \"$output_filestem.err\""
+	if ($ENV{'GSDLOS'} !~ /^windows$/i || $is_winnt_2000);
+    # execute the command
+    $!=0;
+    if (system($cmd)!=0)
+    {
+	print STDERR "Error executing wv converter:$!\n";
+	if (-s "$output_filestem.err") {
+	    open (ERRFILE, "<$output_filestem.err");
+
+	    my $write_to_fail_log=0;
+	    if ($faillogfile ne "" && defined(open(FAILLOG,">>$faillogfile")))
+	    {$write_to_fail_log=1;}
+
+	    my $line;
+	    while ($line=<ERRFILE>) {
+		if ($line =~ /\w/) {
+		    print STDERR "$line";
+		    print FAILLOG "$line" if ($write_to_fail_log);
+		}
+		if ($line !~ m/startup error/) {next;}
+		print STDERR " (given an invalid .DOC file?)\n";
+		print FAILLOG " (given an invalid .DOC file?)\n"
+		if ($write_to_fail_log);
+		
+	    } # while ERRFILE
+	    close FAILLOG if ($write_to_fail_log);
+	}
+	return 0; # we can try any_to_text
+    }
+
+    # Was the conversion successful?
+
+    if (-s "$output_filestem.html") {
+	open(TMP, "$output_filestem.html");
+	$line = <TMP>;
+	close(TMP);
+	if ($line && $line =~ /DOCTYPE HTML/) {
+	    &util::rm("$output_filestem.err") if -e "$output_filestem.err";
+	    return 1;
+	}
+    }
+	
+    # If here, an error of some sort occurred
+    &util::rm("$output_filestem.html") if -e "$output_filestem.html";
+    if (-e "$output_filestem.err") {
+	if ($faillogfile ne "" && defined(open(FAILLOG,">>$faillogfile"))) {
+	    open (ERRLOG,"$output_filestem.err");
+	    while (<ERRLOG>) {print FAILLOG $_;}
+	    close FAILLOG;
+	    close ERRLOG;
+	}
+	&util::rm("$output_filestem.err");
+    }
+    
+    return 0;
+}
+
+
+# Attempt to convert a word document to html with the word2html scripting program
+sub native_doc_to_html {
+    ($input_filename, $output_filestem) = @_;
+
+    my $vbScript = &util::filename_cat($ENV{'GSDLHOME'}, "bin",
+				       $ENV{'GSDLOS'}, "word2html");
+
+    $vbScript = "word2html" if ($ENV{'GSDLOS'} =~ /^windows$/i);
+    if (-e "$output_filestem.html") {
+	print STDERR "*** The conversion file has existed\n";
+	return 1;
+    }
+
+    my $cmd = "";
+    if ($timeout) {$cmd = "ulimit -t $timeout;";}
+    #$cmd .= "$vbScript \"$input_filename\" \"$output_filestem.html\"";
+    #$cmd .=  "$vbScript $input_filename $output_filestem.html";
+    $cmd .=  "$vbScript $input_filename $output_filestem.html";
+
+    # redirecting STDERR
+    $cmd .= " 2> \"$output_filestem.err\""
+	if ($ENV {'GSDLOS'} !~ /^windows$/i || $is_winnt_2000);
+    
+    # execute the command
+    $!=0;
+    if (system($cmd)!=0)
+    {
+	print STDERR "Error executing word2Html converter:$!\n";
+	if (-s "$output_filestem.err") {
+	    open (ERRFILE, "<$output_filestem.err");
+	    
+	    my $write_to_fail_log=0;
+	    if ($faillogfile ne "" && defined(open(FAILLOG,">>$faillogfile")))
+	    {$write_to_fail_log=1;}
+
+	    my $line;
+	    while ($line=<ERRFILE>) {
+		if ($line =~ /\w/) {
+		    print STDERR "$line";
+		    print FAILLOG "$line" if ($write_to_fail_log);
+		}
+		if ($line !~ m/startup error/) {next;}
+		print STDERR " (given an invalid .DOC file?)\n";
+		print FAILLOG " (given an invalid .DOC file?)\n"
+		if ($write_to_fail_log);
+		
+	    } # while ERRFILE
+	    close FAILLOG if ($write_to_fail_log);
+	}
+	return 0; # we can try any_to_text
+    }
+
+    # Was the conversion successful?
+    if (-s "$output_filestem.html") {
+	open(TMP, "$output_filestem.html");
+	$line = <TMP>;
+	close(TMP);
+	if ($line && $line =~ /html/) {
+	    &util::rm("$output_filestem.err") if -e "$output_filestem.err";
+	    return 1;
+	}
+    }
+	
+    # If here, an error of some sort occurred
+    &util::rm("$output_filestem.html") if -e "$output_filestem.html";
+    if (-e "$output_filestem.err") {
+	if ($faillogfile ne "" && defined(open(FAILLOG,">>$faillogfile"))) {
+	    open (ERRLOG,"$output_filestem.err");
+	    while (<ERRLOG>) {print FAILLOG $_;}
+	    close FAILLOG;
+	    close ERRLOG;
+	}
+	&util::rm("$output_filestem.err");
+    }
+    return 0;
+}
+
+# Attempt to convert an RTF document to html with rtftohtml
+
+sub rtf_to_html {
+    my ($input_filename, $output_filestem) = @_;
+
+    # formulate the command
+    $cmd = "";
+    if ($timeout) {$cmd = "ulimit -t $timeout;";}
+    $cmd .= "rtftohtml";
+    #$cmd .= "rtf-converter";
+
+    $cmd .= " -o \"$output_filestem.html\" \"$input_filename\"";
+
+    $cmd .= " 2>\"$output_filestem.err\""
+        if ($ENV{'GSDLOS'} !~ /^windows$/i || $is_winnt_2000);
+
+
+    # execute the command
+    $!=0;
+    if (system($cmd)!=0)
+    {
+	print STDERR "Error executing rtf converter $!\n";
+	# don't currently bother printing out error log...
+	# keep going, in case it still created an HTML file...
+    }
+
+    # Was the conversion successful?
+    my $was_successful=0;
+    if (-s "$output_filestem.html") {
+	# make sure we have some content other than header
+	open (HTML, "$output_filestem.html"); # what to do if fail?
+	my $line;
+	my $past_header=0;
+	while ($line=<HTML>) {
+
+	    if ($past_header == 0) {
+		if ($line =~ /<body>/) {$past_header=1;}
+		next;
+	    }
+
+	    $line =~ s/<[^>]+>//g;
+	    if ($line =~ /\w/ && $past_header) {  # we found some content...
+		$was_successful=1;
+		last;
+	    }
+	}
+	close HTML;
+    }
+
+    if ($was_successful) {
+	&util::rm("$output_filestem.err")
+	    if (-e "$output_filestem.err");
+	# insert the (modified) table of contents, if it exists.
+	if (-e "${output_filestem}_ToC.html") {
+	    &util::mv("$output_filestem.html","$output_filestem.src");
+	    my $open_failed=0;
+	    open HTMLSRC, "$output_filestem.src" || ++$open_failed;
+	    open TOC, "${output_filestem}_ToC.html" || ++$open_failed;
+	    open HTML, ">$output_filestem.html" || ++$open_failed;
+	    
+	    if ($open_failed) {
+		close HTMLSRC;
+		close TOC;
+		close HTML;
+		&util::mv("$output_filestem.src","$output_filestem.html");
+		return 1;
+	    }
+
+	    # print out header info from src html.
+	    while (defined($_ = <HTMLSRC>) && $_ =~ /\w/) {
+		print HTML "$_";
+	    }
+
+	    # print out table of contents, making links relative
+	    <TOC>; <TOC>; # ignore first 2 lines
+	    print HTML scalar(<TOC>); # line 3 = "<ol>\n"
+	    my $line;
+	    while ($line=<TOC>) {
+		$line =~ s@</body></html>$@@ ; # only last line has this
+		# make link relative
+		$line =~ s@href=\"[^\#]+@href=\"@;
+		print HTML $line;
+	    }
+	    close TOC;
+
+	    # rest of html src
+	    while (<HTMLSRC>) {
+		print HTML $_;
+	    }
+	    close HTMLSRC;
+	    close HTML;
+
+	    &util::rm("${output_filestem}_ToC.html");
+	    &util::rm("${output_filestem}.src");
+	}
+	# we don't yet do anything with footnotes ($output_filestem_fn.html) :(
+	return 1; # success
+    }
+
+    if (-e "$output_filestem.err") {
+	if ($faillogfile ne "" && defined(open(FAILLOG,">>$faillogfile")))
+	{
+	    print FAILLOG "Error - rtftohtml - couldn't extract text\n";
+	    #print FAILLOG "Error - rtf-converter - couldn't extract text\n";
+	    print FAILLOG " (rtf file might be too recent):\n";
+	    open (ERRLOG, "$output_filestem.err");
+	    while (<ERRLOG>) {print FAILLOG $_;}
+	    close ERRLOG;
+	    close FAILLOG;
+	}
+	&util::rm("$output_filestem.err");
+    }
+
+    &util::rm("$output_filestem.html") if (-e "$output_filestem.html");
+
+    return 0;
+}
+
+
+# Convert a pdf file to html with the pdftohtml command
+
+sub pdf_to_html {
+    my ($dirname, $input_filename, $output_filestem) = @_;
+
+    $cmd = "";
+    if ($timeout) {$cmd = "ulimit -t $timeout;";}
+    $cmd .= "perl -S pdftohtml.pl -zoom $pdf_zoom";
+    $cmd .= " -c" if ($pdf_complex);
+    $cmd .= " -i" if ($pdf_ignore_images);
+    $cmd .= " -a" if ($pdf_allow_images_only);
+    $cmd .= " -hidden" unless ($pdf_nohidden);
+    $cmd .= " \"$input_filename\" \"$output_filestem\"";
+    
+    if ($ENV{'GSDLOS'} !~ /^windows$/i || $is_winnt_2000) {
+	$cmd .= " > \"$output_filestem.out\" 2> \"$output_filestem.err\"";
+    } else {
+	$cmd .= " > \"$output_filestem.err\"";
+    }
+
+    $!=0;
+
+    my $retval=system($cmd);
+    if ($retval!=0)
+    {
+	print STDERR "Error executing pdftohtml.pl";
+	if ($!) {print STDERR ": $!";} 
+	print STDERR "\n";
+    }
+
+    # make sure the converter made something
+    if ($retval!=0 || ! -s "$output_filestem.html")
+    {
+	&util::rm("$output_filestem.out") if (-e "$output_filestem.out");
+	# print out the converter's std err, if any
+	if (-s "$output_filestem.err") {
+	    open (ERRLOG, "$output_filestem.err") || die "$!";
+	    print STDERR "pdftohtml error log:\n";
+	    while (<ERRLOG>) {
+		print STDERR "$_";
+	    }
+	    close ERRLOG;
+	}
+	&util::rm("$output_filestem.html") if (-e "$output_filestem.html");
+	if (-e "$output_filestem.err") {
+	    if ($faillogfile ne "" && defined(open(FAILLOG,">>$faillogfile")))
+	    {
+		open (ERRLOG, "$output_filestem.err");
+		while (<ERRLOG>) {print FAILLOG $_;}
+		close ERRLOG;
+		close FAILLOG;
+	    }	
+	    &util::rm("$output_filestem.err");
+	}
+	return 0;
+    }
+
+    &util::rm("$output_filestem.err") if (-e "$output_filestem.err");
+    &util::rm("$output_filestem.out") if (-e "$output_filestem.out");
+    return 1;
+}
+
+# Convert a pdf file to various types of image with the convert command
+
+sub pdf_to_img {
+    my ($dirname, $input_filename, $output_filestem, $output_type) = @_;
+
+    # Check that ImageMagick is installed and available on the path (except for Windows 95/98)
+    if (!($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT())) {
+	my $result = `identify 2>&1`;
+	if ($? == -1 || $? == 256) {  # Linux and Windows return different values for "program not found"
+	    #ImageMagick is not installed, thus the convert utility is not available. 
+	    print STDERR "*** ImageMagick is not installed, the convert utility is not available\n";
+	    return 0;
+	}
+    }
+
+    $cmd = "";
+    if ($timeout) {$cmd = "ulimit -t $timeout;";}
+    $output_type =~ s/.*\_(.*)/$1/i;
+     $cmd .= "perl -S pdftoimg.pl -convert_to $output_type $input_filename $output_filestem";
+    if ($ENV{'GSDLOS'} !~ /^windows$/i || $is_winnt_2000) {
+	$cmd .= " > \"$output_filestem.out\" 2> \"$output_filestem.err\"";
+    } else {
+	$cmd .= " > \"$output_filestem.err\"";
+    }
+
+    # don't include path on windows (to avoid having to play about
+    # with quoting when GSDLHOME might contain spaces) but assume
+    # that the PATH is set up correctly
+    $!=0;
+    my $retval=system($cmd);
+    if ($retval!=0)
+    {
+	print STDERR "Error executing pdftoimg.pl";
+	if ($!) {print STDERR ": $!";} 
+	print STDERR "\n";
+    }
+
+    #make sure the converter made something
+    #if ($retval !=0) || ! -s "$output_filestem")
+    if ($retval !=0) 
+    {
+	&util::rm("$output_filestem.out") if (-e "$output_filestem.out");
+	#print out the converter's std err, if any
+	if (-s "$output_filestem.err") {
+	    open (ERRLOG, "$output_filestem.err") || die "$!";
+	    print STDERR "pdftoimg error log:\n";
+	    while (<ERRLOG>) {
+		print STDERR "$_";
+	    }
+	    close ERRLOG;
+	}
+	&util::rm("$output_filestem.html") if (-e "$output_filestem.html");
+	if (-e "$output_filestem.err") {
+	    if ($faillogfile ne "" && defined(open(FAILLOG,">>$faillogfile")))
+	    {
+		open (ERRLOG, "$output_filestem.err");
+		while (<ERRLOG>) {print FAILLOG $_;}
+		close ERRLOG;
+		close FAILLOG;
+	   }	
+	    &util::rm("$output_filestem.err");
+	}
+	return 0;
+    }
+    &util::rm("$output_filestem.err") if (-e "$output_filestem.err");
+    &util::rm("$output_filestem.out") if (-e "$output_filestem.out");
+    return 1;
+}
+
+# Convert a PDF file to text with the pdftotext command
+
+sub pdf_to_text {
+    my ($dirname, $input_filename, $output_filestem) = @_;
+
+    my $cmd = "pdftotext \"$input_filename\" \"$output_filestem.text\"";
+
+    if ($ENV{'GSDLOS'} !~ /^windows$/i) {
+	$cmd .= " > \"$output_filestem.out\" 2> \"$output_filestem.err\"";
+    } else {
+	$cmd .= " > \"$output_filestem.err\"";
+    }
+    
+    if (system($cmd)!=0)
+    {
+	print STDERR "Error executing $cmd: $!\n";
+	&util::rm("$output_filestem.text") if (-e "$output_filestem.text");
+    }
+
+    # make sure there is some extracted text.
+    if (-e "$output_filestem.text") {
+	open (EXTR_TEXT, "$output_filestem.text") || warn "open: $!";
+	binmode(EXTR_TEXT); # just in case...
+	my $line="";
+	my $seen_text=0;
+	while (($seen_text==0) && ($line=<EXTR_TEXT>)) {
+	    if ($line=~ /\w/) {$seen_text=1;}
+	}
+	close EXTR_TEXT;
+	if ($seen_text==0) { # no text was extracted
+	    print STDERR "Error: pdftotext found no text\n";
+	    &util::rm("$output_filestem.text");
+	}
+    }
+
+    # make sure the converter made something
+    if (! -s "$output_filestem.text")
+    {
+	# print out the converters std err, if any
+	if (-s "$output_filestem.err") {
+	    open (ERRLOG, "$output_filestem.err") || die "$!";
+	    print STDERR "pdftotext error log:\n";
+	    while (<ERRLOG>) {
+		print STDERR "$_";
+	    }
+	    close ERRLOG;
+	}
+	# does this converter create a .out file?
+	&util::rm("$output_filestem.out") if (-e "$output_filestem.out");
+	&util::rm("$output_filestem.text") if (-e "$output_filestem.text");
+	if (-e "$output_filestem.err") {
+	    if ($faillogfile ne "" && defined(open(FAILLOG,">>$faillogfile")))
+	    {
+		open (ERRLOG,"$output_filestem.err");
+		while (<ERRLOG>) {print FAILLOG $_;}
+		close ERRLOG;
+		close FAILLOG;
+	    }
+	    &util::rm("$output_filestem.err");
+	}
+	return 0;
+    }
+    &util::rm("$output_filestem.err") if (-e "$output_filestem.err");
+    return 1;
+}
+
+# Convert a PostScript document to text
+# note - just using "ps2ascii" isn't good enough, as it
+# returns 0 for a postscript interpreter error. ps2ascii is just
+# a wrapper to "gs" anyway, so we use that cmd here.
+
+sub ps_to_text {
+    my ($input_filename, $output_filestem) = @_;
+
+    my $error = "";
+
+    # if we're on windows we'll fall straight through without attempting
+    # to use gs
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$error = "Windows does not support gs";
+
+    } else {
+	my $cmd = "";
+	if ($timeout) {$cmd = "ulimit -t $timeout; ";}
+	$cmd .= "gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT -dSIMPLE -c save ";
+	$cmd .= "-f ps2ascii.ps \"$input_filename\" -c quit > \"$output_filestem.text\"";
+	#$cmd .= "pstotext -output \"$output_filestem.text\" $input_filename\"";
+	$cmd .= " 2> $output_filestem.err";
+	$!=0;
+
+	my $retcode=system($cmd);
+	$retcode = $? >> 8;  # see man perlfunc - system for this...
+	# if system returns -1 | 127 (couldn't start program), look at $! for message
+
+	if ($retcode!=0) {if ($!) {$error=$!;} else {$error="couldn't run.\n";}}
+	elsif (! -e "$output_filestem.text") {
+	    $error="did not create output file.\n";
+	}
+	else 
+	{   # make sure the interpreter didn't get an error. It is technically
+	    # possible for the actual text to start with this, but....
+	    open PSOUT, "$output_filestem.text";
+	    if (<PSOUT> =~ /^Error: (.*)/) {
+		$error="interpreter error - \"$1\"";
+	    }
+	    close PSOUT;
+	}
+    }
+
+    if ($error ne "")
+    {
+	print STDERR "Warning: Error executing gs: $error\n";
+	&util::rm("$output_filestem.text") if (-e "$output_filestem.text");
+
+	if ("$faillogfile" ne "" && defined(open (FAILLOG, ">>$faillogfile")))
+	{
+	    print FAILLOG "gs - $error\n";
+	    if (-e "$output_filestem.err") {
+		open(ERRLOG, "$output_filestem.err");
+		while (<ERRLOG>) {print FAILLOG $_;}
+		close ERRLOG;
+	    }
+	    close FAILLOG;
+	}
+	&util::rm("$output_filestem.err") if (-e "$output_filestem.err");
+
+
+	# Fine then. We'll just do a lousy job by ourselves...
+	# Based on 5-line regexp sed script found at:
+	# http://snark.ptc.spbu.ru/mail-archives/lout/brown/msg00003.html
+	# 
+	print STDERR "Stripping text from postscript\n";
+	my $errorcode=0;
+	open (IN, "$input_filename") 
+	    ||  ($errorcode=1, warn "Couldn't read file: $!");
+	open (OUT, ">$output_filestem.text") 
+	    ||  ($errorcode=1, warn "Couldn't write file: $!");
+	if ($errorcode) {print STDERR "errors\n";return 0;}
+	
+	my $text="";  # this is for whole .ps file...
+	$text = join('', <IN>); # see man perlport, under "System Resources"
+	close IN;
+
+	# Make sure this is a ps file...
+	if ($text !~ /^%!/) {
+	    print STDERR "Bad postscript header: not '%!'\n";
+	    if ($faillogfile ne "" && defined(open(FAILLOG, ">>$faillogfile")))
+	    {
+		print FAILLOG "Bad postscript header: not '%!'\n";
+		close FAILLOG;
+	    }
+	    return 0;
+	}
+
+	# if ps has Page data, then use it to delete all stuff before it.
+	$text =~ s/^.*?%%Page:.*?\n//s; # treat string as single line
+	
+	# remove all leading non-data stuff
+	$text =~ s/^.*?\(//s;
+
+	# remove all newline chars for easier processing
+	$text =~ s/\n//g;
+	
+	# Big assumption here - assume that if any co-ordinates are
+	# given, then we are at the end of a sentence.
+	$text =~ s/\)-?\d+\ -?\d+/\) \(\n\)/g;
+
+	# special characters--
+	$text =~ s/\(\|\)/\(\ - \)/g; # j -> em-dash?
+
+	# ? ps text formatting (eg italics?) ?
+	$text =~ s/Fn\(f\)/\(\{\)/g; # f -> {
+	$text =~ s/Fn\(g\)/\(\}\)/g; # g -> }
+	$text =~ s/Fn\(j\)/\(\|\)/g; # j -> |
+	# default - remove the rest
+	$text =~ s/\ ?F.\((.+?)\)/\($1\)/g;
+
+	# attempt to add whitespace between words... 
+	# this is based purely on observation, and may be completely wrong...
+	$text =~ s/([^F])[defghijkuy]\(/$1 \( /g;
+	# eg I notice "b(" is sometimes NOT a space if preceded by a 
+	# negative number.
+	$text =~ s/\)\d+ ?b\(/\) \( /g;
+
+	# change quoted braces to brackets
+	$text =~ s/([^\\])\\\(/$1\{/g;
+	$text =~ s/([^\\])\\\)/$1\}/g ;
+
+	# remove everything that is not between braces
+	$text =~ s/\)([^\(\)])+?\(//sg ;
+	
+	# remove any Trailer eof stuff.
+	$text =~ s/\)[^\)]*$//sg;
+
+	### ligatures have special characters...
+	$text =~ s/\\013/ff/g;
+	$text =~ s/\\014/fi/g;
+	$text =~ s/\\015/fl/g;
+	$text =~ s/\\016/ffi/g;
+	$text =~ s/\\214/fi/g;
+	$text =~ s/\\215/fl/g;
+	$text =~ s/\\017/\n\* /g; # asterisk?
+	$text =~ s/\\023/\023/g;  # e acute ('e)
+	$text =~ s/\\177/\252/g;  # u"
+#	$text =~ s/ ?? /\344/g;  # a"
+
+	print OUT "$text";
+	close OUT;
+    }
+    # wrap the text - use a minimum length. ie, first space after this length.
+    my $wrap_length=72;
+    &util::mv("$output_filestem.text", "$output_filestem.text.tmp");
+    open INFILE, "$output_filestem.text.tmp" ||
+	die "Couldn't open file: $!";
+    open OUTFILE, ">$output_filestem.text" ||
+	die "Couldn't open file for writing: $!";
+    my $line="";
+    while ($line=<INFILE>) {
+	while (length($line)>0) {
+	    if (length($line)>$wrap_length) {
+		$line =~ s/^(.{$wrap_length}[^\s]*)\s*//;
+		print OUTFILE "$1\n";
+	    } else {
+		print OUTFILE "$line";
+		$line="";
+	    }
+	}
+    }
+    close INFILE;
+    close OUTFILE;
+    &util::rm("$output_filestem.text.tmp");
+
+    &util::rm("$output_filestem.err") if (-e "$output_filestem.err");
+    return 1;
+}
+
+
+# Convert any file to HTML with a crude perl implementation of the
+# UNIX strings command.
+
+sub any_to_html {
+    ($input_filename, $output_filestem) = @_;
+
+    # First generate a text file
+    return 0 unless (&any_to_text($input_filename, $output_filestem));
+
+    # create an HTML file from the text file
+    open(TEXT, "<$output_filestem.text");
+    open(HTML, ">$output_filestem.html");
+
+    print HTML "<html><head>\n";
+    print HTML "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html\">\n";
+    print HTML "<META NAME=\"GENERATOR\" CONTENT=\"Greenstone any_to_html\">\n";
+    print HTML "</head><body>\n\n";
+
+    my $line;
+    while ($line=<TEXT>) { 
+	$line =~ s/</&lt;/g;
+	$line =~ s/>/&gt;/g;
+	if ($line =~ /^\s*$/) {
+	    print HTML "<p>";
+	} else {
+	    print HTML "<br> ", $line;
+	}
+    }
+    print HTML "\n</body></html>\n";
+
+    close HTML;
+    close TEXT;
+
+    &util::rm("$output_filestem.text") if (-e "$output_filestem.text");
+    return 1;
+}
+
+# Convert any file to TEXT with a crude perl implementation of the
+# UNIX strings command.
+# Note - this assumes ascii charsets :(		(jrm21)
+
+sub any_to_text {
+    ($input_filename, $output_filestem) = @_;
+
+    if (!$use_strings) {
+      return 0;
+    }
+    
+    open(IN, "<$input_filename") || return 0;
+    binmode(IN);
+    open(OUT, ">$output_filestem.text") || return 0;
+
+    my ($line);
+    my $output_line_count = 0;
+    while (<IN>) { 
+	$line = $_;
+
+	# delete anything that isn't a printable character
+	$line =~ s/[^\040-\176]+/\n/sg;
+
+	# delete any string less than 10 characters long
+	$line =~ s/^.{0,9}$/\n/mg;
+	while ($line =~ /^.{1,9}$/m) {
+	    $line =~ s/^.{0,9}$/\n/mg;
+	    $line =~ s/\n+/\n/sg;
+	}
+
+	# remove extraneous whitespace
+	$line =~ s/\n+/\n/gs;
+	$line =~ s/^\n//gs;
+
+	# output whatever is left
+	if ($line =~ /[^\n ]/) {
+	    print OUT $line;
+	    ++$output_line_count;
+	}
+    }
+
+    close OUT;
+    close IN;
+
+    if ($output_line_count) { # try to protect against binary only formats
+	return 1;
+    }
+
+    &util::rm("$output_filestem.text");
+    return 0;
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gsWget.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gsWget.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gsWget.pl	(revision 10506)
@@ -0,0 +1,72 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This program will download the specified urls (http:, ftp: and file:)
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use util;
+
+# wget should live in the Greenstone directory structure
+# we'll bail if we can't find it
+my $exe = &util::get_os_exe ();
+my $cmd = &util::filename_cat ($ENV{'GSDLHOME'}, "bin", $ENV{'GSDLOS'}, "wget");
+$cmd .= $exe;
+if (! -e "$cmd") {
+    die "gsWget.pl failed: $cmd doesn't exist\n";
+}
+
+# if on windows we expect wget to already be on the path -
+# this allows us to avoid problems when GSDLHOME contains spaces
+# (double quoting the call doesn't work on win2000)
+if ($ENV{'GSDLOS'} =~ /^windows$/) {
+    $cmd = "wget";
+}
+
+# command-line parameters
+my @quoted_argv = map { "\"$_\"" } @ARGV;
+my $args = join(' ', @quoted_argv);
+$cmd .= " $args";
+
+# run the command
+my $status = system($cmd);
+
+# We should check the error status of wget; unfortunately this
+# is set to 1 even when we exit successfully, so we ignore it.
+#
+#$status /= 256;
+#if ($status != 0) {
+#    print STDERR "Error executing $cmd: $!\n";
+#    exit($status);
+#}
+
+print "\nDone: $cmd\n";
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gsdlinfo.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gsdlinfo.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gsdlinfo.pl	(revision 10506)
@@ -0,0 +1,142 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# gsdlinfo.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# This program will look to see what collections are installed
+# under this file system
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use colcfg;
+
+if (scalar(@ARGV) && $ARGV[0] eq "--help") {
+    print STDERR "\n";
+    print STDERR "gsdlinfo.pl: Prints information on any Greenstone collections\n";
+    print STDERR "             found on the local file system.\n\n";
+    exit;
+}
+
+
+# the collection information is stored as an array of hashes
+# (one hash for each collection). The hash contains all the 
+# information in the collect and build configuration files
+
+
+# read in all the collection configuration information
+
+opendir (DIR, "$ENV{'GSDLHOME'}/collect") ||
+    die "ERROR - couldn't read the directory $ENV{'GSDLHOME'}/collect\n";
+@dir = readdir (DIR);
+closedir (DIR);
+
+@collections = ();
+foreach $dir (@dir) {
+    if ($dir =~ /^(\..*|modelcol|CVS)$/) {
+	# do nothing
+
+    } else {
+	# read in the collection configuration file
+	my $collectcfg = {};
+	if (-e "$ENV{'GSDLHOME'}/collect/$dir/etc/collect.cfg") {
+	    $collectcfg = &colcfg::read_collect_cfg ("$ENV{'GSDLHOME'}/collect/$dir/etc/collect.cfg");
+	}
+	$collectcfg->{'collection'} = $dir;
+
+	# read in the build configuration file
+	my $buildcfg = {};
+	if (-e "$ENV{'GSDLHOME'}/collect/$dir/index/build.cfg") {
+	    $buildcfg = &colcfg::read_build_cfg ("$ENV{'GSDLHOME'}/collect/$dir/index/build.cfg");
+	}
+
+	# add the merged configuration files to the current list of collections
+	push (@collections, {%$collectcfg, %$buildcfg});
+    }
+}
+
+
+# do any sorting requested
+
+
+# print out the collection information
+
+# {'creator'}->string
+# {'maintainer'}->array of strings
+# {'public'}->string
+# {'beta'}->string
+# {'key'}->string
+# {'indexes'}->array of strings
+# {'defaultindex'}->string
+# {'builddate'}->string
+# {'metadata'}->array of strings
+# {'languages'}->array of strings
+# {'numdocs'}->string
+# {'numwords'}->string
+# {'numbytes'}->string
+
+print "\n";
+foreach $info (@collections) {
+    if (defined $info->{'collection'}) {
+	$collection = $info->{'collection'};
+	if (defined $info->{'public'}) {
+	    $public = $info->{'public'};
+	} else {
+	    $public = "?";
+	}
+	if (defined $info->{'beta'}) {
+	    $beta = $info->{'beta'};
+	} else {
+	    $beta = "?";
+	}
+	if (defined $info->{'numdocs'}) {
+	    $numdocs = $info->{'numdocs'};
+	} else {
+	    $numdocs = "?";
+	}
+	if (defined $info->{'numbytes'}) {
+	    $numMbytes = int(($info->{'numbytes'}/1024.0/1024.0)*1000)/1000.0;
+	} else {
+	    $numMbytes = "?";
+	}
+	write;
+    }
+}
+print "\n";
+
+exit;
+
+format STDOUT_TOP = 
+  name   public  beta   documents  size (Mbytes)
+-------- ------ ------ ----------- -------------
+.
+
+format STDOUT = 
+@>>>>>>> @>>>>> @>>>>> @>>>>>>>>>> @>>>>>>>>>>>>
+$collection, $public, $beta, $numdocs, $numMbytes
+.
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gsw3mir.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gsw3mir.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gsw3mir.pl	(revision 10506)
@@ -0,0 +1,52 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# urldownload.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This program will download the specified urls (http:, ftp: and file:)
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan/lib");
+    $ENV{'PATH'} = "$ENV{'GSDLHOME'}/perllib/cpan/bin:$ENV{'PATH'}";
+}
+
+my @quoted_argv = map { "\"$_\"" } @ARGV;
+
+my $args = join(' ', @quoted_argv);
+$cmd = "w3mir $args";
+
+my $status = system($cmd);
+$status /= 256;
+if ($status != 0)
+{
+    print STDERR "Error: failed to execute $cmd\n";
+    exit($status);
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/gti.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/gti.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/gti.pl	(revision 10506)
@@ -0,0 +1,1166 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# gti.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2005 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+
+use iso639;
+use strict;
+use util;
+
+
+my $anonymous_cvs_root = ":pserver:cvs_anon\@cvs.scms.waikato.ac.nz:2402/usr/local/global-cvs/gsdl-src";
+my $gsdl_root_directory = "$ENV{'GSDLHOME'}";
+my $gti_log_file = &util::filename_cat($gsdl_root_directory, "etc", "gti.log");
+my $source_language_code = "en";  # This is non-negiotable
+
+my $gti_translation_files =
+    [ # Greenstone macrofiles
+      { 'key' => "coredm",
+	'file_type' => "macrofile",
+	'source_file' => "macros/english.dm",
+	'target_file' => "macros/{bn:bengali;fa:farsi;id:indo;lv:latvian;pt-br:port-br;pt-pt:port-pt;zh-tr:chinese-trad;iso_639_1_target_language_name}.dm" },
+      { 'key' => "auxdm",
+	'file_type' => "macrofile",
+	'source_file' => "macros/english2.dm",
+	'target_file' => "macros/{bn:bengali;fa:farsi;id:indo;lv:latvian;pt-br:port-br;pt-pt:port-pt;zh-tr:chinese-trad;iso_639_1_target_language_name}2.dm" },
+
+      # GLI dictionary
+      { 'key' => "glidict",
+	'file_type' => "resource_bundle",
+	'source_file' => "gli/classes/dictionary.properties",
+	'target_file' => "gli/classes/dictionary_{target_language_code}.properties" },
+
+      # Greenstone Perl modules
+      { 'key' => "perlmodules",
+	'file_type' => "resource_bundle",
+	'source_file' => "perllib/strings.rb",
+	'target_file' => "perllib/strings_{target_language_code}.rb" } ];
+
+
+sub main
+{
+    # Get the command to process, and any arguments
+    my $gti_command = shift(@_);
+    my @gti_command_arguments = @_;
+
+    # Open the GTI log file for appending, or write to STDERR if that fails
+    if (!open(GTI_LOG, ">>$gti_log_file")) {
+	open(GTI_LOG, ">&STDERR");
+    }
+
+    # Log the command that launched this script
+    &log_message("Command: $0 @ARGV");
+
+    # Check that a command was supplied
+    if (!$gti_command) {
+	&throw_fatal_error("Missing command.");
+    }
+
+    # Process the command
+    if ($gti_command =~ /^get-first-n-chunks-requiring-work$/i) {
+	print &get_first_n_chunks_requiring_work(@gti_command_arguments);
+    }
+    if ($gti_command =~ /^get-language-status$/i) {
+	print &get_language_status(@gti_command_arguments);
+    }
+    if ($gti_command =~ /^search-chunks$/i) {
+	print &search_chunks(@gti_command_arguments);
+    }
+    if ($gti_command =~ /^submit-translations$/i) {
+	# This command cannot produce any output since it reads input
+	&submit_translations(@gti_command_arguments);
+    }
+
+    # The command was not recognized
+    # &throw_fatal_error("Unknown command \"$gti_command\".");
+}
+
+
+sub throw_fatal_error
+{
+    my $error_message = shift(@_);
+
+    # Write an XML error response
+    print "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
+    print "<GTIResponse>\n";
+    print "  <GTIError time=\"" . time() . "\">" . $error_message . "</GTIError>\n";
+    print "</GTIResponse>\n";
+
+    # Log the error message, then die
+    &log_message("Error: $error_message");
+    die "\n";
+}
+
+
+sub log_message
+{
+    my $log_message = shift(@_);
+    print GTI_LOG time() . " -- " . $log_message . "\n";
+}
+
+
+sub get_first_n_chunks_requiring_work
+{
+    # The code of the target language (ensure it is lowercase)
+    my $target_language_code = lc(shift(@_));
+    # The key of the file to translate (ensure it is lowercase)
+    my $translation_file_key = lc(shift(@_));
+    # The number of chunks to return (defaults to one if not specified)
+    my $num_chunks_to_return = shift(@_) || "1";
+
+    # Check that the necessary arguments were supplied
+    if (!$target_language_code || !$translation_file_key) {
+	&throw_fatal_error("Missing command argument.");
+    }
+
+    # Get (and check) the translation configuration
+    my ($source_file, $target_file, $translation_file_type)
+	= &get_translation_configuration($target_language_code, $translation_file_key);
+
+    # Parse the source language and target language files
+    my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
+    my @source_file_lines = &read_file_lines($source_file_path);
+    my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
+
+    my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
+    my @target_file_lines = &read_file_lines($target_file_path);
+    my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
+
+    # Filter out any automatically translated chunks
+    foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
+	if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) {
+	    delete $source_file_key_to_line_mapping{$chunk_key};
+	    delete $target_file_key_to_line_mapping{$chunk_key};
+	}
+    }
+
+    my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
+    my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
+    &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
+    &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
+
+    # Determine the target file chunks requiring translation
+    my @target_file_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping);
+    &log_message("Number of target chunks requiring translation: " . scalar(@target_file_keys_requiring_translation));
+
+    # Determine the target file chunks requiring updating
+    my %source_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($source_file, \@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
+    my %target_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($target_file, \@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
+    my @target_file_keys_requiring_updating = &determine_chunks_requiring_updating(\%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping);
+    &log_message("Number of target chunks requiring updating: " . scalar(@target_file_keys_requiring_updating));
+
+    # Form an XML response to the command
+    my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
+    $xml_response .= "<GTIResponse>\n";
+    $xml_response .= "  <TranslationFile"
+	. " key=\"" . $translation_file_key . "\""
+	. " target_file_path=\"" . $target_file . "\""
+	. " num_chunks_translated=\"" . (scalar(keys(%source_file_key_to_text_mapping)) - scalar(@target_file_keys_requiring_translation)) . "\""
+	. " num_chunks_requiring_translation=\"" . scalar(@target_file_keys_requiring_translation) . "\""
+	. " num_chunks_requiring_updating=\"" . scalar(@target_file_keys_requiring_updating) . "\"\/>\n";
+
+    # Do chunks requiring translation first
+    if ($num_chunks_to_return > scalar(@target_file_keys_requiring_translation)) {
+	$xml_response .= "  <ChunksRequiringTranslation size=\"" . scalar(@target_file_keys_requiring_translation) . "\">\n";
+    }
+    else {
+	$xml_response .= "  <ChunksRequiringTranslation size=\"" . $num_chunks_to_return . "\">\n";
+    }
+
+    foreach my $chunk_key (@target_file_keys_requiring_translation) {
+	last if ($num_chunks_to_return == 0);
+
+	my $source_file_chunk_date = $source_file_key_to_last_update_date_mapping{$chunk_key};
+	my $source_file_chunk_text = &make_text_xml_safe($source_file_key_to_text_mapping{$chunk_key});
+
+	$xml_response .= "    <Chunk key=\"$chunk_key\">\n";
+	$xml_response .= "      <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";
+	$xml_response .= "      <TargetFileText></TargetFileText>\n";
+	$xml_response .= "    </Chunk>\n";
+
+	$num_chunks_to_return--;
+    }
+
+    $xml_response .= "  </ChunksRequiringTranslation>\n";
+
+    # Then do chunks requiring updating
+    if ($num_chunks_to_return > scalar(@target_file_keys_requiring_updating)) {
+	$xml_response .= "  <ChunksRequiringUpdating size=\"" . scalar(@target_file_keys_requiring_updating) . "\">\n";
+    }
+    else {
+	$xml_response .= "  <ChunksRequiringUpdating size=\"" . $num_chunks_to_return . "\">\n";
+    }
+
+    foreach my $chunk_key (@target_file_keys_requiring_updating) {
+	last if ($num_chunks_to_return == 0);
+
+	my $source_file_chunk_date = $source_file_key_to_last_update_date_mapping{$chunk_key};
+	my $source_file_chunk_text = &make_text_xml_safe($source_file_key_to_text_mapping{$chunk_key});
+	my $target_file_chunk_date = $target_file_key_to_last_update_date_mapping{$chunk_key};
+	my $target_file_chunk_text = &make_text_xml_safe($target_file_key_to_text_mapping{$chunk_key});
+
+	$xml_response .= "    <Chunk key=\"$chunk_key\">\n";
+	$xml_response .= "      <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";
+	$xml_response .= "      <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n";
+	$xml_response .= "    </Chunk>\n";
+
+	$num_chunks_to_return--;
+    }
+
+    $xml_response .= "  </ChunksRequiringUpdating>\n";
+
+    $xml_response .= "</GTIResponse>\n";
+    return $xml_response;
+}
+
+
+sub get_language_status
+{
+    # The code of the target language (ensure it is lowercase)
+    my $target_language_code = lc(shift(@_));
+
+    # Check that the necessary arguments were supplied
+    if (!$target_language_code) {
+	&throw_fatal_error("Missing command argument.");
+    }
+
+    # Form an XML response to the command
+    my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
+    $xml_response .= "<GTIResponse>\n";
+    $xml_response .= "  <LanguageStatus code=\"$target_language_code\">\n";
+
+    foreach my $translation_file (@$gti_translation_files) {
+	# Get (and check) the translation configuration
+	my ($source_file, $target_file, $translation_file_type)
+	    = &get_translation_configuration($target_language_code, $translation_file->{'key'});
+
+	# Parse the source language and target language files
+	my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
+	my @source_file_lines = &read_file_lines($source_file_path);
+	my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
+
+	my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
+	my @target_file_lines = &read_file_lines($target_file_path);
+	my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
+
+	# Filter out any automatically translated chunks
+	foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
+	    if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) {
+		delete $source_file_key_to_line_mapping{$chunk_key};
+		delete $target_file_key_to_line_mapping{$chunk_key};
+	    }
+	}
+
+	my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
+	my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
+	&log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
+	&log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
+
+	# Determine the target file chunks requiring translation
+	my @target_file_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping);
+	&log_message("Number of target chunks requiring translation: " . scalar(@target_file_keys_requiring_translation));
+
+	# Determine the target file chunks requiring updating
+	my @target_file_keys_requiring_updating = ();
+	if (-e $target_file_path) {
+	    my %source_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($source_file, \@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
+	    my %target_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($target_file, \@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
+	    @target_file_keys_requiring_updating = &determine_chunks_requiring_updating(\%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping);
+	    &log_message("Number of target chunks requiring updating: " . scalar(@target_file_keys_requiring_updating));
+	}
+
+	$xml_response .= "    <TranslationFile"
+	    . " key=\"" . $translation_file->{'key'} . "\""
+	    . " target_file_path=\"" . $target_file . "\""
+	    . " num_chunks_translated=\"" . (scalar(keys(%source_file_key_to_text_mapping)) - scalar(@target_file_keys_requiring_translation)) . "\""
+	    . " num_chunks_requiring_translation=\"" . scalar(@target_file_keys_requiring_translation) . "\""
+	    . " num_chunks_requiring_updating=\"" . scalar(@target_file_keys_requiring_updating) . "\"\/>\n";
+    }
+
+    $xml_response .= "  </LanguageStatus>\n";
+
+    $xml_response .= "</GTIResponse>\n";
+    return $xml_response;
+}
+
+
+sub search_chunks
+{
+    # The code of the target language (ensure it is lowercase)
+    my $target_language_code = lc(shift(@_));
+    # The key of the file to translate (ensure it is lowercase)
+    my $translation_file_key = lc(shift(@_));
+    # The query string
+    my $query_string = join(' ', @_);
+
+    # Check that the necessary arguments were supplied
+    if (!$target_language_code || !$translation_file_key || !$query_string) {
+	&throw_fatal_error("Missing command argument.");
+    }
+
+    # Get (and check) the translation configuration
+    my ($source_file, $target_file, $translation_file_type)
+	= &get_translation_configuration($target_language_code, $translation_file_key);
+
+    # Parse the source language and target language files
+    my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
+    my @source_file_lines = &read_file_lines($source_file_path);
+    my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
+
+    my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
+    my @target_file_lines = &read_file_lines($target_file_path);
+    my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
+
+    # Filter out any automatically translated chunks
+    foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
+	if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) {
+	    delete $source_file_key_to_line_mapping{$chunk_key};
+	    delete $target_file_key_to_line_mapping{$chunk_key};
+	}
+    }
+
+    my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
+    my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
+    &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
+    &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
+
+    # Determine the target file chunks matching the query
+    my @target_file_keys_matching_query = ();
+    foreach my $chunk_key (keys(%target_file_key_to_text_mapping)) {
+	my $target_file_text = $target_file_key_to_text_mapping{$chunk_key};
+	if ($target_file_text =~ /$query_string/i) {
+	    # &log_message("Chunk with key $chunk_key matches query.");
+	    push(@target_file_keys_matching_query, $chunk_key);
+	}
+    }
+
+    # Form an XML response to the command
+    my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
+    $xml_response .= "<GTIResponse>\n";
+
+    $xml_response .= "  <ChunksMatchingQuery size=\"" . scalar(@target_file_keys_matching_query) . "\">\n";
+    foreach my $chunk_key (@target_file_keys_matching_query) {
+ 	my $target_file_chunk_text = &make_text_xml_safe($target_file_key_to_text_mapping{$chunk_key});
+
+ 	$xml_response .= "    <Chunk key=\"$chunk_key\">\n";
+ 	$xml_response .= "      <TargetFileText>$target_file_chunk_text</TargetFileText>\n";
+ 	$xml_response .= "    </Chunk>\n";
+    }
+    $xml_response .= "  </ChunksMatchingQuery>\n";
+
+    $xml_response .= "</GTIResponse>\n";
+    return $xml_response;
+}
+
+
+sub submit_translations
+{
+    # The code of the target language (ensure it is lowercase)
+    my $target_language_code = lc(shift(@_));
+    # The key of the file to translate (ensure it is lowercase)
+    my $translation_file_key = lc(shift(@_));
+    # Whether to submit a target chunk even if it hasn't changed
+    my $force_submission_flag = shift(@_);
+
+    # Check that the necessary arguments were supplied
+    if (!$target_language_code || !$translation_file_key) {
+	&log_message("Fatal error (but cannot be thrown): Missing command argument.");
+	die "\n";
+    }
+
+    # Get (and check) the translation configuration
+    my ($source_file, $target_file, $translation_file_type)
+	= &get_translation_configuration($target_language_code, $translation_file_key);
+
+    # Parse the source language and target language files
+    my @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file));
+    my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
+    my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
+    my %source_file_key_to_comment_date_mapping = &build_key_to_comment_date_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
+    &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
+
+    my @target_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $target_file));
+    my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
+    my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
+    my %target_file_key_to_comment_date_mapping = &build_key_to_comment_date_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
+    &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
+
+    # Submission date
+    my $day = (localtime)[3];
+    my $month = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")[(localtime)[4]];
+    my $year = (localtime)[5] + 1900;
+    my $submission_date = "$day-$month-$year";
+
+    open(SUBMISSION, "-");
+    my @submission_lines = <SUBMISSION>;
+    close(SUBMISSION);
+
+    # Remove any nasty carriage returns
+    &log_message("Submission:");
+    foreach my $submission_line (@submission_lines) {
+	$submission_line =~ s/\r$//;
+	&log_message("  $submission_line");
+    }
+
+    my %source_file_key_to_submission_mapping = ();
+    my %target_file_key_to_submission_mapping = ();
+    for (my $i = 0; $i < scalar(@submission_lines); $i++) {
+	# Read source file part of submission
+	if ($submission_lines[$i] =~ /^\<SourceFileText key=\"(.+)\"\>/) {
+	    my $chunk_key = $1;
+
+	    # Read the source file text
+	    my $source_file_chunk_text = "";
+	    $i++;
+	    while ($i < scalar(@submission_lines) && $submission_lines[$i] !~ /^\<\/SourceFileText\>/) {
+		$source_file_chunk_text .= $submission_lines[$i];
+ 		$i++;
+	    }
+	    $source_file_chunk_text =~ s/\n$//;  # Strip the extra newline character added
+
+	    &log_message("Source file key: $chunk_key");
+	    &log_message("Source file text: $source_file_chunk_text");
+	    $source_file_key_to_submission_mapping{$chunk_key} = $source_file_chunk_text;
+	}
+
+	# Read target file part of submission
+	if ($submission_lines[$i] =~ /^\<TargetFileText key=\"(.+)\"\>/) {
+	    my $chunk_key = $1;
+
+	    # Read the target file text
+	    my $target_file_chunk_text = "";
+	    $i++;
+	    while ($i < scalar(@submission_lines) && $submission_lines[$i] !~ /^\<\/TargetFileText\>/) {
+		$target_file_chunk_text .= $submission_lines[$i];
+ 		$i++;
+	    }
+	    $target_file_chunk_text =~ s/\n$//;  # Strip the extra newline character added
+
+	    &log_message("Target file key: $chunk_key");
+	    &log_message("Target file text: $target_file_chunk_text");
+	    $target_file_key_to_submission_mapping{$chunk_key} = $target_file_chunk_text;
+	}
+    }
+
+    # -----------------------------------------
+    #   Validate the translation submissions
+    # -----------------------------------------
+
+    # Check that the translations are valid
+    foreach my $chunk_key (keys(%source_file_key_to_submission_mapping)) {
+	# Make sure the submitted chunk still exists in the source file
+	if (!defined($source_file_key_to_text_mapping{$chunk_key})) {
+	    &log_message("Warning: Source chunk $chunk_key no longer exists (ignoring submission).");
+	    delete $source_file_key_to_submission_mapping{$chunk_key};
+	    delete $target_file_key_to_submission_mapping{$chunk_key};
+	    next;
+	}
+
+	# Make sure the submitted source chunk matches the source file chunk
+	if ($source_file_key_to_submission_mapping{$chunk_key} ne $source_file_key_to_text_mapping{$chunk_key}) {
+	    &log_message("Warning: Source chunk $chunk_key has changed (ignoring submission).");
+	    &log_message("Submission source: $source_file_key_to_submission_mapping{$chunk_key}");
+	    &log_message("      Source text: $source_file_key_to_text_mapping{$chunk_key}");
+	    delete $source_file_key_to_submission_mapping{$chunk_key};
+	    delete $target_file_key_to_submission_mapping{$chunk_key};
+	    next;
+	}
+    }
+
+    # Apply the submitted translations
+    foreach my $chunk_key (keys(%target_file_key_to_submission_mapping)) {
+	# Only apply the submission if it is a change, unless -force_submission has been specified
+	if ($force_submission_flag || $target_file_key_to_submission_mapping{$chunk_key} ne $target_file_key_to_text_mapping{$chunk_key}) {
+	    $target_file_key_to_text_mapping{$chunk_key} = $target_file_key_to_submission_mapping{$chunk_key};
+	    $target_file_key_to_comment_date_mapping{$chunk_key} = $submission_date;
+	}
+    }
+
+    eval "&write_translated_${translation_file_type}(\$source_file, \\\@source_file_lines, \\\%source_file_key_to_text_mapping, \$target_file, \\\@target_file_lines, \\\%target_file_key_to_text_mapping, \\\%target_file_key_to_comment_date_mapping, \$target_language_code)";
+}
+
+
+sub get_translation_configuration
+{
+    # Get the code of the target language
+    my $target_language_code = shift(@_);
+    # Get the key of the file to translate
+    my $translation_file_key = shift(@_);
+
+    # Read the translation data from the gti.cfg file
+    my ($source_file, $target_file, $translation_file_type) =
+	&get_translation_data_for($target_language_code, $translation_file_key);
+
+    # Check that the file to translate is defined in the gti.cfg file
+    if (!$source_file || !$target_file || !$translation_file_type) {
+	&throw_fatal_error("Missing or incomplete specification for translation file \"$translation_file_key\" in gti.pl.");
+    }
+
+    # Check that the source file exists
+    my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
+    if (!-e $source_file_path) {
+	&throw_fatal_error("Source file $source_file_path does not exist.");
+    }
+
+    # Check that the source file is up to date
+    # unless ($translation_file_is_not_in_cvs) {
+	my $source_file_cvs_status = `cd $gsdl_root_directory; cvs -d $anonymous_cvs_root update $source_file`;
+	if ($source_file_cvs_status =~ /^C /) {
+	    &throw_fatal_error("Source file $source_file_path conflicts with the repository.");
+	}
+	if ($source_file_cvs_status =~ /^M /) {
+	    &throw_fatal_error("Source file $source_file_path contains uncommitted changes.");
+	}
+    # }
+
+    return ($source_file, $target_file, $translation_file_type);
+}
+
+
+sub get_translation_data_for
+{
+    my ($target_language_code, $translation_file_key) = @_;
+
+    foreach my $translation_file (@$gti_translation_files) {
+	# If this isn't the correct translation file, move onto the next one
+	next if ($translation_file_key ne $translation_file->{'key'});
+
+	# Resolve the target language file
+	my $target_language_file = $translation_file->{'target_file'};
+	if ($target_language_file =~ /(\{.+\;.+\})/) {
+	    my $unresolved_target_language_file_part = $1;
+
+	    # Check for a special case for the target language code
+	    if ($unresolved_target_language_file_part =~ /(\{|\;)$target_language_code:([^\;]+)(\;|\})/) {
+		my $resolved_target_language_file_part = $2;
+		$target_language_file =~ s/$unresolved_target_language_file_part/$resolved_target_language_file_part/;
+	    }
+	    # Otherwise use the last part as the default value
+	    else {
+		my ($default_target_language_file_part) = $unresolved_target_language_file_part =~ /([^\;]+)\}/;
+		$target_language_file =~ s/$unresolved_target_language_file_part/\{$default_target_language_file_part\}/;		    
+	    }
+	}
+
+	# Resolve instances of {iso_639_1_target_language_name}
+	my $iso_639_1_target_language_name = $iso639::fromiso639{$target_language_code};
+	$iso_639_1_target_language_name =~ tr/A-Z/a-z/ if $iso_639_1_target_language_name;
+	$target_language_file =~ s/\{iso_639_1_target_language_name\}/$iso_639_1_target_language_name/g;
+
+	# Resolve instances of {target_language_code}
+	$target_language_file =~ s/\{target_language_code\}/$target_language_code/g;
+
+	return ($translation_file->{'source_file'}, $target_language_file, $translation_file->{'file_type'});
+    }
+
+    return ();
+}
+
+
+sub read_file_lines
+{
+    my ($file_path) = @_;
+
+    if (!open(FILE_IN, "<$file_path")) {
+	&log_message("Note: Could not open file $file_path.");
+	return ();
+    }
+    my @file_lines = <FILE_IN>;
+    close(FILE_IN);
+
+    return @file_lines;
+}
+
+
+sub build_key_to_line_mapping
+{
+    my ($file_lines, $translation_file_type) = @_;
+    eval "return &build_key_to_line_mapping_for_${translation_file_type}(\@\$file_lines)";
+}
+
+
+sub build_key_to_text_mapping
+{
+    my ($file_lines, $key_to_line_mapping, $translation_file_type) = @_;
+
+    my %key_to_text_mapping = ();
+    foreach my $chunk_key (keys(%$key_to_line_mapping)) {
+	my $chunk_starting_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[0];
+	my $chunk_finishing_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[1];
+
+	my $chunk_text = @$file_lines[$chunk_starting_line];
+	for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) {
+	    $chunk_text .= @$file_lines[$l];
+	}
+
+	# Map from chunk key to text
+	eval "\$key_to_text_mapping{\${chunk_key}} = &import_chunk_from_${translation_file_type}(\$chunk_text)";
+    }
+
+    return %key_to_text_mapping;
+}
+
+
+sub build_key_to_last_update_date_mapping
+{
+    my ($file, $file_lines, $key_to_line_mapping, $translation_file_type) = @_;
+
+    # If the files aren't in CVS then we can't tell anything about what needs updating
+    # return () if ($translation_file_is_not_in_cvs);
+
+    # Build a mapping from key to CVS date
+    # Need to be careful with this mapping because the chunk keys won't necessarily all be valid
+    my %key_to_cvs_date_mapping = &build_key_to_cvs_date_mapping($file, $translation_file_type);
+
+    # Build a mapping from key to comment date
+    my %key_to_comment_date_mapping = &build_key_to_comment_date_mapping($file_lines, $key_to_line_mapping, $translation_file_type);
+
+    # Build a mapping from key to last update date (the latter of the CVS date and comment date)
+    my %key_to_last_update_date_mapping = ();
+    foreach my $chunk_key (keys(%$key_to_line_mapping)) {
+	# Use the CVS date as a starting point
+	my $chunk_cvs_date = $key_to_cvs_date_mapping{$chunk_key};
+	$key_to_last_update_date_mapping{$chunk_key} = $chunk_cvs_date;
+
+	# If a comment date exists and it is after the CVS date, use that instead
+	my $chunk_comment_date = $key_to_comment_date_mapping{$chunk_key};
+	if (defined($chunk_comment_date) && (!defined($chunk_cvs_date) || &is_date_after($chunk_comment_date, $chunk_cvs_date))) {
+	    $key_to_last_update_date_mapping{$chunk_key} = $chunk_comment_date;
+	}
+    }
+
+    return %key_to_last_update_date_mapping;
+}
+
+
+sub build_key_to_cvs_date_mapping
+{
+    my ($filename, $translation_file_type) = @_;
+
+    # Use CVS to annotate each line of the file with the date it was last edited
+    # The "2>/dev/null" is very important! If it is missing this will never return when run from the receptionist
+    my $cvs_annotated_file = `cd $gsdl_root_directory; cvs -d $anonymous_cvs_root annotate -F $filename 2>/dev/null`;
+    my @cvs_annotated_file_lines = split(/\n/, $cvs_annotated_file);
+
+    my @cvs_annotated_file_lines_date = ();
+    foreach my $cvs_annotated_file_line (@cvs_annotated_file_lines) {
+	# Extract the date from the CVS annotation at the front
+	$cvs_annotated_file_line =~ s/^\S+\s+\(\S+\s+(\S+)\):\s//;
+	push(@cvs_annotated_file_lines_date, $1);
+    }
+
+    # Build a key to line mapping for the CVS annotated file, for matching the chunk key to the CVS date
+    my %key_to_line_mapping = &build_key_to_line_mapping(\@cvs_annotated_file_lines, $translation_file_type);
+
+    my %key_to_cvs_date_mapping = ();
+    foreach my $chunk_key (keys(%key_to_line_mapping)) {
+ 	my $chunk_starting_line = (split(/-/, $key_to_line_mapping{$chunk_key}))[0];
+ 	my $chunk_finishing_line = (split(/-/, $key_to_line_mapping{$chunk_key}))[1];
+
+ 	# Find the date this chunk was last edited, from the CVS annotation
+ 	my $chunk_date = $cvs_annotated_file_lines_date[$chunk_starting_line];
+ 	for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) {
+ 	    if (&is_date_after($cvs_annotated_file_lines_date[$l], $chunk_date)) {
+ 		# This part of the chunk has been updated more recently
+ 		$chunk_date = $cvs_annotated_file_lines_date[$l];
+ 	    }
+ 	}
+
+ 	# Map from chunk key to CVS date
+ 	$key_to_cvs_date_mapping{$chunk_key} = $chunk_date;
+    }
+
+    return %key_to_cvs_date_mapping;
+}
+
+
+sub build_key_to_comment_date_mapping
+{
+    my ($file_lines, $key_to_line_mapping, $translation_file_type) = @_;
+
+    my %key_to_comment_date_mapping = ();
+    foreach my $chunk_key (keys(%$key_to_line_mapping)) {
+	my $chunk_starting_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[0];
+	my $chunk_finishing_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[1];
+
+	my $chunk_text = @$file_lines[$chunk_starting_line];
+	for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) {
+	    $chunk_text .= @$file_lines[$l];
+	}
+
+	# Map from chunk key to comment date
+	my $chunk_comment_date;
+	eval "\$chunk_comment_date = &get_${translation_file_type}_chunk_comment_date(\$chunk_text)";
+	$key_to_comment_date_mapping{$chunk_key} = $chunk_comment_date if (defined($chunk_comment_date));
+    }
+
+    return %key_to_comment_date_mapping;
+}
+
+
+sub determine_chunks_requiring_translation
+{
+    my $source_file_key_to_text_mapping = shift(@_);
+    my $target_file_key_to_text_mapping = shift(@_);
+
+    # Chunks needing translation are those in the source file with no translation in the target file
+    my @target_file_keys_requiring_translation = ();
+    foreach my $chunk_key (keys(%$source_file_key_to_text_mapping)) {
+	if ($source_file_key_to_text_mapping->{$chunk_key} && !$target_file_key_to_text_mapping->{$chunk_key}) {
+	    # &log_message("Chunk with key $chunk_key needs translating.");
+	    push(@target_file_keys_requiring_translation, $chunk_key);
+	}
+    }
+
+    return @target_file_keys_requiring_translation;
+}
+
+
+sub determine_chunks_requiring_updating
+{
+    my $source_file_key_to_last_update_date_mapping = shift(@_);
+    my $target_file_key_to_last_update_date_mapping = shift(@_);
+
+    # Chunks needing updating are those in the target file that have been more recently edited in the source file
+    my @target_file_keys_requiring_updating = ();
+    foreach my $chunk_key (keys(%$source_file_key_to_last_update_date_mapping)) {
+	my $source_chunk_last_update_date = $source_file_key_to_last_update_date_mapping->{$chunk_key};
+ 	my $target_chunk_last_update_date = $target_file_key_to_last_update_date_mapping->{$chunk_key};
+ 	if (defined($target_chunk_last_update_date) && &is_date_after($source_chunk_last_update_date, $target_chunk_last_update_date)) {
+	    # &log_message("Chunk with key $chunk_key needs updating.");
+	    push(@target_file_keys_requiring_updating, $chunk_key);
+ 	}
+    }
+
+    return @target_file_keys_requiring_updating;
+}
+
+
+sub is_chunk_automatically_translated
+{
+    my ($chunk_key, $translation_file_type) = @_;
+    eval "return &is_${translation_file_type}_chunk_automatically_translated(\$chunk_key)";
+}
+
+
+sub make_text_xml_safe
+{
+    my $text = shift(@_);
+    $text =~ s/\&/\&amp\;/g;
+    $text =~ s/</\&lt\;/g;
+    $text =~ s/>/\&gt\;/g;
+    return $text;
+}
+
+
+# Returns 1 if $date1 is after $date2, 0 otherwise
+sub is_date_after
+{
+    my ($date1, $date2) = @_;
+    my %months = ("Jan", 1, "Feb", 2, "Mar", 3, "Apr",  4, "May",  5, "Jun",  6,
+		  "Jul", 7, "Aug", 8, "Sep", 9, "Oct", 10, "Nov", 11, "Dec", 12);
+
+    my @date1parts = split(/-/, $date1);
+    my @date2parts = split(/-/, $date2);
+
+    # Compare year - nasty because we have rolled over into a new century
+    my $year1 = $date1parts[2];
+    if ($year1 < 80) {
+	$year1 += 100;
+    }
+    my $year2 = $date2parts[2];
+    if ($year2 < 80) {
+	$year2 += 100;
+    }
+
+    # Compare year
+    if ($year1 > $year2) {
+	return 1;
+    }
+    elsif ($year1 == $year2) {
+	# Year is the same, so compare month
+	if ($months{$date1parts[1]} > $months{$date2parts[1]}) {
+	    return 1;
+	}
+	elsif ($months{$date1parts[1]} == $months{$date2parts[1]}) {
+	    # Month is the same, so compare day
+	    if ($date1parts[0] > $date2parts[0]) {
+		return 1;
+	    }
+	}
+    }
+
+    return 0;
+}
+
+
+# ==========================================================================================
+#   MACROFILE FUNCTIONS
+
+sub build_key_to_line_mapping_for_macrofile
+{
+    my (@file_lines) = @_;
+
+    my $macro_package;
+    my %chunk_key_to_line_mapping = ();
+    # Process the contents of the file, line by line
+    for (my $i = 0; $i < scalar(@file_lines); $i++) {
+	my $line = $file_lines[$i];
+	$line =~ s/(\s*)$//;  # Remove any nasty whitespace, carriage returns etc.
+
+	# Check if a new package is being defined
+	if ($line =~ m/^package\s+(.+)/) {
+	    $macro_package = $1;
+	}
+
+	# Line contains a macro name
+	elsif ($line =~ m/^(_\w+_)/) {
+	    my $macro_key = $1;
+	    $line =~ s/\s*([^\\]\#.+)?$//;  # Remove any comments and nasty whitespace
+
+	    # While there is still text of the macro to go...
+	    my $startline = $i;
+	    while ($line !~ /\}$/) {
+		$i++;
+		if ($i == scalar(@file_lines)) {
+		    &throw_fatal_error("Could not find end of macro $macro_key.");
+		}
+		$line = $file_lines[$i];
+		$line =~ s/\s*([^\\]\#.+)?$//;  # Remove any comments and nasty whitespace
+	    }
+
+	    # The chunk key consists of the package name and the macro key
+	    my $chunk_key = $macro_package . "." . $macro_key;
+	    # Map from chunk key to line
+	    $chunk_key_to_line_mapping{$chunk_key} = $startline . "-" . $i;
+	}
+
+	# Icon: line in format ## "image text" ## image_type ## macro_name ##
+	elsif ($line =~ m/^\#\# .* \#\# .* \#\# (.*) \#\#/) {
+	    # The chunk key consists of package name and macro key
+	    my $chunk_key = $macro_package . "." . $1;
+	    # Map from chunk key to line
+	    $chunk_key_to_line_mapping{$chunk_key} = $i . "-" . $i;
+	}
+    }
+
+    return %chunk_key_to_line_mapping;
+}
+
+
+sub import_chunk_from_macrofile
+{
+    my ($chunk_text) = @_;
+
+    # Is this an icon macro??
+    if ($chunk_text =~ /^\#\# (.*)/) {
+	# Extract image macro text
+	$chunk_text =~ /^\#\#\s+([^\#]+)\s+\#\#/;
+	$chunk_text = $1;
+
+	# Remove enclosing quotes
+	$chunk_text =~ s/^\"//;
+	$chunk_text =~ s/\"$//;
+    }
+
+    # No, so it must be a text macro
+    else {
+	# Remove macro key
+	$chunk_text =~ s/^_([^_]+)_(\s*)//;
+
+	# Remove language specifier
+	$chunk_text =~ s/^\[l=.*\](\s*)//;
+
+	# Remove braces enclosing text
+	$chunk_text =~ s/^{(\s*)((.|\n)*)}(\s*)(\#.+\s*)?/$2/;
+    }
+
+    return $chunk_text;
+}
+
+
+sub get_macrofile_chunk_comment_date
+{
+    my ($chunk_text) = @_;
+
+    # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk
+    if ($chunk_text =~ /\#\s+Updated\s+(\d?\d-\D\D\D-\d\d\d\d)\s*$/i) {
+	return $1;
+    }
+
+    return undef;
+}
+
+
+sub is_macrofile_chunk_automatically_translated
+{
+    my ($chunk_key) = @_;
+
+    # The _httpiconX_, _widthX_ and _heightX_ image macros are automatically translated
+    if ($chunk_key =~ /\._(httpicon|width|height)/) {
+	return 1;
+    }
+
+    return 0;
+}
+
+
+# Use the source file to generate a target file that is formatted the same
+sub write_translated_macrofile
+{
+    my $source_file = shift(@_);  # Not used
+    my $source_file_lines = shift(@_);
+    my $source_file_key_to_text_mapping = shift(@_);
+    my $target_file = shift(@_);
+    my $target_file_lines = shift(@_);  # Not used
+    my $target_file_key_to_text_mapping = shift(@_);
+    my $target_file_key_to_comment_date_mapping = shift(@_);
+    my $target_language_code = shift(@_);
+
+    # Build a mapping from source file line to chunk key
+    my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_macrofile(@$source_file_lines);
+    my %source_file_line_to_key_mapping = ();
+    foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
+	$source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
+    }
+    my @source_file_line_keys = (sort sort_by_line (keys(%source_file_line_to_key_mapping)));
+    my $source_file_line_number = 0;
+
+    # Build a mapping from target file line to chunk key
+    my %target_file_key_to_line_mapping = &build_key_to_line_mapping_for_macrofile(@$target_file_lines);
+    my %target_file_line_to_key_mapping = ();
+    foreach my $chunk_key (keys(%target_file_key_to_line_mapping)) {
+	$target_file_line_to_key_mapping{$target_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
+    }
+    my @target_file_line_keys = (sort sort_by_line (keys(%target_file_line_to_key_mapping)));
+
+    # Write the new target file
+    my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
+    if (!open(TARGET_FILE, ">$target_file_path")) {
+	&throw_fatal_error("Could not write target file $target_file_path.");
+    }
+
+    # Use the header from the target file, to keep language and author information
+    if (scalar(@target_file_line_keys) > 0) {
+	my $target_file_line_number = 0;
+ 	my $target_file_chunk_starting_line_number = (split(/-/, $target_file_line_keys[0]))[0];
+ 	while ($target_file_line_number < $target_file_chunk_starting_line_number) {
+	    my $target_file_line = @$target_file_lines[$target_file_line_number];
+	    last if ($target_file_line =~ /^\# -- Missing translation: /);  # We don't want to get into the macros
+ 	    print TARGET_FILE $target_file_line;
+ 	    $target_file_line_number++;
+ 	}
+
+	$source_file_line_number = (split(/-/, $source_file_line_keys[0]))[0];
+    }
+
+    # Model the new target file on the source file, with the target file translations
+    foreach my $line_key (@source_file_line_keys) {
+ 	# Fill in the gaps before this chunk starts
+ 	my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0];
+ 	my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1];
+ 	while ($source_file_line_number < $source_file_chunk_starting_line_number) {
+ 	    print TARGET_FILE @$source_file_lines[$source_file_line_number];
+ 	    $source_file_line_number++;
+ 	}
+ 	$source_file_line_number = $source_file_chunk_finishing_line_number + 1;
+
+	my $chunk_key = $source_file_line_to_key_mapping{$line_key};
+	my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key};
+	my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || "";
+
+	my $macrofile_key = $chunk_key;
+	$macrofile_key =~ s/^(.+?)\.//;
+
+	# If no translation exists for this chunk, show this, and move on
+	if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") {
+	    print TARGET_FILE "# -- Missing translation: $macrofile_key\n";
+	    next;
+	}
+
+ 	# Grab the source chunk text
+ 	my $source_file_chunk = @$source_file_lines[$source_file_chunk_starting_line_number];
+ 	for (my $l = ($source_file_chunk_starting_line_number + 1); $l <= $source_file_chunk_finishing_line_number; $l++) {
+ 	    $source_file_chunk .= @$source_file_lines[$l];
+ 	}
+
+ 	# Is this an icon macro??
+ 	if ($source_file_chunk =~ /^\#\# (.*)/) {
+ 	    # Escape any newline and question mark characters so the source text is replaced correctly
+ 	    $source_file_chunk_text =~ s/\\/\\\\/g;
+	    $source_file_chunk_text =~ s/\?/\\\?/g;
+
+	    # Build the new target chunk from the source chunk
+	    my $target_file_chunk = $source_file_chunk;
+	    $target_file_chunk =~ s/$source_file_chunk_text/$target_file_chunk_text/;
+	    $target_file_chunk =~ s/(\s)*$//;
+	    print TARGET_FILE "$target_file_chunk";
+ 	}
+
+ 	# No, it is just a normal text macro
+ 	else {
+ 	    print TARGET_FILE "$macrofile_key [l=$target_language_code] {$target_file_chunk_text}";
+ 	}
+
+	# Add the update date, if one exists
+	if ($target_file_key_to_comment_date_mapping->{$chunk_key}) {
+	    print TARGET_FILE "  # Updated " . $target_file_key_to_comment_date_mapping->{$chunk_key};
+	}
+	print TARGET_FILE "\n";
+    }
+
+    close(TARGET_FILE);
+}
+
+
+sub sort_by_line
+{
+    return ((split(/-/, $a))[0] <=> (split(/-/, $b))[0]);
+}
+
+
+# ==========================================================================================
+#   RESOURCE BUNDLE FUNCTIONS
+
+sub build_key_to_line_mapping_for_resource_bundle
+{
+    my (@file_lines) = @_;
+
+    my %key_to_line_mapping = ();
+    for (my $i = 0; $i < scalar(@file_lines); $i++) {
+	my $line = $file_lines[$i];
+	$line =~ s/(\s*)$//;  # Remove any nasty whitespace, carriage returns etc.
+
+	# Line contains a dictionary string
+	if ($line =~ /^(\S+?):(.*)$/) {
+	    my $chunk_key = $1;
+
+	    # Map from chunk key to line
+	    $key_to_line_mapping{$chunk_key} = $i . "-" . $i;
+	}
+    }
+
+    return %key_to_line_mapping;
+}
+
+
+sub import_chunk_from_resource_bundle
+{
+    my ($chunk_text) = @_;
+
+    # Simple: just remove string key
+    $chunk_text =~ s/^(\S+?)://;
+    $chunk_text =~ s/(\s*)$//;  # Remove any nasty whitespace, carriage returns etc.
+
+    return $chunk_text;
+}
+
+
+sub get_resource_bundle_chunk_comment_date
+{
+    my ($chunk_text) = @_;
+
+    # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk
+    if ($chunk_text =~ /\#\s+Updated\s+(\d?\d-\D\D\D-\d\d\d\d)\s*$/i) {
+	return $1;
+    }
+
+    return undef;
+}
+
+
+sub is_resource_bundle_chunk_automatically_translated
+{
+    # No resource bundle chunks are automatically translated
+    return 0;
+}
+
+
+sub write_translated_resource_bundle
+{
+    my $source_file = shift(@_);  # Not used
+    my $source_file_lines = shift(@_);
+    my $source_file_key_to_text_mapping = shift(@_);
+    my $target_file = shift(@_);
+    my $target_file_lines = shift(@_);  # Not used
+    my $target_file_key_to_text_mapping = shift(@_);
+    my $target_file_key_to_comment_date_mapping = shift(@_);
+    my $target_language_code = shift(@_);  # Not used
+
+    # Build a mapping from chunk key to source file line, and from source file line to chunk key
+    my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_resource_bundle(@$source_file_lines);
+    my %source_file_line_to_key_mapping = ();
+    foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
+	$source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
+    }
+
+    # Write the new target file
+    my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
+    if (!open(TARGET_FILE, ">$target_file_path")) {
+	&throw_fatal_error("Could not write target file $target_file_path.");
+    }
+
+    # Model the new target file on the source file, with the target file translations
+    my $source_file_line_number = 0;
+    foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) {
+ 	# Fill in the gaps before this chunk starts
+ 	my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0];
+ 	my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1];
+ 	while ($source_file_line_number < $source_file_chunk_starting_line_number) {
+ 	    print TARGET_FILE @$source_file_lines[$source_file_line_number];
+ 	    $source_file_line_number++;
+ 	}
+ 	$source_file_line_number = $source_file_chunk_finishing_line_number + 1;
+
+	my $chunk_key = $source_file_line_to_key_mapping{$line_key};
+	my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key};
+	my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || "";
+
+	# If no translation exists for this chunk, show this, and move on
+	if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") {
+	    print TARGET_FILE "# -- Missing translation: $chunk_key\n";
+	    next;
+	}
+
+	print TARGET_FILE "$chunk_key:$target_file_chunk_text";
+	if ($target_file_key_to_comment_date_mapping->{$chunk_key}) {
+	    print TARGET_FILE "  # Updated " . $target_file_key_to_comment_date_mapping->{$chunk_key};
+	}
+	print TARGET_FILE "\n";
+    }
+
+    close(TARGET_FILE);
+}
+
+
+&main(@ARGV);
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/import.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/import.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/import.pl	(revision 10506)
@@ -0,0 +1,485 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# import.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This program will import a number of files into a particular collection
+
+package import;
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use arcinfo;
+use colcfg;
+use plugin;
+use docprint;
+use util;
+use scriptutil;
+use FileHandle;
+use gsprintf 'gsprintf';
+use printusage;
+use parse2;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and vice versa
+no strict 'subs'; # allow barewords (eg STDERR) as function arguments
+
+my $oidtype_list = 
+    [ { 'name' => "hash",
+        'desc' => "{import.OIDtype.hash}" },
+      { 'name' => "incremental",
+        'desc' => "{import.OIDtype.incremental}" },
+      { 'name' => "assigned",
+        'desc' => "{import.OIDtype.assigned}" },
+      { 'name' => "dirname",
+        'desc' => "{import.OIDtype.dirname}" } ];
+
+#** define to use the original GA format or METS format
+my $saveas_list = 
+    [ { 'name' => "GA",
+        'desc' => "{import.saveas.GA}" },
+      { 'name' => "METS",
+        'desc' => "{import.saveas.METS}" } ];
+
+
+# Possible attributes for each argument
+# name: The name of the argument
+# desc: A description (or more likely a reference to a description) for this argument
+# type: The type of control used to represent the argument. Options include: string, int, flag, regexp, metadata, metadatum, language, enum etc
+# reqd: Is this argument required?
+# hiddengli: Is this argument hidden in GLI?
+# modegli: The lowest detail mode this argument is visible at in GLI
+
+my $arguments = 
+    [ { 'name' => "archivedir",
+	'desc' => "{import.archivedir}",
+	'type' => "string",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "collectdir",
+	'desc' => "{import.collectdir}",
+	'type' => "string",
+	# parsearg left "" as default
+	#'deft' => &util::filename_cat ($ENV{'GSDLHOME'}, "collect"),
+	'deft' => "",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "debug",
+	'desc' => "{import.debug}",
+	'type' => "flag",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "faillog",
+	'desc' => "{import.faillog}",
+	'type' => "string",
+	# parsearg left "" as default
+	#'deft' => &util::filename_cat("&lt;collectdir&gt;", "colname", "etc", "fail.log"),
+	'deft' => "",
+	'reqd' => "no",
+        'modegli' => "4" },
+      { 'name' => "groupsize",
+	'desc' => "{import.groupsize}",
+	'type' => "int",
+	'deft' => "1",
+	'reqd' => "no",
+	'modegli' => "3" },
+      { 'name' => "gzip",
+	'desc' => "{import.gzip}",
+	'type' => "flag",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "importdir",
+	'desc' => "{import.importdir}",
+	'type' => "string",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "keepold",
+	'desc' => "{import.keepold}",
+	'type' => "flag",
+	'reqd' => "no",
+        'modegli' => "3" },
+      { 'name' => "removeold",
+	'desc' => "{import.removeold}",
+	'type' => "flag",
+	'reqd' => "no",
+	'modegli' => "3" },
+      { 'name' => "language",
+	'desc' => "{scripts.language}",
+	'type' => "string",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "maxdocs",
+	'desc' => "{import.maxdocs}",
+	'type' => "int",
+	'reqd' => "no",
+	# parsearg left "" as default
+	#'deft' => "-1",
+	'range' => "1,",
+	'modegli' => "1" },
+      { 'name' => "OIDtype",
+	'desc' => "{import.OIDtype}",
+	'type' => "enum",
+	'list' => $oidtype_list,
+	# parsearg left "" as default
+	#'deft' => "hash",
+	'reqd' => "no",
+	'modegli' => "3" },
+      { 'name' => "out",
+	'desc' => "{import.out}",
+	'type' => "string",
+	'deft' => "STDERR",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "saveas",
+	'desc' => "{import.saveas}",
+	'type' => "enum",
+	'list' => $saveas_list,
+	'deft' => "GA",
+	'reqd' => "no",
+	'modegli' => "3" },      
+      { 'name' => "sortmeta",
+	'desc' => "{import.sortmeta}",
+#	'type' => "metadatum",
+	'type' => "string",
+	'reqd' => "no",
+	'modegli' => "3" },
+      { 'name' => "removeprefix",
+	'desc' => "{BasClas.removeprefix}",
+	'type' => "regexp",
+	'deft' => "",
+	'reqd' => "no", 
+	'modegli' => "3" },
+      { 'name' => "removesuffix",
+	'desc' => "{BasClas.removesuffix}",
+	'type' => "regexp",
+	'deft' => "",
+	'reqd' => "no",
+	'modegli' => "3" }, 
+      { 'name' => "statsfile",
+	'desc' => "{import.statsfile}",
+	'type' => "string",
+	'deft' => "STDERR",
+	'reqd' => "no",
+        'hiddengli' => "yes" },
+      { 'name' => "verbosity",
+	'desc' => "{import.verbosity}",
+	'type' => "int",
+	'range' => "0,",
+	# parsearg left "" as default
+	#'deft' => "2",
+	'reqd' => "no",
+	'modegli' => "4" },
+      { 'name' => "gli",
+	'desc' => "",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" },
+      { 'name' => "xml",
+	'desc' => "{scripts.xml}",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" }];
+
+my $options = { 'name' => "import.pl",
+		'desc' => "{import.desc}",
+		'args' => $arguments };
+
+
+&main();
+
+sub main {
+    my ($verbosity, $importdir, $archivedir, $keepold, 
+	$removeold, $saveas, $version,
+	$gzip, $groupsize, $OIDtype, $debug, 
+	$maxdocs, $collection, $configfilename, $collectcfg, 
+	$pluginfo, $sortmeta, $removeprefix, $removesuffix, 
+	$archive_info_filename, $statsfile,
+	$archive_info, $processor, $out, $faillog, $collectdir, $gli, $language);
+
+    my $xml = 0;
+
+    my $service = "import";
+
+    my $hashParsingResult = {};
+    my $blnParseFailed = "false";
+    # general options available to all plugins
+    my $intArgLeftinAfterParsing = parse2::parse(\@ARGV,$arguments,$hashParsingResult,"allow_extra_options");
+    # If there is more than one argument left after parsing, it mean user input too many arguments.
+    if($intArgLeftinAfterParsing > 1)
+    {
+	&PrintUsage::print_txt_usage($options, "{import.params}");
+	die "\n";
+    }
+    
+    foreach my $strVariable (keys %$hashParsingResult)
+    {
+	eval "\$$strVariable = \$hashParsingResult->{\"\$strVariable\"}";
+    }
+
+    # If $language has been specified, load the appropriate resource bundle
+    # (Otherwise, the default resource bundle will be loaded automatically)
+    if ($language && $language =~ /\S/) {
+	&gsprintf::load_language_specific_resource_bundle($language);
+    }
+
+    if ($xml) {
+        &PrintUsage::print_xml_usage($options);
+	print "\n";
+	return;
+    }
+
+    if ($gli) { # the gli wants strings to be in UTF-8
+	&gsprintf::output_strings_in_UTF8; 
+    }
+
+    my $close_out = 0;
+    if ($out !~ /^(STDERR|STDOUT)$/i) {
+	open (OUT, ">$out") ||
+	    (&gsprintf(STDERR, "{common.cannot_open_output_file}\n", $out) && die);
+	$out = 'import::OUT';
+	$close_out = 1;
+    }
+    $out->autoflush(1);
+
+    # get and check the collection name
+    if (($collection = &util::use_collection(@ARGV, $collectdir)) eq "") {
+	&PrintUsage::print_txt_usage($options, "{import.params}");
+	die "\n";
+    }
+
+    if ($faillog eq "") {
+	$faillog = &util::filename_cat($ENV{'GSDLCOLLECTDIR'}, "etc", "fail.log");
+    }
+    open (FAILLOG, ">$faillog") ||
+	(&gsprintf(STDERR, "{import.cannot_open_fail_log}\n", $faillog) && die);
+
+    
+    my $faillogname = $faillog;
+    $faillog = 'import::FAILLOG';
+    $faillog->autoflush(1);
+
+    # check sortmeta
+    $sortmeta = undef unless defined $sortmeta && $sortmeta =~ /\S/;
+    if (defined $sortmeta && $groupsize > 1) {
+	&gsprintf($out, "{import.cannot_sort}\n\n");
+	$sortmeta = undef;
+    }
+    # dynamically load 'docsave' module so it can pick up on a collection
+    # specific docsave.pm is specified.
+
+    unshift (@INC, "$ENV{'GSDLCOLLECTDIR'}/perllib");
+    require docsave;
+
+    # get the list of plugins for this collection and set any options that
+    # were specified in the collect.cfg (all import.pl options except
+    # -collectdir, -out and -faillog may be specified in the collect.cfg (these
+    # options must be known before we read the collect.cfg))
+    my $plugins = [];
+    my @global_opts = ();
+    
+    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc", "collect.cfg");
+    if (!-e $configfilename) {
+	(&gsprintf($out, "{common.cannot_find_cfg_file}\n", $configfilename) && die);
+    }
+    
+    $collectcfg = &colcfg::read_collect_cfg ($configfilename);
+    if (defined $collectcfg->{'plugin'}) {
+	$plugins = $collectcfg->{'plugin'};
+    }
+
+    if ($verbosity !~ /\d+/) {
+	if (defined $collectcfg->{'verbosity'} && $collectcfg->{'verbosity'} =~ /\d+/) {
+	    $verbosity = $collectcfg->{'verbosity'};
+	} else {
+	    $verbosity = 2; # the default
+	}
+    }
+    if (defined $collectcfg->{'importdir'} && $importdir eq "") {
+	$importdir = $collectcfg->{'importdir'};
+    }
+    if (defined $collectcfg->{'archivedir'} && $archivedir eq "") {
+	$archivedir = $collectcfg->{'archivedir'};
+    }
+
+    if (defined $collectcfg->{'gzip'} && !$gzip) {
+	if ($collectcfg->{'gzip'} =~ /^true$/i) {
+	    $gzip = 1;
+	}
+    }
+    if ($maxdocs !~ /\-?\d+/) {
+	if (defined $collectcfg->{'maxdocs'} && $collectcfg->{'maxdocs'} =~ /\-?\d+/) {
+	    $maxdocs = $collectcfg->{'maxdocs'};
+	} else {
+	    $maxdocs = -1; # the default
+	}
+    }
+    if ($groupsize == 1) {
+	if (defined $collectcfg->{'groupsize'} && $collectcfg->{'groupsize'} =~ /\d+/) {
+	    $groupsize = $collectcfg->{'groupsize'};
+	}
+    }
+    if ($OIDtype !~ /^(hash|incremental|assigned|dirname)$/) {
+	if (defined $collectcfg->{'OIDtype'} && $collectcfg->{'OIDtype'} =~ /^(hash|incremental|assigned|dirname)$/) {
+	    $OIDtype = $collectcfg->{'OIDtype'};
+	} else {
+	    $OIDtype = "hash"; # the default
+	}
+    }
+    if ($saveas !~ /^(GA|METS)$/) {
+	if (defined $collectcfg->{'saveas'} && $collectcfg->{'saveas'} =~ /^(GA|METS)$/) {
+	    $saveas = $collectcfg->{'saveas'};
+	} else {
+	    $saveas ="GA";
+	}
+    }
+    if (defined $collectcfg->{'sortmeta'} && (!defined $sortmeta || $sortmeta eq "")) {
+	$sortmeta = $collectcfg->{'sortmeta'};
+    }
+    
+    if (defined $collectcfg->{'removeprefix'} && $removeprefix eq "") {
+	$removeprefix = $collectcfg->{'removeprefix'};
+    }
+    
+    if (defined $collectcfg->{'removesuffix'} && $removesuffix eq "") {
+	$removesuffix = $collectcfg->{'removesuffix'};
+    }
+    if (defined $collectcfg->{'debug'} && $collectcfg->{'debug'} =~ /^true$/i) {
+	$debug = 1;
+    }
+    if (defined $collectcfg->{'gli'} && $collectcfg->{'gli'} =~ /^true$/i) {
+	$gli = 1;
+    }
+    
+    
+    # global plugin stuff
+    if (defined $collectcfg->{'separate_cjk'} && $collectcfg->{'separate_cjk'} =~ /^true$/i) {
+	push @global_opts, "-separate_cjk";
+    }
+    
+    # check keepold and removeold
+    ($removeold, $keepold) = &scriptutil::check_removeold_and_keepold($removeold, $keepold, "archives", $collectcfg);
+ 
+    $gli = 0 unless defined $gli;
+
+    print STDERR "<Import>\n" if $gli;
+    
+    # fill in the default import and archives directories if none
+    # were supplied, turn all \ into / and remove trailing /
+    $importdir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "import") if $importdir eq "";
+    $importdir =~ s/[\\\/]+/\//g;
+    $importdir =~ s/\/$//;
+    $archivedir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "archives") if $archivedir eq "";
+    $archivedir =~ s/[\\\/]+/\//g;
+    $archivedir =~ s/\/$//;
+
+    # load all the plugins
+    $pluginfo = &plugin::load_plugins ($plugins, $verbosity, $out, $faillog, \@global_opts);
+    if (scalar(@$pluginfo) == 0) {
+	&gsprintf($out, "{import.no_plugins_loaded}\n");
+	die "\n";
+    }
+
+    # remove the old contents of the archives directory (and tmp directory) if needed
+    if ($removeold) {
+	if (-e $archivedir) {
+	    &gsprintf($out, "{import.removing_archives}\n");
+	    &util::rm_r ($archivedir);
+	}
+	my $tmpdir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "tmp");
+	$tmpdir =~ s/[\\\/]+/\//g;
+	$tmpdir =~ s/\/$//;
+	if (-e $tmpdir) {
+	    &gsprintf($out, "{import.removing_tmpdir}\n");
+	    &util::rm_r ($tmpdir);
+	}
+    }
+
+    # read the archive information file
+    if (!$debug) {
+	$archive_info_filename = &util::filename_cat ($archivedir, "archives.inf");
+	$archive_info = new arcinfo ();
+	$archive_info->load_info ($archive_info_filename);
+
+	# create a docsave object to process the documents
+	$processor = new docsave ($collection, $archive_info, $verbosity, $gzip, $groupsize, $out, $service, $saveas);
+	$processor->setoutputdir ($archivedir);
+	$processor->set_sortmeta ($sortmeta, $removeprefix, $removesuffix) if defined $sortmeta;
+	$processor->set_OIDtype ($OIDtype);
+	$processor->set_saveas ($saveas);
+	$processor->set_saveas_version ($version);
+
+    } else {
+	$processor = new docprint ();
+    }
+
+    &plugin::begin($pluginfo, $importdir, $processor, $maxdocs);
+
+    # process the import directory
+    &plugin::read ($pluginfo, $importdir, "", {}, $processor, $maxdocs, 0, $gli);
+    
+    &plugin::end($pluginfo, $processor);
+
+    &plugin::deinit($pluginfo, $processor);
+
+    # write out the archive information file
+    if (!$debug) {
+	$processor->close_file_output() if $groupsize > 1;
+	$archive_info->save_info($archive_info_filename);
+    }
+    
+    # write out import stats
+    my $close_stats = 0;
+    if ($statsfile !~ /^(STDERR|STDOUT)$/i) {
+	if (open (STATS, ">$statsfile")) {
+	    $statsfile = 'import::STATS';
+	    $close_stats = 1;
+	} else {
+	    &gsprintf($out, "{import.cannot_open_stats_file}", $statsfile);
+	    &gsprintf($out, "{import.stats_backup}\n");
+	    $statsfile = 'STDERR';
+	}
+    }
+
+    &gsprintf($out, "\n");
+    &gsprintf($out, "*********************************************\n");
+    &gsprintf($out, "{import.complete}\n");
+    &gsprintf($out, "*********************************************\n");
+
+    &plugin::write_stats($pluginfo, $statsfile, $faillogname, $gli);
+    if ($close_stats) {
+	close STATS;
+    }
+
+    close OUT if $close_out;
+    close FAILLOG;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/importfrom.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/importfrom.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/importfrom.pl	(revision 10506)
@@ -0,0 +1,453 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# importfrom.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This program will contact the named DL server
+#  and export its metadata and (optionally) it documents.
+
+# Currently only designed for OAI exporting
+
+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 colcfg;
+use util;
+use parsargv;
+use FileHandle;
+
+my $wgetopt = "";
+
+my $num_processed = 0;
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -getdoc                Also download if source document if present\n";
+    print STDERR "   -importdir directory   Where the original material lives\n";
+    print STDERR "   -keepold               Will not destroy the current contents of the\n";
+    print STDERR "                          import directory (the default)\n";
+    print STDERR "   -removeold             Will remove the old contents of the import\n";
+    print STDERR "                          directory -- use with care\n";
+    print STDERR "   -gzip                  Use gzip to compress exported documents\n";
+    print STDERR "                          (don't forget to include ZIPPlug in your plugin\n";
+    print STDERR "   -maxdocs number        Maximum number of documents to import\n";
+    print STDERR "   -debug                 Print imported text to STDOUT\n";
+    print STDERR "   -collectdir directory  Collection directory (defaults to " .
+	&util::filename_cat ($ENV{'GSDLHOME'}, "collect") . ")\n";
+    print STDERR "   -out                   Filename or handle to print output status to.\n";
+    print STDERR "                          The default is STDERR\n\n";
+}
+
+
+
+sub xml_pretty_print
+{
+    my ($text,$out,$verbosity) = @_;
+
+    if (system("xmllint --version >/dev/null 2>&1")!=0) {
+	if ($verbosity>1) {
+	    print STDERR "Warning: Unable to find xmllint for pretty printing.\n";
+	    print STDERR "         XML will be shown verbatim.\n\n";
+	}
+	print $out $text;
+    }
+    else {
+
+	if (!open (PPOUT,"|xmllint --format -")) {
+	    print STDERR "Error running xmllint: $!\n\n";
+	    print $out $text;
+	    return;
+	}
+
+	print PPOUT $text;
+	close(PPOUT);
+    }
+}
+
+sub wget_oai_url 
+{
+    my ($wget_cmd,$out,$verbosity) = @_;
+
+    if ($verbosity>2) {
+	print $out "  $wget_cmd\n";
+    }
+
+    open (OAIIN,"$wget_cmd |")
+	|| die "wget request failed: $!\n";
+ 
+    my $li_record = "";
+
+    my $line;
+    while (defined($line=<OAIIN>))
+    {
+	$li_record .= $line;
+	# print $out $line;
+    }
+
+    close(OAIIN);
+
+    return $li_record;
+}
+
+sub oai_info
+{
+    my ($base_url,$out,$verbosity) = @_;
+
+    my $base_wget_cmd = "wget $wgetopt -q -O - \"$base_url?_OPTS_\"";
+ 
+    my $identify = "verb=Identify";
+    my $list_sets = "verb=ListSets";
+    my $list_md_formats = "ListMetadataFormats"; # not currently used
+
+    my $identify_cmd = $base_wget_cmd;
+    $identify_cmd =~ s/_OPTS_/$identify/;
+    print $out "-------------------\n";
+    print $out "General Information\n";
+    print $out "-------------------\n";
+    my $identify_text = wget_oai_url($identify_cmd,$out,$verbosity);
+    xml_pretty_print($identify_text,$out,$verbosity);
+
+    
+    my $list_sets_cmd = $base_wget_cmd;
+    $list_sets_cmd =~ s/_OPTS_/$list_sets/;
+    print $out "-------------------\n";
+    print $out "Set Information\n";
+    print $out "-------------------\n";
+    my $list_sets_text = wget_oai_url($list_sets_cmd,$out,$verbosity);
+    xml_pretty_print($list_sets_text,$out,$verbosity);
+}
+
+
+sub get_oai_ids
+{
+    my ($base_url, $set, $format, $out, $verbosity) = @_;
+
+    print $out "Requesting list of identifiers ...\n";
+    
+    my $base_wget_cmd = "wget $wgetopt -q -O - \"$base_url?_OPTS_\"";
+    my $identifiers_cmd = $base_wget_cmd;
+
+    my $identifiers_opts = "verb=ListIdentifiers&metadataPrefix=$format";
+
+    if (defined $set && ($set ne "")) {
+	$identifiers_opts .= "&set=$set";
+    }
+
+    $identifiers_cmd =~ s/_OPTS_/$identifiers_opts/;
+
+    my $li_record = wget_oai_url($identifiers_cmd,$out,$verbosity);
+
+    print $out "... Done.\n";
+
+    return $li_record;
+}
+
+sub parse_oai_ids
+{
+    my ($li_record, $out, $verbosity) = @_;
+
+    # extract identifier list
+    $li_record =~ s/^.*?<identifier>/<identifier>/s;
+    $li_record =~ s/^(.*<\/identifier>).*$/$1/s;
+
+    my @ids = ();
+
+    while ($li_record =~ m/<identifier>(.*?)<\/identifier>(.*)$/s)
+    {
+	$li_record = $2;
+	push(@ids,$1);
+    }
+
+    return \@ids;
+}
+
+
+sub dir_file_split
+{
+    my ($file) = @_;
+
+    my @dirs = split("/",$file);
+    my $local_file = pop(@dirs);
+    my $sub_dirs = join("/",@dirs);
+
+    return ($sub_dirs,$local_file);
+}
+
+sub get_oai_document
+{
+    my ($doc_url,$output_dir, $out) = @_;
+
+    my ($id_dir,$id_fname) = dir_file_split($doc_url);
+
+    print $out "Getting document $doc_url\n";
+
+    &util::mk_dir($output_dir)  if (!-e "$output_dir");
+
+    my $full_id_fname = &util::filename_cat($output_dir,$id_fname);
+
+    my $wget_cmd = "wget $wgetopt --quiet -O $full_id_fname \"$doc_url\"";
+
+    if (system($wget_cmd)!=0) {
+	print STDERR "Error: failed to execute $wget_cmd\n";
+	return 0;
+    }
+
+    return 1;    
+}
+
+sub get_oai_records
+{
+    my ($base_url,$format, $ids,$output_dir, $get_id, $maxdocs, $out) = @_;
+
+    my $doc_count = 0;
+
+    my $i;
+    foreach $i ( @$ids )
+    {
+	# wget it;
+	my $url = "$base_url?verb=GetRecord&metadataPrefix=$format";
+	$url .= "&identifier=$i";
+	print $out "Downloading metadata record for $i\n";
+
+        my $i_url = $i; #convert OAI set separators (:) to directory sep
+        $i_url =~ s/:/\//g;
+	my $file_i_url = "$output_dir/$i_url.oai";
+
+	my $ds = &util::get_dirsep();
+	my $i_os = $i; #convert OAI set separators (:) to OS dir sep
+	$i_os =~ s/:/$ds/g;
+	my $file_i = &util::filename_cat($output_dir,"$i_os.oai");
+
+	# obtain record
+	my $wget_cmd = "wget $wgetopt -q -O - \"$url\"";
+
+	open (OAIIN,"$wget_cmd|")
+	    || die "wget request failed: $!\n";
+	my $i_record = "";
+	
+	my $line;
+	while (defined($line=<OAIIN>))
+	{
+	    $i_record .= $line;
+	}
+
+	close(OAIIN);
+
+	$num_processed++;
+	
+	# prepare subdirectory for record (if needed)
+	my ($i_dir,$unused) = dir_file_split($file_i_url);
+
+	&util::mk_all_dir($i_dir);
+
+	# look out for identifier tag in metadata section
+	if ($i_record =~ m/<metadata>(.*)<\/metadata>/s)
+	{
+	    my $m_record = $1;
+
+	    if ($get_id)
+	    {
+		my $got_doc = 0;
+
+		my @url_matches = ($m_record =~ m/<(?:dc:)?identifier>(.*?)<\/(?:dc:)?identifier>/gs);
+		foreach my $doc_url (@url_matches) 
+		{
+		    if ($doc_url =~ m/^(http|ftp):/) {
+
+			my $revised_doc_url = $doc_url;
+##			$revised_doc_url =~ s/hdl\.handle\.net/mcgonagall.cs.waikato.ac.nz:8080\/dspace\/handle/;
+			
+			my $srcdocs_dir = &util::filename_cat($i_dir,"srcdocs");
+
+			if (get_oai_document($revised_doc_url,$srcdocs_dir, $out)) {			   
+
+			    $got_doc = 1;
+			    my ($id_dir,$id_fname) = dir_file_split($revised_doc_url);
+			    
+			    $i_record =~ s/<metadata>(.*?)<(dc:)?identifier>$doc_url<\/(dc:)?identifier>(.*?)<\/metadata>/<metadata>$1<OrigURL>$doc_url<\/OrigURL>\n   <identifier>srcdocs\/$id_fname<\/identifier>$4<\/metadata>/s;
+			    
+			}
+		    }
+
+		    if (!$got_doc) {
+			$i_record =~ s/<metadata>(.*?)<(dc:)?identifier>$doc_url<\/(dc:)?identifier>(.*?)<\/metadata>/<metadata>$1<OrigIdentifier>$doc_url<\/OrigIdentifier>$4<\/metadata>/s;
+		    }
+		}
+	    }
+	}
+
+	# save record 
+	open (OAIOUT,">$file_i")
+	    || die "Unable to save oai metadata record: $!\n";
+	print OAIOUT $i_record;
+	close(OAIOUT);
+
+	$doc_count++;
+	last if ($doc_count == $maxdocs);
+    }
+}
+
+
+sub main {
+    my ($verbosity, $importdir, $keepold, 
+	$getdoc, $acquire_info, $acquire_set,
+	$removeold, $gzip, $groupsize, $debug, $maxdocs, $collection,
+	$configfilename, $collectcfg,
+	$out, $collectdir);
+
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'getdoc', \$getdoc,
+			 'info', \$acquire_info,
+			 'importdir/.*/', \$importdir,
+			 'keepold', \$keepold,
+			 'removeold', \$removeold,
+			 'gzip', \$gzip,
+			 'debug', \$debug,
+			 'maxdocs/^\-?\d+/-1', \$maxdocs,
+			 'collectdir/.*/', \$collectdir,
+			 'out/.*/STDERR', \$out)) {
+	&print_usage();
+	die "\n";
+    }
+
+    my $close_out = 0;
+    if ($out !~ /^(STDERR|STDOUT)$/i) {
+	open (OUT, ">$out") || die "Couldn't open output file $out\n";
+	$out = 'import::OUT';
+	$close_out = 1;
+    }
+    $out->autoflush(1);
+
+    # set removeold to false if it has been defined
+    $removeold = 0 if ($keepold);
+
+    # get and check the collection name
+    if (($collection = &util::use_collection(@ARGV, $collectdir)) eq "") {
+	&print_usage();
+	die "\n";
+    }
+
+
+    # get acquire list
+    my $acquire = [];
+    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc", "collect.cfg");
+    if (-e $configfilename) {
+	$collectcfg = &colcfg::read_collect_cfg ($configfilename);
+	if (defined $collectcfg->{'acquire'}) {
+	    $acquire = $collectcfg->{'acquire'};
+	}
+	if (defined $collectcfg->{'importdir'} && $importdir eq "") {
+	    $importdir = $collectcfg->{'importdir'};
+	}
+	if (defined $collectcfg->{'removeold'}) {
+	    if ($collectcfg->{'removeold'} =~ /^true$/i && !$keepold) {
+		$removeold = 1;
+	    }
+	    if ($collectcfg->{'removeold'} =~ /^false$/i && !$removeold) {
+		$removeold = 0;
+	    }
+	}
+    } else {
+	die "Couldn't find the configuration file $configfilename\n";
+    }
+    
+    # fill in the default import directory if none
+    # were supplied, turn all \ into / and remove trailing /
+    $importdir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "import") if $importdir eq "";
+    $importdir =~ s/[\\\/]+/\//g;
+    $importdir =~ s/\/$//;
+
+    # remove the old contents of the import directory if needed
+    if ($removeold && -e $importdir) {
+	print $out "Warning - removing current contents of the import directory\n";
+	print $out "          in preparation for the acquire\n";
+	&util::rm_r ($importdir);
+    }
+
+    my $e;
+    foreach $e ( @$acquire )
+    {
+	my $acquire_type = shift @$e;
+	my $acquire_src = undef;
+
+	if ($acquire_type ne "OAI") {
+	    print STDERR "Warning: $acquire_type not currently supported. Skipping.\n";
+	    next;
+	}
+
+	my $store_getdoc = $getdoc;
+
+	if (!parsargv::parse($e, 
+			     'getdoc',  \$getdoc,
+			     'set/.*/', \$acquire_set,
+			     'format/.*/oai_dc', \$metadata_format,
+			     'src/.*/', \$acquire_src)) {
+	    &print_usage();
+	    die "\n";
+	}
+
+	if (!defined $acquire_src) {
+	    print STDERR "Warning: Not -src flag defined.  Skipping.\n";
+	    next;
+	}
+
+	if (defined $acquire_info && ($acquire_info)) {
+	    oai_info($acquire_src,$out,$verbosity);
+	    next;
+	}
+
+	print $out "$acquire_type Acquire: from $acquire_src\n";
+
+	my $li_record = get_oai_ids($acquire_src,$acquire_set,$metadata_format,
+				    $out,$verbosity);
+	my $ids = parse_oai_ids($li_record,$out,$verbosity);
+
+	get_oai_records($acquire_src,$metadata_format, $ids,$importdir, 
+			$getdoc, $maxdocs, $out);
+	$getdoc = $store_getdoc;
+    }
+
+    print "\nNumber of documents processed: $num_processed\n";
+
+    close OUT if $close_out;
+}
+
+
+&main();
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/Core.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/Core.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/Core.pm	(revision 10506)
@@ -0,0 +1,895 @@
+#
+# PDF::Core.pm, version 1.11 February 2000 antro
+#
+# Copyright (c) 1998 - 2000 Antonio Rosella Italy antro@tiscalinet.it, Johannes Blach dw235@yahoo.com 
+#
+# Free usage under the same Perl Licence condition.
+#
+
+package PDF::Core;
+
+$PDF::Core::VERSION = "1.11";
+
+=pod
+
+=head1 NAME
+
+PDF::Core - Core Library for PDF library
+
+=head1 SYNOPSIS
+
+  use PDF::Core;
+
+  $pdf=PDF::Core->new ;
+  $pdf=PDF->new(filename);
+
+  $res= $pdf->GetObject($ref);
+
+  $name = UnQuoteName($pdfname);							  
+  $string = UnQuoteString($pdfstring);							  
+
+  $pdfname = QuoteName($name);							  
+  $pdfhexstring = QuoteHexString($string);
+  $pdfstring = QuoteString($string);
+
+  $obj = PDFGetPrimitive (filehandle, \$offset);
+  $line = PDFGetLine (filehandle, \$offset);
+  
+
+=head1 DESCRIPTION
+
+The main purpose of the PDF::Core library is to provide the data structure
+and the constructor for the more general PDF library.
+
+=cut
+
+require 5.005;
+use strict;
+use Carp;
+use Exporter ();
+
+use vars qw(@ISA @EXPORT_OK $UseObjectCache);
+
+@ISA = qw(Exporter);
+
+@EXPORT_OK = qw( GetObject );
+
+#
+# Object caching
+#
+# If this variable is true, all processed objects will be added to the
+# object cache. If only header information of a PDF are read or very
+# big PDF are processed, turning off the cache reduces the memory usage.
+#
+$UseObjectCache = 1;
+
+
+#################################################################
+#
+# Helper functions
+#
+#################################################################
+
+=pod
+
+=head1 Helper functions
+
+This functions are not part of the class, but perform useful services.
+
+=cut
+
+#
+# Modification by johi: 18.12.1999
+#
+
+#################################################################
+=pod
+
+=head2 UnQuoteName ( string )
+
+This function processes quoted characters in a PDF-name. PDF-names returned by
+B<GetObject> are already processed by this function.
+
+Returns a string.
+
+=cut
+
+sub UnQuoteName ($)
+	{
+	my $value = shift;
+	$value =~ s/#([\da-f]{2})/chr(hex($1))/ige;
+	return $value;
+	}
+
+#################################################################
+=pod
+
+=head2 UnQuoteString ( string )
+
+This function extracts the text from PDF-strings and PDF-hexstrings.
+It will process all quoted characters and remove the enclosing braces.
+
+WARNING: The current version doesn't handle unicode strings properly.
+
+Returns a string.
+
+=cut
+
+sub UnQuoteString ($)
+	{
+#
+# Translate quoted character. 
+#
+	my $param = shift;
+	my $value;
+	if (($value) = $param =~ m/^<(.*)>$/)
+		{
+		$value =~ tr/0-9A-Fa-f//cd;
+		$value .= "0" if (length ($value) % 2);
+		$value =~ s/([\da-f]{2})/chr(hex($1))/ige;
+		}
+	elsif (($value) = $param =~ m/^\((.*)\)$/)
+		{
+		my %quoted = ("n" => "\n", "r" => "\r",
+					  "t" => "\t", "b" => "\b",
+					  "f" => "\f", "\\" => "\\",
+					  "(" => "(", ")" => ")");
+		$value =~ s/\\([nrtbf\\()]|[0-7]{1,3})/
+		defined ($quoted{$1}) ? $quoted{$1} : chr(oct($1))/gex;
+		}
+	else
+		{
+		$value = $param;
+		}
+
+	return $value;
+	}
+
+#################################################################
+=pod
+
+=head2 QuoteName ( string )
+
+This function quotes problematic characters in a PDF-name. This
+function should be used before writing a PDF-name back to a PDF-file.
+
+Returns a string.
+
+=cut
+
+sub QuoteName ($)
+	{
+	my $value = shift;
+	$value =~ s/(?<!\A)([\x00-\x20\x7f-\xff%()\[\]<>\/{}#])/
+						 sprintf ("#%2.2X", ord($1))/gex;
+	return $value;
+	}
+
+#################################################################
+=pod
+
+=head2 QuoteHexString ( string )
+
+This function translates a string into a PDF-hexstring. 
+
+Returns a string.
+
+=cut
+
+sub QuoteHexString ($)
+	{
+	my $value = shift;
+
+	$value =~ s/(.)/sprintf ("%2.2X", ord($1))/ge;
+	return ("<" . $value . ">");
+	}
+
+#################################################################
+=pod
+
+=head2 QuoteString ( string )
+
+This function translates a string into a PDF-string. Problematic
+character will be quoted.
+
+WARNING: The current version doesn't handle unicode strings properly.
+
+Returns a string.
+
+=cut
+
+sub QuoteString ($)
+	{
+	#
+	# Only \character style quotes will be added. The really important
+	# characters to quote are: ()\
+	# 
+	my $value = shift;
+
+	my %quote = ("\n" => "\\n", "\r" => "\\r",
+				  "\t" => "\\t", "\b" => "\\b",
+				  "\f" => "\\f", "\\" => "\\\\",
+				  "(" => "\\(", ")" => "\\)");
+	$value =~ s/([\n\r\t\b\f\\()])/$quote{$1}/g;
+	return ("(" . $value . ")");
+	}
+
+#################################################################
+=pod
+
+=head2 PDFGetPrimitive ( filehandle, offset )
+
+This internal function is used while parsing a PDF-file. If you are
+not writing extentions for this library and are parsing some special
+parts of the PDF-file, stay away and use B<GetObject> instead.
+
+This function has many quirks and limitations. Check the source for details.
+
+=cut
+
+sub PDFGetPrimitive (*\$)
+	{
+	my $fd = shift;
+	my $offset = shift;
+
+	binmode $fd;
+	seek $fd, $$offset, 0;
+
+	my $state = 0;
+	my $buffer;
+	my @collector;
+	my $lastchar;
+
+	while ()
+		{
+		# File offset is positioned on start of stream.
+		last if ($state == -4);
+
+		$state = 0;
+
+		# Process last element
+		if ($#collector >= 0)
+			{
+			my $lastvalue = $collector[$#collector];
+			
+			if ($lastvalue eq "R")
+				{
+				# Process references
+				if ($#collector >= 2
+					&& $collector[$#collector - 1] =~ m/\d+/
+					&& $collector[$#collector - 2] =~ m/\d+/)
+					{
+					$collector[$#collector - 2] .= join (" ", 
+						"", @collector[$#collector - 1, $#collector]);
+					$#collector -= 2; 
+					}
+				else
+					{
+					carp "Bad reference at offset ", $$offset;
+					}
+				}
+			elsif ($lastvalue eq "endobj")
+				{
+				# End of object
+				last;
+				}
+			elsif ($lastvalue eq "stream")
+				{
+				# End of object
+				$state = -4;
+				}
+			}
+		
+		# Set state for next element
+		if ($buffer eq "[") 
+			{
+			# Read array
+			$buffer = "";
+			push @collector, [ PDFGetPrimitive ($fd, $offset) ];
+			}
+		elsif ($buffer eq "<<")
+			{
+			# Read dictionary
+			$buffer = "";
+			push @collector, { PDFGetPrimitive ($fd, $offset) };
+			}
+		elsif ($buffer eq "(") 
+			{
+			# Here comes a string
+			$state = 1;
+			$lastchar = "";
+			}
+		elsif ($buffer eq "<") 
+			{
+			# Here comes a hex string
+			$state = -1;
+			}
+		elsif ($buffer eq ">")
+			{
+			# Wait for next > to terminate dictionary
+			$state = -2;
+			}
+		elsif ($buffer eq "%")
+			{
+			# Skip comments
+			$state = -3;
+			$buffer = "";
+			}
+		elsif ($buffer eq "]")
+			{
+			last;
+			}
+		elsif ($buffer eq ">>")
+			{
+			last;
+			}
+
+		# Read next item
+		while (read ($fd, $_, 1))
+			{
+			$$offset++;
+
+			if ($state == 0)
+				{
+				# Normal mode
+				if (m/[^\x00-\x20\x7f-\xff%()\[\]<>\/]/)
+					{
+					# Normal character inside a name or number
+					$buffer .= $_;
+					}
+				elsif (m/[\/\(\[\]\<\>%]/)
+					{
+					if ($buffer ne "")
+						{
+						# A new item starts
+						if ($buffer =~ m/^\//)
+							{
+							push @collector, UnQuoteName ($buffer);
+							}
+						else
+							{
+							push @collector, $buffer;
+							}
+						}
+					$buffer = $_;
+					last;
+					}
+				elsif (m/\s/)
+					{
+					# All kind of whitespaces are ignored
+					if ($buffer ne "")
+						{
+						# The old item is done starts
+						if ($buffer =~ m/^\//)
+							{
+							push @collector, UnQuoteName ($buffer);
+							}
+						else
+							{
+							push @collector, $buffer;
+							}
+						$buffer = "";
+						last;
+						}
+					}
+				else
+					{
+					# Strange character. Should not exist.
+					# Complain and move on.
+					carp "Strange character '", $_, "' at offset ",
+					$$offset, " in mode ", $state, " detected";
+					$buffer .= $_;
+					}
+				}
+			elsif ($state > 0)
+				{
+				# We have a string
+
+				if ($lastchar =~ m/\\[\r\n]+/ && m/[^\r\n]/)
+					{
+					# Clean up after line continuation
+					$lastchar = "";
+					}
+
+				if ($lastchar =~ m/\\[\r\n]*/)
+					{
+					# Process character after backslash
+					if (m/[\r\n]/)
+						{
+						# end of line
+						$lastchar .= $_;
+						}
+					else
+						{
+						# Just a quote
+						$buffer .= $lastchar . $_;
+						$lastchar = "";
+						}
+					}
+				else
+					{
+					if ($_ eq "\\")
+						{
+						# Quoted string starts
+						$lastchar = $_;
+						}
+					elsif ($_ eq "(")
+						{
+						# Count braces
+						$buffer .= $_;
+						$state ++;
+						}
+					elsif ($_ eq ")")
+						{
+						# End of string
+						$buffer .= $_;
+						unless (-- $state)
+							{
+							push @collector, $buffer;
+							$buffer = "";
+							last;
+							}
+						}
+					else
+						{
+						$buffer .= $_;
+						}
+					}
+				}
+			elsif ($state == -1)
+				{
+				if (m/[0-9a-f\s]/i)
+					{
+					# Hex character
+					$buffer .= $_;
+					}
+				elsif ($_ eq ">")
+					{
+					# End of string
+					$buffer .= $_;
+					push @collector, $buffer;
+					$buffer = "";
+					last;
+					}
+				elsif ($_ eq "<" && $buffer eq "<")
+					{
+					# This is not a string, but a dictionary instead
+					$buffer .= $_;
+					last;
+					}
+				else
+					{
+					# Should not be there. Complain and add it to the $buffer
+					carp "Bad character '", $_ , "' in hex string";
+					$buffer .= $_;
+					}
+				}
+			elsif ($state == -2)
+				{
+				# Wait for second > to terminate dictionary
+
+				# Some sanity checks
+				carp "Character '", $_, "' appeared while waiting for '>'" 
+				if ($_ ne ">");
+				carp "Buffer contains '", $buffer, "' and not '>'" 
+				if ($buffer ne ">");
+
+				$buffer = ">>";
+				last;
+				}
+			elsif ($state == -3)
+				{
+				# Skip comments;
+				last if (m/[\r\n]/);
+				}
+			elsif ($state == -4)
+				{
+				# Wait for newline to start stream
+
+				if ($_ eq "\n")
+					{
+					# Some sanity checks
+					carp "Text '", $buffer, 
+					"' appeared while waiting for start of stream" 
+					if ($buffer ne "");
+
+					$buffer = "";
+					last;
+					}
+				elsif (m/\S/)
+					{
+					$buffer .= $_;
+					}
+				}
+			else
+				{
+				# Unhandled status. Complain and reset
+				carp "Unhandled status ", $state;
+				}
+			}
+		if ($_ eq "")
+			{
+			# Unhandled status. Complain and reset
+			carp "Premature end of file reached";
+			
+			if ($buffer ne "")
+				{
+				push @collector, $buffer;
+				$buffer = "";
+				}
+			last;
+			}
+		}
+
+	return @collector;
+	}
+
+#################################################################
+=pod
+
+=head2 PDFGetline ( filehandle, offset )
+
+This internal function was used to read a line from a PDF-file. It has
+many limitations and you should stay away from it, if you don't know
+what you are doing. Use B<GetObject> or B<PDFGetPrimitive> instead.
+
+=cut
+
+sub PDFGetline {
+#
+# BUG WARNING:
+#
+# This function returns only one line, which doesn't mean anything most of the
+# time. Except for the fileheader and the xref-table, linebreaks can (and will!)
+# occur everywhere in a PDF and are just whitespace. You may find only part of a
+# PDF-primitve on one line, or more than one of them.
+#
+# If you want to read PDF-Primitves, use the function PDFGetPrimitive instead.
+#
+    my $fd = shift;
+    my $offset=shift;
+
+    my $buffer;
+    my $endflag=1;
+
+    binmode $fd;
+    seek $fd, $$offset, 0;
+
+    read($fd,$buffer,2);
+    $buffer =~ s/^\r?\n?// ;
+
+    $$offset +=2;
+
+    while ($endflag) {
+      read($fd,$_,1);
+      $$offset++;
+      $endflag = 0 if ( $_ eq "\r" || $_ eq "\n");
+      $buffer = $buffer . $_ ;
+    }
+    return $buffer;
+	}
+
+#################################################################
+#
+# Constructors
+#
+#################################################################
+
+=pod
+
+=head1 Constructor
+
+=cut
+
+#################################################################
+=pod
+
+=head2 new ( [ filename ] )
+
+This is the constructor of a new PDF object. If the filename is
+missing, it returns an empty PDF descriptor ( can be filled with
+$pdf->TargetFile). Otherwise, It acts as the B<PDF::Parse::TargetFile>
+method.
+
+=cut
+
+sub new {
+
+	my %PDF_Fields = (
+		  File_Name => undef, # Name of file
+		  File_Handler => undef, # Open handle to file
+		  Header => undef, # Identification string
+
+		  Objects => [], # Offset of objects
+		  Gen_Num => [], # Genereation number of objects
+		  Object_Length => [],	# Length of processed objects
+		  Object_Cache => {}, # Cache for objects.
+		  Page => [], # Information about all pages. Useful.
+
+		  Updated => 0,	# Is the PDF updated 
+		  Last_XRef_Offset => undef, # File offset of active Xref table
+		  Trailer => {}, # Content of active trailer
+		  Info => {}, # Content of active info object
+		  Catalog => {}, # Content of catalog
+		  PageTree => {}, # Content of root page
+		  );
+my $that = shift;
+my $class=ref($that) || $that ;
+  my $self = \%PDF_Fields ;
+  my $buf2=bless $self, $class;
+  if ( @_ ) { 			# I have the filename
+    $buf2->TargetFile($_[0]) ; 
+  }
+  return bless $self, $class;
+};
+
+#################################################################
+sub DESTROY {
+#
+# Close the file if not empty
+#
+  my $self = shift;
+  close ( $self->{File_Handler} ) if $self->{File_Handler} ;
+}
+
+#################################################################
+#
+# Methods
+#
+#################################################################
+
+=pod
+
+=head1 Methods
+
+The available methods are:
+
+=cut
+
+#################################################################
+=pod
+
+=head2 GetObject (reference)
+
+This methods returns the PDF-object for B<reference>. The string
+B<reference> must match the regular expression /^\d+ \d+ R$/,
+where the first number is the object number, the second number the
+generation number.
+
+The return value is a PDF-primitive, the type depends on the content
+of the object:
+
+=over
+
+=item B<undef>
+
+The object could not be found or an error. Not all referenced objects
+need to be present in a PDF-file. This value can be ignored.
+
+=item B<Hash Reference>
+
+If (UNIVERSAL::isa ($retval, "HASH") is true, the object is a
+PDF-dictionary. The keys of the hash should be either a PDF name (eg:
+/MediaBox) or a generated value like Stream_Offset. Everything else is
+an error.
+
+The values of the hash can be any PDF-primitive, including PDF-arrays
+and other dictionaries.
+
+This is the most common value returned by GetObject. If the key
+Stream_Offset exists, the dictionary is followed by stream data,
+starting at the file offeset indicated by this value.
+
+=item B<Array Reference>
+
+If (UNIVERSAL::isa ($retval, "ARRAY") is true, the object is a
+PDF-array. Each element may be of a different type, and may contain
+further references to arrays or any other PDF-primitive.
+
+=item B<String matching /^\d+ \d+ R$/>
+
+This is a reference to another PDF-Object. This value can be passed to
+GetObject. This kind of value may appear instead of most other types.
+Some PDF-writing programs seem to have special fun writing references
+when a simple number is expected. If the final number is need, use
+code like this to resolve references:
+
+while ($len =~ m/^\d+ \d+ R$/) {$len = $self->GetObject ($len);	}
+
+Example: 22 0 R
+
+=item B<String matching /^\//>
+
+This is a Name in a PDF dictionary. This string is already processed
+by B<UnQuotName> and may differ from the value in the PDF-file. In
+some very old andstrange non-standard PDF-files, this may lead to
+confusion.
+
+Example: /MediaBox
+
+=item B<String matching /^\(.*\)$/>
+
+This is a string. It may contain newlines, quoted characters und other
+strange stuff. Use PDF::UnQuoteString to extract the text.
+
+Example: (This is\na string with two \(2\) lines.)
+
+=item B<String matching /^E<lt>.*E<gt>$/>
+
+This is a hex encoded string. Use PDF::UnQuoteString to extract the text.
+
+Example: E<lt>48 45 4c4C4 F1cE<gt>
+
+=item B<String matching /^[\d.\+\-]+$/>
+
+This is probably a number.
+
+Example: 611
+
+=item B<String matching none of the above>
+
+this is either a PDF bareword (eg. true, false, ...) or a value
+generated by this method like Stream_Offset.
+
+Example: true
+
+=back
+
+To improve performance GetObject uses an internal cache for objects.
+Repeated requests for the same objects are not read form the file but
+satisfied from the cache. With the Variable B<$PDF::Core::UseObjectCache>,
+the caching mechanism can be turned off.
+
+B<WARNING>
+
+Special care must be taken, when returned objects are modified. If the
+object contains sub-objects, the sub-objects are not duplicated and
+all changes affect all other copies of this object. Use your own copy,
+if you need to modify those values.
+
+=cut
+
+sub GetObject (\*$;$)
+	{
+	my $self = shift;
+	my $ref = shift;
+	my $force = shift;
+
+#
+# Is PDF file open?
+#
+	croak "PDF-file not open." unless ($self->{"File_Handler"});
+
+#
+# Check reference
+#
+	my ($ind, $gen);
+	unless (($ind,$gen) = $ref =~ m/^(\d+) (\d+) R$/)
+		{
+		carp "Bad object reference '", $_, "'";
+		return undef;
+		}
+	if ($ind > $#{$self->{"Gen_Num"}} || $self->{"Gen_Num"}[$ind] != $gen)
+		{
+		#
+		# The page does not exist. According to the PDF specification,
+		# this is not an error.
+		#
+		return undef;
+		}
+
+	# Remove leading zero for cache key.
+	$ind += 0;
+	# Check cache
+	if ($UseObjectCache && ! $force
+		&& defined($self->{"Object_Cache"}{$ind}))
+		{
+		return $self->{"Object_Cache"}{$ind};
+		}
+
+	my $offset = $self->{"Objects"}[$ind];
+	my @data = PDFGetPrimitive ($self->{"File_Handler"}, $offset);
+
+	unless ($#data == 4  && $data[0] == $ind 
+		&& $data[1] == $gen && $data[2] eq "obj")
+		{
+		carp "Object mismatch: Got '", join (" ", @data[0..2]),
+		"' instead of '", join (" ", $ind, $gen, "obj"), "'";
+		return;
+		}
+
+	#
+	# An object is not always a dictionary. In such cases,
+	# adding additional keys breaks the content.
+	#
+	if (UNIVERSAL::isa ($data[3], "HASH"))
+		{
+		if ($data[4] eq "stream")
+			{
+			#
+			# Find end of a stream object
+			#
+			$data[3]{"Stream_Offset"} = $offset;
+			my $len = $data[3]{"/Length"};
+
+			# Length can be a reference to another object. 
+			# Resolve references in this case till something else appears.
+			while ($len =~ m/^\d+ \d+ R$/)
+				{
+				$len = $self->GetObject ($len);
+				}
+
+			# Skip stream
+			if ($len =~ m/^\d+$/)
+				{
+				$offset += $len;
+				}
+			else
+				{
+				carp "Strange: /Length resolves to '", $len, "' in object ", 
+				join (" ", @data[0..2]);
+				}
+
+			my @enddata = PDFGetPrimitive ($self->{"File_Handler"}, $offset);
+			$data[4] = $enddata[$#enddata];
+			}
+		}
+
+	#
+	# Save length of object.
+	#
+	$self->{"Object_Length"}[$ind] = $offset - $self->{"Objects"}[$ind];
+
+	carp "Bad object termination '", $data[4], "' in object ", 
+	join (" ", @data[0..2]) if ($data[4] ne "endobj");
+	
+
+	# Update cache
+	$self->{"Object_Cache"}{$ind} = $data[3] if ($UseObjectCache);
+
+	return $data[3];
+	}
+
+#
+# End of Modification by johi: 18.12.1999
+#
+#################################################################
+
+
+1;
+__END__
+
+=pod
+
+=head1 Variables
+
+Available variables are:
+
+=over 4
+
+=item B<$PDF::Core::VERSION>
+
+Contains the version of the library installed
+
+=item B<$PDF::Core::UseObjectCache>
+
+If this variable is true, all processed objects will be added to the
+object cache. If only header information of a PDF are read or very big
+PDF are processed, turning off the cache reduces the memory usage.
+
+=back 4
+
+=head1 Copyright
+
+  Copyright (c) 1998 - 2000 Antonio Rosella Italy antro@tiscalinet.it, Johannes Blach dw235@yahoo.com 
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 Availability
+
+The latest version of this library is likely to be available from:
+
+http://www.geocities.com/CapeCanaveral/Hangar/4794/
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/PDF.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/PDF.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/PDF.pm	(revision 10506)
@@ -0,0 +1,153 @@
+#
+# PDF.pm, version 1.11 February 2000 antro
+#
+# Copyright (c) 1998 - 2000 Antonio Rosella Italy antro@tiscalinet.it, Johannes Blach dw235@yahoo.com 
+#
+# Free usage under the same Perl Licence condition.
+#
+
+package PDF;
+
+$PDF::VERSION = "1.11";
+
+require 5.005;
+
+#require PDF::Core;  
+#require PDF::Parse; 
+require Core;  
+require Parse;
+ 
+use strict;
+use Carp;
+use Exporter ();
+
+use vars qw(@ISA $Verbose);
+
+#
+# Verbose off by default
+#
+$Verbose = 0;
+
+@ISA = qw(Exporter PDF::Core PDF::Parse);
+
+1;
+
+__END__
+
+=head1 NAME
+
+PDF - Library for PDF access and manipulation in Perl
+
+=head1 SYNOPSIS
+
+  use PDF;
+
+  $pdf=PDF->new ;
+  $pdf=PDF->new(filename);
+
+  $result=$pdf->TargetFile( filename );
+
+  print "is a pdf file\n" if ( $pdf->IsaPDF ) ;
+  print "Has ",$pdf->Pages," Pages \n";
+  print "Use a PDF Version  ",$pdf->Version ," \n";
+  print "and it is crypted  " if ( $pdf->IscryptedPDF) ;
+
+  print "filename with title",$pdf->GetInfo("Title"),"\n";
+  print "and with subject ",$pdf->GetInfo("Subject"),"\n";
+  print "was written by ",$pdf->GetInfo("Author"),"\n";
+  print "in date ",$pdf->GetInfo("CreationDate"),"\n";
+  print "using ",$pdf->GetInfo("Creator"),"\n";
+  print "and converted with ",$pdf->GetInfo("Producer"),"\n";
+  print "The last modification occurred ",$pdf->GetInfo("ModDate"),"\n";
+  print "The associated keywords are ",$pdf->GetInfo("Keywords"),"\n";
+
+  my (startx,starty, endx,endy) = $pdf->PageSize ($page) ;
+
+=head1 DESCRIPTION
+
+The main purpose of the PDF library is to provide classes and
+functions that allow to read and manipulate PDF files with perl. PDF
+stands for Portable Document Format and is a format proposed by Adobe.
+A full description of this format can be found in the B<Portable
+Document Reference Manual> by B<Adobe Systems Inc.>. For more details
+about PDF, refer to:
+
+B<http://www.adobe.com/>
+
+The main idea is to provide some "basic" modules for access 
+the information contained in a PDF file. Even if at this
+moment is in an early development stage, the scripts in the 
+example directory show that it is usable. 
+
+B<is_pdf> script test a list of files in order divide the PDF file
+from the non PDF using the info provided by the files 
+themselves. It doesn't use the I<.pdf> extension, it uses the information
+contained in the file.
+
+B<pdf_version> returns the PDF level used for writing a file.
+
+B<pdf_pages> gives the number of pages of a PDF file. 
+
+B<pagedump.pl> prints some information about individual pages in a
+PDF-file. Although the information as such are not very useful, it
+demontrates well some more complex aspects of the library. Check the
+function B<doprint> in this program on how to handle all possible data
+occuring in a PDF.
+
+The library is now splitted in 2 section :
+
+B<PDF::Core> that contains the data structure, the constructor and low
+level access fuctions;
+
+B<PDF::Parse> all kind of functions to parse the PDF-files and
+provide information about the content.
+
+Check the help-files of these modules for more details.
+
+=head1 Variables
+
+There are 2 variables that can be accessed:
+
+=over 4
+
+`=item B<$PDF::VERSION>
+
+Contain the version of the library installed.
+
+=item B<$PDF::Verbose>
+
+This variable is false by default. Change the value if you want 
+more verbose output messages from library.
+
+=back 4
+
+=head1 Copyright
+
+  Copyright (c) 1998 - 2000 Antonio Rosella Italy antro@tiscalinet.it, Johannes Blach dw235@yahoo.com 
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 Availability
+
+The latest version of this library is likely to be available from:
+
+http://www.geocities.com/CapeCanaveral/Hangar/4794/
+
+and at any CPAN mirror
+
+=head1 Greetings
+
+Fabrizio Pivari ( pivari@geocities.com ) for all the suggestions about life, the universe and everything.
+Brad Appleton ( bradapp@enteract.com ) for his suggestions about the module organization.
+Thomas Drillich for the iso latin1 support 
+Ross Moore ( ross@ics.mq.edu.au ) for ReadInfo fix
+
+=cut
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/Parse.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/Parse.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/Parse.pm	(revision 10506)
@@ -0,0 +1,513 @@
+#
+# PDF::Parse.pm, version 1.11 February 2000 antro
+#
+# Copyright (c) 1998 - 2000 Antonio Rosella Italy antro@tiscalinet.it, Johannes Blach dw235@yahoo.com 
+#
+# Free usage under the same Perl Licence condition.
+#
+
+package PDF::Parse;
+
+$PDF::Parse::VERSION = "1.11";
+
+=pod
+
+=head1 NAME
+
+PDF::Parse - Library with parsing functions for PDF library
+
+=head1 SYNOPSIS
+
+  use PDF::Parse;
+
+  $pdf->TargetFile($filename);
+  $pdf->LoadPageInfo;
+
+  $version = $pdf->Version;
+  $bool = $pdf->IsaPDF;
+  $bool = $pdf->IscryptPDF;
+
+  $info = $pdf->GetInfo ($key);
+  $pagenum = $pdf->Pages;
+
+  @size = $pdf->PageSize ($page);
+  # or
+  @size = $pdf->PageSize;
+
+  $rotation = $pdf->PageRotation ($page);
+  # or
+  $rotation = $pdf->PageRotation;
+
+=head1 DESCRIPTION
+
+The main purpose of the PDF::Parse library is to provide parsing functions
+for the more general PDF library.
+
+=head1 Methods
+
+The available methods are:
+
+=cut
+
+require 5.005;
+#require PDF::Core;
+require Core;
+
+use strict;
+use Carp;
+use Exporter ();
+
+use vars qw(@ISA @EXPORT_OK);
+
+@ISA = qw(Exporter PDF::Core);
+
+@EXPORT_OK = qw( LoadPageInfo GetInfo TargetFile
+				 Pages PageSize PageRotation IsaPDF
+				 Version IscryptPDF );
+
+#################################################################
+sub ReadCrossReference_pass1 {
+  my $fd = shift;
+  my $offset=shift;
+  my $self=shift;
+
+  my $initial_number;
+  my $obj_counter=0;
+  my $global_obj_counter=0;
+  my $buf;
+
+  binmode $fd;
+
+  $_=PDF::Core::PDFGetline ($fd,\$offset);
+
+  die "Can't read cross-reference section, according to trailer\n" if ! /xref\r?\n?/  ;
+
+  while () {
+    $_=PDF::Core::PDFGetline ($fd,\$offset);
+    s/^\n//;
+    s/^\r//;
+    last if (m/\btrailer\b/) ;
+#
+# An Object
+#
+    /^\d+\s+\d+\s+n\r?\n?/ && do { my $buf =$_;
+	       my $ind = $initial_number + ($obj_counter++);
+               ( not defined $self->{Objects}[$ind] )&& 
+		  do { $self->{Objects}[$ind] = int substr($buf,0,10);
+		       $self->{Gen_Num}[$ind] = int substr($buf,11,5);
+		     };
+	       $_=$buf;
+	       s/^.{18}//; 
+	       next ;
+   }; 
+#
+# A Freed Object
+#
+    /^\d+\s+\d+\s+f\r?\n?/ && do { my $buf =$_;
+   	       my $objects_generation_nr = substr($buf,11,5);
+	       my $Num=substr($buf,0,10);
+	       my $ind = $initial_number + ($obj_counter++);
+	       # $ind = $ind . "_" . $objects_generation_nr;
+		       $self->{Objects}[$ind] = - $Num;
+		       $self->{Gen_Num}[$ind] = $objects_generation_nr;
+		       $_=$buf;
+		       s/^.{18}//; 
+		       next ;
+     };
+#
+# A subsection
+#
+    /^\d+\s+\d+\r?\n?/  && do { 
+ 	my $buf = $_ ; 
+ 	 $initial_number = $buf; 
+ 	 $initial_number=~ s/^(\d+)\s+\d+\r?\n?.*/$1/; 
+	 $global_obj_counter += $obj_counter;
+ 	 $obj_counter=0; 
+	 next ;
+    };
+  }
+
+  $global_obj_counter +=$obj_counter;
+#
+# Now the trailer for updates 
+#
+
+#
+# Skip to start of dictionary.
+#
+    until (m/<</)
+		{
+		$_=PDF::Core::PDFGetline ($fd,\$offset);
+		}
+
+#
+# Read the dictionary
+#
+    my %trailer = ( PDF::Core::PDFGetPrimitive ($fd, $offset) );
+
+    if ($self->{"Trailer"}{"/Root"} eq "")
+		{
+		$self->{"Trailer"} = \%trailer;
+		#
+		# This code is here for backward compatibility only. If the content
+		# of the root trailer is needed, use $self->{"Trailer"} instead.
+		#
+		$self->{"Cross_Reference_Size"} = $trailer{"/Size"};
+		$self->{"Root_Object"} = $trailer{"/Root"};
+		$self->{"Crypt_Object"} = $trailer{"/Encrypt"};
+		}
+	if ($trailer{"/Prev"} =~ m/^\d+$/)
+		{  
+  		$self->{"Updated"} = 1;
+		my $old_seek = tell $fd;
+		$global_obj_counter += ReadCrossReference_pass1 ($fd,
+            $trailer{"/Prev"}, $self );
+		seek $fd, $old_seek, 0;
+		}
+
+
+  return $global_obj_counter;
+}
+
+#################################################################
+sub LoadPageSubtree (\*$;%)
+	{
+	my $self = shift;
+	my $ref = shift;
+	my %inheritance = @_ ;
+
+	my $data = $self->GetObject ($ref);
+
+	# Check which attributes are inherited. Adobe did not add any new
+	# inherited attributes in version 1.2 or later, so this list is
+	# complete.
+
+	# Do simple values.
+	foreach my $key ("/Rotate", "/Dur", "/Hid", "/Trans", 
+			 "/MediaBox", "/CropBox") {
+
+	    if (defined ($data->{$key})){
+
+		# Check if it is an indirect reference
+		if ($data->{$key} =~ m/^\d+ \d+ R$/) {
+		    
+		    my $dataref = $data->{$key};
+
+		    do {
+
+			$dataref = $self->GetObject ($dataref);
+
+		    } while ($dataref =~ m/^\d+ \d+ R$/);
+
+		    if (UNIVERSAL::isa ($data, "ARRAY")){
+
+			$inheritance{$key} = [];
+
+			foreach my $i (@{$data}){
+			    # Each element may be a reference.
+			    while ($i =~ m/^\d+ \d+ R$/){
+				$i = $self->GetObject ($i);
+			    }
+			    
+			    push @{$inheritance{$key}}, $i;
+			}
+		    } else {
+			$inheritance{$key} = $dataref;
+		    }
+		} else { #not an indirect reference
+		    $inheritance{$key} = $data->{$key};
+		}
+	    }
+	}
+	
+	# If this objects contains ressources, replace information in inheritance
+	$inheritance{"Resource_Object"} = $data->{"/Resources"}
+	    if (defined ($data->{"/Resources"}));
+
+	if ($data->{"/Type"} eq "/Pages")
+		{
+		# It's just an intermediate Node
+		foreach my $kid (@{$data->{"/Kids"}})
+			{
+			$self->LoadPageSubtree ($kid, %inheritance);
+			}
+		}
+	elsif ($data->{"/Type"} eq "/Page")
+		{
+		# We have a real page!
+		$inheritance{"Page_Object"} = $ref;
+		push @{$self->{"Page"}}, +{ %inheritance };
+		}
+	else
+		{
+		# Strange stuff. Complain and discard.
+		carp "While loading pages got object of type '", $data->{"/Type"}, "'";
+		}
+	}
+
+#################################################################
+=pod
+
+=head2 TargetFile ( filename )
+
+This method links the filename to the pdf descriptor and parses all
+kind of header information.
+
+=cut
+
+sub TargetFile {
+  my $self = shift;
+  my $file = shift;
+
+  croak "Already linked to the file ",$self->{File_Name},"\n" 
+      if $self->{File_Name} ;
+  
+  my $offset;
+
+  if ( $file ) {
+    open(FILE, "< $file") or croak "can't open $file: $!";
+    binmode FILE;
+    $self->{File_Name} = $file ;
+    $self->{File_Handler} = \*FILE;
+    my $buf;
+    read(FILE,$buf,4);
+    if ( $buf ne "%PDF" ) {
+     print "File $_[0] is not PDF compliant !\n" if $PDF::Verbose ;
+     return 0 ;
+    }
+    read(FILE,$buf,4);
+    $buf =~ s/-//;
+    $self->{Header}= $buf;
+    seek FILE,-50,2;
+    read( FILE, $offset, 50 );
+    $offset =~ s/[^s]*startxref\r?\n?(\d*)\r?\n?%%EOF\r?\n?/$1/;
+
+	$self->{"Last_XRef_Offset"} = $offset;
+    ReadCrossReference_pass1 (\*FILE, $offset, $self);
+	$self->{"Info"} = $self->GetObject ($self->{"Trailer"}{"/Info"});
+	$self->{"Catalog"} = $self->GetObject ($self->{"Trailer"}{"/Root"});
+	$self->{"PageTree"} = $self->GetObject ($self->{"Catalog"}{"/Pages"});
+    return 1;
+  } else {
+    croak "I need a file name (!)";
+	}
+}
+
+#################################################################
+=pod
+
+=head2 LoadPageInfo
+
+This function loads the information for all pages. This process can
+take some time for big PDF-files.
+
+=cut
+
+sub LoadPageInfo (\*)
+	{
+	my $self = shift;
+
+	# Reset Page Array
+	$#{$self->{"Page"}} = -1;
+
+	# Recurse
+	$self->LoadPageSubtree ($self->{"Catalog"}{"/Pages"});
+	}								
+
+
+
+#################################################################
+=pod
+
+=head2 Version
+
+Returns the PDF version used for writing the object file.
+
+=cut
+
+sub Version { 
+  return ($_[0]->{Header}); 
+}
+
+#################################################################
+=pod
+
+=head2 IsaPDF
+
+Returns true, if the file could be parsed and is a PDF-file.
+
+=cut
+
+sub IsaPDF { 
+  return ($_[0]->{Header} != undef) ; 
+}
+
+#################################################################
+=pod
+
+=head2 IscryptPDF
+
+Returns true if the PDF contains a crypt object. This indicates that
+the data of the PDF-File is encrypted. In this case, not all function
+work as expected.
+
+=cut
+
+sub IscryptPDF { 
+  return ($_[0]->{Crypt_Object} != undef) ; 
+}
+
+#################################################################
+=pod
+
+=head2 GetInfo ( key )
+
+Returns the various information contained in the info section of a PDF
+file (if present). A PDF file can have:
+
+  a title ==> GetInfo ("Title")
+  a subject ==> GetInfo ("Subject")
+  an author ==> GetInfo("Author")
+  a creation date ==> GetInfo("CreationDate")
+  a creator ==> GetInfo("Creator")
+  a producer ==> GetInfo("Producer")
+  a modification date ==> GetInfo("ModDate")
+  some keywords ==> GetInfo("Keywords")
+
+=cut
+
+sub GetInfo (\*$)
+	{
+	my $self = shift;
+	my $type = shift;
+
+	return PDF::Core::UnQuoteString ($self->{"Info"}{"/" . $type})
+	}
+
+#################################################################
+=pod
+
+=head2 Pages
+
+Returns the number of pages of the PDF-file.
+
+=cut
+
+sub Pages 
+	{
+	my $self = shift;
+
+	return $self->{"PageTree"}{"/Count"};
+	}
+
+
+
+#################################################################
+=pod
+
+=head2 PageSize ( [ page ] )
+
+Returns the size of a page in the PDF-file. If no parameter is given,
+the default size of the root page will be returned. This value may be
+overridden for any page.
+
+If the size of an individual page is requested and the page data is
+not already loaded, the method B<LoadPageInfo> will be executed. This
+may take some time for large PDF-files. The size of the root page is
+always available and will never execute B<LoadPageInfo>.
+
+=cut
+
+sub PageSize (;$)
+	{
+	my $self = shift;
+	my $page = shift;
+
+	if ($page > 0)
+		{
+		return undef if ($page > $self->{"PageTree"}{"/Count"});
+		$self->LoadPageInfo unless ($#{$self->{"Page"}} >= 0);
+		
+		return @{$self->{"Page"}[$page - 1]{"/MediaBox"}}
+		if (defined $self->{"Page"}[$page - 1]{"/MediaBox"});
+		}
+	else
+		{
+		return @{$self->{"PageTree"}{"/MediaBox"}}
+		if (defined $self->{"PageTree"}{"/MediaBox"});
+		}
+
+	return undef;
+	}
+
+
+#################################################################
+=pod
+
+=head2 PageRotation ( [ page ] )
+
+Returns the rotation of a page in the PDF-file. If no parameter is given,
+the default rotation of the root page will be returned. This value may be
+overridden for any page.
+
+If the rotation of an individual page is requested and the page data is
+not already loaded, the method B<LoadPageInfo> will be executed. This
+may take some time for large PDF-files. The rotation of the root page is
+always available and will never execute B<LoadPageInfo>.
+
+=cut
+sub PageRotation (;$)
+	{
+	my $self = shift;
+	my $page = shift;
+
+	my $rotate = 0;
+
+	if ($page > 0)
+		{
+		return undef if ($page > $self->{"PageTree"}{"/Count"});
+		$self->LoadPageInfo unless ($#{$self->{"Page"}} >= 0);
+		
+		$rotate = $self->{"Page"}[$page - 1]{"/Rotate"};
+		}
+	else
+		{
+		$rotate = $self->{"PageTree"}{"/Rotate"};
+		}
+
+	print "Rotation ", 0 + $rotate if ($PDF::Verbose);
+
+	return 0 + $rotate;
+	}
+#################################################################
+1;
+__END__
+
+=head1 Variables
+
+The only available variable is :
+
+=over
+
+=item B<$PDF::Parse::VERSION>
+
+Contains the version of the library installed
+
+=back
+
+
+=head1 Copyright
+
+  Copyright (c) 1998 - 2000 Antonio Rosella Italy antro@tiscalinet.it, Johannes Blach dw235@yahoo.com 
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 Availability
+
+The latest version of this library is likely to be available from:
+
+http://www.geocities.com/CapeCanaveral/Hangar/4794/
+
+=cut
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/amend_pdf.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/amend_pdf.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/amend_pdf.pl	(revision 10506)
@@ -0,0 +1,682 @@
+#!/usr/bin/perl
+#Jessica Thurston
+#usage: perl amend_pdf.pl filename
+#This program takes a pdf file 'filename'
+#and modifys it to include outline entries
+#(bookmarks).  
+#This is achieved using a pdf library which
+#parses the pdf file into objects allowing 
+#this script to more easily manipulate the pdf
+#objects and then modify the file by means
+#of incremental updates. (modifys the necessary
+#pdf objects and appends them to the end of 
+#the file, then updates the xreference table and
+#trailer). This library can be downloaded at
+# http://www.sanface.com/PDF-lib/
+#A file url.txt stored in the same
+#directory is read containing two columns of data:
+#title of related pdf document     url of related pdf document
+#The pdf document is modified so that the title of the
+#related pdf documents are displayed as bookmarks and
+#when the user clicks on it the web browser opens at
+#the url stored in the same column of url.txt.
+#
+#This program was designed to be used with the Greenstone
+#digital library in the following ways:
+#-When a user has built a collection containing
+# pdf documents, they have a choice of either displaying
+# the page in the web browser in gml form or saving the
+# original pdf document to view in an acrobat pdf reader.
+#-The related document file url.txt can be downloaded
+# in the same way if the user has included in the format
+# string for that page (ie search list) in the collection 
+# configuration file [urllink] related documents [/urllink].  
+# This will create a html link 'related documents' which 
+# when clicked on will enable the user to save a file url.txt 
+# containing the related documents for that particular document. 
+#-This file has been written upon running the perl script
+# relationPDF.pl which will also amend the gml documents to 
+# include the 'urllink' information enabling the user to 
+# include the related document links in config file format 
+# strings.
+#-So once this related doc info has been included the user
+# can download both the pdf file (doc.pdf) and the related
+# document file for that particluar document (url.txt).
+#-perl amend_pdf.pl doc.pdf is then run in the command line
+# modifying the pdf document to the desired effect.  
+#bugs:
+#-cannot be run more than once on the same file
+#-doesn't make use of free objects (free objects
+# are quite unlikely though, I didn't come across
+# any while looking through pdfs)
+#-many other things I haven't bothered testing
+
+use Carp;
+use Getopt::Long;
+use PDF;
+
+$objects = 0;
+$offsets = 1;
+
+
+#for each command line argument add the outlines
+#contained in url.txt
+#foreach (@ARGV) {
+#    create_outlines($_); 
+#}
+
+if(defined $ARGV[0]){
+    $pdf_document = $ARGV[0];
+} else {
+    print STDERR "You must supply pdf document filename\n";
+    return;
+}
+if(defined $ARGV[1]){
+    $related_docs = $ARGV[1];
+} else {
+print STDERR "You must supply related document filename\n";
+return;
+}
+create_outlines($pdf_document); 
+
+exit(1);
+
+
+#this function first checks to see is the file is indeed
+#a pdf file - if not then exits. If it is a pdf then it
+#checks to see if it is encrypted. If it is then exits.
+#Next we check if the outlines dictionary exists in the
+#document catalog. 
+#-If the outline entry exists but there are no actual outlines
+# present then call add_outlines but pass on the existing
+# outline dictionary.
+#-otherwise call modify_outlines to modify the existing outline
+# structure to include new outlines.
+#If outlines dictionary doesn't exist call add_outlines.
+sub create_outlines {
+
+  my $filename = shift;
+
+  #parse pdf filename
+  my @filelist = split("/", $filename);
+  my $file = pop @filelist;
+
+  print STDERR "pdf file to be manipulated: $file\n";
+  print STDERR "pdf file to be saved: tmp_$file\n";
+
+  #make a copy of that file in this directory
+  print STDERR "cp $filename $file\n"; 
+  `cp $filename $file\n`; 
+  `cp $filename tmp_$file\n`; 
+
+  #create and parse a new 'pdf' object
+  my $PDFfile = PDF->new($file);  
+
+  #if it is a pdf file
+  if ($PDFfile->{"Header"}){
+
+      if($PDFfile->IscryptPDF){
+	  #an encrypted file so cannot continue with
+	  #adding the related doc outlines to it 
+	  print STDERR "file \"$file\" is encrypted \n"; 
+	  return;
+      }
+
+      #display some relevant information about the document
+      print STDERR "Author: ", $PDFfile->GetInfo ("Author"), "\n"; 
+      print STDERR "Title: ", $PDFfile->GetInfo ("Title"), "\n"; 
+      print STDERR "Subject: ", $PDFfile->GetInfo ("Subject"), "\n"; 
+      print STDERR "Updated: ", $PDFfile->{"Updated"}, "\n";
+     
+      #if the pdf document already includes an outline dictionary
+      if (defined $PDFfile->{"Catalog"}{"/Outlines"}) {
+
+	  #get the outline object from the indirect ref
+	  my $outline_data = $PDFfile->GetObject($PDFfile->{"Catalog"}{"/Outlines"});
+	  #obtain the number of existing outlines
+	  $PDFfile->{"Outlines"}{"/Count"} = $outline_data->{"/Count"};
+	  print STDERR "number of existing outlines: $PDFfile->{\"Outlines\"}{\"/Count\"}\n";
+
+	  #this means that the pdf file had an outline dictionary but
+	  #did not actually include any outlines.
+	  if($PDFfile->{"Outlines"}{"/Count"} == 0){
+	      #obtain object number of outline dictionary and pass to add_outlines
+	      my $dictionary = split(/\s/, $PDFfile->{"Catalog"}{"/Outlines"});
+	     
+	      add_outlines($PDFfile, $file, $dictionary);
+	  } else { 
+	      #collect other outline data to pass to modify_outlines
+	      $PDFfile->{"Outlines"}{"/First"} = $outline_data->{"/First"};
+	      $PDFfile->{"Outlines"}{"/Last"} = $outline_data->{"/Last"};
+
+	      #modify last outline entry
+	      modify_outlines($outline_data, $PDFfile, $file);
+	  }
+      } else { #there was no outline dictionary thus no outlines so add some
+	  print STDERR "no bookmarks in \"$file\" \n"; 
+	  add_outlines($PDFfile, $file, 0);
+      }
+  } else { #the file was not a pdf file
+      print STDERR "$file is not a pdf file!!\n"; 
+  }
+
+
+  #copy back the file we modified and the saved copy 
+  my $copypath = join("/", @filelist);
+  print STDERR "cp $file $filename\n"; 
+  print STDERR "cp tmp_$file $copypath/tmp_$file\n"; 
+  `cp $file $filename\n`; 
+  `cp tmp_$file $copypath/tmp_$file\n`; 
+
+  #remove the copy of that file in this directory
+  #print STDERR "rm $file\n"; 
+  `rm $file\n`;  
+  `rm tmp_$file\n`; 
+}
+
+
+#add_outlines function recieves following params
+#PDF file information, filename of pdf file, outline dictionary
+#(if outline dict. is 0 that means it must be created).
+#First the function decides if we are to create new dictionary
+#or not. Next read in the url file. Open up the pdf document.
+#Modify the catalog so that it includes the outline dictionary
+#(this is done even if the catalog doesn't need modifying 
+# so that the objects in the objects/offset table will not
+# be all mucked up when it comes time to write the xreference
+# table)
+#Then append outline dictionary to end of file (either modified
+#or created). Then append the top heirarchy related document
+#outline.  Then the new file url bookmarks. Call  xref_table
+#to write new xreference table. Call trailer to write new trailer.
+
+#table[0][0] - document catalog
+#table[0][1] - document catalog offset
+#table[1][0] - outline dictionary
+#table[1][1] - outline dictionary offset
+#table[2][0] - related document outline
+#table[2][1] - related document outline offset
+#table[3][0] etc - url outlines, read from file
+#table[3][1] etc - url outlines offset, read from file
+
+sub add_outlines (*\$){
+    
+ my $PDFfile = shift; 
+ my $file = shift; 
+
+ my @table;
+ $table[1][$objects] = shift;
+
+ #read in file of url's
+ my @urls = read_file(); 
+ my $url_num = $#urls + 1;
+ 
+ #if outline dictionary was not present in catalog
+ if ($table[1][$objects] == 0){ #get new object number for new dictionary
+     $table[1][$objects] = $PDFfile->{"Trailer"}{"/Size"}; #outline dictionary to be created
+     $table[2][$objects] = $table[1][$objects] + 1; #related document outline
+ } else { #else get object number for related doc outline to be appended
+     $table[2][$objects] = $PDFfile->{"Trailer"}{"/Size"}; #related document outline
+ }
+ 
+ #open up pdf file for appending
+ open(FILE, ">> $file") or croak "can't open $file: $!"; 
+ binmode \*FILE;
+ 
+ #obtain object number and offset for the document catalog
+ $table[0][$objects] = split(/\s/, $PDFfile->{"Trailer"}{"/Root"});
+ $table[0][$offsets] = tell \*FILE;
+
+ #print the modified or original catalog back to the file (appended)
+ print FILE "$table[0][$objects] 0 obj
+";
+ print FILE "<<
+";
+ print FILE "/Pages $PDFfile->{\"Catalog\"}{\"/Pages\"}
+";
+ print FILE "/Outlines $table[1][$objects] 0 R
+"; #only line actually added
+ print FILE "/Type /Catalog
+";
+ print FILE "/DefaultGray $PDFfile->{\"Catalog\"}{\"/DefaultGray\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/DefaultGray"}));
+ print FILE "/DefaultRGB $PDFfile->{\"Catalog\"}{\"/DefaultRGB\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/DefaultRGB"}));
+ print FILE "/PageLabels $PDFfile->{\"Catalog\"}{\"/PageLabels\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/PageLabels"}));
+ print FILE "/Names $PDFfile->{\"Catalog\"}{\"/Names\"}
+" 
+     if (defined ($PDFfile->{"Catalog"}{"/Names"}));
+ print FILE "/Dests $PDFfile->{\"Catalog\"}{\"/Dests\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/Dests"}));
+ print FILE "/ViewerPreferences $PDFfile->{\"Catalog\"}{\"/ViewerPreferences\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/ViewerPreferences"}));
+ print FILE "/PageLayout $PDFfile->{\"Catalog\"}{\"/PageLayout\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/PageLayout"}));
+ print FILE "/PageMode $PDFfile->{\"Catalog\"}{\"/PageMode\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/PageMode"}));
+ print FILE "/Threads $PDFfile->{\"Catalog\"}{\"/Threads\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/Threads"}));
+ print FILE "/OpenAction $PDFfile->{\"Catalog\"}{\"/OpenAction\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/OpenAction"}));
+ print FILE "/URI $PDFfile->{\"Catalog\"}{\"/URI\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/URI"}));
+ print FILE "/Acroform $PDFfile->{\"Catalog\"}{\"/Acroform\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/Acroform"}));
+ print FILE "/StructTreeRoot $PDFfile->{\"Catalog\"}{\"/StructTreeRoot\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/StructTreeRoot"}));
+ print FILE "/SpiderInfo $PDFfile->{\"Catalog\"}{\"/SpiderInfo\"}
+"
+     if (defined ($PDFfile->{"Catalog"}{"/SpiderInfo"}));
+ print FILE ">>
+";
+ print FILE "endobj
+";
+ 
+ #obtain offset for outline dictionary
+ $table[1][$offsets] = tell \*FILE;
+
+ #append newly created outline dictionary
+ print FILE "$table[1][$objects] 0 obj
+";
+ print FILE "<<
+";
+ print FILE "/Type /Outlines
+";
+ print FILE "/Count ", $url_num + 1, "
+";
+ print FILE "/First $table[2][$objects] 0 R
+";
+ print FILE "/Last $table[2][$objects] 0 R
+";
+ print FILE ">>
+";
+ print FILE "endobj
+";
+
+
+ #get the related document outline object num and offset
+ my $obj = $table[2][$objects]; 
+ $table[2][$offsets] = tell \*FILE;
+
+ #append the top heirarchy related document outline to file 
+ print FILE "$table[2][$objects] 0 obj
+";
+ print FILE "<<
+";
+ print FILE "/Title (Related Documents)
+";
+ print FILE "/Parent $table[1][$objects] 0 R
+";
+ print FILE "/Count ", $url_num, "
+";
+ print FILE "/First ", $obj + 1, " 0 R
+";
+ print FILE "/Last ", $table[2][$objects] + $url_num, " 0 R
+";
+ print FILE ">>
+";
+ print FILE "endobj
+";
+
+ my $ind = 3;
+ $obj++;
+
+ 
+ #store the object nums and offsets of the new related document
+ #outlines and write them to the file (must be outline with
+ #an action eg go to specific url)
+ for $i ( 0 .. $#urls ) {
+     $table[$ind][$offsets] = tell \*FILE; 
+     $table[$ind][$objects] = $obj; 
+     print FILE "$obj 0 obj
+";
+     print FILE "<<
+";
+     print FILE "/Title ($urls[$i][0])
+"; 
+     print FILE "/Parent $table[2][$objects] 0 R
+";
+     print FILE "/Next ", $obj + 1, " 0 R
+" if (($obj + 1) <= ($table[2][$objects] + $url_num)); 
+     print FILE "/Prev ", $obj - 1, " 0 R
+" if(($obj - 1) != ($table[2][$objects]));
+     print FILE "/A << /Type /Action
+";
+     print FILE "/S /URI
+"; 
+     print FILE "/URI ($urls[$i][1])
+"; 
+     print FILE ">>
+";
+     print FILE ">>
+";
+     print FILE "endobj
+";
+     $obj++;
+     $ind++; 
+ }
+
+
+ #append new X-reference table 
+ my $xref_offset = tell \*FILE;
+ xref_table(\*FILE, $url_num, @table);
+
+ #print trailer 
+ trailer(\*FILE, $PDFfile, $obj); 
+ print FILE "$xref_offset
+";
+ print FILE "%%EOF
+"; 
+
+ #close FILE;
+}
+
+#modify_outlines function recieves following params
+#PDF file information, outline data, pdf filename
+#First the function obtains the object data for the
+#last outline entry. Next read in the url file. 
+#Open up the pdf document.Then append the modified 
+#outline dictionary to end of file. Next append the
+#modified last outline.  Then append the 
+#top heirarchy related document outline.  Then the 
+#new file url bookmarks. Call  xref_table
+#to write new xreference table. 
+#Call trailer to write new trailer.
+
+#table[0][0] - outline dictionary
+#table[0][1] - outline dictionary offset
+#table[1][0] - last outline
+#table[1][1] - last outline offset
+#table[2][0] - related document outline
+#table[2][1] - related document outline offset
+#table[3][0] etc - url outlines, read from file
+#table[3][1] etc - url outlines offset, read from file
+
+sub modify_outlines (*\$){
+
+    my ($outline_data, $PDFfile, $file) = @_;
+
+    #collect the data for the last outline (which must be modified)
+    $PDFfile->{"Outlines"}{"/Last"} = $outline_data->{"/Last"};
+    my $last_data = $PDFfile->GetObject($PDFfile->{"Outlines"}{"/Last"});  
+
+    #read in file of url's
+    my @urls = read_file(); 
+    my $url_num = $#urls + 1;
+ 
+    my @table;
+
+    #This number is the number to use for the next created object
+    #eg the related doc heirarchy
+    $table[2][$objects] = $PDFfile->{"Trailer"}{"/Size"};
+  
+    #open up the pdf file for appending
+    open(FILE, ">> $file") or croak "can't open $file: $!"; 
+    binmode \*FILE;
+    
+    #store the object number and offset of the outline dictionary
+    $table[0][$objects] = split(/\s/, $PDFfile->{"Catalog"}{"/Outlines"});
+    $table[0][$offsets] = tell \*FILE;
+   
+    #write the outline dictionary back to the file (appending)
+    print FILE "$table[0][$objects] 0 obj
+";
+    print FILE "<<
+";
+    print FILE "/Type /Outlines
+";
+    print FILE "/Count ", $PDFfile->{"Outlines"}{"/Count"} + 1, "
+"
+	if (defined ($PDFfile->{"Outlines"}{"/Count"}));
+    print FILE "/First $PDFfile->{\"Outlines\"}{\"/First\"}
+"
+	if (defined ($PDFfile->{"Outlines"}{"/First"}));
+    print FILE "/Last $table[2][$objects] 0 R
+";
+    print FILE ">>
+";
+    print FILE "endobj
+";
+    
+    #store the last outline entry object num and file offset
+    my @last_entry = split(/\s/, $PDFfile->{"Outlines"}{"/Last"});
+    $table[1][$objects] = $last_entry[0]; 
+    $table[1][$offsets] = tell \*FILE; 
+
+    #append modified last outline entry
+    print FILE "$table[1][$objects] 0 obj
+";
+    print FILE "<<
+";
+    print FILE "/Title $last_data->{\"/Title\"}
+";
+    print FILE "/Dest $last_data->{\"/Dest\"}
+" if(defined $last_data->{"/Dest"});
+    print FILE "/Parent $last_data->{\"/Parent\"}
+";
+    print FILE "/Prev $last_data->{\"/Prev\"}
+";
+    print FILE "/Next $table[2][$objects] 0 R
+";
+    print FILE "/First $last_data->{\"/First\"}
+" if(defined $last_data->{"/First"});
+    print FILE "/Last $last_data->{\"/Last\"}
+" if(defined $last_data->{"/Last"});
+    print FILE "/Count $last_data->{\"/Count\"}
+"if(defined $last_data->{"/Count"});
+    print FILE "/A $last_data->{\"/A\"}
+" if(defined $last_data->{"/A"});
+    print FILE "/SE $last_data->{\"/SE\"}
+" if(defined $last_data->{"/SE"});
+    print FILE ">>
+";
+    print FILE "endobj
+";
+    
+    #store the object num and offset of the related
+    #document top level outline
+    my $obj = $table[2][$objects] + 1;
+    $table[2][$offsets] = tell \*FILE;
+
+    #append related document top level outline
+    print FILE "$table[2][$objects] 0 obj
+";
+    print FILE "<<
+";
+    print FILE "/Title (Related Documents)
+"; 
+    print FILE "/Parent $last_data->{\"/Parent\"}
+";
+    print FILE "/Count ", $url_num, "
+";
+    print FILE "/First $obj 0 R
+";
+    print FILE "/Last ", $table[2][$objects] + $url_num , " 0 R
+";
+    print FILE ">>
+";
+    print FILE "endobj
+";
+    
+   
+    my $ind = 3;
+
+    #store the object nums and offsets of the new related document
+    #outlines and write them to the file (must be outline with
+    #an action eg go to specific url)
+    for $i ( 0 .. $#urls ) { 
+	$table[$ind][$objects] = $obj;  
+	$table[$ind][$offsets] = tell \*FILE; 
+	print FILE "$obj 0 obj
+";
+	print FILE "<<
+";
+	print FILE "/Title ($urls[$i][0])
+"; 
+	print FILE "/Parent $table[2][$objects] 0 R
+";
+	print FILE "/Next ", $obj + 1, " 0 R
+" if (($obj + 1) <= ($table[2][$objects] + $url_num)); 
+	print FILE "/Prev ", $obj - 1, " 0 R
+" if (($obj - 1) != ($table[2][$objects]));
+	print FILE "/A << /Type /Action
+";
+	print FILE "/S /URI
+"; 
+	print FILE "/URI ($urls[$i][1])
+"; 
+	print FILE ">>
+";
+	print FILE ">>
+";
+	print FILE "endobj
+";
+	$obj++;
+	$ind++;
+    }
+    
+    #append new X-reference table
+    my $xref_offset = tell \*FILE;   
+    xref_table(\*FILE, $url_num, @table); 
+  
+    #print trailer  
+    trailer(\*FILE, $PDFfile, $obj);
+    print FILE "$xref_offset
+";
+    print FILE "%%EOF
+"; 
+
+    close FILE;
+
+}
+
+
+#This function reads a file 'url.txt' which contains
+#two columns of data in the following format:
+#related document title    related document url
+#each array of title, url is stored in an array
+#(to obtain the title of the first related  
+#document in the file)
+#eg table[1st related document][title] 
+#(to obtain the url of the second related 
+#document in the file)
+#eg table[2nd related document][url]
+#this table is then returned to the calling 
+#function.
+sub read_file {
+
+    #create two-dimensional array for urls
+    my @urls;
+
+    #open up url.txt to start reading
+    open(URL, "$related_docs") or croak "Can't open $related_docs: $!"; 
+
+    my $counter = 0;
+
+    #read in url.txt and store into the arry
+    while (<URL>){
+	chomp;
+	if(/([^\t]*)\t(.*)/){ 
+	    push @urls, [ split ]; #split on /s into arrays of arrays
+	}
+    }
+
+    close URL;
+
+    return (@urls);
+
+}
+
+ 
+#this function takes as parameters the filehandle
+#to the pdf document, the number of related documents
+#to this pdf doc and a table of object numbers and
+#their offsets. Using this information it writes
+#(appends) a new xreference table to the pdf 
+#document. 
+
+sub xref_table  (*\$) {
+    
+    my ($fd, $num, @table) = @_;
+    my $offset;
+
+    #print the new xref table (append to file)
+    print $fd "xref
+";
+    print $fd "0 1 
+";
+    print $fd "0000000000 65535 f 
+";
+    print $fd "$table[0][$objects] 1 
+";
+    $offset = '0'x(10-length($table[0][$offsets])).$table[0][$offsets];
+    print $fd "$offset 00000 n 
+";
+    print $fd "$table[1][$objects] 1 
+"; 
+    $offset = '0'x(10-length($table[1][$offsets])).$table[1][$offsets];
+    print $fd "$offset 00000 n 
+";
+    print $fd "$table[2][$objects] ", $num + 1, " 
+"; 
+    for $i ( 2 .. ($num + 2) ) { #add 2 on because already written 2 to file
+	$offset = '0'x(10-length($table[$i][$offsets])).$table[$i][$offsets];
+	print $fd "$offset 00000 n 
+";
+    }
+    
+}
+
+
+#This function recieves as parameters the filehandle
+#to the pdf document, parsed information about the
+#document and the new size (last object number + 1)
+#of the pdf file.  Using this information it appends
+#a new trailer to the end of the pdf document.
+
+sub trailer  (*\$) {
+
+    my ($fd, $PDFfile, $new_size) = @_;
+
+    #append the new trailer to the end of the file
+    print $fd "trailer
+";
+    print $fd "<<
+";
+    print $fd "/Size ", $new_size, "
+";
+    print $fd "/Root $PDFfile->{\"Trailer\"}{\"/Root\"}
+";
+    print $fd "/Info $PDFfile->{\"Trailer\"}{\"/Info\"}
+" 
+	if (defined ($PDFfile->{"Trailer"}{"/Info"}));
+    print $fd "/ID [$PDFfile->{\"Trailer\"}{\"/ID\"}[0]$PDFfile->{\"Trailer\"}{\"/ID\"}[1]]
+"
+	if (defined ($PDFfile->{"Trailer"}{"/ID"}));
+    print $fd "/Prev $PDFfile->{\"Last_XRef_Offset\"}
+";
+    print $fd "/Encrypt $PDFfile->{\"Trailer\"}{\"/Encrypt\"}
+"
+	if (defined ($PDFfile->{"Trailer"}{"/Encrypt"}));
+    print $fd ">>
+";
+    print $fd "startxref
+";
+   
+}
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/buildkpi.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/buildkpi.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/buildkpi.pl	(revision 10506)
@@ -0,0 +1,491 @@
+#! /user/bin/perl 
+
+#usage: perl buildkpi.pl [-R] [collection] [collection] etc
+#
+#-r or -R will remove previous index files so that you may build new ones
+#
+#The program performs the following tasks:
+#-gathers the specified collections on the command line OR
+#-gathers the directories of all the collections in the collect directory, this is all
+# the directories apart from CVS, modelcol, . and .. which are not collections.
+#-It then retrieves the archive.inf file from the archive directory of each collection
+# to obtain the unique file ID and filepath of every document in the collection
+#-Then parse through each doc.gml stored in filepath to gather information
+#-From each file collect kea phrases and/or stems
+#-Determine the number of kea phrases and stems for each document 
+#-Search for the kea phrases in the numbered phrase index. If a phrase is not there then 
+# the program will write the kea phrase to the phrase index . 
+#-Search for the kea phrases in the keyphrase to document index. If the phrase is there, 
+# it will increment the number of documents that the keyphrase appears in and replace that
+# then append the hash ID to the list of documents in the entry. If the phrase is not there 
+# then the program will write the kea phrase to the phrase index.
+#-Then write document ID, no of phrase, phrase number from index followed by number of times 
+# phrase appears into the document_keyphrase index
+
+$gsdlhome = $ENV{'GSDLHOME'};
+
+require "getopts.pl";
+&Getopts('R'); #process option arguments
+
+
+#collections may be specified in the command line
+#otherwise, all collections will be used to build
+#the indexes.  
+if(@ARGV){
+
+    @directories = @ARGV;
+
+} else { #open collect directory and get a list of all collections
+    opendir(DIR, "$gsdlhome/collect");
+    @directories = grep(!/(^\.|(CVS)|(modelcol))/, readdir(DIR));
+    closedir(DIR);
+}
+
+
+#directory to store indexes in using collection names
+$dirname = "";
+foreach $collection (sort @directories){
+    $dirname .= $collection."_";
+}
+$dirname .= "indexes";
+print STDERR "directory name: $dirname\n";
+
+#if option R remove all previous indexes
+if($opt_R == 1){ #remove indexes
+    print STDERR "\nremoving $gsdlhome/bin/script/indexes/$dirname/keyphrase_index.txt\n";
+    print STDERR "removing $gsdlhome/bin/script/indexes/$dirname/keyphrase_document.txt\n";
+    print STDERR "removing $gsdlhome/bin/script/indexes/$dirname/document_keyphrase.txt\n";
+    system("rm $gsdlhome/bin/script/indexes/$dirname/keyphrase_document.txt");   
+    system("rm $gsdlhome/bin/script/indexes/$dirname/document_keyphrase.txt"); 
+    system("rm $gsdlhome/bin/script/indexes/$dirname/keyphrase_index.txt");
+} 
+
+#create the new directory, display an error message if the directory
+#already exists.
+`mkdir --verbose $gsdlhome/bin/script/indexes/$dirname`;
+
+#for each collection specified to build indexes for
+foreach $collection (@directories){
+
+    print STDERR "\nBUILDING INDEXES FOR COLLECTION $collection\n\n";
+
+    my @filelist;
+
+    #archives.inf contains a list of unique hash ID's of each file and file paths
+    open(INFO, "$gsdlhome/collect/$collection/archives/archives.inf")
+	or die "$gsdlhome/collect/$collection/archives/archives.inf could not be opened.";
+
+    while(<INFO>){ #get each line of text from archives.inf (OID \t filepath)
+	chomp;
+	push(@filelist, $_);
+    }
+
+    foreach $file (@filelist){ #add each document to the indexes
+	build_index($file, $collection);
+    }
+}
+
+#This function opens the file in the filepath sent as an argument.  From this it obtains 
+#the kea and/or stem data, and then searches for these phrases in the file, counting and storing 
+#how many times each phrase appears. The data is then sent to function keyphrase_document 
+#with arguments hash ID, kea phrases and stem phrases to build the keyphrase_document index.
+#The function which builds the document_keyphrase index is then passed the hash ID, the kea 
+#phrases and/or the stemmed phrases and the array/s which hold the number of times each phrase
+#appears in the document so that the data it has collected can be written to document_ keyphrase
+#index.
+
+sub build_index {
+
+    my $args = shift(@_);
+    my $collection = shift(@_);
+    my ($ID, $filepath) = split(/\t/, $args);
+    my $keaS = "";
+    my $stemsS = "";
+    my @kea_phrase_counts = 0;
+    my @stem_phrase_counts = 0;
+    my $text = "";
+
+    print STDERR "\nID: $ID\n";
+    print STDERR "filepath: $filepath\n";
+
+    #open file to extract keyphrase information
+    open(FILE, "$gsdlhome/collect/$collection/archives/$filepath")
+	or die "$gsdlhome/collect/$collection/archives/$filepath could not be opened.";
+
+    #patterns to search for so that we can extract the kea information
+    my $kea_search = ".* kea=\"([^\"]*)\"";
+    my $stem_search = "stems=\"([^\"]*)\"";
+
+    while(<FILE>){ #get kea and stem data and store
+	chomp;
+	$keaS = $1 if (/$kea_search/);
+	$stemsS = $1 if (/$stem_search/);
+    }
+
+    close(FILE);
+    
+    print STDERR "Kea: $keaS\n";
+    print STDERR "stems: $stemsS\n";
+
+    my @kea = split(", ", $keaS);
+    my @stems = split(", ", $stemsS);
+
+    if(@kea && @stems){ #if the data exists
+	
+	#open the filepath to the current document
+	open(FILE, "$gsdlhome/collect/$collection/archives/$filepath")
+	    or die "$gsdlhome/collect/$collection/archives/$filepath could not be opened.";
+	
+	while(<FILE>){ #get the text
+	    chomp;
+	    $text .= $_;
+	}
+ 
+	#chop out all things in angled brackets
+	$text =~ s/(<[^>]*>)//g;
+
+	#initilise counts
+	for($i=0; $i<=$#kea; $i++){
+	    $kea_phrase_counts[$i] = 0;
+	}
+	
+	for($i=0; $i<=$#stems; $i++){
+	    $stem_phrase_counts[$i] = 0;
+	}
+
+	print STDERR "counting number of kea phrases in document...\n";
+
+	#using regular expressions generated from kea-reg and stem-reg
+	#count how many of each phrase appear in the document
+	$text_copy = $text;
+	for($i=0; $i<=$#kea; $i++){ #search for text with kea phrases
+	    my $phrase = $kea[$i];
+	    $reg = &kea_reg(split(/\s+/, $phrase));
+	    while($text_copy =~ s/$reg//i){
+		$kea_phrase_counts[$i]++; #count the number of kea phrases 
+	    } 
+	    $text_copy = $text;
+	}  
+
+	print STDERR "counting number of stemmed phrases in document...\n";
+
+	$text_copy = $text;
+	for($i=0; $i<=$#stems; $i++){ #search for text with stem phrases
+	    my $stem = $stems[$i];
+	    $reg = &stem_reg(split(/\s+/, $stem));
+	    while($text_copy =~ s/$reg//i){
+		$stem_phrase_counts[$i]++; #count the number of stem phrases
+	    } 
+	    $text_copy = $text;
+	}
+
+	
+	#write data to keyphrase_document index
+	&keyphrase_document($ID, $keaS, $stemsS); 
+	
+	#write data to document_keyphrase index
+	$kea_counts = join(", ", @kea_phrase_counts);
+	$stem_counts = join(", ", @stem_phrase_counts);
+	&document_keyphrase($ID, $keaS, $stemsS, $kea_counts, $stem_counts);
+	
+    } else { 
+	print STDERR "No kea data was found in file $filepath\n";
+    }
+
+}
+
+#returns a regular expression designed to 
+#search for stems in text
+#eg 'agri cari'
+#    agri followed by 0 or more non-whitespace characters
+#         followed by one or more whitespace OR 0 or 1 non-whitespace characters
+#    cari followed by 0 or more non-whitespace characters
+#modified from original by Stephen Lundy 
+
+sub stem_reg {
+   
+    $regexp = "";
+
+    $l = @_;
+
+    if ($l > 0) {
+        $s = shift;
+        $regexp = "$s\\S*";
+
+        if ($l-1 > 0) {
+            foreach $s (@_) {
+                $regexp .= "(\\s+|\\S?)$s\\S*";
+            }
+        }
+    }
+
+    return $regexp;
+}
+
+#returns a regular expression designed to 
+#search for phrases in text
+#eg 'agris caris'
+#    agris followed by 0 or 1 non-whitespace characters OR
+#          followed by one or more whitespace 
+#    caris followed by 0 or 1 non-whitespace characters
+#modified from original by Stephen Lundy 
+
+sub kea_reg {
+    $regexp = "";
+
+    $l = @_;
+
+    if ($l > 0) {
+        $s = shift;
+        #$regexp = "$s(\\S?)";
+	$regexp = "$s(\\s+|\\S?)";
+
+        if ($l-1 > 0) {
+            foreach $s (@_) {
+                $regexp .= "$s(\\s+|\\S?)";
+            }
+        }
+    }
+
+    return $regexp;
+}
+
+
+#This function is passed as arguments a list of kea phrases and/or stems. Its purpose is to 
+#check in the keyphrase index file for each phrase and determine whether or not an entry has
+#been made for that phrase and an index number assigned to it. If there has not been an entry
+#made then an index number is assigned to the phrase and it is written to the file.  This 
+#function is called by document_keyphrase and keyphrase_document.  Each line in the file has
+#this form:
+#-phrase index number:phrase
+#This function then returns a table of pairs of the phrases that were sent as arguments to it
+#{phrase => phrase index number}.
+ 
+sub keyphrase_index_search {
+
+    my $phrases = shift(@_); 
+    my @phrases = split(", ", $phrases);
+    my %table;
+    my $index = 1;
+    my $create_new_index = 0;
+
+    print STDERR "searching keyphrase index...\n";
+
+    #initilise table of phrases and index numbers
+    foreach $phrase (@phrases){
+	$table{"$phrase"} = "0";
+    }
+
+    #open keyphrase index for appending data and for reading
+    open(INDEX_OUT, ">>$gsdlhome/bin/script/indexes/$dirname/keyphrase_index.txt");
+    open(INDEX_IN, "$gsdlhome/bin/script/indexes/$dirname/keyphrase_index.txt")
+	or $create_new_index = 1;
+
+    if($create_new_index == 0){
+	#if the index already exists read in the phrases
+	while(<INDEX_IN>){
+	    chomp;
+	    foreach $phrase (@phrases){
+		if(/(\d+):$phrase/){
+		    $index = $1;
+		    $table{"$phrase"} = "$index";
+		}
+	    }
+	    $index++; #new starting index (one + the last index)
+	}
+
+	close(INDEX_IN);
+
+    }
+
+    #add new phrases to the phrase index
+    foreach $phrase (keys %table){
+	if($table{"$phrase"} eq "0"){
+	    print INDEX_OUT "$index:$phrase\n";
+	    $table{"$phrase"} = "$index"; 
+	    $index++;
+	}
+    }
+
+    close(INDEX_OUT);
+    return %table;
+}
+
+#This function is passed as arguments file hash ID and a list of kea phrases and/or stems
+#that exist for that particular file.  Its purpose is to write to the keyphrase_document
+#index a line for the document it has been sent:
+#-phrase index number:number of documents it appears in|ID
+sub keyphrase_document{
+
+    my ($ID, $kea, $stems) = @_;
+    my $text = ""; 
+    my @textlist;
+    my $create_new_index = 0;
+
+    print STDERR "writing to keyphrase_document.txt...\n";
+
+    #get table of phrases and phrase indexes 
+    my %table = keyphrase_index_search($kea.", ".$stems); 
+    
+  
+    #open index for reading
+    open(INDEX_IN, "$gsdlhome/bin/script/indexes/$dirname/keyphrase_document.txt")
+	or $create_new_index = 1;
+
+    #read in document if file exists
+    if($create_new_index == 0){
+
+	while(<INDEX_IN>){
+	    $text .= $_;
+	}
+
+	close(INDEX_IN);
+
+	#split text into lines
+	@textlist = split(/\n/, $text);
+
+    } 
+
+    #open index for output
+    open(INDEX_OUT, ">$gsdlhome/bin/script/indexes/$dirname/keyphrase_document.txt");
+
+    if($create_new_index == 0){ #amend existing index
+	
+	foreach $line (@textlist){
+	    foreach $phrase (keys %table){
+		if($line =~ /(\d+):(\d+)(.*)/){ #all lines of this form
+		    $index = $1;
+		    if($table{"$phrase"} eq "$index") { #if phrase exists in index
+			$ids = $3; #get all doc IDs for that keyphrase
+			if($ids !~ /$ID/){ #if doc ID not already included
+			    $num_docs = $2;
+			    $num_docs++; #increment number of docs
+			    $line = "$index:$num_docs$3|$ID"; #line to append to index
+			    $table{"$phrase"} = "0"; 
+			}
+		    }
+		}
+	    }
+	    print INDEX_OUT "$line\n";
+	}
+    }
+
+    #add new phrases to the index
+    foreach $phrase (keys %table){ #write 'phrase index:1:file ID
+	if($table{"$phrase"} ne "0"){
+	    my $line = "$table{$phrase}:1:$ID";
+	    print INDEX_OUT "$line\n"; 
+	}
+    }
+
+    close(INDEX_OUT);
+
+}
+
+#This function is passed as arguments file hash ID and a list of kea phrases and/or stems
+#that exist for that particular file and a list of the number of times each kea and/or stem
+#phrase appear in that document.  Its purpose is to write to the document_keyphrase
+#index a line for the document it has been sent:
+#-file ID:number of phrases and/or stems appear in the document
+#      |pairs of 'phrase index,number of times the phrase appears in the document' 
+sub document_keyphrase {
+
+    my ($ID, $keaS, $stemsS, $kea_c, $stem_c) = @_;
+    my $text = "";
+    my @textlist;
+    my %phrases;
+    my $create_new_index = 0;
+
+    print STDERR "writing to document_keyphrase.txt...\n";
+
+    #split phrase counts into arrays
+    my @kea_counts = split(", ", $kea_c);
+    my @stem_counts = split(", ", $stem_c);
+  
+    #get table of phrases and phrase indexes
+    my %table = keyphrase_index_search($keaS.", ".$stemsS);
+
+    #split phrases into arrays
+    my @kea = split(", ", $keaS);
+    my @stems = split(", ", $stemsS);
+
+    #build new phrases dictionary
+    for($i=0; $i<=$#kea; $i++){
+	my $phrase = $table{"$kea[$i]"};
+	if($kea_counts[$i] > 0){
+	    $phrases{"$phrase"} = "$kea_counts[$i]";
+	} else {
+	    $phrases{"$phrase"} = 1;
+	}
+    } 
+    for($i=0; $i<=$#stems; $i++){
+	my $phrase = $table{"$stems[$i]"};
+	if($stem_counts[$i] > 0){
+	    $phrases{"$phrase"} = "$stem_counts[$i]";
+	} else {
+	    $phrases{"$phrase"} = 1;
+	}
+    }   
+    my @num = keys %phrases;
+    my $phrasenum = $#num + 1; #number of phrases in doc
+
+    #open index for reading
+    open(INDEX_IN, "$gsdlhome/bin/script/indexes/$dirname/document_keyphrase.txt")
+	or $create_new_index = 1;
+
+     
+    if($create_new_index == 0){ #index doesn't need to be created
+
+	while(<INDEX_IN>){
+	    $text .= $_;
+	}
+
+	close(INDEX_IN);
+	
+	#split text into lines
+	@textlist = split(/\n/, $text);
+
+    }  
+
+
+    #must write this line to the file
+    #document ID:num of phrases|phrase index, number of times phrases appears
+    my $newline = "$ID:$phrasenum";
+    foreach $phrase (keys %phrases){
+	$newline .= "|$phrase,$phrases{$phrase}";
+    }
+
+    #open index for output
+    open(INDEX_OUT, ">$gsdlhome/bin/script/indexes/$dirname/document_keyphrase.txt");
+
+    if($create_new_index == 1){ #create a new index
+
+	print INDEX_OUT "$newline\n";
+
+    } else {
+
+	#if ID is already in the file write line overtop incase
+	#someone has modified the file.  Otherwise add the line
+	#to the end of the file
+	my $found = 0;
+
+	foreach $line (@textlist){
+	    if($line =~ /([^:]+):(.*)/){ #all lines should follow this pattern
+		$id = $1;
+		if($ID eq $id){ #id is already in the file
+		    print INDEX_OUT "$newline\n"; #print line overtop
+		    $found = 1;
+		} else {
+		    print INDEX_OUT "$line\n"; #print old line out
+		}
+	    }
+	}
+
+	print INDEX_OUT "$newline\n" if ($found == 0); #append new line to end of file 
+
+    }
+
+    close(INDEX_OUT);
+
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/buildkpiK.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/buildkpiK.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/buildkpiK.pl	(revision 10506)
@@ -0,0 +1,411 @@
+#! /user/bin/perl 
+
+#usage: perl buildkpiK.pl [-R] [collection] [collection] etc
+#
+#-r or -R will remove previous index files so that you may build new ones
+#
+#The program performs the following tasks:
+#-gathers the specified collections on the command line OR
+#-gathers the directories of all the collections in the collect directory, this is all
+# the directories apart from CVS, modelcol, . and .. which are not collections.
+#-It then retrieves the archive.inf file from the archive directory of each collection
+# to obtain the unique file ID and filepath of every document in the collection
+#-Then parse through each doc.gml stored in filepath to gather information
+#-From each file collect kea phrases. 
+#-Determine the number of kea phrases for each document 
+#-Search for the kea phrases in the numbered phrase index. If a phrase is not there then 
+# the program will write the kea phrase to the phrase index . 
+#-Search for the kea phrases in the keyphrase to document index. If the phrase is there, 
+# it will increment the number of documents that the keyphrase appears in and replace that
+# then append the hash ID to the list of documents in the entry. If the phrase is not there 
+# then the program will write the kea phrase to the phrase index.
+#-Then write document ID, no of phrase, phrase number from index followed by number of times 
+# phrase appears into the document_keyphrase index
+
+$gsdlhome = $ENV{'GSDLHOME'};
+$collection;
+
+require "getopts.pl";
+&Getopts('R'); #process option arguments
+
+#if option R remove all previous indexes
+if($opt_R == 1){ #remove indexes
+    print STDERR "\nremoving $gsdlhome/bin/script/indexes/keyphrase_index.txt\n";
+    print STDERR "removing $gsdlhome/bin/script/indexes/keyphrase_document.txt\n";
+    print STDERR "removing $gsdlhome/bin/script/indexes/document_keyphrase.txt\n";
+    system("rm $gsdlhome/bin/script/indexes/keyphrase_document.txt");   
+    system("rm $gsdlhome/bin/script/indexes/document_keyphrase.txt"); 
+    system("rm $gsdlhome/bin/script/indexes/keyphrase_index.txt");
+}
+
+#collections may be specified in the command line
+#otherwise, all collections will be used to build
+#the indexes.  
+if(@ARGV){
+
+    @directories = @ARGV;
+
+} else { #open collect directory and get a list of all collections
+    opendir(DIR, "$gsdlhome/collect");
+    @directories = grep(!/(^\.|(CVS)|(modelcol))/, readdir(DIR));
+    closedir(DIR);
+}
+
+#for each collection specified to build indexes for
+foreach $collection (@directories){
+
+    my @filelist;
+
+    #archives.inf contains a list of unique hash ID's of each file and file paths
+    open(INFO, "$gsdlhome/collect/$collection/archives/archives.inf")
+	or die "$gsdlhome/collect/$collection/archives/archives.inf could not be opened.";
+
+    while(<INFO>){ #get each line of text from archives.inf (OID \t filepath)
+	chomp;
+	push(@filelist, $_);
+    }
+
+    foreach $file (@filelist){ #add each document to the indexes
+	build_index($file, $collection);
+    }
+}
+
+#This function opens the file in the filepath sent as an argument.  From this it obtains 
+#the kea data, and then searches for these phrases in the file, counting and storing 
+#how many times each phrase appears. The data is then sent to function keyphrase_document 
+#with arguments hash ID, kea phrases to build the keyphrase_document index.
+#The function which builds the document_keyphrase index is then passed the hash ID, the kea 
+#phrases and the array/s which hold the number of times each phrase
+#appears in the document so that the data it has collected can be written to document_ keyphrase
+#index.
+
+sub build_index {
+
+    my $args = shift(@_);
+    my $collection = shift(@_);
+    my ($ID, $filepath) = split(/\t/, $args);
+    my $keaS = "";
+    my @kea_phrase_counts = 0;
+    my $text = "";
+
+    print STDERR "\nID: $ID\n";
+    print STDERR "filepath: $filepath\n";
+
+    #open file to extract keyphrase information
+    open(FILE, "$gsdlhome/collect/$collection/archives/$filepath")
+	or die "$gsdlhome/collect/$collection/archives/$filepath could not be opened.";
+
+    #patterns to search for so that we can extract the kea information
+    my $kea_search = ".* kea=\"([^\"]*)\"";
+
+    while(<FILE>){ #get kea and stem data and store
+	chomp;
+	$keaS = $1 if (/$kea_search/);
+    }
+
+    close(FILE);
+    
+    print STDERR "Kea: $keaS\n";
+
+    my @kea = split(", ", $keaS);
+
+    if(@kea){ #if the data exists
+	
+	#open the filepath to the current document
+	open(FILE, "$gsdlhome/collect/$collection/archives/$filepath")
+	    or die "$gsdlhome/collect/$collection/archives/$filepath could not be opened.";
+	
+	while(<FILE>){ #get the text
+	    chomp;
+	    $text .= $_;
+	}
+ 
+	#chop out all things in angled brackets
+	$text =~ s/(<[^>]*>)//g;
+
+	#initilise counts
+	for($i=0; $i<=$#kea; $i++){
+	    $kea_phrase_counts[$i] = 0;
+	}
+	
+	
+	#using regular expressions generated from kea-reg 
+	#count how many of each phrase appear in the document
+	$text_copy = $text;
+	for($i=0; $i<=$#kea; $i++){ #search for text with kea phrases
+	    my $phrase = $kea[$i];
+	    $reg = &kea_reg(split(/\s+/, $phrase));
+	    while($text_copy =~ s/$reg//i){
+		$kea_phrase_counts[$i]++; #count the number of kea phrases 
+	    } 
+	    $text_copy = $text;
+	}  
+	
+	#write data to keyphrase_document index
+	&keyphrase_document($ID, $keaS); 
+	
+	#write data to document_keyphrase index
+	$kea_counts = join(", ", @kea_phrase_counts);
+	&document_keyphrase($ID, $keaS, $kea_counts);
+	
+    } else { 
+	print STDERR "No kea data was found in file $filepath\n";
+    }
+
+}
+
+
+#returns a regular expression designed to 
+#search for phrases in text
+#eg 'agris caris'
+#    agris followed by 0 or 1 non-whitespace characters OR
+#          followed by one or more whitespace 
+#    caris followed by 0 or 1 non-whitespace characters
+#modified from original by Stephen Lundy 
+
+sub kea_reg {
+    $regexp = "";
+
+    $l = @_;
+
+    if ($l > 0) {
+        $s = shift;
+        #$regexp = "$s(\\S?)";
+	$regexp = "$s(\\s+|\\S?)";
+
+        if ($l-1 > 0) {
+            foreach $s (@_) {
+                $regexp .= "$s(\\s+|\\S?)";
+            }
+        }
+    }
+
+    return $regexp;
+}
+
+
+#This function is passed as arguments a list of kea phrases and/or stems. Its purpose is to 
+#check in the keyphrase index file for each phrase and determine whether or not an entry has
+#been made for that phrase and an index number assigned to it. If there has not been an entry
+#made then an index number is assigned to the phrase and it is written to the file.  This 
+#function is called by document_keyphrase and keyphrase_document.  Each line in the file has
+#this form:
+#-phrase index number:phrase
+#This function then returns a table of pairs of the phrases that were sent as arguments to it
+#{phrase => phrase index number}.
+ 
+sub keyphrase_index_search {
+
+    my $phrases = shift(@_);
+    my @phrases = split(", ", $phrases);
+    my %table;
+    my $index = 1;
+    my $create_new_index = 0;
+
+    print STDERR "searching keyphrase index...\n";
+
+    #initilise table of phrases and index numbers
+    foreach $phrase (@phrases){
+	$table{"$phrase"} = "0";
+    }
+
+    #open keyphrase index for appending data and for reading
+    open(INDEX_OUT, ">>$gsdlhome/bin/script/indexes/keyphrase_index.txt");
+    open(INDEX_IN, "$gsdlhome/bin/script/indexes/keyphrase_index.txt")
+	or $create_new_index = 1;
+
+    if($create_new_index == 0){
+	#if the index already exists read in the phrases
+	while(<INDEX_IN>){
+	    chomp;
+	    foreach $phrase (@phrases){
+		if(/(\d+):$phrase/){
+		    $index = $1;
+		    $table{"$phrase"} = "$index";
+		}
+	    }
+	    $index++; #new starting index (one + the last index)
+	}
+
+	close(INDEX_IN);
+
+    }
+
+    #add new phrases to the phrase index
+    foreach $phrase (keys %table){
+	if($table{"$phrase"} eq "0"){
+	    print INDEX_OUT "$index:$phrase\n";
+	    $table{"$phrase"} = "$index"; 
+	    $index++;
+	}
+    }
+
+    close(INDEX_OUT);
+    return %table;
+}
+
+#This function is passed as arguments file hash ID and a list of kea phrases
+#that exist for that particular file.  Its purpose is to write to the keyphrase_document
+#index a line for the document it has been sent:
+#-phrase index number:number of documents it appears in|ID
+sub keyphrase_document{
+
+    my ($ID, $kea) = @_;
+    my $text = ""; 
+    my @textlist;
+    my $create_new_index = 0;
+
+    print STDERR "writing to keyphrase_document.txt...\n";
+
+    #get table of phrases and phrase indexes 
+    my %table = keyphrase_index_search($kea); 
+    
+  
+    #open index for reading
+    open(INDEX_IN, "$gsdlhome/bin/script/indexes/keyphrase_document.txt")
+	or $create_new_index = 1;
+
+    #read in document if file exists
+    if($create_new_index == 0){
+
+	while(<INDEX_IN>){
+	    $text .= $_;
+	}
+
+	close(INDEX_IN);
+
+	#split text into lines
+	@textlist = split(/\n/, $text);
+
+    } 
+
+    #open index for output
+    open(INDEX_OUT, ">$gsdlhome/bin/script/indexes/keyphrase_document.txt");
+
+    if($create_new_index == 0){ #amend existing index
+	
+	foreach $line (@textlist){
+	    foreach $phrase (keys %table){
+		if($line =~ /(\d+):(\d+)(.*)/){ #all lines of this form
+		    $index = $1;
+		    if($table{"$phrase"} eq "$index") { #if phrase exists in index
+			$ids = $3; #get all doc IDs for that keyphrase
+			if($ids !~ /$ID/){ #if doc ID not already included
+			    $num_docs = $2;
+			    $num_docs++; #increment number of docs
+			    $line = "$index:$num_docs$3|$ID"; #line to append to index
+			    $table{"$phrase"} = "0"; 
+			}
+		    }
+		}
+	    }
+	    print INDEX_OUT "$line\n";
+	}
+    }
+
+    #add new phrases to the index
+    foreach $phrase (keys %table){ #write 'phrase index:1:file ID
+	if($table{"$phrase"} ne "0"){
+	    my $line = "$table{$phrase}:1:$ID";
+	    print INDEX_OUT "$line\n"; 
+	}
+    }
+
+    close(INDEX_OUT);
+
+}
+
+#This function is passed as arguments file hash ID and a list of kea phrases and/or stems
+#that exist for that particular file and a list of the number of times each kea and/or stem
+#phrase appear in that document.  Its purpose is to write to the document_keyphrase
+#index a line for the document it has been sent:
+#-file ID:number of phrases and/or stems appear in the document
+#      |pairs of 'phrase index,number of times the phrase appears in the document' 
+sub document_keyphrase {
+
+    my ($ID, $keaS, $kea_c) = @_;
+    my $text = "";
+    my @textlist;
+    my %phrases;
+    my $create_new_index = 0;
+
+    print STDERR "writing to document_keyphrase.txt...\n";
+
+    #split phrase counts into arrays
+    my @kea_counts = split(", ", $kea_c);
+  
+    #get table of phrases and phrase indexes
+    my %table = keyphrase_index_search($keaS);
+
+    #split phrases into arrays
+    my @kea = split(", ", $keaS);
+
+    #build new phrases dictionary
+    for($i=0; $i<=$#kea; $i++){
+	my $phrase = $table{"$kea[$i]"};
+	$phrases{"$phrase"} = "$kea_counts[$i]";
+    } 
+   
+    my @num = keys %phrases;
+    my $phrasenum = $#num + 1; #number of phrases in doc
+
+    #open index for reading
+    open(INDEX_IN, "$gsdlhome/bin/script/indexes/document_keyphrase.txt")
+	or $create_new_index = 1;
+
+     
+    if($create_new_index == 0){ #index doesn't need to be created
+
+	while(<INDEX_IN>){
+	    $text .= $_;
+	}
+
+	close(INDEX_IN);
+	
+	#split text into lines
+	@textlist = split(/\n/, $text);
+
+    }  
+
+
+    #must write this line to the file
+    #'document ID:num of phrases|phrase index, number of times phrases appears
+    my $newline = "$ID:$phrasenum";
+    foreach $phrase (keys %phrases){
+	$newline .= "|$phrase,$phrases{$phrase}";
+    }
+
+    #open index for output
+    open(INDEX_OUT, ">$gsdlhome/bin/script/indexes/document_keyphrase.txt");
+
+    if($create_new_index == 1){ #create a new index
+
+	print INDEX_OUT "$newline\n";
+
+    } else {
+
+	#if ID is already in the file write line overtop incase
+	#someone has modified the file.  Otherwise add the line
+	#to the end of the file
+	my $found = 0;
+
+	foreach $line (@textlist){
+	    if($line =~ /([^:]+):(.*)/){ #all lines should follow this pattern
+		$id = $1;
+		if($ID eq $id){ #id is already in the file
+		    print INDEX_OUT "$newline\n"; #print line overtop
+		    $found = 1;
+		} else {
+		    print INDEX_OUT "$line\n"; #print old line out
+		}
+	    }
+	}
+
+	print INDEX_OUT "$newline\n" if ($found == 0); #append new line to end of file 
+
+    }
+
+    close(INDEX_OUT);
+
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/buildkpiS.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/buildkpiS.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/buildkpiS.pl	(revision 10506)
@@ -0,0 +1,420 @@
+#! /user/bin/perl 
+
+#usage: perl buildkpiS.pl [-R] [collection] [collection] etc
+#
+#-r or -R will remove previous index files so that you may build new ones
+#
+#The program performs the following tasks:
+#-gathers the specified collections on the command line OR
+#-gathers the directories of all the collections in the collect directory, this is all
+# the directories apart from CVS, modelcol, . and .. which are not collections.
+#-It then retrieves the archive.inf file from the archive directory of each collection
+# to obtain the unique file ID and filepath of every document in the collection
+#-Then parse through each doc.gml stored in filepath to gather information
+#-From each file collect stems of kea keyphrases.
+#-Determine the number of keyphrase stems for each document 
+#-Search for the keyphrase stems in the numbered phrase index. If a phrase is not there then 
+# the program will write the keyphrase stem to the phrase index . 
+#-Search for the keyphrase stem in the keyphrase to document index. If the stem is there, 
+# it will increment the number of documents that the keyphrase stem appears in and replace that
+# then append the hash ID to the list of documents in the entry. If the stem is not there 
+# then the program will write the stem to the phrase index.
+#-Then write document ID, no of phrase, phrase number from index followed by number of times 
+# phrase appears into the document_keyphrase index
+
+$gsdlhome = $ENV{'GSDLHOME'};
+$collection;
+
+require "getopts.pl";
+&Getopts('R'); #process option arguments
+
+#if option R remove all previous indexes
+if($opt_R == 1){ #remove indexes
+    print STDERR "\nremoving $gsdlhome/bin/script/indexes/keyphrase_index.txt\n";
+    print STDERR "removing $gsdlhome/bin/script/indexes/keyphrase_document.txt\n";
+    print STDERR "removing $gsdlhome/bin/script/indexes/document_keyphrase.txt\n";
+    system("rm $gsdlhome/bin/script/indexes/keyphrase_document.txt");   
+    system("rm $gsdlhome/bin/script/indexes/document_keyphrase.txt"); 
+    system("rm $gsdlhome/bin/script/indexes/keyphrase_index.txt");
+}
+
+#collections may be specified in the command line
+#otherwise, all collections will be used to build
+#the indexes.  
+if(@ARGV){
+
+    @directories = @ARGV;
+
+} else { #open collect directory and get a list of all collections
+    opendir(DIR, "$gsdlhome/collect");
+    @directories = grep(!/(^\.|(CVS)|(modelcol))/, readdir(DIR));
+    closedir(DIR);
+}
+
+#for each collection specified to build indexes for
+foreach $collection (@directories){
+
+    my @filelist;
+
+    #archives.inf contains a list of unique hash ID's of each file and file paths
+    open(INFO, "$gsdlhome/collect/$collection/archives/archives.inf")
+	or die "$gsdlhome/collect/$collection/archives/archives.inf could not be opened.";
+
+    while(<INFO>){ #get each line of text from archives.inf (OID \t filepath)
+	chomp;
+	push(@filelist, $_);
+    }
+
+    foreach $file (@filelist){ #add each document to the indexes
+	build_index($file, $collection);
+    }
+}
+
+#This function opens the file in the filepath sent as an argument.  From this it obtains 
+#the kea and/or stem data, and then searches for these phrases in the file, counting and storing 
+#how many times each phrase appears. The data is then sent to function keyphrase_document 
+#with arguments hash ID, kea phrases and stem phrases to build the keyphrase_document index.
+#The function which builds the document_keyphrase index is then passed the hash ID, the kea 
+#phrases and/or the stemmed phrases and the array/s which hold the number of times each phrase
+#appears in the document so that the data it has collected can be written to document_ keyphrase
+#index.
+
+sub build_index {
+
+    my $args = shift(@_);
+    my $collection = shift(@_);
+    my ($ID, $filepath) = split(/\t/, $args);
+    my $stemsS = "";
+    my @stem_phrase_counts = 0;
+    my $text = "";
+
+    print STDERR "\nID: $ID\n";
+    print STDERR "filepath: $filepath\n";
+
+    #open file to extract keyphrase information
+    open(FILE, "$gsdlhome/collect/$collection/archives/$filepath")
+	or die "$gsdlhome/collect/$collection/archives/$filepath could not be opened.";
+
+    #patterns to search for so that we can extract the kea information
+    my $stem_search = "stems=\"([^\"]*)\"";
+
+    while(<FILE>){ #get kea and stem data and store
+	chomp;
+	$stemsS = $1 if (/$stem_search/);
+    }
+
+    close(FILE);
+    
+    print STDERR "stems: $stemsS\n";
+
+    my @stems = split(", ", $stemsS);
+
+    if(@stems){ #if the data exists
+	
+	#open the filepath to the current document
+	open(FILE, "$gsdlhome/collect/$collection/archives/$filepath")
+	    or die "$gsdlhome/collect/$collection/archives/$filepath could not be opened.";
+	
+	while(<FILE>){ #get the text
+	    chomp;
+	    $text .= $_;
+	}
+ 
+	#chop out all things in angled brackets
+	$text =~ s/(<[^>]*>)//g;
+
+	#initilise counts
+	for($i=0; $i<=$#stems; $i++){
+	    $stem_phrase_counts[$i] = 0;
+	}
+	
+	#using regular expressions generated from stem-reg
+	#count how many of each phrase appear in the document
+	
+	$text_copy = $text;
+	for($i=0; $i<=$#stems; $i++){ #search for text with stem phrases
+	    my $stem = $stems[$i];
+	    $reg = &stem_reg(split(/\s+/, $stem));
+	    while($text_copy =~ s/$reg//i){
+		$stem_phrase_counts[$i]++; #count the number of stem phrases
+	    } 
+	    $text_copy = $text;
+	}
+
+	
+	#write data to keyphrase_document index
+	&keyphrase_document($ID, $stemsS); 
+	
+	#write data to document_keyphrase index
+	$stem_counts = join(", ", @stem_phrase_counts);
+	&document_keyphrase($ID, $stemsS, $stem_counts);
+	
+    } else { 
+	print STDERR "No stem data was found in file $filepath\n";
+    }
+
+}
+
+#returns a regular expression designed to 
+#search for stems in text
+#eg 'agri cari'
+#    agri followed by 0 or more non-whitespace characters
+#         followed by one or more whitespace OR 0 or 1 non-whitespace characters
+#    cari followed by 0 or more non-whitespace characters
+#modified from original by Stephen Lundy 
+
+sub stem_reg {
+   
+    $regexp = "";
+
+    $l = @_;
+
+    if ($l > 0) {
+        $s = shift;
+        $regexp = "$s\\S*";
+
+        if ($l-1 > 0) {
+            foreach $s (@_) {
+                $regexp .= "(\\s+|\\S?)$s\\S*";
+            }
+        }
+    }
+
+    return $regexp;
+}
+
+
+
+#This function is passed as arguments a list of kea phrase stems. Its purpose is to 
+#check in the keyphrase index file for each phrase and determine whether or not an entry has
+#been made for that phrase and an index number assigned to it. If there has not been an entry
+#made then an index number is assigned to the phrase and it is written to the file.  This 
+#function is called by document_keyphrase and keyphrase_document.  Each line in the file has
+#this form:
+#-phrase index number:phrase
+#This function then returns a table of pairs of the phrases that were sent as arguments to it
+#{phrase => phrase index number}.
+ 
+sub keyphrase_index_search {
+
+    my $phrases = shift(@_);
+    my @phrases = split(", ", $phrases);
+    my %table;
+    my $index = 1;
+    my $create_new_index = 0;
+
+    print STDERR "searching keyphrase index...\n";
+
+    #initilise table of phrases and index numbers
+    foreach $phrase (@phrases){
+	$table{"$phrase"} = "0";
+    }
+
+    #open keyphrase index for appending data and for reading
+    open(INDEX_OUT, ">>$gsdlhome/bin/script/indexes/keyphrase_index.txt");
+    open(INDEX_IN, "$gsdlhome/bin/script/indexes/keyphrase_index.txt")
+	or $create_new_index = 1;
+
+    if($create_new_index == 0){
+	#if the index already exists read in the phrases
+	while(<INDEX_IN>){
+	    chomp;
+	    foreach $phrase (@phrases){
+		if(/(\d+):$phrase/){
+		    $index = $1;
+		    $table{"$phrase"} = "$index";
+		}
+	    }
+	    $index++; #new starting index (one + the last index)
+	}
+
+	close(INDEX_IN);
+
+    }
+
+    #add new phrases to the phrase index
+    foreach $phrase (keys %table){
+	if($table{"$phrase"} eq "0"){
+	    print INDEX_OUT "$index:$phrase\n";
+	    $table{"$phrase"} = "$index"; 
+	    $index++;
+	}
+    }
+
+    close(INDEX_OUT);
+    return %table;
+}
+
+#This function is passed as arguments file hash ID and a list of kea phrases and/or stems
+#that exist for that particular file.  Its purpose is to write to the keyphrase_document
+#index a line for the document it has been sent:
+#-phrase index number:number of documents it appears in|ID
+sub keyphrase_document{
+
+    my ($ID, $stems) = @_;
+    my $text = ""; 
+    my @textlist;
+    my $create_new_index = 0;
+
+    print STDERR "writing to keyphrase_document.txt...\n";
+
+    #get table of phrases and phrase indexes 
+    my %table = keyphrase_index_search($stems); 
+    
+  
+    #open index for reading
+    open(INDEX_IN, "$gsdlhome/bin/script/indexes/keyphrase_document.txt")
+	or $create_new_index = 1;
+
+    #read in document if file exists
+    if($create_new_index == 0){
+
+	while(<INDEX_IN>){
+	    $text .= $_;
+	}
+
+	close(INDEX_IN);
+
+	#split text into lines
+	@textlist = split(/\n/, $text);
+
+    } 
+
+    #open index for output
+    open(INDEX_OUT, ">$gsdlhome/bin/script/indexes/keyphrase_document.txt");
+
+    if($create_new_index == 0){ #amend existing index
+	
+	foreach $line (@textlist){
+	    foreach $phrase (keys %table){
+		if($line =~ /(\d+):(\d+)(.*)/){ #all lines of this form
+		    $index = $1;
+		    if($table{"$phrase"} eq "$index") { #if phrase exists in index
+			$ids = $3; #get all doc IDs for that keyphrase
+			if($ids !~ /$ID/){ #if doc ID not already included
+			    $num_docs = $2;
+			    $num_docs++; #increment number of docs
+			    $line = "$index:$num_docs$3|$ID"; #line to append to index
+			    $table{"$phrase"} = "0"; 
+			}
+		    }
+		}
+	    }
+	    print INDEX_OUT "$line\n";
+	}
+    }
+
+    #add new phrases to the index
+    foreach $phrase (keys %table){ #write 'phrase index:1:file ID
+	if($table{"$phrase"} ne "0"){
+	    my $line = "$table{$phrase}:1:$ID";
+	    print INDEX_OUT "$line\n"; 
+	}
+    }
+
+    close(INDEX_OUT);
+
+}
+
+#This function is passed as arguments file hash ID and a list of kea phrase stems
+#that exist for that particular file and a list of the number of times each stem
+#phrase appear in that document.  Its purpose is to write to the document_keyphrase
+#index a line for the document it has been sent:
+#-file ID:number of phrases and/or stems appear in the document
+#      |pairs of 'phrase index,number of times the phrase appears in the document' 
+sub document_keyphrase {
+
+    my ($ID, $stemsS, $stem_c) = @_;
+    my $text = "";
+    my @textlist;
+    my %phrases;
+    my $create_new_index = 0;
+
+    print STDERR "writing to document_keyphrase.txt...\n";
+
+    #split phrase counts into arrays
+    my @stem_counts = split(", ", $stem_c);
+  
+    #get table of phrases and phrase indexes
+    my %table = keyphrase_index_search($stemsS);
+
+    #split phrases into arrays
+    my @stems = split(", ", $stemsS);
+
+    #build new phrases dictionary
+    for($i=0; $i<=$#stems; $i++){
+	my $phrase = $table{"$stems[$i]"};
+	$phrases{"$phrase"} = "$stem_counts[$i]";
+    }   
+    my @num = keys %phrases;
+    my $phrasenum = $#num + 1; #number of phrases in doc
+
+    #open index for reading
+    open(INDEX_IN, "$gsdlhome/bin/script/indexes/document_keyphrase.txt")
+	or $create_new_index = 1;
+
+     
+    if($create_new_index == 0){ #index doesn't need to be created
+
+	while(<INDEX_IN>){
+	    $text .= $_;
+	}
+
+	close(INDEX_IN);
+	
+	#split text into lines
+	@textlist = split(/\n/, $text);
+
+    }  
+
+
+    #must write this line to the file
+    #'document ID:num of phrases|phrase index, number of times phrases appears
+    my $newline = "$ID:$phrasenum";
+    foreach $phrase (keys %phrases){
+	$newline .= "|$phrase,$phrases{$phrase}";
+    }
+
+    #open index for output
+    open(INDEX_OUT, ">$gsdlhome/bin/script/indexes/document_keyphrase.txt");
+
+    if($create_new_index == 1){ #create a new index
+
+	print INDEX_OUT "$newline\n";
+
+    } else {
+
+	#if ID is already in the file write line overtop incase
+	#someone has modified the file.  Otherwise add the line
+	#to the end of the file
+	my $found = 0;
+
+	foreach $line (@textlist){
+	    if($line =~ /([^:]+):(.*)/){ #all lines should follow this pattern
+		$id = $1;
+		if($ID eq $id){ #id is already in the file
+		    print INDEX_OUT "$newline\n"; #print line overtop
+		    $found = 1;
+		} else {
+		    print INDEX_OUT "$line\n"; #print old line out
+		}
+	    }
+	}
+
+	print INDEX_OUT "$newline\n" if ($found == 0); #append new line to end of file 
+
+    }
+
+    close(INDEX_OUT);
+
+}
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/relation.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/relation.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/indexes/relation.pl	(revision 10506)
@@ -0,0 +1,414 @@
+#!/usr/bin/perl
+
+#data structures used:
+#-document_keyphrase
+#%document_phrases = ("hashID" => {"phrase" => "number of occurrences"})
+#-keyphrase_document 
+#%phrases_document = ("phrase" => "no. of docs phrase occurs in")
+
+#after calculation relational data, it will amend gml files
+#to include this data while writing to a file ID_relatedlinks.txt
+#the html links of the related files
+#if option p is set then the user wishes to add the related documents
+#as bookmarks to the pdf file
+
+require "getopts.pl";
+&Getopts('N:P'); #process option arguments
+
+
+$gsdlhome = $ENV{'GSDLHOME'};
+@directories; #list of directories for the collections
+%phrases_document; #hash storing phrase index => no. of documents with phrase in it
+%document_phrases; #hash of hashes ID => {phrase number => no. of phrases in ID}
+$N = 0; #number of documents in the index (presumably in the collection)
+%cosine_matrix; #2-dimensional matrix, for each pair of documents stores a cosine measure
+$number_of_files = 1; #by default the top related file is returned
+$do_pdfs = 0;
+
+if($opt_N =~ /(\d)+/){ #if flag is set then return top N docs
+    $number_of_files = $opt_N;
+}
+
+#get server name and httpprefix
+$httpprefix;
+$servername = "nzdl2.cs.waikato.ac.nz"; #should be localhost
+
+if($opt_P == 1){ #if flag is set 
+    $do_pdfs = 1;
+    
+    #get the httpprefix from gsdlsite.cfg
+    open(CFG, "$gsdlhome/cgi-bin/gsdlsite.cfg") 
+	or die "$gsdlhome/cgi-bin/gsdlsite.cfg could not be opened";
+    
+    while(<CFG>){
+	chomp;
+	if(/httpprefix \/(.+)/){
+	    $httpprefix = $1; 
+	}
+    }
+    close CFG;
+}
+
+if(@ARGV){
+
+    @directories = @ARGV;
+
+} else { #open collect directory and get a list of all collections
+    opendir(DIR, "$gsdlhome/collect");
+    @directories = grep(!/(^\.|(CVS)|(modelcol))/, readdir(DIR));
+    closedir(DIR);
+}
+
+
+
+#get the name of the directory the index will be stored in
+$dirname = "";
+foreach $collection (sort @directories){
+    $dirname .= $collection."_";
+}
+$dirname .= "indexes";
+print STDERR "directory name: $dirname\n";
+
+#open keyphrases_document.txt
+open(KEY_FILE, "$gsdlhome/bin/script/indexes/$dirname/keyphrase_document.txt") 
+    or die "$gsdlhome/bin/script/indexes/$dirname/keyphrase_document.txt could not be opened";
+
+print STDERR "\nreading keyphrase_document.txt...\n";
+
+#read a list of phrase indexes and number of documents that phrase appears in 
+while(<KEY_FILE>){
+    chomp;
+    if(/(\d+)\:(\d+)(.*)/){ #all lines should be of this form
+	my $phrase_index = $1;
+	my $doc_num = $2;
+	$phrases_document{"$phrase_index"} = "$doc_num"; #build keyphrase hash
+    }
+}
+
+close(KEY_FILE); 
+
+print STDERR "\nreading document_keyphrase.txt...\n";
+
+#open document_keyphrases.txt
+open(DOC_FILE, "$gsdlhome/bin/script/indexes/$dirname/document_keyphrase.txt") 
+    or die "$gsdlhome/bin/script/indexes/$dirname/document_keyphrase.txt could not be opened";
+
+#read a list of documents and the phrases that appear in them (& how many times they appear)
+while(<DOC_FILE>){
+    chomp;
+    my %document;
+    if(/(\w+)\:(\d+)((\|\d+,\d+)+)/){ #every line in the index of this form
+	my $ID = $1;
+	my $pairs = $3;
+	while ($pairs =~ s/\|(\d+),(\d+)//) { #this is the list of keyphrases and numbers
+	    my $phrase_index = $1;
+	    my $num_phrase = $2;
+	    $document{"$phrase_index"} = "$num_phrase"; #table to be stored in another table
+	}
+	$document_phrases{"$ID"} = ({%document});	  
+	$N++; #number of documents in the collection (which have kea metadata)
+    }
+}
+
+close(DOC_FILE);
+ 
+#we do not want to recalculate measures ie if we have already calculated
+#doc1 & doc2 we do not then want to calculate doc2 & doc1
+#to achieve this we must first sort the list of ids so that both lists
+#of documents will be in the same order (otherwise hash tables return values in 
+#no particular order). We then compare each document in the left 
+#column below against the documents in the right column:
+
+#doc0 -> 
+#doc1 -> doc0 
+#doc2 -> doc0, doc 1 
+#doc3 -> doc0, doc 1, doc 2 
+#doc4 -> doc0, doc 1, doc 2, doc 3 
+#doc5 -> doc0, doc 1, doc 2, doc 3, doc 4 
+#etc
+
+#this way we are not recalculating the same value and also not
+#comparing each document to itself (which would result in the
+#value 1) thus more than halving the processing time.
+
+print STDERR "\ncalculating cosine measures for $N documents...\n";
+
+$count = 0;
+@ids = sort keys(%document_phrases);
+
+#repeat for all pairs of documents
+foreach $id1 (sort keys(%document_phrases)) { 
+    my %table;
+   
+    for($i=0; $i<$count; $i++){ #calculate the cosine measure and store
+	my $cosine_measure = &compare_docs($id1, $ids[$i]); 
+	$table{"$ids[$i]"} = "$cosine_measure";  	
+    }
+    $cosine_matrix{"$id1"} = ({%table});
+    $count++; #each iteration the number of documents to compare against expands by 1
+}
+
+&addtogml(); #add the relational data we have just gathered to the documents gml files
+
+   
+#this function takes as an argument two document IDs and uses these to extract the
+#keyphrases from the document_keyphrase data structure.  It then calculates a 
+#'measure of relativity' [0-1] with which we can establish how similar the two
+#documents are to each other. (0-not related, 1-same document).  The equation 
+#used to establish this similarity:
+#
+#                     for all phrases 
+#                     in both d1, d2 (fd1p * loge(N/fp) (fd2p * loge(N/fp) 
+#  cosine(d1, d2) = --------------------------------------------------------------
+#                     sqrt(sum of phrases in d1(fd1p * loge(N/fp))) * 
+#                     sqrt(sum of phrases in d2(fd2p * loge(N/fp))) 
+#
+#where d1 and d2 are lists of keyphrase and represent documents
+#fd1p is the frequency that phrase p occurs in document d1
+#fd2p is the frequency that phrase p occurs in document d2
+#fp is the number of documents that have p as a keyphrase
+#N is the number of documents in the collection 
+sub compare_docs {
+
+  
+    my $ID1 = shift(@_); #ID for document one 
+    my $ID2 = shift(@_); #ID for document two
+  
+    my @phrases; #a list of phrases in document 1 and document 2
+    my @phrases1; #a list of phrases in document 1
+    my @phrases2; #a list of phrases in document 2
+    
+    
+    foreach $phrase (keys %{ $document_phrases{$ID1}}) { #list of phrases in doc1
+	push(@phrases1, $phrase);
+    } 
+    foreach $phrase (keys %{ $document_phrases{$ID2}}) { #list of phrases in doc2
+	push(@phrases2, $phrase);
+    }
+    foreach $phrase1 (@phrases1) { #list holds intersection of doc1 and doc2
+	foreach $phrase2 (@phrases2) {
+	    push(@phrases, $phrase1) if ($phrase1 == $phrase2);
+	}
+    }
+ 
+#COSINE MEASURE
+    my $wqtwdt= 0; 
+   
+    foreach $phrase (@phrases){ #for all phrases ocurring in d1 and d2
+	#the frequency that phrase occurs in document d1
+	$fd1p = $document_phrases{$ID1}{$phrase}; 
+	
+	#log base e(N/the number of documents that have phrase as a keyphrase)
+	$log_freq = log($N/$phrases_document{$phrase});
+	
+	#the frequency that phrase occurs in document d2
+	$fd2p = $document_phrases{$ID2}{$phrase};
+	$sum = ($fd1p * $log_freq) * ($fd2p * $log_freq);
+	$wqtwdt += $sum;
+    }
+  
+   
+    my $wd = 0; #stores the calculation for wd
+
+    foreach $phrase (@phrases1){ #for all phrases ocurring in d1 and d2
+	#the frequency that phrase occurs in document d1
+	$fd1p = $document_phrases{$ID1}{$phrase};
+	
+	#log base e($N/the number of documents that have phrase as a keyphrase)
+	$log_freq = log($N/$phrases_document{$phrase});
+	$sum = $fd1p * $log_freq;
+	$wd += ($sum * $sum); #sum squared
+    }
+
+   
+    my $wq = 0; #stores the calculation for wq
+ 
+    foreach $phrase (@phrases2){ #for all phrases ocurring in d2
+	#the frequency that phrase occurs in document d2
+	$fd2p = $document_phrases{$ID2}{$phrase};
+
+	#log base e($N/the number of documents that have phrase as a keyphrase)
+	$log_freq = log($N/$phrases_document{$phrase});
+	$sum = $fd2p * $log_freq;
+	$wq += ($sum * $sum); #sum squared 
+    }
+   
+    my $wdwq = sqrt($wq)  * sqrt($wd);  
+    my $cosine = $wqtwdt / $wdwq;
+    
+    return $cosine;
+	
+}
+   
+#this function adds the relational data we have collected to the gml files
+sub addtogml {
+
+ print STDERR "\nadding relational data to $N gml documents...\n\n";
+ my @doclist;
+ my %filetable;
+ my $pattern = "kea="; #pattern to search for to find where to insert relation data
+
+ #open archive info for each collecticollection
+ foreach $collection (@directories){
+
+     open(INFO, "$gsdlhome/collect/$collection/archives/archives.inf") 
+	 or die "$gsdlhome/collect/$collection/archives/archives.inf could not be opened";
+     
+     #read a list of ID's and pathnames into a file table
+     while(<INFO>){
+	 chomp;
+	 my %idtable;
+	 my $ID;
+	 if(/(\w+)(\s+)([\w\.\/]+)/){ #format of the line
+	     $ID = $1;
+	     $path = $3;
+	     $idtable{"$path"} = "$collection";
+	 }
+	 $filetable{"$ID"} = ({%idtable});
+     } 
+  
+     close(INFO);
+ }
+
+ 
+
+ #for each id in the matrix calculate a list of related documents
+ foreach $id (keys %cosine_matrix){    
+    
+     @doclist = &calculate_list($id); #gets list of documents with most relevant scores
+
+     my @path = keys %{$filetable{$id}}; #get filepath for document
+     my $collection = $filetable{$id}{$path[0]};
+     
+     #open gml file to amend for each collection
+     open(FILE, "$gsdlhome/collect/$collection/archives/$path[0]") 
+	 or die "$gsdlhome/collect/$collection/archives/$path[0] could not be opened";
+     
+     #read the gml file into text
+     $text = ""; 
+     while(<FILE>){
+	 $text .= $_;
+     }
+     
+     close(FILE);
+     
+     #delete previous relational data and urllinks to files storing rel doc links
+     $text =~ s/(\s)+relation=\"([^\"]*)\"//g;
+     $text =~ s/(\s)+urllink=\"([^\"]*)\"//g;
+     $text =~ s/(\s)+\/urllink=\"([^\"]*)\"//g;
+     
+     #if we want to insert each relation item as 'relation1="id" relation2="id"'
+     #$count = 1; #insert each item in the list
+     #foreach $item (@doclist){ #insert list into text
+     #	 $text =~ s/(\s)($pattern)/ relation$count=\"$item\" $2/g;
+     #	 $count++;
+     #} 
+     
+     #or relation="id, id, id"
+     #my $relation = join(",", @doclist);
+
+     #if pdf flag is set then delete pdf url document
+     if($do_pdfs == 1){ 
+	 my $dirpath = $path[0];
+	 $dirpath =~ s/(^(\/doc\.gml))*\/doc\.(gml)/$1/;
+ 	 `rm $gsdlhome/collect/$collection/index/assoc/$dirpath/url.txt`; 
+     }
+
+     my $title = "related document";
+     $title = $2 if($text =~ /(\s)+Title=\"([^\"]*)\"/g);
+   
+     #relation="collection,id collection,id"
+     my @relationlist;
+     my $relation = "";
+     foreach $doc (@doclist){
+	 my @p = keys %{$filetable{$doc}};
+	 my $collect = $filetable{$doc}{$p[0]};
+	 push(@relationlist, "$collect,$doc");
+
+	 #write pdf docs to file
+	 if($do_pdfs == 1){
+	     my @rel_path = keys %{$filetable{$doc}};
+	     &write_related_urls($title, $collection, $path[0], $collect, $rel_path[0]);
+	 }
+     }
+  
+     #modify the text to include relation data
+     $relation = join(" ", @relationlist); 
+     $text =~ s/($pattern)/ relation=\"$relation\" $1/g;
+
+     #open gml file to write back new text
+     open(FILE, ">$gsdlhome/collect/$collection/archives/$path[0]") or print STDERR "NO!!!!\n";
+     print FILE "$text"; #write back text
+     close(FILE);
+
+     #amend the pdf file 
+     if($do_pdfs == 1){
+	 my $pdf_path = $path[0];
+	 $pdf_path =~ s/(^(\/doc\.gml))*\/doc\.(gml)/$1/;
+	 `perl amend_pdf.pl $gsdlhome/collect/$collection/index/assoc/$pdf_path/doc.pdf $gsdlhome/collect/$collection/index/assoc/$pdf_path/url.txt\n`;
+     }
+ } 
+}
+
+#this function builds a list of cosine measures for each
+#document and sorts the list of ids each measure belongs to
+#in reverse order (ie docs with greatest cosine measure first)
+#returns the list calculated
+sub calculate_list {
+   
+    my $document = shift(@_);
+    my %measures;
+    my @doclist;
+    
+    
+    #find the top $number_of_files for $document  
+    foreach $id (keys %{$cosine_matrix{$document}}){ 
+	    $measures{"$cosine_matrix{$document}{$id}"} = "$id";
+    }
+    
+    my @list = reverse sort {$a<=>$b} keys %measures;
+
+    #list is as big as specified in command line (default is 1)
+    for($i = 0; $i<$number_of_files; $i++){ 
+	my $id = $measures{$list[$i]};
+	push(@doclist, $id) if($id ne "");
+    }
+
+    return @doclist;
+}
+
+
+sub write_related_urls {
+
+    
+ #need server name eg nzdl2.cs.waikato.ac.nz
+ #localhost should work but doesn't on this computer?
+ #open up config file to read httpprefix
+ #get collection name of related document
+ #get hash directory of related document
+ #write http://nzdl2.cs.waikato.ac.nz/httpprefix/collectionname/index/assoc/directory/doc.pdf
+
+ my ($title, $collection, $path, $collect, $rel_path) = @_;
+
+ $rel_path =~ s/(^(\/doc\.gml))*\/doc\.(gml)/$1/;
+ $path =~ s/(^(\/doc\.gml))*\/doc\.(gml)/$1/;
+ 
+ print STDERR "writing related pdf urls to file ";
+ print STDERR "$gsdlhome/collect/$collection/index/assoc/$path/url.txt...\n";
+ 
+ open(URL, ">>$gsdlhome/collect/$collection/index/assoc/$path/url.txt") 
+     or open(URL, ">$gsdlhome/collect/$collection/index/assoc/$path/url.txt")
+	 or print STDERR "This file $title is not a pdf file\n";
+
+ print URL "$title\t"; 
+ print URL "http://$servername/$httpprefix/collect/$collect/index/assoc/$rel_path/doc.pdf\n";
+ close URL;
+
+}
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/lucene_passes.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/lucene_passes.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/lucene_passes.pl	(revision 10506)
@@ -0,0 +1,210 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# lucene_passes.pl -- perl wrapper, akin to mgpp_passes, for Lucene
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use util;
+use ghtml;
+
+
+sub open_java_lucene
+{
+    my ($doc_tag_level,$full_builddir,$indexdir,$create,$verbosity) = @_;
+
+    my $bin_java = &util::filename_cat($ENV{'GSDLHOME'},"bin","java");
+    my $classpath = &util::filename_cat($bin_java,"LuceneWrap.jar");
+
+    my $java_lucene = "java -classpath \"$classpath\" GS2LuceneIndexer";
+    my $cmd_options = "$create -verbosity $verbosity";
+    my $java_cmd = "$java_lucene $cmd_options $doc_tag_level \"$full_builddir\" $indexdir";
+
+    if (!open (PIPEOUT, "| $java_cmd")) {
+	die "$PROGNAME - couldn't run $java_cmd\n";
+    }
+}
+
+sub close_java_lucene
+{
+    close(PIPEOUT);
+}
+
+sub save_xml_doc
+{
+    my ($full_textdir,$output_filename,$doc_xml) = @_;
+    $dir_sep = &util::get_os_dirsep();
+
+    my $full_output_filename 
+	= &util::filename_cat($full_textdir,$output_filename);
+    my ($full_output_dir) = ($full_output_filename =~ m/^(.*$dir_sep)/x);
+    &util::mk_all_dir($full_output_dir);
+    
+    open(DOCOUT,">$full_output_filename") 
+	|| die "Unable to open $full_output_filename";
+
+    print DOCOUT $doc_xml;
+    close(DOCOUT);
+
+    my @secs =  ($doc_xml =~ m/<Sec\s+gs2:id="\d+"\s*>.*?<\/Sec>/sg);
+
+
+# Currently not used, but consult with DB before removing
+#    foreach my $sec (@secs) {
+#	my ($docnum,$sec_text) = ($sec =~ m/<Sec\s+gs2:id="(\d+)"\s*>(.*?)<\/Sec>/s);
+#	my $docnum_filename 
+#	    = &util::filename_cat($full_textdir,"$docnum.xml");
+
+#    
+#	open(SECOUT,">$docnum_filename") 
+#	    || die "Unable to open $docnum_filename";
+
+#	print SECOUT &ghtml::unescape_html($sec_text);
+#	close(SECOUT);
+#    }
+
+}
+
+sub compress_xml_doc
+{
+    my ($full_textdir,$output_filename) = @_;
+
+    my $full_output_filename 
+	= &util::filename_cat($full_textdir,$output_filename);
+
+    `gzip $full_output_filename`;
+}
+
+sub monitor_xml_stream
+{
+    my ($mode, $full_textdir) = @_;
+
+    my $doc_xml = "";
+    my $output_filename = "";
+
+    my $line;
+    while (defined ($line = <STDIN>)) {
+	$line =~ s/&nbsp;/&amp;nbsp;/g;
+	$doc_xml .= $line;
+	if ($line =~ m/^<Doc.+file=\"(.*?)\".*>$/) {
+	    $output_filename = $1;
+	    
+	}
+	
+	if ($line =~ m/^<\/Doc>$/) {
+	    if ($mode eq "text") {
+		save_xml_doc($full_textdir,$output_filename,$doc_xml);
+	    } elsif ($mode eq "index") {
+		# notify lucene indexer
+		# print STDERR $doc_xml;
+##	    print PIPEOUT "$output_filename\n";
+		print PIPEOUT "$doc_xml";
+		#save_xml_doc($full_textdir, "$output_filename.txt", $doc_xml);
+	    }
+	    # compress file
+###	    compress_xml_doc($full_textdir,$output_filename);
+
+	    $doc_xml = "";
+	    $output_filename = "";
+	}
+    }
+}
+
+sub main
+{
+    my (@argv) = @_;
+    my $argc = scalar(@argv);
+
+    my $create = "";
+    my $verbosity = 1;
+
+    my @filtered_argv = ();
+
+    my $i = 0;
+    while ($i<$argc) {
+	if ($argv[$i] =~ m/^-(.*)$/) {
+
+	    my $option = $1;
+
+	    # -create causes build to be incremental
+	    if ($option eq ("create")) {
+		$create = "-create";
+	    }
+
+	    # -verbosity num
+	    elsif ($option eq "verbosity") {
+		$i++;
+		if ($i<$argc) {
+		    $verbosity = $argv[$i];
+		}
+	    }
+	    else {
+		print STDERR "Unrecognised minus option: -$option\n";
+	    }
+	}
+	else {
+	    push(@filtered_argv,$argv[$i]);
+	}
+	$i++;
+    }
+
+    my $filtered_argc = scalar(@filtered_argv);
+
+    if ($filtered_argc < 4) {
+	print STDERR "Usage: $PROGNAME [-create|-verbosity num] \"text\"|\"index\" doc-tag-level build-dir index-name\n";
+	exit 1;
+    }
+
+    my $mode = $filtered_argv[0];
+    my $doc_tag_level = $filtered_argv[1];
+    my $full_builddir = $filtered_argv[2];
+    my $indexdir      = $filtered_argv[3];
+###    print STDERR "**** ARGS = ", join(" ", @argv), "\n";
+
+    my $full_textdir = &util::filename_cat($full_builddir,"text");
+
+    if ($mode eq "index") {
+	# don't need the lucene stuff if we are just storing the docs
+	open_java_lucene($doc_tag_level,$full_builddir,$indexdir,$create,$verbosity);
+    }
+    monitor_xml_stream($mode, $full_textdir);
+    if ($mode eq "index") {
+	close_java_lucene();
+    }
+}
+
+$PROGNAME = $0;
+$PROGNAME =~ s/^.*\/(.*)$/$1/;
+
+&main(@ARGV);
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/lucene_query.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/lucene_query.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/lucene_query.pl	(revision 10506)
@@ -0,0 +1,121 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# lucene_query.pl -- perl wrapper to initiate query using Lucene
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use util;
+
+sub full_indexdir 
+{
+    my ($col_name,$indexdir) = @_;
+
+    my $full_indexdir
+	= &util::filename_cat($ENV{'GSDLHOME'},"collect",$col_name,"index",
+			      $indexdir);
+
+    return $full_indexdir;
+}
+
+
+sub open_java_lucene
+{
+    my ($full_indexdir, $out_file) = @_;
+    my $bin_java = &util::filename_cat($ENV{'GSDLHOME'},"bin","java");
+    my $classpath = &util::filename_cat($bin_java,"LuceneWrap.jar");
+
+    my $java_lucene = "java -classpath $classpath GS2LuceneQuery";
+    my $java_cmd = "$java_lucene";
+
+    if (defined($out_file)) {
+	$out_file = " > \"".$out_file. "\"";
+    } else {
+	$out_file = "";
+    }
+    if (!open (PIPEOUT, "| $java_cmd $full_indexdir $out_file")) {
+	die "$PROGNAME - couldn't run $java_cmd\n";
+    }
+
+}
+
+sub close_java_lucene
+{
+    close(PIPEOUT);
+}
+
+sub main
+{
+    my (@argv) = @_;
+    my $argc = scalar(@argv);
+
+    my $full_indexdir;
+    my $query = undef;
+    my $out_file = undef;
+    if ($argc==1) {
+	$full_indexdir = $argv[0];
+    }
+    elsif ($argc==2) {
+	$full_indexdir = $argv[0];
+	$query = $argv[1];
+    }
+    elsif  ($argc==3) {
+	$full_indexdir = $argv[0];
+	$query = $argv[1];
+	$out_file = $argv[2];
+    }
+    else {
+	print STDERR "Usage: $PROGNAME full-index-dir [query] [outfile]\n";
+	exit 1;
+    }
+
+
+    open_java_lucene($full_indexdir, $out_file);
+
+    if (defined $query) {
+	print PIPEOUT "$query\n";
+    }
+    else {
+	while (defined (my $line = <STDIN>)) {
+	    print PIPEOUT $line;
+	}
+    }
+
+    close_java_lucene();
+}
+
+$PROGNAME = $0;
+$PROGNAME =~ s/^.*\/(.*)$/$1/;
+
+&main(@ARGV);
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/makemapfile.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/makemapfile.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/makemapfile.pl	(revision 10506)
@@ -0,0 +1,188 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# makemapfile.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use util;
+
+# %translations is of the form:
+#
+# encodings{encodingname-encodingname}->blocktranslation
+# blocktranslation->[[0-255],[256-511], ..., [65280-65535]]
+#
+# Any of the top translation blocks can point to an undefined
+# value. This data structure aims to allow fast translation and 
+# efficient storage.
+%translations = ();
+
+# @array256 is used for initialisation, there must be
+# a better way...
+@array256 = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+
+&main();
+
+sub print_usage {
+    print STDERR "\n";
+    print STDERR "makemapfile.pl: Creates unicode map (.ump) files from plain\n";
+    print STDERR "                text code pages.\n\n";
+    print STDERR "  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -encoding name\n";
+    print STDERR "   -mapfile  text file from which to create binary ump file\n\n";
+}
+
+sub main {
+    if (!parsargv::parse(\@ARGV, 
+			 'encoding/.+', \$encoding,
+			 'mapfile/.+', \$mapfile)) {
+	&print_usage();
+	die "\n";
+    }
+
+    if (!&loadencoding ($encoding, $mapfile)) {
+	die "couldn't load encoding $encoding";
+    }
+
+    # write out map files
+    &writemapfile ("$encoding-unicode", $encoding, 1);
+    &writemapfile ("unicode-$encoding", $encoding, 0);
+}
+
+sub writemapfile {
+    my ($encoding, $filename, $tounicode) = @_;
+
+    $filename .= ".ump"; # unicode map file
+    if ($tounicode) {
+	$filename = &util::filename_cat ($ENV{'GSDLHOME'}, "mappings", "to_uc", $filename);
+    } else {
+	$filename = &util::filename_cat ($ENV{'GSDLHOME'}, "mappings", "from_uc", $filename);
+    }
+
+    die "translation not defined" if (!defined $translations{$encoding});
+    my $block = $translations{$encoding};
+
+    print "writing $filename\n";
+    open (MAPFILE, ">" . $filename) || die;
+    binmode (MAPFILE);
+
+    my ($i, $j);
+    for ($i=0; $i<256; $i++) {
+	if (ref ($block->[$i]) eq "ARRAY") {
+	    print MAPFILE pack ("C", $i);
+	    for ($j=0; $j<256; $j++) {
+		# unsigned short in network order
+		print MAPFILE pack ("CC", int($block->[$i]->[$j] / 256), 
+				    $block->[$i]->[$j] % 256);
+	    }
+	}
+    }
+    close (MAPFILE);
+}
+
+# loadencoding expects the mapfile to contain (at least) two
+# tab-separated fields. The first field is the mapped value
+# and the second field is the unicode value.
+#
+# It returns 1 if successful, 0 if unsuccessful
+sub loadencoding {
+    my ($encoding, $mapfile) = @_;
+    
+    my $to = "$encoding-unicode";
+    my $from = "unicode-$encoding";
+
+    # check to see if the encoding has already been loaded
+    if (defined $translations{$to} && defined $translations{$from}) {
+	return 1;
+    }
+
+    return 0 unless open (MAPFILE, $mapfile);
+
+    my ($line, @line);
+    $translations{$to} = [@array256];
+    $translations{$from} = [@array256];
+    while (defined ($line = <MAPFILE>)) {
+	chomp $line;
+	# remove comments
+	$line =~ s/\#.*$//;
+	next unless $line =~ /\S/;
+
+	# split the line into fields and do a few
+	# simple sanity checks
+	@line = split (/\t/, $line);
+	next unless (scalar(@line) >= 2 &&
+		     $line[0] =~ /^0x/ &&
+		     $line[1] =~ /^0x/);
+
+	my $char = hex($line[0]);
+	my $unic = hex($line[1]);
+
+	# might need this for some versions of gb but not gbk
+#	$char = $char | 0x8080 unless ($encoding =~ /gbk/i);
+
+	&addchartrans ($translations{$to}, $char, $unic);
+	&addchartrans ($translations{$from}, $unic, $char);
+    }
+
+    close (MAPFILE);
+
+    return 1;
+}
+
+# addchartrans adds one character translation to a translation block.
+# It also simplifies the translation block if possible.
+sub addchartrans {
+    my ($block, $from, $to) = @_;
+    my $i = 0;
+
+    my $high = ($from / 256) % 256;
+    my $low = $from % 256;
+
+    if (ref ($block->[$high]) ne "ARRAY") {
+	$block->[$high] = [@array256];
+    }
+    $block->[$high]->[$low] = $to;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/mirror.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/mirror.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/mirror.pl	(revision 10506)
@@ -0,0 +1,146 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# mirror.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This program uses w3mirror to mirror a web site.  It looks for a
+# mirror program configuration files in etc, and if it finds them then
+# it runs the mirroring software using this configuration file, and placing
+# the mirror in the import directory.
+#
+# mirror.pl can use the w3mirror program or the wget program if they are
+# installed.
+#
+# To use w3mirror, the configuration file must be in etc/w3mir.cfg.
+# To use GNU wget, the configuration file (i.e. a wgetrc file) must
+# be in etc/wget.cfg and a file of the URLs to read in etc/wget.url
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use arcinfo;
+use colcfg;
+use plugin;
+use docprint;
+use util;
+use parsargv;
+
+sub print_usage {
+    print STDERR "\n";
+    print STDERR "mirror.pl: Uses w3mir or wget to sync a collections import data\n";
+    print STDERR "           with a website.\n\n";
+    print STDERR "  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -importdir directory   Where to place the mirrored material\n";
+}
+
+
+&main ();
+
+sub main {
+    my ($verbosity, $importdir, $etcdir, 
+        $collection, $configfilename, $collectcfg);
+
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'importdir/.*/', \$importdir )) {
+	&print_usage();
+	die "\n";
+    }
+
+    # get and check the collection name
+    if (($collection = &util::use_collection(@ARGV)) eq "") {
+	&print_usage();
+	die "\n";
+    }
+
+    # get the etc directory
+    $etcdir = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc");
+    
+    # check the collection configuration file for options
+    my $interval = 0;
+    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, 
+					   "etc", "collect.cfg");
+    if (-e $configfilename) {
+	$collectcfg = &colcfg::read_collect_cfg ($configfilename);
+	if (defined $collectcfg->{'importdir'} && $importdir eq "") {
+	    $importdir = $collectcfg->{'importdir'};
+	}
+    } else {
+	die "Couldn't find the configuration file $configfilename\n";
+    }
+    
+    # fill in the default import directories if none
+    # were supplied, turn all \ into / and remove trailing /
+    $importdir = "$ENV{'GSDLCOLLECTDIR'}/import" if $importdir eq "";
+    $importdir =~ s/[\\\/]+/\//g;
+    $importdir =~ s/\/$//;
+
+    # make sure there is an import directory
+    if (! -e "$importdir") {
+	&util::mk_dir($importdir);
+    }
+
+    # if w3mir.cfg exists, 
+    # then we are using w3mirror to mirror the remote site
+    if (-e "$etcdir/w3mir.cfg") {
+
+	# run the mirror program from the import directory
+	my  $cmd = "cd $importdir; ";
+	$cmd .= "perl -S gsw3mir.pl -cfgfile $etcdir/w3mir.cfg";
+	# print "\n$cmd\n";
+	`$cmd`;
+
+    } 
+
+    # if wget.cfg and wget.url both exist, 
+    # then we are using GNU wget to mirror the remote site
+    elsif ((-e "$etcdir/wget.cfg") && (-e "$etcdir/wget.url")) {
+	$ENV{WGETRC} = "$etcdir/wget.cfg";
+	my $cmd = "perl -S gsWget.pl --input-file=$etcdir/wget.url --directory-prefix=$importdir";
+	system($cmd);
+    }
+
+    # otherwise, there are no mirror copnfiguration files
+    else {
+	die "Couldn't find the mirror configuration files in $etcdir\n";
+    }
+
+
+}
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/mkcol.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/mkcol.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/mkcol.pl	(revision 10506)
@@ -0,0 +1,305 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# mkcol.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This program will setup a new collection from a model one. It does this by
+# copying the model, moving files to have the correct names, and replacing
+# text within the files to match the parameters.
+
+package 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;
+use gsprintf;
+use printusage;
+
+my $arguments =
+    [ { 'name' => "creator",
+	'desc' => "{mkcol.creator}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "optionfile",
+	'desc' => "{mkcol.optionfile}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "maintainer",
+	'desc' => "{mkcol.maintainer}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "collectdir",
+	'desc' => "{mkcol.collectdir}",
+	'type' => "string",
+	'deft' => &util::filename_cat ($ENV{'GSDLHOME'}, "collect"),
+	'reqd' => "no" },
+      { 'name' => "public",
+	'desc' => "{mkcol.public}",
+	'type' => "string",
+	'deft' => "true",
+	'reqd' => "no" },
+      { 'name' => "title",
+	'desc' => "{mkcol.title}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "about",
+	'desc' => "{mkcol.about}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "plugin",
+	'desc' => "{mkcol.plugin}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "quiet",
+	'desc' => "{mkcol.quiet}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "language",
+	'desc' => "{scripts.language}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "win31compat",
+	'desc' => "{mkcol.win31compat}",
+	'type' => "string",
+	'deft' => "true",
+	'reqd' => "no" } ];
+
+my $options = { 'name' => "mkcol.pl",
+		'desc' => "{mkcol.desc}",
+		'args' => $arguments };
+
+sub gsprintf
+{
+    return &gsprintf::gsprintf(@_);
+}
+
+
+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) ||
+	(&gsprintf(STDERR, "{common.cannot_read}\n", $modeldir) && die);
+    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/;
+	    &gsprintf(STDOUT, "{mkcol.doing_replacements}\n", $destfile)
+		unless $quiet;
+	    $destfile = &util::filename_cat ($coldir, $destfile);
+
+	    open (INFILE, $thisfile) || 
+		(&gsprintf(STDERR, "{common.cannot_read_file}\n", $thisfile) && die);
+	    open (OUTFILE, ">$destfile") ||
+		(&gsprintf(STDERR, "{common.cannot_create_file}\n", $destfile) && die);
+
+	    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;
+
+		print OUTFILE $line;
+	    }
+	    
+	    close (OUTFILE);
+	    close (INFILE);
+	}
+    }
+}
+
+# get and check options
+sub parse_args {
+    my ($argref) = @_;
+    if (!&parsargv::parse($argref,
+			  'language/.*/', \$language,
+			  'optionfile/.*/', \$optionfile,
+			  'collectdir/.*/', \$collectdir,
+			  'creator/\w+\@[\w\.]+/', \$creator,
+			  'maintainer/\w+\@[\w\.]+/', \$maintainer,
+			  'public/true|false/true', \$public,
+			  'title/.+/', \$title,
+			  'about/.+/', \$about,
+			  'plugin/.+', \@plugin,
+			  'quiet', \$quiet,
+			  'win31compat/true|false/true', \$win31compat,
+			  'gli', \$gli,
+			  q^xml^, \$xml
+			  )) {
+	&PrintUsage::print_txt_usage($options, "{mkcol.params}");
+	die "\n";
+    }
+}
+
+sub main {
+
+    &parse_args (\@ARGV);
+
+    # If $language has been specified, load the appropriate resource bundle
+    # (Otherwise, the default resource bundle will be loaded automatically)
+    if ($language) {
+	&gsprintf::load_language_specific_resource_bundle($language);
+    }
+
+    if ($xml) {
+	&PrintUsage::print_xml_usage($options);
+	die "\n";
+    }
+
+    if ($gli) { # the gli wants strings to be in UTF-8
+	&gsprintf::output_strings_in_UTF8; 
+    }
+	
+    if ($optionfile =~ /\w/) {
+	open (OPTIONS, $optionfile) ||
+	    (&gsprintf(STDERR, "{common.cannot_open}\n", $optionfile) && die);
+	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 -smart_block","EMAILPlug",
+		   PDFPlug,RTFPlug,WordPlug,PSPlug,ImagePlug,NULPlug,ArcPlug,"RecPlug -use_metadata_files");
+    }
+
+    # get and check the collection name
+    ($collection) = @ARGV;
+    if (!defined($collection)) {
+	&gsprintf(STDOUT, "{mkcol.no_colname}\n");
+	&PrintUsage::print_txt_usage($options, "{mkcol.params}");
+	die "\n";
+    }
+
+    if (($win31compat eq "true") && (length($collection)) > 8) {
+	&gsprintf(STDOUT, "{mkcol.long_colname}\n");
+	die "\n";
+    }
+
+    if ($collection eq "modelcol") {
+	&gsprintf(STDOUT, "{mkcol.bad_name_modelcol}\n");
+	die "\n";
+    }
+
+    if ($collection eq "CVS") {
+	&gsprintf(STDOUT, "{mkcol.bad_name_cvs}\n");
+	die "\n";
+    }
+
+    # We don't want creator to be required anymore - John Thompson 28-11-2003
+    #if (!defined($creator) || $creator eq "") {
+    #   &gsprintf(STDOUT, "{mkcol.creator_undefined}\n");
+    #   die "\n";
+    #}
+
+    #Of course thats means we don't want to default maintainer unless a creator is provided
+    if (defined($creator) && (!defined($maintainer) || $maintainer eq "")) {
+	$maintainer = $creator;
+    }
+
+    $public = "true" unless defined $public;
+
+    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) {
+	$pluginstring .= "plugin         $plugin\n";
+    }
+
+    $mdir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect", "modelcol");
+    if (defined $collectdir && $collectdir =~ /\w/) {
+	if (!-d $collectdir) {
+	    &gsprintf(STDOUT, "{mkcol.no_collectdir}\n", $collectdir);
+	    die "\n";
+	}
+	$cdir = &util::filename_cat ($collectdir, $collection);
+    } else {
+	$cdir = &util::filename_cat ($ENV{'GSDLHOME'}, "collect", $collection);
+    }
+
+    # make sure the model collection exists
+    (&gsprintf(STDERR, "{mkcol.cannot_find_modelcol}\n", $mdir) && die) unless (-d $mdir);
+
+    # make sure this collection does not already exist
+    if (-e $cdir) {
+	&gsprintf(STDOUT, "{mkcol.col_already_exists}\n");
+	die "\n";
+    }
+
+    # start creating the collection
+    &gsprintf(STDOUT, "\n{mkcol.creating_col}...\n", $collection)
+	unless $quiet;
+    &traverse_dir ($mdir, $cdir);
+    &gsprintf(STDOUT, "\n{mkcol.success}\n", $cdir)
+	unless $quiet;
+}
+
+&main ();
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/nightly.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/nightly.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/nightly.pl	(revision 10506)
@@ -0,0 +1,104 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# nightly.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This program will find all the collections under $GSDLHOME/collect
+# and use the update.pl script to update them all.  It should be run
+# every night to keep mirror collections up-to-date.
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use arcinfo;
+use colcfg;
+use plugin;
+use docprint;
+use util;
+use parsargv;
+
+sub print_usage {
+    print STDERR "\n";
+    print STDERR "nightly.pl: Attempts to update all Greenstone collections found on\n";
+    print STDERR "            the local filesystem by calling update.pl for each of\n";
+    print STDERR "            them.\n\n";
+    print STDERR "  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -importdir directory   Where to place the mirrored material\n";
+    print STDERR "   -archivedir directory  Where the converted material ends up\n";
+}
+
+
+&main ();
+
+sub main {
+    my ($verbosity, $collectdir, $name, $collection);
+
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity )) {
+	&print_usage();
+	die "\n";
+    }
+
+
+    # get the contents of the collect directory
+    $collectdir =  &util::filename_cat($ENV{'GSDLHOME'}, "collect");
+    opendir(CDIR, $collectdir) || die "Cannot open $collectdir: $!";
+    my @files = readdir(CDIR);
+    closedir CDIR;
+
+
+    # update each collection
+    foreach $name (@files) {
+
+	$collection = &util::filename_cat($collectdir, $name);
+
+	# igore entries for "." and ".."
+	next unless ($name =~ /[^\.]/);
+
+	# ignore modelcol
+	next if ($name eq "modelcol");
+
+	# ignore entries that are not directories
+	next unless (-d $collection);
+
+	# ignore directories that do not have a subdir called etc
+	next unless (-d &util::filename_cat($collection, "etc"));
+
+	print "Updating: $name\n";
+	print `update.pl $name`;
+	
+    }
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/pdftohtml.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/pdftohtml.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/pdftohtml.pl	(revision 10506)
@@ -0,0 +1,267 @@
+#!/usr/bin/perl -w
+
+
+###########################################################################
+#
+# pdftohtml.pl -- convert PDF documents to HTML format
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001 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.
+#
+###########################################################################
+
+# pdftohtml.pl is a wrapper for running pdftohtml utility which converts
+# PDF documents to HTML, and converts images to PNG format for display in
+# the HTML pages generated
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use util;
+use Cwd;
+use File::Basename;
+
+sub print_usage {
+# note - we don't actually ever use most of these options...
+print STDERR  
+    ("pdftohtml.pl wrapper for pdftohtml.\n",
+     "Usage: pdftohtml [options] <PDF-file> <html-file>\n",
+     "Options:\n",
+     "\t-i\tignore images (don't extract)\n",
+     "\t-a\tallow images only (continue even if no text is present)\n",
+     "\t-c\tproduce complex output (requires ghostscript)\n",
+     "\t-hidden\tExtract hidden text\n",
+     "\t-zoom\tfactor by which to zoom the PDF (only useful if -c is set)\n"
+     );
+exit (1);
+}
+
+sub main {
+    my (@ARGV) = @_;
+    my ($allow_no_text, $ignore_images, $complex, $zoom, $hidden);
+    
+    # read command-line arguments so that
+    # you can change the command in this script
+    if (!parsargv::parse(\@ARGV,
+			 'a', \$allow_no_text,
+			 'i', \$ignore_images,
+			 'c', \$complex,
+			 'hidden', \$hidden,
+			 'zoom/\d+/2', \$zoom,
+			 ))
+    {
+	print_usage();
+    }
+
+    # Make sure the input file exists and can be opened for reading
+    if (scalar(@ARGV) != 2) {
+	print_usage();
+    }
+
+    my $input_filename = $ARGV[0];
+    my $output_filestem = $ARGV[1];
+
+    $output_filestem =~ s/\.html$//i; # pdftohtml adds this suffix
+
+    # test that the directories exist to create the output file, or
+    # we should exit immediately. (File:: is included by util.pm)
+    my $output_dir =  File::Basename::dirname($output_filestem);
+    if (! -d $output_dir || ! -w $output_dir) {
+	die "pdftohtml.pl: cannot write to directory $output_dir\n";
+    }
+
+    my @dir = split (/(\/|\\)/, $input_filename);
+    my $input_basename = pop(@dir);
+    $input_basename =~ s/\.pdf//i;
+    my $dir = join ("", @dir);
+
+    if (!-r $input_filename) {
+	print STDERR "Error: unable to open $input_filename for reading\n";
+	exit(1);
+    }
+
+    # Heuristical code removed due to pdftohtml being "fixed" to not
+    # create bitmaps for each char in some pdfs. However, this means we
+    # now create .html files even if we can't extract any text. We should
+    # check for that now instead someday...
+
+
+    # formulate the command
+    my $cmd = &util::filename_cat($ENV{'GSDLHOME'}, "bin", $ENV{'GSDLOS'}, "pdftohtml");
+
+    # don't include path on windows (to avoid having to play about
+    # with quoting when GSDLHOME might contain spaces) but assume
+    # that the PATH is set up correctly.
+    $cmd = "pdftohtml" if ($ENV{'GSDLOS'} =~ /^windows$/);
+
+    $cmd .= " -i" if ($ignore_images);
+    $cmd .= " -c" if ($complex);
+    $cmd .= " -hidden" if ($hidden);
+    $cmd .= " -zoom $zoom";
+    $cmd .= " -noframes -p -enc UTF-8 \"$input_filename\" \"$output_filestem.html\"";
+
+# system() returns -1 if it can't run, otherwise it's $cmds ret val.
+    # note we return 0 if the file is "encrypted"
+    $!=0;
+    if (system($cmd)!=0) {
+	print STDERR "pdftohtml error for $input_filename $!\n";
+	# leave these for gsConvert.pl...
+	#&util::rm("$output_filestem.text") if (-e "$output_filestem.text");
+	#&util::rm("$output_filestem.err") if (-e "$output_filestem.err");
+	return 1;
+    }
+
+    if (! -e "$output_filestem.html") {
+	return 1;
+    }
+
+# post-process to remove </b><b> and </i><i>, as these break up
+# words, screwing up indexing and searching.
+# At the same time, check that our .html file has some textual content.
+    &util::mv("$output_filestem.html","$output_filestem.html.tmp");
+    $!=0;
+    open INFILE, "$output_filestem.html.tmp" ||
+	die "Couldn't open file: $!";
+    open OUTFILE, ">$output_filestem.html" ||
+	die "Couldn't open file for writing: $!";
+    my $line;
+    my $seen_textual_content=$allow_no_text;
+    # check for unicode byte-order marker at the start of the file
+    $line = <INFILE>;
+    $line =~ s#\376\377##g;
+    while ($line) {
+	$line =~ s#</b><b>##g;
+	$line =~ s#</i><i>##g;
+	$line =~ s#\\#\\\\#g; # until macro language parsing is fixed...
+# check for any extracted text
+	if ($seen_textual_content == 0) {
+	    my $tmp_line=$line;
+	    $tmp_line =~ s/<[^>]*>//g;
+	    $tmp_line =~ s/Page\s\d+//;
+	    $tmp_line =~ s/\s*//g;
+	    if ($tmp_line ne "") {
+		$seen_textual_content=1;
+	    }
+	    # special - added to remove the filename from the title
+	    # this should be in the header, before we see "textual content"
+	    if ($line =~ m@<title>(.*?)</title>@i) {
+		my $title=$1;
+		
+		# is this title the name of a filename?
+		if (-r "$title.pdf" || -r "$title.html") {
+		    # remove the title
+		    $line =~ s@<title>.*?</title>@<title></title>\n<META NAME=\"filename\" CONTENT=\"$title\">@i;
+		}
+	    }
+	}
+
+	# relative hrefs to own document...
+	$line =~ s@href=\"$input_basename\.html\#@href=\"\#@go;
+# escape underscores, but not if they're inside tags (eg img/href names)
+	my $inatag = 0; # allow multi-line tags
+	if ($line =~ /_/) {
+	    my @parts=split('_',$line);
+	    my $lastpart=pop @parts;
+	    foreach my $part (@parts) {
+		if ($part =~ /<[^>]*$/) { # if we're starting a tag...
+		    $inatag=1;
+		} elsif ($part =~ />[^<]*$/) { # closing a tag
+		    $inatag=0;
+		}
+		if ($inatag) {
+		    $part.='_';
+		} else {
+		    $part.="&#95;";
+		}
+	    }
+	    $line=join('',@parts,$lastpart);
+	}
+
+	print OUTFILE $line;
+	$line = <INFILE>;
+    }
+    close INFILE;
+    close OUTFILE;
+    &util::rm("$output_filestem.html.tmp");
+
+    # Need to convert images from PPM format to PNG format
+    my @images;
+
+    my $directory=$output_filestem;
+    $directory =~ s@[^\/]*$@@;    # assume filename has no embedded slashes...
+    # newer versions of pdftohtml don't seem to do images this way anymore?
+    if (open (IMAGES, "${directory}images.log") || 
+	open (IMAGES, "${directory}image.log")) {
+	while (<IMAGES>) {
+	    push (@images, $_);
+	}
+	close IMAGES;
+	&util::rm("${directory}image.log") if (-e "${directory}image.log");
+
+    }
+
+    # no need to go any further if there is no text extracted from pdf.
+    if ($seen_textual_content == 0) {
+	print STDERR "Error: PDF contains no extractable text\n";
+	# remove images...
+	for $image (@images) {
+	    chomp($image);
+	    &util::rm("${directory}$image");
+	}
+	return 1;
+    }
+
+
+
+    for $image (@images) {
+	chomp($image);
+	my $cmd = "";
+	if ($ENV{'GSDLOS'} =~ /^windows/i) {
+	    $cmd = "pnmtopng \"${directory}$image\"";
+	    if (system($cmd)!=0) {
+		print STDERR "Error executing $cmd\n";
+		#return 1; # not sure about whether to leave this one in or take it out
+		next;
+	    }
+	} else {
+	    my @nameparts = split(/\./, $image);
+	    my $image_base = shift(@nameparts);
+	    $cmd = "pnmtopng \"${directory}$image\" > \"${directory}$image_base.png\" 2>/dev/null";
+	    if (system($cmd)!=0) {
+		$cmd = "convert \"${directory}$image\" \"${directory}$image_base.png\" 2>/dev/null";
+		if (system($cmd)!=0) {
+		    print STDERR "Cannot convert $image into PNG format (tried `pnmtopng' and `convert')...\n";
+		    #return 1; # not sure about whether to leave this one in or take it out
+		    next;
+		}
+	    }
+	}
+	&util::rm($image);
+    }
+
+    return 0;
+}
+
+# indicate our error status, 0 = success
+exit (&main(@ARGV));
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/pdftoimg.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/pdftoimg.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/pdftoimg.pl	(revision 10506)
@@ -0,0 +1,174 @@
+#!/usr/bin/perl -w
+
+
+###########################################################################
+#
+# pdftoimg.pl -- convert PDF documents to various types of Image format
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001 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.
+#
+###########################################################################
+# pdftoimg.pl is a wrapper for running convert utility which converts
+# PDF documents to various types of image (e.g. PNG, GIF, JPEG format, 
+# Then use PagedImgPlug to deal with the the images
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use util;
+use Cwd;
+use File::Basename
+;
+sub print_usage {
+    # note - we don't actually ever use most of these options...
+    print STDERR  
+	("pdftoimg.pl wrapper for pdftoimg.\n",
+	 "Usage: pdftoimg [options] <PDF-file> <output>>\n",
+	 "Options:\n",
+	 "\t-convert_to\toutput image type for the PDF\n"
+	 );
+    exit (1);
+}
+
+sub main {
+    my (@ARGV) = @_;
+    my ($convert_to);
+    
+    # read command-line arguments so that
+    # you can change the command in this script
+    if (!parsargv::parse(\@ARGV,
+			 'convert_to/.*/^', \$convert_to,
+			 )) {
+    	print_usage();
+    }
+    
+    # Make sure the input file exists and can be opened for reading
+    if (scalar(@ARGV) != 2) {
+	print_usage();
+    }
+    
+    my $input_filename = $ARGV[0];
+    my $output_filestem = $ARGV[1];
+    
+    # test that the directories exist to create the output file, or
+    # we should exit immediately. (File:: is included by util.pm)
+    &util::mk_dir($output_filestem) if (!-e $output_filestem);
+	    
+    my @dir = split (/(\/|\\)/, $input_filename);
+    my $input_basename = pop(@dir);
+    $input_basename =~ s/\.pdf//i;
+    my $dir = join ("", @dir);
+
+    if (!-r $input_filename) {
+	print STDERR "Error: unable to open $input_filename for reading\n";
+	exit(1);
+    }
+    # don't include path on windows (to avoid having to play about
+    # with quoting when GSDLHOME might contain spaces) but assume
+    # that the PATH is set up correctly.
+    $cmd = "convert";
+    #if ($ENV{'GSDLOS'} =~ /^windows$/);
+    #Convert utility will convert the PDF to GIF Animation
+    if ($convert_to eq "gif") {
+	if ($ENV{'GSDLOS'} =~ /^windows$/){
+	    $cmd .= " ".$input_filename." ".$output_filestem."\\".$input_basename."-%02d.".$convert_to;
+	} else {
+	    $cmd .= " ".$input_filename." ".$output_filestem."/".$input_basename."-%02d.".$convert_to;
+	}
+    } else {
+	if ($ENV{'GSDLOS'} =~ /^windows$/){
+	    $cmd .= " ".$input_filename." ".$output_filestem."\\".$input_basename.".".$convert_to;
+	} else {
+	    $cmd .= " ".$input_filename." ".$output_filestem."/".$input_basename.".".$convert_to;
+	}
+    }	
+ 
+    # system() returns -1 if it can't run, otherwise it's $cmds ret val.
+    # note we return 0 if the file is "encrypted"
+    $!=0;
+    if (system($cmd)!=0) {
+	print STDERR "Convert error for $input_filename $!\n";
+	# leave these for gsConvert.pl...
+	#&util::rm("$output_filestem.text") if (-e "$output_filestem.text");
+	#&util::rm("$output_filestem.err") if (-e "$output_filestem.err");
+	return 1;
+    } else {
+	# command execute successfully
+	create_itemfile($output_filestem, $input_basename, $convert_to);
+    }
+    return 0;
+}
+
+sub create_itemfile
+{
+    my ($output_dir, $convert_basename, $convert_to) = @_;
+    opendir(DIR, $output_dir) || die "can't opendir $output_dir: $!";  
+    my $item_file = $output_dir."/".$convert_basename.".item";
+    open(FILE,">$item_file");
+    
+    print FILE "<PagedDocument>\n";
+
+    my $page_num = "";
+    @dir_files = grep {-f "$output_dir/$_"} readdir(DIR);
+
+    # Sort files in the directory by page_num    
+    sub page_num {
+	my ($dir) = @_;
+	my $pagenum = "";
+	if ($ENV{'GSDLOS'} =~ /^windows$/){
+	   ($pagenum) =($dir =~ m/^.*\.(\d+)$/i);   
+	} else {
+	   ($pagenum) =($dir =~ m/^.*-(\d+)\.(.*)$/i);
+	}
+	$pagenum = $pagenum || 1;
+	return $pagenum;
+    }
+
+    # sort the files in the directory in the order of page_num rather than lexically. 
+    @dir_files = sort { page_num($a) <=> page_num($b) } @dir_files;
+
+    foreach my $file (@dir_files){
+        if ($ENV{'GSDLOS'} =~ /^windows$/ && $convert_to ne "gif"){
+	  ($page_num) =($file =~ m/^.*\.(\d+)$/i); 
+	} else {
+	    ($page_num) =($file =~ m/^.*-(\d+)\.(.*)/i);   
+	}
+	# as the converter will convert the document to image files start from page 0
+	$page_num =$page_num + 1 if defined $page_num;
+	$page_num = 1 unless defined $page_num;
+	if ($file !~ /\.item/i){
+	    print FILE "   <Page pagenum=\"$page_num\" imgfile=\"$file\" txtfile=\"\"/>\n";
+	} 
+    }
+
+    print FILE "</PagedDocument>\n";
+    closedir DIR;
+    return "";
+}
+
+# indicate our error status, 0 = success
+exit (&main(@ARGV));
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/ping.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/ping.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/ping.pl	(revision 10506)
@@ -0,0 +1,74 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# ping.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan/Ping");
+}
+
+
+require LWP::UserAgent;
+use parsargv;
+
+&main();
+
+sub print_usage {
+    print STDERR "\n";
+    print STDERR "ping.pl: Ping http or ftp URL to see if it's accessable.\n\n";
+    print STDERR "  usage: $0 [options] URL\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -quiet   Quiet operation\n\n";
+}
+
+sub main {
+
+    my ($quiet);
+    if (!parsargv::parse(\@ARGV, 'quiet', \$quiet)) {
+	&print_usage();
+	die "\n";
+    }
+
+    if (!scalar(@ARGV)) {
+	print STDERR "ERROR: no URL was provided\n";
+	die "\n";
+    }
+
+    $ua = new LWP::UserAgent;
+    $ua->timeout(60);
+    $request = new HTTP::Request('HEAD', $ARGV[0]);
+    $response = $ua->request($request);
+    
+    if ($response->is_success) {
+	print STDERR "$ARGV[0] ping succeeded\n" unless $quiet;
+	exit 0;
+    } else {
+	print STDERR "$ARGV[0] ping failed\n" unless $quiet;
+	exit 1;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/pluginfo.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/pluginfo.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/pluginfo.pl	(revision 10506)
@@ -0,0 +1,209 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# pluginfo.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# This program will print info about a plugin
+
+use strict;
+no strict 'subs'; # allow barewords (eg STDERR) as function arguments
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+}
+
+use plugin;
+use util;
+use gsprintf;
+use printusage;
+
+use parse2;
+
+my $arguments =
+    [ { 'name' => "collect",
+	'desc' => "{pluginfo.collect}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "xml",
+	'desc' => "{scripts.xml}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "listall",
+	'desc' => "{scripts.listall}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "language",
+	'desc' => "{scripts.language}",
+	'type' => "string",
+	'reqd' => "no" } ];
+
+my $options = { 'name' => "pluginfo.pl",
+		'desc' => "{pluginfo.desc}",
+		'args' => $arguments };
+
+sub gsprintf
+{
+    return &gsprintf::gsprintf(@_);
+}
+
+
+sub main {
+    my $collect = "";
+    my $xml = 0;
+    my $listall = 0;
+    
+    my ($language, $encoding);
+
+    my $hashParsingResult = {};
+    my $blnParseFailed = "false";
+    # general options available to all plugins
+    my $intArgLeftinAfterParsing = parse2::parse(\@ARGV,$arguments,$hashParsingResult,"allow_extra_options");
+    # If there are more than one argument left after parsing, it mean user input too many arguments.
+    # Error occoured  will return 0
+    if($intArgLeftinAfterParsing > 1)
+    {
+	&PrintUsage::print_txt_usage($options, "{pluginfo.params}");
+	die "\n";
+    }
+
+    foreach my $strVariable (keys %$hashParsingResult)
+    {
+	eval "\$$strVariable = \$hashParsingResult->{\"\$strVariable\"}";
+    }
+
+    # if language wasn't specified, see if it is set in the environment
+    # (LC_ALL or LANG)
+    if (!$language && ($_=$ENV{'LC_ALL'} or $_=$ENV{'LANG'})) {
+	m/^([^\.]+)\.?(.*)/;
+	$language=$1;
+	$encoding=$2; # might be undef...
+# gsprintf::load_language* thinks "fr" is completely different to "fr_FR"...
+	$language =~ s/_.*$//;
+    }
+
+    # If $language has been set, load the appropriate resource bundle
+    # (Otherwise, the default resource bundle will be loaded automatically)
+    if ($language) {
+	gsprintf::load_language_specific_resource_bundle($language);
+	if ($encoding) {
+	    $encoding =~ tr/-/_/;
+	    $encoding = lc($encoding);
+	    $encoding =~ s/utf_8/utf8/; # special
+	    $gsprintf::specialoutputencoding=$encoding;
+	}
+    }
+
+    my $plugin = shift (@ARGV);
+    if (defined $plugin) {
+	$plugin =~ s/\.pm$//; # allow xxxPlug.pm as the argument
+    }
+    if (($listall == 0) && (!defined $plugin || $plugin eq "")) {
+	gsprintf(STDERR, "{pluginfo.no_plugin_name}\n\n");
+	PrintUsage::print_txt_usage($options, "{pluginfo.params}", 1);
+	die "\n";
+    }
+
+    if ($collect ne "") {
+	$ENV{'GSDLCOLLECTDIR'} = &util::filename_cat ($ENV{'GSDLHOME'}, "collect", $collect);
+    } else {
+	$ENV{'GSDLCOLLECTDIR'} = $ENV{'GSDLHOME'};
+    }
+
+    if ($listall) {
+	my $plugin_dir = &util::filename_cat($ENV{'GSDLCOLLECTDIR'},"perllib","plugins");
+	
+	if (!opendir (INDIR, $plugin_dir)) {
+	    print STDERR "pluginfo.pl: could not open directory $plugin_dir\n";
+	} else {
+	    my @plugin_list = grep (/Plug\.pm$/, readdir (INDIR));
+	    closedir (INDIR);
+
+
+	    if ($xml) {
+		my $num_plugins = scalar(@plugin_list);
+
+		print STDERR "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+		print STDERR "<!DOCTYPE PluginList [\n";
+		print STDERR "  <!ELEMENT PluginList (PluginName*)>\n";
+		print STDERR "  <!ELEMENT PlugName   (#PCDATA)>\n";
+		print STDERR "  <!ATTLIST PluginList\n";
+		print STDERR "            length CDATA #REQUIRED>\n";
+		print STDERR "]>\n";
+
+		print STDERR "<PluginList length=\"$num_plugins\">\n";
+		map { print STDERR "  <PluginName>$_</PluginName>\n"; } @plugin_list;
+		print STDERR "</PluginList>\n";
+
+	    }
+	    else {
+		print STDERR join(" ",@plugin_list), "\n";
+	    }
+	}
+
+    }
+    else {
+
+	my $pluginfo = &plugin::load_plugins ([[$plugin]]);
+	my $plugobj = shift @$pluginfo;
+	
+	if ($xml) {
+	    $plugobj->print_xml_usage();
+	}
+	else {
+	    gsprintf(STDERR, "\n{pluginfo.passing_options}\n\n");
+	    gsprintf(STDERR, "{pluginfo.option_types}:\n\n");
+	    gsprintf(STDERR, "{pluginfo.specific_options}\n\n");
+	    gsprintf(STDERR, "{pluginfo.general_options}\n\n");
+	    gsprintf(STDERR, "$plugin {pluginfo.info}:\n\n");
+	    
+	    $plugobj->print_txt_usage();
+	}
+    }
+}
+
+
+# this causes us to automatically send output to a pager, if one is
+# set, AND our output is going to a terminal
+# active state perl on windows doesn't do open(handle, "-|");
+if ($ENV{'GSDLOS'} !~ /windows/ && -t STDOUT) {
+    my $pager = $ENV{"PAGER"};
+    if (! $pager) {$pager="(less || more)"}
+    my $pid = open(STDIN, "-|"); # this does a fork... see man perlipc(1)
+    if (!defined $pid) {
+	gsprintf(STDERR, "pluginfo.pl - can't fork: $!");
+    } else {
+	if ($pid != 0) { # parent (ie forking) process. child gets 0
+	    exec ($pager);
+	}
+    }
+    open(STDERR,">&STDOUT"); # so it's easier to pipe output
+}
+
+
+&main ();
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/ppttohtml.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/ppttohtml.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/ppttohtml.pl	(revision 10506)
@@ -0,0 +1,68 @@
+eval 'exec perl -x -- $0 $@'
+    if 0;
+#! perl
+# line 6
+
+sub usage() {
+    print "$0 <input.ppt> <output.html>\n";
+}
+
+
+if (@ARGV != 2) {
+    usage();
+    exit(1);
+}
+my $input_ppt=shift;
+my $output_html=shift;
+
+# try to find ppthtml binary in GSDLHOME
+my $ppthtml_binary="ppthtml";
+my $GSDLOS=$ENV{'GSDLOS'};
+my $GSDLHOME=$ENV{'GSDLHOME'};
+if ($GSDLOS =~ /^windows$/i) {
+    $ppthtml_binary.=".exe";
+}
+
+# assume it is on the path if running under windows, in case GSDLHOME
+# has a space
+if ($GSDLOS !~ /windows/i && -x "$GSDLHOME/bin/$GSDLOS/$ppthtml_binary") {
+    $ppthtml_binary="$GSDLHOME/bin/$GSDLOS/$ppthtml_binary";
+}
+
+if (! -r $input_ppt) {
+    print STDERR "Unable to read file `$input_ppt'\n";
+    exit (1);
+}
+
+my $return_value=
+    system("$ppthtml_binary \"$input_ppt\" > \"$output_html\"");
+
+if ($return_value != 0) {
+    exit (1);
+}
+
+# Ok, we made an html file. Check to see if it has any content, and remove
+# the little nag link at the the bottom.
+my $html="";
+open (HTML, "$output_html") || die "Can't read file:$!";
+$html=join('', <HTML>);
+close HTML;
+
+$html =~ s@<hr><FONT SIZE=-1>Created with.*\n</BODY></HTML>$@</BODY></HTML>@s;
+
+# if we are using the file name as the title, then get rid of it,
+# as HTMLPlug will use the first 100 chars instead if there's no title.
+$html =~ s@<title>.*?\.ppt</title>@<title></title>@i;
+
+my $tmp=$html;
+$tmp =~ s/^.*?<BODY>//ms;
+$tmp =~ s/(&nbsp;)|\s//gims;
+if ($tmp !~ m/(>[^<]+<)/) {
+    print STDERR "No text found in extracted html file!\n";
+    exit(1);
+}
+open (NEWHTML, ">$output_html") || die "Can't create file:$!";
+print NEWHTML $html;
+close NEWHTML;
+exit (0);
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/process_html.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/process_html.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/process_html.pl	(revision 10506)
@@ -0,0 +1,393 @@
+#!/usr/bin/perl -w
+
+
+# Both this script and its associated process_html.pl were written by
+# Marcel ?, while a student at Waikato University. Unfortunately he
+# was very new to perl at the time so the code is neither as clean nor
+# as fast as it could be (I've cleaned up a few of the more serious
+# bottlenecks -- it could do with alot more work though).  The code
+# does work though, if a little slowly. It's not ready for primetime
+# however and is included in the Greenstone source tree mostly so that
+# I don't lose it. -- Stefan - 24 Jul 2001
+
+
+# This script rebuilds the static collection by linking all the downloaded html files
+# back together. 
+# It searches through html files and replaces links it recognizes from the links.txt file 
+# with the apropriate html file name (eg 1.html, 2.html etc)
+# This script also updates the links for the pictures.
+
+# This is where all the dl-ed html files are located, eg. 'temp_html/'
+my $outputdir  = 'temp_html/';
+
+# This is where all the processed files end up (don't want to overwrite originals ;) eg. 'my_static_collection/'
+my $finaldir   = 'envl_collection/';
+
+# If any options where used (such as &u=1) when the html files where dl-ed then please specify them here.
+my $option = "&u=1";
+
+# Please ensure these two options match the settings used when downloading the collection :)
+my $dir_entries = 250;
+my $fix_empty_pages = '&cl=CL1';
+
+#-------------------------------------------------------------------------------------------------
+
+# global arrays used to store links, links-index & html-filenames
+my %filez;
+my %out_filez;
+my %linkz;
+my %short_linkz1;
+my %short_linkz2;
+my %short_linkz3;
+my %linkz_index;
+#my %remove_these;
+my $remove_these = "";
+
+sub processfiles
+{
+    local($start_here) = @_;
+
+    for my $file($start_here .. $#filez)
+    {
+	if((-e $filez[$file])&&(-s $filez[$file]))
+	{
+	    open (FILE, $filez[$file]) or die "can't open ", $filez[$file],": $! \n";
+	    
+	    print " $filez[$file] ";
+	    
+	    undef $/;
+	    my $content_of_file = <FILE>;
+	    $/ = "\n";
+	    close(FILE);
+	    
+	    #quick & nasty fix for the 'open book' link
+	    local $quick_fix1 = "&cl=\"";
+	    local $quick_fix2 = "&cl=\'";
+	    
+	    $content_of_file =~ s/$quick_fix1/$fix_empty_pages\"/g;
+	    $content_of_file =~ s/$quick_fix2/$fix_empty_pages\'/g;
+	    
+	    for my $link(0 .. $#linkz)
+	    {
+		my $new_link = $linkz_index[$link].".html";
+		
+		if($short_linkz3[$link] ne "")
+		{
+		    $content_of_file =~ s/$short_linkz1[$link].*?$short_linkz2[$link].*?${short_linkz3[$link]}[^\"\'\s\>]*/$new_link/g;
+		}
+		else
+		{
+			$content_of_file =~ s/$short_linkz1[$link].*${short_linkz2[$link]}[^\"\'\s\>]*/$new_link/g;
+		}
+	    }
+    
+            $content_of_file =~ s/(["'])$remove_these/$1..\//g;
+	    open (TEMP, ">temp.html") or die "can't open temp.html: $! \n";
+	    print TEMP $content_of_file;
+	    close(TEMP);
+	    rename("temp.html", $out_filez[$file]) or die "cannot create", $out_filez[$file],": $! \n";
+	    print " --> $out_filez[$file]";
+	    print "..done\n";
+	}
+	else
+	{
+	    last;    # bomb out of loop. Done.
+	}
+    }
+     print " *** Done, cannot find any more files to process ***\n";
+}
+
+# the switch variable there so that I can create a couple of additional arrays without having to write an entirely new function :-)
+# 0 = off, 1 = on (puts values into %linkz_index, %short_linkz1 and %short_linkz2)
+sub sort_array_by_length
+{
+    local (*foo, $switch) = @_;
+    my $total = $#foo;
+    my %temp_linkz;
+    my $shortest = 999999;
+    my $longest = 0;
+
+    if ($switch != 0)
+    {
+	print "Processing linkz (chopping, slicing, dicing and sorting :-)...";
+    }
+
+    for my $counter(0 .. $total)
+    {
+	if (length($foo[$counter]) < $shortest)
+	{
+	    $shortest = length($foo[$counter]);   
+	    $temp_linkz[$total] = $foo[$counter];
+	}
+	if (length($foo[$counter]) > $longest)
+	{
+	    $longest = length($foo[$counter]);   
+	}  
+    }        
+    
+    $backward = $total;
+    for my $l($shortest .. $longest)
+    {      
+	local $numberdir = 0;
+	for my $counter(0 .. $total)
+	{
+	    if ($counter % $dir_entries == 0)
+	    {
+		$numberdir = $counter;
+	    }
+
+	    if(length($foo[$counter]) == $l)
+	    {
+		$temp_linkz[$backward] = $foo[$counter];
+		if ($switch != 0)
+		{ 
+		    $linkz_index[$backward] = "../".$numberdir."/".$counter;
+		    my $d_offset = 0;
+		    for my $search(0 .. (length($foo[$counter]) - 3))
+		    {
+			if((substr($foo[$counter], $search, 3) eq '?e=')||(substr($foo[$counter], $search, 3) eq '&e='))
+			{
+			    $short_linkz1[$backward] = substr($foo[$counter], 0, $search);
+			}
+			
+			for my $second_search($search .. length($foo[$counter]))
+			{
+			    if((substr($foo[$counter], $second_search, 3) eq '?d=')||(substr($foo[$counter], $second_search, 3) eq '&d='))
+			    {
+				$short_linkz3[$backward] = substr($foo[$counter], $second_search);
+				$d_offset = $second_search;
+				last;
+			    }
+			}
+			
+			if(substr($foo[$counter], $search, 3) eq '?a=')
+			{
+			    $short_linkz1[$backward] = substr($foo[$counter], 0, $search);
+			    if($d_offset > 0)
+			    {
+				$short_linkz2[$backward] = substr($foo[$counter], $search, $d_offset - $search);
+			    }
+			    else
+			    {
+				$short_linkz2[$backward] = substr($foo[$counter], $search);
+			    }
+			}
+			
+			if(substr($foo[$counter], $search, 3) eq '&a=')
+			{
+			    if($d_offset > 0)
+			    {
+				$short_linkz2[$backward] = substr($foo[$counter], $search, $d_offset - $search);
+			    }
+			    else
+			    {
+				$short_linkz2[$backward] = substr($foo[$counter], $search);
+			    }
+			}
+		    } 
+		}
+		$backward--;
+	    }
+	}
+    }    
+    # copy the sorted temp_array over the original array (must be a better way of doing this :\ )
+    for my $counter(0 .. $total)
+    {    
+	$foo[$counter] = $temp_linkz[$counter];
+    }
+    if ($switch != 0)
+    {
+	print "done!\n";
+    }
+}
+
+sub how_much_to_chop
+{
+    local($link) = @_;
+    my $bracket_counter = 0;
+    my $chop_offset = 0;
+
+    for my $search(0 .. length($link))
+    {
+	if (substr($link, $search, 1) eq '/')
+	{
+	    $bracket_counter++;   
+	}
+	if ($bracket_counter == 2)
+	{
+	    $chop_offset = $search + 1;
+	} 
+    }
+    return $chop_offset;
+}
+
+my $start_time = (times)[0]; 
+
+#-----------------------------------------------------------------------------------------------
+# No need to start from scratch everytime, we can recover/continue from wherever we left off
+# simply by checking which html files have been created
+#-----------------------------------------------------------------------------------------------
+my $linknumber = 0;
+my $failed     = 0;
+my $check_file = "";
+my $numberdir = 0;
+
+if($outputdir ne $finaldir)
+{
+    while ($failed == 0)
+    {
+	if ($linknumber % $dir_entries == 0) 
+	{
+	    if (!((-e $finaldir.$linknumber)&&(-d $finaldir.$linknumber)))
+	    {
+		$failed++;
+		mkdir($finaldir.$linknumber, 0777) or die " ** Cannot create ",$finaldir.$linknumber, "!: $!\n";
+	    }
+	    $numberdir = $linknumber;
+	}
+	
+	$check_file = $finaldir.$numberdir."/".$linknumber.".html";
+	if ((-e $check_file)&&($failed == 0)) 
+	{ 
+	    $linknumber++;
+	} 
+	else
+	{
+	    $failed++;
+	    # I'm subtracting 1 from the starting link, 
+	    # just in case it only loaded half the page ;^)
+	    if($linknumber>0) 
+	    { 
+		$linknumber--; 
+	    }
+	    print " Will start processing at number $linknumber \n";
+	}
+    }
+}
+my $i = 0;
+my $that = "";
+my $offset = 0;
+
+#read in old links from links text file
+open (CHECK, "links.txt") || die " ** Cannot find/open links text file!: $!\n";
+while (defined ($that = <CHECK>)) {
+    
+    if ($i == 0)
+    {  
+	#chop off the first bit
+	$offset = &how_much_to_chop($that); 
+	print " Offset has been set to: ",$offset,"\n";
+	print " This next bit will be ignored for all links in the links.txt file:\n";
+	print "  -->",substr($that,0,$offset),"<--\n";
+    }
+    
+    $that = substr($that, $offset);
+    
+    #Wipe-out the EOL character
+#    if (substr($that, -1) eq "\n") { substr($that, -1) = ""; }
+    chomp $that;
+    
+    #this wipes the options
+#    if (length($option) != 0)
+#    {	    
+#	substr($that, (length($option)) * -1) = "";
+#    }
+    $that =~ s/$option//;
+    
+    $linkz[$i] = $that;
+    
+    $short_linkz1[$i] = "";
+    $short_linkz2[$i] = "";
+    $short_linkz3[$i] = "";
+    
+    for my $search(0 .. (length($that) - 3))
+    {
+	if((substr($that, $search, 3) eq '?e=')||(substr($that, $search, 3) eq '&e='))
+	{
+	    $short_linkz1[$i] = substr($that, 0, $search);
+	}
+	
+	if(substr($that, $search, 3) eq '?a=')
+	{
+	    $short_linkz1[$i] = substr($that, 0, $search);
+	    $short_linkz2[$i] = substr($that, $search);
+	}
+	if(substr($that, $search, 3) eq '&a=')
+	{
+	    $short_linkz2[$i] = substr($that, $search);
+	}
+    }
+    $i++;
+    
+    if ($i % $dir_entries == 0)
+    {
+	if (!((-e $finaldir.$i)&&(-d $finaldir.$i)))
+	{
+	    mkdir($finaldir.$i, 0777) or die " ** Cannot create ",$finaldir.$i, "!: $!\n";
+	}
+    }
+}
+close(CHECK);
+
+print " - I found ",$i, " links in the links text file -\n";
+
+&sort_array_by_length(*linkz, 1);
+
+$numberdir = 0;
+
+for my $z(0 .. ($i - 1))
+{
+    if($z % $dir_entries == 0)
+    {
+	$numberdir = $z;
+    }
+    $filez[$z] = $outputdir.$numberdir."/".$z.".html";
+    $out_filez[$z] = $finaldir.$numberdir."/".$z.".html";
+}
+
+# ..and last but not least, load any image_dirs from image_dirs.txt
+my $imd_that = "";
+#my $image_dirs_pointer = 0;
+
+my @tmp_arr = ();
+open (IMAGE_DIR, "image_dirs.txt") || die " ** HEY! Cannot find/open image_dirs.txt file! : $! **\n";
+while(defined ($imd_that = <IMAGE_DIR>))
+{
+    chomp $imd_that;
+    push(@tmp_array, $imd_that);
+}
+close IMAGE_DIR;
+
+$remove_these = "(" . join ("|", sort {length $b <=> length $a} @tmp_array) . ")"; 
+
+#print " - I found ",($#remove_these + 1)," picture directories in image_dirs.txt -\n";
+#&sort_array_by_length(*remove_these, 0);
+
+print "-" x 20, "\n";
+print "  Here we go...\n";
+print "-" x 20, "\n";
+
+&processfiles($linknumber);
+
+my $end_time = (times)[0];
+print "\n\n\n *----------------------------*\n";
+print " |  Whew! Task completed! :-D |\n";
+print " *----------------------------*\n";
+printf"  Script took %.2f CPU seconds to complete ;^)\n", $end_time - $start_time;
+print "\n\n"; 
+print " Now there's a few things left to do...load up ",$finaldir, "0/0.html in your webbrowser and\n";
+print " make sure everything works.\n"; 
+print " The grab_collection script will have generated 3 text files that can be removed, namely:\n";
+print " - links.txt \n";
+print " - images.txt \n";
+print " - image_dirs.txt \n\n";
+if ($outputdir ne $finaldir)
+{
+    print "And then finally you can also delete the ",$outputdir," directory.\n\n";
+}
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/registerencoding.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/registerencoding.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/registerencoding.pl	(revision 10506)
@@ -0,0 +1,138 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# registerencoding.pl - Add "Encoding" entry to etc/main.cfg file
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+
+###########################################################################
+#
+# CODE SYNOPSIS
+#
+# This script registers a new encoding by adding an "Encoding" entry to
+#   the $GSDLHOME/etc/main.cfg file. It:
+#
+# - Parses the three required arguments: encoding name, encoding
+#     description, and mapfile name.
+# - Checks if the encoding specified is already defined in main.cfg.
+# - If it isn't, add a new "Encoding" entry and rewrite main.cfg.
+#
+###########################################################################
+
+
+use util;
+
+
+sub main
+{
+    # Get the short name of the encoding being registered
+    local $encodingname = shift(@_);
+    # Get the long name of the encoding being registered
+    local $encodingdesc = shift(@_);
+    # Get the name of the map file for the encoding being registered
+    local $mapfilename = shift(@_);
+
+    # Read any extra arguments
+    local $option_multibyte_encoding = 0;
+    local $optionalarg = shift(@_);
+    while ($optionalarg) {
+	if ($optionalarg eq "-multibyte") { $option_multibyte_encoding = 1; }
+	$optionalarg = shift(@_);
+    }
+
+    # Check that the necessary arguments were supplied
+    if (!$encodingname || !$encodingdesc || !$mapfilename) {
+	print STDERR "Usage: registerencoding.pl <encoding-name> <encoding-desc> <mapfile-name> [-multibyte]\n";
+	die "Error: Required argument missing.\n";
+    }
+
+    # Casefold the encoding name
+    $encodingname =~ tr/A-Z/a-z/;
+
+    # Open and read the etc/main.cfg file
+    local $gsdldir = "$ENV{'GSDLHOME'}";
+    local $maincfgfile = &util::filename_cat($gsdldir, "etc", "main.cfg");
+    open(MAIN_CFG_FILE, "<$maincfgfile") or die "Error: Could not open $maincfgfile.\n";
+    local @maincfglines = <MAIN_CFG_FILE>;
+    close(MAIN_CFG_FILE);
+
+    # Check if the encoding is already defined in the main.cfg file
+    local $lastencline;
+    for ($i = 0; $i < scalar(@maincfglines); $i++) {
+	local $line = $maincfglines[$i];
+
+	# Remove any nasty whitespace at the end of the line
+	$line =~ s/(\s*)$//;
+
+	# Does this line contain an Encoding entry?
+	if ($line =~ /^Encoding\s+/i) {
+	    local @encodingparts = split(/\s+/, $line);
+
+	    # Read the encoding name
+	    local $encname = "";
+	    for ($j = 1; $j < scalar(@encodingparts); $j++) {
+		if ($encodingparts[$j] =~ /^shortname=(.*)$/i) {
+		    $encname = $1;
+		}
+	    }
+
+	    # Casefold the encoding name
+	    $encname =~ tr/A-Z/a-z/;
+
+	    # No need to register an encoding that is already defined
+	    if ($encname eq $encodingname) {
+		# print "Note: Encoding with name '$encodingname' is already defined.\n";
+		return;
+	    }
+
+	    # Remember the last line containing an Encoding entry
+	    $lastencline = $i;
+	}
+    }
+
+    # The encoding has not been defined, so add a new entry to the main.cfg file
+    local $encodingline = "Encoding shortname=$encodingname \"longname=$encodingdesc\"" .
+	                    " map=$mapfilename";
+    if ($option_multibyte_encoding == 1) {
+	$encodingline = $encodingline . " multibyte";
+    }
+    $maincfglines[$lastencline] = $maincfglines[$lastencline] . $encodingline . "\n";
+
+    # Rewrite the (modified) main.cfg file
+    open(MAIN_CFG_FILE, ">$maincfgfile") or die "Error: Could not write $maincfgfile.\n";
+    foreach $line (@maincfglines) {
+	print MAIN_CFG_FILE "$line";
+    }
+    close(MAIN_CFG_FILE);
+}
+
+
+&main(@ARGV);
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/registerlanguage.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/registerlanguage.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/registerlanguage.pl	(revision 10506)
@@ -0,0 +1,139 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# registerlanguage.pl - Add "Language" entry to etc/main.cfg file
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+
+###########################################################################
+#
+# CODE SYNOPSIS
+#
+# This script registers a new interface language by adding a "Language"
+#   entry to the $GSDLHOME/etc/main.cfg file. It:
+#
+# - Parses the three required arguments: language name, ISO 639 language
+#     code, and encoding name.
+# - Checks if the language specified is already defined in main.cfg.
+# - If it isn't, add a new "Language" entry and rewrite main.cfg.
+#
+###########################################################################
+
+
+use util;
+
+
+sub main
+{
+    # Get the code of the language being registered
+    local $languagecode = shift(@_);
+    # Get the name of the language being registered
+    local $languagename = shift(@_);
+    # Get the name of the encoding for the language being registered
+    local $encodingname = shift(@_);
+
+    # Check that the necessary arguments were supplied
+    if (!$languagecode || !$languagename || !$encodingname) {
+	print STDERR "Usage: registerlanguage.pl <language-code> <language-name> <encoding-name>\n";
+	die "Error: Required argument missing.\n";
+    }
+
+    # Casefold the language code and name
+    $languagecode =~ tr/A-Z/a-z/;
+    $languagename =~ tr/A-Z/a-z/;
+
+    # Open and read the etc/main.cfg file
+    local $gsdldir = "$ENV{'GSDLHOME'}";
+    local $maincfgfile = &util::filename_cat($gsdldir, "etc", "main.cfg");
+    open(MAIN_CFG_FILE, "<$maincfgfile") or die "Error: Could not open $maincfgfile.\n";
+    local @maincfglines = <MAIN_CFG_FILE>;
+    close(MAIN_CFG_FILE);
+
+    # Check if the language is already defined in the main.cfg file
+    local $lastlangline;
+    for ($i = 0; $i < scalar(@maincfglines); $i++) {
+	local $line = $maincfglines[$i];
+
+	# Remove any nasty whitespace at the end of the line
+	$line =~ s/(\s*)$//;
+
+	# Does this line contain a Language entry?
+	if ($line =~ /^Language\s+/i) {
+	    local @languageparts = split(/\s+/, $line);
+
+	    # Read the language code and name
+	    local $langcode = "";
+	    local $langname = "";
+	    for ($j = 1; $j < scalar(@languageparts); $j++) {
+		if ($languageparts[$j] =~ /^shortname=(.*)$/i) {
+		    $langcode = $1;
+		}
+		if ($languageparts[$j] =~ /^longname=(.*)$/i) {
+		    $langname = $1;
+		}
+	    }
+
+	    # Casefold the language code and name
+	    $langcode =~ tr/A-Z/a-z/;
+	    $langname =~ tr/A-Z/a-z/;
+
+	    # No need to register a language that is already defined
+	    if ($langcode eq $languagecode) {
+		# print "Note: Language with code '$languagecode'";
+		# if ($langname eq $languagename) {
+		#     print " and name '$languagename'";
+		# }
+		# print " is already defined.\n";
+		return;
+	    }
+
+	    # Remember the last line containing a Language entry
+	    $lastlangline = $i;
+	}
+    }
+
+    # The language has not been defined, so add a new entry to the main.cfg file
+    local $languagenametc = $languagename;
+    substr($languagenametc, 0, 1) =~ tr/a-z/A-Z/;  # Change language name to title case
+    local $languageline = "Language shortname=$languagecode longname=$languagenametc" .
+	                   " default_encoding=$encodingname";
+    $maincfglines[$lastlangline] = $maincfglines[$lastlangline] . $languageline . "\n";
+
+    # Rewrite the (modified) main.cfg file
+    open(MAIN_CFG_FILE, ">$maincfgfile") or die "Error: Could not write $maincfgfile.\n";
+    foreach $line (@maincfglines) {
+	print MAIN_CFG_FILE "$line";
+    }
+    close(MAIN_CFG_FILE);
+}
+
+
+&main(@ARGV);
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/registermacrofile.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/registermacrofile.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/registermacrofile.pl	(revision 10506)
@@ -0,0 +1,134 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# registermacrofile.pl - Add macrofile entry to etc/main.cfg file
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+
+###########################################################################
+#
+# CODE SYNOPSIS
+#
+# This script registers a new macrofile by adding it to the "macrofiles"
+#   list in the $GSDLHOME/etc/main.cfg file. It:
+#
+# - Parses the required argument: macrofile name.
+# - Checks if the macrofile specified is already defined in main.cfg.
+# - If it isn't, add a new macrofile entry and rewrite main.cfg.
+#
+###########################################################################
+
+
+use util;
+
+
+sub main
+{
+    # Get the name of the macrofile being registered
+    local $macrofilename = shift(@_);
+
+    # Check that the necessary arguments were supplied
+    if (!$macrofilename) {
+	print STDERR "Usage: registermacrofile.pl <macrofile-name>\n";
+	die "Error: Required argument missing.\n";
+    }
+
+    # Casefold the macrofile name
+    $macrofilename =~ tr/A-Z/a-z/;
+
+    # Open and read the etc/main.cfg file
+    local $gsdldir = "$ENV{'GSDLHOME'}";
+    local $maincfgfile = &util::filename_cat($gsdldir, "etc", "main.cfg");
+    open(MAIN_CFG_FILE, "<$maincfgfile") or die "Error: Could not open $maincfgfile.\n";
+    local @maincfglines = <MAIN_CFG_FILE>;
+    close(MAIN_CFG_FILE);
+
+    # Check if the macrofile is already specified in the main.cfg file
+    local $lastmacroline;
+    local $inmacrofiles = 0;
+    for ($i = 0; $i < scalar(@maincfglines); $i++) {
+	local $line = $maincfglines[$i];
+
+	# Remove any nasty whitespace at the end of the line
+	$line =~ s/(\s*)$//;
+
+	# Does this line signal the start of the list of macrofiles?
+	if ($line =~ /^macrofiles\s+/i) {
+	    $inmacrofiles = 1;
+	    $line =~ s/^macrofiles\s+//i;
+	}
+
+	if ($inmacrofiles == 1) {
+	    # Remove any whitespace before the macros
+	    $line =~ s/^\s*//;
+
+	    # If there isn't a trailing '\' on this line, it's the last line
+	    if ($line !~ /\\$/) {
+		$lastmacroline = $i;
+		$inmacrofiles = 0;
+	    }
+	    # Otherwise remove the '\'
+	    else {
+		$line =~ s/\\$//;
+	    }
+
+	    # Casefold the line
+	    $line =~ tr/A-Z/a-z/;
+	    local @macrofiles = split(/\s+/, $line);
+
+	    # No need to register a macrofile that is already defined
+	    for ($j = 0; $j < scalar(@macrofiles); $j++) {
+		if ($macrofiles[$j] eq $macrofilename) {
+		    # print "Note: Macrofile '$macrofilename' is already defined.\n";
+		    return;
+		}
+	    }
+	}
+    }
+
+    # The macrofile has not been defined, so add a new entry to the main.cfg file
+    $maincfglines[$lastmacroline] =~ s/(\s*)$//;
+    if (length($maincfglines[$lastmacroline]) > 60) {
+	$maincfglines[$lastmacroline] .= " \\\n";
+	$maincfglines[$lastmacroline] .= "               ";
+    }
+    $maincfglines[$lastmacroline] .= " $macrofilename\n";
+
+    # Rewrite the (modified) main.cfg file
+    open(MAIN_CFG_FILE, ">$maincfgfile") or die "Error: Could not write $maincfgfile.\n";
+    foreach $line (@maincfglines) {
+  	print MAIN_CFG_FILE "$line";
+    }
+    close(MAIN_CFG_FILE);
+}
+
+
+&main(@ARGV);
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/sendmail.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/sendmail.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/sendmail.pl	(revision 10506)
@@ -0,0 +1,89 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# sendmail.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 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.
+#
+###########################################################################
+
+# sendmail.pl is a simple wrapper around the Sendmail perl module written
+# by Milivoj Ivkovic <mi@alma.ch>
+
+# Input is either read from STDIN or, if the -msgfile option is set, read
+# from the given file.
+
+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 lib qq($ENV{'GSDLHOME'}/perllib/cpan);
+use Mail::Sendmail;
+use parsargv;
+
+if (!parsargv::parse(\@ARGV, 
+		     'to/@', \$to,
+		     'from/@', \$from,
+		     'subject/.*/', \$subject,
+		     'smtp/.*', \$smtp,
+		     'msgfile/.*/', \$msgfile)) {
+    print STDERR "\n";
+    print STDERR "sendmail.pl: A simple platform independant mail sending program.\n\n";
+    print STDERR "  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -to addr      Comma separated list of mail recipients\n";
+    print STDERR "   -from addr    Address of message sender\n";
+    print STDERR "   -subject str  Optional subject line\n";   
+    print STDERR "   -smtp server  The outgoing (SMTP) mail server\n";
+    print STDERR "   -msgfile file A file from which message to be sent is read.\n";
+    print STDERR "                 If not set message will be read in from STDIN\n";
+    die "\n";
+}
+
+my %mail = ('SMTP' => $smtp, 
+	    'To' => $to,
+	    'From' => $from,
+	    'Subject' => $subject,
+	    );
+
+my $msg = "";
+if ($msgfile ne "") {
+    if (!open (MSGFILE, $msgfile)) {
+	print STDERR "ERROR: Failed to open $msgfile. Message was not sent\n";
+	exit (-1);
+    }
+    undef $/;
+    $msg = <MSGFILE>;
+    $/ = "\n";
+    close MSGFILE;
+} else {
+    $msg = <STDIN>;
+}
+
+$mail{'Message'} = $msg;
+	
+if (!sendmail %mail) {
+    print STDERR "ERROR: Failed to send message\n";
+    print STDERR "'$Mail::Sendmail::error'\n";
+    exit (-1);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/translate.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/translate.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/translate.pl	(revision 10506)
@@ -0,0 +1,488 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# translate.pl 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# translate.pl takes a translated macro file (filename passed in on command
+# line) and generates any images required by it. Check out english.dm for
+# an example of the format translate.pl expects
+
+# translate.pl uses gimp to generate images so needs gimp installed and set
+# up for scripting with perl
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use Gimp qw/:auto :DEFAULT/;
+use parsargv;
+use util;
+use unicode;
+
+# these html entities will be translated correctly when occurring in 
+# images. Any entities not in this list will not.
+my %rmap = ('auml' => chr (228),
+	    'euml' => chr (235),
+	    'iuml' => chr (239),
+	    'ouml' => chr (246),
+	    'uuml' => chr (252),
+	    'Auml' => chr (196),
+	    'Euml' => chr (203),
+	    'Iuml' => chr (207),
+	    'Ouml' => chr (214),
+	    'Uuml' => chr (220),
+	    'szlig' => chr (223),
+	    'aacute' => chr (225),
+	    'eacute' => chr (233),
+	    'iacute' => chr (237),
+	    'oacute' => chr (243),
+	    'uacute' => chr (250),
+	    'Aacute' => chr (193),
+	    'Eacute' => chr (201),
+	    'Iacute' => chr (205),
+	    'Oacute' => chr (211),
+	    'Uacute' => chr (218),
+	    'agrave' => chr (224),
+	    'egrave' => chr (232),
+	    'igrave' => chr (236),
+	    'ograve' => chr (242),
+	    'ugrave' => chr (249),
+	    'Agrave' => chr (192),
+	    'Egrave' => chr (200),
+	    'Igrave' => chr (204),
+	    'Ograve' => chr (210),
+	    'Ugrave' => chr (217),
+	    'ntilde' => chr (241),
+	    'Ntilde' => chr (209),
+	    'atilde' => chr (227),
+	    'Atilde' => chr (195),
+	    'otilde' => chr (245),
+	    'Otilde' => chr (213),
+	    'ccedil' => chr (231),
+	    'Ccedil' => chr (199),
+	    'ecirc' => chr (234),
+	    'Ecirc' => chr (202),
+	    'acirc' => chr (226),
+	    'Acirc' => chr (194),
+	    );
+
+my $hand_made = 0;
+
+sub print_usage {
+    print STDERR "\n";
+    print STDERR "translate.pl: Uses gimp to generate any images required by a\n";
+    print STDERR "              Greenstone macro file.\n\n";
+    print STDERR "  usage: $0 [options] macrofile\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -save_orig_file       edited macrofile will be written to\n";
+    print STDERR "                         macrofile.new leaving macrofile unchanged\n";
+    print STDERR "   -language_symbol      ISO abbreviation of language (e.g. German=de,\n";
+    print STDERR "                         French=fr, Maori=mi)\n";
+    print STDERR "   -image_dir directory  full path to directory in which to create images\n";
+    print STDERR "                         (defaults to `pwd`/images)\n\n";
+}
+
+sub gsdl_translate {
+
+    if (!parsargv::parse(\@ARGV, 
+			 'save_orig_file', \$save_orig_file,
+			 'language_symbol/[A-Za-z]{2}', \$language_symbol,
+			 'image_dir/.*/images', \$image_dir)) {
+	&print_usage();
+	die "\n";
+    }
+
+    if ($image_dir eq "images") {
+	$image_dir = `pwd`;
+	chomp $image_dir;
+	$image_dir = &util::filename_cat ($image_dir, "images");
+    }
+
+    if (!defined $ARGV[0]) {
+	print STDERR "no macro file supplied\n\n";
+	&print_usage();
+	die "\n";
+    }
+    my $macrofile = $ARGV[0];
+    die "\nmacrofile $macrofile does not exist\n\n" unless -e $macrofile;
+
+    if (!-e $image_dir) {
+	mkdir ($image_dir, 511) || die "\ncouldn't create image_dir $image_dir\n\n";
+    }
+
+    open (INPUT, $macrofile) || die "\ncouldn't open $macrofile for reading\n\n";
+    open (OUTPUT, ">$macrofile.new") || die "\ncouldn't open temporary file $macrofile.new for writing\n\n";
+
+    &parse_file (INPUT, OUTPUT);
+
+    close OUTPUT;
+    close INPUT;
+
+    if (!$save_orig_file) {
+	`mv $macrofile.new $macrofile`;
+    }
+
+    print STDERR "\n\n";
+    print STDERR "translation of macro file $macrofile completed\n";
+    print STDERR "the translated macro file is $macrofile.new\n" if $save_orig_file;
+    print STDERR "\n";
+    if ($hand_made) {
+	print STDERR "$hand_made hand made images were found within $macrofile,\n";
+	print STDERR "these will need to be made by hand (grep $macrofile for 'hand_made'\n\n";
+    }
+    print STDERR "To add your new interface translation to Greenstone you'll need to:\n";
+    print STDERR "  1. Copy your new macro file to your GSDLHOME/macros directory\n";
+    print STDERR "  2. Add your new macro file to the macrofiles list in your\n";
+    print STDERR "     GSDLHOME/etc/main.cfg configuration file\n";
+    print STDERR "  3. Copy your newly created images from $image_dir to \n";
+    print STDERR "     GSDLHOME/images/$language_symbol/\n\n";
+    print STDERR "Access your new interface language by setting the language (l) cgi\n";
+    print STDERR "argument to '$language_symbol'\n\n";
+
+}
+
+sub parse_file {
+    my ($input, $output) = @_;
+
+    undef $/;
+    my $dmfile = <$input>;
+    $/ = "\n";
+
+    # process all the images
+
+    $dmfile =~ s/(?:^|\n)\#\#\s*\"([^\"]*)\"\s*\#\#\s*([^\s\#]*)\s*\#\#\s*([^\s\#]*)\s*\#\#(.*?)(?=(\n\#|\s*\Z))/&process_image ($1, $2, $3, $4)/esg;
+
+    # add language parameter to each macro
+    $dmfile =~ s/(\n\s*)(_[^_]*_)\s*(\[[^\]]*\])?\s*\{/$1 . &add_language_param ($2, $3)/esg;
+    
+    print $output $dmfile;
+}
+
+sub process_image {
+    my ($text, $image_type, $image_name, $image_macros) = @_;
+
+    my $origtext = $text;
+
+    $text =~ s/&(\d{3,4});/chr($1)/ge;
+    $text =~ s/&([^;]*);/$rmap{$1}/g;
+
+    # Default font is set by the individual scripts (flash_button-1.2.pl etc), usually lucida
+    my $fontchoice = "";
+
+    # special case for Kazakh images (can also handle Russian) - encode to match Kazakh font
+    if ($language_symbol eq "kz") {  # || $language_symbol eq "ru") {
+	$text = &unicode::unicode2singlebyte(&unicode::utf82unicode($text), "kazakh");
+	$fontchoice = " -foundry 2rebels -fontname \"helv kaz\"";
+    }
+    # special case for Russian images - font is koi8-r encoded
+    elsif ($language_symbol eq "ru") {
+	$text = &unicode::unicode2singlebyte(&unicode::utf82unicode($text), "koi8_r");
+	$fontchoice = " -foundry cronyx -fontname helvetica";
+    }
+    # special case for Thai images
+    elsif ($language_symbol eq "th") {
+	$text = &unicode::unicode2singlebyte(&unicode::utf82unicode($text), "windows_874");
+	$fontchoice = " -foundry monotype -fontname BrowalliaUPC -fontregistry tis620";
+    }
+    # special case for Ukrainian images - font is windows_1251 encoded 
+    elsif ($language_symbol eq "uk") {
+	$text = &unicode::unicode2singlebyte(&unicode::utf82unicode($text), "windows_1251");
+	$fontchoice = " -foundry rfx -fontname serene";
+    }
+
+    # edit image macros
+    $image_macros =~ s/(_httpimg_\/)(?:[^\/\}]*\/)?([^\}]*\.(?:gif|jpe?g|png))/$1$language_symbol\/$2/gs;
+
+    if ($image_type eq "top_nav_button") {
+
+	# generate images
+	my $options = "-text \"$text\" -filenamestem $image_name -image_dir $image_dir";
+	$options .= " -height 20 -whitespace";
+	$options .= $fontchoice;
+
+	# special case for Kazakh images (can also handle Russian)
+	if ($language_symbol eq "kz") {  # || $language_symbol eq "ru") {
+	    $options .= " -fontsize 10 -fontweight bold";
+	}
+	# special case for Russian images
+	elsif ($language_symbol eq "ru") {
+	    $options .= " -fontsize 10 -fontweight bold";
+	}
+	# special case for Thai images
+	elsif ($language_symbol eq "th") {
+	    $options .= " -fontsize 20 -fontweight bold";  # Browallia
+	}
+	# special case for Ukrainian images
+	elsif ($language_symbol eq "uk") {
+	    $options .= " -fontsize 10";
+	}
+	else {
+	    $options .= " -fontsize 12";
+	}
+	`$ENV{'GSDLHOME'}/bin/script/gimp/flash_button-1.2.pl $options`;
+
+	# get width of new images and edit width macro
+	# my $fullfilename = &util::filename_cat ($image_dir, "${image_name}on.gif");
+	# &process_width_macro ($fullfilename, $image_name, \$image_macros);
+
+    }
+    elsif ($image_type eq "nav_bar_button") {
+
+	# generate on and off images
+	my $options = "-text \"$text\" -filenamestem $image_name -image_dir $image_dir";
+	$options .= " -height 17 -fixed_width -width 87";
+	$options .= $fontchoice;
+
+	# special case for Thai images
+	if ($language_symbol eq "th") {
+	    $options .= " -fontsize 18 -fontweight bold";  # Browallia
+	}
+	else {
+	    $options .= " -fontsize 17";
+	}
+
+	`$ENV{'GSDLHOME'}/bin/script/gimp/flash_button-1.2.pl $options`;
+
+	# generate green image
+	$options = "-text \"$text\" -filenamestem ${image_name}gr -image_dir $image_dir";
+	$options .= " -height 17 -fixed_width -width 87";
+	$options .= " -bgcolor \"#96c19b\"";
+	$options .= $fontchoice;
+
+	# special case for Thai images
+	if ($language_symbol eq "th") {
+	    $options .= " -fontsize 18 -fontweight bold";  # Browallia
+	}
+	else {
+	    $options .= " -fontsize 17";
+	}
+
+	`$ENV{'GSDLHOME'}/bin/script/gimp/flash_button-1.2.pl $options`;
+
+	# delete the unused light image
+	unlink(util::filename_cat($image_dir, "${image_name}gr" . "of.gif"));
+
+	# rename the dark image
+	&util::mv(util::filename_cat($image_dir, "${image_name}gr" . "on.gif"),
+		util::filename_cat($image_dir, "$image_name" . "gr.gif"));
+
+	# get width of new images and edit width macro
+	my $fullfilename = &util::filename_cat ($image_dir, "${image_name}on.gif");
+	&process_width_macro ($fullfilename, $image_name, \$image_macros);
+
+    }
+    elsif ($image_type eq "document_button") {
+
+	# generate on and off images
+	my $options = "-text \"$text\" -filenamestem $image_name -image_dir $image_dir";
+	$options .= " -fixed_width -whitespace";
+	$options .= $fontchoice;
+
+	# special case for Kazakh images (can also handle Russian)
+	if ($language_symbol eq "kz") {  # || $language_symbol eq "ru") {
+	    $options .= " -fontsize 8";
+	}
+	# special case for Russian images
+	elsif ($language_symbol eq "ru") {
+	    $options .= " -fontsize 8";
+	}
+	# special case for Thai images
+	elsif ($language_symbol eq "th") {
+	    $options .= " -fontsize 22 -fontweight bold";  # Browallia
+	}
+	# special case for Ukrainian images
+	elsif ($language_symbol eq "uk") {
+	    $options .= " -fontsize 8";
+	}
+	`$ENV{'GSDLHOME'}/bin/script/gimp/flash_button-1.2.pl $options`;
+
+	# get width of new images and edit width macro
+	# my $fullfilename = &util::filename_cat ($image_dir, "${image_name}on.gif");
+	# &process_width_macro ($fullfilename, $image_name, \$image_macros);
+
+    }
+    elsif ($image_type eq "collector_bar_button") {
+
+	$text =~ s/\\n/\n/g;
+	if ($text !~ /\n/) {
+	    # Format the text so it is centered, one word per line
+	    local @textparts = split(/[ \t\n]+/, $text);
+	    local $maxlength = 0;
+	    for ($i = 0; $i < scalar(@textparts); $i++) {
+		if (length($textparts[$i]) > $maxlength) {
+		    $maxlength = length($textparts[$i]);
+		}
+	    }
+	    $text = "";
+	    for ($i = 0; $i < scalar(@textparts); $i++) {
+		if (length($textparts[$i]) < $maxlength) {
+		    $text .= ' ' x ((($maxlength - length($textparts[$i])) / 2) + 1);
+		}
+		$text .= $textparts[$i] . "\n";
+	    }
+	}
+
+	# generate on and off images (yellow)
+	my $options = "-text \"$text\" -filenamestem yc$image_name -image_dir $image_dir";
+	$options .= " -width 77 -height 26 -fixed_width -whitespace -fontsize 13";
+	$options .= $fontchoice;
+
+	`$ENV{'GSDLHOME'}/bin/script/gimp/flash_button-1.2.pl $options`;
+
+	# generate on and off images (green)
+	$options = "-text \"$text\" -filenamestem gc$image_name -image_dir $image_dir";
+	$options .= " -width 77 -height 26 -fixed_width -whitespace -fontsize 13";
+	$options .= " -bgcolor \"#96c19b\"";
+	$options .= $fontchoice;
+
+	`$ENV{'GSDLHOME'}/bin/script/gimp/flash_button-1.2.pl $options`;
+
+	# generate on and off images (grey) - only the light image (off) is used
+	$options = "-text \"$text\" -filenamestem nc$image_name -image_dir $image_dir";
+	$options .= " -width 77 -height 26 -fixed_width -whitespace -fontsize 13";
+	$options .= " -bgcolor \"#7E7E7E\" -fontcolor \"#a0a0a0\"";
+	$options .= $fontchoice;
+
+	`$ENV{'GSDLHOME'}/bin/script/gimp/flash_button-1.2.pl $options`;
+
+	# delete the unused dark image
+	unlink(util::filename_cat($image_dir, "nc$image_name" . "on.gif"));
+
+    }
+    elsif ($image_type eq "green_bar_left_aligned") {
+
+	# generate green bar image (we're assuming these bars are always 537
+	# pixels and are never stretched by excess text
+	my $options = "-text \"$text\" -filename ${image_name}.gif -image_dir $image_dir";
+	$options .= " -dont_center -width 537 -width_space 15";
+	$options .= $fontchoice;
+
+	# special case for Thai images
+	if ($language_symbol eq "th") {
+	    $options .= " -fontsize 18 -fontweight bold";  # Browallia
+	}
+
+	`$ENV{'GSDLHOME'}/bin/script/gimp/green_bar-1.2.pl $options`;
+
+    }
+    elsif ($image_type eq "green_title") {
+	
+	# read the width if it is specified in $image_macros
+        my ($width) = $image_macros =~ /_width${image_name}x?_\s*[^\{]*\{(\d+)\}/;
+        $width = 200 unless ($width);
+
+        # generate green title image
+	my $options = "-text \"$text\" -filename ${image_name}.gif -image_dir $image_dir";
+	$options .= " -width $width -height 57 -stripe_alignment right -text_alignment right";
+        $options .= $fontchoice;
+
+        # special case for Thai images
+        if ($language_symbol eq "th") {
+	    $options .= " -fontsize 50 -fontweight bold";  # Browallia
+	}
+        else {
+	    $options .= " -fontsize 26 -fontweight bold";
+	}
+
+	`$ENV{'GSDLHOME'}/bin/script/gimp/title_icon-1.2.pl $options`;
+
+	# get width of resulting image and edit _width..._ macro in $image_macros
+        # (no longer needed since we always resize to the width read from $image_macros.)
+        # my $fullfilename = &util::filename_cat ($image_dir, "${image_name}.gif");
+	# &process_width_macro ($fullfilename, $image_name, \$image_macros);
+
+    }
+    elsif ($image_type eq "hand_made") {
+
+	$hand_made ++;
+
+    }
+    else {
+	
+	print STDERR "WARNING (translate.pl): unknown image type found ($image_type)\n";
+
+    }
+
+    return "\n\#\# \"$origtext\" \#\# $image_type \#\# $image_name \#\#$image_macros";
+}
+
+sub process_width_macro {
+    my ($filename, $image_name, $image_macros) = @_;
+
+    my $img_info = &get_img_info ($filename);
+    $$image_macros =~ s/(_width${image_name}x?_\s*(?:\[[^\]]*\])?\s*\{)(\d+)(\})/$1$img_info->{'width'}$3/s;
+}
+
+sub add_language_param {
+    my ($macroname, $paramlist) = @_;
+
+    my $first = 1;
+    if (defined $paramlist) {
+	$paramlist =~ s/^\[//;
+	$paramlist =~ s/\]$//;
+	my @params = split /\,/, $paramlist;
+	$paramlist = "";
+	foreach $param (@params) {
+	    # remove any existing language parameter
+	    if ($param !~ /^l=/) {
+		$paramlist .= "," unless $first;
+		$paramlist .= $param;
+		$first = 0;
+	    }
+	}
+    }
+    $paramlist .= "," unless $first;
+    $paramlist .= "l=" . $language_symbol;
+    return "$macroname [$paramlist] {";
+}
+
+sub get_img_info {
+    my ($imagefile) = @_;
+    my %info = ();
+
+    if (!-r $imagefile) {
+	print STDERR "ERROR (translate.pl): couldn't open $imagefile to get dimensions\n";
+	$info{'width'} = 0;
+	$info{'height'} = 0;
+    } else {
+	my $image = gimp_file_load (RUN_NONINTERACTIVE, $imagefile, $imagefile);
+	$info{'width'} = gimp_image_width ($image);
+	$info{'height'} = gimp_image_height ($image);
+    }
+
+    return \%info;
+}
+
+sub query {
+
+  gimp_install_procedure("gsdl_translate", "translate macro files and create images",
+                        "", "Stefan Boddie", "Stefan Boddie", "2000-03-14",
+                        "<Toolbox>/Xtns/gsdl_translate", "*", &PROC_EXTENSION,
+                        [[PARAM_INT32, "run_mode", "Interactive, [non-interactive]"]], []);
+}
+
+Gimp::on_net {   gsdl_translate; };
+exit main;
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/unbuildv1.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/unbuildv1.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/unbuildv1.pl	(revision 10506)
@@ -0,0 +1,745 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# unbuildv1.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# this program will decompress all the text from a built index
+# and return it to gml format - this version of the program is designed to
+# work on collections built with the first version of the greenstone software
+# it extracts the browse classifications from the gdbm file, and recreates 
+# them. It also creates a default collect.cfg file.
+
+# To run, this program needs the old archive directory (called archives),
+# the index directory with the text and one other index, not paragraphs!! -
+# use one of the section indexes. Also needs the build.cfg file (in the
+# index dir) - used in creating a collect.cfg file. If build.cfg is not
+# present, the parts of the collect.cfg file relating to indexes will not
+# be entered.
+
+# Stefan altered this script slightly August 2002 to use
+# $GSDLHOME/bin/$GSDLOS/mgquery_old instead of the old mgquery in
+# nzdl-1.2. mgquery_old is a statically linked binary compiled from
+# mg-1.3d. It was compiled with SHORT_SUFFIX set so doesn't need the index
+# file extensions to be altered. 
+# Also changed the command line options a little.
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    $FileHandle = 'FH000';
+}
+
+use doc;
+use docsave;
+use util;
+use parsargv;
+use FileHandle;
+use English;
+use cfgread;
+use unicode;
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+
+# globals
+$collection = "";  # the collection name
+$index = "";  # the selected index (like stt/unu)
+$textdir = ""; # the textdir (like text/unu)
+$toplevelinfo = []; #list of document OIDs
+%infodb = (); #hash into GDBM file
+$classifyinfo = []; # list of classifications
+$doc_classif_info = {};  # hash of OIDs->classifications they belong to
+$collect_cfg = {}; #data for the configuration file
+$mgread = ++$FileHandle;
+$mgwrite = ++$FileHandle;
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -old directory         The directory in which the old collection lives\n";
+    print STDERR "   -new directory         The directory in which to put the new collection\n";
+}
+
+&main ();
+
+sub main {
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'old/.*/', \$old,
+			 'new/.*/', \$new)) {
+	&print_usage();
+	die "\n";
+    }
+
+    die "$old does not exist\n\n" unless (-d $old);
+    my $old_indexdir = &util::filename_cat($old, "index");
+    my $old_archivedir = &util::filename_cat($old, "archives");
+
+    my $new_archivedir = &util::filename_cat($new, "archives");
+    my $new_etcdir = &util::filename_cat($new, "etc");
+    if (!-e $new_archivedir) {
+	&util::mk_all_dir($new_archivedir);
+    }
+    if (!(-d $new_etcdir)) {
+	&util::mk_all_dir($new_etcdir);
+    }
+
+    my $gdbmfile = &get_gdbmfile($old_indexdir); # sets $collection and $textdir
+    &set_index($old_indexdir);  # sets $index (just chooses one index)
+
+    my $buildcfgfile = &util::filename_cat($old_indexdir, "build.cfg");
+    my $colcfgfile = &util::filename_cat($new_etcdir, "collect.cfg");
+
+    # don't need this but giving it a value stops an annoying undefined
+    # value warning
+    $ENV{'GSDLCOLLECTDIR'} = 'tmp';
+
+    &add_default_cfg();
+    &add_index_cfg($buildcfgfile);
+
+    # work out all the classifications from the gdbm file, info for each doc
+    # (ie which classifications they belong to, are kept in $doc_classif_info
+    &get_classifyinfo($gdbmfile); #puts a list of classifications into classifyinfo
+    &get_toplevel_OID($gdbmfile); # puts a list of the top level document OIDs into $toplevelinfo
+
+    # read ldb file into %infodb
+    &read_gdbm($gdbmfile);
+
+    #this makes the files specifying the hierarchy of subjects, titles etc
+    foreach my $classify (@$classifyinfo) {
+	&make_info_file($new_etcdir, $classify);
+    }
+    
+    # write out the collect.cfg
+    &output_cfg_file($colcfgfile);
+
+    &openmg($old_indexdir);
+
+    # read the archive information file
+    my $archive_info_filename = &util::filename_cat ($new_archivedir, "archives.inf");
+    my $archive_info = new arcinfo ();
+
+    # create a docsave object to process the documents
+    my $processor = new docsave ("", $archive_info, $verbosity);
+    $processor->setarchivedir ($new_archivedir);
+
+    my ($doc_obj, $hashref, $children);
+    print STDERR "processing documents now\n" if $verbosity >=2;
+    foreach $oid (@$toplevelinfo) {
+	$value = $infodb{$oid};
+	$hashref={};
+	$children = [];
+	&get_metadata($value, $hashref);
+	$doc_obj = new doc ();
+	$doc_obj->set_OID($oid);
+	my ($olddir) = $hashref->{'archivedir'}; # old dir for this doc, where images are stored
+	$top = $doc_obj->get_top_section();
+	&add_section_content ($doc_obj, $top, $hashref, $olddir);
+	&add_classification_metadata($oid, $doc_obj, $top);
+	&add_cover_image($doc_obj, $old_archivedir, $olddir);
+	&get_children($hashref, $children);
+	&recurse_sections($doc_obj, $children, $oid, $top, $olddir) if (defined ($children));
+
+	#change OID to new format
+	$doc_obj->delete_OID();
+	$doc_obj->set_OID();
+	$processor->process($doc_obj);
+#	last;
+    }
+    print STDERR "\n";
+   
+    &closemg();
+
+    # write out the archive information file
+    $archive_info->save_info($archive_info_filename);
+   
+    
+}
+
+# returns the path to the gdbm info database - also
+# sets the $collection and $textdir global variable
+sub get_gdbmfile {
+    my ($indexdir) = @_;
+    my ($gdbmfile);
+
+    opendir (DIR, $indexdir) || die "Couldn't open directory $indexdir\n\n";
+    my @conts = readdir DIR;
+    close DIR;
+
+    foreach $file (@conts) {
+	if ($file =~ /text$/) {
+	    $textdir = $file;
+	    last;
+	}
+    }
+    die "No text directory found in $indexdir\n\n" 
+	unless defined $textdir && $textdir =~ /text$/;
+
+    $gdbmfile = &util::filename_cat ($indexdir, $textdir);
+
+    opendir (DIR, $gdbmfile) || die "Couldn't open directory $gdbmfile\n\n";
+    @conts = readdir DIR;
+    close DIR;
+
+    foreach my $file (@conts) {
+	if ($file =~ /^(.*?)\.(?:ldb|bdb)$/) {
+	    $collection = $1;
+	    $gdbmfile = &util::filename_cat ($gdbmfile, $file);
+	    last;
+	}
+    }
+    
+    if (defined $collection && $collection =~ /\w/) {
+	$textdir = &util::filename_cat ($textdir, $collection);
+    } else {
+	die "collection global wasn't set\n";
+    }
+    return $gdbmfile if (-e $gdbmfile);
+    die "Couldn't find gdbm info database in $indexdir\n\n";
+}
+
+
+#this function will probably need to be changed for any different file formats
+sub get_toplevel_OID {
+    my ($gdbmfile) = @_;
+
+    open (DB2TXT, "db2txt $gdbmfile |") || die "couldn't open pipe to db2txt\n";
+    print STDERR "Finding all top level sections from $gdbmfile\n" if $verbosity >= 2;
+
+    $/ = '-' x 70;
+    my $entry = "";
+    while (defined ($entry = <DB2TXT>)) {
+	next unless $entry =~ /\w/;  #ignore blank entries
+	$entry =~ s/\n+/\\n/g;  # replace multiple \n with single \n
+	my ($key, $value) = $entry =~ /\[([^\]]*)\](.*)/;
+
+	next unless ($key =~ /B\.\d*$/); # assumes top level OID is like
+	                                 # B.12
+
+	push( @$toplevelinfo, $key);
+   
+    }
+
+    $/ = "\n";
+}
+    
+# gets all the metadata from a gdbm file entry, and puts it into a hashref
+#this has changed for old style formats
+sub get_metadata {
+
+    my ($gdb_str_ref, $hashref) = @_;
+#    print STDERR $gdb_str_ref;
+    my @entries = split(/\n/, $gdb_str_ref);
+
+    my $hastext = 1;
+    foreach $entry (@entries) {
+	
+	my($key, $value) = ($entry =~ /^<([^>]*)>(.*?)$/ );
+
+	next if ($key eq "p");
+	next if ($key eq "j");
+	
+	$key = "Title" if $key eq "t";
+	$key = "docnum" if $key eq "d";	
+	if ($key eq "o") {
+	    $key = "archivedir";
+	    $value =~ s/HASH/hash/;
+	}
+	if ($key eq "c") {
+	    $key = "contains";
+	    $hastext=0;}
+
+	$$hashref{$key} .= $value;
+						  
+    }
+    
+    $$hashref{'hastxt'} = $hastext;
+
+}					  
+
+# takes a hashref containing the metadata for a gdbmfile entry, and
+# extracts the childrens numbers (from the 'contains' entry).  assumes
+# format is like B.14.1:B.24.2:B.24.3 returns a list like 1 2 3 4
+sub get_children {	
+    my ($hashref, $children) = @_; 
+
+    my $childs = $hashref->{'contains'};
+    if (defined ($childs)) {
+	@xchildren = split /\:/, $childs;
+	foreach $kid (@xchildren) {
+	    my ($child)= $kid =~ /\.([^\.]*)(?:\\n|$)/;
+	    push (@$children, $child);
+	}
+#	print STDERR "children are: ", @$children;
+    }
+    else {
+	$children = [];
+    }
+}
+
+#takes a hashref containing the metadata for a gdbmfile entry, and extracts 
+#the childrens numbers (from the 'contains' entry).	
+#assumes format is like B.14.1:B.24.2:B.24.3
+#returns a list with the full child name ie B.14.1 B.14.2 etc
+#used for classification stuff
+sub get_whole_children {	
+
+    my ($hashref, $children) = @_; 
+
+    my $childs = $hashref->{'contains'};
+    if (defined ($childs)) {
+	@$children = split /\:/, $childs;
+	#print STDERR "children are: ", @$children;
+    }
+    else {
+	$children = [];
+    }
+}
+    
+sub recurse_sections {
+    my ($doc_obj, $children, $parentoid, $parentsection, $olddir) = @_;
+
+    foreach $child (sort numerically @$children) {
+	$doc_obj->create_named_section("$parentsection.$child");
+	my $value = $infodb{"$parentoid.$child"};
+	my $hashref={};
+	&get_metadata($value, $hashref); # get childs metadata
+	my $newchildren = [];
+	&get_children($hashref, $newchildren); # get childs children
+	#add content fo rcurrent section
+	&add_section_content($doc_obj, "$parentsection.$child", $hashref, $olddir);
+	# process all the children if there are any
+	&recurse_sections($doc_obj, $newchildren, "$parentoid.$child", "$parentsection.$child", $olddir)
+	    if (defined ($newchildren));
+    }
+}					     
+
+sub add_section_content {
+    my ($doc_obj, $cursection, $hashref, $olddir) = @_;
+    
+    foreach $key (keys %$hashref) {
+	#dont need to store these metadata
+	next if $key =~ /(contains|docnum|hastxt|doctype|archivedir|classifytype)/i;
+	my @items = split /@/, $hashref->{$key};
+	map {$doc_obj->add_metadata ($cursection, $key, $_); } @items;
+	
+    }
+
+    my ($hastext) = $hashref->{'hastxt'} =~ /(0|1)/;
+    if ($hastext) {
+	
+	my ($docnum)= $hashref->{'docnum'} =~ /(\d*)/;
+	my $text = &get_text($docnum);
+	$doc_obj->add_text ($cursection, $text);
+	
+	my (@images) = $text =~ /<img.*?src=\"([^\"]*)\"[^>]*>/g;
+	
+	if (scalar(@images)>0) {
+	    
+	    foreach $img (@images) {
+		my ($assoc_file) = $img =~ /([^\/\\]*\..*)$/; #the name of the image
+		$img =~ s/_httpcollection_/$old/; #replace _httpcollection_ with path to old collection
+		$olddir =~ s/HASH/hash/;
+		$img =~ s/_thisOID_/$olddir/; #replace _thisOID_ with old archivedir name   #the path to the image
+		$img = lc $img; # doc names and path upper case in file, lower
+		# case in directory
+		if (-e $img) {
+		    $doc_obj->associate_file($img, $assoc_file);
+		} else {
+		    print STDERR "WARNING: $img does not exist\n";
+		}
+	    }
+	    
+	}
+    }
+}
+
+
+sub add_classification_metadata {
+
+    my ($oid, $doc_obj, $cursection) = @_;
+    
+    if (defined $doc_classif_info->{$oid}) {
+
+	$hashref = $doc_classif_info->{$oid};
+	
+	foreach $key (keys %$hashref) {
+	    my @items = @{$hashref->{$key}};
+	    map {$doc_obj->add_metadata ($cursection, $key, $_); } @items;
+	}
+    }
+}
+# picks up the cover image "cover.jpg" from the old archives directory.
+sub add_cover_image {
+    my ($doc_obj, $archivedir, $olddir) =  @_;
+    $assoc_file = "cover.jpg";
+    $img = &util::filename_cat($archivedir, $olddir, $assoc_file);
+
+    if (-e $img) {
+	$doc_obj->associate_file($img, $assoc_file);
+    } else {
+	print STDERR "WARNING: couldn't find $img\n";
+    }
+}
+
+sub set_index {
+    my ($indexdir) = @_;
+
+    # check that $collection has been set
+    die "collection global was not set\n"
+	unless defined $collection && $collection =~ /\w/;
+
+    # find an index (just use first non-text and non-paragraph directory we
+    # come across in $indexdir)
+    opendir (INDEXDIR, $indexdir) || die "couldn't open directory $indexdir\n";
+    my @indexes = readdir INDEXDIR;
+    close INDEXDIR;
+    foreach $i (@indexes) {
+	next if $i =~ /text$/i || $i =~ /\./ || $i =~ /^p/i;
+	$index = &util::filename_cat ($i, $collection);
+	last;
+    }
+}
+
+
+#########################################################################
+
+################ functions involving mg ################################
+sub get_text {
+    my ($docnum) = @_;
+
+    print STDERR "." if $verbosity >= 2;
+    &mgcommand ($docnum);
+
+   <$mgread>;	# eat the document separator
+
+    my $text = "";
+    my $line = "";
+
+    while (defined ($line = <$mgread>))
+    {
+	last if $line =~ /^<\/mg>/;
+	$text .= $line;
+    }
+
+    # Read in the last statement, which should be:
+    #  "dd documents retrieved."
+    <$mgread>;
+
+    return $text;
+}
+
+
+sub numerically {$a <=> $b;}
+
+
+
+# mg stuff
+
+sub openmg {
+    my ($indexdir) = @_;
+
+    die "Unable to start mgquery." unless
+	&openpipe($mgread, $mgwrite, "mgquery_old -d $indexdir -f $index -t $textdir");
+
+    $mgwrite->autoflush();
+    &mgcommand('.set expert true');
+    &mgcommand('.set terminator "</mg>\n"');
+    &mgcommand('.set mode text');
+    &mgcommand('.set query docnums');
+    &mgcommand('.set term_freq off');
+}
+
+sub closemg {
+    &mgcommand (".quit");
+    close($mgread);
+    close($mgwrite);
+}
+
+sub mgcommand {
+    my ($command) = @_;
+
+    return if $command =~ /^\s*$/;  #whitespace
+    #print STDERR "command: $command\n";
+    print $mgwrite "$command\n";
+
+    # eat up the command executed which is echoed
+    <$mgread>;
+}
+
+# openpipe(READ, WRITE, CMD)
+# 
+# Like open2, except CMD's stderr is also redirected.
+# 
+sub openpipe
+{
+    my ($read, $write, $cmd) = @_;
+    my ($child_read, $child_write);
+
+    $child_read = ++$FileHandle;
+    $child_write = ++$FileHandle;
+
+    pipe($read, $child_write) || die "Failed pipe($read, $child_write): $!";
+    pipe($child_read, $write) || die "Failed pipe($child_read, $write): $!";
+    my $pid;
+
+    if (($pid = fork) < 0) {
+        die "Failed fork: $!";
+    } elsif ($pid == 0) {
+        close($read);
+        close($write);
+        open(STDIN, "<&$child_read");
+        open(STDOUT, ">&$child_write");
+        open(STDERR, ">&$child_write");
+        exec($cmd);
+        die "Failed exec $cmd: $!";
+    }
+
+    close($child_read);
+    close($child_write);
+
+    $write->autoflush();
+    $read->autoflush();
+
+    return 1;
+}
+
+
+######################################################################
+
+############# functions to do with the classificaiton stuff ##########
+sub get_classifyinfo {
+    my ($gdbmfile) = @_;
+
+    open (DB2TXT, "db2txt $gdbmfile |") || die "couldn't open pipe to db2txt\n";
+    print STDERR "Finding all classification sections from $gdbmfile\n" ;
+
+    $/ = '-' x 70;
+    my $entry = "";
+    while (defined ($entry = <DB2TXT>)) {
+	next unless $entry =~ /\w/;  #ignore blank entries
+	$entry =~ s/\n+/\\n/g;  # replace multiple \n with single \n
+	my ($key, $value) = $entry =~ /\[([^\]]*)\](.*)/;
+
+	next unless ($key =~/^[A-Z]$/); # assumes classification OID is like
+	                                 # C or T etc
+
+	push( @$classifyinfo, $key);
+   
+    }
+
+    $/ = "\n";
+}
+
+#this creates the classification files needed for the hierarchy classifier
+#used for subjects, titles, orgs etc
+#also adds in entries to the collect_cfg hash    
+sub make_info_file {
+    my ($etcdir, $classifier) = @_;
+    my $info_file = "";
+
+    $info_file = &util::filename_cat($etcdir, "CL.${classifier}.txt");
+    $classifier_name = "CL.$classifier";
+    print STDERR "classification $classifier will be called CL.$classifier\n";
+
+    open (OUTDOC, ">$info_file" ) || die  "couldn't open file $info_file\n";
+	
+    my $entry = $infodb{$classifier};
+    #print STDERR "entry = $entry\n";
+    my $hashref = {};
+    &get_metadata($entry, $hashref);
+    my $children=[];
+    &get_whole_children($hashref, $children);
+    foreach $child (@$children) {
+	&process_entry(OUTDOC, $classifier_name, $child);
+    }
+  
+    close OUTDOC;
+    
+    &add_classify_cfg($classifier, $classifier_name, $info_file);
+    
+}
+
+
+sub process_entry {
+    my ($handle, $classifier_name, $classify_id) = @_;
+
+    my $value = $infodb{$classify_id};
+    my $hashref={};
+    &get_metadata($value, $hashref);
+    my $title = $hashref->{'Title'};
+
+    &add_line($handle, $classify_id, $title);
+    
+    my $children = [];
+    &get_whole_children($hashref, $children);
+    foreach $child (@$children) {
+	if (&is_document($child)) {
+	    &add_doc_metadata($child, $classifier_name, $classify_id);
+	}
+	else {
+	    &process_entry($handle, $classifier_name, $child);
+	}
+    }
+}
+
+sub add_doc_metadata {
+    my ($doc_id, $classifier_name, $classifier_id) = @_;
+
+    #add entry to doc database
+    #print STDERR "at doc level, docnum=$classify_id\n";
+    $doc_classif_info->{$doc_id}={} unless defined $doc_classif_info->{$doc_id};
+    $doc_classif_info->{$doc_id}->{$classifier_name}=[] unless
+	defined $doc_classif_info->{$doc_id}->{$classifier_name};
+    push (@{$doc_classif_info->{$doc_id}->{$classifier_name}}, $classifier_id); 
+}
+
+sub add_line {
+    my ($handle, $classify_id, $title) = @_;
+    $title = &unicode::ascii2utf8(\$title);
+    my ($num) = $classify_id =~ /^[A-Z]\.(.*)$/; #remove the C. from the front
+    print $handle "$classify_id\t$num\t\"$title\"\n";
+}
+
+sub is_document {
+    my ($oid) = @_;
+    return 1 if $oid =~ /^B\.\d/;
+    return 0;
+}
+    
+########################################################################
+
+########## stuff for producing collect.cfg file ###########################
+
+sub add_default_cfg {
+
+    $username=`whoami`;
+    $username=`logname` unless defined $username;
+    $username="a_user" unless defined $username;
+    $username =~ s/\n//;
+    $collect_cfg->{'creator'}="$username\@cs.waikato.ac.nz";
+    $collect_cfg->{'maintainer'}="$username\@cs.waikato.ac.nz";
+    $collect_cfg->{'public'}="true";
+    
+    $collect_cfg->{'plugin'}=[];
+    push (@{$collect_cfg->{'plugin'}}, ["GAPlug"]);
+    push (@{$collect_cfg->{'plugin'}}, ["ArcPlug"]);
+    push (@{$collect_cfg->{'plugin'}}, ["RecPlug"]);
+
+    $collect_cfg->{'format'}={};
+    $collect_cfg->{'format'}->{'DocumentImages'}="true";
+    $collect_cfg->{'format'}->{'DocumentText'} = 
+	"\"<h3>[Title]</h3>\\\\n\\\\n<p>[Text]\"";
+    $collect_cfg->{'format'}->{'SearchVList'} =
+	"\"<td valign=top>[link][icon][/link]</td><td>{If}{[parent(All': '):Title],[parent(All': '):Title]:}[link][Title][/link]</td>\"";
+
+    $collect_cfg->{'collectionmeta'}={};
+    $collect_cfg->{'collectionmeta'}->{'collectionname'}="\"$collection\"";
+    $collect_cfg->{'collectionmeta'}->{'iconcollection'}="\"_httpprefix_/collect/$collection/images/$collection.gif\"";
+    $collect_cfg->{'collectionmeta'}->{'iconcollectionsmall'}="\"_httpprefix_/collect/$collection/images/${collection}sm.gif\"";
+    $collect_cfg->{'collectionmeta'}->{'collectionextra'} = "\"This is a collection rebuilt from CDROM.\"";
+
+}
+
+sub add_index_cfg {
+  my ($buildfile) = @_;
+
+  my $data={};
+  $collect_cfg->{'indexes'}=[];
+  if (-e $buildfile) {
+      $data=&cfgread::read_cfg_file($buildfile, '^(this)$', '^(indexmap)$'); 
+      foreach my $i (@{$data->{'indexmap'}}) {
+          my ($thisindex, $abbrev)= split (/\-\>/, $i);
+          push (@{$collect_cfg->{'indexes'}}, $thisindex);
+	  $collect_cfg->{'defaultindex'} = $thisindex unless defined 
+	      $collect_cfg->{'defaultindex'};
+          $name=&get_index_name($thisindex);
+	  $thisindex=".$thisindex";
+          $collect_cfg->{'collectionmeta'}->{$thisindex} = "\"$name\"";
+      } 
+  }
+  else {
+      print STDERR "Couldn't read $buildfile, could not add index data to configuration file\n";
+  }
+
+}
+
+sub get_index_name {
+    my ($thisindex) = @_;
+    return "paragraphs" if $thisindex =~ /paragraph/;
+    return "chapters" if $thisindex =~ /section.*text/;
+    return "titles" if $thisindex =~ /Title/;
+    return "other";
+}
+
+sub add_classify_cfg {
+
+    my ($classify, $metadata, $file) = @_;
+    $collect_cfg->{'classify'} = [] unless defined $collect_cfg->{'classify'};
+
+    my ($title);
+    $title = "Howto" if $classify eq 'H';
+    $title = "Subject" if $classify eq 'C';
+    $title = "Organization" if $classify eq 'O';
+    $title = "Title" if $classify eq 'T';
+    $title = "Other" unless defined $title;
+
+    my ($filename) = $file =~ /\/([^\/]*)$/;
+    my $entry = "Hierarchy -hfile $filename -metadata $metadata -buttonname $title -sort Title";
+    $entry .= " -hlist_at_top" if $title eq "Title";
+    push (@{$collect_cfg->{'classify'}},[$entry]);
+   
+
+}
+
+sub output_cfg_file {
+
+    my ($collfile) = @_;
+    &cfgread::write_cfg_file($collfile, $collect_cfg, 
+			     '^(creator|maintainer|public|beta|defaultindex)$',
+                            '^(indexes)$', '^(format|collectionmeta)$',
+                            '^(plugin|classify)$');
+}
+
+sub read_gdbm {
+    my ($filename) = @_;
+
+    open (PIPEIN, "db2txt \"$filename\" |") || die "couldn't open pipe from db2txt\n";
+    my $line = ""; my $key = ""; my $value = "";
+    while (defined ($line = <PIPEIN>)) {
+	if ($line =~ /^\[([^\]]+)\]$/) {
+	    $key = $1;
+	} elsif ($line =~ /^-{70}$/) {
+	    $infodb{$key} = $value;
+	    $value = "";
+	    $key = "";
+	} else {
+	    $value .= $line;
+	}
+    }
+    close PIPEIN;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/unbuildv2.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/unbuildv2.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/unbuildv2.pl	(revision 10506)
@@ -0,0 +1,786 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# unbuildv2.pl --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# this program will decompress all the text from a built index
+# and return it to gml format -
+#this is based on the format current in Nov 1999. (version two)
+
+# Stefan updated unbuildv1.pl in August 2002 but unbuildv2.pl was not
+# updated. It probably needs some work done before using.
+
+# Katherine updated this but apparently it still doesn't work.
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    $FileHandle = 'FH000';
+}
+
+use unbuildutil;
+use doc;
+use docsave;
+use util;
+use parsargv;
+use GDBM_File;
+use FileHandle;
+use English;
+use cfgread;
+use unicode;
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+
+# globals
+$collection = "";  # the collection name
+$index = "";  # the selected index (like stt/unu)
+$textdir = ""; # the textdir (like text/unu)
+$toplevelinfo = []; #list of document OIDs
+%infodb = (); #hash into GDBM file
+$classifyinfo = []; # list of classifications
+$doc_classif_info = {};  # hash of OIDs->classifications they belong to
+$collect_cfg = {}; #data for the configuration file
+
+$mgread = ++$FileHandle;
+$mgwrite = ++$FileHandle;
+
+
+
+sub print_usage {
+    print STDERR "\n  usage: $0 [options]\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -indexdir directory    The index to be decompressed (defaults to ./index)\n";
+    print STDERR "   -archivedir directory  Where the converted material ends up (defaults to ./archives.new\n";
+    print STDERR "   -removeold             Will remove the old contents of the archives\n";
+    print STDERR "                          directory -- use with care\n\n";
+}
+
+&main ();
+
+sub main {
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'indexdir/.*/index', \$indexdir,
+			 'archivedir/.*/archives.new', \$archivedir,
+			 'removeold', \$removeold)) {
+	&print_usage();
+	die "\n";
+    }
+
+    die "indexdir $indexdir does not exist\n\n" unless (-d $indexdir);
+    $indexdir =~ s/\/$//;
+    if (-d $archivedir) {
+	if ($removeold) {
+	    print STDERR "Warning - removing current contents of the archives directory $archivedir\n";
+	    print STDERR "          in preparation for the import\n";
+	    sleep(5); # just in case...
+	    &util::rm_r ($archivedir);
+	}
+    } else {
+	&util::mk_all_dir ($archivedir);
+    }
+
+    $etcdir = "./etc";
+    if (!(-d $etcdir)) {
+	&util::mk_all_dir ($etcdir);
+    }
+
+
+    my $gdbmfile = &get_gdbmfile ($indexdir); #sets $collection and $textdir
+    &set_index ();  # sets $index (just chooses one index)
+
+
+    my $buildcfgfile = &util::filename_cat($indexdir, "build.cfg");
+    my $colcfgfile = &util::filename_cat($etcdir, "collect.cfg");
+
+    &add_default_cfg();
+    &add_index_cfg($buildcfgfile);
+
+
+    #work out all the classifications from the gdbm file, info for each doc
+#(ie which classifications they belong to, are kept in $doc_classif_info
+    &get_classifyinfo ($gdbmfile); #puts a list of classifications into classifyinfo
+
+    &get_toplevel_OID ($gdbmfile); # puts a list of the top level document OIDs into $toplevelinfo
+
+    #tie (%infodb, "GDBM_File", $gdbmfile, 1, 0);
+    
+    #read ldb file into %infodb
+    &unbuildutil::read_gdbm($gdbmfile, \%infodb);
+
+    #this makes the files specifying the hierarchy of subjects, titles etc
+    foreach $classify (@$classifyinfo) {
+	
+	&make_info_file($classify);
+
+    }
+
+    
+    #write out the collect.cfg
+    &output_cfg_file($colcfgfile);
+
+    &openmg ();
+
+    # read the archive information file
+    my $archive_info_filename = &util::filename_cat ($archivedir, "archives.inf");
+    my $archive_info = new arcinfo ();
+
+    # create a docsave object to process the documents
+    my $processor = new docsave ("", $archive_info, $verbosity);
+    $processor->setarchivedir ($archivedir);
+
+    my ($doc_obj, $hashref, $children);
+    print STDERR "processing documents now\n" if $verbosity >=2;
+    foreach $oid (@$toplevelinfo) {
+	$value = $infodb{$oid};
+	$hashref={};
+	$children = [];
+	&get_metadata($value, $hashref);
+	$doc_obj = new doc ();
+	$doc_obj->set_OID($oid);
+	my ($olddir) = $hashref->{'archivedir'}; # old dir for this doc, where images are stored
+	$top = $doc_obj->get_top_section();
+	&add_section_content ($doc_obj, $top, $hashref, $olddir);
+	&add_classification_metadata($oid, $doc_obj, $top);
+	&add_cover_image($doc_obj, $olddir);
+	&get_children($hashref, $children);
+	&recurse_sections($doc_obj, $children, $oid, $top, $olddir);
+	$processor->process($doc_obj);
+	
+    }
+    print STDERR "\n";
+   
+    &closemg();
+
+    # write out the archive information file
+    $archive_info->save_info($archive_info_filename);
+}
+
+# returns the path to the gdbm info database - also
+# sets the $collection and $textdir global variable
+sub get_gdbmfile {
+    my ($indexdir) = @_;
+    my ($gdbmfile);
+
+    opendir (DIR, $indexdir) || die "Couldn't open directory $indexdir\n\n";
+    my @conts = readdir DIR;
+    close DIR;
+
+    foreach $file (@conts) {
+	if ($file =~ /text$/) {
+	    $textdir = $file;
+	    last;
+	}
+    }
+    die "No text directory found in $indexdir\n\n" 
+	unless defined $textdir && $textdir =~ /text$/;
+
+    $gdbmfile = &util::filename_cat ($indexdir, $textdir);
+
+    opendir (DIR, $gdbmfile) || die "Couldn't open directory $gdbmfile\n\n";
+    @conts = readdir DIR;
+    close DIR;
+
+    foreach $file (@conts) {
+	if ($file =~ /^(.*?)\.(?:ldb|bdb)$/) {
+	    $collection = $1;
+	    $gdbmfile = &util::filename_cat ($gdbmfile, $file);
+	    last;
+	}
+    }
+    
+    if (defined $collection && $collection =~ /\w/) {
+	$textdir = &util::filename_cat ($textdir, $collection);
+    } else {
+	die "collection global wasn't set\n";
+    }
+    return $gdbmfile if (-e $gdbmfile);
+    die "Couldn't find gdbm info database in $indexdir\n\n";
+}
+
+
+sub get_toplevel_OID {
+    my ($gdbmfile) = @_;
+
+    open (DB2TXT, "db2txt $gdbmfile |") || die "couldn't open pipe to db2txt\n";
+    print STDERR "Finding all top level sections from $gdbmfile\n" if $verbosity >= 2;
+
+    $/ = '-' x 70;
+    my $entry = "";
+    while (defined ($entry = <DB2TXT>)) {
+	next unless $entry =~ /\w/;  #ignore blank entries
+	$entry =~ s/\n+/\\n/g;  # replace multiple \n with single \n
+	my ($key, $value) = $entry =~ /\[([^\]]*)\](.*)/;
+
+	next if ($key =~ /\./); #ignore any lower level entries
+	next if ($key =~ /^CL/); #ignore classification entries
+	next if ($value =~ /<section>/); #ignore docnum->OID entries
+	next if ($value =~ /<docoid>/); #ignore strange s133->OID entries
+	next if ($key !~ /\d/); #ignore collection, browse entries
+
+	push( @$toplevelinfo, $key);
+   
+    }
+
+    $/ = "\n";
+    #print STDERR "toplevel sections are: ", join ("\n", @$toplevelinfo);
+    #print STDERR "\n";
+}
+    
+# gets all the metadata from a gdbm file entry, and puts it into a hashref
+sub get_metadata {
+    
+    my ($gdb_str_ref, $hashref) = @_;
+    my @entries = split(/\n/, $gdb_str_ref);
+    foreach $entry (@entries) {
+	my($key, $value) = ($entry =~ /^<([^>]*)>(.*?)$/ );
+	$$hashref{$key} .= '@' if defined $$hashref{$key};
+	$$hashref{$key} .= $value;
+	
+    }
+   
+    
+}					  
+
+#takes a hashref containing the metadata for a gdbmfile entry, and extracts 
+#the childrens numbers (from the 'contains' entry).	
+#assumes format is ".1;".2;".3
+sub get_children {	
+    my ($hashref, $children) = @_; 
+
+    $childs = $hashref->{'contains'};
+    if (defined ($childs)) {
+	$childs =~ s/\@$//;  #remove trailing @
+	$childs =~ s/^\"\.//; #remove initial ".
+	@$children = split /\;\"\./, $childs;
+	
+    }
+    else {
+	  $children = [];
+      }
+}
+	
+#takes a hashref containing the metadata for a gdbmfile entry, and extracts 
+#the childrens numbers (from the 'contains' entry).	
+#assumes format is ".1;".2;".3
+#returns a list with the full child name ie HASH0123...ac.1 HASH0123...ac.2 
+#etc
+#used for classification stuff
+sub get_whole_children {	
+
+    my ($parentoid, $hashref, $children) = @_; 
+    
+    my $childs = $hashref->{'contains'};
+    my @items;
+    if (defined ($childs)) {
+	$childs =~ s/\@$//;  #remove trailing @
+	@items = split /\;/, $childs; #split on ;
+	foreach $item (@items) {
+	    $item =~ s/^\"/$parentoid/; # replace " with parentoid
+	    push (@$children, "$item");
+	}
+    }
+    else {
+	  $children = [];
+      }
+}
+
+    
+sub recurse_sections {
+    my ($doc_obj, $children, $parentoid, $parentsection, $olddir) = @_;
+
+    foreach $child (sort numerically @$children) {
+	$doc_obj->create_named_section("$parentsection.$child");
+	my $value = $infodb{"$parentoid.$child"};
+	my $hashref={};
+	&get_metadata($value, $hashref); # get childs metadata
+	my $newchildren = [];
+	&get_children($hashref, $newchildren); # get childs children
+	#add content fo rcurrent section
+	&add_section_content($doc_obj, "$parentsection.$child", $hashref, $olddir);
+	# process all the children if there are any
+	&recurse_sections($doc_obj, $newchildren, "$parentoid.$child", "$parentsection.$child", $olddir)
+	    if (defined ($newchildren));
+    }
+
+
+}					     
+
+sub add_section_content {
+    my ($doc_obj, $cursection, $hashref, $olddir) = @_;
+ 
+    foreach $key (keys %$hashref) {
+	#dont need to store these metadata
+	next if $key =~ /(contains|docnum|hastxt|doctype|archivedir|classifytype)/i;
+	my @items = split /@/, $hashref->{$key};
+	map {$doc_obj->add_metadata ($cursection, $key, $_); } @items;
+
+    }
+    my ($docnum)= $hashref->{'docnum'} =~ /(\d*)/;
+    my ($hastext) =$hashref->{'hastxt'} =~ /(0|1)/;
+
+    my $images=[];
+    if ($hastext) {
+	my $text = &get_text($docnum);
+    
+	#my (@images) = $text =~ /<img.*?src=\"([^\"]*)\"[^>]*>/g;
+    
+	# in text replace path to image with _httpdocimg_/blah.gif
+	#while ($text =~ s/(<img.*?src=\")([^\"]*)(\"[^>]*>)/
+	#   $1.&get_img($2, \@images).$3/sgei) {
+	$text =~ s/(<img.*?src=\")([^\"]*)(\"[^>]*>)/
+	    $1.&get_img($2,$images).$3/sgei;
+    
+	$doc_obj->add_text ($cursection, $text);
+	
+	if (scalar(@$images)>0) {
+	    
+	    foreach $img (@$images) {
+		my ($assoc_file) = $img =~ /([^\/\\]*\..*)$/; #the name of the image
+		$img =~ s/_httpcollection_/\./; #replace _httpcollection_ with .
+		$img =~ s/_thisOID_/$olddir/; #replace _thisOID_ with old archivedir name
+		
+		$doc_obj->associate_file($img, $assoc_file);
+	    }
+	}
+    }
+}
+
+
+
+sub get_img {
+    my ($path, $images) = @_;
+    my $img = "_httpdocimg_/";
+    my ($imgname) = $path =~ /([^\/\\]*\..*)$/;
+    push (@$images, $path);
+    $img .= $imgname;
+    return $img;
+}
+    
+
+sub add_classification_metadata {
+
+    my ($oid, $doc_obj, $cursection) = @_;
+    
+    if (defined $doc_classif_info->{$oid}) {
+
+	my $hashref = $doc_classif_info->{$oid};
+	
+	foreach $key (keys %$hashref) {
+	    my @items = @{$hashref->{$key}};
+	    map {$doc_obj->add_metadata ($cursection, $key, $_); } @items;
+	}
+    }
+}
+
+# picks up the cover image "cover.jpg" from the old archives directory.
+sub add_cover_image {
+
+    my ($doc_obj, $olddir) =  @_;
+    $assoc_file = "cover.jpg";
+    $img = "archives/$olddir/$assoc_file";
+
+
+    if (-e $img) {
+	$doc_obj->associate_file($img, $assoc_file);
+    }
+}
+
+
+
+sub set_index {
+    # check that $collection has been set
+    die "collection global was not set\n"
+	unless defined $collection && $collection =~ /\w/;
+
+    # find an index (just use first non-text directory we come across in $indexdir)
+    opendir (INDEXDIR, $indexdir) || die "couldn't open directory $indexdir\n";
+    my @indexes = readdir INDEXDIR;
+    close INDEXDIR;
+    foreach $i (@indexes) {
+	next if $i =~ /text$/i || $i =~ /\./ || $i =~ /assoc$/i;
+	$index = &util::filename_cat ($i, $collection);
+	last;
+    }
+}
+
+
+#########################################################################
+
+################ functions involving mg ################################
+
+sub get_text {
+    my ($docnum) = @_;
+
+    print STDERR "." if $verbosity >= 2;
+    &mgcommand ($docnum);
+
+   <$mgread>;	# eat the document separator
+
+    my $text = "";
+    my $line = "";
+
+    while (defined ($line = <$mgread>))
+    {
+	last if $line =~ /^<\/mg>/;
+	$text .= $line;
+    }
+
+    # Read in the last statement, which should be:
+    #  "dd documents retrieved."
+    <$mgread>;
+
+    return $text;
+}
+
+sub numerically {$a <=> $b;}
+
+
+
+sub openmg {
+
+    #print STDERR "index: $index\n";
+
+    die "Unable to start mgquery." unless
+	&openpipe($mgread, $mgwrite,
+		 "mgquery -d $indexdir -f $index -t $textdir");
+
+    $mgwrite->autoflush();
+
+    &mgcommand('.set expert true');
+    &mgcommand('.set terminator "</mg>\n"');
+    &mgcommand('.set mode text');
+    &mgcommand('.set query docnums');
+    &mgcommand('.set term_freq off');
+    &mgcommand('.set briefstats off');
+    &mgcommand('.set memstats off');
+    &mgcommand('.set sizestats off');
+    &mgcommand('.set timestats off');
+}
+
+sub closemg {
+    &mgcommand (".quit");
+    close($mgread);
+    close($mgwrite);
+}
+
+sub mgcommand {
+    my ($command) = @_;
+
+    return if $command =~ /^\s*$/;  #whitespace
+    #print STDERR "command: $command\n";
+    print $mgwrite "$command\n";
+
+    # eat up the command executed which is echoed
+    <$mgread>;
+}
+
+# openpipe(READ, WRITE, CMD)
+# 
+# Like open2, except CMD's stderr is also redirected.
+# 
+sub openpipe
+{
+    my ($read, $write, $cmd) = @_;
+    my ($child_read, $child_write);
+
+    $child_read = ++$FileHandle;
+    $child_write = ++$FileHandle;
+
+    pipe($read, $child_write) || die "Failed pipe($read, $child_write): $!";
+    pipe($child_read, $write) || die "Failed pipe($child_read, $write): $!";
+    my $pid;
+
+    if (($pid = fork) < 0) {
+        die "Failed fork: $!";
+    } elsif ($pid == 0) {
+        close($read);
+        close($write);
+        open(STDIN, "<&$child_read");
+        open(STDOUT, ">&$child_write");
+        open(STDERR, ">&$child_write");
+        exec($cmd);
+        die "Failed exec $cmd: $!";
+    }
+
+    close($child_read);
+    close($child_write);
+
+    $write->autoflush();
+    $read->autoflush();
+
+    return 1;
+}
+
+
+
+
+######################################################################
+
+############# functions to do with the classification stuff ##########
+
+#returns the top level classification oids
+sub get_classifyinfo {
+    my ($gdbmfile) = @_;
+
+    open (DB2TXT, "db2txt $gdbmfile |") || die "couldn't open pipe to db2txt\n";
+    print STDERR "Finding all classification sections from $gdbmfile\n" ;
+
+    $/ = '-' x 70;
+    my $entry = "";
+    while (defined ($entry = <DB2TXT>)) {
+	next unless $entry =~ /\w/;  #ignore blank entries
+	$entry =~ s/\n+/\\n/g;  # replace multiple \n with single \n
+	my ($key, $value) = $entry =~ /\[([^\]]*)\](.*)/;
+
+	next unless ($key =~/^CL\d$/); # assumes classification OID is like
+	                                 # CL1 or CL2 etc
+
+	push( @$classifyinfo, $key);
+   
+    }
+
+    $/ = "\n";
+    #print STDERR "classifications are: ", join(", ", @$classifyinfo);
+    #print STDERR "\n";
+    
+}
+
+#this creates the classification files needed for the hierarchy classifier
+#used for subjects, titles, orgs etc
+#also adds in entries to the collect_cfg hash    
+sub make_info_file {
+
+    my ($classifier) = @_;
+    my $info_file = "";
+    my $entry = $infodb{$classifier};
+
+    my $hashref = {};
+    &get_metadata($entry, $hashref);
+   
+    my $classifier_name = "CL".$hashref->{'Title'}; #like CLSubject
+    $classifier_name =~ s/\@$//; #remove trailing @
+   
+    # check children - if there is a classifier node at this level, 
+    # use a hierarchy, otherwise use an AZList.
+    
+    my $children=[];
+    my $hierarchy = 0;
+    &get_whole_children($classifier, $hashref, $children); #returns a list of the child ids
+    foreach $child(@$children) {
+	if(not &is_document($child)) {
+	    $hierarchy = 1;
+	    last;
+	}
+    }
+
+    if (!$hierarchy) {
+	&add_classify_cfg_list($classifier_name);
+    }else { #there is a hierarchy so create a file
+	$info_file = "./etc/$classifier_name.txt";
+
+	print STDERR "classification $classifier will be called $classifier_name\n";
+
+	open (OUTDOC, "> $info_file" ) || die  "couldn't open file $info_file\n";
+	
+	foreach $child (@$children) {
+	    &process_entry(OUTDOC, $classifier_name, $child);
+	}
+	
+	close OUTDOC;
+    
+	&add_classify_cfg($classifier, $classifier_name, $info_file);
+    }
+}
+
+
+sub process_entry {
+    my ($handle, $classifier_name, $classify_id) = @_;
+    my $value = $infodb{$classify_id};
+    
+    my $hashref={};
+    &get_metadata($value, $hashref);
+    my $title = $hashref->{'Title'};
+    $title =~ s/\@$//; #remove trailing @
+    &add_line($handle, $classify_id, $title);
+    
+    my $children = [];
+    &get_whole_children($classify_id, $hashref, $children);
+    foreach $child (@$children) {
+	if (&is_document($child)) {
+	    &add_doc_metadata($child, $classifier_name, $title);
+	}else {
+	    &process_entry($handle, $classifier_name, $child);
+	}
+    }
+    
+}
+    
+
+
+sub add_doc_metadata {
+
+    my ($doc_id, $classifier_name, $classifier_id) = @_;
+
+	#add entry to doc database
+	#print STDERR "at doc level, docnum=$classify_id\n";
+
+    $doc_classif_info->{$doc_id}={} unless defined $doc_classif_info->{$doc_id};
+    $doc_classif_info->{$doc_id}->{$classifier_name}=[] unless
+	defined $doc_classif_info->{$doc_id}->{$classifier_name};
+    push (@{$doc_classif_info->{$doc_id}->{$classifier_name}}, $classifier_id); 
+
+}
+
+
+
+
+sub add_line {
+
+    my ($handle, $classify_id, $title) = @_;
+    #print STDERR "classify id= $classify_id, title= $title\n";
+    $title = &unicode::ascii2utf8(\$title);
+    my ($num) = $classify_id =~ /^CL\d\.(.*)$/; #remove the CL1. from the front
+    
+    print $handle "\"$title\"\t$num\t\"$title\"\n";
+
+
+}
+
+sub is_document {
+    my ($oid) = @_;
+    return 1 if $oid =~ /^HASH/i;
+    return 0;
+}
+    
+########################################################################
+
+########## stuff for producing collect.cfg file ###########################
+
+sub add_default_cfg {
+
+    $username=`whoami`;
+    $username=`logname` unless defined $username;
+    $username="a_user" unless defined $username;
+    $username =~ s/\n//;
+    $collect_cfg->{'creator'}="$username\@cs.waikato.ac.nz";
+    $collect_cfg->{'maintainer'}="$username\@cs.waikato.ac.nz";
+    $collect_cfg->{'public'}="true";
+    $collect_cfg->{'beta'}="true";
+    
+    $collect_cfg->{'plugin'}=[];
+    push (@{$collect_cfg->{'plugin'}}, ["GAPlug"]);
+    push (@{$collect_cfg->{'plugin'}}, ["ArcPlug"]);
+    push (@{$collect_cfg->{'plugin'}}, ["RecPlug"]);
+
+    $collect_cfg->{'format'}={};
+    $collect_cfg->{'format'}->{'DocumentImages'}="true";
+    $collect_cfg->{'format'}->{'DocumentText'} = 
+	"\"<h3>[Title]</h3>\\\\n\\\\n<p>[Text]\"";
+    $collect_cfg->{'format'}->{'SearchVList'} =
+	"\"<td valign=top>[link][icon][/link]</td><td>{If}{[parent(All': '):Title],[parent(All': '):Title]:}[link][Title][/link]</td>\"";
+
+    $collect_cfg->{'collectionmeta'}={};
+    $collect_cfg->{'collectionmeta'}->{'collectionname'}="\"$collection\"";
+    $collect_cfg->{'collectionmeta'}->{'iconcollection'}="\"_httpprefix_/collect/$collection/images/$collection.gif\"";
+    $collect_cfg->{'collectionmeta'}->{'iconcollectionsmall'}="\"_httpprefix_/collect/$collection/images/${collection}sm.gif\"";
+    $collect_cfg->{'collectionmeta'}->{'collectionextra'} = "\"This is a collection rebuilt from CDROM.\"";
+
+}
+
+sub add_index_cfg {
+  my ($buildfile) = @_;
+
+  my $data={};
+  $collect_cfg->{'indexes'}=[];
+  if (-e $buildfile) {
+      $data=&cfgread::read_cfg_file($buildfile, '^(this)$', '^(indexmap)$'); 
+      foreach $i (@{$data->{'indexmap'}}) {
+          ($thisindex, $abbrev)= split ("\-\>", $i);
+          push (@{$collect_cfg->{'indexes'}}, $thisindex);
+	  $collect_cfg->{'defaultindex'} = $thisindex unless defined 
+	      $collect_cfg->{'defaultindex'};
+          $name=&get_index_name($thisindex);
+	  $thisindex=".$thisindex";
+          $collect_cfg->{'collectionmeta'}->{$thisindex} = "\"$name\"";
+      } 
+  }
+  else {
+      print STDERR "Couldn't read $buildfile, could not add index data to configuration file\n";
+  }
+
+}
+
+sub get_index_name {
+    my ($thisindex) = @_;
+    return "paragraphs" if $thisindex =~ /paragraph/;
+    return "chapters" if $thisindex =~ /section.*text/;
+    return "titles" if $thisindex =~ /Title/;
+    return "other";
+}
+
+sub add_classify_cfg {
+
+    my ($classify, $classifier_name, $file) = @_;
+    $collect_cfg->{'classify'} = [] unless defined $collect_cfg->{'classify'};
+
+    my ($title) = $classifier_name =~ /^CL(.*)$/;
+    my ($filename) = $file =~ /\/([^\/]*)$/;
+    my $entry = "Hierarchy -hfile $filename -metadata $classifier_name -buttonname $title -sort Title";
+    push (@{$collect_cfg->{'classify'}},[$entry]);
+   
+
+}
+
+sub add_classify_cfg_list {
+
+    my ($classifier) = @_;
+    $collect_cfg->{'classify'} = [] unless defined $collect_cfg->{'classify'};
+    my ($title) = $classifier =~ /^CL(.*)$/;
+    my $entry = "AZList -metadata $classifier -buttonname $title";
+    push (@{$collect_cfg->{'classify'}},[$entry]);
+}    
+
+sub output_cfg_file {
+
+    my ($collfile) = @_;
+    
+    if (-e $collfile) { #collect.cfg already exists
+	$collfile .= ".new";
+    }
+    &cfgread::write_cfg_file($collfile, $collect_cfg, 
+			     '^(creator|maintainer|public|beta|defaultindex)$',
+                            '^(indexes)$', '^(format|collectionmeta)$',
+                            '^(plugin|classify)$');
+
+
+
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/update.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/update.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/update.pl	(revision 10506)
@@ -0,0 +1,198 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# update.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This program updates any collections that are based on mirrors of
+# web sites after a certain interval.  It first checks that the
+# collection is a mirrored collection and whether it is time to 
+# update the collection.  If so, it updates the mirror with 
+# mirror.pl; then imports the collection with import.pl; then 
+# builds the collection with buildcol.pl; then replaces the 
+# existing index directory with the new building directory.
+# The etc/mirror.log file stores the STDOUT output.
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/classify");
+}
+
+use arcinfo;
+use colcfg;
+use plugin;
+use docprint;
+use util;
+use parsargv;
+
+sub print_usage {
+    print STDERR "\n";
+    print STDERR "update.pl: Updates a collection if it has been set up to mirror\n";
+    print STDERR "           a website. Calls mirror.pl to do the mirroring.\n\n";
+    print STDERR "  usage: $0 [options] collection-name\n\n";
+    print STDERR "  options:\n";
+    print STDERR "   -verbosity number      0=none, 3=lots\n";
+    print STDERR "   -importdir directory   Where to place the mirrored material\n";
+    print STDERR "   -archivedir directory  Where the converted material ends up\n";
+}
+
+
+&main ();
+
+sub main {
+    my ($verbosity, $importdir, $archivedir, $builddir, $indexdir, $etcdir, 
+	$mirror, $interval, $logfile,
+        $collection, $configfilename, $collectcfg);
+
+    if (!parsargv::parse(\@ARGV, 
+			 'verbosity/\d+/2', \$verbosity,
+			 'importdir/.*/', \$importdir,
+			 'archivedir/.*/', \$archivedir )) {
+	&print_usage();
+	die "\n";
+    }
+
+    # get and check the collection name
+    if (($collection = &util::use_collection(@ARGV)) eq "") {
+	&print_usage();
+	die "\n";
+    }
+
+    # check the configuration file for options
+    $configfilename = &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, "etc/collect.cfg");
+    if (-e $configfilename) {
+	$collectcfg = &colcfg::read_collect_cfg ($configfilename);
+	if (defined $collectcfg->{'importdir'} && $importdir eq "") {
+	    $importdir = $collectcfg->{'importdir'};
+	}
+	if (defined $collectcfg->{'archivedir'} && $archivedir eq "") {
+	    $archivedir = $collectcfg->{'archivedir'};
+	}
+	if (defined $collectcfg->{'mirror'}) {
+	    $mirror = $collectcfg->{'mirror'};
+	}
+    } else {
+	die "Couldn't find the configuration file $configfilename\n";
+    }
+    
+    # fill in the default import and archives directories if none
+    # were supplied, turn all \ into / and remove trailing /
+    $importdir = "$ENV{'GSDLCOLLECTDIR'}/import" if $importdir eq "";
+    $importdir =~ s/[\\\/]+/\//g;
+    $importdir =~ s/\/$//;
+    $archivedir = "$ENV{'GSDLCOLLECTDIR'}/archives" if $archivedir eq "";
+    $archivedir =~ s/[\\\/]+/\//g;
+    $archivedir =~ s/\/$//;
+
+    $indexdir = "$ENV{'GSDLCOLLECTDIR'}/index";
+    $builddir = "$ENV{'GSDLCOLLECTDIR'}/building";
+    $etcdir = "$ENV{'GSDLCOLLECTDIR'}/etc";
+    $logfile = "$etcdir/mirror.log";
+
+    # if there is no mirror information, we're all done
+    if (!defined($mirror)) {
+	print "No mirror command in $configfilename\n";
+	exit;
+    }
+
+    # read the mirror interval
+    if (($#$mirror == 1) && ($$mirror[0] =~ /interval/)){
+	$interval = $$mirror[1];
+    } else {
+	die "Malformed mirror information: use \"mirror interval N\"\n" .
+	    "where N is the number of days between mirrors.\n";
+    }
+
+    # make sure there is an import directory
+    if (! -e "$importdir") {
+	&util::mk_dir($importdir);
+    }
+
+    print "archives directory: $archivedir\n";
+    print "  import directory: $importdir\n";
+    print "     etc directory: $etcdir\n";
+    print "          interval: $interval days\n";
+
+    # how many days is it since the last mirror
+    my $seconds = 0;
+    if (-e "$logfile") {
+	my $now = time;
+	my @stats = stat("$logfile");
+	my $then = $stats[9];
+	# calculate the number of days since the last mirror
+	$seconds = $now - $then;
+    }
+    my $days = (($seconds / 3600) / 24);
+
+    # Is it too soon to start mirroring?
+    if (($seconds > 0) && ($interval > $days)) {
+	printf "Mirror not started: only %.1f days have passed\n", $days;
+	exit;
+    }
+    
+    # Mirror the remote site
+    open(WLOG, ">$logfile");
+    print WLOG "Starting mirror at " . time . "\n\n";
+    
+    my $command = "mirror.pl $collection";
+    print WLOG "Executing: $command\n";
+    print WLOG `$command`;
+    
+    # Import the collection
+    print WLOG "\n\nStarting import at " . time . "\n\n";
+    $command = "import.pl -removeold $collection";
+    print WLOG "Executing: $command\n";
+    print WLOG `$command`;
+
+    # Build the collection
+    print WLOG "\n\nStarting buildcol.pl at " . time . "\n\n";
+    $command = "buildcol.pl $collection";
+    print WLOG "Executing: $command\n";
+    print WLOG `$command`;
+
+    # Renaming the building directory to index
+    print WLOG "\n\nRenaming building directory at " . time . "\n\n";
+    if (-e $indexdir) {
+	&util::mv($indexdir, "$indexdir.old");
+	&util::mv($builddir, $indexdir);
+	&util::rm_r ("$indexdir.old");
+    } else {
+	&util::mv($builddir, $indexdir);
+    }
+
+
+    close WLOG;
+    
+}
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/bin/script/xlstohtml.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/bin/script/xlstohtml.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/bin/script/xlstohtml.pl	(revision 10506)
@@ -0,0 +1,69 @@
+eval 'exec perl -x -- $0 $@'
+    if 0;
+#! perl
+# line 6
+
+sub usage() {
+    print "$0 <input.xls> <output.html>\n";
+}
+
+
+if (@ARGV != 2) {
+    usage();
+    exit(1);
+}
+my $input_xls=shift;
+my $output_html=shift;
+
+# try to find xlhtml binary in GSDLHOME
+my $xlhtml_binary="xlhtml";
+my $GSDLOS=$ENV{'GSDLOS'};
+my $GSDLHOME=$ENV{'GSDLHOME'};
+if ($GSDLOS =~ /^windows/i) {
+    $xlhtml_binary.=".exe";
+}
+
+# Trouble happens if there are spaces in GSDLHOME. Assume that on windows
+# the program is found in the path.
+if ($GSDLOS !~ /windows/i && -x "$GSDLHOME/bin/$GSDLOS/$xlhtml_binary") {
+    $xlhtml_binary="$GSDLHOME/bin/$GSDLOS/$xlhtml_binary";
+}
+
+if (! -r $input_xls) {
+    print STDERR "Unable to read file `$input_xls'\n";
+    exit (1);
+}
+
+my $return_value=
+    system("$xlhtml_binary \"$input_xls\" > \"$output_html\"");
+
+if ($return_value != 0) {
+    exit (1);
+}
+
+# Ok, we made an html file. Check to see if it has any content, and remove
+# the little nag link at the the bottom.
+my $html="";
+open (HTML, "$output_html") || die "Can't read file:$!";
+$html=join('', <HTML>);
+close HTML;
+
+$html =~ s@<hr><FONT SIZE=-1>Created with.*\n</BODY></HTML>$@</BODY></HTML>@s;
+
+# xlHtml uses the filename as the title.
+# HTMLPlug will use the first 100 chars instead if there's no title.
+# Don't know if that's a good idea with a spreadsheet, though...
+$html =~ s@<title>.*?\.xls</title>@<title></title>@i;
+
+my $tmp=$html;
+$tmp =~ s/^.*?<BODY>//ms;
+$tmp =~ s/(&nbsp;)|\s//gims;
+if ($tmp !~ m/(>[^<]+<)/) {
+    print STDERR "No text found in extracted html file!\n";
+    exit(1);
+}
+open (NEWHTML, ">$output_html") || die "Can't create file:$!";
+print NEWHTML $html;
+close NEWHTML;
+exit (0);
+
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/CGI.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/CGI.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/CGI.pm	(revision 10506)
@@ -0,0 +1,6697 @@
+package CGI;
+require 5.004;
+use Carp 'croak';
+
+# See the bottom of this file for the POD documentation.  Search for the
+# string '=head'.
+
+# You can run this file through either pod2man or pod2html to produce pretty
+# documentation in manual or html file format (these utilities are part of the
+# Perl 5 distribution).
+
+# Copyright 1995-1998 Lincoln D. Stein.  All rights reserved.
+# It may be used and modified freely, but I do request that this copyright
+# notice remain attached to the file.  You may modify this module as you 
+# wish, but if you redistribute a modified version, please attach a note
+# listing the modifications you have made.
+
+# The most recent version and complete docs are available at:
+#   http://stein.cshl.org/WWW/software/CGI/
+
+$CGI::revision = '$Id$';
+$CGI::VERSION='2.81';
+
+# HARD-CODED LOCATION FOR FILE UPLOAD TEMPORARY FILES.
+# UNCOMMENT THIS ONLY IF YOU KNOW WHAT YOU'RE DOING.
+# $CGITempFile::TMPDIRECTORY = '/usr/tmp';
+use CGI::Util qw(rearrange make_attributes unescape escape expires);
+
+#use constant XHTML_DTD => ['-//W3C//DTD XHTML Basic 1.0//EN',
+#                           'http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd'];
+
+use constant XHTML_DTD => ['-//W3C//DTD XHTML 1.0 Transitional//EN',
+                           'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'];
+
+# >>>>> Here are some globals that you might want to adjust <<<<<<
+sub initialize_globals {
+    # Set this to 1 to enable copious autoloader debugging messages
+    $AUTOLOAD_DEBUG = 0;
+
+    # Set this to 1 to generate XTML-compatible output
+    $XHTML = 1;
+
+    # Change this to the preferred DTD to print in start_html()
+    # or use default_dtd('text of DTD to use');
+    $DEFAULT_DTD = [ '-//W3C//DTD HTML 4.01 Transitional//EN',
+		     'http://www.w3.org/TR/html4/loose.dtd' ] ;
+
+    # Set this to 1 to enable NOSTICKY scripts
+    # or: 
+    #    1) use CGI qw(-nosticky)
+    #    2) $CGI::nosticky(1)
+    $NOSTICKY = 0;
+
+    # Set this to 1 to enable NPH scripts
+    # or: 
+    #    1) use CGI qw(-nph)
+    #    2) CGI::nph(1)
+    #    3) print header(-nph=>1)
+    $NPH = 0;
+
+    # Set this to 1 to enable debugging from @ARGV
+    # Set to 2 to enable debugging from STDIN
+    $DEBUG = 1;
+
+    # Set this to 1 to make the temporary files created
+    # during file uploads safe from prying eyes
+    # or do...
+    #    1) use CGI qw(:private_tempfiles)
+    #    2) CGI::private_tempfiles(1);
+    $PRIVATE_TEMPFILES = 0;
+
+    # Set this to a positive value to limit the size of a POSTing
+    # to a certain number of bytes:
+    $POST_MAX = -1;
+
+    # Change this to 1 to disable uploads entirely:
+    $DISABLE_UPLOADS = 0;
+
+    # Automatically determined -- don't change
+    $EBCDIC = 0;
+
+    # Change this to 1 to suppress redundant HTTP headers
+    $HEADERS_ONCE = 0;
+
+    # separate the name=value pairs by semicolons rather than ampersands
+    $USE_PARAM_SEMICOLONS = 1;
+
+    # Do not include undefined params parsed from query string
+    # use CGI qw(-no_undef_params);
+    $NO_UNDEF_PARAMS = 0;
+
+    # Other globals that you shouldn't worry about.
+    undef $Q;
+    $BEEN_THERE = 0;
+    undef @QUERY_PARAM;
+    undef %EXPORT;
+    undef $QUERY_CHARSET;
+    undef %QUERY_FIELDNAMES;
+
+    # prevent complaints by mod_perl
+    1;
+}
+
+# ------------------ START OF THE LIBRARY ------------
+
+# make mod_perlhappy
+initialize_globals();
+
+# FIGURE OUT THE OS WE'RE RUNNING UNDER
+# Some systems support the $^O variable.  If not
+# available then require() the Config library
+unless ($OS) {
+    unless ($OS = $^O) {
+	require Config;
+	$OS = $Config::Config{'osname'};
+    }
+}
+if ($OS =~ /^MSWin/i) {
+  $OS = 'WINDOWS';
+} elsif ($OS =~ /^VMS/i) {
+  $OS = 'VMS';
+} elsif ($OS =~ /^dos/i) {
+  $OS = 'DOS';
+} elsif ($OS =~ /^MacOS/i) {
+    $OS = 'MACINTOSH';
+} elsif ($OS =~ /^os2/i) {
+    $OS = 'OS2';
+} elsif ($OS =~ /^epoc/i) {
+    $OS = 'EPOC';
+} else {
+    $OS = 'UNIX';
+}
+
+# Some OS logic.  Binary mode enabled on DOS, NT and VMS
+$needs_binmode = $OS=~/^(WINDOWS|DOS|OS2|MSWin)/;
+
+# This is the default class for the CGI object to use when all else fails.
+$DefaultClass = 'CGI' unless defined $CGI::DefaultClass;
+
+# This is where to look for autoloaded routines.
+$AutoloadClass = $DefaultClass unless defined $CGI::AutoloadClass;
+
+# The path separator is a slash, backslash or semicolon, depending
+# on the paltform.
+$SL = {
+       UNIX=>'/', OS2=>'\\', EPOC=>'/',
+       WINDOWS=>'\\', DOS=>'\\', MACINTOSH=>':', VMS=>'/'
+    }->{$OS};
+
+# This no longer seems to be necessary
+# Turn on NPH scripts by default when running under IIS server!
+# $NPH++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/;
+$IIS++ if defined($ENV{'SERVER_SOFTWARE'}) && $ENV{'SERVER_SOFTWARE'}=~/IIS/;
+
+# Turn on special checking for Doug MacEachern's modperl
+if (exists $ENV{'GATEWAY_INTERFACE'} 
+    && 
+    ($MOD_PERL = $ENV{'GATEWAY_INTERFACE'} =~ /^CGI-Perl\//))
+{
+    $| = 1;
+    require Apache;
+}
+# Turn on special checking for ActiveState's PerlEx
+$PERLEX++ if defined($ENV{'GATEWAY_INTERFACE'}) && $ENV{'GATEWAY_INTERFACE'} =~ /^CGI-PerlEx/;
+
+# Define the CRLF sequence.  I can't use a simple "\r\n" because the meaning
+# of "\n" is different on different OS's (sometimes it generates CRLF, sometimes LF
+# and sometimes CR).  The most popular VMS web server
+# doesn't accept CRLF -- instead it wants a LR.  EBCDIC machines don't
+# use ASCII, so \015\012 means something different.  I find this all 
+# really annoying.
+$EBCDIC = "\t" ne "\011";
+if ($OS eq 'VMS') {
+  $CRLF = "\n";
+} elsif ($EBCDIC) {
+  $CRLF= "\r\n";
+} else {
+  $CRLF = "\015\012";
+}
+
+if ($needs_binmode) {
+    $CGI::DefaultClass->binmode(main::STDOUT);
+    $CGI::DefaultClass->binmode(main::STDIN);
+    $CGI::DefaultClass->binmode(main::STDERR);
+}
+
+%EXPORT_TAGS = (
+		':html2'=>['h1'..'h6',qw/p br hr ol ul li dl dt dd menu code var strong em
+			   tt u i b blockquote pre img a address cite samp dfn html head
+			   base body Link nextid title meta kbd start_html end_html
+			   input Select option comment charset escapeHTML/],
+		':html3'=>[qw/div table caption th td TR Tr sup Sub strike applet Param 
+			   embed basefont style span layer ilayer font frameset frame script small big/],
+                ':html4'=>[qw/abbr acronym bdo col colgroup del fieldset iframe
+                            ins label legend noframes noscript object optgroup Q 
+                            thead tbody tfoot/], 
+		':netscape'=>[qw/blink fontsize center/],
+		':form'=>[qw/textfield textarea filefield password_field hidden checkbox checkbox_group 
+			  submit reset defaults radio_group popup_menu button autoEscape
+			  scrolling_list image_button start_form end_form startform endform
+			  start_multipart_form end_multipart_form isindex tmpFileName uploadInfo URL_ENCODED MULTIPART/],
+		':cgi'=>[qw/param upload path_info path_translated url self_url script_name cookie Dump
+			 raw_cookie request_method query_string Accept user_agent remote_host content_type
+			 remote_addr referer server_name server_software server_port server_protocol
+			 virtual_host remote_ident auth_type http
+			 save_parameters restore_parameters param_fetch
+			 remote_user user_name header redirect import_names put 
+			 Delete Delete_all url_param cgi_error/],
+		':ssl' => [qw/https/],
+		':imagemap' => [qw/Area Map/],
+		':cgi-lib' => [qw/ReadParse PrintHeader HtmlTop HtmlBot SplitParam Vars/],
+		':html' => [qw/:html2 :html3 :html4 :netscape/],
+		':standard' => [qw/:html2 :html3 :html4 :form :cgi/],
+		':push' => [qw/multipart_init multipart_start multipart_end multipart_final/],
+		':all' => [qw/:html2 :html3 :netscape :form :cgi :internal :html4/]
+		);
+
+# to import symbols into caller
+sub import {
+    my $self = shift;
+
+# This causes modules to clash.  
+    undef %EXPORT_OK;
+    undef %EXPORT;
+
+    $self->_setup_symbols(@_);
+    my ($callpack, $callfile, $callline) = caller;
+
+    # To allow overriding, search through the packages
+    # Till we find one in which the correct subroutine is defined.
+    my @packages = ($self,@{"$self\:\:ISA"});
+    foreach $sym (keys %EXPORT) {
+	my $pck;
+	my $def = ${"$self\:\:AutoloadClass"} || $DefaultClass;
+	foreach $pck (@packages) {
+	    if (defined(&{"$pck\:\:$sym"})) {
+		$def = $pck;
+		last;
+	    }
+	}
+	*{"${callpack}::$sym"} = \&{"$def\:\:$sym"};
+    }
+}
+
+sub compile {
+    my $pack = shift;
+    $pack->_setup_symbols('-compile',@_);
+}
+
+sub expand_tags {
+    my($tag) = @_;
+    return ("start_$1","end_$1") if $tag=~/^(?:\*|start_|end_)(.+)/;
+    my(@r);
+    return ($tag) unless $EXPORT_TAGS{$tag};
+    foreach (@{$EXPORT_TAGS{$tag}}) {
+	push(@r,&expand_tags($_));
+    }
+    return @r;
+}
+
+#### Method: new
+# The new routine.  This will check the current environment
+# for an existing query string, and initialize itself, if so.
+####
+sub new {
+    my($class,$initializer) = @_;
+    my $self = {};
+
+    bless $self,ref $class || $class || $DefaultClass;
+    if ($MOD_PERL && defined Apache->request) {
+      Apache->request->register_cleanup(\&CGI::_reset_globals);
+      undef $NPH;
+    }
+    $self->_reset_globals if $PERLEX;
+    $self->init($initializer);
+    return $self;
+}
+
+# We provide a DESTROY method so that the autoloader
+# doesn't bother trying to find it.
+sub DESTROY { }
+
+#### Method: param
+# Returns the value(s)of a named parameter.
+# If invoked in a list context, returns the
+# entire list.  Otherwise returns the first
+# member of the list.
+# If name is not provided, return a list of all
+# the known parameters names available.
+# If more than one argument is provided, the
+# second and subsequent arguments are used to
+# set the value of the parameter.
+####
+sub param {
+    my($self,@p) = self_or_default(@_);
+    return $self->all_parameters unless @p;
+    my($name,$value,@other);
+
+    # For compatibility between old calling style and use_named_parameters() style, 
+    # we have to special case for a single parameter present.
+    if (@p > 1) {
+	($name,$value,@other) = rearrange([NAME,[DEFAULT,VALUE,VALUES]],@p);
+	my(@values);
+
+	if (substr($p[0],0,1) eq '-') {
+	    @values = defined($value) ? (ref($value) && ref($value) eq 'ARRAY' ? @{$value} : $value) : ();
+	} else {
+	    foreach ($value,@other) {
+		push(@values,$_) if defined($_);
+	    }
+	}
+	# If values is provided, then we set it.
+	if (@values) {
+	    $self->add_parameter($name);
+	    $self->{$name}=[@values];
+	}
+    } else {
+	$name = $p[0];
+    }
+
+    return unless defined($name) && $self->{$name};
+    return wantarray ? @{$self->{$name}} : $self->{$name}->[0];
+}
+
+sub self_or_default {
+    return @_ if defined($_[0]) && (!ref($_[0])) &&($_[0] eq 'CGI');
+    unless (defined($_[0]) && 
+	    (ref($_[0]) eq 'CGI' || UNIVERSAL::isa($_[0],'CGI')) # slightly optimized for common case
+	    ) {
+	$Q = $CGI::DefaultClass->new unless defined($Q);
+	unshift(@_,$Q);
+    }
+    return wantarray ? @_ : $Q;
+}
+
+sub self_or_CGI {
+    local $^W=0;                # prevent a warning
+    if (defined($_[0]) &&
+	(substr(ref($_[0]),0,3) eq 'CGI' 
+	 || UNIVERSAL::isa($_[0],'CGI'))) {
+	return @_;
+    } else {
+	return ($DefaultClass,@_);
+    }
+}
+
+########################################
+# THESE METHODS ARE MORE OR LESS PRIVATE
+# GO TO THE __DATA__ SECTION TO SEE MORE
+# PUBLIC METHODS
+########################################
+
+# Initialize the query object from the environment.
+# If a parameter list is found, this object will be set
+# to an associative array in which parameter names are keys
+# and the values are stored as lists
+# If a keyword list is found, this method creates a bogus
+# parameter list with the single parameter 'keywords'.
+
+sub init {
+    my($self,$initializer) = @_;
+    my($query_string,$meth,$content_length,$fh,@lines) = ('','','','');
+    local($/) = "\n";
+
+    # if we get called more than once, we want to initialize
+    # ourselves from the original query (which may be gone
+    # if it was read from STDIN originally.)
+    if (defined(@QUERY_PARAM) && !defined($initializer)) {
+	foreach (@QUERY_PARAM) {
+	    $self->param('-name'=>$_,'-value'=>$QUERY_PARAM{$_});
+	}
+	$self->charset($QUERY_CHARSET);
+	$self->{'.fieldnames'} = {%QUERY_FIELDNAMES};
+	return;
+    }
+
+    $meth=$ENV{'REQUEST_METHOD'} if defined($ENV{'REQUEST_METHOD'});
+    $content_length = defined($ENV{'CONTENT_LENGTH'}) ? $ENV{'CONTENT_LENGTH'} : 0;
+
+    $fh = to_filehandle($initializer) if $initializer;
+
+    # set charset to the safe ISO-8859-1
+    $self->charset('ISO-8859-1');
+
+  METHOD: {
+
+      # avoid unreasonably large postings
+      if (($POST_MAX > 0) && ($content_length > $POST_MAX)) {
+	  $self->cgi_error("413 Request entity too large");
+	  last METHOD;
+      }
+
+      # Process multipart postings, but only if the initializer is
+      # not defined.
+      if ($meth eq 'POST'
+	  && defined($ENV{'CONTENT_TYPE'})
+	  && $ENV{'CONTENT_TYPE'}=~m|^multipart/form-data|
+	  && !defined($initializer)
+	  ) {
+	  my($boundary) = $ENV{'CONTENT_TYPE'} =~ /boundary=\"?([^\";,]+)\"?/;
+	  $self->read_multipart($boundary,$content_length);
+	  last METHOD;
+      } 
+
+      # If initializer is defined, then read parameters
+      # from it.
+      if (defined($initializer)) {
+	  if (UNIVERSAL::isa($initializer,'CGI')) {
+	      $query_string = $initializer->query_string;
+	      last METHOD;
+	  }
+	  if (ref($initializer) && ref($initializer) eq 'HASH') {
+	      foreach (keys %$initializer) {
+		  $self->param('-name'=>$_,'-value'=>$initializer->{$_});
+	      }
+	      last METHOD;
+	  }
+	  
+	  if (defined($fh) && ($fh ne '')) {
+	      while (<$fh>) {
+		  chomp;
+		  last if /^=/;
+		  push(@lines,$_);
+	      }
+	      # massage back into standard format
+	      if ("@lines" =~ /=/) {
+		  $query_string=join("&",@lines);
+	      } else {
+		  $query_string=join("+",@lines);
+	      }
+	      last METHOD;
+	  }
+
+	  # last chance -- treat it as a string
+	  $initializer = $$initializer if ref($initializer) eq 'SCALAR';
+	  $query_string = $initializer;
+
+	  last METHOD;
+      }
+
+      # If method is GET or HEAD, fetch the query from
+      # the environment.
+      if ($meth=~/^(GET|HEAD)$/) {
+	  if ($MOD_PERL) {
+	      $query_string = Apache->request->args;
+	  } else {
+	      $query_string = $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
+	      $query_string ||= $ENV{'REDIRECT_QUERY_STRING'} if defined $ENV{'REDIRECT_QUERY_STRING'};
+	  }
+	  last METHOD;
+      }
+
+      if ($meth eq 'POST') {
+	  $self->read_from_client(\*STDIN,\$query_string,$content_length,0)
+	      if $content_length > 0;
+	  # Some people want to have their cake and eat it too!
+	  # Uncomment this line to have the contents of the query string
+	  # APPENDED to the POST data.
+	  # $query_string .= (length($query_string) ? '&' : '') . $ENV{'QUERY_STRING'} if defined $ENV{'QUERY_STRING'};
+	  last METHOD;
+      }
+
+      # If $meth is not of GET, POST or HEAD, assume we're being debugged offline.
+      # Check the command line and then the standard input for data.
+      # We use the shellwords package in order to behave the way that
+      # UN*X programmers expect.
+      $query_string = read_from_cmdline() if $DEBUG;
+  }
+
+    # We now have the query string in hand.  We do slightly
+    # different things for keyword lists and parameter lists.
+    if (defined $query_string && length $query_string) {
+	if ($query_string =~ /[&=;]/) {
+	    $self->parse_params($query_string);
+	} else {
+	    $self->add_parameter('keywords');
+	    $self->{'keywords'} = [$self->parse_keywordlist($query_string)];
+	}
+    }
+
+    # Special case.  Erase everything if there is a field named
+    # .defaults.
+    if ($self->param('.defaults')) {
+	undef %{$self};
+    }
+
+    # Associative array containing our defined fieldnames
+    $self->{'.fieldnames'} = {};
+    foreach ($self->param('.cgifields')) {
+	$self->{'.fieldnames'}->{$_}++;
+    }
+    
+    # Clear out our default submission button flag if present
+    $self->delete('.submit');
+    $self->delete('.cgifields');
+
+    $self->save_request unless $initializer;
+}
+
+# FUNCTIONS TO OVERRIDE:
+# Turn a string into a filehandle
+sub to_filehandle {
+    my $thingy = shift;
+    return undef unless $thingy;
+    return $thingy if UNIVERSAL::isa($thingy,'GLOB');
+    return $thingy if UNIVERSAL::isa($thingy,'FileHandle');
+    if (!ref($thingy)) {
+	my $caller = 1;
+	while (my $package = caller($caller++)) {
+	    my($tmp) = $thingy=~/[\':]/ ? $thingy : "$package\:\:$thingy"; 
+	    return $tmp if defined(fileno($tmp));
+	}
+    }
+    return undef;
+}
+
+# send output to the browser
+sub put {
+    my($self,@p) = self_or_default(@_);
+    $self->print(@p);
+}
+
+# print to standard output (for overriding in mod_perl)
+sub print {
+    shift;
+    CORE::print(@_);
+}
+
+# get/set last cgi_error
+sub cgi_error {
+    my ($self,$err) = self_or_default(@_);
+    $self->{'.cgi_error'} = $err if defined $err;
+    return $self->{'.cgi_error'};
+}
+
+sub save_request {
+    my($self) = @_;
+    # We're going to play with the package globals now so that if we get called
+    # again, we initialize ourselves in exactly the same way.  This allows
+    # us to have several of these objects.
+    @QUERY_PARAM = $self->param; # save list of parameters
+    foreach (@QUERY_PARAM) {
+      next unless defined $_;
+      $QUERY_PARAM{$_}=$self->{$_};
+    }
+    $QUERY_CHARSET = $self->charset;
+    %QUERY_FIELDNAMES = %{$self->{'.fieldnames'}};
+}
+
+sub parse_params {
+    my($self,$tosplit) = @_;
+    my(@pairs) = split(/[&;]/,$tosplit);
+    my($param,$value);
+    foreach (@pairs) {
+	($param,$value) = split('=',$_,2);
+	next unless defined $param;
+	next if $NO_UNDEF_PARAMS and not defined $value;
+	$value = '' unless defined $value;
+	$param = unescape($param);
+	$value = unescape($value);
+	$self->add_parameter($param);
+	push (@{$self->{$param}},$value);
+    }
+}
+
+sub add_parameter {
+    my($self,$param)=@_;
+    return unless defined $param;
+    push (@{$self->{'.parameters'}},$param) 
+	unless defined($self->{$param});
+}
+
+sub all_parameters {
+    my $self = shift;
+    return () unless defined($self) && $self->{'.parameters'};
+    return () unless @{$self->{'.parameters'}};
+    return @{$self->{'.parameters'}};
+}
+
+# put a filehandle into binary mode (DOS)
+sub binmode {
+    CORE::binmode($_[1]);
+}
+
+sub _make_tag_func {
+    my ($self,$tagname) = @_;
+    my $func = qq(
+	sub $tagname {
+            shift if \$_[0] && 
+                    (ref(\$_[0]) &&
+                     (substr(ref(\$_[0]),0,3) eq 'CGI' ||
+                    UNIVERSAL::isa(\$_[0],'CGI')));
+	    my(\$attr) = '';
+	    if (ref(\$_[0]) && ref(\$_[0]) eq 'HASH') {
+		my(\@attr) = make_attributes(shift()||undef,1);
+		\$attr = " \@attr" if \@attr;
+	    }
+	);
+    if ($tagname=~/start_(\w+)/i) {
+	$func .= qq! return "<\L$1\E\$attr>";} !;
+    } elsif ($tagname=~/end_(\w+)/i) {
+	$func .= qq! return "<\L/$1\E>"; } !;
+    } else {
+	$func .= qq#
+	    return \$XHTML ? "\L<$tagname\E\$attr />" : "\L<$tagname\E\$attr>" unless \@_;
+	    my(\$tag,\$untag) = ("\L<$tagname\E\$attr>","\L</$tagname>\E");
+	    my \@result = map { "\$tag\$_\$untag" } 
+                              (ref(\$_[0]) eq 'ARRAY') ? \@{\$_[0]} : "\@_";
+	    return "\@result";
+            }#;
+    }
+return $func;
+}
+
+sub AUTOLOAD {
+    print STDERR "CGI::AUTOLOAD for $AUTOLOAD\n" if $CGI::AUTOLOAD_DEBUG;
+    my $func = &_compile;
+    goto &$func;
+}
+
+sub _compile {
+    my($func) = $AUTOLOAD;
+    my($pack,$func_name);
+    {
+	local($1,$2); # this fixes an obscure variable suicide problem.
+	$func=~/(.+)::([^:]+)$/;
+	($pack,$func_name) = ($1,$2);
+	$pack=~s/::SUPER$//;	# fix another obscure problem
+	$pack = ${"$pack\:\:AutoloadClass"} || $CGI::DefaultClass
+	    unless defined(${"$pack\:\:AUTOLOADED_ROUTINES"});
+
+        my($sub) = \%{"$pack\:\:SUBS"};
+        unless (%$sub) {
+	   my($auto) = \${"$pack\:\:AUTOLOADED_ROUTINES"};
+	   eval "package $pack; $$auto";
+	   croak("$AUTOLOAD: $@") if $@;
+           $$auto = '';  # Free the unneeded storage (but don't undef it!!!)
+       }
+       my($code) = $sub->{$func_name};
+
+       $code = "sub $AUTOLOAD { }" if (!$code and $func_name eq 'DESTROY');
+       if (!$code) {
+	   (my $base = $func_name) =~ s/^(start_|end_)//i;
+	   if ($EXPORT{':any'} || 
+	       $EXPORT{'-any'} ||
+	       $EXPORT{$base} || 
+	       (%EXPORT_OK || grep(++$EXPORT_OK{$_},&expand_tags(':html')))
+	           && $EXPORT_OK{$base}) {
+	       $code = $CGI::DefaultClass->_make_tag_func($func_name);
+	   }
+       }
+       croak("Undefined subroutine $AUTOLOAD\n") unless $code;
+       eval "package $pack; $code";
+       if ($@) {
+	   $@ =~ s/ at .*\n//;
+	   croak("$AUTOLOAD: $@");
+       }
+    }       
+    CORE::delete($sub->{$func_name});  #free storage
+    return "$pack\:\:$func_name";
+}
+
+sub _selected {
+  my $self = shift;
+  my $value = shift;
+  return '' unless $value;
+  return $XHTML ? qq( selected="selected") : qq( selected);
+}
+
+sub _checked {
+  my $self = shift;
+  my $value = shift;
+  return '' unless $value;
+  return $XHTML ? qq( checked="checked") : qq( checked);
+}
+
+sub _reset_globals { initialize_globals(); }
+
+sub _setup_symbols {
+    my $self = shift;
+    my $compile = 0;
+
+    # to avoid reexporting unwanted variables
+    undef %EXPORT;
+
+    foreach (@_) {
+	$HEADERS_ONCE++,         next if /^[:-]unique_headers$/;
+	$NPH++,                  next if /^[:-]nph$/;
+	$NOSTICKY++,             next if /^[:-]nosticky$/;
+	$DEBUG=0,                next if /^[:-]no_?[Dd]ebug$/;
+	$DEBUG=2,                next if /^[:-][Dd]ebug$/;
+	$USE_PARAM_SEMICOLONS++, next if /^[:-]newstyle_urls$/;
+	$XHTML++,                next if /^[:-]xhtml$/;
+	$XHTML=0,                next if /^[:-]no_?xhtml$/;
+	$USE_PARAM_SEMICOLONS=0, next if /^[:-]oldstyle_urls$/;
+	$PRIVATE_TEMPFILES++,    next if /^[:-]private_tempfiles$/;
+	$EXPORT{$_}++,           next if /^[:-]any$/;
+	$compile++,              next if /^[:-]compile$/;
+	$NO_UNDEF_PARAMS++,      next if /^[:-]no_undef_params$/;
+	
+	# This is probably extremely evil code -- to be deleted some day.
+	if (/^[-]autoload$/) {
+	    my($pkg) = caller(1);
+	    *{"${pkg}::AUTOLOAD"} = sub { 
+		my($routine) = $AUTOLOAD;
+		$routine =~ s/^.*::/CGI::/;
+		&$routine;
+	    };
+	    next;
+	}
+
+	foreach (&expand_tags($_)) {
+	    tr/a-zA-Z0-9_//cd;  # don't allow weird function names
+	    $EXPORT{$_}++;
+	}
+    }
+    _compile_all(keys %EXPORT) if $compile;
+}
+
+sub charset {
+  my ($self,$charset) = self_or_default(@_);
+  $self->{'.charset'} = $charset if defined $charset;
+  $self->{'.charset'};
+}
+
+###############################################################################
+################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND ####################
+###############################################################################
+$AUTOLOADED_ROUTINES = '';      # get rid of -w warning
+$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD';
+
+%SUBS = (
+
+'URL_ENCODED'=> <<'END_OF_FUNC',
+sub URL_ENCODED { 'application/x-www-form-urlencoded'; }
+END_OF_FUNC
+
+'MULTIPART' => <<'END_OF_FUNC',
+sub MULTIPART {  'multipart/form-data'; }
+END_OF_FUNC
+
+'SERVER_PUSH' => <<'END_OF_FUNC',
+sub SERVER_PUSH { 'multipart/x-mixed-replace;boundary="' . shift() . '"'; }
+END_OF_FUNC
+
+'new_MultipartBuffer' => <<'END_OF_FUNC',
+# Create a new multipart buffer
+sub new_MultipartBuffer {
+    my($self,$boundary,$length,$filehandle) = @_;
+    return MultipartBuffer->new($self,$boundary,$length,$filehandle);
+}
+END_OF_FUNC
+
+'read_from_client' => <<'END_OF_FUNC',
+# Read data from a file handle
+sub read_from_client {
+    my($self, $fh, $buff, $len, $offset) = @_;
+    local $^W=0;                # prevent a warning
+    return undef unless defined($fh);
+    return read($fh, $$buff, $len, $offset);
+}
+END_OF_FUNC
+
+'delete' => <<'END_OF_FUNC',
+#### Method: delete
+# Deletes the named parameter entirely.
+####
+sub delete {
+    my($self,@p) = self_or_default(@_);
+    my($name) = rearrange([NAME],@p);
+    CORE::delete $self->{$name};
+    CORE::delete $self->{'.fieldnames'}->{$name};
+    @{$self->{'.parameters'}}=grep($_ ne $name,$self->param());
+    return wantarray ? () : undef;
+}
+END_OF_FUNC
+
+#### Method: import_names
+# Import all parameters into the given namespace.
+# Assumes namespace 'Q' if not specified
+####
+'import_names' => <<'END_OF_FUNC',
+sub import_names {
+    my($self,$namespace,$delete) = self_or_default(@_);
+    $namespace = 'Q' unless defined($namespace);
+    die "Can't import names into \"main\"\n" if \%{"${namespace}::"} == \%::;
+    if ($delete || $MOD_PERL || exists $ENV{'FCGI_ROLE'}) {
+	# can anyone find an easier way to do this?
+	foreach (keys %{"${namespace}::"}) {
+	    local *symbol = "${namespace}::${_}";
+	    undef $symbol;
+	    undef @symbol;
+	    undef %symbol;
+	}
+    }
+    my($param,@value,$var);
+    foreach $param ($self->param) {
+	# protect against silly names
+	($var = $param)=~tr/a-zA-Z0-9_/_/c;
+	$var =~ s/^(?=\d)/_/;
+	local *symbol = "${namespace}::$var";
+	@value = $self->param($param);
+	@symbol = @value;
+	$symbol = $value[0];
+    }
+}
+END_OF_FUNC
+
+#### Method: keywords
+# Keywords acts a bit differently.  Calling it in a list context
+# returns the list of keywords.  
+# Calling it in a scalar context gives you the size of the list.
+####
+'keywords' => <<'END_OF_FUNC',
+sub keywords {
+    my($self,@values) = self_or_default(@_);
+    # If values is provided, then we set it.
+    $self->{'keywords'}=[@values] if @values;
+    my(@result) = defined($self->{'keywords'}) ? @{$self->{'keywords'}} : ();
+    @result;
+}
+END_OF_FUNC
+
+# These are some tie() interfaces for compatibility
+# with Steve Brenner's cgi-lib.pl routines
+'Vars' => <<'END_OF_FUNC',
+sub Vars {
+    my $q = shift;
+    my %in;
+    tie(%in,CGI,$q);
+    return %in if wantarray;
+    return \%in;
+}
+END_OF_FUNC
+
+# These are some tie() interfaces for compatibility
+# with Steve Brenner's cgi-lib.pl routines
+'ReadParse' => <<'END_OF_FUNC',
+sub ReadParse {
+    local(*in);
+    if (@_) {
+	*in = $_[0];
+    } else {
+	my $pkg = caller();
+	*in=*{"${pkg}::in"};
+    }
+    tie(%in,CGI);
+    return scalar(keys %in);
+}
+END_OF_FUNC
+
+'PrintHeader' => <<'END_OF_FUNC',
+sub PrintHeader {
+    my($self) = self_or_default(@_);
+    return $self->header();
+}
+END_OF_FUNC
+
+'HtmlTop' => <<'END_OF_FUNC',
+sub HtmlTop {
+    my($self,@p) = self_or_default(@_);
+    return $self->start_html(@p);
+}
+END_OF_FUNC
+
+'HtmlBot' => <<'END_OF_FUNC',
+sub HtmlBot {
+    my($self,@p) = self_or_default(@_);
+    return $self->end_html(@p);
+}
+END_OF_FUNC
+
+'SplitParam' => <<'END_OF_FUNC',
+sub SplitParam {
+    my ($param) = @_;
+    my (@params) = split ("\0", $param);
+    return (wantarray ? @params : $params[0]);
+}
+END_OF_FUNC
+
+'MethGet' => <<'END_OF_FUNC',
+sub MethGet {
+    return request_method() eq 'GET';
+}
+END_OF_FUNC
+
+'MethPost' => <<'END_OF_FUNC',
+sub MethPost {
+    return request_method() eq 'POST';
+}
+END_OF_FUNC
+
+'TIEHASH' => <<'END_OF_FUNC',
+sub TIEHASH { 
+    return $_[1] if defined $_[1];
+    return $Q ||= new shift;
+}
+END_OF_FUNC
+
+'STORE' => <<'END_OF_FUNC',
+sub STORE {
+    my $self = shift;
+    my $tag  = shift;
+    my $vals = shift;
+    my @vals = index($vals,"\0")!=-1 ? split("\0",$vals) : $vals;
+    $self->param(-name=>$tag,-value=>\@vals);
+}
+END_OF_FUNC
+
+'FETCH' => <<'END_OF_FUNC',
+sub FETCH {
+    return $_[0] if $_[1] eq 'CGI';
+    return undef unless defined $_[0]->param($_[1]);
+    return join("\0",$_[0]->param($_[1]));
+}
+END_OF_FUNC
+
+'FIRSTKEY' => <<'END_OF_FUNC',
+sub FIRSTKEY {
+    $_[0]->{'.iterator'}=0;
+    $_[0]->{'.parameters'}->[$_[0]->{'.iterator'}++];
+}
+END_OF_FUNC
+
+'NEXTKEY' => <<'END_OF_FUNC',
+sub NEXTKEY {
+    $_[0]->{'.parameters'}->[$_[0]->{'.iterator'}++];
+}
+END_OF_FUNC
+
+'EXISTS' => <<'END_OF_FUNC',
+sub EXISTS {
+    exists $_[0]->{$_[1]};
+}
+END_OF_FUNC
+
+'DELETE' => <<'END_OF_FUNC',
+sub DELETE {
+    $_[0]->delete($_[1]);
+}
+END_OF_FUNC
+
+'CLEAR' => <<'END_OF_FUNC',
+sub CLEAR {
+    %{$_[0]}=();
+}
+####
+END_OF_FUNC
+
+####
+# Append a new value to an existing query
+####
+'append' => <<'EOF',
+sub append {
+    my($self,@p) = @_;
+    my($name,$value) = rearrange([NAME,[VALUE,VALUES]],@p);
+    my(@values) = defined($value) ? (ref($value) ? @{$value} : $value) : ();
+    if (@values) {
+	$self->add_parameter($name);
+	push(@{$self->{$name}},@values);
+    }
+    return $self->param($name);
+}
+EOF
+
+#### Method: delete_all
+# Delete all parameters
+####
+'delete_all' => <<'EOF',
+sub delete_all {
+    my($self) = self_or_default(@_);
+    undef %{$self};
+}
+EOF
+
+'Delete' => <<'EOF',
+sub Delete {
+    my($self,@p) = self_or_default(@_);
+    $self->delete(@p);
+}
+EOF
+
+'Delete_all' => <<'EOF',
+sub Delete_all {
+    my($self,@p) = self_or_default(@_);
+    $self->delete_all(@p);
+}
+EOF
+
+#### Method: autoescape
+# If you want to turn off the autoescaping features,
+# call this method with undef as the argument
+'autoEscape' => <<'END_OF_FUNC',
+sub autoEscape {
+    my($self,$escape) = self_or_default(@_);
+    $self->{'dontescape'}=!$escape;
+}
+END_OF_FUNC
+
+
+#### Method: version
+# Return the current version
+####
+'version' => <<'END_OF_FUNC',
+sub version {
+    return $VERSION;
+}
+END_OF_FUNC
+
+#### Method: url_param
+# Return a parameter in the QUERY_STRING, regardless of
+# whether this was a POST or a GET
+####
+'url_param' => <<'END_OF_FUNC',
+sub url_param {
+    my ($self,@p) = self_or_default(@_);
+    my $name = shift(@p);
+    return undef unless exists($ENV{QUERY_STRING});
+    unless (exists($self->{'.url_param'})) {
+	$self->{'.url_param'}={}; # empty hash
+	if ($ENV{QUERY_STRING} =~ /=/) {
+	    my(@pairs) = split(/[&;]/,$ENV{QUERY_STRING});
+	    my($param,$value);
+	    foreach (@pairs) {
+		($param,$value) = split('=',$_,2);
+		$param = unescape($param);
+		$value = unescape($value);
+		push(@{$self->{'.url_param'}->{$param}},$value);
+	    }
+	} else {
+	    $self->{'.url_param'}->{'keywords'} = [$self->parse_keywordlist($ENV{QUERY_STRING})];
+	}
+    }
+    return keys %{$self->{'.url_param'}} unless defined($name);
+    return () unless $self->{'.url_param'}->{$name};
+    return wantarray ? @{$self->{'.url_param'}->{$name}}
+                     : $self->{'.url_param'}->{$name}->[0];
+}
+END_OF_FUNC
+
+#### Method: Dump
+# Returns a string in which all the known parameter/value 
+# pairs are represented as nested lists, mainly for the purposes 
+# of debugging.
+####
+'Dump' => <<'END_OF_FUNC',
+sub Dump {
+    my($self) = self_or_default(@_);
+    my($param,$value,@result);
+    return '<ul></ul>' unless $self->param;
+    push(@result,"<ul>");
+    foreach $param ($self->param) {
+	my($name)=$self->escapeHTML($param);
+	push(@result,"<li><strong>$param</strong>");
+	push(@result,"<ul>");
+	foreach $value ($self->param($param)) {
+	    $value = $self->escapeHTML($value);
+            $value =~ s/\n/<br>\n/g;
+	    push(@result,"<li>$value");
+	}
+	push(@result,"</ul>");
+    }
+    push(@result,"</ul>");
+    return join("\n",@result);
+}
+END_OF_FUNC
+
+#### Method as_string
+#
+# synonym for "dump"
+####
+'as_string' => <<'END_OF_FUNC',
+sub as_string {
+    &Dump(@_);
+}
+END_OF_FUNC
+
+#### Method: save
+# Write values out to a filehandle in such a way that they can
+# be reinitialized by the filehandle form of the new() method
+####
+'save' => <<'END_OF_FUNC',
+sub save {
+    my($self,$filehandle) = self_or_default(@_);
+    $filehandle = to_filehandle($filehandle);
+    my($param);
+    local($,) = '';  # set print field separator back to a sane value
+    local($\) = '';  # set output line separator to a sane value
+    foreach $param ($self->param) {
+	my($escaped_param) = escape($param);
+	my($value);
+	foreach $value ($self->param($param)) {
+	    print $filehandle "$escaped_param=",escape("$value"),"\n";
+	}
+    }
+    foreach (keys %{$self->{'.fieldnames'}}) {
+          print $filehandle ".cgifields=",escape("$_"),"\n";
+    }
+    print $filehandle "=\n";    # end of record
+}
+END_OF_FUNC
+
+
+#### Method: save_parameters
+# An alias for save() that is a better name for exportation.
+# Only intended to be used with the function (non-OO) interface.
+####
+'save_parameters' => <<'END_OF_FUNC',
+sub save_parameters {
+    my $fh = shift;
+    return save(to_filehandle($fh));
+}
+END_OF_FUNC
+
+#### Method: restore_parameters
+# A way to restore CGI parameters from an initializer.
+# Only intended to be used with the function (non-OO) interface.
+####
+'restore_parameters' => <<'END_OF_FUNC',
+sub restore_parameters {
+    $Q = $CGI::DefaultClass->new(@_);
+}
+END_OF_FUNC
+
+#### Method: multipart_init
+# Return a Content-Type: style header for server-push
+# This has to be NPH on most web servers, and it is advisable to set $| = 1
+#
+# Many thanks to Ed Jordan <ed@fidalgo.net> for this
+# contribution, updated by Andrew Benham (adsb@bigfoot.com)
+####
+'multipart_init' => <<'END_OF_FUNC',
+sub multipart_init {
+    my($self,@p) = self_or_default(@_);
+    my($boundary,@other) = rearrange([BOUNDARY],@p);
+    $boundary = $boundary || '------- =_aaaaaaaaaa0';
+    $self->{'separator'} = "$CRLF--$boundary$CRLF";
+    $self->{'final_separator'} = "$CRLF--$boundary--$CRLF";
+    $type = SERVER_PUSH($boundary);
+    return $self->header(
+	-nph => 1,
+	-type => $type,
+	(map { split "=", $_, 2 } @other),
+    ) . "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." . $self->multipart_end;
+}
+END_OF_FUNC
+
+
+#### Method: multipart_start
+# Return a Content-Type: style header for server-push, start of section
+#
+# Many thanks to Ed Jordan <ed@fidalgo.net> for this
+# contribution, updated by Andrew Benham (adsb@bigfoot.com)
+####
+'multipart_start' => <<'END_OF_FUNC',
+sub multipart_start {
+    my(@header);
+    my($self,@p) = self_or_default(@_);
+    my($type,@other) = rearrange([TYPE],@p);
+    $type = $type || 'text/html';
+    push(@header,"Content-Type: $type");
+
+    # rearrange() was designed for the HTML portion, so we
+    # need to fix it up a little.
+    foreach (@other) {
+        next unless my($header,$value) = /([^\s=]+)=\"?(.+?)\"?$/;
+	($_ = $header) =~ s/^(\w)(.*)/$1 . lc ($2) . ': '.$self->unescapeHTML($value)/e;
+    }
+    push(@header,@other);
+    my $header = join($CRLF,@header)."${CRLF}${CRLF}";
+    return $header;
+}
+END_OF_FUNC
+
+
+#### Method: multipart_end
+# Return a MIME boundary separator for server-push, end of section
+#
+# Many thanks to Ed Jordan <ed@fidalgo.net> for this
+# contribution
+####
+'multipart_end' => <<'END_OF_FUNC',
+sub multipart_end {
+    my($self,@p) = self_or_default(@_);
+    return $self->{'separator'};
+}
+END_OF_FUNC
+
+
+#### Method: multipart_final
+# Return a MIME boundary separator for server-push, end of all sections
+#
+# Contributed by Andrew Benham (adsb@bigfoot.com)
+####
+'multipart_final' => <<'END_OF_FUNC',
+sub multipart_final {
+    my($self,@p) = self_or_default(@_);
+    return $self->{'final_separator'} . "WARNING: YOUR BROWSER DOESN'T SUPPORT THIS SERVER-PUSH TECHNOLOGY." . $CRLF;
+}
+END_OF_FUNC
+
+
+#### Method: header
+# Return a Content-Type: style header
+#
+####
+'header' => <<'END_OF_FUNC',
+sub header {
+    my($self,@p) = self_or_default(@_);
+    my(@header);
+
+    return undef if $self->{'.header_printed'}++ and $HEADERS_ONCE;
+
+    my($type,$status,$cookie,$target,$expires,$nph,$charset,$attachment,@other) = 
+	rearrange([['TYPE','CONTENT_TYPE','CONTENT-TYPE'],
+			    'STATUS',['COOKIE','COOKIES'],'TARGET',
+                            'EXPIRES','NPH','CHARSET',
+                            'ATTACHMENT'],@p);
+
+    $nph     ||= $NPH;
+    if (defined $charset) {
+      $self->charset($charset);
+    } else {
+      $charset = $self->charset;
+    }
+
+    # rearrange() was designed for the HTML portion, so we
+    # need to fix it up a little.
+    foreach (@other) {
+        next unless my($header,$value) = /([^\s=]+)=\"?(.+?)\"?$/;
+	($_ = $header) =~ s/^(\w)(.*)/$1 . lc ($2) . ': '.$self->unescapeHTML($value)/e;
+        $header = ucfirst($header);
+    }
+
+    $type ||= 'text/html' unless defined($type);
+    $type .= "; charset=$charset" if $type ne '' and $type =~ m!^text/! and $type !~ /\bcharset\b/;
+
+    # Maybe future compatibility.  Maybe not.
+    my $protocol = $ENV{SERVER_PROTOCOL} || 'HTTP/1.0';
+    push(@header,$protocol . ' ' . ($status || '200 OK')) if $nph;
+    push(@header,"Server: " . &server_software()) if $nph;
+
+    push(@header,"Status: $status") if $status;
+    push(@header,"Window-Target: $target") if $target;
+    # push all the cookies -- there may be several
+    if ($cookie) {
+	my(@cookie) = ref($cookie) && ref($cookie) eq 'ARRAY' ? @{$cookie} : $cookie;
+	foreach (@cookie) {
+            my $cs = UNIVERSAL::isa($_,'CGI::Cookie') ? $_->as_string : $_;
+	    push(@header,"Set-Cookie: $cs") if $cs ne '';
+	}
+    }
+    # if the user indicates an expiration time, then we need
+    # both an Expires and a Date header (so that the browser is
+    # uses OUR clock)
+    push(@header,"Expires: " . expires($expires,'http'))
+	if $expires;
+    push(@header,"Date: " . expires(0,'http')) if $expires || $cookie || $nph;
+    push(@header,"Pragma: no-cache") if $self->cache();
+    push(@header,"Content-Disposition: attachment; filename=\"$attachment\"") if $attachment;
+    push(@header,map {ucfirst $_} @other);
+    push(@header,"Content-Type: $type") if $type ne '';
+
+    my $header = join($CRLF,@header)."${CRLF}${CRLF}";
+    if ($MOD_PERL and not $nph) {
+	my $r = Apache->request;
+	$r->send_cgi_header($header);
+	return '';
+    }
+    return $header;
+}
+END_OF_FUNC
+
+
+#### Method: cache
+# Control whether header() will produce the no-cache
+# Pragma directive.
+####
+'cache' => <<'END_OF_FUNC',
+sub cache {
+    my($self,$new_value) = self_or_default(@_);
+    $new_value = '' unless $new_value;
+    if ($new_value ne '') {
+	$self->{'cache'} = $new_value;
+    }
+    return $self->{'cache'};
+}
+END_OF_FUNC
+
+
+#### Method: redirect
+# Return a Location: style header
+#
+####
+'redirect' => <<'END_OF_FUNC',
+sub redirect {
+    my($self,@p) = self_or_default(@_);
+    my($url,$target,$cookie,$nph,@other) = rearrange([[LOCATION,URI,URL],TARGET,COOKIE,NPH],@p);
+    $url ||= $self->self_url;
+    my(@o);
+    foreach (@other) { tr/\"//d; push(@o,split("=",$_,2)); }
+    unshift(@o,
+	 '-Status'=>'302 Moved',
+	 '-Location'=>$url,
+	 '-nph'=>$nph);
+    unshift(@o,'-Target'=>$target) if $target;
+    unshift(@o,'-Cookie'=>$cookie) if $cookie;
+    unshift(@o,'-Type'=>'');
+    return $self->header(@o);
+}
+END_OF_FUNC
+
+
+#### Method: start_html
+# Canned HTML header
+#
+# Parameters:
+# $title -> (optional) The title for this HTML document (-title)
+# $author -> (optional) e-mail address of the author (-author)
+# $base -> (optional) if set to true, will enter the BASE address of this document
+#          for resolving relative references (-base) 
+# $xbase -> (optional) alternative base at some remote location (-xbase)
+# $target -> (optional) target window to load all links into (-target)
+# $script -> (option) Javascript code (-script)
+# $no_script -> (option) Javascript <noscript> tag (-noscript)
+# $meta -> (optional) Meta information tags
+# $head -> (optional) any other elements you'd like to incorporate into the <head> tag
+#           (a scalar or array ref)
+# $style -> (optional) reference to an external style sheet
+# @other -> (optional) any other named parameters you'd like to incorporate into
+#           the <body> tag.
+####
+'start_html' => <<'END_OF_FUNC',
+sub start_html {
+    my($self,@p) = &self_or_default(@_);
+    my($title,$author,$base,$xbase,$script,$noscript,
+        $target,$meta,$head,$style,$dtd,$lang,$encoding,@other) = 
+	rearrange([TITLE,AUTHOR,BASE,XBASE,SCRIPT,NOSCRIPT,TARGET,META,HEAD,STYLE,DTD,LANG,ENCODING],@p);
+
+    $encoding = 'iso-8859-1' unless defined $encoding;
+
+    # strangely enough, the title needs to be escaped as HTML
+    # while the author needs to be escaped as a URL
+    $title = $self->escapeHTML($title || 'Untitled Document');
+    $author = $self->escape($author);
+    $lang ||= 'en-US';
+    my(@result,$xml_dtd);
+    if ($dtd) {
+        if (defined(ref($dtd)) and (ref($dtd) eq 'ARRAY')) {
+            $dtd = $DEFAULT_DTD unless $dtd->[0] =~ m|^-//|;
+        } else {
+            $dtd = $DEFAULT_DTD unless $dtd =~ m|^-//|;
+        }
+    } else {
+        $dtd = $XHTML ? XHTML_DTD : $DEFAULT_DTD;
+    }
+
+    $xml_dtd++ if ref($dtd) eq 'ARRAY' && $dtd->[0] =~ /\bXHTML\b/i;
+    $xml_dtd++ if ref($dtd) eq '' && $dtd =~ /\bXHTML\b/i;
+    push @result,qq(<?xml version="1.0" encoding="$encoding"?>) if $xml_dtd; 
+
+    if (ref($dtd) && ref($dtd) eq 'ARRAY') {
+        push(@result,qq(<!DOCTYPE html\n\tPUBLIC "$dtd->[0]"\n\t "$dtd->[1]">));
+    } else {
+        push(@result,qq(<!DOCTYPE html\n\tPUBLIC "$dtd">));
+    }
+    push(@result,$XHTML ? qq(<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang"><head><title>$title</title>)
+                        : qq(<html lang="$lang"><head><title>$title</title>));
+	if (defined $author) {
+    push(@result,$XHTML ? "<link rev=\"made\" href=\"mailto:$author\" />"
+								: "<link rev=\"made\" href=\"mailto:$author\">");
+	}
+
+    if ($base || $xbase || $target) {
+	my $href = $xbase || $self->url('-path'=>1);
+	my $t = $target ? qq/ target="$target"/ : '';
+	push(@result,$XHTML ? qq(<base href="$href"$t />) : qq(<base href="$href"$t>));
+    }
+
+    if ($meta && ref($meta) && (ref($meta) eq 'HASH')) {
+	foreach (keys %$meta) { push(@result,$XHTML ? qq(<meta name="$_" content="$meta->{$_}" />) 
+			: qq(<meta name="$_" content="$meta->{$_}">)); }
+    }
+
+    push(@result,ref($head) ? @$head : $head) if $head;
+
+    # handle the infrequently-used -style and -script parameters
+    push(@result,$self->_style($style)) if defined $style;
+    push(@result,$self->_script($script)) if defined $script;
+
+    # handle -noscript parameter
+    push(@result,<<END) if $noscript;
+<noscript>
+$noscript
+</noscript>
+END
+    ;
+    my($other) = @other ? " @other" : '';
+    push(@result,"</head><body$other>");
+    return join("\n",@result);
+}
+END_OF_FUNC
+
+### Method: _style
+# internal method for generating a CSS style section
+####
+'_style' => <<'END_OF_FUNC',
+sub _style {
+    my ($self,$style) = @_;
+    my (@result);
+    my $type = 'text/css';
+
+    my $cdata_start = $XHTML ? "\n<!--/* <![CDATA[ */" : "\n<!-- ";
+    my $cdata_end   = $XHTML ? "\n/* ]]> */-->\n" : " -->\n";
+
+    if (ref($style)) {
+     my($src,$code,$stype,@other) =
+         rearrange([SRC,CODE,TYPE],
+                    '-foo'=>'bar', # a trick to allow the '-' to be omitted
+                    ref($style) eq 'ARRAY' ? @$style : %$style);
+     $type = $stype if $stype;
+     if (ref($src) eq "ARRAY") # Check to see if the $src variable is an array reference
+     { # If it is, push a LINK tag for each one.
+       foreach $src (@$src)
+       {
+         push(@result,$XHTML ? qq(<link rel="stylesheet" type="$type" href="$src" />)
+                             : qq(<link rel="stylesheet" type="$type" href="$src">)) if $src;
+       }
+     }
+     else
+     { # Otherwise, push the single -src, if it exists.
+       push(@result,$XHTML ? qq(<link rel="stylesheet" type="$type" href="$src" />)
+                           : qq(<link rel="stylesheet" type="$type" href="$src">)
+            ) if $src;
+      }
+     push(@result,style({'type'=>$type},"$cdata_start\n$code\n$cdata_end")) if $code;
+    } else {
+     push(@result,style({'type'=>$type},"$cdata_start\n$style\n$cdata_end"));
+    }
+    @result;
+}
+END_OF_FUNC
+
+'_script' => <<'END_OF_FUNC',
+sub _script {
+    my ($self,$script) = @_;
+    my (@result);
+
+    my (@scripts) = ref($script) eq 'ARRAY' ? @$script : ($script);
+    foreach $script (@scripts) {
+	my($src,$code,$language);
+	if (ref($script)) { # script is a hash
+	    ($src,$code,$language, $type) =
+		rearrange([SRC,CODE,LANGUAGE,TYPE],
+				 '-foo'=>'bar',	# a trick to allow the '-' to be omitted
+				 ref($script) eq 'ARRAY' ? @$script : %$script);
+            # User may not have specified language
+            $language ||= 'JavaScript';
+            unless (defined $type) {
+                $type = lc $language;
+                # strip '1.2' from 'javascript1.2'
+                $type =~ s/^(\D+).*$/text\/$1/;
+            }
+	} else {
+	    ($src,$code,$language, $type) = ('',$script,'JavaScript', 'text/javascript');
+	}
+
+    my $comment = '//';  # javascript by default
+    $comment = '#' if $type=~/perl|tcl/i;
+    $comment = "'" if $type=~/vbscript/i;
+
+    my $cdata_start  =  "\n<!-- Hide script\n";
+    $cdata_start    .= "$comment<![CDATA[\n"  if $XHTML; 
+    my $cdata_end    = $XHTML ? "\n$comment]]>" : $comment;
+    $cdata_end      .= " End script hiding -->\n";
+
+	my(@satts);
+	push(@satts,'src'=>$src) if $src;
+	push(@satts,'language'=>$language);
+        push(@satts,'type'=>$type);
+	$code = "$cdata_start$code$cdata_end" if defined $code;
+	push(@result,script({@satts},$code || ''));
+    }
+    @result;
+}
+END_OF_FUNC
+
+#### Method: end_html
+# End an HTML document.
+# Trivial method for completeness.  Just returns "</body>"
+####
+'end_html' => <<'END_OF_FUNC',
+sub end_html {
+    return "</body></html>";
+}
+END_OF_FUNC
+
+
+################################
+# METHODS USED IN BUILDING FORMS
+################################
+
+#### Method: isindex
+# Just prints out the isindex tag.
+# Parameters:
+#  $action -> optional URL of script to run
+# Returns:
+#   A string containing a <ISINDEX> tag
+'isindex' => <<'END_OF_FUNC',
+sub isindex {
+    my($self,@p) = self_or_default(@_);
+    my($action,@other) = rearrange([ACTION],@p);
+    $action = qq/action="$action"/ if $action;
+    my($other) = @other ? " @other" : '';
+    return $XHTML ? "<isindex $action$other />" : "<isindex $action$other>";
+}
+END_OF_FUNC
+
+
+#### Method: startform
+# Start a form
+# Parameters:
+#   $method -> optional submission method to use (GET or POST)
+#   $action -> optional URL of script to run
+#   $enctype ->encoding to use (URL_ENCODED or MULTIPART)
+'startform' => <<'END_OF_FUNC',
+sub startform {
+    my($self,@p) = self_or_default(@_);
+
+    my($method,$action,$enctype,@other) = 
+	rearrange([METHOD,ACTION,ENCTYPE],@p);
+
+    $method = lc($method) || 'post';
+    $enctype = $enctype || &URL_ENCODED;
+    unless (defined $action) {
+       $action = $self->url(-absolute=>1,-path=>1);
+       $action .= "?$ENV{QUERY_STRING}" if $ENV{QUERY_STRING};
+    }
+    $action = qq(action="$action");
+    my($other) = @other ? " @other" : '';
+    $self->{'.parametersToAdd'}={};
+    return qq/<form method="$method" $action enctype="$enctype"$other>\n/;
+}
+END_OF_FUNC
+
+
+#### Method: start_form
+# synonym for startform
+'start_form' => <<'END_OF_FUNC',
+sub start_form {
+    &startform;
+}
+END_OF_FUNC
+
+'end_multipart_form' => <<'END_OF_FUNC',
+sub end_multipart_form {
+    &endform;
+}
+END_OF_FUNC
+
+#### Method: start_multipart_form
+# synonym for startform
+'start_multipart_form' => <<'END_OF_FUNC',
+sub start_multipart_form {
+    my($self,@p) = self_or_default(@_);
+    if (defined($param[0]) && substr($param[0],0,1) eq '-') {
+	my(%p) = @p;
+	$p{'-enctype'}=&MULTIPART;
+	return $self->startform(%p);
+    } else {
+	my($method,$action,@other) = 
+	    rearrange([METHOD,ACTION],@p);
+	return $self->startform($method,$action,&MULTIPART,@other);
+    }
+}
+END_OF_FUNC
+
+
+#### Method: endform
+# End a form
+'endform' => <<'END_OF_FUNC',
+sub endform {
+    my($self,@p) = self_or_default(@_);    
+    if ( $NOSTICKY ) {
+    return wantarray ? ("</form>") : "\n</form>";
+    } else {
+    return wantarray ? ($self->get_fields,"</form>") : 
+                        $self->get_fields ."\n</form>";
+    }
+}
+END_OF_FUNC
+
+
+#### Method: end_form
+# synonym for endform
+'end_form' => <<'END_OF_FUNC',
+sub end_form {
+    &endform;
+}
+END_OF_FUNC
+
+
+'_textfield' => <<'END_OF_FUNC',
+sub _textfield {
+    my($self,$tag,@p) = self_or_default(@_);
+    my($name,$default,$size,$maxlength,$override,@other) = 
+	rearrange([NAME,[DEFAULT,VALUE],SIZE,MAXLENGTH,[OVERRIDE,FORCE]],@p);
+
+    my $current = $override ? $default : 
+	(defined($self->param($name)) ? $self->param($name) : $default);
+
+    $current = defined($current) ? $self->escapeHTML($current,1) : '';
+    $name = defined($name) ? $self->escapeHTML($name) : '';
+    my($s) = defined($size) ? qq/ size="$size"/ : '';
+    my($m) = defined($maxlength) ? qq/ maxlength="$maxlength"/ : '';
+    my($other) = @other ? " @other" : '';
+    # this entered at cristy's request to fix problems with file upload fields
+    # and WebTV -- not sure it won't break stuff
+    my($value) = $current ne '' ? qq(value="$current") : '';
+    return $XHTML ? qq(<input type="$tag" name="$name" $value$s$m$other />) 
+                  : qq(<input type="$tag" name="$name" $value$s$m$other>);
+}
+END_OF_FUNC
+
+#### Method: textfield
+# Parameters:
+#   $name -> Name of the text field
+#   $default -> Optional default value of the field if not
+#                already defined.
+#   $size ->  Optional width of field in characaters.
+#   $maxlength -> Optional maximum number of characters.
+# Returns:
+#   A string containing a <INPUT TYPE="text"> field
+#
+'textfield' => <<'END_OF_FUNC',
+sub textfield {
+    my($self,@p) = self_or_default(@_);
+    $self->_textfield('text',@p);
+}
+END_OF_FUNC
+
+
+#### Method: filefield
+# Parameters:
+#   $name -> Name of the file upload field
+#   $size ->  Optional width of field in characaters.
+#   $maxlength -> Optional maximum number of characters.
+# Returns:
+#   A string containing a <INPUT TYPE="text"> field
+#
+'filefield' => <<'END_OF_FUNC',
+sub filefield {
+    my($self,@p) = self_or_default(@_);
+    $self->_textfield('file',@p);
+}
+END_OF_FUNC
+
+
+#### Method: password
+# Create a "secret password" entry field
+# Parameters:
+#   $name -> Name of the field
+#   $default -> Optional default value of the field if not
+#                already defined.
+#   $size ->  Optional width of field in characters.
+#   $maxlength -> Optional maximum characters that can be entered.
+# Returns:
+#   A string containing a <INPUT TYPE="password"> field
+#
+'password_field' => <<'END_OF_FUNC',
+sub password_field {
+    my ($self,@p) = self_or_default(@_);
+    $self->_textfield('password',@p);
+}
+END_OF_FUNC
+
+#### Method: textarea
+# Parameters:
+#   $name -> Name of the text field
+#   $default -> Optional default value of the field if not
+#                already defined.
+#   $rows ->  Optional number of rows in text area
+#   $columns -> Optional number of columns in text area
+# Returns:
+#   A string containing a <textarea></textarea> tag
+#
+'textarea' => <<'END_OF_FUNC',
+sub textarea {
+    my($self,@p) = self_or_default(@_);
+    
+    my($name,$default,$rows,$cols,$override,@other) =
+	rearrange([NAME,[DEFAULT,VALUE],ROWS,[COLS,COLUMNS],[OVERRIDE,FORCE]],@p);
+
+    my($current)= $override ? $default :
+	(defined($self->param($name)) ? $self->param($name) : $default);
+
+    $name = defined($name) ? $self->escapeHTML($name) : '';
+    $current = defined($current) ? $self->escapeHTML($current) : '';
+    my($r) = $rows ? qq/ rows="$rows"/ : '';
+    my($c) = $cols ? qq/ cols="$cols"/ : '';
+    my($other) = @other ? " @other" : '';
+    return qq{<textarea name="$name"$r$c$other>$current</textarea>};
+}
+END_OF_FUNC
+
+
+#### Method: button
+# Create a javascript button.
+# Parameters:
+#   $name ->  (optional) Name for the button. (-name)
+#   $value -> (optional) Value of the button when selected (and visible name) (-value)
+#   $onclick -> (optional) Text of the JavaScript to run when the button is
+#                clicked.
+# Returns:
+#   A string containing a <INPUT TYPE="button"> tag
+####
+'button' => <<'END_OF_FUNC',
+sub button {
+    my($self,@p) = self_or_default(@_);
+
+    my($label,$value,$script,@other) = rearrange([NAME,[VALUE,LABEL],
+							 [ONCLICK,SCRIPT]],@p);
+
+    $label=$self->escapeHTML($label);
+    $value=$self->escapeHTML($value,1);
+    $script=$self->escapeHTML($script);
+
+    my($name) = '';
+    $name = qq/ name="$label"/ if $label;
+    $value = $value || $label;
+    my($val) = '';
+    $val = qq/ value="$value"/ if $value;
+    $script = qq/ onclick="$script"/ if $script;
+    my($other) = @other ? " @other" : '';
+    return $XHTML ? qq(<input type="button"$name$val$script$other />)
+                  : qq(<input type="button"$name$val$script$other>);
+}
+END_OF_FUNC
+
+
+#### Method: submit
+# Create a "submit query" button.
+# Parameters:
+#   $name ->  (optional) Name for the button.
+#   $value -> (optional) Value of the button when selected (also doubles as label).
+#   $label -> (optional) Label printed on the button(also doubles as the value).
+# Returns:
+#   A string containing a <INPUT TYPE="submit"> tag
+####
+'submit' => <<'END_OF_FUNC',
+sub submit {
+    my($self,@p) = self_or_default(@_);
+
+    my($label,$value,@other) = rearrange([NAME,[VALUE,LABEL]],@p);
+
+    $label=$self->escapeHTML($label);
+    $value=$self->escapeHTML($value,1);
+
+    my($name) = ' name=".submit"' unless $NOSTICKY;
+    $name = qq/ name="$label"/ if defined($label);
+    $value = defined($value) ? $value : $label;
+    my($val) = '';
+    $val = qq/ value="$value"/ if defined($value);
+    my($other) = @other ? " @other" : '';
+    return $XHTML ? qq(<input type="submit"$name$val$other />)
+                  : qq(<input type="submit"$name$val$other>);
+}
+END_OF_FUNC
+
+
+#### Method: reset
+# Create a "reset" button.
+# Parameters:
+#   $name -> (optional) Name for the button.
+# Returns:
+#   A string containing a <INPUT TYPE="reset"> tag
+####
+'reset' => <<'END_OF_FUNC',
+sub reset {
+    my($self,@p) = self_or_default(@_);
+    my($label,@other) = rearrange([NAME],@p);
+    $label=$self->escapeHTML($label);
+    my($value) = defined($label) ? qq/ value="$label"/ : '';
+    my($other) = @other ? " @other" : '';
+    return $XHTML ? qq(<input type="reset"$value$other />)
+                  : qq(<input type="reset"$value$other>);
+}
+END_OF_FUNC
+
+
+#### Method: defaults
+# Create a "defaults" button.
+# Parameters:
+#   $name -> (optional) Name for the button.
+# Returns:
+#   A string containing a <INPUT TYPE="submit" NAME=".defaults"> tag
+#
+# Note: this button has a special meaning to the initialization script,
+# and tells it to ERASE the current query string so that your defaults
+# are used again!
+####
+'defaults' => <<'END_OF_FUNC',
+sub defaults {
+    my($self,@p) = self_or_default(@_);
+
+    my($label,@other) = rearrange([[NAME,VALUE]],@p);
+
+    $label=$self->escapeHTML($label,1);
+    $label = $label || "Defaults";
+    my($value) = qq/ value="$label"/;
+    my($other) = @other ? " @other" : '';
+    return $XHTML ? qq(<input type="submit" name=".defaults"$value$other />)
+                  : qq/<input type="submit" NAME=".defaults"$value$other>/;
+}
+END_OF_FUNC
+
+
+#### Method: comment
+# Create an HTML <!-- comment -->
+# Parameters: a string
+'comment' => <<'END_OF_FUNC',
+sub comment {
+    my($self,@p) = self_or_CGI(@_);
+    return "<!-- @p -->";
+}
+END_OF_FUNC
+
+#### Method: checkbox
+# Create a checkbox that is not logically linked to any others.
+# The field value is "on" when the button is checked.
+# Parameters:
+#   $name -> Name of the checkbox
+#   $checked -> (optional) turned on by default if true
+#   $value -> (optional) value of the checkbox, 'on' by default
+#   $label -> (optional) a user-readable label printed next to the box.
+#             Otherwise the checkbox name is used.
+# Returns:
+#   A string containing a <INPUT TYPE="checkbox"> field
+####
+'checkbox' => <<'END_OF_FUNC',
+sub checkbox {
+    my($self,@p) = self_or_default(@_);
+
+    my($name,$checked,$value,$label,$override,@other) = 
+	rearrange([NAME,[CHECKED,SELECTED,ON],VALUE,LABEL,[OVERRIDE,FORCE]],@p);
+    
+    $value = defined $value ? $value : 'on';
+
+    if (!$override && ($self->{'.fieldnames'}->{$name} || 
+		       defined $self->param($name))) {
+	$checked = grep($_ eq $value,$self->param($name)) ? $self->_checked(1) : '';
+    } else {
+	$checked = $self->_checked($checked);
+    }
+    my($the_label) = defined $label ? $label : $name;
+    $name = $self->escapeHTML($name);
+    $value = $self->escapeHTML($value,1);
+    $the_label = $self->escapeHTML($the_label);
+    my($other) = @other ? " @other" : '';
+    $self->register_parameter($name);
+    return $XHTML ? qq{<input type="checkbox" name="$name" value="$value"$checked$other />$the_label}
+                  : qq{<input type="checkbox" name="$name" value="$value"$checked$other>$the_label};
+}
+END_OF_FUNC
+
+
+#### Method: checkbox_group
+# Create a list of logically-linked checkboxes.
+# Parameters:
+#   $name -> Common name for all the check boxes
+#   $values -> A pointer to a regular array containing the
+#             values for each checkbox in the group.
+#   $defaults -> (optional)
+#             1. If a pointer to a regular array of checkbox values,
+#             then this will be used to decide which
+#             checkboxes to turn on by default.
+#             2. If a scalar, will be assumed to hold the
+#             value of a single checkbox in the group to turn on. 
+#   $linebreak -> (optional) Set to true to place linebreaks
+#             between the buttons.
+#   $labels -> (optional)
+#             A pointer to an associative array of labels to print next to each checkbox
+#             in the form $label{'value'}="Long explanatory label".
+#             Otherwise the provided values are used as the labels.
+# Returns:
+#   An ARRAY containing a series of <INPUT TYPE="checkbox"> fields
+####
+'checkbox_group' => <<'END_OF_FUNC',
+sub checkbox_group {
+    my($self,@p) = self_or_default(@_);
+
+    my($name,$values,$defaults,$linebreak,$labels,$rows,$columns,
+       $rowheaders,$colheaders,$override,$nolabels,@other) =
+	rearrange([NAME,[VALUES,VALUE],[DEFAULTS,DEFAULT],
+			  LINEBREAK,LABELS,ROWS,[COLUMNS,COLS],
+			  ROWHEADERS,COLHEADERS,
+			  [OVERRIDE,FORCE],NOLABELS],@p);
+
+    my($checked,$break,$result,$label);
+
+    my(%checked) = $self->previous_or_default($name,$defaults,$override);
+
+	if ($linebreak) {
+    $break = $XHTML ? "<br />" : "<br>";
+	}
+	else {
+	$break = '';
+	}
+    $name=$self->escapeHTML($name);
+
+    # Create the elements
+    my(@elements,@values);
+
+    @values = $self->_set_values_and_labels($values,\$labels,$name);
+
+    my($other) = @other ? " @other" : '';
+    foreach (@values) {
+	$checked = $self->_checked($checked{$_});
+	$label = '';
+	unless (defined($nolabels) && $nolabels) {
+	    $label = $_;
+	    $label = $labels->{$_} if defined($labels) && defined($labels->{$_});
+	    $label = $self->escapeHTML($label);
+	}
+	$_ = $self->escapeHTML($_,1);
+	push(@elements,$XHTML ? qq(<input type="checkbox" name="$name" value="$_"$checked$other />${label}${break})
+                              : qq/<input type="checkbox" name="$name" value="$_"$checked$other>${label}${break}/);
+    }
+    $self->register_parameter($name);
+    return wantarray ? @elements : join(' ',@elements)            
+        unless defined($columns) || defined($rows);
+    return _tableize($rows,$columns,$rowheaders,$colheaders,@elements);
+}
+END_OF_FUNC
+
+# Escape HTML -- used internally
+'escapeHTML' => <<'END_OF_FUNC',
+sub escapeHTML {
+         # hack to work around  earlier hacks
+         push @_,$_[0] if @_==1 && $_[0] eq 'CGI';
+         my ($self,$toencode,$newlinestoo) = CGI::self_or_default(@_);
+         return undef unless defined($toencode);
+         return $toencode if ref($self) && $self->{'dontescape'};
+         $toencode =~ s{&}{&amp;}gso;
+         $toencode =~ s{<}{&lt;}gso;
+         $toencode =~ s{>}{&gt;}gso;
+         $toencode =~ s{"}{&quot;}gso;
+         my $latin = uc $self->{'.charset'} eq 'ISO-8859-1' ||
+                     uc $self->{'.charset'} eq 'WINDOWS-1252';
+         if ($latin) {  # bug in some browsers
+                $toencode =~ s{'}{&#39;}gso;
+                $toencode =~ s{\x8b}{&#139;}gso;
+                $toencode =~ s{\x9b}{&#155;}gso;
+                if (defined $newlinestoo && $newlinestoo) {
+                     $toencode =~ s{\012}{&#10;}gso;
+                     $toencode =~ s{\015}{&#13;}gso;
+                }
+         }
+         return $toencode;
+}
+END_OF_FUNC
+
+# unescape HTML -- used internally
+'unescapeHTML' => <<'END_OF_FUNC',
+sub unescapeHTML {
+    my ($self,$string) = CGI::self_or_default(@_);
+    return undef unless defined($string);
+    my $latin = defined $self->{'.charset'} ? $self->{'.charset'} =~ /^(ISO-8859-1|WINDOWS-1252)$/i
+                                            : 1;
+    # thanks to Randal Schwartz for the correct solution to this one
+    $string=~ s[&(.*?);]{
+	local $_ = $1;
+	/^amp$/i	? "&" :
+	/^quot$/i	? '"' :
+        /^gt$/i		? ">" :
+	/^lt$/i		? "<" :
+	/^#(\d+)$/ && $latin	     ? chr($1) :
+	/^#x([0-9a-f]+)$/i && $latin ? chr(hex($1)) :
+	$_
+	}gex;
+    return $string;
+}
+END_OF_FUNC
+
+# Internal procedure - don't use
+'_tableize' => <<'END_OF_FUNC',
+sub _tableize {
+    my($rows,$columns,$rowheaders,$colheaders,@elements) = @_;
+    $rowheaders = [] unless defined $rowheaders;
+    $colheaders = [] unless defined $colheaders;
+    my($result);
+
+    if (defined($columns)) {
+	$rows = int(0.99 + @elements/$columns) unless defined($rows);
+    }
+    if (defined($rows)) {
+	$columns = int(0.99 + @elements/$rows) unless defined($columns);
+    }
+    
+    # rearrange into a pretty table
+    $result = "<table>";
+    my($row,$column);
+    unshift(@$colheaders,'') if @$colheaders && @$rowheaders;
+    $result .= "<tr>" if @{$colheaders};
+    foreach (@{$colheaders}) {
+	$result .= "<th>$_</th>";
+    }
+    for ($row=0;$row<$rows;$row++) {
+	$result .= "<tr>";
+	$result .= "<th>$rowheaders->[$row]</th>" if @$rowheaders;
+	for ($column=0;$column<$columns;$column++) {
+	    $result .= "<td>" . $elements[$column*$rows + $row] . "</td>"
+		if defined($elements[$column*$rows + $row]);
+	}
+	$result .= "</tr>";
+    }
+    $result .= "</table>";
+    return $result;
+}
+END_OF_FUNC
+
+
+#### Method: radio_group
+# Create a list of logically-linked radio buttons.
+# Parameters:
+#   $name -> Common name for all the buttons.
+#   $values -> A pointer to a regular array containing the
+#             values for each button in the group.
+#   $default -> (optional) Value of the button to turn on by default.  Pass '-'
+#               to turn _nothing_ on.
+#   $linebreak -> (optional) Set to true to place linebreaks
+#             between the buttons.
+#   $labels -> (optional)
+#             A pointer to an associative array of labels to print next to each checkbox
+#             in the form $label{'value'}="Long explanatory label".
+#             Otherwise the provided values are used as the labels.
+# Returns:
+#   An ARRAY containing a series of <INPUT TYPE="radio"> fields
+####
+'radio_group' => <<'END_OF_FUNC',
+sub radio_group {
+    my($self,@p) = self_or_default(@_);
+
+    my($name,$values,$default,$linebreak,$labels,
+       $rows,$columns,$rowheaders,$colheaders,$override,$nolabels,@other) =
+	rearrange([NAME,[VALUES,VALUE],DEFAULT,LINEBREAK,LABELS,
+			  ROWS,[COLUMNS,COLS],
+			  ROWHEADERS,COLHEADERS,
+			  [OVERRIDE,FORCE],NOLABELS],@p);
+    my($result,$checked);
+
+    if (!$override && defined($self->param($name))) {
+	$checked = $self->param($name);
+    } else {
+	$checked = $default;
+    }
+    my(@elements,@values);
+    @values = $self->_set_values_and_labels($values,\$labels,$name);
+
+    # If no check array is specified, check the first by default
+    $checked = $values[0] unless defined($checked) && $checked ne '';
+    $name=$self->escapeHTML($name);
+
+    my($other) = @other ? " @other" : '';
+    foreach (@values) {
+	my($checkit) = $checked eq $_ ? qq/ checked="checked"/ : '';
+	my($break);
+	if ($linebreak) {
+          $break = $XHTML ? "<br />" : "<br>";
+	}
+	else {
+	  $break = '';
+	}
+	my($label)='';
+	unless (defined($nolabels) && $nolabels) {
+	    $label = $_;
+	    $label = $labels->{$_} if defined($labels) && defined($labels->{$_});
+	    $label = $self->escapeHTML($label,1);
+	}
+	$_=$self->escapeHTML($_);
+	push(@elements,$XHTML ? qq(<input type="radio" name="$name" value="$_"$checkit$other />${label}${break})
+                              : qq/<input type="radio" name="$name" value="$_"$checkit$other>${label}${break}/);
+    }
+    $self->register_parameter($name);
+    return wantarray ? @elements : join(' ',@elements) 
+           unless defined($columns) || defined($rows);
+    return _tableize($rows,$columns,$rowheaders,$colheaders,@elements);
+}
+END_OF_FUNC
+
+
+#### Method: popup_menu
+# Create a popup menu.
+# Parameters:
+#   $name -> Name for all the menu
+#   $values -> A pointer to a regular array containing the
+#             text of each menu item.
+#   $default -> (optional) Default item to display
+#   $labels -> (optional)
+#             A pointer to an associative array of labels to print next to each checkbox
+#             in the form $label{'value'}="Long explanatory label".
+#             Otherwise the provided values are used as the labels.
+# Returns:
+#   A string containing the definition of a popup menu.
+####
+'popup_menu' => <<'END_OF_FUNC',
+sub popup_menu {
+    my($self,@p) = self_or_default(@_);
+
+    my($name,$values,$default,$labels,$override,@other) =
+	rearrange([NAME,[VALUES,VALUE],[DEFAULT,DEFAULTS],LABELS,[OVERRIDE,FORCE]],@p);
+    my($result,$selected);
+
+    if (!$override && defined($self->param($name))) {
+	$selected = $self->param($name);
+    } else {
+	$selected = $default;
+    }
+    $name=$self->escapeHTML($name);
+    my($other) = @other ? " @other" : '';
+
+    my(@values);
+    @values = $self->_set_values_and_labels($values,\$labels,$name);
+
+    $result = qq/<select name="$name"$other>\n/;
+    foreach (@values) {
+	my($selectit) = defined($selected) ? $self->_selected($selected eq $_) : '';
+	my($label) = $_;
+	$label = $labels->{$_} if defined($labels) && defined($labels->{$_});
+	my($value) = $self->escapeHTML($_);
+	$label=$self->escapeHTML($label,1);
+	$result .= "<option$selectit value=\"$value\">$label</option>\n";
+    }
+
+    $result .= "</select>";
+    return $result;
+}
+END_OF_FUNC
+
+
+#### Method: scrolling_list
+# Create a scrolling list.
+# Parameters:
+#   $name -> name for the list
+#   $values -> A pointer to a regular array containing the
+#             values for each option line in the list.
+#   $defaults -> (optional)
+#             1. If a pointer to a regular array of options,
+#             then this will be used to decide which
+#             lines to turn on by default.
+#             2. Otherwise holds the value of the single line to turn on.
+#   $size -> (optional) Size of the list.
+#   $multiple -> (optional) If set, allow multiple selections.
+#   $labels -> (optional)
+#             A pointer to an associative array of labels to print next to each checkbox
+#             in the form $label{'value'}="Long explanatory label".
+#             Otherwise the provided values are used as the labels.
+# Returns:
+#   A string containing the definition of a scrolling list.
+####
+'scrolling_list' => <<'END_OF_FUNC',
+sub scrolling_list {
+    my($self,@p) = self_or_default(@_);
+    my($name,$values,$defaults,$size,$multiple,$labels,$override,@other)
+	= rearrange([NAME,[VALUES,VALUE],[DEFAULTS,DEFAULT],
+			    SIZE,MULTIPLE,LABELS,[OVERRIDE,FORCE]],@p);
+
+    my($result,@values);
+    @values = $self->_set_values_and_labels($values,\$labels,$name);
+
+    $size = $size || scalar(@values);
+
+    my(%selected) = $self->previous_or_default($name,$defaults,$override);
+    my($is_multiple) = $multiple ? qq/ multiple="multiple"/ : '';
+    my($has_size) = $size ? qq/ size="$size"/: '';
+    my($other) = @other ? " @other" : '';
+
+    $name=$self->escapeHTML($name);
+    $result = qq/<select name="$name"$has_size$is_multiple$other>\n/;
+    foreach (@values) {
+	my($selectit) = $self->_selected($selected{$_});
+	my($label) = $_;
+	$label = $labels->{$_} if defined($labels) && defined($labels->{$_});
+	$label=$self->escapeHTML($label);
+	my($value)=$self->escapeHTML($_,1);
+	$result .= "<option$selectit value=\"$value\">$label</option>\n";
+    }
+    $result .= "</select>";
+    $self->register_parameter($name);
+    return $result;
+}
+END_OF_FUNC
+
+
+#### Method: hidden
+# Parameters:
+#   $name -> Name of the hidden field
+#   @default -> (optional) Initial values of field (may be an array)
+#      or
+#   $default->[initial values of field]
+# Returns:
+#   A string containing a <INPUT TYPE="hidden" NAME="name" VALUE="value">
+####
+'hidden' => <<'END_OF_FUNC',
+sub hidden {
+    my($self,@p) = self_or_default(@_);
+
+    # this is the one place where we departed from our standard
+    # calling scheme, so we have to special-case (darn)
+    my(@result,@value);
+    my($name,$default,$override,@other) = 
+	rearrange([NAME,[DEFAULT,VALUE,VALUES],[OVERRIDE,FORCE]],@p);
+
+    my $do_override = 0;
+    if ( ref($p[0]) || substr($p[0],0,1) eq '-') {
+	@value = ref($default) ? @{$default} : $default;
+	$do_override = $override;
+    } else {
+	foreach ($default,$override,@other) {
+	    push(@value,$_) if defined($_);
+	}
+    }
+
+    # use previous values if override is not set
+    my @prev = $self->param($name);
+    @value = @prev if !$do_override && @prev;
+
+    $name=$self->escapeHTML($name);
+    foreach (@value) {
+	$_ = defined($_) ? $self->escapeHTML($_,1) : '';
+	push @result,$XHTML ? qq(<input type="hidden" name="$name" value="$_" />)
+                            : qq(<input type="hidden" name="$name" value="$_">);
+    }
+    return wantarray ? @result : join('',@result);
+}
+END_OF_FUNC
+
+
+#### Method: image_button
+# Parameters:
+#   $name -> Name of the button
+#   $src ->  URL of the image source
+#   $align -> Alignment style (TOP, BOTTOM or MIDDLE)
+# Returns:
+#   A string containing a <INPUT TYPE="image" NAME="name" SRC="url" ALIGN="alignment">
+####
+'image_button' => <<'END_OF_FUNC',
+sub image_button {
+    my($self,@p) = self_or_default(@_);
+
+    my($name,$src,$alignment,@other) =
+	rearrange([NAME,SRC,ALIGN],@p);
+
+    my($align) = $alignment ? " align=\U\"$alignment\"" : '';
+    my($other) = @other ? " @other" : '';
+    $name=$self->escapeHTML($name);
+    return $XHTML ? qq(<input type="image" name="$name" src="$src"$align$other />)
+                  : qq/<input type="image" name="$name" src="$src"$align$other>/;
+}
+END_OF_FUNC
+
+
+#### Method: self_url
+# Returns a URL containing the current script and all its
+# param/value pairs arranged as a query.  You can use this
+# to create a link that, when selected, will reinvoke the
+# script with all its state information preserved.
+####
+'self_url' => <<'END_OF_FUNC',
+sub self_url {
+    my($self,@p) = self_or_default(@_);
+    return $self->url('-path_info'=>1,'-query'=>1,'-full'=>1,@p);
+}
+END_OF_FUNC
+
+
+# This is provided as a synonym to self_url() for people unfortunate
+# enough to have incorporated it into their programs already!
+'state' => <<'END_OF_FUNC',
+sub state {
+    &self_url;
+}
+END_OF_FUNC
+
+
+#### Method: url
+# Like self_url, but doesn't return the query string part of
+# the URL.
+####
+'url' => <<'END_OF_FUNC',
+sub url {
+    my($self,@p) = self_or_default(@_);
+    my ($relative,$absolute,$full,$path_info,$query,$base) = 
+	rearrange(['RELATIVE','ABSOLUTE','FULL',['PATH','PATH_INFO'],['QUERY','QUERY_STRING'],'BASE'],@p);
+    my $url;
+    $full++      if $base || !($relative || $absolute);
+
+    my $path = $self->path_info;
+    my $script_name = $self->script_name;
+
+    # for compatibility with Apache's MultiViews
+    if (exists($ENV{REQUEST_URI})) {
+        my $index;
+	$script_name = $ENV{REQUEST_URI};
+        $script_name =~ s/\?.+$//;   # strip query string
+        # and path
+        if (exists($ENV{PATH_INFO})) {
+           (my $encoded_path = $ENV{PATH_INFO}) =~ s/([^a-zA-Z0-9_.%;&?\/\\:+=~-])/sprintf("%%%02X",ord($1))/eg;
+           $script_name      =~ s/$encoded_path$//i;
+         }
+    }
+
+    if ($full) {
+	my $protocol = $self->protocol();
+	$url = "$protocol://";
+	my $vh = http('host');
+	if ($vh) {
+	    $url .= $vh;
+	} else {
+	    $url .= server_name();
+	    my $port = $self->server_port;
+	    $url .= ":" . $port
+		unless (lc($protocol) eq 'http' && $port == 80)
+		    || (lc($protocol) eq 'https' && $port == 443);
+	}
+        return $url if $base;
+	$url .= $script_name;
+    } elsif ($relative) {
+	($url) = $script_name =~ m!([^/]+)$!;
+    } elsif ($absolute) {
+	$url = $script_name;
+    }
+
+    $url .= $path if $path_info and defined $path;
+    $url .= "?" . $self->query_string if $query and $self->query_string;
+    $url = '' unless defined $url;
+    $url =~ s/([^a-zA-Z0-9_.%;&?\/\\:+=~-])/sprintf("%%%02X",ord($1))/eg;
+    return $url;
+}
+
+END_OF_FUNC
+
+#### Method: cookie
+# Set or read a cookie from the specified name.
+# Cookie can then be passed to header().
+# Usual rules apply to the stickiness of -value.
+#  Parameters:
+#   -name -> name for this cookie (optional)
+#   -value -> value of this cookie (scalar, array or hash) 
+#   -path -> paths for which this cookie is valid (optional)
+#   -domain -> internet domain in which this cookie is valid (optional)
+#   -secure -> if true, cookie only passed through secure channel (optional)
+#   -expires -> expiry date in format Wdy, DD-Mon-YYYY HH:MM:SS GMT (optional)
+####
+'cookie' => <<'END_OF_FUNC',
+sub cookie {
+    my($self,@p) = self_or_default(@_);
+    my($name,$value,$path,$domain,$secure,$expires) =
+	rearrange([NAME,[VALUE,VALUES],PATH,DOMAIN,SECURE,EXPIRES],@p);
+
+    require CGI::Cookie;
+
+    # if no value is supplied, then we retrieve the
+    # value of the cookie, if any.  For efficiency, we cache the parsed
+    # cookies in our state variables.
+    unless ( defined($value) ) {
+	$self->{'.cookies'} = CGI::Cookie->fetch
+	    unless $self->{'.cookies'};
+
+	# If no name is supplied, then retrieve the names of all our cookies.
+	return () unless $self->{'.cookies'};
+	return keys %{$self->{'.cookies'}} unless $name;
+	return () unless $self->{'.cookies'}->{$name};
+	return $self->{'.cookies'}->{$name}->value if defined($name) && $name ne '';
+    }
+
+    # If we get here, we're creating a new cookie
+    return undef unless defined($name) && $name ne '';	# this is an error
+
+    my @param;
+    push(@param,'-name'=>$name);
+    push(@param,'-value'=>$value);
+    push(@param,'-domain'=>$domain) if $domain;
+    push(@param,'-path'=>$path) if $path;
+    push(@param,'-expires'=>$expires) if $expires;
+    push(@param,'-secure'=>$secure) if $secure;
+
+    return new CGI::Cookie(@param);
+}
+END_OF_FUNC
+
+'parse_keywordlist' => <<'END_OF_FUNC',
+sub parse_keywordlist {
+    my($self,$tosplit) = @_;
+    $tosplit = unescape($tosplit); # unescape the keywords
+    $tosplit=~tr/+/ /;          # pluses to spaces
+    my(@keywords) = split(/\s+/,$tosplit);
+    return @keywords;
+}
+END_OF_FUNC
+
+'param_fetch' => <<'END_OF_FUNC',
+sub param_fetch {
+    my($self,@p) = self_or_default(@_);
+    my($name) = rearrange([NAME],@p);
+    unless (exists($self->{$name})) {
+	$self->add_parameter($name);
+	$self->{$name} = [];
+    }
+    
+    return $self->{$name};
+}
+END_OF_FUNC
+
+###############################################
+# OTHER INFORMATION PROVIDED BY THE ENVIRONMENT
+###############################################
+
+#### Method: path_info
+# Return the extra virtual path information provided
+# after the URL (if any)
+####
+'path_info' => <<'END_OF_FUNC',
+sub path_info {
+    my ($self,$info) = self_or_default(@_);
+    if (defined($info)) {
+	$info = "/$info" if $info ne '' &&  substr($info,0,1) ne '/';
+	$self->{'.path_info'} = $info;
+    } elsif (! defined($self->{'.path_info'}) ) {
+	$self->{'.path_info'} = defined($ENV{'PATH_INFO'}) ? 
+	    $ENV{'PATH_INFO'} : '';
+
+	# hack to fix broken path info in IIS
+	$self->{'.path_info'} =~ s/^\Q$ENV{'SCRIPT_NAME'}\E// if $IIS;
+
+    }
+    return $self->{'.path_info'};
+}
+END_OF_FUNC
+
+
+#### Method: request_method
+# Returns 'POST', 'GET', 'PUT' or 'HEAD'
+####
+'request_method' => <<'END_OF_FUNC',
+sub request_method {
+    return $ENV{'REQUEST_METHOD'};
+}
+END_OF_FUNC
+
+#### Method: content_type
+# Returns the content_type string
+####
+'content_type' => <<'END_OF_FUNC',
+sub content_type {
+    return $ENV{'CONTENT_TYPE'};
+}
+END_OF_FUNC
+
+#### Method: path_translated
+# Return the physical path information provided
+# by the URL (if any)
+####
+'path_translated' => <<'END_OF_FUNC',
+sub path_translated {
+    return $ENV{'PATH_TRANSLATED'};
+}
+END_OF_FUNC
+
+
+#### Method: query_string
+# Synthesize a query string from our current
+# parameters
+####
+'query_string' => <<'END_OF_FUNC',
+sub query_string {
+    my($self) = self_or_default(@_);
+    my($param,$value,@pairs);
+    foreach $param ($self->param) {
+	my($eparam) = escape($param);
+	foreach $value ($self->param($param)) {
+	    $value = escape($value);
+            next unless defined $value;
+	    push(@pairs,"$eparam=$value");
+	}
+    }
+    foreach (keys %{$self->{'.fieldnames'}}) {
+      push(@pairs,".cgifields=".escape("$_"));
+    }
+    return join($USE_PARAM_SEMICOLONS ? ';' : '&',@pairs);
+}
+END_OF_FUNC
+
+
+#### Method: accept
+# Without parameters, returns an array of the
+# MIME types the browser accepts.
+# With a single parameter equal to a MIME
+# type, will return undef if the browser won't
+# accept it, 1 if the browser accepts it but
+# doesn't give a preference, or a floating point
+# value between 0.0 and 1.0 if the browser
+# declares a quantitative score for it.
+# This handles MIME type globs correctly.
+####
+'Accept' => <<'END_OF_FUNC',
+sub Accept {
+    my($self,$search) = self_or_CGI(@_);
+    my(%prefs,$type,$pref,$pat);
+    
+    my(@accept) = split(',',$self->http('accept'));
+
+    foreach (@accept) {
+	($pref) = /q=(\d\.\d+|\d+)/;
+	($type) = m#(\S+/[^;]+)#;
+	next unless $type;
+	$prefs{$type}=$pref || 1;
+    }
+
+    return keys %prefs unless $search;
+    
+    # if a search type is provided, we may need to
+    # perform a pattern matching operation.
+    # The MIME types use a glob mechanism, which
+    # is easily translated into a perl pattern match
+
+    # First return the preference for directly supported
+    # types:
+    return $prefs{$search} if $prefs{$search};
+
+    # Didn't get it, so try pattern matching.
+    foreach (keys %prefs) {
+	next unless /\*/;       # not a pattern match
+	($pat = $_) =~ s/([^\w*])/\\$1/g; # escape meta characters
+	$pat =~ s/\*/.*/g; # turn it into a pattern
+	return $prefs{$_} if $search=~/$pat/;
+    }
+}
+END_OF_FUNC
+
+
+#### Method: user_agent
+# If called with no parameters, returns the user agent.
+# If called with one parameter, does a pattern match (case
+# insensitive) on the user agent.
+####
+'user_agent' => <<'END_OF_FUNC',
+sub user_agent {
+    my($self,$match)=self_or_CGI(@_);
+    return $self->http('user_agent') unless $match;
+    return $self->http('user_agent') =~ /$match/i;
+}
+END_OF_FUNC
+
+
+#### Method: raw_cookie
+# Returns the magic cookies for the session.
+# The cookies are not parsed or altered in any way, i.e.
+# cookies are returned exactly as given in the HTTP
+# headers.  If a cookie name is given, only that cookie's
+# value is returned, otherwise the entire raw cookie
+# is returned.
+####
+'raw_cookie' => <<'END_OF_FUNC',
+sub raw_cookie {
+    my($self,$key) = self_or_CGI(@_);
+
+    require CGI::Cookie;
+
+    if (defined($key)) {
+	$self->{'.raw_cookies'} = CGI::Cookie->raw_fetch
+	    unless $self->{'.raw_cookies'};
+
+	return () unless $self->{'.raw_cookies'};
+	return () unless $self->{'.raw_cookies'}->{$key};
+	return $self->{'.raw_cookies'}->{$key};
+    }
+    return $self->http('cookie') || $ENV{'COOKIE'} || '';
+}
+END_OF_FUNC
+
+#### Method: virtual_host
+# Return the name of the virtual_host, which
+# is not always the same as the server
+######
+'virtual_host' => <<'END_OF_FUNC',
+sub virtual_host {
+    my $vh = http('host') || server_name();
+    $vh =~ s/:\d+$//;		# get rid of port number
+    return $vh;
+}
+END_OF_FUNC
+
+#### Method: remote_host
+# Return the name of the remote host, or its IP
+# address if unavailable.  If this variable isn't
+# defined, it returns "localhost" for debugging
+# purposes.
+####
+'remote_host' => <<'END_OF_FUNC',
+sub remote_host {
+    return $ENV{'REMOTE_HOST'} || $ENV{'REMOTE_ADDR'} 
+    || 'localhost';
+}
+END_OF_FUNC
+
+
+#### Method: remote_addr
+# Return the IP addr of the remote host.
+####
+'remote_addr' => <<'END_OF_FUNC',
+sub remote_addr {
+    return $ENV{'REMOTE_ADDR'} || '127.0.0.1';
+}
+END_OF_FUNC
+
+
+#### Method: script_name
+# Return the partial URL to this script for
+# self-referencing scripts.  Also see
+# self_url(), which returns a URL with all state information
+# preserved.
+####
+'script_name' => <<'END_OF_FUNC',
+sub script_name {
+    return $ENV{'SCRIPT_NAME'} if defined($ENV{'SCRIPT_NAME'});
+    # These are for debugging
+    return "/$0" unless $0=~/^\//;
+    return $0;
+}
+END_OF_FUNC
+
+
+#### Method: referer
+# Return the HTTP_REFERER: useful for generating
+# a GO BACK button.
+####
+'referer' => <<'END_OF_FUNC',
+sub referer {
+    my($self) = self_or_CGI(@_);
+    return $self->http('referer');
+}
+END_OF_FUNC
+
+
+#### Method: server_name
+# Return the name of the server
+####
+'server_name' => <<'END_OF_FUNC',
+sub server_name {
+    return $ENV{'SERVER_NAME'} || 'localhost';
+}
+END_OF_FUNC
+
+#### Method: server_software
+# Return the name of the server software
+####
+'server_software' => <<'END_OF_FUNC',
+sub server_software {
+    return $ENV{'SERVER_SOFTWARE'} || 'cmdline';
+}
+END_OF_FUNC
+
+#### Method: server_port
+# Return the tcp/ip port the server is running on
+####
+'server_port' => <<'END_OF_FUNC',
+sub server_port {
+    return $ENV{'SERVER_PORT'} || 80; # for debugging
+}
+END_OF_FUNC
+
+#### Method: server_protocol
+# Return the protocol (usually HTTP/1.0)
+####
+'server_protocol' => <<'END_OF_FUNC',
+sub server_protocol {
+    return $ENV{'SERVER_PROTOCOL'} || 'HTTP/1.0'; # for debugging
+}
+END_OF_FUNC
+
+#### Method: http
+# Return the value of an HTTP variable, or
+# the list of variables if none provided
+####
+'http' => <<'END_OF_FUNC',
+sub http {
+    my ($self,$parameter) = self_or_CGI(@_);
+    return $ENV{$parameter} if $parameter=~/^HTTP/;
+    $parameter =~ tr/-/_/;
+    return $ENV{"HTTP_\U$parameter\E"} if $parameter;
+    my(@p);
+    foreach (keys %ENV) {
+	push(@p,$_) if /^HTTP/;
+    }
+    return @p;
+}
+END_OF_FUNC
+
+#### Method: https
+# Return the value of HTTPS
+####
+'https' => <<'END_OF_FUNC',
+sub https {
+    local($^W)=0;
+    my ($self,$parameter) = self_or_CGI(@_);
+    return $ENV{HTTPS} unless $parameter;
+    return $ENV{$parameter} if $parameter=~/^HTTPS/;
+    $parameter =~ tr/-/_/;
+    return $ENV{"HTTPS_\U$parameter\E"} if $parameter;
+    my(@p);
+    foreach (keys %ENV) {
+	push(@p,$_) if /^HTTPS/;
+    }
+    return @p;
+}
+END_OF_FUNC
+
+#### Method: protocol
+# Return the protocol (http or https currently)
+####
+'protocol' => <<'END_OF_FUNC',
+sub protocol {
+    local($^W)=0;
+    my $self = shift;
+    return 'https' if uc($self->https()) eq 'ON'; 
+    return 'https' if $self->server_port == 443;
+    my $prot = $self->server_protocol;
+    my($protocol,$version) = split('/',$prot);
+    return "\L$protocol\E";
+}
+END_OF_FUNC
+
+#### Method: remote_ident
+# Return the identity of the remote user
+# (but only if his host is running identd)
+####
+'remote_ident' => <<'END_OF_FUNC',
+sub remote_ident {
+    return $ENV{'REMOTE_IDENT'};
+}
+END_OF_FUNC
+
+
+#### Method: auth_type
+# Return the type of use verification/authorization in use, if any.
+####
+'auth_type' => <<'END_OF_FUNC',
+sub auth_type {
+    return $ENV{'AUTH_TYPE'};
+}
+END_OF_FUNC
+
+
+#### Method: remote_user
+# Return the authorization name used for user
+# verification.
+####
+'remote_user' => <<'END_OF_FUNC',
+sub remote_user {
+    return $ENV{'REMOTE_USER'};
+}
+END_OF_FUNC
+
+
+#### Method: user_name
+# Try to return the remote user's name by hook or by
+# crook
+####
+'user_name' => <<'END_OF_FUNC',
+sub user_name {
+    my ($self) = self_or_CGI(@_);
+    return $self->http('from') || $ENV{'REMOTE_IDENT'} || $ENV{'REMOTE_USER'};
+}
+END_OF_FUNC
+
+#### Method: nosticky
+# Set or return the NOSTICKY global flag
+####
+'nosticky' => <<'END_OF_FUNC',
+sub nosticky {
+    my ($self,$param) = self_or_CGI(@_);
+    $CGI::NOSTICKY = $param if defined($param);
+    return $CGI::NOSTICKY;
+}
+END_OF_FUNC
+
+#### Method: nph
+# Set or return the NPH global flag
+####
+'nph' => <<'END_OF_FUNC',
+sub nph {
+    my ($self,$param) = self_or_CGI(@_);
+    $CGI::NPH = $param if defined($param);
+    return $CGI::NPH;
+}
+END_OF_FUNC
+
+#### Method: private_tempfiles
+# Set or return the private_tempfiles global flag
+####
+'private_tempfiles' => <<'END_OF_FUNC',
+sub private_tempfiles {
+    my ($self,$param) = self_or_CGI(@_);
+    $CGI::PRIVATE_TEMPFILES = $param if defined($param);
+    return $CGI::PRIVATE_TEMPFILES;
+}
+END_OF_FUNC
+
+#### Method: default_dtd
+# Set or return the default_dtd global
+####
+'default_dtd' => <<'END_OF_FUNC',
+sub default_dtd {
+    my ($self,$param,$param2) = self_or_CGI(@_);
+    if (defined $param2 && defined $param) {
+        $CGI::DEFAULT_DTD = [ $param, $param2 ];
+    } elsif (defined $param) {
+        $CGI::DEFAULT_DTD = $param;
+    }
+    return $CGI::DEFAULT_DTD;
+}
+END_OF_FUNC
+
+# -------------- really private subroutines -----------------
+'previous_or_default' => <<'END_OF_FUNC',
+sub previous_or_default {
+    my($self,$name,$defaults,$override) = @_;
+    my(%selected);
+
+    if (!$override && ($self->{'.fieldnames'}->{$name} || 
+		       defined($self->param($name)) ) ) {
+	grep($selected{$_}++,$self->param($name));
+    } elsif (defined($defaults) && ref($defaults) && 
+	     (ref($defaults) eq 'ARRAY')) {
+	grep($selected{$_}++,@{$defaults});
+    } else {
+	$selected{$defaults}++ if defined($defaults);
+    }
+
+    return %selected;
+}
+END_OF_FUNC
+
+'register_parameter' => <<'END_OF_FUNC',
+sub register_parameter {
+    my($self,$param) = @_;
+    $self->{'.parametersToAdd'}->{$param}++;
+}
+END_OF_FUNC
+
+'get_fields' => <<'END_OF_FUNC',
+sub get_fields {
+    my($self) = @_;
+    return $self->CGI::hidden('-name'=>'.cgifields',
+			      '-values'=>[keys %{$self->{'.parametersToAdd'}}],
+			      '-override'=>1);
+}
+END_OF_FUNC
+
+'read_from_cmdline' => <<'END_OF_FUNC',
+sub read_from_cmdline {
+    my($input,@words);
+    my($query_string);
+    if ($DEBUG && @ARGV) {
+	@words = @ARGV;
+    } elsif ($DEBUG > 1) {
+	require "shellwords.pl";
+	print STDERR "(offline mode: enter name=value pairs on standard input)\n";
+	chomp(@lines = <STDIN>); # remove newlines
+	$input = join(" ",@lines);
+	@words = &shellwords($input);    
+    }
+    foreach (@words) {
+	s/\\=/%3D/g;
+	s/\\&/%26/g;	    
+    }
+
+    if ("@words"=~/=/) {
+	$query_string = join('&',@words);
+    } else {
+	$query_string = join('+',@words);
+    }
+    return $query_string;
+}
+END_OF_FUNC
+
+#####
+# subroutine: read_multipart
+#
+# Read multipart data and store it into our parameters.
+# An interesting feature is that if any of the parts is a file, we
+# create a temporary file and open up a filehandle on it so that the
+# caller can read from it if necessary.
+#####
+'read_multipart' => <<'END_OF_FUNC',
+sub read_multipart {
+    my($self,$boundary,$length,$filehandle) = @_;
+
+    my($buffer) = $self->new_MultipartBuffer($boundary,$length,$filehandle);
+    return unless $buffer;
+    my(%header,$body);
+    my $filenumber = 0;
+    while (!$buffer->eof) {
+	%header = $buffer->readHeader;
+
+	unless (%header) {
+	    $self->cgi_error("400 Bad request (malformed multipart POST)");
+	    return;
+	}
+
+	my($param)= $header{'Content-Disposition'}=~/ name="?([^\";]*)"?/;
+
+	# Bug:  Netscape doesn't escape quotation marks in file names!!!
+	my($filename) = $header{'Content-Disposition'}=~/ filename="?([^\"]*)"?/;
+
+	# add this parameter to our list
+	$self->add_parameter($param);
+
+	# If no filename specified, then just read the data and assign it
+	# to our parameter list.
+	if ( !defined($filename) || $filename eq '' ) {
+	    my($value) = $buffer->readBody;
+	    push(@{$self->{$param}},$value);
+	    next;
+	}
+
+	my ($tmpfile,$tmp,$filehandle);
+      UPLOADS: {
+	  # If we get here, then we are dealing with a potentially large
+	  # uploaded form.  Save the data to a temporary file, then open
+	  # the file for reading.
+
+	  # skip the file if uploads disabled
+	  if ($DISABLE_UPLOADS) {
+	      while (defined($data = $buffer->read)) { }
+	      last UPLOADS;
+	  }
+
+	  # choose a relatively unpredictable tmpfile sequence number
+          my $seqno = unpack("%16C*",join('',localtime,values %ENV));
+          for (my $cnt=10;$cnt>0;$cnt--) {
+	    next unless $tmpfile = new CGITempFile($seqno);
+	    $tmp = $tmpfile->as_string;
+	    last if defined($filehandle = Fh->new($filename,$tmp,$PRIVATE_TEMPFILES));
+            $seqno += int rand(100);
+          }
+          die "CGI open of tmpfile: $!\n" unless defined $filehandle;
+	  $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode;
+
+	  my ($data);
+	  local($\) = '';
+	  while (defined($data = $buffer->read)) {
+	      print $filehandle $data;
+	  }
+
+	  # back up to beginning of file
+	  seek($filehandle,0,0);
+	  $CGI::DefaultClass->binmode($filehandle) if $CGI::needs_binmode;
+
+	  # Save some information about the uploaded file where we can get
+	  # at it later.
+	  $self->{'.tmpfiles'}->{fileno($filehandle)}= {
+	      name => $tmpfile,
+	      info => {%header},
+	  };
+	  push(@{$self->{$param}},$filehandle);
+      }
+    }
+}
+END_OF_FUNC
+
+'upload' =><<'END_OF_FUNC',
+sub upload {
+    my($self,$param_name) = self_or_default(@_);
+    my @param = grep(ref && fileno($_), $self->param($param_name));
+    return unless @param;
+    return wantarray ? @param : $param[0];
+}
+END_OF_FUNC
+
+'tmpFileName' => <<'END_OF_FUNC',
+sub tmpFileName {
+    my($self,$filename) = self_or_default(@_);
+    return $self->{'.tmpfiles'}->{fileno($filename)}->{name} ?
+	$self->{'.tmpfiles'}->{fileno($filename)}->{name}->as_string
+	    : '';
+}
+END_OF_FUNC
+
+'uploadInfo' => <<'END_OF_FUNC',
+sub uploadInfo {
+    my($self,$filename) = self_or_default(@_);
+    return $self->{'.tmpfiles'}->{fileno($filename)}->{info};
+}
+END_OF_FUNC
+
+# internal routine, don't use
+'_set_values_and_labels' => <<'END_OF_FUNC',
+sub _set_values_and_labels {
+    my $self = shift;
+    my ($v,$l,$n) = @_;
+    $$l = $v if ref($v) eq 'HASH' && !ref($$l);
+    return $self->param($n) if !defined($v);
+    return $v if !ref($v);
+    return ref($v) eq 'HASH' ? keys %$v : @$v;
+}
+END_OF_FUNC
+
+'_compile_all' => <<'END_OF_FUNC',
+sub _compile_all {
+    foreach (@_) {
+	next if defined(&$_);
+	$AUTOLOAD = "CGI::$_";
+	_compile();
+    }
+}
+END_OF_FUNC
+
+);
+END_OF_AUTOLOAD
+;
+
+#########################################################
+# Globals and stubs for other packages that we use.
+#########################################################
+
+################### Fh -- lightweight filehandle ###############
+package Fh;
+use overload 
+    '""'  => \&asString,
+    'cmp' => \&compare,
+    'fallback'=>1;
+
+$FH='fh00000';
+
+*Fh::AUTOLOAD = \&CGI::AUTOLOAD;
+
+$AUTOLOADED_ROUTINES = '';      # prevent -w error
+$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD';
+%SUBS =  (
+'asString' => <<'END_OF_FUNC',
+sub asString {
+    my $self = shift;
+    # get rid of package name
+    (my $i = $$self) =~ s/^\*(\w+::fh\d{5})+//; 
+    $i =~ s/%(..)/ chr(hex($1)) /eg;
+    return $i;
+# BEGIN DEAD CODE
+# This was an extremely clever patch that allowed "use strict refs".
+# Unfortunately it relied on another bug that caused leaky file descriptors.
+# The underlying bug has been fixed, so this no longer works.  However
+# "strict refs" still works for some reason.
+#    my $self = shift;
+#    return ${*{$self}{SCALAR}};
+# END DEAD CODE
+}
+END_OF_FUNC
+
+'compare' => <<'END_OF_FUNC',
+sub compare {
+    my $self = shift;
+    my $value = shift;
+    return "$self" cmp $value;
+}
+END_OF_FUNC
+
+'new'  => <<'END_OF_FUNC',
+sub new {
+    my($pack,$name,$file,$delete) = @_;
+    require Fcntl unless defined &Fcntl::O_RDWR;
+    (my $safename = $name) =~ s/([':%])/ sprintf '%%%02X', ord $1 /eg;
+    my $fv = ++$FH . $safename;
+    my $ref = \*{"Fh::$fv"};
+    sysopen($ref,$file,Fcntl::O_RDWR()|Fcntl::O_CREAT()|Fcntl::O_EXCL(),0600) || return;
+    unlink($file) if $delete;
+    CORE::delete $Fh::{$fv};
+    return bless $ref,$pack;
+}
+END_OF_FUNC
+
+'DESTROY'  => <<'END_OF_FUNC',
+sub DESTROY {
+    my $self = shift;
+    close $self;
+}
+END_OF_FUNC
+
+);
+END_OF_AUTOLOAD
+
+######################## MultipartBuffer ####################
+package MultipartBuffer;
+
+# how many bytes to read at a time.  We use
+# a 4K buffer by default.
+$INITIAL_FILLUNIT = 1024 * 4;
+$TIMEOUT = 240*60;       # 4 hour timeout for big files
+$SPIN_LOOP_MAX = 2000;  # bug fix for some Netscape servers
+$CRLF=$CGI::CRLF;
+
+#reuse the autoload function
+*MultipartBuffer::AUTOLOAD = \&CGI::AUTOLOAD;
+
+# avoid autoloader warnings
+sub DESTROY {}
+
+###############################################################################
+################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND ####################
+###############################################################################
+$AUTOLOADED_ROUTINES = '';      # prevent -w error
+$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD';
+%SUBS =  (
+
+'new' => <<'END_OF_FUNC',
+sub new {
+    my($package,$interface,$boundary,$length,$filehandle) = @_;
+    $FILLUNIT = $INITIAL_FILLUNIT;
+    my $IN;
+    if ($filehandle) {
+	my($package) = caller;
+	# force into caller's package if necessary
+	$IN = $filehandle=~/[':]/ ? $filehandle : "$package\:\:$filehandle"; 
+    }
+    $IN = "main::STDIN" unless $IN;
+
+    $CGI::DefaultClass->binmode($IN) if $CGI::needs_binmode;
+    
+    # If the user types garbage into the file upload field,
+    # then Netscape passes NOTHING to the server (not good).
+    # We may hang on this read in that case. So we implement
+    # a read timeout.  If nothing is ready to read
+    # by then, we return.
+
+    # Netscape seems to be a little bit unreliable
+    # about providing boundary strings.
+    my $boundary_read = 0;
+    if ($boundary) {
+
+	# Under the MIME spec, the boundary consists of the 
+	# characters "--" PLUS the Boundary string
+
+	# BUG: IE 3.01 on the Macintosh uses just the boundary -- not
+	# the two extra hyphens.  We do a special case here on the user-agent!!!!
+	$boundary = "--$boundary" unless CGI::user_agent('MSIE\s+3\.0[12];\s*Mac|DreamPassport');
+
+    } else { # otherwise we find it ourselves
+	my($old);
+	($old,$/) = ($/,$CRLF); # read a CRLF-delimited line
+	$boundary = <$IN>;      # BUG: This won't work correctly under mod_perl
+	$length -= length($boundary);
+	chomp($boundary);               # remove the CRLF
+	$/ = $old;                      # restore old line separator
+        $boundary_read++;
+    }
+
+    my $self = {LENGTH=>$length,
+		BOUNDARY=>$boundary,
+		IN=>$IN,
+		INTERFACE=>$interface,
+		BUFFER=>'',
+	    };
+
+    $FILLUNIT = length($boundary)
+	if length($boundary) > $FILLUNIT;
+
+    my $retval = bless $self,ref $package || $package;
+
+    # Read the preamble and the topmost (boundary) line plus the CRLF.
+    unless ($boundary_read) {
+      while ($self->read(0)) { }
+    }
+    die "Malformed multipart POST\n" if $self->eof;
+
+    return $retval;
+}
+END_OF_FUNC
+
+'readHeader' => <<'END_OF_FUNC',
+sub readHeader {
+    my($self) = @_;
+    my($end);
+    my($ok) = 0;
+    my($bad) = 0;
+
+    local($CRLF) = "\015\012" if $CGI::OS eq 'VMS';
+
+    do {
+	$self->fillBuffer($FILLUNIT);
+	$ok++ if ($end = index($self->{BUFFER},"${CRLF}${CRLF}")) >= 0;
+	$ok++ if $self->{BUFFER} eq '';
+	$bad++ if !$ok && $self->{LENGTH} <= 0;
+	# this was a bad idea
+	# $FILLUNIT *= 2 if length($self->{BUFFER}) >= $FILLUNIT; 
+    } until $ok || $bad;
+    return () if $bad;
+
+    my($header) = substr($self->{BUFFER},0,$end+2);
+    substr($self->{BUFFER},0,$end+4) = '';
+    my %return;
+
+    
+    # See RFC 2045 Appendix A and RFC 822 sections 3.4.8
+    #   (Folding Long Header Fields), 3.4.3 (Comments)
+    #   and 3.4.5 (Quoted-Strings).
+
+    my $token = '[-\w!\#$%&\'*+.^_\`|{}~]';
+    $header=~s/$CRLF\s+/ /og;		# merge continuation lines
+    while ($header=~/($token+):\s+([^$CRLF]*)/mgox) {
+	my ($field_name,$field_value) = ($1,$2); # avoid taintedness
+	$field_name =~ s/\b(\w)/uc($1)/eg; #canonicalize
+	$return{$field_name}=$field_value;
+    }
+    return %return;
+}
+END_OF_FUNC
+
+# This reads and returns the body as a single scalar value.
+'readBody' => <<'END_OF_FUNC',
+sub readBody {
+    my($self) = @_;
+    my($data);
+    my($returnval)='';
+    while (defined($data = $self->read)) {
+	$returnval .= $data;
+    }
+    return $returnval;
+}
+END_OF_FUNC
+
+# This will read $bytes or until the boundary is hit, whichever happens
+# first.  After the boundary is hit, we return undef.  The next read will
+# skip over the boundary and begin reading again;
+'read' => <<'END_OF_FUNC',
+sub read {
+    my($self,$bytes) = @_;
+
+    # default number of bytes to read
+    $bytes = $bytes || $FILLUNIT;       
+
+    # Fill up our internal buffer in such a way that the boundary
+    # is never split between reads.
+    $self->fillBuffer($bytes);
+
+    # Find the boundary in the buffer (it may not be there).
+    my $start = index($self->{BUFFER},$self->{BOUNDARY});
+    # protect against malformed multipart POST operations
+    die "Malformed multipart POST\n" unless ($start >= 0) || ($self->{LENGTH} > 0);
+
+    # If the boundary begins the data, then skip past it
+    # and return undef.
+    if ($start == 0) {
+
+	# clear us out completely if we've hit the last boundary.
+	if (index($self->{BUFFER},"$self->{BOUNDARY}--")==0) {
+	    $self->{BUFFER}='';
+	    $self->{LENGTH}=0;
+	    return undef;
+	}
+
+	# just remove the boundary.
+	substr($self->{BUFFER},0,length($self->{BOUNDARY}))='';
+        $self->{BUFFER} =~ s/^\012\015?//;
+	return undef;
+    }
+
+    my $bytesToReturn;    
+    if ($start > 0) {           # read up to the boundary
+	$bytesToReturn = $start > $bytes ? $bytes : $start;
+    } else {    # read the requested number of bytes
+	# leave enough bytes in the buffer to allow us to read
+	# the boundary.  Thanks to Kevin Hendrick for finding
+	# this one.
+	$bytesToReturn = $bytes - (length($self->{BOUNDARY})+1);
+    }
+
+    my $returnval=substr($self->{BUFFER},0,$bytesToReturn);
+    substr($self->{BUFFER},0,$bytesToReturn)='';
+    
+    # If we hit the boundary, remove the CRLF from the end.
+    return (($start > 0) && ($start <= $bytes)) 
+           ? substr($returnval,0,-2) : $returnval;
+}
+END_OF_FUNC
+
+
+# This fills up our internal buffer in such a way that the
+# boundary is never split between reads
+'fillBuffer' => <<'END_OF_FUNC',
+sub fillBuffer {
+    my($self,$bytes) = @_;
+    return unless $self->{LENGTH};
+
+    my($boundaryLength) = length($self->{BOUNDARY});
+    my($bufferLength) = length($self->{BUFFER});
+    my($bytesToRead) = $bytes - $bufferLength + $boundaryLength + 2;
+    $bytesToRead = $self->{LENGTH} if $self->{LENGTH} < $bytesToRead;
+
+    # Try to read some data.  We may hang here if the browser is screwed up.  
+    my $bytesRead = $self->{INTERFACE}->read_from_client($self->{IN},
+							 \$self->{BUFFER},
+							 $bytesToRead,
+							 $bufferLength);
+    $self->{BUFFER} = '' unless defined $self->{BUFFER};
+
+    # An apparent bug in the Apache server causes the read()
+    # to return zero bytes repeatedly without blocking if the
+    # remote user aborts during a file transfer.  I don't know how
+    # they manage this, but the workaround is to abort if we get
+    # more than SPIN_LOOP_MAX consecutive zero reads.
+    if ($bytesRead == 0) {
+	die  "CGI.pm: Server closed socket during multipart read (client aborted?).\n"
+	    if ($self->{ZERO_LOOP_COUNTER}++ >= $SPIN_LOOP_MAX);
+    } else {
+	$self->{ZERO_LOOP_COUNTER}=0;
+    }
+
+    $self->{LENGTH} -= $bytesRead;
+}
+END_OF_FUNC
+
+
+# Return true when we've finished reading
+'eof' => <<'END_OF_FUNC'
+sub eof {
+    my($self) = @_;
+    return 1 if (length($self->{BUFFER}) == 0)
+		 && ($self->{LENGTH} <= 0);
+    undef;
+}
+END_OF_FUNC
+
+);
+END_OF_AUTOLOAD
+
+####################################################################################
+################################## TEMPORARY FILES #################################
+####################################################################################
+package CGITempFile;
+
+$SL = $CGI::SL;
+$MAC = $CGI::OS eq 'MACINTOSH';
+my ($vol) = $MAC ? MacPerl::Volumes() =~ /:(.*)/ : "";
+unless ($TMPDIRECTORY) {
+    @TEMP=("${SL}usr${SL}tmp","${SL}var${SL}tmp",
+	   "C:${SL}temp","${SL}tmp","${SL}temp",
+	   "${vol}${SL}Temporary Items",
+           "${SL}WWW_ROOT", "${SL}SYS\$SCRATCH",
+	   "C:${SL}system${SL}temp");
+    unshift(@TEMP,$ENV{'TMPDIR'}) if exists $ENV{'TMPDIR'};
+
+    # this feature was supposed to provide per-user tmpfiles, but
+    # it is problematic.
+    #    unshift(@TEMP,(getpwuid($<))[7].'/tmp') if $CGI::OS eq 'UNIX';
+    # Rob: getpwuid() is unfortunately UNIX specific. On brain dead OS'es this
+    #    : can generate a 'getpwuid() not implemented' exception, even though
+    #    : it's never called.  Found under DOS/Win with the DJGPP perl port.
+    #    : Refer to getpwuid() only at run-time if we're fortunate and have  UNIX.
+    # unshift(@TEMP,(eval {(getpwuid($>))[7]}).'/tmp') if $CGI::OS eq 'UNIX' and $> != 0;
+
+    foreach (@TEMP) {
+	do {$TMPDIRECTORY = $_; last} if -d $_ && -w _;
+    }
+}
+
+$TMPDIRECTORY  = $MAC ? "" : "." unless $TMPDIRECTORY;
+$MAXTRIES = 5000;
+
+# cute feature, but overload implementation broke it
+# %OVERLOAD = ('""'=>'as_string');
+*CGITempFile::AUTOLOAD = \&CGI::AUTOLOAD;
+
+sub DESTROY {
+    my($self) = @_;
+    unlink $$self;              # get rid of the file
+}
+
+###############################################################################
+################# THESE FUNCTIONS ARE AUTOLOADED ON DEMAND ####################
+###############################################################################
+$AUTOLOADED_ROUTINES = '';      # prevent -w error
+$AUTOLOADED_ROUTINES=<<'END_OF_AUTOLOAD';
+%SUBS = (
+
+'new' => <<'END_OF_FUNC',
+sub new {
+    my($package,$sequence) = @_;
+    my $filename;
+    for (my $i = 0; $i < $MAXTRIES; $i++) {
+	last if ! -f ($filename = sprintf("${TMPDIRECTORY}${SL}CGItemp%d",$sequence++));
+    }
+    # untaint the darn thing
+    return unless $filename =~ m!^([a-zA-Z0-9_ '":/.\$\\-]+)$!;
+    $filename = $1;
+    return bless \$filename;
+}
+END_OF_FUNC
+
+'as_string' => <<'END_OF_FUNC'
+sub as_string {
+    my($self) = @_;
+    return $$self;
+}
+END_OF_FUNC
+
+);
+END_OF_AUTOLOAD
+
+package CGI;
+
+# We get a whole bunch of warnings about "possibly uninitialized variables"
+# when running with the -w switch.  Touch them all once to get rid of the
+# warnings.  This is ugly and I hate it.
+if ($^W) {
+    $CGI::CGI = '';
+    $CGI::CGI=<<EOF;
+    $CGI::VERSION;
+    $MultipartBuffer::SPIN_LOOP_MAX;
+    $MultipartBuffer::CRLF;
+    $MultipartBuffer::TIMEOUT;
+    $MultipartBuffer::INITIAL_FILLUNIT;
+EOF
+    ;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+CGI - Simple Common Gateway Interface Class
+
+=head1 SYNOPSIS
+
+  # CGI script that creates a fill-out form
+  # and echoes back its values.
+
+  use CGI qw/:standard/;
+  print header,
+        start_html('A Simple Example'),
+        h1('A Simple Example'),
+        start_form,
+        "What's your name? ",textfield('name'),p,
+        "What's the combination?", p,
+        checkbox_group(-name=>'words',
+		       -values=>['eenie','meenie','minie','moe'],
+		       -defaults=>['eenie','minie']), p,
+        "What's your favorite color? ",
+        popup_menu(-name=>'color',
+	           -values=>['red','green','blue','chartreuse']),p,
+        submit,
+        end_form,
+        hr;
+
+   if (param()) {
+       print "Your name is",em(param('name')),p,
+	     "The keywords are: ",em(join(", ",param('words'))),p,
+	     "Your favorite color is ",em(param('color')),
+	     hr;
+   }
+
+=head1 ABSTRACT
+
+This perl library uses perl5 objects to make it easy to create Web
+fill-out forms and parse their contents.  This package defines CGI
+objects, entities that contain the values of the current query string
+and other state variables.  Using a CGI object's methods, you can
+examine keywords and parameters passed to your script, and create
+forms whose initial values are taken from the current query (thereby
+preserving state information).  The module provides shortcut functions
+that produce boilerplate HTML, reducing typing and coding errors. It
+also provides functionality for some of the more advanced features of
+CGI scripting, including support for file uploads, cookies, cascading
+style sheets, server push, and frames.
+
+CGI.pm also provides a simple function-oriented programming style for
+those who don't need its object-oriented features.
+
+The current version of CGI.pm is available at
+
+  http://www.genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html
+  ftp://ftp-genome.wi.mit.edu/pub/software/WWW/
+
+=head1 DESCRIPTION
+
+=head2 PROGRAMMING STYLE
+
+There are two styles of programming with CGI.pm, an object-oriented
+style and a function-oriented style.  In the object-oriented style you
+create one or more CGI objects and then use object methods to create
+the various elements of the page.  Each CGI object starts out with the
+list of named parameters that were passed to your CGI script by the
+server.  You can modify the objects, save them to a file or database
+and recreate them.  Because each object corresponds to the "state" of
+the CGI script, and because each object's parameter list is
+independent of the others, this allows you to save the state of the
+script and restore it later.
+
+For example, using the object oriented style, here is how you create
+a simple "Hello World" HTML page:
+
+   #!/usr/local/bin/perl -w
+   use CGI;                             # load CGI routines
+   $q = new CGI;                        # create new CGI object
+   print $q->header,                    # create the HTTP header
+         $q->start_html('hello world'), # start the HTML
+         $q->h1('hello world'),         # level 1 header
+         $q->end_html;                  # end the HTML
+
+In the function-oriented style, there is one default CGI object that
+you rarely deal with directly.  Instead you just call functions to
+retrieve CGI parameters, create HTML tags, manage cookies, and so
+on.  This provides you with a cleaner programming interface, but
+limits you to using one CGI object at a time.  The following example
+prints the same page, but uses the function-oriented interface.
+The main differences are that we now need to import a set of functions
+into our name space (usually the "standard" functions), and we don't
+need to create the CGI object.
+
+   #!/usr/local/bin/perl
+   use CGI qw/:standard/;           # load standard CGI routines
+   print header,                    # create the HTTP header
+         start_html('hello world'), # start the HTML
+         h1('hello world'),         # level 1 header
+         end_html;                  # end the HTML
+
+The examples in this document mainly use the object-oriented style.
+See HOW TO IMPORT FUNCTIONS for important information on
+function-oriented programming in CGI.pm
+
+=head2 CALLING CGI.PM ROUTINES
+
+Most CGI.pm routines accept several arguments, sometimes as many as 20
+optional ones!  To simplify this interface, all routines use a named
+argument calling style that looks like this:
+
+   print $q->header(-type=>'image/gif',-expires=>'+3d');
+
+Each argument name is preceded by a dash.  Neither case nor order
+matters in the argument list.  -type, -Type, and -TYPE are all
+acceptable.  In fact, only the first argument needs to begin with a
+dash.  If a dash is present in the first argument, CGI.pm assumes
+dashes for the subsequent ones.
+
+Several routines are commonly called with just one argument.  In the
+case of these routines you can provide the single argument without an
+argument name.  header() happens to be one of these routines.  In this
+case, the single argument is the document type.
+
+   print $q->header('text/html');
+
+Other such routines are documented below.
+
+Sometimes named arguments expect a scalar, sometimes a reference to an
+array, and sometimes a reference to a hash.  Often, you can pass any
+type of argument and the routine will do whatever is most appropriate.
+For example, the param() routine is used to set a CGI parameter to a
+single or a multi-valued value.  The two cases are shown below:
+
+   $q->param(-name=>'veggie',-value=>'tomato');
+   $q->param(-name=>'veggie',-value=>['tomato','tomahto','potato','potahto']);
+
+A large number of routines in CGI.pm actually aren't specifically
+defined in the module, but are generated automatically as needed.
+These are the "HTML shortcuts," routines that generate HTML tags for
+use in dynamically-generated pages.  HTML tags have both attributes
+(the attribute="value" pairs within the tag itself) and contents (the
+part between the opening and closing pairs.)  To distinguish between
+attributes and contents, CGI.pm uses the convention of passing HTML
+attributes as a hash reference as the first argument, and the
+contents, if any, as any subsequent arguments.  It works out like
+this:
+
+   Code                           Generated HTML
+   ----                           --------------
+   h1()                           <h1>
+   h1('some','contents');         <h1>some contents</h1>
+   h1({-align=>left});            <h1 ALIGN="LEFT">
+   h1({-align=>left},'contents'); <h1 ALIGN="LEFT">contents</h1>
+
+HTML tags are described in more detail later.  
+
+Many newcomers to CGI.pm are puzzled by the difference between the
+calling conventions for the HTML shortcuts, which require curly braces
+around the HTML tag attributes, and the calling conventions for other
+routines, which manage to generate attributes without the curly
+brackets.  Don't be confused.  As a convenience the curly braces are
+optional in all but the HTML shortcuts.  If you like, you can use
+curly braces when calling any routine that takes named arguments.  For
+example:
+
+   print $q->header( {-type=>'image/gif',-expires=>'+3d'} );
+
+If you use the B<-w> switch, you will be warned that some CGI.pm argument
+names conflict with built-in Perl functions.  The most frequent of
+these is the -values argument, used to create multi-valued menus,
+radio button clusters and the like.  To get around this warning, you
+have several choices:
+
+=over 4
+
+=item 1.
+
+Use another name for the argument, if one is available. 
+For example, -value is an alias for -values.
+
+=item 2.
+
+Change the capitalization, e.g. -Values
+
+=item 3.
+
+Put quotes around the argument name, e.g. '-values'
+
+=back
+
+Many routines will do something useful with a named argument that it
+doesn't recognize.  For example, you can produce non-standard HTTP
+header fields by providing them as named arguments:
+
+  print $q->header(-type  =>  'text/html',
+                   -cost  =>  'Three smackers',
+                   -annoyance_level => 'high',
+                   -complaints_to   => 'bit bucket');
+
+This will produce the following nonstandard HTTP header:
+
+   HTTP/1.0 200 OK
+   Cost: Three smackers
+   Annoyance-level: high
+   Complaints-to: bit bucket
+   Content-type: text/html
+
+Notice the way that underscores are translated automatically into
+hyphens.  HTML-generating routines perform a different type of
+translation. 
+
+This feature allows you to keep up with the rapidly changing HTTP and
+HTML "standards".
+
+=head2 CREATING A NEW QUERY OBJECT (OBJECT-ORIENTED STYLE):
+
+     $query = new CGI;
+
+This will parse the input (from both POST and GET methods) and store
+it into a perl5 object called $query.  
+
+=head2 CREATING A NEW QUERY OBJECT FROM AN INPUT FILE
+
+     $query = new CGI(INPUTFILE);
+
+If you provide a file handle to the new() method, it will read
+parameters from the file (or STDIN, or whatever).  The file can be in
+any of the forms describing below under debugging (i.e. a series of
+newline delimited TAG=VALUE pairs will work).  Conveniently, this type
+of file is created by the save() method (see below).  Multiple records
+can be saved and restored.
+
+Perl purists will be pleased to know that this syntax accepts
+references to file handles, or even references to filehandle globs,
+which is the "official" way to pass a filehandle:
+
+    $query = new CGI(\*STDIN);
+
+You can also initialize the CGI object with a FileHandle or IO::File
+object.
+
+If you are using the function-oriented interface and want to
+initialize CGI state from a file handle, the way to do this is with
+B<restore_parameters()>.  This will (re)initialize the
+default CGI object from the indicated file handle.
+
+    open (IN,"test.in") || die;
+    restore_parameters(IN);
+    close IN;
+
+You can also initialize the query object from an associative array
+reference:
+
+    $query = new CGI( {'dinosaur'=>'barney',
+		       'song'=>'I love you',
+		       'friends'=>[qw/Jessica George Nancy/]}
+		    );
+
+or from a properly formatted, URL-escaped query string:
+
+    $query = new CGI('dinosaur=barney&color=purple');
+
+or from a previously existing CGI object (currently this clones the
+parameter list, but none of the other object-specific fields, such as
+autoescaping):
+
+    $old_query = new CGI;
+    $new_query = new CGI($old_query);
+
+To create an empty query, initialize it from an empty string or hash:
+
+   $empty_query = new CGI("");
+
+       -or-
+
+   $empty_query = new CGI({});
+
+=head2 FETCHING A LIST OF KEYWORDS FROM THE QUERY:
+
+     @keywords = $query->keywords
+
+If the script was invoked as the result of an <ISINDEX> search, the
+parsed keywords can be obtained as an array using the keywords() method.
+
+=head2 FETCHING THE NAMES OF ALL THE PARAMETERS PASSED TO YOUR SCRIPT:
+
+     @names = $query->param
+
+If the script was invoked with a parameter list
+(e.g. "name1=value1&name2=value2&name3=value3"), the param() method
+will return the parameter names as a list.  If the script was invoked
+as an <ISINDEX> script and contains a string without ampersands
+(e.g. "value1+value2+value3") , there will be a single parameter named
+"keywords" containing the "+"-delimited keywords.
+
+NOTE: As of version 1.5, the array of parameter names returned will
+be in the same order as they were submitted by the browser.
+Usually this order is the same as the order in which the 
+parameters are defined in the form (however, this isn't part
+of the spec, and so isn't guaranteed).
+
+=head2 FETCHING THE VALUE OR VALUES OF A SINGLE NAMED PARAMETER:
+
+    @values = $query->param('foo');
+
+	      -or-
+
+    $value = $query->param('foo');
+
+Pass the param() method a single argument to fetch the value of the
+named parameter. If the parameter is multivalued (e.g. from multiple
+selections in a scrolling list), you can ask to receive an array.  Otherwise
+the method will return a single value.
+
+If a value is not given in the query string, as in the queries
+"name1=&name2=" or "name1&name2", it will be returned as an empty
+string.  This feature is new in 2.63.
+
+=head2 SETTING THE VALUE(S) OF A NAMED PARAMETER:
+
+    $query->param('foo','an','array','of','values');
+
+This sets the value for the named parameter 'foo' to an array of
+values.  This is one way to change the value of a field AFTER
+the script has been invoked once before.  (Another way is with
+the -override parameter accepted by all methods that generate
+form elements.)
+
+param() also recognizes a named parameter style of calling described
+in more detail later:
+
+    $query->param(-name=>'foo',-values=>['an','array','of','values']);
+
+			      -or-
+
+    $query->param(-name=>'foo',-value=>'the value');
+
+=head2 APPENDING ADDITIONAL VALUES TO A NAMED PARAMETER:
+
+   $query->append(-name=>'foo',-values=>['yet','more','values']);
+
+This adds a value or list of values to the named parameter.  The
+values are appended to the end of the parameter if it already exists.
+Otherwise the parameter is created.  Note that this method only
+recognizes the named argument calling syntax.
+
+=head2 IMPORTING ALL PARAMETERS INTO A NAMESPACE:
+
+   $query->import_names('R');
+
+This creates a series of variables in the 'R' namespace.  For example,
+$R::foo, @R:foo.  For keyword lists, a variable @R::keywords will appear.
+If no namespace is given, this method will assume 'Q'.
+WARNING:  don't import anything into 'main'; this is a major security
+risk!!!!
+
+In older versions, this method was called B<import()>.  As of version 2.20, 
+this name has been removed completely to avoid conflict with the built-in
+Perl module B<import> operator.
+
+=head2 DELETING A PARAMETER COMPLETELY:
+
+    $query->delete('foo');
+
+This completely clears a parameter.  It sometimes useful for
+resetting parameters that you don't want passed down between
+script invocations.
+
+If you are using the function call interface, use "Delete()" instead
+to avoid conflicts with Perl's built-in delete operator.
+
+=head2 DELETING ALL PARAMETERS:
+
+   $query->delete_all();
+
+This clears the CGI object completely.  It might be useful to ensure
+that all the defaults are taken when you create a fill-out form.
+
+Use Delete_all() instead if you are using the function call interface.
+
+=head2 DIRECT ACCESS TO THE PARAMETER LIST:
+
+   $q->param_fetch('address')->[1] = '1313 Mockingbird Lane';
+   unshift @{$q->param_fetch(-name=>'address')},'George Munster';
+
+If you need access to the parameter list in a way that isn't covered
+by the methods above, you can obtain a direct reference to it by
+calling the B<param_fetch()> method with the name of the .  This
+will return an array reference to the named parameters, which you then
+can manipulate in any way you like.
+
+You can also use a named argument style using the B<-name> argument.
+
+=head2 FETCHING THE PARAMETER LIST AS A HASH:
+
+    $params = $q->Vars;
+    print $params->{'address'};
+    @foo = split("\0",$params->{'foo'});
+    %params = $q->Vars;
+
+    use CGI ':cgi-lib';
+    $params = Vars;
+
+Many people want to fetch the entire parameter list as a hash in which
+the keys are the names of the CGI parameters, and the values are the
+parameters' values.  The Vars() method does this.  Called in a scalar
+context, it returns the parameter list as a tied hash reference.
+Changing a key changes the value of the parameter in the underlying
+CGI parameter list.  Called in a list context, it returns the
+parameter list as an ordinary hash.  This allows you to read the
+contents of the parameter list, but not to change it.
+
+When using this, the thing you must watch out for are multivalued CGI
+parameters.  Because a hash cannot distinguish between scalar and
+list context, multivalued parameters will be returned as a packed
+string, separated by the "\0" (null) character.  You must split this
+packed string in order to get at the individual values.  This is the
+convention introduced long ago by Steve Brenner in his cgi-lib.pl
+module for Perl version 4.
+
+If you wish to use Vars() as a function, import the I<:cgi-lib> set of
+function calls (also see the section on CGI-LIB compatibility).
+
+=head2 SAVING THE STATE OF THE SCRIPT TO A FILE:
+
+    $query->save(FILEHANDLE)
+
+This will write the current state of the form to the provided
+filehandle.  You can read it back in by providing a filehandle
+to the new() method.  Note that the filehandle can be a file, a pipe,
+or whatever!
+
+The format of the saved file is:
+
+	NAME1=VALUE1
+	NAME1=VALUE1'
+	NAME2=VALUE2
+	NAME3=VALUE3
+	=
+
+Both name and value are URL escaped.  Multi-valued CGI parameters are
+represented as repeated names.  A session record is delimited by a
+single = symbol.  You can write out multiple records and read them
+back in with several calls to B<new>.  You can do this across several
+sessions by opening the file in append mode, allowing you to create
+primitive guest books, or to keep a history of users' queries.  Here's
+a short example of creating multiple session records:
+
+   use CGI;
+
+   open (OUT,">>test.out") || die;
+   $records = 5;
+   foreach (0..$records) {
+       my $q = new CGI;
+       $q->param(-name=>'counter',-value=>$_);
+       $q->save(OUT);
+   }
+   close OUT;
+
+   # reopen for reading
+   open (IN,"test.out") || die;
+   while (!eof(IN)) {
+       my $q = new CGI(IN);
+       print $q->param('counter'),"\n";
+   }
+
+The file format used for save/restore is identical to that used by the
+Whitehead Genome Center's data exchange format "Boulderio", and can be
+manipulated and even databased using Boulderio utilities.  See
+
+  http://stein.cshl.org/boulder/
+
+for further details.
+
+If you wish to use this method from the function-oriented (non-OO)
+interface, the exported name for this method is B<save_parameters()>.
+
+=head2 RETRIEVING CGI ERRORS
+
+Errors can occur while processing user input, particularly when
+processing uploaded files.  When these errors occur, CGI will stop
+processing and return an empty parameter list.  You can test for
+the existence and nature of errors using the I<cgi_error()> function.
+The error messages are formatted as HTTP status codes. You can either
+incorporate the error text into an HTML page, or use it as the value
+of the HTTP status:
+
+    my $error = $q->cgi_error;
+    if ($error) {
+	print $q->header(-status=>$error),
+	      $q->start_html('Problems'),
+              $q->h2('Request not processed'),
+	      $q->strong($error);
+        exit 0;
+    }
+
+When using the function-oriented interface (see the next section),
+errors may only occur the first time you call I<param()>. Be ready
+for this!
+
+=head2 USING THE FUNCTION-ORIENTED INTERFACE
+
+To use the function-oriented interface, you must specify which CGI.pm
+routines or sets of routines to import into your script's namespace.
+There is a small overhead associated with this importation, but it
+isn't much.
+
+   use CGI <list of methods>;
+
+The listed methods will be imported into the current package; you can
+call them directly without creating a CGI object first.  This example
+shows how to import the B<param()> and B<header()>
+methods, and then use them directly:
+
+   use CGI 'param','header';
+   print header('text/plain');
+   $zipcode = param('zipcode');
+
+More frequently, you'll import common sets of functions by referring
+to the groups by name.  All function sets are preceded with a ":"
+character as in ":html3" (for tags defined in the HTML 3 standard).
+
+Here is a list of the function sets you can import:
+
+=over 4
+
+=item B<:cgi>
+
+Import all CGI-handling methods, such as B<param()>, B<path_info()>
+and the like.
+
+=item B<:form>
+
+Import all fill-out form generating methods, such as B<textfield()>.
+
+=item B<:html2>
+
+Import all methods that generate HTML 2.0 standard elements.
+
+=item B<:html3>
+
+Import all methods that generate HTML 3.0 elements (such as
+<table>, <super> and <sub>).
+
+=item B<:html4>
+
+Import all methods that generate HTML 4 elements (such as
+<abbrev>, <acronym> and <thead>).
+
+=item B<:netscape>
+
+Import all methods that generate Netscape-specific HTML extensions.
+
+=item B<:html>
+
+Import all HTML-generating shortcuts (i.e. 'html2' + 'html3' +
+'netscape')...
+
+=item B<:standard>
+
+Import "standard" features, 'html2', 'html3', 'html4', 'form' and 'cgi'.
+
+=item B<:all>
+
+Import all the available methods.  For the full list, see the CGI.pm
+code, where the variable %EXPORT_TAGS is defined.
+
+=back
+
+If you import a function name that is not part of CGI.pm, the module
+will treat it as a new HTML tag and generate the appropriate
+subroutine.  You can then use it like any other HTML tag.  This is to
+provide for the rapidly-evolving HTML "standard."  For example, say
+Microsoft comes out with a new tag called <gradient> (which causes the
+user's desktop to be flooded with a rotating gradient fill until his
+machine reboots).  You don't need to wait for a new version of CGI.pm
+to start using it immediately:
+
+   use CGI qw/:standard :html3 gradient/;
+   print gradient({-start=>'red',-end=>'blue'});
+
+Note that in the interests of execution speed CGI.pm does B<not> use
+the standard L<Exporter> syntax for specifying load symbols.  This may
+change in the future.
+
+If you import any of the state-maintaining CGI or form-generating
+methods, a default CGI object will be created and initialized
+automatically the first time you use any of the methods that require
+one to be present.  This includes B<param()>, B<textfield()>,
+B<submit()> and the like.  (If you need direct access to the CGI
+object, you can find it in the global variable B<$CGI::Q>).  By
+importing CGI.pm methods, you can create visually elegant scripts:
+
+   use CGI qw/:standard/;
+   print 
+       header,
+       start_html('Simple Script'),
+       h1('Simple Script'),
+       start_form,
+       "What's your name? ",textfield('name'),p,
+       "What's the combination?",
+       checkbox_group(-name=>'words',
+		      -values=>['eenie','meenie','minie','moe'],
+		      -defaults=>['eenie','moe']),p,
+       "What's your favorite color?",
+       popup_menu(-name=>'color',
+		  -values=>['red','green','blue','chartreuse']),p,
+       submit,
+       end_form,
+       hr,"\n";
+
+    if (param) {
+       print 
+	   "Your name is ",em(param('name')),p,
+	   "The keywords are: ",em(join(", ",param('words'))),p,
+	   "Your favorite color is ",em(param('color')),".\n";
+    }
+    print end_html;
+
+=head2 PRAGMAS
+
+In addition to the function sets, there are a number of pragmas that
+you can import.  Pragmas, which are always preceded by a hyphen,
+change the way that CGI.pm functions in various ways.  Pragmas,
+function sets, and individual functions can all be imported in the
+same use() line.  For example, the following use statement imports the
+standard set of functions and enables debugging mode (pragma
+-debug):
+
+   use CGI qw/:standard -debug/;
+
+The current list of pragmas is as follows:
+
+=over 4
+
+=item -any
+
+When you I<use CGI -any>, then any method that the query object
+doesn't recognize will be interpreted as a new HTML tag.  This allows
+you to support the next I<ad hoc> Netscape or Microsoft HTML
+extension.  This lets you go wild with new and unsupported tags:
+
+   use CGI qw(-any);
+   $q=new CGI;
+   print $q->gradient({speed=>'fast',start=>'red',end=>'blue'});
+
+Since using <cite>any</cite> causes any mistyped method name
+to be interpreted as an HTML tag, use it with care or not at
+all.
+
+=item -compile
+
+This causes the indicated autoloaded methods to be compiled up front,
+rather than deferred to later.  This is useful for scripts that run
+for an extended period of time under FastCGI or mod_perl, and for
+those destined to be crunched by Malcom Beattie's Perl compiler.  Use
+it in conjunction with the methods or method families you plan to use.
+
+   use CGI qw(-compile :standard :html3);
+
+or even
+
+   use CGI qw(-compile :all);
+
+Note that using the -compile pragma in this way will always have
+the effect of importing the compiled functions into the current
+namespace.  If you want to compile without importing use the
+compile() method instead (see below).
+
+=item -nosticky
+
+This makes CGI.pm not generating the hidden fields .submit
+and .cgifields. It is very useful if you don't want to
+have the hidden fields appear in the querystring in a GET method.
+For example, a search script generated this way will have
+a very nice url with search parameters for bookmarking.
+
+=item -no_undef_params
+
+This keeps CGI.pm from including undef params in the parameter list.
+
+=item -no_xhtml
+
+By default, CGI.pm versions 2.69 and higher emit XHTML
+(http://www.w3.org/TR/xhtml1/).  The -no_xhtml pragma disables this
+feature.  Thanks to Michalis Kabrianis <kabrianis@hellug.gr> for this
+feature.
+
+=item -nph
+
+This makes CGI.pm produce a header appropriate for an NPH (no
+parsed header) script.  You may need to do other things as well
+to tell the server that the script is NPH.  See the discussion
+of NPH scripts below.
+
+=item -newstyle_urls
+
+Separate the name=value pairs in CGI parameter query strings with
+semicolons rather than ampersands.  For example:
+
+   ?name=fred;age=24;favorite_color=3
+
+Semicolon-delimited query strings are always accepted, but will not be
+emitted by self_url() and query_string() unless the -newstyle_urls
+pragma is specified.
+
+This became the default in version 2.64.
+
+=item -oldstyle_urls
+
+Separate the name=value pairs in CGI parameter query strings with
+ampersands rather than semicolons.  This is no longer the default.
+
+=item -autoload
+
+This overrides the autoloader so that any function in your program
+that is not recognized is referred to CGI.pm for possible evaluation.
+This allows you to use all the CGI.pm functions without adding them to
+your symbol table, which is of concern for mod_perl users who are
+worried about memory consumption.  I<Warning:> when
+I<-autoload> is in effect, you cannot use "poetry mode"
+(functions without the parenthesis).  Use I<hr()> rather
+than I<hr>, or add something like I<use subs qw/hr p header/> 
+to the top of your script.
+
+=item -no_debug
+
+This turns off the command-line processing features.  If you want to
+run a CGI.pm script from the command line to produce HTML, and you
+don't want it to read CGI parameters from the command line or STDIN,
+then use this pragma:
+
+   use CGI qw(-no_debug :standard);
+
+=item -debug
+
+This turns on full debugging.  In addition to reading CGI arguments
+from the command-line processing, CGI.pm will pause and try to read
+arguments from STDIN, producing the message "(offline mode: enter
+name=value pairs on standard input)" features.
+
+See the section on debugging for more details.
+
+=item -private_tempfiles
+
+CGI.pm can process uploaded file. Ordinarily it spools the uploaded
+file to a temporary directory, then deletes the file when done.
+However, this opens the risk of eavesdropping as described in the file
+upload section.  Another CGI script author could peek at this data
+during the upload, even if it is confidential information. On Unix
+systems, the -private_tempfiles pragma will cause the temporary file
+to be unlinked as soon as it is opened and before any data is written
+into it, reducing, but not eliminating the risk of eavesdropping
+(there is still a potential race condition).  To make life harder for
+the attacker, the program chooses tempfile names by calculating a 32
+bit checksum of the incoming HTTP headers.
+
+To ensure that the temporary file cannot be read by other CGI scripts,
+use suEXEC or a CGI wrapper program to run your script.  The temporary
+file is created with mode 0600 (neither world nor group readable).
+
+The temporary directory is selected using the following algorithm:
+
+    1. if the current user (e.g. "nobody") has a directory named
+    "tmp" in its home directory, use that (Unix systems only).
+
+    2. if the environment variable TMPDIR exists, use the location
+    indicated.
+
+    3. Otherwise try the locations /usr/tmp, /var/tmp, C:\temp,
+    /tmp, /temp, ::Temporary Items, and \WWW_ROOT.
+
+Each of these locations is checked that it is a directory and is
+writable.  If not, the algorithm tries the next choice.
+
+=back
+
+=head2 SPECIAL FORMS FOR IMPORTING HTML-TAG FUNCTIONS
+
+Many of the methods generate HTML tags.  As described below, tag
+functions automatically generate both the opening and closing tags.
+For example:
+
+  print h1('Level 1 Header');
+
+produces
+
+  <h1>Level 1 Header</h1>
+
+There will be some times when you want to produce the start and end
+tags yourself.  In this case, you can use the form start_I<tag_name>
+and end_I<tag_name>, as in:
+
+  print start_h1,'Level 1 Header',end_h1;
+
+With a few exceptions (described below), start_I<tag_name> and
+end_I<tag_name> functions are not generated automatically when you
+I<use CGI>.  However, you can specify the tags you want to generate
+I<start/end> functions for by putting an asterisk in front of their
+name, or, alternatively, requesting either "start_I<tag_name>" or
+"end_I<tag_name>" in the import list.
+
+Example:
+
+  use CGI qw/:standard *table start_ul/;
+
+In this example, the following functions are generated in addition to
+the standard ones:
+
+=over 4
+
+=item 1. start_table() (generates a <table> tag)
+
+=item 2. end_table() (generates a </table> tag)
+
+=item 3. start_ul() (generates a <ul> tag)
+
+=item 4. end_ul() (generates a </ul> tag)
+
+=back
+
+=head1 GENERATING DYNAMIC DOCUMENTS
+
+Most of CGI.pm's functions deal with creating documents on the fly.
+Generally you will produce the HTTP header first, followed by the
+document itself.  CGI.pm provides functions for generating HTTP
+headers of various types as well as for generating HTML.  For creating
+GIF images, see the GD.pm module.
+
+Each of these functions produces a fragment of HTML or HTTP which you
+can print out directly so that it displays in the browser window,
+append to a string, or save to a file for later use.
+
+=head2 CREATING A STANDARD HTTP HEADER:
+
+Normally the first thing you will do in any CGI script is print out an
+HTTP header.  This tells the browser what type of document to expect,
+and gives other optional information, such as the language, expiration
+date, and whether to cache the document.  The header can also be
+manipulated for special purposes, such as server push and pay per view
+pages.
+
+	print $query->header;
+
+	     -or-
+
+	print $query->header('image/gif');
+
+	     -or-
+
+	print $query->header('text/html','204 No response');
+
+	     -or-
+
+	print $query->header(-type=>'image/gif',
+			     -nph=>1,
+			     -status=>'402 Payment required',
+			     -expires=>'+3d',
+			     -cookie=>$cookie,
+                             -charset=>'utf-7',
+                             -attachment=>'foo.gif',
+			     -Cost=>'$2.00');
+
+header() returns the Content-type: header.  You can provide your own
+MIME type if you choose, otherwise it defaults to text/html.  An
+optional second parameter specifies the status code and a human-readable
+message.  For example, you can specify 204, "No response" to create a
+script that tells the browser to do nothing at all.
+
+The last example shows the named argument style for passing arguments
+to the CGI methods using named parameters.  Recognized parameters are
+B<-type>, B<-status>, B<-expires>, and B<-cookie>.  Any other named
+parameters will be stripped of their initial hyphens and turned into
+header fields, allowing you to specify any HTTP header you desire.
+Internal underscores will be turned into hyphens:
+
+    print $query->header(-Content_length=>3002);
+
+Most browsers will not cache the output from CGI scripts.  Every time
+the browser reloads the page, the script is invoked anew.  You can
+change this behavior with the B<-expires> parameter.  When you specify
+an absolute or relative expiration interval with this parameter, some
+browsers and proxy servers will cache the script's output until the
+indicated expiration date.  The following forms are all valid for the
+-expires field:
+
+	+30s                              30 seconds from now
+	+10m                              ten minutes from now
+	+1h                               one hour from now
+	-1d                               yesterday (i.e. "ASAP!")
+	now                               immediately
+	+3M                               in three months
+	+10y                              in ten years time
+	Thursday, 25-Apr-1999 00:40:33 GMT  at the indicated time & date
+
+The B<-cookie> parameter generates a header that tells the browser to provide
+a "magic cookie" during all subsequent transactions with your script.
+Netscape cookies have a special format that includes interesting attributes
+such as expiration time.  Use the cookie() method to create and retrieve
+session cookies.
+
+The B<-nph> parameter, if set to a true value, will issue the correct
+headers to work with an NPH (no-parse-header) script.  This is important
+to use with certain servers that expect all their scripts to be NPH.
+
+The B<-charset> parameter can be used to control the character set
+sent to the browser.  If not provided, defaults to ISO-8859-1.  As a
+side effect, this sets the charset() method as well.
+
+The B<-attachment> parameter can be used to turn the page into an
+attachment.  Instead of displaying the page, some browsers will prompt
+the user to save it to disk.  The value of the argument is the
+suggested name for the saved file.  In order for this to work, you may
+have to set the B<-type> to "application/octet-stream".
+
+=head2 GENERATING A REDIRECTION HEADER
+
+   print $query->redirect('http://somewhere.else/in/movie/land');
+
+Sometimes you don't want to produce a document yourself, but simply
+redirect the browser elsewhere, perhaps choosing a URL based on the
+time of day or the identity of the user.  
+
+The redirect() function redirects the browser to a different URL.  If
+you use redirection like this, you should B<not> print out a header as
+well.
+
+One hint I can offer is that relative links may not work correctly
+when you generate a redirection to another document on your site.
+This is due to a well-intentioned optimization that some servers use.
+The solution to this is to use the full URL (including the http: part)
+of the document you are redirecting to.
+
+You can also use named arguments:
+
+    print $query->redirect(-uri=>'http://somewhere.else/in/movie/land',
+			   -nph=>1);
+
+The B<-nph> parameter, if set to a true value, will issue the correct
+headers to work with an NPH (no-parse-header) script.  This is important
+to use with certain servers, such as Microsoft Internet Explorer, which
+expect all their scripts to be NPH.
+
+=head2 CREATING THE HTML DOCUMENT HEADER
+
+   print $query->start_html(-title=>'Secrets of the Pyramids',
+			    -author=>'fred@capricorn.org',
+			    -base=>'true',
+			    -target=>'_blank',
+			    -meta=>{'keywords'=>'pharaoh secret mummy',
+				    'copyright'=>'copyright 1996 King Tut'},
+			    -style=>{'src'=>'/styles/style1.css'},
+			    -BGCOLOR=>'blue');
+
+After creating the HTTP header, most CGI scripts will start writing
+out an HTML document.  The start_html() routine creates the top of the
+page, along with a lot of optional information that controls the
+page's appearance and behavior.
+
+This method returns a canned HTML header and the opening <body> tag.
+All parameters are optional.  In the named parameter form, recognized
+parameters are -title, -author, -base, -xbase, -dtd, -lang and -target
+(see below for the explanation).  Any additional parameters you
+provide, such as the Netscape unofficial BGCOLOR attribute, are added
+to the <body> tag.  Additional parameters must be proceeded by a
+hyphen.
+
+The argument B<-xbase> allows you to provide an HREF for the <base> tag
+different from the current location, as in
+
+    -xbase=>"http://home.mcom.com/"
+
+All relative links will be interpreted relative to this tag.
+
+The argument B<-target> allows you to provide a default target frame
+for all the links and fill-out forms on the page.  B<This is a
+non-standard HTTP feature which only works with Netscape browsers!>
+See the Netscape documentation on frames for details of how to
+manipulate this.
+
+    -target=>"answer_window"
+
+All relative links will be interpreted relative to this tag.
+You add arbitrary meta information to the header with the B<-meta>
+argument.  This argument expects a reference to an associative array
+containing name/value pairs of meta information.  These will be turned
+into a series of header <meta> tags that look something like this:
+
+    <meta name="keywords" content="pharaoh secret mummy">
+    <meta name="description" content="copyright 1996 King Tut">
+
+To create an HTTP-EQUIV type of <meta> tag, use B<-head>, described
+below.
+
+The B<-style> argument is used to incorporate cascading stylesheets
+into your code.  See the section on CASCADING STYLESHEETS for more
+information.
+
+The B<-lang> argument is used to incorporate a language attribute into
+the <html> tag.  The default if not specified is "en-US" for US
+English.  For example:
+
+    print $q->start_html(-lang=>'fr-CA');
+
+The B<-encoding> argument can be used to specify the character set for
+XHTML.  It defaults to iso-8859-1 if not specified.
+
+You can place other arbitrary HTML elements to the <head> section with the
+B<-head> tag.  For example, to place the rarely-used <link> element in the
+head section, use this:
+
+    print start_html(-head=>Link({-rel=>'next',
+		                  -href=>'http://www.capricorn.com/s2.html'}));
+
+To incorporate multiple HTML elements into the <head> section, just pass an
+array reference:
+
+    print start_html(-head=>[ 
+                             Link({-rel=>'next',
+				   -href=>'http://www.capricorn.com/s2.html'}),
+		             Link({-rel=>'previous',
+				   -href=>'http://www.capricorn.com/s1.html'})
+			     ]
+		     );
+
+And here's how to create an HTTP-EQUIV <meta> tag:
+
+      print start_html(-head=>meta({-http_equiv => 'Content-Type',
+                                    -content    => 'text/html'}))
+
+
+JAVASCRIPTING: The B<-script>, B<-noScript>, B<-onLoad>,
+B<-onMouseOver>, B<-onMouseOut> and B<-onUnload> parameters are used
+to add Netscape JavaScript calls to your pages.  B<-script> should
+point to a block of text containing JavaScript function definitions.
+This block will be placed within a <script> block inside the HTML (not
+HTTP) header.  The block is placed in the header in order to give your
+page a fighting chance of having all its JavaScript functions in place
+even if the user presses the stop button before the page has loaded
+completely.  CGI.pm attempts to format the script in such a way that
+JavaScript-naive browsers will not choke on the code: unfortunately
+there are some browsers, such as Chimera for Unix, that get confused
+by it nevertheless.
+
+The B<-onLoad> and B<-onUnload> parameters point to fragments of JavaScript
+code to execute when the page is respectively opened and closed by the
+browser.  Usually these parameters are calls to functions defined in the
+B<-script> field:
+
+      $query = new CGI;
+      print $query->header;
+      $JSCRIPT=<<END;
+      // Ask a silly question
+      function riddle_me_this() {
+	 var r = prompt("What walks on four legs in the morning, " +
+		       "two legs in the afternoon, " +
+		       "and three legs in the evening?");
+	 response(r);
+      }
+      // Get a silly answer
+      function response(answer) {
+	 if (answer == "man")
+	    alert("Right you are!");
+	 else
+	    alert("Wrong!  Guess again.");
+      }
+      END
+      print $query->start_html(-title=>'The Riddle of the Sphinx',
+			       -script=>$JSCRIPT);
+
+Use the B<-noScript> parameter to pass some HTML text that will be displayed on 
+browsers that do not have JavaScript (or browsers where JavaScript is turned
+off).
+
+Netscape 3.0 recognizes several attributes of the <script> tag,
+including LANGUAGE and SRC.  The latter is particularly interesting,
+as it allows you to keep the JavaScript code in a file or CGI script
+rather than cluttering up each page with the source.  To use these
+attributes pass a HASH reference in the B<-script> parameter containing
+one or more of -language, -src, or -code:
+
+    print $q->start_html(-title=>'The Riddle of the Sphinx',
+			 -script=>{-language=>'JAVASCRIPT',
+                                   -src=>'/javascript/sphinx.js'}
+			 );
+
+    print $q->(-title=>'The Riddle of the Sphinx',
+	       -script=>{-language=>'PERLSCRIPT',
+			 -code=>'print "hello world!\n;"'}
+	       );
+
+
+A final feature allows you to incorporate multiple <script> sections into the
+header.  Just pass the list of script sections as an array reference.
+this allows you to specify different source files for different dialects
+of JavaScript.  Example:     
+
+     print $q->start_html(-title=>'The Riddle of the Sphinx',
+                          -script=>[
+                                    { -language => 'JavaScript1.0',
+                                      -src      => '/javascript/utilities10.js'
+                                    },
+                                    { -language => 'JavaScript1.1',
+                                      -src      => '/javascript/utilities11.js'
+                                    },
+                                    { -language => 'JavaScript1.2',
+                                      -src      => '/javascript/utilities12.js'
+                                    },
+                                    { -language => 'JavaScript28.2',
+                                      -src      => '/javascript/utilities219.js'
+                                    }
+                                 ]
+                             );
+
+If this looks a bit extreme, take my advice and stick with straight CGI scripting.  
+
+See
+
+   http://home.netscape.com/eng/mozilla/2.0/handbook/javascript/
+
+for more information about JavaScript.
+
+The old-style positional parameters are as follows:
+
+=over 4
+
+=item B<Parameters:>
+
+=item 1.
+
+The title
+
+=item 2.
+
+The author's e-mail address (will create a <link rev="MADE"> tag if present
+
+=item 3.
+
+A 'true' flag if you want to include a <base> tag in the header.  This
+helps resolve relative addresses to absolute ones when the document is moved, 
+but makes the document hierarchy non-portable.  Use with care!
+
+=item 4, 5, 6...
+
+Any other parameters you want to include in the <body> tag.  This is a good
+place to put Netscape extensions, such as colors and wallpaper patterns.
+
+=back
+
+=head2 ENDING THE HTML DOCUMENT:
+
+	print $query->end_html
+
+This ends an HTML document by printing the </body></html> tags.
+
+=head2 CREATING A SELF-REFERENCING URL THAT PRESERVES STATE INFORMATION:
+
+    $myself = $query->self_url;
+    print q(<a href="$myself">I'm talking to myself.</a>);
+
+self_url() will return a URL, that, when selected, will reinvoke
+this script with all its state information intact.  This is most
+useful when you want to jump around within the document using
+internal anchors but you don't want to disrupt the current contents
+of the form(s).  Something like this will do the trick.
+
+     $myself = $query->self_url;
+     print "<a href=$myself#table1>See table 1</a>";
+     print "<a href=$myself#table2>See table 2</a>";
+     print "<a href=$myself#yourself>See for yourself</a>";
+
+If you want more control over what's returned, using the B<url()>
+method instead.
+
+You can also retrieve the unprocessed query string with query_string():
+
+    $the_string = $query->query_string;
+
+=head2 OBTAINING THE SCRIPT'S URL
+
+    $full_url      = $query->url();
+    $full_url      = $query->url(-full=>1);  #alternative syntax
+    $relative_url  = $query->url(-relative=>1);
+    $absolute_url  = $query->url(-absolute=>1);
+    $url_with_path = $query->url(-path_info=>1);
+    $url_with_path_and_query = $query->url(-path_info=>1,-query=>1);
+    $netloc        = $query->url(-base => 1);
+
+B<url()> returns the script's URL in a variety of formats.  Called
+without any arguments, it returns the full form of the URL, including
+host name and port number
+
+    http://your.host.com/path/to/script.cgi
+
+You can modify this format with the following named arguments:
+
+=over 4
+
+=item B<-absolute>
+
+If true, produce an absolute URL, e.g.
+
+    /path/to/script.cgi
+
+=item B<-relative>
+
+Produce a relative URL.  This is useful if you want to reinvoke your
+script with different parameters. For example:
+
+    script.cgi
+
+=item B<-full>
+
+Produce the full URL, exactly as if called without any arguments.
+This overrides the -relative and -absolute arguments.
+
+=item B<-path> (B<-path_info>)
+
+Append the additional path information to the URL.  This can be
+combined with B<-full>, B<-absolute> or B<-relative>.  B<-path_info>
+is provided as a synonym.
+
+=item B<-query> (B<-query_string>)
+
+Append the query string to the URL.  This can be combined with
+B<-full>, B<-absolute> or B<-relative>.  B<-query_string> is provided
+as a synonym.
+
+=item B<-base>
+
+Generate just the protocol and net location, as in http://www.foo.com:8000
+
+=back
+
+=head2 MIXING POST AND URL PARAMETERS
+
+   $color = $query-&gt;url_param('color');
+
+It is possible for a script to receive CGI parameters in the URL as
+well as in the fill-out form by creating a form that POSTs to a URL
+containing a query string (a "?" mark followed by arguments).  The
+B<param()> method will always return the contents of the POSTed
+fill-out form, ignoring the URL's query string.  To retrieve URL
+parameters, call the B<url_param()> method.  Use it in the same way as
+B<param()>.  The main difference is that it allows you to read the
+parameters, but not set them.
+
+
+Under no circumstances will the contents of the URL query string
+interfere with similarly-named CGI parameters in POSTed forms.  If you
+try to mix a URL query string with a form submitted with the GET
+method, the results will not be what you expect.
+
+=head1 CREATING STANDARD HTML ELEMENTS:
+
+CGI.pm defines general HTML shortcut methods for most, if not all of
+the HTML 3 and HTML 4 tags.  HTML shortcuts are named after a single
+HTML element and return a fragment of HTML text that you can then
+print or manipulate as you like.  Each shortcut returns a fragment of
+HTML code that you can append to a string, save to a file, or, most
+commonly, print out so that it displays in the browser window.
+
+This example shows how to use the HTML methods:
+
+   $q = new CGI;
+   print $q->blockquote(
+		     "Many years ago on the island of",
+		     $q->a({href=>"http://crete.org/"},"Crete"),
+		     "there lived a Minotaur named",
+		     $q->strong("Fred."),
+		    ),
+       $q->hr;
+
+This results in the following HTML code (extra newlines have been
+added for readability):
+
+   <blockquote>
+   Many years ago on the island of
+   <a href="http://crete.org/">Crete</a> there lived
+   a minotaur named <strong>Fred.</strong> 
+   </blockquote>
+   <hr>
+
+If you find the syntax for calling the HTML shortcuts awkward, you can
+import them into your namespace and dispense with the object syntax
+completely (see the next section for more details):
+
+   use CGI ':standard';
+   print blockquote(
+      "Many years ago on the island of",
+      a({href=>"http://crete.org/"},"Crete"),
+      "there lived a minotaur named",
+      strong("Fred."),
+      ),
+      hr;
+
+=head2 PROVIDING ARGUMENTS TO HTML SHORTCUTS
+
+The HTML methods will accept zero, one or multiple arguments.  If you
+provide no arguments, you get a single tag:
+
+   print hr;  	#  <hr>
+
+If you provide one or more string arguments, they are concatenated
+together with spaces and placed between opening and closing tags:
+
+   print h1("Chapter","1"); # <h1>Chapter 1</h1>"
+
+If the first argument is an associative array reference, then the keys
+and values of the associative array become the HTML tag's attributes:
+
+   print a({-href=>'fred.html',-target=>'_new'},
+      "Open a new frame");
+
+	    <a href="fred.html",target="_new">Open a new frame</a>
+
+You may dispense with the dashes in front of the attribute names if
+you prefer:
+
+   print img {src=>'fred.gif',align=>'LEFT'};
+
+	   <img align="LEFT" src="fred.gif">
+
+Sometimes an HTML tag attribute has no argument.  For example, ordered
+lists can be marked as COMPACT.  The syntax for this is an argument
+that points to an undef string:
+
+   print ol({compact=>undef},li('one'),li('two'),li('three'));
+
+Prior to CGI.pm version 2.41, providing an empty ('') string as an
+attribute argument was the same as providing undef.  However, this has
+changed in order to accommodate those who want to create tags of the form
+<img alt="">.  The difference is shown in these two pieces of code:
+
+     CODE                   RESULT
+     img({alt=>undef})      <img alt>
+     img({alt=>''})         <img alt="">
+
+=head2 THE DISTRIBUTIVE PROPERTY OF HTML SHORTCUTS
+
+One of the cool features of the HTML shortcuts is that they are
+distributive.  If you give them an argument consisting of a
+B<reference> to a list, the tag will be distributed across each
+element of the list.  For example, here's one way to make an ordered
+list:
+
+   print ul(
+             li({-type=>'disc'},['Sneezy','Doc','Sleepy','Happy'])
+           );
+
+This example will result in HTML output that looks like this:
+
+   <ul>
+     <li type="disc">Sneezy</li>
+     <li type="disc">Doc</li>
+     <li type="disc">Sleepy</li>
+     <li type="disc">Happy</li>
+   </ul>
+
+This is extremely useful for creating tables.  For example:
+
+   print table({-border=>undef},
+           caption('When Should You Eat Your Vegetables?'),
+           Tr({-align=>CENTER,-valign=>TOP},
+           [
+              th(['Vegetable', 'Breakfast','Lunch','Dinner']),
+              td(['Tomatoes' , 'no', 'yes', 'yes']),
+              td(['Broccoli' , 'no', 'no',  'yes']),
+              td(['Onions'   , 'yes','yes', 'yes'])
+           ]
+           )
+        );
+
+=head2 HTML SHORTCUTS AND LIST INTERPOLATION
+
+Consider this bit of code:
+
+   print blockquote(em('Hi'),'mom!'));
+
+It will ordinarily return the string that you probably expect, namely:
+
+   <blockquote><em>Hi</em> mom!</blockquote>
+
+Note the space between the element "Hi" and the element "mom!".
+CGI.pm puts the extra space there using array interpolation, which is
+controlled by the magic $" variable.  Sometimes this extra space is
+not what you want, for example, when you are trying to align a series
+of images.  In this case, you can simply change the value of $" to an
+empty string.
+
+   {
+      local($") = '';
+      print blockquote(em('Hi'),'mom!'));
+    }
+
+I suggest you put the code in a block as shown here.  Otherwise the
+change to $" will affect all subsequent code until you explicitly
+reset it.
+
+=head2 NON-STANDARD HTML SHORTCUTS
+
+A few HTML tags don't follow the standard pattern for various
+reasons.  
+
+B<comment()> generates an HTML comment (<!-- comment -->).  Call it
+like
+
+    print comment('here is my comment');
+
+Because of conflicts with built-in Perl functions, the following functions
+begin with initial caps:
+
+    Select
+    Tr
+    Link
+    Delete
+    Accept
+    Sub
+
+In addition, start_html(), end_html(), start_form(), end_form(),
+start_multipart_form() and all the fill-out form tags are special.
+See their respective sections.
+
+=head2 AUTOESCAPING HTML
+
+By default, all HTML that is emitted by the form-generating functions
+is passed through a function called escapeHTML():
+
+=over 4
+
+=item $escaped_string = escapeHTML("unescaped string");
+
+Escape HTML formatting characters in a string.
+
+=back
+
+Provided that you have specified a character set of ISO-8859-1 (the
+default), the standard HTML escaping rules will be used.  The "<"
+character becomes "&lt;", ">" becomes "&gt;", "&" becomes "&amp;", and
+the quote character becomes "&quot;".  In addition, the hexadecimal
+0x8b and 0x9b characters, which many windows-based browsers interpret
+as the left and right angle-bracket characters, are replaced by their
+numeric HTML entities ("&#139" and "&#155;").  If you manually change
+the charset, either by calling the charset() method explicitly or by
+passing a -charset argument to header(), then B<all> characters will
+be replaced by their numeric entities, since CGI.pm has no lookup
+table for all the possible encodings.
+
+The automatic escaping does not apply to other shortcuts, such as
+h1().  You should call escapeHTML() yourself on untrusted data in
+order to protect your pages against nasty tricks that people may enter
+into guestbooks, etc..  To change the character set, use charset().
+To turn autoescaping off completely, use autoescape():
+
+=over 4
+
+=item $charset = charset([$charset]);
+
+Get or set the current character set.
+
+=item $flag = autoEscape([$flag]);
+
+Get or set the value of the autoescape flag.
+
+=back
+
+=head2 PRETTY-PRINTING HTML
+
+By default, all the HTML produced by these functions comes out as one
+long line without carriage returns or indentation. This is yuck, but
+it does reduce the size of the documents by 10-20%.  To get
+pretty-printed output, please use L<CGI::Pretty>, a subclass
+contributed by Brian Paulsen.
+
+=head1 CREATING FILL-OUT FORMS:
+
+I<General note>  The various form-creating methods all return strings
+to the caller, containing the tag or tags that will create the requested
+form element.  You are responsible for actually printing out these strings.
+It's set up this way so that you can place formatting tags
+around the form elements.
+
+I<Another note> The default values that you specify for the forms are only
+used the B<first> time the script is invoked (when there is no query
+string).  On subsequent invocations of the script (when there is a query
+string), the former values are used even if they are blank.  
+
+If you want to change the value of a field from its previous value, you have two
+choices:
+
+(1) call the param() method to set it.
+
+(2) use the -override (alias -force) parameter (a new feature in version 2.15).
+This forces the default value to be used, regardless of the previous value:
+
+   print $query->textfield(-name=>'field_name',
+			   -default=>'starting value',
+			   -override=>1,
+			   -size=>50,
+			   -maxlength=>80);
+
+I<Yet another note> By default, the text and labels of form elements are
+escaped according to HTML rules.  This means that you can safely use
+"<CLICK ME>" as the label for a button.  However, it also interferes with
+your ability to incorporate special HTML character sequences, such as &Aacute;,
+into your fields.  If you wish to turn off automatic escaping, call the
+autoEscape() method with a false value immediately after creating the CGI object:
+
+   $query = new CGI;
+   $query->autoEscape(undef);
+
+=head2 CREATING AN ISINDEX TAG
+
+   print $query->isindex(-action=>$action);
+
+	 -or-
+
+   print $query->isindex($action);
+
+Prints out an <isindex> tag.  Not very exciting.  The parameter
+-action specifies the URL of the script to process the query.  The
+default is to process the query with the current script.
+
+=head2 STARTING AND ENDING A FORM
+
+    print $query->start_form(-method=>$method,
+			    -action=>$action,
+			    -enctype=>$encoding);
+      <... various form stuff ...>
+    print $query->endform;
+
+	-or-
+
+    print $query->start_form($method,$action,$encoding);
+      <... various form stuff ...>
+    print $query->endform;
+
+start_form() will return a <form> tag with the optional method,
+action and form encoding that you specify.  The defaults are:
+
+    method: POST
+    action: this script
+    enctype: application/x-www-form-urlencoded
+
+endform() returns the closing </form> tag.  
+
+Start_form()'s enctype argument tells the browser how to package the various
+fields of the form before sending the form to the server.  Two
+values are possible:
+
+B<Note:> This method was previously named startform(), and startform()
+is still recognized as an alias.
+
+=over 4
+
+=item B<application/x-www-form-urlencoded>
+
+This is the older type of encoding used by all browsers prior to
+Netscape 2.0.  It is compatible with many CGI scripts and is
+suitable for short fields containing text data.  For your
+convenience, CGI.pm stores the name of this encoding
+type in B<&CGI::URL_ENCODED>.
+
+=item B<multipart/form-data>
+
+This is the newer type of encoding introduced by Netscape 2.0.
+It is suitable for forms that contain very large fields or that
+are intended for transferring binary data.  Most importantly,
+it enables the "file upload" feature of Netscape 2.0 forms.  For
+your convenience, CGI.pm stores the name of this encoding type
+in B<&CGI::MULTIPART>
+
+Forms that use this type of encoding are not easily interpreted
+by CGI scripts unless they use CGI.pm or another library designed
+to handle them.
+
+=back
+
+For compatibility, the start_form() method uses the older form of
+encoding by default.  If you want to use the newer form of encoding
+by default, you can call B<start_multipart_form()> instead of
+B<start_form()>.
+
+JAVASCRIPTING: The B<-name> and B<-onSubmit> parameters are provided
+for use with JavaScript.  The -name parameter gives the
+form a name so that it can be identified and manipulated by
+JavaScript functions.  -onSubmit should point to a JavaScript
+function that will be executed just before the form is submitted to your
+server.  You can use this opportunity to check the contents of the form 
+for consistency and completeness.  If you find something wrong, you
+can put up an alert box or maybe fix things up yourself.  You can 
+abort the submission by returning false from this function.  
+
+Usually the bulk of JavaScript functions are defined in a <script>
+block in the HTML header and -onSubmit points to one of these function
+call.  See start_html() for details.
+
+=head2 CREATING A TEXT FIELD
+
+    print $query->textfield(-name=>'field_name',
+			    -default=>'starting value',
+			    -size=>50,
+			    -maxlength=>80);
+	-or-
+
+    print $query->textfield('field_name','starting value',50,80);
+
+textfield() will return a text input field.  
+
+=over 4
+
+=item B<Parameters>
+
+=item 1.
+
+The first parameter is the required name for the field (-name).  
+
+=item 2.
+
+The optional second parameter is the default starting value for the field
+contents (-default).  
+
+=item 3.
+
+The optional third parameter is the size of the field in
+      characters (-size).
+
+=item 4.
+
+The optional fourth parameter is the maximum number of characters the
+      field will accept (-maxlength).
+
+=back
+
+As with all these methods, the field will be initialized with its 
+previous contents from earlier invocations of the script.
+When the form is processed, the value of the text field can be
+retrieved with:
+
+       $value = $query->param('foo');
+
+If you want to reset it from its initial value after the script has been
+called once, you can do so like this:
+
+       $query->param('foo',"I'm taking over this value!");
+
+NEW AS OF VERSION 2.15: If you don't want the field to take on its previous
+value, you can force its current value by using the -override (alias -force)
+parameter:
+
+    print $query->textfield(-name=>'field_name',
+			    -default=>'starting value',
+			    -override=>1,
+			    -size=>50,
+			    -maxlength=>80);
+
+JAVASCRIPTING: You can also provide B<-onChange>, B<-onFocus>,
+B<-onBlur>, B<-onMouseOver>, B<-onMouseOut> and B<-onSelect>
+parameters to register JavaScript event handlers.  The onChange
+handler will be called whenever the user changes the contents of the
+text field.  You can do text validation if you like.  onFocus and
+onBlur are called respectively when the insertion point moves into and
+out of the text field.  onSelect is called when the user changes the
+portion of the text that is selected.
+
+=head2 CREATING A BIG TEXT FIELD
+
+   print $query->textarea(-name=>'foo',
+			  -default=>'starting value',
+			  -rows=>10,
+			  -columns=>50);
+
+	-or
+
+   print $query->textarea('foo','starting value',10,50);
+
+textarea() is just like textfield, but it allows you to specify
+rows and columns for a multiline text entry box.  You can provide
+a starting value for the field, which can be long and contain
+multiple lines.
+
+JAVASCRIPTING: The B<-onChange>, B<-onFocus>, B<-onBlur> ,
+B<-onMouseOver>, B<-onMouseOut>, and B<-onSelect> parameters are
+recognized.  See textfield().
+
+=head2 CREATING A PASSWORD FIELD
+
+   print $query->password_field(-name=>'secret',
+				-value=>'starting value',
+				-size=>50,
+				-maxlength=>80);
+	-or-
+
+   print $query->password_field('secret','starting value',50,80);
+
+password_field() is identical to textfield(), except that its contents 
+will be starred out on the web page.
+
+JAVASCRIPTING: The B<-onChange>, B<-onFocus>, B<-onBlur>,
+B<-onMouseOver>, B<-onMouseOut> and B<-onSelect> parameters are
+recognized.  See textfield().
+
+=head2 CREATING A FILE UPLOAD FIELD
+
+    print $query->filefield(-name=>'uploaded_file',
+			    -default=>'starting value',
+			    -size=>50,
+			    -maxlength=>80);
+	-or-
+
+    print $query->filefield('uploaded_file','starting value',50,80);
+
+filefield() will return a file upload field for Netscape 2.0 browsers.
+In order to take full advantage of this I<you must use the new 
+multipart encoding scheme> for the form.  You can do this either
+by calling B<start_form()> with an encoding type of B<&CGI::MULTIPART>,
+or by calling the new method B<start_multipart_form()> instead of
+vanilla B<start_form()>.
+
+=over 4
+
+=item B<Parameters>
+
+=item 1.
+
+The first parameter is the required name for the field (-name).  
+
+=item 2.
+
+The optional second parameter is the starting value for the field contents
+to be used as the default file name (-default).
+
+For security reasons, browsers don't pay any attention to this field,
+and so the starting value will always be blank.  Worse, the field
+loses its "sticky" behavior and forgets its previous contents.  The
+starting value field is called for in the HTML specification, however,
+and possibly some browser will eventually provide support for it.
+
+=item 3.
+
+The optional third parameter is the size of the field in
+characters (-size).
+
+=item 4.
+
+The optional fourth parameter is the maximum number of characters the
+field will accept (-maxlength).
+
+=back
+
+When the form is processed, you can retrieve the entered filename
+by calling param():
+
+       $filename = $query->param('uploaded_file');
+
+Different browsers will return slightly different things for the
+name.  Some browsers return the filename only.  Others return the full
+path to the file, using the path conventions of the user's machine.
+Regardless, the name returned is always the name of the file on the
+I<user's> machine, and is unrelated to the name of the temporary file
+that CGI.pm creates during upload spooling (see below).
+
+The filename returned is also a file handle.  You can read the contents
+of the file using standard Perl file reading calls:
+
+	# Read a text file and print it out
+	while (<$filename>) {
+	   print;
+	}
+
+	# Copy a binary file to somewhere safe
+	open (OUTFILE,">>/usr/local/web/users/feedback");
+	while ($bytesread=read($filename,$buffer,1024)) {
+	   print OUTFILE $buffer;
+	}
+
+However, there are problems with the dual nature of the upload fields.
+If you C<use strict>, then Perl will complain when you try to use a
+string as a filehandle.  You can get around this by placing the file
+reading code in a block containing the C<no strict> pragma.  More
+seriously, it is possible for the remote user to type garbage into the
+upload field, in which case what you get from param() is not a
+filehandle at all, but a string.
+
+To be safe, use the I<upload()> function (new in version 2.47).  When
+called with the name of an upload field, I<upload()> returns a
+filehandle, or undef if the parameter is not a valid filehandle.
+
+     $fh = $query->upload('uploaded_file');
+     while (<$fh>) {
+	   print;
+     }
+
+In an array context, upload() will return an array of filehandles.
+This makes it possible to create forms that use the same name for
+multiple upload fields.
+
+This is the recommended idiom.
+
+When a file is uploaded the browser usually sends along some
+information along with it in the format of headers.  The information
+usually includes the MIME content type.  Future browsers may send
+other information as well (such as modification date and size). To
+retrieve this information, call uploadInfo().  It returns a reference to
+an associative array containing all the document headers.
+
+       $filename = $query->param('uploaded_file');
+       $type = $query->uploadInfo($filename)->{'Content-Type'};
+       unless ($type eq 'text/html') {
+	  die "HTML FILES ONLY!";
+       }
+
+If you are using a machine that recognizes "text" and "binary" data
+modes, be sure to understand when and how to use them (see the Camel book).  
+Otherwise you may find that binary files are corrupted during file
+uploads.
+
+There are occasionally problems involving parsing the uploaded file.
+This usually happens when the user presses "Stop" before the upload is
+finished.  In this case, CGI.pm will return undef for the name of the
+uploaded file and set I<cgi_error()> to the string "400 Bad request
+(malformed multipart POST)".  This error message is designed so that
+you can incorporate it into a status code to be sent to the browser.
+Example:
+
+   $file = $query->upload('uploaded_file');
+   if (!$file && $query->cgi_error) {
+      print $query->header(-status=>$query->cgi_error);
+      exit 0;
+   }
+
+You are free to create a custom HTML page to complain about the error,
+if you wish.
+
+If you are using CGI.pm on a Windows platform and find that binary
+files get slightly larger when uploaded but that text files remain the
+same, then you have forgotten to activate binary mode on the output
+filehandle.  Be sure to call binmode() on any handle that you create
+to write the uploaded file to disk.
+
+JAVASCRIPTING: The B<-onChange>, B<-onFocus>, B<-onBlur>,
+B<-onMouseOver>, B<-onMouseOut> and B<-onSelect> parameters are
+recognized.  See textfield() for details.
+
+=head2 CREATING A POPUP MENU
+
+   print $query->popup_menu('menu_name',
+			    ['eenie','meenie','minie'],
+			    'meenie');
+
+      -or-
+
+   %labels = ('eenie'=>'your first choice',
+	      'meenie'=>'your second choice',
+	      'minie'=>'your third choice');
+   print $query->popup_menu('menu_name',
+			    ['eenie','meenie','minie'],
+			    'meenie',\%labels);
+
+	-or (named parameter style)-
+
+   print $query->popup_menu(-name=>'menu_name',
+			    -values=>['eenie','meenie','minie'],
+			    -default=>'meenie',
+			    -labels=>\%labels);
+
+popup_menu() creates a menu.
+
+=over 4
+
+=item 1.
+
+The required first argument is the menu's name (-name).
+
+=item 2.
+
+The required second argument (-values) is an array B<reference>
+containing the list of menu items in the menu.  You can pass the
+method an anonymous array, as shown in the example, or a reference to
+a named array, such as "\@foo".
+
+=item 3.
+
+The optional third parameter (-default) is the name of the default
+menu choice.  If not specified, the first item will be the default.
+The values of the previous choice will be maintained across queries.
+
+=item 4.
+
+The optional fourth parameter (-labels) is provided for people who
+want to use different values for the user-visible label inside the
+popup menu nd the value returned to your script.  It's a pointer to an
+associative array relating menu values to user-visible labels.  If you
+leave this parameter blank, the menu values will be displayed by
+default.  (You can also leave a label undefined if you want to).
+
+=back
+
+When the form is processed, the selected value of the popup menu can
+be retrieved using:
+
+      $popup_menu_value = $query->param('menu_name');
+
+JAVASCRIPTING: popup_menu() recognizes the following event handlers:
+B<-onChange>, B<-onFocus>, B<-onMouseOver>, B<-onMouseOut>, and
+B<-onBlur>.  See the textfield() section for details on when these
+handlers are called.
+
+=head2 CREATING A SCROLLING LIST
+
+   print $query->scrolling_list('list_name',
+				['eenie','meenie','minie','moe'],
+				['eenie','moe'],5,'true');
+      -or-
+
+   print $query->scrolling_list('list_name',
+				['eenie','meenie','minie','moe'],
+				['eenie','moe'],5,'true',
+				\%labels);
+
+	-or-
+
+   print $query->scrolling_list(-name=>'list_name',
+				-values=>['eenie','meenie','minie','moe'],
+				-default=>['eenie','moe'],
+				-size=>5,
+				-multiple=>'true',
+				-labels=>\%labels);
+
+scrolling_list() creates a scrolling list.  
+
+=over 4
+
+=item B<Parameters:>
+
+=item 1.
+
+The first and second arguments are the list name (-name) and values
+(-values).  As in the popup menu, the second argument should be an
+array reference.
+
+=item 2.
+
+The optional third argument (-default) can be either a reference to a
+list containing the values to be selected by default, or can be a
+single value to select.  If this argument is missing or undefined,
+then nothing is selected when the list first appears.  In the named
+parameter version, you can use the synonym "-defaults" for this
+parameter.
+
+=item 3.
+
+The optional fourth argument is the size of the list (-size).
+
+=item 4.
+
+The optional fifth argument can be set to true to allow multiple
+simultaneous selections (-multiple).  Otherwise only one selection
+will be allowed at a time.
+
+=item 5.
+
+The optional sixth argument is a pointer to an associative array
+containing long user-visible labels for the list items (-labels).
+If not provided, the values will be displayed.
+
+When this form is processed, all selected list items will be returned as
+a list under the parameter name 'list_name'.  The values of the
+selected items can be retrieved with:
+
+      @selected = $query->param('list_name');
+
+=back
+
+JAVASCRIPTING: scrolling_list() recognizes the following event
+handlers: B<-onChange>, B<-onFocus>, B<-onMouseOver>, B<-onMouseOut>
+and B<-onBlur>.  See textfield() for the description of when these
+handlers are called.
+
+=head2 CREATING A GROUP OF RELATED CHECKBOXES
+
+   print $query->checkbox_group(-name=>'group_name',
+				-values=>['eenie','meenie','minie','moe'],
+				-default=>['eenie','moe'],
+				-linebreak=>'true',
+				-labels=>\%labels);
+
+   print $query->checkbox_group('group_name',
+				['eenie','meenie','minie','moe'],
+				['eenie','moe'],'true',\%labels);
+
+   HTML3-COMPATIBLE BROWSERS ONLY:
+
+   print $query->checkbox_group(-name=>'group_name',
+				-values=>['eenie','meenie','minie','moe'],
+				-rows=2,-columns=>2);
+
+
+checkbox_group() creates a list of checkboxes that are related
+by the same name.
+
+=over 4
+
+=item B<Parameters:>
+
+=item 1.
+
+The first and second arguments are the checkbox name and values,
+respectively (-name and -values).  As in the popup menu, the second
+argument should be an array reference.  These values are used for the
+user-readable labels printed next to the checkboxes as well as for the
+values passed to your script in the query string.
+
+=item 2.
+
+The optional third argument (-default) can be either a reference to a
+list containing the values to be checked by default, or can be a
+single value to checked.  If this argument is missing or undefined,
+then nothing is selected when the list first appears.
+
+=item 3.
+
+The optional fourth argument (-linebreak) can be set to true to place
+line breaks between the checkboxes so that they appear as a vertical
+list.  Otherwise, they will be strung together on a horizontal line.
+
+=item 4.
+
+The optional fifth argument is a pointer to an associative array
+relating the checkbox values to the user-visible labels that will
+be printed next to them (-labels).  If not provided, the values will
+be used as the default.
+
+=item 5.
+
+B<HTML3-compatible browsers> (such as Netscape) can take advantage of
+the optional parameters B<-rows>, and B<-columns>.  These parameters
+cause checkbox_group() to return an HTML3 compatible table containing
+the checkbox group formatted with the specified number of rows and
+columns.  You can provide just the -columns parameter if you wish;
+checkbox_group will calculate the correct number of rows for you.
+
+To include row and column headings in the returned table, you
+can use the B<-rowheaders> and B<-colheaders> parameters.  Both
+of these accept a pointer to an array of headings to use.
+The headings are just decorative.  They don't reorganize the
+interpretation of the checkboxes -- they're still a single named
+unit.
+
+=back
+
+When the form is processed, all checked boxes will be returned as
+a list under the parameter name 'group_name'.  The values of the
+"on" checkboxes can be retrieved with:
+
+      @turned_on = $query->param('group_name');
+
+The value returned by checkbox_group() is actually an array of button
+elements.  You can capture them and use them within tables, lists,
+or in other creative ways:
+
+    @h = $query->checkbox_group(-name=>'group_name',-values=>\@values);
+    &use_in_creative_way(@h);
+
+JAVASCRIPTING: checkbox_group() recognizes the B<-onClick>
+parameter.  This specifies a JavaScript code fragment or
+function call to be executed every time the user clicks on
+any of the buttons in the group.  You can retrieve the identity
+of the particular button clicked on using the "this" variable.
+
+=head2 CREATING A STANDALONE CHECKBOX
+
+    print $query->checkbox(-name=>'checkbox_name',
+			   -checked=>1,
+			   -value=>'ON',
+			   -label=>'CLICK ME');
+
+	-or-
+
+    print $query->checkbox('checkbox_name','checked','ON','CLICK ME');
+
+checkbox() is used to create an isolated checkbox that isn't logically
+related to any others.
+
+=over 4
+
+=item B<Parameters:>
+
+=item 1.
+
+The first parameter is the required name for the checkbox (-name).  It
+will also be used for the user-readable label printed next to the
+checkbox.
+
+=item 2.
+
+The optional second parameter (-checked) specifies that the checkbox
+is turned on by default.  Synonyms are -selected and -on.
+
+=item 3.
+
+The optional third parameter (-value) specifies the value of the
+checkbox when it is checked.  If not provided, the word "on" is
+assumed.
+
+=item 4.
+
+The optional fourth parameter (-label) is the user-readable label to
+be attached to the checkbox.  If not provided, the checkbox name is
+used.
+
+=back
+
+The value of the checkbox can be retrieved using:
+
+    $turned_on = $query->param('checkbox_name');
+
+JAVASCRIPTING: checkbox() recognizes the B<-onClick>
+parameter.  See checkbox_group() for further details.
+
+=head2 CREATING A RADIO BUTTON GROUP
+
+   print $query->radio_group(-name=>'group_name',
+			     -values=>['eenie','meenie','minie'],
+			     -default=>'meenie',
+			     -linebreak=>'true',
+			     -labels=>\%labels);
+
+	-or-
+
+   print $query->radio_group('group_name',['eenie','meenie','minie'],
+					  'meenie','true',\%labels);
+
+
+   HTML3-COMPATIBLE BROWSERS ONLY:
+
+   print $query->radio_group(-name=>'group_name',
+			     -values=>['eenie','meenie','minie','moe'],
+			     -rows=2,-columns=>2);
+
+radio_group() creates a set of logically-related radio buttons
+(turning one member of the group on turns the others off)
+
+=over 4
+
+=item B<Parameters:>
+
+=item 1.
+
+The first argument is the name of the group and is required (-name).
+
+=item 2.
+
+The second argument (-values) is the list of values for the radio
+buttons.  The values and the labels that appear on the page are
+identical.  Pass an array I<reference> in the second argument, either
+using an anonymous array, as shown, or by referencing a named array as
+in "\@foo".
+
+=item 3.
+
+The optional third parameter (-default) is the name of the default
+button to turn on. If not specified, the first item will be the
+default.  You can provide a nonexistent button name, such as "-" to
+start up with no buttons selected.
+
+=item 4.
+
+The optional fourth parameter (-linebreak) can be set to 'true' to put
+line breaks between the buttons, creating a vertical list.
+
+=item 5.
+
+The optional fifth parameter (-labels) is a pointer to an associative
+array relating the radio button values to user-visible labels to be
+used in the display.  If not provided, the values themselves are
+displayed.
+
+=item 6.
+
+B<HTML3-compatible browsers> (such as Netscape) can take advantage 
+of the optional 
+parameters B<-rows>, and B<-columns>.  These parameters cause
+radio_group() to return an HTML3 compatible table containing
+the radio group formatted with the specified number of rows
+and columns.  You can provide just the -columns parameter if you
+wish; radio_group will calculate the correct number of rows
+for you.
+
+To include row and column headings in the returned table, you
+can use the B<-rowheader> and B<-colheader> parameters.  Both
+of these accept a pointer to an array of headings to use.
+The headings are just decorative.  They don't reorganize the
+interpretation of the radio buttons -- they're still a single named
+unit.
+
+=back
+
+When the form is processed, the selected radio button can
+be retrieved using:
+
+      $which_radio_button = $query->param('group_name');
+
+The value returned by radio_group() is actually an array of button
+elements.  You can capture them and use them within tables, lists,
+or in other creative ways:
+
+    @h = $query->radio_group(-name=>'group_name',-values=>\@values);
+    &use_in_creative_way(@h);
+
+=head2 CREATING A SUBMIT BUTTON 
+
+   print $query->submit(-name=>'button_name',
+			-value=>'value');
+
+	-or-
+
+   print $query->submit('button_name','value');
+
+submit() will create the query submission button.  Every form
+should have one of these.
+
+=over 4
+
+=item B<Parameters:>
+
+=item 1.
+
+The first argument (-name) is optional.  You can give the button a
+name if you have several submission buttons in your form and you want
+to distinguish between them.  The name will also be used as the
+user-visible label.  Be aware that a few older browsers don't deal with this correctly and
+B<never> send back a value from a button.
+
+=item 2.
+
+The second argument (-value) is also optional.  This gives the button
+a value that will be passed to your script in the query string.
+
+=back
+
+You can figure out which button was pressed by using different
+values for each one:
+
+     $which_one = $query->param('button_name');
+
+JAVASCRIPTING: radio_group() recognizes the B<-onClick>
+parameter.  See checkbox_group() for further details.
+
+=head2 CREATING A RESET BUTTON
+
+   print $query->reset
+
+reset() creates the "reset" button.  Note that it restores the
+form to its value from the last time the script was called, 
+NOT necessarily to the defaults.
+
+Note that this conflicts with the Perl reset() built-in.  Use
+CORE::reset() to get the original reset function.
+
+=head2 CREATING A DEFAULT BUTTON
+
+   print $query->defaults('button_label')
+
+defaults() creates a button that, when invoked, will cause the
+form to be completely reset to its defaults, wiping out all the
+changes the user ever made.
+
+=head2 CREATING A HIDDEN FIELD
+
+	print $query->hidden(-name=>'hidden_name',
+			     -default=>['value1','value2'...]);
+
+		-or-
+
+	print $query->hidden('hidden_name','value1','value2'...);
+
+hidden() produces a text field that can't be seen by the user.  It
+is useful for passing state variable information from one invocation
+of the script to the next.
+
+=over 4
+
+=item B<Parameters:>
+
+=item 1.
+
+The first argument is required and specifies the name of this
+field (-name).
+
+=item 2.  
+
+The second argument is also required and specifies its value
+(-default).  In the named parameter style of calling, you can provide
+a single value here or a reference to a whole list
+
+=back
+
+Fetch the value of a hidden field this way:
+
+     $hidden_value = $query->param('hidden_name');
+
+Note, that just like all the other form elements, the value of a
+hidden field is "sticky".  If you want to replace a hidden field with
+some other values after the script has been called once you'll have to
+do it manually:
+
+     $query->param('hidden_name','new','values','here');
+
+=head2 CREATING A CLICKABLE IMAGE BUTTON
+
+     print $query->image_button(-name=>'button_name',
+				-src=>'/source/URL',
+				-align=>'MIDDLE');      
+
+	-or-
+
+     print $query->image_button('button_name','/source/URL','MIDDLE');
+
+image_button() produces a clickable image.  When it's clicked on the
+position of the click is returned to your script as "button_name.x"
+and "button_name.y", where "button_name" is the name you've assigned
+to it.
+
+JAVASCRIPTING: image_button() recognizes the B<-onClick>
+parameter.  See checkbox_group() for further details.
+
+=over 4
+
+=item B<Parameters:>
+
+=item 1.
+
+The first argument (-name) is required and specifies the name of this
+field.
+
+=item 2.
+
+The second argument (-src) is also required and specifies the URL
+
+=item 3.
+
+The third option (-align, optional) is an alignment type, and may be
+TOP, BOTTOM or MIDDLE
+
+=back
+
+Fetch the value of the button this way:
+     $x = $query->param('button_name.x');
+     $y = $query->param('button_name.y');
+
+=head2 CREATING A JAVASCRIPT ACTION BUTTON
+
+     print $query->button(-name=>'button_name',
+			  -value=>'user visible label',
+			  -onClick=>"do_something()");
+
+	-or-
+
+     print $query->button('button_name',"do_something()");
+
+button() produces a button that is compatible with Netscape 2.0's
+JavaScript.  When it's pressed the fragment of JavaScript code
+pointed to by the B<-onClick> parameter will be executed.  On
+non-Netscape browsers this form element will probably not even
+display.
+
+=head1 HTTP COOKIES
+
+Netscape browsers versions 1.1 and higher, and all versions of
+Internet Explorer, support a so-called "cookie" designed to help
+maintain state within a browser session.  CGI.pm has several methods
+that support cookies.
+
+A cookie is a name=value pair much like the named parameters in a CGI
+query string.  CGI scripts create one or more cookies and send
+them to the browser in the HTTP header.  The browser maintains a list
+of cookies that belong to a particular Web server, and returns them
+to the CGI script during subsequent interactions.
+
+In addition to the required name=value pair, each cookie has several
+optional attributes:
+
+=over 4
+
+=item 1. an expiration time
+
+This is a time/date string (in a special GMT format) that indicates
+when a cookie expires.  The cookie will be saved and returned to your
+script until this expiration date is reached if the user exits
+the browser and restarts it.  If an expiration date isn't specified, the cookie
+will remain active until the user quits the browser.
+
+=item 2. a domain
+
+This is a partial or complete domain name for which the cookie is 
+valid.  The browser will return the cookie to any host that matches
+the partial domain name.  For example, if you specify a domain name
+of ".capricorn.com", then the browser will return the cookie to
+Web servers running on any of the machines "www.capricorn.com", 
+"www2.capricorn.com", "feckless.capricorn.com", etc.  Domain names
+must contain at least two periods to prevent attempts to match
+on top level domains like ".edu".  If no domain is specified, then
+the browser will only return the cookie to servers on the host the
+cookie originated from.
+
+=item 3. a path
+
+If you provide a cookie path attribute, the browser will check it
+against your script's URL before returning the cookie.  For example,
+if you specify the path "/cgi-bin", then the cookie will be returned
+to each of the scripts "/cgi-bin/tally.pl", "/cgi-bin/order.pl",
+and "/cgi-bin/customer_service/complain.pl", but not to the script
+"/cgi-private/site_admin.pl".  By default, path is set to "/", which
+causes the cookie to be sent to any CGI script on your site.
+
+=item 4. a "secure" flag
+
+If the "secure" attribute is set, the cookie will only be sent to your
+script if the CGI request is occurring on a secure channel, such as SSL.
+
+=back
+
+The interface to HTTP cookies is the B<cookie()> method:
+
+    $cookie = $query->cookie(-name=>'sessionID',
+			     -value=>'xyzzy',
+			     -expires=>'+1h',
+			     -path=>'/cgi-bin/database',
+			     -domain=>'.capricorn.org',
+			     -secure=>1);
+    print $query->header(-cookie=>$cookie);
+
+B<cookie()> creates a new cookie.  Its parameters include:
+
+=over 4
+
+=item B<-name>
+
+The name of the cookie (required).  This can be any string at all.
+Although browsers limit their cookie names to non-whitespace
+alphanumeric characters, CGI.pm removes this restriction by escaping
+and unescaping cookies behind the scenes.
+
+=item B<-value>
+
+The value of the cookie.  This can be any scalar value,
+array reference, or even associative array reference.  For example,
+you can store an entire associative array into a cookie this way:
+
+	$cookie=$query->cookie(-name=>'family information',
+			       -value=>\%childrens_ages);
+
+=item B<-path>
+
+The optional partial path for which this cookie will be valid, as described
+above.
+
+=item B<-domain>
+
+The optional partial domain for which this cookie will be valid, as described
+above.
+
+=item B<-expires>
+
+The optional expiration date for this cookie.  The format is as described 
+in the section on the B<header()> method:
+
+	"+1h"  one hour from now
+
+=item B<-secure>
+
+If set to true, this cookie will only be used within a secure
+SSL session.
+
+=back
+
+The cookie created by cookie() must be incorporated into the HTTP
+header within the string returned by the header() method:
+
+	print $query->header(-cookie=>$my_cookie);
+
+To create multiple cookies, give header() an array reference:
+
+	$cookie1 = $query->cookie(-name=>'riddle_name',
+				  -value=>"The Sphynx's Question");
+	$cookie2 = $query->cookie(-name=>'answers',
+				  -value=>\%answers);
+	print $query->header(-cookie=>[$cookie1,$cookie2]);
+
+To retrieve a cookie, request it by name by calling cookie() method
+without the B<-value> parameter:
+
+	use CGI;
+	$query = new CGI;
+	$riddle = $query->cookie('riddle_name');
+        %answers = $query->cookie('answers');
+
+Cookies created with a single scalar value, such as the "riddle_name"
+cookie, will be returned in that form.  Cookies with array and hash
+values can also be retrieved.
+
+The cookie and CGI namespaces are separate.  If you have a parameter
+named 'answers' and a cookie named 'answers', the values retrieved by
+param() and cookie() are independent of each other.  However, it's
+simple to turn a CGI parameter into a cookie, and vice-versa:
+
+   # turn a CGI parameter into a cookie
+   $c=$q->cookie(-name=>'answers',-value=>[$q->param('answers')]);
+   # vice-versa
+   $q->param(-name=>'answers',-value=>[$q->cookie('answers')]);
+
+See the B<cookie.cgi> example script for some ideas on how to use
+cookies effectively.
+
+=head1 WORKING WITH FRAMES
+
+It's possible for CGI.pm scripts to write into several browser panels
+and windows using the HTML 4 frame mechanism.  There are three
+techniques for defining new frames programmatically:
+
+=over 4
+
+=item 1. Create a <Frameset> document
+
+After writing out the HTTP header, instead of creating a standard
+HTML document using the start_html() call, create a <frameset> 
+document that defines the frames on the page.  Specify your script(s)
+(with appropriate parameters) as the SRC for each of the frames.
+
+There is no specific support for creating <frameset> sections 
+in CGI.pm, but the HTML is very simple to write.  See the frame
+documentation in Netscape's home pages for details 
+
+  http://home.netscape.com/assist/net_sites/frames.html
+
+=item 2. Specify the destination for the document in the HTTP header
+
+You may provide a B<-target> parameter to the header() method:
+
+    print $q->header(-target=>'ResultsWindow');
+
+This will tell the browser to load the output of your script into the
+frame named "ResultsWindow".  If a frame of that name doesn't already
+exist, the browser will pop up a new window and load your script's
+document into that.  There are a number of magic names that you can
+use for targets.  See the frame documents on Netscape's home pages for
+details.
+
+=item 3. Specify the destination for the document in the <form> tag
+
+You can specify the frame to load in the FORM tag itself.  With
+CGI.pm it looks like this:
+
+    print $q->start_form(-target=>'ResultsWindow');
+
+When your script is reinvoked by the form, its output will be loaded
+into the frame named "ResultsWindow".  If one doesn't already exist
+a new window will be created.
+
+=back
+
+The script "frameset.cgi" in the examples directory shows one way to
+create pages in which the fill-out form and the response live in
+side-by-side frames.
+
+=head1 LIMITED SUPPORT FOR CASCADING STYLE SHEETS
+
+CGI.pm has limited support for HTML3's cascading style sheets (css).
+To incorporate a stylesheet into your document, pass the
+start_html() method a B<-style> parameter.  The value of this
+parameter may be a scalar, in which case it is incorporated directly
+into a <style> section, or it may be a hash reference.  In the latter
+case you should provide the hash with one or more of B<-src> or
+B<-code>.  B<-src> points to a URL where an externally-defined
+stylesheet can be found.  B<-code> points to a scalar value to be
+incorporated into a <style> section.  Style definitions in B<-code>
+override similarly-named ones in B<-src>, hence the name "cascading."
+
+You may also specify the type of the stylesheet by adding the optional
+B<-type> parameter to the hash pointed to by B<-style>.  If not
+specified, the style defaults to 'text/css'.
+
+To refer to a style within the body of your document, add the
+B<-class> parameter to any HTML element:
+
+    print h1({-class=>'Fancy'},'Welcome to the Party');
+
+Or define styles on the fly with the B<-style> parameter:
+
+    print h1({-style=>'Color: red;'},'Welcome to Hell');
+
+You may also use the new B<span()> element to apply a style to a
+section of text:
+
+    print span({-style=>'Color: red;'},
+	       h1('Welcome to Hell'),
+	       "Where did that handbasket get to?"
+	       );
+
+Note that you must import the ":html3" definitions to have the
+B<span()> method available.  Here's a quick and dirty example of using
+CSS's.  See the CSS specification at
+http://www.w3.org/pub/WWW/TR/Wd-css-1.html for more information.
+
+    use CGI qw/:standard :html3/;
+
+    #here's a stylesheet incorporated directly into the page
+    $newStyle=<<END;
+    <!-- 
+    P.Tip {
+	margin-right: 50pt;
+	margin-left: 50pt;
+        color: red;
+    }
+    P.Alert {
+	font-size: 30pt;
+        font-family: sans-serif;
+      color: red;
+    }
+    -->
+    END
+    print header();
+    print start_html( -title=>'CGI with Style',
+		      -style=>{-src=>'http://www.capricorn.com/style/st1.css',
+		               -code=>$newStyle}
+	             );
+    print h1('CGI with Style'),
+          p({-class=>'Tip'},
+	    "Better read the cascading style sheet spec before playing with this!"),
+          span({-style=>'color: magenta'},
+	       "Look Mom, no hands!",
+	       p(),
+	       "Whooo wee!"
+	       );
+    print end_html;
+
+Pass an array reference to B<-style> in order to incorporate multiple
+stylesheets into your document.
+
+=head1 DEBUGGING
+
+If you are running the script from the command line or in the perl
+debugger, you can pass the script a list of keywords or
+parameter=value pairs on the command line or from standard input (you
+don't have to worry about tricking your script into reading from
+environment variables).  You can pass keywords like this:
+
+    your_script.pl keyword1 keyword2 keyword3
+
+or this:
+
+   your_script.pl keyword1+keyword2+keyword3
+
+or this:
+
+    your_script.pl name1=value1 name2=value2
+
+or this:
+
+    your_script.pl name1=value1&name2=value2
+
+To turn off this feature, use the -no_debug pragma.
+
+To test the POST method, you may enable full debugging with the -debug
+pragma.  This will allow you to feed newline-delimited name=value
+pairs to the script on standard input.
+
+When debugging, you can use quotes and backslashes to escape 
+characters in the familiar shell manner, letting you place
+spaces and other funny characters in your parameter=value
+pairs:
+
+   your_script.pl "name1='I am a long value'" "name2=two\ words"
+
+=head2 DUMPING OUT ALL THE NAME/VALUE PAIRS
+
+The Dump() method produces a string consisting of all the query's
+name/value pairs formatted nicely as a nested list.  This is useful
+for debugging purposes:
+
+    print $query->Dump
+
+
+Produces something that looks like:
+
+    <ul>
+    <li>name1
+	<ul>
+	<li>value1
+	<li>value2
+	</ul>
+    <li>name2
+	<ul>
+	<li>value1
+	</ul>
+    </ul>
+
+As a shortcut, you can interpolate the entire CGI object into a string
+and it will be replaced with the a nice HTML dump shown above:
+
+    $query=new CGI;
+    print "<h2>Current Values</h2> $query\n";
+
+=head1 FETCHING ENVIRONMENT VARIABLES
+
+Some of the more useful environment variables can be fetched
+through this interface.  The methods are as follows:
+
+=over 4
+
+=item B<Accept()>
+
+Return a list of MIME types that the remote browser accepts. If you
+give this method a single argument corresponding to a MIME type, as in
+$query->Accept('text/html'), it will return a floating point value
+corresponding to the browser's preference for this type from 0.0
+(don't want) to 1.0.  Glob types (e.g. text/*) in the browser's accept
+list are handled correctly.
+
+Note that the capitalization changed between version 2.43 and 2.44 in
+order to avoid conflict with Perl's accept() function.
+
+=item B<raw_cookie()>
+
+Returns the HTTP_COOKIE variable, an HTTP extension implemented by
+Netscape browsers version 1.1 and higher, and all versions of Internet
+Explorer.  Cookies have a special format, and this method call just
+returns the raw form (?cookie dough).  See cookie() for ways of
+setting and retrieving cooked cookies.
+
+Called with no parameters, raw_cookie() returns the packed cookie
+structure.  You can separate it into individual cookies by splitting
+on the character sequence "; ".  Called with the name of a cookie,
+retrieves the B<unescaped> form of the cookie.  You can use the
+regular cookie() method to get the names, or use the raw_fetch()
+method from the CGI::Cookie module.
+
+=item B<user_agent()>
+
+Returns the HTTP_USER_AGENT variable.  If you give
+this method a single argument, it will attempt to
+pattern match on it, allowing you to do something
+like $query->user_agent(netscape);
+
+=item B<path_info()>
+
+Returns additional path information from the script URL.
+E.G. fetching /cgi-bin/your_script/additional/stuff will result in
+$query->path_info() returning "/additional/stuff".
+
+NOTE: The Microsoft Internet Information Server
+is broken with respect to additional path information.  If
+you use the Perl DLL library, the IIS server will attempt to
+execute the additional path information as a Perl script.
+If you use the ordinary file associations mapping, the
+path information will be present in the environment, 
+but incorrect.  The best thing to do is to avoid using additional
+path information in CGI scripts destined for use with IIS.
+
+=item B<path_translated()>
+
+As per path_info() but returns the additional
+path information translated into a physical path, e.g.
+"/usr/local/etc/httpd/htdocs/additional/stuff".
+
+The Microsoft IIS is broken with respect to the translated
+path as well.
+
+=item B<remote_host()>
+
+Returns either the remote host name or IP address.
+if the former is unavailable.
+
+=item B<script_name()>
+
+Return the script name as a partial URL, for self-refering
+scripts.
+
+=item B<referer()>
+
+Return the URL of the page the browser was viewing
+prior to fetching your script.  Not available for all
+browsers.
+
+=item B<auth_type ()>
+
+Return the authorization/verification method in use for this
+script, if any.
+
+=item B<server_name ()>
+
+Returns the name of the server, usually the machine's host
+name.
+
+=item B<virtual_host ()>
+
+When using virtual hosts, returns the name of the host that
+the browser attempted to contact
+
+=item B<server_port ()>
+
+Return the port that the server is listening on.
+
+=item B<server_software ()>
+
+Returns the server software and version number.
+
+=item B<remote_user ()>
+
+Return the authorization/verification name used for user
+verification, if this script is protected.
+
+=item B<user_name ()>
+
+Attempt to obtain the remote user's name, using a variety of different
+techniques.  This only works with older browsers such as Mosaic.
+Newer browsers do not report the user name for privacy reasons!
+
+=item B<request_method()>
+
+Returns the method used to access your script, usually
+one of 'POST', 'GET' or 'HEAD'.
+
+=item B<content_type()>
+
+Returns the content_type of data submitted in a POST, generally 
+multipart/form-data or application/x-www-form-urlencoded
+
+=item B<http()>
+
+Called with no arguments returns the list of HTTP environment
+variables, including such things as HTTP_USER_AGENT,
+HTTP_ACCEPT_LANGUAGE, and HTTP_ACCEPT_CHARSET, corresponding to the
+like-named HTTP header fields in the request.  Called with the name of
+an HTTP header field, returns its value.  Capitalization and the use
+of hyphens versus underscores are not significant.
+
+For example, all three of these examples are equivalent:
+
+   $requested_language = $q->http('Accept-language');
+   $requested_language = $q->http('Accept_language');
+   $requested_language = $q->http('HTTP_ACCEPT_LANGUAGE');
+
+=item B<https()>
+
+The same as I<http()>, but operates on the HTTPS environment variables
+present when the SSL protocol is in effect.  Can be used to determine
+whether SSL is turned on.
+
+=back
+
+=head1 USING NPH SCRIPTS
+
+NPH, or "no-parsed-header", scripts bypass the server completely by
+sending the complete HTTP header directly to the browser.  This has
+slight performance benefits, but is of most use for taking advantage
+of HTTP extensions that are not directly supported by your server,
+such as server push and PICS headers.
+
+Servers use a variety of conventions for designating CGI scripts as
+NPH.  Many Unix servers look at the beginning of the script's name for
+the prefix "nph-".  The Macintosh WebSTAR server and Microsoft's
+Internet Information Server, in contrast, try to decide whether a
+program is an NPH script by examining the first line of script output.
+
+
+CGI.pm supports NPH scripts with a special NPH mode.  When in this
+mode, CGI.pm will output the necessary extra header information when
+the header() and redirect() methods are
+called.
+
+The Microsoft Internet Information Server requires NPH mode.  As of
+version 2.30, CGI.pm will automatically detect when the script is
+running under IIS and put itself into this mode.  You do not need to
+do this manually, although it won't hurt anything if you do.  However,
+note that if you have applied Service Pack 6, much of the
+functionality of NPH scripts, including the ability to redirect while
+setting a cookie, b<do not work at all> on IIS without a special patch
+from Microsoft.  See
+http://support.microsoft.com/support/kb/articles/Q280/3/41.ASP:
+Non-Parsed Headers Stripped From CGI Applications That Have nph-
+Prefix in Name.
+
+=over 4
+
+=item In the B<use> statement 
+
+Simply add the "-nph" pragmato the list of symbols to be imported into
+your script:
+
+      use CGI qw(:standard -nph)
+
+=item By calling the B<nph()> method:
+
+Call B<nph()> with a non-zero parameter at any point after using CGI.pm in your program.
+
+      CGI->nph(1)
+
+=item By using B<-nph> parameters
+
+in the B<header()> and B<redirect()>  statements:
+
+      print $q->header(-nph=>1);
+
+=back
+
+=head1 Server Push
+
+CGI.pm provides four simple functions for producing multipart
+documents of the type needed to implement server push.  These
+functions were graciously provided by Ed Jordan <ed@fidalgo.net>.  To
+import these into your namespace, you must import the ":push" set.
+You are also advised to put the script into NPH mode and to set $| to
+1 to avoid buffering problems.
+
+Here is a simple script that demonstrates server push:
+
+  #!/usr/local/bin/perl
+  use CGI qw/:push -nph/;
+  $| = 1;
+  print multipart_init(-boundary=>'----here we go!');
+  foreach (0 .. 4) {
+      print multipart_start(-type=>'text/plain'),
+            "The current time is ",scalar(localtime),"\n";
+      if ($_ < 4) {
+              print multipart_end;
+      } else {
+              print multipart_final;
+      }
+      sleep 1;
+  }
+
+This script initializes server push by calling B<multipart_init()>.
+It then enters a loop in which it begins a new multipart section by
+calling B<multipart_start()>, prints the current local time,
+and ends a multipart section with B<multipart_end()>.  It then sleeps
+a second, and begins again. On the final iteration, it ends the
+multipart section with B<multipart_final()> rather than with
+B<multipart_end()>.
+
+=over 4
+
+=item multipart_init()
+
+  multipart_init(-boundary=>$boundary);
+
+Initialize the multipart system.  The -boundary argument specifies
+what MIME boundary string to use to separate parts of the document.
+If not provided, CGI.pm chooses a reasonable boundary for you.
+
+=item multipart_start()
+
+  multipart_start(-type=>$type)
+
+Start a new part of the multipart document using the specified MIME
+type.  If not specified, text/html is assumed.
+
+=item multipart_end()
+
+  multipart_end()
+
+End a part.  You must remember to call multipart_end() once for each
+multipart_start(), except at the end of the last part of the multipart
+document when multipart_final() should be called instead of multipart_end().
+
+=item multipart_final()
+
+  multipart_final()
+
+End all parts.  You should call multipart_final() rather than
+multipart_end() at the end of the last part of the multipart document.
+
+=back
+
+Users interested in server push applications should also have a look
+at the CGI::Push module.
+
+Only Netscape Navigator supports server push.  Internet Explorer
+browsers do not.
+
+=head1 Avoiding Denial of Service Attacks
+
+A potential problem with CGI.pm is that, by default, it attempts to
+process form POSTings no matter how large they are.  A wily hacker
+could attack your site by sending a CGI script a huge POST of many
+megabytes.  CGI.pm will attempt to read the entire POST into a
+variable, growing hugely in size until it runs out of memory.  While
+the script attempts to allocate the memory the system may slow down
+dramatically.  This is a form of denial of service attack.
+
+Another possible attack is for the remote user to force CGI.pm to
+accept a huge file upload.  CGI.pm will accept the upload and store it
+in a temporary directory even if your script doesn't expect to receive
+an uploaded file.  CGI.pm will delete the file automatically when it
+terminates, but in the meantime the remote user may have filled up the
+server's disk space, causing problems for other programs.
+
+The best way to avoid denial of service attacks is to limit the amount
+of memory, CPU time and disk space that CGI scripts can use.  Some Web
+servers come with built-in facilities to accomplish this. In other
+cases, you can use the shell I<limit> or I<ulimit>
+commands to put ceilings on CGI resource usage.
+
+
+CGI.pm also has some simple built-in protections against denial of
+service attacks, but you must activate them before you can use them.
+These take the form of two global variables in the CGI name space:
+
+=over 4
+
+=item B<$CGI::POST_MAX>
+
+If set to a non-negative integer, this variable puts a ceiling
+on the size of POSTings, in bytes.  If CGI.pm detects a POST
+that is greater than the ceiling, it will immediately exit with an error
+message.  This value will affect both ordinary POSTs and
+multipart POSTs, meaning that it limits the maximum size of file
+uploads as well.  You should set this to a reasonably high
+value, such as 1 megabyte.
+
+=item B<$CGI::DISABLE_UPLOADS>
+
+If set to a non-zero value, this will disable file uploads
+completely.  Other fill-out form values will work as usual.
+
+=back
+
+You can use these variables in either of two ways.
+
+=over 4
+
+=item B<1. On a script-by-script basis>
+
+Set the variable at the top of the script, right after the "use" statement:
+
+    use CGI qw/:standard/;
+    use CGI::Carp 'fatalsToBrowser';
+    $CGI::POST_MAX=1024 * 100;  # max 100K posts
+    $CGI::DISABLE_UPLOADS = 1;  # no uploads
+
+=item B<2. Globally for all scripts>
+
+Open up CGI.pm, find the definitions for $POST_MAX and 
+$DISABLE_UPLOADS, and set them to the desired values.  You'll 
+find them towards the top of the file in a subroutine named 
+initialize_globals().
+
+=back
+
+An attempt to send a POST larger than $POST_MAX bytes will cause
+I<param()> to return an empty CGI parameter list.  You can test for
+this event by checking I<cgi_error()>, either after you create the CGI
+object or, if you are using the function-oriented interface, call
+<param()> for the first time.  If the POST was intercepted, then
+cgi_error() will return the message "413 POST too large".
+
+This error message is actually defined by the HTTP protocol, and is
+designed to be returned to the browser as the CGI script's status
+ code.  For example:
+
+   $uploaded_file = param('upload');
+   if (!$uploaded_file && cgi_error()) {
+      print header(-status=>cgi_error());
+      exit 0;
+   }
+
+However it isn't clear that any browser currently knows what to do
+with this status code.  It might be better just to create an
+HTML page that warns the user of the problem.
+
+=head1 COMPATIBILITY WITH CGI-LIB.PL
+
+To make it easier to port existing programs that use cgi-lib.pl the
+compatibility routine "ReadParse" is provided.  Porting is simple:
+
+OLD VERSION
+    require "cgi-lib.pl";
+    &ReadParse;
+    print "The value of the antique is $in{antique}.\n";
+
+NEW VERSION
+    use CGI;
+    CGI::ReadParse
+    print "The value of the antique is $in{antique}.\n";
+
+CGI.pm's ReadParse() routine creates a tied variable named %in,
+which can be accessed to obtain the query variables.  Like
+ReadParse, you can also provide your own variable.  Infrequently
+used features of ReadParse, such as the creation of @in and $in 
+variables, are not supported.
+
+Once you use ReadParse, you can retrieve the query object itself
+this way:
+
+    $q = $in{CGI};
+    print $q->textfield(-name=>'wow',
+			-value=>'does this really work?');
+
+This allows you to start using the more interesting features
+of CGI.pm without rewriting your old scripts from scratch.
+
+=head1 AUTHOR INFORMATION
+
+Copyright 1995-1998, Lincoln D. Stein.  All rights reserved.  
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+Address bug reports and comments to: lstein@cshl.org.  When sending
+bug reports, please provide the version of CGI.pm, the version of
+Perl, the name and version of your Web server, and the name and
+version of the operating system you are using.  If the problem is even
+remotely browser dependent, please provide information about the
+affected browers as well.
+
+=head1 CREDITS
+
+Thanks very much to:
+
+=over 4
+
+=item Matt Heffron (heffron@falstaff.css.beckman.com)
+
+=item James Taylor (james.taylor@srs.gov)
+
+=item Scott Anguish <sanguish@digifix.com>
+
+=item Mike Jewell (mlj3u@virginia.edu)
+
+=item Timothy Shimmin (tes@kbs.citri.edu.au)
+
+=item Joergen Haegg (jh@axis.se)
+
+=item Laurent Delfosse (delfosse@delfosse.com)
+
+=item Richard Resnick (applepi1@aol.com)
+
+=item Craig Bishop (csb@barwonwater.vic.gov.au)
+
+=item Tony Curtis (tc@vcpc.univie.ac.at)
+
+=item Tim Bunce (Tim.Bunce@ig.co.uk)
+
+=item Tom Christiansen (tchrist@convex.com)
+
+=item Andreas Koenig (k@franz.ww.TU-Berlin.DE)
+
+=item Tim MacKenzie (Tim.MacKenzie@fulcrum.com.au)
+
+=item Kevin B. Hendricks (kbhend@dogwood.tyler.wm.edu)
+
+=item Stephen Dahmen (joyfire@inxpress.net)
+
+=item Ed Jordan (ed@fidalgo.net)
+
+=item David Alan Pisoni (david@cnation.com)
+
+=item Doug MacEachern (dougm@opengroup.org)
+
+=item Robin Houston (robin@oneworld.org)
+
+=item ...and many many more...
+
+for suggestions and bug fixes.
+
+=back
+
+=head1 A COMPLETE EXAMPLE OF A SIMPLE FORM-BASED SCRIPT
+
+
+	#!/usr/local/bin/perl
+
+	use CGI;
+
+	$query = new CGI;
+
+	print $query->header;
+	print $query->start_html("Example CGI.pm Form");
+	print "<h1> Example CGI.pm Form</h1>\n";
+	&print_prompt($query);
+	&do_work($query);
+	&print_tail;
+	print $query->end_html;
+
+	sub print_prompt {
+	   my($query) = @_;
+
+	   print $query->start_form;
+	   print "<em>What's your name?</em><br>";
+	   print $query->textfield('name');
+	   print $query->checkbox('Not my real name');
+
+	   print "<p><em>Where can you find English Sparrows?</em><br>";
+	   print $query->checkbox_group(
+				 -name=>'Sparrow locations',
+				 -values=>[England,France,Spain,Asia,Hoboken],
+				 -linebreak=>'yes',
+				 -defaults=>[England,Asia]);
+
+	   print "<p><em>How far can they fly?</em><br>",
+		$query->radio_group(
+			-name=>'how far',
+			-values=>['10 ft','1 mile','10 miles','real far'],
+			-default=>'1 mile');
+
+	   print "<p><em>What's your favorite color?</em>  ";
+	   print $query->popup_menu(-name=>'Color',
+				    -values=>['black','brown','red','yellow'],
+				    -default=>'red');
+
+	   print $query->hidden('Reference','Monty Python and the Holy Grail');
+
+	   print "<p><em>What have you got there?</em><br>";
+	   print $query->scrolling_list(
+			 -name=>'possessions',
+			 -values=>['A Coconut','A Grail','An Icon',
+				   'A Sword','A Ticket'],
+			 -size=>5,
+			 -multiple=>'true');
+
+	   print "<p><em>Any parting comments?</em><br>";
+	   print $query->textarea(-name=>'Comments',
+				  -rows=>10,
+				  -columns=>50);
+
+	   print "<p>",$query->reset;
+	   print $query->submit('Action','Shout');
+	   print $query->submit('Action','Scream');
+	   print $query->endform;
+	   print "<hr>\n";
+	}
+
+	sub do_work {
+	   my($query) = @_;
+	   my(@values,$key);
+
+	   print "<h2>Here are the current settings in this form</h2>";
+
+	   foreach $key ($query->param) {
+	      print "<strong>$key</strong> -> ";
+	      @values = $query->param($key);
+	      print join(", ",@values),"<br>\n";
+	  }
+	}
+
+	sub print_tail {
+	   print <<END;
+	<hr>
+	<address>Lincoln D. Stein</address><br>
+	<a href="/">Home Page</a>
+	END
+	}
+
+=head1 BUGS
+
+This module has grown large and monolithic.  Furthermore it's doing many
+things, such as handling URLs, parsing CGI input, writing HTML, etc., that
+are also done in the LWP modules. It should be discarded in favor of
+the CGI::* modules, but somehow I continue to work on it.
+
+Note that the code is truly contorted in order to avoid spurious
+warnings when programs are run with the B<-w> switch.
+
+=head1 SEE ALSO
+
+L<CGI::Carp>, L<CGI::Fast>, L<CGI::Pretty>
+
+=cut
+
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/download
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/download	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/download	(revision 10506)
@@ -0,0 +1,102 @@
+#!/usr/bin/perl -w
+
+use gsdlCGI;
+
+sub load_gsdl_utils
+{
+    my ($gsdlhome) = @_;
+
+    require "$gsdlhome/perllib/util.pm";
+}
+
+sub main
+{
+    my $gsdl_cgi = new gsdlCGI("+cmdline");
+
+    $gsdl_cgi->setup_gsdl();
+    my $gsdlhome = $ENV{'GSDLHOME'};
+
+    load_gsdl_utils($gsdlhome);
+
+    my $col = $gsdl_cgi->clean_param("c");
+    if (!defined $col) {
+      $gsdl_cgi->generate_error("No collection specified.");
+    }
+
+    my $dir = $gsdl_cgi->clean_param("dir");
+    $dir = "\"\"" if ((!defined $dir) || ($dir eq "."));
+
+    my $accept_expr = $gsdl_cgi->clean_param("a");
+    if(($accept_expr eq "") || (!defined $accept_expr)) {
+	$accept_expr = "";
+    }
+    else {
+	$accept_expr = "-accept " . $accept_expr;
+    }
+
+    my $reject_expr = $gsdl_cgi->clean_param("r");
+    if(($reject_expr eq "") || (!defined $reject_expr)) {
+	$reject_expr = "";
+    }
+    else {
+	$reject_expr = "-reject " . $reject_expr;
+    }
+
+    my $zip_dirname = "";
+
+    if ($col =~ m/^\//) { 
+	# leading / at start denotes special "cols" such as "/tmp"
+
+	$zip_dirname = $gsdlhome;
+	$col =~ s/^\///;
+    }
+    else {
+	$zip_dirname = &util::filename_cat($gsdlhome,"collect");
+    }
+    
+    my $java = $gsdl_cgi->check_for_java();
+
+    my $classpath 
+	= &util::filename_cat($gsdlhome,"bin","java","SignedGatherer.jar");
+    my $java_prog = "org.greenstone.gatherer.util.Zipup";
+    my $java_args = "$zip_dirname $col $dir $accept_expr $reject_expr";
+    my $java_cmd = "$java -classpath $classpath $java_prog $java_args";
+
+    my $java_output = `$java_cmd`;
+
+    my $status = $?;
+
+    if ($status>0) {
+	$status = $status/256;
+	my $exit_status = "Exit status: $status\n";
+	my $mess = "Java failed: $java_cmd\n--\n$java_output\n$exit_status";
+	$gsdl_cgi->generate_error($mess);
+    }
+	
+    my $zip_filename = &util::filename_cat($zip_dirname,"$col.zip");
+
+    if (open(PIN,"<$zip_filename")) {
+ 	binmode(PIN);
+
+ 	my $buf;
+ 	my $num_bytes = 0;
+
+	print STDOUT "Content-type:application/zip\n\n";
+
+ 	while (read(PIN,$buf,1024)>0) {
+ 	    print STDOUT $buf;
+ 	    $num_bytes += length($buf);
+ 	}
+
+ 	close(PIN);
+    }
+    else {
+        my $mess = "Unable to read in $zip_filename\n  $!";
+	$gsdl_cgi->generate_error($mess);
+    }
+    
+    unlink "$zip_filename";
+}
+
+&main();
+
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/getior
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/getior	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/getior	(revision 10506)
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+echo "Content-type: text/html";
+echo
+
+cat /tmp/localcorba.objid               
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/gsdlCGI.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/gsdlCGI.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/gsdlCGI.pm	(revision 10506)
@@ -0,0 +1,291 @@
+
+package gsdlCGI;
+
+use CGI;
+use Cwd;
+
+@ISA = ('CGI');
+
+sub new {
+    my $class = shift @_;
+    my ($mode) = @_;
+
+
+    my $self;
+    if ((defined $mode) && ($mode eq "+cmdline")) {
+	my $line = <STDIN>;
+	if ((defined $line) && ($line ne "")) {
+	    $self = new CGI($line);
+	}
+	else {
+	    $self = new CGI();
+	}
+    }
+    else {
+	$self = new CGI();
+    }
+
+    my $xml = (defined $self->param("xml")) ? 1 : 0;
+
+    $self->{'xml'} = $xml;
+
+    my @var_names = $self->param;
+    my @arg_list = ();
+    foreach my $n ( @var_names ) {
+	my $arg = "$n=";
+	my $val =  $self->param($n);
+	$arg .= $val if (defined $val);
+	push(@arg_list,$arg);
+    }
+	
+    $self->{'args'} = join("&",@arg_list);
+
+    return bless $self, $class;
+}
+
+
+sub clean_param
+{
+    my $self = shift @_;
+    my ($param) = @_;
+
+    my $val = $self->SUPER::param($param);
+    $val =~ s/[\r\n]+$// if (defined $val);
+
+    return $val;
+}
+
+sub safe_val
+{
+    my $self = shift @_;
+    my ($val) = @_;
+
+    # ensure only alpha-numeric plus a few other special chars remain
+
+    $val =~ s/[^[:alnum:]@\.\/\- :_]//g if (defined $val); 
+
+    return $val;
+}
+
+
+sub generate_error
+{
+    my $self = shift @_;
+    my ($mess) = @_;
+    
+    my $xml = $self->{'xml'};
+
+    my $full_mess;
+    my $args = $self->{'args'};
+
+    if ($xml) {
+	$full_mess =  "<Error>\n";
+	$full_mess .= "  $mess\n";
+	$full_mess .= "  CGI args were: $args\n";
+	$full_mess .= "</Error>\n";
+    }
+    else {
+	$full_mess = "ERROR: $mess ($args)\n";
+    }
+
+    print STDOUT "Content-type:text/plain\n\n";
+    print STDOUT $full_mess;
+
+    die $full_mess;
+}
+
+sub generate_warning
+{
+    my $self = shift @_;
+    my ($mess) = @_;
+    
+    my $xml = $self->{'xml'};
+
+    my $full_mess;
+    my $args = $self->{'args'};
+
+    if ($xml) {
+	$full_mess =  "<Warning>\n";
+	$full_mess .= "  $mess\n";
+	$full_mess .= "  CGI args were: $args\n";
+	$full_mess .= "</Warning>\n";
+    }
+    else {
+	$full_mess = "Warning: $mess ($args)\n";
+    }
+
+    print STDOUT "Content-type:text/plain\n\n";
+    print STDOUT $full_mess;
+
+    print STDERR $full_mess;
+}
+
+
+sub generate_ok_message
+{
+    my $self = shift @_;
+    my ($mess) = @_;
+    
+    my $xml = $self->{'xml'};
+
+    my $full_mess;
+
+    if ($xml) {
+	$full_mess =  "<Accepted>\n";
+	$full_mess .= "  $mess\n";
+	$full_mess .= "</Accepted>\n";
+    }
+    else {
+	$full_mess = "$mess\n";
+    }
+
+    print STDOUT "Content-type:text/plain\n\n";
+    print STDOUT $full_mess;
+}
+
+
+
+sub get_config_info {
+    my $self = shift @_;
+    my ($infotype) = @_;
+
+    my $site_filename = "gsdlsite.cfg";
+    open (FILEIN, "<$site_filename") 
+	|| $self->generate_error("Could not open gsdlsite.cfg");
+
+    my $config_content = "";
+    while(defined (my $line = <FILEIN>)) {
+	$config_content .= $line;
+    }
+    close(FILEIN);
+
+        
+    my ($loc) = ($config_content =~ m/^$infotype\s+(\S+)\s*\n/m);
+    $loc =~ s/\"//g;
+
+    if ((!defined $loc) || ($loc =~ m/^\s*$/)) {
+	$self->generate_error("$infotype is not set in gsdlsite.cfg");
+    }
+
+
+    return $loc;
+}
+
+
+sub get_gsdl_home {
+    my $self = shift @_;
+    
+    if (defined $self->{'gsdlhome'}) {
+	return $self->{'gsdlhome'};
+    }
+
+    my $gsdlhome = $self->get_config_info("gsdlhome");
+
+    require "$gsdlhome/perllib/util.pm";
+
+    $gsdlhome =~ s/(\/|\\)$//; # remove trailing slash
+
+    $self->{'gsdlhome'} = $gsdlhome;
+
+    return $gsdlhome;
+}
+
+sub get_gsdl_os {
+    my $self = shift @_;
+    
+    my $os = $^O;
+
+    if ($os =~ m/linux/i) {
+	return "linux";
+    }
+    elsif ($os =~ /mswin/i) {
+	return "windows";
+    }
+    elsif ($os =~ /macos/i) {
+	return "darwin";
+    }
+    else {
+	# return as is.
+	return $os;
+    }
+}
+
+sub setup_gsdl {
+    my $self = shift @_;
+
+    my $gsdlhome = $self->get_gsdl_home();
+    my $gsdlos = $self->get_gsdl_os();
+
+    $ENV{'GSDLHOME'} = $gsdlhome;
+    $ENV{'GSDLOS'} = $gsdlos;
+
+    my $gsdl_bin_script = &util::filename_cat($gsdlhome,"bin","script");
+    &util::envvar_append("PATH",$gsdl_bin_script);
+
+    my $gsdl_bin_os = &util::filename_cat($gsdlhome,"bin",$gsdlos);
+    &util::envvar_append("PATH",$gsdl_bin_os);
+}
+
+
+sub local_rm_r
+{
+    my $self = shift @_;
+    my ($local_dir) = @_;
+
+    my $prefix_dir = getcwd(); 
+
+    if ($prefix_dir !~ m/collect/) {
+	$self->generate_error("Trying to delete outside of Greenstone collect: $full_dir");
+    }
+
+    my $full_dir = &util::filename_cat($prefix_dir,$local_dir);
+
+    # Delete recursively
+    if (!-e $full_dir) {
+	$self->generate_error("File/Directory does not exist: $full_dir");
+    }
+
+    &util::rm_r($full_dir);
+}
+
+
+
+sub check_for_java()
+{
+    my $self = shift @_;
+
+    my $java = "java";
+
+    if (defined $ENV{'JAVA_HOME'}) {
+	my $java_home = $ENV{'JAVA_HOME'};
+	# Unix specific
+	$java_home =~ s/\/$//; # remove trailing slash if present
+
+	$java = &util::filename_cat($java_home,"bin","java");
+    }
+    else {
+	my $path = $ENV{'PATH'};
+	my $mess = "JAVA_HOME environment variable not set.  Might not be able to find java unless in PATH=$path";
+
+	$self->generate_warning($mess);
+    }
+    
+    return $java;
+}
+
+
+sub checked_chdir
+{
+    my $self = shift @_;
+    my ($dir) = @_;
+
+    if (!-e $dir) {
+	$self->generate_error("Directory '$dir' does not exist");
+    }
+
+    chdir $dir
+	|| $self->generate_error("Unable to change to directory: $dir");
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/gsdlsite.cfg
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/gsdlsite.cfg	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/gsdlsite.cfg	(revision 10506)
@@ -0,0 +1,29 @@
+# this file should be placed in the same directory as your library
+# executable file. it defines parameters that are particular to a
+# given site, and therefore should be edited to suit your site.
+
+# points to the GSDLHOME directory
+gsdlhome    **GSDLHOME**
+
+# this is the http address of GSDLHOME
+# if your webservers DocumentRoot is set to $GSDLHOME
+# then httpprefix can remain commented out
+#httpprefix  /gsdl
+
+# this is the http address of the directory which
+# contains the images for the interface.
+# if your webservers DocumentRoot is set to $GSDLHOME
+# then httpimg will be /images
+httpimg     /images
+
+# should contain the http address of this cgi script. This 
+# is not needed if the http server sets the environment variable 
+# SCRIPT_NAME
+#gwcgi       /cgi-bin/library
+
+# maxrequests is the most requests a fastcgi process
+# will serve before it exits. This can be set to a
+# low figure (like 1) while debugging and then set
+# to a high figure (like 10000) when everything is
+# working well.
+maxrequests 10000
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/launch
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/launch	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/launch	(revision 10506)
@@ -0,0 +1,251 @@
+#!/usr/bin/perl -w
+
+use gsdlCGI;
+
+sub load_gsdl_utils
+{
+    my ($gsdlhome) = @_;
+
+    require "$gsdlhome/perllib/util.pm";
+}
+
+sub run_gencmd
+{
+    my ($prog,$col,$gsdl_cgi) = @_;
+
+    my @arg_keys = $gsdl_cgi->param;
+
+    my $os = $gsdl_cgi->get_gsdl_os();
+
+    my $cmd = "perl -S $prog.pl ";
+
+    foreach my $k ( @arg_keys ) {
+	my $arg_val = $gsdl_cgi->clean_param($k);
+	if ($k eq "about") {
+	    # special case (allow most things, but not quotes)
+	    $arg_val =~ s/\"/&quot;/g;
+	}
+	else {
+	    # ensure only alphanumeric, plus a few special chars
+	    $arg_val = $gsdl_cgi->safe_val($arg_val);
+	}
+	$cmd .= " -$k";
+	if ($arg_val ne "") {
+	    $cmd .= " \"$arg_val\"";
+	}
+    }
+
+    $cmd .= " $col" if (defined $col);
+
+    my $status;
+
+    print STDOUT "Content-type:text/plain\n\n";
+
+    my $report = "";
+
+    if (open(PIN,"$cmd 2>&1 |")) {
+	while (defined (my $line=<PIN>)) {
+	    print STDOUT $line;
+	    $report .= $line;
+	}
+	close(PIN);
+
+	$status = $?;
+
+	if ($status>0) {
+	    $status = $status/256;
+	    my $exit_status = "Exit status: $status\n";
+	    my $mess = "'".$cmd."' failed.\n$report\n$exit_status";
+	    $gsdl_cgi->generate_error($mess);
+	}
+    }
+    else {
+	$gsdl_cgi->generate_error("Unable to execute cmd: $cmd");
+	$status = -1;
+    }
+
+    return $status;
+}
+
+
+sub run_xmlinfo
+{
+    my ($cmd,$col,$gsdl_cgi) = @_;
+
+    if (defined $col) {
+	$gsdl_cgi->param(-name=>"collect",-value=>$col);
+	$col = undef;
+    }
+
+    if ($cmd eq "pluginfo") {
+	my $plug =  $gsdl_cgi->clean_param("plug");
+
+	if (defined $plug) {
+	    $gsdl_cgi->delete("plug");
+	    $col = $gsdl_cgi->safe_val($plug);
+	}
+    }
+    elsif ($cmd eq "classinfo") {
+	my $class =  $gsdl_cgi->clean_param("class");
+
+	if (defined $class) {
+	    $gsdl_cgi->delete("class");
+	    $col = $gsdl_cgi->safe_val($class);
+	}
+    }
+
+    return run_gencmd($cmd,$col,$gsdl_cgi);
+}
+
+
+sub run_buildcol
+{
+    my ($gsdlhome,$col,$gsdl_cgi) = @_;
+    
+    my $full_col_dir  = &util::filename_cat($gsdlhome,"collect",$col);
+    my $full_building = &util::filename_cat($full_col_dir,"building");
+    my $full_index    = &util::filename_cat($full_col_dir,"index");
+
+    if (defined $col) {
+	&util::rm_r($full_building);
+	&util::mk_dir($full_building);
+    }
+
+    my $status = run_gencmd("buildcol",$col,$gsdl_cgi);
+
+    if ($status == 0) {
+	if (defined $col) {
+	    &util::rm_r($full_index);
+
+	    # While it is more efficient to move the building directory
+	    # to become the index folder, this gets things out of order
+	    # back on the client.  Use copy for now as this makes things
+	    # simpler for now.
+
+	    my $full_building_here = &util::filename_cat($full_building,".");
+	    &util::cp_r($full_building_here,$full_index);
+	}
+    }
+    # no need to do else clause as error message will have already
+    # been generated.
+}
+
+sub run_exportcol
+{
+    my ($gsdlhome,$col,$gsdl_cgi) = @_;
+    
+    # multiple collections represented by ':' concatenated list
+    $col =~ s/:/ /g;
+
+    if (defined $col) {
+	my ($remote_user) = ($col =~ m/^([^\-]+)/);
+
+	my $cddir = $gsdl_cgi->clean_param("cddir");
+	
+	my $remote_dirname = &util::filename_cat($gsdlhome,"tmp",$remote_user);
+	my $remote_cd_dirname = &util::filename_cat($remote_dirname,$cddir);
+
+	if (!-e $remote_dirname) {
+	    &util::mk_dir($remote_dirname);
+	}
+
+	if (-e $remote_cd_dirname) {
+	    &util::rm_r($remote_cd_dirname);
+	}
+
+	# Update cddir cgi param prefiexed by remote_user
+	$cddir = &util::filename_cat($remote_user,$cddir);
+	$gsdl_cgi->delete("cddir");
+	$gsdl_cgi->param(-name=>"cddir", -value=>$cddir);
+    }
+
+    return run_gencmd("exportcol",$col,$gsdl_cgi);
+}
+
+sub run_exportas
+{
+    my ($col,$gsdl_cgi) = @_;
+    
+    # multiple collections represented by ':' concatenated list
+    $col =~ s/:/ /g;
+
+    return run_gencmd("export",$col,$gsdl_cgi);
+}
+
+
+
+sub run_deldir
+{
+    my ($col,$gsdl_cgi) = @_;
+
+    if ((!defined $col) || ($col =~ m/^\s*$/)) {
+	$gsdl_cgi->generate_error( "No collection name specified");
+    }
+
+    $gsdl_cgi->checked_chdir("collect");
+
+    my $dir = $gsdl_cgi->clean_param("dir");
+    $dir = "" if ($dir eq ".");
+
+    $gsdl_cgi->local_rm_r("$col/$dir");
+    $gsdl_cgi->checked_chdir("..");
+
+    $gsdl_cgi->generate_ok_message("$col deleted successfully");
+}
+
+sub main
+{
+    my $gsdl_cgi = new gsdlCGI("+cmdline");
+
+    $gsdl_cgi->setup_gsdl();
+    my $gsdlhome = $ENV{'GSDLHOME'};
+
+    load_gsdl_utils($gsdlhome);
+    
+    $gsdl_cgi->checked_chdir($gsdlhome);
+
+    my $cmd = $gsdl_cgi->clean_param("cmd");
+    if (!defined $cmd) {
+	$gsdl_cgi->generate_error("No command specified.");
+    }
+
+    $gsdl_cgi->delete("cmd");
+    $cmd =~ s/\..*$//;
+    $cmd = $gsdl_cgi->safe_val($cmd);
+
+    my $col = $gsdl_cgi->clean_param("c");
+
+    $gsdl_cgi->delete("c");
+    $col = $gsdl_cgi->safe_val($col);
+
+    if ($cmd eq "mkcol") {
+	run_gencmd($cmd,$col,$gsdl_cgi);
+    }
+    elsif ($cmd eq "pluginfo") {
+	run_xmlinfo($cmd,$col,$gsdl_cgi);
+    }
+    elsif ($cmd eq "classinfo") {
+	run_xmlinfo($cmd,$col,$gsdl_cgi);
+    }
+    elsif ($cmd eq "import") {
+	run_gencmd($cmd,$col,$gsdl_cgi);
+    }
+    elsif ($cmd eq "buildcol") {
+	run_buildcol($gsdlhome,$col,$gsdl_cgi);
+    }
+    elsif ($cmd eq "exportcol") {
+	run_exportcol($gsdlhome,$col,$gsdl_cgi);
+    }
+    elsif ($cmd eq "exportas") {
+	run_exportas($col,$gsdl_cgi);
+    }
+    elsif ($cmd eq "deldir") {
+	run_deldir($col,$gsdl_cgi);
+    }
+    else {
+	$gsdl_cgi->generate_error("unrecognised command: '$cmd'");
+    }
+}
+
+&main();
+
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/perl.cgi
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/perl.cgi	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/perl.cgi	(revision 10506)
@@ -0,0 +1,96 @@
+#!/usr/bin/perl
+
+use usabcgi;
+
+print "Content-type:text/html\n\n";
+
+
+
+
+$idno=$ENV{REMOTE_ADDR};
+$idno =~ s/\.//g;
+$idno =~ tr/0123456789/1357902468/;
+$idno .= time;
+
+print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"; 
+print "<html>\n<head>\n<title>Greenstone Usability Thank you!</title>\n";
+print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n";
+
+usabcgi::printstyle($ENV{HTTP_USER_AGENT});
+usabcgi::printscript;
+#print "timeleft=21;\n";
+#print "function timerdisplay(){\n";
+#print "\tif(eval(document.getElementById != undefined )){\n";
+#print "\t\tif(parseInt(timeleft)>0){\n";
+#print "\t\t\ttimeleft-=1;\n";
+#print "\t\t\ttimeforscreen = timeleft+\' second\';\n";
+#print "\t\t\tif(timeleft>1)\{ timeforscreen += \'s\';\}\n";
+#print "\t\t\t\tdocument.getElementById(\'timer\').firstChild.nodeValue=timeforscreen;\n";
+#print "\t\t\t\tsetTimeout(\'timerdisplay()\',1000);\n";
+#print "\t\t}\n";
+#print "\t}\n";
+#print "}\n";
+#print "\n";
+
+print "</head><body onLoad=\"if(parseInt(navigator.appVersion)>3)\{window.resizeTo(420,300);\}\" bgcolor=\"#FFFFFF\">\n";
+
+
+usabcgi::printbanner("Thank You");
+
+($fileoutloc) = usabcgi::get_config_info("gsdlhome");
+if(!($fileoutloc =~/\/$/)) {$fileoutloc.="/";}
+$fileoutloc .= "etc/usability.txt";
+
+if(-e $fileoutloc){
+    open FILEOUT, (">>$fileoutloc");
+}
+else {
+    open FILEOUT, (">$fileoutloc");
+}
+
+usabcgi::printaplinks;
+print "<p>Your comments have been noted. <p>Thank you for helping us make Greenstone more usable.</p>\n";
+print "<table width=\"100%\"><tr>\n";
+print "<td class=\"sans\"><a href=\"readresults.cgi?$idno\" target=\"_blank\">View report details</a></td>\n";
+print "<td class=\"sans\"><a href=\"trackreport.cgi?$idno\" target=\"_blank\">Track report</a></td>";
+print "<td align=\"right\"><form action=\"\"><button type=\"button\" onClick=\"window.close();\"><strong>Close Window</strong></button></form></td>\n";
+print"</tr></table>\n";
+
+
+#print "<h2>Your report ID number is: $idno</h2>";
+#print "<p>The information has now been sent, thank-you.  The information sent is displayed below.  This window will close automatically after <span id=\"timer\">20 seconds</span>.";
+read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
+@pairs=split(/&/,$buffer);
+
+foreach $pair (@pairs) {
+    ($name, $value) = split(/=/,$pair);
+    $value=~ tr/+/ /;
+    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
+    $FORM{$name} = $value;
+}
+
+
+
+if (-e $fileoutloc){ 
+    open FILEOUT, (">>$fileoutloc");
+}
+else { open FILEOUT, (">$fileoutloc") or print "cannot open file $fileoutloc\n"; }
+#print FILEOUT "-------------------------------------\n";
+print FILEOUT "report-id := $idno\&usabend;\n";
+foreach $key (keys(%FORM)) {
+    if($key eq "URL") {
+	$url = $FORM{$key};
+	$url =~s/\&/\&amp\;/g;
+    }
+    print FILEOUT "$key := $FORM{$key}\&usabend;\n"; 
+}
+print FILEOUT "browser-read-by-server :=  $ENV{HTTP_USER_AGENT}\&usabend;\n";
+print FILEOUT "browser-ip-no :=  $ENV{REMOTE_ADDR}\&usabend;\n";
+print FILEOUT "server-ip-no :=  $ENV{SERVER_ADDR}\&usabend;\n";
+print FILEOUT "time := ".scalar(localtime(time))."\&usabend;\n";
+print FILEOUT "----------------------------------------------\n";
+close (FILEOUT);
+
+
+print"</body></html>\n"; 
+
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/readresults.cgi
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/readresults.cgi	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/readresults.cgi	(revision 10506)
@@ -0,0 +1,89 @@
+#!/usr/bin/perl
+
+use usabcgi;
+
+print "Content-type:text/html\n\n";
+
+
+print "<html><head><title>Greenstone Usability - Report Details</title>\n";
+usabcgi::printscript;
+usabcgi::printstyle($ENV{HTTP_USER_AGENT});
+
+print "</head><body bgcolor=\"#ffffff\">\n";
+
+usabcgi::printbanner("Report Details");
+usabcgi::printaplinks;
+ 
+usabcgi::checkidno;
+
+%reportvals=usabcgi::getusabreportdetails;
+
+print "<p>Your automatically generated report ID number is: <b>$reportvals{\"report-id\"}</b>";
+$reportid = $reportvals{"report-id"};
+delete $reportvals{"report-id"};
+
+print "<h2>The following technical information was automatically collected about your problem:</h2>\n";
+print "<table width=\"100%\">\n";
+
+make_table_entry("The URL of the page where you were having problems","URL");
+make_table_entry("the collection you were using when you had problems","collection");
+make_table_entry("Time you opened the usability report window","opentime");
+make_table_entry("Time you sent the usability report","sendtime");
+make_table_entry("Time the report was received by the server","time");
+make_table_entry("Your browser as it identifies itself","browser");
+make_table_entry("Your browser as the server identifies it","browser-read-by-server");
+make_table_entry("Your browser's IP number","browser-ip-no");
+make_table_entry("The server's IP number","server-ip-no");
+make_table_entry("Your language as recorded by your browser","language");
+make_table_entry("The resolution of your screen","resolution");
+make_table_entry("The colour of your screen","screencolour");
+make_table_entry("The number of bits per pixel your display uses to represent colour","pixeldepth");
+print "</table>";
+
+print "<h2>You provided us with the following extra information about the problem</h2>\n";
+
+print"<table width=\"100%\">\n";
+make_table_entry("How bad the problem was","severity");
+make_table_entry("What kind of problem it was","probtype");
+make_table_entry("Other details","moredetails");
+print "</table>\n";
+
+print "<h2>The following data was automatically collected from the form on the Greenstone interface</h2>\n";
+
+print"<table width=\"100%\">\n";
+print "<tr><td class=\"sans\"><b>Type of input</b></td><td class=\"sans\"><b>Name of input</b></td><td class=\"sans\"><b>Value of input</b></td></tr>\n";
+
+foreach $key (keys(%reportvals)){
+    if($key ne "update"){
+	$key=~/-/;
+	print "<tr><td width=\"33%\">$`</td><td width=\"33%\">$'</td><td width=\"34%\">$reportvals{$key}</td></tr>\n";
+    }
+}
+print "</table>\n";
+
+print "<br><br><p class=\"sans\"><a href=\"mailto:dmn&#064;cs.waikato.ac.nz\">Contact us</a> with any queries or if you would like this report to be removed from the database.  Please include your report ID number ($reportid) if your query concerns this report specifically.";
+	
+print "</body></html>";
+
+#This function takes a key into the report values interface, and a desription 
+# of what that entry means, and makes a properly formatted html table entry
+sub make_table_entry {
+    local ($desc, $entry) = @_;
+    print "<tr><td class=\"sans\" width=\"50%\"><strong>$desc:</strong></td>";
+    print "<td width=\"50%\">$reportvals{$entry}</td></tr>\n";
+    delete $reportvals{$entry};
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/trackreport.cgi
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/trackreport.cgi	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/trackreport.cgi	(revision 10506)
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+
+use usabcgi;
+
+print "Content-type:text/html\n\n";
+
+
+print "<html><head><title>Greenstone Usability - Track Report</title>\n";
+usabcgi::printscript;
+usabcgi::printstyle($ENV{HTTP_USER_AGENT});
+
+print "</head><body bgcolor=\"#ffffff\">\n";
+
+usabcgi::printbanner("Track Report");
+usabcgi::printaplinks;
+
+usabcgi::checkidno;
+
+%reportvals=usabcgi::getusabreportdetails;
+
+print "<h2>Your automatically generated report ID number is: $reportvals{\"report-id\"}</h2>\n";
+
+print "<p>Thank you very much for helping us improve the usability of the Greenstone software\n<p>We received your report at $reportvals{\"time\"}, any updates are shown below.\n<p>To track this report continue to use the URL <a href=\"http://$ENV{HTTP_HOST}$ENV{SCRIPT_NAME}?$ENV{QUERY_STRING}\">http://$ENV{HTTP_HOST}$ENV{SCRIPT_NAME}?$ENV{QUERY_STRING}</a>.\n";
+
+print "<h2>Updates on this report</h2>\n";
+if(!(defined($reportvals{"update"}))){ print "<p>None at this time.</p>\n"; }
+else { print $reportvals{"update"}; }
+
+print "<br><br><p class=\"sans\"><a href=\"mailto:dmn&#064;cs.waikato.ac.nz\">Contact us</a> with any queries or if you would like this report to be removed from the database.  Please include your report ID number ($ENV{QUERY_STRING}) if your query concerns this report specifically.\n";
+
+
+	
+print "</body></html>";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/upload
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/upload	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/upload	(revision 10506)
@@ -0,0 +1,119 @@
+#!/usr/bin/perl -w
+
+use gsdlCGI;
+
+sub load_gsdl_utils
+{
+    my ($gsdlhome) = @_;
+
+    require "$gsdlhome/perllib/util.pm";
+}
+
+sub main
+{
+    my $gsdl_cgi = new gsdlCGI();
+
+    $gsdl_cgi->setup_gsdl();
+    my $gsdlhome = $ENV{'GSDLHOME'};
+
+    load_gsdl_utils($gsdlhome);
+
+    my $col = $gsdl_cgi->clean_param("c");
+    if ((!defined $col) || ($col =~ m/^\s*$/)) {
+	$gsdl_cgi->generate_error("No collection name specified");
+    }
+
+    my $full_col = &util::filename_cat($gsdlhome,"collect",$col);
+
+    #If the collection dir on the server somehow got erased, create it.
+    if(!-e $full_col) {
+	&util::mk_dir($full_col);
+    }
+
+    my $dir = $gsdl_cgi->clean_param("dir");
+    if ((!defined $dir) || ($dir =~ m/^\s*$/)) {
+	$gsdl_cgi->generate_error("No directory name specified");
+    }
+
+    my $delete = $gsdl_cgi->clean_param("del");
+    $delete = "all" if((!defined $delete) || ($delete eq ""));
+
+    $dir = "" if (($dir eq ".") || ($dir =~ m/^\.\./));
+
+    if ($col =~ m/^\//) {
+	# leading / at start denotes special "cols" such as "/tmp"
+	$gsdl_cgi->checked_chdir("$gsdlhome");
+	$col =~ s/^\///;
+    }
+    else {
+	$gsdl_cgi->checked_chdir("$gsdlhome/collect");
+    }
+
+    my $col_dir = &util::filename_cat($col,$dir);
+    my $full_col_dir = &util::filename_cat($full_col,$dir);
+
+    if($delete eq "all") {
+	$gsdl_cgi->local_rm_r($col_dir);
+    }
+    elsif($delete eq "files") {
+	my $full_col_dir = &util::filename_cat($gsdlhome,"collect",$col_dir);
+	# delete everything except metadata.xml files
+	&util::filtered_rm_r($full_col_dir,undef,"metadata.xml\$");
+    }
+    elsif($delete eq "metadata") {
+	my $full_col_dir = &util::filename_cat($gsdlhome,"collect",$col_dir);
+	# delete only metadata xml files
+	&util::filtered_rm_r($full_col_dir,"metadata.xml\$",undef);
+    }
+
+    if(!-e $full_col_dir) {
+	&util::mk_dir($full_col_dir);
+    }
+
+    my $zip_file_name = $col . ".zip";
+    my $zip_file_path = &util::filename_cat($full_col_dir, $zip_file_name);
+    if (open(ZOUT, ">$zip_file_path")) {
+	binmode(ZOUT);
+
+	my $ZIN = $gsdl_cgi->upload('zip');
+	binmode($ZIN);
+
+	my $buf;
+	my $num_bytes = 0;
+
+	while (read($ZIN,$buf,1024)>0) {
+	    print ZOUT $buf;
+	    $num_bytes += length($buf);
+	}
+
+	close($ZIN);
+	close(ZOUT);
+
+	my $java = $gsdl_cgi->check_for_java();
+
+	my $classpath = &util::filename_cat($gsdlhome,"bin","java",
+					    "SignedGatherer.jar");
+
+	my $java_cmd = "$java -classpath \"$classpath\" org.greenstone.gatherer.util.Unzip \"$zip_file_path\" \"$full_col_dir\"";
+	$gsdl_cgi->generate_ok_message("Command: $java_cmd\n");
+
+	my $java_output = `$java_cmd`;
+	
+	my $status = $?;
+	unlink "$zip_file_path";
+
+	if ($status > 0) {
+	    $status = $status/256;
+	    my $exit_status = "Exit status: $status\n";
+	    my $mess = "Java failed: $java_cmd\n--\n$java_output\n$exit_status";
+	    $gsdl_cgi->generate_error($mess);
+	}
+	
+	$gsdl_cgi->generate_ok_message("$dir or $col uploaded successfully.");
+    }
+    else {
+	$gsdl_cgi->generate_error("unable to open $zip_file_path");
+    }
+}
+
+&main();
Index: /tags/gsdl-2_61-distribution/gsdl/cgi-bin/usabcgi.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/cgi-bin/usabcgi.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/cgi-bin/usabcgi.pm	(revision 10506)
@@ -0,0 +1,144 @@
+package usabcgi;
+
+
+sub get_config_info {
+    open FILEIN, ("gsdlsite.cfg") 
+	|| die "ERROR: Could not open site configuration file\n";
+
+    my $configfile;
+    while(<FILEIN>) {
+	$configfile .= $_;
+    }
+    close(FILEIN);
+
+    
+    ($infotype) = @_;
+    
+    $configfile =~ /^$infotype\s+(\S+)\s*\n/m;
+    $loc=$1;
+    $loc =~ s/\"//g;
+
+    return ($loc);
+}
+
+sub printscript {
+    
+    print "<script type=\"text/javascript\">\n";
+    print "\tfunction showaboutprivacy(url){\n";
+    print "\t\tinfowin=window.open(url,'infowin','toolbars=0, height=600, width=600')\n";
+    print "\t}\n";
+    print "</script>\n";
+}
+
+sub printbanner {
+    ($title)=@_;
+    ($imageloc) = usabcgi::get_config_info("httpimg");
+    if(!($imageloc =~ "http")) {$imageloc="http://".$ENV{HTTP_HOST}.$imageloc;}
+    print "<table width=\"100%\"><tr>\n<td><h1>Greenstone Usability - $title</h1></td>\n";
+    print "<td align=\"right\">";
+    if ($imageloc) { print "<img src=\"$imageloc\/usabbanner.gif\" alt=\"Greenstone koru design\" title=\"Greenstone koru design\">"; }
+    print "</td>\n</tr></table>";
+}
+
+sub printaplinks {
+    print "<p class=\"sans\">\n";
+    print "<a href=\"javascript:showaboutprivacy('http://nzdl2.cs.waikato.ac.nz/dana/gsdl/about.html')\">About</a>\n &#8226; <a href=\"javascript:showaboutprivacy('http://nzdl2.cs.waikato.ac.nz/dana/gsdl/privacy.html')\">Privacy</a>\n";
+
+}
+
+sub printstyle {
+    ($browser) = @_;
+    $browser=~/([^\/]*)\/([0-9]+\.[0-9]+)/;
+    if(($1 ne "Netscape")||($2 > 4.77)){
+	print "<style type=\"text/css\">\n";
+	print "\th1 {font-family: sans-serif; font-size: 20px}\n";
+	print "\th2 {font-family: sans-serif; font-size: 14px; font-weight: bold; color: #009966}\n";
+	print "\tp.sans {font-family: sans-serif}\n";
+	print "\ttd {vertical-align: top}\n";
+	print "\ttd.sans {font-family: sans-serif; width: 50%}\n";
+	print "</style>\n";
+    }
+
+}
+
+sub checkidno {
+    if((!($ENV{QUERY_STRING}=~/\d/)) || ($ENV{QUERY_STRING}=~/\D/) ) {
+	print "<h2>Each report sent has an ID number.  This page needs one of those numbers to work.</h2>\n";
+	print "<br><br><p class=\"sans\"><a href=\"mailto:dmn&#064;cs.waikato.ac.nz\">Contact us</a> with any queries about this.\n";
+	print "</body></html>\n";
+	die;
+    }
+}
+
+sub getusabreportdetails {
+    ($etcfileloc) = usabcgi::get_config_info("gsdlhome");
+    if(!($etcfileloc =~/\/$/)) {$etcfileloc.="/";}
+    $etcfileloc .= "etc/usability.txt";
+    open (FILEIN, $etcfileloc) or die "could not open usability.txt\n";
+    while(<FILEIN>){
+	$etcfile.=$_;
+    }   
+    close(FILEIN);
+
+    if(!($etcfile=~ / $ENV{QUERY_STRING}\&usabend;/)) {
+	print "<h2>Each report has an ID number.  This program needs one of those ID numbers to work, and the ID number provided wasn't found.</h2>\n";
+	print "<br><br><p class=\"sans\"><a href=\"mailto:dmn&#064;cs.waikato.ac.nz\">Contact us</a> with any queries about this.\n";
+	print "</body></html>";  
+        die;
+    }
+
+#get the report for whjich details are to be viewed.
+    $etcfile=~/report-id := $ENV{QUERY_STRING}\&usabend\;\n/;
+    $report = $&;
+    $tmp=$';
+    $tmp=~/----------------------?/;
+    $report.=$`;
+    @pairs=split(/\&usabend\;\n/,$report);
+    foreach $pair (@pairs) {
+	($name, $value)= split(/ := /,$pair);
+	
+	#this splits long values up for display purposes
+	@tmplist = split(/ /,$value);
+	foreach $item (@tmplist){
+	    if(length $item > 60){
+		$tmp="";
+		while(length $item > 60){
+		    $tmp.= substr $item, 0, 60;
+		    $tmp.=" ";
+		    $item = substr $item, 60;
+		}
+		$tmp.=$item;
+		$item=$tmp;
+	    }
+	}
+	$value = join(' ',@tmplist);
+	
+	#this adds html tags for breaks
+	$value =~ s/\n/\<br\>\n/g;
+	$reportvals{$name}=$value;
+    }
+    return %reportvals;
+
+}    
+
+1;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/demo.col
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/demo.col	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/demo.col	(revision 10506)
@@ -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">false</Argument>
+    <GathererConfig/>
+    <BuildConfig>
+        <Build/>
+        <Import/>
+    </BuildConfig>
+</GathererCollection>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b17mie/b17mie.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b17mie/b17mie.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b17mie/b17mie.htm	(revision 10506)
@@ -0,0 +1,7650 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Microlivestock -  Little-Known Small Animals with a Promising Economic Future</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Microlivestock -  Little-Known Small Animals with a Promising Economic Future</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Acknowledgments</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Board on Science and Tecnology for International Development </P>
+<P ALIGN="JUSTIFY">National Research Council</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOTICE: The project that is the subject of this report was approved by the Governing Board of the National Research Council, whose members are drawn from the councils of the National Academy of Sciences, the National Academy of Engineering, and the Institute of Medicine. The members of the committee responsible for the report were chosen for their special competence and with regard for appropriate balance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been reviewed by a group other than the authors according to procedures approved by a Report Review Committee consisting of members of the National Academy of Sciences, the National Academy of Engineering, and the Institute of Medicine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The National Academy of Sciences is a private, nonprofit, self-perpetuating society of distinguished scholars engaged in scientific and engineering research, dedicated to the furtherance of science and technology and to their use for the general welfare. Upon the authority of the charter granted to it by the Congress in 1863, the Academy has a mandate that requires it to advise the federal government on scientific and technical matters. Dr. Frank Press is president of the National Academy of Sciences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The National Academy of Engineering was established in 1964, under the charter of the National Academy of Sciences, as a parallel organization of outstanding engineers. It is autonomous in its administration and in the selection of its members, sharing with the National Academy of Sciences the responsibility for advising the federal government. The National Academy of Engineering also sponsors engineering programs aimed at meeting national needs, encourages education and research, and recognizes the superior achievements of engineers. Dr. Robert M. White is president of the National Academy of Engineering.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Institute of Medicine was established in 1970 by the National Academy of Sciences to secure the services of eminent members of appropriate professions in the examination of policy matters pertaining to the health of the public. The Institute acts under the responsibility given to the National Academy of Sciences by its congressional charter to be an adviser to the federal government and, upon its own initiative, to identify issues of medical care, research, and education. Dr. Samuel O. Their is president of the Institute of Medicine.</P>
+<P ALIGN="JUSTIFY">The National Research Council was organized by the National Academy of Sciences in 1916 to associate the broad community of science and technology with the Academy's purposes of furthering knowledge and advising the federal government. Functioning in accordance with general policies determined by the Academy, the Council has become the principal operating agency of both the National Academy of Sciences and the National Academy of Engineering in providing services to the government, the public, and the scientific and engineering communities. The Council is administered jointly by both Academies and the Institute of Medicine. Dr. Frank Press and Dr. Robert M. White are chairman and vice chairman, respectively, of the National Research Council.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Board on Science and Technology for International Development (BOSTID) of the Office of International Affairs addresses a range of issues arising from the ways in which science and technology in developing countries can stimulate and complement the complex processes of social and economic development. It oversees a broad program of bilateral workshops with scientific organizations in developing countries and conducts special studies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report was prepared by an ad hoc advisory panel of the Advisory Committee on Technology Innovation, Board on Science and Technology for International Development, Office of International Affairs, National Research Council. Staff support was funded by the Office of the Science Advisor, Agency for International Development, under Grant No. DAN-5538-G-SS-1023-00. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PANEL ON MICROLIVESTOCK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH W. PHILLIPS, Deputy Director General (Retired), Food and Agriculture Organization of the United Nations, Chairman </P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Senior Advisor to the President, African Development Bank, Abidjan, Ivory Coast.</P>
+<P ALIGN="JUSTIFY">BONNIE V. BEAVER, Professor of Veterinary Medicine, Department of Small Animal Medicine and Surgery, Texas A&amp;M University, College Station, Texas, USA</P>
+<P ALIGN="JUSTIFY">KURT BENIRSCHKE, Professor of Pathology and Reproductive Medicine, University of California-San Diego, San Diego, California, USA</P>
+<P ALIGN="JUSTIFY">ROY D. CRAWFORD, Professor of Animal and Poultry Genetics, Department of Animal and Poultry Science, University of Saskatchewan, Saskatoon, Saskatchewan, Canada</P>
+<P ALIGN="JUSTIFY">TONY J. CUNHA, Distinguished Service Professor Emeritus, University of Florida, Gainesville, and Dean Emeritus, School of Agriculture, California Polytechnic University, Pomona, California, USA</P>
+<P ALIGN="JUSTIFY">DAVID E. DEPPNER, Director, New Forest Project, International Center, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY">ELIZABETH L. HENSON, Executive Director, American Minor Breeds Conservancy, Pittsboro, North Carolina, USA</P>
+<P ALIGN="JUSTIFY">DONALD L. HUSS, Menard, Texas, USA (Formerly Regional Animal Production Officer, FAO, Santiago, Chile)</P>
+<P ALIGN="JUSTIFY">DAVID R. LINCICOME, Guest Scientist, U.S. Department of Agriculture, Beltsville, Maryland, USA</P>
+<P ALIGN="JUSTIFY">THOMAS E. LOVEJOY, Assistant Secretary for External Affairs, Smithsonian Institution, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY">ARNE W. NORDSKOG, Professor Emeritus, Department of Animal Science, Iowa State University, Ames, Iowa, USA</P>
+<P ALIGN="JUSTIFY">LINDA M. PANEPINTO, Director, Miniature Swine Laboratory, Colorado State University, Fort Collins, Colorado, USA</P>
+<P ALIGN="JUSTIFY">KURT J. PETERS, Professor of Animal Breeding and Husbandry in the Tropics and Subtropics, University of Gottingen, Gottingen, West Germany, and Director of Research, International Livestock Centre for Africa, Addis Ababa, Ethiopia</P>
+<P ALIGN="JUSTIFY">JOHN A. PINO, Senior Fellow, National Research Council, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Program in Agriculture, University of Florida, Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY">MICHAEL H. ROBINSON, Director, National Zoological Park, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY">KNUT SCHMIDT-NIELSON, James B. Duke Professor of Physiology, Department of Zoology, Duke University, Durham, North Carolina, USA </P>
+<P ALIGN="JUSTIFY">ALBERT E. SOLLOD, Associate Professor and Head, Section of International Veterinary Medicine, Tufts University, North Grafton, Massachusetts, USA </P>
+<P ALIGN="JUSTIFY">LEE M. TALBOT, Visiting Fellow, World Resources Institute, Washington, D.C., USA </P>
+<P ALIGN="JUSTIFY">CLAIR E. TERRILL, Sheep and Goat Scientist, U.S. Department of Agriculture, Beltsville, Maryland, USA </P>
+<P ALIGN="JUSTIFY">CHRISTEN M. WEMMER, Assistant Director for Conservation, National Zoological Park, Front Royal, Virginia, USA </P>
+<P ALIGN="JUSTIFY">DANNY C. WHARTON, Associate Curator Animal Departments, New York Zoological Park, Bronx Zoo, The Bronx, New York, USA </P>
+<P ALIGN="JUSTIFY">CHARLES A. WOODS, Professor and Curator, Florida State Museum, University of Florida, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY">THOMAS M. YUILL, Associate Dean for Research and Graduate Training, School of Veterinary Medicine, University of Wisconsin-Madison, Madison, Wisconsin, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">* * *</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, Board on Science and Technology for International Development (BOSTID), National Research Council, Washington, D.C., Microlivestock Study Director and Scientific Editor </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATIONAL RESEARCH COUNCIL STAFF</P>
+<P ALIGN="JUSTIFY">F.R. RUSKIN, BOSTID Editor</P>
+<P ALIGN="JUSTIFY">MARK DAFFORN, Technical Writer</P>
+<P ALIGN="JUSTIFY">MARY JANE ENGQUIST, Staff Associate</P>
+<P ALIGN="JUSTIFY">ELIZABETH MOUZON, Senior Secretary</P>
+<P ALIGN="JUSTIFY">JOHN VREYENS, MUCIA Intern</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CONTRIBUTORS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following individuals have made general contributions to the development of this book. All of the persons listed as research contacts in Appendix B also contributed - usually on one or two species that are their scientific specialty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ASHIQ AHMAD, Wildlife Management Specialist, Pakistan Forest Institute, Peshawar, Pakistan</P>
+<P ALIGN="JUSTIFY">ANGEL C. ALCALA, Division Research, Extension and Development, Silliman University, Dumaguete City, Philippines</P>
+<P ALIGN="JUSTIFY">HARTI AMMANN, Basel, Switzerland</P>
+<P ALIGN="JUSTIFY">PATRICK ANDAU, Forest Department, Sandakan, Sabah, Malaysia</P>
+<P ALIGN="JUSTIFY">S.P. ARORA, National Dairy Research Institute, Karnal, India</P>
+<P ALIGN="JUSTIFY">S. AYYAPPAN, CIFRI, Kausabyaganga, Bhubaneswar Orissa, India</P>
+<P ALIGN="JUSTIFY">WALTER BAKHUIS, Caribbean Marine Biological Institute, Willemstad, Curacao, Netherlands Antilles</P>
+<P ALIGN="JUSTIFY">JAMES R. BARBORAK, CATIE, Turrialba, Costa Rica</P>
+<P ALIGN="JUSTIFY">PUSHKAR NATH BHAT, Indian Veterinary Research Institute, Izatnagar, Uttar Pradesh, India</P>
+<P ALIGN="JUSTIFY">STEVE BENNETT, Curepe, Trinidad, West Indies</P>
+<P ALIGN="JUSTIFY">K.P. BLAND, Department of Physiology, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh, Scotland</P>
+<P ALIGN="JUSTIFY">MELVIN BOLTON, Yeppoon, Queensland, Australia</P>
+<P ALIGN="JUSTIFY">JOSEPH BONNEMAIRE, Ecole Nationale Superieure des Sciences Agronomiques Appliquees, Dijon, France</P>
+<P ALIGN="JUSTIFY">R.D.S. BRANCKRAERT, Faculte des Sciences Agronomiques, Universite du Burundi, Bujumbura, Burundi</P>
+<P ALIGN="JUSTIFY">PETER BRAZAITIS, Herpetology, New York Zoological Society, The Bronx, New York, USA</P>
+<P ALIGN="JUSTIFY">L. DE LA BRETONNE, JR., Louisiana Cooperative Extension Service, Louisiana State University, Baton Rouge, Louisiana, USA</P>
+<P ALIGN="JUSTIFY">P. BRINCK, Department of Animal Ecology, University of Lund, Lund, Sweden</P>
+<P ALIGN="JUSTIFY">LESLIE BROWNRIGG, CIAT, Cali, Colombia</P>
+<P ALIGN="JUSTIFY">D. HOMER BUCK, Illinois Natural History Survey, Kinmundy, Illinois, USA</P>
+<P ALIGN="JUSTIFY">GERARDO BUDOWSKI, Natural Renewable Resources Programme, CATIE, Turrialba, Costa Rica</P>
+<P ALIGN="JUSTIFY">DAVID BUTCHER, Taronga Zoo, Mosman, New South Wales, Australia</P>
+<P ALIGN="JUSTIFY">JULIAN O. CALDECOTT, World Wildlife Fund Malaysia, Kuching, Sarawak, Malaysia</P>
+<P ALIGN="JUSTIFY">GARY CALLIS, Texline, Texas, USA</P>
+<P ALIGN="JUSTIFY">J.K. CAMOENS, Asian Development Bank, Manila, Philippines</P>
+<P ALIGN="JUSTIFY">A. CHRISTOPHER CARMICHAEL, The Museum, Michigan State University, East Lansing, Michigan, USA</P>
+<P ALIGN="JUSTIFY">ROBERT H. CHABRECK, School of Forestry and Wildlife Management, Louisiana State University, Baton Rouge, Louisiana, USA</P>
+<P ALIGN="JUSTIFY">A.M. CHAGULA, Research, Ministry of Agriculture, Dar-es-Salaam, Tanzania</P>
+<P ALIGN="JUSTIFY">CHARAN CHANTALAKHANA, Department of Animal Science, Kasetsart  University, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY">PETER R. CHEEKE, Rabbit Research Center, Oregon State University, Corvallis,  Oregon, USA</P>
+<P ALIGN="JUSTIFY">G.S. CHILD, Forest Resources Division, FAO, Rome, Italy</P>
+<P ALIGN="JUSTIFY">A.S. CHOPRA, Ministry of Agriculture, Department of Agriculture and Cooperation,  New Delhi, India</P>
+<P ALIGN="JUSTIFY">W. Ross COCKRILL 29 Downs Park West, Bristol, England, BS6 7QH</P>
+<P ALIGN="JUSTIFY">CRISOSTOMO CORTES, Dairy Promotion and Extension Section, Dairy Development  Division, Manila, Philippines</P>
+<P ALIGN="JUSTIFY">WYLAND CRIPE, College of Veterinary Medicine, University of Florida, Gainesville,  Florida, USA</P>
+<P ALIGN="JUSTIFY">A. BEN DAVID, Holon, Israel</P>
+<P ALIGN="JUSTIFY">C. DEVENDRA, International Development Research Centre, Singapore</P>
+<P ALIGN="JUSTIFY">RODNEY DILLINGER, International Agency for Apiculture Development, Rockford,  Illinois, USA</P>
+<P ALIGN="JUSTIFY">DIRECTOR, Natal Parks Board, Pietermaritzburg, South Africa</P>
+<P ALIGN="JUSTIFY">ROLLANDE DUMONT, Ecole Nationale Superieure des Sciences Agronomiques  Appliquees, Dijon, France</P>
+<P ALIGN="JUSTIFY">N.G. EHIOBU, Department of Agricultural Sciences, College of Education, Agbor,  Nigeria</P>
+<P ALIGN="JUSTIFY">DONALD FARNER, Department of Zoology, University of Washington, Seattle,  Washington, USA</P>
+<P ALIGN="JUSTIFY">JOHN A. FERGUSON, Overseas Development Administration, Eland House, London,  England</P>
+<P ALIGN="JUSTIFY">ABELARDO FERRER D., Quinta Nueva Exparta, San Bernardino, Caracas,  Venezuela</P>
+<P ALIGN="JUSTIFY">LYNWOOD A. FIEDLER, Section of International Programs, U.S. Fish and Wildlife  Service, Denver Wildlife Research Center, Denver, Colorado, USA</P>
+<P ALIGN="JUSTIFY">H. FISCHER, Tropical Science Centre, Division of Tropical Veterinary Medicine,  Justus-Liebig University, Giessen, West Germany</P>
+<P ALIGN="JUSTIFY">J. FURTADO, Commonwealth Science Council, London, England</P>
+<P ALIGN="JUSTIFY">FRANK GOLLEY, Institute of Ecology, University of Georgia, Athens, Georgia, USA</P>
+<P ALIGN="JUSTIFY">E. GONZALES J., Instituto de Produccion Animal, Universidad Central de Venezuela,  El Limon-Maracay, Venezuela</P>
+<P ALIGN="JUSTIFY">GRAHAM GOUDIE, Mainland Holdings, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">ALISTAIR GRAHAM, Tanglewood, Crowborough, East Sussex, England</P>
+<P ALIGN="JUSTIFY">GORDON GRIGG, Zoology, University of Sydney, Sydney, New South Wales, Australia</P>
+<P ALIGN="JUSTIFY">M.R. DE GUMAN, JR., Food and Fertilizer Technology Center, Taipei, Taiwan</P>
+<P ALIGN="JUSTIFY">COLIN P. GROVES, Department of Prehistory and Anthropology, The Australian  National University, Canberra, ACT, Australia </P>
+<P ALIGN="JUSTIFY">J. HARDOUIN, Institut de Medicine Tropicale "Prince Leopold," Antwerp, Belgium</P>
+<P ALIGN="JUSTIFY">GEOFFREY HAWTIN, International Development Research Centre, University of  British Columbia, Vancouver, B.C., Canada</P>
+<P ALIGN="JUSTIFY">GORDON HAVORD, Technical Advisory Division, UNDP, New York, New York, USA</P>
+<P ALIGN="JUSTIFY">TIN HLA, Veterinary Department, Director General's Office, Rangoon, Burma</P>
+<P ALIGN="JUSTIFY">JAMES HENTGES, Department of Animal Science, University of Florida, Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY">W.F. HOLLANDER, Department of Genetics, Iowa State University, Ames, Iowa, USA</P>
+<P ALIGN="JUSTIFY">RENE E. HONEGGER, Herpetology, Zurich Zoo, Zurich, Switzerland</P>
+<P ALIGN="JUSTIFY">JACK HOWARTH, School of Veterinary Medicine, University of California, Davis, California, USA</P>
+<P ALIGN="JUSTIFY">HUANG CHU-CHIEN, Institute of Zoology, Academia Sinica, Beijing, China</P>
+<P ALIGN="JUSTIFY">ANGUS HUTTON, Gympie, Queensland, Australia</P>
+<P ALIGN="JUSTIFY">H.A. JASIOROWSKI, Animal Production and Health Division, FAO, Rome, Italy</P>
+<P ALIGN="JUSTIFY">MUHAMMAD YAQUB JAVAID, Directorate of Fisheries, Government of the Punjab, Punjab, India</P>
+<P ALIGN="JUSTIFY">J. MANGALARAJ JOHNSON, Nudumalai Sanctuary, Vannarpet, Udagamandalani, India</P>
+<P ALIGN="JUSTIFY">MATI KAAL, Tallinn Zoo, ESSR Tallinn, USSR</P>
+<P ALIGN="JUSTIFY">STELLAN KARLSSON, Simontorp Aquaculture AB, Blentarp, Sweden</P>
+<P ALIGN="JUSTIFY">JACKSON A. KATEGILE, International Development Research Centre, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">ROBERT E. KENWARD, Institute of Terrestrial Ecology, Furzebrook Research Station, Wareham, Dorset, England</P>
+<P ALIGN="JUSTIFY">JAMES M. KEARNEY, Miami, Florida, USA</P>
+<P ALIGN="JUSTIFY">F. WAYNE KING, Florida State Museum, Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY">H.-G. KLOS Zoologischer Garten Berlin, Berlin, West Germany</P>
+<P ALIGN="JUSTIFY">NELS M. KONNERUP, Boom International, Stanwood, Washington, USA</P>
+<P ALIGN="JUSTIFY">NAVU KWAPENA, Office of Environment and Conservation, Boroko, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">THOMAS E. LACHER, Huxley College of Environmental Studies, Western Washington University, Bellingham, Washington, USA</P>
+<P ALIGN="JUSTIFY">JOHN K. LOOSLI, Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY">PETER LUTZ, Rosenstiel School of Marine and Atmospheric Science, University of Miami, Miami, Florida, USA</P>
+<P ALIGN="JUSTIFY">CRAIG MACFARLAND, CATIE, Turrialba, Costa Rica</P>
+<P ALIGN="JUSTIFY">CONSTANCE M. MCCORKLE, Department of Rural Sociology, University of Missouri, Columbia, Missouri, USA</P>
+<P ALIGN="JUSTIFY">ROBERT E. MCDOWELL, Department of Animal Science, Cornell University, Ithaca, New York, USA</P>
+<P ALIGN="JUSTIFY">JEFFREY A. MCNEELY, International Union for Conservation of Nature and Natural Resources, Gland, Switzerland</P>
+<P ALIGN="JUSTIFY">ADRIAN G. MARSHALL, Institute of South-East Asian Biology, University of Aberdeen, Aberdeen, Scotland</P>
+<P ALIGN="JUSTIFY">RICHARD R. MARSHALL, Veterinary Medicine, Sutter Hospitals Medical Research Foundation, Sacramento, California, USA</P>
+<P ALIGN="JUSTIFY">G.H.G. MARTIN, Department of Zoology, Kenyatta University College, Nairobi, Kenya </P>
+<P ALIGN="JUSTIFY">IAN L. MASON, Edinburgh, Scotland</P>
+<P ALIGN="JUSTIFY">JOHN C. MASON, Pacific Biological Station, Nanaimo, B.C., Canada</P>
+<P ALIGN="JUSTIFY">J. MAYO MARTIN, Fish Farming Experimental Station, Stuttgart, Arkansas, USA</P>
+<P ALIGN="JUSTIFY">YOLANDA MATAMOROS, Escuela de Medicina Veterinaria, Universidad Nacional, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY">ROBIN MCKERGON, Livestock Development Corporation, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">M. MGHENI, Faculty of Agriculture, Sokoine University of Agriculture, Morogoro, Tanzania</P>
+<P ALIGN="JUSTIFY">P. MONGIN, Station de Recherches Avicoles, INRA-Centre de Tours, Nouzilly, Monnaie, France</P>
+<P ALIGN="JUSTIFY">JOSE ROBERTO DE ALENCAR MOREIRA, Agricultural Research Center of the Humid Tropics, Belem, Para, Brazil</P>
+<P ALIGN="JUSTIFY">W.L.R. OLIVER, Jersey Wildlife Preservation Trust, Jersey, Channel Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY">WERNER PAUWELS, Basel, Switzerland</P>
+<P ALIGN="JUSTIFY">W.J.A. PAYNE, Worcester, England</P>
+<P ALIGN="JUSTIFY">IAN PLAYER, Wilderness Leadership School, Bellair, Natal, South Africa</P>
+<P ALIGN="JUSTIFY">JAMES H. POWELL, JR., Plainview, Texas, USA</P>
+<P ALIGN="JUSTIFY">WILLIAM R. PRITCHARD, School of Veterinary Medicine, University of California, Davis, California, USA</P>
+<P ALIGN="JUSTIFY">HECTOR HUGO LI PUN, International Development Research Centre, Bogota, Colombia</P>
+<P ALIGN="JUSTIFY">VICENTE T. QUIRANTE, Small Ruminant Collaborative Research Project, Bureau of Animal Industry, Manila, Philippines</P>
+<P ALIGN="JUSTIFY">DAN RATTNER, The Institute of Animal Research, Kibbutz Lahav, D.N. Negev, Israel</P>
+<P ALIGN="JUSTIFY">C.V. REDDY, Faculty of Veterinary Science, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad, India</P>
+<P ALIGN="JUSTIFY">RHOEHEIT, Institute of Applied Science and Technology, University Campus, Turkeyen, Guyana</P>
+<P ALIGN="JUSTIFY">CHARLES T. ROBBINS, Department of Zoology, Washington State University, Pullman, Washington, USA</P>
+<P ALIGN="JUSTIFY">CARMEN MA. ROJAS G., CATIE, Turrialba, Costa Rica</P>
+<P ALIGN="JUSTIFY">D.H.L. ROLLINSON, Sardinia, Italy</P>
+<P ALIGN="JUSTIFY">JULIO E. SANCHEZ P., Museo Nacional, San Jose, Costa Rica</P>
+<P ALIGN="JUSTIFY">JEFF SAYER, World Conservation Centre, Gland, Switzerland</P>
+<P ALIGN="JUSTIFY">G. SEIFERT, Tropical Cattle Research Centre, CSIRO, Rockhampton, Queensland, Australia </P>
+<P ALIGN="JUSTIFY">ANDRES ELOY SEIJAS, Servicio Nacional de Fauna Silvestre, Maracay, Venezuela</P>
+<P ALIGN="JUSTIFY">S.K. SHAH, Institute of Animal Sciences, National Institute of Health, Islamabad, Pakistan</P>
+<P ALIGN="JUSTIFY">SIEH CHENXIA, Department of Animal Science, Nanjing Agricultural College, Nanjing, People's Republic of China</P>
+<P ALIGN="JUSTIFY">B.P. SINGH, College of Veterinary and Animal Science, Chandra Sekhar Azad University of Agriculture and Technology, Mathura, Uttar Pradesh, India</P>
+<P ALIGN="JUSTIFY">C. CATIBOG SINHA, Forest Research Institute, College, Laguna, Philippines </P>
+<P ALIGN="JUSTIFY">A.J. SMITH, Tropical Animal Health, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh, Scotland, Great Britain</P>
+<P ALIGN="JUSTIFY">A. MITHAT EFENDI, Ankara, Turkey</P>
+<P ALIGN="JUSTIFY">HENRY STODDARD, Shamrock Veterinary Clinic and Fisheries, Cross City, Florida, USA</P>
+<P ALIGN="JUSTIFY">SUKUT SULARSASA, Faculty of Animal Husbandry, Gadjalu Mada University, Yogyakarta, Indonesia </P>
+<P ALIGN="JUSTIFY">D.L. SUTTON, Agricultural Research and Education Center, Fort Lauderdale, Florida, USA</P>
+<P ALIGN="JUSTIFY">NICHOLAS SMYTHE, Smithsonian Tropical Research Institute, Panama</P>
+<P ALIGN="JUSTIFY">J. SZUMIEC, Polish Academy of Sciences, Experimental Fish Culture Station, Chybie, Poland</P>
+<P ALIGN="JUSTIFY">N. TABUNAKAWAI, Ministry of Primary Industries, Suva, Fiji</P>
+<P ALIGN="JUSTIFY">FRANK M. THOMPSON, Wild Animal Brokers, Bradenton, Florida, USA</P>
+<P ALIGN="JUSTIFY">ALLEN D. TILLMAN, Stillwater, Oklahoma, USA</P>
+<P ALIGN="JUSTIFY">DON TULLOCH, Winnellie, Northern Territory, Australia</P>
+<P ALIGN="JUSTIFY">CONRADO A. VALDEZ, Dairy Development Division, Bureau of Animal Industry, Manila, Philippines</P>
+<P ALIGN="JUSTIFY">LUIS VARONA, Havana, Cuba</P>
+<P ALIGN="JUSTIFY">PRAN VOHRA, Department of Avian Sciences, College of Agricultural and Environmental Sciences, University of California, Davis, California, USA</P>
+<P ALIGN="JUSTIFY">ANTOON DE VOS Whitford, Auckland, New Zealand</P>
+<P ALIGN="JUSTIFY">GRAHAME WEBB, Conservation Commission of the Northern Territory, Winnellie, Northern Territory, Australia</P>
+<P ALIGN="JUSTIFY">DAGMAR WERNER, Fundacion Pro Iguana Verde, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY">GARY WETTERBERG, Department of the Interior, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY">CHARLES H. WHARTON, Clayton, Georgia, USA</P>
+<P ALIGN="JUSTIFY">F.W. BERT WHEELER, College Station, Texas, USA</P>
+<P ALIGN="JUSTIFY">ROMULUS WHITAKER, Madras Crocodile Bank, Perur, Tamil Nadu, India</P>
+<P ALIGN="JUSTIFY">WILDLIFE CONSERVATION INTERNATIONAL, New York Zoological Society, The Bronx, New York, USA</P>
+<P ALIGN="JUSTIFY">R.R. YEO, USDA-ARS, University of California, Davis, California, USA</P>
+<P ALIGN="JUSTIFY">BRUCE A. YOUNG, Department of Animal Science, University of Alberta, Edmonton, Alberta, Canada</P>
+<P ALIGN="JUSTIFY">CHAROON YOUNGPRAPAKORN, The Samutprakan Crocodile Farm and Zoo, Samutprakan, Thailand</P>
+<P ALIGN="JUSTIFY">THOMAS M. YUILL School of Veterinary Medicine, University of Wisconsin, Madison, Madison, Wisconsin, USA</P>
+<P ALIGN="JUSTIFY">W. ZEILLER, Miami Seaquarium, Miami, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Preface</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The purpose of this report is to raise awareness of the potential of small livestock species and to stimulate their introduction into animal research and economic development programs. It is geared particularly towards benefiting developing nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Microlivestock" is a term we have coined for species that are inherently small, such as rabbits and poultry, as well as for breeds of cattle, sheep, goats, and pigs that are less than about half the size of the most common breeds. These miniature animals are seldom considered in the broad picture of livestock development, but they seem to have a promising future. Wherever land is scarce it seems reasonable to assume that, things being equal, small animals would be more attractive than large ones. And land for livestock is becoming increasingly scarce.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this report we have emphasized multipurpose species with promise for small  holders. In some species, the promise is immediate; in others, it is long term, and much research must be undertaken before that promise can be realized or even understood.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We have included wild species that seem to have potential as future livestock. Some are threatened with extinction but are described here because their economic merits may be the key to acquiring support for their protection. Also we have highlighted rare breeds of domesticated species because the current tendency has been to concentrate on a small number of large breeds, and many potentially valuable breeds are becoming extinct through neglect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The book was prepared after an intensive survey of more than 300 animal scientists in 80 countries. They suggested more than 150 species for inclusion. The staff then drafted chapters on about 40 species and these drafts were reviewed by more than 400 researchers worldwide. The thousands of resulting comments, corrections, and additions were integrated into the drafts. The panel then met to review the product, to select the most promising species, and to rework the chapters based on their own experiences and joint conclusions. The result is the current 35 chapters. Most of the case studies and accounts of innovations highlighted in the various sidebars were developed by the staff study director. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collectively, this study covers many species, but it by no means exhausts all the microlivestock possibilities. Lack of space and time precludes discussion of creatures such as edible insects, snails, worms, turtles, and bats, which in some regions are highly regarded foods. Similarly, we have not included aquatic life. These decisions were arbitrary; perhaps invertebrates and aquatic species can be included in future volumes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report is addressed to government administrators, technical assistance personnel, and researchers in agriculture, nutrition, and related disciplines who are concerned with helping developing countries achieve a more efficient and balanced exploitation of their biological resources. Hence, we deal with the animals in a general way and do not cover details of biology, husbandry, or economics. A selection of readings that contains such technical information is cited in Appendix A.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A further goal of this project has been to explore the common ground between the disparate arms of animal science: to show that specialists in wildlife, zoology, and livestock science have much to learn from one another's field of expertise; to show that "fanciers" of pigeons, pheasants, chinchillas, iguanas, and other species may have much to offer livestock breeders - including germplasm; and that those who raise "obsolete" breeds are not only playing a vital role in the protection of rare genes but can offer the benefit of their experience to commercial livestock producers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Throughout this report, the scientific names of mammals follow those in: Mammal Species of the World: A Taxonomic and Geographic Reference. 1982. J.H. Honacki, K.E. Kinman, and J.W. Koeppl, editors. Published by Allen Press, Inc.; and the Association of Systematics Collections, Lawrence, Kansas, USA. All dollar figures are in U.S. dollars; all ton figures are in metric tons.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been produced under the auspices of the Advisory Committee on Technology Innovation (ACTI) of the Board on Science and Technology for International Development, National Research Council. ACTI was mandated to assess innovative scientific and technological advances, with particular emphasis on those appropriate for developing countries. In this spirit, therefore, the current report includes some extremely unusual species. Whether these will eventually prove practical for widespread use is uncertain, but we present them here for researchers and others who look forward to challenges and enjoy the satisfaction of successful pioneering. The domestication of new poultry, as well as the management of rodents, iguanas, and small deer and antelope, should be viewed in this spirit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Current titles in the ACTI series on managing tropical animal resources are: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The Water Buffalo: New Prospects for an Underutilized Animal</P>
+<P ALIGN="JUSTIFY">· Little-Known Asian Animals with a Promising Economic Future</P>
+<P ALIGN="JUSTIFY">· Crocodiles as a Resource for the Tropics</P>
+<P ALIGN="JUSTIFY">· Butterfly Farming in Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The production of these books has been supported largely by the Office of the Science Advisor of the U.S. Agency for International Development (AID), which also made this report possible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WARNING</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">If misunderstood, this book is potentially dangerous. Because of the severity of the food crisis, the panel has selected some animals - mainly in the rodent section - that are highly adaptable and grow quickly. These seem appropriate for raising only in areas where they already exist, which are clearly identified in those chapters. Such potentially invasive animals should not be introduced to other environments because they could become serious pests. In any trials, local species should always be given priority.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How to cite this report:</P>
+<P ALIGN="JUSTIFY">National Research Council. 1991. Microlivestock: Little-Known Small Animals with a Promising Economic Future. National Academy Press, Washington, D.C. </P>
+<P ALIGN="JUSTIFY">Cover Design by David Bennett </P>
+<P ALIGN="JUSTIFY">In the developing countries, there are over 100 million farms of less than five hectares, supporting about 700 million people, who represent about 17 percent of the world population. Even more significant is the fact that about 50 million farms have less than one hectare of land. C. Devendra and Marcia Burns Goat Production in the Tropics We may now be in the wind down stage of bigger is better animal selection trend and it has certainly been a wild ride.... the lesson now being learned is that the bigger breeding animals . . . cost more to maintain, are often slower to reproduce, and may even have a shorter lifespan.</P>
+<P ALIGN="JUSTIFY">Kelly Klober</P>
+<P ALIGN="JUSTIFY">Small Farmer's Journal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Introduction</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g001a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like computers, livestock for use in developing countries should be getting smaller and becoming more "personal." Conventional "mainframes," such as cattle, are too large for the world's poorest people; they require too much space and expense. "Miniframes," such as the conventional breeds of sheep and goats, have an increasingly important role to play. But tiny, "user-friendly" species for home use are the ones highlighted in this report. We have called them "microlivestock."'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are two types of microlivestock. One consists of extremely small forms of conventional livestock - such as cattle, sheep, goats, and pigs. The other consists of species that are inherently small poultry, rabbits, and rodents, for instance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microlivestock are important because the developing world's animal production is only a fraction of what it should be. Throughout Latin America, Asia, and Africa, the poor eat almost no meat, milk, or eggs - the most nutritious foods. It is estimated, for example, that in Mexico 25 million campesinos cannot afford meat. In poor countries, even the middle class eats less meat in a year than the populations of North America and Europe eat in a month. Malnutrition is common and its effects, especially on children, can be debilitating. It is one of mankind's most serious imbalances - and most pressing problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rural families in the Third World usually subsist mainly on the products from their homes or farms. Thus, if we are to help their livestock production, more attention must be given to animals that are sized for their situations. Examples discussed in the report are summarized here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microbreeds Small breeds of cattle, sheep, goats, and pigs are common in the developing world. Because they are often raised for subsistence rather than for commerce, the national and global contribution that they make is often overlooked. These small, hardy animals deserve much greater recognition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Later chapters highlight dozens of promising microbreeds. All are less than half average size; some are far smaller than that. The "miniBrahman" cow of Mexico is only 60 cm tall and weighs 140 kg; the southern Sudan dwarf sheep of eastern Africa can weigh as little as 11 kg; the Terai goat of Nepal weighs less than 12 kg; and the cuing pig of Mexico weighs merely 10 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Poultry The widespread use of poultry in Third World villages demonstrates the importance of small, easily managed, household livestock. Small size, the ability to forage for themselves, and a natural desire to stay around the house put chickens, ducks, guinea fowl, and other birds among the most vital resources of rural Asia, Africa, and Latin America. Scratching a living out of the dirt, dust, ditches, and debris, these often-scrawny creatures are a resource to be taken seriously. For the most poverty stricken, a bony bird may be the only source of meat during much of a lifetime. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among poultry, there are many underrated, but highly promising, species, including:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Pigeon. These birds forage widely but return home, thereby providing the farmers with squab, one of the tastiest of all meats. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Quail. Small and efficient, they, too, are suited to home rearing, and in Japan and a few other countries, large numbers are raised commercially in very small space. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Muscovy. A native of South American rainforests, this bird is a major poultry resource of France, Taiwan, and a few other countries. Tame, tolerant, and tough, it deserves greater recognition everywhere. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Guinea Fowl. One of the most self-reliant of all domestic birds, this native of Africa is raised in huge numbers in Europe - notably France. Its potential for increased production elsewhere is exceptional. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Turkey. The traditional turkey of Mexico still exists as a scavenger bird in villages and household backyards. Unlike the highly selected modern breeds, it is self-reliant, robust, and disease-resistant. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbits Like chickens, rabbits exemplify the vast possibilities that microlivestock offer for increasing meat production in the most poverty-stricken parts of the world. Captive rabbits have been popular as food at least since the time of the Romans. Rabbit rearing has been well established in Europe and China, and now national rabbit projects have begun in many developing nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rodents Some 7,000 years ago, guinea pigs were domesticated as a source of food for the high Andes; even today in the uplands of Bolivia, Peru, and Ecuador, most Indians raise them inside their homes and regard them as an essential part of life. For many Indians, these indoor livestock are the main source of meat. Prolific, tractable, and easy to feed, house, and handle, guinea pigs are even kept in downtown apartment buildings - often in boxes under the bed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other rodents might also be suited to domestication; for instance, the potentially tamable, clean-living species of South American fields and woodlands - agouti, capybara, hutia, mare, coypu, pace, and vizcacha. Two remarkable domestication programs have been started in Africa: the grasscutter in West Africa and the giant rat in Nigeria. Both animals provide popular "bushmeat" and researchers are now learning to raise them in captivity. (Because of its tangy taste, Ghanaians actually pay three times more for grasscutter meat than for beef!)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antelope Another wild African mammal with potential for "household animal husbandry," the blue duiker, is a rabbit-sized antelope. In some areas of Central and Southern Africa the demand is so great that its population is declining at an alarming rate. Duiker rearing, if it can be made successful, might provide both food and an economic alternative to slaughtering the wild populations. It is reported that duikers are easy to maintain and they reproduce well in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The meat of several other tiny antelope species is also much sought in many African countries, and these animals are also suitably sized to feed the average family at one meal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Deer Several species of tiny deer - smaller than many dogs - might make useful microlivestock, although much research is needed before their true potential can be judged. Normal-sized deer were once considered too easily frightened to be reared as domestic livestock, but several species are now raised on thousands of deer farms in New Zealand as well as in at least a dozen other countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse deer and musk deer (which, strictly speaking, are not true deer at all) are of microlivestock size and are also possible future livestock. The musk deer produces one of the most valuable materials in the animal kingdom - more valuable, in fact, than gold. The musk from the male's glands is used in oriental medicines as well as in European perfumes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iguanas Over much of the Caribbean and Latin America, iguanas are a traditional source of food. Indeed, the meat of these large herbivorous lizards is so delicious they are being hunted to extinction throughout their wide range. Their eggs are much enjoyed also. Programs in Panama, Costa Rica, El Salvador, Curacao, and Argentina have developed simple methods to hatch and rear three iguana species. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bees Honey bees are present almost everywhere, and honey and wax are high-value products that demand little processing and can be stored and transported easily. Innovations in equipment and technique have made beekeeping successful in the tropics without requiring sophisticated hives or elaborate training. Raising bees can also benefit the many crops that require pollination.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE MICROLIVESTOCK ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although animal science has traditionally emphasized bigness, smallness has its advantages. Some of these are summarized below.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microlivestock lend themselves to economic niches that are not easily filled by large livestock. Much of their potential is for subsistence production. They are promising for the many peasants who, being outside the cash economy, are now unable to purchase meat, milk, cheese, or eggs. These people can afford only animals that can be raised within the home or backyard under ambient climatic conditions and on feeds that are cheap and easily available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A subsistence farmer is likely to benefit more from small species than from large because of several factors:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- The animals are less expensive to buy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They are less of a financial risk to maintain. (A farmer with several small animals is less vulnerable to loss than a farmer with a single large animal, a feature that is particularly important in subsistence farming where success determines whether the family will survive.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They give a faster return on investment. (Small size generally signifies high reproductive capacity and a fast turnover.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They provide flexibility. (Farmers can more easily change the size of their herd or flock to match the amount of feed available at a given time. Also, they can sell animals according to the family's fluctuating needs for cash or food.) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They provide a steadier source of income.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They increase the chances of successful breeding because greater numbers are usually kept. (This also means that breeding stock is more likely to be retained in times of scarcity.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- They are more easily transported. (Who hasn't traveled in a Third World bus or train without chickens, ducks, or guinea pigs as fellow passengers?)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- In some cases they are more efficient converters of food energy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are also a number of other benefits to small species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Reduced Spoilage. A portion of meat that comes in a "package" of a size that can be readily consumed by a family is important in areas where refrigeration is unavailable or uneconomic. A family can eat the meat produced by most microlivestock in one meal or in one day to minimize the risk of spoilage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Efficient Use of Space. The space required for handling and feeding microlivestock is proportionately less than that required for large animals. Low space requirements make many microlivestock (such as guinea pigs, rabbits, pigeons, and quail) available to landless rural inhabitants who have no room for a cow. This is particularly important with respect to feed production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Cheaper Facilities. Facilities and equipment required for microlivestock are, by and large, smaller and simpler than those required for large animals. They often can be made from local products or scrap material or both.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Ease of Management. Farmers and villagers can manage small animals more easily than large, which is an advantage in the many places where women and children are the main keepers of livestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Increased Productivity. Small animals tend to fit well into existing farming systems, thereby expanding the resource base and recycling nutrients. Some - for example bees, ducks, and geese - can feed themselves by scavenging.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- By-Products. Many species have fur, feathers, skins, and other by-products that are often more valuable than their meat, milk, or eggs. Examples include the feet and tails of rabbits, musk from musk deer, and pelts from rodents such as coypu. Processing such byproducts creates diversification for the farmer and perhaps jobs for the village.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RATIONALE FOR LIVESTOCK PRODUCTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many have argued that livestock raising should be discouraged, that it is a primary cause of desertification through overgrazing and that it is an inefficient converter of basic material and energy into human food. "Grow more pulses, grow more grains," these people cry. Their arguments can be valid where the land has high potential for permanent cultivation. Much of the world's surface, however, does not fit into that category, and it is in these areas and for those people who have no access to arable lands that a convincing case for livestock can most easily tee mace. As W.J.A. Payne has written:*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Livestock, particularly ruminants, can process forage and waste crop materials inedible by man into nutritionally desirable food products, many of high protein, mineral and vitamin content and including some of high caloric value. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Approximately 40 percent of total land available in developing countries can be used only for some form of forage production and a further 30 percent is classified as forest with some potential for the production of forage. Some 12 percent of the world's total population live in areas where people depend almost entirely on the products obtained from ruminant livestock. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Livestock provide a range of extremely valuable by-products. Dung is not only a fertilizer and soil-stabilizer but also a fuel of often considerably greater value than the fodder consumed in its production. Other byproducts, especially hides and wool form the bases of rural enterprises that may provide significant incomes to the poorest members of society. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Animal plant and human life are ecologically interdependent. The establishment of agricultural systems in which livestock are integrated with crops, forestry and aquaculture is essential for the improvement of overall productivity. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock produce food that adds to the nutritional quality and variety of human diets. Although it is possible for humans to exist without them, these foods are relished and sought after by the majority of humanity. These foods include meat, eggs and processed products such as biltong and cheese. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Feed</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In general, small species tend to expand the food base by using a wider array of resources than do major livestock such as cattle. Many can be raised on feeds that people discard: fibrous residues, industry by-products, or kitchen wastes. Some collect minute feeds that otherwise go unused. For example, chickens and pigeons gather scattered seeds, turkeys gobble up insects, geese graze water weeds, iguanas feed in the tops of trees, and bees collect nectar and pollen from flowers that may be miles away.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Even some grazing microlivestock prefer different forages from those preferred by cattle. Antelope and deer, for instance, browse tree leaves; capybara and grasscutters eat reeds. Combining microlivestock with conventional livestock results in a more complete utilization of forage resources and greater animal production per hectare.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under conditions of abundance, small size may be of no advantage in mammals, but if feed is limited, it is of great help. A small animal (or its keeper) needs to cover less area to fulfill its daily requirements, so that microlivestock may grow fat in areas where the forage is too sparse to support a larger animal. This is particularly vital when there are seasonal bottlenecks. For example, feed may be plentiful enough for most of the year to supply many large animals; however, the dry season may greatly restrict the numbers that can be kept.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although small animals generally require proportionately higher inputs of feed, they also grow proportionately faster (see sidebar opposite). In addition, species such as rabbits, guinea pigs, and grasscutters digest fibrous matter with surprising efficiency, even though they are not true ruminants like cattle, sheep, and goats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reproduction</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many small animals have high reproductive capacity with short gestation periods, large numbers of offspring, and rapid juvenile growth. They tend to reach sexual maturity at a younger age than large animals, and the interval between the generations can be very short. Thus, meat or other products can be produced more rapidly and more evenly throughout the year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cows, for example, produce a maximum of one calf per year. A pig, on the other hand, may produce 7 or more young; a rabbit, 30 or more; a chicken, more than 100.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adaptability and Hardiness</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The survival rates and manageability of many small breeds and species can be outstanding. Smallness is often an adaptation to harsh environment. Indeed, a major promise for microlivestock is in special environmental niches. Where cold, heat, temperature fluctuations, aridity, or humidity are extreme, microlivestock are likely to show their greatest advantage. Chickens, guinea fowl, goats, and many other small species already live in villages, homes, and backyards in harsh and disease-prone climates, and are usually given no care and sometimes no food: they have to scavenge for their sustenance and survive as best they can. Such selection pressures result in animals of remarkable adaptability, tolerance, and robustness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Some microlivestock can produce under conditions where conventional species die. The capybara, for instance, is at home in the Latin American lowlands, where the climate is hot and humid and floods cause seasonal inundations. Cattle, by contrast, die because of malnutrition, foot rot, or drowning. Other microlivestock species with a wide tolerance to ecological extremes include the turkey, pigeon, and bee. And some dwarf breeds of cattle, sheep, goats, and pigs show surprising tolerance to trypanosomes, the parasites that make conventional breeds impossible to maintain throughout much of Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some small species can be raised in cities, where poverty and malnutrition are often worse than in rural areas. It is estimated, for instance, that one million livestock exist in Cairo, not counting the pigeons that are raised on countless rooftops. Goats and cattle are common in urban India, and many Third World cities have far more chickens than people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p9a.png"></center><br>
+ Food utilization versus body size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICROLIVESTOCK LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raising microlivestock is not a panacea for the Third World's food problems. Efforts to develop them will not be without difficulties. Some likely problems are noted here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">High Energy Requirements</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Smaller animals tend to have a higher feed requirement per unit of body weight than large animals. Anatomical and physiological constraints prevent them from meeting their relatively high energy requirements simply by increasing the rate of food ingestion. Therefore, for optimum production, some small animals, particularly nonruminants, require feed that is higher in protein and lower in fiber than large animals. This is particularly true when the small animals are compared with ruminants such as cattle, sheep, and goats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Increased Labor Requirements</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The advantages of low investment, fast return on capital, flexibility, and efficient resource utilization are offset by higher demands for labor. Keeping small animals often requires considerable effort, and its economic viability may depend on the availability of cheap and willing labor. Many small animals are raised at home by family members, such as children, the elderly, and the handicapped, who have time available and whose labor costs are nominally zero.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Diseases</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some potential microlivestock are undomesticated, and resistance to diseases and parasites is one justification for their consideration. However, the general healthiness of a species when it is free-ranging can be a misleading guide for its husbandry. Confining any animal in high density invariably increases the potential for the spread of infectious diseases and parasites. Moreover, mismanagement can foster respiratory and gastrointestinal diseases (such as salmonella or coccidiosis) that are rare among scattered populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some microlivestock are potential reservoirs for diseases that affect not only local animals but people as well. This may limit their successful development in some areas. Although the dangers are often exaggerated, controls may be needed, particularly of rinderpest, tickborne diseases, and those diseases communicable to humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Predation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small size makes microlivestock easy prey.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lack of Research</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Techniques to manage some microlivestock species are not yet well established. The development of appropriate husbandry techniques, as well as a better understanding of the animals' particular biological and behavioral characteristics, will be needed before major progress can be made. These species (for instance rodents, deer, and iguanas) may require collection of different genotypes, as well as studies of diseases, nutrition, and management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Complex Logistics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is complicated and expensive to reach millions of widely scattered peasants, each having only a handful of small animals. Even though total production may far exceed that of commercial farms raising large animals, the smallholdings are often dispersed, their animals are often used for subsistence rather than commerce, and their managers are often ill-trained and illiterate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Legislative Restrictions</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The use of some microlivestock species may be restricted by legislation. For instance, some countries have meat and veterinary laws that work against the development of species other than cattle. Others have laws to protect wildlife, which could be important in the case of species such as antelope, deer, pace, and iguana.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lack of Markets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microlivestock need not be just for home or local consumption; they can also be raised for market. But some commercial programs, including some with rabbits and guinea pigs, have failed because no public demand was developed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Resistance to New Species</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People have close associations with livestock, and in most cultures they do not easily accept animals or animal foods that are radically different from their traditional ones. In general, the ties between certain ethnic groups and a particular species or breed is very strong (one reason, for example, why European colonists introduced their own large breeds of cattle and sheep to Africa and Asia, paying little attention to small indigenous breeds). Moreover, people who are used to bringing the animal to the feed rather than the feed to the animal may resist a small animal that has to be penned up and fed by hand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Opposition to Smallness</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, there seems to be an innate human trait that considers bigger to be better, especially among the common livestock. For example, because many tropical cattle are small, there is strong inclination on the part of those responsible for livestock improvement to dismiss them or to increase their size by crossing them with large breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FUTURE OF MICROLIVESTOCK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small animals are likely to become increasingly important. As human populations increase, the space available for growing forage decreases, and this phenomenon favors small animals. Many villagers already have little or no pastureland. Some live in areas (the rice-growing areas of Southeast Asia, for instance) where crops are grown on almost every square meter almost every month of the year. Microlivestock are potentially important for urban areas of developing countries as well. There, too, land is at a premium and is usually inadequate for raising conventional livestock. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So far, however, microlivestock have been largely ignored. Compared with cattle, they have been accorded little scientific effort. In the drive towards larger animals, stimulated by experience in the temperate zone, the virtually unstudied gene pool of small species and breeds has been mostly bypassed. There have been few attempts to assess or improve their farm productivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is unfortunate, and it is perhaps due to the fact that small animals may be less efficient at digesting certain foods and therefore technically less attractive than large, "modern" breeds. But to Third World peasants, an animal's efficiency is far less important than its survivability and manageability. If an animal cannot be raised under village conditions, its feed-use efficiency or milk yield is irrelevant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microlivestock production should be integrated into most ruraldevelopment projects. Small animals offer a way to improve the lives of people who are hard to reach by other methods. Only by expanding research on the husbandry, hygiene, nutrition, reproduction, physiology, and breeding can the promise of animals sized for small farms and villages be fulfilled. Moreover, the costs will be small compared with those of programs for large animals.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Specifically, experiment stations should produce and promote methods and materials for use in rearing microlivestock. Donors and development institutions, planners, and policymakers should note the potentials of microlivestock and the benefits that can be derived from them. Teaching manuals and materials are needed, and classes in microlivestock husbandry should be included in rural school curricula.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raising personal livestock on weeds and table scraps in cages beside the house or boxes under the bed will, in many instances, get quality protein to the most poverty stricken more effectively than raising large livestock on pastures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although small size confers many advantages, the question is not whether the large or small animal is "best," but rather how well each can meet a person's varying requirements. In a given situation, livestock can be too small or too large. But the fact remains that not everyone who wants meat or money has the resources to acquire, keep, manage, or utilize a large animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The key is balance. Both microlivestock and traditional livestock deserve serious attention. Indeed, it seems likely that the two will seldom compete. Most microlivestock complement traditional livestock because of unique physical, physiological, behavioral, or economic characteristics. They increase the range of options for the millions of poor for whom the choice may not even be between large and small livestock, but between microlivestock and no livestock at all. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It's an unfortunate fact that small animals don't have the prestige among Third World farmers that large animals do (perhaps this arose because children can look after goats and sheep but it takes men to look after cattle). Even sheep and goats are not accorded the same stature as cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hugh Popenoe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeds and varieties were created from mutant genes and thus haste become living reservoirs of these genes, holding them for use in future generations of mankind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anonymous</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g002a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part I : Microbreeds</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g003a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle, goats, sheep, and pigs supply millions of people around the world with the bulk of their cash and animal products. Yet scores of breeds - especially in the tropics - are left out of livestock development projects merely because they are considered too small. These "microbreeds"' have sometimes been considered genetic dead ends because they appear undersized and puny. Many of these traditional animals - some in local use for thousands of years - are disappearing, and even the small ancestors of large modern breeds are becoming extinct.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These small breeds deserve to be studied and developed in their own right. Throughout Africa, Asia, and Latin America, these usually hardy animals are especially adapted to traditional husbandry practices and harsh local conditions. Some have remarkable qualities and are well adapted to resist hostile weather, ravaging pestilence, and poor diets. In remote places and in areas of extreme climate, they are often vitally important for basic subsistence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indeed, because of stress or disease, or insufficient forage, land, or money, microbreeds may be the only practical livestock in many settings. Their individual output may be low, but it can be efficient considering the lack of care and poor feeds they are given. Their availability and the growing number of small-sized farms in the developing world make them increasingly worthy of consideration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following chapters in this section describe microcattle, microgoats, microsheep, and micropigs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">1 Microcattle</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g004a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the purposes of this report, "microcattle" are considered to be small breeds of cattle (Bos taurus and Bos indicus) with a mature weight of about 300 kg or less. In many areas of the developing world, these are actually the animals most widely held by farmers and pastoralists. They are often treasured because of their resilience and simple requirements. Many survive and produce under harsh conditions, grow rapidly, calve easily, show good maternal ability, yield lean meat, or have other advantages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle have generally been ignored in the push towards larger animals, but they seem inherently suitable for traditional and small-farm husbandry. As rural people in developing countries improve their own productivity, as they become more aware of nutritional needs, and as they depend more upon cash economies, microcattle could become vital means for improving personal, dietary, and economic status.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle have been classified in many ways, but they are generally designated as humped or humpless types. However, clear distinctions among them are sometimes difficult or impossible to make because they have intermingled for thousands of years. Representative microcattle types are listed at the end of the chapter. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than two-thirds of the world's 1.3 billion cattle are found in the developing world; one-third is in the tropics. As noted, a considerable number of these could be called "microcattle."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many strains of microcattle are threatened with extinction because of replacement or crossbreeding with larger types. This is in some respects shortsighted because promoting just a few breeds contributes to narrowing of the genetic base, and valuable traits may be lost when selection is done to conform to any preconceived standard, including large size.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle are adapted to a wide variety of habitats. Many types thrive - even with little or no attention - in climates that are hot, humid, arid, or beset by diseases and parasites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle are ruminants and digest fiber well, although they are selective foragers and prefer tender grasses and low-growing legumes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As with other tropical cattle, microbreeds generally reach physical and sexual maturity in 2 or 3 years. Many can breed year-round when conditions are favorable (gestation lasts about 9 months). Cows may remain fertile 10 years or more, and can live more than 20 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle usually graze from as few as four hours to as many as eight hours a day. If feed is of poor quality, they must forage (and ruminate) longer to receive adequate nutrition. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle are commonly docile and undemanding animals, and many small breeds are surprisingly responsive to humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like conventional breeds, microcattle produce the same well-known products: meat, milk, manure, hides, horn, blood, and bone. They are also used for traction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small cattle often produce only modest amounts of milk and meat per animal. However, given higher stocking rates, a herd of microcattle is often able to outyield larger, genetically improved animals on a per hectare basis, especially under stressful conditions. When their ability to survive adversity and poor management is taken into account, they may often be far and away the most efficient cattle for traditional husbandry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surprisingly, there is a place even for small draft animals. They tend to be active, thrifty (efficient), and more maneuverable in tight spaces, and so are adapted for use in the small fields, terraces, and paddies that are becoming increasingly common. The small hill cattle of Nepal, for instance, are valued because they can negotiate steep slopes and narrow terraces on Himalayan mountainsides. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle are handled like their larger counterparts, but herding, tethering, fencing, and hobbling are generally easier.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle are familiar animals that are accepted in nearly all cultures; their meat, milk, manure, and leather are in demand almost everywhere. In many societies, beef is preferred over other meats, even by those who can rarely afford it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most areas, organized breeding, production, and marketing associations are already in place. Microcattle can also integrate well into traditional forms of husbandry, whether in pastoral herds of hundreds or as solitary backyard milk cows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under humid and hot conditions, microcattle probably suffer less than larger breeds because their greater ratio of skin area to body mass enhances their ability to shed heat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The number of cattle that can be kept on a given parcel of land may be increased, sometimes even doubled, with smaller animals. Microcattle can also be penned and fed cut-and-carry forage more easily than can larger cattle, and more of them can be maintained on the same amount of feed. This permits more continuous production and less financial hardship when an animal perishes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small cattle may require less labor because they are generally easier to handle, herd, confine, and transport. They usually have few problems with calving, and as a rule require little or no assistance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some microcattle have unusual tolerances to disease. In Africa, for instance, there are breeds that tolerate or resist trypanosomiasis, a parasitic disease that makes large areas of that continent uninhabitable for most other cattle breeds. Others seem more tolerant of internal or external parasites, theileriosis (east coast fever), rinderpest, or other afflictions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle often lack the prestige of larger breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When given quality forage and supplemental feeding, small unimproved cattle may not match the overall productivity of the large, highly developed breeds. Their greatest potential may prove to be for traditional husbandry and for grazing marginal areas where survival is more important than feed efficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BONSAI BRAHMAN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Mexico, researchers are deliberately creating microcattle. Since 1970, Juan Manuel Berruecos Villalobos, former director of the Veterinary Medicine school at the National Autonomous University, has directed this enterprise. He and his colleagues have miniaturized cows by selecting the smallest specimens out of a herd of normal-sized Brahman cattle and breeding them with one another. After five generations, adult females average 15-180 kg adult males 20-220 kg. A few of the smallest cows are now only 60 cm tall and 140 kg in weight. Merely one-fifth of normal weight, they are shorter than the turkeys that share the barnyard with them. Indeed, they even get lost in the grassy pastures so that the farmers cannot see them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This program seems to have yielded a productive animal that can be cheaply and easily maintained in a small space. Berruecos has demonstrated that the tiny cows can be stocked on one-third the area needed to support one normal-sized cow. He reports that they are giving remarkable amounts of milk: up to four lifers a day, compared with six lifers from their full-sized counterparts. On a feed-intake to weight-gain basis, the tiny cattle are no less efficient than their normal-sized counterparts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although 17 years have gone into the selection of what Berruecos calls his "bonsai cattle," the process is not yet finished. Future goals include testing embryo transplants to see if one normal-sized cow can support multiple "microfetuses" (possibly as many as eight). This would help to rapidly increase the numbers of the miniature form, which weigh merely 4-5 kg at birth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All in all, the Mexican researchers see miniaturization as a new option for governments and farmers increasingly squeezed by shrinking farm land and rising production costs. Small livestock they say, are a way to produce more food on less land faster. For example, a campesino with almost no land can have one or two bonsais, but could never maintain a standard-sized cow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Their adaptability and robustness make microcattle worthy of preservation, study, and greater use, and they should be incorporated into many ongoing programs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Selective breeding, although infrequently attempted, can probably improve productivity significantly. Records of breed history should be established, and unusual or special characteristics noted and the information disseminated. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p24a.png"></center><br>
+ Original distribution of wild cattle and banteng (Based on Mason , 1984)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In areas where small, indigenous breeds are being replaced, representative populations should be maintained and studied to increase understanding of their adaptive diversity and to retain a genetic storehouse for the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">REPRESENTATIVE EXAMPLES OF MICROCATTLE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dwarf West African Shorthorn</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">West African coastal forests, and inland. Female 125 kg; male 150 kg. Adaptation to harsh, humid climates and good resistance to trypanosomiasis and other diseases allow these small animals to exist where other cattle die. They are perhaps the smallest cattle of all (often weighing less than 100 kg). In the areas of worst disease and highest rainfall, this hardy animal is often found thriving, but half wild. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muturu Nigeria. Female 160 kg; male 210 kg. This notable subtype is slightly larger. It is the most trypanotolerant of all cattle, showing no symptoms or loss of vitality. It is widely kept, mostly as a village scavenger and often as a pet, and yields a high percentage of meat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N'Dama</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West Africa. 200-400 kg. These active, stocky animals utilize low-quality forage, produce good beef, and are used as light draft oxen. Milk production, though poor, improves with feeding level. N'Dama mature early and are exceptionally fertile, and they have already become important in breeding programs. They are resistant to trypanosomiasis, and can exist where temperatures average 30&Yacute; C with 1,500 mm annual rainfall. In the least hospitable areas, N'Damas ranging down to 200 kg are often the only cattle that can remain productive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rodope</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southeastern Europe. Female 200 kg; male 350 kg. A humpless multipurpose breed - draft, milk, and beef - that is exceptionally hardy. The milk is high in butterfat. Possibly adaptable to the subtropics. It is rapidly being lost to crossbreeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zebu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zebus are among the most important tropical domestic animals. However, the dwarfs are not well known, although in many areas they are preferred, especially as draft animals. Zebus use less water, even though their sweat glands are larger and more numerous than those of most other cattle. All have a low basal metabolism and resist heat well. In general, they also have high resistance to ticks and other parasites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taiwan Black Taiwan. Female 250 kg; male 250 kg. Well adapted to poor tropical conditions, these work animals are also used for meat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kedah-Kelantan Malaysia. Female 200 kg; male 250 kg. Hardy, well adapted cattle with exceptional fertility on a poor diet, both sexes are used as draft animals as well as sources of meat and cash. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sinhala (Dwarf Zebu) Sri Lanka. Female 200 kg; male 250 kg. An ancient type of zebu, preferred for its handiness in cultivating small paddies and terraced fields. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nuba Dwarf Sudan. 180-220 kg. These work animals are well proportioned but are not slaughtered for meat, and milk production is low. Although tolerant to trypanosomiasis, their numbers have dwindled because of crossbreeding. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small Zebu Somalia. 160-230 kg. These small native cattle are used for beef, milk, and for work. They are well adapted to poor feed in a desolate environment. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abyssinian Shorthorn Zebu (Showa) Central highlands of Ethiopia. Female 225 kg; male 305 kg. These widespread, small-humped cattle are very hardy. They produce beef and are generally milked, with surplus production about 2-4 kg daily. Resistant to many parasites, they also have a gentle disposition and make good work animals. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dwarf Zebu (Mongalla) Tanzania, Uganda, and Kenya. Female 150 kg; male 250 kg. A highly variable, long-entrenched, small, East-African zebu with some nonzebu blood. Pastoralists favor it because of its hardiness. Although slow-maturing, it is well-fleshed, can yield excellent beef, and some types are milked. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mashona Zimbabwe. Female 200 kg; male 250 kg. This hardy zebusanga type (see below) is widespread in drier areas and has a high resistance to disease and parasites. Since the 1940s, it has been bred for beef production and selected animals now weigh more than 500 kg. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mini-Brahman Mexico. 135 kg. Downsized from 450-kg Brazilian zebus through selective breeding by Mexican researchers, these gentle animals are reported to yield two-thirds as much milk (3-4 liters daily) as the parent stock. Because of much higher stocking rates on grass, production per hectare is reportedly greater than with full-sized animals (see sidebar, page 22). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Criollo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central and South America. Descendants of Spanish and Portuguese  cattle imported over 400 years ago, "criollo" cattle have adapted to a  wide range of harsh climates. Many varieties are small: mature females  often weigh 200-300 kg or less. They sometimes produce little beef or  milk under traditional conditions and management, but they are  extremely hardy and survive when other cattle perish. Through  importation and crossbreeding, many local types have been lost or are  threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chinampo Baja California, Mexico. 200-350 kg. Extremely tolerant of  wild desert conditions, these docile criollo cattle exist largely on scrub  and cactus. They get most of their water from succulent plants, have a  low metabolic rate and body temperature, and are mostly active at night. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Florida Scrub Florida, USA. 225-300 kg. Genetically isolated for more  than 300 years, the Florida Scrub is very hardy in harsh, subtropical  conditions. It has good resistance to ticks and screwworm, and can  subsist on forage with a high roughage content. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sanga</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This type - an ancient cross between longhorns or shorthorns and  humped animals - is found throughout eastern and southern Africa. It  weighs from 150 to 500 kg or more. Some types have been selectively  bred or crossed with European cattle and are quite productive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bavenda Transvaal, South Africa. 240-290 kg. This hardy and  disease tolerant tropical variety is small and prolific. It is generally used  for draft, barter, and beef. However, it has been crossbred with larger  animals so frequently that the smaller types are almost extinct; most  "Bavendas" now weigh more than 300 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ovambo' Northeastern Namibia. Female 160 kg; male 225 kg. A calm  and docile animal with a small hump, it is used by seasonal pastoralists  for beef and milk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nilotic Sudan. 180-300 kg. These cattle of southern Sudan show great variation in size, partly due to environmental factors. They are generally resistant to local parasites and worms, have good potential for increased beef production, and their milk is very important locally.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chadian "Native" and Dwarf Black Cattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad. Female 225 kg; male 275 kg. These two types are small, humped meat animals that graze the sparse savanna and are very drought resistant. Little scientific information exists about them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Arab Cattle"</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Middle East. Small types (female 225 kg; male 300 kg) are used for meat and some milk, especially in Lebanon. There are many local forms with variable appearance, but all have small humps. Well adapted to grazing sparse vegetation on rough land, they are becoming rare due to crossbreeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hill Cattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal. Female 160 kg; male 200 kg. A widespread type often recrossed with Indian zebu animals, they are bred to be small. They are thrifty creatures that maintain themselves well on poor forage. Bulls make sure-footed draft animals on rough ground and slopes, and the cows are milked.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tibetan Dwarf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tibet. Less than 250 kg. These humpless cattle are used as pack animals and can tolerate poor forage and high altitudes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yellow Cattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southwest and south China. Female 220 kg; male 380 kg. In the subtropics and tropics, small multipurpose types of Yellow Cattle withstand high temperature and humidity. They are used mainly for work and meat, and seem well adapted to poor feed, harsh conditions, and rugged terrain. The Chowpei (190-380 kg) is a hardy working breed of more temperate areas in Hubei Province.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cheju Hanwoo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Korea. Female 230 kg; male 280 kg. A yellowish-brown Cheju Island native that has almost no calving difficulty, it is well adapted to poor grazing conditions in harsh environments and is docile and obedient.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madura</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indonesia. Female 220 kg; male 300 kg. An ancient cross between humped cattle and the banteng (see sidebar), these heat- and disease resistant hybrids also have good grazing and mothering ability, and are kept in the most extreme humid tropical environments. Breeding for fighting and racing has given them a poor disposition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dexter Cattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ireland and North America. 220-360 kg. This breed can be traced back to eighteenth-century Ireland and is believed to have been developed by peasant farmers living on rough land. It is exceptionally hardy and produces both milk and meat. In North America, it has become popular among city folk who acquire country property, as this microbreed is particularly well suited to their usually tiny farms. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BANTENG: THE CUTEST COW</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The banteng (Bos Javanicus) is a small Southeast Asian bovine with a promising future.* It is a different species from cattle. The two will interbreed, but the hybrid offspring are normally sterile.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although almost entirely neglected by the animal science community, the banteng is remarkable for an ability to thrive under hot, humid, and disease-ridden conditions where cattle often grow poorly. The sexes are easily distinguished: males are jet black, females are golden brown. Both have bright white socks and rumps as if they had been freshly whitewashed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng are found in remote areas of countries from Burma to Indonesia. But only Indonesia has used it as a farm animal so far. It has more than 1.5 million domesticated banteng - some 20 percent of the country's total "cattle" population. Indonesian farmers value the animal's agility, which allows them to cultivate Relds too narrow for cattle to turn the prow. In addition, gourmets consider banteng meat the tastiest of all. Indonesia appreciates the banteng so much that it has established a genetic sanctuary on the island of Bali - banning cattle in order to maintain the banteng's genetic purity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Outside Indonesia, only a few scientists have studied this animal, but it seems clear that it is particularly useful under tropical conditions. In heat and humidity, it thrives; even when cattle are starving, one rarely sees a skinny banteng. And demand for its meat is never ending.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">2 Microgoats</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than 90 percent of the world's nearly half billion goats (Capra hircus) are found in developing countries; many weigh less than 35 kg fully grown.` Such "microgoats" are noted for their high reproductive rates, rapid growth, early maturity, tasty meat, and rich milk' as well as for their robust constitution, ease of handling, and tolerance of climatic stress and poor feeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To many people - especially where pigs and poultry are not common - meat and milk from microgoats are the primary animal proteins consumed during a lifetime. Perhaps the world's best foragers, goats eat practically anything made of cellulose, and are not dependent on grass. Because of their unselective feeding behavior, they are capable of living where the feeds - tree leaves, shrubs, and weeds - are too poor to support other types of livestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Such microgoats deserve wider recognition, for they are often the poor person's only source of milk, meat, and cash income. They are cheap to acquire and easy to maintain, even by people with little property and scarce resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide, especially in arid and semiarid climates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats generally have a long snout and an upright tail, by which they can be distinguished from most sheep. The mouth is unusual in having a mobile upper lip and a grasping tongue, which permits the animal to nibble even tiny leaves on spiny species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Common commercial goat breeds generally weigh between 60 and 100 kg, with some weighing more than 200 kg. Microgoats may weigh less than 15 kg. Representative examples are listed at the end of the chapter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide, with half in Asia and one-third in Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The FAO projects that world numbers may nearly double by the turn of the century. Goats are thus not endangered, but in some areas select populations of feral goats are being deliberately eradicated, with the consequent loss of potentially valuable genes. Some small breeds are also threatened by excessive crossbreeding with larger types.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most adaptable of all livestock, goats can persist in conditions from arid to humid, and from sea level to high altitude. They are especially well adapted to hot, semiarid climates and to rocky, barren terrain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These ruminants can subsist on many feedstuffs that would otherwise be left to waste. Although selective browsers, they often prefer coarse leaves (including palm fronds) and shrubbery to palatable forage grass.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most microgoats mature quickly, and in the tropics they can generally breed year-round. Their reproductive potential has often been underestimated; kidding is rarely difficult, and many types produce twins and sometimes even triplets or quadruplets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In hot, dry areas, goats require less attention than other livestock, and smaller goats have the added advantage of better heat dissipation. Some microgoats may also show disease resistance. For example, tolerance to trypanosomiasis makes them an important livestock in many regions of Africa. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats are generally gentle, but can be easily frightened. They may become stubborn and aggressive when threatened or thwarted, and can prove hard to confine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If their feed smells of other animals - particularly of other goats -  they usually shun it unless nothing else is available. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microgoats mainly produce meat and form an important part of the diet in southern Asia, the Middle East, Africa, and Latin America, especially the Caribbean. Goat is sometimes a preferred meat, and there are few social or religious prohibitions against eating it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some microgoats are good milkers, and under stressful conditions they may keep producing when other livestock are dry. Goat milk is a valuable dietary supplement: it is nutritious, easily digestible, and usually commands premium prices. It makes excellent cheese and yogurt and can be used by people allergic to cow's milk.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microgoats produce some of the finest and most valuable fibers in the world. Angora and Cashmere goats often weigh less than 30 kg fully grown, for example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats produce a fine-textured, durable leather that finds extensive uses both locally and internationally. Horns, hooves, blood, and bone meal also have commercial value. Manure is another important product, and comes in fairly dry pellets that are easy to collect, store, and distribute.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats perform important functions in land management. Seeds of many trees (Acacia and Prosopis, for example) are "scarified" by passing through the goats' digestive system, fostering germination and natural revegetation. With care, goats can also be used to clear land of weeds and brush.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats are often allowed to roam and scavenge for their own food. They form strong territorial attachments and can be trained to stay within a designated area. However, they cannot be kept from investigating - and quite probably devouring - anything within that territory. They are persistent browsers, so it is essential to prevent overstocking as well as raids on crops.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Variety of diet is important, and goats show much individuality in feed preferences. They are often raised on crop residue and kitchen refuse.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats can be run with other livestock without creating serious competition. The goats browse weedy shrubs, whereas the sheep and cattle graze more on grasses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although perhaps the hardiest of all livestock, most breeds benefit when they are provided shelter from rain and high-noon sun. Abrupt chilling and poor ventilation can cause severe respiratory problems. They are also susceptible to various maladies, such as internal parasites, especially when confined. The highest mortality, however, is caused when very young kids are not supplied with adequate feed and clean, dry shelter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In most developing countries goats are already prominent in rural life. Common almost everywhere in Africa, Asia, and Latin America, they are dependable multi-use animals. They are particularly important in providing ready cash, such as for school fees, taxes, marriages, or funerals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats integrate well in mixed agriculture, for example, by consuming leafy wastes, clearing land, and contributing fertilizer. In many places they are raised almost exclusively by women and children. If confined, goats require only simple, inexpensive shelters or pens, which makes them especially important as subsistence animals. In many situations, they may be the most efficient and economic producers for smallholders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals have a relatively fast rate of growth and early reproductive age, even under harsh conditions. They can graze rougher terrain than cattle and most sheep, can go for longer periods without water, and forage well in wooded areas where grass is lacking. They can derive most or all of their diet from roughage unusable by humans; high-energy feeds, such as protein supplements or carbohydrate supplements, are usually not needed even to fatten them for slaughter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats are generally healthy and are not affected by many of the parasites and diseases that ravage other livestock. Some resistance to mange, internal parasites, foot-and-mouth disease, and other livestock scourges has been reported.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some places (notably, in industrialized nations) there is a strong prejudice against goats and goat meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Smallness makes microgoats targets for predators and thieves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many small goats are poor milkers, especially under hardship conditions; however, even small amounts of milk can often fulfill a child's daily nutritional requirement or reinforce a nursing mother's diet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats are independent and may wander away if not watched, and they can be difficult to pen. They may also have an unpleasant odor when kept confined (males are particularly malodorous during rutting season). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goats are often disparaged for degrading land and destroying vegetation because they continue to survive on overutilized lands often laid waste by mismanagement of sheep or cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRESH GENES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A rare wild animal with spectacular horns, the bezoar (Capra aegagrus) is the goat's wild ancestor. People domesticated it before 7000 B.C., probably in the mountains along the Iran/ Iraq border. Until recent times, it remained widely scattered across the vast region between Greece and Pakistan, but it now exists only in pockets and is threatened with extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This would be a tragedy because the bezoar is a resilient wild species that crosses readily with domestic goats, and it could pass on its genetic inheritance for heat, drought, and cold tolerance: disease resistance; and other survival qualities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p39a.png"></center><br>
+ Distribution of the bezoar. The arrow indicates the area where it was probably first domesticated, resulting in the goat as we know it (From Mason 1984)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fascinating science and valuable results probably await those willing to study this hardy, handsome creature and to explore the reharnessing of its genetic endowment. Today the bezoar is considered merely a trophy for hunters. The power of its genes to refresh - perhaps even revolutionize - the world's 500 million goats has been lost to sight. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The microgoat's potential has hardly been realized. More research on performance and husbandry is needed to preserve and restore small breeds. Selective breeding for prolificacy, viability, and rapid growth, as well as more selective on-site culling, could greatly improve both meat and milk yields and quality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Management systems that exploit smallness, stabilize production, and preserve the environment should be introduced and publicized in appropriate goat-rearing areas. Careful assessments of indigenous management methods should be made, particularly emphasizing their desirable characteristics. Improving hygiene in the wet season and supplemental feeding in the dry season are also important, as are disease- and parasite-control measures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The undomesticated ibex and markhor could possibly be major contributors in the development of new, useful breeds for tropical and arid regions (see sidebar, page 42). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">REPRESENTATIVE BREEDS OF MICROGOATS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West African Dwarf (Djallon)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West and Central Africa. Female 20 kg; male 30 kg. Adapted to humid lowlands, this widespread goat is particularly valuable for meat and skin production. Generally, it is bred for meat, but milk is sometimes an important secondary product. Sexual maturity is very early (3-6 months), and quadruplets occasionally occur (most goat breeds normally produce only single births). Related types go by the names "Cameroon Dwarf," "Dirdi," and "Nigerian Dwarf."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nubian Dwarf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United States. 35-40 kg (often less). A stable miniature variety of the milking Nubian, this microgoat has been developed recently in the United States by crossing standard-sized Nubians with the West African Dwarf. It combines a good milk output with high levels of butterfat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">American Pygmy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United States. 15-25 kg. Derived from the West African Dwarf, it is noted for its hardiness and good nature, good milk production, and adaptability to various climates. There are several varieties, some for milking, others for meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sudanese Nubian</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northern Sudan. 25-30 kg. Widespread milk goats of riverain and urban areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sudanese Dwarf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southern Sudan. 11-25 kg. A very hardy desert goat similar to the West African Dwarf, it averages 15 kg, but some mature individuals may weigh as little as 11 kg. Used for meat and hides, it produces little milk.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small East African</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya, Uganda, Tanzania. 20-30 kg. A widely neglected meat and hide animal found over a wide range, it is fast growing (sexual maturity at four months) and extremely hardy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mauritian</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mauritius. 25-30 kg. A prolific, year-round breeder raised for meat production, it is often confined in simple shelters from birth to slaughter. Perhaps because of this isolation, mortality is less than 10 percent, even with little or no veterinary care.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Criollo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Latin America. "Criollo" is a name given to several breeds of ancient Iberian blood with local adaptations to many unfavorable conditions. They are often small and hardy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Creole Caribbean. Females 20 kg; males 25 kg. Robust meat goats of Spanish or West African origin that are kept throughout the Caribbean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crioulo Brazil. 30-35 kg. A meat and skin goat derived from Portuguese ancestors, it is hardy, prolific, undemanding, and adapted to harsh environments. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chapper</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pakistan. Female 20 kg; male 24 kg. Originating in dry regions, this meat and milk goat is a nonseasonal breeder with outstanding potential.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Barbari</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pakistan, India. Females 20-25 kg; males 20-40 kg. A prolific, fastgrowing "urban" goat with high twinning and low mortality. Often kept inside houses, they adapt well to confinement and are important for both milk and meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaddi (White Himalaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hill districts of northern India. 25-30 kg. Kept for meat and their long, lustrous white hair, they are pure-breeding and healthy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Changthangi (Ladakh)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kashmir, India. Male 20 kg. A pashmina (cashmere) goat of India, it is adapted to a high altitude, high humidity climate with extremes of temperature.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Terai</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal. 8-12 kg. A very small, hardy animal of the southern lowlands, it kids year-round (sometimes twice), and often produces twins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southern Hill Goat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal. 12-16 kg. A small, mid-altitude goat resembling the Terai. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black Bengal (Teddy, Bangladesh Dwarf)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eastern India and Pakistan. Female 10 kg; male 14 kg. A widespread, humid-area, meat goat that is early maturing and very prolific. It kids twice a year, and produces 60 percent twins and 10 percent triplets. It produces a superior leather.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Katjang</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southeast Asia, China, and Pacific Islands. In places, less than 20 kg. A widespread, highly variable, hardy goat adapted to humid conditions, it usually has twins or triplets. Used for meat and skins, with exceptional females being milked.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chinese Dwarf (Tibetan, Jining, Fuyang, or Chengdu Grey)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">China. 20-40 kg. Well adapted to the humid tropics, it normally twins and is a good meat producer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Heuk Yumso</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Korea. Female 25 kg; male 35 kg. A prolific cold-climate goat with a year-round breeding season. The meat is highly prized, and often sells at a premium due to its supposed health-giving effects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hejazi</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Middle East. Female 20 kg; male 20 kg. A meat goat, usually black, for harsh desert conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sinai (Black Bedouin)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sinai, Egypt and Negev Desert, Israel. Female 20 kg; male 50 kg. Native to dry, hot deserts, this milk and meat goat matures at 5-8 months and has a twinning rate over 50 percent. A most important characteristic is its drought tolerance. The female, for instance, can drink only once a day - at a pinch, once every other day - without losing appetite or reducing milk flow. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILD RELATIVES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several wild relatives will cross with the goat. Surprisingly, they have the same chromosome number (2n=60), and the offspring are frequently fertile. Although essentially unknown to agricultural science, these hybrids may offer a new gene pool for creating new farm animals and for improving the world's goats. They seem to combine the self-reliance of wild species with the usefulness of domestic ones. Artificial insemination and other modern techniques could make them easier to produce today than ever before.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ibex*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A project in Israel has already produced a cross between the goat and the Nubian ibex (Capra ibex). The Sinai Desert goat, the breed that was used, ranks next to the camel in its ability to go without water - it often drinks only twice a week - but its meat has such a strong flavor that most people consider it dreadful. On the other hand, the ibex is compact and muscular and produces tender, mild meat that steak lovers find delicious. The product from crossbreeding the two is a creature seemingly able to endure extreme temperatures and drought, make use of poor pasture, and produce wonderful steaks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A herd of several hundred of these hybrids (dubbed 'ya-ez") has been created at Kibbutz Lahav in the northern Negev Desert area. Both sexes are fertile, and they can be bred with each other or with either parent. The meat is already in demand on the menus of elegant Tel Aviv hotels. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Markhor**</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In Pakistan's northern uplands, it is not uncommon to find hybrids between domestic goats and the mountain goat known as "markhor" (Capra falconeri). Each year in Chitral and Gilgit, they can be found in the goat markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Markhors inhabit high elevations in rugged mountains and thrive on diets so meager as to be useless to goats. The hybrids are produced when markhor males - perhaps ousted by more dominant males - come in contact with feral domestic goats. However, some farmers raise young markhor and goats together (to overcome mutual resistance) and produce their own hybrids,</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For a single hybrid animal local goatherds pay up to 5,000 rupees, a princely sum in this impoverished region. Traditionally, villagers have kept them as stud animals. They appreciate the animal's genetic endowment. Markhors tolerate extremes of cold and snow, are nimble and skilled at escaping predators, and survive on scanty fodder, Moreover, they have a high reproduction potential because they generally produce twins. As a result, they also tend to give more milk and it is rich in nutritive value. Instead of long body hairs, markhors possess insulating underfur - a soft and valuable raw material for the famous Kashmiri shawls.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apparently, the hybrids can possess many of these qualities together with a calm disposition. Thus they could be useful in themselves and as conduits for passing such traits on to goats. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">3 Microsheep</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among the hundreds of breeds of sheep (Ovis aries) in the world, those weighing less than 35 kg when mature have been largely ignored. Although these are common, the impression lingers that they are too small to be useful. Yet this virtually untapped gene pool is esnecially well adapted to traditional Third World animal husbandry. Given attention, these "microsheep" could boost meat, milk, skin, wool, and pelt production in many villages and small farms of Africa, Asia, and Latin America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many microsheep thrive in environments that tax the ability of larger breeds to survive. They are adapted to poor feeds and can be grazed in uncultivated wastelands unsuited to any other livestock except goats or camels. Because of their size, microsheep can fatten in areas where forage is so scattered and sparse that larger animals cannot cover enough ground to fill their bellies each day. In addition, their foraging complements that of other livestock. For example, sheep can graze rough grasses and weeds that cattle find unpalatable. Some survive even the stress of extreme aridity and for this reason are the predominant livestock in North Africa and the Middle East.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many small breeds can be disease resistant. Some, for example, are widespread in the zones of Africa where trypanosomiasis is prevalent. They are generally less adversely affected by foot-and-mouth disease than are cattle, and some small native sheep seem to have fewer problems with insects and parasites than do most other livestock, including temperate-area sheep.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giving more attention to the management and improvement of microsheep could pay back abundantly in the form of food, income, and improved land utilization in many parts of the developing world. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide, but notably in drier regions of the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">An average weight for temperate sheep breeds is about 70 kg,' but the smallest microsheep weigh less than 20 kg fully grown. Many tropical microsheep are "hairless," and have little or no wool. These are often difficult to distinguish from goats, but (like all sheep) they generally have blunter snouts, more fat, and hanging tails. Some have greatly enlarged rumps or tails that store fat. Unlike goats, sheep have no odor-producing glands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some representative microsheep are described at the end of this chapter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than one billion sheep occur worldwide, and they occupy every climatic zone in which people live. At least half are in developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although more than 1,000 breeds are recognized, only a handful dominate the world's sheep industries. Lesser-known breeds are rapidly becoming extinct (especially in developed countries, although scattered efforts are being made to preserve them). Elsewhere, genetic resources have not been properly evaluated, and potentially valuable stock is being lost before it is even understood.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep are among the most adaptable animals. Various types are kept in areas of extreme heat, cold, altitude, aridity, humidity, and rainfall. They are especially widespread in hot, dry climates, but some breeds also thrive in humid areas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep make efficient use of a wide variety of fodder: tree leaves, fortes, grasses, crop residues, and agricultural by-products, for instance. They often survive privation by calling on their reserves of body fat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the tropics, sheep reach sexual maturity in about a year. Many breeds lamb year-round, which allows for a continuous production of premium meat. Gestation takes about five months, and lambing is usually timed to occur when feed is most abundant and nutritious. Microsheep often bear two or more young and, under good management, may produce lambs annually for more than five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These shy animals flock together and, in general, are managed with little effort. They are easily panicked, however, and rams can become aggressive during rutting or when threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE LITTLE SHEEP THAT COULD</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dozens of the world's neglected breeds of tiny sheep should be preserved from extinction, for many will undoubtedely prove to have outstanding qualities. Current efforts to save the Navajo sheep in the United States exemplify what can be achieved</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Navajo is a microsheep, and is perhaps the oldest breed of sheep in the United States. It may have been introduced to North America in 1540 by the Spanish explorer Francisco Vazquez de Coronado, who was seeking the mythical Seven Golden Cities of Cibola in the region that is now Arizona and New Mexico. Smaller than many dogs, a full-grown Navajo sheep may weigh only 30 kg, but it became a big part of the culture of the Southwest. Although the Navajos and other local Indians had never seen sheep before the 1500s, they soon became shepherds and weavers, and their rugs made from the unique wool of this wiry little animal remain famous even today.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Navajo sheep have white or brown wool hanging in ringlets around their bodies. The fleece is a double coat: long, coarse guard hairs on the outside and short wool on the inside. It yields warm, waterproof, and long-lasting products. Many of the sheep have four horns because the Indians believed that this trait was sacred, and they favored four-horned rams for breeding purposes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The number of Navajo sheep was reduced sharply between 1950 and 1950 because of severe overgrazing and replacement by improved wool breeds. In recent times there has been so little commercial and scientific interest in this microsheep that by the 1970s only a handful of purebred specimens survived. Since the late 1970s, however, Lyle McNeal, a Utah State University professor, has been working to save it from extinction. By 1988 he had a burgeoning flock at the university and was learning that this supposedly obsolete dwarf is amazingly useful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The breed originated in the arid south of Spain (where it is called the "churro"), and it thrives in the hot, dry climate. Unlike normal breeds, it can exist in the desert without supplementary food and with little water. As McNeal has pointed out, any sheep that can survive and raise a lamb in the aridity and searing heat of the American Southwest has to be superior. He has found that the ewes have a strong maternal instinct, which is vital for protecting lambs against the coyotes that are common in the region. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thanks to the efforts of McNeal and his colleagues, Indians are beginning to use Navajo sheep again; by 1988 there were more than 400 on the Navajo reservation, with their wool fetching premium prices. This tough little sheep could prove valuable not only for American Indians but for poor people in many other dry regions as well. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Microsheep are mainly kept for meat production, but - especially in arid regions - for milk as well. Their meat is usually lean with little "muttony" taste.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wool or hair is taken from many breeds, although the yield is often small. Skins from hair sheep' thinner than cowhide, are widely used and are in international demand. In some places, manure is considered an important product. In Nepal, thousands of small sheep are used as pack animals, especially to carry salt into mountain valleys.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most sheep are maintained in free-ranging flocks. Many are grazed (often tethered) over a small area during the day and confined in a "fold" at night. Others are penned or kept as village scavengers. These are usually fed supplements of household scraps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep form an integral part of a mixed farming economy; for example, they may graze pastures during the wet season, and survive on crop residues and field weeds during the dry season. They have excellent foraging capabilities and are often kept alongside goats. This broadens the variety of forages utilized and often increases total production from a single piece of land, for sheep and goats have complementary feeding habits and male goats help protect the sheep from some predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In spite of the heavy toll that predators (such as feral dogs) can take on lambs and ewes, the largest proportion of sheep in the tropics are lost through lack of basic care. Modest supplemental feeding of lambs and inexpensive preventive medicines can do much to lower mortality and boost production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep are multipurpose animals, and almost everywhere they produce several products. The rich milk is often preferred to that of cows or goats, especially for making cheese and yogurt.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lambs form an important part of the household economy for much of the rural world, and only rarely is social or religious stigma attached to keeping or eating them. Indeed, sheep are the traditional feast animals of several religions, and in some places sheep meat is preferred to beef and sells at a premium.</P>
+<P ALIGN="JUSTIFY">By and large, all sheep products can be processed, utilized, or marketed by the producer. In addition, sheep marketing and transportation systems exist in most countries, at least to some degree.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep are efficient producers and can provide a quick turnover for food and cash. On the brush and coarse grasses of marginal lands, they may be more productive than cattle, and on grass they may outproduce goats. As long as they are not overstocked, sheep do not degrade vegetation; unless starving they will not debark trees. Small breeds cause little erosion, even on steep slopes, heavily traveled paths, or near water holes.2 In South Asia, they have been continuously stocked on the same ground for thousands of years without causing apparent harm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because sheep have a natural tendency to accumulate fat, they "finish" well on grazing and usually do not require a high-energy finishing diet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite their general healthiness, sheep are affected by many internal parasites and diseases, a few of which are communicable to man. They are especially susceptible to infectious conjunctivitis (pinkeye).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Predators and thieves can be greater threats than sickness. Labor inputs can be high because of the almost continual protection sheep need.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some mutton has a strong taste that many find unappealing. However, the taste is carried mainly by the fat, and the generally lean microsheep are often commended for their fine-textured, sweet meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The numerous breeds of small sheep should be investigated. Assessments should be made for the animals' ability to thrive under adverse conditions and for resistance to particular diseases and parasites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, even minimal extension services and veterinary support for sheep could greatly decrease mortality, especially among lambs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improving microbreeds without increasing their size is one of the most interesting challenges facing sheep scientists today. While efforts should be made to conserve and select within types, research should also be conducted on hybrid vigor. Efforts to improve the pelt and fleece of microsheep should also be encouraged.</P>
+<P ALIGN="JUSTIFY">More studies on the interactions between sheep and cropping systems are needed. Sheep (and the manure they produce) could become important components of forestry (see sidebar), crop rotation, alley cropping, and other forms of sustainable agriculture. For instance, sheep are especially effective for weed control in plantation crops such as oil palm and rubber as well as in forests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SMALL SHEEP IN THE FOREST</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Even in countries with long traditions of raising large sheep, there are opportunities for using small, agile, hardy breeds. The following is an example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Seeking safer methods for stopping brush from smothering newly planted trees, U.S. government foresters have turned from chemical defoliants to flocks of sheep. Court decisions in 1983 and 1984 barred the use of herbicides along Oregon's Pacific Coast. Various alternatives were tried, and the animals proved the most successful. Sheep are now the favored method for controlling unwanted vegetation. Indeed, they have changed the foresters' whore approach to managing reforestation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Formerly, the U.S. Forest Service allowed the brush to grow on logged-over sites and then sprayed it down before planting tree seedlings. Now it plants grass to suppress brush and reduce erosion. The sites are later fertilized, tree seedlings are planted, and within a year sheep are brought in to graze. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, in the district around Alsea, Oregon sheep nimbly skirt old stumps to graze on the lush vegetation. Three times each summer since 1984, about 2,000 sheep have been guided across the replanted areas by a herder and a range conservationist. The sheep eat both the grass and the new buds on brush, but they leave most fir-tree seedlings untouched. The key, according to Rick Breckle, a forester, is to have enough sheep to graze an area evenly and to keep them moving so they don't resort to nibbling the young trees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Previously, chemical brush treatments had annually cost $135-$353 per hectare. Now, sowing grass and grazing sheep costs about $300 per hectare. And there is a product to sell: the adult sheep don't fatten well, but the lambs bring a useful income at the end of the summer. What is more, Breckle reports that the trees seem to be growing faster - probably because of the manurings they receive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This method seems likely to be effective elsewhere - at least with trees that are unpalatable or too tall for their growing points to be nibbled. Malaysia, for instance, doubled its sheep population between 1986 and 1989, in part because it has begun raising sheep between the trees in rubber plantations. With the use of agroforestry increasing worldwide, small sheep could find a whole new application.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">REPRESENTATIVE EXAMPLES OF MICROSHEEP</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West African Dwarf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Senegal to Nigeria, and south to Angola. Female 25 kg; male 35 kg. Well adapted to warm, humid conditions. Prolific, and good disease resistance. Major meat producer in West Africa. Fast growing: by six months of age they approach adult weight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Landim (Small East African)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">East and Central Africa. 23-40 kg. Prolific, adaptable, long fat-tailed type. Large litter size for a sheep. In one recent test, ewes averaged more than 1.4 lambs.3 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berber</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Atlas Mountains. 25-41 kg. Needing little feed and remaining constantly outdoors, these extremely hardy sheep are exploited for meat and their coarse, hairy wool. They fatten easily when well fed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arab</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">North Africa. 40-50 kg. This thin-tailed sheep is exceptionally robust, and is resistant to extremes of temperature, drought, and poor nutrition. Primarily a meat producer, its wool is used for coarse cloths and carpets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southern Sudan Dwarf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the many small breeds of eastern and southern Africa, its weight ranges from 15 to 25 kg, but it may weigh as little as 11 kg. Yielding a fine, short fleece, this hardy, frugal sheep is often run with cattle to maximize grazing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hejazi</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Deserts of Arabia. 32 kg. A popular and ancient fat-tailed meat producer that is highly acclimatized to drought and privation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zel (Iranian Thin-Tailed)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caspian region of northern Iran. Female 30-32 kg. Well adapted to subtropical regions, they produce coarse wool, milk, and excellent meat that lacks the "mutton taste" and odor of some sheep meats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Greek Zackel</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mountain and island types. Female 30 kg; male 40 kg. These common sheep are active, hardy, and resistant to extremes of climate and disease. Primarily a milking sheep, their wool is used locally and lambs are slaughtered for special occasions. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sitia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crete. Female 25 kg; male 30 kg. Another of the hardy, screwhorned "zackel" sheep common to the Balkans, they are adapted to poor pasturage and extensive herding. Quick maturing and highly fertile, they can be exploited for milk as well as for meat and coarse wool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Common Albanian</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Female 25 kg; male 35 kg. Similar to the Greek Zackel, they are used as triple-purpose animals: meat, milk, and wool. They survive in low, marshy areas where parasites are common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zeta Yellow</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yugoslavia. Female 25 kg; male 35 kg. A small, hardy sheep used for milk and some meat, its primary product is wool. Often unshorn for several years, the long fibers are woven into expensive carpets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pag</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yugoslavia. Female 20-30 kg; male 25-35 kg. These wool, milk, and meat sheep are frugal and well adapted to scant vegetation and rocky terrain. Although they have a low birth rate and carcass yield, their milk and wool are commercially exploitable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Roccia (Steinschaf)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northern Italy, Austria. Female 30 kg; Male 30-35 kg. These "stone sheep" resemble a goat in their ability to exploit the poor pastures of high, steep, rocky mountains. Although not highly productive, they are hardy and frugal and commonly produce twins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corsican</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corsica (France). 25-30 kg. A hardy native breed that is well adapted to rather sparse feed conditions. Coarse wool, both white and black, is well suited for hand processing. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Entre Douro e Minho</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Portugal. Female 15-18 kg; Male 20-25 kg. These independent sheep yield a good wool in mountainous terrain that would otherwise be nonproductive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Churra do Campo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Portugal. Female 20 kg; male 30 kg. A coarse-woofed sheep extensively kept in Portugal's dry interior for milk and wool. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Galician</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Spain. Female 18 kg; male 25 kg. A milking breed that survives on  poor pasture, it also produces a marketable wool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Soay</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scotland. Female 25 kg; male 30 kg. Adapted to wide temperature  variations. Possibly the most primitive domesticated sheep of Europe,  probably unchanged from Viking times. Immune to foot rot. A wool  sheep with short brown fleece that is shed annually.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">North Ronaldsay (Orkney)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northern Scotland. 27-32 kg. Surviving year-round on seaweed,  this rare breed is adapted to high salt intake and the associated digestive  problems. Yield 1-2 kg medium-coarse wool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Criollo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Latin America. Derived from ''native'' Spanish Churro and Merino  sheep. Many are small and very hardy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Navajo-Churro Southwestern United States. Female 45 kg; male 70  kg. Maternal, and very resistant to internal parasites and hoof rot.  Although the Navajo subsists and reproduces on little feed and scarce  water in desert regions, it was widely replaced by improved breeds  earlier in this century. Because of its hardiness, however, and the use of  its wool in traditional weaving, its numbers are rebounding (see sidebar,  page 50). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Florida Native Southeastern United States. Females 35-45 kg;  males 45-6O kg. This long-isolated and highly variable sheep is  adapted to harsh subtropical climates and is known for its ability to  forage. A medium-wool breed, it is very resistant to intestinal parasites.  Verging on extinction due to neglect and uncontrolled crossbreeding. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Virgin Islands White Hair (St. Croix)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caribbean. Female 35-45 kg; male 45-55 kg. Hair sheep with  some wool in young animals. Well adapted to warm humid conditions, it has fairly good disease and parasite resistance and produces good meat. Prolific, it breeds most of the year and commonly has twins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Magra (Chokhla)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northwest India, Pakistan.4 20-25 kg. Adapted to hot, dry areas, the extremely white and shiny fleece is valued for carpet wool. Slowmaturing and low fertility (lambing at 45 percent) plus extensive crossbreeding have led to serious declines in population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Marwari</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northwest India. 25-30 kg. A widespread, white-fleeced sheep that has a high resistance to disease and worms, good fertility, and low mortality. They do well in large flocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mandya (Bandur)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southwest India. Female 25 kg; male 35 kg. An outstanding meat breed with good mutton quality, it adapts well to mixed farming and has unusually low lamb mortality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hu (Huyang, Lake Sheep)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">China. Female 35 kg; male 45 kg. These fat-tailed sheep have a six month lambing interval and are very prolific. They are used under intensive management to produce meat, wool, and a valuable lambskin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Javanese Thin-Tail</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Indonesia. 25-40 kg. Widely held as a "bank account," these meat, manure, and skin sheep are well known for being prolific. Although single lambs are not uncommon, litters of six have also been recorded. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILD AND WOOLLY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Considering that dozens of countries depend on the productivity of more than a billion domesticated sheep, it is remarkable that their wild ancestor is accorded no attention. This fast-declining animal is now little more than a trophy for hunters, a fact that should be of vital intemational concern.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheep were domesticated in the Middle East and Central Asia in the Stone Age era between 8,000 and 11,000 years ago.* Their wild ancestor was almost certainly the mouflon (Outs orientalis). However, domestication may have occurred in more than one place, and two other wild creatures, the urial (Outs vignei) and the argali (Outs ammon), also possibly provided genes to some sheep breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mouflon, urial, and argali still exist in the mountains of Central Asia, and a European subspecies of mouflon is also found in the Mediterranean, but only on Corsica, Cyprus, and Sardinia.** Because they live in remote, rugged, upland areas, these wild sheep are usually undisturbed, but the numbers are decreasing everywhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This may be a serious loss because these animals could be extremely valuable. They are capable of crossing with domestic sheep, and the offspring are viable and fully fertile.*** For developing new meat-producing breeds, their potential seems almost limitless.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the thousands of years that sheep have been protected by humans, their wild ancestors have continued to face predators, parasites, disease, extreme cold and seasonal starvation. Their genetic endowment, forged and tempered in unforgiving harshness, could be a benefit for all future sheep generations. These animals appear to resist various diseases. Their meat is reported to be of excellent quality, notably lacking the strong mutton flavor that many people find objectionable. They have relatively short, thin tails - a feature that might eliminate the need for docking (tail removal) in the domestic flock. Some (for instance, the Asian mouflon and the urial) have rates of effective reproduction up to 1.6 lambs per ewe, more than twice the average of most domestic types, especially under the conditions where these wild creatures live.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That mouflon and other wild sheep could have practical utility is suggested by research at Utah State University. Scientists there have mated mouflon with farm sheep to create sheep better able to defend themselves against coyotes and other natural dangers. Half-wild, half-tame sheep hybrids have existed on a ranch in southern Utah for the past decade. Also, in Cyprus similar mouflon x sheep hybrids have shown considerable promise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the very least, this wiry little mountain sheep could be a model for educating students and the public. It is a living reminder of the fantastic changes that can be induced in animals by selection for various traits. Also, it is a "map" to the history of sheep domestication. Studies of mouflon genes, blood immunology, morphology, physiology, horn structure, skeleton, fleece, temperament, and a host of other features would help unravel the ancestry. These studies and various biochemical analyses would be a fascinating contribution to agriculture, science, history, and the public perception of the origins of our natural resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Genes from wild sheep are not likely to quickly benefit wool production. Lack of fleece is one reason why these creatures have been neglected but throughout most of Asia and in North Africa, sheep are bred primarily for meat and milk, and there is a growing worldwide interest in the use of hair sheep. All of this brings new possibilities for the use of this old resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">4 Micropigs</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g005a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most breeds of swine (Sus scrofa) are too large to be considered microlivestock, but there are some whose mature weight is less than 70 kg. These micropigs are particularly common in West Africa, South Asia, the East Indies, Latin America, and oceanic islands around the world. At least one, the Mexican Cuino, may weigh a mere 12 kg full-grown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many miniature swine have been developed for use in medical research, but their agricultural potential has been largely ignored. This is unfortunate, for micropigs of all types - native, feral, and laboratory - deserve investigation. Swine provide more meat worldwide than any other animal, and micropigs are potentially important sources of food and income for poor people in many parts of the developing world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Smallness makes for nimble and self-sufficient pigs, in contrast to large, lethargic breeds. Small breeds are easier to manage and cheaper to maintain; the threat of injury from angry or frightened animals is lessened; and the sows are less likely to crush newborn piglets, often a major cause of mortality in large breeds. Some micropigs - particularly those from hot regions or wild populations - also have a higher resistance to heat, thirst, starvation, and some diseases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs adapt to a wide variety of management conditions, from scavenging to total confinement; some are even kept indoors.2 They gain weight quickly, mature rapidly, and help complement grazing livestock because they relish many otherwise unused wastes from kitchens, farms, and food industries, as well as other foods such as small roots, leafy trash, or bitter fruits that are not consumed by humans or ruminants. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For these reasons, micropigs could become useful household and village livestock in the developing world, and they deserve greater attention than they now receive. Although their growth may not be as rapid as that of improved breeds raised under intensive commercial production, with modest care and minimum investment, backyard micropigs can produce sizable yields of meat and other products, as well as improved income for rural and even urban populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide, especially in warm, humid areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like full-sized breeds, micropigs are stout-bodied, short-legged animals with small tails and flexible snouts ending in flat discs. Examples of some micropigs are listed at the end of the chapter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic pigs are found all over the world, but their concentrations vary greatly. Africa has the fewest per capita, but in recent years they have gained increasing favor in the sub-Saharan regions. In Latin America, pigs have long been a major component of backyard agriculture. In the Middle East, an early center of domestication, pigs are not widely kept today because of religious dietary restrictions. In the Ear East, they are the major meat source, and China has more pigs than any other country. And in the Pacific region, pigs and chickens are often the only meat available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are becoming more popular: their worldwide numbers increased by about 20 percent in the 1970s. However, in most countries commercial pig production has focused on a mere handful of breeds, and much genetic diversity is unstudied or even threatened with extinction. Some microbreeds have already been lost, and others are dwindling in numbers.3 Many European breeds have been completely lost. The Cuino and some other Latin American criollo types are threatened, as are most of Africa's traditional breeds. China, however, has made notable efforts to preserve its native types. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although, as previously noted, pigs are found all over the world, they are in general adapted to warm, humid climates where many other livestock species are more susceptible to diseases and environmental stresses. They are also raised at high altitudes, such as in the Andes and Tibet. Although there are few climatic limitations to pig production, only about 20 percent of the world's pigs are currently kept in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are omnivores, willing and able to eat almost anything.4 Unlike most other livestock, they eat their fill and sleep as the food digests, allowing humans to establish a convenient eating and sleeping schedule.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are prolific; a few Chinese breeds routinely have litters of 20 or more. Micropigs are no exception; litters of 6-10 are common. Piglets gain weight rapidly and can be weaned after a few weeks. Sexual maturity is sometimes attained as early as 4-6 months, depending on breed and environment. Pigs are usually slaughtered at 67 months of age, allowing them to be produced on an annual cycle. They can live 10-20 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of their smaller size, micropigs have a relatively greater skin-to-weight ratio than today's commercial breeds, and therefore they probably shed heat more effectively. Certainly they seem to perform better in tropical heat and humidity, which normally keep the heavier types from reaching their maximum productivity. Studies have suggested that an optimal size for some tropical environments - because of metabolic and feed efficiency - may be less than 65 kg.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are social animals; they enjoy companionship and ferociously defend their young and sometimes even the humans who care for them. They are employed as guard animals in some areas and have been used extensively in behavioral research.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contrary to common belief, pigs are clean and tidy if provided adequate space. Larger breeds, however, wallow in mud to stay cool in hot weather and require a wallow or shade (except for some Latin American types, which seem less susceptible to heat). Some lightcolored pigs sunburn easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs will dig up earth with their mobile snouts; some breeds do it constantly. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fresh pork is the major pig product in tropical areas. It usually fetches premium prices, and in many places (such as the Pacific Islands and China) it is the most important red meat available to rural people. Nutritious and tasty, it is one of the easiest meats to preserve, needing only salt or melted fat. Processed products such as bacon and sausages can be important for both home consumption and cash sales.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pig fat (lard) is a good source of food energy, and can substitute for cooking fats and oils. It is easily melted and clarified, is widely used to make soap, and is a valuable commercial product.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pig skin, once degreased, is easily tanned into leathers that are popular for garments, shoes, and other products demanding soft, light, and flexible leathers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pig manure is a good fertilizer. Because the animals are often kept in confinement, it can be easily collected.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In many places, pigs are kept as free-roaming scavengers. They can be trained (by coaxing with feed, salt, or affection) to keep close to home, thereby helping to minimize destructive scavenging.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Herding is a higher level of management that requires more effort, but it allows pigs to be integrated into other types of agriculture while utilizing feeds that otherwise go to waste.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because their exercise needs are minimal and dominance is quickly established within litters, pigs are the easiest hoofed livestock to raise in small enclosures (sties). However, fencing must be secure, and if sties are small, the animals must be moved frequently to prevent diseases and parasites from building up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are well-known, often traditional, animals in many areas, and people usually do not have to be taught how to manage and use them. Efficient scavengers, they can live, grow, and reproduce with a minimum of investment or specialized care. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs are highly efficient converters of feed to meat. They can provide the greatest return for the least investment of any hoofed livestock because of their fecundity, low management costs, broad food preferences, and rapid growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs normally accumulate fat during adolescent growth (making ''finishing" feeds less necessary). Some micropigs (especially those from feral ancestors) have the ability to quickly mobilize and store these body-fat reserves; in times of extreme scarcity, it aids their survival.6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigs work well in multiple-cropping schemes. They are often used to help clear small plots by uprooting weeds, shrubs, and even small trees. In Southeast Asia, they are frequently raised in conjunction with aquaculture, their manure providing food for the fish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If improperly managed or maintained in filthy conditions, pigs may quickly succumb to disease and parasite epidemics. Most diseases are communicated only among pigs, but some can be transmitted to humans. For this reason, pork should always be fully cooked.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some cultures never eat pork. Others do, but nonetheless accord pigs and their keepers low status.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young pigs are vulnerable to many predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A major survey of small pig breeds is needed. They have the potential to be valuable producers in their own right, as well as to improve other pig breeds. For instance, they represent a little-known reservoir of disease resistance and climatic adaptation. Governments, research stations, universities, and individuals should make special efforts to preserve types that have outstanding or unusual qualities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When it is necessary to eradicate feral pig populations (as is common on Pacific islands), representative stocks should be preserved. These rugged animals have been genetically isolated for decades or even centuries and are likely to carry valuable traits for survival under adversity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Large breeds may be promising candidates for genetic "downsizing," which has already produced the many types of miniature pigs that are used in medical research. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE LITTLEST PIG</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although this chapter highlights the world's smallest breeds, there exists a pig that is even smaller. It is, however, an entirely different species and it is on the brink of extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pigmy hog (Sus salvanius) is a shy and retiring wild creature of northeastern India. It is merely 60 cm long with a shoulder height of 25 cm, and weighs less than 10 kg. It was once found widely along the southern foothills of the Himalayas. Today, however, it apparently occurs in only one area, the Manas National Park in Assam. Despite this protection and the fact that it is listed among the 12 most endangered species on earth, it still falls victim to hunters and to habitat destruction - especially illegal grass fires.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If saved from extinction, this minute species - barely reaching a person's calf - might become useful throughout the world. Its chromosome number is the same as that of the common pig and its physiological processes are probably also similar. Therefore, were its numbers to be built up, it might become a valued and well-known resource for laboratories and small farms. Its daily food intake and its space requirements are only a fraction of a normal pig's. It probably has exceptional tolerance to heat, humidity, and disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is not a domesticated species, and there is therefore much to learn before its usefulness can be clearly seen. Indeed, whether it can be reared in captivity is uncertain. Some attempts have ended in disaster, but this seems to have been the result of mismanagement.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before there is any possibility of developing it, however, the pigmy hog must be preserved from ultimate loss. The last specimen could go into a villager's pot at any time now. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g006a.png"></center><br>
+ Adult male of the common pig (wild boar) and pigmy hog draw to same scale. (W.L.R. OLIVER)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">REPRESENTATIVE EXAMPLES OF MICROPIGS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West African Dwarf (Nigerian Black, Ashanti)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">West Africa. Mature weights of 25-45 kg are reported. In the humid lowland forests of West Africa this breed has long been kept by villagers, often as a scavenger. Indigenous to the hot, humid tsetse zones of West Africa, it seems resistant to trypanosomiasis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chinese Dwarfs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">China (and Southeast Asian countries such as Vietnam) has long had small pigs - often characterized by numerous teats and large litters - associated with traditional intensive agriculture as well as scavenging conditions. Some Chinese pigs weighing less than 70 kg are adapted to tropical and subtropical conditions, but the smallest (20-35 kg) live in the cold climates and high altitudes of Gansu, Sichuan, and Tibet. Small black Chinese pigs were crossed with European types in the early 1800s and produced the foundation stock of many modern Western breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Criollo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are a number of "native" breeds throughout Latin America commonly known as "criollo." Many are quite small. Although, apparently, they are slow to mature and bear small litters, they adapt well to environmental extremes and are widely kept by rural inhabitants for food and income. Criollos are little studied and are being replaced by imported breeds before their possibly outstanding qualities can be quantified.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cuino This micropig from the highlands of central Mexico may be descended from small Chinese types and is the smallest domestic pig, weighing as little as 10-12 kg fully grown. Hardy and an efficient scavenger, it can grow quickly when feed - especially corn - is abundant. A century ago the cuing was a widespread household animal and was used for a time for experimental work in central Mexico. It is now little known and could be threatened with extinction. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black Hairless (felon, Tubasqueno, Birish) These small pigs of central and northern South America survive in hot, humid, adverse climates. They are adapted to bulkier feeds than most pigs and can thrive on fruit wastes. Many local types exist. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nilo (Macao, Tatu, Canastrinha) This small, widespread, black, hairless pig of Brazil is often kept inside the house. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yucatan Miniature Swine A subtype of the black hairless from Mexico's hot, arid Yucatan Peninsula, it was imported into the United States in 1960. It has been downsized for laboratory use in the United States and is known as the Yucatan Micropig (registered). Weight at sexual maturity has been lowered through selective breeding from 75 kg to, currently, between 30 and 50 kg, with an ultimate goal of 20-25 kg. There is no evidence of "dwarfism," stunting, or loss of reproductive performance, and it appears to hold notable promise as microlivestock for developing countries. The parent stock, used for meat and lard production in Yucatan, is renowned for gentleness, intelligence, resistance to disease, and relative lack of odor. Exceptional docility, even in older boars and sows with litters, makes them easy to handle without the need for specialized housing or equipment.7 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Laboratory Breeds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other miniature laboratory pigs have potential for tropical use. These include the Goettingen, Hanford, Kangaroo Island, Ohmini, Pitman-Moore, and Sinclair (Hormel). In general they weigh 30-50 kg when ready for slaughter and mature at less than 70 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ossabaw</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United States. 20-30 kg. Feral on Ossabaw Island, South Carolina, for more than 300 years, this pig is well adapted to environmental extremes. Unlike most domestic animals, it can maintain itself in coastal salt marshes. It has perhaps the highest percentage of fat of any pig. The piglets are very precocious, self-reliant, and robust.8</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kunekune (Pua'a, Poaka)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Zealand. Female 40 kg; male 50 kg. Perhaps of Chinese origin, these black-and-white spotted pigs are docile, slow, and easy to contain. Although late maturing, they can fatten on grass alone. Like other native breeds throughout the Pacific region (for example, the Pauta of Hawaii), stock is being lost through crossbreeding, displacement by other breeds, and eradication efforts. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To find certain disease-resistant genes in poultry it may be necessary to go looking in the backyard chicken flocks in Latin America, Africa, or Asia.</P>
+<P ALIGN="JUSTIFY">Kelly Klober</P>
+<P ALIGN="JUSTIFY">Small Farmer's Journal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">. . . Policies are needed to encourage development of a labor-intensive small-scale livestock sector, which would increase employment and provide a major market for surplus cereals. This sector, however, is particularly restrained by poor technology, poor public support services, and poor marketing channels. Third World livestock production of this type could provide a natural focus for foreign assistance that earlier seemed inappropriate because of concerns about global food scarcity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John W. Mellor International Food Policy Research Institute</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Successful development of agriculture often requires an intimate understanding of the society within which it is to take place - of its systems of values, of its customary restraints.... It has been necessary to understand what incentives the farmer needs to change, what practical difficulties he encounters introducing change, what his traditional pattern of land use is and how this pattern or system can be upset by thoughtless innovation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John de Wilde</P>
+<P ALIGN="JUSTIFY">Experience with Agricultural Development in Tropical Africa </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part II : Poultry</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g007a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens, ducks, muscovies, geese, guinea fowl, quail, pigeons, and turkeys epitomize the concept of microlivestock. Throughout Africa, Asia, and Latin America they are (collectively) the most common of all farm stock. In many - perhaps most - tropical countries, practically every family, settled or nomadic, owns some kind of poultry. In the countryside, in villages, even in cities, one or another species is seen almost everywhere; in some places, several may be seen together. Although raised in all levels of husbandry, these birds occur most often in scattered household flocks that scavenge for their food and survive with little care or management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Their size bestows microlivestock advantages, including low capital cost, low food requirements, and little or no labor requirements. They are also "family sized": easily killed and dressed, with little waste or spoilage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These poultry species help meet the protein needs of the poorest people in the world. Some are raised even in areas where domestic cattle cannot survive because of afflictions such as trypanosomiasis and foot-and-mouth disease. Some are maintained under conditions of intensive confinement - provided a source of feed is available - and can be produced in areas with insufficient land for other meat-producing animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, these birds grow quickly and mature rapidly. (For instance, a chicken can, under proper conditions, reach maturity in 26 months.) They adapt readily to being fenced or penned much, or all, of the time. And, compared with the major farm livestock, their life cycles are short and their production of offspring is high. Thus, farmers can synchronize production to match seasonal changes in the availability of feed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although poultry contribute substantially to human nutrition in the tropics, it is a small fraction of what it could be. The meat is widely consumed and is in constant demand. An excellent source of protein, it also provides minerals such as calcium, phosphorus, and iron, as well as the B-complex vitamins riboflavin, thiamine, and niacin. Nutritionally as complete as red meat, it is much lower in cholesterol and saturated fats. Poultry eggs are also important sources of nutrients. They are a renewable resource, easy to prepare, and are among the best sources of quality protein and vitamins (except vitamin C).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In spite of their numbers and potential, poultry are rarely accorded primary consideration in economic development activities. All in all, these small birds lack the appeal of large, four-legged livestock. Indeed, most countries have little knowledge of the contribution household birds actually make to the well-being and diets of their peoples. In some countries - even those where birds are widely kept - there is little or no poultry research or extension. And where such programs do exist they usually focus almost exclusively on the production of chickens under "industrial" conditions near cities (see sidebar, page 75).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most developing countries now have these intensive chicken industries, in which birds are kept in complete confinement. However, these commercial operations provide food for people in the cash economy, not for subsistence farmers. Moreover, grain is sometimes diverted or imported to maintain these operations, perhaps causing food shortages, higher prices, or depleted foreign exchange. Thus, in this section we focus on other, neglected, aspects of poultry production.,</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The neglect of poultry that scavenge around the rural farmhouses and in village yards is understandable. The birds are scattered across the countryside where extension programs are difficult to implement. Their presence is often so ingrained in traditional village life that they are taken for granted and ignored by the authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet village poultry deserve greater attention. As converters of vegetation into animal protein, poultry can be outstanding. In fact, it is estimated that, in terms of feed conversion, eggs rank with cow's milk as the most economically produced animal protein, and that poultry meat ranks above that of other domestic animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most Third World poultry flocks live a wary, half-wild existence, scrounging for insects, earthworms, snails, seeds, leaves, and leftovers from the human diet. From dung and refuse piles they salvage undigested grains, as well as insects and other invertebrates. Often the persons who care for them are women or children. Some keep the birds around the house, penning them at night for protection from predators and thieves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This almost zero-cost production has, in spite of high losses, a remarkable rate of return. Any improvements that require the purchase of supplies cut severely into the profitability. The first step in improving the production of free-ranging poultry is vaccination against diseases (especially Newcastle disease, fowl pox, and Marek's disease) and a modest, supplemental feeding during times of seasonal scarcity. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE INDUSTRIAL CHICKEN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Throughout modem livestock farming the trend is toward more intensive methods, and poultry specialists have set the pace. In many countries, since the 1920s, barnyard fowl have given way to egg and broiler factories. The old-fashioned chicken reared outside on corn stubbles for 5 or 6 months has been replaced by the broiler, mass-produced in controlled environment houses in 7 - 10 weeks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As a result of this revolution in poultry raising, small farmers who once made a comfortable living from a few laying hens have been forced out of business. These economic changes have also forced poultry men to have larger and larger flocks to survive. The largest broiler-chicken companies even control their own breed development, feed production, house construction, slaughtering, and freezing, many even have wholesale outlets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The rapid changes in poultry farming methods can be attributed to the application of advanced technology. The development of the incubator to replace the mother hen sitting her seasonal clutch of eggs was the first mayor step toward intensive poultry farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, chickens were the first livestock to receive serious attention from geneticists. Before World War II, it was discovered that crossbreeding selected pure and inbred lines could result in dramatic increases in production. Hybrids tailor-made for egg or meat production quickly ousted the old pure breeds such as the Rhode Island Red White and Brown Leghorns, Light Sussex, and the various crosses among them. Chicken broilers made by crosses involving parents derived from Cornish and Plymouth Rock have supplanted all others.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This situation now prevails in most industrialized countries. The breeding of commercial stocks is in the hands of a few corporations for each commodity (white eggs, brown eggs, chicken broilers, turkeys) and each has national or even global distribution of its hybrid stocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A BREAKTHROUGH IN POULTRY HEALTH</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Newcastle disease is endemic in developing countries and is a constant threat to poultry. Farmers dread this virus, first identified half a century ago in northern England that brings diarrhea, paralysis, and death to most poultry. It is severe, highly contagious, and can cause 100 percent mortality. When it strikes an area, farmers must kill all chickens - even healthy ones - to stop it from spreading.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only Australia, New Zealand, Northern Ireland and some Pacific islands are unaffected. But, although the disease is not found in Australia, certain strains of the virus are present in Australian chickens. These strains are completely harmless, but Australian researchers have found that they induce antibodies that are effective against Newcastle disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a joint project (funded by the Australian Centre for International Agricultural Research), scientists from Malaysia's University of Agriculture and Australia's University of Queensland* have put this to good use. They have produced a live culture of the harmless virus that farmers can spray onto feed pellets to vaccinate their birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Field tests of the new vaccine, carried out in Southeast Asia, have been extremely promising. Simply coating feeds with the virus seems to be enough to immunize some chickens, which then pass the immunity on to the others in the flock as well as to new hatchlings. In Malaysia, which has 49 million chickens and a population willing to pay a premium for tasty village poultry meat, one economist estimates that the vaccine might increase rural incomes by 25 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conventional vaccines must be stored under refrigerated conditions, which most villages lack. But the Malaysian workers made the Newcastle disease vaccine tolerant of heat. By selective breeding, they now have strains that resist 56&Yacute;C for at least 2 hours. Thus, even in the tropics, the vaccine remains effective for several weeks without refrigeration. The researchers have also devised methods for coating the vaccine onto pelleted feeds. Because the virus can withstand heat, they use a machine designed for coating pharmaceutical tablets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At this stage, the project is showing every promise of producing a cheap means of reducing Newcastle disease losses among chickens throughout much of the world. Already inquiries have come from other Asian countries and from Africa, and it is hoped that the vaccine may eventually benefit many countries. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">5 Chicken</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g008a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens (Gallus gallus or Gallus domesticus)1 are the world's  major source of eggs and are a meat source that supports a food  industry in virtually every country. There may be as many as 6.5 billion  chickens, the equivalent of 1.4 birds for every person on earth.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No other domesticated animal has enjoyed such universal acceptance,  and these birds are the prime example of the importance of  microlivestock. Kept throughout the Third World, they are one of the  least expensive and most efficient producers of animal protein.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To the world's poor, chickens are probably the most nutritionally  important livestock species. For instance, in Mauritius and Nigeria more  than 70 percent of rural households keep scavenger chickens. In  Swaziland, more than 95 percent of rural households own chickens,  most of them scavengers. In Thailand, where commercial poultry  production is highly developed, 80-90 percent of rural households still  keep chickens in backyards and under houses. And in other developing  countries from Pakistan to Peru, a similar situation prevails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Clearly, these chickens should be given far more attention. They  represent an animal and a production system with remarkable qualities;  they compete little with humans for food; they produce meat at low  cost; and they provide a critical nutritional resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scavenger chickens are usually self-reliant, hardy birds capable of  withstanding the abuses of harsh climate, minimal management, and inadequate nutrition. They live largely on weed seeds, insects, and feeds that would otherwise go to waste.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, however, quantitative information about the backyard chicken is hard to obtain. Few countries have any knowledge of its actual contribution to the well-being and diet of their people. Notably lacking is an understanding of the factors limiting egg production, which is markedly low and perhaps could be raised dramatically with modest effort.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens are so well known and ubiquitous that they need no further description. Varying in color from white through many shades of brown to black, they range in size from small bantams of less than 1 kg to giant breeds weighing 5 kg or more. Scavenger chickens tend to weigh about I kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The indigenous chickens of Asia are probably descended directly from the wild junglefowl. Those of West Africa are believed descended from European birds brought by the Portuguese in the sixteenth century; those of Latin America probably descend from Spanish birds introduced soon after the time of Columbus.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p81a.png"></center><br>
+ figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All countries have chickens in large numbers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are not endangered, but industrial stocks are replacing traditional breeds to such an extent that much potentially valuable genetic heritage is disappearing. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although chickens derive from tropical species, they adapt to a wide  variety of environments. The modern Leghorn, for example, is found  from the hot plains of India to the frozen tundra of Siberia, and from  sea level to altitudes above 4,000 m in the Andes. (There are, however,  hatching problems at such high altitudes because of oxygen deficiency.)  They also occur in desert countries such as Saudi Arabia, which has a  vast poultry industry and even exports broilers. (However, the birds  need shade and a lot of water where it is hot and dry.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens are omnivorous, living on seeds, insects, worms, leaves,  green grass, and kitchen scraps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A commercial bird may produce 280 eggs annually, but a scavenger  may produce close to none. Commonly, a farmyard hen lays a dozen  eggs, takes three weeks to hatch out a brood of chicks, stays with the  chicks six weeks or more, and only then starts laying again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Egg production depends on daylength. For the highest production  rate, at least 12 hours of daylight are needed. The incubation period is  21 days. A hen can begin laying at 5 months of age or even earlier, but  in scavengers it may be much later. The average weight of the eggs is  approximately 55 g from industrial layers and approximately 40 g from  scavengers. Hatching success from breeder flocks often exceeds 90  percent. Industrial broilers can be marketed as early as 6 weeks, when  they are called "Cornish hens."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These passive, gregarious birds have a pronounced social (pecking)  order. If acclimated, they remain on the premises and are unlikely to go  feral. If given a little evening meal of "scratch," they learn to come  home to roost at night.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens have multiple uses. They were probably first used for cock  fighting; later they were used in religious rituals, and only much later  were raised for eggs and meat. Today, chickens can provide a family  with eggs, meat, feathers, and sometimes cash.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In different parts of the world, people keep scavenging chickens in  different ways. The managers are often women and children because  they have more time to spend at home to feed the birds and repel  predators. Some people leave the birds entirely to their own devices.  Many house them at night. Others take the birds each day to the fields,  where they may find much more food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are many ingenious local practices. In Ghana, for example,  farmers "culture" termites for poultry by placing a moist piece of cow  dung (under a tin) over a known termite nest. The termites burrow into  the dung, and some can then be fed to the chickens each day. Because  termites digest cellulose, this system converts waste vegetation into  meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A ratio of 1 male to 10-15 females is adequate for barnyard flocks.  Hens will lay eggs in the absence of a rooster - but of course the rooster  is needed if fertile eggs are wanted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Removing chicks stimulates the hen to lay more eggs. This results in  more chicks being hatched, but it requires that the chicks be nurtured  and fed until they are old enough to fend for themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Chickens are everywhere; every culture knows them and how to  husband them. They have been utilized for so many centuries that in  most societies their use is ingrained. Unlike the case with pork and beef,  there are few strictures against eating chicken meat or eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The meat is high in quality protein, low in fat, and easily prepared. In  many countries, the village chicken's meat is preferred to that of  commercial broilers because it has better texture and stronger flavor.  Even in countries with vast poultry industries there is a growing demand  for the tasty, "organically grown," free-ranging chicken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chickens are more suited to "urban farming" than most types of  livestock and can be raised in many city situations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds are conveniently sized, easily transported alive, and, by and  large, do not transmit diseases to humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Throughout Asia, Africa, and Latin America, the problems of village  chickens are mainly those discussed below.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">High Hatching Mortality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Commonly, a hatch of eight or nine village chicks results in only two  or three live birds after a few days. A survey in Nigeria, for instance,  showed that 80 percent died before the age of eight weeks. Losses  elsewhere are known to be similar. This is mostly because of starvation,  cold, dehydration, predators (hawks, kites, snakes, dogs, and cats, for  example), diseases, parasites, accidents, and simply getting lost - all of  which can be prevented without great effort.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chronic and Acute Disease</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Poultry diseases can become epidemic in the villages because there  are few if any veterinarians. Newcastle disease, fowlpox, pullorum  disease, and coccidiosis, for example - all of which are endemic in the  Third World - can destroy the entire chicken population over large  areas. Lice and other parasites are also prevalent. Scavengers and  industrial birds seem to show no differences in their tolerance for such  diseases and parasites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Low Egg Production</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A survey in Nigeria showed that the annual production per hen was  merely 20 eggs. Such low production is common throughout the Third  World and is caused by a combination of low genetic potential,  inadequate nutrition, and poor management. Villagers rarely provide nest  boxes or laying areas, so that some eggs are just not found. Some birds  have high levels of broodiness, and eggs accumulating in a nest  stimulates this. There are indications, however, that some village  chickens (for example, some in China) have quite substantial egg-laying  potential when provided with adequate feed.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Low Egg Consumption</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the tropics, many people choose not to eat eggs. Often this is  because eggs are the source of the next generation of chickens;  sometimes it is because of superstition. Further, eggs do not keep well  because most are fertile and, exposed to constant tropical heat, undergo  rapid embryo development.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crop Damage</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">It is often necessary to confine the birds to protect young crops or  vegetable gardens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Unlike the situation with small cattle, goats, sheep, and pigs, there are  few named and recognized breeds of Third World chickens. Yet, nearly  every country has at least one kind of village chicken. These have  survived there for centuries and are highly adapted to local conditions.  In village projects, these unnamed chickens deserve priority attention  before other types are sought from elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Generally speaking, improving the production of scavenging poultry  does not require sophisticated research. Instead, simple precautions are  sufficient. These are discussed below.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Disease Control</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">At a national or regional level, the initial approach to increasing  chicken production in tropical areas should be disease control. There are  several outstanding instances of success in this endeavor. For example,  the spectacular rise of poultry production in Singapore (from 250,000  birds in 1949 to 20 million in 1957) followed the control of Ranikhet  disease. Village flock-health programs, carried out regularly by visiting  veterinarians ("barefoot veterinarians"), might be the answer to some of  the routine health problems. Today, a prime target should be Newcastle  disease, for which there are good chances for success (see page 76).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Management</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The first step in chicken production at the farm level is improved  management. With more care and attention, mortality can be greatly  reduced. Because incubating and brooding hens must spend the night on  the ground, they are extremely vulnerable. Even modest predator  controls can be highly beneficial. Building crude and inexpensive nest  boxes and constructing a simple holding area around them can  substantially raise production by ensuring that more chicks survive.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE CHICKEN'S WILD ANCESTOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although little known to most people, the red junglefowl has  contributed more to every nation than any other wild bird. It is  the ancestor of the chicken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given its descendants importance worldwide, the neglect of  this bird is baffling. If the cow's wild ancestor, the aurochs, had  not become extinct in the 1600s, it would now be worth millions  of dollars as the ultimate source of cattle genetic diversity. Yet  the world's chicken industry remains virtually unaware of the  origin of its source of livelihood.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the aurochs, the red junglefowl has a wealth of wild  genes, and it deserves more recognition and protection. For one  thing the modern chicken - selectively bred in the temperate  zone - is highly susceptible to heat and humidity; the junglefowl,  on the other hand, is not. It inhabits the warmest and most humid  parts of Asia: Sri Lanka, India, Burma, Thailand, and most of  Southeast Asia. It may also be resistant to various chicken  diseases and pests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is not a rare species. Throughout the wide crescent  stretching from Pakistan to Indonesia, junglefowls are still seen  in the wild, especially in forest clearings and lowland scrub.  Although they are a prized bag for hunters, they survive by fast  running and agile flying. They are sometimes sold in village  markets, but can easily be mistaken for domesticated chickens,  which in this region are often very similar. The wild junglefowl,  however, has feathered legs, a down-curving tail, and an overall  scragginess.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Junglefowls should be under intensive study. They are easy to  rear in captivity and do well in pens, even small ones, as long as  they are sheltered from rain and wind. One drawback is their  craze for scratching unless provided plenty of space they  promptly tear up all grass and dirt. Another is that junglecocks  are violent fighters and must be kept apart. (Cockfighting is  probably a major reason why they were initially selected, and  thus their aggressiveness is perhaps the reason we have the  chicken today.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These highly adaptable creatures live in a variety of habitats,  from sea level to 2,000 m. Most, however, are found in and  around damp forests, secondary growth, dry scrub, bamboo  groves, and small woods near farms and villages. They are  amazingly clever at evading capture and thrive wherever there is  some cover.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other junglefowl species might also provide useful poultry.  They, too, can be raised in captivity with comparative ease, as  long as the cocks are kept apart. Perhaps they might be tamed with imprinting and could prove useful as domestic fowl,  especially in marginal habitats. They are everywhere considered  culinary luxuries and their meat commands premium prices.  Moreover, several have colorful feathers, giving them additional  commercial value. These other species are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- La Fayette's Junglefowl (Gallus lafayettei). Avery attractive  bird of Sri Lanka, it is little known in captivity, and only in the  United States are there any number in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Gray or Sonnerat's Junglefowl (Gallus sonnerati). A native  of India, this colorful bird produces feathers that are used in  tying the most prized trout and salmon flies. Demand is so great  that certain populations have declined, and since 1968 India has  banned all export of birds or feathers. Nonetheless, there are  several hundred in captivity in various countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Green Junglefowl (Gallus varius). This is yet another striking  bird. The cock has metallic, greenish-black feathering set off by  a comb that merges from brilliant green at the base to bright  purple and red at the top. Native to Java, Bali, and the  neighboring Indonesian islands as far out as Timor, it is found  particularly near rice paddies and rocky coasts. This species, too,  can be raised without great difficulty, and there are at least 90 in  captivity in various parts of the world.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nutrition</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Improving poultry nutrition is also of prime importance. There are no quantitative data on the quality of a scavenging chicken's diet. Surveys are badly needed so that appropriate, low-cost supplements can be devised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chances are that the diet for chicks of scavenging poultry is almost always deficient in available energy. Minimal supplementation in the form of cereals or energy-rich by-products can greatly improve both egg and meat production. However, caution must always be exercised and the supplements given only to chicks. Overfed adults will give up scavenging and stay around the owner's house, without really producing much more meat or eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Genetic Improvement</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although it seems attractive to replace the scrawny village chicken with bigger, faster-growing imported breeds, it is a process fraught with difficulty. Exotic breeds lack the ability to tolerate the rigors of mismanagement and environmental stress. Many cannot avoid predators, as a result either of being overweight or of having a poor conformation for flight. The local birds, however, probably have a genetic potential that is much higher than can be expressed in the constraining environment. Thus, the environmental constraints should be tackled first.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, the village birds may have a feed-conversion efficiency that is far less than ideal because they are adapted to a scavenging existence. Modern breeds imported into Ghana, for instance, showed a feed-conversion efficiency of less that 3.5:1 (weight of food eaten: growth and eggs), but the local birds had efficiencies of 11:1.4 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The need for preserving genetic variability is greater in poultry, especially in chickens, than in any other form of domestic animal. North America, for instance, which years ago had 50 or more common breeds, now relies on only 2 for meat production, and the others have been largely lost. Conservation of germplasm has become a matter of serious concern, and the saving of rare breeds in domestic fowl should not be delayed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE SOUTH AMERICAN CHICKEN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Early European explorers of South America were surprised to discover an abundance of unusual chickens that laid colored eggs and had feathers resembling earrings on the side of the head. While the origin of this bird - commonly called the araucanian chicken and classified as Gallus inauris - is debatable, scientists generally agree that it is pre-Columbian. There is archeological evidence that this bird is native to the Americas. It is reported to have occurred in Chile, Ecuador, Bolivia, Costa Rica, Peru, and Easter Island. It still occurs in the wild in southern Chile and on Easter Island.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The araucanian has been called the "Easter-egg chicken" because it lays light green, light blue, and olive colored eggs. It lays well and has a delicious meat. In areas such as southern Chile the eggs are preferred over those of normal chickens because of their flavor and dark yellow yolk. This unusual bird has a high degree of variability; however, specimens of similar genetic background have been grouped to create "breeds" such as the White Araucanian, Black Araucanian, and Barred Araucanian. These are homozygotes and breed true.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The araucanian has been the subject of much public interest,. clubs dedicated to its preservation have been formed in the United States, Great Britain, and Chile. Its possible exploitation as a backyard microlivestock deserves serious consideration. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">6 Ducks</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g009a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic ducks (Anas platyrhynchos)1 are well known, but still have much unrealized promise for subsistence-level production. Although a major resource of Asia, where there is approximately one duck per 20 inhabitants, they are not so intensively used elsewhere. On a worldwide basis, for instance, they are of minor importance compared with chickens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is unfortunate because ducks are easy to keep, adapt readily to a wide range of conditions (including small-farm culture), and require little investment. They are also easily managed under village conditions, particularly if a waterway is nearby, and appear to be more resistant to diseases and more adept at foraging than chickens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, the products from ducks are in constant demand. Some breeds yield more eggs than the domestic chicken. And duck meat always sells at premium. A few recently created breeds (notably some in Taiwan) have much lower levels of fat than the traditional farm duck. This development could open up vast new markets for duck meat, especially in wealthy countries, where consumers are both concerned over fat in their diet and eager for alternatives to chicken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks are also efficient at converting waste resources - insects, weeds, aquatic plants, and fallen seeds, for instance - into meat and eggs. Indeed, they are among the most efficient of all food producers. Raised in confinement, ducks can convert 2.4-2.6 kg of concentrated feed into I kg of weight gain. The only domestic animal that has better feed conversion is the broiler chicken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raised as village birds and allowed to forage for themselves, ducks become less productive but become even more cost effective because much of the food they scavenge has no monetary value. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Several distinctive types have been developed in various regions. Most have lost the ability to fly any distance, but they retain a characteristic boatlike posture and a labored, waddling walk. The Indian Runner, however, has an almost erect stance that permits it to walk and run with apparent ease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic ducks range in body size from the diminutive Call, weighing less than I kg, to the largest meat strains (Pekin, Rouen, and Aylesbury, for example) weighing as much as 4.5 kg. For intensive conditions, the Pekin is the most popular meat breed around the world. In confinement it grows rapidly - weighing 2.5-3 kg at a market age of 78 weeks. In addition, it is hardy, does not fly, lays well, and produces good quality (but somewhat fatty) meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Khaki Campbell breed is an outstanding egg producer, some individuals laying more than 300 eggs per bird per year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Taiwan Tsaiya (layer duck) is also a particularly efficient breed. It weighs 1.2 kg at maturity, starts laying at 120-140 days, and can produce 260-290 eggs a year. Its small body size, large egg weight, and phenomenal egg production make Brown Tsaiya the main breed for egg consumption in Taiwan. More than 2.5 million Brown Tsaiya ducks are raised annually for egg production.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The domestic duck is distributed throughout the world; however, its greatest economic importance is in Southeast Asia, particularly in the wetland-rice areas. For example, about 28 percent of Taiwan's poultry are- ducks. In parts of Asia, some domestic flocks have as many as 20,000 birds. One farm near Kuala Lumpur, Malaysia, rears 40,000 ducks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although ducks are abundant, some Western breeds are becoming rare. Indigenous types are little known outside their home countries and have received little study, so their status is uncertain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These adaptable creatures thrive in hot, humid climates. However, during torrid weather they must have access to shade, drinking water, and bathing water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks are well adapted to rivers, canals, lakes, ponds, marshes, and other aquatic locations. Moreover, they can be raised successfully in estuarine areas. Most ocean bays and inlets teem with plant and animal life that ducks relish, but (unlike wild sea ducks) domestic breeds have a low physiological tolerance for salt and must be supplied with fresh drinking water. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Ducks search for food underwater, sieve organic matter from mud, root out morsels underground, and sometimes catch insects in the air. Their natural diet is normally about 90 percent vegetable matter (seeds, berries, fruits, nuts, bulbs, roots, succulent leaves, and grasses) and 10 percent animal matter (insects, snails, slugs, leeches, worms, eels, crustacea, and an occasional small fish or tadpole). They have little ability to utilize dietary fiber. Although they eat considerable quantities of tender grass, they are not true grazers (like geese), and don't eat coarse grasses and weeds at all. Sand and gravel is swallowed to serve as "grindstones" in the gizzard.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When protected from accidents and predation, ducks live a surprisingly long time. It is not unusual for one to continue reproducing for up to 8 years, and there are reports of exceptional birds living more than 20 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite large differences in size, color, and appearance, all domestic breeds interbreed freely. Eggs normally take 28 days to incubate, brooding and rearing is performed solely by the female.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Depending on breed, a female may reach sexual maturity at about 20 weeks of age. Most begin laying at 20-26 weeks, but the best egg- laying varieties come into production at 16-18 weeks and lay profitably for 2 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">It is generally well known that ducks are shy, nervous, and seldom aggressive towards each other or humans. Skilled and enthusiastic swimmers from the day they hatch, they spend many hours each day bathing and frolicking in any available water. However, most breeds can be raised successfully without swimming water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although wild ducks normally pair off, domestic drakes will mate indiscriminately with any females in a flock. In intensively raised flocks, I male to 6 females, and in village flocks, 1 male for up to 25 females, results in good fertility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most domestic ducks, particularly the egg-laying strains, have little instinct to brood. If not confined, they will lay eggs wherever they happen to be - occasionally even while swimming. To facilitate egg collection, some keepers confine ducks until noon. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY"><center><img src="p96a.png"></center><br>
+ Figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As a meat source, ducks have major advantages. Their growth rate is phenomenal during the first few weeks. (Acceptable market weights can be attained under intensive management with birds as young as 6-7 weeks of age.) Yet, even in older birds, the meat remains tender and palatable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eggs from many breeds are typically 20-35 percent larger than chicken eggs, weighing on average about 73 g. They are nutritious, have more fat and protein, and contain less water than hen's eggs. They are often used in cooking and make excellent custards and ice cream. Eggs incubated until just before the embryos form feathers produce a delicacy known as balut in the Philippines. Salted eggs are popular in China and Southeast Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Feathers and down (an insulating undercoat of fine, fluffy feathers) are valuable by-products. Down is particularly sought as a filler for pillows, comforters, and winter clothing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks have a special fondness for mosquito and beetle larvae, grasshoppers, snails, slugs, and crustaceans, and therefore are effective pest control agents. China, in particular, uses ducks to reduce pests in rice fields.3 Its farmers also keep ducks to clear fields of scattered grain, to clear rice paddy banks of burrowing crabs, and to clear aquatic weeds and algae out of small lakes, ponds, and canals. This not only improves the conditions for aquaculture and agriculture, it also fattens the ducks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In Southeast Asia, droving is a traditional form of duck husbandry, much as it was in medieval Europe. The birds are herded along slowly, foraging in fields or riverbanks as they march to market. The journey might cover hundreds of kilometers and take as long as six months.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This process, however, is generally declining, and most ducks are raised under farm conditions where they scavenge for much of their feed. Throughout Southeast Asia, ducks have been integrated with aquaculture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks can be raised on almost any kitchen wastes: vegetable trimmings, table scraps, garden leftovers, canning refuse, stale produce, and stale (but not moldy) baked goods. However, for top yields and quickest growth, protein-rich feeds are the key. Commercial duck farms rely on such things as fish scraps, grains, soybean meal, or coconut cake. Agricultural wastes such as sago chips, palm-kernel cake, and palm-oil sludge are being used in Malaysia.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks have a very high requirement for niacin (a B vitamin). If chicken rations are used, a plentiful supply of fresh greens must be provided to avoid "cowboy legs," a symptom of niacin deficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Of all domestic animals, ducks are among the most versatile and useful and have multiple advantages, including:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Withstanding poor conditions;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Producing food efficiently;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Utilizing foodstuffs that normally go unharvested;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Helping to control pests; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Helping to fertilize the soil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Also, they are readily herded (for instance, by children).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Excellent foragers, they usually can find all their own food, getting by on only a minimum of supplements, if any. Raising them requires little work, and they provide farmers with food or an income from the sale of eggs, meat, and down.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks can grow faster than broiler chickens if they have adequate nutrients. Like guinea fowl and geese, they are relatively resistant to disease. They also have a good tolerance to cold and, in most climates, don't need artificial heat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">DOMESTICATING NEW DUCKS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Many species of ducks adapt readily to captivity; it is surprising, therefore, that only the mallard and the muscovy have been domesticated so far. Several wild tropical species seem especially worth exploring for possible future use in Third World farms, Because of the year-round tropical warmth, their instinct to migrate is either absent or unpronounced, and the heavy layer of fat (a feature of temperate-climate ducks that consumers in many countries consider a drawback) is lacking. Moreover, because of uniform daylength, they are ready to breed at any time of the year. Candidates for domestication as tropical ducks include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Whistling ducks (Dendrocygna species). These large, colorful, gooselike birds are noted for their beautiful, cheerful whistle.* They are long-necked perching ducks that are found throughout the tropics. By and large, they are gregarious, sedentary, vegetarian, and less arboreal than the muscovy - all positive traits for a poultry species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The black-bellied whistling duck (D. auturunalis) seems especially promising. It is common throughout tropical America (southwestern United States to northwestern Argentina) and is sometimes kept in semicaptivity. Occasionally, in the highlands of Guatemala, for instance, Indians sell young ones they have reared as pets. When hand reared, the birds can become very tame. * * They eat grain and other vegetation, require no swimming water, and will voluntarily use nest boxes. In the wild, they "dump" large numbers of eggs so that even if substantial numbers were removed for artificial hatching, the wild populations should not be affected.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Greater wood ducks (Cairina species). The muscovy (C. moschata) was domesticated by South American Indians long before Europeans arrived (see page 124). Its counterparts in the forests of Southeast Asia and tropical Africa are, however, untried as domesticates. The white-winged wood duck (C. scutulata) is found from eastern India to Java. Hartlaub's duck (C. hartlaubi) occurs in forests and wooded savannas from Sierra Leone to Zaire. Both are rare in captivity, but might well prove to be future tropical resources. Both are strikingly similar to muscovies in size and habits, being large, phlegmatic, sedentary, and omnivorous. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Predators are the most important cause of losses in farm flocks. Ducks are almost incapable of defending themselves, and losses from dogs and poachers can be high. Locking them in at night both protects the birds and prevents eggs from being wastefully laid outside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ducks do suffer from some diseases, mainly those traceable to mismanagement such as poor diet, stagnant drinking water, moldy feed or bedding, or overcrowded and filthy conditions. Of all poultry, they are the most sensitive to aflatoxin, which usually comes from eating moldy feed. They are also susceptible to cholera (pasteurellosis) and botulism, either of which may wipe out entire flocks. Duck virus enteritis (duck plague) and duck virus hepatitis also can cause severe losses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If not carefully managed, ducks can become pests to some crops, especially cereals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, ducks tend to be extremely poor mothers and can be helped by using broody chicken hens or female muscovies as surrogate mothers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Major limitations to large-scale, intensive production are mud, smell, and noise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Defeathering ducks is much more difficult than defeathering chickens because of an abundance of small pinfeathers and down feathers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These birds already function so well that no fundamental research needs to be done. Nonetheless, there are a number of topics that could improve their production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For example, different types of low-cost systems need to be explored and developed. These must be low-input systems since cash is a limiting factor for most subsistence farmers. One possibility is the integration of duck and fish farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A survey of all breeds is needed to determine their status and likelihood of extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One need in countries that already have ducks is to encourage the consumption of duck meat. Indonesia, for instance, has 25 million egg-producing ducks, but little duck meat is consumed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research on economically significant diseases is needed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">7 Geese</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g010a.png"></center><br>
+ Brown Chinese Geese</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although geese (Anser spp.) were one of the first domesticated animals, they have yet to receive the level of commercial or industrial exploitation of chickens or even ducks. Thus, their global potential is far greater than is generally recognized today.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic geese are easily managed and well suited to small-farm production; they are among the fastest growing avian species commonly raised for meat, and they have immediate application in many developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These birds are especially appropriate for providing farmers a supplemental income. With little extra work they supply nutritious meat, huge eggs, and rich fat for cooking, as well as soft down and feathers for bedding and clothing. Moreover, their strident voices sound the alarm when strangers or predators approach. They are especially well suited to aquatic areas and marshy lands and are completely at home in warm shallow waterways. Nevertheless, they can thrive away from water. In fact, wherever pasture is available geese readily adapt to captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese are grazers, and can be raised almost exclusively on pasture. They are excellent foragers, and on succulent grass can find most or all of their own food. With their powerful bills they pull up grasses and underwater plants and probe soil and water for roots, bulbs, and aquatic animals. Their long necks make them adept at gleaning weeds from hard-to-reach places - such as fence rows, ditches, and swampy areas that baffle larger livestock. They will also feast on vegetable trimmings, garden and table leftovers, canning refuse, and stale baked goods. Like other poultry, they pick up shattered grains of rice, wheat, barley, and other crops, which can reduce the bothersome problem of weeds volunteering in subsequent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese are available worldwide. In most climates, they require little or no housing. Given reasonable care and protection from predators, mortality can be extremely low. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic geese come in an assortment of colors, sizes, and shapes. There are two main types, however. Descendants of the wild greylag goose (Anser anser) make up the domestic breeds common in North America and Europe, including the Embden, Toulouse, Pilgrim, American Buff, Pomeranian, Sebastopol, and Tufted Roman breeds. These are generally best suited to temperate climates. On the other hand, descendants of the wild "swan goose" (Anser cygnoides) make up the geese of Asia, including the Chinese and "African" types. These breeds seem better suited to hot climates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to these, many European and Asian countries have their own local breeds and types, and there are even several wild species that show some potential for captive production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With their long legs and webbed toes, geese are equally at home walking or swimming. Avid walkers, they march long distances to find forage, but return home at dusk. Accomplished and graceful swimmers, geese are able to take to water soon after they hatch. Despite their large size, some domestic breeds - especially the leaner ones - have retained the ability to fly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Geese are found worldwide, but goose farming is nationally important only in Asia and Central Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic geese are not threatened, although much local variation among the breeds is being lost.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most geese adapt well to hot climates - as long as some shade is available. Their waterproof feathers help them adapt well to high rainfall regions. They also tolerate extreme cold. (For instance, in Canada, geese are wintered outdoors in subfreezing temperatures, with merely 'e simple shelter from wind.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For tropical developing countries, the Chinese type, which is widely kept in Southeast Asia, is especially promising. Smaller than most geese (although ganders can weigh over 5 kg), they are the best layers, the most active foragers (making them economical and useful as weeders), the most alert and "talkative," and they produce the leanest meat. Some European breeds, such as Embden and Toulouse, have also been used in the tropics with notable success. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DOMESTICATING GEESE</P>
+<P ALIGN="JUSTIFY">(Temperate Zones)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Today's domestic geese are descended from two species: the greylag (Anser anser) and the swan goose (Anser cygnoides). These were domesticated in Europe and China, respectively. Their domestication occurred in ancient times, long before people knew about genetics, microorganisms, veterinary science, or behavior modifications such as imprinting. Today, armed with such knowledge, more geese may be amenable to domestication. Most of the 15 other wild species adapt to captivity. Compared to most birds, geese spend much time walking and swimming and are less inconvenienced by pinioning (removing the tip of the wing). Thus, they can be kept outdoors rather than in cages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both of the ancestors of today's domestic geese are native to the northern temperate zone. Two more wild species that might make useful domesticates are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Canada goose (Branta canadensis). North America. People feeding these birds in city parks and wildlife refuges are causing many local flocks to develop. These birds no longer migrate. They are increasing in numbers each year and are well on the way to de facto domestication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- American swan goose (Coscoroba coscoroba). Southern South America. Although most closely allied to swans in shape and physiology, this bird resembles a muscovy (see page 124) in size and behavior. Its calm disposition, as well as its attractive red feet and bill that accent its white plumage, have made it much sought as an ornament for parks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In its diet, the goose utilizes large quantities of tender forage. It can break down plant-cell walls and digest the contents. Although it has no crop for storing food, there is an enlargement at the end of the gullet that serves as a temporary storage organ. Sand and small gravel are swallowed to aid the gizzard in grinding hard seeds and fibrous grasses. Research has shown that geese can digest 15-20 percent of the fiber in their diet, which is 3-4 times the amount that other poultry species can digest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The natural diet consists of grasses, seeds, roots, bulbs, berries, and fruits, normally supplemented with a little animal matter (mainly insects and snails) picked up incidentally. Most feeding takes place on land. They characteristically feed for prolonged periods, even at night.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Females may lay for 10 years or more. It is generally believed that reproduction is best in the second year and that it remains good until the fifth year. Geese outlive other types of poultry; life spans of 1520 years are common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The eggs incubate in 27-31 days. The incubation time is more variable than in most poultry species, perhaps because geese have not been subjected to the selection pressure that is imposed by artificial incubators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">One of the most intelligent birds, the goose has a good memory and does not quickly forget people, animals, or situations that have frightened it. While personalities and habits vary among individual specimens, there are common behavioral patterns, such as the pecking order, that allow individuals to live peaceably together.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unless conditions are crowded or there are too many males, geese normally live harmoniously both with themselves and with other creatures. The bond between male and female is strong. Changing mates is difficult, although most geese will eventually accept a new mate after a period of "mourning."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese nest on the ground and prefer the water's edge, but they adapt readily to man-made nesting boxes. The gander usually stands guard while the goose incubates the eggs. He then assists in rearing the goslings. Most geese become irritated if intruders approach their nest or goslings, and will even attack people and large dogs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As previously noted, these birds provide meat, eggs, fat, and down. The meat is lean, flavorful, and of outstanding quality. The fat accumulates between the skin and the flesh and can be rendered into a long-lasting oil. The eggs are large and taste much like chicken eggs. The "down" (the small, fluffy feathers that lie next to the body of adult birds) is the finest natural insulating material for clothing and bedding, and can fetch a premium price. Worldwide markets exist for both down and other goose feathers. In France, in particular, some geese are raised for their livers (foie gras).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese can control many types of aquatic weeds in shallow water as well as grass and some types of palatable broad-leaf weeds on the banks of lakes, ponds, and canals. They can also be used as ''lawn mowers" and "weeders" among cotton, fruit trees, and other crops (see sidebar).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Elongated necks not only allow geese to reach many different foods, they also help them keep a watchful eye on the surroundings. With their exceptional eyesight they can see great distances, and the position of the eyes gives them a wide field of vision. Geese are among the most alert of all animals, and strangers cannot calm them into silence. In the high Andes, in Southeast Asia, and in many other locations, they replace guard dogs. In Europe, they are used to guard whiskey warehouses and sensitive military installations (see page 111).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Methods of caring for adult geese vary according to climate, breed, and people's experiences and needs. Overall, however, the birds cause little trouble and require little expense. They range freely without restriction, feeding themselves and returning home of their own accord. They have strong flocking instincts and can readily be herded from one area to another.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like all young poultry, goslings are fragile. The highest mortality is caused by predators. Until the goslings are 6-10 weeks old, it is prudent to confine the parents and their young at night in a secure pen or building.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese are the only domestic fowl that can live and reproduce on a diet of grass. They cannot remain healthy on coarse dry fodder, but when grass is succulent they need little else other than drinking water. Many legumes also make excellent goose forage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the tropics, eggs can be laid year-round. The production seldom exceeds 40 eggs per year, although with feed supplement and simple management, the Chinese breed may yield more than 100 eggs. Geese go broody quickly. To break up broodiness, the goose can be confined for 4 6 days away from, but in sight of, the ganders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goslings grow rapidly and can reach market size as early as 10-12 weeks; most geese, however, are marketed at 20-30 weeks of age, when they may weigh from 5 to 7 kg, depending on type and breed. Some young birds (also called green or junior geese), force-fed for rapid growth, are marketed at 4-6 kg when they are 8-10 weeks old.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If fed a good diet to maximize growth and if slaughtered at, say, 10 weeks, the Embden, Chinese, or African will have a carcass low in fat. However, the carcass normally has much more fat than other poultry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese must have a constant supply of reasonably clean drinking water during daylight hours. Although swimming water is not necessary, it promotes cleaner and healthier birds because they find it easier to care for their plumage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DOMESTICATING GEESE</P>
+<P ALIGN="JUSTIFY">(Tropics)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Geese of the tropics have seldom if ever been considered for domestication, but they might provide poultry of considerable value. Presumably they are more heat tolerant and lack the layers of subcutaneous fat (which the ancestors of today's geese needed for warmth in the Arctic). They might thus produce lean birds that would fetch premium prices because excessive fat is the major drawback of today's commercial geese. Examples of tropical species that might be domesticable are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Egyptian goose (AIopochen aegyptiacus). Found throughout the African tropics, this bird is already partly domesticated. However, it is bad tempered and quarrelsome and, so far, this has limited its utility. It has therefore been kept only under semidomestication, without intensive breeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Nene (Branta sandvicensis). A native of the Hawaiian Islands, this is one of the most endangered species on earth. So few specimens are in existence that farming enterprises cannot now be envisaged. Yet, should this bird prove amenable and suitable, the possibility of an economic future could boost efforts to build up its now meager populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Bar-headed goose (Anser indicus). India and Central Asia. These smallish geese are handsome, dainty, and have a musical horn-like call. They have distinct black bars across the nape, which gives them their popular name. Hand-reared specimens breed well in captivity. Despite heavy hunting they are still abundant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Northern spur-winged goose (Plectropterus gambensis gambensis). Tropical Africa (Senegal to Zimbabwe). This large bird is a ground nester, but it has long bony spurs on the wings that enable it to easily protect its eggs and young from predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Semipalmated (magpie) goose (Anseranas semipalmata). Australia and New Guinea. One of the most aberrant and primitive of all waterfowl, this long-legged sturdy-billed bird has only partially webbed feet. It perches high in trees and has a loud ungooselike whistling call. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE WADDLING WORK FORCE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Because geese relish grasses and shun most broad-leafed plants, some enterprising U.S. farmers in the 1950s began using them to rid cotton fields of grassy weeds, which are difficult to kill with herbicides. The geese were put into the fields as soon as the crop came up. A brace of birds kept an acre of cotton weeded; a gaggle of 12 would gobble as many weeds as a hard-working man could clear with a hoe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This method of clearing fields was so effective that by 1960 more than 175,000 geese honked their way across the carefully tended farmland, mainly in the Southwest. Seven days a week, rain or shine, the feathered field hands slaved uncomplainingly from daybreak to dusk, even putting in overtime on moonlit nights. Many toiled so diligently that they worked themselves out of a job.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The geese cleared the fields more cheaply than hoe hands. They left the crop untouched and ate only the succulent young weeds. They did not damage crop roots (as hoes or tractors can), and they were safe and selective, unlike many herbicides. On top of all that they spread fertilizer for the farmer, and ultimately provided him meat for the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eventually, farmers found that geese could be used to weed nearly all broad-leafed crops: asparagus, potatoes, berry fruits, tobacco, mint, grapes, beets, beans, hops, onions, and strawberries, for example. Geese were used in vineyards and fruit orchards to eat both weeds and the fallen fruits that could otherwise harbor damaging insects. They were employed in fields producing trees for the forest industry and flowers for florists shops. Some growers turned goslings loose in cornfields to consume the "suckers" (cone, after all, is a grass) as well as the grain left on the ground. This eliminated the problem of corn as a weed when different crops were later planted in those fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the 1970s when cotton acreage dropped and herbicides selective for the troublesome grasses were developed, the use of geese declined. But today, some organic farmers are returning to the practice. From February to June in the Pacific Northwest, fields are resounding once more to the old-fashioned racket of White Chinese geese. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Mature geese are independent creatures. When kept in small flocks and allowed to roam the farmyard or field, they require less attention than any other domestic bird with the possible exception of guinea fowl. In areas where grass is green for much of the year, they can be raised on less grain or concentrated feed than any other domestic fowl.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Durability is one of their most attractive features. Along with ducks, geese seem to be the most resistant of all poultry to disease, parasites, and cold or wet weather. They also do well in hot climates as long as drinking water and deep shade are available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Growth is not only rapid, it is also efficient. If managed properly, goslings can produce I kg of body weight for every 2.25-3.5 kg of concentrated feed consumed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese are not usually thought of as prolific layers. However, as noted, some strains of the Chinese breed will yield well over 100 eggs per goose per year. At 140-170 g per egg, that compares favorably with the output of laying chickens. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p112a.png"></center><br>
+ figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These birds are messy and their loud trumpeting is often irritating. However, unless they have been teased or mistreated or if they are nesting or brooding young, they are not aggressive. But kilo for kilo, they are stronger than most animals, and a harassed or angry adult can express its displeasure effectively with powerful bill and pounding wings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Excessive concentrations of geese on ponds or along creeks encourages unsanitary conditions, muddies water, hastens bank erosion, and destroys plant life. Where sanitation is poor, salmonellosis can devastate geese and be transmitted, via meat and eggs, to humans. Coccidiosis and gizzard worm are other infections.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Defeathering geese is more difficult than plucking chickens because there are two coats (feathers and down) to remove.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some situations, geese may need a diet supplement (such as grain) if they are grazing vegetation exclusively. A balance must be struck: too much supplement and they will quit foraging and become too fat; too little and they grow slowly and may suffer malnutrition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese are not fully mature until two years of age. Their overall reproductive rate, therefore, is lower than that of other poultry. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Poultry researchers worldwide should begin studies to clarify the role that geese could play in helping to feed Third World nations. Studies might include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Management practices for tropical areas;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Breeding and management for increased egg production;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Incubation techniques;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Nutrition supplementation (for example, vitamins, minerals, energy, specific amino acids) needed by grazing geese;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Physiology of digestion and reproduction;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Clarifying the inheritance of various traits;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Genetic selection for specific meat, eggs, growth factors, or disease resistance;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Comparative studies of the relative efficiency (especially of feed utilization) of the various types and breeds for specific climates in underdeveloped countries;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Weeding tropical crops with geese; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Studying diseases and cross-infection with other birds. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">8 Guinea Fowl</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g011a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For Third World villages, the guinea fowl (Numida meleagris) could become much more valuable than it is today. The bird thrives under semi-intensive conditions, forages well, and requires little attention. It retains many of its wild ancestor's survival characteristics: it grows, reproduces, and yields well in both cool and hot conditions; it is relatively disease free; it requires little water or attention; it is almost as easily raised as chickens and turkeys; and it is a most useful all-round farm bird.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guinea fowl's potential to increase meat production among hungry countries should be given greater recognition. The birds are widely known in Africa and occur in a few areas of Asia, but they show promise for use throughout all of Asia and Latin America and for increased use in Africa itself. Strains newly created for egg and meat production in Europe - notably in France - show excellent characteristics for industrial-scale production. Also, many semidomestic types in Africa deserve increased scientific assessment as scavenger birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meat from domestic guinea fowl is dark and delicate, the flavor resembling that of game birds. It is a special delicacy, served in some of the world's finest restaurants. Several European countries eat vast amounts. Annual consumption in France, for example, is about 0.8 kg per capita.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea fowl also produce substantial numbers of eggs. In Africa, these are often sold hard-boiled in local markets. In the Soviet Union, they are produced in large commercial operations. In France, guinea fowl strains have been developed that not only grow quickly but lay as many as 190 eggs a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Outside Europe, virtually all guinea fowl are raised as free-ranging birds. These find most of their feed by scratching around villages and farmyards. Their cost of production is small, and they yield food for subsistence farmers. In Europe, on the other hand, most are raised in confinement, with artificial insemination, artificial lighting, and special feeding. In the main, this is to produce meat for luxury markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea fowl production is beginning to increase all over the world. During the last 20 years, for example, many of Europe's chicken farmers and breeders, wishing to diversify, have switched to this bird. The United States is now studying ways to establish industrial production, and both Japan and Australia are increasing their flocks. Nonetheless, there is still a vast untapped future for this bird.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide. This species is robust and resilient and adapts to many climates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea fowl are somewhat larger than average scavenger-type chickens: adults weigh up to 2.5 kilograms. They have dark-grey feathers with small white spots. Their heads are bare with a bony ridge (helmet) on top, which makes them look something like vultures. The short tail feathers usually slope downwards.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The chicks, known as "keels," resemble young quail. They are brown striped with red beaks and legs. The sexes are indistinguishable until eight weeks of age. After that, the males' larger helmets and wattles and the cries of the different sexes can be identified. Both sexes give a one-syllable shriek, but females also have a two-syllable call.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the chicken, the guinea fowl is a gallinaceous species and possesses the characteristic sternum with posterior notches and a raised "thumb."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among domestic types are pearl, white, royal purple, and lavender. Pearl is the most common, and is probably the type first developed from the wild West African birds. Its handsome feathers are often used for ornamental purposes. The white is entirely white from the time of hatching and has a lighter skin. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p117a.png"></center><br>
+ figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Europe dominates industrial production. France, Italy, the Soviet Union, and Hungary all raise millions of guinea fowl under intensive conditions, just as they raise chickens. Elsewhere, guinea fowl have become established as a semidomesticated species on small family farms. Native flocks are found about villages and homes in parts of East and West Africa, and free-ranging flocks can be seen in many parts of India, notably Punjab, Uttar Pradesh, Assam, and Madhya Pradesh. During the slavery era, they were introduced from Africa to the Americas to be used for food. In Jamaica, Central America, and Malaysia, the birds have reverted to the wild state and are treated as game.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea fowl are abundant; in most places even wild populations are not threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea fowl are native to the grasslands and woodlands of most of Africa south of the Sahara where they occupy all habitats except dense forests and treeless deserts. Being native also to temperate South Africa, they appear to have an inherent adaptability to both heat and cold. However, in cool climates, regardless of daylength, they will not begin egg production until temperatures exceed 15&Yacute;C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea fowl accept many foods: grains, leaves, ant eggs (for which they will tear anthills open), and even carrion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Normally, they lay their first egg at about 18 weeks of age. Unlike many wild birds, which produce a single clutch a year, guinea hens lay continuously until adverse weather sets in.2 Free-range "domestic" guinea hens lay up to 60 eggs a season. And well-managed birds under intensive management lay close to 200. The eggs weigh approximately 40 g. Shells are stronger than those of chickens and are usually brown, but can be white or tinted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guinea hen goes broody after laying, which can be overcome by removing most of the eggs. A clutch of 15-20 is common. The incubation period is 27 days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These birds never become "tame," but neither do they leave the premises. Although they stray farther than chickens do, they always return. They like to hide their eggs in a bushy corner, often in hollows scratched in the ground. They can fly, although even in the wild they do not fly far. They prefer to roost on high branches and (unless pinioned) can be hard to catch during the day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although wild guinea fowl live in groups, they are monogamous by nature and tend to bond in pairs. However, in domestication a single male may serve four or more females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, guinea fowl are valuable sources of both meat and eggs. They can also be used to control insect pests on vegetable crops.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea fowl are good "watch animals"; they have fantastic eyesight, a harsh cry, and will shriek at the slightest provocation. Their agitation on sighting dogs, foxes, hawks, or other predators have saved the lives of many a chicken, duck, and turkey. They are brave and will attack even large animals that threaten them.4 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea fowl can be kept in confinement using the methods for raising battery chickens. In this system, breeding stock are housed in cages and artificially inseminated. It gives the best egg production and fertility but requires housing, equipment, and skilled labor.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These birds can also be kept in a semidomestic state in and around the farmyard. In such cases they are penned until they are 12 weeks old. Unaccustomed to foraging for natural food, they constantly return to their artificial food supply. Eventually, however, they learn to subsist by scavenging.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds have been called "the worst parents in the world," and are almost incapable of looking after their keets.5 Because the females are such indifferent mothers, the eggs are best hatched in incubators or under other birds, to avoid the keets' being lost by their natural mothers. In many African countries, eggs are hatched under chickens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Keets are often kept indoors until they are 3-4 weeks old to protect them from predators and wet weather. Sexual maturity can be delayed to as late as 32 weeks of age by holding the birds in windowless housing and controlling the lighting. This improves egg size and hatchability and reduces early mortality. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">GUINEA FOWL AND THE ANCIENTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The earliest reference to guinea fowl can be found in murals in the Pyramid of Wenis at Saqqara in Egypt, painted about 2400 B.C. Aviaries were quite fashionable at the time, and wealthy landowners maintained guinea fowl within their walled gardens. A thousand years later, by the time of Queen Hatshepsut (about 1475 B.C.), the junglefowl (the ancestor of the chicken) had arrived, and from then on it was raised on a substantial scale. Records of this period refer to "walk-in" incubators, constructed of mud bricks and heated by cameldung fires. The largest could hold up to 90,000 eggs (mainly from junglefowl but some from guinea fowl) and hatching rates of up to 70 percent were claimed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By 400 B.C., guinea fowl were well established on farms in Greece. Later, they rose to importance in ancient Rome. Pliny the elder (in his Natural History, published 77 A.D.) stated that they were the last bird to be added to the Roman menu and that they were in great demand, both eggs and flesh being considered great delicacies. The emperor Caligula offered them as sacrifices to himself when he assumed the title of deity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guinea fowl then died out in Europe but was reintroduced by the Portuguese navigators returning from their African explorations in the late 1400s. They gave it the name pintada or "painted chicken" and this changed to pintade in French, while the name "Guinea fowl" (fowl from Africa) stayed in English, and gallina de Guinea in Spanish. Coincidentally, guinea fowl and turkeys were both introduced to England between 1530 and 1550, and the English, smitten with the original French misnomers, were left sorting out "Ginny birds" and "Turkey birds" for the remainder of the century. Both birds were adopted with great enthusiasm, and within 150 years they had utterly displaced the peafowl and swan as the major table birds for festive occasions.</P>
+<P ALIGN="JUSTIFY">Adapted from R.H.H. Belshaw, 1985 Guinea Fowl of the World</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Compared with the farmyard chicken the guinea fowl's advantages are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Low production costs;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Premium quality meat;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Greater capacity to utilize green feeds;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Better ability to scavenge for insects and grains;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Better ability to protect itself against predators; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Better resistance to common poultry parasites and diseases (for example, Newcastle disease and fowlpox).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Surprisingly, this semidomestic bird, which has been farmed for centuries, retains the characteristics (feather morphology, hardiness, social behavior) of its wild ancestor - even when subjected to the most modern intensive-rearing methods employing battery cages and artificial insemination. Thus, it thrives under semicaptive conditions and needs little special care. The birds forage well for themselves and do not require much attention; their meat is tasty and they produce substantial numbers of eggs. Unlike chickens, they don't scratch to get insects out of the soil, so they are less destructive to the garden.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In backyard production the guinea fowl is supreme, but when produced intensively it costs more to raise than chickens. In Europe, for instance, day-old keets cost about twice as much as day-old broiler chicks. (The major reason is that guinea fowl produce fewer hatching eggs and require a longer feeding period.) Guinea fowl are also more expensive to feed. Their feed conversion (for meat production at the marketing age) is about 3.3-3.6 as compared with a broiler's feed conversion of 1.8-1.9. Moreover, guinea fowl take about twice as long to reach marketable size: they are marketed for meat at age 12-14 weeks, compared with 7-8 weeks for the broilers. Therefore, the selling price of guinea fowl in the Western world is up to twice that of broilers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea fowl are nervous and stupid. They can be difficult to catch' and when panicking they can easily suffocate their keets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are susceptible to some of the common diseases of chickens and turkeys. Salmonella is the most prevalent, but others are pullorum disease, staphylococcus, and Marek's disease. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE GUINEA FOWL'S WILD COUSINS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The domesticated guinea fowl is descended from just one subspecies of the family's seven known species and numerous subspecies. Some of the others may also have promise as poultry. They, too, generally occur in flocks in bushy grasslands and open forests in Africa. All feed on vegetable matter such as seeds, berries, and tender shoots, and on invertebrates such as slugs. They rarely fly except to roost. They acclimatize well are easy to maintain in captivity, and can survive long periods away from water.** Their disposition is tame and nonaggressive, and they mix well with other birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild subspecies closely related to the domestic guinea fowl that might make future poultry in their own right include the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Gray-breasted guinea fowl (Numida meleagris galeata). This subspecies is the principal ancestor of domestic guinea fowls. It is found throughout West Africa and probably has many valuable genetic traits. There is much variation in the size and other characteristics among the various individuals. People along the Gambia, Volta, and Niger rivers have long traditions of breeding these birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Tufted guinea fowl (Numida meleagris meleagris). This subspecies is quite large and has black plumage thickly spotted with white dots. It is the probable ancestor of the birds reared in ancient Egypt and in the Roman empire (see page 120). Hill farmers in the southern Sudan sometimes breed them in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Mitred guinea fowl (Numida meleagris mitrata). Probably the most popular game bird in East Africa, this type has a bright blue-green head and red wattles. It was once a common sight in the wild but it has now been decimated by overhunting. It is now most numerous in the Masai lands of Kenya and Tanzania. It has been kept in a semidomesticated form in Zanzibar for several centuries. Zoos and aviaries around the world have imported it, and it has bred well for them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild guinea fowl that are different species from the domestic one but that are still worth considering as potential poultry include the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Black guinea fowl (Phasidus niger or Agelastes niger). This bird of the tropical rainforests of West and Central Africa is the size of a small chicken. It has sooty black plumage, a naked head, and a pink or yellow neck. It is seldom hunted because the meat tastes dreadful but this is probably because of a particularly pungent fungus they eat in the forest. Raised on fungus-free forages, these birds are probably very palatable. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Crested guinea hen (Guttera spp.). Three species. These strange-looking birds have a thick mop of inky black feathers above their black, naked faces. Widely distributed in the thickly forested areas of sub-Saharan Africa. Unlike the other species, they prefer the rainforest. They have a musical trumpeting call. At least one species has bred well in Europe. For example, a flourishing colony has been established in the Walsrode Bird Park in Germany.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Vulturine guinea fowl (Acryllium vulturinum). The largest of all guinea fowl, this species is found in parts of Ethiopia, Somalia, and East Africa. One of the most striking looking of all birds, its head is bare and blue, its body black with white spots, and its breast bears long bright cobalt-blue patches on either side. This has been reared as an aviary bird in both Europe and America and might make a useful domesticate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agencies involved in international economic development should undertake guinea fowl assessment trials, evaluations, and coordinated introductions to stimulate programs for small farmers and for industries in dozens of countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeders have been working to improve guinea fowl only since the 1950s. There is a need for more information on growth rate, health, egg production, feed conversion, body weight, carcass yield, laying intensity, fertility, hatchability, and egg weight - especially under free-ranging conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Husbandry research should also be directed towards feeds and feeding systems for growing and breeding stock. Other efforts are needed to increase the hatchability of eggs under natural conditions (under guinea hens or surrogate mothers), and to identify the best lighting regimes (both sexual maturity and rate of lay are influenced by changes in daylength).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guinea fowl that has become an important domesticated bird throughout the civilized world is descended from just one of seven known species in the family. These birds generally occur in flocks in bushy grasslands and open forest in Africa and Madagascar, and some of the others may also have promise as poultry (see sidebar opposite). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">9 Muscovy</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g012a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The muscovy (Cairina moschata), a unique ducklike species of the South American rainforest, belongs to a small group of waterfowl that perch in trees. In poultry science, however, it is normally grouped with domestic ducks for lack of a better classification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Except in France, Italy and Taiwan muscovies have received little modern research. But their promise can be judged from the fact that they account for 50 percent of the duck meat consumed in France - about 60,000 tons per year - and they are often consumed in Italy and Taiwan as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For Third World subsistence farming, muscovies have excellent possibilities. There is probably no better choice for a meat bird that requires minimal care and feed. Tame, quiet, and able to forage for much of their keep, they are inherently hardy, vigorous, and robust. They have heavily fleshed breasts and are highly prized for their meat, which is dark, more flavorful, and less fatty than that of common ducks. An average muscovy gives more meat than a chicken of the same age, and it also survives hot, wet environments better. In addition, muscovies are better parents than the domestic duck. Females are probably the best natural mothers of any poultry species, as measured by their success at incubating their eggs and caring for their young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All in all, this bird deserves more attention than it has received so far in Third World livestock projects. Dispersed around the warm and hot regions of the world, muscovies already exist in small numbers in backyards and villages, much like the domestic chicken in previous centuries. Despite a lack of research, the present unimproved stocks are already impressive meat yielders. Used more widely and more intensively, they could contribute much to poor people's meat supplies. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crossing the muscovy with the common duck produces a hybrid that combines many of the advantages of both. This cross, known as "mulard," or "mule duck" in English, is raised in France for its liver and meat and is produced in quantity in Taiwan (see sidebar, page 132). It, too, has a major future role.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muscovies are suitable for use almost anywhere that chickens can be kept. Moreover, their tropical ancestry and inherent robustness give them an advantage in hot and humid climates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although a muscovy somewhat resembles a goose, it is one of the greater wood ducks of tropical South America. It was domesticated in pre-Columbian times, most likely in the rainforests of Colombia. Related wild types, looking very much like the muscovy, still occur in South American wetlands, particularly mangrove swamps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males have mature live weights of 5 kg and females about 2.5 kg. Both have broad and rounded wings. The adults have patches of bare skin around the eyes, rather than feathers. Much of this is covered in "caruncles," which superficially resemble warty outgrowths. The feet have sharp claws. Both sexes raise a crest of feathers when alarmed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is much color variation among the various muscovy populations including types that are called white, colored, black, blue, chocolate, silver, buff, and pied.2 The most common types (they are not considered breeds) are the white and the colored. The white produces a cleaner looking carcass, but the colored is the most popular meat type in France. Its plumage is an iridescent greenish black, except for white forewings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The native range of the muscovy's probable wild ancestor covers much of Central America and northern South America. The domestic form also occurs over most of Latin America - from southern Chile to the northern limits of traditional culture in lowland Mexico - including the Caribbean, where it was present shortly after Columbus landed.3 The birds can be observed among the domestic fowl in the high Andes, for example, and are feral in southern coastal areas of the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Carried across the Atlantic, probably in the early 1500s, the domesticated muscovy spread quickly in Europe, and thence to North America, Asia, Africa, and Oceania. Today, it finds favor with the food-loving French as "canard de Barbarie," and France has the greatest concentration of muscovies in Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Down the centuries the muscovy became popular in tropical Asia (especially the Philippines and Indonesia) and in China and Taiwan. Throughout Indonesia (where it is known as "entok") it is popular with villagers for incubating eggs from ducks, geese, and chickens. It is now spreading into Oceania, and has recently gained particular favor in the Solomon Islands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovies are also known in Africa and can be found in many villages, especially in West Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Not endangered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wild muscovies occur mainly along tropical jungle streams, but domestic muscovies are found in many environments from the heat of Central America to the cold of Central Europe. They also tolerate dry conditions, but they thrive best where climates are both hot and wet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muscovies utilize high-fiber feeds better than chickens and common ducks, and eat larger quantities of grass. They also consume other green vegetation and readily snap up any insects they can find. If quality forage is available, only a small daily ration of grain or pellets is required for them to reach peak production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovy females normally hatch and raise large broods efficiently. It is not unusual to see them with a dozen or more fragile ducklings in tow - many of them adopted from other species. They bravely protect their young and have been known to beat off cats, dogs, foxes, and other marauders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Normally, muscovies are healthy and live and breed for many years. They suffer few diseases, especially when free ranging. However, they seem to be more susceptible to duck virus enteritis (duck plague) than common ducks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p129a.png"></center><br>
+ figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">While appearing to be slow and lethargic, muscovies can be quick and agile when one tries to catch them. Females are strong fliers and readily clear a standard fence. Males frequently become so ponderous that they cannot get airborne without an elevated perch or the aid of a strong wind. Although they forage over a larger area than chickens, they generally neither decamp nor wander as far as common ducks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated muscovies are either solitary or live together in small family groups, but sometimes in winter they flock together on bodies of water. They swim and dive well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These birds seldom make loud noises. A drake's voice resembles a muffled "puff"; females are almost mute. However, both can hiss or make a soft sound not unlike that of sleigh bells.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The muscovy is polygamous (a young male will try to mate with almost any fowl, including chickens). Mating can occur on land or in water. Males are pugnacious and tolerate no opposition. Because of this, they do not do well in close confinement.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A BETTER FLY TRAP</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The muscovy is a voracious omnivore that is particularly fond of insects. For years, some Canadian farmers have sworn that a few muscovies took care of all fly problems on their farms. In 1989, Ontario biologists Gordon Surgeoner and Barry Glofcheskie (see Research Contacts) decided to put this to the test.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Starting with laboratory trials, the entomologists first put a hungry five-week-old muscovy into a screened cage with 400 living houseflies. Within an hour it had eaten 326. Later, they placed four muscovies in separate cages containing 100 flies each. Within 30 minutes over 90 percent of the insects were gone. It took flypaper, fly traps, and bait cards anywhere from 15 to 86 hours to suppress the populations that much.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moving to fleld tests, the researchers placed pairs of twoyear-old muscovies on several Ontario farms. Videotapes showed the birds snapping at houseflies and biting flies about every 30 seconds and being successful on 70 percent of their attempts. With that efficiency, they achieved 80-90 percent fly control in enclosures such as calf rooms or piggeries. The birds were given only water and had to scavenge for all their food. Females seemed to eat about 10 percent more flies than males, and individuals of any age between eight days and two years were equally effective.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds fit the practical needs for farmyard fly control. They stayed close to piglets and calves, to which flies are particularly attracted. They even snatched flies off the hides of resting animals without waking them up. On one farm, the birds huddled between sleeping piglets and were accepted by the sow lying beside them. This was noteworthy because most fly-catching devices (chemical, electrical, or mechanical) must be kept far from animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To the Canadians, the economic advantages are clear. A 35-cow dairy needs $150-$590 worth of chemicals for controlling flies during the fly season; muscovy chicks, on the other hand, cost less than $2 each, eat for free, and can be sold for a profit of 200-400 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The researchers point out that employing muscovies does not eliminate all need for insecticides, but it reduces the amounts required. And muscovies are biodegradable, will not cause a buildup of genetic resistance, and taste better than flypaper. Indeed, their meat is excellent, and the naturally mute birds seldom make any noise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reportedly, muscovies are kept in some houses in South America to control not only flies, but also roaches and other insects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The muscovy is generally raised only for its meat, which is of excellent quality and taste. In stews it is hard to distinguish from pork; cured and smoked it is similar to lean ham.4 The fat content is low.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovy eggs are as tasty as other duck eggs, and a muscovy female can supply a large number if she is kept from sitting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These birds are useful for clearing both terrestrial and aquatic weeds.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Down feathers are used, like those of other ducks, in clothing and comforters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muscovies may be raised like common ducks. An ideal grouping is one male to five or six females. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Except in Taiwan, France, Hungary, and a few other European countries, they exist predominantly in small flocks in farmyards and village ponds. However, they can be reared under intensive conditions in a shed or pen that is well lighted and equipped with low roosts and bedding. Under such conditions, they may be fed diets recommended for rearing common ducks or given coarse feeds, including whole grain. If chicken rations are used, fresh greens must be provided to avoid "cowboy" legs, a symptom of niacin deficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although they thrive in areas where there is abundant water, they do not require access to swimming water. They prefer to nest under cover and will use nesting boxes. A normal clutch size is 9-14 eggs; however, clutches of up to 28 can occur. There may be 4 clutches annually, and (when the hen does not have to brood the ducklings) some muscovies have laid 100 eggs in a year.6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The egg weight, which increases with the female's age, ranges from 65 to 85 g. The eggs require 33-35 days to hatch, a week longer than the common duck's. Hatching success of 75 percent or more is common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Compared with domestic ducks early growth is slow, which is perhaps why muscovies have not enjoyed wider industrial use. However, after the slow period they grow rapidly and, because they forage on a broader range of vegetation than common ducks, they can scavenge a large proportion of their diet at little or no cost.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When raised intensively, females average 2 kg and males 4 kg at 11-12 weeks of age. Females may reach sexual maturity by 28 weeks of age; males require a month more.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE MULE DUCK OF TAIWAN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In parts of Europe, hybrids between muscovies and common ducks are reared for fattening. However, Taiwan has made the most outstanding use of this "mule duck." Thanks in part to this muscovy hybrid, Taiwan's duck industry has grown rapidly in the last decade. The total value of duck products now exceeds $346 million per year. Much of the boom in duck production is due to improved feeding disease control and management systems, but much is also due to the performance of the mule duck. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This hybrid is now Taiwan's major meat-duck breed, and about 30 million are consumed each year. Indeed, the duck industry has been so successful that Taiwan is increasingly exporting frozen duck breast and drumstick meat to Japan. It now provides 24 percent of the duck meat eaten in Japan most of it coming from mule ducks. Also, Taiwan is exporting partially incubated mule-duck eggs throughout Southeast Asia. And mule ducks supply most of the raw material for Taiwan's large feather industry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taiwan farmers have been producing mule ducks for 250 years, but the recent jump in production is due to the use of artificial insemination to overcome the natural reticence of the different species to mate. Fortunately, artificial insemination is well developed and is a standard part of farming practice in Taiwan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mule ducks are successful because they have less fat than a broiler chicken and they grow faster. Indeed, they can reach a market weight of 2.8 kg at 65 - 75 days of age, depending upon the weather, season, and management. In part, this fast growth is because they are sterile and waste no energy in preparing for a sexual existence or in laying eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The usual cross employs a muscovy male and a domesticduck female. The domestic breeds most employed for muleduck production are White Kaiya (Pekin male x White Tsaiya female), Large White Kaiya (Pekin male x White Kaiya female) and colored Kaiya. Both sexes of the hybrid offspring weigh about the same.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crosses between a muscovy hen and a domestic drake are much rarer (traditionally, this was because of the different mating behavior of the two species, but even with artificial insemination available they are not much used) and the males of these hybrids are much heavier than the females. Females of this cross do lay eggs, but the eggs are small (about 40 g) and their embryos do not develop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are almost 300 duck-breeding farms in Taiwan, annually producing more than 600,000 female domestic ducks for use in producing mule ducks. Some farmers combine duck raising with fish farming. The excrete of 4,000 ducks on one hectare of pond can provide 30,000 tilapia with 20 percent of their feed. It helps the farmer get rid of waste as well as giving him fresh fish to sell. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, the muscovy is an extremely good forager and thrives under free-ranging conditions. Unlike other ducks, it grazes on grass and leaves and will maintain itself on pasture. Apparently, it can digest bran and other fibrous feeds better than common ducks can.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The males are larger than all but the largest strains of table duck. They have exceptionally broad, well-muscled breasts and provide one of the leanest meats of any waterfowl.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The muscovy is apparently more resistant to diseases that regularly decimate other poultry. This is one reason why villagers favored them: when chickens die, muscovies often survive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The female's strong parental qualities help assure the survival of ducklings with a minimum of human intervention. Her ability to incubate and hatch most other poultry eggs is an added advantage to small farmers who have neither the capital to buy, nor the knowledge to operate, artificial incubators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike other ducks, muscovies are not easily alarmed, and fright does not affect their egg production and laying. Indeed, they are so phlegmatic that automobiles can be major causes of death.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Because they are a tropical species, these birds are much less tolerant of cold than common ducks and require more protection from freezing weather.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The muscovy's feed conversion is not as good as the chicken's. Also, compared with some other meat-duck breeds, muscovies have a slower rate of growth and require about 4 6 weeks longer to attain maximum development of breast muscles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovies can be difficult to handle. If their legs are free, the handler may be badly lacerated by the claws.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although adults have a fair homing ability, muscovies may wander away when local forage is sparse, and young birds may be carried long distances downstream, never to return.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because they feed on greenery, they can devastate gardens if the plants are very young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovies can be unsuspected carriers of poultry diseases, so that healthy-looking muscovies may infect the other species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Poultry scientists should unite in efforts to advance technical knowledge and public appreciation of this bird. Governments and researchers should begin evaluations of local varieties and their uses and performances. The experiences of France, Italy, Eastern Europe, and Taiwan should be gathered and made available for a worldwide readership.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important that the many muscovy varieties within the countries of Latin America - where the bird has a centuries-long history of domestication - be maintained and studied. Many superior varieties and specimens may be awaiting discovery.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The muscovy's nutritional requirements, range and confined systems of management, and disease vulnerability are poorly understood and need study. Especially needed are ways to increase growth rate. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">10 Pigeon</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g013a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeons (Columba livia)1 are durable birds that can be raised with little effort. Able to survive in inhospitable climates, they fend for themselves - often ranging over many square kilometers to locate seeds and edible scraps. They have been raised for centuries, especially in North Africa and the Middle East. In parts of North America and Europe, they are produced as a delicacy for the gourmet market. But raising pigeons for food is not nearly as widespread as it could be; indeed, in modern times its potential has hardly been touched. Farmed pigeons are particularly promising as urban microlivestock because they require little space and thrive in cities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young pigeons (squab) grow at a rapid rate. Their meat is finely textured, has an attractive flavor, and is often used in place of game fowl. Tender and easily digested, it commands premium market prices. In many areas, the continuing demand is unfilled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeons are traditionally raised in dovecotes - "houses" that protect the birds from the elements and from predators. This system allows free-ranging flight and requires almost no human intervention. Dovecotes are a good source of both squab and garden manure, and they continue to be used, especially in Egypt. On the other hand, pigeons can also be raised in confinement - usually in enclosed yards - with all their needs supplied by the farmer. There are, for example, pigeon farms in the United States with up to 35,000 pairs of breeding birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeon production may never rise enough to compete with commercial poultry as a major source of food, but for Third World villages these birds could become a significant addition to the diet as well as a source for substantial supplemental income. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pigeons have small heads, plump, full-breasted bodies, and soft, dense plumage. They weigh from about 0.5 to nearly I kg. A few large breeds (Runts, for instance, which commonly weigh 1.4 kg) are the size of small domestic chickens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many breeds have been developed for meat production. They produce squab that grow quicker and have larger breasts than unselected birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The wild ancestor of the common pigeon - domestic, wild, or feral -  is thought to be the rock pigeon or rock dove of Europe and Asia. Today its domestic descendants are bred in virtually every country, and those that have gone feral (reverted to the wild) occur in most of the world's cities and towns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">They are abundant. However, as with most other domestic species there is concern over the decline and loss of certain breeds. Societies have been organized (notably in the United Kingdom) to preserve rare types.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p138a.png"></center><br>
+ Natural habitat of the rock dove ancestor of the domestic pigeon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The domestic pigeon can be raised equally well in temperate and tropical zones. Indeed, this adaptable species can be kept anywhere that wild pigeons exist, including arid and humid regions. It should be noted, however, that cold climates do not favor squab production and hot climates promote vermin and disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The pigeon's natural diet consists mostly of seeds, but includes fruits, leaves, and some invertebrates. Feral pigeons consume a wide array of materials, including insects, bread, meat scraps, weed seeds, and many kinds of spilled grains at mills, wharves, railway yards, grain elevators, and farm fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the first four or five days of life, the young are fed "crop milk." This substance, common to pigeons and doves,2 is composed of cells from the lining of the crop and is very high in fats and nutritional energy. The phenomenal growth rate of young squab has been attributed to crop milk and to its early replacement (within 8-10 days) with concentrated foods, regurgitated by both parents. The parents feed the squab for about four weeks before pushing it out of the nest to prepare for the next clutch.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In domestic birds, sexual maturity (as measured by age at first egg) is reached at 120-150 days. Life span can be 15 years, although growth and egg production decline rapidly after the third year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wild pigeons often nest on cliff sides. Domestic pigeons prefer to nest around buildings, in nooks and shelves and under the eaves - that is, in "pigeonholes."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In domestic varieties, the pair-bond often lasts until severe illness or death. Sometimes, however, a vigorous male will "invade" a nest and mate with the females there. Both sexes take nearly equal part in nest building, incubation, and caring for the young. Typically, there are two eggs to a clutch. Eight clutches a year is not uncommon for a breeding pair. The incubation period is 17-19 days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike most birds, pigeons drink by inserting their beaks into water and sucking up a continuous draft. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Courtship is characterized by cooing, prancing, and displays of spread, lowered tail feathers. "Bow and coo" exhibitions are unique to pigeons and doves and differ among species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pigeons are usually raised exclusively for meat. The squab are harvested just before full feather development and before the youngster has started to fly, usually at 21-30 days of age. At this time the ratio of flesh to inedible parts is highest; once flying begins, the meat becomes tougher. Weight depends upon breed, nutrition, and other factors, but usually ranges from 340 to 680 g.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeons are extensively used for scientific research, notably in physiology and psychology. They are also widely kept as pets for plumage and for racing. The pigeon's unique homing ability was recognized in Roman times, and the birds have been trained to return to the dovecote from as far away as 700 km. Even today, homing pigeons are used to carry messages, especially during war.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pigeons are easily trained to recognize "home." The wing feathers are clipped and the birds are fed close to the dovecote; by the time they refledge, their homing instinct has been developed. Alternatively, newly captured pigeons may be trained by confining them to the dovecote for at least one week. At first, a little grain is provided in the morning (this is to ensure the birds will return to the coop). The birds can obtain the rest themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any waterproof house that is easy to clean is suitable for keeping pigeons. Many traditional dovecotes are built of earthenware pots. In Asia and Europe, wooden pigeon towers are generally used.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike chickens, pigeons do not prefer communal roosts. Instead, they prefer nesting shelves, of which there should be two for each breeding pair. The shelves are usually placed in dark corners and are fitted with low walls to keep eggs from rolling out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grit is important in the diet, both to provide minerals and to allow the birds to grind feed in their gizzards.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Commercial squab breeds are often kept permanently in pens, a process that requires care and experience. Growers expect an average of 12-14 squab per pair per year, although much depends on environment and management. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds need fresh water daily and water for bathing at least weekly. Since they feed their young by regurgitation, the adults must have a continuous supply of clean drinking water. Orphan squab can be fed egg yolk until old enough to consume adult feeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like all poultry, confined pigeons must be provided enough supplemental feed to ensure a balanced diet. A mixture of whole grains can be fed for maximum production. It is important that grains be dry and free of mold (pigeons will not thrive on mash). Peas, beans, or similar pulses make good supplements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CARRIER PIGEONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most people consider message-carrying pigeons to be a quaint anachronism. But in a few countries (both developed and developing) carrier pigeons are making a comeback, and in the future they may be used routinely once again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New techniques are making this process far more practical than before. For example, in the past the pigeons would be flown in one direction only. They were transported away from home and at the appropriate time released to find their way back. That was very limiting. But it has since been found that pigeons can be trained to carry messages in two directions: flying from one point to another and then back again. They will do it twice a day, and with almost perfect reliability. The key is to place the feeding station at one end and the nest at the other. This limits the pigeon's range, but they still can handle round-trip distances up to 160 km.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With a little ingenuity, there is no need for a person to monitor the stations to receive the messages as the bird arrives. One simple technique is to arrange the station with one-way doors - one opening inwards, the other outwards. Placing a bar across the outward door means that the bird cannot get out until someone releases it. Thus the message can always be retrieved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This system has been employed in Puerto Rico and Guatemala, but it could be used almost anywhere. In many parts of the Third World, in particular, there are remote areas with no phones and with hilly, rough terrain where delivering messages can take hours of strenuous travel. Some locations are subject to unexpected isolation by natural calamities or military or terrorist actions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Puerto Rico, for instance, we kept pigeons in a village 32 km from the capital. The pigeons could get downtown in 20-30 minutes. It took us 1.5-2 hours each way by road. What was easy for the birds was a major trip for us. Pigeons carried the villagers' requests for certain foods and medicines. Our contact in the city then sent up the supplies by bus. The birds never let us down.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Carrier pigeons are useful for more than just flying far and fast. They have been bred for racing and their large pectoral muscles make them excellent meat producers - much better than the common pigeons normally raised for food. A pair of carriers typically will raise 12 - 16 young each year, and those not needed for message carrying can be butchered at 28 days of age - yielding meat that is nutritious and considered a delicacy in many countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David Holderread</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Every day on the northwest coast of France, Petit Gendamme, a black and white carrier pigeon, flies on average 23 km between hospitals on his blood delivery route. Trussed in tiny hand-sewn harnesses, he and a flock of carrier pigeons set out (except during the hunting season) with little red tubes of blood secured to their breasts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"It's a simple, effective, and cost-saving transport system," said Yves Le Henaff, head of the Avranches Hospital laboratory, Cotentin, France, a central blood-testing center that serves a number of isolated medical centers along the coast.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The service becomes particularly valuable during the summer tourist rush, when travellers flock to the seashore to visit nearby Mont Saint Michel, crowding the small country roads and increasing the risk of traffic accidents.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds' average flight time between the hospitals of Avranches and Granville, for example, a distance of about 27 km, is 20 minutes, including the time for harnessing up. And with a favorable western wind their best time can reach 11 minutes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While gasoline costs the equivalent of $0. 75 a lifer in France, hospital officials say that a few grains of corn is all it takes to run this operation. According to Le Henaff, who supervises the carrier pigeon operation, the hospital is saving up to $46 a day on gas and auto maintenance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 40-year-old Le Henaff got the idea five years ago from an article in a scientific journal describing a similar experiment in Britain. A year later, he and an associate called on the local seamstress to design a light harness that could hold a tube, which, when filled, weighs approximately 39 g.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The flock now consists of 40 veteran fliers and 20 carrier pigeons in training.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And what if the winged creatures stray en route? Le Henaff has devised a fall-back option: two pigeons carry two different test tubes containing the same blood sample.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds fly every day of the year with the exception of the three-month autumn hunting season. Since the beginning of the experiment four years ago, there have been two casualties. Le Henaff believes the birds probably met their fate in some Normand's oven.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sometimes weather is a factor, and heavy fog can keep the delivery team grounded.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So far, the new job seems to benefit the pigeons, too. Unlike sickly city pigeons, whose average life span is about four years, well-cared-for carrier pigeons can live up to 15 years, Le Henaff said. "And how many people do you know who are willing to stay with the same outfit for that long?"</P>
+<P ALIGN="JUSTIFY">Sabine Maubouche</P>
+<P ALIGN="JUSTIFY">The Washington Post</P>
+<P ALIGN="JUSTIFY">December 2, 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Under extensive conditions - where the birds are released each day to feed themselves - almost no land is needed. Under intensive conditions, where the birds spend their lives in confinement, a mere half hectare can be enough space to raise 2,000 pairs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Free-ranging pigeons forage over a wider area than most domestic fowl because they fly out to find their feed. Nutrient requirements3 are similar to those of chickens and other fowl (making allowance for the energy needed for flying), so commercial feed and other supplements - if needed at all - are generally available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In dovecote culture, pigeons require little or no handling. They brood the young with little intervention. Although not continuous, the production of meat from these fast-growing, rapidly reproducing birds is more sustained than with most livestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Almost nowhere are there taboos against consuming pigeon meat. Prices received for squab are normally high, and in most places the demand is constant. The only limitation in some areas is the absence of an effective market, which is usually easy to create.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Squab contains a larger proportion of soluble protein and a smaller proportion of connective tissue than most meats and is therefore good for invalids and people with digestive disorders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As many hobbyists can testify, raising pigeons can be gratifying.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pigeons are subject to few diseases. However, worms, lice, diarrhea (coccidiosis), canker (trichomoniasis), and salmonella (paratyphoid) occur at some time in most domestic breeds. Salmonella exists in low levels in most flocks and will flare up if birds are stressed. Treatments recommended for domestic chickens are usually suitable for pigeons. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By flying over a wide area and eating grains and other foods, pigeons can cause conflicts with farmers. Indeed, in the 13th century the aristocracy's pigeons became a major grievance of the peasants who saw their seed devoured. On the other hand, "croppers" (breeds with large crops) were developed to steal grain from the lord's fields. The pigeon returned home and his crop was emptied of the grain, which was used by the peasant to make bread.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds can become nuisances. They leave droppings in annoying places, some people find them too noisy, and a few people are severely allergic to "pigeon dust."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Every conceivable type of predator can be expected; therefore, precautions must be taken. The dovecote must be well protected against rats, which are the principal enemy of the eggs and the squabs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nesting birds need a high-protein diet to raise squab at the high rates of gain that are possible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Poultry researchers should study the increased role pigeons might play in Third World economic development. Nothing comparable to the sophisticated selection employed with the domestic chicken has so far been attempted. Given such attention the gains could be great.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among pressing research needs are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Breeding. This needs to be better understood. For example, the effects of hybridization and inbreeding need clarification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Environmental limits. Little work has been done outside the temperate regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Diseases. These deserve increased attention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">There is also the potential of "dovecotes" for wild pigeons. Numerous local species are well adapted to local conditions, and these deserve to be tested for "domestication."4 Many wild species quickly lose their fear of man, and in time they can even become too fat to fly. Wild pigeons are already found throughout the humid tropics and are trapped for meat and rearing in New Guinea and other places. They are already an important food source for many subsistence farmers and shifting cultivators, and with some dovecote management could provide a greater, more dependable source of food and income. The potential for domesticating local pigeon species, especially those suited to the tropics, deserves exploration. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">11 Quail</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g014a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Native to Asia and Europe, quail' (Coturnix coturnix2) have been farmed since ancient times, especially in the Far East. They reproduce rapidly and their rate of egg production is remarkable. They are also robust, disease resistant, and easy to keep, requiring only simple cages and equipment and little space. Yet they are not well known around the world and deserve wider testing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail are so precocious that they can lay eggs when hardly more than 5 weeks old. It is said that about 20 of them are sufficient to keep an average family in eggs year-round. Quail eggs are very popular in Japan, where they are packed in thin plastic cases and sold fresh in many food stores. They are also boiled, shelled, and either canned or boxed like chicken eggs. Quail eggs are excellent as hors d'oeuvres and they also are used to make mayonnaise, cakes, and other prepared foods.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In France, Italy, the United States, and some countries in Latin America (Brazil and Chile, for example) as well as throughout Asia, it is the meat that is consumed. It is particularly delicious when charcoal broiled. One company in Spain annually processes 20 million quail for meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of the domesticated strains seem to have originated in China, and migrating Chinese carried them throughout Asia. Today, millions of domestic quail are reared in Japan, Indonesia, Thailand, Taiwan, Hong Kong, Indochina, Philippines, and Malaysia, as well as in Brazil and Chile. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Commercial production is carried out, as in the chicken industry, in specialized units involving hatcheries, farms, and factories that process eggs and meat. However, quail have outstanding potential for village and "backyard" production as well. It is this aspect that deserves greater attention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Quail come in various sizes. The smaller types are used for egg production, whereas the larger ones are better for meat. Adult females of improved meat strains may weigh up to 500 g. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are several color varieties. However, mature females are characterized by a tan-colored throat and breast, with black spots on the breast. Mature males, which are slightly smaller than females, have rusty-brown throats and breasts. All mature males have a bulbous structure, known as the foam gland, located at the upper edge of the vent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the United States, the Pharaoh strain is the bird of choice for commercial production. Other available strains tend to be bred more for fancy than for food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail eggs are mottled brown, but some strains have been selected for white shells. These eggs are often preferred by consumers and are easier to candle (the process of holding eggs up to a light to check for interior quality and stage of incubation). An average egg weighs 10 g - about 8 percent of the female's body weight. (By comparison, a chicken egg weighs about 3 percent of the hen's body weight.) Quail chicks weigh merely 5-6 g when hatched and are normally covered in yellowish down with brown stripes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The ancestral wild species is widely distributed over much of Europe and Asia as well as parts of North Africa. Although domestic quail are now available almost everywhere, Japan is probably the world leader in commercial production; quail farms are common throughout its central and southern regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Not endangered. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p149a.png"></center><br>
+ figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Quail are hardy birds that, within reasonable limits, can adapt to many different environments. However, they prefer temperate climates; the northern limit of their winter habitat is around 38&Yacute;N.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A quail's diet in the wild consists of insects, grain, and various other seeds. To thrive and reproduce efficiently in captivity, it needs feeds that are relatively high in protein.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The females mature at about 5-6 weeks of age and usually come into full egg production by the age of 50 days. With proper care, they will lay 200-300 eggs per year, but at that rate they age quickly. The life span under domestic conditions can be up to 5 years. However, second-year egg production is normally less than half the first year's, and fertility and hatchability fall sharply after birds reach 6 months of age, even though egg and sperm production continue. Thus, the commercial life is only about a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crosses between the wild and domestic stocks produce fertile hybrids. Repeated backcrossing to either wild quail or domestic quail is successful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Only females hatch the eggs and raise the chicks. Males go off and court other females when their partners begin the nesting process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Quail eggs taste like chicken eggs. They are often served hard boiled, pickled, fried, or scrambled. Because of their size they make attractive snacks or salad ingredients. They provide an alternative for some people who are allergic to chicken eggs. On frying, the yolk hardens before the albumen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail meat is dark and can be prepared in all of the many ways used for chicken. The two meats are similar in taste, although quail is slightly gamier.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its hardiness, small size, and short life cycle, quail are now commonly used as an experimental animal for biological research and for producing vaccines - especially the vaccine for Newcastle disease, to which quail are resistant. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many fanciers and hobbyists have also become interested in raising this adaptable species as a pet. Science teachers find it an excellent subject for classroom projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">QUAIL IN JAPAN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In some areas of Japan, quail are widely raised for their eggs and meat. However, Japanese originally valued the quail as a songbird. Tradition has it that about 600 years ago people began to enjoy its rhythmic call. In the feudal age, raising song quail became particularly popular among Samurai warriors. Contests were held to identify the most beautiful quail song and birds with the best voices were interbred in closed colonies. Even photostimulation was practiced to induce singing in winter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Around 1910, enthusiastic breeders produced the present domestic Japanese quail from the song quail. It was created as a food source and became a part of Japanese cuisine. During World War II it was almost exterminated, but Japanese quail breeders restored it from the few survivors and from birds imported from China. The original song quail, however, were lost. In the 1960s, commercial quail flocks rapidly recovered and Japan's quail population again reached its prewar level of about 2 million birds. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A QUAIL IN EVERY POT: AN OLD DELICACY FINDS A NEW PUBLIC</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">For centuries, quail were considered a great delicacy: a dish that only eminent chefs would cook and diners with an appreciative palate could enjoy. These small migratory birds, which are found in one variety or another throughout the world, were available until recently almost exclusively to hunters in the wild.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But now quail are in danger: in danger of becoming commonplace.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the last few years, quail have gone from being rarefied to a supermarket specialty item. They are on menus in the most elegant restaurants and the most casual cafes and bistros.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Why so much interest?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail are now available semi-boneless, which makes them faster and easier to cook, and easier to eat as well. The breastbones are removed by hand before the birds are packaged and shipped to stores. The bones in the wings and legs remain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A stainless-steel V-shaped pin - invented and patented by a restaurant chef who wanted a way to keep quail flat for grilling is inserted into the breast. The pin can be left there throughout cooking and removed just before serving.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While whole quail might require 45 minutes to cook, the semi-boneless variety can be grilled in less than 10 minutes, or pan-roasted, braised or sauteed in less than 20 minutes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The flavor of farm-raised quail has also helped bring them into the mainstream. Most farm-raised quail have tender meat like the dark meat of chicken, whose flavor is enjoyed by many people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And at a time when people are searching for foods, specifically animal protein, with low fat and cholesterol, quail fills the bill. The Agriculture Department says that quail skin has about 7 percent fat, about the same as dark meat of roasted chicken without the skin.</P>
+<P ALIGN="JUSTIFY">Judith Banrett Adapted from The New York Times </P>
+<P ALIGN="JUSTIFY">June 21, 1989</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">It is necessary to keep quail in battery cages on wire floors because males secrete a sticky foam (from the foam gland) with their feces; on a solid floor, this adheres to the feet and collects dung, leading to crippling and breakage of eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adult quail can live and produce successfully if they are allowed 80 cm2 of floor space per bird. However, for reproduction about twice that is needed to allow for mating rituals.3 If properly mated, high fertility rates and good egg hatchability can be expected. To obtain fertile eggs, one male is needed for roughly six females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eggs hatch in about 17 days. Chicks require careful attention. Brooding temperatures of between 31 C and 35 C  are needed for the first week and above 21 C for the second week. From the second week on, chicks can survive at room temperature. (These temperatures are similar to those required for common chickens.) In cold climates, supplemental heat may be needed as well as protection from cool drafts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Clean water must be provided at all times, with care taken to prevent the chicks from drowning in their water troughs. Shallow trays, jar lids, or pans filled with marbles or stones may be used.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Quail production can be started with little money. These easy-care birds can be housed in small, simple, inexpensive cages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, they are resistant to Newcastle disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SIX OF ONE, HALF A DOZEN OF THE OTHER</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The fact that chickens can be crossed with quail has been known for some time, but there has been little attempt to develop the fertile hybrids. Now Malaysia has begun a project aimed at producing a new poultry bird - a cross between a cockerel and a hen quail. Zainal Abidin bin Mohd Noor, of the Department of Veterinary Services in Kuala Lumpur, is creating a strain that produces eggs of good quality and meat with the flavor of both parents. The new bird is intermediate in size between chicken and quail which is convenient because it is about right for an individual helping.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The crossbreeding is done through artificial insemination. The progeny exhibit a range of appearances, sizes, and plumage colors, depending on the strains of cockerel and quail hens used. In the Malaysian research, cockerels have been local Ayam Kampung Bantam, Hybro, and Golden Comet hybrids. The quails have been local inbred Japanese quail (IJQ) and imported meat strain quail (IMSQ).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The trials show that the hybrids derived from the IMSQ flocks grew faster and bigger than those from the IJQ cross. The best have been the Hybro x IMSQ crosses, which weigh 475 g at 10 weeks of age. The best of the IJQ group weighed 290 g during the same period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This type of "tropical game hen" might be a way to introduce hybrid vigor into poultry production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The researchers who developed the hybrid have named it the "yamyuh." </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although generally disease resistant, quail are affected by several common poultry diseases, including salmonella, cholera, blackhead, and lice. They also suffer epidemic mortality from "quail disease" (ulcerative enteritis), which can, however, be controlled with antibiotics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail seem to require more protein than chickens, and produce best when given feed that is fairly high in protein.4 However, they also perform satisfactorily when fed rations designed for turkeys. They have high requirements for vitamin A, which they do not store.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail are not suitable as free-ranging "scavengers." They must be kept confined, which is a major constraint. Unlike chickens or pigeons, they have no homing instinct and will not remain on a given site; if released, they will be lost. In addition, since they nest on the ground, they are highly susceptible to predation; they must be protected, especially where certain animals, the mongoose for example, are common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Artificial incubation is essential. Natural incubation using the female is futile; the females do not go broody and rarely incubate their eggs. The shells are extremely thin, but the eggs can be incubated under a small chicken hen, such as a bantam.5 The eggs are also subject to minute fractures. However, the shell membrane is extremely tough and unfertilized eggs are generally unaffected, but the cracks cause fertilized embryos to dehydrate and die. This is a serious limitation. Whenever quail husbandry is introduced, artificial incubation should be included.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Quail deserve to be included in all poultry research aimed at helping the Third World. Through its international scientific program, Japan, in particular, could apply to developing nations its vast experience with quail farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experiences with quail in the tropics (for example, Japanese farmers in the Amazon Basin) and in tropical highlands (for instance, in India, Nepal, or Central Africa) should be collected and assessed to improve understanding of the environmental limits to Third World quail farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cooperation between commercial and laboratory quail breeders should be encouraged. Mutants found at the commercial level would be useful for laboratory work. Conversely, introducing new stocks could help the farmer. In both cases, more genetic diversity might also lead to the production of hybrid vigor, and genetic variability would be conserved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sex-linked genes, if they can be found, would be useful to the commercial quail breeder for the rapid sexing of newly hatched chicks. This could lead to more efficient production techniques, like those in the chicken industry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although virtually all work to date has been on the Japanese quail, other species and subspecies warrant research and testing. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">12 Turkey</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g015a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The turkey (Meleagris gallopavo) is well-known in North America and Europe, but in the rest of the world, especially in developing countries, its potential has been largely overlooked. Partly, this is because chickens are so familiar and grow so well that there seems no reason to consider any other poultry. Partly, it is because modern turkeys have been so highly bred for intensive production that the resulting birds are inappropriate for home production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, there is a much wider potential role for turkeys in the future. There are types that thrive as village birds or as scavengers, but these are little known even to turkey specialists. These primitive types are probably the least studied of all domestic fowl; little effort has been directed at increasing their productivity under free-ranging conditions. However, they retain their ancestral self-reliance and are widely used by farmers in Mexico. That they are unrecognized elsewhere is a serious oversight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Native to North America, the turkey was domesticated by Indians about 400 BC, and today's Mexican birds seem to be direct descendants.' Unlike the large-breasted, modern commercial varieties, they mate naturally and they retain colored feathers and a narrow breast configuration. Their persistence in Mexico after 500 years of competition with other poultry highlights their adaptability, ruggedness, and usefulness to people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These birds complement chicken production. They are able to thrive under more arid conditions, they tolerate heat better, they range farther, and they have higher quality meat. Also, the percentage of edible meat is much greater than that from a chicken. Turkey meat is so low in fat that in the United States, at least, it is making strong inroads into markets that previously used chicken exclusively. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turkeys are natural foragers and can be kept as scavengers. Indeed, they thrive best where they can rove about, feeding on seeds, fresh grass, other herbage, and insects. As long as drinking water is available, they will return to their roost in the evening.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appreciation for the turkey could rise rapidly. Interest already has been shown by several African nations. A French company has created a strain of self-reliant farm turkeys and is exporting them to developing countries.2 Researchers in Mexico are displaying increased interest in their national resource. And as knowledge and breeding stock continue to be developed, it is likely that village turkeys will become increasingly popular around the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Modern turkey breeding has been so dominated by selection for increased size and muscling that commercial turkeys have leg problems and cannot mate naturally (they are inseminated artificially). These highly bred birds are adapted for large-volume intensive production, and must be raised with care. As noted, this chapter emphasizes the more self-reliant, less highly selected turkeys found in Mexico and a few other Latin American countries. They do not require artificial insemination, and with little attention can care for themselves and their young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fully grown "criollo" turkeys of Mexico are less than half the size of some improved strains. Males weigh between 5 and 8 kg; females, between 3 and 4 kg.3 They vary in color from white, through splashed or mottled, to black. The skin of the neck and head is bare, rough, warty, and blue and red in color. A soft fleshy protuberance at the forehead (the snood) resembles a finger. In males it swells during courtship. The front of the neck is a pendant wattle. A bundle of long, coarse bristles (the beard) stands out prominently from the center of the breast.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The unimproved domestic turkey is essentially limited to central Mexico and scattered locations throughout nearby Latin American countries. Some village birds are also kept in India, Egypt, and other areas, but these are descended from semi-improved strains exported from North America and Europe in earlier times. Generally speaking, few turkeys are found in tropical countries outside Latin America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domesticated turkeys are not endangered; there are estimated to be about 124 million in the world. However, the wild Mexican varieties, ancestors to the first domesticated turkeys sent to Europe, may now be endangered since their distribution in southwestern Mexico has been greatly reduced. Certainly, some primitive domestic strains in the uplands of central Mexico are also being depleted. A separate type, independently domesticated by the Pueblo Indians of the southwestern United States, seems to have disappeared entirely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Turkeys can be reared virtually anywhere. Their natural habitat is open forest and wooded areas of the North American continent, but in Mexico they are raised from sea level to over 2,000 m altitude, from  rainforest to desert, and from near-temperate climates to the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p159a.png"></center><br>
+ The original distribution of the turkey and the occellated</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The range of diet is broad. Turkeys eat greens, fruits, seeds, nuts,  grasses, berries, roots, insects (locusts, cicadas, crickets, and  grasshoppers, for example), worms, slugs, and snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reproduction is generally seasonal and is stimulated by increasing  daylength. (A minimum daylength of 12 hours is required.) The birds  can reach sexual maturity at six months of age and may start breeding at  this time. Ten days after first mating, the hen searches out a nest and  commences laying. Industrial birds in temperate climates lay, on  average, 90 eggs a year. The nondescript type of turkey in the tropics  seldom lays more than 20 small eggs (weighing about 60 am) before  going broody.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic turkeys walk rather than fly, and find almost all their food  on the ground. They can, however, fly short distances to avoid  predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The commercial birds have lost many abilities for survival in the wild;  they can no longer exist without human care. However, village types  can do well with little management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turkeys prefer to make their own nests but can be induced to lay in a  convenient spot if provided with nest boxes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These birds are raised almost exclusively for meat. In many countries,  they are a treat for holidays, birthdays, and weddings. In their native  range of Mexico and Central America, the "unimproved" birds are  usually produced as a cash crop for market. They receive little care or  feed, and thus they are almost all profit - providing a significant income  supplement to many rural homes.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The principles of turkey management (nutrition, housing, rearing' and prevention of disease, for example) are basically the same as those for other poultry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Mexico, turkeys are usually kept under free-ranging conditions around houses and villages. Some shelter and kitchen scraps are occasionally provided. A number of them, however, are confined in backyards as protection from marauders and for shelter against rain and wind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One male can service up to 12 females. Roomy nests are needed. (As a rule, turkeys require three times the space occupied by chickens.) Most range turkeys are corralled when they begin to lay, so as to protect them from predators. Eggs may be gathered to prevent broodiness and thereby increase production. The eggs may be kept for several days (cool, but not refrigerated) if turned daily, and then may be placed under a chicken hen. (A setting chicken can be used this way to hatch up to nine eggs at a time.) Hatching takes 28 days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As in other birds, newly hatched turkeys (poults) must be kept warm during the first weeks of life. Until they begin foraging and have full access to pasture they are usually fed broken grain or fine mash, as well as finely chopped, tender green feed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although free-ranging turkeys are simple to raise, confined turkeys require more complex management. The birds need uncrowded, well ventilated conditions and should be on a wire or slatted floor to reduce parasitic infections. Any feeds recommended for chicks are suitable, but the protein content should be somewhat higher; that is, about 27 percent. They can be fed mixed grains, corn, and chopped legume hay. It may be necessary to provide vitamin supplements and antibiotics and take steps to prevent coccidiosis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"AN INCOMPARABLY FINER BIRD"</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The turkey was domesticated in Mexico some time before the Conquest. It is the one and only important domestic animal of North American origin. When the Spanish arrived, they found barnyard turkeys in the possession of Indians in all parts of Mexico and even in Central America. However, the Aztecs and the Tarascans, originating in west-central Mexico, seemed to have achieved the highest development of turkey culture, and it is probable that turkeys were domesticated in the western highlands, perhaps in Michoacan. Wild turkeys of that region are morphologically very similar to the primitive domestic bronze type. Both the Aztecs and Tarascans kept great numbers of the birds, including even white ones. They paid royal tribute to their respective kings in turkeys, according to the Relacion de Michoacan. The Tarascan king fed turkeys to the hawks and eagles in his zoo. The economy of some highland tribes was based on the cultivation of corn and the raising of turkeys.</P>
+<P ALIGN="JUSTIFY">A. Starker Leopold</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE INDUSTRIAL TURKEY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The modern domesticated turkey is thought to be descended from two differing wild subspecies, one found in Mexico and Central America and the other in the United States. The southern type is small, whereas the U.S. native is larger and has a characteristic bronze plumage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mexican turkeys were exported to Europe soon after the Conquest, and spread rapidly. In the 17th century, some were returned to North America, where they interbred with the eastern subspecies of wild turkey, producing a heavier bird, which was then re-exported to Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These types underwent little change until this century, when the Englishman Jesse Throssel bred them for meat quality. In the 1920s, he brought his improved birds to Canada, where their large size and broad breasts quickly made them foundation breeding stock. Crossed with the narrow-breasted North American types, these heavily muscled meat birds quickly supplanted other varieties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">About the same time, the U.S. Department of Agriculture began the scientific development of a smaller meat turkey derived from a more diverse genetic base. By the 1950s, the Beltsville Small Whites predominated in the home consumption market in the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The birds are efficient and generally take care of themselves. They tolerate dry, hot, or cold climates and forage farther than chickens. They are large, fast growing, highly marketable, low in fat, and tasty. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE TURKEY'S TROPICAL COUSIN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The ocellated turkey (Agriocharis ocellata) occurs in Yucatan, Guatemala, and Belize. It is much like the common turkey in size, form, and behavior: however, unlike the common turkey, which in Mexico lives in the high mountain pine and oak forests, the ocellated turkey inhabits bushy, semiforested lowlands. This splendid bird lacks the kind of beard sported by the common turkey gobbler, is generally more metallic in appearance, and has brighter coppery colors. The chief character is a neck and head that are bare, blue, and profusely covered with coral-colored pimples. It also has a yellow-tipped protuberance growing on the crown between the eyes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This species is worthy of investigation by poultry researchers because it might prove to be domesticable. It was possibly domesticated by the Mayas, whose ruins often include appropriately sized stone enclosures whose soil has elevated levels of phosphorus and potassium. Even today, in the rural Peten area of Guatemala, ocellated turkeys are sometimes kept around houses as scavengers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Young birds are readily affected by temperature changes and must be protected from the sun as well as from sudden chills, such as may occur at night. They are particularly susceptible to dampness, especially if associated with cold. One peculiarity is the turkey's aversion to any change in feeding routine or the nature of the food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young turkeys are susceptible to parasitic infestation as well as to the same type of bacterial and virus diseases as chickens (for example, fowlpox and coccidiosis). Blackhead, a devastating disease of young turkeys, is carried by a common parasitic nematode, and can be contracted from chickens. Medicines are available to prevent or treat most disease and pest problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Turkey development is almost nonexistent in the Third World (and much of the rest of the world, too). Although commercial turkeys are highly developed in some countries, little or no research has been conducted on the criollo turkey. Research on physiology, disease, and husbandry of the criollo turkey should be given high priority.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The need for conservation of genetic variability is perhaps more critical in this species than in almost any other domesticated animal. The unimproved types in Mexico should be collected and assessed, and a program to conserve the stocks should be initiated. An analysis should also be made of the traditional management and performance of these birds. In addition, the four or five recognized turkey subspecies should be evaluated for their potential as seed stock for Third World countries. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">13 Potential New Poultry</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g016a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several preceding chapters have discussed the possibilities of domesticating certain wild birds.l Here, briefly, are highlighted other wild species with qualities that might make them suitable for sustained production. It should be understood that their practical use in the long run is pure speculation; they are included here merely to guide those interested in exploring the farthest frontiers of livestock science.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collectively, poultry have become the most useful of all livestock and the most widespread. Yet only a handful of species are employed. Of the 9,000 bird species, only a few (for instance, chickens, ducks, geese, muscovies, pigeons, and turkeys) have been domesticated for farm use. Strictly speaking, all birds are edible - at least none have poisonous flesh - so it seems illogical to conclude that these are the only likely candidates. Perhaps they are not even the best.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At first sight there may seem to be little need for new species, but poultry meat is in ever increasing demand and there are many niches where the main species are stricken by disease, or are afflicted by heat, humidity, altitude problems, or other hazards. For these areas, a new species might become a vital future resource. Perhaps some could even become globally important. The modern guinea fowl, for example, is a relative newcomer as a worldwide resource (see page 120).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The birds now used as poultry were domesticated centuries ago by people unaware of behavior modification, nutrition, genetics, microbiology, disease control, and the other basics of domestication. Today we can tame species that they couldn't. In particular, the new understanding of "imprinting" may make the domestication of birds easier today than ever before. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this highly speculative concept, the birds described on the following pages are worth considering. They all eat vegetation and tend to live in flocks, which makes them likely to be easy to feed and to keep in crowded conditions. Most are sedentary, nonmigratory, and poor fliers. All but three (tinamous, sand grouse, and trumpeters) are gallinaceous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gallinaceous birds are already the most important to people. The best known are chickens, turkeys, quail, and guinea fowl. But there are about 240 other species. Most are chickenlike: heavy bodied with short, rounded wings, and adapted for life on the ground. Although some are solitary, many are sociable. Basically vegetarian, they also eat insects, worms, and other invertebrates. The young birds are extremely precocious, walking and feeding within hours of hatching. All of these are advantageous traits for domestication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Game birds are also emphasized here. Many today are considered gourmet delights, and this should give them a head start in the marketplace. Indeed, some are already being raised in a small way on game farms and are at least partly on the way to domestication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHACHALACAS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These brownish birds (Ortalis vetula and nine other species) are found throughout Central and South America, and, given research, could possibly be raised on a large scale. A sort of "tropical chicken," they tame easily, live together in dense populations, and protect their chicks extremely well. They commonly scavenge around houses and people often put out scraps to feed them.2 The chicks are easily hatched, grow fast, and can be fed standard chicken rations.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is already considerable demand for these birds. Everywhere they are found, they are prized as food. In some areas they constitute the single most important game species, and are heavily hunted to supply local communities. Although they have less meat than a chicken, it is tastier and darker.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chachalacas are very adaptable. They occur mainly around forest edges and thrive in the thickets that appear after tropical forests have been felled. They do well close to humans, and their populations are not threatened, despite much hunting. Indeed, they seem well adapted to existence around villages and towns. Although not strong fliers, they are one of the few tree-roosting gallinaceous species. Primarily fruit eaters, they also consume tender leaves, twigs, and buds, and they scratch up the ground, presumably for insects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although excitable and noisy, chachalacas become remarkably tame when fed by people. In a few cases, full domestication has almost been reached. Farmers like to have chachalacas around and have even used them to guard domestic chickens. These very raucous and fearless birds will take on all potential threats, even weasels.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GUANS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Close relatives of the chachalacas, guans5 are glossy black birds about the size of small geese. They are highly gregarious and perhaps could be raised in larger numbers. They commonly live around houses, farms, and settlements in their native region of tropical America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike most game birds, guans are chiefly tree dwellers, but they also feed on the ground. Some 12 species are known. All are relentlessly hunted for food and sport - their tameness and inability to fly far or fast making them easy targets. The rapid destruction of tropical forests threatens their populations in some parts of their range. Conservation projects and specific plans of action are being proposed for the most threatened species. Perhaps for the other species, game-ranching projects or even outright domestication might provide just the right incentive for their protection and multiplication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CURASSOWS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Curassows are also relatives of guans and chachalacas, but they are even larger - up to 1 m tall and 5 kg in weight. At least seven species are found over the vast area from northern Mexico to southern South America.6 Among them are Latin America's finest game birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It might be possible to produce curassows in organized farming or ranching. They are commonly called "tropical turkeys" because they look like and run like turkeys. Indeed, Latin Americans normally refer to them as "pavos" or "pavones," as if they were the real thing. Their plumage ranges from deep blue to black, invariably with a purple gloss, and all have rather curly crests on their heads. They are not good fliers and spend most of their time on the ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Curassows are increasingly hunted; their tropical forest habitat is shrinking, and the subsequent loss of populations is a calamity. They are special targets, not only because they are large but also because their light-colored flesh makes exceptional eating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is hope that these large wild fowls can be raised and managed in organized programs. Even now, people commonly keep them around their farms and villages. For example, on a number of Venezuelan ranches, yellow-raped curassows can be seen wandering around the cattle yards as if they were chickens.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FOREST BIRD RANCHING</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This report has intentionally focused on intensive farming - the type where people bring feed to animals in captivity. However, where this normal type of farming is of marginal value, `'ranching'' free-ranging birds may often be a more effective option. In this, the farmer simply monitors and improves the condition of the range and devises methods to harvest the birds on a sustainable basis. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Bird ranching" may today have outstanding merit, particularly in tropical rainforests. Hence, in this chapter we emphasize birds of the jungle. These might help make standing rainforests profitable producers of income, and thereby provide economic incentives to stop felling trees for cow pastures. Indeed, forest birds might become part of a whole new "salvation farming'' that makes forests more valuable than fields. It is a technique that may contribute to preserving both bird life and its vitally valuable habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MEGAPODES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Megapodes (family Megapodiidae) include some of the world's most interesting birds. They have temperature-sensitive beaks and employ nature's own heat sources as incubators. The best-known species build piles of leaves and use the heat of decomposition to incubate their eggs. The species of Papua New Guinea and Indonesia, however, take advantage of sun-warmed sand or even geothermal activity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People have long revered these birds. Aborigines in Australia, Melanesians in New Guinea, and many Micronesians all protect the bizarre nesting sites, and "farm" them for eggs. Local people consider the large eggs special delicacies, and sometimes the egg-laying sites are owned and exploited for generations without a single bird being killed for food.8</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Programs that provide sustainable supplies of eggs have been established in Papua New Guinea. One is near Mt. Tovarvar, a simmering volcano on the island of New Britain. Here, megapodes gather in large numbers to lay eggs in the hot sands. They dig until they locate sand that is exactly 32.7&Yacute;C, before laying their huge (more than 10 cm long and 6 cm wide) pink eggs. Each year the villagers dig up some 2O,OOO eggs, which are an important source of protein and cash income. The government now regulates the harvest in a way that protects the bird population while supplying a nourishing food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Megapodes are found in only a few parts of the world, but projects such as those in Papua New Guinea provide hope and guidance not only for the sustainable "ranching" of megapodes, but also for other species elsewhere. Many wild birds yield locally important products down, colored feathers, eggs, meat, and skins, and they make excellent songbirds and pets, for example. Their management on a sustainable basis may in certain cases be the key to turning local people into the most dedicated conservationists of all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PARTRIDGES AND FRANCOLINS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Partridges include many small game birds native to the Old World. They are robust, precocious, and larger than quails. Some lay many eggs - the European partridge, for example, lays up to 26 in a clutch. Newly hatched chicks are soon able to feed themselves and can fly within a few weeks, sometimes even within the first few days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Species that may make useful poultry include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The European (or gray) partridge (Perdix perdix); </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The rock partridge (Alectoris), bantamlike birds of Africa; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The chukar (A. graeca). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A native of the vast area from southeastern Europe to India and Manchuria, the chukar is stocked as a game bird in many countries. It is now produced routinely under poultrylike husbandry in many parts of the United States, not only for hunting clubs, but also for expensive food markets. The birds are generally raised on turkey rations and dress out at about 500 g after 18 weeks. They sell for more than broiler chickens and are a profitable sideline for increasing numbers of poultry farmers.9</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A group of closely related birds are the francolins (genus Francolinus), of which there are 34 species in Africa and 5 in West and South Asia. These adaptable birds are sturdy, live in a variety of habitats, and tend to be rather noisy. Basically, they are partridges with leg spurs. They are highly regarded as a food source and are hunted and trapped wherever they are found.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Francolins are much like quail, but are several times larger. Arabs introduced one of the most beautiful species (Francolinus francolinus) into southern Spain, Sicily, and Greece during the Middle Ages. However, it was hunted so heavily that it soon became extinct in Europe. More recently, francolins have been introduced to the Soviet Union.'&Yacute;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Francolins inhabit steppes, savannas, primeval forests, and mountains. They thrive in cultivated land with much cover. The clutch consists of 6-8 hard, thick-shelled eggs. In recent times at least one program to domesticate them for food has been started in Africa.11</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MALAYSIA'S MOBILE MOUSETRAP</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although the report emphasizes microlivestock as food suppliers, it should be realized that small animals - even wild ones - can have other important uses as welt The following interesting example, with possible worldwide implications, comes from recent experiences in Malaysia. *</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Certain rodents are major pests on farms and plantations. Now, however, Malaysian zoologists are finding that owls, particularly barn owls (Tyto alba), can help control them. An owl pair and its chicks annually consume 1,500 or more rodents. This is not new knowledge; indeed, on farms throughout the world the barn owl has always been a welcome guest. What is new is that Malaysians are showing how outstandingly effective this process is, and they have initiated major projects to attract and maintain these feathered friends. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Barn owls are found in many parts of the world, but were formerly almost unknown in Peninsular Malaysia. In 1969, however, a pair began nesting in an oil-palm plantation in Johore State. Since then, these birds have steadily increased in numbers and have spread throughout most of the peninsula. Today, the population is increasing remarkably quickly as more and more managers erect nest boxes for the owls to live in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The owls are proving to be a good way to remove rats and are notably effective in plantations of oil palm. They perch on fronds and fly under and between the rows of trees. A cost of $1 - $2 per hectare per year is all that is required to install nest boxes, a negligible outlay for the control of such a serious and expensive problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is believed that the barn owls hunt mainly in plantations and other agricultural areas and not in the rainforest. Barn owls are, after all primarily adapted to open spaces and not dense forest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perhaps this experience can be replicated and adopted in other locations and with other crops. Grain crops - notably rice - are particularly prone to the ravages of rodents, and one trial has commenced in Selangor State in a rice area. The concept of using owls for rodent control is also catching on in the United States. Indeed owl nest boxes are being erected in Central Park in the heart of New York City.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PHEASANTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">One pheasant, the red junglefowl, gave the world the chicken (see page 86). The other 48 species may have some potential, too. These are rarely seen forest birds; all but one are confined to Asia.13 Because they are prolific they can sustain heavy predation, and many species, notably the ring-necked pheasant (Phasianus colchicus), are constantly hunted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People in several countries have learned to exploit pheasants on farms and estates. As a result, there is a vast amount of information on how to rear and manage these birds. So far, however, it has been applied only to sport hunting in wealthy societies; the potential of raising pheasants for the mass market should now be seriously addressed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most dramatic-looking pheasant, the peacock (Pavo cristatus), is raised as a poultry species in Vietnam. The meat of the young birds is considered outstanding. In fine restaurants in New York, a peacock dinner is reputed to cost $150. Common peafowls are considered sacred in many parts of India, where they have become so tame that they are essentially domesticated. They also control snakes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">QUAIL</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic quail have been previously described (page 146)J but dozens of wild quail species and subspecies occupy many different habitats and ecological niches in almost all parts of the world. Out of all this genetic wealth only one species - the Japanese quail - is widely used. Yet many other species seem easy to raise, becoming exceedingly tame after about the sixth generation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The management and even perhaps intensive production of these various local quails might provide long-term benefits for many developing nations. Quail meat ranks among the finest.14 Some of these lesser-studied birds are more meaty than the Japanese quail or have other possibly useful traits. Much is known about rearing a few of them because they are used in sport hunting or laboratory research. The possibility of domestication, therefore, is not farfetched.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Particular quail that might be considered for domestication are the lesser-known subspecies of Coturnix coturnix. These subspecies are found in various places, including the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Europe (C. c. coturnix breeds in the area ranging from northern Russia to North Africa and from the British Isles to Siberia. In winter it migrates to tropical Africa, Asia, and southern India.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The Azores (C. c. conturbans) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The Azores, Madeira, and the Canary Islands (C. c. confisa) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Cape Verde Islands (C. c. inopinata) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- East Africa (C. c. erlangeri) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Tropical Africa, southern Africa, Madagascar, and Mauritius (C. c. africana) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Japan (C. c. japonica, the most probable ancestor of the domesticated quail)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- China (C. c. ussuriensis, a possible ancestor of the domesticated Japanese quail)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TINAMOUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Tinamous are quail-like birds of Central and South America's forests and grasslands. They are, however, much larger than quail and resemble small chickens, with plump bodies and no visible tail. There are more than 40 species, and all are much sought for food because their meat is tender and flavorful. The breast is surprisingly large, and its flesh is pale and translucent. One species, the great tinamou (Tinamus major), has been called "the most perfect of birds for culinary purposes." Frozen tinamous from Argentina were formerly sold in the United States under the name "South American quail."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tinamous are found mainly in tropical areas, but are also widely distributed in Argentina and Chile. They dwell in varied habitats: rainforests, thickets, bushlands, savannas, and grasslands up to 5,000 m altitude in the Andes. Some species sleep in trees, others on the ground. They spend their days creeping about in heavy cover, flying only when forced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At least some species tame readily. Indeed, during the nesting period males become so tractable that they can be picked up off the nest. At the turn of the century, many tinamous were raised as game birds in France, England, Germany, and Hungary. However, for reasons unknown, subsequent attempts to settle them in Europe have failed. Tinamous have been raised in Canada without undue difficulty; they showed little or no stress under captivity and there were few losses.15</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tinamous may also prove suitable for egg production. They lay clutches of 16-20 spectacular-looking shiny eggs that seem to be made of sky-blue and bright-green ceramic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SAND GROUSE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Sand grouse (mainly Pterocles species) are highly adapted to life in arid regions - desert, dry grasslands, arid savanna, and bushveld. Their entire body (including most of the bill and feet) is covered with dense down, which in the desert insulates them from the burning heat of midday and the freezing cold of night. It also protects the nostrils against blowing sand and dust.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These pigeonlike birds are found throughout the drier regions of Africa and Asia - for instance, the Sahara, Kalahari, Namib, Arabian, and Thar deserts. They live mainly on small seeds, and sometimes flocks of thousands may be seen at waterholes, flying in for a drink from up to 80 km away. For peoples of the driest spots on earth, these birds may make a useful food species: for one thing, they are not endangered. Indeed, they are proliferating as drought and overgrazing is increasing the amount of dry, desolate rangeland that they prefer. The bore holes provided for livestock have both boosted their populations and afforded a place where these wide-ranging birds can be easily captured. When nesting, sand grouse are highly vulnerable to foxes, jackals, mongooses, and other predators. Protection of the nesting sites may be the key to maintaining their populations if harvesting schemes are introduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TRUMPETERS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Trumpeters (Psophia species) might prove to be a useful species for sustainable production within tropical forests. As "tree poultry," these relatives of cranes could help provide meat without destroying the trees, as is now done to raise cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These chicken-sized birds inhabit South America's jungles.16 They are nonmigrating, ground-dwelling, and are often kept as pets, notably by Amerindians. Under human protection, trumpeters become very tame. They recognize strangers and challenge them with a loud cackle. 17 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fully adapted to the forest environment, they can run fast, but fly poorly. In the wild, this makes them easy targets for hunters. Because of this and the fact that they make excellent eating, they are approaching extinction in some areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No attempts have been made to rear these birds in numbers, but this should be tried. They feed mainly on plant materials, particularly berries of all kinds. They also relish grasshoppers, spiders, and centipedes, and are particularly fond of termites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trumpeters require trees; they completely avoid cultivated land. Thus, as the destruction of forests in South America continues, their habitat is shrinking. Although their existence is not as yet threatened, the long-term prognosis is bleak. If managed in "forest-ranching" programs, however, they might be saved from extinction and thriving populations built up. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interest in rabbits continues to increase. It is now widely recognized that the raising of small animals in developing countries has great potential as a means of improving human nutrition and economic security. The famines in Africa, Latin America, and Southeast Asia starkly illuminate the need for maximum efficiency in food production to maintain the quality of human life. Rabbit raising contributes to meeting these needs.</P>
+<P ALIGN="JUSTIFY">P.R. Cheeke, N.M. Patton, S.D. Lukefahr, and J.I. McNitt Rabbit Production </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbits are especially well adapted to backyard rearing systems in which capital and fodder resources are usually limiting factors in animal production. When rabbits are reared according to the techniques appropriate to the environment they can do much to improve the family diet of many of the most needy rural families, while at the same time supplying them with a source of income. With more advanced technology rabbit production can also help to supply big city meat markets.</P>
+<P ALIGN="JUSTIFY">Food and Agriculture Organization The Rabbit: Husbandry, Health, and Production </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g017a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part III : Rabbits</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Contrary to popular opinion, the domestic rabbit is a substantial part of the world's meat supply. Annual production of rabbit meat is estimated to be one million metric tons, and the total number of rabbits is approximately 708 million.' However, rabbits are now intensively raised for food only in temperate, mostly industrialized, nations. France, Italy, and Spain, for example, have long consumed rabbit meat; West German production was 20,000 tons each year; Hungary raises rabbits in large numbers (two of its commercial rabbitries have more than 10,000 does each); and the United States raises almost 8.5 million rabbits each year for consumption in homes and restaurants.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most developing countries, on the other hand, rabbits are not well known - at least compared with other livestock. But they have great promise there, and in recent years there has been a dramatic increase in interest. For those developing countries where information is available, rabbit meat production almost doubled between 1966 and 1980. For instance, several African countries - among them Ghana, Kenya, Malawi, Mauritius, Mozambique, Nigeria, Sudan, Tanzania, Togo, and Zambia - now have national rabbit-raising programs. A number of Asian countries - such as the Philippines, Indonesia, India, and Vietnam - are also encouraging rabbit farming. And some Latin American countries - Mexico, Costa Rica, and El Salvador, for instance - are actively promoting rabbits for subsistence farmers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghana is also extensively promoting rabbit farming. Although able to produce all the cereals its population needs, it cannot produce enough meat to satisfy demand. In response, the government organized "Operation Feed Yourself." The National Rabbit Project was created </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hares</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The common hare (Lepus europus) has not been domesticated, but it is nevertheless a major cash crop of several countries. In Argentina, for example, there is a booming, million-dollar enterprise that exports hundreds of thousands of carcasses, mainly to Germany where they are sold as game meat. For Argentine campesinos, many of whom have few sources of livelihood, trapping hares provides a vital income. In New Zealand, too, hare has become an export item.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A closely related species (Lepus capensis) is native to Africa, and perhaps could be "ranched in the same fashion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rainforest Rabbit</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The forest rabbit, or tapeti (Sylvilagus brasiliensis), is commonly eaten in its native habitat, which extends from southern Mexico to southern Brazil. It occurs in various hot and humid areas of Central and South America and probably within the Amazon Basin itself. Thus, this creature seems a possible candidate for a "tropical rabbit" that can be raised under sweltering conditions, perhaps even in rainforest regions. Although it seems to be heat resistant, it has an especially fine fur.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is now known about the tapeti. It is rather secretive and its natural history and even its range are still uncertain. However, its populations appear stable and it is not threatened with extinction. It produces litters of 1 - 5 young after a 44-day gestation, and may bear 4 litters a year. This may seem a lot, but compared with other wild rabbits, the litter size is small and the gestation period long. under this program to provide farmers with breeding stock and practical information on rearing rabbits. (To qualify for the purchase of new breeding stock, would-be rabbit raisers are required to take an intensive three-day course in rabbit husbandry, which is provided at no charge.) With both official and popular support, the rabbit's potential for Ghana has been enhanced through media campaigns complete with radio jingles (examples: "Get the bunny money!" "Grow rabbits - grow children." "Get into the rabbit habit!"), television spots, and large posters. Already, rabbit breeding is included in school curricula and rabbit meat is available in school lunches.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other countries have mounted similar campaigns. In Mexico, for instance, teachers raise rabbits in rural schools as a way of training students; scores of government officials have taken to breeding rabbits in their homes; and several army units are raising rabbits as mess-hall substitutes for costly beef, pork, and chicken. In Nigeria, farmers can now acquire rabbits from 18 government rabbit-breeding centers, which distribute thousands of animals each year. In Costa Rica, the government has similarly established a series of breeding, distribution, and rabbit-farming training centers. And in El Salvador, the technology of rabbit production is being transferred to farmers via the army.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although rabbits are ideal microlivestock in a general sense, rabbit rearing has many problems and limitations. Poor management is a common difficulty. Unlike the traditional method of keeping scavenger animals, rabbits have to be contained and cannot be left to find their own food. Raising rabbits requires more skills, more time, and much more effort than raising barnyard chickens or other familiar scavengers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For all that, rabbits produce more food than scavenging animals; they are less likely to damage crops because they are kept confined; they live exclusively on forage, which tends to grow vigorously in tropical zones; and they generally produce a more valuable product. The rabbit's potential is far from exploited, and rabbit farming will have to increase enormously before its promise for the small farms of the world is realized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is, however, an increasing concern over a recent outbreak of an exceptionally virulent viral rabbit disease - hemorrhagic tracheopneumonis, which attacks the lungs and lung tissue, killing 48 hours after the onset of symptoms. The virus, which has ravaged the animals in parts of Asia and Europe, was identified in China five years ago in Angora rabbits imported from Germany. It spread to Korea in 1986, and in early 1988 moved through southern and eastern Europe and spread as far as Egypt. It has also been identified in Mexico. Vaccination may become a future prerequisite of rabbit rearing in many countries. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FAST FOOD</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The order Lagomorpha includes more than 60 small quickmaturing, and rapidly reproducing species. It seems illogical to think that only one is useful as microlivestock. In principle, any rabbit, hare, or pike could be raised in captivity. All are clean, fast growing and rapid breeding. They are opportunistic feeders and can digest fibrous vegetation. Their meat tastes better than chicken and does not carry the stigma of rodent. The animals are small inoffensive, efficient at foraging, and generally tolerant of difficult environments. In theory, at least, they could be raised on vegetation not used by people or by many domesticated livestock.</P>
+<P ALIGN="JUSTIFY">Species worthy of exploratory research include the following.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">14 Domestic Rabbit</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g018a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The domestic rabbit (Oryctolagus cuniculus)1 is suited to small-scale production and backyard farming. It is easily maintained, requires scant space, makes minimal demands on the family budget, and thrives on plant materials that are usually disdained by humans. It utilizes forage efficiently. even coarse vegetation that is high in fiber, and under ideal conditions it can grow so rapidly that its rate is only slightly lower than that of broiler chickens.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The rabbit's capacity for reproduction is legendary. In theory, a single male and four females can produce as many as 3,000 offspring a year, representing some 1,450 kg of meat - as much as an average sized cow.3 The meat is pink, delicately flavored, and is usually considered a premium product that provides variety in the diet. It has more protein and less fat and calories per gram than beef, pork, lamb, or chicken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some breeds are raised for their wool. The long-haired Angora, for instance, yields a luxury fiber that makes a soft, lustrous fabric. It sells at high prices and makes these animals very valuable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbit pelts also bring cash. They are used in fur coats and other luxury garments. In addition, rabbit feet and tails are used in good luck charms and many curios.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits are well known for their long ears, fluffy tails, and long hind legs. Many commercial breeds are white, although colored types are sometimes chosen because of special qualities in their meat or pelts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are many breeds and much genetic diversity within and between breeds. (Almost 160 varieties are recognized by the American Rabbit Breeders Association.) However, in both North America and Europe, the New Zealand White has traditionally displaced most other breeds for commercial meat production. This medium-weight breed bears large litters, is a good milk producer, and has good mothering ability. It reproduces best under intensive farming and, among purebreds, yields the most meat. A full-grown New Zealand White weighs 4-5 kg, giving about 2 kg of meat at 8-10 weeks of age. Large breeds include the Flemish Giant or the Checkered Giant, which weigh more than 6 kg at maturity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hybrids are rapidly replacing purebreds in Europe for commercial production. Specific crosses of breeds have been shown experimentally to be more productive overall compared with purebred New Zealand Whites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Different meat breeds are preferred in various countries. For example, in Ghana the most popular are Flemish Giants, New Zealand Whites, Yellow Silvers, and Checkered Giants; in Tanzania and Nigeria, New Zealand Whites and Dutch are preferred; in China, Chinchillas and Japanese Large Whites are the most widely consumed. Some smaller breeds - for instance, the Polish - are also valuable for husbandry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some Third World strains have already evolved. They show high tolerance to local conditions (for example, the Baladi - the main strain of the Sudan and the Near East - and the Criollo of Mexico). The Baladi has a small body and relatively low production, but it is hardy and tolerates harsh conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Specialized breeds have been developed for wool, fur, and laboratory research. The Angora wool breed has already been mentioned. The Rex breed produces a high-quality pelt used in furs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The wild ancestor of the domestic rabbit was originally restricted to Spain and Portugal. Today, its descendants are found worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Plentiful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domestic rabbits are best suited to temperate climates, but they do well in tropical and subtropical conditions if hutches are constructed and sited to take advantage of shade and cooling breezes. Ventilation is important (but care must be taken to avoid direct exposure to cold drafts). Prolonged exposure to temperatures higher than 30&Yacute;C reduces both fertility and growth. Apparently, all breeds tolerate heat equally well. However, heat is shed through the ears, and the longer the ear, the more heat a rabbit will tolerate. Lop-eared varieties withstand heat poorly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits eat fibrous vegetation. In addition to normal feces, they produce special droppings called cecotropes. Softer and smaller than the regular fecal pellets, they are excreted in clusters and are swallowed as soon as they are eliminated. Cecotropes are rich in bacterial protein, and this double digestion (coprophagy) enables the animals to utilize the fermentation products formed in the cecum. This process is rather like that of ruminants, and rabbits are sometimes called pseudoruminants.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeding begins at 4-6 months of age and may continue up to age 4, occasionally to age 6. Gestation takes 28-32 days. Females can conceive within 24 hours after giving birth and can produce a second litter merely 4 weeks later. With good feed and early rebreeding, 9 or more litters a year are possible. (Such a rate is only achievable under exceptional management, however.) Litter size depends on breed and body weight. Small breeds average 4 young per litter; large breeds 810. Births occur at any time of the year, but production slackens when the weather is exceptionally cold or hot, when feed is scarce, or when days are short. Extremes of heat or cold can also affect the survival of the young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbits raised under subsistence conditions are likely to produce 4 or 5 litters a year, with an average of 5-8 young per litter' depending on management and feed quality.5 Annual production of about 20 weaned offspring per female per year under tropical and subtropical conditions is common. The young remain in the nest until they are 2-3 weeks old. Their eyes open at approximately 10 days of age. About 4 months are required to produce a 2-kg market rabbit under subsistence conditions. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits that receive human handling are very gentle and can be trained to live inside people's houses and even use a "litter box."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits are multipurpose animals yielding the following products:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Meat. Delicious hot or cold, fancy or plain, it can be breaded and fried, broiled, baked, or barbecued.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Wool. The fineness of rabbit hair is an asset in the production of wool, which is the plucked or shaved hair of the long-haired Angora breed. It is usually mixed with fine Merino sheep wool to give more substance and to improve its wearing quality. An average Angora rabbit produces about 850 g of wool each year. (Some specimens produce as much as 1,000 g.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Fur. The fur is dense.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Leather or vellum. Rabbit hide has the tension and strength required for tiny drive-belts in tape recorders and other delicate machines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Fertilizer. Rabbit manure often contains high proportions of nitrogen, phosphorus, and potash, and it comes in convenient drypellet form.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Tourist charms. In many societies, rabbits are connected with good luck. Feet and tails are used for car decorations, key chains, charms, and mementos that appeal to tourists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbits are also used in biochemical and physiological research.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits can be housed in hutches ranging from sophisticated commercial cages to simple packing crates with a few ventilation holes and rough troughs for food and water. In all cases, watertight roofing is essential. A floor space of only 0.25 m&Yacute; is sufficient for one rabbit, but about 1 m&Yacute; is recommended for a female and her young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Starting small-scale rabbit production is generally inexpensive. An almost infinite variety of backyard feeding and drinking equipment can be made from various scrap items, such as old bottles. The main criteria are that cleaning should be easy and spillage minimized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In practice, diets can be based largely on herbage: grass, leaves, legumes, crop residues, and kitchen scraps. However, the diet must be wholesome, and caged rabbits fed on forage usually need some grain or agricultural by-products (rice bran, for instance) as a dietary supplement. Supplementation is particularly important for newborns and lactating females, whose diet must contain about 16 percent protein and at least 18 percent fiber. When "noncommercial" feeds are used, salt must be added to prevent salt deficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of higher protein content, legumes (for instance, alfalfa, cowpea, vetch, or pea) are better than grass. Alfalfa is particularly valuable, and in the Sudan and Mozambique it is already grown extensively for feeding rabbits. On diets consisting of alfalfa and rye grass, weaned New Zealand Whites have demonstrated growth rates of 38-39 g per day in animals weighing up to 2 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rabbits, as mentioned, can utilize almost any type of edible vegetation. Also, despite their diminutive size, they can collectively produce as much meat per unit of forage as large livestock, or even more (see page 183).6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is much genetic diversity. Differences in growth rate, fertility, maternal ability, milk production, disease resistance, heat resistance, and other features have been noted. This is useful, since a wide genetic base enhances the likelihood of success of selection programs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbits are easy to handle and can be raised under primitive conditions. They require little financial investment and their husbandry is easily accomplished in the home by women and children.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal's rapid reproduction is a big advantage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Tropical conditions produce special problems. There, rabbits must be protected from heat and rain. Stress brought on by high temperatures, high humidity, and wet conditions can lead to respiratory disorders and even sudden death.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most diseases are caused by poor management. Dirty or wet cages lead to diarrhea, sores, mites, and ringworm, all of which can cause serious losses. Enteritis (diarrhea) often kills 20 percent or more of all rabbits before they attain market age and weight. A major disease problem in most countries is coccidiosis, which is particularly harmful to young rabbits. Again, damp and unsanitary conditions increase the susceptibility; better management can control it. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some countries - notably Australia and New Zealand - escaping rabbits have become a serious menace and have destroyed crops and grazing lands. Because of this threat, it is illegal to import rabbits into some countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present, many people are unaccustomed to eating rabbit. Indeed, where commercial ventures have been established in areas with an otherwise plentiful meat supply, there have been financial failures. However, where rabbit meat is familiar, there is usually great demand for it. Also, in poorer areas where animal protein is in short supply, the tasty pink meat is widely appreciated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HOW RABBITS WERE DOMESTICATED</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">For 30 or 40 million years the wild species Oryctolagus Cuniculus lived only in the area that today is Spain. Caves there contain Stone Age drawings of it. Phoenician traders landing on the Iberian Peninsula in about 1100 B.C. found huge numbers of these wild rabbits. The little animals were unknown to them and they mistook them for the hyraxes they had seen in Africa. (Although small and rabbitlike, the hyrax is actually related to elephants.) Since the Semitic name for hyrax was shaphan ("one who hides"), the Phoenicians named the peninsula l-shepan-im, from which the Latin name Hispania developed. Thus, "Spain" actually means "island of hyraxes," even though these African animals have never occurred there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the rabbit's reproductive powers and adaptability it is surprising that it hadn't spread beyond Spain, but dense forests covered most of Europe after the last Ice Age. The rabbit, which is suited to open country, only spread rapidly after man had cleared most of the trees. Even then, the natural spread was slowed by the Pyrenees mountains blocking the way into the rest of Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ancient Romans became acquainted with rabbits after they invaded Spain, and they eagerly added wild rabbit meat to their banquets. The meat was so popular that around 1 A.D. Roman voyagers released a pair of rabbits onto the Balearic Islands. In time, these produced so many offspring that the islanders had to appeal to the Roman emperor for help. They even asked to be moved to another country if the emperor could not get rid of the plague of rabbits!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eventually, Romans in Italy, France, and other parts of the European mainland began raising rabbits for meat. They kept them in special cages called leporaria. Their rabbits were probably not truly domesticated; instead they were netted in the wild and caged for fattening before being prepared for the table. The Romans had little incentive to domesticate an animal that could be so easily captured.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tne rabbit was the last farm animal to be domesticated. It seems likely that this did not begin until the Christian era when monks in French monasteries began taming rabbits. In those days, rabbit embryos and newborn young were considered delicacies, called "laurices." In 600 A.D. the Pope declared that laurices were "not meatp," and permitted them to be eaten during fasts and in monasteries of strict discipline where meat was forbidden. Within a few years, the animal was domesticated, </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Government-sponsored rabbit-research stations and programs are found in France, Germany, Italy, Spain, the United States, and the United Kingdom.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rabbit husbandry is well known, but much basic research is needed; for example, specific nutrient requirements, breed comparisons, disease control, reproductive management, and efficient housing and equipment. There is a particular need to reduce the labor required for feeding, breeding, caging, and cleaning.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With the increasing number of rabbit programs in Africa, Asia, and Latin America, there is a need to share information and ideas among the various countries. The exchange of experiences with rabbit breeding, health and nutrition, and the practical experiences and field studies could be of great value.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Further research in rabbit nutrition is necessary to identify nutrient requirements more precisely. Moreover, links between nutrition and disease should be clarified.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Further research into the cause and prevention of enteritis is needed. (At present, this condition is prevented by maintaining a fiber level in the diet of at least 18 percent and keeping the energy level relatively low.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Legume shrubs could be an answer to the feed problems in the dry season. Deep-rooted shrubby legumes, such as gliricidia or leucaena, remain green well into the dry season and have high protein contents. Rabbits find the leaves of leucaena palatable (see companion report Leucaena: Promising Forage and Tree Crop for the Tropics. National Academy Press. Washington, D.C. 1984), and they are fairly resistant to mimosine (a sometimes toxic amino acid found in leucaena foliage). More research on this promising approach is needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted earlier (page 181), a killer virus has recently appeared. Studies into its epidemiology and control are most important. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Outsiders who hope to improve conditions in underdeveloped areas, sometimes . . . introduce new food avoidances to the communities they came to help [if outsiders] show repugnance toward consuming goats, . . . rats, . . . crows, insects, intestines and blood, then the people they are educating may likewise give up those . . . foods and lose valuable proteins.</P>
+<P ALIGN="JUSTIFY">Calvin W. Schwabe</P>
+<P ALIGN="JUSTIFY">Unmentionable Cuisine</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">You can count on the fingers of one hand the domestic animals that produce virtually all of mankind's meat and milk - a selection made more than 10,000 years ago by our Neolithic ancestors. Yet the earth teems with thousands of species of animals; why limit ourselves to cattle, pigs, goats, and sheep? Given the world's shortages of energy and water and arable land, why not try to domesticate wild animals? The effort would save many species from extinction, provide the world with more food, and introduce gentle farming to fragile environments.</P>
+<P ALIGN="JUSTIFY">N.D. Vietmeyer</P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY"><center><img src="g019a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part IV : Rodents</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rodents are the world's most widespread, adaptable, and prolific group of mammals. They reproduce well, grow fast, learn quickly, and adapt to a wide variety of local conditions. Many convert vegetation into meat efficiently, digesting some fiber, even though their stomach, like man's, is a simple one.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It seems probable, therefore, that some species would make suitable microlivestock - a notion supported by the previous domestication of the guinea pig, laboratory rat and mouse, gerbil, and hamster. Indeed, "ranching" rodents might be an effective way to increase food supplies in remote areas. It could also be a mechanism to ensure the survival of rare rodents whose natural habitats are being rapidly destroyed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RODENTS AS FOOD</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Rodents are already common foods in many countries and are valued items of commerce. It has been estimated that 42 of 383 cultures eat rodents.! But the fact that they are a major meat source is almost unrecognized. This is due in part to cultural misunderstanding. Rodents suitable for human food or other products do not live in filth, like common rats. They are clean and vegetarian. Like rabbits, they eat grass and grains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some regions of the world, cooked rodent meat is regarded as the epitome of dining. In many countries, local rodent species are the most eagerly sought meats. City markets in different parts of Latin America carry guinea pig, pace, capybara, and vizcacha. Markets in Asia may carry rice rats, cloud rats, and bandicoot rats. Those of rural Africa are filled with "bushmeats" - usually including grasscutters, giant rats, and several other rodent species. These are often preferred to the meat of domestic stock and fetch higher prices than beef. And the amounts of rodent bushmeat available are not minor. In one year, for example, hunters in Botswana have brought to market 3.3 million kg of meat of the rodent called springhare (see page 278).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fondness for rodent meat is not restricted to the tropics. In the United States, squirrel was once a much sought treat. Fat, nut-fed grey squirrels went into Brunswick stew, which has been called the most famous dish to emerge from the campfires and cabins of Colonial America. Thomas Jefferson liked it. Today, squirrel is the country's number two game animal (after deer), and many are still eaten.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ancient Romans kept fat dormice in captivity, serving them as a delicacy. "The fat dormice are fattened up in barrel-like pots like those in country houses," wrote Varro (116-27 BC). "One feeds these animals large amounts of acorns, chestnuts, or other nuts."2 This small rodent remains a prized food in Europe and still appears on tables in certain areas. The meat is regarded as a delicacy because it tastes of almonds and other nuts. Often it is roasted, broiled, and cooked with its cracklings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rodents have seldom been included in livestock programs or economic development plans. Yet human appetite has actually caused the extinction of a number of species. Caribbean Indians ate several endemic rodents (one of which was as big as a bear), and may have caused several species to become extinct just before the time of Columbus. Others may soon follow the same dismal route, including the beautiful cloud rat of the Philippines, the hare-like mare of Argentina, the vizcacha of southern South America, and the gentle hutias of the Caribbean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guinea pig is described in a later chapter, but as it is the epitome of a rodent microlivestock species, some historical background is given here. It was domesticated for food use at least 7,000 years ago, probably in what is now the central highlands of Peru and Bolivia. With only llama and deer available, the prehistoric Andean peoples had few readily available sources of meat. They adopted wild cavies, and found that these rangeland rodents (which are more closely related to porcupines than to rats or mice) were gentle, manageable, and easy to rear. By the time the Spaniards arrived in the 1500s, the "cuy"  (pronounced "coo-ee," like the faint cry it makes) was a major food from  Argentina to the Caribbean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This impressed the conquistadores, who introduced cuys into Europe,  where they also became a delicacy.3 Within a century, these easily  transported animals began to appear on tables in many parts of the  Spanish empire. Guinea pigs are now reared in campesino huts in the  mountains of central Mexico, in the Philippines, and in several African  nations, along with other areas of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Elsewhere, guinea pigs came to be used only as house pets and  laboratory animals. Although during World War II Mussolini's  government urged Italians to keep them to supplement their meager  meat rations, their use as food was largely ignored in most parts of the  world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DOMESTICATION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The idea of domesticating rodents may seem radical, but  domestication projects are already under way with capybara in  Venezuela (see page 206), pace in Panama (see next page and page  262), giant rat in Nigeria (see page 224), and the grasscutter in Ghana  (see page 232). Rodent husbandry is not complicated and the animals'  environmental requirements seem relatively simple and easy to satisfy.  Moreover, rodents are not usually fastidious feeders, and being  essentially vegetarian will readily accept a wide variety of commonly  available foodstuffs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As with most animals with which man is in close contact, rodents can  transmit human diseases.4 With care, however, managed rodents need  not be any more dangerous to care for or to eat than pigs or  horses - both of which are worldwide food resources.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DOMESTICATING RODENTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">To domesticate the pace (see page 262) would seem to be impossible. These large rodents of Central and South America are nocturnal and fiercely territorial; they have low fecundity and take 10 months to reach weaning, and they have tender skin that is easily damaged Most researchers have written them off as candidates for domestication. But at least two have undertaken to beat the odds. We present the findings of one of them here to show that, using modem techniques, even species that normally fight each other to the death on sight are potential farm animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Through years of studying paces in Panama, Smithsonian biologist Nicholas Smythe has found that with care and planning the aggressive behavior can be so radically altered that the animals become calm. Indeed, some become almost loving. Newborns, Smythe found, undergo "imprinting" and when he places them with docile adults or with humans, the fierce territoriality never develops. He nurses newborns on "surrogate" mothers that have been imprinted on people. The youngsters then welcome human company and, if fumed out of the cage, return there voluntarily. "It's difficult to imagine a more manageable animal," Smythe said. "Technically speaking they are behaviorally indistinguishable from traditional domestic animals."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As of this writing, Smythe has three generations totalling about 50 individuals, and has several "families" of gentle paces living together in harmony. He has observed that they lose their nocturnal habit and, although they live mainly on fruits in the wild, they readily eat leafy vegetables and other foods in captivity. His captive specimens have recently begun to breed. The offspring remain docile, but they have so far averaged only a little more than two young per female per year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"If we can just double the reproduction rate, then raising paces can compete economically with raising cattle," Smythe explained. "The potential for a bigger brood is all in the animal's anatomy, and if successful, paces in the wet tropics could produce as much protein as cattle."*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacas need the shade and protection of the forest. Thus, pace raising might provide an alternative to cutting down rainforests for cattle raising. Instead of toppling trees and planting pastures, people could farm paces in the forest, and perhaps make as much or more money at the same time. In tropical America, the ready acceptance of pace meat is a near guarantee that all they produce will be snapped up at premium prices. In the past, many territorial and aggressive species have been dismissed as being impossible to domesticate or manage. But Smythe has demonstrated that with imprinting and other methods of behavior modification, these need be dismissed no longer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indeed, the pace may already be becoming a new domesticated species. In the first stage of his experiments, Smythe had to train his captive-born paces to be social and nonaggressive. Subsequent generations, however, need no training adopt the new behavior patterns of the parents, and do not revert to aggressive asocial behavior. By the third generation, they have become as accepting of, and indifferent to, people as cattle or sheep. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">15 Agouti</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g020a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among the best known of all animals of the American tropics, agoutis (Dasyprocta species)' are prolific rabbit- or hare-sized rodents that are probably easily farmed. They are valued for food and are hunted throughout most of their range. Indeed, agouti meat, once common in Latin markets. is now difficult to find because of indiscriminate killing. Agouti hunting is already prohibited in Brazil; restaurants in Belem, for example, once offered a variety of "cotta" (agouti) dishes at prices equivalent to those of choice filet mignon, but since the early 1970s they have been banned from serving it. Other countries will probably have to institute similar bans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agoutis are active, long-legged, and high-strung. They flee in panic at the slightest alarm. They do not climb but they do burrow occasionally, being essentially specialized ground-dwellers that live in tropical forest regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There have been no organized scientific attempts to raise these swift, shy animals in captivity, but Latin Americans sometimes keep them as "domestics," especially in parks and large gardens. (Agoutis are well known, for instance at the Goeldi Museum in Belem, Brazil.) These animals seem to tame easily, and could perhaps be mass produced on a large scale like rabbits or guinea pigs. They make affectionate pets, sometimes refusing to return to the wild. A research project on captive breeding of two local agouti species (Dasyprocta mexicana and D. punctata) for food is already under way in Tuxtla Gutierrez, Mexico.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most of lowland, tropical Latin America and the Caribbean. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agoutis are delicately built, graceful, nimble, and beautifully proportioned. They have slender bodies, short ears, and look somewhat like a rabbit that has been "jacked up" in back. Generally, adults are 40-60 cm long and weigh 2-5 kg. Some are even bigger.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They run well and are good jumpers. From a standing start an agouti reportedly can leap as high as 2 m or as far as 6 m; however, as long as they are well fed, there is little problem keeping them behind a wall only 1 m high.2 Reportedly, they sometimes climb easy-sloping trees to collect green fruits, but researchers studying Central American agoutis report that they are strictly terrestrial.3 They swim well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The body hair is thick, coarse, and glossy: pale orange to black on the back, and white to yellow on the belly. Some species have faint stripes, and some have a rump that contrasts with the rest of the back. The short tail is partially concealed under the long body hair.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agoutis occur over a vast area from southern Mexico to Paraguay, including many islands in the Caribbean.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Because they occasionally damage sugarcane plantings and because the meat is particularly tasty, people hunt agoutis relentlessly, especially near cities and towns. Now, in the l990s, they are becoming rare because of excessive hunting and habitat destruction. Many Latin Americans have never heard of them. In Mexico, for instance, there are few places where agoutis survive, and Dasyprocta mexicana may become extinct if habitat destruction and overhunting continue in its restricted range. In Costa Rica and Panama, agoutis occur only where there is little or no hunting or human interference.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">From sea level to elevations of at least 2,500 m, the adaptable agouti lives in many habitats: moist lowland forests, dry upland forests, thick brush, and savannas. However, although they thrive in secondary growth areas, they are mainly forest dwellers. Nonetheless, they often enter fields to forage, and young animals occasionally are seen in open areas such as grassy stream banks and cultivated fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agoutis shelter in hollows among boulders, in riverbanks, or under tree roots. They also hide in heavy brush and sometimes in holes dug out by other species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These herbivores eat seeds, fruit, stalks, leaves, roots, and other succulent plant parts, as well as occasional insects and fungi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They seem to mate twice each year. The estrous cycle is variable, but is only about 34 days long. The young are born after a gestation period of 3.5-4 months. Usually, there are twins; however, single births and triplets have been recorded. Newborns are fully developed and are able to run around within hours. They start feeding on solids within a few days. Puberty occurs at about 9 months of age. Life expectancy is 10 years or more.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the wild, agoutis are shy and retiring. Every sense seems constantly triggered for instantaneous action and sometimes they become hysterical. If danger threatens, they usually "freeze," but when discovered they stamp their feet as an alarm signal and dash away, nimbly dodging obstacles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite excessive timidity, they can be violent among themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In undisturbed forests, agoutis are diurnal and are often seen. But around villages they become nocturnal, as a means of self-preservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the most part, these rodents live in loosely formed pairs, with previous litters living around their territory as "satellites." There is some "bigamy," some "philandering," and some "divorce."5.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite their long claws, they display much finger dexterity. To eat, they usually sit erect, crouching on their haunches and holding the food in their forepaws. If it has a skin' they carefully peel it before starting their meal. They save some nonperishable foods (nuts, for instance) by digging holes in scattered locations, dropping each one in a separate location, stamping it down, and covering it over. This behavior helps disperse the seeds of many species of trees so that agoutis benefit tropical forests and reforestation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p203a.png"></center><br>
+ figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, agoutis are popular game animals. They are often hunted with dogs that even follow them into the burrows. Agouti meat is tasty, although it is usually said to fall short of the meat of the pace (see page 262) because it is leaner and gamier.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agoutis adapt well to captivity. With appropriate care they can be bred without difficulty.6 The nervousness that is pronounced in nature is quickly lost in captivity. The young become tame pets. They can be fed on foods such as leafy vegetables, fruit, potatoes, and bread scraps. Although many wild specimens have become nocturnal, captives readily readapt to daylight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Being entirely terrestrial, agoutis require no trees, but they do need space. Given enough area, they get on well (with each other and with different species), and they breed freely. To avoid fighting, it seems necessary to separate females from males at puberty. Probably removing progeny from breeding pens at weaning could also help avoid most of the interpersonal aggression. In large areas with plenty of cover (banana plants, for instance), groups can be kept, but breeding may be disappointing. Husbandry may be most appropriate in large enclosures (50-100 agoutis) with some animals then removed to small cages 0.5-1 m&Yacute; for selective feeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACOUCHIES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Close relatives, the green and red acouchies (Myoprocta acouchy and Myoprocta exilis) also deserve study. These are smaller animals with longer tails, bearing a little plume of white hairs. Although even more delicate and hypersensitive than agoutis, they can be kept in captivity and breed well. They then become less nervous and are easily handled. Acouchies. show remarkable intelligence and even some affection for those they trust. They frequent rainforests, but are rare or even absent in disturbed areas. Adults weigh up to 1.5 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The general biology (diet, reproduction, activity rhythm), is almost the same as that of the agouti, but they live in smaller home ranges (0.6-1.2 hectares versus 2.5 hectares for the agouti) and travel singly, although belonging to a well-established family unit. Adult males tolerate the juvenile males. They occur only in Colombia, the Guianas, Ecuador, Peru, and Brazil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Farming methods would probably be the same as for the agoutis, but acouchies always need plant cover.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agoutis are appropriately sized: a dressed carcass can weigh 1-3 kg. The meat is good, and large commercial undertakings in urban centers could profit from the ready market that already exists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are prolific: females can produce up to two litters a year, each litter averaging two offspring. In protected areas, populations may grow fast.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These forest dwellers might provide a source of meat and income without destroying the forests in favor of cattle pastures. Also, they thrive in disturbed areas as long as there is some cover. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Experiments in Brazil show that agoutis are highly susceptible to foot-and-mouth disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals might become pests: they eat the roots, leaves, and fruit of agricultural crops and occasionally damage sugarcane and banana plants. However, current experience suggests that if they escape captivity they are quickly caught by hunters and do not reach pest levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Live agoutis have strong-smelling anal glands that may be offensive to breeders or could contaminate the meat if the animals are carelessly handled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where the rainforest is destroyed, the agouti population is destroyed. The animals were once well known throughout Latin America, but not anymore. In some areas, therefore, wild breeding stock may not be locally available. Moreover, people may have become sufficiently unfamiliar with them that their value may no longer be appreciated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In captivity, they can be the prey of large birds such as eagles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The taxonomy of agouti species needs clarification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Husbandry experiments are required, including studies on topics such as:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Nutrition;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Growth rate;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Shelters and enclosures;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Reproduction; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Techniques for catching, moving, marketing, and managing the animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One area where agoutis might profitably be raised is in enclosures in palm plantations. Palms such as the babassu provide food, shade, and shelter, while fallen and rotten logs offer secure retreats from predators. This deserves investigation.8</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Instead of clearing vast areas of rainforest for cattle pasture, as is being done in much of Latin America, people might well "farm" agouties in the forests. Few of the settlers flooding into such regions can afford, let alone raise, beef. Small-scale agouti farming offers a promising and inexpensive alternative that would be gentle on the fragile land. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">16 Capybara</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g021a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The capybara (Hydrochoerus hydrochaeris), the world's largest rodent, can be as big as a sheep and weigh as much as a small person. Its natural habitat is the environs of South America's rivers, marshlands, and swamps, where it feeds on the grasses and reeds that grow near water.1</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its size, tasty meat, valuable leather, and rapid reproduction, the capybara is a candidate for both ranching and intensive husbandry throughout the hot and humid lowland tropical regions of Latin America. It seems easy to handle. It is commonly raised in zoos or occasionally as a pet, and has, in at least one instance, been proven successful in large commercial herds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In floodplain ecosystems, capybaras complement cattle because they prefer to graze swamp grasses rather than the dryland grasses on which cattle feed. They have simple stomachs, but are one of the more efficient herbivores. Although they are "selective feeders" that eat lush waterside grasses "preserved in quality" by the water, they also graze pasture, usually selecting new growth that is often too short and scattered for cattle, with their large muzzles, to eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The floodplains of the South American subtropics and tropics where the animal is indigenous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although they have blunt, horselike heads, capybaras look like gigantic guinea pigs. They are ponderous, barrel shaped, and have a tail too small to be seen from a distance. Their skin is tough and covered by sparse, bristlelike hairs: the color above is reddish brown to gray; beneath, it is yellowish brown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The front legs are shorter than the back. Slightly webbed toes - four on the front feet and three on the back - make them good swimmers. They dive with ease and can stay underwater for up to five minutes. They also move nimbly on land.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The capybara is extremely large for a rodent. In size and color, it looks much like a pig. Often more than 100 cm long and 50 cm high at the shoulder, it can exceed 50 kg liveweight. Indeed, specimens weighing up to 90 kg have been reported.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Before livestock were introduced, the capybara grazed widely over riverine regions throughout South and Central America. Today, it is found in the flooded grasslands from Panama to Paraguay. Mainly, it occurs in the watersheds of the Orinoco, Amazon, Paraguay, and Parana rivers. High population densities exist in the Pantanal of western Brazil and on the Llanos floodplains of Venezuela and Colombia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">There are few precise population counts, but capybaras can occur in large numbers.2 However, in many areas they appear to be on the verge of extinction, being deliberately eradicated by farmers who think they compete with cattle and transmit diseases. Also, in some areas illegal hunting goes on year-round and great numbers are killed. The animals are particularly vulnerable during the dry season, when they concentrate around the diminished river channels and water holes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, most capybaras live in swampy or grassy areas bordering rivers. However, some are found in other habitats, ranging from open plains to tropical rainforests. But even here they stay near ponds, lakes, streams, and swamps, and never venture much more than 500 m from water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p210a.png"></center><br>
+ The capybaras native range</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The capybara, like all rodents, is a simple-stomached animal, but it is a true herbivore. Its digestive system is especially adapted for fibrous materials. The large cecum - the site of enzymatic digestion serves a function like that of the rumen of sheep, cattle, and goats. It has a digestive capacity similar to that of a sheep's rumen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like rabbits and all the rodents, capybaras are coprophagous. That is, during the morning hours when they are resting, soft feces from the cecum are passed a second time through the digestive system.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contributing to the animal's digestive ability is its efficient mastication. It chews its forage seemingly incessantly, reducing it to extremely small particles before it is swallowed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under natural conditions, the females annually bear 1 or 2 litters, each averaging from 4 to 6 offspring. Birth weight is between 1 and 2 kg, depending on litter size and sex. Both males and females reach sexual maturity when they reach a liveweight of 30 kg or more usually between the first and second year of life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Capybaras are intelligent, shy, inoffensive, and harmless. In undisturbed ecosystems, they are gregarious and live in family groups of up to 30. The young follow the mother about for many months after birth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike most rodents, they do not construct dens, but the groups have specific resting areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are both diurnal and nocturnal and, like many herbivores, they graze at daybreak and dusk, and perhaps also at midnight. They spend the morning resting in weeds on riverbanks, and at noon they cool off by bathing for an hour or so before grazing. They may feed belly deep in water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capybaras wallow in mud, allowing it to dry on their skin before bathing again. Mange can develop in captivity when they cannot take a mud bath.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When startled, a capybara barks loudly and dashes away, but after running 200 m or so it tires, slows down, and may lapse into hyperthermia. At that point a hunter can easily catch it. However, if the animal reaches water, it usually eludes the pursuer because it swims so well - especially underwater.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Capybara meat is white and has qualities and properties (such as high emulsification) that might allow it to compete with pork and other meats in the food industry. Spanish-style sausages, Italian-style mortadellas, frankfurters, and German-style smoked chops have been produced experimentally.4 However, at present, the meat is mainly consumed only in the dried and salted form. It is particularly popular in Venezuela, where more than 400 tons are sold every year, especially during Easter festivities.5 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The capybara's hide is one of the best for glove making. This luxury product, known in international commerce as carpincho leather, fetches high prices on European markets because it is more heat resistant than most leathers and because it stretches in only one direction. This one way grain allows gloves to stretch sideways without lengthening and looking sloppy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The capybara appears suitable for raising as a livestock animal. Amerindians traditionally collected capybara orphans during the hunting season and raised them until needed for food. Capybara breeding was reported in Brazil as early as 1565.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Modern attempts have been made towards domestication. Researchers at the Institute of Animal Production in Venezuela, for instance, started a breeding program in the 1970s using 20 females and 5 males. Since that time they have continuously kept capybaras in confinement. Through selection and management, they have improved the reproduction of captive animals. The current aim is to get 16 offspring per mother per year. Newborns are weaned after 5 weeks and the mother is returned to the breeding pen.6 In Colombia, similar work is in progress, and guidelines for raising capybaras on breeding farms have been published.7 In Brazil, research has been carried out to study capybara nutrition, genetics, management, reproduction, and social behavior in total confinement.8</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Throughout South America, the price of beef has increased greatly within the last few years, thereby providing a new incentive for capybara husbandry. It has also forced many campesinos to eat more wildlife, which adds another incentive for producing capybara meat on farms and thereby perhaps helping to relieve pressure on the wild stocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When tame, the animals are amenable to handling without physical restraint. They are so tractable that in Surinam a blind man once used one as a guide animal. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capybaras can be raised on a variety of readily available vegetation: leaves, roots, fruits, and vegetables. They thrive in coarse grasses, if given opportunity to select nutritious parts. Their large incisors allow them to bite off short grasses that many herbivores cannot use. For instance, they eat "capybara grass" (Paspalum fasciculatum) that is abundant on river edges in Venezuela and is normally too short for cattle to graze. This makes for low-cost feeding and utilization of a resource that is otherwise unused.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capybaras are at home in hot, humid environments and are fully adapted to life on the tropical floodplains and seasonally flooded savannas. They thrive in extreme climates where cattle struggle, such as in the parts of the lower Paraguayan Chaco where summer temperatures reach 45&Yacute;C.9 An ecological benefit to raising capybaras is that there is no need to alter habitats by introducing exotic forage plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They reproduce quickly. Age at first conception for females is about 1.5 years, and the time between parturitions is generally shorter than that of goats or sheep in the tropics. Young capybaras grow so fast that in 18 months they can reach a liveweight of more than 40 kg. In their natural conditions, they are more disease resistant than cattle. The annual productivity is said to exceed that of cattle in many parts of its range.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This species is already so widely eaten in South America that the meat from farmed animals should be readily acceptable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Capybaras occasionally raid fields and can harm sugarcane, rice, bananas, sweet potatoes, cassava, corn, and other crops. In many parts of Brazil, they are considered agricultural pests and are shot.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Confining these animals in high density may create serious problems. Infectious diseases and parasite outbreaks seem to be worse than those that occur with conventional livestock. Aggression might prove a limitation to capybara husbandry: it is almost impossible to cage two adult males together or to introduce new animals to an existing group.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals may transmit disease to people and livestock. They can harbor foot-and-mouth disease and are known to be susceptible to brucellosis. They also carry a form of trypanosome, Trypanosoma evansi. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Compared with cattle, capybara use only a small proportion of the total plant biomass. They are largely selective feeders, and for satisfactory performance must have sufficient area to select the plants they need. If placed in a paddock of only coarse grass, most will eventually die. Like goats and gazelles, capybara probably select a diet that is at least 15 percent richer in crude protein than a typical cattle diet.'&Yacute;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">High mortality has never been observed in Venezuela, but keeping the animals alive on a farm in some areas may not be easy. In one trial, more than half (55 percent) of the capybara died of disease, and a few of septicemia (the result of wounds incurred during fights), but most apparently of trypanosomiasis. Other losses were caused by speeding vehicles (29 percent), poaching (6 percent), and predation, mainly by jaguars (12 percent)."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">It is important for researchers to undertake the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Gather specimens from different regions for comparative evaluation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Assess experiences of zoos and farms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Undertake nutritional trials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Initiate captive breeding trials - measurements of growth rates, space requirements, feed needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Characterize the animal's productivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Study the capybara's basic physiology and production potentials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Investigate biological factors, such as reproductive physiology, and social behavior (both in the wild and under controlled conditions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Determine the factors influencing capybara reproduction, growth, and development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Determine the animal's adaptability and economic merit in various farming systems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Study the influence of environment on reproduction rate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Determine their complementarily with water buffalo or other ruminants that normally use swampy habitats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Determine relative causes of mortality (such as diseases specific to capybaras) and predation (especially of the young) by spectacled caiman, crested caracayes, black vultures, and others. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">17 Coypu</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g022a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The coypu' (Myocastor coypus) is an aquatic rodent native to South America. It has been called the "South American beaver," but its size is actually closer to that of a small dog or an agouti. It seems suited to be a microlivestock species because, compared with most rodents' it has a large body size and a relatively high reproduction rate. Moreover, it is easy to manage, and there is much literature on how to raise it in captivity.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fur is the main item of commercial value. In the late 19th century, it was in such high demand that the animal was nearly exterminated. However, in 1922 Argentineans began raising coypu in captivity and this practice spread through South America and to other regions. In many European countries and in various locations in the United States some specimens escaped or were released, and coypu have become established in the waterways.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu meat is tasty and is consumed in many regions of South America as well as in parts of Europe. Because of the absence of musk glands, the meat is free of the "gamy" flavor found in squirrels and rabbits. It is moist, fine "rained, medium light in color, and firm. It is one of the mildest and tenderest of wild meats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This animal has been widely distributed, but its area of safest use is within its natural range in South America. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The coypu is adapted to a semiaquatic existence and has webbed feet, valvular nostrils that can be closed to keep water out, and underfur that remains dry even under water. Its long, powerful claws on the forefeet are used for grooming, excavating burrows, and digging up and holding food. The tail is slender; the extremely large incisor teeth are orange-red.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An adult is 40-65 cm long and weighs 7-10 kg. Some occasionally weigh up to 17 kg. Males are larger than females. The pelage is thick, with coarse guard hairs overlying the underfur. The soft dense underfur (the commercially valuable pelt called "nutria") is about 2 cm long on the belly, and 2-5 cm long and less dense on the back. The color is yellowish to reddish brown on the back and pale yellow on the belly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The coypu is distributed through southern Brazil, Paraguay, Uruguay, Bolivia, Argentina, and Chile. It has been widely introduced in North America, Europe, northern Asia, and eastern Africa. As a result of escapes and releases from fur farms, the animals are now feral in Europe, North America, northern Asia, Japan, and East Africa. In the United States, they are abundant in Louisiana, Oregon, Florida, and the Chesapeake Bay region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In various countries, the animal's status ranges from that of a rarity to that of a pest. Wild coypu are protected by law in Argentina because of overhunting, but there are about 100 producers of farmed coypu.3 Elsewhere the animals are destroyed en masse to reduce the threat of damage to irrigation ditches, dams, and agricultural crops. In England a decade-long program has eradicated them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Coypu mainly inhabit the banks of fresh or brackish waterways.4 They live in temperate zones and are highly sensitive to freezing conditions. Also, their heat tolerance is poor; lowland tropical regions may be too hot for them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p219a.png"></center><br>
+ figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The coypu feeds mainly at night. The diet consists chiefly of plants, particularly water plants and reeds. Large amounts of fibrous vegetation is decomposed in the cecum, where bacteria break down cellulose particles. Mussels, snails, and other small organisms are also often eaten.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals burrow into soft soil or construct nests out of vegetation above ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu are relatively fast breeding. Females first give birth at ages ranging from 6 to 15 months. From then on, they produce 2 or 3 litters a year. They are able to mate and give birth at any time of the year, although more young are born during certain seasons. The gestation period is between 128 and 140 days. There are 5 or 6 (sometimes up to 12) young in each litter. Newborns are well developed, able to see, and fully covered with hair at birth. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The female's four or five pairs of mammae are located on the side of the body, an adaptation that permits the young to nurse while floating with their mothers in the water. In captivity, young are nursed for two months, but can survive if weaned at five days. The mean body weight at birth is about 225 g, but growth is rapid during the first five months.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu have a potential life span of more than six years. However, they seldom survive more than three years, and in the wild probably no animals are older than five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These are passive creatures, usually entirely lacking in aggression. They are shy and fearful; the slightest disturbance will send them scurrying to the shelter of water, a burrow, or other hiding place. With their large incisors they can bite viciously, but in captivity they tame down, even to where they can be carried around by hand. Compared with domestic animals, they are very sanitary in their feeding and living habits.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In hot climates they are nocturnal, in cooler climates crepuscular, and in cold weather they become diurnal. Captive animals become conditioned to diurnal activity if fed during daylight hours. Most of the active period is spent feeding, grooming, and swimming. Grooming is done by scratching and "nibbling" the fur, and an oily secretion from glands located near the mouth and anus lubricates the pelage. Secretions from the anal glands are also employed for marking out territory.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Excellent swimmers, coypu spend most of their time in the water. They can remain submerged for five minutes or more. On land, they lumber about with awkward, clumsy movements; however, when the need arises they can run fast and jump short distances.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although they usually live together in pairs, coypu will form large colonies. They tend to remain in one area throughout their lives: their daily "cruising range" has been measured at less than 45 m.5 However, drought or freezing weather can induce mass migrations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The burrows, which are dug in sloping banks, are usually short with no branching tunnels and generally end in a simple chamber. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In South America, the coypu has a long history of use. Nutria fur was in such high demand and the animal was hunted so avidly at the beginning of the last century that it became rare and had to be protected by government decree. As a result, populations increased dramatically. Nowadays, coypu are protected in many areas, but widespread poaching has reduced their numbers and range.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many thousands are killed each year just for the guard hairs, which are used in making felt.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu are used in marsh management to reduce infestations of aquatic weeds and to keep waterways open.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In most areas where it is found, the coypu is trapped by commercial hunters. However, as noted, several countries have coypu farms. In Germany, the animals have been raised on diets consisting chiefly of potatoes supplemented with oats, clover, corn, hay, green forage, legumes, turnips, or cabbage. Elsewhere, feeds generally include such materials as hay, corn, crushed oats, greens, root vegetables, apples, bread, and rabbit feed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To confine coypu, a wall of stone or concrete or a fence of stout wire netting is necessary. It must be set 1 m deep into the ground and rise 1-1.5 m above ground. Water must be available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where selected strains of animals are kept, it is usual to house each female in separate small compartments, complete with pools and shelter boxes. Each is then paired with a male, which is removed after mating to leave the female to rear her brood in seclusion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The fur is particularly valuable because the female's nipples are so high that the soft belly fur is unbroken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This herbivore is much cheaper to feed than the furbearing carnivores such as mink. Furs of coypu raised in captivity fetch a price about three times greater than furs from wild animals.6 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wherever the coypu has escaped it has damaged embankments and stream banks. The burrows sometimes weaken dikes that protect low lying areas from flooding. In northern Europe and eastern England, for example, it is considered a serious pest. In rice paddies, coypu could become particularly devastating. They can also damage crops and natural plant communities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu can carry viruses that result in toxoplasmosis, papillomatosis, rabies, and equine encephalomyelitis; bacteria that cause salmonellosis, paratyphoid, and leptospirosis; protozoans that produce sarcosporidiosis and coccidiosis; and rickettsia. Common diseases of captive specimens are bacterial pneumonia, hepatitis-nephritis, Strongyloides infection, and neoplasms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">European winters often cause the coypu's tail (which is hairless) to freeze, but the animal hardly seems to notice. A more dangerous situation arises when lakes, streams, or rivers freeze over; beneath the ice, coypu cannot find their way as easily as beavers, and often drown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Little research needs to be done. There is massive literature on farming coypu. Nonetheless, the animal's behavior is little studied, and there are few reliable published observations on its social organization. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">18 Giant Rat</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The giant rat, also known as the pouched rat, is one of Africa's largest rodents.! Two species have been distinguished: Cricetomys gambianus, which lives chiefly in savannas and around the edges of forests and human settlements; and Cricetomys emini, which occurs mainly in rainforests. Both are highly prized as food </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals are solitary, but they are easy to handle, have a gentle nature, and make good pets. Researchers at the University of Ibadan in Nigeria have been developing techniques for managing them in captivity. Breeding stocks were established in 1973, and since then so many generations have been bred that this small population is considered domesticated. Commercial-scale giant rat farming is now being established in southern Nigeria.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This is a promising development because giant rats are a common "bushmeat" throughout much of Africa. Since these herbivores are well known there, and are acceptable as food, they may have as much or more potential as meat animals than the introduced rabbits that are getting considerable attention (see page 178).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The intertropical zone of Africa from the southern Sahara to the northern Transvaal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This species is among the most striking of all African rodents. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its large size, it often causes amazement - even alarm -  when seen for the first time. The body measures as much as 40 cm, and, on average, weighs about 1-1.5 kg. The record for a hand-reared specimen is 1.6 kg 2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Apart from its size, the best known species (Cricetomys gambianus) is noted for the dark hair around its eyes, a nose that is sharply divided into dark upper and pale lower regions, and a tail that has a dark (proximal) section and pale (distal) section. The overall body color is a dusky gray.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The lesser known species (Cricetomys emini) has short, thin, and relatively sleek fur. Its upper parts are pale brown; the belly is white.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Giant rats are commonly found from Senegal to Sudan, and as far south as the northern region of South Africa. The main species is mostly found in moist savannas, patches of forests, and rainforests. However, it can also be found in all West African vegetation zones from the semiarid Sahel to the coast. It also exists at high altitudes up to about 2,OOO m in West Africa and 3,000 m in eastern Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The rainforest species occurs in the great equatorial forest belts of Zaire and neighboring Central African countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals are probably not threatened with extinction. However, they have been exterminated in some areas (such as in parts of eastern Zaire) where the human population is dense, the land fully cultivated, and the wildlife overhunted. Although common, they are not as well known as one might suppose from their bulk and from the fact that they are sometimes found around, and even inside, houses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Giant rats occur largely in lightly wooded dryland regions or in forested humid regions. They cannot tolerate high temperatures or truly arid conditions. They often live in farm areas and in gardens. Their burrows are commonly found inside deserted termite mounds and at the base of trees. Some have also been found in the middle of cassava fields. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p227a.png"></center><br>
+ The giant rats distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These are herbivores with a tendency to omnivory. They prefer fruits, but also subsist on tubers, grains, vegetables, leaves, legume pods, and wastes (such as banana peels). However, they are not grasseaters. Giant rats also kill and eat mice, insects (caterpillars, cockroaches, and locusts, for example), and probably many other small animals.3 They are particularly fond of mollusks (such as snails).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Reproduction is prolific and year-round. The female attains puberty at 20-23 weeks and the gestation period is about 20-42 days. The young are weaned at 21-26 days of age but stay with their mother until 2-3 months of age. So far, the record for the most litters has been 5 in 9 months. It thus seems possible that a female can reproduce 6 times a year. Litter size ranges between I and 5, but 4 is most common. Thus, in 1 year a single female could produce 24 or more young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These strictly nocturnal animals usually lead solitary lives and forage alone. Mostly, they occupy a burrow by themselves, except when the </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">young are being raised. The burrows can be complex. Below the entrances are vertical shafts leading to a system of galleries and chambers for storing food, depositing droppings, sleeping, or breeding. The home range is individual and limited (1-6 hectares). In the wild, one male "supervises" the home ranges of several females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In captivity, the animals are often seen sitting up and ramming large amounts of food into their spacious cheek pouches. With full cheeks, they return to their burrows and disgorge the food into a "larder." Food (chiefly hard nuts) is stored there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They swim and climb well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A study carried out in Nigeria showed that the giant rat produces about the same amount of meat as the domestic rabbit.4 The meat's nutritional value compares favorably with that of domestic livestock, and African villagers know how to preserve it by smoking or by salting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The giant rat has recently attracted attention as a potential laboratory animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Farmers in Nigeria have traditionally trapped the juveniles and fattened them for slaughter. They usually keep the animals in wire cages and feed them daily with food gathered in the wild as well as with scraps from the household.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, the program at the University of Ibadan indicates that the giant rat can be domesticated. Already, specimens are being bred and reared in an intensive program. They adapt to captivity after about a month. They are subsequently transferred into breeding cages, which are wooden boxes with a rectangular wire-mesh "playroom." Each cage holds a breeding pair or a nursing female with its young. Experimental feeding cages have also been designed.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Food-preference trials show that palm fruits and root crops (especially sweet potato) are preferred to grains and vegetables. Nutritional studies show that the animals can tolerate up to 7 percent crude fiber in their rations. Although largely vegetarian, they eagerly consume dry and canned dog food. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals have several advantages:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· They are well known and much sought after for food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· They have adapted to life in lowland tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· They are able to live on locally available plant materials, including vegetable waste.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· They reproduce rapidly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· They are more tolerant of captivity than the grasscutter (see next chapter). This is largely because omnivorous feeding makes them easier to feed than the grasscutter and other strict herbivores.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This species could easily become a pest. It is recommended for rearing only in areas where it already exists. The crops it damages include cacao, root crops, peanuts, maize, sorghum, vegetables, and stored grains and foods. There is also the possibility that this rodent may transmit diseases to humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A project at the University of Kinshasa in Zaire reports problems in getting giant rats to reproduce in captivity. When two specimens were paired they sometimes fought so viciously that copulation was impossible.6 Special management may be required, such as housing animals in adjacent cages before actually introducing them to each other. Moreover, selection for docility may also be necessary.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The ratlike appearance is not attractive, and a few African tribes have taboos against consuming the meat of these animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Throughout Africa south of the Sahara, giant rat domestication deserves experimentation and trials. Success would open up the potential for supplemental meat supplies in rural and urban areas where meat is now scarce. Tests are needed to determine the factors that favor breeding: temperature, aeration, light, privacy, and size and form of cages. Moreover, diets that are cheap and easy to make from local feedstuffs must be identified. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Further research on the domestication of the giant rat might include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Identifying husbandry techniques that are applicable at low cost in rural areas;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Studying food digestibility and setting up various diets;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Illuminating social behavior: pairing of animals, the best moment for pairing, duration of pairing, age of partners;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Outlining the basics of husbandry (for instance, capital costs, food conversion ratios, growth rates) and making simple and cheap cages;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Studying biology (anatomy, physiology, birth records, growth rate); and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Testing the practical likelihood that this rodent may transmit diseases to people and other animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The giant rat has an interesting commensal relationship with Hemimerus, an insect that feeds on secretions in the skin. It seems to cause no irritation or damage, and may even benefit the host by helping to keep the skin clean. Caging these animals results in the general loss of the insect, but attempts should be made to maintain them and to determine their role and life cycle.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The potential of this species as a laboratory animal in nutritional, clinical, and pharmacological research also deserves exploration. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">19 Grasscutter</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g023a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The grasscutter (Thryonomys swinderianus and Thryonomys gregorianus) is found in many forests and savannas of Africa. Its meat, said to resemble suckling pig, often sells for more per kilogram than chicken, beef, pork, or lamb. It is the preferred, and perhaps most expensive meat in West Africa. Indeed. in Ivory</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coast it sells for about $9 per kg. With prices like that, grasscutter is a culinary luxury that only the wealthy can afford.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">If domestication of this wild species were successful in providing meat at a price similar to that of poultry (the second most popular meat), markets would be unlimited.2 However, as production costs are high, long-term research will be required before grasscutter production can be profitable to the small farmer. This research should now be undertaken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In an effort to capitalize on the markets for this delicacy, agricultural extension services of Cameroon, Ghana, Ivory Coast, Nigeria, Togo, and particularly Benin are already encouraging farmers to rear grasscutters as backyard livestock. They furnish breeding stock and information, and maintain central offices for records. In addition, a bilateral cooperation project in Benin has started experimental work on improved breeding methods combined with the study of animal responses under domestication.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In future, this vegetarian animal might become the African equivalent of South America's guinea pig, playing an important role in reducing Africa's chronic protein shortage. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Humid and subhumid Africa south of the Sahara.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Grasscutters are robust animals with short tails, small ears, and stocky bodies. Taxonomically, they are more closely related to porcupines than to common rats or mice.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although many varieties have been described, there are probably only two species. The larger (Thryonomys swinderianus) weighs 9 kg or more and has a head-and-body length of up to 60 cm. The smaller species (Thryonomys gregorianus) may occasionally reach 8 kg and a body length of 50 cm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Both species have yellow-brown to gray-brown bodies, with whitish bellies. The fur is extremely coarse, firm, and bristly - reflecting the animal's kinship to the porcupine. The tail is scaly and has short, sparse hairs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Both species have thick, heavy claws and enormous orange incisors that can chew through even the toughest vegetation. (Grasscutters have been known to tear holes in corrugated iron fences.) Nevertheless, they do not bite when handled, although their claws sometimes cause injuries.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Grasscutters occur in grassland or in wooded savanna throughout the humid and subhumid areas of Africa south of the Sahara. They often live in forest-savanna habitats where grass is present. They do not inhabit rainforest, dry scrub, or desert, but they have colonized the road borders in forest regions. Distribution is determined by availability of adequate or preferred grass species for food. Specifically, Thryonomys swinderianus occurs in virtually all countries of west, east, and southern Africa. Thryonomys gregorianus occurs in savannas in Cameroon, Central African Republic, Zaire, Sudan, Ethiopia, Kenya, Uganda, Tanzania, Malawi, Zambia, Zimbabwe, and Mozambique.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Despite heavy hunting, these animals are not threatened with extinction. Nonetheless, many individual populations are well below carrying capacity, or are extinct because of local overexploitation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The larger grasscutter (T. swinderianus) generally lives in swampy, low-lying areas, especially along river banks and the borders of lakes and streams. Occasionally, it is found on higher ground among bushes and rocks, living where savanna grasses are dense and tangled enough to afford good cover. In Ivory Coast and southern Guinea, for instance, grasscutters are found (and hunted) throughout the savanna zones. And they can occur in close proximity to farmlands and people (for example, in southwest Nigeria).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although the precise diet in the wild has not been determined, grasscutters are vegetarian. They consume nuts, bark, and the soft parts of grasses and shrubs. They particularly favor elephant grass and sweet potatoes. They commonly "raid" cassava and yam plantations, and are considered local pests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grasscutters reproduce year-round, although the births seem to peak at certain times of the year, correlated with weather conditions.5 Probably one male takes several females, and the family group possibly has more than one generation of young. The gestation is about 152 days. Apparently, litters normally contain between 2 and 4 young, but in Benin and Togo some litters of up to 11 or 12 are reported.6 Newborns are fully developed, their eyes are open, they weigh approximately 80 g, have thick fur, and quickly become accomplished runners.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p236a.png"></center><br>
+ figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although they commonly forage in groups, grasscutters are generally solitary. They are nocturnal, and they travel at night through trails in reeds and grass, often to water. Most specimens seen in markets are males, possibly because males lead the groups and are thus most prone to being trapped.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When alarmed, these animals stamp their hind feet and give a strange booming grunt. When fleeing, they can run very fast and, given a chance, will take to water. They swim with ease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For shelter, grasscutters usually weave nests of matted vegetation or scoop out shallow burrows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In a broad geographic band across sub-Saharan Africa, cattle raising is severely limited by trypanosomiasis. There, other sources of animal protein, including rodents, are traditionally used. Thus, grasscutter meat constitutes an important food for many Africans. The animals are mostly caught and eaten by families for their own use, but some are sold in markets and especially in roadside stalls. Many families depend exclusively on selling bushmeat, particularly that of grasscutters. In Accra, Ghana, during one year, 73 tons of grasscutter meat were sold in the local market. This represented more than 15,000 animals. In southern Africa, too, people find that these rodents make tasty food, although they may cut off the tail to make the carcass look less ratlike.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The meat is usually eaten smoked, and is so much in demand that grasscutters are hunted in organized drives with spears, dogs, and sometimes fire. It is considered excellent, especially when cooked in soups and stews or barbecued.7 It has been described as resembling venison in flavor, but it is dark like the meat of wild duck.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the savanna area of West Africa, people have traditionally captured wild grasscutters and raised them at home. As an extension of this, organized grasscutter husbandry has been initiated in West Africa. The animals are provided with marshy, tightly fenced areas with plenty of plant cover. The young are harvested from these areas and raised separately.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghanaian researcher Emanuel Asibey, a pioneer of this research, reports success at getting such captive stocks to reproduce. To this end, farmers are provided with breeding boxes and foundation grass cutter colonies. They are taught how to rear and feed the animals for home consumption or for cash income. Basically, the farmers make available large sheds where the animals can move freely. To prevent escape, the walls may be reinforced with cement plaster. The farmers also provide piles of grass, sugarcane, and other foods. A grasscutter reportedly takes about a month to adjust to such confinement. High mortality can occur in this period. The average weight of a mature, home-raised grasscutter is 4-7 kg. The average killing-out (dressed carcass) is 64 percent.8</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Wildlife Domestication Unit of Ibadan University in Nigeria, another pioneer of rodent domestication, has also reported the potential of domesticated grasscutter colonies.9</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research on grasscutter breeding, husbandry, and feeding is similarly being implemented by the Ministry for Rural Development in Benin and at the Lacena in Ivory Coast (see Research Contacts).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The demand for grasscutter meat is so large that it is not being met. Markets for it already exist over much of Africa,</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Grasscutters can devastate such crops as rice, sugarcane, soybeans, peanuts, yams, cassava, sweet potatoes, oil-palm seedlings, maize, young rubber, sorghum, and wheat. Therefore, as with most rodents, they should be reared only in areas where they already exist.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In past years, captive animals in Benin have suffered fatal Clostridium infections during September and October. In 1986, a broad-spectrum antibiotic was given with outstanding results. During this season, the animals also suffered from ascarid worms, which were also successfully treated with standard drugs.10</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Research is needed in the following areas:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Digestive physiology, feeding habits, feed preferences, feed conversion and growth rate; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Diseases (pathogens and parasites);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Captive breeding and management (growth rates, space requirements, feed needs, etc);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Performance under different environments;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Productivity; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Basic biology (for example, chromosome type, reproductive physiology, and social behavior both in its wild state and under controlled conditions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, specimens should be gathered from different regions for comparative evaluation. A particular need is to select and breed docile specimens because today, even after several generations in captivity, the animal must still be handled with caution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although domestication of the grasscutter is encouraged, wild populations might also be managed to maximize and sustain production through habitat manipulation. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">20 Guinea Pig</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g024a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea pigs (Cavia porcellus) are promising microlivestock because they require little capital or labor; provide an inexpensive, readily available, palatable meat; have no odor, and are suitable for keeping indoors. In the highlands of the Andes, many Indians raise them to supplement diets based on grains  and vegetables. Families eat them mostly on special occasions such as weddings and first communions, or they sell them to restaurants or peddle them in village markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The low cost of these small animals makes them available even to many landless peasants. For both the small farmer and apartment dweller, the guinea pig is a possible food reserve. It converts kitchen scraps and marginal wastelands into meat. According to estimates, 20 females and 2 males may produce enough meat year-round to provide an adequate meat diet for a family of 6.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since husbandry practices are simple and cheap, the guinea pig is an excellent source of supplementary income. An FAO study at Ibarra, Ecuador, showed that on small mountain farms the guinea pig provided more profit than either pigs or dairy cows, partly because its meat fetched high prices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although domesticated guinea pigs are mainly a food resource of Latin America, their use has also spread to parts of Africa and Asia. They are raised, for instance, in Nigeria, Cameroon, Ghana, Sierra Leone, Togo, and Zaire. In southern Nigeria, at least 10 percent of all households raise guinea pigs for food, with colonies of up to 30 animals per household. Guinea pigs are also raised in small cages or cardboard boxes by small farmers in the Philippines.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The feeding efficiency is high: studies have shown that it takes between 3.2 and 5.7 kg of forage to produce 1 kg of growth. This makes guinea pigs more efficient than most farm mammals. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea pigs seem especially adapted to the climate and forages of high-altitude zones, but the fact that they are being raised in Central and West Africa indicates that they are also adapted to the lowland tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p243a.png"></center><br>
+ The native distribution of the guinea pigs wild ancestor</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea pigs have stocky bodies, fairly short hind legs, and short, unfurred ears. Adults can weigh up to 2 kg, but an average-sized specimen is about 0.5 kg. They are 20-40 cm long (average 28 cm) and have no tail. In domesticated forms, the pelage may be smooth or coarse, short or long, and in some types the hairs form rosettes.4 Domesticated types come in colors ranging from white to dark brown, as well as piebald.5 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The original home of the wild guinea pig is believed to have been the central highlands of Peru and Bolivia. Its domesticated descendants are important as meat animals mainly in that same area, but, as noted, they are also important in certain African and Asian countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A few strains are distributed worldwide as laboratory animals and pets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Domesticated guinea pigs, as a whole, are in no danger of extinction, although some rare strains are threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These extremely adaptable animals are found in temperate zones and in the highland tropics, but they are usually kept indoors and protected from the extremes of weather. In Lambayeque and other departments of Peru, they are reared at elevations from sea level to more than 4,000 m. In areas where they are raised, daily temperatures fluctuate as much as 30&Yacute;C. In the Bolivian or Peruvian puna region, for instance, day temperatures can be 22&Yacute;C, while night temperatures are -7&Yacute;C. However, they cannot survive freezing temperatures and they may not perform well when exposed to the full tropical heat and sunlight. Many people of the Peruvian highlands keep the animals in darkness (for example, in wood boxes with little or no light).6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal's original wild habitat is believed to have been an area of grasslands, forest edges, swamps, and rocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These herbivores can be raised on kitchen scraps, garden wastes, and weedy vegetation plucked from backyards or roadsides. Andean peasants mainly feed them potato peels, scraps of cabbage, lettuce, carrot, wild grasses, corn stalks, and the foliage of miscellaneous wild plants. Some barley and alfalfa is grown specifically for guinea pigs; it is cut green and sold in small bundles in the markets. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea pigs mate throughout the year except when climate is excessively adverse. Domestic breeds average 2-3 young per litter, although larger litters sometimes occur. The gestation period is 65-70 days with an average of 67. Females come into estrus every 13-24 days, and there is a fertile postpartum estrus.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Females can become pregnant when merely 3 months old, and many produce 4 litters every year from then on. In principle, a farmer starting with 1 male and 10 females could see his herd grow to 3,000 animals in one year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Newborns are so large that the female's pubic bones must separate for the birth. They emerge fully developed, with fur and open eyes. They look like miniature adults, and they start eating grass and other feedstuffs within hours. (For this reason, babies orphaned at birth have been known to survive.) Weaning may be reached as early as 21 days of age.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The life span in captivity is as long as 8 years, but animals used for breeding usually live only 3.5 years. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SUPER GUINEA PIGS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Even in their native region, guinea pigs have traditionally received little research attention. However, that began changing in the 1970s with the onset of meat shortages in Peru. (For a time the government restricted beef sales to only 15 days a month.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For instance, in 1972 Peru began a guinea pig improvement project. Researchers from i a Molina National Agrarian University traveled throughout Peru gathering many kinds of guinea pigs short haired long haired black, white, yellow, brown, and even purple. Practically all the guinea pigs eaten in Peru are home grown, and researchers observed that the bigger ones were generally winding up in the stew, leaving the smaller ones for breeding. The people inadvertently were making the animals smaller. (This is a common phenomenon for many animals.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To overcome it, the university research workers compared the mature size and growth rates of all the different guinea pigs. They selected and cross-bred the biggest, meatiest, and fastest-growing ones. This program, later taken over by Instituto Nacional de Investigacion y Promocion Agropecuaria (INIPA), produced remarkable results. The starting animals averaged little more than 0.5 kg, the resulting ones averaged almost 2 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peru's "super guinea pigs" are now getting international recognition. They have been introduced into the highlands of Honduras, where the animal is also part of the Indian cuisine. The FAO has shipped some to the Dominican Republic. In addition, Bolivia, Ecuador, and Colombia have all begun their own guinea pig improvement programs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Within Peru the government has established 11 breeding stations to encourage the farming of guinea pigs for food. The goal is to provide better stud males to the people so that future animals will grow more quickly and reach a greater weight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea pigs generally congregate in small groups, normally made up of 5-10 adults. In favorable areas, however, such groups may coalesce into large colonies. The animals communicate incessantly among themselves, emitting a variety of squeaks and other noises.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males, although good-natured with other species, often fight fiercely among themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea pigs are raised mainly for meat. Peru has about 20 million, which annually provide 16-17,000 tons of meat (only 4,000 tons less than Peru's sheep meat production).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea pigs are used worldwide for studies on disease, nutrition, heredity, and toxicology, as well as for the development of serums and other biomedical research. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Guinea pigs require so little space that a small cage or pit can house up to 10 females and 1 male. They can be raised in cages with wire floors of small mesh as well. The labor required is low. A colony of 1,000 females reportedly can be properly cared for by one person. A layer of wood shavings, shredded paper, straw, and dried corncobs is usually recommended for bedding. The droppings are odorless, so the bedding does not need changing as often as with other animals. When the diet mainly consists of greens, much urine is produced, and then the beds have to be changed frequently.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When grown for meat, the young are weaned at 3-4 weeks and are ready for market in a matter of 10-13 weeks. Weight gain is rapid for the first 4-6 weeks, and then decreases. The carcasses normally dress out at about 65 percent, including the skin and legs. The meat's protein content is approximately 21 percent.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a few regions of Peru, guinea pigs are "herded" on the open range and retired at night into small adobe coops.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This small, inoffensive animal rarely bites, is easy to manage, and has no smell. It is an excellent supplemental meat supply. The improved breeds cannot climb or jump so that they are easy to contain. (Primitive "criollo" types, however, can jump.) If kept dry and given green vegetation, grain, and water, it survives in many environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A major constraint is consumer reluctance. Even in Latin America, attempts to promote guinea pig consumption outside the Indian communities have failed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When raised in a clean environment and under normal feeding conditions, guinea pigs thrive and reproduce and do not need routine vaccinations or antibiotics that cattle, sheep, and pigs often require. However, guinea pigs can be carriers of Chagas' disease and salmonella. Further, they are susceptible to pneumonia if temperatures change abruptly when conditions are wet. Coccidiosis and internal and external parasites are also common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Green forages and surplus fruits or by-products are critical to provide vitamin C, which the animal is unable to synthesize for itself. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Since the greatest concentration of guinea pigs is found in the Andes, particular efforts should be directed towards this region. Already, research on guinea pigs has begun in some universities and government research stations in Colombia, Ecuador, Venezuela, Peru, and Bolivia, but more work is needed on matters such as:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Breeding "elite" stock for distribution;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Feeding and nutritional-requirement trials, especially for creating alternate feeds that peasants and commercial producers can use during seasons when conventional feeds are hard to get;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Diseases and parasites that may limit production in small farming systems;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Management practices concerning reproduction, housing, herd size, and feeding; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The genetic basis for weight gain and productivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some research should be directed towards developing rations or introducing drought-resistant forages for the dry season because green forage is needed year-round. A range of practical and economical diets needs to be created.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal geneticists in Latin American countries should establish "elite" populations that can provide superior stock throughout the world. It can be anticipated that applying modern breeding methods to existing improved strains will result in great advances in a relatively short period and at little cost (see sidebar).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Three species of wild cavies (Cavia aperea, C. fulgida, and C. tschudii), close relatives of the guinea pig, are native to South America and are declining drastically. Research to preserve them is urgently needed. C. aperea is a widely used item of food in rural Brazil and other parts of South America. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">21 Hutia</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g025a.png"></center><br>
+ Hispaniolan Hutia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first meat Christopher Columbus tasted in the New World was probably hutia, a rodent avidly hunted by the Carib Indians. Hutia bones have been unearthed from kitchen middens of pre-Columbian inhabitants of all the Greater Antilles. Indians carried live hutias on voyages possibly in a semidomestic state as a source of food. On some islands, hutias were so eagerly sought that their populations were destroyed long before Europeans arrived. Slaves in the cane fields also hunted hutias for food. The surviving species later suffered when forests were cleared and cats, dogs, mongooses, and other predators were introduced. Consequently, the majority of hutia species died out, and today most surviving members of the family (Capromyidae) are facing extinction. Human predation continues in some areas (for instance, in Jamaica) where the tradition of "coneyhunting" still endures in a few regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hutias should be tested as possible microlivestock: success could create the incentive for their complete protection. The animals seem to take well to captivity. The Jamaican hutia is already overproducing in zoos, causing a local glut of animals. And hutias are, or were until recently, kept in barns by some people in Cuba, who fed them on banana and other vegetable waste and ate them regularly.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">POTENTIAL AREA OF USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Caribbean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hutias are broad-headed, short-legged, robust animals with small eyes and ears. The various species are from 20 to 60 cm long and weigh from 1 to 9 kg - a size range from that of a guinea pig to that of a small dog. They walk with a slow, waddling motion, but can hop quickly if frightened or pursued. They also climb well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 10 1iving species are all big enough to be candidates for microlivestock. The best known and easiest species to keep in captivity are the Cuban hutia (Capromys pilorides) and Jamaican hutia (Geocapromys brownii). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Cuban hutia (also called hutia conga) is about 60 cm long, with coarse fur, a raccoon-shaped body, and a thick tail covered with sparse bristles. A forest dweller, it weighs up to 7 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The short-tailed Jamaican hutia is smaller: it is 33-45 cm long and weighs up to 2.5 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p252a.png"></center><br>
+ The hutias native range .</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hutias are found only in the Caribbean (Greater Antilles and Bahamas). Most species are confined to a single island, where they represent the only remaining indigenous land mammals. The Cuban hutia is found only in Cuba. The Jamaican hutia is found only in Jamaica, although a close relative occurs on East Plana Cay, Bahamas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This once widely distributed and plentiful family is now failing. Of the 30 or so known recent taxa, more than half are already extinct, and the remainder all suffer from habitat alteration, predation by introduced animals, and hunting by man. With the exception of the Cuban hutia, all species are included on the list of the world's threatened mammals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hutia ranges have been so reduced that these animals survive only in the most inaccessible forests and rocky drylands. Both the Cuban and the Jamaican hutias occur in a variety of habitats from montane cloud forests to arid coastal semideserts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most species are terrestrial, but some live in trees. The Cuban and Jamaican species are terrestrial, but they can climb trees if circumstances demand. They maneuver well on trunks and larger branches, descending head first like squirrels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hutias are primarily vegetarian, their diets consisting of leaves, bark, fruits, and twigs, as well as incidental catches of small animals such as lizards and invertebrates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hutias seem to breed year-round, generally giving birth to litters of 1-4 offspring after a gestation period of 16-20 weeks. The young are well developed at birth, fully haired, open eyed, and capable of most adult movements. After 10 days they begin taking solid food, although they are not fully weaned for at least a month and a half (5 months for the Cuban hutia). Sexual maturity is at 10 months; life expectancy is 8-11 years in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Jamaican hutia has one of the highest diploid chromosome numbers (2n = 88) of any mammal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most hutias are wary and secretive and are easily displaced by human encroachment. They live like rabbits, hiding among tangled vegetation, in holes, and among rocks - communicating by voice and scent markings. They build shelters mainly in rock crevices, but also in the base of thick bushes or in natural cavities in trees. The Cuban hutia is often diurnal, whereas the Jamaican hutia is largely nocturnal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HISPANIOLAN HUTIA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Hispaniolan hutia, or zagouti (Plagiodontia aedium) as it is known in Haiti is smaller than the two Capromyids discussed here, weighing just 1.2 kg. It is difficult to breed in captivity and has a lower reproductive rate than either the Jamaican or Cuban hutia. It is therefore less suitable as an economic or food source.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, there is a significant need for supplemental protein sources in both Haiti and the Dominican Republic. It might be possible to develop a special captive-breeding program for this animal, but it should be done with great care. It is important that a hunting tradition for this animal not be reestablished in rural areas of Haiti or the Dominican Republic, and that local organizations not be misled into believing that there will be a rapid increase in the numbers of this species in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hutia meat is relished, especially in Jamaica. The animals are still hunted, often by using dogs that smell them out and retrieve them from a hole or hold them at bay in treetops.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Experiences of zoos suggest that the Cuban and Jamaican hutias will thrive in captivity. The animals are generally long-lived and have survived up to 17 years. They are often friendly with their keepers and, when tame, can be held and carried about without any particular danger. However, if angered they can inflict deep bites and should normally be handled with considerable caution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals are already much in demand. Their meat has an excellent flavor and they are big enough to provide a worthwhile quantity. If husbandry could be developed on a sustainable basis, it could be used as a mechanism for both economic development and for saving the remnant populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wild populations are threatened. Any captive population must be built up without endangering them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All hutias are susceptible to predation by domestic cats, mongooses, dogs, and human poachers, so care must be taken to design predator-proof breeding facilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals are carriers of eastern equine encephalomyelitis, a serious disease of horses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hutias deserve urgent conservation attention. In particular, the following steps should be taken:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Establish reserves in natural habitats containing breeding populations to ensure the survival of the genetic diversity of these animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Build up breeding populations in suitable zoos and livestock research centers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Gather specimens from different regions for comparative evaluation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Investigate hutia biology, including chromosome type, reproductive physiology, nutrition, and diseases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Assess experiences of zoos.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Perform captive breeding trials, measuring growth rates, space requirements, food needs, and social behavior (both in its wild state and under controlled conditions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Study the social organization and tameability.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Colonies of some species could be established on uninhabited islands, as has been done with the Bahamian hutia Geocapromys ingrahami. Even this rare species might eventually be raised to yield meat for local inhabitants, as it is well adapted to dry and barren environments and was a regular food of the pre-Columbian Indians. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">22 Mara</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g026a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many wild relatives of the guinea pig are native to South America. Some, such as the guinea pig itself, are small; others, such as the mare, are much bigger. Maras1 (Dolichotis patagonum) are as tall as terriers and, at first glance, look like dwarf antelopes or huge hares They have large ears and eyes, long legs, and short tails. They generally behave like hares or wild rabbits, but, like deer, they run with a stiff-legged gait when pursued by predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These strange-looking creatures are found in temperate regions in the southern half of South America. They are dry-country animals, living on the thorn-scrub, desert plains of Argentina and the stony wastes of Patagonia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although exceedingly shy, restless, and watchful, mares tame easily, make good pets, and are much favored by the local populace. They were introduced to France last century, and in Victorian times Europeans sometimes bred them. These big, handsome rodents, grazing in little herds, were considered an attractive addition to the lawns of country estates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">POTENTIAL AREA OF USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras are best kept in their native region of southern South America. With care, however, they could be used in other areas because they are slow breeders and their population growth is easy to control.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">At first sight, these large rodents look like some weird hybrid. They have the long ears of a hare and the tidy body and spindly legs of a small antelope. Although related to guinea pigs, they are long legged. The tail is short; the ears are long and erect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Average-size mares weigh about 8 kg, but large ones can be 1 m long and weigh up to 16 kg.2 Females are larger than males. The coat is light in color, with grey upper parts and whitish underparts. The limbs and feet are tinged a yellowish brown. The pelage is dense, with individual hairs standing at nearly right angles to the skin. This gives a harsh texture, even though the hairs are soft and fine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals can hop, walk, gallop, or run. They are extremely swift and can reach 45 km per hour over long distances. They are also accomplished jumpers, often leaping 2 m high from a standing start. The feet are compact and rather hooflike, but with sharp claws. The hind foot has three digits; the front foot has four.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The mare's range in the thorn-scrub desert and Patagonian steppe of Argentina extends from about 28&Yacute;S to 50&Yacute;S.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Endangered. These animals, once plentiful, are now threatened because of the introduction of the European hare, which is more successful at competing for food. In many of the eastern parts of its distribution (see map) it is now extinct.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras inhabit open, dry plains and other treeless semidesert areas of coarse grass or scattered shrubs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras are pure vegetarians. They feed on short grasses and herbs that are sparsely distributed between patches of dry desert scrub. Usually, they are satisfied with a few coarse weeds and the shoots of bushes. However, their overall diet consists of any available vegetation: leaves, roots, fruits, and stems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Female mares become sexually receptive within a few hours after giving birth. The estrous cycle is 35 days, plus or minus 5 days.3 The gestation period is 77 days. Each female gives birth to 1-3 young at the mouth of the den; the pups crawl inside to safety. Newborns are well developed, and within a few hours they begin grazing vegetation. They remain in the vicinity of the den for up to 4 months.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initially, at least, the young are nervous and easily frightened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras shelter in a burrow that they either construct for themselves or "borrow" from another animal that has abandoned it. They are active during the day and spend considerable time basking in the sun. They are always alert for danger. When alarmed, they flee at high speed. The white rump patch flashes a warning to the others, who then follow this "flag."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A fundamental element of their social system is the monogamous pair bond. Certainly in captivity, and probably in the wild as well, the bond between a pair lasts for life. When breeding, 20 or more pairs may band together temporarily to share a single den for the pups.4 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals stand on straight legs, sit on bent haunches with the forepart of the body resting on the fully extended front legs, or recline in a catlike position with the front legs folded under the chest, an unusual position for a rodent. They travel in single file, with the female usually leading. Members of a pair maintain contact by means of a low grumble. Although the long legs can quickly carry it to safety, a mare usually stops every 20-30 m and turns to peer at its pursuer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals clean themselves by licking their sides and apparently by "combing" their fur with their teeth. They wipe their faces as cats do, with the inside of a foreleg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p260a.png"></center><br>
+ The maras native range</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although the light-colored meat is said to be dry and flavorless, it is widely consumed in South America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras have been successfully raised and bred in many zoos, and, as noted, have been kept as pets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adults make little use of any shelter; they seem fond of being out and about in all weather. As long as they have a protected burrow for the use of the pups, mare populations can thrive in severe climates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In zoos, diets include straw, vegetables, and crushed oats. Drinking water is supplied, although the animals rarely take it if they are feeding on fresh plant materials. They like to have salt blocks, however.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In South America, one mare lived in captivity for almost 14 years; most specimens do not live beyond 10 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Maras are a good size for microlivestock. They have a short gestation period, and they are social and easy to maintain in groups. They can be successfully kept in pens and can be fed relatively low-quality forage. Colonies can grow to be quite large.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals can easily dig under the edges of cages and escape. Extra-deep foundations are needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following heavy rains, care must be taken to keep them from drowning in their subterranean burrows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If suddenly disturbed, mares can become hysterical, leaping away regardless of anything in the way, and often seriously injuring or even killing themselves as a result. They fear bodily contact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mare's monogamous nature in the wild is a likely limitation. But perhaps, like chinchillas, the animal will become polygamous in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are sensitive to tuberculosis when kept in humid conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Research needs to increase understanding of the mare include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Nutritional trials;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Husbandry experiments - measurements of growth rates, space requirements, feed needs;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Productivity tests;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Grazing-efficiency measurements;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Exploration of commercial details; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Determination of diseases and parasites. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">23 Paca</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pacas (Agouti paca)1,2 are large, white-spotted, almost tailless rodents with the potential to become a source of protein for the American tropics. They are found in lowlands from Mexico to northern Argentina. The meat is white and is considered the best of all Latin American game meat. It is common in local markets and restaurants. Tasting like a combination of pork and chicken, it sells at higher prices than beef and is a regular item of diet in some areas. In Costa Rica, pace is served on special occasions such as weddings or baptisms. It has a higher fat content than the lean meat of agoutis, rabbits, and chickens, and has no gamy taste.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paca has promise as a microlivestock. In several countries, Belize and Mexico for example, people already keep them in cages beside their homes and fatten them on kitchen scraps. In Costa Rica, some are bred on farms, under houses, and even in apartments. Research on raising paces in captivity is under way at the Universidad Nacional in Heredia, Costa Rica; at the Smithsonian Tropical Research Institute in Balboa, Panama (see page 196); and at the Instituto de Historia Natural in Tuxtla Gutierrez, Mexico. In Turrialba, Costa Rica, an entrepreneur is already breeding and raising pace commercially.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the pace has potential as a food source, many problems still must be resolved before it can be recommended for mass rearing. If solved, however, this species would become an attractive microlivestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The pace has potential for use throughout its vast geographical range in Latin America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In general appearance, paces are somewhat like giant guinea pigs. The legs are short, the forefeet have four "fingers," and the hindfeet have five small, hooflike "toes." The feet are partially webbed and are adapted both for digging and for swimming. Pacas burrow with all four feet as well as their teeth; even large roots are no obstacle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adults weigh 6-14 kg, males being somewhat larger than females. Although they may become bulbously fat, paces remain "one of the fastest things on four feet. " From a standing start, even a fat specimen can jump at least 1 m off the ground. Pacas are also agile. However, their skin's epidermal layer is thin and fragile, and large strips may be ripped off as they rush headlong through spiky undergrowth. However, such wounds heal astonishingly fast - frequently within days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacas are chocolate brown in colon The head is somewhat lighter in shade than the body, and the underparts are whitish or buff colored. There are usually four longitudinal rows of white spots that may merge into stripes along each side of the body. The fur is coarse, spiny, and slippery, and has no underwool. Each hair is stiff, relatively sharp, and very smooth, which makes paces extremely difficult for predators to hang on to.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parts of the cheekbones are enlarged, and the cheeks can open to form special pouches. This is more developed in adult males than in females - indeed, adults can be readily sexed by head shape. The pouches are outside of the mouth and are fully haired. The animals use them mainly to create a resonating chamber for their booming bark and noisy tooth grinding. These enlarged cheeks push the large bulging eyes toward the top of the skull. The eyes are suited for nocturnal conditions, the senses of smell and hearing are uncannily acute, and there is an array of long whiskers that is used when maneuvering at night.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Lowland paces are found throughout most of Latin America from east central Mexico to northern Paraguay, Argentina, and Minas Gerais, Brazil. This includes all of Central America and most of Colombia, Ecuador, Peru, Venezuela, and the Guianas. The animal has also been introduced into Cuba.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p265a.png"></center><br>
+ The pacas native range</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Burgeoning human populations are severely reducing many of Latin America's native animal resources, and the pace is one of the most persecuted. It has been exterminated within hunting range of virtually all cities, towns, and villages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several governments, recognizing the pace's plight, have passed laws prohibiting the hunting and marketing of its meat. Nevertheless, people continue to take it, usually at night, using trail dogs and headlights.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pacas thrive in a variety of tropical habitats but are most common in forests, swamps, and partly cleared grazing lands. They inhabit most types of forests from deciduous woodland to rainforest. Usually, they stay near streams or rivers, but they often live where there is no permanent water. They are abundant only in little-disturbed forest areas. Although preferring low, dense tree cover, paces sometimes inhabit open rocky areas and farmland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These herbivores feed mainly on fruits, young seedlings, and some seeds. However, when fruits are scarce they may switch to browsing leaves and roots. They probably sometimes eat large insects, and, on rare occasion, may perhaps eat small vertebrates. Captive paces, like many other "frugivores," seem to develop a protein deficiency and will eagerly eat meat scraps on occasion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The young are usually born singly after a gestation period of 146 days. There are probably 2 births a year. Females have an estrous period that begins shortly after giving birth. If mating does not take place at this time, the female becomes unreceptive until after the 3-month (sometimes 4- to 6-month) lactation is over. The length of the estrous cycle is 30 days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During daylight hours, paces seclude themselves in brushy cover, in or under fallen logs, or in extensive underground burrows. The burrows, which may be several meters long, are dug in moist soil or taken over from other animals; they are often in river banks, on slopes, among tree roots, or under rocks. Usually, several exits are provided, often being plugged with leaves as a disguise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the wild, paces dig large holes and rummage about the forest floor at night, gnawing on fruits. Pairs inhabit a defended area, sometimes living together in the same burrow, sometimes not. Also, they usually travel alone, following paths that lead to feeding grounds and water. Individual home ranges are small (1-3 hectares).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although paces are terrestrial, they enter water freely, they swim well, they copulate in water, and, when alarmed, they generally attempt to escape by swimming. They are also lively and playful; however, they can be exceedingly obstinate. Sometimes fighting among themselves becomes very savage. When angered they growl, sometimes noisily, and they can suddenly jump on aggressors, real or imagined, delivering frightful wounds with their chisel-like front teeth thrust forward like a spear. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, pace meat is tasty and brings high prices in the markets. It is considered a delicacy in fine restaurants and was served to Queen Elizabeth during her October 1985 visit to Belize. In Mexico, paces, like pigs, are usually boiled unskinned. Even the skin is then edible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">If treated appropriately when young, paces become manageable. They undergo "imprinting," a characteristic of most species that have been domesticated. An imprinted pace becomes so tame that it seeks out human company, follows people around like an amiable dog and, if turned out of its cage, returns voluntarily. (To achieve this degree of tameness it is necessary to remove the animal from its mother at an early age.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although wild paces are almost entirely nocturnal, tame paces are more active during daylight hours.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young or partly grown paces are commonly exhibited in zoos. They eat prodigious quantities of almost any vegetation and have been called, "a good substitute for a large garbage pail." Diets can include rolled oats, raw vegetables, bananas, apples, and bread. They probably need additional protein occasionally, and seem to appreciate some fat in their diet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">If husbandry can be developed, the clamor for pace meat throughout tropical America would be a big economic incentive for farming these animals. The excellence and wide acceptance of the meat is an indication that pace farming would be taken up both in rural and urban areas and by many levels of society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pacas can harbor human diseases, including leishmaniasis and Chagas' disease.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apart from the project in Panama (see page 194), paces have bred only sporadically in captivity, with few offspring surviving. However, successes have been recorded in zoos in London, San Diego, and Washington, D.C., and in a research project in Tuxtla Gutierrez, Mexico. In Costa Rica, they are also reportedly breeding well, with a survival rate of 90 percent since 1982, and 80 percent of the females are reproducing.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All adult paces can be aggressive and dangerous. Their powerful incisors can inflict serious wounds. (They can even rip through planks.) Intraspecific aggression is one of the most serious impediments to captive breeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike the capybara, the pace not only has a long gestation but usually bears a single young. Thus, the output of a single breeding female may be, at best, two offspring per year (at least this is the expected production in the wild). This "slow" breeding is a limitation. In captivity, however, there is a possibility that it can be speeded up.4 The fact that paces bond together in pairs is a limitation. If every female has to be accompanied by a male, then many (otherwise unnecessary) males have to be fed and maintained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Male paces are considered difficult to keep as household pets because they spray females (or human substitutes) with a mixture of urine and glandular secretions. This can occur several times a day. In addition, they have anal glands that produce a musky odor that some people find objectionable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Although paces are common in some areas over the vast region from Mexico to Argentina, they are little understood, even by zoologists. In fact, most data concerning this animal have come from interviews with local hunters. Intensive field work is needed to develop an understanding of the pace's biology, status, and habitat requirements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The popularity of pace meat makes it urgent to start this work as well as to begin breeding paces on an organized basis. Such projects would lay the groundwork for preserving the species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Particular research needs concern the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Age structure and reproductive performance;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Growth rates and feeding habits;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Behavioral patterns in captivity;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Nutritional requirements;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Meat quality;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Helminth and arthropod parasites;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Role in transmitting or perpetuating diseases;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Reproduction (such as external manifestations of estrus in females); and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Genetic variations that would allow the selection of animals adapted to captivity and females that produce multiple offspring - twins, triplets, or more.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Ways must be found to introduce more than one female to each male without inciting aggression. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">24 Vizcacha</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g027a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcachas (Lagostomus maximus) are soft-furred South American rodents that look like long-tailed guinea pigs. They can weigh as much as 8 kg and are resilient animals, inhabiting dry pampas and shrub lands in northern Argentina and neighboring countries. They seem to have promise for producing meat and hides in marginal zones whithin their native habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like chinchillas (page 277), these rodents provide a prized furry pelt. They also provide meat that reportedly tastes "as good as hare," which in Europe is considered the epitome of dining. They are easily trapped alive in cheap, homemade, multiple-catch, funnel traps. And they are thought to be suitable for farming on a large scale.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the other hand, vizcachas are currently considered pests because they take grazing from cattle and sheep and because they build large burrows that undermine the land. Government campaigns have eradicated them in the richer agricultural areas of Argentina, but the animals are still common in marginal zones. There is evidence that they become more abundant when domestic livestock overgraze the land. In improverished marginal sites, where other livestock enterprises are unsuitable, the potential exists for game-ranching vizcachas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Because of the potential hazard to new areas, vizcachas can be used only in the pampas regions of southern South America where they are already widespread.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas have short front legs, long, muscular hind legs, and round eyes and ears. Their heads seem oversized in proportion to their bodies. Males weigh 5-8 kg, females 2-4.5 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members of the same rodent subfamily as the chinchilla, they have a thick, soft, valuable fur that is grey or brown above, whitish or greyish below. They are, however, much larger than chinchillas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although basically running animals, vizcachas often jump bipedally (like kangaroos), and they sit erect while eating or grooming. The forefeet have four long flexible digits used to grasp food. Their soles and palms are naked and have fleshy pads (pallipes).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas once swarmed widely over the savannas of southern Paraguay, Bolivia, and Argentina, but they are being systematically exterminated. Today they inhabit isolated areas of north, central, and western Argentina and southern Paraguay.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Since 1907, these animals have been mercilessly hunted. The governments of the Argentine provinces where they are mostly found, reward hunters for killing this "pest." However, the numbers are so reduced that now there is no need for a bounty system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas live in flat, dry, steppelike plains; in dry woodland (Chaco), and in low mountains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The fact that these rodents eat their own droppings (coprophagy) augments their ability to utilize natural forages, and allows them to abound in degraded zones. They feed on any plant materials they can find near their colonies, particularly grasses. In feeding trials, their daily dry matter intake was 2-5 percent of the body weight. The metabolic efficiency (dry matter per kg) was 33-56 percent; the digestive efficiency was 50-60 percent.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Male vizcachas become sexually mature at about seven months of age and remain fertile throughout the year. The gestation period is long: 154 days. Litters contain one or two young. Newborns are well developed, fully furred, and open eyed, although they cannot fend for themselves for at least three weeks. In the wild, one or two litters are reared each year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas are nocturnal and are active year-round. They inhabit underground burrows, living in colonies often containing many individuals. They collect a variety of materials (for example, bones, sticks, and stones), and heap them in piles above the entrances to their burrows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Their hearing and sense of smell are acute. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p274a.png"></center><br>
+ Vizcachas native range</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas have long been hunted for food as well as for their fur. Their meat is often consumed in pickled form in southern South America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The skins are fabricated into table runners, rugs, bedspreads, slippers, and belts. The skins are also popular for overcoats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcachas can be kept in captivity without major difficulty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In zoos, vizcachas are fed the typical diets furnished for vegetarian rodents: rolled oats, green vegetables, bananas, apples, and bread. They are usually kept indoors in wire-fronted cages, about 1 x 2 m in size, and provided with sleeping boxes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known about vizcacha husbandry, but in one trial, weight rose most rapidly in males until age 18 months (the average size was then 5.3 kg) and subsequently slowed. The heaviest male was 7.3 kg at 30-32 months. The female's weight gain was greatest until 16-18 months (average size 3.3 kg).3 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The animals seem well adapted to harsh sites where the climate and forage make raising conventional livestock difficult.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The meat is white and has a good nutritive value because of its high digestibility, low levels of saturated fats, and high levels of proteins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In marginal zones of the pampas, these rodents appear far more productive than traditional livestock.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Vizcachas may do considerable damage by foraging in cultivated crops. As noted, ranchers claim that they take grazing away from domestic animals, 10 vizcachas eating as much as a sheep. In addition, they claim, vizcachas destroy pasture with their acidic urine. And the large burrow systems sometimes create a hazard.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because their reproductive rate is low and their growth rate is only moderate, their commercial breeding might not be profitable except in well-designed projects with clear markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcachas require sturdy pens, which implies a high initial cost for materials such as concrete and brick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcachas can be aggressive to one another, especially in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">There are several possible research projects, including:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Gathering specimens from different regions for comparative evaluation of characters such as biology, chromosome type, reproductive physiology, social behavior (both in its wild state and under controlled conditions);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Attempting captive rearing and small-scale husbandry;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Assessing performance under various environments; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Quantifying productivity and population dynamics in relation to rangeland use and improvement practices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A rational cropping program based on wild stocks is perhaps more viable than captive breeding. This could be organized so as to keep vizcacha numbers in check while sustaining a small chain of processing plants by providing a constant supply of meat and skins. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">25 Other Rodents</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The 10 previous chapters have described some rodent species that show promise as microlivestock. Rodentia, however, is one of the largest families of mammals, and the species highlighted by no means exhaust the possibilities. In this chapter we briefly mention others that deserve consideration and exploratory research. These might prove to be potential resources, at least in localized situations. Several are fast nearing extinction and they deserve protection and immediate attention from animal scientists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHINCHILLAS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the high Andes of South America are found the short-tailed chinchilla (Chinchilla brevicaudata) and the long-tailed chinchilla (Chinchilla lanigera). These plump little rodents have fur that is possibly the thickest, softest, and warmest of any animal's.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the surface they would seem to be ideal candidates for microlivestock in Third World regions. Indeed, in recent years chinchilla-rearing has been successfully carried out in northern India. However, raising these animals for commercial markets is a highly specialized and costly business because only rare and expensive breeding stock produces top-quality pelts, and all other pelts are worthless in today's marketplace.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These guinea-pig-sized animals have round ears, a bushy tail, and range from 25 to 50 cm long. Adult males rarely weigh more than 500 g, but females may weigh up to 800 g.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PACARANA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The pacarana (Dinomys branickii) is the third-largest living rodent only capybaras and some beavers are larger. But little is known about this seldom-encountered, forest-dwelling species. Nevertheless, pacaranas appear to be likely candidates for domestication. They are amazingly even-tempered and peaceful, and become surprisingly tame.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because these animals are endangered they are unlikely candidates for microlivestock in the short run, but their large size and good meat could be the stimulus for an international effort to study, protect, and rear them in large numbers before it is too late.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacaranas are found along the eastern foothills of the Andes, including parts of Bolivia, Brazil, Colombia, Ecuador, and Peru. Their area of potential use is in Latin America and the Caribbean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It would be advantageous for livestock scientists to investigate this species in captivity. Studies are needed of the animal's general biology, including its nutritional requirements, reproductive capacity, behavior, and physiology. For wildlife specialists, there is a compelling need to protect this species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SPRINGHARE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Scattered through the dry lands of eastern and southern Africa - on numerous grasslands, plains, fossil lake beds, hill slopes, and floodplains - is the springhare (or springhaas). With its powerful hind legs, tiny forelegs, upright stance, and hopping gait, it looks something like a tiny kangaroo. It is commonly seen at night, eyes glowing a characteristic red in the headlights.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This animal is an important source of food and skins for rural peoples throughout southern Africa. In Botswana, it is the principal bushmeat in the human diet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Springhares are 35-40 cm long and weigh 3-4 kg. There is one species (Pedetes capensis) and two subspecies: the East African springhare and the Cape springhare (formerly Pedetes cafer). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROCK CAVY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The rock cavy (Kerodon rupestris) is closely related to the guinea pig and occurs in the impoverished semiarid region of northeastern Brazil. It is large and lean and has a face somewhat resembling a dog's. It is hunted extensively and is an important source of meat for country people, who consider it a delicacy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This creature might be suitable as a microlivestock. It consumes leaves and bark, and breeds well in captivity. Famine is a serious periodic problem in the often-drought-stricken area, and protein deficiency is common. The rock cavy, like the guinea pig, may be amenable to domestication and may be able to provide the people with better nutrition. However, it is difficult to keep in a cage because it moves fast, climbs well, and easily slips out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because these rodents occur in rare and patchily distributed habitats, they are in desperate need of protection, whether or not they prove to have any long-term utility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SALT-DESERT CAVY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A smaller relative of the mare (page 256), the salt-desert cavy (Dolichotis salinicola) is rabbitlike in appearance and behavior. It has large ears and eyes, long legs, and a short tail. It lacks the mare's white rump patch.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This animal inhabits dry, salty areas of the Chaco desert, particularly areas of dry, woody brush. Specifically, it is found in the saline western Chaco of Paraguay and northwestern Argentina, as well as in the extreme south of Bolivia. It is about 45 cm long and weighs up to 4 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it might make a useful microlivestock in its native habitat, the salt-desert cavy breeds rapidly and can cause much devastation; it should never be introduced to new regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The salt-desert cavy's life in the wild is largely unknown; however, some have been successfully raised and bred in zoos. Exploratory research on keeping and managing these little creatures is warranted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">OTHERS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted earlier (page 193), it has been estimated that 42 peoples of various cultures eat rodents. Most of these eat locally available species, some of which are listed below. Whether any have long-term usefulness is uncertain, but study of them in the wild and in captivity could result in some interesting and valuable scientific discoveries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Solomon Islands Rodents</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Solomon Islands in the southwest Pacific are home to a collection of six rare giant rodents that live in the rainforest canopy. At one time they were important food items. Archeologists have dug up tens of thousands of rodent bones on sites where people lived as long as 30,000 years ago. These mysterious animals were classified last century, but most have not been seen by biologists for decades. However, one, the thinking rat (Solomys sapientis), was rediscovered in 1987 - the first time it had been reported seen since 1901. The others may also be inhabiting the dense and undisturbed forests.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The thinking rat was located on the island of Santa Isabel. It proved to be gentle, unafraid, and friendly. It lives in the forest canopy, weighs up to 1 kg, and feeds on nuts and fruits. Efforts to build up the population are urgently needed. The other species should also be sought.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Such animals could be a resource for rainforest production (perhaps in the manner of butterfly farming in Papua New Guinea2). They may never be plentiful enough to be food sources again, but they could nonetheless become valuable. Zoos the world over are likely first customers for these scientific curiosities if production can be boosted and the populations secured.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giant New Guinea Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The giant New Guinea rat (Mallomys rothschildi) is often eaten in New Guinea. It is little known to science but is odorless and easily tamed. It grows so fast that it becomes as big as a guinea pig even before it is weaned. It feeds on a wide variety of tubers and vegetable products. An attractive species native to mountain forests, it has a long heavy tail and black fur with white ticking.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Porcupines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Porcupines, brush-tailed porcupines, and their relatives are distantly related to guinea pigs and are widely consumed as food in tropical regions. Examples are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Indian porcupine (Hystrix indica) and other species of South Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Cape porcupine (H. africaeaustralis) of southern Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Prehensile-tailed porcupine (Coendou prehensilis), which inhabits Central and South America. These nocturnal creatures live in the thick, leafy crowns of trees or in hollow trees or holes in the ground. Although often belligerent among themselves, they can be very friendly and tame toward humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kiore</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The kiore (Rattus exulans) was formerly an important component of  the diet of most Polynesians, including the Maoris of New Zealand. It  has been successfully reared in captivity in recent times. Unlike many  other rodents, this animal is normally not a scavenger; it is a clean,  even fastidious feeder that is basically a vegetarian (flowers, berries,  nuts, and seeds) and is reckoned remarkably good eating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Soft-Furred Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The soft-furred rat (Praomys) is relatively large and slender and is  found in the tropical forests of Africa from sea level to more than  3,000 m. Among the most common rodents of the African jungle, it is  trapped almost everywhere. It feeds largely on plants, but eats large  quantities of ants and other insects. It has been raised successfully in  captivity and is eaten by villagers in Malawi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giant Squirrels</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The giant squirrel (Ratufa bicolor) occurs throughout Indonesia,  Malaysia, and Sri Lanka. It is the largest squirrel on earth, almost the  size of a cat. A related species, the palm squirrel (Funambulus), also  gets very large. It can crop nuts in the very high treetops that are  inaccessible to people. It is widely used as food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Squirrels</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Squirrels of the genus Callosciurus (notably C. notatus and C.  prevostii) are significant pests on cocoa, oil palm, and mixed fruit  plantations in Southeast Asia. They can be reared and bred on a diet of  most types of fruit as long as a little protein, in the form of insects or  cooked wheat, is available. The systematic use of this animal may  offer a chance to turn a pest to advantage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cloud Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Two species of slender-tailed cloud rats (Phlocomys spp.) are found  only in southeastern Asia. They live in tree cavities, climb well, and  are well adapted to tree life.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of these (P. cumingi) lives in the northeastern part of Luzon in the Philippines, where it appears to be thriving. It has a large body and long tail and is the largest member of the mouse subfamily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other (Crateromys schadenbergi) has long, thick hair and a thick, bushy tail. It lives in the mountainous areas of northern Luzon. A nocturnal animal, it feeds on buds, bark, and fruits.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both are attractive, even fascinating, creatures that are relentlessly hunted for food. They might make useful livestock in forest situations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Spiny Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Cayenne spiny rat (Proechimys guyannensis) is found throughout most of South America. It is tasty, easily kept in captivity, and is popularly used in Colombia for food. A nocturnal animal, it is one of the most common mammals in many areas. It has been raised in captivity on bananas, sweet corn, coconut, grain, and various seeds.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bamboo Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The bamboo rat (Rhyzomys spp.) is the largest rodent on the island of Sumatra in Indonesia; it weighs 2-4 kg and the body can be as long as 45 cm. It prefers to live in bamboo thickets and is hunted and eaten by many local peoples.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a need - in considering any sort of game farming - to relate the animal's "preferred" conditions (range, feed, temperature, etc.) to the varying land and climate types not being effectively utilized. In other words, rather than looking at animals that might be farmed, it might be necessary to consider the terrain and climate and then seek animals that would "do" well under those conditions. One major fault with traditional farming has been the tendency to force traditional livestock onto unsuitable land. This has given rise to numerous serious problems. In many cases the most suitable use of an area is provided by several species grazing together to mutual benefit (e.g., goats and sheep on New Zealand hill country improve grazing for each other if ratios are right).</P>
+<P ALIGN="JUSTIFY">David Yerex</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g028a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part V : Deer and Antelope</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Several types of tropical deer' and antelope are no bigger than an average-size dog. These "microdeer" and "microantelope"2 are the smallest of all ruminants. Although there is considerable experience with rearing and utilizing the larger species, little is known about these miniature ones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given research, mouse deer, muntjac, musk deer, pudu, brocket, huemul, and water deer, as well as half a dozen small antelope, might prove to have considerable potential. Collectively, they come from diverse habitats, ranging from equatorial to subarctic and from moist rainforest to arid savanna. They are adapted to some environmental conditions that are only marginal for production of conventional livestock because of drought, heat, diseases, altitude, or other constraints.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DEER FARMING</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Deer appear to be unlikely candidates for livestock, but reindeer were probably among the first domesticated animals and have been draft animals for perhaps 2O,OOO years. Even today, tens of thousands of reindeer pull sleighs in the European arctic. On military expeditions, the ancient Romans took along herds of fallow deer as a source of meat, and more than 1,000 years ago deer were annually herded off the Scottish Highlands for winter meat supplies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years, there have been breakthroughs in the "domestication" of deer. Species already being [armed are: red deer (New Zealand, Australia, Taiwan, Korea, Russia, China, Scotland, the United States), elk (New Zealand, Canada, the United States), fallow deer (New Zealand, Australia, England, Denmark, Sweden, Switzerland, Germany, the United States), ruse deer (Australia, Mauritius, New Zealand, Papua New Guinea), sika deer (Taiwan, New Zealand), musk deer (China, India), and PFre David's deer (New Zealand). Although not truly domesticated, even the moose has been tamed in Scandinavia and the Soviet Union, the calves being bottle-raised from three days of age.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Zealand has made particular progress in domesticating large deer (see sidebar). It seems probable, therefore, that similar success with small deer could be achieved. For those seeking interesting, pioneering research, microdeer are good candidates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ANTELOPE RANCHING AND FARMING</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The worldwide experiences in domesticating various deer species suggest that the organized production of small antelope should also be considered. Several large species have already been studied and are used in game farming in eastern and southern Africa. Similar research on the smaller species, which so far have received little or no attention, is one of the more speculative ideas in this report. We put it forward only for consideration by researchers, but if exploratory studies prove successful, this is a topic deserving international support.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some parts of Africa there are large expanses of uninhabited lands, and producing any sort of livestock there is limited by aridity and by the presence of tsetse flies. But in this habitat live tiny antelope such as dikdik, suni, and klipspringer. In the rainforests and secondary forests are found duikers and the royal antelope. All these creatures have advantages that justify their consideration as microlivestock: they have a more rapid turnover than the big species, and they produce a high yield of quality meat. In addition, compared with cattle, these native ungulates make better use of the habitat. Cattle select a limited number of grass species; antelopes choose a wider range, and also include fortes, bushes, and trees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More important perhaps is their resistance to many diseases. Most, if not all, are resistant to trypanosomiasis, the disease carried by the tsetse fly. They are not immune to this and other tropical diseases, but they are less susceptible than cattle. However, part of this may be owing to their ability to roam widely; if confined and treated like domestic animals, they may also require some protection against parasites and diseases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antelopes are also more productive than cattle; that is, they produce a given quantity of meat more quickly because they breed better in the African hinterlands and grow more rapidly on its existing forages. On the other hand, they generally require a richer diet than cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, in their favor, antelopes affect the habitat less than the same density of cattle does; they spread out more while feeding and thereby cause less erosion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are two ways of exploiting this potential. One is by "cropping"taking a controlled offtake from free-ranging populations without depressing the overall population. Several methods for producing meat this way from large antelope have been attempted in countries such as Kenya, Tanzania, and Mozambique. Few have persisted. Often this has been due to opposition from the vested interests of the cattle industry and from stringent veterinary requirements. Nonetheless, game ranching offers a means by which marginal lands could produce food of a high nutritional quality on a sustained basis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other method is by farming - that is, domesticating or partially domesticating the animals, keeping them in pens or herding them like cattle. Experiments in farming antelopes have been less common than game ranching, but one of the most interesting is that conducted on the Galana Ranch in Kenya. Three wild species - buffalo, eland, and oryx - were selected for comparison with cattle. Half-grown animals were preferred for capture, and it was found that if they were kept in the dark for the first week after capture, and then gradually provided with more and more space while they became familiar with people, after about six weeks they could be released into the open and herded from place to place. Grazing during the day under the eye of a herdsman, they allowed themselves to be herded back to a pen at night in the traditional African manner, where they would sleep around the campfire. This was a promising advance in behavior modification leading toward domestication. The oryx, for example, gained weight on grazing that would not even sustain cattle, and it required only a quarter of the amount of water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At bottom, the question is not what contribution antelopes can make to the African larder, for they already make a significant contribution through (largely illegal) hunting. The question is whether farming could make them a sustainable asset rather than their being senselessly squandered, as is the case at present. Although its potential has yet to be realized, antelope farming is not a panacea for Africa's food problems, and certainly not the world's, but it might pave the way to a new and more gentle way to make savannas useful. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TAME GAME</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Since the 1970s, deer have taken the place of sheep on many New Zealand pastures, and today the country has more than 5, 000 deer farms carrying over one million head, mainly red deer. It is now common along country roads to see tall fences surrounding graceful deer quietly grazing ryegrass and clover. And there are all the appurtenances for deer that exist for cattle and sheep. Auctions and shows are held regularly. Deer farmers have a professional association and produce their own glossy magazine. Government scientists publish pamphlets on the care and management of deer. There are recognized stud stags, computerized recording schemes for breed improvement, and even veterinary services specifically for deer. Hybridization between wapiti and red deer, and PFre David's deer and red deer, is accepted practice. The animals are moved by use of dogs (which command by mere presence rather than by bark or bite), and herds of up to 80 are shifted by truck. Slaughter facilities specifically for deer are in operation throughout the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This transformation of a nervous, jumpy, and retiring wild species into a farm animal is a remarkable achievement. Once accustomed to people, many specimens become gentle, even affectionate, and will come at a farmer's call. Males are generally as easy to handle as females, except during the rutting season when they become aggressive and cannot be handled at all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, even at the best of times the farmed deer must be handled gingerly. If the causes of stress are not quickly suppressed, hysteria can erupt throughout a herd; in an instant, quiet animals can be leaping suicidally in all directions, disoriented, diving head-on into fences, charging gates. Chronic stress, the causes of which are not always obvious, can result in illness or death, although this trait diminishes in subsequent generations of farm-born stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A deer farm has to be laid out to certain special specifications. To prevent escapes, the boundary fences must be 2 m high with netting of 15- or 30-cm mesh. Inner fences need only be 1.5 m high. Water troughs are placed in the middle of the fields, and nothing is allowed to jut inwards from the fences because the animals tend to walk fencelines and take comfort from the illusion of openness. Because deer like to wallow in hot weather, some farmers also provide shallow waterholes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Deer yards can be of any design, but the sides of the passageways and holding pens should be solid, as deer do not see fences very well, particularly when under pressure, and may injure themselves in a leap towards what appear to be wide open space. (New Zealanders usually make the sides of plywood.) Also, the holding pens should be roofed, as semidarkness has a calming effect. Animals that in the sunlight become hysterical on seeing a person in the distance, can, in the relative darkness of a roofed shed, be touched and even given injections.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the special facilities, however, handling deer takes time and care and experience. The most successful farmers spend much time among the deer so that the animals become accustomed to human presence. This helps to make yard work easier. Also, new arrivals are allowed to wander through the yards on their own to become familiar with them. In addition, special tame deer are used as leads or decoys to encourage the rest of the herd to follow. Using such simple techniques, a formerly intractable species has become almost fully domesticated.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">26 Mouse Deer</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g029a.png"></center><br>
+ Lesser Malayan Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse deer1 (Tragulus spp. and Hyemoschus aquaticus) are among the smallest ruminants known. The lesser mouse deer of Southeast Asia is probably the smallest; an adult stands only 20 cm high and weighs a merc 1-2.5 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although they look vaguely like tiny deer, mouse deer differ in several particulars. The stomach is simpler and (like the camel's) has three instead of four effective compartments. Rumination occurs, but mouse deer are the most primitive of all ruminants. Indeed, they share a number of characteristics with nonruminants, including lack of horns or antlers; continually growing, tusklike upper canines in males; sharp-crowned premolars; and four fully developed toes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Virtually unchanged in 25 million years of evolution, these are solitary, nocturnal, retiring animals that have seldom received detailed research. Whether they might make suitable microlivestock is unknown. However, they seem to be tractable, and people in Southeast Asia (Sarawak, for instance) have traditionally kept at least one of the species as backyard pets. Moreover, mouse deer are indigenous to tropical lowland regions and withstand the heat and humidity that are stressful to most conventional livestock species. They probably also are resistant to many diseases of those torrid regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the United States, mouse deer are being raised as laboratory animals for basic research on ungulates. This is because the animals are easier to handle than large deer or goats.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Mouse deer are graceful, lithe, and look somewhat like large rodents. The Asian species are the shape and size of an agouti (see page 198); the African species is more like the pace (see page 262). All have short legs, a small head, and a pointed snout. Adults weigh from 1 to 5 kg, depending on species. The head and body are only 04-1 m long, and the shoulder height is merely 20-36 cm. Males are generally smaller than females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most species the body is a rich brown with white spots and stripes. The belly is usually white. The animals stand on the middle toes, so that the lateral ones do not touch the ground. Neither sex bears antlers. In males the upper canines form long tusks that may extend outside the lips and even to below the line of the jaw.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Twenty-five million years ago, early forms of mouse deer existed throughout Asia, Africa, and Europe. Today's species are restricted to tropical forests and mangrove thickets of Southeast Asia and Central Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of the three Asian species, the Indian mouse deer occurs in southern India and Sri Lanka; the larger Malayan mouse deer occurs on the mainland of Southeast Asia and the lesser Malayan mouse deer occurs on Java as well. The water chevrotain, a related African animal, is found from eastern Zaire to the Atlantic coast. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p292a.png"></center><br>
+ figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p293a.png"></center><br>
+ Range of water chevrotain .</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In recent years, human encroachment into the forest has caused the destruction of the mouse deer habitats and has put various mouse deer species under a pressure that is causing their populations to decline.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals inhabit equatorial forests and mixed secondary tropical forest. They generally live among undergrowth on the edges of dense lowland rainforests. They especially haunt rivers and swampy bush areas, seeking escape by water when in danger.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Little about these animals is recorded. Essentially vegetarians, they feed chiefly on fruits, supplemented by leaves. They also eat insects (for instance, ants), if available. They do not seem to eat grass.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The premolars of the mouse deer are designed for piercing and chopping food rather than for chewing. As noted, the stomach consists of three functional compartments: the rumen, the reticulum, and the abomasum. (The omasum of ruminants is represented only by a rudimentary area.) The stomach occupies almost the whole of the abdominal cavity, extending from the diaphragm to the pelvic inlet, which provides this small animal with large food-storage capacity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The blood has a very high erythrocyte (red blood corpuscle) count as well as the smallest erythrocyte size of any mammal. The flesh is "white" and the muscles contain little myoglobin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mature females reproduce almost continuously, and usually regardless of season. In the female larger Malayan mouse deer, mating occurs within 2 days of giving birth. In the African species, many births are synchronized with the rainy seasons, when fruits are plentiful. The gestation period is about 5-6 months, depending on the species. There is only one young per birth. Weaning normally occurs at 2-3 months, but can occur as early as 3 weeks, with sexual maturity achieved at 4-5 months (Asian species) and 10 months (African species). The young stay alone, hidden in vegetation during the first month or two.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Mouse deer are shy, keeping to dense jungle and depending on concealment for protection. Although often present in large numbers, they are seldom seen. Preferring to be near lakes, rivers, or streams, they can nevertheless wander I km or more from water. They feed mostly at dusk or at night, sheltering in undisturbed areas or under shady bushes during the day. They utter weak, bleating sounds, and when frightened, jump a meter or more in the air.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Communication is by scent and calls. The African species possess anal and preputial glands, with which, along with urine and feces, they mark their home ranges. Males of both Asian and African species possess a chin gland to mark either the vegetation or their mates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse deer are among the most excitable, nervous, and jumpy animals. One must tread softly in their presence for fear of causing absolute pandemonium and mishap.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Mouse deer are widely sought by native people for food, and their meat is highly regarded. Dressed carcasses have a high proportion of muscle (84 percent in Asian species), low proportion of bone (15 percent), and an insignificant amount of fat. The ratio of muscle to bone is large - 5.6:1. The mean dressing percentage of 62.1 percent is greater than that reported for cattle, water buffalo, or goat.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Adults are wild, generally intractable, and "flighty," but young animals (at least of the Asian species) tame readily and make good pets. Nevertheless, these are delicate creatures and must always be handled gently. Individuals caught in the wild tend to bash against the sides of cages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite an unpromising temperament, Asian mouse deer are regularly bred in zoos, including those in Amsterdam, New York, and Zurich. They also have been reared successfully in small enclosures at several research institutes, such as the I.R.E.T. Institute, Makokou, Gabon; the Institute of Medical Research in Kuala Lumpur, Malaysia; and at Fort Detrick in the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perhaps the best way to breed this animal is by using the battery system of small units comprising one male and two females per cage. The costs are mostly for obtaining suitable enclosures and for feeding and watering troughs.6 The cages must be covered with mesh because the mouse deer can jump. However, the covering must be sufficiently high to allow the male to stand with its body vertical during copulation.7 They can be fed a variety of foods and grow well on stems of bean plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, these are small, seemingly tractable creatures that are at home in the heat, humidity, and diseases of tropical lowlands. They might play a particularly important role as livestock for tropical rainforests; the forests could be left standing while the animal still produces meat. Today, in a widely condemned process, tropical rainforests are being felled in order to raise cattle for meat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Small size makes mouse deer easy prey for various predators. In the wild, snakes, crocodiles, eagles, and forest cats feed on them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse deer are among the most excitable, nervous, and jumpy animals. One must tread softly in their presence for fear of causing absolute pandemonium and mishap.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The different species are solitary, and it is difficult to keep many individuals (especially males) in a restricted space. They must be kept in a quiet enclosure, with cover or good shelters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The survival of these four "living fossils" depends on conserving their rainforest habitat and restricting hunting, especially night hunting. But studies of their propagation and management are also imperative.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In particular, research is warranted on various aspects of their husbandry, such as enclosure design, space requirements, and health. A special research need is to understand the animal's nutritional requirements and to develop diets for use in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">27 Muntjac</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g030a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muntjac, or barking deer (Muntiacus species), are among the most widespread but least known of all Asian animals.1 They are almost the size of an average dog and they bark, but they are true deer. These little animals adapt well to captivity and have been introduced to zoos and wildlife collections throughout the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years one species, the Reeves' muntjac, has become established in England, and a few specimens have settled into semicaptivity - staying behind fences, accepting human presence, and even eating out of people's hands. In Sarawak, villagers have also been known to keep muntjac, feeding them a diet of rice with some leafy matter occasionally added.2 Such experiences show that these small, shy deer can be calm and adaptable. It also shows that they can be raised on practical, artificial diets and that they are not strictly browsers. This creates the possibility (admittedly highly speculative) that they might make future microlivestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muntjac produce lean, palatable venison and perhaps could be farmed on an organized basis. They are native to severe environments where heat, humidity, and endemic diseases make raising conventional livestock difficult. In future, given research, muntjac might become widespread contributors to Asian economic development. The lessons learned in captive breeding could also be important for conserving endangered muntjac species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One species, the Indian muntjac, has an incredibly low chromosome number (2n=7 in males; 2n=6 in females), which makes them particularly promising candidates for mammalian genetic studies. This species has regularly bred well in both zoos and research institutions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muntjac are small and slender. Reeves' muntjac, the smallest, has a shoulder height of 45-60 cm. Fully grown, it weighs less than 20 kg; commonly it is merely 10-12 kg. The Java subspecies of the Indian muntjac is the biggest, with a shoulder height of 58 cm and a mature weight of 43 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antlers on the males usually include a main prong as well as a much shorter brow tine. Even the main prong is no larger than a finger, but its pointed tip is hooked and must be treated with caution. There are also two tusklike canine teeth that protrude from the mouth. These have sharp points and a knifelike posterior edge, capable of cutting to the bone a person's finger or another muntjac's rump.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coloration varies from deep brown to yellowish or greyish brown with cream or whitish markings, depending on the species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muntjac are native to a vast region from eastern China to Nepal, India, Sri Lanka, and Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Almost a century ago, Indian and Reeves' muntjac were introduced to a deer park in southeast England. Some escaped, and (as noted) the Reeves' muntjac has adapted, spread, and settled down to life in the countryside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Of the five muntjac species, the Reeves' and the Indian are well known and in no danger. For instance, recent estimates of annual game production have shown that there are about 650,000 Reeves' muntjac in China. The other three are threatened with extinction. Black, Roosevelt's, and Fea's muntjacs are virtually untried in captivity, but the success of raising Reeves' muntjac in English country gardens suggests that perhaps their populations could be saved through captive breeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In their native habitats, these small deer are usually found in dense vegetation on hilly ranges at elevations up to at least 3,000 m.3 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p301a.png"></center><br>
+ The native ranges of the various muntjacs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muntjac seem to be primarily browsers. However, in captivity they eat fresh grass, alfalfa hay, and feed pellets. They also readily eat root crops such as potatoes, carrots, and parsnips. They are "concentrate selectors," preferring foods low in fiber and rich in protein and nutrients. Captive specimens reportedly need; a supply of cut browse.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeding may occur year-round, but in practice it is synchronized with certain seasons. The first conception can occur as early as 6 months of age. One, occasionally two, young are born after a gestation of about 200 days. They weigh around I kg at birth, and the fawns usually remain hidden until they can move about with the mother. The females mate within a few days of giving birth. Life spans up to 16 years have been recorded.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, the Indian muntjac is a species of great cytogenetic interest. It has the lowest diploid chromosome numbers yet found in a mammal.4 The large, easily distinguishable chromosomes are a great advantage in tissue culture, and many laboratories now have muntjac cell lines. The karyotypes of the different species' chromosomes are very different; the Indian and Reeves' muntjac can hybridize, but the offspring are infertile.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muntjac are dainty and have a captivating charm. Always on the alert, they are active both day and night. Often they will bark for an hour or more, but typically they bark for only a minute or two. When panicked, captive muntjac may rush into fences or walls. They can easily leap barriers 1.5 m high.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males are highly territorial and defend their territories vigorously. Adult females also inhabit a specific territory, which they defend against strange individuals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males mark the ground at intervals by lowering the head and rubbing the frontal glands on the ground and by scraping their hooves against the ground. They mark trees by scraping the bark with the lower incisors and rubbing the base of their antlers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In Asia, muntjac are hunted for meat, skins, and antlers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Muntjac thrive and, at least under ideal conditions, breed freely in captivity. However, they may stop breeding if they are crowded.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In England, zoos and private collections keep as many as six muntjac in an area of 40 x 20 m. Plenty of cover is provided for the animals to hide in. Fences almost 2 m high are used. (Lower fences are reportedly adequate where there is no risk of the deer being panicked by dogs or people.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Like other deer, muntjac produce extremely lean meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They seem to be healthy animals. In Britain, wild and captive muntjac have few gastrointestinal worms, and ectoparasites such as ticks and lice are not a problem. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MUNTJAC</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In England, far from Asia's forests and mountains, the Reeves' muntjac is the subject of a peculiar chapter in the otherwise unhappy history of introduced species. Charmed by the deer's odd characteristics, the British have welcomed its invasion into gardens around the country. Now, there are tens of thousands of muntjacs on the loose, and some people have even adopted them as pets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although other alien species have wreaked havoc on native plants and animals, muntjacs appear to be a merciful exception. At least over the short term, muntjacs "have proven to be an almost innocuous asset to the countryside. They give pleasure to thousands and pain to few. Eating mostly ivy, grass, leaves, and prickly bushes, they rarely feed in one place long enough to do much damage except to an occasional suburban garden." </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life for many muntjacs is made soft by homeowners who find the deer's large, dewy eyes and tiny antlers irresistible. The kind-hearted suburbanites put out salt licks, water, and kitchen scraps, and they built snug little shelters against the cold north wind. "All our adult deer will take food from the hand," says Walter Buckingham, who has kept muntjacs for five years in his garden in the county of </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hertfordshire, just north of London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The adaptable immigrant is colonizing new areas so rapidly, say biologists, that soon there may be more in England than in Asia. "In time," predicts muntjac-researcher Oliver Dansie (pictured opposite), "it may eventually establish itself as our most widely distributed deer species."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In the wild these animals are not gregarious and are generally found alone or in pairs. Because of their strong territorial instincts, large males may not be able to be kept together without fighting. The upper canine teeth can inflict serious wounds. Some females are intolerant of each other as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muntjac are fragile; they cannot be held by the legs, for example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some infectious diseases may prove to be of epizootic importance: foot-and-mouth disease, mucosal disease, epizootic hemorrhagic disease, rinderpest, and tuberculosis (all three types). This may be a problem, especially when people are raising the animals by hand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">To ensure a better understanding of their potential as microlivestock, muntjac deserve research and recognition from animal scientists and conservationists from Nepal to China. The English experience shows how populations of the endangered species might be built up. At present, however, none are receiving any husbandry research; only the two most common species can generally be found in zoos.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals deserve investigation into physiology, reproductive requirements, fertility, nutrition (for example, food preferences, feeding strategies, and food utilization), growth, adaptability and environmental tolerance, diseases, management, social structure, and selection for calm temperament. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">28 Musk Deer</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The musk deer (Moschus species)1 is so small that (like other ungulates in this section) it is only as large as an average-size dog. A gland in males produces musk, a thick, oily secretion that is one of the most valuable substances in the animal kingdom. Musk is used in Oriental Medicine as well as in Europeans perfumes, and in recent year it has sometimes sold for as much as three times the price of gold.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Musk is traditionally obtained by killing these deer and removing their glands. The dried glands, called pods, contain a reddish brown musk powder that has been a commodity in international commerce for more than 1,000 years. Despite bans in India (1972) and Nepal (1973), musk continues to be illegally exported, mainly via Hong Kong, for use in Japan and Europe. In Japan, for example, it is an ingredient in more than 200 different medicines.2 In Europe, musk goes into some of the most famous perfumes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The international trade in Himalayan musk, originating from both northern and southern sides of the Himalayan divide, amounts to 200 kg per year, representing an annual slaughter of 20,000-32,000 male deer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The commercial value of the animal makes it highly attractive for development as a livestock species. The economic force causing its slide toward extinction could be employed to protect and restore both the species and its habitat. Ranching these deer might put musk production on a sustainable footing. It might also encourage habitat protection, because in the harsh climate of the high Himalayas, rearing musk deer could be much more profitable to villagers than raising crops or cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Musk deer are already being farmed under primitive conditions in China, where techniques for extracting musk without killing the animal have been developed. In India, small collections of musk deer have been established by the forest departments of Himachal Pradesh and Uttar Pradesh. For several years authorities in Nepal have successfully extracted musk from an adult male at the Kathmandu Zoo' without apparent harm to the animal.3 These experiences suggest that musk might become a farmed product. So far, however, success has been limited. The Chinese animals, for example, have a high mortality rate and the musk is said to be of poor quality. Nonetheless, these examples are valuable pioneering case studies that deserve recognition, support, and further development.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">With their long ears, arched back, and bounding gait, these diminutive deer remind one of large hares. The pointed face and large ears make their heads strikingly reminiscent of kangaroos. The coarse hair gives them a stocky appearance. The color varies according to species (and subspecies) from rich reddish brown to dark grey or black. The peculiarly brittle and wavy hair probably has good insulating properties, as it consists of air-filled cells arranged like a honeycomb.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Musk deer have an average mature weight of about 6-11 kg and a body length of 50-90 cm. They stand 50 60 cm high at the shoulder and 5 cm higher at the rump because the hind legs are longer than the forelegs. Some dwarf types are only 40-46 cm high. The tail is short, and in males it is naked, except for a terminal tuft of hair, because they mark their territories by constantly rubbing the caudal gland, which is located near the tail, onto objects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All four toes are flexible, which, compared to the rigid hoof of other ungulates, gives a firmer grip on precipitous slopes. The dew claws are enlarged and, together with the central digits, splay out, to minimize sinking in soft snow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Neither sex possesses antlers, but males have long upper canine teeth that project well below the lips. The lower front teeth have a spatulate form that probably helps the animals scrape lichens from the surfaces of rocks and trees in winter, when most vegetation is snow covered. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p309a.png"></center><br>
+ The musk deers native range.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The genus is distributed patchily throughout the forested mountainous parts of most of Asia. One population extends from just north of the Arctic Circle southward to the northern edge of Mongolia and Korea. Others occur in China, northern Vietnam, and the Himalayan region including Bhutan, Assam, Tibet, the Indian Himalayas, Nepal, and northern Pakistan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">During this century, the musk deer has rapidly declined throughout its former regions. In many parts of Afghanistan, Pakistan, India, Nepal, and probably Tibet, it is already regarded as rare, with a distribution that is becoming increasingly localized. Possible exceptions are Bhutan and most of China, where its population is thought to be stable. In southern China, a recent estimate puts the musk deer population at 100,000 head. In western and northwestern China, the population is estimated at 200,000-300,000 head.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is the uncontrolled hunt for musk that in most places is driving this animal toward extinction, but its habitat is also being increasingly destroyed by livestock and woodcutters. Part of the loss to hunters is owing to the mindless way in which the animals are caught. Most are snared in traps or nets or killed by poisoned stakes set on trails. This kills all the animals indiscriminately, even females and fawns, which produce no musk. This waste of reproductive animals is extremely destructive to the populations and is senselessly hastening the musk deer's extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Musk deer mainly occur in upland woodland and scrub areas. They prefer remote, dense vegetation, especially birch-rhododendron forests in mountainous terrain. They are seldom found in treeless regions or areas thickly populated by people. In the Himalayas, the upper limit coincides approximately with the tree line, which is as high as 4,600 m at the eastern end.6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Despite its economic importance and wide distribution, little is known of the musk deer's biology. Nonetheless, it is known that musk deer have a gall bladder, a bovid feature that distinguishes it from the true deer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are browsers, relying on young leaves, buds, fruits, and flowers. During the winter, as snow deepens, they depend more on lichens growing above the snow on rocks or tree bark, although in shallow snow they scrape for vegetation with their hooves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The male's musk sac is unique among deer. Situated between the umbilicus and penis, it contains the gelatinous, odoriferous oil. The amount varies with the season and the age of the animal, but pods of adult males usually weigh about 30 g; occasionally up to 45 g.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males also have a caudal gland under the tail, which secretes a viscous yellow substance with a goaty smell. They mark vegetation with this secretion by rubbing their hindquarters against stems and branches.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Males become sexually mature at about 18 months, but females seem capable of reproducing in their first year. The estrous cycle is 18-25 days; the receptive period lasts 36 60 hours. Gestation varies from 178 to 192 days. Each female usually bears one or two fawns, rarely three. The fawn is precocious - able to stand and move within 15 minutes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Musk deer are shy, furtive animals with keen senses of hearing, smell, and sight. They are normally solitary and are most active at dawn and dusk. Only under cover of darkness do they frequent the more open spaces. Except in the rutting season, more than two animals are seldom seen together; groups usually consist only of a female and her young. The alarm call, a loud hiss, is often accompanied by a highstepping, springy gait.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the wild, musk deer lead "orderly" lives. They use well established trails connecting well-established feeding places, resting places, and "latrines" where they deposit their droppings. Migration is uncommon.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Remarkably sure footed, musk deer climb cliffs and even the trunks of leaning trees. Being small and solitary, they rely on camouflage to avoid predators but flee through established escape routes when disturbed. If cornered, males defend themselves by slashing with their tusks, often inflicting deep cuts and severe injuries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The strong-smelling, reddish-brown musk is obtainable only from this animal.7 It is used as a fixative in expensive perfumes to increase the retention of the fragrance on the skin. In Oriental medicines it is used in stimulants, sedatives, and other products. Some medicinal properties appear to be genuine.8 Recently, highly purified musk has been selling for as much as $27 a gram.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade in the Himalayan musk deer or its products is banned by all countries that are parties to the Convention on International Trade in Endangered Species of Wild Fauna and Flora (CITES). However, products from musk deer in the Soviet Union and China can be traded legally under license. It seems likely that if formal, self-sufficient, musk-deer farming projects can be established elsewhere, with safeguards to minimize poaching, a wider trade would be officially sanctioned.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Since at least 1919, Chinese scientists have been experimenting with the extraction of musk without killing the males. When the sexual activity is at its peak, the males are caught and musk removed from the pod with a runcible spoon (curved fork) inserted into the sac's aperture. The procedure takes only minutes. There are records of up to 9 g being recovered at a time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, China established formal musk deer farms in 1958. They are clustered in the Maerkang, Miyalo, and Manchuan areas of Sichuan Province; the Zhenping county of Shanxi Province; and the Fuziling area of Anhui Province. Despite heavy initial losses of animals, mainly during transportation and acclimatization, the Chinese now breed musk deer in considerable numbers. However, juvenile mortality is still high and longevity relatively short. Zoos in other parts of the world have also had difficulties maintaining the animals.9</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In captivity, musk deer readily accept many foods: lettuce, carrots, potatoes, apples, rolled oats, hay, alfalfa, bananas, some grass, bamboo leaves, and pumpkins, for example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The musk deer's social system may represent an impediment to its successful reproduction in captivity. It is irascible and scares easily. In close confinement, males fight and may have to be isolated from each other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is an inherent danger in any captive-breeding scheme in the Himalayas: resumption of legal trade in natural musk could damage the remaining populations by stimulating the market and providing an outlet for illicit musk from poached animals. Some biologists (notably in India) consider that a total ban on the trade in natural musk from all sources is essential.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So far, removing the musk without damaging the animals has not proved commercially successful because of market resistance. Most purchasers require the entire pod in order to be certain that they are receiving the genuine product. Given a regularized farming program, however, it seems likely that mutual trust would circumvent this lack of confidence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">To protect this species will not be easy. It occurs in vast, remote areas that are difficult to patrol. The local people are poor and traditionally have used it as a source of income and food. The value of musk is so high that smuggling is already well organized and will be difficult to eradicate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is imperative that the status of existing musk deer populations be established. This is especially important in Nepal. The total population may be not more than 500 in the wild.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No matter what is achieved in farming, pressure on populations will only be reduced by protecting the wild specimens. Thus, the dietary requirements and behavior of musk deer should also be evaluated with a view to building up the wild populations directly. If the techniques of breeding and handling can be improved, farming the animal may also indirectly help wild populations by reducing the pressure to harvest them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An alternative to captive breeding might be ranching the wild animals. In this process, males would be caught periodically and the musk extracted before releasing them. The organized, sustainable harvesting is particularly attractive if developed at the rural level with revenue going directly to local people; it would provide them incentive to conserve not only "their" musk deer but also its habitat. For this purpose, today's musk deer hunters could be trained to extract musk from live animals, releasing and recapturing them on a controlled basis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another alternative could be controlled culling at a sustainable level, as is now done in the Soviet Union, where about 5 percent of the population is harvested each year. However, elsewhere annual culls at any level would not be feasible for at least 10 years because the populations are now so low. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g031a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">29 South America's Microdeer</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g032a.png"></center><br>
+ Pudu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South America contains three types of tiny, indigenous deer. None are well known to science, yet they are of microlivestock size, and if given research attention at least two might respond to rearing in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PUDU</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The pudu (pronounced "poo-doo") is native to temperate forests of the Andean region. It is among the smallest of all true deer, adult males being merely the size of small terriers and the females being smaller still. It is very shy and retiring and is endangered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All things considered, this animal would appear to be an unlikely candidate for microlivestock. But wherever it is found, the pudu is mercilessly hunted, and captive rearing might be the only way to save its populations from extinction. Indeed, it is already being raised in experimental herds in Chile and Argentina.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pudus (also called the Andean dwarf deer) once ranged widely through the foothills, valleys, and lowlands of the Andes. They prefer the dark, dank underbrush of the cool rainforest, particularly thick bamboo stands. There are two species: Pudu pudu is distributed in parts of southern Bolivia and throughout much of southern Chile nearly to the Straits of Magellan. It is also found on islands off the Chilean coast. Pudu mephistophiles is distributed throughout the highlands of Ecuador, where it occurs only in cool areas at great height.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With their short legs, stocky bodies, and compact heads, pudus do not look much like deer - more like small antelopes with foxlike faces and spiky antlers. Full grown, they are only 40 cm tall and weigh less than 12 kg. They have thick fur ranging from reddish brown to pale gray.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of the pudu's small size, shy and secretive nature, and forbidding habitat, few people have ever even seen one. Nonetheless, these animals tame easily and reportedly were once kept by South American Indians. Several generations were also once bred in a Paris apartment and were treated exactly like domestic dogs, which most people who saw them for the first time thought they were.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years, habitat destruction has greatly reduced the range and numbers of these attractive and fascinating little creatures. The International Union for the Conservation of Nature already lists them as vulnerable to extinction. Pudu studies are highly recommended, and raising pudus promises to be an interesting and valuable activity that may one day lead to one of the most intriguing microlivestock of all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BROCKET</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Brockets (Mazama spp.) are small deer that occupy the place in South America's environment that duikers occupy in Africa (see page 326). They typically reside in thick brush. They occur widely throughout South America and are found in every country except Chile and Uruguay. They also occur in Central America, the West Indies, and Mexico.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are four species:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">- Red brocket (Mazama americana), the most common and widespread, is found from Mexico to Argentina. It is also the largest species, with a mature weight of about 20 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Gray (brown) brocket (Mazama gouazoubira) is also found throughout Latin America. It is slightly smaller, weighing about 17 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Lesser brocket (Mazama rufina)2 resides in small and scattered locations in Venezuela, Ecuador, Peru, Bolivia, Brazil, Argentina, and Paraguay. It weighs 10-20 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Dwarf brocket (Mazama chunyi) is found only in pockets of forest and brush on certain mountainsides in Venezuela, Colombia, Ecuador, and northern Peru. The smallest brocket, it weighs only 8-12 kg. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Except for their size and color, all brockets look alike. The head,  neck, and tail are short; the ears are wide. The lumbar region is higher  than the shoulders, and this, together with an arched back, gives them a  hunched appearance not unlike a duiker's. The antlers are simple  spikes, never longer than a person's hand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The different species are similar in behavior, too.3 They generally  wander around singly or in pairs. Although frequenting dense cover  during the day, they emerge at night to feed in open areas. Little is  known of their food preferences. But farmers know only too well how  fond they are of melons, beans, peppers, and corn. Doubtless, wild  forest fruits dominate their native diet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although extensively hunted, brockets are so adept at dodging into  dense brush that relatively few get caught. However, small size makes  them vulnerable to many other predators: puma, jaguar, ocelot, and  eagles and other large birds of prey. Near villages the domestic dog is  probably their worst enemy. (Infuriated vegetable growers commonly  set their dogs on them.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although at first sight these retiring, nervous, and agile creatures  seem unlikely to be even potential microlivestock, young brockets are  sometimes caught and raised by people. It is not uncommon to find  them as pets on farms and in gardens. They seem to become very  tame and might therefore make useful livestock at some future time.  At least one species, the grey brocket, adjusts particularly well to life in  and around human settlements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUEMUL</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The third type of South American microdeer, the huemul,4 is a much  less likely candidate. It is very rare, very shy, and has so far shown  little likelihood of settling into captivity. However, huemul conservation  is critical: without urgent attention, the animal will become extinct.  Although totally protected by law, it is declining owing to poaching,  farm dogs, habitat loss and diseases transmitted by cattle and other  livestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are two species:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The Chilean huemul (Hippocamelus bisulcus)5 occurs in high altitude forests, thickets, and grasslands in the Andes of southern Chile and Argentina.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- The Peruvian huemul, or taruca (H. antisepsis), occurs in parts of the Andes of southern Peru and Bolivia as well as of northern Chile and Argentina.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both species live in small herds above the tree line. They are very shy, and even though the Chilean national seal bears the depiction of a huemul, almost no Chilean (or anyone else, for that matter) has ever seen a live one.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At less than 85 cm tall and probably weighing under 15 kg, huemuls are sized to be microlivestock. However, previous attempts at rearing them in Chile have met with little success. Nevertheless, huemuls have been kept in zoos in Germany, and such experiences - together with the increasing knowledge of how to raise red deer and other species - may eventually provide the keys to their continued existence. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g033a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">30 Water Deer</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g034a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known about the water deer' (Hydropotes inermis), but it should be considered along with mouse deer, muntjacs, musk deer, and others as a possible species for microlivestock development. It is comparable in size, and it is unusual among deer for producing large litters: births of triplets or more are common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As with the other species in this section, this is a highly speculative notion; however, there is some justification for it. The Zoological Society of London has successfully established breeding colonies, and other zoos have also bred the animal in captivity. The water deer has the advantage of rapid growth, early maturity, and high fecundity. Indeed, given protection, its populations have been known to increase rapidly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The animal has a graceful and delicate appearance, its best known characteristic being the male's long tusks. Both sexes are about the same size, standing 45-55 cm at the shoulder and weighing up to 19 kg. Body length is up to about I m, and the tail is so tiny that it is barely noticeable. The round-tipped ears are characteristically held erect above the head.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water deer are somewhat like muntjacs, but they are longer in the leg and lighter in build. Their forelegs are shorter than their hindlegs so that they stand slightly higher at the haunches than at the shoulders. This gives them a hunched appearance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The hair is generally thick and coarse, longest on the flanks and rump. The backs and sides are usually yellowish brown, finely stippled with black. In winter, the coat is thick and variable in color; pale fawn and peppery gray-brown are common shades. In summer, the coat is sleek and reddish. Fawns are white spotted at birth, but this dappling soon fades.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Neither sex has antlers. The upper canine teeth, especially in the males, are enlarged, forming curved tusks 7 cm long. These are much bigger than those in muntjacs and can protrude well below the jawline.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In both sexes there is a small inguinal gland present between the hind legs, the only instance among deer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In China the water deer has a wide distribution range. It is mainly found in the provinces of Jiangsu, Zhejiang, Anhui, Jiangxi, Hunan, Hubei, and Fujian, the mid and lower Yangtze River Basin, and coastal areas and islands in central and eastern China. It is also found in Guilin, southern Sichuan Province, Guangxi Province, and Guangdong Province in the south.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Korea, the animal lives along the lower reaches of most rivers, except those in the extreme northeast. Its northern limit of distribution is probably about latitude 43&Yacute;N.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At Woburn Park in England, a few escaped from a herd early this century and have increased and become established in a number of counties, particularly Bedfordshire, Hertfordshire, Cambridgeshire, and Norfolk.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In China, owing to increasing reclamation and cultivation of wetlands, the habitat of the water deer is gradually shrinking. At present the animal is protected by the government, which designates appropriate hunting seasons. It is estimated that about 10,000 are killed each year by hunters. In Korea the water deer is still plentiful. As noted, in England it is maintaining itself and is thriving in some protected parks. It is also reported to be present in France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In its home range, the water deer is usually found among reeds and rushes in swampy areas. It also frequents the tall grasses and sparse shrubs of mountainsides and cultivated fields. In England it has adapted to a variety of habitats, including woodlands. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p323a.png"></center><br>
+ Native range of the water deer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The water deer is chiefly a grazer. It feeds mainly on reeds, coarse grasses, and some tree leaves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As previously mentioned, this is the most prolific species of deer. Up to seven fetuses have been observed in a single pregnant female, although the normal litters are two or three. The gestation period is about 176 days. Fawns are born in late spring or early summer, and weigh only about 0.5 kg at birth. Within 4 days the newborns can live almost exclusively on grasses. Usually, however, they are fully weaned after 4 8 weeks, but remain socially attached to the mother. They appear to become independent after about 4 months. Males become sexually mature at about 5-6 months; females at about 7-8 months.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Water deer are generally seen alone. Even where abundant, they seldom congregate in herds. Females are sometimes intolerant of each other, as are adult males or young males. However, in captivity, several females can graze and rest in loose aggregations. The peak period of grazing activity occurs around dusk. Feeding sessions are interspersed with periods of passive cud-chewing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water deer "bark" at intruders. During the rut, males are especially noisy and aggressive, and defend their territories with vigor. Fighting involves striking their tusks into the shoulder or back of their opponents. 3 Information from Lu Houji. These are extremely excitable little animals. When upset, they often "hump" their backs and bound away like rabbits. They are also good swimmers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In China the water deer are hunted for their meat and skins, and newly born fawns are killed to obtain the mother's colostrum for medicinal purposes. In a few localities in England, the species has become a game animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The water deer is not yet known on "farms." However, it seems to be easily kept, has bred well in zoos, and has thrived in many British wildlife parks. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The assets of early maturity and high fecundity mean that the potential exists for rapid population expansion. Such an event occurred at Britain's Whipsnade Zoo. In 1929 and 1930, 32 deer were released into undeveloped pasture; by 1937, 120 fawns had been raised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because they are relatively small, and because in the wild state they aggregate only under exceptional conditions, water deer are unlikely to have any appreciable impact on vegetation in forests, farms, or gardens. Nonetheless, they can damage crops, and Chinese farmers, who consider them pests, often illegally kill them out of season.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals are swift and adept at escaping captivity. It is possible that because of territoriality only a single pair will live in a given area. Moreover, males are aggressive and must be kept apart.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They seem able to withstand chilly weather well, but a combination of wet and cold is harmful. Their heavy winter coat, essential to survival in the Far East, renders the animal susceptible to dehydration and heat exhaustion in comparatively mild climates, such as England's.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At birth, the tiny fawns are extremely vulnerable to a variety of predators, both birds and mammals. The species may need areas of dense cover or some shelter from wind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The water deer has been successfully kept in semicaptivity for many years; however, for it to reach a level of domestication suitable for use as microlivestock, research is needed in the following areas:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Reproduction;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Performance under a range of environments;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Grazing efficiency;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Basic physiology;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Captive breeding and domestication - measurements of growth rates, space requirements, and feed needs; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Modifying behavior to overcome territoriality - for instance, imprinting on humans, selection of docile specimens, hand rearing, and castration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water deer is not an endangered species; however, efforts should be made to preserve the populations in their native ranges and habitats. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">31 Duikers</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g035a.png"></center><br>
+ Red Duiker</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers (Cephalophus and Sylvicapra species) are small African antelopes. Although they are ruminants like cattle, sheep, and goats, some are hardly bigger than hares or rabbits. One, the blue duiker, is less than 40 cm high and usually weighs a mere 4-6 kg. It and some of the slightly larger duikers might be suitable for household husbandry because their meat is an extremely popular food throughout much of Africa. In West Africa, for example, it is one of the most common meats sold in both rural and urban markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This idea, however, is highly speculative because, despite their popularity, little is known about these tiny animals. Their husbandry has been attempted only a few times, but the results were encouraging, and rearing duikers deserves further investigation. They are already being raised in captivity in the United States,' Zimbabwe,2 Togo,3 and Gabon. Researchers in Nigeria have bred blue duikers to the fourth generation and found that, if the animals were first handled by people while young, they remained docile.4 Even blue duikers caught in the wild tame quickly if they are very young, but by the time they reach 3.5 months, they become barely tolerant of man's presence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If duiker husbandry can be developed, it might provide not only a more regular source of meat, but also a lessening of the hunting pressures, thereby giving the wild populations a better chance of survival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These antelopes are suitable for testing as microlivestock only in their native region, sub-Saharan Africa. Eventually, they might prove to have wider applicability. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Duiker species vary from about the size of a small dog to that of a small donkey. Most are similar in shape and are characterized by short front legs, arched back, and pointed hoofs. The tail is stubby, often with a terminal tuft. The coat varies from reddish brown to nearly black, although a few species are blue-grey and one is zebra striped.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Females are slightly larger than males, but the sexes look alike. In most species, both sexes bear small straight horns that project backward from the skull, frequently hidden in a long tuft of hair.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Duikers inhabit virtually all regions of Africa below the Sahara from Gambia in the west to Ethiopia in the east, and all countries as far south as South Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Duikers are so shy that they are rarely encountered by people. But almost anywhere in Africa (other than North Africa), the observant traveler may glimpse them ducking into forests or thickets. Although there are still countless numbers, people are eating so many that in some localized areas the populations are fast heading toward extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">All but one species are found in rainforests or dense woodlands. The grey duiker, however, is found in savannas. If the vegetation is juicy, only a few of the species need a separate water source, so they can thrive in very dry sites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The main foods are fruits and seeds supplemented by leaves and shoots. Fruits, which they eat to a much greater degree than other antelopes, are an important part of their diet. Some rare species (for example, the red-flanked duiker, C. rufilatus) can graze. Occasionally (especially in captivity), duikers are also omnivorous, eating fish, crabs, insects, snails, frogs, small animals, or carrion; they also readily accept chopped meat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers reach sexual maturity at 9-15 months; gestation lasts about 7-8 months. In some species, females conceive a few days after calving on a 3- to 5-day postpartum estrus. Apparently one calf per birth is normal. A newborn blue duiker weighs between 0.4 and 0.7 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before one year of age, young duikers leave their parents to find their own mates and territories. Life expectancy is more than 10 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In spite of habitat differences, most duikers behave alike. In the wild they are nervous, shy, and retiring. When alarmed, they plunge into the protection of dense vegetation - hence the origin of the name duiker, which means "diver." Nonetheless, their behavior allows them to be easily netted. An experienced hunter can imitate duiker sounds and call the male out of the bush. Also, a startled animal freezes, thereby facilitating its capture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moving easily through dense vegetation, the head carried low, these tiny animals use regular runs. Forest duiker species are largely diurnal, although a few, such as the bay duiker, are nocturnal. Bush duikers are mainly nocturnal, feeding from early evening until morning. Such nocturnal species shelter during the day in holes (presumably dug by other animals) or inside fallen trees; the diurnal ones lie directly on the ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blue duikers are the best-known species and are probably the most likely candidates for microlivestock (see page 332). They seem to be monogamous and apparently mate for life. Unlike most antelopes, their population densities can be high. The pairs reside in territories of 2-4 hectares, which both male and female stoutly defend against rivals. Other species appear to be polygamous and live in large territories (up to 80 hectares).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In captivity, the animals are generally calm. However, both males and females can be aggressive toward unfamiliar individuals of their own species. In an enclosure, one male can serve several females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Large glands, located beneath each eye, exude a scent that is rubbed onto fences, trees, and other objects as territorial marking. In another form of marking the horns are rubbed against tree trunks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, duiker meat is much sought in many African countries, and the animals are regularly hunted. The meat is lean with little or no intramuscular fat (marbling). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers also have promise as experimental animals. They are true ruminants, with four-part stomachs, and they produce cud. Some are only rabbit size, they need far less room or feed than sheep, and thus are potentially an efficient test animal for determining the nutritional value of forages. Blue duikers, for instance, have a digestion efficiency comparable to that of sheep, but, because of their small size, a test needs only four rabbit cages and 5-10 kg of feed. Sheep, by comparison, require much more spacious facilities and 150 kg of feed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Nigeria, blue duiker pelts are used in making karosses, a traditional dress. A single garment may contain up to 60 pelts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Almost nothing is known about rearing duikers, but they seem to tame easily and perhaps may be kept in backyards like goats. Indeed, they reportedly make good house pets when hand raised. They are attractive, and from the day of capture young ones can be handled and petted.5</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Nigerian researchers who bred blue duikers to the fourth generation bottle-fed young specimens five times a day. Older animals were given feeds that included banana, plantain, and papaya; leaves of hibiscus, cassava, and banana; and dried corn. Variety seemed to be important, and the researchers could not predict the quantity of particular foods the animals would choose on any given day. In addition to varied vegetables, a small dish of salt or a salt lick was sometimes required.6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers are unlikely to run away, except when startled. However, providing an enclosure is worthwhile. It enables them to establish a territory by marking poles, bushes, and fences. Although needing space in which to run, as little as 10 m&Yacute; is reportedly sufficient for 24 animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Satisfactory shelters include an open-ended oil drum laid on its side, a lean-to made of palm frond, or a small hut made of local matting. Apart from providing shade and protection, shelters should be built so that excited animals can run through them. When cornered, duikers tend to either flee for shelter or jump upwards; a run-through shelter can prevent a frightened one from accidentally leaping over the fence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Based on their own experiences, researchers at Pennsylvania State University in the United States report that blue duikers raised in captivity are easy to maintain, reproduce well, and are not fussy about environmental conditions. In fact, they say, blue duikers seem to enjoy living in cages.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In order to raise duikers successfully, post-pubertal males must be separated. A female should be bred with the same male throughout her productive life span.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE BLUE DUIKER</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In one sense, the blue duiker is the most important animal in Africa. It is the only one found throughout the continent south of the Sahara. It occurs at a greater range of altitudes than most - as low as sea level in many places to almost 5,000 m elevation in Kenya. It occurs in habitats from dense rainforests to dryland savannas. And, in sub-Saharan Africa as a whole, the blue duiker is eaten more than any other animal (although in West Africa it is generally called Maxwell's duiker).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This very small antelope, caught by snare or net, can be found in the meat markets of villages, towns, and cities in all countries from Senegal to Madagascar. It is a source of food for tens of millions. Bushmen, Pygmies, Dinkas, and Mandingos, thousands of miles apart; all share the same fondness for duiker meat and for duiker-skin clothes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, scientifically speaking, this is one of the world's least-known animals. And its numbers are diminishing rapidly. Areas that used to have plenty now have few or none. Overhunting and destruction of the rainforests are jointly contributing to their decline.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the losses, people are snaring as many as they can, and there is no sense of concern - not even among most conservationists. However, in many locations there is already evidence that the animals won't be around much longer. Unless something is done - and soon - people will lose their major source of animal protein. If that happens, it is likely that they will move on to larger animals, such as gorillas, which would be an even worse disaster.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The best long-term solution is to organize duiker husbandry. Learning to rear duikers would benefit people throughout Africa. The blue duiker is the most suitable species; it is the most common and the most important. Also, it inhabits the edges of the forest and could therefore become a suitable species for ranching without denuding the forest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blue duikers are easy to maintain in captivity. They tame readily and like to shelter and sleep In boxes or cages. They are good converters of vegetation and produce top-quality lean meat. In addition, they are neither affected by tsetse flies nor are very susceptible to diseases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The key now is to learn how to keep these very timid creatures under different conditions. We need to know their foods (especially foods that might be harvested from forests) and reproductive biology. We need to know the right numbers to house together. Most of all, we need projects aimed at rearing and breeding them in captivity under village conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vivian J. Wilson</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Many African countries already have a ready market for duiker meat. It is somewhat similar to goat meat, but most people agree that it is superior.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal can live on fibrous vegetation. Unlike conventional ruminant livestock, it is suitable for feeding an average family at one meal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ability to forage in undergrowth where other domestic livestock do not thrive makes duikers potential livestock for tropical forest and bushland regions. They can be raised for meat without cutting the trees or bushes to create pastures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Duikers are easy prey for predators: eagles, pythons, wildcats, and people, among others. Thus, they probably require more sophisticated management than common livestock such as goats. However, the quality of their meat could more than compensate for the extra effort.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some species are territorial, which means that they may do poorly in captivity, unless their social organization can be altered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under good conditions, the ideal slaughtering age reportedly occurs at 8-10 months, when the blue duiker can weigh 4 kg. Compared to rabbits and guinea pigs, production is relatively slow because of long gestation and lack of multiple births.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers are resistant to trypanosomiasis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One general problem is that duikers have short, sharp horns designed specifically for jabbing. This could be a potential danger, especially since the males of some species become aggressive when their females are receptive. However, the horns can easily be clipped and taped to limit the danger. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Because of the duikers' secluded lifestyle, much has still to be learned about their habits. Specific information on behavior and breeding is needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal scientists in Africa should gather small herds for comparative studies. This will provide insights into whether duiker temperaments facilitate or hinder their utilization. In addition, assessments of diet, growth rates, behavior in captivity, reproductive rate, adaptability, and future potential can be made. Management considerations include clipping horns, trimming hooves, and controlling lice and fleas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research of particular value would be chemical analysis of duiker milk and of other characteristic glandular secretions. The latter lend themselves especially to a study of animal communication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parming duikers might help rescue the wild populations by relieving hunting pressures. Programs in this area are recommended for locations where overhunting is occurring. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g036a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">32 Other Small Antelope</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g037a.png"></center><br>
+ Klipspringer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The least known and most obscure of all antelope are the delicate African creatures called dikdik, suni, royal antelope, pygmy antelope, and klipspringer. The smallest is a West African form of the royal antelope that stands a mere 25 cm high and weighs less than 2 kg. The four-horned antelope of South Asia is a similarly tough, tractable animal that is also the size of a small dog.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">None of these has previously been seriously considered for use as livestock, but they are possibly amenable to rearing in captivity and they provide some of the finest game meat in the world. Given New Zealand's experience with various deer species (see page 288) and Africa's experience with large antelopes, basic research to test out the possibility of organized dwarf-antelope production could prove to be rewarding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AREA OF POTENTIAL USE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The areas where these antelopes might be used are sub-Saharan Africa for the African species and South Asia for the four-horned antelope.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Of these animals, some, such as the pygmy antelopes, have a crouched appearance with an arched back and short neck; others have a more upright posture with a long neck and a raised head. In all species, the males are smaller than the females and bear tiny spikelike horns. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Collectively, these antelopes have native ranges covering huge areas of Africa and part of Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dikdik: Six species occur in two discontinuous distributions - one from Somalia and Ethiopia southward through Kenya and Tanzania, the other in Namibia and Angola. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sunis: Eastern Africa, from Kenya to South Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Royal antelope: West African forests. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pygmy antelope: Central Africa from southeastern Nigeria to Zaire. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Klipspringer: Ethiopia to the Cape of Good Hope. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Four-horned antelope: India. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Many forms are protected by local laws, but none of the species is on the international endangered-species list.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The animals occupy habitats from dense, moist forests to dry, rocky outcrops and even to deserts. Their ranges have almost certainly been affected by humans - sometimes for the better, since many prefer the secondary growth that invades disturbed areas, notably after overgrazing or slash-and-burn agriculture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although dikdik and klipspringer usually frequent dry areas with scattered brush, the other dwarf antelopes normally stay in dense vegetation. All seem to live in definite areas and do not migrate. For instance:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Dikdik live near streambanks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Sunis inhabit dry country with thick bush, but they can also be found in reed scrub along rivers and in forests up to 3,000 m elevation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Klipspringers live on stony mountain slopes, rocky outcrops' or the sides of steep gorges at altitudes from sea level to 4,000 m.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Four-horned antelopes live in undulating or hill country and shelter in tall grass and open jungle, a terrain more common to deer than to antelope. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Most of these antelope browse on shrubs. They are "concentrate selectors," taking easily digested vegetation such as buds, fruit, and succulent young leaves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Also, most obtain much of their water requirement from dew and the vegetation they consume. Klipspringers, for example, are able to live for months without drinking. Sunis and four-horned antelope, on the other hand, drink regularly and seldom live far from water sources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known of the reproduction and general performance of these animals. Females become sexually mature at about 6 months in the smaller species and 10 months in the larger. Males become sexually mature at about 14 months. The young are born throughout the year, but births peak with the vegetation flush following the first rains. Where there are two rainy seasons a year, two birth peaks occur. Usually a single calf is born. Dikdik is the only one whose reproduction has been studied in detail. Its pregnancy lasts 172 days, one young is born at a time, and the birth weight is 600-800 g.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Their longevity is unknown but is probably in the range of 10-12 years.l</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These tiny creatures have some of the habits of deer. They are shy and elusive and generally rely on concealment to escape detection. Their first response to a predator is to freeze, and then to flee like hares - dashing off in a series of erratic, zigzag leaps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They live alone, in pairs, or in small family groups, but sometimes congregate in larger groups in thorn thickets. The species that have been studied most (dikdik and klipspringer) are strongly pair bonded. (A male, a female, and one or two young is typical, and a klipspringer rarely moves more than 5 m from its mate.) However, the royal and pygmy antelopes and the suni are more solitary in their behavior. Four-horned antelope are usually seen alone or in pairs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals feed mostly in the early morning and late afternoon Some species deposit dung and urine on particular sites. And they repeatedly daub secretions from glands in front of the eyes onto plant stems, where a sticky mass accumulates. Glands near the hooves mark the ground along frequently traveled pathways. Males also mark females with the scent, thus reinforcing the bond. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The four-horned antelope has a whistling call, which helps keep the family group together. Males repeat it frequently in hot weather. Gestation is 8-8.5 months. If taken young, they reportedly tame easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Much more research needs to be done before attempts are made to convince anyone to domesticate these antelope. There are likely to be considerable difficulties. Guinea pigs, rabbits, and giant rats can successfully be kept in cages or small enclosures, but most antelope probably cannot. Larger enclosures will be needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The food habits and general behavior of these small animals must be studied closely. They are strictly monogamous, and it may be necessary to keep them in pairs. Reproduction, growth, and general performance must become understood under different environmental and nutritional conditions. Mixing species is another aspect to be examined - whether these antelope can be kept with other species in the same enclosure (typical of livestock farming in most poor nations) is not known.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To settle such questions, representative species of microantelope should be gathered for comparative assessment. Researchers should focus on the animals' social structure, on husbandry methods for maintaining them over generations, and on how best to breed them. If the findings are promising, then a campaign to domesticate these antelope could be mounted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Throughout most of their ranges these animals are highly sought "bushmeats." The meat is lean and of extremely high quality. In Zaire's Ituri Forest, for example, pygmies net and kill large numbers of pygmy antelope, hanging the carcasses on sticks by the roadside for sale.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of their small size, these species might make good laboratory animals for ruminant studies. The dikdik, for instance, becomes a fully functioning ruminant at a body weight of about only 1.5 kg.2 However, their digestive physiology is quite different from that of cattle, sheep, and goats, which makes them atypical ruminants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given organized production, it is likely that dwarf-antelope pelts could become commercially important. North Africa exports the hides of medium-size antelopes to Europe for use in fine sueded leathers. Hides of the small species would almost certainly be in demand as well if a steady supply could be obtained as a by-product of meat production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Microantelope provide some of the finest game meat. They are small and perhaps tractable. Most are already widely eaten and are being eliminated over broad areas of their range. Turning them into a sustainable, economic food source could provide motivation for their conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These antelope can digest, and are adapted to, the indigenous forage over vast areas of Africa and South Asia. They are native to tropical habitats, where cattle and other livestock often grow poorly. They also appear to be resistant to trypanosomiasis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Some African peoples (for example, the Kalahari Bushmen) have superstitions or social injunctions that prohibit the eating of some of these species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small antelope are probably not as efficient as larger ruminants in digesting fiber: the retention time in the rumen may be too short. On the other hand, quickly digestible cell walls of lush green plants can be used efficiently.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The territorial behavior of most of these species may limit their rearing in large numbers under captive conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted, preliminary research on dwarf antelope husbandry is required. Specifically, studies should be conducted to assess:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Growth rates, feed efficiency, and reproductive rate;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Carcass quality;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Economics and the likely cost of production per animal unit; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Studies of digestion.4 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The few statistics available today on the use of wildlife as food are probably much below actual consumption. Most food consumption surveys record food obtained by hunting or trapping under the indiscriminate heading of "Bushmeat" and neglect to include the many small animals that are normally collected by children. In Africa, an amazing variety of wildlife is eaten, including all wild ungulates, primates, all cats, and many species of birds and reptiles.</P>
+<P ALIGN="JUSTIFY">Food and Agriculture Organization Ceres magazine</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All the world's people must begin to overcome in themselves - and even more so in their children - senseless taboos about what is edible and what is not. Only then can we stop today's universal animal-protein wastage. How ironic it would be, in this scientific age, for mankind to starve largely because of a bunch of old wives' tales, irational beliefs, silly associations, and the lack of a sufficient spirit of culinary and gustatory adventure.</P>
+<P ALIGN="JUSTIFY">Calvin W. Schwabe Unmentionable Cuisine </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iguana is really good, a thousand times better than chicken.</P>
+<P ALIGN="JUSTIFY">Omero Asinto, waiter Pochote Bar and Restaurant</P>
+<P ALIGN="JUSTIFY">Barranca, Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part VI : Lizards</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Large lizards have been important foods since prehistoric times and are still commonly hunted in parts of Asia, Africa, and Latin America.1 Some (such as the monitor lizards seen in markets in Indochina) are carnivorous species that may be difficult to feed and raise economically. However, the iguanas of the Americas offer promise as microlivestock. They are herbivorous and feed primarily on leaves, flowers, and fruits, including many that are too high in the trees to be gathered by man or by other livestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iguana meat is popular throughout much of Latin America, where consumers willingly pay more for it than for fish, poultry, pork, or beef. To fill the demand, several iguana species are hunted by rifle, slingshot, trap, and noose; they are even run down by trained dogs. Villagers (often small children) catch them for food for the family; professional hunters snare and sell them to vendors. Iguanas are hauled around in gunny sacks and wicker baskets by car, boat, horseback, and people on foot. In parts of El Salvador they have been known to arrive at the market by the truckload.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As a result of this indiscriminate hunting, iguanas are now steadily becoming more scarce, and the destruction of their habitat makes the situation even worse. At present, many parts of Latin America's tropical forests are being cleared. The green iguana in particular depends on trees, and as forests disappear its populations are destroyed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, iguanas are forest-edge species: they will grow well on ranches and farms as long as patches of trees are left standing. This offers the hope that they can be raised as microlivestock. They reproduce so prolifically that, in principle, populations can build up exponentially. Mature females, for example, may produce 30 or more eggs a year for up to 10 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the past few years, a notable research program in Panama and Costa Rica (see page 351) has laid the practical foundation for iguana farming. It has artificially incubated and raised thousands of green iguana hatchlings. With less than half a square meter of living space per animal, the hatchlings have grown as fast or faster than their wild counterparts. Unlike their kin in the wild - which in their first year of life suffer 95 percent mortality from birds, snakes, and other predators the captive-raised iguanas show almost 100 percent survival. This research project demonstrates that ranching iguanas both for food or for repopulating depleted habitats is feasible. In addition, experimental projects for farming green iguanas have begun in Curacao and El Salvador.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As livestock, lizards have advantages. Being cold-blooded they do not carry human diseases (except for those such as salmonella that result from gross mismanagement). They can be kept in captivity in fairly high densities without diseases breaking out. Although often aggressive in the wild, they coexist in dense populations with few problems as long as they are well fed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is an important conservation component as well. Farming these lizards may help check and may even reverse the downward trends of their populations by allowing large numbers to be released back to the wild at a size that inhibits predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are three alternatives for utilizing iguanas:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- To manage wild stocks as game animals;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- To raise iguanas on farms, like chickens and pigs; or</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- To raise young iguanas in captivity and then release them into the wild where they can grow to full size and later be harvested on a sustainable basis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the green iguana has so far received the most attention, two other Latin American species are in farming trials. Black iguanas (garrobos) are being raised experimentally in El Salvador and Costa Rica. And the omnivorous tegu lizard, which produces a valuable leather, is beginning to be farmed in Argentina and is briefly described opposite. Both iguana species are described in the following chapters. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TEGU</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The tegus (Tupinambis rufescens and T. teguixin) are large lizards of South America. They are highly prized for their skins, which are made into leather for handbags and similar items. Tegus are heavily exploited; on average, Argentina exports over one million skins a year - about $15 million worth. The 50-year-old tegu industry is estimated to support as many as 30,000 people, including tannery employees and people in rural areas who hunt the lizards full- or part-time. Poor agricultural conditions make farming difficult in the Chaco, and sale of a single tegu skin is worth more than a day's wages for a farmband. Some families also eat the tegu meat and use the fat for medicinal purposes. In many areas, the populations have already been driven to the verge of extinction. Husbandry, therefore, could be beneficial. Traders are hoping that captive operations run by families can eventually replace hunting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although usually associated with the arid regions of northern Argentina and Paraguay, the tegu's range actually covers much of South America - as far north as Colombia, including Trinidad and the Amazon basin. One species (T. rufescens) normally occurs in a dryland habitat, such as Argentina's Chaco region. It can occur in great numbers in pastures, probably because of the insects associated with cattle. But it also occurs in areas that are unsuitable for cattle. Some places where tegus are common are so dry that they can carry only a single cow in 10 hectares. There, farmers might find it profitable to raise tegus. This would maintain the native biological diversity while perhaps reducing the soil degradation that cattle cause.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other species (T. tegubixin) occurs in wet forests, such as those found in Argentina's Formosa Province.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tegus are scientifically interesting. Little is known about their biology, and basic studies are needed. They are not much eaten, but in some areas the tail is considered a delicacy. Indeed, deteriorating economic conditions are already making them more important as a food resource. Convincing campesinos that they can increase their cash income and their meat production by rationally exploiting these large lizards should not be difficult.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sustainable exploitation could also benefit tegu conservation. Large populations still exist in some areas in Argentina and Paraguay, but, overall, the species are declining. A welldesigned management project could ensure the maintenance and reestablishment of large populations where numbers have drastically decreased. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">33 Green Iguana</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g038a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, the green iguana (Iguana iguana) is consumed throughout Central America. It is already subject to heavy commercialization and its populations are plummeting. This is not likely to change: as human population increases, so does demand for iguana meat and eggs as well as for live iguanas, thousands of which are kept as house pets. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its herbivorous diet, inoffensive nature, and high reproductive potential, this reptile is a prime species for intensive management. Alert, curious, and social, it is easily tamed from birth. Given minimal protection during the reproductive season, large populations can build up, and animals can be maintained in simple facilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, although iguanas can be maintained as microlivestock, they may require three years to reach market size. Raising them to maturity entirely under captive conditions is thus probably uneconomic at present, when specimens can still be inexpensively (albeit often illegally) harvested from the wild. However, it has been found that if released into the wild, most will remain in nearby trees, especially if people erect simple feeding stations and keep them stocked with table scraps or weedy vegetation. This makes for very low-cost production during the years of waiting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given such findings, iguana farming has a promising future. With research, growth rates can undoubtedly be increased and maintenance costs reduced. Also, iguanas are becoming more valuable each year. Even now, farming them could be economic in some areas where wild iguanas are scarce, especially if the young are released into forested sites when they have grown to a size where mortality is low.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although green iguanas will happily graze pastures, they need trees. Iguana farming, therefore, provides a way to keep tropical forests standing while still providing people with meat and income. By growing lizards, farmers don't have to fell the forests to create space for growing food crops or cattle. Iguana farming thus gives an economic incentive to preserve the beleaguered tracts of remaining trees. It may even render reforestation economically attractive. And it may promote the use of shelterbelts and contour strips of trees in cattle-ranching areas. Today's researchers estimate that 200-300 kg of meat can be produced per year per hectare from iguanas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The green iguana can grow to more than 2 m long, but more than half of that length is in its whiplike tail. Adults of breeding size generally weigh 2-4 kg. The scaly skin is green, yellowish, or golden brown with dark markings; color is a function of age and reproductive stage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This large lizard is indigenous to a vast region stretching from Mexico to northern Brazil and Peru, including a number of Caribbean islands. In Mexico, it occurs in tropical forests along both coasts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Green iguanas were formerly abundant throughout Central America, but no longer. In the mangrove forests along Mexico's Pacific coast, for instance, only 5 percent of the former population remains. In Guatemala's Pacific lowlands, mere remnants are left. In El Salvador's jungles, the animals have declined to 1 percent of their former density. And in both Panama and Costa Rica, the species is now officially classified as endangered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The green iguana usually lives near water in tropical lowland forests. It thrives only as long as some trees remain. The forests may be either humid or seasonally dry. The animal normally inhabits the treetops, feeding on tender shoots and fruits in the canopy; few other herbivores can convert such forest foliage into food for humans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Like cattle and other herbivorous mammals, iguanas have a specialized digestive system with an enlarged fermentation chamber in which bacteria break down plant cells. Vegetation is converted into meat about as effectively as in cattle, but not as quickly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After reaching sexual maturity, at 2 or 3 years of age, females lay one clutch of 10 85 eggs each year. (For most specimens the average is probably about 35.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p349a.png"></center><br>
+ Native habitat of the green iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The animals are generally slow moving and lethargic when cold, but during the heat of the day they become extremely alert and can run, swim, and climb with speed and agility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They have a complex social structure and a defined annual reproductive cycle. Hatchlings adapt easily to captivity both when artificially incubated and when captured in the wild. However, captured adults, used to living free, are hard to keep in small enclosures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Green iguanas are used mainly for food. The meat tastes somewhat like chicken and in Latin America is typically cooked in a spicy stew. The eggs are also consumed. Small and leathery shelled, they are considered special delicacies and are said to cure various ailments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a sizable demand for live iguanas in the international pet trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Exploitation has been mainly for the flesh; the skins are wasted in most cases. However, given organized production, green iguana skin could perhaps become a farm by-product. It sells in the international reptile-leather market under the trade name "chameleon lizard." The hide is typically up to 20 cm wide. Thin and relatively fragile, it is glued to a fabric or cowhide backing to prevent it from tearing. The prime uses are for ladies' accessories, belts, wallets, and shoes. It is inappropriate for uses that involve flexure because the scales overlap and repeated flexing causes them to separate. The skin then becomes rough to the touch and loses its glossy finish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IGUANA MAMA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The program that now offers hope for raising green iguanas as microlivestock is the brainchild of zoologist Dagmar Werner. She began in 1983 by collecting 700 iguana eggs and then learning what to do with them "on the job."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through a combination of luck and intuition, coupled with determination, she discovered appropriate conditions for incubating the eggs on the first try - no less surprising because her incubators (dirt-filled wooden boxes warmed with light bulbs) were in an apartment in a high-rise building in Panama City. Nonetheless, most of the eggs hatched and the several hundred squirming young lizards were quickly trucked to a forest park near the Panama Canal. Here, for five years, assisted by a steady stream of enthusiastic Panamanian biology students, Wemer experimented with cages, feeds, facilities, breeding genetic selection, and the myriad aspects of management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These dedicated researchers eventually devised what might be considered a production line, and they hatched and raised tens of thousands of green iguanas, reduced the animals' infant mortality rate, and created the basic underpinnings for economic production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1988, administration for the project was shifted to neighboring Costa Rica, where Werner established another research farm as well as a fund-raising foundation. From there, she hopes to catalyze all Central America to take up iguana production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Her immediate goal is, paradoxically, to preserve the lizards by putting an iguana in every pot. That will help reduce the indiscriminate hunting that is taking these animals toward extinction in the wild.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Her system is based on setting up feeding stations in the woods and releasing iguanas at seven months, an age at which they are virtually immune to predators. Iguanas need trees, and her ultimate goal is to help save the vanishing rainforests. With profitable iguana farming, she hopes to persuade farmers to save the trees as homes for iguanas, rather than clearing them for crops and cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Iguana management and an international marketing system will protect, rather than exterminate, the iguana," Werner says. "I don't think iguana farming will stop deforestation. But I do think it will contribute a great deal." </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The iguana farming project in Panama and Costa Rica (see sidebar) provides a model for what might be done elsewhere. In its first five years of operation, the project raised more than 10,000 green iguanas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To create the farms, enclosures are constructed with sheet-metal wails sunk 30 cm in the ground.' Inside, the animals sleep in shelters made of bamboo and vegetation. Each shelter has an adjustable entrance slit through which young lizards can slither, but predators, which usually are larger, cannot. Most are set on stilts and food is served in the shade underneath. With this system, from 20 to 60 young iguanas are kept in an area of 10 m&Yacute; (0.5-0.17 m&Yacute; of land area per individual). In another "high-intensity" design, 30 hatchlings are kept in cages I m&Yacute; in size (only 0.05 m&Yacute; per individual).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The iguana farms also include an artificial nest consisting of a "tunnel" leading to a sand-filled egg-laying chamber. (Both tunnel and chamber are made of concrete blocks or other predator-safe material.) Female iguanas (at least in captivity) prefer this to digging their own tunnels, and it is an important advance in iguana breeding because it produces a hatching success of close to 100 percent. Recent versions require no human intervention: the eggs incubate and hatch by themselves and the hatchlings climb out of the nest through a hollow bamboo "pipe" and fall into plastic bags, which can be easily emptied twice a day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The iguanas are fed mixtures of broken rice meal, meat meal, bone meal, fish meal, papayas, bananas, mangos, avocados, and a variety of leaves and flowers. Each day they receive fresh-cut leaves from plants such as beans, mustard, or hibiscus. Hatchlings are raised to an age of 6-10 months, when they are big enough to be released into forests, farmland with scattered trees, or into village backyards with almost no vulnerability to predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">With each female producing an average of 35 eggs annually, these animals have inherently high reproductive potential. And if the young are protected from predators during their first few months, populations can build up rapidly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iguanas adapt well to second-growth forest and to backyard conditions and can feed on the leaves of fruit trees or timber trees while the farmer can harvest the fruits or wood. Unless grossly overstocked, they are unlikely to affect the productivity of the trees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These lizards may take three years to reach marketable size,2 and the cost of raising them to usable size entirely in captivity is currently greater than their market value as food. Less-expensive methods of raising the animals must be found if large-scale commercial iguana farming is to become economically feasible. The main problem is the high cost of the enclosures, not the cost of food. The food costs no more than that for raising a chicken to marketable size, but iguanas do not grow as fast as chickens. For smallholders the only cost of raising them is labor, and that is often unimportant. Free-ranging herbivorous lizards can damage home gardens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">For conservation purposes, the main need is to educate people throughout Latin America to the iguana's plight. For example, in Central America people catch pregnant females and cut out the eggs for food. (There is a widespread misconception that the females survive this brutality.) This is devastating to the iguana populations, yet by installing artificial nests, farmers could let the females live and still harvest the eggs. Moreover, people could eat half the eggs and incubate the other half to repopulate the trees around their farms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is also important to develop an understanding of iguana reproduction in the wild. At present, the longevity, growth rate, and age of sexual maturity are not well known. Such information would provide baseline data for creating conservation measures to reverse the depletion of this natural resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Further husbandry research is needed. Costs must be reduced. The effectiveness of artificial nests must be tested in village practice. Survival rates of captive-raised young after release must be studied. And harvesting and recruitment schemes should be developed to secure optimum exploitation of the repopulated forests. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">34 Black Iguana</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g039a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The work on green iguana husbandry may apply also to the black iguanas' (Ctenosaura similis, C. acanthura, C. hemilopha, and C. pectinata). These are similar lizards that live in dry habitats throughout Central America </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Exploitation of wild black iguanas for food began in ancient times and has continued in most places over hundreds of years without much harm to the natural populations. Until the 1970s, Latin Americans could obtain the meat and eggs with little effort, and the animals sold cheaply in city markets. In recent years, however, the lizards have become scarce and prices have risen sharply. For instance, in 1976 the central market of San Salvador was selling large specimens for the equivalent of 80 cents, but by 1979 prices were generally from three to six times as much. Today, black iguana meat costs more than fish, poultry, pork, or beef.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eating small game animals is deeply rooted in the traditions of Central America and cannot readily be changed by legislation or education. Despite official edicts, campesinos on a subsistence diet will not willingly forego the little meat they get by capturing and eating lizards. Moreover, legislation is seldom effective because there are too few enforcement officials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As with the green iguana, it seems likely that when the factors causing hatchling mortality are reduced, a large harvestable annual surplus can be produced. Black iguanas efficiently convert vegetation into high-grade protein suitable for human consumption. Young ones, however, are insectivorous and carnivorous rather than purely herbivorous, and during their first weeks of life may require a more expensive diet (perhaps meat scraps) than green iguanas require. Moreover, most insectivorous lizards require moving prey. They may or may not accept meat scraps as food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Black iguanas are smaller and more stocky than green iguanas, but weigh up to 3 kg. Their tails are spiny and short. The scales on the tail are enlarged, grow in spirals, and are sharp-pointed. Other than that (apart from being generally greyish black in color), the two animals are similar in appearance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The different black iguana species range from northern Mexico along both coasts of Central America to Panama and Colombia's Caribbean islands. Most tolerate moderate human presence well, often thriving around town garbage dumps and cemeteries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As recently as 1981, black iguanas were shipped to markets by the truckload. Today, they are generally limited or even absent over much of their original range. Nevertheless, they are still the major game animals across extensive areas of Central America. Many of those taken are gravid females, which is disastrous for the populations. Excessive insecticide spraying is also thought to be reducing their populations in some areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Black iguanas thrive in dry, open woodland. They particularly like rocky hillsides, for they depend for shelter on crevices, rock piles, or soft soil in which they dig burrows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These omnivores feed on foliage, flowers, and fruits, but also on insects and small vertebrates. Adults spend some of their time climbing trees, but they are much less arboreal than green iguanas. Hatchlings are initially terrestrial but have a mostly arboreal stage in their early weeks of life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Females lay one clutch of 20-90 eggs each year. The eggs are much smaller than those of the green iguana and therefore are not as popular a food. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p357a.png"></center><br>
+ Distribution of the black iguana.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These lizards live in burrows or in holes in trees. A typical burrow has several entrances and is 1-2 m long. Several females may combine efforts to form a complex communal burrow with several individual nest chambers. They are such diligent diggers that many are caught while absorbed in the task of adding a new room.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In some places, even where they are not common, black iguanas are still intensively hunted. Because their meat is valuable, the reward justifies the considerable effort involved in finding and killing them. Hence, where populations are so depleted that organized hunting is unprofitable, the animals are still subjected to relentless destruction by individuals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Farming black iguanas is a novel idea. However, it is not a foolish one. In 1981 the Centro de Recursos Naturales (CENREN) in El </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Salvador started a black iguana farming project. Since then, its researchers have collected data on growth rates, feeding patterns, and the maintenance and reproduction of captive adults. The program offers some promise of maintaining breeding stock in large outdoor enclosures, of producing large numbers of hatchlings, and of restocking depleted areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">OTHER IGUANAS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Other iguanas that deserve consideration for husbandry include the rock (rhinoceros) iguana (Cyclura cornuta), a herbivorous lizard of the Antillean region. This has been raised in considerable numbers at the National Zoo of Santo Domingo, Dominican Republic. Captive-bred specimens have reproduced at the age of 32 months, average clutch size has been about 15, and the average incubation time has been 82 days (at 31&Yacute;C). The innate tameness of these island iguanas renders them better adapted for captive rearing than either the green or the black iguana, and their greater size is an advantage as well. On the other hand, the length of time required to reach maturity, and the relatively small egg clutch (about half that of the green iguana and one-third that of the black iguana) are definite disadvantages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A related species, Iguana delicatissima, also deserves research and conservation attention. It occurs in the Leeward Islands and Martinique, and (as its specific name implies) is even better eating than the green iguana.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Latins believe that various ailments are cured or benefited by the flesh of these lizards, so they willingly pay much more for their meat than they would for equivalent amounts of other meats. In most places where the two occur together, the black iguana is preferred over the green iguana.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Compared with green iguana, the black iguana reproduces readily in captivity and has an even higher reproductive potential (averaging 43 eggs per clutch). It has the additional advantage that it thrives in deforested and altered habitats. It can survive near human settlements despite the attacks of dogs and cats, and it attains dense populations in suburban lots or open spaces. (It survives even downtown in cities such as Managua, but not in dense populations because dogs, cats, and humans take so many.) Hence, even in towns and cities, there are habitats capable of supporting it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black iguanas will feed on weedy vegetation or garbage, and adults seem easier to maintain in captivity than their green iguana counterparts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The long delay (probably at least two years) before the animals reach marketable size might make it difficult for the grower to compete with common meats such as poultry or fish. Certain parasitic worms can make the flesh inedible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although smaller than green iguanas, black iguanas are much more aggressive and will defend what they perceive to be their territory. They can inflict a painful bite. They also tend to escape from captivity more readily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, these omnivores depend on animal matter during part of their life cycle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The biology of the black iguana deserves much more study.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Management techniques developed for the green iguana should be tested for their applicability for black iguana species. Harvesting and recruitment schemes must be developed to create sustainable populations in the wild. The specific needs for feeding the young also need to be addressed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I am convinced that in the Third World, it is only when poor people are assured of their livelihood that they will help us to safeguard their natural environments. So long as people remain hungry, it is very difficult to talk to them about conservation. As a result, I believe that development and conservation are inseparable. Only when conservation takes on a dimension of helping the poor, the downtrodden, the destitute, will it have an enduring impact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M.S. Swaminathan International Union for Conservation of Nature and Natural Resources</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I suspect that wildness is an inherited characteristic as was found for the turkey by Starker Leopold. So in attempting domestication one should expect to have difficulty until there are enough animals that you can select breeding stock for quietness and tractability.</P>
+<P ALIGN="JUSTIFY">Ian McTaggart Cowan Emeritus Professor of Zoology</P>
+<P ALIGN="JUSTIFY">University of British Columbia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle will never be extinct for the simple reason that man eats cattle. The best way to preserve wild species is by demonstrating that they, too, can be a valuable resource.</P>
+<P ALIGN="JUSTIFY">Ernie Matteram</P>
+<P ALIGN="JUSTIFY">New York Times Magazine</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wildlife utilization should be considered a legitimate form of land use, just as much as livestock husbandry. In fact, what has happened in the past is that Man has domesticated a limited number of animals, mainly in the temperate zones, while overlooking a considerable potential of other animals, which could be domesticated or used with equal validity.</P>
+<P ALIGN="JUSTIFY">Antoon De Vos </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part VII Others</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As noted in the preface, this report by no means exhausts all the microlivestock possibilities. Lack of space and time precludes discussion of creatures such as edible insects, snails, worms, frogs, turtles, and bats, which in some regions are highly regarded foods. Similarly, we have not included fish, shrimp, and other aquatic life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is not to say that these are less worthy of consideration. The decision to leave them out was arbitrary, but with several recent breakthroughs in tropical beekeeping it seems prudent to include bees. Accordingly, the final chapter of this book describes the smallest livestock of all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bees are one of the most promising microlivestock. They forage on flowers that are otherwise little utilized and produce honey, wax, and other products of high value. They are important as plant pollinators and can greatly increase the production of some crops. Bees can be kept virtually anywhere with little disruption of other activities, and they are easily available. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">35 Bees</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="g040a.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of all the livestock reviewed in this publication, bees are the smallest, the least demanding of space, probably the most familiar, and perhaps the most easily adapted to worldwide rural development efforts. For all that, however, they are an often forgotten component in agricultural programs. This is unfortunate because bees can be particularly valuable to tropical countries, providing pollination of crops, useful products, and a premium source of income.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Almost every village in every tropical country traditionally has had a beekeeper or two. Most use "seat-of-the-pants" methods and "rustic" hives, and this generally leads to low yields and inefficiencies. Today, numerous innovative methods and appropriate equipment are coming available. Many are still not widely known; however, their importance is slowly being recognized. Indeed, some developing countries are already turning bees into a valued natural resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For example, in less than 10 years Kenya has become self-sufficient in honey production and - despite increased local consumption - is now exporting. In seven years, Papua New Guinea has met its local honey requirements and now also exports its surplus. In only four years, Thailand increased yearly production from practically nothing to more than 1,000 tons. In Brazil, beekeeping is more widespread and production greater than before the outbreak of the African honey bee. These achievements can be largely attributed to the promotion of innovative equipment, modern beekeeping techniques, and extension support for small-scale beekeepers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">APPEARANCE AND SIZE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey bees are generally easily recognized and need no description here. The major species and subspecies are all roughly similar in appearance and size. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DISTRIBUTION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Among several hundred species of bees that store honey and pollen in harvestable amounts, only two "social" species, Apis mellifera and Apis cerana, produce multiple combs and can be kept in hives.' Given adequate forage and proper management, they can build up a honey surplus that can be harvested without harming their colonies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apis mellifera, the most widely distributed and exploited honey bee, comes from Europe and Africa. The subspecies from Europe (especially the Italian type, A. mellifera ligustica) is normally preferred because of its docility and high honey yields. It is now the predominant honey bee throughout the temperate zones of Europe, North America, Australasia, and China. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of the many subspecies in Africa, A. mellifera adansonii and A. mellifera scutellata have the widest native ranges. The latter was accidently released in Brazil in 1957. It has become naturalized and has dominated the European bees formerly kept by beekeepers. By l990, it had spread northwards to the southernmost areas of the United States and southwards deep into Argentina.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The docile Asian hive bee, A. cerana, is found in Asia from the Middle East to Japan and as far south as Indonesia. Although it produces much less honey per hive than A. mellifera, its overall production in many Southeast Asian countries may be greater.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STATUS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey bees do not face extinction. However, genetic diversity is disappearing due to loss of habitat, insecticides, displacement by massproduced, genetically uniform queens and exotic breeds, destructive harvesting, and the spread of diseases and pests such as protozoans, bacteria, insects, and mites.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HABITAT AND ENVIRONMENT</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey bees can exist in locations from deserts to rainforests and from near the Arctic to the tropics. They occur wherever there is nectar, pollen, tree resin (for nest building), shelter, and a little water. Heat, drought, and especially rain and humidity may curtail their activities, but a well-managed colony can survive periods of extreme adversity. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BIOLOGY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey bees live in rigidly hierarchical colonies. Normally there is a  single queen. After mating, she begins laying hundreds of eggs a day.  Those that are fertilized become sterile females, called workers; those  that remain unfertilized develop into males (drones), whose only role is  to fertilize future queens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After two or three years the queen, worn-out, starts laying fewer  and fewer eggs, and the colony may replace her. At that time a few  female larvae are raised on royal jelly, a nutritious, little-understood  secretion that causes them to develop into queens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Workers perform different tasks as they mature. Young ones tend  the queen, guard the hive, and raise the larvae. Older ones, comprising  the vast majority of a colony's population, gather pollen and nectar and  water. Pollen provides the protein and fats, and the nectar, converted  into honey in the bee's body, provides carbohydrates to feed the colony.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEHAVIOR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey bee activities are dictated by weather, availability of food,  genetics, and the overall strength of the colony. They are mediated by  chemical interactions between the queen and the workers that control  almost all behavior.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the Asian and European hive bees are relatively docile, most  of the African subspecies are unpredictable and may defend their  colonies in great numbers and with great persistence. The threat of  "killer bees" has been greatly exaggerated, however. Africans have  provided them nests and hives - and harvested their honey - for  thousands of years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Occasionally, large numbers of the bees in a colony split off from  their nest or hive. They usually cluster on a nearby tree or building,  calmly waiting for "scouts" to find a suitable new home. These  homeless swarms can be captured and will readily move into a hive  the simplest and cheapest way for beekeepers to acquire a colony.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">USES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Honey and beeswax are two of nature's best known and most  valuable products. Honey can be employed in hundreds of foods. It is  widely used in baking because, in addition to its flavor, it retains  moisture better than sugar or syrup, and the product keeps longer. Honey-based alcoholic beverages are popular in many parts of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beeswax also is used in many products, including candles, lubricants, polish, waterproofings, soaps, cosmetics, and electronics. Beeswax can be locally important for `'lost-wax" metal-casting and sculptures as well as batik-dyed clothing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both bee pollen and royal jelly are used in cosmetics and can be eaten. Bee venom is used medicinally, particularly in Europe and the developing world. Bee larvae are eaten raw or fried in many parts of Asia and Africa and are considered a delicacy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUSBANDRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Keeping bees means managing a colony so that it produces surplus honey or wax. Specifically this requires:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Providing a suitable hive;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Obtaining bees by collecting a swarm, transferring a wild colony, or purchasing a colony complete with an active queen;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Maintaining the colony free from natural enemies in an area that allows it to produce excess honey; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Harvesting the excess honey without weakening the colony or causing it to flee (abscond).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADVANTAGES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Few other livestock enterprises require less capital, less space, or less attention. Moreover, scarcely any other provides higher quality, more marketable products.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beekeeping is a respected and traditional activity in most areas of the world. It promotes self-reliance and requires little, if any, land or money. It is an easy-entry cottage industry that can be started with minimal equipment or training. It can be done by any member of a family as it requires no special strength or size. It is especially appropriate for increasing women's income in the many areas where men are away working.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beekeeping is suited to remote areas where many agricultural enterprises are at a competitive disadvantage because their products are bulky and far from the markets. Honey, wax, pollen, and other bee products can all be sold far from their point of origin, have high monetary value for their weight, and generally find a ready market. Local honeys often command premium prices (in part because many of them are considered medicinal). In addition, beekeeping encourages people to remain in rural areas rather than move to the city in search of an income.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pollination increases the productivity of many crops, and therefore a few hives can boost local food production. By rotating hives among farmers' fields and orchards, a beekeeper performs a valuable service.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beekeeping is also an important adjunct to reforestation and desert reclamation projects. It can provide income during the long wait for the trees to reach marketable size. Many forests are potential reservoirs of honey and other products. In some cases, the bees also enhance the fruitfulness and standing value of forests. They also increase pollination in tree-seed orchards and tree nurseries. And in newly established forests, bees improve reseeding potential. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">BETTER BEEHIVES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">So many hives have been developed in recent years that a design now exists for almost any level of expertise. One of the most important for Third World beekeeping is the top-bar hive. This crate-like box, derived from an ancient Greek design, incorporates modern beekeeping principles but adds the innovation of sloping sides. Beneath its lid are removable boards (top bars) from which the bees hang the combs (because the sides are sloping the bees do not attach the edges of the comb to them). By lifting a top bar, the comb can be inspected and handled - and the honey harvested - with little disturbance to the colony.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This simple hive can make beekeeping accessible to even the poorest people. It is easy to build and use, and can be locally constructed from scrap lumber. It is well suited for raising most types of honey bees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More elaborate and productive is the African long hive. In addition to having top bars, this square-sided box has removable frames within which the bees build their comb.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most elaborate is the Langstroth hive - the type most common in temperate zones.* These yield the most honey. They can be made only where there are facilities for precise carpentry, where durable, nonwarping parts are available, and where there are good extension services to aid and assist beekeepers. Although traditional Langstroth hives are demanding to build and maintain, simplified designs have been created for use in developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STINGLESS BEES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">By far the most common bees in the tropics, perhaps in the  world, are bees that cannot sting. Their stingers are so akophied  as to be essentially nonexistent (but some can deliver a pretty  fierce bite). They live in colonies and store their honey in wax  pots, some as large as egg cups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Stingless bees can be abundant. In a two-block area in  downtown Panama City, 150 nests have been counted. However,  many species depend on trees and their populations are  plummeting as more and more tropical forests are felled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like honey bees, stingless bees have been "domesticated." For  thousands of years in the tropical Americas, Indians have raised  them in special hives made out of logs, gourds, clay pots, and  other simple containers. Cortes reported in 1519 that Indians on  the island of Cozumel, the now popular tourist spot off the east  coast of Yucatan, practiced beekeeping. That was almost 300 years  before the European honeybee was introduced. A popular Mayan  drink was honey wine, and Mayan beekeepers carved stone  earplugs to keep these bees out of their ears.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Honey from stingless bees has less sugar than normal honey.  However, it is usually more tasty. It is used throughout the  tropics: the Americas, Central Africa, and Southeast Asia, for  instance. Normally, the nests are just robbed, which devastates  the bees because the queen cannot fly, and when she is disturbed  the colony dies. In some areas people open a little hole in the nest.  By putting in a plug, they can then harvest honey a couple of  times a year without destroying the colony.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, a few scientists are reconsidering stingless beekeeping.  In the state of Maranhao in Brazil, an area of crushing poverty,  biologist Warwick Kerr is harnessing stingless bees. He began  after learning that peasants were spending a third of their meager  incomes buying sugar. As part of his experiments, he keeps 60  hives stacked in his garage on the outskirts of the city of San Luis.  (A notable feature of these bees is that there is no prohibition  against keeping them in populated areas.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kerr has found that stingless bees can be made to produce well.  After years of experimenting with different-sized boxes, he can  now obtain more than 4.5 lifers of honey per hive per year. He  reports that the stingless bees are easy to maintain, and can be  raised by poor peoole without land or equipment.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIMITATIONS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Compared to raising four-footed livestock, beekeeping is inexpensive and fairly trouble free, but it is not without problems. Many things can go wrong, and include, for example:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Losses. Bees are susceptible to various predators, pests, and diseases. Although ways to avoid or control most afflictions are available, once a colony becomes infested it may have to be destroyed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Theft. Hives or combs - usually kept in secluded areas - that are full of honey are tempting targets and may be stolen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Swarming and absconding. Some or all of the bees may leave a hive and start a new nest, taking even the honey with them.2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Bad management. Beekeeping requires certain skills and knowledge, and sometimes frequent attention (such as when the colony is stressed, diseased, or swarming).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Lack of equipment. Beekeepers need hives, smokers (to quiet and repel the bees), hive tools, and - advisable but not absolutely necessary - gloves and a veil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Inadequate storage. Some areas lack the knowledge or the bottles in which to store liquid honey.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Pesticides and herbicides. Nectar- and pollen-collecting bees are vulnerable to insecticides, which farmers may apply (often inappropriately) at the time their crops are flowering. Herbicides can destroy important sources of bee forage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Neighborhood concerns. Bees can sting people and livestock. Although wild bees (and other insects) are the principal culprits, the beekeeper is often blamed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Stressful conditions. When rainfall, aridity, heat, or cold are excessive, bees often cannot produce surplus honey.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RESEARCH AND CONSERVATION NEEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Surprisingly, much remains to be learned about the natural science of bees. Although some of the research requires sophisticated equipment and facilities, much can (or must) be performed locally by beekeepers because many factors - such as colony behavior, foraging habits, and microclimatic adaptation - depend on the local conditions. This research may include the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Adaptation. The provision of locally adapted bee varieties is an important basis for developing advanced beekeeping. This can be done by selecting an appropriate local queen. Further, local breeding of queens and workers lessens the probability of importing exotic diseases and pests. Recent developments promise to move the mass production of queens and workers from the realm of high technology to common practice.4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Integration. Continued developments in beekeeping cannot succeed without research, promotion, education, training, and extension services. These are essential for integrating beekeeping with agriculture and reforestation efforts. Thus, descriptions of agronomic plants should always include pollination requirements as well as nectar and pollen potentials. Planting nectar- and pollen-producing firewood species would increase the number of bees, which would in turn help ensure forest survival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Bee plants. There is still much to be understood about the relative qualities that different plants bring to beekeeping. Recently, many valuable bee-forage plants have been identified.5 These deserve special consideration in any reforestation or beautification projects. Broad introduction of these plants may also encourage beekeeping that could produce high-value "specialty" honeys or ensure more continuous production of honey. There may also be a place for "bee farms," where every plant is bee forage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- New bee species. Nontraditional species of Apis as well as other members of the bee family (such as Anthophora, Bombus, Megachilae, Nomia, Osmia, Xylocopa, and especially Trigona and Melipona, which are stingless) should be studied to determine their role in pollination and - for some species - their further exploitation for honey. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendixes</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">A Selected Readings</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A small selection follows of books and articles that are not too  difficult to locate and that will help readers explore each topic further. Obscure documents are accompanied by an address from which readers can obtain a reprint or photocopy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GENERAL</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grzimek, B. 1975. Animal Life Encyclopedia. Vol. 1-13. Van Nostrand Reinhold  Company, New York.</P>
+<P ALIGN="JUSTIFY">Robbins, C.T. 1983. Wildlife Feeding and Nutrition. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICROBREEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mason, I.L. 1988. A World Dictionary of Livestock Breeds, Types and Varieties.  Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK. Microcattle</P>
+<P ALIGN="JUSTIFY">Barnard, J.P. and J.P. Venter. 1983. Indigenous and Exotic Beef Cattle in South West  Africa - A Progress Report. Available from Department of Agriculture and Nature  Conservation, PB 13184, Windhoek 9000, Namibia. (Sanga)</P>
+<P ALIGN="JUSTIFY">Cheng Peilieu. 1984. Livestock Breeds of China. FAO Animal Production and Health  Paper 46. Food and Agriculture Organization of the United Nations, Rome. 217 pp.</P>
+<P ALIGN="JUSTIFY">Cole, H.H. and W.N. Garrett, eds. 1974. Animal Agriculture. 2nd edition. W.H. Freeman  and Company, San Francisco, California, USA.</P>
+<P ALIGN="JUSTIFY">Epstein, H. and l.L. Mason. 1984. Cattle. Pages 6-27 in Evolution of Domesticated  Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Felius, M. 1985. Genus Bos: Cattle Breeds of the World. MSD-AGVET, Merck and Co.,  Rahway, New Jersey. 234 pp.</P>
+<P ALIGN="JUSTIFY">Gryseels, G. 1980. Improving Livestock and Farm Production in the Ethiopian Highlands:  Initial Results. ILCA study. International Livestock Centre for Africa, Addis Ababa,  Ethiopia.</P>
+<P ALIGN="JUSTIFY">ILCA. 1979. Trypanotolerant Livestock in West and Central Africa. Vol. 1, General Study.  International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">Joshi, N.R. and R.W. Phillips. 1953. Zebu Cattle of India and Pakistan. FAO Agricultural  Study No. 19. Food and Agriculture Organization of the United Nations, Rome. 297 pp.</P>
+<P ALIGN="JUSTIFY">Joshi, N.R., E.A. McLaughlin, and R.W. Phillips. 1957. Types and Breeds of African  Cattle. FAO Agricultural Study No. 37. Food and Agriculture Organization of the  United Nations, Rome. 297 pp. </P>
+<P ALIGN="JUSTIFY">Koger, M., T.J. Cunha, and A.C. Warnick, eds. 1973. Crossbreeding Beef Cattle. Series 2. University of Florida Press, Gainesville, Florida, USA.</P>
+<P ALIGN="JUSTIFY">Martinez Balboa, A. 1980. La Ganaderia en Baja California Sur. Vol. 1. Editorial J.B. La Paz, BCS: Mexico. 229 pp. (Criollo)</P>
+<P ALIGN="JUSTIFY">Mason, I.L. and J.P. Maule. The Indigenous Livestock of Eastern and Southern Africa. Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK.</P>
+<P ALIGN="JUSTIFY">Maule, J.P. 1989. The Cattle of the Tropics. Centre for Tropical Veterinary Medicine, Edinburgh University, Edinburgh, UK.</P>
+<P ALIGN="JUSTIFY">McDowell, L.R., ed. 1985. Nutrition of Grazing Ruminants in Warm Climates. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">McDowell, R.E. 1972. Improvement of Livestock Production in Warm Climates. W.H. Freeman and Company, San Francisco, California, USA.</P>
+<P ALIGN="JUSTIFY">McDowell, R.E. 1983. Strategy for Improving Beef and Dairy Cattle in the Tropics. Cornell International Agricultural mimeo. Cornell University, Ithaca, New York.</P>
+<P ALIGN="JUSTIFY">Miller, W.J. 1979. Dairy Cattle Feeding and Nutrition. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">National Research Council. 1980. Animal Science in China. CSCPRC Report No. 12. National Academy Press, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">National Research Council. 1981. Effect of Environment on Nutrient Requirements of Domestic Animals. National Academy Press, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Perry, T.W. 1980. Beef Cattle Feeding and Nutrition. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">Rollinson, D.H.L. 1984. Bali cattle. Pages 28-34 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Rouse, J.E. 1970. World Cattle. Vol. 1, Cattle of Europe, South America, Australia, and New Zealand. University of Oklahoma Press, Norman, Oklahoma, USA.</P>
+<P ALIGN="JUSTIFY">Rouse, J.E. 1970. World Cattle. Vol. 2, Cattle of Africa and Asia. University of Oklahoma Press, Norman, Oklahoma, USA.</P>
+<P ALIGN="JUSTIFY">Rouse, J.E. 1973. World Cattle. Vol.3, Cattle of North America. University of Oklahoma Press, Norman, Oklahoma, USA.</P>
+<P ALIGN="JUSTIFY">Rouse, J.E. 1977. The Criollo-Spanish Cattle in the Americas. University of Oklahoma Press, Norman, Oklahoma, USA. 303 pp.</P>
+<P ALIGN="JUSTIFY">Shirley, R.L. 1986. Nitrogen and Energy Nutrition of Ruminants. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">Thrower, W.R. 1954. The Dexter Cow. Revised third impression, 1980. The Spaulding Press, Bethel, Vermont, USA</P>
+<P ALIGN="JUSTIFY">Williamson, G. and W.J.A. Payne. 1965. An Introduction to Animal Husbandry in the Tropics. 2nd edition. Longman, London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microgoat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Acharya, R.M. 1982. Sheep and Goat Breeds of India. FAO Animal Production and Health Paper No. 30. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY">Ademosun, A.A. 1985. Capra spp.: The Emblem of Anarchy - The King-Pin of Man's Pastoral Life. Ife Lectures No. 3. University of Ife, Ile-Ife, Nigeria.</P>
+<P ALIGN="JUSTIFY">Cheng Peilieu. 1984. Livestock Breeds of China. FAO Animal Production and Health Paper 46. Food and Agriculture Organization of the United Nations, Rome. 217 pp.</P>
+<P ALIGN="JUSTIFY">Cole, H.H. and W.N. Garrett. 1980. Animal Agriculture. W.H. Freeman and Company, San Francisco, California, USA.</P>
+<P ALIGN="JUSTIFY">Copland, J.W. 1985. Goat Production and Research in the Tropics. Proceedings of a workshop held at the University of Queensland, Brisbane, Australia, February 6-8, 1984. Australian Centre for International Agricultural Research (ACIAR) Proceedings Series No. 7, 118 pp.</P>
+<P ALIGN="JUSTIFY">Devendra, C. and M. Burns. 1983. Goat Production in the Tropics. Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK. 83 pp.</P>
+<P ALIGN="JUSTIFY">Devendra, C. and G.L. McLeroy. 1983. Goat and Sheep Production in the Tropics. 2nd edition. Longman, London. 271 pp.</P>
+<P ALIGN="JUSTIFY">Devendra, C. and J.E. Owen. 1983. Quantitative and qualitative aspects of meat production from goats. World Animal Review (FAO) 47:19-29.</P>
+<P ALIGN="JUSTIFY">Fielding, D. Goat-keeping in Mauritius. Sonderdruck aus Zeitschrift fur Tierzuchtung und Zuchtungsbiologie. Vol 97(1)(1980):21-27.</P>
+<P ALIGN="JUSTIFY">Gall, C., ed. 1981. Goat Production. Academic Press, London. 619 pp.</P>
+<P ALIGN="JUSTIFY">Haenlein, G.F.W. and D.L. Ace. 1983. Goat Extension Handbook. University of Delaware Cooperative Extension Service, Newark, Delaware, USA.</P>
+<P ALIGN="JUSTIFY">Husnain, H.V. 1985. Sheep and Goats in Pakistan. FAO Animal Production and Health Paper No. 56. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY">International Development Research Centre (IDRC). Small Ruminant Production Systems in South and Southeast Asia, C. Devendra, ed. Proceedings of a workshop held in Bogor, Indonesia, October 6-10, 1986, cosponsored by the Small Ruminant Collaborative Research Support Program. Ottawa, Ontario, Canada.</P>
+<P ALIGN="JUSTIFY">ILCA. 1983. Peste des Petits Ruminants (PPR) in Sheep and Goats, D.H. Hill, ed. Proceedings of the International Workshop held at the International Institute of Tropical Agriculture (IITA), Ibadan, Nigeria, September 24-26, 1980. International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">ILCA. 1985. Sheep and Goats in Humid West Africa. Proceedings of the International Workshop held in Ibadan, Nigeria, January 23-26, 1984. International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">ILCA. 1979. Trypanotolerant Livestock in West and Central Africa. Vol. 1, General Study. International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">King, J.W.B., ed. 1988. Directory of Research on Sheep and Goats. Commonwealth Agricultural Bureaux International, Wallingford, Oxford, UK. 271 pp.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. 1981. Breeds. Pages 57-110 in Goat Production, C. Gall, ed. Academic Press, London.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. 1984. Goat. Pages 85-99 in Evolution of the Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. and J.P. Maule. 1960. The Indigenous Livestock of Eastern and Southern Africa. Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK.</P>
+<P ALIGN="JUSTIFY">National Research Council, 1980. Animal Science in China. CSCPRC Report No. 12. National Academy Press, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Phillips, R.W., R.G. Johnson, and R.T. Moyer. 1945. The Livestock of China. U.S. Department of State Publication No. 2249, Far Eastern Series 9. U.S. Department of State, Washington, D.C. 174 pp.</P>
+<P ALIGN="JUSTIFY">Proceedings of the 3rd International Conference on Goat Production and Disease. January 10-15, 1982, University of Arizona, Tucson, Arizona. Copies can be obtained from Kent Leach, Dairy Goat Journal, P.O. Box 1808, Scottsdale, Arizona 85252, USA. </P>
+<P ALIGN="JUSTIFY">Williamson, G. and W.J.A. Payne. 1965. An Introduction to Animal Husbandry in the Tropics. 2nd edition. Longman, London.</P>
+<P ALIGN="JUSTIFY">Wilson, R.T., T. Murayi, and A. Rocha. 1989. Indigenous African small ruminant strains with potentially high reproductive performance. Small Ruminant Research 2: 107-117.</P>
+<P ALIGN="JUSTIFY">Winrock International, 1984. Sheep and Goats in Developing Countries. Winrock International Technical Paper. The World Bank, Washington, D.C. </P>
+<P ALIGN="JUSTIFY">Acharya, R.M. 1982. Sheep and Goat Breeds of lndia. FAO Animal Production and Health Paper No. 30. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY">Carles, A.B. 1983. Sheep Production in the Tropics. Oxford University Press, London. 213 pp.</P>
+<P ALIGN="JUSTIFY">Cheng Peilieu. 1984. Livestock Breeds of China. FAO Animal Production and Health Paper 46. Food and Agriculture Organization of the United Nations, Rome. 217 pp. Cole, H.H. and W.N. Garrett. 1980. Animal Agriculture. W.H. Freeman and Company,</P>
+<P ALIGN="JUSTIFY">San Francisco, Calffornia, USA.</P>
+<P ALIGN="JUSTIFY">Devendra, C. and G.L. McLeroy. 1983. Goat and Sheep Production in the Tropics. </P>
+<P ALIGN="JUSTIFY">Longman, London. 271 pp.</P>
+<P ALIGN="JUSTIFY">Fitzhugh, H.A. and G.E. Bradford, eds. 1983. Hair Sheep of Western Africa and the Americas. Westview Press, Boulder, Colorado, USA. </P>
+<P ALIGN="JUSTIFY">Husnain, H.V. 1985. Sheep and Goats in Pakistan. FAO Animal Production and Health Paper No. 56. Food and Agriculture Organization of the United Nations, Rome. International Development Research Centre (IDRC). 1987. Small Ruminant Production Systems in South and Southeast Asia, C. Devendra, ed. Proceedings of a workshop held in Bogor, Indonesia, October 6-10, 1986, cosponsored by the Small Ruminant Collaborative Research Support Program. IDRC, Ottawa, Canada. </P>
+<P ALIGN="JUSTIFY">ILCA. 1983. Peste des Petits Ruminants (PPR) in Sheep and Goats, D.H. Hill, ed. Proceedings of the International Workshop held at the International Institute of Tropical Agriculture (IITA), Ibadan, Nigeria, September 24-26, 1980. International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">ILCA. 1985. Sheep and Goats in Humid West Africa. Proceedings of the International Workshop held in Ibadan, Nigeria, January 23-26, 1984. International Livestock Centre for Africa, Addis Ababa, Ethiopia.</P>
+<P ALIGN="JUSTIFY">ILCA. 1979. Trypanotolerant Livestock in West and Central Africa. Vol. 1, Ceneral </P>
+<P ALIGN="JUSTIFY">Study. International Livestock Centre for Africa, Addis Ababa, Ethiopia. </P>
+<P ALIGN="JUSTIFY">King, J.W.B., ed. 1988. Directory of Research on Sheep and Goats. Commonwealth</P>
+<P ALIGN="JUSTIFY">Agricultural Bureaux International, Wallingford, Oxford, UK. 271 pp.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. 1980. Prolific Tropical Sheep. FAO Animal Production and Health Paper No. 17. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY">Mason, l.L.1967. Sheep Breeds of the Mediterranean. Food andAgriculture Organization of the United Nations. Commonwealth Agricultural Bureaux, Farnham Royal, UK.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. and J.P. Maule. 1960. The Indigenous Livestock of Eastern and Southern Africa. Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK. Phillips, R.W., R.C. Johnson, and R.T. Moyer. 1945. The Livestock of China. U.S. Department of State Publication No. 2249, Far Eastern Series 9. U.S. Department of State, Washington, D.C. 174 pp.</P>
+<P ALIGN="JUSTIFY">Ponting, K. 1980. Sheep of the World. Blandford Press, Ltd., Poole, Dorset, UK.</P>
+<P ALIGN="JUSTIFY">Ryder, M.L. 1984. Sheep. Pages 63-85 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Ryder, M.L. 1983. Sheep and hIan. Monograph. Duckworth, London.</P>
+<P ALIGN="JUSTIFY">Terrill, C.E. 1970. Sheep breeds of the world. (505 breeds). USDA mimeo. U.S. Department of Agriculture, Washington, D.C. 163 pp.</P>
+<P ALIGN="JUSTIFY">Whitehurst, V.E., R.M. Crown, R.W. Phillips, and D.A. Spencer. 1947. Productivity of Columbia sheep in Florida and their use for crossing with native sheep. Florida Agricultural Experimental Station Bulletin 429. 34 pp.</P>
+<P ALIGN="JUSTIFY">Williamson, G. and W.J.A. Payne. 1965. An Introduotion to Animal Husbandry in the Tropics. 2nd edition. Longman, London. </P>
+<P ALIGN="JUSTIFY">Wilson, R.T., T. Murayi, and A. Rocha. 1989. Indigenous African small ruminant strains with potentially high reproductive performance. Small Ruminant Research 2: 107-117. Winrock International. 1984. Sheep and Goats in Developing Countries. Winrock International Technical Paper. The World Bank, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Yaltin, B.C. 1979. The Sheep Breeds of Afghanistan, lran, and Turkey. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Micropig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cheng Peilieu. 1984. Livestock Breeds of China. FAO Animal Production and Health Paper 46. Food and Agriculture Organization of the United Nations, Rome.</P>
+<P ALIGN="JUSTIFY">Clutton-Brock, J. 1981. Domesticated Animals from Early Times. British Museum (Natural History), London.</P>
+<P ALIGN="JUSTIFY">Cole, H.H. and W.N. Garrett. 1980. Animal Agriculture. W.H. Freeman and Company, San Francisco, Calffornia, USA.</P>
+<P ALIGN="JUSTIFY">Cunha, T.J. 1977. Swine Feeding and Nutrition. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">Epstein, H. and M. Bichard. 1984. Pigs. Pages 145-162 in Evolution of Domesticated </P>
+<P ALIGN="JUSTIFY">Animals, I.L. Mason, ed. Longman, London. </P>
+<P ALIGN="JUSTIFY">Krider, J.L., J.H. Conrad, and W.E. Carroll. 1982. Swine Production. McGraw-Hill Company, New York.</P>
+<P ALIGN="JUSTIFY">Mason, I.L. and J.P. Maule. 1960. The Indigenous Livestock of Eastern and Southern Africa. Commonwealth Agricultural Bureaux, Farnham Royal, Buckinghamshire, UK. National Research Council. 1983. Little-Known Asian Animals with a Promising Economic Future. National Academy Press, Washington, D.C. National Research Council. 1980. Animal Science in China. CSCPRC Report No. 12. National Academy Press, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Panepinto, L.M. 1986. Miniature swine in biomedical research. LabAnimal 15(8)(November/December 1986):21-27.</P>
+<P ALIGN="JUSTIFY">Panepinto, L.M., R.W. Phillips, L.R. Wheeler, and D.H. Will. 1978. The Yucatan miniature pig as a laboratory animal. Laboratory Animal Science 28(3):308-313.</P>
+<P ALIGN="JUSTIFY">Phillips, R.W. and T.Y. Hou. 1944. Chinese swine and their performance compared with modern and crosses between Chinese and modern breeds. Journal of Heredity 35:365-79.</P>
+<P ALIGN="JUSTIFY">Pond, W.G. and J.H. Maner. 1984. Swine Production and Nutrition. AVI Publishing Company, Westport, Connecticut, USA.</P>
+<P ALIGN="JUSTIFY">Williamson, G. and W.J.A. Payne. 1965. An Introduction to Animal Husbandry in the Tropics. 2nd edition. Longman, London. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">POULTRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The World's Poultry Science Journal is published 3 times a year by the World's Poultry Science Association, (c/o Institut f-r Kleintierzucht, Dornbergstrasse 25/27, Postfach 280, C-3100 Celle, Germany). It has also published a multilingual poultry dictionary.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Poultry, an international journal on poultry, is published by Misset International, a department of Uitgeversmaatschappij, C. Misset b.v., Doetinchem-The Netherlands. (Address: Misset International, P.O. Box 4, 7000 BA Doetinchem, Netherlands.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Poultry Science is published monthly by the Poultry Science Association, Inc., 309 West Clark Street, Champaign, Illinois 61820, USA. British Poultry Science, a quarterly, is available c/o Longman Group Ltd., Subscriptions (Journals) Department, Fourth Avenue, Harlow, Essex CM195AA, UK. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chicken</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Attfield, H.H.D. 1990. Raising Chickens and Ducks. Volunteers in Technical Assistance, Arlington, Virginia, USA.</P>
+<P ALIGN="JUSTIFY">Crawford, R.D. 1984. Domestic fowl. Pages 298-311 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Ensminger, M.E.1971. Poultry Science. Interstate Printers and Publishers, Inc., Danville, Illinois, USA.</P>
+<P ALIGN="JUSTIFY">Fielding, D. 1984. The silent scavengers. African Farming September/October 1984: 11-13.</P>
+<P ALIGN="JUSTIFY">Howman, K.C. 1980. Pheasants: Their Breeding and Management. K&amp;R Books, UK.</P>
+<P ALIGN="JUSTIFY">Huchzermeyer, F.W. 1973. Free ranging hybrid chickens under African tribal conditions. Rhodesian Agricultural Journal 70:73-75.</P>
+<P ALIGN="JUSTIFY">Latif, M.A. 1985. In-Depth Analysis on the Successful Experience of Poultry Production in Bangladesh. Report submitted to FAO-APHC Regional Animal Production and Health Office. FAD/UN, Bangkok, Thailand.</P>
+<P ALIGN="JUSTIFY">Matthewman, R.W. 1977. A Survey of Small Livestock Production at the Village Level in the Derived Savannah and Lowland Forest Zones of South West Nigeria. M.Sc. thesis, University of Reading, UK.</P>
+<P ALIGN="JUSTIFY">MTrat, P. 1986. Potential usefulness of the Na (Naked Neck) gene in poultry production. [Vorld's Poultry Science Journal 42:124-142.</P>
+<P ALIGN="JUSTIFY">Nesheim, M.C., R.E. Austic, and L.E. Card. 1979. Poultry Production. 12th edition. Lea and Febiger, Philadelphia.</P>
+<P ALIGN="JUSTIFY">Phillips, R.W., R.C. Johnson, and R.J. Moyer. 1945. The Livestock of China. U.S. Department of State Publication No. 2249, Far Eastern Series 9. U.S. Department of State, Washington, D.C. 174 pp.</P>
+<P ALIGN="JUSTIFY">Sainsbury, D. 1980. Poultry Health and Management. Granada, London.</P>
+<P ALIGN="JUSTIFY">Scott, M.L., M.C. Nesheim, and R.J. Young. 1982. Nutrition of the Chicken. M.L. Scott and Associates, Ithaca, New York.</P>
+<P ALIGN="JUSTIFY">Smith, A.J. nd. Supplementation for scavenging animals. Unpublished paper. Copies available from A.J. Smith, Centre for Tropical Veterinary Medicine, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK.</P>
+<P ALIGN="JUSTIFY">Somes, R. 1984. International Registry of Poultry Genetic Stocks. BuDetin 469, University of Connecticut Agricultural Experiment Station, Storrs, Connecticut, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Araucanian</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wilhelm, G.O.E. 1965-1966. La Gallina Araucana (Gallus inauris castelloi 1914). Universidad de Concepcion, Concepcion, Chile, Boletia de Concepcion 40:5-26.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duck</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A film, Duck Farmingan Indonesian Tradition, is available from the CSIRO Film and Video Unit, 314 Albert Street, East Melbourne 3002, Victoria, Australia. Soundtrack is in English or Indonesian and it is available in 16 mm or VHS/Beta Video.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Attfield, H.H.D. 1990. Raising Chickens and Ducks. Volunteers in Technical Assistance, Arlington, Virginia, USA. </P>
+<P ALIGN="JUSTIFY">Clayton, G.A. 1984. Common duck. Pages 334-339 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Farrell, D. and P. Stapleton, eds. 1986. Duck Production, Science and World Practice. Proceedingsofaduckproductionworkshop, November 18-22, 1985, Bogor, Indonesia. Central Research Institute for Animal Science. Available from Department of Biochemistry, Microbiology and Nutrition, University of New England, Armidale, NSW 2351, Australia. 430 pp.</P>
+<P ALIGN="JUSTIFY">Holderread, D. 1978. The Home Duck Flock. The Hen House, P.O. Box 492, Corvallis, Oregon 97330, USA.</P>
+<P ALIGN="JUSTIFY">Kingston, D.K., D. Kosasih, and I. Ardi. 1979. The Rearing of Alabio Dt~cklings -nd Management of the Laying Duck Flocks in the Swamps of South Kalimantan. Report No. 9. Centre for Animal Research and Development, Ciawi, Bogor, Indonesia.</P>
+<P ALIGN="JUSTIFY">Petheram, R.J. and A. Thahar. 1983. Duck egg production systems in West Java. Agricultural Systems 2:75-86.</P>
+<P ALIGN="JUSTIFY">Phillips, R.W., R.G. Johnson, and R.J. Moyer. 1945. The Livestock of China. U.S. Department of State Publication No. 2249, Far Eastern Series 9. U.S. Department of State, Washington, D.C. 174 pp.</P>
+<P ALIGN="JUSTIFY">Sainsbury, D. 1980. Poultry Health and Management. Granada, London.</P>
+<P ALIGN="JUSTIFY">Scott, M.L. and W.F. Dean. 1991. Nutrition and Management of Ducks. M.L. Scott of Ithaca, Publisher (P.O. Box 4464, Ithaca, New York 14852, USA)</P>
+<P ALIGN="JUSTIFY">Warren, A.G. 1972. Ducks and geese in the tropics. World Animal Review 3:35-36.</P>
+<P ALIGN="JUSTIFY">Yi Yung and Yu-Ping Zhon. 1980. The Pekin duck in China. World Animal Review 34:11-14.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crawford, R.D. 1984. Goose. Pages 345-349 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">FAO. 1983. The Goose and its Possible Use for Controlling Weeds. Small Animals for Small Farms. GAN-I. FAO Regional Office for Latin America and the Caribbean, Casilla 10095, Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">Holderread, D. 1981. The Book of Geesea Complete Guide to Raising the Home Flock. Hen House Publications, P.O. Box 492, Corvallis, Oregon 97339, USA.</P>
+<P ALIGN="JUSTIFY">Phillips, R.W., R.G. Johnson, and R.J. Moyer. 1945. The Livestock of China. U.S. Department of State Publication No. 2249, Far Eastern Series 9. U.S. Department of State, Washington, D.C. 174 pp.</P>
+<P ALIGN="JUSTIFY">Soames, B. 1980. Keeping Domestic Geese. Blandford, London. 159 pp.</P>
+<P ALIGN="JUSTIFY">USDA Extension Service. 1983. Raising Geese. Farmer's Bulletin No. 2251. U.S. Department of Agriculture, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Warren, A.G. 1972. Ducks and geese in the tropics. World Animal Review 3:35-36.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea Fowl</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many research papers have been published in French, Italian, Spanish, and Russian, but few in English.</P>
+<P ALIGN="JUSTIFY">Ayeni, J.S.O. 1983. Studies of Grey Breasted Helmet Guineafowl (Numida meleagris galeata Pallas) in Nigeria. World's Poultry Science Journal 39(2):143-151.</P>
+<P ALIGN="JUSTIFY">Belshaw, R.H.H. 1985. Guinea Fowl of the World. Nimrod Book Services, P.O. Box No. 1, Liss, Hampshire, UK. </P>
+<P ALIGN="JUSTIFY">Blum, J.C., J. Guillaume, and B. Leclercq. 1975. Studies of the energy and protein requirements of the growing guinea-fowl. Br-ish Poultry Science 16:157-168.</P>
+<P ALIGN="JUSTIFY">Cauchard, J.C. 1971. La Pintade. Henri Peladan, UzFs, France.</P>
+<P ALIGN="JUSTIFY">Chemillier, J. 1984. L'Alimentation de la Pintade. F. Hoffmann-La Roche and Cie, 52, Boulevard du Parc, 92521 Neuilly-sur-Seine, Cedex, France.</P>
+<P ALIGN="JUSTIFY">Commonwealth Agricultural Bureaux. 1968. Guinea Fowl Breeding and Managernent. Annotated Bibliography No. 85. The Commonwealth Bureau of Animal Breeding and Genetics, King's Buildings, Edinburgh 9, Scotland, UK.</P>
+<P ALIGN="JUSTIFY">Leclercq, B. 1982. Alimentation des Futurs Reproducteurs Pintades. Pages 101-111 in FertilitT et Alimentation des Volailles. I.N.R.A. Edit.7 Versailles, France.</P>
+<P ALIGN="JUSTIFY">Leclercq, R. and B. Sauveur. 1982. L'alimentation des reproducteurs pintades. Pages 113-135 in FertilitT et Alimentation des Volailles, I.N.R.A. edit., Versailles, France.</P>
+<P ALIGN="JUSTIFY">Lukefahr, S. Raising guinea fowl. Paper available from author, c/o International Small Livestock Research Center, Alabama Agricultural and Mechanical University. P.O. Box 264, Normal, Alabama 35762, USA.</P>
+<P ALIGN="JUSTIFY">Ministry of Agriculture, Fisheries and Food. 1985. Small-scale guinea-few! production. Pamphlet 934. Ministry of Agriculture, Fisheries and Food (Publications), Lion House, Alnwick, Northumberland NE66 2PF, UK.</P>
+<P ALIGN="JUSTIFY">Mongin, P. and M. Plouzeau. 1984. Guinea-fowl. Pages 322-324 in Evolution of Domesticated Animals, I . L. Mason, ed. Longman, London .</P>
+<P ALIGN="JUSTIFY">USDA. 1970. Raising Cuinea Fowl. Leaflet No. 519. U.S. Department of Agriculture, Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Clayton, G.A. 1984. Muscovy duck. Pages 340-344 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">De Corville, H. 1972. La Production du Canard de Barbarie. Copies available from Institut nacional de la recherce agronomique (INRA), Nouzilly, France.</P>
+<P ALIGN="JUSTIFY">Farrell, D. and P. Stapleton, eds. 1986. Duck Production, Science and World Practice. Proceedings of a duck production workshop, November 18-22, 1985, Bogor, Indonesia. Central Research Institute for Animal Science. Copies available from D. Farrell, University of New England, Armidale, NSW 2351, Australia.</P>
+<P ALIGN="JUSTIFY">Jeffreys, M.D.W. 1956. The Muscovy duck. The Nigerian Field21(3):108-11.</P>
+<P ALIGN="JUSTIFY">Kingston, D.J., D. Kosasih, and I. Ardi. 1978. The Use of the Muscovy Drrck for Hatching of Alabio Duck &Yacute;ggs in the Swamplands of Kalimantan. Centre Report No. 7. Centre for Animal Research and Development, Bogor, Indonesia.</P>
+<P ALIGN="JUSTIFY">Richet, M. 1985. La production du canard de Barbarie. Techniques Agricoles 3770.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abs, M., ed. 1983. Pltysiology and Behavior of the Pigeon. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">Hawes, R.O. 1984. Pigeons. Pages 351-356 in Evolution of Domesticated Anirnals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Hollander, W.F. and W.J. Miller. 1981. Hereditary variants of behavior and vision in the pigeon. Iowa State Journal of Research 55(4):323-331.</P>
+<P ALIGN="JUSTIFY">Levi, W.M. 1965. Encyclopedia of Pigeon Breeds. T.F.H. Publications, Jersey City, New Jersey, USA. </P>
+<P ALIGN="JUSTIFY">Levi, W.M. 1981. The Pigeon. 2nd edition revised. Levi Publishing, Sumter, South Carolina, USA.</P>
+<P ALIGN="JUSTIFY">Murton, R.K., R.P.J. Thearle, and J. Thompson. 1972. Ecological studies of the feral pigeon (Columba livia). 1. Population, breeding biology and methods of control. II. Flock behaviour and social organisation. Ecology 9:835-889.</P>
+<P ALIGN="JUSTIFY">University of Wisconsin. 1977. Pigeons. Bulletin 4-H 135. University of Wisconsin, Madison, Wisconsin, USA.</P>
+<P ALIGN="JUSTIFY">USDA. 1963. Squab Raising. Farmers Bulletin No. 684. U.S. Department of Agriculture, Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bourquin, O. 1980. Biology of rhe Quail (Coturnix coturnix Linnaeus 1758). Ph.D. thesis, University of Natal, Pietermaritzburg, Republic of South Africa.</P>
+<P ALIGN="JUSTIFY">Katoh, H. and N. Wakasugi. 1980. Studies on the blood groups in the Japanese quail: detection of three antigens and their inheritance. Developmental and Comparative Immunology 4:99-110.</P>
+<P ALIGN="JUSTIFY">Kawahara, T. 1973. Comparative study of quantitative traits between wild and domestic Japanese quail (Coturnix coturnix japonica). Experimental Animals 22(supplement): 138-50.</P>
+<P ALIGN="JUSTIFY">Marsh, A. Quail Manual. Marsh Farms, 7171 Patterson Drive, Garden Grove, Calffornia 92641, USA.</P>
+<P ALIGN="JUSTIFY">National Academy of Sciences. 1969. Coturnix (Coturnix coturnix japonica): Standards and Guidelines for the Breeding, Care, and Management of Laboratory' Animals. National Academy of Sciences, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Quail Production Technology. Leaflet No. 13/1982. Central Avian Research Institute, Izatnagar, India. </P>
+<P ALIGN="JUSTIFY">Somes, R.G., Jr. 1981. International Registry of Poultry Genetic Stocks. Storrs Agricultural Experiment Station, University of Connecticut, Storrs, Connecticut, USA.</P>
+<P ALIGN="JUSTIFY">Varghese, S.K. 1981. Coturnix Internationalat home and in the Caribbean. Poultry Science 60:1747.</P>
+<P ALIGN="JUSTIFY">Varghese, S.K. 1982. Coturnix production proves to be a profitable business. Poultry Science 61:1560.</P>
+<P ALIGN="JUSTIFY">Varghese, S.K. 1983. Processing and yield of coturnix (Japanese quail). Poultry Science 62:1517</P>
+<P ALIGN="JUSTIFY">Wakasugi, N. and K. Kondo. 1973. Breeding methods for maintenance of mutant genes and establishment of strains in the Japanese quail. Experimental Animals 22(Supplement): I 51 -9.</P>
+<P ALIGN="JUSTIFY">Woodard, A.E., A. Abplanalp, W.O. Wilson, and P. Vohra. 1973. Japanese Quail Husbandry in the Laboratory. Department of Avian Sciences, University of Calffornia, Davis, Calffornia 95616, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turkey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berg, R. and D. Halvorson. 1985. Turkey Management Guide. Minnesota Turkey Growers Association, 678 Transfer Road, St. Paul, Minnesota 55114, USA.</P>
+<P ALIGN="JUSTIFY">Crawford, R.D. 1984. Turkey. Pages 325-334 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London. </P>
+<P ALIGN="JUSTIFY">Ensminger, M.E. 1971. PoultryScience. InterstatePrintersandPublishers, Inc., Danville,</P>
+<P ALIGN="JUSTIFY">Illinois, USA. Sainsbury, D. 1980. Poultry Health and Management. Granada, London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RABBITS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Rabbit Research Center has been established at Oregon State University, Corvallis, Oregon 97331, USA. It publishes the Journal of Applied Rabbit Research, whose purpose is to convey current research information to those with an interest in commercial rabbit production. The journal describes research conducted at the center and reviews rabbit research results reported in the world's scientific literature.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Founded in 1976 in Paris, the World Rabbit Science Association (Typing House, Shurdington, Cheltenhem, Gloucestershire, GL51 SXF, UK) publishes a newsletter of coming events and chronicles the progress of rabbit farming in most countries of the world. Its aims are to facilitate the advancement of the various branches of the rabbit industry, disseminate knowledge, and study problems of production and marketing. Its members represent individuals and associations in 20 countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The American Rabbit Breeder's Association (1925 South Main Street, Bloomington, Illinois 61701, USA) has published a book, Guide to Producing Better Rabbits, which contains an abundance of information concerning management and diseases of the domestic rabbit. The organization also publishes a bimonthly magazine, Domestic Rabbit, that includes a great deal of updated information on rabbit raising.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asociacion Espanola de Cunicultura (Spanish Rabbit Science Association), Now, 23 08785 Ballbona d'Anoia, Barcelona, Spain, has a set of slides for training, covering breeds, handling, pathology, and commercialization.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Report of the Workshop on Rabbit Husbandry. Copies of this report are available free of charge from the International Foundation for Science, Sibyllegatan 47, S-114 42 Stockholm, Sweden. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A Working Rabbit Literature Resources File. This materia, is directed at scientists working on some aspect of domestic rabbit research. It lists methods of computer searching for scientific reports in the world's scientific literature, various types of computer literature searches, including commerciaHy available ones, and government services. It a,so includes a list of prepared abstracts. The address is D.D. Caveny and H. L. Enos, Colorado State University, Fort Collins, Colorado 80523, USA. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic Rabbit</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ministry of Livestock Development. 1981. Rabbit Production. Kenya Ministry of Livestock Development. Copies can be obtained from the Agricultural Information Centre, P.O. Box 14733, Nairobi, Kenya.</P>
+<P ALIGN="JUSTIFY">Attfield, H.H.D. 1977. Rabbit Raising. Volunteers in Technical Assistance, 1815 Lynn</P>
+<P ALIGN="JUSTIFY">Street, Arlington, Virginia 22209, USA. 90 pp.</P>
+<P ALIGN="JUSTIFY">Bennett, R. 1975. Raising Rabbits the Modern Way. Garden Way Publishing, Charlotte, Vermont 05445, USA.</P>
+<P ALIGN="JUSTIFY">Cheeke, P.R. 1987. Rabbit Feeding and Nutrition. Academic Press, Inc., New York.</P>
+<P ALIGN="JUSTIFY">Cheeke, P.R., N.M. Patton, S.D. Lukefahr, and J.I. McNitt. 1986. Rabbit Production. Sixth edition. The Interstate, Danville, Illinois, USA. </P>
+<P ALIGN="JUSTIFY">FAO. 1986. Cooking Rabbits. Food and Agriculture Organization of the United Nations,  Regional Office for Latin America and the Caribbean, Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">FAO. 1986. Self-Teaching Manual on Backyard Rabb- Rearing. Food and Agriculture  Organization of the United Nations, Regional Office for Latin America and the  Caribbean, Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">FAO. 1986. Backyard Rabbit Rearing: Some Basic Husbandry Practices. Small Animals  for Small Farms. GAN-16. Food and Agriculture Organization of the United Nations,  Regional Office for Latin America and the Caribbean, Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">Schlolaut, W., ed. 1985. A Compendium of Rabbit Production. Gesellschaft f-r  Technische Zusammenarbeit (GTZ) Publication No. 169. TZ-Verlagsgesellschaft mbH,  Postfach 36, D6101 Rossdorf, Germany.</P>
+<P ALIGN="JUSTIFY">Sicivaten, J. and D. Stahl. 1982. A Complete Handbook on Backyard and Commercial  Rabbit Production. CARE/Philippines.</P>
+<P ALIGN="JUSTIFY">Vogt, D.W. 1982. Raising Rabbits in Hawaii. Circular 499, Cooperative Extension  Service, College of Tropical Agriculture and Human Resources, University of Hawaii at  Manoa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RODENTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agouti</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A report summarizing preliminary results in a captive-breeding project in Mexico is available from A. D. Cuaron (see Research Contacts for address).</P>
+<P ALIGN="JUSTIFY">Deutsch, L.A., and G. Santos. 1984. Contribuitao pare o conhecimento do gOnero  Dasyproctareprodutao de cutiasentre cruzamente das espTcies Dasyprocta aguti,  Dasyprocta azarae e Dasyprocta fuliginosa. Congresso Brasileiro de Zoologia, II,  BelTm, 1984. Resumos. . .BelTm, SBZ/UFPalMPEC, p. 383-4/(Resumos 390). Copies  available from the authors, see Research Contacts.</P>
+<P ALIGN="JUSTIFY">Clark, M.M. and B.G. Galef, Jr. 1977. Patterns of agonistic interaction and space  utilization by agoutis, Dasyprocta punctata. Behavioral Biology 20:135-140.</P>
+<P ALIGN="JUSTIFY">Leopold, A.S. 1959. Pages 388-393 in Wildlife of Mexico. University of California Press,  Berkeley and Los Angeles.</P>
+<P ALIGN="JUSTIFY">Meritt, D.A., Jr. 1982. Bibliography of Dasyprocta (Rodentia). Brenesia 19/20:595-612.</P>
+<P ALIGN="JUSTIFY">Meritt, D.A., Jr. 1983. Preliminary observations on reproduction in the Central  American agouti, Dasyprocta punctata. Zoo Biology 2:127-131.</P>
+<P ALIGN="JUSTIFY">Morris, D. 1962. The behaviour of the green acouchi (Myoprocta pratti) with special  reference to scatter hoarding. Proceedings Zoological Society of London 139:701732.</P>
+<P ALIGN="JUSTIFY">Smith N. 1974. Agouti and babassu. Oryx 12(5):581-582.</P>
+<P ALIGN="JUSTIFY">Smythe, N. 1978. The Natural History of the Central American Agouti (Dasyprocta  punctata). Smithsonian Contributions to Zoology No. 257. Smithsonian Institution,  Washington, D.C., USA. 52 pp.</P>
+<P ALIGN="JUSTIFY">Tribe, C.J., R. Leher, M.C.O. Doglio, M.I.L. Rebello, D.S. Mello, and E.M.M. Guimar es.  1985. Uma tentative de esclarecimento do uso de espato e estrutura social na cutia  Dasyprocta a. aguti (Rodentia). Pages 296-7 in Congresso Brasileiro de Zoologia, 12,  Campinas, 1985. Resumos. . .Campinas, SBZ/UNICAMP, 1985. (Resumo 614.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capybara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A capybara bibliography, Bibliograf a sobre Chiguires (Hydrochoerus hydrochaeris), is available from E. Gonzalez-Jimenez and JosT Roberto de Alencar Moreira (see Research Contacts for addresses).</P>
+<P ALIGN="JUSTIFY">Aliaga Rodriguez, L. 1979. Produccion de Cuyes. Universidad Nacional del Centro del Peru, Puno.</P>
+<P ALIGN="JUSTIFY">Baldizan, A., R.M. Dixon, and R. Parra. 1983. Digestion in the capybara (Hydrochoerus hydrochaeris). South African Journal of Animal Science 13(1):27-28.</P>
+<P ALIGN="JUSTIFY">Gonzalez-Jimenez, E. 1977a. The capybara, an indigenous source of meat in tropical America. World Animal Review', 21:24-30.</P>
+<P ALIGN="JUSTIFY">Gonzalez-Jimenez, E. 1977b. Digestive physiology and feeding of capybaras. Pages 167177 in Handbook Series in Nutrition and Food. Section G, Diets, Culture Media and Food Supplements, M. Rechcigl, ed. CRC Press, Cleveland, Ohio, USA.</P>
+<P ALIGN="JUSTIFY">Gonzalez-Jimenez, E. and R. Parra. 1975. The capybara, a meat-producing animal for the flooded areas of the tropics. Pages 81-86 in Proceedings of the Third World Conference on Animal Production, R.L. Reid, ed. Sydney University Press.</P>
+<P ALIGN="JUSTIFY">Gonzalez-Jimenez, E. 1984. Capybara. Pages 258-259 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Macdonald, D.W., K. Krantz, and R.T. Aplin. 1984. Behavioural, anatomical and chemical aspects of scent marking amongst Capybaras (Hydrochoerus hydrochaeris) (Rodentia:Caviomorpha). Journal of Zoology (London) 202:341-360.</P>
+<P ALIGN="JUSTIFY">Mones, A. and J. Ojasti. 1986. Hydrochoerus hydrochaeris. Mammalian Species 264: 1-7.</P>
+<P ALIGN="JUSTIFY">Ojasti, J. 1968. Notes on the mating behavior of the capybara. Journal of Mammalogy 49:345-374.</P>
+<P ALIGN="JUSTIFY">Ojasti, J. 1973. Estudio Biologico del Chiguire o Capybara. Fondo Nacional de Investigaciones Agropecuaria, Caracas, Republica de Venezuela. 27 pp.</P>
+<P ALIGN="JUSTIFY">Zara, J.L. 1973. Breeding and husbandry of the capybara at Evansville Zoo. International Zoo Yearbook 13:137-139.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Christen, M.F. 1978. Evaluacion nutritive de cuatro dietas mono especificas en la alimentacion del coipo (Myocastor coypus Molina 1782). Tesis. Faculty of Veterinary Science, Universidad Austral de Chile, Valdivia, Chile.</P>
+<P ALIGN="JUSTIFY">Deems, E.F., Jr., and D. Pursley. 1978. North American Fur bearers. Maryland Wildlife Administration, Department of Natural Resources, Cheltenham, Maryland, USA. pp. 155.</P>
+<P ALIGN="JUSTIFY">CORFO. n.d. Pieles fieas. Especie coipos. Tomo 1, I! and III. Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">Murua, R., O. Newman, and J. Propelmann. 1981. Food habits of Myocastor coypus (Molina) in Chile. Pages 544-558 in Proceedings of rhe Worldwide Furbearer Conference, J.A. Chapman and D. Pursley, eds. Vol. 1. Worldwide Furbearer Conference, Inc., Frostburg, Maryland, USA.</P>
+<P ALIGN="JUSTIFY">Willner, G.R. 1982. Nutria; Myocastor coypu. Pages 1059-1076 in Wild Mammals of NorthAmerica, J.A. Chapman and G.A. Feldhamer, eds. The John Hopkins University Press, Baltimore, Maryland, USA. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giant Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ajayi, S.S. 1975. Domestication of the African Giant Rat. Department of Forest Resources, University of Ibadan, Ibadan, Nigeria.</P>
+<P ALIGN="JUSTIFY">Faturoti, E.O., O.O. Tewe, and S.S. Ajayi. 1982. Crude fibre tolerance by the African giant rat (Cricetomys gambianus Waterhouse) (Potential sources of protein, Nigeria.) African Journal of Ecology 20(4):289-292.</P>
+<P ALIGN="JUSTIFY">Faturoti, E.O., O.O. Tewe, and S.S. Ajayi. 1983. Effect of varying dietary oil levels on the performance of the African giant rat (Cricetomys gambianus Waterhouse). Nutrition Reports International 27(3):525-530.</P>
+<P ALIGN="JUSTIFY">Den Hartog, A.P. and A. de Vos. 1973. The use of rodents as food in tropical Africa. Nutrition Newsletter (FAO) 11 (2):1-14.</P>
+<P ALIGN="JUSTIFY">Halcrow, J.G. 1958. The giant rat of East Africa. Nature (London) 181:649-650.</P>
+<P ALIGN="JUSTIFY">Matthewman, R.W. 1977. A Survey of Small Livestock Production at the Village Level in the Derived Savanna and Lowland Forest Zones of South West Nigeria. Development Studies 24. Department of Agriculture and Horticulture, University of Reading, UK.</P>
+<P ALIGN="JUSTIFY">Tewe, O.O., S.S. Ajayi, and E.O. Faturoti. 1984. Giant rat and cane rat. Pages 291-293 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grasscutter</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asibey, E.O.A. 1979. Some problems encountered in the field study of the grasscutter (Thryonomys swinderianus) population in Ghana. Pages 214-7 in Wildlife Management in Savannah Woodland, S.S. Ajayi and L. B. Halstead, eds. Cambridge University Press, Cambridge, UK.</P>
+<P ALIGN="JUSTIFY">Baptist, R. and G.A. Mensah. 1986. The Cane-RatFarm animal of the future? [Vorld Animal Review 60:2-6.</P>
+<P ALIGN="JUSTIFY">Matthewman, R.W. 1977. A Survey of Small Livestock Production at the Village Level in the Derived Savanna and Lowland Forest Zones of South West Nigeria. Development Study 24. Department of Agriculture and Horticulture, University of Reading, UK.</P>
+<P ALIGN="JUSTIFY">Pich, S. and K.J. Peters. 1985. Possibilities of using the cane cutter for meat production in Africa. Unpublished manuscript. Copies available from K.J. Peters, Institute of Animal Breeding, Gottingen, Germany.</P>
+<P ALIGN="JUSTIFY">Tewe, O.O., S.S. Ajayi, and E.O. Faturoti. 1984. Giant rat and cane rat. Pages 291-293 in Evolution of Domesticated Animals, I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">"Let's Raise Guinea Pigs," a filmstrip on guinea pig farming, is available from World Neighbors International Headquarters, 5116 North Portland Avenue, Oklahoma City, Oklahoma73112, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aliaga Rodriguez, L. 1979. Produccion de Cuyes. Universidad Nacional del Centro del Peru, Huancayo, Peru. </P>
+<P ALIGN="JUSTIFY">Aliaga Rodriguez, L. 1983. improvement of Guinea Pig Breeding as a Means of Increasing the Productivity and Production of Meat for Consumption oy the Rural Population in Peru. National University of Central Peru, Huancayo, Peru.</P>
+<P ALIGN="JUSTIFY">Bolton, R. 1979. Guinea pigs, protein, and ritual. Ethnology 18(3):229-252.</P>
+<P ALIGN="JUSTIFY">Huss, D.L. 1982. Small animals for small farms in Latin America. World Animal Ret~iew (FAO) 43:24-29.</P>
+<P ALIGN="JUSTIFY">FAO. 1982. The Guinea Pig and a Hypothetical Development Centre. Small Animals for Small Farms. FAO, Regional Office for Latin America and the Caribbean, Santiago, Chile.</P>
+<P ALIGN="JUSTIFY">Loetz, E. and C. Novoa. 1983. Meat from the guinea pig. Span 26(2):84-86.</P>
+<P ALIGN="JUSTIFY">Muller-Haye, B. 1984. Guinea-pig or cuy. Pages 252-257 in Evolution of Domesticated Animals I.L. Mason, ed. Longman, London.</P>
+<P ALIGN="JUSTIFY">Stansfield, S.K., C.L. Scribner, R.M. Kaminski, T. Cairns, J.B. McCormick, and K.M. Johnson. 1982. Antibody to ebola virus in guinea pigs: Tandala, Zaire. The Journal of Infectious Diseases 146(4):483-486.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hutia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anderson, S., C.A. Woods, G.S. Morgan, and W.L.R. Oliver. 1983. Geocaprornys brownii. Mammalian Species 201:1-5.</P>
+<P ALIGN="JUSTIFY">Canet, R.S. and V. Berovides Alvares. 1984. Ecomorfologia y rendimiento de la jutia conga (Capromys pilorides Say). Poeyana 279:1-19.</P>
+<P ALIGN="JUSTIFY">Canet, R.S. and V. Berovides Alvares. 1984. Reproduccion y ecolog~a de la jutia conga (Capromys pilorides Say). Poeyana 220:1-20.</P>
+<P ALIGN="JUSTIFY">Howe, R., and G.C. Clough. 1971. The Bahamian hutia Geocapromys ingrahami in captivity. international Zoo Yearbook 11:89-93.</P>
+<P ALIGN="JUSTIFY">Johnson, M.L., R.H. Taylor, and N.W. Winnick. 1975. The breeding and exhibition of capromyd rodents at Tacoma Zoo. International Zoo Yearbook 15:53-56.</P>
+<P ALIGN="JUSTIFY">Oliver, W.L.R. 1977. The hutias (Capromyidae) of the West Indies. International Zoo Yearbook 17:14-20.</P>
+<P ALIGN="JUSTIFY">Oliver, W.L.R. 1985. The Jamaican hutia or Indian Coney (Geocapromys brownii). A model programme for captive breeding and reintroduction? Symposium of the Association of British Wild Animal Keepers, 10:35-52. (Copies available from author, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Rowlands, I.W., and B.J. Weir, eds. 1974. The Biology of Hystricomorph Rodents. Symposium of the Zoological Society of London, 34:1-482.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dubost, G. and H. Genest. 1974. Le comportement social d'une colonide mares, Dolichotis patagonum Z. dans le Parc de BranfTrT. Zeitschrift fin Tierpsychologie 35:225-302.</P>
+<P ALIGN="JUSTIFY">Taber, A.B. and D.W. Macdonald. 1984. Scent dispensing papillae and associated behaviour of the mare, Dolichotis patagonum (Rodentia: Caviomorpha). Journal of Zoology (London) 203:298-302. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paca</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A report summarizing progress in the captive-breeding project in Panama is available from Nicholas Smythe, Smithsonian Tropical Research Institute, Box 2071, Balboa, Panama. A report summarizing preliminary results in the captive-breeding project in Mexico is available from Alfredo D. Cuaron, (see Research Contacts).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collett, S.F. 1981. Population characteristics of Agouti paca (Rodentia) in Colombia. Michigan State University, Publications of the Museum, Biological Series 5(7): 485-602.</P>
+<P ALIGN="JUSTIFY">Matamoros, Y. 1982. Investigaciones preliminares sobre la reproduccion, comportamiento, alimentacion y manego del tepezcuinte (Cuniculus paca, Brisson) en cautiverio. Pages 961-992 in Zoologia Neotropical, Actas del VIII Congreso Latinoamericano de Zoologia, P.J. Salinas, ed. (Copies available from Y. Matamores, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcacha</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jackson, J.E. nd. Growth rates in vizcacha (Lagostomus maximus) in San Luis, Argentina. Instituto Nacional de Tecnologia Agropecuaria, San Luis, Argentina. (Copies available from author, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Llanos, A.C., and J.A. Crespo. 1952. Ecologia de la vizcacha (Lagostomus maximus maximus Blainv.) en el nordeste de la provincia de Entre Rios. Revista de Investigaciones Agricolas (Buenos Aires) 6:289-378.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Rodents</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butynski, T.M. 1973. Lffe history and economic value of the springhare (Pedetes capensis Forster) in Botswana. Botswana Notes Record 5:209-213.</P>
+<P ALIGN="JUSTIFY">Butynski, T.M. 1979. Reproductive ecology of the springhaas Pedetes capensis in Botswana. Journal of Zoology 189:221-232.</P>
+<P ALIGN="JUSTIFY">Butynski, T.M. 1984. Nocturnal ecology of the springhare, Pedetes capensis, in Botswana. African Journal of Ecology 22:7-22.</P>
+<P ALIGN="JUSTIFY">Butynski, T.M. and R. Mattingly. 1979. Burrow structure and fossorial ecology of the springhare Pedetes capensis in Botswana. African Journal of Ecology 17:205-215.</P>
+<P ALIGN="JUSTIFY">Kofron, C.P. 1987. Seasonal reproduction of the springhare, Pedetes capensis, in southeastern Zimbabwe. African Journal of Ecology 25.</P>
+<P ALIGN="JUSTIFY">Rosenthal, M.A., and D.A. Meritt. 1973. Hand-rearing springhaas at Lincoln Park Zoo. International Zoo Yearbook 18:206-208.</P>
+<P ALIGN="JUSTIFY">Smithers, R.H.N. 1983. The Mammals of the Southern African Subregion. University of Pretoria, Pretoria.</P>
+<P ALIGN="JUSTIFY">Velte, F.F. 1978. Hand-rearing springhaas Pedetes capensis at Rochester Zoo. International Zoo Yearbook 18:206-208. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DEER AND ANTELOPE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Deer Farmer, a quarterly magazine, is published by the New Zealand Deer Farmers' Association, P.O. Box 2678, Wellington, New Zealand.</P>
+<P ALIGN="JUSTIFY">Deer Farming is the quarterly magazine of the British Deer Farmers Association (22 Levat Road, Inverness IV2 3NS, Scotland, UK).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chaplin, R.E. 1977. Deer. Blandford Press, Poole, Dorset, UK.</P>
+<P ALIGN="JUSTIFY">Hoffman, R.R. 1985. Digestion and feeding in deer: their morphophysiological adaptation. In Proceedings International Conference on Deer Biology and Production, eds. P.F. Fennessy and K.R. Drew. Royal Society of New Zealand Bulletin 22, Wellington, New Zealand.</P>
+<P ALIGN="JUSTIFY">Fennessy, P.F. and K.R. Drew, eds. 1985. Biology of Deer Production. Proceedings of an international conference held February 13-18, 1983, Dunedin, New Zealand. Royal Society of New Zealand Bulletin 22, Wellington, New Zealand. Available from Royal Society of New Zealand, Private Bag, Wellington, New Zealand.</P>
+<P ALIGN="JUSTIFY">Wemmer C., ed. 1987. The Biology and Management of the Cervidae. Smithsonian Institution Press, Washington, D.C., USA.</P>
+<P ALIGN="JUSTIFY">Yerex, D. 1982. The Farming of Deer. Agricultural Publishing, Box 176, Carterton, New Zealand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kay, R.N.B. 1987. The comparative anatomy and physiology of digestion in tragulids and cervids and its relation to food intake. In The Biology and Management of the Cenvidae, C. Wemmer, ed. Smithsonian Institution Press, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">Dubost, G. 1975. Le comportement du chevrotain africain, Hyemoschus aquaticus Ogilby (Artiodactyla, Ruminantia). Zeitschrift fdr Tierpsychologie 37:403-501.</P>
+<P ALIGN="JUSTIFY">Dubost, G. 1978. Un apertu sur l'Tcologie du chevrotain africain, Hyemoschus aquaticus Ogilby, Artiodactyle Tragulide. Mammalia 42:1-62.</P>
+<P ALIGN="JUSTIFY">Ralls, K., C. Barasch, and K. Minkowski. 1975. Behaviour of captive mouse deer, Tragulus napu. Zeitschrift Tierpsychology 37:356-378.</P>
+<P ALIGN="JUSTIFY">Robin, K.P. 1979. Zum Verhalten des Kleinkantschils (Tragulus javanicus). Ph.D. dissertation, University of Zurich. (Copies available from K.P. Robin, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Vidyadaran, M.K., M. Hilmi, and R.A. Sirimane. 1982. The gross morphology of the stomach of the Malaysian lesser mousedeer (Tragrrlus javanicus). Pertanika 5(1): 34-38.</P>
+<P ALIGN="JUSTIFY">Vidyadran, M.K., S. Vellayan, and R. Karuppiah. 1983. Muscle weight distribution of the Malaysian lesser mousedeer (Tragulus javanicus). Pertanika 6(2):63-69. </P>
+<P ALIGN="JUSTIFY">Wharton, D.C. 1987. Captive Management of Tragulids at New York Zoological Park. In Biology and Management of the Cervidae, C. Wemmer, ed. Smithsonian Institution Press, Washington, D.C., USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muntjac</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anderson, J. 1981. Studies on digestion in Muntiacus reeves). M.Phil. thesis. Cambridge University. </P>
+<P ALIGN="JUSTIFY">Barrette, C. 1977. The social behavior of captive muntjac Muntiacus reeves) (Ogilby  1839). Zeitschrift f-r Tierpsychologie 43: 188-213.</P>
+<P ALIGN="JUSTIFY">Chaplin, R.E. 1977. Deer. Blandford Press, Poole, Dorset, England</P>
+<P ALIGN="JUSTIFY">Chapman, D.I., N.G. Chapman, J.G. Mathews, and D.H. Wurster-Hill. 1983. Chromosome  studies of feral muntjac (Muntiacus sp.) in England. Journal of Zoology, London  201:557-559.</P>
+<P ALIGN="JUSTIFY">Dansie, O. 1970. Muntjac. British Deer Society, Welwyn Garden City, England. 22 pp.</P>
+<P ALIGN="JUSTIFY">Dubost, G. 1970. L'organisation spatiale et sociale de Muntiacus reeves) Ogilby 1839 en  semi-liberte. Mammalia 34:331-355.</P>
+<P ALIGN="JUSTIFY">Dubost, G. 1971. Observations Tthologiques sur le muntjac (Muntiacus muntjak  Zimmermann 1780 et Muntiacus reeves) Ogilby 1839) en captivitT et semi-libertT.  Zeitschrift fdr Tierpsychologie 28:387-427.</P>
+<P ALIGN="JUSTIFY">Jackson, J.E., D.I. Chapman, and O. Dansie. 1977. A note on the food of muntjac deer  (Muntiacus reeves)). Journal of Zoology (London) 183:546-548.</P>
+<P ALIGN="JUSTIFY">Lu Ho-gee and Sheng He-lin. 1984. Status of the black muntjac Muntiacus crinifrons, in  eastern China. Mammal Review 14(1):29-36.</P>
+<P ALIGN="JUSTIFY">Oli, Madan K. 1986. Studies on stereotyped behavior of barking deer (Muntiacus  muntjak). M.S. dissertation, Institute of Science and Technology, Tribhauvan  University, Kathmandu, Nepal. 84 pp.</P>
+<P ALIGN="JUSTIFY">Shi Liming, Ye Yingying, and Duan Xinsheng. 1980. Comparative cytogenetic studies on  the red muntjac, Chinese muntjac, and their Fl hybrids. Cytogenetics and Cell Genetics  26:22-7.</P>
+<P ALIGN="JUSTIFY">Yonzon, Pralad B. 1978. Ecological studies on Muntaicus muntjack. Journal of Natural  History Museum (Nepal) 2(2):91-100.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Musk Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anonymous. 1974. Feeding musk deer in captivity and collecting musk from the live  animal. Dongwuxue Zhazi, China 2:11-14.</P>
+<P ALIGN="JUSTIFY">Anonymous. 1975. Preliminary experience in raising the survival rate of musk deer.  Dongwuxue Zhazi, China 1 :17-19.</P>
+<P ALIGN="JUSTIFY">Bannikov, A.G., S.K. Ustinov, and P.N. Lobanov. 1980. The musk deer Moschus  moschiferus in the USSR. International Union for Conservation of Nature and Natural  Resources (IUCN), Gland, Switzerland.</P>
+<P ALIGN="JUSTIFY">Bi, S.Z., Y.H. Yan, Z.X. Qing, P.T. Sheng, Y.M. Wu, C.F. Chen, G.K. Yang, T.B. Yin,  and Y.J. Lu. 1980. Dissection and analysis of the musk gland of M. moschiferus and a  preliminary investigation into its histology. The Protection and Use of Wild Animals  (China) 1: 14-19.</P>
+<P ALIGN="JUSTIFY">Green, M.J.B. 1978. Himalayan musk deer (Moschus moschiferus moschiferus). Pages  56-64 in Threatened Deer. International Union for Conservation of Nature and Natural  Resources (IUCN), Morges, Switzerland.</P>
+<P ALIGN="JUSTIFY">Green, M.J.B. 1985. The musk trade, with particular reference to its impact on the  Himalayan population of Moschus chrysogaster. In Conservation in Developir~g  Countries. Bombay Natural History Society, Bombay.</P>
+<P ALIGN="JUSTIFY">Green, M.J.B. 1985. Aspects of the Ecology of the Himalayan Musk Deer. Ph.D.  dissertation, University of Cambridge, U.K. 280 pp.</P>
+<P ALIGN="JUSTIFY">Groves, C.P. 1978. The taxonomy of Moschus, with particular reference to the Indian  Region. Journal of the Bombay Natural History Society 72:662-676.</P>
+<P ALIGN="JUSTIFY">Holloway, C.W. 1973. Threatened deer of the world: conservation status. Biological  Conservation 5(4).  </P>
+<P ALIGN="JUSTIFY">IUCN. 1974. Red Data Book: Mammalia. International Union for Conservation of Nature and Natural Resources (IUCN), Morges.</P>
+<P ALIGN="JUSTIFY">Jamwal, P.S. 1972. Collection of deer musk in Nepal. Journal of Bombay Natural History Society 69(3):647-649.</P>
+<P ALIGN="JUSTIFY">Seth, S.D., A. Muktiopadtiyay, K. Raghunatham, and R.B. Arora. 1975. Pharmodymamics of Musk. Central Council for Research on Indian Medicine and Homoeopathy, New Delhi, India.</P>
+<P ALIGN="JUSTIFY">Zhang B. 1983. Musk-deer. Their capture, domestication and care according to Chinese experience and methods. Unasylva 35(139):16-24.</P>
+<P ALIGN="JUSTIFY">Zhang, B.L., F.M. Dang, and B.S. Li. 1979. The Farming of Musk Deer. Agricultural Publishing Company, Peking.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chaplin, R.E. 1977. Deer. Blandford Press, Poole, Dorset, England.</P>
+<P ALIGN="JUSTIFY">Cooke, A. and L. Farrell. 1983. Chinese water deer (Hydropotes inermis). British Deer Society Publication No. 2. Elvy and Gibbs, Canterbury, UK.</P>
+<P ALIGN="JUSTIFY">Feer, F. 1982. Quelques observations Tthologiques sur l'Hydropote de chine, Hydropotes inennis (Swinhoe, 1870) en captivitT. Zeitschrift fitr Saeugetierkunde 47: 175-185.</P>
+<P ALIGN="JUSTIFY">Sheng Helin and L. Housl. 1984. A preliminary study on the river deer (Hydropotes inermis) population of Shoushau Island (China) and adjacent islets. Acta Theriologica Sinica 4:161-166.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dittrich, L. 1972. Beobachtungen bei der Haltung von Cephalophus-Arten sowie zur Fortpflanzung und Jugendentwicklung von C. dorsalis und C. rufilatus in gefangenschaft. Zoologische Garten Lpz (N.F.) 42:1-16.</P>
+<P ALIGN="JUSTIFY">Dubost, G. 1980. L'Tcologie et la vie sociale du cTphalophe bleu (Cephalophus monticola Thunberg), petit ruminant forestier africain. Zeitschrift fur Tierpsychologie 54: 205-266.</P>
+<P ALIGN="JUSTIFY">Dunbar, R.l.M. and E.P. Dunbar. 1979. Observations on the social organisation of common duiker in Ethiopia. African Journal of Ecology 17:249-252.</P>
+<P ALIGN="JUSTIFY">Dunbar, R.I.M. and E.P. Dunbar. 1980. Animal Behaviour 28:219.</P>
+<P ALIGN="JUSTIFY">Ketelhodt, H.F. Von. 1977. The lambing interval of the blue duiker, Cephalophus monticola Gray in captivity, with observations on its breeding and care. South African Journal of Wildlife Research 7:41-43.</P>
+<P ALIGN="JUSTIFY">Ralls, K. 1975. Agonistic behavior in Maxwell's duiker, Cephalophus max~elli. Marnrnalia 39:241-249.</P>
+<P ALIGN="JUSTIFY">Schweers, S. 1984. The reproductive biology of the banded duiker Cephalophus zebra in comparison with other species of Cephalophus. Zeitschrift fur Saeugetierkunde 49(1):21-36.</P>
+<P ALIGN="JUSTIFY">Whittle, C. and P. Whittle. 1977. Domestication and breeding of Maxwell's duiker. The Nigerian Field 42(4):13-21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antelope</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Spinage, C.A. 1986. The Natural History of Antelopes. Christopher Helm, UK. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Klipspringer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dunbar, R. and P. Dunbar. 1974. Zeitschrift fur Tierpsychologie 35:481-493.</P>
+<P ALIGN="JUSTIFY">Dunbar, R.I.M. 1979. Energetics, thermoregulation and the behavioural ecology of klipspringer. African Journal of Ecology 17:217-230.</P>
+<P ALIGN="JUSTIFY">Dunbar, R. I . M . and E. P. Dunbar. 1 980 . The pairbond in klipspringer. A nimal Beha vior 28:219-229.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dikdik</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hendricks, H. 1975. Zeitschrift fdr Tierpsychologie 38:55-69.</P>
+<P ALIGN="JUSTIFY">Feer, F. 1979. Observations Tcologiques sur le neotrague de Bates (Neltragus bates) de Winton, 1903, Artiodactyle, ruminant, Bovide) du nord-est du gabon. Terre et vie 33: 159-239.</P>
+<P ALIGN="JUSTIFY">Hoppe, P.P. 1975. Acta Physiol. Scand. 95, 9A.</P>
+<P ALIGN="JUSTIFY">Hoppe, P. P. 1 976 . Tritiated water turnover in Kirk' s dikdik, Madoqua (Rhynchotragus) kirk), Gunther, 1880. Zeischrift far Sadgetierkunde, Mitt. 24:318-319.</P>
+<P ALIGN="JUSTIFY">Hoppe, P.P. 1977. How to survive heat and aridity: ecophysiology of the dikdik antelope. Veterinary Medical Review 1:77-86.</P>
+<P ALIGN="JUSTIFY">Hoppe, P.P. 1977. Comparison of voluntary food and water intake and digestion in Kirk's dik-dik and suni. East African Wildlife Journal 15:41-48.</P>
+<P ALIGN="JUSTIFY">Hoppe, P.P. 1977. Rumen fermentation and body weight in African ruminants. Pages 141-150 in Proceedings 13th International Congress of Game Biologists, T.J. Peterle, ed. Wildlife Society, Washington, D.C., USA.</P>
+<P ALIGN="JUSTIFY">Hoppe, P. 1984. Strategies of digestion in African herbivores. Pages 222-243 in Herbivore Nutrition in the Tropics and Subtropics. F.M.C. Gilchrist and R.I. Machie, eds. The Science Press, South Africa.</P>
+<P ALIGN="JUSTIFY">Hungate, R.E., G.D. Phillips, A. McGregor, D.P. Hungate, and H.K. Buechner. 1959. Microbial fermentation in certain mammals. Science 130:1192-1194.</P>
+<P ALIGN="JUSTIFY">Morat, P. and M. Nording. 1978. Maximum food intake and passage of markers in the alimentary tract of the lesser mouse-deer. Malaysian Applied Biology 7:11-17.</P>
+<P ALIGN="JUSTIFY">Yalden, D.W., M.J. Largen, and D. Kock. 1984. Catalogue of the mammals of Ethiopia. 5. Artiodactyla. Monitore Zoologico Italiano Supplemento 19:67-221.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIZARDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Green Iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burghardt, G.M. and A.S. Rand, eds. 1982. Iguanas of the World: Behavior, Ecology, and Conservation. Noyes, Park Ridge, New Jersey, USA.</P>
+<P ALIGN="JUSTIFY">Fitch, H.S. and R.W. Henderson. 1977. Age and Sex Differences, Reproduction and Conservation of Iguana iguana. Milwaukee Public Museum Press. Milwaukee, Wisconsin, USA.</P>
+<P ALIGN="JUSTIFY">Hirth, H.F. 1963. Some aspects of the natural history of Iguana iguana on a tropical strand. Ecology 44:613-615.</P>
+<P ALIGN="JUSTIFY">Klein, E.H. 1982. Reproduction of the green iguana (Iguana iguna L.) in the tropical dry forest of southern Honduras. Brenesia 19/20:301-310. </P>
+<P ALIGN="JUSTIFY">Lazell, J.D., Jr. 1973. The lizard genus Iguana in the Lesser Antilles. Bulletin of the Museum of Comparative Zoology, Harvard University 145(1):1-28.</P>
+<P ALIGN="JUSTIFY">Tamsitt, J.R. and D. Valdivieso. 1963. The herpetofauna of the Caribbean Islands San Andres and Providencia. Revista de Biologfa Tropical 11(2): 131- 139. (Copies available from C. LardT, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Van Devender, R.W. 1982. Growth and ecology of spiny-tailed and green iguanas in Costa Rica. with comments on the evolution of herbivory and large body size. Pages 162-183 in Iguanas of the World. Behavior, Ecology, and Conservation. Noyes, Park Ridge, New Jersey, USA.</P>
+<P ALIGN="JUSTIFY">Werner, D. and T. Miller. 1984. Artificial nests for female green iguanas. Herpetological Review 15(2):57-58.</P>
+<P ALIGN="JUSTIFY">Werner, D. 1986. Iguana management in Central America. BOSTID Developments 6(1). 4 pp. (Available from BOSTID Publications, HA 476, National Research Council, 2101 Constitution Avenue, N.W., Washington, D.C. 20418.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black Iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burghardt, G.M. and A.S. Rand, eds. 1982. Iguanas of the World: Behavior, Ecology, and Conservation. Noyes, Park Ridge, New Jersey, USA.</P>
+<P ALIGN="JUSTIFY">Fitch, H.S. and R.W. Henderson. 1978. Ecology and exploitation of Ctenosaura similis. University of Kansas Science Bulletin 51 :483-500. (Copies available from the authors, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Fitch, H.S., R.W. Henderson, and D.M. Hillis. 1982. Exploitation of Iguanas in Central America. In Iguanas of the World: Behavior, Ecology, and Consen~ation. Noyes, Park Ridge, New Jersey, USA.</P>
+<P ALIGN="JUSTIFY">Iverson, J.B. 1979. Behavior and ecology of the rock iguana, Cyclura carinata. Bulletin of the Florida State Museum Biological Science 24(3):175-358.</P>
+<P ALIGN="JUSTIFY">Martinez, M.G. 1986. Habitos alimenticios de iguanas y garrobos. La Prensa Grafica, San Salvador, May 5:55. (Copies available from G. LardT, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY">Sanchez, S.A. 1985. El garrobo. El Diario de Hoy, San Salvador June 18:36. (Copies available from G. LardT, see Research Contacts.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tegu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Donadio, O.K. and J.M. Gallardo. 1984. Biologia y Conservacion de las Especies del GTnero Tupinambis (Squamata, Sauria Teiidae) en la Republica Argentina. Revista del Museo Argentino de Ciencias Naturales 'Bernardino Rivadavia" Zoologia, 13(11):117-127. Agosto.</P>
+<P ALIGN="JUSTIFY">Revision Bibliografica de algunos aspectos de la Biologfa conservacion y explotacion de los lagartos del gTnero topinambis (Daudin, 1803) by Laura Venturino, Dr. Thesis, Universidad de la Republic (Uruguay) 1983).</P>
+<P ALIGN="JUSTIFY">Report to World Wildlife Fund, USA, Biologia y aprovechamiento de una poblacion de Tupinambis references, by Claudio Blanco and Leohor Pessina (1985).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the publications listed, many countries run beekeeping programs, and have literature and extension services available based on local experiences. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The International Bee Research Association (IBRA) publishes a Newsletter for Beekeepers in Tropical and Subtropical Countries twice each year. Its purpose is to provide a forum for exchange of information about beekeeping. The Newsletter is funded by the United Kingdom Overseas Development Agency (ODA) and is distributed free of charge to those in developing countries involved with beekeeping. Write to the International Bee Research Association, 18 North Road, Cardiff CFI 3DY, United Kingdom, for subscription information. The IBRA can also provide information on forthcoming conferences, grant programs, and the names of other beekeepers in your country. The International Agency for Apiculture Development (IAAD) publishes a quarterly newsletter called Cornucopia that contains articles from beekeepers around the world, especially from the developing world. It provides information on producing, selling, and manufacturing hive products on a local level and discusses agroforestry and the pest and pesticide problems of honeybees. Write to Cornucopia, c/o M. Coleman, 6N 909 Roosevelt Avenue, St. Charles, Illinois 60174, USA, for a free sample. Subscriptions are $12 a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adjare, S. 1984. The Golden Insect: a Handbook on Beekeeping for Beginners. Technology Consultancy Centre, University of Science and Technology, Kumasi, Ghana, in association with Intermediate Technology Publications, Ltd., 9 King Street, Covent Garden, London, WC2 E8HN, UK. 103 pp.</P>
+<P ALIGN="JUSTIFY">Anderson, R.H., B. Buys, and M.F. Johannsmeier. 1983. Beekeeping in South Africa. Department of Agriculture BuHetin No. 394. Pretoria, South Africa. 207 pp.</P>
+<P ALIGN="JUSTIFY">Bradbear, N. and D. De Jong. 1985. The management of africanized honeybees. IBRA Leaflet No. 2. International Bee Research Association (IBRA). Available in English or Spanish from Hill House, Gerrards Cross, Buckinghamshire SL9 ONR, UK. 4 pp.</P>
+<P ALIGN="JUSTIFY">Clauss, B. 1982. A Beekeeping Handbook. Agricultural Information Service, Gaborne, Botswana. 65 pp.</P>
+<P ALIGN="JUSTIFY">Crane, E., P. Walker, and R. Day. 1984. Honey plants of the world. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">FAO. 1984. Proceedings of the expert consultation on beekeeping with Apis mellifera in tropical and sub-tropical Asia. 9-14 April, 1984. FAO Regional Office for Asia and the Tropical Region, Paliwan Mansion, Phra Atit Road, Bangkok, Thailand.</P>
+<P ALIGN="JUSTIFY">Gentry, C. 1984. Small Scale Beekeeping. Manual M-17. Peace Corps, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">IBRC. 1976. Apiculture in Tropical Climates. E. Crane, ed. Full report of the First Conference. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">IBRC. 1982. Proceedings of the Second International Conference on Apiculture in Tropical Climates. New Delhi, 1980. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">IBRC. 1985. Proceedings of the Third international Conference on Apiculture in Tropical Climates. Nairobi, Kenya, November 5-9, 1984. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">IBRC. 1988. Proceedings of the Fourth International Conference on Apiculture in Tropical Climates. Cairo, Egypt, November 1988. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">Kigatiira, K.I. 1974. Hive Designs for Beekeeping in Kenya. Proceedings Entomological Society of Ontario 105:118-128.</P>
+<P ALIGN="JUSTIFY">McGregor, S.E. 1976. Insect Pollination of Cultivated Crop Plants. U.S. Department of Agriculture Handbook No. 496. Government Printing Office, Washington, D.C. 411 pp.</P>
+<P ALIGN="JUSTIFY">Razafindrakoto, C. 1972. Beekeeping in Madagascar. UniversitT Paul-Sabaier de Toulouse, France. 123 pp. </P>
+<P ALIGN="JUSTIFY">Sammataro, D. 1985. Beekeeping in the Philippines. 2nd edition. International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">Sammataro, D. and A. Avitabile. 1986. Beekeepers Handbook. 2nd edition. Collier Books' MacMillan Co., New York.</P>
+<P ALIGN="JUSTIFY">Saubolle, B.R, and A. Bachmann. 1979. Beekeeping: an Introduction to Modern Beekeeping in Nepal. Sahayogi Prahashan, Tripureshwar, Kathmandu, Nepal.</P>
+<P ALIGN="JUSTIFY">Silberrad, Roger E.M. n.d. Beekeeping in Zambia. Apimondia. Available through the International Bee Research Association, London.</P>
+<P ALIGN="JUSTIFY">Singh, S. 1964. Beekeeping in India. Silver Jubilee Publication of the Entomological Society of India. Entomological Society of India, New Delhi.</P>
+<P ALIGN="JUSTIFY">Smith, Francis G. 1960. Beekeeping in the Tropics. Western Printing Service, Bristol UK.</P>
+<P ALIGN="JUSTIFY">Townsend, G.F. 1978. Preparation of Honey for Market. Ministry of Agriculture and Food Publication 544. Ministry of Agriculture and Food, Ontario, Canada.</P>
+<P ALIGN="JUSTIFY">Townsend, G.F. 1976. Transitional hives for use with the tropical African bee Apis mellifera adansonii. Pages 181-189 in Apiculture in Tropical Climates. E. Crane, ed. Full report of the First Conference. International Bee Research Association, London. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">B Research Contacts</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This section includes the names and addresses of individuals and institutions who are familiar with the animal listed. Each person has agreed to answer requests for information and advice. This personal follow-through is the main way this book can stimulate the development of microlivestock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICROBREEDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microcattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B.K. Ahunu, Animal Science Department, University of Ghana, P.O. Box 25, Legon, Ghana</P>
+<P ALIGN="JUSTIFY">D.O. Alonge, Meat Hygiene and Preservation Laboratory, Faculty of Veterinary Medicine, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">M. Andres Poli, EEA San Luis INTA, CC 17, 5730 Mercedes (SL), Argentina</P>
+<P ALIGN="JUSTIFY">F.B. Bareeba, Department of Animal Science, Makerere University, P.O. Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">J.A. Bennett, Department of Animal, Dairy, and Veterinary Sciences, Utah State University, Logan, Utah 84322-4815, USA</P>
+<P ALIGN="JUSTIFY">J.M. Berruecos V., School of Veterinary Medicine and Zoology, Universidad Nacional Aut6noma de MTxico, Ciudad Universitaria, Alvaro Obreg6n, 04510, Mexico D.F., Mexico</P>
+<P ALIGN="JUSTIFY">Cai Li, Animal Science and Veterinary Research Institute, Southwest College of Minority Nationalities, Chengdu, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Centro de Investigaciones Pecuarias (CENIP), A.P. 227-9, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">G.L. Chan, B4-5 Nanyang Mansion, Shenzhen, Guangdong, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Y. Cheneau, Institut d'Elevage et de MTdecine VTtTrinaire des Pays Tropicaux, Laboratoire de Farcha, BP 433, N'Djamena, Chad</P>
+<P ALIGN="JUSTIFY">Cheng Peilieu, Institute of Animal Science, Chinese Academy of Sciences, Beijing, People's Republic of China</P>
+<P ALIGN="JUSTIFY">W.R. Cockrill, 29 Downs Park West, Bristol BS6 7QH, UK</P>
+<P ALIGN="JUSTIFY">J.H. Conrad, Department of Animal Science, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">T.J. Cunha, P.O. Box R, La Verne, California 91750, USA</P>
+<P ALIGN="JUSTIFY">D.E. Deppner, Trees for the Future, 11306 Estona Drive, Silver Spring, Maryland 20902, USA (breeds of the Himalayas, East Indies)</P>
+<P ALIGN="JUSTIFY">C. Devendra, Agriculture Food and Nutrition Sciences Division, International Development Research Centre (IDRC), Tanglin P.O. Box 101, 9124 Singapore</P>
+<P ALIGN="JUSTIFY">N.l. Dim, Department of Animal Science, Faculty of Agriculture, Institute for Agricultural Research, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">Director, Agriculture and Forestry, PB 13184, Windhoek 9000, Namibia</P>
+<P ALIGN="JUSTIFY">V.M.S. Duarte, Instituto de Investigatao Veterinaria, C.P. 7, Huambo, Angola</P>
+<P ALIGN="JUSTIFY">M. Felius, Kerkhoflaan 47C, 3034 TA Rotterdam, The Netherlands</P>
+<P ALIGN="JUSTIFY">D. Fleharty, American Dexter Cattle Association, R.R. #1, Box 378, Concordia, Missouri 64020. USA </P>
+<P ALIGN="JUSTIFY">G. Garcia Lagombra, Animal Husbandry Department, Universidad Nacional "Pedro Henriquez Urena," Decanato Ciencias Agropecuarias, Km 5~/z Aut. Duarte, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">F. Gebreab, College of Veterinary Science, Addis Ababa University, Addis Ababa, Ethiopia</P>
+<P ALIGN="JUSTIFY">G.F.W. Haenlein, Department of Animal Science and Agricultural Biochemistry University of Delaware, Newark, Delaware 19717-1303, USA</P>
+<P ALIGN="JUSTIFY">Z.B. Jensen, Animal and Dairy Science Research Institute, PB X02, Irene, Transvaal 1675, South Africa</P>
+<P ALIGN="JUSTIFY">Jin Xizhen, Animal Science and Veterinary Research Institute, Southwest College of Minority Nationalities, Chengdu, People's Republic of China</P>
+<P ALIGN="JUSTIFY">G. Kitsopanidis, Faculty of Agriculture, Aristotelian University of Thessaloniki, University Campus, Thessaloniki, Greece</P>
+<P ALIGN="JUSTIFY">G.E. Kodituwakku, Department of Veterinary Clinical Studies, University of Peradeniya, Peradeniya, Sri Lanka</P>
+<P ALIGN="JUSTIFY">N.M. Konnerup, 74 North Sunrise Boulevard, Camano Island, Washington 98292, USA</P>
+<P ALIGN="JUSTIFY">L.Y.L. Li, Department of Animal Husbandry and Veterinary Science, South China Agricultural College, Ghangzhou, People's Republic of China</P>
+<P ALIGN="JUSTIFY">J.K. Loosli, 406 S.W. 40th Street, Gainesville, Florida 32607, USA</P>
+<P ALIGN="JUSTIFY">A.B. Lwoga, Sokoine University of Agriculture, P.O. Box 3000, Morogoro, Tanzania</P>
+<P ALIGN="JUSTIFY">A. Martinez Balboa, Legaspy 1025, Apartado Postal 43, 23000, La Paz, Baja California Sur, Mexico</P>
+<P ALIGN="JUSTIFY">A. Masam, Livestock Training Institute, Tengeru, P.O. Box 3101, Arusha, Tanzania</P>
+<P ALIGN="JUSTIFY">J.P. Maule, Hannahfield Quarry House, 578 Lanark Road West, Balerno, Midlothian EH 14 7BN, UK</P>
+<P ALIGN="JUSTIFY">M. Mazid, Faculty of Agriculture, University of Aleppo, Aleppo, Syria</P>
+<P ALIGN="JUSTIFY">L.R. McDowell, Department of Animal Sciences, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">J.A. Morgan, College of Natural Resources and Environmental Studies, University of Juba, P.O. Box 82, Juba, Sudan</P>
+<P ALIGN="JUSTIFY">D.B. Mpiri, Livestock Production Research Institute, Private Bag, Mpwapwa, Tanzania</P>
+<P ALIGN="JUSTIFY">Ni Shicheng, Animal Husbandry and Veterinary Science, Zhejiang Agricultural University, Hangzhou, People's Republic of China</P>
+<P ALIGN="JUSTIFY">B. Nikolov, Institute of Cattle and Sheep Breeding, 6000 Stara Zagora, Bulgaria</P>
+<P ALIGN="JUSTIFY">T. Olson, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">T.W. Perry, Department of Animal Sciences, Purdue University, West Lafayette, Indiana 47907, USA</P>
+<P ALIGN="JUSTIFY">R.W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY">F. Pirchner, Technical University of Munich, D-8050 Munich-Weihenstephan, Germany</P>
+<P ALIGN="JUSTIFY">A. Ramamohana Rao, Postgraduate Studies, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad, Andhra Pradesh 500 030, India</P>
+<P ALIGN="JUSTIFY">Soedomo Reksohadiprodjo, Department of Animai Nutrition, Faculty of Animal Husbandry, Universitas Gadjah Mada, Sekip Blok N-42, Yogyakarta, Indonesia</P>
+<P ALIGN="JUSTIFY">A.Y. Robles, Dairy Training and Research Institute, University of the Philippines at Los Banos, College, Laguna 3732, Philippines</P>
+<P ALIGN="JUSTIFY">Sie Cheuxia, Department of Animal Science, Nanjing Agricultural University, Nanjing, People's Republic of China</P>
+<P ALIGN="JUSTIFY">A.D. Tillman, 523 West Harned Place, Stillwater, Oklahoma 74074, USA</P>
+<P ALIGN="JUSTIFY">J.C.M. Trail, Livestock Productivity and Trypanotolerance Group, International Livestock Centre for Africa (ILCA), P.O. Box 30709, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">A.C. Warnick, Department of Animal Science, University of Florida, Gainesville, Florida 32611, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microgoat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">E.A. Adebowale, Institute of Agricultural Research and Training, University of Ife, Moor Plantation, P.M.B. 5029, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">A.A. Adeloye, Faculty of Agriculture, Adeyemi College of Education, Onjo, Nigeria</P>
+<P ALIGN="JUSTIFY">A.A. Ademosun, Department of Animal Science, University of Ife, lle-Ife, Nigeria</P>
+<P ALIGN="JUSTIFY">I.F. Adu, N.A.P.R.I., Ahmadu Bello University, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">I.A. Akinbode, Faculty of Agriculture, University of Ife, Ile-Ife, Nigeria</P>
+<P ALIGN="JUSTIFY">A.O. Akinsoyinu, Department of Animal Science, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">J.A. Akonji, Institut de Recherches Zootechniques, Office National de la Recherche Scientifique et Technique (ONAREST), B.P. 65, Yaounde, Cameroon</P>
+<P ALIGN="JUSTIFY">D.O. Alonge, Faculty of Veterinary Medicine, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">Baik Dong Hoon, Department of Animal Science, College of Agriculture, Jeonbug National University, JEONJU, 520, Republic of Korea</P>
+<P ALIGN="JUSTIFY">J.S.F. Barker, Department of Animal Science, University of New England, Armidale, New South Wales 2351, Australia</P>
+<P ALIGN="JUSTIFY">K. Boateng, Cooperative Extension Service, University of the Virgin Islands, Box L, Kingshill, St. Croix, Virgin Islands 00850, USA</P>
+<P ALIGN="JUSTIFY">G.E. Bradford, University of California, Davis, California 95616, USA</P>
+<P ALIGN="JUSTIFY">M.S. Browne, Nutrition Consulting Services, P.O. Box 788, St. Thomas, Virgin Islands 00801, USA</P>
+<P ALIGN="JUSTIFY">T.D. Bunch, Department of Animal, Dairy, and Veterinary Sciences, Utah State University, Logan, Utah 84322-4815, USA</P>
+<P ALIGN="JUSTIFY">T.C. Cartwright, Department of Animal Science, Texas A&amp;M University, College Station, Texas 77843, USA</P>
+<P ALIGN="JUSTIFY">Centro de Investigaciones Pecuarias (CENIP), A.P. 227-9, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">C. Devendra, Agriculture Food and Nutrition Sciences Division, International Development Research Centre (IDRC), Tanglin P.O. Box 101, 9124 Singapore, Singapore</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Department of Animal Science, Faculty of Agriculture, Institute for Agricultural Research, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">D. Fielding, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">H.A. Fitzhugh, Winrock International, Route 3, Petit Jean Mountain, Morrilton, Arkansas 72110, USA</P>
+<P ALIGN="JUSTIFY">W.C. Foote, Utah State University International Sheep and Goat Institute, UNC 48, Utah State University, Logan, Utah 84322, USA</P>
+<P ALIGN="JUSTIFY">G.R. Gerona, Department of Animal Science and Veterinary Medicine, Visayas State College of Agriculture, Baybay, Leyte, Philippines</P>
+<P ALIGN="JUSTIFY">G.F.W. Haenlein, Department of Animal Science and Agricultural Biochemistry, University of Delaware, Newark, Delaware 19717-1303, USA</P>
+<P ALIGN="JUSTIFY">A. Essa Haid, Essa International, Inc., 2550 M Street, Suite 405, Washington, D.C. 20037, USA (small East African)</P>
+<P ALIGN="JUSTIFY">W. Harding, Agrarian Society, Palazzo de la Salle, Valletta, Malta</P>
+<P ALIGN="JUSTIFY">M.A. Hasnath, Department of Animal Husbandry, Bangladesh Agricultural University, P.O. Agricultural University, Mymensingh, Bangladesh</P>
+<P ALIGN="JUSTIFY">A.S. Hoversland, Division of Research Grants, National Institutes of Health, 5333 Westbard Avenue, Bethesda, Maryland 20205, USA</P>
+<P ALIGN="JUSTIFY">L. Hulse, National Pygmy Goat Association, RFD #1, Fern Avenue, Amesbury, Massachusetts 01913, USA</P>
+<P ALIGN="JUSTIFY">T.P. Husband, Department of Natural Resource Science, University of Rhode Island, Kingston, Rhode Island 02881, USA (bezoar, agrimi) </P>
+<P ALIGN="JUSTIFY">D.L. Huss, P.O. Box 426, Menard, Texas 76859, USA</P>
+<P ALIGN="JUSTIFY">B. Hutchins, 2535 Halsted Road, Apartment 1, Rockford, Illinois 61103, USA</P>
+<P ALIGN="JUSTIFY">N. Iba+ez Herrera, Paraguay 160-Urbanizacion, Apartado 315, El Recreo, Trujillo, Peru</P>
+<P ALIGN="JUSTIFY">S. Karam Shah, Livestock Experimental Station Rakh Khairewala, District Muzaffergarh, Pakistan</P>
+<P ALIGN="JUSTIFY">C. Katongole, Faculty of Veterinary Medicine, Makerere University, PO Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">G. Kiwuwa, Department of Animal Science, Makerere University, PO Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">L.Y.L. Li, Department of Animal Husbandry and Veterinary Science, South China Agricultural College, Ghangzhou, People's Republic of China</P>
+<P ALIGN="JUSTIFY">D.R. Lincicome, Animal Parasitology Institute, U.S. Department of Agric£lture, Building 1180, BARC-East, Beltsville, Maryland 20705, USA</P>
+<P ALIGN="JUSTIFY">Liu Chengxiang, Animal Husbandry and Veterinary Science Research Institute, Guang^ dong Agricultural Academy, Guangdong, People's Republic of China</P>
+<P ALIGN="JUSTIFY">J.K. Loosli, 406 S.W. 40th Street, Gainesville, Florida 32607, USA</P>
+<P ALIGN="JUSTIFY">M. Mahyuddin Dahan, Department of Animal Sciences, Universiti Pertanian Malaysia, Serdang, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY">G.C.H. Mandari, Livestock Research Centre, West Kilimanjaro, P.O. Box 103, Hai, Tanzania</P>
+<P ALIGN="JUSTIFY">J. Mann, Institute of Tropical Veterinary Medicine, University of Giessen, Germany</P>
+<P ALIGN="JUSTIFY">A. Martinez Balboa, Legaspy 1025, Apartado Postal 43, 23000, La Paz, Baja California Sur, Mexico</P>
+<P ALIGN="JUSTIFY">I. Mecha, Department of Animal Science, University of Nigeria, Nsukka, Anambra State, Nigeria</P>
+<P ALIGN="JUSTIFY">J. Metcalf, School of Medicine, University of Oregon, Eugene, Oregon 97403, USA</P>
+<P ALIGN="JUSTIFY">K. Mitchell, Baptist Bible Institute, P.O. Box 301, Basseterre, St. Kitts, West Indies</P>
+<P ALIGN="JUSTIFY">M. Khusahry Mohd Yusuff, Malaysian Agricultural and Research Institute (MARDI), G.P.O. Box 12301, Kuala Lumpur 01-02, Malaysia</P>
+<P ALIGN="JUSTIFY">A. Monsi, Departments of Animal Science/Food Science and Technology, Rivers State University of Science and Technology, P.M.B. 5080, Port Harcourt, Nigeria</P>
+<P ALIGN="JUSTIFY">G. Montsma, Klomperweg 79, 6741 PD, Lunteren, Netherlands</P>
+<P ALIGN="JUSTIFY">J. Moore, Department of Animal Science, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">C.M. Munyabuntu, Department of Animal Science, P.O. Box 7062, Makerere University' Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">Th. Murayi, Institut des Sciences Agronomiques du Rwanda, P.O. Box 138, Butare, Rwanda</P>
+<P ALIGN="JUSTIFY">W.N.M. Mwenya, School of Agricultural Sciences, University of Zambia, Box 32379, Lusaka, Zambia</P>
+<P ALIGN="JUSTIFY">A. Nivyobizi, FacultT des Sciences Agronomiques, UniversitT du Burundi, BP 2940, Bujumbura, Burundi</P>
+<P ALIGN="JUSTIFY">G.A. Norman, Tropical Development Research Institute, 56/62 Gray's Inn Road, London WCIX 8LU, UK</P>
+<P ALIGN="JUSTIFY">K. Okello-Lapenga, Department of Veterinary Pathobiology, Makerere University, PO Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">S. Ramahefarison, DTpartement de Recherches Zootechniques et VTtTrinaires tCENRADERU), BP 904, Amatobe, Antananarivo, Madagascar</P>
+<P ALIGN="JUSTIFY">A. Ramamohana Rao, Postgraduate Studies, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad, Andhra Pradesh 500 030, India</P>
+<P ALIGN="JUSTIFY">R.K. Rastogi, Department of Livestock Science, University of the West Indies, St. Augustine, Trinidad, West Indies </P>
+<P ALIGN="JUSTIFY">G. Rasul, District Forest Officer &amp; Wildlffe Warden, P.O. Box 501, Gilgit (northern area), Pakistan</P>
+<P ALIGN="JUSTIFY">D. Rattner, Institute of Animal Research, Kibbutz Lahav, Israel (Sinai goat, ya-ez hybrids)</P>
+<P ALIGN="JUSTIFY">Soedomo Reksohadiprodjo, Department of Animal Nutrition, Faculty of Animal Husbandry, Universitas Gadjah Mada, Sekip Blok N-42, Yogyakarta, Indonesia</P>
+<P ALIGN="JUSTIFY">A. Repollo, Jr., Palawan National Agricultural College, Aborlan, Palawan, Philippines</P>
+<P ALIGN="JUSTIFY">A.Y. Robles, Dairy Training and Research Institute, University of the Pbilippines, Los Banos, Laguna 3732, Philippines</P>
+<P ALIGN="JUSTIFY">A. Rocha, Instituto de Reprodutao e Melhoramento Animal, C.P. 25, Matola, Mozambique</P>
+<P ALIGN="JUSTIFY">C. Rodriguez, Centro de Investigaciones Pecuarias (CENIP), Autopista Duarte Km 24, Apartado 227-9, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">M. Nasim Siddiqi, Zoology Department, University of Peshawar, N.W.F.P., Pakistan</P>
+<P ALIGN="JUSTIFY">M. Shelton, Texas A &amp; M University, College Station, Texas 77843, USA (criollo)</P>
+<P ALIGN="JUSTIFY">A. Shkolnik, Department of Zoology, Tel Aviv University, Tel Aviv, Israel</P>
+<P ALIGN="JUSTIFY">O.C. Simpson, Cameroon Road, Prairie View A&amp;M University, Prairie View, Texas 77445, USA</P>
+<P ALIGN="JUSTIFY">Sie Chenxia, Department of Animal Science, Nanjing Agricultural University, Nanjing, People's Republic of Cbina</P>
+<P ALIGN="JUSTIFY">R.G. Wahome, Department of Animal Production, University of Nairobi, P.O. Box 29053, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">R. Watts, Animal Science Department, Natural Resources Development College, Lusaka, Zambia</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY">H. Wood, Highland Game Farm, Route 4, Box 450, Alexandria, Indiana 46001, USA</P>
+<P ALIGN="JUSTIFY">T.P. Husband, Department of Natural Resources Science, University of Rhode Island, Kingston, Rhode Island 02881, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Microsheep</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">E.A. Adebowale, Institute of Agricultural Research and Training, University of Ife, Moor Plantation, P.M.B. 5029, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">I.F. Adu, N.A.P.R.I., Ahmadu Bello University, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">I.A. Akinbode, Faculty of Agriculture, University of Ife, Ile-Ife, Nigeria</P>
+<P ALIGN="JUSTIFY">A.O. Akinsoyinu, Department of Animal Science, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">M. Amin, Jammu and Kashmis State Sheep and Shearing Products Development Board, Nowshera, Srinigar, Kashmir 190 011, India</P>
+<P ALIGN="JUSTIFY">Ahmad Mustaffa B. HJ. Babjee, Veterinary Services Department, Ibu Pejabat Perkhidmatan Haiwan, Kementerian Pertanian, Malaysia, Jalan Mahameru, Kuala Lumpur 10-02, Malaysia (grazing in rubber plantations)</P>
+<P ALIGN="JUSTIFY">J.S.F. Barker, Department of Animal Science, University of New England, Armidale, New South Wales, 2351, Australia (Indonesian breeds)</P>
+<P ALIGN="JUSTIFY">K. Boateng, Cooperative Extension Service, College of the Virgin Islands, Box L, Kingshill, St. Croix, Virgin Islands 00850, USA</P>
+<P ALIGN="JUSTIFY">G.E. Bradford, University of Calffornia, Davis, Calffornia 95616, USA</P>
+<P ALIGN="JUSTIFY">R. Breckle, U.S. Forest Service, Alsea, Oregon 97324, USA (grazing sheep in forests)</P>
+<P ALIGN="JUSTIFY">T. Bunch, Department of Animal, Dairy, and Veterinary Sciences, Utah State University, Logan, Utah 84322-4815, USA (Iranian thin-tailed, Navajo, wild-sheep hybrids)</P>
+<P ALIGN="JUSTIFY">M. Carpio P., Departamento de Produccion Animal, Universidad Nacional Agraria, Apartado 456, La Molina, Lima, Peru </P>
+<P ALIGN="JUSTIFY">Centro de Investigaciones Pecuarias (CENIP), A.P. 227-9, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">S. Cottrell, Pippin Farm, 3081 Goshen Road, Bellingham, Washington 98226, USA</P>
+<P ALIGN="JUSTIFY">C. Courtney, Veterinary Faculty, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">D. Deller, Virgin Islands Department of Agriculture, St. Thomas, Virgin Islands 00820, USA</P>
+<P ALIGN="JUSTIFY">A. Dettmers, 5620 Longwood Avenue, Port Charlotte, Florida 33953, USA (West African dwarf)</P>
+<P ALIGN="JUSTIFY">C. Devendra, Agricultural Food and Nutrition Sciences Division International Development Research Centre (IDRC), Tanglin P.O. Box 101, 9124 Singapore, Singapore</P>
+<P ALIGN="JUSTIFY">N.l. Dim, Department of Animal Science, Faculty of Agriculture, Institute for Agricultural Research, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">K. Drew, Invermay Agricultural Research Centre, Private Bag, Mosgiel, New Zealand</P>
+<P ALIGN="JUSTIFY">F. El Amin, Department of Animal Husandry, Faculty of Veterinary Science, University of Khartoum, P.O. Box 32, Khartoum North, Sudan</P>
+<P ALIGN="JUSTIFY">Gholam-Hossein Erabi, Faculty of Agriculture, University of Tabriz, Tabriz 51664, Iran</P>
+<P ALIGN="JUSTIFY">H.A. Fitzhugh, Winrock International Institute for Agricultural Development, Route 3, Petit Jean Mountain, Morrilton, Arkansas 72110, USA</P>
+<P ALIGN="JUSTIFY">W. Foote, Animal' Dairy, and Veterinary Science Department, UNC 48, Utah State University, Logan, Utah 84322-4815, USA (Virgin Islands white hair, wild-sheep hybrids)</P>
+<P ALIGN="JUSTIFY">E.-H. Gueye, Centre de Recherches Zootechniques de Kolda, Institut SenTgalais de Recherches Agricoles, (ISRA), B.P. 53, Kolda, Senegal</P>
+<P ALIGN="JUSTIFY">G. Garcia Lagombra, Animal Husbandry Department, Universidad Nacional "Pedro Henriquez Urena," Decanato Ciencias Agropecuarias, Km 5 1/2 Aut. Duarte, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">G.F.W. Haenlein, Department of Animal Science and Agricultural Biochemistry, University of Delaware, Newark, Delaware 19717-1303, USA</P>
+<P ALIGN="JUSTIFY">E. Henson, Bemborough, Guiting Power, Cheltenham, Gloucester, UK (rare breeds)</P>
+<P ALIGN="JUSTIFY">D.L. Huss, P.O. Box 426, Menard, Texas 76859, USA</P>
+<P ALIGN="JUSTIFY">N. Ibanez Herrera, Paraguay 160 - Urbanizacion, Apartado 315, El Recreo, Trujillo, Peru</P>
+<P ALIGN="JUSTIFY">P. Jewell, Department of Physiology, University of Cambridge, Cambridge CB2 ITN, UK</P>
+<P ALIGN="JUSTIFY">Jones Sheep Farm, RR 2 Box 185-55, Peabody, Kansas 66866, USA</P>
+<P ALIGN="JUSTIFY">P.E. Loggins, Animal Science Department, 108-D Suite, University of Florida, Gainesville, Florida32611, USA</P>
+<P ALIGN="JUSTIFY">J.K. Loosli, 406 S.W. 40th Street, Gainesville, Florida 32607, USA</P>
+<P ALIGN="JUSTIFY">G.C.H. Mandari, Livestock Research Centre, West Kilimanjaro, P.O. Box 103, Hai, Tanzania</P>
+<P ALIGN="JUSTIFY">J.P. Maule, Hannahfield Quarry House, 578 Lanark Road West, Balerno, Midlothian EH14 7BN, UK</P>
+<P ALIGN="JUSTIFY">L.K. McNeal, Animal, Dairy, and Veterinary Science Department, UNC 48, Utah State University, Logan, Utah 84322-4815, USA</P>
+<P ALIGN="JUSTIFY">I. Mecha, Department of Animal Science, University of Nigeria, Nsukka, Anambra State, Nigeria</P>
+<P ALIGN="JUSTIFY">K. Mitchell, Baptist Bible Institute, P.O. Box 301, Basseterre, St. Kitts, West Indies</P>
+<P ALIGN="JUSTIFY">A. Monsi, Department of Animal Science, Food Science and Technology, Rivers State University of Science and Technology, P.M.B. 5080, Port Harcourt, Nigeria</P>
+<P ALIGN="JUSTIFY">C.M. Munyabuntu, Department of Animal Science, Makerere University, P.O. Box 7062, Kampala, Uganda </P>
+<P ALIGN="JUSTIFY">Th. Murayi, Institut des Sciences Agronomiques du Rwanda, P.O. Box 138, Butare, Rwanda</P>
+<P ALIGN="JUSTIFY">W.N.M. Mwenya, School of Agriculture Sciences, University of Zambia, Box 32379, Lusaka,  Zambia</P>
+<P ALIGN="JUSTIFY">M. Ngendahayo, Institut des Sciences Agronomiques du Rwanda, B.P. 138, Butare, Rwanda</P>
+<P ALIGN="JUSTIFY">R. Njwe, DTpartement des Sciences Animales, Ecole Nationale SupTrieure Agronomique, Centre  Universitaire de Dschang, B.P. 138, YaoundT, United Republic of Cameroon</P>
+<P ALIGN="JUSTIFY">W.J.A. Payne, 91 Bedwardine Road, London SE19 3AY, UK</P>
+<P ALIGN="JUSTIFY">R.W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington,  Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY">G.V. Raghavan, Animal Science Department, College of Veterinary Science, Andhra Pradesh  Agricultural University, Rajendranagar, Hyderabad 500 030, Andhra Pradesh, India</P>
+<P ALIGN="JUSTIFY">A. Ramamohana Rao, Postgraduate Studies, Andhra Pradesh Agricultural University,  Rajendranagar, Hyderabad, Andhra Pradesh 500 030, India</P>
+<P ALIGN="JUSTIFY">R.K. Rastogi, Department of Livestock Science, University of the West Indies, St. Augustine,  Trinidad, West Indies</P>
+<P ALIGN="JUSTIFY">Soedomo Reksohadiprodjo, Department of Animal Nutrition, Faculty of Animal Husbandry,  Universitas Gadjah Mada, Sekip Blok N-42, Yogyakarta, Indonesia</P>
+<P ALIGN="JUSTIFY">A.Y. Robles, Dairy Training and Research Institute, University of the Philippines at Los Banos,  College, Laguna 3732, Philippines</P>
+<P ALIGN="JUSTIFY">A. Rocha, Instituto de Reprodutao e Melhoramento Animal, C.P. 25, Matola, Mozambique</P>
+<P ALIGN="JUSTIFY">M.L. Ryder, c/o H.F.R.O., Bush Estate, Penicuik, Edinburgh, UK (Barbados blackbelly, wool)</P>
+<P ALIGN="JUSTIFY">Sie Chenxia, Department of Animal Science, Nanjing Agricultural University, Nanjing, People's  Republic of China</P>
+<P ALIGN="JUSTIFY">C. David Simpson, Range and Wildlife Department, Texas Tech University, P.O. Box 4349,  Lubbock, Texas 79409, USA</P>
+<P ALIGN="JUSTIFY">C.E. Terrill, U.S. Department of Agriculture, Building 005, BARC-West, Beltsville, Maryland 20705,  USA</P>
+<P ALIGN="JUSTIFY">H.N. Turner, Genetics Research Laboratories, CSIRO, P.O. Box 184, North Ryde, New South  Wales 2113, Australia (Indonesian breeds)</P>
+<P ALIGN="JUSTIFY">R. Vaccaro, Universidad Nacional Agraria, La Molina, P.O. Box 456, Lima, Peru</P>
+<P ALIGN="JUSTIFY">R.G. Wahome, Department of Animal Production, P.O. Box 29053, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">S. Wildeus, College of the Virgin Islands, Agricultural Experiment Station, R.R. 2, Box 10051  Kingshill, St. Croix, Virgin Islands 00850, USA</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY">Wu Jitang, Animal and Veterinary Science, Jiangsu Province Academy of Agricultural Sciences,  Nanjing, People's Republic of China</P>
+<P ALIGN="JUSTIFY">A. Yenikoye, FacultT d'Agronomie, UniversitT de Niamey, B.P. 10662, Niamey, Niger</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Micropig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I.A. Akinbode, Faculty of Agriculture, University of Ife, Ile-Ife, Nigeria</P>
+<P ALIGN="JUSTIFY">D.O. Alonge, Meat Hygiene and Preservation Laboratory, Faculty of Veterinary Medicine,  University of Ibadan, Ibadan, Nigeria  </P>
+<P ALIGN="JUSTIFY">J.M. Andrews, Mesoamerican Ecology Institute, Tulane University, New Orleans, Louisiana 70118, USA (Yucatan pig)</P>
+<P ALIGN="JUSTIFY">G. Ashton-Peach, Box 17, Ohaeawai, Bay of Islands, New Zealand (kunekune)</P>
+<P ALIGN="JUSTIFY">M. Berruecos V. Muz, Facultad de Medicina Veterinaria y Zootecnia, Ciudad Universitaria, Mexico D.F., Mexico</P>
+<P ALIGN="JUSTIFY">R. Blakely, Sedgwick County Zoo, Wichita, Kansas 67203, USA (Ossabaw)</P>
+<P ALIGN="JUSTIFY">K. Boateng, Cooperative Extension Service, University of the Virgin Islands, Box L., Kingshill, St. Croix, Virgin Islands 00850, USA</P>
+<P ALIGN="JUSTIFY">I.L. Brisbin, Savannah River Ecology Laboratory, P.O. Drawer E, Aiken, South Carolina 29801, USA (Ossabaw)</P>
+<P ALIGN="JUSTIFY">L. Bustad, Veterinary School, Washington State University, Pullman, Washington, 99163, USA</P>
+<P ALIGN="JUSTIFY">C. Catibog-Sinha, Forest Products Research and Development Institute, College, Laguna 4031, Philippines</P>
+<P ALIGN="JUSTIFY">Centro de Investigaciones Pecuarias (CENIP), A.P. 227-9, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">Charles River Laboratories, Inc., 251 Ballardvale Street, Wilmington, Massachusetts 01887-0630, USA</P>
+<P ALIGN="JUSTIFY">J.H. Conrad, Department of Animal Science, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">T.J. Cunha, PO Box R, LaVerne, California 91750, USA</P>
+<P ALIGN="JUSTIFY">F. Dederer, 712 Brown Street, Philadelphia, Pennsylvania 19123, USA</P>
+<P ALIGN="JUSTIFY">A. Dettmers, 5620 Longwood Avenue, Port Charlotte, Florida 33953, USA (miniature pigs)</P>
+<P ALIGN="JUSTIFY">C. Devendra, Agriculture Food and Nutrition Sciences Division, International Development Research Centre (IDRC), Tanglin P.O. Box 101, 9124 Singapore</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">G. Edgar, Greenhill, I R.D., Balfour, Southland, New Zealand (kunekune)</P>
+<P ALIGN="JUSTIFY">H. Hendricks, Department of Animal, Dairy, and Veterinary Sciences, Utah State University, Logan, Utah 84322-4815, USA</P>
+<P ALIGN="JUSTIFY">B.J. Hepburn, Swine Program, Charles River Laboratories, 251 Ballardvale Street, Wilmington, Massachusetts 01887-0630, USA (laboratory pigs)</P>
+<P ALIGN="JUSTIFY">P. Holbrook, Aria Road' via Te Kuiti, New Zealand (kunekune)</P>
+<P ALIGN="JUSTIFY">R.R. Hook, Jr., Sinclair Medical Research Farm, University of Missouri, Route 3, Columbia, Missouri 65203, USA (laboratory pigs)</P>
+<P ALIGN="JUSTIFY">J.O. Ilori, Faculty of Agriculture, University of If e, Ile-Ife, Nigeria</P>
+<P ALIGN="JUSTIFY">G. E. Kodituwakku, Department of Veterinary Clinical Studies, University of Peradeniya, Peradeniya, Sri Lanka</P>
+<P ALIGN="JUSTIFY">J.K. Loosli, 406 S.W. 40th Street' Gainesville, Florida 32607, USA</P>
+<P ALIGN="JUSTIFY">J.H. Maner, Winrock International, Route 3, Petit Jean Mountain, Morrilton, Arkansas 72110, USA</P>
+<P ALIGN="JUSTIFY">J.J. Mayer, Savannah River Ecology Laboratory, P.O. Drawer E, Aiken, South Carolina 29801, USA (Ossabaw)</P>
+<P ALIGN="JUSTIFY">K. Mitchell, Baptist Bible Institute, P.O. Box 301, Basseterre, St. Kitts, West Indies</P>
+<P ALIGN="JUSTIFY">A. Monsi, Departments of Animal Science/Food Science and Technology, Rivers State University of Science and Technology, P.M.B. 508O, Port Harcourt, Nigeria</P>
+<P ALIGN="JUSTIFY">J. Mtimuni, Livestock Production Department, Bunda College of Agriculture, University of Malawi, P.O. Box 219, Lilongwe, Malawi</P>
+<P ALIGN="JUSTIFY">D.G. Mugisa, c/o Insure Consult, P.O. Box 30002, Nakivubo, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">K. Mull, 2834 Hamner Avenue #208, Norco, California 91760, USA</P>
+<P ALIGN="JUSTIFY">W.L.R. Oliver, Pigs and Peccaries Specialist Group, Jersey Wildlife Prescrvation Trust, Les AugrFs Manor, Jersey, Channel Islands, UK (pigmy hog) </P>
+<P ALIGN="JUSTIFY">L. Panepinto, Redstone Canyon, P.O. Box 105, Masonville, Colorado 80541, USA (miniature pigs)</P>
+<P ALIGN="JUSTIFY">W.J.A. Payne, 91 Bedwardine Road, London SE19 3AY, UK</P>
+<P ALIGN="JUSTIFY">C.C. Perdomo, Centro Nacional de Pesquisa de Suinos e Aves, BR 153, km 110, CP D-3, 89700 Concordia, SC, Brazil</P>
+<P ALIGN="JUSTIFY">R.W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA (Chinese breeds)</P>
+<P ALIGN="JUSTIFY">W.G. Pond, Meat Animal Research Center, U.S. Department of Agriculture, Box 166, Clay Center, Nebraska 68933, USA</P>
+<P ALIGN="JUSTIFY">H. Popenoe, International Programs in Agriculture, 3028 McCarty Hall, University of Florida, Gainesville, Florida 32611, USA (New Guinea pigs)</P>
+<P ALIGN="JUSTIFY">B.S. Reddi, CoHege of Veterinary Science, Andhra Pradesh Agricultural University, Tirupati 517 502, India</P>
+<P ALIGN="JUSTIFY">S. Avendano Reyes, Instituto Nacional de las Investigaciones sobre los Recursos BiotTcnicos, (INIREB), Apartado Postal 97, MTrida, Yucatan, Mexico (Yucatan)</P>
+<P ALIGN="JUSTIFY">C. Robinson, Robinson's Racing Pigs, 5809 20th Avenue South, Tampa, Florida 336195457, USA (miniature pigs)</P>
+<P ALIGN="JUSTIFY">C. Arellano Sota, Regional Office for Latin America and the Caribbean, Food and Agriculture Organization of the United Nations, Casillo 10095, Santiago, Chile (Cuing)</P>
+<P ALIGN="JUSTIFY">A. Sriramamurty, College of Veterinary Science, Andhra Pradesh Agricultural University, Tirupati 517 502, India</P>
+<P ALIGN="JUSTIFY">M.M. Swindle, Comparative Medicine/Lab Animal Resources, Medical University of South Carolina, 171 Ashley Avenue, Charleston, South Carolina 29425, USA (laboratory pigs)</P>
+<P ALIGN="JUSTIFY">N. Tilakaratne, Veterinary Research Institute, Gannoruwa, Peradeniya, Sri Lanka</P>
+<P ALIGN="JUSTIFY">R.G. Wahome, Department of Animal Production, P.O. Box 29053, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">Wu Jitang, Animal and Veterinary Science, Jiangsu Provincial Academy of Agricultural Sciences, Nanjing, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Yong Shen Lee, Department of Animal Husbandry and Veterinary Medicine, South China Agricultural University, Guangzhou, People's Republic of China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">POULTRY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Information on poultry can generally be obtained from local ministries of agriculture or veterinary and livestock services. However, another source is the World's Poultry Science Association (c/o Institut fur Kleintierzucht, Dornbergstrasse 25/27, Postfach 280, C-3100 Celle, Germany). It has over 5,000 members from 40 national groups. Its objectives are (1) to advance poultry science and the poultry industry, (2) to disseminate and facilitate the exchange of knowledge pertaining to all branches of the poultry industry, (3) to encourage the promotion of world poultry congresses and regional conferences, and (4) to cooperate with other international organizations. It maintains working groups to explore and assess research work on tropical poultry problems. The World's Poultry Science Journal is published 3 times a year. It has also published a multilingual poultry dictionary.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chicken</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.O. Aduku, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria </P>
+<P ALIGN="JUSTIFY">D.O. Alonge, Meat Hygiene and Preservation Laboratory, Faculty of Veterinary Medicine, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">A. Ben-David, Poultry Production Specialist, 5, Azar Street, Holon 58291, Israel</P>
+<P ALIGN="JUSTIFY">I.L. Brisbin, Jr., Savannah River Ecology Laboratory, P.O. Drawer E, Aiken, South Carolina 29801, USA</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Senior Livestock Specialist, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">J.R. Couch, Poultry Science Department, Texas A&amp;M University, College Station, Texas 77843, USA</P>
+<P ALIGN="JUSTIFY">R.D. Crawford, Department of Animal and Poultry Science, University of Saskatchewan, Saskatoon, Saskatchewan S7N 0W0, Canada</P>
+<P ALIGN="JUSTIFY">M. Cuca G., Institucion de Ensenanza e Investigacion en Ciencias Agricolas, Colegio de Postgraduados, Chapingo, Mexico</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Animal Science Department, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">D. Fielding, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">R.O. Hawes, Department of Animal and Veterinary Sciences, University of Maine, Orono, Maine 04469, USA</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">C.H. Huang, Food and Fertilizer Technology Center for the Asian and Pacific Region, Fifih Floor, 14 Wenchow Street, Taipei, Taiwan</P>
+<P ALIGN="JUSTIFY">E.H. Ketelaars, Department of Tropical Husbandry, P.O. Box 338, 6700 A.H. Wageningen, The Netherlands</P>
+<P ALIGN="JUSTIFY">M.A. Latif, Department of Poultry Science, Bangladesh Agricultural University, Mymensingh, Bangladesh</P>
+<P ALIGN="JUSTIFY">H. Martoyo, Faculty of Animal Science, Institut Pertanian Bogor, Jalan Raya Pajajaran, Bogor, West Java, Indonesia</P>
+<P ALIGN="JUSTIFY">K. Mitchell, Baptist Bible Institute, P.O. Box 301, Basseterre, St. Kitts, West Indies</P>
+<P ALIGN="JUSTIFY">E.T. Moran, Jr., Poultry Science Department, Auburn University, Auburn, Alabama 36849-4291, USA</P>
+<P ALIGN="JUSTIFY">S. Ochetim, School of Agriculture, University of the South Pacific, Alafua Campus, Apia, Western Samo</P>
+<P ALIGN="JUSTIFY">S. Parks, Route 1, Box 47-C, Brookshire, Texas 77423, USA (Araucanian chicken)</P>
+<P ALIGN="JUSTIFY">R.W. Phillips, The Representative, Apt.810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY">H.L. Polley, Programme DTveloppement Plateau Bateke, CBZO, B.P. 4728, Kinshasa 2, Zaire</P>
+<P ALIGN="JUSTIFY">A. Ramakrishman, Center for Advanced Studies in Poultry Science, Kerala Agricultural University, Mannuthy 680 651, Kerala, India</P>
+<P ALIGN="JUSTIFY">C.V. Reddy, Faculty of Veterinary Science, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad 500 030, India</P>
+<P ALIGN="JUSTIFY">E. Ross, Department of Animal Science, University of Hawaii, Honolulu, Hawaii 96822, USA</P>
+<P ALIGN="JUSTIFY">M.L. Scott, 16 Spruce Lane, Ithaca, New York 14850, USA</P>
+<P ALIGN="JUSTIFY">T.J. Sexton, Agricultural Research Service, U.S. Department of Agriculture, Beltsville Agricultural Research Center, Building 262, Beltsville, Maryland 20705, USA</P>
+<P ALIGN="JUSTIFY">R.G. Somes, Nutritional Sciences, Box U-17, University of Connecticut, Storrs, Connecticut 06268, USA</P>
+<P ALIGN="JUSTIFY">M. Sunde, Poultry Science Department, University of Wisconsin, Madison, Wisconsin 53706, USA</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duck</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R.E. Abdelsamie, Department of Biochemistry, Microbiology, and Nutrition, University of New England, Armidale, New South Wales 2351, Australia</P>
+<P ALIGN="JUSTIFY">S. Ahmed, Department of Poultry Science, Bangladesh Agricultural University, Mymensingh, Bangladesh</P>
+<P ALIGN="JUSTIFY">A. Bande, PATI, Popondetta Agricultural College, Box 131, Popondetta, Oro Province, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">R.S. Bird, Cherry Valley Farms Ltd., Rothwell, Lincoln LN7 6BR, UK</P>
+<P ALIGN="JUSTIFY">V.D. Bulbule, Central Duck Breeding Farm, Government of India, Hessaraghatta, Bangalore 560 088, India</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">K.M. Cheng, Avian Genetics Laboratory, Department of Animal Science, University of British Columbia, Vancouver, British Columbia V6T 2A2, Canada</P>
+<P ALIGN="JUSTIFY">W.F. Dean, Cornell University Duck Research Laboratory, P.O. Box 217, Eastport, New York 11941, USA</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Animal Science Department, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">P. Edwards, Agricultural and Food Engineering Division, Asian Institute of Technology, P.O. Box 2754, Bangkok 10501, Thailand</P>
+<P ALIGN="JUSTIFY">L. Fishelson, Department of Zoology, Tel Aviv University, Ramat-ave, Tel Aviv 69978, Israel</P>
+<P ALIGN="JUSTIFY">W.F. Floresca, Department of Animal Science and Veterinary Medicine, Visayas State College of Agriculture, Baybay, Leyte 7127, Philippines</P>
+<P ALIGN="JUSTIFY">H. Godoy, Ingeniero Agronomio, Simon Bolivar 2397, Santiago, Chile</P>
+<P ALIGN="JUSTIFY">P. Hardjosworo, Fakultas Peternakan, Institut Pertanian Bogor, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY">R. Henry, Cherry Valley Farms Limited, Divisional Offices, North Kelsey Moor, Lincoln LN7 6HH, UK</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">W.F. Hollander, Route 4, Box 168, Ames, lowa 5001O, USA</P>
+<P ALIGN="JUSTIFY">E. Hoffmann, Canning, Nova Scotia BOP IHO, Canada</P>
+<P ALIGN="JUSTIFY">C.H. Huang, Food and Fertilizer Technology Center for the Asian and Pacific Region, Fifth Floor, 14 Wenchow Street, Taipei, Taiwan</P>
+<P ALIGN="JUSTIFY">G. Ibanez H., Bolivar 451, Trujillo, Peru</P>
+<P ALIGN="JUSTIFY">Z. Jungkaro, Research Institute for Inland Fisheries, Jalan Sempur No. 1, Indonesia</P>
+<P ALIGN="JUSTIFY">G.A.R. Kamar, Animal Production Department, Faculty of Agriculture, Cairo University, Giza, Egypt</P>
+<P ALIGN="JUSTIFY">E.H. Ketelaars, Department of Tropical Husbandry, P.O. Box 338, 6700 A.H. Wageningen, The Netherlands</P>
+<P ALIGN="JUSTIFY">I.P. Kompiang, BaliPenelitianTernak, P.O. Box 123, Bogor 16001, WestJava, Indonesia</P>
+<P ALIGN="JUSTIFY">M.A. Latif, Department of Poultry Science, Bangladesh Agricultural University, Mymensingh, Bangladesh</P>
+<P ALIGN="JUSTIFY">H. Martoyo, Faculty of Animal Science, Institut Pertanian Bogor, Jalan Raya Pajajaran, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY">P. Mongin, Station de Recherches Avicoles, I.N.R.A., Nouzilly 37380 Monnaie, France</P>
+<P ALIGN="JUSTIFY">E.T. Moran, Jr., Poultry Science Department, Auburn University, Auburn, Alabama 36849-4291, USA</P>
+<P ALIGN="JUSTIFY">S. Ochetim, School of Agriculture, University of the South Pacific, Alafua Campus, Apia, Western Samoa</P>
+<P ALIGN="JUSTIFY">R.W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY">H. Pingel, Karl-Marx-Universitat, Sektion TV, Lehrstuhl Geflugel- und Pelztierzucht, 7010 Leipzig, Stephanstrasse 12, Germany </P>
+<P ALIGN="JUSTIFY">S. Poernomo, Research Institute for Veterinary Science, Jalan R.E. Martadinata 32, P.O. Box 52, Bogor, West Java, Indonesia</P>
+<P ALIGN="JUSTIFY">A. Ramakrishman, Center for Advanced Studies in Poultry Science' Kerala Agricultural University, Mannuthy 680 651, Kerala, India</P>
+<P ALIGN="JUSTIFY">B. Retailleau, Grimaud FrFres S.A., La CorbiFre, 49450 Roussay, France</P>
+<P ALIGN="JUSTIFY">T.S. Sandhu, Cornell University Duck Research Laboratory, P.O. Box 217, Eastport, New York 11941, USA</P>
+<P ALIGN="JUSTIFY">M.L. Scott, 16 Spruce Lane, Ithaca, New York 14850, USA</P>
+<P ALIGN="JUSTIFY">B.K. Shingari, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">C. Tai, Taiwan Livestock Research Institute, 112 Farm Road Shin-hua, Tainan, Taiwan 71210</P>
+<P ALIGN="JUSTIFY">B. Tangendjaja, Bali Penelitian Ternak, P.O. Box 123, Bogor 16001, Indonesia</P>
+<P ALIGN="JUSTIFY">Tian Fuh Shen, Department of Animal Husbandry, National Taiwan University, Taipei 10764, Taiwan</P>
+<P ALIGN="JUSTIFY">S.S. Tsai, Laboratory of Veterinary Pathology, National Pintung Institute of Agriculture, Pintung, Taiwan</P>
+<P ALIGN="JUSTIFY">A. Romero Villanueva, Centro Tropical de Capacitaci6n Agropecuaria y Forestal, Apartado Postal #4S, Macuspana 86700 Tabasco, Mexico</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY">Wildfowl Trust, Slimbridge, UK</P>
+<P ALIGN="JUSTIFY">Yeong Shue Woh, Malaysian Agricultural Research and Development Institute (MARDI), G.P.O. No. 12301, 50774 Kuala Lumpur, Malaysia</P>
+<P ALIGN="JUSTIFY">Cha Tak Yimp, Poultry and Swine Unit, Department of Veterinary Services, Jalan Mahameru, 50630 Kuala Lumpur, Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Geese</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many universities have a department of animal or poultry science that should know about the culture and management of these birds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. Bande, PATI, Popondetta Agricultural College, Box 131, Popondetta, Oro Province, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">F.D. Chesterley, 4502 Loomis Trail, Blaine, Washington 98230, USA</P>
+<P ALIGN="JUSTIFY">R.D. Crawford, Department of Animal and Poultry Science, University of Saskatchewan, Saskatoon, Saskatchewan S7N 0W0, Canada</P>
+<P ALIGN="JUSTIFY">N.l. Dim, Animal Science Department, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">S. Jackson, P.O. Box 3, Creenbank, Washington 98253, USA (weeder geese)</P>
+<P ALIGN="JUSTIFY">Liu Fuan, Department of Animal Husbandry and Veterinary Medicine, South China Agricultural University, Guangzhou, People's Republic of China</P>
+<P ALIGN="JUSTIFY">P. Mongin, Station de Recherches Avicoles, l.N.R.A., Nouzilly 37380, Monnaie, France</P>
+<P ALIGN="JUSTIFY">E. Ross, Department of Animal Science, University of Hawaii, Honolulu, Hawaii 96822, USA</P>
+<P ALIGN="JUSTIFY">B.K. Shingari, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">H.R. Wilson, Poultry Science Department, University of Florida, Gainesville, Florida 32611, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea Fowl</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.O. Aduku, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">American Guinea Club, c/o Angie Papp, 620 Payne Road, New Albany, Indiana 47150, USA</P>
+<P ALIGN="JUSTIFY">J.S.O. Ayeni, Kainji Lake Research Institute, P.M.B. 666, New Bussa, Kwara State, Nigeria</P>
+<P ALIGN="JUSTIFY">A. Ben-David, 5, Azar Street, Holon 58291, Israel</P>
+<P ALIGN="JUSTIFY">G.S. Brah, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">X. Colonna C., 14 Cotham Road, Bristol BS6 6DR, UK</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">R. Dumont, Ecole Nationale SupTrieure des Sciences Agronomiques AppliquTes, 26, boulevard Docteur Petitjean 21100 Dijon, France</P>
+<P ALIGN="JUSTIFY">R. Etches, Department of Animal and Poultry Science, University of Guelph, Guelph, Ontario NIG 2WI, Canada</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">A.F. Hutton, Garaina Farms, Scrubby Creek Road, Gympie MS: 115, Queensland 4570, Australia</P>
+<P ALIGN="JUSTIFY">D.N. Johnson, Natal Parks, Game and Fish Preservation Board, P.O. Box 661, Pietermaritzburg 3200, South Africa</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Food Science and Animal Industries, Alabama A&amp;:M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">W. Michie, Poultry Husbandry Division, North of Scotland College of Agriculture, Parkhead, Craibstone, Bucksburn, Aberdeen AB2 9SX, Scotland, UK</P>
+<P ALIGN="JUSTIFY">P. Mongin, Station de Recherches Avicoles, I.N.R.A., Nouzilly, 37380 Monnaie, France</P>
+<P ALIGN="JUSTIFY">S. Ochetim, School of Agriculture, University of the South Pacific, Alafua Campus, Apia, Western Samoa</P>
+<P ALIGN="JUSTIFY">A.N. Okaeme, Wildlife/Range Division, Kainji Lake Research Institute, P.M.B. 666, New Bussa, Kwara State, Nigeria</P>
+<P ALIGN="JUSTIFY">J.S. Sandhu, Poultry Breeder, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">B.K. Shingari, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">R.G. Somes, Nutritional Sciences, Box U-17, University of Connecticut, Storrs, Connecticut 06268, USA</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muscovy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R.E. Abdelsamie, Department of Biochemistry, Microbiology, and Nutrition, University of New England, Armidale, New South Wales 2351, Australia</P>
+<P ALIGN="JUSTIFY">G.P. Bilong, Department of Primary Industry, Monogastric Research Centre, P.O. Box 73, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">H. de Carville, Station de Recherches Avicoles, I.N.R.A., Centre de Tours, Nouzilly 37380, Monnaie, France</P>
+<P ALIGN="JUSTIFY">F.D. Chesterley, 4502 Loomis Trail, Blaine, Washington 98230, USA</P>
+<P ALIGN="JUSTIFY">X. Colonna C., 14 Cotham Road, Bristol BS6 6DR, UK</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Animal Science Department, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">R. Dumont, Ecole Nationale SupTrieure des Sciences Agronomiques AppliquTes, 26, boulevard Docteur Petitjean 21100 Dijon, France</P>
+<P ALIGN="JUSTIFY">G.R. Gerona, Department of Animal Science and Veterinary Medicine, Visayas State College of Agriculture, Baybay, Leyte, Philippines</P>
+<P ALIGN="JUSTIFY">Barry Glofcheskie, Department of Environmental Biology, University of Guelph, Guelph, Ontario NIG 2WI, Canada (fly control)</P>
+<P ALIGN="JUSTIFY">D. Holderread' P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">W.F. Hollander, Route 4, Box 168, Ames, Iowa 50010, USA</P>
+<P ALIGN="JUSTIFY">E. Hoffmann, Canning, Nova Scotia BOP IH0, Canada</P>
+<P ALIGN="JUSTIFY">C.H. Huang, Food and Fertilizer Technology Center for the Asian and Pacific Region, Fifth Floor, 14 Wenchow Street, Taipei, Taiwan (mule duck)</P>
+<P ALIGN="JUSTIFY">G.A.R. Kamar, Animal Production Department, Faculty of Agriculture, Cairo University, Giza, Egypt</P>
+<P ALIGN="JUSTIFY">W. Michie, Poultry Husbandry Division, North of Scotland College of Agriculture, Parkhead, Craibstone, Bucksburn, Aberdeen AB2 9SX, Scotland, UK</P>
+<P ALIGN="JUSTIFY">Donald E. Mock, Department of Extension Entomology, 239 Waters Hall, Kansas State University, Manhattan, Kansas 66506-4004, USA (fly control)</P>
+<P ALIGN="JUSTIFY">P. Mongin, Station de Recherches Avicoles, I.N.R.A., Nouzilly 37380 Monnaie, France</P>
+<P ALIGN="JUSTIFY">S. Ochetim, School of Agriculture, University of the South Pacific, Alafua Campus, Apia, Western Samoa</P>
+<P ALIGN="JUSTIFY">H. Pingel, Karl Marx Universitat, Sektion TV, Lehrstuhl Geflugel- und Pelztierzucht, 7010 Leipzig, Stephanstrasse 12, Germany</P>
+<P ALIGN="JUSTIFY">B. Retailleau, Grimaud FrFres S.A., La CorbiFre, 494S0 Roussay, France</P>
+<P ALIGN="JUSTIFY">I. Romboli, Le Quericole, Universita Delgi Studi di Pisa 56010 S. Piero A Grado, Italy</P>
+<P ALIGN="JUSTIFY">T.S. Sandhu, Cornell University Duck Research Laboratory, P.O. Box 217, Eastport, New York 11941, USA</P>
+<P ALIGN="JUSTIFY">G.A. Surgeoner, Department of Environmental Biology, University of Guelph, Guelph, Ontario NIG 2WI, Canada (fly control)</P>
+<P ALIGN="JUSTIFY">C. Tai, Taiwan Livestock Research Institute, 112 Farm Road Shin-hua. Tainan, Taiwan 71210</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigeon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.O. Aduku, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">D.O. Alonge, Meat Hygiene and Preservation Laboratory, Faculty of Veterinary Medicine, University of Ibadan, Ibadan, Nigeria</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">K.M. Cheng, Avian Genetics Laboratory, Department of Animal Science, University of British Columbia, Vancouver, British Columbia V6T 2A2, Canada</P>
+<P ALIGN="JUSTIFY">R. Dillinger, 3201 Huffman Boulevard, Rockford, Illinois 61103, USA</P>
+<P ALIGN="JUSTIFY">N.I. Dim, Animal Science Department, FacultyofAgriculture, AhmaduBello University, P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">R.O. Hawes, Department of Animal and Veterinary Sciences, University of Maine, Orono, Maine 04469, U.S.A.</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA (carrier pigeons) </P>
+<P ALIGN="JUSTIFY">W.F. Hollander, Route 4, Box 168, Ames, lowa 5001O, USA</P>
+<P ALIGN="JUSTIFY">M.A. Latif, Department of Poultry Science, Bangladesh Agricultural University, Mymensingh, Bangladesh</P>
+<P ALIGN="JUSTIFY">Y. Le HTnaff, Laboratoire de l'H(pital Avranches, Avranches, Cotentin, France (carrier pigeons)</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Food Science and Animal Industries, Alabama A&amp;M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">G.A.R. Kamar, Animal Production Department, Faculty of Agriculture, Cairo University, Giza, Egypt</P>
+<P ALIGN="JUSTIFY">W.J. Miller, Department of Genetics, Iowa State University, Ames, Iowa 50011, USA</P>
+<P ALIGN="JUSTIFY">G. Owen, 6520 Wiscasset Road, Bethesda, Maryland 20816, USA</P>
+<P ALIGN="JUSTIFY">G. Pena PTrez, Apartado Postal 23, La Nucia, Alicante, Spain</P>
+<P ALIGN="JUSTIFY">E. Ross, Department of Animal Science, University of Hawaii, Honolulu, Hawaii 96822, USA</P>
+<P ALIGN="JUSTIFY">M.D. Roush, Green Valley Squab Farm, 1348 Green Valley Road, Folsom, California 9563O, USA</P>
+<P ALIGN="JUSTIFY">T.S. Sandbu, Cornell University Duck Research Laboratory, P.O. Box 217, Eastport, New York 11941, USA</P>
+<P ALIGN="JUSTIFY">J.S. Sim, Department of Animal Science, University of Alberta, Edmonton, Alberta TOG 2P5, Canada</P>
+<P ALIGN="JUSTIFY">R.T. Wilson, Bartridge House, Umberleigh, North Devon EX37 9AS, UK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quail</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Many people raise Japanese quail. Probably the best way to locate a local source is to consult local pet stores, the county farm advisor's office, university faculty of agriculture, game-bird fanciers, and the like. Finding people with local research experience is usually most useful to beginners. Coturnix International, Inc., is a nonprofit organization with primary interests in promoting small domesticated food animal production for both youth training and improved nutrition. The use of coturnix (Japanese quail) for these purposes is already well established in a number of Michigan schools and in the Dominican Republic, with special emphasis on science projects, especially where nutritional inadequacies exist. The address is Coturnix International Inc., International Headquarters, 1111 Michigan Avenue, Box 250O, East Lansing, Michigan 48823, USA. Avian Sciences Department, University of California, Davis, California 95616, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines </P>
+<P ALIGN="JUSTIFY">K.M. Cheng, Avian Genetics Laboratory, Department of Animal Science, University of British Columbia, Vancouver, British Columbia V6T 2A2, Canada</P>
+<P ALIGN="JUSTIFY">D.E. Deppner, Trees for the Future, 11306 Estona Drive, Silver Spring, Maryland 20902, USA</P>
+<P ALIGN="JUSTIFY">D. Holderread, P.O. Box 492, Corvallis, Oregon 97339, USA</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Food</P>
+<P ALIGN="JUSTIFY">Science and Animal Industries, Alabama AOcM University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">H.L. Marks, Genetics Unit, Room 107 Livestock-Poultry Building, University of Georgia, Athens, Georgia 30602, USA</P>
+<P ALIGN="JUSTIFY">A. Marsh, Marsh Farms, 7171 Patterson Drive, Garden Grove, California 92641, USA</P>
+<P ALIGN="JUSTIFY">H. Martoyo, Faculty of Animal Science, Institut Pertanian Bogor, Jalan Raya Pajajaran, Bogor, West Java, Indonesia</P>
+<P ALIGN="JUSTIFY">Z. Abidin bin Mohd Noor, Department of Veterinary Services, Jalan Sultan Salahuddin, 50630 Kuala Lumpur, Malaysia (chicken-quail hybrids)</P>
+<P ALIGN="JUSTIFY">P.K. Pani, Indian Veterinary Research Institute, Izatnagar 243 122, Bareilly, Uttar Pradesh, India</P>
+<P ALIGN="JUSTIFY">H. Pingel, Karl Marx Universitat, Sektion TV, Lehrstuhl Geflugel- und Pelztierzucht, 7010 Leipzig, Stephanstrasse 12, Germany</P>
+<P ALIGN="JUSTIFY">D. Polin, Department of Animal Science, Michigan State University, East Lansing, Michigan 48824, USA</P>
+<P ALIGN="JUSTIFY">C.V. Reddy, Faculty of Veterinary Science, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad 500 030, India</P>
+<P ALIGN="JUSTIFY">Rodale Research Center, RD #1, Box 323, Kutztown, Pennsylvania 19530, USA</P>
+<P ALIGN="JUSTIFY">E. Ross, Department of Animal Science, University of Hawaii, Honolulu, Hawaii 96822, USA</P>
+<P ALIGN="JUSTIFY">B.K. Shingari, Department of Animal Science, Punjab Agricultural University, Ludhiana 141 006, India</P>
+<P ALIGN="JUSTIFY">R.G. Somes, Nutritional Sciences, Box U-17, University of Connecticut, Storrs, Connecticut 06268, USA</P>
+<P ALIGN="JUSTIFY">R. Tempest, Heifer Project International, P.O. Box 808, Little Rock, Arkansas 72203, USA</P>
+<P ALIGN="JUSTIFY">S. K. Varghese, Department of Animal Science, Michigan State University, East Lansing, Michigan 48824-1225, USA</P>
+<P ALIGN="JUSTIFY">N. Wakasugi, Laboratory of Animal Genetics, Nagoya University, Furo-cho, Chikusaku, Nagoya, Japan</P>
+<P ALIGN="JUSTIFY">H.R. Wilson, Poultry Science Department, Archer Road, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turkey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. Berruecos V. Muz, Facultad de Medicina Veterinaria y Zootecnia, Ciudad Universitaria, Mexico D.F., Mexico</P>
+<P ALIGN="JUSTIFY">R.D. Crawford, Department of Animaland Poultry Science, UniversityofSaskatchewan, Saskatoon, Canada</P>
+<P ALIGN="JUSTIFY">M. Cuca G., Institucion de Ensenanza e Investigacion en Ciencias Agricolas, Colegio de Postgraduados, Chapingo, Mexico</P>
+<P ALIGN="JUSTIFY">K.E. Nestor, Ohio Agricultural Research and Development Center, Ohio State University, Wooster, Ohio</P>
+<P ALIGN="JUSTIFY">H. Pingel, Karl-Marx-Universitat, Sektion TV, Lehrstuhl Geflugel- und Pelztierzucht, 7010 Leipzig, Stephanstrasse 12, Germany</P>
+<P ALIGN="JUSTIFY">M.L. Scott, 16 Spruce Lane, Ithaca, New York 14850, USA</P>
+<P ALIGN="JUSTIFY">H.J. Sexton, Agricultural Research Service, U.S. Department of Agriculture, Beltsville Agricultural Research Center, Building 262, Beltsville, Maryland 20705, USA</P>
+<P ALIGN="JUSTIFY">R.G. Somes, Nutritional Sciences. Box U-17, University of Connecticut, Storrs, Connecticut 06268, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential New Poultry</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.E. Duckett, P.O. Box 12378, 50776 Kuala Lumpur, Malaysia (barn owls)</P>
+<P ALIGN="JUSTIFY">W.R. Marion, Department of Wildlife and Range Science, University of Florida, Gainesville, Florida 32611, USA (chachalaca)</P>
+<P ALIGN="JUSTIFY">C. Smal, Wildlife Service, Sidmonton Place, Bray County, Wicklow, Ireland (barn owls) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RABBITS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic Rabbit</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.O. Aduku, Department of Animal Science, Faculty of Agriculture, Ahmadu Bello University,  P.M.B. 1044, Zaria, Nigeria</P>
+<P ALIGN="JUSTIFY">J. Baranga, Department of Zoology, Makerere University, P.O. Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">M. Baselga, Departamento de Ciencia Animal, Escuela TTcnica Superior de Ingenieros  Agronomos, Camino de Vera 14, 46022 Valencia, Spain</P>
+<P ALIGN="JUSTIFY">C. de Blas, Departamento Alimentacion Animal, Escuela TTcnica Superior de Ingenieros  Agronomos, Ciudad Universitaria, 28040 Madrid, Spain</P>
+<P ALIGN="JUSTIFY">J.A. Castell6, Real Escuela Oficial y Superior de Avicultura (REOSA), Calle Plana Parafso, s/n  Arenys de Mar, Barcelona, Spain</P>
+<P ALIGN="JUSTIFY">C.B. Chawan, International Small Livestock Research Center, Department of Food Science and  Animal Industries, Alabama A&amp;M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">P.R. Cheeke, Rabbit Research Center, Department of Animal Science, Oregon State University,  Corvallis, Oregon 97331, USA</P>
+<P ALIGN="JUSTIFY">S. Fekete, University of Veterinary Science, Department of Animal Nutrition, Budapest, Pf.2,  H-1400 Hungary</P>
+<P ALIGN="JUSTIFY">J. Fernandez C., Departamento de Ciencia Animal, Escuela TTcnica Superior de Ingenieros  Agronomos, Universidad PolitTcnica de Valencia, Camino de Vera, 14, 46022 Valencia, Spain</P>
+<P ALIGN="JUSTIFY">C. Cervera Fras, Departamento de Ciencia Animal, Universidad PolitTcnica de Valencia, Apartado  22012, Valencia, Spain</P>
+<P ALIGN="JUSTIFY">D.J. Harris, Pel-Freez Rabbit Meat, Inc., P.O. Box 68, Rogers, Arkansas 72756, USA</P>
+<P ALIGN="JUSTIFY">J.A.B. Hundleby, Ciskei Agricultural Corporation Ltd., P.O. Box 59, Bisho, Ciskei, South Africa</P>
+<P ALIGN="JUSTIFY">D.L. Huss, P.O. Box 426, Menard, Texas 76859, USA</P>
+<P ALIGN="JUSTIFY">R. de Jong, Department of Tropical Animal Production, Marykeweg 40, 6709 P.G. Wageningen,  The Netherlands</P>
+<P ALIGN="JUSTIFY">L.A. Kamwanja, Bunda College of Agriculture, University of Malawi, P.O. Box 219, Lilongwe,  Malawi</P>
+<P ALIGN="JUSTIFY">M. Leyun, Instituto TTcnico Gesti6n Porcino (ITGP), Seccion Conejos, Ctra. del Sadar, s/n 31006  Pamplona (Navarra), Spain</P>
+<P ALIGN="JUSTIFY">H. Loliger, Lisztstrasse 20, 3100 Celle, Germany</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Food Science and  Animal Industries, Alabama A&amp;M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">T.P.E. Makhambera, Bunda College of Agriculture, University of Malawi, P.O. Box 219, Lilongwe,  Malawi</P>
+<P ALIGN="JUSTIFY">J.I. McNitt, Center for Small Farm Research, Southern University, P.O. Box 11170, Baton Rouge,  Louisana 70813-1170, USA</P>
+<P ALIGN="JUSTIFY">M. Mgheni, Sokoine University of Agriculture, Animal Science and Production Department, P.O.  Box 3004, Morogoro, Tanzania</P>
+<P ALIGN="JUSTIFY">K. Mitchell, Baptist Bible Institute, P.O. Box 301, Basseterre, St. Kitts, West Indies</P>
+<P ALIGN="JUSTIFY">G.A. Norman, Tropical Products Institute, Culham, Abingdon, Oxfordshire OX14 3DA, UK</P>
+<P ALIGN="JUSTIFY">L.N. Odonker, P.O. Box 11, Tsito-Awudome, Volta Region, Ghana</P>
+<P ALIGN="JUSTIFY">O.C. Onwudike, Department of Animal Science, University of Ife, Ile-Ife, Nigeria  </P>
+<P ALIGN="JUSTIFY">G.G. Partridge, Rowett Research Institute, Bucksburn, Aberdeen AB2 9SB, Scotland, UK</P>
+<P ALIGN="JUSTIFY">N.M. Patton, Rabbit Research Center, Oregon State University, Corvallis, Oregon 97331, USA</P>
+<P ALIGN="JUSTIFY">M.J. Paya, Departamento de Microbiologia, Facultad de Veterinaria, Avenida Puerta de Hierro, Ciudad Universitaria, 28040 Madrid, Spain</P>
+<P ALIGN="JUSTIFY">T. PTrez, Departamento de Reproduccion Animal, Instituto Nacional de Investigaciones Agrarias (INIA), Avenida Puerta de Hierro, s/n, 28040 Madrid, Spain</P>
+<P ALIGN="JUSTIFY">H.L. Polley, Programme DTveloppement Plateau Bateke, CBZO, B.P. 4728, Kinshasa 2, Zaire</P>
+<P ALIGN="JUSTIFY">R. Ramchurn, School of Agriculture, University of Mauritius, RTduit, Mauritius</P>
+<P ALIGN="JUSTIFY">T.E. Reed, Box 98, Markle, Indiana 46770, USA</P>
+<P ALIGN="JUSTIFY">E. Respaldiza, Instituto Nacional de Investigaciones Agrarias (INIA), Departamento de Higiene y Sanidad Animal, Calle Embajadores, 68, 28012 Madrid, Spain</P>
+<P ALIGN="JUSTIFY">B. Retailleau, Grimaud FrFres S.A., La CorbiFre, 49450 Roussay, France</P>
+<P ALIGN="JUSTIFY">A. Rodriguez, Departamento Microbiologia e Inmunologia, Facultad de Veterinaria, Calle Miguel Servet, numero 117, 50013 Zaragoza, Spain</P>
+<P ALIGN="JUSTIFY">R. Rodriguez de L., "Conejos" Centro de Investigacion Cientifica del Estado de MTxico A.C., Camino a Huexotla No. 5, San Miguel Coatlinchan, 56170 Texcoco, Estado de MTxico, Mexico</P>
+<P ALIGN="JUSTIFY">W. Schlolaut, Hessen Institute for Animal Production, Neu-Ulrichstein, 6313 Homberg, West Germany</P>
+<P ALIGN="JUSTIFY">W.D. Semuguruka, Department of Veterinary Pathology, Faculty of Veterinary Medicine, Sokoine University of Agriculture, P.O. Box 3018, Chuo Kikuu Morogoro, Tanzania</P>
+<P ALIGN="JUSTIFY">I. Sierra, Departamento Produccion Animal, Facultad de Veterinaria, Calle Miguel Servet, numero 117, 50013 Zaragoza, Spain</P>
+<P ALIGN="JUSTIFY">R. Valls, Institut de Recerce i Tecnologia Agroalimentaria (IRTA), Torre Marimon, 08140 Caldes de Montbui, Barcelona, Spain</P>
+<P ALIGN="JUSTIFY">P. Zaragoza, Departamento de Genetica y Mejora, Facultad de Veterinaria, Calle Miguel Servet, numero 117, 50013 Zaragoza, Spain</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RODENTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agouti</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C.J.R. Alho, Departamento de Biologia Animal, Universidade de Brasilia, 70910 Brazilia, DF, Brazil</P>
+<P ALIGN="JUSTIFY">R.H. Baker, 302 North Strickland Street, Eagle Lake, Texas 77434-1841, USA</P>
+<P ALIGN="JUSTIFY">H. Bonilla Encizo, ICA Tibaitata, Apartado Aereo 151123, BogotG, Colombia</P>
+<P ALIGN="JUSTIFY">A.D. Cuaron O., Instituto de Historia Natural, Apartado Postal No. 6, Tuxtla Gutierrez, Chiapas 29000, Mexico</P>
+<P ALIGN="JUSTIFY">L.A. Deutsch, Parque Zoologico de Sao Paulo, SGo Paulo, Brazil</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratorie d'Ecologie, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">J.K. Frenkel, Department of Pathology, University of Kansas Medical Center, Kansas City, Kansas 66013, USA</P>
+<P ALIGN="JUSTIFY">A. Escajadillo, Gorgas Memorial Laboratory, P.O. Box 935, APO Miami, Florida 340020012, USA OR Avenida Justo Arosemena 34-30, Apartado 6991, Panama 5, Panama</P>
+<P ALIGN="JUSTIFY">W. Hallwachs, Department of Biology, University of Pennsylvania, Philadelphia, Pennsylvania 19104-6018, USA </P>
+<P ALIGN="JUSTIFY">G. Hislop, Wildlife Section, Forest Division, Ministry of Food Production, Port-ofSpain, Trinidad and Tobago</P>
+<P ALIGN="JUSTIFY">S. Ingrand, I.N.R.A., Campus agronomique, B.P. 709, 97387 Kourou Cedex, French Guiana</P>
+<P ALIGN="JUSTIFY">D.H. Janzen, Department of Biology, University of Pennsylvania, Philadelphia, Pennsylvania 19104, USA</P>
+<P ALIGN="JUSTIFY">D. Kleiman, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">A. Lavorenti, Animal Sciences Department, ESALQ Universidade de Sao Paulo, C.P. 9, Piracicaba, Sao Paulo 13.400, Brazil</P>
+<P ALIGN="JUSTIFY">D.A. Meritt, Jr., 2200 North Cannon Drive, Chicago, IHinois 60614, USA</P>
+<P ALIGN="JUSTIFY">J.R. de Alencar Moreira, EMBRAPA-CPATU, Agricultural Research Center of the Humid Tropics, Caixa Postal 48, BelTm, Para 66000, Brazil</P>
+<P ALIGN="JUSTIFY">C.Ma. Rojas G., CATIE, 7170 Turrialba, Costa Rica</P>
+<P ALIGN="JUSTIFY">G. Santos, Fundatao Parque Zoologico de Sao Paulo, Sao Paulo, Brazil</P>
+<P ALIGN="JUSTIFY">N. Smith, Department of Geography, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">N. Smythe, Smithsonian Tropical Research Institute, Box 2072, Balboa, Panama</P>
+<P ALIGN="JUSTIFY">O. Sousa, Department of Microbiology, Cinuad Universitaria "Dr Octavio MTndez Pereira," El Cangregio, Apartado Estafeta Universitaria, Panama City, Panama</P>
+<P ALIGN="JUSTIFY">A.B. Taber, Animal Behaviour Research Group, Department of Zoology, South Parks Road, Oxford OXI 3PS, UK</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">C.A. Woods, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capybara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C.J.R. Alho, Departamento de Biologia Animal, Universidade de Brasilia, 70910 Brasilia, DF, Brazil</P>
+<P ALIGN="JUSTIFY">K.P. Bland, Department of Veterinary Physiology, Royal (Dick) School of Veterinary Studies, Summerhall, Edinburgh EH9 IQH, Scotland, UK</P>
+<P ALIGN="JUSTIFY">H. Bonilla Encizo, ICA Tibaitata, Apartado Aereo 151123, Bogota, Colombia</P>
+<P ALIGN="JUSTIFY">P.R. Cheeke, Rabbit Research Center, Department of Animal Science, Oregon State University, Corvallis, Oregon 97331, USA</P>
+<P ALIGN="JUSTIFY">T.J. Cunha, P.O. Box R, LaVerne, California 91750, USA</P>
+<P ALIGN="JUSTIFY">J.F. Eisenberg, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">F. Golley, Institute of Ecology, University of Georgia, Athens, Georgia 30601, USA</P>
+<P ALIGN="JUSTIFY">E. Gonzalez-Jimenez, Facultad de Agronomia, Universidad Central de Venezuela, Maracay, Venezuela</P>
+<P ALIGN="JUSTIFY">H. Hemmer, Institute of Zoology, Johannes Gutenberg University, Anemonenweg 18, D-6500 Mainz-Ebersheim, Germany</P>
+<P ALIGN="JUSTIFY">J.A. Howarth, School of Veterinary Medicine, University of California, Davis, California 95616, USA</P>
+<P ALIGN="JUSTIFY">S. Ingrand, I.N.R.A., Campus agronomique, B.P. 709, 97387 Kourou Cedex, French Guiana</P>
+<P ALIGN="JUSTIFY">N. Konnerup, 74 North Sunrise Boulevard, Camano Island, Washington 98292, USA</P>
+<P ALIGN="JUSTIFY">J.E. Jackson, Terraza Turrado 80, 5730 Villa Mercedes, San Luis, Argentina</P>
+<P ALIGN="JUSTIFY">D. Kleiman, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">A. Lavorenti, Animal Sciences Department, ESALQ Universidade de Sao Paulo, C.P. 9, Piracicaba, Sao Paulo 13.400, Brazil </P>
+<P ALIGN="JUSTIFY">R.D. Lord, Biology Department, Indiana University of Pennsylvania, Indiana, Pennsylvania 15705, USA</P>
+<P ALIGN="JUSTIFY">D.W. MacDonald, Animal Behaviour Research Group, Department of Zoology, South Parks Road, Oxford OXI 3PS, UK</P>
+<P ALIGN="JUSTIFY">J.R. de Alencare Moreira, Agricultural Research Center of the Humid Tropics, EMBRAPA-CPATU, Caixa Postal 48" BelTm, Para 66000, Brazil</P>
+<P ALIGN="JUSTIFY">B. Muller-Haye, Food and Agricultural Organization of the United Nations, Room F524, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY">J. Ojasti, Institute of Tropical Zoology, Apartado 47058, Universidad Central de Venezuela, Caracas 1041A, Venezuela</P>
+<P ALIGN="JUSTIFY">N.L. Rondon, Departamento de Engenharia Florestal, Centro de Ciencias Agrarias, Universidada Federal de Mato Grosso, Cuiaba-MT, 78000, Brazil</P>
+<P ALIGN="JUSTIFY">N. Smith, Department of Geography, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">A.E. Sollod, Section of International Veterinary Medicine, Tufts University, 200 Westboro Road, North Grafton, Massachusetts 01536, USA</P>
+<P ALIGN="JUSTIFY">F. Sunquist, Route 1, Box 1434, Melrose, Florida 32666, USA</P>
+<P ALIGN="JUSTIFY">A.B. Taber, Animal Behaviour Research Group, Department of Zoology, South Parks Road, Oxford OXI 3PS, UK</P>
+<P ALIGN="JUSTIFY">K.D. Thelen, FAO Regional Of fice for Latin America and the Caribbean, CasiHa 10095, Santiago, Chile</P>
+<P ALIGN="JUSTIFY">D. Wharton, New York Zoological Society, Bronx, New York 10460, USA</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coypu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.C. Carmichael, The Museum, Michigan State University, East Lansing, Michigan 48824-1045, USA</P>
+<P ALIGN="JUSTIFY">G. Chapman, Utah State University, Logan, Utah 84322, USA</P>
+<P ALIGN="JUSTIFY">L. Contreras, Universidad Cat61ica de Valpariso, Avenida Brasi. 295O, Casilla 4059, Valparaiso, Chile</P>
+<P ALIGN="JUSTIFY">D. Huss, P.O. Box 426, Menard, Texas 76859, USA</P>
+<P ALIGN="JUSTIFY">H.-G. Klos, Zoologischer Garten Berlin, Aktiengesellschaft, Hardenbergplatz, 1000 Berlin 30, Germany</P>
+<P ALIGN="JUSTIFY">P. Lutz, Rosenstiel School of Marine and Atmospheric Science, Biology and Living Resources, University of Miami, 4600 Rickenbacker Causeway, Miami, Florida 33149, USA</P>
+<P ALIGN="JUSTIFY">J.R. de Alencar Moreira, Agricultural Research Center of the Humid Tropics, Caixa Postal 48, BelTm, ParG, 66000, Brazil</P>
+<P ALIGN="JUSTIFY">J. Szumiec, Experimental Fish Culture Station, Polish Academy of Sciences, Golysz 43-422 Chybie, Poland</P>
+<P ALIGN="JUSTIFY">C.A. Woods, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giant Rat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Research Institute, Council for Scientific and Industrial Research (CSIR), P.O. Box 20, Achimota, Chana</P>
+<P ALIGN="JUSTIFY">J. Baranga, Department of Zoology, Makerere University, P.O. Box 7062, Kampala, Uganda </P>
+<P ALIGN="JUSTIFY">K.P. Bland, Department of Veterinary Physiology, Royal (Dick) School of Veterinary Studies, Summerhall, Edinburgh EH9 IQH, Scotland, UK</P>
+<P ALIGN="JUSTIFY">P. Brinck, Ecology Building, Department of Animal Ecology, University of Lund, S223 62 Lund, Sweden</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratorie d'Ecologie, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">D. Fielding, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">D.C.D. Happold, Department of Zoology, Australian National University, Canberra, Australian Capital Territory 2601, Australia</P>
+<P ALIGN="JUSTIFY">J.C. Heymans, BP 1910, Cotonou, Benin</P>
+<P ALIGN="JUSTIFY">J.A. Kamara, c/o Njala University College, Private Mail Bag, Freetown, Sierra Leone</P>
+<P ALIGN="JUSTIFY">M.H. Knight, Kalahari Gemsbok Park, Private Bag X5890, Upington 8800, South Africa</P>
+<P ALIGN="JUSTIFY">M. Malekani, DTpartement de Biologie, FacultT des Sciences, UniversitT de Kinshasa, B.P. 190, Kinshasa XI, Zaire</P>
+<P ALIGN="JUSTIFY">R.W. Matthewman, Centre for Tropical Veterinary Medicine, Royal (Dick) School for Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">A.J. Smith, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grasscutter</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. Alexander, Department of Biology, Natal University, King George V Avenue, Durban 4001, South Africa</P>
+<P ALIGN="JUSTIFY">E.O.A. Asibey, Department of Game and Wildlife, Ministry Post Office, Accra, Ghana</P>
+<P ALIGN="JUSTIFY">E.S. Ayensu, African Development Bank, 01 B.P. No. 1837, Abidjan 01, Ivory Coast</P>
+<P ALIGN="JUSTIFY">R. Baptist, Institute for Animal Production in the Tropics and Subtropics, University of Hohenheim (480), P.O. Box 700562, D-7000 Stuttgart 70, Germany</P>
+<P ALIGN="JUSTIFY">S.Y. Bimpong-Buta, Council for Law Reporting, P.O. Box M165, Accra, Ghana</P>
+<P ALIGN="JUSTIFY">P. Brinck, Department of Animal Ecology, University of Lund, Ecology Building, S223 62, Lund, Sweden</P>
+<P ALIGN="JUSTIFY">H. Dosso, Institut d'Ecologie Tropicale, Abidjan, Ivory Coast</P>
+<P ALIGN="JUSTIFY">D. Fielding, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">D.C.D. Happold, Department of Zoology, Australian National University, Canberra, Australian Capital Territory 2601, Australia</P>
+<P ALIGN="JUSTIFY">J. Hardouin, Institut de Medicine Tropicale "Prince Leopold," Nationalestraat 155, B2000 Antwerp, Belgium</P>
+<P ALIGN="JUSTIFY">J.C. Heymans, BP 1910, Cotonou, Benin</P>
+<P ALIGN="JUSTIFY">A. Hutton, Garaina Farms, Scrubby Creek Road, Gympie MS:115, Queensland 4570, Australia</P>
+<P ALIGN="JUSTIFY">J.A. Kamara, c/o Njala University College, Private Mail Bag, Freetown, Sierra Leone</P>
+<P ALIGN="JUSTIFY">Laboratoire Centrale de Nutrition Animale (LACENA), B.P. 353, Abidjan 06, Ivory Coast</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Food Science and Animal Industries, Alabama A&amp;M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">R.-P. Mack, Projet BTnino-Allemand Conseiller Technique auprTs du MDRAC, BP 504, Cotonou, Benin </P>
+<P ALIGN="JUSTIFY">G.H.G. Martin, Department of Zoology, Kenyatta University College, P.O. Box 43844, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">R.W. Matthewman, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">G.A. Mensah, Responsable PBAA (Projet BTnino-Allemand d'Aulacodiculture), P.B. 2359, Cotonou, Benin</P>
+<P ALIGN="JUSTIFY">T.A. Omole, Department of Animal Science, University of Ife, Ile-lfe, Nigeria</P>
+<P ALIGN="JUSTIFY">K.J. Peters, International Livestock Centre for Africa (ILCA), P.O. Box 5689, Addis Ababa, Ethiopia</P>
+<P ALIGN="JUSTIFY">F. Petter, MammifFres et Oiseaux, Museum National d'Histoire Naturelle Zoologie, 55 rue de Buffon 75005, Paris, France</P>
+<P ALIGN="JUSTIFY">W. Schr(der, Institute of Animal Breeding, Albrecht-Thaer-Weg 1, 3400 Gottingen, Germany</P>
+<P ALIGN="JUSTIFY">A.J. Smith, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">D.W. Thomas, Department of Biology, University of Sherbrooke, Sherbrooke, Quebec JIK 2RI, Canada</P>
+<P ALIGN="JUSTIFY">St. von Korn, Institute of Animal Breeding, Albrecht-Thaer-Weg 1, 3400 G(ttingen, Germany</P>
+<P ALIGN="JUSTIFY">J. Walder, Presbyterian Rural Training Centre, P.O. Box 72, Bamenda, NW Province, Cameroon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G.P. Bilong, Department of Pimary Industry, Monogastric Research Centre, P.O. Box 73, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">K.P. Bland, Department of Physiology, Royal (Dick) School of Veterinary Studies, Summerhall, Edinburgh EH9 IQH, Scotland, UK</P>
+<P ALIGN="JUSTIFY">R. Bolton, Department of Anthropology, Pomona College, Claremont, California 91711, USA</P>
+<P ALIGN="JUSTIFY">H. Bonilla Encizo, ICA Tibaitata, Apartado Aereo 151123, Bogota, Colombia</P>
+<P ALIGN="JUSTIFY">J.K. Camoens, Asian Development Bank, P.O. Box 789, Manila 2800, Philippines</P>
+<P ALIGN="JUSTIFY">A. Del Carpio R., Facultad de Zootecnia, Universidad Nacional "Pedro Ruiz Gallo," Calle Atahualpa No. 179, Apartado 48, Lambayeque, Peru</P>
+<P ALIGN="JUSTIFY">P.R. Cheeke, Rabbit Research Center, Department of Animal Science, Oregon State University, Corvallis, Oregon 97331, USA</P>
+<P ALIGN="JUSTIFY">T.J. Cunha, P.O. Box R, LaVerne, California 91750, USA</P>
+<P ALIGN="JUSTIFY">J. Descailleux, Laboratorio GenTtica Humana, C.P. 11010, Lima 14, Peru</P>
+<P ALIGN="JUSTIFY">J.A. Ferguson, Overseas Development Administration, Eland House, Stug Place, London, UK</P>
+<P ALIGN="JUSTIFY">D. Fielding, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RC, Scotland, UK</P>
+<P ALIGN="JUSTIFY">J.K. Frenkel, Department of Pathology, University of Kansas Medical Center, Kansas City, Kansas 66013, USA</P>
+<P ALIGN="JUSTIFY">J. Hardouin, Institut de MTdecine Tropicale "Prince Leopold," Nationalestraat IS5, B2000 Antwerpen, Belgium</P>
+<P ALIGN="JUSTIFY">R.E. Honegger, Zurich Zoo, Zurichbergstrasse 221, CH-8044 Zurich, Switzerland </P>
+<P ALIGN="JUSTIFY">J. Howarth, School of Veterinary Medicine, University of Calffornia, Davis, Calffornia 95616, USA</P>
+<P ALIGN="JUSTIFY">D.L. Huss, P.O. Box 426, Menard, Texas 76859, USA</P>
+<P ALIGN="JUSTIFY">J.E. Jackson, Terraza Turrado 80, 5730 Villa Mercedes, San Luis, Argentina</P>
+<P ALIGN="JUSTIFY">C. Jenkins, PNG Institute Medical Research, P.O. Box 60, Goroka, Eastern Highlands Province, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">R. de Jong, Department of Tropical Animal Production, Marykeweg 40, 6709 PG Wageningen, The Netherlands</P>
+<P ALIGN="JUSTIFY">J.A. Kamara, c/o Njala University College, Private Mail Bag Freetown, Sierra Leone</P>
+<P ALIGN="JUSTIFY">P.J. Kohun, Department of Agriculture, PNG University of Technology, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">N.M. Konnerup, 74 North Sunrise Boulevard, Camano Island, Washington 98292, USA</P>
+<P ALIGN="JUSTIFY">T.E. Lacher, Jr., Huxley College of Environmental Studies, Western Washington University, Bellingham, Washington 98225, USA</P>
+<P ALIGN="JUSTIFY">S.D. Lukefahr, International Small Livestock Research Center, Department of Feed Science and Animal Industries, Alabama A&amp;M University, P.O. Box 264, Normal, Alabama 35762, USA</P>
+<P ALIGN="JUSTIFY">R.C. Malik, Department of Agriculture, PNG University of Technology, Lae, Papua New Guinea</P>
+<P ALIGN="JUSTIFY">R.W. Matthewman, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">A.R. Moreno, Departamento de Produccion Animal, Universidad Nacional Agraria, Apartado 456, La Molina, Lima, Peru</P>
+<P ALIGN="JUSTIFY">B. Muller-Haye, Food and Agriculture Organization of the United Nations, Room F524, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY">H.L. Polley, Programme DTveloppement Plateau Bateke, CBZO, B.P. 4728, Kinshasa 2, Zaire</P>
+<P ALIGN="JUSTIFY">V. Purizaga A., Alcalde del Concejo Provincial de Pacasmayo, Dos de Mayo 360, Peru</P>
+<P ALIGN="JUSTIFY">V.T. Quirante, Bureau of Animal Industry, Research Center, Alabang 3124, Metro Manila, Philippines</P>
+<P ALIGN="JUSTIFY">C.V. Reddy, Faculty of Veterinary Science, Andhra Pradesh Agricultural University, Rajendranagar, Hyderabad 500 030, India</P>
+<P ALIGN="JUSTIFY">O.W. Robinson, Department of Animal Science, North Carolina State University, Box 7621 Raleigh, North Carolina 27695-7621, USA</P>
+<P ALIGN="JUSTIFY">A.J. Smith, Centre for Tropical Veterinary Medicine, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Easter Bush, Roslin, Midlothian EH25 9RG, Scotland, UK</P>
+<P ALIGN="JUSTIFY">D. Wharton, New York Zoological Society, Bronx, New York 10460, USA</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hutia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.C. Allen, Hope Zoo, Kingston, Jamacia</P>
+<P ALIGN="JUSTIFY">R.S. Canet, Instituto de Zoologla, Academia Ciencias de Cuba, Calle 214, esq. a Avenida 19, No. 17A 09, Reparto Atabey, Havana 16, Cuba</P>
+<P ALIGN="JUSTIFY">D. Kleiman, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">K. Jordan, Department of Zoology, University of Florida, Gainesville, Florida 32611, USA </P>
+<P ALIGN="JUSTIFY">W.L.R. Oliver, Jersey Wildlife Preservation Trust, Les AugrFs Manor, Jersey, Channel Islands, UK</P>
+<P ALIGN="JUSTIFY">J.A. Ottenwalder, Parque Zool6gico Nacional (ZOODOM), Apartado 2449, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">C. Woods, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">L.T. Blankenship, Animal Resources Center, School of Medicine, East Carolina University, Greenville, North Carolina 27858-4354, USA</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratoire d'Ecologie, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">J.E. Jackson, Terraza Turrado 80, 5730 Villa Mercedes, San Luis, Agentina</P>
+<P ALIGN="JUSTIFY">D. Kleiman, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">D.W. MacDonald, Animal Behaviour Research Group, Department of Zoology, South Parks Road, Oxford OXI 3PS, UK</P>
+<P ALIGN="JUSTIFY">W.H. Pryor, Jr., School of Medicine, East Carolina University, Greenville, North Carolina 27858-4354, USA</P>
+<P ALIGN="JUSTIFY">A.B. Taber, Animal Behaviour Research Group, Department of Zoology, South Parks Road, Oxford OXI 3PS, UK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paca</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.R. de Alencar Moreira, Agricultural Research Center of the Humid Tropics, EMBRAPA-CPATU, Caixa Postal 48, BelTm, Para 66000, Brazil</P>
+<P ALIGN="JUSTIFY">C.J.R. Alho, Departamento de Biologia Animal, Universidade de Brasilia, 70910 Brasilia, DF, Brazil</P>
+<P ALIGN="JUSTIFY">R.H. Baker, 302 North Strickland Street, Eagle Lake, Texas 77434-1841, USA</P>
+<P ALIGN="JUSTIFY">A.D. Cuardn O., Instituto de Historia Natural, Apartado Postal No. 6, Tuxtla Gutierrez, Chiapas 29000, Mexico</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratoire d'Ecologie, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">L. de Escalante, Zool6gico Nacional, Direccion del Patrimonio Natural y Cultural, San Salvador, El Salvador</P>
+<P ALIGN="JUSTIFY">J.K. Frenkel, Department of Pathology, University of Kansas Medical Center, Kansas City, Kansas 66013, USA</P>
+<P ALIGN="JUSTIFY">W. Hallwachs, Ecology and Systematics, Corson Hall, Cornell University, Ithaca, New York 14853, USA</P>
+<P ALIGN="JUSTIFY">C. Hislop, Wildlife Section, Forest Division, Ministry of Food Production, Port-ofSpain, Trinidad and Tobago</P>
+<P ALIGN="JUSTIFY">D.H. Janzen, Department of Biology, University of Pennsylvania, Philadelphia, Pennsylvania 19104, USA</P>
+<P ALIGN="JUSTIFY">D. Kleiman, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">A. Lavorenti, Animal Sciences Department, ESALQ Universidade de Sao Paulo, C.P. 9, Piracicaba, Sao Paulo 13.400, Brazil</P>
+<P ALIGN="JUSTIFY">Y. Matamoros, Escuela de Medicina Veterinaria, Universidad Nacional, Apartado 86, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY">D. Meritt, Jr., 2200 North Cannon Drive, Chicago, Illinois 60614, USA</P>
+<P ALIGN="JUSTIFY">C.Ma. Rojas G., CATIE, 7170 Turrialba, Costa Rica </P>
+<P ALIGN="JUSTIFY">O. Rosado, Ministry of Industry and Natural Resources, Belmopan, Belize</P>
+<P ALIGN="JUSTIFY">N. Smith, Department of Geography, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">N. Smythe, Smithsonian Tropical Research Institute, Box 2072, Balboa, Panama</P>
+<P ALIGN="JUSTIFY">V. Solis, Union Internacional pare la Conservacion de la Naturaleza y de los Recursos Naturales, Oficina Regional pare Centro AmTrica, Apartado Postal 91-1009-FECOSA, San JosT, Costa Rica</P>
+<P ALIGN="JUSTIFY">S. VaidTs, Centro Universitario del Norte Carrera ZootTcnica, Coban, A.V., Ciudad Guatemala 16001, Guatemala</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vizcacha</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Bonilla Encizo, ICA Tibaitata, Apartado Aereo 151123, Bogota, Colombia</P>
+<P ALIGN="JUSTIFY">J.E. Jackson, Terraza Turrado 80, 5730 Villa Mercedes, San Luis, Argentina</P>
+<P ALIGN="JUSTIFY">E.L. Marmillon, Estancias del Conlara S.A., Casilla de Correo 451, 5800 Rio Cuarto, Argentina</P>
+<P ALIGN="JUSTIFY">K.D. Thelen, FAO Regional Office for Latin America and the Caribbean, Casilla 10095, Santiago, Chile</P>
+<P ALIGN="JUSTIFY">E. Wing, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Rodents</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">T.M. Butynski, Impenetrable Forest Conservation Project, Zoology Department, Makerere University, P.O. Box 7062, Kampala, Uganda (springhare)</P>
+<P ALIGN="JUSTIFY">T. Flannery, Australian Museum, 6-8 College Street, Sydney, New South Wales 2000, Australia (Solomon Island rodents)</P>
+<P ALIGN="JUSTIFY">Inter-African Bureau for Animal Resources, Maendeleo House, Monrovia Street, POB 30786, Nairobi, Kenya (springhare)</P>
+<P ALIGN="JUSTIFY">N. Jacobsen, Nature Conservation Division, Private Bag X209, Pretoria 0001, South Africa (springhare)</P>
+<P ALIGN="JUSTIFY">C.P. Kofron, Museum of Zoology, Louisiana State University, Baton Rouge, Louisiana 70893, USA (springhare)</P>
+<P ALIGN="JUSTIFY">T. Leary, Ministry of Natural Resources, Honiara, Solomon Islands (Solomon Island rodents)</P>
+<P ALIGN="JUSTIFY">C.A. McLaughlin, San Diego Zoo, San Diego 92112, California, USA (springhare)</P>
+<P ALIGN="JUSTIFY">R.P. Millar, Department of Chemical Pathology, Medical School, Observatory 7925, South Africa (springhare)</P>
+<P ALIGN="JUSTIFY">J.D. Skinner, Mammal Research Institute, University of Pretoria, Pretoria 0002, South Africa (springhare)</P>
+<P ALIGN="JUSTIFY">Southern African Wildlife Management Association, POB 413, Pretoria, South Africa ( s p ring hare )</P>
+<P ALIGN="JUSTIFY">L. Talbot, 6656 Chitton Court, McLean, Virginia 22101, USA (springhare)</P>
+<P ALIGN="JUSTIFY">M. Van der Merwe, University of Pretoria, Mammal Research Institute, Pretoria 0002, South Africa (springhare)</P>
+<P ALIGN="JUSTIFY">Wildlife Society of Zimbabwe, POB 3497, Harare, Zimbabwe (springhare) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DEER AND ANTELOPE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mouse Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.O. Caldecott, World Wildlife Fund Malaysia, 7 Jalan Ridgeway, 93200 Kuching, Sarawak, Malaysia</P>
+<P ALIGN="JUSTIFY">R. Chaplin, Burnhouse, Fountainhall, Galashiels, Selkirk TDI 2RX, UK</P>
+<P ALIGN="JUSTIFY">G.W.H. Davison, Zoology Department, Universiti Kebangsaan Malaysia, 43600 Bangi, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">P. Grubb, 35 Downhills Park Road, London N17 6PE, UK</P>
+<P ALIGN="JUSTIFY">Liu Ruiqing, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">M. MacNamara, Fauna Research, Inc., 11 Park Avenue, Ardsley, New York 10502, USA</P>
+<P ALIGN="JUSTIFY">I. Muul, Integrated Conservation Research, P.O. Box 920, Harpers Ferry, West Virginia 25425, USA</P>
+<P ALIGN="JUSTIFY">M. Nordin, Bureau of Research and Consultancy, University Kebangsaan Malaysia, Bangi, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY">S. Pathak, Department of Genetics, M.D. Anderson Hospital and Tumor Institute, Houston, Texas 77030, USA</P>
+<P ALIGN="JUSTIFY">C.T. Robbins, Wildlife Biology Program, Washington State University, Pullman, Washington 99164-4220, USA</P>
+<P ALIGN="JUSTIFY">K. Robin, Tierpark Dahlholzli Bern, Dalmaziquai 149, CH-3005 Bern, Switzerland</P>
+<P ALIGN="JUSTIFY">C.R. Schmidt, Zoological Garden, CH-8044 Zurich, Switzerland</P>
+<P ALIGN="JUSTIFY">R.A. Sirimanne, Singapore Zooological Gardens, 80 Mandai Lake Road, Singapore 2572</P>
+<P ALIGN="JUSTIFY">L. Talbot, 6656 Chilton Court, McLean, Virginia 22101, USA</P>
+<P ALIGN="JUSTIFY">M.K. Vidyadaran, Faculty of Veterinary Science, Department of Animal Science, Universiti Pertanian Malaysia, Serdang 43400, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY">Wang Yingxiang, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">D. Wharton, New York Zoological Society, Bronx, New York 10460, USA</P>
+<P ALIGN="JUSTIFY">G.C. Whittow, Department of Physiology, John A. Burns School of Medicine, University of Hawaii, 1960 East West Road, Honolulu, Hawaii 96822, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Muntjac</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. Barrette, DTpartement de Biologie, FacultT des Sciences et de GTnie, UniversitT Laval, QuTbec, GIK 7P4, Canada</P>
+<P ALIGN="JUSTIFY">K. Benirschke, 8457 Prestwick Drive, La Jolla, California 92037, USA</P>
+<P ALIGN="JUSTIFY">The British Deer Society, Church Farm, Lower Basildon, Reading, Berkshire RG8 9NH, UK</P>
+<P ALIGN="JUSTIFY">J.O. Caldecott, World Wildlife Fund Malaysia, 7 Jalan Ridgeway, 933200 Kuching, Sarawak, Malaysia</P>
+<P ALIGN="JUSTIFY">N. Chapman, Larkmead, Barton Mills, Bury St. Edmunds, Suffolk IP28 6AA, UK</P>
+<P ALIGN="JUSTIFY">M. Coe, Department of Zoology, University of Oxford, South Parks Road, Oxford OXI 3PS, UK </P>
+<P ALIGN="JUSTIFY">O. Dansie, The Chapel, 2 Hobbs Hall, Welwyn, Hertsfordshire, UK</P>
+<P ALIGN="JUSTIFY">S.K. Dhungal, Department of Parks and Wildlffe, P.O. Box 860, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY">C. Dubost, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">R.J. Goss, Division of Biology and Medicine, Brown University, Providence, Rhode Island 02912, USA</P>
+<P ALIGN="JUSTIFY">C.P. Groves, Department of Prehistory and Anthropology, Australian National University, P.O. Box 4, Canberra, Australian Capital Territory 2600, Australia</P>
+<P ALIGN="JUSTIFY">P. Grubb, 35 Downhills Park Road, London N17 6PE, UK</P>
+<P ALIGN="JUSTIFY">S.P. Harding, Animal Ecology Research Group, Zoology Department, South Parks Road, Oxford OX1 3PS, UK</P>
+<P ALIGN="JUSTIFY">S. Harris, Department of Zoology, University of Bristol, Woodland Road, Bristol BS8 JUG, UK</P>
+<P ALIGN="JUSTIFY">H. Heck, CatskiH Game Farm, Inc., RD #1, Box 133, Catskill, New York 12414, USA</P>
+<P ALIGN="JUSTIFY">H.A. Jacobson, Fish and Wildlffe Department, Mississippi State University, Mississippi State, Mississippi 39762, USA</P>
+<P ALIGN="JUSTIFY">Liu Ruiqing, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Lu Houji, Department of Biology, East China Normal University, Shanghai 200062, People's Republic of China</P>
+<P ALIGN="JUSTIFY">M. MacNamara, Fauna Research, Inc., 11 Park Avenue, Ardsley, New York 10502, USA</P>
+<P ALIGN="JUSTIFY">V.J.A. Manton, Zoological Society of London, Whipsnade Park, Dunstable, Bedfordshire LU6 2LF, UK</P>
+<P ALIGN="JUSTIFY">S. Miura, Department of Biology, Hyogo College of Medicine, Mukogawa-cho 1-1, Nishinomiya, Hyogo-ken 663, Japan</P>
+<P ALIGN="JUSTIFY">I. Muul, Integrated Conservation Research, P.O. Box 920, Harpers Ferry, West Virginia 25425, USA</P>
+<P ALIGN="JUSTIFY">S. Pathak, Department of Genetics, M.D. Anderson Hospital and Tumor Institute, Houston, Texas 77030, USA</P>
+<P ALIGN="JUSTIFY">C.T. Robbins, Wildlife Biology Program, Washington State University, Pullman, Washington 99164, USA</P>
+<P ALIGN="JUSTIFY">B. Seidel, Tierpark Berlin, Tierklinik, DDR-1136 Berlin, Friedrichsfelde, Germany</P>
+<P ALIGN="JUSTIFY">Shi Liming, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">H. Soma, Department of Obstetrics and Gynecology, Tokyo Medical College Hospital, 1-7, Nishishinjuku 6, Shinjuku-ku, Tokyo 160, Japan</P>
+<P ALIGN="JUSTIFY">S. Stadler, Fakultat fur Biologie, Universitat Bielefeld, 4800 Bielefeld, Universitatsstrasse 25, Germany</P>
+<P ALIGN="JUSTIFY">L. Talbot, 6656 Chilton Court, McLean, Virginia 22101, USA</P>
+<P ALIGN="JUSTIFY">P.F. Taylor, Taylor Energy Company, The 2-3-4 Loyola Building, New Orleans, Louisiana 70112, USA</P>
+<P ALIGN="JUSTIFY">Wang Yingziang, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">C. Wemmer, Conservation and Research Center, National Zoological Park, Front Royal, Virginia 22630, USA</P>
+<P ALIGN="JUSTIFY">D. Wharton, New York Zoological Society, Bronx, New York 10460, USA</P>
+<P ALIGN="JUSTIFY">D.M. Wurster-HiH, Department of Pathology, Dartmouth Medical School, Hanover, New Hampshire 03755, USA</P>
+<P ALIGN="JUSTIFY">R.H. Yahner, 320 Forest Resources Laboratory, Pennsylvania State University, University Park, Pennsylvania 16802, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Musk Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. Chaplin, Burnhouse, Fountainhall, Galashiels, Selkirk TDI 2RX, UK</P>
+<P ALIGN="JUSTIFY">S.K. Dhungel, Department of Parks and Wildlife, P.O. Box 860, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY">A.J. Gaston, Canadian Wildlife Service, Ottawa KIA OE7, Canada</P>
+<P ALIGN="JUSTIFY">C.P. Groves, Department of Prehistory and Anthropology, Australian National University, P.O. Box 4, Canberra, Australian Capital Territory 2600, Australia</P>
+<P ALIGN="JUSTIFY">M.J.B. Green, IUCN Conservation Monitoring Centre, 219C Huntingdon Road, Carnbridge CB3 ODL, UK</P>
+<P ALIGN="JUSTIFY">P. Grubb, 35 Downhills Park Road, London N17 6PE, UK</P>
+<P ALIGN="JUSTIFY">M.L. Hunter, Jr., Wildlife Department, University of Maine, Orono, Maine 04469, USA</P>
+<P ALIGN="JUSTIFY">H.A. Jacobson, Fish and Wildlife Department, Mississippi State University, Mississippi State, Mississippi 39762, USA</P>
+<P ALIGN="JUSTIFY">B. Kattel, P.O. Box 3070, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY">Liu Riqing, Kunming Institute of Zoology, Academia Sinica, Kunming Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Lu Houji, Department of Biology, East China Normal University, Shanghai 200062, People's Republic of China</P>
+<P ALIGN="JUSTIFY">J. McNeely, Program and Policy Division, International Union for Conservation of Nature and Natural Resources, Avenue du Mont-Blanc, CH1196 Gland, Switzerland</P>
+<P ALIGN="JUSTIFY">B.W. O'Gara, Montana Cooperative Wildlife Research Unit, University of Montana, Missoula, Montana 59812, USA</P>
+<P ALIGN="JUSTIFY">C.T. Robbins, Wildlife Biology Program, Washington State University, Pullman, Washington 99164-4220, USA</P>
+<P ALIGN="JUSTIFY">B. Seidel, Tierpark Berlin, Tierklinik, DDR-1136 Berlin, Friedrichsfelde, Germany</P>
+<P ALIGN="JUSTIFY">Shi Liming, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">P.F. Taylor, Taylor Energy Co., The 2-3-4 Loyola Building, New Orleans, Louisiana 70112, USA</P>
+<P ALIGN="JUSTIFY">Wang Yingxiang, Kunming Institute of Zoology, Academia Sinica, Kunming, Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water Deer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. Cooke, Nature Conservancy Council, Northminster House, Peterborough PEI I UA, UK</P>
+<P ALIGN="JUSTIFY">L. Farrell, Nature Conservancy Council, Northminster House, Peterborough PEI IUA, UK</P>
+<P ALIGN="JUSTIFY">F. Feer, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">P. Crubb, 35 Downhills Park Road, London N17 6PE, UK</P>
+<P ALIGN="JUSTIFY">Liu Riuqing, Kunming Institute of Zoology, Academia Sinica. Kunming Yunnan Province, People's Republic of China</P>
+<P ALIGN="JUSTIFY">Lu Houji, Department of Biology, East China Normal University, Shanghai 200062, People's Republic of China</P>
+<P ALIGN="JUSTIFY">V.J.A. Manton, Zoological Society of London, Whipsnade Park, Dunstable, Bedfordshire LU6 2LF, UK</P>
+<P ALIGN="JUSTIFY">B. Seidel, Tierpark Berlin, Tierklinik DDR-1136, Berlin, Friedrichsfelde, Germany</P>
+<P ALIGN="JUSTIFY">R Smith, Department of Zoology, Whiteknights Park, University of Reading, Reading, Berkshire RG6 2AH, UK</P>
+<P ALIGN="JUSTIFY">S. Stadler, Fakultat fur Biologie, Universitat Bielefeld, 4800 Bielefeld, Universitats strasse 25, Germany</P>
+<P ALIGN="JUSTIFY">P.F. Taylor, Taylor Energy Company, The 2-3-4 Loyola Building, New Orleans, Louisiana 70112, USA</P>
+<P ALIGN="JUSTIFY">C. Wemmer, Conservation and Research Center, National Zoological Park, Front Royal, VA 2263O, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South American Microdeer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. Sampath, Trinidad and Tobago Wildlffe Breeders and Farmers Association, c/o 5 3/4 Mile Mark, Penal Rock Road, Penal, Trinidad, West Indies (red brocket)</P>
+<P ALIGN="JUSTIFY">M. MacNamara, Fauna Research, Inc., 11 Park Avenue, Ardsley, New York 10502, USA (pudu)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duikers</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. Baranga, Department of Zoology, Makerere University, P.O. Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">B. Chardonnet, Projet Petits Ruminants, B.P. 65, Atakpame, Togo</P>
+<P ALIGN="JUSTIFY">R.L. Cowan, 324 Henning Building, Pennsylvania State University, University Park, Pennsylvania 16802, USA</P>
+<P ALIGN="JUSTIFY">G. Dubost, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">RI.M. Dunbar, Department of Zoology, University of Liverpool, P.O. Box 147, Liverpool L69 3BX, UK</P>
+<P ALIGN="JUSTIFY">F. Feer, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">K.R. Kranz, Zoological Society of Philadelphia, 34th Street and Girard Avenue, Philadelphia, Pennsylvania 19104, USA</P>
+<P ALIGN="JUSTIFY">S. Lumpkin, Department of Zoological Research, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">I. Player, Wilderness Leadership School, P.O. Box 15036, BeHair 4006, Natal, South Africa</P>
+<P ALIGN="JUSTIFY">K. Pond, Department of Animal Science, North Carolina State University, Box 7621, Raleigh, North Carolina 27695, USA</P>
+<P ALIGN="JUSTIFY">S. Schweers, Bahnhofstrasse 29, D-6744 Kandee, Germany</P>
+<P ALIGN="JUSTIFY">J.D. Skinner, Mammal Research Institute, University of Pretoria, Pretoria 0002, South Africa</P>
+<P ALIGN="JUSTIFY">A.E. SoHod, International Veterinary Medicine, Tufis University, 200 Westboro Road, North Grafion, Massachusetts 01536, USA</P>
+<P ALIGN="JUSTIFY">L. Talbot, 6656 Chilton Court, McLean, Virginia 22101, USA</P>
+<P ALIGN="JUSTIFY">C.C. Udell, 14934 VaHey Vista Blouvard, Sherman Oaks, Calffornia 91403, USA</P>
+<P ALIGN="JUSTIFY">G.A. Varga, Department of Dairy and Animal Science, 225B Borland Laboratory, Pennsylvania State University, University Park, Pennsylvania 16802, USA</P>
+<P ALIGN="JUSTIFY">V.J. Wilson, Duiker Research and Breeding Centre, Chipangali Wildlife Trust, P.O. Box 1057, Bulawayo, Zimbabwe </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Small Antelope</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">L. Asibey, Department of Game and Wildlife, Ministry Post Office, Accra, Ghana</P>
+<P ALIGN="JUSTIFY">J. Baranga, Department of Zoology, Makerere University, P.O. Box 7062, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">J.I. Boshe, College of African Wildlife Management, Mweka, P.O. Box 3031, Moshi, Tanzania (dikdik)</P>
+<P ALIGN="JUSTIFY">B. Chardonnet, Project Petits Ruminants, BP 65, Atakpame, Togo (oribi)</P>
+<P ALIGN="JUSTIFY">S.K. Dhungel, Department of National Parks and Wildife, Conservation, Babar Mahal, Kathmandu, Nepal (four-horned antelope)</P>
+<P ALIGN="JUSTIFY">R.I.M. Dunbar, Department of Zoology, University of Liverpool, P.O. Box 147, Liverpool L69 3BX, UK (dikdik, klipspringer)</P>
+<P ALIGN="JUSTIFY">F. Feer, Laboratoire d'Ecologie GTnTrale, 4 avenue Petit ChGteau, 91800 Brunoy, France</P>
+<P ALIGN="JUSTIFY">A.M. Goebel, Department of Biology, University of Texas at Arlington, Arlington, Texas 76019, USA</P>
+<P ALIGN="JUSTIFY">P.P. Hoppe, Am Hauenstein 13, 6706 Wachenheim, Germany (dikdik, suni)</P>
+<P ALIGN="JUSTIFY">K.R. Kranz, Zoological Society of Philadelphia, 34th Street and Girard Avenue, Philadelphia, Pennsylvania 19104, USA (royal antelope, beira, dikdik, klipspringer, suni, four-horned antelope)</P>
+<P ALIGN="JUSTIFY">I. Player, Wilderness Leadership School, P.O. Box 15036, Bellair 4006, Natal, South Africa</P>
+<P ALIGN="JUSTIFY">E.N.W. Oppong, UNDP/FGN/FAO Livestock Project, P.O. Box 6603, Jos, Plateau State, Nigeria</P>
+<P ALIGN="JUSTIFY">W.R. Pritchard, School of Veterinary Medicine, University of California, Davis, California 95616, USA</P>
+<P ALIGN="JUSTIFY">J. Skinner, Mammal Research Institute, University of Pretoria, Pretoria 0002, South Africa (otibi, steinbok)</P>
+<P ALIGN="JUSTIFY">A.E. Sollod, International Veterinary Medicine, Tufts University, 200 Westboro Road, North Grafton, Massachusetts 01536, USA (dikdik, klipspringer)</P>
+<P ALIGN="JUSTIFY">L. Talbot, 6656 Chilton Court, McLean, Virginia 22101, USA (dikdik, klipspringer, four-horned antelope)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LIZARDS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Green Iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">K. Benirschke, 8457 Prestwick Drive, La Jolla, California 92037, USA</P>
+<P ALIGN="JUSTIFY">G.M. Burghardt, Department of Psychology, University of Tennessee, Knoxville, Tennessee 37996, USA</P>
+<P ALIGN="JUSTIFY">A. Ferreira, Parque Zoologico Nacional, Apartado 2449, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">H.S. Fitch, Route #3, Box 142, Lawrence, Kansas 66044, USA</P>
+<P ALIGN="JUSTIFY">G. Hemley, World Wildlife Fund, 1255 23rd Street, N.W., Washington, D.C. 20037, USA (for trade information)</P>
+<P ALIGN="JUSTIFY">R.W. Henderson, Milwaukee Public Museum, 800 West Wells Street, Milwaukee, Wisconsin 53233 USA</P>
+<P ALIGN="JUSTIFY">J. Higginson, Voluntaria del Cuerpo de Paz, #156 6a Avenida 1-46, Zona 2 Guatemala, Guatemala</P>
+<P ALIGN="JUSTIFY">J.B. Iverson, Department of Biology, Earlham College, Richmond, Indiana 47374, USA S.R. Kellert, School of Forestry and Environmental Studies, Yale University, 205 Prospect Street, New Haven, Connecticut 06511, USA</P>
+<P ALIGN="JUSTIFY">F.W. King, Florida State Museum, University of Florida, Gainesville, Florida 32601, USA</P>
+<P ALIGN="JUSTIFY">G. Larde, Ministerio de Agricultura y Ganaderia Planes de Renderos, Km. 10 Col. Los Angeles 13, CP 01196 San Salvador, El Salvador</P>
+<P ALIGN="JUSTIFY">D. Marcellini, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">J.M. Mora, 200 m sur Pulperia la Uni6n, Cinco Esquinas, Carrieal, Alajuela, Costa Rica</P>
+<P ALIGN="JUSTIFY">J.A. Ottenwalder, Parque Zool6gico Nacional, Apartado 2449, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">G.C. Packard, Department of Zoology, Colorado State University, Fort Collins, Colorado 80523, USA</P>
+<P ALIGN="JUSTIFY">J.J. Perez, Condominio Su. Antonio 7, C. San Antonio Abad, San Salvador, El Salvador</P>
+<P ALIGN="JUSTIFY">J. Phillips, Research Department, San Diego Zoo, Box 551, San Diego, Calffornia 92112, USA</P>
+<P ALIGN="JUSTIFY">D. Werner, Fundacion Pro Iguana Verde, Apa,-tado 1501-3000, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black Iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H.S. Fitch, Route #3, Box 142, Lawrence, Kansas 66044, USA</P>
+<P ALIGN="JUSTIFY">R.W. Henderson, Milwaukee Public Museum, 800 West Wells Street, Milwaukee, Wisconsin 53233, USA</P>
+<P ALIGN="JUSTIFY">J. Higginson, Voluntaria del Cuerpo de Paz, #156 6a Avenida 1-46, Zona 2 Guatemala, Guatemala</P>
+<P ALIGN="JUSTIFY">D.M. Hillis, Department of Biology, University of Miami, Coral Gables, Florida 33124, USA</P>
+<P ALIGN="JUSTIFY">G. Larde, Ministerio de Agricultura y Ganaderia, Planes de Renderos Km. 10 Col. Los Angeles 13, CP 01196, San Salvador, El Salvador</P>
+<P ALIGN="JUSTIFY">D. Marcellini, National Zoologica, Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">J.M. Mora, 200 m sur Pulperita La Union, Cinco Esquinas, Carrieal, Alajuela, Costa Rica</P>
+<P ALIGN="JUSTIFY">G.C. Packard, Department of Zoology, Colorado State University, Fort Collins, Colorado 80523, USA</P>
+<P ALIGN="JUSTIFY">J.J. Perez, Condominio Su. Antonio 7, C. San Antonio Abad, San Salvador, El Salvador</P>
+<P ALIGN="JUSTIFY">J. Phillips, Research Department, San Diego Zoo, Box 551, San Diego, Calffornia 92112, USA</P>
+<P ALIGN="JUSTIFY">D. Werner, Fundacion Pro Iguana Verde, Apartado 1501-3000, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rock Iguana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. Auffenberg, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">D. Auth, Florida State Museum, University of Florida, Gainesville, Florida 32611, USA</P>
+<P ALIGN="JUSTIFY">T.J. Cullen, Cullen Vivarium, 3401 South 16th Street, Milwaukee, Wisconsin 53215 USA</P>
+<P ALIGN="JUSTIFY">A. Ferreira, Parque Zool6gico Nacional, Apartado 2449, Santo Domingo, Dominican Republic </P>
+<P ALIGN="JUSTIFY">R.W. Henderson, Mi]waukee Public Museum, 800 West Wells Street, Milwaukee, Wisconsin 53233, USA</P>
+<P ALIGN="JUSTIFY">J.B. Iverson, Department of Biology, Earlham College, Richmond, Indiana 47374, USA</P>
+<P ALIGN="JUSTIFY">J.A. Ottenwalder, Parque Zool6gico Nacional, Apartado 2449, Santo Domingo, Dominican Republic</P>
+<P ALIGN="JUSTIFY">T.A. Wiewandt, Wild Horizons, Inc., P.O. Box 5118, Tucson, Arizona 85703, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tegu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C.A. Blanco, Direccion Nacional de Fauna Silvestre, Avenida Paseo Colon 922 2&Yacute;piso, (1063) Buenos Aires, Argentina</P>
+<P ALIGN="JUSTIFY">O.K. Donadio, Museo Argentino de Ciencias Naturales, CC 220, Avenida Angel Gallardo 470, Suc. 5, 1405 Buenos Aires, Argentina</P>
+<P ALIGN="JUSTIFY">J.M. Gallardo, Museo Argentino de Ciencias Naturales, CC 220, Avenida Angel Gallardo 470, Suc. 5, 1405 Buenos Aires, Argentina</P>
+<P ALIGN="JUSTIFY">G. Hemley, World Wildlife Fund, 1255 23rd Street, N.W., Washington, D.C. 20037, USA</P>
+<P ALIGN="JUSTIFY">D. Marcellini, National Zoological Park, Washington, D.C. 20008, USA</P>
+<P ALIGN="JUSTIFY">E.L. Marmillon, Casilla de Correo 451, 5800 Rio Cuarto, Argentina</P>
+<P ALIGN="JUSTIFY">G.C. Packard, Department of Zoology, Colorado State University, Fort Collins, Colorado 80523, USA</P>
+<P ALIGN="JUSTIFY">D. Werner, Fundacion Pro Iguana Verde, Apartado 1501-3000, Heredia, Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEES</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Local Agriculture Extension Services and beekeepers are often the best source of information for beginning beekeeping. In addition, the following organizations can provide information: International Bee Research Association, 16/18 North Road, Cardiff CF1 3DY, UK; International Agency for Apiculture Development, 6N 909 Roosevelt, St. Charles, Illinois 60174, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. Abt, Centre for International Agricultural Development Cooperation, Tel Aviv, Israel M. Adey. International Bee Research Association, 16/18 North Road, Cardiff CFI 3DY, UK</P>
+<P ALIGN="JUSTIFY">S.O. Adjare, Technology Consultancy Centre, University of Science and Technology, Kumasi, Ghana</P>
+<P ALIGN="JUSTIFY">All India Beekeepers' Association, 817 Sadashiv Peth, Poono 411 030, India</P>
+<P ALIGN="JUSTIFY">S.K.N. Atuahene, Forest Product Research Institute (Ghana Forestry Commission), University P.O. Box 63, Kumasi, Ghana</P>
+<P ALIGN="JUSTIFY">H.S. Brar, Department of Entomology, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">N. Bradbear, International Bee Research Association, North Road, Cardiff CFI 3DY, UK</P>
+<P ALIGN="JUSTIFY">D.M. Caron, Department of Entomology and Applied Ecology, University of Delaware, Newark, Delaware 19717, USA</P>
+<P ALIGN="JUSTIFY">B.S. Chahal, Department of Entomology, Punjab Agricultural University, Ludhiana 141 004, India</P>
+<P ALIGN="JUSTIFY">B. Clauss, Beekeeping Survey, Kabompo, Zambia </P>
+<P ALIGN="JUSTIFY">M.P. Coleman, International Agency for Apiculture Development, 6N 909 Roosevelt, St. Charles, Illinois 60174, USA</P>
+<P ALIGN="JUSTIFY">Director, or Resident Bee Specialist, Apiary Studies, Zoological Institute, Leningrad, USSR</P>
+<P ALIGN="JUSTIFY">D. DeJong, Departamento de Genetica, Faculdade de Medicina de Ribeirao Preto, Universidade Sao Paulo, 14.049Ribeirao Preto, Sao Paulo, Brazil</P>
+<P ALIGN="JUSTIFY">R.W. Dutton, Centre for Overseas Research and Development (CORD), University of Durham, South Road, Durham DHI 3LE, UK (Apisflorea) </P>
+<P ALIGN="JUSTIFY">E.H. Erickson, Carl Hayden Bee Research Center, Agricultural Research Service, U.S. Department of Agriculture, 2000 East Allen Road, Tucson, Arizona 85719, USA</P>
+<P ALIGN="JUSTIFY">Faculdade de Medicina de Ribeirao Preto, Departamento de GenTtica, 14100Ribeirao Preto, Sao Paulo, Brazil</P>
+<P ALIGN="JUSTIFY">R.D. Fell, Virginia Polytechnic Institute, Blacksburg, Virginia 24061, USA</P>
+<P ALIGN="JUSTIFY">K. Flottum, Gleanings in Bee Culture, 623 West Liberty Street, P.O. Box 706, Medina, Ohio 44258-0706, USA (editor)</P>
+<P ALIGN="JUSTIFY">J. Free, Rothamstead Experimental Station, Harpenden, Hertfordshire L5 2JQ, UK</P>
+<P ALIGN="JUSTIFY">D. Wolde-Semait Gebre-Wold, P.O. Box 7505, Addis Ababa, Ethiopia</P>
+<P ALIGN="JUSTIFY">C.B. Habarugira, AHO (Apiary), Mbara Stockfarm, Beekeeping Section, P.O. Box 4, Mbarara, Uganda</P>
+<P ALIGN="JUSTIFY">L.A.M. Hassan, Njiro Wildlife (Beekeeping) Research Centre, P.O. Box 661, Arusha, Tanzania</P>
+<P ALIGN="JUSTIFY">R. Hoopingarner, Department of Entomology, University of Michigan, East Lansing, Michigan 48824-1115, USA</P>
+<P ALIGN="JUSTIFY">W.E. Kerr, Departamento de Biolgia, Universidade Federal de UberlGndia, 38400 UberlGndia, Brazil</P>
+<P ALIGN="JUSTIFY">P.G. Kevan, or Resident Bee Specialist, Department of Environmental Biology, University of Guelph, Guelph, Ontario NIG 2WI, Canada</P>
+<P ALIGN="JUSTIFY">K.K. Kigatiia, Beekeeping Branch, Ministry of Agriculture c~ Livestock Development, P.O. Box 30028, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">H.C. Killins, 163 Trowbridge Avenue, London, Ontario N6J 3M2, Canada</P>
+<P ALIGN="JUSTIFY">H.M. Kiwuwa, AHL (Apiary), Department of Veterinary Services, Headquarters, Beekeeping Section, P.O. Box 7141, Kampala, Uganda</P>
+<P ALIGN="JUSTIFY">G. Lanarolle, Apiculture Project, Bindunuwewa, Bandarawela, Sri Lanka</P>
+<P ALIGN="JUSTIFY">Y. Lensky, Triwaks Bee Research Center, Hebrew University Faculty of Agriculture, Rehovot 76-100, Israel</P>
+<P ALIGN="JUSTIFY">M.D. Levin, Carl Hayden Bee Research Center, Agricultural Research Service, U.S. Department of Agriculture, 2000 East Allen Road, Tucson, Arizona 85719, USA</P>
+<P ALIGN="JUSTIFY">M. Singh Limbu, Godavari Ashram, GPO Box 50, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY">I. Mann, 14 Millimani Road, Box 20360, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY">R.J. McGinley, Department of Entomology, NHB-105, Smithsonian Institution, Washington, D.C. 20560, USA (Apoidea, except Apis) </P>
+<P ALIGN="JUSTIFY">J. McKay, Peace Corps, American Embassy, Asunci6n, Paraguay</P>
+<P ALIGN="JUSTIFY">C.D. Michener, Snow Entomological Museum, University of Kansas, Lawrence, Kansas 66045, USA</P>
+<P ALIGN="JUSTIFY">R.A. Morse, Department of Entomology, Cornell University, Ithaca, New York 14853, USA</P>
+<P ALIGN="JUSTIFY">J. Morton, Morton Collectanea, University of Miami, Box 248204, Coral Gables, Florida 37724, USA (bee plants)</P>
+<P ALIGN="JUSTIFY">D.G. Mugisa, c/o Insure Consult, P.O. Box 30002, Nakiuubo, Uganda</P>
+<P ALIGN="JUSTIFY">M. Bin Muid, Department of Plant Protection, Faculty of Agriculture, Universiti Pertanian Malaysia, Serdang 43400, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY">H.C. Mulzac, International Agency for Apiculture Development, 393 Decatur Street, Brooklyn, New York 11233, USA </P>
+<P ALIGN="JUSTIFY">K.S. Najar, Faculty of Agriculture, University of Aleppo, Aleppo, Syria</P>
+<P ALIGN="JUSTIFY">B.E. Nightingale, Box 23, Njoro, Kenya</P>
+<P ALIGN="JUSTIFY">G. Patty, Foreign Agriculture Service, U.S. Department of Agriculture, 6095 South Building, Washington, D.C. 20250, USA</P>
+<P ALIGN="JUSTIFY">L.M. Phiri, Office of Chief Beekeeping Officer, P/BAC Mwekera, Kitwe, Zambia</P>
+<P ALIGN="JUSTIFY">R. Pickard, Zoology Department, University College, P.O. Box 78, Cardiff CFI IXL, South Wales, UK</P>
+<P ALIGN="JUSTIFY">G.W. Robins, GPO Box 50, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY">D. Roubik, Stop 105, Museum of Natural History, Smithsonian Institution, Washington, D.C. 20560, USA (stingless bees)</P>
+<P ALIGN="JUSTIFY">D. Sammataro, 7011 Spieth Road, Medina, Ohio 44256, USA (editor, Cornucopia) </P>
+<P ALIGN="JUSTIFY">G. Schechtel, Cnel. Bogado/Itapua, Paraguay</P>
+<P ALIGN="JUSTIFY">H. Shimanuki, Beneficial Insects Laboratory, Agricultural Research Service, U.S. Department of Agriculture, B-476 BARC-East, Beltsville, Maryland 20705, USA</P>
+<P ALIGN="JUSTIFY">O.R. Taylor, Department of Entomology, University of Kansas, Lawrence, Kansas 66045, USA</P>
+<P ALIGN="JUSTIFY">J.E. Tew, Agricultural Technical Institute, Ohio State University, Wooster, Ohio 44691, USA</P>
+<P ALIGN="JUSTIFY">M. Tomasko, Pennsylvania State University, 106 Patterson Building, University Park7 Pennsylvania 16802, USA</P>
+<P ALIGN="JUSTIFY">P. Torchio, Agricultural Research Service, U.S. Department of Agriculture, Bee Laboratory, Utah State University, Logan, Utah 84322-5310, USA</P>
+<P ALIGN="JUSTIFY">R. Wadlow, 8381 San Mateo, Ft. Myers, Florida 33907, USA</P>
+<P ALIGN="JUSTIFY">D.W. Whitehead, International Agency for Apiculture Development, c/o 1000 Connecticut Avenue NW, #707, Washington, D.C. 20036, USA</P>
+<P ALIGN="JUSTIFY">Siriwat Wongsiri, Department of Biology, Chulalongkorn University, Bangkok7 Thailand (Apis cerana) </P>
+<P ALIGN="JUSTIFY">Wu Yan-ru, Department of Insect Taxonomy and Faunistics, Institute of Zoology, Academia Sinica, 7 Zhongguancun Lu, Haitien, Beijing, People's Republic of China </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">C BIOGRAPHICAL SKETCHES OF PANEL MEMBERS</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH W. PHILLIPS retired in 1982 from the post of deputy director general of the Food and Agriculture Organization of the United Nations (FAO), Rome, Italy, a post he held for four years. Among his earlier posts were that of professor and head, Animal Husbandry Department, Utah State University; senior animal husbandman in charge, Genetic Investigations, United States Department of Agriculture (USDA); chief, Animal Production Branch and deputy director, Agriculture Division, FAO; and executive director, International Organization Affairs, USDA. Among his special assignments were: serving as consultant on animal breeding to the governments of China and India for the U.S. Department of State in 1943-44; and as scientific secretary for agriculture of the United Nations Conference on Science and Technology for the Benefit of Developing Countries, in Ceneva, Switzerland, 1962-63. Dr. Phillips holds a B.S. degree in agriculture from Berea College (1930), M.A. (1931) and Ph.D. (1934) degrees from the University of Missouri, and Honorary D.Sc. degrees from Berea College and West Virginia University. He has been awarded the Berea College Distinguished Alumnus Award and the USDA's Distinguished Service Award. He is author or coauthor of some 240 scientific papers, review papers, chapters in books, and books on various aspects of physiology of reproduction, genetics, livestock production, and international agriculture. In his research, writings, and international activities, Dr. Phillips has given particular attention to breeding in relation to the environment and to the identification and conservation of valuable animal genetic resources. He is also the author of a definitive history of FAO entitled FAO: Its Origins, Formation and Evolution, 19451981 and an autobiography, The World Was My Barnyard. </P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU is currently senior advisor to the president of the African Development Bank. He is also president of ESA Associates, Washington, D.C., and former director of the Office of Biological Conservation, Smithsonian Institution, Washington, D.C. A citizen of Ghana, he received his B.A. in 1961 from Miami University in Ohio, M.Sc. from The George Washington University in 1963, and his Ph.D. in 1966 from the University of London. His research interests cover many areas of tropical biology. An internationally recognized expert on topics relating to science, technology, and development, especially in developing countries, he has also published extensively on tropical plants. Dr. Ayensu chairs and serves as a member of many international bodies. </P>
+<P ALIGN="JUSTIFY">BONNIE V. BEAVER, professor of small animal medicine and surgery, Texas A&amp;M University, College Station, is a specialist in animal behavior and problem behaviors, especially in domestic and laboratory animals. She received her B.S. and D.V.M. from the University of Minnesota and her M.S. from Texas A&amp;M. In addition to being a popular speaker at scientific meetings, she is the author of five books and numerous book chapters and articles. </P>
+<P ALIGN="JUSTIFY">KURT BENIRSCHKE, professor of pathology and reproductive medicine, University of California at San Diego, received his M.D. from the University of Hamburg, Germany, in 1948. He served on the faculties of Harvard and Dartmouth medical schools before coming to San Diego in 1970. At the San Diego Zoo he initiated a research department to advance knowledge in endangered species and now serves as a trustee of that organization. He has written on comparative mammalian cytogenetics, vanishing species, and human reproductive pathology. </P>
+<P ALIGN="JUSTIFY">ROY D. CRAWFORD is professor of animal and poultry genetics at the University of Saskatchewan, Saskatoon, Saskatchewan, Canada. He received his B.S.A. from the University of Saskatchewan in 1955, his M.S. in animal genetics from Cornell University in 1957, and his Ph.D. in poultry genetics from the University of Massachusetts in 1963. He was employed as a scientist with the Research Branch of Agriculture Canada from 1957 to 1964 in Prince Edward Island and Nova Scotia. He joined the faculty of the University of Saskatchewan in 1964. He was made a fellow of the Agricultural Institute of Canada in 1986 in recognition of his teaching and research work. His research interests include single gene genetics of poultry, and conservation of genetic resources in poultry and livestock. He has discovered and studied many mutants in chickens; some of them have biomedical importance, including one shown to be an animal genetic model of human grand mal epilepsy; some of them are potentially useful in food production, including an albinism mutant that is being developed for autosexing of commercial chicken broilers. He maintains a very large conservation collection of poultry genetic resources at the University of Saskatchewan and has prepared an inventory and assessment of Canada's poultry and livestock genetic resources. Dr. Crawford is a member of the Expert Panel on Animal Genetic Resources Conservation and Management, FAO/UNEP, Rome, and is a member of the Animal Resources Committee, Canadian Council on Animal Care, Ottawa. He serves on the International Scientific Committee for the French journal GTnTtique, STlection, +volution. He is a member of the Rare Breeds Survival Trust (UK) and is a board member of the American Minor Breeds Conservancy (USA). </P>
+<P ALIGN="JUSTIFY">TONY J. CUNHA, distinguished service professor emeritus, University of Florida, Gainesville, and dean emeritus, California State Polytechnic University, Pomona, received his Ph.D. at the University of Wisconsin in 1944. He has given more than 100 lectures in livestock feeding and nutrition in 40 foreign countries. He served as chairman of the Animal Nutrition Committee of the National Academy of Sciences and as a member of the NAS-NRC Board of Agriculture and Renewable Resources, Latin American Science Board, and as chairman of the livestock committee of two world food studies by NAS-NRC. He served as a member of the organizing committee for the first two World Conferences on Animal Production in Rome (1963) and Washington, D.C. (1968). He served as a member of the Title XII Board of International Food and Agricultural Joint Committee on Research and as chairman of its research priorities committee 1977-1981. He is author, editor, coeditor, or contributor to 30 books and author of more than 1,423 scientific and professional articles. He is a winner of 42 campus, state, national, and international honors and awards. </P>
+<P ALIGN="JUSTIFY">DAVID E. DEPPNER, director of Trees for the Future in Silver Spring, Maryland, has been a consultant for international development projects involving livestock and poultry management and marketing for the past 14 years. He has served in 17 countries of Asia, Africa, and Central America. He has written on processing livestock rations under tropical conditions and about the Madurese breed of cattle found in East Java, Indonesia, where he spent two years studying this ancient breed. He is currently providing technical assistance to projects in several countries for the development of improved forage production as an answer to destruction of natural resources of tropical uplands caused by overgrazing. He received his B.Sc. in animal science from Ohio State University in 1954 and M.Sc. in livestock economics from Araneta University, the Philippines, in 1977. </P>
+<P ALIGN="JUSTIFY">ELIZABETH L. HENSON is the director of the American Minor Breeds Conservancy, based in Pittsboro, North Carolina. She received an M.A. in zoology from Oxford University in 1980 and an M.Sc. in domestic animal breeding from Edinburgh University in 1981. Her primary interests are in the conservation of rare and endangered breeds and varieties of domestic livestock as a genetic resource for changing agricultural needs. She represented Britain at the first international conference on domestic animal conservation in Hungary in 1982, and was a member of the Office of Technology Assessment Committee on grassroots strategies to maintain genetic diversity in 1985. She is executive secretary for four British breed associations and is a member of the British Rare Breeds Survival Trust Technical Panel. </P>
+<P ALIGN="JUSTIFY">DONALD L. HUSS was regional animal production officer of the FAO Regional Office for Latin America and the Caribbean, Santiago, Chile, before his retirement. He received a B.S. in 1949, an M.A. in 1954, and a Ph.D. in 1959, all at Texas A&amp;M University. He was assistant professor of range management at Texas A&amp;M before joining the Food and Agricultural Organization of the United Nations (FAO) in 1967. He founded the FAO Regional Office's Small Animals for Small Farms programme in 1980. Professional assignments and travels in Latin America, the Caribbean' Near and Middle East, and Africa have contributed to his knowledge and experience in microlivestock development. Dr. Huss was recognized by Texas A&amp;M University by being chosen as the recipient of the Memorial Student Center Appreciation and Distinguished Service Awards in 1958 and 196O, respectively, and Honour Professor in the College of Agriculture in 1966 67. He also received the Society for Range Management's Outstanding Service and Achievement Award in 1975 and its Fellow Award in 1978. </P>
+<P ALIGN="JUSTIFY">DAVID RICHARD LINCICOME has been a guest scientist with the Animal Parasitology Institute, United States Department of Agriculture Experiment Station, Beltsville, Maryland, since 1978, having retired as professor of parasitology, Howard University, Washington, D.C., in 1970. He received the B.S. and M.S. degrees cum laude simultaneously in 1937 from the University of Illinois and a Ph.D. in tropical medicine from the Tulane Medical School, New Orleans, Louisiana, in 1941. His principal research interests have centered around morphologic studies on Acanthocephala, molecular exchanges of dependent cells and their environments, and diagnosis of parasitic diseases. He has been a breeder of Nubian and American pygmy goats for the past 20 years. Dr. Lincicome is currently a member of the Board of Directors of the American Dairy Goat Association and is past president of the National Pygmy Goat Association. He was founder and long time trustee of the American Dairy Goat Association Research Foundation. He is also past president of the Helminthological Society and currently serves the society as archivist. He received the Helminthological Society's Anniversary Award in 1975. He was founder and, for 27 years, editor of the journal Experimental Parasitology, and is the author and editor of more than 180 scientific contributions. </P>
+<P ALIGN="JUSTIFY">THOMAS E. LOVEJOY is a tropical biologist and ornithologist. He is assistant secretary for external affairs, Smithsonian Institution' Washington, D.C. He was formerly executive vice president for the World Wildlife Fund-U.S., chairman of the Wildlife Preservation Trust International, and a member of two commissions of the International Union for the Conservation of Nature and Natural </P>
+<P ALIGN="JUSTIFY">Resources. At present, Dr. Lovejoy is a principal investigator of the world's largest controlled ecological experiment, which is attempting to determine the optimum size for parks and reserves. This project, conceived and designed by Dr. Lovejoy, is called "the Minimum Critical Size of Ecosystems" and is a joint program of World Wildlife Fund-U. S. and Brazil's National Institute for Amazon Research. Dr. Lovejoy is also the principal advisor for NATURE (WNET/THIRTEEN, New York), a series that he started in 1980. As principal advisor, he recommends program content and oversees the factual accuracy of the program scripts. A member of 11 scientific societies, Dr. Lovejoy has received grants from 16 foundations and institutions and written more than 100 articles for various national and International publications. He has published three books, Key Environments, Pergamon Press, Oxford; Nearctic Avian Migrants in the Neotropics, a Department of the Interior publication; and Conservation of Tropical Forest Birds, an ICPB publication. He is currently working on The Magnificent Exception, a book on people and the biosphere.</P>
+<P ALIGN="JUSTIFY">ARNE W. NORDSKOG is professor emeritus, Department of Animal Science, Iowa State University. He received his B.S., M.S., and Ph.D. degrees from the University of Minnesota between 1937 and 1943. His training and principal area of research has been in quantitative genetics, but by about 1960 his interests shifted to immunogenetics and more recently to molecular genetics. He has traveled widely, spending two years as an instructor in agriculture at the University of Alaska (1937-39), and has been an NSF Research Fellow at Cal Tech (1960), a visiting professor at the University of Minnesota (1966), an FAO lecturer at the Indian Veterinary Institute (1973), and an FAO-sponsored lecturer on poultry breeding in China (1979). He has acted as a consultant to a commercial breeder in Japan for 20 years. He has been the major professor at Iowa State for more than 60 M.S. and Ph.D. candidates and has published more than 150 scientific papers. Dr. Nordskog is an honorary member of the Norwegian Poultry Breeding Association, a fellow of the Poultry Science Association, and a fellow of the AAAS. In 1972, he was the recipient of the Poultry Science Distinguished Service Research Award. </P>
+<P ALIGN="JUSTIFY">LINDA M. PANEPINTO, swine research consultant, was director of the Colorado State University Swine Laboratory through 1988. She earned her B.S. in animal sciences at Colorado State University in 1972. In 1973 she joined the research team developing Yucatan miniature swine at Colorado State University, where she was given primary responsibility for colony management, protocol development, and genetic selection programs. In 1977, she designed an experimental research program for the development of a line of Yucatan pigs with a genetic propensity for exceptionally small size. She has continued her work in that area and has developed the Yucatan Micropig, described elsewhere in this publication. Her other major professional area of interest has been the design of facilities and equipment for swine with emphasis on animal comfort and minimizing stress. Her invention, known as the Panepinto Sling, has been widely adopted as the primary restraint method for numerous medical schools and research facilities using swine in the laboratory. She has published extensively in the field.</P>
+<P ALIGN="JUSTIFY">KURT J. PETERS is professor of animal breeding and husbandry in the tropics and subtropics, University of Gottingen, and is currently director of research at the International Livestock Centre for Africa. He received his Dr. Agr. degree from the Technical University of Berlin in 1975. He has undertaken research in livestock production development in Southeast Asia and Africa. The major focus of his research has been small animals, with special attention given to the potential of unconventional animals. Early in 1985 he assumed his present position directing research at the International Livestock Centre for Africa. </P>
+<P ALIGN="JUSTIFY">JOHN A. PINO is a senior fellow of the National Research Council, Board on Agriculture, and is currently the project director of the study "Managing Global Genetic Resources: Agricultural Imperatives." He received his B.S. in agriculture in 1944-47 and Ph.D. in zoology in 1951 from Rutgers University. As an associate professor he taught and did research in the Department of Poultry Science at Rutgers until 1955 when he accepted a position with the Rockefeller Foundation as animal scientist with the Mexican Agricultural Program, becoming the associate director of that program in 1960. In 1965 he was transferred to the Rockefeller headquarters in New York and became director of the Agricultural Science Program in 1970. Most of his career has been in international agricultural development. He retired from the Foundation in 1983 and went to Washington to become agricultural science advisor at the InterAmerican Development Bank until July 1986 when he accepted his present position. Dr. Pino has been a member of the Board on Agriculture since 1983 and previously from 1973 to 1977. </P>
+<P ALIGN="JUSTIFY">HUGH POPENOE is professor of soils, agronomy, botany, and geography, and director of the Center for Tropical Agriculture and International Programs (Agriculture) at the University of Florida. He received his B.S. from the University of California at Davis in 1951 and his Ph.D. in soils from the University of Florida in 1960. His principal research interest has been in the area of tropical agriculture and land use. His early work on shifting cultivation is one of the major contributions to this system. He has traveled and worked in most of the countries in the tropical areas of Latin America, Asia, and Africa. His current interests include improving indigenous agricultural systems of small landholders, particularly with the integration of livestock and crops. He was chairman of the Advisory Committee on Technology Innovation and a member of the Board on Science and Technology for International Development (under whose aegis this report is presented). He chaired the BOSTID report panels on water buffalo and little-known Asian animals. Currently, he is on the International Advisory Committee of the National Science Foundation and serves as U.S. Board Member for the International Foundation of Science.</P>
+<P ALIGN="JUSTIFY">MICHAEL HILL ROBINSON, director of the Smithsonian Institution's National Zoological Park, is an animal behaviorist and a tropical biologist. Before his appointment to the National Zoo, Dr. Robinson served as deputy director of the Smithsonian Tropical Research Institute in Panama, which he joined in 1966 as a tropical biologist. He received his Ph.D. from Oxford University after being awarded his B.S., summa cum laude, from the University of Wales. His scientific interests include predator-prey interactions, evolution of adaptations, tropical biology, courtship and mating behavior, phenology of arthropods, and freshwater biology. In the course of his studies, Dr. Robinson has done research in the United States and throughout the developing world. Recent publications include articles on predator-prey interactions, tropical forest conservation, reproductive behavior in spiders, and the function and purpose of zoos in relation to education and conservation. Dr. Robinson's favorite animals are cats, of all kinds. </P>
+<P ALIGN="JUSTIFY">KNUT SCHMIDT-NIELSON, J.B. Duke Professor of Physiology in the Department of Zoology at Duke University, has studied animal responses to extreme environmental conditions. His major emphasis has been on life in hot deserts, and he is widely recognized for his studies of camels and other desert animals. His research has involved field studies in North and South America, Africa, Asia, and Australia. Dr. Schmidt-Nielson has written several books, which have been translated into more than a dozen languages, and he has published several hundred research papers. He has been elected to the National Academy of Sciences, the Royal Society, the French Academie des Sciences, and several other academies. </P>
+<P ALIGN="JUSTIFY">ALBERT E. SOLLOD, is associate professor and head of the international veterinary medicine section at Tufts University School of Veterinary Medicine. He is currently stationed in Niger as chief of party of the integrated livestock project and policy advisor in the Ministry of Animal Resources. He has consulted in 15 countries in Africa and Asia, and his research interests include interdisciplinary systems analysis, indigenous pastoral technologies, monitoring change in agricultural production systems, and monitoring and assessing drought impact.</P>
+<P ALIGN="JUSTIFY">LEE M. TALBOT received his Ph.D. in geography and ecology from the University of California at Berkeley in 1963 and has worked on environmental and natural resource ecology and management in over 110 countries. At present he is visiting fellow at the World Resources Institute, Washington, D.C., and senior environmental consultant to the World Bank. He carried out pioneering research in Africa and elsewhere on the use of wild animals for food production. He has written more than 180 scientific and technical publications, including ten books and monographs. </P>
+<P ALIGN="JUSTIFY">CLAIR E. TERRILL, animal scientist, collaborator, Agricultural Research Service, United States Department of Agriculture (USDA), Beltsville, Maryland, received his Ph.D. from the University of Missouri in 1936, served briefly at the Georgia Agricultural Experiment Station, and joined the USDA at the U.S. Sheep Experiment Station, Dubois, Idaho, in the same year. His research concerned genetics and reproduction of sheep, leading to national and international responsibility regarding research and production of sheep, goats, and other animals, with primary emphasis on increasing efficiency of production of meat, wool, and other products. </P>
+<P ALIGN="JUSTIFY">CHRISTIAN M. WEMMER is assistant director for conservation and captive breeding programs at the National Zoological Park and is also in charge of the zoo's 3,100 acre Conservation and Research Center in Front Royal, Virginia. He is vice chairman of the IUCN Deer Specialist Group and a member of the Mustelid and Viverrid Specialist Group of the same organization. His interest in evolutionary and conservation biology has been motivated by frequent travel to South Asia and his role as scientific coordinator of the Smithsonian Nepal Terai Ecology Project. For the past 12 years he has coordinated the development of facilities and programs at the Conservation and Research Center and with Dr. R. Rudran has promoted conservation training and wildlife research in developing nations. He has published over 50 papers on various aspects of mammalian biology and conservation and has co-edited with Benjamin Beck one book on PFre David's deer. His edited volume "The Biology and Management of the Cervidae" was published by the Smithsonian Institution Press. </P>
+<P ALIGN="JUSTIFY">DANNY C. WHARTON is associate curator, Animal Departments, at New York Zoological Park, Bronx, New York. He received a B.S. from the College of Idaho and an M.Sc. in 1975 from the School for International Training in Brattleboro, Vermont. His Ph.D. in biology was earned at Fordham University. Dr. Wharton was a Peace Corps volunteer to Ecuador 1969-71 and a Fulbright scholar to Germany 1976-77. His research interests have been in the genetic and demographic management of small populations. He works on several committees including the IUCN/SSC Captive Breeding Specialist Group, Species Survival Plan Committee of the American Association of Zoological Parks and Aquariums, and is species chairman for the North American Propagation Group for the Snow Leopard.</P>
+<P ALIGN="JUSTIFY">CHARLES A. WOODS IS curator of mammals at the Florida State Museum and a professor of zoology at the University of Florida. He received his B.S. in zoology from the University of Denver and his Ph.D. in zoology from the University of Massachusetts. He worked at the University of Vermont from 1970 to 1979 when he assumed his present position at the University of Florida. His principle research interests have been in the areas of mammalian ecology (Rodentia) and systematics and evolution and he is especially concerned with island biology. He has spent many years working in the West Indies on a variety of projects and has worked closely with the government of Haiti in establishing a plan for the National Parks of Haiti and in completing a biogeophysical inventory of the natural resources of Hispaniola. He is the ecological consultant for the Institut de Sauvegarde du Patrimoine National in Haiti. He is the author of a number of scientific articles on the fauna of the Antilles including a multivolume series on the fauna of the mountains of Haiti. </P>
+<P ALIGN="JUSTIFY">THOMAS M. YUILL is associate dean for research and graduate training of the School of Veterinary Medicine, assistant director of the Agricultural Experiment Station, and professor of pathobiology and of veterinary science at the University of Wisconsin-Madison. He received his B.S. in wildlife management from Utah State University in 1959 and his Ph.D. jointly in veterinary science and wildlife ecology in 1964 from the University of Wisconsin. His principal research interests are animal health and diseases of wildlife, including those transmissible to domestic animals and to man. He worked in Thailand for two years and has had active research programs in Colombia for 17 years, and Costa Rica for 5 years. He has recently become involved in animal health and production development in the Gambia, West Africa. Dr. Yuill is an executive committee member and immediate past president of the Organization for Tropical Studies and currently serves as president of the Wildlife Disease Association. He completed a five-year term as Chairman of the U.S. Virus Diseases Panel of the U.S.-Japan Cooperative Biomedical Sciences Program. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Board on Science and Technology for International Development (BOSTID)</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ALEXANDER SHAKOW, Director, Strategic Planning and Review,</P>
+<P ALIGN="JUSTIFY">The World Bank, Washington, D.C., Chairman</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PATRICIA BARNES-MCCONNELL, Director, Bean/Cowpea CRSP, East Lansing, Michigan</P>
+<P ALIGN="JUSTIFY">JORDAN J. BARUCH, President, Jordan Baruch Associates, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">PETER D. BELL, President, The Edna McConnell Clark Foundation, New York, New York</P>
+<P ALIGN="JUSTIFY">BARRY BLOOM, Professor, Department of Microbiology, Albert Einstein College of Medicine, The Bronx, New York</P>
+<P ALIGN="JUSTIFY">JANE BORTNTCK, Assistant Chief, Congressional Research Service, Library of Congress, Washington, D.C.</P>
+<P ALIGN="JUSTIFY">GEORGE T. CURLIN, The National Institute of Allergy and Infectious Diseases, The National Institutes of Health, Bethesda, Maryland</P>
+<P ALIGN="JUSTIFY">DTRK FRANKENBERG, Director, Marine Sciences Program, University of North Carolina, Chapel Hill, North Carolina</P>
+<P ALIGN="JUSTIFY">RALPH HARDY, Boyce-Thompson Institute for Plant Research, Cornell University, Ithaca, New York</P>
+<P ALIGN="JUSTIFY">FREDERICK HORNE, Dean, College of Sciences, Oregon State University, Corvallis, Oregon</P>
+<P ALIGN="JUSTIFY">ELLEN MESSER, Allan Shaw Feinstein World Hunger Program, Brown University, Providence, Rhode Island</P>
+<P ALIGN="JUSTIFY">CHARLEs C. MUSCOPLAT, Executive Vice President, Molecular Genetics, Inc., Minneapolis, Minnesota</P>
+<P ALIGN="JUSTIFY">JAMES QUINN, Amos Tuck School of Business, Dartmouth College, Hanover, New Hampshire </P>
+<P ALIGN="JUSTIFY">VERNON RUTTAN, Regents Professor, Department of Agriculture and Applied Economics, Saint Paul, Minnesota</P>
+<P ALIGN="JUSTIFY">ANTHONY SAN PIETRO, Professor of Plant Biochemistry, Department of Biology, Bloomington, Indiana</P>
+<P ALIGN="JUSTIFY">ERNEST SMERDON, College of Engineering and Mines, University of Arizona, Tucson, Arizona</P>
+<P ALIGN="JUSTIFY">GERARD P. DINEEN, Foreign Secretary, National Academy of Engineering, National Research Council, Washington, D.C., ex officio </P>
+<P ALIGN="JUSTIFY">JAMES B. WYNGAARDEN, Foreign Secretary, National Academy of Sciences, National Research Council, Washington, D.C., ex officio </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development Publications and Information Services (H A-476E)</P>
+<P ALIGN="JUSTIFY">Office of International Affairs</P>
+<P ALIGN="JUSTIFY">National Research Council</P>
+<P ALIGN="JUSTIFY">2101 Constitution Avenue, N.W.</P>
+<P ALIGN="JUSTIFY">Washington, D.C. 20418 U SA</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<!--
+</Section>
+</Section>
+-->
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b17mie/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b17mie/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b17mie/metadata.xml	(revision 10506)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">Microlivestock - Little-Known Small Animals with a Promising Economic Future (b17mie)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Animal Husbandry and Animal Product Processing|Other animals (micro-livestock, little known animals, silkworms, reptiles, frogs, snails, game, etc.)</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">BOSTID</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+            <Metadata mode="accumulate" name="dls.Keyword">introduce small animals and micro-livestock in your farm</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b18ase/b18ase.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b18ase/b18ase.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b18ase/b18ase.htm	(revision 10506)
@@ -0,0 +1,2966 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Little Known Asian Animals With a Promising Economic Future</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Little Known Asian Animals With a Promising Economic Future</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Report of an Ad Hoc Panel of the Advisory Committee on Technology Innovation Board on Science and Technology for International Development Office of International Affairs National Research Council </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Acknowledgments</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATIONAL ACADEMY PRESS</P>
+<P ALIGN="JUSTIFY">Washington, D.C. 1983</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOTICE: The project that is the subject of this report was approved by the Governing Board of the National Research Council, whose members are drawn from the Councils of the National Academy of Sciences, the National Academy of Engineering, and the Institute of Medicine. The members of the Committee responsible for the report were chosen for their special competences and with regard for appropiate balance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been reviewed by a group other than the authors according to procedures approved by a Report Review Committee consisting of members of the National Academy of Sciences, the National Academy of Engineering, and the Institute of Medicine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The National Research Council was established by the National Academy of Sciences in 1916 to associate the broad community of science and technology with the Academy's purposes of furthering knowledge and of advising the federal government. The Council operates in accordance with general policies determined by the Academy under the authority of its congressional charter of 1863, which establishes the Academy as a private, nonprofit, self-governing membership corporation. The Council has become the principal operating agency of both the National Academy of Sciences and the National Academy of Engineering in the conduct of their services to the government, the public, and the scientific and engineering communities. It is administered jointly by both Academies and the Institute of Medicine. The National Academy of Engineering and the Institute of Medicine were established in 1964 and 1970, respectively, under the charter of the National Academy of Sciences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Board on Science and Technology for International Development (BOSTID) of the Office of International Affairs addresses a range of issues arising from the ways in which science and technology in developing countries can stimulate and complement the complex processes of social and economic development. It oversees a broad program of bilateral workshops with scientific organizations in developing countries and conducts special studies. BOSTID's Advisory Committee on Technology Innovation publishes topical reviews of technical processes and biological resources of potential importance to developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been prepared by an ad hoc advisory panel of the Advisory Committee on Technology Innovation, Board on Science and Technology for International Development, Office of International Affairs, National Research Council. Program costs for the study were provided by the Office of Technical Resources, Bureau for Asia, Agency for International Development, under Grant No. ASB-0249-SS-00-1026-00 and the Office of the Science Advisor, Agency for International Development, under Grant No. DAN/ 5538-G-SS-1023-00.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Funding for this printing was provided by the Office of Agriculture, Bureau for Science and Technology, Agency for International Development, Washington, D.C., under Grant No. DAN 1406-G-SS-4001-00.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">First Printing, June 1983</P>
+<P ALIGN="JUSTIFY">Second Printing, July 1984</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Library of Congress Catalog Card Number 83-061909</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Participants in the Study</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, USA, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contributors </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AMBAR ROESYAT, Research Institute for Animal Husbandry, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1. B. ARKA, Faculty of Veterinary Science and Animal Husbandry, Udayana University, Bali, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. S. F. BARKER, Professor of Animal Sciences and Head of Department, The University of New England, Armidale, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">KURT BENIRSCHKE, Research Department, San Diego Zoological Garden, San Diego, California, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BEN BERESKIN, Research Geneticist, Nonruminant Animal Nutrition Laboratory, Animal Science Institute, United States Department of Agriculture, Beltsville, Maryland, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALEIGH A. BLOUCH, World Wildlife Fund, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. BONGERS, Nature Conservation Department, Wageningen Agricultural University, Wageningen, The Netherlands </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. BONNEMAIRE, Ecole Nationale Superieure des Sciences Agronomiques Appliquees, Dijon, France </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. A. BOSMA, Vakgroep Funktionele Morfologie, Rijksuniversiteit, Utrecht, The Netherlands </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. BUTCHER, Assistant Director, Western Plains Zoo, Dubbo, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G. S. CHILD, Wildlife and Parks Management Officer, Food and Agriculture Organization, Rome, Italy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. ROSS COCKRILL, International Animal Consultant, Almansil, Algarve, Portugal </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PAUL CONRY, Division of Aquatic and Wildlife Resources, Department of Agriculture, Guam </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HAROLD J. COOLIDGE, Former President, International Union for the Conservation of Nature, Beverly, Massachusetts, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. P. CROWCROFT, General Director, Metropolitan Zoo, Toronto, Canada </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TONY J. CUNHA, Dean Emeritus, California State Polytechnic University, Pomona, California, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. DEPPNER, Tropical Livestock Consultant, Washington, D.C., USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. DEVENDRA, Head, Feed Resources and Animal Nutrition Branch, Malaysian Agricultural Research and Development Institute, Selangor, Malaysia </P>
+<P ALIGN="JUSTIFY">J. M. DOLAN, San Diego Zoological Garden, San Diego, California, USA DUKUT SULARSASA, Department of Tropical Veterinary Science, James Cook University, Townsville, Queensland, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. EPSTEIN, Faculty of Agriculture, The Hebrew University of Jerusalem, Tel Aviv, Israel (retired) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">T. FINNIE, Taronga Zoo, Mosman, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. FISCHER, Director, Institute of Tropical Veterinary Medicine, JustusLiebig-Universitat, Giessen, Federal Republic of Germany </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IAN FLETCHER, Project for Animal Research and Development, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ANNIE P. GRAY, Commonwealth Bureau of Animal Breeding and Genetics, Edinburgh, Scotland (retired) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. B. GRIFFITHS, Director, Animal Production and Health Division, Food and Agriculture Organization, Rome, Italy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1. R. GRiMWOOD, Nairobi, Kenya </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">COLIN P. GROVES, Australian National University, Canberra, A.C.T., Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ULRICH HALDER, Swiss League for Nature Conservation, Basel, Switzerland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHARLES G. HICKMAN, Livestock Consultant, A. Mithat Efendi Sokak No. 36/11, Cankaya, Ankara, Turkey </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. HOFFMAN, Veterinarian, Project for Animal Research and Development, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. H. G. HOLMES, Department of Agriculture and Forestry, University of Melbourne, Victoria, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. HUITEMA, Veterinarian, Osterbeek, The Netherlands </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. H. HUTASOIT, Director-General, Livestock Services, Jakarta, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BENT JORGENSEN, Director, Copenhagen Zoo, Copenhagen, Denmark </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NAT KlEFFER, Department of Animal Science, Texas A&amp;M University, College Station, Texas, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. WAYNE KING, Director and Professor, Florida State Museum, University of Florida, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GRAHAM W. M. KIRBY, Principal Animal Production Officer, Department of Primary Production, Darwin, Northern Territory, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HEINZ-GEORG KLOS, Director, Zoologischer Garten, Berlin, West Germany </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">KUSMAT TANUDIMADJA, Professor of Veterinary Anatomy, Faculty of Veterinary Medicine, Institut Pertanian, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN K. LOOSLI, Department of Animal Science, University of Florida, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN A. LUKAS, White Oak Plantation, Yulee, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. A. MACDONALD, Vakgroep Funktionele Morfologie, Rijksuniversiteit, Utrecht, The Netherlands </P>
+<P ALIGN="JUSTIFY">JOHN MACKINNON, Representative, World Wildlife Fund, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT E. McDOWELL, Professor, Department of Animal Science, Cornell University, Ithaca, New York, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JEFFREY A. McNEELY, Executive Officer, Commission on National Parks and Protected Areas, International Union for Conservation of Nature and Natural Resources, Gland, Switzerland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ADRIAN G. MARSHALL, Honorary Secretary, Institute of South-east Asian Biology, Department of Zoology, University of Aberdeen, Scotland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">[AN L. MASON, Animal Breeding Consultant, Edinburgh, Scotland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEERT MONTSMA, Vakgroepen Veefokkerij, Veehouderij, Tropische Veehouderij, Wageningen, The Netherlands </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. B. MORAN, Senior Research Officer, Animal and Irrigated Pastures Research Institute, Kyabram, Victoria, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT H. MILLER, Chief, Milk Secretion and Mastitis Laboratory, Beltsville, Maryland, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JAN NARI, Director, Central Research Institute for Animal Science, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARVEY NEESE, President, Agri-Food Systems International, Inc., Troy, Idaho, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. M. NITIS, Department of Animal Nutrition and Tropical Pasture Production, Udayana University, Denpasar, Bali, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM L. R. OLIVER, Chairman, lUCN/SSC Pigs and Peccaries Specialist Group, Jersey, Channel Islands, United Kingdom </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN PAYNE, Wildlife Section, Forest Department, Sandakan, Sabah, Malaysia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W.J.A. PAYNE, Tropical Animal Breeding Consultant, London, England </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH W. PHILLIPS, Arlington, Virginia, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Scientific Advisor, Consultative Group on International Agricultural Research, Washington, D.C., USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DAVID W. ROBINSON, Associate Dean, International Programs, University of California, Davis, California, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PATRICK J. ROBINSON, Department of Agricultural and Forest Sciences, University of Oxford, Oxford, England </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. H. L. ROLLINSON, Animal Production Officer, Animal Production and Health Division, Food and Agriculture Organization of the United Nations, Rome, Italy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CLIVE ROOTS, Director, Assiniboine Park Zoo, Winnipeg, Manitoba, Canada </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. A. SAYER, Nature Conservation and National Parks Project, FAO, Rangoon, Burma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. E. SATTER, Nature Conservation and National Parks Project, FAO, Rangoon, Burma </P>
+<P ALIGN="JUSTIFY">GEORCE B. SCHALLER, New York Zoological Society, New York, New York, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN SCHOTTLER, Principal Animal Production Officer, Department of Primary Industry, Lae, Papua New Guinea </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE SEIFERT, CSIRO, Rockhampton, Queensland, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROGER V. SHORT, Professor of Reproductive Biology, Monash University, Melbourne, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. C. SINHA, Outdoor Recreation and Wildlife Research Division, Forest Research Institute, College, Laguna, Philippines </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK J. SIMOONS, Professor, Department of Geography, University of California, Davis, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. D. SIMPSON, Senior Extension Specialist, Department of Agricultural, Technical and Extension Services, Bulawayo, Zimbabwe </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P. SITORUS, Research Institute for Animal Production, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. J. SMITH, Royal School of Veterinary Studies, University of Edinburgh, Edinburgh, Scotland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. J. STOLP-DIEPEVEEN, Department of Tropical Animal Production, Agricultural University, Wageningen, The Netherlands </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SUBANDRlYO, Research Institute for Animal Production, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. SUMADI, Faculty of Animal Husbandry, Gadjah Mada University, Yogyakarta, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">L. M. TALBOT, World Wildlife Fund International, Gland, Switzerland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WARREN D. THOMAS, Director, Los Angeles Zoo, Los Angeles, California, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. L. THROP, Director, Taronga Zoo, Mosman, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ALLEN D. TILLMAN, Private Consultant in Animal Production, Stillwater, Oklahoma, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD G. TULLOCH, Division of Wildlife Research, CSIRO, Winnellie, Northern Territory, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HELEN NEWTON TURNER, Genetics Research Laboratories, CSIRO, North Ryde, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B. VAN PUIJENBROECK, Curator of Mammals, Royal Zoological Society of Antwerp, Antwerp, Belgium </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">E. J. WARWICK, Visiting Professor, Faculty of Animal Husbandry, Gadjah Mada University, Yogyakarta, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WARTOMO HARDJOSUBROTO, Lecturer in Animal Husbandry, Faculty of Animal Husbandry, Gadjah Mada University, Yogyakarta, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. H. WHARTON, Chief Research Scientist, CSIRO, Long Pocket Laboratories, Brisbane, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. L. WHEELER, Project Manager, Project for Animal Research and Development, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY">M.H. WOODFORD, Wildlife Veterinarian, Food and Agriculture Organization, Rome, Italy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B.A.YOUNG, Department of Animal Science, the University of Alberta, Edmonton, Canada </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M.ZULBARDI, Research Institute for Animal Production, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, Professional Associate, Board on Science and Technology for International Development, Asian Animals Study Director </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Research Council Staff</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. R. RUSKIN, BOSTID Editor </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MARY JANE ENGQUIST, Staff Associate </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CONSTANCE RECKS, Administrative Secretary </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">It is high time that the world was made aware of the valuable, large ruminant genetic resources of Southeast Asia.</P>
+<P ALIGN="JUSTIFY">J. B. MORAN Livestock Specialist Animal and Irrigated Pastures Research Institute Kyabram, Victoria, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Without utilization preservation is doomed to failure. Local breeds able to perform well in difficult habitats, such as in sparse vegetation, mountainous terrain, or the tropics, should be used for their agricultural potential. Breeds that demonstrate hybrid vigor on crossing with improved or exotic breeds also merit utilization. Genetically unique breeds should be retained for scientific studies of genetics, evolution, and biochemistry. And aesthetically attractive and historically important breeds should be maintained in parks and preserves for their educational and cultural values.</P>
+<P ALIGN="JUSTIFY">I. L. MASON Animal Breeding Consultant Edinburgh. Scotland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p00.png"></center><br>
+ YAK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Preface</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report began as a brief examination of the domesticated banteng, a little studied bovine that is an important livestock resource in eastern Indonesia. But the study expanded to include other possibly useful but obscure bovines of Asia: the madura (a hybrid between banteng and cattle), gaur, mithan, kouprey, anoa, tamaraw, yak, and yakowshybrids formed by crossing yaks with cattle. Four pig species were also included (the bearded pig, the Sulawesi warty pig, the Javan warty pig, and the pygmy hog) that are important traditional resources in parts of Asia, as well as the babirusaa piglike, wild animal of Sulawesi that may have a rudimentary rumen. (Asia also has some interesting, little-known breeds of cattle, water buffalo, sheep, goats, and the common pig, but in this report we have chosen to highlight unconventional species only.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">These animals are unfamiliar to international animal science. This report aims to kindle awareness of their possible promise and to stimulate their introduction into projects in the world's animal research facilities. Only through active investigation will the potential of these species - most of which are now familiar only to a small number of wildlife specialists - become clear. Many are threatened with extinction; their genetic merits should be assessed before it is too late.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Development agencies and governments in the tropics should regard local species, such as those described in this report, as important genetic material for bolstering the long-term success of domestic livestock breeding programs. These indigenous resources can probably be improved genetically to compare favorably with imported livestock, particularly in difficult tropical environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report was prepared after Hugh Popenoe, Chairman of the Advisory Committee on Technology Innovation (ACTI), and Noel Vietmeyer of the ACT! staff visited banteng researchers in Indonesia, northern Australia, and Papua New Guinea in May 1981. More than 90 researchers (see contributor's list) provided information to the report through correspondence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACTI is a committee of the Board on Science and Technology for International Development, National Research Council. It assesses unconventional resources and technologies that might prove especially applicable to problems of developing countries. Current titles in the ACTI series Managing Tropical Animal Resources are: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Water Buffalo: New Prospects for an Underutilized Animal (1981)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Little-Known Asian Animals with a Promising Economic Future (1983) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Crocodiles as a Resource for the Tropics (1983) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Butterfly Farming in Papua New Guinea (1983). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The production of these books has been supported largely by the U.S. Agency for International Development (AID). Program costs for this study were sponsored by AID'S Bureau for Asia, and staff costs by AID'S Office of the Science Advisor, which also made possible the free distribution of this report.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is an exploratory volume. It will, perhaps, lead in a few years' time to a more complete book on indigenous Asian animals - and perhaps also to similar books on little-known animals of Africa and Latin America. If you have material to contribute to the future edition, please send it to Noel Vietmeyer, JH213, National Academy of Sciences, 2101 Constitution Avenue, Washington, D.C. 20418, USA, who will contact you when any new publication on this subject is planned.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Introduction</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asia has several domesticated animals about which little is known. Among them are the banteng ("Bali cattle") of Indonesia, the yak of Central Asia's high country, and the mithan of the border region of India, Burma, and Bangladesh.( *The promise of another Asian animal, the water buffalo, is described in companion report no 32. ) Some Asian farmers use domesticated bovine hybrids: the madura (banteng-cattle hybrid) in Indonesia and the yakow (yak-cattle hybrid) in Central Asia. In addition, domesticated forms of at least two Asian pig species (the Indonesian wild boar and the Sulawesi warty pig) are important husbandry animals in parts of Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among Asia's undomesticated animals are five interesting and potentially valuable species of wild bovines: the kouprey in Thailand, Laos, and Kampuchea; the gaur in India and much of Southeast Asia; two species of anoas in Indonesia; and the tamaraw in the Philippines. There are also three species of undomesticated Asian pigs: the bearded pig, the Javan warty pig and pigmy hog. Perhaps the strangest Asian animal of all is the babirusa, a piglike species of eastern Indonesia that may be a rudimentary ruminant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of these animals are either threatened or endangered species, and some will soon be extinct unless scientists, governments, and resource managers take forceful action to preserve them. Scientific management and a better understanding of the animals themselves is required.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An important need is to investigate their potential as livestock resources. All seem to be disease resistant and well adapted to difficult natural conditions. Some will interbreed with conventional livestock and might thereby pass on important characters to hybrid progeny. A few of the wild species are ancestors of domestic livestock and could be important genetic reservoirs for maintaining or improving the quality of their domestic descendants. Others may make useful new domesticates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appreciation of their potential in the long-term for the world's agricultural development could create a momentum for the protection, preservation, and greater use of these little-known animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Imported Livestock</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the past, many thought that the best way to raise animal productivity in tropical developing countries was to introduce high-performing breeds from temperate industrialized areas. The fact that the exotic animals were much more productive than local stock made this seem very appealing. But many such importations ended in failure when the animals either quickly died or their growth or reproduction rates declined so drastically that the herds dwindled away or became uneconomic. These introductions had been made without adequate consideration of the local environment that was expected to support the imported animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More recently, some animal scientists have decried the idea of wholesale importing of temperate-zone livestock into tropical countries without also evaluating the indigenous livestock. In many cases the local animals' apparent poor performance results not from their lack of genetic potential, but from inadequate feeding, breeding, selection, management, and health care.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indigenous Animals</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Until an objective evaluation of particular indigenous breeds is undertaken, governments should regard local animals as vitally important for the long-term development of their domestic livestock industries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To achieve an agriculture that is compatible with nature, we should try to raise an animal as much as possible within its own natural environment. Indigenous species are necessarily well adapted to their surroundings and have survival qualities that imported livestock often lack. They generally select food, either graze or browse, better than foreign species and can therefore exploit the habitat more efficiently and live within it more harmoniously.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But most of the livestock species the world depends on today are best adapted to temperate conditions. This is because Stone Age peoples in what today are Europe, the Middle East, and eastern China domesticated the prototypes of agricultural animals that were available in those places. The world's best-known breeds of cattle, wool sheep, and horses, for example, usually perform well in temperate regions and poorly in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The species described in this report offer promise as new and important alternative livestock resources for tropical regions. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Embryo Transplants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It seems likely that modern technology will substantially improve our ability to use new species and breeds of livestock. One of the most encouraging of the new biotechnology techniques is embryo transplantation. In this process multiple eggs (produced by hormonally stimulating female animals) are fertilized and transplanted to other female animals. The hormonal cycles of the donor and receiving animals are synchronized so that a pregnancy results.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This technique is widely used to transfer embryos between cattle, but researchers are now exploring transfers between different species and even between different genera. In 1981, for example, animal scientists at the New York Zoological Garden transplanted a fertilized gaur ovum into a Holstein cow, which carried the gaur calf to term. Now veterinarians at the University of Florida are attempting to transplant water buffalo embryos into both zebu and Holstein-Friesian cattle, and vice versa. If such pioneering work can become everyday practice, it will open possibilities of using common livestock to raise rare animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, because embryos are thought to be free of many diseases, their shipment between nations may soon be permitted without elaborate quarantine precautions. Methods for freezing embryos have been worked out so that the tiny bundles of cells can be air freighted inexpensively in small, insulated containers. This may make animals such as those discussed in this report available to Africans, Latin Americans, North Americans, and Europeans. It may vastly simplify the worldwide exchange of animal genetic material and become the animal counterpart of exchanging seeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An additional benefit of embryo transplants is that the surrogate mother's placental blood supply provides the fetus with natural immunity to some local diseases, thus perhaps reducing one of the most serious causes of failure when exotic animals are introduced to new environments. And at Utah State University it has been noted that raising wildsheep embryos in domestic ewes produces lambs that are more docile than if they were raised by their biological mothers. Embryo transplants may be a small step toward domesticating new animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With these possibilities on the horizon, it becomes even more important that all countries preserve their indigenous animals. The rest of this report suggests and discusses Asian species for protection and study. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part I : Domesticated Bovine Species</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It seems probable that two of our widely used livestock species were domesticated in the Asian tropics: the zebu or humped cattle in India and the water buffalo in the humid marshlands of northeastern India or Southeast Asia. (Both the chicken and some races of pig may also have a tropical Asian origin, but the exact sites of their earliest domestication is unclear.) There are, however, other, much more localized, domesticated bovines in Asia. These are not well studied and deserve greatly increased recognition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This section highlights:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Domesticated banteng</P>
+<P ALIGN="JUSTIFY">· Banteng-cattle hybrids</P>
+<P ALIGN="JUSTIFY">· Mithan</P>
+<P ALIGN="JUSTIFY">· Yak</P>
+<P ALIGN="JUSTIFY">· Yakows. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is time for the world's scientific community to study the genetics, evolution, and biochemical parameters of the unique animal resources, that are found in Southeast Asia. ALLEN D. TILLMAN Animal Consultant Stillwater, Oklahoma, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Though well adapted for survival in their own harsh tropical environments, many domestic livestock breeds are being neglected in the race to achieve temperate zone levels of productivity. CHARLES HICKMAN Department of Dairy Cattle Breeding Ottawa, Canada </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Studies should be made of the present and potential role, productivity and efficiency of all domestic animals and birds, large and small, before they are replaced by imported types. Many wild species also could make important contributions to human welfare with proper management. J. K. LOOSLI Department of Animal Science University of Florida .</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The conservation of endangered genetic resources represents a genuine and welcome synthesis of the concerns of the agriculturalist and the wildlife enthusiast.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN TINKER British Journalist</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY"><center><img src="p06.png"></center><br>
+ MITHAN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">1 Domesticated Banteng</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The banteng (*Bos javanicus is now the accepted name, but Bos sondaicus, Bibos banteng, and other synonyms have been used in the past. (See Hooijer, 1956.) The name "banteng" has traditionally referred to the wild form of Bos javanicus; the name "Bali cattle" to the domesticated form. This chapter describes the domesticated form, but we retain the name banteng to reinforce the fact that the animal is not a breed of cattle, but a distinct species. Despite a cattle-like appearance, the animals are at least as genetically remote from cattle as is the bison. Both produce sterile males when hybridized with European cattle. Australia. (N.D. Vietmeyer)) is a bovine that resembles a small cow. It is, however, an entirely different species from either European cattle (Bos taurus) or zebus (Bos indicus). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These docile animals thrive under hot, humid conditions and, like the water buffalo, have high resistance to ticks and tick-borne diseases. In parts of Southeast Asia they have proved acceptable for draft power and meat production, and they may have potential for many other regions of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng are remarkably uniform in type and have changed little from their wild ancestors (see chapter 6). Bulls stand from 1.3 to 1.5 m high at the shoulders, while cows are about 1.2 m high. They have the general conformation of beef cattle. The skin is tight, the neck short, and the dewlap inconspicuous. The face is narrow and is carried horizontally with the large ears pointing forward. There is no hump, but the male possesses a distinctive crest over the thorax because the spines of the thoracic vertebrae are unusually elongated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On both sexes a striking white oval patch covers the rump and all four legs have white stockings. Calves and females are usually light brown with a thin black line along the middle of the back. Bulls are brown when young but usually turn near-black at maturity, unless castrated. Thus, in a herd the sexes - black males and brown females - are strikingly apparent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Male horns grow sideways, upward, and outward from a horny mass on the forehead. Females lack this horny shield and their horns usually grow upward and back, eventually curving down again toward the head. Polled animals have not been reported.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mature banteng bulls can weigh from 450 to 500 kg. Under exceptional conditions they may reach 550 kg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nearly all the world's domesticated banteng are found in Indonesia. They are particularly important on the islands of Bali, Kalimantan, Lombok, Sulawesi, Sumbawa, and Timor. On Bali and Sumbawa, they are virtually uncontaminated by crossbreeding with other cattle and are thought to have been domesticated there in prehistoric times. Since 1913 government officials have enforced a law that prohibits crossbreeding so as to maintain the purity of the breed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small numbers of banteng have been introduced to Sumatra, Malaysia, and northern Australia, and there are experimental herds in Texas, USA, and New South Wales, Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY"><center><img src="p09.png"></center><br>
+ DISTRIBUTION OF DOMESTICATED BANTEG</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated banteng account for about 20 percent of Indonesia's total population of "cattle." The banteng population increased from 1.1 million in 1967 to 1.4 million in 1975 and is now estimated to be more than 1.5 million.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng are found mainly in lowland areas on Indonesian islands straddling the equator. The environment is monsoonal with mean annual temperatures ranging from 23° to 31°C. Most of the region receives heavy rainfall throughout the year, but dry spells as long as five months occur at some locations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng normally have high conception rates. In northern Australia they regularly achieve 80-90 percent conception, as compared with the 50-60 percent of Brahman-Shorthorn crossbred cattle. Similar conception rates have been recorded in Sulawesi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little basic information on the banteng's reproductive physiology has been reported. However, it appears that this differs little from that of cattle. Sexual maturity has been observed as early as 13 months and mating at 16 months.* The gestation period is about one week longer than that of cattle and twinning is not common. At birth, males weigh about 16-17 kg and females about 14-15 kg (about half the size of Brahman-Shorthorn calves). Calves are not weaned at any specific time, and dams may continue suckling a calf until the next birth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng will crossbreed with domestic cattle, producing hybrids with notable vigor and heat tolerance (see chapter 2).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It has been reported that banteng have the ability to drink water with high salinity," and in northern Australia they have even been seen grazing seaweed on coral reefs at low tide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On high-quality diets, feed-conversion ratios approach those of other bovine species. For example, banteng bulls on high-concentrate diets have shown daily growth rates of 0.7 kg, compared with 0.7 kg in water buffalo, 0.8 kg in zebu cattle, and 0.9 kg in British cattle bulls.:"</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As the banteng matures, its weight remains lower than that of cattle of similar age. However, relative to mature liveweight, this disadvantage is only about 8 percent.§</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behaviour</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng cannot be handled as roughly as domestic cattle. Cows and calves are timid and easily upset. When stressed they may run into fences and walls, incurring head and spinal injuries. They also easily get into a state of shock. Special squeeze chutes and other special facilities, along with much care in handling the animals, are essential. However, despite their lively temperament banteng are docile if reared, as in Indonesia, with frequent human contact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These animals are promising beef producers. Gourmets consider banteng cuts among the finest of meats, and Indonesia cannot export enough to satisfy the demand in Hong Kong and Japan alone. The meat's outstanding characteristics are its tenderness and leanness. When the animals are maintained and finished under traditional village management, total fat content of the meat (both on a liveweight and carcass basis) is usually less than 4 percent. Little of the fat is deposited among the meat fibers (marbling); about two-thirds of it is mesenteric and the remainder is subcutaneous, laid down in small globules. The carcasses have a high dressing-out percentage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng have proved to be useful as draft animals for the farm but are reportedly less suitable than zebus for hauling carts on roads. Traditionally, both male and female animals are worked, but Balinese farmers normally use females for cultivating light soils only. Banteng are trained when they are about 2 years old and are reportedly easier to train than zebus.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like water buffaloes banteng can utilize low-quality feeds; they are similar in that they can live off forage unpalatable to cattle. It is rare to see banteng in poor condition. Animals of all ages appear to have an ability to maintain weight and body condition even when pasture quality is poor. In this respect, they have been noted to outperform cattle in Australia's Northern Territory. Moreover, due to their lower milk production banteng cows lose less weight and condition during lactation than, for example, Brahman-Shorthorn cows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In comparison with cattle (European breeds) kept under similar circumstances in Australia, banteng are less infested with external parasites. Their hair is short and their hide tough, which helps them resist ticks. Under field conditions few adult cattle ticks (Boophilus microplus) are observed on the animals, except on malnourished individuals, and the incidence of tick-borne disease is said to be very low. Sarcoptic mange is known to affect the animals, but it has a low incidence as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng also appear to tolerate several internal parasites. Liver fluke is probably the most prevalent. Although the animals themselves appear healthy at slaughter, some 80 percent or more of carcasses are found to have partially infected livers. In addition, intestinal worms are often present.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are only slightly affected by Asian trypanosomiasis (Trypanosoma evansi). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are poor milkers; their udders are almost invisible. The lactation varies from 6 to 10 months and milk production is only 0.9-2.8 kg per day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To keep from reverting to the wild state, banteng may need close contact with humans or regular handling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An unidentified banteng disease first appeared on Bali in 1964. Known locally as "jembrana," it spread rapidly, causing mortalities from 10 to 60 percent in certain localities. It was originally thought to be rinderpest; it is now believed to be caused by a rickettsia transmitted by cattle ticks. Outbreaks have occurred with decreasing intensity and virulence since the original outbreak. The disease is under intensive investigation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Bali ziekte," a disease affecting only banteng, has also been noted. It is characterized by dry eczema, followed by severe necrosis of the skin and exposed mucous membrances.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of their high susceptibility to bovine malignant catarrhal fever, banteng must not be brought in contact with sheep and some other animals. This virus is widely disseminated in sheep and several domestic and wild hoofed mammals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There have been few scientific studies of banteng and no coordinated attempt to improve their performance. They deserve more recognition and they merit testing in tropical locations outside their traditional home in Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The herds in northern Australia (descendants of animals remaining from an abortive colonization attempt in the 1820s) are in a relatively disease-free zone, and although they are feral, they can potentially provide animals for breeding and use in other nations. Although these few hundred banteng are a valuable resource, they are vulnerable to destruction if adverse environmental conditions arise or exotic diseases break out in Australia. Representatives of the herd should therefore be distributed and viable breeding stock established at several new locations. (Their genes and gene combinations may even prove valuable for the indigenous herds in Indonesia, and banteng research and development would make a valuable topic for cooperative research between Australia and Indonesia.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is particularly needed to identify the reasons for the banteng's apparent ability to maintain weight and body condition on poor-quality grazing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The problems of bovine malignant catarrhal fever, Bali ziekte, and jembrana need increased attention, particularly directed toward prevention and control. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p13.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">2 Banteng Cattle Hybrids</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng and cattle have the same number of chromosomes, and they will interbreed. Few scientific details on the hybrid progeny are available, but on the Indonesian island of Madura they are a "stabilized crossbreed" because they seem to be genetically uniform. This hybridization took place some 1,500 years ago, when Indian invaders brought zebus of the Sinhala, or Ceylonese, type to Madura and crossed them with the banteng.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These maduras reportedly show better growth rate than the pure banteng species itself. They are thrifty, hardy, and able to perform well under extremes of heat and poor nutrition. Though a hybrid in origin, both sexes of the madura are fully fertile. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For more than 15 centuries the winners of the bull races ("kerapan sap)") have been the herd sires of Madurese villages. This long breeding history has led to an animal with the following characteristics:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Long legs and small feet</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Elongated muscles of the rear legs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Heavy muscling over the back, loin, and shoulder</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Quick reactions and nervous temperament</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Great heat tolerance</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The ability to perform well as a work animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng-cattle hybrids vary in appearance, depending on whether European or zebu cattle are used in the cross as well as on the amount of backcrossing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maduras (banteng x zebu) are graceful animals. Their bodies are neat, compact, and deep, with well developed forequarters. The cows attain an average weight of about 210 kg and bulls range from 350 to 375 kg at maturity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Superficially, maduras are like Jersey cattle, except for having a much smaller udder. In most of them the banteng dominates the body structure and coat color. Bulls have a well-developed hump; females have almost none. There is no distinct dewlap. Horns are medium sized and curve upwards and slightly backwards. Ears are medium length and horizontal. Breeders on Madura accept only red-brown animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, crossbreeds of banteng and zebu are distributed throughout Indonesia. On the other hand, hybrids between banteng and European cattle have been made only in small programs in the United States and Australia. For example, researchers in central Texas are producing a cross that is one-eighth banteng/seven-eighths Charolais. They believe this will result in a beef animal able to grow well in warm, humid conditions. In the Northern Territory of Australia, no problems have been encountered in mating banteng bulls to Brahman-Shorthorn cows. Calves that are one-fourth banteng/three-fourths Brahman-Shorthorn have since been produced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Virtually all of the 575,000 "cattle" on the Indonesian island of Madura are hybrid animals resulting from crossing indigenous domesticated banteng with zebus. More than 200 head of banteng/Charolais hybrids are found near Easterly, Texas, and a score or so banteng/ Brahman-Shorthorn hybrids are on a research station near Darwin, Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The environment in Madura, where most of these hybrids occur, is monsoonal, with mean average temperatures as high as 31°C in the hot season, and dry spells as long as 5 months. It seems likely that judicious selection of the cattle breed could result in hybrids suitable for many other environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, the animals on Madura are bred to be raced. They are probably the fastest running bovines. From a standing start, a yoked pair pulling a sled can reach 50 kph by the end of the 130-meter course. An unencumbered individual can approach the speed of a horse (about 68 kph).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When compared with other bovine genotypes in Indonesia, the performance of these hybrids is more closely related to the banteng than the zebu ancestry."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the cross between banteng and European cattle all F1 bulls are sterile; their sperm development ceases at the secondary spermatocyte stage. Infertility also exists in most one-fourth banteng (although some sperm are present) and in all three-fourths banteng bulls. The fertility of the F1 cows, on the other hand, is high - 90 percent as compared with 70 percent for Brahman-Shorthorn cows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The hybrids have a lively temperament. However, when they are reared with other domestic cattle or handled on a regular basis, they are almost as docile as cattle. For instance, they remain calm even in Madura's extremely crowded towns. Nevertheless, personal contact probably must be maintained to keep them accustomed to human management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The cows are very protective of their calves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several reports from the livestock service of the former Dutch colonial government, as well as several books on the East Indies, state that meat from the madura is the tenderest of any known breed. In addition, the hides are pliable and superior to those of cattle and are used in the highest quality leather goods. They command a price about 20 percent higher than zebu hides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The breed is reportedly one of the best draft animals for its size in the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maduras have several desirable traits, including those outlined below:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Feed efficiency. With grain rations, yearling bulls can gain 1 kg on less than 7 kg of ration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Thriftiness. The breed can maintain its body condition on low quality forages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Heat tolerance. The madura has a high rate of cutaneous evaporation and is therefore well adapted to the tropical monsoonal climate. Teams of madura can plow or cultivate land for more than 6 hours, even at high temperatures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Carcass quality. The madura fattens readily on a high-quality diet and  produces carcasses with high dressing percentages, a large rib-eye area, and  high yields of lean meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· External fat thickness. A well-finished madura normally has only a slight  covering of fat over ribs and lower round. Maximum thickness (over the top  round) is less than 1.5 cm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Intelligence. These animals are responsive and easily trained. The famous  dancing cattle of Madura, for instance, are actually these banteng-cattle  hybrids.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Parasite resistance. Despite often high levels of fluke infections, the  animals continue to work, reproduce, and maintain body condition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maduras have been bred for one thing - speed. Some of their genetic  limitations are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Low birth weight. The calves begin small, weighing 12-14 kg at birth, and  they continue to be slow weight gainers. [Feeding trials with yearling bulls  have shown daily gains of over 600 g for 180 days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Poor lactation. Milk production is normally less than 1.5 lifers per day and lactation ends after about 4 months. The cows often fail to produce milk. Much of this is probably caused by poor nutrition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the important features of the madura is that its genetic variation has been largely removed during 1,500 years of continuous breeding; with study much valuable information could be obtained that is beneficial to all bovine breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following topics need further study:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Fertility levels</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Crossbreeding to test the effect of using a wider range of cattle breeds*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Assessment of the hybrid's advantages over the pure banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Performance under a wide range of environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">3 Mithan</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mithan (Bos frontalis) is believed to be a domesticated form of gaur (see chapter 6).t (However, it resembles the banteng and some authors have proposed that it is a gaur-cattle cross, others a gaur-banteng cross.) The mithan is a domestic animal indigenous to parts of India, Burma, and Bangladesh. Because of large size and the high butterfat content of its milk it is widely used to crossbreed with cattle in Bhutan. It deserves greater recognition both in Asia and elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mithan is a handsome animal. Bulls may occasionally exceed 1.7 m at the shoulder and weigh 1,000 kg, but the average bull is about 1.5 m tall and weighs 540 kg. Cows are shorter and weigh less.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal has a dorsal ridge on the crest of the shoulders, a small but pronounced dewlap, and a generally flat forehead. Mithan horns are often of unusual girth; they are straight or gently curving, and many have an enormous base that practically covers the top of the skull.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most calves and females are brown, but adult males are generally black with white stockings on all four legs. Some, however, are light brown, white, or piebald.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the hill ranges of Assam, where gaur are still plentiful and interbreeding between mithan and gaur frequently occurs, the mithans are massive and gaurlike. But in the Chin Hills, where gaur are scarce, the mithans have lost their bulky proportions, probably by interbreeding with cattle. With them, the high dorsal ridge on the shoulder (which lends so much to the imposing stature of the gaur) has disappeared, the horns are cowlike, and the varied coloring of the domestic cow begins to appear.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mithan are kept in a domesticated condition by the hill tribes of northeastern India (Mishmis, Mizo, Nagas), the Chittagong Hill tracts, and some Burmese hill ranges (Arakan and Chin Hills). It is the main domestic animal of the Nagas of Nagaland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In India feral herds totalling some 50,000 head roam the jungles of Arunachal Pradesh. Recently the Royal Government of Bhutan has established two herds by purchasing animals from Arunachal Pradesh. Bhutanese farmers have some 60,000 head of animals that are hybrids of mithan and the local breed of cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government of Bhutan is breeding mithans on government farms and distributing males to private breeders to improve the genetic base.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mithan is a grazing animal, but in some areas herds are allowed to browse freely in the woods; some return to the villages for protection at night, while others remain largely in the forests. The villagers keep the forest mithans nearby by providing salt, for which the animals have an insatiable craving.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Feral mithan live in the same habitat as gaurs and are said to move equally skillfully in mountainous terrain. Usually they are found at elevations from 600 to 3,000 m. However, in the Chittagong Hill tracts and the Mishmi country they descend to 300 m and lower, while in Bhutan they have been reported grazing in summer at altitudes as high as 3,300 m, for example around Thimphu.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p23.png"></center><br>
+ Mithan distribution. (after Simoons and Simoons, 1968)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mithans are fully fertile amongst themselves. Also, they interbreed freely with the gaur, banteng, yak, and cattle of both the taurus and zebu types. Naga owners encourage the interbreeding with gaur, regarding it as an improvement of the race. (They arrange this by placing salt licks in the forest. After gaur bulls have formed a habit of coming to the licks, mithan cows are left there and in due course mating takes place.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The crosses between mithan and zebu are also encouraged in certain districts. Unlike most crosses between bovine species, those between mithan and cattle result in fertile male and female offspring (although some owners indicate that the F1 male is not a reliable breeder).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is an unusually gentle animal with a quiet disposition, as revealed in the Chin tribe's expression "gentle as a mithan." Normally even a stranger is safe to approach one; if he gives it a bit of salt, it will usually follow him about. Thus, mithans are easily managed in a regular cattlerearing operation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many mithans are not domesticated in the strict sense. Their herds live in a semi-tame state near jungle villages and come to settlements only in the evening to lick salt.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some regions of northern India, mithans are used for field work and as draft animals. They are also important as a meat supply. The Bhutanese government is establishing a national dairy-mithan breeding program, which could result in a valuable dairy animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To many tribes of northeast India and Burma, mithans serve mainly as sacrificial animals. The Nagas use them as a kind of "currency" to pay for goods, to buy brides, and to pay penalties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hybrids resulting from backcrossing mithan with common cattle are also used as work animals. For at least a century, Bhutanese livestock breeders, particularly those in the eastern section, have mated mithan bulls to siri cows (Bos taurus) from India. This produces very profitable hybrid offspring that have high milk production. The milk is rich in total solids and produces exceptional yields of cheese and butter.* The male of the cross (called "jatsha") is a powerful draft animal, and the female ("jatshum") is a prized milk cow. To this day, extensive crossing continues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mithan is potentially an animal that can be used in difficult terrain where most domestic cattle breeds do not perform well. Mithans are superior when it comes to feeding on steep slopes and cliffs and for grazing native grass and the leaves of local fodder trees. They are also adapted to tropical and subtropical environments. And they are able to maintain themselves in small herds (6-10 head) in dense jungle.*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mithan could prove valuable in other parts of the world, and it could be important particularly for the genetic improvement of cattle in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If they are disturbed, mature mithans can be temperamental. They can be difficult to hold with normal fences or chutes, because of their size. When given injections or otherwise subjected to pain, they are liable to bolt to the jungle and not return.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The productivity of these animals needs to be better characterized and defined. Attention should be given to their grazing efficiency as compared with that of cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The two farms the Bhutan government has established for breeding mithans provide an opportunity to gather genetic information on the species and to have experimental matings take place to establish the most suitable animal for various conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The genetic relationship of mithan to gayal, gaur, and cattle needs to be clarified. Although it is believed that the mithan and gayal are the same animal, one of this report's reviewers points out that the mithan of Bhutan are strikingly different in color, body shape, and horn structure from gayals seen in zoos in Europe and India. Although the mithan is now considered a domesticated gaur, many in the past have claimed it as a gaur-cattle hybrid. Physiological research could remove lingering doubts. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p26.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">4 Yak</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The yak (Bos grunniens), is a grazing animal that is accustomed to traveling great distances in a harsh environment. Nothing is known about when it was first domesticated, but there has probably been a close association between man and yaks ever since the first humans migrated into the high mountains of Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated yaks are about the size of ordinary cattle and rarely exceed heights of 1.3 m at the shoulder. Their liveweight is generally 250-550 kg for the males and 180-350 kg for the females. They differ little from wild yaks except that they are smaller, have shorter and thinner horns, and may be rusty brown, black, silver grey, or piebald instead of black. Often they have whitish spots on their faces.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The yak's hair is long, especially on the flanks, where it forms a shaggy fringe that often reaches the ground. This, together with an underlying layer of thick, fine wool, protects the animal from the bitter cold of its native region. The yak has an enormous tail with a brush of long hair coming from its root, which is rare in bovines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Long extensions of the thoracic vertebrae give the yak shoulders that look like a hump, but this is different from the boneless hump in zebus. The body is long, short-legged, and compact, with particularly large forequarters because, like the bison, the yak has 14 or 15 pairs of ribs instead of the 13 of domestic cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The horns spread outward and upward, and the head is held low, like that of the bison. While no hornless domestic yaks have been reported in Nepal, more than 90 percent of those found in Mongolia lack horns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most yaks are found especially in the mountains and plateaus of Tibet and western China, however they occur from northern Afghanistan, Pakistan, India, and Bhutan to Mongolia, and the Soviet Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are more than one million domestic yaks in the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Himalayas the domestic yak is almost always found above 2,000 m elevation. Males are sometimes brought as low as 1,700 m for mating with cattle (see chapter 6), but they do not fare well at such altitudes. In Mongolia and Buryatiya (U.S.S.R.), however, they are found as low as 1,500 m elevation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY"><center><img src="p29.png"></center><br>
+ Yak distribution. (after J. Bonnemaire, 1976)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The wild yak lives in desolate mountain areas at altitudes of 4,000-6,000 m. Its habitat is the alpine tundra and the cold desert regions of the northern part of the Tibetan plateau. These barren mountain regions are remote and at higher elevations than the zones of human habitation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yaks look ungainly, partly because they are covered with long hair, but they are agile climbers and can maneuver narrow mountain paths. Their long hair is one adaptation to the cold climate. Other adaptations are the small, compact scrotum of the male and udder of the female, the small teats (only 2-3 cm long) and covering of hair over the udder, and the covering of short hair over the muzzle, except just around the nostrils.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In early summer yaks graze the lush grass in valley bottoms, but for much of the year they live on dry, coarse mountain grass and for long periods obtain water by eating snow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The gestation length is 258 days - slightly shorter than that of cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domestic yaks are docile and easily managed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yaks are especially useful as riding and pack animals; they can manage loads of more than 150 kg. At altitudes up to 6,000 m they may carry a pack or a person at a steady pace for days and still remain in good condition. In some regions they are the only feasible pack animal. Yak bulls (generally castrated) are also used for plowing and for threshing grain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Occasionally the yak is slaughtered for meat. The meat is particularly important in parts of the USSR and in Mongolia, where in the cold, high-altitude environments it reportedly costs only half as much to produce as beef.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most areas milk production is an essential aspect of yak husbandry. Yields vary considerably according to management and nutrition, but they average about 600 kg and can be more than 1,000 kg per lactation. Yak milk is golden colored. It is much richer than cow's milk; a typical analysis is: total dry matter, 17.35 percent; fat, 6.5 percent; protein, 5.3 percent; and sugars, 4.6 percent. The fat globules are much larger than those in cow's milk. People of Tibetan stock use yak butter as a food staple and as a lighting fuel.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yak hide, though apparently not as good as that of cattle, is used for many purposes. It makes outstanding saddles. Yak hair is used for making ropes, saddle blankets (purportedly the best in the world), grainstorage bags, and tents. The fine wool that occurs beneath the long hair is used for making felt. The annual yield of adult females and males is about 750 g and 1,600 g of hair and about 350 g and 600 g of wool, respectively.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because yaks are often found above the timberline their dung is an important fuel in many areas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yaks can live and work hard in a cold climate. They are the only bovines to thrive at high altitudes. In cold, high areas they can work and produce meat and milk more efficiently and cheaply than cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yaks are not well able to eliminate surplus heat because their heavy coat reduces their ability to sweat. In warm climates their respiration rate and body temperature increase and they become exhausted and susceptible to infections. At low altitudes in Nepal yaks die of a variety of diseases. Apparently not even yak-cattle hybrid animals (see next chapter) can successfully live below 700 m in that part of the world. This is probably due to overheating, since during the first half of this century yaks grew successfully in trials at low altitudes in Alaska and northern Canada.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yak improvement programs are much needed. It seems probable that the genetic potential of the species is far from realized because Buddhist beliefs oppose the deliberate killing of stock. Techniques for deep freezing yak semen have been successfully developed at Regents Park Zoo, London and should prove invaluable for improving the breed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· As a result of uncontrolled hunting the wild yak is endangered and is now restricted to remote barrens on upland plateaus and highlands in northern Tibet and Chinghai, inhospitable even to domestic yaks. The numbers of wild yak are unknown. They require total protection throughout their range and the establishment of adequately protected reserves with good pasture. To preserve their genetic purity, it is important to isolate wild yaks from domestic yaks and thus keep them pure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· A primary need is to catalog the numbers and locations of purebred yaks. Today we have little idea of the total breeding population. Gathering such information is difficult, owing to the geographical isolation of the communities involved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· It is also important to catalog the movement of yaks between different areas to see if enough genetic exchange occurs to prevent inbreeding of the population. Exchanges between local pastoralists were much more frequent in the past (for example, between Tibet and Nepal), but this is now more difficult because of border restrictions and because many yak </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">herders that used to move herds long distances have become sedentary farmers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Breeding strategies, herd management, product processing, and herd hygiene in Nepal, Bhutan, Sikkim, northern India, and northern Pakistan, Tibet, Mongolia, and the Soviet Union all differ greatly. It is important to get an overall perspective so that the strengths of the different systems can be judged and the weaknesses reduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· There are clearly different domestic yak "breeds" in terms of their appearance, and these need to be identified and compared systematically. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p33.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">5 Yakows</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yaks and cattle have the same diploid number of chromosomes (60). And in the regions where yaks are found, they are often interbred with cattle, either the humpless cattle (Bos taurus) of Tibet and Mongolia or the zebu (Bos indicus) of South Asia. As with mules, the hybrid offspring of cattle and yak surpass their parents in strength and vigor. Yakows* grow faster than their parents, and they suffer less from high temperatures than yaks. The hybrid cow reaches sexual maturity earlier and yields larger quantities of milk than the yak cow. The males, however, are sterile.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The yakow's appearance varies with the type of cattle used in the cross. But because of the phenomenon of hybrid vigor (heterosis), the hybrids are considerably bigger than the mean size of their parents. (For instance, in one test the liveweight was approximately 18 percent higher than the average weight of the parents.) The hybrids also excel in hardiness, working ability, growth rate, and milk production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, their appearance and performance is closer to that of the mother than of the father. Because of this, the yakows can be "custom designed" for various altitude zones. For example, the farmer at lower altitudes may produce cattle-like yakows by breeding yak bulls to domestic cows, while farmers at higher altitudes would use the reverse cross.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Yakows have shorter hair and a much less downy undercoat than purebred yaks. They are similar in color to yaks. (In Nepal, black is most frequent, but brown shades and even white may occur.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yakows are found in parts of northeastern Afghanistan, northern Pakistan, northeast and northwest India, Nepal, Sikkim, Bhutan, Tibet, western China, Mongolia, and southeastern Russia. They are found notably in the Himalayan region of Nepal, where they are bred by people of Tibetan culture and language. Sherpas, for instance, supply hybrid cows and heifers to dairy farmers throughout northeastern Nepal. Hybrids are also much bred in Ladakh (northern Pakistan) and Mongolia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whereas farmers in Nepal tend to use zebus to cross with yak, the inhabitants of the Tibetan plateau generally use Bos taurus cattle. People in some areas favor mating yak bulls to cows, while those in other areas prefer the reverse. But even within one village there can be a degree of specialization by different families, depending on wealth and the location of traditional grazing grounds. Generally, however, the crosses between domestic cattle bulls and yak cows are the predominant ones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The number of yak-cattle hybrids in the world is unknown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the yak, the hybrid can live in cold, barren, upland terrain, but it has the advantage of being able to adapt to lower altitudes. In winter, caravans of hybrids may come down as low as 1,600 m in some parts of Nepal, and hybrid herds (especially those resulting from crossing yak bulls with zebu cows) can spend several weeks grazing at altitudes as low as about 1,700 m in winter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Female hybrids are fertile when mated with either parent stock. Male hybrids, however, are sterile. Although they have fully developed secondary sexual characters and show libido, their testes do not produce spermatozoa because the seminiferous tubules are poorly developed and the spermatogonia and their nuclei are degenerate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A few normal or motile spermatozoa may be found in the semen of backcrosses of the F1 hybrids to either parent, but as a rule the spermatozoa are normal and dead.* Backcrossing is reportedly not common, however, as the progeny do not retain hybrid vigor.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tibetan farmers prefer the hybrids for plowing because of their docile temperament. The yak is said to be more stubborn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The hybrids are valued as beasts of burden and draft, and are often preferred over yaks. Male hybrids are generally castrated at about 3 years of age so as to increase their strength and size.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where pastures occur over areas of greatly varying altitude, the use of hybrid livestock is likely to be more efficient, in biological terms, than the use of yaks or cattle. By judiciously selecting cattle, yaks, or hybrids all altitudes from sea level to above 5,000 m can be utilized with best efficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The hybrid's milk is intermediate in composition between that of its parents. However, hybrids yield up to 7 kg of milk per day against the yak's 3 kg. (It seems that the hybrid derived from cattle bull and female yak produces considerably more milk, with a higher fat content than that derived from yak bull x cattle female.) Also the female hybrids produce larger quantities of milk than Nepalese zebu cows on the same hill pastures. They also produce a calf each year, while under normal herd management yaks tend to produce a calf every 2 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hybrids do not tolerate extremes of altitude or cold as well as purebred yaks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The normal gestation period for yaks is about 1 month shorter than that of cattle, and the gestation period for a hybrid is intermediate between that of the parents - hence there may be problems at calving when a female yak is sired by a bull from a large cattle breed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is needed to identify differences in altitude tolerance between various hybrids. This should include measurements of hemoglobin count, respiration rate, and pulse rates at different altitudes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Studies are also needed on all production characteristics, particularly on the meat and milk production potentials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cataloging the breeding strategies of different areas where hybrids occur would be useful, along with a historical perspective.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research to determine the most productive hybrids by crossing different yak and cattle "breeds" in areas with different environmental conditions could be extremely useful. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part II : Wild Bovine Species</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In various parts of Southeast Asia there exist little-known relatives of cattle and water buffaloes. Many of these wild animals are close to extinction, and attention is drawn to them in hope their populations will be preserved. All of them survive in tropical regions subject to environmental extremes - flooding annual rains, searing droughts, and swarming pests and parasites. These are conditions to which conventional livestock are poorly adapted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">None of Africa's bovines is threatened with extinction, and both the European and American forms of bison are being preserved by governments and individuals. In Asia, however, there has been an alarming drop in the numbers of wild water buffalo, wild yak, wild banteng, kouprey, gaur, and tamaraw in recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This section describes:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Wild banteng</P>
+<P ALIGN="JUSTIFY">· Gaur</P>
+<P ALIGN="JUSTIFY">· Kouprey</P>
+<P ALIGN="JUSTIFY">· Tamaraw</P>
+<P ALIGN="JUSTIFY">· Anoas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If not molested, many of these animals can thrive side by side with human settlements. They may therefore have an important future role in the development of the tropics. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is little point in conservation for conservation's sake, but loss of irreplaceable resources through ignorance, greed, or thoughtlessness should be avoided. It may be that these Asian animals have little merit other than their uniqueness, but at the very least, sufficient numbers should be conserved until we have time to find out. A. J. SMITH Royal School of Veterinary Studies, Edinburgh, Scotland </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rapid human increase and relative poverty deny hope that any land can lie idle when so many would be robbed of an opportunity simply to exist. For wildlife to survive, let alone at its breathtaking best, we must think of new and better ways to justify its future, preferably by having it contribute to the welfare of those hard-pressed humans who inevitably are further disadvantaged by the creation of national parks. DAVID WESTERN New York Zoological Society, Bronx, New York, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is an urgency to conserve and study nontraditional animal species, especially for use in the environmentally challenging tropical areas of the world. The philosophy plant scientists apply to exploring the potential of the plant kingdom needs to be more enthusiastically adopted for the world's animal species. G. W. M. KIRBY, Principal Animal Production Officer Department of Primary Production Darwin, Australia</P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY"><center><img src="p40.png"></center><br>
+ GAUR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">6  Wild Banteng</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The wild banteng (Bos javanicus)* are the most cowlike of all the wild bovines and are the parent stock of the 1.5 million domesticated banteng in Indonesia (see chapter 1). They have a scattered distribution throughout Southeast Asia, and three subspecies are recognized:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The Java banteng Bos javanicus javanicus (Java and Bali)</P>
+<P ALIGN="JUSTIFY">· The Borneo banteng Bos javanicus lowi (Borneo)</P>
+<P ALIGN="JUSTIFY">· The Burma banteng Bos javanicus birmanicus (Burma, Thailand, Indochina).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng have been called the most beautiful of all wild relatives of cattle. The cows are usually a vibrant reddish brown, while adult bulls are mostly blackish-brown and sometimes even blue-black (although in Burma and Indochina bulls remain golden brown like the cows, and in Thailand a few banteng have been recorded with white, deerlike spots on their brown coats). Both sexes have white "stockings" and a large white patch on their rumps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng are larger than their domesticated counterparts. Average-sized bulls of the Java and Burma subspecies stand 1.6 m high and weigh 635 kg, but bulls as large as 1.9 m and 825 kg have been recorded. Cows average 1.4 m in height and weigh 400 kg. The Borneo subspecies is smaller.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The horns of banteng bulls are angular, turning out and then up, with inward-pointing tips and reaching a spread of 60-75 cm. The horns of cows are short and crescent shaped. There is a patch of thick, naked skin between the horns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are found in restricted localities scattered over an area ranging from the northeastern edge of India, through Burma, Thailand, the northern Malay Peninsula, central and southern Indochina, and the islands of Borneo, Java, and Bali.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only a few thousand wild banteng survive, and their numbers are decreasing. Most populations are endangered because their habitats are being encroached upon by the growing human population. In Sabah, Malaysia, for example, the areas where an estimated 300-550 banteng (the last remaining herds) occur are scheduled for conversion to permanent agriculture. The animals are being forced to use smaller and smaller habitats, thus increasing losses caused by malnutrition, diseases, and parasites. In addition, throughout much of the animal's range, hunting, military operations, and perhaps interbreeding with domestic cattle are further reducing the original stocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY"><center><img src="p43.png"></center><br>
+ Distribution of wild banteng. (courtesy of C.H. Wharton)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The banteng's general distribution lies in the zone of deciduous monsoon forest in Southeast Asia. Habitats vary between the extremes of dry wooded parkland with large grassy plains to tropical rain forest with small clearings. The animals prefer flat or undulating terrain. In northern Kampuchea and eastern Java, they inhabit grassland savannas. In western Thailand, they live in a belt of grass and bamboo thickets along upper slopes of dry mountains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng inhabit sites from sea level to around 2,000 m elevation. They avoid large human settlements and plantations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most areas there are no pronounced hot or cold seasons, but dry seasons can be long.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng prefer feeding on grass, but are fond of herbs, leaves, fruits and blossoms, as well as the sprouts of trees, brush, and young bamboo. Under favorable conditions they drink daily, preferring standing water. During droughts, they seem able to survive several days without water. In coastal areas where there are no mineral licks they can meet their need for salt by occasionally drinking seawater. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sex ratio at birth is 140 males to 100 females, but mortality of bulls is heavy and the adult ratio is about three cows for every bull.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Calves are suckled until they are 14-16 months old.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In undisturbed conditions, the banteng's daily activity has a more or less fixed rhythm. During daytime, the animals alternate active and resting periods of 2-3 hours each. The active periods predominantly involve feeding, drinking, and social interactions. While resting, the animals commonly ruminate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As a reaction to heavy rains or human disturbances, the animals retreat into dense vegetation. In regions with frequent human disturbance they generally appear in the open only at night. However, where they find particularly suitable localities they become somewhat accustomed to human presence and will venture out in daylight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng live alone or in small groups of up to eight members. Males separate from their mothers at an age of 2-3 years. Sometimes female calves continue living with their mother even beyond maturity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cows and dominant bulls command the best pastures, and young and weaker bulls roam widely, rarely leaving the protection of the thick forest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The banteng bull has a reputation for extraordinary savagery, but stories of its lightning attack have been exaggerated. Wildlife biologists in Indonesia have not been able to document any such attacks and have no qualms about walking in banteng habitats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng show important promise for improving domesticated banteng (see chapter 1) or for interbreeding with cattle (chapter 2). Almost 170 years ago Sir Stamford Raffles, founder of Singapore, noted that in Java "The degenerate domestic cows are sometimes driven into the forest to couple with the wild benteng, for the sake of improving that breed."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tourism could be developed in areas where these magnificent animals occur.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng are large, robust animals fully at home both in the heat and humidity of the wet season and in the hot dry season. Their genetic </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">endowment for such tolerance could be of significant value fin improving domestic stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Possible Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild banteng may prove to have a special susceptibility to diseases of domestic animals. Blackleg (Clostridium chauvoli) and mucosal disease have caused heavy losses in banteng in European zoos.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capture of wild banteng may prove difficult.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research on the physiology, production potential, and possible uses of wild banteng is needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hunting and destruction of its habitats menace the wild banteng over all of its range. The only promising means for conservation is creation of nature reserves where hunting and forest destruction are forbidden. Conservation efforts should particularly include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Supporting government of Thailand efforts to conserve banteng in western Thailand and the Petchabun Range;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Cooperating with the Burmese government in surveys to locate the best banteng habitats;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Cooperating with the governments of Kampuchea and Laos to identify banteng habitats and establish appropriate protective measures; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Carrying out research in Java's nature reserves (Ujung Kulon National Park and Baluran Reserve) to ascertain the genetic distinctiveness of the banteng, its status, and its characteristics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Sabah and other areas of Southeast Asia there are cattle breeding projects that use imported stock exclusively. Experimental crossbreeding of local banteng with this stock should be encouraged. There are some feral and domestic banteng, as well as hybrids between wild banteng and feral cattle, that should also be tested.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p45.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">7 Gaur</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The gaur (Bos gaurus) would seem to be an ideal meat-producing animal. It is a large bovine with massive muscular development, and it has already been domesticated (see mithan, chapter 3). Gaurs, which are threatened with extinction, deserve much greater attention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two subspecies of gaurs are recognized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Bos gaurus gaurus (India, Nepal) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Bos gaurus laosiensis (Burma, Thailand, Laos, Vietnam, Kampuchea, West Malaysia). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With its huge head, massive body, and sturdy limbs, the gaur is the embodiment of vigor and strength. It is among the biggest of bovines. Bulls weigh 600-940 kg and stand 1.6-1.9 m tall at the shoulder, but a record bull of 2.2 m and 1,225 kg has been recorded. Cows are only about 10 cm shorter in height, but they are more lightly built and weigh 150 kg less.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On their shoulders gaur bulls have a striking muscular ridge that slopes down to the middle of the back, where it ends in an abrupt dip. The horns are crescent shaped, creamy yellow, and taper to a sharp point, which is usually tipped in black.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Newborns are a light golden yellow, but soon darken to coffee or reddish brown, the color of young bulls and cows. Old bulls are jet black, their bodies almost hairless. Gaurs have light colored forehead and yellowish or white stockings. Their eyes are brown but in certain lights, because of reflection, they appear blue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs excrete an oily, aromatic sweat, unique to this species and to the mithan. It gives the animals a strong bovine smell and may be an adaptation for keeping away insects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Once common throughout South and Southeast Asia, gaurs now survive only in scattered remnant herds of up to 30 animals in the hill forests of India, Nepal, Burma, Thailand, Laos, Kampuchea, Vietnam, and the Malay Peninsula.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY"><center><img src="p48.png"></center><br>
+ Gaur distribution. (courtesy of C.H. Wharton)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Historically, the largest concentrations have coexisted with farmers in areas of shifting cultivation. The animals adjust to disturbed land, and they also adapt to man's presence if not unduly harassed. For example, gaurs will feed in agricultural fields, along roadsides, and near occupied houses. Herds in national parks feed peacefully while tourists stand by. Gaurs in zoos also become quite tame and manageable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Populations not protected in parks and reserves are in immediate danger of extinction. Even in the remotest hill forests gaurs are harassed by hunting, exposed to the diseases of domestic cattle, and driven from their natural habitat by human invasion. Most herds outside of parks or wildlife reserves are threatened by agricultural development, hydroelectric dam projects, human settlement, or extensive logging.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In India, large populations still exist in the larger sanctuaries such as </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mudumalai and Kanha Park. In Thailand diseases carried by domestic animals, poaching, and habitat destruction have reduced total gaur numbers to fewer than 500. In Malaysia, the population is estimated to be only 400 animals. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs typically live on gentle, undulating terrain with natural mineral licks. They inhabit gaps in the forest, such as abandoned clearings, where they can find grasses and shrubs. In the northern portions of their range, they inhabit deciduous and semideciduous hill and mountain forests with light brush and many grassy clearings. In the lowlands they live in open bamboo jungles, grassy plains near forests, or dense forests broken by glades or open meadows. (In the forest they probably depend to some extent on the slash and burn agriculture of hill people.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals appear to be adapting to increased human presence. They make use of such man-modified habitats as logged forests and fringe areas of agricultural estates that abound with grasses and early secondgrowth vegetation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs are combination grazers and browsers. They feed on the grasses of forest openings as well as on the young leaves, fruits, twigs, and bark of shrubs and juvenile trees. In one study in Malaysia, grasses comprised 41 percent of their diet, fortes 23 percent, and woody browse 36 percent."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs develop large muscular bodies and maintain excellent condition on relatively low-quality feed. In the Malaysian study, crude protein content of grass species varied from 7.0 to 7.6 percent and phosphorus content varied from 0.11 to 0.17 percent; yet calves reached weights of 300 kg or more during their first year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Birth and survival rates of up to 100 percent have been reported for wild gaur populations. Calves are born at any time of the year. The gestation period is 270 days, a little shorter than for banteng or domestic cattle and longer than for yak or kouprey.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Captive gaurs calve first at 2.5 years of age.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The gaur interbreeds with the mithan, and both have a diploid chromosome number of 2n = 58.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By nature gaurs are shy and timid. As with most wild bovines, their hearing and eyesight seem comparatively poor. Their defense lies in their massive size and acute sense of smell. When a herd with juveniles is threatened by a predator, the adults form a protective circle around the young. Although individuals retreat from danger if they can, they have a unique form of threat: they approach their opponents broadside instead of head on, displaying the huge muscular body and dorsal ridge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In common with other wild bovids, gaurs habitually visit mineral licks, which appear to be necessary to their habitat and influence the herd's movements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike water buffaloes, gaurs do not wallow. They take cover in the forest during the heat of the day and may feed at night and in the early morning during hot weather. In populated areas such as near agricultural estates, they may feed only at night to avoid people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the past, gaurs associated in loose herds of up to 400 animals, but today groups of only 5 to 12 animals are normally found. The herds, which are of more stable composition than those of banteng, are separated by sex for most of the year; however, during the rut stronger bulls form a series of "tending bonds" with estrous cows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs are thought to be interfertile with domestic cattle. If so, their attributes of size, massive muscular development, tolerance of heat and humidity, and resistance to diseases and parasites can contribute to beef production in the tropics. A gaur-cattle hybrid might also have immunity to some cattle diseases; if it retained the mild temperament of the domesticated parent, an extremely powerful beast of burden could be produced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The gaur is a truly majestic animal. Its habit of using grassy forest clearings and salt licks makes it a likely tourist attraction in parks and reserves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a climate and environment where domestic cattle are susceptible to heat stress and parasite infestation, gaur thrive and maintain body condition. Further, they are able to develop large muscular bodies and maintain excellent body conditions on relatively low-quality forage by feeding on a variety of woody browse, grasses, and fortes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Retaining its wild instincts for survival, the gaur is better able to withstand predator attacks them domestic cattle. This could be an advantage when animals graze in remote areas. Adult gaurs are strong enough to defend themselves against a predator as powerful as a tiger. In addition, they are also very protective of their young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs have little immunity to some cattle diseases. In many regions of India, cattle driven into the forests to graze infect gaur herds with rinderpest, foot and mouth disease, cattle plague, and other contagious diseases. Severe losses occur. Gaurs also appear very susceptible to malignant catarrhal fever.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaur numbers are declining throughout their range. If this trend is not reversed, it could effectively prohibit the use of gaur for domestication or crossbreeding purposes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs are shy and excitable, making them difficult to catch, but once in captivity the animals calm down. Second generation zoo populations are easily worked and handled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaurs on occasion damage cultivated crops such as young rubber trees and cassava. They require sturdy and well-kept fences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Southeast Asia there is special need to support the efforts of the governments of Malaysia and Thailand to conserve this species and to identify important gaur populations. Similar protective measures are needed in Burma, Laos, Kampuchea, and Vietnam.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is needed to establish and manage new gaur herds in forest reserves and build up the gaur population in the world's zoos. Techniques have been developed to capture and release wild gaur safely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fertilized gaur ova have been successfully transferred into a foster Holstein cow. The cow carried the gaur fetus to a successful delivery. This could be the forerunner of an important means of rapidly expanding captive herds by transferring gaur embryos into cattle in different parts of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is also needed on the basic physiology and production potential of gaur.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crossbreeding experiments should be started immediately to establish the degree of interfertility between the gaur and other bovine species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p52.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">8 Kouprey</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kouprey (Bos sauveli) is the most primitive of living cattle. Its features are typical of some forms that existed in the Pleistocene era, 600,000 years ago. Discovered by Western scientists only in 1937, the kouprey was the last large mammal to enter the biology books. It is perhaps the most primitive of living cattle and is closely allied to Bos namadicus, the wild ancestor of zebu cattle. In 1964 it was declared Cambodia's national animal. It is now perilously close to extinction, and for a decade no koupreys have been observed close enough for a positive identification by a specialist. In 1982, however, five of the animals were believed sighted in Thailand, near the border with Kampuchea. Thus there are hopes that the kouprey still exists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kouprey is large. Males stand 1.5-2 m high at the shoulder and may weigh 900 kg. Females are approximately three-quarters the height and weight of the males. The body is slender and long-legged. The hump from the withers to the center of the back is smaller than that of the gaur, but larger than that of the banteng. There is a well-developed dewlap from the throat to the mid-chest, which in old animals is sometimes so pendulous that it drags through the grass in front of the forelegs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young bulls are gray, with black on the head and dewlap. Old bulls are entirely black and cows are mouse gray or dullish light brown. As in the gaur and the banteng, the lower parts of the legs have white stockings, but kouprey stockings have a streak of dark hair down the front.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Kouprey. (P. Pfeffer)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey horns are among the longest and widest of any bovine. The tips of the adult male horns are surrounded by rough, frayed tissue caused by the animals' habit of digging in the soil with their horns. The females have slender, lyre-shaped horns that corkscrew upwards, unlike those of any other wild or domesticated cattle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey are said to have a grace more reminiscent of deer than cattle. They move at a light trot, as fast as 32 kph.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kouprey's prevalence in ancient times is evidenced by prehistoric cave-paintings in Kampuchea. The animal was also a favorite of the ancient Khmers, who carved kouprey statues and featured the animal in bas-reliefs on temples, including the monuments of Angkor Wat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, whatever kouprey exist are restricted to an area along both sides of the Mekong River in northern Kampuchea, the Dangrek Range, and other parts of eastern Thailand to the far south of Laos, and to the westernmost part of Vietnam. Although one or two small herds may still exist in remote pockets of Laos and Vietnam, the bulk of the population has always been centered in Kampuchea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are no koupreys in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of their large size, gregarious behavior, comparatively low reproductive rate, and preference for open areas, kouprey are vulnerable to hunting. The impressive horns and other tissues are valued as trophies and as medicinals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1964 it was estimated there were about 500 kouprey in Kampuchea, but by 1970 fewer than 70 were left. The subsequent fate of the species is unknown because of the years of warfare in the area. (Early in 1970, the three nominal kouprey reserves of Kampuchea were overrun by military forces.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p55.png"></center><br>
+ KOUPREY DISTRIBUTION. (AFTER C.H. WHARTON )</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1975 the kouprey stocks in Laos and Thailand were estimated at only 50 and 20 animals, respectively. By now, hunting and habitat destruction probably have all but eliminated the kouprey from Thailand. However, a reported sighting of five animals that had strayed across the border from Kampuchea was made in July 1982. (By the time Thai zoologists arrived to investigate, the herd apparently had crossed back into Kampuchea.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the banteng, the kouprey inhabits open sites such as light savannas, woodland meadows, and scattered glades in the monsoon forests. It is adapted to dry country. This type of habitat is not widespread in Indochina, and the range of the kouprey is consequently limited.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey spend most of the year among low rolling hills in open areas where grazing and visibility are good. These open areas are a fire climax mosaic of dry dipterocarp savannas and patches of dense forest. Fires occur each dry season, most of them deliberately set by man. Kouprey capitalize on the young growth in burned-over areas. They feed primarily on grasses, sedges, and tree leaves. They also require salt licks and a supply of water in the dry season.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The gestation period is thought to be about 8.5 months. Cows leave the herd before parturition and return with their calves after about a month. They nurse their calves for about 6 months.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey are said to be even more shy than banteng and gaur. They feed in erratic patterns and are always alert and nervous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Loose herds of 20 or more have been reported. These were of mixed composition, often with more than one adult male, and were usually led by an old female. Adult bulls sometimes form bachelor herds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey utilize some of the same feeds as wild banteng, and the two animals often live in a loose association. They graze together, and, especially after the mating season, solitary kouprey bulls often associate with banteng herds. The two species do not, however, interbreed in the wild. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kouprey is a candidate for domestication and has important potential as breeding stock. It is a wild animal, but it may have been domesticated temporarily during the Khmer culture, 400-800 years ago.* Both Vietnam and Laos have cattle breeds that resemble kouprey, and a kouprey bull, reputed to be a domestic animal of the Stieng tribe, was exhibited in the Paris Menagerie in the mid-nineteenth century. It may be that kouprey are domestic even today in parts of Indochina.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey survival has worldwide significance. The animals could be important for studies of bovine evolution and as a genetic resource for crossbreeding to improve disease resistance and other characteristics of domesticated bovines. For instance, the kouprey is thought to be resistant to rinderpest, a killer disease of domestic cattle. Also, kouprey bulls are distinctive for their long dewlap, and they probably have more skin area for their weight than other bovines and are therefore better able to eliminate body heat. This genetic trait may help large cattle breeds survive in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kouprey's potential may be moot - there may be none left in the world. It is feared that the warfare of recent years may have caused its extinction. However, if enough animals survive and can be protected, the kouprey could probably recover its numbers, as a higher calf-to-cow ratio (1:3) was reported for this species than for either banteng (1:4) or gaur (1:10).*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If wild kouprey are found, their capture is likely to be difficult.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a long-term sequence of research needs for the kouprey, which includes the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">.  Working with the governments of Thailand, Laos, and Kampuchea to identify any remaining pockets of this species and to establish conservation programs;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Establishing one or more captive breeding herds (because there is little chance of the animal surviving in the wild owing to the fighting and turmoil in the area);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Studying the animal's basic physiology and production potential;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Exploring its possible commercial utilization; and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Investigating the kouprey's genetic relationship to zebu cattle and the transferability of genetic characters through interbreeding. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p58.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">9 Tamaraw</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tamaraw (Bubalus mindorensis) is related to the water buffalo, one of Asia's most important animal resources, but it has never been domesticated or studied and is threatened with extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tamaraw looks rather like a miniature water buffalo of the swamp type that is found in Southeast Asia. It reaches about I m in height and 300 kg in weight. It is much more stockily built and is blacker than the swamp buffalo. The tamaraw has white marks on the fetlocks, instead of completely white lower legs like the banteng, gaur, and kouprey. It has short (35-50 cm), very stout horns that curve out and back slightly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Endemic to the Philippine island of Mindoro the tamaraw is now virtually restricted to three small areas (Mount Iglet/Mount Baco, Mount Calavita, and Sablayon) in Mindoro Occidental.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its limited distribution, the tamaraw's future is of concern to conservationists. Until World War II, hunting was carefully regulated in its native region and no serious concern was felt for the animal's safety. Since then, however, increases in human population, lumbering, and ranching have restricted the tamaraw's habitat, and the availability of rifles and automatic weapons has seriously threatened its numbers. In 1971, research teams counted 148 head, consisting of 116 adults and 32 calves. The latest estimate is 150-200 head.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of these last remaining animals, about 80 are located at Mount Iglit, a game refuge established in 1961 primarily to protect the tamaraw. Recently an active tamaraw conservation program has been started in a 400-hectare enclosed area on the refuge. Stockade traps have been built and tamaraw are beginning to move into them. The goal is to establish a small, semicaptive population that can be properly guarded, studied, and managed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY"><center><img src="p61.png"></center><br>
+ Tamaraw distribution. (courtesy Wildlife magazine)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The habitat requirements of the tamaraw appear to be fairly flexible, and present habitat use reflects human pressures rather than the animal's preferences. In the past, tamaraw were found in virtually all parts of Mindoro, from sea level to mountain tops. They occupied open grasslands or glades, but hunting pressure and habitat change have forced it to retreat into forest environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present the tamaraw is found primarily in remote areas that have been partly cleared, largely by fire, so that only small pockets of trees remain among coarse grasses such as Imperata cylindrica (a widespread, unpalatable tropical weed commonly called cogon, kunai, alang alang, lalang, or blady grass), and "tahalib" (Saccharum spontaneum). The tamaraw uses the forest pockets for rest and retreat and the open land for grazing. It must have a supply of water for wallowing and drinking.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to cattlemen, tamaraw eat both Imperata grass and tehalib but only when these are short and green. During the wet season when most forages are tall and unpalatable, the animals are known to feed on bamboo shoots.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy is about 20 years. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tamaraw are reputed to be nocturnal, ferocious, and retiring. However, in earlier times they were reportedly relatively tame, diurnal animals of open areas. It was the continual hunting that made them increasingly nocturnal and secretive, and like other wild bovids they can become aggressive and dangerous when harassed or wounded. Given effective protection they doubtless would revert to placid, diurnal behavior.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tamaraw appears to be a possible livestock animal. Its meat and hides were highly regarded by local peoples, cattlemen, and visiting hunters. Because of its close relationship to the water buffalo, it may be able to provide genetic material for improving the health and hardiness of that valuable animal resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal is renowned for hardiness and resilience to heat, humidity, and poor forage, as well as its capability to thrive in a variety of environmental conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tamaraws have only once produced offspring in a zoo and may prove difficult to raise in captivity. However, they have been kept in captivity so seldom that the prospects are unclear. Experiences with other wild bovids suggests that captivity and captive breeding should be no problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tamaraw must be protected and preserved. There is urgent need, for example, to establish more secure parks in the Philippines to rebuild the wild population to safe levels. Other conservation measures should include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Establishing and maintaining more reserves in natural habitats containing breeding populations, and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Building up breeding populations in suitable zoos and livestock research centers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is needed on the tamaraw's physiology, production characteristics, behavior, and genetic relationship to the water buffalo. None of these is well understood. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p63.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">10 Anoas</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The lowland anoa (Bubalus depressicornis) and the mountain anoa (Bubalus quarlesi)* are small bovines that are related to the water buffalo but that are scarcely bigger than goats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Compared with other bovines, the anoa is tiny. It stands only 0.75-1 m tall at the shoulder. The mountain anoa is smaller than its lowland counterpart. The limbs are short, the body plump, and the neck thick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoa horns are short and straight, reaching a maximum length of about 380 mm; they are ringed and triangular in cross section at the base in lowland species and simple and conical in cross section in mountain species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the young are thickly covered with yellowish-brown woolly hair, the mountain anoa adults tend to have curly hair, while lowland anoa have straight hair or are hairless. Adults vary from dark brown to black, with frequent blotches of white on the face, nape, throat, and lower limbs. In mountain anoas the entire lower limbs are creamy white. The underbody parts are usually light brown. Males are generally darker than females.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The hide is exceptionally thick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas are native to dense, mature forests of Sulawesi in eastern Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both species are abundant and well distributed on Sulawesi. Most of the northern, eastern, and southeastern peninsulas and the central area of Sulawesi are still forested and have anoa populations, and there are several large nature reserves to protect them. *</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several of the world's zoos have anoa collections (see Research Contacts).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The climate of Sulawesi is hot, but tempered by sea winds; annual rainfall varies from 500 mm to 4,000 mm. The eastern and southeastern peninsulas have a sparse population and a scattering of subsistence agriculture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The lowland species is found in forests and was once common along the coasts. The mountain anoa is found in primary forests at high altitudes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY"><center><img src="p66.png"></center><br>
+ DISTRIBUTION OF ANOA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas have a wide-ranging diet that includes grasses, ferns, saplings, palm, ginger, and fallen fruit, especially figs. It is of particular interest that the animals can live on a diet that contains no grass.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas have a high requirement for minerals. They visit mineral-rich hot springs and salt licks, and they even drink from the sea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The San Diego Zoo in the United States and Surabaya Zoo in Indonesia have successfully bred and reared the animals in captivity. The gestation period is 276-315 days, and there is generally only a single birth. The life expectancy is about 20-25 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas are shy animals, but they can be aggressive. The sideways and upwards stab of their straight, sharp horns can be dangerous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Except when the cows are about to give birth, anoas apparently associate in pairs rather than in herds. They enjoy water and frequently wallow in mud. Their gait is a trot, but a times they make clumsy leaps. During the morning they feed alone. In the heat of the afternoon they seek refuge under shade trees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On Sulawesi anoas are prized for their hide, horns, and meat. The flesh, especially that of calves, is tender and well flavored.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although somewhat aggressive and pugnacious, anoas might make a suitable livestock animal. They grow and reproduce well in captivity and are adaptable and intelligent. Their small size makes them easier to handle than many other wild bovines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known about the habits of these animals because of their wary nature, secluded environment, and restricted range. They can be tamed enough to obey commands ("lie down," for example) but they remain nervous and likely to butt strangers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surveys are needed throughout Sulawesi to determine the distribution and taxonomy of possible races of the two species, with a view to establishing a protected-area system that will ensure the survival of the genetic diversity of this group.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is also needed on social organization and tameability, as well as on the anoa's biological relationship to the tamaraw and water buffalo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One target should be to build up the zoo populations of both species. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p68.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part IlI : Pig and Piglike Species</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In parts of Asia wild and feral pigs are often the most abundant source of meat. These animals are predominantly variants of the domestic pig, Sus scrofa, or of its ancestor, the Eurasian wild boar. Also contributing to the pig population are five Asian species:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Bearded pig</P>
+<P ALIGN="JUSTIFY">· Sulawesi warty pig</P>
+<P ALIGN="JUSTIFY">· Javan warty pig</P>
+<P ALIGN="JUSTIFY">· Pigmy hog</P>
+<P ALIGN="JUSTIFY">· Babirusa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Southeast Asia hybridization between these species and common pigs has resulted in a confusing diversity of forms and interrelationships. Because of their value, these pigs have been spread since prehistoric times by traders and migrating peoples, creating odd and unpredictable distribution patterns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The species listed represent a gene pool of potential importance for the further development of one of man's most important sources of food. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In many areas of the world, one must start with the native animals adapted to that environment. In many cases, they are the only animals the native human population can afford to begin with. And it is amazing the increased animal production that can result from the use of better production practices with them. TONY J. CUNHA, Dean Emeritus California State Polytechnic University Pomona, California, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fitting the animal to the vegetation might be a better approach than trying to fit the vegetation to the animal, especially on ranges that have been changed or degraded by man. JAMES TEER, Director Texas Parks and Wildlife Department, Austin, Texas, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is now widespread realization that breed importation is not necessarily the quickest route to increased animal production. Indigenous, adapted breeds should be examined more closely and, where necessary, steps should be taken to ensure conservation of at least some of them. HELEN NEWTON TURNER Genetics Research Laboratories, CSIRO, North Ryde, New South Wales, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maximizing the animal harvest, essentially of animal protein, assumes in concept that all animals will be fully exploited in efficient and economic production systems. C.DEVENDRA Malaysian Agricultural Research and Development Institute, Selangor, Malaysia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p70.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">11 The Bearded Pig</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it apparently has never been domesticated, the bearded pig (Sus barbatus) has a long history as an important resource in Southeast Asia. Human remains from the Niah Caves in Sarawak are accompanied by large numbers of its bones and teeth, indicating that 40,000 years ago it was the most commonly eaten large animal. Today in Sarawak and some other areas the bearded pig is still probably the most sought after source of wild meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bearded pigs are large. Boars measure 1-1.6 m in length (crown to rump), up to 1 m in height, and may weigh as much as 150 kg. Sows are smaller. Adult males have small facial warts (infraocular and preocular) and a bushy tuft of hair on the cheek. Both sexes vary in color from pale red-brown to yellow-brown or black. They have elongated skulls with longer, more flexible snouts than the common pig.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Five subspecies are recognized. They range through the Philippines (Balabac, Palawan and offshore islands, Calamianes, Luzon, Mainit, Mindanao, Jolo, Mindoro, and Cebu) to Borneo, Bangka, Sumatra, the Riau Archipelago, and the Malay Peninsula.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Borneo subspecies (Sus barbatus barbatus) is still abundant in some parts of Sabah, Sarawak (including several wildlife reserves), and </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kalimantan. It remains an important food resource for some hill tribes, although with the spread of Islam, attitudes toward pork are changing in some areas. The Malayan subspecies (Sus barbatus of) is now rare in the Malay Peninsula. It is also becoming rare in Sumatra as the lowland forests are logged and broken up by commercial interests and as the human population expands. The status of the three Philippine subspecies is currently unknown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The bearded pig is most commonly found in both primary and secondary evergreen forests. However, it seems to have wide adaptability, and in Sarawak bearded pigs are found in virtually all habitats from the beaches to the upland rain forests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No biological research has yet been conducted on bearded pigs, but naturalists have made several observations. The pigs eat the seeds of trees (for example, those of species of Dipterocarpaceae and Fageceae), fallen fruits (of Moraceae, Bombacaceae, and other plant families), roots, stems of wild bananas, herbs, and probably earthworms, and along the coast they dig up and eat turtle eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Births occur throughout the year in Sabah, but the peak coincides with the fruiting season of forest trees, usually August-September. The litter size is from 3 to 11 piglets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p73.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No behavioral studies have been conducted, but observations suggest that bearded pigs are generally sedentary animals, although in some areas they congregate into large groups that may travel long distances together.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The species might be used (alone or together with other pig species) as a local source of meat, or even as the foundation of a meat industry. The bearded pig is accustomed to living in groups, which may make it suitable for husbandry or game management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is evidence that the bearded pig will interbreed with the common pig, producing young in which both sexes are fertile.* The progeny might have considerable hybrid vigor.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The bearded pig may have tolerance (if not actual resistance) to tropical diseases and conditions that affect the common pig. The species survives in areas of Southeast Asia where feral herds of common pigs are not common, apparently owing to their inability to cope with disease or other environmental challenges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No negative qualities have been reported, but the animal's biology, behavior, management, and potential uses are so far virtually unstudied.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aspects of the animal's general biology that should be investigated include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Chromosome type and variability, and chromosomal differences between the bearded pig and other wild and domesticated pig species</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Reproductive physiology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Nutritional physiology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Social behavior (both in its wild state and under controlled conditions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To assist in the selective capture of young bearded pigs in the wild, external features that characterize the species at an early age need to be identified.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To assess the bearded pig's potential for contributing hybrid vigor, crossbreeding with other pig species should be attempted under controlled conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">12 The Sulawesi Warty Pig</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Sulawesi warty pig (Sus celebensis) is one of the world's few domesticated animals. It is maintained as a village or household animal in a few areas of Southeast Asia, such as on the Indonesian island of Roti. The common pigs of New Guinea and parts of the Moluccas group are hybrids between this species and the common pig.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sulawesi warty pigs are medium sized, averaging about 60 cm high and 40-70 kg. Boars are larger than females and have longer (10 cm) tusks on both jaws. Boars have three pairs of prominent facial warts: on the snout, the cheek, and on the angle of the jaw. In sows these warts are small or absent entirely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are usually red-brown with sharply marked white and yellow undersides; older animals have a round white spot (about 3 cm in diameter) on each side of the upper cheek. Piglets have horizontal stripes on the body, which disappear as they mature.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The body is covered with scanty coarse hair, but stiff bristles, which become erect when the animal is alarmed, occur along the mid-dorsal line of the body. The longest and stiffest occur on the head and nape.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Native to mainland Sulawesi and certain surrounding islands, the Sulawesi warty pig has been introduced to the Lesser Sunda Islands (Flores, Sumba, Roti, Semau, and Timor), the Moluccas (Malmahera and Buru), and Simaleue, a small island west of Sumatra. In some parts of the Philippines (for instance, Naujan and Mindoro Oriental) the animal either occur naturally or has been introduced. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hybrids between the Sulawesi warty pig and the common domestic pig occur on New Guinea, Ternate, Morotai, Bacan, Amron, Seram, Kei island, Aru island, and Sulawatti.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In many islands of eastern Indonesia, this species is widespread and common. In a few places it is extremely abundant, particularly at higher altitudes; in others, it has been greatly reduced by overhunting, deforestation, and expanding human settlement.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Overall, however, Sulawesi warty pig populations are declining, probably due to increased hunting and to human alterations of the animal's habitats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This pig inhabits varied environments, including rain forest, mountain forest, grasslands, and agricultural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p77.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the common pig, the Sulawesi warty pig has broad dietary preferences. It feeds on roots, fallen fruit, leaves, and young shoots. The bulk of its food consists of vegetable materials, but it also feeds on earthworms, insects, aquatic invertebrates, rats, birds, and even carrion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The uterus and placenta are anatomically indistinguishable from those of the common pig. The litter size is from 2 to 8 piglets, with an average of 5.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sows can give birth throughout the year, but usually have their young in April or May. The gestation period is about 4 months.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeding and farrowing occur in the forest and in open Imperata cylindrica grasslands. The pregnant female makes a nest of grasses, leaves, twigs, and branches, which she collects and places over a hole (approximately 2 m long) that she has previously dug. Here she gives birth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Foraging is the main activity of the day and usually takes up several hours, mainly in the early morning and evening. In the wild the pigs travel in small groups, the young always traveling with an adult female. On the move, warty pigs feed and rest intermittently.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As a source of meat the Sulawesi warty pig has been recognized and exploited by local populations since prehistoric times. The presence of feral specimens far outside the pigs' natural range indicates that traders or migrants have long carried it with them on voyages, either as domestic stock or as wild specimens to be released for later capture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tusks, which can be carved like ivory, are a resource for local artisans. Wild specimens are suitable for sport hunting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a body of unrecorded indigenous experience with this animal as a domesticate, but the information needs to be collected and appraised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Sulawesi warty pig may be expected to possess resistance or tolerance to the many diseases prevalent in its native habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is promising potential for hybridization between this species and domestic pigs, which might lead to the improvement of common pigs in tropical regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apart from the unwritten knowledge of the indigenous people who raise the species, very little information is available on the characteristics and management of this animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The genetic variability within the species, as well as the karyotypic differences with common pigs and other Sus species, should be defined. Further, the hybrid vigor resulting from crossbreeding with other Sus species should be- quantified under controlled conditions. Apart from producing potentially important heat-tolerant livestock, crossbreeding may shed important light on the origins of the common pig in Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal's nutritional requirements and reproductive biology also need study. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p79.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">13 Javan Warty Pig</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Javan warty pig (Sus verrucosus) apparently has never been domesticated, but it has been a resource for hunting peoples for centuries. Now, however, the human population in its native region is predominantly Moslem, and all pigs are widely regarded as agricultural pests. Increasing numbers of them are poisoned each year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Javan warty pig can be up to 1.35 m long and 0.9 m tall. Mature males usually weigh between 80 and 120 kg; females are only half that weight - an unusually dramatic example of sexual dimorphism. The animal has a markedly elongated face with large warts, particularly the infraorbital wart and the smaller preorbital and mandibular warts. Body hairs can be black, red, or yellow, with black tips.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This species is found only on the Indonesian islands of Java and Bawean. It was formerly found on Madura as well, but because of deforestation it is now thought to be extinct there. Two extant subspecies are recognized. The nominate one, Sus verrucosus verrucosus, occurs on mainland Java. The second, Sus verrucosus blouchi, a smaller animal, has recently been described on Bawean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For years it was thought that the Javan warty pig was extinct in the wild, but in October 1981 a herd was found in a small area on Mount Penanggungan in East Java. This population may prove to be substantial, and there is reason to hope that other populations can be found. Overall, however, it is clear that the Javan warty pig is endangered and declining in numbers. In many areas the animals are subjected to uncontrolled poisoning and hunting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Five new reserves have recently been proposed to protect the animal in a variety of habitats because it is not found in appreciable numbers in any of Java's nature reserves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Bawean subspecies is believed to be relatively secure since the establishment of a large reserve.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A breeding colony of 12 Javan warty pigs at the Surabaya Zoo includes 5 young ones born in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitats of the Javan warty pig appear to be confined to elevations below about 800 m. The animals prefer relatively large expanses of grassland or secondary vegetation, where human population is sparse. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p82.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The piglets can be born throughout the year; in one study of 8 sows the litter size ranged from 2 to 8, with a mean of 5.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The (diploid) chromosome number has been found to be 38, the same as that of the common pig. Hybridization between these species is thought to occur in the wild, but apparently not with enough frequency to contaminate the Javan warty pig gene pool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unreported.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These are omnivorous, adaptable animals that might make useful domesticates.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The small size of the sows could make this species particularly appropriate for households or smallholder farms. The animal's genetic "distance" from the domestic pig may make it a useful generator of hybrid vigor in crossbreeds. It could have particular value because its meat is much leaner than pork from the common pig.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The numbers in the wild are now too few to permit any cropping.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Efforts should be directed towards locating and breeding up the Javan warty pig populations that still exist. An immediate need is to isolate pure populations in reserves because it is essential to protect the animal from crossbreeding with other species. In addition, current specimens in zoos should be cataloged and a breeding program established. Other captive breeding colonies should also be started.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important to determine the genetic differences between the Javan warty pig and the common pig, as well as the levels of existing hybridization between them. It is also necessary to determine what variation in karyotype may exist within the populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Basic ecological and behavioral studies are needed, as well as studies of the dietary requirements, growth rates, and nutritional physiology of captive specimens. The reproductive biology of the animal should be studied, and the possibility of crossbreeding it with other Sus species should be examined under controlled conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Javan warty pig's potential for local meat production should be evaluated. The benefit to rural people of converting an agricultural pest into a profitable source of income should be explored within the local religious context. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p84.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">14 Pigmy Hog</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pigmy hog (Sus salvanius), a shy and very small pig of northeastern India, is close to extinction because of hunters and the destruction of its habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pigmy hog is only about 60 cm long, with a shoulder height of about 25 cm and a body weight of less than 10 kg. The hair is medium brown on the sides, darkening to blackish brown along the mid-dorsal line. A facial band of short, dark hair extends from the bridge of the nose to below the eye. The tiny tail is only 3 cm long.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This animal was once widely found along the southern foothills of the Himalayas; today, it is definitely known to occur in only one area, the Manas National Park in Assam.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigmy hogs are seriously endangered; in the wild they are close to extinction. Captive animals are now reduced to a single male in the Assam State Zoo and four male siblings in the Zurich Zoo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The few remaining pigmy hogs mainly inhabit tall-grass savannas, but it seems likely that they could adapt to other environments. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigmy hog. (W.L.R. Oliver)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal is omnivorous and consumes roots, tubers, grass, leaves, insects, earthworms, eggs, and carrion. While foraging, it undoubtedly consumes large quantities of earth as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The chromosome number, 38, is the same as that of the common pig. The karyotype is similar to that the common pig, but small, significant differences have been demonstrated using chromosome banding techniques.*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The age at puberty, time of weaning, length of gestation and estrous cycle, and season of breeding are not yet known with certainty. However, the animal is known to have a single well-defined birth peak (April/May) that coincides with the onset of the rainy season when the food supply increases. The uterus and placenta are anatomically similar to those of the common pig. The litter size varies from 2 to 6. It is not known if the animal can be crossbred with the common pig.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY"><center><img src="p87.png"></center><br>
+ Distribution of pigmy hog. (W.L.R. Oliver)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals are shy, but can be tamed. They tend to forage and run in groups. Nest building is carried out by both males and females and is not restricted to pre-farrowing periods.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is no evidence that the pigmy hog has ever been domesticated; it has, however, been extensively hunted and trapped, and recently it was still being sold for human consumption. There would probably be no inherent difficulty in maintaining this species in husbandry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pigmy hog's small size may make it useful in studies of the physiology of pigs and like mammals. In particular, a study of the uterine capacity may contribute to our understanding of the maternal factors that influence the number and size of mammalian young at birth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is unknown if the animal carries genetic resistance to diseases of the domestic pig, but given its habitat, such resistance seems likely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The small numbers of surviving pigmy hogs obviate any consideration of its use in husbandry at the present time. Moreover, its nervous temperament might restrict its potential as a domesticate. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is essential to ensure the survival of this animal. Efforts should be directed towards locating and breeding up the populations that still exist. If its habitat could be protected by preventing the annual dry-season burning of grasses, it is possible that substantial populations could be established. Attempts should also be made to acquire two or more females as mates for the male pigmy hogs at the Assam and Zurich zoos.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is also an urgent need to ensure that the animals breed successfully in captivity, and the wealth of international expertise in pig reproduction should be applied to that end. For example, the reproductive biology of the animal could be studied by swine experts; the age at puberty, the length of the estrous cycle, the season of breeding (and whether it is influenced by light or temperature), the length of gestation, and time of weaning all need to be determined.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal is an omnivore, but the physiology of its digestion has not been studied. Thus, its nutritive requirements are not well enough known to ensure its survival in captivity or reserves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experiments should be made to determine if pigmy hog embryos can be brought to term in the uterus of the common pig. If so, such embryo transfers could be used to distribute embryos and set up new herds, lessening the risk of this species" extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p88.png"></center><br>
+ Adult male of the common pig (wild boar Sus scrofa) and pigmy hog drawn to the same scale. (W.L.R. Oliver) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">15 The Babirusa</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The babirusa (Babyrousa babyrussa) is a piglike animal whose closest relative appears to be an ancestral animal that lived in Europe 35 million years ago. It is easily tamed, and in its native area there is an ancient tradition of raising young babirusa for meat and for the males' unique tusks. The animal appears to reproduce well in captivity, and with good management techniques it might gain wide use in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appearance and Size</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Male babirusa can be up to 110 cm long and 80 cm tall and weigh up to 100 kg; females are smaller. The male has large upper canines that grow upwards, piercing right through the flesh of the snout and curving back and downwards towards the forehead without ever entering the mouth. The female may sometimes have small upper canines projecting through the skin of the upper lip.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animal is more slender than a pig of similar size. It has a gray or brown-grey skin color, although one subspecies, Babyrousa babyrussa babyrussa, has light body hair that is fawn colored or black.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The babirusa is unique to a few islands of eastern Indonesia: north, central, and southeast Sulawesi, the Togian Islands, and the Sula (Taliabu and Sulabesi) and Buru Islands. On Sula and Buru it is probably not native but was introduced in prehistoric times.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On Sulawesi the babirusa remains abundant, despite hunting and the widespread clearing of the forest. Nevertheless, disturbances created by wood and rattan collectors, hunters, loggers, and farmers threaten the babirusa's survival. Throughout the rest of its range, it is also vulnerable to extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biologists are particularly concerned about some of the babirusa subspecies. The one from the north of mainland Sulawesi, Babyrousa babyrussa celebensis, is still relatively abundant in places and is probably in no immediate danger. The Togian Islands' subspecies, Babyrousa babyrussa togeanensis, is abundant in small islands but is threatened by Indonesia's settlement programs and deforestation. The Buru and Sula Islands subspecies, Babyrousa babyrussa babyrussa, may already be extinct; there have been no confirmed sightings in recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1981, there were 26 male and 27 female babirusa held in six zoo collections; 22 of these animals are in the Surabaya Zoo in Indonesia, where they breed well. Most, if not all, are believed to belong to the mainland Sulawesi race.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat and Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The animals mainly inhabit moist forests at low altitudes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p91.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Biology</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Precise details of babirusa biology are unknown, but the stomach has an extra sac, suggesting that the animals may have some ability to break down cellulose. Indeed, they browse leaves, a behavior more often found in a deer than in a pig, and have been referred to as "ruminant pigs." Babirusa also live on roots, berries, and grubs, making them true omnivores. Compared to other pigs, they do little rooting, and in captivity their enclosures remain quite grassy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Babirusa are said to be sexually mature at 5-10 months, but this depends on nutrition. Gestation length is about 158 days. One or two young are produced although there are some reports of litters of three.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One specimen was kept for 24 years in captivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Behavior</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The babirusa is a social animal that moves in groups. A retiring native of the dense jungle, it is a fast runner and swims readily. Mating behavior in captivity generally resembles that of domestic pig. Evidence from zoo animals suggests that the male must be removed from the young at birth but that by the time they are a month old the young are safe from paternal attack.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uses</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When captured young or reared in captivity, the babirusa is easily tamed. It has potential as a domesticated species, and with appropriate management may provide a useful source of meat. The meat is tasty and of good quality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its unique tusks, the skull of the male finds ready markets. This could provide additional income to farmers raising babirusa for meat. The ivory of the tusks could also be a resource for local artisans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Potential Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, the anatomy of the stomach suggests that the babirusa may be able to make more efficient use of fibrous foodstuffs than other pigs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The babirusa produces only one or two young after a gestation period of just over five months; it may therefore take considerable time to build up herds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the babirusa is easily tamed, it is not known whether it can be husbanded in large groups. Also, present lack of knowledge of the animal's nutrition may restrict its husbandry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Conservation Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The number of animals in the wild is decreasing, and attempts should be made to determine their exact status. Particular attention should be paid to the subspecies Babyrousa babyrussa togeanensis and Babyrousa babyrussa babyrussa. Captive breeding programs for these subspecies should be started.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p93.png"></center><br>
+ When seen in longitudinal section, the stomach of babirusa presents striking similarities  to that of a relatively simple ruminant such as the domestic sheep. Every part except the  omasum, even including a rudimentary reticulum, is represented and occupies the same  relative position. The babirusa stomach differs from that of the domestic pig chiefly in  the enormous size of the diverticulum ventriculi, the prominence of the constrictions  that delimit its three main divisions, and in the size and complexity of the cardia. Regions  corresponding to parts of the ruminant stomach are labeled in brackets. (Information  from Davis, 1940; diagram courtesy Field Museum of Natural History, Chicago.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild populations should be maintained in several regions to ensure that  the species" genetic base is retained. Advantage could be taken of the large  number of islands in eastern Indonesia to establish reserves for the different  babirusa subspecies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Currently, little is known about the biology of the animal in the wild its  diet, social behavior, or reproductive performance are almost unstudied. In  view of the relatively small number of babirusa in zoos and the scarcity of  information about the animal's growth rate and general biology, coordinated  studies between zoos could provide much basic information. It has been  suggested that a studbook be initiated for this species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is clear from chromosome analysis that this pig differs markedly in  its karyotype from that of other pigs. However, more anatomical and  biochemical knowledge is needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Basic parameters of the animal's reproductive physiology are not known.  Questions to be answered include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Can the babirusa be induced to reproduce twice per year?</P>
+<P ALIGN="JUSTIFY">· Can babirusa embryos be developed to term in the uterus of the domestic  pig? If so, can the number of babirusas be rapidly multiplied in this way?</P>
+<P ALIGN="JUSTIFY">· Does the babirusa genotypic and gestation-length difference with the  common pig prevent the two from successfully crossbreeding? And if  crossbreeding can be achieved, will the progeny be fertile?  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p94.png"></center><br>
+ FIGURE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Part IV : Recommendations and  General Research  Needs</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Asian animals described in this report are a natural resource whose  potential is barely glimpsed. They are virtually unknown to established  livestock interests and there has been little thought to developing them as  livestock. As a result, the research and trials that could lead to further use of  these animals is scattered, small scale, and conducted outside the mainstream  of livestock science, mainly by wildlife conservationists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet these animals seem worth considering for use in husbandry in many  tropical regions, especially where poor grazing and harsh environments limit  the performance of conventional livestock. There is a pressing need for  research to develop these species and to explore their potential. Only through  rapid action can many of them be kept available for study and possible  inclusion in agriculture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One suggestion is that funds be provided to establish an Asian  native-livestock research-support team. Its primary purpose would be to  assist in the funding of research projects and to coordinate research being  done in various Asian countries. The team's goal would be to establish a  network of animal scientists based at institutions in Asia and elsewhere to  work cooperatively on the region's little-known bovines and pigs. In this  manner, relatively small sums of money could be used to stimulate and  coordinate Asia-wide research on indigenous animals.*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Basic Research</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The time has come for basic studies on each of the 15 animals discussed in  this book. For each species, the following areas should be investigated:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· Physiology</P>
+<P ALIGN="JUSTIFY">· Reproductive requirements and fertility</P>
+<P ALIGN="JUSTIFY">· Nutritional requirements (such as food preferences, feeding strategies, and food utilization)</P>
+<P ALIGN="JUSTIFY">· Growth</P>
+<P ALIGN="JUSTIFY">· Adaptability and environmental tolerance (for instance, water balance, sweat rate, and shade-seeking habits, as well as temperature, pulse, and respiration rates, both under normal conditions and heat stress)</P>
+<P ALIGN="JUSTIFY">· Diseases</P>
+<P ALIGN="JUSTIFY">. Management (including stocking rates and other production characteristics</P>
+<P ALIGN="JUSTIFY">· Genetic selection for calm temperament, quick growth, and other desirable qualities</P>
+<P ALIGN="JUSTIFY">· Crossbreeding to take advantage of hybrid vigor</P>
+<P ALIGN="JUSTIFY">· Social structure (for example population density and distribution, social organization, leadership, herding potential, aggressiveness of bulls)</P>
+<P ALIGN="JUSTIFY">· Habitat characteristics (behavior-habitat interactions and herd dynamics, for instance).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Studies are also needed on better utilization of products, such as milk, meat, hides, horn, and hair, from these animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experimental transfer of fertilized eggs of all of these animals into domestic species should be explored with a view to establishing herds in secure and disease-free areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Efforts specific to domesticated and wild species, and to hybrids of these species, are discussed below. The report concludes with brief discussions of a few promising species not taken up in the body of the text.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated Species Improving Performance</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little data is available on the performance of the domesticated animals discussed in this report. Yet the main value of these species lies in the new and superior genes and gene combinations that can be adapted to animal production in the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Studies need to be conducted with the indigenous species and strains in their native countries to determine if they will respond to improved conditions with improved performance. These projects could provide opportunities for geneticists and animal breeders to improve livestock production while conducting challenging basic research. It would be helpful to establish studbooks of captive specimens and to select and breed for desirable genetic qualities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Genetic improvement must be directed towards remedying production deficiencies. Methods include selection of superior breeding animals, crossbreeding, and combinations of selection and crossbreeding. Different genetic improvement techniques will be required for each species. Progress should be regularly monitored against the unselected animals and the domestic livestock breeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Introductions</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tropical countries should import breeding stock to evaluate the performance of some of these Asian animals in the local environment. Strict quarantine procedures must, of course, be observed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Special emphasis should be placed on the domesticated banteng of eastern Indonesia. These animals are already an important source of human food and they may have considerable potential for increasing production elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild Animals</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild animals contribute extensively to the welfare of people and economies of developing countries. In many areas they supply much of the animal protein consumed. But the contributions they make are largely unrecorded, and local officials and aid agencies seldom regard wildlife as an economic resource. As a result, few developing countries have analyzed how their people use indigenous animals for subsistence, and few nutritional studies recognize "bushmeat," although large numbers of people eat it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wildlife's contribution justifies more detailed and precise evaluations. In many tropical regions few people even know what species are present, let alone in what numbers. Ecologists and animal scientists should be employed to identify and collect data on the fauna of the tropical forests and how it is used by local people. Their work will provide baseline information on the species present and on the potential utility of the undisturbed natural ecosystems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initial Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All wildlife utilization must be based on a thorough knowledge of the resource, its numbers, the animals' condition, annual recruitment in the </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">various populations, and the seasonal movements of the herds. In addition, it is important to understand the interactions of the species with its habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thus, the immediate need is for action to assure the preservation of populations of these animals until research studies can be conducted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this regard, priority actions include the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Establishing adequate preserves</P>
+<P ALIGN="JUSTIFY">· Providing total protection for remaining animals</P>
+<P ALIGN="JUSTIFY">· Preventing poaching.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With few exceptions, the wild species described in this report are under the pressures of agricultural and human expansion. Without efforts to preserve their habitats it will be difficult for these species to survive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Developing Wildlife Resources</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments cannot stop hungry people from hunting game, but they can use this impetus to help protect some indigenous animals as well as forest and woodland habitats. Fostering the production and supply of wild animals such as those described in this book could open up a new: source of meat and other products, particularly for subsistence farmers in remote areas. In the last analysis, this may be the only way of protecting and maintaining these animals and developing local awareness of their value.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International economic development organizations have traditionally shown little interest in wildlife or wildlife habitats. Yet maintaining these animals and their habitats is crucial to the continuing supply of many indigenous food animals, the most important of which are often the smaller ones that flourish in secondary growth. And the forests that support wildlife also protect some of the huge investments that AID, the World Bank, and other other agencies have made to help developing countries. The forest is the sponge that absorbs the water from tropical rains. Without trees covering the watersheds, heavy rains cause rushing water that erodes the land, despoils highways, silts up dams and reservoirs, knocks out bridges, and inundates towns, villages, and farm fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In principle, the farming of tropical wildlife could become a force in preventing clear-felling of the tropical forests. Rational utilization of tropical animals offers productive alternative use of the land. In some cases, the farming of indigenous animals can fit smoothly into tropical habitats and into traditional village life, because the livestock and its needs are usually familiar to local people and are often ingrained in their traditions.( For successful examples see companion reports nos. 44 and 45, Butterfly Farming in Papua New Guinea and Crocodiles as a Resource for the Tropics. </P>
+<P ALIGN="JUSTIFY">Hybrid Animals)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hybridization may offer new prospects for using underexploited tropical animal resources. This is a speculative notion, but it deserves serious attention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crossbreeding between the animals mentioned in this report holds exciting possibilities for expanding livestock options in the tropics. Some of the crosses, known or envisaged, are:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· gaur x cattle</P>
+<P ALIGN="JUSTIFY">· banteng x cattle</P>
+<P ALIGN="JUSTIFY">· kouprey x cattle</P>
+<P ALIGN="JUSTIFY">· yak x cattle</P>
+<P ALIGN="JUSTIFY">· yak x banteng</P>
+<P ALIGN="JUSTIFY">· anoa x water buffalo</P>
+<P ALIGN="JUSTIFY">· tamaraw x water buffalo</P>
+<P ALIGN="JUSTIFY">· domestic pig x warty pigs</P>
+<P ALIGN="JUSTIFY">· warty pigs x bearded pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Care must be taken, however, to guard against the dilution of wild genes by the escape of hybrid or interbreeding domestic species, or the establishment of feral hybrid populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">International Exchange of Pig Germ Plasm</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Present veterinary restrictions effectively prevent the movement of pigs between most countries. Relatively few species of wild pigs are therefore maintained in zoos outside their countries of origin. This stifles the promising potential for the species described in Part III, as well as for captive-breeding safeguards and research on the endangered species. It is important that attempts be made to identify channels for the future establishment of viable captive stocks both within Asia and elsewhere. Transfer of embryos should be verified as a means of permitting disease-free movement across frontiers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Species Not Covered in this Report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This project, which began as a short report on banteng, quickly developed momentum as it brought in suggestion after suggestion of further species. Through pressures of time and budget, it was not possible to take up all of these interesting animals. Some of the omitted ones are listed below. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Takin (Budorcas taxicolor).* A heavily built, Southeast Asian hoofed mammal of the family Bovidae, the takin lives in small herds in the mountains, often above timberline. Though robust and short-legged, it can move about quickly and easily over difficult slopes. It stands up to about 1 m at the shoulder and has a shaggy yellowish- to blackish-brown coat. Both sexes have heavy horns that turn outward from the center of the forehead and then curve up and backward.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goral (Naemorhedus goral).* This small Asian goatlike bovine has slightly backward curving cylindrical horns and a coarse brownish-grey coat. It is related to the chamois and serow (see below) but is distinguished from them by peculiarities in skull form, as well as by smaller size, shorter horns, and the absence of face glands. Gorals are native to a vast area, ranging from the Himalayas to eastern Siberia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Serow (Capricorhis sumatrensis). The serow has been called a "goatantelope." Found in Sumatra, the Malay Peninsula, Vietnam, Thailand, Burma, the eastern Himalayas, and China, it lives on forest-clad slopes, such as the mountains of southern China that are the home of the giant panda. Serows have coarse black hair, long pointed ears, a distinct mane, and short, backward pointing horns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Native species of goats are also valuable genetic resources of Asia and examples include ibex (Capra ibex), markhor (Capra falconeri), and bharal (Pseudois nayaur). There are also various species of sheep, including the various races of argalis (Ovis ammon), which form small herds in the mountains, often above timberline. Although robust and short-legged, these animals can move about quickly and easily over difficult slopes. Soviet animal breeders apparently are exploring some of the possibilities of using argalis in animal husbandry. They are crossing domestic sheep with arkhar (Ovis ammon karelini) to produce a commercially viable hybrid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The marketable size of lamb might be increased appreciably to provide larger, leaner cuts of meat by crossing domestic sheep with the Marco Polo sheep (Ovis ammon polii), which is as big as deer and has a mature body weight of 400-500 pounds. Marco Polo sheep meat is reported to have none of the "mutton" favor of domestic sheep. Thus, crosses might enhance consumer acceptance of sheep meat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asia also has several species of deer that could have been included.§ The musk deer (Moschus moschiferus) is now domesticated in China for musk production and is a resource with a promising future. Also, sambar deer (Cervus unicolor), Asia's largest deer, may prove useful in husbandry. Several deer species are being farmed in New Zealand and ruse deer (Cervus rusa), which are native to South and Southeast Asia, are being farmed in Mauritius, Australia, and Papua New Guinea for meat and medicinal by-products. Two small, goat-sized Asian deer, the hog deer (Cervus porcinus) and the barking deer (Muntiacus muntjak), may also be worth considering. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p101.png"></center><br>
+ KOUPREY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendixes</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Selected Readings</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">General</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bohlken, H. 1961. Haustiere und Zoologische Systematik. Zeitschrift fur Tierzuchtung und Zuchtungsbiologie76:107-113.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul, and J. A. McNeely. 1977. Mammals of Thailand. Association for the Conservation of Wildlife, Bangkok, Thailand. 758 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corbet, G. B., and J. E. Hill. 1980. A World List of Mammalian Species. British Museum of Natural History, London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Groves, C. P. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Genus Sus. Department of Prehistory Technical Bulletin No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gray, A. P. 1972. Mammalian Hybrids: A Check-List with Bibliography. Commonwealth Technical Communication No. 10 (Rev.). Bureau of Animal Breeding and Genetics, Edinburgh, Scotland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Honacki, J. H., K. E. Kinman, and J. W. Koeppl. 1982. Mammal Species of the World. Allen Press, Lawrence, Kansas, USA. 694 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mochi, U. and T. D. Carter. 1953. Hoofed Mammals of the World. Charles Scribner's Sons, New York.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Payne, W. J. A. 1970. Cattle Production in the Tropics. Longman, London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robbins, C. T. In Press. Wildlife Feeding and Nutrition. Academic Press, New York, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Walker, E. P. 1975. Mammals of the World. The Johns Hopkins University Press, Baltimore, Maryland, USA, and London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wharton, C. H. 1969. Man, fire and wild cattle in Southeast Asia. Tall Timbers Fire Ecology Conference 8: 107-167.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated and Wild Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appleton, D. C., G. Dryden, and A. C. Kondos. 1976. A comparison of the digestive efficiency of the water buffalo and Brahman and Banteng cattle. In Proceedings of the Australian Society of Animal Production 11.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Budiarso, I. T., and S. Hardjosworo. 1976. Jembrana disease in Bali cattle. Australian Veterinary Journal 52(2):97.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Copland, R. S. 1974. Observations on banteng cattle in Sabah. Tropical Animal Health and Production 6(2):89-94.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Darmadja, D., and P. Sutedja. 1975. Gestation period and calving interval in Bali cattle. Majalah Ilmiah Universitas Udayana 9:61 -65.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Darmadja, D., and P. Sutedja. 1976. Masa kebuntingan den interval beranak padas sapi Bali. In Proceedings, Seminar Reproduksi den Performance Sapi Bali, April 5-6, 1976. Dinas Peternakan Daerah Ternak Institute, Bali, Indonesia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Devendra, C., T. Lee Kok Choc, and M. Pathmasingam. 1973. The productivity of Bali cattle in Malaysia. Malaysian Agricultural Journal 49(2):183-197.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Holmes, J. H. C., J. H. Schottler, and T. F. Leche. 1977. Southeast Asian cattle, buffalo, and beef in Papua New Guinea. In Agriculture in the Tropics, B. A. C. Enyi and T. H. Varghese, eds. University of Papua New Guinea, Port Moresby, Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hoogerwerf, A. 1970. Udjung Kulan, The Land of the Last Javan Rhinoceros. E. J. Brill, Leiden, The Netherlands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hooijer, D. A. 1956. The valid name of the banteng Bibos javanicus d'Alton. Zoologische Mededelingenuitgegeven door het Rijksmuseum van Natuurlijke Historie te Leiden 34:223-226.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jellinek, P. J., J. Avenell, A. Thahar, and P. Sitorus. 1980. Infertility associated with crossbreeding of Bali cattle. In Proceedings, 2nd Ruminant Seminar, Ciawi, Indonesia. 79 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jenkinson, D. M., and T. Nay. 1975. The sweat glands and hair follicles of different species of Bovidae. Australian Journal of Biological Science 28:55-68.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kirby, G. W. M. 1979. Bali cattle in Australia. World Animal Review 31 :24-29.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mason, 1. L. In Press. Evolution of Domesticated Animals. Longman, London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meijer, W. C. P. 1962. Das Balirind (Balinese Cattle). Die Neue Brehm-Bucherei, No. 303, A. Ziemsen Verlag, Wittenberg Lutherstadt, Federal Republic of Germany. (Translated from the Dutch by E. Mohr.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1973a. Liveweight changes of Brahman cross, Shorthorn, Banteng and buffalo steers grazing improved pastures at Darwin, Northern Territory. Journal of the Australian Institute of Agricultural Science 39:68-9.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1973b. Heat tolerance of Brahman cross, buffalo Banteng and Shorthorn steers during exposure to sun and as a result of exercise. Australian Journal of Agricultural Research 24:775-782.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1978. Digestibility and water metabolism in Brahman cross, buffalo, Banteng and Shorthorn steers fed roughage diets. Journal of the Australian Institute of Agricultural Science 44: 57-59.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1980. The prediction of chemical content of the whole carcass from the physically-dissected rib in cattle and buffaloes. Proceedings of the Australian Society of Animal Production 13:503.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1981. Beef and buffalo production by smallholders in Indonesia. World Review of Animal Production 17:55-64.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1982. The performance of Indonesian beef breeds under traditional and improved management systems. Pp. 347-351 in Animal Production and Health in the Tropics, M. R. Jainudeen and A. R. Omar, eds. Universiti Pertanian Malaysia, Serdang, Selangor, Malaysia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B., B. W. Norton, and J. V. Nolan. 1979. The intake, digestibility and utilization of a low quality roughage by Brahman cross, buffalo, Banteng and Shorthorn steers. Australian Journal of Agricultural Research 30:333-340.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Namikawa, T., and W. Widodo. 1978. Electrophoretic variations of hemoglobin and serum albumin in the Indonesian cattle including Bali cattle (Bos banteng). Japanese Journal of Zootechnical Science 49(11):817-827.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nitis, 1. M., K. Rika, M. Supardjata, K. D. Nurbudhi, and L. R. Humphreys. 1976. Productivity of improved pastures grazed by Bali cattle under coconuts: a preliminary report. Universitas Udayana, Denpasar, Bali, Indonesia. 18 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nitis, 1. M., and K. Rika. 1978. Bali cattle grazing improved pasture under coconuts. 1. Effects of stocking rate on steer performance and coconut yield. In Seminar on Integration of Animals with Plantation Crops, April 13-15. Preprint No. 10. Penang, Indonesia. 8 pp</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nitis, 1. M. 1979a. Effects of replacing 30 percent of the green roughage with concentrate on the performance of Bali steer. Progress report to the International Development Research Centre, Ottawa, Canada. Centre file:3-P77-0087. 25 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nitis, 1. M. 1979b. Performance of Bali cattle fed grass supplemented with stylosanthes. Progress report to the International Foundation for Science, Sweden. Project No. RR 76. 15 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nitis, 1. M., K. Lana, 1. B. Sudana, N. Sutji, and 1. C. N. Sarka. I980. Persediaan den kebutuhan hijauan ternak di Bali (Roughage supply and requirement of livestock in </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bali). Fakultas Kedokteran Hewan den Peternakan, Universitas Udayana, Denpasar, Bali, Indonesia. 218 pp. (Report series mimeograph.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Norton, B. W., J. B. Moran, and J. V. Nolan. 1979. Nitrogen metabolism in Brahman cross, buffalo, Banteng and Shorthorn steers fed on low quality roughage. Australian Journal of Agricultural Research 30:341.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nursamad, M. 1972. Berat lahir den petumbuhan anak sapi Bali selama 4 bulan di kecamatan Watang Pulu, kabupaten Sidenreng, Sulawesi Selatan. Laporan, Fakultas Peternakan Universitas Hasanuddin yang berafinasi dengan Fakultas Peternakan Institut Pertanian Bogor, Bogor, Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pastika, M., and D. Darmadja. 1976. Performance reproduksi sapi Bali. In Proceedings, Seminar Reproduksi den Performance Sapi Bali, April 5-6, 1976. Dinas Peternakan Daerah Ternak Institut, Bali, lndonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Payne, W. J. A., and D. H. L. Rollinson. 1973. Bali cattle. World Animal Review 7: 13-21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pulungan, H., and K. Ma'sum. 1977. Performance sapi Bali den hasil persilangannya dengan sapi Hereford den Shorthorn. Laporan Khusus Lembaga Penelitian Peternakan, Cabang Grati 1977 (Abstract).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robinson, D. W. 1977. Livestock in Indonesia. Research Report No. 1. Centre for Animal Research and Development, Bogor, Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Siebert, B. D., and W. V. MacFarlane. 1969. Body water content and water turnover of tropical Bos taurus, Bos indicus, Bibos banteng, and Bos bubalus bubalis. Australian Journal of Agricultural Research 20:613-622.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Siregar, M. G., and 1. M. Suparjata. 1975. A half century existence of Bali cattle in South Sulawesi. Majalah llmiah Universitas Udayana 9: 13-21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Subandriyo, P. Sitorus, M. Zulbardi, and A. Roesyat. 1979. Performance of Bali cattle, as work animals and milk and beef producers. Indonesian Agricultural Research and Development Journal 1(1/2):9-10, 24.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sutedja, P., M. Kota, 1. B. Mantra, and D. Darmadja. 1976. Progress report beberapa performance pada sapi Bali. In Proceedings, Seminar Reproduksi den Performance Sapi Bali, April 5-6, 1976. Dinas Peternakan Daerah Ternak Institut, Bali, Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thahar, A., J. B. Moran, and J. T. Wood. In press. Studies on the haemotology of Indonesian large ruminants. Tropical Animal Health and Production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thahar, A., J. B. Moran, and R. E. Soerifpo. In press. Observations on the hair and skin of Indonesian large ruminants and their relationships to heat tolerance. SABRAO Journal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vercoe, J. E., and J. E. Frisch. 1977. The importance of voluntary feed intake and metabolic rate to production in different genotypes of cattle in different environments. Pp. I(c)-42 in Proceedings of the 3rd International Congress of the Society for the Advancement of Breeding Researchers in Asia and Oceania, Canberra, Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yeates, N. T. M., and P. J. Schmidt. 1974. Beef Cattle Production. Butterworths Pty Ltd., Chatswood, Sydney, Australia. 323 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng Cattle Hybrids</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Payne, W. J. A., and D. H. L. Rollinson. 1976. Madura cattle. Zeitschrift fur Tiezuchtung und Zuchtungsbiologie 93:89-100.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mithan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Simoons, F. J., and E. S. Simoons. 1968. A Ceremonial Ox of India: The Mithan in Nature, Culture, and History. The University of Wisconsin Press, Madison, Wisconsin, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mason, 1. L. In Press. Evolution of Domesticated Animals. Longman, London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scheurmann, E. 1975. Observations on the behaviour of the mithan (Bibos frontalis Lambert 1837) in captivity. Applied Animal Ethology I :321 -355. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yak and Yakow</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Accolas, J. P., and J. P. Deffontaines. 1970. Quelques donnees sur l'elevage du Yak en Republique Populaire de Mongolie. Pp. 133-141 in The Yak: Its Role in the Economic and Cultural Life of Breeders in Central Asia. Societe d'Ethnozootechnie, 25 Boulevard Arago, 75013 Paris, France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bonadonna, T. 1970. Nuove possibilita per la Zootechnia dei tropic). Zootecnica e Veterinaria 25:202-221.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bonnemaire, J. 1976. Le Yak domestique et son hybridation. Pp. 46-77 in The Yak: Its Role in the Economic and Cultural Life of Breeders in Central Asia. Societe d'Ethnozootechnie, Paris, France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dor, R. 1976. Note sur le Yak au Pamir. Pp. 126-131 in The Yak: Its Role in the Economic and Cultural Life of Breeders in Central Asia. Societe d'Ethnozootechnie, Paris, France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ekvall, R. B. 1968. Fields on the Hoof: Nexus of Tibetan Nomadic Pastoralism. Holt, Rinehart and Winston, New York, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Epstein, H. 1974. Yak and chauri. World Animal Review 9:8-12.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Epstein, H. 1977. Yak and Yak-cattle hybrids. Chapter 3 in Domestic Animals of Nepal. Holmes and Meier Publishers, Inc., New York, USA, and London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ivanova, V. V. 1938. K voprosu izucenija plodovitosti samvoc gibridov jaka s rogatym skotom (On the fertility of male yak x cattle hybrids). Izvestiya Akademii Nauk SSSR, Seriya Biologicheskaya 883-884.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Phillips, R. W., R. G. Johnson, and R. T. Moyer. 1945. The livestock of China. Pp. 67-76 in United States Department of State Publication No. 2249; Far Eastern Series 9.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Phillips, R. W., I. A. Tolstoy, and R. G. Johnson. 1946. Yaks and Yak-cattle hybrids in Asia. The Journal of Heredity 37(6): 162-170; 37(7):206-215.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schley, P. 1967. Der Yak und seine Kreuzung mit dem Rind in der Sowjetunion. Giessener Abhandlungen zur Agrar- und Wirtschaftsforschung des Europaischen Ostens, Vol. 44. Otto Harassowitz, Weisbaden, Federal Republic of Germany. 131 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shahrani, M. Nazif Mohib. 1979. The Kirghiz and Wakki of Afghanistan. University of Washington Press, Seattle, Washington, USA. 264 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vlasov, P., S. Gersenzon, and A. Poljakov. 1932. Gibridizacija mezdu jakom i krupnym rogatym skotom (Hybrids between yak and cattle). Problemy Zhivotnovodstva (1):48-57.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">White, W. T., R. W. Phillips, and E. C. Elting. 1946. Yaks and Yak-cattle hybrids in Alaska. Journal of Heredity 37:355-358.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zawadowsky, M. M. 1931. Zebu-Yak hybrids. Journal of Heredity 22:297.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zuitin, A. I. 1938. New data on the chromosome number in yak (Poephagus grunniens L.). Doklady Akademii Nauk Uzbekskoi SSR 19:201-202.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A unique, interesting film showing wild banteng, gaur and kouprey in Cambodia in 1951</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">is available for hire from The Coolidge Foundation, 38 Standley Street, Beverly, Massachusetts 01915, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul and J. A. McNeely. 1977. Mammals of Thailand. Association for the Conservation of Wildlife, Bangkok, Thailand. 758 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fischer, H., and E. Scheurmann. 1977. Cytogenetic investigations on domestic and wild animal populations in South and Southeast Asia. Animal Research and Development 6:63-71.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Halder, U. 1975. Okologie und Verhalten des banteng (Bos javanicus) in Java. Eine Feldstudie. Verlag Paul Parey, Hamburg and Berlin, Federal Republic of Germany. 124 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hoogerwerf, A. 1974. Report on a Visit to Wildlife Reserves in East Java. Mededelingen No. 21. Nederlandsche Commissie voor Internationale Natuurbescherming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">McNeely, J. A. 1975. Wildlife and national parks in the Lower Mekong Basin. Unpub</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">lished report to the Committee for the Coordination of Investigations of the Lower  Mekong Basin, Economic Commission for Asia and the Far East, Bangkok, Thailand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sumardja, E. A. 1976. The relationships between banteng Bos javanicus (d'Alton) and  vegetation at the Pananjung-Pangandaran Nature Reserve. Research Grant No. 1237/  TF/VI/74. Preliminary Study Internal Report Biotrop. Bogor, Indonesia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wind, J., and H. Amir. 1977. Distribution of banteng (Bos javanicus) in Java and Bali,  Indonesia. Unpublished ms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wind, J., and H. Amir. 1977. Management Plan Baluran Reserve FAO INS/73/013.  Nature Conservation and Wildlife Management Project.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaur</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul. 1965. The gaur. (Bos gaurus). Conservation News of South East  Asia 5:7-10.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul and J. A. McNeely. 1977. Mammals of Thailand. Association for the  Conservation of Wildlife, Bangkok, Thailand. 758 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conry, P. J. 1980. The impact of development and the behavioural response of the  Malaysian seladang. Pp. 279-286 in Tropical Ecology and Development, Proceedings  Fifth International Symposium of Tropical Ecology. International Society of Tropical  Ecology, Kuala Lumpur, Malaysia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conry, P. J. 1981. Habitat selection and use, movements, and home range of Malayan  gaur (Bos gaurus hubbacki) in Central Pahang, Malaysia. M.S. thesis. University of  Montana, Missoula, Montana, USA. 120 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conry, P. J. (In press) Immobilizing Malayan gaur with etorphine. Journal of Wildlife  Management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fischer, H. 1975. The water buffalo and related species as important genetic resources:  their conservation, evaluation and utilization. In The Asiatic Water Buffalo.  Proceedings of an International Symposium, Khon Kaen, Thailand. Food and Fertilizer  Technology Center, Taipei, Taiwan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fischer, H. 1980. Hybrids between Gaur and Gayal and between Gayal and Banteng as  zoological rarities in Thailand. Animal Research and Development 12:116-119.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fradrich, H., and H. G. Klos. 1976. Zur Haltung und Zucht des Gaurs, Bos gaurus.  Zoologische Garten 46(6):417-425.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hussain, M. Khader. 1969. The southern Asiatic gaur or Indian bison (Bos gaurus  gaurus H. Smith). Cheetal 12(1):29-47.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Krishnan, M. 1972. An ecological survey of the larger mammals of peninsular India.  Journal of the Bombay Natural History Society 69:322-349.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Medway, Lord. 1978. The Wild Mammals of Malaya and Singapore. 2nd Edition. Oxford  University Press, Kuala Lumpur, Malaysia. 128 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Momin Khan, M. K. bin 1973. Studies on the seladang (Bos gaurus) in the State of  Perak. Malaysian Nature Journal 26:163-169.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sahai, R. C. 1972. Distribution, composition and herd size of Gaur (Bos gaurus) in  Palamau, Bihar. Cheetal 15:60-66.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schaller, G. B. 1967. The Deer and the Tiger. Chicago University Press, Chicago, USA.  370 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Weigun, L. E. 1971. The last refuge. Malaysian Nature Journal 24:132-137.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Weigun, L. E. 1972. The problems in the preservation of the seladang in the Malaysian  National Park. M.S. thesis. Michigan State University, East Lansing, Michigan, USA.  55 pp</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul and J. A. McNeely. 1977. Mammals of Thailand. Association for the  Conservation of Wildlife, Bangkok, Thailand. 758 pp.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coolidge, H. J. 1940. The Indo-Chinese Forest Ox or Kouprey. Memoirs, Museum of Comparative Zoology at Harvard College 54(6):421-431.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coolidge, H. J. 1955. The Forest Ox or Kouprey of South East Asia. P. 109 in Breeding Beef Cattle for Unfavorable Environments, A. O. Rhoad, ed. University of Texas Press, Austin, Texas, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Neese, H.C. 1976. Kouprey along the Laos/Cambodia border area. Unpublished report to the New York Zoological Society, 185 and Southern Blvd., New York, New York 10460, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pfeffer, P., and O. Kim-San. 1967. Le kouprey, Bos(Bibos) sauvelli, Urbain, 1937: discussion systematique et status actuel. Hypothese sur l'origine du zebu (Bos indicus). Mammalia 31(4):521-536.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pfeffer, P. 1969. Considerations sur l'ecologie des forets claires du Cambodge oriental. Terre et Vie 23(1):3-24.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wharton, C. H. 1957. An Ecological Study of the Kouprey. Novibos sauveli (Urbain). Monograph No. 5. Institute of Science and Technology, Manila, Philippines. 111 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dolan, J. M. 1965. Breeding of the lowland anoa in the San Diego Zoological Garden. Zeitschrift Saugetierekunde 30(4):241-248.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duplaix-Hall, N., ed. 1975. International Zoo Yearbook 15. Zoological Society of London</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fradrich, H. 1973. Einige Bemerkungen uber den Anoa. Zeitschrift des Kolner Zoo 16(3):101-105.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fischer, H., and H. Hohn. 1976. Der Karyotyp eines weiblichen Tamarau (Anea mindorensis) [The Karyotype of a Female Tamaraw (Anoa mindorensis)]. Giessener Beitrage zur Erbpathologie und Zuchthygiene 6:173.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Groves, C. P. 1969. Systematics of the anoa (Mammalia, Bovidae) Beaufortia 17(223): 1-12.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Koulischer, L., J. Tyskens, and J. Mortelsmanns. 1972. The chromosomes of a male specimen of Anoa depressicornis quarlesi. Acta Pathologica, Antwerp 56:21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scheurmann, E., H. Hohn, and H. Fischer. 1977. The karyotype of a male Bubalus (Anoa) depressicornis quarlesi Ouwens 1911. In Symposium, Domesticated Animal Cytogenetics, Jouy en Josas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tamaraw</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alvarez, J. B., Jr. 1970. Philippines tamaraw, here to stay. IUCN Publication, New Series 18:46-51.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grimwood, l. R. 1975. National Parks and Wildlife Conservation in the Philippines. FAO: PHI/72/006. UNDP/FAO, Rome, Italy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Harrisson, T. 1969. The tamaraw and its survival. Conservation News of South East Asia 8:60-61, 70.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kuchn, D. 1975. Tamaraw at Mt. Iglit Came Refuge, Philippines. Tigerpaper 2(3):26.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sitwell, N. 1975. On the track of the tamaraw. Wildlife 17:428-430.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Talbot, L. M., and M. H. Talbot. 1966. The tamaraw, Bubalus mindorensis (Heude). Observations and recommendations. Mammalia 30(1): 1 - 12.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bearded </P>
+<P ALIGN="JUSTIFY">Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Allen, E. F. 1948. The bearded pig. Malaysian Nature Journal 3(2):98-99.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cranbrook, Earl of. 1979. A review of domestic pig remains from archaeological sites in </P>
+<P ALIGN="JUSTIFY">Diong, C. H. 1973. Studies of the Malayan wild pig in Perak and Johore. Malaysian Nature Journal26(2):120-151.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Croves, C. P. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Cenus Sus. Department of Prehistory Technical Bulletin No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hertwig, P. 1936. Artbastarde bei Tieren. Handbuch Vererb Wissenschaften 2B:21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hislop, J. A. 1949. Field notes on the bearded pig. Malaysian Nature Journal 4(2):62-64.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hislop, J. A. 1952. More about the bearded pig. Malaysian Nature Journal 7:22-23.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International Union for the Conservation of Nature. 1972. Red Data Book 1: Mammalia. IUCN, Cland, Switzerland. (This is a loose-leaf binder that is updated from time to time.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kempe, J. E. 1948. The riddle of the bearded pig. Malaysian Nature Journal 3(1):36-42.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lotsy, J. P. 1922. Die Aufarbeitung des kuhn'schen kreuzungsmaterials im Institut fur Tierzucht der Universitat Halle. Cenetica 4:32-61.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MacKinnon, J. 1981. The distribution and status of wild pigs in Indonesia. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 9 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Medway, Lord. 1978. The Wild Mammals of Malaya and Singapore, 2nd Edition. Oxford University Press, Kuala Lumpur, Malaysia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mohr, E. 1960. Wilde Schweine. Die Neue Brehm-Biicherei, A. Ziemsen Verlag, Wittenberg Lutherstadt, Federal Republic of Cermany.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1981. First written report. IUCN/SSC Pigs and Peccaries Specialist group. Unpublished report. 14 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pfeffer, P. 1959. Bologie et migrations du sanglier de Borneo (Sus barbatus Muller 1869). Mammalia 23:277-303.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sulawesi Warty Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appelman, F. J. 1955. Uber Sus celebensis Muller und Schlegel. Der Zoologische Garten 21:152-156.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Catibog-Sinha, C. S. 1981. The quantity and quality of wild food plants and the depredation of wild pigs in the Philippines. Ph.D. thesis. Oklahoma State University, Stillwater Oklahoma, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Croves, C. P. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Cenus Sus. Department of Prehistory Technical Bulletin No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hooijer, D. A. 1968. Pleistocene Vertebrates from Celebes. 8. Sus celebensis Muller and Schlegel, 1845. Beaufortia 16:215-218.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MacKinnon, J. 1981. The distribution and status of wild pigs in Indonesia. IUCN/SSC Pigs and Peccaries Specialist Croup. Unpublished report. 9 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mohr, E. 1960. Wilde Schweine. Die Neue Brehm-Bucherei, A. Ziemsen Verlag, Wittenberg Lutherstadt, Federal Republic of Germany.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1981. Interim report. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 14, pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Javan Warty Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blouch, R. A. 1979. Proposed Bawean Island Wildlife Reserve Management Plan. World Wildlife Fund, Report to Directorate of Nature Conservation, Indonesia. Unpublished report. 63 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blouch, R. A. 1981. Results of a preliminary search for Sus verrucosus in the Mt. Arjuna area. World Wildlife Fund, Meru Betiri Project 1024. Unpublished report. 4 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Groves, C. P. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Genus Sus. Department of Prehistory Technical Bulletin No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hoogerwerf, A. 1970. Udjung Kulonthe Land of the Last Javan Rhinoceros. E. J. Brill, I.eiden. The Netherlands. Pp. 330-349. </P>
+<P ALIGN="JUSTIFY">MacKinnon, J. 1981. The distribution and status of wild pigs in Indonesia. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 9 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1981. First written report. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 14 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigmy Hog</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bosma, A. A., W. L. R. Oliver, and A. A. MacDonald. In press. The karyotype, including g- and c- banding patterns, of the pigmy hog Sus (Porcula) salvanius (Suidae, Mammalia).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Groves, C. T. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Genus Sus. Department of Prehistory Technical Bulletin No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1980. The Pigmy Hog: The Biology and Conservation of the Pigmy Hog Sus (Porcula) salvanius, and the Hispid Hare, Caprolagus hispidus. Special Scientific Report No. I. Jersey Wildlife Preservation Trust. 93 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1981. Pigmy hog and hispid hare: further observations of the continuing decline (or, a lament for Barnadi and a good cause for skepticism). The Dodo, Journal of the Jersey Wildlife Preservation Trust 18:10-20.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Babirus a</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bosma, A. A., 1980. The karyotype of the babirusa (Babyrousa babyrussa); karyotype evolution in the Suidae. Fourth European Colloquium Cytogenetics Domestic Animals 1980:238-241.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bosma, A. A., and De Haan, N. A. 1981. The karyotype of Babrousa babyrussa (Suidae, Mammalia) Acta Zoologica et Pathologica Antverpiensia 76: 17-27.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Davis, D. D. 1940. Notes on the anatomy of the babirusa. Field Museum of Natural History-Zoology 22(5):363-411.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fradich, H. 1974. A comparison of behaviour in the suidae. Pp. 133-144 in The Behaviour of Ungulates and Its Relation to Management. V. Ceist and F. Walther, eds. IUCN Publication No. 24.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Groves, C. P. 1981. Ancestors for the Pigs, Taxonomy and Phylogeny of the Genus Sus. Department of Prehistory Technical Bulletin, No. 3. Australian National University Press, Canberra, Australia. 96 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Croves, C. P. 1980. Notes on the systematics of Babyrousa (Artiodactyla, Suidae). Zoologische Mededelingen, Deel 55(3):29-46.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MacKinnon, J. 1981. The structure and function of the tusks of babirusa. Mammal Review 1 1(1):37-40.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MacKinnon, J. 1981. The distribution and status of wild pigs in Indonesia. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 9 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oliver, W. L. R. 1981. First written report. IUCN/SSC Pigs and Peccaries Specialist Group. Unpublished report. 14 pp.</P>
+<P ALIGN="JUSTIFY">1</P>
+<P ALIGN="JUSTIFY">Selmier, V. J. 1978. Only in Indonesia: the babirusa. Unpublished report to Directorate of Nature Conservation (P.P.A.), Bogor, Indonesia. 40 pp. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Research Contacts</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because Asia contains many livestock breeds about which little is known, an expert committee on Animal Genetic Resources has been recently formed by the Society for the Advancement of Breeding Researchers in Asia and Oceania (SABRAO). Its chairman is Professor J. S. F. Barker of the University of New England, Armidale, New South Wales 2351, Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Species Survival Commission of the International Union for the Conservation of Nature has a Wild Cattle Specialist Group that concerns itself with wild banteng, gaur, and kouprey. Its chairman is Mr. Mohd. Khan bin Momin Khan, Director-General, Wildlife and National Parks, West Malaysia, Kompleks Pejabat-Pejabat Kerajaan, Block K-20, Jalan Duta, Kuala Lumpur, Malaysia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following have particular knowledge of the animals described in this book, have contributed to the various chapters, and (in most cases) have agreed to provide advice to bona fide researchers wishing to study further the animals in this report.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Domesticated Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ida Bagus Arka, Faculty for Veterinary Science and Animal Husbandry, Udayana University, Jalan Sudirman Sanglah, Denpasar, Bali, Indonesia J. S. F. Barker, Department of Animal Science, University of New</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">England, Armidale, New South Wales 2351, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. Bongers, Department of Nature Conservation, Wageningen Agricultural University, Ritzema Bosweg 32a, 6703AZ Wageningen, The Netherlands David Butcher, Western Plains Zoo, Box 813, Dubbo, New South Wales</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2830, Australia (Banteng are available for research projects and zoos.</P>
+<P ALIGN="JUSTIFY">Quarantine for shipments between Australia and most countries are</P>
+<P ALIGN="JUSTIFY">straightforward)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. K. Camoens, Livestock Specialist, Asian Development Bank, P.O. Box 789, Manila, Philippines 2800</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David Deppner, 1603 Dayton Road, Hyattsville, Maryland 20783, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. Devendra, Malaysian Agricultural Research and Development Institute (MARDI), Serdang, Selangor, Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.-M. Duplan, Institut Technique de l'Elevage Bovin, Section Amelioration Genetique, Maison Nationale des Eleveurs, 149, rue de Bercy F, 75595 Paris Cedex 12, France</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Fischer, Institute of Tropical Veterinary Medicine, 63 Giessen, Wilhelmstrasse 15, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S. I. Furtado, Universiti Malaya, Lembah Pantai, Kuala Lumpur 22-11, Malaysia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Hodges, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Huitema, Overzicht 60, 6862 CT, Oosterbeek, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Graham W. M. Kirby, Principal Animal Production Officer, Department of Primary Production, P.O. Box 4160, Darwin, Northern Territory 5790, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moh. Zain Katoe, P.T. United Livestock, Jalan Bau Massepe 472, ParePare, South Sulawesi, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. -G. Klos, Director, Zoologischer Garten Berlin, Hardenbergplatz 8 , 1000 Berlin 30, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prof. Kusmat, Dean, Faculty of Veterinary Medicine, Institut Pertanian Bogor, Jalan Oto Iskandardinata, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ian L. Mason, 8 Ramsay Garden, Edinburgh, EH1 1NA, Scotland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert E. McDowell, Department of Animal Science, Frank B. Morrison Hall, Cornell University, Ithaca, New York 14853, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G. Montsma, Department of Animal Production, Wageningen Agricultural University, Ritzema Bosweg 32a, 6703 AZ Wageningen, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. B. Moran, Senior Research Officer, Animal and Irrigated Pastures Research Institute, Kyabram, Victoria 3620, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jan Nari, Director of Central Research Institute for Animal Science, Jalan Raya Pajajaran, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. M. Nitis, Department of Animal Nutrition and Tropical Pasture Production, Udayana University, Jalan Sudirman Sanglah, Denpasar, Bali, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. J. A. Payne, 91 Bedwardine Road, London SE19 3AY, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Donald L. Plucknett, Consultative Group on International Agricultural Research, 1818 H Street, Washington, D.C. 20433, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research Institute for Animal Production, P.O. Box 123, Bogor, Indonesia (Amber Roesyat, Ian Fletcher, Dennis Hoffmann, P. Sitorus, Subandriyo, M. Zulbardi)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David W. Robinson, International Programs, University of California, Davis, California 95616, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. H. L. Rollinson, Animal Production and Health Division, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G. Seifert, CSIRO, Tropical Cattle Research Centre, P.O. Box 5545, Rockhampton Mail Centre, N. Rockhampton, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. David Simpson, Senior Extension Specialist, Veld, Pastures and Wildlife, Agritex Box 363, Bulawayo, Zimbabwe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. J. Smith, Tropical Animal Health, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Summerhall, Edinburgh, EH9 1QH Scotland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dukut Sularsasa, Department of Tropical Veterinary Science, James Cook University, Townsville, Queensland 4811, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. Syamsul Arifin, Jalan Amin Jakfar 41, Pamekasan Madura, Jatim, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taronga Zoo, P.O. Box 20, Mosman, New South Wales 2088, Australia (T. Finnie and J. L. Throp)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frank M. Thompson, Wild Animal Brokers, 15605 S. R. #64, Bradenton, Florida 33508, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Allen D. Tillman, 523 West Harned Place, Stillwater, Oklahoma 74074, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Don Tulloch, P.O. Box 38841, Winnellie, Northern Territory 5789, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Helen Newton Turner, P.O. Box 184, North Ryde, New South Wales 2113, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antoon de Vos, P.O. Box 34, Whitford, Auckland, New Zealand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert Warren, Department or Range and Wildlife Management, Texas Tech University, Lubbock, Texas 79409, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Everett J. Warwick, The Rockefeller Foundation, P.O. Box 63, Yogyakarta, D.I.Y., Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Woodward, 35AI, Sultan Hasanudin, Ujung Pandang, South Sulawesi, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Domesticated Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antwerp, Belgium (Royal Zoological Society of Antwerp)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Askaniya-Nova, USSR (Zoologicheskii Park Askaniya-Nova)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bangkok, Thailand (Dusit Zoological Park; banteng-mithan hybrid)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berlin, Federal Republic of Germany (Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berlin, German Democratic Republic (Tierpark Berlin)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Copenhagen, Denmark (Zoologisk Have)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dubbo, New South Wales, Australia (Western Plains Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jakarta, Indonesia (Kebun Binatang Ragunan)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kiev, USSR (Kievskii Zoologicheskii Park)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madrid, Spain (Zoo de la Casa de Campo; mithan-banteng hybrid)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pretoria, South Africa (National Zoological Gardens of South Africa) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rome, Italy (Giardino Zoologico e Museo de Zoologia del Comune de Rome and Zoorama)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rotterdam, The Netherlands (Stichting Koninklijke Rotterdamse Diergaarde; 2 male, 2 female, may be wild form)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surabaya, Indonesia (Kebun Binatang Surabaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yogyakarta, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Banteng-Cattle Hybrids</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abubakar Aldjufri, Secretary, Asian Livestock Business Club, Kebun Pala I/79B Tanah Abang, Jakarta, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Saleh Aldjufri, Jalan Jakarta 42, Surabaya, Jawa Timur, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David Deppner, 1603 Dayton Rd., Hyattsville, Maryland 20783, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Huitema, Overzicht 60, 6862 CT, Oosterbeek, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Graham W. M. Kirby, Principal Animal Production Officer, Department of Primary Production, P.O. Box 4160, Darwin, Northern Territory 5790, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. B. Moran, Senior Research Officer, Animal and Irrigated Pastures Research Institute, Kyabram, Victoria 3620, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. J. A. Payne, 91 Bedwardine Road, London SE19 3AY, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David W. Robinson, International Programs, University of California, Davis, California 95616, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. H. L. Rollinson, Animal Production and Health Division, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B. Wheeler, 1000 Shady Lane, College Station, Texas 77840, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mithan</P>
+<P ALIGN="JUSTIFY">Chaichana Satrulee, Dusit Zoological Park, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">H. Fischer, Institute of Tropical Veterinary Medicine, 63 Giessen, Wilhelmstrasse 15, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. von Furer Haimendorf, School of Oriental and African Studies, University of London, London WC1, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles G. Hickman, Livestock Consultant, A. Mithat Efendi Sokak No. 36/11, Cankaya, Ankara, Turkey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frederick J. Simoons, 140 Bartlett Ave., Woodland, California 95695, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Mithan (Gayal)</P>
+<P ALIGN="JUSTIFY">Aalborg, Denmark (Aalborg Zoologiske Have)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Amsterdam, The Netherlands (Stichting Koninklijk Zoologisch) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arnhem, The Netherlands (Burgers' Zoo and Safari)</P>
+<P ALIGN="JUSTIFY">Bangkok, Thailand (Dusit Zoological Park)</P>
+<P ALIGN="JUSTIFY">Berlin, German Democratic Republic (Tierpark Berlin)</P>
+<P ALIGN="JUSTIFY">Calcutta, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cologne, Federal Republic of Germany (Aktiengesellschaft Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Heidelberg, Federal Republic of Germany (Tiergarten Heidelberg)</P>
+<P ALIGN="JUSTIFY">Kolmarden, Sweden (Koemardens Djurpark)</P>
+<P ALIGN="JUSTIFY">Madrid, Spain (Zoo de la Casa de Campo; mithan-banteng hybrid)</P>
+<P ALIGN="JUSTIFY">Rabat, Morocco (Pare Zoologique National)</P>
+<P ALIGN="JUSTIFY">Vienna, Austria (Schonbrunn Zoo)</P>
+<P ALIGN="JUSTIFY">Tallin, USSR (Tallinna Loomaaed)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yak</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joseph Bonnemaire, Ecole Nationale Superieure des Sciences Agronomiques Appliquees, 26, Bd. Docteur Petitjean, 21100 Dijon, France</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corneille Jest, Centre National de la Recherche Scientifique, 1, Place Artistide-Briand, 92190 Meudon, France</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. A. Kazarova, Director, Riga Zoological Garden, Meza prospekt 1, Riga 14 226014, Latvian SSR, USSR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">K. K. Panday, Swiss Association for Technical Assistance (SATA), Box 113, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ralph W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Patrick J. Robinson, Department of Agricultural and Forest Sciences, University of Oxford, Commonwealth Forestry Institute, South Parks Road, Oxford OX1 3RB, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">George B. Schaller, New York Zoological Society, 185 and Southern Blvd., New York, New York 10460, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">T. B. Singh, Director General, Department of Livestock, HMG, Harihar Bhawan, Pulchowk, Laitpur, Nepal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Societe d'Ethnozootechnie, 25, Boulevard Arago, 75013 Paris, France (R. Laurans)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Yak</P>
+<P ALIGN="JUSTIFY">Antwerp, Belgium (Royal Zoological Society of Antwerp)</P>
+<P ALIGN="JUSTIFY">Arnhem, The Netherlands (Burgers' Zoo and Safari)</P>
+<P ALIGN="JUSTIFY">Baltimore, Maryland, USA</P>
+<P ALIGN="JUSTIFY">Bronx, New York, USA (New York Zoological Park)</P>
+<P ALIGN="JUSTIFY">Chicago, Illinois, USA (Brookfield Zoo)</P>
+<P ALIGN="JUSTIFY">Denver, Colorado, USA (Denver Zoological Gardens)</P>
+<P ALIGN="JUSTIFY">Detroit, Michigan, USA (Detroit Zoological Park)</P>
+<P ALIGN="JUSTIFY">Evansville, Indiana, USA (Meeker Park Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Granby, Quebec, Canada (Societe Zoologique de Granby, Inc.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grand Rapids, Michigan, USA (John Ball Zoological Gardens)</P>
+<P ALIGN="JUSTIFY">Kansas City, Missouri, USA (Kansas City Zoological Gardens)</P>
+<P ALIGN="JUSTIFY">Knoxville, Tennessee, USA (Knoxville Municipal Zoo)</P>
+<P ALIGN="JUSTIFY">London, England</P>
+<P ALIGN="JUSTIFY">Rochester, New York, USA (Seneca Park Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rotterdam, The Netherlands (Stichting Koninklijke Rotterdamse Diergaarde)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Diego, California, USA (San Diego Wild Animal Park)</P>
+<P ALIGN="JUSTIFY">Sioux Falls, South Dakota, USA (Great Plains Zoo)</P>
+<P ALIGN="JUSTIFY">South Bend, Indiana, USA (Potawatomi Park Zoo)</P>
+<P ALIGN="JUSTIFY">Syracuse, New York, USA (Burnet Zoo)</P>
+<P ALIGN="JUSTIFY">Toronto, Ontario, Canada (Metro Toronto Zoo)</P>
+<P ALIGN="JUSTIFY">Utica, New York, USA (Utica Zoo)</P>
+<P ALIGN="JUSTIFY">Wichita, Kansas, USA (Sedgwick County Zoo)</P>
+<P ALIGN="JUSTIFY">West Orange, New Jersey, USA (Turtleback Zoo)</P>
+<P ALIGN="JUSTIFY">Winnipeg, Manitoba, Canada (Assiniboine Park Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yakows</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joseph Bonnemaire, Ecole Nationale Superieure des Sciences Agronomiques Appliquees, 26, Bd. Docteur Petitjean, 21100 Dijon, France</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Agriculture, Hari Har Bhawan, Pulchok, Lalitpur, Kathmandu, Nepal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Husbandry and Veterinary Science, Kathmandu, Nepal (Tewari and Burathoky)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director of Livestock Development, Peking, China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Professor Karl Fredge, Department of Genetics, University of Uppsala, Uppsala, Sweden</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indian Veterinary Research Institute, P.O. Izatnagar 243 122, Uttar Pradesh, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock Division, National Agricultural Research Center, Islamabad, Pakistan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Sheep and Yak Development Project, Dechhen Pelrithang, P.O. Bumthang, Bhutan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ralph W. Phillips, The Representative, Apartment 810, 1101 South Arlington Ridge Road, Arlington, Virginia 22202, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Patrick J. Robinson, Department of Agricultural and Forest Sciences, University of Oxford, Commonwealth Forestry Institute, South Parks Road, Oxford OX1 3RB, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whipsnade Zoo, Whipsnade, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bruce A. Young, Department of Animal Science, University of Alberta, Edmonton, Alberta TOG 2P5, Canada </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wild Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Amir, c/o Ministry of Development Supervision and the Environment, JalanMirdekaBarat 15, Jakarta, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. H. Blower, National Parks Project, c/o UNDP, Box 650, Rangoon, Burma</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bonsong Lekagul, Association for the Conservation of Wildlife, No. 4 Customhouse Road, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chaichana Satrulee, Dusit Zoological Park, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Z. Coto, Tropical Forest Biology, SEAMEO-BIOTROP, P.O. Box 17, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Forest Department, P.O. Box 311, Sandakan, Sabah, Malaysia (Patrick Andau, Assistant Chief Game Warden)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. R. Grimwood, P.O. Box 45079, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The Australian National University, P.O. Box 4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">U. Halder, Swiss League for Nature Conservation, P.O. Box 73, CH4020 Basel, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Huitema, Overzicht 60, 6862 CT, Oosterbeek, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. Wayne King, Director and Professor, Florida State Museum, University of Florida, Gainesville, Florida 32601, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lembaga Biologi Nasional (LBN-LIPI), Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John A. Lukas, White Oak Plantation, Rt. 3 Box 224, Yulee, Florida 32097, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jeffrey A. McNeely, Executive Officer, Commission on National Parks and Protected Areas, International Union for Conservation of Nature and Natural Resources, Avenue du Mont-Blanc, 1196 Gland, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Payne, Wildlife Section, Forest Department, P.O. Box 311, Sandakan, Sabah, Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Somtob Norapuckprutikorn, Captive Propagation Section, Wildlife Conservation Division, Royal Forest Department, Bangkhen, Bangkok 9, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B. Wheeler, 1000 Shady Lane, College Station, Texas 77840, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Wild Banteng</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Albuquerque, USA (Rio Grande Zoological Park)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Amsterdam, The Netherlands (Stichting Koninklijk Zoologisch)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bangkok, Thailand (Dusit Zoological Park)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berlin, Federal Republic of Germany (Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chicago, Illinois, USA (Brookfield Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cologne, Federal Republic of Germany (Aktiengesellschaft Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Copenhagen, Denmark (Zoologisk Have)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Darmstadt, Federal Republic of Germany (Vivarium Darmstadt)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dortmund, Federal Republic of Germany (Tierpark Dortmund)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dresden, German Democratic Republic (Zoologischer Garten Dresden)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frankfurt, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jakarta, Indonesia (Kebun Binatang Ragunan)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Diego, California, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">St. Louis, Missouri, USA (St. Louis Zoological Park)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surabaya, Indonesia (Kebun Binatang Surabaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yogyakarta, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yulee, Florida, USA (White Oak Plantation)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gaur</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Aspinal, Howlett's Wildlife Park, near Canterbury, Kent, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul, Association for the Conservation of Wildlife, No. 4 Customhouse Road, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paul Conry, Division of Aquatic and Wildlife Resources, Department of Agriculture, P.O. Box 23367, GMF Guam 96921, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Fischer, Institute of Tropical Veterinary Medicine, 63 Giessen, Wilhelmstrasse 15, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. R. Grimwood, P.O. Box45079, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mohd Khan bin Momin Khan, Director-General, Department of Wildlife and National Parks, P.O. Box 611, Kuala Lumpur, Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. A. Kazarova, Director, Riga Zoological Garden, Meza prospekt 1, Riga 14 226014, Latvian SSR, USSR</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H.-G. Klos, Director, Zoologischer Garten Berlin, Hardenbergplatz 8, 1000 Berlin 30, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adrian G. Marshall, Department of Zoology, University of Aberdeen, Aberdeen, Scotland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">George B. Schaller, New York Zoological Society, 185 and Southern Blvd., New York, New York 10460, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lee Simmons, Omaha Zoo, Omaha, Nebraska 68108, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Janet Stover, Bronx Zoo, 185 and Southern Blvd., New York, New York 10460, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frank M. Thompson, Wild Animal Brokers, 15605 S. R. #64, Bradenton, Florida 33508, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Guar </P>
+<P ALIGN="JUSTIFY">The Berlin Zoo was assigned by the IUCN in cooperation with the</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">lUDZG to keep the guar studbook records. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bangkok, Thailand (Dusit Zoological Park)</P>
+<P ALIGN="JUSTIFY">Berlin, Federal Republic of Germany (Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY">Bronx, New York, USA (New York Zoological Park; 7 male, 3 female)</P>
+<P ALIGN="JUSTIFY">Brownsville, Texas, USA (Gladys Porter Zoo; 5 male, 10 female)</P>
+<P ALIGN="JUSTIFY">Copenhagen, Denmark (Zoologisk Have; 1 male, 2 female)</P>
+<P ALIGN="JUSTIFY">Holiday Island, Eureka Springs, Arkansas, USA</P>
+<P ALIGN="JUSTIFY">Hyderabad, Andhra Pradesh, India (Nehru Zoological Park)</P>
+<P ALIGN="JUSTIFY">Ivey, Wilburton, Oklahoma, USA</P>
+<P ALIGN="JUSTIFY">Kansas City, Missouri, USA (Kansas City Zoological Gardens; I male)</P>
+<P ALIGN="JUSTIFY">Kings Mill, Ohio, USA (Wild Animal Safari,; 1 male)</P>
+<P ALIGN="JUSTIFY">Kuala Lumpur, Malaysia</P>
+<P ALIGN="JUSTIFY">London, England</P>
+<P ALIGN="JUSTIFY">Los Angeles, California, USA (The Los Angeles Zoo; I male, 3 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Memphis, Tennessee, USA (Memphis Zoo and Aquarium; I male, 2 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Munich, Federal Republic of Germany (Munchener Tierpark Hellabrunn Ag)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mysore, Karnataka, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oklahoma City, Oklahoma, USA (Oklahoma City Zoo; 7 male, 7 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Omaha, Nebraska, USA (Henry Doorly Zoological Gardens; 7 male, 15 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Riga, Latvian SSR, USSR (Riga Zoological Garden)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Diego, California, USA (San Diego Wild Animal Park; 6 male, 6 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Bend, Indiana, USA (Potawatomi Park Zoo; 1 male)</P>
+<P ALIGN="JUSTIFY">St. Louis, Missouri, USA (St. Louis Zoological Park; 1 male, 2 female)</P>
+<P ALIGN="JUSTIFY">Toronto, Ontario, Canada (Metro Toronto Zoo; 3 male, 1 female)</P>
+<P ALIGN="JUSTIFY">Vienna, Austria (Schonbrunn Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kouprey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boonsong Lekagul, Association for the Conservation of Wildlife, No. 4 Customhouse Road, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Harold Coolidge, 38 Standley Street, Beverly, Massachusetts 01915, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jeffrey A. McNeely, Executive Officer, Commission on National Parks and Protected Areas, International Union for Conservation of Nature and Natural Resources, Avenue du Mont-Blanc, 1196 Gland, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Harvey C. Neese, P.O. Box 332, Troy, Idaho 83871, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David Anthony Parkinson, White House, San Roque 1, San Jose, Occidental Mindoro, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pierre Pfeffer, Zoologie, Mammiferes et Oiseaux Museum National d'Histoire Naturelle 55, rue de Buffon 75005 Paris, France</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. Kelly Shelton, 211-A North Cordova, Burbank, California 91505, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Henry Stoddard, Branford Veterinary Clinics, Inc., P.O. Box 548, Branford, Florida 32008, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles H. Wharton, Institute of Ecology, University of Georgia, Athens, Georgia 30602, USA (Rt. 2, Clayton, Georgia 30525)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">World Conservation Centre, Avenue du Mont-Blanc, CH 1196 Gland, Switzerland (David Mitchell, Elizabeth Kemf)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Kouprey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">None</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anoas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. M. Dolan, San Diego Zoological Garden, San Diego, California 92112, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Fischer, Institute of Tropical Veterinary Medicine, 63 Giessen, Wilhelmstrasse 15, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The Australian National University, P.O. Box 4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Anoas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antwerp, Belgium (Royal Zoological Society of Antwerp; mountain anoa)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berlin, Federal Republic of Germany (Zoologischer Garten; mountain anoa)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">London, England (lowland anoa)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Leipzig, German Democratic Republic (Zoologischer Garten Leipzig; mountain anoa)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jakarta, Indonesia (Kebun Binatang Ragunan) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rotterdam, The Netherlands (Stichting Koninklijke Rotterdamse Diergaarde; 1 male, 3 female)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Diego, California, USA (San Diego Zoological Garden; 1 male)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Diego, California, USA (San Diego Wild Animal Park; 1 male)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surabaya, Indonesia (Kebun Binatang Surabaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sydney, New South Wales, Australia (Taronga Park Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tamaraw</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Natural Resources, Quezon City, Manila, Philippines (J. B. Alvarez, Jr., Assistant Director)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Fischer, Institute of Tropical Veterinary Medicine, 63 Giessen, Wilhelmstrasse 15, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I. R. Grimwood, P.O. Box 45079, Nairobi, Kenya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Natural Resources Conservation Office, Ministry of Natural Resources, Visayas Avenue, Diliman, Quezon City, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David Anthony Parkinson, White House, San Roque 1, San Jose, Occidental Mindoro, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ian Player, P.O. Box 192, Howick 3290, Natal, South Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N. Sitwell, c/o WWF(UK), 11-13 Ockford Rd., Godalming, Surrey GU7 lQU, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">L. M. Talbot, 6656 Chilton Court, McLean, Virginia 22101, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Forest Research Institute, College, Laguna 3720, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bearded Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Julian Oliver Caldecott, Sub-Department of Veterinary Anatomy, University of Cambridge, Downing Street, Cambridge CB2 3DY, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The AustralianNationalUniversity, P.O. Box4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alastair A. Macdonald, Department of Anatomy, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh EH9 10H, Scotland, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. MacKinnon, WWF/IUCN Representative, P.O. Box 133, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Parks and Wildlife Office, Sarawak Forest Department, Jalan Gartak, Kuching, Sarawak, Malaysia (Kron Aken, David Labang, Mike Kavanagh)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. L. R. Oliver, Jersey Wildlife Preservation Trust, Les Augres Manor, Jersey, Channel Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Payne, Wildlife Section, Forest Department, P.O. Box 311, Sandakan, Sabah, Malaysia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Bearded Pig</P>
+<P ALIGN="JUSTIFY">Singapore, Singapore</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Manila, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sulawesi Warty Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. Catibog-Sinha, Outdoor Recreation and Wildlife Research Division, Forest Research Institute, College, Laguna 3720, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The AustralianNationalUniversity, P.O. Box4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alastair A. Macdonald, Department of Anatomy, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh EH9 10H, Scotland, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. Mackinnon, WWF/TUCN Representative, P.O. Box 133, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. L. R. Oliver, Jersey Wildlife Preservation Trust, Les Augres Manor, Jersey, ChanneL Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Sulawesi Warty Pig</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">None.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Javan Warty Pig</P>
+<P ALIGN="JUSTIFY">Raleigh A. Blouch, 2125 Forest Glen, Lansing, Michigan 48906, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">A. A. Bosma, Department of Functional Morphology, Faculty of Veterinary Sciences, State University Utrecht, P.O. Box 80157, 3508 TD Utrecht, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Directorate of Nature Conservation (PPA), Jalan Ir. H. Juanda 9, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The Australian National University, P.O. Box 4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lembaga Biologi Nasional (LBN-LIPl), Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alastair A. Macdonald, Department of Anatomy, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh EH9 10EI, Scotland, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. MacKinnon, WWF/IUCN Representative, P.O. Box 133, Bogor, Indonesia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. L. R. Oliver, Jersey Wildlife Preservation Trust, Les Augres Manor, Jersey, Channel Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Werner Pauwels, Pfeffingerstrasse 48, CM-053, Basel, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perum Perhutani, Forest State Corporation, Jalan Jendral Gatot Subroto 17-18, Post Box 111, Jakarta, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M. H. Woodford, c/o FORW, FAO, Via delle Terme di Caracalla, 00100 Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Javan Warty Pig</P>
+<P ALIGN="JUSTIFY">Jakarta, Indonesia (Kebun Binatang Ragunan)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surabaya, Indonesia (Kebun Binatang Surabaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pigmy Hog</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. A. Bosma, Department of Functional Morphology, Faculty of Veterinary Sciences, State University Utrecht, P.O. Box 80157, 3508 TD Utrecht, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P. C. Gogoi, Adviser Forests, (Wildlife and Environmental Planning), Meghalaya, P.O. Shillong 793 001, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The AustralianNationalUniversity, P.O. Box4, Canberra, ACT 2600, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alastair A. Macdonald, Department of Anatomy, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh EH9 lOH, Scotland, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. MacKinnon, WWF/IUCN Representative, P.O. Box 133, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. L. R. Oliver, Jersey Wildlife Preservation Trust, Les Augres Manor, Jersey, Channel Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S. Deb Roy, Manas National Park, P.O. Barpeta Road, Kamrup 781 315, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Pigmy Hog</P>
+<P ALIGN="JUSTIFY">Gauhati, India (Assam State Zoo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zurich, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Babirusa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. A. Bosma, Department of Functional Morphology, Faculty of Veterinary Sciences, State University Utrecht, P.O. Box 80157, 3508 TD Utrecht, The Netherlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C. P. Groves, Department of Prehistory and Anthropology, The Australian National University, P.O. Box 4, Canberra, ACT 2600, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alastair A. Macdonald, Department of Anatomy, Royal (Dick) School of Veterinary Studies, University of Edinburgh, Edinburgh EH9 lOH, Scotland, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. MacKinnon, WWF/IUCN Representative, P.O. Box 133, Bogor, Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. L. R. Oliver, Jersey Wildlife Preservation Trust, Les Augres Manor, Jersey, Channel Islands, United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Victoria Selmier, 353 10th Street, San Francisco, California 94103, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zoos with Babirusa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antwerp, Belgium (Royal Zoological Society of Antwerp, W. de Meurichy)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bandung, Indonesia</P>
+<P ALIGN="JUSTIFY">Berlin, Federal Republic of Germany, (Zoologischer Garten)</P>
+<P ALIGN="JUSTIFY">Copenhagen, Denmark, (Zoologisk Have)</P>
+<P ALIGN="JUSTIFY">Frankfurt, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY">Jakarta, Indonesia, (Kebun Binatang Ragunan)</P>
+<P ALIGN="JUSTIFY">Nuremberg, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY">Poznan, Poland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rotterdam, The Netherlands (Stichting Koninklijke Rotterdamse Diergaarde)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Stuttgart, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY">Surabaya, Indonesia, (Kebun Binatang Surabaya)</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Advisory Committee on Technology Innovation</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY">WILLIAM BRADLEY, Consultant, New Hope, Pennsylvania</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">HAROLD DREGNE, Director, International Center for Arid and Semi-Arid Land Studies, Texas Tech University, Lubbock, Texas (member through 1981) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CARL N. HODGES, Director, Environmental Research Laboratory, Tucson, Arizona </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CYRUS MCKELL, Native Plants, Inc., Salt Lake City, Utah </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOlS MERGEN, Pinchot Professor of Forestry, School of Forestry and Environmental Studies, Yale University, New Haven, Connecticut (member through 1982) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Consultative Group on International Agricultural Research, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THEODORE SUDIA, Deputy Science Advisor to the Secretary of Interior, Department of Interior, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Board on Science and Technology for International Development</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE BUGElARELLO, President, Polytechnic Institute of New York, Brooklyn, New York, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SAMUEL P. ASPER, Educational Commission for Foreign Medical Graduates, Philadelphia, Pennsylvania </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DAVID BELL, Department of Population Sciences, Harvard School of Public Health, Boston, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LEONARD BERRY, Professor, Graduate School of Geography, Clark University, Worcester, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ERNEST.J. BRISKEY, Dean, School of Agriculture, Oregon State University, Corvallis, Oregon </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARRISON S. BROWN, Director, Resources Systems Institute, East-West Center, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT H. BURRIS, Department of Biochemistry, University of Wisconsin, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CLAUDIA JEAN CARR, Associate Professor, Conservation and Resource Studies, University of California at Berkeley, Berkeley, California </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATE FIELDS, Director, Developing Markets, Control Data Corporation, Minneapolis, Minnesota </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROLAND J. FUCHS, Chairman, Department of Geography, University of Hawaii at Manoa, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN HOWARD GIBBONS, Director, U.S. Congress, Office of Technology Assessment, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N. BRUCE HANNAY, Foreign Secretary, National Academy of Engineering, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM HUGHES, Director, Engineering Energy Laboratory, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM A. W. KREBS, Vice President, Arthur D. Little, Inc., Acorn Park, Cambridge, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE I. LYTHCOTT, University of Wisconsin, School of Medicine, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JANICE E. PERLMAN, Executive Director, Committee for a New New York, New York City Partnership, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK C. ROBBINS, President, Institute of Medicine, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WALTER A. ROSENBLITH, Foreign Secretary, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY">FREDERICK SEITZ, President Emeritus, The Rockefeller University, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH HERBERT SMUCKLER, Dean of International Studies and Programs, Michigan State University, East Lansing, Michigan </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GILBERT F. WHITE, Institute of Behavioral Science, University of Colorado, Boulder, Colorado </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BILL C. WRIGHT, Assistant Dean for International Programs, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN G. HURLEY, Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">MICHAEL G. C. McDONALD DOW, Associate Director/Studies </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL P. GREENE. Associate Director/Research Grants </P></FONT>
+<!--
+</Section>
+</Section>
+-->
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b18ase/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b18ase/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b18ase/metadata.xml	(revision 10506)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">Little Known Asian Animals With a Promising Economic Future (b18ase)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Animal Husbandry and Animal Product Processing|Other animals (micro-livestock, little known animals, silkworms, reptiles, frogs, snails, game, etc.)</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">BOSTID</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+            <Metadata mode="accumulate" name="dls.Keyword">introduce little-known Asian farm animals with a promising future</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b20cre/b20cre.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b20cre/b20cre.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b20cre/b20cre.htm	(revision 10506)
@@ -0,0 +1,1134 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Managing Tropical Animal Resources - Crocodiles as a Resource for the Tropics</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Managing Tropical Animal Resources - Crocodiles as a Resource for the Tropics</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Report of an Ad Hoc Panel of the</P>
+<P ALIGN="JUSTIFY">Advisory Committee on Technology Innovation</P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development</P>
+<P ALIGN="JUSTIFY">Office of International Affairs</P>
+<P ALIGN="JUSTIFY">National Research Council</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Cooperation with the Division of Wildlife, Department of Lands and Environment, Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATIONAL ACADEMY PRESS</P>
+<P ALIGN="JUSTIFY">Washington, D.C. 1983</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development(BOSTID) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Panel on Crocodile Farming</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Director, Office of Biological Conservation, Smithsonian Institution, Washington, D.C., USA, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HOWARD W. CAMPBELL (deceased) U.S. Fish and Wildlife Service, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ARCHIE F. CARR, Jr., Department of Zoology, University of Florida, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. WAYNE KING, Director, Florida Museum, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOIS MERGEN, Pinchot Professor of Forestry, Yale University, New Haven, Connecticut, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. MORRIS, Furzebrook Research Station, Institute of Terrestrial Ecology, Wareham, Dorset, England </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, USA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT M. PYLE, Species Conservation Monitoring Unit, Cambridge, England </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SHELDON R. SEVERINGHAUS, Representative, The Asia Foundation, Taipei, Taiwan </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contributors</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CAROL GABARA, Wildlife Division, Department of Oro Province, Popondetta </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WASSAM GABARA, Wildlife Division, Department of Oro Province, Popondetta </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">KAROL KISOKAU, Director, Office of Environment and Conservation, Waigani </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NAVU KWAPENA, Division of Wildlife, Department of Lands and Environment, Konedobu </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MIRO LAUFA, Division of Wildlife, Department of Lands and Environment, Konedobu </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GREG MITCHELL, Crocodile Farm, Lae </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LEO NING, Division of Wildlife, Department of Lands and Environment, Wewak </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MIGUEE AEVAREZE DEE TORO, Instituto de Historia Natural, Departamento de Zoologia, Chiapas, Mexico</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ANGUS D'A.BELLAIRS, Department of Anatomy, St. Mary's Hospital Medical School, University of London, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PETER BRAZAITIS, Department of Herpetology, New York Zoological Society, Bronx, New York, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT H.CHABRECK, Louisiana Cooperative Wildlife Research Unit, Louisiana State University, Baton Rouge, Louisiana, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MAX C.DOWNES, The Game Conservation Centre, Melbourne, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">KARLHEINZ FUCHS, hoechst Aktiengesellschaft, Frankfurt, Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CLAIRE HACEN, Reptile Products Association, New York, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RENEE.HONEGGER, Zurich Zoo, Zurich, Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TED JOANEN, Rockefeller Wildlife Refuge, Chenier, Louisiana, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN LEVER, Koorana Crocodile Farm, Rockhampton, Queensland, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM MAGNUSSON, Instituto Nacional de Pesquisas da Amazonia, Manaus, Amazonia, Brazil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARRY MESSEE, School of Physics, University of Sydney, Sydney, New South Wales, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRED PARKER, Kirwan Queensland, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ANTHONY POOLEY, St. Lucia Estuary, Zululand, South Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHARLES A.ROSS, National Museum of Natural History, Smithsonian Institution, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">K.B.SALE, UNDP/FAO Crocodile Breeding and Management Project, Hyderabad, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LUISVARONA, La Habana, Cuba</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHAROON YOUNGPRAPAKORN, The Samutprakan Crocodile Farm, Samutprakan, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UTAl YOUNGPRAPAKORN, The Samutprakan Crocodile Farm, Samutprakan, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MYRNA WATANABE, Co-editor of ICUN Newsleter, Brooklyn, New York, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROMULUS WHITAKER, Guindy Deer Park, Madras, India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, Professional Associate, Board on Science and Technology for International Development, Crocodile Study Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Research Council Staff</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. R. RUSKIN, BOSTID Editor</P>
+<P ALIGN="JUSTIFY">MARY lANE ENGQUIST, Staff Associate</P>
+<P ALIGN="JUSTIFY">CONSTANCE REGES, Administrative Secretary</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This publication is dedicated to the memory of panel member Howard W. "Duke" Campbell who devoted most of his professional life to the conservation of crocodilians. Dr. Campbell was Chairman of the Crocodilian Specialist Group of the Survival Commission of the International Union for Conservation of Nature and Natural Resources at the time of his death in 1981.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Preface</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel that produced this report met in Papua New Guinea in May 1981. Its purpose was to consider the principles of the Papua New Guinea crocodile farming program and their implications for economic development and for the management and survival of crocodilians elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles are an integral part of the tropical fauna; they are ecologically important, biologically interesting, and, potentially, a renewable natural resource of considerable economic value. The panel hopes that through this report the possibility of saving and managing this animal throughout the tropics can be better assessed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members of the panel consulted officials of the Ministry of Wildlife and Conservation in Port Moresby and visited crocodile farms in Moitaka, Popondetta, and Lae. The panel is grateful to Karol Kisokau, Navu Kwapena, and Miro Laufa of the Division of Wildlife for arranging its itinerary and visits in Papua New Guinea. It also wishes to thank Yano Belo, Minister of Environment, for hosting an evening social at the Moitaka crocodile farm; Greg Mitchell and his wife Judy, who entertained the panel at their home in Lae and conducted a tour of their company's crocodile farm; and Wassam and Carol Gabara who acted as guides and hosts in Popondetta.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Advisory Committee on Technology Innovation (ACTI) of the Board on Science and Technology for International Development, National Research Council, is assessing scientific and technological advances that might prove especially applicable to problems of developing countries. This report is one of a series that explores promising areas of science previously unknown, neglected, or overlooked. Current titles in the ACT! series on Managing Tropical Animal Resources include:</P>
+<P ALIGN="JUSTIFY">· Water Buffalo: New Prospects for an Underutilized Animal (1981) </P>
+<P ALIGN="JUSTIFY">· Little-Known Asian Animals with a Promising Economic Future (1983) </P>
+<P ALIGN="JUSTIFY">· Crocodiles as a Resource for the Tropics (1983) </P>
+<P ALIGN="JUSTIFY">· Butterfly Farming in Papua New Guinea (1983) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These activities are supported largely by the U.S. Agency for International Development (AID). Program costs for this study were sponsored by AID'S Bureau for Asia, and staff costs by AID'S Office of the Science Advisor, which also made possible the free distribution of this report. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">1 Introduction</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles, alligators, caimans, and gavials ( Present-day crocodilians are grouped into three families: crocodiles, alligators and caimans, and gavials (gharials). The animals differ from one another only in minor characters such as shape of snout, arrangement of scutes, and dental features. This report focuses mainly on crocodile species, but its conclusions are generally applicable to alligators, caimans, and gavials.) have existed for some 200 million years - much longer than mammals - but they are now disappearing at alarming rates. Of the 21 or so species of crocodilians distributed in the warm waters of the world, at least 18 are threatened with extinction in most of the countries where they are found.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although some species, such as the American alligator, appear to be out of danger because of strict conservation measures, many of the others survive mostly in national parks, protected preserves, or a few breeding stations. This is true for the slender-spouted crocodiles of Africa and Asia, the saltwater crocodile of Australia and Southeast Asia, the black caiman and Orinoco crocodile of South America, the Chinese alligator, the Siamese crocodile, and other species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat destruction is a major contributor to crocodilian decline; each year more breeding areas are disturbed as swamps and marshlands are drained, rivers dammed, estuaries reclaimed, and riverine forests denuded. However, illegal poaching by tribal people with their simple but effective traps, snares, and set hooks, as well as professional hunters operating with power boats, spotlights, and modern firearms are also decimating the animals over most of their ranges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To a large extent these animals are being destroyed because of their market value. Crocodile is regarded as the costliest and most fashionable leather in western markets. Since World War II, demand for crocodile leather shoes, handbags, luggage, wallets, watchbands, and other expensive luxury articles has far exceeded supply. Even small items such as purses and handbags sell for many hundreds of dollars each. For instance, a ladies' purse or handbag made from crocodile skin can command prices as high as $4,000. A pair of men's shoes may cost from $500 to $900, and a wallet from $150 to $250.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The crocodile trade peaked in the mid-1960s, when world markets absorbed more than 2 million crocodile skins each year. Today it is still large. In 1979, for instance, 1,000,000 caiman hides and 300,000 true crocodile hides entered international commerce. In 1981 the United States itself imported 100,000 hides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International markets for reptile hides and leathers are centered in France, Italy, the Federal Republic of Germany, and Japan. France, the single largest buyer of raw crocodilian hides, uses an estimated 300,000 to 400,000 skins a year. The major buyers of finished crocodile leather products are Hong Kong, Japan, Thailand, Singapore, and the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unrestricted hunting and poaching for hides are wiping out the large breeding animals. Excessive hunting has a devastating effect on crocodile populations because their age distribution is like a pyramid: a small number of breeding animals dominates a large number of juveniles and hatchlings, most of which never survive to maturity. Such societies, in which the size of future populations depends on only a few animals, are highly vulnerable to extinction; once some of the mature members are killed the population can crash. And it takes a long time for a crocodilian population to rebuild because for most large species the females do not begin breeding until they are at least 8 years old.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rearing Crocodiles</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there may seem to be no future for many crocodile populations, the situation is not hopeless. With intelligent intervention and under good conditions they can recover rapidly. Mature crocodiles have no enemies other than man, and, given some care and protection, a small number of breeders can produce a huge number of progeny each year. Mature females of the various crocodilian species usually lay between 30 and 70 eggs each year, and under normal conditions most of these eggs hatch successfully. The key to conserving the population is to protect the few mature animals and their habitats. Then, because of their fecundity, crocodilians can rapidly build up large numbers of young.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This has been exemplified by the American alligator (Alligator mississippiensis). Ten years ago its future seemed doubtful, but the legal protection of the populations has brought a remarkable recovery. Numbers are now so high that two states have lifted the ban on harvesting alligators, and between lo,ooo and 20,000 American alligator hides now enter commerce each year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The past few decades have seen several other examples of successful crocodile-rearing projects. Later chapters of this book highlight the national program in Papua New Guinea. In addition, three successful government-operated farms exist in India (where all the progeny is returned to the wild because current Indian law prohibits commercial crocodile farms). A remarkable farm with more than 3,000 breeding animals operates on the outskirts of Bangkok, Thailand. Australia has four crocodile farms, and a few African countries now have crocodile farms that are already beginning to supply hides internationally. For example, in 1982 Zambia had two such farms, Zimbabwe, five, South Africa, four (with five more planned or under construction), and Kenya, one. Appendix A lists these and other countries that are initiating farms for various crocodilian species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The early technical success of these projects offers the expectation that with an appropriate framework of safeguards and research, crocodiles might become a thriving resource for tropical nations. If such experiences can be replicated, crocodilians and their habitats may come to be considered as resources to be managed and treasured. This will require considerable investment, strict legislation and law enforcement, and international cooperation and research, as well as careful monitoring of the traffic in farmed hides. But national crocodile industries are a possibility, and they could result in thriving natural populations that are free from the danger of extinction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Such prospects may also provide economic incentives for preserving the often-fragile ecosystem in which wild crocodilians live. Crocodile farming could play a part by slowing the uncontrolled draining of swamps and other wetlands that cover large areas of the lowland humid tropics of Asia, Africa, and Latin America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles as a managed resource could economically benefit remote areas of the lowland tropics. Villagers there often have few alternative sources of income and possibilities for economic development are limited. Because the human population is relatively sparse, few opportunities exist for local trading; even where fish are abundant the problems of marketing are formidable. Indeed, in some areas crocodiles may constitute the only readily salvable resource.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles as Farm Animals</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Well-fed crocodiles grow quickly. Under ideal conditions they may reach lengths of 1 m or more in a year and 1.5 m in 2 years. They are normally harvested in the third year when they reach about 2 m in length. In this time their value may have risen from about $5 to as much as $200.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles have acquired a reputation as voracious feeders; investigations reveal this to be false. The animals actually have modest food requirements. Many hatchling animals have a food conversion rate of about 50 percent; that is, the crocodile adds 1 kg of weight for every 2 kg of food it consumes. Cattle, sheep, and pigs would have to eat 3-5 times as much food to achieve the same weight increase. After 2 years the crocodile's growth rate begins to slow down. During the third year the conversion falls to about 25 or 30 percent, which is still a high figure, and makes crocodiles probably the most nutritionally efficient land animal for commercial husbandry. Only the growth of some fish is comparable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The high food conversion efficiency is due to the fact that crocodiles have low metabolic rates and are normally extremely lethargic. They are active only in short bursts, spend hours immobile, and move only about one-third as much as mammals. Moreover, being reptiles, they spend almost no food energy maintaining body temperature. They bask in the sun to keep warm and seek shade or water to cool off. For these reasons crocodilians can thrive in marginal habitats unsuitable for mammals or birds (Investigations on the Nile crocodile showed that a pelican takes 3 days to consume food equal to its own weight, whereas a crocodile takes 125-160 days - Cott, 1961.) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile farming is also space efficient. As long as they are sorted by size, hundreds of juveniles or dozens of larger animals can be penned together in a small area. Indeed crocodiles often choose to pile up on top of one another in stacks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known about disease in reptiles. However, as farm animals, crocodiles have a major advantage: they produce antibodies readily and have few problems with external infections. In the wild it is common to find crocodiles missing limbs or tips of tails, with eyes gouged out, or enormous scars on the body. But the wounds heal readily, with little sign of infection (The American alligator is being used at the University of Florida College of Veterinary Medicine as a model for studies on antibody formation.). This minimizes the need for veterinary services, a distinct benefit in remote village farms. Nevertheless, internal bacterial diseases, such as salmonella, can get out of hand and destroy a program by reducing growth rates, lowering hide quality, or killing the animals outright.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile Hides</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is the belly skin that is the valuable part of a crocodile, and the worth of a hide is determined by the size of the belly skin, the smallness of its scales, and the hide's general condition. (Holes, cuts, scars, and rot drastically reduce its value.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although international markets utilize any crocodile skin from 0.3 m to 6 m long, the most sought-after hides are not the biggest but the moderate-sized ones from animals about 1.5-2 m long. These hides are approximately 25-50 cm in belly width.( A crocodile's total length is approximately 4-4.5 times the width of its belly). Large hides, for example those more than 3 or 4 m in length, are suitable only for luggage and briefcases because their scales are large. Smaller hides, on the other hand, are suitable both for items such as shoes, handbags, and wallets and for larger items.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Internationally, the most desirable hides come from the saltwater crocodile (Crocodylus porosus). It has proportionally the smallest belly scales of any crocodile, it lacks osteoderms,(Osteoderms are deposits of calcium carbonate under the skin. They are undesirable because they dissolve away during the tanning process, leaving a pitted surface),and on the side of its body the scales are uniformly small. The next most valuable hides probably come from Morelet's crocodile (Crocodylus moreletii), the American alligator, the Siamese crocodile (Crocodylus siamensis), and the Nile crocodile (Crocodylus niloticus). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The rest of this report highlights the program in Papua New Guinea, where during the last 10 years the government has made crocodile rearing an organized industry, much as poultry farming is elsewhere. This program, which is beginning to establish crocodiles as a significant natural asset, is designed both to protect the wild populations and to integrate traditional uses of these reptiles into a scientifically managed hide industry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Papua New Guinea crocodile farming (In the official terminology of the Convention on International Trade in Endangered Species of Wild Fauna and Flora (CITES), the Papua New Guinea program is "ranching" rather than "farming" because the young livestock are mostly culled from wild populations and are not bred on the farm) has become the cornerstone for the economic improvement of some of the world's poorest people. It offers a means for bringing the rural poor into the process of economic development, and it can be blended into a traditional village structure where land and resources may be communally owned.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The projects are small and many have had operational difficulties, but they suggest that conservation and economic development can be not only compatible, but also mutually reinforcing. The innovative idea is not that crocodiles can bring in money, but that sound conservation can be blended with marketing crocodile skins, meat, and by-products.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An important aspect of this approach to crocodile conservation is that it is based on protecting the existing landscape and resources. It provides a tool for conserving the species in their own wild habitats so that survival will not depend on a few captive specimens living under artificial conditions. It requires none of the bush clearing, fencing, forage planting or pesticide spraying that domestic animals often demand ,important advantages in an economic development project in a fragile tropical swamp or rain forest ecosystem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Papua New Guinea approach, then, provides an economic incentive for wildlife protection. Everyone ,from the villager to the minister of trade ,has a stake in keeping the wild populations healthy. Out of self-interest, in addition to natural respect, large numbers of people become the guardians of the resource and the habitat needed to keep it surviving and productive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The world's major conservation organizations have given Papua New Guinea's crocodile program their stamp of approval. In 1976 a team of scientists representing the International Union for the Conservation of Nature and Natural Resources, one of the most prestigious conservation organizations in the world, inspected the program. As a result, Papua New Guinea was given special dispensation, and its crocodile skins can be legally traded internationally. For example, because of its endangered status the saltwater crocodile is banned from trade by the Convention on international Trade in Endangered Species of Wild Fauna and Flora (CITES). An exemption, however, is granted to Papua New Guinea in recognition of the fact that its crocodiles now are sufficiently well managed to sustain a skin industry without seriously damaging the wild stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This program serves as a model for nations of the Americas, Asia, and Africa where crocodilian resources are still unmanaged or managed poorly. Crocodiles are being destroyed so fast that within about five years Papua New Guinea and other countries that have organized crocodile farming operations may be the only ones supplying significant numbers of skins to the international market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the principles developed in Papua New Guinea deserve international attention, the recipe will not be a cure-all for problems of rural development or crocodile conservation. Instead, the Papua New Guinea experience suggests that local social, political, economic, and conservation goals can become the impetus for a successful blend of village improvement and wildlife protection.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">2 Crocodile Farming in Papua New Guinea</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As recently as the l950s, crocodiles were abundant in Papua New Guinea. Hunting was a major occupation and was unrestricted. Some Australians and Europeans made fortunes by shooting thousands of crocodiles a year to make shoes and handbags in Europe and North America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it was obvious that wild populations could not sustain such wholesale slaughter, the destruction continued. By 1967 both the saltwater crocodile (Crocodylus porosus) and the freshwater crocodile (Crocodylus novaeguineae) were threatened with extinction. By 1968, despite increased hunting, the yield of skins had dropped in half; along the easily accessible river systems, crocodile populations had been wiped out. By 1969 the saltwater crocodile had disappeared from much of its range throughout the country, and wildlife officers estimated that without protection most specimens of breeding size would be eliminated within five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But how could crocodiles be protected? Papua New Guinea is divided by mountain ranges, ravines, torrential rivers, forests, seas, malarial swamps, and more than 700 languages. It would take hundreds of trained wildlife officers to enforce a ban on crocodile hunting, particularly in the face of opposition from tribesmen who have traditionally harvested crocodiles for food, decorative items, and implements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The challenge was given to the officers of the Wildlife Division. Under the leadership of Max C. Downes, these officials concluded that the best way to protect crocodile populations was to halt the slaughter of the large breeding adults and build up a new hide industry based on the increased numbers of young that would result.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Few young crocodiles ever reach breeding age in the wild. The tiny, virtually defenseless hatchlings are easy prey for large fish, birds, or other crocodiles. Almost all of them are killed by predators or by other natural causes, such as floods..</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Main areas of crocodile distribution in Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What was needed, the wildlife officers concluded, were incentives to make these smaller animals economically attractive, incentives to encourage local people to raise small crocodiles to commercial size. If that could be accomplished, hundreds of hatchlings that would normally perish could be utilized without endangering the wild populations' future. Villagers could benefit by selling skins while the vital breeding-sized animals were being left alone to provide more hatchlings. The system could benefit both the villagers and the vulnerable crocodile populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="b20a.png"></center><br>
+ Main areas of crocodile distribution in Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The idea was viable partly because many Papua New Guineans - particularly those of the Sepik and Fly Rivers - have ancient spiritual and cultural attachments to crocodiles. To them, the idea of handling and managing the animals is not unusual. Crocodile motifs are common in their art and they live in harmony with the big beasts and do not consider them dangerous pests to be eliminated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Legislation passed by the Papua New Guinea government in 1969 capitalized on this tradition by making the villagers themselves the real force in crocodile protection. The law did not ban crocodile hunting, but instead banned the possession, sale, and export of skins larger than 20 inches (51 cm) wide. In this way, it protected breeding-sized animals while allowing for the harvest of juveniles. It also allowed a person to kill a crocodile if attacked (but barred the selling of the skin, if it were oversized).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1980, the legislation was supplemented by a law banning the export of small skins. Together, the bans on possessing large skins and exporting small skins have created a stimulus for gathering small crocodiles from the wild and rearing them to moderate size on farms. The legislation has been the impetus for crocodile farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile farming officially started in Papua New Guinea in 1972. In the late 1970s, it was extensively supported by a UNDP/FAO assistance program that provided personnel and funds for technical support and program management. Today there are about 300 small village farms (The numbers vary, since some villagers go in and out of production depending on their need for income, seasonal variation in river levels, the cost of fuel, and the availability of government extension agents) supplying a number of larger business groups that rear crocodiles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wildlife officers now teach crocodile farming, not crocodile conservation per se. They have introduced crocodile-rearing techniques to villagers all over Papua New Guinea. They help build pens and teach tribesmen how to care for the young reptiles, which are so vulnerable and timid that they can literally die of fright.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government loans of up to US$10,000, along with matching development bank loans, are available to help a farmer enter the crocodile farming business. The funds pay for pumps for changing the water in the pens and sometimes for an outboard motor used in gathering young crocodiles. Everything else a villager needs can be obtained from the forest, including materials for pen construction; a small farm can therefore be established inexpensively.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Three Types of Farms</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government's crocodile management program recognizes three levels of operation: village farms (up to 300 crocodiles), small-business farms (up to 1,000 crocodiles), and large-business farms (more than 1,000 crocodiles).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A village crocodile farm consists of a small pen fenced with posts lashed together with vines. This stockade fence is about 1.5 m high and is sunk about 60 cm in the ground so the crocodiles cannot burrow out. Much of the enclosure is planted with grass, cassava, and banana trees to provide secluded areas where the animals, which regulate their body temperature by the warmth of the sun, can find shade. A shallow pool is excavated in the center.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These village farms are usually run by only one or two people. Many are little more than pens scattered in the remote bush for holding young crocodiles until a buyer from a larger farm comes around. Small crocodiles bring less money than medium-sized animals, but the villager avoids having to feed and care for them for a long period.(Because of operational difficulties, many village farms were abandoned in 1982. Lack of proper husbandy - despite government efforts - were the main reason for these difficulties. Most villagers now collect and hold young only until buyers from commercial farms arrive. However, they are still earning money from crocodiles, and the concept of fully functioning village farms remains valid for the future in Papua New Guinea, as well as for appropriate sites elsewhere). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The small-business farm usually consists of a group of enclosures (each about 6 m x 6 m) constructed of bush materials. It is typically located near an airstrip. It buys crocodiles from the village farmer and, in turn, supplies them to the larger farms, which sometimes dispatch aircraft to pick the animals up (Special cardboard shipping containers have been devised. They can be folded to make cylinders of various diameters to fit crocodiles of different sizes). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Large-scale crocodile farms accommodate as many as 20,000 crocodiles and require a large investment. They serve to regulate the export of skins and are the major purchasers of live crocodiles from the smaller farms. During periods of drought, flooding, or diminished food supplies, the large-scale farms also act as emergency buyers. On the outskirts of Lae on Papua New Guinea's northern coast, there is a 100-hectare farm with nearly 8,000 crocodiles. It is associated with a poultry company, and the crocodiles are raised on the offal from the slaughterhouse.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government Research and Extension</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Wildlife Division has constructed four demonstration farms across the country and one large research farm at Moitaka near Port Moresby, the capital city. After training at one of these, a tribesman can start his own farm alone or can call on the government for further assistance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moitaka is also the site of short courses in crocodile farming. Prospective farmers are brought in for several weeks' training. They learn how to build pens, to feed and care for crocodiles, to kill and skin them, and to prepare the hides for market. They also learn about the crocodile laws and the reason they were enacted. A farm at Lake Murray, in a remote and swampy area of the Western Province, serves the same purpose. It is built entirely from bush materials (see picture, pp. 6-7).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Wildlife Division provides instruction books, profusely illustrated for the illiterate. The books include vivid descriptions of all phases of farming the animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic Gains</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 10 years, crocodile rearing has expanded remarkably in Papua New Guinea. It has already become the main source of income for the people of some swamp and river areas. The Ambunti area, for example, produces coffee and rice, but crocodile skins now bring in much of the area's income. By 1981 the farms nationwide contained a total of 30,000 crocodiles, ensuring a sustained production of at least 10,000 skins a year worth approximately US$ 1-2 million on the international market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because crocodiles are a familiar resource, villagers take to the program quickly. By contrast, introducing cattle or western-style crop raising requires massive education and training, in addition to some social and environmental disruption.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On government farms in Papua New Guinea, fish-fed crocodiles have increased their belly width by 25 cm per year and are ready for slaughter in 2-3 years when the width approaches 50 cm. The selling price of the skin is then between $100 and $200, depending on species, flaws, and size.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But skins are not the only product. A crocodile with a skin big enough to market can provide 20 kg of meat. The meat is white and is low in fat. Papua New Guinea is a net importer of meat, and crocodile farming is now augmenting local supplies. The large farm at Lae already sells frozen crocodile meat (including front and hind legs, tail steaks, ribs, and chops) both locally and on foreign markets. Some orders have come in from dealers in Paris who supply expensive French restaurants.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">3 Conclusions</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Benefits of Crocodile Farming</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile farming seems to be singularly appropriate for rural, isolated, lowland communities in the tropics. The land there is often unsuitable for conventional agriculture, and the people lead a tenuous existence or drift to the cities looking for work. In such areas, there are few opportunities for people to earn cash without drastic and expensive modifications to the environment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile farming has many advantages over hunting the animal in the wild. For instance, crocodiles farms can:</P>
+<P ALIGN="JUSTIFY">· Permit government monitoring of the crocodile industry. (Hunters are more difficult to regulate since they work in remote areas, often undetected and crossing borders at will.)</P>
+<P ALIGN="JUSTIFY">· Yield a regular harvest of a specific number of animals of a selected size.</P>
+<P ALIGN="JUSTIFY">· Produce a standardized, premium product that better serves the needs of the international hide industry, making skins poached from the wild less desirable. (They may provide, for instance, a standard first grade 1-1.5 m long hide rather than hides of mixed size and quality.)</P>
+<P ALIGN="JUSTIFY">· Reduce the wasteful losses of hides from improper handling, the fate of a high proportion of skins now brought in from the wild.(*In remote areas, salt may become scarce late in the season as it is used for hides. This often results in insufficient salt being used when the supply runs out and hides subsequently rot or "slip". In some isolated areas, as much as 25 percent of the hides are lost or downgraded because of improper curing for lack of salt. However, skins produced on farms, especially near urban areas or large villages, are usually properly salted; if salt becomes scarce, killing of the animals can be delayed) </P>
+<P ALIGN="JUSTIFY">· Educate the public about crocodile ecology and the animal's importance to the habitat and the local economy.</P>
+<P ALIGN="JUSTIFY">· Provide sites for scientific studies on crocodilians. Studies conducted on alligators at the Rockefeller Refuge in Louisiana, USA, for example, have provided reproductive, nutritional, and growth data directed specifically towards developing efficient farming techniques.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For some farms the earnings from hides, meat, and by-products may be supplemented by tourism (through gate admissions and the sale of curios), as well as by selling eggs and young to other farms for breeding stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A long-term program of wise utilization of crocodiles can benefit governments by providing revenue from hides, curios, craftwork, and manufactured articles, as well as from export duties. Furthermore, in their natural state in parks and preserves, crocodiles are an important tourist attraction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In an effort to preserve crocodile habitats, the Papua New Guinea program has encouraged the collection of eggs or young from the wild and has discouraged the breeding of crocodiles in captivity. This is because a reliance on the wild creates economic incentives to conserve crocodile habitats; if the habitats are drained for human settlement or conventional agriculture the farmers lose the source of their stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contrary to popular impression, preliminary observations indicate that crocodiles benefit commercial fisheries. The animals are important links in the ecosystems of rivers and lakes and are often the largest inhabitants of the freshwater wetlands. Their movements inhibit the growth of aquatic plants in the waterways, and, in areas with prolonged dry seasons, some species maintain residual waterholes that benefit small aquatic organisms that would otherwise perish. In estuaries and lakes, crocodiles enrich the nutrient content of the water by converting terrestrial prey into feces that in turn feed invertebrates and fish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where crocodiles have been eliminated, reductions in the tonnage of fish caught for human consumption can usually be demonstrated. For example, in Brazil, Kenya, and India, a decline in the fishermen's catch has paralleled the decline in crocodiles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Limitations of Crocodile Farming</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments and individuals seeking rapid returns on investments should realize that a crocodile farming industry is not a get-rich-quick scheme. To build a stable national industry may require 10 years and an investment of at least $500,000 before it is biologically and economically successful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, an organized industry is vital. A village crocodile-rearing pond is only profitable if there is someone to buy, grade, package, and ship the product with all its documentation. Services will be needed at all levels to advise on disease control, nutrition, skinning, and preserving the hides. In many parts of the world crocodile farms have been financial and conservation failures not just because of poor husbandry management, but also because of fiscal shortsightedness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Selection of a suitable farm site is basic to the economics of the entire operation. Farms demand a steady supply of meat or fish to feed the crocodiles, and are most successful when located near a reliable source of inexpensive food. Some farms take advantage of offal from nearby chicken or cattle abattoirs; others use the fish by-catch from shrimping operations. In the absence of an inexpensive animal protein feed, the farm will have to raise its own food (tilapia is frequently used) or harvest it from the wild, both of which can be expensive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodile farms also require a steady year-round supply of clean water for the holding ponds and tanks. If this cannot be supplied by gravity flow from nearby sources, it must be pumped from wells or from nearby lakes or ponds. This, too, is likely to be expensive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the general hardiness of crocodiles, the farms must have access to veterinary care. Most disease problems stem from poor sanitation, low water temperatures, and poor diet, all of which can be easily corrected. But with large numbers of animals crowded together, disease problems, if not quickly diagnosed and treated, can wipe out the young captive animals in epidemic proportions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capturing and transporting large crocodilians is dangerous and difficult. Dealing with a large captive population of crocodiles of different age groups and sizes requires a great deal of experience.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although crocodilians are common in zoos, successful breeding of these reptiles in captivity is so far a rare and remarkable event. However, researchers are now coming to understand the behavioral requirements for success. For instance, gravid females must have access to appropriate nesting sites, males must have ample space when they are penned in with other males, and juveniles and hatchlings must be separated from their parents and housed by size and feeding preferences. That prolific breeding can be achieved, however, is illustrated by the Samutprakan crocodile farm near Bangkok, Thailand, which reportedly has reared tens of thousands of its own animals and now aims for a population of 100,000 crocodiles by 1987.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The worldwide shortage of crocodile leather is becoming more acute each year, and it will be many years before any output from farms can significantly reduce pressure on wild populations. Thus, farming should be only one aspect of an overall conservation program that includes total protection of some populations in national parks and sanctuaries. In addition, the conservation of natural wetlands is an important part of overall economic planning. If wetlands are lost, many wild species in addition to crocodiles will be affected.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Australia, Asia, Africa, and the Americas, many crocodilian populations are poorly protected because governments lack the manpower or the will to enforce conservation laws rigorously, especially in the remote areas where the last remaining crocodiles reside. Because most wildlife departments in the tropics are short staffed and have vast areas to police, their efforts at wildlife protection are frequently ineffective. Moreover, some countries have been slow to introduce protective legislation for an animal that does not engender public sympathy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua New Guinea's program offers one of the best hopes for saving all endangered crocodiles, alligators, caimans, and gavials. The methods developed there serve as a model for other nations. By providing an alternative, Papua New Guinea gives villagers the incentive to protect wild crocodiles that are breeding nearby so as to assure themselves of future supplies. The people themselves become the conservators of the local animals and habitats. In turn, watersheds, soils, and conventional agricultural development (including natural and forest products) can all benefit. The habitat is also preserved for many other wildlife species that share it, and genetic diversity can be maintained. Conversely, without a special incentive to conserve them, all these resources are normally degraded as a region develops.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">4 Regulations, Safeguards, and Research Needs</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Papua New Guinea experience provides a model for other nations, but to implement such a program requires a foundation of legislation, government support, and legal safeguards. Prerequisites of any crocodile farming program are an overhaul of legislation, strict law enforcement, and reciprocal laws with neighboring countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The enforcement of wildlife regulations is so inadequate in most countries that crocodile farming is open to abuse. Farms can front for illegal poaching operations, and hides taken from the wild can be intermingled with hides produced on the ranch or farm unless government enforcement is stringent and inspection frequent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, the stimulation of world trade in crocodile hides through the sale of farmed hides might lead to increased poaching of wild crocodiles or eggs. Poachers have fewer operating expenses than farmers, and unscrupulous hunters and dealers can harvest hides, steal crocodile eggs or young, and subsequently sell them through countries that lack enforcement capabilities. This practice could be disastrous for countries where crocodile populations have almost disappeared.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government Regulations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before any farming scheme is attempted, protective legislation should be in operation throughout the country. This should make it unlawful to kill, capture by any means whatsoever, disturb willfully, or pursue any crocodiles, or to collect or gather any crocodile eggs without a permit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No crocodile eggs should be allowed to be imported or exported with out a permit. No persons should possess, sell, buy, donate, receive consequent upon a donation, convey, keep in captivity, or display any live crocodiles without being the holder of a permit. And no person should be allowed to import or export any crocodile, dead or alive, or any portion of a crocodile, processed or not, from any country without a permit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before granting a license for a commercial farm, the government should investigate the applicant's land tenure and financial resources, particularly since the farm will have to operate for three to four years before producing crocodiles suitable for culling. The applicant's ability and experience in rearing crocodiles should be determined. A plan of the proposed farm, including details of water and food supply and the proposed methods of harvesting food, should be examined.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is suggested that:</P>
+<P ALIGN="JUSTIFY">· No permit for egg harvesting should be issued until adequate rearing facilities have been prepared. The permit should state the name of the holder or his authorized representative, the annual total number of eggs allocated for harvesting, and the area where collection is permitted.(In some cases it is also important to specify a harvest time. Often it is best to take eggs laid early in the season because the female will then lay another clutch.) </P>
+<P ALIGN="JUSTIFY">· Permits should be issued on a year-by-year basis. The applicant should understand that the department may refuse to renew or issue further permits if the farm is not managed satisfactorily or if permit conditions have not been observed.</P>
+<P ALIGN="JUSTIFY">· The applicant should understand that the farm and all production records should be available for inspection by an official of the conservation department.</P>
+<P ALIGN="JUSTIFY">· The farmer should be required to submit periodic reports detailing the total number of nests raided and eggs harvested, the egg mortality, and the number of eggs hatched. Thereafter, the number of animals held in captivity, the rate of mortality and its causes, if known, and the number of animals sold or culled should be included in each report.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Furthermore, it is recommended that the permit holder release 5 percent of his annual crop of hatchlings in order to restock the natural habitat. In addition, a further 5 percent of the hatchling crop should be reared to a length of 1 m before being released, bringing the total release of young crocodilians to 10 percent of the annual crop of hatchlings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The distribution of hatchlings and young reared animals should be supervised by the conservation department.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unless government agencies monitor the wild populations of crocodilians being harvested for hides, eggs, or young, the farms themselves could become a major drain on those populations, leading to their extinction. Therefore, before any farming program is started, a survey of the breeding grounds should be undertaken to determine the number of nests available and those from which eggs can be taken with least danger to the wild population (for example, from nests on grounds likely to be flooded).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These breeding grounds should be fully protected; tourists on foot, in vehicles, or in launches should not be allowed to visit or disturb crocodiles during the breeding season.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International Safeguards and Cooperation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The international traffic in millions of unmarked crocodilian hides and products poses one of the greatest obstacles to enforcement of national and international endangered species regulations. Hides and skins frequently cannot be traced to their source or country of origin. Legally harvested or farmed animals cannot readily be distinguished from those exported in secret from illegal sources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The need for internationally acceptable methods of marking individual hides and products is critical. Traffic in illegal crocodilian hides and products will continue as long as law enforcement agencies lack the means to detect them easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the United States a system has been developed in some states that enables conservation, police, and customs officials to monitor traffic in alligator hides. A conservation authority issues an official tag for each animal allowed by the license. All hides exported are tagged with a serially numbered plastic tag that cannot be removed without breaking it. The serial number is recorded on the export permit and with details of the buyer's and seller's name and address. This tag remains on the hide, right through the tanning process, until the hide reaches the manufacturer. Each tannery maintains a register of purchases that is available for inspection. This system also is being implemented in Zimbabwe and is worthy of trial in other countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tagging of all hides and products for individual identification is an important safeguard. Other safeguards include:</P>
+<P ALIGN="JUSTIFY">· The use of engraved stamps or seals to authenticate legal licenses and export permits and make it more difficult for documents to be forged.</P>
+<P ALIGN="JUSTIFY">· Internationally accessible data and a retrieval system that allows law enforcement personnel to corroborate the authenticity of documentation and the origin of hides and products;</P>
+<P ALIGN="JUSTIFY">· Monitoring agencies to record and publish market statistics, traffic, and trends;</P>
+<P ALIGN="JUSTIFY">· Laws limiting the sale of hides only to nations that cooperate in an internationally sanctioned program of safeguards; and</P>
+<P ALIGN="JUSTIFY">· Research funding to monitor populations and develop new marking and identification techniques. (For instance, the use of dyes, roll marking, and infusion of detectable chemical tracers has yet to be fully explored.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research Needs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is urgent need for tannery owners, manufacturers, and conservation authorities to jointly work out the rational exploitation of crocodile populations. Commercial interests have reaped a rich reward over many years, and if the crocodile industry is to continue, its entrepreneurs must invest in management and conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Clearly, research to improve farming techniques will be a wise investment for both commercial operators and the countries concerned. Surveys to determine population numbers and size as well as the structure of breeding stocks and recruitment rates are essential. Such surveys may indicate the need to establish sanctuaries to protect breeding stock and nesting grounds, or perhaps to ban hunting to allow populations to recover. A rearing program and restocking of suitable habitats might be necessary.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendixes</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Appendix A: Crocodile Farming Around the World</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experiences with crocodile farming in Papua New Guinea, the main subject of this report, are described in chapter 2. Here we summarize the status of similar efforts in other countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Four crocodile farms have been established in Australia, one in the Northern Territory and three in Queensland. To date, only the Edward River farm, operated by the government as an aboriginal development project, has developed a successful breeding program. There, seven-yearold saltwater crocodiles (Crocodylus porosus) hatched on the farm from wild eggs are now breeding and laying fertile eggs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People's Republic of China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A farm for Chinese alligators (Alligator sinensis) has been established at Xuancheng, Anhui Province. Its purpose is to breed alligators for conservation, although the hide of this species is not in great demand because it has many osteoderms in the belly scales. Recently the government has expressed interest in establishing a farm for saltwater crocodiles in southern China. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taiwan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taiwan has one crocodile farm or rearing station, but it is too far north to breed its own stock, except in heated indoor enclosures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are several buyers in the Philippines who maintain pens of crocodiles for short periods. None of these is a farm. A new experimental farm for the Philippine freshwater crocodile (Crocodylus novaeguineae mindorensis) was established by Silliman University in an attempt to preserve that endangered species and to promote an economic interest in crocodile conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Micronesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A farm for saltwater crocodiles has been established on Palau, where a small population of these crocodiles occurs in a brackish interior swamp. In the past, the government hired a hunter to reduce the population whenever the local people felt it had become sufficiently large to present a danger, about once a decade. Presumably the nuisance crocodiles will now end up in the farm. The farm, which has been in existence only for a year or two, earns money from tourist admissions as well as hide production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A few crocodile-rearing stations have operated for several decades in Java, Sumatra, and Kalimantan. These have been stocked with eggs and young animals collected from the wild in Sumatra and Kalimantan. In the early 1970s, three such operations in Samarinda, East Kalimantan, closed down for lack of wild stock. At least one operation in Jakarta, Java, continues to survive, but with virtually no output of stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A survey of Irian Jaya (Indonesian New Guinea) in 1980 indicated a number of ranches in that region as well, but revealed that some were having difficulty obtaining stock because of overharvest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singapore</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singapore has a famous crocodile farm that figures prominently in tourism. It breeds some of its stock, but also obtains wild stock from all over Southeast Asia. Singapore has a thriving crocodile hide trade. Many buyers and several tanneries are located there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singapore is not a member of CITES and openly trades in any and all species of crocodilians.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are several crocodile farms in West Malaysia (at Penang, for example) and at least one in East Malaysia (near Sandakan, Sabah). These started out as rearing stations relying on wild young, but have moved slowly toward breeding their own stock. The Penang farm depends on tourism to pay many of its expenses. The Sandakan farm is operated in conjunction with a duck and pig farm that supplies it with offal. Its stock consists of saltwater crocodiles. Until at least 1980, it had very little production from captive animals, but the owner is hoping to broaden his stock from them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sarawak (East Malaysia) also used to have several rearing farms. The present status of these operations is unknown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Samutprakan Crocodile Farm was started in 1950 with 20 wild crocodiles and an investment of US$500. Today it is reported to be the world's largest crocodile farm, with about 30,000 individuals. About 3,700 of these animals, placed in eight separate breeding ponds, are used for breeding stock, and there are plans for a population of 100,000 by 1987. The Samutprakan farm opened to the public 12 years ago and now receives about one million visitors annually.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most of the farm's crocodiles are from the two species native to Thailand, the saltwater crocodile and the Siamese freshwater crocodile (Crocodylus siamensis). It also has hybrids of the two, as well as the indigenous false gavial (Tomistoma schlegelii) and five exotic species: South American caiman (Caiman crocodilus), New Guinea freshwater crocodile (Crocodylus novaeguineae), Chinese alligator (Alligator sinensis), broad-spouted caiman (Caiman latirostris), and dwarf caiman (Paleosuchus palpebrosus). The farm has succeeded in breeding South American caiman (Caiman crocodilus); the other species are approaching maturity and it is hoped they will breed in the near future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The farm sells crocodile meat locally, mostly to restaurants as a delicacy (for US$5 per kg).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The commercial and biological success of the farm is largely due to favorable conditions at Samutprakan. The temperature and humidity are high year-round, and low costs of labor and building materials permit the physical plant to be profitably established and maintained. The main cost is for food; approximately 4,000-5,000 kg of by-catch fish are needed daily at a cost of US 20 cents per kg. If the supply of fish is inadequate, the diet is supplemented with chicken wings, legs, and necks from a slaughterhouse.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burma</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Rangoon there are some crocodile-holding pens operated by hide buyers. It is not clear whether breeding or farming of crocodiles occurs in them or whether the operation simply acts as a clearing center for wild hides. The government has expressed interest in establishing farms in the mangrove areas near the mouth of the Irrawaddy River. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1974 an FAO report on India's crocodiles noted that the Indian gavial (Gavialis gangeticus) was on the verge of extinction, the saltwater crocodile was extremely rare, and the Indian mugger (Crocodylus palustris was a depleted, although not threatened, species).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government, with United Nations assistance, then initiated a project for the conservation and management of all three species. This program aimed to protect and restock habitats. Animals for restocking were obtained by collecting eggs laid in the wild, incubating them under controlled conditions, raising the resulting hatchlings, and returning juveniles to specially selected sanctuaries when they reached about 1.2 m in length,at which time they are free from predation other than by man.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project has resulted in the comeback of the gavial. By March 1979, 200 gavials had been restored to the wild. The wild population now exceeds 1,000 animals of more than 2 m length, and the number is expected to increase rapidly through natural reproduction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project has also carried out extensive research on crocodiles, and since its founding in 1978 the Central Crocodile Breeding and Management Training Institute, located in Hyderabad, has trained many wildlife officers in crocodile protection. Crocodile-rearing facilities are also located near Madras, Lucknow, and Cuttack. All have had success in raising the animals and restocking their habitats.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Indian crocodile project has been a notable success and it coincided with (and perhaps helped create) a wave of local interest in India's wildlife and its conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Israel</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A farm stocked with American alligators (Alligator mississippiensis) was established at a popular hotwater spring resort area, using animals supplied by a Florida farm. The Israeli program will earn money from tourist admissions and from future production of hides. The first successful hatching of captive-bred alligators was reported in 1982.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Near Mombasa a farm for the Nile crocodile (Crocodylus niloticus) has been set up to produce hides from captive-bred stock. The farm is a demonstration project of a large cement factory that is attempting to return its limestone-mined areas to productive agriculture. Some sophisticated experiments are under way on crocodile nutrition, with food for the animals produced in an intensive aquaculture project using tilapia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia is planning a series of farms patterned after those in Zimbabwe (described below).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe has made great strides in captive breeding. In 1979, 87 captive females at two farms produced 1,906 eggs, and a third farm has set aside 30 captive females for breeding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Four of the country's five crocodile farms are on the shores of Lake Kariba and the other is at Victoria Falls. The government allows each farm an annual allotment of wild eggs (averaging 2,000 to 2,500 eggs) for stocking its rearing programs. Each farm is also striving to become self sufficient in egg production by developing successful breeding programs. The government is considering reducing each farm's allotment by the number of eggs produced annually in the farm so that each will eventually become independent of the wild populations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe farmers operate on a system that obliges them to return a small percentage of live animals to the wild if the government requires it. At present, this requirement is being waived because the wild population is increasing on its own.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe has built its crocodile conservation program on a broad base. Crocodiles are protected throughout the country, as game animals in the country at large and as totally protected species in parks and sanctuaries. Populations have increased dramatically, from endangered status in the l950s to over 50,000 individuals today. In the 1950s a survey of the Zambesi River and Lake Kariba revealed no crocodiles; today thousands are seen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe's Department of National Parks and Wildlife is striving to ensure that its legitimate international trade in farm-raised hides does not provide illegal operators in other countries with the opportunity to sell poached hides (for example, forging papers that claim their hides originated on legitimate Zimbabwe farms). To make poaching difficult, Zimbabwe, taking a clue from the state of Louisiana, plans to use serially numbered nonremovable plastic tags to mark legitimate hides. Numbers of the tags will be noted on export permits. In addition, every export permit will be validated by the government with an engraved security stamp that is difficult to forge and that shows ink damage if any erasures or modifications are attempted. The use of such stamps is recommended by CITES, and Zimbabwe is the first nation to put them into use.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Africa has four crocodile farms, and another five are planned or under construction. Apart from the Natal Parks Board Crocodile Research Station at St. Lucia Estuary, which breeds Nile crocodiles for restocking and conservation purposes, all farms are for tourism and hide production. So far only one farm, outside Pretoria, is reported to produce many offspring. Only the provinces of Transvaal and Natal have wild crocodiles, and neither allows eggs, young, or adults to be collected for stocking farms. Both provinces, however, permit the killing of nuisance crocodiles on private land. Transvaal will allow one or two nuisance crocodiles to be taken captive by farmers, but it refuses permission for removing larger numbers of nuisance animals,presumably for fear that this would generate a flood of spurious nuisance complaints. Natal will not permit the removal of any wild crocodiles to farms, nor will it supply offspring from the St. Lucia station to farmers. This makes the Pretoria farm the only source of crocodiles in South Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following the example of Zimbabwe, the South African farmers (present and potential) formed a crocodile farming association in 1982.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Botswana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several farms patterned after those in Zimbabwe are planned for the Okavango area. Petitions for approval are currently before the Botswana government.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the late 1960s French businessmen established a farm for Nile crocodiles near Lake Chad. It collapsed after only a few years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ivory Coast</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government of Ivory Coast has obtained assistance from Zimbabwe to establish a conservation program for its three native crocodiles: the Nile crocodile, African slender-spouted crocodile (Crocodylus cataphractus), and Congo dwarf crocodile (Osteolaemus tetraspis). Recommendations were made for conserving the wild populations as well as for establishing farms. Field studies are under way.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Europe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A commercial farm for the South American caiman (Caiman crocodilus) was established in southern Italy in the late 1970s. Stock was obtained from Colombia. The animals, numbering in the thousands, arrived in Rome in winter and were transported south to the farm in an open truck. Most died from cold. Later shipments fared no better, and the few animals that survived died from poor husbandry. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Americas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United States</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are between 15 and 20 successful alligator farms in the United States. Most are located in Florida and Louisiana, and there is at least one in California. All earn a portion of their money from tourist admissions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cuba</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the 1960s the Cuban government established at least two farms for crocodiles. One is located in the Zapata Peninsula National Park; the other is near Cienfuegos. The purpose of these farms is to breed crocodiles whose wetland habitat has been converted to sugar cane fields. Eventually, the farms will also produce a cash crop of hides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, what started out as an admirable effort created several conservation problems because the farm managers did not realize there were two crocodiles in Cuba ,the American crocodile (Crocodylus acutus) in brackish waters, and the Cuban crocodile (Crocodylus rhombifer) in freshwater areas. The two were mixed in the farms and hybridization resulted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mexico</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Mexican government has established several farms for Morelet's crocodile (Crocodylus moreletii) in Chiapas and Veracruz. The purpose is to breed the species in captivity to relieve hunting pressure on the wild population and prevent its extinction. Original funding was provided by the World Wildlife Fund. At least one of these farms still exists. Breeding has been achieved, but there have been problems of survival in hatchlings. The cause of the deaths has not been discovered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years several businessmen in Mexico have expressed interest in starting one or more crocodile farms, but none has yet materialized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">El Salvador</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the late 1960s, the Louisiana Game and Fisheries Commission supplied specimens of the American alligator to a cattle rancher in El Salvador for the purpose of establishing an experimental farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Louisiana was interested in studying growth rates of American alligators in a tropical nation where the animals did not have to undergo winter hibernation. The husbandry on the farm followed methods worked out in Louisiana. The animals grew fast and presumably have started breeding. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Venezuela</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A captive breeding program for the Orinoco crocodile (Crocodylus intermedius) was established in Venezuela in the late 1970s on the ranch of Tomas Blohm. The operation is not commercial; its purpose is to prevent extinction of the species. The offspring may be used for restocking wild habitats in the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under Venezuelan law there can be no commercial export of any crocodilians. In addition, the Orinoco crocodile and the various caimans are protected. However, the reptiles are everywhere killed as vermin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peru</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peru has proposed harvesting certain wild populations of caimans (Caiman crocodilus) to supply animals to a ranching operation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BraziI</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government of Brazil is interested in establishing farms for several species of caiman, including the yacare (Caiman crocodilusyacare). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Latin American Nations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the past two years, other Central and South American nations that have indicated their intention to set up farms for crocodiles or caimans are Bolivia, Colombia, Costa Rica, Ecuador, French Guiana, Guatemala, Guyana, Haiti, Honduras, Nicaragua, Panama, Paraguay, Suriname, and Uruguay. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendix B: Practical Crocodile Farming</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This appendix is adapted from a paper by A. Pooley that detailed the lessons learned from farming crocodiles to restock depleted habitats in Natal, South Africa. The information is presented here not as a blueprint for setting up a farm, but to show prospective farmers some of the points that they must first consider before attempting to rear crocodiles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Farm Location</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reliable supplies of good water and suitable food are the most important considerations for establishment of a crocodile farm; the area selected must have both. Village farms also need to be close enough to wild crocodile populations for the animals to be obtained easily. Larger farms can be located farther from the source.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For small farms, a natural supply of food should also be readily available in the wild. Areas that have a fishing industry are ideal locations. For large farms, sites near slaughterhouses or fish-processing facilities are ideal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other considerations also include the volume of water available throughout the year, the distance over which water must be piped to the ponds, and pumping costs. The quality of the water should be established, with samples tested for salinity and acidity and, where the supply comes from mineral springs, analyzed for harmful chemicals. Chlorinated water must be tested regularly to ensure that the chlorine content is not too high, and the nature of any factory effluents present should be determined. It is important to establish whether fish, frogs, crabs, mollusks, or aquatic insects survive in the water intended for use.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bacterial analysis is advisable where the water is drawn from a river that drains an area densely populated by humans and livestock. If the water is found to be contaminated, the stagnant pond rearing pen system should not be used, particularly when Salmonella spp. are present in high concentrations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A filter system has advantages if water is pumped straight from a river carrying a heavy silt load. Apart from enabling farmers to see the animals in the pools, filtered water makes the pools and pipes easier to clean. Filtration can be achieved by drawing water from a deep pit close to the river so that the water collected seeps through sand or mud.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A reservoir or a series of supply tanks is useful as an additional method of filtering water. In the event that pumping equipment fails, such a reserve supply may prove vital to the health and survival of the crocodiles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ponds should receive as much sun as possible, particularly during the winter months. A series of winter air temperature recordings would be useful in choosing the site of rearing pens, since valley temperatures are often several degrees lower than the temperatures some 50 to 100 m uphill. Preference should be given to the warmer locations, taking into account the direction of local winds and heavy rains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Soil types are the next consideration. If soils are sandy and porous, earth ponds are impractical and a concrete lining is required to retain water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Drainage of the ponds must be carefully considered. Drainage is far easier if the ponds are built on a slight rise. Water from the ponds must not be allowed to stagnate nearby; the drainage system must be efficient. It is recommended that pens be spaced at least 8 m apart and that their drainpipes lead underground at least 10 m before emptying.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pen Construction</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pens with rounded corners are the most successful. Crocodiles frequently choose to lie together in a pile. Square corners allow them to pile up against the angle, smothering those on the bottom and sometimes allowing animals to climb over the fence. With rounded corners, the pile cannot grow very high before the crocodiles slide sideways and the heap collapses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experiments in South Africa indicate that natural pools containing rooted vegetation are less prone to become sources of disease than are concrete pools. The surface of the concrete seems to become impregnated with liquid and debris from food and to become a breeding ground for bacteria. For hatchlings and very small juvenile crocodiles, concrete has an added disadvantage; its rough surface can abrade the belly skin when the animals slide in and out of the water, which can foster infection. In 5 or 10 years, even smooth concrete will erode sufficiently to become a problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Researchers elsewhere, however, report better results with concrete lined ponds, which they find easier to clean. Concrete pools are useful for summer because they can be scrubbed clean and because the volume of water used is small. Normally they need only be emptied, cleaned, and refilled every third day, and there is no wastage through seepage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pools are best built as channels. This provides more bank for basking and enables the pools to accommodate more crocodiles. Because the larger males become belligerent only when they can see each other, floating logs, patches of grass, or channel corners are visual barriers that reduce interactions. The channel system also gives more water edge, and this appears to satisfy the territorial instinct.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles are famous for basking in the sun, but they die surprisingly easily of heat prostration. At least one-third of the land area of a farm pen should be shaded with vegetation. The amount of space around each pool is calculated to allow ample basking room for each animal, and an area of shade must likewise be provided.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On land, crocodiles often seek contact with each other (thigmotaxis) and frequently lie piled on top of each other, but this should be a matter of choice rather than of overcrowding. There should be few enough animals in the enclosure to allow every crocodile to get out of the water if it chooses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ideally, only half the available number of pools should be occupied at a time, so that they can be used in rotation. In this system, the animals can be moved to fresh pools every two months (or as necessary), leaving the "used" pools to be drained and dried out to bake in the sun. After two months, the pools will then be clean and ready for use again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An important requirement is that the pools be at least 60 cm in depth; otherwise, the water becomes too hot in summer. The pool floor should be sloped towards the drain outlet to facilitate cleaning and flushing away uneaten food. Also, the outlet pipe should be 10 cm in diameter, with a stopcock outside the enclosure, so that the pool can be cleaned and emptied efficiently. It is essential to place a screen in the drainpipe to prevent small crocodiles from escaping or being sucked out of the pool during cleaning. After some time, stagnant ponds may become difficult to clean because of the heavy growth of algae on their sides. Hard-bristle scrubbing brushes are needed to dislodge this growth. Small amounts of copper sulfate in the water will help control algae if used regularly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The entire pond and surrounding apron must be smoothly plastered to facilitate cleaning. It helps to have a water source close to each pool from which a hose pipe can be led to pressure spray and clean the pool and its apron.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An important part of the design is a partly submerged, gently sloping ledge, some 45 cm in width, around the perimeter of the pool. This provides a shallow resting zone for the crocodiles and gives them easy access to the water. The crocodiles rest there when feeding, and the ledge prevents them from scraping their bellies and damaging their claws when they enter or leave the pool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For small crocodiles it is advisable to roof over the entire pen with wire netting or cries-crossed strands of wire. This protects against predators. Further, young crocodiles can climb vertical wire netting with ease and will escape unless the enclosure is either roofed or has side walls that slope inwards. A skirting board (planking, sheet iron, tin, or plastic sheeting) placed against the wire netting can also prevent this. If wire netting is used for the sides of the pens it should have mesh no larger than 1 cm so that hatchlings will not injure themselves by trying to climb through. While these pools are being cleaned, care must be exercised to prevent crocodiles from falling into the empty pool.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water can be passed continuously through the pools. The advantage of this is that during hot summer weather, when crocodiles are feeding at their maximum rate, small uneaten food particles, feces, and urine are carried away. Constant dilution of the pond's water also ensures a low bacteria level. However, the pool must be drained and scrubbed clean at least weekly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Earthen pools are easy and cheap to build and are a "natural" habitat where vegetation can be planted and small live fish introduced; insects, frogs, and other creatures attracted to the dams will be an important addition to the diet and health of the crocodiles. Earthen pools are ideal in climates where low winter temperatures are likely to cause respiratory illness in the young animals. During cold weather the crocodiles burrow into the mudbanks and survive nights of heavy frost.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of the animal's burrowing capabilities, it is important to provide a strip of land 4 m wide between the pool's edge and the boundary fence. Otherwise, crocodiles may tunnel beyond the fence line. Fences must be buried at least 1 m deep to intercept the burrows and to prevent predators from burrowing in. Burrowing, however, can be hazardous, because the burrows can collapse and suffocate the animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In areas where the soil is porous or sandy, the floor of an earth dam can be sealed with concrete or plastic irrigation sheets. A layer of earth can be used to conceal this artificial floor. The disadvantages of earth pools are that, because of seepage, they require more water than concrete ones and that they require more maintenance because they cannot be efficiently cleaned. Even if the pools are provided with constantly circulating water, they eventually become fouled, particularly during hot weather.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Removing crocodiles from an earth pond can prove difficult, since most will take refuge in their burrows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capturing Crocodiles</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles are located at night, usually from a boat, by shining a light along the edges of rivers and lagoons. Because of a reflective tapetum, the eyes of crocodiles glow reddish or orange and are visible for a hundred meters or more. If the population has not become exposed to hunting and become wary of people, the animals will not submerge when the light strikes them. Dazzled by the beam, they tolerate a stealthy approach, and small animals can simply be grabbed by hand or scooped up in a net. They can then be transported in sacks to the rearing pens. Larger animals may be noosed or baited into cylindrical screen traps at places they frequent along the water's edge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Managing a Crocodile Farm</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is a problem to sort the young crocodiles. From one clutch of eggs, some individuals will be aggressive and others may be shy or extremely timid; growth may vary from rapid to very slow, with a few individuals classed as runts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Larger animals can be so dominant that smaller individuals will not even attempt to feed. If sorting is not done, the smaller, less-aggressive individuals do not get a fair share of the food; they grow slowly and get bitten and harassed by the larger animals. At feeding time, some will flee to the opposite side of the pen and stop feeding altogether. Keeping the young animals sorted into classes of the same size avoids many of these problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nutrition and Feeding</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the crocodilian's reputation as a man-eater, small wild crocodiles live mainly on invertebrates and larger ones live mainly on fish. Papua New Guinea's farmers feed a varied diet of locally caught fish, crab, shrimp, frogs, snails, grasshoppers, beetles, and slaughterhouse waste. Whole animals minced up should be used, if necessary, because crocodiles require a diet of bone, intestine, scales, and other tissues to provide calcium and minerals. Bones in chopped fish must be minced thoroughly for hatchlings or very young crocodiles, or they should be fed very small fish supplemented by tadpoles or insects. One village in Papua New Guinea has shown remarkable success in rearing hatchlings on a diet of chopped fish and live freshwater shrimp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fish is an excellent food for the bulk feeding of a large captive population. Whole fish chopped into pieces, including the livers and hearts, forms a balanced diet that may be supplemented by meat, if available, to make up bulk. Small whole fish are particularly suitable; the crocodiles derive calcium from the bones and scales, plus roughage to facilitate digestion, while the flesh, liver, and heart are rich in nutrients and protein The main difficulty usually lies in harvesting enough fish to meet the crocodiles' demands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any method of supplementing the diet with live creatures is recommended. For instance, a light can be left burning in each pen about 15 cm above the water for attracting insects. Various types of insect traps may also be used.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles also can be fed on a variety of wastes such as offal or noncommercial fish. Ideally, a large-scale farm should be located near a poultry slaughterhouse. (Cattle offal is also satisfactory, but it is not nutritionally adequate as a sole ration for crocodiles.) Even crocodile offal itself can be fed back to crocodiles. However, the use of offal will necessitate dietary supplements to assure sufficient phosphorus and calcium. These minerals are generally provided by feeding bones to the crocodiles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crocodiles usually consume their food in the water, but they can also be fed on land. They will eat daily, but are able to remain active for weeks without food. If they are fed in the water of a farm pen, the water will become polluted unless there is considerable flow to carry away the debris. In extreme cases, the pools become septic. To ensure the health of the growing animals, constantly flowing water is far superior to standing water. (The Samutprakan Crocodile Farm in Thailand feeds some of its animals in water, but the small feeding pools are separate from the large regular breeding pools and at a lower level to prevent their overflowing into the breeding pools.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important to feed pieces of food small enough to be swallowed without difficulty. Large fish should be cut into elongated rather than square pieces, since the bones can cause damage during swallowing. Similarly, whole live fish should not be so large that the dorsal fin may cause damage to the reptile's throat and gullet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important to know the amount of food that each group of animals will consume at each meal. By feeding at the same time each day, it is easy to calculate how much is required. Moreover, the crocodiles become accustomed to a routine and the food is consumed while it is still fresh. In the hot summer months the animals will devour a full meal every 24 hours, but the feeding rate slackens with the onset of colder weather. It is then wise to start reducing frequency and quantities until food is required only every second or third day, depending on the climate. Generally, young crocodiles will refuse food when the air or water temperature falls below 60°F (15.6°C). Even in midsummer sudden cold spells may occur; at such times, it is usually futile to feed the animals or try to coax them to eat until the weather warms up again. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During hot weather conditions it is preferable to feed late in the afternoon or evenings, mainly to avoid placing the food on a hot cement surface. The food should be spread out around the edge of the pool under the shaded area so that the animals do not have to climb over one another to reach it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In cemented pens the area where the food is laid out should be cleaned and scrubbed two hours after feeding time and any uneaten food removed from the water with a hand net. In earthen pools, the food should be placed at a different spot along the bank at each feeding. A useful aid to hygiene is keeping a few predacious fish, such as barbel (Clarias spp.), in each pool to clean up scraps of uneaten food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population Density</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Twenty-five crocodiles are considered the maximum manageable number per unit; staying within this limit reduces competition for food, bullying and fighting, and the number of injuries. A low stocking rate also results in a more even average growth rate. Most important is the fact that the overall health of the crocodiles is better than in a more crowded pen; disease problems are fewer and the symptoms easier to detect in a small group. If the units are spaced 8 m apart, there is also less danger of infectious disease spreading to other pens. The cleaning of pens is facilitated, and the disturbance caused by capturing crocodiles to be moved to other units is minimized. Housing 500 crocodiles in groups of 25 will require 20 separate pens, and an additional two pens should be provided to allow for intensive care of sick, injured, and weaker animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the first year, when animals are graded frequently, they will often be moved from one pen to another. Recording the number of animals housed in each pen will make it possible to keep track of numbers and movements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breeding</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reproduction is impossible when crocodiles are kept in large groups composed of different species and sizes and in more or less unnatural enclosures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Healthy, sexually mature pairs of crocodiles are usually not enough to start a breeding program. Genetic diversity to maintain a long-term breeding group must be considered, and certain environmental factors are vital for success. The distinct size and age classes of a free-living population must also be taken into consideration. Optimal sex ratios for breeding in enclosed compounds must be determined and adhered to. If a breeding unit is not based on regard for the animals' basic needs for space, nesting sites, and retreats, the larger specimens will disturb, injure, and often kill smaller specimens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Diseases and Parasites</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Disease symptoms may be easily overlooked if the observer is not familiar with the behavior of crocodiles under a variety of conditions. It is essential to know how they normally walk, swim, sleep, feed, and bask in relation to the time of day, the air and water temperatures, and the amount of sunlight or rain, by day, by night, and at different seasons of the year. Caretakers should notice the appearance of feces from healthy animals to be able to detect evidence of diarrhea, and to identify misaligned teeth and weakened limbs to detect nutritional deficiencies. Eggs are critically dependent on specific temperature and moisture requirements if the embryos are to develop normally.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is often difficult to determine the cause of illness or death, and even if the ailment has been correctly diagnosed, it is not easy to capture and administer drugs to large numbers of sick animals. Some animals may be injured during the handling process. Emphasis on preventing disease, rather than curing it, is the best way of ensuring a healthy crop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Almost inevitably, the water in the pools will harbor concentrations of bacteria such as salmonella. If strict hygiene is observed, however, the bacterial level will not be harmful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is recommended that whenever possible animals found newly dead should be dissected and vital organs such as the brain, heart, lung, liver, spleen, kidney, and stomach removed for veterinary research. Blood slides should also be taken and feces samples collected. The various specimens must be carefully labeled, frozen as quickly as possible, and packed on ice in a vacuum flask for immediate dispatch to the nearest veterinary research institute or pathologist. Alternatively, dying animals may be sent live for research purposes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is helpful for the handler to become thoroughly acquainted with the animal's internal anatomy, in order to distinguish between healthy and diseased organs. This knowledge, coupled with the symptoms noted before the animal dies, and the veterinary report, will be useful in future diagnosis and treatment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One problem for the crocodile farmer is a roundworm (nematode) parasite that burrows into the belly skin. When the burrow collapses it produces an undulating track across the belly and throat scales that ruins the hide. These parasites have been found in crocodiles from Latin America, Africa, Australia, Papua New Guinea, and Asia. They seem more prevalent in some areas and some farms than in others. The organism has been identified, but no treatment or control has been discovered. It is, however, believed that damp, muddy conditions foster the nematode, and that to reduce it pens should have areas of dry land where the animals can bask.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Killing, Skinning, and Tanning</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some farmers kill the crocodiles themselves, but many rear the animals and then sell them to a larger concern that is better equipped to deal with the skins. Killing is done most quickly and humanely by catching the crocodile with a noose and severing the spinal cord just behind the skull.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many hides are ruined or severely damaged during skinning. Even a single hole resulting from a slip of the skinning knife may reduce a hide's value by 25 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After skinning, the hides are normally coated with about 0.5 cm of coarse salt and rolled up. Within 48 hours they are unrolled and resalted. If the hide is not sufficiently salted, it may become infected with bacteria or fungi that cause the epidermis of the scales to decay or slip. Although this layer is removed during tannage, scale slip is a symptom of rot and usually causes damage to the finished hide product. If the decay is intense, the salted hides may become reddish or brown in color. This is called "red heat."</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although salt remains the universally used preservative for raw hides, the reptile leather industry has developed chemical fixatives that are used in addition to salt for preserving hides for tanning. Most of these pretannage fixatives are liquid and require soaking the hide in a vat, which may not be feasible in remote areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A pretanned hide is called a crust. It is green-gray (chrome tanned) or tan (vegetable tanned) and is stiff. The hide is dyed and glazed to its final finish. To increase the workability and to remove as many of the osteoderms as possible (if they are present), the underside of the hide is shaved to an even thickness. The shaving is done by craftsmen. If they shaved too much, the hide will be thin and weak, especially over the suture between the scales.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendix C: Selected Readings</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information on the management and status of crocodiles can be found in the following:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IUCN/Crocodile Specialist Group Newsletter. Available from the editors, Peter Brazaitis and Myrna Watanabe, c/o New York Zoological Park, Bronx Zoo, The Bronx, New York 10460, USA.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A Field Guide of Captive Rearing and Management of Crocodiles in India is available from Mr. R. K. Rao, Director, Central Crocodile Breeding and Management Training Institute (Government of India), Hyderabad, Andhra Pradesh, India.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blake, D. K. 1974. The rearing of crocodiles for commercial and conservation purposes in Rhodesia. The Rhodesia Science News 8(10):315-324.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blake, D. K., and J. P. Loveridge. 1975. The role of commercial crocodile farming in crocodile conservation. Biological Conservation 8(4): 261-272.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bolton, M. 1981. Crocodile Husbandry in Papua New Guinea. Field Document 4. FO: DP/ PNG/74/029. Food and Agriculture Organization of the United Nations, Rome, Italy. 103 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bolton, M., and M. Laufa. 1982. The crocodile project in Papua New Guinea. Biological Conservation 22:169-179.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazaitis, P. (In press) Problems in the Identification of Commercial Crocodilian Hides and the Effect on Law Enforcement. Proceedings of the IUCN Crocodile Specialist Group meeting in Zimbabwe September-October, 1982. International Union for the Conservation of Nature and Natural Resources, Gland, Switzerland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazaitis, P. 1973. The identification of living crocodiles. Zoologica 58(3-4):59-101.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cott, H. B. 1954. Ecology and economic status of the crocodile in Uganda. Record of the Symposium on African Hydrobiology and Inland Fisheries, Committee on Technical Cooperation for Africa South of the Sahara 6:119-122.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cott, H. B. 1961. Scientific results of an inquiry into the ecology and economic status of the Nile crocodile (Crocodylus niloticus) in Uganda and Northern Rhodesia. Transactions of the Zoological Society of London 29(4):211-337.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Downes, M. C. 1978. An explanation of the National Policy for the Crocodile Programme. Wildlife Division, Department of Lands, Surveys and Environment, Konedobu, Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fuchs, K., nd. Die Krokodilhaut Eduard Roether Verlag Darmstadt, Frankfurt, West Germany.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Graham, A., 1981. Mapping the pattern of crocodile nesting activity in Papua New Guinea. Field Document No. 3, FO: DP/PNG/74/029. Food and Agriculture Organization of the United Nations, Rome, Italy. 50 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joanen, T., and L. McNease. 1975. Notes on the Reproductive Biology and Captive Propagation of the American Alligator. Proceedings of the 29th Annual Conference of the Southeastern Association of Game and Fish Commissioners 29:407-415. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joanen, T., and L. McNease. 1979. Culture of the American alligator. International Zoo Yearbook 19:61-66.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">King, F. W., and P. Brazaitis. 1971. Species identification of commercial crocodile skins. Zoologica 56(2): 15-72.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Loveridge, J. P. ed. 1982. The Zimbabwe Science News 16(9):196-219. Causeway, Zimbabwe. (Contains five articles on crocodilian research and conservation; from Zimbabwe, Australia the United States, and lndia.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Millichamp, N. J. ;980. Medical aspects of disease in reptile collections. In The Care and Breeding of Captive Reptiles, The British Herpetological Society, London, England.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parker, F. 1981. New Crocodile Laws for Papua New Guinea. Division of Wildlife, Department of Lands and Environment, Konedobu, Papua New Guinea. 50 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. 1969. Some observations on the rearing of crocodiles. Lammergeyer 10:45-59.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. 1971. Crocodile rearing and restocking. Pp. 104-130 in Crocodiles, IUCN Publications New Series Supplementary Paper 32. International Union for Conservation of Nature and Natural Resources, 1110 Gland, Switzerland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. 1973. Conservation and Management of Crocodiles in Africa. Journal of the South African Wildlife Management Association 3(2):101-103.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. 1977. A report on Crocodile Farming. Papua New Guinea. Wildlife leaflet No. 77/27. pp. 1-14.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. 1981. Disappearing African Crocodiles. Oryx 16(1):38-40.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C. (In press). The status of crocodiles in Africa. Paper Presented at 5th Meeting IUCN Survival Service Commission's Crocodile Specialist Group. Gainesville Florida, USA. September 1980.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pooley, A. C., and C. Gans. 1976. The Nile crocodile. Scientific American 234(4): 114-124.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wallis, B. E. 1980. Market prospects for reptile leathers. Report number ITC/DIP/12, International Trade Commission, Geneva, Switzerland. 50 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wermuth, Von H., and K. Fuchs. 1978. Bestimmen von Krokodilen und ihrer Haute. Gustav Fischer Verlag, Stuttgart, New York.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whitaker, R. 1982. Export prospects from commercial crocodile farms in Bangladesh. ITC/UNCTAD, Geneva, Switzerland. 47 pp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whitaker, R., and M. Kemp. 1981. The crocodile industry in Papua New Guinea: Commercial Aspects. Field Document No. 2. FO:DP/PNC/74/029. Food and Agricultural Organization of the United Nations, Rome, Italy. 35 pp. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendix D: Research Contacts</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following individuals are involved in crocodilian research. Most are biologists concerned with the conservation or natural history of the animals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Applied Ecology Crocodile Farm, Edward River, Queensland 4870</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shelley Burgin, Total Environment Center, 18 Argyle Street, Sydney, New South Wales 2000</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Melvin Bolton, Woodbury Farm, Woodbury Road, M.S. 142, Via Yeppoon, Queensland 4703</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Max C. Downes, The Game Conservation Center, 24 Queens Parade, North Fitzroy, Victoria 3068</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alistair Graham, P.O. Box41266, Darwin, Northern Territory 5792</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gordon Grigg, Zoology A08, University of Sydney, Sydney, New South Wales 2006</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Lever, Koorana Crocodile Farm, M.S.F. 76, Rockhampton, Queensland 4702</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Harry Messel, Head, School of Physics, University of Sydney, Sydney, New South Wales 2006</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fred Parker, 717 Ross River Road, Kirwan, Queensland 4814</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grahame Webb, School of Zoology, University of New South Wales, Kensington 2033</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bangladesh</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mohd. Reza Khan, Assistant Professor, Department of Zoology, University of Dacca, Dacca 2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">William Magnusson, Depto de Ecologia, Instituto Nacional de Pesquisas da Amazonia, Caixa Postal 478, 69000, Manaus, Amazonia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burma</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ko Ko Gyi, Professor of Zoology, Rangoon Arts and Sciences University, Rangoon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nyan Taw, Research Officer, People's Pearl and Fishery Corporation, Myakhwanyo Street, Thaketa, Rangoon </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People's Republic of China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Huang Chu-Chien, Institute of Zoology, Chinese Academy of Science, Beijing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Swatow Prefecture Crocodile Farm, Shantou, Guang Dong Province</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Colombia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Federico Medem, Instituto Roberto Franco, Apartado Aereo 2261, Villavicencio (Meta)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gerado Budowski, Head, Natural Renewable Resources Programme, CATIE, Turrialba</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cuba</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Luis Varona, Norte 29, Nuevo Vedado, La Habana 6</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dominican Republic</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jose Alberto Ottenwalder, Museo Nacional de Historia Natural, Plaza de la Cultura, Santo Domingo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Karlheinz Fuchs, Schillerstrasse 2, 6257 Hunfelder 2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guatemala</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jaime Tres 1., Centro de Estudias Conservacionistas, Universidad de San Carlos de Guatemala, Avenida de la Reforma 0-63, Zona IO, Guatemala</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B. C. Choudhury and Lala A. K. Singh, Central Crocodile Breeding and Management Training Institute, 19-4-319, Lake Dale, Rajendranagar Road, Hyderabad 500 264, Andhra Pradesh</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indian Board for Wildlife, c/o Department of Environment, Bikaner House, Shahjahan Road, New Delhi 110 011</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Sale, UNDP/FAO Crocodile Breeding and Management Project, 19-4-319, Lake Dale, Rajendranagar Road Hyderabad 500 264, Andhra Pradesh</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S. Shanmugunathan, Chief Wildlife Warden, Vivekananda Road, Coimbatore, Tamil Nadu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sudhakar Kar, Saltwater Crocodile Research and Conservation Unit, Danginal 754 220 Via Rejkanika, District Cuttack, Orissa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Romulus Whitaker, Madras Snake Park Trust, Guindy Deer Park, Madras, Tamil Nadu, 600 002</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G. S. Child, Wildlife and Parks Management Of ficer FAO, Rome</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Japan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wataru Kimura, Proprietor, Atagawa Tropical and Alligator Garden, Atagawa Higashi Zlu Town, Shizuoka Prefecture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">R.D. Haller , Bamburi Portland Cement Co. ,Ltd., P.O. Box 90202 ,Mombasa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paul R. Wycherley, President, Malayan Nature Society, P.O. Box 150, Kuala Lumpur</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mexico</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Miguel Alvarez del Toro, Director, Instituto de Historia Natural, Departamento de Zoologia, Apartado Postal No. 6, Tuxtle Gutierrez, Chiapas, 29000</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Marco Antonio Lascano B., INIREB, Apdo. No 281, Merida</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tirtha Maskey, National Parks and Wildlife Conservation Office, Thapathali, P.O. Box 107, Kathmandu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Zealand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antoon de Vos, Box 34, Whitford, Auckland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nicaragua</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Milton G. Camacho B., Instituto Nicaraguense de Recursos Naturales y del Ambiente (IRENA), Depto. de Fauna Silvestre, Kim 12 1/2 Carreterra Norte, Managua.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pakistan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ashiq Ahmad, Wildlife Management Specialist, Pakistan Forest Institute, Peshawar</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abdul Latif Rao, Conservator of Wildlife, National Council for Conservation of Wildlife, Ministry of Food and Agriculture, U.G. St. 51, Sector F 6/4, Islamabad</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Miro Laufa, Division of Wildlife, Department of Lands and Environment, P.O. Box 2585, Konedobu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Karol Kisokau, Director, Office of Environment and Conservation, Central Government Offices, Waigani</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Navu Kwapena, Division of Wildlife, Department of Lands and Environment, Konedobu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Graham Goudie, Crocodile Farm, Lae</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Martin Hollands, Monitoring Ecologist, National Crocodile Project, P.O. Box 2585 Konedobu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peru</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pedro Vasques Ruesta, Departamento de Manejo Forestal, Universidad Nacional Agraria, Apdo. 456, La Molina</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angel C. Alcala, Division Research, Extension and Development, Silliman University, Dumaguete City, 6501, Negros</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">School of Agriculture, Silliman University, Dumaguete City, 6501, Negros.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. B. Anthony, The Natal Parks, Game and Fish Preservation Board, Box 662, Pietermaritzburg, Natal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antony Pooley, P.O. Box 42, St. Lucia Estuary, 3936 Zululand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Switzerland</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rene E. Honegger, Curator, Zurich Zoo, Zurichbergstrasse 221, 8044 Zurich</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">U. Srisomboon, Ministry of Agriculture, Department of Livestock Development, Bangkok Utai Youngprapakorn and Charoon Youngprapakorn, The Samutprakan Crocodile Farm and Zoo Co., Ltd., Talban Road, Samutprakan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angus d'A. Bellairs, Department of Anatomy, St. Mary's Hospital Medical School University of London, Paddington, London W2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Robert Bustard, Isle of Man</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">United States</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Behler, New York Zoological Society, 185th Street &amp; Southern Blvd., The Bronx, New York 10460</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peter Brazaitis, New York Zoological Society, 185th Street &amp; Southern Blvd., The Bronx New York 10460</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gary Callis, Rt. I, Box 360, Clayton, New Mexico</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert H. Chabreck, Louisiana State University, School of Forestry and Wildlife Management, Baton Rouge, Louisiana 70803</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Michael Davenport, Department of Herpetology, National Zoological Park, Smithsonian Institution, Washington, D.C. 20008</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Claire Hagen, Representative, Reptile Products Association, 120 Cabrini Blvd., New York, New York 10033</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fred Hauptfuhrer, Director of Planning and Development, World Wildlife Fund, Inc., 910 17th Street NW, Washington, D.C. 20006</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Howard Hunt, Atlanta Zoological Park, 518 Atlanta Ave. S.E., Atlanta, Georgia 30315</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ted Joanen, Rockefeller Wildlife Refuge, Route 1, Box 20-B, Grand Chenier, Louisiana 70643</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. Wayne King, Director, Florida State Museum, Gainesville, Florida 32611</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jeffrey W. Lang, Biology Department, University of North Dakota, University Station, Grand Forks, North Dakota 58202</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles J. Lankester, UNDP, I United Nations Plaza, New York, New York 10017</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">James H. Powell, 1110 Kokomo Street, Plainview, Texas 79072</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles A. Ross, Division of Reptiles and Amphibians, National Museum of Natural History, Smithsonian Institution, Washington, D.C. 20560</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Myrna Watanabe, 141 Columbia Heights, Brooklyn, New York 11201</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uruguay</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Federico Achaval, Departamento de Zoologia (Vertebrados), Universidad de la Republic Cerrito73, Montevideo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Venezuela</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tomas Blohm, Apartado 69, Caracas 1010-A</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Andres Seijas Y., Servicio Nacional de Fauna Silvestre, MARNR, Apartado 184, Maracay</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. K. Blake, Department of National Parks and Wildlife Management, P.O. Box 8365, Causeway, Harare</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John Loveridge, Zoology Department, University of Zimbabwe, P.O. Box MP 167, Mount Pleasant, Harare</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kevin van Jaarsveldt, Crocodile Farmers Association of Zimbabwe, P.O. Box 2569, Harare </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendix E: Biographical Sketches of Panel Members</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Director of the Office of Biological Secretary General Smithsonian Institution, Washington, D.C., is currently the Secretary General of the International Union of Biological Sciences. He received his B.A. in 1961 from Miami University in Ohio, M.Sc. from The George Washington University in 1963, and his Ph.D. in 1966 from the University of London. His research interests are in comparative anatomy and phylogeny of flowering plants, commercial timbers, histology of monocotyledons, economic botany, and tropical biology. An internationally recognized expert on tropical plants, he has published extensively in these areas and on topics relating to science, technology, and development, especially in developing countries. Dr. Ayensu was co-chairman of the Panel on Underexploited Tropical Plants of the Advisory Committee on Technology Innovation and chairs and serves as a member of many international bodies. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ARCHIE F. CARR, JR., is Graduate Research Professor in the Department of Zoology, University of Florida, Gainesville. As Technical Director of the Caribbean Conservation Corporation, he has directed a seasonal research program at the breeding ground of the green turtle at Tortuguero, Costa Rica, since 1952, with continuous grants from the National Science Foundation from 1955 to 1980, and has carried out investigations of marine turtle ecology and navigation in various parts of the world. The author of numerous papers, articles, and books, he received the Daniel Giraud Elliot Medal of the National Academy of Sciences for Handbook of Turtles and the John Burroughs Medal for The Windward Road. He is Research Associate of the American Museum of Natural History; Affiliate Curator of Natural Sciences, Florida State Museum; Chairman of the Marine Turtle Specialist Group of the Survival Service Commission, International Union for the Conservation of Nature; Honorary Consultant of the World Wildlife Fund; Fellow of the Linnean Society of London; Fellow of the American Fisheries Society; and a member of Phi Beta Kappa and Sigma Xi.In 1973 he was awarded a gold medal from the World Wildlife Fund for the application of scientific findings to the conservation of marine turtles. In 1975 he received the Edward W. Browning Award for achievement in biological conservation. In 1978 Dr. Carr was awarded the Gold Medal of the New York Zoological Society for contributions to natural science and conservation; in 1978 he became Officer of the Order of the Golden Ark (The Netherlands).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. WAYNE KING is the Director of the Florida State Museum, Gainesville. He received a B.S. in 1957 and an M.S. in 1961 from the University of Florida and a Ph.D. from 1966 from the University of Miami. His research interests are in wildlife conservation and habitat preservation, impact of international trade on wildlife populations, and ecology and behavior of reptile populations. He worked at the New York Zoological Society from 1967 to 1975. As an international wildlife consultant, Dr. King has received honors from the Dominican Republic, the American Association of Zoological Parks and Aquariums, and from H.R.H. Prince Bernhard of The Netherlands. He has served on committees advising the State Department and the International Union for Conservation of Nature and Natural Resources on policies regarding the trade of crocodile skins, turtle products, and other wildlife materials. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOIS MERGEN, Pinchot Professor of Forestry and Professor of Forest Genetics, Yale University, was Dean of the School of Forestry and Environmental Studies at Yale from 1965 to 1975. He received a B.A. from Luxembourg College and a B.Sc.F. from the University of New Brunswick in 1950, an M.F. in ecology in 1951, and a Ph.D. in forest genetics from Yale in 1954. He is especially knowledgeable about francophone Africa and was chairman of the Sahel program of the Board on Science and Technology for International Development and a member of the Advisory Committee on Technology Innovation. From 1960 to 1965 he was research collaborator at the Brookhaven National Laboratory. In 1966 he was the recipient of the Award for Outstanding Achievement in Biological Research from the Society of American Foresters and in 1975 was Distinguished Professor (Fulbright-Hays Program) in Yugoslavia. Before joining the Yale faculty, he served as project leader in forest genetics for the U.S. Forest Service in Florida. He has served as a consultant to FAO, various foreign governments, and private forestry companies, and he has traveled extensively in the tropical countries of Asia, Africa, and Latin America. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. MORRIS is head of the Furzebrook Research Station of the Institute of Terrestrial Ecology (National Environment Research Council, U.K.). He received a B.A. in natural sciences (zoology) at the University of Cambridge of 1958, M.A. in 1962, and received his Ph.D. from London University in research on the integrated control of orchard pests. Dr. Morris worked at Monks Wood Experimental Station on the effects of grassland management on populations of invertebrates and developed a strong interest in community and applied ecology, particularly the conservation of insect populations. Recently he has become involved with problems of butterfly conservation and resource utilization. He is Secretary of the Joint Committee for the Conservation of British Insects, a Vice-Chairman of the Lepidoptera Specialist Group of lUCN'S Survival Commission, and Chairman of the Habitat and Species Protection Committee of SEL (Societal Europaea Lepidoptero-Logica). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH L. POPENOE is Professor of Soils, Agronomy, Botany, and Geography and Director of the Center for Tropical Agriculture and International Programs (Agriculture) at the University of Florida. He received his B.S. from the University of California at Davis in 1951 and his Ph.D. in soils from the University of Florida in 1960. His principal research interest has been in the area of tropical agriculture and land use. His early work on shifting cultivation is one of the major contributions to this system. He has traveled and worked in most of the countries in the tropical areas of Latin America, Asia, and Africa. He is past Chairman of the Board of Trustees of the Escuela Agricola Panamericana in Honduras, Visiting Lecturer on Tropical Public Health at the Harvard School of Public Health, and a Fellow of the American Association for the Advancement of Science, the American Society of Agronomy, the America Geographical Society, and the International Soils Science Society. He is Chairman of the Advisory Committee for Technology Innovation and a member of the Board on Science and Technology for International Development. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT MICHAEL PYLE, a writer and consulting lepidopterist based in Gray's River, Washington, has served since 1979 as Co-Compiler of the lUCN Invertebrate Red Data Book. In this capacity he is consultant to the Conservation Monitoring Center in Cambridge, England. After receiving his B.S. and M.S. at the University of Washington, he took his Ph.D. through the School of Forestry and Environmental Studies at Yale University in 1976. He worked for the Government of Papua New Guinea on the conservation and utilization of insect resources and then with the Nature Conservancy as Northwest Land Steward. A former Fulbright Scholar to the United Kingdom, Dr. Pyle subsequently founded the Xerces Society for conservation of beneficial insects and their habitats. He has been chairman of IUCN'S Lepidoptera Specialist Group (Species Survival Commission) since 1976. His publications include the Audubon Society Field Guide to North American Butterflies. A comprehensive book on insect conservation in his next project.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SHELDON R. SEVERINGHAUS received his Ph.D. from Cornell University in 1977 in natural resources management. He has worked on various wildlife research projects in Asia since 1964 and is representative for the Asia Foundation in Taiwan. He has published articles on butterfly conservation and wildlife industries in Taiwan, where he has been studying the butterfly and wildlife farming projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, staff officer for this study, is Professional Associate of the Board on Science and Technology for International Development. A New Zealander with a Ph.D. in organic chemistry from the University of California, Berkeley, he now works on innovations in science that are important for developing countries. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Advisory Committee on Technology Innovation</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM BRADLEY, Consultant, New Hope, Pennsylvania</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HAROLD DREGNE, Director, International Center for Arid and Semi-Arid Land Studies, Texas Tech University, Lubbock, Texas (member through 1981) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CARL N. HODGES, Director, Environmental Research Laboratory, Tucson, Arizona </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CYRUS MCKELL, Native Plants, Inc., Salt Lake City, Utah </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOIS MERGEN, Pinchot Professor of Forestry, School of Forestry and Environmental Studies, Yale University, New Haven, Connecticut (member through 1982) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Consultative Group on International Agricultural Research, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THEODORE SUDIA, Deputy Science Advisor to the Secretary of Interior, Department of Interior, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Board on Science and Technology for International Development</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE BUGLIARELLO, President, Polytechnic Institute of New York, Brooklyn, New York, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SAMUEL P. ASPER, Educational Commission for Foreign Medical Graduates, Philadelphia, Pennsylvania </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DAVID BELL, Department of Population Sciences, Harvard School of Public Health, Boston, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LEONARD BERRY, Professor, Graduate School of Geography, Clark University, Worcester, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ERNEST I. BRISKEY, Dean, School of Agriculture, Oregon State University, Corvallis, Oregon </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARRISON S. BROWN, Director, Resources Systems Institute, East-West Center, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT H. BURRIS, Department of Biochemistry, University of Wisconsin, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CLAUDIA JEAN CARR, Associate Professor, Conservation and Resource Studies, University of California at Berkeley, Berkeley, California </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATE FIELDS, Director, Developing Markets, Control Data Corporation, Minneapolis, Minnesota </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROLAND J. FUCHS, Chairman, Department of Geography, University of Hawaii at Manoa, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN HOWARD GIBBONS, Director, U.S. Congress, Office of Technology Assessment, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N. BRUCE HANNAY, Foreign Secretary, National Academy of Engineering, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM HUGHES, Director, Engineering Energy Laboratory, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM A. W. KREBS, Vice President, Arthur D. Little, Inc., Acorn Park, Cambridge, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE I. LYTHCOTT, University of Wisconsin, School of Medicine, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JANICE E. PERLMAN, Executive Director, Committee for a New New York, New York City Partnership, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK C. ROBBINS, President, Institute of Medicine, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WALTER A. ROSENBLITH, Foreign Secretary, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK SEITZ, President Emeritus, The Rockefeller University, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH HERBERT SMUCKLER, Dean of International Studies and Programs, Michigan State University, East Lansing, Michigan </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GILBERT F. WHITE, Institute of Behavioral Science, University of Colorado, Boulder, Colorado </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BILL C. WRIGHT, Assistant Dean for International Programs, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN G. HURLEY, Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. C. McDONALD DOW, Associate Director/Studies </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL P. GREENE, Associate Director/Research Grants </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P></FONT>
+<!--
+</Section>
+</Section>
+-->
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b20cre/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b20cre/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b20cre/metadata.xml	(revision 10506)
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">Managing Tropical Animal Resources - Crocodiles as a Resource for the Tropics (b20cre)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Animal Husbandry and Animal Product Processing|Other animals (micro-livestock, little known animals, silkworms, reptiles, frogs, snails, game, etc.)</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">BOSTID</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b21wae/b21wae.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b21wae/b21wae.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b21wae/b21wae.htm	(revision 10506)
@@ -0,0 +1,1888 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; The Water Buffalo: New Prospects For An Underutilized Animal (1984)</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">The Water Buffalo: New Prospects For An Underutilized Animal (1984)</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Original editon 1981</P>
+<P ALIGN="JUSTIFY">Second printing 1984</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Report of an Ad Hoc Panel of the</P>
+<P ALIGN="JUSTIFY">Advisory Committee on Technology Innovation</P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development</P>
+<P ALIGN="JUSTIFY">Commission on International Relations</P>
+<P ALIGN="JUSTIFY">National Research Council</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Panel on Water Buffalo</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of  Florida, Gainesville, Florida, USA, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">STEVE P. BENNETT, Bennett's Animal Clinic, Port of Spain, Trinidad, West Indies</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CHARAN CHANTALAKHANA, Dean, Department of Animal Science, Kasetsart  University, Bangkok, Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD D. CHARLES, Senior Lecturer, Meat Production, Department of Animal  Husbandry, University of Queensland, St. Lucia, Queensland, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. ROSS COCKRILL, Livestock Expert, Food and Agriculture Organization (retired),  Rome, Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WYLAND CRIPE, Department of Veterinary Science, University of Florida,  Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TONY J. CUNHA, Dean, School of Agriculture, California Polytechnic University,  Pomona, California, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. JOHN DE BOER, Winrock International Livestock Research and Training Center,  Morrilton, Arkansas, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MAARTEN DROST, Department of Veterinary Science, University of Florida,  Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MOHAMED ALI EL-ASHRY, Department of Animal Production, Faculty of  Agriculture, Shoubra el Khiema, Cairo, Egypt </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ABELARDO FERRERD ., Former Director, Breeding Administration Centers,  Animal Sciences Division, Ministry of Agriculture, Caracas, Venezuela</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JEAN K. GARDNER, Former Chief, Logistics Division USAID/Philippines, Jackson,  Mississippi, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JAMES F. HENTGES, Department of Animal Science,University of Florida,  Gainesville, Florida, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JACK HOWARTH, School of Veterinary Medicine, University of California, Davis,  California, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NELS M. KONNERUP, Livestock Expert, Agency for International Development  (retired), Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. P LEONARDS, Water buffalo breeder, Lake Charles, Louisiana, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN K. LOOSLI, Department of Animal Science, University of Florida, Gainesville,  Florida, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOSEPH MADAMBA, Director, Asian Institute of Aquaculture, Iloilo, Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CRISTO NASCIMENTO,Director, Brazilian Agriculture Research Corporation  (EMBRAPA), Agriculture Research Center for Humid Tropics (CPATU), Belem,  Para, Brazil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Consultative Group on International Agricultural  Research, The World Bank, Washington, D.C., USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM R. PRITCHARD, Dean, School of Veterinary Medicine, University of California, Davis, California, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. THOMAS REID, (deceased), Department of Animal Science, Cornell University, Ithaca, New York, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN H. SCHOTTLER, Animal Production Officer, Department of Primary Industries, Lae, Papua New Guinea </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DALBIR SINGH DEV, Dean, Animal Science Department, College of Agriculture, Agricultural University, Ludhiana, Punjab, India </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT W. TOUCHBERRY, Dean, Department of Animal Science, University of Minnesota, St. Paul, Minnesota, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD G. TULLOCH, Division of Wildlife Research, Commonwealth Scientific and Industrial Research Organization, Winnellie, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, Board on Science and Technology for International Development, National Research Council, Washington, D.C., Staff Study Director </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MARY JANE ENGQUIST, Board on Science and Technology for International Development, National Research Council, Washington, D.C., Staff Associate </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Preface</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo is an animal resource whose potential seems to have been barely recognized or examined outside of Asia. Throughout the world there are proponents and enthusiasts for the various breeds of cattle; the water buffalo, however, is not a cow and it has been neglected. Nevertheless, this symbol of Asian life and endurance has performed notably well in recent trials in such diverse places as the United States, Australia, Papua New Guinea, Trinidad, Costa Rica, Venezuela, and Brazil. In Italy and Egypt as well as Bulgaria and other Balkan states the water buffalo has been an important part of animal husbandry for centuries. In each of these places certain herds of water buffalo appear to have equaled or surpassed the local cattle in growth, environmental tolerance, health, and the production of meat and calves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although these are empirical observations lacking painstaking, detailed experimentation, they do seem to indicate that the water buffalo could become an important resource in tropical, subtropical, and warm temperate zones in developing and developed countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If this is the case, then it is clear that many countries should begin water buffalo research. Serious attention by scientists could help dispel the misperceptions and uncertainties surrounding the animal and encourage its true qualities to emerge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report describes the water buffalo's attributes as perceived by several animal scientists. It is designed to present the apparent strengths of buffaloes compared with those of cattle, to introduce researchers and administrators to the animal's potential, and to identify priorities for buffalo research and testing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel that produced this report met at Gainesville, Florida, in July 1979. It was composed of leading water buffalo experts (particularly those from outside Asia who have directed the beginnings of water buffalo industries in their countries) and leading American animal scientists, many of whom are also familiar with the animal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report complements The Husbandry and Health of the Domestic Buffalo, edited by W. Ross Cockrill and published in 1974 by the Food and Agriculture Organization of the United Nations. Cockrill's 933-page book is a "bible" of water buffalo knowledge and provides details of breeds, world distribution, physiology, and an extensive bibliography.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The present report is an introduction to the water buffalo and its potential. It is written particularly for decision makers, as well as scholars or students, in the hope that it will stimulate their interest in the animal and thereby increase the appreciation of, and funding for, buffalo research. The report includes much empirical observation, largely from the panel members. Some of these observations may, in the long run, prove not to be universally applicable. Much benchmark information needs to be obtained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since its creation in 1971, the Advisory Committee on Technology Innovation (ACTI) has investigated innovative ways to use current technology and resources to help developing countries. Often this has meant taking a fresh look at some neglected and unappreciated plant or animal species. The committee assembles ad hoc panels of experts (usually incorporating both skeptics and proponents) to scrutinize the topics selected. The panel reports serve to draw attention to neglected, but promising, technologies and resources. (For a list of ACTI reports, see page 115.) ACTI reports are provided free to developing countries under funding by the Agency for International Development (AID).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Program costs for this study were provided by AID'S Office of Agriculture, Development Support Bureau, and staff support was provided by the Office of Science and Technology, Development Support Bureau.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The final draft of this report was edited and prepared for publication by F. R. Ruskin. Bibliographic editing was by Wendy D. White. Cover art was by Deborah Hanson.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">1 Introduction</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The domesticated water buffalo Bubalus bubalis numbers at least 130 million-one-ninth the number of cattle in the world. It is estimated that between 1961 and 1981 the world's buffalo population increased by 11 percent, keeping pace with the percentage increase in the cattle population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there are some pedigreed water buffaloes, most are nondescript animals that have not been selected or bred for productivity. There are two general types-the Swamp buffalo and the River buffalo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Swamp buffaloes are slate gray, droopy necked, and ox-like, with massive backswept horns that make them favorite subjects for postcards and wooden statuettes in the Far East. They are found from the Philippines to as far west as India. They wallow in any water or mud puddle they can find or make. Primarily employed as a work animal, the Swamp buffalo is also used for meat but almost never for milk production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">River buffaloes are found farther west, from India to Egypt and Europe. Usually black or dark gray, with tightly coiled or drooping straight horns, they prefer to wallow in clean water. River buffaloes produce much more milk than Swamp buffaloes. They are the dairy type of water buffalo. In India, River buffaloes play an important role in the rural economy as suppliers of milk and draft power. River buffaloes make up about 35 percent of India's milk animals (other than goats) but produce almost 70 percent of its milk. Buffalo butterfat is the major source of cooking oil (ghee) in some Asian countries, including India and Pakistan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although water buffaloes are bovine creatures that somewhat resemble cattle, they are genetically further removed from cattle than are the North American bison (improperly called buffalo) whose massive forequarters, shaggy mane, and small hindquarters are unlike those of cattle. While bison can be bred with cattle to produce hybrids,( This is not, however, very successful, the male progeny (at least of the F 1 generation) are sterile).there is no well-documented case of a mating between water buffalo and cattle that has produced progeny.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parts of Asia and even Europe have depended on water buffaloes for centuries. Their crescent horns, coarse skin, wide muzzles, and low-carried heads are represented on seals struck 5,000 years ago in the Indus Valley, suggesting that the animal had already been domesticated in the area that is now India and Pakistan. Although buffaloes were in use in China 4,000 years ago, they are not mentioned in the literature or seen in the art of the ancient Egyptians, Romans, or Greeks, to whom they were apparently unknown. It was not until about 600 A.D. that Arabs brought the animal from Mesopotamia and began moving it westward into the Near East (modern Syria, Israel, and Turkey). Water buffaloes were later introduced to Europe by pilgrims and crusaders returning from the Holy Land in the Middle Ages. In Italy buffaloes adapted to the area of the Pontine Marshes southeast of Rome and the area south of Naples. They also became established in Hungary, Romania, Yugoslavia, Greece, and Bulgaria and have remained there ever since.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Villagers in medieval Egypt adopted the water buffalo, which has since become the most important domestic animal in modern Egypt. Indeed, during the last 50 years, their buffalo population has doubled to over 2 million head. The animals now supply Egypt with more meat-much of it in the form of tender "veal"-than any other domestic animal. They also provide milk, cooking oil, and cheese.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other areas have capitalized on the water buffalo's promise only in very recent times. For instance, small lots of the animals brought to Brazil (from Italy, India, and elsewhere) during the last 84 years have reproduced so well that they now total about 400,000 head and are still increasing, especially in the lower Amazon region. Buffalo meat and milk are now sold widely in Amazon towns and villages; the meat sells for the same price as beef. Nearby countries have also become familiar with the water buffalo. Trinidad imported several breeds from India between 1905 and 1908, while Venezuela, Colombia, and Guyana have been importing them in recent decades. During the 1970s Costa Rica, Ecuador, Cayenne, Panama, Suriname, and Guyana introduced small herds. By 1979 the buffalo in Venezuela numbered more than 7,000 head.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Across the Pacific, the new nation of Papua New Guinea has found the water buffalo well suited to its difficult environment. For 9 years the government has attempted to run cattle on the Sepik and Ramu Plains on Papua New Guinea's north coast, where the temperatures are high and the forage of poor quality. But the cattle remain thin and underweight. In the 1960s animal scientists began evaluating water buffaloes already living in Papua New Guinea and, encouraged by the results, introduced additional buffaloes from Australia. These have performed remarkably well, producing greater numbers of calves and much more meat than the cattle in the region. The buffaloes appear to maintain appetite despite the heat and humidity, whereas cattle do not. The government of Papua New Guinea has since imported more water buffaloes and today has thriving herds totaling almost 3,500 head. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The United States has been slow to recognize the water buffalo's potential, but the first herd (50 head) ever imported for commercial farming arrived in February 1978.(Air-freighted from the wilds of Guam, the U.S. island possession on the western Pacific, by panel member Tony Leonards. Prior to that time (in 1974), four head of water buffalo were imported to the Department of Animal science' university of Florida, for study. The only other water buffaloes in North America were a few animals in zoos.) The humble water buffalo, normally considered fit only for the steamy rice fields of Asia, is now proving itself on farm fields in Florida and Louisiana. As a result, interest in the animal is on the rise in U.S. university and farm circles.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From experience accumulated in Asia, Egypt, South America, Papua New Guinea, Australia, the United States, and elsewhere, animal scientists now perceive that many general impressions about the water buffalo are incorrect.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For example, it is widely believed that the water buffalo is mean and vicious. Encyclopedias reinforce this perception, and in the Western world it is the prevalent impression of the animal. The truth is, however, that unless wounded or severely stressed, the domesticated water buffalo is one of the gentlest of all farm animals. Despite an intimidating appearance, it is more like a household pet-sociable, gentle, and serene. In rural Asia the care of water buffaloes is often fumed over to small boys and girls aged about four to nine. The children spend their days with their family's gentle buffalo, riding it to water, washing it down, waiting while it rolls and wallows, and then riding it to some source of forage, perhaps a grassy field or thicket. It is not uncommon to see a buffalo patiently feeding, with a young friend stretched prone on its broad gray back, asleep.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perhaps the notion about the viciousness of water buffaloes stems from confusing them with the mean-tempered African buffalo Syncerus caffer, actually a distant relative with which they will not interbreed and which is classified in a different genus.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ferocity is the most blatant misconception concerning the water buffalo, although other fallacies are widely reported as well.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One generally held belief is that water buffaloes can be raised only near water. Actually, buffaloes love to wallow, but they grow and reproduce normally without it, although in hot climates they must have shade available.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another belief is that the water buffalo is exclusively a tropical animal. River-type buffaloes, however, have been used to pull snow plows during Bulgarian winters. They are found in Italy (over 100,000 head), Albania, Yugoslavia, Greece, Turkey, the Georgia and Azerbaijan areas of the Soviet Union (almost 500,000 head) and other temperate-zone regions as well. They are also found in cold, mountainous areas of Pakistan, Afghanistan, and Nepal.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p04to05.png"></center><br>
+ World Distribution of Water Buffaloes</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet another misconception is that the water buffalo is just a poor man's beast of burden. In addition to providing fine lean meat, buffaloes in fact provide rich milk. Mozzarella cheese, one of the most popular in Europe, comes from the buffaloes in Italy. Buffalo milk has a higher content of both butterfat and nonfat solids than cow's milk does. It therefore often brings higher prices than cow's milk. Throughout much of India it is in such demand that cow's milk is sometimes hard to sell.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of the misconceptions generally held about buffaloes are based on little data and much prejudice. For instance, it is widely believed that water buffalo meat is tough and less desirable than beef. However, when the animals are raised for meat, buffalo steaks are lean, as tender as beef, and in appearance it is difficult to distinguish the two. In taste-preference tests at the University of Queensland, buffalo steaks were preferred over those from Angus and Hereford cattle. Tests conducted in Trinidad, Venezuela, the United States, and Malaysia produced similar results.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Australia has shipped water buffalo meat to Hong Kong, the United States, Germany, and Scandinavia. Buffalo meat is now available in stores in Australia's Northern Territory, where demand exceeds supply. It sells at competitive prices and is particularly sought for barbecues and the famous Australian meat pie. In the Philippines, two-thirds of the meat consumed in homes and restaurants is actually water buffalo, a fact that many Filipinos do not realize.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Compared with cattle,waterbuffaloes apparently have an efficient digestive system, one which extracts nourishment from forage so coarse and poor that cattle do not thrive on it. Thin cattle are commonly seen in Asia and northern Australia, for example, but it's rare to see a protruding rib on a buffalo, even though it uses the same source of feed.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Asia, the Middle East, and Europe, water buffaloes live on coarse vegetation on the marginal land traditionally left to the peasants. They help make human survival possible. An old Chinese woman in Taiwan once told panelist W. Ross Cockrill: "To my family the buffalo is more important than I am. When I die, they'll weep for me; but if our buffalo dies, they may starve."  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A better understanding of the water buffalo could be invaluable to many developing nations. In particular, improved production of water buffalo meat offers hope for helping feed India, the second most populous nation on earth. Although India for religious reasons forbids the slaughter of cows, it has no prohibitions regarding slaughter of water buffaloes or the consumption of buffalo meat.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most developing countries are in the tropics, and the water buffalo is inherently a tropical animal. It is comfortable in hot, humid environments. In the Amazon, for example, buffaloes are now common on the landscape and may even replace cattle completely.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tropical countries have more serious disease problems than temperate countries do. Although susceptible to most cattle diseases, the water buffalo seems to resist ticks and often appears to be more resistant to some of the most devastating plagues that make cattle raising risky, difficult, and sometimes impossible in the tropics. Several researchers report that when water buffaloes are allowed to wallow, their mud-coated skin seems to deter insect and tick ectoparasites and they consequently require greatly reduced treatment with insecticides. Although the buffalo fly (Siphona exigua) affects the animals, other pests such as the warble fly and the screwworm, for example, seldom affect healthy buffaloes. AIso, despite their inclination for living in swamps, Avers, and ponds, diseases of the feet such as foot rot and foot abscesses are rare.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another benefit to developing countries is the water buffalo's legendary strength. A large part of the total farm power available in South China, Thailand, Indonesia, the Philippines, the Indochina states, India, and Pakistan comes from this "living tractor." Dependable and docile, the animals pull plows, harrows, and carts with loads that weigh several tons. In the Amazon buffalo teams pull boats laden with cargo and tourists through shallows and swamps.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The petroleum crisis has forced many farmers to reconsider animal power even in some of the technically advanced countries. Buffaloes are not only extraordinarily strong, they can also work in deep mud that may bog down a tractor. Even up to their bellies they forge on, dragging both plow and driver through the mud. Although its average walking speed is only about 3 kilometers per hour, the buffalo, unlike its mechanical competition, doesn't need gasoline or spare parts and its working life is often 20 years or more.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Breeds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As already noted, the major genetic divisions of the water buffalo are the Swamp buffalo of the eastern half of Asia, which has swept-back horns, and the River buffalo of the western half of Asia, which usually has curled horns. There is also the Mediterranean buffalo, which is of the River type but has been isolated for so long that it has developed some unique characteristics. (Records of the buffalo in Italy date back 1,000 years, during which there have been no reported imports.) Mediterranean buffaloes are stocky, high yielding animals that combine both beef and dairy characteristics.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there is only one breed of Swamp buffalo, certain subgroups seem to have specific inherited characteristics. For example, the buffaloes of Thailand are noted for their large size, averaging 450-550 kg, and weights of up to 1,000 kg have been observed. Elsewhere, Swamp buffaloes range from 250 kg for some small animals in China to 300 kg in Burma and 500-600 kg in Laos.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only in India and Pakistan are there well-defined breeds with standard qualities. There are eighteen River buffalo breeds in South Asia, which are further classified into five major groups designated as the Murrah, Gujarat, Uttar  Pradesh, Central Indian, and South Indian breeds. These are the five groups and  main breeds:  </P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=484>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<B><FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Group</B></FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<B><FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Breeds</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Murrah</FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Murrah, Nili/Ravi, Kundi</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Gujarat</FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Surti, Mehsana, Jafarabadi</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Uttar Pradesh</FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Bhadawari, Tarai</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Central Indian</FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Nagpuri, Pandharpun, Manda, Jerangi, Kalahandi, Sambalpur</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">South Indian</FONT></TD>
+<TD WIDTH="79%" VALIGN="TOP">
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY">Toda,  South Kanara</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The best-known breeds are Murrah, Nili/Ravl, Jafarabadi, Surti, Mehsana, and  Nagpuri. Most of the buffaloes of the Indian subcontinent belong to a nondescript  group known as the Desi buffalo. There is no controlled breeding among these  animals and most are quite small, yield little milk, and are variable in color.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Genetics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Swamp buffalo has 48 chromosomes, the River buffalo, 50. The chromosomal  material is, however, similar in the two types and they crossbreed to produce fertile  hybrid progeny. Cattle, however, have 60 chromosomes and although mating  between cattle and buffaloes is common, hybrids from the union are unlikely to  occur.( In 1965 a reputed hybrid was born at Askaniya Nova Zoopark in the Soviet Union  (see Gray, A., 1971. Mammalian Hybrids, Commonwealth Agricultural Bureaux,  Slough, England, p. 126). Hybrids have also been reported from China (Van  Fu-Czao 1959, Gibridy buivolc i krupnogo  i rogatogo skota(buffalo and  cattlehybrids)Zhivotnovodstro, Mosk., 21:92). Both of these reports seem doubtful  because despite many attempts, no other hybrids have ever been claimed to have  been produced). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Individual buffaloes show large variation in milk yield, conformation, horn shape,  color, meat production, temperament, growth rate, and other characteristics.  Selection for survival under adverse conditions has occurred naturally (those that  could not stand adversity died early) and farmers have probably tended to select  animals of gentle temperament. But systematic genetic improvement has almost  never been attempted. It seems likely that further selection could quickly improve  their productivity.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, the large bulls that would be best for breeding purposes are often  being selected as draft animals and castrated, or sent to slaughter, or (as with  some feral animals in northern Australia and on the Amazon island of Marajo) shot  by hunters. The result is that the buffalo's overall size in countries such as Thailand  and Indonesia has been decreasing as the genes for large size and fast growth are  lost.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Limitations  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The buffalo is still largely an animal of the village, and many of its reported  limitations are caused more by its environment than by the animal itself. Moreover,  much of the animal's genetic potential is obscured by environmental influences. For  example, for many breeds and types the genetic variations in milk yield and growth  cannot be accurately determined because they are overwhelmed by the effects of  inadequate nutrition and management.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, some inherent limitations of buffaloes can be identified. For instance,  buffaloes suffer if forced to remain, even for a few hours, in direct sunlight. They  have only one-tenth the density of sweat glands of cattle and their coating of hair is  correspondingly sparse, providing little protection from the sun. Accordingly,  buffaloes must not be driven over long distances in the heat of the day. They must  be allowed time for watering and, if possible, for wallowing. Driving under a hot sun  for long hours will cause heat exhaustion and possibly death; losses can be very  high and can occur suddenly. Young calves are particularly affected by heat.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes are also sensitive to extreme cold and seem less able than cattle to  adapt to truly cold climates(A rule of thumb is that buffaloes don't do well where the sun is inadequate to ripen,  say, cotton, grapes, or Ace. Kaleff, B., 1942. Der Hausbuffel und seine  Zuchtungsbiologie im Vergleich zum Rind. Zeitschsift Tierzucht Biologze,  51:131-178). Sudden drops in temperature and chill winds may lead  to pneumonia and death.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo is usually found m areas where there is ready access to a wallow  or shower. This is not a necessity, but when temperatures are high the availability of  water is important for maintaining buffalo health and productivity. It seems clear,  then, that the buffalo is not suitable for arid lands.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Increasing buffalo productivity through breed improvement is just now beginning.  Throughout Asia buffalo mating is almost completely haphazard, and so the animal  lacks the quality improvement through breeding that most cattle have had.  Therefore, most buffaloes are of nondescript heritage and genetic potential.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On poor quality feed water buffalo grow at least as well as cattle, but under intensive  conditions they probably won't grow as fast as the best breeds of cattle. In feedlots,  therefore, the buffalo is likely to be less productive than improved cattle. Weight  gains of about 1 kg per day have been recorded, some exceptional cattle may gain  at almost twice that rate.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The buffalo has long been considered a poor breeder-slow to mature sexually,  and slow to rebreed after calving. Accumulated experience now shows, however,  that this is mainly a result of poor management and nutrition. Buffaloes are not  sluggish breeders. Nevertheless, their gestation period is about a month longer  than that of cows, buffalo estrus is difficult to detect, and many matings occur~at  night so that~ farmers are likely to encounter more problems breeding buffaloes  than cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes are gentle creatures, but if roughly or inexpertly handled they can, through fear or pain, become completely unmanageable. Buffalo behavior sometimes differs from that of cattle. For example, most buffaloes are not trained to be driven. Instead, the herdsman must walk alongside or ahead of them; they then instinctively follow. Also, because of their innate attachment to an individual site or herd it is more difficult to move buffaloes to new locations or herds. In addition, buffaloes respect fences less than cattle do and when they have the desire to move they are harder to contain. (Electric fences, however, will stop them.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite their general good health, buffaloes are probably as susceptible as cattle to most infections. However, the buffalo seems to be peculiarly sensitive to a few cattle diseases and resistant to a few others (see chapter 7). Reactions to some diseases seem to vary with region, environment, and breed, and the differences are not well understood.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Destruction of the environment is sometimes attributed to buffalo wallowing. This danger seems to have been overstated, except in cases where stocking rates were unreasonably high.(An ongoing study in Northern Australia of environmental degradation widely attributed to buffalo has now shown that the effects are caused by man and climatic changes and only very slightly by buffaloes. (information supplied by D. G. Tulloch.) ) However, buffaloes rub against trees more often than cattle do, and they sometimes de-bark the trees, causing them to die.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, some of the best genetic stocks of water buffaloes exist in areas where certain infections and viral and other diseases sometimes occur. Thus, many countries are reluctant to permit importation of water buffaloes, despite the fact that modern quarantine procedures under conditions of maximum security can essentially eliminate the risk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, it must be emphasized that because buffalo research has been largely neglected, most results reported in this and other buffalo writings cover small numbers of animals and short periods of time. Many are merely empirical observations that have not been subjected to independent confirmation.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anonymous. 1972.Buffalo at the crossroads. World Farming 14(n:l0-l3.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asian and Pacific Council. 1979. Priorities in buffalo research identified.ASPAC News letter No. 43.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bowman, J. c. 1977. Animals for Man. Edward Arnold Publishers, Ltd., London, United Kingdom.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo Bulletin. Newsletter published by the Buffalo Research Committee of Kasetsart University, Bangkok' Thailand. (In English and Thai.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo World. Newsletter published by the National Dairy Research Institute, Karnal, 132001, Haryana, India.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chantalakhana, C. 1975. The buffaloes of Thailand-their potential, utilization and conservation. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chantalakhana, C., and Na Phuket, S. R. 1979. The role of swamp buffalo in small farm development and the need for breeding improvement in Southeast Asia. Extension Bulletin No. 125. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1967. The water buffalo. Scientific American 217:118.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R., ed. 1974. The Husbandry and Health of the Domestic Buffalo. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill W. R. 1975. The domestic buffalo. Blue Book for the Veterinary Profession No. 25. Animal Production and Health Division, Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1976. The Buffaloes of China. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R., ed. 1977. The Water Buffalo. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1977. The water buffalo: domestic animal of the future. Bovine Practitioner 12:92-98.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1978. Domestic water buffaloes. In: The Care and Management of Farm Animals, edited by W. N. Scott. Bailliere TindaU, London, United Kingdom.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1980. The ascendant water buffalo-key domestic animal. World Animal Review 33:2-13.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DeBoer, A. J. 1972. Technical and economic constraints on bovine production in three villages in Thailand. Dissertation Abstracts International 33(5):1935.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DeBoer, A. J. 1975. Livestock and Poultry Industry in Selected Asian Countries. Report of Survey on Diversification of Agriculture: Livestock and Poultry Production. Asian Productivity Organization, Tokyo, Japan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">de Guzman, M. R., Jr. 1979. An overview of recent developments in buffalo research and management in Asia. Extension Bulletin No. 124. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Documentation Center on Water Buffalo. 1978. Abstract Bibliography on Water Buffalo, 1971-1975. Documentation Center on Water Buffalo, University of the Philippines at Los Banos Library, College, Laguna 3720, Philippines.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fahimuddin, M. 1975. Domestic Water Buffalo. Oxford and IBH Publishing Company, New Delhi, India  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fischer, H. 1975. The water buffalo and related species as important genetic resources: their conservation, evaluation and utilization. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6  1975. Food and Fertilizer Technology Center, Taipei, Taiwan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ford, B. D., and Tulloch, D. G. 1977. The Australian buffalo-a collection of papers. Technical Bulletin No.18. Department of the Northern Territory, Animal Industry and Agriculture Branch, Australian Government Publishing Service, Canberra, Australia.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gupta, H. C. 1977. Possibilities and realities of developing buffalo's performance, breeding and feeding. Indian Dairyman 29(6):337-346.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kartha, K. P. R.1965. Buffalo. In: An Introduction to Animal Husbandry in the Tropics edited by G. Williamson and W. J. A. Payne. Longman, London, United Kingdom.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">McKnight, T. L. 1971. Australia's buffalo dilemma. Annals of the Association of American Geographers 61(4):759-773.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madamba, J. C., and Eusebio, A. N. 1979. Developments in the strengthening of buffalo research in Asia. Buffalo Bulletin 2(3):7-16.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mahadevan, P. 1978. Water buffalo research-possible future trends. World Animal Review 25: 2-7.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oloufa, M. M. 1979. Buffaloes as producers of meat and milk. Egyptian Journal of AnimalProduction 19:1-10. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pant, H. C., and Roy, A. 1972. The water buffalo and its future. In: Improvement of Livestock Production in Warm Climates, edited by R. E McDowell. W. H. Freeman and Company, San Francisco, California, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Philippine Council for Agriculture and Resources Research. 1978. The Philippines Recommends for Caraboo Production, PCARR, Los Banos, Laguna 3732, Philippines.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ranjhan, S. K., and Pathak, N. N. 1981. Management and Feeding of Buffaloes. Vikas Publishing House, New Delhi, India  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robinson, D. W. 1977a. Livestock in Indonesia. Research Report No. 1. Centre for Animal Research and Development, Bogor, Indonesia. (In English and Indonesian.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robinson, D. W. 1977b. Preliminary Observations on the Productivity of Porking Buffalo in Indonesia. Research Report No. 2. Centre for Animal Research and Development, Bogor, Indonesia. (In English and Indonesian.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sundaresan, D. 1979. The role of improved buffaloes in rural development. Indian Dairyman 31(2):73-78.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1978. The water buffalo, Bubalus bubalis, in Australia: grouping and home range.Australian Wildlife Research 5:327-34.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wahid, A. 1973. Pakistani buffaloes. World Animal Review 7:22~28. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">2 Meat</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo offers promise as a major source of meat, and the production of buffaloes solely for meat is now expanding.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because buffaloes have been used as draft animals for centuries, they have evolved with exceptional muscular development, some weigh 1,000 kg or more. Until recently, however, little thought was given to using them exclusively for meat production. Most buffalo meat was, and still is, derived from old animals slaughtered at the end of their productive life as work or milk animals. As a result, much of the buffalo meat sold is of poor quality. But when buffaloes are properly reared and fed, their meat is tender and palatable.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are exported for slaughter from India and Pakistan to the Middle East and from Thailand and Australia to Hong Kong. Demand for meat is so great that Thailand's buffalo population has dropped from 7 million to 5.7 million head in the last 20 years, a period in which the human population has more than doubled.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Carcass Characteristics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All buffalo breeds-even the milking ones-produce heavy animals whose carcass characteristics are similar to those of cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite heavier hide and head, the amount of useful meat (dressing percentage) from buffaloes is almost the same as in cattle. Mediterranean type buffalo and Zebu cattle steers in Brazil yielded dressing percentages of 55.5 and 56.6 percent respectively. Swamp buffalo dressing percentages have been measured in Australia at 53 percent. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes are lean animals. Although a layer of subcutaneous fat covers the carcass, it is usually thinner than that on comparably fed cattle. Even animals that appear to be fat prove to be largely muscle. Australian research on Swamp buffaloes reveals that buffaloes with more than 25 percent fat are difficult to produce, whereas average choice-grade beef carcasses may contain  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In general, the buffalo carcass has rounder ribs, a higher proportion of muscle, and a lower proportion of bone and fat than beef has.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo hide is so thick that it can be sliced into two or three layers before tanning into leather.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Meat Quality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo meat and beef are basically similar. The muscle pH (5.4), shrinkage on chilling (2 percent), moisture (76.6 percent), protein (19 percent), and ash (1 percent) are all about the same in buffalo meat and beef. Buffalo fat, however, is always white and buffalo meat is darker in color than beef because of more pigmentation or less intramuscular fat (2-3 percent "marbling," compared with the 3-4 percent in beef).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Eating Quality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taste-panel tests and tenderness measurements conducted by research teams in a number of countries have shown that the meat of the water buffalo is as acceptable as that of cattle. Buffalo steaks have rated higher than beefsteaks in some taste tests in Australia, Malaysia, Venezuela, and Trinidad.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In taste-panel studies in Trinidad, cooked joints from three carcasses Trinidad buffalo, a crossbred steer (Jamaica-Red/Sahiwal), and an imported carcass of a top-grade European beef steer-were served. The 28 diners all had experience in beef production, butchery, or catering and were not told the sources of the various joints. All the carcasses were held in cold storage for one week before cooking. The buffalo meat was rated highest by 14 judges; 7 chose the European beef; 5 thought the crossbred beef the best; and 2 said that the buffalo and crossbred were equal to or better than the European beef. The buffalo meat received most points for color (both meat and fat), taste, and general acceptability. There was little difference noted in texture.( Information supplied by P. N. Wilson.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo veal is considered a delicacy. Calves are usually slaughtered for veal between 3 and 4 weeks of age; dressed weight is 59-66 percent of live weight.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is some evidence that buffaloes may retain meat tenderness to a more advanced age than cattle because the connective tissue hardens at a later age or because the diameter of muscle fibers in the buffalo increases more slowly than in cattle(Joksimonc, 1979) In one test the tenderness (measured by shearing force) of muscle samples from carcasses of buffalo steers 16-30 months old was the same as that from feedlot Angus, Hereford, and Friesian steers 12-18 months old. This gives farmers more flexibility in meeting fluctuating markets while still providing tender meat.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anonymous. 1976. Livestock Production in Asian Context of Agricultural Diversification. Asian Productivity Organization, Tokyo, Japan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arganosa, F. C., Sanchez, P. C., Ibarra, P. I., Gerpacio, A. L., Castillo, L. S., and Arganosa, V. G. 1973. Evaluation of carabeef as a potential substitute for beef. Philippine Journal of Nutrition 26(2).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arganosa, F. C., Arganosa, V. G., and Ibarra, P. I. 1975. Carcass evaluation and utilization of carabeef. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bennett, S. P. 1973. The "buffalypso"-an evaluation of a beef type of water buffalo in Trinidad, West Indies. Paper presented at the Third World Conference on Animal Production, Melbourne, Australia.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Borghese, A., Gigli, S., Romita, A., Di Giacomo, A., and Mormile, M. 1978. Fatty acid composition of fat in water buffalo calves and bovine calves slaughtered at 20, 28, and 36 weeks of age. In: Patterns of Growth and Development in Cattle: A Seminar in the EEC Programme of Coordination of Research on Beef Production, held at Ghent, October 11-13,1977. Martinus Nijhoff, The Hague, Netherlands.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles, D. D., and Johnson, E. R. 1972. Carcass composition of the water buffalo (Bubalus bubalis). Australian Journal of Agriculture Research 23:905-911.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles, D. D., and Johnson, E. R. 1975. Live weight gains and carcass composition of buffalo (Bubalus bubalis) steers on four feeding regimes. Australian Journal of Agriculture Research 26:407-413.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1975. Alternative livestock: with particular reference to the wafer buffalo (Bubalus bubalis). In: Meat. Proceedings of the 21st Easter School in Agricultural Science, University of Nottingham, edited by D. J. A. Cole and R. A. Lawrie. Butterworth, London, England.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">El-Ashry, M. A., Mogawer, H. H., and Kishin, S. S. 1972. Comparative study of meat production from cattle and buffalo male calves. Egyptian Journal of Animal Production 12:99-107.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">El-Koussy, H. A., Afifi, Y. A., Dessouki, T. A., and El-Ashry, M. A. 1977. Some chemical and physical changes of buffalo meat after slaughter. Agriculture Research Review 55:1-7.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Johnson, E. R., and Charles, D. D. 1975. Comparison of live weight gain and changes in carcass composition between buffalo (Bubalus bubalis) and Bos taurus steers. Australian Journal of Agriculture Research 26:415- 422.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joksimovic, J. 1979. Physical, chemical and structural characteristics of buffalo meat. Arhiv za Polloprivredne Nauke 22:110.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joksimovic, J., and Ognjanovic, A. 1977. A comparison of carcass yield, carcass composition, and quality characteristics of buffalo meat and beef Meat Science 1:105 -110.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mai, S. C., and Wu, T. H. 1974. TSC's intensive feed-lot system for cow-calf and beef production program. Taiwan Sugar 21(6):198-211.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Matassino, D., Romita, A., Cosentino, E., Girolami, A., and Cloatruglio, P. 1978. Myorheological, ohemical, and colour characteristics of meat in water buffalo and bovine calves slaughtered at 20, 28 and 36 weeks. In: Patterns of Growth and Development in Cattle: A Seminar in the EEC Programme of Coordination of Research on Beef Production, held at Chent, October 11-13, 1977. Martinus Nijhoff, The Hague, Netherlands.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mogawer, H. H., El-Ashry, M. A., and Mahmoud, S. A. 1976. Comparative study of meat production from cattle and buffalo male calves. II. Effect of different roughage concentrate ratios in ration on carcass traits. Journal of Agriculture Research {Tanta University) 2:6-12.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ognjanovic, A. 1974. Meat and meat production. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. CockrilL Food and Agriculture Organization of the United Nations, Rome, Italy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rastogi, R., Youssef, F. G., and Gonzalez, F. D. 1978. Beef type water buffalo of Trinidad-Beefalypso. World Review of Animal Production 14(2) :49 -56.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Romita, A., Borghese, A., Gigli, S., and Di Giacomo, A. 1978. Growth rate and carcass composition of water buffalo calves and bovine calves slaughtered at 20, 28 and 36 weeks. In: Patterns of Growth and Development in Cattle: A Seminar in the EEC Programme of Coordination of Research on Beef Production, Held at Chent, October 11-13, 1977. Martinus Nijhoff, The Hague, Netherlands.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wilson, P. N. 1961. Palatability of water buffalo meat. Journal of the Agricultural Society of Trinidad 61:457, 459-460. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">3 Milk</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than 5 percent of the world's milk comes from water buffaloes. Buffalo milk is  used in much the same way as cow's milk. It is high in fat and total solids, which  gives it a rich flavor. Many people prefer it to cow's milk and are willing to pay more  for it. In Egypt, for example, the severe mortality rate among buffalo calves is due in  part to the sale of buffalo milk, which is in high demand, thus depriving calves of  proper nourishment. This also occurs in India, where in the Bombay area alone an  estimated 10,000 newborn calves starve to death each year through lack of milk.  The demand for buffalo milk in India (about 60 percent of the milk consumed; over  80 percent in some states) is reflected in the prices paid for a liter of milk: about  130 paisa for cow's milk compared with about 200 paisa for buffalo milk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Twelve of the 18 major breeds of water buffalo are kept primarily for milk production  (although males may be used for traction and all animals are eventually used for  meat). The main milk breeds of India and Pakistan are the Murrah, Nili/Ravi, Surti,  Mehsana, Nagpuri, and Jafarabadi. The buffaloes of Egypt, Eastern Europe  (Bulgaria, Romania, Yugoslavia, and the USSR), and Italy are used for milk  production and there are also herds used principally for this purpose in Iran, Iraq,  and Turkey.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Composition</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo milk contains less water, more total solids, more fat, slightly more lactose,  and more protein than cow's milk. It seems thicker than cow's milk because it  generally contains more than 16 percent total solids compared with 12-14 percent  for cow's milk. In addition, its fat content is usually 50-60 percent higher (or more)  than that of cow's milk. Although the butterfat content is usually 6-8 percent,( An analysis of 7,770 records of Nili/Ravi buffaloes in herds at the Pakistan  Research Institute showed that average butterfat content was 6.40 (a mean based  on 10 tests over 10 months). of all the samples tested, 77 percent ranged between  5 and 8 percent butterfat and 12 percent were below 5 percent butterfat.  -information supplied by R. E. McDowell.)  it can  go much higher in the milk of some well fed dairy buffaloes and in the milk of  Swamp buffaloes (which are not normally used for milking). Cow's milk butterfat content is usually between 3 and 5 percent.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of its high butterfat content, buffalo milk has considerably higher energy value than cow's milk. Phospholipids are lower but cholesterol and saturated fatty acids are higher in buffalo milk. Studies have shown that digestibility is not adversely affected by this. Because of the high fat content, the buffalo's total fat yield per lactation compares favorably with that of improved breeds of dairy cattle; it is much higher than that of indigenous cows.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Normally the protein in buffalo milk contains more casein and slightly more albumin and globulin than cow's milk. Several researchers have claimed that the biological value of buffalo milk protein is higher than that of cow's milk, but this has not yet been proved conclusively.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p27.png"></center><br>
+ Tables 1 and 2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mineral content of buffalo milk is nearly the same as that of cow's milk except for phosphorus, which occurs in roughly twice the amount in buffalo milk. Buffalo milk tends to be lower in salt.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo milk lacks the yellow pigment carotene, precursor for vitamin A, and its whiteness is frequently used to differentiate it from cow's milk in the market. Despite the absence of carotene, the vitamin A content in buffalo milk is almost as high as that of cow's milk. (Apparently the buffalo converts the carotene in its diet to vitamin A. The two milks are similar in B complex vitamins and vitamin C, but buffalo milk tends to be lower in riboflavin.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Milk Products</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo milk, like cow's milk, can provide a wide variety of products: butter, butter oil (clarified butter or ghee), soft and hard cheeses, condensed or evaporated milks, ice cream,yogurt, and buttermilk. It is of great economic importance in India in preparing "toned" milk-a mixture of buffalo milk and milk made by reconstituting skim milk powder.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The richness of buffalo milk makes it highly suitable for processing. To produce 1 kg of cheese, a cheese maker requires 8 kg of cow's milk but only 5 kg of buffalo milk. To produce 1 kg of butter requires 14 kg of cow's milk but only 10 kg of buffalo milk. Because of these high yields, processors appreciate the value of buffalo milk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo cheese is pure white. It many countries it is among the most desirable cheeses (mozzarella and ricotta in Italy, gemir in Iraq, the salty cheeses of Egypt, and pecorino in Bulgaria, for example). In Venezuela all the cheese produced from the small La Guanota milking herd in the Apure River basin (about 100 kg a day) is bought by the Hilton Hotel and sells for 15 bolivars per kg compared with 8 bolivars per kg for cheese made from cow's milk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although much in demand for making soft cheese, buffalo milk is less desirable for making hard cheeses such as cheddar or gouda. During cheesemaking it produces acid more slowly than cow's milk, retains more water in the curd, and loses more fat in the whey.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cheeses are becoming increasingly popular throughout the world. Demand is rising at a rate that is among the highest for any food product. Cheese offers particular benefit to areas where refrigeration is not widely available, where transporting high-protein foods to remote areas is difficult, and where seasonal fluctuations affect milk supplies. Buffalo milk may make cheesemaking profitable on an even smaller scale than conventional dairying; it is more concentrated than cow's milk and requires relatively less energy to transport and process (an increasingly important factor where fuels are limited).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p31.png"></center><br>
+ Table 3 Highest Milk Yield (kg per Day) Recorded in the All India Milk Yield</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Yield</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In countries like India and Egypt, the milk yield of buffaloes is generally higher  (680-800 kg) than for local cattle (360-500 kg). However, since selection for  exceptional milk production is not conducted systematically, large variations in yield  occur between individual animals, and milk production of dairy buffaloes falls short  of its potential.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nonetheless, some outstanding yields have been recorded. On Indian government  farms, average yields for milking buffaloes range from 4 to 7 kg per day in  lactations averaging 285 days. Daily yields of 12 kg have been reported for some  Bulgarian buffalo cows and a daily production of over 20 kg has been reported for  some remarkable animals in India. A peak milk yield of 31.5 kg in a day has been  recorded from a champion Murrah buffalo in the All India Milk Yield Competition  conducted by the Government of India (see Table 3).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At Caserta, Italy, a herd of 1,600 machine-milked, pedigreed dairy buffaloes has  produced average yields of 1,500 kg during lactations of 270 days. In Pakistan an  analysis of over 6,000 lactations of Nili/Ravi buffalo cows showed an average yield  of 1,925 kg during lactations averaging 282 days(Average adjusted for year and  season and calving. Cady et al., in press.) . In India the average milks yield of  Murrah buffaloes in established herds is also reported to be about  1,800kg(*"Williamson and Payne, 1965.)Table 4 lists some outstanding lactation  yields reported from different parts of the world. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As with cattle, the percentages of fat, protein, and total solids decrease as the milks yield increases.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Swamp buffaloes of Southeast Asia are usually considered poor milk producers. They are used mainly as draft animals, but it may be that their milk potential has been underestimated. In the Philippines Swamp buffalo cows with nursing calves have produced 300-800 kg of milk during lactation periods of 180-300 days(*Philippines Council for Agriculture and Resources Research (PCARR). 1978. The Philippines Recommends for Caraboo Production, PCARR, Los Banos, Philippines)In Thailand Swamp buffaloes selected and reared for milk production have yielded 3-5 kg per day during 305-day lactations.(Information supplied by Charan Chantalakhana.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p32.png"></center><br>
+ Table 4 Milk Production of Some Outstading Buffalo Cows and Dairy Herds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Nanning Livestock Research Institute and Farm in Kwangsi Province,which is representative of many others in South China, is upgrading the native  Swamp buffaloes (or Shui Niu) by selective breeding for size and weight and by  crossbreeding with dairy breeds such as the Murrah and Nili/Ravi. The crossbreeds  that are milked yield 4-5 kg daily.(*CockriH, W. R. 1976. The Buffaloes of China.  FAO, Rome.) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">  </P>
+<P ALIGN="JUSTIFY">Dairy Management</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The characteristics of the dairy buffalo so closely approximate those of the dairy cow that successful methods of breeding, husbandry, and feeding for  milks production for the cow can be applied equally to the dairy buffalo. Buffaloes,  however, have not been bred for uniform udders and it is more difficult to milk them  by machine.(Some thousands of buffaloes are machine milked in Bulgaria and Italy, however. At  Ain Shams University in Egypt, buffaloes have adapted to machine milking. The  calves are separated from their dams immediately after birth and no problems of  milk letdown have been observed. -information supplied by M. El Ashry.)Also, some buffaloes have more of a problem with milks letdown than  dairy cows (although not as much of a problem as some native cattle breeds in the  tropics). Frequently, a calf is kept with the cow and is tied to her foreleg at milking  time. In India, Burma, and other countries a dummy calf may be provided; playing  music seems to work, too.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Addeo, F., Mercier, J. C., and Ribadeau-Dumas, B. 1977. The caseins of buffalo  milk. Journal of Dairy Research 44(3):455-468.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agarwala, O. P. 1962. Certain factors of reproduction and production in a water  buffalo herd. Indian Joumal of Dairy Science 15(2):45-51.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Albourco, F., Mincione, B., Addeo, F., and Ameno, M. 1969. Buffaloes' milk. II.  Variations in composition during lactation of milk produced without change in  feeding. Industrie Agraria 7(5):210-219.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associazione Italiana Tecnici del Latter. 1970. Buffaloes' milk and cheese. Scienza  e Tecnica 21(3):175-196.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhatnagar, V. K., Lohia, K. L., and Monga, O. P. 1961. Effect of the month of  calving on milk yield, lactation length and calving interval in Murrah buffaloes. Indian  Journal of Dairy Science 14(3): 102-108.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhasin N. R., and Desai, R. N. 1967. Effect of age at first calving and first lactation  yield on life time production in Hariana cattle. Indian Veterinary Journal 44:684694.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cady, R. A., Shah, S. K., Schermerhorn, E. C., and McDowell, R. E. In Press.  Factors affecting performance of Nili-Ravi buffaloes in Pakistan. Journal of Dairy  Science.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Castillo, L. S. 1975. Production, characteristics and processing of buffalo milk. In:  The Asiatic Water Buffalo. Proceedings of an International Symposium held at  Khon Kahn, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology  Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dassat, P. M., de Paolis, P., and Sartore, G. 1966. Environmental effects on milks  yield in Italian buffalo.Acta Medica Veterinaria 12(6):587-593.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dave, B. K., and Taylor, C. M. 1975. A study on relationship of persistency with other first production traits in Indian water buffaloes. Indian Journal of Animal Health 14(1) :77-80.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Deshmukh, S. N., and Choudhury, P. N. R. 1971. Repeatability estimates of some economic characteristics in Italian buffaloes. Zentralblatt fuer Veterinaer-medizen 18:104-107.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ganguli, N. C. 1979. Buffalo milk technology. World Animal Review 30:2-10.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gomez, I. V. 1977. The manufacture of semihard cheese (Danish type) from carabao milk. Philippine Agriculturalist 61(3/4) :78-86.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gurnani, M., and Nagarcenkar, R. 1971. Evaluation of breeding performance of buffaloes and estimation of genetic and phenotypic parameters. Annual Report of the National Dairy Research Institute, Karnal, India.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Katpatal, B. G. 1977. Dairy cattle crossbreeding in India. I. Growth and development of crossbreeding. World Animal Review 22: 15-21.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kay, H. D. 1974. Milk and milk production. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kohli, M. L., and Malik, D. D. 1960. Effect of service period on total milk production and lactation length in Murrah buffaloes. Indian Journal of Dairy Science 13(3): 105-111.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nascimento, C. N. B., Moura Carvalho, L. O. D., and Lourenco, J. B. 1979. Irnportancia do Bufalo para a Pecuarfa Brasileira. Agricultural Research Center for Humid Tropics (CPATU), Belem, Para, Brazil.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raafat, M. A., El-Sayed, Abou-Hussein, Abou-Raya, A. K., and El-Shirbiny A. 1974. Some nutritional studies of colostrum and milk of cows and buffaloes E:gyptian Journal of Animal Production 14(1) :137-148.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ragab, M. T., Asker, A. A., and Kamal, T. H. 1958. The effect of age and seasonal calving on the composition of Egyptian buffalo milk. Indian Journal of Dairy Science 11(1):18-28.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Saudi Arabia Standards Institution. 1978. Raw milk. Saudi Arabia Standard 98.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sebastian, J., Panthulu, P. C, and Bhimasena, M. 1971. Composition of Surti buffalo milk. Annual Report of the National Dairy Research Institute, Karnal, India.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sekhon, G. S., and Gehlon, M. S. 1966. Repeatability estimates of some economic traits in the Murrah buffalo. Ceylon Veterinary Journal 14:18-22.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, B. B., and Singh, B. P. 1971. Comparative study of lifetime economics of Hariana versus Murrah buffaloes. Indian Veterinary Journal 48:485-489.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, R. P. 1966. A study of production up to ten years of age in buffaloes maintained at military farms. Indian Veterinary Journal 43:986-992.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, S. B., and Desai, R. N. 1962. Production character of Bhadawari buffalo cow. Indian Veterinary journal 39:332-343.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Venkayya, D., and Anantakrishnan, C. P. 1957. Influence of age at first calving on the performance of Murrah buffaloes. Indian Journal of Dairy Science 10(1):20-24.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Williamson, G., and Payne, W. J. A. 1965. An Introduction to Animal Husbandry in the Tropics. Longman, London, United Kingdom. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">4 Work</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo is the classic work animal of Asia, an integral part of that  continent's traditional village farming structure. Probably the most adaptable and  versatile of all work animals, it is widely used to plow; level land; plant crops; puddle  rice fields; cultivate field crops; pump water; haul carts, sleds, and shallow-draft  boats; carry people; thresh grain; press sugar cane; haul logs; and much more.  Even today, water buffaloes provide 20-30 percent of the farm power in South  China, Thailand, Indonesia, Malaysia, Philippines, and Indochina(Figures provided by A. J. de veer. In India water buffaloes contribute much less to  farm power (6-12 percent); bullocks are more commonly used. In Pakistan  buffaloes are little used for farm power (1-2 percent) but provide much of the road  haulage. Papua New Guinea has no tradition of using any work animal, but villagers  are increasingly using buffaloes for farm work and the government is employing  Fillipinos to train them) . Millions of  peasants in the Far East, Middle East, and Near East have a draft buffalo. For them  it is often the only method of farming food crops.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As fuel becomes scarce and expensive in these countries, the buffalo is being used  more frequently as a draft animal. ln 1979 water buffalo prices soared in rural  Thailand because of the increased demand.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although Asian farms have increasingly mechanized in the last 20 years, it has  often proved difficult to persuade the farmer to replace his buffalo with a tractor  since the buffalo produces free fertilizer and does not require diesel fuel. Now there  is renewed official interest in draft power. Sri Lanka has recently opened up large  new tracts of farmland in the Mahawali Valley, creating such a demand for work  animals that buffalo shortages have become a national development problem.  Indonesia's transmigration schemes are also handicapped by shortages of animal  power.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For many small farmers the buffalo represents capital. It is often the major  investment they have. Buffalo energy increases their productivity and allows them to  diversify. Even small farms have work animals that, like the farmer himself, subsist  off the farm. Tractors usually require at least four hectares for economical operation,  which precludes their use on most peasant farms. Further, the infrastructure to  maintain machinery is often not readily available.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes are also used for hauling. Buffalo-drawn carts carry goods between  villages where road surfaces are unfit for trucks. The animals easily traverse  ravines, streams, paddies, and narrow and rocky trails. In the cities carts can  compete economically with trucks where the road surface is unprepared, where  loading or unloading takes longer than the journey itself, or where the loads are too  small and distances too short to make trucking economical. For road haulage  buffaloes are generally shod: the shoes are flat plates fitted to each hoof.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Capacity for Work</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo is a sturdy draft animal Its body structure, especially the  distribution of body weight over the feet and legs, is an important advantage. Its  large boxy hooves allow it to move in the soft mud of rice fields. Moreover, the  buffalo has very flexible pastern and fetlock joints in the lower leg so that it can bend  back its hooves and step over obstacles more easily than cattle. This water-loving  animal is particularly well adapted to paddy farming because its legs withstand  continual wet conditions better than mules or oxen(Australian animal scientists working in Bogor, Indonesia, found that the puddling  effect of buffalo hooves on the soil was critical for rice cultivation in the local soils.  Tractors produced fields so porous that they drained dry. (Information supplied by  A. F. GurnettSmith.) On one research station near Darwin, Australia, buffaloes were  used to prevent water draining from a dam. (Information supplied by D. G. Tulloch.). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although buffaloes are preferred by farmers in the wet, often muddy lowlands of  Asia, mules, horses, and cattle move more rapidly and are preferred in the dryer  areas.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes do not work quickly. They plod along at about 3 km per hour. In  most parts of Southeast Asia they are worked about 5 hours a day and they may  take 6-10 days to plow, harrow, and grade one hectare of rice field. Their stamina  and drawing power increase with body weight.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because they have difficulty keeping cool in hot, humid weather (see next chapter),  it is necessary to let working buffaloes cool off, preferably in a wallow, every 2 hours  or so. Without this their body temperatures may rise to dangerous levels.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A pair of 3-year-old buffaloes costs about the same as a small tractor in Thailand.  But many farmers raise their own calves and there is no investment beyond labor.  The "fuel" for the animals comes mainly from village pastures and farm wastes such  as crop stubble and sugarcane tops. Buffaloes have an average working life of  about 11 years, but some work to age 20.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">  </P>
+<P ALIGN="JUSTIFY">Harness</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The yoke used on working buffalo in Asia has changed very little in the last 1,500 years. It is doubtful that a working buffalo can exert its full power with it. The hard wooden yoke presses on a very small area on top of the animal's neck, producing severe calluses, galls, and obvious discomfort. The harness tends to choke the animal as the straps under the neck tighten into the windpipe. Since the traditional hitch is usually higher than the buffalo's low center of gravity, the animal cannot pull efficiently. Considerably more pulling power and endurance can be obtained by improving the harness. The situation is not unlike that in Western agriculture in the twelfth century when the horse collar-one of the most important inventions of the Middle Ages first appeared. Before that, horses were yoked like buffalo and the harness passed across their windpipes and choked them as they pulled. Use of the horse collar improved pulling efficiency and speeded the development of transportation and trade.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The curved yoke now universally used on water buffalo contacts an area of the neck that is only about 200 cm2 (little more than half the size of this page). The entire load is pulled on this small area and causes the wood to dig into the flesh.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A horse collar is a padded leather device that encircles the animal's neck. One modified in Thailand for use on water buffalo (see page 43) had a contact area of 650 cm2, more than three times that of the yoke it replaced. The collar's padding pressed against the animal's shoulders, not its neck, and  therefore did not choke it. Attached to the collar were wooden hames with the traces for hitching the animal to a wagon or plow. In trials a buffalo pulled loads 24 percent heavier with the collar than with the yoke, and the horsepower it developed increased by 48 percent(These trials were conducted by J. K. Garner in Thailand in 1958. In the maximum-load test the yoked buffalo failed to move a load of 570 kg, but it moved a load of 640 kg when fitted with the horse collar. In an endurance test the yoked animal took 35 minutes to pull a load 550 m, but harnessed with the collar it took only 21 minutes). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another potentially valuable harness is the breast strap, a set of broad leather straps that pass over the animal's neck and back. One breast strap modified for water buffalo use had a contact area of 620 cm2, almost as much as that of the horse collar, and in trials the buffalo pulled a load 12 percent heavier than with a yoke and the horsepower it developed increased by almost 70 percent( The same animal used in the horse collar trials pulled 700 kg with the breast strap, in the endurance test it took 18.5 minutes to travel the 550-m distance). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These seem very good innovations. In the humid tropics, however, leather collars and breast straps may decay rapidly. To make them widely practical may require experimentation with, or development of, special leather treatments or more durable materials.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1974. The working buffalo. In: The Husbandry and Health of the Domes tic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1976. The Buffaloes of China. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">de Guzman, M. R., Jr. 1975. The water buffalo-Asia's beast of burden and key to progress. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Garner, J. K. 1958 (Reprint 1980) Increasing the Work Efficiency of the Water Buffalo Through Use of Improved Harness. (Copies available from Office of Agriculture, Development Support Bureau, Agency for International Development, Washington, D.C. 20523)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kamal, T. H., Shehata, O., and Elbanna, I. M. 1972. Isotope Studies on the Physiology of Domestic Animals. International Atomic Energy Agency, Vienna, Austria.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robinson, D. W. 1977. Preliminary Observations on the Productivity of Working Buffalo in Indonesia. Research Report No. 2, Center for Animal Research and Development, Bogor, Indonesia.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vaugh, M. 1945. Report on a detailed study of methods of yoking bullocks for agricultural work. Indian Journal of Veterinary Science 15:186-198.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ward, G. M., Sutherland, T. M., and Sutherland, J. M. 1980. Animals as an energy source in Third World agriculture. Science 208:570. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">5 Adaptability and Environmental Tolerance</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Heat Tolerance</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the buffalo is remarkably versatile, it has less physiological adaptation to extremes of heat and cold than the various breeds of cattle. Body temperatures of buffaloes are actually lower than those of cattle, but buffalo skin is usually black and heat absorbent and only sparsely protected by hair. Also, buffalo skin has one-sixth the density of sweat glands that cattle skin has, so buffaloes dissipate heat poorly by sweating. If worked or  driven excessively in the hot sun, a buffalo's body temperature, pulse rate, respiration rate, and general discomfort increase more quickly than those of cattle(Failure to appreciate this has caused many buffalo deaths in northern Australia when the animals were herded long distances through the heat of the day as if they were cattle).. This is particularly true of young calves and pregnant females. During one trial in Egypt 2 hours' exposure to sun caused temperatures of buffalo to rise 1.3°C, whereas temperatures of cattle rose only 0.2-0.3°C.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes prefer to cool off in a wallow rather than seek shade. They may wallow for up to 5 hours a day when temperatures and humidity are high. Immersed in water or mud, chewing with half-closed eyes, buffaloes are a picture of bliss.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In shade or in a wallow buffaloes cool off quickly, perhaps because a black skin rich in blood vessels conducts and radiates heat efficiently (Tests at the University of Florida have shown that buffaloes in the shade cool off more quickly than cattle. -Robey, 1976).  Nonetheless, wallowing is not essential. Experience in Australia, Trinidad, Florida, Malaysia, and elsewhere has shown that buffaloes grow normally without wallowing as long as adequate shade is available.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Cold Tolerance</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although generally associated with the humid tropics, buffaloes, as already noted, have been reared for centuries in temperate countries such as Italy, Greece, Yugoslavia, Bulgaria, Hungary, Romania, and in the Azerbaijan and Georgian republics of the USSR. In 1807 Napoleon brought Italian buffaloes to the Landes region of southwest France and released them near Mont-deMarsan. They became feral and multiplied prodigiously in the woods and dunes of the littoral, but unfortunately the local peasants found them easy targets, and with the fall of Napoleon the whole herd was killed for meat(In the twelfth century Benedictine monks introduced buffaloes from their possessions in the Orient to work the lands of their abbey at Auge in northeastern France. In the thirteenth century a herd was introduced to England by the Earl of Cornwall, the brother of Henry III. Nothing is known about how well either herd survived). Buffaloes are also maintained on the high, snowy plateaus of Turkey as well as in Afghanistan and the northern mountains of Pakistan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The buffalo has greater tolerance of cold weather than is commonly supposed. The current range of the buffalo extends as far north as 45° latitude in Romania and the sizable herds in Italy and the Soviet Union range over 40° N latitude(Philadelphia and Peking are at comparable latitudes. In the Southern Hemisphere the 40° line of latitude easily encompasses Cape Town, Buenos Aires, Melbourne, and most of New Zealand's North Island).  Cold winds and rapid drops in temperatures, however, appear to have caused illness, pneumonia, and sometimes death. Most of the animals in Europe are of the Mediterranean breed, but other River-type buffaloes (mainly Murrahs from India) have been introduced to Bulgaria and the Soviet Union, which indicates that River breeds, at least, have some cold tolerance.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Altitude</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although water buffaloes are generally reared at low elevations, a herd of Swamp buffaloes is thriving at Kandep in Papua New Guinea, 2,500 m above sea level. And in Nepal, River buffaloes are routinely found at or above 2,800 m altitude.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wetlands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are well adapted to swamps and to areas subject to flooding. They are at home in the marshes of southern Iraq and of the Amazon, the tidal plains near Darwin, Australia, the Pontine Marshes in south-central Italy, the Orinoco Basin of Venezuela, and other areas.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Amazon, buffaloes (Mediterranean and Swamp breeds) are demonstrating their exceptional adaptability to flood areas. Buffalo productivity outstrips that of cattle, with males reaching 400 kg in 30 months on a diet of native grasses( Information supplied by C. Nascimento). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The advantage of water buffaloes over Holstein, Brown Swiss, and Criollo cattle was demonstrated in a test at Delta Amacuro, Venezuela, when the cattle developed serious foot rot In the wet conditions of the Orinoco Delta and had to be withdrawn from the test. The area of Venezuela is flooded 6 months of the year and creates constant problems for cattle, yet the buffalo seems to adapt well(*Information supplied by A. Ferrer). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">High humidities seem to affect buffaloes less than cattle. In fact, if shade or wallows are available, buffaloes may be superior to cattle in humid areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In southern Brazil, trials comparing buffalo and cattle on subtropical riverine plains have favored the buffalo also. This work is being carried out on native pastures, mostly in  the State of Sao Paulo.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hafez, E. S. E., Badreldin, A. L., and Shafei,M. M. 1955. Skin structure of Egyptian buffaloes and cattle with particular reference to sweat glands. Journal of Agricultural Science, Cambridge 46:19-30.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Katyega, P. M. J., Masoud, A. J., and Kobo, E. 1980. Information on body and carcass characteristics of Egyptian water buffalo and Mpwapwa x Friesian steers raised in central Tanzania. Tanzania Veterinary Bulletin 2:86-90.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mason, I. L. 1974. Environmental physiology. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moran, J. B. 1973. Heat tolerance of Brahman cross, buffalo, Banteng and Shorthorn steers during exposure to sun and as a result of exercise. Australian Journal of Agricultural Research 24(5) :775 -782.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nair, P. G., and Benjamin, B. R. 1963. Studies on sweat glands in the Indian water buffalo. 1. Standardization of techniques and preliminary observations. Indian Journal of Veterinary Science 33:102.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pandey, M. D., and Roy, A. 1969a. Studies on the adaptability of buffaloes to tropical climate. I. Seasonal changes in the water and electrolyte status of buffalo cows. Indian Journal of Animal Science 39:367.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pandey, M. D., and Roy, A. 1969b. Studies on the adaptability of buffaloes to tropical climate. II. Seasonal changes in the body temperature, cardio-respiratory and hematological attributes in buffalo cows. Indian Journal of Animal Science 39:378.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prusty, J. N. 1973. Role of the sweat glands in heat regulation in the Indian water buffalo. Indian Journal of Animal Health 12(1):33-37.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robey, C. A., Jr. 1976. Physiological Responses of Water Buffalo to the Florida Environment. M.S. Thesis, University of Florida, Gainesville, Florida, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">6 Nutrition</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most buffaloes are located in countries where land, cultivated forage crops, and pastures  are limited. Livestock must feed on poor-quality forages, sometimes supplemented with  a little green fodder or byproducts from food, grain, and oil seed processing. Usually  feedstuffs are in such short supply that few animals have a balanced diet, but the buffalo  seems to perform fairly well under such adverse conditions.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Growth Rate</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Insufficient measurements have been taken to allow unequivocal state. meets about the  relative growth rates of cattle and buffaloes. However, many observations made in  various parts of the world indicate that the buffalo's growth is seldom inferior to that of  cattle breeds found in the same environments. Some observations are given below.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Trials in Trinidad in the early 1960s involved buffaloes grazing pangola grass (Digitaria  decumbens) together with Brahman and Jamaican Red cattle. Over a period of 20  months the buffaloes gained an average of 0.72 kg per day, whereas the cattle on a  comparable nearby pasture gained 0.63 per day(Experiments performed by P. N. Wilson. -Information supplied by S. P. Bennett.).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In the Orinoco Delta of Venezuela unselected Criollo/Zebu crossbred cattle gained  0-0.2 kg per day on Paspalum fasciculatum, whereas the water buffaloes with them  gained 0.25-0.4 kg per day(Cunha  et al., 1975).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In the Apure Valley of Venezuela, 100 buffalo steers studied in 1979 reached an  average weight of 508 kg in 30 months, whereas the 30-month old Zebu steers tested  with them weighed 320 kg. The feed consumed was a blend of native grasses (25  percent of the diet) and improved grasses (such as pangola, pare, and guinea grass)( Information supplied by A. Ferrer). In  the same valley 200 buffalo heifers (air freighted from Australia) produced weight gains  averaging 0.5 kg per day over a 2-year period (and 72 percent of them calved). Government statistics for the area record average weight gains in crossbreeds between Zebu and Criollo cattle as 0.28 kg per day (with 40 percent calving).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In the Philippines, buffaloes showed weight gains of 0.75-1.25 kg per day, the same as those of cattle. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Daily weight gains of over 1 kg have been recorded for buffaloes in Bulgaria and Yugoslavia.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Liveweight gains of 0.80 kg per day have been recorded for buffaloes in Papua New Guinea. In a very humid, swampy area of the Sepik River coastal plains liveweight gains by males averaged 0.47 kg per day and females 0.43 kg per day for more than a year. The average weight of 30 4-year-old female buffaloes was 375 kg, while the average weight of 4-year-old female Brahman/ Shorthorn crossbred cattle was 320 kg.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· At the research station near Belem in the Brazilian Amazon weaned Murrah buffaloes, pastured continuously on Echinochloa pyramidalis (a nutritious grass), gained 0.8 kg daily and reached 450 kg in about 18 months. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Liveweight gains of 0.74-l.i kg per day have been obtained in Australia. Buffalo steers grew as fast or faster than crossbred Brahman cattle on several improved pastures near Darwin, but on one very poor pasture, 40-year-old buffaloes each weighed only 400 kg, whereas the Brahman crossbred steers reared with them weighed 500 kg. The reason for this is not clear.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Efficiency of Digestion</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indian animal nutritionists have investigated water buffaloes intensively over the past two decades. Many have reported that buffaloes digest feeds more efficiently than do cattle, particularly when feeds are of poor quality and are high in cellulose.One trial revealed that the digestibility of wheat straw cellulose was 24.3 percent for cattle and 30.7 percent for buffalo. The figures for berseem (Trifolium alexandrinum) cellulose were 34.6 percent for cattle and 52.2 percent for buffalo. In another trial the digestion of straw fiber was 64.7 percent in cattle, 79.8 percent in buffalo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other nutrients reported to be more highly digested in buffaloes than in cattle (Zebu) are crude fat, calcium and phosphorus, and nonprotein nitrogen.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recent experiments in India suggest that buffaloes also are able to utilize nitrogen more efficiently than cattle. Buffaloes digested less crude protein than cattle in one trial but increased their body nitrogen more (and they were being fed only 40 percent of the recommended daily intake of crude protein).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ability of buffaloes to digest fiber efficiently may be partly due to the microorganisms in their rumen. Several Indian research teams have published data indicating that the microbes in the buffalo rumen convert feed into energy more efficiently than do those in cattle (as measured by the rate of production of volatile fatty acids in the rumen).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Also, in laboratory studies samples of buffalo rumen contents produced volatile fatty acids more quickly from a variety of animal feedstuffs than did samples from the rumen of cattle  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No single reason alone explains the buffalo's success in using poor quality forages. Rather, it is a combination of reasons that differ with the breed and conditions used. Studies by other researchers suggest that additional causes might include:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Higher dry matter intake; </P>
+<P ALIGN="JUSTIFY">· Longer retention of feed in digestive tract;  </P>
+<P ALIGN="JUSTIFY">· Ruminal characteristics more favorable to ammonia-nitrogen utilization;  </P>
+<P ALIGN="JUSTIFY">· Less depression of cellulose digestion by soluble carbohydrates (e.g., starch or molasses);  </P>
+<P ALIGN="JUSTIFY">· Superior ability to handle stressful environment; and  </P>
+<P ALIGN="JUSTIFY">· A wider range of grazing preferences.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Calf Growth Rates</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the buffalo's gestation period is more than a month longer than that of cattle, the calves are born weighing 35-40 kg, or about the same as that of a newborn Holstein calf. But because buffalo milk has about twice the butterfat of cow's milk, the calves grow very quickly. They also suffer more shock at weaning and have to be slowly changed to their new feeding program. Buffaloes can be marketed as full-grown animals for beef at the age of 2-3 years, sometimes even earlier.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p59.png"></center><br>
+ Table 5 Some Coarse Grasses and Forages Palatable to Buffaloes but Less Readily</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For example, in Indonesia it has been found that buffalo steers can be marketed 6 months before Zebu steers because they may be 100 kg heavier. In Egypt some buffalo calves given feed supplemented with concentrates weighed 360 kg at 1 year of age. At Ain Shams University near Cairo, buffalo calves weaned at 7-14 days of age gained 0.7 kg per day from weaning to slaughter at 18 months of age and weighed 400 kg. Rice straw comprised 50 percent of the finishing diet.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes on Italian farms have reached 350 kg in 15-18 months and some year-old calves weighed 320 kg. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grazing trials on native pasture (with mineral supplementation) in the Brazilian Amazon indicate that buffalo calves grew faster than cattle. At 2 years of age Mediterranean-type buffaloes averaged 369 kg, Swamp type, 322 kg, and Jafarabadi type, 308 kg. The Zebu cattle tested with them averaged 265 kg and the crossbred Zebu/Charolais, 282 kg. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Feed Preferences</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes graze a wider range of plants than cattle. During floods near Manaus in the  Brazilian Amazon when cattle become marooned on small patches of high ground,  many suffer from foot rot and many starve to death. Their buffalo companions on the  other hand-bodies sleek and full-swim out to islands of floating aquatic plants and eat  them, treading water. Also, they dive almost 2 m to graze beneath the floodwaters. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">University of Florida buffaloes in a lakefront voluntarily consumed vines, sedges, rushes, floating aquatic weeds, and the leaves and shoots of willows and other  trees along the water's edge. Few of these plants are voluntarily grazed by cattle. In  northern Australia water buffaloes graze the very pickily leaves of pandanus; they also  graze sedges, reeds, floating grass, and aquatic weeds. Hungry buffaloes will eat bark,  twigs, and other unpalatable vegetation.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of the variety of their tastes they have been used in northern Queensland,  Australia, to clear pastures of woody weeds left untouched by cattle. In some countries  cattle are used to graze the palatable tops of pasture plants and are followed by  buffaloes to graze the less desirable lower parts.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Afifi, Y. A., El-Koussy, H. A., El-Khishen, S. S., and El-Ashry, M. A. 1977. Production of  meat from Egyptian buffaloes. I. The effect of using different sources of roughages on  rate of gain, gross and net efficiency during the growth and finishing periods. Egyptian  Journal of Animal Production 17(2).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appleton, D. c., Dryden, G., and Kondos, A. C. 1976. A comparison of the digestive  efficiency of the water buffalo and the Brahman and Banteng cattle. Proceedings of the  Australian Society of Animal Production 11.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhatia, L S. 1967. The Study of Factors Affecting the Utilization of Low Grade  Roughages and Production of Volatile Fatty Acids in the Rumen of Indian Cattle. Punjab  Agricultural University, Ludhiana, India.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chalmers, M. 1.1974. Nutrition. In: The Husbandry and Health of the Domestic Buffalo  edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations Rome,  Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Charles, D. D., and Johnson, E. R. 1975. Live weight gains and carcass composition of  buffalo (Bubalus bubalis) steers on four feeding regimes. Australian Journal of  Agricultural Research 26:407-413.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chaturvedi, M. L, Singh, u. B., and Ranjhan, 5. K 1973. Comparative studies on the  efficiency of feed unitization in cattle and buffaloes. Indian Journal of Animal Science  43(12):1034.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chutikul, K. 1975. Ruminant (Buffalo) nutrition. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kacn, Thailand, March 31April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cunha, E., Alvarez, F., Larez, O., and Bryan, W. B. 1975. Pasture and Livestock Investigations in the Humid Tropics: Orinoco Delta, Venezuela. 4. Beef Cattle and Water Buffalo Grazing Trials with Native and Introduced Grasses. IRI Research Institute, New York, New York, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Davendra, C. 1979. The potential value of grasses and crop by-products for feeding buffaloes in Asia. Extension Bulletin No. 126. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">de Guzman, M. R., Jr. 1975. A summary of research into buffalo feeding in the Philippines. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dunkel, R. 1981. Animal production using nutrient-deficient fodders in the tropics and subtropics. Animal Research and Development 13:32-39.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">El-Ashry, M. A., Mogawer, H. H., and Kishin, S. S. 1972. Comparative study of meat production from cattle and buffalo male calves. I. Effect of roughage: concentrate ratio in ration for rate of gain and feed efficiency of native cattle, Friesian and buffalo calves. Egyptian Journal of Animal Production 12(2) :99 -107.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Grant, R. J., Van Soest, P. J., McDowell, R. E., and Perez, C. B. 1974. Intake, digestibility and metabolic loss of Napier grass by cattle and buffaloes when fed wilted, chopped and whole. Journal of Animal Science 39(2):423.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ibrovic, M., Cvetkovic, A., Smrcek, A., and Janevski, K. 1972. A contribution to the knowledge of metabolism of carotene and seasonal dynamics of vitamin A in the buffalo. Veterinaria 21(4) :511.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., Makkar, G. S., Sidhu, G. S., and Moxin, A. L. 1962. Cellulose digestion in water buffaloes and Zebu cattle. Journal of Animal Science 21:1001.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., and Sidhu, G. S. 1966. Effect of urea on the voluntary intake of wheat skew in Zebu cattle and the buffalo. Indian Veterinary Journal 43:880-886.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., Makkar, G. S., and Sidhu, G. S. 1969. Biochemical processes in the rumen. 111. Effect of different carbobydrates on in vitro digestion of cellulose and utilization of urea nikogen by rumen micro-organisms from zebu and buffalo. Indian Journal of Animal Science 39 :27-32.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani J. S., Makkar, G. S., and Sidhu, G. S. 1971a. Studies on the biochemical process in the rumen. Vl. In vivo digestion of cellulose in buffalo and cattle. Indian Veterinary Journal 48:267-271.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., Makkar, G. S., and Sidhu, G. S. 1971b. Studies on the biochemical process in the rumen. VII. In vitro digestion of cellulose in cattle and buffalo. Indian Veterinary Journal 48:583-586.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., Makkar, G. S., and Sidhu, G. S. 1972. Studies on the biochemical processes in the rumen. VIIL The significance of molar proportions of acetic and propionic acids in the rumen on the growth rate of buffalo and Zebu. Indian Veterinary Journal 49:995-1000.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ichhponani, J. S., Gill, R. S., Makkar, G. S., and Ranjan, S. K. 1977. Work done on buffalo nutrition in India-a review. Indian Journal of Dairy Science 30(3): 173-191.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Langar, P. N., Sidhu, G. S., and Bhatia, I. S. 1969. Utilization of nitrogen and production of volatile fatty acids in the rumina of buffalo (Bos bubalis) and zebu (Bos indicus) at different time intervals, under a feeding regimen deficient in carbohydrates. Indian Veterinary Journal 46:593-598.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ludri, R. S., and Razdan, M. N. 1975. Effect of level and source of dietary nitrogen on water metabolism in cows and buffaloes. Indian Journal of Dairy Science 28:107109.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ludri, R. S., and Razdan, M. N. 1980. Efficiency of nitrogen utilization by Zebu cows and buffaloes. I. Nutrient utilization and nitrogen balances on preformed protein diets. TropicalAgriculture (Trinidad) 57:83-90. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Makkar, G. S., and Sidhu, G. S. 1964. The fractionation of carbohydrates in Indian feedstuffs and the digestion of different fractions in the rumina of cattle and buffalo. Journal of Research, Ludhiana 1:56-66.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Misra, R. K., and Ranhoka, G. S. 1969. Influence of energy levels on the utilization of peanut protein-urea nikogen by cattle and buffalo. Journal of Animal Science 28: 107-109.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mullick, D. N. 1964. Review of the investigations on the physiology of Indian buffaloes. Indian Journal of Dairy Saience 17:45-50.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Naga, M. A., El-Shazly, K., Deif, H. I., Abaza, M. A., and El-Faham, R. H. 1975. Relationship between nitrogen balance, digested nitrogen and dry matter digestibility in ruminants. Journal of Animal Science 40(2):366-373.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nangia, O. P., Aggarwal, V. K., and Singh, A. 1972. Studies on the utilization of dietary protein in cattle and buffaloes. Indian Joumal of Dairy &amp;ience 25: 1-5.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nascimento C. N. B., Moura Carvalho, L. O. D., and Lourenco, J. B. 1979. Importdneia do Bufaio para a Pecubria Brasileira. Agricultural Research Center for Humid Tropics (CPATU), Belem, Para, Brazil.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nascimento, C. N. B., and Velga, J. B. 1973. Weight gains in stabled buffaloes of the Mediterranean breed. Boletim Tecnico do Instituto de Pesqutsas e Experimentacao Agropecuarias do Norte 58:24-72.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ponnappa, G. G., Nooruddin, M. D., and Raghavan, G. V. 1971. Rate of the passage of food and its relation to digestibility of nutrients in Murrah buffaloes and Hariana cattle. Indian Journal of Animal Science 41:1026-1030.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Punj, M. L., Kochar, A. S., Bhatia, I. S., and Sidhu, G. S. 1968. In vitro studies on the cellulolytic activity and production of volatile fatty acids by the inocula obtained from the rumen of Zebu cattle and Murrah buffalo on different feeding regimens. Indian Journal of Veterinary Science 38 :325-332.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raghavan, G. V., Kakkar, B., Rao, M. V. N., and Mullick, D. N. 1963. Effects of air temperature and humidity on the metabolism of food nutrients in cattle and buffalo bulls. Annals of Biochemistry and Experimental Medicine 23 :23-28.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ray, S. N., and Mudgal, V. D. 1962. Rumen metabolism studies in cattle and buffalo. Proceedings of the 16th International Dairy Congress, Copenhagen. A:105-l11.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sahai, L., Johri, P. N., and Kehar, N. D. 1955. Effect of feeding alkali and water-treated cereal straws on milk yield. Indfan Journal of Veterinary Science 25:201-212.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Saini, B. S., and Ray, S. N. 1964. Comparative utilization of coarse fodders in cattle and buffalo. Annual Report of the National Dairy Research Institute, Karnal, India.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schottler, J. H., Boromana, A., and Williams, W. T. 1977. Comparative performance of cattle and buffalo on the Sepik Plains, Papua New Guinea.AustralianJournal of Experimental Agriculture and Animal Husbandry 17(87) :550 -554. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sebastian, L., Mudgal, V. D., and Nair, P. G. 1970. Comparative efficiency of milk production by Sahiwal cattle and Murrah buffalo. Joumal of Animal Science 30:253256.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sharma, C. B., and Mugdal, V. D. 1966. Studies on the lignin and cellulose contents of fedder crops and effect of lignification of cellulose digestion. Indian Journal of Dairy Science 19:100.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sidbu, G. S., Kochar, A. S., and Makkar, G. S. 1967. Effect of supplementing Bajra stalks with lucerne and concentrates and their part replacement by urea on the production of volatile fatty acids in the rumen of cows and buffaloes. Journal of Research, Ludhiana 4:104-110.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, B. K., and Mudgal, V. D. 1967. The comparative utilization of feed nutrients from lucerne hay in buffalo and crossbred zebu heifers. Indian Journal of Dairy Science 20: 142-145.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tandon, R. N.' Sharma, D. D., and Mugdal, V. D. 1972. Effect of feeding urea with different levels of energy on the biochemical changes in the rumen of cows and buffaloes. Indian Journal of Animal Science 42: 174-179  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Upadhyaya, R. S., Singh, U. B., and Ranjhan, S. K. 19i3. Digestibilit of nutrients and VFA concentation in zebu cattle and buffalo calves fed on green cowpea and maize. Indian Journal of Animal Science 43 :5 83-s 88.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Verma, M. L., Sidhu, G. S., and Kochar, A. S. 1968. Effect of frequency on the production of VFA in the rumen by zebu cattle and buffalo. Journal of Research, Ludhiana 5(3) :1 -6.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Verma, M. L., Singh, N., Sidhu, G. S., Kochar, A. S., and Bhatia, I. S. 1970. The in vitro cellulose digestion and VFA production from some of the common Indian feeds using rumen inocula from Zebu cattle and buffalo. Indian Journal of Dairy Science 23:155 -160. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">7 Health</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When compared with other domestic livestock, the water buffalo generally is a healthy animal. This is particularly impressive because most of them live in hot, humid regions that are conducive to disease, and the buffalo is a bovine susceptible to most diseases and parasites that afflict cattle. Although the reasons are not specifically known, the effect of disease on the buffalo and its productivity is often less deleterious than on cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antibiotics and vaccines developed for cattle work equally well on buffaloes. As a result, treatments are available for most of the serious diseases of buffaloes, although some are not very effective for either animal.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The greatest buffalo losses are often among calves. Newborn buffalo calves, like bovine calves, can succumb in large numbers to viruses, bacteria, and poor nutrition. This is largely due to poor management during the calf's frst 2 months of life. For example, as noted previously, villagers in some countries often sell the valuable buffalo milk, thus depriving the calves.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo calf losses are often similar to those of the cattle around them, but the animal's proclivity for wallowing exposes calves to waterborne diseases. Further, a young one occasionally drowns when an adult rolls on top of it.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reactions to some specific diseases and parasites are discussed below.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pasteurellosis- Probably the water buffalo's most serious disease, pasteurellosis, or hemorrhagic septicemia, is caused by the bacterium Pasteurella multocida (P. septica). Buffaloes are more susceptible to it than cattle and die in large numbers where pasteurellosis occurs. A vaccine against pasteurellosis is effective in protecting both buffaloes and cattle; it is cheap and easily made.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tuberculosis- Despite some claims to the contrary, the water buffalo is susceptible to the bovine strain of tuberculosis (Alycobacterium bovis). Scattered reports from different parts of India indicate no difference in the incidence of infection between cattle and buffaloes(Information supplied by S. K. Misra, Department of Veterinary Medicine, Punjab Agricultural University, Ludhiana, Punjab, India).  Other strains of mycobacteria have been isolated from feral buffaloes and cattle in northern Australia but seem to have little effect on the animals. Tuberculosis occurs among the buffalo herds of the world only because most are kept under unsanitary conditions(In 1905 buffaloes were introduced to Trinidad because the cattle herds (Zebu and srahman breeds) were infected with tuberculosis and, in those days, it was thought that buffaloes were resistant to the disease. Most were housed in muddy, ill-kept pens and forced to eat sugarcane tops off the ground; consequently, in 1949 over 30 percent of the buffaloes reacted to the tuberculin test. (The cattle herds had 80 percent reactors.) Tuberculosis was eliminated in Trinidad's buffaloes by improving the sanitary conditions: installing concrete floors and mangers and cleaning the pens regularly. This, together with regular tuberculin testing and removal of reactors, led to such a dramatic improvement that buffalo tuberculosis is now virtually unknown. -Information supplied by S. K. Bennett.) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brucellosis-Buffaloes and cattle are equally susceptible to brucellosis. Although seldom reported as a problem elsewhere, brucellosis in Venezuela is increasing more rapidly among buffaloes than among cattle. In India the disease is no more prevalent among buffaloes than among cattle.  As many as 57 percent of some Venezuelan herds are infected with the disease. It is a frequent cause of abortion in buffaloes. Serologic procedures and measures developed for the control of the disease in cattle are also effective means of curbing this infection in buffaloes. (Consumption of raw milk or contact with aborted fetuses may cause undulant fever in humans.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mastitis- Among milking buffaloes mastitis is a problem as it is in dairy cows, but to a lesser extent. It is likely to increase, however, as the milk production per individual buffalo is increased. The bacteria that cause mastitis in the buffalo are similar to those in cattle. Treatment and control programs used for cattle are equally effective for buffaloes.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Diseases -Among the epizootic diseases, rinderpest and piroplasmosis seem to affect buffaloes as much as cattle. Foot-and-mouth disease also affects buffaloes, but to a lesser degree than cattle, producing smaller lesions and having a lower incidence. In northern Australia buffaloes deliberately infected with bovine pleuropneumonia bacteria exhibited slight fever, but the disease never appeared. No naturally occurring eases have been reported in buffaloes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ticks -Buffaloes are notably resistant, although not immune, to ticks. In a tick-infested area of northern Australia only 2 engorged female ticks were found on 13 adult buffaloes during a 2-year test. Accordingly, healthy buffaloes are not commonly affected by diseases borne by ticks nor are the hides damaged by their bites. Since ticks are rarely found on buffaloes, anaplasmosis, theileriasis, and babesiosis, which are tick-borne, have little effect on buffaloes in the field. (Buffaloes and cattle are equally susceptible, however, if inoculated with East Coast fever, a form of theileriasis.) This is important because tick infestations in cattle are particularly troublesome in the tropics and the pesticides used to control them are becoming ineffective as the ticks develop resistance. The pesticides are also becoming expensive.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The basis of the buffalo's tick resistance is not known, but wallowing and rubbing may play a role in it; animals kept in experimental concrete pens in Australia have developed heavy tick infestation. (rials carried out on Magnetic Island by R. H. V/harton, Commonwealth Scientiflc and Industrial Research Organisation, Townsville, Queensland, Australia). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p68to69.png"></center><br>
+ Table 6 Some Infections and Parasites of Buffalo</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Screwworm- Larvae of the screwworm fly (Callitroge species), a major pest of livestock in Central and South America and some other tropical areas, do not affect adult water buffalo. In Venezuelan areas where cattle (Zebu type) are severely infested, adult water buffaloes are virtually free of screwworm larvae and the umbilicus of newborn calves seldom if ever becomes infected. ( Information supplied by A. Ferrer). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The same is true in Papua New Guinea. It is thought that the mud plaster produced by wallowing suffocates the larvae, but in India screwworms do not affect water buffaloes either, and there they wallow in fairly clear water and the farmer usually washes them off. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Roundworm- The heavy losses of young buffalo calves throughout the world are caused, in large measure, by the roundworm Toxocara vitulorum. The calves seem more susceptible than mature animals and they become infected before birth or within 24 hours after birth through the mother's colostrum. The roundworm is the most serious buffalo parasite and in untreated calves the small intestine can get packed with worms to the point of complete occlusion. Although huge numbers of calves die each year, anthelmintic drugs that control roundworms are highly effective and widely available.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The adult water buffalo appears to have a high degree of resistance to strongyloid nematodes. Being such excellent converters of rough fodders they do not suffer the nutritional deficiency and the resulting liability to these roundworms experienced seasonally by cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Liver Fluke- During wallowing, water buffaloes can easily become infected with the waterborne infective stages of liver fluke (Fasciola gigantica). Although the number of flukes in a buffalo may be phenomenally high, no clinical signs of the disease are usually evident. It seems likely that the resulting liver damage reduces the growth and the work and milk production of buffaloes more than is generally appreciated.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trypanosomiasis- The water buffalo is susceptible to trypanosomiasis and is reportedly more susceptible than cattle to Trypanosoma evansi.Experience with the animal in Africa is limited, but trypanosomiasis may be the reason why Egypt is the only African country that has traditionally employed water buffalo.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Parasites- The wallow and its resulting mud cake seem to protect water buffalo from many biting flies, but the main ectoparasite in Australia and Southeast Asia is the buffalo fly (Siphona spp.). Pediculosis, caused by the sucking louse (Hematopinus tuberculatus), occurs widely among buffalo, and sarcoptic mange (Sarcoptes scabiei var. bubalus) is a serious disease, especially among calves and during dry seasons when wallowing opportunities are restricted. The lung worm Dictyocaulus ririparus thrives in warm, humid areas and sometimes infects buffaloes heavily, although its outward manifestations are rare.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Barlow, J. N. 1977. Toxicology and safety evaluation of Phosvel to Egyptian water buffalo. Pages 517-522 in: Pesticide Management and Insecticide Resistance, edited by D. L. Watson and A. W. A. Brown. Academic Press, New York, New York, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhowmik, M. K., and Iyer, P. K. R. 1977. Studies on the pathology of chronic lesions in the mammary glands of buffaloes (Bubalus bubalis). 1. Actinomycosis, nocardiosis and lesions simulating tuberculosis. Indian Veterinary Journal 54(5):342-346.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhowmik, M. K., Singh, S. P., and Iyer, P. K. R. 1977. Studies on chronic mastisis in buffaloes (Bubalus bubalis). lndian Journal of Animal Health 16(2) :157-160.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1974. Aspects of disease. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. Cockrill, Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dhar, S., Bhattacharyulu, Y., and Gautam, O. P. 1973. Susceptibility of Indian water buffalo (Bubalus bubalis) to Theileria annulata infection. Haryana Agricultural University Journal of Research 3(1):27-30.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dwivedi, S. K., Mallick, K. P., and Malhotra, M. N. 1979. Babesiosis: clinical cases in Indian water buffaloes. Indian Veterinary Journal 56(4):333-335.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Griffiths, R. B. 1974. Parasites and parasitic diseases. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hafez, S. M., and Krauss, H. 1979. Detection of antibodies against some respiratory pathogens in the sera of domestic animals in Egypt. Bulletin of Animal Health and Production in Africa 27(3):209-214.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ho, T. M. 1976. Animal disease control program in Republic of China for better animal production. Korean Journal of Animal Science 18(4):317-321.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iannelli, D. 1978. Water buffalo (Bubalus bubalis Arnee) allotypes: identification of a multiple allelic system. Animal Blood Groups and Biochemical Genetics 9(2):105113.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kapur, M. P., and Singh, R. P. 1977. Diagnosis of mastitis: a comparative study of four indirect tests.Haryana Veterinarian 16(2):69-73.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Leue, A. 1971. Buffaloes in Nepal. Tierartliche Umschau 26(4):173-178.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mohan, R. N. 1968. Diseases and parasites of buffaloes. I. Viral, mycoplasmal, and rickettsial diseases. II. Bacterial and fungal diseases. III. Parasitic and miscellaneous diseases. Veterinary Bulletin 38:567-576, 647-659, 735-756.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Murthy, D. K., and Sharma, S. K. 1974. Studies on reactivity and immunogenecity of cell-culture rinderpest vaccine in different species of ruminants. Indian Journal of Animal Science 44(6):359-365.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">San Agustin, F. 1973. Important diseases and parasites of Carabaos. Philippine Journal of Nutrition 26(2):68-79.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schneider, C. R., Kitikoon, V., Sornmani, S., and Thiachantra, S. 1975. Mekong schistosomiasis. III. A parasitological survey of domestic water buffalo (Bubalus bubalis) on Khong Island, Laos. Annals of Tropical Medicine and Parasitology 69(2):227-232.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sharma, K. N. S., Jain, D. K,, and Noble, D. 1975. Calf mortality in pure and crossbred Zebu cattle and Murrah buffaloes reared artificially from birth. Animal Production 20(2):207-211.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sharma, S. K., Banegee, D. P., and Gautam, O. P. 1978. Anaplasma marginale infection in Indian water buffalo (Bubalus bubalis). Indian Journal of Animal Health 17(2): 105-110.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shaw, J. J., and Lainson, R. 1972. Trypanosoma vivax in Brazil. Annals of Tropical Medicine and Parasitology 66(1):25-32.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shukla, R. R., and Singh, G. 1972. Studies on tuberculosis amongst Indian buffaloes. Indian Veterinary Journal 49(2):119-123.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Soni, J. L. 1978. Suitability of different serological tests for diagnosis of brucellosis in buffaloes (Bubalus bubalis). Indian Journal of Animal Science 48(12) :873-881. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tantawi, H. H., Fayed, A. A., Shalaby, M. A., and Skalinsky, E. I. 1979. Isolation, cultivation and characterization of poxviruses from Egyptian water buffaloes .Journal of the Egyptian Veterinary Medical Association 37(4):15-23.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thomson, D. 1977. Diseases of water buffalo in the Northern Territory of Australia. Australian Veterinary Practioner 7(1):50-52.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young, P. L. 1979. Infection of water buffalo (Bubalus bubalis) with bovine ephemeral fever virus. Australian Veterinary Journal 55(7):349-350. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">8 Reproduction</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo has a reputation for being a sluggish breeder, but the average animal is so poorly fed that its reproductive performance is unrepresentative of its capabilities. Without reasonable nutrition the animals cannot reach puberty as early in life or reproduce as regularly as their physiology or genetic capability would normally allow.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Actually, adequately nourished buffaloes reach puberty at about the same age as cattle, as early as 18 months of age in buffalo bulls. In northern Australia Swamp females have conceived even as early as 14 months of age and feral buffaloes routinely conceive at 16 months of age. In the herd at Punjab Agricultural University in Ludhiana, India, 11 River buffalo heifers showed estrus at ages less than 18.5 months and a few came into heat when less than 15 months old. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo also can calve at an age comparable to that of cattle. At the Ain Shams University in Egypt a well-fed Egyptian buffalo herd of several hundred animals has an average age at first calving of 27 months, 22 days(Information supplied by M. El Ashry. Because of nutritional uncertainties, El Ashry and his colleagues believe that body weight is a better indicator of sexual preparedness than age is. These researchers at Ain Shams University recommend mating heifers when they weigh 365 kg no matter what their age. Research at Punjab Agricultural University shows that buffalo heifers can be bred when they weigh over 270 kg and manifest estrus).Most animals in the Punjab Agricultural University River buffalo herd calved before 35 months, one at 28.3 months.! In one Venezuelan herd almost all heifers 20-24 months old were pregnant; virtually all calved before age 38 months, most by 30 months, and one at age 23 months. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In trials in Queensland, Australia, and in Papua New Guinea buffaloes produced more calves over a 3-year period than the cattle tested with them. In the hot, humid Sepik Plains in northern Papua New Guinea it was noticed that female buffaloes (Swamp breed) came into estrus even while they were losing weight because of inadequate nutrition, whereas cattle did not. Under these stressful conditions the buffalo calves also reached sexual maturity earlier and the buffaloes had a higher calving percentage and a shorter calving interval because they came back into estrus more quickly than cattle(Information supplied by J. Schottler. The age at first calving of more than 60 nutritionally poor buffaloes was 38 months in one herd and 45 months for Brahman cross cattle) . Similar observations have been made in Florida, Trinidad, the Brazilian Amazon, Venezuela, and elsewhere. Although these are exceptions to the normal observations in Asia, where buffaloes seem to breed more slowly than cattle, they do demonstrate the buffalo's potential for improved breeding.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Estrus in buffalo cows usually lasts about 24 hours, but duration varies and may range from 11 to 72 hours. It occurs on an average 21-day cycle. Determination of when a cow is in estrus is difficult because often the animal shows few outward signs of "heat." This increases the chances of missing a cycle, especially for artificial insemination. Unclean surroundings, poor nutrition, and poor management, cause a high death rate among calves; this also contributes to the buffalo's often low reproductive rate.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In many areas, calving is seasonal. This seems to be largely due to changes in nutrition. It may also be caused by heat stress, in either males or females, which results in a low breeding rate during the hot season. However, when buffalo cows are well fed, they come into estrus and will breed in any season.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many matings take place at night and are therefore unobserved. In one set of pregnancy diagnoses in northern Australia, the buffalo's conception rate (81 percent) was higher than that of the Brahman crossbreeds (70 percent) they were with. In India, artificial insemination of water buffaloes began in the late 1950s. Deep-frozen semen is now available and its use is spreading. Overall conception rates of 70-80 percent are obtained. It is estimated that some 100,000 buffaloes are now being artificially inseminated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo's gestation period is about one month longer and is more variable than that of cattle. Whereas cattle give birth after about 280 days (Angus, 279, Holstein, 279-280, Brown Swiss, 286), buffaloes take 300334 days (average 310) or roughly 10 months and 10 days (differences between breeds are unknown). In Punjab, India, River buffaloes have been observed to come into estrus as early as 40 days after calving. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nonetheless, only under uncommon circumstances can a buffalo cow produce a calf each year. In one herd of 800 cows in Venezuela the average female buffalo over age 4 produces 2 calves every 3 years. In response to a recent questionnaire, the majority of Indonesian farmers estimated that the calving rate was between 3 and 4 calves in 5 years. A few claimed a calf a year, some only 1 or 2 calves In 5 years. In Florida it has been noted that some buffalo cows having just calved became pregnant more quickly than cattle, so that a calf may indeed be produced each year. Regular yearly breeding has been noted also in northern Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The incidence of abortion, dystocia, retained placenta, and other parturition problems in buffaloes is similar to that in cattle. Twinning is very rare; probably no more than 0.01 percent of buffalo pregnancies produce twins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Preliminary results in northern Australia indicate that weaning can be carried out as late as 12 months of age without any effect on conception time of the buffalo dam.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bhattacharya, P. 1974. Reproduction. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chauhan, F. S., Singh, N., and Singh, M. 1977. Involution of uterus and cervix in buffaloes. Indian Journal of Dairy Science 30(4):286-291.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eusibio, A. N. 1975. Breeding, management and feeding practices of buffaloes in the Philippines. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FAO Animal Production and Health Paper. 1979. Buffalo Reproduction and Artificial Insemination. Proceedings of the Seminar Sponsored by FAO/SIDA/Government of India, held at National Dairy Research Institute, Karnal, 132001-India, December 4-15, 1978. Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghanem, Y. S. 1955a. Environmental causes of variation in the length of gestation of buffaloes. Indian Journal of Veterinary Science 25 :301-311.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghanem, Y. S. 1955b. Genetic causes of variation in the length of gestation of buffaloes. Indian Journal of Veterinary Science 25:307-311.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Health, E., and Gupta, R. 1976. Ultrastructure of water buffalo (Bos bubalis) spermatozoa. Zentralblatt fuer Veterinaerrnedizin 23(2):106-120.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Liu, C. H. 1978. The preliminary results of crossbreeding of buffaloes in China. Research Institute for Animal Science of Kwangsi, People's Republic of China.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Matharoo, J. S., and Singh, M. 1980. Revivability of buffalo spermatozoa after deepfreezing the semen using various extenders. Zentralblatt fuer Veterinaermedizin 27(5): 385-391.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rao, A. V. N., Murthy, T. S., and Dutt, K. L. 1979. Effect of lunar cyclicity on oestrus rhythmicity in the Indian water buffalo. Livestock Advisor 4(7):29-30.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rawal, C. V. S. 1978. A study on correlations of weight of pituitary gland and reproductive organs in males of Indian water buffalo. Indian Journal of Heredity 10(3):11-12.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robinson, D. W. 1977. Livestock in Indonesia. Research Report No. 1. Centre for Animal Research and Development, Bogor, Indonesia. (In English and Indonesian.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Roy, A. 1974. Observations on the physiology of reproduction. In: The Husbandry and Health of the Domestic Buffalo, edited by W. R. CockrilL Food and Agriculture Organization of the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sahai, R., and Singhal, R. A. 1977. The sex chromatin profile of water buffaloes of Murrah breed. Indian Journal of Animal &amp;Science 11(2):63-67.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sharma, A. 1978. Studies on the process of spermatogenesis and epididymal sperm reserve in water buffalo (Bubalus bubalis). Thesis Abstracts, Haryana Agricultural University 4(4):331.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, M., Matharoo, J. S., and Chauhan, F. S. 1980. Preliminary fertility results with frozen buffalo semen in Tris extender. Theriogenology 13(3):191-194.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singh, N., Chauhan, F. S., and Singh, M. 1979. Postpartum ovarian activity and fertility in buffaloes. Indian Journal of Dairy Sefence 32(2): 134-139.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sunkaporn Ratanadilok Na Puket. 1975. The improvement of buffalo production through breeding and management under Thailand conditions. In: Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Takkar, P. O., Chauhan, F. S., Tiwana, M. S., and Singh, M. 1979. Breeding behaviour of buffalo cows. Indian Veterinary Journal 56: 168-172.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Toelihere, M. R. 1975. Physiology of reproduction and artificial insemination of water buffaloes. In: The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1968. Incidence of calving and birth weights of domesticated buffalo in the Northern Territory. Proceedings of the Australian Society for Animal Productlon 7: 144-147.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1979. The water buffalo in Australia: reproductive and parent-offspring behaviour of buffalo. Australian Wildlife Research 6:265-287. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">9 Management</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are adaptable and are managed in many ways. In general, they are raised like cattle. But in some operations they must be handled differently. This chapter highlights these differences.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Millions of water buffaloes are managed in "backyards" in Asia. They exist on the resources of small holdings. Management and expenditures are minimal. Care of the family buffalo is usually entrusted to children, old people, or women not engaged in other farm duties; the buffalo allows them to be useful and productive.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The buffalo fits the resources available on the farm, but it is also an urban animal. Thousands of herds of 2-20 buffaloes may be found in the cities and towns of India, Pakistan, and Egypt-all fed, managed, and milked in the streets.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, the buffalo has important qualities as a feedlot animal; it can be herded and handled with relative ease because of its placid nature. The Anand Cooperative in India's Gujarat State, which daily contributes thousands of gallons of milk to Operation Flood (the world's largest nutrition project), involves more than 150,000 Surti buffaloes that are fed, managed, and milked by their owners under feedlot-like conditions in their villages. Many of Italy's 100,000 buffaloes are maintained under similar conditions.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes can also be managed on rangelands. In Brazil, Venezuela, Trinidad, the United States, Australia, Papua New Guinea, Malaysia, Indonesia, the Philippines, and elsewhere there is rising interest in raising buffalo beef on the range. The production practices for raising them are similar to those used for range cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes in the humid tropics must be able to cool off. Shade trees are desirable, and although a wallow is not essential, it is probably the most effective way the animal has of coping with heat. Alternatively, water showers may be provided to wet down the animals 3-5 times during the hottest part of the day.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are intelligent animals. Young ones learn patterns quickly and often are reluctant to change their habits. Feral animals-even those born in the wild-tame down after a week or two in a fenced enclosure to the point where many can be handled, haltered, and hand fed(In one example, loo feral buffalo were captured in Northern Territory, Australia. With in 14 days all the animals-males and females, young and old-had become docile and amenable to handling. -Information supplied by D. G. Tulloch) . Among feral herds of northern Australia it has been observed that buffaloes have clans and families. A female calf seems to remain with its family and mother for many years (possibly for life). A male calf stays until it is about 2 years old, when it is driven from the group by an adult bull. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It has also been noted in northern Australia that free-ranging buffaloes instinctively select clean water areas to drink from, other areas to wallow in, and still others as "toilet areas." In addition, China's buffaloes reportedly are being "toilet trained" to defecate only at specific sites to avoid contaminating waterways with schistosome eggs.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another interesting observation from northern Australia is that most buffalo dams readily adopt a calf that has been orphaned by the death of its mother. In fact, females will allow several calves to nurse (including calves of other mothers and sometimes even adults).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes are also self-reliant. For several months each year in Vietnam and Malaysia, for instance, they are turned loose in the forests to fend for themselves.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Provision of adequate fencing is one of the great problems of buffalo management. The  animals have strong survival instincts and if feed runs short, such as in the dry season,  they will break through fences that would deter cattle who would remain and starve. They  will also break through fences if their family unit is split up. Barriers must be stronger  than those used for cattle and the wires closer together and lower to the ground because  buffaloes lift fences up with their horns rather than trample them down. In northern  Australia, Papua New Guinea, and Costa Rica it has been found that buffaloes are  particularly sensitive to electric fences (a single wire is all that is needed), and in Brazil a  special suspension fence has been devised(Moura Carvalho et al., 1979). Both of these  seem to be cheap and efficient answers to the fencing problem.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are easily handled from horseback and easily worked through a corral.  Actually, because of their docility they can be mustered on foot, even on ranges where  cattle require horses. Unless they come from different areas they tend to herd together  and can be mustered like sheep.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the major management adjustments to be made by cattlemen is understanding  and capitalizing on the buffalo's placid nature. Buffaloes are naturally timid and startle  easily; they must be handled quietly and calmly. Rough handling, wild riding, and loud  shouting make handling them more difficult and training them much harder.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Village buffaloes are led and managed by a ring threaded through the septum between  the nostrils. The technique is frequently applied crudely and cruelly, often resulting in a  ripped septum.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The identification of individual buffaloes is difficult. Fire brands do not remain legible on  the skin for long. Cryobranding (freeze branding) is more durable. Most types of ear tags  are not very successful; the numbers wear off and mud covers up the tag's color. In  northern Australia ear tattooing has been the most successful identification technique,  with tattoos remaining legible for at least 8 years(Between 1958 and 1962 hundreds of  Australian buffalo were shipped on the hoof to the meat markets in Hong Kong without  trouble, despite crowded shipboard conditions and the long sea voyage. But in 1962 one  roughly treated bull went berserk in Hong Kong and killed a handler, and the Hong Kong  authorities stopped the trade as a result, although the problem was really one of  mismanagement. Buffalo have since been sent by air from Australia to Venezuela,  Nigeria, and Papua New Guinea and by barge to Papua New Guinea. No handling  problems have been experienced en route).  When they pasture together, cattle and  buffaloes coexist satisfactorily. They segregate themselves into their own groups and do  not interfere with one another. The buffaloes, however, usually dominate the cattle and  tend to monopolize the areas with the best feed supply.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Feed troughs and mineral boxes used for cattle are suitable for buffaloes, but chutes and  crushes must be widened to accommodate the buffalo's broader body and, when  necessary, the Swamp buffalo's greater horn spread. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes are powerful  swimmers. In Brazil they have been known to escape by swimming down the Amazon River. An unusual management difficulty is caused by piranha in the rivers and swamps of Venezuela. In one herd of 100 heifer buffaloes, 40 have lost all or part of a teat to these voracious fish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The horns of water buffaloes are seldom removed or prevented from growing, a  testament to the animal's docility. (When questioned, one Thai villager said that he wouldn't  allow it because it would be a disgrace to the buffalo.) However, the animals can be  dehorned as calves in the same manner as cattle. They are then easier to handle In  chutes and cause less accidental injury to neighboring animals, handlers, walls, and  trees.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Benya, E. G. 1972. Cattle and buffalo production in Vietnam. Dairy Science Mimeo  Report, Florida Agricultural Experiment Station, Gainesville, Florida, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cockrill, W. R. 1974. Management, conservation and use. In: The Husbandry and Health  of the Domestic Buffalo, edited by W. R. Cockrill. Food and Agriculture Organization of  the United Nations, Rome, Italy.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">De Boer, A. J. 1976. A further report on the Taiwan livestock industry: general policy  conclusions and further research needs. Journal of Agricultural Economics 19:116129.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lin, C. H. 1975. The breeding, management and feeding of water buffaloes in Taiwan. In:  The Asiatic Water Buffalo. Proceedings of an International Symposium held at Khon  Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer Technology Center, Taipei,  Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">McDowell, R. E. 1972. Improvement of Livestock Production in Warm Climates. W. H.  Freeman and Company, San Francisco, California, USA.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moura Carvalho, L. O. D., LouIenco, J. B., Nascimento, C. N. B., and Costa, N. A. 1979.  Cerca de Contencao pare Bubalinos e Bovinos. Comunicado Tecnico No. 28,  Agricultural Research Center for the Humid Tropics (CPATU), Belem, Para, Brazil.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rufener, W. H. 1975. Management and productive performance of water buffalo in  northeast Thailand. In: The Asiatic TVater Buffalo. Proceedings of an International  Symposium held at Khon Kaen, Thailand, March 31-April 6, 1975. Food and Fertilizer  Technology Center, Taipei, Taiwan.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1978. The water buffalo in Australia: grouping and home range. Australian  Wildlife Research 5:327-354.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1979. Redomestication of water buffaloes in the Northern Territory of  Australia. Animal Regulation Studies 2(1):5-20.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">10 Environmental Effects</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The grazing and wallowing habits of water buffaloes may have unexpected consequences when the animals are introduced to new, perhaps fragile environments. The presence of several thousand feral buffaloes on the coastal plains of northern Australia, for example, has become a very emotional issue among Australian environmentalists, some of whom foretell the complete destruction of the environment if the uncontrolled feral herds are not destroyed( It is not at all clear, however, that the buffaloes (which have existed in the area for 150 years) are causing the observed environmental degradation. Other possibilities include: fire, climatic stress, overgrazing, and a variety of farming, hunting, and other human activities, especially the use of four-wheel-drive vehicles. Thousands of wild pigs also share the area, along with crayfish that burrow into and weaken the levees that keep out the sea, something for which the buffaloes have been blamed). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Soil Compaction</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes have larger hooves than cattle of comparable size and thus they compact the soil less. But buffaloes often live in damp, boggy areas where their feet may compact soft soils. Also, buffaloes are creatures of habit and, when able, they set up fixed points for drinking, feeding, defecating, wallowing, and sleeping. Between the points they wear sharply defined trails in the vegetation and soil.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Wallowing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Possibly the water buffalo's greatest environmental limitation is its propensity to build wallows. In hot climates every buffalo will wallow at some time during the heat of the day if water is available. When they can, buffaloes will make their own wallows, enlarging a mud puddle by rolling in it or even using their heads to flip water out of a drinking trough and muddying the ground nearby.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pasture in the immediate area of the wallow is usually damaged by trampling and waterholes may become fouled, but buffaloes return to the same wallow day after day and do not build new ones indiscriminately. Thus, the muddied area is not a large proportion of the location in which they graze unless a large number of animals are confined in a small space(At Gainesville, Florida (possibly because of its subtropical but not hot climate), a herd of 52 buffaloes concentrated in a one-hectare field did not attempt to build a wallow at ale -Information supplied by H. Popenoe.) . In addition, man-made wallows can be dug at safe sites and the animals will use them. The problem of wallowing is therefore not generally a serious one.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Damage to Waterways</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because buffaloes often live near and enter water freely, they may cause erosion in ditches, river banks, canals, and levees. Also, their wallowing muddies the water, which may adversely affect some fish species and reduce the growth of algae. Buffaloes commonly urinate and defecate in the water, possibly creating a pollution hazard, although in most situations this contamination is likely to be minor.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The presence of this herbivore in natural waterways may reduce the number of water plants. Some plants are trampled, some eaten, and some underwater species are suppressed because the muddied water transmits less light. This (and several other of the buffalo's environmental effects) can be turned to advantage (see picture page 85) when, as often occurs, aquatic plants grow out of control and become obnoxious weeds.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Damage to Pastures</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water buffaloes have very strong jaws, and when forage is sparse they graze it close to the ground; this overgrazing can destroy a pasture. In addition, they eat virtually all available plant material (including many species that cattle shun), so that a densely stocked pasture can become completely defoliated. In northern Australia it has been found that, with time, buffaloes become accustomed to a given pasture, and unless fences are strong they will instinctively return to it until the forage has been depleted.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The buffalo's inclination to eat many plants can be used to improve the environment and suppress growth of coarse weedy species of plants. On the Sepik Plains in Papua New Guinea buffaloes are being used to graze and suppress sedges (Cyperus species), as a result, the more desirable Paspalum species are beginning to appear. At Mount Bundy in northern Australia native pastures are being improved on a commercial scale by overstocking them with buffaloes. The animals reduce or completely eliminate spear grass and other weeds-even those with thorns-and thus foster the survival and growth of introduced forage legumes such as stylo (Stylosanthes guianensis). In Sri Lanka buffaloes have been used to graze out the vigorous tropical grass Imperata cylindrica.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Damage to Trees</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffaloes instinctively rub against trees (and walls and fences), eagerly browse leaves, and sometimes nibble bark, so they damage trees more so than cattle. In northern Australia it has been noted that each "family herd" of feral buffaloes selects one or two trees for rubbing against so that the rubbing damage is confined to them. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Selected Readings</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rajapske, G., 1950. Death of illuk. Ceylon Coconut Quarterly, 1:7-9.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1969. Home range in feral water buffalo. Australian Journal of Zoology 17:143-152.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1970. Seasonal movement and distribution of the sexes in the water buffaloes in the Northern Territory. Australian Journal of Zoology 18:399-414.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1975. Buffalo in the northern swamplands. Proceedings III of the World Conference on Animal Production. Theme 1, Paper 7.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tulloch, D. G. 1977. Some aspects of the ecology of the water buffalo in the Northern Territory. In: The Australian buffalo-a collection of papers, edited by B. D. Ford and D. G. Tulloch. Technical Bulletin No. 18, Department of the Northern Territory, Animal Industry and Agriculture Branch, Australian Government Printing Service, Canberra, Australia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">11 Recommendations and Research Needs</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has outlined the water buffalo's apparent merits, but most of the statements made about the animal are based on empirical observations. Many of its most exciting and potentially valuable features have not been subjected to the careful scrutiny needed to confirm their validity.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the fact that there are 130 million or more water buffalo in the world, research on the animal is scanty and limited to only a few situations and sites. Quantitative information (especially for the various breeds), tests, trials, and comparison studies are needed.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The research to be done on the water buffalo offers scientific challenges that can be undertaken in laboratories and experiment stations in most parts of the world and in many disciplines: breeding, physiology, microbiology, veterinary science, nutrition, food science, dairy science, and other fields. Water buffalo research is an area worthy of financial support by philanthropic institutions and international development agencies concerned with problems of food and resource shortages. The dominant role of the buffalo in the rural economies of Egypt and Asian countries offers the opportunity for buffalo research that can bring improvements quickly and easily to the rural poor. For other countries the water buffalo is an untapped resource, and they should test its productivity on native pasturelands, marshy lowlands, hot and humid areas where cattle do not thrive, and on areas prone to cattle diseases and parasites that are difficult to control.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Specific recommendations follow.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Comparison with Cattle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal scientists worldwide should undertake trials to compare growth rate, feeding, nutrition, breeding, and other aspects of buffalo and cattle performance.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cattle and water buffaloes are obviously different animals. Each has its own limitations and advantages, and each deserves to be studied in its own right. Perhaps the quickest way for animal scientists to experience for themselves the merits of the water buffalo is to conduct their own comparative trials with buffaloes and cattle in their areas. The results will provide local guidance and will help extend recognition of the buffalo's value, especially under difficult conditions where it may exceed cattle in productivity and profitability.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Germ Plasm Preservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Urgent action is needed, especially in Southeast Asia, to preserve and protect outstanding buffalo specimens.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In some countries (Thailand, Malaysia, and Indonesia, for example) buffalo populations are decreasing dramatically. High demands for meat are causing slaughter at younger and younger ages. Much of the meat is exported to restaurants and markets in Singapore and Hong Kong. Unfortunately, the largest and quickest growing animals are often selected for slaughter. This results in the loss of a major genetic resource, which is compounded by the practice of castrating the largest males to make them more tractable as work animals. Ten years ago in Thailand it was common to find buffalo weighing 1,000 kg; now it is hard to find 750-kg specimens. A similar situation exists in the Philippines where there is no dearth of good breeding stock, but butchers are paying such high prices that farmers are selling even quality animals for slaughter. In northern Australia, where some of the bulls weigh almost 1,200 kg, the largest animals are being shot for meat, hides, pet food, or sportsmen's trophies,  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A large number of high-yielding buffaloes are taken each year to big cities in India (for example, Bombay, Calcutta, Madras) for milking. At the end of lactation many are returned to the villages, but many others are slaughtered, rather than being fed and retired. This creates a huge loss of valuable germ plasm. In many locations most of the largest animals have already been lost. Only urgent action will protect those remaining.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">International Shipment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo quarantine stations should be organized in "disease-free" areas to develop buffalo germ plasm pools for international exchange.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The importation of buffaloes presents difficulties for any government, researcher, or farmer wishing to obtain the animals for the first time or for breeding purposes. Quarantine laws make it extremely difficult and expensive to exchange genetic resources.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Australia is one of the few nations where there are large numbers of water buffalo in an area free of the major animal diseases. Papua New Guinea, </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nigeria, Colombia, Venezuela, and other nations have taken advantage of this and have  imported Australian buffaloes. But Australian herds are all Swamp buffaloes(The island  of Guam is also a safe source of Swamp animals, although the feral herds there are  depleted, only 300 or 400 animals were left on Guam in 1978) and so breeding centers  should be set up also (in Sri Lanka and Italy perhaps) where importers can obtain  River-type (including Mediterranean) buffaloes.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Genetic Improvement</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide efforts should be made to select superior buffalo bulls and cows for breeding.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Performance testing, leading to the mass selection of superior animals, deserves high  priority. Virtually all buffalo breeding is haphazard and unplanned. Village animals graze  together and matings are usually not con" trolled, observed, or recorded. Thus, the full  genetic potential of the water buffalo is not being realized.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A massive selection program is needed to bring about genetic progress. For each breed,  bulls and cows with the potential for improving production of meat and milk and  increasing draft power should be identified and used for breed improvement. However,  the wide variations between the characteristics of individual animals may make  exceptional genetic advances difficult to achieve quickly.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Important traits for culling and selection include behavior, temperament, reproduction  rate, easy milk letdown, average daily gain in weight or weight at a given age, carcass  quality (for example, large hindquarters), and milk production, as well as strength and  endurance for work.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Crossbreeding of Swamp and River buffaloes is a potentially important route to genetic  improvement. The progeny reportedly show hybrid vigor (heterosis) in milking ability,  fertility, meat production, and working ability. Infusing genes for high milk production into  the Swamp buffalo, now used mainly for meat and work, creates the potential for a  triple-purpose animal.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The use of artificial insemination and deep-frozen semen should be a major help in  upgrading the buffalo. Moreover, the transport of live embryos (rather than neonatal  animals) for implantation in the uterus of surrogate mothers could be important for water  buffalo. It seems unlikely, however, that buffalo embryos can be implanted in cattle.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most genetic selections should be made in Asia where 97 percent of the world's water  buffaloes are located. The improvements will depend on how accurately bulls can be  identified, selected, and mated. Performance and  progeny testing is sorely needed at research stations as well as "on the farm." Governments should also institute bull-loan or artificial-insemination programs as a means for upgrading the village herds.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Comparison of Breeds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The relative merits of the various buffalo breeds should be determined,  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little or no information is available on the comparative performance of the different buffalo breeds in various environments, especially the 17 or so River breeds in the Subcontinent and the Egyptian and Mediterranean breeds. Comparison trials of the breeds and breed-crosses are needed in a wide range of climates from the humid tropical to the temperate. In addition, the cytogenetic, immunogenetic, and inheritance relationships of breeds should be clarified.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel encourages countries such as India and Pakistan that have a number of buffalo breeds (for example, Murrah, Surti, Jafarabadi, Mehsana, and Nili/Ravi) to set up experimental farms for scientific reproduction of superior specimens. Substantial research benefits as well as profitable economic returns from using and exporting some of them would be realized.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Meat and Milk Research</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and demonstration is needed to foster the widespread consumption of buffalo meat and milk.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo milk, cheese, and other dairy products are considered outstanding foods in all locations where they are produced. Taste tests so far have indicated that buffalo meat is similar or slightly superior to beef produced under the same conditions.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A specific need is to feed the male calves and use them for meat. Many are now slaughtered at a young age and light weight. Research that provides either a partial or complete milk substitute for feeding calves would have a major impact on meat supplies and farmer income. Diets being developed for calves in Egypt incorporate such ingredients as whey, soybean meal, corn flour (corn starch), and yeast.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other research topics include:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The effect of climate, thermoregulation, and wallowing on meat and milk production;  </P>
+<P ALIGN="JUSTIFY">· The meat characteristics of each of the breeds and the differences between them,  </P>
+<P ALIGN="JUSTIFY">· Milk production and quality for each of the breeds;  </P>
+<P ALIGN="JUSTIFY">· Adapting buffaloes to machine milking by genetic selection or by designing new milking  machinery;  </P>
+<P ALIGN="JUSTIFY">· Developing new or improved milk products (such as yogurt, cottage cheese, and hard  cheese); and  </P>
+<P ALIGN="JUSTIFY">· Banking genetically superior germ plasm for later use.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Work Research</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel recommends research on new harnesses to replace the omnipresent yoke.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As already noted, the wooden yoke, which has not changed in 1,500 years or more, is an  inefficient harness. Research is needed to adapt horse collars, hames, breast straps,  and other devices for the buffalo. Because much of the farm power in Asia comes from  buffaloes, the impact of improved harness could be dramatic, widespread, and of  enormous value to millions of small farmers there. If the experiments in Thailand  described earlier are an indication, the farm power in Asia could be increased by 25  percent overnight with the adoption of an improved harness. The buffalo will continue to  be the small farmer's "tractor," so the benefits from improved harnesses are likely to  continue for a long time.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are 13 million buffalo and bullock carts in India and 20 million Indians are engaged  in the business of road haulage. Application of appropriate technology would eliminate  the archaic wooden wheels, axles, and heavy carts and substitute lightweight carts,  perhaps with such features as metal wheels, pneumatic tires, ball bearings, and fixed  axles. With such improvements, loads might be increased and hauled over longer  distances at greater speed and with less work.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Trials in New Areas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Testing of water buffalo production is needed in many areas where the animal is not  known.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A seemingly adaptable animal, the water buffalo should be productive throughout the  earth's warm temperate, subtropical, and tropical zones. Different breeds may adapt  differently to extremes of heat, humidity, and cold, and this needs further study.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The United States, the Mediterranean Basin of Europe, and some of the more temperate  European areas like southern England are worth considering for water buffalo trials. In the Southern Hemisphere River buffaloes are already found as far south as 25° latitude in Brazil's Sao Paulo State (where large herds are raised); an experimental herd of Swamp buffaloes has performed outstandingly in Brisbane, Australia (27°S); and there are a few Swamp buffalo in South Australia and Victoria (35°S or more). There is good reason to believe that water buffaloes may be productive in all of the states in Australia, New Zealand's North Island, South Africa, Argentina, and other warm temperate areas of the Southern Hemisphere.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The biggest void in the water buffalo map is virtually the entire continent of Africa. It seems a paradox that the buffalo-Egypt's most important domestic animal-is not farmed commercially in any other African country. Experimental herds have been introduced to Nigeria, Uganda, Mozambique, Tanzania, and other countries in the past, and the initial success of three of them is described in Appendix A.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The water buffalo, with its tolerance for heat, disease, poor-quality feed, and mismanagement, appears to have outstanding promise for African nations such as Sudan, Tunisia, Morocco, Senegal, and The Gambia as well as all nations south of the Sahara (Nambia perhaps being an exception).  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More specific aspects of environmental tolerance deserving research attention are:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">· The physiology of the buffalo's response to heat, cold, humidity, and other environmental factors;  </P>
+<P ALIGN="JUSTIFY">· The effect of climate on growth, reproduction, milk production, health, respiration rate, behavior, and carcass quality; and  </P>
+<P ALIGN="JUSTIFY">· Measurement of the calorific efficiency and chemical composition of all breeds of buffaloes and cattle to determine the environments best suited to each breed.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Nutrition Research</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite observations of the buffalo's ability to utilize poor quality forage, research is needed to learn how the animal does it.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This research should:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Establish the buffalo's nutrient requirements by breed, sex, age, and weight for maintenance, growth, reproduction, lactation, and work;  </P>
+<P ALIGN="JUSTIFY">· Determine voluntary forage consumption and the nutrient utilization of different forages in various stages of maturity;  </P>
+<P ALIGN="JUSTIFY">· Examine rumen microbiology and fermentation, the rate of digestion, production, and absorption of volatile fatty acids produced in the rumen, and utilization of energy, nitrogen, vitamins, and minerals; </P>
+<P ALIGN="JUSTIFY">· Develop milk replacements for early~weaned calves;  </P>
+<P ALIGN="JUSTIFY">· Observe the current village-level feeding of low~uality forages to learn their nutrient requirements, nutrient deficiency diseases, and nutrient supplementation needed;  </P>
+<P ALIGN="JUSTIFY">· Study the utilization of concentrated, high-energy feeds (especially byproduct feeds) to determine the upper limits of buffalo growth and productivity (milk, meat, and work) and carcass quality;  </P>
+<P ALIGN="JUSTIFY">· Compare various breeds of water buffaloes and other ruminants to determine possible differences in nutritional requirements and performance; and  </P>
+<P ALIGN="JUSTIFY">· Apply economic research to production practices, including night feeding of cut forage and the use of improved pastures.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Management</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research to improve management practices could benefit small farmers, ranchers, and feedlot feeders alike.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Little is known about the farm management factors that influence water buffalo productivity. Studies and extension literature for farmers are needed on subjects such as:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Proper fencing;  </P>
+<P ALIGN="JUSTIFY">· Procedures for dehorning and for preventing horn growth in calves;  </P>
+<P ALIGN="JUSTIFY">· Grazing management methods;  </P>
+<P ALIGN="JUSTIFY">· Preservation of forages;  </P>
+<P ALIGN="JUSTIFY">· Methods and effect of castration;  </P>
+<P ALIGN="JUSTIFY">· Methods and effect of spaying;  </P>
+<P ALIGN="JUSTIFY">· Breeding methods;  </P>
+<P ALIGN="JUSTIFY">· Milking methods;  </P>
+<P ALIGN="JUSTIFY">· Artificial insemination, methodology and use;  </P>
+<P ALIGN="JUSTIFY">· Methods of handling animals under grazing conditions or in feedlots;  </P>
+<P ALIGN="JUSTIFY">· Age for weaning under different conditions;  </P>
+<P ALIGN="JUSTIFY">· Mineral and protein supplementation methods;  </P>
+<P ALIGN="JUSTIFY">· Semen freezing;  </P>
+<P ALIGN="JUSTIFY">· Ova transplantation methods;  </P>
+<P ALIGN="JUSTIFY">· Cryobranding and other methods of animal identification;  </P>
+<P ALIGN="JUSTIFY">· Control of internal parasites; and  </P>
+<P ALIGN="JUSTIFY">· Disease prevention and treatments. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Health</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is needed in areas where uncertainties about buffalo diseases are hindering  the animals' use.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The research should:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Develop control and management practices to prevent specific infections and parasites  for buffalo groups such as calves, yearlings, heifers, pregnant cows, newly calved cows,  and bulls;  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Elucidate the factors (genetic, nutritional,management, disease) causing losses of  newly born calves;  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Prevent and control the major diseases and parasites of the buffalo: hemorrhagic  septicemia, brucellosis, tuberculosis, foot-and-mouth disease, sarcoptic mange,  fascioliasis, nematode parasites, rinderpest and "rinderpestlike" diseases, nephritis, and  conjunctivitis;  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Develop herd-health programs and specific disease-control programs for the various  production systems;  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Determine the level of susceptibility to trypanosomiasis, a disease that might mitigate  against introducing the animal widely to Africa; and  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Define the buffalo's role in malarial ecology.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Reproduction</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research is needed to improve water buffalo reproduction.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research topics should include:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Physiology and deep-freezing of buffalo semen. (Although it is possible to freeze the  buffalo semen now, further improvements are needed to achieve higher conception  rates.)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Incidence of sub-estrus and anestrus. This is fairly high in buffaloes. Work is needed to  determine the factors contributing to this problem and find solutions applicable in the  field. A simple, inexpensive test for the routine diagnosis of estrus is needed. It could  ensure that buffaloes are inseminated at the optimal time and could lead to the possible  synchronizing of estrus in groups of animals as well as the elimination of seasonal  breeding.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Seasonality of breeding. Investigations are needed into seasonal effects on the intensity  and deviation of estrus in buffaloes. Most of the buffaloes in northern India and Pakistan,  for example, calve between July and December, causing scarcity of milk in the summer  season and a flush of production in the winter months (this phenomenon causes serious  marketing problems).  </P>
+<P ALIGN="JUSTIFY">· Low libido and low semen yield in buffalo bulls. Semen yield in buffalo bulls is less than half of the yield from cattle bulls.  </P>
+<P ALIGN="JUSTIFY">· Effect of season and other factors on semen quality.  </P>
+<P ALIGN="JUSTIFY">· Variation in the freezability of semen from different bulls.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Dissemination of Information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel recommends that two water buffalo publications be produced.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These should be:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· An international water buffalo newsletter. It is important to maintain communication among researchers working with the water buffalo in far flung research stations, universities, missions, and villages. Research findings may not be widely shared if technical animal science journals and the one or two national newsletters now available remain the only source of water buffalo information. A newsletter would bring together results from different parts of the world. It would provide rapid exchange of information as well as a forum for informal opinions, observations, and preliminary experimental data that are usually not accepted by journals.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· A formal journal of water buffalo research.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, other methods for disseminating water buffalo information are to be encouraged. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendixes</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Appendix A</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Water Buffalo in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the water buffalo, Africa is the unknown continent. Apart from Egypt, where the  "gamoosa" is a major livestock resource, there have been few recorded experiences  with the animal in Africa. While this may be attributed to disease, chances are it is  because of historical oversight.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small herds of buffaloes were recently introduced to Uganda, Tanzania, and Nigeria, but  because there were so few animals no firm conclusions can be drawn. Initial  observations, however, suggest that the water buffalo could have an important future role  in Africa, south of the Sahara. There seems little reason to believe that they won't thrive  there as they have done elsewhere in the tropics.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The following statements were provided by researchers involved in the enterprises.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Uganda</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"Uganda imported a herd of 12 buffalo cows and one bull in 1969. Grazed on poor-quality  unimproved pasture they received neither supplementary feeding nor any preferential  treatment over the East African zebus kept with them. The herd stayed 7 years at  Entebbe before being moved to another part of the country. They proved to be very  efficient converters of the low protein, high-fber fodder. During this time the herd grew to  40 adult cows and 2 bulls (all other steers were slaughtered). The cows calved every  year. The calves matured at 2 to 21/2 years; the zebu calves took at least 3 years to  mature. Buffalo calves were much heavier than the zebus of comparable age.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"The buffalo cows averaged 7 liters of milk per milking. In taste it was preferred to zebu  milk. Also, the quality of the meat after slaughter was much better than that of the zebus.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">"A major advantage the buffaloes had over the cattle was that they were remarkably  unaffected by diseases endemic to the area. Apart from a few calves that died of  diseases that also killed cattle on the farm at Entebbe, the buffaloes resisted tick-borne  diseases, the biggest killers of cattle in Uganda, and were unaffected by the virulent  strains of East Coast Fever (Theileriosis), Uganda's most serious endemic animal  disease."(Information supplied by G. L. Corry, Director, Veterinary Research Services, Entebbe  Uganda)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Nigeria</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Early in 1976, 194 buffaloes aged 6-9 months were imported from the environs of Darwin in Australia's Northern Territory. The animals settled down quite well, and by the end of 1978 the stock population had risen to about 320, the adults weighing about 400 kg with about 80 percent fertility. The animals were in excellent health when an outbreak of streptothricosis occurred early in 1979. Because of the intractable nature of this rare disease of cattle, sheep, and pigs, the apparent spread of the disease in the confined area of the ranch, and the persistence of the organism, the animals were slaughtered(nformation supplied by Dr. J. E. Erhiaganoma, Chief Veterinary Officer, Ministry of Agriculture and Natural Resources, Benin City, Bendel State of Nigeria)..  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Tanzania</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tanzania introduced 21 buffalo heifers and 2 buffalo bulls from Egypt in 1968 and 1970. By 1977 the herd had grown to 150 animals. They were kept at the Livestock Production Research Institute at Mpwapwa, a site representative of central Tanzania(Mpwapwa is located at an elevation of 1,000 m. It receives an annual rainfall of 700 mm during a single season between late November and early May. Mean minimum temperatures of 13°C occur in June, and mean maximum temperatures of 26°C occur in November). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over a period of 10 years the buffalo were studied and compared with crossbreeds of local Mpwapwa cows and Friesian steers. On average, the buffaloes conceived and calved 4 months earlier than the cattle, their mean calving intervals were about a month shorter, their birth and weaning weights were 1.5 times higher, and their daily weight gain was about double that of the crossbred cattle. The milk yield from the buffaloes was only about two thirds that of the crossbred cattle, but their rnilk's high butterfat content meant that the overall butterfat production was higher in buffaloes.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Figures reported are shown below:  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p98.png"></center><br>
+ Table</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a second study (Shoo, R A. 1980. A study of the performance of Egyptian water buffaloes. Student project, Animal Production Department, Faculty of Agriculture, Forestry and Veterinary Medicine, University of Dar-Es-Salaam, Morogoro, Tanzania.), 30 buffaloes and 34 Mpwapwa cattle (not the crossbreeds) were compared(Mpwapwa cattle are a Tanzanian breed with 55 percent Asian, 35 percent African, and 10 percent European blood). The calving intervals were 396 + 126 days for buffaloes and 437 + 109 days for cattle. The buffaloes first conceived at mean ages of 23-25 months (matings occurred in both wet and dry seasons), the cattle at 27-36 months. The buffaloes calved at 35 months, the cattle at 46 months.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On farms at Ruvu and Mabuki the calving rate was 63 percent, and the mortality rate 1.2-6.9 percent(Rakha, A. 1980. water buffalo Production, Tanzania. Report of the technical Cooperation Program TCP/URT/9002, Food and Agriculture Organization of United Nations, Rome, Italy). The buffalo's overall milk yields averaged 1,237 kg in 225 days, or 5.5 kg per day.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The results of the introduction of buffalo to Tanzania are considered "quite encouraging and the future of buffaloes in Tanzania will be bright." (Oloufa, M. M. 1981. The future of water buffaloes in Tanzania Paper presented at the Tanzania Society of Animal Production Eighth Scientific Conference, Arusha, Tanzania May 26-29, 1981.) Future plans call for increasing the herd to about 200 animals with a view toward establishing another buffalo herd. In addition, 5 buffalo sires have been selected in Egypt for shipment to Tanzania.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendix B</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research Contacts</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A directory of names in buffalo studies and research is available from the International Buffalo Information Center, Kasetsart University Library, Bangkhen, Bangkok 10900, Thailand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Industry Branch, Department of Primary Production, P.O. Box 5160, Darwin, Northern Territory 5790 (D.R. Thomson, B. Ford)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Berrimah Agricultural Research Station, Darwin, Northern Territory</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coastal Plains Research Station, near Darwin, Northern Territory</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D. G. Tulloch, P.O. Box 38841, Winnellie 5789, Northern Territory</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">University of Queensland, Department of Animal Husbandry, St. Lucia, Queensland (D.D. Charles)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Brazil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associacao de Criadores de Bufalos do Brasil, Cx Postal 832, Sao Paulo (President, Dr. Paulo Joaquim Monteiro da Silva)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Centro de Pesquisa Agropecuaria do Tropico Umido (Agricultural Reseach Center of the Humid Tropics), Caixa Postal, 48, Belem, Para, 66000  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Faculdade de Medicina Veterinaria e Zootecnia (Faculty of Veterinary Medicine and Zootechnology), Universidade Estadual "Julio de Mesquita Filho," Campus de Botucatu, Estado de Sao Paulo  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Instituto de Zootecnia (Institute of Zootechnology), Nova Odessa, Sao Paulo (Prof. Alberto Alves Santiago)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr. Geraldo Mosse, Rua Apinages 716-CEP, 05017, Sao Paulo, S.P.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr. Walmore Muller Lacort, Ministerio de agriculture Explanada des Ministerios, Bloco 8-50 Andar Sala 518, 70.000 Brasilia, D.F.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Bulgaria</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Academy of Agricultural Sciences, Sofia (P. Ivanov, Z. Zahariev)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Buffalo Basis, Livestock Breeding Research Institute, Shumen (Dr. D. St. Polikhronov, Director; Dr. A. Alexis)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">China</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Husbandry and Veterinary Medicine, Nanking Agricultural College, Nanking (Professor Sieh Chen-Hsia)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kwangsi Agriculture College, Nanning, Kwangsi (Professor Wang Pei Chien</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock Farm, Lu Hsu, Pinyang County, Kwasngsi Chang Autonomous Region</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research Institute for Animal Science, Nanning, Kwangsi (Dr. Chou Chi-Sheng)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Singchow Dairy Farm, Kwangtung Province</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Costa Rica</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jose Luis Pacheco, Director, Dept Formento, 8502 JAPDEVA, Puerto Limon</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Egypt</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ain Shams University, Kasr-EI-Zaafran, Abbasiyah, Cairo (M.A. El-Ashry, A.M. El-Serafy)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Production, College of Agriculture, Cairo University, Cairo (Dr. M.T. Ragab)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">University of Alexandria, 22 Al-Gueish Avenue, Shatby, Alexandria (K. El-Shazly)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Federal Republic of Germany</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr. R. Dunkel, Herzeleidstrasse 39, 5330 Konigswinter 41, Bonn</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prof. Dr. H. Fischer, Insitut fur Tropische Veterinarmedizin, Wilhelmstr. 15, 6300 Giessen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gesellschaft fur Agrarentwicklung (GAE), Meckenheimer Allee 113, 5300 Bonn 1</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Hungary</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. Kovacs, Department of Animal Husbandry, Agricultural University, Deak F. -u16, 8361Keszthely  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">India</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Andhra Pradesh Agricultural University, Hyderabad, A.P. (Director of Research)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Husbandry Commissioner, Government of India, Ministry of Agriculture and Irrigation, Krishi Bhavan, New Delhi  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Sciences, Director General, Indian Council of Agricultural Research, Krishi Bhavan, New Delhi  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Buffalo Breeding Farm, Sambalpua, PO: Sunbeda, Distt. Kerapur, Orissa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Frozen Semen Bank, Hessarghatta, Bangalore, Kamataka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Murrah Breeding Farm, Almadi, Tamil Nadu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Surti Buffalo Farm, Dhamrod, Gujarat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chief Superintendent, Govenment Livestock Farm, Hissar, Haryana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">College of Veterinary and Animal Science, Chandra Sekhar Azad University of Agriculture and Technology, Mathura Campus, Mathura, U.P.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Co-ordinator, All India Buffalo Improvement Project, Natioal Dairy Research Institute, Karnal, Haryana, (Dr. V. N. Tripathi)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director, Military Dairy Farm, Army Headquarters, Quatermaster, General Branch, DHQ PO New Delhi 11  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G.B. Pant, University of Agriculture and Technology, Pantnagar, U.P.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government Livestock Farm, Anjora Distt: Durg, Madhya Pradesh</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gujarat Agricultural University, Reproductive Biology Research Unit, PO Anand Agricultural Institute, Anand, Gujarat  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Haryana Agricultural University , Hissar, Haryana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indian Veterinary Research Institute, Izatnagar, Barcilly, V.P. (Dr. S.K. Ranjan)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jawaharlal Nehru Krishi Vishwa Vidyalaya, Jabalpur, 482004, M.P.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kaira District Cooperative Milk Producers Union Ltd., Anand, Gujarat (Dr. V. Kurien, Chairman)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Dairy Development Board, Anand, Gujarat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Dairy Research Institute (ICAR), Karnal 132002, Haryana (S.P. Arora, Dr. D. Sundaresan, Director)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Punjab Agricultural University, Ludhiana, Punjab (Dr. J.S. Ichhponani, Dr. S.K. Misra)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">University of Agricultural Sciences, Dharwar Campus, Dharwar, Karnataka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">University of Udaipur, Udaipur, Rajasthan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Indonesia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Balai Inseminasi Buatan Lembang, Jawa Barat (Dr. R.D. Simangunsong)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Directorate of Animal Husbandry, Department of Agriculture, Jl Salemba Raya 16, Jakarta (Dr. Jaman Zailani)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pusat Penelitian den Pengambangan Ternak (Centre for Animal Research and Development), Bogor</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Iraq</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Rearing Station, Abu Ghraib, Baghdad</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Italy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Production and Health Division, FAO,00100 Rome</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associazione Provinciale Allevatori, via Redentare, Caserta (Professore de Franciscis,Presidente)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Instituto de Ricerche soll'Adattamento Bovini e dei Bufali, Ponticelli, Napoli (Director: Pro£ Lino Ferrara)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Instituto Sperimentale per la Zootecnica, via Onofrio Panvino, Rome (Prof. A. Pilla)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Instituto Sperimentale per la Zootecnice di Roma, via Salaria 31, 00016, Monterotondo Scalo (Dr. Augusto Romita)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ugo Jemma, Torre Lupara, 81050 Pastorano, near Caserta</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Japan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. Shimuzu, The University of Tsukuba, Sakura-mura niihar gun ibaraki-ken 300-311</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Malaysia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Animal Husbandry Station, Kluang</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Faculty of Veterinary Medicine and Animal Science, University Pertanian, Serdang, Selangor</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malaysian Agricultural Research and Development Institute, Serdang, Selangor</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Nepal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Artificial Insemination Project, Tfipureshwar, Kathmandu (Dr. A.C. Gupta)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock Division, Khumaltar, Lalitpur, Kathmandu (Dr. N.D. Joshi)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Pakistan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">College of Animal Husbandry, Lahore (Dr. Mohammad Shafi Chaudhry)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Reproduction, University of Agriculture, Faisalabad (Dr. Rashid Ahmad Chaudhary)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock Production Research Institute, Bahadurnagar District, Sahiwat, Punjab (Dr. S.K. Shah, Director)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Punjab Veterinary Research Institute, Lahore 13</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Panama</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hugo Giraoud, Apartado 60-2745, El Dorado</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Primary Industry, ERAP, P.O. Box. 348, Lae (John H. Schottler)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sepik Plains Livestock Station, Ufimo via Wewak, E.S.P.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Philippines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Science Department, Central Luzon State University, Muiloz, Nueva Ecija</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">College of Veterinary Medicine, University of the Philippines Systems, Diliman, Quezon City Dairy Development Division, Bureau of Animal Industry, Sta. Mesa, Metro Manila (Dr. Conrado A. Valdez)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dairy Training and Research Institute, University of the Philippines at Los Banos, College, Laguna 3720  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Science, University of the Philippines at Los Banos, College, Laguna 3720 (Dr. V. C. Momongon)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Documentation Center on Water Buffalo, University of the Philippines at Los Banos Library, College, Laguna 3720  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Philippine Council for Agriculture and Resources Research, Livestock Research Division, Los Banos, Laguna 3732 (Dr. Alfonso N. Eusebio)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Portugal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">W. Ross CockriII, 591 Vale do Lobo, Almansil, Algrave 8100</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Sri Lanka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Animal Production and Health, Peradeniya (Dr. K. Balachandran)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">School of Veterinary Science, University of Sri Lanka, Peradenlya Dr. B.M.A.O. Perrera)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Taiwan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Food and Fertilizer Technology Center, P.O. Box 22-149, Taipei City</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Tanzania</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal Production Department, Faculty of Agriculture, Forestry and Veterinary Medicine, University of Dar es Salaam, Morogoro (M.L. Kyomo)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DAFCO Farm, Ruvu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director, Livestock Development Division, Ministry of Agriculture, Dar es Salaam</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P.M.J. Katyega, Director, Livestock Production Research Institute, Private Bag, Mpwapwa M.M. Oloufa, FAO, Morogoro  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Thailand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kasetsart University, Department of Animal Science, Bangkok (Dr. Charan Chantalakhana) Faculty of Veterinary Science, Chulalongkorn University, Henri Dunant Street, Bangkok 5 (Dr. Maneewan Kamonpatana)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Department of Obstetrics, Gynecology and Reproduction, Faculty of Veterinary Science, Chulalongkorn University, Henri Dunant Road, Bangkok 10500  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FAO Regional Office, Maliwan Mansion, Phra Atit Road, Bangkok 2 (Dr. B. K. Soni)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Office of Livestock Development Project, Tha Phra, Khon Kaen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Buffalo Research and Training Center, Surin</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Trinidad</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Steve Bennett, 61 Mucurapo Road, Port-of-Spain</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Uganda</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">G. L. Corry, Director, Veterinary Research Services, P.O. Box 24, Entebbe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S. Mugerwa, Faculty of Agriculture, MaKerere University, P.O. Box 7062, Kampala</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">United Kingdom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">T. B. Begg, Resident Veterinary Surgeon, Howletts and Port Lympne Estates, Ltd., Port Lympne, Lympne, Kent CT21 4PD  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P. N. Wilson, BOCM Silcock Ltd., Basing View, Basingstoke, Hampshire RG21 2EQ</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">United States</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wyland Cripe, Asst. Dean for Public Services, College of Veterinary Medicine, Box J-125, JHMHC, University of Florida, Gainesville, Florida 32610  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J. Harrington, IRI Research Institute, Inc. One Rockefeller Plaza, New York, New York 10020 James Hentges, Department of Animal Science, Room 2104 McCarty Hall, University of Florida, Gainesville, Florida 32611  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jack Howarth, School of Veterinary Medicine, University of California, Davis, California 95616</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nels M. Konnerup, 609 East Iverson Road, Camano Island, Washington 98292</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A. P. Leonards, P.O. Box 1094, Lake Charles, Louisiana 70602</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">John K. Loosli, Department of Animal Science, Room 2103 McCarty Hall, University of Florida, Gainesville, Florida 32611  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert E. McDowell, Department of Animal Science, Frank B. Morrison Hall, Cornell University, Ithaca, New York 14853  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hugh Popenoe, International Programs in Agriculture, 3028 McCarty Hall, University of Florida, Gainesville, Florida 32611  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">William R. Pritchard, School of Veterinary Medicine, University of California, Davis, California 95616  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Venezuela</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abelardo Ferrer D., Quinta Nueva Exparta, Avenida Jose Felix Rivas, San Bernardino, Caracas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendix C</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Advisory Committee on Technology Innovation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, Chairman  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM BRADLEY, Consultant, New Hope, Pennsylvania</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HAROLD DREGNE, Director, International Center for Arid and Semi-Arid Land Studies, Texas Tech University, Lubbock, Texas  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ANDREW HAY, President, Calvert-Peat, Inc., New York, New York (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CARL N. HODGES, Director, Environmental Research Laboratory, Tucson, Arizona  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CYRUS MCKELL, Institute of Land Rehabilitation, Utah State University, Logan, Utah  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOIS MERGEN, Pinchot Professor of Forestry, School of Forestry and Environmental Studies, Yale University, New Haven, Connecticut  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Consultative Group on International Agricultural Research, Washington, D.C.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THEODORE SUDIA, Deputy Science Advisor to the Secretary of Interior, Department of Interior, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE BUGLIARELLO, President, Polytechnic Institute of New York, Brooklyn, New York, Chairman  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Director, Office of Biological Conservation, Smithsonian Institution, Washington, D.C. (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PEDRO BARBOSA, Department of Entomology, University of Maryland, College Park, Maryland (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FLETCHER L. BYROM, Chairman, Koppers Company, Inc., Pittsburgh, Pennsylvania  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARRISON BROWN, Director, Resource Systems Institute, The East-West Center, Honolulu, Hawaii  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DORIS GALLOWAY, Department of Nutrition Sciences, University of California, Berkeley, California  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MARY E. CARTER, Associate Administrator, U.S. Department of Agriculture, Washington, D.C.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELIZABETH COLSON, Department of Anthropology, University of California, Berkeley, California  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BREWSTER C. DENNY, Dean, Graduate School of Public Affairs, University of Washington, Seattle, Washington (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROLAND I. FUCHS, Chairman, Department of Geography, University of Hawaii at Manoa, Honolulu, Hawaii, ex-officio  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HERBERT I. FUSFELD, Director, Center for Science and Technology Policy, Graduate School of Public Administration, New York University, New York, New York (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MARTIN GOLAND, President, Southwest Research Institute, San Antonio, Texas (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LINCOLN GORDON, Senior Fellow, Resources for the Future, Washington, D.C. (member through September 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JAMES P. GRANT, President, Overseas Development Council, Washington, D.C. (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N. BRUCE HANNAY, Foreign Secretary, National Academy of Engineering, ax-officio  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE R. HERBERT, President, Research Triangle Institute, Research Triangle Park, North Carolina  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM N. HUBBARD, JR., President, The Upjohn Company, Kalamazoo, Michigan (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT N. KREIDLER, Private Foundation Consultant, New York, New York  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RICHARD LASTER, Executive Vice President, General Foods Corporation, White Plains, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN LISTON, Director, Institute for Food Science &amp; Technology, College of Fisheries, University of Washington, Seattle, Washington  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THOMAS F. MALONE, Foreign Secretary, National Academy of Sciences, ex-officio  FRANCOIS MERGEN, Pinchot Professor of Forestry, School of Forestry and Environmental Studies, Yale University, New Haven, Connecticut  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RODNEY W. NICHOLS, Executive Vice President, Rockefeller University, New York, New York (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DANIEL A. OKUN, Department of Environmental Sciences and Engineering, School of Public Health, University of North Carolina, Chapel Hill, North Carolina  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">E. RAY PARISER, Senior Research Scientist, Department of Nutrition and Food Science, Massachusetts Institute of Technology, Cambridge, Massachusetts  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NAMES BRIAN QUINN, Amos Tuck School of Business Administration, Dartmouth College, Hanover, New Hampshire (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PRISCILLA C. REINING, Director, Project on Desertification, International Division, American Association for the Advancement of Science, Washington, D.C. (member through 1980)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH W. RICHARDSON, JR., Department of Horticulture, Pennsylvania State University, University Park, Pennsylvania (member through 1979)  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK SEITZ, President Emeritus, Rockefeller University, New York, New York  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H. GUYFORD STEVER, Consultant, Washington, D.C.  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BILL C. WRIGHT, Program Officer, Africa and the Middle East, International Agricultural Development Service, New York, New York  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">VICTOR RABINOWITCH, Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. C. McDONALD DOW, Deputy Director  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN G. HURLEY, Deputy Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P></FONT>
+<!--
+</Section>
+</Section>
+</Section>
+-->
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b21wae/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b21wae/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b21wae/metadata.xml	(revision 10506)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">The Water Buffalo: New Prospects For An Underutilized Animal (1984) (b21wae)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Animal Husbandry and Animal Product Processing|Cattle</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Animal Husbandry and Animal Product Processing|Other animals (micro-livestock, little known animals, silkworms, reptiles, frogs, snails, game, etc.)</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">BOSTID</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+            <Metadata mode="accumulate" name="dls.Keyword">utilize the Water Buffalo more effectively</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b22bue/b22bue.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b22bue/b22bue.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b22bue/b22bue.htm	(revision 10506)
@@ -0,0 +1,656 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Butterfly Farming in Papua New Guinea </TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Butterfly Farming in Papua New Guinea</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Managing Tropical Animal Resources</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">First Printing, June 1983 </P>
+<P ALIGN="JUSTIFY">Second Printing, May, 1985 </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY">&nbsp;</P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"><A NAME="Acknowledgements"></A></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Acknowledgments</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Report of an Ad Hoc Panel of the Advisory Committee on Technology Innovation </P>
+<P ALIGN="JUSTIFY">Board on Science and Technology for International Development </P>
+<P ALIGN="JUSTIFY">Office of International Affairs </P>
+<P ALIGN="JUSTIFY">National Research Council </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Cooperation with the Insect Farming and Trading Agency, Bulolo, Papua New Guinea </P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY">NOTICE: The project that is the subject of this report was approved by the Governing  Board of the National Research Council, whose members are drawn from the Councils of  the National Academy of Sciences, the National Academy of Engineering, and the  Institute of Medicine. The members of the committee responsible for the report were  chosen for their special competencies and with regard for appropriate balance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been reviewed by a group other than the authors according to the  procedures approved by a Report Review Committee consisting of members of the  National Academy of Sciences, the National Academy of Engineering, and the Institute  of Medicine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The National Research Council was established by the National Academy of Sciences in  1916 to associate the broad community of science and technology with the Academy's  purposes of furthering knowledge and of advising the federal government. The Council  operates in accordance with general policies determined by the Academy under the  authority of its congressional charter of 1863, which establishes the Academy as a  private, nonprofit, self-governing membership corporation. The Council has become the  principal operating agency of both the National Academy of Sciences and the National  Academy of Engineering in the conduct of their services to the government, the public,  and the scientific and engineering communities. It is administered jointly by both  Academies and the Institute of Medicine. The National Academy of Engineering and the  Institute of Medicine were established in 1964 and 1970, respectively, under the charter  of the National Academy of Sciences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Board on Science and Technology for International Development (BOSTID) of the  Office of International Affairs addresses a range of issues arising from the ways in which  science and technology in developing countries can stimulate and complement the  complex processes of social and economic development. It oversees a broad program of  bilateral workshops with scientific organizations in developing countries and conducts  special studies. BOSTID's Advisory Committee on Technology Innovation publishes  topical reviews of technical processes and biological resources of potential importance to  developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report has been prepared by an ad hoc advisory panel of the Advisory Committee  on Technology I innovation, Board on Science and Technology for International  Development, Office of international Affairs, National Research Council. Program costs  for the study were provided by the Office of Technical Resources, Bureau for Asia,  Agency for International Development under Grant No. ASB-0249-SS-00-1026-00 and  the Office of the Science Advisor, Agency for International Development, under Grant  No DAN/5538-GSS- 1023-00.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">First Printing, June 1983 </P>
+<P ALIGN="JUSTIFY">Second Printing, May, 1985 </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Panel_on_Butterfly_Farming_in_P"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Panel on Butterfly Farming in Papua New Guinea</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT M. PYLE, Chairman, Lepidoptera Specialist Group, International  Union for Conservation of Nature and Natural Resources, Gland,  Switzerland, Chairman </P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Director, Office of Biological Conservation, Smithsonian  Institution, Washington, D.C. </P>
+<P ALIGN="JUSTIFY">ARCHIE F. CARR, JR., Professor, Department of Zoology, University of Florida,  Gainesville, Florida </P>
+<P ALIGN="JUSTIFY">F. WAYNE KING, Director, Florida State Museum, C;ainesville, Florida </P>
+<P ALIGN="JUSTIFY">FRANCOlS MERGEN, Pinchot Professor of Forestry, Yale University, New  Haven, Connecticut </P>
+<P ALIGN="JUSTIFY">MICHAEL G. MORRIS, Head of Subdivision of Invertebrate Ecology,  Furzebrook Research Station, Institute of Terrestrial Ecology, Wareham,  Dorset, England </P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University  of Florida, Gainesville, Florida </P>
+<P ALIGN="JUSTIFY">SHELDON R. SEVERINGHAUS, Representative, The Asia Foundation, Taipei,  Taiwan </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Contributors_"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Contributors</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua New Guinea </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PETER CLARK, Manager, Insect Farming and Trading Agency, Bulolo </P>
+<P ALIGN="JUSTIFY">CAROLE GABARA, Wildlife Division, Department of Oro Province, Popondetta </P>
+<P ALIGN="JUSTIFY">WASAM GARARA, Wildlife Division, Department of Oro Province, Popondetta </P>
+<P ALIGN="JUSTIFY">KAROL KISOKAU, Director, Office of Environment and Conservation, Waigani </P>
+<P ALIGN="JUSTIFY">NAVU KWAPENA, Division of Wildlife, Department of Lands and  Environment, Konedobu </P>
+<P ALIGN="JUSTIFY">MIRO LAUFA, Crocodile Section, Department of Lands and Environment,  Konedobu </P>
+<P ALIGN="JUSTIFY">LEO NING, Division of Wildlife, East Sepik Province, Wewak </P>
+<P ALIGN="JUSTIFY">RODERICK ORARI, Butterfly farmer, Popondetta </P>
+<P ALIGN="JUSTIFY">MICHAEL PARSONS, Ecologist, Insect Farming and Trading Agency, Bulolo </P>
+<P ALIGN="JUSTIFY">BLU RAIRI, Butterfly farmer, Maprik  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Countries </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">K. S. BROWN, JR., Department of Zoology, State University of Campinas, Sao  Paulo, Brazil </P>
+<P ALIGN="JUSTIFY">N. M. COLLINS, Co-compiler, Invertebrate Red Data Book, International Union  for Conservation of Nature and Natural Resources, Cambridge, England </P>
+<P ALIGN="JUSTIFY">WAYNE GAGNE, Bishop Museum, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY">ANGUS HUTTON, Garaina Farms, Gympie, Queensland, Australia </P>
+<P ALIGN="JUSTIFY">ASHLEY C. MORTON, Department of Biology, The University, Southampton,  England </P>
+<P ALIGN="JUSTIFY">FRED PARKER, Kirwan, Queensland, Australia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">* * *</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, Professional Associate, Board on Science and Technology for International Development, Butterfly Study Director </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National Research Council Staff </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. R. RUSKIN, BOSTID Editor </P>
+<P ALIGN="JUSTIFY">MARY JANE ENGQUIST, Staff Associate </P>
+<P ALIGN="JUSTIFY">CONSTANCE REGES, Administrative Secretary </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Preface_"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Preface</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly farming is a growing new industry in Papua New Guinea, and by  turning irdwings, mauve swallowtails, and other insects into a cash crop  villagers are both earning money and practicing sound wildlife conservation.  In this unique program butterfly farming is being used to complement the  preservation of species and of habitats. In balancing the utilization of  common butterflies with the protection of the most threatened species, Papua  New Guinea is providing a model for other countries, particularly those in the  tropics. The program demonstrates how village development can become an  integral part of conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel that produced this report convened in Papua New Guinea in  May 1981. Its purpose was to investigate the concepts underlying this  project and to assess their potential for application elsewhere. Panel members  met with staff of the government's Division of Wildlife in Port Moresby and  later visited butterfly farms in Popondetta and the insect trading agency in  Bulolo. The panel is grateful to Karol Kisokau, Navu Kwapena, and Miro  Laufa of the Division of Wildlife for arranging the itinerary in Papua New  Guinea and to Peter Clark and Michael Parsons for hosting the Bulolo and  Popondetta visits.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report is one of the National Research Council series, Managing  Tropical Animal Resources. Current titles in the series are:*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Water Buffalo: New Prospects for an Underutilized Animal (  1981 ) </P>
+<P ALIGN="JUSTIFY">· Little-Known Asian Animals with a Promising Economic Future  (1983) </P>
+<P ALIGN="JUSTIFY">· Crocodiles as a Resource for the Tropics (1983)</P>
+<P ALIGN="JUSTIFY">· Butterfly Farming in Papua New Guinea ( 1983)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These activities have been conducted under the auspices of the Advisory  Committee on Technology Innovation (ACTI) of the Board on Science and Technology for International Development, National Research  Council (see page 29). The purpose of ACT}iS the assessment of  unconventional scientific advances that might prove especially applicable to  problems of developing countries. Since its founding in 1971, it has produced  about 30 reports covering subjects as diverse as ferrocement construction  materials, the winged bean (a high-protein tropical food crop), and techniques  to provide more water for arid lands. This study adds the dimension of  conservation and ecosystem protection to ACTI'S principal concerns of  promising but neglected resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACTI activities are supported largely by the U.S. Agency for International  Development (AID). Program costs for this study were supported by AID'S  Bureau for Asia, and staff costs by AID'S Office of the Science Advisor, which  also made possible the free distribution of this report.  </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY">&nbsp;</P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"><A NAME="BM1_Introduction_and_Summary_"></A></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">1 Introduction and Summary</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The international demand for tropical butterflies is much greater than is  generally recognized. Each year millions of them are caught and sold  throughout the world. Many buyers are scientists engaged in research on  aspects of systematics, ecology, ethology, evolution, and conservation.  Others are individuals who like expensive curios that incorporate butterflies,  such as display cases, coffee tables, wall hangings, or other objects. But  increasingly, the fragile, iridescent creatures, mounted in plastic or glass, are  used to decorate less-expensive items such as purses, trays, platters, screens,  and other common objects in Europe, North America, and Japan. In addition,  amateur butterfly collecting, which reached a peak in Victorian times, is again becoming popular.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All this has produced a strong and active market. The current trade is  estimated to be between US $10 and $20 million annually, and the demand is  rising.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly Farming in Papua New Guinea </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Remote regions of Papua New Guinea are benefiting from this burgeoning  interest in tropical insects, and several hundred villagers are rearing or  collecting butterflies, beetles, and other insects for export. The Papua New  Guinea government now considers insects a national resource, and it has  made butterfly farming part of the nation's village economic development. At Bulolo it has established an Insect Farming and Trading Agency (IFTA) to  handle the business details of a growing international trade. And Papua New  Guinea is the only country so far to specify insect conservation as a national  objective in its constitution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Botanical research is the key to Papua New Guinea's butterfly farming  program. Local botanists and ecologists have identified the plants that the  various butterfly species use during their life cycle. The butterfly farmers  then build up their "livestock" by clearing small areas of ground  and planting leafy food plants for larvae, together with the nectar-producing  flowering plants that adult butterflies feed on. The combination of flowering  and leafy plants provides a complete habitat where butterflies find everything  they need to grow and reproduce. Therefore, most remain, and the farmer  retains his livestock without fences or walls.*</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are among the most unusual farms in the world. Around their edges  are hibiscus and bougainvillea that attract the adult butterflies, whose  mouthparts are adapted for drinking nectar from flowers. And inside are leafy  plants, such as the strange Dutchman's pipe vine (Aristolochia tagala), on  which the caterpillars of several birdwing butterflies feed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The enriched butterfly habitat in the villager's garden attracts and holds a  breeding population that becomes a self-renewing resource. By varying the  plant species the farmer can even maintain colonies of different butterfly  species. And because insects are so prolific, some butterfly farmers are  beginning to have problems with overstocking and have had to shift larvae  from plant to plantrather like moving cattle from one field to the next as the  grazing runs out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic Development </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The IFTA program started in 1974 with fewer than 30 Papua New Guineans  from villages in two provinces. By 1978, more than 500 villagers in 10  provinces had been introduced to farming or collecting butterflies for export.  Since then, business has been increasing about 40 percent a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gram for gram, exotic butterflies are far more valuable than cattle. Prices  paid by dealers in Europe, North America, and Japan range from 30 cents for  individuals of common species to around $10 for the two birdwing species  whose export is allowed. A specimen of a rarer species (for example, a female  of the mauve swallowtail Graphium weiskei) may bring as much as $50.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project is still an embryonic activity; it is not large, as development  programs go. IFTA has only one professional staff person and two local  technicians to handle the distribution of specimens. The agency's goal is to  export between 5,000 and 10,000 specimens a month, from which the villages  can expect a return of $10,000 or more.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agency purchases butterflies from villagers and uses them to fill orders from overseas buyers. Colorful beetles, strange-looking stick and leaf insects, and some moths and cicadas are also caught in the wild and sent to Bulolo. The profits, less 25 percent, are returned to the villagers. At the time of the panel's visit, IFTA had received about 4,000 shipments of butterflies and other insects from the rural people and had paid out about US $180,000 to purchase them. In 1979, the average farmer or collector received about $37 per box of specimens. By 1980, this had risen to about $50 per box. In 1981 it was estimated that a diligent butterfly farmer could earn an annual income of about $1,200.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Even so small an annual income is substantial in rural areas where the mean annual per capita income may be only $50. In many remote areas it is difficult to create income-producing opportunities because of illiteracy, dispersed population, and, in some cases, resistance to foreign ways.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through butterfly farming many rural Papua New Guineans are for the first time participating in a cash economy. The product is a highvalue, low-volume crop. It brings needed or supplementary income to the people of the predominantly rural areas. Compared with farming coffee, another possible industry in Papua New Guinea's rural regions, it requires far less effort or land, and it involves minimal costs to the producer. And where a few expatriate opportunists once made small fortunes exploiting Papua New Guinea's butterflies, the profits now go to the villagers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat loss is by far the most critical issue in butterfly conservation. If habitat changes, the animals must change, leave, or die. Usually they die, since alternative habitats are already occupied or too distant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nearly all the world's butterfly species have suffered diminished ranges, and an estimated half of the world's butterfly populations face threats from human development. From Britain to Bhutan, the insects' habitats have come under siege. In Europe, perhaps one-third of all butterfly species are threatened, owing chiefly to the reductions in their various habitats. In California, half-a-dozen coastal butterflies have been lost since the 1860s, and an equal number are now endangered. In Madagascar and Rwanda, swallowtails and some species that occur nowhere else are being sacrificed to the clearing of forests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The losses are much more than aesthetic, for many butterflies benefit people. They pollinate crops, are a major link in the food chain, and serve as sensitive indicators of ecological health.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A striking feature of the Papua New Guinea butterfly farming program is that it is designed to conserve and increase the species being traded. It is a pioneering conservation effort that has been endorsed by the Lepidoptera Specialist Group of the International Union for Conservation of Nature and Natural Resources. The program helps relieve pressure on endangered populations, because for successful butterfly farms the villagers must retain - and even foster - a healthy wild population on or near their land.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Insect farming also helps preserve habitats because it leaves the bulk of the land intact and it helps landowners earn money without requiring them to cut down the rain forest as they would for timber or for cocoa, coffee, or oil palm plantations. Similarly, villagers can retain their traditional hunting grounds while cropping the insects that rely on these grounds for survival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The existence of the butterfly farming project has served to focus attention on the status of all butterfly species. In 1968 this led to a law banning the taking of even a single specimen of the seven birdwing species threatened with extinction in Papua New Guinea. These large, brilliantly colored creatures can bring as much as $1,000 each in international trade, but there is a stiff fine in Papua New Guinea for even possessing one.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enriching habitats with butterfly food plants (notably the Dutchman's pipe vine, Aristolochia tagala) has greatly increased the numbers of Papua New Guinea's two common birdwing species, Ornithoptera priamus and Troides oblongomaculatus. Now the country is taking on the challenge of increasing the seven endangered birdwing species that are protected and banned from trade. Already the IFTA staff has found that at least one of these rare species (Ornithoptera victoriae) is easily reared on the Dutchman's pipe vine. Farms are now being designed and sited with a view to building up the populations of this giant endangered species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conclusions</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At this stage, the importance of this pioneering activity lies not in its size, but in the new vistas it opens up for the use of tropical resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Village Development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In farming butterflies, Papua New Guinea is showing that indigenous wildlife resources (especially those being depleted because of their commercial value) can contribute to economic development and that the farming of indigenous animals can be fitted smoothly into traditional village life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Providing employment in rural areas is a major problem of developing countries. And in a sense, butterflies are an "appropriate" livestock, particularly for remote areas of the tropics where other income-producing activities are difficult to establish or are harmful to traditional lifestyles and fragile environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterflies may seem unusual farm animals, but to villagers in the Papua New Guinea jungle it is cattle that are exotic. The villagers live in close contact with their local insects; invariably they know much about butterfly locations, behavior, habits, life cycle, and the food eaten by the caterpillars.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Farming butterflies is proving a business to which villagers quickly adapt. Butterflies do not require the equipment or financing of a conventional farm; no capital is required, except for postage on the first shipment of specimens. Insect farming allows people to participate in the cash economy without causing disruptive changes in traditional village life. The villagers can work long and hard if they wish or they can put in only enough time to produce a little cash for necessities, leaving plenty of time for raising crops and other village activities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat Conservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is often claimed that economic development is necessarily destructive to the environment and detrimental to conservation - that as rural societies develop, their natural surroundings must suffer. The Papua New Guinea butterfly farming project is an innovative program that demonstrates this need not be true.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The program also shows that where human needs are given attention, conservation can be successful. Elsewhere in the tropics, attempts to conserve habitat without considering the needs of the people who live nearby have often failed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In sum, the butterfly farming program demonstrates that certain natural resources can be used profitably in a way that protects the environment. The program offers a culturally appropriate use of the land; on a broad scale, it could become a force in preventing clear-felling of the forest for timber exports or the wholesale conversion of rain forest to cash-crop monocultures such as coconut, coffee, or oil palm. Most of Papua New Guinea is still covered by primary rain forest; exploiting the economic value of the insects that live there is helping safeguard this increasingly rare habitat, which is fast disappearing in most parts of the tropics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Species Conservation </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The knowledge gained from farming Papua New Guinea's butterflies has already contributed to relieving the threat of extinction from seven endangered species of birdwings. This experience could be replicated in other places where there are endangered butterfly species. Indeed, the program provides a model for nations that could profitably farm butterflies while protecting their threatened butterfly species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Extension to Other Organisms</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This project has a strategy and organizational structure that could well be applied to plants, such as rare orchids, and animals, such as crocodiles, that are endangered because of their commercial value. Indeed, using similar concepts of combining village income and conservation, the Papua New Guinea Division of Wildlife is farming crocodiles,* ruse deer, wallabies, and two native birds, the megapode and cassowary.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through such husbandry practices, many species elsewhere might be saved from extinction, while providing income to the local people who traditionally have used the resource. Other countries should look with interest at the way Papua New Guinea is handling its wildlife enterprises. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="BM2_Butterfly_Status_and_Conserva"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">2 Butterfly Status and Conservation</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">About 100,000-150,000 species of butterflies have been described; perhaps half that number remain to be discovered. Although there are important concentrations in the Arctic and temperate regions, most species are found in the tropics. There, the diversity of colors and forms is dazzling; every imaginable combination of hue and color is displayed. And many tropical butterflies are enriched with "structural" colors, which cause the wings to flash iridescently in the sun as they bend the light they reflect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although butterflies have long been admired and often depicted in art, they have been seriously studied only since the end of the seventeenth century. Linnaeus, in his Systema Naturae, placed the small number of butterflies then known in the single genus Papilio. Today that genus is restricted to the true swallowtails, and more than 700 genera of butterflies are recognized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Butterfly Trade</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Last century, as knowledge of butterflies grew and methods of preserving them improved, they become popular collectors' items. Wealthy naturalists such as Rothschild and LeMoult dispatched collectors to all parts of the world for specimens. Today the trade in butterflies is even more extensive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are three major kinds of butterfly and insect trade. In one, large numbers of common species are collected in the wild and processed for use in ornamental objects such as coasters, mats, and lampshades. This is a low-value, high-volume industry that is both labor- and capital-intensive. It frequently uses "chipped" or slightly damaged butterflies. It often sells butterflies with paper bodies and only the wings of actual insects, which seem to be acceptable to a large part of the buying public.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Taiwanese butterfly trade is an example. It operates on a large scale. At least a dozen Taiwanese factories employ scores of workers to capture and process butterflies. Estimates of annual sales vary from 15 million to 500 million butterflies. Taiwanese butterfly wings pasted onto paper bodies with pig-bristle antennae are used in ornaments and household objects from wall hangings to clear-plastic toilet seats. The bodies are recycled as pig feed. Despite this massive trade, Taiwan's wild butterfly populations seem to be remaining steady.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Similar, though smaller, industries trafficking in common butterflies are found in Korea, Malaysia, Hong Kong, Brazil, Honduras, and several African nations. The famous blue morpho butterflies of the American tropics enter the trade at the rate of some 50 million per year. Nearly all of these are the brilliant iridescent males, and biologists believe the number sold could be doubled without harming the overall population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second type of trade involves higher value and lower volume. This produces a vastly different product from the paper-bodied butterflies bound for novelty stores. It is exemplified by the operation in Papua New Guinea where sales are to collectors, museums, and students, and the specimens are high-quality insects in good to perfect condition, usually bearing scientific data. Because of the relatively high value per specimen, this trade can be carried on by fewer individuals in a nonfactory setting, and it is well suited to village industry, provided there is supervision and a quality-control checkpoint.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The third type of butterfly trade is for high-quality, expensive ornamental items, such as glass cases, domes, wall mounts, or jewelry containing beautiful insects. Brazil, for example, has a thriving jewelry trade based on the iridescent blue morpho butterfly. This type of trade can also furnish high-paying outlets for village-farmed insects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p08.png"></center><br>
+ Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In all three divisions of the butterfly trade, dealers fulfill an essential role. Few collectors and scientists can travel the world collecting their own specimens. Some dealers have established reputations for honesty, some have not. Exploitation of suppliers and customers alike has been rife. Few dealers are careful to attach accurate locality data to their specimens; some make serious mistakes in identifying them. (To combat this problem, British insect dealers have formed an association to monitor conservation-related activities and improve professional practice.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Generally, dealers supply specimens bred from the caterpillar or chrysalis and described as "ex pupa." Unless butterflies are caught immediately after emerging from the pupa the fragile wings tear and the scales detach to produce "worn" specimens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly Taxonomy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Classifying butterflies is difficult. Their most obvious features, the color and pattern of the wings, vary greatly; individuals and populations of the same species often look quite different. This has led to the dubious naming of many species and subspecies. And the uncertainties it causes have led some biologists, especially those working in ecology and genetics, to name populations rather than species or subspecies. However, populations frequently evolve, and this introduces a further uncertainty. Much additional work on basic butterfly systematics is needed. The knowledge gained should contribute particularly to the conservation of endangered species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly Conservation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly conservation is still in an early state of development, bedeviled by scarce or incomplete information. The conservation status of even the most thoroughly studied butterfly species is known in only a few areas. The distribution and status of most species is essentially unknown, and proposals for conservation measures are largely based on guesswork. Nevertheless, some conservation programs have been enacted. Most have concentrated on designating endangered species and banning their collection.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The greatest threat to butterflies and other insects, however, is habitat alteration. On several continents some species have already become extinct or endangered when humans altered the special environment they require. The importance of protecting butterfly habitats should not be underrated. Many species are restricted to very small areas, particularly to individual islands (Corsica, Sardinia, Jamaica, Madagascar, Sumba, the Comoros, Fiji, the Solomon Islands, Manus, and the Duke of York Islands, for instance). Such species are vulnerable to extinction because nearly all island habitats are fragile and are changing rapidly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it is uncommon for insect species to be dangerously reduced merely by the capture of specimens, renewed commercial interest in butterflies gives rise to concern for their conservation. Most insects reproduce rapidly, and their high fecundity enables them to replace such losses in a generation or two - provided the basic environment has not been altered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But there are certain species of butterfly that reproduce slowly and are therefore more threatened by collection. The unusual birdwing butterflies of New Guinea, for example, produce only small broods. Moreover, these rare species command higher prices. Because this makes them particularly vulnerable, legislation to protect birdwing butterflies has been instituted in both parts of New Guinea - Papua New Guinea and Irian Jaya.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Accordingly, to save Queen Alexandra's birdwing (the largest and most threatened of the birdwings) from extinction, several wildlife management areas have been set up in Popondetta on Papua New Guinea's north coast. The government is also setting up refuges, administered by village councils, to preserve and protect other birdwing butterflies and wildlife resources. This habitat conservation is an important adjunct to the butterfly farming program. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="BM3_History_and_Government_Policy"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">3 History and Government Policy</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Soon after Europeans discovered New Guinea's remarkable insect fauna around the turn of the century, collectors began arriving, and they have been coming ever since. Many were reputable professional or amateur scientists, gathering modest numbers of specimens for study and for museums, including Papua New Guinea's own national collection. Others, however, were plunderers who carried away large numbers of rare butterflies, giving little or no compensation to the local people and showing no concern for survival of the species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1966 the Papua New Guinea government responded to excessive collecting by designating seven rare birdwing butterflies as protected species. It became illegal to collect these huge, colorful birdwings, and strong measures were instituted - fines for nationals, deportation of expatriates - to halt black market trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the late 1960s and early 1970s commercial collecting of the other butterfly species continued piecemeal and unsupervised. Income was erratic, and expatriate dealers often paid their Papua New Guinean suppliers only a few cents for specimens that retailed for several hundred dollars in Europe and Japan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Insect Farming and Trading Agency</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When Papua New Guinea achieved independence in 1975, the new government decreed that only nationals should profit from the country's butterfly resource. Since that time only Papua New Guineans have been able to export butterfly specimens (nonprotected species) for profit. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1978, to guarantee Papua New Guineans fair prices and stable sales, a marketing agency was established. Its purpose was to protect the resource, to foster butterfly farming, and to ensure a high-quality export product.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Modest in its beginnings, the Insect Farming and Trading Agency (IFTA) was organized by Angus Hutton, a former tea planter and amateur lepidopterist. The business side of the agency was later developed by Peter Clark, who had worked with Hutton. Identification and production of food plants was advanced by Michael Parsons, Robert Pyle, and others.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IFTA provides a market for those Papua New Guinea nationals who farm and collect butterflies and other insects. The agency allows them to obtain fair and fixed prices, maintains quality control, and ensures that current data accompanies all specimens. It also pools the insects from many sources and fills large orders from overseas dealers. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of the butterflies IFTA exports, about 30 percent are from village farms and 70 percent are collected in the field. However, more than 50 percent of the revenue is made up of the farmed butterflies because of their better quality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Quality Control</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agency strives to sell only highest-quality insects; it rejects many butterflies as substandard. Most specimens are sold as named subspecies and to identify and name them requires much skill. Staff members have been specially trained to do this. (To a large extent, the area of origin, particularly in the case of the offshore islands, defines the subspecies concerned.) Locality data, usually consisting of village, province, and month and year of collecting or emergence, is affixed to all butterfly envelopes before they are pooled at the agency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IFTA stores its collection by species, in simple wooden boxes kept in cupboards lit from below (to lure potential pests away from the insects and to warm the cupboards and prevent mold). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Marketing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agency makes up orders and dispatches them (with the required export permits) to customers "on trust." Although this is open to abuse, most buyers pay promptly and the system is easy and convenient. Careful records are kept of all suppliers, customers, and species in stock.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the time of the panel's visit, about 80 percent of the agency's business consisted of responding to requests from dealers. However, less than 10 percent of the orders received from all sources could be filled.Some requests were too small and others too specialized; in some cases the agency simply didn't have the specimens on hand (for example, a request for all the subspecies of a given butterfly). Furthermore, the agency has neither the office staff nor space to cope with every order in a business whose volume is almost doubling every two years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Field Extension</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wildlife extension officers periodically visit clients and new villages to sustain or develop enthusiasm for insect farming. They explain and demonstrate the procedures of butterfly farming and collecting and teach potential farmers how to recognize a valuable species in each of its life stages. Above all, they demonstrate how to prepare specimens for sale. This is because it is often difficult to convince farmers of the need for extreme care and delicacy in handling, and many inexperienced farmers send in bruised or hopelessly damaged specimens. Although about 500 villagers were farming butterflies at the time of the panel's visit, fewer than 50 were supplying good material regularly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These contacts are also important because the butterfly farmers easily become discouraged if no interest is shown in their work. In the Papua New Guinea countryside there is often little need for cash; people can obtain all their food, clothes, shelter, and resources from their gardens or from the bush. Money received from one shipment of butterflies may last a subsistence farmer for months, making it difficult for the agency to sustain his interest in providing regular shipments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agency's extension officers have initiated a number of butterfly farming projects at primary, secondary, and vocational schools. These projects have proved most successful. Apart from the practical education they give students, they provide early insight into one of Papua New Guinea's most useful resources. Several vocational schools also provide training in mounting butterflies and beetles as souvenirs for tourists, as well as in the construction of hatching cages and solar driers. Beautiful wooden cabinets to hold butterflies have also been made by some teenage students.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research and Monitoring</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to teaching Papua New Guineans to collect and farm insects, IFTA promotes research both to conserve species and to make them available in quantity. Success has already been achieved in farming the common birdwing butterflies by planting large numbers of the Dutchman's pipe (Aristolochia tagala) vines that they feed on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agency's staff includes an ecologist, indicating the importance of the scientific basis for conservation in this project. The ecologist is at hand to conduct research on life histories, farming methods, and management measures for rare species.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">IFTA staff are now identifying new food plants that will permit more species to be farmed. Research into the life histories of many butterflies with economic potential is well under way, so that an increasing number of species will become "farmable" and will be available in future in perfect ex pupa condition. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sources of all specimens received by IFTA are recorded on a map so that a butterfly's range and rarity or abundance can be assessed and conservation measures implemented where necessary. In this way, even insects too damaged for sale at least have value to conservation efforts. All specimens of unusual scientific interest are lodged in the national insect collection for future study. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="BM4_Operating_a_Butterfly_Farm"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">4 Operating a Butterfly Farm</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Planting the Farm</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The key to farming butterflies is to establish a garden of the plants the various species need for their life cycles. The ideal farm area is about 0.2 hectares. This is spacious enough for growing food plants for adults and larvae and small enough to keep the plants watered, weeded, pruned, and generally well tended. Such a farm can contain about 500 vines, grown like bean plants on poles or shade trees.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important to surround the site with a thick hedge of hibiscus, bougainvillea, ixora, poinsettia, or other nectar-bearing plants whose flowers attract adult butterflies and encourage them to remain in the area. The hedges also keep out pigs and other livestock that may damage the leafy plants inside the farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A good way to start a farm is to establish it in a vegetable garden. (Papua New Guinea butterfly farmers often plant butterfly vines between their rows of sweet potato or tarot) By the time the vegetables are ready to harvest, the area already has some thriving butterfly food plants and probably some winged livestock as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most successful butterfly food plants in Papua New Guinea is Aristolochia tagala, a vine on which the larvae of more common birdwing butterflies feed. Another is Evodea - a food plant of the large blue ulysses swallowtail and many colorful weevils.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shade trees also can be food plants for butterflies other than birdwings and for beetles or weevils. Examples are species of Annona (such as soursop), Citrus (such as lemon), Cerbera, and Graptophyllum. Wallace's Longhorn Beetle feeds on breadfruit (Artocarpus communis). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Normally, one area of the farm is kept aside for growing seeds or cuttings. (IFTA sells seed of some suitable species.) In this nursery the butterfly food plants are watered and cared for, and unhealthy ones are easily spotted and weeded out. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p16.png"></center><br>
+ Stylized diagram of a butterfly farm:</P>
+<P ALIGN="JUSTIFY">A Hedge of hibiscus, ixora, and poinsettia to keep pigs out and provide nectar.</P>
+<P ALIGN="JUSTIFY">B Fruits trees (such as lemon).</P>
+<P ALIGN="JUSTIFY">C The aristolochia vine grown on the branches of others trees (such as leucaena), to feed    caterpillar larvae.</P>
+<P ALIGN="JUSTIFY">D Nursery area.</P>
+<P ALIGN="JUSTIFY">E A hut for tools.</P>
+<P ALIGN="JUSTIFY">(Diagram courtesy IFTA, Bulolo)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Life Cycle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Normally, each butterfly species has a preferred food plant for its larvae. After the female has mated she searches for the correct plant and lays her eggs on or near it. In a few days the eggs hatch, and the young caterpillars usually eat their own eggshells and begin feeding on the softer leaves and shoots of the food plant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As they grow, the caterpillars shed their skins. Each molt is called an instar, and five instars occur before a larva is big enough to pupate. Pupation is a resting stage during which the adult butterfly develops inside the hard, protective chrysalis. For pupation the larva selects the underside of a stem or leaf to protect it from rain and predators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After 10 days to 3 weeks, depending on the type of butterfly, the pupal case splits open and the adult insect emerges. This usually occurs before 9 o'clock in the morning. The freshly emerged adult then takes from 3 to 4 hours to expand and dry its wings before flying off to feed on nectar and to search for a mate to begin the life cycle once again. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Harvesting</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Once the farm is well established, pupae can be collected daily. Ideally, about 50 percent should be left or released. At least as many females as males should be released. Pupae that are too high to reach are usually left to emerge naturally and repopulate the farm. Others are left because they are not quite perfect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The farmer can usually see that emergence will occur on the next day, since the pupa becomes darker in color as the adult wing and body colors develop. He then plucks off the stem or leaf to which the pupa is attached. (The soft, new pupae are not touched because this damages the adult.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He pins the leaf to a board or puts it in a net or in a small cage. Often these are kept inside to protect the pupae against pests and large predators. However, some farmers construct small houses out of bush materials to hold pupae ready for hatching. Others keep their pupae in the open and count on being able to collect the adults before they have flown away.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Care is taken to protect the specimens from ants and rats. For example, the legs of the cage are placed in bowls of water to deter ants from climbing up. The pupae are sprayed with water 2-3 times a week to speed up the hatching process and to prevent them from drying out. (Only a light spray is used; otherwise the pupa develop mold.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The pupae are best kept in a shady place so the butterflies will remain calm after hatching and will not flap and damage their wings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Processing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the newly emerged butterfly has completely dried its wings, it is carefully caught by the thorax and injected with a small amount of a killing agent such as ethyl acetate or boiling water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small butterflies are particularly easily damaged if handled, so they are placed for about 10 minutes in a killing jar containing cotton (cotton wool) soaked with a little ethyl acetate. A layer of cardboard is placed above the cotton so that the butterflies are not stained by the solvent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The farmer places the dead butterflies in paper envelopes, being careful at all times not to touch or damage the wings. The envelopes are easily made from grease-proof paper, which the agency supplies on request.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To ensure that the butterflies will not mold, they are placed on a black plastic tray and dried in the sun, in their papers, for about 4 days. During this time they are protected from pests such as ants, and the drying trays have a screen on top to prevent the envelopes from blowing away or from being rained on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Once properly dried, the insects, still in their envelopes, are stored in boxes, preferably airtight to prevent condensation and molding. When enough specimens have been collected, the villager packs them carefully in strong cardboard boxes (which the agency also supplies) with cotton or kapok. A few naphthalene crystals are added to keep away pests, and the box is wrapped and sent to Bulolo. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="BM5_Application_to_Other_Nations"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">5 Application to Other Nations</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As noted, the essence of the Papua New Guinea approach is the cultivation of food plants that the butterflies need to complete their life cycles. This is a process that could be replicated elsewhere, and the potential for butterfly farming exists in many countries. In fact, although Papua New Guinea is rich in butterfly species - some 700 of them - it is not unusually so. Other countries also have large numbers of species. There are, for instance 2,500 species known in Costa Rica.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are some 14,000 species of true butterflies in the world. Although there is possible competition, many countries have no overlap in species at all. As collectors and specialists usually want butterflies from many different parts of the world, the likely competition among countries exporting farmed or wild-caught butterflies is minimal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterflies are supplied to the trade from nearly every part of the world. But because they are most diverse in the tropics, it is likely that the best chance for success in farming them lies there. However, some temperate countries also have an abundance of particular species, and in Europe, the United States, and Japan, butterfly farming is already established on a small scale. This is mainly because many collectors like to rear their own material and they purchase eggs, caterpillars, or chrysalids instead of killed adults. Many dealers in these countries supply a few tropical species that are easy to rear, such as the orchard swallowtail (Papilio aegeus). However, this trade is generally low in volume and value, and temperate-zone butterfly farms are little more than a sideline to normal dealerships.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some general comments follow on the potential of butterfly farming in various parts of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Temperate regions of the Old World (Palaearctic Realm). East palaearctic species are in great demand internationally and obtainable with great difficulty. China, in particular, has species of both Parnassius and Papilio that might be farmed. However, all Parnassius species are montane to some degree and none has been farmed yet. Eurasian arctic satyrids, lesser fritillaries, and sulphurs are also in great commercial demand and could perhaps be farmed. Swallowtails are few and are frequently protected.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Tropical Africa and associated islands (Afrotropical Region). The potential for butterfly farming has not yet been considered in Africa, although the diversity of desirable species is great and the potential market extensive. This area has important swallowtails and Charaxes species (Nymphalidae), but so far as is known, no farming enterprises exist. Experimental or trial farms for butterflies are needed in different parts of Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Indian subcontinent and Southeast Asian tropics (Oriental Realm). Silk moths, such as Bombyx mori, are commercially farmed in Asia, and butterfly farming would seem to be a natural extension of this. Many Asian butterflies are supplied to dealers, especially from Taiwan and the Philippines, but there is little farming. A very large trade originates in Malaysia, especially for Rajah Brooke's birdwing (Trogonoptera brookiana). Farming is reputed to take place, but most specimens are actually collected. Desirable species of swallowtails, including the black and gold birdwings (Troides species), occur throughout the region. Species belonging to the families Nymphalidae and Pieridae are good candidates for farming, as they are in much demand from dealers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Australia, New Guinea, and associated islands to the west (Australasian Realm). Australia is not rich in butterflies, but it has some important endemic species. At least one "farm" exists in Australia, but this appears to be an offshoot of a normal dealership, which rears a few local species to supply at early stages to collectors. Farming is to be encouraged here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Guinea's most coveted butterflies, which it shares with Irian Jaya, are the Ornithoptera birdwings. But almost equally desired by collectors and specialists are the Troides birdwings, concentrated to the west of New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Temperate regions of the Americas (Nearctic Realm). There is a considerable trade in New World butterflies from nearly every family (few Lycaenidae and Hesperiidae), but almost all are caught in the wild. There is a strong market for far-northern species (Boloria, Colias, Erebia, Oenesis). Farming these might be possible among Canadian and Alaskan Indian or Eskimo groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Tropical regions of the Americas (Neotropical Realm). This is a likely area for the development of butterfly farming, particularly as its species are completely different from those of the tropics elsewhere. The Morpho and Agrias species of South America are much desired by collectors. It is possible that some of the highly prized morpho butterflies are already farmed (as the law, in fact, requires), but evidence is conflicting, and most biologists believe that the major supply of specimens is from wild populations. Other groups that lend themselves to farming include the swallowtails, nymphalids (including Agrias), and certain members of the family Satyridae. There are large fauna of Riodinidae and Lycaenidae that are potentially suitable for farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A dealer in preserved butterflies has recently set up business in the Dominican Republic, and butterfly farms have been established in Costa Rica.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· General. Butterflies in the family Riodinidae and, especially, Lycaenidae seem to be a neglected resource. Many species are relatively small but brightly colored. A major difficulty is that many Lycaenidae have to live with ants for part of their lives and this complicates their rearing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly Parks</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some regions with tourist industries are showing interest in establishing "butterfly zoos" or "butterfly jungles." These displays have live butterflies (usually farmed or reared) in artificial habitats resembling the natural ones. Some species, such as the orchard swallowtail (Papilio aegeus), respond well to such conditions. One British dealer has a "tropical jungle" in an enclosed environment in which both temperature and atmospheric pressure are regulated. A large British butterfly zoo has been established and a smaller one has been proposed. The New York Zoological Society is developing a butterfly component in its Wild Asia Hall at the Bronx Zoo, and San Francisco, Portland, Cincinnati, and Tokyo all have thriving insect zoos. Also, the Colombo Zoo in Sri Lanka has a live display and a successful program of butterfly rearing. Similar enterprise could be shown in other places with tourist industries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Starting a Butterfly Farm</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Butterfly farming is initially an ecological and botanical challenge. One must first observe, identify, and propagate the plants that the various species use for food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Success for butterfly farmers rests on their choosing commercially attractive species. Unfortunately, ecological details of the life histories of suitable species are known in only a few cases. The prospective farmer will be largely on his own and must first develop this information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of the most desirable species are native to primary tropical forests, and they may need protection because of the rate at which their habitat is being destroyed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any program to commercially exploit butterflies and other insects must either bypass the rarest, most restricted, and slowest reproducing species; farm them cautiously with a high percentage of adults released; or take them with the greatest of care. Further, there must be adequate habitat protection both in the natural state and in mixed land uses (rather than just agricultural croplands) to support the insects and furnish a continuing supply.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some competition could occur if live butterflies were exported between countries and used to establish farming enterprises. In general, however, butterflies are easier to farm in their native habitats. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Appendix_A"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendixes</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">A Selected Readings</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Carvalho, J. C. M., and O. H. H. Mielke. 1972. The trade of butterfly wings in Brazil and its effect upon survival of the species. Proceedings 19th International Congress of Entomology (Moscow) 1 :486-488.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fenner, T. L. 1976. Aspects of butterfly conservation in Papua New Guinea, Pp. 121-127 in Ecology and Conservation in Papua New Guinea, K. P. Lamb and J. L. Gressitt eds. Pamphlet 2. Wau Ecology Institute, Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parsons, M. n.d. Insect Farming and Trading Agency Farming Manual. Insect Farming and Trading Agency, Division of Wildlife, P.O. Box 129, Bulolo, Morobe Province, Papua New Guinea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pyle, R. 1981. Butterflies: now you see them.... International Wildlife I I (1):4- 11.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pyle, R., M. Bentzien, and P. Opler. 1981. Insect conservation. Annual Review of Entomology 26:233-258.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pyle, R. M. and S. A. Hughes. 1978. Conservation and utilization of the insect resources of Papua New Guinea. Unpublished report, copies available from the author, see Research Contacts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Severinghaus, S. R. 1977. The butterfly industry and butterfly conservation in Taiwan. Atala 5(2):20-23.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unno, K. 1974. Taiwan's butterfly industry. Wildlife 16: 356-359.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vietmeyer, N. D. 1979. Butterfly ranching is taking wing in Papua New Guinea. Smithsonian 10(2):119-135. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Appendix_B"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendix B</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Research Contacts</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wayne Gagne, Bishop Museum, P.O. Box 6037, Honolulu, Hawaii, 96818 USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angus Hutton, Garaina Farms, Scrubby Creek Road, Gympie 4570, Queensland, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Insect Farming and Trading Agency, P.O. Box 129, Bulolo, Morobe Province, Papua New Guinea (Peter Clark, Manager; Michael Parsons, Ecologist)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Karol Kisokau, Director, Office of Environment and Conservation, Central Government Offices, Waigani, Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Navu Kwapena, Division of Wildlife, Department of Lands and Environment, Konedobu, Papua New Guinea</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rudi Mattoni, 9620 Heather Road, Beverly Hills, California 90210, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Michael G. Morris, Chairman, Butterfly Specialist Group, International Union for Conservation of Nature and Natural Resources, Furzebrook Research Station, Institute of Terrestrial Ecology, Wareham, Dorset BH20 5AS, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ashley C. Morton, Department of Biology, Building 44, The University, Southampton S09 5NH, England</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fred Parker, 717 Ross River Road, Kirwan, Queensland 4814, Australia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert M. Pyle, Chairman, Monarch Project, Xerces Society, 369 Loop Road, Gray's River, Washington 98621, USA</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sheldon R. Severinghaus, Representative, The Asia Foundation, 42, Chien Kuo North Road, Taipei 104, Taiwan, Republic of China </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Appendix_C"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Appendix C</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Biographical Sketches of Panel Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EDWARD S. AYENSU, Director of the Office of Biological Conservation, Smithsonian Institution, Washington, D.C., is currently the Secretary-General of the International Union of Biological Sciences. He received his B.A. in 1961 from Miami University in Ohio, M.Sc. from The George Washington University in 1963, and his Ph.D. in 1966 from the University of London. His research interests are in comparative anatomy and phylogeny of flowering plants, commercial timbers, histology of monocotyledons, economic botany, and tropical biology. An internationally recognized expert on tropical plants, he has published extensively in these areas and on topics relating to science, technology, and development, especially in developing countries. Dr. Ayensu was co-chairman of the Panel on Under exploited Tropical Plants of the Advisory Committee on Technology Innovation and chairs and serves as a member of many international bodies. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ARCHIE F. CARR, JR., is Graduate Research Professor in the Department of Zoology, University of Florida, Gainesville. As Technical Director of the Caribbean Conservation Corporation, he has directed a seasonal research program at the breeding ground of the green turtle at Tortuguero, Costa Rica, since 1952, with continuous grants from the National Science Foundation from 1955 to 1980, and has carried out investigations of marine turtle ecology and navigation in various parts of the world. The author of numerous papers, articles, and books, he received the Daniel Giraud Elliot Medal of the National Academy of Sciences for Handbook of Turtles and the John Burroughs Medal for The Windward Road. He is Research Associate of the American Museum of Natural History; Affiliate Curator of Natural Sciences, Florida State Museum; Chairman of the Marine Turtle Specialist Group of the Survival Service Commission, International Union for the Conservation of Nature; Honorary Consultant of the World Wildlife Fund; Fellow of the Linnean Society of London; Fellow of the American Fisheries Society; and a member of Phi Beta Kappa and Sigma Xi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1973 he was awarded a gold medal from the World Wildlife Fund for the application of scientific findings to the conservation of marine turtles. In 1975 he received the Edward W. Browning Award for achievement in biological conservation. In 1978 Dr. Carr was awarded the Gold Medal of the New York Zoological Society for contributions to natural science and conservation; in 1978 he became Officer of the Order of the Golden Ark (The Netherlands).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F. WAYNE KING is the Director of the Florida State Museum, Gainesville. He received a B.S. in 1957 and an M.S. in 1961 from the University of Florida and a Ph.D. from 1966 from the University of Miami. His research interests are in wildlife conservation and habitat preservation, impact of international trade on wildlife populations, and ecology and behavior of reptile populations. He worked at the New York Zoological Society from 1967 to 1975. As an international wildlife consultant, Dr. King has received honors from the Dominican Republic, the American Association of Zoological Parks and Aquariums, and from H.R.H. Prince Bernhard of The Netherlands. He has served on committees advising the State Department and the International Union for Conservation of Nature and Natural Resources on policies regarding the trade of crocodile skins, turtle products, and other wildlife materials. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOlS MERGEN, Pinchot Professor of Forestry and Professor of Forest Genetics, Yale University, was Dean of the School of Forestry and Environmental Studies at Yale from 1965 to 1975. He received a B.A. from Luxembourg College and a B.Sc.F. from the University of New Brunswick in 1950, an M.F. in ecology in 1951, and a Ph.D. in forest genetics from Yale in 1954. He is especially knowledgeable about francophone Africa and was chairman of the Sahel program of the Board on Science and Technology for International Development and a member of the Advisory Committee on Technology Innovation. From 1960 to 1965 he was research collaborator at the Brookhaven National Laboratory. In 1966 he was the recipient of the Award for Outstanding Achievement in Biological Research from the Society of American Foresters and in 1975 was Distinguished Professor (Fulbright-Hays Program) in Yugoslavia. Before joining the Yale faculty, he served as project leader in forest genetics for the U.S. Forest Service in Florida. He has served as a consultant to FAO, various foreign governments, and private forestry companies, and he has traveled extensively in the tropical countries of Asia, Africa, and Latin America. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. MORRIS is head of the Furzebrook Research Station of the Institute of Terrestrial Ecology (National Environment Research Council, U.K.). He received a B.A. in natural sciences (zoology) at the University of Cambridge of 1958, M.A. in 1962, and received his Ph.D. from London University in research on the integrated control of orchard pests. Dr. Morris worked at Monks Wood Experimental Station on the effects of grassland management on populations of invertebrates and developed a strong interest in community and applied ecology, particularly the conservation of insect populations. Recently he has become involved with problems of butterfly conservation and resource utilization. He is Secretary of the Joint Committee for the Conservation of British Insects, a Vice-Chairman of the Lepidoptera Specialist Group of lUCN'S Survival Commission, and Chairman of the Habitat and Species Protection Committee of SEL (Societal Europaea Lepidoptero-Logica). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH L. POPENOE is Professor of Soils, Agronomy, Botany, and Geography and Director of the Center for Tropical Agriculture and International Programs (Agriculture) at the University of Florida. He received his B.S. from the University of California at Davis in 1951 and his Ph.D. in soils from the University of Florida in 1960. His principal research interest has been in the area of tropical agriculture and land use. His early work on shifting cultivation is one of the major contributions to this sytem. He has traveled and worked in most of the countries in the tropical areas of Latin America, Asia, and Africa. He is past Chairman of the Board of Trustees of the Escuela Agricola Panamericana in Honduras, Visiting Lecturer on Tropical Public Health at the Harvard School of Public Health, and a Fellow of the American Association for the Advancement of Science, the American Society of Agronomy, the America Geographical Society, and the International Soils Science Society. He is Chairman of the Advisory Committee for Technology Innovation and a member of the Board on Science and Technology for International Development. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT MICHAEL PYLE, a writer and consulting lepidopterist based in Gray's River, Washington, has served since 1979 as Co-Compiler of the lUCN Invertebrate Red Data Book. In this capacity he is consultant to the Conservation Monitoring Centre in Cambridge, England. After receiving his B.S. and M.S. at the University of Washington, he took his Ph.D. through the School of Forestry and Environmental Studies at Yale University in 1976. He worked for the Government of Papua New Guinea on the conservation and utilization of insect resources and then with the Nature Conservancy as Northwest Land Steward. A </P>
+<P ALIGN="JUSTIFY">former Fulbright Scholar to the United Kingdom, Dr. Pyle subsequently founded the Xerces Society for conservation of beneficial insects and their habitats. He has been chairman of IUCN'S Lepidoptera Specialist Group (Species Survival Commission) since 1976. His publications include the Audubon Society Field Guide to North American Butterflies. A comprehensive book on insect conservation in his next project.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SHELDON R. SEVERINGHAUS received his Ph.D. from Cornell University in 1977 in natural resources management. He has worked on various wildlife research projects in Asia since 1964 and is representative for the Asia Foundation in Taiwan. He has published articles on butterfly conservation and wildlife industries in Taiwan, where he has been studying the butterfly and wildlife farming projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NOEL D. VIETMEYER, staff officer for this study, is Professional Associate of the Board on Science and Technology for International Development. A New Zealander with the Ph.D. in organic chemistry from the University of California, Berkeley, he now works on innovations in science that are important for developing countries. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Advisory_Committee_on_Technolog"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Advisory Committee on Technology Innovation</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM BRADLEY, Consultant, New Hope, Pennsylvania </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HAROLD DREGNE, Director, International Center for Arid and Semi-Arid Land Studies, Texas Tech University, Lubbock, Texas (member through 1981) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L.GADEN,JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CARL N. HODGES, Director, Environmental Research Laboratory, Tucson, Arizona </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CYRUS MCKELL, Native Plants, Inc., Salt Lake City, Utah </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FRANCOIS MERGEN, Pinchot Professor of Forestry, School of Forestry and Environmental Studies, Yale University, New Haven, Connecticut (member through 1982) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DONALD L. PLUCKNETT, Consultative Group on International Agricultural Research, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THEODORE SUDIA, Deputy Science Advisor to the Secretary of Interior, Department of Interior, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+</FONT><FONT FACE="Arial" SIZE=2 COLOR="#0000ff"><P ALIGN="JUSTIFY"><A NAME="Board_on_Science_and_Technology"></A></P>
+</FONT><B><FONT FACE="Arial" SIZE=2><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Board on Science and Technology for International Development</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE BUGLIARELLO, President, Polytechnic Institute of New York, Brooklyn, New York, Chairman </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Members</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SAMUEL P. ASPER, Educational Commission for Foreign Medical Graduates, Philadelphia, Pennsylvania </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DAVID BELL, Department of Population Sciences, Harvard School of Public Health, Boston, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LEONARD BERRY, Professor, Graduate School of Geography, Clark University, Worcester, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ERNEST J. BRISKEY, Dean, School of Agriculture, Oregon State University, Corvallis, Oregon </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HARRISON S. BROWN, Director, Resources Systems Institute, East-West Center, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROBERT H. BURRIS, Department of Biochemistry, University of Wisconsin, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CLAUDIA JEAN CARR, Associate Professor, Conservation and Resource Studies, University of California at Berkeley, Berkeley, California </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NATE FIELDS, Director, Developing Markets, Control Data Corporation, Minneapolis, Minnesota </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ROLAND J. FUCHS, Chairman, Department of Geography, University of Hawaii at Manoa, Honolulu, Hawaii </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ELMER L. GADEN, JR., Department of Chemical Engineering, University of Virginia, Charlottesville, Virginia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JOHN HOWARD GIBBONS, Director, U.S. Congress, Office of Technology Assessment, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N. BRUCE HANNAY, Foreign Secretary, National Academy of Engineering, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM HUGHES, Director, Engineering Energy Laboratory, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WILLIAM A. W. KREBS, Vice President, Arthur D. Little, Inc., Acorn Park, Cambridge, Massachusetts </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GEORGE 1. LYTHCOTT, University of Wisconsin, School of Medicine, Madison, Wisconsin </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">JANICE E. PERLMAN, Executive Director, Committee for a New New York, New York City Partnership, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUGH POPENOE, Director, International Programs in Agriculture, University of Florida, Gainesville, Florida </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK C. ROBBINS, President, Institute of Medicine, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WALTER A. ROSENBLITH, Foreign Secretary, National Academy of Sciences, Washington, D.C. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FREDERICK SEITZ, President Emeritus, The Rockefeller University, New York, New York </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RALPH HERBERT SMUCKLER, Dean of International Studies and Programs, Michigan State University, East Lansing, Michigan </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GILBERT F. WHITE, Institute of Behavioral Science, University of Colorado, Boulder, Colorado </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BILL C. WRIGHT, Assistant Dean for International Programs, Oklahoma State University, Stillwater, Oklahoma </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">JOHN C. HURLEY, Director</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL G. C. McDONALD DOW, Associate Director/Studies </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MICHAEL P. GREENE, Associate Director/Research Grants </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P></FONT>
+<!--
+</Section>
+</Section>
+-->
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b22bue/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b22bue/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/b22bue/metadata.xml	(revision 10506)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">Butterfly Farming in Papua New Guinea (b22bue)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Animal Husbandry and Animal Product Processing|Other animals (micro-livestock, little known animals, silkworms, reptiles, frogs, snails, game, etc.)</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">BOSTID</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+            <Metadata mode="accumulate" name="dls.Keyword">start a butterfly farm</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec158e/ec158e.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec158e/ec158e.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec158e/ec158e.htm	(revision 10506)
@@ -0,0 +1,2772 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; The Courier - N°158 - July - August 1996 Dossier Communication and the media - Country report Cape Verde</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P ALIGN="JUSTIFY"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">The Courier - N°158 - July - August 1996 Dossier Communication and the media - Country report Cape Verde</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">AFRICA-CARIBBEAN-PACIFIC - EUROPEAN UNION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dossier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Communication and the media</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Press freedom, regarded as a fundamental human right, is also a key component in the democratization process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With the help of experts in the field, we look at what various organizations are doing to combat censorship and promote a free press in ACP countries and elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We also highlight the new trend of donor support for projects aimed at promoting press freedom. These include, notably, provisions for the training of journalists. And as new means of communication, such as the World Wide Web, develop, we consider what is being done to prevent the opening up of a new divide - this time between the 'information rich' end the 'information poor'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Country report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among the least-developed countries, Cape Verde is seen as a model of good governance and stable democracy. It is also admired for its perseverance in the struggle against the exigencies of history and climate. The country suffers from almost permanent drought and has virtually no regular supplies of fresh water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Its history has been punctuated by serious famines and while the people are no longer hungry, they still face formidable economic difficulties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde produces just 10% of what it consumes and its exports are one fifteenth of its imports. The one bright spot is in services, where it enjoys a positive trade balance. This sector (in particular, international transport and tourism), together with the country's cultural industries, offer the best hope for future development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Meeting point</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Robert M&eacute;nard, Director of 'Reporters sans fronti&egrave;res'</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Combating attacks on press freedom</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Reporters sans fronti&egrave;res' was founded in June 1985 in Montpellier where Robert M&eacute;nard was working as a journalist with Radio France. Now based in Paris, RSF has two main policy areas. In the first place it alerts international public opinion and the media to situations involving violations of press freedom (via publications such as 'RSF News letter' the Annual Report and specific books and reports). Secondly, RSF actively intervenes by sending letters of protest to official bodies and assisting victims. Last year RSF dealt with more than 350 cases involving the press throughout the world. The organisation's ambition, according to Mr M&eacute;nard, is to be a kind of Amnesty International in the press field. The interview began with Mr M&eacute;nard giving a detailed description of RSF's work.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - We do two things - we report violations of press freedom and help journalists who are the victims of such violations. Take the former Yugoslavia, for example. It would have been unthinkable to monitor what was going on in that war-torn country without, at the same time, helping the media who were victims of the repression. So we sent over lawyers to help in trials involving the press, helped the families of imprisoned journalists and gave general assistance to the media. In the case of Oslabodenje, the Sarajevo daily, this went on for four years. We did similar work in Rwanda where RSF helped the media to get back on its feet after the genocide. In Algeria at the moment we are involved in aiding  journalists who are obstructed when doing their work. We also give help in Europe - currently to refugee journalists in Belgium, France, Spain, Switzarland and Germany. That's basically what we do; reporting violations of press freedom and helping those who are the victims of it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you work with other organisations, for example the United Nations ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - We work with various types of organisations. We have daily contact with other NGOs specialising in press freedom, such as Article 19 in London and the Committee for the Protection of Journalists in New York, to give just two examples. We also have contacts with NGOs involved in human rights issues in general and, above all, with Amnesty International.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Then there are our links with international organisations and, first and foremost, with the UN system. RSF has submitted reports in response to requests from various organisations, ranging from the UN Committee for Human Rights to UNESCO. We also work with the Council of Europe and the Organisation of African Unity. But our closest  relationship is with the European Union, or two reasons; firstly because it is RSF's main financial backer and secondly Because the EU enables us to do three things. It has helped us set up and has Financed a vast network of correspondents in 130 different countries and, to my mind, this is the most important thing in terms of defending human rights and press freedom. We also publish reports, which we write in response to EU requests, on press freedom in one country or another and which are made available to the EU and European Parliament. Our third \ink comes in the form of assistance. We manage an aid fund to help where the press is in difficulties, and the money is provided by the Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-You have mentioned a network of correspondents which has been set up. How does it operate ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is a network of people who are in daily contact with RSF and who tip us off when a situation requiring our attention arises. Whenever there is a violation of press freedom in a country where the network operates, our correspondent lets us know - that's the first priority. Then, they make enquiries at our request. The third stage is to set up events. For example May 3 was World Press Freedom Day and, on that day, in about 20 countries in Africa, our correspondents organised events on the theme of press freedom. A fourth aspect of our correspondents' work is that they are often responsible on the ground for helping journalists in difficulty. They also help the media in general because we give them documents and supply them with information which they distribute in their particular country. Their task, therefore, is to alert us to a situation, meet our requirements for information and, on our behalf, physically to assist people on the ground, set up events and disseminate information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Are the correspondents all nationals of the countries in which they work ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes. Also, about 90% of them are joumalists and they are all paid for what they do. Their relationship with us is clear-cut. It is very important for them to be paid because this means that   we can ask certain things of them. If you   work as a volunteer no-one can give you  a deadline to produce such and such a   document. In our case, we pay them to   do this work for RSF.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you choose countries where the situation is already problematic ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Unfortunately, problems exist in many countries. Less than half the countries in the world show any degree of respect for press freedom and that means we have a great deal of work. In addition, information arriving at RSF from the correspondents is distributed to other organisations. We have set up a system called Infex which is an electronic mailbox.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All RSF's information is put on a computerised system and immediately disseminated to all the organisations involved in the defence of human rights, and press freedom in particular.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· So the technological revolution is a positive thing as far as you are concerned ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Absolutely. Both the Imais and Internet systems are unbelievably useful tools which have completely revolutionised our work. For example, RSF might protest about the situation in some country or other. Take China, for example - we regularly lodge protests against the lack of press freedom there. There are 17 journalists in jail, no freedom for the press and a great many problems. However, people in China are not aware of what we do and in order to get information they have to listen to international radio stations. On the Internet, RSF's services are available in French, English and Spanish and it is consulted by people the world over. It is thus one of their sources of information. Another example would be a case where we set up an operation and inundate a number of people in a particular country with faxes, in order to pass on the information. Modern technology enables us to break down the fortresses which totalitarian or dictatorial regimes attempt to construct around themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- RSF has just published its 1996 Report. What do you have to say regarding the current position of press freedom ? Has progress been made ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY"> - I would say two things. In the long term, the situation is improving. If you remember, 25 years ago, the regimes in half the countries in Latin America were dictatorships, communism dominated half of Europe and nearly all of Africa had single-party systems. Even in Europe, there were dictatorships - in Spain, Portugal and Greece. So we cannot deny that there has been progress. The problem is that, for three or four years now, there has been a noticeable rise in new threats to press freedom, and this is a great source of concern to us. Here I am thinking of the rise in power of fundamentalist movements, particularly religious fundamentalism. In a number of countries nowadays - the best example, or perhaps I should say the worst example, is Algeria - journalists are not only threatened by the state but are being killed by armed Islamic groups. The rise in religious fundamentalism is indeed a real danger.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second type of threat confronting the press is the increased influence of mafia-type criminals. You will, of course, have heard about drug trafficking in places like Colombia or Peru. Nowadays, in some countries where communism has been overthrown, the big threat comes from these criminal gangs. Not so long ago in Russia, the star presenter on the main TV channel was killed because he got in the way of 'Mafia' interests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The third threat comes from uncontrolled actions by groups fighting for autonomy or independence, like the Kurdish movement in Turkey (the PKK), and a number of separatist groups in India. The EU is no stranger to this either</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - ETA poses a continual threat to the press, as do members of the FLNC in Corsica. It is only a few months since members of the latter group machine gunned a journalist's house. A fourth and new kind of threat, particularly in countries with a democratic system, comes from the rise of the extreme right.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lastly, a point I draw particular attention to in our recent report is, in fact, a dual phenomenon. On the one hand there are states which pass laws under which any criticism is a crime and may lead to prosecution. An example of this is Egypt where the government has enacted a law which has led to charges being brought against some 60 journalists since summer 1995. On the other hand, there are states where justice simply does not operate and there is no will to make it function.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Last year, 51 journalists were killed and a number of others were attacked, but there has not been a single trial or conviction. It is a real culture of impunity. In some countries, the justice system either does not operate, or it is not independent. In such places, the authorities are reluctant to identify and prosecute those responsible for attacks on journalists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· RSFcurrently has project running in Rwanda, in collaboration with the EU. Could you tell us something about this ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The EU is helping us to meet a wide range of needs in Rwanda, as well as in Burundi, where sadly, the situation is rather similar. In Rwanda, there are those who governed the country before the genocide and those in power at the moment. There was a specific problem there in that nearly half of Rwanda's journalists were killed during the genocide - 49 out of about 100. We had virtually to reconstruct the press system and the EU gave us the means to do this.The press currently has difficulties vis-&agrave;-vis the authorities but it is attempting to do its job.  in Burundi, where our work is of a more conventional type, we see continuing attacks on press freedom. There, RSF is trying to resist the pressure, again supported by the EU. In fact, thanks to the EU, we are helping a   number of countries' media to survive despite difficult conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another quite new problem is that before and during the genocide in Rwanda, the media were used as vehicles for disseminating hatred. They issued calls for people to kill their compatriots, in this instance the Tutsis, and the language they used was unbelievably violent. On Radio Mille Collines, presenters would say - and I quote; 'The graves are not full yet'. They would give out the addresses of people who had to be killed and when the murders had been carried out they would actually say, 'You killed them too quickly - you should have killed them more slowly to make them suffer more', or, 'You didn't kill the children, go back and kill the childreni. We actually have recordings of statements like this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In such a situation, journalists must be made to answer for what they have done and be brought to justice.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU has helped us conduct a number of surveys which will enable the international criminal court in The Hague to charge Rwandan journalists with complicity or incitement to genocide. We expect this to take place in the very near future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of course in Rwanda, all that is in the past but the same thing is happening today in Burundi where there is a radio station called 'Radio Democracy' - what a joke! A number of journalists there are issuing calls for people to be killed and we have a copy of one of their newspapers whose front page offers a cash reward to anyone who kills such and such a person. This is not journalism. RSF has lodged complaints against these people and one of these 'journalists' has just been charged.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We are doing three things in Rwanda and Burundi: denouncing violations of press freedom by the authorities, helping media victims and - something new - reporting what has come to be known as 'the media of hatred'. Unfortunately, this type of media is not restricted to Rwanda and Burundi. it is a phenomenon that we see in a number of African countries, in the former Yugoslavia, the Caucasus and the</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Middle East. Perhaps you are aware that the 50th anniversary of the Nuremberg trials has just passed ? But did you know that there were two journalists among the accused? The press has forgotten that journalists played a part in the rise of Nazism. RSF is pointing out that the same thing is happening today in many countries and we have to fight it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> 'The EU is a  perfect partner</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Given what you have just said, should restrictions be placed on press freedom ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - This is a very complex subject. You have to remember that international texts, particularly the convention on civil and political rights, place restrictions on press freedom. Article 19, which defines press freedom, stipulates that there are certain limits to this and Article 20 forbids any dissemination of racist or antisemitic ideas and any incitements to violence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">RSF has two things to say. First, governments which have signed the agreements must ensure they are observed. These set limits. Journalists are not above the law and they must be punished when they say certain things. So states must face up to their responsibilities and apply the treaties they have signed. Second, I feel that the international community, and Europe in particular - when it signs agreements or gives aid to third countries - should demand that they respect press freedom but clamp down on the media of hatred.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· RSF has just published a draft model legislation governing the press. In preparing this, were you influenced by your experience of the extremist media ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Perhaps we were influenced too much. I am my own worst critic. We sent a mission to Rwanda before the genocide but did not appreciate the full effects of the evil disseminated by the media of hatred, particularly Radio Mille </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collines. We underestimated the situation and are concerned at what is happening. We believe there must be express limits on press freedom and this draft framework law is one way of formulating such restrictions. It is not necessarily the best way of going about things, but our profession has to ask itself questions regarding the definition of press freedom and the limits we must not exceed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Are you satisfied with what the EU is doing in this area ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The EU is a perfect partner and has never exerted any pressure. With the Union, we are able to do things that would not be possible with individual Member-State government because the latter conduct foreign policy in defence of certain interests. Each country has its own cultural history linguistic links or links arising out of former colonial times which prevent it financing RSF's studies unconditionally. As far as our missions are concerned, RSF decides what it wants to do and we send our reports to the EU. They have also granted us a budget enabling us to give immediate aid to people in difficulty. This is the most positive action possible If the EU were not there, there would unfortunately be no-one else to finance an organisation like ours. 60% of our budget comes from the Union, 20%from various companies. We generate the remaining 20% ourselves through sales of books and contributions. Because the EU is a grouping of governments, the Commission has some room for manoeuvre. This is the only possible kind of support for organisations like RSF and, if it were not there, it would be the end for the people whom RSF supports.  interview by Dorothy Morrissey</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">ACP</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">The economy of Cameroon: Better prospects but still a long way to go</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is an astonishing sight to behold during the rainy season. As you drive along the road from Yaound&eacute; to Bamenda, you come to a point where human habitation starts - and it then continues unbroken for more than 100 kiLom&eacute;tres. Just before Bafoussam, and as far as the eye can see, every patch of land is cultivated. Bananas, oranges, mangoes, sugarcane, cassava, palm trees, groundnuts and maize grow luxuriantly in open fields and in the front and back gardens of many houses. This route, of course, takes you mainly through the western part of Cameroon, home to the Bamilelr&eacute;s, recognised as one of the country's most enterprising and industrious ethnic groups. The population density here is 200 per km2 as opposed to 1 per km2 in the East.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The impact of this widespread farming, carried out by a large number of smallholders, is visible in the local markets, whether in Bafoussam, Mbouda or Bamenda. There, the stalls overflow with fruits and vegetables and prices are very low - a virtual paradise for the middlemen whose unmistakable presence is signalled by the significant number of trucks loading the produce for distribution throughout the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These scenes come as no surprise to the long-time observer of Cameroon's economy. The country achieved virtual self-sufficiency in food over 15 years ago. It is one of the few African countries to have been able to do this, thanks both to its physical  endowments and an early recognition of its agricultural vocation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon is often described as a microcosm of Africa, not just in terms of its make-up of English- and French speaking communities, but because it enjoys almost all the continent's climatic conditions. The south is equatorial, with two rainy seasons and two dry seasons of equal duration, the centre is Savannah country with one rainy season and one dry season, while the extreme north (part of the Sahel) is hot and dry. The country has a very good supply of rainfall - from 5000 mm annually in the southwest to around 600 mm near Lake Chad.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Such varied climates favour the cultivation of a variety of crops. Timber is  produced mainly in the southern provinces while palm oil, tea, cocoa, coffee, rubber, timber and foodcrops are produced in the southwestern and western areas. The central and north provinces specialise in cattle and cotton production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Concentration on agriculture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon has, not surprisingly, concentrated on agriculture. Indeed the government has given top priority to the sector in all its development plans   since independence in 1960. It has been involved in the marketing of the main export crops and has provided subsidies to farmers in the form of low-priced fertilisers and pesticides for their cocoa, coffee, rubber, palm oil, etc. Almost three-quarters of the working population (the majority of whom are smallholders) are engaged in farming. And despite a low level of mechanisation, they are very efficient. The rate of growth in food outstrips the rate of population growth. Only a few largescale farmers or firms are involved in the production of cash crops.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Until the early 1980s, when oil came into the picture, these large scalefarmers and firms amounted for more than 70% of export earnings, 40% of state revenue and 32% of the Gross Domestic Product. The plan initially was to use oil revenues to further boost and transform agriculture. However, the dramatic increase in the country's oil production, combined with much higher world petroleum prices during the first half of the 1980s, made the sector not only Cameroon's biggest export earner, but also, in a certain sense, a 'spoiler' for agriculture. Increased revenues enabled the government to maintain the level of prices paid to farmers, even though world prices had slumped to disastrous levels. This created distortions in the market. (Later, when the oil price slumped, and revenues dropped sharply, producer prices were also reduced, bringing them closer into line with international prices.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture's contribution to GDP declined steadily to around 21 % in 1985, rose to 27% in 1989 and has hovered around 30% ever since. The sector's share of export earnings has also fallen to about 40% of total exports by value.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite this, Cameroon's agriculture remains, comparatively, in a much better shape than that of most African countries. Indeed, it contributed in large measure to the country's reputation as one of Africa's economic successes in the 1980s. During that decade, growth averaged 8% per annum. However, the period was also marked by dramatic increases in oil revenues which induced  significant policy changes as well as leading to maladministration. The government paid less attention to taxation and customs duties as sources of income and turned a virtual blind eye to smuggling which harmed the manufacturing sector. The civil service, on the other hand, expanded beyond reason, a phenomenon that some have attributed to patronage by the ruling single party.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Boom in public expenditure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Protected somewhat against fluctuations in earnings from export crops, by a strong but overvalued CFA franc, the government embarked on a wide range of capital expenditure and imports. Then, in 1987, international oil prices fell as dramatically as they had risen earlier in the decade. At the time, public spending was running at CFAF 8 billion - well above the CFAF 5.6bn the country actually earned. Revenues from oil continued their downward slide to CFAF4.5 bn in 1988, CFAF 2.8 bn in 1991 and CFAF 2.5 bn in 1994. 1995 saw a modest rise to CFAF 3 bn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1987 thus marked the beginning of a rapid deterioration in Cameroon's financial situation. In the period which followed, civil servants' salaries were unpaid for months, several of the country's foreign missions were left without resources and both domestic and foreign debts worsened. In 1993, the government owed commercial banks around CFAF 3.3bn. Its external debt stood at around $7.5bn with a service ratio of more than 25% of foreign exchange earnings. The devaluation of the CFA franc in January 1994 improved the internal debt situation significantly. In February, the government signed a letter of intent with the IMF after agreeing to a series of reforms which included, among other things, rationalising the banking and insurance sectors, raising revenue from non-oil sources, bringing inflation down and reducing the budget deficit. In return the IMF provided a stand-by loan equivalent to CFAF 1.4bn. However, the agreement was suspended just a few months later when the Fund reached the conclusion that the government lacked the will to carry the reforms through. The 1994/95 budget foresaw a deficit of 4.5% of GDP - well above the IMF's guideline of 1.5%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meanwhile the country's financial situation had become so critical that it could no longer service its debts, most notably, those it owed to the World Bank. France, which had traditionally been ready to come to the rescue, refused to bail Cameroon out and it finally dawned on the authorities that structural adjustment was unavoidable. When, in September 1995, talks resumed with the IMF, the commitment to adjustment was no longer in doubt. The government agreed, in addition to fiscal reforms, to liberalise trade in cocoa, coffee and timber, to prune the civil service and to privatise state enterprises which dominate the industrial sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Commitment to reforms</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since then the reform process has been in full swing. The first and most important task has been to improve the government's financial position. The civil service, which employs more than 175000 people, is gradually being reduced and salaries have been cut. Trade is also being liberalised and subsidies are being removed. The 1995/96 budget, unveiled in June last year, was welcomed by the IMF. It included, for the first time in a long while, increases in income tax and a widening of tax bands. A series of measures have also been introduced to combat tax evasion and fraud. External signs of wealth, water and electricity consumption, and telephone bills are now being used as means of assessing income tax.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Responsibility for the collection of customs duties has been removed from the Customs Department which was often accused in the past of corruption and inefficiency. The task has been given instead to a Swiss-based preshipment inspection company. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The donor community has responded positively. With French assistance, the government has been able to clear its outstanding debt to the World Bank. The IMF has provided a stand-by credit facility of $101 million in support of the adjustment programme for 1995/ 96 and debts to the Paris Club covering the same period have been rescheduled. In addition, now that Cameroon has been reclassified as a poor country, it is entitled to benefit from the terms of the Naples Agreement, which allow for up to 67% of debts to western govemments to be written off. A number of creditor nations have either forgiven the country its debts or have reduced them substantially. More loans have come from France and a number of other donors, including the World Bank and the European Community.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EC is financing a series of projects within the framework of the adjustment programme, including the restructuring of the civil service and preparation of the ground for privatisation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lately though, the donor community has been showing signs of disenchantment, following allegations of misuse of funds and perhaps even outright embezzlement. Last March, an IMF mission to Yaound&eacute; failed to obtain an adequate explanation concerning the allocation of certain sums. The result, at the time The Courier went to press, was that an IMF loan for settlement of Cameroon's debt to the African Development Bank was being held up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dealing with the negative social impact</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p07a.png"></center><br>
+ Figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sudden devaluation of the CFA franc in January 1994 halved Cameroon's purchasing power overnight. The government has since cut wages twice. The average salary of a top civil servant, which stood at around CFAF 300 000 before devaluation, is now less than CFAF 180 000 while the lowest paid government employees receive just CFAF 30 000. At the same time, prices, particularly of imported manufactured goods and inputs, have risen sharply. Increases of up to 150% have been  recorded. By way of example, the price of a baguette (french bread), which was only CFAF 80 in January 1994 had risen to CFAF 130 by March 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there is considerable hardship, Cameroonians are a great deal more fortunate than fellow Africans in many other countries undergoing a similar adjustment process. Staple food remains cheap and affordable to the vast majority, thanks to the continuing strength of agriculture. As a result, there are few, if any, cases of malnutrition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A number of donors, including China, Belgium and the EC, are concentrating on health and education with the specific aim of reducing the negative social impact of adjustment. The EC, for example, has a project designed to strengthen health provision at the grassroots. This entails rehabilitating  infrastructures (health centres and district hospitals in particular) and establishing medical supply centres in areas that are not covered by other donors. The project is governed by the principle of cost-recovery to ensure viability and sustainability. But one area where the donors cannot do much is in the field of job creation. There is growing unemployment and job prospects in the formal sector, at least in the short term, are not good.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In macro-economic terms, things are locking up slightly for Cameroon. After recording economic growth of 3% in 1994/95, the hope is for a 5% increase in 1995/96. However, Cameroon's main economic operators, grouped under the umbrella of GICAM (Groupement inter-patronal du Cameroun), expressed fears late last year   that the country would not achieve this level of growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon exports a variety of primary commodities, most of whose prices have recovered in recent years, and devaluation has had a positive impact on the country's balance of trade. Specifically, it has helped make exports more competitive and in 1994/ 95 the trade surplus was a healthy CFAF 349bn, almost double the CFAF 128bn recorded in the previous year. There was a noticeable slowdown in the export of timber in the latter half of last year and the qualities of coffee and cocoa being sold were not up to the usual standard, a situation that led to both crops being shunned in the world market. Bananas exported to France were also meeting stiffer competition from French Caribbean bananas. However, the fact that rubber production has risen by more than 10%, while aluminium output and sales have increased, should help Cameroon to record another positive trade balance when the figures are next published.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The forestry sector, which has huge foreign-exchange earning and employment potential, is being rationalised as part of the current structural adjustment programme. The Canadian Agency for International Development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(CAID) has a five-year project to conserve and regenerate some 30 000 hectares. In fact, half of Cameroon is covered by forest and less than 500 000 ha is currently being exploited. The objective is to ensure that forest resources are exploited in the future at a sustainable level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The private sector</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Industry, which is still in its infancy, has been developed by the government since independence largely with a view to import-substitution, although with some gearing towards the regional market. It accounts for about 14% of GDP and is currently dominated by aluminium smelting. Although devaluation has lately improved the competitiveness of those enterprises that add value to locally available raw materials, the manufacturing sector as a whole faces two major challenges now that the government has accepted the idea that the economy is best driven by the private sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first relates to private investments, which have been sluggish  over the past ten years; a clear illustration of a lack of confidence in the economy. This was amply demonstrated when Cameroonians with funds abroad failed to repatriate them to take advantage of the CFAF devaluation as was widely expected. This phenomenon puts the whole privatisation exercise in jeopardy as it means that the government is more likely to have to rely on foreign entrepreneurs. The best the authorities can therefore expect in the short term, some observers say, is to convert those state enterprises that are not already joint-ventures into ones where private investors become the majority shareholders. Complete divestment will then take place gradually over a longer timescale. Overall, 150 state enterprises have been earmarked for sale.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to Andr&eacute; Siaka, director of Cameroon's Brewery, who is also Chairman of GICAM, another reason for the lack of investment was high interest rates. These hovered around 20% for many years. Even now, after the reform of the banking sector, interest rates remain very high and there are no borrowers, he told The Courier. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Donors again have been conscious of this and some of their interventions have reflected this concern. For example, Canada is providing funds for the establishment in Douala (the commercial capital) of a centre for the development of private enterprises. Meanwhile, the Chinese have promised to provide CFAF 7bn to enable a line of credit to be opened for small and medium sized enterprises.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government itself is puting in place a number of incentives, according to Minister of Trade and Industry Eloundou Mani Pierre. The liberalisation of the economy and the reform of the customs regime in collaboration with UDEAC, to which Cameroon belongs, are part of these. Mr Mani told The Courier that with a population of under 12 million, Cameroun's most important market was Central Africa. He also, perhaps surprisingly, has high hopes for the new World Trade Aareement. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon meanwhile is reviewing its plan for the establishment of export processing zones with the help of its main donors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is also looking at other ways of attracting foreign investment, particularly in 'value-added' enterprises involved in the processing of locally available raw materials such as cotton, cocoa, coffee and timber.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social and political peace</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second, and by far the more serious challenge facing manufacturing, is the problem of large-scale smuggling by petty traders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Evidence of this abounds in the booming central market of Douala, where goods of all kinds can be found at very reasonable prices. Ironically the measures which were being taken and judged to be relatively effective against smuggling in recent years have had to be abandoned under structural adjustment rules imposed on the government.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As Mr Siaka pointed out, petty traders dealing in smuggled goods put pressure on enterprises, 'because they do not pay tax', and threaten to render domestic manufacturing uncompetitive. It is also widely acknowledged, however, that the small-scale traders, who dominate the informal sector, provide job opportunities to Cameroonians, which is important at a time of economic austerity. Indeed petty trading has arguably been the safety-valve, helping to ease the social pressures brought about by structural adjustment, and thus preventing civil unrest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But the extent to which that safety-valve can withstand the emerging political pressures is a different matter. Democratisation, understandably, was one of the conditions imposed by donors for assistance to Cameroon. After a series of elections - presidential, legislative and municipal - which were marred by violence and deaths, there are still doubts about the health of democracy in the country. Indeed, there are signs that tension is  mounting. And few would dispute that if Cameroon is to succeed economically, it needs both social peace and political stability. </P>
+<P ALIGN="JUSTIFY">Augustin Oyowe </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Jacques Santer commends regional  initiative</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Alex Kremer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Commission President's visit to West Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union's commitment to regional development in sub-Saharan Africa is as strong as ever, but sustainable development can only come from Africa's own initiative. This was the message delivered by Jacques Santer, President of the European Commission, in his address to African heads of state at the UEMOA (Economic and Monetary Union of West Africa) summit in Ouagadougou, Burkina Faso, on May 10.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'I wish to emphasise from the start,' Mr Santer declared to the Presidents of Benin, Burkina Faso, C&ocirc;te d'lvoire, Mali, Niger, Senegal and Togo, 'that the European Commission and the European Parliament are both determined to make our partnership even more dynamic and in tune with today's rapidly changing world.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The presence of the Commission President at the UEMOA summit marks a milestone in the European Community's support for regional integration in the developing world. With its own Commission, Council of Ministers and Court of Justice, the UEMOA appears to be consciously  following the supranational model of regional integration pioneered by the European Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sequencing of UEMOA integration, however, is almost the reverse of the European model. Already linked by a single currency in the CFA franc, the West African Union's member states are now pressing ahead with plans for integration of their 'real' economies. The implementation timetable agreed in Ouagadougou covers freedom of establishment, free movement of capital, mutual macroeconomic monitoring and the first steps to customs union with the harmonisation of external tariffs and the lowering or removal of intra-regional barriers to trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">President Santer indicated that the European Commission is keen to discuss how the European Development Fund (EDF) can support these initiatives. Such aid could take the form of technical assistance and training as well as direct budgetary support to mitigate the short-term costs of customs union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UEMOA is not, however, an aid project. Its member states have designed it to stand on its own feet financially from the start. A 'community solidarity levy' was due to come into effect on 1 July 1996. The money will be used for a structural fund programme beginning in late 1997, as well as to finance the Union's operating costs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meeting with the President of Burkina Faso, Blaise Compaor&eacute;, Mr Santer said that it was particularly significant that his first official visit to Africa as President of the European</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Commission was to Ouagadougou. Not only was it a reaffirmation of the partnership between Africa and the EU, and a statement of the EU's willingness to support regional integration in the developing world. It was also a tribute to the determination of the people of Burkina Faso and other African countries to promote their own development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Community is Burkina Faso's second largest donor, contributing 10% of total aid payments in 1994. Since 1991, the EC has committed an average of ECU 45 million each year to development cooperation with this country, rising to a peak of ECU 100m in 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Santer visited the EDF-financed road improvement site at Tougan, close to the frontier with Mali, and noted that intra-regional transport links were an essential complement to the legislative programme of the UEMOA. He concluded his tour of regional cooperation projects with a visit to a photovoltaic pumping system financed by the EC under its West African solar energy programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, on a more personal note, the Commission President was able to drop in on a project managed by the charity Chr&eacute;tiens pour le Sahel. Mr Santer worked for this Luxembourg-based organisation before starting his career in politics and he was visibly pleased to see that it was still going strong - supporting home-grown African initiatives with a little financial help from the European Community.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.K. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">CTA - moving with the times</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the Technical Centre for Agricultural and Rural Cooperation (CTA) was inaugurated 11 years ago in Ede, Prince Claus of the Netherlands - whose interest in development issues is well-known - attestded as guest of honour. On 19 April, he returned to take part in the official opening of the CTA's new building in neigh bouring Wageningen in the Dutch province of Gelderland. The siting of the purpose built premises is significant. The town of Wageningen has long been an important European centre for agricultural research and the Dutch, of course, are renowned for their commitment to cooperation with developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The CTA may only have moved a short distance from its previous headquarters, but the Centre's 38-strong staff are also aware of the need to move with the times when it comes to fulfilling  their role in the field of agricultural information. This point was particularly emphasised by CTA Director, Dr. R.D. Cooke in his presentation at the opening ceremony. Recalling the Centre's main tasks (see box) Dr Cooke spoke of the 'changing horizons and challenges' which they faced, and he focused on four specific aspects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first of these is the big change taking place in national agricultural systems, with the state withdrawing more and more in favour of the private sector and NGOs. This is being accompanied by a trend towards decentralisation with the result that the CTA has many more potential partners to cater for and work with.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Global liberalisation has also had an effect on the kind of information being sought by the CTA's 'customers'. In the past, demand was almost exclusively for scientific or technical information, notably aimed at increasing productivity. Dr Cooke reported that while this remained important, there was now  an increasing interest in marketing and socio-economic aspects to facilitate decision-taking.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It came as no surprise to hear the Director highlight the challenge posed by new technologies such as electronic networking and digital storage. The key point here, he stressed, was to find ways of adapting these to ACP needs and realities. 'In the next century,' he argued, 'the haves and the heve-nots will be defined by their access to information.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, Dr Cooke referred to the growing significance of regional linkages. He indicated that the CTA was locking at ways in which it could help its partners to devise regional development programmes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The declaration signalling the official opening of the building was made in the preceding presentation by E.F.C. Niehe who is Deputy DirectorGeneral for European Cooperation at the Dutch Ministry of Foreign Affairs. In his speech, Mr Niehe emphasised the relevance of the CTA, pointing out that while the world food situation had improved, 'we are now on the threshold of structural food insecurity'. He also spoke in more general terms about the future of ACP-EU cooperation and acknowledged that 'partnership, sovereignty and equality had been somewhat neglected' by donors. However, he suggested that these concepts were now 'coming back'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the ACP side, the Swaziland ambassador, CS. Mamba,who is co-President of the Committee of Ambassadors, took up the theme of food shortages in sub-Saharan Africa and identified some of the difficulties encountered by African producers, particularly in respect of new technologies and marketing. He also referred to the environmental challenges facing ACP countries, especially in the Caribbean and Pacific. He was keen, however, to stress that the picture was 'not entirely negative'. Thus, for example, new technologies and methods had had a positive impact on grain production in Zimbabwe, horticulture in Kenya, and cocoa and coffee in West Africa. Mr Mamba echoed Dr Cooke in stressing the advantages of regional markets, and concluded with a firm statement of support for continuing ACP-EU cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'History,' he said, 'will show that the Lom&eacute; Convention played a central role in the momentum of development.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The final speaker was Steffen Smidt, Director-General for Development at the European Commission, who suggested that the CTA had played a pioneering role in developing a sectoral  approach at a time when the focus of development cooperation tended to be on individual projects. 'The Centre', he said, 'has become a well-respected international institution in the field of agricultural information.' The Director General focused on the need for ACP countries to develop their own capacities and on the gap that exists 'between potential and reality', because of capacity limitations. The Centre, he believed, could 'help bridge this gap.' Mr Smidt also reiterated a point made earlier that the information flow should not just be in one direction. 'Information from South to North is vital,' he argued, to ensure better targeting of programmes in future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After the speeches, guests had an opportunity to learn more about the CTA's work by speaking to the Centre's personnel and visiting a special exhibition illustrating the nature and purpose of the Centre's activities. _</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Simon Homer About the CTA </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The CIA's tasks are: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - to develop and provide services which improve access to information for agricultural and rural development ; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - to strengthen the Opacity of ACP countries to produce, acquire, exchange and utilise information in these areas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Programmes are organised around three principal themes: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Strengthening information centres - designing strategies for improving agricultural information services; - promoting use of new information technologies; - providing training; - donating books. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Promoting contact and exchange of: experience among CTA's partners in rural development - seminars; - study visits. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Providing information on demand - publication s; - radio and audiovisual materials; - literature services for researchers; - Question and answer service. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(The address of the Technical Centre for Agriculture and Rural cooperation can be found in the CTA section towards the end of the white pages in   this issue.) </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Bananas, Hamlet and the Windward IsIands</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Martin Dihm</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What do the Windward Islands' banana industry and Hamlet have in common ? Both are intrigued by the same question: 'To be or not to be.' But unlike Hamlet, whose fete was decided rather quickly and tragically, the future of Windward Canibbean banana production is still open. And what is more, Windward producers have a distinct advantage over Hamlet. They can hire consultants to analyse their problem and come up with fresh solutions. That is what has happened. But before turning to the solutions, what have the problems been ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The four Windward Islands; Dominica, St Lucia, St Vincent and Grenada, have long enjoyed preferential market access to the UK. This first permitted the creation of the industry and then secured its survival, even with production costs that are much higher than those of other producers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A traumatic moment came when the European Community had to decide on a common market regime for bananas. Coming into effect in mid 1993 the regime maintained the principle of preferential access for traditional ACP producers. Nevertheless, it introduced a move towards greater market liberalisation. Fierce attacks on the regime by certain of the EU's trading partners have raised doubts about its viability. The system is due, in any case, to expire in 2002 when even further liberalisation seems likely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All this could cause great difficulties for the Windward Islands which still depend substantially on banana exports to the EU. A decline in prices since mid-1993 and the appearance of new competitors in the previously protected UK market have further underlined the need for the Windwards to compete in a more liberal arena. The Islands commissioned a study, funded by the UK and the EC, into the competitiveness of their industry and on ways of improving its position. It was not the first study of this type, but earlier ones had had no real impact on the industry which had always been sufficiently protected to avoid swallowing the bitter pill of adjustment. This time, it was clear from the outset that action would have to be taken if the industry were to master the new situation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The study provided a wealth of interesting insights and recommendations. The first big surprise - at least for outsiders - was the discovery that the industry was wasting considerable amounts each year through certain deficiencies in governance, management and production methods. The second theme of the study was the poor banana quality resulting from an inappropriate pricing system. In effect, price differences paid to farmers were not sufficient to reward extra attention to quality aspects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The study's recommendations pertaining to management, production and quality were all agreed in a meeting on 29 September 1995, which brought together the Prime Ministers, the EC and other donors. Prime Minister Mitchell of St Vincent labelled this chance for the industry to get its business right as 'the last train to San Fernando'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What has happened since then ? After some hesitation, the industry has indeed begun to 'take up arms against its sea of troubles' (to return to the Hamlet analogy). The EC, for its part, has taken the part of Horatio, the faithful friend. Its role is a delicate one though - for the EC has a lot of money available. Take, for example, the ECU 25m allocated to St Vincent in the 1994 STABEX exercise (roughly five times that  country's national indicative programme). How are such funds to be injected reasonably into the islands without undermining their own strength and sense of purpose in pursuing the right strategy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To answer this, one has to look at the actual requirements. Streamlining the banana industry is less a question of big infrastructure projects than of providing expertise to guide the necessary structural changes. It also means fewer people will be employed in the sector. Aid should, therefore, focus on technical assistance, promoting diversification, and social 'cushioning'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The challenge, of course, remains considerable and the outcome will not be known for some time. But it is clear that the Windwards have taken bold steps in the right direction and that further steps are on the agenda. There is also little doubt that the islands small, sweet bananas can only be competitive in their market segment if they are produced and marketed professionally, and with dedication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So what could Hamlet have learnt from this experience ? In short - get sound analysis and fresh advice from outside - and then boldly implement. And stick close to your good old friend, Horatio! </P>
+<P ALIGN="JUSTIFY">M.D.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">British beef overshadows Development Council</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most recent meeting of the EC`s Development Council was one of the first to be hit by the non-cooperation policy adopted by the UK in protest at the export ban on British beef. The Overseas Development Minister, Linda Chalker, announced at the outset to her fellow ministers: 'I will not be able to agree today to the adoption of those texts... on which unanimity is required'. Britain is seeking agreement 'for a step-by-step lifting of the export ban', which was imposed after scientific evidence suggested a link between Bovine Spongiform Encephalopathy (BSE) - and its human 'equivalent', Creuzfeld Jakob Disease. Cases of BSE have been recorded across Europe, but the vast majority have been in the UK.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Texts which were approved included a regulation on refugees in non-Lom&eacute; developing countries. This makes available ECU 240 million over a four-year period (19961999) for longer term assistance to refugees and displaced persons - mainly in Asia and Latin America. Also agreed were two three-year programmes covering Aids control and environmental projects respectively. They will cover the period 1997-1999, and each has been allocated the sum of ECU 45m. In addition, ministers confirmed a regulation on the criteria for disbursing humanitarian aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But the British stance meant that a number of important resolutions were blocked, including a text on mounting projects which link emergency, rehabilitation and longer-term aid. Rino Serri, Italy's Under Secretary of State for Foreign Affairs who presided the Council meeting, said that once adopted, this approach would represent a 'qualitative leap for the EU's development policy.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other resolutions awaiting approval relate to the strengthening of coordination between Member States, evaluation of the environmental impact of development policies, decentralised cooperation, and migration and development. Since good headway was made on these subjects despite the British attitude, the texts are expected  to be speedily agreed once the UK lifts its veto. Ministers also had an initial discussion on a paper presented by Commissioner Pinheiro on preventing conflicts in Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As is customary at these biannual meetings, several delegations raised points of particular national concern. Belgium, for example, is worried about the Commission's proposal which would finally establish the single market in chocolate products while leaving Member States the choice of adapting their legislation to allow a vegetable oil content of up to 5% in chocolate. Belgium feels that this approach could ultimately prove harmful to cacoa-producing countries and claims that it will be difficult to control the exact percentage of oil used. Sweden, meanwhile, wants action to reform the UN institutions while Italy is keen to increase public awareness of development policies. Finland emphasised the need for better coordination between the European Community and its Member States on environmentally sustainable projects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Great Lakes region</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was backing for the June Round Table meeting on Rwanda organised by the UNDP, as well for the various diplomatic initiatives aimed at bringing stability to the Great Lakes region. On 27 May, the ministers dined  with Emma Bonino, the European Commissioner responsible for humanitarian issues, and with former US President, Jimmy Carter, who has played a major role in the search to find a solution to the region's problems. Others active in this effort include South Africa's Archbishop Tutu, and former Presidents Nyerere and Tour&eacute; of Tanzania and Mali respectively. Ministers also commended the efforts of the UN and the OAU.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Serri said there was a 'desperate need for a ceasefire' in Burundi and called for a 'speeding up of the peace process and full deployment of available humanitarian and development aid.' He told journalists it was vital for the EU to make special efforts to strengthen the judicial systems in Rwanda and Burundi - 'so that the justice system can work properly and identify those responsible for the genocide.' He pledged that 'substantial resources' would be made available once peace is secured. Ministers also called for a control of arms sales to the region, although they have no power to legislate in this area, which remains the preserve of the Member States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Outside the meeting place, Senegalese fishermen and NGOs joined forces to mount a protests against the effects of traditional EU fisheries agreements. These provide financial compensation to governments in exchange for access to their waters for EU vessels, but the protesters claim that they harm local fishing industries and disrupt food supplies. A significant number of agreements are due to come up for renewal later this year. NGOs are lobbying for a new and 'fairer' type of accord which provides for catch reductions, more selective fishing methods and the employment of locally-hired fishermen on EU boats. These proposals are all set out in a paper entitled 'The Fight for Fish: Towards Fair Fisheries Agreements,' published by Eurostep, a Brussels-based NGO. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Country report</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Cape Verde</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Making the best of history</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde has been shaped by the harmattan, the hot dry wind which blows from Africa, strong ocean currents and five hundred years of Portuguese colonialisation. Portugal has been a constant presence in the archipelago's history since the fifteenth century, when it granted the colonists who were to settle on the islands of Cape Verde a monopoly over the slave trade. The country became an interface between Africa, Europe and the Americas, at the centre of the triangle of trade in slaves, hardware and gold. The intermingling of black populations of every origin who  passed through the islands meant that the country was unable to present a united face against the colonialist culture. The colonists were therefore able to impose their own culture, with their fervent and proselytzing Catholicism becoming the principal ingredientin the mixture that is Cape Verde. Strong, scorching winds from the desert have shaped the islands' landscape and inhospitable ocean currents mean that approaches to the islands are difficult, their rocky cliff faces plunging into the sea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mythical Portuguese colonial oasis</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Up to the eighteenth century, Cape Verde was no more than a commercial centre for Portugal, its population at the end of that century barely exceeding 50,000, to be halved by the great drought between 1773-75. Other periods of drought regularly decimated the population and the arrival of new colonists and slaves did not offset such losses or compensate for the massive exodus which began in the early nineteenth century with the arrival of American whalers in search of crew members for their ships. Seven hundred thousand Cape Verdians currently live abroad, half of these in the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only four hundred thousand  have stayed in their own country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the beginning of the twentieth century, a period which signalled a turning point in the country's history, the population still numbered no more than 150 000. At the time, major sea voyages were being undertaken and Cape Verde's geographical location was highly valued. Mindelo, on the island of S&atilde;o Vicente in the north of the archipelago, developed as a coal-and-watersupply port for English vessels plying the route between India and the Americas, and England helped construct this port. However, Portugal's policy towards Cape Verde was double-edged. On the one hand, the islands were regarded as a natural extension of the home country, but as a competitor in terms of port activities. This led to Mindelo's slow development, although the trade in  skins, fishery produce, coffee and salt  could have made it a thriving centre. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mixing of races in Cape Verde has often been held up as, so-to-speak, 'humane colonisation', but this opinion is not corroborated by the under-developed state of the country at the time of independence and the fact that Portugal implemented food security measures to combat the ravages of catastrophic famines only when under pressure from public opinion, at the end of the first half of the twentieth century. The island's colonists had always used slave labour to produce food or fabrics which enabled them to purchase more slaves and it was only when the slave based economy began to decline, which   resulted in the impoverishment of the colonists, that a major grouping of free Blacks and rebel or emancipated slaves came into being. That is when the intermixing of races began. Therefore, before the abolition of slavery (18641869-1878), the vast majority of the black population of the island was free; both unmarried and married colonists would generally emancipate their children born of a secret relationship with female slaves. The aristocracy and white upper-middle classes continued to live a cloistered, aloof life and did not mix with other races. A second factor which would suggest that Portuguese colonisation of Cape Verde was sympathetic in outlook is the reputation of this small country's intellectuals; although colonisation created only a small intellectual elite which was the product of a single institution, the Mindelo College, opened in 1917. In a quote by Michel Lesourd, Deirdre Meintel refers to this phenomenon as the mythical 'cultural oasis'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A nation born of a middle class in tatters</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through its contradictions, it was this black, mulatto and 'petty white' middle class which was to forge the mixed-race culture and national identity, caught between its own privileges and its aspirations of aristocracy, between its rejection of African culture (they sought a 'lusotropical' culture) and the need to find allies amongst the lower classes who retained African cultural values. In order to acquire the wealth and attributes of power, this middle class was to take over the lands vacated by the decline of the slavebased economy and which were often much improved by the former slaves (renamed 'tenant farmers' without a major change in their living conditions) preventing a major economic upheaval which could have put an end to this iniquitous system. Their wholesale appropriation of land explains why, today, there is a very high proportion of landless farmers in Cape Verde, seasonal agricultural workers who survive only thanks to the State's welfare system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This petty bourgeoisie was to give birth to growing awareness which would lead to calls for independence. Officially, Cape Verde was not a colony but a province, and its inhabitants in theory had the same rights or lack of rights as Portuguese citizens in Salazar's 'New State', where the right to vote depended on social and cultural status. In other Portuguese territories, members of the petty bourgeoisie held the rank of colonial administrators and, from their ranks, the pro-independence movements emerged. Such was the case of the PAIGC (Guinea-Bissau and Cape Verde pro-lndependence Party), created by Amilcar Cabral, a symbolic figure in Africa's striuggles for independence and Cape Verde's national hero. He was assassinated in mysterious circumstances in Guinea-Conakry in 1973. His brother, Luiz Cabral, was to become president of Guinea-Bissau, and Aristides Pereira his successor as Party leader and Cape Verde's first president.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde's uneventful transition to independence in July 1975 mirrored Portugalts Carnation Revolution and was quite unlike the fierce war entered into by Portugal in Mozambique and Angola. There was a clandestine struggle during which a number of combatants were imprisoned, but there was never any real guerilla warfare. The Portuguese governor remained at his post until he was replaced by an ambassador. The PAIGC was to govern both Guinea-Bissau and Cape Verde until the coup d'&eacute;tat against Luiz Cabral in Guinea-Bissau in 1980, when it adopted the name of PAICV in Cape Verde, thereby signalling the end to any dream of a union between the two countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Diplomatic ventures</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new state pursued an even-handed diplomatic approach and accomplished the considerable diplomatic feat of remaining equidistant between the Cold wer's principal adversaries, adapting over time to all the changes which occurred on the world  scene. Post-independence, embassies were opened by the United States, China and the Soviet Union. Cape Verde, with its marxist leanings, maintained the former links created with apartheid South Africa by Portugal. The arrival in power of a liberal party had no effect on this diplomatic tightrope-walking act. It was South Africa which was to provide aid to build the international airport at Sal. Ironically, after the establishment of democracy in South Africa, it was at this very airport that President Mandela was to stress his desire for strengthened links with the archipelago. Latterly, Cape Verde has demonstrated this flexible in its recent decision to Join the group of, French-speaking countries whilst still regarding itself as a mouthpiece for the Portuguese-speaking world, enjoying a privileged relationship with Portugal, the Azores, Brazil and African countries where the official language is Portuguese. It is also a very active member of the CEDAO (Community of West-African States) and its President is currently chairman of the CILSS (Inter  national Commitee to Combat Drought). Cape Verde receives as much aid from China as from the US, from Russia and Sweden as from Cuba and Japan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This diplomacy is in keeping with the atypical 'Marxist' Party which first initiated it. With its interventionist approach to economics, its highly developed social policy which gives priority to education, health and combating unemployment through public welfare, this party could be regarded as a socialist party, yet it opted decisively for a market economy. Its single-party structure mirrored the example of would-be popular democracies, but it never set up a system of repression and terror: only one opposition member's death is said to have taken place in suspicious circumstances on the island of Santo Antao. The population was able to discuss politics at popular assemblies and held no fear of openly criticising the government and, in the case of the well-off, of displaying its wealth. A mudan&ccedil;a (change) was implemented calmly and collectedly by the PAICV when it was in power, sowing the seeds of its own downfall. With no pressure from street demonstrations and no insistent demands from political classes, the government of President Aristides Pereira and Prime Minister Pedro Pires adapted to the new situation created by the fall of the Berlin Wall. In early 1990, the PAICV gave up its privileged position as the single party and, one year later, at the legislative elections in January 1991 and presidential elections in February 1991, Africa witnessed the first democratic overthrow of a single-party government which had achieved independence. After the legislative elections, the PAICV, which had placed too great a reliance on being credited for its good governance, was silenced. The desire for change was too great and the position adopted by the Catholic church, anxious to punish a party which had dared to opt for a referendum on abortion, did the rest. President Aristides Pereira's personal prestige stood for little in the full face of this onslaught.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What change?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister Carlos Veiga, who had founded the MPD only eight months before his overwhelming success in the 1991 elections, became the new figurehead in Cape Verde politics. His power sharing with Antonio Mascarenhas Monteiro was again successful at the most recent elections (December 1995 and January 1996). Shortly before the poll, the MPD experienced a near-fatal split, but the new party which emerged, the PCD, had only one representative as against 50 (an absolute majority) for the MPD and 21 for the PAICV, which continued to exist. Three other parties taking part in the elections fell by the wayside and the polarisation of Cape Verde's politics into two camps locks set to continue. This is the second time that the MPD has surprised its opponents - this time, the political adversaries had attacked the MPD's attempt to curry favour, but the majority of the electorate, concentrated on the island of Santiago, continued to show their appreciation of the visible signs of modernisation in their lives and also the government's seductive politics, particularly in the ran-up to the elections. The country had also had a good harvest and, although this was unconnected with the MPD, that party could only benefit from it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite what MPD leaders might say, there has been no real ideological split, any political reorientation having been instigated in 1990 by the previous regime when it threw off its socialist trappings. Diplomacy remains  pragmatic and the new government's liberal rhetoric and social policy, particularly in the areas of education and health, has essentially been maintained. Suspension of the State's collective works programme, the symbol of the State's interventionist social policy, is only temporary, according to statements issued by the Prime Minister, counter to several rumours.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More visible changes have taken place in the economy: partial liberalisation of the banking system; legislation relating to foreign investment; suspension of the requirement for preliminary import authorisation; despite the government's backtracking as regards certain basic products; privatisation of State assets, particularly in the hotel business, etc. Here, too, the PAICV government engineered the changes, but it can surely not be criticised for maintaining a delicate balance between the new demands of the global village and the social practices of a country which is very poor, but which is succeeding in putting an end to its poverty and creating a modest quality of life, but a secure one. Given its bleak geographical location, Cape Verde is simply  continuing to make the best of history. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H&eacute;gel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The economy: too weak to worsen</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The arrival in Praia on 30 April of a throng of IMF officials cannot have failed to cause the government some concern, despite its air of calm. Ministers repeated publicly that Cape Verde had already carried out its own programme of structural adjustments, that they were on the same wavelength as the Bretton Woods institutions, and that they could not, therefore, see any reason why any further adjustments  should be imposed upon them. Nevertheless, the fact that the Cape Verde escudo has had rather a bumpy ride since last year's elections, trading sometimes by as much as 15% under its official rate on the parallel market, caused a certain degree of anxiety within financial circles, with the banks taking action by freezing certain credit facilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government insists that this situation has by no means arisen because of a sudden anxiety raised by opposition parties as to the effects of possible devaluation The truth is that there is a genuine structural imbalance caused by the trade deficit, a disequilibrium which is only being partially offset by official development assistance and the transfer of currency by Cape Verde emigres. As a percentage of the GDP, the overall budgetary deficit has tripled between 1993 and 1994 (increasing from 3.3% to 13.6%). For a country which could always be relied upon to pay its debts promptly, Cape Verde is now, for the first time, in arrears with its payments (see the 1995 report of the Bank of Portugal). The servicing of external debts represents 25.7% of goods and services exported - although these are relatvely small compared with neighbouring countries - the country's total outstanding debt is now nearing $200 million.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although Cape Verde is one of the LDCs (least developed countries) with a total GNP of approximately $850 per capita, out of a total of 174 States, it actually ranks 123 in the Human Development Indicator Tables, which take into account various factors such as life expectancy, education, etc. Its position near the middle of these tables clearly shows that, although the country is poor, its affairs are nevertheless being managed fairly efficiently. Boasting an adult literacy rate of 66% and a life expectancy of 64.7 years, Cape Verde is well ahead of those countries at the bottom of the list, which include a number of its Sahelian neighbours. Efficient administration of the State and the absence of rampant corruption are further feathers in the nation's cap. These achievements have earned Cape Verde much esteem from its sponsors, which goes to explain the prudence of the Bretton Woods institutions and their relative sympathies towards the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unkind Mother Nature</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde's history has been punctuated by great famines. Between the sixteenth and nineteenth centuries the country suffered no less than 30 famines, with this century seeing some of the cruellest: 16 000 people died in 1903-1904, the death toll in 1921 was 17000, in 1941-43 it was 25000 and between 1946-48 famine claimed 20 000 lives - a figure which at the time represented 20% of the total population of the archipelago. After the last famine, the colonial authorities, under pressure from international opinion, adopted food programmes which made the country more able to cope with the consequences of subsequent droughts. The last great famine ended 50 years ago. The nation may no longer be hungry, but the factors which make its inhabitants' lives so difficult remain. The  main reason lies in the country's geography. Cape Verde has virtually no permanent springs and the topography of most of the islands, which are very mountainous, means that heavy rain simply runs down to the sea, the parched soil being unable to absorb it sufficiently. What is more, these downpours simultaneously wash away the little arable land that do" exist, thereby aggravating erosion. The whole situation is further worsened by the fact that the winter in this Sahelian region is very short. Despite huge efforts by successive governments, barely half the population has access to drinking water, with this figure barely reaching 25% in rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With a population of less than 400 000, there are just not enough people to pull off the miracle of making such an unforgiving soil bear fruit. Hence, although providing 50% of all jobs, agriculture represents only 17% of the nation's gross domestic product and produces only 10% of food consumed locally. The mountainous islands that make up Cape Verde are like teeth jutting out of the sea, and with virtually no continental shelf to speak of, small scale fishing is extremely difficult. Even with industrial equipment such as that installed on board large trawlers, catches are small - so small in fact that the country's fisheries agreement with the European Commission brings it only one million ECU over three years, one tenth of the proportional amount earned by neighbouring Senegal. Fishing thus represents less than 4% of the GDP.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mere survival - a</P>
+<P ALIGN="JUSTIFY">Herculean task</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Transport difficulties are another handicap for the economy. The sheer force of the harmattan, the strong ocean currents and the fog which often covers the region, make journeying by boat between the islands frequently hazardous. In addition, the volcanic relief of the islands makes them difficult to reach and means that there are very few locations that make suitable har  bours. construction is both complex and costly due to the steep rocky barriers that seal off deep valleys. Those roads which have been built under the FAIMO scheme (Highly Labour-lntensive Projects) have sometimes turned into real labours of Hercules, and many areas, especially those on sparsely-populated islands, remain completely cut-off. The use of aeroplanes only partly solves the problem. Although competitive, the prices charged by the national airline, TAICV, are still too high for the average inhabitant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Not only does the soil on Cape Verde contain very little water, it has virtually no natural resources: a few stones, lime, pozzolana and a little salt. Within the manufacturing sector (which makes up less than 20% of the GDP), only the construction and civil engineering industries, representing more than 10% of the GDP, contribute in any significant way to the economy, thanks partly to the transfer of currency from emigres who invest in the construction  sector and works with wide public interest. These works, known as FAIMO schemes, have to some extent given this impoverished country a gloss that masks its poverty. Launched after Cape Verde gained its independence, they employ more than 25 000 people for up to ten months of the year in the construction of paved roads or in reafforestation projects, and ensure the survival of one hundred thousand people - over one quarter of the population. The workers are on the whole recruited from among farm labourers, with another large section of the workforce being made up of 'Solteiras' or 'single women', numerous in a country where the male population is constantly emigrating. Unfortunately, the liberal option adopted by the present government has cast some doubt as to whether these projects will continue and this year, for the first time, work ceased in April - three months ahead of the usual termination date. Yet the poor wages which these seasonal jobs pay (ECU 2 per day) are sometimes the only source of income for some families.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only the tertiary sector shows a healthy balance of trade, accounting for  more than 60% of the country's gross domestic production, with the biggest slice of the sector going to the hotel industry, followed by the transport industry. Although, overall, Cape Verde's balance of trade records a large deficit, the balance of trade for the services sector generally shows a profit, with the transport services provided by the international airport, Amilcar Cabral de Sal, alone accounting for 13% of exports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Barely 10% of commercial goods are domestically produced and this has at times fallen below 5%. Cape Verde is therefore genuinely dependent upon foreign aid. Official development assistance represents 27.8% of the GNP (1989 figures), having risen from 17.7% to 27.2% of the GNP between 1980 and 1986. Cape Verde also relies on a second source of income - its emigrant population. In 1990 the currency transfers of its emigres represented nearly 20% of the GNP. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The colonial heritage</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contributing too to the country's poverty are relatively low educational standards. In this area too, successive governments have continued their predecessors' efforts to improve standards of education. However, at the time the country achieved independence, it was in a deplorable state. The reputation of a small intellectual elite of Cape Verdians had, over several decades, led the world to believe that Portuguese colonial rule had been 'enlightened'. This was a mere illusion. It was not until 1917, when the Mindelo grammar school was founded, that the country was able to claim an educational establishment of any cultural sophistication. The Mindelo school was the first state school in the country and it was to provide the nation with its first batch of 'home-grown' intellectuals. Until the middle of the nineteenth century, the Church, which was in charge of all matters educational, had provided basic primary education; then, at the end of the last century, it opened two secondary schools with the purpose of training students for positions in government and the civil service.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Even so, the Mindelo school remained an exception until the middle of this century. In 1950, no more than 5000 children received primary education and no more than 400 went to secondary school. Thirty years earlier, the figure was slightly higher, but Salazar, with his retrograde ideologies, saw education as dangerous and threatening and trimmed the number of schools on the islands from 150 to 60. True, Cape Verde was undoubtedly in a better state than other Portuguese colonies, but, with an illiteracy rate of 80% at the beginning of the 1960s, its position was nevertheless far from enviable. It was not until independence that any real progress was made, with 60% of children attending primary school in 1989 (the average for LDCs is 54%). However, this figure is still well below the average for developing countries, which stands at 90%, and even now, only 13 % of children have access to secondary education. As for higher education, this is virtually only available abroad; in Europe, Brazil, USA and Cuba, in particular.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Serious health problems still exist, exacerbated in particular by the scarcity of water. The cholera epidemic which has struck several African countries over the last two years has killed over 150 people in Cape Verde. The prevalence of AIDS exceeds the average for sub-Saharan Africa, with more than 2000 people being HIV positive and with some one hundred having developed the full-blown disease. According to official figures, 70 have died of the disease. The cholera epidemic which, unlike previous epidemics has affected towns much more than rural areas, is a sign of the deterioration of sanitary conditions in towns - particularly in Praia - affected by a lack of water, a dilapidated sewerage system and overcrowding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anchoring the country's economy in its culture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet, through all the doom and gloom, a small miracle is taking place in Cape Verde. Despite such a heavy burden of poverty, the country has, since gaining independence 20 years ago, managed to clamber up the league tables notably in the essential areas of health and education. Life expectancy at birth, which was only 52 years in 1950,  had increased in 1992 to 64.7 years, better than the average for developing countries and 13 years more than the average for sub-Saharan Africa. The infant mortality rate which stood at 110 per thousand in 1960, had dropped drastically to 50 per thousand by 1992, while virtually all children now receive essential vaccinations. Malaria is also now rare. In 1988 the GDP of Cape Verde amounted to only C.V.Esc 20 billion ($289 million), in other words, 6.9% of the GDP of Trinidad and Tobago, and 16.6% of that of Mauritius. But it is growing steadily. From 1980 to 1988, it grew by 6% per annum, compared with 3% per annum for the Sahel, and since 1980 the GDP per capita has doubled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The solution the nation's leaders should be seeking is greater integration in the global economy context by encouraging foreign investment. They do not need to create free zones but free enterprise, such as the shoe manufacturing concerns which, over the last two years, have contributed to achieving a considerable increase in exports. Various steps have been taken to attract investors, such as the adoption of the principle of tacit acceptance of applications for investment within 30 days. The Prime Minister, Carlos Veiga, and the 'Super-Minister' for Economic Coordination, Antonio Guelberto do Rosario, have highlighted the service, tourism and fishing industries as top government priorities. In order to develop these areas they intend to invest in infrastructures, with the aid, of course, of foreign backers. The modernisation of the port of S&atilde;o Vicente and of the international airport of Sal are currently underway, and the telecommunications project to link the islands by cable has also already been launched. The government's short-term plans also include the development of industries connected with the islands' culture. In the words of Mr Veiga: 'We in Cape Verde should develop our culture and use it as our anchor, to prevent our country drifting into oblivion. That way, our tiny country, which is fortunate enough to have a strong cultural identity, will be a Nation rather than a just a State'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H.G. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Interview with President Antonio Mascarenhas Monteiro</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A wealth of culture and a realistic approach to diplomacy: Cape Verde's two major assets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- How the current government differ from the former administration which had Marxist leanings ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The two eras are distinct from each other in that, since 1990, the Cape Verde people have been able to choose a life of freedom and democracy. Before that, for the   first fifteen years after independence, there was a single-party system. So it is also valid to speak of a break - a break with the way in which institutions used to function at a political level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-The single-party era does not seem to have been as strict as in other countries and the current regime appears to be continuing along the same lines in some areas. Was the former administration not, to some extent, responsible for initiating the change which has taken place ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - No, that's something else entirely. I often say that we had a civilised single party, and I assume that is what you are referring to. However, it is not possible to speak of continuity when formerly we had a single party and now we have moved on to a system where there is freedom of expression and new parties can be set up. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Admittedly, the single party did initiate a change when it created the conditions necessary for the advent of democracy. It removed the infamous Article 4 from the constitution, which seates that the PAICV was the guiding force of society and the state. In fact, it was the PAICV which drew up the country's first electoral laws whereby we were elected. When I say 'we', I mean the party which is in power and also myself, President of the Republic. The single party thus opened the way to  democracy here: that much is undeniable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Am I also right in thinking that many of those who are in power today received their training in that single party ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - You are quite correct. When a change such as this comes about, one has to appreciate, and I do not wish to be elitist here, that it is the higher echelons of a party which lead the move towards change. Such people were there, working in the administration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Since politics gives direction to economic affairs, has there been a total turnaround in this sector, with a clear decision to opt for liberalisation and privatisation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Before 1990, we had a staterun economy. After that, the country's economy was opened up with a number of privatisations, fewer import restrictions, and so on. The word 'break' is also applicable in this area in that we now have a market economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Do you feel that the economy has really shaken off state control given that the govemment still manages important sectors, such as the price of raw materials ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That is necessary a market economy does not mean that the state is entirely absent. I am in favour of a market economy, but with state monitoring. As far as possible, the state has to correct the injustices which are necessarily generated by competition. This is not, as some would have it, ultraliberalism. The government is still entitled to monitor the economy, but the change has been greatest in terms of attitude, in terms of the way things are done.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Do you, like many leaders of developing countries, believe that the requirements set by international institutions as regards structure/ adjustment are too great ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - We are not subject to compulsory adjustment - it is on a voluntary basis here. However, I do feel that adjustment, as implemented in Africa, sometimes has regrettable aspects. On occasion, it is asking a little too much to impose the same requirements on countries whose actual situations are very different. What is applicable to Nigeria is not necessarily suitable for S&atilde;o Tome.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-The 1992 constitution switched Cape Verde over from a presidential system to a parliamentary system. As President of the Republic, do you fee/ trapped by this constitution ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Cape Verde's constitution was never a presidential one. The system under which I was elected is effectively 'semi-presidential'. Admittedly, the constitution which was approved by Parliament in 1992 reduced the powers of the </P>
+<P ALIGN="JUSTIFY">President, particularly as regards the right to dissolve Parliament - which was unrestricted in the 1980 text. The revision was made to permit democratisation and ensure the proper functioning of the institutions, and it was therefore fairly wide-ranging. Now, in order to dissolve Parliament, the President has to have the support of the Council of the Republic, which means that his hands are tied to some extent. Previously, the President could also dismiss the government, without too many restrictions. I would say that the President's prerogatives have undergone a substantial reduction in comparison with those exceptional powers. As for the rest, things are as they were. In a semi-presidential regime as that envisaged by the 1980 constitution, the President has no executive role.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You seem to have chosen to play the role of 'wise man' Some observers think you give the Prime Minister too much leeway.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - They are wrong. The Prime Minister's post is conferred on him by the constitution. He is Head of Government and it is he who governs. I cannot govern in his place. What is true is that there is a great deal of ignorance - people do not restrict themselves to their own fields and attempt to teach lessons in subjects they are unfamiliar with. Germany has a parliamentary  regime like we do - what is the position of the President of the Republic in Germany? If you were to ask a Cape Verde intellectual for the name of the President of Germany, he would be unable to answer you. The parliamentary regime does not give the President of the Republic any powers to run the country. I do not know what the Prime Minister can have taken away from me because I have no power for him to take over. However, I would say that, here, the President of the Republic does have a fairly high profile, in spite of his reduced powers, because all the country's citizens know him. In terms of foreign policy, he plays a significant role in that he represents the country abroad. I attend international conferences like the Rio Summit, go to meetings of the OAU and sign international undertakings on behalf of my country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The President is also the guarantor of the new democracy, which observers seem to regard as well-established. But there still seem to be some bad habits. For instance, I have heard criticism of MPD power and of the fact that state  resources are made available to one party at election time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Look, this is criticism from the government's opponents - it is a normal state of affairs and happens everywhere. Any party, in any country, which has a parliamentary majority, can govern easily. This is possible, even when the majority is very small - and even in Europe. Look at Portugal when Cavaquo Silva was Prime Minister. There were people who said it was a PSD State. You will be familiar with France when Pompidou and even de Gaulle were in power, and Francis Mitterrand used to speak of a Gaullist state. As far as the election campaign is concerned, I am not aware of the government here having monopolised state resources and I don't believe this has happened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Another important factor involved in democracy is the press. Several journalists from the private media sector are awaiting a decision from you on a number of points - for example the lack of pubic support for the private press - in contrast to thestate-run press which has access to all that it needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - What decision are they waiting for ? Do they want me to decide in favour of resourcess being given to the private media ? I have already done that on a number of occasions. Recently, I had a meeting with the Prime Minister and I brought this matter up. He told me that it was something that was currently being considered. Sometimes, however, I get the impression that some of my critics want me to do the work of an opposition leader and to oppose the Government. That is not my job. I think that the President of the Republic, in a regime such as ours, ought to be a unifying force and not someone who foments political tension and instability. That is something I have always tried to avoid, but I do have sufficient courage to tell the government and the Prime Minister exactly what I think and I have actually dared to criticise them publicly several times. I am sole judge of the criticism I make, and I decide if it is appropriate and also when the time is right. Sometimes, people would have   me criticise the government according to a timetable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· A number of journalists in the private sector are currently being prosecuted and these actions nearly all originate from sources close to the government Surely if they were actually acting unprofessionally, we would see legal actions from parts of society, such as business, and not just from the political class.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The reason for this is very simple. It is the political class that they vilify. I myself have been insulted on a number of occasions and, despite having put up with it for five years, I have not instigated any lawsuits. There was one case which was taken seriously by the Attorney General's office and there  were other cases when the Prime Minister was called a thief. I would ask you, is this a normal state of affairs ? Does freedom of the press mean that it can call a Minister or the Mayor of Praia a thief? Is that what is meant by democracy ? You have to be aware of the background to these court cases - and there are a good many of them, some dating from 1991. They are not designed to 'get at' any particular newspaper. The reason many of these cases have been brought is because serious insults of the kind we are talking about are a crime. That is true of even the most advanced democracies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In economic terms, Cape Verde does not appear too badly off. But some economic indicators do give rise to concern, notably the big gap between the export and import figures. How do you see your country's future when it no longer relies so much on international aid ? Do you believe in the dream of many of your fellow countrymen, that Cape Verde will be Africa's 'little dragon'?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Unlike some people, I have never spoken of becoming a dragon. I don't like this expression. I do believe that, despite our enormous problems - Cape Verde has few resources and we have been in the grip of drought for many years - it does have a number of assets. We are capable of making progress and I believe that there are a number of promising areas which have already been identified: for example, fisheries, tourism and even 'foreign' investment. We have to be optimistic about Cape Verde's future. We are in a difficult situation, everyone knows that, but we are a hard-working and courageous people and our prospects are good. The country will be able to forge ahead.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-On the diplomatic front, Cape Verde appears something of an expert at maintaining good relations with different regimes: for instance, with both Israel and the Arab countries, with China, and with South Africa before and after apartheid. How do you manage this ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - There is no magic formula. Since independence, Cape Verde has tried to adopt a realistic and pragmatic foreign policy. We are a small country with no great influence on the international scene and we have to be on good terms with everyone. That is the principle on which we base our foreign policy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Cape Verde and Guinea Bissau used to be fairly close - do you foresee any future rapprochement, perhaps in some form of federation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is difficult to say. I feel that there is already a degree of rapprochement in progress, particularly in economic terms. Recently, we signed a civil aviation cooperation agreement, and there are opportunities for similar achievements in the fisheries and shipping sectors as well. Relations between the Cape Verde and Guinea Bissau governments are excellent but, to my mind, the idea of our forming a federation is out of date. It would not be in our interests nor in those of Guinea Bissau. We do, however, intend to develop a closer economic relationship and our political relations are very good indeed. I would wager that our partners in Guinea Bissau would give you a similar analysis of the situation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-In cultural terms, can it be said that your country has succeeded in becoming a multi-ethnic state ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The important thing is that the Cape Verde people should have their own identity; that there should be a specific Cape Verde culture. What I would say is that all the citizens of Cape Verde are proud of their culture and citizenship. This constitutes a great source of strength for a country such as ours which has major challenges to overcome. Our culture is also an asset in our country's development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interview by Hegel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interview with Aristides Lima, leader of the Opposition</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'The government owes its victory to abuse of the electoral system'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· As main leader of the Opposition, what are your views on the fact that the governing party has recently been reelected ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I believe the country's economy is in crisis. Growth rates are not very high, just like in the 1980s, for example, and there is a high level of structural imbalance. Unemployment has increased: in 1990, unemployment stood at approximately 25% and now it is 30%. There used to be 25 000 people who worked in what we call the high intensity labour sector and who had a job for about 10 months of the year. They were recently laid off early. Such jobs were part of a social programme which, amongst other things, enabled us to build roads. The prices of staple products, such as sugar, maize and rice, which were stable, have just gone up, and the price of cement, which was also controlled to promote economic growth, is no longer subject to the same control and I can foresee this giving rise to many problems in areas outside the towns and cities. In Praia, a 50-kg bag of cement used to cost 440 escudos and, although that price will stay more or less the same, on islands like Fogo, it will go up to about 660 escudos. This will generate problems for economic growth and a number of major projects in the tourism sector, for example, will suffer. The balance between exports and imports has also been adversely affected in that the level of coverage of imports by exports has fallen, despite announcements to the contrary made by the government.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· From 1993 to 1995, exports tripled in volume, if the government is to be believed. What are your thoughts on that ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The problem is that, in this country, some exports rely on the import of considerable amounts of raw materials. For example, in S&atilde;o Vicente, there is a shoe-manufacturing plant which gets its supplies of raw materials from abroad. The same applies to fishing and a number of fisheries products, such as anchovies, which are still canned in S&atilde;o Vicente but which have to be imported from Chile or elsewhere. This causes great problems when it comes to managing the country's foreign currency reserves, which have fallen markedly. In 1990, reserves provided over 6 months' coverage for imports, but now we have to operate in terms of weeks or even days.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Nevertheless, the government could say that it is not responsible for the economic picture you have just painted because the world economic situation is hitting all small countries harder.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - No, the government is responsible, because it has been unable to implement the appropriate liberalization policy. For example, this should have been applied gradually to the trade sector, but the government rushed in and has now had to backtrack on goods which needed import authorization. What happened was that it lifted this authorization requirement but has now  had to bring it in once again. And another thing, the policy of liberalization has not been accompanied by very high levels of foreign investment and, in addition, the country's skilled workers feel marginalised, all of which goes to make the situation worse. As for structural adjustment, the government has always supported the idea of 'less State equals a better State', but, in practice, we have seen spending on the State's everyday activities go up and up. Civil service staff levels have now risen to about 12 000, compared with the former 10 000. However, increased spending is also a result of a not always equitable wages policy - the difference between the highest and lowest salaries is huge and, in some public bodies, one worker might be earning 15 times as much as another.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· According to the Minister for Economic Coordination, the currency is under pressure as a result of the Opposition's irresponsible scare tactics of announcing a future devaluation, leading to the stock-piling of currency and goods, a kind of artificial speculation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That's a very good way of offloading one's responsibilities - the Opposition did no more than criticise the government's policy and point to the   facts of the situation. It was members of the government themselves who acknowledged the low levels of currency reserves and the State bank which suspended transfers abroad. The Minister would have people believe that the Opposition lacks any credibility so how could this same Opposition have any influence on peoples' behaviour? The problem is actually extremely basic: economic operators, society and foreigners are not really au fait with the country's real economic situation because the government does not issue information, which is one of our basic criticisms. Parliamentary representatives and political parties no longer receive the figures they need and the latter are sometimes forced to consult foreign sources or to rely on their personal links with people who are close to sources of information. I myself criticised the Prime Minister for adopting this attitude of regarding information as subversive. I asked the Prime Minister for a copy of the study on Cape Verde's economy by a Portuguese professor, which had been paid for with tax payers' money. I never received it. For our part, we hope that Cape Verde's partners will be able to recognise the true situation and persuade the government to act in a more equitable manner.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Nonetheless the people cannot be too disappointed, because they reelected the government for another term.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That could be explained in many ways - the government controls information and therefore holds the reins of power. It controls television, radio, part of the print media, and the private-press sector is fairly weak, so it has been able to manipulate information and give people the idea that the country is on the right track. The government did do things to change peoples' lives, but it exaggerated its achievements using the State social communication means available to it. In fact, it did not achieve the major objectives it set itself: firstly its fight against unemployment - a failure. Balancing foreign economic relations - another failure. Balancing the domestic  economic situation: differences between our various islands have become more acute. In matters of health, Cape Verde made major advances when our party was in power and, although, to all intents and purposes, the health sector is just as good when compared with other African countries, it has, in fact, deteriorated. Diseases which had been eradicated from the country are returning, like malaria, for example, cholera, etc. Health services are concentrated in the capital city, Praia, and there is no decentralisation, which has negative effects on even links between carers and patients. Humanism shows the effects of a situation such as this, and it applies not only to health: there is an unfair distribution of State financial resources between the central government and local government. The State has been unable to reform local finances and has politicised transfers of funds to those districts which are closest to it. The government has also profited from the structural problems encountered in the working of our democracy. One of these structural problems is Parliament's weakness: it sits only three times a year and the representatives do not work full-time - they are sometimes employed by the administration which they are supposed to monitor. Democracy has a price and although savings can be made in other spheres, when one is  seeking good governance, one of the conditions for which is a strong, functional and effective Parliament, this is not possible. The weakness of the private-press sector is yet another problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-And are you continuing to work in the administration ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I am a 'full-time' parliamentary representative. There are now about 10 out of 79 representatives who work on a full-time basis. They are members of Parliament's office, chairmen of committees and parliamentary leaders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-The government says that it inherited a serious state of affairs when it took over power from the PAICV.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is simply not true that the good life began with this government's accession to power. Here's a little history lesson: think back to colonial times. Admittedly, there were negative aspects to our time in power but you must remember that the PAICV did, in fact, leave in place the subjective.  physical basis for the new policy direction. When we achieved independence, Cape Verde had no ports or airports, apart from small-scale port facilities at S&atilde;o Vicente. We built the port at Praia, the port at Sal, the port at S&atilde;o Nicolau and a number of airports. The telecommunications system was also set up by the PAICV government and we implemented the initial educational reforms. In the 1980s, the GDP growth rate was 7%and the per capita income was one of the highest in Africa, more than $820.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The party in power describes the PAICV as marxist and non-democratic claiming that it was they, not the PAICV, who introduced democracy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That is nothing more than rhetoric, because all of the current governing party's members were in the PAICV - they were radicals, more marxist than anyone. Everyone knows that here, in Cape Verde, we had a pragmatic party, not a marxist party, although marxism was a source of ideas for many people. The idea was not to build socialism here. In those days, we had an open, not a centralised economy and all trade was private. We always had a market economy and to describe us as non-democratic is idle rhetoric. The PAICV's ideology has always been one of national liberation based on political and economic independence, with power vested in the people. This was a normal state of affairs during a national liberation struggle and, although it would be true to say that we were influenced by a certain single-party model which had gained widespread acceptance in Africa, the single party here could not be compared with any other. Both the PAIGC and later the PAICV attempted to force people into taking part in citizens' assemblies in order to put forward suggestions to the candidates. The current Prime Minister, Mr Veiga, for example, was put forward by a militants' assembly - he was on the PAICV's lists and they used to sit one beside the other on the benches in Parliament. The regime was, I suppose, slightly paternalistic but it was the people themselves who were really responsible for national liberation, it was they who had an idea of justice, patriotism, of being African, which explains the total commitment of Cape Verde's people to our party in the struggle for independence and also the good results we achieved when in power.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Why, then, were you not re-elected ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The party had been in power for a long time, with the same president, the same prime minister, the same president of the national assembly and virtually all the same ministers. People were hungry for change because the ruling elite had been in place for so long. The international scene, also, did not favour the old single-party system. Another element, too, was the Church, which fought us over the question of abortion. Perhaps I should point out that, from the very beginning, a section of the Catholic church was not in favour of independence, but younger members of the clergy, with more sympathetic feelings towards the population, supported us and, thus, we changed peoples' attitudes. The Church in Africa is a phenomenon worthy of greater analysis, particularly in Cape Verde, where, I feel, the current government was able to take advantage of the Cape Verde peoples) essentially religious nature to criticise us and present us as an anticlerical party. In fact, the situation is quite different: most PAICV leaders and militants are Roman Catholics and some church" were damaged by opponents in an attempt to discredit the party. Another example of abuse of the electoral system, apart from taking advantage of the peoples' religious nature, is the country's poverty. During election campaigns, the government make it easier for people to obtain food, and it also creates more jobs, en masse, but these disappear again after the elections - precisely as is happening at the moment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· As it is governed at the moment, Cape Verde is regarded by other countries as a 'star pupil'. Surely this is another success for the government ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Cape Verde has always been regarded as a star pupil because, here, our society is fairly homogeneous and there are no major social or ethnic imbalances. However, in my opinion, the future depends on changes at a structural level and such changes cannot take place unless we have a functioning parliament and a strong private press. I cannot deny that the government has had some successes, but I also believe that the people will have an opportunity to judge how it keeps its promises.  interview by Hegei Gouger</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">A portrait of towns and cities with atmosphere</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It suffices for an unruly little bird to escape</P>
+<P ALIGN="JUSTIFY">For, suddenly, Fire to spark, Night to dissolve</P>
+<P ALIGN="JUSTIFY">The walls of every prison to cave in</P>
+<P ALIGN="JUSTIFY">From the tidal-wave battering</P>
+<P ALIGN="JUSTIFY">Amassed, in its untamed heart,</P>
+<P ALIGN="JUSTIFY">By a tiny breathless bird.</P>
+<P ALIGN="JUSTIFY">(Mario Fonseca in 'La Mer a tous les coupe')</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most cities in the Third World devote all their energy to mere survival and there are few imbued with the same atmosphere as Mindelo - the very air  appears to brim over with art and good taste, beauty and sensuality. Our guide to the city speaks slowly, measuring his words, his delivery not an indication that he is searching for a translation, although it could be interpreted as an affectation, but matching the modulation of the language which is closest to his heart: 'I believe the air in this city is imbued with hedonism. Here, we mix work and pleasure - today is a holiday, but I am working. However, my day is not so rigidly timetabled that I cannot do some work and, since you have invited me out for a drink, take some time off to accept'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antonio Firmino, director of the Craft Centre, continues to tell us about his favourite city in the same steady language, a dreamy look in his eyes and wearing a Che Guevara-style beret. The tale he tells is the story of a tiny country which has fallen in love with culture: the actual building housing the Craft Centre used to be a school, the 'Mindelo Technical College', founded in 1917, the first secular educational institution. It was to transform the city into a cultural haven. The story goes that a certain senator named Vera Cruz, who represented the island of S&atilde;o Vicente in the Portuguese Senate, wanted to establish Cape Verde's first college. His peers objected, arguing that Mindelo had no building worthy of housing an institution of such a high standing but</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vera Cruz straight away replied: 'So, why not use mine?'. Thus, he casually handed over his private residence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Art even in the fish market</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How many inhabitants are there in Mindelo? According to Antonio Firmino, 'Just me and my friends'. How right he is. It would be impossible not to become part of such a captivating place. And so a long journey began, which included the creation of Claridade, a review (and cultural movement) established in 1938 by Balthasar Lopes, a writer and essayist of world renown who was born in S&atilde;o Nicolau but taught in Mindelo, and other great artists who were to make up the country's literary and artistic roll of honour. Claridade was to be followed by Certeza which was also to influence the cultural elite. Although historians and other commentators feel that Claridade did no more than praise Cape Verde's 'latinity', rejecting its African side, artists are unanimous in regarding it as the cradle of Cape Verdian intellectual culture and the soil which was to nurture Mindelo and make it such an extraordinary little town. The impression is that everyone here is interested in art - the local authorities encourage and help sculptors in their creative activities all over the town, making it a living museum: here, there is a painting by Antonio Concei&ccedil;&auml;o and, over there, a huge flat sculpture of couples in languorous embraces, by Ro and Anildo, an illustration of the marvellous hedonism evoked by our host.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The same assured but delicate touch of these two artists can be seen in the lobby of Fishpackers, an anchovy- and tunapacking company, this time in the form of a celebration of fishermen. One of the finest examples of this type of art, which can be seen everywhere in the streets and public places, is the sequence of four huge decorative-tile frescoes in the fish market. When Bela Duarte showed them to us, it was such a delight to see how much at ease this famous artist was in the company of the staliholders, to whom both she and her work seemed so familiar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over and above this hedonistic atmosphere, there is, in Mindelo, an eclecticism which can be detected just as widely in other towns and cities, which means that you can talk about painting with the President of the Republic, dancing with a factory manager and decorative tiles with the man in the street. And the latter is literally 'in the street' - the inhabitants of S&atilde;o Vicente, the capital, derive immense pleasure from strolling in its squares and narrow streets, and around the port. A little stall, looking like a sugar loaf in the middle of one of the city's many squares, opposite a grand hotel, opens up in the early evening just like a flower, attracting hundreds of people to it who come to quench their thirst, to converse or woo, and to dance to the music escaping from the terrace of the Porto Grande Hotel, which has just reopened after being privatised and modernised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is as if a dress ball were taking place on two different levels, one in front of the other, dancing to the same music and with equal pleasure: above, in an enormous gallery open to the sky, elegant guests (who include a small gathering of government officials and pretty Brazilian actresses who are here to film television soaps) and, down in the square, the dancing promenaders, full of admiration, almost stimulating those above.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verdian nights</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like all the island's intellectuals, Antonio Firmino has a number of different jobs. In addition to running the </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Craft Centre, he teaches 'nautical' English to would-be sailors, is an amateur painter and musician (he plays and composes for his wife, who is a singer). His spare time is devoted to writing a column. The Craft Centre exhibits, amongst other things, a large number of tapestries, an art form much prized in Cape Verde. These admirable examples are by Ju&auml;n Fortes, Juamo Pento, and a good many others, in particular Bela Duarte, Tchal&ecirc; Figueira, Lucia Queiros and Miguel Figueira, Mindelo's top artistic foursome who appear to be  involved in everything, including the frescoes at the fish market. Bela, who showed us her studio, her house and the fish market, does not conceal the joy she derives from colour and allusion in her pictures, tapestries or decorative tiles, ranging from the most distant abstraction to an anecdotal figuration, using her native land with its doleful nuances, soft cries and romantic strength as raw  material. Above all, there is convivial artistic writing: 'Resistencia', which is at first sight a tapestry and then a patchwork of colour and sinuous lines. Scarcely has the artist begun to explain her work than everything becomes clear: this is a story, in threads and colours, about drought, representing roots, energy, space and struggle, all part of the Cape Verdian soul. She is also paying homage to those weavers of traditional African loincloth (badiu) from Cape Verde from whom today's artists inherited their technique.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So, where to meet Antonio's friends? To find them, look no further than the Cape Verdian nights (noite caboverdiana), those gatherings which take place everywhere and resemble both a nightclub and an artistic association, all those present sharing a fondness for Cape Verde mingled with nostalgia and yearning. One such place is the Piano Bar, which was closed on account of the departure of its owner Chico Serra, another notable in local society, who was accompanying a friend, C&eacute;saria Evora, in her attempt to conquer new lands. Mission accomplished, Chico Serra is back and will soon be open for business again, his club's atmosphere just as intimate and warm as before - just enough room for his piano, his musician friends and others who come to sample grog and music.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Africa nonetheless</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mario Fonseca also adores Mindelo but he would not agree that that wind-blown city has a monopoly on art and culture. He is from an island in the lee of the wind, from Praia, capital of the island of Santiago and of the country. In his opinion, it is the whole of Cape Verde which is bubbling with creativity and he will enchant you with his tales of Praia and its old colonial district, the 'Plateau', which still retains much of the nostalgic character to be seen in the now yellowing photographs taken 50 years ago when the city was not so sprawling and the ambience of Sucupira market was almost tangible. He will also tell you everything about the island of Santiago, with Cidade Velha, the ancient capital  which was too difficult to defend against repeated pirate attacks. It bowed to Praia's supremacy and, today, has an old-fashioned feeling, nestling within a cove around the ruins of its castle, and dominated by the fort which perches above a cliff face. The architecture owes much of its charm to the predominant Creole style which is vaguely reminiscent of Portugal, in every pastel shade. Cidade Velha's central square is caressed by a gentle breeze and groups of young people can always be seen lazing around the monument to the slaves. Time seems to stand still. The pretty little white church whose walls are decorated with sheaves of bougainvillaea, Santa Maria do Rosario, is the oldest on the island and, indeed, along the entire West African coast. It was built in 1460 and the white marble paving in the central nave conceals the final resting place of grandees from colonial times, their epitaphs erased over five hundred years by the soles and knees of penitents.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The director of the INAC (National Cultural Institute), responsible for Praia National Museum (which is soon to open its doors), is Mario Alberto de Almeida Fonseca, who once taught French in Portugal; he is a former administrator who has worked in Mauritania and Turkey, a translator and also a former regional manager of the national airline. In addition he is a poet whose works have been translated into several languages, including Serbo-Croat and Russian. Above all, he is an amateur connoisseur of the art and artists of his country. As the INAC's director, he is responsible for cultural events, exhibitions, shows, publishing and also the compilation of an oral record of the country's history and the preparation of  a Creole dictionary. The INAC's work also involves a major history of Cape Verde, the first volume of which has already been published. He will show you the future National Museum's collection, moving from one painting to another, from an old photograph to an antique cimboa, a type of locally-manufactured violin from the 1 9th century, or to an old Massachusetts galleon, testament to the past explorations of his people. You will first of all discover the works of artists from Praia such as Mito and Kiki Lima, not on account of Fonseca's chauvinism but because he feels he has to 'convert' the visitor who may have left Mindelo with the impression that that city is Cape Verde's premier cultural centre. There is also the music from the island of Santiago - the funana, the batuque, the fina&ccedil;o - all more African than the languid style so influenced by the Portuguese fado of this island's musical groups (Fina&ccedil;on, Bulimundo, Tuvaroes, Kod&eacute; di Dona or the great traditional style singer Nha Inacia Gomes). Gomes is a 'women of the people' whose musical heritage consists of no more than local tradition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It was she who 'reinvented' jazz and whom Alberto Fonseca admires a great deal. Cesaria Evora, moreover, is not the first musician to publicise Cape Verdian music abroad: Fina&ccedil;on or Kod&eacute; di Dona, for example, have captivated many music-lovers, particularly musicians, in Europe and America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Chamber and the stage</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Daniel Brito is not from Mindelo either. He is from Sal but confesses to having to pay regular visits to Mindelo, to immerse himself in that city's hedonistic atmosphere. For three years he has been director of the National Cinematographic Institute which was established in 1967 and is currently exhibiting newfound dynamism on account of the 'production tax' (4% of the filming budget, paid to the Institute and generally converted into a holding, which the State supplements to make the sum up to slightly more than 10% in co-productions). There is also an agreement with Portugal which encourages co-productions between the two countries, thereby enabling Cape Verdian technicians to receive their training. Brito is working on a local video-film-production project (TV viewers are very fond of such things) and wants to set up a major production centre to be made available to lusophone African countries and, perhaps, others. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Daniel Spencer Brito is also Sal's parliamentary representative (10 000 inhabitants), musician, writer/composer and guitarist in his own group, Madrugada. His talents include the composition of morna and coladeira pieces, as well as jazz-rock. At the end of May, the MP was due to appear in his own production at the Cirque d'Hiver in Paris, as part of the lusophone music festival. You could say that he divides his time between the Institute, the Chamber and the stage; however, he is also involved in research into copyright protection in Cape Verde. Daniel (it would never occur to you to call him anything else, even five minutes after making his acquaintance) always gives the same advice to anyone wishing to discover Cape Verde, namely to get to know the atmosphere of a tocatinha, spontaneous jam sessions which take place at one location or another, usually even more intimate than the 'Cape Verdian nights'. By the way, I almost forgot - by training, Brito is a vet, having studied in Romania. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H&eacute;gel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Cape Verd-EU Cooperation</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sponsors are delighted at the full use of aid</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde's physical characteristics - its small size, the fact that its territory is scattered over a number of islands and islets, its Sahelian climate (continually rendering it vulnerable to drought), the arid nature of the soil and its low population (under five hundred  thousand inhabitants) - might explain its high levels of poverty and mean that, in order to survive and develop, it requires considerable amounts of foreign aid. However, it is the effort made by this small country to stabilise its economy and to gain maximum profit from foreign aid which has attracted special attention from sponsors. Last year the European Commission decided to increase its contribution to Cape Verde's National Indicative Programme, within the framework of the Lom&eacute; Convention (tome IV, first protocol 199-95, seventh EDF) by 7%, i.e. an extra ECU 1.7 million. Cape Verde had already put virtually all the ECU 23 million allocated to it to good use, an indication of the government's desire to use the aid granted to the full.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When realism is a luxury</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is difficult to imagine an island inhabited by 160 000 people - the island of S&atilde;o Vicente, where the country's second largest city, Mindelo, with its population of 70 000, is located - having no source of drinking water. In former times, water was shipped in from the neighbouring island of Santo Antao, but Mindelo now has a number of seawater desalination plants, most of these provided by Israel, which meet 100% of its supply needs. The supply of both water and electricity is managed by</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Electra, a publicly-owned company, which, within the framework of the EDF (European Development Fund), has received European Commission aid to increase its electricity-generating capacity. It has set up three wind pumps, of Danish manufacture, which alone supply 13% of the island's non-industrial requirements. Elsewhere, such solutions as sea-water desalination and wind pumps might appear to be unrealistic but, for 160 000 people with no indigenous supply, realism is sometimes a luxury.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the island of Santiago, which is home to Praia, the capital city, does have some natural water sources, these are far from sufficient for its needs. One of the projects recently financed by the European Union concerned improvements to water-distribution systems, water purity and rainwater drainage. Amongst other things, this work involves the recycling of waste water which the island cannot afford to let drain away. Cape Verde's Achilles' heel is definitely its lack of water, its strong point unquestionably the dynamic outlook of its population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has an office on Cape Verde where the work done at Praia (water distribution and purity, support for poorer districts of the capital threatened with overpopulation) is regarded as symbolic of the EU's desire to take account of both weaknesses and strengths and represents the overall intention behind Community aid to this country. Generally speaking, such aid is geared towards infrastructures (water and electricity production and distribution, urban development) on the one hand and education and health on the other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Praia's historic old town, the 'Plateau', with its wealth of fine colonial and neo-classical architecture, risks losing many of its buildings which have been abandoned by their owners who lack the means to maintain them. Community aid has also been provided to help save this part of the country's heritage. Funds are insufficient to finance a complete restoration of the 'Plateau', but, following the example of the Cape Verde government, which has maintained administrative buildings in good condition, the Commission will probably assume responsibility for renovation of a superb nineteenth-century building, the 'Case Cor-de-Rosa'. The purpose of this project is two-fold; not only will the building be restored, but also it will become the core of a more general project to train professionals in building techniques and restoration and it will serve as an example to motivate future purchasers, institutions, businesses and individuals to preserve the historic old town.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Community has also funded a study into the preservation of the capital's historic old town, which has been used as a basis by Praia Town Council. A project is currently underway, costing 1 million ECU, to restore an islet. The principal aim of this project is to train Cape Verdian technicians. Other work in the field of training has induded the building of the Praia Technical College. The next phase of this project, worth almost ECU 1 million, will fund the supply of equipment and teacher training.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Still within the context of the overall project to develop Praia city, an EDF programme worth ECU 1.3 million has been created for the development of a designated area as an industrial site. A rural electrification project in the area around Praia was, at the end of 1995, granted a budget of ECU 1.5 million and will benefit a population of 7500 people living in the three most densely populated rural centres on the island of Santiago. The technical side of the works will be entrusted to Electra, with the private sector being responsible for supplying equipment and monitoring the works. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde's 'essence' as a resource</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cape Verde's leaders regularly point to the richness, which they term the 'essence', of Cape Verde, contrasting this with the fact that their country is so poor. Indeed, despite limited resources, this country devotes a great deal of energy and ingenuity to 'cultivating' its culture. Two projects, financed within the framework of the National Indicative Programme and amounting to ECU 500 000, concern two feature-length films and will play a part in lessening the island's isolation by publicising its culture and people abroad. The first film, made during 1995 and entitled 'llh&eacute;u de Contenda', is the first fiction-based feature film to be made in Cape Verde and is the work of Leao Lopes, a director who has drawn his inspiration from the work of another Cape Verdian citizen, Teixeira de Sousa, and which centres on the history of Cape Verde and the birth of its national identity. The EDF contribution (approximately ECU 250 thousand) amounts to 14% of the total production cost. The film is currently being shown in a number of European countries. Virtually the same amount of  money has been set aside to fund another production, this time by a Portuguese director, Francisco Manso, based on a novel by a Cape Verdian author, Germano de Almeida, and entitled 'O Testamento do Sr. Napuceno', which was being filmed on the island of S&atilde;o Vicente at the time of our visit. 50% of the finance for this film comes from Portuguese producers, the other co-producers being French and Belgian.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Others EDF projects recently completed or being completed include one for improving roads on the islands of Santiago, S&atilde;o Nicolau and Maio (ECU 3 million) and a micro-project programme (ECU 1 million). In addition to funds from the EDF, Cape Verde has received further finance under the Lom&eacute; Convention, including ECU 700 000 within the context of the Stabex transfer schemes to offset loses in the banana-production sector during 1994.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Design a micro climate</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Extemal food aid is essential in a country which cannot meet its own requirements and the Commission's most recent food-aid-budget contribution amounted to nearly ECU 2 million. Other special budget lines include funds provided under 'Human Rights and Democratisation in Developing Countries'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To an attentive foreign visitor, one of Cape Verde's most interesting achievements is the progress it has made in reforesting such an infertile soil. One of these reforested areas, covering 5000 hectares (1990-94) forms the basis of a regional project to disseminate knowhow accumulated in this sphere in Cape Verde. Training course. have enabled technicians and others involved in the reformtation of the Sahel countries to gain experience in methods which have proved succesful here. The production and distribution of teaching tools (books, posters, films, etc.) supplement the project. Since independence, Cape Verde has achieved a tenfold increase in the amount of land which is forested - admittedly there was little to start with, but since climatic conditions are so hostile this result can be regarded as a major accomplishment. There is even a hope that a micro-climate might form. On the island of Santiago, in some of these new green areas, wild duck which had long since disappeared have returned. It is nice to dream but the country cannot afford to rest on its laurels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">H&eacute;gel Goutier </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Profile</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Area: 4 033 km2 Population: 390 000 (1990) Population density: 97 per km2 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population growth rate: 2.8 % (forecast for the period 19922000) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capital: Praia (pop. 75 000)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other main town: Mindelo (pop. 65 000) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Languages: Portuguese, Creole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Currency: Cape Verde Escudo (CVE). In May 1996,1 ECU was worth CVE 104 ($1 = CVE 83 approx.) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Politics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government: Mixed presidential/parliamentary system. The President is not the head of the executive but he represents the country and is guarantor of national unity and the Constitution. Unicameral Parliament. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">President: Antonio Mascarenhas Monteiro (elected in 1991 and reselected at the beginning of this year) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister: Carlos Veiga (since 1991) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Political parties represented in Parliament:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Movimento pare a Democracia (MPD)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Partido Africano pare a Independencia de Cabo Verde (PAICV)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Partido da Convergencia Democratica (PCD) - formed as a result of a break away from the MPD</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Party representation in Parliament: MPD 50, PAICV 21, PCD 1 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(1992 figures)</P>
+<P ALIGN="JUSTIFY">GDP: CVE 23.9 billion</P>
+<P ALIGN="JUSTIFY">GDP per capita: US $840</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Origin of GDP by sector: agriculture 13%, industry 17%, services 70% </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Real GDP growth (estimate 1995): 4% Balance of payments: deficit of CVE 11.9 billion </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Main trade partners: Portugal, Spain, Netherlands, Brazil. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Annual inflation rate: 9.1%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social indicators</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy at birth: 64.7</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Infant mortality per 1000 live births: 56 Adult literacy: 66.4% </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enrolment in education (primary, secondary and tertiary): 59% </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Human Development Index rating: 0.536 (123rd out of 174) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sources: UNDP Human Development Report, 1995; Economic Intelligence Unit 1995; 'Etat et soci&eacute;t&eacute; aux iles du Cap Vert, by Michel Lesourd. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p32a.png"></center><br>
+ Figure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Europe</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">The Lom&eacute; Convention in focus</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Poll results and new brochure launched in Brussels</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A new poll of Europeans high lights a deficit of information about the European Community's development policies. A brochure just published on the Lom&eacute; Convention, available in all EU languages, seeks to fill some of the gaps.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At a press conference on May 21, Development Commissioner, Joso de Deus Pinheiro, unveiled the findings of a survey commissioned from the Brussels consultancy, International Research Associates (INRA). The aim of the exercise was to sound out how Europeans perceive developing countries. The sample was 16 346 people, of 15 years and upwards, who were polled in the 15 Member States during December 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The survey shows that since 1991, helping the poor in the developing countries has slipped in the 'league' of issues of most concern to Europeans. The subject now ranks eighth in a table topped by the fight against unemployment. But the better news is that Europeans believe development of these regions should be the fourth most important priority for joint actions between Member States. This comes just below combating terrorism, environmental questions and defending Europe's economic interests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While 82% of Europeans are favourable to development cooperation, 12% are against. The degree of support varies, as one would expect, from one EU country to another. Interestingly, the survey shows that Member States facing an economic squeeze are the most reticent, irrespective of their past track record in development aid. In Belgium, only 65% are in favour while in</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Austria and France, the figures are 69% and 72% respectively. At the other end of the scale, Greece comes out top with 97% just ahead of Spain on 96% and Ireland on 91%. INRA's explanation for this variation is that it reflects the economic problems which are increasingly being felt in northern states of the Community. It is also worth pointing out that nations on EU's southern flank may be more convinced of the effectiveness of aid since they themselves are recipients of EC structural funds allocated to modernise the Union's disadvantaged regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But INRA's report also reveals some misconceptions about European development aid. These, says Commissioner Pinheiro, may be attributed to the lack of visibility of the relevant development policies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">57% of those questioned believe that the bulk of the Community's assistance consists of emergency aid, rather than longer-term project support. The reverse is actually true. More people answer 'no' then 'yes' to the question: 'Does aid contribute to reducing poverty in developing countries'? And most consider that United Nations agencies (UNICEF, UNESCO etc.) do more in the  field of helping developing countries than the EC. Non-governmental organisations also have a high profile, with the EU Member States and Bretton Woods institutions (IMF and World Bank) trailing behind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other key findings from the poll - which Professor Pinheiro says will provide much food for thought in the coming months as thoughts turn to cooperation after Lom&eacute; IV - are highlighted in the box.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mid-term review and beyond</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Professor Pinheiro feels that some of results, which signal the need to tighten up on the management of development aid, have already been addressed in the mid-term review of the Lom&eacute; Convention which will come on stream from the beginning of 1997. The programming of the eighth European Development Fund (EDF) is already well under way and, with a view to increasing the effectiveness of aid, just 70% of resources earmarked for each ACP state will be allocated at the outset (for a three year period). An analysis of how the remainder should be spent will take place at the end of the three years. In addition, Professor Pinheiro indicated that a 'strategic' document was being drawn up on each of the 70 ACP states prior to allocation of funds. This was being done in 'permanent consultation with Member States and Commission delegations, in the interests of achieving a real synergy between the two.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More sweeping changes to the relationship are likely after the current</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some key findings from the INRA report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Aid must reach its intended destination and arrive where it is needed 93.2%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Aid must meet the needs of the local people</P>
+<P ALIGN="JUSTIFY">90.7%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The beneficiary state must raspect human rights</P>
+<P ALIGN="JUSTIFY">85.1%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Transparency, effective public management and the fight against  corruption are essential</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The beneficiary state must respect an overall development plan put forward by an  international aid organisation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">78.3%  plan  put  forward</P>
+<P ALIGN="JUSTIFY"> by an  internati onal  aid  organisa tion</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Aid must be used to fund action by local NGOs</P>
+<P ALIGN="JUSTIFY"> - The beneficiary state must have a democratic system of government</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">59.3%</P>
+<P ALIGN="JUSTIFY">56.0%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Convention expires at the turn of the century. Professor Pinheiro indicated that a first draft (green paper) on the possible shape of the ACP-KU relationship after 2000 will be published by the Commission by the end of the year. This, however, is likely to offer more questions than answers about future cooperation. 'I am not sure if we should keep the Lom&eacute; structure for every country, in the third millennium,' the Commissioner told the assembled journalists, highlighting the different levels of development now apparent between Lom&eacute; nations. Mauritius, now well on the way to becoming the 'Singapore' of Africa, was a case in point. He also pointed out the small island states of the Caribbean are at a very different stage of development from countries such as the Central African Republic or Burundi. He added that, in deciding what to do in future it would also be necessary to take stock of regional developments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Questions about Lom&eacute; answered</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the meantime, efforts are under way to boost the image of Community aid. With this in mind, the Information Unit of the Development Directorate-General has just published a brochure entitled 20 Questions and Answers about the Lom&eacute; Convention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Besides explaining in a nutshell what the Convention is, it answers some of the questions most frequently asked by sceptics about the benefits of development aid and trade preferences, highlighting the positive aspects for developing and developed economies alike. It points out, for example, that for every ECU 100 spent on aid, the Community recovers ECU 48 in the form of projects, supplies and technical assistance purchased from European companies!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The brochure provides a succinct explanation of how the Commission monitors aid to stop embezzlement and corruption. It highlights the right of the European Court of Auditors to check accounts of projects and fund transfers - and to investigate documents in the Lom&eacute; states, without the permission of the country concerned. Another precaution is that once a project is under way, financing is by banker's transfer. This involves a paper specifying that the holder of contract X, whose bank account number is Y. should be credited with Z amount of money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An explanation is given as to why the European Commission is involved in development aid when the Member States have their own bilateral development policies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The brochure explains the advantages of EC assistance over bilateral arrangements and details how the Lom&eacute; system has been evolving in line with the increasing globalisation of the economy, in particular since the fall of the Berlin Wall.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It also contains some pocket statistics on official development assistance (ODA) flows which help to underline the message that the European Union (Community plus Member States) digs deeper into its pocket than its industrialised competitors in providing development aid. In 1994, the Community and its then 12 member states (excluding Austria, Sweden and Finland), contributed an average of 0.40% of their gross national product in ODA. The individual percentages varied from 1.03% in the case of Denmark to 0.20% in Italy. This compared with figures of 0.29% and 0.15% for Japan and the United States respectively.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1994, total ODA from the Twelve reached $26.59 billion. Of this, $4.83 billion came from the European Community in its own right. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The content of chocolate</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Months of heated debate in the EU over the maximum allowable content of vegetable fats in chocolate have culminated in a Commission proposal for a revised Directive which, claim officials, should be to the taste of most interested parties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has proposed that the 'subsidiatity' principle should apply to the content of chocolate. This means leaving it to individual Member States to decide whether they will allow the use of vegetable oil - up to a maximum of 5% by weight - in their chocolate-making. The eight EU countries where this practice is currently prohibited  are free to modify their laws to take account of this 5% rule. The other cocoa butter and dry cocoa contents specified in the Directive - 18% and 35% respectively - may not be reduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The addition of up to 5% vegetable fats was authorised under Directive 73/241 for the UK, Ireland and Denmark when they first joined the EC. Other Member States who acceded later - Austria, Finland, Portugal and Sweden - also use these oils in chocolate production. The remaining EU countries have continued to prohibit the use of vegetable fats - and the sale of chocolate containing such fats. The result has been a partitioning of the EU market, in direct conflict with the Single Market principle.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If the proposal is approved by the Council and the Parliament, all 15 Member States will be free to decide whether vegetable oil can be used in making chocolate. Whatever their individual decisions, however, the barriers will come down, thus opening up the 'pure' chocolate markets to competition from less expensive varieties containing vegetable oil. Stricter labelling rules will also be introduced, with the precise nature of any substitute oils being clearly indicated. The simple mention 'vegetable oil' will no longer suffice. Martin Bangemann, the Commissioner responsible for industry, stressed the significance of revising the Directive in allowing  chocolate products to circulate freely throughout the KU. This, he argued, would be in the interests of consumers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Winners and losers</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Traditional cocoa producers such as Cote d'lvoire, Ghana, Nigeria and Cameroon are fearful that the proposal may prompt some of Europe's 'pure' chocolate countries to change their laws - and that they will lose trade as a result. On the other hand, sheanut exporters in Burkina Faso, Mali, Ghana, Togo and Benin are hoping for higher sales if the 5% rule is adopted by more EU countries. Sheanuts account for 20% of Burkinabe exports and 98% of these are used to make vegetable oil substitute for chocolate products. The sheanut price is just 10% of the cocoa bean price. The Commission calculates that the maximum saving a manufacturer could expect by substituting vegetable fat for cocoa butter is around 1.5% of the ax-factory price.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In weighing up what to do, the Commission also considered the objectives of the International Cocoa Organisation (ICCO). These include taking 'all practical measures to increase the cocoa consumption in their countries by eliminating or reducing all obstacles to the growth of consumption in cocoa.' The ICCO estimates that if the 5% rule is applied in the remaining eight states - Belgium, Luxembourg, France, Germany, Greece, Italy, the Netherlands and Spain - it will lead to a reduction in cocoa butter usage of 36 000-50 000 tonnes, which amounts to a drop in demand for cocoa beans of between 88000 and 125000 tonnes. This represents between 9-12% of current consumption.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some producers suggest that these estimates are too high since they assume that manufacturers will go for  almost full substitution, which is not necessarily seen as inevitable. In addition, there is a belief that overall demand for chocolate products may grow as a result of the legal change.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was not the view taken by NGOs who reacted promptly - and critically - to the Commission text. The Brussels NGO Liaison Committee issued a statement claiming that it would lead to a drop of between 6.25% and 12.5% in the main exporting countries' cocoa receipts - and an additional burden on the European Community's Stabex fund. But chocolate producers and others argue that this is speculative. The impact, they say, will depend on the legal response of the eight Member States, as well as on the reaction of manufacturers. There are signs that the latter may well stick to their traditional and distinctive methods. A spokesperson for the Belgian-based Cote d'Or/ Suchard, pointed out that the proposal had a long way to go before it was approved, and stressed that his company had no intention of changing their 'winning recipes which had served them well since 1883. At the same time, he admitted, vegetable oil could be useful in a more diversified range of chocolate products.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The vegetable oil 'lobby' argues that the addition of vegetable fat makes chocolate easier to mould and less likely to melt in warm climates. And for those who fear the elimination of 'pure' chocolate from the market, they point to manufacturers in Britain, where vegetable oil has traditionally been used, who still exclude such fats from some of their brands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The proposal must now be debated by the Council and it is clear that the arguing is not over yet. But it is beginning to look as if the consumers may be the final arbiters. Through their purchasing habits, they are likely to be the ones who finally determine the winners and losers in the great chocolate debate. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Minority businesses in the UK</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In no country in Europe are ethnic minorities more organised than in the United Kingdom - though they are still not adequately organised, in the opinion of many, to pool their considerable resources together and overcome stereotypes, racism and unenployment. But this may  change if the morale engendered by a recent exhibition of minority businesses in the UK is anything to go by.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The statistics speak for themselves. There are 3.3 million Asians, Africans and Afro-Caribbeans in Britain, about 5% of the population (and the figure is projected to double in the next 25 years). They have six elected Members of Parliament - five Labour and one Conservative - as well as numerous personalities in the world of sports and the media. According to the 1994 Labour Force Survey, 48% of ethnic minorities are graduates or are in full time studies and 55% earn salaries well over &amp;15 000 (ECU 18 000) annually. They have a combined gross annual income estimated at f42 billion and an annual spending power of at least f26 ten.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past 15 years, ethnic minority-owned businesses have grown considerably. In the last two years alone, they were responsible for more than 30 000 new business concerns throughout the country, according to the Commission for Racial Equality (CRE). Although many are in the retail trade, the 10% or so involved in production or manufacturing are extremely dynamic,  particularly those connected with the clothing industry or operating franchises.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are considerable differences between Asians on the one hand and Africans and Afro-Caribbeans on the other. The former are more business oriented and account for well over 80% of all ethnic enterprises. This success in business is often attributed to Asians' industriousness, but there is another crucial and often neglected factor: Asians have a stronger sense of group solidarity and patronage than Africans and Afro-Caribbeans. Whereas the former spend virtually all their earnings within their community, the latter (who are mainly Christians and are known to make greater efforts at integration into the British society) spend theirs in the society at large.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unemployment among the black population in general is 19% compared to 8% for whites (in London it is three times higher). They are much more likely to be turned down by employers even when they have better qualifications than their white counterparts. Often self-employment is the only way out. This explains why there has been a boom in business start-ups by ethnic minorities over the past two years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although several black profffsional associations have come into being in recent years, it has been clear for some time to black leaders that the community's energies are dispersed and that these needed to be harnessed for the benefit of ethnic minorities as a whole. Blacks clearly have political and business clout to be exploited.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The idea for an exhibition of black businesses in the United Kingdom was mooted by a black business couple who, were influenced by a similar event  held annually in the United States called 'Black Expo USA'. But the impetus came from the 'Race for Opportunity Campaign' launched in October last year by the Conservative Government through the Department of Trade and Industry. The campaign has so far seen more than 20 big British companies pledge to do business with ethnic minority enterprises. These include British Airways, British Gas, British Telecom, British Aerospace and several high-street banks and finance houses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Held at the Barbican Centre in London on 4 and 5 May, the exhibition was aimed at creating awareness among ethnic minorities of their potentialities, showing the opportunities available to them not only in the UK but also in Europe, and at promoting networking amongst their businessmen and women. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cross-party support</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The exhibition, which had a cross-party support, could not have come at a more favourable time. Both the Tory government and opposition Labour Party have expressed support for policies favourable to small and medium-sized enterprises, which means that there should be continuity in this area if Labour comes to power in the next general election.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was borne out by the enthusiasm with which the shadow minister for small business, Mrs Barbara Roche greeted the exhibition. To her, the event should be seen in the context of Labour's overall policy on small businesses. Speaking at one of the seminars which was run alongside the exhibition to discuss various aspects of minority business problems, Mrs Roche explained that there were three important reasons why her party was promoting small enterprises, especially those involved in exports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first was that large companies were downsizing, and job-creation towards the end of this century and into the next would be largely by small and medium-sized enterprises. The second was that small businesses were efficient distributors of wealth and the third was that they were good at innovation and using new technologies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because a large number of small businesses are folding, or are struggling to survive in the UK today (often as a result of late payment of bills by large companies), Mrs Roche said a Labour government would introduce a statutory limit of 30 days for the settlement of bills by large companies. The latter would then have to pay interest to small businesses for any late payments. Ethnic minority businesses, she also said, were part and parcel of Labour's strategy for economic growth and jobs in Britain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Barbican exhibition attracted more than 80 exhibitors mainly in retailing, finance, telecommunications, consultancy, arts and crafts, publishing, electronics and education. There were  very few exhibitors from the manufacturing sector (a disappointment considering the number of Asians in the clothing industry) and virtually none in engineering. Some of the big companies connected with the 'Race for Opportunity Campaign' like British Airways and British Gas, as well as the newly created government-backed Business Link, the Customs and Excise department, the Inland Revenue, the Army and the Metropolitan Police were there. Also present was Louis Farrakan's 'Nations of Islam', (not necessarily on a recruitment drive, though that must have been part of the game), but as a reminder of its campaign for greater self-reliance by the black community which culminated late last year in the 'Million-Man' march on Washington DC. Video tapes of the march and speeches by Farrakan and other black leaders in the United States were on sale.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Difficulties</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The seminar run concurrently with the exhibition attracted many notable speakers, among them Members of Parliament, Keith Vaz, Bernie Grant and Barbara Roche and Commissioner Dr Zaka Khan of the Commission for Racial Equality. Jessie Boseman, vice-president of 'Black Expo USA, who was also scheduled to speak, did not turn up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was general agreement on the main factors inhibiting the growth of ethnic minority businesses, the most obvious being racism and  discimination. Ethnic businesspeople not only have difficulties obtaining public contracts, but they are often denied access to finance, market and even premises. Furthermore, they suffer from lack of management skills, networks and feedback. Dr Khan of the Commission for Racial Equality highlighted mounting racist attacks, mostly against Asianowned shops, which have claimed a number of lives in recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Integration into mainstream economy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is no longer a hidden fact that banks discriminate against black businesses. Surveys carried out by the NatWest and Midland banks have confirmed that fact. The latter though, it must be acknowledged, has a laudable Fellowship Programme, designed to encourage ethnic minority university students to take up careers in the Midland Bank on graduation. Lack of access to the market has effectively meant that black businesses have been left out of the mainstream of the British economy. Everyone agreed that it makes good economic sense to see them integrated into it. This was particularly   the position of both Barbara Roche and Zaka Khan. The question was: would it be possible ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some of the issues raised on the floor by businesspeople revealed that many were sceptical that racism and discrimination could be overcome in multiracial Britain. The Commission for Racial Equality symbolises the fight against these two evils and Dr Khan had a hard time defending its role. The CRE was criticised for constantly quoting statistics on improvements in the living conditions of ethnic minorities which, it was argued, were totally removed from reality. Despite this, Dr Khan remained upbeat. To him the future promises great things for ethnic minorities. He promised to look into the grievances aired by some businespeopie during the seminar. Barbara Roche, for her part, promised that a Labour government would encourage the banks to offer packages of assistance to small enterprises, in particular, black-owned ones. They would also ensure that local councils offered minority enterprises a share of local government contracts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Greater self-reliance and global trade</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In view of the problems black businesspeople have had to contend with over the years, Bernie Grant, the Member of Parliament for Tottenham in North London, did not devote much time to the idea of integrating them into mainstream British economy. He felt that racism and discrimination were so prevalent that there was little chance of that happening. For him, the future for black businesspeople in Britain lay in greater self-reliance and entry into international trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a speech entitled 'political responsibility, and black import and export business', the M.P. set the Barbican exhibition in the context of the global economic situation - one where he said, 'the countries of the North are exploiting those of the South, in particular African countries.' Africa's heavy debts to the West should in fact be the other way round. He argued that the new world trade agreement, which  opens up the developing countries to competition, was unfair. 'This means that countries where minorities in the UK came from are going to have problems, and it is the duty of thee minorities to ensure that their countries have a fair deal,' he said. Mr Grant cited, by way of example, the EU's banana protocol under the Lom&eacute; Convention which gives preferential treatment to small Caribbean island producers and which is currently being 'unfairly' challenged by South American producers under the WTO rules. The role of multinationals, which are effectively acting es 'middleman', was, he believed, pernicious for developing countries. There was a need for black businessmen to step in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Minority enterprises in the UK do not exist in isolation from the rest of the world, he elaborated. They should seek to engage in international trade and take advantage of their connection with their countries of origin. To facilitate this, Mr Grant said that a group under his chairmanship had set up a Global Trade Centre in his constituency in North London with the aim of helping black and minority enterprises establish direct trade links with Africa, the Caribbean and black America. The Centre was already in contact with a number of African countries which have expressed interest in the idea. Such a link would not only ensure a better deal for African producers but also favour the growth of minority businesses across the world. This was, he confessed, 'a political agenda' designed to reduce the excessive profits of multinationals, if not put an end to their 'outright exploitation' of Africa and the Caribbean. Mrs Roche expressed support for the Centre for the role it could play in boosting British exports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UK minorities and the</P>
+<P ALIGN="JUSTIFY">European Union</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A self-confessed Eurosceptic, who would have preferred the UK to strengthen economic ties with the Commonwealth rather than with Europe, Mr Grant displayed an extraordinary understanding of the European</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Union's affairs. What worried him most about greater European integration, he said, was racism and the fact the UK job market, where black and ethnic minorities are already heavily disadvantaged, will be exposed to further competition from other Europeans most of whom speak several languages. However, he had no alternative but to support the Labour Party's line on Europe and work to secure the best advantage of British membership for ethnic minorities. He contrasted Tory 'divisions' on Europe with Labour's 'united' policy and condemned the British Government's attitude generally towards the Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The development of the Union, Mr Grant said, was of great significance to black people. He was sure the Government's Immigration and Asylum bill, which had come up against strong opposition in the House of Lords, was aimed at harmonising immigration laws with other countries in the Union. The bill, if passed, will change the UK's visa regime and have serious implications for ethnic minorities and their businesses in Britain. He revealed that, with the support of ethnic minority members of the British Parliament, Bill Morris, the black General Secretary of the Transport and General Workers Union (the second biggest trade union in the UK) and other European trade union leaders, the Intergovernmental Conference was being lobbied for the inclusion of a stronger clause against racism in the Treaty of Rome. The aim, ultimately, is to see measures in line with the UK's laws against racism and discrimination enacted at the Union level. This would include the establishment of a European equivalent of the Commission for Racial Equality - with similar powers - so as to establish a level-playing field for ethnic minorities in competition for jobs and in business throughout Europe. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Augustin Oyowe</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Dossier</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Communication and the media</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Dossier coordinated by Debra Percival)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Press freedom is widely acknowledged as the cornerstone of democracy with a clamp-down anywhere in the world frequently interpreted as a sign of government repression. The rash of multi-party elections in African nations at the beginning of the</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1990s brought new publications to news-stands. Many of these have since folded - often because of a lack of funds and sometimes because of government censorship.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many organisations are campaigning vigorously in the public eye for a free press in developing nations. These include Reporters Sans Frontieres, Article 19 and the International Federation of Joumalists - all of which are featured in this Dossier. The US-based Freedom House has also been monitoring the state of press freedom worldwide since 1979. In its recently published 1996 survey, it says that even today, only 22% of the world's population live in countries with a free press. 38% have a press sector that is 'partly free' while the description 'not free' is applied to the remaining 40%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are also regional organisations such as The Media Institute of Southern Africa (MISA), which are playing a part in keeping media issues to the fore. David Nthengwe, a researcher with MISA, highlights the fact that democratisation does not necessarily guarantee a free media or free expression more generally. He also draws attention to the difficulties faced by private and community organisations in obtaining adequate finance. These are  typical of the problems facing the media in many countries, both in the ACP group and elsewhere in the developing world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In seeking to tackle these issues, donors are showing increasing interest in backing media programmes with development finance (linked to democratisation and human rights). The European Union, UNESCO and a number of bilateral donors have expanded their activities in this area with a variety of projects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One big change has been the rapid growth of the 'Information Superhighway'. This has prompted fears that the developing countries may fall further behind, although donors have indicated a willingness to help ensure this does not happen. One NGO closely monitoring the development of the Internet for the South is the PANOS Institute. Meanwhile, multilateral donors (notably the World Bank, through its INFODEV programme) are also becoming involved. A number of EU personalities lent their support to the development of the information society in the developing world, at a major conference staged in South Africa in May on the initiative of the country's Vice President, Thabo Mbeki. A work programme of projects was drawn up with the aim of making sure, in the words of European Commissioner, Martin Bangemann, that there is no divide between the 'information-poor' end the 'information-rich'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Finally, although the world is undergoing an information revolution, the more traditional media (the press and above all, radio) will, for the foreseeable future, continue to have a central part in informing, educating and entertaining people in many developing  countries. It is important that those of us who increasingly communicate via our computer screens do not lose sight of this essential fact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this Dossier, we examine a number of the key issues affecting the media and highlight some innovative projects in this area - with the help of a series of experts. The subject has clearly moved higher up the development agenda, but there is still a long way to go, as the figures cited above show. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Aidan White of the IFJ</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Confronting the age-old problem</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the chance, 'governments would like to run and manipulate the media'. This is the view of Aidan White, General Secretary of the Brusselsbased International Federation of Journalists (IFJ), who says it is an 'ageold problem'. And the Federation, which has member organizations in 93 countries, works to prevent it from happening. It also provides a range of services to journalists throughout the world. We recently spoke to Mr White, who used to write for the British daily, The Guardian. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He began by outlining to us the Federation's key areas  of activity which include, in particular, the professional conditions in which journalists work and the defence of human rights. On the first of these, Mr White focused on the problem of economic pressures and difficult social conditions. 'We take a strong view that you can't have press freedom if journalists work in conditions of poverty or technical deprivation. It is a nonsense,' he stressed, 'to talk about a free press in a situation where journalists aren't paid, or if they are unable to function properly.' In seeking to tackle this, he spoke, in particular, of the 'need for independent organisations of journalists defending professional and social interests.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As regards human rights, the IFJ is active in the international community, working with bodies such as UNESCO and the UN Human Rights Commission. 'We are very interested in issues such as the legal environment in which journalists and the media operate, and are extremely active in the defence of physical safety.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr White went on to give more detailed information about the IFJ's work in Algeria, where many journalists have been killed in recent years. This country clearly has a bad international reputation and the General Secretary was anxious to offer a more balanced picture of the situation. 'In my view, there is a real malformation of Alaeria's  image in Europe and elsewhere. The view we get is of a paralysed society where nothing can function properly - a kind of international basket case. It is not like that. In Algeria, life continues. There is a form of democracy. There are a dozen newspapers which appear every day. The streets are full of traffic and people walking about. The reality is that there is a particularly horrifying and barbaric form of terrorism which is targeted against intellectuals including journalists. This means that the media has a terrible problem.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aidan White explained the strategy of the IFJ in seeking to confront this. 'We began by going to Algeria to investigate what was going on. Then we established an international office on the spot. This is a direct contact point of solidarity for local journalists and the local media. So we don't report Algeria through Paris. We don't see the need to go through some sort of middleman in order to find out what's going on in the country or have contact with Algerian journalists.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'And then we have two specific programmes which are very important', he continued. One involves providing humanitarian assistance to journalists and their families. The other is a series of practical activities in Algeria. Thus, for example, we are organising a round table on terrorism and information.' He pointed out that the Algerian government had resorted to the traditional method of press censorship in the face of ,the terrorist threat and stressed the 'need to counter this. 'We are also organising a practical seminar on personal safety, as well as one on professional social rights, the need for ethical standards and better social conditions.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The point, he emphasised was that events were being organised on the spot. Algeria may pose terrible difficulties 'but it doesn't mean we walk away from it.' The IFJ's emphasis was firmly on being a 'functional organisation working directly with the people who need help.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Funding and the EU link</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tuming to the issue of the IFJ's funding, Mr White explained how the core activities - his own salary and administrative costs - are paid for by the subscriptions of member organisations, which amount to roughly $1 million. On top of that, the Federation carries out projects with the EU and other donors. They also distribute funds, offering their expertise as a representative body to help other organisations that want to undertake work.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asked in what way the EU could do more, the General Secretary stressed the political dimension. 'It should intervene,' he argued, 'to establish certain standards in international relations. We say, for instance, that political, economic and military cooperation with any state outside the Union should be based on a commitment to and respect for freedom of expression and opinion.' He underlined the 'responsibility' of the EU to take a stand against countries that locked up journalists, implicitly criticising those who argued that freedom of expression was very important but who then shelved the issue when economic relations were involved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He also urged a more proactive approach 'moving away from the strategy of counting bodies, complaining, and making reports about how bad the situation is' towards one based on comprehensive programmes of assistance. He described the IFJ's Media for Democracy programme in Africa as a 'first attempt' in that direction. Mr </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">White highlighted what he saw as a difficulty with existing projects. 'The problem is that the EU is confronted by all sorts of different NGOs who come and say: 'we have got this good project - give us support for it'. This is fine but it inevitably means that resources are spread very diffusely and often to no effect.' A lot of activities, he suggested, such as one-off seminars and conferences, were 'like fireworks in the night sky: they glow bright for a brief period and then they disappear.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He went on to plead for an integrated, comprehensive strategy. 'Until that exists, you will not be able to solve the fundamental problems facing journalists.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Training and status</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The discussion moved on to the subject of training. Perhaps surprisingly, Aidan White did not see this as an important priority in itself. As he explained: 'It's no use training journalists to be very high quality if they go off to work in a country where the legal environment does not allow them to function properly. And it's no use training them to be ethical if they go somewhere that is steeped in political or financial corruption, and where there is no culture which appreciates the media's role in democratic society.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With this in mind, he believes that training should be directly related to the strategic approach he referred to earlier. 'Yes, we need professional, well trained journalists, but it should be part of a range of programmes. And professional training is not just important for journalists. It should also be provided for managers, editors, advertisers... and perhaps even for politicians!'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The General Secretary noted that the status of journalists in most countries was quite high. They are seen as a filter for information 'coming from the government to the governed'. This was important, he thought, but 'tine real question is how the filter functions. On the one hand journalists have a relatively high status, and what they do is extremely important, but they work close to the political elites, which means they  are subject to pressure. They must retain their independent role, scrutinising and investigating what governments are doing.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the subject of access to information in developing countries, Aidan White observed that the situation is now better than it was ten years ago but pointed to the 'age-old problem of people in power wanting to control the media.' He gave the example of journalists in Indonesia, 'who really want to speak independently of the government, but who are being killed because they represent independent strands of opinion.' Overall, however, he believes the situation has been improving. 'This is partly due to changes in information technology. A government can no longer simply take a journalist out and beat him up. There are half a dozen press freedom organisations around the world watching for and reporting on such events.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a tendency in Europe to assume that 'everything in the garden is rosy' in terms of press freedom, and we were interested to hear what the Secretary General thought of this proposition. He was quick to offer a less complacent view. 'We have just issued a very strong statement against the EU about their secrecy policy,' he pointed out. 'You cannot claim the moral high ground for democracy in Africa or elsewhere if you have a system of secrecy in Europe which operates at the highest political level and which denies citizens access to information.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He was also concerned about the concentration of the media in enormous congLom&eacute;rates. This trend, he argued, 'is actually profoundly damaging to the culture of information.' He cited, in this context, the action of the Murdoch organisation 'in banning all news from his cable channels going into China.' Mr White continued: 'They banned the BBC and they banned news coverage in the Chinese language in order to make a business arrangement with the Beijing government. That sort of activity, in our view, is direct censorship from the heart of western democracy.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In conclusion, Aidan White gave some more detailed information about the Media for Democracy programme in Africa which he described as 'ground-breaking.' The Federation has used it to develop key themes, including the coverage of elections. 'The real test of press freedom,' he continued, 'is at an election, because that is when the political pressure is toughest and the professional quality of journalism is exposed. For Africa, we developed a manual on election reporting and, interestingly, it has become the source document worldwide for election reporting.' He explained how it formed the basis for developing a text which is universal. This has been translated into various European languages, and Arabic, and has been employed in Poland, Romania, Albania and Latin America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the first phase of the Media for Democracy programme, the Federation held a serf. of seminars and conferences on how the media covered elections. As Mr White stressed, this was a crucial time in Africa. Political change was taking place, multi-party democracy was being introduced and there was a need to clarify how elections operated and how they should be reported. 'People didn't have the experience. They wanted the information, and to discuss how things should be done.' The seminars covered aspects such as financial corruption, the organisation of journalists and the role of ethics. And what the IFJ found was that the same kind of things happen in Kenya, Tanzania, Mozambique and South Africa - and indeed across the world. In the words of the Secretary General, 'they have an echo everywhere because, at its root, the problem is the same - those in power want to manipulate the media and use whatever pressures they can.' The lesson learnt from the IFJ's experience in Africa is that common solutions are also valid. Or as Aidan White put it, 'there is no part of the world that can't teach the rest of the world something.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.M. &amp; S.H.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Freedom of expression: the first freedom</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Frances d'Souza</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frances d'Souza who is Executive Director of AROSE 19, a nom governmental organization which campaigns against censorship globally, explains why Freedom of Expression is for her the most important human right</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the absence of freedom of expression, it is almost impossible to protect other rights, including the right to life. Once governments can draw a cloak of secrecy round their actions and remain unaccountable, massive human rights violations can, and do, take place. For this reason alone, the right to free expression, specifically protected in international human rights treaties, must be considered a primary right. It is significant that one of the first indications of a government's intention to depart from democratic principles is when it increases its control over information, usually by gagging the media. At the one end of the spectrum, supposedly minor infringements of this fundamental right occur daily in western democracies; for example the abuse of national security laws to prevent publication of information which might embarrass the authorities. At the other end of the scale are regimes of terror which brutally suppress opposition, information and even the freedom to exercise religious beliefs. Without free speech and an independent media, it is easier for governments to employ propaganda to promote ethnic conflict, war and genocide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The right to freedom of expression is formally protected in major international treaties including the Universal Declaration of Human Rights, the International Covenant on Civil and</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">* This text is an abridged version of a submission made by the author to a public hearing hosted by the European Parliament's Committee on Foreign Affairs, Security and Defence and the Sub-Committee on Human Rights and the Committee on Culture, Youth, Education and the Media, April 25, 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Political Rights (Article 19), and the European Convention on Human Rights (Article 10). It is also enshrined in many national constitutions, although this does not always guarantee its protection. Freedom of expression is something which applies even in countries which have not ratified the relevant international treaties. This is because the Universal Declaration is so widely accepted that its provisions now form part of customary international law.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While it is generally agreed that freedom of expression is the cornerstone of democracy, international treaties permit certain restrictions. Unlike the American First Amendment rights which allow few, if any, checks on free speech, the international treaties aim for a balance between competing rights. Thus, for example, free speech may be limited where it impinges on the individual's right to privacy, or where it involves incitement to violence or hatred. Given that the permitted restrictions are necessarily broad, the limits of free speech are constantly being tested in national courts and in regional tribunals such as the European Commission and Court of Human Rights. In recent years, several landmark cases have helped define what restrictions may be imposed by governments and under what circumstances. In particular, it has been emphasised by the European Court that any restriction should 'pass' a threepart test; it should be prescribed by law (and thus not be arbitrarily imposed), it should be proportionate to the legitimate aims pursued, and it should be demonstrably necessary in a democratic society in order to protect the individual and/or the state.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Who censors what?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the rules governing restrictions on free speech, many justifications are still invoked by governments in suppressing information which may be inimical to their policies or interests. These include arguments in defence of national security or the 'public interest'. The mechanisms used to restrict the free flow of information range from subtle economic pressures, and devious methods of undermining political opponents and the independent media, to the enactment of restrictive press laws and rules for licensing journalists. In extreme cases, they may involve the illegal detention, torture and disappearance of journalists and others associated with the expression of independent views.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The right of free speech may appear less important than, for example, freedom from torture or extrajudicial killing. It is also sometimes difficult to persuade the public that censorship, generally associated with banning obscene materials, is a bad thing! It requires a recognition of some of the fundamental principles of democracy to understand why censorship is so dangerous. Democracy implies that people can make choices about the issues that affect their lives, including what they wish to see, read, hear or discuss. While this may seem a luxurious freedom, mainly preoccupying the wealthy West, it is a comparatively short distance between state censorship of an offensive book to the silencing of political dissidents. And the distance between this and the use of violence to suppress opposition is even shorter. Censorship tends to grow rapidly from small beginnings. Allowing a government the power to deny people information, however trivial, not only leads to laws and procedures which can and will be used by those in authority against those with less authority. It also denies people the information they need to render their governments accountable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There have been some terrible examples of the role of censorship in recent years. We have seen it in the republics of the former Yugoslavia   where the media were manipulated for propaganda purposes. We have seen it in Rwanda where the government associated radio incited citizens to kill each other in the name of ethnic supremacy. And we have seen it in Iran which maintains the threat of murder against a citizen of another country because he wrote a book which displeased the authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are clear links between access to information (or rather the lack of it), and war. Democracy empowers people by increasing participation in decision-making at all levels. The poor, who are denied access to information on decisions which deeply affect their lives, are powerless and have no voice. They cannot influence the ruling elites whose interest in consolidating their own power and position may be served by initiating conflict.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is significant that of the 126 developing countries listed in the 1993 Human Development Report, wars were being waged in 30 and a further 33 were suffering severe civil conflicts. 55 of these 63 countries were to be found at the lower end of the Human Development Index which is an indicator of poverty. It is reasonably safe to assume that most people never welcome war. They may be coerced into supporting 'their' side in a conflict by their governments, using propaganda designed to whip up fear and extreme nationalist sentiment. If the majority had a democratic voice, they would undoubtedly object to war. But voices are silenced. Thus, the freedom to express one's views, to challenge government decisions and to insist upon political rather than violent solutions, are necessary aspects of democracy which can, and do, avert war.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">State-sponsored propaganda in Rwanda, as in the former Yugoslavia, succeeded because there were no ways of challenging it. One can conclude that it is impossible for a country to wage war in the absence of a compliant media willing to indulge in government propaganda. Governments needs civilians to fight wars for them and the media is needed to reinforce government policies and intentions at every turn. In a  totalitarian state where the expression of political views, let alone the possibility of political organisation is suppressed, one has to ask what other possibilities are open to a genuine political movement intent on introducing justice. All too often, terrorism and violence are the only perceived options available to communicate the need for change.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What NGOs can do</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The work of human rights organizations has to become much more proactive and should be concerned with providing early warning and preventive action. Monitoring freedom of exprmsion, especially freedom of the press, offers an excellent context because it is widely recognised that would-be dictators always seek to silence people's voices through banning newspapers or other methods of censorship. One has to assume that when censorship begins in earnest, worse human rights abuses will follow and this should be the point for action. Had there been a greater international lobby for an independent media, for access to information and for participation in decision-making in the former Yugoslavia, Rwanda, Nigeria, Burma and many other countries, some of the gross violations which continue to occur, could have been prevented.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Censorship is the first instrument of a government intent on departing from democratic procedures. In this sense it is an early warning signal and at ARTICLE 19, we believe we have a special responsibility to understand better how democracy is destroyed through censorship and how we can alert the international community to act to prevent it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By way of conclusion, anything which can build strong and sound media infrastructures, at the earliest to pportunity, in transitional democracies, is both a gift and a great investment. A crusading press, prepared to separate fact from opinion and to verify its sources, can create a level playing field in which all sectors of society have a voice. This would preclude political control and manipulation for nationalistic power purposes. There is also a need to strengthen local monitoring groups which have the capacity to verify information. International organisations should amplify the voices of local organisations and bring them to the attention of the international community. It is only where there is a strong human rights culture in a given country, whether it has achieved democracy or not, that political changes can be seized upon and shaped into the democratic process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To achieve these objectives, NGOS need to work with governments which are obliged by international law to uphold fundamental rights. We need organisations such as the KU, the UN, ASEAN, and others, to insist on respect for human rights in their dealings with third countries. We also need the general public to be aware of what fundamental rights are, what are the consequences of infringement, and how they can, as individuals, successfully challenge restrictionss imposed on them by their governments. Above all, NGOS need to work with multilateral organisations to determine where slender resources can most fruitfully be targeted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F.d'S.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Commission support for democratisation through the media</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Mark Leysen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Amongst the many cooperation activities in which it is involved, the Lom&eacute; Convention covers cultural cooperation, which includes information and communication, yet European Development Fund support for the media in ACP countries is negligible. Although considerable and increasing amounts of aid are granted for the cinema in such countries, EU support for TV, radio and the printed media is small.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the other hand, for some years now, the Commission has provided considerable aid to the printed media and radio in ACP countries under its 'Support for democratisation and respect for human rights' budget, which heralds a new approach to media questions. The EDF does not participate in the vast majority of big communications projects in Africa, namely PANA (Panafrican News Agency), URTNA (African National Television and Radio Union, the African equivalent of the European Broadcasting Union), the Programme Exchange Centre, Afrovision, Cierro, etc. The reluctance of EU and ACP partners to embark on such media projects can be explained both by EDF procedures and by the worldwide political context including the situation in most African countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Until recently, the media was a matter for the State in Africa. The 'New World Information and Communications Order', announced in the 1 970s, foresaw the participation of not only African citizens, but also of their governments in the world information highway. However, the democratic credentials of such governments were open to question - they controlled the printed media, radio, television and press agencies and any support for such media amounted to a strengthening of the State monopoly and this is why the EDF did not take part.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, aid to the independent media was impossible because such entities did not exist in most African countries and the authorities were not prepared to back a request for aid to the press which they regarded as contrary to their country's interests. If support for the media did exist, it was indirect and restricted to backing of means of communication servicing development projects: literacy campaigns, the fight against AIDS, increasing awareness of ecological problems, etc.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It was not until the advent of the democratisation movement and the support that Europe decided to grant to it that a media-aid strategy was to take root. As a kind of 'Fourth Estate', the media monitor executive power and report any abuse of it. In parallel, they play a key role in strengthening civil society by providing information (if not objective information, then at least information from many sources) on current political, social, economic and cultural issues and by providing a medium which offers an opportunity to speak out on matters of importance to society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Commission focuses its media support in five areas in agreement with representatives of African press and specialist European . organisations in this area. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Freedom of expression It provides direct aid to national, regional and international organizations to defend freedom of expression, specifically financing monitoring, surveys and the reporting of any violation of press freedom (censorship, intimidation, arrests and arbitrary trials, etc.), and direct assistance to the media and any journalists who are victims of such attacks on press freedom. This direct aid is channelled to, inter alia, the activities of Reporters sans frontieres (see 'Interview with Mr Robert Menard', in this issue), 'Article XIX' and Index on Censorship, all organisations which operate like an Amnesty International for the press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Training</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new independent press is often run by journalists who have had no journalistic training and the former State media often require being updated after many years of professional 'distortion' responding to 'his master's voice'. The Commission hence finances programmes offering training in basic journalistic techniques, election coverage; professional codes of ethics, etc. In this area, it is working with a number of European and African organizations, giving priority to long-term actions which are likely to spawn others and to programmes aimed at achieving a higher level of professionalism.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aid for vocational organizations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vocational organizations for journalists have a role to play in improving the profession's social standing, in strengthening its cohesion in the face of political division, in defending its interests and in coming to the aid of journalists who have been victims of repression. The Commission finances a vast 'Media for Democracy' programme conducted by the International Federation of Journalists and its affiliated regional and national organisations (see interview with Aidan White, in this issue). The programme aims to strengthen or create national and regional associations of journalists, but is also involved in more general actions to   increase the professional standing of the media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Access to sources of information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A credible and responsible press requires sources of information which the new and financially precarious press cannot allow itself. The Commission supports the creation or updating of documentation centres, North/South  and South/South exchanges between publications and radio stations, access to international press agencies or photographic libraries, etc., being shared between several media bodies. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Legislative framework and code of ethics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is not enough merely to guarantee freedom of expression in the   constitution. This principle must be embodied in all legislative and regulatory texts to prevent a journalist being prosecuted arbitrarily for 'defamation' or 'a breach of State security'. Moreover, to appear credible, the profession must observe a code of ethics. The Commission backs the drafting of press codes, codes of ethics and regulations to govern the air waves. It also backs the creation of press and air wave regulatory bodies as well as the provision of training in journalistic ethics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is obvious that the 'Democracy and Human Rights' budget cannot alone meet the needs of Africa's multi-faceted media scene. Moreover, although the media are a key element in any democratisation process, they are also much more than that - as a means of information and recreation, they have a role to play in the human development of society; as an instrument to create greater awareness, they can contribute to the strengthening of a civil society which is gradually taking charge; and as an economic sector in the full throes of development, they can make a contribution to the GDP and create jobs. All the more reason for national sponsors and the EDF to take more of an interest. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">National television, victim of  democracy </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than the other media, television in Africa is controlled by the State and serves, first and   fore most, to disse minat e news about the leade r and his govern ment. The state of equip ment depen ds on when it was suppl ied by a friend ly count ry from the North, and as it was almos t certai nly offere d to the count ry's leade rs 'as a perso nal gift', it usual ly consi sts of oversi zed equip ment which the nation al televis ion statio n canno t maint ain correc tly owing to a lack of resou rces. Whils t Europ e is movin g over to digita l Betac am and 1619 forma t, many Africa n TV statio ns are still opera ting with Umat ic and with mach ines that are impos sible to maint ain. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With such deriso ry mean s, nation al TV statio ns have to conte nd with unfair comp etition from the intern ationa l statio ns which, from their satell ites, are inund ating the contin ent with their broad casts . The worldbroad castin g chann els of Europ ean statio ns are receiv ed clearl y (CFI, TV5 Afriqu e, BBC World Telev ision, Deut sche Welle, etc.). The numb er of religio us statio ns (gene rally Islam ic) contin ues to increa se and comm ercial televi sion is develo ping apace - CN N, MTV, Cana l Horizo ns, M-Ne t and others can be picke d up just about every where and can thus cream off the best of a comm ercial mark et which is still virtual ly non-e xisten t and awaiti ng better days . </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The URTN A is unabl e to defen d the intere sts of its memb ers, prope rly and its initiat ives (which are, nevert heles s, lauda ble) are stagn ating: the -progr amme rexch ange centre in Nairob i does not excha nge very much at all and Afrovi sion, . the syste m for excha nging news betw een   nation al TV statio ns via satell ite, is strugg ling to Get off the aroun d. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Never theles s, Africa n TV statio ns do not lack talent or motiva tion and many of them are capab le of produ dng more qualit y progra mmes . What can be done to help them ? Firstly, a decis ion has to be made regar ding who is to be helpe d. Certa inly not intern ationa l TV statio ns' be they private or public, which have their own strate gy (comm ercial or politic al and produ ce televis ion progra mmes for impor t which make only a very margi nal contri bution to the expre ssion of Africa n talent . It would also be wrong to rely or, privati sation and comm ercial statio ns in order to obtain quali ty televis ion - t his much has been demo nstrat ed by the Europ ean exper ience . As for direct aid to nation al televis ion, this would mere ly reinfo rce the State mono poly over inform ation. Wha t is requir ed is greate r suppo rt for the transi tion of State televi sion into a genui ne public servic e. with the benef it of an indep enden t statut e and also true editor ial indep enden ce. Conse quent ly, as things curre ntly stand, aid for trainin g teievis ion' profes siona ls, suppo rt for qualit y progra mme produ ction and any aid aimed at draftin g a public -servic e televis ion Statu te, are usefu l forms of suppo rt which are neutra l with regard to State -medi a contro l. Any direct aid to nation al </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> televis ion statio ns in the form of   hardw are and equip ment shoul d be </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> subje ct to their conve rsion into an auton omou s public servic e. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M.L. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Images of Africa in the Western media</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Geoff Mungham</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It seems difficult to find an African leader or African journalist who has not, at some time, been either fiercely critical or quietly despairing of the way in which the continent is depicted by the western media. Their grievances have come to form part of a now familiar litany. Claims are made that the reporting of Africa is now almost entirely in terms of what has been called a'coup, crisis and famine syndrome', and that the western media focus only on 'bad news' out of Africa and ignore the 'positive' achievements of many African countries. These criticisms go hand-in-hand with accusations that Africa cannot ' tell its own story, in its own way', because the global news market is dominated by powerful, westerr-owned corporations, who have their own agenda for reporting Africa. For many Africans, their continent is becoming increasingly invisible in the trade in global news. For them, Rupert Murdoch's cynical remark that 'the Third World sells no newspapers' would appear to have been uttered with Africa specifically in mind. Finally there are those Africans who are concerned about 'western cultural imperialism' undermining traditional African values and culture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How true are these claims? Is Africa becoming once again a dark continent; one largely excluded from the glare of western media coverage? Are some of the correctives suggested by different African leaders worse than the problems they are complaining about? And if Africa is in danger of becoming a 'disappearing world' for news, to what extent are many African countries themselves to blame?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To begin with, there is no doubt that African critics have a case. First and most obvious, is the undeniable brute fact that global news and information flows are dominated by a small number of multinational operators, nearly all of whom - especially since the end of the Cold War - are western owned and controlled. This is true of the great international news agencies, whether the traditional wire services like Reuters or Agence France-Press, or the newer global television news services represented by WTN and CNN, among others. The major clients for their output are western news organizations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, most African countries are in no position to mount a challenge to this world news order. The continent has recently been described as one of the 'least dynamic regions in the global economy, where buying power of consumers is low' and in which many countries are burdened with crippling debt payments. In the same vein, a 1991 World Bank report not only pointed to the increasing 'communications gap' between Africa and the developed world, but went on to suggest that most of the continent offered poor prospects for those wanting to invest in telecommunications projects. These are among the reasons why Africa scores so poorly in terms of putting in place viable national communications infrastructures, let alone being able to take on the global market leaders in securing a higher profile for Africa in the world's news rooms. The same factors also help explain why most African countries remain so dependent on western-controlled news sources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This dependency is not simply a question of the easy availability of copy or other material from the western news agencies. Puri (a Tanzanian journalist and Managing Editor of Newslink Africa)  presents other reasons why African editors are interested in what's happening in the West. These include the links between many African countries and their former colonial rulers, the realities of global and economic relations and his claim that African editors often have little interest in other parts of the continent. As he puts it, '...a newspaper reader in Botswana, for example, is not much interested in reading detailed reports from Morocco.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, there is plenty of evidence to support the criticisms of the 'coup, crisis, famine' coverage. Examples are too numerous to cite here, but the following small selection is fairly representative of the broader picture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Introducing the findings of a 'Global News Agenda Survey', Malik and Anderson noted: 'For the rest of the world, Africa means coupe, and largescale killings (covered usually only in the first few days), almost ritualistic famine relief... and the occasional travelogues in the guise of saving something or other'. Similar claims were made by Okigho when he wrote that while CNN and other satellite organisations have 'revolutionised international news coverage', the most common images of Africa still depict internecine warfare (in Angola, Liberia, Somalia), pogroms in Rwanda, political violence in Sierra Leone and ethnic conflicts in Kenya and elsewhere in Africa. In contrast, says Okigho, the 'many positive developments' are routinely ignored.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A limited review that I made of wire service copy from the main international news agencies during the week of 13-20 May 1996, produced findings that seemed to echo some of these complaints. In this period, hard news stories were concentrated on a handful of the 50 plus countries of Africa; Burundi, the Central African Republic (C.A.R.), Egypt, Liberia, Somalia, Sudan and South Africa - together with stories of alleged financial irregularities in the World Health Organisation in Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Copy about Burundi dealt with ethnic violence and attacks inside Zaire   on Burundi by Hutu 'rebels'. Reports from the C.A.R. focused on an army mutiny, street battles and looting, but were angled on the mediating role of French troops (the C.A.R is a former French colony) and the fate of 100 Americans trapped in the capital, Bangui. Egypt was featured after its government accused Sudan of harbouring a 'vipers' nest of terrorists'. Out of Liberia came a torrent of wire copy about fighting in Monrovia along with assorted atrocity stories, but pinning the emphasis on the plight of foreign nationals (especially Britons and Americans) and the role being played by the USS Guam in air-lifting them to safety. Somalia rated a mention because of the release of two foreign aid workers (British and German) held by an unidentified 'rebel faction'. On South Africa, the wire services were fixed on further violence and killings in KwaZuluNatal, the result of ongoing struggles between rival supporters of the A.N.C and the Inkatha Freedom Party.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'agenda for Africa' sent out by the wire agencies, was replicated by  the menu offered by Reuters TV and APTV. For instance, on one day during the study period, the former was offering ten picture feeds; only one was from Africa (on the C.A.R.) while the rest included such compelling visuals as the British Queen's visit to the Chelsea Flower Show. For the fifteen picture feeds being touted by the APTV on a single day, one featured Africa ('news pictures to offer on the airlift by US marines'), which competed for the attention of western news rooms alongside visuals of a US woman who collected hubcaps (140 000 of them, no less!), Hugh Grant arriving by boat at the Cannes Film Festival, footage of the Monaco Grand Prix and a 'fun run' in Sarajevo (whether or not pictures are available, the idea of a 'fun-run' in Bosnia still seems a difficult concept to grasp) But what these studies show is not the whole picture about Africa which circulates in the West. Nor should they necessarily be used to support the usual criticisms about the performance of the western media in relation to the continent. In the first place, not all news  out of Africa fits into the syndrome the critics complain about. For example, a great deal of the coverage of South Africa has been 'positive' (if we trace the reporting of that country's transition to majority rule). So, too, have the moves towards multi-party politics in African states like Zimbabwe. Similarly, there is plenty of reporting of Africa's sporting successes (such as South Africa's Rugby World Cup triumph). Nor is the West unaware of the work of certain African musicians and film makers - indeed, it has been influenced by them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And even if 'positive' coverage is sometimes hard to find, the critics may still be missing some key points. The first is to do with western 'news values' or rather a failure to appreciate how they work - whether in relation to Africa or anywhere else. The staple diet of much of the global news flow is about 'bad news' and, in this respect, Africa prob  ably fares no worse or better than other parts of the developing world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Second, a more 'systematic' reporting of much of Africa is still difficult. My point here is about a lack of efficient and developed communication infrastructures, but also a reluctance by many African leaders to tolerate - let alone actively encourage - free and honest open reporting. Too many African journalists have been, and are being, harassed, imprisoned or killed by their own governments. Much of the media in Africa - especially the broadcast media - remains under state control. Newspapers that show a 'lack respect' for the ruling party are frequently shut down. These realities help explain why some of the maligned western media are turned to by those Africans who want something more than state propaganda from their newspapers or broadcasters. This is why the BBC World Service has come to enjoy such a high reputation in many parts of Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Third, the attempts made by the African states to try and take on western dominance of global news and information flows, have been misjudged. Two failed initiatives in particular are worth mentioning in this context; the launch in 1983 of the Pan African News Agency (PANA) and the long-time obsession with setting up a 'New World Information Order' (NWIO).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the start, PANA has been dogged by financial and management problems. African governments owe $18 million, journalists have gone unpaid, lines have been disconnected and in 1992 a UNESCO-funded audit found evidence of financial mismanagement. The main source of information PANA traded in was material from the domestic news agencies of OAU member states. Since most of these are state-controlled, the 'news' they were offering was never likely to attract many western users. To try and give PANA a new lease of life, UNESCO are backing a rescue package, which would allow for private investors to be shareholders along with state-owned African national news agencies. But the pro  posed partnership funding is unlikely to work, especially in one-party states where the ruling groups have always been suspicious of any media not under their direct ownership.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The NWIO project has chased even more impossible dreams. Any attempt fundamentally to change the global news order was always going to be beyond countries with severe national communication 'deficits'. Most African countries, with weak and undercapitalised information infrastructures were never in a position to take on the market leaders in the global news business. In pursuit of the NWIO idea, endless international conferences were held, declarations passed and ritual attacks made on ' western media dominance'. Nothing came of it all. If the sense of frustration which kept the concept alive was understandable, less easy to grasp was why African leaders focused on the NWIO idea, while their own grassroots communication systems remained impoverished and under-resourced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most recent attempt to develop 'top-down' communications facilities in parts of Africa comes with the attempts to push satellite-delivered payTV on the continent. Among the 'players' here are Multi-Choice (which will be offered to subscribers in over 30 countries in sub-Saharan Africa), Canal Horizons (targeted on North Africa and Francophone West Africa) and Panafnet (also aimed at buyers in Francophone West Africa). Because these enterprises are subscription-based there will be a clear bias in take-up towards upperincome groups; and - certainly in the case of Multi-Choice - the output will have a 'strong UK/USA programming flavour'. It is hard to see how these initiatives will ever meet the real news and information needs of the vast majority of African consumers, who have limited spending power and are often deprived of the most basic communication tools.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As Hans Dieter Klee (former Head of the Africa Service of Deutsche Welle) has rightly argued, what Africa urgently needs is large-scale international media aid to help strengthen its own media. This aid should not be targeted at projects designed somehow to allow Africa to 'compete' with Western media congLom&eacute;rates. It should, instead, be aimed at building up diverse, viable and professional local and national media enterprises in African countries themselves. In this, the EU can play a leading role, working through the links established under the Lom&eacute; Convention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robust national communication structures in Africa will not, of course, alter the balance of global media power. They will be able to do little to stop the international news agencies reporting Africa in the way they have done in the past. And it will be a long time before most Africans becomes travellers on the 'information superhighway', since this, in essence, is an extension of existing computer and telephonic communications, which the continent lacks. But a vigorous local and national media, Africa-wide, would be good for Africa and the best barrier for resisting outside media influences. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">6.M.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">References</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Okigho: 'National Images in the Age of the Information Super Highway </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">African Perspectives', African Media Review, vol. 9,1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R. Malik and K. Anderson: 'TV: The Global New Agenda Survey', intermedia, January-February 1992. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">B. Hicks 'North of the Limpopo', Cable and Satellite Europe, April 1996. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">A message of hope on the Burundi airwaves</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Parliament may seem an unlikely launch pad for a radio station, but two members of this elected body, who are committed to a free and fair press as one of the cornerstones of democracy, have set up Radio Espoir (Radio Hope) in Burundi with backing of the European Community Humanitarian Office (ECHO).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Parliamentarians, Pierre Pradier (ERA-F) and Bernard Kouchner (PSE-F) are co-founders of Radio Espoir (Radio Umwizero, in Kirundi) which brings together a French association and a local Burundi radio station. Three expatriates are working on the Bujumbura-based project; an editor, a radio technician and an administrator. They have teamed up with local journalists who, for the moment, are providing their services free of charge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The station, which broadcasts in Kirundi, is targeted at an audience in the 15-25 age group. In a country with an 80% illiteracy rate, radio is the only way of reaching the population. 'The idea came to us in 1994, with Rwanda and Radio Libre des Mille Collines' says Pierre Pradier. 'If so much harm could be done with radio, then why equally could good not be achieved.' RLMC was the radio set up in July 1993 on the eve of the genocide in Rwanda. It became a mouthpiece  for the Akazu, a clan of Hutu extremists grouped around the then President's wife, Agathe Habyarimana, and it undermined the Arusha agreements by whipping up ethnic conflict in Rwanda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Pradier explains that Radio Hope journalists intentionally avoid speaking about Hutus and Tutsis. He also highlights the problems encountered in providing news coverage when local conditions are so difficult. As he points out; 'When you speak about the situation of a woman who has lost her husband in Burundi, you are talking politics.' Security considerations are important too while the MEP stresses that a proper analysis of events can only come with time: 'At the moment we are limited to reporting the facts. And it is only when the facts are verified that one can begin to interpret them.' The news items broadcast by the station rely on agency dispatches confirmed by a network of local people who call in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of such sensitivities and in an effort to find as much common ground as possible, the radio station gives music top billing. This has the added advantage of helping to attract listeners. It also offers general programmes on African roots, sport, culture and educational themes, in addition to its news items. It is currently broadcasting for six hours a day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pierre Pradier says he would like to see an end to the 'navel gazing' of Burundi's population. 'We want to show that peace is possible, by showing how it is progressing elsewhere: in Haiti, for example, where there is a legitimate President now, and amongst the Chiapas in Mexico.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But, like many fledgling stations, finding enough funds from donors to guarantee its future is a worry. The station's current ECHO grant runs out in September 1996. Indeed, the project, classified under emergency aid, was atypical for the humanitarian aid office. But Mr Pradier is hoping that continued support will come from one of the EU's budget lines. He believes that the Union is a particularly suitable donor because it tends to be less 'colonialistic' than some others. He also raises the possibility of seeking funds from private donors such as the Fondation de France. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Looking to the future of the station, Pierre Pradier argues that they cannot let the project 'drop' and hopes eventually to see it being handed over to local broadcasters, assuming 'they are people we can depend on'. The signs so far are encouraging. He would also like to see Radio Hope's programme content broadened to include game shows, with radios offered as prizes for the winners. As far as he is concerned, the more people who tune in, the better! _</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joint Assembly resolution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ACP/Ku Joint Assembly is pushing for EC institutions and Lom&eacute; signatories to be more supportive of media issues. A resolution on the role of communications media in the development and consolidation of democracy in ACP states. passed by the Assembly in March, contained the following points:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - freedom of expression and free communications and media are vital to the development of a democratic society;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - more ACP countries should give opposition parties access to the media' notably where this is controlled by the state;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - all candidates and political parties should be given access to the media in a 'balanced and fair manner'; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - laws which restrict press freedom and the electoral process should be repealed;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - any threat of physical attack against media organisations or their employees should be investigated by the authorities, with those responsible being brought to justice;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - the media should be impartial, providing accurate information during elections, helping to educate the electorate, explaining the importance of elections, giving information on where, when and how to vote, and explaining the secret ballot;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - EU assistance for free and a fair elections - and a free media sector in ACP countries - should be increased. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Catholic radio in Southern Africa</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Antonio Pacheco</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this abridged article, the author, who is a Portuguese journalist, gives details of two church-supported local radio projects in Southern Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the end of the 1980s, the Social Communication Department of IMBISA, the conference of Catholic bishops in Southern Africa (a kind of SADC for Roman Catholics) embarked on a local radio project. It had a two-pronged approach. First, it involved setting up a network of small community radio stations. The local population were involved, sharing responsibility for making programmes and broadcasting information and news about everyday life in the remotest places. In some cases, the programme content was retransmitted at a provincial or even national level. The second aspect was that it was supplemented by the creation of flexible and independent associations of journalists/presenters. They formed information agencies operating as a network to link up local radio stations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At that time, the main concern in Southern Africa was to rid South Africa of apartheid. There was also a desire to promote freedom of expression in Angola and Mozambique. Given that radio was (and still is) the most important means of communication in the region, the idea was to set up a regional network capable of overcoming all the constraints ranging from legal bans and restrictions on broadcasting to widespread illiteracy. The ultimate objective was to set up a Catholic radio station based in Swaziland. This project did not go ahead, however, because it was too expensive to finance and, above all, because it was dependent on the regional Catholic hierarchy. It proved difficult to reconcile the various ideological views and sensitivities of bishops in the various countries of the region. There was also a growing feeling amongst the Christian communities that the underlying need was not for a radio station which would be a vehicle for bishops' views, but rather a media system that served the people, offering recreation, training and information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Radio Pax</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another local radio project of interest, which is now up and running, involved reviving Radio Pax, the private Catholic radio station which made a significant contribution during the 1 960s to the struggle for a free Mozambique. The operation closed down in 1977 but the experience was not forgotten and 16 years later, the decision was made to bring the station back on air. Those behind the new project took advantage of the trend towards greater political openness in the country. Their aim was to offer a credible and informative alternative, which, they hoped, would be up and running in time for the elections scheduled for October 1994. A course was run between July and September 1994 which brought together young presenters chosen by small communities on the outskirts of Beira, Chimoio, Nampula, Quelimane and Maputo. The course involved honing the participants' presentation skills and providing practical training in technical subjects, and programme and information preparation. This was how the first association of young independent Christian journalists came into being.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For various reasons, including red-tape and customs regulations, the  new Radio Pax was unable to broadcast in the run-up to the general election. However, the young journalists, who received their training at various locations, were able to act as important independent sources of information. This was channelled to Maputo and used as backup for a number of international press officials and observers. The information relayed by the young presenters in the provinces made it possible to publish a newsletter which was circulated throughout the country, using fax, religious channels and a variety of other means.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Radio Pax is now in operation, although it faces major technical problems. It is based in a community centre in Inhamizua, 20 km from Beira. The station has already done important work in gathering information about local traditions, and has broadcast programmes aimed particularly at women and young people in suburban areas. The network also incorporates Mozambique's Radio Encontro, which broadcasts from Nampula in conjunction with the Anchilo training centre. There are plans for further local radio stations in Maputo in the south, Quelimane and Chimolo in the centre and Pemba in the north.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Radio Pax is managed entirely by the Association of Independent Young Christian Journalists in Beira. In terms of training, the current preoccupation is to teach the young people involved how to manage the small radio stations which have been made available to them, and to set up local self financing systems. Although equipment is important, what really counts in this project is the training of the presenters. Working in close collaboration with the community, it is they who are in the front linepromoting the inalienable right of free expression.</P>
+<P ALIGN="JUSTIFY">A.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The Voice of the Disabled in Chad!</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Mand Rya&iuml;ra Ngarara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Support Group for the Disabled in Chad (AEHPT) was set up in 1987 with the assistance of the International Christian Service for Peace (EIRENE), which has its headquarters in Germany. By coming together to form a group, disabled people hoped to take charge of their lives and break down the wall of silence that surrounds them. However, despite setting up various workshops (welding workshops, small printing works, musical groups) and publishing an information newsletter, entitled 'Perspectives'. the AEHPT has been unable to improve the image of disabled people within Chad society and has failed to  raise awareness that the work done by the disabled is not only of value, but deserves due recognition. From this status quo sprang the idea of broadcasting a national weekly radio programme called 'The Voice of the Disabled'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are two reasons why radio was chosen as the communication medium: firstly, the very strong oral tradition of the country, together with the population's weak purchasing power, which make access to newspapers difficult, means that radio remains the most appropriate medium for reaching a wide audience; and secondly, radio programmes are not difficult to produce, since they do not require vast technical, financial or human resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Letting the disabled have their say</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initially launched by the AEHPT, The Voice of the Disabled is now jointly produced and broadcast by four associations actively involved in defending the interests of those with disabilities. It is broadcast nationwide every Monday at peak listening times.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The programme is not, however, aimed solely at those with disabilities but, on the contrary, seeks to increase awareness in Chad society as a whole. It also acts as a platform from which to urge the authorities to take concrete measures to help this section of the population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, more than a year after its launch, The Voice of the Disabled is enjoying tremendous success, with ever larger numbers of people, from all walks of life, tuning in. For the disabled themselves it provides a vast source of information, explaining the facts behind the causes of their disabilities and giving advice on how to prevent such disabilities and what can be done to treat them, and it keeps people informed about  what is happening within the various associations for the disabled, giving information about the activities, projects and special events that are taking place. As far as the rest of the population is concerned, The Voice of the Disabled has helped to raise the profile of disabled people in Chad. Slowly but surely, people's preconceptions are beginning to change and one of the programme's greatest achievements has been to eradicate gradually the negative image which people used to have of disabilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless, the lamentable fact remains that this programme is broadcast solely in French, and this is why plans are now in the pipeline to broadcast The Voice of the Disabled in both Arabic and Sara - Chad's two national languages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M.R.N. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">TV documentaries and development</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Africa Express experiment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Richard Synge</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'Africa Express' documentory series mounted by Channel4, an independent British TV station, has done more than just put a new slant on news provided by state-run African channels. it has also created jobs for African producers and reporters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Television viewers in Africa will soon get the chance to see documentaries on African current affairs and development topics which have hitherto only been seen on British TV sets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Channel Four's Africa Express programme has recently concluded its third series to much critical acclaim in Britain. it included items on a surprisingly diverse range of topics. One film showed how a cash-strapped Congolese prison saves money by sending its prisoners home one day in every month, and included lively interviews with the governor and the prisoners themselves as well as footage of the grim prison conditions. Others focused on the flourishing free currency market in Zaire, the spread of South Africa's 'shebeen' culture into the country's upmarket suburbs, political battles in Namibia over the rights to manage historic tourist sites and the Nigerian military government's blatant attempts to censor television reporting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The latest series supplemented the work of British film crews by incorporating several documentaries that were made entirely by African production teams. Special funding for this element of the Africa Express project came from the environmental television distribution agency TVE. As a result, Africa Express hired four African directors and used African-based crews to film half of the 24 films in the series.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other innovative part of the project was that the programmes are now becoming available to viewers in Africa at the lowest possible cost. To promote this concept of 'media feedback', TVE has been actively marketing the series to non-governmental organisations and facilitating arrangements for the distribution of the cassettes to African broadcasting stations, both state-owned and private.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'It is a way forward for us, because nothing like this has been done before,' says Raphael Tuju, a Kenyan film producer who runs a video resource centre in Nairobi, marketing documentaries to local broadcasting stations and the educational sector. 'There are too few opportunities for producers in African countries to break into the international networks. The subjects we cover are rarely of interest to the distribution companies, the differences in technology are too wide and getting wider, and there are not enough African producers who have reached the professional level to compete with their counterparts abroad.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peter Gill, who edited Africa Express for Channel Four, welcomed the opportunity to help promote the independent film industry in Africa. 'It was thoroughly stimulating,' he says, adding that one of the constant challenges was 'finding ways to bridge the gap between what is technically possible in Africa and the standards required for a European television production.' The four African directors hired for the series were two South Africans, Eddie Mbalo and Teddy Mattera, a Zimbabwean, </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Albert Chimedza, and a Namibian, Bridget Pickering. They all worked directly under Peter Gill's management and in contact with a producer in the field. Gill was impressed with the level of journalistic and technical expertise available in Africa and the dedication of the teams working in difficult situations. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Even where the production teams were British, all the 24 films in the latest Africa Express series used African journalists and presenters. They researched and organised most of the films in advance of the actual shoot by the visiting film crews. Cameroonian journalist, Emmanual Wotany, played a prominent role in the films on Congo and Zaire. Kenyan reporter Joseph Warungu proposed and presented a film on the hazards of skin-bleaching in The Gambia. The presenter of the programme on Nigeria, Toyin Fane-Kayode, bravely challenged the censorship of the country's military regime.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An all-African camera and sound team led by Lawrence Mbada and Mandla Mlambo was responsible for the four films in the series that were shot by the South African Broadcasting Corporation (SABC). In the extremely difficult conditions of Angola and Namibia, an experienced SABC cameraman was used. Here there was a need to ensure that the less experienced directors were not further challenged by having to work with an inexperienced crew.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For TVE's Robert Lamb, one of the main breakthroughs made by Africa Express was in the agreement of Channel Four to collaborate both with the SABC and with TVE itself, which insisted on the involvement and participation of African journalists, film-makers and technicians. He was impressed by the results and hopes that thee could be 'an even greater African involvement in another series, if one is commissioned.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The latest series was a success, being regularly watched by up to two million viewers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Channel Four granted broadcasting rights for the series in lowincome countries to TVE and Worldview International Foundation as well as the non-broadcast rights to TVE and its partners in the third world. These   agreements allow TVE to provide the tapes at nominal cost to a network of video resource centres, similar to that run by Raphael Tuju in Nairobi. Such centres seek to get development-oriented documentary films shown by the local broadcasting stations but survive by supplying the needs of schools, colleges, non-governmental organisations and other categories of 'multipliers'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most successful documentary centres is the Film Resource Unit (FRU) in Johannesburg. From its origins as a way of sharing bootlegged foreign films and TV programmes during the political repression of the 1980s, FRU is now a major distributor of educational and documentary films.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To overcome the inexperience of state-owned African broadcasting networks in showing programmes of developmental relevance to their societies, video resource centres have to provide their own sponsorship. 'It is difficult for us to compete with the likes of Coca Cola, which will sponsor programmes like soap operas,' says Raphael Tuju, 'but one way round this obstacle is to sponsor a programme and at the same time advertise our services. The business we generate this way usually means that we can at least break even.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Film-making capacity in Africa has been severely limited by most governments' domination of the broadcasting media and a deep and institutional reluctance to encourage independent local productions. The mainly government-owned television stations rarely have a policy to buy in locallymade programmes and tend to look to Britain, France or the US for outside material, which is often dumped on the market at low prices, making it an even harder challenge for local producers to generate the funds to make their own programmes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The decline of the once-active film industry in Nigeria, in particular, means that in English-speaking Africa, the field is now dominated by South Africa and Zimbabwe. In French-speaking Africa, the continuation of subsidies  has kept an 'art house' tradition alive, especially in Senegal and Burkina Faso. In most of the continent, however, the only development-oriented programmes shown to the public tend to be made by the governments' own propaganda departments rather than by independent film-makers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where there is a lack of access  to local broadcasting media, African film-makers continue to experiment with making their own dramas and documentaries, showing their work on video in village halls and schools. 'At the grassroots, African film-making can be stimulated simply by consumer demand,' says Russel Honeyman, who publishes the African Film and TV Yearbook in Harare. 'But local products do not usually translate into international products. Film and television is a global industry and film-makers should not insist on being too parochial. There is room for greater international collaboration.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Based on the experience of the latest Africa Express series, TVE now plans to build on its achievements. In May 1996, it exhibited the series to the directors of African television stations at a conference in Windhoek, Namibia, and discussed arrangements for distribution of the cassettes. It is also planning to  participate in a workshop for French speaking West African nations in Senegal under a grant from the European Union's human rights division. The consultative process will continue with a meeting of the African video resource centre network at the end of 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TVE's Robert Lamb hopes that the success of Africa Express might encourage international funding agencies in Europe to take up the challenge of funding films made in Africa for African consumption. He doubts that Channel Four on its own would take such a risk. Constraints are, perhaps inevitably, imposed on TVE's concept by the fact that programmes produced for European audiences use a production and editorial structure that requires 'post production' in European capitals. 'Although we came out owning the rights to the programmes in Africa, Channel Four still had 80% of the control over the production and editorial decisions,' he acknowledges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Robert Lamb is fully aware of the challenges that lie ahead. 'National broadcasters are in a parlous financial position and are still, for the most part, stifled by government controls,' he notes. 'Africans who have received formal training rarely find the funds to apply their newly-acquired skills.' But Mr Lamb and his TVE organisation are convinced that there will be increasing demand for more programmes like Africa Express, as much from Africa itself as from European audiences. </P>
+<P ALIGN="JUSTIFY">R.S. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The Internet and the South</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Renaud de la Brosse</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author, who works at the Panos Institute in Paris, reflects on the pros and cons of new information technology for countries in the South and on their chances of success.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Internet has become such a craze amongst users in Third-World countries (researchers, teachers, businesses,, liberal professions, etc.) that it amply demonstrates that a real and genuine need is being met, despite adverse comments from its detractors. The rapid increase in the number of connections to the network in the North is mirrored by an exponential growth in the South. Africa is a good example of the possibilities offered by access to the global network whilst at the same time revealing the technical and financial restrictions facing countries in the South.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Almost all of Africa's 55 countries are today connected to the network, from South Africa, which has over 800.000 computers, to Uganda, which has just a few thousand. The importance of the Internet in Africa must be viewed less in terms of the number of computers (means of access to the Internet) and more in terms of the constant increase it represents in numbers of subscribers to the network. In the last six months alone, the number of subscribers increased by over 50%, whilst the increase in France, for example, was only 20%. Another telling figure is the number of host computers per 1.000 inhabitants, which rose by 147% in South Africa between 1994 and 1995 whereas the increase for Taiwan and Australia was 83% and 50%, respectively!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because it is under-supplied in communications equipment, Africa is starting out with a disadvantage compared with other continents. However, the recent G7 Conference on Information and Development, which took place in mid-May in Midrand in South Africa, brought together 40 countries and 18 intergovernmental organizations and made it possible 'to build a bridge between developed countries and developing countries' so that the latter are not excluded from the world of new information technologies. The benefit to be gained from the Net for the Black Continent lies in the fact that African surfers are anxious to break free  from their scientific, cultural or economic isolation which comes not only from relationships between Africa and the rest of the world, but often from relationships between regions and countries on the African continent itself.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Precursors</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As in Europe and the United States, scientists and researchers in Africa are the first to have understood the importance of the Net and there are now - in French speaking Africa - networks such as the Intertropical Computer Network, which groups together approximately 3000 surfers in 11 countries. The importance of the Internet for these researchers is manifold; in most countries, the education system is in grave crisis, essentially because of diminishing budget resources which for years, on account of structural adjustment measures, have been melting away. This explains the absence of libraries or documentation centres. The Internet is therefore becoming a stopgap measure, offering access to all current scientific production and giving African researchers the chance to publicise and gain recognition for their work outside their own continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interesting experiments in North/South cooperation are also being set up, with the French-speaking Agency for Higher Education and Research currently establishing what it calls a 'virtual French-speaking campus', a kind of vast library to which affiliated universities will be connected. The project is also justified in economic terms since, through the medium of electronic mail (e-mail), which goes hand in hand with the Internet, exchanges of information will be cheaper than by fax, for example, which costs at least five times as much for the same amount of information transmitted. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Outside the academic community, heads of African businesses are also launching themselves into cyberspace, particularly in the case of several hundred of them who have grouped together within a West-African Business Network. Internet's financial viability in the South is dependent on membership of African businesses and multinational companies established in Africa. The cost of subscription is still beyond the means of private individuals and only 'institutional' subscribers are currently able to guarantee payment in the short term.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A useful tool</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of the possibilities on offer remain to be explored, so the Internet can therefore be an important medium for promoting African culture - Niger has set up a Web via which it is possible to visit its archaeological sites and Benin has just set up a server dedicated to voodoo. In general terms, there is the challenge of mastering content, in other words the African suffers should not restrict themselves to a  passive use (sleeking information from the North) but should, on the contrary, move progressively as players providing content and information. For the countries of the South, it is a matter of mastering information and preserving their culture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The range of possibilities offered by the Net is limitless. Its development in Africa or in the South in general does, however, run up against a number of obstacles, including those of both a technical and financial nature. The importance of the Internet lies in being able to transmit greater quantities of information more cheaply than by using other communications techniques. However, the required technology is expensive and therein lies the principal difference between the North and the South.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The infrastructure which would permit rapid, longterm expansion of the Internet is nowhere near being installed in Africa, just as in the other developing countries. The continent is still under-equipped in terms of telephone lines; according to a survey by the BDT (Telecommunications Development Office), the number of main telephone lines per 100 inhabitants is less than 0.5 in sub-Saharan Africa, and in terms of equipment providing access to the Net (computer, modem, etc.). In real terms, this makes access to the network much more expensive for a user in the South than for one in the North. All these imported electronic goods are much more expensive than in the West, and this is without taking account of the additional cost, in most African countries, imposed by tariff barriers on IT goods, which are regarded with great suspicion by the authorities who perceive them as a potential danger more than as essential development tools.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fear is that the remote transmission of data might pose a threat to less than democratic regimes. Under the pretext of 'the control of information-based wealth', a State may decide to interfere with the 'consent' or even 'suppress' a site for producing and exchanging information deemed contrary to its interests. Once more, the question of freedom of expression arises in different terms in the South and North. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Panos Institute</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Panos Institute is a non-profit-making association set up in 1988. Together with its counterparts in London and Washington, the Paris Panos Institute founded Panos International The Institute's aim is to strengthen, particularly in Africa, local expression and information capabilities. Within the context of sustainable and  better-shared development, it aims to promote the emergence of a more democratic culture and of more democratic debate. To this end, the Panos Institute runs two main programmes in west Africa from Paris and its branch offices (Senegal, Mali, Chad and Ghana).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The programme to support pluralism in matters of information, which has four major objectives: - to expand and consolidate the legal, institutional and statutory framework of pluralist-type information - to increase professionalism in the media - to give institutional support to authors in west Africa who promote pluralism in information - to contribute to the production and circulation of more diversified and more qualified information on certain priority topics such as the environment, human rights, management and prevention of conflict, etc.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The migration and cooperation programme seeks to enhance the value of the contribution made by citizens from Third World countries residing in the rich nations to development in their countries of origin. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union, UNESCO and the ACCT, American foundations (Ford, Rockefeller) or German foundations, and bilateral cooperation agreements (Denmark, Netherlands, Norway, Germany, France) support the actions of the Panos Institute. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The press in Africa as a tool in the democratic  process</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Florence Win&eacute;ry</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although radio is 'king of the media' in Africa, the press is increasingly becoming an active player in the democratic process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This has been seen particularly over the last six years in the French-speaking African states where a burgeoning of political parties has been matched by the appearance of an unusually large number of  newspapers. In these countries, the press still requires rudimentary political stability - in contrast to English-speaking countries, where it has a much longer tradition and can nowadays be generally regarded as the 'Fourth Estate'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nigeria is a good illustration of this. One need only cite the press campaigns mounted there to protest against the Federation's membership of the Islamic Conference Organisation in 1986, and more recently, the support given to Moshood Abiola. The vitality of the Nigerian press is something that deserves to be emphasised. Despite a series of measures over the years aimed at suppressing it (not exclusively by the military authorities) it is still much in evidence. There are demonstrations to support it, and it has 'gone underground' at times, continuing to publish clandestinely. The journalists' struggle intensified in June 1993, when it was recommended that they should exercise 'discretion and self-regulation'. In spite of the problems, the Nigerian press endeavours to remain a source of pressure in Nigeria's political and social arena.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Returning to the French-speaking media, we see that the pace of expansion varies considerably from one country to another. In Benin, for example, current discussions are centred  strongly on opening up the country's airwaves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Is a private press a partisan press?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is debatable whether the private press is truly independent. In the political sphere, it is often highly partisan while 'economic' independence - in the sense of access to the materials needed to produce a newspaper - is not always possible. Printing and distribution are often subject to monopolies which may constitute a form of disguised censorship for the publishers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initiatives aimed at setting up press associations in one form or another have been launched in an attempt to overcome these problems. This helps explain why the SEP (publishers' Society) was established. This group, which hopes to extend its activities throughout the region, is based in Benin where the democratisation process (and the proliferation of press titles) first begun. In many countries, media associations have already been formed covering specific areas such as radio, the press and publishing. There are plans for similar organisations in the field of television. Sometimes, they have printing facilities which are available to other private publications.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The principal challenge facing a general information-based newspaper is that it should appear regularly and on time. The next stage, ideally, is for it to be able to increase its distribution. Initially, a number of newspapers only came out monthly or even every two months. After appearing regularly for several months - and thereby achieving  relative financial stability - they then moved to weekly publication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most countries, a new legal framework was also adopted, although the application of the legislation has often proved laborious. This is particularly true of the setting up of regulatory authorities. In Senegal, where the media was previously governed by a law passed in 1979 (and amended in 1986), new legislation was enacted at the beginning of 1996. The measure was prompted by concerns over ethical standards, a demand for a more 'responsible' approach, a desire to prevent monopolies developing, and fears of excessive foreign involvement. This year has also seen the implementation of media law amendments in Cote d'lvoire.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The focus of the work of many newly-formed organisations has been the drawing up of a professional code of ethics, with a view to defining the basis of the journalist's profession. In Cote d'lvoire, the OLPED (Press Freedom and Professional Ethics Monitor) was created in September 1995 in Yamoussoukro at a seminar on journalists' responsibilities during elections. The OLPED is made up of 13 members representing publishers, civil society and the nation's journalists. Although the 'Monitor' has only moral authority, it has had considerable influence on journalists' professional consciences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The OLPED held weekly working sessions up to March 1996 and now meets every two months. One of its main achievements has been to define the criteria whereby a responsible attitude can be guaranteed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vigilance</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The press can expect to be subject to rigorous supervision during an election campaign - as happened recently in Benin. Indeed, Benin's press has attracted special attention from various national institutions including, most notably, the NGO community. This interest resulted In the organisation of seminars on journalism during an election period, designed to avoid incitements to violence. The HAAC (Audi  ovisual and Communications High Authority), responsible for statutory control of the media in the run-up to and during the campaign, took part in these meetings which were aimed at increasing awareness and highlighting the heavy responsibility carried by the media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite a number of incidents during the campaign (which were immediately reported) and although the situation threatened to get out of hand while the country was obliged to wait for the publication of the results of the second round, the press conducted itself in a fairly moderate manner. It should be recalled that there was a great deal of apprehension in Benin before the results were announced with a widespread fear that violence might break out. These fears were given extensive coverage by the media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The HAAC proved to be central to the electoral process and, ultimately, the press was congratulated by most political leaders in Benin, and by those from abroad who were involved in organising and observing the poll, for the role that it played in the process. By and large, it concentrated on portraying popular expectations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During an election period, the print media is an essential vehicle of opinion and power, justifying the creation of special titles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present, the private press is playing an increasingly important role in the democratic process and the question of its survival appears to have attracted more serious attention from the authorities. In Senegal, a subsidy has been granted to a number of newspapers, subject to certain conditions, and Mali set an example this year by establishing a private press aid fund, with Cote d'lvoire about to follow suit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The political context which has favoured this flourishing of the private press has had a marked influence on the way it has developed and on the editorial content of most journals - which is strongly focused on politics and 'national' issues. The press has barely had a chance to find its feet on the media scene and in the political process, and it has had to contend with huge  economic constraints. Low circulation figures are one key reason for its precarious position - newspapers are read only by an educated, urban minority. However, the press is now embarking on a new course, attempting to establish a loyal readership with a view to guaranteeing its long-term survival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Independence and integrity ought, of course, to be the hallmark of journalism, although currently it is not  possible to say that the profession is dissociated entirely from political militancy. In the past, the press has played  a part in undermining the national consensus by promoting division and, on occasion, fomenting exclusion and confrontation. The issue today is whether the sector can now take its place in states governed by the rule of law, representing public opinion and helping to bring about a rapprochement of ideas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F.M. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Benin's press on parole?</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Richard Lawson T&egrave;vi</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When President Mathieu K&eacute;rekou of Benin granted permission to set up private newspapers in his country, the result was an upsurge of new titles. The following article is written by a journalist who works on  one of these publications ('Tam-Tam Express'). He offers an assessment of the way the private press has developed in Benin, and in particular of the ethical and economic challenges it needs to overcome in the new democratic order.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1988, President K&eacute;r&eacute;kou's revolutionary regime authorised the setting-up of private newspapers in Benin. At the beginning, only a limited degree of freedom was granted to new publications but things have evolved quickly. 'La Gazette du Golfe' and 'Tam-Tam Express', the first independent weeklies to be set up (two years prior to the 1990 national conference), went beyond what the Marxist regime had in mind and effectively achieved press freedom in the face of opposition from the Ministry of Information and Propaganda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Journalists took advantage of their initial limited freedom to publish reports about political and financial scandals and this, not surprisingly, gave a new lease of life to the media more generally in Benin. In particular, journalists from the national radio and television  channels were quick to switch their style of reporting, dispensing with the stereotyped formal language which had previously characterised the public-service media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meanwhile, several politically oriented publications came into being ('L'Opinion', 'La Recade', 'Le Canard du Golfe'). This development gave newfound dynamism to the emergence of a free and independent press in the crucial period prior to Benin's national conference, which was held in February 1990.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To date, 170 titles have been registered with the Ministry of the Interior, although barely half of these have been published more than five times. Some appeared only once and many have existed in name only. Publications which have had only a sporadic existence are legion and, in the years between 1991 and 1996, when political power alternated between Presidents Soglo and Kerekou, independent privatepress titles flourished. Unfortunately, they faced a number of problems - such as prohibitive paper and printing costs and poor distribution networks. The result was that many operators were financially ruined as a result of their decision to venture into this area of publication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Currently, the Benin market has only 20 or so titles which appear on a   reasonably regular basis. For the most part, these are two-weekly and monthly publications which concentrate their activities in Cotonou. The audiovisual media are conspicuous by their absence, despite the provisions of the Constitution adopted in December 1990, which gave special powers to the HAAC (Audiovisual and Communications High Authority), particularly as regards guaranteeing 'press freedom' and 'opening up the audiovisual sector'. No one knows when this law will actually be implemented, but it does appear that the Benin Parliament, which sits in Porto Novo, has been giving more attention to this issue since General K&eacute;r&eacute;kou's accession to power.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The relationship between the press and the state</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governmen/press relationships are not particularly healthy at the moment. The usual reflex of authorities in any country is to control or manipulate the press wherever possible. At the ORTB (Benin Broadcasting and Television Office), a branch of the public sector, journalists often complain of the pressures they face in processing information. The same is said at the national daily, 'La Nation'. Fortunately, such pressures have not always shaken the resolve of the professional journalists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The private press has a different problem. In this case, it is the newspaper proprietors who look to collaborate with the political parties. As one publishing editor has said, 'Our problem is more one of allegiance than of harassment'. Virtually all publications are political vehicles for one or other group - which makes nonsense of the code of ethics that is supposed to govern the profession. This phenomenon was most marked during the election period. All the titles that had been in 'hibernation' came to life again and new titles were born, only to disappear once the poll was over. This is also a reflection of the very meagre resources available to most private publishers. Those who do have sufficient means are usually quick to offer allegiance - for example to particular businesses - in order to position themselves more favourably from an economic  standpoint. Thus, some of the press rather overtly promotes particular economic interests. Others assiduously woo politicians and, in some cases, use blatant blackmailing techniques. In the latter situation, the 'market' operates on the basis that a file (sometimes assembled from a number of documents) will not be published if an endorsement is given or - what is worse - in return for hard cash. The justification for this shameful practice is that the market is highly restricted, sales of newspapers bring in very little income and advertising is non-existent but the newspaper has to keep going nonetheless. This situation also explains why defamation actions are frequently settled 'out of court' by the parties to the dispute.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A profession fraught with difficulties</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another explanation for the existence of blackmail is the lack of training. The majority of journalists working for private publications come into the profession for want of something better to do, after they have finished their university courses. One experienced journalist refers to these people as mere 'hirelings'. It is only once they have entered the profession that they learn the basics through joining journalists' associations and by receiving support from some of the bilateral-cooperation missions and foundations that are operating in Benin. The country does not, itself, have any colleges of journalism to speak of. Only recently, the national daily newspaper inaugurated a course for young journalists receiving their training on the country's various publications. This course will be spread over one year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Young journalists working at the national agency, the Benin Press Agency, are trained by WANAD (the West-African National Agencies Development) centre, under the auspices of UNESCO, which is subregional in vocation. The 20 or so trainees have no clear idea of what awaits them when they finish their course - whether all, or just some of them, will be taken on full-time by the agency. Those who are not kept on at the end of their training period are likely to  swell the ranks of the 'hirelings' - who seem fated to remain at that level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new administration will have to tackle the more general question of aid to the press in order to give a fresh boost to the private sector. This has been facing a real struggle since the devaluation of the CFA franc. The effect of the devaluation was to increase the cost of all the inputs needed for publishing newspapers. A new initiative of the part of the authorities would make it possible to offer more work to journalists and to improve considerably the quality of work they produce. To quote the publisher of a private newspaper: 'The influence of money must be curbed. To do this, the state must grant genuine aid to the press so that the profession can be genuinely free and objective and thereby fulfil the important role it has to play in the consolidation of democracy'. R.L.T. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Current media in the English-speaking Caribbean</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Dr Marjan de Bruin</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author of this abridged article, who leaches et the Caribbean institute of Media and Communication (CARIMAC) at the Mona (Jamaica) Campus of the University of the West Indies, focuses on some of the peculiarities of press and media development in small island Caribbean states.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The English-speaking</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caribbean comprises thirteen independent nations that are members of Caricom (the Caribbean Community) and a few  remaining small dependent territories. The total population is about six million. In most of these countries, the majority of the population is of African descent although in Trinidad and Guyana, about half the people are of Asian (Indian) origin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sea, whose name unites the islands, is a serious barrier to communication and social interchange between them. it takes as long to go by plane from Barbados to Jamaica (1200 miles direct, but 2000 miles via Miami) as it takes to cross the Atlantic from Paris to New York (3600 miles) - and the latter journey is usually cheaper! And until fairly recently, telephone calls from neighbouring Caribbean countries without a common language were routed through London, Paris or Miami.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The distances make communications difficult. Mail can take weeks, telephone circuits are often overloaded and, in some countries, unscheduled power cuts often disrupt computer systems at the most inopportune moments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Communication and the media</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Caribbean has a strong oral tradition. This, together with poverty and an estimated general literacy rate of about 80%, makes radio the most popular medium. Recent studies show,  for instance, that 99% of Jamaican households reported having at least one radio at home. In Jamaica alone, three large national radio stations between them broadcast nine hours of prime time call-in radio.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In all Caribbean countries, alongside the mass media, 'alternative' medias play an important role in communication for social change. In some countries, the term simply connotes non mainstream operations. In others it refers to alternative formats which are found in the mainstream media. The term also represents the use of other communication behaviour - popular theatre, dance, music, oral history, story telling. It has been suggested that the increased use of alternative media and alternative uses of mainstream media are an indication of the audience's dissatisfaction with the mainstream mass media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most English-speaking Caribbean countries, the government owns some of the major mass media, especially electronic. Only recently has the private sector developed its own strongholds in radio and television. Print has always been an area of mainly private ownership. Only the larger countries have daily newspapers; morning or evening papers - although usually not more than two or three. In the smaller countries the press consists of weeklies, or bi-weeklies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government ownership</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ownership or control of media houses by governments is recognised as  a serious obstacle to true investigative journalism.The economies of all Caribbean countries are heavily dependent on tourism. Stories on environmental hazards and crises which might affect this essential source of income are subject to explicit or implicit (selfl censorship.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government ownership in some instances means policy discontinuity over time; each new regime imports its own set of administrators and sometimes even entire newsroom staffs. In other instances, where the same party has ruled for a long time, positions within the media are very stable because they are tied to political loyalty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Private ownership, however, does not mean an absence of potential pressure or political influences. In Trinidad &amp; Tobago, the country's oldest daily - The Trinidad Guardian - recently lost its Managing Director, its editor and six of its top editorial executives, after the owners - a supermarket chain - pressurised the editor to moderate criticisms of the country's new administration. The owners also tried to convince the managing director and editor to dismiss a columnist who was a disaffected and now hostile former member of the new ruling party. In apparent justification, the owners produced a document which suggested that it was the policy of the Guardian not to endanger the commercial prospects of its owners by injudicious criticism of the powers that be. Caribbean journalists attacked the Guardian ownership for what some saw as an attempt to turn a respected newspaper into the public relations arm of a commercial congLom&eacute;rate. Despite the protests, the Guardian's new editor, a veteran of forty years in journalism, argued that the proprietors had good reason to interfere with his predecessors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The region's oldest daily, The Jamaica Gleaner (established in 1834) went even further. In an editorial it said: 'In our view the owners have a right to oppose the way in which the judgment of the Editor and others is exercised. The right of the Guardian Board to query content cannot be questioned. It is impossible for a newspaper to be run   without the input of the Board of Governors.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small markets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most English-speaking Caribbean countries are relatively small in population as well as area. The number of media organizations is limited. The limited size of the market has important implications for the financial basis of the media, especially the part that is privately-owned. It limits the horizontal mobility of media workers - there are simply not that many options - and it makes the relationship between media and sources extremely vulnerable. There are not that many sources either. It also means that most Caribbean media houses have very limited resources. Many reporters have to cover a wide range of topics. Specialised reporting for instance on the environment, or health, is usually not feasible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the major problems in the Caribbean media is the high proportion of imported television programming. The region is geographically close to the United States and satellite broad  casting makes access to the Northern networks even easier. In the ten years from 1976 to 1986, the imported content of four large television stations in the region moved from an average of 78.5% to 87%. When the amount of imported content carried by the smaller stations was included, the average increased to 90% of all material televised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Privatisation and new technologies</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several of the larger Caribbean countries have seen an explosive growth in the electronic media. Jamaica, which has a population of about 2.5 million living in some 620 000 households, and per capita GDP of $1563, has seen the number of radio stations grow from three to nine and TV stations from one two, in a period of just five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trinidad &amp; Tobago, with 1.2 million inhabitants in 300 000 households, and per capita GDP of $4049, went through a similar process, with seven new radio stations and two new, privately-owned TV stations being set up over the last five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Barbados, with a population of 260000 living in about 50000 households has long supported two daily newspapers. There are also two TV stations on the island, while viewers can receive television signals from neighbouring islands. This country has the highest per capita GDP in the region ($5562) after The Bahamas ($10,308).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One positive effect of this intensive growth is certainly to be found in the increased employment opportunities for broadcasters. In the past, journalists risked their careers if they disagreed with their employers. Now people have more options. However, increased competition in a relatively small market also enlarges the risk of commercialisation and a lowering of standards. One does not need to undertake in-depth research to discover that locally-produced television is scarce and not always of the highest standard. It is cheaper to buy foreign programming than to produce original content. Some   of the graduates of the Caribbean Institute of Media and Communication, who performed above average during their training and education in print journalism, can be seen sliding down the standards scale once they enter the mass media as working journalists. Similarly, the standards of newsrooms are not always high. In fairness to the professionals, it must be said that the decline in standards is partly due to the lack of resources in editorial departments. The major newsrooms in radio and television in Jamaica, still depend on typewriters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Development of new technologies has contributed to two almost opposite movements. On the one hand, greater access to worldwide networks has widened horizons. On the other, the introduction of cable TV offers, at least in principle, the possibility for small-scale communication initiatives, such as community radio stations either for geographical communities or communities of interest (for example, people or groups interested in the environment).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Satellite dishes, VCRs and computers are breaking down traditional communication borders. In the Jamaican capital, Kingston, 28% of households have a dish and 21% a computer. The picture is very different just 20 miles away, in the neighbouring but rural parish of St Thomas, where the figures are just 1% and 2% respectively. New technologies are affordable for the happy few and are increasing the gap between the 'haves' and 'have-nots' of information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In all of these societies, computers sit uneasily in otherwise nondigital environments. The information that one works with is usually not computerised. Many records are still handwritten, with data kept on index cards. Computerisation is a costly process for which there is rarely a budget.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Once the hardware is available, it is easy to retrieve data from non Caribbean sources. At the same time, it is barely possible - at least at the moment - to tap into Caribbean data sources. There is no commercial Caribbean software. Page make-up and layout programmes, for instance, rely on  non-Caribbean electronic clip-art-images and symbols. It may simply be a matter of time before local products develop, but currently, the main constraints are to do with lack of funds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Journalism</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How is journalism faring in this environment ? The Caribbean context gives journalism a special professional profile. The small size of Caribbean societies has implications for the use of sources. Access is easier, but it also creates sharper dilemmas where loyalty is concerned: most sources are people you know personally and who know you. Anonymity is almost impossible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because the societies are so small, you will meet many of the same people in different roles on different occasions. The small scale of the market makes all enterprises in media and journalism very vulnerable to market forces: the withdrawal of one or two major advertisers would endanger the chances of survival of some media houses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The situation of the press is most marginal in the smaller countries. In Antigua (population 66000), radio and television are controlled either by the Government or by people with close links to those in power. One opposition paper, a trade union publication, has survived several legal assaults by the authorities over the years. The other, little more than a newsletter, has managed to survive into its second year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Grenada (population 91000), journalists complain about police harassment of reporters on duty, and in most of the smaller countries, journalists are uneasily aware of the continuing hostility of long-ruling political parties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The working environment of journalists in Caribbean media organisations is usually more modest compared to that of journalists in rich countries. There is less technology, smaller staffs and lower salaries. In the smaller Caribbean countries, it is not unusual for journalists to have to combine two jobs. Journalism alone cannot pay the bills.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a sharp difference between rich and poor in most developing countries. For large sections of the population, the big decisions will have nothing to do with buying a second or a third television set.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is more likely to be a simple matter of whether there is food on the table tonight. These different priorities obviously influence a journalist's agenda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In developing economies, this can create serious dilemmas for the journalists: if you know your story is likely to hurt the tourist industry - which happens to be the main national income earner of your country - will pursuing it be a waste of valuable time ? And how do you decide on the relevance of a scoop when people - some of whom are your friends - could lose their jobs ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">M.d.B.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Sources</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hilary Brown (1995): American Media Impact on Jamaican Youth: The Cultural Dependency Thesis in 'Globalization, Communications and Caribbean identity', Edited by Hopeton S. Dunn, Kingston, Jamaica, lan Randle Publishers. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aggrey Brown and Roderick Sanatan !1987). Talking With Whom ? A Report a the State of the Media in the Caribbean. Caribbean Institute of Media and Communication (Carimac), Kingston, Jamaica. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aggrey Brown (1995). Caribbean Cultures and Mass Communication Technology: Re-examining the Cultural/ Dependency Thesis, in 'Globalization, Communications and Caribbean Identity'. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">'Doctoring' the image</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With modern computer technology, it is now very easy for publishers (and film-makers) to dabble with reality. Whereas in the past, you could be reasonably sure that what you saw was a fair representation of what actually happened, today there is no such guarantee.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recently in the United Kingdom, one of the country's regional newspapers came in for criticism when it published a 'doctored' photograph of a well-known opposition politician. He was captured on  film at a social function sitting at a table with a glass of beer in front of him. By the time the paper's computer experts had finished with the photo, it looked as if he was drinking champagne ! When the story broke, the journal thought it expedient to issue an immediate apology. For while  this kind of misrepresentation may appear trivial, in the modern age, image is crucial for those who are involved in public life. Put simply, voters' are more likely to look kindly on beer-drinking politicians than on those whose favourite tipple is champagne.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was a similar case involving an advertisement issued by a well-known car manufacturer. For their publicity in Britain, the company used a landscape photo portraying a selection of their employees. In Poland, the same picture was used but black and Asian workers were no longer to be seen. Their places in the line-up were miraculously taken by people of Caucasian appearance. The advertisers' rather surprising explanation was that this had been a 'mistake'!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other recent victims of 'doctored' pictures or socalled 'photo collages' have included members of the European Parliament and a senior EC official, although these particular misrepresentations received very little publicity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Should consumers of printed or broadcast material be entitled to assume that images are never tampered with ? And if some doctoring is acceptable, where do you draw the line ? The answer to the first question is clearly no. There are certain situations where photo or film enhancement techniques are unobjectionable. We sometimes use them on The Courier cover pages to remove blemishes or fill in gaps which may detract from the main image. In fashion  advertising, it is common for the 'look' of the model to be altered. The aim here is to draw the reader's eye to the page so that their attention can then be focused on the product. More dramatic alterations may even be acceptable if it is evident to the reader that a change has been made. Satirical articles, for example, can sometimes be amusingly illustrated with obviously altered images.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Where the practice is reprehensible is where the picture has been changed in a way that leads the reader to draw false conclusions about what he or she is observing. The  classic example of this is where the image of a person captured in one setting is placed against a different backdrop, without the reader being informed. This may be done to give either a more positive or a more negative impression (the latter approach is more usual) but in either case, it is dishonest. If a politician allows himself to be photographed on a Caribbean beach while on mission at the taxpayers' expense, even if he was only there during the lunch break for a quick dip, then he can't really complain. But if the picture was actually taken when he was on holiday in Majorca, and superimposed against a more exotic back  ground, then both the 'victim' and the reader are being cheated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There will always be borderline cases, but in principle, it ought to be possible to draw a reasonably clear distinction between 'right' and 'wrong' in this area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nonetheless, it is likely that distorted images will continue to be presented to us in the future. In pluralist societies, newspapers and broadcasters operate in a fiercely competitive environment and in theory, this should provide a deterrent. If one media organisation is found to have doctored images in a dishonest way, there will always be plenty of others willing to expose the misbehaviour.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In practice, however, the only real deterrent is the likelihood of a drop in circulation, or lower viewing figures. And while consumers may say they disapprove of journalistic dishonesty (whether in photographs or the written word), there is little evidence to suggest that they react by taking their custom elsewhere. Indeed, in some developed countries, the closer a journal sails to the wind, the more likely it is to enjoy a high circulation!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It used to be said that 'the camera never lies'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nowadays, we can't be so certain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S.H.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Analysis</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Broadening the debate</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In issue 156 of The Courier, we announced the launch of a programme by the European Centre for Development Policy Management on the future of KU-ACP relations beyond Lom&eacute; IV. Here, we publish an abridged text supplied by the ECDPM reporting on progress.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After 20 years, the Lom&eacute; Convention is thought by some not to have lived up to expectations and now that East West rivalry is no longer an issue, many doubt its continued relevance. Questioning, as such, is no bad thing, provided it takes place in a fair and unbiased manner and is not used as a pretext to abandon the acquis  of more than 20 years of cooperation. This is the rationale behind a number of private and official initiatives to redefine KU-ACP cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Consultations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ECDPM's post-tome IV exercise has now been up and running for more than a year. Consultations have been held in more than 20 ACP countries, involving representatives from the private and non-governmental sectors, officials in the National Authorising Offices, EC delegations, regional organisations and research centres. A number of strong impressions have emerged from these interviews. In the first place, the initial comment of many NGOs and private sector representativ  was essentially 'what is in it for us ?'. This points to a lack of knowledge of the Convention in non-governmental circles and suggests that this complicated instrument is not entirely 'user-friendly'. Its government to government character was also criticised. There were calls for ACP-KU relations to be opened up to the private sector and civil society. In this context, experience with decentralised cooperation was seen as encouraging.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Second, the benefits of the Lom&eacute; trade provisions were highlighted with fears being expressed about what would happen after the year 2000. It was felt that at a time when many ACPs  are undergoing structural adjustment, and the private sector is getting its act together, a clearer European commitment in this area would benefit both sides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Various actors from the private, NGO and research communities indicated a willingness to engage in debate on redefining mutual ACP-KU interests and on the design of a new cooperation contract. Some of them had an opportunity to present their views at an ECDPM conference on the future of KU-ACP relations held on 12-14 June.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is clear that the process of reflection is now firmly under way. At the institutional level, the Joint Assembly began as far back as February 1995, when it launched an action plan to revitalise KU-ACP cooperation. This year, it asked Senator Jean-Louis Firmin of Haiti to draw up a report on the future of the Lom&eacute; Convention. It also requested the Social Partners to tackle the issue at their next annual meeting in November 1996. On the European side, the Commission will present a Green Paper later this year while the ACPs are also studying the question. Last November, the ACP Council resolved that Heads of State should meet before the end of 1997 to agree on a joint position.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Obstacles</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All this activity suggests a real awareness of what is at stake. Many obstacles have to be overcome, however, if a new type of partnership is to emerge. The main pillars of Europe's commitment to the ACP countries - aid and trade - both appear under threat. It will be necessary to redefine mutual interests - beyond the negative interdependencies - so that they can serve as a basis for a more modern and effective partnership. Greater creativity  will also be required to find new forms of EU support on ACP trade issues that are compatible with World Trade Organisation obligations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An in-depth rethink of ACP-KU cooperation will significantly benefit from inputs by actors traditionally excluded from the discussions - who are anxious to participate in redefining cooperation ties. For instance, in Namibia, NGOs called for formal consultation mechanisms for non-governmental actors. Similarly, economic operators meeting in Trinidad in November called for a new Europe-Caribbean partnership. There should also be a role for applied research conducted in ACP centres. There is already a joint research project on the future of West Africa Europe relations and similar initiatives are being formulated elsewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The plea for a debate that is open to the key ACP actors should be taken on board by decision-makers and negotiators - and thus far, they have proved receptive. However, two conditions are needed to maintain this fruitful exchange. First, ACP stakeholders need to be able to base their views on full knowledge of the facts and issues. It is essential that the Convention's authors make a major effort to provide more and better information. The ECDPM is willing to play a part in this. Initiatives already under way include the development of EUFORIC - a Forum on the Internet for specialised information on European development cooperation - and the preparation of practical guides to the Lom&eacute; Convention. Enhanced access to information can help all partners move towards a real dialogue. Second, forms and channels for dialogue. need to be devised to ensure that an open debate is sustained beyond the initial reflections taking place within the EU and ACP groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ECDPM</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">'Re-compromising' development aid for the future</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Jos Jonckers</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author of this article offers an academy critique of *e challenges facing the global system of development cooperation in the post-cold War era. He argues that the old compromises that have shaped development assistance since the Second World War have broken down and pleads for a radical re-think of the strategy in order to 'enable' fess affluent societies to gain from the advent of global 'free market democracy'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let us face it. International development early 50 years, the developed world has taken aid for granted. It no longer does. In real terms, it has started to give less. The expected 'peace dividend' has not materialised and scepticism is rising. Aid and solidarity are considered old-fashioned concepts. Progress and development, it is increasingly argued, must come from cooperation based on mutual interest and a businesslike approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aid scepticism is at its highest in the USA. A conservative majority in Congress promotes radical 'winner' recipes and aid has been slashed. Slowly but surely, America is getting out of the development business. Lacking domestic support, the Clinton administration seeks to 'rescue' the country's aid programme by seeking more cooperation with other donors - particularly the KU, whose solidarity horizons do not yet stop at its own borders. But even here, horizons are shrinking. European aid to its immediate neighbours in the East and the southern Mediterranean basin has risen. Happy and prosperous neighbours suddenly seem more important than distant friends in need.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Has the end of the cold war marked the beginning of a cold world - where international solidarity is being dismantled together with the nuclear warheads ? Or could we be experiencing the beginning of a fundamental reshaping of international solidarity and aid between nations?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beyond altruism - self interest</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International aid has always involved a compromise within affluent society. People and nations are not normally disposed to give something away unless they receive something in return. Any attempt at understanding and reshaping the future of development aid must therefore start from the premise that those providing development aid do so as a result of a complex and evolving compromise between altruism and self-interest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Affluent countries are usually only interested in assisting poorer ones when the effect is to strengthen their international leadership, and in some way to enhance their security and material wellbeing. Looked at in this context, we must recognise that development aid, whatever its altruistic aims, will only exist if it also serves the legitimate, albeit more selfish agenda of the donor. It also means that the compromise which gives aid its rationale in affluent society changes over time: aid is regularly 'recompromised'. In secure and prosperous times, donors are  more inclined to forego self-interest and to cooperate in the interest of less affluent countries. In times of insecurity, the altruistic dimension is likely to diminish in importance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In colonial times, systematic aid flows first emerged as a result of a compromise between expansionist Northern governments and Christian society with its own 'colonizing' clergy. Decolonisation had the effect of increasing insecurity in most former colonial powers. In an attempt to safeguard the capital they had 'invested' in their overseas territories, following the latter's independence, they increasingly shaped aid with a view to 'buying' goodwill from the new rulers. This process, which 'recompromised' aid from a colonial into a neocolonial form, resulted in the secular, institutionalised arrangement now known as 'bilateral aid'. In addition, during the Cold War, Western aid was used increasingly as a device to stop the Third World joining the Second World (the communist bloc). The result was an aid system which was both more internationalised and more politicised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The next stage came with the end of the Cold War. Communism had joined colonialism and fascism in the dustbin of history. Affluent Western society had emerged as the winner. With it came the Western vision for stability, peace and progress: a world of sovereign nations, organised on the basis of democratic and capitalist market principles and committed to respect for each other's territory and for basic human rights. Today, capitalism has become the norm in most nation states. Long-time sceptics such as India, and even convinced opponents such as China and Vietnam, have embraced it. Democracy has not yet achieved the same coverage, but it is sailing forward under favourable conditions. Political pluralism is steadily being consolidated in much of East and Central Europe, while dictatorial regimes in Africa, Asia and Latin America are now the exception.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The effect of all of this has been a speedy erosion of the terms of the compromise on which development aid thrived for so long. In a rapidly globalis  ing,multi-polar world, the old approaches appear increasingly redundant. From this perspective, the current aid crisis is not surprising and is not necesarily a bad thing. Western affluent society is essentially trying to come to terms with the demystification of its development aid, as part of a process of reshaping it for the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Three 'recompromising' strategies</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As in the past, the recompromising process is influenced by both self-interest and altruism in affluent society. Three trends can be identified.. The first, which is the most idealistic, involves restoring altruism. This approach seeks to 'purge' aid of the perverse political and economic compromises and contradictions caused by decades of neocolonial and Cold-War self-interest. It has impacted on aid in several ways. First, it has given a significant boost to humanitarian aid - the most altruistic form - at the expense of development assistance. Second, it has led to a 'decentralisation' of aid - with more assistance being channelled through organisations such as NGOs, that have an 'uncompromised' altruistic profile. Third, it has led to a 'deconstruction' of development aid along idealistic-altruistic lines. 'Women in development', 'child health', 'environment'and 'poverty alleviation' are all examples of deconstructed labels around which aid is increasingly being structured and justified. Finally, it has prompted an 'intellectualisation' of development aid with the particular purpose of tightening its altruistic aims. For example, the Logical Framework Approach, the concept of 'sustainable development', the UNDP's Human Development Index and various experiments with more 'accountable' project management systems, have all essentially been devised as ways of encapsulating and supporting the altruistic intentions that lie behind aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second recompromising strategy, which may be summed up in the expression be businesslike, approaches development cooperation  much more skeptically. Aid, it is argued, only makes sense if it leads to real progress and development - and the prevailing view is that this is not happening. The approach is fueled by the obsession of trying to measure progress with the help of business tools such as 'output', 'impact', 'efficiency', 'rates of return' and so on. This has led to burgeoning aid 'evaluation'. It has also probably contributed to the discovery of aid failures which, in turn, has prompted growing criticism of aid agencies and operators. The businesslike strategy has gained further ground because of the failure of many countries to achieve any real progress in recent decades. Its advocates argue that the compromises which undermined aid's development impact in the past are inherently linked with its altruistic nature. The conclusion is that altruistic aid will seldom or never work. The strategy has impacted on aid in a number of ways being, for example, the major cause of so-called 'aid fatigue'. It has also prompted a search for ways to enhance cooperation for mutual benefit, indeed transforming the narrow, pre Cold War trade cooperation link with developing countries into a much broader and rapidly growing economic cooperation approach. Finally, it has sought to enhance aid's impact on the economic conditions and growth prospects of developing countries through more ambitious, structural-oriented forms of aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Regionalism, the third major strategy, is linked to globalisation. Rooted in human survival psychology, this approach prompts nations in close proximity to form 'strategic' coalitions. In the post-Cold War era, development aid is one of the instruments used by affluent regions to strengthen their position in a 'globalising' environment. The strategy entails promoting 'open' regionalism elsewhere in the world and capitalising on this to create linkages and interactions which enhance their own influence or hegemony. From the point of view of the international political economy, this makes perfect sense. Having succeeded in making the 'world of nations' accept capitalism and democracy, it is through the consolidation   process of free market democracy in other countries and regions that powerful affluent nations will seek to gain maximum advantage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Need for a vision</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With this improved insight into the dynamics that have been reshaping development aid, is it now possible to go further and develop a more political vision of relations between affluent and less affluent nations in future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Free market democracy, having endured the 'crises' of decolonisation, fascism and communism, has succeeded in promoting stability and peace within and between nations. Its main strength has probably been its crucial enabling function, with an increasing number of people and nations now in a position to 'earn' a better future. It appears that the model has the capacity to generate fairly equitable growth and progress, which is presumably why more and more countries are turning to it. As is so often the case, however, the strength of the system also contains the seeds of its weakness. Conceived as an 'enabling' mechanism, it results in the categorisation of those who fail to 'be enabled' as 'unable'. Marginalised because they cannot participate and perform in the   system, the excluded (whether individuals or states) are dubbed 'losers'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are seen as a burden and a threat by the 'winners'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The result is disparity in society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experience in most affluent nations suggests that despite the enabling environment created by free market democracy, up to a quarter of the population finds itself unable to perform effectively, and is marginalised as a result. Moreover, there seems to be an upward trend in the numbers affected by unemployment, underemployment and poverty. Disparity never occurs without some cost to society, which is a good reason why it ought to be minimised. The costs come mainly in the form of internal transfers earned (but foregone) by the active, 'winning' section of society. In more sociallyinspired, free market democracies, it is accepted that marginalisation resulting from the model's shortcomings must be minimised and/or adequately compensated for. In more conservative free market democracies, exclusion is seen more as a weakness of individuals than of the system. Compensatory transfers are generally kept to a minimum to induce people to 'break out' of their situation. But while such societies may save on 'empathetic' transfers, they will generally need to spend much more of their wealth defending against threats posed by growing disparity, such as crime, drug-trafficking and political extremism.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The costs of disparity are political as well as financial. Genuine democracy is based on the participation of a representative majority of citizens. In affluent societies, however, a growing minority no longer participates. The real danger stems from the fact that this is highly skewed. It is the same, growing, marginalised minority that is 'unable' to participate which is also withdrawing from democratic involvement. The result is alienation from the political system and an erosion of democracy to the extent that its very survival may be threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What is really at stake </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Having conquered most of the world's nations, free market capitalism is now set to conquer the world of nations, helped by technological advances in communications, transport and computer technology. Economists have amply shown that the interdependence resulting from free international competition need not be detrimental. Indeed, because global capitalism ensures that ideas, initiatives and resources can be 'put to work' anywhere in the world - wherever they generate most profit - interdependence is usually seen as mutually beneficial. In essence, it confirms what might be called the global enabling effect of free-market capitalism. The basic thesis is that the adoption by less affluent nations of free market democracy should 'enable' many more of them to improve the lives of their people in the coming decades. The boost engendered by this 'enabling effect' will, in turn, help to sustain progress in the more affluent countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If this is the aim, then a new vision should progressively inspire future cooperation between the affluent and less affluent countries. The first concern should be to define 'purpose' and 'interest' much more in terms of system and process, than of output. What really matters is the 'enabling potential' of free market democracy in the specific context of the less affluent countries. How something is achieved and by whom should take precedence over what is achieved. The ultimate aim must be to ensure that free-market democracy 'takes root' in less affluent nations and is able to determine who does what and how.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A second major concern should be to maximise the 'enabling potential' of free market democracy for the most vulnerable sections of individual populations. As mentioned earlier, up to a quarter of the people in affluent societies are excluded. In poorer countries, the figure is much higher. If free market democracy fails to enable a significant proportion of this marginalised group, then it will not take root. And if the poor cannot be mobilised, the  growth that does occur will be highly skewed, leading to growing disparity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A third point is to ensure that the 'global enabling' effect of free market capitalism does not become the exclusive preserve of deregulated capital and the 'winners' who control it, leading to new forms of exploitation and disparity. The concern must be to find a way of directing the combined forces of 'capitalism without borders' and 'democracy within borders' in such a way that it leads to a genuinely better world in which the number of 'losers' is dropping and disparities are diminishing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A historic perspective</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is useful at this stage to take a look at the history of capitalism. Freemarket democracy delivered affluence to about a third of the global population over the last century mainly because of the 'accommodation' between labour and capital in an enabling environment created by 'Fordist' mass-production and consumption. A similar accommodation is now needed to enable global free market democracy to extend material wellbeing to the remaining two thirds of the (continually growing) world population, while at the same time sustaining it among the existing affluent third. It is no longer an accommodation between capitalists and workers that is required, however, but one between the affluent and the less affluent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fordism basically transformed the 'interdependent' stake of capital and labour in the economic pie, into a 'joint stake' - leading to the production of a larger pie. By analogy, what is needed today is to ensure that affluent and less affluent societies develop a joint stake in the production of a larger 'global pie' as a result of new technologies and more efficient, globalised modes of production. Attracting and sustaining capitalist investment in such modes will increasingly depend on demand and consumption structures which guarantee that poorer societies share with affluent ones the benefits of such global production systems. In the same way that a larger 'mess-produced pie' was dependent on higher and more   equitable mass consumption, so will a larger 'globally-produced pie' depend increasingly on higher and more equitable global consumption. In this context, the principal policy aim of development cooperation should be to ensure that growth resulting from globalisationis both enabling and disparity-reducing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The disabling effect of</P>
+<P ALIGN="JUSTIFY">'poor' competition</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Driven by the powerful motive of capital accumulation, globalisation has the tendency to promote competition. In principle, this should be a good thing, but left unchanneled, it can have negative effects. One might draw an analogy between the conquering of the global market and the spread of water during a flood. The water always takes the easiest route, entering the most vulnerable areas first where it causes the most damage. Likewise, globalization, fueled by 'deregulated' capital, often tends to promote competition where it is easiest, but where it is not necessarily beneficial. This is the case, for example, in less affluent countries, where poverty is exploited to achieve what might be dubbed a 'poor' competitive advantage - in the sense that it is based on disparity, but also in that, far from 'enabling', it may actually have the opposite effect. Child labour, sex tourism, environmentally destructive tourism, tropical forms logging, the export of industrial pollution and misuse of intellectual property are all examples of 'disabling' competition resulting from global disparity. In a rapidly globalising world this is ultimately damaging to all concerned, which is why both affluent and less affluent nations have an interest in reducing the gap.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All of this points to the need for a major redefinition of society's role in general and of aid in particular. During the colonial and Cold War periods, development cooperation was progressively uprooted and alienated from society. Serving an increasingly complex and non-transparent agenda, it became more and more a 'cockpit' affair, piloted by a small specialised crew - and it  found itself flying higher and higher above society. In short, affluent society lost touch with development cooperation and aid. Occasionally, the media intervened to 're-establish contact' but the result was that development aid usually only attracted mainstream public attention when things had gone terribly wrong.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turning vision into action</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If the aim is to have affluent and less affluent society working together to ensure that the latter adopts 'free market democracy'- and can adapt it in a way which benefits both - it is vital that the former be reconnected to the business of development cooperation. The affluent must be challenged to help transform their less affluent partners, in the interested and creative manner of a minority stakeholder. They must be ready to share the wealth of knowledge and experience generated in their own process of development. Representatives of all walks of affluent life should therefore be provided with greater opportunity for dialogue and cooperation with their less affluent counterparts. Increasingly easy and cheap communications and transport should facilitate this. This new form of stakeholdership will not happen, however, unless affluent society can be imbued with the new vision.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Donors should actively support the process. Instead of spending most of their time and resources determining the scope and content of development cooperation, they should step down from their cockpit. Their new role should be as brokers and facilitators of cooperation. An initial priority must be to extol the vision itself. As this gathers momentum, they should then turn to 'brokering' it in practice - acting as a catalyst between the affluent and less affluent in order to facilitate 'enabling' cooperation between them. The development of an effective brokerage profile and methodology will probably entail important changes in the way that donors work. They need to move much closer to their  constituency, and to be made democratically accountable again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As mentioned earlier, the concept of enabling cooperation concentrates on who does what, and how. Essentially, therefore, it should be seeking to mobilise democratic and free market forces in less affluent societies. The advantage of working this way is that change and progress will be determined primarily from within the society in question - with cooperation as a source of encouragement. Such an approach also entails acceptance of the fact that the pace of progrms must be left much more to the enabling forces of the maturing democracies and free markets, however weak and imperfect these may still appear. Indeed, the central purpose of cooperation should be to help these fore" become stronger. To achieve this, cooperation will need to move away from an emphasis on engineering outputs to one which involves 'messaging' the system and process. And it is not just methodologies that need to be altered; there must also be a radical change in cooperation mentality. Thus, for example, donors should attempt to broker cooperation which is 'small but smart'. Advancing 'best practice' might be another creative way to pursue cooperation which is enabling. And while some output-related decision techniques can still be used, these must be creatively reshaped to support a more 'enabling' approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In conclusion, this enabling vision entails an awareness of the imperfections of free-market democracy, combined with a conviction that it offers enormous potential for the less affluent countries of the world. 'Recompromising' development aid for the future will mean reshaping it to support a process of adoption and adaptation of free market democracy in less affluent countries which is highly 'enabling'. The result should be a system of international solidarity which is working for free-market democracy, rather than as a substitute for it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J.J.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The effects of corruption on development</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Dieter Frisch</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corruption - defined as 'the abuse of public power for personal ends' - has always existed. During recent decades, however, it has grown both in terms of geographic extent and intensity. Since the mid 1970s, it has infiltrated virtually every country in the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It was hoped that the easing of political and economic restrictions that characterised the 1990s after the end of the Cold War would have gone some way to reducing this phenomenon. Through increased openness resulting from political pluralism and the freedom of the press, the process of democratisation should, under normal circumstances, mobilise efforts to overcome corruption. However, emergent democracies are still fragile and seem to find the task of tackling established self interests a formidable one.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By reducing state intervention and therefore the opportunities for corruption, economic liberalisation should improve matters. In the short term, however, the opposite would appear to be true. Weakened state structures, a lack of appropriate legislation, powerlessness on the part of the judicial system to combat corruption, the pursuit of easy money - mistakenly perceived by some as being equivalent to a market economy - all these factors together contribute to aggravating the phenomenon, at least in the transitional stages. Such a state of affairs cannot fail to have some effect on those who are involved in and concerned by development issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Needless to say, corruption and its effects can be seen from a multitude of viewpoints. There is always the ethical angle - but how can we possibly presume to preach to countries of the South and East when bribery is just as rife in the North and when, as far as corruption within international economic relations is concerned, it is in fact, virtually by definition, the North who is the corrupter and the South and East who are the corrupted ? The only possible reply to such an argument - and one which is morally disputable even though economically valid - would be that the rich North can afford the luxury of wasting some of its wealth whereas in the case of developing countries, their sparse financial resources need to be used in the best way possible! Other lines of reasoning emphasise the distortions that corruption causes in the fair application of conditions of competition by penalising successful, yet honest, undertakings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A major obstacle in the path of development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In my opinion, corruption should be approached from the point of view of the effects it has on development. I say this because long professional experience has taught me that corruption is one of the major obstacles to progress, and that its effects on development are disastrous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some people would no doubt counter this assertion with the 'cultural' argument whereby they would have us believe that, in certain cultures, corruption is quite normal and morally acceptable. Well I do not know of a single place on earth where growing rich through taking bribes is considered lawful or morally acceptable! I should like to quote Olusegun Obansanjo,  former President of Nigeria, on the subject: 'In the African concept of appreciation and hospitality, a gift is a token. It is not demanded. The value is in the spirit of the giving, not the material worth. The gift is made in the open for all to see, never in secret. Where the gift is excessive, it becomes an embarrassment, and is returned. If anything, corruption has perverted the positive aspects of this age-old tradition'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Then there are the cynics - including renowned professors - who claim that corruption oils the wheels of progress and enables development to take place. In this respect again, and putting all ethical aspects aside, it would be worthwhile distinguishing between the small baksheesh which 'helps' certain administrative procedures along ('acceleration fees') and large-scale corruption which perverts the course of de  velopment. This does not of course mean that we should underestimate the destructive effects that even small-scale corruption can have on society!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet others have simply resigned themselves to the situation. For them, corruption is intrinsically linked to underdevelopment. As long as a person's normal income does not provide him with a decent living, the door will always be open to bribes. It is, therefore, through development that we should be attempting to eradicate corruption. Yet this argument is reminiscent of the debate on the population explosion. It is only through development, some say, that the problems of population growth will be resolved. But by then, the planet will be inexorably overpopulated! In my opinion, the same argument is just as valid as far as corruption is concerned. We simply cannot wait for it to be stamped out through development. (In any case, development is hardly a miracle cure: true, we have the examples of Singapore and Hong Kong where corruption is extremely uncommon, but we could also mention Italy, where it was precisely at the height of the country's development that corruption became the norm). We must act therefore, and without delay, focusing our efforts on eradicating large-scale corruption.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If we analyse some of the effects that corruption has on development, the first thing we notice is that it increases the cost of goods and services, and not insignificantly either. Although a 5% reduction in the profit margin might, at a pinch, be absorbed by the supplier, corruption levels of 10% to 20%, which have become commonplace, will inevitably be reflected in the price and will, consequently, be paid for through the national or foreign (in the case of foreign aid) resources of a country. It is therefore the national economy that ultimately suffers the consequences of an unjustified surcharge on the goods or services, with the difference being pocketed by some government official or politician who has abused his power for his own personal gain. Given that such operations are generally financed by bank  loans or, in the case of foreign aid, by concessional loans, these surcharges inevitably bring about a proportionate increase in that country's debts. In fact it is now assumed that the exchange value of sums paid out in backhanders makes up a considerable proportion of the foreign debts of developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, the damaging effects of such practices do not stop there. The corrupt decision-maker may well be tempted to accept a substandard quality of service which will make his personal profit all the greater. Thus, with a road building project for example, complicity between government departments and contractors may result in corner-cutting with regard to agreed standards of quality so that the savings made may be shared out between the two parties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At their very worst, the disastrous effects of corruption mean that the conception of a project, and ultimately its very choice, are determined by corruption. As far as conception is concerned, a good example would be the purchase of a technology which is wholly unsuited to the particular needs of a country or the choice of a capital intensive project - more lucrative in terms of corruption - rather than a labour-intensive one which would nevertheless be far more beneficial to that nation's development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The absolute peak of perversion, however, is when the very choice of priorities - and therefore of projects - is determined by corruption. What we are referring to here are those situations in which the real development priorities of a country are neglected in favour of operations which generate the greatest personal gain for the decision-makers. At this point I would like to quote R&eacute;mi Godeau, writing in Jeune Afrique: 'These currency-guzzling abortive projects have become a graveyard of white elephants. Africa is littered with vast deserted motorways which are being eroded by the Savannah, with fully functional but empty factories which have been left to fall into ruin only a few years after they were opened, with railway lines which are now impassable  through a lack of maintenance, and with hydroelectric dams abandoned because they cost too much to run'. Let us pick up on the point about empty factories. These 'follies of development' are to be found in many developing countries and in Africa in particular. Some have never produced, others have failed to reach full production capacity while others still face such prohibitive costs that big state subsidies are needed to keep them going. If we follow the thread right back to the beginning we find, more often than not, that factories have been sold without ensuring real competition between suppliers. Admittedly, such projects usually have only private-sector backing (they are rarely financed through official aid), but the funding is nonetheless backed by state-controlled bodies. The existence of corruption in such cases must be more than mere presumption - what other reason could there be for making decisions which run so counter to the interests of development ? In his work 'Grand Corruption in Third World Development', George Moody-Stuart identified those areas which are especially vulnerable to corruption. These are most notably, the procurement of military and other   technically sophisticated equipment, and large-scale works (in other words, any major, capital-intensive project and any scheme where objective valuation and comparison is hampered because of the technical sophistication involved).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is worthwhile mentioning at this point that a country which borrows money to finance projects that do not satisfy its real needs, and which may indeed be considered economically futile or absurd, will see its debt burden increase - and not simply by the 10% to 20% that is used to fund 'backhanders'. The loss will ultimately be 100% if one views it in terms of the cost of the unproductive investment to the national economy. Discussions about the debts of developing countries rarely focus on the mechanisms which have produced these debts. Yet in most cases, they have become unserviceable on account of the ineffective use of overseas aid - the sort of bad management to which corruption contributes considerably.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What is more, by deflecting the sparse resources which do exist towards non-priority or low-priority areas, corruption contributes to a large extent to ensuring that fundamental needs such as food, health and education, are not met. It is therefore one of the causes of under development and of poverty in general. Needless to say, official aid is often called upon to make good the deficit left by the irresponsible management of otherwise available resources. Is it any surprise if, in the long run, public opinion in the countries of the North begins to grow weary of bridging gaps which efficient management of resources should never have allowed to appear in the first place ? How are we to convince European taxpayers that it is they who need to provide the money to fund bush clinics in countries which put their funds in prestige projects, if not directly into Swiss bank accounts?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A vicious circle that must be broken</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Effectively, we find ourselves in a 'catch-22'situation. Corruption is one of the causes of under development and poverty, yet poverty is in part responsible for its continuation. If a person cannot earn an honest living for himself and his family, then he is more or less forced into earning it by less honest means. Hence corruption is both the cause and the consequence of under development. In order to break the pattern we must therefore combat large-scale corruption inasmuch as it is a significant cause of underdevelopment and we must work gradually to eradicate the reasons for its propagation in society, and in particular to remedy the notorious lack of adequate income to ensure a decent standard of living.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In general terms, we can say that corruption also kills off the spirit of development. Nothing is more destructive to a society than the pursuit of 'a fast and easy buck' which makes honest people who work hard appear naive or foolish. That is why, in the context of economic reforms under the heading of 'structural adjustment', it is vital that the model advocated be one of a market economy based on a sound framework of legislation and on an efficient state. It should not allow free rein to the sort of ruthless capitalism which is aimed at immediate profit at all costs. The example of certain transition countries in the East, where a market economy has become synonymous with the law of the jungle, the Mafia and corruption, really should make us stop and think.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the final analysis, an economy undermined by corruption has the effect of discouraging potential foreign investors and public donors. Yet if development is to succeed, countries have to be able to attract a flow of capital. As Serge Michailof put it: 'Success attracts money. Waste, failure and chaos drive it away'. And although investors are very keen to do business, with the exception of a few opportunists, they all look for host countries that have a stable and predictable climate. Entrepreneurs have been known to withdraw from certain African countries - which are nevertheless rich in resources - because of the constraints imposed on them by corruption on a scale which they considered to be unacceptable. As for public donors, they are increasingly reluctant to offer financial aid to those countries that manage their own resources poorly. It is precisely this failing which is one of the causes of what we now refer to as 'aid fatigue'. Financial aid institutions should go as far as suspending their cooperation in blatant cases of corruption and bad management, just as they do in cases of serious violation of human rights. Conversely, 'good governance' should be the determining factor when allocating aid, and it would appear that Article 5 of the revised Lom&eacute; IV Convention does in fact foresee such an approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In conclusion, far from reserving the foregoing criticisms for countries of the South, I believe that the partners of the North have their part to play in the ravages wrought by corruption, be it only as a result of the inconsistencies between their development cooperation policies and their export promotion policies. Basing our assumptions on the principle that cooperation efforts are genuinely motivated by concerns for development - and I can attest that this is precisely the motivation behind the policies of the European Union, which I have served for a great many years - we should not forget that Western countries have a tendency to promote exports, by other means, without any consideration for the effects this has in terms of development. They thus contribute to the dishonest practices which we have been discussing. The fact that they tolerate, or even go as far as to encourage corruption as a means of promoting exports - restricting the application of the criminal law to acts committed on their own territory and allowing corruption to be taxdeductible under the heading of 'necessary expenses' - seems to me to be absolutely scandalous. In the AlortR too, the battle against the canker of international corruption is a formidable one. But it is a fight to which we are committed in the context of 'Transparency International' This NGO, which was created in 1993, makes its services available to any country which genuinely wishes to eradicate the scourge of corruption. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> D.F. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Close-up</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">National park  restoration in Chad: luxury or necessity ?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Phllippe Dejace</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Terms like 'democracy' and 'sustainable development' are increasingly used to keep donors happy, and to present new development projects in the most favourable possible light. With this in mind, it is interesting to look at an example from 'the field' to see how genuine the commitment actually is. Adherence to these concepts has undoubtedly made a positive contribution to environmental protection, but there is also a negative side</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since 1989, the Zakouma National Park in south-east Chad has been undergoing restoration in a   programme supported by the KU. Devastated by a decade of conflict, this wildlife sanctuary of nearly 3000 square kiLom&eacute;tres was little more than a huge graveyard in 1986 when Pierre Pfeffer of the Paris Natural History Museum visited it and decided to campaign for its restoration. Today, this is recognised to have been a sensible decision. It is acknowledged that wildlife are better off when they have a reasonably large area in which to live, away from human activity. Aerial counts made in 1986, 1991 and 1995 confirm that animal numbers are on the increase in the park and that irreversible destruction has been averted. Currently, Zakouma is the only area effectively being protected in Chad. The other designated sites (one park and seven reservations) remain impoverished and in a state of near devastation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recognising the challenge</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One should not be lulled into complacency. Even when a process involving local village communities is initiated, the low standard of living of the inhabitants, their educational level, and the progressive deterioration of vegetation around protected areas in  variably make the latter a tempting 'target'. In these circumstances, it is very hard to preserve their integrity. At Zakouma, a busy time lies ahead. The local people must be educated and informed as quickly as possible. This presents us with the first hurdle given the inadequacy of the education sector. The Ministry of Education is underfunded and with growing numbers of pupils in the system, it is virtually impossible to plan special programmes aimed at increasing awareness of this particular problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are other reasons why there should be short-term investment in this sector. There are good arguments for preserving a few control sites while the awareness programme is under way, since these will one day serve to illustrate what can be achieved. It is also much less difficult to preserve an area than to try to reconstitute it, once desertification has set in. The site is part of the national heritage whose value can only increase. Moreover, in most cases, the protected areas ensure the survival of fish stocks in lakes and rivers downstream and act as a reservoir for game: many of the animals which breed there provide food for the people living at the zone's edges. Even frequent wholesale slaughter of wildlife, as happens during a war, is reversible if the vegetation remains intact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the park is cut off from human activity (the area is flooded and therefore closed, to all intents and purpose, for four months of the year), it has an uncertain future. It faces pressure  from itinerant herdsmen and poachers, the latter tracking giraffe right up to the outskirts of Zakouma village, which is in the middle of the park. Although located in a wildlife reserve of 20 000 km2 - which is supposed to be a buffer zone - the park is not truly protected because human activity inside the reserve is not controlled. In the dry season, the park teems with wildlife. A clear density gradient has been identified with the animal population dropping as you move from the centre to the periphery. Indeed, only about a third of the 3000 km2 is intensively exploited by the wildlife which lives there - and even this area is relatively insecure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enclosure would give those who are keen to defend the park a grace period in which to set up long-term awareness strategies. Ironically, one danger results from the striking democratisation that has taken place in Chad. To win votes, some politicians have called for the bans applying to the park to be lifted. This approach has the potential to succeed because, owing to shortfalls in the education system, the electorate is insufficiently mature in political terms. Another factor is that traditional leaders, seeing their power progressively diminish, are inclined to 'revolt'. Thus, they may fail to intervene when stockmen deliberately invade the park, encouraged by demagogues in search of votes. When the grasslands are invaded by cattle, few wild animals can compete and they are forced to retreat to the central area of the park. Against this background of a need for urgent action, the Zakouma Park team is concentrating its awareness-raising efforts on traditional leaders and the administrative authorities - rather than on teaching schoolchildren about environmental protection (although such a campaign is also envisaged).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Participation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some argue that setting up a 'sustainable and participation-based development' strategy would make it possible to avoid the situation that now exists in Zakouma. The idea behind such a strategy - which clearly has its   attractions - is that man is perfectly capable of managing his native territory. All that is needed is for him to be granted land and to receive support for his initiatives. Many who espouse this approach continue to despatch teams to demonstrate that this is the ideal response. Unfortunately, in the particularly complicated case of managing the environment on the fringes of a national park, the local people are usually reluctant to make the investment. The more normal inclination is to reap a short-term profit from resources that are within reach. The inhabitants are also tired of the lectures they get from specialists who visit for just a few hours. The scope of the problem is such that expertise needs to be available on an ongoing basis. Considerable resources are also needed to ensure.that the effort is sustained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is not easy to halt environmental destruction in a market economy which has overturned traditional values and gives priority to increasing personal wealth and consumption. A natural environment's potential for exploitation is always limited. Yet stock-rearing involves the use of animals 'selected' over thousands of years to take maximum advantage of the least scrap of vegetation. By contrast, a wild animal is much more selective and never ruins the environment it exploits. It may even be able to adapt its reproductive cycle to the available food resources! We are nowhere near this situation in domestic stockbreeding!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is where 'sustainable development', which sounds highly reassuring, appears at odds with reality. Beyond a certain threshold, one cannot avoid depleting the resource. If one is to adopt an approach that involves the population actively, one must acknowledge that their response may fall short of what is needed. Indeed, they may do things which provoke migration, and are thus damaging. Thus, for example, the opening-up of a water source may attract more nomadic herdsman, thereby undermining rather than enhancing the surrounding area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Awareness programme</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The single most significant step towards protecting the park would be to ease population pressure, but progress in this area is very limited. We can only wait for the birthrate to decrease; something which invariably happens as a country develops. But what will become of the national parks in the meantime ? In Zakouma, an eco-development team is currently listening to the villagers' claims. As elsewhere, an attempt is being made to gain time. Unfortunately, the current climate of transparency in Chad, which is one of the positive aspects of democratisation and should be a major asset, has not had much impact in this area. The awareness programme suffers from a serious lack of trained workers and when meetings are held, they usually turn into interminable discussions, simply increasing the level of frustration. On the other hand, a convincing discussion-leader can advance matters considerably and discussion is surely the right approach to adopt. Furthermore, the process must lead to concrete results. Otherwise, decisions taken may end up being postponed indefinitely because they conflict with the interests of political decision-makers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the difficulties, the Zakouma team is placing heavy reliance on this desire for transparency. Although the project's initial aims have essentially been to restore infrastructures and thereby promote an increase in wildlife, the addition of an ecodevelopment aspect and ecological monitoring has made it possible to create an important 'reservoir' of knowledge. A computerized map of the vegetation has been produced with the help of a microlight equipped with a GPS (satellite positioning) system. There have also been aerial inventories tracking the seasonal density and distribution of wildlife, as well as in-depth sociological surveys in the villages most hostile to the park's existence. This major database makes it possible to organise meetings, conferences and discussions to demonstrate that the park's contribution is greater than it seems. One big frustration for local people living on the  park's fringes concerns the redistribution of the income it generates. Looking first at tourism, Chad hardly qualifies as a major holiday destination and those who do visit the park are too few to make a significant contribution (the income raised barely covers the cost of replacing their bedlinen !)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One interesting conclusion has been drawn from studies of the animal distribution in the different seasons. It appears that when pressure from nomadic herdsman is at its strongest, during the dry season, the wildlife take refuge in the park and numbers multiply in safety. When the stockmen return northward, the wild animals then go beyond the park boundaries where they are hunted and eaten by villagers. This is surely a form of income redistribution! Moreover, many young fish in the park's only river (the bahr Salamat), take advantage of the flooding of the area during the rains. This releases huge volumes of nutrients back into the ecosystem. In the park, the fish are safe from the fishermen who work downstream and they can swim back to their spawning grounds. This guarantees the renewal of stocks depleted during the dry season. The level of fish stocks in Lake Iro - and probably in the River Chari as well - is thus linked to the existence of the Zakouma Park! When this version of income redistribution is explained, it often helps to convince traditional leaders who then use their influence to limit incursions by stockmen or poachers. However, a lot remains to be done because demographic pressure and standards of living both make it more difficult to get the message across.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We know that excessive human activity always results in environmental deterioration. Zakouma, although under pressure, has been 'spared' to some extent, and as such, it represents an important resource. But some see it as a luxury and it faces a suspended death sentence. If people stop regarding its conservation as something that is necessary, the sentence will end up being carried out. In my opinion, the most reliable way of guaranteeing its preservation would be to enclose it completely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P.H.D. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Developing World</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">European NGOs look ahead at annual meeting in Brussels</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Agostino Ambrogetti</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 22nd annual General Assembly of European Development Non-Governmental Organisations (NGOs), and a thematic conference entitled 'A Europe open to the world', were held in Brussels from 18 - 20 April. Representatives of more than 800 NGOs attended, with the Assembly adopting 14 resolutions as well as issuing specific appeals on the European Union's Intergovernmental Conference (IGC) and on Lebanon. The Assembly renewed its approval of the development NGOs' 'Strategic Priorities', adopted the Work Plan for the 1996-98 period, and looked at the overall impact of the Lom&eacute; Convention with an eye to likely future developments. The subsequent Conference focused, among other things, on the issue of coherence between the EU's development cooperation and its other policies (notably trade and agriculture). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A general impression that emerged from the two events was that the NGO movement was attaching increasing importance to its role as advocate for the developing countries. A fundamental aspect of this is the ongoing dialogue that NGOs have with the European institutions, and the lobbying they carry out on policy issues. Commission representatives who spoke at the Assembly indicated their understanding and appreciation of this. For example, Development Commissioner, Jao de Deus Pinheiro, referred warmly to 'the very active role played by the NGO community in the debate on the mid-term revision of the Lom&eacute; Convention,' and acknowledged that the NGOs had mounted an 'important political lobby' in favour of increased funding for the next five-year period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commissioner was keen to emphasise the complementarily that existed between the European Commission and the NGO movement in support of emerging societies in the South. He also urged his audience to continue in their task of challenging the general apathy towards development cooperation. This, he said, entailed appealing directly to public opinion in order to influence political leaders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A similar tone was adopted by Bernard Ryelandt, who heads the unit responsible for cofinancing NGO projects in the Commission's development directorate-general (DG VIII) He spoke of the 'decisive' action of European NGOs in balancing other lobbies such as the agricultural one. This, he believed, had the effect of improving the coherence of EU policies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Delegates from a number of countries set out their views on the advocacy issue, and what they saw as the growing NGO role in this area. Andy Rutherford from the United Kingdom said that he saw increased lobbying as necessary, complementing the work carried out in the field through development projects. He pointed out that Southern NGOs had themselves requested their Northern partners to pressurise European governments in the hope that the latter would adopt external policies more favourable to the developing world. Mr Rutherford also raised the thorny question of structural adjustment. The view that adjustment policies were not succeeding in eradicating poverty, had, he said, been acknowledged by the EU's Development Council in its resolution adopted in June 1995. With this in mind, the NGOs would be raising the issue with the World Bank and the IMF - where the EU Member States are among the most substantial contributors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guido Barbera, who headed the Italian delegation to the Assembly, took up this point, calling for more pressure to be exerted on the Bretton Woods institutions by European NGOs and indeed, by the European Commission itself. This was necessary, he believed, to promote coherent macroeconomic policies favouring the development of economic relationships with the less-developed countries. In more general terms, Mr Barbera applauded the growing NGO participation in the political arena, stating that this was both 'positive' and fundamental'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Evaluation of the Liaison</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Committee's work</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A document was presented to the Conference by the NGDO-EU Liaison Committee containing an evaluation of its activities. The aim, in drawing up the document, was to 'review and critically assess the work and organization of the Committee, and evaluate whether it meets the expectations of its stake holders.' In order to do this, NGO members were consulted through questionnaires.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The evaluation revealed that support for the Liaison Committee as the representative umbrella organization of European NGOs remains strong, although there is widespread uncertainty about the future. This is reflected in the perception that the Committee has   gradually been losing momentum. There were also some doubts expressed about its representativeness. Large NGOs, it was noted, were able to spread their efforts across different networks. The fact that small NGOs tended not to be involved in the Committee emerged as one of the critical issues for discussion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Attention was also focused on the alleged weakness of many national platforms (the documents containing proposals drawn up by the various national NGO assemblies) in representing the aspirations of their member organizations. This issue, and the question of voting on resolutions without debating the documents in question gave rise to controversy. Some delegates boycotted the vote while others submitted a written protest and there is clearly some demand for reforms designed to make the Assembly's procedures more democratic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General conditions of cm  financing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another highly topical subject on the Assembly's agenda was the proposed revision of the General Conditions for the Co-financing of NGO </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Projects in Developing Countries. Commission speakers who touched on this subject included Professor Pinheiro and Jacob Houtman who is a Director in DG VIII Both referred to the revision process that was currently under way, and emphasised the higher priority that would be attached to capacity building for Southern NGOs. This involves providing support to strengthen the organisational structure of the bodies in question, and to improve the skills of their staff in managing and implementing projects. Such an approach is now recognised as essential for the long-term sustainability of NGO activities. As Mr Houtman was keen to stress, the principles underpinning the KU-NGO relationship (recognition of NGO independence and specificity, freedom of initiative for European NGOs in cooperation with their Southern partners) would be safeguarded in the revised conditions. Other priorities to be set out in the conditions would include the promotion </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Notice at the site of a non governmental organisation in</P>
+<P ALIGN="JUSTIFY">Zimbabwe devoted to improving agricultural productivity</P>
+<P ALIGN="JUSTIFY">'Crucial to provide more institutional support for Southem</P>
+<P ALIGN="JUSTIFY">NGOs' of democracy and human rights through reinforced structures of civil society, and a greater emphasis on the fight against poverty, income-generating activities and social development programmes. With these objectives in mind, it was all the more crucial to provide more institutional support for Southern NGOs. They, unlike their Northern partners, had a permanent presence in society in the developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The revised general conditions would also reflect the new orientation which favours a long-term programme approach over the traditional project by-project method. This should lead to a reduced administrative burden, and benefit long-standing NGO partners who have demonstrated viable approaches in working with their Southern counterparts, as well as good management and accountability.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'A Europe open to the world'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Conference which took place following the NGO General Assembly focused on assessing the coherence of different EU policies and on ways of achieving coherence where it might be lacking. As the title of the Conference suggests, the question which was never far from participants' minds was 'what sort of Europe is being created.' Is it a Europe which stands in solidarity with the South (and East), or is it one which retreats into its fortress, concerned only with its own prosperity ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the outset, EU policy - or rather its mode of implementation - came in for criticism. It was claimed, on the bask of the experience of both European and Southern NGOs, that the principles of development cooperation set out in the Maastricht Treaty (Title XVII) were not being applied universally and consistently. These principles include the sustainable economic and social development of developing countries, their integration into the world economy, the fight against poverty, and the development and consolidation of democracy, human rights and the rule of law.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this connection, three specific discussion topics were selected: the EU's common foreign and security policy (CFSP), its common commercial and agriculture policies (CCP and CAP) and its immigration and asylum policy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Regarding the first of these, it was suggested that the EU's definition of 'security' tended to be viewed solely in terms of common defence, and that the concept of 'human security' drawn up by the UNDP had been neglected. The latter seeks to define the concept on a broader basis including aspects such as equitable and sustainable development, as well as human rights and democracy. The view was also expressed that a more firm and coordinated CFSP was needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the second topic - trade and agriculture - there was a strong feeling that the policies of the EU (and the USA) were heavily weighted in favour of 'home' producers and that this had the effect of undermining local production and food security in the</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Developing countries. The Union was urged to remove the policy 'contradictions' that allowed this situation to arise bearing in mind the specificity and sensitivity of the food trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, several speakers were highly critical of what they viewed as negative trends in the approach to immigration and asylum adopted by the EU and its Member States, with increasingly strict rules being implemented. There were also calls for measures designed to integrate resident migrants into society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indeed, integration may well be seen as the key message to have emerged from the NGOs' gathering. The call was for the people and governments of the European Union, acting in the Intergovernmental Conference (IGC), to integrate the needs of the rest of the world's people into their actions and programmes. The talk was of common values of human rights and solidarity, in both internal and external polices. And it was clear from the commitment of those who attended that the NGOs are determined to maintain and strengthen their role - as active partners in the development of the South, as advocates for the developing countries and perhaps indeed as keepers of the European conscience.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.A.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Workshops</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As part of the proceedings of the NGO General Assembly, three workshops were organised dealing with specific themes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Workshop 1 was entitled Beyond Lom&eacute; IV. There was a general consensus among those taking part that the Convention's underlying philosophy helped to protect developing countries in today's global commercial environment. Without the Lom&eacute; system, it was felt that the ACP countries would have suffered even more from the deterioration in their terms of trade. With this in mind, the World Trade Organisation came in for criticism for its stance against regional preferential agreements (even if this does not apply to the least developed countries).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The major finding of Workshop 2, which dealt with Poverty in the North and the South, was that  poverty is the result of interactions at a global level - and is not 'nation specific'. It was therefore important to adopt a global approach in  seeking to tackle the causes of poverty, and to develop further North-South exchanges of experience for the benefit of both sides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The third workshop was devoted to making the most of EU Presidencies. Here, the aim was to evaluate past experience of lobbying undertaken by the NGO community in those countries holding the EC Council Presidency, during the six-month period in question. The main recommendation to emerge was that more needed to be done in establishing contacts and exchanging information between the relevant national NGO communities. Such exchanges, it was felt, were needed before, during and after the six month Presidency period, in order to facilitate continuity of lobbying on key themes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Resolutions </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Resolutions adopted by the NGO General Assembly, considerable emphasis was placed on human rights</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> issues, with texts being agreed on Nigeria, the peoples of the Western</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sahara and the child sex 'industry'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade (in the widest sense of the word) also featured prominently. In addition to a general resolution on world trade, representatives passed motions on the arms trade, traffic in landmines and the production of the drug coca.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Also adopted were resolutions on preventive diplomacy, cooperation with Cuba, the Euro-Mediterranean partnership and the 'deterioration' of the situation in the Great Lakes region of Africa. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Africans seek bigger share of tourist dollar</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Godfrey Karoro</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe's government is under pressure to encourage greater African involvement in the predominantly white-run tourism industry, which is facing intense competition from neighbouring South Africa. 'Black participation in all sectors of tourism is a priority,' says Environment and Tourism Minister Chen Chimutengwende. 'Blacks have waited in the wings long enough,' he adds, 'and their entry on to centre stage is inevitable. The solution lies in nurturing black entrepreneurship and giving it the material and technical backup to ensure its growth.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Only 38 of the country's 436 tour operators are indigenous, and most focus on provision of goods and services, particularly transport. African interest in the business was kindled last year when the government identified tourism as one of the sectors which could benefit from an international $74 million credit facility. This prompted enquiries from  about 500 potential entrepreneurs. Interest was heightened during the election campaign earlier this year, when President Mugabe's government made an issue of the continuing economic domination of the white community which constitutes  less than 1% of the country's 11 million population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Chimutengwende pledged support for greater black participation, but the government itself is under fire for not doing enough. 'We have a time-bomb and the government should do something about it quickly before it explodes,' says Colin Blythe-Wood, managing director of a tour company and chairman of the Zimbabwe Association of Tour and Safari Operators (ZATSO), referring to the black-white imbalance in the whole economy. 'We are indeed fortunate that this industry, which has perhaps the greatest potential in our economy, is still in its infancy,' he says. He argues that the government holds the trump card, through its ownership of vast tracts of land in national parks, forests and communal areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A 1994 Zatso report identified more than 100 sites on state-owned land suitable for development by African tourism ventures. At least half, says Mr Blythe-Wood, were in areas of abundant wildlife, including the 'big five' - elephant, lion, rhinoceros, hippopotamus and buffalo. Other opportunities could be provided he suggests, if the National Park service got out of the accommodation business and concentrated on flora and fauna conservation. 'The government cannot be a referee and a player at the same time. It should sell off its shares in the Rainbow Tourism Group' - a wholly-owned government company which is the third largest operator in the tourism sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the industry's problems is that South Africa, too, has found tourism to be an unexpectedly good economic performer. Arrivals there rose by 50% in 1995, and a new government discussion document suggests that tourism could double its foreign exchange earnings by the year 2000 and triple its contribution to national income. South Africa's parks and beaches are well developed, but entrepreneurs are also fostering attractions such as Boer War battle sites and 'Road to Freedom' tours in which visitors have breakfast with former freedom fighters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fear is that South Africa will be the regional hub for visitors, siphonino off  most of the earnings, with</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zimbabwe merely getting the overspill from short side-trips.</P>
+<P ALIGN="JUSTIFY">Zatso chief executive, Elias Nyakuni, points out that South</P>
+<P ALIGN="JUSTIFY">Africa is already using Zimbabwe's top attraction to lure visitors, urging them 'to come to South Africa to see the</P>
+<P ALIGN="JUSTIFY">Victoria Falls'! Efficient train, luxury bus and air services connect several South African cities to the Falls, which are on the Zimbabwe-Zambia border. Mr Nyakuni says that Zimbabwe  could also lose out if things go wrong in their southern neighbour. 'Violence in South Africa could deter people from coming to Zimbabwe.' He accuses the government of not taking marketing in Europe and North America sufficiently seriously. 'The 4-5% annual growth is, in essence, through word of mouth. We need to investt more in marketing.' He says that the Zimbabwe Council for Tourism is underfunded and that it operates 'without brochures or pamphlets.' Neverthelms,  with 1.25 million visitors last year spending $252m (up from 1.04m spending $203m in 1994) - tourism is a growth area in which black people could take a bigger share - and not just, as at present, as guides, drivers, mechanics and cooks.</P>
+<P ALIGN="JUSTIFY">Lovemore Chihota, who runs a booming Victoria Falls safari business, has shown the way. He admits that there is a lot of money to be made from tourism, but warns that careful preparation is needed, as well as determination, commitment and, a realisation that there are no quick returns. He also points to the need to have some equity. 'The promoter,' he stresses, 'must put his money where his mouth is.'</P>
+<P ALIGN="JUSTIFY"> G.K.</P>
+<P ALIGN="JUSTIFY"> </P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Culture and society</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Dak'Art 96</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most important exhibitions of African art, the Biennial Festival of Conternporary African Art, opened its doors to the public in Dakar, Senegal, on 8 May 1996. The 'Pan-African Art Exhibition', as it is still called, was being staged for the third time although it almost failed to take place at all, having been postponed several times over the last four years. All those who participated - from the artists who exhibited to the directors of art galleries and cultural  institions - were pleasantly surprised. The next edition of me Courier will include a more comprehensive account of the exhibition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">President Abdou Diouf of Senegal inaugurated the event at the Daniel Sorano National Theatre in the company of a number of VlPs, including BartoLom&eacute; Amat Armengol who represented the European Commission. The Commission was Dak'Art 96's main financial partner providing support to the tune of CFAF 200 million (ECU 300 000 approx). The Biennial Festival aims to be a showcase for African artists allowing them to break into the international plastic arts market. Hitherto, this has remained relatively closed to them despite the general recognition that Africa has a contribution to make to the art world in this area. Mr Ousmane Sow Huchard, chairman of the Festival's scientific board, stressed that success lay first in stimulating the art market in Africa itself. He gave the example of his own country which had voted the so-called '1 % law', which stipulated the proportion of works of art that should be used to decorate all new public buildings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Festival's main exhibition, at the Ifan Museum of African Arts, was devoted to major trends in African sculpture. 42 artists selected by an international panel took part and, despite some criticism, their choice was a  judicious one. The same cannot be said, unfortunately, of the second major exhibition, at the National Art Gallery. This was devoted to contemporary Senegalese art and the skill involved in producing the exhibits was not of a consistently high standard.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were also five individual exhibitions featuring artists chosen by internationally famous judges. These might be expected to have a dynamic effect in setting standards on the market. Zeribun Yempeta of Ethiopia offered a quite original style, working on a support of leather straps fastened to a trellis of fine strips of wood. He draws his inspiration from a combination of African design, Coptic and Greek influences, and ancient Egyptian art. Ethiopian painting was one of the major revelations of the 'Africa 95' exhibition in London last year and the Festival gave a further opportunity for such art to be displayed. Another display presented work by the Moroccan painter, Mohamed Kacimi, whose pictures have been hung in various exhibitions - although the term 'pictures' is not always appropriate to this artist's work. It is perhaps more fitting to say that he 'occupies space'. In Dakar, he covered three walls of a large room with 'rolling art'. His skill, particularly in monumental works, is to offer excitement and calm simultaneously, through the use of animated forms and soft, rhythmic harmonies. Ezrom Legae of South Africa, Moustapha Dime of Senegal and Pascale Martine Tayou of Cameroon were the three other artists granted individual exhibitions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the trends which came to the fore at Dak'Art was the use of alternative media and recycled material. The latter, in a sense, is the man in the street's legacy to art. Initially, recycling was used predominantly in the informal sector to produce utilitarian objects. The 'Biennial Festival Village' was set aside for informal sculptors, and in an open area beside the Village, both inside a marquee and outdoors, one of the most individually striking exhibitions was presented. This combined a variety of artistic forms ranging from painting to video, not to mention Adeagbo's unusual montages, including 'African artists and AIDS'. This had already been exhibited in a number of countries and was staged by the Revue Noire team in parallel with its 'AIDS' issue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Festival included dozens of on-site exhibitions as well as all the 'fringe' presentations. The AIDS exhibition was one of the boldest but the display entitled 'Love' offered the greatest degree of unity and uniformity of design. Dak'Art 96 also made an attempt to integrate other forms of creativity such as dance, design and fashion. The latter two, for example, were presented at the Espace Vema, a fine metal structure where the creations of the Senegalese designer Claire Kane were in perfect harmony with the highly original furnishings. The European Union's prize for creativity, one of the Festival's four major prizes, was awarded to Vincent Namien, a designer from Cote d'lvoire.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hege'Goueier</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">On creativity... in Africa and elsewhere</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> by Alain Nicolas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author of this article is head curator and director of the Museum of African, Oceanic and Amerindian Arts in Marseilles. Here he offers his thoughts on the (partially unconscious) reluctance of the 'official' art world in the West - museums, critics and art historians - to accept contemporary African artists. Even now, they tend to be relegated to the sphere of 'alternative' art. However, he believes that the abundance of creative Africans, and the pressure they are exerting on the art world and market will, sooner or later, generate a 'new revolution' in the museums. This iswhat happened in the early20th century when traditional African art first arrived in the West. This article is linked to the dossier on African creativity published in our previous issue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When I was asked to make this small contribution on African creativity, I was happy to oblige since, as a non-specialist, I am able to content myself with a few generalisations. I believe that there are still barriers, sometime not very visible, but nonetheless real, which have to be broken down.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, writing just a few lines on creativity is a difficult exercise given the amount of literature on the subject and so many divergent opinions. So, what line should I adopt? About 15 years ago - in the wake of hordes of specialists in the humanities from sociology, psychology, ethnology, anthropology and so on - a rational approach, known as 'the anthropology of art', was at last proposed. The term 'rational' should be seen here in the context of the distinction between exact or 'hard' sciences such as mathematics, physics and astronomy, and the humanities, which are essentially inexact or 'soft' disciplines. And in brief, the West tends to take a scientific approach, relying on empirical evidence, even when it seeks to study such subjects as human creativity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Creativity obviously is to be found in many different spheres. It is needed in technology, it is fundamental to story-telling, it underpins all forms of social organisation and has a part to play in religion. Similarly, what we term 'art'  is one of the spheres of creative endeavour. The anthropology of art seeks to document artistic creativity and to analyse the conditions surrounding its expression in various cultures. This is a laudable enterprise insofar as art is regarded as another means of expression, used in one form or another by all human groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The creative function is universal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The basic postulate is that any society - and any individual - possesses creative potential which may be expressed in any way. The first thing to examine, therefore, is the context of choice. There are various modes of artistic expression ranging from music, poetry, prose and dance to architecture, painting and fashion. Some individuals or societies may have no choice, perhaps because of socio-economic constraints. Others may favour a particular mode of expression while nonetheless dabbling in more than one area. The expression of creativity is, therefore, like an identifying mark, claimed by the group or by the individual. The concept of 'style' now comes into play. The expression of one group is different from that of another and no two can ever be the same. Fundamental elements are at work in this materialisation of creativity. Some  are due to the natural environment. Thus, for example, a society located in a place where wood is abundant may favour sculpture. Others come from the group or individual themselves. And in the final analysis, it is the groups or individuals that decide what to portray (or not) on the basis of their own social norms and what they want to express.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These few limited thoughts should be supplemented by the observation that sculpture or the plastic arts more generally can also be examined from at least two angles: as a means of conveying information, and as a form of linguistic expression.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As regards the former, some have proposed analysing any work of art, from whatever culture, as a message. Analysis of the work therefore includes an examination of the conditions surrounding the production and transmission of the message. What message is broadcast ? How does it function ? What does the addressee gain from it? This approach is fine in hypothetical terms but does not allow one to go beyond theoretical and formal data, teaching us nothing about the content of the message under study. It refers back to the originator who holds the keys to the way in which it was sent and thus to its form and meaning.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Linguistically speaking, we assume that all expression through sculpture is a language and that the techniques for studying language can therefore be applied to the work of art. This approach is more rewarding because it brings us closer both to the sources and to the function of communication.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Be that as it may, all methods involve knowledge of the group or of the individual (but also of the relationships between them) and thus of any organised knowledge. Art cannot be separated from perception. This is the position of the majority of scientists. Yet we are not completely certain of this. Briefly, we are led to imagine that art could be irreducible at a certain level. When we look at a sculpture or listen to a piece of music, aside from the emotional content which is at least   partly quantifiable, what are we able to understand about the culture which produced them ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Having travelled widely throughout the world and kept my eyes open, without having become the 'observer-participant' which the ethnologist should be, I am certain that the same creative function can be seen everywhere, and it is not difficult to identify.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Frequent visits to the world's museums and, perhaps above all, to their vaults, further reinforces the impression that constants do exist and are worthy of more and better investigation. Art, and more particularly the art of others, from other continents, is still the domain of a happy few.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are usually highly literate people, and are seldom activists expounding a cause.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contemporary African art must find its niche</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The above statements relate as much to contemporary art as to what we term 'traditional' art. How many of the world's museums really show contemporary art from Africa ? It is as if this sector were cut off from current cultural reality. This is despite the fact that each week, new artists, musicians, designers, painters, sculptors, dancers, film-makers, stylists and photographers emerge from Africa, to be 'recognised' in the West (if anyone knows what 'recognition' really means!). The museums are, in fact, confused by this burgeoning of talent because they have no idea how to manage it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It has been said that contemporary African art is an urban phenomenon aimed at those living in towns and cities - and that it rebels against essentially rural, traditional art.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The argument is that the usual methods for analysing traditional art cannot be fully mobilised because 'urban civilisation' conforms to a set of universal norms (more or less), which are distinct from those studied by ethnologists. It would, therefore, be more appropriate to consider contemporary art in the context of sociology and aesthetics. This may be true, but it still comes down to a matter of observation. Confusion reigns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When we staged an exhibition in Marseilles by the Senegalese sculptor, Ousmane Sow, the first individual showing of his works came as a major shock to many people, including the specialists. I can remember the reactions of at least   two colleagues from museums of contemporary art. What they said was almost identical, and was along the following lines:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What's the name of this sculptor ? I am not familiar with him...</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A N. Do you like his work ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yes, I do, but what's his name ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.N. Ousmane Sow </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· I don't know him. Astonishing! Where's he from ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A N. Senegal - he lives in Dakar. Are you interested in his sculptures ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yes, but..</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A N. You can buy one of his works - he's not very expensive yet and it would be good for your museum. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The problem is he's African.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AN. I see... </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· His works are more your sphere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.N. But they don't have anything to do with traditional art which is what I have in my museum. Ousmane Sow is a contemporary artist, isn't he ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yes, but he's African, and your museum is a museum of African art.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A N. You're correct, I would love to buy one of his works. But it would be the only example of contemporary art in my museum and would represent a change of policy for me. You wouldn't have anything by Ousmane Sow. And we would then be rivals! </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Critics, artists and art historians have begun discussing contemporary African art, more and more good reviews of it are being published, talks are being given and some major exhibitions have been mounted. There are pioneers and supporters in France, Germany and elsewhere, and there is even a great museum - Washington's Smithsonian - which took it on board several years  ago - but we still seem to be a long way from a commitment from most institutions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I hope this statement will soon be proved wrong. Institutions do not like taking risks. Either they create 'ghettos' ('let's set up a museum of contemporary African art'), or they set up committees to consider the subject. It is up to us to set our houses in order, but we must not be too naive. This is the art market, after</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although we tend to cling to this somewhat short-sighted administrative view that there should be different institutions depending on whether we are dealing with heritage or contemporary creativity, museums of contemporary art must integrate all the world's sculptural expression. If not, they will be in conflict with the above; postulate which claims that creative  potential is the same everywhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for so-called museums of anthropology and also a few rare museums such as the Museum of African, Oceanic and Amerindian Art in Marseilles, the systematic exhibition of contemporary art does generate a number of problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When I have wanted to do this in the past, I have been reminded of the 'museographic landscape' and advised to consult the authorities, to organise a major debate on the topic: who, what, where ? That is the rational approach, we are told. There is no great hurry!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact, the recent arrival of African artists comes at a moment in our history when we are questioning the existence of our museums. When I say 'we', I mean the West in general.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So, what might happen ? Traditional African art caused an explosion in Western art and traditional art history at the very beginning of the 20th century, with the cubists and their research which led them to develop a passion for African sculpture. We are all aware of what we owe to Africa and its traditional artists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Contemporary art from Africa is knocking on the closed door of Western museums, but the arrival of contemporary African artists and the pressure they exert on the art world and  market might trigger a new revolution in the museums, which are also the archives. Certainly, all the usual followers are ready to take up the cause, and that is how it should be. Let's be optimistic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A.N. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The works of Ainsley Yearwood: Bombarded with colour</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Claude Smets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ainsley Yearwood is a Trinity dadian artist based in London. me Courier had the opportunity to meet him recently when an exhibition of his works was staged at his country's embassy in Brussels. Brought up in Trinidad, he moved to London to study fine arts at the Chelsea Art School. Feeling unable to express himself fully in this discipline, he ended up taking a degree in graphic design. Mr Yearwood is still based in the UK capital where, in addition to his work as a painter, he also designs costumes for the Notting Hill Carnival, a cousin of the famous Trinidad Carnival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The artist is fortunate to be able to live from his work. Besides the present exhibition which is touring Europe (Manchester, Brussels, Geneva and London), he has other works currently on show at three galleries in the US. He finds that the reaction of the American public is different from the European one. Americans, he believes, are more spontaneous and openminded. 'Europeans tend to stick more to things they already know; to which they are more accustomed.' The titles he gives to his art pieces are for him 'a basis for artistic conversation' with his audience. They express his emotions, feelings, and thoughts, but do not try to impose a specific interpretation of the painting on the viewer. Ainslie Yearwood dislikes the idea of being labelled or categorised - or as he describes it, 'to  be put into a box'. As such, he rebels against people who try to make him conform.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A world citizen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although Ainsley Yearwood recognises his African roots within Trinidadian society, he sees himself as 'a world citizen'. The influences in his paintings are many and varied - deriving from the multicultural background of Trinidad and Tobago, European art and graphic design, the memories of his own childhood and his recent experiences. 'I am like a sponge', he says. 'Everything influences me in my work... people, places and all that I see around me. They help me to view things from a different perspective.' These all then flow together to be visualised through his 'inner eye' (expressed, for example, by two blue dots in his work In the Company of Nature which represents the Grand Canyon). By paying particular attention to what he sees, his 'visual view' is transformed into an 'emotional view'. Thus, for example, his painting Evolution appears to be a landscape. A :loser look reveals that the rocks are in the shape of hands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The artist also uses symbols in dome of his work, as a personal means 'or him to express life. The butterfly :rapped in a jar, for example, in Love lost, is a symbol of the fragility of life. The glass of water in Soul of a Mother symbolises the way a child looks at the world as something exciting and new. he also draws strongly on the imagery of candles, inner eyes and doorways.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Strong colours, strong emotions</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What unifies Mr. Yearwood's work, is his use of colours. As he says, they are 'strong colours to express strong emotions'. In this, he has been inspired by his childhood in Trinidad which, in his own words, 'was an environment that constantly bombarded you with colour - from crystal to aquamarine, sapphire and emerald - a perpetual rainbow of red, yellow, green and blue'. One painting where colour is used to striking effect is Carnival Bacchanal. This depicts Trinidad's Carnival and reflects both the island's multicultural society and its vividness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ainsley Yearwood has also produced more surrealist and psycho-biographical works, under the influence of artists such as Salvador Dali and Francis Bacon. Emotions are revealed through the use of darker though still vivid colours. These works (such as Evolution, </P>
+<P ALIGN="JUSTIFY">Translucent State and Suspended in Limbo) show a fragmented self, stuck between past, present and future, looking for a way forward. They come in stark contrast to the brighter mood of paintings of island scenes - which are in a more African style - or of jazz musicians (such as Soul of a City or The Musician). According to the artist, this is being realistic. If he wants to paint life, he must show the different and contrasting emotions a human being experiences. 'You get up in the morning and you are feeling a little bit happy. You come home in the evening and you are feeling a little bit down. So emotions are continuously changing. If I said that I was always happy, that wouldn't be true.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As mentioned above, a number of Ainsley Yearwood's pieces portray jazz players. He enjoys going to New Orleans to listen to jazz bands and in Soul of a City he portrays one of the musicians. The title underlaines the importance of performers in a place like New Orleans - where indeed, they form an integral part of city life. In A Musical Love affair, the painter uses techniques learned as a graphic designer to help him express his feelings. By drawing graphic lines, the cello player and the instrument flow into one another. He explains: 'The cello player was not just playing the instrument. She was actually part of it. It is as if she were making love to the cello.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is clear from the foregoing that Mr. Yearwood's art is primarily visual. The onlooker is bombarded with strong colours - which are used, together with abstraction and symbolism, to express both optimistic and pessimistic feelings. The artist uses his multicultural background to great effect, drawing on influences from Trinidad, Africa and Europe, to create different modes of expression. These are the essential factors which make his paintings interesting and refreshing to look at.  c.s. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">CTA-Bulletin</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Fairness on the livestock field of play</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Sarah Reynolds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the town of Thies one of Senegal's regional capitals, there is an abattoir where nothing goes to waste. Even the horns of cattle are sold for making carvings for sale to tourists while the tips of the horns are exported to Japan. In a rural area of Chad, small-scale livestock farmers are preserving meat by the age-old process of cutting it into strips and drying it in the sun. Careful attention to hygiene and quality control has resulted in a product so consistently good that it has found an export market as far away as Gabon. Livestock producers in sub-Saharan Africa are responding to market opportunities, not because they recognise the need to improve national food requirements, but in pursuit of profit. Therein lies the best chance for stimulating the livestock sector's production capacity. The challenge is to design policies that protect consumers without crushing entrepreneurial potential for producers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than half the population of sub-Saharan Africa is likely to be living in a town or city within the next 30 years. These city dwellers will have neither the skill, the time nor the space to raise livestock. There are indications on present trends that their demand for food of animal origin will increase. Where will they get it from ? Imported meat is more expensive than it used to be, largely as a result of the change in policies of the European Union. These have also affected the supply of low-cost milk powder and butter oil. Imports from countries outside the continent will  undoubtedly continue but intra-African   trade and local production will become   far more significant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It has been estimated that the production of animal products in sub-Saharan Africa would have to increase by 4% per year to ensure an adequate supply of animal protein for the region's growing population, and to end the need for imports. This presents a major challenge to policy-makers. Already, the current pressure on land resources is causing conflict in some areas and the prospect of more people, more animals, and more strain on already inadequate resources, is perturbing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Information vacuum  in developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The concept of value</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Decisions on how to achieve sustainable and yet more productive land-use, while at the same time ensuring fair access to resources for other interested users, cannot be soundly based if made in an information vacuum. It was in recognition of the lack of information about the livestock sector that the CTA organised and sponsored a seminar on Livestock development policies in the humid and sub-humid zones of sub-Saharan Africa. This was held in Abidjan, Cote d'lvoire on 5-9 February 1996. It was attended by participants from 17 countries within the region and by representatives from international institutions and from Europe. The objective was to contribute to the ongoing debate on policies aimed at bringing about sustainable livestock development while respecting natural resources in developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The concept of value</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Effective planning of government action on issues such as import policy, provision of inputs and services, marketing and research priorities requires quantitative information on livestock production systems. Why is this information lacking when it is estimated that livestock products contribute about 25% of total agricultural GDP in subSaharan Africa? The livestock sector is too important to ignore and yet it is consistently undervalued. The reason is that economists and statisticians like to deal with a tangible unit that can be counted. Ideally, this should be a monetary unit but, failing that, it should at least be a unit that can be easily converted to money, such as the number of animals potentially available to the market. But if animals are used to sustain a traditional way of life, for people who do not have to pay before they can eat, it is difficult to put a monetary value on the food they consume. Similarly, if a herd of animals is sustained by forage that has no other use, on land that can be used for no other purpose, the cost of feeding cannot easily be measured in financial terms. Indeed producers have little to gain from allowing government   departments to acquire information about their assets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Livestock owners have their own objectives when deciding whether and how to increase production. Livestock provide energy in the form of draught power, and dung for fuel or biogas. Their manure restores structure and fertility to the soil. Social prestige may be measured in the quantity and quality of the animals one possesses. For some livestock owners, their animals are their 'barking' system. They represent a deposit account for accumulated wealth and a current account when an animal is sold to raise cash. Indeed it may be impossible to obtain credit from an orthodox bank. There is an added advantage in that there are no interest charges to pay when you raise cash by selling your own animals as opposed to taking out a loan from a bank. It may be difficult to measure real production when animals are treated as a capital reserve. For example, an increase in meat prices, perhaps as a response to a change in economic policy, may result in a short-term reduction rather than increase, in the number of animals being marketed. This is because producers are able to maintain their income by selling fewer animals and can simultaneously  increase their breeding herds. Alternatively, there may be little incentive to producers to sell more animals if they have no use for the extra money they earn. It is of course true that more people are joining the cash economy as they become aware of the desirability of consumer goods, or of services such as schooling. Governments may aspire to design policies which will develop the livestock sector for the economic welfare of society as a whole, but if these policies ignore the objectives of livestock owners, they will fail.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fair play</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a football match, the referee is there to see fair play. In the livestock sector, governments have to ensure fair play between the 'demand team' and the 'supply team', in other words the -consumers and the producers. Governments often make two mistakes. Either they help one team at the expense of the other, or else they join in the game themselves. The role of the authorities should be to make the rules that protect both teams from unfair or unsafe practices. For example, health and hygiene regulations must be in place, and  enforced, but not be so onerous that illegal and totally unregulated marketing channels are established.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Private traders have considerable power to manipulate markets if they collude to form cartels and prevent outsiders from entering their ring. Governments should ensure that this is not allowed to happen, that markets are open and that traders are free to operate provided that they observe health and hygiene regulations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Veterinary services</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most countries are no longer able to supply even minimum standards of veterinary support to their livestock producers. The efforts that have been made in recent years have been largely in the form of donor-funded projects where continuity is rarely guaranteed. The only viable alternative seems to be to transfer activities of this kind to service providers in the private sector. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The work that they do under contract to the government, for example relating to the control of epidemic diseases, must be funded by government or other central agencies since cost-recovery from individual livestock owners is not feasible when participation has to be compulsory. The work that they do on behalf of individuals, or associations of livestock owners, should, however, be paid for by those who benefit directly from the increased productivity that should result - the farmers. The greatest difficulty lies in managing what will be a long and difficult transition period. The success of ventures to privatise veterinary services depends on whether the profession can deliver a decent living in the private sector, particularly in rural areas where the need is undoubtedly greatest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rural development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is in the rural areas that livestock production needs to be intensified. On the outskirts of Africa's major cities, intensive pig and poultry production is already being supported by commercial, joint venture capital. Dairy units, in which exotic, high performance cattle breeds are managed in a controlled environment, are producing fresh milk for cash-paying consumers in nearby towns and cities. Urban areas create the demand but it is the rural areas that need the development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Animal products are seasonal and prices fluctuate accordingly. However, consumers are more likely to develop the habit of using products that are consistently available at stable prices. Government intervention to stabilise  prices risks favouring the consumer at the expense of the producer. For example, if imports are used to counter temporarily high prices during periods of drought, then producers will receive less for their reduced output at the very time when they need support. The most effective policy of price stabilization is to encourage the adoption of production systems that are less vulnerable to seasonal changes. Processing achieves this to some degree and brings benefits to both producers and consumers. Furthermore, because animal products are perishable, and dangerous to human health when they deteriorate, processing extends storage life, and may even have an effect in improving food security.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most countries, the time of greatest food shortage is at the beginning of the rainy season. This is also the time when milk production soars because cattle have good feed; and yet much of that milk is wasted because there is more than required for home consumption. If that surplus milk can be fumed into cheese, potential customers in more distant markets may be reached. Provided that the product is acceptable to the consumer, cheese-making reduces wastage, diversifies the producer's source of income and may also provide employment, and therefore income, to those brought in to help with the production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A technology that has been exhaustively tested by FAO for its suitability for use in Africa is lactoperoxydase. This is an enzyme which extends by three hours the length of time before milk begins to curdle and clot. This effectively doubles the time available for milk to reach the cooling centre, and thereby extends the catchment areas for producers wishing to supply fresh milk to urban markets. The trials that have been conducted show that it is entirely safe. When milk is brought to rural collecting points, it is the responsibility of the cooling centre employee, not the farmer, to add the enzyme at the prescribed rate as the milk is transferred into cans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On current trends, it seems probable that there will be more than 20 capital cities in Africa that have a population of 10 million people by the year 2010. How many other cities and towns will have developed by that time ? There are so many people migrating to the urban areas, and they are doing so because the type of activities that ought to be taking place in the countryside do not exist. If the livestock industry, both primary production and processing, can be encouraged in rural areas, and if the infrastructure is in place to ensure that animal products, in whatever form, can reach urban markets, rural dwellers will find it more comfortable to stay where they are rather than going to the cities to look for jobs that do not exist.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The challenge for policy-makers is to deal even-handedly, not only in the interests of the livestock sector, but in the interests of other farmers, consumers, the national economy and the long-term sustainability of the nation's natural resources. For this task, reliable information, which is accessible to all countries within the region, is essential. The database structure of this information should be standardised so that it can form the basis of regional cooperation on trade and the sustainable use of land resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S.R. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The Couriers Mailbag</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WCL seeks a wider  expression views</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We refer to the article published by The Courier in issue no 156 (March-April 1996) entitled The changing face of trade unionism in Africa, which reflects the views of the ICFTU (AFRO) and OATUU.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We are surprised that you have not taken pains to solicit the views of the World Confederation of Labour (WCL) and its regional organisation, the Democratic Organisation of African Workers Trade Unions (DOAWTU) - which participated on the same footing as the two other trade union organisations at the ACP-KU Social Partners meeting in December last year. We strongly believe this omission on your part should be corrected in future in order to allow a wider expression of the views and stands of all representative trade unions in Africa on such important issues as structural adjustment programmes, the social clause, labour standards and working conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Carlos L. Custer, Secretary-General, World Confederation of Labour, Brussels, Belgium</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Linked destinies</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The continuing dialogue between the ACP and EC Groups has exposed many mutual concerns about world affairs and has promoted a more complete understanding of the problems of both advanced and developing  nations. I am confident that in the future, we shall see further progress in our efforts to create a favourable financial climate for the resolution of our economic problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Global political and economic events have brought home to all of us how inextricably our social and economic destinies are linked. This is true of a whole range of subjects from human rights and political reform to economic development, conservation, health education and industrial promotion. None of these subjects can be put into independent boxes. We must seek more effective integration of our social and economic policies - both internally and internationally - if we are to serve the welfare of the people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I rejoice in your initiative in publishing The Courier. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Teddyiniovo, International institute for Global Cooperation, Benin City, Nigeria</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scope for energy selfsufficiency</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">May I congratulate you on the new layout of The Courier, which is a great deal clearer and which you have instituted as a result of comments made by a number of your readers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I am surprised to discover that you have not said anything about the question of energy dependence in the Lom&eacute; Convention countries. Energy self sufficiency is an extremely important issue. ACP countries face a famine in this area which is rarely mentioned. Most are majors exporters of petroleum, which is  costly and absorbs a significant proportion of their foreign exchange earnings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Practically all the Lom&eacute; countries are in a position to produce alcohol from crops such as sugar cane and manioc without any negative impact on their food resources. These crops could be distilled to produce big-ethanol which is an excellent fuel. All that is needed - and it is a major challenge admittedly - is for production to be organised in each country, and for the required national and international financing to be set up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Also required is the political will in these countries to overcome the various obstacles, including those lobbies who oppose this kind of production because they want petrol imports to be maintained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pierre Mariotte Consultant, Paris, France </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Bibliography</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jean Monnet - 1888-1979  </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Eric Roussel. Published by Fayard, Paris. 1996. 1004 pages. FFR 198.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jean Monnet was almost 91 years old when he died and, despite the fact that he had no higher education qualifications and at times did not hold any official post, his public role was legendary. From the very first page of his book, Eric Roussel stresses the fact that, from the moment Jean Monnet met the Prime Minister, Rene Viviani, in September 1914 until 9 May 1975, the day the Action Committee for a United States of Europe was dissolved, he worked constantly for the European cause.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He applied the same tireless enthusiasm to all his duties, in whatever sphere of activity he was involved - and these were many and varied. Despite his provincial origins, Jean Monnet was, among other things, a cognac merchant, an advocate of the Allied coordination effort during the First World War, Deputy Secretary General of the League of Nations (for a short time), a banker in America and China during the 1930s and in charge of the Victory Program in the USA in 1941. From 1947 to 1952, he was the first Commissioner-General of the Economic Plan in France. He and Robert Schuman were the architects of the famous Declaration of 9 May 1950 which was to form the basis of European construction. He went on to become the first President of the ECSC's High Authority and, until 1975, he was the driving force behind the Action Committee for a United States of Europe. And that is just to highlight his renowned roles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, Jean Monnet was both a visionary and a pragmatist, who was to become adviser to some of the greatest names of his day. General de Gaulle, another great visionary, albeit with a very different ideology, called him 'the inspiration' behind European integration, although such an accolade was not completely devoid of irony given that the two men could hardly be said to see eye to eye.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jean Monnet was a purveyor of new ideas, but also an eternal realist who never failed to recognise the importance of the status quo. Indeed, he could have stepped right out of the pages of a Paul Morand novel. And yet, despite the fact that he was held in the highest esteem by world political heavyweights (Clemenceau, Roosevelt, Churchill, Adenauer, de Gasperi, Brandt, Pompidou, John Kennedy, Henry Kissinger, Heath and Giscard d'Estaing, to name but a few), in his private life he was a simple man, of modest disposition - in fact a bourgeois in the best sense of the word.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A 'workaholic', like many great men, Jean Monnet defied categorization. He has recently been described as 'a man of fringe ideologies who was nevertheless always at the centre of things'. During the latter part of his life, he settled comfortably into his role as 'rather' of Europe. His fundamental thoughts on that topic could be summed up in one line from the Declaration of 9 May 1950, (now a public holiday in the European institutions). 'Europe will not be built in a day, nor as a single structure, but will come about through concrete actions which, first and foremost, create a de facto solidarity'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For Monnet, nationalism meant only war and, from 1942 onwards, he set his sights on preparing for the future, surrounding himself with a team of extraordinary talent - people such as Etienne Hirsch, Herve Alphand, Rene Mayer and Robert Marjolin. These men strove to find ways to avoid war between the countries of Western Europe, to define the objectives of European unification and to establish European institutions which would be equal to such a task.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eric Roussel is a journalist with an arts degree and a doctorate in law, and this is an outstanding work on the 'pragmatic visionary' that was Jean</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Monnet. The book is comprehensive, extremely well-written and impressively documented. Most notably, the author had access, for the first time, to the famous journal kept by Jean Monnet in which he recorded his countlles conversations with the key players and set out his own thoughts. Today, his dream of 'a united Europe complemented by a partnership with the United States' is still one of the big issues. And as the arguments rage, we should perhaps recall some other famous words from Jean Monnet's Memoires: 'We do not seek to form a coalition of States, we seek to unite men . </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alain Lacroix </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Le Choix de l'Europe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Opting for Europe)  by Laurent Cohen-Tanugi. Pub/ished by Fayard, Paris. 225 pages. FFR 110 - BFR 748.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Laurent Cohen-Tanugi successfully reminds us of the modernity of the European project; that there are aspects of it that are essential to our independence and our prosperity, to preserving our model of society and maintaining our influence on the international stage. By urging Europeans and European leaders to look to the future so as to be better able to manage the risks and seize the opportunities that it offers and, ultimately, to be in a better position to change things, he brings us all hope'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was how Jacques Delors described this book, and, basically, there you have it in a nutshell. It would, however, be worthwhile adding that 'opting for Europe' is not quite as simple as it sounds - a fact which has not escaped the attention of the author, who is a graduate of France's elite Ecole normale superieure and of the Harvard Law School. He is also a barrister and member of a renowned firm of international lawyers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since the Treaty of Rome, European progress has very often come about because Member States have set themselves deadlines for achieving particular objectives. 1996 sees the opening of the Intergovernmental Conference, an event of major importance, which is expected to continue at least until the spring of 1997 (with parliamentary elections planned in several Member States in 1997 and 1998). Among the items on the agenda for the IGC is the need to adapt the European institutions - which in essence have hardly changed since 1958 - and to open up the way for the third phase of Economic and Monetary Union in 1999 for those States which have fulfilled the economic convergence criteria set out in the Maastricht Treaty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, besides the technical and financial problems involved, there are also differences between certain Member States about the political future of Europe. The author rightly stresses, in this respect, that the situation has become even more complex since the demise of the Soviet Union. In particular, some politicians support an expansion of the EU towards Central and Eastern Europe, so as to avoid strengthening European integration. The author believes that, broadly speaking, there are two distinct positions. On the one hand, there is the United Kingdom, which would be happy with a large free trade area guided by a 'Secretariat-Commission'and with flexible and relatively loose inter-State cooperation structures at a political level. On the other hand, there is Germany, which wants expansion of the Union towards the East as well, but also wants a swift and concrete consolidation of a common monetary and political 'hard core'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In his book, the author expresses his view that France will play a vital role in maintaining and advancing the essential elements that form the basis of the European enterprise. And he nails his own colours firmly to the mast as someone who hopes to see the continent moving towards some form of federal structure. As one observer commenting   on the work has noted, 'This little Bible, brimming with faith in the concept of a unified Europe, will be invaluable - even to the doubting Thomases among us'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publications received</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Et.... qu'en pensent les villageois? Projets de developpement durable et be veins de base b&eacute;n&eacute;ficiaires</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(But... what do the villagers think about it ? Sustainable development projects and basic needs of aid recipients)  by Myriam Bacquelaine. Published by Ured (Research, Education and Development Unit) of the K.U. Brussels (17, avenue de la Liberte, B- 1080 Brussels). 1995. 3Z2 pages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Les problemes du monde rural vus par les habitants - Portraits de villages de Haute-Guinee</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(me problems of rural life as seen by the inhabitants - Profiles of villages in Upper Guinea)  by Myriam Bacquelaine. Published by Ured (Research, Education and Development Unit) of the KU. Brussels (17, avenue de la Liberte, B- 1080 Brussels). 1995. 222 pages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author, who has a PhD in educational sciences and is a researcher at Ured, has written these two works on the basis of a study she carried out on behalf of the European Commission in Guinea (Conakr,v). This aimed at identifying the most urgent priorities of village communities within the context of an environment restoration project.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The conclusion of the first book underlines research results which point to the adoption of a different approach to development at local level: one which respects the wishes of the recipients and which finally breaks free from western ethnocentrism.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the second volume, the author presents the results of the survey conducted in the villages of Upper Guinea. Six villages with varying characteristics in terms of size, geographical location and administrative status are featured in more detail. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Informations pour le Developpement: Agriculture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Information on development: Agriculture)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Published by Ibiscus (ibis, rue du Havre, F-75008 Paris) and by the Agency for Cultural and Technical Cooperation. 1995. 271 pages. FFR 150.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More than just an index, this publication is a useful working tool for anyone seeking reliable information about development in the agricultural sector. It includes a list of the main organisations specialising in agriculture in 40 French-speaking countries and a list of the principal places and means from which to obtain information (documentation centres, data banks, optical discs, CDs and on-line data services). There is also a selection of periodicals, a bibliographic section (with more than 300 references, including abstracts) and contributions by specialists relating to major topics connected with rural development: landownership systems, links between cash crops and food crops, agricultural funding, etc.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda - Trois jour qui ont fait basculer l'histoire</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Rwanda - Three days that shook history)  by Filip Reyntjens. Published by L'Harmattan (5-7, rue de l'Ecole-Polytechnique, F75005 Paris). Cahiers africains no. /6! 1995. 148 pages FFR 9O. ISBN 2-738437044.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although much has been written about the tragic events in Rwanda, this work examines an aspect of the story which is still largely a mystery: the brief period which began on 6 April with the missile attack on the presidential jet and ended on 9 April, when the 'caretaker government' was swam into office. According to the author, these 72 hours were of critical importance since it was during  this time that the country's killing machine was set in motion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Essentially based on eye-witnffs accounts, it is a tale which is far from complete. The book, however, does provide some hitherto undocumented information which allow us to delve deeper in search of the truth behind one of the darkest pages of recent human history.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Les refugies rwandais a Bukavu au Zaire - De nouveaux Palestiniens?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(The Rwandan refugees in Bukavu, Zaire - the new Palestinians ?)  by Philippe de Dorlodot Published by L'Harmattan (5-7, rue de l'Ecole-Polytechnique, F-75005 Paris) and by the Jeremie Group. 1995. 253 pages. FM 150. ISBN 2-7384-3698-6.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author has brought together various stories, appeals, communiques, analyses and thoughts to write this book about the crisis facing the Rwandan refugees. The accounts cover the period from April 1994 to October 1995 and relate to the situation in South Kivu, Zaire, where an already volatile position has been greatly exacerbated by the arrival of the refugees. The people living in the regional centres of Goma and Bukavu are having to live with the tragedy of gross overcrowding and all its consequences - environmental deterioration, price increases, general insecurity and the threat of war on the border between Rwanda and Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zaire now wants the refugees to leave as quickly as possible, but their return to Rwanda is still problematic. Rejected at every turn, are these Rwandan refugees set to become the new Palestinians? In the postscript to the work, Filip Reyntjens (the author of the book reviewed previously) states that 'These new refugees will not accept eternal exile. H voluntary repatriation is not possible, and if forced repatriation is unacceptable, the only way left open to them may be armed repatriation... The civil society of South Kivu... is well aware of this, and the international community would do well to listen to their cries of alarm... If  it does not, the tragic events of the past year will have been merely a prelude, with the worst still to come'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">La tragedie rwandaise - Historique et Perspectives</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(The Rwandan tragedy - historical background and future prospects)  by Emmanuel Nkunzumwami. Published by L'Harmaffan (5-7, rue de l'Ecole Polytechnique, F-75005 Paris). 1995. 480 pages. FFR 250. ISBN 2-7384-3697-8.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author, a teiecommunications engineer and economist, was born and raised in Rwanda. He now lives in France and has had several articles about the situation in his country published. In this work, he seeks to Reconstruct the machine of central Rwandan power which first appeared in the eleventh century, seeking answers to questions such as: Who ruled the country and how? What alliances were forged and according to what criteria? What kinds of social structure existed and what forms did conflict take? He then goes on to describe the trauma of colonial rule which 'deliberately' fanned the flames of socio-ethnic conflict so that the people could be more easily controlled. From there, he takes us through the era of an 'independent' Rwanda under a dictatorial regime. Its power was progressively stripped away, initially under the pressure of internal calls for democracy, and then by the demands of Western aid donors. Finally, he recounts the events since April 1994.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Having given the historical background, the author examines the country's future prospects. He believes that the 'siege mentality' of the new government does nothing to induce the return of the 2 million refugees who shuffle back and forth across the border and who find themselves stuck between a 'rock and a hard place'. Finally, the author poses a straightforward question - but one which has yet to be answered: How can we rebuild a country that has witnessed genocide on such a scale ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">News round-up</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In brief</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNCTAD Report on the least-developed countries (LDCs)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to the annual report of UNCTAD (The UN Conference on Trade and Development), the 48 least developed countries of the planet, after several years of stagnation - and indeed, decline in some cases - enjoyed an average growth rate of 3% in Gross Domestic Product (GDP) in 1994-95. The figure was 4.6% for LDCs in Asia and 2.2% for those in Africa (33 out 48).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNCTAD says that the renewed grovvth rate for Africa's least developed nations is due to an increase in commodity prices, to improved political and social stability in certain countries and to economic reforms which have been implemented. If these favourable conditions are maintained, further modest progress can be anticipated for 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the positive impact of these factors on the development of countries, notably in Asia, UNCTAD believes that there is still a short-term danger that the world's weakest economies will suffer further marginalisation. It is pointed out, in this context, that the LDCs' share of total world trade - which stood at 1.7% in 1970 - had fallen to 0.4% for exports and 0.7% for imports, by 1994.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the longer term it is thought that the LDCs, with their reliance on basic commodities for export receipts, may benefit from the globalization of their economies. This should happen notably through the regional trade agreements to which they are parties, alongside other developing countries. These regional markets, which are more attractive for investors, offer an opportunity for LDCs to try out their products and can, in time, help improve their competitiveness. In the  meantime, however, UNCTAD has noted that the immediate effects of the Uruguay Round have tended to be more negative, with reductions in the preferences enjoyed by LDCs in export markets and increases in the price of foodstuffs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, because they are dependent on official development aid (ODA) to finance investment, and even for their national budgets, LDCs are faced with possible further marginalisation as such aid flows are reduced. The figures show that, in terms of total resource flows, the amount of ODA provided by the Development Assistance Committee (DAC) of the OECD fell to 23% in 1994 from a figure of 27% a decade previously.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Likewise, the amount of aid, expressed as a proportion of the GDP of the donor countries, has been falling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNCTAD suggests a bolder policy as regards external debt - which, in 1994, amounted to 73% of the entire Gross Domestic Product of the LDCs. The organisation believes that the establishment of a new mechanism with sufficient resources to reduce multilateral indebtedness, combined with the expansion of existing mechanisms, could have the effect of reducing the overall debt burden to a more reasonable level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the subject of globalisation, UNCTAD argues that the international community should work to ensure that the LDCs' export markets do not become blocked by protectionist measures. It also believes that extensions to regional trade agreements, taking in the main industrialised countries, should not be allowed to have a damaging effect on the commercial interests of the LDCs. It points out that these countries have only limited scope for pursuing independent, national economic policies and that</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No agreement over banning landmines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Humanitarian organisations have expressed disappointment over the outcome of a recent United Nations conference, convened in Geneva to draw up a convention on 'Inhumane weapons). Both NGOs, and public agencies such as UNICEF, are particularly unhappy that state representatives at the meeting were unable to agree to an immediate and comprehensive ban on anti-personnel mines. These devices, which often lie hidden in the soil for many years, kill and maim thousands of civilians in current (and former) conflict areas across the globe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Diplomats attending the Geneva conference were keen to emphasise what had been achieved. So-called 'dumb' mines, which do not self-destruct after a certain time will eventually be phased out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Seif-destructing devices, which are still permitted under international law, will be subject to strict new standards, designed notably to ensure that they can be detected. And there will be new rules to ensure that minefieids are properly marked.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Critics point out that signatories to the Convention will not be obliged to phase out 'dumb' mines immediately and that their use will remain legal for a further nine years after the agreement enters into force.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is also an exception to the rule about marking the location of mines, 'where direct military action makes its impossible to comply' - a not uncommon circumstance in conflict situations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since the Geneva Conference, a number of countries, including the United States, have announced their intention to reduce their stockpiles of mines. Few nations, however, seem willing to renounce their use altogether. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">S.H.  their governments have little choice but to adopt the prevailing market oriented approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Long-term food security</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A seminar on 'Long-Term Food Security Policies' was held in Brussels on 1-3 April at the initiative of the European Commission. The meeting, which was opened by Professor Pinheiro, Commissioner with responsibility for relations with the ACP countries, brought together about a hundred participants representing Member States, third countries, international organisations and major cooperation agencies. It was also attended by experts and researchers in the field of food security.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fulfilling a promise made by the Commission, the aim of the seminar was to clarify the long term strategic issues and take a closer look at food security policies with a view to preparing a European position for the World Food Summit scheduled for Rome in November under the auspices of the UN Food and Agriculture Organisation (FAO).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Community and its Member States are the world's main donors of food aid having spent ECU 1.089 billion on this in 1994. This amounted to 53% of the global total with the United States providing 44% and Japan 3%. Despite the large amounts being given, the FAO, the International Food Policy Research Institute (IFPRI) and the World Bank are all predicting that unless global food donations are boosted significantly, certain Asian and African countries will face an alarming food deficit by the beginning of the next century.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Between 600 million and 800 million people are likely to be facing hunger by the year 2010 and the cereal needs  of the developing countries could well double between now and then.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This projected scenario coincides with a period of market difficulty. World stocks are low and grain prices have risen by 40% in just one year. Whether or not this is a portent of future food shortage, it has given rise to renewed debate on the ability of certain countries and regions of the world to supply themselves and the extent to which they will have to have recourse to the international markets. Closer attention is also being paid to the wider strategies that need to be implemented to ensure food security in the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If one looks at the issue solely in terms of increasing supply, the projections are gloomy. Experience shows that the 'right' of access to a sufficient food supply for each of the planet's inhabitants cannot be guaranteed whether through world economic growth, food self-sufficiency at the national level, or the international markets and trade liberalisation. There is, therefore, a need for food security policies, in the developing countries in particular, which act on the conditions of demand as well as supply.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In his presentation opening the seminar, Commissioner Pinheiro stressed the fact that of the ECU 7 billion allocated by the EU for development cooperation last year, ECU 1 billion was in the form of food aid. He also noted that this aid 'category' had evolved over the last decade in the context of the search for food security and explained how the Commission, in revising the policy towards the end of 1994, had set out three essential aspects:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - the use of food aid as a policy instrument designed to achieve longterm food security with the emphasis on local purchases and 'triangular' operations - thereby encouraging the growth of the agricultural sector in the developing countries: this entailed developing a new aid instrument in which funds are available to import basic food products (as a way of encouraging the private sector to  take a more active part in the economic life of those countries facing a structural food deficit);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - the integration of aid instruments into the actual development efforts of the beneficiary countries;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - improved access for the people who suffer most from food shortages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Professor Pinheiro indicated that the Commission would shortly be presenting a communication on the strengthening of the link between development aid on the one hand and emergency, rehabilitation and food aid on the other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He stressed the important role that food aid operations could play in preventing conflicts and easing social tensions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to the Commissioner, the challenge in this area have been clearly identified but he believes that additional thinking is needed, notably on the impact of events in China and the countries of the former Soviet Union, and on the effect of US and EC agricultural policies on the world markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In conclusion, Professor Pinheiro expressed the view that food security was, above all, a national responsibility with all civil society actors having a role to play.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Citing the rise in the price of cereals during the second half of 1995 - which had prompted concerns about the availability of food aid and its impact on the balance of payments (notably in sub-Saharan Africa and the Indian sub-continent) - he gave an assurance that the Commission would remain vigilant about this. At the same time, he was concerned not to see a return to situations where aid in the form of straightforward transfers of food increased. These, he observed,</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· had at least partly contributed to food costs, the destabilisation of local production and constraints on intra-regional trade. As such, they had set   back or undermined the reforms in this sector in the countries concerned.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caribbean rice exporters fear changes in OCT . rules</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guyana and Suriname, together with a number of Overseas Countries and Territories (OCTs), have expressed concern over the European Commission's recently announced intention to change the shape of its relations with the OCTs. In particular, they are worried that proposed new rules could harm their rice sales to the 15 European Union nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guyana currently exports 180 000 tonnes of rice (80% of its exports) to the KU. This is shipped initially to the Netherlands Antilles (Cura&ccedil;ao, Aruba and Bonaire) to be partially milled. It then enters the EU market duty-free by virtue of the Union's existing trade rules with the OCTs. But Caribbean exporters fear that this 'OCT route' could soon be blocked by changes currently being considered in Brussels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As already announced in issue no 157 of The Courier (May-June 1996), in the context of the mid-term review of the association with the OCTs, the Commission published a text on February 14 proposing some fine tuning to the trade preferences it grants to these territories. This has now gone forward to the Council of Ministers for decision. The Commission proposal is that while agricultural produce may continue being processed in the OCTs - and hence still benefit from the more relaxed rules - this should happen in future on a case-by-case basis, and only if priority is given to the least developed OCTs and the operations are economically justified.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact, preferential arrangements do apply to direct rice exports from Guyana and Suriname to the KU, but it is argued that the levies are still too high to make the trade viable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to Yesu Persaud, who is Chairman of Guyana's Institute of Private Enterprise; 'it is only via the OCTs that we can export to the European Union.' Mr Persaud was speaking to journalists during a lobby visit to Brussels on April 16. He was accompanied by Charles P Kennard, Chairman of the Guyana Rice Development Board and David Jessop, director of the London-based Caribbean Council for Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Justifying the need for derange, some EU officials point to evidence that non-tome developing countries are 'abusing' the OCT rice route. Rice is a sensitive product for some EU nations such as Spain and Italy, who grow their own.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Persaud said that Guyana and Suriname were lobbying either for their own duty-free quota under the Lom&eacute; trade rules, or for 'a more reasonable levy'. At the same time, however, he indicated that the Caribbean rice growers were keen on keeping the route open via the Dutch and other OCTs (such as Montserrat and the Turks and Caicos) where major investments have been made on the  strength of the existing arrangements. A representative of the Turks and Caicos told reporters that his country earned half a million dollars a year from the trade, and that a new jetty had been built with British government support.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guyana's rice exports have climbed from less than 39 000 tonnes in 1986 to more than 200 000 tonnes in 1995. And as Mr Persaud also stressed, the trade has done so well that Guyana is now investing in high-yielding varieties. </P>
+<P ALIGN="JUSTIFY">D.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fight against locusts</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fipronil, a recently developed pesticide, is said to be 10 times more effective than other products on the market in the control of locusts, according to representatives of the pharmaceutical giant, Rhone-Poulenc who organised a seminar on locust control </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Links between emergency, rehabilitation and development aid </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European commission has recently approved a communication </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> (COM(96) 153) which was due to be presented to the Development Council on 28 May. The document seeks to respond tO the challenge of I maintaining and improving the effectiveness of emergency aid  rehabilitation assistance and development cooperation with third countries - in the face of a wide variety of political, economic and social circumstances.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Communication suggests ways of strengthening the links between the three types of aid within a strategic planning framework which includes intensified dialogue and political cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This initiative follows extensive consultations, both within the Commission (i_ service groups) and with representatives of numerous outside bodies (Member State experts, USAID, UN agencies, NGOs, academic institutions etc.). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the key phrase in the Communication may be 'strategy and global planning', emphasis is also placed on 'coordination' end 'opportunity'. This underlines a commitment to adapting procedures, where necessary, so that measures can be taken at the right time and the transition from emergency aid, to rehabilitation and subsequently to development cooperation can take place in the best possible conditions.  with the 70-member African, Caribbean and Pacific group. The event took place in Brussels in April.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new product, claims the company, fills a big gap that was left in the war against locust infestation when DDT was banned in 1986 (toxic residues from the chemical having been found to enter the food chain and damage the ecosystem).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is stated that Fipronil causes 99% mortality among locusts and gives complete protection for up to three weeks when applied in doses of six grammes per hectare.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Its developers claim that it is three times cheaper than any other form of anti-locust pesticide used between 1987-1995, a calculation which includes the logistical costs involved in distributing the pesticide. It is said to be very effective in preventing locust infestations in countries in the Sahel that are particularly at risk.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Sahel has some 250 acridian species. Of these, about 15, are known regularly to attack crops in large numbers, according to Michel Launois, who heads the French agricultural research body, CIRAD-GERDAT-PRIFAS.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the Brussels seminar, emphasis was placed on the need for donors to set aside more funds for the prevention of locust infestations. It was also stressed that locust control must be at a regional level because of the migratory nature of the species, and the link between locust control and food security was underlined.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CIRAD-GERDAT-PRIFAS has just published an educational cartoon strip entitled 'Les Dents du Ciel 11' (available from Cirad-Gerdat-Prifas, B.P. 5035, F34032 Montpellier Cedex 1). This is intended to explain to a wide audience the need for an integrated approach to locust control.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I New fishing agreement between Angola and the EU</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A new fisheries agreement between Angola and the EU was initialled on 2 May. It is due to run for three years (as opposed to two years for the previous one) and should ensure greater stability and better programming of the Community fleet's fishing activities in Angolan waters. The EU will pay Angola the sum of ECU 13.35 million per annum in exchange for improved fishing rights for European fishermen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is worth noting that the agreement contains certain innovations. These concern, for example, the legal status of catches (which are given Community origin). This should help to avoid the kind of dispute that has arisen in the recent past. There is also the possibility of imposing an annual biological 'rest-period' for shrimp fishing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I African conference on consumer protection</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first African conference on consumer protection was held in Harare, Zimbabwe from 28 April to 2 May. This resulted from a joint initiative by the organization Consumers international and the United Nations, and it was supported financially by the European Commission. The latter was represented at the event by Mrs Emma Bonino, the Commissioner responsible for Consumer Policy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The aim of the conference was to lay down the basis for a genuine consumer policy in Africa. Representatives of 45 African governments attended, together with officials from various regional and sub-regional organizations and delegates from a large number of</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">African consumer bodies. Coinciding with the tenth anniversary of the adoption by the UN of the guiding principles for the protection of consumers, the Conference offered an opportunity to track progress on the application of these principles in African countries. It also saw the adoption of 'model' legislation setting out the essential rights which should be guaranteed to consumers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In her speech, Mrs Bonino stressed the Commission's commitment to supporting the efforts of African governments and consumer organisations in seeking to establish, in a clear and pragmatic way, the link between consumption and development. Evidence of this commitment, she pointed out, was to be seen in her very presence at the conference. She also lent her support to the broad application of the UN's guiding principles in Africa. This would ensure that the health, security and economic rights of African consumers could be protected.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But the European Commissioner stressed that legislation, while important, was not enough in itself to tackle the fundamental problem - which was the satisfaction of basic needs. She appealed for global action in Africa deigned to break the vicious circle of poverty - based on voluntary action at all levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mrs Bonino added that the Commission would seek ways of supporting projects, in particular in the fields of food and health. This should assist citizens to meet their essential needs - with the opportunity to consume products which were different, 'local' and of better quality, and with risks to health and security minimised. The approach should avoid the exhaustion of scarce resources and respect nature. She indicated that an action plan would be drawn up by the Commission in collaboration with Consumers International. This, it was hoped, would allow financing of pilot programmes under a separate budget line which would be sought from the European Parliament for 1997. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE INSTITUTIONS</P>
+<P ALIGN="JUSTIFY">AT WORK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">COMMON FOREIGN</P>
+<P ALIGN="JUSTIFY"> AND SECURITY POLICY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Within the framework of its Common Foreign and Security Policy (CFSP), the European Union has recently issued a number of statements, details of which are set out below:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Towards national reconciliation in Angola</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 4 April 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Troika of the European Union Ambassadors in Luanda made a formal demarche with both the Government of Angola and UNITA in order to welcome the positive outcome of the Libreville Summit between the President of Angola, Jose Eduardo dos Santos, and the President of UNITA, Jonas Savimbi, and in particular their commitment to establish an integrated national army by June and the creation of an appropriate institutional structure, including the formation of a government of unity and national reconciliation by June/July. The Government and UNITA were encouraged to continue to refrain from military activity and hostile propaganda and to provide for free circulation of persons and goods as soon as possible. The EU Ambassadors underlined also the importance of securing human rights as well as transparency in financial management, economic stabilisation and reforms. Having recalled the terms of reference of the EU Joint Position adopted on 2 October, 1995, the Ambassadors underlined that the Union will continue to monitor, with the greatest attention, the development of the situation particularly as regards respect for the implementation of the calendar agreed in Libreville. Welcoming the recent steps taken by UNITA, the EU expressed concern at the slow pace of the quartering and disarming of UNITA troops and urged UNITA to proceed with its commitments, in full cooperation with UNAVEM ill. The EU encouraged the Government to continue the quartering of the rapid intervention police and the disengagement and pulling back of the FAA to the nearest barracks. The importance of disarming the civilian population was also emphasised. The EU also reiterated their call to the Government and UNITA to refrain from acquiring lethal material and to cooperate fully with the de-mining process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU has reiterated its full support to the Special Representative of the UN Secretary-General, Maitre Blondin Beye, to the Joint Commission and to the United Nations Angola Verification Mission (UNAVEM).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cyprus, Estonia, Latvia and Malta align themselves with this declaration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Free elections in Sierra Leone</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 4 April 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union welcomes the fact that presidential and parliamentary elections took place in Sierra Leone in a free and fair atmosphere and in fulfilment of the established timetable for the return to democracy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The results reflect the will of the people of Sierra Leone to achieve a democratically elected civilian government despite attempts at intimidation by armed elements and the ongoing fighting in various parts of the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU welcomes the peace talks between the Revolutionary United Front (RUF) and the Freetown authorities as well as the intention expressed by President Kabbah to meet Mr Sankoh at the earliest possible opportunity. The EU calls on all the parties to work for peace and national reconciliation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Serious threat to peace process in Liberia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 11 April 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union expresses its deep concern at the outbreak of fighting in Monrovia, which represents a serious threat to the peace process in Liberia. The EU is firmly convinced that the AbuJa agreement provides the right framework for resolving the crisis and calls upon the Council of State, the Liberian national transitional government and the Liberian factions to implement it, and to put the peace process back on track, in order to avoid further deterioration of the situation, and the violation of human rights. The EU condemns the loss of human life and the harassment of the civilian population and humanitarian workers. All parties concerned should prove their willingness to re-establish and maintain the ceasefire which represents the necessary prerequisite to disarmament and demobilization. The relevant measures and the necessary preparations can no longer be delayed. The EU asks the factions to return all weapons seized during the fighting to ECOMOG. The EU will base its attitude to Liberia on the concrete steps taken by all parties concerned to implement the Abuja agreement and bring the conflict to an end.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Treaty of Pelindaba on a nuclear weapon-free zone in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 12 April 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union welcomes the signature in Cairo on 11 April 1996 of the Pelindaba Treaty establishing the African Nuclear Weapon Free Zone. The Treaty is in line with the Decision on Principles and Objectives for Nuclear Non-Proliferation and Disarmament issued by the 1995 NPT Review and Extension Conference which   recognised that the creation of Nuclear Weapon Free Zones enhances global and regional peace and security.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU considers that Nuclear Weapon Free Zones are welcome complementary instruments to the Treaty on the Non-Proliferation of Nuclear Weapons, the universality of which the EU continues to promote.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Central and Eastern European countries associated with the EU and the associated countries Cyprus and Malta align themselves with this declaration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appeal for the 'boat people' of Liberia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 14 May 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union expresses its deep concern at the grave humanitarian situation caused by the ongoing fighting in Monrovia and condemns the violence against the civilian population and the harassment of aid operations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While recognising the enormous efforts already made by neighbouring countries to assist the hundreds of thousands of existing Liberian refugees, the Council deplores the fact that the thousands of people crammed in precarious conditions on ships in the area are still in search of a friendly port.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It appeals on humanitarian grounds to the neighbouring countries to give at least temporary shelter to these victims of the fighting and affirms its own willingness to give humanitarian aid to cover their most urgent needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Council calls on all the Liberian factions to stop the fighting immediately and put the peace process back on track in order to avoid further suffering.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">VISITS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Prime Minister of Rwanda</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Prime Minister of Rwanda, Pierre Celestin Rwigema, visited Brussels from 26 to 29 March in the course of a tour aimed at informing the main donors about the work undertaken by his government in recent months and about the policies which would be implemented in the future. He was accompanied by the Minister of Planning and the Minister for Rehabilitation. The Prime Minister was received by Commissioner Pinheiro, who is responsible for relations with the ACP countries and by Mrs Bonino, the Commission member in charge of humanitarian actions. He also spoke at meetings of the External Relations and Development Committees of the European Parliament. Professor Pinheiro took the opportunity to highlight to the Prime Minister his concerns about the current situation in Rwanda, reiterating the Commission's commitment to the country and its people. He also spoke of the need for the authorities to pursue policies and implement measures leading to the restoration of normality. He said it was essential to have a dialogue with the Rwandan refugees in neighbouring countries (there are now about 1.7 million) and to pursue the pacification process under the auspices of the United Nations and the Organisation of African Unity, with the involvement of all the heads of government in the Great Lakes region. Mr Rwigema's visit came at a crucial time for Rwanda. Even if the immediate crisis had passed, there was still a dire need for rehabilitation and development assistance, on top of the existing emergency aid programmes. The political situation remained delicate and the future was by no means secure, notwithstanding some encouraging signs of a progressive improvement as exemplified by the Tunis summit. The recent nomination of</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aldo Ajello as the EU's special envoy to the Great Lakes region underlined the political and moral dimension of the EU's commitment to the peace process in this troubled part of Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SUPPORT FOR HUMAN</P>
+<P ALIGN="JUSTIFY">RIGHTS</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has recently decided to provide the following financing for projects under the budget line 'Support for. democratisation and human rights'. Non-ACP countries </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central America: ECU 180.000 to support seven national and one regional fore aimed at providing training in the field of human rights for instructors. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central America: ECU 100.000 for a democracy consolidation training programme for 30 teams from various organisations in Nicaragua, Guatemala and El Salvador. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central America/Colombia: ECU 263.000 for a series of actions, notably in Colombia, involving the provision of information on human and citizens' rights. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazil: ECU 190.000 for a project designed to boost the civil rights of black people in the country, through the training of judicial personnel and the strengthening of legislation against race discrimination. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazil: ECU 145.000 for a training programme for magistrates, prosecutors and the police aimed at facilitating the uniform application of the law in the State of S&atilde;o Paulo. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazil: ECU 290.000 for a training programme in the sphere of democratic municipal management, in the cities of Recife, Porto Alegre, Santos and Fortaleza. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guatemala: ECU 308.000 for a project to collect and make available the case law of the Constitutional Court, and  to train officials and members of civil society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Honduras: ECU 326.000 to support the National Human Rights Commission with a view to promoting such rights in the Departments of Comayagua and Olancho. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Honduras: ECU 131.000 for an education programme dealing with civic and electoral issues and the rights of children. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mexico: ECU 20.000 to support an initial Latin-American colloquium on the subject of the Ombudsman (in the face of the objectives and challenges of the region). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nicaragua: ECU 285.000 to support the social rehabilitation of minors in custody. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Panama: ECU 125.000 for a training action in the field of the defence of human rights. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Panama: ECU 250.000 to support a communication campaign designed to strengthen the image of the 'people's ombudsman'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Venezuela: ECU 160.000 to strengthen the institution of Justices of the Peace in the country's municipalities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Venezuela: ECU 100.000 ECU for a training and promotion action in the field of human rights and the strengthening of civil society. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EUROPEAN</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DEVELOPMENT FUND</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following, where required, favourable opinions from the EDF Committee, the Commission has decided to provide grants and special loans from the 5th, 6th and 7th EDFs to finance the following operations (grants unless otherwise stated). Major projects and programmes are highlighted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic and social infrastructure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon: ECU 7.3 million for a programme aimed at protecting the urban boundary of the city of Kousseri from the encroachments of the Logone river, to improve sanitation and for the upgrading of an urban access route towards Chad. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghana: ECU 54 million for a transport infrastructure programme aimed at facilitating the social and economic development of the people living in the recisions in question (Western region, Brong Afaho, the Ashanti region). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghana: ECU 3.8 million for a human resource development programme designed to achieve better planning, management and implementation of development projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya: ECU 1.9 million for a project to support the development of tourism. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 385 000 to extend the water supply system in the town of Mantola </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad: ECU 13.5 million to upgrade the Ere-Kelo road </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade promotion/ structural adjustment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Benin-Cameroon C&ocirc;te-d'lvoire-GhanaGuinea-Togo: ECU 1.99 million for a regional programme of trade activities and training with a view to relaunching the pineapple business in West and Central Africa. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burkina Faso: ECU 180 000 for the construction of an 'export and creativity' pavilion at the Salon international de l'artisanat in Ouagadougou. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Papua-New Guinea: ECU 5.3 million for the fourth structural adjustment support programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madagascar: ECU 1.9 million for a rice irrigation project. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enterpris</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Botswana: ECU 33.7 million from the Sysmin fund, to support the work of the BCL, Tati and FEB mining companies in the SelebiPhikwe region. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Health</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dominican Republic: ECU 1.3 million to support the STD-HIV-AIDS prevention programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Education</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madagascar: ECU 1.9 million for a decentralised training project in favour of regional tourism operators. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tuvalu: ECU 300 000 for the rehabilitation of primary schools on the islands of Nukutetau and Nanumea. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Central Africa (Cameroon-Central African Republic-Congo-GabonEquatorial Guinea): ECU 16 million for phase 2 of the ECOFAC project (Conservation and rational utilisation of forest ecosystems in Central Africa). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Institutional support</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malawi: ECU 1 million towards a study aimed at allowing the government to implement its land reform policy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eritrea: ECU 4.5 million for a study aimed at allowing the government to undertake proper planning in the area of water resources and irrigation. </P>
+<P ALIGN="JUSTIFY">Miscellaneous</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacific region: ECU 4.9 million for a project designed to improve the efficiency and security at certain airports. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HUMANITARIAN AID</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali: ECU 1 million towards the reintegration of some 200 000 Malians who fled to Algeria and Mauritania during the rebellions of the 1980s. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 317 000 for victims of the severe floods that struck the centre and south of the country recently. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nigeria: ECU 850 000 to help fight the meningitis epidemic affecting seven provinces of the country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sierra Leone: ECU 700 000 in urgent food and medical assistance for some 250 000 refugees who fled to the areas around the towns of Bo and Kemena following the fighting. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad: ECU 200 000 to help fight the meningitis epidemic. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zaire: ECU 145 000 to help victims of the cholera epidemic and to assist in preventing its further spread (following the course of the Zaire river). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Non-ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Colombia: ECU 60 000 to help fight cholera in the municipality of Silvia, where some 40 000 are under threat due to a lack of drinking water and deficiencies in basic hygiene. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guatemala: ECU 1.52 million to provide food aid and basic essentials to returnees from other parts of the country, and from Mexico, following years of civil war. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Armenia/Azerbaijan: ECU 11.57 million (ECU 4.07m for Armenia and ECU 7.5m for Azerbaijan), for food and medical assistance, targeted at the most vulnerable sections of the population, and for the provision of agricultural materials with a view to reducing progressively the dependence of the refugees, who are victims of the conflict in Nagomo-Karabakh.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caucasus-Georgia-Tadilkistan: ECU 3.2 million for food aid to be targeted at the most vulnerable sections of the population. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Georgia: ECU 7.43 million for victims of the internal conflict in this country where the loss of the Russian market has seriously undermined the rural economy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lebanon: ECU 600 000 for displaced people, to allow for the purchase of basic essentials including food, medicines, shelter and blankets. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Afghanistan: ECU 600 000 for health infrastructures in the refugee camps   around Jalalabad, and for medical aid to refugees in the town of Herat. Indonesia: ECU 120 000 for toots and materials to construct shelters for the victims of the earthquake that struck in February. China (Tibetan nomads): ECU 550 000 for food aid, medicines and blankets for some 72 000 people living in the mountainous regions who have been badly hit by severe weather and a food shortage.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FOOD AID </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p95a.png"></center><br>
+ The Commission has recently taken decisions to finance food aid as set out in the chart which follows: </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Aknowlegments</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier</P>
+<P ALIGN="JUSTIFY">Africa - Caribbean - Pacific - European Union</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Address: Postal address (mail only) 'The ACP-KU Courier' Commission of the European Communities 200, rue de la Loi 1049 Brussels Belgium</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier office address (visitors) First floor Astrid Building 1, rue de Geneve Evere - Brussels Belgium</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publisher Steffen Smide commission of the European Communities 200, rue de la Loi 1049 - BRUSSELS (Belgium) Tel. 00-32-2-299 11 11 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director of Publications</P>
+<P ALIGN="JUSTIFY">Dominique David</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Editor</P>
+<P ALIGN="JUSTIFY">Simon Homer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Assistant editors</P>
+<P ALIGN="JUSTIFY">Augustin Oyowe</P>
+<P ALIGN="JUSTIFY">Jeanne Remade</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associate assistant  editor</P>
+<P ALIGN="JUSTIFY">Hegel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Joumalist:</P>
+<P ALIGN="JUSTIFY">Debra Percival</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Production Manager:</P>
+<P ALIGN="JUSTIFY">Dorothy Morrissey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Secretariat:</P>
+<P ALIGN="JUSTIFY">Carmela Peters</P>
+<P ALIGN="JUSTIFY">Fax: 299-30~02</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Circulation:</P>
+<P ALIGN="JUSTIFY">Margriet Mahy-van der Werf</P></FONT>
+<!--
+</Section>
+</Section>
+-->
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec158e/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec158e/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec158e/metadata.xml	(revision 10506)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">The Courier - NÂ°158 - July - August 1996 Dossier Communication and the media - Country report Cape Verde (ec158e)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Communication, Information and Documentation|Communication, telecommunication, mass communication, mass media, film-making</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Development Periodicals and Magazines|The Courier ACP 1990 - 1996 Africa-Caribbean-Pacific - European Union</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">EC Courier</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec159e/ec159e.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec159e/ec159e.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec159e/ec159e.htm	(revision 10506)
@@ -0,0 +1,2869 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; The Courier - N°159 - Sept- Oct 1996 Dossier Investing in People Country Reports: Mali ; Western Samoa</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">The Courier - N°159 - Sept- Oct 1996 Dossier Investing in People Country Reports: Mali ; Western Samoa</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">AFRICA-CARIBBEAN-PACIFIC - EUROPEAN-UNION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Country report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali, which used to be the centre of great appears hemmed in by its frontiers, colonisation having culminated in the break-up of the old 'French Sudan'. Following the marxist regime of Modibo Keita (the 'founder' of the nation) and the dictatorship of Mousse Traor&eacute;, Mali has discovered democracy. It is still one of the world's poorest countries but recent macro-economic trends are highly encouraging and there is a new dynamism. It seems that the ending of the Tuareg conflict has provoked a surge of optimism- even among ordinary citizens whose wallets have yet to feel the effects of an improving national economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Country report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Western Samoa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacific island nations have a reputation for idyllic scenery and rich cultural traditions. Western Samoa has both of these assets in abundance, but it also faces many development challenges. With a population of just 165 000, the country has a limited local market, and it is a very long way from potential overseas customers. It is also susceptible to destructive tropical storms. Despite these constraints, there have been some promising signs of economic progress in recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dossier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Investing in people</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To say that investing in people makes economic sense is to state the obvious. But to what extent are the implications of this statement fully understood in the developing countries, especially in sub-Saharan Africa, in these days of constantly shifting development theories? We look at this subject in our Dossier. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Acnowledgements</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier</P>
+<P ALIGN="JUSTIFY">Africa - Caribbean - Pacific - European Union</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Address: Postal address (mail only) </P>
+<P ALIGN="JUSTIFY">'The ACP-EU Courier' Commission of the European Communities 200, rue de la Loi </P>
+<P ALIGN="JUSTIFY">1049 Brussels </P>
+<P ALIGN="JUSTIFY">Belgium </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier office address (visitors) </P>
+<P ALIGN="JUSTIFY">First floor Astrid Building 1, rue de Gen&egrave;ve </P>
+<P ALIGN="JUSTIFY">Evere - Brussels </P>
+<P ALIGN="JUSTIFY">Belgium</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publisher Steffen Smidt </P>
+<P ALIGN="JUSTIFY">Commission of the European communities </P>
+<P ALIGN="JUSTIFY">200, rue de la Loi </P>
+<P ALIGN="JUSTIFY">1049 - BRUSSELS </P>
+<P ALIGN="JUSTIFY">(Belgium) </P>
+<P ALIGN="JUSTIFY">Tel. 00-32-2-299 11 11 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director of Publications</P>
+<P ALIGN="JUSTIFY">Dominique David</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Editor</P>
+<P ALIGN="JUSTIFY">Simon Homer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Assistant editors</P>
+<P ALIGN="JUSTIFY">Augustin Oyowe</P>
+<P ALIGN="JUSTIFY">Jeanne Remacle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associate assistant editor</P>
+<P ALIGN="JUSTIFY">H&eacute;gel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Journalist:</P>
+<P ALIGN="JUSTIFY">Debra Percival</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Production Manager:</P>
+<P ALIGN="JUSTIFY">Dorothy Morrissey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Secretariat:</P>
+<P ALIGN="JUSTIFY">Carmela Peters</P>
+<P ALIGN="JUSTIFY">Fax: 299-30-02</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Circulation:</P>
+<P ALIGN="JUSTIFY">Margriet Mahy-van der Werf</P>
+<P ALIGN="JUSTIFY">(299-30-12)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cower page:</P>
+<P ALIGN="JUSTIFY">Cover photo by</P>
+<P ALIGN="JUSTIFY">John and Penny Hubley</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Meeting points</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Ieremiah Tabai, Secretary General of the Forum Secretariat</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Pacific Forum: 'responding to the needs of the Member States'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although an accountant by training, leremiah Tabai has never had the opportunity to practise his profession, having pursued a successful political career instead since 1974. In 1978, he was annointed head of government in Kiribati and a year later he became his country's first President, when it achieved independence. He held this position for 12 years. In 1991, he took up the top post in one of the South Pacific's key regional bodies, the Forum Secretariat, which is based in Suva, Fiji. During a recent Courier visit to the region, we had the opportunity to interview the Secretary General. Our discussion was wide-ranging, covering issues such as the Forum Secretariat's role, the economic challenges facing the South Pacific, and the development of regional links with Australia, New Zealand and Asia. We began by asking Mr Tabai to outline the objectives of the organisation that he heads.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Like many other organisations in the region, the Forum was established essentially to try and assist the development process of the Member States. At the time it was set up, there was already an organisation in existence - the South Pacific Commission - which dates back to 1947. But there was a feeling that we needed an organisation that was not just restricted to economic issues; that could talk about other matters with a bearing on the development of the region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the early years, when the organisation was called the South Pacific Bureau for Economic Cooperation (SPEC), the focus was heavily on trying to assist the trade and economic development of the member countries. Later, the name was changed to the Forum Secretariat and its role evolved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In what way ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-It has evolved in seeking to respond to the needs of the Member States. It started as a very small bureau essentially dealing, as I said, with trade and economic issues. Subsequently, it moved into areas like energy, civil aviation, maritime questions and telecommunications. It also became more involved in political issues. We have a division which deals specifically with these.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1995 was a very important year in the history of the Forum. We had a review of the organisation, looking at ways we could perform better and taking account of the changes in the region and the world at large. The fundamental recommendation in the report which came out of that review was that the Secretariat should focus mainly in future on poliy-related issues, in the areas of trade and investment, economics and international relations. This report was discussed and endorsed at the last Forum in Madang, Papua New Guinea. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Does this mean, in practice, a withdrawal from project activity ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-It may. The essential focus of the work will be providing policy advice to countries. Having said this, there should still be some project work. For instance, we will be engaged in a programme to provide assistance for importers, particularly in the small island countries. The idea is to help people- who may not be familiar with all the legal requirements-to learn how to get into the business. This will involve running a workshop and inviting people with expertise to pass on their knowledge. So even though the focus will be on policy issues, there will still be room for project-type activities where needed -so long as these fit in with the policy priorities. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You mentioned the fact that the Forum now deals with political questions. Although the issue may now be seen as 'water under the bridge' to what extent was the Forum Secretariat involved in the diplomatic disagreement over French nuclear testing ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- We were very much involved from the beginning. In 1991, when the French testing was not underground but atmospheric, the region, at a Forum meeting, came out strongly in opposition to the tests. Right up to our last meeting in Madang, the subject was always a major item on the agenda, and we left France in no doubt as to the resolve of our region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the new President took the decision to resume testing after a gap of several years, I was in the group from the South Pacific that went to France to express our views to French ministers, face-to-face. Our team was led by the then Australian Foreign Minister, Gareth Evans, who was President of the Forum. And when the tests began again, the Chairman took a decision suspending the dialogue and partner status of France with the Forum. So, as you see, we have been heavily involved in the issue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What resources does the Forum have at its disposal and where does the money come from ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- An important source of funds is our members' contributions. These tend to be used to cover the operational costs of the organisation. Then of course, there are the funds made available by our donors. The main ones are obviously Australia and New Zealand but there are many other countries and international organisations who provide assistance. The EU, of course, is an important partner. There was also a private donor who funded our conference centre.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· How many people are employed in the Secretariat ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Around 80, all based here in Suva. Most of these are support staff.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What is the current state of relations between the Forum Secretariat and the main donors ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I would say our relations are good. We have an extensive mechanism for consultation with the donors. Every two years, we invite them here for a dialogue. We talk about the key issues and discuss ways in which they can assist us. There is also usually a dialogue associated with the Forum (ministerial) meetings. In September this year, after the Forum meeting, we will have more discussions with our main partners such as the EU, Canada, France, Japan and the UK. I should mention too the close links we have with international organisations like the Asian Development Bank, the World Bank and the IMF.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I think it is fair to say that the Forum Secretariat is seen as a particularly important organisation in the region. That is why donors are quite keen to be seen assisting us in what we do.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What are the key development issues facing the South Pacific nations ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Development is quite a difficult process for our region. There are various international reports (particularly from the World Bank) - that describe how we have fared over the last few years. If you compare our performance with the Caribbean countries, for example, you find that we have not done nearly so well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We face a number of problems. First, there is the fact that we are so small. Small communities find it much more difficult than large ones to achieve development. You need to have the market and the critical mass to do all the things that are needed and we lack these. A second, related point is that our countries are very isolated from the rest of the world. It is true that here in Fiji, there are quite good connections, but if you go to Tuvalu, Kiribati or Niue, you will soon discover how difficult it is to get out. And if you are so isolated in terms of communication, how can you hope to increase your exports ? How can you airfreight your fish to Japan when there is no aircraft available-or the one that is available is not fast enough to ensure that the product is still fresh when it arrives?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On this question, one of the things we are increasingly realising is the need to do more in terms of human resource development. We all recognise that, without an educated population and workforce, it is very hard to achieve the development that we are aiming for. To be fair, if you compare the literacy rates here with those of many other countries, say in Africa, they are not at all bad. Our literacy levels are quite high. But I think we have a long way to go in acquiring problem-solving skills of the type needed to compete internationally. We are now talking with the EU about how we can utilise funding from the second protocol of Lom&eacute; IV. And I suspect that human resource development will remain high on the agenda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Is that view shared by the European side ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I think so. l have a feeling that they will support it because it is so obvious. If you develop human skills, you are better placed when it comes to problem-solving.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Going back to the key development issues, another point is the lack of natural resources. This is less of a difficulty for countries like Fiji or Papua New Guinea, but it certainly affects the small island states. It hardly needs saying that if you don't have the resources in the first place, it is much harder to develop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, I think there is a question of how the Pacific region can get a better return on the resources it does have. This theme of 'managing our resources' was discussed by the Forum in Brisbane two years ago. Fisheries is probably the most important area here. The question is how we can earn more from this than we are currently doing- and there is no easy answer. Likewise in the forestry sector. We have to ensure that logging is done on a sustainable basis. But we must also recognise that leaders of the Pacific nations are under pressure. On the one hand, they are trying to take a lona-term view. but they are also striving to tackle the immediate problems. In an ideal world, our region would obtain a far better return on our resources, and that is something that we have to work on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Having said all this, I don't think one should be too pessimistic. This region is still a very good place to live in. That is clearly reflected in the number of visitors we get. The 'South Seas' still have a special connotation that draws people here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You effectively have two 'genera/' regional organisations, with overlapping memberships, covering the South Pacific -the Forum, and the South Pacifc Commission (SPC). Do you think there is room for bath ? Do you complement each other or is there a rivalry ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We have more than two regional organisations. We also have SPREP (South Pacifc Regional Environment Programme), the FFA (Forum Fisheries Agency)....</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yes, but these are specialist bodies with distinct sectoral responsibilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Yes, that's true. In answer to your question, my view is that we have no problem with things as they stand. I was very involved in the debate some years back on the question of what we called an SRO - a single regional organisation. There was a strong push to try and achieve an SRO. The subject was debated for a few years and, in the end, it was possible to resolve the question.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You mean it was resolved by the idea being abandoned ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I suppose it depends on the way you look at it. The outcome was a decision to leave the regional organisations as they are but with the establishment of a mechanism to ensure they work together more effectively. This mechanism is called SPOCC-the South Pacific Organisations Coordinating Committee. It is a meeting of heads of regional organisations which happens at least once a year. We talk about the issues that are common to our mandate and work out ways of doing things better. SPOCC has been operating for six or seven years now and I think it works fairly well. There is, after all, no conflict in our underlying objectives. So my answer here is no, I don't see any problem. I don't see any rivalry between us. It is a question of seeing how we can work together to achieve the goals that we share.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In the European Union, the fundamental goal, set out in the Treaty, is to move towards 'ever-closer union' We have been doing this in fits and starts over the past 35 years. Do you see the Forum perhaps taking on a similar role here-as the focus for economic, and perhaps ultimately, political integration in the South Pacifc ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- I think it is too early to speculate. We already have a number of sub-groups in the region like the MSG, the Melanesian Spearhead Group, whose members are the Solomon Islands, Papua New Guinea, Vanuatu and Fiji (admitted last year). Further north, we have the Micronesian grouping which brings together Nauru, Tuvalu, the Marshall Islands and Kiribati. These groups meet outside the Forum framework and they essentially have a common aim which is to work more closely together. I think they feel it is easier to do it at this level because they are closer to each other and have more in common.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for the Forum Secretariat, you can never tell what may come in the future. On balance, however, I think at the moment that integration is a long way off. Having said this, you do sometimes hear people putting the idea forward. There is, for example, something called the CER system, which stands for 'closer economic relations' between Australia and New Zealand. There have been suggestions that it might be possible to enlarge this grouping.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Looking at closer economic cooperation, and the general dismantling of trade barriers, we also need to recognise the growing importance of APEC (Asia-Pacific Economic Cooperation) for the region. We are trying strengthen our links with the APEC countries and in October, we will be establishing a trade office in Japan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You mean a Forum Secretariat office ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Yes, in Tokyo. We are also talking with the Chinese and will probably end up with an office in Beijing. This is all part of our attempt to integrate ourselves with the Asean region. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interview by Simon Homer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mission statement of the Forum Secretariat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mission of the Forum Secretariat is to enhance the economic and social well being of the people of the South Pacific, in support of the efforts of the national governments. The Secretariat has particular responsibility to facilitate, develop and maintain cooperation and consultation between member governments. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Secretariat must pursue its mission in accordance with the directives of the Forum and within its mandated areas of operation. it undertakes political and economic activities, regional in nature and complementary to the activities of the member governments. Its role requires it to act as the secretariat to the Forum and to disseminate the Forum's views, to coordinate activities with other regional institutions in particular through the SPOCC process, and to represent the Forum's interests intemationally, as required. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">ACP</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Investment symposium</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">A success story for African mining</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The MIGA (Multilateral Investment Guarantee Agency) symposium was held in Montreal from 22-24 May. It brought together some 40 African mining ministers, most of the important donor agencies and representatives of around 25 mining companies. MIGA, which is a specialised agency of the World Bank, promotes the flow of private investment to developing countries. It provides insurance against political risks and assists member countries in attracting foreign investment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The purpose of the symposium was to attract investors from all over the world in order to exploit the rich mining possibilities offered by many African states. Several of the countries that attended went to considerable effort to present themselves well, and it was evident that some are quickly learning what it takes to attract foreign investors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The climate for mining investment in most African states has improved tremendously over the last two to three years. Most countries have introduced new mining codes, clearly defining the rights and obligations of foreign investors. State-owned companies are also being privatised, taxation has been made more reasonable and institutions in the mining sector, such as geological surveys, are becoming more efficient.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All this has led to a big increase in exploration for new deposits and a substantial increase in investment. At present, the activity is particularly heavy in West Africa, where many countries have very good gold potential. The European Community is contributing to this development in several ways. The biggest success so far has been the exploration campaign in Mali, funded under that country's Lom&eacute; National Indicative Programme (NIP), which led to the discovery of the Sadiola gold deposit. A world-class gold mine will be built here, bringing substantial benefits to the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The World Bank has also supported many African countries in their efforts to reform the legal and administrative framework for the mining industry. An important element, however, in attracting mining companies is the availability of good geological data. This is a very expensive activity, which does not bring immediate returns, if at all. So it is not appropriate to finance this through bank loans. The NlPs and SYSMIN Fund, on the other hand, are instruments that are well-suited to this kind of work. The Community has already financed a series of airborne geophysical surveys in Botswana and Namibia -to mention just two examples-and a new Sysmin project is currently being prepared for Burkina Faso.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission Unit responsible for Mining Cooperation and Sysmin (VIIIl.B.5) was represented at the symposium. Its main purpose for being there was to present the functioning of Sysmin and the Community's cooperation in the field of mining to ACP ministers, mining companies and other donor agencies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Current state of the mining sector</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mining sector is currently very active. Exploration in West Africa doubled between 1993 and 1995 and new mines are being opened all the time. A lot of this new activity is to be found in the gold sector. This is mainly due to the development of cheaper production methods combined with a much more positive investment climate in many African countries. A gold mine takes less time to reach the production stage than, for example, a copper mine, with the former being far less dependent on good infrastructure. Outside the gold sector, activity is much more subdued. While base-metal prices are at a reasonable level, the pay-back period is much longer and the lack of suitable infrastructure kills many projects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For many countries, mining is a key area in the growth of the private sector. State-ownad mines are being privatised and the new mines that are being opened have little or no state participation. Foreign investors are bringing in the most up-to-date mining technologies and business methods, and they are faced with the need to train local people in technical and business skills. Supporting the mining sector is clearly an efficient way of supporting private sector development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SYSMIN's future role</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given that most metals are currently fetching quite high prices, it is probable that relatively few ACP countries will be eligible for SYSMIN assistance over the next two to three years. The viability of most existing mines is not thought to be under threat and they should continue to be profitable. Thus, countries that are heavily dependent on mining should not experience severe losses in export income, which in turn means that relatively few SYSMIN requests are expected during the period of Lom&eacute; IV's second financial protocol. At the same time, the financial allocation for SYSMIN has been increased from ECU 48Om to ECU 575m.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When trying to attract new mining investors, it is essential for a country to have good geological information. Private companies are normally unwilling to undertake much general prospect ion, such as airborne geophysical surveys, because it is very expensive and, if they do, it is usually limited to very small areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present, companies are tending to restrict their activities to areas for which general information is already available. These points were raised by several of the mining companies that attended the symposium.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But the present mining boom is not going to last for ever. Metal prices are volatile and, with the next downturn in the business cycle, a decline in metal prices will surely follow. So it is essential to prepare the basis for future mining activities by collecting general data. Given that a significant part of the SYSMIN allocation may remain unused because of a lack of requests, it would be worthwhile to consider whether a part could be reallocated to prepare general geological data for mining activities in the next century. </P>
+<P ALIGN="JUSTIFY">F. B.-H.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Joint Assembly to consider climate problem</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY">by Hans van de Veen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Can the EU-ACP relationship be used to strengthen the dialogue between Europe and the main victims of climate change ? And can the Lom&eacute; Convention be one of the tools to promote climate protection measures, as well as the implementation of the Climate</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Treaty? These questions will be considered in depth at a hearing on climate derange scheduled for the next ACP-EU Joint Assembly, to be held in the last week of September 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Periods of heavy rain have always been part of normal life in Fiji. But the latest rains were different, says counsellor Taina Tudau of the Fiji Embassy in Brussels. 'They were much more extreme than what we were used to, and caused heavy damage. Normally it took several days of heavy rain before the floods came up. This time, the water flooded the islands almost immediately the rain began to fall.' Mrs Tudau sees two main causes for the recent flooding. First, there is heavy deforestation on the islands, causing widespread erosion. But she is sure there was another reason for the recent damage: 'In the Pacific we know the local climate is changing. We see that the sea is rising. We are experiencing more extreme weather events. There can be no doubt that global warming is already going on.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji is a prominent member of the Alliance of Small Island States (Aosis), the group of 36 nations which feel particularly threatened by global warming. At the first Conference of Parties to the UN Framework Convention on Climate Change, held in Berlin in March 1995, Aosis called for industrialised nations to reduce their C02 emissions by 20% by 2005 (based on 1990 levels). At the end of the conference, the 150 national delegations agreed to begin negotiations on targets for industrialised nations to cut emissions in the early years of the next century.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So intentions may be good, but in practice not much has been done yet. The EU, for its part, risks losing credibility if firm action is not taken soon. According to a recent Commission White Paper on energy policy, the use of energy within the Union will increase by 1% a year up to 2020. Failing 'any strong policy interventions', the paper says, emissions of carbon dioxide are likely to show a 'substantial increase' during this period. Says Fiji-counsellor Tudau: 'As small island states we know what's at stake, but there seems to be no feeling of urgency in the rest of the world. We really wonder how long it will take before there is a definite move towards reduction of greenhouse gases.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EU-ACP cooperation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the Berlin conference, the ACP countries-led by Aosis but with support from most of the African states -took a constructive and moderate position in the G77. The position adopted by the EU could also be described as moderate, certainly compared to that of other OECD countries. Several observers have pointed to the fact that these two moderate approaches by important blocks within the Climate Convention negotiations offer possibilities for some form of cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'No doubt the EU represents the most progressive group of countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">within the OECD, although its position is far from sufficient', says Sible Schone, a representative of the World Wide Fund for Nature. 'Besides that, the EU has a special relationship with a large group of developing countries. Quite obviously it will be significant to get a dialogue started between the EU and the ACPs on the subject of climate change.' Currently, there is no such dialogue. 'At the moment we are not in a dialogue with ACP countries on climate change', says Bertil Heerink of the European Commission's Environment Directorate-General who is a member of the EU delegation to the climate negotiations. 'I'm convinced this will happen some day, but first we have to agree on our own goals and measures. I am sure developing countries want us to give priority to this too.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The special ACP subcommittee to deal with tropical timber, the environment and fisheries, formed after the signing of the revised Lom&eacute; IV, only recently started its work. With respect to the global warming issue, it is waiting for the Joint Assembly hearing, according to ambassador Michael King of Barbados, who is a committee member. 'The specific interests of the different regions have to be articulated there, and then some kind of sustained effort has to be initiated.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The unit for Sustainable Development and Natural Resources in the Development Directorate-General of the Commission (DG VIII) not at present dealing with the subject of climate change. Says Head of Unit, Amos Tincani: 'We have worked on biodiversity and desertification, and we want to do more on the specific environmental problems of small island states. But we have done nothing similar on climate change. This is partly because it is so much a global problem, but the main reason is we simply lack the people and the time to go into it.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Assembly hearing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At its meeting in Windhoek in March this year, the Joint Assembly adopted a resolution which had been proposed by representatives of 13 small island states. This urged the EU to take the lead in combating climate change and the adverse effects thereof. More specifically, the Commission is being asked to update its climate change strategy for the period post-2000 and to achieve significant reductions in emissions of greenhouse gases over the coming decade and thereafter. The resolution riches on to call for extra assistance to ACP countries in the Caribbean, Pacific and Indian Ocean to help them improve their disaster preparedness. The Commission is also urged to accelerate the transfer of appropriate technologies and practices, to enable ACP states to develop coastal zone management strategies and to rehabilitate and protect areas stricken by drought and desertification as well as by hurricanes and floods.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two representatives of the European Parliament, Maartje van Putter (PES) and Peter Liege (EPP), have been active on the situation of the small island states and climate change for several years. According to Mrs Van Putten, the main effect of the coming Assembly hearing should be to put extra pressure on the Commission to take its responsibility seriously. 'Talking about climate change,' she says, 'one should never forget who is to blame and who, therefore, must take decisive action. A European tax on energy or carbon dioxide would be an important first step, but no more than that.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Besides influencing the Commission's energy policy, Mrs Van Putten hopes the Assembly hearing will raise public awareness on the climate problem in those ACP countries which are not in the 'small island' category. 'If you are talking about rising sea levels, the African states with low-lying coastal zones face the same problems as the small island countries,' she points out. 'And they also face the problem of desertification and declining food production.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Integrating the climate dimension</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a recent briefing paperto the Commission, the International Institute for Environment and Development (IIED) concluded that, hitherto, the aid community (including the EU) had not incorporated measures on global warming into their strategic thinking on sustainable development. 'Indeed, the possibility of climate change has been considered of minor importance in comparison to other environmental concerns.' This is hardly surprising, says the London-based institute, as the climate issue has only recently been placed on the international agenda. Moreover, the long-term threat of global warming raises some difficult questions regarding priorities in circumstances where resources are limited. In other words: who wants to spend scarce funds on problems the full effects of which will probably not be felt for another 25 to 50 years? The best way forward, suggests the IIED, is to tackle the apparent conflict between shortterm development priorities and longterm climate protection, by 'integrating the climate dimension' rather than considering climate change as an issue in isolation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Technology transfer could be a central point, according to WWF's Sible Schone. 'Developing countries see technology transfer as a central theme in the Climate Convention, but the industrialised countries don't give enough weight to these There are a lot of paragraphs about technology transfer in the Convention as well as in Lom&eacute;. Now it's time to fill in these commitments.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Strangely, there are hardly any Lom&eacute; projects currently under way in the field of energy efficiency. It is strange because experts have pointed to the large potential in developing countries for cost-effective energy improvement and energy conservation. Improved management could save at least 25% of the energy now being consumed. Quick realisation of this potential would significantly contribute to alleviating environmental &agrave;nd development problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Henri Martin, energy specialist in DG VIII, agrees a lot more could be done in this field, but he points out: 'We are dependent on requests. If you look at the wording of the Convention, everything has already been said. There are chapters on energy and technology transfer. The problem is that we don't get enough signals back from the ACP countries that these items are a priority for them. I'm afraid sustainable energy or energy efficiency is not high on the agenda of most countries.' Taina Tudau disagrees strongly: 'Our experience is that the projects that could make a difference and contribute to sustainable development, protection of the environment and local sustainable energy production, are found to be too small. It is the donor that sets the conditions for the projects, not us, the small island states.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New funding?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Can the EU build a credible policy linking climate and development cooperation, without reserving extra money? Not surprisingly, there is disagreement on this question. In Brussels, officials are inclined to point to possibilities that are already there but not being used. Amos Tincani, for instance, observes that 'there are budgets for this kind of problem under Lom&eacute;. We have provisions specially targeted for the islands'. He mentions regional budgets in particular: 'A lot can be started at the regional level which then trickles down to the national level. But after producing fine resolutions, everybody seems to forget the work still needs to be done. The idea is: 'oh yes, we can do it, provided it is with fresh money'. We say: a lot more can be done with existing budgets and instruments.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maartje van Putten, from the Parliament, says the discussion should not be 'dominated by southern demands for additional money'. She agrees that ACP countries could make better use of existing funds and possibilities, such as, for instance, the funds for intra ACP cooperation. But counsellor Tudau points to the fact that the Climate Convention urges industrialised countries to support the response of developing countries to climate problems through 'new and additional' money, besides the transfer of environmentally sound technologies and expertise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a financial mechanism built into the Climate Convention, which is administered by the Global Environmental Facility, to cover additional costs of appropriate measures. But much more could be done by the aid community, including the EU, according to Mrs Tudau. 'Most European countries will not succeed in stabilising, let alone reducing, their emissions. In reaction to this, as ACP countries we should say: European Union, you are not fulfilling your obligations. You have to try harder and you have to set extra money aside to compensate for the damage this is doing to us. </P>
+<P ALIGN="JUSTIFY">H.v.d.V.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">ACP-EU Council in Apia</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were no real surprises or unexpected developments at the ACP-EU Council meeting which took place in Apia, Western Samoa, on 27 and 28 June, 1996. The session was preceded by an ACP Council, which saw the adoption of three important decisions. The first of these was the appointment of a new ACP Secretary-6eneral, Mr Ng'andu P. Magande of Zambia. The post had been vacant for some time, following deadlock within the ACP Group over a successor to Berhane Ghebray (see issue 155 of The Courier, p.6). The ministers also agreed to hold a summit of ACP heads of government in Libreville, Gabon, during the second half of 1997. This meeting is expected to focus heavily on the future of ACPEU relations once the present Lom&eacute; Convention has expired.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the substantive area, the ACP Council adopted a resolution deploring the suspension of cooperation with Equatorial Guinea. Ministers urged the European Union to make use of the procedure in Article 366a of the revised Lom&eacute; Convention, and to set in train the consultation procedure envisaged in this provision.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This issue was raised again by the ACP side at the subsequent ACP-EU Council. This meeting, which was presided over by Mrs Toya (Italian Under Secretary for Foreign Affairs) and Mr Syamujaye (Zambia's Trade Minister) had a relatively light agenda. There was a discussion about the Commission proposal for a directive on the use of vegetable fats, other than cocoa fat, in chocolate (see issue 158 of The Courier, p.35). Somalia also featured in the debate, with representatives agreeing on the need to find ways of allowing this country to benefit from Lom&eacute; Convention provisions. The civil conflict in Somalia, and the absence of an effective central administration have prevented the deployment of regular development aid for many years, although significant amounts of emergency assistance have been and are still being provided.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, the ACP-EU Council approved two reports drawn up by the development finance cooperation subcommittee and commodities sub-committee respectively. Representatives were able to reach a compromise on two outstanding points of contention in the resolution on development finance relating to tenders and the dissemination of the user's guide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note was taken of the number of countries that have so far lodged instruments of ratification for the revisad Lom&eacute; Convention (Mauritius agreement). At the time of the Apia meeting, only nine countries had ratified: seven on the ACP side (Barbados, Dominica, Equatorial Guinea, Jamaica, Malawi, Mauritius and Solomon Islands) and two EU Member States (Denmark and Sweden). Appeals were made for the contracting parties to speed up their ratification procedures so that the Eighth European Development Fund can come on stream as speedily as possible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The next ACP-EU Council meeting will take place in Luxembourg on 24 and 25 April 1997.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government of Western Samoa deserves a special mention for the warmth of their hospitality and the efficient way in which they organised the Council meeting. Delegates from all sides were keen to express their appreciation of the host country's efforts, which ensured the smooth running of the various meetings and gave the visitors a real taste of this Pacific country's unique culture. ed. S.H.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">New ACP Secretary-General</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ng`andu Peter Magande, is no stranger to the challenge of development at the grassroots. The new Secretary-General of the ACP Group, who was born in 1947, began his working career as a provincial development officer, planning and supervising projects in the Southern Province of his native Zambia. He is an economics graduate of the University of Zambia and also holds a master's degree in agricultural economics from Makerere university, Uganda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From working in the field, he moved into government administration, rising to the position of Permanent Secretary-a post which he held in a number of ministries. Since the mid-1980s, he has had key jobs in a number of Zambian enterprises (including Managing Director of the Zambia National Commercial Bank) His most recent work has been on a project to develop private sector participation in agricultural input and produce marketing.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Kenya's economy in the 1990s</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Elisabeth Pape</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya has enjoyed rare political stability since independence in 1963. It is one of the most famous holiday destinations in Africa, with abundant wildlife, fine beaches and stunning scenery. But despite having the most advanced economy in East Africa, it is still one of the world's poorest countries. Over 11 million Kenyans live below the poverty line. But better times may be ahead. The Government has embarked on an ambitious reform programme which promises to lay the foundations for strong growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The early 1990s marked the worst time in Kenyan history, in economic development terms. Real GDP growth dropped from 4.3% in 1990 to 2.1% in 1991 and was almost zero in 1992 and 1993. This poor performance was due to drought, structural rigidities, lack of monetary discipline, non-enforcement of banking regulations, and reduced donor assistance. While Kenya was used to receiving substantial foreign aid inflows, the present decade began with growing tensions between Government and donors. In the new post-Cold War atmosphere, the latter wanted to see political and economic reforms, and in November 1991 they decided to halt guick-disbursing aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Multi-party elections in December 1992 did not immediately restore relations with the donors, in particular as they were accompanied by a lack of fiscal and monetary discipline whose effects threatened economic ruin. Monetary expansion was fuelled, among other things, by discretionary exemptions to Banking Act provisions, which enabled over-borrowing by certain 'political' banks from the Central Bank. In early 1993, things came to a head. Foreign currency reserves were down to just a few weeks of imports, the banking system was on the verge of collapse, and consumer prices had shot up. Against this background, the Government went for a comprehensive, IMF-supported structural adjustment programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A number of far-reaching reforms were implemented with unprecedented speed. Exchange restrictions were removed, import licensing was ended, import procedures were made easier and tariffs were reduced. The export license requirement was also lifted and price controls were abolished. In March 1993, the Central Bank (CBK) began to tighten monetary policy. By issuing large amounts of treasury bills, it soaked up most of the excess liquidity which had been injected the previous year. There was also stricter bank supervision and a number of weak financial institutions were closed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Structural reforms</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Government began structural reforms aimed at reducing its own role in the economy in favour of the private sector. The privatisation programme, begun in 1991, was accelerated. By the end of 1995, the authorities had divested more than half of the 211 non-strategic parastatals-though critics complained the process often lacked transparency. The Government also substantially reduced its fiscal deficit through, above all, an improved revenue policy. The deficit fell from 11.4% of GDP in 1992/93 to 2.5% in 1994/95. The number of civil servants was reduced, mainly through voluntary early retirement, so that, by the end of 1995, the service had been trimmed by more than 30 000 (10% of the payroll).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1995, the reform programme lost momentum as proponents of the old and the new systems locked horns. Vested interests stood in the way of more radical reforms. Temporary import bans on maize and sugar were reimposed, key parastatal reforms were delayed and expensive but economically dubious projects were approved outside normal budgetary procedures. These included an international airport in Eldoret, a presidential jet and an identity card project. These further delayed the resumption of balance of payments support by the Bretton Woods Institutions and contributed to the frustration of efforts to improve relations with donors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The economic crisis peaked in early 1993 and the shilling was sharply devalued. The official rate went from about KSh 36 to the dollar at the end of 1992 to KSh 60 in April 1993. On the market, the currency was being traded at a premium of more than 30% and that continued until July-i.e. about two months after the removal of exchange restrictions. The market premium then started to decline and the two rates converged in mid-October when the shilling stood at 69 to the dollar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The high interest rate on treasury bills under the liberalised foreign exchange regime was the main reason behind strong currency inflows which began in October 1993. Other factors, whose exact impact is difficult to gauge, included capital flight from neighbouring crisis-torn countries, the international money laundering one normally finds in places with newly liberalised foreign exchange regimes, and a surplus in the current account position. The shilling then started to rise, despite the CBK's massive currency purchases which led to a build up of reserves to the equivalent of six months of imports. The appreciation continued up to October 1994: indeed, at one point, the shilling reached a high of 35 to the dollar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That was the turning point. Strong import demand, fuelled in particular by a surge in oil imports in the wake of petroleum market liberalisation, and an outflow of portfolio investments due to lower interest rates, weakened the currency. By mid-1995, after two sharp falls, it reached a rate of 56 to the dollar. Since then, it has been relatively stable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic recovery</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Real GDP grew by 3% in 1994 and an estimated 5% in 1995. Good weather certainly helped, but the economy also benefited from the Government's reforms. Agriculture, the mainstay, grew by 2.8% in 1994 and by more than 5% in 1995. This compares with negative growth rates in 1992-93, when the sector was hard hit by bad weather. Elsewhere, the trends were more mixed. Many producers for the local market were affected by trade liberalisation and, in 1994, by the strong shilling. The former created a highly competitive environment almost overnight-after years of cosy protectionism. For cloth manufacturers, the liberalisation of imports of second-hand clothing further aggravated the problem. In 1994, the clothing sector's output dropped 35%. Tourism, the main foreign exchange earner, fared quite well in volume terms in 1994 despite the strong shilling. But while turnover may have gone up, it is likely that many operators did not earn enough extra to cover their increased local currency costs. In 1995, visitor arrivals fell by 20% to the lowest figure since 1988. In consequence, tourism earnings fell by a quarter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As intended, liberalisation led to higher trade volumes. In 1994, exports ( + 16%) rose by more than imports ( + 13%) in value terms, but the position was reversed in 1995 when the latter jumped by 35% while the former were 14% lower. One good sign was that the highest import growth was in industrial supplies and machinery (60% up) but the fact that the deficit almost doubled to reach record levels was obviously a cause for concern.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A major revolution has also taken place in trade flows. In 1994, for the first time, Uganda overtook the UK as the biggest importer of Kenyan goods. In the same year, the value of Kenya's exports to African countries moved ahead of its combined exports to Europe and North America.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During 1994, the Nairobi Stock Exchange proved to be one of the worid's best-performing stock markets, the value of shares rising by 80%.1995 was disappointing, however. Although foreigners were allowed to invest for the first time, the index nonetheless fell by 25%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fighting inflation has been the CBK's main objective since 1993 and a tight monetary policy has brought the problem under control. Inflation dropped from 46% in 1993 to 29% in 1994 and to below 2% in 1995. Recently, however, an upward trend has bean observed. This follows a money supply increase far in excess of the expansion of economic activity, and is mainly due to a substitution of treasury bills for borrowing from the Central Bank since the end of 1994. If inflation is to remain within the 5% target for 1996-which already seemed highly unlikely by the middle of the year - the trend needs to be speedily reversed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initially, the main way of mopping up excess liquidity was through the sale of treasury bills. When the sales began in March 1993, there was a huge liquidity overhang and high interest rates had to be offered to take money out of the market quickly. The rate earned on 90-day bills-which became the lead interest rate in the economy- rose from 17% to 80% between March and July 1993. It then declined steadily, reaching 18% at the end of 1994. This prompted an outflow of short-term capital, leading to currency depreciation and lower foreign reserves. Since mid 1995, treasury bill rates have been back above 20% and this seems to have stabilised the foreign exchange situation. It is generally believed that the high prevailing real interest rates are a major obstacle to investment and economic growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interest on domestic debt is still a big item in the state budget, although, the situation is much improved, thanks to the reduction in the stock of treasury bills and lower interest rates. In fiscal year 1993/94, interest payments on domestic debt alone swallowed one third of total gavernnnent expenditure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agriculture sector employs 70% of the total labour force and generates more than a quarter of Kenya's GDP. Much of industry is linked to agricultural processing, and tea, coffee and horticultural products are Kenya's major foreign exchange earners after tourism. The marketing of key farm products is dominated by large parastatals and cooperatives which are often run like parastatals. Most marketing organisations have been hard hit by the liberalisation, which brought both inefficiency and corruption to light. Tea growers have complained about improprieties at the Kenya Tea Development Authority. Imported sugar flooded the local market, often without paying import duties, leaving the mills with huge stocks. This, in turn, created severe cash flow problems. Most sugar farmers have not been paid for months. Kenya Cooperative Creameries was not able to pay farmers for milk deliveries for up to half a year, and could only start servicing the arrears when the Government came to its rescue with KSh 800 million in January 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Formidable challenges</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya's labour force, around 12.5 million in 1996, is growing at more than 4% a year. This means that at least half a million people enter the job market annually. The challenge of absorbing the new workers is formidable. Studies show that any strategy to deal with this must be based on three pillars: smallholder agriculture (to absorb most of the growth in the rural labour force), continuing substantial job creation in the informal sector, and high real GDP growth (+8% per year is needed to ensure that the modem sector absorbs a significant number of workers).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Informal sector employment has risen rapidly (up by 15-20% a year since 1991). By 1994, for the first time, there were more people working here than in the modern economy. The informal sector covers semi-organised and unregulated activities largely under taken by self-employed people or employers with just a few workers. Typically, they do not comply fully with tax, registration, and licensing rules, and this sometimes leads to conflict with the authorities. Workers are often paid below the minimum wage and have no social security. For many, the informal sector is, therefore, an 'employer' of last resort.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is estimated that almost 50% of rural people and 30% of urban residents live in absolute poverty- unable to meet their minimum requirements for food and essential non-food items. While the percentage has remained fairly stable in recent decades, the increase in the number of 'absolute' poor is alarming. So too is the extent of the poverty: the gap between these people's minimum needs and their actual disposable income has reportedly increased over the last ten years. The bulk of the poor live in the central and western parts of the country, which have the best agricultural potential, the rich soils having always attracted settlers. For decades there was enough land to go around, but demographic trends have finally started to take their toll. The size of landholding has declined continuously, in many cases reaching levels which are no longer capable of sustaining a family.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There has been some progress in restructuring parastatals, but much remains to be done. The performance of key parastatals has been unsatisfactory by international standards and this has constrained growth. At Mombasa port, which is managed by the Kenya Ports Authority, handling charges are 50% higher than the global average, while container turnover is three times slower. Rail transport is unreliable, slow and more expensive than road haulage. The Kenya Power and Lighting Company has a shortage of generating capacity which means periodic power cuts. And intervention in the maize market by the National Cereals and Produce Board- at above-market prices-has prevented private sector involvement as well as placing a heavy burden on government finances. The Board has posted annual operating losses of between KSh 1.8bn and KSh 2.5bn each fiscal year since 1992/93.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corruption, misuse of funds, and the politics of patronage remain endemic and these clearly distort development. Elimination of corruption has been an aim of most reform programmes but it seems that the effect so far has only been to change its form. Trade liberalisation has killed cash cows such as import and foreign exchange licences, and the commercialisation of parastatals has stopped them from doing deals with cronies which were profitable only for the latter. But other forms of non-acceptable wealth accumulation have emerged. In the early 1990s, alleged exports of gold and diamonds are thought to have resulted in a loss of KSh 7 billion of public funds. Land grabbing has also become widespread. This either involves land being sold to individuals or companies with well-established political connections at well below market prices, or the purchase of land by public institutions from the same individuals or companies at inflated prices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After delays because of political differences, cooperation between the three states of the former East African Community (Uganda, Tanzania and Kenya) was revived in early 1996. The EAC Secretariat, based in Arusha, is headed by a Kenyan, Francis Muthaura, a former ambassador in Brussels. For the three countries, the new cooperation aims at facilitating movements of people, capital and trade within the region, and harmonisation of external tariffs and investment regulations. Currencies will be fully convertible. This revived cooperation is expected to have a major growth impact. The Nairobi Stock Exchange is currently assisting Kampala and Dar es Salaam to set up their own exchanges. And the NSE Chairman, Jimnah Mbaru, sees the future not only in a cross-listing of companies in the three places, but in a regional stock exchange.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Policy framework</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Policy Framework Paper (PFP) for 1996-1998, which was published in February ahead of the donors' Consultative Group (CG) Meeting, was highly applauded for both its content and form. The programme, which the media has dubbed 'the big push', promises finally to crack most of the 'hard nuts' of previous reform agendas, in particular in the parastatal and public sector. It also lays down measures aimed at supporting fiscal and monetary discipline through the next elections. These include cutting the budget deficit to 1.5 % of GDP by 1997/98, a tight monetary policy, and more autonomy for the Central Bank. In addition, it tackles some areas'that have emerged as avenues of corruption in recent years, such as the National Social Security Fund. While previous PFPs were highly confidential, this one was published, and the President appointed a Commission chaired by himself to oversee its implementation. These are seen as important steps in bridging the credibility gap which threatened to open up again in 1995. Donors are prepared to support the reform agenda and are eager to see it implemented speedily. Shortly after the positive outcome of the CG meeting, the IMF approved a three-year Enhanced Structural Adjustment Facility programme for a total of $220m. The World Bank is expected to follow suit with a credit of $85m.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An increasing number of donors, however, have pointed to the link between democratic governance/ human rights issues on the one hand, and aid and investment flows on the other. If Kenya is to meet its ambitious targets and turn into a newly-industrialising country by 2010, foreign inflows will be vital. The point was succinctly put by a delegate to the CG meeting. 'If its (the Government's) economic successes are matched by a commitment to democracy and human rights, Kenya may yet prove that surging economic growth is not just for Asian tigers, but for African lions, too.' The period leading up to the next general election will be the acid test. </P>
+<P ALIGN="JUSTIFY">E.P. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Country report</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Mali : An omnipresent sense of history</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some countries have a strong folk memory. Despite its size, Mali appears hemmed in by its frontiers. For more than a thousand years, this state was a splendid empire, constantly spreading outward and reflecting the history of the African continent with its conquests and alliances, reversals of fortune and moments of glory. At its height, it extended from the Atlantic to the Sudanese border, from the south of Morocco to the north of Nigeria. Mali's history rests in the minds of its people rather than in any structures inherited from the past. This acts as an antidote to the 'amnesia' often brought on by colonisation, which has the effect of paralysing the future. Although poor, the country has a well-established sense of its place in the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A racial melting pot</P>
+<P ALIGN="JUSTIFY">`</P>
+<P ALIGN="JUSTIFY">On the eve of colonisation, Mali was known es 'west Sudan'. In 1924, the territory then known as 'French Sudan' was split up and small portions of the Malian nation were incorporated into the seven states bordering it-a move certainly not calculated to have a cohesive effect on the remnants of the old empire. Mali has long been a melting pot of races, ethnic groups and cultures. They have learned to live together- intermingling, sometimes forming unexpected alliances, and occasionally fighting one another. The result today is a potpourri where true racial or ethnic confrontation is difficult to imagine. The interplay of history and the mixing of ethnic groups, families and individuals, has created what one intellectual de scribed to us as 'the anti Rwanda vaccine'. Historical mythology offers, perhaps, further evidence of the fusion of cultures in this country. As in ancient Greece or Rome, to take European examples, each ethnic group and each Malian empire, was 'backed' by a host of gods, spirits and totems. In this nebulous world, where dreams beget history and where vastly differing ethnic groups can trace themselves back to a common ancestor, the result was a multiplicity of interrelationships. Under various names, the python totem belongs to many different peoples, including the Peal, Ma/inke and Sarakolle. A study of the migrations of the peoples who make up Mali also reveals a great many relationships - for example, between the Dogon, who are black, and the Shongoi; who are more half-caste. They regard one another as cousins, originating from Aswan in Egypt.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malians appear to share a genuine sense of belonging in keeping with their shared culture. The 'people' of Mali came into being long before the state of the same name. The guerilla war fought in recent years by the Tuaregs (this is the English plural, Tuareg already being the plural form of Targul) against the Malian army, is often viewed abroad as a struggle between whites (or Arabs) and blacks. But this is an illusion. Although the Tuaregs are probably the only 'white' minority in the country, they are an integral ingredient in the melting pot. They are also known as 'Kel-Tamasheq' - those who speak Tamashek, which was originally the language of their Bella slaves. Like all the country's ethnic groups, they have dominated and have in turn been dominated. They have forged alliances with one another, and, more commonly, have united against Arab or Berber invasions. The relative absence of bitterness overall is probably due to the fact that each of Mali's peoples has had its era of glory and imperial dominance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali is lucky to have such knowledge of its history. For centuries, the most precise details have been collected by the griots. The same role has also been played by the many secret societies which have initiation periods lasting, in some cases, up to 50 years. They were, and sometimes still are, repositories for the secrets of history, magic, astrology and science, and also for the symbols of power-the religious objects and artefacts of the former emperors. There are written sources as well, something which is quite rare in Africa. These have been transcribed since the beginning of the millennium and, in recent decades, close collaboration between historians, griots and members of traditional societies has enabled a deeper knowledge to be gained of Mali's history.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A rich empire</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Asselar Man, discovered near Timbuktu in the centre of Mali, was a contemporary of Cro Magnon Man. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cave paintings from five thousand B.C. reveal similarities with those in Egypt and are probably the work of migrant populations from the east, who moved into Mali as the Sahara Desert expanded. Less reliable sources state that interbred populations of Jews and Egyptians under the command of an officer of the Pharaoh Dinga created the Soninke dynasty (originating from Aswan). These people probably laid the found ations of the first great Malian empire, that of Ouagadou. Other sources, equally unreliable, report that they were probably Judaeo-Syrians who arrived at the end of the third century A.D. and found a population already in place. What is more or less certain is that, during the first millennium, a Soninke dynasty was installed around the current frontier between Mauritania and Mali and that 40 princes ruled it in succession in the period prior to 750 A.D. Initially, these rulers were white but, with increasing intermarriage, their skins became darker and darker. To Arab chroniclers, Mali came to be known as Bafour or Bilad es-Soudan (the country of the blacks). At the beginning of the second millennium, the Ouagadou empire held sway over several kingdoms in the south, including the Nigerian delta and a number of Berber principalities. Documents dating from this period have replaced the name Ouagadou with that of Ghana, by analogy, perhaps, with the emperor's title. The empire was already very rich, the richest in the world according to an Arab chronicler who visited it in 970. A work by the writer A/ Bakri, which appeared a century later (1087) went into great detail about the empire's organisation-the system of matrilinear succession, the role of councils of dignitaries, and the capital, Koumbi (whose foundations were discovered in 1914 in southern Mauritania). This city was divided into two districts, one of these being the sacred, imperial city, home to the empire's python totem to which a young girl was sacrificed every year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A story of courage</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The killing of the snake totem is the most significant myths in the country's history. The hero of the story is Amadou Sefedokete whose love for his beautiful fiancee Sia (who was about to be offered in sacrifice), prompted him to descend into the monster's lair and confront it. By killing the totem, he broke the thread of countless generations before him, who had carried out the ritual sacrifice. He is still remembered for this magnificent action, based on love and a sense of nobility, and he remains a subject for artists of all types. His brave action still causes young lovers in Africa to shudder in admiration. However, this act of deicide brought about a reversal of fortunes. The monster's seven heads, which the young hero is said to have cut off one after the other, are reputed to have been scattered to the four comers of the earth, thereby dispersing the empire's riches and leaving it penniless. The true story is more prosaic. Ghana's wealth was eyed greedily by the Arabs and Berbers who had long traded with it. The empire's resistance in the face of Islam gave Moroccan religious fanatics a pretext for organising a jihad. It was invaded by an army of 30000 devotees supported by forces from some of the empire's black vassal states. The 'holy war' began in 1042 ending 34 years later with the occupation of Koumbi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The occupation did not last long but was followed by internal clan wars which brought about the end of an era. Restoration came about at the end of the 72th century , in the small Sosso kingdom, south of Ouagadou (also set up by a small group of Sonink&eacute;). One of the minor kings called Soumangourou Diarasso dreamed of recreating Ghana's empire, and, in 1203, he succeeded in sacking the ancient capital of Koumbi in a move designed to establish his own dynasty. This was an important symbolic act and in the fierce war which followed, Soumangourou subjugated Mand&eacute;, a region which was overflowing with wealth. One of Africa's greatest heroes, Soundjata, rose up against him. He was supposedly the legitimate heir to the Mandingo throne, but was unable to walk, having been born an invalid of a deformed mother who had been married at the recommendation of the king's sorcerer. His young half-brother took his place on the throne and sent the paralysed prince into exile. At the age of 18, Soundjata decided to seize his own place in history and a 'giant' was thus bom. In 1235, his army fought that of the bloodthirsty Sosso monarch whom he himself is said to have cut down in an extraordinary battle. It was a fight which, according to the legends, saw the use of all types of weapon, including magic. Soundjata had forged a grand alliance in order to gain victory. Rather than reducing to vassalage the small kingdoms which had allied themselves with him, the new emperor decided to form them into a federation-although he wisely declared that from Niani (his capital), 'I shall see all'. His empire took the name of 'Mali' (the hippopotamus) on account of that animal's strength and mastery of bath water and land. For 20 years, the empire was to stretch as far as the Atlantic Ocean. Its structure, based on a number of warrior clans, craftsmen, freemen and marabous, is still characteristic of Mali and neighbouring countries today. The empire was rich in gold once again but also in terms of agricultural organisation with the development of cotton and groundout farming. Soundjata disappeared mysteriously in 1255, leaving a prosperous empire.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Conquest' of America?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1285, there was a struggle for succession between two princes and a third, Prince Sakoura (a freed slave), took advantage of the quarrel to take power for himself. Sakoura expanded the empire by subjugating the Timbuktu Tuaregs and the Gao Shongoi: After his short reign, a genuine heir of Soundjata, Aboubakar II, ascended the throne. He had his eye on conquests over the seas and, according to the story, he set sail westwards leading a fleet of 2000 vessels. He was never seen again. However, recent studies favour the hypothesis that he was not lost at sea as had always been supposed' but did, in fact, reach the Americas. A series of ineffective monarchs succeeded this 'conqueror of the impossible', who preceded Christopher Columbus by 200 years, leaving little real impression on history other than the records of their exuberant behaviour. One of them, for example, went on a pilgrimage to Mecca in 1324 with a reported retinue of 60 000 and distributed considerable amounts of gold to all the dignitaries he encountered in that holy place. These kings, however, are acknowledged as having preserved the empire's unity, guaranteeing order without repression and allowing wide religious, moral and sexual tolerance, even for married women. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The kingdom centred on Gao dates back to at least the first millennium but it was usually a vassal of the Ouagadou empire and of Mali. One of its kings, Sonny Ali Ber (known as Sonny the Great), came to the throne in 1464, profiting from the decay of the Mali empire. His reign was marked by a bitter struggle against the Ul&eacute;mas of Timbuktu who, over a period of four centuries following the Almoravid conquest, had converted a large portion of the empire to Islam. The circumstances of Sonny's disappearance are uncertain, but he is thought to have drowned in 1492, the year when a certain Genoese navigator was to achieve the ancient goal of 'discovering' the Malian empire.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sonny Ber's successor did not last long in the face of Islamic expansion. The new Askia dynasty was installed to lead the Shongoi empire, and this expanded with the annexation of Dahomey and part of Nigeria. However, a small part of the former Mali empire never passed under their rule. The Askia dynasty blew hot and cold in terms of religious fervour. Tyrannical at first, it later took a softer line. Under the reign of one monarch, the Gao court based in the university city of Timbuktu became a place of exceptional refinement-only to slide once again into a state of intolerance. One of the Askias, having destroyed the last symbols of the former Mali empire, the city of Niani, set upon his former Moroccan allies. Another emperor, Askia Daoud (1549-1582), turned out to be a fine administrator. He developed agriculture and set up a genuine bank in Gaol War with Morocco continued throughout his reign and beyond. In 1584, imperial force defeated 20 000 Moroccan soldiers, winning a victory which might have been decisive had it not been for internal dissent. This weakened the Askia side and enabled Morocco, with a band of Spanish mercenaries, to take over the empire, following a battle in April 1591. Success was due, above all on this occasion, to the firearms deployed by the winning side. Such weapons were unknown to the 45 000 Malian cavalry and infantry who were engaged. It also turned out to be a Pyrrhic victory. The occupying troops sent the great scholars from Timbuktu University to Morocco, where their peers took up their cause. Moreover, the foreign soldiers were won over by the easy life in Mali-and one of the first results of their presence was a big increase in the half-caste population. In 1612, the troops rejected the Moroccan command: the occupation was at an end and the last few Moroccans were later expelled from Timbuktu by the Tuaregs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Black religious proselytism and colonisation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To each dog his day. In the 17th century, the Bambaras set up an empire around Segou, but the debauched lifestyle of several of the sovereigns and disapproval of the part they played in the slave trade proved to be their downfall. Once again, the history of the country was to be shaped by a slave- Ngolo Diarra-who founded his dynasty in 1766. He was able to restore a degree of prestige to the kingdom, but his efforts were undermined after his death. As a reaction, a proselytising Black Islam then began to evolve.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Massina became a theocratic state around the beginning of the 19th century, in common with other kingdoms which appeared at the same time. One of their most famous rulers, the conqueror El Hadj Oumar, was defeated by the troops of the French General Faidherbe who forced him to give up West Senegal. The days of Malian independence were now numbered. The courage of his successor only delayed the progress of French colonisation, which finally prevailed at the end of the century.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Resistance fighters carried on the war from other points in the old empire, particularly from what is now Guinea. The country was dismantled by the colonial system and pacified, but the end of the Second World War and the return of African soldiers brought a renewed desire for independence. French Sudan became the rallying point for freedom fighters in the French colonies-the old dream of reunification was not dead and buried. In 1946, the Rassemblement Democratique Africain was set up, later to become the USRDA (Union soudanaise-Rassemblement democratique africain). In 1956, the future architect of Mali's independence, Modibo Keita, was appointed leader of the movement and elected to represent the 'Sudan' in the French Assembly. A 'Malian Federation' project was drawn up to include Dahomey (Benin), Upper Volta (Burkina Faso), Senegal and 'Sudan' (Mali). A constituent assembly of independence movement representatives was set up in 1959. However, the constitution adopted by the local Malian and Senegalese assemblies was rejected by the other two. The Federation now had only two members but was nonetheless proclaimed independent on 20 June 1960. In the event, the spirit of unity was lacking and, on the pretext of a rivalry between the two leaders (the 'Sudanese' Modibo Keita and the Senegalese Mamadou Dia), Senegal withdrew from the union in August. On 22 September 1960, the 'Sudan', now without an outlet to the sea, adopted one of the most prestigious names in its history: Mali.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new state was landlocked not only geographically but also, very soon, politically. Modibo Keita's socialist agenda prompted foreign investors to pull out, and the country was organised increasingly as a 'people's democracy'. Fortunately, the repression was not excessive but a sizeable proportion of the population disapproved of the system that had been chosen. Mali and Guinea still had modest aspirations to their old dream of unification. The founder of the Republic, Modibo Keita, was overthrown by a military coup on 19 November 1968. More than the break-up by colonisation, which left dreams of Sudan being reconstituted, this military putsch sounded the knell of the old empire. Mali became just another state whose colonial and post-colonial eras have been marked by a lack of success. Nevertheless, a sense of history is still omnipresent. </P>
+<P ALIGN="JUSTIFY">Hegel Goueier</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Three republics to create one democracy</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is just something you have to get used to-in French-speaking Africa, virtually all countries have imitated France in assigning a number to each republic formed under a new constitution. At the time of its independence on 20 June 1960, Mali was a federation of two states; Senegal and the former 'French Sudan'. It was an alliance which failed after only a few weeks'existence end 'French Sudan' then adopted one of its most prestigious former names- Mali. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first regime, under Modibo Keita, became increasingly unpopular as its form of 'tropical' marxism caused it to become more and more isolated. One of its main shortcomings was its unrealistic five-year plans, none of which were ever implemented. Discontent became rife among various social groups. including the farmers who, opposed collectivisation and were adept at passive resistance which they employed to disrupt the supply of produce. The regime also modelled itself on the so-called 'people's democracies' in certain respects. For instance, it made a determined effort to improve education, health and social justice, while refraining from the more dictatorial excesses that often characterised such systems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initially welcomed by some sections of the population, the November 1968 putsch, by Lieutenant Moussa Traore quickly fumed into dictatorship although it was to be more than 10 years before there were any significant anti-government protests. At the end of 1990, opponents of the regime openly set up organisations which claimed opposition-party status. One of these was ADEMA (the Alliance for Democracy in Mali), formed by the current President of the Republic, Alpha Oumar Konare. Marches calling for a multi-party state attracted the support of tens of thousands of people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The dictator then sought to neutralise the opposition, beginning with the Tuaregs in the north who had been waging a guerilla war. This conflict was viewed by many as the 'front line' in the people's struggle against dictatorship, and the Tuareg cause was supported by opposition movements. The government, which had for some time opted for 'soft' repression, now revealed its claws and in January 1991 it began to imprison student leaders. The streets were filled with armoured vehicles and the first death amongst the students brought condemnation. Repression reached its height on 22 March 1991, when several dozen students were killed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prior to this, in February 1991, Moussa Traore's UDPM (Democratic Union of the Malian People) came out in support of a multi-party system - a move which marked the beginning of the end of the regime. The day after the students were killed, a democracy coordination committee launched an appeal for a general strike, to last until the dictator was overthrown. This began on 26 March, and amounted, in effect, to a 'democratic' coup d'etat. Its instigator was Lieutenant Colonel Amadou Toumani Toure, who took charge of the transition to-tether with the democratic movements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The former dictator was arrested and put on trial for his crimes. He was later condemned to death but his sentence was recently commuted by President Konare.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Tuareg guerilla war continued despite the government's conciliatory attitude. The new administration also had to deal with a number of social claims which had long been stifled by the dictatorship. However, popular support for the regime remained firm. The new constitution was adopted virtually unanimously in a January 1992 referendum and, a week later, ADEMA won the municipal elections, the first in a series of electoral victories for Alpha Oumar Konare. He went on to win the Presidential election (for the Third Republic) in April, with almost 70% of the vote. Meanwhile, negotiations with the Tuareg rebels resulted only in signatures on agreements which were not observed. The situation grew worse with the Ghanda Koy counter-offensive, but this in turn led to a seemingly viable accord between the Azawad Arab Islamic front, the most important guerilla movement, and the Malian government. Last March, President Konare presided over an enormous bonfire of weapons seized from the former guerilla fighters. The flames lit up the skies above Timbuktoo, the symbol par excellence of rapprochement between the peoples of Mali.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the beginning of January 1994, the regime suffered the effects of the devaluation of the CFA franc. Economic liberalisation had enabled Mali to improve its macroeconomic position, but social discontent, particularly in the towns and cities, demonstrated that the average citizen was continuing to suffer economic hardship. The President still enjoys considerable support, and political democracy is greatly appreciated. Obviously, the government cannot be blamed for all the difficulties facing the country. There is, for example, a lack of professionalism in the press. However, it could have given a lead in the case of the State media, which still studiously avoids criticising the government's actions. The administration has also been taken to task for its apparently lax attitude towards 'economic' misdemeanours.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Next year will see a series of elections. The government views these with apprehension, although it has stolen a march over its rivals by signing a political accord with several small parties. Opposition is centred around the MPR (Patriotic Movement for Renewal), the revamped former party of the dictator Moussa Traore. This has undergone a 'facelift, and now seems to be regaining support. lts trump card is decentralisation. Its former leaders, who held total power for a quarter of a century, can take advantage of the network of contacts they built up. The US-ADA, the party of the Republic's founder, Modibo Keita, which until recently appeared to be the herald of change, seems lately to have restricted its role to that of arbiter. Surprises are in the offing, but one thing is certain: the Third Republic's constitution will remain the guarantee of democracy in Mali. </P>
+<P ALIGN="JUSTIFY">H.G.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Interview with Ali N. Diallo, President of the National Assembly</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Mali, the army has learnt if from the past</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali's institutions were radically remodelled in the wake of the recent vote on decentralisation. This is aimed at allowing, among other things, a degree of autonomy for the north of the country-which is essential to guarantee national reconciliation. The sudden growth in the number of small towns and villages may result in some political surprises during the long e/ection campaign period which is due to begin early next year. The President of the National Assembly, Ali N. Diallo, finds himself in a pivotal position: his Adema (A/fiance for Democracy in Mali) party current/y holds a comfortable majority in Parliament. With democracy being consolidated in Mali, he must find this an exhilarating time. Our frst question touched on this</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-This is certainly an excellent time to be in Mali, but freedom is the most difficult of man's needs to satisfy. Our National Assembly has 12 parties and most people in our country are inspired by ideas based on tolerance and respect for the right to be different. The main concern of those of us who lead the party currently in the majority, is to question constantly whether we are necessarily always right. We have a comfortable majority-72 members out of 115-but this certainly doesn't mean that the National Assembly is just a rubber stamp.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· There is, of course, another stumbling block when one has such a large majority, which is the possibility of internal divisions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Yes, I would agree with you there. Mali's MPs have to realise that they came into this business after a three-stage process. First there was a popular uprising, then the army intervened to put an end to the bloodbath.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, we had the high level national conference to draft the constitution, the electoral code and the charter for the country's parties. MPs, therefore, must always bear in mind that, though they can claim legitimacy on the basis of the revolution, there is also a republican legitimacy they ought to respect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The second phase in the process was the intervention of the army-are you not a*aid that the 'Niger syndrome'will raise its ugly head in Mali, too ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Naturally, MPs have seen what happened in Niger and elsewhere, but fear is tempered here because officers in Mali's forces have also given a great deal of thought to the effects of military dictatorship. Democrats and republicans within the armed forces are very aware that only a minority of men in uniform profited to any degree from the previous regime.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think that because Mali had what might be called a 'moderate' dictatorship, it is now in a better position than it would have been had the previous administration been more repressive ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Let me put it this way. The military dictatorship went through three different stages. During the first stage, just after the coup on 19 November 1968, the junta chose Mao Tse Tung as a model, hammering home the idea that power could be won by force of arms-and it was carried away by the popular acclaim it initially received. Subsequent popular resistance then took them by surprise. People wanted more freedom, but they also wanted to keep what they had gained in social matters. Army officers asked the protestors to abandon their action so that normal constitutional life could be resumed, but the trade unions had their own ideas. They advocated things which the people in power opposed. The ensuing repression was therefore fierce.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was a second phase during which the military were at odds with one another over the leadership question. The popular view was that the country had fourteen different heads of state at that time. This went on until 28 February 1978 when there was a brief Iuli and they were tempted to return power to the civil authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Then came the third phase when, despite appearances, poverty was on the increase. At first, Malians said that there were two 'IMFs' on the loose in Mali-the International Monetary Fund and the intimate circle surrounding the Moussa family. When the social foundation of the regime contracted, and all the country's business became concentrated in the hands of Moussa, his wife and her relations, the popular forces went on the offensive. This was a period of vociferous protest. Moussa Traore reacted with brutality: hence the 200 dead amongst the schoolchildren and students who were protesting- we will never know the exact number.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yet, the former regime could be said to have made the crucial economic choices which your government has continued with. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I wouldn't agree with that. There was a half-hearted discussion at the time about liberalising the economy but, in reality, bureaucracy got in the way. It is the economic laws voted in by ourselves which form the true basis of a liberal economy. However, if you really want to look to the past, I would say that it was the February 1967 accords signed between Mali and France, when we came back into the franc zone, which set the whole process rolling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The Tuaregs and the government have just signed an agreement but the question of the north of the country is still a sensitive one. What are your views on this subject ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-The problem in the north of Mali is extremely complex. First, the Malian nation is made up of a patchwork of minorities, the largest being the Ban Mana (Ed. 'Bambara' in the colonial vocabulary), but no ethnic group is larger than all the others put together. Second, all groups have, at one time or another, held supremacy. But the fact is that the peoples involved have all lived in the same area throughout history- they have shared joys and sorrows, and their blood has mingled on Malian soil. l would accept that the Malian nation is not as well consolidated as it should be, but it is arguably one of the most advanced in the sub-region in terms of its constitution-though I don't mean to sound chauvinistic here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anyway, the problem in the north of the country seems to me to be one of development. The various regions have not all developed at the same rate on account of climate differences. In addition, the dictatorship did not show any great respect for minorities - although it did not direct its actions solely against the Tuaregs, who resorted to arms. The Tuaregs exaggerated the mistreatment they had suffered because they were unfamiliar with what was happening in the rest of the country. In fact, Moussa Traore oppressed everyone: the French-style Jacobin state we inherited did not allow for regional differences. After independence, the regime redoubled its efforts to centralise the state. both because it was Jacobin in outlook and because of Modibo Keita's communist leanings. In 1959, the French forced the Tamashek (ea. 'Tuaregs') to secede-Max Lejeune and Houphouet Boigny were mixed up in all that. This was when oil was first discovered in Algeria and the war with Algeria had been in full swing since 1954. Modibo Keita set up the Malian Federation and declared in 1959 that, upon independence, he would withdraw all soldiers from the Algerian front. Since the Malian Federation was dismantled, Gao virtually became an Algerian willaya, a base camp for its fighters. Mali did not accept this. Moreover, Algeria, around the time it achieved independence, took retaliatory measures and sealed off its borders, mercilessly sending back huge numbers of refugees. It mobilised them through humiliation, telling them that they were the last members of the white race-the only ones to allow themselves to be under black rule.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· But when Ganda Koy's militia halted the Tuareg movement, they appeared to have been supported by the black population. Doesn't that also suggest a racist attitude ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I addressed the Tuaregs in October 1992, and pointed out that their wish to regard themselves as overlords and the other peoples in Mali as vassals who ought to pay tribute would provoke a general uprising, with the risk of a slide into civil war. I told several of the Tuareg chiefs seated around me the legend of Ouagadou- about the serpent of the well who each year demanded that the Soninke people should sacrifice an 18-year-old girl in its honour. Then the day came when a young man refused to accept the sacrifice of his fiancee. He went down into the monster's lair, watched by a horrified crowd who saw his recklessness as folly, and cut off the serpent's head. In the beginning, the Malian people's sympathies in fact lay with the rebellion. On 26 March, when the rebellion against the dictatorship took place, the president at the time, Konare, asked for all the Tuareg chiefs to be brought to him so that they could set up a transition body. He got a nasty surprise when the Tuaregs resorted to arms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Was the government, as rumoured, behind the Ganda Koy ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Not the government as such. To my mind, it would be wrong to applaud when one faction of the people one governs wants to exterminate another faction.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· It appears that some of the people are unhappy with the concessions that have been made to the Tuaregs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-This is a myth. The idea that we are frustrated because the Tuaregs were once our masters, is a story put about by Europe. The situation is quite the reverse. At the time of colonisation, they were unwilling to ream, like other nomads, such as the Peul people, for example. There were splits with them, of course, but no actual, all-out war. Forging a nation always requires tears, sweat and mourning. Those who return will find what they left broken or stolen and will want land which is less barren than that impoverished by the encroaching desert. However, those who stayed put in the face of rebel attacks had their houses smashed and their animals taken away. There will be problems when some Peals, for example, identify their cows which were stolen. We will have to negotiate, but I have confidence in the people. Just as they ended the war, they will be able to heal the wounds-of this I am sure. And the process has already started.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· I gather that you continue to practice as a doctor, on top of your political duties. Is this to teach a moral lesson to your political colleagues ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I would say that it is more of a weakness, an inability to abandon a passion, even for supposedly good reasons. l am an 'internalist' and I have a passion for mechanisms. If you cure an infection and it returns, you have to look elsewhere to solve the problem. There are those in authority who spend money on trying to tackle problems without troubling to locate the cause. I would like to think that the analytical rigour of clinical science might also be put to good use in promoting understanding in politics. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Profile</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Area: 1 240 190 km²</P>
+<P ALIGN="JUSTIFY">Population: 10 million</P>
+<P ALIGN="JUSTIFY">Population density: 8.15 per km²</P>
+<P ALIGN="JUSTIFY">Population growth rate: 3.1 % </P>
+<P ALIGN="JUSTIFY">Capital: Bamako (pop.700 000) </P>
+<P ALIGN="JUSTIFY">Other main towns: S&eacute;gou (65 000), Mopti (52 000), Sikasso (50 000), Koutiala (37 000) </P>
+<P ALIGN="JUSTIFY">Languages: French (official language), Bambara, Peul, Shongoi, Tamashek </P>
+<P ALIGN="JUSTIFY">Curreny: CFA franc. In July 1996,1 ECU was worth CFAF 647.5 ($1 = CFAF 515) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Politics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government: Mixed presidential and parliamentary system. Greater powers are due to be transferred to the regions after the next elections. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Head of State: Alpha Oumar Konar&eacute;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister: Ibrahim Boubacar Keita Political parties represented in Parliament: ADEMA (absolute majority). 'Opposition' - CNID, USRDA and numerous other smaller groupings. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p021.png"></center><br>
+ Map</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economy</P>
+<P ALIGN="JUSTIFY">(1993 figures unless otherwise stated) GDP: CFAF 753.8 billion</P>
+<P ALIGN="JUSTIFY">GDP per capita: $530</P>
+<P ALIGN="JUSTIFY">Origin of GDP by sector: agriculture 42%, industry 11 %, services 47% </P>
+<P ALIGN="JUSTIFY">Real GDP growth: 2.4%</P>
+<P ALIGN="JUSTIFY">Balance of payments: deficit of CFAF 84.1 billion (estimated) </P>
+<P ALIGN="JUSTIFY">Main trade partners (% of total trade) </P>
+<P ALIGN="JUSTIFY">Exports: Thailand (24.2%), Brazil (19.1%), Ireland (9.7%), Belgium/Luxembourg (9.7%) </P>
+<P ALIGN="JUSTIFY">Imports: C&ocirc;te d'lvoire (22.2%), France (14.5%), Senegal (9.7%), Hong Kong (4.6%)</P>
+<P ALIGN="JUSTIFY">Main exports: cotton 40%, livestock 28%, gold 17.5%</P>
+<P ALIGN="JUSTIFY">Annual inflation rate: 3%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social indicators</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy at birth: 46.2 </P>
+<P ALIGN="JUSTIFY">Infant mortalityper 1000 live births: 158 </P>
+<P ALIGN="JUSTIFY">Adult literacy: 28.4% </P>
+<P ALIGN="JUSTIFY">Enrolment in education (primary, secondary and tertiary): 16% </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Human Development Index rating: 0.223 (171st out of 174)</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Interview with Amadou Seydou Traor&eacute;, opposition leader and USRDA spokesman</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Macro-economic indicators tell you nothing about the distribution of the country's resources'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· It cannot be easy to be in opposition when Parliament is dominated by a majority which is given a good press and is regarded abroad as a good pupil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We do not really find it a problem. If one is familiar with Mali's current situation, the people's views, reactions and judgments count for more than outside opinion, despite the fact the latter may seem important. However, we do take account of others' opinions. We are pleased to be able to speak to you-to express our ideas and points of view- so that outsiders can see that the USRDA offers a credible alternative for Mali. We feel quite secure in our current position because the principles and values we stand for are those closest to the Malian people. So we have no problem in being the opposition party. We are not the kind of hysterical opposition which resorts to foul means as well as fair ones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Given that most Malian political trends stem from the revolutionary democratic movement, what are your party's special features ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Our party's origins are in the movement which dates from 26 March 1960-which itself grew out of an underground movement. The main component of this was the USRDA whose government was overthrown by a reactionary military putsch. Adema won the last elections, and we do not contest this fact despite a number of irregularities. Indeed, we supported the Adema government's initial actions. We were one of seven parties who regarded the Third Republic as our own offspring. Between 1992 and 1994, even when we faced grave difficulties and they were asking for suggestions, the government ignored our proposals. This happened, for example, at the time the World Bank threatened to pull out. As it functions at the moment, the government is not meeting the Malian people's basic aspirations. They want to see a change from the previous regime.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What are your essential criticisms of the way Adema works ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We are critical on a number of fronts. Looking at it first from an institutional standpoint, when the Malian people rejected the old regime, they wanted the existing set-up to be changed into a democratic one. The few institutions that have been established since then do not reflect this desire. They are virtually no different from what we had under the single-party system. True, we have an opposition party, but its views are ignored. Second, in terms of the management of democracy, a number of bodies, such as the State Commission on the public media, simply do not function. You have been in Mali for a week now, so you must have heard Adema spokesmen on the TV or radio. But you will never hear a member of the opposition. The space reserved for that -formerly an open forum for free political discussion-has been removed and the state-controlled TV and radio stations do not allow political parties to have a say. In the economic sphere, our approach is also completely different. We believe that support for the development of the private sector means that the state has to act as regulator. Economic development cannot simply be left to run its course as a kind of 'rat race'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Could you give us a few practical examples of what you describe as Use selling-off of the family jewels ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-With pleasure. Before the 26 March revolution, there was a general consensus that, in the process of privatisation, the state sector should be managed in a way that benefited the Malian economy. But the reality is that privatisation methods have not changed. They are no different from what they were in Moussa Traor&eacute;'s time. The electricity sector, for example, which has not yet really been privatised, is now managed by the Bouyges group of France. And it costs more, which will hardly help the country's economic development. The state airline has simply been absorbed by Air Afrique. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· If you were in power, how much economic scope do you think you would have, given the prevailing trend towards international liberalisation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I recognise that there is a dominant international lobby which has drawn up its own conditions, laws and principles. Even if one does not agree with this approach, one has to take it into account. However, it should be feasible to achieve privatisation in a different way. We know what we are talking about because we used to run this country. Indeed, we set up the national economy. Before 1960, there was no economic system to speak of. l am currently completing the text of a work which looks at our economic position at the time of independence. The plain fact is that we had nothing at the time of independence. There were only three pharmacists, fewer than ten doctors, and about ten people qualified to teach in our grammar schools-not much to write home about after 70 years of colonialism! After 1960, we had to set everything up from scratch. If you trace the history of every country in the world, whether under a monarchy or a republic, you see that the state has always made the first move in bringing about industrialisation, developing the maritime sector, and stimulating imports and exports. If you think about it, at the outset, the main manufactured activities were the domain of royalty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You claim that your party left a legacy, but some might say that the highly interventionist regime of your hero, Modibo Keita, who brought about independence, contained the seeds of Moussa Traore's dictatorship.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-These are just fairy stories. When a regime is overthrown by a coup d'etat, it always becomes the victim of systematic defamation campaigns in the press. We were maligned for 23 years with no right of reply and no right to issue a statement to set the record straight. In a way, we are talking today about a past which did not exist. You know the saying 'you are not only what you are but also what people say you are'. This reference to dictatorship is one of the most serious calumnies. But no matter what lies are told, something of the truth will always remain. If our regime had been dictatorial or inquisitorial, a coup d'etat would not have been possible. Before the 1968 coup, Modibo Keita was given a file by the security services warning him of the plot by Moussa Traore, and giving a list of his accomplices. He was advised to arrest the conspirators and put them on trial. His response was that he would not agree to a Malian citizen being deprived of his liberty without a scrap of evidence. I knew Keita very well. It will be a long time before we have another head of state with such democratic convictions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The ordinary people, the farmers, say that they did better under Traore, than under Keita.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Yes, but it depends who you talk to. With Traore, there was an atmosphere of moral decline. We were free to plunder, steal and murder, but it was not real freedom. The farmers see it from a different perspective. However, l can still show you a copy of the 'Summary Report on the Seminar on Cooperation in the Rural Environment' which we drew up in 1968, just a few months before the coup d'etat. This highlighted the fact that socialism had not penetrated into the countryside during the seven or eight years we were in power. So you see our own self criticism appeared in a document published in May 1968. This demonstrates the fact that we were not complacent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What is your view of the compliments the current government is receiving from many foreign observers, and the good marks it has been given in the macro-economic field by international institutions ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Good macro-economic results which are due to good management of public finances are beneficial for the country. However, such management must be accompanied by greater welfare and an improved standard of living for the people. There is no point hailing a GDP increase of 3-4% if more than 10% of the population does not have enough to eat. You have been through Bamako and other towns and cities and you have seen the construction sites and big buildings. But in their daily life, people are now more ill at ease. They have been disappointed by the Adema regime. The welfare of the ordinary citizen cannot be defined by reference to the personal wealth of someone who is having a seven-storey building put up. All of this new construction is reflected in the higher GDP. But the macro-economic indicators tell you nothing about the distribution of the country's resources-and the scales are currently tipped towards injustice. Those who are working are earning less but those who do not work are earning more. Embezzlement and corruption are currently worse than under Moussa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What is the likelihood of a changeover of political power given that the opposition groups are at odds? The union between yourselves and Parena appears to have been suspended.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We are capable of winning the forthcoming elections without entering into an agreement with any other party. Having said this, we are the party to which most groupings in Mali are now turning and we are currently in the process of forming an alliance which will carry a great deal of weight. l am not one to speculate but I am sure that Parena's supporters will, in time, reach the same conclusions as ourselves regarding the timeliness and suitability of an alliance between us. We have contacts with a number of other parties but we do not want to form an electoral pact in the way one would make preparations for a coup-forming a group, ousting the regime and then shooting at each other! Moreover, it is important not to confuse change with restoration. There are those who advocate the restoration of Moussa's regime. Opposition of that kind would suit the current government very well because it would allow them to raise the spectre of our former dictator in the hope of attracting support from those who are frightened by such a pro spect. </P>
+<P ALIGN="JUSTIFY">Interview by H.G.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The magnetism of the unfamiliar... but unexotic</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In West Africa, there is a dry, desert-like region which a river tried to bring under its sway. Instead of flowing seawards, the river's path went in the opposite direction to find this region, impulsively tracing a majestic loop of 2000 kiLom&eacute;tres before heading seawards. The Niger may not have provided an ideal site for Mali's major towns and villages, but it was considerate enough to form a major waterway between them which is navigable over almost its entire course. Its network of tributaries has resulted in the formation of large landlocked lakes whose waters are full of fish-a reminder of the times when the Sahara was one huge expanse of water. It has also resulted in the extraordinary Niger basin, a central delta area the size of Belgium, criss-crossed by lesser tributaries which reach into the smallest valleys. The river has created a diverse landscape which entices the visitor back. The land is steeped in history and if one wishes to learn its secrets, one has no choice but to study the empires of the past, forged it is said, by mythological deities and heros.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the dry season, visitors marvel at the beauty of the plains, which stretch as far as the eye can see. They will be tempted to return to view the waters that will cover them for just a few months during the rains. This is when the towns and villages appear as islands in the flooded landscape. Later in the seasonal cycle, Nature divests itself of its watery raiment and prepares to welcome the egrets, pink flamingos and all the other richly coloured birds which have flown in from afar. The cultural life of this region is also imbued with a rare richness, combining mystery and individuality. Mali has a distinctive character: it is accessible but not adulterated by frippery, welcoming but not taken over, affable but able to treat everyone as its equal. There is no need to make constant reference to the past which existed before colonial times-the past simply exists, eloquent in its tranquil humility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A survey of Mali should logically begin in Bamako, the likely port of arrival. But if one immediately journeys to the towns and villages that were the cradles of empire, one is better able to appreciate this young capital, barely 250 years old, whose history owes much to its smaller forebears. We arrived in the evening and departed at dawn the next day. So Bamako was no more than a blur. The River Niger, still known as the Djoliba in the capital, is crossed by two long bridges which offer a view over the wild river banks. Most of the constructions are brand-new and some have a style borrowed from their thousandyear-old 'Sudanese' architectural heritage. It would have been more romantic to travel by river to the central part of the delta but, despite the welcoming nature of the Niger as it flows through Mali, it is difficult to navigate over the Sotuba rapids, between Bamako and Koulikoro approximately 50 km away. When the waters are in spate from July to December, it takes no more than two days to reach Segou, three to reach Mopti, five to reach Gao and an extra day to arrive in Timbuktu.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Segou, the rebel</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Our first stop after Bamako is Koulikoro, the departure point for Niger cruises. After the unusual houses of the bazo fisherman on the banks of the river, as one leaves Bamako, it is the river itself which is a source of curiosity, transforming the voyage into a wonderful promenade through a forest abounding in game. Then there are the thatched, circular mud huts. Those without a roof are built on piles and are often ovens for preparing karite-nut oil whose bitter-sweet fragrance mingles with the fruity scent of the mango trees which line our route. In Koulikoro, every day is market day. The market spills out into the road and then shrinks back to allow vehicles to pass. It is also a centre for hunters and poachers who come here to seek customers. Above all, it is the centre for the guilds of masons who jealously guard the secrets of traditional Sudanese building skills. For the visitor who cares to linger, the griots will sing the praises of the old magician-king Soumangourou whose spirit has haunted this small town for eight-and-a-half centuries. When he was overthrown by the hero Soundjata, he just vanished into thin air-in the land of mystery that is Mali, great kings do not die, they simply disappear.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first 250 kiLom&eacute;tres of the river's course from Bamako are enchanting. One's first real encounter with Mali's past come at Segou-when the balanzans come into view. The charming, independent city is close by. Segou, the Bambara capital, did not form part of most of Mali's empires. Indeed, the word Bambara comes from 'Ban-Mane', which means 'those who reject a master'. There are 4444 + 1 balanzans to announce the city, all of which are numbered except the last one, which still guards its secret. The balanzans conceal another secret: during the dry season they are covered with leaves, which they lose during the winter. A curious traveller might arrive at Segou with memories of Maryse Conde's fine prose (Segou, Robert Laffont, France, 1984). Her work is an epic fresco of life at the court of the Bambara kingdom in the nineteenth century. The city itself stretches for eight kiLom&eacute;tres along the river bank, with a promenade high above the river on an embankment from where there is an uninterrupted view over the water to the horizon. The richly coloured fabrics of the washer women create a dreamlike atmosphere, giving an impression of the shimmering tunics worn by princes, and the women who swim in the river are not given to excessive prudishness, another reminder of the city's enduring rebellious nature. The charm and cleanliness of the town are striking, its administrative buildings stretching along a grand boulevard lined with modern structures. We see in their profiles, the traditional architectural styles as well as a variety of colours. The whole scene is shaded by gardens full of flowers. It is easy to forget that Segou has retained none of its former architectural wealth. This was all destroyed by the organisers of a jihad who sacked this city of infidels who had never been won over to Islam or, later, to Catholicism. The city walls and the regal courtyards are all gone, so what remains is jealously protected: the sceptre and regal symbols of King Diarra, the kingdom's treasures and its secrets. On Mondays, market day, it is possible to see people kneeling at the feet of an old man. He is the custodian of the town's remaining riches, but will never reveal where they are held. Oumar Santara, one of Segou's intellectuals, is attempting to gain an insight into these mysteries in order to protect them better because, he says, the pillage is still going on. Mali's cultural heritage is being ransacked by outsiders. In some villages on the opposite bank of the river, it is still possible to find 13th-century coins in the village squares.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trial marriage</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nearly 500 kiLom&eacute;tres separate Segou from Mopti. Midway between the two is San, barely more than a large village. San is bathed by the waters of the Bani, a major tributary of the Niger which it flows into it at Mopti. In the market, fine cotton fabrics can be bought, as can the skills of the blacksmiths. Here, however, there is above all an air of secrecy. The town's inhabitants are members of the Bobo people. The name translates es 'stammering', 'mute' being implied. This is the town which holds the secrets of fatal poisons- cocktails of poisonous plants and snake venom. There are also unguents of all kinds to relieve pain, alleviate scarring, and so on. San has another reputation, that of handing out severe punishment to adulteresses. This seems paradoxical when one discovers that women here enjoy exceptional sexual freedom during adolescence and up to the time of their marriage, and even afterwards. They enter into a trial marriage for three or four years, during which time they are free to 'play the field'. At the end of this period, on the occasion of a feast, they reveal whether or not they will accept their 'provisional' husband. If not, the woman regains her freedom and can start all over again as many times as she wishes. If she decides to become the man's wife, she chooses some of her husband's friends with whom she may 'have a fling' for two weeks, the aim being that she thereby lays to rest her unmarried freedom. She will then swear an oath of fidelity to her husband which she breaks on pain of being cast out of society and even, it would appear, at the risk of losing her life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A 1 2-kiLom&eacute;tre dyke, which seems to float on the water during the winter season, links Sevare, the crossroads of the major routes across Mali, to Mopti. Situated below water level, Mopti owes its existence to the embankments which protect it. The dyke offers a fine promenade which opens out onto the quayside of this bustling town. The streets are crowded and the settlement has a vitality and beauty, with coloured lights mirrored in the water. On land, the crowds drift in much the same way as the multitude of boats anchored in staggered rows along the riverbank. These stretch for hundreds of metres- as far as the eye can see. All this wealth of detail forms a tableau punctuated by the outlines of the slender fishing smacks (pirogues or dugout canoes). Despite their size, these vessels retain their uncluttered lines, always giving the impression that they are slicing through the water. The biggest of them are perhaps 50 metres long, carrying cargoes of up to 150 tonnes. This strange, animated scene, which resembles no other in the world, seems to have been staged as a way of reviving the buried images of the Mali of legend-provoking a memory of things unseen and prompting new sensations. Despite the fact that it is replete with Malian influences, Mopti did not develop until colonial times. Like Segou, it never really belonged to any of Mali's great empires, although it became their meeting point. It is a place where all the country's languages are spoken. Indeed, the word 'mopte' in Peal means 'place of assembly'. At Zigui's restaurant or in a cafe down by the port, one find groups of beribboned Tuareg artisans still with their belle servants (former slaves) in tow. One can watch the Peals, also followed by their servants, negotiating their deals. Some trade in gold jewellery, dogon or other ethnic sculptures. Others buy and sell the magnificent Segou carpets or cotton fabrics. Others still dabble in ancient archaeological artifacts (which it is forbidden to sell) and in sacred objects from all over the country. The town itself is an artifact: the apparent hotchpotch is regulated by an internal, almost natural organisation. The hundreds of boats, fishing smacks and other small craft are arranged along the river banks according to the goods they are importing. There is one place for fishing boats, another for furniture imports, and so on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mopti merits an overnight stay. In the curve of the great arc which forms the port, a soft light lingers on the congested river banks. It is not just the people who seem to tire of the day's hustle and bustle. The biggest boats with their gentle backwash, anchored in the mud until the next incoming tide, grow too lazy for their images to be reflected in the water and they seem to hold on to the last of the sun's glow, awaiting the first glimmers of moonlight</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Dogon region, poetry in stone</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As one approaches Bandiagara, on the threshold of the cliff faces which bear the name of this town, the landscape changes. Most of Mali is flat, but here, we find ourselves in the high land. In fact, the altitude is only a few hundred metres, but the landscape is dominated by sheer and rugged rock faces. This is Dogon country where everything seems to be made of stone: the roads, houses and hills appear in matching tones of salmon pink. The inhabitants, too, seem to have been hewn from the very rock. At first glance, the landscape is unremarkable apart from the sight of all this rock, but as one's perception grows keener, shapes can be made out. At the foot of the slopes are caves that are still lived in. And in the most vertical part of the cliff faces, we can pick out regular, sculpted barrel shapes, combining to form an impressive design. These stone cylinders are the ancient dwellings of the Telems, a mysterious people who preceded the Dogons and were conquered by them. Nothing is known about their disappearance. Today, the cylinders are used as Dogon graves. Access is gained to them during funeral services, by means of a system of ropes. At the top of the cliff is Shanga, the beauty of the Dogon region. It stands atop a 400metre sheer drop which extends over a length of 200 kiLom&eacute;tres. Reaching Shanga from Bandiagara involves picking one's way through the rocky landscape and sliding over sandstone scree.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before the Europeans arrived to colonise the country, no one had succeeded in subjugating the Dogon region. Was it really ever under the sway of the colonists ? This region, whose beauty lies in its harshness, has no embellishments. And its language is as hard on the ears as the rock is underfoot. As everywhere, to feed themselves, the Dogons till the soil. But this must be carried on the backs of men and women over distances of several kiLom&eacute;tres and then deposited on the rock. Every onion bulb and every root pulled from this thin layer is a testament to the tenacity of humankind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Dogon region is like a magnet-it attracts pilgrims from afar who come to venerate El Hadj Oumar, the founder of the Islamic brotherhood of the African Tidjani-a military and religious leader whose life and disappearance are shrouded in mystery. It also attracts people because of the beauty of its works of art. Some of these, apparently of recent manufacture, are actually centuries old. For the custodians of the sacred objects, the interest of outsiders is viewed as a catastrophe. The artefacts are constantly pilfered and sometimes, their keepers commit suicide in their horror at such desecration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fine regalia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Djenne translates as 'the beloved of the waters' and is surrounded by two strekhes of the Bani river. Thus, apart from a short time in the dry season, when the river can be forded, it is an island accessible only by boat. The town has always been a rival of Timbuktu, the 'daughter' of the desert. Before Mopti was created, Djenne was the country's meeting point. The town is dominated by its mosque which is a masterpiece of Sudanese architecture. This imposing clay structure has been a magnet for the faithful since the thirteenth century. It has always been rebuilt in the same style, each version scrupulously identical to the previous one. The most recent reconstruction dates from the early 1900s.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Centre of the Malian empire, Djenne has retained all its finery, magnificence and prestige. It was annexed by the Shongoi empire at the end of the Middle Ages and its conquerors have always been seduced by the town's beauty. The mosque has been designated a World Heritage Site, and the entire town has protected status. For centuries, its architecture influenced other towns and cities in the Sahel and it continues to do so. The secrets of the knowledge and skills of its master masons are still jealously guarded, passed on only reluctantly to the initiated. The whole town is built around the mosque, revealing an interplay of balance and power. There are magnificent inner courtyards to which entry is gained through massive, ornate studded gates. The elaborate and finely carved windows, the intertwined leaves and scrolls of the arabesques and the moucharabies, all bear witness to the Moroccan influence. This has, however, been toned down and it now blends in with Djenne's indigenous forms of decoration and architecture. Whilst all Mali's former great towns and cities were known for their power and military glory, Djenne takes pride in having dispensed with brute force, its spirit protecting it from subjugation. All those who pass through take something of Djenne's spirit away with them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coca Cola kept at bay</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Returning to the capital from where we started, we discover that it was colonisation that turned Bamako from a village into the large city that it is today. It inhabitants now number approximately one million. Although a city of recent origin, the site on which it is built dates back to the dawn of time. The hills overlooking the city are home to cave paintings and the underground tombs provide more evidence of a human presence dating from ancient times. There is then a gap of several thousand years in Bamako's history. In early colonial times, just two centuries ago, the village had no more than 700 inhabitants. Bamako began to be developed at the beginning of the 1900s and it is the only city in Mali to have a colonial atmosphere. It has not, however, lost out to change. The ministerial buildings at Koulouba hill, one of five dominating the city, or the Point G houses in the National Museum area, may not equal the beauty of Sudanese architecture, but they are elegant nonetheless. Their plain style is softened by their leafy gardens. The administrative buildings in the lower part of the city are often a fusion of colonial or modern styles and traditional architecture. These edifices are also made more attractive by fine gardens, which lend originality to the city. One of the most successful combinations is the great market, unfortunately in the process of restoration at the time of our visit and whose beautiful interior we were unable to appreciate. It is interior beauty which characterises this city in comparison with other African capitals. Despite its congestion and the density of its population, Bamako still has the atmosphere of a lively village. There is little of what one might term a 'social scene', but it is enough to be invited into the 'squares' or respectfully to visit the block-shaped houses which are still home to entire families and where discussion sessions (grins) last into the small hours. These sessions are enhanced with food and the omnipresent cup of tea. Bamako still prefers tea to imported beverages and to receive guests in the family home rather than joining in the social round in the hotel foyers so characteristic of major capital cities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For those hesitant to venture into the traditional life of Bamako (although they would be assured of a welcome), there are many restaurants which make a good attempt at recreating a homely atmosphere. One is not, however, required to take part in the conversations. Two restaurants (the Djenne and the Santoro), which have opened recently, allow one to enjoy the pleasures of art and history. They are part of a wider project to promote Malian art and set up an organisation for artists and craftsmen. They contain areas modelled on the refinement of former imperial furnishing, interior design and architecture, as well as exhibits by Mali's greatest artists. Their creator, Aminata Traore, is an intellectual, art connoisseur and international expert. In Dakar or Abidjan, patrons of such establishments would probably be expatriates with perhaps a few local dignitaries. But at the Santoro and Djenne, prices have been kept reasonably low (no account having been taken of the 50% devaluation in the CFA franc) and the art remains accessible to middle-class Malians. Thus, the spirit of the 'grins' is preserved. The preferred beverage is still a cup of fragrant tea or perhaps a glass of refreshing juice. Whisky will never replace tea, nor will Coca Cola replace fruit juices. Mali is not a country which rejects other people, but it resists cultural encroachment, preferring the </P>
+<P ALIGN="JUSTIFY">familiar to the exotic. </P>
+<P ALIGN="JUSTIFY">Hegel Goutier</P>
+<P ALIGN="JUSTIFY"> </P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Mali-EU cooperation</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY">Roads and adjustment</P>
+<P ALIGN="JUSTIFY">by Theo Hoorntje</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For 1990-95, ECU 151.7m was allocated (mainly in project aid) under the seventh EDF National Indicative Programme (NIP). This is equivalent to about 1.5% of Mali's GDP and 13% of its public-sector investment programme for the period in question. European funds from sources other than the NIP-emergency aid, Stabex, European Investment Bank (EIB) venture capital and resources from the structural adjustment facility- reached ECU 87.2m over the same five-year period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1995, support for the structural adjustment programme represented 5.4% of the balance of payments deficit and 7.8% of the budget deficit. Looking at all instruments together, the amount involved in financing decisions taken by the Commission last year was ECU 42m, with the disbursement figure rising to ECU 40m.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The NlP's primary commitment level under the 7th EDF rose from 76% at the beginning of the financial year to 92% at the end, which means that virtually all available programmable resources are now allocated to projects and programmes. The secondary commitment level, which involves the conversion of proposals into concrete agreements and contracts, rose from 33% to 45% by the end of the financial year. Disbursement rates remain relatively low (32% of available resources).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Allocations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aid is distributed to the various sectors, as follows:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Roads (29% of the total);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Support for structural adjustment (20%);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Rural development / Environment (1 4%);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Support for the private sector (12%);</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Decentralisation (9%); </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Public health (9%); </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Water supplies (4%); </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Education/Culture (3%).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is clear that Community aid concentrates mainly on road infrastructures-covering both maintenance and the opening-up of remote regions. Support for structural adjustment, which comes second, is used to finance the State budget's current expenses, particular emphasis being placed on improvement of fiscal and customs income and greater efficiency in health-policy matters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In other areas, such as rural development, Community aid also makes an attempt to consolidate gains from previous actions, particularly through the development of rice growing and stock rearing, which should improve supplies to the domestic market and offer further export potential. As far as the environment is concerned, the aim is to contribute to the sustainable management of natural resources on the part of basic users, such as farmers, breeders, etc.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The private sector is supported by actions in key areas and by a programme that was recently set up which involves directing resources through a financial institution (Credit Initiative SA). The objective is to promote lending to SMEs, which is in keeping with the general aim of achieving economic growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the context of administrative reform, priority is given to the decentralisation process which aims to promote the emergence of new local decision making centres (which should, in the long term, become key players in project development and implementation), and to give such decentralised bodies the means they require to fulfil these new public-sector missions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for health, Community aid has contributed to the PSPHR project financed by other donors. Its main focus is initially on infrastructures and on the policy relating to the supply of essential medicines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the water-supply sector, actions are aimed at strengthening village infrastructures, particularly in the Bankass and Koro areas. A solar-pump programme has also been set up in the Mopti and Koulikoro regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to a school reconstruction programme in the north of the country, the Commission has been able to support education and culture through a dozen or so film projects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under the general 'heading' of non-programmable resources, there have been a number of interventions. These include extra support for structural adjustment, Stabex transfers, deployment of the balance from the 5th EDF and EIB projects. Emergency aid has been deployed in the north of the country where, despite difficult conditions, programmes have been able to continue without interruption.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, Community regional aid is helping to combat rinderpest, as well as being directed towards road maintenance, and the provision of training and information on environmental protection. </P>
+<P ALIGN="JUSTIFY">T.H. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">NGOs finally achieve tangible results</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Catherine Beauraind and her five colleagues in the small team of foreigners and Malians, woke early. It had been a short night: our fault, since we had arrived at Bandiagara on the edge of the Niger valley much later than expected having taken the Sevare route. This is the gateway to the rocky Dogon region and travellers on the road occacionaliy fall victim to bandits-which probably made our hosts somewhat apprehensive about our late arrival. The people we had come to see are road builders, working without sophisticated equipment in a region of rocks and cliffs. They seem very youth froml, particularly those who have come from afar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These are 'Progress Volunteers', the name given to the many young people who come to this very poor African country to offer their commitment and dynamism, if not perhaps their experience. On this particular morning, still feeling fatigued, Catherine was having to coordinate the departure of escorts for seasonal workers who were being dispatched to various locations. Their job is to ensure the upkeep of the rocky roads, and the equipment they use is rudimentary to say the least. The Bandiagara-Dourou stretch is maintained by the AFVP (French Association of Progress Volunteers) and is one in a long list of NGO projects. In 1995 alone, the European Commission supported over 50 NGO schemes, to the tune of ECU 1.5 million. Most EU countries and a number of others also have their own projects. On top of this, there is the emergency help provided by the European Commission Humanitarian Office (ECHO), which has just approved a grant of ECU 1 million for the north of Mali. Now that a peace accord has been signed between the government and the Tuareg rebels, this region is likely to see a huge influx of refugees returning to villages that are ill prepared to receive them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali is a least-developed nation and one of the most highly subsidised countries in terms of per capita aid, though recently, its political fortunes have been boosted by the democratisation process. And the efforts of the NGOs now seem to be paying off. The recent times of famine have faded in people's memories even in the Dogon region, where many families ate calabashes in desperation before succumbing to starvation. Mother nature is playing a part in the country's renewal: there has been ample rain over the last Many NGO projects are aimed at helping the population use its meagre resources to exploit the natural wealth of the River Niger and its tributaries. At Konna, for example, a striking village at the confluence of two rivers, the Regional Literacy and Self-Management Project is up and running. Financed, among others, by the European Development Fund, this is being implemented at a number of localities, and it has played a part in the renewal which can now be seen. Fresh coats of paint, repairs to houses, fewer starving children and the return of many migrants all underline this new vitality. Each of the 17 small cultivated areas in the village that are covered by the project (worked by about 60 people), receives no more aid than a motorised pump, a few cereals and a small amount of cash in the first year. A basic course in management is also provided. It is up to the villagers to use these resources to yield a profit. Results tend to be good, proof of success being the growing number of such schemes which are being set up without aid from the organisation. The project is now in its seventh year. It did experience one bad year-1992-when, despite bumper harvests, rice imports into Mali were excessive and prices dropped. The village has therefore made an attempt to diversify its crops. Its objective is to sell onions in Cote d'lvoire, where the inhabitants are very fond of this vegetable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most villages have been able to save money which was initially placed in banks and then invested elsewhere in the wake of devaluation's harsh lessons. Konna opted for purchasing livestock. In nearby Kotaka, surpluses partially funded the construction of an impressive mosque. Kotaka was one of the places most affected by the recent meningitis epidemic, but a hospital would probably have been too expensive. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hegel Goutier </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Western Samoa</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">A new spirit of enterprise</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Small countries with a limited resource base are frequently buffeted by economic forces over which they have no control. If you live in Western Samoa, however, you are likely to be preoccupied by forces of a different kind. For while most of the time, Mother Nature presents a benign face in this attractive and fertile Pacific state, every once in a while, she loses her temper.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tropical storms are an unavoidable reality in much of the Pacific and they breed a special form of resilience which should impress the inhabitants of more temperate climes. The people of Samoa, and other cyclone prone countries in the region, are adept at picking themselves up and, if necessary, starting all over again, once the winds have passed. But between 1989 and 1993, the Samoans' capacity for renewal was to be tested more than ever before. Like a plucky boxer facing a much stronger opponent, the country would just be struggling back to its feet when another hammer blow would send it reeling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The closest to a knock-out punch came in December 1991 in the shape of Cyclone Val-the worst storm to hit the islands in more than a century. This brought death and injury, as well as widespread economic devastation. The coconut and coffee trees on which the country depends for much of its export income were either swept away or stripped bare. Many homes were also destroyed and infrastructures were severely damaged. (The 1993 cyclone, although less powerful, caused further crop destruction.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the last five years, virtually all the damage has been repaired. Indeed, a great many facilities have been upgraded with plans for further improvements in the pipeline. To some extent, the credit for this remarkable recovery must be shared. Overseas donors played an important part in restoring key infrastructures while expatriate Samoans, whose remittances are an important 'invisible' earning for the country in normal times, also rallied round. But the key players, of course, were the people themselves, who rose to the challenge of reconstructing their country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, Western Samoa - which has a population of 165 000-is experiencing an economic mini-boom. Growth during 1996 is expected to be between 5% and 6% for the second consecutive year and there are encouraging signs of a new, home-grown entrepreneurial spirit. This is not to say that everything in the garden is rosy. The latest growth figures need to be set against the unavoidable recession caused by Cyclones Val and Ofa (which struck in 1990) and a mediocre economic performance throughout the 1980s. And while there is some evidence of diversification, the economy is still very narrowly based. There is also considerable room for improvements in health care and education provision. Doubts have been expressed, for example, as to the accuracy of the official literacy figures. Finally, there is a high level of dependence on foreign aid (the country's main donors are the Asian Development Bank, Japan, Australia and the European Community).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economists will tell you how notoriously difficult it is to express the wealth of a developing nation in statistical form. GDP figures can offer a pointer, but they do not present the whole picture as they take no account of the informal economy. Western Samoa provides a particularly good illustration. At US $950, the estimated per capita GDP is very low by Pacific standards. Yet there is clearly no starvation. A great deal of the food consumed by the Samoans simply does not 'show up' in the cash economy. The term subsistence agriculture seems peculiarly inappropriate here since locally available food sources are many and varied.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Similarly, many of the materials used to build the 'fares' (traditional houses) in the villages are obtained without recourse to builders' merchants. And when a Samoan wants a new house, he builds it himself-with the help of his family and neighbours. This involves skilled carpentry work-for which people would pay highly in industrialised societies - and which does not register either in the country's economic statistics. So it is clear that the basic GDP figures do not paint a complete picture. Nonetheless, they illustrate the relatively underdeveloped state of the formal economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Looking at exports, Western Samoa's traditional agricultural sector has gone through some rough times, for a variety of reasons. In the past, the mainstays were copra and coconut products (oil and cream), cocoa and tarot</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The storms destroyed or damaged many of the coconut and cocoa trees, wiping out exports for a number of years until new plantings could reach maturity. The market in food products derived from the coconut had been depressed in any case. One reason for this was negative publicity over the high cholesterol content of coconuts, although more recent research, suggesting that not all types of cholesterol are bad for you, has at least partly restored the reputation of this highly flexible crop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taro, which is Western Samoa's staple food crop, was exported in ever increasing quantities during the 1980s but the trade has suffered badly in recent years because of an outbreak of taro leaf blight.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, Western Samoa's most important primary exports are, once again, coconut-based (oil and cream). With the new trees reaching maturity, production recommenced on a small scale towards the end of 1994. The following year saw a big jump in exports and the figures for 1996 are expected to - come close to pre-cyclone levels,The marketing situation has also improved as a result of privatisation. The old Copra Board, a parastatal with a reputation for inefficiency, was abolished in 1990, its assets being bought for a nominal sum by a Samoan businessman who has invested heavily in refurbishment. This has all been achieved despite continuing low prices for coconut products in the world markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cocoa takes longer to recover but harvesting of the first new crop is due to take place this year with the emphasis on a high value, fine tasting variety. A new chocolate factory (Wilex C.C.P. Ltd), also masterminded by a local entrepreneur, Eddie Wilson, has been built with assistance from the EU's Centre for the Development of Industry (CDI) and a credit from the European Investment Bank (EIB) channelled through the Development Bank of Western Samoa (DBWS). This is a particularly significant venture since it aims to maximise added value before export. The factory is currently operating well below full capacity, awaiting the arrival of the first local crop, but there are high hopes for its long term success.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other main crops exported are bananas and kava. The latter is a mild narcotic based on the root of the pepper plant, which is used in pharmaceutical preparations. It also has an important place in Samoan (and wider Pacific) culture, being drunk in diluted form on ceremonial occasions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With a view to achieving further export diversification, a number of other agricultural/horticultural export possibilities have also been identified. These include asparagus, mangos and cut flowers. The most likely potential market for new tropical production is New Zealand-already the destination for more than half of Western Samoa's exports. However, this country has stringent health rules with rigorous controls on the import of plant and animal material. The understandable aim is to protect the local farming sector from diseases introduced from outside, but it creates an additional hurdle for potential exporters in the developing countries of the Pacific. In particular, Western Samoa needs to come to grips with the fruit fly problem, if it wishes to make inroads into the New Zealand market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Timber also once featured prominently in the trade statistics before declining at the end of the 1980s. There are hopes for a revival here with the authorities keen to encourage value added processing of wood products within the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite its obvious association with the sea, Western Samoa has never really gone in for commercial fishing. While the Exclusive Economic Zone is small by Pacific standards, the country being 'hemmed in' by other island nations and territories, it is still more than 40 times the land area. The government would particularly like to attract foreign investment in fish processing and canning.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Industry</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is probably unrealistic to expect a small and geographically isolated nation such as Western Samoa to develop a highly diversified industrial base but there have been one or two notable ventures which show signs of potential. The above-mentioned chocolate factory is one such. The country also has a highly successful brewery. It is not uncommon for developing nations to produce their own local beer but Western Samoa's Vailima brand has managed to break out successfully into the regional market, bringing in useful foreign exchange in the process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The biggest industrial success story-dwarfing all other manufacturing ventures-has been the establishment of a factory by the Japanese company Yazaki to produce wire harnesses for cars. The business employs some 2500 people (mainly women) in a highly labour-intensive operation-and it makes a significant contribution to the trade balance. The value-added electrical components are re-exported for incorporation into cars sold mainly in Australia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The company was attracted by a number of factors including low labour costs in this non-unionised society, and the political stability of Western Samoa. Perhaps most important, however, were the incentives offered by the government. These went well beyond the usual tax holidays provided by developing countries to attract foreign investors. Indeed, it was the government that built the factory and the company was allowed to occupy it rent-free. Some observers have expressed concern at such largesse but the authorities are insistent that it was still a good deal. They point to the jobs that were created (a huge number by Samoan standards) at a time when many people's livelihoods were threatened by taro blight. They also argue that the profits of the operation are retained in Western Samoa, thereby helping to boost the wider economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Services</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The service sector offers perhaps the best potential for expansion of Western Samoa's formal economy. Top of the list here comes tourism (featured in a separate article), which has been expanding much faster than the underlying rate of economic growth. Despite the increase in both visitors and income, tourism is still underdeveloped. The government (supported by the opposition) believes that this is one field where Western Samoa definitely has a 'comparative advantage'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Linked to tourism, of course, is the air transport business. Although it might still be possible to obtain passage on a merchant ship bound for the South Sea islands, the vast majority of visitors arrive by plane, and good air connections are obviously essential. The history of the country's national carrier, Polynesian Airlines, offers two object lessons. The first is how not to run an airline and the second, more recent and encouraging one, is how to grasp the nettle when the crisis finally breaks. In 1992, with tourism in mind, the government owned airline decided to expand its operations substantially. It leased three long-haul aircraft which it hoped to fill with visitors in search of a new tropical haven. The market research was clearly inadequate and the planes flew with many empty seats. Other aspects of the company's management proved deficient and there was a chronic lack of financial. Debts mounted at such a frightening rate that the budgetary position of the entire country was threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1994, the government took decisive action, bringing in Richard Gates, the experienced airline entrepreneur, who is credited with having turned Air New Zealand around. Relatively small airline businesses in the Pacific are not likely to make a.fortune for anyone, but with proper management, they should at least be able to break even and perhaps even turn in a small profit. This was not something that even the prodigious talents of Mr Gates could achieve, however, with the crushing burden of debt accumulated by Polynesian Airlines. So the government assumed responsibility for the debts and then gave the new manager a free hand, on the firm understanding that the taxpayer would not come to the rescue again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the airline side, the operation was drastically slimmed down. The leases on the large aircraft were terminated, staff 'down-sizing' took place and bath ticketing and financial management were tightened up. The positive impact of these measures was soon evident, with a small operating profit registered in 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Left with huge debts, the action of the authorities was equally impressive, although it entailed discomfort for most Western Samoans. In order to restore its own financial position, the government instituted 15% public expenditure cuts across the board. In macro-economic terms, it is generally acknowledged that this strong medicine was needed, but the social consequences were all too clear as well: reduced funds for health and education, and pressure on important capital investment budgets. Perhaps fortuitously for the country, the financial crisis caused by the Polynesian Airlines debacle coincided with the payment of a substantial Stabex payment from the European Community. The country's was eligible for Stabex funds because of the collapse in agricultural export receipts following the cyclones, and the money-which was directed mainly into infrastructure projects-could hardly have come at a better time. Meanwhile, the government has paid off a large portion of the airline's debt with the residue rescheduled for payment over a five-year period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government has taken a number of steps aimed at attracting offshore finance business to the country. Western Samoa now has a comprehensive legal framework governing such activities, including crucial provisions guaranteeing secrecy. Another vital factor in attracting offshore funds, which has already been mentioned, is political stability. There is even the suggestion that the country's time zone, which puts it almost a day behind Australia and New Zealand, might somehow be turned to its advantage in global financial dealings (although it is not clear how the benefit would be derived in otherwise legitimate transactions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The last three years have seen a big increase in company incorporations and there are now more than 2500 offshore companies (including 15 banks and eight insurance companies) registered. It is difficult to imagine Western Samoa ever challenging the likes of Liechtenstein, the Bahamas or Jersey in this market, given its geographical distance from the main industrialised nations, but even a successful 'niche' operation could bring some useful income to the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Politics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Five years ago, when the Courier last covered Western Samoa, the emphasis was heavily on recent constitutional changes and most notably, the introduction of universal franchise. At the time, there was a lot of interest in how the traditional Samoan way of life (faa-Samoa) would be affected. This is based on the village structure and the matai system which vests considerable authority in family heads. There is also a strong attachment to the Christian faith, as exemplified by strict Sunday observance rules (also found in Tonga and other Pacific countries).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact, the Samoans appear to have embraced their more 'westernised' system of government without any difficulty. Although everyone over 21 has a vote, one still has to be a matai to be eligible to stand for Parliament. In contrast to hierarchical structures elsewhere in the Pacific, however, the system here seems to be based largely on merit and it is not particularly exclusive (there are an estimated 19 000 matai). The matai, nonetheless, exercise considerable authority in village affairs, most notably over the use of customary land.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In short, the change seems to have caused few problems because Western Samoa already had its own decentralised form of democracy. It was not a question of educating people about hitherto alien concepts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fact that change in Western Samoa is slow and progressive rather than sudden and violent, is recognised by most observers to be a good thing. An illustration of this evolutionary approach is the arrangement governing the position of Head of State. The post, which is held by His Highness Malietoa Tunamefili 11, currently appears to be a cross between a presidency and a monarchy. Under the 1962 independence constitution, two of the country's four paramount chiefs were given the position, to be held jointly, for life. With the death of Tupua Tamasese Meaole in 1963, the surviving incumbent became sole Head of State. There will be no automatic succession, however, and Parliament will decide who should have the post in future, with the term of office limited to five years. There is obviously a great deal of respect for the Head of State and his office among Western Samoans, although it should be stressed that his role is largely ceremonial, with political authority being vested in the elected government. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for party politics, there are two groupings represented in Parliament, the ruling Human Rights Protection Party and the opposition Samoa National Development Party. The party system is not particularly strong, however, being based more on personalities than ideology. Corruption is not seen to be a major problem although a major row did blow up recently over a critical report issued by the Auditor-General for 1994. This led to him being suspended and this issue had not yet been resolved at the time The Courier went to press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Western Samoa is not unique in having to adapt to a rapidly changing world. The phenomenon affects all societies, with modern communications technology increasingly breaking down the 'protection' that geographical isolation used to afford. In Westem Samoa, as elsewhere, there must be concern about the impact of this on the country's traditional way of life. Yet the indications are that this Pacific nation is managing the transition rather better than many other developing countries. The people seem to combine an unselfconscious pride in their traditions and cultural assets with a pragmatic welcoming of ideas from outside which help to improve their material wellbeing. The hope must be that this process can continue as we approach the third millennium. S'imon Homer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Historical summary</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to archaeological evidence, the islands of Samoa were first settled about 3000 years ago, after gradual migration within the Pacific from people originally from South East Asia. Samoa, it seems, was the cradle of the Polynesian culture, and settlers from there spread to other islands of Polynesia in the east, north and south.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first European to sight the group in 1722 was Jacob Roggeveen, and although there was intermittent contact between European sailing vessels and the islanders during the 18th century, more permanent contact was established with the arrival of the European missionaries in the early 1980s. They were soon followed by traders looking for copra, beche de mer, sandalwood and other products. Later, some of the trading firms, notably German, fumed to large-scale production of copra and other products such as cotton, cacao and rubber, which also led a corresponding increase in interest on the part of colonial powers. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the late 1800s, the Samoan group became the focus of colonial rivalry between Great Britain, the USA and Germany, leading, in 1900, to the partitioning of the islands between Germany and the United States. The eastern part of the group came under American control and has remained so to this day, while Germany controlled the western islands. Britain received territorial concessions elsewhere in the Pacific. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the outbreak of World War I, New Zealand took over what had come to be known as German Samoa, and became the administrative power there under the League of Nations and later the United Nations until Western Samoa became the first Patific island nation to become an independent state in 1962.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Source: Government of Western Samoa. this text is taken from the information brochure prepared by the authorities for distribution to delegates at the recent ACP-EU Council of Ministers meeting). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dream ticket ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Depart Nuku'alofa-12.00, January l 2000 Arrive Apia - 14.00, December 37 1999</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People with cash to burn are often ready to spend surprising amounts of money in their pursuit of the unusual. Tonga has already recognised this as it begins preparing for the third millennium Lying just to the west of the International Dateline, it believes it will the first country to see the sun rise on the new millennium, although other Pacific territories have also made the claim. (For this purpose, we ignore the purists who point out that the third millennium will not actually begin until January 1, 2001.) Celebrations are planned and bookings are already being taken.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Westem Samoa is obviously not in the running for this distinction since it is east of the dateline, but what this means is it will be the last nation in the world to say goodbye to the old millennium. This surely presents an opportunity for the local tourist industry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And what about those intrepid voyagers who fancy greeting the year 2000 in Tonga and then 'seeing out' the old millennium 24 hours later in Samoa. If i were an airline manager, I would be examining the possibility of extra flights from Nuku'alofa on the big day. (Let's hope it's not a Sunday I)</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">An interview with Tuilaepa Sailele Malielegaoi, Deputy Prime Minister and Minister of Finance</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY">'Economic future in tourism end manufacturing'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier visited Western Samoa at the end of June while the country was hosting the ACP-EU Council of Ministers meeting. At the time, veteran Prime Minister, Tofilau Eti Alesana, was recovering from an operation, and his duties were being carried out by his deputy, Tuilaepa Sailele Malielegaoi, who is also the Minister of Finance. Despite a hectic schedule, the Deputy Prime Minister kindly managed to find a slot for a keynote interview with The Courier.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· There is growing evidence of a new economic dynamism in this island nation, which has managed to find its feet remarkably speedily after the destruction wrought by cyclones in 1989 and 1990. With this in mind, we began by asking the Minister about the economic prospects for the country ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I think they are excellent. Our country suffered a major catastrophe as a result of the cyclones, coming, as they did, in two successive years. There was major damage to our infrastructure and forestry resources- coconuts and cocoa. At the time, we estimated the bill at more than $600m. But the rehabilitation of the infrastructure went ahead quickly, thanks to the major support provided by bodies like the World Bank, the Asian Development Bank, and of course, the European Union, not to mention the bilateral donor countries who answered our call for help. So in some ways, it was a blessing in disguise. We suffered badly, but with the assistance that came, we have been able to improve our roads and electricity supply, and the protection of our foreshore. It also encouraged us to embark on replanting to replace the trees-mainly cocoa and coconut -that had been destroyed. Last year, for the first time since the cyclones, our copra exports came back in strength. We have, at last, started to approach the pre-cyclone export levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What are likely to be the key sectors for future economic activity ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We believe that the economic future of our country now lies more in tourism and in manufacturing industries. Dealing with the latter first, we have already succeeded in attracting some industries. The major investment so-far has come from Yazaki, a Japanese company that produces wire harnessing systems (electrical components) for vehicles. This employs almost 3000 people in Western Samoa. In fact, the company set up here before the cyclones and it did not take long for us to see the benefits. The value added equivalent provided by just that one plant is roughly equivalent to our total agricultural exports for last year. So you can see the importance of manufacturing industry for us. We have provided very generous incentives and have also allocated sufficient government land to provide space for factories.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other industry which is now in the forefront, in terms of foreign exchange earnings, is tourism. We now earn four times more from this sector than we do from agriculture-and agriculture is supposed to be the mainstay of our economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of course, we mustn't reduce the priority that we give to agriculture. It is one area where we have the resources. More specifically, I think that we have great potential for beef production. If we should have another cyclone, the trees will be damaged but cattle should not be affected. So I think we should look more towards beef production and other forms of agricultural diversification. We do have some good commercial farming in place at the moment, but it is not enough. We need to do more.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What about the chocolate industry ? You have traditionally grown cocoa but you now also have a factory to process the raw material right up to the end product.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-This is a direct result of our drive to promote more manufacturing - whether it is export-oriented or geared towards import substitution. The chocolate venture is a new one and I think there are good, prospects here as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An important point is that we are moving back into growing the fine flavour variety of cocoa here. We used to be one of the 14 producers of fine flavoured cocoa in the world, and we got premium prices for it. But somehow, over the years, we switched to producing inferior quality bulk cocoa. We regretted doing that and are now switching back to the higher quality variety-which is just coming back into production following the cyclones. So here we have another potential area for exports. On the other hand, taro which used to be our major export prior to 1993 is facing difficulties. It is affected by a disease, the taro blight, which seems to be uncontrollable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Thinking in particular of the impact of tourism, are you concerned that an influx of foreign visitors might damage Western Samoa's unique and very special culture ? I see, for example, that you now have a 'McDonalds' restaurant in the centre of Apia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- No. I am not really concerned. In 1992, we set up our own tourism festival. This takes place in the first week of September and is quite clearly intended to be a feature event with an emphasis on promoting tourism. All the activities at the festival focus on the various aspects of our culture-the arts, the dances, the preparation of food, the singing and so on. It seems to me that our drive for tourism is actually helping to revive some of the cultural aspects that would otherwise have been dvina out. So I believe there is a complementarily between culture and tourism, so long as we ensure that the relationship between the two is maintained. I think this point is backed up, if you look at the growing popularity of ecotourism nowadays. This is very much concerned with preservation-of both the environment and of local cultures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In international circles, Western Samoa is deemed to be a least-developed country on account of its low GDP per head figures. Yet nobody is starving here and you appear to have a very 'rich' lifestyle, even if people don't have a great deal of cash in their pockets. Do you think the international classification is a fair one ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- I think the first point to emphasise is that a lot of the signs of development you see here are of recent origin. They date back only to 1992-93. Infrastructures have improved considerably over a very short time and this could well create a certain impression about the people's standard of living. On the other hand, it is true that our economy is not completely based on cash. And, of course, our earnings are in Tala which go a lot further here than their dollar equivalent in the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Presumably, it is to your benefit to be classified as an LDC because it gives you access to more sources of foreign funding ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I am happy to leave the classification to the experts. They are the ones who come and estimate our average per capita income, which is then used as the yardstick for placing a country in one or other category. I think it is ironic though, that if you go to a country like the USA, which is supposed to be very rich, you find beggars on the street. It certainly makes you wonder. Perhaps it is not really the statistical wealth of a country that is important, but its social system. And our social system here ensures that no-one goes hungry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· That leads on rather neatly to my next question. What do you think are the main social challenges that need to be tackled here ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-We still have quite a lot of 'service care' needs in the villages that we need to attend to. That is why we have placed the highest priority on social services over the next five years. I am talking here in particular about health, education and water supplies. There are still a lot of villages that need to have piped water brought into the home. Education-wise, we have reasonable access, but we need to improve the teaching material that is available in the classes and upgrade the general level of village schooling. We need to dissuade families from moving to the capital in the belief that they can get better education for their children here. So we still have a lot of work to do to ensure that the primary schools in the villages are upgraded. It is not simply a question of ensuring that competent teachers are available, but also as I say, providing good teaching materials and laboratory equipment for science subjects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· All of this obviously needs to be paid for, which entails healthy government finances. You recently had a serious problem over the debts run up by Air Polynesia, and you took very stringent measures to tackle this which resulted in expenditure cuts. What do the figures look like today ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-They are OK. We are running a budget deficit which means we have to borrow both overseas and locally, but we try to keep the deficit at a reasonable level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What has been the effect of introducing the Value Added Goods and Services Sales Tax (VAGST) ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-It has helped enormously. Of course, in order to sell the idea, we had to reduce other taxes and duties. As you know, there is an international trend towards removing customs duties and shifting revenue-raising in the direction of consumption taxes. Customs levies, which are the traditional source of revenue are diminishing. So what we have done is to lay the foundation for the eventual shift in our revenue base. Also, we promised to cut income taxes even more-from 38% to 25% within two years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Has this measure been implemented yet ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-No, it is due to be introduced in 1998.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Finally, I would like to turn to a constitutional question. Western Samoa introduced universal franchise some five or six years ago, but you still have a system in which only matai (family heads) are entitled to stand as candidates in elections. Do you envisage any further changes to the system ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I cannot really see that we will ever change again. The Constitution stipulates that our government is based on Samoan traditions and Christian principles. When we introduced universal suffrage, we were applying something that had always been there in any case. Samoans have always taken part in the process of choosing their leaders and voting is simply another way of doing this. The only difference is that we would arrive at a decision by getting together through our village structures and talking, whereas your system involves marking a ballot. So the change was quite in accordance with our customs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let me say something about the way villages choose their matai. When there is a question of succession, everyone has a right to take part in the process. There is no age limit. So in that sense, you could argue that we are more advanced. And we always had female matai, even before the arrival of the Europeans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this respect, I believe we are quite different from Fiji and Tonga. In Tonga, the dividing line is quite clear. If you are born a noble, you remain a noble and if you are born a commoner, you will always be a commoner. It is the same in Fiji. There, you are automatically a ratu K your father was one. By contrast, here in Samoa, my son cannot automatically succeed to my title. So to become a matai, a person has to earn it, and to put his case at the family meeting which is convened to choose a successor. Usually, the person chosen is the one who displays the best leadership qualities. I think I should also point out that becoming a matai is not that difficult. If you want to be one, you inform the family and if they think you have matured sufficiently, you will generally get the position and then become eligible to be a parliamentary candidate. It is typical that when a family sees a fellow has matured, he becomes a matai.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Profile</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Area: 2934 km² (Exclusive Economic Zone of 130 000 km²)</P>
+<P ALIGN="JUSTIFY">Population: 165000</P>
+<P ALIGN="JUSTIFY">Population density: 57 per kiLom&eacute;tres</P>
+<P ALIGN="JUSTIFY">Capital: Apia (situated on the island of Upolu)</P>
+<P ALIGN="JUSTIFY">National language: Samoan (English is the business language)</P>
+<P ALIGN="JUSTIFY">Currency: Tala (WS$) made up of 100 sene. In June 1996, 1 ECU was worth approximately WS$ 3. (US$1 = WS$ 2.3)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Politics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">System of government: A unicameral constitutional democracy with strong traditional elements. The current Head of State is one of the country's four paramount chiefs, and he holds the office for life. Thereafter, the Fono (Legislative Assembly) will elect the Head of State for five-year terms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is universal franchise (introduced in 1991) but in order to be a Parliamentary candidate, one has to be a matai (family head). Western Samoa is said to have about 19000 matai. The minimum voting age is 21.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Head of State: HH Malietoa Tanumafili II</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister: Tofilau Eti Alesana</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Main political parties: Human Rights Protection Party (HRPP), Samoa National Development Party (SNDP)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Party representation in Parliament: HRPP 35, SNDP 11, Independent 3. (The HRPP total includes 11 members elected as independents in the April 1996 election who subsequently joined the governing party).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p038.png"></center><br>
+ Map</P>
+<P ALIGN="JUSTIFY"> </P>
+<P ALIGN="JUSTIFY">Economy (1995 figures unless otherwise stated)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Annual GDP per capita: approx US$ 950</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GDP growth rate: 7%. The target for 1996 is 34%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Principal exports: coconut oil (WS $8m), coconut cream (WS $4.8m), copra (WS $2.2m).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Balance of payments: exports - WS $21.7m, imports - WS $228.1m. 'Invisible' earnings, officially described as 'net foreign earnings' amounted to WS $171m, leaving a current amount deficit of WS $36.8m in 1995 (20%lower than the previous year). The main 'invisibles' are private transfers (remittances from Western Samoans living abroad), tourism, income from services and the value added trade of the Yazaki electrical components firm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inflation rate (end 1995): 1 %. Inflation tends to fluctuate a great deal. The figure for 1994 was 18.4%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government budget (projected for 1996/97): revenue WS $288.4m, expenditure WS $312.7m, deficit WS $24.3m.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Accumulated government debt: WS$ 389 m</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social indicators</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy at birth (1993): 67.8 years</P>
+<P ALIGN="JUSTIFY">Adult literacy (1993): 98% (A UNESCO report in 1994 suggested that real literacy levels were significantly below those indicated in official figures) </P>
+<P ALIGN="JUSTIFY">Enrolment in education: all levels from age 6-23: 74%</P>
+<P ALIGN="JUSTIFY">Human Development Index rating: 0.700 (88th out of 174) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Marketing a tropical idyIl</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Folasaito Joe Annandale and his wife Tui are the brains behind Western Samoa's latest tourist facility- the Sinalei Reef Resort, which has just opened on the beautiful south coast of Upolu island. They are among a growing number of Samoan entrepreneurs who are injecting new dynamism into the country's economy although they are somewhat unusual in the tourist trade. With the notable exception of the famous 'Aggie Grey's Hotel' in Apia, tourist accommodation in Western Samoa has tended to be the preserve of foreign investors, including some of the major international hotel chains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At first sight, it is surprising to discover how underdeveloped the tourism sector is in Western Samoa. Tour operators may be inclined to use the phrase 'tropical paradise' a little too freely but this island nation certainly seems to meet most of the essential criteria. It has the obligatory golden beaches fringed with palm trees, extensive coral reefs and striking mountain scenery overlaid with lush vegetation. The vivid colours leave a particularly strong impression. Greens predominate but there are also many copper-leafed trees and bushes, and an abundance of red, orange and yellow flowers. Western Samoa can also offer a number of special features which are important in marketing terms. There is, of course, the legendary hospitality of the Samoans and their distinctive and vibrant traditions. This must be one of the most musically 'literate' populations in the world, a talent which is reflected in the numerous choirs/dance groups. The harmonies are impressive and the traditional dances are both expressive and entertaining. There is also the unique 'fare' architecture which is a particular source of fascination to outsiders, not to mention the Robert Louis Stevenson connection. The famous author spent the last four years of his life in Western Samoa and the house where he lived- which used to be the Head of State's residence - has recently been converted into a museum.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Good prospects</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The potential for expanding tourism is something that has not escaped the government. In today's highly competitive free-market world, countries are being urged to exploit their 'comparative advantage' and the Western Samoan authorities recognise that this sector offers some of the best prospects for future growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like most other economic activities, the tourist trade was badly hit as a result of cyclone devastation in 1989 and 1990. However, visitor numbers have increased substantially since then. Indeed, looking at year on year earnings, the tourist sector is performing better than any other area of the economy. In 1994, income was WS$.58 million (50 000 + visitors). The following year, it reached WS$.78m and there are hopes that it could top WS$.100m in 1996. Of course, no-one in Samoa is talking about 'mass' tourism. The country is too far from the main industrialised nations to be able to offer traditional package holidays (perhaps fortunately !), and too small to absorb the cultural and environmental impact without lasting damage. Having said this, the market can be divided into two very distinct portions. At one end of the scale are the low spending 'back-packers'-often taking advantage of relatively cheap 'round the world' airline tickets to stop off and sample the pleasures of Western Samoa. These tourists may not spend very much on a daily basis but they are reasonably significant from a financial standpoint because they tend to stay for quite lengthy periods.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the other end, you find the high-spending, 'exclusive' customer willing to pay for high quality accommodation and catering. Perhaps not surprisingly, the Government is more interested in attracting the latter, which is why they are keen to encourage investors such as the Annandales.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier spoke to Joe Annandale about his business strategy when we recently visited the country. The Sinalei Reef Resort, which has received EIB loan financing channelled through the Development Bank of Western Samoa, has just 20 rooms (including four suites) giving it a capacity of less than 50. Customers will be offered a tropical idyll and a chance to escape completely from the pressures of modern living. The long term aim, according to Mr Annandale, is to entice Europeans in general and Germans in particular. The latter, it is said, have a preference for environmentally-friendly, 'escapist' vacations and, of course, there is a historical link between Germany and Western Samoa. Until a European clientele can be built up, the focus will be on attracting guests from Australia and New Zealand. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Culture clash?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there is no question of Western Samoa being swamped by visitors from overseas, even a modest increase in tourist numbers is bound to have an impact in this country of just 165000 inhabitants. On the negative side, the Samoan system of customary (village) land ownership sometimes appears at odds with entrepreneurship founded on individual ownership of property and resources. In the early stages, Joe and Tui Annandale encountered local difficulties-including squatters-when they bought the land to develop the resort. The usual arrangement is for overseas tourism operators to lease customary land, a process which may involve protracted and ultimately fruitless negotiations with the matai (village heads) who have traditionally used the land for other purposes. Of course, the clash between traditional land tenure systems and 'modern' capitalism is not restricted to tourist ventures-as mining operators in Papua New Guinea have discovered. But while one understands the frustrations for developers, who may find themselves embroiled in complex and interminable land disputes, we should also recognise the concerns of local people who see a possible threat to their way of life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the positive side, new tourism developments mean jobs and trading opportunities. In the building of the Sinalei Resort, the Annandales drew heavily on local labour, employing 35 people from the neighbourhood. As Mr Annandale pointed out, this was essential for a complex designed to fit in with the local environment. The Samoans have always built their own houses and only they had the required carpentry skills. The resort also employs 35 regular staff for catering, housekeeping etc. and again, the majority are local people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, there is one criticism often levelled against tourist ventures which certainly does not apply at the Sinalei Reef (or other Samoan hotels). This is that most of the food and drink consumed by visitors is imported. The Annandales make a point of purchasing their fish, meat and fruit locally, thereby ensuring that some of the financial benefits of their venture flow back to their own community: in short, a happy combination of astute public relations and good economics. </P>
+<P ALIGN="JUSTIFY">S.H.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Interview with opposition leader Tupua Tamasese Efi</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY">'Revive the agricultural base'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tupua Tamasese Efi a former Prime Minister of Western Samoa, is leader of the opposition Samoa National Development Party which won 11 of the 49 seats in the parliamentary elections held in April 1996. In this interview, he outlines his own and his party's views on some of the key political and economic issues in his country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In what ways does your party offer a different agenda from that of the governing HRPP ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I think the differences are mainly of emphasis. The present government tends to focus on law-making and exploiting the country's least developed status. Our focus would be more on developing our indigenous agricultural industries. If you scrutinise the economic picture in Samoa, you will find that there has been a very substantial decline in agricultural exports in the last fifteen years. Our economy, if you can call it that, is increasingly sustained by largesse-the donations that we get from overseas. This has complicated our situation. Our relative economic independence has been sabotaged to a point where, suddenly, we are getting a proletariat. That might be unavoidable in a lot of places, but it doesn't have to happen in a small country like ours which has self-sustaining village units, and a potentially secure agricultural base supported by products like cocoa, copra and bananas. If you look at what is happening today, you see that, all of a sudden, we have a new class of under-privileged people with absolutely no income at all. And the tragedy is that it has happened without anyone really noticing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So our emphasis is to try and revive our agricultural base, and to seek out exports. In the past, our economy was sustained by cocoa and copra exports, and a lot of our food was sold to New Zealand. Now, you find that there are hardly any exports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· So your focus would be more on boosting the traditional aspects of the Samoan economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Not necessarily traditional. Our party is not bound to cocoa, or copra or whatever. But we are committed to improving our agriculture. It matters little whether it is traditional or other crops. But we need to break back into the New Zealand market. This is the best place to aim for. Australia has its own tropical sector and nothing that we can produce is needed by them. New Zealand is different. One of the biggest challenges we have to overcome in getting back into that market is our fruit fly problem. It would seem sensible for us to channel substantial resources into overcoming this hurdle so that we can sell to New Zealand again. There is a tremendous potential market-and not just for copra. There are also products such as flowers, and a whole number of other possibilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Given what you have just said,what emphasis would you place on sectors like manufacturing and tourism ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-I think that tourism is an obvious way to go and this is where we are in agreement with the government. Of course, you will have heard of the debacle of the Air Polynesia finances. When you compare the losses that were run up with our foreign exchange reserves you get some idea of how enormous the problem was. It was a situation that went badly awry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This issue aside, we agree that we need to get into tourism-but it must be within reason. Part of the explanation for people gravitating towards tourism is that they see it as the only available avenue-or at least the most visible way of making money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another economic point I want to raise concerns debt. Loans can be a quick fix, but when your whole economy is tied to indebtedness, you are creating something that is built on sand. You end 'A potentially secure agricultural base' up acquiring more and more capital items that are totally unrelated to your present or likely future resources. This is one of the most destructive things that can happen to a society, and it is very clearly happening here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You have a rich and vibrant living culture here in Western Samoa. Are you concerned that globalisation could ultimately pose a threat to this ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-No, I am not worried. You have to accept it as a natural development. The things that are distinctive in our culture have to find their place in adapting to the new realities. There is no point putting your head in the sand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Turning to political aspects, you now have universal franchise, but you still have to be a matai to be eligible to stand for Parliament Does your party have any plans to change this ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Some years ago, we had a constitutional convention which led to changes in the system. Attached to that was a provision requiring a further constitutional convention to be convened in 20 or 25 years (I can't remember the exact period). So we are committed to that. We have to sit down and look at the overall picture. We have gone a long way in terms of universal franchise and it is possible that we need to go even further.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But if one takes the United Kingdom as a model, I think the important lesson is that you should 'make haste slowly'. The genius of the Westminster model is that it involves careful evolution. I hope that this tradition will be followed by our country. The constitution, as it was put together some 30 or 40 years ago, has served its purpose very well but there are quite a few anomalies appearing now.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What is your view about regional cooperation in the South Pacific What future do you see in working together with the other countries of the region- perhaps presenting a more united front to the outside world ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-There is a lot of sense in the SAS approach-I am referring here to the Scandinavian countries getting together to form an airline. It is sensible to take a common stand where we have a common interest. But there are obviously intricacies resulting from historical, economic and social factors. At the moment I am reading a book on lain Macleod, the British Conservative statesman. His experience in the failed attempt to form a federation in the Caribbean is very revealing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When you enter a common endeavour, there is always the pull of your own particular interests. And there can be a suspicion that the 'bigger boys' will use the others to promote their own interests. A lot of this may be perception rather than reality. Also, traditional rivalries can intrude. Sometimes you need to fall flat on your face before you Let me give you an example from the world of rugby. It took Rupert Murdoch to get Fiji, Tonga and Western Samoa to realise that our fates are intertwined. He has come in with a commercial package that has taken over the entire rugby scene in the region- with a heavy emphasis on Australia and New Zealand-and this has hit us in a big way. For example, we find ourselves being cut out of traditional rugby tours. There is no point in us trying to claim that we are self-sufficient in this area. The big lesson is that we need to cooperate a lot more with the Tongans and Fijians in order to make an impact on the wider rugby scene._ </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Western Samoa-EU cooperation</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY">Focus on utilities</P>
+<P ALIGN="JUSTIFY">by Mylanwy van de Velde</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Western Samoa's cooperation with the European Community began in 1975 with its accession to the Lom&eacute; Convention. From the start, the sector to benefit most from programmable funds (ECU 4.6 m under Lom&eacute; I and ECU 6m under Lom&eacute; II) was the energy sector, with the financing of the Samasoni Hydroelectric Scheme in the late 1970s and the Sauniatu Hydropower Scheme in the early 1980s.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In parallel, a programme of 260 microprojects was funded involving the development of poultry and pig farming, and fisheries, covering 96 villages on the main islands of Upolu and Savai'i. A further ECU 890 000 was allocated to the Western Samoa Development Bank, in the form of a credit line, to increase the Bank's lending capacity. In addition, at a time when copra exports were still considerable, the Community financed storage and handling facilities for coconut oil and copra pellets (ECU 900 000).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On top of programmable aid, Western Samoa received 12 Stabex transfers totalling ECU 9.3m for export losses on copra, wood, bananas and cocoa in the period 1975-84.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under Lom&eacute; III, the development of the country's substantial hydroelectric power potential continued, and Western Samoa began to make considerable steps towards self-sufficiency in energy needs. While in 1980 some 78% of the electricity generated came from diesel plants, by 1986 this percentage had dropped to 26%. The volume of petroleum imports for electricity generation dropped to 36% in the period 1982-86. With the building of the Afulilo Hydropower Plant (Lom&eacute; III and IV), these volumes have decreased further, with positive benefits in terms of foreign exchange savings. The scheme (which was co-funded by the Asian Development Bank, the EIB, the World Bank and the Western Samoa Electric Power Corporation) involved the construction of a 10 million cubic metre reservoir, a penstock, a powerhouse, and the installation of mechanical equipment and transmission lines, and has contributed substantially to the quality of electricity supply on the island of Upolu.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p043.png"></center><br>
+ Community aid to Western Samoa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Additional work has been done with Lom&eacute; IV funds to address the question of rural water supply: a water master plan and design study for a number of rural areas have been completed, and a public awareness programme on the rational use of water resources has been designed for implemention at such time as planned infrastructural work goes ahead.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, an ECU 1 m microprojects programme has been initiated with the aim of financing the renovation of infrastructure for rural communities in the fields of water supply, health, education, tourism, agriculture and fisheries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Stabex payments under Lom&eacute; 111 (1985-1989) and Lom&eacute; IV (1990-1994) amounted to ECU 11.1 m and ECU 5.7m respectively. These were paid to compensate for losses in coconut oil and copra products, especially, but also for losses on exports of cocoa beans and of wood in the rough.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the above grant aid, the EIB has provided a total of some ECU 9m in risk capital in the years since 1981, the bulk of which was used in connection with the Sauniatu and Afulilo Hydropower Schemes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A further total of ECU 660 896 has been allocated in emergency aid to Western Samoa, in 1983 after a serious fire on Savai'i, and in 1990 and 1991 after the disastrous cyclones Ofa and Val.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Programming of the next tranche of EC funding under the eighth EDF has still to be completed, but the indications are that prominence will be given to extending and upgrading the water supply network. </P>
+<P ALIGN="JUSTIFY">M.v.d.V.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A new health-centre for Tafua</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sight that greeted the people of Tafua when they emerged from shelter in 1990, following the passage of Ccyclone Ofa,was one of complete devastation. The tropical storm had been one of the worst in living memory and this village community on the island of Savai'i, together with many others in the Samoas, found themselves having to start almost from scratch. Homes had been swept away' crops destroyed and much of the essential infrastructure Iay in ruins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is a testament to the resilience and determination of the people in these communities that there are few signs today of the havoc wrought by the winds just six years ago. In some places, rows of dead trees still stand in silent witness to the power of Mother Nature, although the scene is softened : by the new crops and lush vegetation growing beneath. But the villagers have rebuilt their houses and, with some help from outside, they have been able to re-establish i the essential community facilities as well. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through its micro-projects programme, the EC was able to offer a helping hand in the task of reconstruction. For the modest sum of just ECU 10 000, Tafua now has a new community health clinic adjacent to the site of the old one which was swept away by Ofa. In keeping with the rules of the scheme, the villagers were obliged to contribute 25% of the cost-which they provided in kind, in the shape of the labour for rebuilding the clinic. The Courier visited Tafua in June and was shownaround the facility by Nurse Agata Leuelu who provides primary health care for the 600 villagers. We also met local Methodist minister, the Rev. Siaosi Selesele, who explained how the people had taken shelter in the neighbouring school when the storm reached Samoa. It turned out to be the right choice as it was one of very few structures left standing in the neighbourhood. Villagers are obviously hoping that there won't be another 'Ofa' for a very long time' but if and when the next big wind does strike, the new ctinic-which has been built to withstand a lot more strain-should hopefully be able to weather the storm. In the meantime, it provides an important service in the delivery of health care to the people of the area. The European Community has also provided micro-project funding to help rebuild the health clinic at Taga on Savai'i. </P>
+<P ALIGN="JUSTIFY">S.H.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Dossier</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Investing in people</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Dossier coordinated by Augustine Oyowe)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Previous editions of The Courier have dealt, separately and at length, with various aspects of human resource development, especially in the context of recent dossiers on population and social development, education and training, public health, women, and poverty. Our current dossier looks at the issue from the investment perspective.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To say that investing in people makes economic sense is to state the obvious. But to what extent are the implications of this statement fully understood in the developing countries, especially in sub-Saharan Africa in these days of constantly shifting development theories?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Labour or 'human capital' has long been recognised as a key factor of economic growth. As opposed to sustainable human development, which places human beings at the centre of economic activities (the recipient of the fruits of economic progess), 'human capital' places them at the beginning of the process. The difference of approach is thus evident even though the objective is the same. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Investing in people is a concept which simultaneously combines 'human welfare' with the 'human capital' approach at the beginning of the economic development process. It encompasses nutrition, health and education, and should, under the right investment climate or conditions, enable any investor, whether State or individual, to reap an adequate return .</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After three decades of considerable efforts at investment in health and education by sub-Saharan African countries, the returns in terms of standards of living, economic grovvth and rate of development have been extremely disappointing. The conclusion which can be drawn is that the conditions necessary for adequate returns on these investments have been absent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Colonial legacy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sub-Saharan Africa inherited from the colonial regimes, infrastructures in health delivery and education that were not only alien to its culture and traditions, but also totally inadequate for nation building. It is a well known fact that in 1960, there were no more than 1200 university graduates in Capital redefined</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is important when thinking of investnent in human resources to understand the real concept of capital. Below is an extract of a definition given by Stefan de Vylder (taken from his UNDP discussion paper: 'Sustainable Human Development and Macroeconomics strategic links and implications' . </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A child in the North is born wealthy. His or her share of the capital accumulated by earlier generations is worth a fortune. The higher wages and salaries in the North, compared with those in the South, largely reflect differences in endowment of the country, rather than of the individual. The fact that, for example, a nurse in Germany earns 30 times more than one in Bangladesh or Zambia has little to do with individual differences in training or skills; the higher salaries in the North simply reflect the higher dividend on the capital bestowed from the past. Part of this wealth or heritage is easily visible: factories, roads, schools hospitals, universities, telecommunications, and other infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, there are other, less tangible, forms of capital that constitute a crucial complement to physical and infrastructural capital; parliamentary democracy, a free press, respect for human rights' norms for social interaction, systems of rapid dissemination of new ideas, trade unions and a myriad of other large or small social organisations, a judiciary system which, by and large, defends law and justice, and other institutions. This latter form of capital may be called institutional or social capital. It is also highly unevenly distributed in the world, with large differences both between the North and the South and within individual countries of the North as well as in the South the region as a whole. Indeed, some countries had no graduates at all and in others, they could be counted on the fingers of one hand. In what was effectively a race against time, African leaders understandably responded by investing massively in human resource development. This was made possible partly by small, but steady rates of economic growth and partly by sustained foreign assistance. Between 1960 and 1980, sub-Saharan African governments consistently allocated high proportions of their annual budgets to health and education. Households and individuals made similar efforts (accounting for nearly 75% of all spending on health). They made sacrifices and gave a high premium to the education of their children.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The results were tangible and very significant. By the late 1980s, sub-Saharan Africa was producing over 70 000 graduates a year. Major cities had hospitals and health centres and the rural areas, clinics and dispensaries. Amid a general improvement in nutrition and health-care delivery, the incidence of infectious disease, and maternal and infant mortality were considerably reduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite these achievements, the approach to manpower building by the post-independent African leaders was, to say the least, haphazard. As a result, a number of problems, such as the appropriateness of school curricula, under staffing and the long-term budget implications of recurrent expenditures, were overlooked (although reform efforts have since been attempted in some countries with varying degrees of success).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The consequences were felt in the 1980s when Africa's economic crisis was only just beginning. Health and school infrastructures deteriorated for lack of maintenance. There were shortages of qualified teachers and teaching materials leading to falls in educational standards as well as in primary school enrolments. And health systems failed for lack of personnel and drugs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The situation has worsened as the continent's economic crisis has deepened-a crisis characterised by huge budget deficits, high inflation rates, sluggish growth rates and a heavy debt burden. Structural adjustment programmes (SAPs), introduced in response to this, have only served to undermine further the gains made in human resource development. SAPs have been aimed mainly at macroeconomic stabilisation, deregulation and privatisation of state enterprises, and the social sectors have lost out in the process. Subsidies on basic commodities, especially food, have been removed, civil servants and employees of state enterprises have been made redundant and cost-recovery has become the standard practice in medical services. These measures have all combined to produce a level of poverty never before seen in the region, a situation which has adversely affected nutritional standards, provoked malnutrition in many countries and reduced resistance generally to infectious diseases. Because of the rise in unemployment, large sections of the educated population have been rendered unproductive, a waste of several years investment by both the state and the individuals in question.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Appropriateness of skills</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although sub-Saharan Africa produced a large number of graduates before the economic crisis began, few had the kinds of skills needed for industry and agriculture. The evidence of this lies in the unsuccessful attempts by some governments in the late 1970s to indigenise executive positions, most of which required high levels of technological knowledge or experience. The 1980s saw a dramatic increase in the number of foreign technical assistants working on the continent and, paradoxically, in the number of qualified African professionals leaving, mainly for Western Europe, the United States and Canada.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International technical assistance to, or cooperation with, subSaharan Africa has intensified. Organisations such as the World Bank, IMF, UNDP, UNCTAD, UNESCO, European Union and Commonwealth are all involved in one form or another. The effectiveness of this assistance varies, however. This dossier features articles on the work of three of these bodies (the Commonwealth, UNDP and VNESCO). The Commonwealth Fund for Technical Cooperation was set up more than 25 years ago to mobilise Commonwealth skills to meet the needs of member states as required. The UNDP's TOKTEN programme is designed to reduce the negative impact of the brain drain by getting highly qualified developing country expatriates to contribute their skills to the development of their home countries without necessarily having to return permanently. Finally, UNESCO's university twinning programme is designed as a mechanism for the rapid transfer of technology and sharing of knowledge. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While international assistance or cooperation is indispensable, it is surely no substitute for Africa's own efforts at human resource development. Three years ago, Edward Jaycox, then World Bank Vice-President for the Africa Region, announced what appeared to be a change of policy at the annual conference of the African-American Institute in Washington DC. He said that the Bank would no longer pay for foreign technical assistants to help resolve African economic problems but would instead help African governments build their own capacity. Although the Bank has traditionally had enormous influence on development thinking and policy worldwide, the apparent policy change does not appear to have influenced other donors. Nor, indeed, is there any evidence that the Bank itself is implementing it vigorously. The number of foreign experts being sent to Africa continues to grow. There were over 100 000 in 1988.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rationality of investing in people</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the negative social impact, ten years of structural adjustment have not produced the sought-after stabilisation or the economic growth that was initally anticipated. Even the World Bank and IMF, who spearheaded the structural adjustment idea, have admitted that it has flaws and the need for a new approach to sub-Saharan Africa's economic problems could hardly be more urgent. In the Dossier, Giovanni Andreas Cornia argues for a new focus for structural adjustment, based on restoring adequate levels of public spending on health, education, social welfare and water supplies, so as to enable sub-Saharan Africa to restore and develop its human resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Evidence of the impact of a healthy and educated population on economic growth and development abound. Studies on the economies of the East Asian 'tigers' have all concluded that big investments in education in the late 1950s and 1960s were largely responsible for the rapid growth they have experienced in recent years. Malaysia, although a latecomer, appears to be following in the footsteps of its neighbours. After nearly two decades of investment in human resource development, and the introduction of a foreign investment policy which requires some technology transfer, the Government now predicts Malaysia will achieve 'fully developed' status by 2016-twenty years from now.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A relatively well-educated workforce and a certain amount of physical capital or natural resources are all a country needs to succeed economically. Sub-Saharan Africa has sufficient natural resources as is often pointed out. The other side of the equation-a relatively well-educated workforce-is missing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sub-Saharan Africa lags behind other regions in human resource development for a complex variety of reasons. The natural and political environment are not conducive to the delivery of social services: low population density and weak transport infrastructures make such delivery expensive and the achievement of economies of scale impossible. The region's climate favours a variety of diseases (such as malaria and sleeping sickness) and many areas have little or no access to natural water sources. Political instability and weak institutions also continue to cast a long shadow. Although these constraints are long-term, appropriate policy measures could reduce their negative impact significantly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Giovanni Cornia analyses the distributive effects of appropriate health care, nutrition and education on economic growth. He suggests ways of making rational use of available resources for maximum returns and of mobilising funds through taxation, foreign aid and other sources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In an age of increasing globalisation, where technology is more easily transferable across borders, a healthy and educated population is essential, not only for the absorption and use of new technology but also for meaningful participation in international trade.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is insufficient, however, to have an educated workforce. Sub Saharan Africa must acquire the institutional and managerial capacity to make the right decisions, both in the public and private sectors. This is essential in the quest to eliminate poverty, achieve sustained and sustainable economic growth and ensure a realistic integration of the region into the global economy. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">A much needed new focus for SAPs</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY">by Giovanni Andrea Cornia </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past two decades, a clear consensus, supported by a growing amount of empirical evidence, has emerged on the growth and distributive effects of appropriate health care, nutrition and education, and on the rationality of investing in human resources to promote development in low-income economies, and in sub-Saharan Africa in particular. It is now clear that public and private rates of return on investment in primary and secondary education are substantially greater than those in most industrial sectors. Similarly, it is now well demonstrated that nutritional interventions in favour of workers at low levels of food intake has a very large impact on labour productivity. Also, provision of simple but adequate nutrition and health care at an early age has been shown to spare substantially greater health outlays over the longer term. While the number of these examples can be multiplied, the lesson is overwhelmingly clear: investing in people is a sound development policy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the same two decades, a broad political consensus has also emerged on the need to establish realistic targets in these areas and mobilise adequate resources to achieve them. The latter decade, however, has also been characterised by a widespread and acute recession which has reached its lowest point in the African continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While there has been a general recognition of the link between the deterioration of the social sector and Africa's economic decline, the interpretations of the causes of this decline and how best to address them vary considerably.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 1980s also witnessed the advent of structural adjustment, an approach aiming at revitalising economies affected by severe crises and which calls, amongst other things, for a reduction in public spending, including on social services. With sharp falls in revenues, it was argued, African governments could no longer afford to provide health and education free of charge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments were to encourage instead the role of the private sector (since competition between state, private and non-governmental agencies fosters efficiency and enhances quality) and make households bear a greater share of the cost of publicly provided social services (as-it was alleged-households had a strong 'willingness to pay' for better quality health care and education).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a debate characterised by an overwhelming concern for expenditure reduction, little thought was given to protecting the provision and effectiveness of basic health care and education for all. Nor was sufficient attention paid to the mobilisation of additional revenue through taxation, foreign aid or other measures Even the introduction of rationalisation measures, which would have allowed for use and preservation of limited resources, received scant attention. During this period, public policies often ignored a number of well-known public finance arguments concerning market failures, externalities, natural monopolies, etc. typical of basic health and education. It was all too often forgotten, for instance, that the market systematically undersupplies 'quasi-public goods' like education, safe water, immunisation and collective infrastructure (i.e. goods which produce benefits not only for consumers but also for society as a whole); that incomplete or non-existent markets alone are unable to provide complete insurance coverage against the risks of sickness and disability; that the free play of market forces can generate levels of poverty that are socially unacceptable, and that competition among many small providers does not allow for the realisation of the economies of scale which only the public sector can realise because of its size, administrative infrastructure and revenue raising ability.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Greater and better government involvement</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this paper, I will attempt to point out the main distortions in the social sector in sub-Saharan Africa and the major reforms, part of an alternative policy paradigm to the standard approach focusing on large expenditure reductions. My main line of argument is for more efficient and renewed but, in most cases, greater rather than less government involvement. I do not deny the important role of communities, nongovernmental bodies and private providers of social services, but the retreat of the state, which has been underway for several years in most of Africa, is palpably wrong: it may be a good survival strategy, it is definitely not a good development strategy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any approach to revitalisation of the social sector in Africa must aim at increasing both the quality and the relevance of services to the life, health and productivity of the population; enhancing efficiency; reducing distributive biases in the use of public expenditure, and improving the flow of both public and private resources to the social sector. These sets of measures are briefly discussed here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Raising relevance, reducing unit costs and enhancing quality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two basic initiatives are essential to the achievement of this goal. Firstly, it is necessary to adapt the content of services to the demands placed on the child, the adolescent and the family by the external environment. Secondly, in doing so, it is necessary to provide minimum resources, particularly recurrent inputs, for every unit of service offered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Much can be done to improve the relevance of education in Africa. A key element in this is the wider use of African languages in the educational system. Admittedly such a step would probably encounter obstacles, but the results of pilot projects in the continent and experiences in several English speaking countries have been encouraging. The use of African languages should be expanded throughout primary and at least part of secondary schooling. And the curriculum of basic education should include basic health science, agriculture, food and nutrition, basic technological science, ecology and environmental studies as well as reading, writing, arithmetic, history, geography and elementary civics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While responding more appropriately to the life and developmental needs of children and adolescents, these measures offer the potential to improve substantially the cost effectiveness of the educational system by reducing the number of drop-outs and repeaters, particularly if the measures are accompanied by school-based nutritional support programmes and by steps to ensure a steady, if basic, supply of teaching materials such as books, chalk, slates, pens, exercise books and so on. Minimum expenditures for the latter, estimated at $5-10 per child per year, have been shown to have a profound impact on the quality and attractiveness of education.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improving the relevance and quality of African secondary and higher education will require an increase in the number of courses in science, engineering, agronomy, management and other fields. Given the limited success of vocational training and yet the profound need for this type of education, a more flexible approach may be appropriate. Business associations and ministries of labour, rather than ministries of education, for example, could organise the type of vocational training that responds more closely to labour market conditions. Much needs to be done to gear university research to local and national needs. Rather than maintaining the model of independent residential universities, faculties could interact more with and rely upon local institutions and non-governmental organisations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the health sector, a more vigorous approach is necessary to implement the 'Health for All' strategy. In particular, more attention must be paid to the quality of the training imparted to village health workers, the provision of minimum supplies of essential drugs, adequate supervision, the mobilisation of communities and the strengthening of family planning services in the first tier of the primary health care pyramid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Greater efforts are needed to contain unit costs through the mobilisation of community resources (such as materials and time) and the introduction of 'product standards' and 'production techniques' more in line with local factor endowments. With respect to capital expenditure, one major source of potential savings is the substitution of imported materials with local ones in the construction of schools, clinics and other public health facilities. Through this approach, capital costs per student could be more than halved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In health care, savings are also possible, in some cases, in wages and other recurrent expenditures. The potential for savings through increased efficiency in the procurement, management, storage, distribution and prescription of pharmaceuticals is substantial. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And there is a need for more carefully articulated manpower policies, with recognition of the cost implications of alternative skill mixes. Many tasks carried out by senior professionals can be performed by auxiliary personnel. In this regard, there is substantial scope for the application of nominal fees as a tool to guide demand for health care and thus increase efficiency.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Similar considerations are valid in the education sector. Despite considerable declines during the 1980s in both French-speaking and Eastern and Southern Africa, teacher salaries in the late 1980s were still considerably higher than per capita GNP in several countries. While a cutback may be possible in some countries, reductions below the 'efficiency wage' should be avoided as they affect the quality of teaching.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are, of course, other approaches to reducing unit costs such as using teachers trained on crash courses and- paid salaries lower than that of fully trained ones, multi shift education to increase teaching hours, multigrade classes to increase class sizes and the creation of regional training centres with donor support. In addition, in most of sub-Saharan Africa, all university students receive fellowships to cover living expenses while at school. In many cases these fellowships represent a substantial proportion of total unit costs at the tertiary level. They add, in effect, to the regressive nature of educational subsidies and should be suppressed for all except for those who are least able to pay.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improving distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Substantial improvements in the distribution of benefits of public expenditure could be obtained through its restructuring towards basic services which benefit the poor more than they do the rich. This would mean, typically, the reallocation of part of the expenditure on hospitals to primary health care activities and part of the expenditure on universities to primary education. It would also mean that a greater share of investments in water supply and sanitation should be assigned to rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Correcting existing misallocation, however, is not simple, as capital and labour resources are only partially mobile. This is particularly true of capital expenditure which has already been invested in physical infrastructure. Inter sect oral reallocation is easier for recurrent expenditure, particularly when budgets are expanding, and it can lead to the achievement of more efficient and distributive gains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government subsidies need to be improved through effective targeting on 'merit goods' (such as food and shelter). Targeting is distributionally and administratively more effective when it is accomplished according to some objective criteria such as geography (the poorest areas), type of commodity ( low quality foods not consumed by the rich), easily identifiable population group (like pregnant women, young children, children in elementary school in poor areas, etc.) or season. It is less effective when carried out by means-testing or by targeting individuals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The decentralisation of health care and education in the African context is likely to improve the geographical distribution of services. Poor communications and transport systems, population dispersion and the fact that the supervision of personnel, resource distribution and operations is easier at lower levels of administration, are all arguments in favour of such decentralisation. Nonetheless, where it means loss of control over the implementation of national policies (in curriculum development, manpower training, drug procurement and so forth) and excessive additional financial burdens on households and communities, decentralisation is potentially damaging. This was the experience of Kenya when the purchase of drugs was decentralised at the district level. It subsequently had to reverse this policy because of the problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Increasing the flow of resources to basic social services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the considerable scope for protecting and, in some cases, expanding the delivery of cost-effective and high-impact social services, even during periods of declining resources, there are limits to what can be achieved through the measures discussed above, particularly in countries where the share in GDP of public health and education expenditure is already low. Indeed in most African countries, the flow of resources to these sectors must be vastly increased. The options available include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Increasing the share of government expenditure on key social services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Top priority should be given to a radical restructuring of government expenditure involving the shifting of resources towards those sectors with high social rates of return. Expenditure on defence can be cut substantially, while subsidies to chronically lossmaking public and private enterprises and interest payments on debt (the relief effect on foreign-debt interest payments of current provisions is utterly inadequate) should be reduced. If realistic expenditure restructuring like that proposed here were implemented, 1015% of overall public spending in many countries could be redirected to social activities with high rates of return. One half to two-thirds of these savings could be allocated to health care, nutrition, training, education and welfare, thus raising the share of these activities to about 30-35% of total expenditure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Increasing taxation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Between the late 1970s and the mid-1980s, the average tax to GDP ratio for sub-Saharan Africa fell from 18% to 16-17%. (Only recently are there signs of recovery, but these are confined to only a few countries). This resulted mainly from the recession affecting the region and from the limited priority attached to revenue collection in most adjustment programmes implemented during the first part of the 1980s. In these 'first generation' programmes, the stabilisation of deficits was achieved mainly by cutting expenditure and raising excise duties. Increases in income taxes and progressive indirect taxes were far less frequent and land and property taxes were almost never introduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While taking effect rapidly, the measures implemented led to excessive drops in public expenditure on 'quasi public goods' and have had a regressive distributive impact. It is now widely recognised that a more active tax policy is needed. Such a policy should aim at improving revenue generation and enhancing the efficiency and equity of the overall tax system. This would permit a controlled rise in specific 'socially efficient' public expenditures, particularly basic health, primary and secondary education and public infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the 1980s, a number of countries, including Burkina Faso, Kenya, Malawi and Zimbabwe, initiated efforts to reform their tax systems. While the choice of optimal tax instruments has depended on specific country conditions, a few general principles of tax reform apply to all countries. First, colonial type tax systems emphasising the taxation of exports (and to some extent, of imports) should evolve towards systems which focus on income taxes, progressive and efficient indirect taxes and increases in the prices of such public utilities as telephone and electricity which benefit mainly the wealthier sections of society. Second, purchases of goods and services consumed by the poorest should be exempted from indirect taxes. Third, efforts should not concentrate on raising marginal tax rates but rather on broadening the tax base by reducing tax evasion and tax elusion, and fourth a low, uniform and broad-based tax on wealth (such as on land or other assets) should be introduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A non-distortionary and equitably-spread increase in the tax ratio equivalent to 2-3% of GPD is technically feasible in a good number of African countries and would by itself add to the real flow of resources to health care and education by about 15%, even assuming no growth and no shift in priorities towards the social sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Introducing 'earmarked' taxes or raising local ones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The flow of tax resources to the social sector could be augmented more readily if the new tax revenue thus generated, or at least part of it, were directly earmarked for specific health and education activities (for which there are guarantees that tax money is spent efficiently), or if these taxes were raised directly by district and provincial authorities, who are usually entrusted with responsibility for social services at the local level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Mobilising additional resources from households and communities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In sub-Saharan Africa, as in most other developing regions, households have long borne a substantial share of the national expenditure on health, education, water supply and so on by contributing resources (in kind, cash and time) for the construction of health and education facilities, covering direct and indirect costs (transport uniforms, fees, drugs etc.) associated with the provision of public services and making payments to private providers. Despite these already considerable contributions, user charges have been introduced or raised on a large scale in recent years in many countries to alleviate the burden on public expenditure imposed by the economic crisis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, while the small but significant contribution of user charges to health and education budgets should be acknowledged, the negative effects of the indiscriminate application of these charges should also be emphasised. Indeed, in many African countries the need for health care, education and other social services rarely coincides with the ability to pay. The implementation of user charges can have adverse effects in three ways. First, it may lead to a contraction in the demand for services. Second, in the health sector, it tends to discourage the use of preventive services for which potential patients may not see an immediate relevance (such as ante natal care and immunisation). Third, it may adversely affect a household's ability to meet other basic needs, such as the purchase of food, particularly if fees are charged simultaneously for health, education and other services and if the household's income declines. In addition to these problems, there is little evidence that the revenue from user charges is actually reinvested to improve the quality or expand the coverage of local services, as those who promote user charges argue. Despite recent attempts at keeping a share of the user fees at the local level (e.g. at the collecting facilities), in most cases revenue merely flows to the public treasury. Moreover, user charges usually generate a relatively small proportion of the total operating cost of the health care sector, with gross yields at around 5%. If the costs of fee collection are included, the yields are lower and, in some cases, negative.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, health care, education and the provision of water include different types of services, some clearly geared to the needs of the poor and others catering more for middle and upper-income groups. While user charges are not well suited to primary education, disease control programmes, basic curative services and communal water supply, the same cannot be said of university education and other 'income elastic' services. For the latter, cost recovery measures would be advisable, although subsidised access for the deserving poor must be assured. For the intermediate category, which includes most curative health services and secondary education, selective cost-recovery measures might be desirable, with low income individuals exempted or charged only a nominal fee.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While direct user fees (levied on patients at the moment of their treatment) are problematic from several perspectives, there are other indirect ways to mobilise resources from communities (generally before episodes of illness), such as various kinds of prepayment schemes, health insurance, lotteries, mutual funds and the sale of produce from community fields, in addition to their contributions in kind. These schemes have two main features which are attractive for health-care: they shift the moment of payment, so that individuals are not burdened with relatively more significant expenditure at the time of illness, and they spread the burden of costs (e.g. for drugs) over a larger group.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Increasing the volume of international aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There has been a considerable shift in official development assistance (ODA) in favour of Africa over the past two decades. Africa's share in total ODA rose from 19.4% in 1975/6 to 25.1% in 1980/1, and to 34.2% in 1988/9. However, the share assigned to human resource development has dropped, while- debt-service obligations have often absorbed a growing share of ODA. Greater flows are therefore needed. In the late 1980s, the World Bank estimated that additional annual aid of about $1 billion was required during the 1990s to halt social retrogression and ensure reasonable progress. But this flow of aid has not materialised on any appreciable scale. Indeed the trend in the 1990s has been towards an absolute decline in aid flows. The simplest and the most cost-effective way to effect such aid transfer would be through debt relief, although some increases in ODA are needed. Improvement in the quality of aid, including substantial shifts to programme aid, greater participation in the financing of recurrent costs and more focus on primary health care and education and on rural water supply are also required.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What role for NGOs and private providers?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While private providers, including church missions, have always been important in Africa, much of the market oriented literature tends to be very optimistic about the scope for expanding private services in order to replace government ones. Although a multiplicity of providers is desirable (and frequently unavoidable), there are several reasons why such optimism should be tempered. First, private sector services in Africa are typically concentrated in urban areas, and because of their cost, cater for upper-income groups. Although non-governmental providers (especially missions) are often located in rural areas, and they generally provide valuable services, they are seldom able to guarantee extensive coverage and in some cases may duplicate government services. Second, private providers are not without costs to governments; they often receive subsidies or preferential treatment in the allocation of foreign exchange and typically offer higher salaries and better working conditions which draw manpower away from the public sector. In Zambia, for instance, a teacher in a primary school run by the Consolidated Copper Mines can earn more than a lecturer at the University of Zambia. In countries with extremely limited numbers of doctors, certified nurses, qualified teachers and so on, greater privatisation would exacerbate the 'brain drain' from the public to the private sector and the undersupply of 'quasi public goods' for the majority, leading to harmful social differentiation. Third, quality is not necessarily an important incentive in the private sector in developing countries. The view that private institutions in health care and education are more efficient tends to be based largely on analyses in developed countries. Fourth, the growing pressure for pluralism in social service provision often gives scant attention to the problems of central coordination and planning and the development of an adequate 'regulatory framework' for private sector activities. While playing an important complementary role, the private sector and, to a lesser extent, the NGO sector, are thus affected by important objective limitations. Indeed, ironically, their proper functioning and social utility depends crucially on the existence of a stronger, not weaker, state able to regulate, coordinate and ensure that basic social services are provided - possibly through a multitude of public, NGO and private providers-to all citizens of a nation. G.A.C</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Capacity building for management and development</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Franklyn Lisk</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The development experience of much of sub-Saharan Africa in past decades provides ample illustration of the importance of capacity building in the development process. The importance is related to the ability to manage economic and social processes, including the analysis and formulation of policy options, for attaining development objectives such as employment generation and poverty reduction. The consequences of failures in domestic economic management, compounded by the effects of a prolonged economic crisis in the region have, inter alla, contributed to high and rising levels of open unemployment and underemployment, declining per Capita incomes and real wages, and an increase in the incidence and intensity of poverty in a number of African countries. The persistence of these adverse consequences, which represent a serious threat to economic growth and sustainable development, are somehow linked-either as a cause or an effect -to weaknesses and instability in the institutional framework for management and public administration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The problem of weak institutional and general capacity for management in Africa today can be traced to the colonial legacy. This left many countries in the region, at the time of independence, with insufficient institutional and human capacity to cope with the transition from colony to independent sovereign state, particularly with respect to the responsibility for economic management. More specifically, this related to the unequal and disadvantageous manner of Africa's incorporation into the international economic system in the late 1950s and the early 1960s. Lack of technological know-how, inadequate infrastructure and limited investment resources compounded the immediate post-independence problem of weak institutional capacity, and left many African countries highly vulnerable to external shocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It was extremely difficult for the majority of African countries to break out of the old 'protected' colonial production and trade systems and rapidly to diversify their economies in line with the requirements of participating effectively in a competitive world economy. Since independence, institutional and human capacity for management in many African countries has not grown fast enough to keep up with the requirements of changing socioeconomic circumstances at the national level and to face the challenge of increasing globalisation. Critical skill shortages in public administration and private sector management in Africa can hardly be addressed in the context of the current economic crisis. The consequences of this crisis can be seen, for example, in underfunded and poorly equipped training and management development institutions, and in low-paid and demoralised civil services. At the same time, the 'brain drain' from the continent, partly as a consequence of poor pay and career prospects, has further undermined capacity in Africa. The interaction of foreign donors and African governments has not always served the interest of capacity building. It has been admitted, even by the World Bank that 'aid has done much less than one might have hoped to reduce poverty (in Africa)'. There is now more or less a consensus in the international donor community that expatriate technical assistance does not and cannot solve all kinds of development problems in the region. Far from solving problems, the imposition of foreign technical assistance has, in some cases, become a destructive force which undermines the development of domestic capacity that is critical to solving local development problems. Where donor assistance is inappropriate in terms of project concept and design, or there is a mismatch between design and domestic implementation and management capacity, technical assistance could end up becoming part of the problem rather than the solution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conceptual issues</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Before examining the requirements for institutional capacity building in developing countries, and particularly African countries, it is necessary to clarify salient issues pertaining to the concept. Broadly speaking, capacity building in a development context refers to a comprehensive process which includes the ability to identify constraints and to plan and manage development. The process usually involves the development of human resources and institutions, and a supportive policy environment. Ideally, it aims at improving on existing capabilities and resources and using them efficiently to achieve sustainable economic and social development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Narrowing the concept to focus on institution-building, the emphasis will be on the development of particular institutions, their human and material resources, their organisational management and their administrative capacities. More specifically, the aim of institutional capacity building is to improve significantly the outputs and impacts of institutions concerned with economic management, public administration (including project management), enterprise development and so on-in both the public and private sectors. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is obvious that relevant development-oriented institutions within an economy can exert a decisive influence on economic growth and employment prospects, and indeed on the attainment of sustainable economic and social development. From a macro standpoint,planning and similar development institutions are required for better management of the economy including, more crucially, the ability to mobilise, allocate and utilise human and material resources in an efficient and productive manner. At the micro level, human and institutional capacity is critical to sound project management and public administration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The framework</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The general situation in Africa today suggests that capacity building is required in relation to the following priority areas:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- good governance, to ensure stability;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-economic management, to maximise resource mobilisation and promote sustainable development;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- human resource development, to support employment creation and income generation, and reduce poverty;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- science and technology, to increase the efficiency of the population and facilitate infrastructural development;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-enterprise development, to enhance the critical role of the private sector in overall development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The degree of emphasis given to each of the above in a given context would vary according to the level and complexity of existing human and institutional capacities, the economic and financial means to support capacity, the relative roles of the public and private sectors, and the degree of involvement of civil society in the decision-making process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The policy context for institutional capacity building should be multi-sectoral and flexible, but coherent in relation to the desired objectives of development. This is to ensure that the process of capacity building is adaptable to changing circumstances-an issue that is particularly relevant in the context of countries undertaking structural adjustment and economic reform programmes when there is a need effectively to nurture and utilise local skills and to mobilise investment resources efficiently.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the light of the development challenge facing African countries, the process of capacity building in the region requires, above all, appropriate and adequate human and institutional capabilities to plan and manage economic and social development processes. These capabilities should include the means of assessing the achievements and impact of capacity building on poverty reduction, employment creation, etc. Existing public sector institutions for development planning and management could provide the operational framework for national capacity building, but the process should also include the participation of diverse social forces, the private sector and non-governmental institutions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Regarding the role of external donors and technical assistance agencies, the approach should be based on the concept of 'partners in development', which implies consultation and dialogue between donor and recipient on all aspects of project planning, design and implementation- with project 'ownership' resting with national authorities. Technical assistance from foreign donors should therefore go mainly towards developing the necessary domestic capacity, rather than contributing to the undermining of existing or potential capacity. Furthermore, assistance provided by external donors should be directed towards the building of capacity for promoting regional economic cooperation and integration through support for the development of viable African regional and sub-regional development organisations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Support initiatives</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The issue of domestic capacity building in Africa has more recently been the focus of attention by the international community as a whole. Indeed, the former World Bank vice-president for Africa, Edward Jaycox, has described 'capacity building' es the 'missing link in African development' which is 'critical to the development effort (of the region) and the chances of success'. UN agencies, spearheaded by the UNDP, have been active in promoting capacity building as a major requirement for attaining sustainable development. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1991, the UNDP Governing Council took a decision which resulted in the development of guidelines covering assistance to governments in the formulation and implementation of national capacity building strategies relating to all stages of the project cycle in the developing countries. The decision coincided with the introduction of the 'programme approach' by the UNDP which emphasised the centrality of national development programmes as the hub for the integration of UN technical assistance activities with national efforts. Emphasis on the use of national skills in the development process was consolidated within the general operational framework for 'national execution', which implied that overall responsibility for management of UN operational activities and accountability remained with the government and other national institutions and beneficiaries who 'owned' these activities. Under these new arrangements, a high priority was thus placed on the strengthening and sustaining of development management and administrative capacities on a long-term basis as an integral part of UNDP technical assistance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The World Bank's interest in capacity building in Africa has been more closely linked to the need for administrative and technical capacity at the national level to carry out policy analysis and economic management in the context of on-going structural adjustment and economic reform programmes. In a trailblazing address to the African American Institute Conference in 1993, Mr Jaycox came out strongly in favour of a new approach to lending to African countries which gave top priority to the development of critical human and institutional capacity. He admitted that the Bank's $4 billion a year lending programme in sub-Saharan Africa had not had the desired impact on development in the region because not enough attention had been paid to national capacity in the past. He went on to criticise the international donor community and financial institutions, including the World Bank itself, for designing and carrying out technical assistance activities which not only fail to solve problems but end up undermining the development of capacity in Africa. Mr Jaycox accordingly pledged to give direct support to capacity building in the Bank's lending programmes, mainly through human resource development and the creation of a 'demand for professionalism in Africa.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The UNDP, the African Development Bank and the World Bank, collaborated in the early 1990s to set up the 'African Capacity Building Foundation' (ACBF), based in Harare, Zimbabwe, with initial seed money of about $30 million and another $70 million attracted from bilateral donors and African governments themselves. The fund is to be used by the Foundation to support capacity building in Africa through training and institution building. Particular attention will be paid to the rehabilitation and strengthening of selected research and training institutions to meet the challenge of indigenous capacity building. Another initiative set up with foreign donors and African support, the Africa Research Consortium in Nairobi, is a good example of collaboration at regional level that is contributing to capacity building in the critical area of economic policy analysis and management. Similarly, the African Development Bank helped establish the African Business Round table which promotes entrepreneurship and enterprise development based on African ownership and control.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Role of the ILO</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For well over three decades the ILO, as part of its technical cooperation programme in Africa, has been involved in a wide range of management development, productivity and institution building initiatives at both national and regional levels. This is consistent with the need to strengthen African training institutions to play a crucial role in providing development managers with the necessary skills to analyse and formulate policy options and manage public and private enterprises efficiently.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most successful initiatives undertaken by the ILO, in collaboration with the UNDP and the Economic Development Institute (EDI) of the World Bank, is the UNEDIL programme for strengthening management training in Africa. Since its inception in 1987, the UNEDIL programme has proven to be a worthwhile initiative in institutional capacity building in the management field. Support for the programme has also come from national and regional management development institutes (MDIs) in Africa, regional and sub-regional organisations such as SADC and the Commonwealth Secretariat, and major bilateral donors such as USAID, CIDA, NORAD, the Netherlands and France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apart from aiming at strengthening institutional capacity, the UNEDIL programme has been instrumental in fostering networking among African development institutes and promoting professional contacts and the exchange of experience. One outcome of the programme has been the revival of three subregional MDI associations which enjoy the direct support of UNEDIL and serve as focal points for UNEDIL's subregional networking arrangements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Networking on a subregional basis has made it possible to optimise the use of scarce resources and talents, and this has helped to increase managerial capacity in the region as a whole. Collaboration has also permitted an exchange of experience among African institutions, and has brought together expertise both from within Africa and from outside to assist in the development of managerial capacity across the continent. This fits in with the goals of technical cooperation in general, and of South-South cooperation in particular. </P>
+<P ALIGN="JUSTIFY">F.L. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The role of international academic cooperation</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Increasing demands and diminishing resources in higher education</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Professor Dumitru Chitoran</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As we approach the end of the millennium, higher education world-wide finds itself in a paradoxical situation. On the one hand, it is witnessing unprecedented growth. Enrolments are on the increase and so are the expectations placed on it by society. The correlation between investment in higher education and research, and the level of social, economic and cultural development of nations is well-established and is gaining increasing ground at a time when all development has become knowledge-intensive. On the other hand, higher education is in a state of crisis in practically all countries of the world, under the pressure of serious financial constraints. It has to compete for public funds with many other sectors and very often it is among the first to undergo severe cuts. These cuts have reached a dramatic threshold in the developing countries. As a result, the gap between the developing and the developed countries with regard to higher learning and research is wider than ever and it continues to grow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inter-university cooperation has emerged as a major tool for the support of higher education in the developing countries and as a flexible mechanism for the rapid transfer and sharing of knowledge, channelled via university links and exchanges. As emphasised in the Policy Paper for Change and Development in Higher Education issued by UNESCO in 1995, 'the most pressing need for international cooperation in higher education is to reverse the process of decline of institutions in the developing countries, particularly in the least developed.' The internationalisation of higher education has advanced steadily, reinforced by current processes of economic and political integration and facilitated by the steady advances in information and communication technologies. But, as indicated in the UNESCO World Education Report (1993), it is increasingly subject to the competitive laws of the market. Universities have been urged to develop an entrepreneurial, commercial attitude and to regard international cooperation mainly as a source of additional income. Fees for foreign students have risen considerably in many countries. As a result, academic mobility is becoming more North-North and less South-North or South-South. The benefits of study abroad, of exchanges, networking and access to data are recognised, but the costs involved render them increasingly a privilege, restricted to those who can afford it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An innovative programme</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNESCO's response to these trends was the UNITWIN/UNESCO Chairs Programme, launched in 1991. While serving as an instrument to foster overall inter-university cooperation, it was aimed at giving a clear direction and goal, namely to support higher education in the developing countries. It was meant to mark a return to the spirit of international academic solidarity, through twinning, networking and other linking arrangements among universities. The programme was also designed as an innovative form for the rapid transfer of knowledge, and for institutional development in higher education, including the establishment of transnational centres for advanced studies and research, as a means of redressing the widening knowledge gap between industrially developed and developing countries. One other aim of the Programme was to alleviate the negative effects of the brain drain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The UNITWIN/UNESCO Chairs Programme has seen steady and dynamic development from the very beginning, and has emerged as the major thrust of UNESCO's action in the field of higher education. The favoured institutional framework for carrying out activities is a UNESCO Chair. The programme's activities are extremely diverse. They include the appointment of visiting professors, provision of scholarships and fellowships, facilitating of staff and student exchanges and undertaking of joint research. The 'chairs' are typical of basic units of research and training, with a strong international dimension, since either the chairholder, or some of the professors or researchers associated with its programme come from abroad. Other projects involve complex inter university networks, varying in size from three to more than 50 institutions. Within networks, certain institutions serve as focal points, responsible for initiating activities and securing broad participation in their execution. Also included are cooperation programmes established by UNESCO with major university associations and networks in order to carry out UNITWIN-related activities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present, there are 163 established UNESCO Chairs (a further 84 are under consideration) and 34 largescale networks (18 more are being developed). A total of over 750 teachers, researchers and other support staff are involved in their activities. It is estimated that 350 courses (mainly at the graduate level), attended by more than 7500 students, were organised by the established UNESCO Chairs during the 1992-1996 period. Also, 120 seminars, training workshops, symposia and colloquia were staged over the same period, attended by more than 6000 participants. Some 580 academics from developing countries spent short periods of time at partner universities in the developed countries to upgrade their training. In addition, 355 scholarships have been granted to students and young academics from developing nations within the framework of the Programme. Research has been encouraged through 240 projects (mainly joint ones) resulting, according to progress reports received so far, in the publication of 55 volumes, some 100 published articles and over 150 monographs and progress reports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ACPs in the programme</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A large number of these projects (UNESCO Chairs and networks) concern ACP countries. Africa has been given top priority. Over 30 of the established Chairs are located there and 18 more are under consideration for subSaharan Africa, in order to reinforce the contribution of the programme to the development of higher education in this region. In addition, certain projects located at institutions in Europe and North America carry on activities which are designed to support African universities. A few examples illustrate this. Starting from its bilateral links with several African universities, the University of Utrecht proposed developing these into a broader, multilateral project under the umbrella of UNITWIN. For this purpose, it joined forces with three other European institutions: the University of Lund in Sweden, the Ruhr University in Bochum, Germany and the University of Porto in Portugal. The result was the establishment of the Utrecht/Southern Africa/UNITWIN (USU) network. It includes, at its southern pole, the universities of Harare, Maputo, Namibia, and Western Cape, where UNESCO Chairs have been established in different fields. The aim is to develop each of them into (sub)regional centres of advanced study and research. This is well under way in the case of the UNESCO Chair in Mathematics and Science Education at Western Cape University in South Africa. A first step was to link its activities to those of the MESA (Mathematics Education in South Africa) project, a cooperation project between the Utrecht-Freundenthal Institute for Mathematics Education and the University of the Western Cape. A school for Science and Maths Education is to be established at the University of Western Cape.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another large scale project is the Network of African Teacher Training Institutions, built around a UNESCO Chair at the Ecole Normale Superieure in Dakar. This is designed to serve as a regional centre for postgraduate training and research in the field of education. After several years preparation, activities were launched in 1995. The strength of networking is illustrated by a number of other linking arrangements in support of African higher education institutions. These include the network initiated by the NATURA Group of European universities in the field of agriculture, the ORBICOM Network in the field of Communication, which is a global network but pays particular attention to the needs of African universities, and the UNESCO/John Hopkins University Networking and Partnership in Adolescent Youth Health and Development. The last-mentioned focuses on HlV/AIDS-related research, and includes institutions such as Addis Ababa and Makerere Universities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The agreement signed by UNESCO with the Association of African Universities (AAU) within the framework of UNITWIN provides for support of the latter's staff development and management programme. A UNESCO Chair in Educational Management and Administration is to be established. It will function on a rotating basis at several universities in South Africa, Botswana and Malawi. There are also a number of 'tailor-made' chairs which respond to more specific needs of institutions, notably to develop training and research capabilities in areas such as human rights, democray and peace (at the Universities of Namibia, Addis Ababa and Fianarantsoa in Madagascar), or in the field of Water Resources and Water Culture (at the Universities of Malawi and Omdurman in Sudan). In the latter field, an interesting example is the UNESCO Chair established at the University of Nice, which, although located in France, carries out its activities in Mauritania and has produced the most comprehensive study so far on water resource management in that country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The programme has also made a good start in the Pacific and the Caribbean, even if achievements there are on a more modest scale. There are already 22 established chairs with 14 more under consideration. They cover a wide spectrum of priority fields, including the sustainable use of rain forest resources at the University of Guyana, higher education management and information technology at the University of Havana in Cuba, educational sciences in Fiji, and the use of drugs in Chulalongkorn University in Thailand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNESCO works closely with the University of the South Pacific and the University of the West Indies, with which it has established four UNESCO Chairs. Moreover, it has signed a cooperation agreement, in the framework of UNITWIN, with the Commonwealth Secretariat and the Association of Commonwealth Universities for activities in both regions. There is great potential for the further development of the Chairs programme in the Pacific and Caribbean, given the existence of the two regional universities mentioned above and the strong interest of universities in a number of developed countries (such as Australia, Canada, Japan and Spain) in supporting the programme. It appears to be particularly well suited for the systems of higher education in the two regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Funding</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The cost of international cooperation in higher education has risen steadily and this is currently one of the major obstacles preventing the full use of the potential of academic links. New information and communication technologies help reduce costs, but universities in the least-developed countries would first need considerable investment in order to procure and maintain the necessary equipment. That is why UNESCO has based the Chairs programme on funding principles aimed at lowering costs and sharing them in a genuine spirit of academic solidarity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the outset, UNESCO made it very clear that, since it was not a funding agency, it could not, by itself, assume the financial burden of such an ambitious programme, involving several hundred institutions and thousands of university teachers, researchers and students. However, it decided to make a commitment by providing some initial funds. Rough estimates indicate that, over the 1992-1995 period, UNESCO has contributed some $2.5 million (from its Regular and Participation Programmes, Fellowship Bank and Funds-in-Trust) to the UNITWIN/UNESCO Chairs Programme. At the same time, it has pressed for increased international development aid for higher education, particularly from the developed countries, and from international organisations, including the UN specialised agencies. A strong case is made for the benefit of pooling resources and for involving directly the higher education institutions themselves </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNITWIN-based projects, including UNESCO Chairs, are usually initiated through the direct contributions of UNESCO (the range is generally between $15 000 and $25 000 per individual project). This is meant to help prepare and launch projects and to secure further funding from other sources. The institutions themselves must include allocations for the respective projects in their own budgets and request their appropriate national authorities to make contributions. This applies equally to universities in the developing countries, however poor their resources may be. It serves to indicate that the project in question is indeed seen as a priority by them and by their national authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Experience of the UNITWIN funding formula so far gives cause for cautious optimism. Many projects have been able to secure funds by having recourse to the various sources mentioned above. Thus, the Utrecht/ Southern Africa/UNITWIN Project received a first UNESCO allocation of $50 000 in 1993, in order to launch its activities. The fact that it concerned a large-scale project (a network of eight universities, with four chairs established at four African universities and one at the University of Utrecht) explains the larger UNESCO allocation. This was followed by a second allocation of $70 000 in 1994 for the actual implementation of activities in Africa. The UNESCO seed money led to additional funding-$600 000 annually, for the 1992-1995 period, from various Dutch donors (mainly the Ministry of Development Cooperation, through NUFFIC) and from the European Union, and $450 000 from the University of Utrecht budget, including the total cost for the functioning of the UNESCO Chair on African Studies established at that university. The other three European universities participating in the network (Bochum, Lund and Porto) have also made contributions and are now looking for donor funding in their countries. It is important to mention that the four African universities belonging to the network have also allocated funds from their own budgets to the UNITWIN projects and are actively seeking additional resources from aid and development programmes established for their countries by various donor agencies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It can be fairly argued that in terms of cost-effectiveness, efficiency and the ability to generate funding from various sources, UNITWIN compares favourably with existing cooperation schemes in higher education and research. But it is still too early to conclude that the Chairs Programme can continue and develop further on the basis of the present funding arrangements. The needs are arguably too big for the institutions and individuals involved, who may find themselves in a perpetual search for funds. An evaluation of the programme is under way and this will be submitted to the Member States for their decision. UNESCO is hoping that its efforts to revive academic solidarity, and its campaign in favour of higher education in the developing countries will receive the support of the international community. More than ever before, these countries need to develop their capacity for advanced training and research in order to achieve self sustainable development. The academic community has already indicated its willingness to join forces with UNESCO in this undertaking. </P>
+<P ALIGN="JUSTIFY">D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Brain drain : Colossal loss of investments for developing countries</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When a highly qualified professional chooses to leave his own country for another, he does so for one or several legitimate political or economic reasons: peace and security for himself and his family, job satisfaction, better pay and conditions. a higher standard of living, etc. Throughout history, countries and centres of academic excellence which offer these attractions have received the largest numbers of professional migrants and these have, in turn, made substantial contributions, not only to the economic growth of their host countries, but also to the scientific and technological advancement of humanity. The wave of German scientists who moved to the United States after the Second World war, and their discoveries and inventions, come readily to mind. On a global level, therefore, the free movement and interaction of highly skilled people is a positive thing. But the costs to the home countries of losing their professionals is incalculable-in terms of both development opportunities and loss of investment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whereas Western Europe was the main loser, especially to the United States, up until the 1960s, the developing countries have emerged in recent years as the biggest suppliers of qualified professionals to the industrialised world as a whole. Today there are more than a million and a half skilled expatriates from the developing countries settled in Western Europe, the USA, Japan and Canada. The USA's educational system and its research institutions are heavily dependent on them. These migrant professionals contribute in no small way to increasing the disparities between the world's rich and poor nations. And it is the developing countries that need them most.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Africa, which has serious shortages of manpower, has been worst hit. It is said to have lost 60 000 professionals (doctors, university lecturers, engineers, surveyors, etc) between 1985 and 1990 and to have been losing an average of 20 000 annually ever since.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are more than 21 000 Nigerian doctors practising in the United States alone. Meanwhile, Nigeria's own health system suffers a cruel lack of medical practitioners. 60% of all Ghanaian doctors trained locally in the 1980s have left the country, according to the UNDP's 1992 Human Development Report, while, in Sudan, 17% of doctors and dentists, 20% of university lecturers, 30% of engineers and 45% of surveyors have gone to work abroad.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it is difficult to calculate the cost of an expatriate professional in terms of the nutrition, health care and education provided by households and the State, it is clear developing countries are losing colossal amounts of investment annually to the developed countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The US Congressional Research Service, for example, computed in 197172 that the USA gained $20 000 annually on each skilled migrant from the developing countries. If this rather conservative amount is extrapolated for Africa, then the continent lost more than $1.2 billion of investment between 1985 and 1990 on the 60 000 or so African professionals who emigrated during that period. Much closer perhaps to the truth today would be the estimate made by the United Nations Conference on Trade and Development (UNCTAD), using 1979 prices, which put a cash value of $184 000 on each African professional migrant (and this only for those between the ages of 25 and 35).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the other hand, expatriate remittances, particularly from skilled workers who earn higher salaries than the average migrant, constitute an important source of funds for development in their home countries. Throughout Africa, households are being maintained by remittances from relatives working abroad. Also, fine buildings are being put up and small-scale projects are financed in villages and cities across the continent with funds sent from overseas. But taken together, these will never be large enough to compensate Africa for the loss of investment suffered as a result of the 'brain drain'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Serious flaw in international cooperation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The migration of highly qualified professionals from the developing countries is an extremely complex problem which presents the international community with a major dilemma. First, the 'brain drain' cannot be stopped by force nor can it be legislated against. It is linked to fundamental human rights- the right of individuals to move from one country to another, although the exercise of that right is governed by the immigration policies of individual countries. Second, it is fundamentally a national problem which can only be resolved at the national level by providing enough incentives for qualified nationals to remain at home. Third, some industrialised countries like the USA and Canada, have historically operated liberal immigration policies. Even European states, whose immigration policies tend to be more restrictive, have a good number of third world professionals, but there are over a million in the USA and Canada. It is arguable whether, under the circumstances, the liberalisation of the international labour market under the World Trade Organisation, as is being suggested (even by some developing countries), will actually be in Africa's interests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The reasons for Africa's brain drain problem are legion and easily identifiable, being both structural and economic. The most often cited cause is the continent's school curricula which many see as still largely modelled on the systems of the former colonial masters. This, it is argued, has led to the production of graduates in disciplines that have little or no relevance to the socio-cultural and economic milieux of the continent. This is a highly debatable assertion, given the large numbers of the technical assistants currently working in Africa who are products of the educational systems of the former colonial powers-at least some of whom are having a positive impact on the continent's development. This, however, must not distract from the fact that African higher schools systems are illequipped to produce the right skills for Africa's development needs. Because of shortages of both science equipment and teachers, the system instructs the vast majority of pupils in arts rather than in science and technology-and it is the latter which hold the key to economic growth and development. Thus, there is overproduction of graduates in areas where there are few employment opportunities. This results in high levels of migration, even, paradoxically among the few trained scientists because of the absence of an environment conducive to full professional expression and satisfaction. It is not uncommon for things as simple as electricity and water supply to provide reasons for emigration. Examples abound of frustrated African scientists who have had their experimental work of several years destroyed overnight through power failures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Powerful factors in the brain drain include Africa's poor rates of economic growth over the past 30 years (worsened by structural adjustment measures which have resulted in dramatic falls in living standards) and political instability (disturbances in Nigeria and Zaire, civil war in Liberia, Sierra Leone and Somalia etc). Thousands of qualified professionals have been forced unwillingly into exile, and the majority of those left behind, in these times of serious economic crisis, are engaged in unskilled pursuits-in petty trading and taxi driving-far removed from their professional training. The loss of investment associated with this situation cannot be underestimated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sub-Saharan Africa is in the paradoxical situation today of having large numbers of graduates in various disciplines -from medicine and engineering to architecture and accountancy-who have either emigrated or are simply unemployed, while it hosts a large army of foreign technical assistants. Indeed, Africa receives more advice per capita than any other continent. In 1988, there were more than 80 000 technical assistants, and today the figure is well over 100 000. These experts are believed to cost donors a total of $4bn annually to maintain, a figure which represents nearly 35% of Africa's total official development aid. This situation reveals a serious flaw in the operation of international development cooperation. Would it not be more efficient and cost effective to employ qualified African expatriates in the place of many of these foreign technical experts. The former, after all, have both linguistic and cultural links with the continent. The United Nations Development Programme (UNDP) has a programme in this area which points to a possible way forward. The article on that programme, TOKTEN, follows. </P>
+<P ALIGN="JUSTIFY">A.O.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">'Brain gain' : A cost - effective UNDP programme</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the scale of the brain drain problem facing the developing countries, the UNDP's Transfer of Knowledge Through Expatriate Nationals (TOKTEN) project may not amount to much, but it has proved, in its 19 years of existence, to be a cost-effective way of getting highly qualified expatriates from the developing countries to contribute to the development of their countries of origin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It all started in Turkey in 1977 by pure accident. A Turkish mineral expert in Alberta, Canada, was asked by a compatriot if he would be kind enough to come over to Turkey and explain his innovative coal cleaning process to the staff and students of his old university in Ankara-the Middle East Technical University. He expressed his interest in the project. Soon afterwards he was contacted by the UNDP which offered to fund part of his trip to Ankara. The expert spent one month in Turkey giving a series of seminars, not only at the Middle East Technical University, but also at the Istanbul and Dokuz Eylul Universities. During these lectures, he made recommendations on resolving Turkey's specific coal utilisation problems. His impact was immense and such that the UNDP was inspired to set up the TOKTEN project along similar lines to help developing countries gain from the knowledge of their expatriate professionals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The system is simple. Member States of the United Nations can apply to join the project. The latter is administered in each country by a National Working Commitee (NWC) which is made up of representatives from the government, local organisations, the private sector and the UNDP. Institutions of that country (government ministries and agencies, private and public sector enterprises, universities, research and development institutions, hospitals, etc) can apply for assistance in a variety of areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Applications are processed by the NWC and recruitment of experts is usually in one or more of the following ways:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> through consultants with lists of experts recognised by the Government as having extensive contacts within their expatriate communities;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> through embassies and missions, alumni associations and research institutions;</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> through prominent members of the country's expatriate community who identify and alert other high level expatriates of the opportunities to return home and serve their countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the Working Committee chooses a consultant, an offer of assignment is made. The beneficiary organisation and the consultant will then determine the timing of the mission and inform the UNDP.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TOKTEN assignments last between one and three months depending on the ability of the consultant and the needs of the beneficiary'. They are not meant to be highly remunerative. Consultants are only entitled to round trip economy fare tickets (by the most direct route) and a daily subsistence allowance at the prevailing UN rate. The costs are paid out of the beneficiary country's 'Indicative Planning Figure'(IPF) which is the amount of assistance the UNDP makes available to a developing country over a five-year programming cycle. Health insurance cover and accommodation is not provided. Usually these are the responsibilities of the beneficiary government or organisation. The salaries of the consultants during their absence are paid by their affiliated employers whose agreement is often necessary for the projects to go ahead.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">TOKTEN consultants are thus not motivated by money but by a genuine desire (with a modicum of patriotism) to contribute to the development of their countries of origin to which they retain strong cultural and linguistic ties. And their impact on the ground is usually immediate and measurable. Pressures are not put on volunteers to return permanently to their countries, although many have chosen to do so since the programme began in 1977.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The system is not only low-cost and cost-effective. It covers a great variety of specialised fields and enables programmes to be implemented with speed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conditions for success</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A UNDP assessment of the programme in 1987, ten years after it began, concluded that regular monitoring of its operation had enabled information garnered to be applied to increase its effectiveness. It had been found, for example, that short-term expatriate consultancies were especially beneficial when the problem tackled was specific and the consultant selected was of international standing, when both the requesting organisation and the expatriate were well prepared in advance, and when the initial mission was followed up by a series of measures, often including a return visit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By 1992, 35 countries were participating in the programme and over 3800 consultancies had been run. Since then, the number of countries has increased dramatically to 51 and con</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">sultancies to 5000. In 1994 and 1995 alone, 28 countries reported over 700 consultancies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It has also become clear that, whereas the main recipient institutions have been government agencies, science and technology research institutions, universities and organisations, the private sector is increasingly showing interest in the programme. The number of female specialists is also increasing: in 1991, 40 consultants were women and last year this figure rose to over 100.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So far, the ACP countries participating in the programme are; Benin, Cape Verde, Central African Republic, Chad, Dominica, Ethiopia, Fiji, Guinea, Guyana, Haiti, Liberia, Nigeria, Sao Tome &amp; Principe, Sierra Leone, St Lucia, Trinidad &amp; Tobago and Uganda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Success stories include a highly skilled Guyanese medical practitioner in the United States who returned home after 17 years to assume the post of minister of health. He had been sent to oversee the introduction of certain aspects of health care such as preventive medicine (immunisation, general child care and nutrition), treatment of trauma (victims of accidents and violence etc) and the establishment and management of the physical facilities for emergency patients. During his stint, his recommendation on the upgrading of the emergency room facilities was rapidly implemented and this contributed significantly to improving patient care. Another story involved a Guinean banker who, after a consultancy stint in Guinea, abandoned a lucrative job in France to return home permanently to work at the Central Bank of Guinea, helping to set up a new loan system for commercial imprt and export businesses. Guinea, in fact, has been one of the greatest beneficiaries of the TOKTEN programme with numerous consultancies involving the University of Conakry, covering more than 20 disciplines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For very small sums the programme is ensuring that developing countries which have invested enormously in the education of their expatriate nationals have a return, at least, in the form of the knowledge they oquired.</P>
+<P ALIGN="JUSTIFY">A.O </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Mobilising Commonwealth skills for Commonwealth development</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The role of the Commonwealth in the economic and social progress of its member states is neither widely known nor widely publicised. Yet for over 25 years, the Commonwealth Fund for Technical Cooperation (CFTC) has made significant contributions to the efforts of its developing member countries to accelerate the pace of their economic development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The recognition by the Commonwealth that people are its greatest resource forms the basis of its approach to development assistance-providing, in the short term, specialist technical skills which are either not available or are in short supply to governments to enable them to fill key positions in areas as diverse as export and industrial promotion, high-level economic and legal services etc, and in the longer term, a wide range of training programmes in areas that are crucial for economic development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commonwealth Fund for Technical Cooperation is funded by voluntary financial contributions from member governments which, as has just been mentioned, can also draw on it according to their needs and priorities. As a pioneer of technical cooperation between developing countries, the Fund recruits its experts from these countries and encourages South/South cooperation. It is thus not uncommon to see West Africans serving, on short-term contracts, as legal officers in remote Pacifc island states or Sri Lankans or Indians advising on new agricultural techniques in Africa. The Fund is administered by four separate divisions within the Commonwealth Secretariat: the management and training division; the general technical assistance division; the export and industrial development division, and the economic and legal advisory services division. In 1994-95 the CFTC's financial resources stood at around f23.6 million (ECU 30m).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Human resource development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nearly one-third of the CFTC's budget is spent on human resource development, helping enhance people's skills through a mix of training workshops, study visits and individual attachments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some 4000 training fellowships were awarded in 1993-95 to enhance technical skills. These were given to middle and senior professional, technical and administrative managers to study at some of the Commonwealth's best institutions or to take up work attachments (63% of training takes place in less-developed countries).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Fund also enables universities and other institutions to become centres of excellence and upgrade the tuition they offer by appointing academic and technical specialists. In 1993-95, for example, it helped five universities in Africa and the Caribbean to run applied Masters courses through collaboration with other Commonwealth universities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As the CFTC is usually able to meet only 60% of the requests it receives for specialised training, its programmes are held on a regional and pan-Commonwealth basis to maximise impact, especially in topics such as administrative reform, financial management and strategic planning.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Fund's training priorities include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- first and foremost, identifying needs (consultants are sent to countries to examine their development plans and help them to prioritise training needs).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- providing education and training in key areas that reflect CFTC concerns such as well-managed economic and financial reform by government, sustainable development, participation of women and application of technology.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- ensuring an integrated package of consultancy, advice and training to help managers in government, and public and private sector enterprises to coordinate and manage reforms and restructuring.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- organising policy workshops and seminars that bring together senior government officials, executives and academics from Commonwealth countries to pool experiences, learn examples of best practice, discuss problems and reflect on emerging issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- giving support to institutions to offer new and specialised education and training programmes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- providing technical and vocational training under the Commonwealth Industrial Training and Experience Programme (between 1993 and 1995, workshops were held in hospital equipment repairs, railway repairs and maintenance and computer-assisted manufacturing).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- providing training in information systems, new technologies and environmental issues (governments are helped to develop management information systems and apply information technology). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-setting up programmes for women with a particular focus on entrepreneurs and community managers (among other initiatives, the CFTC is helping three African universities develop specialised programmes in entrepreneurship for women in non-traditional sectors).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-coordinating wider linkages among professional networks to facilitate exchanges of information and examples of best practice (the CFTC recently helped to set up the Commonwealth Association for Public Administration and Management to assist in improving public service performance and in raising ethical standards).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Expertise on tap</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shortage of skills is one of the biggest stumbling-blocks facing countries trying to raise the living standards of their people. Providing experts accounts for about one-third of the CFTC's budget.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because its assistance is relatively small and carefully targeted, it avoids the potential waste associated with larger scale projects and poor technical planning. In 1993-95, the cost both of a typical long-term expert and an average project was around £50 000 (ECU 62 000) a year. Experts can be in place within three or four weeks of project approval.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the same period, over 200 long- and short-term experts were provided to 43 developing Commonwealth countries, six dependent territories and 18 regional organisations. The expertise requested is extremely diverse, from hydrography and agroforestry to tourism, statistics, legal affairs, health, social planning and computer science.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Assignments for short-term experts can range from a few days to six months. Their role is advisory, helping governments to introduce new systems or technologies. Long-term experts stay usually from six months to two years; others may stay up to four years. Experts assist in the development and implementation of policies or in the provision of managerial skills and the training of counterpart staff to take over in due course. Some long-term experts are trainers in specialist fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The CFTC makes every effort to appoint women experts. In 1993-95, they made up 13% of experts that were sent to the field. These included a consultant anaesthetist in Ghana, an agricultural economist in Mozambique, an information specialist in Barbados, a fisheries development officer in Papua New Guinea and an environmental lawyer in Seychelles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A scheme to allow suitably qualified and experienced people to volunteer as short-term experts for a maximum of three months was launched in mid-1995. The scheme draws on experts from the Commonwealth who are willing to give their services on a voluntary basis to developing countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Entrepreneurs come first</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In its help to small businesses, the CFTC focuses on those who manage the businesses and identify new entrepreneurial talent. Most assistance is given to small states, especially in the Pacific. The programme has three phases: the first relates to 'surveys of opportunity' which is aimed at identifying suitable entrepreneurs, investment opportunities and potential for expansion as well as specific problems. Next comes 'workshops on entrepreneurship development' during which business owners and operators are helped to think creatively, to become more aware of opportunities that are available and to act strategically when planning expansion. And the last are what we call 'business clinics' in which one-to-one counselling is provided to an entrepreneur at his or her business. This personal support has proved very successful in helping individual entrepreneurs to become more efficient and competitive and, by implication, adapt to changing world economic conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Developing exports</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The CFTC has pioneered the use of Contact-Promotion programmes and 'Buyer-Seller Meets' forums to help small exporters. These forums allow company representatives, often from small Commonwealth countries, to display their wares and meet prospective buyers from other countries. CFTC consultants plan these activities well ahead, short listing producers that are likely to succeed, identifying suitable foreign markets and advising on redesigning of products. Sometimes exporters and factory staff also receive training.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The CFTC funds a special 'export development programme' for women entrepreneurs. This includes detailed country studies of women engaged in exporting as well as sales promotions abroad. Studies of this type have recently been conducted in Cyprus, Sri Lanka and Zambia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women are helped, under the programme, to adapt their handicrafts for export, improve their manufacturing techniques and undertake sales missions abroad. Training is also given in export marketing, product development, costing and pricing. If necessary, changes to government policy are recommended. In 1994, the assistance given to Ghanaian women to develop markets for their basket ware and handicrafts is estimated to have helped generate sales worth US$3.1 million (ECU 2.4m). </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">EU's investments in education and training in the ACP states</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY">by Digby Swift</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Community's investments in human resource development-health, nutrition and education-in ACP states have regularly been covered in the pages of this magazine whether in the context of dosiers or of country resorts. Here we present a brief description of how the EU's policy in education and training evolved under the Yaounde and Lom&eacute; Convemntions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Educating all the people. This is not just a slogan. In a poor, underdeveloped country, there may be some short-term gains from supplying high quality education and training to an elite few. But, as the 'Asian Miracle' has proved, major long-term gains in development and wealth are possible only if the entire population possesses a reasonable level of education.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Now for the problem. For many countries, notably those of sub-Saharan Africa, a large proportion of school age children receive no education at all. Of those who do attend school, many receive little benefit from their education because of the very low quality of provision. Only a small minority reach secondary education. And yet a higher proportion than ever of national budgets is now going to the education sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The problem is urgent because of the time it will take to resolve. Even if we could wave a magic wand to provide all children with a good primary education, it would take a decade to see the benefits.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How is European aid helping to tackle this problem? What have been the guiding principles of European aid to education in the past? And why is the problem still acute in, for example, subSaharan Africa, despite decades of investment in aid to education ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aid mirrors developments</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aid to education has mirrored developments in the education sectors of the countries concerned. For example, the low-income countries of Africa, which account for 73% of Africa's population, have seen a rapid expansion in their education systems followed by a collapse of funding. This has resulted in a serious decline in standards of provision. European aid, which began by providing piecemeal assistance to infrastructure and manpower, shifted to a 'project approach' to tackle these emerging problems and is now moving towards a coordinated sectoral approach to help tackle the reform of whole education systems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From 1970 to 1980, the number of pupils enrolling in the primary schools of developing countries more than doubled, and the numbers in secondary and tertiary education quadrupled. Even relative to the increasing population, there was a 90% increase in the proportion of primary-aged children in school, and a large increase in the proportion of girls. This growth was accompanied by a doubling of government budgetary resources made available to education.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the massive general economic decline between 1980 and 1985, the money made available for education from the public purse fell by 40%, yet the education systems continued to grow. The result was that teachers' salaries plummeted, and funds for non-salary recurrent costs such as teaching materials and maintenance virtually dried up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since 1985, the financial situation has somewhat improved and funding is now at an all-time high. Nevertheless, for many African states, the education sector is in a state of crisis. Buildings are crumbling and inadequate; teachers are untrained or undertrained and often absent because of low incentives and weak supervision. There are few books and other teaching materials. Consequently, many pupils leave school virtually illiterate and innumerate. Moreover, because of the low quality of instruction and increasing costs to parents, many parents are no longer bothering to send children to school even when places are available. Primary enrolment fell by around 10% between 1990 and 1992. Thus in many countries, a fundamental reform of the sector is seen as the only way forward.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Evolution of aid</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the early days of European aid, education and training were seen as suppliers of manpower for countries to modernise their economies. The priority themes of the 1970 Yaounde Convention for European Community aid were industrialisation, regional cooperation and international trade. Community support to education and training focused on the construction of colleges and university faculties to serve industrialisation and regional cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 1975 Lom&eacute; I Convention referred specifically to 'the establishment of regional institutions of advanced technology, in the context of training programmes to enable nationals to participate fully in economic development'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 1980 Lom&eacute; II Convention introduced multiannual training programmes, and support in the form of training awards and courses/seminars; experts and instructors; teaching equipment; collaboration between training or research establishments and universities. The emphasis was still on vocational training for other sectors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A significant proportion of European bilateral aid to education and training took the form of European teachers for secondary schools, colleges and universities. These helped to cover the shortage of locally trained teachers, whilst educating an elite able to fill senior and middle positions in the public and private sectors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By 1985, problems were becoming all too apparent within the education systems being supported. As in other sectors, there was increased emphasis on the 'project approach' towards tackling these problems. Thus the Lom&eacute; Ill Convention includes support to education and training 'in the form of integrated programmes aimed at a well defined objective'. This could include, for example, 'assisting the ACP States' own efforts to restructure their educational establishments and systems and to update curricula, methods and technology employed, in order to step up the effectiveness and cut back the cost of all types of training'. A concern for under-represented groups, particularly women, was also becoming explicit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By 1990, the concept of investing in people through education and training had moved high on the donor agenda, and alongside it, a growing concern for sectoral reform. According to the 1989 Lom&eacute; IV Convention, 'Cooperation shall be aimed at supporting development in the ACP States, a process centred on man himself and rooted in each people's culture. It shall back up the policies and measures adopted by those States to enhance their human resources, increase their own creative capacities and promote their cultural identities. Cooperation shall also encourage participation by the population in the design and execution of development operations.' In a chapter entitled Operations to enhance the value of human resources, a section on Education and Training refers to supporting the ACP State's efforts to 'reform their basic education institutions and systems, in particular by providing overall primary education coverage and adjusting imported systems as well as building them into development strategies'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the late 1980s and early 1990s, European states and the Community joined the World Bank in support of structural adjustment. In a 1991 communication to the European Development Council, the Commission stated that it 'will give absolute priority to the social dimension of adjustment, in particular ensuring that the health and education sectors are adequately covered, in conjunction with sectoral reforms introduced or planned in these two areas.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Balancing this concern for system reform has been a growing appreciation of the importance of decentralised cooperation. An example is the cost-sharing microprojects for grassroots development first introduced in Lom&eacute; I with explicit mention of support to primary schools. Another example is the need to support the activities of nongovernmental organisations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A new policy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two events in the early 1990s have had a profound impact on European support for education and training. The first was the World Conference on Education for All: Meeting the Basic Learning Needs held in Jomtien in 1990. This emphasised the need for universal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">primary education and adult literacy to be firmly placed on the political agenda, and has resulted in a profound swing of donor support away from higher education and towards primary education. The second important event was the 1992 Treaty of European Union which requires the coordination of Member States' policy and operations, particularly in the social sectors. Guidelines are contained in the 1994 Council Resolution on support to education and training in developing countries in which 'the Council emphasises that education, in particular basic education, is a fundamental right'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to the Resolution, 'the priority for the Community and the Member States must be both to maximise access to education within the limits of the resources available and to ensure that the quality of education provided is suited to the needs of the majority of students. 'This is to be achieved through 'a balanced, programme-based strategy, tailored to the specific circumstances of the individual developing country', with pride of place accorded to basic education. It should provide 'support to the developing countries' own policies and efforts', not acting as a substitute for local initiative, and should involve better integration of action under structural adjustment with education sector priorities and aid activities. The Council also recommends a special emphasis on coordination in a number of pilot countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the outset, Community aid to education and training in African, Caribbean and Pacific countries has been in response to requests from the ACP states with an emphasis on ownership of the resulting programme by those states. What the new policy introduces into this process is a dialogue between government and all donors on needs, priorities and approaches set in the context of the education sector as a whole. Only through such a comprehensive approach can developing countries and European states reach a true partnership in realising the education and training needs of all citizens on which the future of their countries so crucially depends. </P>
+<P ALIGN="JUSTIFY">D.S.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Analysis</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">EU-ACP relations : Building for tomorrow</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY">by Kenneth Karl</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1989 saw the end of the Yalta inspired twin-superpower dominance. Nations had to examine their priorities in their desire for integration in an international environment in which geostrategic and economic realignment would be unavoidable. The philosophy which had served as a basis and reference point for North/South relations throughout the Cold War period is now being called into question and necessary adjustments in ideas have been triggered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Lom&eacute; Convention, which governs the development-cooperation relationship between the EU and the 70 ACP countries, is a unique North/South cooperation agreement on account of its contractual nature, its durability, the funds it allocates and the fact that it provides for a permanent dialogue. But it is also now at a decisive point in its history.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Those who regard the Convention as out-of-date and in need of renovation, and those more radical critics who believe that it no longer serves any useful purpose and must be phased out, both argue that a new direction is needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Beyond all the criticism formulated against this system, the fundamental question remains as to whether the Lom&eacute; Convention will be able, given the necessary changes, to carry on after its fourth version expires.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The years between now and the end of the century will, naturally, see the application of the revised Lom&eacute; IV, including the substantial improvements made to it. However, this same period must also be used to prepare the ground for ACP/KU development cooperation in the future, whatever form it might take.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shortly after his nomination as European Commissioner for relations with the ACP countries and South Africa, Professor Pinheiro commented, realistically, that the ACP countries are no longer 'in fashion'. The change of emphasis can be seen clearly if one looks at the EU's burgeoning relations with its eastern neighbours from the former Communist bloc (illustrated by the wide range of European programmes now benefiting these countries). One might also cite the strengthening of ties with countries in the Mediterranean basin. Economic and security concerns underpin this development, but it undoubtedly reduces the significance which was once accorded to the ACP states.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, the economic objectives of virtually all EU countries, as they seek to reduce budget deficits and deal with increasing internal social problems inevitably put pressure on the amount of development aid being granted to the Third World.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This situation is, of course, not restricted to the European Union - which in fact remains the world's main contributor of official development aid. At the instigation of a Republican dominated Congress, the United States is planning much more swingeing cuts in its contribution, both to certain international agencies and to certain regions (including Africa).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This undeniable cutback in public development aid has been offset in recent years by net increases in private capital flows, but the geographical distribution is highly skewed. Only a few of the poorest developing countries have benefited from the trend, the main 'winners' being the emerging states of Asia. These include countries such as China, India and Indonesia which, it is worth noting in passing, do not have particularly good human rights records, in the sense that the term is understood in Europe. Despite the fact that ACP countries have identified potential for attracting foreign investment, they have not actually benefited from this change in resource flows.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this climate, with official development aid in inaeasingly short supply, innovative methods for making optimum use of the available resources must be devised within the context of the Lom&eacute; Convention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On current indications, it is quite possible that in the year 2000, the Lom&eacute; Convention will be filed away in the archives. ACP/KU relations will certainly have to be more in step with recent developments on the international scene. The initial reasons for the establishment of a cooperative relationship between Europe and the ACPs, following the signature of the Rome Treaty, are now outmoded. As Paul Valery has commented: 'One of the worst mental aberrations is to think that things can survive when the reasons for their existence have gone'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So, what type of development cooperation should the countries of the European Union and their ACP partners aim for in the future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Alternative trends</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU has stated that it is in favour of a globalisation of aid within an innovative framework. One of the first questions to be asked is whether uniform cooperation with regions whose monolithic character is being increasingly called into question is still desirable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Variable geometry in development cooperation relations is increasingly being seen as the trend to be followed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If this option is chosen, there is a risk of the following scenario being created: The EU's relationship with the Caribbean could become diluted within its relationship with Latin-American countries and links with the Pacific countries could become confused with economic relations with Asia. What would then become of Africa, the continent needing most attention on account of the wide range of its difficulties and its increasing marginalisation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1990, the United Nations General Assembly, aware of the African question, adopted a new agenda on development in Africa, thus making that continent its number-one priority. Europe, on the other hand, must not simply focus on Africa but must invent new modes of action which are more concrete and more effective.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Secondly, recent trends imply greater conditionality. This has been taken on board not just by EU Member States. A number of multilateral aid agencies have also included it in their strategy. The OECD's Development Aid Committee believes that future relationships between North and South will be greatly influenced by conditionality and, indeed, the Organisation goes so far as to advocate this approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, conditionality in terms of development is a strategic element which must be handled with extreme caution. If cooperation, whether today or in the future, is to be based on conditionality, then it can only be rendered effective if aid recipients (both governments and the governed) are genuinely committed to the idea. They must be convinced, in a climate of resource-scarcity, than the approach is motivated above all by a desire for greater success.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union thus has a vital role to play, making full use of its advantages in terms of dialogue and consultation in order to prevent conditionality being perceived as a condescending mechanism. Thereby, it can help to prevent conditionality from generating the well-known perverse effects of 'tied' aid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of course, conditionality raises the thorny question of national sovereignty, but it is important to observe that modern international relations have moved on, both de jure and de facto, from a concept of absolute sovereignty to one of relative sovereignty. This is illustrated by the trend towards humanitarian intervention as a right, the requirements of the Bretton Woods institutions, supranationality in certain regional international organisations, and the very fact of world economic interdependence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This does not mean that the developing states should sell off their sovereignty to the highest bidder but that conditionality should be the subject of negotiation. Donors must be more flexible in their demands and thereby give the country in question such room to manoeuvre as is necessary for programmes to succeed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thirdly, development of the private sector appears now to be approved by all parties. Since independence, the State has been omnipresent and omnipotent in most productive areas of ACP economies. Given the failures of the public sector, private enterprise is now being called in to help. Its development is one of the sector specific policies which will and must receive most support.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The development of the private sector must permit better distribution of the fruits of the growth that it generates and promote integration of the ACP countries into the market economy. There can be no question of pitting private enterprise against the public sector, because any Manichean approach in this sphere might prove to be risky. It is important also to stress that free market development cannot take place overnight and that it is subject to inescapable macro and microeconomic preconditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Indeed, the birth and expansion of a dynamic private sector depends on the politico-economic fabric. This includes reliable financial bodies, functioning financial intermediation, adequate infrastructures, technical qualifications and training, a suitable legal/ regulatory framework, institutions to support private businesses, the channelling of the informal sector and a public sector which is prepared to play fair, aware of its regulatory role. These, in short, are the necessary ingredients for the adjustment of the private sector to permit the development of a true enterprise culture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The development of a harmonious private sector will make it possible more easily to achieve the transformation and export objectives required by international competitiveness. It should, therefore, help to counteract the erosion of commercial preferences generated by the Uruguay Round. The latter's time limits should, in any case, be extended, because it seems clear that the ACP countries will be unable to fulfil their obligations by the end of the moratorium obtained by the EU during the negotiations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The notion of compensating for inequality that is found in international development law, implies the adoption of a normative system to counteract the weak trading position of developing countries vis-a-vis their competitors in the North. But in recent times, this idea has been losing ground and it is unlikely to cut much ice with the WTO authorities. Legal equality in a situation where there is structural inequality is not, in fact, equitable, and it is therefore necessary to find some other way of mitigating the adverse effects, looking at it in a global context.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Promotion of domestic and foreign investment should be better supported. People talk of the 'risk/ country' threshold that deters foreign investors. It may be that this can be measured objectively by looking at economic and other indicators, but even if this is not possible, it clearly exists as a psychological barrier. This is a problem for many ACP countries and it needs to be crossed, using measures which tackle the many obstacles to investment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Changing the culture of development cooperation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Besides all the technical aspects, one could argue that the shortcomings of the Lom&eacute; Convention stem also from the perceptions of those involved in development cooperation. In short, it is the actual concept and culture of development aid which must be changed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the European side, the colonial legacy has conditioned attitudes, imprinting on them a dominant patemalism which is prejudicial to the aim of development. This European concept of cooperation must be overturned. Moreover, development cooperation must not be seen as the art of the possible but as the art of making possible what is strictly necessary, by virtue of genuine negotiation with the countries which have resolved to move forward.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, it is desirable to have a better developed policy of informing European public opinion about development cooperation. An effort is needed to counter false impressions, such as the one left by the French journalist who wrote: 'Official development aid is like taking money from the poor in rich countries to give it to the rich in poor countries'. Better information is needed to ensure that the public can decide such matters for itself.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Coordinating the Union's policies with those of the Member States now presents an enormous challenge. The political obstacles are huge and development cooperation may well suffer as a result of them if the objectives of coordination, coherence and complementarity contained in the Maastricht Treaty are not achieved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for the ACP countries, success in their economic development depends on many factors, cooperation being only one of them. Many political leaders in these nations have too often described cooperation with the North as the only way in which they can develop. In fact, this should be seen as nothing more than an additional factor - supporting the national effort and a genuine desire for development. It is pure fantasy to believe that development can be set in motion solely on the basis of an external impetus. To succeed, it must come from within a country. This is why future cooperation between the EU and the ACP countries must progress towards reinforcing the aptitude of the latter to devise, master and control their own development process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the future, the ACP countries must propose concrete and responsible solutions to their partners, doing so by means of the dialogue system. They must also promote development based on participation, particularly with the involvement of young people and women.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fact that the ACPs can offer a credible prospectus for development must be acknowledged. It is undoubtedly a challenge, but it can successfully be overcome if a climate of stability, security and confidence is created, matched by an unambiguous political will.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In KU/ACP relations, programmes must include the long-term vision necessary for sustainable development. Too often in the past, the strategy has been aimed at an immediate and ostentatious result. Successful development in the future will depend crucially on a change in such attitudes. </P>
+<P ALIGN="JUSTIFY">K.K. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let us know what you think</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The debate about the future of cooperation between the European Union and the ACP states is now beginning to gash' pace. Last year, we established the 'Analysis' section in The Courier to report on this debate-and give readers an opportunity to express their own views on the subject.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The response so far has been encouraging, but it has come mainly from the European side. We are keen to receive contributions from ACP readers as well. If you have you own ideas or opinions about what should happen after Lom&eacute; IV expires, why not put them on paper and send them to us. Our address is on the inside front cover of the magazine. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The view of civil society on the future after Lom&eacute; IV</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was the subject of a conference which took place in Maastricht from 12-14 June, under the auspices of the European Centre for Development Policy Management (ECDPM). It brought together participants from ACP countries and Europe, including representatives of civil society (NGOs, the private sector, etc.). Four major topics were addressed:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· How can a new KU/ACP commercial relationship be constructed ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was agreement that some form of preferential trade regime should continue after 2000. Some participants stressed the need to Promote 'fair trade', which would contribute not only to growth but also to development. The impact of individual trade preferences is not always clear-cut, but obviously there cannot be a single solution covering all problems in all ACP countries. An analysis of negative constraints demonstrated the difficulties involved in reconciling the rules of the Lom&eacute; Convention and those of the World Trade Organisation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· How can the private sector become involved in development ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most important aspect of this topic is knowing how to create a favourable and business-friendly environment which will enable the private sector to play its part-and the role the European Union could play in this process. The private sector was defined as both formal and informal, encompassing large, medium and small enterprises, whether local or foreign. The importance of a strong local private sector in guaranteeing long-term stability was particularly emphasised. In this respect, the view was expressed that the role of the state and its relationship with the European Commission should be redefined. There was also a call for time to be set aside time for effective dialogue, and to create the space for a partnership between the public and private sectors. It was felt that the role of Economic and Social Councils should be expanded and specified more clearly. As for the specific issue of privatisation, the point was made that this should not be seen as a panacea and that it should be approached on a country-by-country basis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As regards current instruments, it was noted that their objective is essentially to meet public-sector requirements. The role of the Centre for the Development of Industry (CDI) attracted some criticism. Speakers felt that the private sector should be more involved in the preparation and implementation of cooperation programmes with the European Community. Direct financial support to the private sector was seen as desirable, including backing from the European Investment Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What partnership ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The partnership concept was seen to have been eroded over the past two decades, with the pretext of efficiency resulting in a more paternalistic approach. Mechanisms needed to be found to enable EU priorities and the prerogatives of ACP countries to be reconciled. Reference was made to the political nature of the origin of the partnership and the need to find a new political raison d'etre for this type of relationship. The problems of cohesion within the ACP group and its relations with the EU were also raised, and there was a discussion about the possibility of giving the Convention a regional character-although a number of speakers expressed reservations about this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the European side, two lacunae emerged, namely coordination between donors, and consistency between Lom&eacute; and other Community policies (including relationships with the Bretton Woods institutions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the principle of partnership, some participants were keen to stress the motives of solidarity and common interest that lay behind cooperation. It was not simply a matter of 'negative' interdependence. The appropriateness of the term 'partnership' was questioned, if this was only to mean financial and technical cooperation. The politicisation of Lom&eacute; appears to be on the agenda, involving a move from the current partnership to a genuine 'contractual approach' through political dialogue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As for the role of partnership in cooperation policy management, it was felt essential that civil society and the private sector be involved. There was also a discussion of the debt problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· How can financial and technical cooperation be improved ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As usual, reference was made to the need to simplify and differentiate management of Lom&eacute; Convention instruments, particularly in the context of the programming process. As regards the role of non-state actors, a cautious approach was recommended. Finally, new instruments were called for to prevent conflict.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Conclusions</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This conference, coming after several others of the same type, was characterised essentially by private sector and NGO calls for greater participation in Community cooperation policy. Moreover, the need for 'politicisation' of the Lom&eacute; policy, shifting from purely financial and technical aid to a genuine cooperation contract, seems to have attracted the support of all participants. These questions are sure to figure in the 'Green Paper' on 'tome after 2000', which the European Commission plans to publish before the end of 1996. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dominique David</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">'Democratising democracy'</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On 6 and 7 June, the Belgian Par/iament hosted a UN seminar on 'me future of international development cooperation: new communication challenges' 'Democratising Democracy' was the succinct, journalistic way in which one of the speakers at the meeting summed up his solution to the problem of underdevelop meet. He was Jean-Bertrand Aristide, former President of Haiti, who observed that democracy, as advocated by the developed world, and increasingly accepted by developing countries, does not prevent the latter's slide into even greater poverty. The Courier had the opportunity to interview Mr Aristide. We began by asking him whether his statement implied that democracy is failing in a world striving to 'globalise' it J-B.A.-The word democracy comes from the Greek words 'demos', meaning people and 'kratein', meaning to govern. In other words, it signifies government of the people, for the people by the people-but if we take a look at the world today, the impression we get is that not all so-called democratic governments are in fact what they purport to be. Hence the need to 'democratise democracy', so as to create a situation in which all citizens can help set governments on a course towards such a model.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Concepts usually generate conflict and, therefore, when speaking of revolution, democracy or globalisation, it is necessary to be au fait with the subject matter so as not to become involved in a dialogue of the deaf. In the specific case of globalisation, my opinion is that this has a tendency to make what is an already precarious situation even more unbalanced. Concepts cannot be applied everywhere without thought being given to their harmful consequences. This does not mean to say that we should give up completely. It's one thing to speak of the globalisation of peace, as if an ineluctable need existed to promote peace on a world scale, but I'm not sure that everyone would define the globalisation of peace in the same way as I do.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Could we turn now to your own country, Haiti. How do you view the future of democracy there, bearing in mind the economic circumstances ? At the seminar, you mentioned several factors which demonstrate democracy's *agility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Democracy is indeed fragile. 1% of Haiti's population owns 48% of the country's wealth and it is estimated that about 65% of the working population is employed in agriculture as against 5.1% in the 'industrial' sector. But is this really the true picture ? Reality for most people is poverty-unacceptable and sub-human poverty. A man needs work to earn his daily crust by the sweat of his brow, but unemployment has reached catastrophic proportions. When people are unable to earn their living, there is little point in discussing the positive influence of democracy. What is needed is for those with a great deal of wealth and those with less wealth to talk to each other; a dialogue between the private and public sectors, so that we can head off futile conflicts and devote all our efforts to economic growth coupled with human development. I do believe that this is possible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yet, the rich are so rich and the poor so poor. Is it not fantasy to think that the gulf which separates them, and their mutual mistrust, can simply be set aside so that genuine dialogue can take place ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-This is one of the challenges we have faced ever since 1960 and, although we have not yet reaped the harvest of this process, we have to carry on. It's not too late. We just have to approach the subject logically and with all the facts to hand, and we must have the intelligence to be patient. If we continue with dialogue, we will achieve real results. Only the citizens of Haiti can play a part in Haiti's development-this is not a task for outsiders. We, on the other hand, have to be more receptive to international cooperation, while maintaining mutual respect and dignity. But what we also need is for our own people to act together in order to enhance our own growth. This is not to say that geopolitical reality can be disregarded. Other countries have to be taken into account, but, as a starting point, we have to consider Haiti's human and material resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Thereisdialogueata world level, but there are rules to be applied. I am thinking, here, of free competition. Haiti has to play by the rules, just like any other country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-Since we gained independence, our history has seen a succession of coups d'etat and people have been over-eager in brandishing weapons to solve economic, political or social problems. Now that democracy has been restored in Haiti, weapons are not the solution to our problems-I cannot stress this enough. What we need is for those with money to sit down and negotiate with those who have none: for the government to get people round the table and devise a common plan to accommodate all interested parties- looking at both the nation's interests and the interests of investors. I do believe that it is possible to achieve this. We have, in fact, already begun to prepare the ground. I am not basing my words, here, on pure theory, but am speaking from experience. In concrete terms, we have to transcend class and racial differences to recognise that Haitian men and women, regardless of their colour and the country they might live in outside Haiti, regardless of their nationality, even, are still part of Haiti's indigenous population. The way must be kept open for dignified and balanced cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The other point you mentioned today was that there can be no development without the effective involvement of the population. Are you not leaving yourself open to accusations of having socialist or even communist tendencies ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-As I have just said, we have to be scientific in our approach and check our facts over and over again. I fail to see how anyone can claim to be working towards peace without looking at poverty which is the greatest threat to social cohesion. Of course, there are those who would deny this assertion, and that is their right. However, rational analysis of the situation can help us alleviate poverty and promote security. It needs to be underlined that security is also one of the essential factors in economics. The UN Security Council is called in to prevent or resolve conflicts. To my mind, we should also be talking about an economic security council to deal with the economic realities. The deeper one plunges into poverty, the greater one's feelings of insecurity-the two always go hand in hand. And insecurity can crop up anywhere in the world. Nor is it a question of charity. It is a real, rational question which must sharpen our awareness, stimulate our common sense and set us on a course to protect the world by alleviating poverty. That, at least, is one approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, you have to recognise that politics is essentially a question of power while economics is influenced by interests. Everyone uses the means at their disposal to defend their personal interests and we know perfectly well that there are no free gifts. The so-called developed countries allocate just 0.3% of their GDP to development aid, yet we are losing our tropical forests at the rate of the area of a football pitch every second. In Haiti, forests now cover only a small area of the country. But in the final analysis, environmental catastrophe threatens us all, rich and poor alike, even if certain countries do not face specific ecological risks. We either deal with it as reasonable people, or we close our eyes to the 'cause and effect' realities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Yes, but are we reasonable people ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-The crisis of ethics is indeed a reality and a great many values are now being called into question. These days, we have to love in order to prove we are not contradicting ourselves. If we believe in God, we might call this love 'God', just as we might call it 'justice'. It all depends on your philosophy, religion or beliefs. If I feel love, I cannot be indifferent to the situation of victims of injustice, both in Haiti and elsewhere. If a man is humiliated, crushed, exploited or marginalised, then 1, too, am humiliated, crushed and marginalised. It is love which makes us fight for justice everywhere. Either one is a demagogue revelling in big words or one is sincere and ready to die so that another might live-this brings immortality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· One final question. You were speaking just now of insecurity and economics. Is there a link, here, with one of your most recent decisions, the abolition of Haiti's army ? Could you tell us how you were able to pull off this 'coup'? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- I am perfectly happy to answer such an important question and would like to be able to give a clear and direct reply. But given that the struggle is still going on, I don't think I should go into too much detail. A decision was made. The Haitian people opted to rid themselves of the army. Supporting their democratic wish, it was our job to help bring about this dissolution. The army, it is worth recalling, had about 7000 men, absorbed 40% of the national budget-and had killed many of our compatriots. We have had to be logical and patient in achieving this goal, bearing in mind that the guarantors of the agreement which led to my return had their own views, which were different from ours. We also needed courage and wisdom and, above all, the determination of the people. My motto has always been that it is better to fail with the people than to succeed without them, and in this we did not fail. Our task now is not to bask in our own glory but to continue the work of structuring the police force, to prevent it becoming another army. To achieve this, we have to make steady progress and use sound judgment. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interview by Hegel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Close-up</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Growing rice at high altitude in Burundi</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY">by Jean-Pierre Tilquin and Miguel Amado</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This tiny country tucked away at the heart of Africa has, as is well known, been convulsed over the last three years by an acute socio-political crisis. The tragic consequences have included loss of human life, damage to the economic and social infrastructure, and a movement of refugees to neighbouring countries. Burundi, already one of the most densely populated nations in Africa, also has high population growth. It could be argued that it is only thanks to the hard work and perseverance of the farmers (admittedly, 90% of the population) that the country manages to keep going at all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture in Burundi follows traditional lines and is based on a farming system divided between food crops for consumption by the farmer and his family, and cash crops (mainly coffee, tea and cotton). Although at the beginning of the decade the crops grown for food were sufficient to meet the population's needs, today demographic pressures are forcing farmers to increase food-crop production. It is these pressures that have prompted them to descend into the marshlands which cover approximately 110 000 hectares (8% of cultivable land in Burundi). These marshes are flooded during the rainy season and so allow rice to be cultivated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population growth has also meant that fields cannot be left fallow for long periods. This has resulted in more intensive use of marginal land and an increase in forest clearing. Such practices exacerbate erosion of cultivated areas. The loss of organic matter and nutrients leads to reduced soil fertility and lower yields. Although rainfall in Burundi is high, the soil is only moderately fertile, because of factors such as acidity, aluminium toxicity, and phosphorus immobilisation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While 20% of land suitable for cultivation is currently given over to growing dry beans-a staple in the Burundi diet - various factors now point towards farming the low-lying marshlands, with a particular emphasis on rice. This is one way of increasing the useful agricultural surface area of the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The events of 1993 (democratic elections, followed by the assassination of President Ndadaye), have created a period of instability which has been highly damaging for the country's agriculture. Some people lost their property and livelihood, and are only now slowly re-establishing themselves. The environment has also suffered as a result of the sheer numbers of displaced people. They occupy areas, both urban and rural, which were completely unprepared for the flood of people. it is estimated that 50 000 hectares of forest have been destroyed as a result-with devastating consequences for the country's ecosystem. What is more, the rate of demographic growth has led to overfarming and to a reduction in the average surface area of farms (to 0.7 ha per household).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rice-a crop for the future</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Against this background, the prospect of farming low-lying marshland offers some hope for the people of Burundi. In fact, the marshy valleys have long been used to grow beans, maize and sweet potatoes during the long dry season for later consumption during the short dry season. This practice, which was environmentally sound, provided a regular harvest, but also ensured the preservation of the marshlands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The practice of growing rice during the rainy season, followed by a crop of maize and beans during the dry season, is a form of integrated agriculture. It should be economically viable and environmentally sustainable while ensuring product quality, delivering a good yield, limiting any risks involved and allowing a high degree of social integration. These are the criteria which need to be examined in determining whether high-altitude rice cultivation in Burundi succeeds or fails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rice crops have been grown in this region, on the shores of Lake Tanganyika and in the Ruzizi valley (altitude 800 m), for more than 200 years, having been introduced by successive migrations of people travelling along the old slave route from Zanzibar. Certain varieties, known as 'pandabilima' (which in Swahili means 'he who climbs the mountain') can be grown on land up to a height of 1300 metres. They cannot, however, be planted on the higher central plateau because low temperatures at night render them completely infertile.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is not surprising that the new scheme to grow rice at high altitudes was greeted with interest. Indeed, it became almost a craze among farmers -to the extent that in 1990, rice crops covered more than 20 000 ha of Burundi. The area planted with rice fell subsequently, and in some regions the crop disappeared altogether. This was due largely to the appearance of the fungal 'rice blast disease', which can wipe out an entire crop, and to inadequate planning and misguided husbandry. The extensive planting of only one variety left the crop particularly vulnerable and once the disease did take hold, it was virtually impossible to eradicate. Needless to say, in a country where access to pesticides is non-existent, the introduction of a new crop cannot be based on a single variety; if it is to establish itself successfully, varietal diversification is vital. We should point out here that attempts were made in 1984 to improve varietal diversification </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">in the framework of the EU's Scientific and Technical Programme run by DG XII of the Commission. At that time, it was necessary to familiarise farmers with the techniques for growing the new crop and this aspect of the programme was funded by the EDF, in particular through three integrated projects. These related to agriculture and pastoral forestry and were initiated during 198889 in three provinces of Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Without going into the technical details of the programme, it suffices to say that growing rice at high altitude in the tropics differs from rice-growing in temperate regions. The low night-time temperatures characteristic of high altitudes mean that the crop is subject to constant stress. In temperate regions, the stress caused by cold weather is a problem only at the beginning and end of the growing cycle. As for selection methods, rice varieties have been produced that are resistant to rice blast disease - which remains the main problem. Also, by mixing the varieties grown, the farmers have created a wide diversity which offers a stable basis for a sustainable crop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Transformation of an ecosystem</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the viewpoint of development aid specialists, turning marshland into cultivable land means draining it (digging a ditch and fitting pipes). But this leaves the land open to erosion, causes silting in rivers and ultimately leading to desertification. By changing water levels in a region and disturbing the thermal equilibrium, marshlands cease to be marshlands. The method may have been justifiable before rice growing became possible. Indeed, it was employed in the natural marshlands of Buyenzi by some experts who specialised in upland rice. But it also resulted in large-scale destruction of one ricevariety-Yunnan 3-by rice blast disease in 1990.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Development projects which set themselves spectacular objectives can involve major alterations to the landscape. More often than not, these need to be rectified later. Thus, when it was decided to cultivate vast expanses of papyrus, the plants were moderately successful only thanks to constant artificial assistance. Put simply, the land could not sustain the crop on its own. In the process, the marshes were turned into floating peat bogs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The option chosen here was to adapt the small valleys for rice cultivation and teach the farmers the relevant techniques. Together with their families, they have eagerly embarked on the work needed to prepare the terrain for cultivation, although there are still some land tenure issues that need resolving. (Some people have refused to commit themselves to marshland reclamation projects as long as the land does not belong to them). It should be stressed that growing rice along a strip of water is an option which is in harmony with environmental needs. It promotes percolation of the water, thereby restoring underground water levels and preventing pollutants from being washed down towards the Nile or Zaire basins. It is therefore in keeping with global strategies for conserving resources and ensuring sustainable development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the marshlands, farmers traditionally plant beans and maize in banked-up beds during the dry season (from June to November). By skilfully selecting and growing different bean varieties, the farmer can stagger his crops and thereby ensure a continuous harvest from September until the time the maize is harvested. The marshes are then left fallow during the heavy rains which reach their peak in April. A rice variety which can be harvested in six months could thus be fitted in during this perriod with out disturbing the traditional hill-farming work schedule.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since farmers on the high plateaux had not traditionally grown rice, it was necessary to teach them the techniques needed to produce a successful crop. They were also informed of the benefits that improvements such as dykes, water supply pipes and drainage pipes could have on crop productivity. They have since applied this knowledge in their cultivation. During the dry season, without disrupting the infrastructures on which their rice cultivation is based, they have rebuilt banked-up beds and grown the traditional bean and maize crop. The system has been in place for about ten years and no drop in yield has been recorded. The yield averages 4.5 t/ha for rice, 1 t/ha for beans and 0.4 t/ha for maize-figures which are quite remarkable when compared with the yields of crops grown on the hills in acid soil with increasing levels of aluminium toxicity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By alternating two different farming systems, the problem of weeds -and therefore hoeing-and of pests is greatly limited. The extensive mixing of the soil that takes place accelerates the recycling of biogenic material-and the marshlands stay as marshlands!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Manageable land development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are three main types of marshy valley, each requiring specific programmes. The first consists of valleys lying above 1400 m with a rainfall in excess of 1500 mm. These areas are characterised by a clay soil, are constantly fed with water (with a high iron content) from the mountains, and are often very rich in organic matter. They require drainage using ditches and filtration channels, with changes of gradient so that the mountain water tables can be tapped and the water levels controlled. This is important to prevent a build-up of ferrous toxicity in the soil, which is extremely harmful to rice. A farming system involving paddy fields and banked-up beds can be accommodated perfectly in these types of valleys. Then there are the valleys lying between 800 and 1400 m with a rainfall of between 1100 and 1500 mm. These are known as 'dambos' in Swahili, and they extend from Northern Kenya right down to Southern Zimbabwe. Strewn with giant termite nests, the land here is well-suited to rice cultivation as long as water levels are carefully controlled. All the available water needs to be harnessed via filtration canals dug into the hillside. These allow the paddies to be irrigated speedily and, during the dry season, they can also be used to irrigate between the rows of ridgeplanted crops. It would, however, be very difficult to irrigate the entire valley during the dry season and so it is pointless digging a drainage ditch. The third and final type consists of small alluvial plains tucked away between the hills and stretching along the escarpments. Here, the level of soil fertility is determined by the heavy erosion resulting from farming on burnt land, and the practice of setting fire to the hills in order to 'regenerate' pastures. To grow rice in such locations, a filtration canal needs to be dug into the hillside, into which water then collects from the water table. The paddy fields also need to be terraced. These alluvial plains lend themselves perfectly to a farming system in which paddy fields are alternated with banked-up beds. All these land-adaptation schemes can be easily implemented and maintained by the farmers themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A sociological revolution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although rice grows quickly, it is highly labour-intensive. Thus, when</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">the young rice plants need to be planted out-which happens to coincide with the end-of-year school holidays-the whole family takes part. What is more, rice has become extremely important in sociological terms: reserved in days gone by for special occasions, it now forms part of the nation's staple diet, being mixed together with beans and dressed with palm oil and tomato sauce. The rice harvest is also a time for merrymaking and festivities which go on for the best part of a week.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rice cultivation has also engendered a vital sense of solidarity among farmers as far as sharing water is concerned, and rice-growing cooperatives have been a runaway success. These enable farming operations to be synchronised and running costs to be reduced, in particular by reducing the number of bird scarers needed. The crop, furthermore, can be harvested when fully ripe. On individual plots, farmers usually only allow the rice to mature to 75% before harvest for fear of theft. Finally, the cooperative helps to ensure that infrastructures such as drains and canals are properly maintained and that water supply installations are treated with respect. Each cooperative is run by a representative appointed by the group of farmers. These supervisors are then responsible for organising all operations: choosing and storing seed for the following season's crops, getting information about new varieties, consulting each other and pointing out any problems they may have to those in charge of research and advisory services. The area allotted to each cooperative depends on the number of households in the group and also takes into account the area available, with 10 ares per family being the usual maximum for planted-up paddy fields. Cooperatives may range in size from 5 to 25 families.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cooperatives like this are just the beginning. Networks of rural organisations, in which the farmers club together to buy equipment and fertilisers, need to be developed on a larger scale and they could provide a springboard for the development of the secondary sector, which is vital to the development of the country as a whole.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We would do well to recall that the cassava mills which have been so successful in Burundi and which still run today without any 'technical assistance' had equally humble beginnings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The future</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It must be acknowledged that the people who migrated to this 'wild frontier' of rice cultivation in Burundi also introduced into these regions diseases such as bilharzia and malaria (the mosquitoes carrying the parasite were transported in the luggage of people travelling from the capital to the provinces). Despite this, rice cultivation at high altitude has proved a veritable lifesaver for Burundi. In the year that the FAO plans to stage a summit on famine, it is appropriate to highlight the important role of rice-growing in the food production strategy of this country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Until recently, Burundi ensured that it had enough to feed its people through a delicate balancing act between growing food crops, leaving land fallow and rearing livestock which produced manure. At present, however, increased agricultural production is only possible by increasing the surface area of the country under cultivation-at the expense of fallow land and livestock farming. Such a move risks reducing soil fertility and could lead to the substitution of crops of high nutritional value, such as beans, with higher yield crops such as cassava or sweet potatoes which suck the subsoil dry of minerals and nutrients.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In short, traditional farming methods in Burundi are arguably now out of balance and the situation is getting worse. This may, indeed, be a root cause of the ethnic crisis. A systematic policy of re-establishing marshlands and organising rural communities around high-altitude rice cultivation would allow the country to look ahead with optimism to the next 20 years. Suitable varieties are currently available and the altitudes at which rice can be grown have been pushed back in Burundi as far as 1700 m. What is now needed is the funds! </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">J-P.T. &amp; M.A.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Developing world</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Freedom of expression: the heartbeat of democracy</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A view from UNESCO.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The article which follows is an abridged version of a text compiled by Carlos Amaldo, who heads UNESCO's research into communication and the free flow of information. Mr Arnaldo highlights some of the main aspects of the UN agency's support for the development of a free press in the African, Caribbean and Pacific regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The resolution passed by the ACP/KU Joint Assembly in March 1996 in Windhoek, Namibia, reflected the spirit of many of UNESCO's communication programmes in these regions. Echoing the principal tenets of the Universal Declaration of Human Rights, the resolution declares: 'freedom of expression is a precondition for holding free and fair elections'; 'the monopoly of information media is a barrier to the development of democracy,'; 'there is a need to create a climate in which all part)" can participate fully in political life.' It further holds: 'communication media must not only inform the electorate in an impartial and objective manner' but also; 'freedom of expression and the existence of free communications media are vital preconditions for the development of a democratic society.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The resolution was timely, responding to a need to remind political leaders, as well as civic society, of the relation between free communication media and truly democratic practices. Just five years ago, on 3 May 1991,</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">African journalists and media adopted the Windhoek Declaration at the UN/ UNESCO seminar on promoting an independent and pluralistic African press. Likewise, journalists and media practitioners of each major region adopted the Declarations of Alma Ata (October 1992), Santiago (May 1994) and Sana'a (January 1996), all of which affirmed the unwavering belief of professional communicators in freedom of expression, press freedom, independence and pluralism of the media, and the contribution of such freedoms to democratic processes. At their 28th General Conference, UNESCO Member States further declared that, 'press freedom is an essential component of any democracy.' All these declarations contain action programmes to strengthen press freedom in these regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turning to look at some practical initiatives, a media project entitled 'Independent Press in Africa', which was put in place after the signing of the Windhoek declaration, soon attracted the interest of a number of donors (Italy, USA, France). Under this project, the International Programme for the Development of Communication (IPDC) organised four sets of courses for journalists in 1994. In April 1995, IPDC arranged a multi-theme workshop for 33 English-speaking journalists and editors from Central and West Africa on marketing, distribution techniques, managing mass media enterprises in Africa, new communication technologies, journalism and ethical issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are now plans afoot to study the situation of the press in Mauritius, Madagascar and Comoros, and to publish several handbooks about press enterprises. Efforts will also be made to attract increased donor contributions so that the successes achieved by these initial training activities can be strengthened and shared with other regions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A further example of positive action in support of the media is the work of MISA (the Media Institute of Southern Africa-featured in more detail in the following article). This organisation has been receiving UNESCO support since 1994 under a funding arrangement with the Danish International Development Agency. The project seeks to strengthen links among the region's independent media so as to enhance the free flow of information. It also aims to boost cooperation and information-sharing with similar groups in developing and developed countries worldwide, to strengthen the ability of the region's independent media to stand on its own feet and to improve professional standards.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MlSA, which was set up in 1992, has been monitoring and safeguarding press freedom in the region, facilitated by an electronic network for distribution of information on press freedom issues. It has mounted seminars and training workshops for professional journalists on computer-aided design, strategic financial management, journalism ethics and advertising management. MISA's campaigning material includes a bi-monthly magazine, Free Press: the Media Magazine of Southern Africa and a booklet, So this is Democray, which is a compilation of its 'action alerts' curing 1994 and 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another UNESCO initiative is the 'Communication and Good Governance in West and Central African Countries' project, supported by Germany. This aims to strengthen the human and technical capacity of the media in these regions so that they can make a contribution to good governance. The three year project is to be implemented in 10 countries - Benin, Chad, Equatorial Guinea, Gambia, Ghana, Guinea Bissau, Liberia, Mali, Sao Tome &amp; Principe and Togo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Together with other institutions such as legislatures, the judiciary and civic organisations, media bodies like MISA have a useful role to play. They can enhance transparency and accountability by systematic analysis and reporting of government programmes, policies and pledges, and by encouraging public discussions which help people to make informed decisions about public issues and about how their leaders discharge the power vested in them. Fulfilment of these functions requires access to the media, and qualified, well-trained practitioners who can effectively use the media for information, education and communication on good governance issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caribbean</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turning our attention now to the Caribbean, the question of media freedom recently came to the fore in Trinidad and Tobago when 13 editors and journalists on The Guardian lost their jobs following publication of a number of controversial articles (some reports said they 'constructively resigned'). The events cast a shadow over the famous Carnival. Indeed, as one journalist put it, the Carnival quickly ceded to the 'sacrificial rites' of Holy Week. Six of the paper's youngest reporters were among those who lost their jobs-but out of the furore, a new newspaper was born.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A 'Comparative Study of Media Laws in the CARICOM countries' by Ainsley Sahai, commissioned earlier by UNESCO, became a reference in the debates that followed. The study highlighted that all Caribbean countries guaranteed freedom of expression in their national constitutions. Indeed, Trinidad and Tobago's constitution explicitly guarantees press freedom as well. The Media Association of Trinidad and Tobago (MATT) organised two meetings. The first of these, on 10 April 1996, was a public forum on issues of press freedom. Although a full cross-section of society was not present, and not all the issues at stake were fully debated, it was nevertheless a start. Those who took the floor came from many sectors of society -women, the unemployed, workers, community organisations and at least three different religious groups. About a quarter of those who contributed spoke as individuals. While many criticised the press for errors in reporting, all confirmed the need to uphold a free press vis-a-vis both political pressures and economic and financial interests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The public gave strong support to MATT and demanded that the forum be replicated in other parts of the country. It was the first time that the public had been given the opportunity to speak out on these issues. It was not so much the content of the discussion which counted, but the very fact that the event took place, bringing the media closer to its 'customers'. The meeting gave the public an opportunity to put over their own perceptions of press freedom, impartial reporting and the strengthening of democratic processes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two days later, with support from UNESCO, the Media Association staged a journalists' symposium, moderated by George John, consulting editor at The Guardian. David de Caires, publisher of Guyana's Stabroek News was invited by MATT as an external consultant. Drawing on past and more recent examples of uneasy relations between a free press and governments, Mr de Caires concluded with a headlinehitting statement; the relations of the press with government should not be too cosy, the press must maintain its adversarial position.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many journalists took the floor to stress Trinidad and Tobago's constitutional guarantees for both freedom of expression and press freedom. They also stressed the need to safeguard editorial independence, not only in the printed press, but also in broadcasting, and urged the repeal of 'antiquated' libel laws-a point also made in the Sahai study. The preparation of a Freedom of Information Act was strongly urged to ensure access to public information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These events appear to have strengthened the resolve of the jobless journalists. They grouped together to set up a new weekly newspaper, called The Independent. The new publication focuses on investigative articles, comment and reviews. In addition, a monthly called The Formatt was launched by MATT to disseminate specialised news on press freedom issues and to provide print support for future public fore. Both newspapers brought out their first editions in early May amidst the celebrations of World Press Freedom Day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pacific</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Pacific, issues of freedom of expression and press freedom are no less salient, although a key issue for practitioners there is the modernisation of infrastructures. This is needed to ensure that this vast island region does not find itself in the slow lane of the information highway.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The computerisation of radio newsrooms, in places such as the Cook Islands, Vanuatu, Fiji, Solomon Islands and Tonga, is a priority. The Cook Islands already has a fully computerised newspaper operation. Indeed, this is the first newspaper in the Pacific with the capacity to transmit photographs from various parts of the country to the newsroom electronically by phone.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Considerable concern has been expressed about the inadequacy of national television programming. There is a need for the people of the Pacific to see themselves and their culture, and not just the imported fare distributed by most international TV services. With UNESCO support, women media producers from seven island countries were able to meet to work out ways of cooperating on a series of television documentaries that they themselves produced and exchanged within the region. Preparations are now under way for the annual evaluation and awarding of prizes at the end of 1996. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">C.A.A. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Campaigning for free expression in the SADC region</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY">by David Nthengwe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Media Institute of Southern Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Officially launched in September 1992, the role of the Media Institute of Southern Africa is primarily that of coordinator, facilitator and communicator in the promotion of media freedom and diversity, (as envisaged in the 1991 Windhoek Declaration). MISA operates in 11 of the 1 2 SADC countries and is currently investigating setting up a chapter in the twelfth-Mauritius- which joined the Community 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The chapters are serviced by a regional secretariat based in the Namibian capital, Windhoek. The secretariat is accountable to a policy-making governing council of elected representatives from each national chapter, while funding for MISA and its projects is channeled through the MISA Education and Production Trust, overseen by a board of independent trustees. The organisation is currently almost entirely donor-funded, with UNESCO, NORAD, SIDA, the KU, the Friedrich Ebert Stiftung, IBIS, and the Australian and German governments being the main contributors. Other income is generated through the sale of subscriptions to MISA publications and services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Institute's main work is in the field of advocacy; highlighting violations of media freedom and free expression, and exploring ways of ensuring that these fundamental freedoms become entrenched throughout Southern Africa. In 1994, MISA became a member of the International Freedom of Expression Exchange (IFEX) network in a bid to increase international awareness of media freedom violations in Southern Africa. Membership of IFEX has enabled MISA to distribute as well as receive information on media freedom issues in a quick and relatively cheap way via the Internet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Action alerts'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1994 and 1995, MISA issued via IFEX and its own electronic mail network, the MISANET (see below), more than 190 'action alerts' relating to media freedom infringements in Southern Africa, and effective campaigns against some of these violations have resulted. In August 1994, Lesotho journalist, Rabuka Chalatse, was shot by soldiers while covering a demonstration. An alert issued by MISA triggered a swift response, and within 24 hours, funds had been raised to pay for emergency treatment which saved the young journalist's leg. In November 1995, Angolan freelance journalist, Mario Paiva, had his life threatened by people who, it was alleged, were state security agents. MlSA's alert prompted protest from throughout the world, and resulted in several governments offering Paiva sanctuary in their embassies in Angola. The threat against the journalist was subsequently lifted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MlSA's advocacy work has also shown that democratisation does not necessarily result in guaranteed media freedom and free expression. In Zambia, for example, which had a multi-party election in 1991, arcane laws inherited from previous regimes have been used against the private media in particular, and free expression, in general. As this article was being written, Fred M'membe, the Editor-in-Chief of Zambia's privately-owned daily 'The Post', and two of his colleagues, were starting an indefinite prison term for contempt of Parliament. The sentence was passed not by a court of law, but by the Speaker, under legislation inherited from British colonial rule. Their 'crime' was to comment on criticism made in Parliament of a Supreme Court decision which declared unconstitutional, laws requiring anyone wishing to stage a demonstration to obtain police permission first.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Five months prior to his arrest, M'membe received the MISA Press Freedom Award, which is presented annually to individuals or institutions considered to have made an outstanding contribution to the advancement of media freedom in Southern Africa. M'membe was the third recipient of the award.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Free flow of information essential</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As the Windhoek Declaration points out, 'the establishment, maintenance and fostering of an independent, pluralistic and free press' is essential to economic development, as well as for the growth of democracy. Accordingly, MISA argues that the free flow of information is vital to the development process. Effective communication within SADC-a 'development community'- has been hampered by the region's poor postal and telecommunications services. MISA considers that these logistical barriers to the free flow of information are a form of censorship. In a bid to break through the information voids which have kept Southern African media workers and their audiences isolated from each other for so long, it has made particular use of advances in information technology, including, most notably, the Internet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past two years, MISA has been linking member organisations up to electronic mail (e-mail). This allows members throughout the region to exchange news, photographs and other information. To date, 25 MISA member organisations are linked to this network, called the MISANET, although further growth has been hampered by members' unfamiliarity with e-mail, and the lack of local technicians to train people and provide user support. Nonetheless, computerised communications have proved to be an appropriate technology, and development of the MISANET remains a top priority. By making some services available to non-MISA subscribers, MISA also intends to generate income and thus reduce its current dependency on donor funding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Focus on training</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The coordination of training and material support to independent media is another area where MISA looks to develop media freedom and diversity. The region's independent media sometimes operates in politically and economically hostile environments. Its survival-and thus the sustenance and growth of media diversity-hinges on these organisations becoming highly professional, well-managed concerns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Working through training institutions based primarily in the region, MISA coordinates workshops and other training programmes aimed at improving the skills of media workers, particularly in the fields of management and finance. Workshops in strategic and financial management, project management, advertising, marketing, sales and subscription management, ethics, subediting, and computerised design were staged during 1994 and 1995. For 1996, training is scheduled in economic reporting, project management, photography, advertising sales, circulation and sales management, computer-aided design, developing world and financial and strategic management. Instruction will also be provided to media workers without formal training. Meanwhile, research is to be carried out into setting up a media ombudsman for Southern Africa, printing press initiatives, media training needs, and the difficulties faced by women media workers in the region. The last-mentioned is in line with MlSA's policy of encouraging gender awareness and equality within the Southern African media.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Private and community-based media organisations face constant problems securing adequate finance. As businesses, they often do not qualify for donor support, while banks are reluctant to lend them money. Therefore, MISA is looking to set up of a Media Development Fund to which independent media can apply for loans, credit guarantees and grants. A study is currently being conducted into the feasibility of such a fund, which MISA hopes to have up-andrunning by early 1997.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Broadcasting in Southern Africa is still largely state-controlled. Moves by some of the region's governments to 'deregulate' broadcasting have been erratic, and many private broadcasting licenses granted in the process have gone to organisations or individuals closely linked to the authorities. MISA is now drawing up a policy aimed at seeking the effective liberalisation of broadcasting legislation covering public, private and community broadcasting throughout the region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As part of this process, MISA will, this year, stage a conference on broadcasting and community media, to coincide with its Annual General Meeting-which has become one of the largest gatherings of media workers on the African continent. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.N.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Volunteers show their worth</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY">by Thomas M. Neufing</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Volunteers have become a major component in international development efforts. They make up a significant proportion of the total human resources available for development cooperation (up to a fifth of the skilled international personnel serving in developing countries). In the early days, volunteer service was strongly influenced by the idea of oneway technical assistance. Specialists, mainly from the North, served in developing nations where their expertise was desperately needed but not yet found among local citizens. Much has changed since.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After the US Peace Corps, the UN Volunteers Programme (UNV) ranks as the second largest volunteer-sendina agency with some 4000 professionals in the field every year. Its universality and internationality is reflected in the high number of UNV specialists (74%) who come from developing countries. The scope and size of the international volunteer contribution to development cooperation (notably areas such as HIV/AIDS and the environment), has increased significantly over the years as a result of the changing development challenge. The re-thinking of the role of technical cooperation is equally central to the volunteer debate and this has led to much greater flexibility in the ways in which volunteer services are provided. The important role volunteers can play in peace building efforts with a long-term development dimension, complementary to humanitarian relief, is increasingly being recognised.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Working with rather than for people</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With the UNV's 25th anniversary, and the relocation of its headquarters to Bonn this summer, it is an appropriate time both to assess and to acknowledge the contribution made by these volunteers. Since the programme began in 1971, some 14 000 professionals have dedicated a period of their lives to serve as a UNV. The programme is administered by UNDP, and is therefore intimately linked to its structures, particularly in the field. Regarding community-based initiatives, the comparative advantage of UNVs is that of working with rather than for people over an extended period, thus facilitating their initiatives. The experience of many development agencies shows that in promoting socio-economic change at the village level, the type of person needed is one who-through long-term commitment and sensitivity -can learn as much from local partners as offer advice to them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International volunteers are engaged mainly in rural development tasks. Those working through specialised NGOs such as the Red Cross, and Medecins Sans Frontieres have proved to be highly effective agents, supporting governments faced with disaster situations. In the case of UNV, the value of using volunteer specialists from other developing nations, as a way of encouraging technical cooperation amongst developing countries, is particularly recognised. Most volunteers- perhaps two-thirds - serve in least developed and small island countries. And about three-quarters serve in rural areas, working mostly in programmes of agricultural and community development, health, education and the supply of basic services. Since the end of the Cold War, a growing number have been deployed in emergency relief, refugee and rehabilitation programmes. UNVs make up 10% of the UN's civilian component in Cambodia; 4096 of the field staff of the World Food Programme and almost 100% of outreach workers attached to the UN Mission in Guatemala. UNVs are increasingly involved in human rights promotion, the organisation of elections and conflict resolution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a consensus among the main international humanitarian and development actors that their programmes should be mutually supportive. For example, development efforts must respond to humanitarian crises by remaining on the scene and supporting immediate needs, as well as aiding in the prevention of crises which are known to be looming. Emergency humanitarian assistance should also pave the way for longer term development by viewing the immediacy of the moment through the lens of future sustainable rehabilitation. Both sets of activities should, ideally, be launched and implemented in tandem with local bodies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">External assistance efforts must include strengthening local capacity to cope with problems. Empowerment strategies which inform, educate and facilitate the people's own vision of peaceful and sustainable living environments (including respect for human rights) are fundamental to the future of communities coping in the aftermath of crisis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Relief, rehabilitation and development?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The UNV programme has been active in exploring the efficacy of volunteer support to communities in crisis in order to bridge the gap between immediate needs and longer term developmental goals. In 1994, the UNV held its 4th Special Consultation, entitled, Between Crisis and Development - Volunteer Roles and UNV's Contribution. At this event, donor governments, UN agencies and cooperating partners from civil society had an indepth discussion of the issues surrounding volunteer efforts, and the complementary nature of emergency interventions and follow-up measures. The participants reconfirmed the need for local capacity building. They also affirmed the usefulness of the UN Volunteer contribution in crisis prevention, emergency rehabilitation and 'building bridges' to sustainable development. The work of UNVs in preventive action and promoting post-conflict development was highlighted. There has been a significant increase in demand for specialist volunteer services in all types of crisis. These may be economic, natural or man-made, but they all have in common the need to provide essential relief and rehabilitation services for basic survival (to refugees and resident populations). In many countries, disasters and internal strife have put so much pressure on essential public services that the longterm capacity of the people to recover may be threatened. Governments in developing countries and donors both believe it is fully justified to use volunteer specialists to help provide such services during the adjustment period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Mixed' teams</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The contribution of both international and national volunteers is often essential to link immediate relief efforts to future long-term development. National volunteers-people working in their own countries within the UN framework-complement the international approach by providing the key grassroots perspective. UN Volunteers who speak local languages, live and work in remote communities, are familiar with community structures and are known to local leaders, play a key part in facilitating preventive action and providing follow-up in the aftermath of a crisis. UNV specialists are well-placed to build effective partnerships with national and local actors. In the last two years, some 2000 UN Volunteers have worked in various parts of the world in prevention and preparedness, peacekeeping, electoral support, human rights, rehabilitation and reconstruction, and humanitarian relief.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burundi offers an example of an initiative designed to stem a crisis through local capacity-building. The UNV is financing a project there which supports the mediation and dialogue efforts of the UN Secretary General's Special Representative (SRSG) through the recruitment of UNV peace advisers and conflict resolution facilitators. This project is being run successfully out of the SRSG's office, extending public awareness of the reconciliation process. It includes use of the mass media to promote understanding, and brings local actors together to work for peaceful solutions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The tasks undertaken by UN volunteers all fit into the spectrum which has 'crisis' et one end end 'development' at the other. The work, moreover, is undertaken in partnership-with civil society (NGOs and community-based organisations), government departments, UN agencies and regional international organisations (such as the KU).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through efforts that aim to link relief, rehabilitation and development, new productive partnerships are emerging to enhance coherence, coordination and complementarily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The growth of professionalism</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">30 years ago, the typical profile of an international volunteer was that of a generalist graduate from an industrialised country seeking first-time experience abroad before settling down to a career. Over time, the governments of developing countries made clear their need for practical and often specialised skills aimed at giving them the ability to manage their own programmes. They increasingly expressed impatience at hosting untrained volunteers. Professionalism became the key word. Unfortunately, the word 'volunteer' is still a source of confusion: it is often equated with 'amateur'. This is a perception that now needs to be corrected. The personnel sent out by most agencies that supply volunteers are likely to be in their thirties, with post-graduate qualifications and several years' practical experience in their fields. The typical UNV specialist is an example par excel/ence of this trend: 39 years of age, holding a Master's degree and with more than ten years of experience in a particular discipline.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It was not just the dedication, but also the professionalism of the hundreds of UN Volunteers serving in Mozambique that impressed Aldo Ajello, the former UN Special Representative in Mozambique (now EU Special Envoy for the Great Lakes Region). 'If I were to run another mission,' he said, 'I would ask immediately for volunteers.' In terms of monitoring-which was vital in building up the trust and confidence needed to ensure the election results were accepted-'UNV electoral officers were our only real presence and they proved to be extremely professional.' ~ T.N. </P>
+<P ALIGN="JUSTIFY">Study by the World Wide Fund for Nature</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Structural adiustment, the environment, and sustainable development</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY">by David Reed</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On 29 May, David Reed of the World Wide Fund for Nature (WWF) was in Brussels to present the results of a study undertaken by the WWF, with the support of the European Commission, the longterm consequences of structural adjustment programmes (SAPs) on the environment and the use of nature/ resources. Conclusions were drawn from nine country case studies from Cameroon, Mall Tanzania, Zambia, El Salvador, Jamaica, Venezuela, Vietnam and Pakistan. We publish here an abridged version of Mr Reed's general presentation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SAPs, often implemented at the instigation of the international financial institutions, have responded to the pervasive economic problems of the 1980s and to profound changes in the economy in recent decades. The programmes have generally been successful in improving macroeconomic indicators in developing countries. The marketorientation of economies has been increased through liberalised trade and capital flows, privatisation, reductions in regulation and price setting, and cuts in government budgets and programmes. For most developing countries, these changes were essential to economic recovery and adjustment to the new global marketplace.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sustainable development in the social, economic, and environmental sense, has, however, been ignored in SAPs. Many reform programmes have been accompanied by increases in poverty and unemployment, worsening income distribution, and the collapse of social services, environmental protection and state institutional capacities. These immediate costs of adjustment inhibit countries' long-term ability to expand productivity and employment opportunities, as natural resources are exploited indiscriminately to meet short-term needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Environmental impacts</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The environmental effects of structural adjustment vary from country to country depending on the specific components of the reform package, the structure of the economy, and the implementation process. The WWF's country case studies reveal particular mechanisms through which structural adjustment has altered resource-use patterns. Some more general patterns also emerge from the studies. Everywhere, cuts in government institutions and funding have reduced the state's capacity to facilitate the transition process, to compensate for market failures, and to provide for long-term and social sustainability.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many reforms associated with structural adjustment have the potential to improve both environmental and economic outcomes. However, the failure to implement complementary environmental policies or strengthen institutions and regulations, has created a very mixed environmental record. Increases in poverty, greater production incentives, and the loss of government regulatory capacity, have all aggravated patterns of poor resource use.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Extractive and agricultural economies generally increased production in response to greater exposure to global markets. Without proper policies in place, this increase has put a strain on fragile ecosystems. Environmental pressures include increased land degradation and deforestation for agriculture, livestock and timber production; increased production of non-renewables without long-term investment of the proceeds or environmental safeguards; and increased pollution and damage to the ecosystem from unregulated tourism.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The burden of fiscal retrenchment and price changes under structural adjustment have fallen most heavily on the poor, particularly women. The strong association between poverty and environmental degradation has been revealed, as efforts to maintain livelihoods have led to deforestation, land degradation, overhunting and other pressures on endangered species, as well as the unmanaged extraction of nonrenewable resources. Increasing poverty and unemployment associated with adjustment has also added to population pressures in urban areas with insufficient infrastructure exacerbating problems of pollution, disease and congestion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The implications of disregarding the environmental and social impact of adjustment are examined in the various case studies. Structural adjustment has been sustained by the promise that market-orientation and export-led - growth will raise living standards. Evidence from the studies, however, strongly suggests that long-term productive capacity is being destroyed by short-term exploitation of natural resources. Not only environmental but also economic and social sustainability are threatened by the loss of environmental goods and services. Drawing down natural capital has been encouraged by government policies that promote exports and open resources up to international markets. And the process is accelerated by the growing population of poor and unemployed who rely on natural resources for survival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recommendations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following its study, the WWF offers a series of recommendations to reduce the environmental costs of structural adjustment and economic integration, and to reorient structural adjustment aims towards sustainable development. Most urgently, environmental issues must be integrated into structural economic reforms - environmental assessments must become part of the programmes. A strategic vision of the role that natural resources and environmental goods and services could play in the transformation of developing economies is essential to designing appropriate strategies. Efforts to industrialise economies must include consideration of the environmental implications. Social services and environmental institutions must be maintained during the adjustment process to prevent increases in poverty and environmental degradation that have both short-term and long-term consequences for development. Essential services include credit and marketing support to small farmers, income-generating opportunities for women, food-assistance programmes, and promotion of distributional equity. The state's role in providing services which neither the private sector nor civil society can provide, must be maintained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the great variety in economic structures and in the capacity of markets and civil society among developing countries, adjustment strategies and government roles must be tailored to each case. Everywhere, countries must implement national institutional reforms for environmental management. Civil society must be strengthened to allow participation in the adjustment process. International financial institutions promoting and designing SAPs must reform their policies and approaches to implementation in the light of the clear evidence that macroeconomic reforms are having a profound effect on the environment and on the possibilities for sustainable development. Continuing failure to correct these problems on a national level accentuates the concern for addressing issues of sustainability on a global level. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.R. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Culture and society</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Why a Biennial Festival of Contemporary African Art?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dak'Art 96</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first World Festival of Negro Art, held in 1966, was essentially a political exercise. In the post-independence period, it was felt necessary to show the world that the people of Africa (both the continent and the diaspora), had a rich culture which had long been suppressed. The festival - which has never been repeated-is viewed with a great deal of nostalgia by supporters of modern African art and black intellectuals. The better, brighter future, which seemed at the time to be just over the horizon, never quite lived up to expectation. Even before financing problems had surfaced, the festival's fate had already been sealed by petty political rivalries and a greedy pursuit of the limelight. Years later, attempts to relaunch the event met with a lukewarm reception. It was already the beginning of the end as far as ideologies were concerned. In complete contrast, Dak'Art 96 (Dakar, 915 May 1996) set its sights firmly on the market place, nowadays the yardstick by which all success is measured. Its goals were simple: to break into the art market and overcome the generally held prejudice that contemporary African art lacks modernity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An international market for African art does exist, but it concerns itself solely with ancient art- and Africa itself profits little from such trade. Indeed, it would be more accurate to speak of plundering than of trade. The seminar, organised last year by the Terveuren Museum in Brussels on the looting of African works of art, revealed the true extent of the phenomenon. Despite the fact that pirated works fetch considerable sums on the black market, contemporary African artists are faced with a 'Catch-22' situation. Major galleries in Europe, America and Japan do not exhibit their work because African art is ignored by the leading art periodicals; and their work never appears in these publications because it is never exhibited. One reason for the fact that African art is not put on show is that virtually no funds are allocated by international institutions to sponsor exhibitions by the artists in question.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many third-world governments do not dare, are unwilling or are unable to include culture on their list of priorities within international cooperation agreements. One exception is Burkina Faso which now boasts a cinema industry as a result. Senegal is trying to follow in its footsteps. But there are not many places in Africa where artists are promoted for the quality of their creative output. The majority of initiatives have, in fact, been on a voluntary basis. The magazine Revue Noire is one of the most significant examples of this approach. A group of aficionados of contemporary African art - indeed with a passion for art pure and simple, whether African or European-decided to try and break the vicious circle. They looked at two options: the establishment of an art gallery of worldwide renown or of an equally prestigious arts publication, and came down in favour of the latter. Thus Revue Noire was born. However, its success was generally given very slim odds: it was seen as too glossy, too expensive and too intellectual. The sub-text here of course, is that a publication about African art had no right to be glossy, expensive or intellectual, especially since the money could have been used for something far more 'useful' to the development of these countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Others, such as Marie-Claire Mwanza from l'Espace Alizes in Brussels, have attacked the problem from a different angle-by exhibiting contemporary African art. Prior to her initiative, there was not a single gallery in Brussels that specialised in this sector of the market, and there are still none that figure on the shopping lists of the world's great collectors. Whatever the price set for a contemporary African work, it is generally perceived as being too high. The contrast with the prices demanded for works by even the youngest European or American artists, even for their very first exhibitions, speaks volumes. African art is too expensive in relation to what exactly ? The answer is in relation to the status accorded to it, which is of course determined by the art world. In other words, a big fat zero if one considers the fact that African art is never exhibited.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thanks to Revue Noire, African art has been brought to the major galleries of the Western world. Similar projects have been launched or are in the process of being launched in various countries of the West, such as the magazine NKA in Brooklyn, for example. Exhibition organisers, museums, galleries and those looking to stage art festivals now know on whose door to knock, and the last few months have proved extremely promising. The Guggenheim Museum in New York is currently hosting a major exhibition of African art, and Africa 95, held in London, was swiftly followed by Copenhagen 96. The Guggenheim Museum, moreover, is in a completely different league to the Museum of African and Oceanic Art in Paris or the Museum of Central Africa in Tervueren, Belgium (formerly the Colonial Museum)-it is one of the world's most prestigious temples of modern art. What is more, London's Africa 95, which was so disparaged by African art specialists, who considered it nothing more than a meeting place for traders, did, whether we like it or not, act as a significant catalyst. And what about pirated works of art, such as those plundered from the Niger Valley ? These have found a 'home' in public as well as private collections, pointing to a real need to 'clean out the Augean stables'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A few African artists are beginning to get themselves known within 'the market', but there are still not enough of them. It was with great foresight that the organisers of Dak'Art placed these artists at the top of their invitation list. Another shrewd move was to invite the art market's arbiters of taste to select those African artists who should present solo exhibitions, and to ask celebrated art critics and collectors to form part of the international panel of judges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is probably true to say that Africa has rarely known such a dynamic period of creativity which places it at the forefront of global aesthetic trends. The aim of the Biennial Festival was to underline this fact beyond any doubt. Among those artists who are currently in a position to break into the market, the Senegalese sculptor, Ousmane Sow, probably heads the list. Paradoxically, however, Ousmane Sow's work was not presented at Dakar although he himself was there, his tall, striking figure standing out from the crowd. Despite the fact that he lent his support to Dak'Art 96 and that the opening gala was partly dedicated to him with the magnificent film of Beatrice Soule, Ousmane Sow resolutely refused to display his own work. He has no wish to take part in gatherings of 'African artists'. He is an artist and he is African, but he is not an 'African artist'. 'A Japanese artist is a contemporary artist in this universal world', he argues, 'so why should I allow myself to be pigeon-holed in a ghetto ?' No matter how satisfied and pleased champions of contemporary African art may be with the organisation behind the Biennial Festival, they cannot deny that Ousmane Sow has a point. Having said this, there is no contradiction here, but rather a complementary vision. Sow's stance and the idea behind Dak'Art are part of a two-pronged attack, to borrow a military term. The organisers of the Biennial and Sow himself doubtless saw it in this way, and decided to join forces.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Each time Beatrice Soule tackles the work of an artist, she explores it in a very unusual way, reinventing the arts documentary. Her films are reminiscent of the music of Nino Rota in Fe//ini's films, Rota subjugating himself to the service of the director's work, sublimating his own originality through this extreme humility. It is impossible to picture the images of Federico Fellini without Rota's haunting music. Beatrice Soule saw in Sow's work a love affair between an artist and his sculpture, coming up with the idea of placing Sow's sculptures in the savannah and imagining the intimate interaction between Africa's natural world, which is at the heart of the artist's inspiration, and his works, which the natural world is able to absorb back into itself. The result of this juxtaposition is that the physical work of art is eclipsed by sheer creative force and spirit. The genius behind the work becomes the work, merges with it and is reincarnated in it. The one thing that Soule did not film was Ousmane Sow himself, her images concentrating solely on the creative act. It would be illusory to attempt to explain a Beatrice Soule film, especially this film. When she unveils how the artist tames physical matter, reinventing materials in order to create a work of art, technique simply recedes into the background, becoming blurred and intangible. Whereas others would have adopted a scientific or factual approach, her camera perceives the abstract aspects of the piece-and its gestation. The film was due to be broadcast on the international FrancoGerman arts channel Arte. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If Ousmane Sow's sculptures are characterised by their gigantic proportions, then those of Georges Adeagbo, a Beninois artist whose name is also beginning to be heard in the commercial art establishment, are characterised by their 'fugacity'. Adeagbo's artistic constructions are as fleeting as puffs of smoke, like voodoo symbols scratched out in the sand. His art is symbolic and ephemeral. Once one of his works has been exhibited, all that remains of it is a hollow shell which he has to reinvent over and over again. Adeagbo constructs ideas, using a host of assorted materials which he painstakingly selects over months, even years. Yet despite the meticulous care with which they are put together, as far as the artist is concerned, the materials per se are of no importance. He could convey exactly the same idea using other elements. An Adeagbo piece is not merely a pile of objects. It is neither conceptual art, nor scrap art. It consists rather of 'installations' which rise and spread outwards. Sometimes, he uses specially constructed sculptures. At other times he employs everyday objects- shoes, saucepans, stones, spectacles or footballs. He also works with written material; manuscripts, parchment, pieces of newspaper and books, portraying the written word as both a creative force and a deceptive screen. Adeagbo himself is a man of few words. Perpetually crouched on the ground, he constructs, modifies, touches and observes his creations. Why should these constructions remind us so much of paintings? They are as much a pile of objects as a painting is an accumulation of layers of paint. It is by forgetting the paint that we are able to admire the picture and it is by looking beyond the materials used by Adeagbo that his work truly reveals itself. Indeed, it is a sign of his genius as an artist that the materials never intrude upon our contemplation of his work. In Dakar, Adeagbo's work was shown in the AIDS exhibition organised by Revue Noire. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another artist who took part in the AIDS exhibition, and whose art could well be the impetus behind the new universal aesthetic, the avant-garde (if such a concept has a meaning), is Pascale Marthine Tayou from Cameroon. He was given the honour of presenting one of the five solo exhibitions. Tayou was sponsored by Yakuyi Kawagushi, the curator of the Setagaya Museum in Tokyo, who exhibited his work at the forum organised within the overall framework of the exhibition. While the term 'installation' may best describe the works of Georges Adeagbo's, Tayou's work falls unquestionably under the heading of sculpture. This is despite the fact that the two artists use virtually identical materials. Tayou sculpts from wood, covering his pieces with all manner of manufactured and salvaged objects such as shoes, nails, plastic bags and enormous condoms, or with natural objects such as bits of roots and stones. He then paints the arrangement. The work is dense, unyielding and mesmerising, often etching itself into the onlooker's mind. His sculpture lacks heavy ornamentation, yet its starkness has a rich quality, the theme encompassed by a jumble of material standing out clearly, like the outline of a silhouette. Take his work 'Fight against AIDS'. The piece consists of a wooden frame in the shape of figure-of-eight, with each horizontal line doubled, defining a key element in a tragic body with bulging eyes and a Pere Ubu belly. In contrast to this suffocatingly tragic figure, the brightly-coloured shoes of a Harlequin with a faded costume offer a comical note.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were other creators who could well ruffle a few feathers in the art market that ultimately makes or breaks an artist: Tamsir Dia of Cote d'lvoire (whose screaming figures are reminiscent of Munch), Cheikh Niass of Senegal, Mathilde Moro of Cote d'lvoire and Abdoulaye Konate of Mali. The last mentioned was honoured with the highest award of the festival.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A decision was taken that Dak'Art 96 should encompass other areas of creativity, such as music, design and fashion, in addition to the visual arts. At the gala evening held to inaugurate the Festival, there was a fashion show choreographed in the manner of a ballet. The staging of this can only be described as mawkish. The audience were treated neither to a real performance, nor to a good fashion show. The second fashion spot, which was supposed to present an overview of African design, was also quite pitiful. If the event's organisers decide to keep these parallel areas of creativity in the Festival, then their decision will be solely thanks to the success of the International Design Exhibition. Apart from two or three 'exotic' pieces, this was generally of a very high standard.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Community's choice in awarding the prize for creativity to a designer, Vincent Amian Namien from the Cote d'lvoire, was particularly revealing. This artist strips everything down to its bare essentials, creating a line that is so purified as to leave only the quintessence of form. Thus, he creates a chair that is nothing more than a perfect metal triangle, with four boards and four metal wires-and yet offers perfect comfort.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Claire Kane, a fashion designer of Franco-Senegalese descent, had the verve to go it alone and show her collection at the prestigious Salon of Design. Her clothes are characterised by the rejection of all superfluous detail, achieving a fluid line that stylises movement. Following an aesthetic code that has been decanted from the melting pot of the collective costume heritage of the entire continent, Claire Kane is directly involved in the creation of her designs, from the weaving of the cloth to the last finishing touches. In fact, she admits that her true passion is fabric rather than fashion, her favourite material being woven pagne. She often uses silk-screen printing to introduce pattern. She then adds words to the patterns in her designs and, abracadabra, one would think that this is the way it has always been done in Africa. A subtle modernity, combining both past and future, seems to be a recurring motif in African creativity. International artists, still few in number, travel from Dakar to be dressed by her.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If, in the future, the Festival's organisers decide to concentrate solety on the visual arts, this would come as no surprise. On the other hand, it would also make sense to continue to include design and fashion. A country's cultural heritage should be considered one of its raw materials and a source of economic wealth, and unimaginative accountants may have to resign themselves to this fact. Herein lies a possible answer to the question: 'why hold a Biennial Festival of Contemporary African Art?'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hegei Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Acting against AIDS</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY">by Robert Rowe</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many ways of raising money to fight AlDS have been tried, but one of the most unusual must surely be the approach taken by an official of the European Commission. Robert Rowe, who until last year was an assistant editor on The Courier, put on a oneman show in Brussels and then rook it to the other side of the world to raise money for a voluntary organisation working on AIDS prevention and care in Malaysia. Here is his story of fighting the virus with the power of the theatre.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'By the year 2000, South-East Asia will be host to the majority of the world's AIDS cases.' So runs a stark prediction from the World Health Organisation, quoted in a recent paper from a grouping of NGOs affiliated to the Malaysian AIDS Foundation. It goes on to predict that 'the region faces a potential HIV spread of titanic proportions.' In Thailand, a country with a large population and a sad reputation for prostitution, the HIV threat was recognised relatively early and effective public awareness campaigns have successfully reversed the rise in the incidence of infection. But in neighbouring Malaysia, where stricter religious and social attitudes have inhibited wide public discussion of the disease and its methods of transmission, over 13000 people were HIV-positive at the last count-and that is just the figure derived from the small percentage of the population who have been tested. Activists say the true number is certainly higher and it is growing every day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first cases of HIV in Malaysia were found among intravenous drug users and sex workers, and one of the earliest organisations to begin working with people engaged in these high-risk activities was Pink Triangle. This is a voluntary, non-profit-making body which started up in 1987 by setting up AIDS prevention and support programmes for and with the general public and the gay community. Its name, in fact, refers to the pink triangle badge which men sent to concentration camps in Nazi Germany for homosexuality were made to wear. The group has always depended heavily on volunteers to plan and carry out its programmes, which now also involve running a support group for people with HIV or AIDS and a street outreach programme and drop-in centre providing AIDS information, basic medical care, temporary shelter and food for sex workers, injecting drug users and transsexuals. The centre can also provide legal referrals for members of these groups summonsed to appear in court. For the general public, talks, workshops and poster and photo exhibitions are held in schools, hospitals, factories, youth and corporate organisations and other NGOs. Pink Triangle trains its volunteers, too, to provide counselling and information about AIDS and sexuality to anyone who calls up on a confidential telephone line.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The work is serious and vital, but the atmosphere is far from gloomy in Pink Triangle's premises in a lively part of the Malaysian capital, Kuala Lumpur. Though funding comes from several sources at home and abroad, including the European Union, the organisation still has to generate a lot of its own money, and one successful method they have used is to put on imaginative events where fund-raising can be combined with an opportunity to raise public awareness. Last December, for example, they marked the week surrounding World AIDS Day with a string of shows, dance parties, talk-ins and street activities called Pinkfest '95. In venues all over the town, and on television and radio, well-known personalities joined a hundred of Pink Triangle's own speakers and performers to provide education without moralising. The aim was to personalise the issue of AIDS by showing how anyone could be at risk, but at the same time dealing in facts, not fear. Thousands of attractively designed and very frank leaflets and posters put across the virus-busting message in catchy graphics and pithy phrases in several languages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I happened to be in Kuala Lumpur around New Year and saw a video of some of the Pinkfest highlights which set me thinking how admirable an impression of solidarity and self-help the anti-AIDS struggle in Malaysia conveys, and to wondering whether, back in Brussels, it might not be possible for us in Europe to do something to help. It particularly impressed and touched me that while Pink Triangle delivers its message to every single member of Malaysian society, it makes quite clear, even by its name, that it has a special care for some of that society's most downtrodden members, people for whom no one else had ever ventured to speak. Public silence, opprobrium and ridicule make it especially hard to get the safe-sex message through to gay men, especially the young, to transsexuals and sex workers, and as long as there is no cure the only way of containing the spread of infection is by education- and by changing social attitudes. The many women whose husbands or partners are careless about infection also stand to benefit from greater openness and more factual information. But organising all this takes money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It happens that among the multinational English-speaking expatriate community in Brussels there is a thriving amateur theatre scene-in fact they say that if two British people found themselves on an otherwise deserted island, one would immediately put on a play for the other, and the same seems to hold true of the Irish and the North Americans. However, it was less certain that anyone apart from me would want to exert themselves, for the many weeks required to stage a production, on behalf of an AIDS charity in a remote Asian country, so l decided to go ahead by myself and perform a one-man comedy. The play was Brief Lives; it has nothing whatever to do with AIDS, but in its day it was a huge success in London and New York. Adapted in the 1960s by the British actor Patrick Garland from the dusty old memoirs of a real historical figure, John Aubrey, it depicts a day in the life of this 1 7th-century English scientist, historian and wit. As he potters about, an extremely old man, in a garret full of manuscripts and curios, he reminisces about his contemporaries in hilarious and touching vignettes, the potted biographies which give the play its name. Aubrey died in penury, but the picture he gives of a vanished age is now reckoned to be the equal of the record we find in the diary of the better-known Samuel Pepys.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is also a great deal funnier, and when I showed the script to various friends I was astounded and moved to discover how many of them wanted to be involved in the project. Eventually we put together a team headed by the director, Anne Wilkinson, a music impresario married to a coal expert from the European Commission, with production, design, stage management, lighting, sound effects, costume, music and offstage voices-not to mention publicity and box office-provided by other friends from the European institutions or the private sector. The five performances were given in June in a small theatre just adapted from a pottery workshop, and altogether the Brussels showing made a profit of some 110 000 Belgian francs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We had expected just to send this donation to Pink Triangle through the post, but to our immense pleasure they said they would like to see not just the money but, if possible, the play too. By ingenious compression the designer, Burt Baum, managed to cut the essentials of the set down to three sheets painted to give a three-dimensional effect, we put the voices and music on cassette, rolled up the costume tightly and worked out that the whole play, thus reduced, could be got into one suitcase. There is a little theatre company in the Pacific ACP state of Vanuatu called Wan Smol (One Small) Bag which actually gave me this idea. So off I went to Kuala Lumpur with this bag, and did the play another five times there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The staging in Malaysia was done by an adventurous outfit called Instant Cafe Theatre. This young company has a reputation for pushing forward the boundaries of public discussion with topical plays and supports Pink Triangle's aims and work. Brief Lives was well outside their usual repertoire, as well as being spoken in the English of 300 years ago. My worry was that bringing such a Western and Eurocentric entertainment might be resented as cultural imperialism in a country with three great and fascinating cultures of its own, Malay, Chinese and Indian, each with its own style of drama. But it turned out there was a local tradition of amateur dramatics in English, particularly Shakespeare, and that English is the usual lingua franca for speakers of different Asian languages. What went down unexpectedly well was the depiction of an old man nearing death and reviewing the best moments of his life; as the character puts it in the play, 'When a boy, I did always love to converse with old men, as living histories,' and Maiaysians have a particular regard and affection for the elderly. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I came away from Kuala Lumpur with many charming memories: the unfailing, sweet-natured enthusiasm of the audience; the relief on the first night as I stood on stage in a floor-length costume of three layers, designed to suggest London in midwinter rather than to cope with the equatorial heat of the Malay peninsula, and realised that the stage was air conditioned. The night when this air conditioning blew out a vital candle on the stage, and a man in the front row lent me his highly un-17th-century lighter to get my clay pipe going. The Chinese friend who gave me a genuine antique opium pipe to add to John Aubrey's collection of exotic curios. The delicious succession of Asian chicken dishes which the stage manager produced for me to eat on stage, cooked in very un-English coconut milk or glazed with rice wine. The work permit which specified I could perform as an artiste but must not 'sit out' or dance with the audience! The theatre's resident singer asking if she could add the play's Elizabethan theme song, with lute accompaniment, to her repertoire.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taking this play to another continent was a fascinating cultural experience for me as a European, and I hope for the audiences too it was something more than just a painless way of being relieved of money in a deserving cause. At any rate the theatre asked if they could have another play soon, one in which Malaysian actors could be incorporated as well. As for Pink Triangle, some of its leading lights were packing their bags to go to Vancouver for this year's International AIDS Conference, but before they left it was a pleasure to hand over the proceeds of the whole venture and to hear that the organisation will use the money to develop a drop-in centre for people approaching them in person for the first time. Some first-timers are understandably timid about coming to the unfamiliar (and clearly signposted) premises for help or information, and a private space where they can talk in confidence is something Pink Triangle has always wanted to provide but could never find the funds for, as the project or programme money they get from their regular donors is invariably tied to what outsiders might think were more urgent priorities. It is not only the headline grabbing schemes which have useful effects: a quietly welcoming space where someone can be himself or herself may do more to dispel an individual's fear and ignorance than publicly visible campaigning, especially where religious and social pressures against certain types of nonconformity are strong. In fighting HIV/AIDS, we must try whatever works. And empowerment must begin with the self. It was a great privilege to be welcomed in like any other volunteer wanting to help bring about a necessary change. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">R.R. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">CTA-Bulletin</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Earthen architecture</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Materials, techniques and knowledge at the service of new architectural applications</P>
+<P ALIGN="JUSTIFY">by Hugo Houben and Hubert Guilland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A major building material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The importance - both in quantity and quality- of unbaked earth constructions in the world is very little known. Believed to be of ancient origin, (it is associated with the early civilisations of the Nile, Tigris and Euphrates, Indus and Huang He), nowadays, earth is not usually regarded as a major building material. This is despite the fact that it continues to leave an undeniable and distinctive imprint on the architectural landscapes, both rural and urban, of many countries. Unbaked earth is still, in fact, a major building material, being used extensively by people to erect homes and other buildings. Although sites of human occupation have seen constant regeneration with the passage of time, unbaked earth construction has persisted. Excavated from the soil itself, and moulded by the hand of man (or trampled by beasts of burden), the result is a building material which is used in all forms of construction-from simple huts and modest homes, to farm buildings, large houses, urban blocks, religious edifices, castles and palaces. The skills employed are based on knowledge acquired and refined over a long period of time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A contemporary building material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the use of earth in so called 'advanced' countries has declined in the 40 years since the end of the Second World War, in the developing countries it has continued unabated. In the former, the industrialisation of construction and other sweeping changes have rendered obsolete ancient techniques based on the use of local skills and materials, and on mutual help within communities. In the latter, various factors have dictated the continuing use of locally available solutions, materials and knowledge. These include shortages of processed materials (which are costly in both foreign currency and imported energy terms), the widening of the development 'gap', the accumulation of debt contracted within the international monetary system and the survival of local life-styles in which people are accustomed to coming to get her for mutual help for survival. In these countries, which have no industrial means, and which are to be found in various latitudes across the world, earth remains the main-if not the only- building material. Do these circumstances mean that it is a poor material, fashioned using outmoded techniques and unsuitable for promoting the development which is so necessary? The answer to this question is a clear 'no'. On the contrary, the materials and techniques involved are generally of a high standard. They can ensure true architectural quality, allowing communities to continue creating their private or public living environments, and to integrate their buildings into a coherent framework of self-generated development which makes the most of the resources available, both human and material. In fact, scientific and architectural research into earth as a building material, and on related building techniques, has made considerable progress in recent decades. Combined with investments made by industrialists and construction companies, the result is that we now have a wide range of properly mastered production procedures and technical solutions available. These offer great flexibility in meeting a wide range of possible applications.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Making a mark on world architecture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recent global surveys, although partial (covering about 30% of the world's housing), have given us an indication of how extensively earth is used in construction. In developing countries alone, 50% of the rural population and 20% of those living in urban areas are believed to be concerned. The figures, which are drawn from the combined data of statistical surveys in various areas, and from bibliographical information, almost certainly underestimate the true position. They show, for example, that 60% of the housing in Peru is in moulded bricks or rammed earth. 83% of the houses in Kigali, the capital of Rwanda, are made of earth. More than 70%of India's housing stock is constructed out of moulded earth bricks or using successive layers of earth, and these buildings provide shelter for nearly six hundred million people. In France, many rural dwellings are built from unbaked earth and one finds, for instance, that in the Dauphine region, up to 90% of the buildings in certain villages are made out of rammed 'pise' earth. Finally, in California, there were estimated to be almost 200 000 'adobe' (sun-dried earth brick) dwellings by 1980 and the use of this material was growing at the rate of 30% a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Closer examination reveals that the whole world bears the indelible stamp of earthen architecture. Earth is used in Africa-in humble shelters built on leased land and in the great granaries of the continent. It is found in the palaces of the Hausa emirs of Nigeria, the ksours and kasbahs of Morocco and the mosques of Mali. In the Middle East, you come auoss it in the tightly-packed neighbourhoods of Ispahan and Iran, the fortified dwellings of Najran in Saudi Arabia, the multi-storey earth blocks of Shibam and the valley of the Hadramaut in Yemen. In Europe, there are the mouded brick farms of Aquitaine and the baroque and neo-classical castles of the Saone valley. And bringing in other parts of the world, we might mention the pueblos of the New Mexico Indians, and the houses built by the Hakkas in the Chinese province of Fujian, laid out in their characteristic concentric circles. The use of unbaked earth in building may be seen as a vestige of past history, but it is actually a living framework for history in the making.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Realistic uses for the future</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Confronted with the energy crisis of the 1970s, oil-dependent industrialised countries were forced to look again at tried and tested technical solutions which were now proving to be too 'energy-greedy'. The building sector did not escape this reappraisal and the search began for ways of reducing energy consumption both at source (covering the production and use of building materials) and further down the production chain (maintenance). Research on biomass and solar energy ran in parallel with experiments to update traditional materials and to attempt to rationalise the production process. Earth again became a focus of interest, with government institutions supporting a considerable amount of new research and experimentation. This covered applications in both the industrialised world and in developing countries, research for the latter being undertaken in the context of bilateral or multilateral cooperation. With the threat to the ecological balance posed by pollution, degradation and the plundering of natural areas, this interest in developing materials and techniques that are inherently friendly to the environment has not lessened. In many places, people are becoming increasingly involved in controlling and managing their living environment. The field has been opened up by qualitative research, a new awareness of the available options and an increase in leisure time. With techniques now at hand that are easy to use and economical, a greater measure of (partial or complete) selfhelp building is now possible. The USA, Australia and Germany all encourage new forms of intervention in building which give greater responsibility to the occupier in the creation of his living environment. Viewed from this perspective, earth as a building material has definite advantages and plays an important role.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In developing countries, burdened by debt and confronted by an urgent need to build on a scale unprecedented in history, imported materials, techniques and energy are largely inaccessible to the majority of people, and their use may contribute to promoting 'bad' development. Building with earth emerges as an efficient shortterm way of producing houses or public buildings such as schools, which are both economical and of high quality (being culturally and climatically suitable). Decision-makers in these countries are well aware of this and have mobilised 'upstream' feasibility studies in their education and public housing programmes. The research covers local resources and knowledge, and the use of labour intensive techniques that generate employment and enable the population gradually to become 'monetarised'. The days of costly experimentation, often with no practical result, are now over. A new confidence in the resources that are available must be encouraged. There needs to be an increase in building completions and those who built them need more training. Today, this is happening in Mexico (850 earthen houses recently built in the state of Zacatecas) and in Burkina Faso (6000 school classrooms constructed by 1995.) No fewer than forty million homes will have to be built between now and the year 2000 for the urban population of Africa alone.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Studies show that for most of the people involved, there is no choice but to employ local materials, most often earth. One can thus predict that at least 20% of urban and pert-urban housing in African countries (about eight million units), will be built in earth over the next ten years, at a rate of eight hundred thousand units per year. If demand from rural areas is added to this, one gets some idea of the scale of the task facing decision-makers and builders. The use of earth and other locally available materials is unavoidable, and should be encouraged.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Environmental advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is particularly important to enumerate the many advantages of building in unbaked earth from the point of view of the environment. This issue, one of the contemporary problems facing society, is increasingly moving centre-stage, and in the future, it is sure to play a greater part in political, economic, social and cultural strategies linked to the planning and improvement of the quality of life. Here we refer to the concept of the environment in the widest sense of the word, ecological, economic, technical, health-wise and psychological, cultural and human.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the point of view of the ecological environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In terms of pollution and degradation, unbaked earth offers a highly positive picture:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It does not contribute to the deforestation which results, for example, from the use of organic resources for firing baked earth materials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It does not consume any nonrenewable energy (oil, gas, etc.) at source for the processing and production of materials, or further down the production line in their application. This is in sharp contrast to the production of cement, lime and other conventional binding materials, and steel.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- By exploiting strata on construction sites, it allows a considerable saving in energy for the transport of materials.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It does not contribute to a degradation of the landscape as does the extraction of minerals and ores which hollows out hillsides and creates open cast sites. A great deal of the earth excavated in the course of large public works (notably roads and motorways) can be recycled and used in building (allowing very easy decentralised distribution).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It does not contribute to the diminution of resources of aggregates such as gravel and sand, excavated either from quarries or from water courses, in insular sites or lagoons. The latter can endanger the ecological balance of these natural environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It uses very little water which is essential for the life of the people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It produces no industrial or chemical waste and has the additional advantage of being almost entirely recyclable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the point of view of the economic environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It is often comparable in cost with, or indeed more economic than competing technologies and requires no major financial mobilisation for its generally light production infrastructure. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It guarantees rapid amortisement thresholds for bankable investments thanks to its low infrastructure requirements for usable production.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It contribution to local flexibility, being readily susceptible to a decentralised approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Throughout the production process, it creates employment and monetary added-value which can be injected for development purposes into other sectors of the economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- By allowing savings in energy and foreign currency, it contributes at the macro and micro economic levels of the building sector, to a considerable reduction in developing countries' debt and to the balance of payments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the point of view of the technical environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It has thermophysical and hydric properties (good conductivity, energy retention capacity, thermal differential, delayed temperature differences etc.) which help ensure comfortable temperatures:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It normally only requires simple production and application tools (moulds, presses, light shuttering, normal masonry tools, etc.) which are widely accessible to masons and self-help builders.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the point of view of health and the psychological environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Not only non-polluting in its use, it also guarantees the absence of harmful effects in the context of daily life (no gaseous emissions or other toxic chemical components, radioactive emissions etc.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It contributes to psychological wellbeing by the architectural exploitation of its inherent characteristics; these include the surface texture, colour, form and luminosity of the material. It thus makes an active contribution to the beauty of the living environment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From the point of view of the cultural and human environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-It maintains the traditional architecture heritage of the area in question through the use of local materials and thus plays a part in the respect for, as well as the survival and updating of, cultural, architectural and urban environments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- It allows local populations to take charge of the production of their built environment and thus contributes to the expression of the democratic rights of all to control their living environment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The future of earth on the move</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In her work entitled 'A Fate Worse than Debt' (Penguin Books, 1988), the famous political commentator, Susan George, analysed the debt situation of developing countries and attempted to determine the basis for a positive resolution of the problem. Her approach focused in particular on solutions involving repayment in creative values or 'in kind' rather than in strictly monetary means. At the end of her analysis, she put forward eleven potential solutions to allow this repayment in kind and to launch a coherent approach for the development of less advanced societies. One of these recommendations was that it would be necessary to develop 'the study and survey (and if necessary the improvement) of local building techniques, in particular earth architecture ('pise' or 'banco').' Ms George argued that new buildings, particularly public ones, should be constructed using these techniques.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is clear that various solutions are being considered for the future: one in which building with earth, using a wide range of local techniques, will have a new technological, social, cultural, ecological, economic and political role of paramount importance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Various methods of utilisation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The technical, constructional and architectural possibilities of earth are very extensive. The study of popular traditions and of traditional knowledge throughout the world has enabled some 18 different methods of utilisation of the material to be identified, each in itself capable of being applied in a wide variety of ways. This wide construction potential has enabled the building of modest shelters, village houses, urban blocks, religious edifices and palaces. This is not to say that other traditional materials do not have an important role, but the sheer diversity and flexibility of earthen architecture probably cannot be equalled.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As was indicated earlier, the use of earth as a building material has given rise to numerous applications using a wide variety of production and construction techniques. Some of these techniques are still used in traditional construction many countries, some have been abandoned, while others have only recently been the subject of developmental experimentation. It is worth noting that there is a register of the principal techniques, mainly associated with processes using moulds, shuttering and direct shaping. The six most widely used techniques are: 'adobe', 'rammed earth', 'straw clay', 'wattle and daub', 'cob' and 'compressed blocks'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of these six, three (wattle and daub, straw clay, and cob), are highly traditional, while the others (adobe, rammed earth and compressed earth blocks) have recently been the subject of spectacular evolution linked to the modernisation of production machinery and methods of application. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p094.png"></center><br>
+ The use of earth</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The couriers mailbag</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Plea for African solidarity</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thank you sincerely for your report on the second plenary of the Global Coalition for Africa which appeared in the March-April 1996 edition. As a 'displaced' Liberian, I would like to comment on some of the issues reported in the article.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">First, I hope that Africans recognise and appreciate all that former President Jimmy Carter has done and continues to do for our beloved continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Second, I support the view of Ms Johnson-Sirleaf and President Afwerki of Eritrea that we, as Africans, must invest in ourselves and in productive endeavours in our own countries. However, given the number of civil wars, that have resulted in displacement of our peoples and migration of the labour force, it is imperative that we also begin to think of and recognise each other as Africans first - and only then as members of whatever ethnic group we belong to. As a Liberian with professional qualifications who relocated to Ghana in 1992, I met with opposition and resentment because of my nationality and sex. I subsequently went to the Caribbean where my acceptance as an African was easier.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When there is a population movement, the psychological impact associated with feelings of rejection and intimidation is severe. Sub-Saharan Africa will never develop or reach its fullest potential until we begin to think and act as a united, yet diverse group of people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I agree that it is important to develop our homelands first, but in the case of Liberia, Burundi or Rwanda, where no one seems to understand the concept of peace or the idea of having a future, it is crucial that the displaced be respected and accepted as fellow Africans. It would be even better if we were afforded the opportunity to integrate and assimilate into society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ciata A. Bishop, Grand Cayman.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What about Guinea-Bissau ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I am a student from Guinea-Bissau reading international law and political science at the Social Science University in Toulouse. I have also been a faithful Courier reader for more than seven years. In the March-April issue of 1996, you published an article on fisheries by Anthony Acheampong entitled 'A vital food source in West Africa'. You gave the figures for fish production in 16 West African countries-but did not mention my native country! I should point out that Guinea-Bissau consumes and exports a great deal of fish, and the product is an important source of foreign exchange to the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">F.J. Alves d'Almada, Toulouse, France.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Media and democracy in Southern Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I refer to the article with the above title by Francis Caas which appeared in issue no. 154 of The Courier (November-December). I enjoyed reading the text which examined the emergence of a free press due to the advent of political liberalisation in the Southern African region. However, I wish to make a correction as to what I think is a misrepresentation of fact. The author said, and I quote: 'The installation of a democratic regime in 1994 (in Malawi) enabled the MBC to begin broadcasting in all languages spoken in the country'. This is not actually correct although the Malawi Broadcasting Corporation, apart from broadcasting in English and Chechewa, has since introduced Tumbuka on the radio. I felt it was important to put the record straight on this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Disher G.DJ. Pindani Lecturer in Public Administration, Chancellor College, Zomba, Malawi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Corrigenda </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In issue no 157, a number of 'author' footnotes were inadvertently omitted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pascal Dotchevi, author of 'Togo: the victory of the taxi. bikes' (p.11) is a journalist on Kpakpa Desenchante, a satirical weekly published in Lom&eacute; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Piritta Sorsa, author of 'Banking and securities' (p.13) works at the IMF office in Geneva.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yves Delafon, author of 'Developing consultancy work in the ACP countries' (p.15) is the director of a consultancy and President of the Federation of External Trade Associations in Provence/ Cote d'Azur.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">N'Gone Fall, author of 'Fashion; Out of Africa.. the breath of inspiration' (p.53) is a journalist.</P>
+<P ALIGN="JUSTIFY">Also in issue 157, some errors appeared in the article entitled 'Sparks fly in Namibia'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the introductory section it was stated that secret harlots were held on resolutions relating to Nigeria, Niger and Sudan. This should have read Nigeria, Niger and Equatorial Guinea; a resolution on Sudan was passed by normal, open vote procedure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under the heading 'The future of Lom&eacute;' the ACP Generai Rapporteur vvas refered to as Mr Firmin, which is the forename. The General Rapporteur's surname is Mr Jean-Louis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the fifth paragraph under the same heading, there was a reference to Helena Torres Couto. This should have read Mr Jose Manuel Torres Couto. </P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Bibliography</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">L'Afrique est-elle protectionniste- Les chemins buissonniers de la liberation exterieure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Is Africa protectionist ? Greater economic freedom via the maze)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Beatrice Hibou. Karthala Publications (22-24, boulevard Arago, F-75013 Paris). 1996. 334 pp. ISBN 286537-633-8.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This volume offers a clearsighted analysis of the foreign trade policies of African states, fraud, smuggling and the way in which the franc zone operates, giving a definitive, reformulated account of structural adjustment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In her approach, the author is critical of both the liberal political economy and the new trends (the 'new political economy' end the neoinstitutionalist trends) which perpetuate the division between the economy and society. She refers to K Polanyi for whom Man's social relationships include economics and in whose opinion the economic system is managed as a function of non-economic motives.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">From this starting point, Beatrice Hibou demonstrates the part played by the unexpected and the unintentional in economic policies as they currently exist, revealing that coherence in foreign-trade policies on the part of African countries is not an economic priority but a socio-political one. In this connection, she shows that structural adjustment programmes have been unsuccessful in making any real impact on protectionist practices, at least in terms of their political and historical bases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After an overview of (legal or illegal) foreign-trade practices in contemporary Africa, protectionism is clearly alive and well, although much less widely applied and effective than about a decade ago. The reduction in the State's legal powers has meant increased freedom for 'informal networks', various types of dispensation, and an increase in fraud and smuggling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the basis of Jean-Francois Bayart's opinion, dating from 1989, the author suggests that the explanation is to be found in the specific nature of Africa's economic history, which is one of independent means, a lack of production and management of dependency without the way in which it operates being affected. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dominique David</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Reality of Aid</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Independent review of international aid. Pub.: J. Randel and T. German. Earthscan Publications Ltd. (120, Pentonville Road, UK London N1 9JN). 1996. 244 pp. ISBN 1 85383 292 8.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Reality of Aid (now an annual publication) compiled by two NGOs; Eurostep and ICVA, aims to highlight the extent to which donor aid helps developing nations, looking beyond the official publications of governments, banks and inter-governmental bodies. It contains a useful critique of the European Union's various aid policies and the respective bilateral policies of each of its 15 member states, as well as those of other Western nations like Australia, New Zealand, Switzerland and the United States. This year's review highlights, in particular, the need to mount more projects to alleviate poverty, despite aid commitments becoming more scarce.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It says, for example, 'Too much aid is being squandered by governments on projects which have more to do with commercial and political advantage than poverty eradication. Rigorous evaluation needs to identify those programmes which can make an impact -and aid must increasingly be directed only to these areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">International aid to developing nations has fallen off over the years. In 1994, members of the OECD's Development Assistance Committee-21 of the world's richest countries-allowed their aid to fall to just 0.3 % of GNP, the lowest level for more than 20 years. The review stresses the need for donors to address in particular; policy coherence (environment, agriculture and consumption policies are all linked to poverty), the effectiveness of aid, the failure thus far to invest in people and the fact that the amount of assistance going to health and education is stagnating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The review also features analytical case studies of various donor activities in selected developing nations (India, Fiji, Cambodia, Peru, Zimbabwe) and looks at Western assistance to post communist countries in transition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A chapter on the European Union's current development policies, edited by Mirjam van Reisen, a Brussels-based Eurostep researcher, criticises the lack of coherence of EU aid with its Member States bilateral programmes-an issue which is likely to come more to the fore as other European nations join the Union in the next millennium. Ms van Reisen also claims that there are too few staff running the EU's development policies and suggests, in particular, that there is a lack of expertise in the social and poverty areas. She stresses the importance for the EU's political leaders of giving more political clout to the EU's development policies at the Intergovernmental Conference (IGC), which is currently engaged in revising the EU's treaties. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Debra Percival</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">News round-up</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">In brief</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trafficking of women</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">European Commissioner for immigration policy and legal affairs, Anita Gradin, will set to work with fellow Commissioners over the coming months to draw up a European Union action programme to clamp down on the trafficking of women which she describes as, 'the modern slave trade'. This comes hot on the heels of the Vienna European conference on trafficking of women, held on June 10 and 11, which was co-hosted by the European Commission, the Austrian government and the International Organisation for Migration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ms Gradin told journalists on June 12: 'I will put forward to the Council and the European Parliament a communication on the trafficking in women for sexual exploitation. This will cover migration policy, police and judicial cooperation, and social aspects to support and protect the victims. It will also consider European relations with the source countries, where the women are recruited.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Vienna conference highlighted the need for cooperation between Member States and third countrie from which women are lured into prostitution in Western Europe. Recommendations, which are expected to be part of the EU policy, include setting up central national units in each Member State to exchange information.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commissioner told the participants in Vienna: 'The slave trade in women is growing, a slave-trade that aims at sexual exploitation. No part of the world seems to be free from this degrading treatment of women. Women are bought and sold like cattle or commodities. They are deprived of their rights and their dignity. And the direction of the trade is the same all over-it is women from poor conditions that are forced into a deplorable life by men in richer countries.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">She cited a typical case of one woman from the Dominican Republic from the book 'Stolen Lives' by Sietske Altinks: 'One day I went to visit a friend who was going to discuss job opportunities in Europe. I went with her and met a schoolteacher who knew somebody called Juan who could get me a job in the Netherlands. When I went to see him, his associates told me that I would easily find employment in a beauty parlour.' She ended up in prostitution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ms Gradin continued: 'The consequences for the women are dreadful. Often, they find themselves deprived of their freedom to move and decide for themselves; they are often locked up and subjected to violence and sexual exploitation. And should they be able to free themselves, they are regarded as illegal residents and expelled.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Debra Percival</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Aid for development in the field of communication</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A seminar was held under the auspices of the United Nations in the Belgian Parliament on 6 and 7 June, on 'the future of international development cooperation: new challenges for communication'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union was represented at the event, among others, by Colette Flesch and Steffen Smidt, the directors general respectively of DG X and DG VlII of the Commission. Mrs Flesch gave a presentation at the opening session in which she highlighted the various communication approaches adopted by the European Community in its efforts to counter what appears to be a growing lack of interest in development aid on the continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Smidt, who spoke in the second session of the seminar, began his presentation with an anecdote, citing a text displayed at the entrance to a Federal building in Washington. This states: 'Taxes are what we pay to have a civilised society'. Paraphrasing this sentiment, the Director-General argued that, 'development assistance is what we pay to have a civilised European Union.' The question, he went on to pose, was whether we were paying enough ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A number of the participants painted a discouraging picture of the situation facing the world's poorest countries in a world of advanced communications and increasing globalisation. Almost all were pessimistic about the impact of the socalled 'information super highways' on the least-developed nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the most striking interventions came from Mabbub Ul Haq, the former Finance Minister of Pakistan, who spoke just after Mr Smidt in the plenary meeting, as well as at one of the discussion workshops. Mr Ul Haq urged the creation of a UN Economic Security Council, arguing that the main risk of global conflagration lies in the disparity that exists between rich and poor, now that the dangers associated with the Cold War have receded. One of the most acute issues under discussion was the growing challenge to the received wisdom that technical assistance is essential for consolidating national capacities. The evidence of 40 years of technical assistance would suggest otherwise (with 95% of funds set aside for this purpose going to foreign experts). Indeed, it was argued that those countries receiving most technical assistance per capita, had 'benefited' least from the system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In his second contribution, Mr Ul Haq painted a somewhat more encouraging picture, pointing out that the shaky 0.3% share of GNP allocated to development aid by the industrialised countries had achieved miracles in terms of increased life expectancy (up by 17 years) and the doubling of school enrolments in the countries of the South.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hegel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Round one of the South Africa-EU talks</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Africa gave no immediate response to the European Union's proposals for a bilateral trade agreement at the first round of high level negotiations in Brussels on June 20. The talks were headed by Dr L. T Links who is South Africa's new Ambassador in Brussels and for the KU, by the Director General for Development, Steffen Smidt. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most difficult subject to negotiate will be future terms of access for South Africa's farm produce. The European mandate, which was agreed by EU Member States on March 25, foresees the exclusion of 39% of South Africa's farm produce currently sold to the EU from the planned free trade area. Applying World Trade Organisation (WTO) rules, the EU wants a scaled dismantling of barriers to trade in both farm and manufactured goods over a 10-year period, with a maximum of 12 years for a few highly sensitive items. But the EU has agreed to 'asymmetry' whereby, in some areas, it will open up its market to South Africa at a faster pace than vice versa. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Abdul Minty, deputy Director General at the Foreign Affairs Department in Pretoria, who is one of ,the chief negotiators, explained that South Africa had not yet responded to the terms because it is still consulting internally with the National Economic Development and Labour Council and with its partners of the Southern African Customs Union (Botswana, Swaziland, Namibia and Lesotho). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During a recent visit to Brussels, South Africa's former agriculture minister, Dr Kraai van Niekerk and his deputy, Mrs Thoko Didiza, told reporters that as it stood, the EU's mandate was 'anti-developmental'. Dr van Niekerk said he would like to see citrus fruit, in particular, removed from the list of exclusions. He also sought to dispel the fears of some EU Member States who wish to omit a larger proportion of South Africa's farm produce from the FTA, for fear of competition with equivalent EU produce.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr van Niekerk stressed the 'complementary' nature of South Africa's farm production. He pointed out that his country's growing season was at the opposite time of year to that of the EU and noted that South Africa's output of farm produce could only increase by about 2%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EU spokesman, Joao Vale de Almeida, said that progress had been made during the Brussels talks on aspects of South Africa's 'tome protocol'. This is aimed at giving South Africa certain benefits from the Lom&eacute; Convention- some eligibility for South African companies to tender for Lom&eacute; contracts and the partial extension of the Lom&eacute; rules of origin to South African exports. It was originally planned that the Lom&eacute; protocol should be implemented at the same time as a bilateral trade accord, (on January 1 1997). Mr Vale de Almeida spelt out that although it would not be technically and legally impossible for the Lom&eacute; protocol to come on stream without the bilateral pact, it would be more practical if the two could be implemented at the same time. A second round of talks is expected to take place in the autumn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Echo Media Awards</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On 29 June, the European Community Humanitarian Office (ECHO) launched a Television and Radio awards scheme to reward high-quality coverage of humanitarian affairs. Prizes will go to programmes produced or co-produced by independent production companies and/or broadcasting stations in the 15 EU countries which have been transmitted in a Member State on terrestrial or satellite television or radio between January 1 1995 and September 1 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Judging by a panel made up of NGOs, environmentalists, politicians and the media will be in six categories:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People on the move-a television documentary on the humanitarian consequences of sudden or forced population movements; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the minds of the people-a TV documentary on the psychological trauma in crisis situations; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Forgotten conflicts-TV coverage of a long-running crisis forgotten by the mainstream; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vulnerable groups-TV coverage of the hazards encountered by women, children and the elderly in rebuilding their lives; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Broadcast commitment-to a radio or TV station for consistent, high-quality coverage of humanitarian issues; </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Radio award-for the most incisive and analytical coverage of an emergency or humanitarian crisis. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Announcing the scheme, EC Commissioner, Emma Bonino, said: 'These awards give us an opportunity to acknowledge the vital role that broadcasters play in raising awareness of the issues at stake in imaginative, accurate and moving ways. They also serve to remind us of some of the basic European values such as solidarity and humanitarianism that have sometimes been eclipsed by barrages of headlines about mad cows and fish wars.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Entries for this inaugural year must be submitted by September 19, 1996. Details can be obtained from: Mandy Duncan-Smith, Media Natura (UK), tel: (44 171) 240 4936 fax: (44171) 240 2291 E-mail: medianatura@gn.apc.org</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Posters featuring contemporary Bantu art</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the framework of its cooperation programme with the Commission, CICIBA (Centre international des civilisations bantu-B.P. 770-Libreville- Gabon) has recently launched a series of large format reproductions featuring contemporary Bantu art. Thirteen works have been chosen, displaying a representative selection of art forms-painting, sculpture, engraving and moulded leather. The posters, more than 5000 of which have been printed in quadrichromic colour, have a 40 x 60 format. They are also available as postcards.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The artists featured are Marcela Costa (Angola), Assouambo (Cameroon), Daikou (Central African Republic), Mouanga Nkodia (Congo), Abdou Moeou (Comoros), Pambou Boulaz (Gabon), Jose Menan (Equatorial Guinea), Protais Hakizimfura (Rwanda), Protasio Pina (Sao Tome &amp; Principe), Silu Kinanga and Munyenz Tshibangu (Zaire) and Mulenga Chafilwa (Zambia).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CICIBA has also put together a similar series on ancient Bantu art. The fourth bi-annual exhibition of contemporary Bantu art, which has received some support from the European Commission, was due to be staged in Luanda (Angola) during July and August.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Links between technology and society</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For more than 50 years, technological innovation has been regarded by many writers in the field as the motor of economic development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, with rapid developments in the media sector and the emergence of 'information super-highways', the whole world is talking about the emergence of a new society dominated by 'smart' technology linked with research and creativity. This trend gives rise to many questions. Will the information be made available to all, and if so, when ? Will it lead to a change in North-South relations? Can we imagine what a world of 'tale-working', 'tale-education' and video on demand will be like ? What will the cost of all this be? Will biotechnology rescue the world or be the cause of its downfall ? What will the consequences be for the environment ? And in a globalised world, what standards and norms will be used ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In short, what is the real nature of the relationship between technology and society; between science and humankind ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fifteen universities of the EEA (European Economic Area) from Oslo to the Basque country and from London to Athens (taking in Roskilde, Maastricht, Louvainla-Neuve, Namur, Strasbourg, Lausanne, Sienna, Bari, Madrid, Valencia and Lisbon), have come together to offer a multidisciplinary course focusing on these key questions. During the first term, classes in theory and seminars are offered (in the local language of the institution) by experts from the academic world and the public and private sectors. Visits are also planned to multinational companies and laboratories. For the second half of the course, the students gain a wider European dimension by 'changing' university (with grants from the Socrates programme). The bulk of their time at this stage will be spent preparing a research dissertation in English on a topic which fits in with the specialisation of the host institution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For further information on the ESST</P>
+<P ALIGN="JUSTIFY">programme, contact:</P>
+<P ALIGN="JUSTIFY">Prof. E Lints (UCL-Belgium)</P>
+<P ALIGN="JUSTIFY">Tel. (32) 01047.82.60</P>
+<P ALIGN="JUSTIFY">Prof. T. Nguyen (FUNDP-Belgium)</P>
+<P ALIGN="JUSTIFY">Tel. (32) 081-72.49.09</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The institutions at work</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Common foreign and security policy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Within the framework of its Common Foreign and Security Policy (CFSP), the European Union has recently issued a number of statements, details of which are set out below:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Antipersonnel mines</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 13 May 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the closure of the Review Conference of the States Parties to the Convention on Certain Conventional Weapons, the European Union recalls that it has, in recent years, redoubled its efforts to combat the severe consequences caused to civilians by the indiscriminate use of land mines, in particular anti-personnel mines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The KU, which adopted joint action in May 1995 in order to reconfirm its commitment to the objective of an overall strengthening of Protocol 11 of the CCW, considers that the achievements of the Review Conference (such as the extension of the scope of Protocol II; the strengthening of restrictions on the use of mines; the new and immediate prohibitions regarding transfers; the provisions on technological cooperation and assistance; the regular review mechanism, etc), taken together, are significant steps forward, both in terms of the land mines protocol itself and of the development of international humanitarian law.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The KU, however, underlines that the resuits of the Review Conference fall short of its expectations and of some of the goals set out in its joint action. In particular, the EU should have liked an effective and binding verification mechanism and no periods of deferral of compliance, or at least much shorter ones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU is convinced that the conclusion of this Review Conference is only the beginning of a challenging process which requires constant and widespread efforts and persistence in order to fully achieve its basic humanitarian objectives. The EU will continue to seek solutions to the problems caused by antipersonnel land mines and will strive towards the goal of their eventual elimination as stated in UN Resolution 50/70 (O). In the meantime, the Member States of the EU will seek early ratification of the amended Protocol II, as well as of the new Protocol IV on blinding laser weapons, and will take urgent steps to ensure their compliance with all the provisions of these two protocols pending their entry into force.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU will also continue to make active efforts with a view to achieving universal adherence to the CCW, since its objectives can only be effectively attained through implementation of its provisions by the widest number of states and parties to conflicts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Furthermore, the EU recalls its determination to pursue its contribution to the international mine clearance efforts. The EU has already contributed to the UN Voluntary Trust Fund, financing, in particular, projects in Angola and Mozambique as well as in Bosnia-Herzegovina and Croatia. In addition, the EU will consider the possibility of conducting specific demining actions and will continue to seek to that effect the contribution of the WEU to the elaboration and implementation of such actions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Central and Eastern European countries associated with the EU (Bulgaria, the Czech Republic, Estonia, Hungary, Latvia, Lithuania, Poland, Romania and Slovakia) and the associated countries Cyprus and Malta, as well as the EFTA country members of the EEA, Iceland, Liechtenstein, and Norway, align themselves with this statement.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Great Lakes region and the situation in Burundi</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 24 June 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU's objectives and priorities with regard to the Great Lakes region are to secure peace, to consolidate the process of national reconciliation in the countries concerned, to facilitate a return to normal democratic life, in particular by restoring the rule of law, and to encourage economic and social recovery.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Aware as it is of the close links between the various political, economic and humanitarian problems in the region and of the serious risk of destabilisation which remains, the EU would emphasise the need for a comprehensive approach and a regional dimension in the search for lasting solutions to the crisis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It considers that the presence of over a million and a half refugees in the region constitutes a major factor of destabilisation and that their return to their countries of origin in safety and with dignity is essential if peace is to be restored.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It appeals to the Heads of State who signed the Cairo and Tunis Declarations to comply with the undertakings they gave, so as in particular to stop trafficking in arms and the training of the various militia and armed groups which serve only to increase insecurity in the region. It would point to United Nations Resolution 1053 in this regard and also the measures in the plan of action adopted by the Bujumbura Conference (12 to 17 February 1995) for the prevention of subversive activities in countries of asylum. The EU also emphasises the importance of deploying United Nations observers in airports and at frontiers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU is increasingly concerned at the deteriorating political and human rights situation in Burundi and at the increase in violence. The persistent clashes, spreading over different parts of the country, and the killings and atrocities committed against the civilian population could well involve Burundi in a spiral of permanent conflict.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU strongly condemns all recourse to violence, which will never bring about a solution to the country's problems, and appeals to all the factions in the country to begin negotiating a resolution of their differences and to agree on an immediate, general cessation of violence. It supports the initiatives taken by the United Nations and the Organisation of African Unity to restore peace, as well as former President Nyerere's current efforts in this area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It fervently hopes that the talks taking place will result in a national dialogue open to all factions within the country. It also expresses its support for the ongoing efforts made by various bodies and eminent figures such as former Presidents Carter and Toure, and Archbishop Tutu.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU would point out that it too has taken initiatives aimed at resolving the crisis and recently appointed a special envoy for the Great Lakes region, Mr Aldo Ajello, to assist the current efforts of the United Nations, the Organisation of African Unity and other bodies and individuals, and specifically to lend support to the organisation of a regional conference under the joint aegis of the UN and the OAU to examine and resolve the deep-rooted causes of the crisis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU remains convinced that such a conference must be convened as soon as possible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU reiterates that it is prepared to assist with specific measures to promote peace and reconciliation in Burundi, in particular the organisation of a national dialogue, support for action to promote human rights and the restoring of the rule of law. It is furthermore willing to continue funding the presence of OAU observers and United Nations human rights observers in the country. It is also prepared to help with the economic and social recovery of Burundi as soon as political and security conditions allow rehabilitation programmes to be set up in the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Niger: progressive restoration of aid</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 28 June 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union takes note of the fact that the regime in Niger has announced the results of the country's constitutional referendum and has lifted the state of emergency and the ban on political parties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU takes the view that Niger has thus met the conditions set out by the Council on 13 May 1996 for the progressive restoration of cooperation. In the first instance, this will take the form of: -support for the electoral process; -aid for structural adjustment which, at present, needs to be focused exclusively on the most pressing needs in the social sectors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Council will continue to follow closely the situation in Niger, in particular as regards the preparation and conduct of the presidential and legislative elections.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arusha summit on Burundi</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 5 July 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recalling its declaration of 25 June 1996, the European Union congratulates President Mkapa on the organisation of the Arusha regional summit, which has produced constructive proposals on the conflict in Burundi. It expresses appreciation for the untiring efforts of former President Nyerere and reiterates its support for his peace initiative.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU encourages the region's Heads of State and the Organisation of African Unity to commit themselves resolutely to supporting and giving substance to the Arusha recommendations and to contribute to the restoration of security in Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU expects the President and the Prime Minister of Burundi to fulfil the undertakings they gave at the Summit to overcome the crisis in Burundi and, with the help of the countries of the region, to put an end to the violence which is destroying the people of Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU calls on all the political forces of Burundi to seek a political solution and to give a favourable reception to regional initiatives to restore peace to their country. It calls the attention of all the parties to the conflict in Burundi to the fact that it condemns all forms of violence and that it will not recognise a government that has taken power by force of arms. Only peace, a peace consolidated at regional level, can guarantee the security of all and lay the foundations for economic and social development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU is prepared to support the realisation of the Arusha objectives with a view to restoring peace and security in Burundi. It reiterates its readiness to help Burundi in its economic and social recovery when political and security conditions make it possible to begin its rehabilitation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU reiterates the need to convene the Conference on Peace, Security and Stability in the Great Lakes Region under the joint aegis of the United Nations and the OAU.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burundi: support for the OAU Resolution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 15 July 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recalling its previous Declarations and Common Position on Burundi and, in particular, the Declarations of 25 June 1996 and 5 July 1996, the European Union warmly welcomes the Resolution on Burundi adopted by the Organisation of African Unity's Assembly of Heads of State and Government in Yaounde on 8 -10 July 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Union particularly welcomes the reaffirmation by the OAU of its support for the Mwanza Peace Talks under the facilitation of former President Nyerere and its encouragement to him to continue with his efforts based on and incorporating the principles of sustainable democracy and security for all the people of Burundi and an all-inclusive negotiation process. The Union reiterates its appreciation of the untiring efforts of former President Nyerere and its support for his peace initiative in this context.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The declaration in the Resolution of the OAU's full support for the outcome of the Arusha Summit of 25 June 1996, especially the acceptance of the request by the Government of Burundi for security assistance in order to complement and reinforce the Mwanza peace talks, as well as creating conducive security conditions for all parties to freely participate in the Mwanza process is also welcomed by the Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU reaffirms its willingness to support the realisation of the Arusha objectives with a view to restoring peace and security in Burundi. It remains ready to help Burundi in its economic and social recovery when political and security conditions make it possible to begin its rehabilitation.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Visits</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The President of Haiti</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The President of the Republic of Haiti, Rene Preval, visited the Commission on 11 June. He met with President Jacques Santer, Commissioner Joao de Deus Pinheiro (responsible for relations with the ACP States) and Commissioner Emma Bonino (responsible for humanitarian aid).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">President Preval thanked the European Union for all the support it had provided both for the restoration of democracy in Haiti and for the country's economic development. He spoke in particular of the discussions that are currently under way with the Bretton Woods institutions aimed at restoring Haiti's economy. The President indicated that an economic recovery programme would need balance of payments support to the tune of $119m during 1996, as well as assistance for a range of economic sectors amounting to a billion dollars over a three-year period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For his part, Professor Pinheiro expressed satisfaction at being able to welcome the President at a time when the democratic process in Haiti was functioning normally and institutional consolidation was taking place. In a statement to the press, he said it was an appropriate moment 'to evaluate our cooperation and to strengthen it in a way that will contribute to economic and social development' in Haiti. He added that it was essential for the Haitian people to recognise that democracy was worthwhile. Professor Pinheiro also welcomed the normalisation of relations between Haiti and its neighbour, the Dominican Republic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The President of the Dominican Republic</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The newly-elected President of the Dominican Republic, Leonel Fernandez Reyna, had a working session at the Commission on 15 and 16 July.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This trip to Brussels was the President's first overseas visit in his new capacity, following his election on 30 June. Indeed, he had not yet formally assumed office at the time of his visit. His inauguration was due to take place on 16 August and the President-elect extended an invitation to the Commission to attend the ceremony. Mr Fernandez Reyna's subsequent itinerary included visits to Spain, France and the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Support for human rights</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has recently approved the financing of the following projects under the budget line 'Human Rights and Democracy in the Developing Countries):</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea: ECU 120 000 for a project aimed at actively involving members of the National Assembly in the institution's functioning, and in the democratisation process taking place in the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Niger: ECU 72 000 for a human rights training programme in schools in both urban and rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nigeria: ECU 118 000 for a human -rights training programme to be run in educational establishments and through itinerant projects in regions lacking education infrastructures. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji: ECU 119 000 for a project to support a non-partisan, multi-ethnic civic forum, aimed at contributing to the achievement of a consensus among various social groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Non-ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal: ECU 59 112 to safeguard texts which are essential to the preservation of Tibetan culture. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nepal: ECU 30196 for the archiving of slides and photographs depicting art objects in order to preserve the culture and traditional techniques of Tibet. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Philippines: ECU 61 750 for a mission to identify the areas in which strategies for human rights and democracy could lead to positive and lasting changes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sri Lanka: ECU 84 314 for a programme of information in the field of promoting equal opportunities and non-discrimination </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Aid for rehabilitation</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has recently decided to finance the following projects in developing countries affected by serious civil disturbances or natural disasters:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angola: ECU 847 000 for an integrated programme covering the rehabilitation of agriculture and basic infrastructures, training in demining, hygiene and self sustaining development in Kipungo. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angola: ECU 185 000 for the rehabilitation of basic infrastructures (water, health, education and housing) In the province of Luanda. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eritrea: ECU 353 947 to support the rehabilitation and development of basic </P>
+<P ALIGN="JUSTIFY">health care services in the south-west of the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eritrea: ECU 575 197 for the rehabilitation of water supplies and community development in the town of Hagaz. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia: ECU 515.685 for the rehabilitation of primary care and water supplies in the Warder area. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia: ECU 455 630 to help the rehabilitation of repatriated people and displaced persons in the Borena area. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia: ECU 308 475 for the rehabilitation of health care and water supplies in the Hararghe area. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 848 000 for a programme of support to upgrade medical infrastructures. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 590 000 to consolidate the water sector and rehabilitate livestock infrastructures in Maputo and Gaza provinces. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 500 000 for the second phase of a programme to help reestablish and reintegrate displaced people in Milange. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda: ECU 241 259 for a project designed to revitalise livestock producer groups, make available essential veterinary products and support cattle production in the landward prefecture of Kigali. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda: ECU 411 751 to provide professional training in primary health care. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda: ECU 805 475 for an environment rehabilitation project in the prefecture of Kibungo. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda: ECU 437 622 for the rehabilitation of primary schools in the southwest of the country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rwanda: ECU 94 650 to train laboratory technicians. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Somalia: ECU 626 439 for the rehabilitation of wells and water points in the Nugal region. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zaire: ECU 423 687 for the creation of enterprises involved in making bricks and earth blocks in order to assist in the rehabilitation of rural habitats. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zaire: ECU 1 491 117 for a tree-planting project around the Virungas National Park as part of a rehabilitation programme directed at Rwanda's immediate neighbours.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Haiti: ECU 213 536 for operational and methodological support for rural development projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Haiti: ECU 645 120 for technical assistance in the follow-up and evaluation of rehabilitation projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Haiti: ECU 551980 for a programme to rehabilitate schools and provide support for the education sector. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">European development fund</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following, where required, favourable opinions from the EDF Committee, the Commission has decided to provide grants and special loans from the 5th, 6th and 7th EDFs to finance the following operations (grants unless otherwise stated). Major projects and programmes are highlighted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic and social infrastructure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malawi: ECU 1.9 million for the rehabilitation and construction of customs facilities. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia: ECU 11 million for resurfacing and improvements to the runway at Lusaka international Airport. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji ECU 1.8 million for the rebuilding of three bridges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade promotion/ structural adjustment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Member states of SADC (Southern Africa), ECOWAS (West Africa) and ECOCAS (Central Africa): ECU 500 000 for a follow-up pilot project relating to industrial fore in different sectors. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Botswana: ECU 1.9 million for a tourism development programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Djibouti: ECU 4.1 million to support the 1996-97 structural adjustment programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Netherlands Antilles/Aruba: ECU 5 million for a tourism promotion programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture/ rural development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Madagascar: ECU 1.9 million to support professional organisations in the field of rural credit. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Swaziland: ECU 1.4 million to build a bridge at Maphobeni, to facilitate rural development in this area. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Swaziland: ECU 1.5 million to improve the storage and commercialisation of maize. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Health</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Benin: ECU 700 000 to enhance the security of blood supplies in the Oueme, Mono and Atlantique departments. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Education/training</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Botswana: ECU 15 million for a training programme directed at SMEs, independent operators and the unemployed. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia: ECU 1.05 million for a programme designed to strengthen training and research capacity in the economic field. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Member states of IGAD (Djibouti, Eritrea, Ethiopia, Kenya, Somalia, Sudan, Uganda): ECU 1.9 million for a training programme for the commercialisation of cereals. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lesotho: ECU 1.3 million for a community reforestation programme in the Lesotho Highlands. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Institutional support</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Djibouti: ECU 250 000 to provide technical support for the computerisation of the National Bank's accounting system. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Niger: ECU 1.8 million to support the electoral process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya: ECU 1.7 million for an assistance programme for the National Authorising </P>
+<P ALIGN="JUSTIFY">Officer covering the management of funds allocated by the European Community.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia: ECU 1.5 million for the first phase of a tourism development programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cariforum countries-Antigua &amp; Barbuda, Barbados, Belize, Bahamas, Dominica, Dominican Republic, Grenada, Guyana, Haiti, Jamaica, St Kitts &amp; Nevis, St Lucia, St Vincent &amp; the Grenadines, Suriname, Trinidad &amp; Tobago): ECU 725 000 in technical assistance for the programming unit of the Cariforum General Secretariat. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Miscellaneous</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All ACPs: ECU 5 million to strengthen fisheries management and biodiversity. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghana: ECU 1.5 million for a pilot project in the field of decentralised cooperation. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya: ECU 12.5 million for a community development programme in the battle against poverty. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Somalia: ECU 47 million for the second rehabilitation programme. The focus will be on productive activities (livestock, agriculture and fisheries), the social sectors (health, water, sanitation systems and education), the private sector (revenue generation, job creation, SMEs), the public sector (training, establishment of institutions), demobilisation, and the integration of former combatants </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia: ECU 1.6 million for a programme to combat poverty including, in particular, the provision of credit to micro-enterprises. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zaire: ECU 2 million to support the integration of displaced people in Kasai. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">European investment bank</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Africa: A loan of ECU 56 million for Eskom, the public electricity company, for the modemisation of part of its electricity distribution network.</P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Humanitarian aid</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angola: ECU 14 million for a global assistance programme covering food and medical aid, the distribution of equipment and demining operations. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad: ECU 500 000 for the distribution of essential food products and to meet the special nutritional needs of children in the north of the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cote d'lvoire: ECU 340 000 to help combat cholera and yellow fever among refugees from Liberia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ghana: ECU 140 000 towards the setting up of a camp for 'boat people' arriving from Liberia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guinea: ECU 160000 for the distribution of food to refugees from Liberia and Sierra Leone. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Senegal: ECU 250 000 towards the fight against cholera, notably in the town of Touba.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sierra Leone: ECU 4.2 million for food and emergency medical aid (to combat cholera) for people displaced by the civil war. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Somalia: ECU 1.5 million for a measles vaccination programme and for medical and food aid for victims of the internal conflict. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Southern Sudan: ECU 13 million to finance ECHO flights, and for food, medical aid and the provision of water supplies, for civilian victims of the conflict, notably in Khartoum and its environs and in the refugee camps in the north of Uganda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Non - ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nicaragua: ECU 1.5 million for medicines, essential provisions, drinking water supply equipment and training actions in the area of epidemic prevention. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Peru: ECU 800 000 for shelters and medical assistance to people in the process of reestablishing their homes having fled from the violence that has occurred over the past ten years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ex-Yugoslavia: ECU 102 million for various emergency operations. The breakdown of this aid, by country, is as follows: Bosnia-Herzegovina-ECU 77.45 million; Croatia-ECU 11.95 million; Serbia-Montenegro-ECU 12,6 million.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Russian Federation: ECU 900 000 for street children in St Petersburg and homeless people in Moscow. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Afghanistan: ECU 7 million for a coordinated aid programme covering public health measures, the provision of drinking water, hygiene and refuse collection. The aid will be directed both at the people of Kabul and at other provinces of the country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kirghizistan: ECU 3.6 million for the purchase and distribution of food. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tadilkistan: ECU 8.9 million for a food and medical programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bangladesh: ECU 300 000 to help victims of the tropical storm that struck in the middle of May. </P>
+<P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Food aid</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Angola: 15 000 tonnes of cereals, 2000 tonnes of oils and 3000 tonnes of beans amounting to a total value of ECU 20.075 million. </P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<!--
+</Section>
+</Section>
+</Section>
+</Section>
+-->
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec159e/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec159e/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec159e/metadata.xml	(revision 10506)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">The Courier - NÂ°159 - Sept- Oct 1996 Dossier Investing in People Country Reports: Mali ; Western Samoa (ec159e)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Society, Culture, Community, Woman, Youth, Population|Social sciences, sociology (works comprising several subgroups) incl. participatory research and training</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Development Periodicals and Magazines|The Courier ACP 1990 - 1996 Africa-Caribbean-Pacific - European Union</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">EC Courier</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec160e/ec160e.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec160e/ec160e.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec160e/ec160e.htm	(revision 10506)
@@ -0,0 +1,2777 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; The Courier - N°160 - Nov - Dec 1996 - Dossier Habitat - Country reports: Fiji , Tonga</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">The Courier - N°160 - Nov - Dec 1996 - Dossier Habitat - Country reports: Fiji , Tonga</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Africa - Caribbean - Pacific - European Union </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Country reports</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji is home to people of a variety of cultures but it would not be accurate to describe this Pacific island country as a 'melting pot'. Politics here are dominated by the difficult relationship between indigenous Fijians and the descendants of indentured Indian labourers brought in to work the sugar cane fields. We look at how this situation affects the economy -  which everyone acknowledges has considerable potential, and examine the prospects for ethnic rapprochement as the nation begins a 'great debase' on the future shape of its Constitution. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Tonga</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tonga appears like a haven of tranquility in a turbulent world. A society which respects hierarchies and is strongly attached to 'traditional values', it is also one of the few remaining places with a hereditary ruler who wields substantial power. But outside influences cannot be ignored altogether and nations everywhere are having to adapt to living in the 'global village'. Our report focuses on the possible consequences of this for the 'Friendly Islands' as the new millenium approaches. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Dossier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Habitat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The concept of 'habitat' conjures up different things to different people - from the right to a roof over one's head to the way in which we manage the flora and fauna of the planet. In our dossier, we consider the legacy of the United Nations 'Habitat' Conference held in Istanbul earlier this year. We also highlight some of the initiatives being taken to improve the quality of people's living environment. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Acknowledgements</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The Courier: Africa  - Caribbean - Pacific - European union</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Address: Postal address (mail only) 'The ACP-EU Courier' Commission of the European Communities 200, rue de la Loi 1049 Brussels Belgium </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Courier office address (visitors) First floor Astrid Building 1, rue de Geneve Evere- Brussels Belgium</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publisher Steffen Smidt commission of the European communities 200, rue de la Loi 1049 - Brussels (Belgium) Tel. 00-32-2-299 1111 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Director of Publications</P>
+<P ALIGN="JUSTIFY">Dominique David</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Editor</P>
+<P ALIGN="JUSTIFY">Simon Homer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Assistant editors</P>
+<P ALIGN="JUSTIFY">Augustin Oyowe</P>
+<P ALIGN="JUSTIFY">Jeanne Remacle</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Associate assistant editor</P>
+<P ALIGN="JUSTIFY">Hegel Goutier</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Journalist:</P>
+<P ALIGN="JUSTIFY">Debra Percival</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Production Manager:</P>
+<P ALIGN="JUSTIFY">Dorothy Morrissey</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Secretariat:</P>
+<P ALIGN="JUSTIFY">Carmela Peters</P>
+<P ALIGN="JUSTIFY">Fax: 299-30-02</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Circulation:</P>
+<P ALIGN="JUSTIFY">Margriet Mahy-van der Werf (299-30-1 2)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Meeting point</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Jacques Bugnicourt, Executive Secretary of Enda Tiers Monde</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main development battle must be fought in the towns and cities</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Founded in 1972, Enda Tiers Monde ('Enda' stands for 'environment and development') is one of the few large international NGOs to be based in a developing country. It has a presence in a number of states in Africa, Latin America and Asia and has been concentrating its efforts on towns and cities, in the belief that this is where deprived populations can be best assisted. Jacques Bugnicourt, who is Enda's Executive Secretary, has some strong views about what needs to be done to tackle the problem of urban deprivation. When we interviewed him at the Enda headquarters in Dakar, Senegal, we began by asking him about the history of the organisation that he heads.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - When we launched Enda, I am not sure that we had any particular goal in mind. You would have to go back to the end of the 1950s, with the war in Indochina, the approaching conflict in Algeria, the independence of countries in Africa and the last-ditch struggles of the colonial powers, notably France. It was in Paris that links were forged between activists from many Third-World countries - in particular, we all took part in the street demonstrations mounted by people from the French colonies. There were some very strong groupings like the Federation of Students from Black Africa, and its equivalents set up by students from the Maghreb, Latin America and Asia. Ten years later, in the 1970s, we could see that the independence experiment was turning sour and the hopes we vested in the actions of determined and brilliant people had come to nothing. The United Nations was becoming increasingly bureaucratic. Some of our friends and colleagues who had government posts had their hands tied, while others were in prison and were equally powerless. In addition, the communists were disappointed at not being able to apply their doctrine to local conditions. Some did, in fact, manage to achieve small-scale results locally when working at the grass-roots, but by and large, their efforts were not successful. I came to Dakar, where I taught in a United Nations institute.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A lot of people had theories. But you cannot take up the battle for the poor without the poor themselves, or for those under the yoke of colonial rule without the participation of the subjugated population. To begin with, you have to appreciate the diversity of the various peoples in developing countries, and be aware of their daily life and struggle. Cesaire wrote that you had to ask questions about the soil, about cities, about men and about the sun. Later, once you have done this, you can act.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We need to dismantle the barriers. There can be no agronomy without economics, and no economics without sociology. If you are talking about jobs in Senegal, you also must talk about jobs in Mali and Guinea - treat Africa as a whole. Another thing is that you have to stand up for yourself and not allow yourself to be manipulated by people from the developed countries. One of the major problems we have noticed is that part of Africa's elite is out of touch with the general population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These are the underlying reasons for the foundation of Enda. Nowadays, it is a non-profit-making international organisation working with various communities - an 'INGO', if you like, with the 'I' standing for 'international'. We have bases almost everywhere in the Third World, from Ho Chi Minh City to La Paz.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Is each section of Enda independent, then ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes. We took the view that there was a danger of becoming too centralised and acting like a small-scale UNICEF or UNESCO, so we decided to guard our independence very carefully. We opted for the widest-ranging autonomy possible. This has its drawbacks of course, but these are far outweighed by the advantages.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You mention drawbacks. Would it be true to say that the original enthusiasm which greeted the creation of Enda has fallen off somewhat ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That's something we are always concerned about. It is not structures which maintain cohesion, but the sharing of goals and the channelling of our actions towards the common good.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the various sections get together, we find that we have a great many things in common. But there is no good reason why those of us in Dakar should try to influence the way people work in working-class districts in Santo Domingo, for example, where they are trying to tackle problems like AIDS and unemployment. We simply tell them what we are doing here and vice versa. If you want to serve the people, you have to have a decentralised set-up. It would be wrong to deal with a problem centrally, and to do so would be against our instincts. Most of us have no particular liking for institutions. An institution must be of service in the battle, not the other way round.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· How do you guarantee cohesion in practice ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It costs a great deal to travel of course, but we do have a lot of joint programmes. For example, the cities programme includes people from Bogota, Santo Domingo, Rabat, Dakar, Ho Chi Minh City and Bombay, all working together. They meet from time to time and, when they do, it is to get down to practical work. Together, their work is, say, three-quarters practical and one quarter reflective. Nevertheless, there is ongoing tension, particularly in the relationship between overall policy and local demands. Another conflict arises between grass-roots action and reflection.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The impression one gets is that you yourself are the 'cement' between the various groups which make up Enda. Could this not be seen as a weakness which may make things difficult in the future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That's what other people say, not what I think. I try to make my presence useful and those who come after me will do the same. What really holds us together is our belief in what we are doing. It is not a question of adhering to some kind of 'monolithic' faith. We simply believe that we can be of use, recognising that there are many limitations. Let me give you a practical example. If someone involved in recycling in Bogota were to meet up with someone from a poor district in Dakar who works at the rubbish tip, they would have a great deal in common and would find it useful to compare their problems and consider practical ways of solving them together.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What are your most important activities in Senegal ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - By far the most important is the one covering the city of Dakar. As well as being a focus for the country itself, Dakar is a metropolitan centre for the entire sub-region, with influence over Bamako, Conakry, Bissau and perhaps even Praia in Cape Verde and Nouakchott in Mauritania. What happens here has repercussions in all those cities. I do not want to sound too dramatic, but the decisive factor in our destiny will be the fate of young people and the poor in the major cities. Two-thirds of these people are facing chronic problems. Those under twenty make up more than half the population and their lives are continuing to spiral down into poverty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enda should obviously be operating in those areas where it can be of most use. And in the context of towns and cities, we have completely reviewed our strategy. For some years we gave priority to the countryside. For a long time, in fact, we believed that rural development would permit a much improved urbanisation process. There was even the view that people in developed countries would not object to paying a little more for agricultural produce, because they could be certain that the money was going to those who actually grew the cotton, groundnuts, cocoa or whatever.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the last fifteen years or so, though, we have come round to the view that our actions must be directed principally at towns and cities. We found initially that there were some interesting projects involving small groups - working to improve the position of children or banding together in cooperative savings ventures. It was good, long-term work which gave results. But that is all out of date now. We have to speak in terms of much larger numbers  -  tens of thousands and not tens or hundreds. Otherwise, there is no chance of making a real difference. That is why we have considerably altered our strategy. Three years ago, approximately two thousand children were able to go to holiday camps. Most of these holidays were paid for by companies, but fewer than 10% of the beneficiaries were genuinely poor. Last year, no fewer than 10 000 children were sent away on five days' holiday -  to the coast near Dakar. Enda was involved in this programme working with 200 local cultural and sports associations. The idea was to give the children the chance to splash about in the sea, but also to use African resources to help them become full citizens and learn that our diversity is the source of our wealth. There are at least 100 000 children living in misery and many of them could end up joining the ranks of the street children. If you can give these youngsters five days holiday plus a bit of follow-up, you allow friendships to be built. It offers a brief escape from everyday reality. It may not be paradise, but it is something tangible.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another example is the tontines that have been formed into a federation. We currently have nineteen thousand women participating in these and if you bear the large family sizes in mind - there are perhaps ten people in every family - that represents a lot of people. The women pay into the tontines and the money is used, not just for the security of their immediate family, but also to help young people set themselves up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Then there is rubbish collection. Enda runs its own scheme but there are also a number of groups that have turned rubbish collection into a profession. The young people collect the rubbish and recycle it. There are about 50 000 people in the biggest district where we are involved in rubbish collection. There are also some young people in that district who are engaged in water recycling and although it only involves supplying about a hundred people at the moment, I believe this scheme will grow. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We also organise schools and are currently involved in making films for schools on the subjects of the environment, hygiene and solidarity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Enda has just opened an 'eco-centre'. If I understand it correctly, this is a showcase to promote a horizontal link between Enda's various activities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That is right. We want it to be a place of passage, meeting, exhibition, permeation and redistribution. We hope people will feel comfortable there, and that it will be a tool symbolising a new way of working. So the centre offers an experience, but we also want it to be used to promote activity. A variety of events have been organised there simultaneously - recently for example, a meeting of shoe-shiners, a gathering of teachers from a long-standing educational centre, an exhibition for the Biennial Festival of Contemporary African Art, and a local-community meeting about setting up a small production facility. Two days earlier, there was a preliminary holiday-camp meeting where the instructors got together to look at the best available teaching methods designed to make children more aware of the importance of solidarity. We believe that solidarity is essential in tackling problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So the centre has a multitude of uses, all of which contribute to the vitality of the local economy. You have to understand the crucial importance of the local economy. It responds to all the basic needs of the poorest people, who want to live their lives just like the rest of us.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You talk of depending on the local (what some would call the informal) economy to live - or at least survive. But this sector is not viewed with enthusiasm by the international authorities ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  Their policy is based on domination and fear: fear of those who accumulate assets. To see these hordes of people in the developing countries frightens them. It's a bit like the horror of the wealthy classes at the end of the nineteenth century when faced with a working class which dared to aspire to wealth. They will give to charity but are not prepared to make a long-term investment. The lack of support for the local economy stems from the fact that foreign aid is geared, first and foremost, towards major projects or emergency aid. Four or five years ago, the UN conducted a survey in 10 towns and cities in West Africa, but the results were not published because they showed that the average rate of growth of the local economy was 7.5%. So, you see, we are far from just muddling along. Great things could be achieved if only there were a change in attitude. It also requires a change of terminology. How can one justify the use of the word 'informal' and, worse still, treat the work of the poorest people and fraudulent activities under the same heading. Fraud may be formal or informal. Knowing African society as I do, I am aware that fraud is statistically more widespread amongst the prosperous and highly respected. So we must not cast stones at the little man selling socks who has no trading licence because he cannot afford one, or at the woman who sets up a stall at a school entrance without complying with the law which requires a recent certificate stating that she does not have tuberculosis. What is the bottom line here ? Must we respect the law or the people who want to live without being thieves, beggars or prostitutes ? It is unacceptable for force to lie with the law and for the majority to be cast into wretchedness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Senegal, there used to be fixed prices for milk. The World Bank protested, declaring that this was a restriction on free competition. Now we have to pay much more and many people can no longer afford to give their children-milk every day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To put it in perspective, Senegal's economy is about the same size as that of the city of Bordeaux. So we must use all the available potential. Highly qualified managers should do their job looking after the high-tech sectors. But, at the same time, we should not be driving out the poor people who are just trying to eke out a living. The informal sector creates services for a very small investment, and people also require services. Economic policy must allow society to walk on two legs, not just one. What that means is that we need a great deal of flexibility, and perhaps a complete review of the law. Contraceptive implants have to be licensed so that there are no more back-street abortions. And it must be possible for girls to attend school even if they do not have a proper birth certificate - why should they be excluded from education for want of a piece of paper. It should be possible to trade with a simple one-day ticket which people should be able to buy in post offices or cinemas. What would be wrong with that? And we should have a moratorium on a number of regulations. We need to wage war on the destitution that we are suffering and that means taking decisive measure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">ACP</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Joint Assembly begins discussions on future ACP-EU relations</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the agenda was, as usual, heavily laden with a variety of long-standing issues ranging from regional cooperation, fisheries, the cocoa content of chocolate and bananas to the situation in several ACP states (in particular Rwanda and Burundi), the future of ACP-EU relations was at the forefront of discussions at the ACP-EU Joint Assembly, which was held in Luxembourg from 23-26 September 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Opened in the presence of the Grand Duke and Grand Duchess of Luxembourg, the Assembly's general attitude was not one of speculation as to whether or not the European Union would abandon the ACP states when the Lom&eacute; IV Convention expires in the year 2000 - a feeling that was rife shortly after the signing of the revised version in Mauritius in November 1995. Instead, it was one of positive thinking and of exploring the kind of agreement that would succeed it. 'There is no question of the European Union getting out of a relationship which took decades to build', Luxembourg's Prime Minister Jean-Claude Junker, told participants in his welcoming address.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As pessimism gives way to guarded optimism, ACP-EU parliamentarians have taken an important initiative, even before the Commission's Green Paper is published, in what is bound to be a long and passionate debate. A special summit of ACP Heads of State is planned for Gabon later in 1997 to discuss the issue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Options for the future</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A general report, introduced by Mr Firmin Jean-Louis (Haiti), provided the main platform for the Joint Assembly's deliberation. Although presented too late for representatives to have the opportunity to examine it in detail, the exchange of views on the floor was wide-ranging and reflected the report's content to a considerable degree.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The report encapsulates all the ideas that have emerged so far in various fore. It analyses framework options for future ACP-EU relations  -  bilateral, regional and multilateral - and raises pertinent questions and concerns. Noting that international cooperation is increasingly dictated by economic and security considerations, and that North-South solidarity is, as a result, being pushed to the background, it regrets the fact that certain EU member states appear to indicate a preference for bilateral over multilateral cooperation. The author of the report warns that this trend would not only diminish the credibility of the Union but also its international influence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any instrument of cooperation, the report says, should take into account the different levels of development among ACP states as well as the regional vocation of many others. Its objective must be poverty eradication, sustainable economic and social development, and the harmonious integration of the ACP states into the global economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It recognises the need to secure the support of European public opinion which is largely unconvinced that EU aid to ACP states has been effective over the past 20 years. Not enough publicity; it says, has been given to its positive aspects. The report goes on to warn that solidarity and development are at stake and that the debate on the future of ACP-EU relations should not be left to politicians and technocrats. It should also involve wider civil society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Joint Assembly debate, the commitment of EU political leaders to the development of the ACP states was often called into question. Francis Wurtz (EUL-F) summed it up when he said there were worrying signs that the EU intends to downgrade its relationship with the ACP states - signs which go back to the negotiations on the Lom&eacute; IV second financial protocol, when several countries refused to increase their contributions to the 8th EDF. The EU draft budget for 1997, which he said revealed a substantial reduction in the funds allocated to the developing countries outside the Mediterranean region, provided further evidence of this. 'We must be vigilant,' he told his colleagues, 'and must not allow the Lom&eacute; Convention to be revised downwards.' Mr Wurtz agreed that greater efforts were needed to create awareness and mobilise European opinion in favour of development. The European public should know that EU development policy was not based on charity but on self-interest. 'Without Africa developing, Europe has little chance of maintaining growth in the long run.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lord Plumb (EPP-UK), the European Co-President of the Joint Assembly, admitted that it would not be easy to influence European public opinion. 'One of the roles of the Joint Assemby,' he said, however, 'must be to ensure that the peoples of Europe have confidence in the progress being made by the countries of the South. We must all help in this task of confidence-building.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Glenys Kinnock (PES-UK) urged that there should be as much participation as possible in the ongoing dialogue over future ACP-EU relations in order to bridge what she saw as 'the gap between rhetoric and reality.' Equity, she argued, should be the main objective.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACP Co-President, Sir John Kaputin (Papua New Guinea), said there was no doubt that the EU was forging closer ties with the former Eastern bloc countries at the expense of the ACPs. He pointed out, however, that the Lom&eacute; Convention had always encouraged a 'forward-looking' approach and argued that whatever succeeded the current ACP-EU relationship should be 'the most important' agreement ever.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The representative from Barbados, Dr Richard Cheltenham, was of the opinion that whatever the outcome of the discussions, efforts were needed to avoid 'chaos'. There should, for example, be no immediate abandonment of the trade preferences that ACP states had acquired. Transformation must be gradual to enable them to adjust and restructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">European Commissioner, Professor Pinheiro, chose, first of all, to underline the importance of the role of 'the state and civil society' in development. He indicated that he saw this as growing more and more in importance. This was reflected in the agreement signed in Mauritius -  an agreement which seeks to encourage the consolidation of democracy, the rule of law, good governance and transparency, and which emphasises decentralised cooperation and the role of the private sector. the Commissioner spoke about the current programming exercise, reminding the Assembly that resources were being allocated in two tranches in accordance with the provisions of the revised Convention, to take account of each ACP state's development strategy and the objectives and priorities of the Community's development policy. He revealed that only 16 ACP countries and two EU Member States had ratified the revised Convention and urged those that have not done so to accelerate the process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He welcomed the Joint Assembly's initiative in debating future ACP-EU relations. The Commission's Green Paper, he told representatives, will be published in November. He was, therefore, not in a position to enter into detailed discussions with members on the subject at this stage. He stressed, nonetheless, that the document 'will not be a blueprint for future EU strategy towards the ACP countries. It will be a discussion paper.' there were a number of key questions that needed to be addressed regarding strategy, the scope of future relations and the use of the traditional instruments of aid and trade. 'This is not to say that we should start afresh', he argued. 'We should build on what has been achieved so far, and adapt where necessary.' Professor Pinheiro was certain that whatever the outcome of the discussions, there were a number of 'unchallengeable principles' on which ACP-EU relations should continue to be based. These were: partnership, ownership by ACP countries of their development policies, security in terms of EU support and predictability of relations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New areas of concern</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This session of the Joint Assembly saw the emergence of two new areas of concern: urban development, and the effects of climate change on small island states. An initial report on the former was presented by the rapporteur, Daby Diagne (Senegal). It did not give rise to much debate. The report emphasises the pivotal role towns play in economic development and urges the Community to adopt an integrated policy on urban development (See our interview with Mr Daigne in the Dossier). The latter was the subject of a full morning hearing, involving a panel of ACP-EU experts who are closely involved with the problem. They warned of the threat posed by global warming to the survival, and even existence, of many islands in the Caribbean and the Pacific. The emission of greenhouse gases, the Assembly was told, has reached levels never before experienced (see the article which follows). Representatives agreed on the need to integrate climate change considerations into sustainable development strategies. A Working Group on the issue was set up with Karin Junker (PES-G) as general rapporteur.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cocoa and babanas</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was no avoiding the intractable problems of cocoa and bananas. On cocoa, opinions were divided as usual. There were those who felt that the Commission's proposed new directive allowing chocolate to contain vegetable oils (up to 5% of total volume) in place of cocoa butter, was reasonable. The proposal also involves a labelling system to ensure that the exact contents of the product are clearly indicated Advocates of this strategy argued that it would not only widen consumer choice but would also promote the export of shea-butter and other vegetable oils which a number of ACP countries produce. Opponents were worried that if implemented, the directive could lead to a big fall in cocoa exports and a commensurate loss of earnings for ACP cocoa producers. Magda Aelvoet (Greens-B) argued in favour of maintaining the status quo, saying that this was preferable to what was being put forward in the draft directive. She warned that the Commission propose' would almost certainly result in everyone (cocoa producers, shea-butter producers and consumers) losing out. There was no guarantee that menu facturers would choose shea-butter given that they would be free to use whatever vegetable oils they liked She was certain they would go for the cheapest substitute or even for synthetic products. Accordingly, Mrs Aelvoet proposed a 'freeze' on all proposals. This view was reflected in the resolution passed by the Assembly, which called on the Council to reject the proposed directive. It also requested the sever member countries which currently authorise the use of vegetable oil to comply gradually with the existing directive  -  which bans their use altogether.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The banana issue proved even thornier. There is a dispute at the World Trade Organisation, where the Lom&eacute; Protocol is being challenged by the United States and Latin American banana producers. Mrs Kinnock expressed anger at the fact that the arbitration panel set up by the WTO is made UP of three countries known to advocate free trade. The panel, she said, is chaired by Hong Kong - which the Organisation told her was representing the 'developing countries!' The general feeling among representatives was that the odds were stacked against the European Union and the ACPs. The Assembly passed a resolution asking the Union to stand firm in defence of the banana regime.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Democracy, human rights, peace and security</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Twenty-seven questions were addressed to the Council of Ministers and a further 28 to the Commission. More than a third of these dealt with issues relating to emergency relief operations, democracy, human rights, peace and security  -  recurring themes throughout the four-day meeting. The emphasis, in this context, was on Burundi, Rwanda, Liberia and Nigeria, all of which were considered individually under the agenda item 'the situation in ACP states'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the detailed answers given by Commissioner Pinheiro to questions on Burundi and Rwanda, the Assembly had a long session with Aldo Ajello, the EU's Special Representative to the Great Lakes. The discussion focused on efforts to restore democracy and legitimate government in Burundi, national reconciliation, and the repatriation of refugees from neighbouring countries to both Burundi and Rwanda. Mr Ajello gave members a comprehensive picture of the complex political and humanitarian situation in the region. He spoke of the sanctions imposed on Burundi by neighbouring countries and the efforts of the former Tanzania President, Julius Nyerere, to bring about dialogue and a just political settlement in Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nigeria was again in the dock. Its representative, Dada Olisa, acting Charge d'affaires at the Embassy in Brussels, gave an account of what he considered was the progress made by the Abacha regime on human rights and democracy since the Joint Assembly met in Windhoek last March. He mentioned the repeal of the decree under which Ken Saro-Wiwa and other minority activists were executed, the release of detainees and the transitional programme for a return to democracy by 1998. He pleaded for the Assembly's understanding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">His explanation cut no ice with any of the seven political groupings in the European Parliament, who came together to present a compromise draft resolution on Nigeria. They wish to see all political prisoners released immediately, and the restoration of civil and political rights, as well as a democratically elected civilian government, by the end of 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The resolution on Nigeria was again passed by secret ballot - the very last act of the session. It calls, among other things, for a total arms embargo (preventing the trade in future but also covering existing supply agreements) and for the financial assets of the Nigerian government and of members of the country's ruling councils (and of their families), to be frozen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The resolution does not differ very much from the previous one. Mrs Junker, Johanna Maij-Weggen (EPP-NL) and Mrs Kinnock all expressed disappointment that the EU Council had failed to implement this fully. However, by repeating the demand for sanctions, they said, the Assembly was sending a very strong message to the Council that it was determined to see Nigeria return to democracy as quickly as possible. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Alarm bells sound on small island states</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Climate change</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A morning session of the ACP-EU Joint Assembly was devoted to a public hearing on the effects of climate change on small island states. It was appropriate that the issue should be brought to the attention of the Assembly by Maartje van Putten (PESNL). Representing a country much of which lies below sea-level. she is familiar with the devastating effects of sea flooding. At the hearing, which was very well attended, a panel of invited ACP-EU experts was on hand to enlighten the audience on the extent of the problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although global warning has been on the international agenda for more than 10 years, the seriousness of the threat it poses to the survival of small island states is only now beginning to be taken seriously - and it might already be too late, if some of the most apocalyptic scientific predictions are to be believed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is now growing evidence that global warming is taking place. In recent years, we have experienced more extreme weather conditions - heatwaves, floods and increasingly destructive tropical storms - while there are signs that icecaps are melting and sea levels rising. The increasing incidence of malaria in Africa has been linked to these changes. And it is all happening because of the influence our style of living is having on the planet - in particular the huge emissions of greenhouse gases such as carbon dioxide and methane, from our factories, vehicles and so on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That the public hearing attracted a large audience was not only a reflection of the interest the problem is now commanding. It also symbolised the mounting international pressure for reductions in CO2 levels in the atmosphere, and for the adoption of more realistic strategies of sustainable development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel of experts comprised Dr Leonard Nurse, Manager of the Coastal Conservation Project in Barbados, Donald Stewart, Acting Director of the South Pacific Regional Environmental Programme (SPREP), Dr Robert Watson, Senior Scientific Adviser at the Environment Department of the World Bank and Chairman of the second Working Group of the Intergovernmental Panel on Climate Change (IPCC), and Neroni Slade, Vice-Chairman of the Association of Small Island States (AOSIS) and AOSIS Coordinator on Climate Change. A separate workshop on climate change was also organised on the same afternoon outside the formal Joint Assembly setting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to Dr Nurse, current estimates based on most reliable models, suggest sea level is rising at the rate of 5mm a year (the 'range of uncertainty' is between 2mm and 9mm). This is two to five times the rate experienced in the last 100 years. This rise is expected to continue beyond the year 2100 even if greenhouse gases are stabilised. The implications for small island states, particularly the low-lying ones, would be severe. 'Atolls such as Tokelau, Marshall Islands, Tuvalu and the Maldives could possibly disappear', he said. 'Major population displacement would be experienced in Micronesia, Palau, Nauru, French Polynesia, the Cook Islands and Tonga.' Meanwhile, small islands with extensive coastal plains and limited upland areas such as Barbados, the Bahamas and Antigua, 'would be highly vulnerable to social and economic disruptions', as major cities, ports and tourist facilities, industries, freshwater sources, fertile agricultural lands and even coral reefs are destroyed by typhoons and cyclones, or washed away in floods. 'Given the limitations of climate models,' Dr Nurse said, 'it is not possible to state with certainty at this stage whether there will be a change in the behaviour of tropical storms and hurricanes. However, it is highly probable that an increase in the frequency and intensity of these phenomena could occur in a 'warmer world'. One study, he claims, predicts tropical storms would have a potential destructive force at least twice what they have today.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr Watson, similarly, struck a pessimistic note when he said that the potential for irreversible damage was great. He agreed with Dr Nurse that even if we took measures now to reduce CO2 emissions, stabilisation of the situation will take centuries. He pleaded for climate change to be taken into consideration 'in our everyday decisions.' Governments must not wait for cause and effect to be established before taking action. 'It is,' he said, 'economically feasible to reduce CO2' by introducing appropriate policy measures: looking at supply of and demand for energy, resorting to new and renewable energy sources, nuclear power, etc. and ensuring more efficient land management.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The question of 'burden-sharing' in the reduction of emissions between the industrialised world and the developing countries was debated at length. It was noted, for example, that small islands states are responsible for a very small proportion of the emissions, yet they bear the brunt of the consequences. There was a general consensus that burden-sharing should be based on equity and justice.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It should be noted that the Alliance of Small Island States (which was formed during the Second World Climate Conference in 1990) has called on the industrialised world to achieve a 20% reduction in their greenhouse gas emissions by the year 2005 (The 'Toronto objective'). This, it hopes, would bring CO2 in the atmosphere down to 1990 levels. Whether this is realistic is debatable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, a number of strategy options are being closely examined by the European Commision and the Council with a view to adopting Community-wide measures to reduce emissions significantly by 2005-2010. Member States have made phasing-out proposals with targets of 5-10% by 2005, 15-20% by 2020 and 50% by 2030. This works out at an average reduction of 196 2% annually from the year 2000.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Several parliamentarians wanted to know what the Commission, in particular, had done and will do to help small ACP island states overcome the effects of climate change. It was soon discovered during the discussion that a number of African countries were equally concerned. A Commission representative referred the Assembly to the provisions in the Convention which covered global warming and the special problems of island states. Although there is no specific reference to climate change, the Commission had dealt and would continue to deal with the issue in the broader context of its environmental action. Studies, projects and programmes are being implemented in the Caribbean and Indian Ocean in particular. Furthermore, DG VIII has drawn up internal briefing papers aimed at making departments aware of the issues of climate change and the environment. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Country reports</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Fiji</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Political stability is the key to economic success</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In most of the ACP states featured in our Country Reports, the vital issues are usually economic and social ones. How is a nation with a poor natural resource base to achieve lasting development ? What can be done to improve the skills of the people? How can a vibrant private sector be created ? Can better health care be delivered and how should it be paid for? Some of these questions might well be valid for Fiji but the visiting journalist soon discovers that they are all secondary issues. For this is a country whose political system itself dominates the agenda. The fundamental issue here is the relationship between the indigenous people of Fiji and the descendants of indentured Indian labourers brought in by the British between 1879 and 1916 to work in the sugar cane fields.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji, in fact, is home to people of a variety of cultures. On the indigenous side, the majority are Melanesians but there are also some Polynesians (living on the island of Rotuma). The country even plays host to Banabans, from Kiribati, who were displaced from their homes on Ocean Island to make way for the phosphate diggers. They hold a freehold to the island of Rabi and enjoy a special self-governing status. And while the Indians form the bulk of the non-indigenous population, there are also small Chinese and European communities as well as a number of inhabitants of mixed race.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite this diversity, it would be inappropriate to describe Fiji as a melting pot. Ever since the rapid expansion of the Indian population, official policy has tended to accentuate the divisions. In the early days, it was the British who were responsible for this, although one has to be careful to avoid value judgments. The colonial administrators, it seems, were aware of the tensions that would arise by bringing in large numbers of people of a different culture, language and religion. Their eventual response was to provide guarantees for the local population, notably as regards land rights. The effect was to preserve the traditional land tenure system which was based on villages and families. At the time, it seemed a logical thing to do, but several generations on, the country now has a settled population of Indian origin (43% of the total) who have limited opportunities to own land - even though many of them work on it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As the economy has developed, each of the two main communities has found itself 'specialising' in different fields. For example, cane farmers and retailers tend to be of Indian origin while the public service has traditionally attracted more native Fijians. Significantly, the army is almost exclusively filled by indigenous people - a crucial factor in the 1987 military coup.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the political front, as Fiji moved towards independence, the idea of providing separate representation for each ethnic group also took hold. The independence constitution of 1970 reflected this with the two main communities being given parity (22 seats each) in the House of Representatives.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Shattered illusion</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there was no real assimilation between 1970 and 1987, Fiji was seen by many as a model of a successful multiracial society. It was only when the country got its first Indian-dominated administration (sustained in power by a smaller native Fijian party) that this illusion was shattered. There was a military coup led by Lieutenant-Colonel Sitiveni Rabuka, who is now the elected Prime Minister,. Shortly thereafter, Fiji became a republic (Queen Elizabeth was formerly Head of State) and in 1990, a new Constitution was adopted giving political primacy to the indigenous Fijians. Needless to say, it was a time of greatly heightened communal tension.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 1987 coup and the events that followed have been well covered elsewhere (including our previous Country Report which was published in 1991). It suffices to say here that while the last few years have been a lot less turbulent, tensions remain. In 1997, the country must adopt a new set of constitutional proposals and a big debate is currently under way about the shape of the system of government for the 21st century. This subject is covered in a later article and also features prominently in our interviews with the Prime Minister and Opposition Leader.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main focus of this article is therefore on economic and social aspects although, as one soon discovers, this frequently leads us back to the ethnic question. This is particularly the case when one considers the overall economic performance of the country. Fiji is not poor by developing nation standards and it has enjoyed modest growth during 1995 and 1996, but there is a widespread view that it could be doing a great deal better were it not for the political uncertainties. The problem is summed up by the Economic Intelligence Unit in its Fiji Country Report for the first quarter of 1996: 'Political instability will continue to deter investment, other than that on highly favourable tax terms.' In other words, Fiji is paying a high economic price for its internal difficulties.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General unease about the future and, in particular, the outcome of the constitutional review process is compounded by specific concerns over land tenure. The long-term leases granted to (mainly Indian) farmers are approaching their end and the government must soon decide what it should do next. Will any of the sugar cane farmers be evicted and if so, how many ? What alternative arrangements will be made for them? These questions remained to be answered when The Courier visited Fiji in July although, as our keynote interviews show, the subject was clearly exercising the minds of the politicians.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A long-term strategy for agriculture?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The way in which the land question is dealt with will have a crucial impact on the sugar industry - still the country's most important product in terms of its contribution to GDP and the jobs that it generates (see the article entitled 'Sugar definitely has a future'). With other uncertainties facing this sector - in particular, the process of global liberalisation - there is a growing recognition of the need for a long-term strategy. The government has a two-pronged approach  -  improving efficiency within the sector and diversifying into other agricultural products. To learn more about this, we spoke to Luke Ratuvuki, who is the Permanent Secretary for Agriculture, Fisheries and Forests.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Ratuvuki began by stressing the scope for increasing the sugar yield per hectare by as much as 75% (and by even more with irrigation). If productivity could be boosted on this scale, Fiji sugar would be in a much better position to compete in open world markets. He admitted, however, that the country would still face a struggle in maintaining market share and, looking ahead ten years, foresaw a slimmed down industry providing high quality sugar with more of a focus on niche markets. This inevitably meant looking at other agricultural products as possible long-term substitutes. The coconut (or as the Permanent Secretary dubbed it, 'the tree of life') is traditionally grown here and seems poised to enjoy a new lease of life following a period of decline. Fiji has also picked up the taro trade at the expense of Western Samoa, which is affected by taro blight, while there are significant exports of ginger to Australia, New Zealand, Canada and Europe. Mr Ratuvuki spoke enthusiastically about branching out into other areas such as pawpaws, mangoes, bananas and aubergines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji has potential for growth in a range of non-agricultural sectors, but farming is sure to play a vital part in the economy for many years to come. Currently, sugar represents almost three quarters of all crops by value (excluding subsistence growing) and the Fijians are only too aware that this makes the country particularly vulnerable to external shocks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The other primary sectors are all present in Fiji, albeit on a more modest scale. There is some deep-sea fishing backed by Asian investors. This provides useful employment although perhaps not the best possible financial return to the country. As one would expect in a nation of three hundred islands, there is also extensive artisanal and subsistence fishing in the inshore areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The forestry sector divides into two parts: artificial softwood plantations which are said to be managed sustainably and the naturally growing hardwoods. As regards the latter, the EU is helping with a mapping project. Although Asian loggers do not operate in Fiji, there is considerable land clearance taking place, leading to problems of erosion and silting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prospects for mining</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gold is the main mineral being exploited with important deposits around Vatukoula. The sector has had its ups and downs but the Emperor Gold Mining Company has now embarked on an expansion project aimed at raising production from the current level of about 4000 kilos per annum to 6000 kilos by the year 2000. A huge copper and gold mine is also planned for Namosi, some 35 km from Suva. Other minerals discovered but not exploited include bauxite, iron, lead, zinc, phosphates and marble. Mining currently makes a modest contribution to overall GDP but represents an important component in the export earnings figures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With one key exception, manufacturing is on a fairly small scale with an emphasis on staple items (butter, beer, soft drinks, paint, soap etc.) for the local market. The exception is the garment industry which provides some 20% of the country's export income and a considerable amount of employment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The investments in garment manufacturing and mining have been important in jobs terms and in improving the trade figures, but there are those who criticise the fact that the government appears to derive little revenue from the operations. The exact fiscal benefits are not easy to determine, prompting some observers to suggest that official secrecy should be eased (see the article on the Constitutional Review later in this Country Report).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the service sector, long-term growth is foreseen in the key area of tourism. The number of holidaymakers choosing Fiji dipped sharply at the time of the coup, illustrating the importance of political stability in attracting visitors. Tourist arrivals bounced back once Fiji's internal difficulties had receded from the international headlines. The politicians must be hoping that nothing will occur during the current period of constitutional discussion and negotiation to put Fiji back on the front pages. It is worth mentioning here that Fiji's national carrier, Air Pacific, is an example of a relatively rare bird - an airline that makes money ! According to journalist Avin Rahish, writing in the July 1996 issue of The Review (the news and business magazine of Fiji): 'It is one of the few government investments that is profitable on its own.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If tourism is a success story, there is something of a shadow over the financial services sector, which is more extensive here than in most developing countries. The reason is the collapse last year of the National Bank of Fiji with losses of US$ 142m (equivalent to 10% of the annual GDP). The authorities were accused of a failure in supervision and the taxpayers have had to pick up some of the bill. More serious, however, is the undermining of confidence in the system and it will take time for this to be restored.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social challenges</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">As a middle-income country, Fiji has relatively favourable social indicators in the areas of health and education. Medical facilities are provided by the government but it is said that the public health system is not as good as it once was. This is attributed, among other things, to the emigration of highly qualified staff in the aftermath of the events of 1987. Nonetheless, the country does have 27 hospitals and one doctor for approximately every 1900 people. At 72 years, life expectancy is high compared to the ACP average.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The education sector is well-developed with more than 800 primary and secondary schools (for a population of less than 800 000) and 41 technical or vocational institutions. As a result, primary school enrolment is close to 100% while the 1986 census revealed that 60% of 15-year olds were still in education. On the other hand, there are concerns over the proportion of teachers lacking qualifications, notably in the primary school system. In practice, there is considerable racial segregation at both primary and secondary levels, although there is no official policy to this effect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Educationally, the jewel in the crown is almost certainly the University of the South Pacific whose main campus is in Suva. This regional institution, which has departments in a number of other countries of the South Pacific, draws students from various island nations. Dr Vijay Naidu, who is the USP's Pro-Vice Chancellor, outlined some of the special features of this unique university which has to cater for a highly dispersed population. Like traditional tertiary institutions, it provides a wide range of degree programmes on campus, catering for 3500 students. It has a further 9000 who are being educated using the 'distance mode'. Distance learning is organised through centres in each of the participating countries. Students can attend these centres from time to time but much of their work is done through radio and telephone linkages and, increasingly nowadays, by e-mail and satellite communications. The University, Dr Naidu stressed, also provides continuing education at non-degree level 'in everything from computing to basket-weaving'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Like the health sector, the USP suffered a loss of highly qualified staff after 1987  -  and not just among employees of Indian origin. As the Pro-Vice Chancellor pointed out, the coup created 'a new sense of insecurity' all round and teachers who decided to emigrate were quickly accepted in Australia and New Zealand. The loss has been particularly serious in the scientific disciplines.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">90% of the USP's recurrent expenditure is covered by member government contributions with the remainder coming from Australia and New Zealand. For capital investments, there is heavy reliance on external donors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In both of Fiji's main ethnic communities, a strong commitment to the family ensures that there is relatively little absolute poverty although things may be changing as the country become more urbanised. It is rare to see beggars in the streets in the South Pacific but Suva, sadly, has a number of these.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The overall picture is of a country with very considerable potential in both human and natural resource terms which needs to overcome a number of challenges to secure a more prosperous future. Some of these challenges - adapting to the world of free markets, tackling bureaucratic impediments, bringing development to rural villages, improving the infrastructure, and so on - are familiar to all developing countries. The single most important constraint, however, is the big ethnic divide, and the political uncertainty which flows from this. And this is something which can only be solved by the people of Fiji themselves. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Interview with Prime Minister Sitiveni Rabuka</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'The last ten years have been very educational for me'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is almost ten years since Sitiveni Rabuka led the military coup which toppled the newly-electerl coalition government The stormy events of 1987 are long gast end Fiji has returned to more peaceful ways, but the country is arguably not yet at peace with itself. Major-General Rabuka is now the erected Prime Minister, having led the SVT to victory at the polls in 1992 and 1994. But the gulf between the native Fijians end citizens of Indian descent remains -  indeed, it is institutionalised in a political system which ensures a parliamentary majority for the former. A constitutional review is currently under way end a new text must tee adopted by July 1997. For both sides, the stakes are high. In this interview, Prime Minister Rabuka speaks frankly about the crucial issues facing Fiji as the nation gears up for the great constitutional debate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji also faces some formidable economic challenges and we began by asking the Prime Minister about these.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The main challenge is the one that everybody faces: achieving an acceptable rate of growth to ensure job creation and address the unemployment problem. We also want to improve the standard of living of the people, to upgrade our infrastructure, and to develop both the urban and rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What sectors do you see as offering the best hope for future growth ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  We are looking particularly at tourism and the agro-based industries. In the international sphere, we are aiming to boost trade, particularly with our traditional trading partners, Australia and New Zealand, and with new partners that we are trying to cultivate in Asia.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We are very grateful for the Lom&eacute; Convention and the various arrangements associated with it - particularly as regards access to the EU market for our sugar products. Although it would be desirable for us not to have to rely on preferential pricing for sugar, for the moment, there is no alternative. And while we are looking for alternatives and seeking to diversify our economy, we will need that system to remain in place. We would like to continue the dialogue to ensure that this happens. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the area of trade, as I say, our focus is on Australia and New Zealand, and the regional trade agreement that the Pacific island territories have with them. This agreement is currently under review. One important aspect is the clause governing the rules of origin. If we can convince Australia and New Zealand to reduce the local input requirement from 50% to 35%, then we won't need any aid from them. The effect will be to secure existing jobs and, indeed, to increase employment, particularly in the garment industry. At the moment, most of the textiles we import for further processing come from Australia. Because of the market we have to sell to, it is very good quality material. This means the costs are high, in comparison with the local input needed to turn it into finished products, and this makes it difficult for us to get up to the required 50%.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If we don't get that reduction, things could go in the opposite direction. Manufacturers might relocate and we could be facing jobs losses. You have to remember that we are competing with Asian producers who have very low wage costs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Is this proposal for a reduction in the local input requirement on the agenda with the Australians and New Zealanders ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The review actually excludes the clause on the rules of origin. Having said this, we have effectively raised the calculation of our local input in negotiations on a series of other points. On paper, the 50% figure is unchanged but in fact, there has been a reduction of about 5%, thus giving us a little margin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· On the sugar issue you said you were hopeful that some form of preferential access to the EU market would be maintained. Isn't there a concern that this may not last beyond the year 2000, particularly given the increasingly liberal world trading system ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, and we are looking at that. We should be gearing ourselves up for what happens at the end of the current Lom&eacute; agreement. It remains to be seen whether, with the WTO and the new trends, the curtain will suddenly be brought down on 1 January 2000, or whether there will be a grace period in which we are given time to consolidate our diversification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The other big issue in the sugar sector concerns the impending expiry of the land leases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That is a local issue and a very important one. It has high priority on our government agenda. We are currently talking to the landowners and lessees, explaining what will happen. The legislation (the Agricultural Landlord and Tenant Act) makes no provision for further extensions to the leases, which are now nearing their end. Do we need a new act or should we amend the present law to allow extensions beyond the 50 years originally allowed for ? And if we are to do that, what happens to the compensation provisions? At the moment, these are viewed in a rather one-sided way. The emphasis is on the situation where the landlord compensates the tenant for improvements made to the land. But the rules also provide for compensation in the other direction where the value has been reduced. This may be due to constant cultivation over 50 years. What if the owner wants to return the land to its original use, planting taro, yams or cassava, as his father may have done fifty years ago, and finds he can no longer do so ? There has to be a balancing act here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hopefully, most of the land will be leased again under a new agreement or under an amendment to the existing law - because we will need to continue sugar production. It is also worth noting that some sugar farmers are beginning to diversify into other crops, both subsistence and commercial.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What arrangements do you envisage for those farmers who do not have their leases renewed ? Will they be relocated ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Right now, we are looking at the use of state land. There are two basic categories here - what used to be known as 'Crown Land under Schedule A' and 'Crown Land under Schedule B'. Schedule A covers the land not claimed by anybody during the Commission that was set up to determine the ownership of land in the very early colonial years. Schedule B is land that belonged to a community or landholding unit that has since died out: in other words, where there is no surviving member of the land-owning unit. So we have those parcels of land available. My party's policy is to restore land to the traditional owners where possible, but in those cases where you cannot identify the original owners, there will be land available for resettlement - although resettlement is perhaps not a very good term to use. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· It is somewhat emotive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It implies taking a person, family or community from somewhere and planting them somewhere else -  and I hope we can avoid that. On the other hand, if you look at what people are doing nowadays, everybody's relocating. People are always resettling, moving away from home and setting up elsewhere. In this case it is perhaps a necessity, in the sense that the legislation has caught up with us. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Can I turn now to the sensitive issue of the constitution. This is another area where decision day is looming. You currently have a constitutional review under way with the Commission's report due out soon. What do you think will emerge from this process over the next 12-18 months ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I don't feel that the constitutional issue is a sensitive one and do not think anyone should feel restrained in asking questions about it. It reflects the reality of the situation in Fiji. There is a requirement that the 1990 Constitution be reviewed and we have a Review Commission chaired by Sir Paul Reeves. He is a very capable man who is a former Governor-General of New Zealand and a very eminent constitutional lawyer. Assisting him, we have two party nominees - one from the main Fijian party and one nominated jointly by the Indian parties in Parliament. I have total confidence in that Commission. I believe they will come up with very objective observations and recommendations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let me explain the timetable to you. The report is expected by the end of August. It will be presented first to the President and then to me for submission to Cabinet. I envisage it being tabled in Parliament towards the end of September. We cannot debate it until three months have elapsed from the date it was tabled - which takes us to the end of the year. A lot of work will be needed during the first half of 1997. The Joint Parliamentary Select Committee, made up of members of both the upper and lower houses, will have to work on the report and try and build consensus on the various issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given that the house is racially divided, and the possibility that a premature discussion on the floor of the house may raise the temperature, I would prefer not to have a full parliamentary sitting in the early part of next year. Instead, we should go into committee and deal with it there. And then when we are satisfied that the issues can be brought out into the open, we will debate them fully in Parliament. As soon as we start talking next year, the legislative craftsmen should begin their work. On the basis of this programme, I believe we can meet the deadline to the day, promulgating a new Constitution which has been accepted by both houses on 25 July 1997. So I am very hopeful.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Without prejudging the final outcome, do you envisage a move away from strict communal separation ? I am thinking here, in particular, of the separate voting lists ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think there may be provision for some cross-communal voting. There was something like this in the 1970 Constitution which had both communal and national rolls.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What about the longer term. Do you foresee a political system developing in Fiji where ethnic origin is irrelevant -  perhaps a 'right-left' divide, if that is still a meaningful concept ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I am not bold enough to say that that will happen. I have seen the darkest side of Fijian nationalism. I have seen the fear that was in the Indian population in 1987. But if we move too quickly to remove the racial safeguards that are in the Constitution, we may run the risk of prolonging the bad relationship between the races that we now have. So I would say we should proceed very cautiously and let the natural healing process take its course. We also need to look beyond the Constitution at aspects such as our education system and enhancing the ability of the Fijians to compete.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· I believe the education system is also very divided.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Some schools are reserved for Fijians although, slowly, there are Indians from families close to the schools who are beginning to enter them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think that this is a promising sign for the future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think so. I went to a purely Fijian school and when I came out of that, everything was Fijian for me. I went straight into the army which is another Fijian-dominated institution. It was not planned that way. It is just the way it happened. My tolerance level of other races was very low. But you cannot expect somebody who gets to this level of leadership to have a low racial tolerance level. I must admit that the last ten years have been very, very educational for me - very good for my own being. I consider what I used to think before and the way I used to feel before. I have never been threatened by an Indian, but I had always been in Fijian 'safe' areas - a Fijian school and then in the army. But since coming out of that sort of cocoon, I have managed very well to accept that I have to compete with them, I have to look after them, and I have to devise policies and programmes that will be good for them as well as being good for us.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· One final question. Do you envisage Fiji seeking to rejoin the Commonwealth in the near future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think seeking is the wrong word. We will do what we feel is good for Fiji and its people. The people of Fiji are those who are here now but it will include some of those who have moved on looking for greener pastures and who are willing to come back. We were not expelled from the Commonwealth; our membership lapsed. It is up to the Commonwealth to say whether they are prepared to reconsider our member ship. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Profile</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Area: 18 272 km². Fiji has two main islands (Viti Levu and Vanua Levu) and about 300 smaller ones. It has an Exclusive Economic Zone of approximately 1.3 million km²). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population: 790 000</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population density: 43 per kilometre² </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capital: Suva (situated on the island of Viti Levu) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Main languaqes: English, Bauan </P>
+<P ALIGN="JUSTIFY">(main Fijian language)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Currency: Fiji dollar (F$). In June 1996, 1 ECU was worth approximately F$ 1.80. (US$1 = F$ 1.40) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p15.png"></center><br>
+ Fiji</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Politics</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">System of government: A bicameral parliamentary system consisting of an appointed Senate and an elected House of Representatives. The President is a non-executive head of state chosen by the Great Council of Chiefs. The President appoints the Prime Minister. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under the Constitution, adopted in 1990, the Parliament is divided along racial lines. The Senate has 34 members, 24 of whom are indigenous Fijians. In the 70-member House of Representatives, 37 seats are reserved for native Fijians, 27 for Indo-Fijians, 5 for 'general voters' (other ethnic groups) and 1 for Rotuma Island (whose inhabitants are Polynesian). The 1990 Constitution provides for a review within seven years and discussions are currently under way with a view to amending the Constitution by the 1997 deadline.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">President: Ratu Sir Kamisese Mara</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister: Major General Sitiveni Rabuka </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Main political parties: Soqosoqo ni Vakavulewa ni Taukei (SVT - Fijian), National Federation Party (NFP  -  Indian), Fiji Labour Party (FLP - Indian),  Fijian Association (FA - Fijian), General Voters Party (GVP).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Party representation in Parliament (1994 election result): SVT 31, NFP 20, FLP 7, FA 5, GVP 4, Others 3. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economy</P>
+<P ALIGN="JUSTIFY">GDP: (1995) F$ 2.85 billion</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Annual GDP per capita: approx US$ 2600 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GDP growth rate (1995): 2.2% (2.9% predicted for 1996) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Principal exports (1994): Sugar (US$ 182m), Garments (US$ 96m), Gold (US$ 43m), Fish (US$ 38m), Timber (US$ 21 m) Main trading partners (in order of importance):</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Exports - Australia, UK, USA, Japan, New Zealand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Imports - Australia, New Zealand, USA, Japan, Singapore.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade balance (1994): exports - US$ 547m, imports - US$ 826, deficit - US$ 279m. The current account figures also usually reveal a deficit but this is much smaller due to tourism earnings and official transfers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inflation rate (1995): 2.2%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Government budget (1996): revenue -  F$ 759m, expenditure  -  F$ 851 m, deficit - F$92 (about 3.5% of GDP) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Forma/sector employment: 98 112 (out of a total economically active population of about 265 000) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social indicators</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy at birth (1993): 71.6 years </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adult literacy (1993): 90.6%</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Enrolment in education: all levels from age 6-23: 79% </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Human Development Index rating: 0.853 (47th out of 174) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sources: Economic Intelligence Unit, UNDP Human Development Report, 1996, EC Commission. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">An interview with opposition leader Jai Ram Reddy</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'We need to move to a more racially neutral system'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji is not unique in having a political system that is heavily influenced by racial or communel issues In places as diverse as Northern Ireland, Belgium, Guyana and Trinidad - not to mention many parts of Africa - people vote for parties which claim to represent the particular ethnic, religious or linguistic group to which they belong. Where Fiji is different, however, is in having a Constitution that gives primacy to one particular community. Since the 1987 coup, native Fijians have held the upper hand with a guaranteed majority in Parliament and a firm grip on the levers or power.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 1990 Constitution, adopted when communal feelings were still running high, contained a requirement for a constitutional review within seven years. When The Courier visited Fiji (July 19961 the work of a three-member Commission appointed to carry out the review and make recormmendations was nearing completion. All sides seem to accept the need for reforms designed to help bridge the sharp racial divide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The big question is how radical these reforms are likely to be. We sought the views of Jai Ram Reddy, the leader of the opposition National Federation Party (NFP) which has the support of most of the country's Indian (Indo-Fijian) community.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You are the first opposition leader I have met who cannot, constitutionally, become Prime Minister. How do you feel about that ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is something that rankles with me - the mere thought that I am not equal with my fellow citizens of other races. I think that's generally the way the Indians feel here. All the constraints and limitations, the denial of basic human rights, are the source of a great deal of unhappiness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You talk about basic human rights. Obviously, the political aspects are very important but I get the impression that, in other respects, this is a fairly free and easy society: there is free expression, for example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, but free expression is only one aspect of human rights. The fact is that discrimination based on race is widespread and institutionalised. About 45% of the population is Indo-Fijian but you will find they are not fairly represented in the higher levels of the public service. At the Permanent Secretary level, there is definitely a government policy to have a limited number of Indians - and there are hardly any in the more crucial ministries. The same is true of managerial positions throughout the public sector. In the statutory bodies and major public undertakings, there is a deliberate policy of excluding Indians. So we are very much a marginalised community in the public sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Wouldn't it be true to say that Indians have quite a lot of economic power ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - No, I don't agree. There is a tendency for people who come here, end for some people in Fiji, to project this image of Indians controlling the economy. It is a fallacy. It all boils down to how you define economic power.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let's take natural resources. The land, and therefore the forests, are almost exclusively owned and controlled by native Fijians. Even in the corporate sector, the largest business undertaking is the manufacture of sugar, and 80% of the shares are owned by the government. The Indians don't own this industry. They are the small sugar cane producers working on ten-acre plots. And who controls banking and insurance ? Certainly not the Indians. Most of the financial services companies are foreign-owned.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The area where the Indians are most visible is in the retail sector. But those little shops you see in the towns are small family businesses. The shopkeepers work up to 15 hours a day, and you will discover that many of them do not even own their premises; they are tenants. So the idea that Indians control the economy is a bit of a myth. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The Constitution, and in particular the system of racial differentiation for voting and holding certain offices, is obviously a key issue for you. With the Constitution currently under review, what is your party's policy in this area ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The first elections under the current Constitution took place in 1992 and we took part in them under protest. We made clear that our participation should not be construed as acceptance of the system. Indeed, the sole issue on which we campaigned was our rejection of the Constitution. But we accepted the fact that we needed to get into the system as it was, and to try and create an environment where there would be widespread appreciation that it had to change. The 1990 text, in fact, laid down that it had to be reviewed by the seventh anniversary of its promulgation. I think the architects of the Constitution realised themselves that it was deficient. And we laid great emphasis on the need for dialogue; a general recognition that the country would be much better off with everybody working together and that there was nothing to be gained by oppressing or marginalising a community. And that is the kind of environment we have tried to create.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The Constitutional review will shortly be published. What do you hope will come out of that exercise ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I am reasonably optimistic. I think the environment is more favourable now and there is a general recognition that the system has to change. I am sure you will get confirmation of this when you talk to the government side. We need to move away from this very polarised, compartmentalised political system to a more racially neutral one. I think views may diverge as to how far we should go. That will be the contentious issue. But I believe we will make progress.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I certainly think we will get a good report from the Constitutional Review Commission. One of our fears, when we started on this journey, was whether it would be independent and be given fair terms of reference. Largely because of the cooperative and accommodating attitude that we ourselves adopted, and to which the government responded, we were able to get a Commission that was well-balanced. We are very fortunate to have Sir Paul Reeves, a former Governor-General of New Zealand. His independence is taken for granted. The Commission also has one nominee from the indigenous side and one from the Indo-Fijian side. So we certainly expect a good report. There is already a kind of acceptance I think on all sides that political parties need to prepare themselves for a more multiracial approach to governance in the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· On this point, I see that the SVT (the governing party) is looking at the idea of opening up its membership to other groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - That's right.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think there will be many nonnative Fijians interested in joining ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Not straight away but at least it is a beginning. It is an acceptance that they can't remain racially exclusive. If, for example, the Commission recommends a move toward a racially neutral system - at least for a certain number of seats - then it would be important for the SVT to have non-Fijians in their party.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Can I turn to economic issues, which I presume cannot be divorced altogether from political ones ? There is a lot of discussion about the future of the sugar industry which is tied in with the question of renewing the land leases This is an issue which is due to be resolved soon. How concerned are you about the impending decision on the leases ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - This is something that concerns us very deeply. As you correctly observe, you can't separate the political and economic aspects. The two are very closely interlinked here - perhaps more so than in other countries - because of the land situation. The bulk of Indian peasant farmers, both within and outside the sugar industry, are on leases that will begin to expire next year. If these are not renewed, the problem will not just be an economic one but an enormous human one. What do we do with these people who all belong to a particular racial group. It really boils down to our very survival. Despite the growth in the towns, the bulk of the people are still rurally based. They are small subsistence farmers, living in the country areas with no more than 10 or 12 acres to cultivate. So the social implications of non-renewal in terms of poverty, dispossession and hardship are enormous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· But how real is the concern ? Surely, the overwhelming economic logic is for the leases to be renewed. After all the land is being put to productive use at the moment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  Yes, but unfortunately, when you have a communal dimension to the problem, logic does not always prevail. If you think about it, there was no logic in the events of 1987. The trouble is that every issue here has a racial twist. After the coup, communal sentiments were aroused and sharpened. There was a prolonged period of anti-lndian propaganda and in that environment of anger, a highly racial constitution was adopted. There were people in positions of influence openly advocating non-renewal, threatening to take all the land back. Now they need to undo all this and it will not be easy, given the enormous strength of feeling that has been aroused. Having said this, I believe that we are now in the process of restoring sanity to our public life. It is also beginning to dawn on everybody that the sugar industry is vital for Fiji and it will continue to be so for some years to come.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· I have heard that view expressed on all sides, but I wonder if people are sufficiently aware of the implications of global liberalisation. It has been suggested that this will make sugar increasingly unviable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think a lot of people are unaware of the implications, because there has been very little public education in this field. But amongst those 'in the know', there is certainly an appreciation. I am a member of the Parliamentary Select Committee on Sugar and we were recently addressed by the head of the marketing company and the head of the Sugar Commission. At that level, there is an awareness, but if you speak to the average farmer who has been growing and selling sugar for many years, he will probably assume that life will just go on as before.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Isn't it true to say that sugar depends heavily on the Lom&eacute; Convention arrangement with the European Community ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Very much so. In my view, the sugar industry is run so inefficiently that but for the huge subsidy we get from the European Community, it would not be viable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Presumably, this means that measures must be taken to improve efficiency ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, absolutely. But the first issue to resolve is the land question.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is no point talking to the farmers about efficiency  -  asking them to improve their husbandry and focus on sugar content rather than the quantity of cane produced - when they don't know if they will have land to cultivate after next year. So you see all other issues have become completely subsidiary to the tenure question. At the moment, we are in a limbo. The government and the people urgently need to resolve this problem. Then we can put it behind us and address the other concerns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Are there any other economic sectors which you feel offer promise for the future of the country ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  Any growth outside of tourism will, I think, have to be centred on the agricultural sector. We need more agro-based industries and more diversification. We could grow a lot of other crops here - mangoes for example. We also need to improve extension services to farmers, and make an aggressive effort to identify markets. The farmers will grow the crops but they must be sure that somebody will buy them. Every year, for example, we have a glut of tomatoes - so many that they can't even give them away in the markets. This kind of problem kills the incentive to produce.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is obviously heavy state involvement in the running of agriculture. Do you see scope for more privatisation or 'corporatisation' in line with global trends ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think that growth, even in the agricultural sector has to be private-sector driven. At the same time, you have got to create the right environment and infrastructure for this to happen. Unfortunately, it keeps coming back to this question of land. If big investors, for instance, want to come here and invest in agriculture, they need to know what sort of tenure they are going to get and whether they can buy the freehold. I am sure there are people, particularly now from the Asian region, who would be interested in investing in agriculture, but the land problem is a big constraint.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Do you think Fiji will rejoin the Commonwealth at any point ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Well, we hope so. You know we are all very strongly in favour of rejoining. One of the things that I personally feel very strongly about is the unfortunate severance of our link with the Queen. I don't know, constitutionally, whether it can be restored. Obviously, there are difficulties in that area, but I think a large majority of ordinary people in this country would like at least to see Fiji back in the Commonwealth. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Seeking a lasting constitutional settlement</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When The Courier visited Fiji in July, the report of the Constitutional Review Commission headed by Sir Paul Reeves (former Governor-General of New Zealand) had not yet been completed  -  and what it would contain was a major topic of speculation. As readers will see from the interview we publish with the Prime Minister and Opposition Leader, the impartiality of the three-member Commission was not in question  -  at least within the political mainstream on both the native Fijian and Indian sides. Nonetheless, there were doubts about whether a consensus could be found. For the Indo-Fijians, a scaling down of the 'racial' features in the Constitution was seen as a prerequisite. Yet the ruling SVT, in its own submissions to the Commission, had effectively supported the status quo. In view of this apparently unbridgeable gulf, could the compilers of the Report come up with recommendations capable of forming the basis for a lasting constitutional settlement ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The long-awaited Report was formally transmitted to President Ratu Mara on 6 September and a few days later, it was tabled to a joint session of the Senate and the House of Representatives. It now falls to a joint select committee of the two Houses to thrash out a new set of constitutional proposals. These will be presented to Parliament for debate and decision in the first half of next year with a view to meeting the July 1997 deadline foreseen in the 1990 Constitution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Report of the Review Commission is lengthy (almost 800 pages) and contains no fewer than 697 separate recommendations. The key ones, however, relate to the system for electing members of the House of Representatives. Currently, separate electoral lists based on race are used to fill all 70 seats (37 native Fijians, 27 Indo-Fijians, 1 Rotuman and 5 'General Electors', covering all other races). It was widely expected that the Commission would propose a mixture of 'reserve' seats and 'open' ones, with the latter, as their name implies, being chosen by the whole electorate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">45 'open' seats proposed</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is precisely what they have done - but the suggested breakdown may have come as a surprise to some. The proposal is for 45 open seats (15 three-member constituencies) and 25 single-member 'reserve seats (12 native Fijian, 10 Indo-Fijian, 1 Rotuman and 2 'General Electors'). If adopted, the new system would no longer legally guarantee a majority for people of Fijian origin in the country's legislature. What would happen in practice would depend on a number of factors including the nature of the voting system in the three member open constituencies, the willingness of people to cast their ballots across the ethnic divide and the actual turnout of voters from the different communities. It should be pointed out, however, that native Fijians now constitute half the population, large numbers of Indians having emigrated over the past nine years. So long as communal voting patterns persist, this will presumably be reflected in the Parliamentary arithmetic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is also proposed that the bulk of the 35-member Senate (Bose e Cake) should be made up of elected representatives of Fiji's provinces. In the field of local government, it is suggested that the present system based on villages and provinces, which applies only to native Fijians, might be replaced by an arrangement applicable to all races. In this context, the rote of the Council of Chiefs (Bose Levu Vakaturaga) would be reduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the sections of the Report relating to representation are bound to attract most attention, the Commission also put forward a series of other proposals aimed at improving the governance of Fiji. One idea, which appears designed to alter the political culture, is for the 'Official Secrets Act' to be replaced by a 'Freedom of Information Act'. The presumption of secrecy would be replaced by a rule that official information should be accessible to the public except where there is good reason to withhold it. In a similar vein, the Report recommends an 'integrity code' to govern the behaviour of holders of public office.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Initial reactions to the outcome of the Commission's work were mixed. Key players, including the President, Prime Minister and opposition spokespersons broadly welcomed the Report but more nationalistic elements were quick to reject it and one group even mounted a ceremonial burning of the document.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is obvious that a great many more words will be exchanged - and some of them will no doubt be heated  - in the coming months. It is difficult to see how everyone can be 'brought on board' but the hope must be that a compromise can be crafted that is acceptable to the majority on both sides of the communal divide. The people of this Pacific island nation are well aware that prosperity and stability go hand in hand. The single most important achievement in ensuring stability for the longer term would be to secure a satisfactory settlement of the constitutional issue. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">'Sugar definitely has a future'</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was the key sentiment expressed by Isimeli Bose, Fiji's Trade Minister, when he spoke to The Courier earlier this year. Mr Bose insisted that 'no matter what anybody says, sugar will be the backbone of this country's economy for years to come.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When we discussed Fiji's current economic situation and future prospects with the Minister, it was not surprising that sugar should have featured so prominently. The sector faces a difficult future for both internal and external reasons. At home, the long-term leases granted to the farmers (mainly Fiji Indians) under the Agricultural Landlord and Tenant Act are due to expire over the next few years. No provision was made for their renewal and the resulting uncertainty has provoked widespread concern, not least among the leaseholders themselves. The external 'threat' comes from new international trade rules administered by the World Trade Organisation. At present, Fiji's sugar industry is heavily dependent on the preferential access to the EU market which was granted under the Lom&eacute; Sugar Protocol. No one is quite sure what will happen when Lom&eacute; IV expires at the turn of the century but it is clear that the stakes are high.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mr Bose was quick to acknowledge the importance of ending the uncertainty facing the sugar farmers. 'But the real challenge', he said, 'is to ensure the maintenance of our markets for sugar.' He was aware of the encroachment of global trade liberalisation but stressed that the industry's leaders and the government were 'doing the work now and planning for the future.' At the same time, the authorities are clearly hoping that the European Union will be able to continue with some form of preferential arrangement after the year 2000, if only to buy time so that the industry can adapt and farmers can diversify.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the subject of trade diversification, Mr Bose pointed out that 'the field is very limited'. He continued; 'However, since 1988, we have seen garment production picking up from very humble beginnings. By 1995, we had about F$185 million-worth of exports in this area.' He also spoke enthusiastically about the government policy of encouraging manufacturing in tax-free factories and zones. 'This developed well between 1989 and 1992 and then there was something of a slowdown.' Tax-free factories have been established in a number of locations and the first real tax-free zone is now being set up in Kalabo. Mr Bose indicated that EU assistance was being provided in this area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Privatisation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Our conversation then turned to the changing economic role of governments - throughout the world, they are withdrawing from active involvement in industrial and commercial operations. We asked how far this process had occurred in Fiji and, in particular, whether there was a privatisation policy. The Minister replied in the affirmative, pointing out that government departments 'do not usually make very good businesspeople.' The policy, therefore, was to 'corporatise' and 'privatise', although the process is still in its early stages. The Trade and Commerce Ministry has a public enterprise unit which is responsible for drawing up a policy framework for the government. In 1995, Mr Bose explained, a public enterprise bill was presented to Parliament, 'but there were so many concerns expressed to the previous Minister that it was referred to a select committee -  which, in fact was chaired by me before I took up my present poet.' The committee had now completed its work and the Minister indicated that the issue would go back to Parliament in September.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the legislative delay, Mr Bose was keen to stress that his department was already working on individual programmes. The post and telecoms business, for example, had just gone through another stage towards privatisation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is, of course, an important distinction between 'corporatisation' and 'privatisation' - the former implies staying within the state sector but at arms-length from the administration. This point was acknowledged by our interviewee who explained that the approach was a step-by-step one. The first stage was to reorganise a department along commercial lines. Corporatisation came next 'and then finally you have privatisation by disposing of shares.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He stressed that the most important aim was to ensure an element of competition wherever possible. 'There is no point simply moving from a government monopoly to a private monopoly', he insisted, 'although obviously, there are utilities like water, electricity and even telephones where this may not be easy.' The minister concluded; 'Where they are natural monopolies, we will regulate them.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Our final topic of discussion was the possibility of regional integration in the Pacific.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How far had the South Pacific countries gone in this direction and did the Minister think there was a need for closer economic cooperation? Mr Bose replied that he thought economic integration was a good thing. He pointed to a document on his desk containing a draft proposal for a bilateral trade agreement with Papua New Guinea. 'We will soon be holding negotiations with them, and have also just signed an agreement with Tonga.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The focus on bilateral trade arrangements at this stage suggests that the region still has some way to go on the regional integration path.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But the Minister nonetheless insisted that it was something 'that can and will happen'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Our daily bread - courtesy of a remarkable Fijian businesswoman</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How can a businesswomen succeed in Fiji's patriarchal society? Mere Samisoni, the entrepreneur behind the 'Hotbread Kitchen' gave us an appropriate answer when she said 'I roll with it', although the pun was probably unintentional In fact, it is difficult to imagine this dynamic lady being pushed around. Anybody who manages to build up a chain of bakeries from scratch, capturing 35% of the country's urban consumer market in the process, must have a lot of determination. At the same time, Mrs Samisoni displays a strong sense of social commitment. She believes in community values, advocates group decision-making and consensus, and even describes the tax system as 'reasonably fair'. In short, she contradicts the widely-held view propagated by lurid American TV series, that a dogeat-dog attitude is needed for business success.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact, Mrs Samisoni started out with the idea of working with one of the caring professions. Trained in nursing administration in Australia and New Zealand, she returned to Fiji only to find that there were no openings available. That was when she decided to go into the private sector, establishing 'Samisoni Enterprises'. And over the years, she has succeeded in building up one of the largest bread-making operations in the country. The Hotbread Kitchen operation is highly decentralised with the bread being baked in different locations for sale through the company's local outlets. Her business is also the first Fijian one to franchise out its operations. And having already won a big chunk of the urban market, she is now looking to expand operations in the rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Samisoni Enterprises, of course, is not simply a bread-making operation. The company now offers a line of 62 separate bakery products, with some local adaptations to suit varying tastes. It employs some 275 staff with perhaps another 50 working in the related franchise operations. And the business had an important breakthrough when it won the contract for 'MacDonalds' in Nadi. With branches of the famous hamburger chain likely to open in other parts of Fiji, this could be the start of something big. In fact, there is even a suggestion that Fiji could be used to source Macdonalds' operations in New Zealand, the rolls (or buns, as the Americans like to call them) being exported frozen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Constant quality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For Mrs Samisoni, the key to a successful and profitable operation is 'constant quality' and unfailing attention to customer service. As she puts its, 'if you let quality slip just once, you can end up losing customers for a very long time.' Baking is a labour-intensive business and she is keen to stress the importance of developing people's abilities - in particular, the human relaitons skills of those who deal direct with the customer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As if running a business wasn't enough, Mere Samisoni is also busy completing a Masters in Business Administration (MBA) at the University of the South Pacific, with a thesis on indigenous business. From what we discovered, speaking to this remarkable Fijian entrepreneur, she should have been helping to teach the course! </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Viti Levu - island of contrasts</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Anyone from overseas who is travelling to the Fijian capital, Suva, will soon discover that the country's largest island is a very diverse place. Roughly circular in shape, Viti Levu provides more than half of Fiji's total land area and is home to about three-quarters of the population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The journey to Suva on the south-east coast will almost certainly involve transiting through Nadi International Airport (pronounced Nandi) which is situated in the west. This is the country's only major international gateway and while it is ideal for tourists heading for the resort hotels, it is less convenient for business travellers whose destination is Suva. Their journey has to be completed either by road (which takes several hours) or on one of the small commuter planes which ply regularly between Nadi and Nausori (itself a half-hour drive from the capital).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The biggest surprise to those who are unfamiliar with the country is that the west and the south-east have very different weather patterns. When your aircraft lands at Nadi, the chances are high that the sun will be shining. On reaching Suva, you are more likely to encounter rain. This part of the country enjoys - if that is the correct term - a micro-climate which is good for tropical vegetation but less appealing to human beings. The 'blame' for locating the Fijian capital in such a spot is said (not too seriously) to lie with the country's former colonial rulers. According to the story, a British envoy visited Suva on one of its rare sunny days and, on the strength of this, designated it as the seat of administration. The British can hardly deny their involvement since it was in 1882, during the early years of colonial rule, that the capital moved from Levuka (situated on the much smaller island of Ovalau). But the key reason was almost certainly the fact that Suva, with its large bay, could be developed as a port. Whatever the explanation, one must have some sympathy with the foreign diplomats who keep a raincoat or umbrella to hand at all times, and yet are viewed with envy back home because they have a 'paradise' posting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To be fair, Suva has attributes other than its weather which make it an interesting place. It has, for example, some very attractive architecture, both local and colonial. The views across the bay can be dramatic - and, in this respect, the rolling cloud formations may actually enhance the picture. And the centre of the city buzzes with activity (except on Sunday because of the Sabbatarian influence).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The population of the greater Suva area is about 160 000. This may not be enormous, but it is the largest concentration of humanity to be found between Hawaii and Australia. In some ways, it is the 'capital' of the South Pacific - a point which is underlined by the fact that the Forum Secretariat is based here. It is also the site of the University of the South Pacific's main campus. The local population is mainly ethnic Fijian but there are Indo-Fijians as well as citizens of Chinese and European extraction. Add to this the diplomatic corps, foreign businesspeople and students from other parts of the region, and you get a very cosmopolitan mix. This is reflected in the variety of cuisines available in the local restaurants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The western part of Viti Levu is also cosmopolitan but in a very different way, with a stronger Indian influence and, of course, a constantly changing tourist population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most of the island's inhabitants live a relatively short distance from the sea. Thus, in demographic terms, Viti Levu is like a doughnut with a thick layer of humanity around the edge and a hole in the middle. The analogy may not be entirely apt since the 'hole' is, in fact, a spectacular mountainous area. This makes the road that runs round the island a key arterial route. Meanwhile, those who choose to fly from Nadi to Suva, assuming they are not of a nervous disosition, can enjoy the experience of travelling below the height of the surrounding peaks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The few people who do occupy the central region live in traditional Fijian villages and have a lifestyle far removed from either the town dwellers or the sugar cane farmers. Its size may be little more than ten thousand square kiLom&eacute;tres but Viti Levu is truly an island of contrasts. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Fiji-EU cooperation: comprehensive package</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Ernst Kroner</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji was a signatory of the first Lom&eacute; Convention in 1975 and, to date, the country has been allocated some ECU 190m in EU development cooperation funds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Starting with a relatively modest ECU 9.9m under Lom&eacute; I, the national indicative programme rose to ECU 13m under the following Convention. Without neglecting rural development (feeder roads in Vanua Levu), under Lom&eacute; I most of the resources were devoted to transport infrastructure (a main road on Vanua Levu). Under Lom&eacute; 11, cooperation concentrated clearly on agriculture and rural development, in particular by means of the funding of microprojects, with infrastructural programmes (the extension of the Vanua Levu road, social infrastructure) taking second place. Under this Convention, a new field of action was also addressed: trade development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tax free zone</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade development was addressed further under Lom&eacute; III (6th EDF, ECU 20m, of which ECU 5m in special loans), with support given to an Investment and Trade Development Programme. The longer-term objective of the project was to widen the economic base of Fiji and to create employment. The more immediate objective was the i establishment of a Tax Free Zone near Suva. In order to promote this scheme and to secure markets for exporting the goods which would eventually be produced, the project included a programme of trade and investment promotion to be implemented by the Fiji Trade and Investment Board. Due to problems linked with identifying an appropriate site, the project, which had been given the go-ahead in 1990, only came on stream in 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rural and agricultural development continued to be one of the main sectors of cooperation, with the funding of three major projects. The first was a coconut rehabilitation and development project, situated on the island of Taveuni, which aimed at improving the productivity of coconut plantations through the introduction and multiplication of high yield hybrids. The project also provided for the establishment of a 30 hectare coconut nursery centre, which was expected to finance itself through the sales of seedlings. EC support for this project ended in 1992, since when the scheme has been taken over by the Government. A second project (a large-scale microprogramme divided into two sub-programmes) aimed on the one hand at the construction of access roads to facilitate the development of cocoa plantations, and on the other at the introduction and development of pineapple plantations in Vanua Levu. The first component was closed after disappointing results. The second component, however, produced very interesting and promising results, which will, however, need private and governmental support in order to become sustainable. A rural electrification project involving 28 rural electrification schemes and the supply and installation of a small power plant is still ongoing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Developing human resources</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under Lom&eacute; III, the formerly prominent transport infrastructure sector lost some importance. The Kubulau Peninsula road project on Vanua Levu brought to an end the work started under previous Conventions. This road, which filled the last gap in the circuminsular road, was opened on in July 1994. Lom&eacute; III also saw the beginning of human resources development as a new theme of cooperation, with Technical Assistance funded for the logging school. This area, embodying strong links with forestry and environmental issues, has been further developed under Lom&eacute; IV with the reconstruction of the school burnt down in 1993, and the enlargement of the training and education provided to what now constitutes a Forest Training Centre.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The national indicative programme relating to the first protocol of Lom&eacute; IV (7th EDF, ECU 22m in grant aid) identifies rural development and social infrastructure as the sectors of concentration to which 65% of resources are to be devoted. The remaining 35% will be used for non-focal activities, including trade and services, tourism, cultural cooperation, training and technical cooperation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Building bridges</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately, it was only following the very destructive cyclone Kina in January 1993 that cooperation activities could start in the form of the rebuilding of four bridges either severely damaged or completely destroyed by the post-cyclone floods.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Work on two smaller bridges of major importance to Viti Levu (Korovou and Vunidawa, ECU 1.135m) was started in 1994 by the Public Works Department and completed in January 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Financing Agreement for the two major bridges (ECU 10.24m) was signed in June 1994 and provides for the rebuilding of the bridges of Ba and Sigatoka. These form part of the main road around the island of Viti Levu and are therefore vital for the movement of people and goods on Fiji's main island. The new bridges, 190 and 182 metres long respectively, will be two-lane, and will provide for footpaths and utilities. To enable the traffic to by-pass the often congested towns of Ba and Sigatoka, new sites for both bridges have been chosen, which also call for the building of new approach roads. Building works were under way in early 1996 and completion is expected by April 1997.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Non programmable aid for Fiji has been considerable over the years. While Stabex transfers for losses on coconut oil (totalling ECU 5.4m under Lom&eacute; I - Lom&eacute; III) came to a halt under Lom&eacute; IV (because levels of exports fell below the required dependency threshold), emergency aid (total ECU 9.5m) has continued, unfortunately, to be needed. Time and again the islands have been hit by cyclones (the most recent occasion being in January 1993, when the EU made available ECU 1 m for food rations following cyclone Kina).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the past, a significant feature of EU-Fiji cooperation was the credits provided by the European Investment Bank. It was very active under Lom&eacute; I to Lom&eacute; III, providing loans from its own resources to a total value of ECU 87.5m with a further ECU 6.1 m allocated in risk capital. Loans went to the energy sector (hydropower scheme), industry (wood processing) and services (telecommunications, sea and air transport). Considerable interest rate subsidies (totalling ECU 14.1m) have also been made available under the various EDFs in support of these loans. More recently, the EIB has financed an aircraft maintenance centre (1991) and a telecommunications project (1995).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Trade cooperation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over and above financial cooperation, Fiji benefits from the second largest quota (165348 tonnes per annum) under the Sugar Protocol annexed to the Lom&eacute; Conventions. This covers some 45% of its total sugar exports. The yearly benefit from this provision is estimated at between ECU 45m and ECU 55m - in other words, only slightly less than the total of all programme aid granted since Lom&eacute; I (ECU 64.9m). About two-thirds of these benefits reach the farmers, so that the EU subsidises every sugar smallholder, on average, to the extent of some ECU 1500 a year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recently, Fiji's quota under the Sugar Protocol was increased by 881 tonnes, as a result of the reallocation of the shortfall of deliveries by Barbados. Furthermore, Fiji benefits from an annual special tariff quota to the tune of some 30 000 tonnes up to the year 2001.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Industrial development and external trade have been supported by the relaxation of the rules of origin for exports to the EU of canned tuna to the extent of 500 tonnes a year from 1993 to 1996. A similar arrangement, applicable for certain quantities of garments up the end of 1993 was recently extended to the end of 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fiji's main exports to the EU (sugar, fish and garments) - and the resulting surplus in its trade relations with the EU - are consequently highly dependent upon the continuity of these preferences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Support for tourism</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the field of services, and specifically in tourism, the EU - through its support of the Tourism Council of the South Pacific - has contributed to the fact that every sixth tourist or so arriving in Fiji comes from a member country of the Union. Tourism being by far Fiji's most important source of foreign exchange earnings, receipts from European tourists amount at present to some ECU 30m, and are greater than those from the export of fish and fish products</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Taking the Sugar Protocol into consideration, the EU is by far the most important of Fiji's development partners, followed by Australia. The country also benefits from bilateral cooperation arrangements with EU Member States (UK, France, Germany). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Tonga</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Hoping to maintain harmony</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'None of the most civilised nations have ever exceeded these islanders in the great order and regularity maintained on every occasion, in ready and submissive compliance with the commands of their chiefs, and the perfect harmony that subsists among all ranks.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These were the words of Captain Cook who visited the Tonga archipelago several times on his voyages around the world in the eighteenth century. The famous explorer was obviously impressed by the social organisation of this island nation and, although it is more than two centuries since he undertook his Pacific voyages, many of his observations hold true today. Talk of submissive compliance may no longer be appropriate, but in contrast to the turbulence of much of the outside world, Tonga certainly ranks as a peaceful society, which is respectful of hierarchies and strongly attached to 'traditional values'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The reference to harmony is particularly apposite, as The Courier discovered when we visited Tonga earlier this year. It was fortunate that our trip coincided with the King's birthday celebrations and we had the opportunity to enjoy the superb choral music which plays a central part in many important ceremonies here. Like their Polynesian cousins in Western Samoa (featured in our last issue), the Tongans seem to have a natural flair for music and a talent for spontaneous harmony. The question is whether these 'Friendly Islands' - a name they certainly deserve  -  can maintain their reputation for social harmony into the third millenium.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In order to answer this, one has to identify where discordant notes could creep in. The biggest challenge appears to come from the process of globalisation. New technologies, particularly in the field of communications, are rapidly breaking down barriers. The tide of the international economic system, with its emphasis on mass production, con sumerism and free trade, is lapping at the islands' shores And political systems everywhere are under pressure to con form to a 'democratic' model which some would argue places the individual above the community. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of course, external influences can be both positive and negative Cultural exchanges can be enriching, and new ideas and techniques may offer opportunities for improving the quality of life. The key is to adapt without undermining the social fabric. And in Tonga, as in other countries, a harmonious future will ultimately depend on the way the country evolves both politically and economically.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Looking first at the current political set-up in Tonga, one cannot fault the use of the term constitutional monarchy which is the preferred description locally. It is important, however, to recognise that the constitution - which dates back to 1875 - gives considerable power to the monarchy. There is a measure of democracy in that all adults over 21 have a vote, but they only elect nine of the 30 Members of Parliament A further nine are chosen by the country's 30+ nobles while the twelve Cabinet Ministers, who sit in the House ex officio are nominated by the King. Tonga may' be small (it has fewer than 100 000 inhabitants) but it nonetheless attract: the interest of political scientists as one of the few remaining states with a hereditary ruler who wields substantial power.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Critics of the system view it as an anachronism, although their emphasis is on reform rather than revolutionary change. Defenders argue that the arrangement works well in a small, homogenous nation which values its unique culture and traditions (even if the constitution contains many 'British' elements). The latter also point, with some justification, to the attitude of the population. There are dissenting voices but the majority appears to be happy with the existing set-up, thereby lending it democratic legitimacy  -  at least indirectly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There may not, at present, be any overwhelming demand for constitutional reform but things can change. In particular, a people's view of their political system and how it might evolve is likely to be influenced by the prevailing economic conditions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic outlook</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tonga's economy is not exactly booming with the most recent estimates suggesting a 2% GDP drop in 1995-96. Several of the traditional problems faced by developing countries are to be found writ large here. The local market is not just small but tiny by global standards, and this makes it exceptionally difficult to achieve economies of scale. There is heavy demand for imported manufactured items and few viable export opportunities to balance the equation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The education system compares favourably with those of other developing nations but the pool is so small that Tonga inevitably suffers from human resource shortages. This is exacerbated by a steady 'brain drain'. Qualified Tongans, who may already have experienced life abroad at college or university, are tempted by a range of attractions including higher salaries, better housing and more extensive career prospects. The skills shortage is particularly severe in the medical profession. In a recent issue of Matangi Tonga (the 'national news magazine'), it was reported that the country would only have one anaesthetist by 1997 - with a local doctor observing wryly that there was no need for one since the main hospital's only specialist surgeon had recently left to take up a post abroad.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although it would be better for Tonga to retain its qualified people, the fact that the country 'exports' labour does have its positive side. Tongans have a strong sense of family and community, and overseas workers send significant amounts of money back home. This injection of 'foreign' funds boosts the local economy and reduces the overall balance of payments deficit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agriculture is by far the most important economic sector, with most crops being grown for local consumption. The islands benefit from a fertile soil and a tropical climate, allowing the cultivation of a wide variety of fruit and vegetables. All land is vested in the Crown, with estates allocated to the nobles. By law, each adult male is also supposed to be allotted three hectares although there is not enough land to go round. Despite this difficulty, which means that some people do not receive their allocation, the result is that most Tongans are involved in farming. The advantage of the arrangement is that it guarantees a living for the bulk of the population even if their cash income is low. On the other hand, it is obviously a feudal system which favours the upper echelons of Tongan society. In addition, it tends to hinder the development of larger units which could benefit from economies of scale. While anxious to make farming more efficient (and export-oriented), the government currently has no plans to introduce land reform.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In export terms, the main crop is squash (pumpkins). Production increased dramatically in the early 1990s when a market niche was identified in Japan and it soon became the country's biggest foreign exchange-earner. More recently, income has been depressed, with overproduction in 1994 leading to a drop in prices, and poor rainfall the following year reducing yields. The November export figures for the last three years (November is the month when squash deliveries peak) illustrate the extent of Tonga's reliance on this single product. In November 1993, the country's overall export income was T$15m - more than half of the annual total. Twelve months later, the figure had dropped to T$9m and last year, it fell below T$6m. When The Courier visited Tonga, the authorities were talking about limiting the amount of squash exported to Japan this year to 15 000 tonnes, in the hope of maintaining premium prices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government is also acutely aware of the risks of mono-dependence and is looking for other outlets for its agricultural produce. Demand for copra, Tonga's traditional export, has apparently been reviving, but the price has not been high enough to attract local farmers back into the market. Other crops sold abroad include vanilla, cocoa, coffee, black pepper and ginger.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One farmer who is doing his bit in the quest for export diversification is Masao Soakai, a former general manager of the Copra Board. He is now the managing director of a company that specialises in the import and export of produce. This energetic 73 year-old gave us a guided tour of the plots he had rented. He cultivates an astonishing range of different crops which include potatoes (for Fiji), cassava, taro, yams, carrots, broccoli, cauliflowers, strawberries, bananas and capsicums. He also rears cattle and pigs (a Tongan tradition). Masao Soakai stresses the importance of rotation in maintaining yields and believes strongly in planting for the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other sectors</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wherever you happen to be in Tonga, the Pacific Ocean is never far away. Evidence of the country's maritime tradition can be found in accounts of the appropriately named William Mariner (see box article on this page). But while, in the past, Tongan vessels sailed far and wide, and the country has a huge exclusive economic zone (EEZ), the fishing industry is relatively undeveloped. The sector generates about 5% of GDP. A project sponsored jointly by the FAO and the UNDP revealed that there was considerable scope for expansion, both in the inshore and reef zones and in the deep sea area. The main species which could be exploited commercially are albacore, skipjack and yellowfin tuna. Tonga has received assistance to develop its fisheries from the USA and Japan, and the government has offered tax advantages in the hope of promoting investment, but there is still a long way to go before the country realises its full potential in this area. Hitherto, the country has not licensed foreign vessels to fish in its waters but there is talk of this policy changing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tourism could also generate a lot more income although it currently faces a number of infrastructural and practical constraints. The government is committed to expanding the sector but Mrs Papiloa Bloomlield Foliaki, the owner and manager of Nuku'alofa's third largest hotel (the 'Friendly Islander') feels that a lot more could be done. She pointed out to The Courier that a healthy tourist sector would provide employment as well as stimulating new business for food producers, builders and craft industries. She focused, in particular, on deficiencies in training and marketing, and suggested that some of the resources allocated to agriculture might be better spent in tackling these.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tonga's natural assets make it a 'dream' location for visitors looking for a complete change of scene - particularly if they happen to be keen on sailing, snorkelling or scuba diving. The problem is that the country is so far off the beaten track that it is expensive to get to (some would see this as an advantage in deterring mass tourism). Nothing much can be done to change this but it does mean that they have to aim at the upper end of the market. This requires top quality accommodation  -  of which there is a distinct shortage at the moment. As regards marketing, Mrs Foliaki was hopeful that the recent formation of a hotel association would enable the Tongan tourist industry to raise its profile abroad. Despite her optimism - echoed by all those we spoke to in official circles - the latest figures for visitor arrivals show a downturn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the manufacturing sector, the story is, sadly, one of long term decline. Clothing production ceased in 1994 and the output of leather items has been falling. There are very few industrial activities in which Tonga has a comparative advantage (whether actual, or potential) and this is something which is recognised locally. There may be some scope for adding value to agricultural products through processing but it is unlikely that industry will take off in a big way in the foreseeable future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sale of passports (see the interview with Prime Minister Baron Vaea) is an issue which attracted publicity - not all of it favourable - some years ago, when the government launched the TPPP (Tonga Protected Person's Passport). This was designed to be a travel document which did not confer the right of residence in the country. The authorities adopted the scheme with an eye firmly on Hong Kong, a British colony which is due to be transferred to China in 1997. Some passports were sold but the project never really took off as the immigration authorities of other countries refused to accept the document. Now there are suggestions that the idea may be revived, although this time involving normal passports.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The foregoing survey of Tonga's economy does not paint a particularly happy picture but it should be stressed that there is very little real poverty in the islands. In many ways, the informal economy is more important, and subsistence agriculture and fishing ensure that people do not go hungry. With their traditional family structures and strong attachment to the Christian faith, the Tongans have not yet encountered many of the social problems associated with more consumption-oriented societies. But to paraphrase a famous saying, 'no nation is an island' nowadays - even if it happens to be surrounded by water! In an era of increasing globalisation, the key question is how to manage change. Let us hope that the people of Tonga can find the right answer. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Interview, Prime Minister Baron Vaea</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Constrained by our geography'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">No-one can accuse Tonga's Prime Minister of being a starry-yed optimist. As the following interview reveals, Baron Vaea, who heads a twelve-member ministerial team, is refreshingly honest about the economic difficulties facing his small island country. The Courier interviewed him in July, at his office in Nuku'alofa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You have suffered a GDP drop and a general slowdown of activity in recent years. What is the government doing to restore the situation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is true that the economy has been declining. The main cause is the excessive demand from the private sector for imports from New Zealand and Australia, combined with diminishing exports. Our exports fell when the price of copra dropped. Another problem is New Zealand's quarantine rules. New Zealand is very particular on quarantine against insects, notably fruit flies, which may damage their own export trade. We have endeavoured to balance this out by selling squash to Japan and indeed, it has been a saviour as far as our economy is concerned. Squash is something our farmers know how to grow. Of course, the market goes up and down. Recently, we made the mistake of over-producing and quite a lot of the crop could not be sold abroad. I think our farmers are now realising this, and that they have to plant according to the quota that we ourselves have imposed. Tourism is another important area although levels of room occupancy are very dependent</P>
+<P ALIGN="JUSTIFY">on the economic situation in other countries. Then there are passport sales.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Is this something you are still doing ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, but it has been hit by technical difficulties. A number of Hong Kong Chinese bought our Tongan Protected Persons Passport (TPPP) in the hope that they could travel. The immigration authorities in other countries decided they would not accept the document so this source of income dried up. We have changed to national passports which people can use to travel. We are hoping to revive this in order to suit the conditions of the Hong Kong people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Is this being done on the assumption that the people who purchase such a passport would not ultimately settle here ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes. The main reason people in Hong Kong want a passport is to keep open the option of leaving after the changeover.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Has this policy prompted any criticism from other countries ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - No. The main problem is the Chinese themselves who are due to take over Hong Kong next year. It is possible that they will not recognise these passports. We are planning to have discussions with the Chinese on this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Going back to the agricultural sector, are you not putting too many eggs in one basket in focusing so heavily on squash. What efforts are you making to diversify ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - We have just signed a trade agreement with Fiji. They are such a close neighbour yet we have had virtually no trade with them. This should change with the agreement, to the benefit of our economy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What products are we talking about here ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Mainly vegetables, particularly those that are favoured by the Indian community, such as chills and spices. A trade mission has just returned from Fiji where they picked up a number of orders. The representative of a group of growers also recently returned from Japan. He took a sample of dried pawpaw, a crop which is popular with the Japanese, and apparently received an excellent response. This is an area which is promising.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The key issue, however, is the amount of space available in the aeroplane. You can't ask everyone to grow pawpaw when the airline tells us that they can only take eight tonnes at a time. Only a limited number of farmers can be involved, so that we can continue to supply the tonnage that the airline can handle. We will encourage the rest of the farmers to concentrate on other products.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What is your policy regarding foreign investment ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - We encourage overseas investors to engage in activities that local people are not involved in. Land leases are available for anything they want to do which fits in with this policy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tonga has an extremely limited manufacturing sector and there appears to have been a long-term decline. What prospects are there for reversing this trend ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - For many years, the policy of the government has been to encourage exports. We have had entrepreneurs here who have exported things like woollen garments, small boats, horse saddles and so on - but it didn't last. The sad fact is that hardy anything is exported from Tonga. The main reason is that we are constrained by our geography. We are so far away from the main markets. The raw materials have to be brought in and by the time the article is finished, there is no way that it can compete in price terms. This has always been our problem. We are always looking for new markets but it is not easy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A second limitation is the private sector in Tonga. This is weak in terms of technology, marketing and product quality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What about further processing of local products - perhaps value-added agricultural activity ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, this is something that we would hope to do, though the same kinds of problem arise. People don't set up the processing plant because they say there isn't enough local cultivation to make it worthwhile. And the farmers don't grow the crop because they say there is no market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· So it is 'chicken and egg' situation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes. The result is that people only grow for home consumption.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I should mention here that there are other resources we have yet to exploit, notably in our waters. We have reserved these for ourselves and do not allow foreign fishing vessels. So we are trying to recover resources from the sea.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is also the possibility of drilling for oil. Research ships operating in the Pacific have found a limited number of locations where it would be worth looking for oil reserves and two of them are in our waters. We have been publicising this with a view to encouraging further exploration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· This would presumably involve drilling licences for oil multinationals.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes. Some companies have done this in the past although only on a small scale. The answer we got from the oil companies is that they are interested in exploitation - but not now because of the low oil price. When the price goes up, I think we may attract interest again but that is clearly only a long term possibility.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· A lot of young Tongans leave the islands to work overseas. What is the explanation for this ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is true that a high percentage of our population migrates. These are people in search of a better life, who seek to reap the benefits of their abilities by working overseas. They can have a nice house and get a good education for their children.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I should stress that we have a good education system here but there is a heavy emphasis on gaining qualifications in order to get into the civil service. Where we are lacking is in the field of technical education. We have some facilities of course - an Institute of Science and Technology and a Marine Institute to train people to go to sea. This is very much in its infancy and we hope it will help for the future. But even some who have gone through this system end up looking for jobs overseas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Turning to political issues, you have a monarchy here which is still very powerful. Do you anticipate any changes in the system ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - There has been some public pressure for change. I don't think people want a radical upheaval but there is a feeling in certain quarters that the present system could be improved upon. As you probably know, Parliament has nine members elected by the people and a further nine selected by the 28 nobles from among their own number. The third component is the government -  12 ministers who are appointed by the King. It has been suggested that qualified people who don't presently sit in Parliament should be there to help deal with the economy. One idea is to change the Constitution so that whole population elects 30 members. The King would then choose his ministers from these 30.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Has this idea made any headway ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  No, not so far. We are maintaining the old system. The proposal has been aired but it hasn't been passed in the House. There are a lot of people, I think, who prefer the present system because they feel the monarchy works for the benefit of all the people. Would a new team necessarily stick to this principle? There must be a danger that they would tend to favour just one section of the population.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Can you comment, finally, on Tonga' relations with its partners in development cooperation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - As you know, we have good relations with the EU through the Lom&eacute; Convention. We also have strong bilateral links with Australia and New Zealand which have been giving us assistance. But I think we have to face up to the fact that the aid cannot continue. The UK, for example, used to provide us with our judges. That has been taken over by Australia and New Zealand -  but for how long ? I think it is bound to be phased out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So we will continue to have relations with our partners, but we need to recognise that they are concentrating their efforts now and adapt accordingly. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Profile</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">General information</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Area: 669 km². Tonga has about 170 small islands and four main island groups (Tongatapu, Ha'apai, Vava'u and the Niuas). It has an Exclusive Economic Zone of approximately 700 000 km,). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Capital: Nuku'alofa (situated on Tongatapu) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population: 99 000 (1994 census) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population density: 149 per kilometre² </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy at birth (1992): 68 years Official languages: Tongan and English Currency: Pa'anga (T$) made up of 100 seniti. The currency is pegged to the Australian dollar. In September 1996, 1 ECU was worth T$ 1.57 (US$1 T$ 1.22)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p32.png"></center><br>
+ Tonga</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Polities</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">System of government: Constitutional monarchy based on the Constitution promulgated in 1875. Considerable powers remain vested in the King. The Parliament has 31 members  -  the Speaker, 12 ministers (including the Governors of Vava'u and Ha'apai) who are appointed by the King, 9 nobles chosen by the 33 members of the nobility and 9 People's Representatives elected by universal suffrage. There are no political parties although there has been talk of setting up a 'people's Party'. The twelve cabinet ministers hold office until they reach retirement age.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Head of State: King Taufa'ahau Tupou IV</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prime Minister: Baron Vaea of Houma</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economy (estimated 1995 figures unless otherwise stated) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Annual GDP per capita: approx US $1900</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">GDP growth rate: -2% (1995/96)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Principal exports: squash, vanilla, manufactured goods and fish. In the early 1990s, squash accounted for more than half the country's total export income. In 1995, however, the harvest was affected by drought and exports dropped significantly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Balance of payments: A trade deficit of US $38.8m (exports  -  US $18.3m, imports  -  US $57.1 m). The current account deficit is much smaller thanks to 'invisible' earnings, notably from tourism and remittances from Tongans living overseas. Inflation rate (April 1995): 4.5%. Total external debt: T$ 44m (1993)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sources: Tonga in Profile (on the Internet -  http: 11l www. netstorage. com/kami/ tonga) Economic Intelligence Unit Country Report 1996. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Interview with peoples representative, Teisina Fuko</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'There is much more political awareness'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">People's representative, Teisina Fuko offers an alternative view</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While Tonga has no political parties, and the main levers of power remain in the hands of the monarch, it would be a mistake to conclude that there is no questioning of the status quo in this small Pacific kingdom. As The Courier discovered on its recent visit, Tongans are happy to speak openly about their political system and to criticise (or praise) aspects of it me local media may not be particularly extensive but it nonetheless allowe for different viewpoints to be expressed, including criticism of the authorities. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Those who advocate political reforms in Tonga face something of an uphill struggle. There is no overwhelming demand for change and although the lever of popular support for the current system is not easy to judge, there appears to be widespread acquiescence  -  which effectively amounts to the same thing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years, the focus of 'opposition' has tended to be within the ranks of the people's representatives who sit in Parliament We spoke to one of these elected members, Teisina Fuko, who comes from the Ha'apai island group and began by asking how democratic the thought the system was.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I would say about 50%. Up until the 1970s, the system was very traditional but we now seem to be westernising quite quickly. People are returning from overseas with different ideas and this is having an impact on the way we are governed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think you will ultimately have a Parliament whose members are all elected by universal franchise ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I would say it is more certain now than ever before. There is much more political awareness. We see it in the schools, where children are being taught to think independently. There are also the new economic trends -  commercialisation and the focus on foreign earnings which imply the need for modernisation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You sound quite enthusiastic about the 'westernisation' process. Are you not concerned about the possible negative aspects in terms of the survival of your traditional culture ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think we have to strike a balance. We mustn't go to extremes. Our culture and traditions are important but there are new things we need to take on board and some old habits we should drop. Take business opportunities: we have to be more democratic in this area. If one group has all the power then they will tend to favour their friends which isn't necessarily efficient. What it boils down to is a lack of checks and balances.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the present economic difficulties, I also think we need to move quite quickly. I recently wrote an article arguing that the King should transfer his power to appoint ministers to the people. Ministers should be elected so that they can be accountable to the taxpayer. We are a close-knit family here and there is no question of getting rid of the monarchy. But we need to sit down and hammer out a compromise which will allow us to improve our economy and make it more competitive.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Let me give you a practical example. Defence is now third on our list of priorities. That doesn't make sense to me. We would be better spending the money on economic development. We also need to boost the private sector so it can create jobs, instead of tying its hands. At present, 50% of our revenue goes on paying civil servants. What for 7 It may create employment, but it is not productive. So the government has to be minimised. Having said this, there are some positive signs. I am glad, for example, to see new blood being brought into the ministerial team.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Parliament is currently composed of three groups - twelve ministers, nine nobles and nine people's representatives. On paper, that suggests that no group can dominate ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">- Yes, but the ministers and nobles often work together and we are  outvoted. It is difficult to imagine the nobles saying 'no' to the King although, to be fair, they do sometimes abstain and some of them recognise the need for certain reforms to the system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Turning to the economy, which areas do you think offer the best development prospects ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">-  Tonga's potential lies in fishing. We are an island nation that has always depended on the resources of the sea and we have the necessary labour force. What the people need is the know-how  -  advanced technologies to develop this sector. We also have to set up credit programmes so that people can invest in boats and equipment. I believe we should spend a lot more on fishing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unfortunately the government does not take the same view. It has put a lot of resources into small industries, airlines and so on. Yet the reality is that these sectors are in decline. Manufacturing has fallen and so have agricultural exports. Fishing is the only sector that is expanding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· What about the prospects for agriculture ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think we have reached the limit in this sector. There is very little scope for expansion. I also believe we should be concentrating on what we can produce to use locally. There is very little more we can do in terms of commercial exploitation. Tonga is somewhat overcrowded and we cannot use too many chemicals because the water table is so low.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· One local issue, which presumably has economic implications, concerns the possible expulsion of foreigners who have been here for a certain amount of time. Apparently, the decision has been taken not to renew certain residence permits. What is your view on this ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think Tonga should encourage skilled people who are here to stay. We should use make use of their skills, particularly where they have expertise that is lacking locally. At the same time, there are some people here who just came for a visit and ended up staying without doing anything very productive. There are also a number who came after the coup in Fiji and I think we should give them some leeway.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the whole, I don't think it is a big problem. Tonga has traditionally been very liberal in the application of its immigration law. We have never been colonised so we tend not to have a suspicion of foreigners. And whatever we do must be in accordance with the law.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Could you sum up your vision for the future ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  You only need to look around you to see that we have a youthful population here: a lot of young people who need to be catered for. We are investing heavily in education which I think is good but we need to do more to adapt to the changing world. We were peaceful in the past because most Tongans were on roughly the same level in terms of wealth. Now the poor are getting poorer while the rich get richer. This could lead to an increase in social tensions. With a more democratic system, we should be able to close the gap and work for a peaceful and more prosperous future. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Seeking business overseas</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">New Minister outlines economic strategy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If the policy of appointing Ministers for life - or at least until retirement age - is maintained, then Dr Giulio Masasso Tu'ikolongahau Paunga can look forward to a long career in the Tonga Cabinet. At just 32, he has recently been been given the job of Minister for Labour, Commerce and Industries (with responsibility also for tourism). He may be relatively young, but the new minister has impressive academic credentials. He took a master's degree in Japan (in Japanese) and as we soon discovered, he has some new ideas about how to achieve economic development in his country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dr Masasso's portfolio covers a wide range of economic activities and we began by asking what he thought the main focus of his work would be. He identified three areas  -  agriculture, which is the single most important sector; fisheries which has potential for growth; and tourism. He would also like to see more manufacturing, particularly for export, but acknowledged that the current prospects in this area were very limited.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Looking first at agricultural production for export, we noted that a significant change had taken place over the last decade. Coconut-related products had been largely replaced by squash, a 'gap' in the Japanese market having been identified when other sources of supply were not available. Tonga may have been the first to spot the opportunity but was there not a danger that other countries might 'muscle in'? The government was 'very aware of this danger', said the Minister and was trying very hard to diversify its export products. He mentioned vanilla, papaya, beans and, in particular, carrots. The last-mentioned crop grows well in the islands and there is apparently a growing taste for carrot juice in Japan. A list of products with export potential, which could be grown successfully in Tonga, had been drawn up in cooperation with the Ministry of Agriculture, and Dr Masasso's department would be actively seeking new business overseas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The government is obviously interested in developing trade with Japan and other countries in Asia, but the Minister felt that New Zealand and Australia were likely to remain the principal markets for Tongan farm products in the future. He was looking forward to easier access to New Zealand once new quarantine facilities had been set up at the international airport on Tongatapu. This, he said, should allow for a larger throughput of export crops.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Efficiency, of course, is the key to winning and keeping overseas customers. With this in mind, our discussion turned to the land tenure system. The allocation (at least in theory) of parcels of land to all male Tongans discourages the development of larger farms or plantations. Was this the most effective way of exploiting the country's fertile lands? Dr Masasso acknowledged that the system hampered efficiency but stressed that the question was a very sensitive one. The right to cultivate a plot of land is deeply rooted in Tongan culture, and radical changes to the property laws are not on the agenda. As the Minister put it; 'We are trying to maximise our efficiency under the present system of land tenure.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Turning to tourism, Dr Masasso observed that 'this has been the most stable industry over the past ten years,' bringing an average of T$ 12 million into the country every year. In looking at possible growth, however, he stressed the need to take account of the environmental and cultural impact. 'Tonga is a very small country, and it would not be right to build too many hotels and related facilities. It might be possible, but the long-term effects would be a little too much for the country.' Dr Masasso said he favoured tourism which has 'e closer relationship with people -  a cultural exchange, targeting people who really wish to understand our country.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fishing is a sector which appears to have huge potential given the size of Tonga's exclusive economic zone. Dr Masasso explained how Japanese assistance was being used in a boat building scheme designed to produce vessels that local people could afford. He also spoke enthusiastically of the research that had been carried out to determine the nature and size of the fish stocks. He recognised, however, that while most of Tonga's fishing was inshore, there was scope for a great deal more revenue from deep-sea fishing. In this connection, negotiations were underway with the United States, Taiwan and Japan, to allow vessels from these nations to fish in Tongan waters. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The conversation then moved on to the more general issue of entrepreneurship and the role of the state in the economy. The Minister indicated that the government believed in privatisation but stressed that this was not simply 'because other countries are doing ft.' The main issue at this stage, he said, was to create a sufficiently large pool of well-trained people to take over activities currently run by the authorities. 'The government wishes it didn't need to get involved but we are a small developing nation, and to get things started, you need capital and know-how  - which locals sometimes don't have access to.' In these circumstances, the state had to activate projects which could later be privatised once the necessary skills had been built up. Another 'major strategy' was to develop a much closer relationship between the Ministry and the private sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This led us into a discussion about Tonga's attitude to foreign investors who might also be in a position to supply capital and know-how. The authorities had recently threatened that a number of residence permits would not be renewed. Was this not a disincentive to potential overseas investors ? Dr Masasso was keen to offer clarification. 'The media makes it look as if Tonga doesn't like investors but they have misinterpeted the situation. He insisted; 'we want the foreign investment here and are encouraging it in those areas where locals cannot get involved.' Defending the actions of the immigration authorities, the Minister stressed that what they were doing was normal practice. 'Those who stay here illegally and do not extend their visa have to be deported.' The action, he argued, was not directed against foreign investors and indeed, the latter should be encouraged by the government's commitment to upholding the law.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Tonga-EU cooperation</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Developing the Vava'u islands</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Myfanwy van de Velde</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EC-Tonga cooperation began in 1975 with the first Lom&eacute; Convention, soon after Tonga gained full independence in 1970. Grant aid totalling ECU 19.8m (Lom&eacute; I - Lom&eacute; IV) has been allocated to the country during its 20-year membership of the Convention.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under Lom&eacute; I, funds were directed principally towards two main projects: the construction of the wharf at Neiafu, Vava'u, and funding for the Ministry of Works to procure road maintenance equipment and build schools, rural health centres and small wharves at Ha'apai and Vava'u. Remaining funds were used to finance studies involving dredging, trade promotion and designs for Vava'u and Faua fisheries harbours. The EIB also financed a line of credit of ECU 130 000, under Lom&eacute; I, to the Tonga Development Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lom&eacute; II funds focused on the fisheries sector, and on initiating works relating to the upgrading of the Vava'u airport. There were also projects in the fisheries sector, aimed at encouraging fishermen to undertake commercial fishing to meet local demand. To this end, the Faua Fisheries Harbour for small boats was built, and marketing and cold storage facilities were provided.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By the time Lom&eacute; III funds came on stream, Tonga had adopted a regional development approach with regard to its various island groups. The aim was to have a coherent development programme taking account of the specific constraints and potential of each. The Vava'u group of islands became identified as the focal area for the use of EC assistance, and Lom&eacute; III resources (ECU 6.5m in grants and ECU 0.5m in the form of risk capital to be managed by the EIB) as well as Lom&eacute; IV funds (ECU 6m and ECU 1 m respectively) have duly focused on its development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Located in the north of the Kingdom, Vava'u is the second group of islands both in terms of population (16 000) and land area. With an abundance of natural resources, the group is thought to have greater potential for agriculture and tourism than other parts of the Kingdom. However, this potential was largely untapped at the time Lom&eacute; III was initiated. This was due to a variety of constraining factors including relatively low productivity, undeveloped marketing infrastructures, substantial import levels and poor distribution of utilities and other public services. One particular constraint preventing the development of tourism was limited access caused by a lack of transport infrastructures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two main projects aimed at addressing these problems have been implemented. The first, costing ECU 1.24m, involved completing the upgrading of the local airport at Lupepau'u (begun under Lom&eacute; II). In addition to runway improvements, a new terminal building was provided, complete with safety and navigational equipment. Passengers began using the new facilities in early 1995. The second project, entitled the 'Vava'u Development Programme', was allocated the sum of ECU 5m. This money is being used to pay for a series of activities including road upgrading, the provision of photovoltaic equipment for household energy needs and the supply of equipment for vocational training colleges. New buildings being funded include health clinics, a market and an agricultural quarantine building. The funds also cover the cost of establishing the Vava'u Development Unit as the monitoring and implementing agency for the programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Programme continues under Lom&eacute; IV, with about 85% of programmable resources for Tonga (approximately ECU 5m) set aside for activities in the focal area. Funds will be directed towards developing the Neiafu urban area, in recognition of the need to upgrade access and services in the commercial centre of Vava'u. The projects envisaged include upgrading the town centre and urban roads, port improvements, and measures to increase the capacity and improve the distribution of piped and rain water to households. In addition, a multi-annual micro-projects programme will lead to the construction of jetties on the inhabited outer islands of Vava'u, thereby improving access to Neiafu which is the main centre of the archipelago.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to the above grant aid, Tonga has received funds in the form of Stabex transfers for losses in export earnings in respect of coconut products, bananas and vanilla. It also received emergency aid in 1977, following an earthquake, and in 1982 following Hurricane Isaac.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EIB interventions have contributed to the share capital of the Tonga Development Bank and have increased the Bank's lending capacity to small and medium-sized enterprises. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Switching on the Iights</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Uelingatoni Tevita Vaea (known as 'T' to his friends), proved to be a mine of information for The Courier, when we visited the Vava'u island group in northern Tonga recently. 'T' is a Tongan engineer who returned to his native land from Australia to work as assistant project manager in the Vava'u Development Unit. His help was particularly useful during the highlight of our visit - a traditional celebratory feast laid on by the villagers of Nuapapu. This is one of Vava'u's inhabited outer islands and the celebration was staged to mark the installation of solar powered lighting, courtesy of Lom&eacute; Convention funds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nuapapu is one of a number of outlying villages to receive solar installations under the Vava'u Development Programme. In all, some 350 homes have been wired up. Units attached to individual buildings collect the power and convert it into electricity which is stored in a battery. When night falls, the lights can then be switched on. Although the bulk of the installation costs are covered by the project, each participating household is required to pay a lump sum to have a unit fitted. They are also contracted to pay a modest amount each month towards maintenance of the system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It may all seem rather prosaic to those of us accustomed to electrical power at the flick of a switch, but for the people of the villages in the Vava'u group, the project is little short of revolutionary. For centuries, their daily rhythm has been governed largely by the rising and setting of the sun. The only 'artificial' light available after darkness came from fuel-burning (and more recently, battery) torches or lamps  - enough perhaps to reveal a path or highlight the position of an object, but certainly not to read or do intricate work with one's hands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The formal 'switching on' ceremony was performed by the Dutch Ambassador, Mr van Thessen and Jonathan Rodwell, who is the European Commission's resident advisor in Tonga. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This was preceded by a courtesy visit to the village chief and the above-mentioned feast, which gave the European visitors an authentic and memorable taste of traditional Tongan hospitality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The food was brought from all quarters of the village on long rectangular trays covered with leaves. Each was laden with food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fare was predominantly local: the famous roast pigs featured prominently along with fish, chicken, bananas, coconuts and a variety of root and tuber vegetables.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were also some 'imported' items: the corned beef which is so popular here, some packets of crisps to add colour to the guest 'table' and boiled sweets woven into garlands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The trays were laid end to end, stretching perhaps 20 metres and woven mats were placed all around. Having received our garlands of flowers, we were invited to sit down.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The feast was interspersed by various speeches and 'T' helped out with a translation and explanation of the proceedings. We began with a prayer in Tongan, delivered by the local minister. This was followed by a speech of welcome and thanks by the matapule (spokesman) of the village chief.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">High ranking people in Tonga always have a matapule to speak on their behalf on such occasions. Ambassador van Thessen and Mr Rodwell then replied on behalf of the guests, (in English, with consecutive translation provided).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They expressed thanks to the people of Nuapapu for their hospitality and wished them success with their new electric lighting. There was then a short discourse by the District Officer followed by a closing prayer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">References to all this speechmaking could leave a false impression that this was a formal and stilted affair.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact the reverse was very much the case: the mood was relaxed throughout and there is no doubt that the villagers know how to enjoy themselves. Music was supplied by a group of men playing a variety of instruments and the women joined in the festivities with what appeared to be spontaneous bursts of dancing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were also special solo dances performed by two young ladies whose bodies had been smeared with coconut oil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As tradition dictates, once their performances (involving highly expressive hand and finger movements) were complete, the audience expressed their appreciation by slapping banknotes on the oily exposed surfaces of the dancers' bodies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The light was fading as the feast ended and we moved to the brief 'lighting up' ceremony, carried out to the accompaniment of applause.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The guests (including the staff of the Vava'u Development Unit who have guided the project through its various stages) then took their leave of this hospitable community and set off by boat on the return journey to Neiafu. As the vessel drew away from the shore, we were able to look up and see, for the first time, the twinkling lights of Nuapapu. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Dossier</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Habitat</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Livable cities and rural rights</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(Dossier coordinated by Debra Percival and  Claude Smets)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The United Nations Conference, Habitat 11, on human settlements (Istanbul, June 3-14 1996) exposed the Herculean task of addressing the problems of ever-growing cities and called for 'shelter for all.' The special contribution of civil society in making cities more liveable was acknowledged at the conference - but the big question is, who will foot the bill ? The meeting also spoke of improving dwellings in rural areas to keep people on the land and halt the mass exodus to the cities. But the right to remain and prosper from one's habitat can be at odds with outside pressures for environmental conservation. The dossier looks at some of the issues raised by the conference, and the wider significance of 'Habitat II' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second UN gathering on the theme of 'habitat', staged two decades after the first conference in Vancouver, took place against a backdrop of rapid and alarming urban growth. In 1900, one person in ten lived in a city. By 1948, the ratio was three in ten and by the year 2000 half the world's population are expected to be urban dwellers. 25 years after that, the figure is expected to have climbed to 60%. Africa is the region that currently has the highest rate of urban growth. In 1950, it had only one city with a population of one million. By the end of this decade there could be 60 cities of this size, according to UN figures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The focus on human settlements and liveable cities inevitably meant that Habitat II covered some of the same ground as other UN conferences convened during the 1990s to explore the big issues facing mankind: the 1992 'Earth Summit' on environmental matters in Rio de Janeiro, the 1994 Population Conference in Cairo, the 1995 Social Summit in Copenhagen and the 1995 Women's Conference in Beijing. Issues common to all the agendas included rapid population growth, environmental degradation, access to clean water, poor sanitation, lack of infrastructures, and women's issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The rallying calls of Habitat II, set out in the Conference's conclusions, were 'shelter for all' and 'sustainable human settlements in an urbanising world.' The Nairobi-based Centre for Human Settlements is to be the focus for the follow-up. But as delegates dispersed, one of the pressing questions was where the money will come from to meet the host of agreed objectives -  which include clean water with improved technology, conservation and protection of the environment, and better health and education. In this dossier, European Commission officials from the Development Directorate General, who attended the conference, reflect on Istanbul and its likely followup.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whereas in the past, cities were associated with economic development, innovation and the diffusion of new ideas, nowadays they conjure up the vision of urban poverty, environmental degradation, poor sanitation and a host of health hazards. Urbanisation is the direct consequence of rapid population growth, according to the 1993 Human Development Report. In 1965, agriculture provided 77% of employment in developing countries and represented more than 41 % of Gross Domestic Product. By 1985, this sector was contributing a lot less to GDP but was still providing 72% of all employment. So a large number of people continue to depend on agriculture although its share of the global economy is declining. In these circumstances, it not surprising that many of the world's poorest people are migrating to cities - the annual estimate is 20-30 million.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The dossier looks, in particular, at the environmental cost of rampant urbanisation and at the problems of city living for more vulnerable groups such as women. They are often among the poorest urban dwellers and can fall victim to exploitation and crime.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Paradoxically, poor people in cities are becoming even poorer as economies improve. Additional pressures on these marginalised groups living in cities are neatly summed up by Jeremy Seabrook, author of 'In the Cities of the South.' In a recent article for Gemini news agency: 'Tougher Struggle for Survival in the Concrete Jungle,' he writes; 'As the pace of development quickens, with high economic growth and increased migration to urban areas, land price in most big cities have soared. Poor people are being increasingly removed from their hoary" - by mysterious fires, explosions and 'accidents'. Meanwhile, the urban poor's ability to mobilise and achieve has been used against them. The capacity of people to create homes and secure local communities has been used as a justification for the withdrawal of government services.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He continues: 'As inequalities become more glaring, enclaves of prosperity are sealed off from the slums by checkpoints, guards and fences - like frontiers to another country. Despite this, people are still flocking to the city  -  often refugees from intensifying, industrialised agriculture and.. megaprojects in the countryside...' Mr Seabrook points out that without decent jobs, they fall prey to sub-contractors, who exploit them, offering them low pay and demanding that they work long hours.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Civil society</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the cities of many developing nations, 'civil society' is taking a lead, with projects to bridge the gap between the 'haves' end the 'have note'. Numerous participants at the Istanbul conference applauded the urban programmes undertaken by various elements of civil society, which include NGOs, community groups and individuals. Their significance was recognised in Istanbul, where their voice came through loud and clear. Nigerian journalist, Paul Okunlola, writing in this dossier notes a move towards 'bottom up' projects in Lagos as a result of the tough times.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agostinho Jardim Gon&ccedil;alves, the President of the NGO-EU Liaison Committee, was particularly pleased at the input of civil society to the conference's committees and conclusions. The debate, he said, had not just been about the macroeconomic aspects. Instead, it had come 'within the reach of the populations themselves.' The people, he argued, were both victims of the anomalies of inhumane settlement and the key players in efforts to construct a humane, dignified habitat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jeremy Seabrook describes some of the inspiring international initiatives undertaken by civil society. Examples include the Society for the Promotion of Area Resource Centres (SPARC) in Bombay, which works with pavement dwellers; the Association of Basic Needs (ARBAN), and 'Health for All' in Dhaka; the Eddie Guazon Foundation in Manila, which seeks to protect the poor against private interests; and the Foundation for Women, which is trying to tackle the trafficking of girls for Bangkok's brothels. But Mr Seabrook also warns against overestimating the strengths of popular organisation. As he points out: 'They require an enabling and positive framework, which the free market can never provide. Government intervention, of a more benign and positive kind than hitherto, is vital if people are to help themselves. As it is, too often they are forced to struggle against the people elected to govern them.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The chair of the Habitat Conference, Wally N'Dow, emphasised local solutions. The conference, he said, 'recognised the changing global patterns of life' and that solutions must be found at the local level. 'National governments and international agencies', he argued, were not in a position to solve massive urban problems or to pay to put them right.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were a number of donor pledges at the conference. The European Union countries, for example, reiterated their long-standing commitment to provide 0.7% of GNP for development by the year 2000  -  though many of the 15 member states are still well short of this target.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One scheme which has attracted the particular interest of donors is South Africa's Reconstruction and Development Programme (RDP). To a considerable extent, the success of President Mandela's government is likely to be judged on the success of this programme. It aims, among other things, to improve health, education, housing and sanitation and as such, it mirrors many of the 'Habitat II' goals. Launched in 1994, it is the centrepiece of the South African government's efforts to create a more democratic, prosperous, non-racial and non-sexist society. In the dossier, we look at the RDP's objectives, how it is faring and what sort of support the EU is giving.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rural rights</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beyond the city, the dossier looks at what is happening to some rural dwellers who have not taken flight to the city. Although, largely focused on the city, Habitat II acknowledged the importance of urban and rural linkages in its conclusions: 'Rural and urban settlements are interdependent... governments must work to extend adequate infrastructure and opportunities to rural areas to increase their attractiveness and thereby minimise... migration.' There was mention too of the need for more jobs and housing for rural areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But in some rural areas, the inhabitants have found themselves in dispute with conservationists. The latter seek to protect wildlife and the rural habitat by setting up national parks - a solution which is not necessarily in the interests of local people struggling to maintain their livelihood. We take a look at such dilemmas and the possible solutions being developed so that rural dwellers can continue to make the most of their habitat. This rural struggle, where solutions are also being called for at a local level, is not unlike the battle being waged for a better quality of life in the cities. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Towards a global concept of urban development - an interview with Daby Diagne</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Deputy mayor of the city of Louga, Daby Diagne is also President of the Finance Committee of Senegal's National Assembly, General Secretary of the Association of Mayors of Senegal and President of the World Federation of United Cities. He is the ACP-EU Joint Assembly's General Rapporteur on urban development and The Courier had the opportunity to interview him in September at the Assembly's meeting in Luxembourg.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You have just submitted an initial report on urban development to the Joint Assembly. In it, you recommend that the Community adopt a specific and consistent global policy in this field, notwithstanding the fact that successive Lom&eacute; Conventions have contained a number of significant provisions relating to the subject. What is the reasoning behind your recommendation ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - There are several reasons. First, there is the fact that, in the past, cities were often viewed solely in terms of infrastructures and sectors. Experience shows that this approach is not effective. Specialists are increasingly opting for a more global 'city' concept. The Commission must therefore adapt itself to the new situation. It is true that it has financed infrastructures and launched health and clean-up programmes, but the problem is that this has been done in a somewhat unsystematic way without being linked to long-term regional development or a zonal policy. There is now an increasing need for an integrated regional development approach. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think ACP countries are aware of the importance of cities ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That's another question altogether. Obviously, the ACP countries are in the process of changing their views on this subject and a number have appointed ministers to look after urban affairs. The reality of city life has to be taken into account. The rate of urban growth in the ACPs far exceeds that in other parts of the world and it is in the towns and cities that one sees the most glaring instances of poverty and under-development. People have therefore been forced to take the 'city' phenomenon into account in the ACP countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The political will must exist for a policy to be successful. Do the ACP countries have a genuine will to implement an urban policy ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I don't think it is possible to speak of a uniform trend in all ACP states. However, in certain regions - for example in West Africa, which I know well - a municipal culture is beginning to take shape. There is a growing political will, which is illustrated by the discussions on decentralisation, and people are increasingly recognising that central government cannot do everything by itself. One can find regional development and planning policies designed to create the fabric of mediumsized cities. Not everyone has them but it is something we are seeing more and more of.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· ACP countries face complex challenges and there are people who say that the actions of the European Community are too dispersed owing to the number of sectors it is involved in. Doesn't your recommendation simply add to this problem ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - On the contrary. I regard my recommendation as being pro-integration and therefore pro-globalisation  - which is not the complete opposite of a sectoral, diversified approach. I believe it would allow the Union's activities in certain fields to be better interlinked. I am thinking here of water, health, clean-up operations and infrastructures  - all of which are major problems for society. Naturally, a more global concept will require greater dedication, and if there are additional resources, so much the better, but, in my view, the situation could be improved even with what we currently have available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The rate of urbanisation in Africa is higher than elsewhere and the living conditions of city dwellers - particularly those in the shanty towns  -  are becoming increasingly difficult in terms of health, education, environment and so on. What, in your opinion, would be the optimum strategy for reversing the decline, at least in the short-term ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - First of all, I think we have to make a distinction here. Let's take the actual rate of urbanisation. Contrary to what is generally thought, this is lower than in the rest of the world. In other words, Africa has fewer towns and cities than the rest of the world. It is the rate of growth in the urban population that is higher. Populations are becoming increasingly concentrated in the cities, with the drift of people from the countryside. In addition, the phenomenon is being fed by demographic trends. You ask me if there is anything we can do to halt this. There are actions that can be taken to restore some balance. For example, we could make investments in the rural environment to keep people in the countryside, and we could implement suitable agricultural policies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But we must not labour under too many illusions, because life in towns and cities will be an inevitable characteristic of the next century. Economists and urban planners have been considering the phenomenon for a long time now - perhaps 30 or 40 years. It is  something that cannot be halted, because it is a fact of civilisation. So, what should we do? Above all, we should devote our efforts to regional development, achieving a balanced distribution of human resources, and a more equitable exploitation of natural resources. Power has to be decentralised so that people do not abandon their roots but face up to local challenges. And we have to implement urban policies which are satisfactory in terms of investment, management and popular participation. In simple terms, urbanisation has to be managed. We cannot hope to reverse the trend overnight, particularly in the case of a continent like Africa where everything happens quickly. Africa is enormous and its population has not yet reached its maximum levels. We have to take all this into account.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We must acknowledge that scientific progress and improvements in the field of health have contributed to population growth, and a reduction in mortality rates. This means that urban civilisation is a reality that we have to manage. There is a risk of uncontrolled growth in urban centres. When infrastructures are lacking, when there is no water, when hygiene cannot be guaranteed and when there is no work, a country's security is threatened.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You have mentioned democracy end the decentralisation of government This also requires adequate financial resources. Where do you think the ACP countries will find the money to implement decentralisation strategies ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Democracy involves a search for freedom - freedom of opinion and expression, independent of material or financial problems. The problem with decentralisation lies in administrative method. It is not purely a matter of money. In the first instance, it is a question of choosing the right approach. It has been demonstrated that without any extra resources, one can still act differently by delegating and decentralising. And success is much more likely because the people are involved in the process. Admittedly, it requires an internal reallocation of resources. A proportion of everything that was formerly centralised has to be allocated to development and to basic needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To answer your question more directly, there is a great deal of talk of this alternative method of governing. It is inspiring new hope and a thirst for something better. It is even being viewed as an 'ideal' solution - which it cannot be entirely. However, by decentralising human and economic resources, and by allowing people to participate, hope can be inspired at local level. This should make for better administration and support, which is an improvement in itself. Of course, this may make people more demanding. Will it satisfy their requirements? As I have already said, internal resources will have to be reallocated, but resources must also come from outside. One cannot make an allout effort for decentralisation without doing something to improve international cooperation. This cooperation, however, must be adaptable, and the state must retain its pre-eminent position and its role as guarantor and arbiter. But in addition, local communities should have access to international cooperation either directly or indirectly through their organisations, municipal structures and so on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· In this context, what role do you see for international organisations - not just in terms of financial resources, but also of human resources ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I think what we now need to do is build up a pool of skills in each municipal area. The developed countries have experience in this field. We have to take their processes as a model without necessarily copying their experience. This is something which will be discussed. Secondly, in the context of relationships between towns and cities, I believe it is possible to make access to experts more flexible and that this can take place very quickly, with the provision of training and fairly basic technology transfers. General training is also extremely important. In order to build up a pool of skills in towns and cities, local government must form a dynamic, management-oriented team. The approach has to be one of business-like management and objectives have to be targeted using private-sector methods, although public-service requirements always have to be borne in mind. A great deal, therefore, can be done at international level, in terms of support for networks of associations and committees of locally elected representatives, enabling them to discuss matters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We could, for example, carry out a comparative study of legislation in a particular area, thereby gaining access to other types of experience. Internationally, aid can be given to associations to help them buy equipment and attain a degree of freedom of manoeuvre vis-&agrave;-vis the authorities. In the field of decentralised cooperation, the international community can help elected representatives to implement their projects through partnerships, conducting studies, and providing personnel. Cooperation is possible in all spheres -  implementation, management, financing and so on. I believe that a new type of cooperation will gradually come into being. It is not a question of creating 'white elephants', but rather small and medium-scale projects which are of genuine use to the population. And I am not talking here about acts of charity, such as the donation of medicines, but sustainable projects. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Habitat II: taking stock</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Christian Cure'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The future of towns and cities is not what it was. In the 20 years between the first United Nations conference on human settlements (1976) and Habitat II which took place in Istanbul in June 1996, the situation has changed a good deal. The significance of urbanisation  - and its irreversible nature -  are now acknowledged, as is the powerlessness of the authorities to deal single handedly with the complex phenomena which result The author of this article points out that civil society has suddenly broken into a field hitherto the preserve of official agencies and qualified experts, claiming a 'right to the city' based on research into more equitable development models.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vancouver to Istanbul: two symbols for two eras</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Vancouver was the 1976 host of the first conference on human settlements organised by the United Nations. At that time, the UN was celebrating 30 years of existence and Vancouver, a model of urban development and modernity, provided inspiration for the developers and experts needed to plan the cities of the future. 'Appropriate technologies' heralded the possibility of mass-produced, cheap housing for everyone.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Twenty years later, the UN chose Istanbul as the host city for the Habitat II conference on human settlements, forcing us to face up to a quite different situation: uncontrollable urban growth (400 000 migrants arrive there every year), social and environmental problems, and intercultural and political tensions (amply illustrated by the Turkish politicians' inability to form a government at the very time the Conference was taking place). In brief, Istanbul presents us with the usual list of problems facing most of the world's major cities - and those of developing countries in particular.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Against this backdrop, the international community  -  180 countries, 500 local dignitaries, a few thousand professionals and even some ordinary citizens - came together from 3 to 14 June to discuss a 'settlement action plan'. This document, which had been in preparation for two years, contains 183 articles. It sets out a series of goals, principles and undertakings as well as providing an action plan for cities, the initial results of which should begin to be seen by the year 2001.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The preparatory committee selected two basic topics for discussion: securing adequate shelter for all, a basic but nonetheless controversial theme; and sustainable urban development The latter encompasses housing, demographic factors, infrastructure, services, the environment, transport, energy, social and economic development, the future of underprivileged groups and combating exclusion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The cycle initiated at the Rio Earth Summit in 1992 (followed by the Copenhagen, Beijing and Cairo meetings) was continued by Habitat II. Two major handicaps had to be overcome - 'conference fatigue' (with the resulting fact that there were fewer delegates than anticipated) and ensuring that what had been accomplished at earlier conferences was not undermined. Given that the subject of the meeting was human settlements, it was inevitable that sensitive issues already debated at previous summits, relating to the environment and social aspects, would keep recurring.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Civil society as an active force</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A number of conclusions arose from the official sessions (hearings, dialogues and various forums) which took place over the two weeks of the conference.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">First, Habitat II represented a recognition of the fact of urbanisation. In the past, there was a tendency on the part of the international community to play down, or even ignore, the phenomenon of urban growth and this was reflected in the meagre resources allocated to this area by donors. Today, the issue is better understood than it was 10 or 20 years ago, and it is acknowledged that the growth trend is unstoppable. Statistical studies and a set of 'urban indicators' drawn up for Habitat II confirm the scale of the problem. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Second, the Istanbul summit was a lesson in modesty. The obvious powerlessness of public authorities to deal single-handedly with the challenge of burgeoning towns and cities is recognised. The result was an understanding that a more pragmatic view is needed -  one which pays more attention to the complexities of urbanisation, to the wide variety of possible responses and, above all, to the multi-faceted nature of the players involved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Conference therefore became a genuine forum for debate. One of its most significant aspects was the emergence of 'civil society' as an active force. Hitherto, the field has largely been the preserve of official agencies and qualified experts. For the first time in a UN forum, local authorities, community leaders, private sector representatives and other dynamic forces in civil society were invited to give their views and take part in discussion groups. Whereas in the past, the debate was dominated by macroeconomic and technical questions, in Istanbul, the political and social aspects were given prominence as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The effect of this was to improve the quality of the debate. The outlines of a new relationship between governments and civil society (NGOs, ordinary citizens and popular urban groups) were defined - with the local authorities slotting in somewhere in the middle. And there was a particular focus on the question of dimension or scale: what should be the basis for urban democracy and citizenship. Both of these are seen as essential if one is to have successful and sustainable urban development policies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A right to the city?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first stage of the analysis is to look at urban life from a macroeconomic standpoint. Urban growth is determined by the evolution of the world economic system and, in particular, by the globalisation of markets. This has generated increased competition, including competition between cities themselves. Since the end of the 1980s, cities have been responsible for between 50% and 80% of the GDP of most countries. In other words, they represent more than mere links in the global economy; they are, in fact, pivotal points.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hence the principles which broadly underpin the Habitat 11 programme. In fundamental terms, public policies must promote the capital, housing, property and employment markets, with a view to improving the efficiency of urban management (living conditions, infrastructures, services, environment, etc.). This is not just desirable in human terms but also essential if urban productivity is to be improved. Many decision-makers at the meeting agreed that privatisation of services, partnerships involving the authorities, the community and the private sector, and decentralisation were all part and parcel of a new standard for good local governance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Representatives of 'social' interests, on the other hand, were successful in focusing the debate on fundamental rights and principles, including individual and social rights. Indeed, these issues dominated the Conference and gave rise to the most difficult negotiations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There were prolonged talks, for example, on the central issue of the right to a roof over one's head. The outcome was a commitment by governments to promote 'the full and progressive acceptance of the right to adequate shelter'. The NGOs had been hoping for a more clear-cut undertaking. Questions relating to the status of vulnerable groups, women's rights and their equal access to land, and protection against eviction, were also the subject of heated exchanges.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perhaps the most important step forward, however, was the success of civil society representatives in sowing the seeds of a new idea - the 'right to the city'. This concept has been devised on the basis of research into more equitable and soundly-based development models to which local authorities are increasingly giving practical support. Thousands of individual experiences and issues were highlighted in Istanbul by NGOs and community groups. Thus, there is a mass of evidence that populations are capable of responding through local initiatives and of taking responsibility for improving their living and housing conditions. If this 'resource' is to be exploited to the full, urban politicians must develop a deeper understanding of the scale of micro-territories and local societies within cities. They also need to promote and coordinate their decision-making in a way which involves consulting and involving the local populations. In the modern era, this is the key to ensuring social cohesion.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beyond Istanbul</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There may have been a lot of new thinking on the basic principles, but there was no reference to financial undertakings in the Habitat 11 programme. On the latter issue, the international community was highly circumspect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The World Bank took the initiative, announcing the launch of an 'urban compact', involving an additional $15 billion in loans for urban projects over the next five years. It also revealed that it would triple its aid to NGOs involved in the urban environment. Recent World Bank estimates suggest that just 0.2% to 0.5% of a country's GDP would need to be set aside for the poor to gain access to basic urban services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As regards monitoring, the NGOs and local authorities won the right to sit on the Human Settlements Committee which will be responsible for implementing the habitat programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The most important points to emerge from Istanbul, however, were that local authorities were given both formal recognition, and a major practical role - in keeping with their current responsibilities. The habitat programme is, in fact, a powerful call for decentralisation and increased local autonomy, its action plan being built on the implicit principles of 'subsidiarily' and 'proximity'. To a large extent, the successful implementation of the programme will depend on the mobilisation of municipal politicians and officials - and on the policies they adopt at local level. The agenda for cities in the 21 st century that was adopted at the Rio Summit must now be fleshed out and become the future reference for action by local authorities, NGOs and citizens' associations. Finally, the importance of decentralised cooperation and the role of local councils in international cooperation have been reconfirmed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Local authorities and their international organisations decided to form a worldwide coordinating group to continue structured dialogue with the international community and to guarantee that the Istanbul resolutions are followed up.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some people predicted that Habitat 11 would be 'the revenge of the cities'. To quote P. Maragall, chairman of the Committee of the Regions, the conference at least provided the opportunity to build, and to give a wider audience to 'the voice of the United Cities within the United Nations'. That itself is a major step forward. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">'A house to call my own'</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tackling violence against women</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Rosemary Okello</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author of this article is a journalist with the Nairobi-based Women's Feature Service (WFS) She contends that the Habitat 11 conference skirted around some of the issues affecting women city dwellers in Africa, such es violence and sexual abuse. Improving their lives, she argues, starts with a roof over their heads</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The lofty ideals set during this year's UN Conference on Human Settlements in Istanbul meant little to African women like Catherine Kaberu. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As she recalls the misery of living on the streets of Nairobi, she is just happy now to have a safe, secure room for her family. 'I thought by running away from home and coming to Nairobi, I would find a better life" says Ms Kaberu. Instead, the streets became her home and her life was defined by the fear of violence against her. Her two children were born during that difficult period, following rapes. She cannot identify their father. There are an estimated 30 000 street people in Nairobi and Catherine Kaberu says that all street women and girls are regularly abused.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Every day we had to look for a place to sleep and we bribed the watchmen to guard us.' Often it was the same watchmen, employed to guard office blocks in the city's central district, who took advantage of the women's desperate situation. Not even age could protect them says 63-year old Felista Nyambura, herself a veteran of the streets. 'I suffered all manner of humiliation,' she states, referring to ten years spent on the streets with her seven children. 'The watchmen would rape me if I refused to give in to them - after they had offered me a place to sleep for the night with my children. I am just so happy to be off the streets. I will never go back,' she states firmly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The confidence of the two women comes from their new security as owners of simple one-roomed houses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'Having a house to call my own is the most important thing that ever happened to me,' says Ms Nyambura as she explains how she ended up on the street after the piece of land her husband left in their rural home was taken over by her in-laws.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The two women are part of a group of 114 who have benefited from the Urban Destitute Programme, a project of the African Housing Fund which is involved in participatory community development with the homeless women of Nairobi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Catalina Trujillo, the 'Women in Development' coordinator for the Habitat conference stresses: 'If a woman's place is in the house, we had better make sure she owns it.' These sentiments were supported in Istanbul by the conference Secretary General, Wally N'Dow: He stated: 'By conviction, by analysis and even by instinct, women's rights to ownership and inheritance of property is right. If Habitat II... does not also contribute to social progress by addressing some of the issues like property rights for women, then it will have failed.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the women of-Africa in particular, the most important thing that should have come out of Istanbul was an affirmation of their right to own and inherit property, and to security.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These issues affect most African women regardless of their status and they were presented to ministers concerned with shelter and settlements when they met in Johannesburg last year to prepare an African agenda for the Istanbul meeting.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Most African countries accept the theoretical premise that women must have access to land, credit and inheritance, and recognise that certain types of violence are targeted primarily at women. South Africa's President Mandela affirmed: 'When we talk about people-centred development, we should understand that the involvement of women is often the difference between success and failure.' Yet in reality, customary law and insensitivity to gender concerns continue to predominate. Unfortunately, when the African ministers adopted their declaration, the point on the "unencumbered access of women to credit and land ownership' appeared in only 20th place. And while forced evictions were highlighted in Istanbul, violence against women did not feature at all among the 'key priorities'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet in parts of Africa these are major concerns affecting women every day. 'In South Africa, a women is raped every 83 seconds and in some areas, a girl can expect to be raped four times in her life,' says Emelda Boikanyo of the Johannesburg-based Women's Health Project. Idah Matou remembers how one Sunday morning in 1992, five men stormed into her shop in Alexandria township. They seized the day's earnings and anything else they could carry away before raping her 1 5-year old daughter. A few weeks earlier, they had called to demand protection money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Violence in the home is also a growing problem. Mmatshilo Motsei, Director of Agisanang Domestic Abuse Prevention and Training, an NGO based in Alexandria, South Africa, says the problem is so pervasive, 'it must be raised as a national concern.' Habitat II turned a deaf ear on these women's concerns. This was not their forum. Shawna Tropp of the NGO Women's Caucus criticised those attending the conference who claimed that it was not about women but cities. 'Women live in cities,' she says and adds: 'By and large, human settlements are still very much seen in terms of bricks and mortar'. She calls for greater understanding of the role played by women, usually in an unpaid capacity, in the management of communities. 'Everything begins with having a house in a secure neighbourhood where the dignity of women is protected.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Megacities</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The megacity personifies human misery for many in developing nations. As agglomerations proliferate in the twenty-first century, the United Nations Population Fund's 1996 report - The State of the World Population  -  considers how one might go about remedying the ills of city dwelling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The UNFPA's figures for urban growth make worrying reading. Over half the world's people will live in cities within ten years (3.3 billion out of a total of 6.59 billion). Between 1970 and 2020, the urban population will have risen by more than two billion - and 93% of these will be in developing nations. These increases will add to the strain of an estimated 600 million people already living in urban areas of developing nations without the resources to meet their basic housing and health needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Back in 1950, New York was the only city with more than 10 million inhabitants. Today, there are 14 in this category. Tokyo, which is home to 26.5 million people, is the largest. And by 2015, many others are expected to join the megacity 'club'  -  Djakarta (Indonesia), Karachi (Pakistan), Dhaka (Bangladesh), Delhi (India), Tianjin (China), Manila (Philippines), Cairo (Egypt), Istanbul (Turkey), Rio de Janeiro (Brazil), Lahore (Pakistan), Hyderabad (India), Bangkok (Thailand), Lima (Peru), Teheran (Iran) and Kinshasa (Zaire).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the majority of the world's people will be living in cities by 2005, it will take a little longer for the 50% threshold to be crossed in the less developed regions. However, this is expected to happen before 2015. Looking specifically at Africa, the current estimates reveal significant regional variations. In Southern Africa the rate of urbanisation is 48%. The figures for North, West, Central and East Africa are 45%, 36%, 33% and 21 % respectively.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Expanding populations are likely to add to the widely reported list of horrors emanating from cities that are bursting at their seams. Problems include the collapse of basic services such as water and waste management, escalating social conflict, millions of urban children open to labour exploitation, sexual exploitation, environmental degradation, traffic congestion and environmental hazards such as increased air pollution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the other hand, the UNFPA report acknowledges that cities are also 'concentrations of human creativity and the highest form of social organisation'. It continues: 'Cities provide capital, labour and markets for entrepreneurs and innovators at all levels of economic activity'. Indeed, between 60% and 80% of developing countries' GNP is generated by their major conurbations. Social transformation occurs at a faster pace in urban areas. Thus, health indicators tend to be better, literacy is higher and there is more social mobility. And there are more opportunities for women. The city presents fewer obstacles for women's education and female city dwellers are less likely to be constrained by traditions which may stifle their creativity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But harnessing this potential is no easy task. The final chapter of the UNFPA report, entitled 'Policies, strategies and issues for improving cities', argues that urban dwellers in developing nations have been badly affected by structural adjustment policies. These have resulted in the elimination of subsidies on food and other commodities, increases in school fees and job losses in the public sector. Cities will also be required to adapt to the 'mass global experience in decentralisation' involving the shifting of local decisions from central government to municipal authorities, parastatal bodies and the private sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p48.png"></center><br>
+ Regional distribution of urban population</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Women - a priority</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The report stresses the importance of improving education and health, with a particular focus on women. As Dr Nafis Sadik, who is Executive Director of the UNFPA, observes; 'If urban centres are to be made liveable, and the quality of life of the poorer members of society is to be improved, women should be given the chance to play their role in the process.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The report reiterates the specific targets for improving the lives of women that were drawn up by the 1994 International Conference on Population and Development held in Cairo.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the field of education, these include 100% primary school enrolment (for both girls and boys) by 2015, improving access for girls and women to secondary, tertiary and vocational education, and closing the gender gap in the primary and secondary sectors by 2005.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other goals include a progressive reduction in infant and maternal mortality, making reproductive health services accessible to all through the primary health care system by 2015, greatly improved provision for family planning (allowing couples to make free and informed decisions on the number, spacing and timing of births) and providing better protection against sexually transmitted diseases.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The State of the World Population Report concludes: 'A successful urban future depends, as much as anything else, on engaging all members of the community - especially women and the poor  -  in a constructive political process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There will have to be partnerships struck between governments, nongovernmental organisations, the private sector, and local and community organisations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And global urbanisation will require that the international community  -  governments, NGOs and international institutions - act to exploit the potential of cities to improve the lives of the world's people and to establish the foundations of sustainable development in the 21st century.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Lagos under stress</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Paul Okunlola</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With a present population of some 7.5 million, the new millenium will propel Lagos to megacity status. The United Nations Population Fund predicts that 24 million people will live in the city by 2015, making it the third most populous conurbation on the globe. Whilst the donor community has supported urban projects in the past, tough times mean more reliance on 'bottom up' schemes backed by N60s and community-based groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When it began to rain in the small hours of Thursday 18 July 1996, residents of Lagos -  Nigeria's largest city and economic nerve centre -  merely stirred in their slumber. The gentle, but persistent showers, didn't rank among the heaviest downpours experienced by this coastal city, which gets rain on average for eight months in every year. Nor are Lagosians unfamiliar with spells of rain lasting up to seven days without break.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But by the time of the early morning 'rush hour', the traffic-laden streets of metropolitan Lagos were being swept with rampaging floods. Until well after noon, the city's social and economic life was at a standstill. Already difficult road conditions were rendered impossible for motorists, marooned at the wheel for hours. Exhausted school children eventually made it back home after spending the better part of the day in traffic. Crowds of commuters waited interminably at bus-stops for vehicles that never came.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The economic toll was expected to be heavy, with offices in both government and the private sector remaining empty all day. Commercial activities were put on hold as shops remained shuttered until well after noon. The communications network and electricity supply to key areas of the city were shut down for hours, to protect equipment. One state government official commented: 'It has never been so bad.' By the time the water receded and life had returned to normal, both government engineers and private sector consultants were in agreement: the main reasons for the flooding were illegal development along the natural courses of inner-city waterways, and the reduced drainage capacity of the overdeveloped metropolitan area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Exploding metropolis</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both the flood itself, and the acknowledgement of the human limitations of the city officials, illustrate the frustrations that have attended the management of this exploding metropolis over the last three decades. In the months leading up to the July flooding, a major controversy erupted over plans to landfill the inland Kuramo lake in the highbrow Victoria Island district and develop it as a housing estate. This pitted state government officials and a firm of developers on the one hand, against a motley band of citizens groups, non-governmental organisations and concerned environmentalists on the other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The unusual strength of local feeling against the project reflects growing fears that the island itself could be submerged. Five years ago, this was thought to be a remote prospect but today it is seen as a real threat, given the increasing frequency of flooding incidents and ocean surges along the coastal area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More and more people are arguing that there is a correlation between the growing frequency of flooding incidents and the massive sandfilling activity that has taken place over the years. The Kuramo issue remains contentious but it is just one example of the wider dilemma facing the city's development planners. They have the daunting task of providing for legions of migrants to Lagos - whose swelling numbers are placing great stress on the failing infrastructure. The problem may be particularly acute in the Nigeria's largest city, but it reflects a wider trend of urbanisation in the country over the past half century, as the overall population has increased.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1921, Nigeria had just 18.7 million inhabitants. Current estimates put the population in the region of 103.5 million. And the growth in the proportion of urban dwellers has been equally dramatic. In 1931, fewer than 7% of the people lived in urban centres. The figure had risen to 10% by 1952,19% by 1963, 33% by 1984, and 42% at the last count, in 1991. Current figures suggest that there are now seven Nigerian cities with more than a million inhabitants and no fewer than 78 whose population exceeds 100 000.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The changing structure of the country's human settlement profile has been linked to broader economic and social changes. The situation has been exacerbated by the economic depression of the last two decades. Analysts have noted a trend of declining primary production in such areas as agriculture, mining, quarrying and exploitation of natural resources. This has resulted in greater attention being paid to secondary and tertiary economic activities -  which are generally city-based. The figures illustrate the dramatic nature of the change that has taken place. In 1952, the ratio of primary to secondary/ tertiary economic activity, as measured in Nigeria's GDP, was 68:32. Four decades later, the ratio was 38:62.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">According to World Bank consultant, Prof. Akin Mabogunje, the trend is exemplified by the expansion of a whole range of activities located in urban centres -  large, medium and small-scale enterprises in manufacturing and construction, utilities, transport and communications systems, wholesale and retail outlets, hotels, restaurants, finance and insurance companies, and estate agencies. Then there is the whole range of government activity. Until 1991, Nigeria's huge federal bureaucracy was located in Lagos, operating alongside a state administration and some 15 local authorities. Add to this the major docks and airports of Lagos, and you get an urbanisation phenomenon which has, to say the least, been intimidating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lagos, which only occupies 0.4% of the country's land area, gains an extra 300 000 inhabitants every year on top of its natural growth rate. That the city is a 'pole of attraction' is hardly surprising. It is clearly the economic nucleus of the country, reputed to account for about 57% of total value added in manufacturing and about 40% of the nation's most highly skilled manpower.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Urban toll</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The costs have also been high. Professor Poju Onibokun, a human settlements expert, enumerates these: grossly inadequate housing and infrastructure with millions dwelling in slums; social amenities under enormous pressure with a shortage of schools and poor health facilities; endemic crime and juvenile delinquency; the breakdown of traditional values, family cohesiveness and community spirit. The capacity of law enforcement institutions is also increasingly hampered by technological and resource limitations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Of these ills, the shortage of housing and lack of infrastructure are seen as the most acute. This is borne out by a recent World Bank study which notes that:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - the quality of life and living conditions have deteriorated;</P>
+<P ALIGN="JUSTIFY"> - economic production has plunged;</P>
+<P ALIGN="JUSTIFY"> - the inadequate provision of infrastructural services has negatively affected the operations of most private sector investors, who now need to spend between 22% and 25% of their capital outlay on providing their own infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over 90% of the city's housing is provided by the private sector. But this has been handicapped in recent times by spiralling development costs and a general shortage of funds. New private housing has consisted largely of thousands of individual units, built mainly in areas of existing large scale developments. The authorities have made their own efforts to plug the gap and over the last 15 years, no fewer than 6000 hectares of marshland have been sandfilled and reclaimed in six separate development schemes (some of which have proved controversial). The Land Use Act of 1978 vested all urban land in the state authorities, although the administration of the legislation has not always proved satisfactory.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Public transport is another problem for Lagos residents. There is no integrated system of mass transport and the sector is essentially made up of hundreds of privately operated buses and a dwindling taxi fleet. Massive currency devaluations have meant that the purchase price of new vehicles has rocketed. Maintenance costs for the increasingly dilapidated fleet have also spiralled. As a result, the system is stretched to beyond its capacity and it is the commuters who bear the brunt.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Public sector spending obviously has an important part to play in maintaining urban structures. The downturn in international aid flows has, therefore, had a visible impact with decline in infrastructure provision and maintenance, leading to a less favourable operating environment for private investors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the past, Lagos has been a notable beneficiary of urban support programmes with multi-million dollar schemes for water supply, storm water drainage, and infrastructure. Most of these have been World Bank-led but the support of the European Union and its Member States in this area is also considered crucial.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the positive side, adversity has proved a catalyst for greater community-based and NGO activity in environmental and human settlement issues over the last decade. This is a fresh approach, based on 'bottom-up' strategies, which should open up muchneeded new avenues to urban management in Nigeria more generally and in Lagos in particular. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">A Eurocrat in Istanbul</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Gilles Fontaine</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author, a specialist in urban development, offers us his thoughts on the Istanbul conference. This event, he believes, was a landmark in the collective process of raising awareness which was begun at the Rio Conference on the environment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">14 June 1996 - last day of Habitat II</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Night fell a long time ago. A feeling of hope permeates the hall. Most of the work is completed but there are still disputes over a few paragraphs of the text of the Habitat 11 Agenda. Some delegates have not slept for two days and they can be seen standing around, afraid they might fall asleep. The sense of fatigue increases further when, at midnight, the symbolic 'stopping of the clocks' (to permit a successful outcome of the final negotiations) is announced over the PA system.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At two in the morning, the wait has become almost unreal. It is virtually unimaginable that the Conference should come to nothing, after two years of intense work. Since Wednesday evening, the general atmosphere has been almost euphoric. Agreement has been reached on all the essential points within the allotted time and the Conference is already being heralded as another success story. All that remains to be done is to finalise the 'Istanbul Declaration', a four-page policy text broadly summarising the work of the Conference. The Conference would finally close about two hours later, amid general relief - but why the impasse?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Breaking new ground... and remaining steadfast</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some problems arose where they were least expected! To everyone's surprise, 'informal' working sub-groups had to be set up to discuss nuclear testing and anti-personnel mines! These themes were a far cry from the Habitat Agenda, but this sort of thing inevitably happens at major international conferences.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other stumbling blocks appeared without any real warning, when some delegates attempted to renegotiate the conclusions of the Beijing and Cairo conferences. The negotiators had to stand firm on two counts. The hard-won recognition of women's rights needed to be defended all over again. And, more importantly, the attempt in Istanbul to reopen the debate on everything that had been gained at previous conferences had to be avoided. The European Union's negotiators took an aggressive stance on both these issues.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The fact that so much negotiating effort is expended is a good illustration of the political significance governments attach to the topics debated on such occasions. A conference may be seen as resembling the proverbial half-bottle of water  - some regard it as half empty and others as half full. One's viewpoint depends on one's expectations  -  and much disappointment is caused by a misunderstanding of how such conferences operate.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meeting the delegates</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although I am no anthropologist, I think I was able to identify three major groups of participants. First, there were the 'negotiators', who have built up a common language from conference to conference. I was surprised at the extent to which reference was constantly made, in the negotiating groups, to the 'Languages' of Rio, Copenhagen or Beijing. This is not just a question of vocabulary or syntax, but represents a genuine revolution in thought at international level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second group, to which I myself belonged, was made up of national and international officials. These are the people who, to a greater or lesser extent, prepare the conference. They then attend it and, ideally, write a mission report on returning to their offices (bemoaning the fact that few people will read their words of wisdom !)'These delegates tend to offer the harshest judgments. A common refrain is: 'We have long argument about words in parenthesis in a huge document that no one will ever read!'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The third group, which nowadays is the largest, consists of representatives of so-called civil society. Since Rio, every United Nations conference has seen the parallel organisation of an NGO Forum, and the latter's influence has constantly increased. At Beijing, the authorities banished the NGO Forum to a site 60 km from the capital, but Istanbul welcomed it with open arms on the same footing as the 'Cities Summit' and the meetings of researchers and industrialists. A more fundamental development was the invitation to NGOs and local authorities to take an active part in the working groups and at meetings. This was a 'first' in international conference history and I was struck by the motivation and competence of many of the participants, as well as by the ease with which they have adapted to the information society. Gone are the days when addresses are exchanged on scraps of paper, accompanied by the ritual 'We must keep in touch!'. These days, your business card must include your Internet Email address. Contacts are organised through networks connected to databases, and people swap CD ROMs with each other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What did Habitat II achieve?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'official' end most visible result of the Conference was obviously the adoption of the Habitat Agenda - the final fruit of long hours of work within the national committees set up for the occasion. This document, over a hundred pages in length, contains a 'World Action Plan', accompanied by the 'Istanbul Declaration'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What is not so well-publicised is the fact that many countries  -  including a number of ACPs  -  took the opportunity to publish their own national reports containing individual action plans. The amount of preparation that went into these reports revealed a high degree of motivation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Having looked at them more closely since, I have gained a somewhat better understanding of the months of work put in tens of thousands of people across the world. This reassures me that the majority of state participants will monitor the Habitat 11 follow-up very closely.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One has to recognise that the mere adoption of a text, however significant it may be, cannot be regarded as a magic formula which will change the face of the world overnight. To the impatient among us who want everything straight away, and to unrepentant sceptics, I would say this. In environmental matters there are two major periods in our recent history - the period before Rio and the period after Rio. The Rio meeting, and each subsequent conference, have been milestones in a long, coherent process of collective reflection and growing awareness. Istanbul did, in fact, keep its promises: the right to adequate shelter is now recognised internationally as the fundamental right of every human being.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The exploding city</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Stephane Yerasimos</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Istanbul. Ten million inhabitants - with double that number expected in 20 years time. Financial irregularities, a chaotic house-building sector, a lack of infrastructure and rampant speculation. One needed to look no further than the host city to find the key issues facing the Habitat Conference.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Istanbul is a city steeped in history. It is also one of the Third World's biggest conurbations. Over the last 16 centuries, it has been the capital of two great empires - the Byzantine and the Ottoman - resulting in a rich legacy of monuments and a historic centre on a par with that of Rome. From the Middle Ages to the beginning of the modern era, it was regarded as Europe's largest city. On the eve of the Second World War, it had a population of one million, but that figure has now multiplied tenfold. Almost half of its ten million inhabitants are living on a knife edge, and many are in 'illegal' housing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first big transformation of the city came in the middle of the 19th century when the Ottoman authorities opted for westernisation and embarked on an extensive management programme. By the time the Empire collapsed in 1922, much of the ancient fabric - and traditional housing -  of the city had already been lost. Under the new republic, the capital was transferred to Ankara, and the authorities stepped up their efforts at modernisation. In 1937, Ataturk gave Frenchman Henri Prost, a city planner who had helped preserve the old centres of a number of Moroccan towns, the job of devising major public works in the heart of the old city. The infrastructure was also updated and taken together, these works (which were completed during the 1950s) transformed the old walled city and its ancient suburbs (Galata and Uskudar) into a modern aggLom&eacute;ration, interspersed with ancient monuments.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mass immigration</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unlike the colonial powers who attempted to preserve the traditional character of old city centres around the Mediterranean rim and in the rest of the Islamic world, the desire of successive Turkish governments to modernise the country resulted in the disappearance of most of Istanbul's ancient fabric, and the city no longer has a compact area of old districts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The transformation of the city centre was matched, after the Second World War, by an explosion of building on the outskirts - a phenomenon characteristic of Third World countries. Improved sanitation and hygiene standards led to a natural population increase of between 2.5% and 3% per year. Meanwhile, the modernisation of agricultural practices caused a mass rural exodus. Marginalised in both economic and social terms. the people who flooded into Istanbul soon over whelmed the resident population. Today, the bulk of the people living in the city have rural origins.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The new residents began by occupying the edges of the old quarters and taking over the open spaces which remained after the ravages of an earlier fire. They then began to settle in ever-increasing circles around Istanbul, establishing the first gecekondu districts (groups of huts constructed overnight). These have been incorrectly described as shanty towns. In fact, most buildings are permanent structures and they rapidly develop into multi-storey dwellings. Most of the land on which these illegal buildings have sprung up was originally privately owned. But the elected multi-party government in power at the time was quick to spot the electoral possibilities in these areas. Each district was a reservoir of potential voters and, on the eve of each election, the parties in power would distribute property titles to the illegal occupants. They, in turn hastened to consolidate and increase their assets. This explains the emergence of increasingly densely populated districts without infrastructure during the 1950s and early 1960s</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Industrialisation, and the arrival in the city of people who used to be rural landowners (driven out by the new market economy) later created a demand for housing which the normal market was unable to meet. This has given rise to a new phenomenon of urban marginalisation, involving the illegal division of land into plots. The system involves the purchase of agricultural properties by developers and speculative builders. These are divided into small plots and resold, quite legally, to purchasers  -  who then build unauthorised structures in contravention of the normal planning rules. Often, benefiting from political alliances, the developers take control of these districts and 'convert' the votes of the people living there into cash, in return for urban investments. This enables them to consolidate their power and increase the value of their remaining stock of plots.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An uncontrolled population increase</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, a third phenomenon, linked to the growth of a middle class, began to occur in the mid-1980s, when building cooperatives came into being. Their predecessors were the corporate associations which grouped together public officials (beginning with the army and the police). These developed into ad-hoc associations enabling a group of developers to tap people's savings, thereby dispensing with the need for loans in a country where chronic inflation makes credit prohibitive. Several thousands of dwellings are often constructed at the same time, in the form of tightly packed, multiple-occupancy blocks. The requirements of multi-storey construction mean that these buildings are of acceptable quality, but the related infrastructures are sorely lacking. Entire districts are built 'in the wilds' without any infrastructural investment by the developers or local authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The city is continuing to expand, without reference to any development plan. The fifteen or so major urban schemes drawn up since the 1950s have all remained in desk drawers and the only significant construction work has been on roads (notably bridges and ring roads). These generate further uncontrolled population increases on the outskirts of the city.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the natural rate of demographic growth is slowly declining - it has just dropped to under 2% per year -  the most recent census (in 1990) reveals that Turkey now has more people living in its cities than in its rural areas. Yet the statistics also show that half of the country's people are still involved in agriculture. Given the continuing natural growth, and the fact that in semi-industrialised countries, the rural population tends to settle at around a third or even just a quarter of the total, we can assume that the drift to towns and cities will continue for the next 30 or 40 years. This trend will affect all Turkish towns and cities, be they large, small or medium-sized. But Greater Istanbul, where the majority of the country's economic and social activity is concentrated, is set to experience a doubling of its population within the next twenty-five years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dilemma for urban planners</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The problem caused by demographic changes is exacerbated by economic constraints. For a number of years now, Turkey has suffered a high (albeit stable) inflation rate of about 70% per year. This situation discourages investment in industry, and makes people take refuge in ownership of land that they can build on. Land has thus become the target of speculation by people in all social classes. Against this background, it is virtually impossible to regulate the use of land  - something which must be at the heart of any urban-development programme. An alternative is to discuss the possibility of developing a social consensus involving a more liberal approach to property speculation, recgnising that land is a source of revenue at all levels. This might entail releasing central and local authorities from any responsibility to provide services or other infrastructural investment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the present circumstances, however, any scheme to redevelop Istanbul effectively would seem doomed to failure. The only intervention which might succeed would be at the 'cleaning-up' stage - coming in after the construction of the dwellings under the conditions described above. It is only once the new inhabitants' dream of having a roof over their heads is realised that they come face to face with the harsh daily realities of living in a self-built city of nearly ten million people. They may then be prepared to make some sacrifices in order to improve their living conditions. The moment when harsh reality replaces emotion, is the only time the urban planner has the slightest chance of being listened to. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Adequate housing in the EU: rights and realities</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Misia Coghlan</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are 2.7 million homeless people in the European Union and many millions more are badly housed. But the EU is said to be lagging in taking measures to provide adequate housing - one of the internationally recognised human rights. An expert from a leading campaign group for the homeless explains.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rights</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the weeks and months leading up to the Second United Nations Conference on Human Settlements (Habitat II), much argument and debate centred around the existence of the right to adequate housing. The legal basis of this right was challenged by a handful of delegates and the arguments continued right through the Conference itself. The outcome is that the final Declaration includes a reaffirmation of states to a 'commitment to the full and progressive realisation of the right to adequate housing as provided for in the international instruments.' (see first box)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The political impact of Habitat II as the culmination of the recent series of UN Conferences has been disappointing. The Istanbul Conference was originally heralded with the catch-phrase 'housing for all'. In the course of the preparatory process, this was watered-down to become 'shelter for all' and, as has been seen, the wording of the final Declaration simply refers to existing international commitments and allows for the 'full and progressive realisation of the right.' This of course begs the question of how such a right was ever supposed to have been achieved other than 'progressively' and how meaningful such a commitment can be in the absence of parallel undertakings as to implementation and enforcement. In short, very little has been achieved in progressing international commitment to the realisation of the right.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The right to adequate housing has in fact been recognised for some time now by the Member States of the European Union, all of whom have ratified the 1966 International Covenant on Economic, Social and Cultural Rights (the most important legal basis of housing rights found in international law). Under article 11(1), the parties to the Covenant recognise, 'the right of everyone to an adequate standard of living for himself and his family, including adequate food, clothing and housing...'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The concept of 'adequacy', it is generally acknowledged, is determined at least in part by social, economic, cultural and climatic factors. Adequate housing can be understood as including the following components: legal security of tenure, affordability, habitability, accessibility, location and availability of services, materials, facilities and infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It hardly needs pointing out that commitments in international law, whether legally binding or not, remain statements of intent and are of limited practical use unless accompanied by a comprehensive legislative framework in domestic law which will secure both the access to the right as well as providing enforcement mechanisms. What, then, is the reality ? Has the right to adequate housing been enacted into national legislation and, most importantly, is the right actually being respected across the European Union?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Realities</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FEANTSA, the European Federation of National Associations Working with the Homeless, has been conducting the European Observatory on Homelessness with the support of the European Commission since 1991. FEANTSA's research findings have increasingly demonstrated both the extent and the gravity of the housing crisis in Europe: in what is one of the wealthiest subregions of the world, a large and growing group of the population is being excluded from adequate housing. (see box on next page)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moreover, FEANTSA's 1995 transnational research report (Home/essness in the European Union) has found that the right to housing does not exist in any Member State as a legally enforceable claim. Although the right is recognised in the constitution of several Member States, this remains a statement of intent and does not create any entitlement. Other Member States have adopted a different approach - housing legislation in the United Kingdom, for example, does create an obligation on the local authorities to provide housing for those homeless people assessed to be in priority need and found to be unintentionally homeless. There is no sign of convergence in the ways EU Member States address the right to housing and housing exclusion in their national legislation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The right to housing is not addressed in EU legislation as a legal principle and Member States have exclusive competence to deal with housing issues themselves. There is thus no overall European housing policy, nor is there yet any European policy on homelessness. FEANTSA has, however, identified common trends throughout Europe which have contributed to the escalation of homelessness and the lack of adequate housing provision.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The overall European trend has been an increased reliance on the competitive market to meet all housing needs, with an unwillingness on the part of government to commit public resources to assist lower income groups, who are therefore confronted with the limited choice available to them on the open housing market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The supply of housing has been undergoing change throughout Europe. In all countries, owner-occupation is on the increase, with tax relief generally being offered as an incentive. The private rented sector, on the other hand, has continued to decline. Social housing has generally suffered from cuts in funding. The result is that there is a shortfall in the supply of affordable housing for rent and rents have become correspondingly higher. It is clear that the competitive housing market cannot and will not meet the needs of the increasing numbers of people without the resources to afford market rents.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The type of housing required has also changed: demographic trends have meant that households are getting smaller but more numerous - thus, there is a need for more but smaller dwellings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The problem has been exacerbated by the lack of an overall strategy either at European level or, indeed, often at national level, to meet the realities of structural changes on the labour market. Indeed, in some countries, the increase in long-term unemployment has been accompanied by an erosion of social protection systems. Faced with escalating demand for longterm welfare assistance, the authorities have often responded by tightening up on eligibility criteria in an attempt to cut or limit benefit payments, with shortterm palliative measures to deal with emergency cases. Thus, increasing numbers of people living on or under the poverty threshold, coupled with the deregulation of the housing market, have led to severe housing stress and increased vulnerability to homelessness.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finland sets an example</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finland is one EU country tackling the housing problem. In 1987, the International Year of the Homeless, the Finnish government announced its intention to eliminate homelessness. At that time, the number of homeless people was put at close to 20 000. The programme for the development of housing set the objective of making 18 000 homes available for the homeless over a period of five years. Special funds were set aside in the national budget to permit the local authorities and other organisations to purchase housing for the homeless. State loans for the construction of housing for rent were made available to municipalities with a large homeless population. In under ten years, the number of homeless people in Finland has been reduced to half what it was in the mid-1980s. Finland now enjoys a comprehensive system of carefully targeted housing supply, housing subsidies, benefits and allowances and housing is seen as an integral part of a multi-dimensional strategy to combat poverty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For one in twenty citizens of the European Union, the criteria which, as a whole, constitute adequate housing remain inaccessible. Yet at Istanbul, the EU voiced its determination to make an important and constructive contribution to the implementation of the Habitat objectives. This included an acknowledgement that increased attention should be paid to people living in poverty and that appropriate action should be taken by governments at all levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European housing ministers were due to meet informally in Dublin, on 24 and 25 October of this year, specifically to tackle the question of 'housing for socially excluded people'. The time has come to devise and implement coherent strategies to prevent housing exclusion for low income groups. The market has neither the ethics nor the long-term planning capacity to do this; it remains the responsibility of the state. It can only be hoped that the housing ministers will recognise this and agree on the necessity of protecting housing as a product and as a service from the competitive market, at least for vulnerable groups. The housing ministers have been holding informal meetings since 1989. This year's meeting provides the opportunity, particularly in the light of the Habitat II debate, to exchange information on effective measures to help low income groups access and maintain a home. The result should be the drafting of a number of concrete goals to be achieved within a realistic time-scale.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Homelessness in Europe is not on the scale seen in other regions of the world - with the development and reinforcement of effective preventive policies, based on proven and cost-effective welfare models existing in some Member States, the housing crisis can still be contained. In short, where there is a political will, there is a way. Europe has the potential to serve as a model of good practice to the rest of the world and should do so, more especially in the light of all that was - and wasn't  - achieved at Istanbul. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">References</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Is the European Union Housing its Poor ? Dragana Avramov, Catherine Parmentier and Brian Harvey, FEANTSA, Brussels 1995 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Homelessness in the European Union, Dragana Avramov, FEANTSA, Brussels 1995</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Invisible Hand of the Housing Market, Dragana Avramov, FEANTSA, Brussels 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Cities of the Third World</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Francis Cass</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In ten or so years' time, more than half the world's population will be living in built-up areas and, according to UN figures, by 2025 nearly two thirds of us will live in towns and cities. This is not a complete surprise -  over the last few decades, the ratio of city dwellers to rural people has consistently moved in 'favour' of the former. In 1950, 29% of people were city dwellers. Since 1985, the urban population has exceeded 40% of the global total.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Today, we are witnessing an acceleration in demographic growth, especially in developing countries. Of the 2.6 billion people who currently live in towns, 1.6 billion live in the world's least developed regions. By 2025, the urban population of the Third World will have risen to 3.2 billion, out of a global urban population of just over 4 billion. On the basis of these figures, it is estimated that the number of urban dwellers in developing countries is increasing by approximately 150 000 people each day! In Cape Town in South Africa, for example, as in many towns and cities of the Third World, this demographic explosion can actually be seen happening. All you need to do is drive regularly along the N2 motor way  - which passes through the shanty towns of Khayelitsha and Guguletu -  to see how, week by week, the makeshift dwellings are spreading - gradually expanding to every available plot of land. The same scene is repeated in all of Africa's large towns. In Cot&eacute; d'lvoire, the population of Abidjan rises by 400 inhabitants a day on average. In Gabarone, the capital of Botswana, whose population was barely 3000 at the time of independence in the 1960s, the population is increasing by 18% each year and today 160 000 people live there. Such growth is often accompanied by widespread indifference on the part of local authorities. Such indifference is due, in particular, to a shortage of financial resources, but it also reflects an absence of political will to do anything to tackle the problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Demography and poverty</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The demographic explosion which has taken place in the urban areas of developing countries is due to three main factors: natural population growth, rural emigration to towns and cities, and (less importantly) the redefinition of the administrative boundaries of built-up areas. The first two factors are equally to 'blame' but in future, it is predicted that rural depopulation in Africa will become the single most important element in urban population growth. This will be especially true of countries where there is rampant rural poverty. In this context, we need to recognise other circumstances, such as famine, desertification, a shortage of cultivable land and conflicts, which serve to exacerbate the phenomenon. If people living in the countryside decide to migrate to towns, it is because they are looking for a better life and hope to improve their standard of living. Few succeed. According to a World Bank study, 50% of people in abject poverty will be living in urban areas by the year 2000.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The effects that urban poverty has on the environment are often dramatic. The reverse is also true. A damaged environment constitutes a daily hazard for town and city dwellers, in particular the most destitute. The precarious nature of their living conditions means that only in extremely rare cases are these people able to guard against the degeneration of their immediate surroundings. Driven to the outer limits of the towns - where even basic infrastructures such as sewers and the collection of household waste are often lacking, the poorest sections of society are left to fend for themselves. Local authorities have neither the means nor (often) the inclination to do anything to help them. Even those who are comfortably off and who can afford to give part of their income to safeguard their immediate environment (thereby protecting themselves to some extent) cannot escape the consequences of more general ecological problems such as air pollution and the contamination of water supplies. Living in a modern house in a well-to-do district is simply not enough. It is not possible to shield oneself completely from the problems created by environmental destruction. For example, even an unofficial rubbish tip, located several kilometres away from a residential area, can have disastrous effects on groundwater - meaning that sooner or later, the quality of the drinking water will suffer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Towns gasping for water...</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At present, the vast majority of Third World towns are facing a series of ecological problems which directly or indirectly, affect the lives of their inhabitants. According to the World Health Organisation (WHO), 220 million city dwellers have no access to drinking water and 420 million have no latrines. It does not take much to imagine the potentially catastrophic health consequences of such a situation - in which people are forced to drink and irrigate their land with water from contaminated sources. The WHO has estimated that three million children died during 1993 as a direct result of diarrhoea, and that nearly two million of these victims had consumed drinking water contaminated with faecal matter. In developing countries, 90% of waste water is poured, completely untreated, into rivers, lakes and coastal waters. Again, one can easily imagine the impact on marine flora and fauna, and on the health of those who eat the products fished from these waters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">...and gasp for breath</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As far as air quality is concerned, the WHO intimates that more than a billion city dwellers throughout the world breathe highly polluted air. For the most part, this pollution is generated by industry and motor vehicles. A small improvement has been recorded in the urban areas of developed countries, but air quality in the towns and cities of the South has deteriorated considerably during recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are many reasons for this. First, there has been an increase in industrial activity, mainly concentrated around towns and cities. This is a result of economic development, but also of the fact that many factories - including some with the worst pollution records  - have relocated from the North to the South, where legislation governing emissions is less stringent. Second, in contrast to the trends seen in developed countries - where cars are usually well-maintained, (running on unleaded petrol and rarely more than five years old) motor vehicles in the Third World -  whose numbers are increasing significantly  -  are frequently old, badly maintained and run on leaded fuel. According to the World Bank, 95% of the lead polluting the air in the towns and cities of developing countries comes from vehicles which run on leaded petrol and studies carried out on the subject have revealed concentrations of up to 1.5 microgrammes of lead per cubic metre of air. In North America and Europe the concentration varies between 0.2 and 0.8 microgrammes per cubic metre.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another problem facing towns and cities in the southern hemisphere arises from the enormous amounts of waste they produce and from the fact that they have few treatment facilities. In many cases, the rubbish is not even collected and is left to accumulate into the piles which can often be seen on the edges of shanty towns. This accumulation of refuse encourages the proliferation of certain diseases and poses a real threat to the health of residents both nearby and further away. In addition to this ordinary, everyday waste, the countries of the Third World have to deal with problems generated by toxic waste  - not just their own, but also that which is 'exported' there by industrialised countries. Needless to say, the towns which actually have the means and facilities needed to treat this highly polluting waste are few and far between.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Linking development with environmental protection</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While environmental problems have a direct impact on human health and on the natural world, they also entail huge economic costs. The effect of pollution on human health translates into ever-increasing health costs and a decline in productivity. And it is not only city dwellers who suffer the consequences of a deteriorating urban environment. Depending on their size, the degree of industrial activity and population concentration, towns and cities pollute and destroy areas well beyond their own administrative boundaries. They swallow up enormous amounts of natural resources, suck their hinterlands dry and spit out 'what is left'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nowadays, there is an increasing global consensus over the need to tackle these growing problems rapidly. This was seen clearly at the Habitat II Conference in Istanbul. Most cities of the southern hemisphere urgently need to get to grips with their numerous ecological problems - the alternative is to sink further into chaos. In a similar vein, it has become obvious that some sort of balance must be found between economic development and safeguarding the environment - and that considerable investments are needed to achieve this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Solutions do exist. Recycling projects, for example, could provide jobs for large numbers of town and city dwellers, as well as cleaning up the environment. Governments of industrialised nations should take the necessary steps to ensure that their toxic waste does not end up in the rubbish dumps of the countries of the South. Authorities in urban areas in the Third World should set aside more of their budgets to help the most underprivileged sections of their populations, so that they can manage their own environment. Local authorities should also respond more efficiently to the basic needs of impoverished districts, not least by building roads and sewer systems, by ensuring that rubbish is collected and by guaranteeing all people access to drinking water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Last but not least, a concerted effort - especially a concerted financial effort - should be made by decision-makers at the local, national and international levels. We need to recognise that environmental damage is a phenomenon which rarely confines itself to the local level. Sooner or later, it becomes a problem for all of us. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">When conservation is at odds with the local population</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Hendrik Smets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The clash between the interests of people living on the edges of the Zakouma National Park in Chad and the authorities' attempts at conservation illustrates the situation facing many other nature reserves in Africa. This article argues in favour of a form of eco-development to suit everyone.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the Zakouma National Park (PNZ) WAS officially set up in 1963 (it had been at the planning stage since 1956), the area it covered meant that local people had to be moved -  but the promised compensation was never paid. During the second phase of the PNZ's relaunch, financed by the European Development Fund (EDF), a perimeter path following the 1963 boundaries was marked out, but local villagers opposed this, regarding it as an extension of the Park's area. Subsequently, they rejected a move to build a dispensary in a village located at the edge of the park on the pretext that such a structure would again constitute an extension to the reserve's land.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Conflict between the itinerant stockbreeders of the region and the authorities has simmered for many years. The latter have shrunk from enforcing the 1963 law on transhumance corridors which applies to the fringes of the national park. Under this law, it is prohibited (in principle) to gather wood, hunt for game, fish, or gather honey and other natural produce. The result is a tendency among locals to view the PNZ as an adversary rather than a potential partner in development. Safari tourism is developing too slowly and is not leading to sufficient benefits for example, from a craft industry, or more general redevelopment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the second phase of the project was at the planning stage, its organisers recognised that, in order to guarantee the park's future, support had to be given to the people living on its edges. A high-level 'cooperation committee' was therefore proposed. The membership of this committee, which would sit in N'Djamena, was to include ministers, directors-general, park authorities and Commission representatives. Unfortunately it has not yet been brought into operation. By contrast, the local authorities and park management have been able to set up their own committee which met for the first time in January 1996. This body has helped to tackle some of the most sensitive problems.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The second phase also saw the implementation of a series of microprojects. - school renovations, a dispensary, a bridge, the sinking of wells, a dam, a mill and a nursery. But these were set up without preliminary study, and no arrangements were made to sound out the views of the local people, or the form of development they would like promoted. Understandably, local hostility was encountered and the projects cannot, in any real sense, be viewed as offshoots of the wider PNZ scheme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The future</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project has not been extended to a third phase. Because of this, there is a risk that the capital invested -  and the positive results that have been achieved - could be lost altogether. Should any donor choose to 'pick up the baton' in future, they will need to recognise the key imperative of creating a symbiotic relationship between the park and the local population. To do this, there must be an awareness-raising effort, undertaken in parallel with any eco-development programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the first instance, a higher profile should be given to institutional issues. In particular, the cooperation committee in N'Djamena must be able to act, where necessary, as an appeal or arbitration chamber to deal with any disputes which cannot be resolved by the local authorities' committee. The latter, of course, would continue to meet on a regular basis to discuss any problems encountered.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, there should be campaigns to disseminate information and train local people who are in daily contact with the park's environment. The aim here would be to make them progressively more accountable for conservation and the exploitation of natural resources (cutting wood, gathering produce, hunting, fishing, and so on). They must also gain a better understanding of the effects of poaching and desertification. Above all, such campaigns should seek to convince the people of the benefits they stand to gain from the park, if they continue to respect its integrity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this context, some lessons might be drawn from a regional project dating from April 1987 (which was never fully implemented). This was aimed at halting the advance of the desert in the northern Central African Republic and southern Chad. The component of the project which is of interest to the present discussion was its programme to increase public awareness  -  which involved training organisers, preparing and disseminating information (posters, videos, films), organising information tours and giving support to the Training and Environmental Information Programme of the CILSS (Inter-State Committee to Combat Drought in the Sahel), of which Chad is a member.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One could also learn something from the approach adopted by the Manda National Park which is situated 270 km from Zakouma. This has 'volunteer villagers' appointed by the chiefs of the four cantons making up the park zone, who know the territory well. The volunteers take part in information, awareness and monitoring operations alongside national park and animal reserve employees. Dressed in pale olivegreen uniforms, they cycle between the villages and encampments, providing a link between the villagers and officials in N'Djamena. They have an invaluable role in convincing village people of the advantages of cooperating in the development of the park and its surrounding areas. And the cost of a volunteer is just CFAF 5 000 (ECU 7.5) per month.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Eco-development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Returning to the PNZ, it is true that a small proportion of the population already benefits from the park's existence. Wages are paid to the patrols, and the permanent and seasonal workforce, while micro-projects have been set up. The park pays traders, artisans, farmers and stockbreeders for certain services and there are some tourists. But the bulk of the population does not see these advantages having been largely excluded up to now.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any future eco-development programme should therefore aim at reducing pressure on the park in order to guarantee its long-term integrity. This would obviously need to be preceded by a clear definition of the action to be undertaken, but in the meantime, it might be useful to offer a few guidelines. The programme should include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - a series of flanking or support activities providing infrastructure and equipment, such as a dispensary, a school, paths, wells and carts;</P>
+<P ALIGN="JUSTIFY"> - a food-security programme providing for the conservation of agricultural areas, as well as measures to prevent erosion and safeguard harvests (cereal banks, stores, gardens, agro-forestry systems and pest control);</P>
+<P ALIGN="JUSTIFY">- a project to promote natural resources such as fisheries, gum arable, honey, and straw fodder;</P>
+<P ALIGN="JUSTIFY">- a wood/energy management programme providing improved hearths and brick ovens, and the organised gathering and use of supplies;</P>
+<P ALIGN="JUSTIFY">- development of the craft industry and training of tourist guides.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If, in a third phase, an awareness and eco-development programme could be successfully implemented, the Zakouma National Park should be able to look forward to a brighter future. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">A new 'eco-centre' in West Africa: Two Presidents amid the dust</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In April, on the eve of the International Conference on Human Settlements, the first West-African eco-centre ('Ecopole`) was opened in Dakar. It was set up by Enda, one of the few international non-governmental organisations of significant size based in a developing country. The 'eco' refers to two things - the economic life of the ordinary people and the ecological aspect of the centre. One of the most memorable images of the opening ceremonies was the sight of two Presidents  -  Abdou Diouf of Senegal and his Malian counterpart, Alpha Oumar Konare  -  striding through the dust in a working-class district of the Senegalese capital. For supporters of the 'Ecopole', the event epitomised the fight back of the popular urban economy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The dust which settled on the Presidents' fine clothes was that of the Rail district, so called on account of the railway which cut through it in former times. Built in an old, disused factory, the airy, clean 'eco-complex' adds a touch of style to this semi-industrial, semi-shanty town district. The old buildings were redeveloped with the help of members of some two hundred cultural and sports associations, working in partnership with the NGO. They used recycling techniques of which they are past masters.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The complex had, in fact, been in operation for some time prior to its formal inauguration, but the ceremony  -  which attracted the interest of international press agencies - provided an opportunity to publicise the venture. Since its formation in 1972, Enda has been working to give a higher profile to the 'popular' economy (they eschew the term 'informal') in Senegal and elsewhere. The NGO has focused, in particular, on trying to encourage those involved in the popular economy to collaborate more closely and integrate their activities, as well as on boosting awareness of what is happening in similar communities elsewhere. The opening of the 'Ecopole' provided a showcase for the achievements of the popular economy in West Africa, as well as a forum for dialogue. And it now has the seal of approval of two Heads of State, not to mention other VlPs who made supportive statements at the opening.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The popular economy fights back</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For the inaugural ceremony, the former sheds - now converted into airy vaults clustered around a central structure - hosted a major presentation of the popular economy in a series of exhibitions. It is a kind of 'eco-museum' with pride of place going to recycling. Exhibits ranged from 'fabrics' made of old plastic bags crocheted together, to toy sports cars fashioned from wire and tin cans. And the reaction to the exhibition went beyond the usual, somewhat condescending appreciation of 'the skill of these people'. There were, of course, some curios of interest to tourists such as the aforementioned children's toys, small metal suitcases and papier-mache boxes. But there were also works of art, masks and sculptures, which captured something of the nature of this 'recycling culture'. Indeed, international art critics at the Biennal Festival of Contemporary African Art, taking place in Dakar, were talking of a new artistic trend, also seen in the work of artists from other regions, based on reclamation. This, of course, begs the question: 'Has art not always been based on reclamation?'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Interesting though the subject may be, the artistic and aesthetic qualities of the fruits of recycling are of only secondary importance when one is dealing with everyday objects. The important thing is for deprived populations to use what means they have to survive and to improve the quality of their lives. Tourists may choose to buy decorative and unusual objects on the reclamation market, but more significantly, families can obtain essential items such as kitchen utensils, ploughing implements, carpentry tools and stoves  - all cast from vehicle wheels and bits of scrap metal. They are made using small forges and furnaces the size of a large saucepan, or cut from otherwise unusable pieces of metal sheet. The craftsmen can also supply somewhat more sophisticated equipment: ploughs, brick-moulding machines or soldering irons. One of the exhibitions staged at the 'eco-centre' was a co-production with the Quebec Museum of Civilisation and the Canadian Embassy in Senegal, which had previously toured Canada and four African countries. Entitled 'Africa's ingenuity', it covered a wide variety of styles, ranging from the utilitarian to the artistic. It will, in due course, form the eco-museum's centrepiece. Another temporary exhibition was called 'Antuka: Kinshasa, the art of living in the city', and this paid homage to the Zairean capital - a place which, of necessity, has become one of the 'capitals' of resourcefulness. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jet engines and donkeys</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One hopes that the two Heads of State found time to admire the jet engine constructed by a young Zairean from nothing but reclaimed materials: parts taken from cars, mopeds and unwanted metal sheet. And it works -  not on an aircraft, naturally, but on the bench. This engine is now a legend. Its constructor has apparently already been spotted by a European head-hunting company and offered a job in France. This is part of the 'fight-back' referred to by Enda officials, in which some recognition is finally being given to the economies of the world's poorest populations. During his visit, the President of Senegal issued a plea for greater integration of the informal sector into the overall economic fabric. His remarks were revealing: the West-African 'Ecopole', as its name implies, covers an entire region, and assumption of responsibility by the local people for the shanty towns and poorer districts has lifted a significant burden from central government.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another example of this trend is found in the Malian capital, Bamako, where a hundred or so local community associations have banded together to take over full responsibility for the collection of domestic waste. This organisation, whose initial efforts were ridiculed, is now fully operational. One wonders whether the authorities in other cities have heard about Bamako's scheme. What about Port-au-Prince in Haiti, for example, where they are struggling with mountains of rubbish which they cannot deal with owing to a lack of resources ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since their inception, economic interest groupings (ElGs) such as the one in Bamako have helped bridge the gap between the 'formal' and 'informal' economies. They rely on collaboration and their enterprise is exemplary. At the outset, the inhabitants of poor districts, acting on the initiative of the ElGs, expressed the desire to improve their neighbourhoods by organising refuse collection. They used whatever means were available - which in most cases meant donkeys and carts. In more central districts, delivery tricycles were employed for collection. Specially constructed, tipper-style carts, each costing CFAF 200 000 (ECU 300) have since been brought into service. The price of a donkey, by contrast, is about CFAF 50 000 (ECU 75). The animals and equipment belong to the ElGs and are looked after and maintained by them, with carters receiving a monthly income and social security benefits. A number of groups were set up eight years ago, promoted by young technicians, academics, architects and economists. Those who benefit are known as 'subscribers', with each family paying a contribution towards the service. Managing equipment and collecting contributions both require a well-structured administrative department, but the administrators are not confined to their offices. As employees of the business, they see nothing wrong in lending a hand and assisting the carters. In short, it is an enterprise based on a whole new approach. The contribution made by families varies according to the EIG and the district in question, but it is generally set at around CFAF 750 (ECU 1.2) per family per month. The price of the service may be up to twice this sum in the so called 'quartier des Blancs' (the 'white' district). In theory, the state ought to be subsidising the ElGs, but in practice, this does not happen. The authorities do not even fulfil the task allocated to them under agreements signed with the ElGs, which is to transport the refuse from temporary dumps to a final site. According to local people, the problem is not that the local authorities do not have the trucks available for the task. The vehicles, they allege, are used instead for the officials' own private purposes. The ElGs are forced to plug the gap as far as possible. At present, they appear to be the only ones taking any interest in waste recycling, aware as they are of the risk to the environment posed by permanent dumping grounds, and of the specific danger that the water table will be polluted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A modern concept of the 'informal' economy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'informal' economy is increasingly becoming the norm. According to an Enda survey, 90% of businesspeople in Senegal started out in the informal sector. The conclusion would seem to be that the necessary training for dealing with current conditions is not to be found in the formal education system. The popular economy is not out of step with the modern economy as some would claim. Indeed, one could argue that it is the modern economy, as adapted to today's conditions. The increasing involvement of ordinary people in the economic circuit, which they enter via parallel routes, should also guarantee the continuation of Africa's experiment with democracy. We have seen attempts by former dictators to backtrack in this respect. They cite as evidence, the failure of technicians trained abroad - the 'darlings' of the West who, they claim, are at the beck and call of international institutions. But a return to the past, as exemplified by the regime of Nicephore Soglo, strikes fear into many people. Their response is to generate productivity, social cohesion and political stability through the popular economy, by way of compensation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is suggested that small-scale traders, who distribute hardware from south-east Asia, constitute an obstacle to the development of local production. But there is a confusion here between cause and effect. In fact, the popular economy appears more as a response to the lack of consumer goods. The problem lies with the so-called 'major' local entrepreneurs who favour the import/ export business over production, and with the banks that prefer to focus on larger businesses (influenced by anonymous officials or major economic interests) and have no time for small-scale operators.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Rail district in Dakar has a long history. It is overpopulated, having been settled by workers and artisans, and their influx made it the most expensive poor district. It is a place where the rents, for even the humblest hut without water or electricity, accounted for most of the inhabitants' meagre income. This situation led to the appearance of squatters who built their own shacks on waste ground. For these people, the threat of eviction loomed constantly like a sword of Damocles. The district is also home to a large number of maids and other household employees. Two thousand of these people (from Rail and other parts of the city) set up their own friendly society to which they pay regular contributions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is a world which has always teemed with good ideas: artisans recycling materials, blacksmiths working at the forge and so on. In this sense, nothing much has changed, but the big difference now is that the people have organised themselves. In so doing, they have been able to provide training for adults and children in makeshift schools, and to purchase and renovate old huts  - having extracted a guarantee from officials that such moves would not be opposed. Nowadays, those who live in the district no longer pay rent. However, it will only be possible to measure the true success of the Rail district when there is no longer a need for an organisation like Enda to ensure that it operates effectively.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some years ago, a former sailor, who always dreamed of being a teacher, set up his own school in the main street which runs through the district. He worked on the pavement and in the car park in front of a furniture store, teaching children in the morning before the offices opened and adults in the evening after they had closed. Enda recently offered him a few pieces of furniture, but for many years, he received no help other than a few pieces of chalk, worn-down pencils and the remains of exercise books from his 'colleagues' in regular education. This is a man who has to supply his pupils not just with teaching materials but also sometimes with food. This year, with his voice catching in his throat, he told us that one of his former 'street pupils' is going to college. How can the learned economists calculate the value of this devoted 'academic'? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The RDP challenge</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Professor Willie Esterhuyse</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The cornerstone of South Africa's Reconstruction and Development Programme (RDP) announced by President Nelson Mandela on May 24 1994, shortly after taking office, is people-centred development with an accent on modern infrastructure, health, education, housing and sanitation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lessons have already been learnt from teething troubles.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The RDP is the government's response to the massive socio-economic needs of the bulk of the South African population. It is foremost a strategic framework aimed at human development and restructuring the country's economy. It involves housing projects and programmes to improve the socioeconomic infrastructure covering clean water, electricity, public works, schools, urban renewal and primary health care. Empowerment programmes have been developed, for example; micro and small businesses, support for emergent farmers and skills training.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of the main achievements of the RDP has been to sensitise South Africans to the plight of the poor. Apartheid, amongst other things, succeeded in keeping this out of sight, effectively locking the poor out of the system. A veil of ignorance prevailed among the privileged class. The RDP tore away the veil and has led to a willingness to participate in development and reconstruction programmes, especially in private sector circles. It is succeeding in prioritising South Africa's socio-economic challenges, as well as mobilising funding and organising a common and sustainable approach. Its most important achievement to date is probably the idea of partnerships in development between the state, private sector institutions and non-governmental organisations. Through the RDP, South Africans have accepted that they will have to 'run with the development ball'. They are also aware that the state cannot go it alone, nor should it act as a 'super' development agency. Thus, a very high premium is put on involving the private sector and other actors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Problems</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But many problems have already been encountered. Unfortunately, the RDP was seen by some as a quick-fix solution to South Africa's socio-economic difficulties. Expectations over delivery were too high. Red tape and a growing bureaucracy stifled the initiative early on. Frustrations among the poor quickly surfaced. Many of those who wanted to participate, and applied for RDP funding, were unable to develop viable business plans - a strict requirement to get funds. The launch of projects was further complicated by the absence, at one stage, of legitimate local and governmental structures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But important lessons were learnt from the initial phases, in particular the need to involve people on the ground from day one - starting with the identification of needs, the design of a specific project and its execution. It was accepted that process is more decisive than the product. A second lesson was that a separate RDP office, with its own Ministry, complicated matters as far as delivery was concerned, tending to centralise development. This led to the announcement by President Mandela on March 28 1996 that the RDP office would be closed down. RDP programmes were thereafter integrated into the main budget administered by functional government agencies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another very important lesson was that socio-economic development and reconstruction had to go hand in hand with a dynamic macro-economic strategy - made public earlier this year. It was realised that one cannot have good projects in a bad policy environment - to quote a World Bank report.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In fact, it is generally accepted that the RDP, on its own, cannot launch South Africa on a road to sustainable and vigorous economic growth. We needed a twin-track approach.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Progress</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The RDP has notched up a number of successes. The provision of clean water to rural and urban communities has gone a long way under the leadership of Minister Kadar Asmal -  highlighting the fact that leadership strengthened by solid management, does make a difference. The electrification programme for low-income households, involving the parastatal, Eskom (Electricity Supply Commission), is another success story. The same goes for the Presidential projects, such as free health care for expectant mothers and infants, and some of the nutrition programmes. But the provision of housing for low-income groups has been less successful than anticipated. Rent and services boycotts, as well as unemployment, are some of the reasons for slow progress. Job creation is another problem area. It is envisaged that visible progress in these areas will emerge in the course of next year. Establishing a culture of learning is another great challenge. A restructuring of the educational system is underway, but progress is restricted by severe financial constraints.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Implementation of the RDP, the best strategic framework for socioeconomic development South Africa has ever had, will be a long process. Courage and sustainability are key issues. How to lead and manage expectations, without undermining hope, is a great challenge. The meaningful involvement of donors is another issue. Joint ventures between donors, the private sector, government agencies and communities are happening. Most of these, having been carefully negotiated and executed, are already making a significant difference.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But spectacular progress should not be expected. Development, reconstruction, and growth of the kind that South Africa needs, will take time. However, the lessons and achievements of the past two years have put South Africa in an excellent position to change the country's socio-economic environment. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Targeting South Africa's poor</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Christine Thompson</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The provision of basic amenities for the urban and rural poor rank high on the agenda of the EU's aid policy towards South Africa. In this respect, European cooperation has been tailored to fit with the government's own Reconstruction and Development Programme.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Programme for Reconstruction and Development (EPRD) is the name of the current EU development assistance package to South Africa and it seeks to help improve living conditions for all South Africans. The programme earmarks ECU 125 million a year until 1999. It has evolved from the so-called 'positive measures' programme launched in 1985 to help counter the negative effects of sanctions and to help the victims of apartheid.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under a Declaration of Intent drawn up with Minister Jay Naidoo, then at the helm of South Africa's Reconstruction and Development Programme, it was decided that EU aid should be channelled to the key sectors of education and training, health, rural development, water supply, urban development, economic cooperation, trade and investment promotion, and the promotion of good governance and democracy. In each of these areas, the EU actively encourages a partnership effort between governmental structures and NGOs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2.5 million homes wanted</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over 60% of South Africa's population is urbanised. The apartheid government's restrictions on home ownership in urban areas for the past four decades resulted in a housing backlog estimated at 2.5 million units, with demand growing by 200 000 units per year. Estimates vary, but approximately seven million people are believed to be living in informal settlements throughout South Africa on land occupied both legally and illegally.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improved housing and sanitation are seen as priority areas in urban and rural development. Between 1991 and 1996, the EU has funded 18 projects in the urban development sector valued at approximately R303.1 m (ECU 52m). The Urban Sector Network (USN) and the Cato Manor Development Programme are typical.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU is providing the USN with a total of R26.2m (ECU 4.5m) between 1995 and 1998. The USN is a national network of nine affiliate NGOs, and its aim is to improve living conditions for the urban poor. The beneficiaries of the programme are city dwellers earning less than R2000 (ECU 344) a month and there is a particular emphasis on households with monthly incomes of under R800 (ECU 137) a month.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Through integrated, community-based development, the USN and its affiliates provide technical support and service provision to urban development projects, focusing on housing, local government transformation, skills transfer, project planning, facilitation, information dissemination, education and training.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Cato Manor Development Programme received funding in 1995, also for a three year period. The EU has contributed R117.6m (ECU 20.2m) to the project. Cato Manor, an area in Natal near Durban, was the location of the largest forced resettlement scheme implemented under apartheid. Today, it is the first area targeted for integrated housing in a former white township.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The overall objective of the programme is to improve living conditions through a policy that strengthens the delivery system for infrastructure and housing. The programme anticipates providing the community with primary and secondary schools, sports fields, community halls, libraries and a community health centre. Access to housing finance will be improved and opportunities for income generation provided through a vocational training centre and small-scale industry workshops. In addition, provision is being made to improve management and general policy-making capabilities. By continuing to fund such projects, the EU is working with the South African government to improve the living conditions of the urban and rural poor. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">'Guardians of Eden'</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Theatre for Africa, a performing group from Southern Africa, went on tour this autumn to put across the message that the exploitation of Africa's fauna should remain in the hands of rural communities. They did this with a powerful mix of words, dance, mime and song, in a play entitled Guardians of Eden '. The Courier met the author and cast on the Brussels leg of their tour. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The setting for the Brussels' performance was the 'Grand Place' (Grote Markt). With its ornate mediaeval architecture, this famous square in the centre of the Belgian capital could hardly have been more removed from the theme of the play - which is about conservation and development problems in Africa and empowering rural people to manage, use and benefit from the wildlife around them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The play was commissioned by the Southern Africa Sustainable Use Specialist Group (SASUSG) and the idea was that it should reach as many people as possible in the run-up to the World Conservation Congress planned for Montreal in October 1996. South African writer and former economist, Nicolas Ellenbogen, travelled throughout Southern Africa to recruit the all-African cast. Many examples of cultural imperialism leading to the destruction of habitat, highlighted in the production, were actually encountered by Mr Ellenbogen as he travelled through the region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The play opens with a spirit medium summoning representatives from villages in several African countries to discuss the threat to their survival. The actors display their athletic skills performing mimes of the abundant wildlife with simple props, as the history of Africa is recalled from the dinosaurs to the present day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A parable is then told. An old chief informs his three sons that to prosper in the 21st century, the village must change. He instructs them to return a year later with ideas for prosperity, which will be discussed in an indaba (debate). Each chooses a different path. The wheeling and dealing first son seeks out quick fix schemes with NGOs and various city authorities. The second son learns from the difficulties of city life and comes up with a blend of simple wisdom and new ideas. The third spends his time in beer halls -  and his revelry provokes roars of laughter throughout the performance.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Arriving back in his village after almost a year has elapsed, the second son finds that his older brother returned several months earlier to implement his money raising projects. Enjoying the cash benefits of the scheme, the men of the village do not want to hold an indaba. They are forced to do so by the women and Midzimu - the old chief. The audience is then asked to vote and there is a unanimous show of hands for the second son who symbolises the sustainable use of natural resources. The dissolute third son, meanwhile, is eaten by a crocodile.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ivory ban fury</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the message goes out to developers and donors to respect rural autonomy, the play also raises serious questions for Europe's politicians. The frequent appearance of the destructive elephant, in the course of the play, allows Mr Ellenbogen to vent his anger at the ivory import ban imposed by many European states. 'I am furious about the ban', be told The Courier, 'as it is having a profound effect on the daily needs of the people.' He rejects the argument that it helps conservation, insisting that; 'with a stroke of a pen, you reduced the value of the elephant.' The playwrite argues that local people need to see wildlife as economically and socially valuable. Otherwise, they will adopt new forms of land use which will result in the extinction of the species. He also draws attention to the growing black market in ivory in Southern Africa since the ban was introduced.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'token' South African - symbolically played by the only woman in the cast - is given a 'rough time as the baby of Africa', says Ellenbogen. The play also contains numerous swipes at the donor community which frequently gives grants, without, it is said, any respect for local traditions. The Swiss doctoral student researching the potential for producing goat's cheese in Africa exits the stage squealing after asking a goat herder what he does with his animals. 'We slit their throats', is his reply.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guardians of Eden was first launched at the Grahamstown Arts Festival in South Africa in July. It was performed in Zimbabwe and Kenya, and won a prize at the Edinburgh Festival 'Fringe' in August. From there, it moved to Frankfurt and Geneva before reaching Brussels. It was due to be performed in Antwerp, London and several American cities before a final staging at the Montreal Congress in October.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The play is in English and the languages of Southern Africa, but Nicolas Ellenbogen believes it can be readily understood by his multinational audiences. For him, the message - that local people must have the power to manage their own wildlife on their own land - needs no translating. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Analysis</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Europeans and development cooperation: there are opportunities too!</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Stelios Christopoulos</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If politicians in Europe see jobs as their primary concern, it is probably because the citizens regard unemployment as their most serious problem. In the Europe of the Fifteen, the average unemployment rate was about 10% in 1985 dropping to 7.5% in 1990. By 1994, it had risen to a record high of more than 11%. By contrast, unemployment in the United States fell below 6.5% in 1994 and the figures for 1995 reveal a continuing downward trend. In Japan, the proportion of people without work remained below 3% in 1994. Assuming there is no change in current trends, the most recent demographic projections suggest that there will be 70 million people over the age of 65 in the EU by the year 2020, out of a total population of 348 million. This is 18 million more than there are today. The proportion of over-65s is, thus, projected to rise from 15% at present to 20% in less than 25 years. These two elements  -  an ageing population and ongoing structural unemployment - clearly reveal that European society lacks a degree of dynamism compared with its competitors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In an attempt to address this problem, albeit partially, the President of the European Commission, Jacques Santer, launched a European employment pact in April 1996. There are three underlying reasons for this initiative -  Europe's endemic unemployment, the need to reestablish a climate of confidence as a prerequisite for renewed investment and consumption, and the need to fit the creation of the single currency into an overall economic strategy aimed at increasing growth, competitiveness and employment in Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'I'm young, help me find a job', is the heartfelt plea of many of young Europeans. But what chance is there that their cry for help will be answered in a difficult global environment?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We have seen the globalisation of strategic relationships in a range of key areas including the environment, the management of energy resources, health, demography and security. The trend has been accelerated by rapid technical progress in the fields of transport and telecommunications. This process has not taken the big multinational companies by surprise - they were already free of the constraints of sovereignty or space, and were quick to globalise their structures. These enterprises have become more competitive by taking advantage, wherever possible, of the most favourable production conditions, particularly regarding raw materials and employment conditions. More spectacular still has been the growth of international trade: in 1990, the volume of world trade was 11.5 times as great as it had been 40 years earlier. During the same period, global production only increased fivefold.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What this means nowadays is that employment in the EU Member States is directly affected (and some would say threatened) by the world situation. Productivity and growth conditions in Europe are no longer sufficient to ensure full employment. Competition from developing countries, with their low wage bills and undervalued currencies, is too great for countries in the EU. Their position is not the same as that of the multinational companies. They do not have the structures to deal with swiftly evolving events, nor are they capable of controlling the process of globalisation. This is demonstrated, inter alia, by their inability to respond to the financial speculation which turns capital away from productive investment. Today, for example, for every US dollar in circulation, there are at least 30 dollars which are the product of financial speculation. This is not money from productive work by any particular person, but money which is the product of a financial 'virtual reality' and which is usually reinvested in financial speculation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Countries are beginning to realise the need to pool their national skills and cooperate at a regional level, in order to enhance their business competitiveness and take on the challenges of the globalised trading system. But the level of integration implied by this strategic choice must be sufficiently comprehensive if it is to make up for the reduced capability of countries to respond on an individual basis. This process of regionalisation may well be a prerequisite for regulating the world economy in such areas as exchange parities and financial speculation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">And what of Europe in particular? Despite having a head-start on other regional groupings (such Asean, Nafta and Mercosur), the situation is not too rosy. Owing to the lack of a full internal market, Europe is unable to compete on equal terms with the United States or Japan. The internal market still comes up against blocks in important areas, as evidenced by problems over the European employment pact. And there are a number of other defects which make the internal market insufficiently competitive in the context of globalisation. It is true that a more coherent environment has been created for European companies, with common regulations and rules of competition enabling them to distribute their goods and services among the EU's consumers. But despite the appearance of a domestic, or single, market, it is one which is devoid of a genuine internal policy in keeping with its size. This is what distinguishes it from the internal markets of the United States or Japan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The explanation for the disparity may lie in the fact that the most recent moves towards the single market, through 'Single Act', date from 1987. This was before the upheavals which so decisively signalled the globalisation trend. Despite the criticisms sometimes levelled at it, it is a genuine single market which is largely open to the outside world (with only a few exceptions, notably as regards the Common Agricultural Policy, where it is recognised that there is a need for progressive adaptation). But there is still no single currency, nor is there a genuine common commercial and economic policy. The EU is unable to react to change at world level in the same way as its competitors. The common customs tariff, together with protective measures such as the anti-dumping regulations, are still not sufficient to solve all the Union's problems. What is needed on top of this is an active common policy component.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yet, as the European employment pact makes clear, the EU holds a trump card in an increasingly interdependent world. The proviso is that it must speak with one voice, enforce multilateral rules and open up new markets for itself, because, as the document points out 'exports create jobs...'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1994, the developing world received 37% of global direct foreign investment ($84 billion) as against less than 20% at the beginning of the 1980s (the flow of foreign exchange is regarded nowadays as the principal factor influencing development). This is a spectacular increase but the resources are not 'fairly' distributed from the point of view of either the investing countries or the recipients. For example, southeast Asia is currently the world's most dynamic region. Yet, not to put too fine a point on it, it is virtually ignored by European investors. Only 3% of European overseas investment is directed towards this zone. Likewise, Europe's market share in the region is no more than 5%. The US has invested between two and three times more in south-east Asia while Japanese investment is four times higher.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1994, sub-Saharan Africa attracted just 0.8% of direct foreign investment ($1.8 billion). And there is no evidence that Europeans have invested more than the Japanese or Americans in this region. This is despite the highly optimistic outlook for the situation in Africa offered by the late Ron Brown, the former US Trade Secretary. On returning from a tour of Africa with American businesspeople in February 1994, he remarked that major opportunities were opening up in that continent, with spectacular returns on investments  - at the time, the best in the world. His regret was that so few people were aware of the situation. Undoubtedly more significant still was the declaration made in Washington before his departure for Africa to the effect that the United States would no longer leave African markets exclusively to the former colonial powers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">So although others are beginning to explore the possibilities offered by Africa, Europe is still sceptical. A similar scepticism prevailed during the 1960s when it was assumed that the lot of south-east Asia would be famine, and few development prospects. Given the historical links between Europe and Africa, the geographical proximity of the two continents, and the pressing problems faced by the 'old' continent vis-&agrave;-vis its competitors, such an attitude appears difficult to explain. In the years since the former European colonies in Africa gained independence - and despite the creation of an institutional cooperation framework (the Lom&eacute; Convention, which many regard as a model of development cooperation)  -  many Europeans clearly no longer wish to be involved in Africa. The explanation for this lack of interest may be the difficult conditions within African countries -  obstacles preventing access to markets, the lack of liberalisation or political instability.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But this analysis in not entirely convincing. More ACP countries are democracies than ever before in the post-independence era. As for Africa - a much-debated ACP region  -  it is wrong to talk purely in terms of internal conflict, famines or the AIDS epidemic. There are countries in this continent with growth rates of between 5% and 6%, and several examples of where European companies have successfully penetrated local markets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The need to highlight the existence of genuine business opportunities in ACP countries and to make the European public aware of development aid success stories, were among the main conclusions to come out of the first meeting of a television delegates' network, organised by the European Commission's Development Directorate-General on 31 January 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Any European company chairman interested in expanding into an ACP country - thereby enlarging the company's market and enhancing its competitiveness - is likely to acknowledge the possibilities, if offered back-up from the EU or from national governments. But they will then probably point to the complications which remain -  and with some justification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With this in mind, it is worth reiterating the fact that specialised institutions exist for facilitating contact with the ACP countries. In 1995, for example, the Centre for the Development of Industry (CDI) was involved in 367 projects, assisting, free of charge, in the expansion or rehabilitation of industrial companies in ACP countries, in partnership with European business. Although the number of such projects is constantly increasing (190 in 1993,229 in 1994), it is still a long way short of what is needed. But it should be stressed that the CDl's approach, which involves promoting the creation of networks, appears to work. The establishment OF ACP contact networks in ACP countries makes it easier to identify potential areas for involvement and to prepare better for European institutional and sectoral networks. There are several successful projects which have led to the creation or safeguarding of jobs in Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Also in 1995, the European Investment Bank (EIB) granted ECU 430 million in loans to businesses in various sectors in 29 ACP countries. This includes an increase in the Bank's activity in Africa over previous years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What, then, of the effect of Europe's development cooperation policies on the European market ? According to the most conservative estimates, for every ECU 100 granted in aid, the Community 'gets back' ECU 48 in the form of jobs, supplies and technical assistance. This figure does not take account of additional 'secondary' business generated by, for example, the supply of spare parts or the provision of technical advice. This business can be quite significant given the degree of penetration achieved by European companies in the markets of many developing countries. Nor does the estimate include any new business opportunities directly arising from the links established between the companies involved in aid projects and the recipient countries. Thus, it is clear that when a project is set up, it may well have extra beneficial effects for Europe through additional flows of goods and services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The 'return' on aid is even greater in Member States' individual bilateral programmes. For example, tied aid from countries such as Belgium, Italy and the United Kingdom leads to a payback of more than 70%. Another point is that as Europe's industrial rules are harmonised, the success of a single European company in penetrating a particular developing country market may pave the way for companies in other EU Member States, thus benefiting the Union as a whole. Tied aid creates favourable conditions for setting up European companies and for placing European goods and services in other markets. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While the return on aid may be described as satisfactory, the same is not true of the number of companies that benefit or of the actual turnover involved. One wonders whether this weakness is due to a lack of information about existing resources and facilities, or whether there still a lack of confidence about countries which, despite the progress they have made, are still politically unstable and therefore unpredictable.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One might also wonder whether the time is right for investment. Our answer would be that, even though financial speculation is currently governed by global economic considerations, which prevent productive targeting of capital, this situation cannot last. There is a worldwide move to rectify the situation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We all need to be aware that time is no longer on our side. In many sectors, European companies still have a competitive edge over businesses from third countries, owing to their degree of specialisation and technological expertise. But if they are to survive, they must take on a worldwide dimension. In particular, they should pay attention to the comparative advantage that they have in the ACP countries on account of their special skills, historic links, geographical location and, above all, the institutional connections between these developing nations and the 'old' continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although problems do exist and although both European and ACP bureaucracy can sometimes discourage private operators from exploring the potential of the developing world (and more particularly the ACP region), they should not give up. Europe's challenge is to help them to exploit this potential whilst not raising false hopes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nothing can take the place of the shared experience and confidence which arises spontaneously in full knowledge of the facts. In this regard, we feel, there is still much to be done. In both Europe and the ACP countries, one way to succeed is to increase the number of networks representing industrial, economic and financial interests at various levels, and to assist them in identifying opportunities more effectively. This would help to create a new dynamism and renewed vigour in Europe. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Close - up</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Eritrea: the start of a renaissance ?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the Courier's issue of July-August 1994, we published a country report on Eritrea. This country became independent in 1993 after almost 30 years of fighting which had bled the county white. Loss of human life, displaced persons, socio-economic disruption and environmental damage have been Eritrea's sad fate in recent times. However, there has now been peace for three years and the Eritrean people are attempting to pick up the threads. Alfonso Artico, a freelance journalist who recently travelled to Eritrea, now offers us a few on-the-spot impressions of his trip, focusing on some current projects which offer hope to this sorely afflicted people</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fisheries at Massawa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The port of Massawa is located on the Red Sea, whose blue waters are teeming with fish. In 1986, the European Union suggested that it would be a suitable place for fisheries development. At the time, the city was a maze of back streets, baking in the sun. Few could have predicted the fate that would befall it five years later. For in 1991, war came to Massawa and 80% of the city was destroyed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Italians, it is said, have 'always' been here, and they once had great plans for the city. Together with Assab, further to the south, Massawa was to be a key point of access to the sea, and a potential launch pad for the, country's struggling economy. The colonial days are long past but, when the Eritrean Popular Liberation Army took over the country after the recent war, the Italians came back to help tackle an immense task. The city, by then, was little more than a pile of rubble.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Help also came from somewhat further afield, in the shape of Professor Seichi Etoh, a Japanese specialist in marine biology. He had made a study of the city in 1989 and he chose to return in 1992 to help in fisheries development. At the outset, his working methods disconcerted the Eritreans who were used to a slightly more relaxed attitude to labour, under the hot sun and eternally blue sky.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Armed with the experience of working in Kenya and a number of other developing countries, Professor Etoh arrived in Massawa and installed himself in a house looking over the sea. After a period of adaptation, to gain his bearings, he took up his new challenge.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The challenge in question is a fisheries project whose main funders are the UNDP, Japan, Italy and the African Development Bank. A total of $7 million has been committed with payments spread over a five-year period. The project began operating in January 1993.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main problem at the outset was one of skills and qualifications. Important posts were often filled by high-ranking former solders, whose administrative skills were less than satisfactory. Conversely, those with the right qualifications - some of whom were criticised for spending the war years in the lecture theatres of European universities  -  had problems finding work. This was particularly true in the closed and conservative world of the fisherman. After a few teething troubles, Etoh was able to announce that he had the confidence of the government, and his efforts rapidly bore fruit thereafter. He set about reorganising the fishermen's cooperative - a task which entailed overcoming the reluctance of members to adopt new practices. He also arranged for the construction of jetties where vessels could take on supplies. Fish were to be unloaded at one spot, and their diesel tanks would be refilled at a different location. The cost of diesel is 1.41 birr (ECU 0.17) per litre. The fishermen's cooperative, which has 440 members, has 35 000 birr (ECU 4000) in its funds. It is also making repayments on a 1.8 million-birr (ECU 200 000) loan.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'In the beginning, there was frenzied activity, which some regarded as chaos', Seichi Etoh recalls. However, in less than two years, the jetties have been completed and the ice plants -  essential for preserving the fish - are running flat out. Now they are producing eight tonnes of ice a day. The daily catch is about two tonnes of fish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The real revolution occurred when Seichi Etoh decided to try and organise cooperatives for women, who represent 25% of the workforce in the production chain. He followed up with an even more radical scheme, offering them paid work in the relatively unrewarding but essential field of ship maintainance and repair. This freed the fishermen, most of whom had no remunerative activity outside the fishing season (November to March), to seek work elsewhere during the other seven months of the year. Eritrea, a country where women's potential has not traditionally been acknowledged (or tapped) had never seen the like before. Nowadays, of the 200 who fish out of Massawa, 50 are women who have formed their own organisation - and they generate a considerable profit. They have even opened up a fish restaurant!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The overall standard of living has increased considerably. This year, fisheries-related production has risen 120% compared with 1995. And the port is doing reasonably well in quality terms. Using the international scale, which ranks the catches from 0 to 10, the quality of fish landings by the Massawa fishermen is rated 6 overall - as against 8 for Japan. 5 for China and 6.5 for Europe. The local market has expanded as a result of efforts to modify local eating habits. People have been taught to grill fish instead of frying it in expensive (and somewhat unhealthy) oil. The message - 'eat grilled fish' - is going out daily on national radio, and women are going into the schools and villages to teach this 'latest' cooking technique.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The local market may be important, but the main target for the increased production is Ethiopia. With the purchase of four refrigerated lorries, it is now possible to transport fish products over long distances. Another important customer is Italy, which currently takes about a third of the total production. Seichi Etoh is hopeful that, following this example, new markets can be found in other parts of Europe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The success of the Massawa project has exceeded all expectations and, although he downplays the achievement with typical oriental modesty, it is clear that Etoh's bet has paid off. The fishermen have come to understand the advantages to be gained in reorganisation and maintaining their 'tools' of production. And as anticipated, the bulk of the profit from the project is going back to the fishermen. The government has taken care not to cream off too much for itself.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other projects are now under way. Etoh is attempting to persuade the fishermen to give up their wooden craft in favour of ferro-cement vessels but after centuries of doing things in a certain way, it will take more than a few months for the new plans to be adopted. The monthly meetings with representatives from the cooperatives are stormy and animated. However, two vessels are already being built, on the assumption that a practical demonstration is worth far more than a long speech. The 60 people working directly on the project are awaiting the outcome.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This change has become necessary owing to the cost of wood - which is one of the reasons why the fishermen have grown progressively poorer. Timber prices have been rising sharply for some years, particularly in Dubia, the regional centre of the wood trade. The war, in the meantime, sent incomes spiralling downwards.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Overall, the Eritrean fishing fleet has 500 vessels, all made of wood, of which 250 have Massawa as their home port. In previous years, the wood (known as tengi in Eritrean) came from Ethiopia. But this country is facing ecological problems and fishermen have been forced to search elsewhere for building and maintenance materials for their unstable and costly vessels (a 13-metre boat requires 8 m³ of wood). Etoh explains that the new boats, while slower, glide more easily over the water on account of their stability. However, the first attempts at change have not been easy. Indeed, things got so bad that Etoh went on holiday 'for longer than expected', he said, though he took advantage of the break to visit Singapore and buy Chinese tricycles  -  which can now be seen in the streets of Massawa. The reign of the bicycle with a simple wicker basket which could carry just 20 kilos is over. Now, each tricycle can deliver 100 kg of fresh fish, packed in ice. All in all, the programme is running smoothly. Etoh has only to check it from time to time. After all this labour, will the smiling Japanese professor be taking a well-earned rest? 'Probably not,' he says, adding 'I am currently thinking about a chain of restaurants. Fish restaurants of course !'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An unusual 'bank'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The road leading to Gersteti village is so beautiful that it takes your breath away. Multicoloured birds fly lazily above the vehicle carrying the journalists and humanitarian aid workers - who are deep in discussion about the kind of world they wish to create. However, there is a switch in the conversation once they reach the Seraye plateaux. Their attention is drawn to the fields which stretch as far as the eye can see. It doesn't take long to discover that demand for land here far outweighs supply. The situation, which is already critical, has not been helped by the influx of refugees returning from neighbouring countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When the war ended in 1991, everyone's prime concern was to relaunch an agricultural sector ruined by 28 years of combat. Farmers and farming communities, the lifeblood of the countryside, had been mobilised to fight on the front line. In 1990, agricultural production was at such a low level that the word 'negligible' featured prominently in the Ministry of Agriculture's statistics.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Oxfam, which first came to Eritrea in 1978, has been running an unusual project on the Seraye plateaux. Located to the south of Asmara, the capital, this region is the second most densely populated part of the country. Five districts containing 65 villages and 17000 families, were chosen for the project  -  on account of their low rainfall and the fact that it is difficult, and in some cases, impossible, to cultivate the exhausted soil. Local communities, village leaders and politicians all understood that only full-scale collaboration could prevent a food-supply disaster in the province. An organisation was therefore created: the villagers elected 13 representatives (12 men and one woman) and began by setting up a seed bank. There was a severe shortage of seed materials in this devastated country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project got off the ground in November 1995 and is set to run for three years. Its objective is simple: to guarantee self-sufficiency in seeds and to provide a reserve during hard times. The 'Seed Bank Committee' has also given training to 40 farmers in seed conservation, terracing and basic agricultural economics. Two wells have been sunk, but these are insufficient for the 40 square kiLom&eacute;tres that require irrigation. Oxfam is putting up the money for the various initiatives while the local community is providing the labour force. It is worth noting that a bag of averagequality cement costs 35 birrs (ECU4), equivalent to one third of a worker's monthly wage. Fourteen different varieties of seed have been stored in sheds - which the locals visit to obtain their supplies. The purchase of 230 quintals of local seeds and the donation of 70 quintals from elsewhere have started the programme off. Next year, Individual farmers will have to repay this 'loan' in kind, with a 10% 'interest payment', also in the form of seeds. The surplus generated will be retained by the bank as a resource to be drawn upon, if necessary, when times are hard.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Advantages</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The local community was quick to understand the advantages to be gained from this system. They were all too aware of the low productivity of their land and up to then, were powerless to resolve the situation. The possibility of falling back on traditional resources to offset production difficulties no longer existed. And the skills they had acquired over the generations were now insufficient, given the poor condition of the soil. In these circumstances, one can well understand their enthusiasm when they saw that 100 kg of seeds per hectare yielded a harvest six times larger than previously. Other elements which contributed to a progressive improvement in conditions were the sinking of new wells, a reduced influx of refugees from Sudan, and a slow but appreciable improvement in the country's general economic situation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As well as being involved in this project, Oxfam is an active member of Acord, an NGO association which extends cash loans at rates much lower than those demanded by the banks. (Acord's rate is 12% per annum with a minimum repayment of 5 birrs per month). Targeted mainly at the most deprived sections of the population, the loans enable the poor to set up small businesses or, more commonly, to purchase agricultural implements, repair irrigation channels and buy cattle. Once again, a village committee manages the transactions. The scheme has brought renewed hope to the most deprived groups. Individual loans have been available since 1994 and the association currently has 163 clients. The total amount lent so far is 878 000 birrs (ECU 110 000).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The combined effects of these programmes - seed banks and preferential loans - are already visible. It would take months to visit all the farms and fields, workshops and stores, where men and women have invested their energies and hopes. Seraye province now produces a third of Eritrea's cereals, a telling illustration of the fact that one does not need billions of dollars for development and humanitarian aid for the work to be effective. In the final analysis, a country's wealth lies in its citizens. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An up-to-date printing plant</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As one strolls down Liberation Avenue, which cuts the city of Asmara in two, one might be forgiven for thinking that 28 years of war have already been forgotten. Surveying the multi-coloured neon signs of the shops, it certainly appears as if the country has turned the corner and the wounds are healing rapidly. One building whose restrained frontage stands outs in sharp contrast is the Adulis printing-works. Adulis was the name of a semi-mythical city founded by the Greeks on the Red Sea in the third millennium before Christ. 'But there is nothing insubstantial about this place', comments Mohamad Shiffa Osman, with a smile. He is one of three expert typesetters who went on a training course in Belgium earlier this year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> The Adulis printing works has its own particular memories of the Eritrean people's struggle for independence. As far back as the 1960s, when the first shots were being fired, the resistance recognised that their fighters and the civil population both had to have access to information. However, it was not until the 1980s that a true propaganda structure came into being. During the war, the Eritrean People's Liberation Army ran a clandestine ministry of information. In Eritrea and elsewhere, this became the channel for conveying practical information, and providing the latest news from the front. It was also used to transmit personal messages, which were delivered to the heart of areas occupied by the Ethiopian Army. 'Our presses were hidden in caves, up in the mountains, and everything was run on generators', Mohamed remembers. The initial amateur approach was quickly replaced by a more professional one. 'We did have professional printers working for us, but it was mainly self-taught comrades'. On-the job apprenticeships had to be fitted in between bouts of fighting!</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'At the time of liberation, in 1991, we set about restoring this printing works, which was founded in 1896 by the Italians', Mohamed explained as he gave us a guided tour of the works. The effort put into relaunching this essential activity soon bore fruit. Within the year, the printing operation was running at a profit - indeed it had a virtual monopoly of printing in the country. The presses were brought down from the mountains on the backs of camels and then taken to Asmara by truck. 'You see this Aurelia 48?', asks Mohamed, pointing to a machine. 'Well, it was up in the north, hidden away in a village'. Throughout our visit, Mohamed draws attention to equipment from an earlier age  -  candidates for the museum which are still in operation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some items have their own story to tell, like the press donated years ago by Oxfam which still churns out thousands of sheets every day. During the war, it was taken from cave to cave, following the army's advance as it conquered new terrain. Most of the Adulis machines, however, were already there, when the decision was taken to restart the operation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The initial budget for the works was a tidy five million birr (ECU 620 000). Today, Adulis has an annual turnover of 20 million birr. Monthly salaries range from 400 birr (ECU 50) for maintenance staff to 1800 birr (ECU 225) for the director, Michael G. Bakhli. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The printing works also acts as a testing ground for workers' social progress. According to Mohamed and the director, the 350 or so people employed at the works benefit from exceptional social cover. If a worker falls ill, his wage is guaranteed for one month, then it drops to 50% in the second month and stops altogether at the end of the third. if a woman is pregnant, she has to take a month's statutory leave and is granted a further two months on full pay. In the event of dismissal, an employee receives two months' wages, although this latter arrangement is gradually changing to one month's wages for each year of service.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Far from resting on the laurels of their success, the Adulis works' directors have appealed for assistance. In order to be at the cutting edge of technology and to have the resources to break into new markets, they need to supplement their knowledge. Therefore, three 'volunteers' spent the three months from January to March this year working in Belgian companies, to the satisfaction of everyone, both hosts and visitors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under Mohamed's gaze, the walls of the workshop have been brightened up with posters which provide a splash of colour. Although the noise from the presses often drowns out conversation, you cannot escape the feeling of hope here. It is like a breath of fresh air, and one leaves with the strong impression of a country that is rising from the ashes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Developing world</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">ECHO fine-tunes disaster preparedness strategy</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Eva Kaluzynska</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When a cyclone strikes in the Caribbean, beware of giant flying razorblades - airborne sheets of corrugated iron that kill and maim unsuspecting victims every time. 'The use of galvanised iron sheeting for roofing is extremely dangerous in cyclone-prone areas,' says Professor Debarati Guha-Sapir, Director of the Centre for Research on the Epidemiology of Disasters (CRED) at the Universite Catholique de Louvain. 'We know this, and we need to encourage the use of lighter materials, such as thatching, which doesn't kill if it flies off in a gale,' she adds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">That is the kind of issue facing people exposed to unavoidable natural disasters  -  in the Caribbean's case, every year. In 1995, there were 27 tropical storms in the region. CRED has been in the vanguard of monitoring natural disasters and in coming up with solutions to the problems they create since it was set up in 1973. Now it is assisting the European Community Humanitarian Office (ECHO) in developing its new Disaster Prevention, Mitigation and Preparedness Programme (DIPECHO) to cover the next two years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since 1994, ECHO has spent almost ECU 7 million on 50 disaster prevention operations, at both national and regional levels. Now, instead of just responding to requests for funding from non-governmental organisations, international organisations and governments, ECHO has decided to fine-tune its strategy. It will concentrate its efforts on specific regions known to be particularly vulnerable and prone to natural disasters. We may not know exactly when disasters will strike, but we certainly know where to expect them. The regions selected at present are: the Caribbean, Central America, South East Asia and Bangladesh.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All of them are exposed to repeated emergencies. All of them have a struggle to develop when their efforts are disrupted so frequently. They cannot just pick up where they left off. Loss of life and property is just the most visible aspect of what happens when disaster strikes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The infrastructure, such as it is, takes a hammering. Road and rail links are severed. Communications, electricity and water supplies break down. Add loss of health care and sanitation, and you get populations exceedingly vulnerable to epidemics. Add loss of education facilites, and a vicious spiral of poverty sets in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An expert in emergency aid cites the sad example of the Aetas, a tribal group that used to live a secluded life on the remote slopes of Mount Pinatubo, the volcano that erupted spectacularly in 1991 in the Philippines. Though the volcano was known to be menacingly active, the Aetas were not evacuated and resettled in time. They fled in panic as disaster struck, to the plains, where they faced a deadly, invisible enemy: measles, a disease to which they had never been exposed. Measles claimed more victims than the volcano itself did in the months that followed. They could have been resettled earlier. And they could have been immunised years before, but weren't.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It's easy to be wise after the event. DlPECHO aims to encourage action before it's too late. The idea behind ECHO's new policy is to take each region, and to identify its hazards and capacity for dealing with disasters. This will help to pinpoint the gaps. Then it will draw up Action Plans that slot into the wider picture of potential development in each case.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DIPECHO projects will involve training personnel in the regions affected to handle disasters, and to strengthen the institutions that can contribute to effective prevention, preparedness and mitigation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some of the solutions are ingenious, low-cost, low-tech ideas. Take, for instance, the use of light, widely-available, inexpensive materials for roofing in earthquake or cyclone-prone zones - an idea poorer countries could adapt from wealthy Japan's experience. Or the construction of safe, raised 'islands' that will stay above the waterline amid flooding in Bangladesh to offer shelter. Or adapting drainage, and changing cropping patterns in Andhra Pradesh, India, to mitigate the effects of cyclones.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In earthquake-prone Central America, protecting roads and bridges, or building schools less prone to collapse is very important. Using the radio or even neighbourhood watch systems to sound the alarm when disaster is imminent can make a big difference to its impact in terms of injuries. Drilling all at risk, from school-age up, to know what to expect and to know what to do is vital.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">DIPECHO did not include Africa in its first selection of regions for Action Plans. This is not to underestimate the gravity or scale of the disasters experienced there, says Professor Guha-Sapir: 'Floods, drought and famine are very frequent events there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">They are often killers.' Overexploitation of scarce resources and political turmoil compound situations that lead to disasters which seem less dramatic than a volcano eruption, but are no less far-reaching in impact.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The instability in many of the areas worst affected means that African countries lack the institutions needed to prepare for disasters in an organised way, she says. 'There are limits on ECHO's ability to intervene. It's unrealistic to expect the kind of grassroots, technical preparedness we are talking about in the current situation.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ECHO's Jean-Claude Heyraud sums up the new policy: 'As far as preventing, mitigating and preparing for catastrophes goes, the new proactive approach reflects the importance ECHO attaches to this type of action. The DIPECHO programme meets the growing need to evaluate risks in order to reduce loss of life and damage to property. If and when emergency aid is needed, preparation and prevention can help to reduce the scale and cost of such actions.' </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Culture and society</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">African reflections</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">by Seydou Sarr</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The third Festival of African Cinema was held in Brussels on 15-22 June. For one week, film-goers in the Belgian capital filled the auditoria of the Palais des Beaux-Arts, where they discovered new images of an alternative Africa. And as always, when the time came to assess how the Festival had gone, professionals and organisers alike were left pondering the problems facing the African film industry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Organised for the first time in 1994, on the initiative of Diaspora Productions, the Festival had a number of objectives, including that of bringing Africa's finest films to wider public notice. The initiative stemmed from two observations. In the first place, the European public's opinion of Africa is based on what it sees on television -  and that image is of a continent so ravaged by famine, misery and strife that it is incapable of progress. Second, from a professional standpoint, there is no effective distribution network in Belgium for African films. Samba Traore by Burkina Faso's Idrissa Ouedraogo and Hyenes by the Senegalese Djibril Diop Mambety were two rare exceptions in succeeding in getting on to the circuit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A forum for reflection</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In setting up film-industry meetings, the organisers of the Brussels Festival wanted the event to be a forum for reflection on the problems facing African cinema. In the 40 years it has existed, there has undoubtedly been some progress. It is even possible to speak of genuine mastery of images and cinematographic language. But there are also many problems -  involving production and distribution, a lack of official support, a shortage of private capital and limited access to international markets. At home, meanwhile, African firms face fierce competition from multi-million dollar productions coming out of the USA, Europe and Asia. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Europe has traditionally offered the only feasible route for those seeking technical and financial resources. The principal donors are the European Union, the ACCT (Cultural and Technical Corporation Agency) and the French Ministry of Cooperation. There are, of course, many instances of African directors producing films without taking this route, but these ventures usually have smaller budgets, and insufficient funds to devote to promotion (press releases, trailers etc). As regards distribution in Belgium, directors face an additional difficulty - they have to take the language issue into account (particularly when films are shown in Flanders).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">African professionals are looking at various ways of solving these problems, including the possibility of coproduction with European operators. For some years now, public and private bodies have also been considering the idea of establishing combined co-production teams in a form of partnership, as a way of supporting African cinema. This topic has been on the agenda of other African film festivals (notably in Amiens) and it came up for discussion in Brussels as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A colloquium on the subject of ACP/Europe co-production was staged on the fringe of the Brussels event. This served to highlight a number of successful experiments in North/South collaboration. One example was the Cape Verdian film Ilheu de Contenda, by Leao Lopes which was made with support from a Belgian production company, Saga Films. This film was screened at the Festival. It also gave an opportunity to discuss a range of other topics. African journalists accredited to the Festival were given the task of drafting a resolution whose conclusions will be submitted to various contributors including FEPACI (the Pan-African Federation of Film-Makers), the European Union, producers and other donors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There was general agreement that a coherent legal framework for organising relationships between directors and producers, on the basis of mutual trust, was badly needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Positive results</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is worth making a brief assessment of the efforts made by the organisers of the Brussels Festival to offer an improved programme. The showing of shorts at the beginning of a performance is undoubtedly a formula they should employ again. These works are a specialised genre which give young directors the chance to present their first work. The bulk of the shorts that were screened this year were in the form of 'documentaries' based on fiction - but with one foot in the real world. They dealt with people's lives, their daily concerns, and a variety of social phenomena. Thus, we were presented with films dealing with Aids, urban delinquency, the role of women in society and so on.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another positive point the organisers should concentrate on is the space resewed for English and Portuguese-language films. There were eight performances in this category including four feature films in English and two in Portuguese. A further worthwhile element was the space allocated to African women (from Nigeria, Kenya, Zimbabwe and Burkina Faso) who have chosen to use the cinema as a means of expression.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Diaspora Productions' managers are said to be reasonably satisfied with the way the Festival went. They hope it can continue to be held at the Palais des Beaux-Arts, since they see this as one way of liberating African cultural events from the Afro-Brussels 'ghetto' where they have often been held. They are also keen, in future years, for African films to be shown in Brussels cinemas while the Festival is under way. If this happens, film-goers in Brussels will have the pleasure, from next year, of seeing quality works in their usual cinemas. The timing is appropriate since the 1997 Brussels event will follow the Ouagadougou Festival (Fespaco) which traditionally sees the launch of a number of new films.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Family meeting</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The organisers chose to close the 1996 Festival with a fashion parade which gave Pathe 'O, the designer from Cot&eacute; d'Ivoire, the chance to present his collection to the Brussels audience.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the fringes of the Festival, there was also a musical offering in the shape of the Toure Kunda brothers who came to lend their support to filmmakers and other African artistes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are those who would argue that the Brussels Festival has now entered the category of a 'not-to-bemissed' event. Every year, it attracts significant numbers of film-makers from Africa and the diaspora, even when they have no current projects or films to present. There was a real family atmosphere in the corridors of the Palais des Beaux-Arts, due in no doubt to the absence of competition. From the outset, the Diaspora Productions team chose to stage an event at which prizes were not awarded, thereby promoting reflection and contact with the public. It is generally agreed that the Brussels Festival offers a rare opportunity for film-makers to meet and discuss their productions and projects in a relaxed atmosphere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The credit for this, in the view of many of the participants, lies with Pape Mbaye Sene, one of the guiding lights of the event, who has also been dubbed the 'high priest' of African cinema. It has, in fact, been suggested tongue-in-cheek that 'in Brussels, they award a Pape, not an Oscar'. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">'We make films... but we do not exist!' - interview with Souleymane Cisse</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The future of African cinema seen through the eyes of the Malian film maker, </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In April, The Courier had the opportunity of meeting Souleymane Cisse, one of Africa's most celebrated film-makers, who has won several awards at major international film festivals. His films, such as Yeelen, which was awarded the Prix du Jury in Cannes in 1987 (the first African film to receive such a prestigious accolade), Waati, which was entered at the same festival, and Finye, have already become classics. Cisse is not just a director, he also produces his own films. In 1972, he impressed international critics by single-handedly producing a short film of exceptionally high quality Cinq jours d'une vie -  which won an award at the Carthage Film Festival. By relying, above all, on his own limited resources, combined with a powerful determination to develop and promote Africa's film industry, Souleymane Cisse has an implied but powerful message for the entire African continent. When he went on stage at the Palais des Festivals in 1987 to receive his award for Yeelen, he said that he was accepting it on behalf of all those who did not have the opportunity to speak for themselves. In particular, he dedicated the film to all the South African technicians who had worked together with him on the project. His has made spirited efforts to boost the African film industry and it was in this context that he helped set up the 'Union of African cinema and audiovisual producers and entrepreneurs' last March. This organisation aims to encourage African countries (especially in West Africa), to take the necessary political decisions to ensure the survival and grouwth of African cinema. When we spoke to Souleymane Cisse, our discussion ranged far and wide. We began by asking the film director whether African art gets the recognition it deserves in Europe? He seemed surprised at the question but then, without hesitation, proceeded to explain his own approach - with the emphasis on the political rather than the aesthetic.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The recognition that African art gets in the West has more to do with politics than aesthetic discernment. Such recognition evolves from the spirit of Africa's relations with the other continents, a spirit which is often devoid of all honesty. We stand at the threshold of the 21st century. We should be looking to develop ways of communicating with each other and finding common ground. We should be able to look each other in the eye. When, for example, people in France debate whether or not the Louvre should have a gallery of African art, it begs the question, 'who is asking for what ?'. When some people wonder whether or not African art really is art, they are asking themselves a pointless question. African art is. Nothing more, nothing less. In any case, the West has some highly contradictory views as far as the whole idea of art in Africa is concerned. On the one hand they dispute the fact that the culture of the Ancient Egyptians was, in essence, an African one, and yet on the other hand the characters of Ancient Egypt - in films for example - are always portrayed as dark-skinned. African art is the 'in' thing at the moment, despite the current tendency to belittle Africa. They think that today's Black Americans and Afro-Caribbeans can be made to forget their African roots, but that just will not happen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Generally speaking, do you think that African politicians should devote time and energy to this battle to defend African culture when their countries face such insurmountable material problems ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> -  Once they have gained power, the obsessive preoccupation of our politicians has been to concentrate on economic policies, neglecting their countries' cultural needs. But without a deeply-rooted culture, you cannot discuss matters on equal terms with representatives of other nations. In their heart of hearts, they will not respect you fully. There have been two or three countries which have tried to combine economic development with cultural development - I'm thinking of Guinea under Sekou Toure, Mali under Modibo Keita and Ghana under Kwame Nkrumah, but in one way or another, all three have been thwarted, for their perceptiveness. I am not now commenting on, or necessarily agreeing with, their domestic policies, but rather with the broad vision they shared for Africa as a whole. The fact that Europe is currently in the process of forging the European Union will be an instrumental force in the opening up of other regions of the globe. It was Europe, after all, which divided much of the world into English speakers, French speakers, Portuguese speakers, Spanish speakers and so on. Now that Europeans are themselves seeking to unite their countries, how could they possibly object to a similar union in Africa - for the sake of its cultural identity. This idea of a United Europe is, therefore, a welcome one. What is more, I believe that the issue has already been tackled within relations between the European Union and ACP countries. Not only is Africa the continent closest to Europe; it is in helping to develop the African continent that Europe has most to gain.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· The cultural aspect has already been incorporated into Lom&eacute; IV, but it seems that ACP countries do not attach as much importance as they should to such matters when drawing up their lists of priorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Many of the politicians in charge of these countries themselves lack any sort of culture. Alternatively, stripped of their own culture, they flaunt that of a foreign land. They say that health care is a priority, that food is a priority, but cultural needs do not figure on their list. Yet culture forms part of an urgent need. You'll see - as soon as any sort of cultural development takes place in a country, or wherever a country already has a viable, thriving culture, its economy will also flourish; of that there is no doubt. A nation which has a highly developed culture will always be able to stand on its own two feet economically. Take, for example, the nations of the former Soviet Union  - their economies may be unstable at the moment. It's only natural that they have to start from scratch, but as long as they manage to hold on to their cultures, they will pull through. These countries will not lag behind as Africa has done.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· It costs money to operate a film industry. Have you found that your reputation as a director has made the financial side of things any easier for you ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - I don't honestly think much has changed in the way we finance our films. Perhaps I should only speak for myself, but I do not believe it is any easier for me than it is for young filmmakers. Mali has no film production facilities, so we are all in the same boat. That is why we organised a colloquium in March this year, aimed at getting a picture of the exact state of West Africa's film industry. What we learned was that it is in pretty bad state. We make films but, in a certain sense, we don't really exist as a film industry. I would dearly like my works to be screened, for example, in Mali, Guinea and Senegal, but that is not possible because the distribution and screening networks are no longer there. Even the most liberal Western countries have passed laws to promote and protect their local film industries, so why don't we do the same ? I cannot make films in the United States without first going through various unions and other professional associations. In France, I cannot distribute my films the way I want, and if I want to make a film, I have to make it through French producers. If people come to work here, they should have to use national producers. The relevant laws were drawn up three or four years ago, but they still haven't been passed. We want all those involved in the film industry to have the opportunity to be true professionals. There should be assistance available to modernise projection rooms and theatres. We are currently in the process of setting up the 'Union of African cinema and audiovisual producers and entrepreneurs' which should help to persuade governments to take our requests into account.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Isn't African cinema also a victim of television ? </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - The problem in Mali is a very simple one. We live in a country where people like to get out and about. The cinema is somewhere they can do that quite easily. So people use it as a place where they can meet up in the evening, just as they like to congregate around the fire to sing and dance. So why are our cinemas empty ? Because when people do go to the cinema, they cannot see the screen properly or they cannot hear the soundtrack, or they are uncomfortable sitting on broken and rickety chairs. If you can provide a suitable and comfortable environment for them, people will start going to the cinema again. That doesn't mean that television doesn't have its place, but people like to go out. This is especially the case with our open air cinemas, which are the perfect places for people to come together, have a chat, enjoy each other's company and relax. A nice auditorium, a good film, and you'll see how the queues will form. All we need to do is upgrade the auditoria, re-equip the projection rooms, overhaul the sound systems, put new chairs in - just a few basic comforts. When people go out to the cinema, it's because they want to escape from their humdrum routine for a while, to dream and unwind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">African governments should do what they can to enable people to relax and enjoy themselves like this. Going to the cinema is like going to school. People go there to learn something - whether consciously or subconsciously - and to see something different. We really must get rid of this purely commercial vision of the cinema, especially in Africa. It should, first and foremost, be a cultural experience, and only subsequently a commercial exercise. But we also need to be realistic. When helping those involved in promoting the film industry, the government should lay down a precise set of conditions, specifying how and when the loans should be repaid and requiring something in return for their subsidies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· So you think that if the Ministries of Culture in African countries were given greater powers, they would be in a position to carry out this task ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - It is not something solely for the Ministry of Culture. This is the type of approach which should be adopted by the state as a whole, in each country. For example, the government should provide a support fund for the film industry and certain other branches of the arts. Even if they were increased substantially, the meagre budgets allocated to the Ministry of Culture in our countries would still represent paltry sums. In Africa, the department of culture is at the bottom of everybody's list.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· But if you look at the number of African films that have been shown in recent years at Cannes and other international festivals, surely one can afford to be a little more optimistic than you are ? More and more young African filmmakers are releasing films.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - True, but as I said earlier, no progress has been made as far as film production is concerned. In that respect, contrary to what people may think, we are still at square one. Young filmmakers are put off and, as more and more avenues are closed to them, they gradually lose their fighting spirit. A film director has no choice but to be his own producer, his own manager - to do everything himself in fact. The result is that he becomes a jack of all trades and a master of none. During our recent colloquium, we decided to set up smallscale facilities which will deal solely with film production and where young people can go and use their services, thus leaving them free to channel their energies into actually directing their films. In the same way, we intend to set up other structures which will deal exclusively with other aspects of the cinema industry. The goal we have set ourselves is that of fostering professionalism in the West African film industry. Maybe then our governments will listen to us.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· Do you think there is any difference between African countries as far as opportunities are concerned ? For example, Burkina Faso would appear to be the cinema capital of Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - Yes, and no. More often than not, it is African film-makers who have chosen Burkina Faso to stage events connected with the cinema industry because it is a landlocked country. This is what has made it the film capital of Africa, not any deliberate move on the part of the politicians. Having said this, the government in Burkina Faso is also making great efforts, despite its limited resources. But each country has its own potential. We must stop trying to tear this continent apart.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">· You mentioned the former President of your own country, Modibo Keita, as one of those far-sighted enough to appreciate the importance of nurturing African culture. Where does Mali stand at the moment in terms of strengthening its own cultural heritage identity ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - After independence, in the years from 1960 to 1968, there was a time when young people would get together and become involved in various biennial art festivals. We had a series of events which encouraged a kind of a 'cultural vision' nationwide. They were so successful that other countries were soon following our example. After the coup in 1968, however, everything fell apart. In the following 23 years there was a total cultural vacuum, in which young people felt completely disorientated, despite superficial attempts to relaunch the festivals. We are now only just trying to rediscover our cultural roots after a long period of upheaval. What we in Mali do have working in our favour, is the fact that our country is a harmonious patchwork of different peoples, all living together without the slightest trace of bitterness or hatred. We are lucky here because our rulers rarely tried to manipulate our ethnic loyalties to set one group against another. A Malian, irrespective of his roots, will always rejoice in the success of his fellow countrymen, whatever tribe they happen to belong to. We owe our good fortune to a heritage in which our peoples have always respected one another - even when they have faced each other as enemies. It is only as a result of this historic mutual respect that we can now speak of a Malian culture where each individual group of people has its own idiosyncrasies, its own customs, is sensitive towards other cultures and actually rejoices in their differences. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">CTA Bulletin</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">CTA and the promotion of rural development through book distribution</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One of CTA's tasks is to provide information on request to researchers, extension workers, planners, farmers' organisations, trainers and information specialists involved in agricultural development in ACP states. In addition to requested publications, CTA also distributes publications on its own initiative to its target groups. These publications, some 550 titles, are also supplied free of charge and consist of books published by CTA, co-published, or purchased specially because of their relevance. In 1995, almost 65 000 books were posted to ACP countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The people who receive the publications to some extent select themselves, because they write to CTA with requests for information. They find out about its existence through attending CTA seminars held in ACP countries or in Europe, or through seeing copies of Spore (CTA's bi-monthly bulletin in English, French and Portuguese which goes to around 50 000 addresses and is seen by many more), or by word of mouth. Over the years, CTA has built up a mailing list of 42 500 addresses of people and organisations active in some way in agriculture and rural development. Of the total, 37 800 are in ACP countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But there are questions. Are our books getting to those who need them and is the targeting accurate enough? And, most importantly, is this the best way of doing things ? For CTA does not - and cannot - satisfy the total demand for books on agriculture and rural development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">What is the best way?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the number of addresses on the mailing list, many more people could in theory still be added. Should CTA even try to satisfy this demand ? The publications are free and, if CTA increased its coverage of the demand, it might in some countries hold back the development of local bookselling with a consequent detrimental effect on local publishing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The majority of those now on the mailing list are 'individuals' rather than institutions, libraries, documentation centres, associations, organisations, etc. On the face of it, more people could be reached by sending CTA publications to groups rather than to individuals, but it's not always clear who is an individual in the sense of information not being shared with others. Some individuals are teachers, some are extension agents, some receive publications on behalf of a cooperative, for example.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Because of the importance of information - the driving force behind development  -  CTA has been investigating and giving support to technical publishing and book distribution in Africa over the last few years and is currently examining its own policy on book distribution over the ACP countries as a whole. Part of the context for this policy re-appraisal is the state of bookselling.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Difficulty of book distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Everyone involved in the books business in and for the ACP countries knows that getting books where you want them to go, book distribution, is not straightforward. The reasons for the difficulty are not straightforward either. One development officer remarked of Papua New Guinea that the lack of books outside the capital, Port Moresby, couldn't simply be explained by lack of roads, because in the most out of the way places you could be sure of finding Coca Cola. Is it, then, that the Coca Cola company has superior marketing and distribution arrangements ? Probably so, but it is the nature of the two products which also determines how far they get. Traders will more readily take goods which they know they will be able to sell easily and the immediate satisfaction given by cigarettes or Coca Cola tends to put them before books in the list of priorities for purchase.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Among the ACP countries where CTA sends books and information, many have under-developed road and rail networks while the postal facilities provide a reliable service only to a relatively small part of the country. The local book publishing and bookselling industries are often themselves developing. Potential readers often cannot afford to buy the books and consequently book distribution is the weak link in the chain from writing and publishing a book to selling it. If books can't be sold, new ones can't be published, for the investment finance for a new publishing project has to come from somewhere.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Africa, the lack of a strong local book sector was attributed in part to the traditional oral culture of the continent which left little need for reading. The majority of students would read in order to pass their exams, after which they hardly sought books again to buy or to read.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main books distributed were therefore textbooks for schools, colleges and for higher education. As long as these were distributed through booksellers, a forum still existed for displaying and raising interest in other books.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Booksellers could also function as sources and conduits of information about the variety of books in print and of their interest to particular groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This development was stunted because of the low purchasing power of many people, lack of foreign exchange (except in the CFA franc states), high cost of importing (either books or the raw materials, print machinery and spare parts to manufacture books) and, consequentially, shortage and lack of variety of locally-published books.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition, in some countries the state intervened in school book publishing and supply (for example in Tanzania), so that the bread and butter of the bookselling business disappeared.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Booksellers then either diversified their stock so that they became bookseller-stationers or worse - books came after groceries, footballs, hats, etc., or the booksellers ceased trading in books or closed down.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The publishing-distribution chain in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Book distribution is part of a chain of activities in the book sector which depend on each other and support each other. The chain starts with an idea for a book which may come from an author or from potential readers who make known their needs and it ends with the published books being bought. The lack of a good book distribution infrastructure in Africa is linked to the lack of a wide variety of books from a good number of publishers and the lack of a market for the books.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At least until South Africa became a democracy, Nigeria probably had the most active publishing industry in Africa with a high level of publishing professionalism. In such a huge country this may not be surprising: there is a large market, state administrations with urban headquarters, and a variety of arrangements for publishing and distributing books. But publishers suffer from a scarcity of investment funds, with high costs of borrowing, which affects their ability to keep books in print and to start new publishing projects. Relatively few technical books are published locally because of the risks when compared with, for example, publishing school textbooks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In such a vast country, the state of book distribution varies from place to place, with cities and large towns obviously having a greater variety of books available for sale than small towns and rural areas. Small traders carry books to the latter; they do not take orders and the books they carry are those that they can get hold of which they think will sell. Would-be readers are frustrated unless they or their friends visit a city. Mail order is not a possibility because the domestic postal service is not trusted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the urban areas, where there are booksellers, an indeterminate number of potential readers cannot afford to buy books, especially those that have been imported. Book piracy is a consequence of this. Booksellers' sales have declined, their turnover has been reduced as has their ability to stay in business. Some institutions in the country buy direct from publishers or from overseas suppliers rather than from booksellers, which further damages them. Booksellers buy books from publishers in small quantities for a fast turn-round which affects publishers' ability to build up investment funds for the next publishing project or for a large reprint with its possibility of reducing unit book costs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This is not to say that technical books are totally unavailable from Nigerian booksellers, but it is clear that only specialised outlets which know their book-buying customers well can risk stocking some of them. Rural dwellers have no chance of buying them without making a big effort in time and money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In contrast, Senegal has a less developed publishing and bookselling industry than Nigeria, with about a dozen professional publishers and a small network of booksellers, mostly in Dakar and the larger towns in the regions. The most important publishing opportunities in Senegal are in the field of primary school textbooks - where there is competition both within the country, with publishers from other developing states, and from the North. Senegal being a lot smaller than Nigeria, there is only room for one textbook, and primary school book production is not therefore the mainstay of local publishers. The publisher which used to supply all primary and secondary school textbooks for the Ministry of National Education is an exception and is still probably dependent upon educational publishing for its turnover. Few technical books are published; as with books for higher education, they are imported.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The network of booksellers has been decreasing and it is difficult to make a living just by selling books without the back-up of other products to sell. Thus there are bookseller-stationers, bookseller-grocers, kiosks and street sellers, especially of secondhand books. Booksellers tend to order titles in small quantities because they cannot risk being left with unsold stock which ties up their capital. They order little and often. Most school textbooks are distributed through the Ministry of National Education, but booksellers still sell a variety of textbooks, some official and approved and some not. Before the devaluation of the CFA franc, booksellers ordered more from abroad. These books have now doubled in price, making them unaffordable, with a consequent opportunity opened for local publishers to fill a gap.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Apart from the professional publishers, various sorts of publications are being produced and distributed by literacy and post-literacy organisations and a delegated literacy ministry. Some organisations promote literacy for its own sake, while others use the attainment of literacy as the means through which development can spread in rural areas. The publications concern rural development, agriculture, health and nutrition, and rural democracy, amongst others. There is a good variety of different titles and a good supply of cheap and affordable books. Some are sold through booksellers, but most people buy them when they take their literacy courses, while small traders carry them up-country to sell and buy more copies from the publishers with the proceeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Book aid schemes</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A whole literature exists on book aid schemes. Briefly, book aid comes in two forms, one using the local book sector and the other not to any great extent. The British Government's Educational Low Prices Books Scheme (sadly scheduled to end, at least in its present form, in April 1997) and the French Government's Programme Plus both use the local bookselling industry to make available standard tertiary textbooks and others at subsidised rates. Not all students could afford to buy them, but the two schemes nonetheless promote bookselling and commercial life within ACP countries and beyond. To some extent they safeguard the continuation of fore where up-to-date books can be seen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CTA's books aid scheme does not use the local book sector in terms of book distribution, although cooperation in co-publishing is beginning. The FAO, in distributing publications to ACP and other developing countries, is similar. Books supplied under multilateral and bilateral agencies' projects have tended to sidestep the local book sector, although this has been changing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As with food aid, the question to be answered is whether continuing the aid prolongs the condition ? Or does the analogy with food aid break down in certain circumstances because books are different ?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improving book distribution in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Various efforts are being made to improve book markets for African publishers. For example, the African Books Collective, based in Oxford, UK, markets and sells both anglophone and francophone African publishers' selected books in the North and also to other African countries. It is often easier for publishers in the North to sell their books in Africa than it is for African publishers to sell their books across frontiers and in the continent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publishers Associations have been formed in about a dozen countries with APNET, the African Publishers' Network, celebrating its fourth year as a continental association. CTA supported APNET in the production of the first catalogue of agricultural books published by African publishers. Very recently, an Africa-wide booksellers association has been created.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">CTA and future book distribution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since CTA started distributing books on agriculture and rural development, publishing and bookselling activities in many ACP countries have multiplied and the context has changed somewhat. As noted at CTA's Montpellier conference in 1995, there is now much information and many documents going from North to South, suited to the planners, research workers and extension agents who process the information and pass it down to the small-scale farmers. Rather, a two-way information route would be more efficient, between farmers who have information to offer as well as information needs and information providers. The growth in requests to CTA for publications from co-operatives and farmer associations and from non-academic libraries and documentation units is evidence that the publications distribution service is fulfilling a need. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The Couriers mailbag</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Earthen architecture</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">I read your article on 'Earthen Architecture', published by the CTA Bulletin in the September-October 1996 issue of The Courier (n° 159) with a great deal of interest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The article presents such traditional products as rammed earth and adobe which have been used by man since time immemorial as witnessed by constructions and monuments to be found in the countries cited by the authors of the article, as well as industrial products such as the compressed earth block (CEB), which have provoked much interest in many parts of the world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The authors also demonstrate that the use of the compressed earth block has a distinct advantage in that it valorises local raw materials, encourages the setting up of local enterprises and creates employment.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this regard, I would particularly wish to inform you that the Centre for the Development of Industry (CDI) has, for the last ten years, been working on the industrial development of the CEB sector through support to ACP promoters at various levels:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - diagnostic studies of projects and setting-up of production units;</P>
+<P ALIGN="JUSTIFY"> - search for EU technical partners who have economically advantageous technologies and are ready to transfer their know-how;</P>
+<P ALIGN="JUSTIFY">- training of enterprise personnel in CEB production and in the utilisation of this product;</P>
+<P ALIGN="JUSTIFY">- support in the manufacturing of brick presses such as is currently the case in Nigeria.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some 100 small and mediumsized enterprises and non-governmental organisations in ACP countries involved in the CEB sector have benefited from direct CDI assistance. This assistance has, notably, led to the improved technical and economic performance of these enterprises.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beyond support to projects, the CDI in collaboration with CRATerre actively participates in the industrial promotion of this technology. The Centre recently disseminated 2000 copies of a technical guide entitled 'CEB: Production Equipment' throughout the ACP countries. An exhibition on the compressed earth block and its application took place during the Industrial Mining Forum held in Lusaka, Zambia, in December 1994. Similar exhibitions were held during the Matconstruct Forum (Libreville, Gabon, October 1995) and at the Industrial Partnership event (Bordeaux, France, February 1995). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The standardisation of the compressed earth block is a prerequisite for the development of this sector. The Centre therefore organised a workshop on this topic in Yaounde in 1996 as a follow-up to the Matconstruct Forum. This seminar brought together some 40 ACP and EU participants to discuss the 'CEB: Standardisation' guide currently being prepared by CRATerre for publication in December 1996.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main objective of the guide is to encourage ACP promoters to manufacture products in conformity with accepted norms and thus facilitate CEB integration in the industrial construction market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Efforts made by the CDI, in collaboration with CRATerre, to develop the CEB sector deserve to be better known. We would therefore look forward to an opportunity to present the Centre's activities in this sector in a future issue of me Courier. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Surendra Sharma, Director, Centre for the Development of Industry,</P>
+<P ALIGN="JUSTIFY">Brussels, Belgium.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Map insets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thank-you for your informative magazine. I wish you all the best in your endeavours to improve me Courier further. May I suggest that in the Country Report profiles, you include an inset map of the region highlighting the country in question for those readers who may not be familiar with the area.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Andrew Frederick Meya, Kampala, Uganda.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A number of readers have raised this point with us since we have rearranged the cover pages and transferred the ACP and Europe 'regional' maps to the inside back cover. In future, we will endeavour to ensure that there is a cross-reference to this page in the Country Report profile. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Bibliography</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Publications received</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">La politique etrangere du Cameroun (Cameroon's foreign policy) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Narcisse Mouelle Kombi. Pub. L'Harmattan, Collection «Points de vue» (5-7, rue de l'Ecole Polytechnique, F-75005 Paris). 1996. 238 pp. ISBN 2-73843701-X.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cameroon belongs to the zone formerly called the 'Third World' which is nowadays labelled the 'South'. This region of great diversity currently faces major socio-economic and political conflict, and receives 'multiform' and 'tied' aid from the developed countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This does not, however, prevent it from having a degree of freedom of action in diplomatic terms.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author, who is a specialist in international law, believes that as a player on the world scene, Cameroon puts its foreign-policy skills to good advantage and has acquired a certain respect in international relations and in global institutions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He argues that Yaounde is attempting to implement a realistic and pragmatic foreign policy, reflecting its own sovereign status and the imperatives of development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, the country is endeavouring to implement the changes forced upon it by modern circumstances.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Le developpement institutionnel - Les organisations a l'epreuve de la specificite et de la concurrence (Institutional development - Organisations based on specificity and competition) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Arturo Israel. Translated from the English by Alain Claisse. Pub. L'Harmattan (5-7, me de l'Ecole Polytechnique, F-75005 Paris). 1996. 235 pp. 140 FF. ISBN 2-73844322-2.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A graduate of the University of Chile and the London School of Economics, the author has devoted most of his career (particularly within the World Bank) to examining the problems of economic and social development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He has been one of the pioneers of institutional development, a field which is nowadays seen as essential to all development strategies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He argues that institutional development requires not bureaucratisation but the promotion and recognition of two principles in both public and private organisations. These are competition and specificity. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The former induces those involved to improve the quality of their work, whilst forcing them to listen to the 'consumer'. The latter involves qualifications, specialisation and a precise definition of objectives, tasks, resources and results.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">After a critical review of assessment reports produced over a 15-year period by the World Bank in the field of institutional development, Arturo Israel tells us why such development is one of the keys to success in development projects. He demonstrates that a good project being implemented in an unfavourable institutional environment has little chance of achieving positive long-term effects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">La justice internationale face au drame rwandais (International justice confronted by the Rwandan crisis) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under the direction of Jean-Fran&ccedil;oise Dupaquier, with William Bourdon, Pierre-Serge Heger, Frederic Mutagwera, Fran,cois-Xavier Nsanzuwera, Rakiya Omaar, William A. Schabas and Anne-Marie Swartenbroekx. Pub. Karthala (22-24, boulevard Arago, F-75013, Paris). 1996. 248 pp. FF 130. BF. 715. ISBN 2-86537-662-1.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is two years since the genocide and political massacres which resulted in the death of a million people in Rwanda. In this work, the authors describe and analyse the progress made in various legal proceedings in Rwanda itself, in the international arena and in the jurisdictions of Belgium, France, Canada and Switzerland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some countries have been slow and apparently reluctant to fulfil their international obligations and this has resulted in disappointment and impatience on the part of the victims' families, jurists and human rights activists.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the example of the Nuremberg trials, the authors suggest there are good grounds for concluding that international human rights have become less important over the last 50 years. This work allows one to reach a considered opinion. Modern legal instruments provide for the punishment of those responsible for the appalling tragedy in Rwanda. These instruments could be seen as a significant advance in the recognition of human rights by the international community. But what is missing at the moment is the political will (and public pressure) to implement them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Methodologies d'analyse de la mortalite des enfants - Applications au Cameroun (Analytical methodologies in child mortality as applied to Cameroon) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Amadou Noumbissi. Pub. Braylant-Academia (25, Grand Rue, B-134B Louvainla-Neuve) and L'Harmattan (5-7, rue de l'Ecole Polytechnique, F-75005 Paris). 1996. 305 pp. ISBN 2-87209389-3 (Academia-Braylant) and ISBN 2-7384-3722-2 (L'Harmattan).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Child mortality, always very high in sub-Saharan Africa, varies according to social class, habitat and region. The identification of the social, economic and cultural factors which influence the survival of children depends on the quality of data, and on the relevance of the indicators and statistical models used.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">With the aid of specific examples, this work attempts to demonstrate the origin of a number of sources of bias in so-called classical approaches and the distortion of the truth which a poor choice or detrimental manipulation of statistical models can give rise to.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A teacher and researcher at the Demographic Institute of the Catholic University of Louvain (Belgium), the author proposes methods to take account of the interdependence and synergy which exist between the factors which affect the risk of mortality. He applies these methods to the data gained in two national surveys which were carried out in Cameroon in 1978 and 1991.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Revue Region et Developpement (Region and Development Journal)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pub. L'Harmattan (5-7, rue de l'Ecole Polytechnique, F75005 Paris). 1995. 238 pp. ISBN 2-7384-4125-4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This half-yearly journal, first launched in 1995, deals with the various socio-economic aspects of regional development. The second issue contains articles which may be of interest to our readers, including: 'Regionalisation, globalisation and polarisation of the world economy: is there room for developing countries?', and 'Housing models in developing countries'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Structural adjustment and ethnicity in Nigeria</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">By Eghosa E. Osaghae. Pub. The Nordic Africa Institute (P.O. Box 1703, S-751 47 Uppsala, Sweden). 1995. 66 pp. ISBN 91-7106373-0.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The author is a lecturer who heads the politics department at the University of Transkei in South Africa. A significant conclusion from his study, undertaken at the Nordic Africa Institute, is that from the ethnic standpoint, the implementation of structural adjustment (with its corollary of reduced state involvement in public life), has had positive effects in Nigeria. This contrasts with the usual perception of the structural adjustment process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The migration experience in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collection prepared under the direction of Jonathan Baker and Tade Akin Aina. Pub. The Nordic Africa Institute (P.O. Box 1703, S-751 47 Uppsala, Sweden). 1995. 353 pp. ISBN-91-7106366-8.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This volume aims to take stock of migration in Africa. The causes of the phenomenon are varied and complex, and the authors have chosen an approach which illustrates the diversity of the theories, and methodological and analytical trends involved.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The book offers an empirical assessment of migration in contemporary Africa, focusing particularly on the problem of women migrants. Migration is an important element in the wider development equation and this work fills a gap in the literature.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Challenges to the Nation-State in Africa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collection prepared under the direction of Adebayo O. Olukoshi and Liisa Laakso. Pub. The Nordic Africa Institute (P.O. Box 1703, S-751 47 Uppsala, Sweden) in collaboration with the Institute of Development Studies, University of Helsinki. 1996. 213 pp. ISBN 91-7106381-1.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The challenge confronting the nation state in contemporary Africa are of great interest to specialists attempting to understand how deconstruction and recomposition of the political identity of populations affects the post-colonial unitarian project. The studies offered in this volume show that this process has often taken ethno-regionalist, religious or separatist forms -  reinforced by economic crisis and the negative effects of structural adjustment, not to mention the legacy of years of political authoritarianism and exclusion dating from the colonial period.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The authors believe that in order to promote national unity and a sense of citizenship in Africa, priority should be given, inter alia, to more representative forms of government, power-sharing and decentralisation, multi-party elections, the reinvention of the post-colonial social contract and cultural autonomy for minority groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agenda for Africa's economic renewal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Collection prepared under the direction of Benno Ndulu and Nicolas van de Walle. Pub. Overseas Department Council (1875 Connecticut Avenue, NW, Suite 1012, Washington, DC 20009, USA). 1996. 246 pp. ISBN 1-56000900-4.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For 20 years, sub-Saharan Africa has been experiencing a severe economic crisis. Growth has been stagnant and the result has been reduced living standards for much of the population, and ever-increasing pressure on the continent's political structures. Structural adjustment, advocated by international organisations in an attempt to restore growth in Africa, has not had the anticipated results and has given rise to a number of disputes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this book, 10 African, US and European experts attempt to look beyond the immediate horizon and identify strategies which could be implemented to give renewed vigour to the African economy. They analyse the choices which should be made in key areas such as agriculture, trade and industry, the role of the state and the social sectors. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">News round - up</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<I><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">In brief</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">World congress against the sexual exploitation of children</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first international congress dealing with the problem of the sexual exploitation of children for profit was held in Stockholm from 27 to 31 August. The initiative for the meeting came from ECPAT (End Child Prostitution in Asian Tourism), working in collaboration with the Swedish government, the United Nations Children's Fund (UNICEF) and a group of NGOs supporting the Convention on the Rights of the Child. The congress was attended by government representatives from most of the UN countries, participants from various international and regional organisations (including the UN Centre for Human Rights, the International Labour Organisation, the World Health Organisation, UNESCO, UNHCR and Interpol), NGOs, health professionals and media representatives from across the globe.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The aim of the congress was to draw the international community's attention to the issue of the sexual exploitation of children and to promote the development of national plans to tackle all forms of abuse in this area. It focused particularly on three aspects: child prostitution, the 'trade' in children for sexual purposes, and child pornography.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although there are a number of legal instruments which refer to these problems, the key one for the purposes of the Stockholm meeting was the Convention on the Rights of the Child. In Article 34 of this multilateral treaty, which has been ratified by 186 countries, the signatory states commit themselves to protect children against all forms of exploitation and violence of a sexual nature. For the purposes of the Convention, a child is defined as any human being less than 18 years old, except where the age of majority is lower than 18 in the relevant local legislation (Article 1).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The committee that was responsible for planning the Congress drew up documents on a number of themes including: the revision and application of laws; psycho-social prevention; tourism and child prostitution; those who engage in abuse; hygiene and health; the role of the media; child pornography; education; and human values. These subjects were all examined by working groups during the two-day session.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The congress was addressed by Anita Gradin, Member of the European Commission with responsibility for internal and judicial affairs, and matters relating to immigration. She took the opportunity to underline the point that the traffic in women and children was international. Organised crime, she said, lay at the heart of the 'trade' and it was closely linked to a whole range of other criminal activities. She cited, in this context, kidnapping, forging of documents, 'false' marriages and adoptions, clandestine immigration, violence and forced labour. these, in turn were associated with the drug trade, extortion and murder. The conclusion was that a global action plan and more international cooperation were needed. Ms Gradin acknowledged that existing arrangements had been successful in exposing the existence of paedophile networks but she was convinced that international cooperation should be strengthened further, and that organisations such as Interpol and Europol would be called upon to play a bigger part in the future. The European Commissioner went on to declare that a commitment to the protection of children ought to be a priority. The UN Convention on the Rights of the Child - which is now eight years old -  should not merely tee 'adopted' by all countries. It should, rather, be applied in full and integrated into the legislation of every nation. There was no point, she suggested, in enacting new laws, if the existing ones were not being implemented and the financial resources had not been provided. Ms Gradin reaffirmed the European Commission's commitment to the fight against the exploitation of children. This would be reflected in communications to be drawn up by the Commission for presentation to the Council of Ministers and European Parliament, on the following subjects:  - the treatment of women (on the basis of the recommendations made by the Vienna Conference on this subject, which was held in June 1996);  - sex tourism, notably in certain countries in Asia and Latin America;  - actions designed to eliminate paedophile rings and child pornography networks which make use of new information technologies such as the Internet. During the congress, the Belgian Minister of Foreign Affairs announced that his country would be launching an initiative at the EC's Justice and Internal Affairs Council meeting scheduled for 26 and 27 September. They would be proposing common action designed to strengthen police and judicial cooperation in the fight against the sexual exploitation of children for profit. He believed that it should be possible to take measures both within the framework of the Europol Convention, and by means of new and specific cooperation instruments. The culmination of the Stockholm congress was the adoption of a declaration and an action plan. These foresee strengthened cooperation and coordination among local and national authorities, and a series of measures to protect children, prevent abuse and provide rehabilitation. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">1997: European year against racism </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In a resolution adopted on 23 July, the Council of Ministers formally designated 1997 as the European year against racism. The aims, set out in the resolution, include:  - highlighting the threat posed by racism, xenophobia and antisemitism, in terms of both respect for fundamental rights, and in ensuring the economic and social cohesion of the European Community;  - encouraging reflection and discussion of the measures needed to tackle racism, xenophobia and antisemitism in Europe;  - promoting a sharing of experiences, best practice, and effective strategies drawn up at the local, national and European levels;  - disseminating information on the aforementioned best practice and strategies amongst those most closely involved in the fight against racism, xenophobia and antisemitism, with a view to enhancing the effectiveness of their actions in this area;  - highlighting the advantages of integration policies implemented at the national level, in particular in the fields of employment, education, training and housing;  - taking account, wherever possible, of the experiences of victims of racism, xenophobia and antisemitism, and promoting the participation of these people in society. ECU 6 million will be spent on a series of activities designed to help achieve these objectives during the 'year against racism'. A logo and slogan will be devised, and seminars and conferences will be staged with the aim of strengthening international cooperation (themes will include the role of education in eliminating racism, ways of establishing dialogue, and establishing mutual respect between different communities living in towns and cities). Documents and audiovisual material will be distributed, and an effort will be made to get the message across in the media. There will also be action to encourage information exchanges on best practice, and to increase public awareness of the issue. Prizes will be awarded to media organisations which safeguard the quality of the information they put out and which seek to promote tolerance. A specific effort will be made to counter the racist propaganda now appearing on the Internet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">WTO banana challenge</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union has set out its legal defence of duty-free preferences for African and Caribbean banana producing countries that are members of the Fourth Lom&eacute; Convention. This took place in September at an initial hearing of a World Trade Organisation (WTO) panel  - convened at the request of a number of competing banana producer nations. African and Caribbean states were permitted to voice their opinion as third part)" in the case, despite an objection from the United States. The EU's banana market arrangements  - notably Protocol 5 of the Lom&eacute; Convention, which sanctions duty-free access  - have twice before come under attack in the Geneva body. Two earlier hearings in the WTO's forerunner, the General Agreement on Tariffs and Trade (GATT), concerned the EU's previous state-to-state regime, and the new single market arrangements which have been in operation since July 1993. The present panel was set up at the request of four Latin American banana producer nations - Ecuador, Honduras, Mexico and Guatemala - together with the United States which is arguing that its domestic banana companies are losing out. The complainants jointly claim that the tariff quota for Latin American nations, the core of regulation 404/93 establishing the EU regime, discriminates against them. They also challenge the licensing arrangements of the so-called 'framework agreement' made under the GATT framework in 1994 with four Latin American nations (Colombia, Costa Rica, Nicaragua and Venezuela). In return for a bigger share of the EU market, these four agreed to refrain from further challenges in the WTO against the EU's banana arrangements.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The panel is expected to give its verdict in March 1997. The hearings are taking place behind closed doors, but it is understood that EU and ACP nations can count on the support of Japan - which currently imposes its own quotas on imports of other items and does not want to be challenged for these - and that of India which wants to show solidarity with the ACP countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Speaking in Geneva, Cot&eacute; d'lvoire's Commodities Minister, Alain Gauze, stressed the heavy dependence of many African and Caribbean states on banana growing. 90% of Dominica's commodity exports are bananas and the crop accounts for 70% of its export receipts and 25% of its Gross Domestic Product.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One ACP representative in Brussels described the task ahead es 'convincing them (the panel) that the banana regime and regulation 404/93 are required to fulfil the obligations of the EU under the Lom&eacute; Convention and the subsequent waiver.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The waiver to which he referred was accorded by GATT to the Lom&eacute; Convention's various non-reciprocal trade preferences in 1994, but it is up for renewal at the end of the year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU has already put in a request for its extension until February 29, 2000, coinciding with the expiry date of Lom&eacute; IV.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The WTO was expected to rule on the renewal of the waiver in mid-October ahead of the panel's decision. If the renewal of the waiver were to be disallowed, the EU and ACP 'defendants' at the panel could find themselves on shaky legal ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the meantime, the EU has fixed its 1996 tariff quota, allowing a maximum of 2.553 million tonnes of Latin American bananas to be imported into the Union with a tariff of ECU 75 per tonne.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A further quota of 72 440 tonnes has been allocated to this region following tropical storms Iris, Luis et Marilyn. The damage caused by these storms led to the suspension of supplies of bananas from several Caribbean islands. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EU banana production is expected to reach 750 000 tonnes in 1996, while preferential imports from the African and Caribbean members of the ACP group have been fixed at 680 000 tonnes. According to latest predictions, the total consumption of this fruit in the European Union in 1996 will be 4030440 tonnes. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">D.P.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Trade and labour standards</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ahead of the first ministerial meeting of the World Trade Organisation (WTO) to be held in December in Singapore, the European Commission has published a discussion paper (COM (96) 402 final) on whether labour standards should be linked to trade - which could mean sanctions for nations which do not comply with globally recognised labour clauses. What is at stake is to draw up globally recognised criteria and implement them without accusations of protectionism from some developing nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At an informal meeting of EU trade ministers in Dublin on September 18, EC Trade Commissioner, Sir Leon Brittan, said that, in supporting an international code, the European Union had no intention of damaging the competitive advantage of developing nations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many Asian countries, who view the move of the EU and of other industrialised nations as veiled protectionism, do not even want the subject broached at the Singapore meeting. However, mention was made of the link between trade and internationally recognised labour standards in the conclusions of the Uruguay Round of GATT in Marrakesh in 1994, which requested that the WTO do more work on this issue.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The recent Commission paper advances the reasons for an international code: 'Workers in certain sectors in particular perceive that their jobs are under threat from imports from countries which allow unfair or unacceptable working practices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These concerns cannot be ignored and should be addressed by the world trading system. Otherwise the perception will be - wrongly - that trade liberalisation is the problem and not the solution to the challenge to all societies to create a higher standard of living for all their citizens.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It further makes the point that such a policy is in line with others such as the promotion of democracy, respect for human rights and adherence to the rule of law. The EU has always upheld the view that there is a positive correlation between social progress, economic growth and trade liberalisation. According to the paper: 'There is no question of imposing on developing countries the higher wage levels and better working conditions which pertain in the industrialised world. Nor is this an action designed to re-erect new barriers to trade under cover of a social agenda.'</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU and international bodies are already looking at the kind of global criteria that might be adopted. A report of the International Labour Organisation (ILO), published in 1994, as well as the conclusions of the 1995 World Social Summit in Copenhagen, both suggest that freedom of association, collective bargaining, prohibition of forced labour and the elimination of child labour are top of the list.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A report entitled: 'Trade, Employment and Labour Standards - a study of core workers' rights and international trade', produced this year by the Paris-based Organisation for Economic Cooperation and Development (OECD), looks at the options in depth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jeff Atkinson, trade policy advisor for the NGO, Oxfam UK, suggests that initial negotiations should be limited to matters covered in ILO Conventions 87 and 98. The former deals with freedom of association and protection of the right to organise, while the latter is on the right to organise and collective bargaining. He argues that other Conventions, covering such matters as the right to equal renumeration for men and women workers, freedom from discrimination and the abolition of forced labour, depend on the first two. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A notable omission from Jeff Atkinson's list is ILO Convention 138 on child labour. He does not feel that this Convention adequately addresses the issue. While international concern has focused on the most abusive forms of child labour such as slavery and prostitution, he points out not all child labour is so grossly abusive. Some forms can bring in money for food and shelter, which would otherwise not be available.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">He argues that if conditions are right, employment (say on a family farm or business) can contribute positively to a child's development, by providing an informal learning environment in which social and physical skills can develop.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">'To tackle the symptoms, for example by banning child labour, without addressing the underlying cause is likely to be counterproductive', says Mr Atkinson. He argues that it might induce children to seek illegal work in order to survive, or alternatively that they may end up becoming destitute.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some bodies are already trying to enforce improved standards. Although the ILO cannot implement sanctions, if an ILO member fails to comply with Conventions, a dialogue can be instituted with the defaulting country. It is also running an extensive public campaign against child labour and is assisting the development of social labelling for goods produced which fully respect ILO Conventions.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under its new Generalised System of Preferences (GSP), the EU can remove some trade preferences if goods imported from non-Lom&eacute; developing nations are found to have been made with forced or slave labour. And from January 1, 1998, extra preferences can be given to countries which so request and comply with Conventions 87, 98 and 138. But if the enforcement of a socalled 'Social Clause' does reach the WTO level, some voices are already calling for joint monitoring involving the WTO and that long-time champion of human rights, the ILO. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">The 1996 UNCTAD Report</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A slow world growth rate is revealed in this year's annual report of the United Nations Conference on Trade and Development (UNCTAD), published in September. The global economy expanded by only 2.4% in 1995 compared with a 2.8% increase in 1994. And production is below what it could be, says the report. On the whole, developing nations achieved higher growth rates than their industrialised counterparts in 1995.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1996, world growth is expected to slow further although there will still be 'star performers' in some regions, and particularly slow movers in others. Asia is the continent currently doing best and China has the fastest expanding economy - despite this having slackened in recent years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1995, Africa recorded higher growth than Latin America, according to the Rubens Ricupero, UNCTAD Secretary General. It also managed the first real increase in average per capita income for a long time. This was partly due to commodity prices picking up - they rose 10% on average.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">But not such good news for the continent was a drop in private capital flows, notably direct investment. And the growth rate was highly variable across Africa. In some countries it was above 5% but in others, the economic situation was hit badly by political and armed conflicts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Meanwhile, drought led to lower production in the Sahel. The prospects for 1996 are uncertain according to the report. It noted that even countries whose economies have expanded during 1995 and 1996 will need another ten concurrent years of good economic results to get back to the per capita income they enjoyed 20 years ago.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The report highlights the tremendous difficulties facing many of the heavily-indebted, least developed nations. This is despite the fact that a number of donors have recently written off substantial amounts of some countries' public debts while the Paris Club has rescheduled repayments from other nations. Even if the new arrangements are followed through, UNCTAD is predicting that debt will remain a major burden for many countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One worrying factor is the weight of their multilateral debt and bilateral obligations to creditors other than the Paris Club. Multilateral institutions have implemented a number of measures, but these are of very limited scope. The UNCTAD Secretary General is encouraging multilateral creditors in particular, to put more muscle behind their debt relief plans.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The authors of the report are also recommending the establishment of an agency, within UNCTAD itself, to help developing nations achieve trade diversification and industrialisation strategies for economic growth. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Seminar on NGOs and government relations in humanitarian emergencies</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The British Council is organising an international seminar on the above subject in Oxford, UK, from 12-17 December 1996. The main themes to be covered at the meeting will include:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - the actors in humanitarian assistance;</P>
+<P ALIGN="JUSTIFY"> - funder and donor policy;</P>
+<P ALIGN="JUSTIFY">- government sovereignty;</P>
+<P ALIGN="JUSTIFY">- rights and obligations of intervention;</P>
+<P ALIGN="JUSTIFY">- the role of the beneficiary;</P>
+<P ALIGN="JUSTIFY">- conflicts of interest and areas of cooperation between donor NGOs and host governments, and;</P>
+<P ALIGN="JUSTIFY">- accountability and evaluation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Further information can be obtained from the Marketing Manager, International Seminars, The British Council, 1 Beaumont Place, GB-Oxford, OX1 2PJ.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tel. (44) 1B65 316 636, Fax. (44) 1865 57368.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">E-mail: International. Seminar@britcoun.org </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<I><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The institutions at work</Metadata>
+  </Description>
+-->
+</I><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">COMMON FOREIGN AND SECURITY POLICY</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Within the framework of its Common Foreign and Security Policy (CFSP), the European Union has recently issued a number of statements, details of which are set out below:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burundi: condemnation of the massacre on 19 July</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 23 July 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union expresses grave concern at the deteriorating situation in Burundi especially at the killing of civilians and other gross violations of human rights which continue to be perpetrated in that country. It vehemently condemns the massacre of civilians in the Bugendana camp for displaced persons on 19 July last and deplores the expulsions of Rwandan refugees against their will. This massacre, following as it does those at Gishubi, Kivyuka, Teza, Mutoyi, Songa and Kamenge, represents a new stage in the vortex of violence, action and reaction putting Burundi at risk of being drawn ever further into a full civil war, the effects of which would be catastrophic for the people of Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU calls on all Burundians to turn away from violence and move singlemindedly along the road to a peaceful and negotiated solution of their problems. It would point to the undertakings given on 25 June 1996 at Arusha during the Summit of Heads of State of the region in favour of dialogue open to all sectors of Burundi's population together with provision of the security measures needed to create the conditions for such dialogue. It would also point out that these undertakings were given formal backing by the Heads of State and Government of the entire continent of Africa when they met from 8 to 10 July at Yaounde under the aegis of the Organisation for African Unity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU believes that only compliance with the undertakings given at Arusha and their swift implementation can restore a climate of confidence and prevent Burundi becoming embroiled in a generalised conflict. As it has already stressed in the Council's statement of 15 and 16 July, the EU reiterates that it is prepared to assist in pursuit of the Arusha objectives in order to restore peace and security in Burundi and it supports the efforts of former President Nyerere and the countries of the region to achieve this.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burundi: appeal for reconciliation following the coup d'Etat </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 26 July 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union shares the deep concern of the Secretary General of the United Nations, and others, about yesterday's military coup in Burundi.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU urges all sides to avoid recourse to violence and to take all steps to resolve the crisis by exclusively peaceful means.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU believes that the main immediate priority is the humanitarian situation. There must be no further loss of life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An immediate beginning of a national debate is essential, leading to a real process of national reconciliation, founded on democracy and security for all sections of society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this regard, the EU commends the efforts of former President Nyerere and regional leaders to broker an all-inclusive, negotiated settlement in Burundi, in peaceful conditions, and urges them to examine the possibility of continuing their efforts in this respect.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU reiterates its firm commitment to the re-establishment of peace in Burundi. The Union is following developments in the country closely, in active consultation with partners in the UN, with the OAU and others, towards the goal of restoring peace and security in Burundi. The EU Special Envoy, Mr Ajello, who is in the region, is actively assisting in this process.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Niger: doubts about the first round election results</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 1 August 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union expresses deep concern about the way in which the first round of the presidential elections in Niger on 7-8 July was conducted. In particular, it deplores the decision taken by the Niger authorities to dissolve the independent national electoral commission during the voting process and to replace it with an alternative body. It is the view of the EU that this decision, by the Niger authorities, casts serious doubts on the credibility of the election results. It requests the Niger authorities to explain this decision and why observers found it impossible to assist in gathering and collating the election results.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU urges the Niger authorities, in dealing with the critical situation which has resulted from their decision, to respect fully the fundamental freedoms of movement, expression and association of the Niger people. It attaches great importance to the restoration of all civil rights.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU will examine, in the light of recent developments, its policies of economic and development cooperation with the Niger authorities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU calls for the full restoration of democratic civilian government in Niger through transparent processes. Free and fair elections will be crucial in this respect. The EU will continue to follow the situation in Niger closely and in particular the preparation, holding and transparency of the forthcoming legislative elections on 22 September. Iceland, the Central European countries associated with the EU and the associated countries Cyprus and Malta align themselves with this declaration.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Swaziland: revision of the Constitution</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 6 August 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The European Union welcomes the announcement by King Mswati III of the names of the new Prime Minister of Swaziland and of the Constitutional Review Commission and is pleased that its membership represents all shades of political opinion in Swaziland.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU wishes to encourage all members of the Constitutional Review Commission to participate fully in its work and expresses confidence that their endeavours will bring about the adoption of a draft democratic constitution acceptable to the people of Swaziland as a whole. It hopes that the Commission will pursue its task energetically and is ready to offer appropriate assistance to the Commission if it so wishes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burundi: appeal for talks and reconciliation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Declaration of 19 August 1996</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recalling its declarations of 25 June and 5, 15, 23 and 26 July 1996, the European Union reiterates its deep concern about the situation in Burundi. It urges all sides to refrain from violence and to commit themselves to, and work actively towards, a negotiated and peaceful resolution of the crisis.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU wishes to express its support for the regional leaders, the Organisation of African Unity and the former President of Tanzania, Mr Julius Nyerere, in the efforts which they have been making to assist Burundi to overcome peacefully the grave crisis which it is experiencing, and encourages them to continue their efforts to facilitate the search for a political solution.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU considers it essential for a dialogue to be organised without delay, bringing together all of Burundi's political forces without exception, including representatives of civil society, in order to negotiate a democratic, institutional consensus ensuring security for all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU is convinced that national reconciliation and civil peace in Burundi can be restored on a lasting basis only through the participation of all sections of society in the principal institutions and bodies of the State.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The EU urges all sides in Burundi to call an immediate halt to the violence and respect the safety of all Burundians.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It reaffirms its willingness to support Burundi's recovery efforts, once the necessary national reconciliation is embarked upon with all the resolve required.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AID FOR REHABILITATION</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Within the framework of the 'European Programme for Reconstruction and Development in South Africa', the Commission has recently decided on financing for the following ten projects:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> - ECU 19.2 million for a development programme covering the management of the public service;</P>
+<P ALIGN="JUSTIFY"> - ECU 17.2 million for technical assistance to the Ministry of Education;</P>
+<P ALIGN="JUSTIFY"> - ECU 16 million for a support programme for Parliament;</P>
+<P ALIGN="JUSTIFY"> - ECU 15 million for the electrification of rural schools;</P>
+<P ALIGN="JUSTIFY"> - ECU 9 million to support the reform process in the police services of the Eastern Cape province;</P>
+<P ALIGN="JUSTIFY"> - ECU 8.9 million for a financing and investment development programme for SMEs;</P>
+<P ALIGN="JUSTIFY"> - ECU 5 million for a programme of rural water supply and sanitation projects to be implemented </P>
+<P ALIGN="JUSTIFY">by the NGO Mvula Trust; </P>
+<P ALIGN="JUSTIFY"> - ECU 4.3 million to support the trade union movement;</P>
+<P ALIGN="JUSTIFY"> - ECU 2.3 million for the 'Soul City 1996' project designed to make full use of the mass media to promote health and development issues;</P>
+<P ALIGN="JUSTIFY"> - ECU 1.9 million to support the 'Truth and National Reconciliation Commission'.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">EUROPEAN DEVELOPMENT FUND</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Following, where required, favourable opinions from the EDF Committee, the Commission has decided to provide grants and special loans from the 5th, 6th and 7th EDFs to finance the following operations (grants unless otherwise stated). Major projects and programmes are highlighted.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic and social infrastructure</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burkina Faso: ECU 4.125 million for studies relating to certain road infrastructures. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mauritius: ECU 9 million for an irrigation programme in the northern plains. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Dominica: ECU 1.65 million towards the establishment of refuse treatments systems.  Trade promotion/ structural adjustment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cot&eacute; d'lvoire: ECU 25.5 million to , support the structural adjustment programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lesotho: ECU 8.6 million for the fourth structural adjustment programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Agriculture/rural development</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia-Kenya-Uganda: ECU 20 million for a programme to coordinate national activities aimed at achieving sustainable rural development in the region (notably involving the fight against the Tsetse fly)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Education/training</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Caribbean region: ECU 5.9 million towards a post-secondary education training programme in the countries of the OECS (Organisation of Eastern Caribbean States - Antigua &amp; Barbuda, British Virgin Islands, Dominica, Grenada, Montserrat, St Kitts &amp; Nevis, St Lucia, St. Vincent &amp; the Grenadines). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Environment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Malawi: ECU 4.4 million for a social/ participatory programme in the forestry sector as part of the implementation of a national forestry policy. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Institutional support</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">SADC member states: ECU 1.7 million to support the SADC (Southern African Development Community) secretariat in order to strengthen the SADC-EU regional programme. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UEMOA (West Africa Economic and Monetary Union): ECU 12 million to support the regional integration process in the member states (Benin, Burkina Faso, Cot&eacute; d'lvoire, Mali, Niger, Senegal and Togo) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia: ECU 1.5 million for a support programme for the Ministry of Finance and Economic Development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">EUROPEAN INVESTMENT  BANK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the first half of 1996, the Bank has provided the following loans from its own resources or in the form of risk capital:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Africa/Madagascar: ECU 30 million for ASECNA (I'Agence pour la securite de la navigation aerienne en Afrique et a Madagascar) for the renewal and modernisation of air safety equipment. Botswana: ECU 6.6 million to the Botswana Power Corporation to help increase electricity-generating capacity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Burkina Faso: ECU 6 million to SOFITEX (Societe burkinabe des fibres textiles) for the renewal and extension of its cotton ginneries facility. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mali: ECU 5.3 million to the Societe Energie du Mali for the financing of the Balingue thermal power station. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mauritania: ECU 2 million to SNIM (Societe rationale industrielle et miniere) for the setting up and operation of a mechanical workshop. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mauritania: ECU 1.4 million to the Societe arabe du fer et de l'acier (Arab iron and steel company) for the construction of a foundry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mozambique: ECU 500 000 to Grafites de Ancuabe for the exploitation of a graphite mine.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Zambia: ECU 2 million to the Zambia Venture Capital Fund, set up to subscribe for minority equity stakes in SMEs. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jamaica: ECU 40 million to Telecommunications of Jamaica Ltd for expansion and modernisation of the domestic and international telecommunications network. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">British Virgin Islands: ECU 600 000 to the government for the design and feasibility study of the main airport at Beef Island, Tortola. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tonga: ECU 3.7 million to the Tonga Telecommunications Commission for the development of the country's domestic telecommunications network.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">HUMANITARIAN AID</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Ethiopia: ECU 5 million for the purchase and distribution of vegetable oils and cereals to refugees living in the country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kenya: ECU 420 000 for emergency medical assistance in the fight against cholera in the Mandera region.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Somalia: ECU 1.9 million for emergency food aid to the victims of the continuing factional fighting. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sudan: ECU 2.5 million for the purchase and distribution of maize in a transit camp close to the capital (154 000 people) and in the south of the country (1 million people), and for the distribution of sorghum to Ethiopian and Eritrean refugees in the east (200 000 people). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chad: ECU 150 000 to help tackle the cholera epidemic. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Haiti: ECU 10 million for a programme to counter malnutrition and improve basic health care, in particular for women and children in isolated locations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Montserrat: ECU 380 000 to help evacuees in the wake of the recent volcanic eruption. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Non-ACP countries</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Colombia: ECU 1 million for people displaced as a result of drug terrorism and the fighting that has been taking peace between government forces and guerillas. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Costa Rica: ECU 400 000 for the victims of Hurricane Cesar. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Guatemala: ECU 220 000 to train teachers in order to improve education among repatriated communities in the department of Alta Verapaz. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nicaragua: ECU 440 000 to improve conditions for the social and economic reintegration of uprooted populations (people who have been repatriated, displaced or demobilised) in the department of Rio San Juan. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Northern Caucasus: ECU 4.18 million for civilian victims of the war in Chechnya and for refugees in Ossetia and Dagestan. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Iraq: ECU 9 million for food aid, medical provisions, rehabilitation of drinking water systems, sanitary equipment and educational material to assist 3 million people in the north and centre of the country.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Yemen: ECU 150 000 for flood victims. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Cambodia: ECU 290 000 for a programme to construct and distribute artificial limbs to land-mine victims. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thailand (Burmese refugees): ECU 220 000 for 'Mon' refugees from Burma (Myanmar) who have fled the violence in their country. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thailand (Burmese refugees): ECU 500 000 for medical aid in favour of 'Karen' refugees from Burma (Myanmar). </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FOOD AID</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Commission has recently decided to allocate the following aid: </P>
+<P ALIGN="JUSTIFY"></P>
+
+<!--
+</Section>
+</Section>
+</Section>
+</Section>
+-->
+
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec160e/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec160e/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/ec160e/metadata.xml	(revision 10506)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">The Courier - NÂ°160 - Nov - Dec 1996 - Dossier Habitat - Country reports: Fiji , Tonga (ec160e)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Settlements, Housing, Building - Infrastructure Construction (Roads etc)|Settlements and housing: general works incl. low- cost housing, planning techniques, surveying, etc.</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Development Periodicals and Magazines|The Courier ACP 1990 - 1996 Africa-Caribbean-Pacific - European Union</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">EC Courier</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb33fe/fb33fe.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb33fe/fb33fe.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb33fe/fb33fe.htm	(revision 10506)
@@ -0,0 +1,890 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Farming snails 1: Learning about snails; Building a pen; Food and shelter plants</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Farming snails 1: Learning about snails; Building a pen; Food and shelter plants</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FOOD AND AGRICULTURE ORGANIZATION OF THE UNITED NATIONS</P>
+<P ALIGN="JUSTIFY">Rome 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P-69</P>
+<P ALIGN="JUSTIFY">ISBN 92-5-102396-4</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&copy; FAO 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Introduction</Metadata>
+  </Description>
+-->
+</B><P ALIGN="CENTER"></P>
+<P ALIGN="JUSTIFY">1. Did you know that many kinds of snails are good to eat?</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2. Snail meat tastes good and it is also good for you. If you have snail meat to eat, it will help to keep you and your family strong and healthy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p60a.png"></center><br>
+ Family kept strong and healthy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3. If you want to have snails to eat you can get them in different ways.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">4. Many people gather wild snails that live nearby. Sometimes you can buy snails at the market or from people who gather them to sell to others.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">5. You can also raise your own snails. This is called snail farming. Today, a great many people all over the world farm snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">6. If you farm your own snails, you will always have a supply of fresh snail meat whenever you want it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">7. Then, if your family is not too big and you grow more snails than you need to eat, you can sell what you do not use to your neighbours or at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p61a.png"></center><br>
+ Selling snails at the market</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">8. With more food to eat and the money you get by selling snails, you and your family can live better.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">9. However, if your family is big you will need to grow many more snails if you are going to have enough to eat and to sell at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p61b.png"></center><br>
+ You need to grow more snails if your family is big</P>
+<P ALIGN="CENTER"></P>
+<P ALIGN="CENTER">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">What do you need to start?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="CENTER"></P>
+<P ALIGN="JUSTIFY">You will need</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> enough snails to start your snail farm</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY"><center><img src="f33p61c.png"></center><br>
+ Snail</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> a place near your house with the right kind of soil and the right amount of water for snails to live and grow</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY"><center><img src="f33p61d.png"></center><br>
+ A place near your house</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> the kinds of plants that snails need for food and shelter</P>
+<P ALIGN="JUSTIFY"> the materials to build a pen for the snail</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY"><center><img src="f33p62a.png"></center><br>
+ Plants that snails need; The materials to build a pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">10. If you have or can get all of these things, you can raise snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="CENTER">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Learning about snails</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">11. To farm snails is not hard; however, it is quite different from keeping chickens or ducks or from growing crops such as maize, rice, cassava or groundnuts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">12. Since farming snails is so different from other kinds of farming, you will have to learn a lot of new things.</P>
+<P ALIGN="JUSTIFY">13. One way to learn about snails so that you will be able to farm them is to watch the wild snails that live near you.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p62b.png"></center><br>
+ Watch the wild snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">14. Try to see how they live, how they move and where they go, what plants they like best and what they eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">15. You can learn many things by watching wild snails that will help you later if you decide to start a snail farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p63a.png"></center><br>
+ Wild snail</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">16. Another way to learn about snails is to ask an older farmer who knows a lot about your area. If there are people near you who gather snails to sell to others, they may be able to help you.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">17. In the next part of this booklet, you will begin to learn some things that you need to know to farm snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">What kind of snails can you farm?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">18. The kind of snails that you can farm are snails that live on land, and there are many kinds of land snails that are good to eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">19. However, some kinds of land snails are not good to eat and they may even make you very, very sick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">20. So, you must be very careful when you choose snails to farm. If you are not sure that a snail is good to eat, do not use it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p63b.png"></center><br>
+ Do not use snail unless you are sure it is good to eat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">21. Now look at the drawings on pages 8 to 11 and you will see four kinds of good snails that live in different places.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">22. You may be able to find one of these kinds of snails where you live. Notice that two of them are small and two of them are large.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">23. The smaller kinds of snails, shown on pages 8 and 9, can often be found in places where part of the year is warm and part of the year is cold.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">24. The larger kinds of snails, shown on pages 10 and 11, can often be found in places where it is warm all year round.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p64a.png"></center><br>
+ Helix pomatia</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">This kind of small snail</P>
+<P ALIGN="JUSTIFY">1 can be found in places where part of the year is warm and part of the year is cold</P>
+<P ALIGN="JUSTIFY">2 weighs from 15 to 25 grams and measures from 40 to 50 millimetres</P>
+<P ALIGN="JUSTIFY">3 has a strong shell which is pale brown and off- white</P>
+<P ALIGN="JUSTIFY">4 grows to full size in two to three years if it is well fed</P>
+<P ALIGN="JUSTIFY">5 lays from 30 to 50 eggs each growing season</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p64b.png"></center><br>
+ Helix Pomatia - 30 to 50 small eggs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p64c.png"></center><br>
+ Helix aspersa</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This kind of small snail</P>
+<P ALIGN="JUSTIFY">1 can often be found in places where part of the year is warm and part of the year is cold</P>
+<P ALIGN="JUSTIFY">2 weighs from 4 to 20 grams and measures from 30 to 45 millimetres</P>
+<P ALIGN="JUSTIFY">3 has a weak shell with broken stripes which are light brown to black</P>
+<P ALIGN="JUSTIFY">4 grows to full size in one year if it is well fed</P>
+<P ALIGN="JUSTIFY">5 lays from 40 to 170 eggs one to three times each growing season</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p64d.png"></center><br>
+ Helix aspersa - 40 to 170 small eggs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p65a.png"></center><br>
+ Achatina achatina</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This kind of large snail</P>
+<P ALIGN="JUSTIFY">1 can often be found in places where it is warm all year round</P>
+<P ALIGN="JUSTIFY">2 weighs from 150 to 200 grams or more and measures from 90 to 130 millimetres</P>
+<P ALIGN="JUSTIFY">3 has a very strong brown shell</P>
+<P ALIGN="JUSTIFY">4 grows to full size in two years if it is well fed</P>
+<P ALIGN="JUSTIFY">5 lays from 100 to 300 eggs one to two times each growing season</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p65b.png"></center><br>
+ Achatina achatina - 100 to 300 small eggs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p65c.png"></center><br>
+ Archchatina marginata</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This kind of large snail</P>
+<P ALIGN="JUSTIFY">1 can often be found in places where it is warm all year round</P>
+<P ALIGN="JUSTIFY">2 weighs from 150 to 200 grams or more and measures from 90 to 130 millimetres</P>
+<P ALIGN="JUSTIFY">3 has a very strong brown shell</P>
+<P ALIGN="JUSTIFY">4 grows to full size in two years if it is well fed</P>
+<P ALIGN="JUSTIFY">5 lays from five to ten eggs four to eight times each growing season</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p65d.png"></center><br>
+ Archchatina marginata - five to ten large eggs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">25. If you cannot get one of these snails, you may be able to get others very much like them where you live.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">26. There are many other kinds of good snails. There may even be several kinds of good snails that are eaten where you live.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">27. If snails are eaten where you live, you can farm one of these. Then you will be sure that it is good to eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Where can you get snails?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">28. When you are ready to get snails, perhaps you can get them by gathering wild snails that live near you.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p66a.png"></center><br>
+ Gathering wild snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">29. Perhaps you can buy them from people who gather wild snails to sell to others.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p66b.png"></center><br>
+ Buying from one who gathers wild snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">30. You may even be able to buy them from another snail farmer.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p66c.png"></center><br>
+ Buying from another snail farmer</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">Never term snails that you buy at the market. Snails at the market may have been washed, kept too cold or hurt and they may die soon.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Where can you farm snails?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">31. A good place for a snail farm is one where there already are snails. If there already are snails, you will know that the soil and the water in the soil are right for snails to live and grow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">32. However, if there are no snails near where you live it does not mean that you cannot raise snails there.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">33. If you have the right kind of soil with the right amount of water, you can bring good snails from another place to start your snail farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The soil and the water in the soil</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">34. Soil is important for snails. Part of the time they live on the soil and part of the time they live in the soil, and to live well, snails need good soil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p67a.png"></center><br>
+ Snail on the soil; Snail in the soil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">35. When snails are not on the soil or in the soil, they are on plants which grow in the soil. So, the soil must also be good for the kinds of plants that snails need.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p67b.png"></center><br>
+ Snail on plant</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">36. When snails are in the soil, they are resting or laying their eggs. If the soil has the right amount of water, snails will live well, the eggs they lay will hatch well and the baby snails will come out of the soil easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">37. Snails cannot live in hard soil such as heavy clay soils. When heavy clay soil is too dry, snails cannot dig into it to rest and lay their eggs. When heavy clay is too wet, snails and the eggs they lay may die.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">38. Snails cannot live in loose soil such as soils that have a lot of sand. Sandy soils do not hold enough water for snail eggs to hatch.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">39. The drawings on the next page show how a snail digs a hole, lays its eggs, closes the hole and how the baby snails come out when they have hatched.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">40. Snails need calcium from the soil to make their shells. All snails grow better and have stronger shells when there is a lot of calcium in the soil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">41. So, if you are going to farm snails, you must have a good medium soil that has neither too much clay nor too much sand. It must also have enough calcium and the right amount of water for your snails to live and grow.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">If you have a garden, you can easily tell if your soll is good for snails. If your green leafy vegetables grow well, snails will also grow well in the same kind of soil</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p68a.png"></center><br>
+ Snails will grow well in a garden</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1 snail digging a hole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p68b.png"></center><br>
+ 1 snail digging a hole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2 laying the eggs and closing the hole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p68c.png"></center><br>
+ Snail laying eggs</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3 baby snails hatching and coming out of the hole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p68d.png"></center><br>
+ Baby snails hatching and coming out of the hole</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Plants for food and plants for shelter</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">42. Snails need plants for both food and sheller. Most kinds of snails use several kinds for food and several other kinds for shelter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p69a.png"></center><br>
+ Plants for food and plants for shelter</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">43. They may also use different plants for food and shelter at different times of the year. Sometimes during the growing season snails eat and find shelter on the same plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">44. Snails usually hide on shelter plants during the day when it is dry and move to food plants to eat at night or early in the morning when they are wet with dew. However, sometimes snails do eat during the day after it has rained.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">45. If you live in a place which has a season when plants do not grow, snails will dig into the soil to rest and they do not eat then.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">46. During the growing season snails will eat a lot and grow very fast if they have food plants that they like.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">47. So, before you begin you will have to find out exactly what plants they like to eat. To do this you will have to watch snails at night when they eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p69b.png"></center><br>
+ See what snails eat at night</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">48. You can tell that snails are eating when you see their heads moving as they scrape food into their mouths. You can also tell when a snail has been eating by the holes it makes in the leaves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p69c.png"></center><br>
+ Snail on leaf</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">49. You will also have to find out what plants they like for shelter. To do this you will have to watch snails during the day when they rest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p70a.png"></center><br>
+ See where snails rest during the day</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">50. It is often difficult to find snails on shelter plants because they are hiding. So, you will have to look very carefully.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p70b.png"></center><br>
+ Snails are hiding on shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">51. In addition to the food plants, there are many other kinds of foods that you can put into a pen for your snails to eat. You will learn about these foods and when you should use them in the next booklet in this series.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Dew and rain</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">52. Dew at night in the growing season helps the plants to grow and makes the leaves and the ground wet so that snails can move about.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">53. Rain in the growing season also helps the plants to grow and it cleans the plants of dust and the dirt that snails leave when they move about. The dirt that snails leave may make them sick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">54. So, it is very important that the food and shelter plants are wet and clean.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">55. When the leaves are wet, snails move easily, eat more and grow well. When the leaves are dry, snails move very little, or not at all, and they grow poorly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p70c.png"></center><br>
+ Wet leaves are good for snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">56. When it rains and the plants are clean, the snails will be healthy. When it does not rain and the plants are dirty, the snails may get sick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">57. Dew and rain also keep the ground moist so that the snails can move easily and dig into it to rest and to lay their eggs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">58. In the next booklet, you will be told how to wet the leaves of plants and moisten the ground when it is too dry.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Land that is wet</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">59. Land that is very wet, low land that does not drain well or land that floods in the rainy season is not good for snail farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p71a.png"></center><br>
+ Low, wet land is bad for snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Wind</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">60. Wind during the growing season is bad because it dries the dew and dries out the snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p71b.png"></center><br>
+ Wind is bad for snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">61. If you decide to farm snails, try to keep them in a place that is protected from the wind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p71c.png"></center><br>
+ Snails should be farmed in a place protected from the wind</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Where do you keep snails when you farm them?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">62. If you decide to farm snails you must keep them in a pen. Snails kept in a well- built pen will not get away easily and you can watch them and take care of them well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">63. After the first year you will need at least two pens. If you decide to farm more snails you may want even more pens. You will learn how to use two or more pens in the next booklet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p72a.png"></center><br>
+ Two pens the second year</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">64. In each pen you can give your snails the right kinds of plants for them to eat and to use as shelter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">65. In each pen you can put the food and shelter plants near each other so that the snails can move easily from one to the other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">66. Each pen you build must also keep the snails safe from their enemies. Snails have many enemies. You must be careful to protect them from</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> mice and rats</P>
+<P ALIGN="JUSTIFY"> shrews and moles</P>
+<P ALIGN="JUSTIFY"> walking insects that live on the ground such as ants and beetles</P>
+<P ALIGN="JUSTIFY"> slugs and other snails that eat snail meat</P>
+<P ALIGN="JUSTIFY"> birds that eat snails</P>
+<P ALIGN="JUSTIFY"> frogs and toads</P>
+<P ALIGN="JUSTIFY"> thieves</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY"><center><img src="f33p72b.png"></center><br>
+ Protect them from
+</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">67. A snail pen can be small or large depending on how many snails you want to raise. However, when you first begin, start with a small pen. You will need fewer materials. It will be easier to take care of.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">68. In addition, with a small pen you will need fewer snails to begin. When you know more about raising snails, you can build a bigger pen and get more snails to raise.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">69. A good size for a pen is 5 x 5 metres. Later in this booklet you will learn how to build a small pen of this size.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">How many snails will you need when you first begin?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">70. If you are using small snails like those you have seen on pages 8 and 9 in this booklet, you will need more snails to begin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">71. If you are using large snails like those you have seen on pages 10 and 11 in this booklet, you will need fewer snails to begin.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">72. With a pen of 5 x 5 metres (25 square metres) you will need</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> 150 snails if you use the small kind (6 for each square metre)</P>
+<P ALIGN="JUSTIFY"> 25 snails if you use the large kind (1 for each square metre).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p73a.png"></center><br>
+ 150 small snails; 25 large snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">How much snail meat can you expect to get?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">73. The amount of snail meat that you will get from small snails will be about the same as what you would get from large snails. This is because you will use many more small snails than large snails and the meat will be about equal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">74. With one 5 x 5 metre pen you will get 12 to 13 kilograms of snail meat each year and with two 5 x 5 metre pens you will get 24 to 26 kilograms each year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p73b.png"></center><br>
+ 12 to 13 kilograms each year; 24 to 26 kilograms each year</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Now you must decide</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">75. In the first part of this booklet you have learned many things about snails and farming snails. You have learned</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> why it is good to farm snails</P>
+<P ALIGN="JUSTIFY"> what you need to farm snails</P>
+<P ALIGN="JUSTIFY"> what kinds of snails you can farm</P>
+<P ALIGN="JUSTIFY"> how to find plants near you that are good for food and shelter</P>
+<P ALIGN="JUSTIFY"> what kind of soil and how much water in the soil snails need</P>
+<P ALIGN="JUSTIFY"> where to keep snails and how many you need to start</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">76. You may also have been able to learn a lot about snails by watching the wild snails near where you live.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">77. An old farmer may have told you what he knows about snails. Someone who gathers snails to sell to others or another snail farmer may have helped you to learn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">78. So, now that you know a lot about snails it is time to decide if you would like to start your own snail farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">79. If you would like to begin you will learn exactly what to do in the rest of this booklet and in the next booklet.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">How to begin</Metadata>
+  </Description>
+-->
+<P ALIGN="CENTER"></P>
+<P ALIGN="CENTER">&nbsp;</P>
+<P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Choose a place on your land to put your snail farm</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">80. Try to choose a place that is close to your house. That way you will be able to watch your snails, protect them from their enemies and take care of them easily</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p74a.png"></center><br>
+ Close to your house</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">81. In Items 34 to 41 you were told that to farm snails you must have the right kind of soil with the right amount of water.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">82. Remember, if green leafy vegetables grow well in your soil, snails will also grow well in the same kind of soil.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p74b.png"></center><br>
+ If your garden grows well, so will your snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">83. In Items 59 to 61 you were told that low, wet land and wind are bad for snails. So, avoid low, wet places and try to put your snail farm where it is protected from the wind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p75a.png"></center><br>
+ Avoid low, wet land; Find a place protected from wind</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">84. In Item 63 you were told that after the first year you will need at least two pens and later you may want even more. In Item 69 you were told that it is best to start with a small pen of 5 x 5 metres.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">85. So, try to find a place where you can put at least two or three 5 x 5 metre pens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p75b.png"></center><br>
+ two or three 5 x 5 metre pens</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Clean the site and prepare the ground</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">86. Clean the site and prepare the ground a little before the growing season so that you can build the pen in time to plant the food and shelter plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">87. First, mark out a square of 8 x 8 metres on the place that you have chosen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p75c.png"></center><br>
+ Mark and clear the 8 x 8 metre square</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">88. That way, with a pen of 5 x 5 metres in the centre of the square, you will have a path of 1.5 metres all the way around it (see Item 92). If you have enough land, the path can be even wider.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">89. Clear the square of trees, bushes grass, creeping grass and weeds. Take away all of the roots and the big stones that you can.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p76a.png"></center><br>
+ Take away roots and big stones</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">90. Spread the plant material that you have cleaned evenly on the ground and cover the whole square. If there is not enough, bring more plant material from another place.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p76b.png"></center><br>
+ Cover the square with plant materials</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">91. When the plant material is dry, burn it. This will kill the insects, the weed seeds and the roots of creeping grass, and rid the ground of mice, rats and shrews.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p76c.png"></center><br>
+ Burn the plant materials</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">Insecticides and poisons can also be used to rid your pen of insects, mice, rats and other enemies of snails. However, if you use them, do not use them by yourself because they are very dangerous. Ask someone who knows how to use them, such as your extension agent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">92. Now mark out a smaller square of 5 x 5 metres inside the big square. This is for your first snail pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p77a.png"></center><br>
+ Mark the 5 x 5 metre square</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">93. Dig the ground in the smaller square to a depth of 20 centimetres and turn it over well. As you dig, remove any rubbish or roots that you find.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p77b.png"></center><br>
+ Dig in the ground</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">94. While you are digging, if you see any more insects or any of the enemies of snails, bring more dry plant material and burn the ground again. To farm snails, the area must be free of insects, mice, rats and other enemies.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">95. When you have finished digging, the ground in the 5 x 5 metre square should be as smooth and well worked as it would be if you were planting a vegetable garden.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p77c.png"></center><br>
+ The 5 x 5 metre square should be smooth</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">96. However, do not use any fertilizer, animal manure or compost as you might with a vegetable garden. Fertilizers may burn the snails and animal manure or compost may bring in insects and weed seeds.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Building a pen</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">97. Build a pen for your snails as soon as you can after you have burned the plant material. This is to keep other insects, mice, rats or shrews from getting into your pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">98. A snail pen is a simple fenced- in area and you can build a fence using</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> corrugated sheet metal or plastic sheets</P>
+<P ALIGN="JUSTIFY"> woven plant material</P>
+<P ALIGN="JUSTIFY"> woven plant material with chicken wire</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY"><center><img src="f33p78a.png"></center><br>
+ Materials for fence</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Using corrugated sheet metal or plastic sheets</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">99. A fence of corrugated sheet metal or plastic sheets makes the best pen for snails because it keeps out their enemies very well. However, sheet metal or plastic costs a lot of money.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p78b.png"></center><br>
+ A fence of corrugated sheet metal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">100. If you are going to build a pen using corrugated metal or plastic, you must build it in such a way that the enemies of snails cannot get in between the sheets.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Using woven plant material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">101. To save money, you can build a fence of woven plant material such as split bamboo. If the woven material is tight, it will keep out enough of enemies for you to farm snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p79a.png"></center><br>
+ Woven material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Using woven plant material with chicken wire</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">102. If you can get fine- mesh chicken wire, you can improve a fence that is made of woven material.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p79b.png"></center><br>
+ Chicken wire</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">103. To do this, first make the fence of chicken wire and then cover it with woven material.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p79c.png"></center><br>
+ First use chicken wire then cover it with woven material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">104. The chicken wire will keep out rats and other small animals. The woven plant material will keep most of the insects out and keep the snails in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p79d.png"></center><br>
+ Keep out small animals</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">With any kind of pen animals such as rats may get in, and this is especially true with pens made only of woven plant material. So, you must always watch for rats and other animals and keep them out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">How to build the fence</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">105. Build the fence as you would any fence, by driving posts into the ground. Use posts 1.40 metres long. When the posts are in place they should be 1.00 metre above and 0.40 metre below the ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p80a.png"></center><br>
+ Drive posts into the ground</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">106. Whatever material you use for the fence of your pen, it should be buried 0.40 metre below the ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">107. If you are using woven material you will have to change the bottom of the fence when it rots.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">108. This can be done more easily by making the woven material in two parts, one for the top and one for the bottom. When the bottom part rots, you can change it without having to change the whole fence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p80b.png"></center><br>
+ Attach top parts first; attach bottom parts second</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Keeping your snails in the pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">109. Many of your snails may crawl over the fence and get out of the pen. If you build a flap on the inside at the top of the fence, it will be more difficult for your snails to get out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">110. However, even with a flap some snails may get out, and for this reason many snail farmers put two flaps on their fence. With two flaps they find that fewer snails get out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p81a.png"></center><br>
+ With two flaps, your snails will not easily crawl out of the pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">If you make your pen using galvanized sheet metal, you will not need flaps. Snails will not crawl on galvanized sheet metal.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">111. The drawings show you how to build a 5 x 5 metre pen using woven plant material, with and without chicken wire and how to build flaps to keep your snails in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p81b.png"></center><br>
+ How to build a 5 x 5 metre small pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3 if you are using woven material only, attach it as you were told to do in Item 108</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p82a.png"></center><br>
+ Attach woven material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">4 If you are using chicken wire and woven material, attach the chicken wire first and then the woven material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p82b.png"></center><br>
+ Attach the chicken material first</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">5 be sure that the fence cover goes all the way to the bottom of the 0.40- m trench</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p82c.png"></center><br>
+ 0.40- m trench</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">6 fill in the trench</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p82d.png"></center><br>
+ Fill in the trench</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">7 attach the flaps to the inside of the pen</P>
+<P ALIGN="JUSTIFY">Note: use woven material 0.25 m wide for the flaps</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">8 first attach the bottom flap using heavy cord</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p83a.png"></center><br>
+ Use heavy cord</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">9 then attach the top flap</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Plant the food and shelter plants</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">112. You have already been told that you should clean and prepare the site and build your snail pen in time for the planting season.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">113. If it has been only a short time since you dug the ground and worked the soil in your pen, you can begin to plant.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">114. If it has been a long time, dig and work the soil again before you plant. However, as you were told in Item 96, do not use fertilizer, animal manure or compost.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">115. Now you can begin to plant the food and shelter plants. Remember that you should use</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> plants that grow well where you live</P>
+<P ALIGN="JUSTIFY"> plants that last a long time</P>
+<P ALIGN="JUSTIFY"> plants that snails like</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">116. The drawings, show you two ways to plant food and shelter plants in a 5 x 5 metre pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">117. On pages 50 to 55 you will see some food and shelter plants that snails are known to like. Look at them carefully. Perhaps you can find some of them where you live.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two ways plant food and shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1 if your shelter plants are small, plant your pen like this</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p84a.png"></center><br>
+ Mark three places for small shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2 plant the shelter plants first and then plant the food plants all around the shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p84b.png"></center><br>
+ First plant the shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3 if your shelter plants are large, plant your pen like this</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p84c.png"></center><br>
+ Mark only one place for large shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">4 plant the shelter plants first and then plant the food plants all around the shelter plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p84d.png"></center><br>
+ Leave a path inside the fence</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">RAMPE</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p85a.png"></center><br>
+ Some plants for food</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rape is one of many kinds of smooth- leaved cabbage. It grows from seed and lasts a number of months. Rape is the best food plant for Helix snails (see pages 8 and 9 in this booklet). Many of the other kinds of smooth- leaved cabbage also make good food plants for snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p85b.png"></center><br>
+ Rape</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AFRICAN SPINACH (Amaranthus)</P>
+<P ALIGN="JUSTIFY">This green leafy vegetable is a good food plant for young Achatina and Archachatina snails. However, if you plant African spinach for your snails, they will need other kinds of food plants as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p85c.png"></center><br>
+ African spinach</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PAPAYA</P>
+<P ALIGN="JUSTIFY">You have already been told that snails can be given food to eat other than the food plants that you have planted in the pen (see also Items 175 to 179 in the next booklet). The tender green leaves and cut- up fruit of the papaya tree are very good for Achatina and Archachatina snails. However, the papaya should not be planted inside the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p86a.png"></center><br>
+ Papaya</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HORSE- RADISH</P>
+<P ALIGN="JUSTIFY">Horse- radish is a good food and shelter plant for young Helix snails. However, when they are older they will need other kinds of food plants as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p86b.png"></center><br>
+ Horse- Radish</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">LEAF BEET</P>
+<P ALIGN="JUSTIFY">Leaf beet grows well from seed and lives for one year. It can be used with He/ix snails for both food and for shelter. As a food plant alone it is not the best and you will have to give your snails other food plants as well. However, as a shelter plant it is very good for Helix snails. These snails lay eggs under the beet plants and find shelter around the roots in cold weather.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p86c.png"></center><br>
+ Leaf Beet</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BURDOCK</P>
+<P ALIGN="JUSTIFY">Burdock grows from seed and lives for more than a year. It grows very slowly and you should plant it as soon as you can so that it can grow big enough for your snails. However, once it has grown it makes a good food and shelter plant for almost any kind of snail.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p87a.png"></center><br>
+ Burdock</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BANANA and LOOFAH</P>
+<P ALIGN="JUSTIFY">Banana and loofah plants together provide both food and shelter for Achatina and Archachatina snails. Ripe bananas can be cut up and fed to the snails and they can use the loofah plant for food and for shelter. However, your snails will need other food plants as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p87b.png"></center><br>
+ Banana and Loofah</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">PLANTAGO</P>
+<P ALIGN="JUSTIFY">Plantago grows well from seed and lasts about two years. It is the best shelter plant for Helix snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p87c.png"></center><br>
+ Plantago</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ASPARAGUS</P>
+<P ALIGN="JUSTIFY">Asparagus lives for many years and it is a good shelter plant for young Achatina and Archachatina snails. However, it is not good for older snails because they are too heavy for asparagus plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">When are the plants big enough for food and for shelter?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">118. The food plants must be big enough to feed your snails and the shelter plants tall enough to cover them and to protect them from the sun.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">119. Depending on the kind of snails that you are raising, most plants will be big enough after they have been growing for about five to six weeks or when they have reached a height of 10 to 20 centimetres.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f33p88a.png"></center><br>
+ Plants will grow to a height of 10 to 20 cm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">120. When you are sure that the plants are big enough to provide food and shelter, you can begin to collect the snails and put them into the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">121. In Booklet No. 34, Farming snails 2, you will learn</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> how to choose good snails and how to put them in the pen</P>
+<P ALIGN="JUSTIFY"> how to take care of your snails</P>
+<P ALIGN="JUSTIFY"> when and how to harvest snails</P>
+<P ALIGN="JUSTIFY"> how to prepare snails for cooking</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">122. You will also be told some things that you can do to improve your snail farm so that later when you have more experience you can raise more and better snails.</P></FONT>
+<!--
+</Section>
+</Section>
+</Section>
+-->
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb33fe/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb33fe/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb33fe/metadata.xml	(revision 10506)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">Farming snails 1: Learning about snails; Building a pen; Food and shelter plants (fb33fe)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Agriculture and Food Processing|Better Farming series of FAO and INADES - 46 booklets</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Settlements, Housing, Building - Infrastructure Construction (Roads etc)|Settlements and housing: general works incl. low- cost housing, planning techniques, surveying, etc.</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">FAO Better Farming series</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb34fe/fb34fe.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb34fe/fb34fe.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb34fe/fb34fe.htm	(revision 10506)
@@ -0,0 +1,671 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Farming snails 2: Choosing snails; Care and harvesting; Further improvement</TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT FACE="Arial" SIZE=2><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Farming snails 2: Choosing snails; Care and harvesting; Further improvement</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FOOD AND AGRICULTURE ORGANIZATION OF THE UNITED NATIONS</P>
+<P ALIGN="JUSTIFY">Rome 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">P-69</P>
+<P ALIGN="JUSTIFY">ISBN 92-5-102397-2</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&copy; FAO 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Preface</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first twenty- six volumes in FAO's Better Farming Series were based on the Cours d'apprentissage agricole prepared in C&ocirc;te d'Ivoire by the Institut africain de d&eacute;veloppement &eacute;conomique et social for use by extension workers. Later volumes, beginning with No. 27, have been prepared by FAO for use in agricultural development at the farm and family level. The approach has deliberately been a general one, the intention being to constitute basic prototype outlines to be modified or expanded in each area according to local conditions of agriculture.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many of the booklets deal with specific crops and techniques, while others are intended to give the farmer more general information which can help him to understand why he does what he does, so that he will be able to do it better. Booklets No. 33 and 34 were added to the series owing to a growing interest in small- scale snail farming for food and profit in many countries where FAO's Better Farming Series is widely used.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Adaptations of the series, or of individual volumes in it, have been published in Amharic, Arabic, Bengali, Creole, Hindi, Igala, Indonesian, Kiswahili, Malagasy, SiSwati, Thai and Turkish.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Requests for permission to issue this manual in other languages and to adapt it according to local climatic and ecological conditions are welcomed. They should be addressed to the Director, Publications Division, Food and Agriculture Organization of the United Nations, Via delle Terme di Caracalla, 00100 Rome, Italy.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">The snails</Metadata>
+  </Description>
+-->
+<P ALIGN="CENTER"></P>
+<P ALIGN="CENTER">&nbsp;</P>
+<P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Choosing your snails</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">123. All of the snails that you choose for your pen must be of the same kind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p093a.png"></center><br>
+ All of the snails that you farm must be the same kind</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">124. You may have found one of the kinds of snails shown on pages 8 to 11 in the last booklet living in your area. You may also have found a different kind of snail.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">125. Now you must learn to choose the beat of the kinds of snails that you have found. When you first begin you will need fully grown snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">126. Remember, that all snails are both male and female and all snails lay eggs. So, when you are looking for snails, you can choose any one that is fully grown.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">127. You can tell that a snail is fully grown because it has a lip on the mouth of its shell. The drawings below show two fully grown snails with lips.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p094a.png"></center><br>
+ Snails which fill and which does not fill their cells</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">128. Look at the drawings again. Notice that although both snails are fully grown, one of them fills its shell and one of them does not.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">129. The snail that does not fill its shell may be sick or it may have lost its water because of dry weather. This snail may not grow well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">130. Choose only snails that fill their shells. Snails that fill their shells will usually grow well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">131. Choose snails that have good, strong shells. Strong shells protect snails from their enemies, and snails with strong shells sell better at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">132. Choose the largest of the fully grown snails that you can find from the kind of snail that you are going to farm.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p094b.png"></center><br>
+ Choose the largest snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">133. The larger snails of any kind of snail will be better and healthier and lay more eggs than a snail that is smaller.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">134. In addition, the eggs of large, healthy snails hatch better and the baby snails grow bigger and faster.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">135. Later, when you have more experience in choosing snails, you will learn just how large a fully grown snail should be. You will also learn the different colours of the kind of snail that you are farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">136. Then you can choose snails that are the same size and colour that you want your baby snails to be.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">As you collect your snails, handle them very gently and put them carefully into a container such as a basket so that you can carry them to the pen without hurting them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p095a.png"></center><br>
+ Handle your snails carefully</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Putting your snails in the pen</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">137. Just before you put your snails in the pen, take out all the grass, the creeping grass and the weeds that may have grown while the food and shelter plants were growing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p095b.png"></center><br>
+ Take out all grass, creeping grass and weeds</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">138. Never put snails in a pen in the morning or during the day when the sun is hot. Always put them in the evening when it is cool. This is when they begin to move about and to eat.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p095c.png"></center><br>
+ Always put snacks in the pen in the evening</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">139. If there is no dew and leaves of the plants and the ground are dry, wet them. Items 160 to 165 in this booklet will tell you how.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p096a.png"></center><br>
+ Wet the plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">140. When you put snails in the pen, put an equal number of them in four different places.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">141. In the last booklet you were told that for a 5 x 5 metre pen you would need 150 snails if you use the small kind, and 25 snails if you use the large kind. So, if you need</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> 150 snails, put 35 to 40 snails in four places</P>
+<P ALIGN="JUSTIFY"> 25 snails, put 6 snails in three places and 7 snails in one place.</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">142. The arrows in the drawing at the top of the next page will show you where to put snails in a 5 x 5 metre pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p096b.png"></center><br>
+ Where to put the snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">When you put snails in a pen, never put them near the fence or in a corner of the fence. If you put them near the fence it is easier for them to get out than it is if you put them near the centre of the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p096c.png"></center><br>
+ Do not put snails in the corner or near the fence</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">143. The morning after you have put your snails in the pen, look to see that they have all moved. If any of them have not moved, put them under shelter plants.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">144. If any snails die, take them out and put in the same number of new snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p097a.png"></center><br>
+ Take out the dead snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">145. At first your snails will try to crawl out of the pen. During this time, go around the pen each morning and put them back.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">146. After about two weeks your snails will become used to their new home and most of them will not try to crawl out.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">147. However, it is a good idea, even after the first two weeks, to check from time to time and put back any of the snails that may have got out of the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">When to take out the fully grown snails</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">148. When you see a lot of baby snails in your pen, you will no longer need to keep the fully grown snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">149. So, take out all of the fully grown snails that you first put into your pen. You can either eat them or sell them at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p097b.png"></center><br>
+ Take out all fully grown snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">150. Now, with only the baby snails left, the food plants in the pen will be more likely to last until the baby snails are big enough to harvest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">151. Later in this booklet, you will be told when the baby snails are big enough to harvest and how to harvest them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Taking care of your snails</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">152. After you have put your snails in their pen, watch them carefully to see that they are eating well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">153. If you have given them enough of the right kinds of food plants, they will eat a lot and you will have very little to do for them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">154. However, here are some things that you must do</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> wet the plants and moisten the ground</P>
+<P ALIGN="JUSTIFY"> take care of the plants</P>
+<P ALIGN="JUSTIFY"> take away the weeds and the creeping grass</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P></DIR>
+
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Wet the food and shelter plants and moisten the ground</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">155. You have already been told that the leaves of the food and shelter plants must be wet and clean and that the ground must be moist (see Items 52 to 58 in the last booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">156. If there is too lime dew and not enough rainfall during the time when the plants and the snails are growing, you will have to water the plants and the ground yourself.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">157. If it is dry, you should water the plants and the ground at least every second day. However, if it is very dry, you may have to water them every day.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">158. Never water in the morning or during the day when the sun is hot. Always water in the evening at about sunset.</P>
+<P ALIGN="JUSTIFY">159. If you water when the sun is hot, the snails will begin to move away from the shelter plants and the hot sun may kill them before they can find shelter again.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">160. An easy way to wet the plants and moisten the ground is by hand. First fill a bucket with water and wrap a piece of cloth around your hand.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p098a.png"></center><br>
+ Wrap a cloth around your hand</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">161. Then, dip your hand with the cloth into the bucket of water and gently splash the plants and the ground.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p099a.png"></center><br>
+ Gently splash plants and ground</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">162. Continue to splash the plants and the ground gently until you have watered the whole pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">163. When you have finished, the leaves of the plants should be wet and the ground should be moist.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">164. You can tell when the plants are wet enough and the ground is moist enough when you can see your snails moving about easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p099b.png"></center><br>
+ Snails move about easily</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">165. Remember: the soil must be moist and not wet in order for snail eggs to hatch.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">You have already been told that if you live in a place that has a dry season when the plants do not grow, snails dig into the ground to rest. Never water at this time or your snails may come out of the ground when they should not.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Tend the food and shelter plants</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">166. Watch all of your plants to see that they are growing well and that they do not get too tall or too thick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">167. Plants that are too tall or thick stop the dew from reaching the leaves and stop the rain from washing away the dust and the dirt that snails leave when they move about.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">168. If you see that the plants are not being wet or washed by dew or rain, cut them back.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p101a.png"></center><br>
+ Cut back the plants</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Take away the weeds and creeping grass</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">169. After your snails are in their pen you must be sure to take away all weeds and especially creeping grass as soon as you see them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">170. Creeping grass grows very fast and so thick that it can kill the food and shelter plants. If this happens, your snails will have no food and no place to find shelter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">171. Taking away weeds and creeping grass when snails are in the pen is very difficult. So, you must be very careful not to hurt them or step on them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">172. If the weeds and creeping grass get too thick, it may be better to move the snails before you take weeds and creeping grass away (see Item 183 in this booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">173. Keep the path around the pen clear of weeds, grass and creeping grass. This will help to keep weed seeds and unwanted plants out of the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p101b.png"></center><br>
+ Keep the path clean</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">174. If the path is clean, insects will be less likely to cross it to get into the pen and you will be able to see signs of mice, rats and shrews.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Feeding your snails other kinds of food</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">175. There are a number of reasons for giving your snails other kinds of food. Here are a few</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> when you have not planted the right kinds of food plants</P>
+<P ALIGN="JUSTIFY"> when you have too many snails for the number of food plants that you have planted</P>
+<P ALIGN="JUSTIFY"> when most of the food plants in the pen have been eaten by the snails</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">176. If you decide for any of these reasons that you must give your snails other kinds of food, here are some foods that snails like to eat</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> the outside leaves of vegetables such as cabbage or cauliflower</P>
+<P ALIGN="JUSTIFY"> the tops of vegetables such as carrots or beets</P>
+<P ALIGN="JUSTIFY"> ripe banana fruit</P>
+<P ALIGN="JUSTIFY"> most waste fruit and vegetables</P>
+<P ALIGN="JUSTIFY"> cut- up papaya, melon or squash</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY"><center><img src="f34p102a.png"></center><br>
+ Food snails eat</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">177. There are many other foods that snails like to eat. If you have some food that you think might be good, try it with your snails and see if they like it.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">178. If your snails are not eating their food plants well, you also can try some others. Cut pieces from the plant that you want to try and put them in the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">179. If you see that your snails like the new food plants better, you can use these plants when you build the second pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Building the second pen</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">180. In the last booklet you were told that to farm snails you will need at least two pens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p103a.png"></center><br>
+ Two pens needed</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">181 . With two pens you can move your snails from one pen to the other to get rid of any enemies that may have got in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">182. You can also move your snails to dig the ground and work the soil so that they can dig into the soil to rest and can lay their eggs easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">183. With two pens you can move your snails from one pen to the other if the weeds and creeping grass get too thick to take away with snails in the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">184. You can also plant new food plants when the old ones have been eaten. When you are moving the snails, you can get rid of any of them that have not grown well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">When to build the second pen and how to build it</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">185. Build your second pen a little before the growing season and exactly one year after you built the first pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">186. Begin just as you did before, by cleaning and preparing the ground (see Items 86 to 96 in the last booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">187. However, if you put your second pen near your first pen, be very careful when you burn the plant material not to burn your first pen or harm the snails in it.</P>
+<P ALIGN="JUSTIFY">188. For this reason it is best to leave an open space of at least 3 metres between your first and second pens.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p103b.png"></center><br>
+ Be very carefull when you burn the plant material</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">189. Now you are ready to build the second 5 x 5 metre pen and to plant the food and shelter plants (see Items 97 to 117 in the last booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Putting snails in your second pen</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">190. When the plants in your second pen have grown big enough to provide food and shelter, you can put in the snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p104a.png"></center><br>
+ When the plants are grown, you can bring the snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">191. If the snails in your first pen have grown well, you can use some of them for your second pen. So, collect the right number of the biggest and best snails from your first pen to put in your second pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">192. If the snails in your first pen have not grown well, you will have to begin again with new fully grown snails for your second pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">193. Remember, with your first pen you put in 150 snails if you used the small kind and 25 snails if you used the large kind.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">194. However, different snails lay different amounts of eggs. So with your second pen you may want to change the number of snails that you put in.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">195. If there were too many baby snails for the food plants in your first pen, put fewer fully grown snails in your second pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">196. If there were too few baby snails for the food plants in your first pen, put more fully grown snails in your second pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">197. If you are not sure how many snails to use, it is best to continue to put in 150 if you use small snails and 25 if you use large snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p104b.png"></center><br>
+ 25 Large snails; 150 small snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">198. Later, when you have learned more about the kind of snails that you are using and how many baby snails they have, you will be better able to judge just how many fully grown snails that you should use.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">Do not forget to take out all of the fully grown snails that you have put in after you see a lot of baby snails in your second pen (see Items 148 to 151 in this booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Harvesting your snails</Metadata>
+  </Description>
+-->
+<P ALIGN="CENTER"></P>
+<P ALIGN="CENTER">&nbsp;</P>
+<P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">When to harvest your snails</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">199. If your snails have grown well, some of them will be big enough to harvest about one year after you have first put snails in the pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">200. If you need any snails to put in another pen, collect them first. So, choose the right number (see Items 193 to 198 in this booklet) of the biggest and best snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">201. Carefully put these snails into a container so that you can carry them to the other pen without hurting them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p105a.png"></center><br>
+ Put snails into a container</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">202. Now you are ready to harvest the rest of your biggest snails. Remember, the best way to harvest is a few snails at a time when you want some to eat or to sell at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">203. However, harvest all of the snails by the end of the second year so that you can plant the pen in time for the next growing season.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">How to harvest your snails</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">204. Harvesting snails is done by hand. It is often hard work to find them because they may be hiding.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p105b.png"></center><br>
+ Harvesting snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">205. The easiest time to find the snails is when the plants are wet, after it has rained or at night when there is dew and they are moving about or eating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">206. You can also put out some of the food that snails like and when they come to eat it, you can collect them easily.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p105c.png"></center><br>
+ Put out some food</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">207. When you are harvesting, handle your snails carefully and put them into a container such as a box or basket or a net sack. However, do not put more than 10 kilograms in a container or you may hurt them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p106a.png"></center><br>
+ Put snails in a container</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">What to do with the snails you harvest</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">208. If you are going to sell the snails, you can carry them to the market in containers like the ones above. However, you must be very careful not to hurt them or break their shells.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">209. Remember, snails with clean shells and well- cared- for snails will sell better at the market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">210. If you want to keep the snails for you and your family to eat later, you can store them alive in containers filled with material such as sawdust or chopped maize husks.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">211. That way you can keep them for as long as six to eight weeks before you use them. The drawings below show you how to store snails this way.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1 a box is a good container to store snails in</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p106b.png"></center><br>
+ A box</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2 cover the bottom of the box with about 5 cm of sawdust or chopped maize husks</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p106c.png"></center><br>
+ Cover the bottom of the box with sawdust</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3 carefully put in a layer of snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">4 cover the snails with about 3 cm of sawdust or chopped maize husks</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p106d.png"></center><br>
+ Cover the snails</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">5 continue to do this until the box is full</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note: be sure that the top layer of snails is covered</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Preparing snails for cooking</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">212. Before snails can be used you must be sure that there is no food in them. They must be clean inside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">213. Snails that have been stored in a container (see Items 210 and 211 in this booklet) for more than four days will have no food left in them. They are clean inside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">214. However, snails which have just been taken from the pen have been eating and are usually full of food.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">215. So, before you can use them you must wait for them to become clean inside. To do this you need only to keep them from eating.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">216. Put them in a container where they can get no food but plenty of air. You can use a covered basket or a net sack.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p107a.png"></center><br>
+ Use a covered basket or a net sack</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">217. Put the basket or sack in a cool place away from the sun. After four days the snails will be clean inside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p107b.png"></center><br>
+ Put the container away from sun</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">218. All snails must be washed and boiled just before cooking them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">219. First, put them in clean, cool water with a little salt and vinegar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p107c.png"></center><br>
+ Put them in clean water</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">220. After a short time the water will begin 10 turn white and you will know that the snails are being washed inside.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">221. When the water is very white, take the snails out and empty out the old water. Then put them again in clean, cool water with a little salt and vinegar.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p108a.png"></center><br>
+ Empty out dirty water; wash snails again</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">222. Continue to wash them this way until the water no longer turns white. Then you will know that the snails are completely washed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">223. Now put the snails in boiling water, again with salt and vinegar, and boil them at least five minutes. The snails are now ready to be cooked.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p108b.png"></center><br>
+ Boil snails with salt and vinegar for five minutes</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Note</P>
+<P ALIGN="JUSTIFY">Snail meat can be cooked like any meat or it can be cut into pieces and added to a stew or vegetables. If snails are eaten where you live, there will be many ways to cook them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Further improvement</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">224. After you have been farming snails using two pens for some time, you may find that you and your family could eat or sell more snails if you had them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">225. You can raise more snails by building another pen. You can either build another 5 x 5 metre pen or you can build a still bigger pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">226. You can also raise more snails by taking better care of the snails that you have. If you take better care of your snails, year after year they will become bigger, healthier and stronger and produce more baby snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Building the third pen</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">227. Perhaps the most important thing that you can do to improve your snail farm is to build a third pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p109a.png"></center><br>
+ Build a third pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">228. Up until now, using only two pens, you have had to use both of them all of the time so that you could take fully grown snails from one after you had harvested the other.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p109b.png"></center><br>
+ Using two pens</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">229. Today, farmers know that it is not good to grow the same crops in the same place all of the time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">230. This is also true if you grow the same food and shelter plants in the same pen all of the time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">231. However, if you plant vegetables in one of your three pens for a year, the vegetables will grow well because of the snail manure in the soil. Afterwards, your food and shelter plants will also grow better because the soil has had a rest.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">232. Also, if you raise snails in the same place all of the time, the sicknesses that they may get would do more harm year after year.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">233. So, if you plant something else for a year or two and then start with snails again, they will be less likely to get sick.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">234. The diagram below shows you how to improve a snail farm by planting a vegetable garden in each pen from to time.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p110a.png"></center><br>
+ Diagram</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Building a bigger pen</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">235. You may want to build a still bigger pen for your third pen so you can grow many more snails.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">236. If you build a 5 x 10 metre pen, you can grow two times as many snails. If you build a 10 x 10 metre pen, you can grow four times as many snails as you did in a 5 x 5 metre pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p110b.png"></center><br>
+ Pens</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">237. However, building a bigger pen is a lot more work and you will need</P>
+<P ALIGN="JUSTIFY"></P><DIR>
+
+<P ALIGN="JUSTIFY"> more land</P>
+<P ALIGN="JUSTIFY"> more materials to build it</P>
+<P ALIGN="JUSTIFY"> more food and shelter plants</P>
+<P ALIGN="JUSTIFY"> more fully grown snails to begin</P>
+<P ALIGN="JUSTIFY"></P></DIR>
+
+<P ALIGN="JUSTIFY">238. You must also be sure that you and your family have enough time to take care of a bigger pen.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">239. If you do decide to build a bigger pen, build it exactly the same way that you built your first 5 x 5 metre pen (see pages 43 to 46 in the last booklet).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="f34p111a.png"></center><br>
+ Building a bigger pen</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Taking better care of your snails</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">240. The better you understand the snails that you are farming, the better you can take care of them. So, you should always watch them and learn as much as you can.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">241. When you have learned the exact kinds of food plants that your snails like to eat, you will see that they grow well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">242. Then, if you always choose the biggest and best snails each time you begin, you will improve the quality of the snails that you are farming.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">243. So, with bigger and better snails and with more pens or bigger pens, you will be able to raise many more snails to eat or to sell and you arid your family will be able to live better.</P>
+<P ALIGN="JUSTIFY"></P>
+
+<!--
+</Section>
+</Section>
+</Section>
+-->
+
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb34fe/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb34fe/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/fb34fe/metadata.xml	(revision 10506)
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">Farming snails 2: Choosing snails; Care and harvesting; Further improvement (fb34fe)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Agriculture and Food Processing|Better Farming series of FAO and INADES - 46 booklets</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Settlements, Housing, Building - Infrastructure Construction (Roads etc)|Settlements and housing: general works incl. low- cost housing, planning techniques, surveying, etc.</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">FAO Better Farming series</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+            <Metadata mode="accumulate" name="dls.Keyword">farm snails</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/wb34te/metadata.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/wb34te/metadata.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/wb34te/metadata.xml	(revision 10506)
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE GreenstoneDirectoryMetadata SYSTEM "http://greenstone.org/dtd/GreenstoneDirectoryMetadata/1.0/GreenstoneDirectoryMetadata.dtd">
+<GreenstoneDirectoryMetadata>
+    <FileSet>
+        <FileName>.*</FileName>
+        <Description>
+            <Metadata name="dls.Title">Development in practice: Toward Gender Equality (wb34te)</Metadata>
+            <Metadata mode="accumulate" name="dls.Language">English</Metadata>
+            <Metadata mode="accumulate" name="dls.Subject">Women, gender and development, women&apos;s organizations</Metadata>
+            <Metadata mode="accumulate" name="dls.Organization">World Bank</Metadata>
+            <Metadata mode="accumulate" name="dls.AZList">A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z</Metadata>
+            <Metadata mode="accumulate" name="dls.Keyword">achieve gender equality</Metadata>
+        </Description>
+    </FileSet>
+</GreenstoneDirectoryMetadata>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/wb34te/wb34te.htm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/wb34te/wb34te.htm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/import/wb34te/wb34te.htm	(revision 10506)
@@ -0,0 +1,1910 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="Generator" CONTENT="Microsoft Word 97">
+<TITLE>&lt;&lt;TOC1&gt;&gt; Development in practice: Toward Gender Equality </TITLE>
+</HEAD>
+<BODY>
+
+<B><FONT SIZE=2><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Development in practice: Toward Gender Equality</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Role of Public Policy</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">@ 1995 The Intentional Bank for Reconstruction and Development / THE WORLD BANK</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">All rights reserved Manufactured in the United States of America First printing July 1995</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Development in Practice series publishes reviews of the World Bank's activities in different regions and sectors. It lays particular emphasis on the progress that is being made and on the policies and practices that hold the most promise of success in the effort to reduce poverty in the developing world.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This book is a product of the staff of the World Bank. and the judgments made herein, do not necessarily reflect the views of its Board of Executive Directors or the countries they represent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Photo credits: Maurice Asseo</P>
+<P ALIGN="JUSTIFY">Library of Congers Cataloging-in-Publication Data</P>
+<P ALIGN="JUSTIFY">Toward gender equality: the role of public policy.  p. cm-(Development in practice)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Includes bibliographer references (p. 70)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ISBN 0-8213-3337-2</P>
+<P ALIGN="JUSTIFY">1. Women-Government policy. </P>
+<P ALIGN="JUSTIFY">2. Women's rights. </P>
+<P ALIGN="JUSTIFY">3. Sex discrimination against women. </P>
+<P ALIGN="JUSTIFY">4. Economic development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1. Series:</P>
+<P ALIGN="JUSTIFY">Development in practice (Washington. D.C.)</P>
+<P ALIGN="JUSTIFY">HQ 1 236.T68; 1995</P>
+<P ALIGN="JUSTIFY">305.4-dc20 95-631</P>
+<P ALIGN="JUSTIFY">CIP</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="CENTER"></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Foreword</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">TWENTY years ago in Mexico the First World Conference on Women inspired a movement that has helped to reduce gender inequality worldwide. Illiteracy among women is declining, maternal mortality and total fertility rates are beginning to fall. and more women are participating in the labor force than ever before. However. much remains to be done.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In low-income countries women are often denied health care and basic education. Worldwide. women face limited access to financial services, technology. and infrastructure. They are locked into relatively low-productivity work. In addition to performing household tasks and child-rearing duties, women work longer hours for lower pay than most men. And. most discouraging of all. hundreds of thousands of women each year are subject to gender-related violence.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Persistent inequality between women and men constrains a society's productivity and, ultimately slows its rate of economic growth. Although this problem has been generally recognized evidence on the need for corrective action is more controlling today than ever.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report written for the Fourth World Conference on Women is intended as a reference to strategies for promoting gender equality and. consequently enhancing economic efficiency. It pulls together evidence, including case studies, that demonstrates the need for governor action to improve the economic status of women. It points out how public policy can and should support services and infrastructure that provide the highest social returns and that are most heavily used by women. The report also aims to stimulate creative solutions to the problem of gender inequality by high lilting innovative and sometimes not obvious strategies that have proved successful. A study in Morocco, for instance, shows that paving public roads to schools increases by 40 percent the probability that local girls will attend classes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Policy reform that provides an enabling environment for economic growth goes hand in hand with investing in people. The success of one strategy draws on the success of the other. No efforts at gender equality. however, can be successful without the participation of women themselves.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As the international community gathers in Beijing for the Fourth World Conference on Women, the World Bank stands ready to assist client governments in response to the challenges ahead. The Bank believes that by advancing gender equality, governments can greatly enhance the future well-being and prosperity of their people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Armeane M. Choksi Vice President Human Capital Development and Operations Policy The World Bank</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Acknowledgments</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THIS REPORT was prepared by a team led by Kei Kawabata and comprising Alison Evans, Zafiris Tzannatos. Tara Vishwanath, and Rekha Menon. The work was carried out under the direction of Minh Chau Nguyen and the overall guidance of K. Y. Amoako. Valuable contributions were made by Joyce Cacho, Lionel Demery, Shahid Khandker, and Kalanidhi Subbarao.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Background papers for the report were prepared by team members and by Anjana Bhushan; Lynn Brown and Lawrence Haddad; Florencia Castro-Leal, with Ignacio Tavares and Ramon Lopez; Roberta Cohen; Monica Fong: Roger Key, with Beverly Mullings; Andrew Mason; and Veena Siddharth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">An external review group and a Bankwide advisory committee provided valuable guidance at all stages of the report's preparation. Kalpana Bardhan. Pranab Bardhan, Nancy Folbre. and T. Paul Schultz were the external reviewers. Harold Aldennan, Jean-Jacques Dethier, Louise Fox, Sunita Gandhi, Chris Grootaert, Jeffrey Hammer, Tariq Husahl, Elizabeth King, Augusta Molnar, Helena Ribe, and Paula Valad made up the advisory committee. The report was edited by Jo Bischoff, Richard M. Crum, and Fiona Mackintosh; Benjamin Crow provided word-processing and graphics support.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The report also reflects the contributions of the participants in consultations held with nongovenamental organizations on March 1S, 1995, in New York. Data supplied by the United Nations and its agencies. particularly the International Labour Organization, the United Nations Educational, Scientific, and Cultural Organization (UNESCO), the United Nations Statistical Office, and the World Health Organization, were invaluable for the preparation of the report.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The production of the report was made possible by the assistance of the Norwegian Ministry of Foreign Affairs, which has given unwavering support to the protnotion of gender equality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Definitions and Data Notes</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Definitions</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Expected number of years of formal schooling The total number of years of schooling that a child of a certain age can expect to receive if current enrollment patterns remain unchanged.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Literacy rate. The proportion of the adult population that can read or write. This indicator is not always accurate because it is self-reported and represents past investments in schooling. It is often defined only with respect to selected languages and may not take into account the progress being made in many countries through literacy campaigns.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Life expectancy AT BIRTH The number of years a newborn infant would live if prevailing patterns of mortality at the time of birth were to remain unchanged throughout the child's life.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Maternal mortality ratio. The number of women who die in pregnancy and childbirth per 100,000 live births: A measure of the risk that women face of dying from pregnancy-related causes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Data Notes</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unless otherwise specified, dollar amounts are current U.S. dollars. A billion is a thousand million.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The data used in this report cover a range of time periods and are from more than 100 countries (both developing and industrial).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unless otherwise specified, geographic regions are those used by the World Bank in its analytical and operational work and are defined as follows:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">sub-Saharan  Africa countries south of the Sahara except Africa.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">East Asia and the Pacific: low- and middle-income economies of East and Southeast Asia and the Pacific.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Europe and Central Asia. middle-income European countries and the countries that formed the former Soviet Union.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Latin America anti the Caribbean all American and Caribbean economies south of the United States.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Middle East and North Africa all the economies of North Africa and the Middle East.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">South Asia: Bangladesh, Bhutan, India. Myantnar, Nepal, Pakistan. and Sri Lanka.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Summary</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THREE messages echo throughout this document:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> The causes of gender inequality are complex, linked as they are to the intrahousehold decisionmaking process. However the decisions are made. the intrahousehold allocation of resources is influenced by market signals and institutional norms that do not capture the full benefits to society of investing in women. Low levels of education and training. poor health and nutritional status, and limited access to resources depress women's quality of life and hinder economic efficiency and growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> It is therefore essential that public policies work to compensate for market failures in the area of gender equality. These policies should equalize opportunities between women and men and redirect resources to those investments with the highest social returns. Of these investments. female education, particularly at the primary and lower-secondary level, is the most important, as it is the catalyst that increases the impact of other investments in health, nutrition, family planning, agriculture, industry, and infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Women themselves are agents for change because they play a key role in shaping the welfare of future generations. Public policies cannot be effective without the participation of the target group-in this case. women, who make up more than half the world's people. Their views need to be incorporated into policy formulation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Progress to Date</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past two decades considerable progress has been made in reducing the gender gap world wide.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> In 1960. for every 100 boys enrolled in primary school. there were 65 girls. In 1990 the ratio had risen to 85.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> In 1980 an average six-year-old girl in a developing country could expect to attend school for 7.3 years. By 1990 this figure had Increased to 8.4 years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Since the 1950s the female labor force has grown twice as last as the male labor force. Worldwide, more than 40 percent of women over 15 years of age are now in the labor force; in developing countries women account for 30 percent of the labor force (These figures. it should be noted, do not fully reflect women's participation in the informal sector as unpaid family members in agriculture.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Nevertheless. inequalities between men and women persist in many important areas.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Despite women s biological advantage, their mortality and morbidity rates frequently exceed those of men, particularly during childhood and the reproductive years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Traditionally women are employed in lower-pay jobs and in a narrower range of occupations than are men. Women's wages are typically only 60-70 percent of wages earned by men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Whether in private sector employment or public sector decisionmaking, women are less likely to be in positions of responsibility than are men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Why Do Gender Inequalities Persist?</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The causes of the persistent inequality between men and women are only partially understood. In recent years attention has focused on inequalities in the allocation of resources at the household level. as seen in the higher share of education, health. and food expenditures boys receive in comparison with girls. The decisionmaking process within households is complex and is influenced by social and cultural norms market opportunities, and institutional factors. There is considerable proof that the intrahousehold allocation of resources is a key factor in determining the levels of schooling. health. and nutrition accorded household members.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inequalities in the allocation of household resources matter because education, health. and nutrition are strongly [hiked to well-being, economic efficiency. and growth. Low levels of educational attainment and poor health and nutrition aggravate poor living conditions and reduce an individual's capacity to work productively. Such economic inefficiency represents a significant loss to society and hampers future economic growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social returns to investments in women's education and health  a? e significantly greater than for similar investment in men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The social and economic losses are greatest when women are denied access to basic education and health care. Data from around the world show that private returns to investments in education are the same for women as for men and may even be marginally higher (Psacharopoulos 1994). More importantly. social returns (that is, total benefits to society) to investment in women's education and health are significantly greater than for similar investments in men, largely because of the strong correlation between women's education, health, nutritional status. and fertility levels and the education. health, and productivity of future generations. These correlation are even stronger when women have control over the way resources are allocated within the household.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wage differentials between women and men in the market are closely linked to educational levels and work experience. since on average. women earn 30-40 percent less than teen' it is not surprising that fewer women than men participate in the labor force. This wage disparity, reinforced by discriminality institutional norms, in turn influences the intrahousehold division of resources. A vicious circle ensues as households invest less in daughters than in sons in the belief that investment in girls yields fewer benefits. As a result. many women are unable to work outside the household because they lack the education or experience that men have.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The decision not to participate in the labor force does not necessarily reflect a woman's own choice, no' does it always correspond to the optimum use of household resources. Furthermore. the market wage does not take into account the social benefits of educating and hiring women. Discrimination in households and in the market carries not only private costs for individuals and households but social costs for society as well.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Public policies for reducing gender inequalities are therefore essential for counteracting market failure and improving the well-being of all members of society. Investing in women's education and health expands their choices in labor markets and other income-generating activities and increases the rate of return on a household's most valuable asset-its labor.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The decision to allocate women's time to the type of non wage work women typically carry out within the household. such as child care. food preparation, and, in low-income countries especially, subsistence farming and the collection of fuel wood and water, has less to do with economics than with social conventions and norms. These nones can have a strong influence on the household division of labor, even in industrial economies, where women's levels of human capital are equal to-and some times higher than those of most men</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The economy pays to this inequality in reduced labour productivity today and diminished national output tomorrow</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Whether this division of labor is appropriate is, essentially, for society to decide. However. there is no doubt that women's entry into the labor market and other spheres of the economy is directly affected by the extensive amounts of time they traditionally devote to household maintenance and family care. Most men do not make similar allocations of time in the home. Such inequality constrains women's employment choices and can limit girls' enrollment in schools. The economy pays for this inequality in reduced labor productivity today and diminished national output tomorrow. Public policy can address inequalities in the household division of labor by supporting initiatives that reduce the amount of time women spend doing unpaid work. Examples of such interventions include improved water and sanitation services, rural electrification, and batter transport infrastructure.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Constraints on female employment opportunities arising from the household division of labor are compounded by institutional norms operating within the labor market. Although overt wage discrimination is illegal in many countries, employers frequently segregate jobs or offer less training to women workers. Employers often perceive the returns to investing in women workers as lower than those for men mainly because of women's primary role in childbearing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lack of access to financial services, to land, and to intonation and technology compounds the unequal treatment of women. Requirements for collateral, high transaction costs, and limited mobility and education contribute to women s inability to obtain credit. When women do have access to credit, the effect on household and individual well-being is striking. Bon-owing by women is linked to increased holdings of non-land assets, to improve in the health status of female children, and to an increased probability that girls will enroll in school. Independent access to land is associated with higher productivity and. in some cases, with greater investments by women in land conservation.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Strategies for the Future</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">If the benefits from investing in girls and women are so great and can be quantified. why do households and employers underinvest in women? The main reason is that. as discussed above. markets fail to capture the full benefit to society of' investing in women and girls. Where the market fails or is absent. government must take the lead Public policy can contribute directly and indirectly. to reducing gender inequalities by, for example:</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"> Modifying the legal and regulatory framework to ensure a opportunities </P>
+<P ALIGN="JUSTIFY"> Ensuring macroeconomic stability and improving, microeconomic incentives</P>
+<P ALIGN="JUSTIFY"> Redirecting public policies and public expenditures to those investments with the highest social returns</P>
+<P ALIGN="JUSTIFY"> Adopting targeted interventions that correct for gender inequalities at the micro-level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Modifying the law to eliminate gender discrimination and equalize opportunities for women and men is an important first step. However. legal reform by itself does not ensure equal treatment. Further public action is required to make sure that gender-neutral laws are enforced at the national and local levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sound economic policies and well-functioning markets are essential for growth, employment generation, and the creation of an environment in which the returns to divesting in women and owls can he fully realized. Economic instability and price distortions can hinder the process. Consequently. sound macroeconomic management is critical. In general. two sets of policies are necessary: one emphasizing macroeconomic stability and the elimination of price distortions. the other focusing on labor-demanding growth and a reorientation in public spending toward basic services with high social returns- such as education. health care and water supply.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gender inequalities in the distribution of the benefits of public spending frequently arise because of a bias within households that limits women's access to publicly provided services. In addition, the services provided by public spending often are of less benefit to women than to men. Public policy can help remedy this problem by rearranging expenditure priorities among sectors and within the social sectors. It can ensure support for those services and types of infrastructure that offer the highest social returns to public spending and that are most heavily used by women and children. such as water supply anti sanitation services and rural electrification.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally general policy interventions may not be enough. and programs that specifically target women and girls may be required. Targeting is justified. Governments can no longer afford not to invest in women gable on two grounds. First. because women are disproportionately represented among the poor. targeting women can be an effective strategy for reducing poverty (broadly defined to include limited access to services. re sources, and other capability-enhancing factors). Second. where gender differences are wide, targeting-for example. the provision of stipends so that girls can attend school-they be needed to capture social gains and increase  internal efficiency</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Conclusion</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments can no longer afford not to invest in women. The evidence on the high private and social returns to investments in women and girls cannot be ignored. By directing public resources toward policies and projects that reduce gender inequality. policymakers not only promote equality but also lay the groundwork for slower population growth, greater labor productivity, a higher rate of human capital formation, and stronger economic growth However, none of these developments can be sustained without the participial of women themselves. Governments and collaborating institutions must listen more carefully to the voices of individual women. including policymakers. and to women's groups. By working with others to identity and implement policies that promote gender equality, governments can make a real difference to the future well-being and prosperity of their people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Chapter one</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Gender Inequalities Persist</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ALTHOUGH the gap between opportunities for men and women is narrowing. inequalities persist, especially in certain regions. This report examines four major development indicators: educational attainment, maternal mortality. life expectancy. and economic participation outside the household. All four are closely related to each other and in turn are closely correlated with individual well-being. These indicators provide a broad picture of trends in gender inequality and their impact on the relative well-being of women and of men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Education</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite the progress in raising educational enrollment rates for both males and females across all regions in the past three decades, growth in educational opportunities at all levels for females lags behind that for males (figure 1.1). In 1990 an average six-year-old girl in a developing country could expect to attend school for 8.4 years. The figure had increased from 7.3 years in 1980-but an average boy of the same age in a developing country could expect to attend school for 9.7 years The gender gap in expected years of schooling is widest in some countries in South Asia, the Middle East, and Sub-Saharan Africa (see figure 1.2). Gender differences in access to education are usually worse in minority populations such as refugees and internally displaced persons. of which only a few children go to school.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p16.png"></center><br>
+ School enrollment ratios in developing countries </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The latest available figures show that 77 million girls of primary school age (6-11 years) are not in school, compared with 52 million boys (figure 1.3). Moreover, even these gross enrollment rates often mask high absenteeism and high dropout rates. Dropout rates are notably high in low-income countries but vary by gender worldwide and within regions. The rates for girls tend to be linked to age, peaking at about grade 5 and remaining high at the secondary level (Herz and others 1991) Cultural factors, early marriage, pregnancy, and household responsibilities affect the likelihood that girls will remain in school.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the gross enrollment rate is an acceptable indicator of progress in education, most studies use literacy rates as an indicator of well-being. Overall illiteracy rates have decreased among adults in low- and middle-income countries, but the percentage of illiterate women in the world is still higher than the percentage of illiterate men. Older women constitute the largest share of the illiterates in the world today, a consequence of past inequalities in access to education. In Sub-Saharan Africa, the Middle East, and South Asia more than 70 percent of women age 25 and older are illiterate (United Nations 1991).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At post-secondary levels. where the gap in enrollment between women and men is wider, there is implicit "gender streaming," or sex segregation, by field of study, even in areas with snore female than male enrollees. Gender streaming. which is widespread in both developing and industrial countries, prevents women from acquiring training in agriculture, forestry, fishing, "hard" sciences, and engineering (figure 1.4).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p17.png"></center><br>
+ Expected years of schooling </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Health</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past two decades life expectancy at birth has increased for both men and women in all regions of the world. In industrial countries women tend to outlive men by six to eight years on average: in low-income countries gender differences are much narrower (two to three years). Despite women's biological advantage, female mortality and morbidity rates frequently exceed those of men, particularly during early childhood and the reproductive years.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">During the reproductive period the most Important causes of morbidity and mortality among women are high fertility and abortion rates, vulnerability to sexually transmitted diseases (STDS), genital mutilation. and gender violence. Each year, about 500,000 women worldwide die from the complications of pregnancy and childbirth. Maternal mortality ratios for developing and industrial countries vary greatly: the rates in parts of South Asia are among the world's highest, in some cases exceeding 1,500 per 100.000 live births. In Sub-Saharan Africa where the ratio is 700 maternal deaths per 100.000 live births, a woman runs a 1 in 22 lifetime risk of dying from pregnancy-related causes, but in northern Europe the risk falls to 10 in 100,000 (United Nations 1993). In the transition economies of Eastern Europe and the former Soviet Union, the rates are around 40 to 50 per 100,000 live births</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p18.png"></center><br>
+ Figure 1.3 children not in school 1990 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A major cause of maternal deaths is complications from unsafe abortions. Abortion-related deaths are highest in South and Southeast Asia. followed by Sub-Saharan Africa and Latin America and the Caribbean. Lack of access to contraceptives can mean that abortion, is used as a form of birth control. For example, in parts of Eastern Europe and Central Asia abortions are more numerous than live births (World Bank 1994b), and abortion rates were as high as 1.76 per live birth in Russia prior to the transition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As increasing numbers of women become aware of and learn to use contraceptives, total fertility rates are falling worldwide. The exception is Sub-Saharan Africa where the total fertility rate averaged 6.4 between 1985 have been infected by HIV. The World Health organization (WHO 1994) estimates that more than 13 million women will have been infected by HIV by 2000 and that about 4 million of that number will have died (figure 1.5 In Atrica, where 10 million adults are infected with the virus, ode-half of all newly infected adults are women, and more than 5 million are women of childbearing age. In Asia almost half of all adults newly infected with the virus are women, compared with less than 25 percent just six years ago.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p19.png"></center><br>
+ Figure 1.4 fields of study</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p20.png"></center><br>
+  Figure 1.5 HIV infected women 1995 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The mortality risk for females is high during the reproductive years. but it is even higher during infancy and early childhood. Between 1962 and 1992 INFANT mortality in the developing world decreased by 50 percent (UNICEF 1993 However, in seventeen of the twenty-nine developing countries for which recent survey data are available, female children age 1-4 were found to have higher mortality rates than male children. despite girls? biological advantage (World Bank 1994b). In many of these countries the underlying cause of high mortality among girls is the parents' bias toward boys, who receive the best food and medical care.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Genital mutilation, prevalent in twenty-eight countries, is performed on 2 million young girls yearly. The practice leads to long-term morbidity, complications during childbirth, mental trauma, and even death. Table 1.1 summarizes the best available statistics on this practice for selected countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Employment Work</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The time women spend on paid and unpaid work is typically greater than the time men spend in the labor market (see table 1.2 for an example). Unpaid family work is rarely recorded in official statistics. It manifests itself only indirectly in the labor market in the form of gender differences in labor force participation rates. sector of employment, hours of work, and wage level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">On the whole. labor force participation rates for women are lower than those for men (figure 1.6). However. these differences are often exaggerated because the definition of the participation rate fails to capture many aspects of women's work, particularly time spent on childbearing, childbearing. and other household tasks. Men are usually in the labor force throughout the prime working years (age 20-60), and their participation rates are typically more than 90 percent in virtually every country. Female participation rates vary widely across countries. In 1990, for every ten men in the labor force there were two women in the Middle East and North Africa, three in South Asia. six in Sub-Saharan Africa, and seven in Southeast Asia (United Nations 1991). Worldwide, 41 percent of women age 15 years or over are in the labor force, but in developing countries the corresponding figure is 31 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">These numbers are deceptive, however, because they do not take into account the agricultural work for which women in developing countries are responsible within the family For example, the Dominican census of 1981 reported that only 21 percent of rural women participated in the labor force, but just three years later a special study suggested a figure of 81 percent. The census had omitted such activities as cultivating gardens and caring for domestic animals In India different definitions of what constitutes "work" have resulted in estimated participation rates as low as 13 percent and as high as 88 percent (Beneria 1992).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tens of Millions of Women Suffer Female Genital Mutilation.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 1.1 female genital mutilation</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=468>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Country</B></FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Estimated prevalence (percent)</B></FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Estimated number of women affected (millions)</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Djibouti</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">98</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0.2</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Egypt</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">50</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">13.5</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Eritrea</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">90</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1.5</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Ethiopia</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">90</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">22.5</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Kenya</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">50</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">6.3</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Nigeria</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">50</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">29.2</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Sierra Leone</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">90</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">2.0</FONT></TD>
+</TR>
+<TR><TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Sudan</FONT></TD>
+<TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">89</FONT></TD>
+<TD WIDTH="36%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">118</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Sri Lanka's Dry Zone, Women Work Longer Hours than Men.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 1.2 distribution of monthly work hours per month)</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=451>
+<TR><TD WIDTH="40%" VALIGN="TOP">&nbsp;</TD>
+<TD WIDTH="31%" VALIGN="TOP" COLSPAN=2>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Peal. Season</B></FONT></TD>
+<TD WIDTH="29%" VALIGN="TOP" COLSPAN=2>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Slack season</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Activity </B></FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Male</B></FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Female</B></FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Male</B></FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Female</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Agricultural production</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">298</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">299</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">245</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">235</FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Household tasks</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">90</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">199</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">220</FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Fetching water and firewood</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">30</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">50</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">:30</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60</FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Social and religious duties</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">8</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">12</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">15</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">15</FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Total work hours</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">426</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">560</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">350</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">530</FONT></TD>
+</TR>
+<TR><TD WIDTH="40%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Leisure and sleep</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">294</FONT></TD>
+<TD WIDTH="17%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">160</FONT></TD>
+<TD WIDTH="10%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">370</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">190</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women are usually employed in different sectors than men. Most of women's nonagricultural employment is in the service sector. but in developing countries female employment in manufacturing has been increasing and is catching up with female employment in services (ILO/ INSTRAW 1985). Women in manufacturing tend to be concentrated in only a few sub sectors: more than two-thirds of the global labor force in garment production is female. and this subsector absorbs almost one-fifth of the female labor force in manufacturing (UNIDO 1993). Men's employment is more evenly distributed across other sectors such as mining manufacturing, construction, utilities, and transport.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over their lifetime, women change their employment status more often than do men. They are also more likely to be self-employed or employed in occupations with flexible house such as subcontracted home work. Regardless of the sector in which they are employed, women tend to work in a narrow range of occupations. Only a few women are in high-paying jobs or in positions with significant responsibility. Nearly two-thirds of the women in manufacturing ate laborers, machine operators. and production workers; only 5 percent ate professional and technical workers and only 2 percent are administrators and managers (UNIDO 1993). However. there are regional differences: women occupy nearly 60 percent of clerical, sales. and service jobs in Latin America and the Caribbean but fewer than 20 percent of similar positions in South Asia North Africa. and the Middle East (figure 1.7).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p23.png"></center><br>
+ Figure 1.6 rates of participation in the labor force by gender</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Wages paid to women are typically about 60-70 percent of those paid to men. About one-quarter of the gender wage gap is explained by differences in educational levels, labor market experience, and other human capital'' characteristics (Psacharopoulos and Tzannatos 1992 Horton 1994). The gender wage gap can also be explained in part by women's lower participation in the labor market-a consequence of domestic and other demands on their time and, possibly, of discriminatory employment practices.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Significant changes in the global economy have affected patterns of employment and working conditions for men and women worldwide. "Globalization" is associated with the deregulation of product and labor markets, with regionalization. and with the liberalization of international trade. In turn. these processes at-e associated with increased female participation in the labor force and with the at-owing "casualization'' of employment, as seen in the growth of part-time work in industrial economies. However, the net effect of globalization on women workers is not yet clear. Growth in the international traded service sector (for example, banking and telecommunications) seems to have offered women in developing countries greater employment opportunities. In addition, the participation rate of women in manufacturing jobs has increased faster than that of men. Women's average participation in the manufacturing labor force is now around 30 percent for both developing and industrial countries.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p24.png"></center><br>
+ Figure 1.7 types of jobs held by women </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Worldwide, the number of women employed in export manufacturing has been increasing rapidly, even though this sector employs only a small fraction of all women workers. In Mexico, for example, the number of women employed in export manufacturing rose by nearly 15 percent a year in the 1980s (Jurisman and Moreno 1990). However, employment in this sector has been increasing more rapidly for men than for women, partly because of</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">technological upgrading over time and partly; because women are less educated and tend to remain in low-skill occupations (Baden 1992).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women now account for a growing share ret wage employment they tend to stay longer in the labor force than ever before</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite persistent gender inequalities in the labor market. some recent trends  are encouraging. Increasing educational opportunities and decreasing fertility  rates have fed to an increase in the number of women entering the labor market. since the 1950s the female labor force has expanded twice as fast as the male  labor force. Women now account for a growing share of wage employment. and they tend to stay longer in the labor force than ever before The narrowing of the gender gap in labor force participation is enabling women to accumulate the work experience necessary tot- improving their job opportunities and increasing their amines. In the formal sector more and more women are working in occupations and sectors once dominated by men. and in many countries women s wages relative to men s have increased over time</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The data in this chapter illustrate some aggregate trends but they cannot tell US anything about the processes behind the persistence of gender inequality. For a more detailed look at these processes. We turn in the next chapter to a growing body of empirical evidence generated at the household and enterprise level. These studies provide a telling insight into the way in which gender inequalities are being challenged particularly by women At the same time these inequalities are reinforced by economic, legal. and cultural incentive systems that discriminate against women Discrimination continues despite compelling evidence showing that less inequality especially within the household. is associated with heftier welfare outcomes for children and better economic outcomes for the household as a v hole.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Chapter two</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Gender Inequalities Hamper Growth</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inequality women and men limits productivity ultimately slows economic growth. early empirical studies (for example, Kuznets 1955) suggested that income inequality would increase with economic growth during the initial phases of development. This chapter, however. starts with the hypothesis that there is not necessarily a tradeoff between inequality and growth and. indeed that high inequality especially as it affects human capital. hampers growth (Fields 1992: Birdsall and Sabot 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Both theory and empirical evidence point to the importance of human capital in creating the necessary conditions for productivity growth and in reducing aggregate inequality in the future. In addition. women s human capital generates benefits for society in the form of lower child mortality.  higher educational attainment improved nutrition. and reduced population growth. Inequalities in the accumulation and use of human capital at-e related to lower economic and social well-being for all.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Household and Intrahousehold Resource Allocation</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In recent years, attempts to explain persistent gender inequalities in the accumulation and use of human capital have focused on the key role of household decisionmaking and tile process of resource allocation within household Households do not make decisions in isolation. however: their decision are linked to market prices and incentives and are influenced by cultural legal and state institutions. These institutions indirectly affect not only the returns on household investment but also access to productive resources and employment outside the house hold.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Household decisions about the allocation of resources have a profound effect on the schooling, health care, and nutrition children receive. The mechanisms used to make these decisions and the effect of the decisions on the well-being of individual household members are not fully understood. Two frameworks for thinking about household decisions are the unitary household model and the collective household model (see box 3.1)</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">BOX 2.1 </P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Two models of household members having their own prefer decisionmaking encase. Decisions on allocating resources reflect market rates of return. The unitary household model assumes but they also mirror the relative bar that household members pool regaining power of household members sources and allocate them according within the collective (Manser and to a common set of objectives and Brown 1980: McElroy and Homey goals. Households maximize the joint 1981). Bargaining power is a function welfare of their members by allocating of social and cultural norms. as well income and other resources to the in as of such external factors as opposed individuals and enterprises that promise "unities for paid work, laws governing the highest rate of return as reflected inheritance, and control over producing prices and wages. An increase initiative assets and property rights. These household income increases the well factors influence the terms governing being of all household members.</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Policy interventions based on the sources and decisions about how unitary household model aim to in those resources are used within the crease household welfare, but they household. Thus, an increase in do not necessarily affect all household income may benefit some hold members in the same way. Some household members but leave others household members may be worse unaffected or worse off. The outcome off, for example, if they lose control depends on a member's ability to exover certain resources; others may excise control over resources both in be better off. in which case house-side and outside the household, and it hold welfare is not maximized. cannot be assumed that individual well</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Under the collective household being increases as household income model. the welfare of individual house-rises. (Collective household models do hold members is not synonymous with not exclude the possibility that the universal household welfare. Resources unitary model may be the best approximate not necessarily pooled, and the motion of household decisionmaking household acts as a collective, with in some contexts.)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The collective household model helps explain why gender inequalities persist even though household becomes increase over time The next sections adopt a collective household framework to explain how these inequalities exact costs in forgone productivity, seduced welfare for individuals and households, encl. ultimately. slower economic growth.(fender Inequalities in Human Capital )</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are strong complementaires between education. health. and nutrition on the one hand, and increased well-being, labor productivity, and growth. On the other. Inequalities in resource allocation that limit household members' educational opportunities. access to health care, or nutrition are costly to individuals, households, and the economy as a whole.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Linkages between Education Health, and Nutritious</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the household level. gender differences in access to education are closely related to inequalities in the shares of household education expenditures allocated to boys and to girls This finding stands even though private returns to girls' schooling are similar to or marginally higher than. those to boys' schooling (figure 2.1; see also Schultz 1988: Mwabu 1994). In this case. parental choice reflects the relatively greater restrictions on educational opportunities and employment choices for girls. in comparison with boys. and cultural norms on the appropriate role for girls within the household.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p28.png"></center><br>
+ Figure 2.1 private returns to education</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p29a.png"></center><br>
+ Figure 2.2 education, fertility. and child mortality (a)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY"><center><img src="p29b.png"></center><br>
+ Figure 2.2 education, fertility. and child mortality (b)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">More importantly. the social externalities linked to female education are crucial. Evidence from a large number of countries shows that female education is linked with better health for women and their children and with lower levels (figure 2.2). This link stems from the direct effect of education on the value of a woman's time and consequently. on private returns to her labor. It also stems from the indirect effect of education on the average age at which women marry on their knowledge of basic health care and nutrition, and on reproductive choices (Rosenzweig and Schultz 1982, 1987).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Educating girls and women reduces maternal mortality and fertility rates and increases the demand for health services. A simulation study of seventy two developing countries shows that, with all other factors held constant, a doubling of female secondary school enrollments in 1975 would have reduced tile average fertility rate in 1985 from 5.3 to 3.9 children per household and would have lowered the number of births by 29 percent (Subbarao and Raney 1992. Studies for individual countries have found that one additional year of female schooling can reduce the fertility rate. on average, between 5 and 1 (i) percent (Summers 1994)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women are more vulnerable than men to micronutrient deficiencies that aggravate poor health (World Batik 1994b). Poor health and nutrition reduce productivity and the chances of reaping gains from investment in education. Intrahousehold inequalities in consumption and nutritional allocations can therefore be a signal of inefficiency Recent estimates suggest that the com effects on morbidity and mortality of just three types of deficiency-in vitamin A, iodine. and iron-could waste as much as 5 percent of gross domestic product (GDP), yet correcting these deficiencies would cost less than 0.3 percent of low-income countries' GDP (World Bank 1994c, pp. 50-51). Studies of women tea producers in Sri Lanka and of women workers in Chinese cotton mills document the reduction in productivity associated with iron deficiencies and the positive effects of in-on supplementation on work and output (Edgerton and others 1979). A study of six villages in Andhra Pradesh, India, found that disabling conditions caused by malnutrition and the prevalence of diseases reduced female labor force participation by 22 percent (Chatterjee 1991).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Physical anti mental abuse can also have deleterious effects on the well-being and productivity of women (table 2.1). Violence against women is widespread in all cultures and cuts across all age and income groups Its consequences. include unwanted pregnancy. infection with STDs, miscarriage partial or permanent disability. and psychological problems such as depression anti low self-esteem. Recent World Bank estimates indicate that in both industrial and developing countries domestic violence and rape cause women of reproductive age to lose a significant percentage of really days. Domestic violence appears to be an example of how the relatively weaker bargaining power of women and the paucity of options for them outside the home can affect the intrahousehold distribution of welfare.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Violence against Women Starts in the Womb and Continues  trough Life</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2.1 Violence against women through the life cycle</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=590>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Phase</B></FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Type of violence</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Pre birth</FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Battering during pregnancy (emotional and physical effects on the ottoman) effects on birth outcome</FONT></TD>
+</TR>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Infancy</FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Female infanticide: emotional and physical abuse</FONT></TD>
+</TR>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Girl hood</FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Sexual abuse by family members and strangers: forced child prostitution</FONT></TD>
+</TR>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Adolescence</FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Dating and courtship violence: economically coerced sex: sexual abuse in the workplace: rape: farce prostitution and trafficking in women</FONT></TD>
+</TR>
+<TR><TD WIDTH="22%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Reproductive</FONT></TD>
+<TD WIDTH="78%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Coerced pregnancy: rape: abuse of women by male partners: down abuse and murder partner homicide psychological abuse sexual abuse of unmarried and childless women: abuse of women with disabilities</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY">Source: Heise 1993 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Prospects for gainful employment. as well as the availability of basic social services such as water supply and sanitation. also influence women's well-being. The survival chances of female children in India appear to increase as the employment rate for women rises and the earnings differential between men and women decreases Battilan 1988 Dowry and marriage practices. along with household ownership of land are closely linked to women's chances of survival The effect of such practices cannot be over late. Sen's (1990) comparison of female-male mortality rates in China. India. and Sub-Saharan Africa suggest that more than 100 million women are "missing"</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Public spending on social services affects the ability of individuals and households to benefit from their own private spending on human capital. In most industrial countries mortality rates decreased even before modern medical care became widely available, mainly because of improved water supplies and sanitation. The same is likely to hold for the developing world. Public interventions that address market under provision of water and sanitation facilities and shortages of health set-vices such as immunization and family planning-have a significant effect. and one that is probably greater for women than for men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lack of data makes it difficult to evaluate the effects of public spending on the educational attainment and health of women and men Very little empirical evidence in this area exists, but there is some indication that the proportion of public subsidies for education that benefits females is lower than the proportion that benefits males. In Kenya in 1992-93. for example. public spending on education amounted to the equivalent of an annual subsidy of 605 Kenyan shillings per capita: males received. on average. 670 shillings and females only 543 shillings. In Mexico the gender difference in public education subsidies was somewhat less: in Pakistan males received almost twice the female subsidy. Gender inequalities in the distribution of subsidies are greater at high than at primary levels. In Pakistan girls receive, on average. only 96 rupees a year for secondary school bag. compared with 58 rupees for boys. Box 2.2 explains how these figures are calculated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Supply-side differences are partly a function of poorly targeted resources (as. for example, when more is spent on tertiary than on primary schooling). More importantly. they reflect differences in household demand for education for girls and boys. If more girls attended anti stayed in school. the proportion of public subsidy going to girls would he greater.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In health care assessing the incidence of public spending by gender is particularly difficult because of the marked differences in the health needs of women and men. These differences are related to different biological re</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7>
+<TR><TD></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY">The main advantage of this type of analysis is that it measures how well public  services are targeted to certain groups in the population, including women, the  poor, and residents of regions of interest.  Requirements anti to women's reproductive and childbearing roles. Some evidence suggests that because of these differences. per capita health cat-e subsidies to women are the same as and sometimes larger than those to men What is clearer is that women are less likely than men to seek health care. including in many countries. hospital care when it is netted and ate mote likely to consult a non medical health cat-e worker (lather than a qualified medical practitioner). Education tends to increase the likelihood that women will seek health care. whether public or  ace the likelihood that women will seek health care. whether public or private (World Bank 1994b). </P>
+<P ALIGN="JUSTIFY">The importance of private and public investments in education and health services that will improve women's well-being is cleat. These services at-e also important for another season: these is important evidence that increases in women's well-being yield important intergenerational benefits and productivity gains in the future World Bank Living Standards Measure Study (LSMS) surveys car-tried out in Nicaragua (1993 Viet Nam 1993) Pakistan (1991), and Cote (1988) suggest that the probability of children being enrolled in school increases with their mother's educational level and that (controlling, for income and household size) girls. particularly those in non poor households. are mote likely to attend school if their mothers attended school. Other studies show that households with educated mothers lend to provide children with greater quantities of mote nutritious food often at a lower cost. than households with poorly educated mothers (Thomas 1990b)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Data from Brazil show that giving women more control over nonlabor income has a larger impact on child measures, nutritional intakes, and the proportion of the household budget devoted to human capital inputs than if men had control of this income (Thomas 1993) Other studies indicate that women spend proportionately mote of the income they control on health care for children than do men. Women also spend more on food products (as opposed to such goods as alcohol and tobacco) than men do (Duraiswamy 1992: Hoddinot and Haddad 1992) But fathers education is also important especially in interaction with mothers' education (Thomas 1990a) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other studies have shown that children's educational attainment is lowest in households whet-e the male head has no schooling In Ghana the impact of a mother's education on her children's schooling is reduced when  their father has no schooling. even after controlling for income and household size (Lavy 1992).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Material health (which is linked to education) also has important intergenerational effects. Children of mothers who are malnourished or sickly or receive inadequate prenatal and delivery cat-e face a greater risk of disease and premature death. Iodine-deficient mothers run a greater risk of giving birth to infants with severe mental retardation and other congenital abnormalities than do healthy mothers. Reduced fertility and improved health for women can increase individual productivity and improve family well-being. When good health is combined with education and access to jobs. the result is higher rates of economic growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Household and Labor Market Linkages</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The link between the household and the labor market is particularly important. Specialization of labor within the household-whether individually chosen. socially determined. or legally induced-can accentuate gender inequalities in the formal and informal labor markets by leaving most of the unpaid work to women. This situation arises from convention rather than  from comparative advantage Inadequate public and community services.  transport. and housing also often have an uneven effect on the way men and women spend their time and can increase the demand for goods produced at home using unpaid labor (Moser 1994) Thus women may spend its much (or more time on unpaid work as on market work. In some countries this unpaid work contributes as much as one-third to the economy recorded GDP-and even mote to the welfare of poor families.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The amount of time women contribute to household production and maintenance, direct income generation. and family care combined is widely held to exceed that of men Analysis of data from Bangladesh. Botswana. Ghana. Kenya. Pakistan. the Philippines. and Zambia on how rural women spend their time confirms that, although use of time by women, and by different generations of women varies according to location. available technology. household characteristics. and cultural norms. gender bias in time use is widespread.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women are generally responsible for collecting fuelwood and carrying water. Girls and alder women often do most of this work, although cultural norms in some countries affect women s mobility. The amount of time allocated to these activities is influenced by seasonal patterns of agricultural activity. the availability of substitute goods and services. and environmental changes. A study in Nepal, for instance, found that deforestation associated with a 75 percent rise in the time per trip would increase the time spent gathering fuelwood by 45 percent for all adults and by 50-60 percent for women.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In addition to fuel and water collection, child care is another activity that dominates women s time-although. considering the importance of children to future household welfare, the amount of direct time spent with children is limited. The seven-country study suggests that more time is spent on child cat-e in female-headed households. Female-headed households tend to have high dependency ratios and relatively large numbers of children, Implying more child-care time overall, but not necessarily on a per child basis. (Kumar and Hotchkiss 1988).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">When a large proportion of women's use of time goes unrecorded the design of projects and policies can yield false evaluations of costs and benefits. For example, women's unpaid work may be assumed to have zero value. As a result, women's response to changing incentives may be predicted as being higher than their time constraints actually allow. Project benefits-such as the time saved by locating piped water close to homes or by expanding rural electrification-may also be undervalued. Conversely, the benefits of treeing up time may be far more significant than might have been thought. A study in Tanzania, for example. shows that relieving certain time constraints in a community of smallholder coffee and banana growers increases household cash incomes by 10 percent, labor productivity by 15 percent, and capital productivity by 44 percent (Tibaijuka 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Formal Sector Employment</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Unpaid work and family responsibilities. as well as lack of investment in women's education. are strongly associated with women's relatively low rates of participation and their limited earnings in formal sector labor. Women's participation rates usually dip in the childbearing years, and earnings tend to decline following an interruption in employment. Younger on average, work more hours than older women, and married women with young children tend to work less than childless women and mothers of grown children. The correlation of marriage and childbearing with labor market outcomes can be seen even in industrial countries, where wage differences between married women and men are larger than those between single women and men Similarly, in some developing countries relative earnings decline with age (table 2.2) Children are not the only treason for interruptions in women's labor force participation; caring for ill or aged family members is often a womans responsibility. A study from Hungary estimates that half of all absenteeism by women workers is the direct result of the need to care for sick relatives (Einhorn 1993).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Countries, Single Women Earn More Than Married Women and Younger Women More Than Older Women.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2.2 female-male earnings (adjusted for hours worked) by marital status and age (percent)</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=345>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Country</B></FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Female-male</B></FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Earnings ratio</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">By marital status</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Married </FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Single</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Australia</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">69</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">91</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Austria</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">66</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">97</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Germany</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">57</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">103</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Norway</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">72</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">92</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Sweden</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">72</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">94</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Switzerland</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">58</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">94</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">United Kingdom</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">95</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">United States</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">59</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">96</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Age</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">A 25 </FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">B 45</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Brazil</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">75</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">63</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Colombia</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">94</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">70</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Indonesia</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">81</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Malaysia</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">82</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">61</FONT></TD>
+</TR>
+<TR><TD WIDTH="38%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Venezuela</FONT></TD>
+<TD WIDTH="27%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">92</FONT></TD>
+<TD WIDTH="35%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">70</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY">Sources: Blau and Kahn 1992 Sedlacek Gutierrez. and Mohindra 1993 </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thus. women s labor market outcomes can be substantially poorer than those of men because women's employment opportunities are constrained by social arrangements at the family or household level. These social demands are reinforced by legal conventions. Within the labor market itself, social or employer discrimination can affect women and men differently. and these differences are reflected in the resource allocation decisions taken within the household. Although wage discrimination is illegal in many countries, employers may respond to an increase in the supply of workers by segregating jobs by gender or offering less training to women who they perceive as being temporarily attached to the labor force (even if in fact most women never drop out). For example, women in the former Soviet Union are fairly well educated and have high labor force participation. but they are concentrated in occupations requiring fewer skills and less vocational training than men, and, on average. they earn less than men (Fong 1993).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Female Wages Are Lower than Male Wages, but This Is Changing.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2.3 female-male earnings ratio over time Female-male earning 1 ratio (percent) </P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=2 CELLPADDING=7 WIDTH=496>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Country</B></FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP" COLSPAN=2>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">First observation</B></FONT></TD>
+<TD WIDTH="25%" VALIGN="TOP" COLSPAN=2>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Second observation</B></FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">A v Average annual percentage change</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Brazil</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">50.2</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1981) </FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">51.6</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1990)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0.7</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Colombia</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">67.2</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1984)</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">70 2</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1990)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0.7</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">C&ocirc;te d'Ivoire</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">75.7</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1985)</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">81.4</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1988)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">2.4</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Indonesia</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">55.6</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1986)</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60.0</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1997)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1.3</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Philippines</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">70.9</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1978)</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">80.0</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1988)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1.2</FONT></TD>
+</TR>
+<TR><TD WIDTH="21%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Thailand</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">73.5</FONT></TD>
+<TD WIDTH="15%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1980)</FONT></TD>
+<TD WIDTH="11%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">79.8</FONT></TD>
+<TD WIDTH="13%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">(1990)</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0.8</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY">Note: Monthly earnings for Indonesia and Thailand rural and urban: for all others urban only</P>
+<P ALIGN="JUSTIFY">Source: Tzanntors 1995</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women's earnings relative to men's tend to increase over time. A study of six developing countries shows that female earnings relative to male earnings increased by 1 percent a year in the 1980s (table 2.3). There were two reasons for this increase: over the years women entered higher-paying sectors. and within sectors, their pay increased in relation to that of men. This gain would have been even greater had it not been for the effect on wages of increased female participation in the labor force. However, the most visible dimension of gender inequality in the formal labor sector remains the wage difference between men and women. Women's wages are. on average lower those of men by about 30 to 40 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social or employer discrimination can affect women and men difference and these difference are reflected i/? the resource allocation decisions taken within the household</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A recent study of the gender wage gap in Russia shows that after controlling for education differences, the ratio of women's to men's average hourly earnings stands at just over 71 percent: it has remained at that level since the 1960s. Part of the reason for women s lower hourly earnings in Russia and many other countries lies in patterns of occupational segmentation by ,gender. Some analysts argue that women-who do most of the household work in Russian households and also have high participation in the formal labor market cope with the burdens imposed on them by taking less demanding work and devoting less time to advancing their careers (Newell and Reilly 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Informal Sector</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One difficulty analysts face in interpreting trends in women's labor force participation and employment in developing economies is the large number of women engaged in informal sector activities, many of which overlap with subsistence - orientated household or community-based activities. Informal sector employment in most developing countries. whether in microentreprises or in casual work, is an important source of livelihood for women and their households.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The L competitiveness of women's informal sector activities is  constrained by women's limited mobility and lack of access to financial and public sectors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A recent study in Mexico estimates that 41 percent of the work force in Mexico's major-cities is employed in the informal sector (World Bank 1995c). Data from a 1989 survey show that 60 percent of men working in the sector are salaried workers' compared with only 18 percent of women. By contrast. 80 percent of women working in the sector are unpaid family members, as against 27 percent of men. By far the most common activity in the informal sector is commerce (fixed-location or itinerant), followed by repair works food preparation. and sales, and small-scale manufacturing. The sectoral distribution of informal employment reflects the hey role informal workers play in supplying goods and services to low-income consumers. Women tend to be concentrated in commerce and men in services and manufacturing, although the percentage differences are relatively small. Two generalizations can be made on the basis of this study: informal sector workers earn less than workers in large firms and women earn less than men.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another recent study of tour communities in Lusaka. Guayaquil (Ecuador), Metro Manila, and Budapest shows that informal sector activities ate especially important for during periods of economic reform Although the numbers both of men and of women in the labor force tend to increase during these times women rely more on the informal sector than men clot The competitiveness of womens informal sector activities is informal by women's limited mobility and lack of access to financial and public services. Women also tend to specialize in non traded goods and services that show relatively low average returns to labor. Across the tour cities in the study, women earn between 46 and 68 percent of men's wages (Moser 1994)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ability of informal sector workers to increase their returns depends on access to physical and human capital and their relationship to the institutional and regulatory environment. Contrary to the common belief, many microenterprises face considerable costs associated with the regulatory environment, including registration and licensing fees, as well as outlays for contracts with public authorities concerning zoning regulations and use of public utilities. In Argentina regulatory costs are estimated to absorb as much as 21 percent of the average microfirm's operational expenses. In some sectors, such as manufacturing and construction, the costs of regulation are about 44 percent (World Bank 1994d). In Mexico real regulatory costs. including the costs of compliance and evasion, are about 20 percent of total costs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Regulatory costs also inhibit Job creation in the informal sector. In Argentina across-the-board deregulation could generate as many as 170,000 jobs in small-scale manufacturing alone. Furthermore. poor workers in family-based firms or micro enterprises and particularly women entrepreneurs-often lack access to such basics as water and power. Targeting infrastructure investments to the poor, which takes account of the needs of women entrepreneurs s. can significantly enhance their productivity and earnings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In rural area where formal markets often are not well developed. informal employment activities play a vital role. In Asia the proportion of female rural wage laborers increased sharply in the 1960s and 1970s. In India women make up a larger proportion of rural wage laborers than of the entire labor force, probably because of growing landlines and poverty among rural households. Rural household labor accounts for a disproportionately large share of employment among the poor and an even larger share among women. Furthermore, a larger proportion of female than male laborers are hired on a casual basis, largely because family arrangements, especially lack of control over property, limit women's ability to work (Hart 1986: Bardhan 1993). Low status in the labor market is also linked to low female indicators in education, health, and nutrition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Providing credit directly to women has a positive effect on  household and individual welfare and improved gender equality.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Social norms affecting decisions within the family about occupational choices or migration can also lead to differential patterns of male and female earnings in informal markets (Bhiswanger and Rosenzweig 1984). Family responsibilities hinder women's geographic mobility, constraining their ability to command high wages and limiting them to certain areas or industries. The concentration of women in certain sectors, especially nontraded goods and set-vices. intensifies competition between women entrepreneurs and wage workers and lowers the returns to female labor. These effects are compounded by women's lack of access to credit. training, and technology.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">(fender Inequality in Access to Assets and Services )</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Access to Financial Markets</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The availability of financial services and access to them are considered important for several reasons. First. savings provide a kind of self-insurance. Second, credit helps households maintain a certain level of consumption at those times when their income fluctuates temporarily. Third, credit can be used to fund investments in capital or other inputs that will yield relatively high returns to production. if households cannot finance such investments from their own savings. A fourth and no less important reason is the role of savings and credit in increasing household members' options outside the home.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Inequalities between women and men in access to financial services- particularly credit--are widely documented. Collateral requirements, high transaction costs. limited mobility and education, and other social and cultural barriers contribute to women's inability to obtain credit (Holt and Ribe 1991). The implications tot household efficiency and individual well-being differ, however, depending on whether the household pools its financial resources. If, as the unitary household model assumes. a household pools its resources the characteristics of individual borrowers are less important than if there is little or no pooling. In the first case. credit resources will be used to meet household needs that have been jointly determined, regardless of who the borrower is. In the second case, the use credit is put to and the needs it then satisfies depend on which household member is borrowing.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A recent study of credit programs in Bangladesh sponsored by the World Bank shows that providing credit directly to women has a positive effect on variables typically associated with household and individual welfare and improved gender equality (Pitt and Khandker 1995). The study looks at three programs in Bangladesh: the Grameen Bank. the Bangladesh Rural Advancement Committee (BRAC), and the Bangladesh Rural Development Board (BRDB). in 1992, women accounted for 94 percent of Grameen Bank members. 82 percent of BRAC members. and 68 percent of BRDB members (Khandker and Khalily 1995; Khandker, Lavy, and Filmer 1994). Only the results for the Grameen Bank are presented here.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Table 2.4 presents the impact of credit obtained by women and men on a variety of social and economic indicators. The results show a clear and positive impact of both male and female borrowing on all indicators of Toward gender equality family welfare especially through an increase in per capita expenditures increases in both boys' and girls schooling, anti a reduction in fertility. Females borrowing has a greater effect on girls' schooling anti per capita expenditure than does male loot-rowing: male borrowing has a greater effect on boys' schooling and fertility than does female borrowing. Interestingly. female borrowing also results in mote female ownership of nonoland assets and an increased supply of female labor to cash - income -earning activities (Pitt and Khandker 1995).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Loans to Women and Men Have Important Welfare Implications.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2 4 welfare effects of Grameen Bank loans (percentage increase)</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=545>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Welfare e change</B></FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Effect of male borrowing</B></FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Effect female borrowing</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Increase in boys' schooling</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">7.2</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">6.1</FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Increase in girls schooling</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">3.0</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">4.7</FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Increase in per capital expenditure</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1.8</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">4.3</FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Reduction in recent fertility</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">7.4</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">3.5</FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Increase in women's labor supply to cash-income earning activities</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">10.4</FONT></TD>
+</TR>
+<TR><TD WIDTH="47%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Increase in women nonland assents</FONT></TD>
+<TD WIDTH="28%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">0</FONT></TD>
+<TD WIDTH="26%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">19.9 </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The introduction of programs such as the Grameen Bank in a village has a positive effect on agricultural and nonagricultural production (Khatidketati Chowdhuty 1994: Rahman and Khandke 1994 The probability that women will be self-employed rather than work for wages increases by 52 percent. The latter finding is important because much of the wage employment open to women in rural areas is very poorly remunerated and can be quite exploitative. Self employment can bring the opportunity of higher returns for women, plus the freedom to integrate their earning activities into other work as they see fit.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Access to financial services alone cannot reduce gender inequalities in the allocation of household resources. A qualitative study reviewing several targeted credit programs in Bangladesh cautions against overgeneralizing about the benefits of giving women access to credit. The study finds that it is difficult to infer that increased borrowing alone improves women's bargaining power because in many rural Bangladesh households the question of who controls the resources is quite complex (Goetz and Sen Gupta 1994). Nevertheless. the possibility of receiving credit (or similarly of working for wages) may give women greater bargaining power within the household. This bargaining power can be used to improve child health and nutrition and may increase the likelihood that children will attend school.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Access to Lund and Property</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The ownership of land and the distributions of land rights influence the productivity of labor and capital resources and the incentive to invest in resource management Private property rights. in particular. are associated with increased access to product and factor markets. especially credit markets. and to public services such as public utilities and agricultural extension. However. relatively little direct evidence exists to link independent owner of land by women with increased access and productivity. One obstacle to empirical work is that women s access to land and property is often mediated trough marriage (A married woman land rights are frequently limited to use rather than ownership.) Future more. complex systems of land tenure make it difficult to generalize about the effects of owner ship on productivity. None some evidence suggests that independent land rights for women could enhance both the efficiency with which resources are used and the well-being of women and their households: (Agarwal 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The possibility of receiving credit may give e women   greater bargaining power within the  household which  can be used to improve child health and nutrition.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">While independent land rights may increase efficiency and household welfare, lack of secure land  appears to be associated with low investments by women in land conservation. In Zimbabwe's communal areas, land that a women acquires is often allocated to her only temporarily: for example, the location of land allotment received from husbands or borrowed from neighbors is usually subject to periodic change (Jackson 1993). The same is true in parts of West Africa (David 1992 Jackson 1994). Uncertainly about the permanence of their control over the land means that women may be reluctant to invest in improvements that will benefit the landowner rather than the user.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A significant trend in recent decades in developing countries has been the move toward private ownership In some countries this trend has been encoulagecl by reforms dealing with land redistribution tenancy or land titling Such reforms are considered important for promoting long-term investments and the adoption of the latest technology They also provide the collateral people need to gain access to credit and other factor markets Ironically, evidence also suggests that perform inequalities in male and female land rights are reinforced by land reform programs For example, in Latin America most reforms are based on the premise that the man of the household its the household head. This presumption means that women (except for widows  and ownership. Even where women and men benefit equally from land reform differences exist between nominal and real land rights (see box 2.3).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the central part of European Russia and in Moldova the lands and assets of state and collective farms are being parceled out in allotments as part of wider economic reforms. Every person who lived and worked on a collective farm receives a share of the land Data show that although on average, women have received a slightly higher proportion of land shares than men, the nonland capital assets of the old farms ale being distributed as property shares on the basis of a formula heavily weighted toward an individual's wage rate and years of employment. Such criteria favor men over women and give men more valuable property chares. Dividends paid on these property shares also tend to be higher than those paid 011 land shares Holt 1995).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Land reform programs that fail to account for gender differences in rights</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 2.3 who gets access to land? Honduras and Cameroon</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Honduras' Agrarian Modernization Law of 1974 includes a provision giving men age 16 or older the right to access to land, independent of any other qualification. For women. however, this right is restricted to unmarried mothers or widows with dependent children. Furthermore. if a male beneficiary dies or becomes incapacitated. the law gives preference in inheritance rights to a male child over the child's legally married mother. Some 30 percent of rural Honduran households are headed by women at least part time because of the seasonal migration of men to look for work (Saito and Spurling 1992). </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the northwest and southwest provinces of Cameroon. an estimated 50 percent or more of those who claimed land within the first ten years of land registration (1974-85) were classified as public servants. Over 32 percent of all the remaining land titles went to businesses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women make up more than 51 percent of Cameroon s population and do more than 75 percent of the agricultural work. but they are virtually absent from land registers. Only 3.2 percent of all land titles issued in the Northwest Province were given to women; in the Southwest Province the figure was 7.2 percent. For the country as a whole. it is estimated that women obtained under 10 percent of all land certificates (World Bank 1995a).  to own. use, and transfer land may actually exacerbate the insecurity of women's land claims and. as a result, harm household welfare. For example, there is evidence that land titling focused on male household heads has adversely affected women's ability to farm independently. Moreover. intrahousehold inequalities in income and decisionmaking have increased (FAO 1993) In Africa some titling programs have allowed men to take advantage of their control over land to redesignate land formerly cultivated by women as household land. This switch provided the opportunity for men to increase the amount of work they expect from women on household plots. In other cases women have received smaller and less fertile plots than they had before for their personal crops (FAO 1993).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Recognizing women's independent claims to land is therefore an important issue in property reform. In poor households. having rights to land could alleviate both women's own poverty and the household's risk of remaining poor. The season is mainly that women s access to economic resources has a positive effect on household welfare (Agarwal 1994). From the point of view of efficiency, secret land tenure increases the incentive to manage resources efficiently and expands access to formal credit markets. Because secure land tenure can mean greater productivity, it may also increase the household's incentives to invest in women's human capital.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Access to Extension Services</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agricultural extension services provide information training and technology to agricultural producers. Extension services have always been regarded as necessary for agricultural modernization. Given the importance of women's labor to agriculture in most regions, providing women with access to agricultural extension services is essential for current and future productivity. Types of agricultural extension services vary, hut in most countries publicly provided services dominate. Evidence suggests that women have not benefited as much as men have from publicly provided extension services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Given the importance of women's labor to agriculture it is in most regions providing women with access to agricultural extension services is essential for current  and future of productivity.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A review of five African countries shows that extension agents are most likely to visit male farmers than female farmers (table 2.5) The impact of this inequity on female productivity depends in part on whether women and men within households pool information. There is, however. little evidence to suggest that this happens (see box 2.4). It is important to ensure that extension services reach omen directly, not only to redress gender inequalities but also to maximize productive efficiency. omen play a critical role in production of food and cash crops for the household. in postharvest activities. and in livestock care Men and omen perform different tasks they can substitute for one another only to a limited extent. and this imitation creates different demands for extension information Also, as men leave farms in search of paid employment ill urban areas. women are increasingly managing and operating farms on a regular and full-time basis. Hence. omen are becoming a constituency for extension and research services in their own right (World Bank 1994e)</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2.5 visits by agricultural extension agents (percentage of households visited)</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=439>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Country and year</B></FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Households with female head</B></FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Households with male head</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<FONT SIZE=2><P ALIGN="JUSTIFY">Kenya. 1989</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">112</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">9</FONT></TD>
+</TR>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<FONT SIZE=2><P ALIGN="JUSTIFY">Malawi, 1989</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">70</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">58</FONT></TD>
+</TR>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<FONT SIZE=2><P ALIGN="JUSTIFY">Nigeria 1989</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">37</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">22</FONT></TD>
+</TR>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<FONT SIZE=2><P ALIGN="JUSTIFY">Tanzania, 1984</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">40</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">20</FONT></TD>
+</TR>
+<TR><TD WIDTH="37%" VALIGN="TOP" COLSPAN=2>
+<FONT SIZE=2><P ALIGN="JUSTIFY">Zambia</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">&nbsp;</TD>
+<TD WIDTH="32%" VALIGN="TOP">&nbsp;</TD>
+</TR>
+<TR><TD WIDTH="4%" VALIGN="TOP">&nbsp;</TD>
+<TD WIDTH="33%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1982</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">57</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">29</FONT></TD>
+</TR>
+<TR><TD WIDTH="4%" VALIGN="TOP">&nbsp;</TD>
+<TD WIDTH="33%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1986</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">60</FONT></TD>
+<TD WIDTH="32%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">19</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 2.4 do women farmers learn from their husbands?</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A survey of women farmers in Burkina Faso found that 40 percent had some knowledge of modern crop and livestock production technologies. For most of these women, relatives and friends were the source of information; nearly one-third had acquired their knowledge from the extension service, and only 1 percent had heard of the technologies from their husbands.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Men are less likely to pass information on to their wives when crops and tasks are gender specific. In Malawi women claimed that their husbands rarely passed on advice to them: if their husbands did tell them something. the women did not find it relevant to their needs. In India women learned from friends, relatives. neighbors. and sometimes from their husbands. but this second-hand information seldom changed their production patterns (Saito and Spurling 1992). </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The expansion of agricultural services beyond the public sector is a growing phenomenon in developing economies. The inadequacies of public funding plus the need to provide snore client-oriented services, suggest that the private sector has an important role to play However, women's limited access to land and credit put the many potential benefits offered by extension services out of reach. For example in Kenya's Meru and Maranga areas more than half the women surveyed cited a shortage of cash as their reason for not adopting, technologies that would maximize their output and increase their efficiency. The amount of education omen receive and the efficiency with which they run their farms are also closely linked This tie is particularly significant in light of the fact that one purpose of extension services is to advise farmers on use of modern technology.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Three studies of Kenya found that the gender of the farm manager was, by itself. an insignification factor in output per hectare but that the manager's educational level had a significant effect on farm productivity (Moock 1976: Saito and Spurling 1992: Bindlish and Evenson 1993). Simulations based on these studies suggest that significant gains could accrue to increased investment in women's physical and human capital. As the data in table 2.6 show, if women and men shared the same educational characteristics and input levels. farm-specific yields would increase between 7 and 22 percent. Giving women primary schooling, by itself. would increase yields by 24 percent. Thus under investment in women's education limits growth of agricultural productivity. Well-targeted extension services can help to narrow the differences in productivity that arise from educational inequalities (Schultz 1988)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Increasing Human Capital and Input Levels Would Increase tile Yield for Women Farmers.</P>
+<P ALIGN="JUSTIFY"></P>
+<B><P ALIGN="JUSTIFY">Table 2.6 effects of increasing women farmers' human capital and input levels Increase  yields</P>
+</B><P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Policy experiment </B></FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">(percent)</B></FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Maize farmers Kenya, 1976</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">&nbsp;</TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of giving female farmers sample mean characteristics and input levels</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">7</FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of giving female farmer s men's education and input levels</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">9</FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of giving women primary schooling</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">24</FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Food maize (maize beans and cow pears) farmers</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">&nbsp;</TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of giving female farmer men's education and input levels</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">2.0</FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of increasing land area to male farmers' levels</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">10.5</FONT></TD>
+</TR>
+<TR><TD WIDTH="82%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">Effects of increasing fertilizer to male farmers' levels</FONT></TD>
+<TD WIDTH="18%" VALIGN="TOP">
+<FONT SIZE=2><P ALIGN="JUSTIFY">1.6</FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Conclusion</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Analysts must look beyond market outcomes to identity the sources of persistent inequality between women and men. The search must focus on the household and its role in the formation of present and future human capital and on institutions beyond the household that reinforce and perpetuate gender inequalities. Gender inequalities within the household affect market outcomes, and these feed back; into household decisionmaking. This process is reinforced by inequalities in access to assets and services beyond the household. Improving the relative status of women within the household and increasing their access to assets and services will increase the returns to investment in human resources and improve the prospects for sustainable economic growth.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">We must look for that which we have been trained not to see  Ann Scales, Yale Law Journal 1986</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Chapter three</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<B><P></P>
+<!--
+<Section>
+  <Description>
+    <Metadata name="Title">Public Policies Matter</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As CHAPTER 2 has shown underivesting in girls and women is inefficient for society as a whole. Correcting for past underinvestment will require a "genders" approach to public policy. How this can be concretely achieved is the topic of this chapter.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Equalizing Opportunities by Modifying, the Legal Framework</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Laws form tile functional framework of the economy and of civil society. Equality in the legal treatment of men and women creates the legitimacy policymakers need to seek change. Legal and regulatory provisions that discriminate against women-that. for example bar married women from seeking employment or prevent women from holding legal title to land-perpetuate gender inequalities and severely restrict women's ability to participate fully in social and economic development.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Modifying the legal framework to  eliminate discrimination and equalize opportunities for women and men is an important goal for public policy at the national and international levels. A supportive legal environment is also vital for other aspects of public policy that have a direct bearing on the opportunities available to women. such as regulations affecting the formal and informal sectors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Four areas of the law are particularly important for equalizing the opportunities available to men and women: land and property rights; labor market policies and employment law: family law: and financial laws and regulations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Land and Property Rights</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Policymakers should ensure that women and men are treated equally in the public allocation of land. Eligibility for land reform programs, for example. should not discriminate against women's perform claims whether the women are heads of households or members of households headed by men. When communities have been resettled or when a project allocates land to participating producers, women should have the same rights to land as men For refugee and displaced women returning to their homelands. often as de facto heads of households. need fair and equal treatment to allow them to establish a Farming or enterprise base as soon as possible. Whet-e land is in short supply, it may be necessary to recognize the land rights of certain groups, as well as their individual rights. The Indian National Sericulture Project is an example; it has leased land to women's groups and promoted women's access to land under state land-grant schemes (Quisumbilig 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Some countries have enacted legislation to ensure gender equality in property and contractual rights. Under China's Law of Succession, for example males and females have equal rights to inheritance. Complementary measures are needed to ensure that women know their rights. Such measures include legal programs and campaigns to make judges and administrators sensitive to gender issues in the area of property rights (see box 2.1)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Labor Market Policies and Employment Law</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Discriminatory labor market policies and employment laws are widespread: examples are bans on hiring married women and restrictions on the type of work pregnant women may pet-form. Labor laws may also restrict female participation in jobs and deny women access to work settings. Even legislation that seeks to promote equal opportunity can have outcomes tot women workers. For example, generous maternity and child-care benefits tot women workers may make hiring women relatively mote costly than hiring men. perpetuating the gender wage gap.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The main issue for public policy its to ensure that fair and equal employment laws exist and are enforced.</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.1 some NGO efforts to promote women's legal literacy</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schuler and Kadirgamar - Rajasingham (1992) describe innovative approaches by  non governmental organizations to provide women with useful legal knowledge and tools.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Caribbean Association for Feminist Research and Action (CAFRA) has launched "women and the law" projects in five English-speaking Caribbean countries. Using a participatory methodology. the projects aim to create awareness of the law. provide women with legal information that will be useful to them in their daily lives, identify specific areas for action, and influence overall legislative policy. The projects develop educational materials for legal literacy and offer topic specific paralegal training for women's organizations.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The legal literacy program of the Ugandan Women Lawyers' Association (FDA-Uganda) conducts legal literacy campaigns on specified dates each month in different districts. Pairs of FIDA volunteers conduct sessions, using role playing and discussions, on legal topics of relevance to women's lives and provide advice on contacting the FIDA legal clinic for advice and representation. In addition, FIDA and Action for Development broadcast regular radio and television programs on women and the law and publish pamphlets on legal issues of interest to women. </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In India the Self - Employed Women's Association (SEWA) holds worker education meetings to provide members with legal information and offers one day training sessions on specialized legal information for community leaders. Members of SEWA paralegal staff research cases, prepare briefs, and argue all cases in labor courts for members. SEWA'S legal literacy efforts are part of its overall strategy of action for supporting self-employed women and women in the informal sector.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In this regard. the main issue for public policy is to ensure that fair and equal employment laws exist and are enforced. Such laws should cover employment and employment-related benefits and should not be applied in a way that restricts women's access to the labor market.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In many countries women are protected by special standards in the workplace. These safeguards are of two types. The first includes measures intended to end discrimination in the labor market by requiring equal pay for work of equal value or by prohibiting the exclusion of workers from certain jobs because of gender. The second type protects women in their role as mottles by requiring employers to pay the full cost of maternity leave and provide childcare facilities. restricting night work, and limiting work categorized as dangerous or hazardous.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The first type of labor standard is often difficult to enforce. although nearly 120 countries have enacted equal opportunity laws. In most cases the law is in place but is not enforced. Furthermore. it often applies only to the formal sector of the labor market. leaving large number of women in the informal sector with little protection. More concerted public and private action is required to devise appropriate for enforcement. In additions complementary measures are needed to increase womens chances of entering the labor force. Such measures would include mote met-it-based hiring of women in the public sector and the creation of an appropriate regulatory framework that encourages the establishment of day-care centers private nursery schools. and kindergartens for the children of workers in both the formal and informal sectors. (Box 3.2 describes a day-care projects in Bolivia)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many countries have laws that limit night work. over theme and the use of heavy machinery by women. While well intentioned. these laws. too. can reduce women's employment options by raising the employer's cost of hiring women and perpetuating the notion that women workers are less flexible than male workers. This adverse result occurs because women already tend to have lower levels of capital than men and are limited by traditional notions of what womens work. Devising effective protective legislation for women is thus a difficult balancing act.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Effective laws to protect women must honor the fine line between ensuring sate working conditions for all workers, including women in the informal sector. and providing equal opportunities for all workers seeking employment. Standards relating to maternity leave and child-care benefits are common in the formal sector. To ensure that such standards do not raise the costs of female labor unnecessarily employment legislation should avoid having employers pay benefits directly. Maternity benefits should be funded through general revenue taxes</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Box 3.2 day-care center in Bolivia to enhance the status of women by increasing their employment opportunities in other Latin American countries, and their knowledge of women in Bolivia are over represented , health, and nutrition. The project among the poor, and many live in will establish day-care centers to proficult circumstances. They are twice vice non formal,  home-based, integrals likely as men to be illiterate, their child development for children unaccess to child care is limited, they the age of 6 in thirty-four poor subject to discrimination in hiring ban and purebred areas. Women and wages, and they are restricted benefit from the project either as by law from engaging in certain procure givers employed at the minimum ductive activities. wage or as clients of the centers. The Integrated Child Development children in day care gives women Project, financed by a credit from the more time to search for jobs or to in World Bank's International Development their current situations (Winkler opponent Association designed and Guedes 1995).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Or social security systems rather than by direct contributions from individual employers. In Eastern Europe and Latin America, however, this method of funding benefits has imposed a significant cost on the treasury, raising the question of how much should be paid and for how long.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">One way of addressing this issue is for governments to encourage women and men to share the responsibility for childrearing by adopting legislation allowing either parent to qualify for the leave and benefits associated with having a child (Folbre 1994). Such legislation can be supported by changes in the tax system to ensure equal treatment of workers within the household and a margin tax rate on the earnings of additional workers in the household low enough to avoid creating a disincentive to women's participation in the labor force (Mac Donald 1994). These tax changes can be complemented by legislation that encourages absent to pay child support. Such laws are in place in many Latin American and Caribbean countries. but none systematically monitors transfers (Folbre 1994). Greater efforts to enforce the law are needed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Family Law</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gender inequality in family law can worsen women's bargaining position within and outside the household and affect household welfare and efficiency. As noted in chapter women's bargaining position in relation to Household resource allocation is often a key factor in determining the wellbeing of household members. particularly children. Reforms of family law can enhance women's economic and social opportunities while still respecting cultural norms. For instance the minim age of marriage for women  should be set high enough so that girls can complete secondary schooling: this would help lower fertility rates. (Allowing for exceptions such as parent consent negates the potential fertility benefit.) Marriage contracts should include stipulations guaranteeing the wife's rights. especially on separation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Women's bargaining position in relation to household</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Legal and policy measures can have a direct bearing on the health of women. The law and its enforcement are essential for combating domestic violence against women. If the laws on violence against women are to be enforced, women need to be made aware of the legal recourse available to them and the judiciary and police need to be sensitized to the existence and</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.3 innovative approaches to combating gender violence</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Brazil's women-only police stations are an innovative approach to the problem of violence against women. They have been so successful that other countries-including Argentina, Colombia, Costa Rica, India, Peru, and Uruguay-have emulated them. The police stations have made it easier for women to report gender based crimes of violence, and, with that experience, women are now demanding more support from the police, such as legal counseling and advice. Despite the program's success, the number of convictions for gender-based crimes has not increased, largely because similar innovations have not been made in the  judicial system (Heise, Pitanguy, and Germain 1994). </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Zimbabwe the Mussasa project provides support and counseling to abused women and sensitizes police and prosecutors to the issues of domestic violence and rape. To ensure the credibility and acceptability of the training, legal professionals are involved in the program. One branch of the criminal justice system-the police department, for example-often hosts training for another, such as prosecutors (Stewart 1992).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Costa Rica El Instituto Legal de las Naciones Unidas y Desarrollo runs gender sensitization training for prosecutors, judges, lawyers, and other professionals who deal with crimes of violence against women (Heise, Pitanguy, and Germain 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Implication of violence against women. Affirmative action policies can increase the number of women police officers lawyers, and judges. Trading police, lawyers, and judges can increase their gender sensitivity. making the legal system more responsive to women's needs. Legal literacy efforts can make women aware of their rights and show them how to use these rights to mobilize for change. Some approaches to dealing with domestic violence are illustrated in box 3.3</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Financial Laws and Regulations</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Access to credit is vital for women, allowing them to manage fluctuations in income and expenditures and to expand their businesses. As we saw in the preceding chapters, credit can be an important source of economic empowerment for women within the household. But in many countries. underdeveloped financial markets, controlled interest rates, and overly rigid backings regulations have led to systems of credit that tend to shut out the pool. many of whom are women If financial institutions are to lend to those unable to obtain credit in the current environment. interest rates must be liberalized. Positive interest rates have important effects on informational money markets, which tend to be more exploitative when formal sector credit is rationed.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Changes in the laws governing access to credit are also vital because women's business profiles often differ from men's. Compared with men. women are more likely to work in low-risk small, and home-based businesses (Rhyne and Holt 1994). This situation creates a demand for small loans that can be obtained without formal, legally secured collateral and that offer relatively flexible repayment terms. Legislation that encourages broad access to financial institutions can increase the availability of these types of loans. but legal changes may also be needed to extend the range of acceptable collateral.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In many countries the regulatory framework contains provisions that are especially punitive to small firms. This adds an additional constraint on women, whose businesses are concentrated at the small end of the size The deregulation of the microentreprise sector would remove implicit disincentives to small-film activity and would relieve some of these Such action would enhance women entrepreneurs' prospects of benefiting from training or credit programs targeted to the microentreprise sector (World Bank 1994d. 1995c).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Redirecting Public Policies and Expenditure to Promote (tender Equality)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is unlikely that legal reform by itself will be sufficient to ensure that women and men ate treated equally. Further public action may be required to guarantee that gentler-neutral laws are enforced at both national and local levels.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Macroeconomic: Policies</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Many developing countries are implementing important policy and institutional reforms to address changing economic conditions on both the domestic and international fronts. These reforms are often supported by international financial institutions and bilateral donors. The pace of reform has varied across countries Those countries that have implemented reforms early on, carried them out consistently, and received adequate financial support have generally enjoyed faster and stronger economic growth than count ties that have undertaken reforms too slowly, too intermittently, or not at all. Where implementation has been slow or the government's commitment weak, economic distortions have tended to multiply and economic trowels to slow. limiting the government's ability to invest in physical and human capital for the future.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is often the poorest groups in society that stand to lose the most from economic distortions. High and rising inflation places a disproportionate tax burden on the poor including low-paid wage workers and those with fixed incomes. For this and other reasons, inflation tends to hit women harder than men. An overvalued currency is also regressive; it keeps the price of goods artificially low. crowding out many locally produced goods. Women's businesses. which ate often concentrated in the informal sector, can be particularly vulnerable to competitions from cheap snorts. An overvalued currency reduces international competitiveness. limiting the availability of foreign exchange for domestic entrepreneurs and constraining business expansion and employment creation. A firm commitment to policy refortify is therefore essential to economic growth and sustainable initiatives for alleviating poverty.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Inflation tends to hit women harder than men.</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Such reforms generally include two kinds of necessary policies. The first emphasizes macroeconomic stability and the removal of price distortions: the second promotes labor-demanding growth in agriculture and industry and better. mote accessible basic social services. mightily in education, health care and water supply. Macroeconomic stability can be achieved by reducing large current account and government budget deficits and by curtailing excessive money and credit expansion. Correct pricing of foreign exchange and of domestic goods and services facilitates trade and investment and promotes growth Reforms of trade and price incentives encourage job creation and higher earnings.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In shots. broadly based economic reforms benefit the poor, as the experiences of diverse countries have shown. Data from the LSMS and similar studies confirm that in Costa Rica, Ethiopia. Than Indonesia, Peru, the Philippines, and Tanzania, declines in poverty rates have accompanied economic reforms. Because of underlying gender inequalities, reductions in poverty do not necessarily improve the economic status of women. Nonetheless. although empirical evidence on changes in women's welfare following reforms is scarce, data from the Philippines suggest that for women. economic reform is by improvements in social indicators and important employment gains (box 3.4). An analysis of household data from Peru indicates that reforms there have not only led to renewed growth and reduced poverty but have also improved the status of female-headed households (box 3.5).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Despite their seminal role in encouraging sustainable. long-term growth. some economic reforms involve transitional costs. for two reasons: the need to implement radical shifts in government policy, and the lag. perhaps of years, between acceleration of economic growth and the realization of the 
+</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.4 social progress and labor force gains for women in the Philippines</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The Philippines began implementing economic reforms in the early 1980s. While political turmoil and some policy slippage have weakened GDP growth over the period and led to the need for further reforms, quality of life indicators have improved during adjustment. For example, by 1990 the incidence of absolute poverty had declined by about one-third (to approximately 20 percent of the population). Maternal and infant mortality rates also declined over the period: in 1980 the infant mortality rate was 52 per 1,000 live births, but by 1990 it had fallen to 41 per 1,000 births (Johansen 1993). </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The percentage of the population with access to safe drinking water increased between 1980 and 1990, from 65 to 93 percent of the urban population and from 43 to 72 percent of the rural population. The figures for sanitation services showed the same increase, climbing from 81 percent with access in 1980 to 98 per  cent in 1990 among urban dwellers and from 67 to 85 percent among those in rural areas. Secondary school enrollment rates for boys and girls also showed gains. Girls and boys have traditionally reached similar educational levels in the Philippines, a trend that contributed to women's gains in the labor market during adjustment in the 1980s. While labor force participation rates for men rose only slightly, the rates for women increased dramatically, from 23 to 37 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">At the same time, women's wages as a percentage of men's grew from 71 to 80 percent between 1978 and 1988 (Tzannatos 1995). A recent study of a low-income community in Manila found that in some private sector jobs women earn more than men, reflecting in part the high educational level among women in the sector. Earnings in the informal sector are generally low for both women and men. although some women have been so successful in their informal sector businesses that their spouses have opted to leave low-paying jobs in the formal sector to participate in their wives enterprises (Moser 1994).  benefits of growth by large segments of the population. The short-term costs can include increases in food prices as subsidies are removed temporary restrictions on credit to control monetary expansion, and cuts in public spending as governments attempt to control budget deficits and reorient spending toward the most important public services. Moreover, inequalities in access to and control over resources and in entry into markets hamper some groups in taking advantage of the opportunities created by economic reform For example, people who are unable to acquire new skills may remain for some thee. Gender inequalities in access to and control over land in rural areas can keep women farmers from taking advantage of changes in the relative prices of tradable and non tradable crops.</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.5 macroeconomic reform and improved living standards in Peru</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Between 1985 and 1990 Peru's economic regime was marked by expansionary monetary and fiscal policies and high levels of government intervention in most areas of the economy. Although these policies led to an initial period of growth, the approach proved unsustainable: by late 1987 growth had given way to hyperinflation and deep recession. During 1988-90 real GDP dropped by an average of 8 percent a year. Real wages and consumption expenditure also fell sharply as inflation soared to 7,600 percent a year in 1990.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In 1990 the new government of President Alberto Fujimori introduced macroeconomic reform measures designed to stabilize the economy, reduce fiscal deficits and inflation, increase market efficiency, and improve the country's competitiveness. Under this reform program inflation declined dramatically, falling to 57 percent in 1992 and to 17 percent in 1994. Real GDP grew by about 20 percent between 1991 and 1994, while real per capita consumption expenditure grew by more than 18.5 percent. LSMS data show that poverty declined by 11 percent-from 55 percent of the population in 1991 to 49 percent in 1994. Although the country experienced a brief contractionary period following the introduction of reform measures, household data from Lima for 1990, 1991, and 1994 indicate that in 1994 per capita expenditure was well above, and the incidence of poverty well below, 1990 levels. </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Improvements in living standards have been widespread, and the largest gains have been made in some of the country's poorest regions, such as the urban and rural sierra (mountain areas). In most parts of the country, increases in per capita expenditure among households headed by women have been above the national average. In the urban and rural sierra, for example. consumption expenditure by these households increased by 47.7 and 44.8 percent. respectively-figures that compare favorably with increases in per capita expenditure among households headed by men (35 and 28 percent for the same regions).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although both women and men are expected to gain from economic reform in the long run. gender inequalities at the household and market levels can mean that the benefits of reform reach women, especially poor women. only slowly. Reforms must incorporate measures aimed at counter acting shot-term transitional costs. Among the most important are safety nets specifically targeted to vulnerable groups. For example, in fiscal 1994 seventeen of the twenty-three reform programs supported by the World Bank included components aimed specifically at reducing poverty: fourteen of them targeted programs or safety net measures such as labor-intensive public works projects. targeted and social assistance programs, and unemployment and social security schemes (see box 3.6).</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7 WIDTH=590>
+<TR><TD VALIGN="TOP">
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.6 food coupons improve nutrition in Honduras</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The food coupon program in Honduras, part of a social safety net supported by the World Bank and financed by IDA and other donors, was put in place in 1990 to protect the country's most vulnerable people during economic reforms. Starting with about 182,000 participants, by 1994 the program had expanded its coverage to 345.000 of the estimated 430,000 children at risk of malnutrition. The effort also supports nutrition education for health workers, community groups, and mothers. Because coupons are used instead of food. the government saves some 30 percent over traditional food distribution costs, and the beneficiaries are able to choose the food  they will consume. Beginning in 1995, an adjustment for inflation will maintain the value of the coupons, enabling participants to satisfy a constant proportion of their food needs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The project also supports the development and implementation of a long-term nutrition assistance strategy for Honduras. Although attempting to measure changes in malnutrition is difficult in the short term, there have already been noticeable benefits. Between 1990 and 1993 the number of first-graders with severe or moderate malnutrition dropped by 4 percent. Organizers are now trying to graduate women participants from the program by offering training in basic skills such as food processing and helping them find assembly work in local factories (World Bank 1995b). </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However, safety nets are not a substitute for a mote integrated approach to economic and social policy that includes appropriate levels of harvest in social services and infrastructure. Recognizing this fact, governments and donors are increasingly incorporating into their reform packages antipoverty initiatives and measures to reduce gender inequality. In Pakistan, for example, the FIDA-financed Public Sector Adjustment. Program provides much needed the financial support for the balance of payments account and reinforces the emphasis on government investment in the social sectors. The program promotes increased access to and improvements in basic education. health. and water supply services that benefit girls and rural areas. It also supports a shift it government education and health spending toward the primary level.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">In fiscal 1994 twelve of twenty-three World Bank economic reform pro emphasized the restructuring public expenditure, primarily to and increase spending on education. health care, and other areas important to poverty reduction such as water supply and sanitation. The Burkina Faso reform program is typical; it supports an increase in the total budgeted amounts for primary education and health services, which are particularly beneficial to the poor and to women. Uganda s program seeks to protect and enhance public expenditures for basic social services. including water supply primary health care and primary education. In the long term, the reform of public spending-especially in the social sectors, physical infrastructure and agricultural research and extension-promises significant benefits) trot women.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Sectoral Investments</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In principle. public expenditures on social services and infrastructure are allocated on a gender-neutral basis; in practice men and women use these services differently. The resulting inequalities frequently perpetuate gender based differences in the accumulation and distribution of human capital within households. Public policy can address this problem by public expenditure priorities between secrets and within social sectors. Further it can support services and types of infrastructure that provide the highest social returns to public spending and are most heavily used by women  and children.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">EDUCATION. Estimations of the private returns to education for a number of countries (Psachatopoulos 1994) show that returns are at least equal for girls anti boys and are often higher for girls. Moreover, these rates do not capture the externalities generated by providing education to girls. The combination of private and social returns provides a clear signal for restructuring the allocations of public resources so as to support female education. Yet incidence analysis for a number of countries for which the necessary data are available reveals that educational subsidies per capita are higher for males than for females This difference is partly a result of the bias in allocation of subsidies toward higher levels of education, where female enrolled is lowest. Distortions in the allocation of public resources, such as the provision of mote money foe male-dominated tertiary institutions than for education that benefits girls, should be corrected by reallocating spending toward basic (primary and lower-secondary) schooling. Targeting these educational levels will have the maximum effect on girls' education and will yield higher social returns for society as a whole. In countries where universal basic education has been achieved and capital markets are unable to help households finance higher education, continuing subsidize higher education may be warranted. The rationale for the subsidy would be the productivity gains associated with a better-trained labor force.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">To correct the bias against enrollment of girls more targeted interventions are need to influence household (see decisionmaking)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">However reallocating public spending toward primary education and later toward higher levels is not sufficient to erase the gender gap in education The bias against enrolling girls in school is evident in both poor and no poor households and applies even at the primary level. To correct this bias, more targeted interventions are needed to influence household decision making</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">HEALTH. Correcting the gender bias in the public financing of health care IS a more complex process than correcting the bias in education. for two main reasons: the marked differences between the health needs of men and women, and the unreliability of household data on demand for health services in comparison with the data on demand tot education). However it is cleat that targeting health services to women implies provision of adequate funding for prenatal care. infant immunization, and mother and child health services. Because of the significant social benefits of providing women with appropriate health care, governments should make basic services ices that benefit women a top priority among, public health care expenditures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There is a critical link between the public provision of health care and women's access to educational opportunities. A mother educated to seek preventive care and early treatment of illness for herself and her children (particularly girls) will reduce the cost of health care and in many cases. prevent premature death. Most of these highly cost-effective services can be supplied in rural clinics and health centers. Public spending should be so allocated as to ensure sufficient funding for these primary health facilities.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">AGRICULTURAL EXTENSION SERVICES. Agricultural extension and research services are widely considered vital to increasing and sustaining agricultural productivity. Many of these services are being provided by the private sector. but in some countries private services need public support, either because certain markets have not yet been developed or because the infrastructure is poorly developed. However. women farmers and small holders are often not served as effectively by public agricultural extension systems as ate and male farmers (FAO 1993). This disparity stems paltry from expend priorities within agricultural extension services. which concentrate resources on the crops and the technology controlled primarily by male commercial farmers. Reallocating public spending on agricultural extension and research services toward crops and technology raised by or used by small holders and women farmers could yield high social returns to public investment and could increase private returns by improving the skills and productivity of small agricultural producers.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reallocating public spending on agricultural extension  and research services toward crops and technology </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Techniques for small holders and women farmers should take into account the need for quality and cost-effectiveness in public services, Economies of scale can be achieved if extension agents deal with groups of farmers instead of with individuals. This approach also provides a valuable forum for exchanging information. fostering peer learning. sharing expensive equipment. and pooling resources for- credit. Mobile trailing units and flexible hours that fit the crowded schedules of women farmers should also be considered. and more female extension agents should be trained to deal directly with female farmers. Such measures can be introduced without large additional resources if existing expenditures are carefully reallocated.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">INFRASTRUCTURE, Public investment in economic and social infrastructure is vital in facilitated individual and household investment in physical and human capital. However, public expenditures on roads, water supply, and sanitation infrastructure frequently do not meet the needs of those who use the services most heavily. Women are the main users of water services, and it is essential to involve them in designing and implementing water projects. For example. in areas where transport is inadequate and water collection is a daily burden for women and children, the population tends to use the closest available facility rather than the safest one. In such cases. projects that ensure a safe water supply and take into account the specific needs and constraints of the users often have a significant effect on users' health. In two villages in Zaire where a piped water network was installed to provide safe drinking water, the median incidence of diarrhea was halved among children in households located less than a five-minute walk from a public standpipe. Spending allocations that favor public water supply and sanitation improve the general health of the population, save time for women and children. and increase school attendance. A study from Morocco chows that access to tap and well water instead of pond or river water raised school enrollment for both boys and girls (Khandker, Lavy, and Filer 1994).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Women are the main users of water services and it is essential  to involve them in designing and implementing water projects.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Public spending on roads and energy-related facilities (for instance electrification or energy conservation) or other infrastructure is usually assumed to be gander neutral. Yet women and men use these facilities differently The Morocco study cited above found that the availability of electricity increased the rate for girls substantially more than for boys. The study also showed that the presence of a paved road increased by 40 percent the probability that girls would attend school and reduced by 5 percent their probability of dropping out. Overall, improved road conditions increased the probability of school attendance for girls by 32 percent and for boys by 20 percent.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rural electrification can also ease the time constraints on women who must balance household and productive work. Lack of time is often a primary season for women's weak response to economic incentives. especially in rural areas. The case for making public investments in infrastructure would be stronger if gender differences in the use of projects and services, as well as the potential effect of such investment on productivity and social development. were taken into account.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Using Targeting Measures to Narrow the Gender</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">As we have seen. policies that specifically target women or girls can address the needs or this group more efficiently and with greater cost-effectiveness than general policy measures. Female household members tend to allocate resources more directly to children. while men tend to allocate more resources to adults. In households in which resources are not pooled. targeting programs to the household as a where will not necessarily benefit all members equally.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Targeting women directly is justifiable on two grounds. First, to the extent that gender inequalities prevent an economy from realizing its full potential. targeting to women can be an effective strategy for increasing productivity and output Second, where gender differences are wide, targeting may be needed to capture social gains and to increase internal efficiency.</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7>
+<TR><TD></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY">Targeting women is especially when doing so contributes directly to reducing poverty; or when women have particular needs-for example. when maternal mortality is very high. The exceptionally high gender gap in educational enrollments in some countries can be reduced only by policies (including subsidies) that target girls. An obvious example would be policies that affect the private costs of schooling. </P>
+<P ALIGN="JUSTIFY">Female household members tend to allocate resources more  directly to children it while men</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Reducing these direct costs to households Will mean setting new public spending priorities. For example. education institutions for girls especially at the primary level, might be exempted from cost recovery measures. thus increasing the implied public spending subsidy to girls. Similarly. a far; number of publicly funded scholarships can be provided for girls' as has been done in and Guatemala.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Opportunity and travel costs can discourage parents from enrolling especially daughters in school. Some counties have tried to overcome the constraints imposed by opportunity costs by introducing flexible school hours and calendar years and providing child care for younger siblings (box 3.7). In some cases girls who are responsible for looking after their younger brothels and sisters ate allowed to bring them to school.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In countries where cultural values may prevent girls from traveling alone to school. measures are needed that will increase access to safe transport.</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<TABLE BORDER CELLSPACING=1 CELLPADDING=7>
+<TR><TD>
+<B><FONT SIZE=2><P ALIGN="JUSTIFY">Box 3.8 economic reforms and gender targeting in Mongolia</P>
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Since Mongolia began its transition to a market economy in 1990, the living conditions of the population have deteriorated dramatically. According to the government's estimates, a quarter of all Mongolians are now living below the poverty line. Single women with young children are among the "new" vulnerable groups that have emerged in the wake of the transition. As of December 1993 nearly 72 percent of households headed by single persons, usually women, were estimated to have incomes below the poverty line. (About 28 percent of all households in Mongolia are headed by women). The Mongolian Women's Federation reports that the divorce rate is rising among jobless low-income couples, increasing the number of single-parent households. </FONT></TD>
+</TR>
+</TABLE>
+
+<FONT SIZE=2><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Along with job loss women are affected by the decline in services such as day care and maternity homes.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mothers now have to look after their children at home, which restricts their ability to participate in the labor market and, ironically, increases their dependence on welfare. When herds were privatized, priority was given to people who, according to the government, could take better care of the animals. Unfortunately, this policy adversely affected female-headed households.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The maternal mortality rate has doubled over the past three years. in part because many more babies are being delivered at home. Other factors that have contributed to the rising maternal mortality rate include a decrease in the number of ambulances and the need for patients to pay for the food they consume while they are hospitalized.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In Mongolia, targeting female-headed households, pregnant women, and children is essential for reducing poverty. Social assistance, health care. education, and help in finding employment are particularly important (Subbarao and Ezemenari forthcoming).  change the geographic distribution of primary schools, of provide more boarding facilities. Projects in Pakistan are using school mapping techniques to establish criteria for placing new schools in currently underserved areas. Such programs benefit both girls and boys.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It may be necessary to target women when economic reforms of systemic transitions are occurring. For example, in Mongolia, as well as in other countries making the transition from a socialist to a market economy, women are disproportionately represented among the unemployed and otherwise disadvantaged (box 3.8). Thus, in designing safety nets to mitigate the short negative effects or economic transitions. policymakers need to recognize and evaluate the specific adverse effects on women</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">It is not always necessary to restrict a particular program of benefit exclusively to women: the objective can sometimes be achieved indirectly.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Techniques based on self-selection appear to be particularly efficient. In Zambia. where men have a strong preference for cash wages, offering wages in kind (food) attracted more women workers than men to public works programs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the financial sector. women entrepreneurs are enabled to borrow at market rates of interest when banking institutions adopt innovate collateral requirements, reduce transaction costs, and offer small loans at repeated intervals The Grameen Bank in Bangladesh and Badan Kredit Kecaman in Indonesia do not reserve loans for women specifically: instead. they adopt innovative lending policies the result of which is that women snake up the majority of participants-is 96 percent in a new branch of the Grameen Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Involving Beneficiaries in Public Policy</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Until recently. the absence of input from beneficiaries often let's ignorant about how the costs and benefits of policy changes would be distributed among the population Today the views and needs of potential beneficiaries are being taken into account at both the macroeconomic and sectoral levels. This trend should make it possible to determine who benefits. who does not, and why. A good example of a situation in which a beneficiary's point of view can make a significant difference is in public expenditure reviews. Governments with unsustainable budget deficits must make difficult decisions about the allocation of public resources. Their task can of ten be facilitated by suggestions from the potential beneficiaries themselves, since one of the key questions policymakers face is whether investments as presently allocated are reaching the intended populations efficiently and effectively</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Three broad approaches can be used to guarantee that the views of women and other intended beneficiaries are adequately reflected in policy and project formulation. First. surveys and other methods of collecting statistical data can be designed to ensure that gender-desegregated data are properly collected and analyzed. Second, beneficiary assessments, which use a range of qualitative research methods such as direct observation. selected individual of group interviews. and case studies. can be used to ensure that the views of all groups are adequately represented.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A third approach involves a range of participatory planning and management techniques that reflect a significant transfer of control to the community and local levels. Participatory evaluations use innovative research that allow illiterate and otherwise voiceless groups to express their concerns and priorities. Small grants and credits managed at the local level by NGOs or governments agencies permit a community to choose the projects that best reflect its OWN priorities. Social funds. whereby resources are channeled to demand-driven projects, are one such mechanism While these participatory approaches have been implemented primarily at the local level, they are also beginning to be used to involve the community in regional and national planning. Participatory methods, by helping to create local capacity. ensure the sustainability of projects and programs. They also help establish rational criteria for making public investment choices that incorporate both social and efficiency objectives.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Generating and Analyzing Gender-Desegregated Data</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gender-desegregated data and the capacity to analyze these data provide public policymakers with essential information and enhance the dialogue with agents outside government. One of the most valuable instruments for collecting desegregated data is the household survey. which can provide detailed information that is invaluable in policymaking. Obtaining full gender information in many instances entails only a small increase in costs. since the desegregation itself involves little extra work. However additional resources ate often needed to analyze the data and make it useful to policymakers. Public statistical agencies might analyze gender-desegregated information in partnership with private and academic institutions in order to share the costs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">There are several important steps in collecting useful and accurate data. First. in places where gender -desegregated household data have not yet been collected. special efforts should be made to obtain them. At a minimum data on how individuals use health and educational services should be collected routinely as part of national consumption and expenditure surveys. If household consumption. income or production surveys have already been carried out but little or no gender--desegregated data have been collected, the marginal cost of collection is likely to be quite modest-perhaps on the order of 10 percent of total costs.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Participatory methods help establish rational criteria  for making public investment choose that incorporate  both social and efficiency objectives. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Second. in places where basic gender-desegregated data have already been collected, it is important to gather more data from individuals on consumption and. as much as possible. on income and the ownership of assets. Such data ate vital for developing a deeper understanding of how access to and allocation and control of resources are determined within households. More data on men's and women's access to credit and information services, such as agricultural extension programs, are needed for an understanding of women's limited access to important production inputs. The data also indicate the effectiveness of projects and programs in providing such services to women.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Third, there should be an increased emphasis on collecting panel data (thee series) to facilitate snore detailed analyses of changes in household behavior over time. Because full panel surveys are costly, it may be necessary to adopt less-expensive panel methods and combine them with flexible data collection. Anthropological and participatory research methods can be used to enhance the quality and relevance of formal survey questions, as well as to provide a "reality check" on formal survey responses.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Finally, greater priority needs to be given to gender-disaggregated analysis of existing data sets. This analysis should be carried out not only in social sectors such as health and education but also on such issues as the intrahousehold allocation of time and labor and access to and use of productive resources.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Working in Collaboration</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments' ability to identify and implement policies that promote gender equality is greatly enhanced by the active participation of other players from the development community and civil society. These agents include individual women and men, community-based groups, private-for-profit firms, trade unions, non governmental organizations, and multilateral and bilateral agencies. Interaction between public institutions and other actors provides the basis for a more informed policy dialogue on gender issues. It also lays the foundation for operational collaboration and for broadly based support for public policy measures.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Over the past several decades NGOs have become major players in international development. NGOs are by no means homogenous. In the field of development, they range from large volunteer and charity organizations, many of them based in industrial countries, to community-based self-help groups. They also include research institutes, volunteer-sending agencies, religious organizations, professional associations, and lobbying groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">NGOs concerned with gender issues have had a particularly important role in designing and implementing gender programs, especially at the grassroots level, and in advocating policy change at the national level NGOs have been effective in providing information and education to women and in helping community-based women's organizations lobby for change. In many countries collaboration between NGOs and governments is still relatively new. Nonetheless, it is growing rapidly-most visibly in the delivery of social and financial services.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">For example, in Peru a proposed basic health and nutrition project aims to improve the quality and accessibility of health and nutritional services, with an emphasis on poor women and children. NGOs are expected to play a major role in implementing the project and will be responsible for 75 percent of training and research, 40 percent of education, and 20 percent of service delivery (World Bank 1994g). In Africa many HIV/AIDS support programs are managed by NGOs with assistance from governments and funds from international donors.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the long run choices made by private sector agents are profoundly important for the persistence  or reduction of gender inequalities </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">In the financial services sector NGOs have found innovative ways of overcoming barriers that women face in access to credit and savings facilities. Among the better-know programs are the Grameen Bank in Bangladesh, ACCION International in Latin America, and the NGO consortium ACCORD in Africa. NGOs have been very successful in organizing village banks and mobile banking systems to reach the rural poor. These credit programs provide women not only with the funds to finance income-generating activities but also with opportunities to acquire basic business skills and to assume leadership positions within their peer groups.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments also seek to collaborate with a range of institutions from the private sector. In the long run the choices made by private sector agents- whether households, firms, or trade unions-are profoundly important for the persistence or seduction of gender inequalities. Joint public-private sector initiatives can be vital in changing peoples perceptions about the benefits of investing in or hiring women. The private sector has a comparative advantage in providing certain kinds of services to women-for example, vocational education and training. Collaboration with the private sector- often means that public resources can be reallocated to those investments that offer the highest rate of social return. such as basic education and health care.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Strengthening International Policies to Meet New Challenges</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Not all issues that bear on gender equality can be effectively addressed by individual nations. For example, refugee and displaced women and children account for up to 80 percent of the 50 million refugees and displaced persons worldwide. The sheer numbers of refugee and displaced women and children highlight the urgent need to devise international strategies for dealing with this problem.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The sheer numbers of refugee and displaced women and  children (estimated at 4 million) </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The constraints that refugee and displaced women lace are similar to those faced by other women, only magnified many times. They lack access to health services, even though their health risks are high. Girls often have less access to basic education than in their home countries. With little access to family planning, women s fertility rates may be extraordinarily high at a time when the burden of additional children hinders the chances of survival for both mothers and infants. In the absence of professional abortion services, women may rely on self-induced and unsafe abortions. The proportion of female-headed households is highest in refugee situations, yet the women's income-generating activities and skills are minimal</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">The international response to this type of crisis is usually limited to emergency relief measures. Although vital, these measures often fail to recognize the long-term economic and social costs involved in restructuring the lives of displaced women when they return to their home countries. International public policy has an important role in preparing refugee and displaced women for their future role in rebuilding their societies. Long-term repatriation and development on a regional basis along the lines of the International Conference on Central American Refugees (CIREFCA) in Central America is one approach to involving governments, NGOs and development agencies in a coordinated response to refugee problems. Governments and agencies must make every effort to collaborate in making repatriation viable by establishing development programs that explicitly take account of refugees' needs. Otherwise, chances are high that people will once again be forced to leave their countries. putting at risk national reconciliation efforts.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Another area that demands an international response is the establishment of legal conventions for the enforcement of social justice and human rights. Equality under the law creates the legitimacy policymakers and private individuals need to seek change that will increase well-being and encourage economic opportunity. In certain instances, legitimacy needs to be established at the international level. For this reason it is vitally important that governments ratify the Convention on the Elimination of All Forms of Discrimination against Women. This convention. adopted by the United Nations General Assembly in 1979, provides a framework for action by countries to reduce discrimination against women in political and public life, law and education, employment, health care. commerce. and domestic relations. International conventions of this type provide an important policy lever for women's organizations and other groups in civil society.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Conclusions</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This chapter has presented the rationale for public interventions to promote gender equality. Such interventions are needed because of market failures and social externalities that extend beyond the individual household to affect society in general. For resources to be allocated efficiently, public spending should focus on those investments with the highest social returns. Given the evidence of high social and private returns to investments in women's human capital, public expenditures should give priority to the investments that have the largest impact on the welfare of girls and women, especially in basic education and reproductive and other health care services. Policymakers also need to identify areas in which actions can be taken that would have gender neutral outcomes, including sectoral programs addressing transport and infrastructure, water supply. and sanitation</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">BY directing  public resource toward policies and projects  that reduce gender inequality policy markers are promoting  not only equality today but also higher labor productivity </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governments can no longer afford not to invest in women. The evidence on private and social returns to investments in women and girls cannot be ignored. By directing public resources toward policies and projects that reduce gender inequality, policy makers are promoted not only equality today but also higher labor productivity, a higher rate of human capital formation, slower population growth. and stronger economic growth tomorrows However, none of these goals can be reached without the participation of women  themselves. Governments and collaborating institutions must listen carefully to the voices of individual women, to women s groups, and to woman policymakers By working with others to identify and implement policies for greater gander equality, governments can take actions that will make a real difference to the future well-being and prosperity of their people.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">Notes</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1. Birdsall and Sabot (1994) use earlier findings by Barro (1991) to test the relationship between inequality and growth. They find that in Latin America unequal distribution of education. in terms of both quality and quantity, constrained economic growth in the region by reducing opportunities for increasing labor productivity. In East Asia open and relatively equal access to high-quality basic education led to a virtuous circle of high educational performance that stimulated growth and reduced inequality</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">2. Subbarao and Raney (1993) estimate that a doubling of family planning services in 1982 would have reduced the fertility rate from 5.5 to 5 0 and the number of births by 3.5 percent</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">3. The Living Standards Measurement Study (LSMS) is a series of multitopic surveys designed to study multiple aspects of household welfare</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">4. Deforestation is represented by the time required to collect a standard load of fuelwood</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">5. It would be more illuminating to compare wage differences across three categories of women workers: women without children: women with children but with no interruption in employment except for statutory maternity leave: and women with children and with interrupted employment</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">6. Among women workers. 53 percent are in commerce. compared with 33 percent of men. In manufacturing. 16 percent of the workers are men. compared with 14 percent for women. In services, 37 percent are men anti 33 percent are women (World Bank 1995c)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">7. In Bolivia informal moneylenders require borrowers to write postdated checks. If borrowers tail to make timely repayments, these checks are deposited and, as the lender knows will bounce for lack of funds A bounced check is a criminal offense in Bolivia. and the lender can have the borrower arrested The World Bank estimates that about 20 percent of all Bolivian prison inmates-and 40 percent of female inmates imprisoned for 'bouncing' checks and for other collateral-related crimes. In many cases children must live in prison with their mothers (winkler and Guedes, 1995)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">8. The International Conference on Central American Refugees (CIREECA) was held in Guatemala City in May 1989 A total of 126 projects in seven countries were introduced. with an overall investment of $365 million Areas with high densities of returnees were targeted. and special attention was given to projects to support displaced women</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<B><P ALIGN="CENTER"></P>
+<!--
+</Section>
+<Section>
+  <Description>
+    <Metadata name="Title">References</Metadata>
+  </Description>
+-->
+</B><P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agarwal. Bina. 1994. "Gender and Command Over Property: A Critical Gap in Economic Analysis and Policy in South Asia." World/Development 22(10) 22(10): 145578.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Baden. Sally. 1993. "The Impact of Recession and Structural Adjustment on Women's Work in Developing and Developed Countries." Working paper. International Labour Office. Geneva</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bardhan, Kalpana 1993. "Women and Rural Poverty: Some Asian Cases" In M G Quibria, ea., Rural Poverty in Asia Priority Issues and Policy Options. New York: Oxford University Press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bardhan, Pranab. 1988. "Sex Disparity in Child Survival in Rural India In T. Srinivasan and Pranab Bardhan. eds., Rural Poverty in South Asia. New York: Columbia University Press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Barro. Robert 1991 "Economic Growth in a Cross-section of Countries' Journal of Economics 106 (May):407 43.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Beneria. Lourdes. 1992. 'Accounting for Women's Work: The Progress of Two Decades.'' World Id Development 20(11): 1547-60.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bindlish. Vishva. and Robert Evenson. 1993. Evaluation of the Performance of T and V Extension it? Kenya. World Bank Technical Paper 208. Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Binswanger. Hans, and Mark R. Rosenzweig, eds. 1984 Contractual Arrangements Employment and Wages in Rural Labor Markets m Asia. New Haven. Conn.: Yale University Press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Birdsall, Nancy, and Richard Sabot 1994 ''Inequality as a Constraint on Growth Working Paper. Manila: Asian Development Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Blau. Francine. and Lawrence N. Kahn. 1992 " The Gender Earnings Gap: Learning from International Comparisons" America Economic Review 82 (2):533-38.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Bouis Howarth E., and Eileen T. Kennedy. 1989. "Traditional Cash Crop Schemes' Effects on Production, Consumption and Nutrition: Sugarcane in the Philippines and Kenya." Prepared for IFPRI-INCAP Policy Workshop. Antigua. Guatemala</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Chatterjee. Meera 1991. Indication Women Their Health and Productivity World Bank Discussion Paper 109. Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">David, Rosalind 1992 The Effects of Male Out-migration on Women's Management of the Natural Resource Base of the Sahel. SOs International, London.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Donors to African Education. 1994. A Statistical Profile of Education in Sub Saharan Africa in the 1980s. Paris.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Duraiswamy. P. 1992. "Child Survival. Preventive Health Care and Schooling in Rural Households of Tamil Nadu: India." Yale University, New Haven, Conn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Edgerton, V. R. G. W Gardner, Y Ohira. K. A Gunarwardena, and B. Senewiratne 1979 'lron Deficiency Anaemia and Its Effects on Worker Productivity and Activity Patterns' British Medical Journal 2:1546-49.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Einhorn. Barbara. 1993 Citizenship. Gender and Women's Movements in East Cent/al Europe London: Verso</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">FAO (Food and Agriculture Organization) 1993 Rural Poverty Alleviation Polices and Trends Economic and Social Development Paper 113 Rome</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fields, Gary S. 1992 ''Changing Poverty and Inequality in Latin America" Public Finance 47 (Supplement): 59-76.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Folbre. Nancy. 1994. Who Pays for the Kids:' Gender and the Structures of Constraint. London: Routledge</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Fong, Monica 1993. The Role of Women in Rebuilding the Russian Economy. Studies of Economics in Transformation 10 Washington, D.C.: World Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Goetz. Anne Marie. and Rina Sen Gupta. 1994 'Who Takes the Credit'? Gender. Power and Control over Loan Use in Rural Credit Programmes in Bangladesh." Draft University of Sussex, Institute of Development Studies. Brighton, U.K.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hart, Gillian 1986 Power Labor and Livelihood: Processes of Change in Rural Java San Francisco: University of Berkeley Press.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Heise, Lori. 1993 ''Violence Against Women: The Missing Agenda." In Marge Koblinsky. Judith Timyan. and Jill Gay. eds.. The Health of Women A Global</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Perspective Boulder. Colo: Westview</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Heise. Lori. Jacqueline Pitanguy, and Adrienne German. 1994 Violence Against Women The Hidden Health Burden World Bank Discussion Paper 255. Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Herz, Barbara. and Shahidur Khandker. 1991 Women Work Education and Welfare in Peru. World Bank Discussion Paper 116. Washington. D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Herz Barbara, K Subbarao, Masooma Habib. and Laura Raney 1991 Letting Girls Lea/n. Promising Education. World Bank Discussion Paper 1. Washington, D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hoddinot, John, and Lawrence Haddad 1992. Does Female Income Insentience Household Expenditures  Evidence from C&ocirc;te d'Ivoire Trinity College. Oxford University, Oxford. U K</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Holt, Sharon. 1995 Gender and Property Rights: Women and Agrarian Reform in Russia and Moldova.' World Bank, Europe and Central Asia Region, Washington, D C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">&nbsp;</P>
+<P ALIGN="JUSTIFY">Horton, Susan 1994. "Women and Industrialization in Asia" University of Toronto. Institute for Policy Analysis</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Hosken, Fran P., ed 1992. Women's International Network News 18(4).</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">ILO/INSTRAW. 1985. Women in Economic Activity: A Global Statistical Survey 1950-2000 Geneva</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jackson. Cecile 1993 "Doing What Comes Naturally? Women and Environment in Development." World Development 21 (12): 1947-63.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Johansen. Frida 1993 Poverty Reduction in East Asia. World Bank Discussion Paper 203. Washington. D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Jurisman. Clara, and Araceli Moreno. 1990. ''Women, Labour and Crisis: Mexico." Prepared for International Center for Research on Women (ICRW) project on Weathering Economic Crises: Women's Economic Responses to Recession in Latin America and the Caribbean. ICRW, Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kalima Rose. 1992. Where Women are Leaders The Sewa Movement in India. London Zed Press</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Khandker. Shahidur R. and Osman H. Chowdhury 1994 "Targeted Credit Programs and Rural Poverty in Bangladesh." World Bank, Education and Social Policy Department. Washington, D.C. and Bangladesh Institute of Development Studies, Dhaka.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Khandker, Shahidur R. and Baqui Khalily. 1995. "Designing a Sustainable Poverty Alleviation Program: The BRAC Strategy in Bangladesh." World Bank, Education and Social Policy Department. Washington, D.C., and Bangladesh Institute of Development Studies, Dhaka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Khandker, Shahidur R. Baqui Khalily. and Zahed Khan 1993 ''Sustainability of Grameen Bank: What Do We Know ? World Bank. Education and Social Policy Department. Washington. D C, and Bangladesh Institute of Development Studies, Dhaka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Khandker, Shahidur R., Victor Lavy, and D Filmer. 1994. Schooling and Cognitive in World Bank Discussion Paper 264. Washington. </P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kumar, Shubh K. and David Hotchkiss. 1988 Consequences of Deforestation for Women's Time Allocation Agricultural Production and Nutrition in Hill Areas of Nepal International Food Policy Research Institute Research Report 69 Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Kuzoets. Simon. 1955 Economic Growth and Income Inequalities." American Economic Review 45 (March): 1-28.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Lavy, Victor. 1992. Investment in Human Capital Schooling Supply in Rural Ghana Living Standards Measurement Study Working Paper 93 Washington, D C: World Bank.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">MacDonald, Martha. 1994. 'Panel Presentation at the Gender Symposium" World Bank. Poverty and Social Policy Department, Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Manser Marilyn, and Murray Brown 1980 "Marriage and Household Decision making: A Bargaining Analysis " International Economic Review 21:11 44</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">McElroy, Marjorie, and Mary Jean Homey. 1981. "Nash-bargained Household Decisions: Towards a Generalisation of the Theory of Demand" International</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Economic Review 22 (June):333 49</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moock, Peter R 1976 "The Efficiency of Women as Farm Managers: Kenya." American an Journal of Agricultural Economic 58(5):831-35.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Moser, Caroline O. 1992 "Adjustment from Below: Low-income Women, Time and the Triple Role in Guayaquil. Ecuador" In Haleh Ashar and Carolynne Dennis, eds., Women and Adjustment Policies in the Third World. New York: St. Martin Press</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">1994. "Urban Poverty and Social Policy in the Context of Adjustment" World Bank, Urban Development Division, Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Mwabu, Germano. 1994 "Household Composition and Expenditures on Human Capital Inputs in Kenya" Presented at Northeast Universities Development Conference, Economic Growth Center Yale University, New Haven, Conn</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Newell, Andrew and Barry Reilly 1994. "Pine Gender Wage Gap in Russia. ' World Bank, Europe and Central Asia Country Department 3, Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Pitt, Mark, and Shahidur Khandker. 1995 "Household and Intrahousehold Impacts of the Grameen Bank and Similar Targeted Credited Programs in Bangladesh " World Bank, Education and Social Policy Department, Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Population Reference Bureau 1994. The Wood'. Youth 1994 A Special Focus on Reproductive Health Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Psacharopoulos George 1994. "Returns to Investment in Education: A Global Up-date ' World Development 22(9):1325 43</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Psacharopoulos. George, and Zafiris Tzannatos. 1992 Women's Employment and PUN in Latin America Overview and Methodology. A World Bank Regional and Sectoral Study Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Agnes. 1994. ''Improving Women's Agricultural Productivity as Farmers and Workers." Education and Social Policy Department Discussion Paper 37. World Bank, Washington. D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rahrnan. Rushidan I. and Shahidur Khandker 1994 "Role of Targeted Credit Programs in Promoting Employment and Productivity of the Poor in Bangladesh." World Bank, Education and Social Policy Department. Washington, D.C. and Bangladesh Institute of Development Studies. Dhaka</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rhyne, Elisabeth. and Sharon Holt 1994 ''Women in Finance and Enterprise Development'' Education and Social Policy Department Discussion Paper 40. World Bank. Washington, D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Rosenzweig, Mark. and T. Paul Schultz. 1982 'Market Opportunities. Genetic Endowments, and Intrafamily Resource Distribution: Child Survival in Rural India'' American an Economic Review 72:4:803-15.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">. 1987. 'Fertility and Investments in Human Capital: Estimates of the Consequences of Imperfect Fertility Control in Malaysia.' Journal of Econometrics 36: 163-84</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Saito, Katrine, and Daphne Spurlirio 1992 Developing Agricultural Extension to/ Women Farmers World Bank Discussion Paper 156 Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Scales, Ann 1986 "The Emergence of Feminist Jurisprudence'' Yale Law Journal 95(7): 1373-1403.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schuler, Margaret, ed. 1986 Empowerment and the Law Strategies of Third World Women  Washington, D.C.: OEF</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schuler, Margaret. and Sakuntala Kadirgamar-Rajasingilam. eds 1992 Legal Literary. A TOOL for Women's Empowerment New York: United Nations Development Fund for Women (UNIFEM)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Schultz. T. Paul 1988 ''Education Investments and Returns'' In Hollis Chenery and T.R. Srinivasan. eds. Handbook of Development Economics Amsterdam: North land.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sedlacek, Guilhemie, Leah Gutierrez, and Amit Mohindra 1993. "Women in the Labor Market" World Bank. Education and Social Policy Department Washington, D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sen, Amartya 1990 'More Than One Hundred Million Women Are Missing: Women's Survival as a Development Problem." New York Review of Books (December 20):61-66.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Sivard, R L 1985. Women: A World Survey. Washington, D.C.: World Priorities</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Stewart, Sheelagh. 1992. ''Working the System: Sensitizing the Police to the Plight of Women " In Margaret Schuler. ed. Freedom from Violence e: Women Strategies from around the World. New York: United Nations Development Fund for Women (UNIFEM)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Subbarao Kalanidlli. and Kene l Ezemenari Forthcoming "Transition. Poverty and Social Assistance in Mongolia.'' World Bank. Education and Social Policy Department Washington, D C</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Subbarao Kalanidhi. and Laura Raney 1993 Social Gains from Female Education: A Cross-National Stud!. World Bank Discussion Paper 194. Washington! D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Summers, Lawrence H. 1994 Investing in All the People Education Women in Developing Countries ED' Seminar Paper 45 Washington, D.C: World Bank</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Thomas, Duncan 1990a "Household Resources and Child Health in Zimbabwe." Working Paper. Yale University, Economic Grow Center, New Haven, Conn.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">. 1990b Intrahousehold Resource Allocation: An Inferential Approach of Human Resources 25(4):635-64.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">. 1991 Gender Differences in household Resource Allocation. Living Standards Measurement Study Working Paper 79 Washington. D C: World Bank</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">. 1993. "The Distribution of Income and Expenditure within the Household." A Annals of Economics and Statistic 29: 109-35.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tibaijuka, Anna 1994 ''Cost of Differential Gender Roles in African Agriculture: A Case Study of Smallholder Banana-Coffee Fames in the Kagera Region, Tanzania." Journal of Agricultural Economics (U K) 45(1):69-81</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Toubia, Nahid 1993. Female Genital Mutilation: A Call for Global Action. New York: United Nations</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Tzannatos, Zafiris 1995. "Growths, Adjustment, and the Labor Market: Effects on Women Workers." World Bank, Poverty and Social Policy Department, Washington. D.C.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNESCO (United Nations Educational, Scientific, and Cultural Organization). 1991. 1991. Paris</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">. 1993b Trends and Projections of Enrollment by Level of Education by Age and Sex, 1960-2025. Paris</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNICEF (United Nations Children's Fund! 1993. The Progress of Nations. New York</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">UNIDO (United Nations Industrial Development Organization). 1993 11 Women in Manu</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Other Recent Development in Practice Books</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Priorities and Strategies for Education: A World Bank Review (also available in French and Spanish)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Better Urban Services: Finding the Right Incentives (also available in French and Spanish)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Strengthening the Effectiveness of Aid: Lessons for Donors</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Enriching Lives: Overcoming Vitamin and Mineral Malnutrition in Developing Countries (also available in French and Spanish)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">A New Agenda for Women's Health and Nutrition (also available in French)</P>
+<P ALIGN="JUSTIFY">Population and Development: Implications for the World Bank</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">East Asia's Trade and Investment: Regional and Global Gains from Liberalization</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Governance: The World Bank's Experience</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Higher Education: The Lessons of Experience (also available in French and Spanish)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Better Health in Africa: Experience and Lessons Learned (also available in French)</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Argentina's Privatization Program: Experience, Issues, and Lessons Sustaining Rapid Development in East Asia and the Pacific</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">THE WORLD BANK A partner in strengthening economies and expanding markets to improve the quality of life for people everywhere, especially the poorest</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Gender equality is not only a matter of social justice but also good economics. It is of foremost importance to women's wellbeing and development. Discrimination means losses in productivity and lower welfare of women, their families, and society at large.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">Although the gender gap is narrowing in education, health, and many other areas, women are still less educated than men, work more hours, and are paid less. The reasons why gender disparities persist are complex, having to do with social and institutional norms, relationships within households, and even lack of information about the benefits of educating and employing women. Despite the weight of social and cultural factors, public policy can influence women's status and well-being. Governments have a leading role in widening the opportunities available to women and extending the services that are vitally important to them.</P>
+<P ALIGN="JUSTIFY"></P>
+<P ALIGN="JUSTIFY">This report outlines what governments and development agencies can do to work toward greater gender equality- one of the best investments a society can make. Public policy can affect investments in health, education, and infrastructure through laws and regulations. It can also affect land ownership, financial services, and access to employment. Not least important, public  policies can affect macroeconomic performance and create a favorable climate for economic development.</P>
+<P ALIGN="JUSTIFY"></P></FONT>
+<!--
+</Section>
+</Section>
+-->
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/metadata/dls.mds
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/metadata/dls.mds	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/metadata/dls.mds	(revision 10506)
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param family      The namespace of this metadata set.                           -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param namespace   The abbreviated namespace of this metadata set.               -->
+  <!ELEMENT MetadataSet (Element+)>
+  <!ATTLIST MetadataSet
+				contact     CDATA #REQUIRED
+				creator     CDATA #REQUIRED
+            family      CDATA #REQUIRED
+				lastchanged CDATA #REQUIRED
+				namespace   CDATA #REQUIRED>
+
+  <!-- The name of a metadata set. Is language specific. -->
+  <!ELEMENT Name (#PCDATA)>
+  <!ATTLIST Name
+            language CDATA "en">
+
+  <!-- The description of a metadata set. Is language specific. -->
+  <!ELEMENT Description (#PCDATA)>
+  <!ATTLIST Description
+            language CDATA "en">
+
+  <!-- An element in the metadata set. -->
+  <!ELEMENT Element (Attribute*,OptionList?)>
+  <!ATTLIST Element
+				hierarchy  CDATA "false"
+            name       CDATA #REQUIRED
+				occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+]>
+<MetadataSet contact="nzdl.org" creator="New Zealand Digital Libraries Project: Greenstone" family="Development Library Subset" lastchanged="Tue Jun 04 10:35:30 2002 - jmt12 on blackbird" namespace="dls">
+    <Name language="en">Development Library Subset Example Metadata</Name>
+    <Description language="en">A metadata set file for use in The Gatherer, created from original metadata found within the Development Library Subset.</Description>
+    <Element name="Title" occurances="11" remember_values="true">
+        <Attribute language="en" name="comment">Title</Attribute>
+        <Attribute language="en" name="definition">The title of this resource.</Attribute>
+        <Attribute language="en" name="identifier">Title</Attribute>
+        <Attribute name="version">1.0</Attribute>
+    </Element>
+    <Element hierarchy="true" name="Organization" occurances="11" remember_values="true">
+        <Attribute language="en" name="comment">Organization.</Attribute>
+        <Attribute language="en" name="definition">The organization responsible for producing this resource.</Attribute>
+        <Attribute language="en" name="identifier">Organization</Attribute>
+        <Attribute name="version">1.0</Attribute>
+    </Element>
+    <Element hierarchy="true" name="Subject" occurances="17" remember_values="true">
+        <Attribute language="en" name="comment">Currently uses a hierarchy.</Attribute>
+        <Attribute language="en" name="definition">The subject of this resource.</Attribute>
+        <Attribute language="en" name="identifier">Subject And Keywords</Attribute>
+        <Attribute name="version">1.0</Attribute>
+    </Element>
+    <Element hierarchy="true" name="Keyword" occurances="6" remember_values="true">
+        <Attribute language="en" name="comment">Informal.</Attribute>
+        <Attribute language="en" name="definition">A more specific indication of what the resource can be used for.</Attribute>
+        <Attribute language="en" name="identifier">Keyword</Attribute>
+        <Attribute name="version">1.0</Attribute>
+    </Element>
+    <Element name="Language" occurances="11" remember_values="true">
+        <Attribute language="en" name="comment">Language.</Attribute>
+        <Attribute language="en" name="definition">The language of this resource.</Attribute>
+        <Attribute language="en" name="identifier">Language</Attribute>
+        <Attribute name="version">1.0</Attribute>
+    </Element>
+    <Element hierarchy="true" name="AZList" occurances="11" remember_values="true">
+        <Attribute language="en" name="comment">Not the same as an AZList classifier.</Attribute>
+        <Attribute language="en" name="definition">A customizable AZList based on document titles.</Attribute>
+        <Attribute language="en" name="identifier">AZList</Attribute>
+        <Attribute name="version">1.0</Attribute>
+    </Element>
+</MetadataSet>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/metadata/ex.mds
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/metadata/ex.mds	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/metadata/ex.mds	(revision 10506)
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE MetadataSet [
+
+  <!-- The outer tag of any metadata set. Contains some number of elements.             -->
+  <!-- @param contact     A contact address for the creator.                            -->
+  <!-- @param creator     The name of the entity resposibly for this set.               -->
+  <!-- @param family      The name of this sets family.                                 -->
+  <!-- @param lastchanged The full date, user name and machine name of the last editor. --> 
+  <!--   uses the form:                                                                 -->
+  <!--   Day Mon(th) dd hh:mm:ss yyyy '-' <username> on <machine>                       -->
+  <!-- @param namespace   The namespace of this metadata set.                           -->
+  <!ELEMENT MetadataSet ((Name|Description|Element)+)>
+  <!ATTLIST MetadataSet
+				contact     CDATA #REQUIRED
+				creator     CDATA #REQUIRED
+				description CDATA #REQUIRED
+            family      CDATA #REQUIRED
+				lastchanged CDATA #REQUIRED
+            name        CDATA #REQUIRED
+				namespace   CDATA #REQUIRED>
+
+  <!-- The name of a metadata set. Is language specific. -->
+  <!ELEMENT Name (#PCDATA)>
+  <!ATTLIST Name
+            language CDATA "en">
+
+  <!-- The description of a metadata set. Is language specific. -->
+  <!ELEMENT Description (#PCDATA)>
+  <!ATTLIST Description
+            language CDATA "en">
+
+  <!-- An element in the metadata set. -->
+  <!ELEMENT Element (Attribute*,OptionList?)>
+  <!ATTLIST Element
+            name       CDATA #REQUIRED
+				occurances CDATA "0">
+
+  <!-- Each element has several attribute children. -->
+  <!ELEMENT Attribute (#PCDATA)>
+  <!ATTLIST Attribute
+            name CDATA #REQUIRED>
+
+  <!-- For listing predefined values for this element. -->
+  <!ELEMENT OptionList (Value+)>
+  <!ATTLIST OptionList
+            restricted (true|false) "false">
+]>
+<MetadataSet contact="nzdl.org" creator="New Zealand Digital Libraries Project: Greenstone" family="Extracted Greenstone" lastchanged="Tue May 20 10:30:32 2003 - jmt12 on narya" namespace="ex">
+    <Name language="en">Extracted Greenstone Metadata 1.0</Name>
+    <Description language="en">This document is the reference description, version 1.0 of the automatically extracted Greenstone Metadata Element Set.</Description>
+    <Element name="Encoding">
+        <Attribute language="en" name="comment">Not always available.</Attribute>
+        <Attribute language="en" name="definition">The encoding of the imported document as extracted by Greenstone.</Attribute>
+        <Attribute language="en" name="identifier">Encoding</Attribute>
+    </Element>
+    <Element name="Language">
+        <Attribute language="en" name="comment">Not always available.</Attribute>
+        <Attribute language="en" name="definition">The language of the imported document as extracted by Greenstone.</Attribute>
+        <Attribute language="en" name="identifier">Language</Attribute>
+    </Element>
+    <Element name="Source">
+        <Attribute language="en" name="comment">Hidden in the Librarian Interface as it already shown by the various file trees.</Attribute>
+        <Attribute language="en" name="definition">The filename of the document imported by Greenstone.</Attribute>
+        <Attribute language="en" name="identifier">Source</Attribute>
+    </Element>
+    <Element name="Title">
+        <Attribute language="en" name="comment">Not always available.</Attribute>
+        <Attribute language="en" name="definition">The title of the imported document as extracted by Greenstone.</Attribute>
+        <Attribute language="en" name="identifier">Title</Attribute>
+    </Element>
+</MetadataSet>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/demo/metadata/profile.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/demo/metadata/profile.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/demo/metadata/profile.xml	(revision 10506)
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Profiles [
+<!ELEMENT Profiles (Action*)>
+<!ELEMENT Action (#PCDATA)>
+<!ATTLIST Action
+                source     CDATA #REQUIRED
+                target     CDATA "">
+]>
+<Profiles/>
Index: /tags/gsdl-2_61-distribution/gsdl/collect/modelcol/etc/collect.cfg
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/collect/modelcol/etc/collect.cfg	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/collect/modelcol/etc/collect.cfg	(revision 10506)
@@ -0,0 +1,18 @@
+creator       **creator**
+maintainer    **maintainer**
+public        **public**
+
+indexes        document:text document:Title document:Source
+defaultindex   document:text
+
+**plugins**
+
+classify       AZList -metadata Title
+classify       AZList -metadata Source
+
+collectionmeta collectionname    "**title**"
+collectionmeta iconcollection    ""
+collectionmeta collectionextra   "**about**"
+collectionmeta .document:text    "text"
+collectionmeta .document:Title  "titles"
+collectionmeta .document:Source  "filenames"
Index: /tags/gsdl-2_61-distribution/gsdl/config.guess
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/config.guess	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/config.guess	(revision 10506)
@@ -0,0 +1,1298 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+#   Free Software Foundation, Inc.
+
+timestamp='2001-07-12'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script.
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int dummy(){}" > $dummy.c ;
+	for c in cc gcc c89 ; do
+	  ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ;
+	  if test $? = 0 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	rm -f $dummy.c $dummy.o $dummy.rel ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# Netbsd (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	# Determine the machine/vendor (is the vendor relevant).
+	case "${UNAME_MACHINE}" in
+	    amiga) machine=m68k-unknown ;;
+	    arm32) machine=arm-unknown ;;
+	    atari*) machine=m68k-atari ;;
+	    sun3*) machine=m68k-sun ;;
+	    mac68k) machine=m68k-apple ;;
+	    macppc) machine=powerpc-apple ;;
+	    hp3[0-9][05]) machine=m68k-hp ;;
+	    ibmrt|romp-ibm) machine=romp-ibm ;;
+	    *) machine=${UNAME_MACHINE}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE}" in
+	    i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep __ELF__ >/dev/null
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit 0 ;;
+    alpha:OSF1:*:*)
+	if test $UNAME_RELEASE = "V4.0"; then
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+	fi
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	cat <<EOF >$dummy.s
+	.data
+\$Lformat:
+	.byte 37,100,45,37,120,10,0	# "%d-%x\n"
+
+	.text
+	.globl main
+	.align 4
+	.ent main
+main:
+	.frame \$30,16,\$26,0
+	ldgp \$29,0(\$27)
+	.prologue 1
+	.long 0x47e03d80 # implver \$0
+	lda \$2,-1
+	.long 0x47e20c21 # amask \$2,\$1
+	lda \$16,\$Lformat
+	mov \$0,\$17
+	not \$1,\$18
+	jsr \$26,printf
+	ldgp \$29,0(\$26)
+	mov 0,\$16
+	jsr \$26,exit
+	.end main
+EOF
+	eval $set_cc_for_build
+	$CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+	if test "$?" = 0 ; then
+		case `./$dummy` in
+			0-0)
+				UNAME_MACHINE="alpha"
+				;;
+			1-0)
+				UNAME_MACHINE="alphaev5"
+				;;
+			1-1)
+				UNAME_MACHINE="alphaev56"
+				;;
+			1-101)
+				UNAME_MACHINE="alphapca56"
+				;;
+			2-303)
+				UNAME_MACHINE="alphaev6"
+				;;
+			2-307)
+				UNAME_MACHINE="alphaev67"
+				;;
+		esac
+	fi
+	rm -f $dummy.s $dummy
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit 0 ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit 0;;
+    amiga:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit 0 ;;
+    arc64:OpenBSD:*:*)
+	echo mips64el-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    arc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    hkmips:OpenBSD:*:*)
+	echo mips-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    pmax:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sgi:OpenBSD:*:*)
+	echo mips-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit 0 ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit 0 ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    i86pc:SunOS:5.*:*)
+	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit 0 ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit 0 ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    atari*:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    sun3*:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mac68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+	echo m88k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit 0 ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit 0 ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	eval $set_cc_for_build
+	$CC_FOR_BUILD $dummy.c -o $dummy \
+	  && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+	  && rm -f $dummy.c $dummy && exit 0
+	rm -f $dummy.c $dummy
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit 0 ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit 0 ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit 0 ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit 0 ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit 0 ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit 0 ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+	exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit 0 ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		eval $set_cc_for_build
+		$CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+		rm -f $dummy.c $dummy
+		echo rs6000-ibm-aix3.2.5
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit 0 ;;
+    *:AIX:*:[45])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+              case "${HPUX_REV}" in
+                11.[0-9][0-9])
+                  if [ -x /usr/bin/getconf ]; then
+                    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+                        esac ;;
+                    esac
+                  fi ;;
+              esac
+              if [ "${HP_ARCH}" = "" ]; then
+              sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+	eval $set_cc_for_build
+	(CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+	if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+	rm -f $dummy.c $dummy
+	fi ;;
+	esac
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    3050*:HI-UX:*:*)
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	eval $set_cc_for_build
+	$CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+	rm -f $dummy.c $dummy
+	echo unknown-hitachi-hiuxwe2
+	exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit 0 ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit 0 ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit 0 ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit 0 ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit 0 ;;
+    hppa*:OpenBSD:*:*)
+	echo hppa-unknown-openbsd
+	exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:*:*:*)
+	echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*T3D:*:*:*)
+	echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY-2:*:*:*)
+	echo cray2-cray-unicos
+        exit 0 ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    hp300:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:FreeBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit 0 ;;
+    *:OpenBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+	exit 0 ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit 0 ;;
+    i*:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit 0 ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i386-pc-interix
+	exit 0 ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit 0 ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit 0 ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    *:GNU:*:*)
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit 0 ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit 0 ;;
+    arm*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux
+	exit 0 ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    mips:Linux:*:*)
+	case `sed -n '/^byte/s/^.*: \(.*\) endian/\1/p' < /proc/cpuinfo` in
+	  big)    echo mips-unknown-linux-gnu && exit 0 ;;
+	  little) echo mipsel-unknown-linux-gnu && exit 0 ;;
+	esac
+	;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit 0 ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev67 ;;
+        esac
+	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit 0 ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit 0 ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit 0 ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	ld_supported_targets=`cd /; ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit 0 ;;		
+	  coff-i386)
+		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+		exit 0 ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit 0 ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+#  if __GLIBC__ >= 2
+    printf ("%s-pc-linux-gnu\n", argv[1]);
+#  else
+    printf ("%s-pc-linux-gnulibc1\n", argv[1]);
+#  endif
+# else
+   printf ("%s-pc-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+  printf ("%s-pc-linux-gnuaout\n", argv[1]);
+#endif
+  return 0;
+}
+EOF
+	eval $set_cc_for_build
+	$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+	rm -f $dummy.c $dummy
+	test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit 0 ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit 0 ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit 0 ;;
+    i*86:*:5:[78]*)
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit 0 ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit 0 ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit 0 ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+	echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit 0 ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit 0 ;;
+    M68*:*:R3V[567]*:*)
+	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit 0 ;;
+    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                           # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit 0 ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit 0 ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit 0 ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit 0 ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit 0 ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Darwin:*:*)
+	echo `uname -p`-apple-darwin${UNAME_RELEASE}
+	exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	if test "${UNAME_MACHINE}" = "x86pc"; then
+		UNAME_MACHINE=pc
+	fi
+	echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+	exit 0 ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit 0 ;;
+    NSR-[KW]:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit 0 ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit 0 ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit 0 ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit 0 ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit 0 ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit 0 ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit 0 ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit 0 ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+eval $set_cc_for_build
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit 0 ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit 0 ;;
+    c34*)
+	echo c34-convex-bsd
+	exit 0 ;;
+    c38*)
+	echo c38-convex-bsd
+	exit 0 ;;
+    c4*)
+	echo c4-convex-bsd
+	exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+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`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
Index: /tags/gsdl-2_61-distribution/gsdl/config.h.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/config.h.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/config.h.in	(revision 10506)
@@ -0,0 +1,211 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+#ifndef _GSDL_CONFIG_H
+#define _GSDL_CONFIG_H
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro.  */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function.  */
+#undef HAVE_VPRINTF
+
+/* Define if on MINIX.  */
+#undef _MINIX
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+
+/* Define if you don't want to use long long's with GCC */
+#undef DISABLE_LONG_LONG
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define FASTCGI if needsbe */
+#undef USE_FASTCGI
+
+/* Define USE_CORBA if needsbe */
+#undef USE_CORBA
+
+/* Define MICO_DIR if needsbe */
+#undef MICO_DIR
+
+/* Define MICO_VERSION if required */
+#undef MICO_VERSION
+
+/* Define if you have the ftime function.  */
+#undef HAVE_FTIME
+
+/* Define if you have the ftruncate function.  */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the getpagesize function.  */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the mallinfo function.  */
+#undef HAVE_MALLINFO
+
+/* Define if you have the select function.  */
+#undef HAVE_SELECT
+
+/* Define if you have the setbuffer function.  */
+#undef HAVE_SETBUFFER
+
+/* Define if you have the strcasecmp function.  */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if you have the strstr function.  */
+#undef HAVE_STRSTR
+
+/* Define if you have the strtol function.  */
+#undef HAVE_STRTOL
+
+/* Define if you have the times function.  */
+#undef HAVE_TIMES
+
+/* Define if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define if you have the <crypt.h> header file.  */
+#undef HAVE_CRYPT_H
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <memory.h> header file.  */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <ndir.h> header file.  */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/procfs.h> header file.  */
+#undef HAVE_SYS_PROCFS_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the crypt library (-lcrypt).  */
+#undef HAVE_LIBCRYPT
+
+/* Define if you have the g library (-lg).  */
+#undef HAVE_LIBG
+
+/* Define if you have the gdbm library (-lgdbm).  */
+#undef HAVE_LIBGDBM
+
+/* Define if you have the m library (-lm).  */
+#undef HAVE_LIBM
+
+/* Define if you have the stdc++ library (-lstdc++).  */
+#undef HAVE_LIBSTDC__
+
+/* Define if you have gettext (eg glibc) */
+#undef ENABLE_NLS
+
+#endif /* _GSDL_CONFIG_H */
Index: /tags/gsdl-2_61-distribution/gsdl/config.sub
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/config.sub	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/config.sub	(revision 10506)
@@ -0,0 +1,1375 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+#   Free Software Foundation, Inc.
+
+timestamp='2001-06-08'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis)
+		os=
+		basic_machine=$1
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc \
+	        | arm | arme[lb] | arm[bl]e | armv[2345] | armv[345][lb] | strongarm | xscale \
+		| pyramid | mn10200 | mn10300 | tron | a29k \
+		| 580 | i960 | h8300 \
+		| x86 | ppcbe | mipsbe | mipsle | shbe | shle \
+		| hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+		| hppa64 \
+		| alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
+		| alphaev6[78] \
+		| we32k | ns16k | clipper | i370 | sh | sh[34] \
+		| powerpc | powerpcle \
+		| 1750a | dsp16xx | pdp10 | pdp11 \
+		| mips16 | mips64 | mipsel | mips64el \
+		| mips64orion | mips64orionel | mipstx39 | mipstx39el \
+		| mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
+		| mips64vr5000 | mips64vr5000el | mcore | s390 | s390x \
+		| sparc | sparclet | sparclite | sparc64 | sparcv9 | sparcv9b \
+		| v850 | c4x \
+		| thumb | d10v | d30v | fr30 | avr | openrisc | tic80 \
+		| pj | pjl | h8500 | z8k)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	# FIXME: clean up the formatting here.
+	vax-* | tahoe-* | i*86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
+	      | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | c[123]* \
+	      | arm-*  | armbe-* | armle-* | armv*-* | strongarm-* | xscale-* \
+	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+	      | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
+	      | xmp-* | ymp-* \
+	      | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* \
+	      | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
+	      | hppa2.0n-* | hppa64-* \
+	      | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
+	      | alphaev6[78]-* \
+	      | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
+	      | clipper-* | orion-* \
+	      | sparclite-* | pdp10-* | pdp11-* | sh-* | sh[34]-* | sh[34]eb-* \
+	      | powerpc-* | powerpcle-* | sparc64-* | sparcv9-* | sparcv9b-* | sparc86x-* \
+	      | mips16-* | mips64-* | mipsel-* \
+	      | mips64el-* | mips64orion-* | mips64orionel-* \
+	      | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
+	      | mipstx39-* | mipstx39el-* | mcore-* \
+	      | f30[01]-* | f700-* | s390-* | s390x-* | sv1-* | t3e-* \
+	      | [cjt]90-* \
+	      | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
+	      | thumb-* | v850-* | d30v-* | tic30-* | tic80-* | c30-* | fr30-* \
+	      | bs2000-* | tic54x-* | c54x-* | x86_64-* | pj-* | pjl-*)
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	cray2)
+		basic_machine=cray2-cray
+		os=-unicos
+		;;
+	[cjt]90)
+		basic_machine=${basic_machine}-cray
+		os=-unicos
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mipsel*-linux*)
+		basic_machine=mipsel-unknown
+		os=-linux-gnu
+		;;
+	mips*-linux*)
+		basic_machine=mips-unknown
+		os=-linux-gnu
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	mmix*)
+		basic_machine=mmix-knuth
+		os=-mmixware
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+        pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pentium | p5 | k5 | k6 | nexgen)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2)
+		basic_machine=i686-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+	        ;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+	        ;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sparclite-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=t3e-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	windows32)
+		basic_machine=i386-pc
+		os=-windows32-msvcrt
+		;;
+	xmp)
+		basic_machine=xmp-cray
+		os=-unicos
+		;;
+        xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	mips)
+		if [ x$os = x-linux-gnu ]; then
+			basic_machine=mips-unknown
+		else
+			basic_machine=mips-mips
+		fi
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh3 | sh4)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv9 | sparcv9b)
+		basic_machine=sparc-sun
+		;;
+        cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	c4x*)
+		basic_machine=c4x-none
+		os=-coff
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -os2*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto*)
+		os=-nto-qnx
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-ns2 )
+	        os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+        -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+	        os=-mint
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+	pdp10-*)
+		os=-tops20
+		;;
+        pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+        *-gould)
+		os=-sysv
+		;;
+        *-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+        *-sgi)
+		os=-irix
+		;;
+        *-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-vxsim* | -vxworks*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
Index: /tags/gsdl-2_61-distribution/gsdl/configtest.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/configtest.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/configtest.pl	(revision 10506)
@@ -0,0 +1,1 @@
+print $]
Index: /tags/gsdl-2_61-distribution/gsdl/configure
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/configure	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/configure	(revision 10506)
@@ -0,0 +1,8424 @@
+#! /bin/sh
+# 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="lib/text_t.h"
+# 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_subdirs_all="$ac_subdirs_all packages"
+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 PACKAGE VERSION USE_FASTCGI USE_LANGACTION USE_CORBA MICO_DIR USE_Z3950 CFLAGS CC LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX AWK YACC build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB MICO_VER CPP EGREP U ANSI2KNR ALLOCA LIBOBJS STATIC GDBM_LIBPATH GDBM_INCLUDE gsdlos MODULEDIRS subdirs 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_CXX_set=${CXX+set}
+ac_env_CXX_value=$CXX
+ac_cv_env_CXX_set=${CXX+set}
+ac_cv_env_CXX_value=$CXX
+ac_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_env_CXXFLAGS_value=$CXXFLAGS
+ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_cv_env_CXXFLAGS_value=$CXXFLAGS
+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
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+  --target=TARGET   configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-corba          Enable CORBA support
+  --enable-z3950          Enable Z39.50 client support
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-micodir          Use installed MICO directory
+  --with-gdbm=dir         Use local gdbm library and headers
+  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz
+  --with-regex            use older regex in lieu of GNU rx for matching
+
+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>
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+          ac_config_headers="$ac_config_headers config.h"
+
+
+PACKAGE=gsdl
+VERSION=2.1
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+
+
+
+USE_FASTCGI=0
+if test USE_FASTCGI = 1; then
+cat >>confdefs.h <<\_ACEOF
+#define USE_FASTCGI 1
+_ACEOF
+
+
+fi
+
+if test USE_LANGACTION = 1; then
+cat >>confdefs.h <<\_ACEOF
+#define USE_LANGACTION 1
+_ACEOF
+
+
+fi
+
+# Check whether --enable-corba or --disable-corba was given.
+if test "${enable_corba+set}" = set; then
+  enableval="$enable_corba"
+  USE_CORBA=1
+else
+  USE_CORBA=0
+fi;
+cat >>confdefs.h <<_ACEOF
+#define USE_CORBA $USE_CORBA
+_ACEOF
+
+
+
+
+# Check whether --with-micodir or --without-micodir was given.
+if test "${with_micodir+set}" = set; then
+  withval="$with_micodir"
+  MICO_DIR=$enableval
+else
+  MICO_DIR="default"
+fi;
+cat >>confdefs.h <<_ACEOF
+#define MICO_DIR "$MICO_DIR"
+_ACEOF
+
+
+
+# Check whether --enable-z3950 or --disable-z3950 was given.
+if test "${enable_z3950+set}" = set; then
+  enableval="$enable_z3950"
+  USE_Z3950=1
+else
+  USE_Z3950=0
+fi;
+if test USE_Z3950 = 1; then
+cat >>confdefs.h <<\_ACEOF
+#define USE_Z3950 $USE_Z3950
+_ACEOF
+
+
+fi
+
+
+# Check whether --with-gdbm or --without-gdbm was given.
+if test "${with_gdbm+set}" = set; then
+  withval="$with_gdbm"
+  gdbmdir=$withval
+fi;
+
+LDFLAGS=
+if test -z "$CFLAGS"; then
+CFLAGS=-O2
+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
+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_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+  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_CXX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # 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_CXX="$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
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  echo "$as_me:$LINENO: result: $CXX" >&5
+echo "${ECHO_T}$CXX" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+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_CXX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # 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_CXX="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+echo "${ECHO_T}$ac_ct_CXX" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$ac_ct_CXX" && break
+done
+test -n "$ac_ct_CXX" || ac_ct_CXX="g++"
+
+  CXX=$ac_ct_CXX
+fi
+
+
+# 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); }
+
+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_cxx_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_cxx_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_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6
+GXX=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cxx_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_cxx_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_cxx_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cxx_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+for ac_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_cxx_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_cxx_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
+
+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
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_AWK+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # 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_AWK="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$AWK" && break
+done
+
+for ac_prog in 'bison -y' byacc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_YACC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # 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_YACC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+  echo "$as_me:$LINENO: result: $YACC" >&5
+echo "${ECHO_T}$YACC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  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.
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+  { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+   { (exit 1); exit 1; }; }
+
+echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+  ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+  { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+   { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+  { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+  ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+  { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+echo "$as_me:$LINENO: checking target system type" >&5
+echo $ECHO_N "checking target system type... $ECHO_C" >&6
+if test "${ac_cv_target+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_target_alias=$target_alias
+test "x$ac_cv_target_alias" = "x" &&
+  ac_cv_target_alias=$ac_cv_host_alias
+ac_cv_target=`$ac_config_sub $ac_cv_target_alias` ||
+  { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_target" >&5
+echo "${ECHO_T}$ac_cv_target" >&6
+target=$ac_cv_target
+target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+# 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
+
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.make <<\_ACEOF
+all:
+	@echo 'ac_maketemp="$(MAKE)"'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftest.make
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+  SET_MAKE=
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; 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_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # 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_RANLIB="${ac_tool_prefix}ranlib"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; 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_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # 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_RANLIB="ranlib"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  RANLIB=$ac_ct_RANLIB
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+#moved CORBA MICO directory test to get version of MICO
+if test $USE_CORBA = 1; then
+
+if test $MICO_DIR = "default"; then
+#do something
+MICO_INC="-I packages/mico/mico/include"
+else
+#build the micotest program
+MICO_INC= ""
+if test $MICO_DIR != yes; then
+MICO_INC="-I $MICO_DIR"
+fi
+fi
+
+#get MICO_VER value
+sh -c "$CC -c micotest.cpp -o micotest.o $MICO_INC 2>&1" > /dev/null
+sh -c "$CC -o micotest micotest.o -lstdc++ 2>&1" > /dev/null
+MICO_VER=`./micotest` || MICO_VER=2.3.5
+sh -c "rm micotest"
+sh -c "rm micotest.o"
+
+#do test of MICO_VER
+if test MICO_VER != 0; then
+cat >>confdefs.h <<\_ACEOF
+#define MICO_VER 1
+_ACEOF
+
+
+fi
+#end USE_CORBA test
+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 AIX" >&5
+echo $ECHO_N "checking for AIX... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef _AIX
+  yes
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "yes" >/dev/null 2>&1; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+cat >>confdefs.h <<\_ACEOF
+#define _ALL_SOURCE 1
+_ACEOF
+
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest*
+
+
+echo "$as_me:$LINENO: checking for library containing strerror" >&5
+echo $ECHO_N "checking for library containing strerror... $ECHO_C" >&6
+if test "${ac_cv_search_strerror+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_strerror=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char strerror ();
+int
+main ()
+{
+strerror ();
+  ;
+  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
+  ac_cv_search_strerror="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_strerror" = no; then
+  for ac_lib in cposix; do
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char strerror ();
+int
+main ()
+{
+strerror ();
+  ;
+  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
+  ac_cv_search_strerror="-l$ac_lib"
+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_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_strerror" >&5
+echo "${ECHO_T}$ac_cv_search_strerror" >&6
+if test "$ac_cv_search_strerror" != no; then
+  test "$ac_cv_search_strerror" = "none required" || LIBS="$ac_cv_search_strerror $LIBS"
+
+fi
+
+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
+
+
+if test "${ac_cv_header_minix_config_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for minix/config.h" >&5
+echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6
+if test "${ac_cv_header_minix_config_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5
+echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking minix/config.h usability" >&5
+echo $ECHO_N "checking minix/config.h usability... $ECHO_C" >&6
+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 <minix/config.h>
+_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_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking minix/config.h presence" >&5
+echo $ECHO_N "checking minix/config.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <minix/config.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
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: minix/config.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: minix/config.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: minix/config.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: minix/config.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: minix/config.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: minix/config.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: minix/config.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: minix/config.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: minix/config.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: minix/config.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: minix/config.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: minix/config.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for minix/config.h" >&5
+echo $ECHO_N "checking for minix/config.h... $ECHO_C" >&6
+if test "${ac_cv_header_minix_config_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_minix_config_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5
+echo "${ECHO_T}$ac_cv_header_minix_config_h" >&6
+
+fi
+if test $ac_cv_header_minix_config_h = yes; then
+  MINIX=yes
+else
+  MINIX=
+fi
+
+
+if test "$MINIX" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define _POSIX_SOURCE 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _POSIX_1_SOURCE 2
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _MINIX 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for ${CC-cc} option to accept ANSI C" >&5
+echo $ECHO_N "checking for ${CC-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_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif
+
+int
+main ()
+{
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+  ;
+  return 0;
+}
+_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_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 conftest.$ac_ext
+done
+CFLAGS="$ac_save_CFLAGS"
+
+fi
+
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+
+echo "$as_me:$LINENO: checking for function prototypes" >&5
+echo $ECHO_N "checking for function prototypes... $ECHO_C" >&6
+if test "$ac_cv_prog_cc_stdc" != no; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+  cat >>confdefs.h <<\_ACEOF
+#define PROTOTYPES 1
+_ACEOF
+
+  U= ANSI2KNR=
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  U=_ ANSI2KNR=ansi2knr
+fi
+
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+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 ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this.  */
+  typedef int charset[2];
+  const charset x;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *ccp;
+  char **p;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  ccp = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++ccp;
+  p = (char**) ccp;
+  ccp = (char const *const *) p;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; };
+    struct s *b; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+  }
+#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_cv_c_const=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for off_t" >&5
+echo $ECHO_N "checking for off_t... $ECHO_C" >&6
+if test "${ac_cv_type_off_t+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 ((off_t *) 0)
+  return 0;
+if (sizeof (off_t))
+  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_off_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_off_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_off_t" >&5
+echo "${ECHO_T}$ac_cv_type_off_t" >&6
+if test $ac_cv_type_off_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define off_t long
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+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 ((size_t *) 0)
+  return 0;
+if (sizeof (size_t))
+  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_size_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6
+if test "${ac_cv_header_time+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 <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+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_header_time=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_time=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6
+if test $ac_cv_header_time = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5
+echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6
+if test "${ac_cv_struct_tm+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 <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm *tp; tp->tm_sec;
+  ;
+  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_struct_tm=time.h
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5
+echo "${ECHO_T}$ac_cv_struct_tm" >&6
+if test $ac_cv_struct_tm = sys/time.h; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TM_IN_SYS_TIME 1
+_ACEOF
+
+fi
+
+
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdio.h>
+
+int
+main ()
+{
+ FILE *rubbish = popen("yes", "r");
+  ;
+  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
+
+CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+echo "$as_me:$LINENO: checking for main in -lg" >&5
+echo $ECHO_N "checking for main in -lg... $ECHO_C" >&6
+if test "${ac_cv_lib_g_main+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lg  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+main ();
+  ;
+  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
+  ac_cv_lib_g_main=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_g_main=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_g_main" >&5
+echo "${ECHO_T}$ac_cv_lib_g_main" >&6
+if test $ac_cv_lib_g_main = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBG 1
+_ACEOF
+
+  LIBS="-lg $LIBS"
+
+fi
+ac_cv_lib_g=ac_cv_lib_g_main
+
+
+echo "$as_me:$LINENO: checking for main in -lm" >&5
+echo $ECHO_N "checking for main in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_main+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+main ();
+  ;
+  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
+  ac_cv_lib_m_main=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_m_main=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_main" >&5
+echo "${ECHO_T}$ac_cv_lib_m_main" >&6
+if test $ac_cv_lib_m_main = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+ac_cv_lib_m=ac_cv_lib_m_main
+
+
+echo "$as_me:$LINENO: checking for main in -lcrypt" >&5
+echo $ECHO_N "checking for main in -lcrypt... $ECHO_C" >&6
+if test "${ac_cv_lib_crypt_main+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+main ();
+  ;
+  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
+  ac_cv_lib_crypt_main=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_crypt_main=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_main" >&5
+echo "${ECHO_T}$ac_cv_lib_crypt_main" >&6
+if test $ac_cv_lib_crypt_main = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCRYPT 1
+_ACEOF
+
+  LIBS="-lcrypt $LIBS"
+
+fi
+ac_cv_lib_crypt=ac_cv_lib_crypt_main
+
+
+
+
+
+
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do
+  as_ac_Header=`echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5
+echo $ECHO_N "checking for $ac_hdr that defines DIR... $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.  */
+#include <sys/types.h>
+#include <$ac_hdr>
+
+int
+main ()
+{
+if ((DIR *) 0)
+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
+  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_hdr" | $as_tr_cpp` 1
+_ACEOF
+
+ac_header_dirent=$ac_hdr; break
+fi
+
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+  echo "$as_me:$LINENO: checking for library containing opendir" >&5
+echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6
+if test "${ac_cv_search_opendir+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_opendir=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char opendir ();
+int
+main ()
+{
+opendir ();
+  ;
+  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
+  ac_cv_search_opendir="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_opendir" = no; then
+  for ac_lib in dir; do
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char opendir ();
+int
+main ()
+{
+opendir ();
+  ;
+  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
+  ac_cv_search_opendir="-l$ac_lib"
+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_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5
+echo "${ECHO_T}$ac_cv_search_opendir" >&6
+if test "$ac_cv_search_opendir" != no; then
+  test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS"
+
+fi
+
+else
+  echo "$as_me:$LINENO: checking for library containing opendir" >&5
+echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6
+if test "${ac_cv_search_opendir+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+ac_cv_search_opendir=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char opendir ();
+int
+main ()
+{
+opendir ();
+  ;
+  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
+  ac_cv_search_opendir="none required"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+if test "$ac_cv_search_opendir" = no; then
+  for ac_lib in x; do
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char opendir ();
+int
+main ()
+{
+opendir ();
+  ;
+  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
+  ac_cv_search_opendir="-l$ac_lib"
+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_exeext conftest.$ac_ext
+  done
+fi
+LIBS=$ac_func_search_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5
+echo "${ECHO_T}$ac_cv_search_opendir" >&6
+if test "$ac_cv_search_opendir" != no; then
+  test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS"
+
+fi
+
+fi
+
+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
+
+
+
+
+
+
+
+
+
+
+for ac_header in fcntl.h limits.h sys/time.h unistd.h crypt.h string.h memory.h sys/procfs.h sys/stat.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  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
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+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
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_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
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+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
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+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
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdio.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "fread" >/dev/null 2>&1; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_FREAD_DECL 1
+_ACEOF
+
+fi
+rm -f conftest*
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdio.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "fgetc" >/dev/null 2>&1; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_FGETC_DECL 1
+_ACEOF
+
+fi
+rm -f conftest*
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/procfs.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "pr_brksize" >/dev/null 2>&1; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_PR_BRKSIZE 1
+_ACEOF
+
+fi
+rm -f conftest*
+
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+echo "$as_me:$LINENO: checking for working alloca.h" >&5
+echo $ECHO_N "checking for working alloca.h... $ECHO_C" >&6
+if test "${ac_cv_working_alloca_h+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 <alloca.h>
+int
+main ()
+{
+char *p = (char *) alloca (2 * sizeof (int));
+  ;
+  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
+  ac_cv_working_alloca_h=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_working_alloca_h=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_working_alloca_h" >&5
+echo "${ECHO_T}$ac_cv_working_alloca_h" >&6
+if test $ac_cv_working_alloca_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA_H 1
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for alloca" >&5
+echo $ECHO_N "checking for alloca... $ECHO_C" >&6
+if test "${ac_cv_func_alloca_works+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.  */
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+#  define alloca _alloca
+# else
+#  if HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   ifdef _AIX
+ #pragma alloca
+#   else
+#    ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+int
+main ()
+{
+char *p = (char *) alloca (1);
+  ;
+  return 0;
+}
+_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
+  ac_cv_func_alloca_works=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_alloca_works=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_alloca_works" >&5
+echo "${ECHO_T}$ac_cv_func_alloca_works" >&6
+
+if test $ac_cv_func_alloca_works = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ALLOCA 1
+_ACEOF
+
+else
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+# that cause trouble.  Some versions do not even contain alloca or
+# contain a buggy version.  If you still want to use their alloca,
+# use ar to extract alloca.o from them instead of compiling alloca.c.
+
+ALLOCA=alloca.$ac_objext
+
+cat >>confdefs.h <<\_ACEOF
+#define C_ALLOCA 1
+_ACEOF
+
+
+echo "$as_me:$LINENO: checking whether \`alloca.c' needs Cray hooks" >&5
+echo $ECHO_N "checking whether \`alloca.c' needs Cray hooks... $ECHO_C" >&6
+if test "${ac_cv_os_cray+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.  */
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "webecray" >/dev/null 2>&1; then
+  ac_cv_os_cray=yes
+else
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_os_cray" >&5
+echo "${ECHO_T}$ac_cv_os_cray" >&6
+if test $ac_cv_os_cray = yes; then
+  for ac_func in _getb67 GETB67 getb67; do
+    as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+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.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  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
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define CRAY_STACKSEG_END $ac_func
+_ACEOF
+
+    break
+fi
+
+  done
+fi
+
+echo "$as_me:$LINENO: checking stack direction for C alloca" >&5
+echo $ECHO_N "checking stack direction for C alloca... $ECHO_C" >&6
+if test "${ac_cv_c_stack_direction+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_stack_direction=0
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+int
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
+  else
+    return (&dummy > addr) ? 1 : -1;
+}
+
+int
+main ()
+{
+  exit (find_stack_direction () < 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_c_stack_direction=1
+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_c_stack_direction=-1
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_stack_direction" >&5
+echo "${ECHO_T}$ac_cv_c_stack_direction" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+_ACEOF
+
+
+fi
+
+if test $ac_cv_c_compiler_gnu = yes; then
+    echo "$as_me:$LINENO: checking whether $CC needs -traditional" >&5
+echo $ECHO_N "checking whether $CC needs -traditional... $ECHO_C" >&6
+if test "${ac_cv_prog_gcc_traditional+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sgtty.h>
+Autoconf TIOCGETP
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "$ac_pattern" >/dev/null 2>&1; then
+  ac_cv_prog_gcc_traditional=yes
+else
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <termio.h>
+Autoconf TCGETA
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "$ac_pattern" >/dev/null 2>&1; then
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_gcc_traditional" >&5
+echo "${ECHO_T}$ac_cv_prog_gcc_traditional" >&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
+if test "${ac_cv_type_signal+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 <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int
+main ()
+{
+int i;
+  ;
+  return 0;
+}
+_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_signal=void
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_signal=int
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+echo "${ECHO_T}$ac_cv_type_signal" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+for ac_func in vprintf
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+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.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  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
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+echo "$as_me:$LINENO: checking for _doprnt" >&5
+echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6
+if test "${ac_cv_func__doprnt+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.  */
+/* Define _doprnt to an innocuous variant, in case <limits.h> declares _doprnt.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define _doprnt innocuous__doprnt
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef _doprnt
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char _doprnt ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+char (*f) () = _doprnt;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != _doprnt;
+  ;
+  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
+  ac_cv_func__doprnt=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func__doprnt=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5
+echo "${ECHO_T}$ac_cv_func__doprnt" >&6
+if test $ac_cv_func__doprnt = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DOPRNT 1
+_ACEOF
+
+fi
+
+fi
+done
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize strerror
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+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.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  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
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+for ac_func in ftruncate strstr strcasecmp
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+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.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  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
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  case $LIBOBJS in
+    "$ac_func.$ac_objext"   | \
+  *" $ac_func.$ac_objext"   | \
+    "$ac_func.$ac_objext "* | \
+  *" $ac_func.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;;
+esac
+
+fi
+done
+
+
+
+echo "$as_me:$LINENO: checking for textdomain" >&5
+echo $ECHO_N "checking for textdomain... $ECHO_C" >&6
+if test "${ac_cv_func_textdomain+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.  */
+/* Define textdomain to an innocuous variant, in case <limits.h> declares textdomain.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define textdomain innocuous_textdomain
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char textdomain (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef textdomain
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char textdomain ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_textdomain) || defined (__stub___textdomain)
+choke me
+#else
+char (*f) () = textdomain;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != textdomain;
+  ;
+  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
+  ac_cv_func_textdomain=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_textdomain=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_textdomain" >&5
+echo "${ECHO_T}$ac_cv_func_textdomain" >&6
+if test $ac_cv_func_textdomain = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define ENABLE_NLS  1
+_ACEOF
+
+fi
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+echo "$as_me:$LINENO: checking for HP-UX needing gmalloc" >&5
+echo $ECHO_N "checking for HP-UX needing gmalloc... $ECHO_C" >&6
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+  case $LIBOBJS in
+    "gmalloc.$ac_objext"   | \
+  *" gmalloc.$ac_objext"   | \
+    "gmalloc.$ac_objext "* | \
+  *" gmalloc.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS gmalloc.$ac_objext" ;;
+esac
+
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_VALLOC 1
+_ACEOF
+
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+
+for ac_func in valloc
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+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.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  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
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+fi
+
+# we cannot generate static libraries under Darwin
+echo "$as_me:$LINENO: checking for Apple MacOS X/Darwin" >&5
+echo $ECHO_N "checking for Apple MacOS X/Darwin... $ECHO_C" >&6
+if test "`(uname -s) 2> /dev/null`" = 'Darwin'; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+  STATIC=""
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+  STATIC="-static "
+fi
+
+
+echo "$as_me:$LINENO: checking if malloc debugging is wanted" >&5
+echo $ECHO_N "checking if malloc debugging is wanted... $ECHO_C" >&6
+
+# Check whether --with-dmalloc or --without-dmalloc was given.
+if test "${with_dmalloc+set}" = set; then
+  withval="$with_dmalloc"
+  if test "$withval" = yes; then
+  echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+  cat >>confdefs.h <<\_ACEOF
+#define WITH_DMALLOC 1
+_ACEOF
+
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi;
+
+echo "$as_me:$LINENO: checking which of rx or regex is wanted" >&5
+echo $ECHO_N "checking which of rx or regex is wanted... $ECHO_C" >&6
+
+# Check whether --with-regex or --without-regex was given.
+if test "${with_regex+set}" = set; then
+  withval="$with_regex"
+  if test "$withval" = yes; then
+  ac_with_regex=1
+  echo "$as_me:$LINENO: result: regex" >&5
+echo "${ECHO_T}regex" >&6
+  cat >>confdefs.h <<\_ACEOF
+#define WITH_REGEX 1
+_ACEOF
+
+  case $LIBOBJS in
+    "regex.$ac_objext"   | \
+  *" regex.$ac_objext"   | \
+    "regex.$ac_objext "* | \
+  *" regex.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS regex.$ac_objext" ;;
+esac
+
+fi
+fi;
+if test -z "$ac_with_regex"; then
+  echo "$as_me:$LINENO: result: rx" >&5
+echo "${ECHO_T}rx" >&6
+  echo "$as_me:$LINENO: checking for re_rx_search" >&5
+echo $ECHO_N "checking for re_rx_search... $ECHO_C" >&6
+if test "${ac_cv_func_re_rx_search+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.  */
+/* Define re_rx_search to an innocuous variant, in case <limits.h> declares re_rx_search.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define re_rx_search innocuous_re_rx_search
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char re_rx_search (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef re_rx_search
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char re_rx_search ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_re_rx_search) || defined (__stub___re_rx_search)
+choke me
+#else
+char (*f) () = re_rx_search;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != re_rx_search;
+  ;
+  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
+  ac_cv_func_re_rx_search=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_re_rx_search=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_re_rx_search" >&5
+echo "${ECHO_T}$ac_cv_func_re_rx_search" >&6
+if test $ac_cv_func_re_rx_search = yes; then
+  :
+else
+  case $LIBOBJS in
+    "rx.$ac_objext"   | \
+  *" rx.$ac_objext"   | \
+    "rx.$ac_objext "* | \
+  *" rx.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS rx.$ac_objext" ;;
+esac
+
+fi
+
+fi
+
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+  case $LIBOBJS in
+    "xmalloc.$ac_objext"   | \
+  *" xmalloc.$ac_objext"   | \
+    "xmalloc.$ac_objext "* | \
+  *" xmalloc.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS xmalloc.$ac_objext" ;;
+esac
+
+  case $LIBOBJS in
+    "error.$ac_objext"   | \
+  *" error.$ac_objext"   | \
+    "error.$ac_objext "* | \
+  *" error.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS error.$ac_objext" ;;
+esac
+
+fi
+
+
+# ---------------------------------------------------------------------------
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+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_cxx_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_cxx_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
+
+
+
+
+
+echo "$as_me:$LINENO: checking that Perl 5 is available" >&5
+echo $ECHO_N "checking that Perl 5 is available... $ECHO_C" >&6
+success="no"
+pl_path="$PATH"
+IFS="${IFS=   }"; pl_save_ifs="$IFS"; IFS=":"
+for pl_dir in $pl_path; do
+  test -z "$pl_dir" && pl_dir=.
+  if test -x $pl_dir/perl; then
+    success="yes"
+    break
+  fi
+done
+IFS="$pl_save_ifs"
+
+if test $success = "yes"; then
+try=`perl configtest.pl` || try="0"
+try=`expr $try \> 5.000`
+if test $try = "1"; then
+echo "$as_me:$LINENO: result: \"yes\"" >&5
+echo "${ECHO_T}\"yes\"" >&6
+else
+success="no"
+fi
+fi
+
+if test $success = "no"; then
+echo "$as_me:$LINENO: result: \"no\"" >&5
+echo "${ECHO_T}\"no\"" >&6
+{ { echo "$as_me:$LINENO: error: \"Perl 5 not available - cannot install\"" >&5
+echo "$as_me: error: \"Perl 5 not available - cannot install\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+success=no
+echo "$as_me:$LINENO: checking \"whether STL library has known faults\"" >&5
+echo $ECHO_N "checking \"whether STL library has known faults\"... $ECHO_C" >&6
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <vector>
+
+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_cxx_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
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $success = "no"; then
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <vector.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_cxx_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
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test $success = "no"; then
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ospace\\std\\vector>
+
+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_cxx_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
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test $success = yes; then
+echo "$as_me:$LINENO: result: \"no\"" >&5
+echo "${ECHO_T}\"no\"" >&6
+else
+echo "$as_me:$LINENO: result: \"yes\"" >&5
+echo "${ECHO_T}\"yes\"" >&6
+{ { echo "$as_me:$LINENO: error: \"STL Broken - Obtain newer version of GNU C Compiler\"" >&5
+echo "$as_me: error: \"STL Broken - Obtain newer version of GNU C Compiler\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+gsdlos=`uname | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+# check for running bash under cygwin
+ if test "`echo $gsdlos | sed 's/cygwin//'`" != "$gsdlos" ;
+ then
+  gsdlos=windows
+ fi
+
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+  case $LIBOBJS in
+    "xmalloc.o.$ac_objext"   | \
+  *" xmalloc.o.$ac_objext"   | \
+    "xmalloc.o.$ac_objext "* | \
+  *" xmalloc.o.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS xmalloc.o.$ac_objext" ;;
+esac
+
+  case $LIBOBJS in
+    "error.$ac_objext"   | \
+  *" error.$ac_objext"   | \
+    "error.$ac_objext "* | \
+  *" error.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS error.$ac_objext" ;;
+esac
+
+fi
+
+# ---------------------------------------------------------------------------
+
+moduleDirs=""
+MODULEDIRS=""
+for x in `find modules -mindepth 1 -maxdepth 2`; do
+  if test -d "$x"; then
+    d="$x/Makefile.in"
+    if test -e "$d"; then
+      moduleDirs="$moduleDirs $x/Makefile"
+      MODULEDIRS="$MODULEDIRS $x"
+    fi
+  fi
+done
+echo "Making$moduleDirs in modules directory"
+
+
+# ---------------------------------------------------------------------------
+
+
+subdirs="$subdirs packages"
+
+
+# the list of folders in the src folder
+srclist="src/mgpp/lib/Makefile src/mgpp/text/Makefile src/mgpp/Makefile \
+          src/hashfile/Makefile src/colservr/Makefile src/recpt/Makefile src/txt2db/Makefile \
+          src/oaiservr/Makefile src/db2txt/Makefile src/getpw/Makefile src/phind/generate/Makefile"
+
+                                                                                                    ac_config_files="$ac_config_files packages/Makefile packages/mg/Makefile packages/mg/src/text/Makefile packages/mg/src/images/Makefile packages/mg/src/scripts/Makefile packages/mg/lib/Makefile lib/Makefile Makefile $srclist $moduleDirs"
+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
+
+DEFS=-DHAVE_CONFIG_H
+
+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
+  --header=FILE[:TEMPLATE]
+		   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+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.
+  "packages/Makefile" ) CONFIG_FILES="$CONFIG_FILES packages/Makefile" ;;
+  "packages/mg/Makefile" ) CONFIG_FILES="$CONFIG_FILES packages/mg/Makefile" ;;
+  "packages/mg/src/text/Makefile" ) CONFIG_FILES="$CONFIG_FILES packages/mg/src/text/Makefile" ;;
+  "packages/mg/src/images/Makefile" ) CONFIG_FILES="$CONFIG_FILES packages/mg/src/images/Makefile" ;;
+  "packages/mg/src/scripts/Makefile" ) CONFIG_FILES="$CONFIG_FILES packages/mg/src/scripts/Makefile" ;;
+  "packages/mg/lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES packages/mg/lib/Makefile" ;;
+  "lib/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
+  "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+  "$srclist" ) CONFIG_FILES="$CONFIG_FILES $srclist" ;;
+  "$moduleDirs" ) CONFIG_FILES="$CONFIG_FILES $moduleDirs" ;;
+  "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+  *) { { 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
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+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,@PACKAGE@,$PACKAGE,;t t
+s,@VERSION@,$VERSION,;t t
+s,@USE_FASTCGI@,$USE_FASTCGI,;t t
+s,@USE_LANGACTION@,$USE_LANGACTION,;t t
+s,@USE_CORBA@,$USE_CORBA,;t t
+s,@MICO_DIR@,$MICO_DIR,;t t
+s,@USE_Z3950@,$USE_Z3950,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@CC@,$CC,;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,@CXX@,$CXX,;t t
+s,@CXXFLAGS@,$CXXFLAGS,;t t
+s,@ac_ct_CXX@,$ac_ct_CXX,;t t
+s,@AWK@,$AWK,;t t
+s,@YACC@,$YACC,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@target@,$target,;t t
+s,@target_cpu@,$target_cpu,;t t
+s,@target_vendor@,$target_vendor,;t t
+s,@target_os@,$target_os,;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,@SET_MAKE@,$SET_MAKE,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@MICO_VER@,$MICO_VER,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;t t
+s,@U@,$U,;t t
+s,@ANSI2KNR@,$ANSI2KNR,;t t
+s,@ALLOCA@,$ALLOCA,;t t
+s,@LIBOBJS@,$LIBOBJS,;t t
+s,@STATIC@,$STATIC,;t t
+s,@GDBM_LIBPATH@,$GDBM_LIBPATH,;t t
+s,@GDBM_INCLUDE@,$GDBM_INCLUDE,;t t
+s,@gsdlos@,$gsdlos,;t t
+s,@MODULEDIRS@,$MODULEDIRS,;t t
+s,@subdirs@,$subdirs,;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
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([	 ]*\)#\([	 ]*define[	 ][	 ]*\)'
+ac_dB='[	 ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([	 ]*\)#\([	 ]*\)undef\([	 ][	 ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; 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
+
+  test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+  # 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; }; }
+	 # Do quote $f, to prevent DOS paths from being IFS'd.
+	 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; }
+  # Remove the trailing spaces.
+  sed 's/[	 ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h.  The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status.  Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*\)\(([^)]*)\)[	 ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless.  Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[	 ]*#[	 ]*undef[	 ][	 ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo '  if grep "^[	 ]*#[	 ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo '  # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo '  :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+  # Write a limited-size here document to $tmp/defines.sed.
+  echo '  cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#define' lines.
+  echo '/^[	 ]*#[	 ]*define/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/defines.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo '  fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+  # Write a limited-size here document to $tmp/undefs.sed.
+  echo '  cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#undef'
+  echo '/^[	 ]*#[	 ]*undef/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+  rm -f conftest.undefs
+  mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+  # 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
+    echo "/* Generated by configure.  */" >$tmp/config.h
+  else
+    echo "/* $ac_file.  Generated by configure.  */" >$tmp/config.h
+  fi
+  cat $tmp/in >>$tmp/config.h
+  rm -f $tmp/in
+  if test x"$ac_file" != x-; then
+    if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      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; }; }; }
+
+      rm -f $ac_file
+      mv $tmp/config.h $ac_file
+    fi
+  else
+    cat $tmp/config.h
+    rm -f $tmp/config.h
+  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
+
+#
+# CONFIG_SUBDIRS section.
+#
+if test "$no_recursion" != yes; then
+
+  # Remove --cache-file and --srcdir arguments so they do not pile up.
+  ac_sub_configure_args=
+  ac_prev=
+  for ac_arg in $ac_configure_args; do
+    if test -n "$ac_prev"; then
+      ac_prev=
+      continue
+    fi
+    case $ac_arg in
+    -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=*)
+      ;;
+    --config-cache | -C)
+      ;;
+    -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+      ac_prev=srcdir ;;
+    -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+      ;;
+    -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+      ac_prev=prefix ;;
+    -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+      ;;
+    *) ac_sub_configure_args="$ac_sub_configure_args $ac_arg" ;;
+    esac
+  done
+
+  # Always prepend --prefix to ensure using the same prefix
+  # in subdir configurations.
+  ac_sub_configure_args="--prefix=$prefix $ac_sub_configure_args"
+
+  ac_popdir=`pwd`
+  for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue
+
+    # Do not complain, so a configure script can configure whichever
+    # parts of a large source tree are present.
+    test -d $srcdir/$ac_dir || continue
+
+    { echo "$as_me:$LINENO: configuring in $ac_dir" >&5
+echo "$as_me: configuring in $ac_dir" >&6;}
+    { 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
+
+
+    cd $ac_dir
+
+    # Check for guested configure; otherwise get Cygnus style configure.
+    if test -f $ac_srcdir/configure.gnu; then
+      ac_sub_configure="$SHELL '$ac_srcdir/configure.gnu'"
+    elif test -f $ac_srcdir/configure; then
+      ac_sub_configure="$SHELL '$ac_srcdir/configure'"
+    elif test -f $ac_srcdir/configure.in; then
+      ac_sub_configure=$ac_configure
+    else
+      { echo "$as_me:$LINENO: WARNING: no configuration information is in $ac_dir" >&5
+echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;}
+      ac_sub_configure=
+    fi
+
+    # The recursion is here.
+    if test -n "$ac_sub_configure"; then
+      # Make the cache file name correct relative to the subdirectory.
+      case $cache_file in
+      [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;;
+      *) # Relative path.
+	ac_sub_cache_file=$ac_top_builddir$cache_file ;;
+      esac
+
+      { echo "$as_me:$LINENO: running $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5
+echo "$as_me: running $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;}
+      # The eval makes quoting arguments work.
+      eval $ac_sub_configure $ac_sub_configure_args \
+	   --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir ||
+	{ { echo "$as_me:$LINENO: error: $ac_sub_configure failed for $ac_dir" >&5
+echo "$as_me: error: $ac_sub_configure failed for $ac_dir" >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+
+    cd $ac_popdir
+  done
+fi
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/configure.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/configure.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/configure.in	(revision 10506)
@@ -0,0 +1,410 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl Use autoconf-2.59 or later... it might not work anymore with
+dnl the older 2.1x versions - jrm21 12/2004
+AC_INIT(lib/text_t.h)
+AC_CONFIG_HEADER(config.h)
+
+PACKAGE=gsdl
+VERSION=2.1
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+
+dnl
+dnl Set use of fast cgi
+dnl
+USE_FASTCGI=0
+if test USE_FASTCGI = 1; then
+AC_DEFINE(USE_FASTCGI)
+AC_SUBST(USE_FASTCGI)
+fi
+
+dnl
+dnl Set use of langaction
+dnl
+dnl USE_LANGACTION=0
+if test USE_LANGACTION = 1; then
+AC_DEFINE(USE_LANGACTION)
+AC_SUBST(USE_LANGACTION)
+fi
+
+dnl
+dnl Set use of corba
+dnl
+AC_ARG_ENABLE(corba, [  --enable-corba          Enable CORBA support], USE_CORBA=1, USE_CORBA=0)
+AC_DEFINE_UNQUOTED(USE_CORBA, $USE_CORBA)
+AC_SUBST(USE_CORBA)
+
+AC_ARG_WITH(micodir, [  --with-micodir          Use installed MICO directory], MICO_DIR=$enableval, MICO_DIR="default")
+AC_DEFINE_UNQUOTED(MICO_DIR, "$MICO_DIR")
+AC_SUBST(MICO_DIR)
+
+dnl
+dnl Set use of z39.50
+dnl
+AC_ARG_ENABLE(z3950, [  --enable-z3950          Enable Z39.50 client support], USE_Z3950=1, USE_Z3950=0)
+if test USE_Z3950 = 1; then
+AC_DEFINE(USE_Z3950, $USE_Z3950)
+AC_SUBST(USE_Z3950)
+fi
+
+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)
+
+dnl Checks for programs.
+LDFLAGS=
+dnl only set CFLAGS if not already set in environment
+if test -z "$CFLAGS"; then
+CFLAGS=-O2
+fi
+AC_SUBST(CFLAGS)
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_AWK
+AC_PROG_YACC
+dnl get $target_cpu, $target_vendor, and $target_os
+dnl (as well as host_*)
+AC_CANONICAL_SYSTEM
+dnl do we actually want this? It adds a prefix based on host, system etc
+dnl AC_ARG_PROGRAM
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+#moved CORBA MICO directory test to get version of MICO
+if test $USE_CORBA = 1; then
+
+if test $MICO_DIR = "default"; then
+#do something
+MICO_INC="-I packages/mico/mico/include"
+else
+#build the micotest program
+MICO_INC= ""
+if test $MICO_DIR != yes; then
+MICO_INC="-I $MICO_DIR"
+fi
+fi
+
+#get MICO_VER value
+sh -c "$CC -c micotest.cpp -o micotest.o $MICO_INC 2>&1" > /dev/null
+sh -c "$CC -o micotest micotest.o -lstdc++ 2>&1" > /dev/null
+MICO_VER=`./micotest` || MICO_VER=2.3.5
+sh -c "rm micotest"
+sh -c "rm micotest.o"
+
+#do test of MICO_VER
+if test MICO_VER != 0; then
+AC_DEFINE(MICO_VER)
+AC_SUBST(MICO_VER)
+fi
+#end USE_CORBA test
+fi
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_AIX
+AC_ISC_POSIX
+AC_MINIX
+fp_C_PROTOTYPES
+AC_C_CONST
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl --- This should be in the stdc checking -----------------
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+dnl The Pyramids running SMP_DC.OSx on MIPS r3000 chips with
+dnl /usr/opt/cc3.11/bin/cc treat -Xc as full ANSI mode - no POSIX or
+dnl XOPEN extensions (like popen).
+dnl Unfortunately -D_{XOPEN,POSIX}_SOURCE can't provide all that mg
+dnl needs. So drop back to -Xa
+AC_TRY_COMPILE(
+[#include <stdio.h>
+], [ FILE *rubbish = popen("yes", "r"); ],,
+[CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'])
+fi
+dnl ----------------------
+
+
+dnl Checks for libraries.
+dnl check for -lg:
+AC_HAVE_LIBRARY(g)
+dnl check for -lm:
+AC_HAVE_LIBRARY(m)
+dnl check for -lcrypt:
+AC_HAVE_LIBRARY(crypt)
+
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h unistd.h crypt.h string.h memory.h sys/procfs.h sys/stat.h)
+AC_EGREP_HEADER(fread, stdio.h, AC_DEFINE(HAVE_FREAD_DECL))
+AC_EGREP_HEADER(fgetc, stdio.h, AC_DEFINE(HAVE_FGETC_DECL))
+AC_EGREP_HEADER(pr_brksize, sys/procfs.h, AC_DEFINE(HAVE_PR_BRKSIZE))
+
+dnl Checks for library functions.
+AC_FUNC_ALLOCA
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize strerror)
+AC_REPLACE_FUNCS(ftruncate strstr strcasecmp)
+
+dnl see if gettext is in libc. (try the textdomain() function).
+AC_CHECK_FUNC(textdomain, AC_DEFINE(ENABLE_NLS ,1) )
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+AC_MSG_CHECKING(for HP-UX needing gmalloc)
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  AC_MSG_RESULT(yes)
+  AC_LIBOBJ([gmalloc])
+  AC_DEFINE(HAVE_VALLOC)
+else
+  AC_MSG_RESULT(no)
+  AC_CHECK_FUNCS(valloc)
+fi
+
+# we cannot generate static libraries under Darwin
+AC_MSG_CHECKING(for Apple MacOS X/Darwin)
+if test "`(uname -s) 2> /dev/null`" = 'Darwin'; then
+  AC_MSG_RESULT(yes)
+  STATIC=""
+else
+  AC_MSG_RESULT(no)
+  STATIC="-static "
+fi
+AC_SUBST(STATIC)
+
+fp_WITH_DMALLOC
+fp_WITH_REGEX
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+dnl    support functions for alloca.c
+  AC_LIBOBJ([xmalloc])
+  AC_LIBOBJ([error])
+fi
+
+
+# ---------------------------------------------------------------------------
+
+dnl
+dnl Switch into C++
+dnl
+AC_LANG_CPLUSPLUS
+
+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)
+
+dnl
+dnl Now check that Perl is actually around, and can be found
+dnl
+AC_MSG_CHECKING(that Perl 5 is available)
+success="no"
+pl_path="$PATH"
+IFS="${IFS=   }"; pl_save_ifs="$IFS"; IFS=":"
+for pl_dir in $pl_path; do
+  test -z "$pl_dir" && pl_dir=.
+  if test -x $pl_dir/perl; then
+    success="yes"
+    break
+  fi
+done
+IFS="$pl_save_ifs"
+
+dnl
+dnl Perl actually can be run; now we see if it is version 5 by
+dnl running a sample script (which returns a "clean" version number
+dnl and then tests the result using expr.  If perl errors in some
+dnl way (eg. broken Perl executable, missing script), we set a failure
+dnl value ("0") and then proceed as best we can
+dnl
+if test $success = "yes"; then
+try=`perl configtest.pl` || try="0"
+try=`expr $try \> 5.000`
+if test $try = "1"; then
+AC_MSG_RESULT("yes")
+else
+success="no"
+fi
+fi
+
+if test $success = "no"; then
+AC_MSG_RESULT("no")
+AC_MSG_ERROR("Perl 5 not available - cannot install")
+fi
+
+dnl
+dnl Check if the STL library has any known faults;
+dnl In GCC 2.7.2.x series, some STL library headers are missing
+dnl a file called "new" which is referred to by other headers
+dnl (eg. vector/vector.h); if this applies, then all use of the
+dnl STL will cause a compile fail, so we'd better let the user
+dnl know now, before things really go wrong!
+dnl
+success=no
+AC_MSG_CHECKING("whether STL library has known faults")
+
+dnl - first shot, try simple good old vector on its own
+AC_TRY_COMPILE(
+[#include <vector>
+], 
+[],
+success=yes,
+)
+
+dnl - try using the .h equivalent
+if test $success = "no"; then
+AC_TRY_COMPILE(
+[#include <vector.h>
+], 
+[],
+success="yes",
+)
+fi
+
+dnl - now try for the objectspace headers
+if test $success = "no"; then
+AC_TRY_COMPILE(
+[#include <ospace\\std\\vector>
+], 
+[],
+success="yes",
+)
+fi
+
+if test $success = yes; then
+AC_MSG_RESULT("no")
+else
+AC_MSG_RESULT("yes")
+AC_MSG_ERROR("STL Broken - Obtain newer version of GNU C Compiler")
+fi
+
+gsdlos=`uname | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+# check for running bash under cygwin
+ if test "`echo $gsdlos | sed 's/cygwin//'`" != "$gsdlos" ;
+ then
+  gsdlos=windows
+ fi
+AC_SUBST(gsdlos)
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+dnl    support functions for alloca.c
+  AC_LIBOBJ([xmalloc.o])
+  AC_LIBOBJ([error])
+fi
+
+# ---------------------------------------------------------------------------
+
+dnl
+dnl Locate all children of the modules folder
+dnl
+moduleDirs=""
+MODULEDIRS=""
+for x in `find modules -mindepth 1 -maxdepth 2`; do
+  if test -d "$x"; then
+    d="$x/Makefile.in"
+    if test -e "$d"; then
+dnl      echo $d
+      moduleDirs="$moduleDirs $x/Makefile"
+      MODULEDIRS="$MODULEDIRS $x"
+    fi
+  fi
+done
+echo "Making$moduleDirs in modules directory"
+AC_SUBST(MODULEDIRS)
+
+# ---------------------------------------------------------------------------
+dnl for Darwin, as our packages don't (yet) correctly guess our system type.
+dnl not needed any more?
+dnl ac_configure_args="$ac_configure_args --build=$build --target=$target"
+AC_CONFIG_SUBDIRS(packages)
+
+# the list of folders in the src folder
+srclist="src/mgpp/lib/Makefile src/mgpp/text/Makefile src/mgpp/Makefile \
+          src/hashfile/Makefile src/colservr/Makefile src/recpt/Makefile src/txt2db/Makefile \
+          src/oaiservr/Makefile src/db2txt/Makefile src/getpw/Makefile src/phind/generate/Makefile"
+
+AC_OUTPUT(packages/Makefile packages/mg/Makefile packages/mg/src/text/Makefile packages/mg/src/images/Makefile 
+          packages/mg/src/scripts/Makefile packages/mg/lib/Makefile
+	  lib/Makefile Makefile $srclist $moduleDirs)
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/etc/BVERSION
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/BVERSION	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/BVERSION	(revision 10506)
@@ -0,0 +1,1 @@
+build version: 2.1
Index: /tags/gsdl-2_61-distribution/gsdl/etc/VERSION
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/VERSION	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/VERSION	(revision 10506)
@@ -0,0 +1,3 @@
+gsdl version: x.xx
+cvs tag: gsdl-x_xx-distribution
+build version: 2.1
Index: /tags/gsdl-2_61-distribution/gsdl/etc/main.cfg
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/main.cfg	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/main.cfg	(revision 10506)
@@ -0,0 +1,259 @@
+# This file must be utf-8 encoded
+#
+# This is the main configuration file for configuring
+# your Greenstone receptionist (the bit responsible for the way
+# things are displayed) and contains information common
+# to the interface of all collections served by the site.
+
+# Email address of the webmaster of this Greenstone installation
+# If maintainer is set to "NULL" EmailEvents and EmailUserEvents
+# will be disabled.
+maintainer      NULL
+
+# Outgoing (SMTP) mail server for this Greenstone installation.
+# This will default to mail.maintainer-domain if it's not set
+# (i.e. if maintainer is greenstone@cs.waikato.ac.nz then MailServer
+# will default to mail.cs.waikato.ac.nz). If MailServer doesn't
+# resolve to a valid SMTP server then the EmailEvents and
+# EmailUserEvents options (see below) won't be functional. Likewise,
+# turning off EmailEvents and EmailUserEvents will remove any 
+# reliance on MailServer.
+MailServer      NULL
+
+# Set status to "disabled" if you don't want the Maintenance and
+# Administration facility to be available.
+status          enabled
+
+# Set collector to "disabled" if you don't want the "collector"
+# end-user collection building facility to be available.
+collector       disabled
+
+# Set gliapplet to "disabled" if you don't want the remote users
+# to be able to build collections on your server through an applet
+# version of GLI
+gliapplet       disabled
+
+# Set translator to "enabled" if you want the translation
+# service for keeping language fragments of macro text up to date 
+translator      disabled
+
+# Set logcgiargs to true to keep a log of usage information in
+# $GSDLHOME/etc/usage.txt.
+logcgiargs      false
+
+# Set usecookies to true to use cookies to identify users (cookie 
+# information will be written to the usage log if logcgiargs is
+# true).
+usecookies      false
+
+# LogDateFormat sets the format that timestamps will be stored in the usage
+# log (i.e. if logcgiargs is enabled). It takes the following values:
+# LocalTime: (the default) The local time and date in the form 
+#            "Thu Dec 07 23:47:00 NZDT 2000".
+# UTCTime: Coordinated universal time (GMT) in the same format as LocalTime.
+# Absolute: Integer value representing the number of seconds since 
+#           00:00:00 1/1/1970 GMT
+LogDateFormat   LocalTime
+
+# Log any events that Greenstone deems important in 
+# $GSDLHOME/etc/events.txt. 
+# The only events that are currently implemented come from the 
+# collector (e.g. someone just built/deleted the following collection)
+# LogEvents may take values of:
+# AllEvents: All important events
+# CollectorEvents: Just those events originating from the collector
+#                  (e.g. someone just built a collection)
+# disabled: Don't log events
+LogEvents       disabled
+
+# Email the maintainer whenever any event occurs. EmailEvents
+# takes the same values as LogEvents.
+# Note that perl must be installed for EmailEvents or
+# EmailUserEvents to work.
+EmailEvents     disabled
+
+# In some cases it may be appropriate to email the user about a
+# certain event (e.g. notification from the collector that a collection
+# was built successfully)
+EmailUserEvents false
+
+
+# The list of display macro files used by this receptionist
+macrofiles      tip.dm style.dm base.dm query.dm help.dm pref.dm about.dm \
+                document.dm browse.dm status.dm authen.dm users.dm html.dm \
+                extlink.dm gsdl.dm extra.dm home.dm collect.dm docs.dm \
+		bsummary.dm gti.dm garish.dm gli.dm \
+		english.dm english2.dm french.dm french2.dm spanish.dm \
+		spanish2.dm russian.dm russian2.dm
+		# hebrew.dm czech.dm czech2.dm galician.dm galician2.dm \
+		# indo.dm japanese.dm japanese2.dm thai.dm thai2.dm \
+		# kazakh.dm kazakh2.dm port-br.dm port-pt.dm \
+		# chinese.dm german.dm maori.dm arabic.dm dutch.dm  \
+                # italian.dm italian2.dm turkish.dm turkish2.dm \
+		# ukrainian.dm croatian.dm hindi.dm kannada.dm finnish.dm \
+		# greek.dm armenian.dm  farsi.dm serbian.dm georgian.dm \
+		# georgian2.dm catalan.dm catalan2.dm latvian.dm latvian2.dm \
+		# vietnamese.dm vietnamese2.dm chinese-trad.dm chinese-trad2.dm \
+		# mongolian.dm mongolian2.dm kirghiz.dm bengali.dm polish.dm
+
+# Define the interface languages and encodings supported by this receptionist
+
+# An "Encoding" line defines an encoding to be used by the receptionist.
+# Uncomment "Encoding" lines to include an encoding on your "preferences" page.
+# Encoding line options are:
+# shortname -- The standard charset label for the given encoding. The
+#              shortname option is mandatory.
+# longname  -- The display name of the given encoding. If longname isn't set
+#              it will default to using shortname instead.
+# map       -- The name of the map file (i.e. the .ump file) for use when
+#              converting between unicode and the given encoding. The map
+#              option is mandatory for all encoding lines except the
+#              special case for utf8.
+# multibyte -- This optional argument should be set for all encodings that use
+#              multibyte characters.
+
+# The utf8 encoding is handled internally and doesn't require a map file.
+# As a rule the utf8 encoding should always be enabled, especially if you
+# have collections of documents that may not all be in the same
+# language/encoding.
+Encoding shortname=utf-8 "longname=Unicode (UTF-8)"
+
+# This is very experimental, and you almost certainly don't need it
+#Encoding shortname=utf-16be "longname=Unicode (UTF-16BE)"
+
+# The ISO-8859 series
+Encoding shortname=iso-8859-1 "longname=Western (ISO-8859-1)" map=8859_1.ump
+#Encoding shortname=iso-8859-2 "longname=Central European (ISO-8859-2)" map=8859_2.ump
+#Encoding shortname=iso-8859-3 "longname=Latin 3 (ISO-8859-3)" map=8859_3.ump
+#Encoding shortname=iso-8859-4 "longname=Latin 4 (ISO-8859-4)" map=8859_4.ump
+#Encoding shortname=iso-8859-5 "longname=Cyrillic (ISO-8859-5)" map=8859_5.ump
+#Encoding shortname=iso-8859-6 "longname=Arabic (ISO-8859-6)" map=8859_6.ump
+#Encoding shortname=iso-8859-7 "longname=Greek (ISO-8859-7)" map=8859_7.ump
+#Encoding shortname=iso-8859-8 "longname=Hebrew (ISO-8859-8)" map=8859_8.ump
+#Encoding shortname=iso-8859-9 "longname=Turkish (ISO-8859-9)" map=8859_9.ump
+#Encoding shortname=iso-8859-15 "longname=Western (ISO-8859-15)" map=8859_15.ump
+
+# Windows codepages
+Encoding shortname=windows-1250 "longname=Central European (Windows-1250)" map=win1250.ump
+Encoding shortname=windows-1251 "longname=Cyrillic (Windows-1251)" map=win1251.ump
+#Encoding shortname=windows-1252 "longname=Western (Windows-1252)" map=win1252.ump
+Encoding shortname=windows-1253 "longname=Greek (Windows-1253)" map=win1253.ump
+Encoding shortname=windows-1254 "longname=Turkish (Windows-1254)" map=win1254.ump
+Encoding shortname=windows-1255 "longname=Hebrew (Windows-1255)" map=win1255.ump
+Encoding shortname=windows-1256 "longname=Arabic (Windows-1256)" map=win1256.ump
+#Encoding shortname=windows-1257 "longname=Baltic (Windows-1257)" map=win1257.ump
+#Encoding shortname=windows-1258 "longname=Vietnamese (Windows-1258)" map=win1258.ump
+#Encoding shortname=windows-874 "longname=Thai (Windows-874)" map=win874.ump
+#Encoding shortname=cp866 "longname=Cyrillic (DOS)" map=dos866.ump
+#Encoding shortname=cp850 "longname=Latin-1 (DOS)" map=dos850.ump
+
+# KOI8 Cyrillic encodings
+#Encoding shortname=koi8-r "longname=Cyrillic (KOI8-R)" map=koi8_r.ump
+#Encoding shortname=koi8-u "longname=Cyrillic (KOI8-U)" map=koi8_u.ump
+
+# CJK encodings (note that Shift-JIS Japanese isn't currently supported)
+Encoding shortname=gbk "longname=æ±è¯­ (Chinese Simplified GBK)" map=gbk.ump multibyte
+Encoding shortname=big5 "longname=æŒ¢èª (Chinese Traditional Big5)" map=big5.ump multibyte
+Encoding shortname=euc-jp "longname=Japanese (EUC)" map=euc_jp.ump multibyte
+Encoding shortname=euc-kr "longname=Korean (UHC)" map=uhc.ump multibyte
+
+
+# A "Language" line defines an interface language to be used by the
+# interface. Note that it is possible to display only a subset of the
+# specified languages on the preferences page for a given collection by
+# using the "PreferenceLanguages" format option in your collect.cfg
+# configuration file.
+# Arguments are:
+# shortname        -- ISO 639 two letter language symbol. The shortname
+#                     argument is mandatory.
+# longname         -- The display name for the given language. If longname
+#                     isn't set it will default to using shortname instead.
+# default_encoding -- The encoding to use by default when using the given
+#                     interface language. This should be set to the
+#                     "shortname" of a valid "Encoding" line
+# Language shortname=ar longname=Arabic default_encoding=windows-1256
+# Language shortname=bn "longname=àŠ¬àŠŸàŠàŠ²àŠŸ (Bengali)" default_encoding=utf-8
+# Language shortname=ca "longname=CatalÃ  (Catalan)" default_encoding=utf-8
+# Language shortname=cs "longname=Äesky (Czech)" default_encoding=utf-8
+# Language shortname=de "longname=Deutsch (German)" default_encoding=utf-8
+# Language shortname=el "longname=ÎÎ»Î»Î·ÎœÎ¹ÎºÎ¬ (Greek)" default_encoding=windows-1253
+Language shortname=en longname=English default_encoding=utf-8
+Language shortname=es "longname=EspaÃ±ol (Spanish)" \
+	 default_encoding=utf-8
+# Language shortname=fa longname=Farsi default_encoding=utf-8
+# Language shortname=fi longname=Finnish default_encoding=utf-8
+Language shortname=fr "longname=FranÃ§ais (French)" \
+	default_encoding=utf-8
+# Language shortname=gl longname=Galician default_encoding=utf-8
+# Language shortname=he longname=Hebrew default_encoding=windows-1255
+# Language shortname=hi longname=Hindi default_encoding=utf-8
+# Language shortname=hr longname=Croatian default_encoding=windows-1250
+# Language shortname=hy longname=Armenian default_encoding=utf-8
+# Language shortname=id "longname=Bahasa Indonesia (Indonesian)" default_encoding=utf-8
+# Language shortname=it longname=Italiano default_encoding=utf-8
+# Language shortname=ja "longname=æ¥æ¬èª (Japanese)" default_encoding=utf-8
+# Language shortname=ka longname=Georgian default_encoding=utf-8
+# Language shortname=kk "longname=ÒÐ°Ð·Ð°Ò (Kazakh)" default_encoding=utf-8
+# Language shortname=kn longname=Kannada default_encoding=utf-8
+# Language shortname=ky "longname=ÐÑÑÐ³ÑÐ·ÑÐ° (Kirghiz)" default_encoding=utf-8
+# Language shortname=lv longname=Latvian default_encoding=utf-8
+# Language shortname=mi "longname=MÄori" default_encoding=utf-8
+# Language shortname=mn "longname=ÐÐŸÐœÐ³ÐŸÐ» (Mongolian)" default_encoding=utf-8
+# Language shortname=nl "longname=Nederlands (Dutch)" default_encoding=utf-8
+# Language shortname=pl "longname=polski (Polish)" default_encoding=utf-8
+# Language shortname=pt-br "longname=portuguÃªs-BR (Brasil)" \
+#	default_encoding=utf-8
+# Language shortname=pt-pt "longname=portuguÃªs-PT (Portugal)" \
+#	default_encoding=utf-8
+Language shortname=ru "longname=ÑÑÑÑÐºÐžÐ¹ (Russian)" default_encoding=windows-1251
+# Language shortname=sr longname=Serbian default_encoding=utf-8
+# Language shortname=th longname=Thai default_encoding=utf-8
+# Language shortname=tr longname=Turkish default_encoding=windows-1254
+# Language shortname=uk longname=Ukrainian default_encoding=utf-8
+# Language shortname=vi "longname=Tiáº¿ng Viá»t (Vietnamese)" default_encoding=utf-8
+# Language shortname=zh "longname=ç®äœäž­æ (Simplified Chinese)" \
+# 	default_encoding=gbk
+# Language shortname=zh-tr "longname=ç¹é«äž­æ (Traditional Chinese)" default_encoding=big5
+
+
+# Define any additional page parameters to be used by the above macro files
+# (the current default page parameters are c (collection) and l (language)
+
+# Define v (version -- text or graphic) page parameter and give it a default
+# value of 0 (0 = text version off)
+pageparam       v 0
+
+# Set the precedence given to the page parameters. This effects which macro 
+# will be selected for display when there are multiple versions of the same 
+# macro with different page parameters.
+# e.g. Given a macroprecedence of "c,v,l" and the following macro definitions:
+# _content_ []
+# _content_ [l=en]
+# _content_ [c=demo]
+# _content_ [v=1]
+# _content_ [l=fr,v=1,c=hdl]
+# If the corresponding cgi arguments were set to l=en&v=1&c=hdl then the
+# _content_[v=1] macro would be selected for display. It would be selected 
+# ahead of the _content_[l=en] macro because "v" has a higher precedence 
+# than "l". The _content_[l=fr,v=1,c=hdl] macro would not be selected 
+# because one of the page parameters is completely wrong ("l").
+macroprecedence c,v,l
+
+
+# Define any additional cgi arguments. Most cgi arguments are built into
+# Greenstone but it's possible to define them here (or set defaults for
+# existing built-in cgi arguments).
+
+# define the "v" cgi argument (to correspond to the "v" page parameter defined
+# above).
+cgiarg          shortname=v longname=version multiplechar=false argdefault=0 \
+                defaultstatus=weak savedarginfo=must
+
+# set a default value for the built-in "a" cgi argument
+cgiarg          shortname=a argdefault=p
+
+# set a default value for the built-in "p" cgi argument
+cgiarg          shortname=p argdefault=home
+
+# set the default encoding to utf-8
+cgiarg          shortname=w argdefault=utf-8
Index: /tags/gsdl-2_61-distribution/gsdl/etc/marctodc.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/marctodc.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/marctodc.txt	(revision 10506)
@@ -0,0 +1,86 @@
+#
+# This file is used by MARCPlug for mapping MARC field numbers to
+# Greenstone-style metadata.
+#
+# The field numbers listed in this file are for USMARC / MARC21.
+#
+# Lines beginning with "#" are comments.
+# The format for these files are:
+#  <number> -> GreenstoneMetadataName
+#
+# This is loosely based on the MARC -> Dublin Core mapping as found at
+#   http://lcweb.loc.gov/marc/dccross.html
+#
+# The problem with that is that some mappings are conditional on
+# subfield values...
+
+### Contributor	###
+# 720 = "Uncontrolled Name", with $e=collaborator
+
+### Coverage	###
+#500 -> Coverage
+
+### Creator	###
+# 720 = "Uncontrolled Name" with $e=author
+720 -> Creator
+# 100 = "Personal Name"
+100	-> Creator
+# 110 = "Corporate Name" 
+110	-> Creator
+# 111 = "Meeting Name"
+111	-> Creator
+
+### Date	###
+# Don't do this yet, as greenstone expects dates in YYYYMMDD format...
+# 260, $c (but also see Publisher below)
+# 260 -> Date
+
+### Description	###
+# 520 = "Summary, Note"
+520 -> Description
+
+### Identifier	###
+# 024 = "Standard Identifier/number"
+# greenstone uses its own Identifier metadata
+024 -> MarcIdentifier
+
+# 856 = "Electronic Location"
+856 -> URL
+
+### Language	###
+# Greenstone has its own Language metadata...
+546 -> MarcLanguage
+
+### Publisher	###
+# 260 = "Publication, etc"
+# 260 $b if $e=publisher... (but see Date)
+260 -> Publisher
+
+### Relation	###
+# 787 = "Nonspecific Relationship Note"
+787 -> Relation
+
+### Rights	###
+# 540 = "Reproduction Note"
+540 -> Rights
+
+### Source	###
+# greenstone has its own Source metadata...
+# 786 = "Data Source Entry"
+786 -> MarcSource
+
+### Subject	###
+# 650 = "Subject: Topical Term"
+650 -> Subject
+# 653 = "Index Term: Uncontrolled"
+653 -> Subject
+
+### Title	###
+# 245 = "Title Statement"
+245	-> Title
+# 246 = "Varying Form of Title"
+
+### Type	###
+# 655 = "Index Term - Genre/Form"
+655 -> Type
+
Index: /tags/gsdl-2_61-distribution/gsdl/etc/oai.cfg
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/oai.cfg	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/oai.cfg	(revision 10506)
@@ -0,0 +1,80 @@
+# OAI Server Configuration
+
+# This is the main configuration file for configuring your Greenstone oai server.
+# The server is a cgi program called oaiserver (oaiserver.exe on Windows).
+# Some basic commands that you can send it are:
+# ....cgi-bin/oaiserver?verb=Identify
+# ....cgi-bin/oaiserver?verb=ListSets
+# ....cgi-bin/oaiserver?verb=ListIdentifiers&set=xxx (1.1 only)
+# ....cgi-bin/oaiserver?verb=ListIdentifiers&set=xxx&metadataPrefix=oai_dc (2.0 only)
+# ....cgi-bin/oaiserver?verb=ListRecords&set=xxx&metadataPrefix=oai_dc
+# ....cgi-bin/oaiserver?verb=GetRecord&identifier=xxx&metadataPrefix=oai_dc
+# For more information about the OAI-PMH protocol, see 
+# http://www.openarchives.org/
+
+# Strings containing spaces should be enclosed in double quotes ""
+
+# The OAI repository name - human readable
+repositoryName ""
+
+# The central administrative email address for the repository.
+maintainer  ""
+
+# Which version of OAI the repository supports, 1.1 or 2.0
+# (The server supports both)
+oaiversion "2.0"
+
+# Other free text items describing the repository. There is no restriction 
+# on the number of items, or item names
+# The format is like the following:
+# oaiinfo "item name" "item value"
+# Examples may include sponsor, purpose, size...
+
+# A list of collections that should be made available to OAI clients. By
+# default, collections are not available.
+# There can be more than one line: each line must start with oaicollection, 
+# and this is followed by one or more collection names. The collection name 
+# is the name of the collection's folder in the collect directory.
+oaicollection demo oai-e 
+
+# Metadata mapping information. At present, Greenstone's OAI server only
+# supports the Dublin Core metadata format. Metadata in other formats must 
+# be mapped to Dublin Core. This can be done in this file, or for a 
+# particular collection, in its collect.cfg file.
+
+# The format is like
+# oaimapping <greenstone fieldname> <oaifieldname>
+
+# As Greenstone's OAI server only supports Dublin Core, the oai fieldnames 
+# should be like dc.Title, dc.Subject etc.
+# The Greenstone field names can be unqualified (Title, Subject) or 
+# qualified by a namespace (dc.Title, dls.Subject). These mapping rules 
+# will apply to the entire repository. Collection specific rules can also 
+# be specified in this file using a collection name qualifier. This is 
+# the collection name followed by a colon (demo:Title, demo:dls.Title). 
+# Mappings specified in a collect.cfg file do not need the collection 
+# qualifier.
+
+# Details about the Dublin Core metadata format can be found at
+# http://dublincore.org/
+# Elements include Title, Creator, Subject, Description, Publisher, 
+# Contributor, Date, Type, Format, Identifier, Source, Language, 
+# Relation, Coverage, Rights
+
+# mappings for the demo collection
+oaimapping demo:dls.Title dc.Title
+oaimapping demo:dls.Subject dc.Subject
+oaimapping demo:dls.Language dc.Language
+oaimapping demo:dls.Organization dc.Publisher
+
+# mappings for the oai-e collection
+oaimapping oai-e:Title dc.Title
+oaimapping oai-e:Creator dc.Creator
+oaimapping oai-e:Subject dc.Subject
+oaimapping oai-e:Description dc.Description
+oaimapping oai-e:Publisher dc.Publisher
+oaimapping oai-e:Date dc.Date
+oaimapping oai-e:Type dc.Type
+oaimapping oai-e:Format dc.Format
+oaimapping oai-e:Language dc.Language
+oaimapping oai-e:Rights dc.Rights
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/example.dbi
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/example.dbi	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/example.dbi	(revision 10506)
@@ -0,0 +1,85 @@
+# -*- perl -*-
+# This is an example configuration file for greenstone's DBPlug
+# (DataBase plugin).
+#
+# This config file should be a fragment of perl, specifying how to
+# get records out of a database. This uses perl's DBI module, which
+# includes back-ends for mysql, postgresql, comma separated values (CSV),
+# MS Excel, ODBC, sybase, etc...
+#
+# You need to install the separate backends - For example, on debian you
+# need the libdbi-perl base package and then the libdbd-mysql-perl,
+# libdbd-csv-perl, libdbd-pg-perl and/or libdbd-sybase-perl (etc) packages.
+
+
+# debugging. Uncomment this line if you want extra information printed
+# out during greenstone's import process.
+#
+$dbplug_debug=1;
+
+
+# If these are commented out, then we will use the plugin's defaults.
+# However, you might want to override them here if you know what they
+# are for this particular database
+# run "$ pluginfo.pl DBPlug | less" to see a list of valid encodings
+# Language metadata isn't really necessary unless you want indexes by language
+# However, Encoding is important, for converting data to utf8
+#
+$language = "en";
+$encoding = "iso_8859_1";
+
+
+# Data Source.
+# This is going to be dependent on which back-end you use.
+# Eg, for postgres, it is "DBI:Pg:dbname=<database>".
+# For mysql, it might look like "DBI:mysql:database=<database>;host=localhost"
+# Case is important!
+#
+#$db='';
+
+# If you need a username and password to connect to this database,
+# uncomment these lines and fill in the details
+#
+#$username='';
+#$password='';
+
+# sql query required to get your rows out of the database. Each row will
+# become a separate greenstone document.
+#
+#$sql_query = 'SELECT id, name,  data FROM table1 JOIN table2 WHERE something';
+
+
+# a map of database field names to Greenstone metadata field names.
+# You should have a "Title" field and a "text" field, at a minimum.
+# If you want to give records a unique identifier from a database field
+# rather than have greenstone perform a hash on the document, also provide
+# an "Identifier" metadata field.
+# If you do map something to Identifier, make sure that the field is unique
+# for each record, and also note that because greenstone does special things
+# if this field is only numeric, DBPlug will add some letters to the front
+# if this is the case.
+#
+#%db_to_greenstone_fields=(
+#			  "name" => "Title",
+#			  "data" => "text",
+#			  "id" => "Identifier"
+#			  );
+
+
+# finally, you can declare subroutines here to post-process the fields
+# in case you want to do any mark up or processing of it. 
+# For example, you might want to do HTML formatting.
+# The subroutine's name should be the greenstone metadata field name,
+# followed by "_callback", and must end with "}" in the first column.
+#
+#sub text_callback {
+#    my $text=shift;
+#    # do markup stuff...
+#    return $text;
+#}
+#
+#sub Title_callback {
+#    my $title=shift;
+#    return ucfirst($title); # uppercase first letter
+#}
+
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/phind/stopword/en/brown.sw
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/phind/stopword/en/brown.sw	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/phind/stopword/en/brown.sw	(revision 10506)
@@ -0,0 +1,2009 @@
+a
+aah
+aback
+abed
+abjectly
+ablaze
+ably
+abnormally
+aboard
+about
+abreast
+abroad
+abroade
+abruptly
+absently
+absentmindedly
+absolutely
+abstractly
+absurdly
+abundantly
+academically
+accidentally
+according
+accordingly
+accurately
+accusingly
+acourse
+acoustically
+across
+actively
+actually
+actuarially
+acutely
+adamantly
+additionally
+adequately
+administratively
+admirably
+admiringly
+admittedly
+adrift
+advantageously
+adversely
+advisedly
+afar
+affectingly
+affectionately
+affirmatively
+afield
+afloat
+afoot
+aforethought
+afresh
+after
+afterward
+afterwards
+aftuh
+again
+against
+agayne
+aggressively
+agilely
+agin
+ago
+agreeably
+agriculturally
+ah
+ahah
+ahead
+ahem
+ahn
+ai
+aimlessly
+airily
+ajar
+alarmingly
+alas
+albeit
+alertly
+algebraically
+alike
+all
+allegedly
+allso
+almost
+aloft
+alone
+along
+alongside
+aloud
+alreadeh
+already
+also
+alternately
+alternatively
+altho
+although
+altogether
+altruistically
+always
+am
+amazingly
+ambitiously
+ame
+amen
+amicably
+amid
+amidst
+among
+amongst
+amorphously
+amply
+amusedly
+amusingly
+an
+analogously
+analytically
+anatomically
+anciently
+and
+anesthetically
+anew
+angrily
+anhydrously
+ani
+annually
+another
+anti
+anxiously
+any
+anybody
+anye
+anyhow
+anymore
+anyone
+anyplace
+anythin
+anything
+anyway
+anyways
+anywhere
+apart
+apiece
+apologetically
+appallingly
+apparently
+appraisingly
+appreciably
+appreciatively
+apprehensively
+appropriately
+approvingly
+approximately
+aptly
+arbitrarily
+are
+aristocratically
+around
+arrogantly
+artfully
+artificially
+artistically
+as
+asham
+ashore
+aside
+askance
+askew
+asleep
+associatively
+assuredly
+astonishingly
+astray
+astride
+astronomically
+asunder
+asymmetrically
+asymptotically
+at
+atonally
+atop
+atrociously
+att
+atta
+attentively
+attractively
+audibly
+aurally
+auspiciously
+austerely
+authentically
+authoritatively
+automatically
+avidly
+aw
+away
+awaye
+awfully
+awhile
+awkwardly
+axially
+aye
+backstage
+backstairs
+backward
+backwards
+badly
+bah
+bannnnnng
+barely
+basically
+be
+beautifully
+because
+beefore
+been
+befoh
+before
+beforehand
+behahn
+behaviorally
+behind
+bein
+being
+beinge
+belatedly
+believably
+belligerently
+below
+beneath
+beside
+besides
+between
+bewilderedly
+bewilderingly
+beyond
+bi
+billion
+biologically
+bitterly
+blandly
+bleakly
+blindly
+blissfully
+blithely
+bluntly
+boastfully
+bodily
+boldly
+bong
+both
+bravely
+brazenly
+breathlessly
+briefly
+brightly
+brilliantly
+briskly
+broadly
+brokenly
+brusquely
+brutally
+busily
+but
+by
+callously
+calmly
+can
+candidly
+cannot
+capably
+carefully
+carelessly
+casually
+catastrophically
+categorically
+causally
+cautiously
+ceaselessly
+centrally
+ceremonially
+ceremoniously
+certainly
+characteristically
+charmingly
+cheaply
+cheerfully
+chemically
+chiefly
+childishly
+chronically
+chronologically
+circa
+circumspectly
+clairaudiently
+classically
+cleanly
+clearly
+cleverly
+clinically
+clockwise
+closely
+clumsily
+coarsely
+cogently
+cohesively
+colde
+coldly
+collectively
+comfortably
+comically
+commercially
+commonly
+compactly
+comparatively
+compassionately
+competently
+competitively
+completely
+comprehensively
+compulsively
+concededly
+conceivably
+conceptually
+concerning
+conclusively
+concretely
+concurrently
+confidentially
+confidently
+consanguineously
+consciously
+consequently
+considerably
+considerately
+consisently
+consistently
+conspicuously
+constantly
+constructively
+consummately
+contemptuously
+contentedly
+continentally
+continually
+continuously
+contradictorily
+contrarily
+conveniently
+conventionally
+conversely
+convincingly
+convulsively
+coolly
+copiously
+correctly
+correlatively
+correspondingly
+cortically
+cosily
+coud
+coudn
+could
+courageously
+courteously
+covertly
+coyly
+crazily
+creatively
+credibly
+crisply
+critically
+crossways
+crosswise
+crucially
+crudely
+cruelly
+culturally
+cunningly
+curiously
+currently
+curtly
+curvaceously
+customarily
+cynically
+d
+da
+daintily
+dammit
+damnit
+dandily
+dangerously
+darkly
+dearly
+deathly
+decently
+deceptively
+decidedly
+decisively
+deeply
+defiantly
+definitely
+dejectedly
+deliberately
+delicately
+deliciously
+delightfully
+demandingly
+demonstrably
+denominationally
+depending
+deplorably
+depressingly
+dere
+derisively
+despairingly
+desperately
+despite
+determinedly
+devastatingly
+devotedly
+devoutly
+dey
+diagonally
+dialectically
+diametrically
+did
+diddle
+didn
+differently
+diffusely
+diligently
+dimensionally
+dimly
+directionally
+directly
+disapprovingly
+disconcertingly
+discordantly
+discreetly
+dismally
+dispassionately
+disproportionately
+distally
+distantly
+distastefully
+distinctively
+distinctly
+distractedly
+disturbingly
+divinely
+dizzily
+do
+doan
+docilely
+doctrinally
+does
+doggedly
+doggone
+dogmatically
+domestically
+dominantly
+doo
+dost
+doubly
+doubtfully
+doubtingly
+doubtless
+dourly
+down
+downright
+downstairs
+downwind
+dramatically
+drastically
+dreadfully
+dreamlessly
+drowsily
+drunkenly
+druther
+dryly
+dully
+duly
+during
+dutifully
+dynamically
+each
+eagerly
+earnestly
+easily
+eastward
+eclectically
+economically
+edgewise
+editorially
+eerily
+effectively
+efficaciously
+efficiently
+effortlessly
+egregiously
+eh
+eight
+eighteen
+eighteenth
+eighth
+eighty
+either
+elaborately
+electrically
+elegantly
+eleven
+eleventh
+eloquently
+else
+elsewhere
+em
+embarrassingly
+eminently
+emotionally
+emphatically
+empirically
+enchantingly
+encouragingly
+endlessly
+enduringly
+energetically
+engagingly
+enny
+enormously
+enough
+enterprisingly
+enthusiastically
+entirely
+enviably
+enviously
+epicyclically
+equally
+equidistantly
+equitably
+ere
+erotically
+erratically
+erroneously
+especially
+essentially
+etcetera
+ether
+ethically
+evenly
+eventfully
+eventshahleh
+eventually
+evenutally
+ever
+everlastingly
+every
+everybody
+everyone
+everything
+everywhere
+evidently
+exactly
+exasperatingly
+exceedingly
+excellently
+except
+excepting
+exceptionally
+excessively
+excitedly
+excluding
+exclusively
+exhaustingly
+exhaustively
+expansively
+expectantly
+expectedly
+expeditiously
+experientially
+experimentally
+expertly
+explicitly
+explosively
+expressly
+exquisitely
+extempore
+extensively
+externally
+extraordinarily
+extremely
+exuberantly
+exultantly
+facetiously
+faintly
+fairly
+faithfully
+familiarly
+fantastically
+farther
+fascinatingly
+fatally
+favorably
+fearfully
+fearlessly
+feebly
+fer
+ferociously
+fervently
+feverishly
+few
+fewer
+fiercely
+fifteen
+fifteenth
+fifth
+fiftieth
+fifty
+finally
+financially
+finely
+firmly
+first
+fitfully
+five
+flagrantly
+flamboyantly
+flatly
+flatteringly
+fluently
+focally
+foh
+fondly
+foolishly
+for
+forcibly
+foremost
+forever
+formally
+former
+formerly
+formidably
+forth
+forthrightly
+fortunately
+forty
+foully
+four
+fourteen
+fourteenth
+fourth
+fragmentarily
+frankly
+frantically
+freely
+frenziedly
+frequently
+freshly
+friendlily
+frighteningly
+frightfully
+from
+frowningly
+frugally
+fruitfully
+fruitlessly
+fully
+functionally
+fundamentally
+furiously
+furthermore
+furtively
+fussily
+futhermore
+gaily
+gaspingly
+gawdamighty
+generally
+generously
+gently
+genuinely
+geographically
+geometrically
+girlishly
+gladly
+glaringly
+gleefully
+glibly
+globally
+gloomily
+gloriously
+glumly
+godamit
+goddamit
+goddammit
+golly
+goodbye
+goodnight
+goody
+goolick
+goooolick
+gorgeously
+gosh
+governmentally
+gracefully
+graciously
+gradually
+grammatically
+grandly
+graphically
+gratefully
+gratifyingly
+gratingly
+gratis
+gratuitously
+gravely
+greatly
+greedily
+greenly
+grevouselye
+grimly
+grossly
+grotesquely
+grudgingly
+ha
+habitually
+had
+hadd
+haf
+haggardly
+haint
+half
+halfways
+haltingly
+handsomely
+haphazardly
+happily
+harder
+hardly
+harmlessly
+harmoniously
+harro
+harshly
+has
+hast
+hastily
+hath
+haughtily
+have
+having
+he
+healthily
+heartily
+heatedly
+heavily
+hello
+helpfully
+helplessly
+hence
+henceforth
+henh
+her
+here
+hereabouts
+hereafter
+hereby
+herein
+hereinafter
+heretofore
+hereunto
+herewith
+heroically
+hers
+herself
+hesitantly
+hesitatingly
+hev
+hevin
+hey
+hi
+hideously
+highly
+hilariously
+him
+himself
+himselfe
+hir
+his
+hisself
+historically
+hither
+hitherto
+hmpf
+hoarsely
+homeward
+homewards
+homogeneously
+honestly
+honorably
+hopefully
+hopelessly
+horizontally
+horribly
+horrifyingly
+hotly
+how
+howe
+however
+howsomever
+hubba
+huh
+humanely
+humanly
+humbly
+humiliatingly
+hundred
+hundredth
+hurriedly
+huskily
+hydraulically
+hym
+hyperbolically
+hypnotically
+hypothalamically
+hys
+hytt
+ideally
+identically
+idiotically
+idly
+if
+illegally
+imaginatively
+immeasurably
+immediately
+immensely
+impassively
+impatiently
+impeccably
+imperceptibly
+imperfectly
+imperiously
+impersonally
+implausibly
+implicitly
+importantly
+importunately
+impossibly
+imprecisely
+improbably
+improperly
+imprudently
+impudently
+in
+inadequately
+inadvertently
+inasmuch
+incessantly
+incidentally
+including
+incoherently
+incomparably
+incompletely
+inconspicuously
+inconveniently
+increasingly
+incredibly
+incredulously
+incurably
+indecisively
+indeed
+indefinitely
+indelibly
+independently
+indignantly
+indirectly
+indiscriminantly
+indisputably
+individually
+indolently
+indoors
+industrially
+industriously
+ineffectively
+ineptly
+inescapably
+inevitably
+inexorably
+inexplicably
+inexpressibly
+infernally
+infinitely
+infinitesimally
+informally
+infra
+infrequently
+ingeniously
+inherently
+initially
+inland
+innocently
+inordinately
+insanely
+insidiously
+insofar
+insolently
+insomma
+instantaneously
+instantly
+instead
+instinctively
+instrumentally
+insufficiently
+insuperably
+intellectually
+intelligently
+intensely
+intensively
+intentionally
+intently
+interestingly
+intermittently
+internally
+internationally
+intimately
+into
+intramuscularly
+intricately
+intriguingly
+intrinsically
+intuitively
+invariably
+inversely
+invisibly
+involuntarily
+inwardly
+ironically
+irrationally
+irredeemably
+irregularly
+irreparably
+irresistibly
+irreversibly
+irrevocably
+irritably
+is
+isothermally
+it
+its
+itself
+jaggedly
+jealously
+jist
+jocularly
+jointly
+joyfully
+joyously
+jubilantly
+judiciously
+july
+jurisprudentially
+justifiably
+justly
+kaboom
+keenly
+kin
+kinda
+kinesthetically
+knowingly
+laboriously
+lahk
+lak
+largely
+last
+lastly
+lately
+latter
+laudably
+laughingly
+lavishly
+lazily
+least
+legally
+legitimately
+lengthily
+less
+lest
+lewdly
+liberally
+lightly
+likewise
+limply
+linearly
+linguistically
+listlessly
+literally
+litle
+lo
+locally
+logically
+loosely
+lopsidedly
+loudly
+lovingly
+luckily
+lustily
+m
+macroscopically
+madly
+magically
+magnetically
+magnificently
+mah
+maht
+mai
+mainly
+majestically
+maliciously
+manifestly
+manually
+many
+manye
+marginally
+markedly
+marketwise
+marvelously
+masterfully
+materially
+mathematically
+may
+maybe
+maye
+mayst
+me
+meaningfully
+meanwhile
+measurably
+mechanically
+mechanochemically
+medically
+mee
+meekly
+melodically
+mentally
+mercifully
+mercilessly
+merely
+merrily
+methodically
+meticulously
+metrically
+microscopically
+midway
+might
+mightily
+mildly
+militantly
+militarily
+million
+mimetically
+mine
+minimally
+minus
+minutely
+miraculously
+miserably
+mistakenly
+mmm
+mmmm
+mockingly
+moderately
+modestly
+momentarily
+monolithically
+monumentally
+moodily
+mor
+morally
+more
+moreover
+morosely
+mortally
+most
+mostly
+mountainously
+mournfully
+movingly
+much
+municipally
+musically
+must
+mutely
+mutually
+my
+myn
+myne
+myself
+mysteriously
+n
+na
+nae
+naively
+nakedly
+namely
+narrowly
+nary
+natch
+nationally
+naturally
+naught
+naw
+nawt
+nay
+nearly
+nearsightedly
+neatly
+necessarily
+needlessly
+negatively
+neither
+nervously
+nether
+never
+nevertheless
+next
+nicely
+nigh
+nightly
+nilly
+nimbly
+nine
+nineteen
+nineteenth
+ninetieth
+ninety
+ninth
+no
+nobody
+noisily
+nominally
+noncommittally
+nondescriptly
+none
+nonetheless
+nonspecifically
+nope
+nor
+normally
+northward
+nostalgically
+not
+notably
+noth
+nothin
+nothing
+noticeably
+notoriously
+nott
+notwithstanding
+now
+nowadays
+nowhere
+nuf
+numbingly
+numerically
+o
+objectively
+obligingly
+obliquely
+obscurely
+obviously
+occasionally
+octillion
+oddly
+of
+off
+offensively
+officially
+offstage
+oft
+often
+oftener
+oftentimes
+oh
+okay
+ominously
+on
+once
+onct
+one
+oneself
+onleh
+only
+onto
+ontologically
+onward
+onwards
+oooo
+oops
+openly
+operationally
+optically
+or
+orally
+ordinarily
+organically
+organizationally
+originally
+ornately
+ostensibly
+other
+otherwise
+ought
+our
+ours
+ourselves
+out
+outdoors
+outstandingly
+outwardly
+over
+overboard
+overland
+overly
+overtly
+overwhelmingly
+ovuh
+owly
+ownself
+painfully
+painlessly
+painstakingly
+palely
+palpably
+paradoxically
+parenthetically
+partially
+particularly
+partly
+passionately
+passively
+paternally
+patiently
+peacefully
+peculiarly
+per
+perchance
+perennially
+perfectly
+perforce
+perfunctorily
+perhaps
+perilously
+periodically
+peripherally
+permanently
+perpendicularly
+perpetually
+persistently
+personally
+persuasively
+pervasively
+perversely
+philosophically
+photographically
+physically
+physiologically
+pictorially
+piecewise
+pinkly
+piously
+pip
+pitifully
+pitilessly
+pityingly
+plainly
+plastically
+pleasantly
+pleasingly
+plumb
+plus
+poetically
+poignantly
+pointedly
+politely
+politically
+pompously
+poorly
+popularly
+positively
+possibly
+potentially
+powerfully
+practically
+prayerfully
+precariously
+precisely
+precociously
+predictably
+predominantly
+predominately
+preferably
+preferentially
+prematurely
+preponderantly
+presente
+presently
+presentlye
+presumably
+prettily
+pretty
+previously
+primarily
+primly
+principally
+privately
+probably
+probly
+prodigally
+professedly
+professionally
+profitably
+profoundly
+profusely
+progressively
+prominently
+promptly
+pronto
+properly
+prophetically
+proportionally
+proportionately
+protectively
+proudly
+provocatively
+prudentially
+prudently
+psychically
+psychologically
+publically
+publicly
+pugh
+punctually
+pungently
+purely
+purportedly
+purposefully
+purposely
+purposively
+pursuant
+quadrillion
+qualitatively
+quantitatively
+querulously
+questioningly
+quickly
+quietly
+quintillion
+quite
+quitely
+racially
+radically
+rakishly
+randomly
+rapidly
+rarely
+rather
+rationally
+raucously
+readily
+realistically
+really
+reasonably
+reassuringly
+rebelliously
+recently
+recklessly
+rectlinearly
+recurrently
+reflexly
+refreshingly
+regarding
+regardless
+regionally
+regretfully
+regrettably
+regularly
+relatively
+relentlessly
+reliably
+religiously
+reluctantly
+remarkably
+remotely
+repeatedly
+reportedly
+reproducibly
+reprovingly
+reputedly
+residentially
+resignedly
+resolutely
+resourcefully
+respectfully
+respectively
+responsibly
+responsively
+restively
+restlessly
+reverently
+rhythmically
+richly
+ridiculously
+rightfully
+rightly
+rigidly
+rigorously
+rollickingly
+romantically
+rotationally
+roughly
+roughtly
+roundly
+routinely
+rudely
+ruefully
+ruggedly
+ruthlessly
+sadly
+safely
+same
+sarcastically
+satirically
+satisfactorily
+savagely
+scarcely
+scathingly
+schematically
+scholastically
+scientifically
+scornfully
+scrupulously
+searchingly
+seasonally
+second
+secondarily
+secondly
+secretly
+securely
+sedately
+sedulously
+seekingly
+seemingly
+seldom
+selectively
+semantically
+senselessly
+sensibly
+sensitively
+separately
+septillion
+serenely
+seriously
+seven
+seventeen
+seventeenth
+seventh
+seventy
+several
+severally
+severely
+severly
+sextillion
+sexually
+sha
+shabbily
+shakily
+shall
+shamefacedly
+sharply
+shatteringly
+she
+shh
+shiningly
+shockingly
+shortly
+should
+shrewdly
+shrilly
+shucks
+shuld
+shulde
+shyly
+sidewise
+signally
+significantly
+silently
+similarly
+simply
+simultaneously
+since
+sincerely
+single
+singlehandedly
+singly
+singularly
+sinuously
+six
+sixteen
+sixteenth
+sixth
+sixty
+skeptically
+skilfully
+skillfully
+sleepily
+sleeplessly
+slightly
+slimly
+sloppily
+slowly
+sluggishly
+slyly
+smartly
+smilingly
+smolderingly
+smoothly
+snobbishly
+snugly
+so
+sobbingly
+soberly
+socially
+sociologically
+soddenly
+soe
+sofar
+softly
+solely
+solemnly
+solidly
+some
+somebody
+someday
+somehow
+someone
+someplace
+somethin
+something
+sometime
+sometimes
+somewhat
+somewhere
+somewheres
+sompin
+sonuvabitch
+soon
+sooner
+soothingly
+sorely
+soulfully
+soundly
+sourly
+sparsely
+spatially
+specially
+specifically
+spectacularly
+spectrally
+speculatively
+speedily
+spiritually
+splendidly
+spontaneously
+squarely
+sssshoo
+staggeringly
+starkly
+startlingly
+statistically
+steadfastly
+steadily
+stealthily
+steamily
+steeply
+sternly
+stiffly
+stirringly
+stolidly
+stonily
+stoutly
+straightway
+strangely
+strategically
+strenuously
+strictly
+strikingly
+stringently
+strongly
+structurally
+stubbornly
+studiously
+stunningly
+stupidly
+subconsciously
+subjectively
+subsequently
+substantially
+substantively
+subtly
+successfully
+successively
+succinctly
+suddenly
+sufficiently
+suitably
+sulkily
+sullenly
+superbly
+superficially
+supinely
+supposedly
+supposing
+supra
+supremely
+surely
+surprisingly
+surreptitiously
+suspiciously
+sweepingly
+sweetly
+swiftly
+sycophantically
+symbolically
+symmetrically
+sympathetically
+synce
+syntactically
+systematically
+ta
+tacitly
+tactically
+tactually
+tangibly
+tantalizingly
+tarantara
+tardily
+tartly
+tauntingly
+tearfully
+technically
+technologically
+tediously
+telepathically
+temperately
+temporally
+temporarily
+temptingly
+ten
+tenaciously
+tenderly
+tenfold
+tensely
+tentatively
+tenth
+tenuously
+terribly
+tersely
+testily
+than
+thar
+that
+thatt
+thay
+the
+theare
+thease
+theatrically
+thee
+thees
+thei
+their
+theirs
+them
+themselves
+thence
+thenceforth
+theoretically
+ther
+there
+thereabouts
+thereafter
+thereby
+therefor
+therefore
+therefrom
+therein
+thereof
+thereon
+thereto
+theretofore
+thereunder
+thereupon
+therewith
+thermally
+thermodynamically
+these
+thet
+they
+thickly
+thine
+thinly
+third
+thirdly
+thirteen
+thirteenth
+thirtieth
+thirty
+this
+thither
+thoroughly
+those
+thou
+though
+thoughtfully
+thoughtlessly
+thousand
+thousandth
+threateningly
+three
+thrice
+through
+throughout
+thru
+thum
+thus
+thy
+tighter
+tightly
+till
+timidly
+tiredly
+tirelessly
+to
+together
+tonally
+too
+totally
+toward
+towardes
+towards
+traditionally
+tragically
+transversally
+transversely
+tremendously
+tremulously
+trillion
+triumphantly
+truly
+trustfully
+trustingly
+truthfully
+tunelessly
+twelfth
+twelve
+twentieth
+twenty
+twice
+twirlingly
+twise
+two
+typically
+u
+ugh
+uh
+uhhu
+ultimately
+ultracentrifugally
+ultrasonically
+um
+umm
+unaccountably
+unambiguously
+unanimously
+unappeasably
+unashamedly
+unavoidably
+unbearably
+unbelievably
+unblinkingly
+unceasingly
+uncertainly
+uncomfortably
+uncommonly
+uncomplainingly
+unconcernedly
+unconditionally
+unconsciously
+uncritically
+undeniably
+underfoot
+underneath
+understandably
+understandingly
+underway
+undoubtedly
+unduly
+uneasily
+unequally
+unequivocally
+unerringly
+unexpectedly
+unfailingly
+unfairly
+unfalteringly
+unfortunately
+unfunnily
+unhappily
+unhesitatingly
+unhurriedly
+uniformly
+unilaterally
+unimpeachably
+unintentionally
+uninterruptedly
+uniquely
+universally
+unknowingly
+unless
+unlike
+unluckily
+unmanageably
+unmistakably
+unnaturally
+unnecessarily
+unnnt
+unobtrusively
+unofficially
+unpleasantly
+unpredictably
+unqualifiedly
+unquestionably
+unquestioningly
+unrealistically
+unreasonably
+unreassuringly
+unreservedly
+unrestrictedly
+unselfishly
+unsmilingly
+unsteadily
+unsuccessfully
+unsuitably
+until
+unto
+unusually
+unutterably
+unwaveringly
+unwillingly
+unwisely
+unwittingly
+up
+upon
+uppermost
+uppon
+uproariously
+upside
+upstate
+upwards
+urgently
+us
+usefully
+uselessly
+usually
+utterly
+vaguely
+vainly
+valiantly
+validly
+variously
+vastly
+vehemently
+verbally
+verbatim
+verie
+versa
+versus
+vertically
+very
+via
+victoriously
+vigorously
+violently
+virtually
+visibly
+visually
+vitally
+vividly
+vocally
+vocationally
+vociferously
+volumetrically
+voluntarily
+voraciously
+warily
+warmly
+warningly
+was
+waspishly
+we
+weakly
+wearily
+wee
+weirdly
+were
+westward
+westwards
+wetly
+whad
+what
+whatever
+whatsoever
+wheare
+when
+whence
+whenever
+wher
+where
+whereas
+whereby
+whereever
+wherefore
+wherein
+whereon
+whereupon
+wherever
+wherewith
+whether
+which
+whichever
+whitely
+who
+whoe
+whoever
+wholeheartedly
+wholly
+whom
+whoosh
+whose
+whosoever
+why
+wickedly
+widely
+wil
+wildly
+wilfully
+will
+willfully
+willingly
+willy
+wilt
+wisely
+wistfully
+with
+withal
+within
+without
+wittingly
+wod
+woefully
+wold
+wolde
+wolfishly
+wonderfully
+wonderingly
+wondrously
+wordlessly
+worriedly
+would
+wow
+wrongly
+wryly
+wuh
+ya
+ye
+yea
+yeah
+yearningly
+yehhh
+yes
+yesiree
+yet
+yff
+yon
+yonder
+yooee
+you
+your
+yours
+yourself
+yourselves
+yow
+ys
+yuh
+zealously
+zero
+zoooop
+zounds
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/phind/stopword/fr/JASIS.sw
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/phind/stopword/fr/JASIS.sw	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/phind/stopword/fr/JASIS.sw	(revision 10506)
@@ -0,0 +1,215 @@
+a
+afin
+ai
+ainsi
+aprÃšs
+attendu
+au
+aujourd
+auquel
+aussi
+autre
+autres
+aux
+auxquelles
+auxquels
+avait
+avant
+avec
+avoir
+c
+car
+ce
+ceci
+cela
+celle
+celles
+celui
+cependant
+certain
+certaine
+certaines
+certains
+ces
+cet
+cette
+ceux
+chez
+ci
+combien
+comme
+comment
+concernant
+contre
+d
+dans
+de
+debout
+dedans
+dehors
+delÃ 
+depuis
+derriÃšre
+des
+desquelles
+desquels
+dessous
+dessus
+devant
+devers
+devra
+divers
+diverse
+diverses
+doit
+donc
+dont
+du
+duquel
+durant
+dÃšs
+elle
+elles
+en
+entre
+environ
+est
+et
+etc
+etre
+eux
+exceptÃ©
+hormis
+hors
+hui
+hÃ©las
+il
+ils
+j
+je
+jusqu
+jusque
+l
+la
+laquelle
+le
+lequel
+les
+lesquelles
+lesquels
+leur
+leurs
+lorsque
+lui
+lÃ 
+ma
+mais
+malgrÃ©
+me
+merci
+mes
+mien
+mienne
+miennes
+miens
+moi
+moins
+mon
+moyennant
+mÃªme
+mÃªmes
+n
+ne
+ni
+non
+nos
+notre
+nous
+nÃ©anmoins
+nÃŽtre
+nÃŽtres
+on
+ou
+out
+outre
+oÃ¹
+par
+parmi
+partant
+pas
+passÃ©
+pendant
+plein
+plus
+plusieurs
+pour
+pourquoi
+proche
+prÃšs
+puisque
+qu
+quand
+que
+quel
+quelle
+quelles
+quels
+qui
+quoi
+quoique
+revoici
+revoilÃ 
+s
+sa
+sans
+sauf
+se
+selon
+seront
+ses
+si
+sien
+sienne
+siennes
+siens
+sinon
+soi
+soit
+son
+sont
+sous
+suivant
+sur
+ta
+te
+tes
+tien
+tienne
+tiennes
+tiens
+toi
+ton
+tous
+tout
+toute
+toutes
+tu
+un
+une
+va
+vers
+voici
+voilÃ 
+vos
+votre
+vous
+vu
+vÃŽtre
+vÃŽtres
+y
+Ã 
+Ã§a
+Ãšs
+Ã©tÃ©
+Ãªtre
+ÃŽ
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/ansi.gen
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/ansi.gen	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/ansi.gen	(revision 10506)
@@ -0,0 +1,215 @@
+# RTF ANSI character set (\ansi) general map
+# These are taken from the ISO-Latin-1 (ISO-8859-1) encodings, with
+# a few additions
+
+# Field 1 is the standard character name which the character value in
+# field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+# use the value in field 2.)
+# jrm21 - ie, given the input in field 2, what name do we use for it?
+
+# The character value may be given either as a single character (which will be
+# converted to the ASCII value of the character), or in numeric format, either
+# in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+# characters.
+
+# characters in ASCII range (00-127)
+
+formula		0x06
+nobrkhyphen	0x1e
+opthyphen	0x1f
+
+space		" "
+exclam		!
+quotedbl	'"'
+numbersign	#
+dollar		$
+percent		%
+ampersand	&
+quoteright	"'"
+parenleft	(
+parenright	)
+asterisk	*
+plus		+
+comma		,
+hyphen		-
+period		.
+slash		/
+zero		0
+one		1
+two		2
+three		3
+four		4
+five		5
+six		6
+seven		7
+eight		8
+nine		9
+colon		:
+semicolon	;
+less		<
+equal		=
+greater		>
+question	?
+at		@
+A		A
+B		B
+C		C
+D		D
+E		E
+F		F
+G		G
+H		H
+I		I
+J		J
+K		K
+L		L
+M		M
+N		N
+O		O
+P		P
+Q		Q
+R		R
+S		S
+T		T
+U		U
+V		V
+W		W
+X		X
+Y		Y
+Z		Z
+bracketleft	[
+backslash	\
+bracketright	]
+asciicircum	^
+underscore	_
+quoteleft	"`"
+a		a
+b		b
+c		c
+d		d
+e		e
+f		f
+g		g
+h		h
+i		i
+j		j
+k		k
+l		l
+m		m
+n		n
+o		o
+p		p
+q		q
+r		r
+s		s
+t		t
+u		u
+v		v
+w		w
+x		x
+y		y
+z		z
+braceleft	{
+bar		|
+braceright	}
+asciitilde	~
+
+# non-ASCII characters (128-255)
+null		0x80
+
+nobrkspace	0xa0
+exclamdown	0xa1
+cent		0xa2
+sterling	0xa3
+currency	0xa4
+yen		0xa5
+brokenbar	0xa6
+section		0xa7
+dieresis	0xa8
+copyright	0xa9
+ordfeminine	0xaa
+guillemotleft	0xab
+logicalnot	0xac
+opthyphen	0xad
+registered	0xae
+macron		0xaf
+degree		0xb0
+plusminus	0xb1
+twosuperior	0xb2
+threesuperior	0xb3
+acute		0xb4
+mu		0xb5
+paragraph	0xb6
+periodcentered	0xb7
+cedilla		0xb8
+onesuperior	0xb9
+ordmasculine	0xba
+guillemotright	0xbb
+onequarter	0xbc
+onehalf		0xbd
+threequarters	0xbe
+questiondown	0xbf
+Agrave		0xc0
+Aacute		0xc1
+Acircumflex	0xc2
+Atilde		0xc3
+Adieresis	0xc4
+Aring		0xc5
+AE		0xc6
+Ccedilla	0xc7
+Egrave		0xc8
+Eacute		0xc9
+Ecircumflex	0xca
+Edieresis	0xcb
+Igrave		0xcc
+Iacute		0xcd
+Icircumflex	0xce
+Idieresis	0xcf
+Eth		0xd0
+Ntilde		0xd1
+Ograve		0xd2
+Oacute		0xd3
+Ocircumflex	0xd4
+Otilde		0xd5
+Odieresis	0xd6
+multiply	0xd7
+Oslash		0xd8
+Ugrave		0xd9
+Uacute		0xda
+Ucircumflex	0xdb
+Udieresis	0xdc
+Yacute		0xdd
+Thorn		0xde
+germandbls	0xdf
+agrave		0xe0
+aacute		0xe1
+acircumflex	0xe2
+atilde		0xe3
+adieresis	0xe4
+aring		0xe5
+ae		0xe6
+ccedilla	0xe7
+egrave		0xe8
+eacute		0xe9
+ecircumflex	0xea
+edieresis	0xeb
+igrave		0xec
+iacute		0xed
+icircumflex	0xee
+idieresis	0xef
+eth		0xf0
+ntilde		0xf1
+ograve		0xf2
+oacute		0xf3
+ocircumflex	0xf4
+otilde		0xf5
+odieresis	0xf6
+divide		0xf7
+oslash		0xf8
+ugrave		0xf9
+uacute		0xfa
+ucircumflex	0xfb
+udieresis	0xfc
+yacute		0xfd
+thorn		0xfe
+ydieresis	0xff
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/ansi.sym
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/ansi.sym	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/ansi.sym	(revision 10506)
@@ -0,0 +1,114 @@
+# RTF ANSI character set (\ansi) Symbol font map
+
+# Field 1 is the standard character name which the character value in
+# field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+# use the value in field 2.)
+
+# The character value may be given either as a single character (which will be
+# converted to the ASCII value of the character), or in numeric format, either
+# in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+# characters.
+
+# characters in ASCII range (00-127)
+
+formula		0x06
+nobrkhyphen	0x1e
+opthyphen	0x1f
+
+space		" "
+exclam		!
+universal	'"'
+mathnumbersign	#
+existential	$
+percent		%
+ampersand	&
+suchthat	"'"
+parenleft	(
+parenright	)
+mathasterisk	*
+mathplus	+
+comma		,
+mathminus	-
+period		.
+slash		/
+zero		0
+one		1
+two		2
+three		3
+four		4
+five		5
+six		6
+seven		7
+eight		8
+nine		9
+colon		:
+semicolon	;
+less		<
+mathequal	=
+greater		>
+question	?
+congruent	@
+Alpha		A
+Beta		B
+Chi		C
+Delta		D
+Epsilon		E
+Phi		F
+Gamma		G
+Eta		H
+Iota		I
+# J		J
+Kappa		K
+Lambda		L
+Mu		M
+Nu		N
+Omicron		O
+Pi		P
+Theta		Q
+Rho		R
+Sigma		S
+Tau		T
+Upsilon		U
+varsigma	V
+Omega		W
+Xi		X
+Psi		Y
+Zeta		Z
+bracketleft	[
+backslash	\
+bracketright	]
+asciicircum	^
+underscore	_
+quoteleft	"`"
+alpha		a
+beta		b
+chi		c
+delta		d
+epsilon		e
+phi		f
+gamma		g
+eta		h
+iota		i
+# j		j
+kappa		k
+lambda		l
+mu		m
+nu		n
+omicron		o
+pi		p
+theta		q
+rho		r
+sigma		s
+tau		t
+upsilon		u
+# xxx		v
+omega		w
+xi		x
+psi		y
+zeta		z
+braceleft	{
+bar		|
+braceright	}
+mathtilde	~
+
+# non-ASCII characters (128-255)
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/cpg1252.gen
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/cpg1252.gen	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/cpg1252.gen	(revision 10506)
@@ -0,0 +1,244 @@
+# RTF Windows Codepage-1252 character set (\ansi) general map
+# Note (jrm21) - this is basically a modified version of the ANSI map.
+
+# Field 1 is the standard character name which the character value in
+# field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+# use the value in field 2.)
+
+# The character value may be given either as a single character (which will be
+# converted to the ASCII value of the character), or in numeric format, either
+# in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+# characters.
+
+# printable characters in ASCII range (00-127)
+
+formula		0x06
+nobrkhyphen	0x1e
+opthyphen	0x1f
+
+space		" "	# 0x20
+exclam		!	# 0x21
+quotedbl	'"'	# 0x22
+numbersign	#	# 0x23
+dollar		$	# 0x24
+percent		%	# 0x25
+ampersand	&	# 0x26
+quoteright	"'"	# 0x27
+parenleft	(	# 0x28
+parenright	)	# 0x29
+asterisk	*	# 0x2a
+plus		+	# 0x2b
+comma		,	# 0x2c
+hyphen		-	# 0x2d
+period		.	# 0x2e
+slash		/	# 0x2f
+zero		0	# 0x30
+one		1	# 0x31
+two		2	# 0x32
+three		3	# 0x33
+four		4	# 0x34
+five		5	# 0x35
+six		6	# 0x36
+seven		7	# 0x37
+eight		8	# 0x38
+nine		9	# 0x39
+colon		:	# 0x3a
+semicolon	;	# 0x3b
+less		<	# 0x3c
+equal		=	# 0x3d
+greater		>	# 0x3e
+question	?	# 0x3f
+at		@	# 0x40
+A		A	# 0x41
+B		B	# 0x42
+C		C	# 0x43
+D		D	# 0x44
+E		E	# 0x45
+F		F	# 0x46
+G		G	# 0x47
+H		H	# 0x48
+I		I	# 0x49
+J		J	# 0x4a
+K		K	# 0x4b
+L		L	# 0x4c
+M		M	# 0x4d
+N		N	# 0x4e
+O		O	# 0x4f
+P		P	# 0x50
+Q		Q	# 0x51
+R		R	# 0x52
+S		S	# 0x53
+T		T	# 0x54
+U		U	# 0x55
+V		V	# 0x56
+W		W	# 0x57
+X		X	# 0x58
+Y		Y	# 0x59
+Z		Z	# 0x5a
+bracketleft	[	# 0x5b
+backslash	\	# 0x5c
+bracketright	]	# 0x5d
+asciicircum	^	# 0x5e
+underscore	_	# 0x5f
+quoteleft	"`"	# 0x60
+a		a	# 0x61
+b		b	# 0x62
+c		c	# 0x63
+d		d	# 0x64
+e		e	# 0x65
+f		f	# 0x66
+g		g	# 0x67
+h		h	# 0x68
+i		i	# 0x69
+j		j	# 0x6a
+k		k	# 0x6b
+l		l	# 0x6c
+m		m	# 0x6d
+n		n	# 0x6e
+o		o	# 0x6f
+p		p	# 0x70
+q		q	# 0x71
+r		r	# 0x72
+s		s	# 0x73
+t		t	# 0x74
+u		u	# 0x75
+v		v	# 0x76
+w		w	# 0x77
+x		x	# 0x78
+y		y	# 0x79
+z		z	# 0x7a
+braceleft	{	# 0x7b
+bar		|	# 0x7c
+braceright	}	# 0x7d
+asciitilde	~	# 0x7e
+# undefined (delete)	# 0x7f
+
+# non-ASCII characters (128-255)
+euro		0x80
+# undefined	0x81
+quotesinglbase	0x82 # single low-9 quotation mark
+florin		0x83 # f with hook (fnof) ## not sure if florin is right...
+quotedblbase	0x84 # double low-9 quotation mark
+ellipsis	0x85
+dagger		0x86
+daggerdbl	0x87
+circumflex	0x88 # modifier
+perthousand	0x89
+Scaron		0x8a
+guilsinglleft	0x8b
+OE		0x8c # OE ligature
+# undefined	0x8d
+Zcaron		0x8e
+# undefined	0x8f
+# undefined	0x90
+quoteleft	0x91 # single quote left - use ascii for now
+quoteright	0x92 # single quote right - use ascii for now
+quotedblleft	0x93
+quotedblright	0x94
+bullet		0x95
+endash		0x96
+emdash		0x97
+asciitilde	0x98 # use ascii tilde
+trademark	0x99
+scaron		0x9a
+guilsinglright	0x9b # single rightpointing quotemark
+oe		0x9c
+# undefined	0x9d
+zcaron		0x9e
+Ydieresis	0x9f # Y with diaeresis
+nobrkspace	0xa0
+exclamdown	0xa1
+cent		0xa2
+sterling	0xa3
+currency	0xa4
+yen		0xa5
+brokenbar	0xa6
+section		0xa7
+dieresis	0xa8
+copyright	0xa9
+ordfeminine	0xaa
+guillemotleft	0xab
+logicalnot	0xac
+opthyphen	0xad
+registered	0xae
+macron		0xaf
+degree		0xb0
+plusminus	0xb1
+twosuperior	0xb2
+threesuperior	0xb3
+acute		0xb4
+mu		0xb5
+paragraph	0xb6
+periodcentered	0xb7
+cedilla		0xb8
+onesuperior	0xb9
+ordmasculine	0xba
+guillemotright	0xbb
+onequarter	0xbc
+onehalf		0xbd
+threequarters	0xbe
+questiondown	0xbf
+Agrave		0xc0
+Aacute		0xc1
+Acircumflex	0xc2
+Atilde		0xc3
+Adieresis	0xc4
+Aring		0xc5
+AE		0xc6
+Ccedilla	0xc7
+Egrave		0xc8
+Eacute		0xc9
+Ecircumflex	0xca
+Edieresis	0xcb
+Igrave		0xcc
+Iacute		0xcd
+Icircumflex	0xce
+Idieresis	0xcf
+Eth		0xd0
+Ntilde		0xd1
+Ograve		0xd2
+Oacute		0xd3
+Ocircumflex	0xd4
+Otilde		0xd5
+Odieresis	0xd6
+multiply	0xd7
+Oslash		0xd8
+Ugrave		0xd9
+Uacute		0xda
+Ucircumflex	0xdb
+Udieresis	0xdc
+Yacute		0xdd
+Thorn		0xde
+germandbls	0xdf
+agrave		0xe0
+aacute		0xe1
+acircumflex	0xe2
+atilde		0xe3
+adieresis	0xe4
+aring		0xe5
+ae		0xe6
+ccedilla	0xe7
+egrave		0xe8
+eacute		0xe9
+ecircumflex	0xea
+edieresis	0xeb
+igrave		0xec
+iacute		0xed
+icircumflex	0xee
+idieresis	0xef
+eth		0xf0
+ntilde		0xf1
+ograve		0xf2
+oacute		0xf3
+ocircumflex	0xf4
+otilde		0xf5
+odieresis	0xf6
+divide		0xf7
+oslash		0xf8
+ugrave		0xf9
+uacute		0xfa
+ucircumflex	0xfb
+udieresis	0xfc
+yacute		0xfd
+thorn		0xfe
+ydieresis	0xff
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/cpg1252.sym
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/cpg1252.sym	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/cpg1252.sym	(revision 10506)
@@ -0,0 +1,221 @@
+# RTF ANSI character set (\ansi) general map
+# These are taken from the ISO-Latin-1 (ISO-8859-1) encodings, with
+# a few additions
+
+# Field 1 is the standard character name which the character value in
+# field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+# use the value in field 2.)
+
+# The character value may be given either as a single character (which will be
+# converted to the ASCII value of the character), or in numeric format, either
+# in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+# characters.
+
+# jrm21 - the character name is used when outputting a particular character
+# code. This name is then looked up in the *-gen file to see what to output
+# for that symbol name. It's a bit round-about...
+
+# characters in ASCII range (00-127)
+
+formula		0x06
+nobrkhyphen	0x1e
+opthyphen	0x1f
+
+space		" "
+exclam		!
+quotedbl	'"'
+numbersign	#
+dollar		$
+percent		%
+ampersand	&
+quoteright	"'"
+parenleft	(
+parenright	)
+asterisk	*
+plus		+
+comma		,
+hyphen		-
+period		.
+slash		/
+zero		0
+one		1
+two		2
+three		3
+four		4
+five		5
+six		6
+seven		7
+eight		8
+nine		9
+colon		:
+semicolon	;
+less		<
+equal		=
+greater		>
+question	?
+at		@
+A		A
+B		B
+C		C
+D		D
+E		E
+F		F
+G		G
+H		H
+I		I
+J		J
+K		K
+L		L
+M		M
+N		N
+O		O
+P		P
+Q		Q
+R		R
+S		S
+T		T
+U		U
+V		V
+W		W
+X		X
+Y		Y
+Z		Z
+bracketleft	[
+backslash	\
+bracketright	]
+asciicircum	^
+underscore	_
+quoteleft	"`"
+a		a
+b		b
+c		c
+d		d
+e		e
+f		f
+g		g
+h		h
+i		i
+j		j
+k		k
+l		l
+m		m
+n		n
+o		o
+p		p
+q		q
+r		r
+s		s
+t		t
+u		u
+v		v
+w		w
+x		x
+y		y
+z		z
+braceleft	{
+bar		|
+braceright	}
+asciitilde	~
+
+# non-ASCII characters (128-255)
+#ellipsis		0x85
+#dagger		0x86
+#daggerdbl	0x87
+
+nobrkspace	0xa0
+exclamdown	0xa1
+cent		0xa2
+sterling	0xa3
+currency	0xa4
+yen		0xa5
+brokenbar	0xa6
+section		0xa7
+dieresis	0xa8
+copyright	0xa9
+ordfeminine	0xaa
+guillemotleft	0xab
+logicalnot	0xac
+opthyphen	0xad
+registered	0xae
+macron		0xaf
+degree		0xb0
+plusminus	0xb1
+twosuperior	0xb2
+threesuperior	0xb3
+acute		0xb4
+mu		0xb5
+paragraph	0xb6
+periodcentered	0xb7
+#asterisk	0xb7
+cedilla		0xb8
+onesuperior	0xb9
+ordmasculine	0xba
+guillemotright	0xbb
+onequarter	0xbc
+onehalf		0xbd
+threequarters	0xbe
+questiondown	0xbf
+Agrave		0xc0
+Aacute		0xc1
+Acircumflex	0xc2
+Atilde		0xc3
+Adieresis	0xc4
+Aring		0xc5
+AE		0xc6
+Ccedilla	0xc7
+Egrave		0xc8
+Eacute		0xc9
+Ecircumflex	0xca
+Edieresis	0xcb
+Igrave		0xcc
+Iacute		0xcd
+Icircumflex	0xce
+Idieresis	0xcf
+Eth		0xd0
+Ntilde		0xd1
+Ograve		0xd2
+Oacute		0xd3
+Ocircumflex	0xd4
+Otilde		0xd5
+Odieresis	0xd6
+multiply	0xd7
+Oslash		0xd8
+Ugrave		0xd9
+Uacute		0xda
+Ucircumflex	0xdb
+Udieresis	0xdc
+Yacute		0xdd
+Thorn		0xde
+germandbls	0xdf
+agrave		0xe0
+aacute		0xe1
+acircumflex	0xe2
+atilde		0xe3
+adieresis	0xe4
+aring		0xe5
+ae		0xe6
+ccedilla	0xe7
+egrave		0xe8
+eacute		0xe9
+ecircumflex	0xea
+edieresis	0xeb
+igrave		0xec
+iacute		0xed
+icircumflex	0xee
+idieresis	0xef
+eth		0xf0
+ntilde		0xf1
+ograve		0xf2
+oacute		0xf3
+ocircumflex	0xf4
+otilde		0xf5
+odieresis	0xf6
+divide		0xf7
+oslash		0xf8
+ugrave		0xf9
+uacute		0xfa
+ucircumflex	0xfb
+udieresis	0xfc
+yacute		0xfd
+thorn		0xfe
+ydieresis	0xff
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/html-map
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/html-map	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/html-map	(revision 10506)
@@ -0,0 +1,265 @@
+# Output sequence map for rtftohtml
+
+# Field 1 is the standard character name.  Field 2 is the output sequence
+# to produce for that character.
+
+# The output sequence is simply a string of characters.  If it contains
+# whitespace, it may be quoted.  If it contains quotes, it may be quoted
+# with a different quote character.
+
+null		''
+# characters in ASCII range (32-127)
+
+space		" "
+exclam		!
+quotedbl	'"'
+numbersign	#
+dollar		$
+percent		%
+ampersand	&amp;
+quoteright	"'"
+parenleft	(
+parenright	)
+asterisk	*
+plus		+
+comma		,
+hyphen		-
+period		.
+slash		/
+zero		0
+one		1
+onesuperior	&sup1;
+two		2
+twosuperior	&sup2;
+three		3
+threesuperior	&sup3;
+four		4
+five		5
+six		6
+seven		7
+eight		8
+nine		9
+colon		:
+semicolon	;
+less		&lt;
+equal		=
+greater		&gt;
+question	?
+at		@
+A		A
+B		B
+C		C
+D		D
+E		E
+F		F
+G		G
+H		H
+I		I
+J		J
+K		K
+L		L
+M		M
+N		N
+O		O
+P		P
+Q		Q
+R		R
+S		S
+T		T
+U		U
+V		V
+W		W
+X		X
+Y		Y
+Z		Z
+bracketleft	[
+backslash	\
+bracketright	]
+asciicircum	^
+underscore	_
+quoteleft	"`"
+a		a
+b		b
+c		c
+d		d
+e		e
+f		f
+g		g
+h		h
+i		i
+j		j
+k		k
+l		l
+m		m
+n		n
+o		o
+p		p
+q		q
+r		r
+s		s
+t		t
+u		u
+v		v
+w		w
+x		x
+y		y
+z		z
+braceleft	{
+bar		|
+braceright	}
+asciitilde	~
+
+# non-ASCII
+# use HTML 4.0 entity names where practical
+# starting at decimal code 160
+nobrkspace	&nbsp;
+# inverted exclamation mark 161
+cent		&cent;
+sterling	&pound;
+currency	&curren;
+yen		&yen;
+#netscape will only do this in utf-8: brokenbar	&brvbar;
+brokenbar	|
+section		&sect;
+# uml / diaeresis = 168
+copyright	&copy;
+copyrightsans	&copy;
+
+
+# Latin Extended-A
+OE		&OElig;
+oe		&oelig;
+Scaron		&Scaron;
+scaron		&scaron;
+Ydieresis	&Yuml;
+
+acute		"'"
+angleleft	[
+angleright	&gt;
+approxequal	~
+arrowboth	&lt;-&gt;
+arrowdblboth	&lt;=&gt;
+arrowdblleft	&lt;=
+arrowdblright	=&gt;
+arrowleft	&lt;-
+arrowright	-&gt;
+#bullet		*
+bullet		&middot;
+circumflex	^
+# next 2 have named entities, which netscape 4 doesn't use...
+# unicode &#8224; and &#8225;
+dagger		&#134;
+daggerdbl	&#135;
+
+degree		&deg;
+delta		d
+divide		&divide;
+dotlessi	i
+ellipsis	...
+# next 2 have named entities, which netscape 4 doesn't use...
+endash		&#150;
+emdash		&#151;
+euro		&euro;
+fi		fi
+fl		fl
+fraction	/
+grave		"`"
+greaterequal	&gt;=
+# &#171; # was &lt;&lt;
+guillemotleft	&laquo;
+# &#187; # was &gt;&gt;
+guillemotright	&raquo;
+# netscape 4.7 doesn't do this? - unicode: &#2039; or &lsaquo;
+guilsinglleft	&lt;
+# ditto? unicode: &#203A; or &rsaquo;
+guilsinglright	&gt;
+lessequal	&lt;=
+logicalnot	&not;
+mathasterisk	*
+mathequal	=
+mathminus	-
+mathnumbersign	'#'
+mathplus	+
+mathtilde	~
+minus		-
+mu		&micro;
+multiply	&times;
+nobrkhyphen	-
+
+notequal	!=
+onehalf		&frac12;
+onequarter	&frac14;
+periodcentered	&middot;
+plusminus	&plusmn;
+quotedblbase	,,
+quotedblleft	'"'
+quotedblright	'"'
+quotesinglbase	,
+registered	&reg;
+registersans	&reg;
+threequarters	&frac34;
+tilde		~
+trademark	&trade;
+AE		&AElig;
+Aacute      &Aacute;
+Acircumflex &Acirc;
+Agrave      &Agrave;
+Aring       &Aring;
+Atilde		&Atilde;
+Adieresis	&Auml;
+Ccedilla	&Ccedil;
+#ETH		&ETH;
+Eacute	&Eacute;
+Ecircumflex	&Ecirc;
+Egrave	&Egrave;
+Edieresis	&Euml;
+Iacute	&Iacute;
+Icircumflex	&Icirc;
+Igrave	&Igrave;
+Idieresis	&Iuml;
+Ntilde	&Ntilde;
+Oacute	&Oacute;
+Ocircumflex	&Ocirc;
+Ograve	&Ograve;
+Oslash	&Oslash;
+#Otilde	&Otilde;
+Odieresis	&Ouml;
+#THORN	&THORN;
+Uacute	&Uacute;
+Ucircumflex	&Ucirc;
+Ugrave	&Ugrave;
+Udieresis	&Uuml;
+#Yacute	&Yacute;
+ae		&aelig;
+aacute	&aacute;
+acircumflex	&acirc;
+agrave	&agrave;
+aring	&aring;
+atilde	&atilde;
+adieresis	&auml;
+ccedilla	&ccedil;
+eacute	&eacute;
+ecircumflex	&ecirc;
+egrave	&egrave;
+#eth	&eth;
+edieresis	&euml;
+iacute	&iacute;
+icircumflex	&icirc;
+igrave	&igrave;
+idieresis	&iuml;
+ntilde	&ntilde;
+oacute	&oacute;
+ocircumflex	&ocirc;
+ograve	&ograve;
+oslash	&oslash;
+otilde	&otilde;
+odieresis	&ouml;
+germandbls	&szlig;
+#thorn	&thorn;
+uacute	&uacute;
+ucircumflex	&ucirc;
+ugrave	&ugrave;
+udieresis	&uuml;
+yacute	&yacute;
+ydieresis	&yuml;
+newline	<br>
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/html-trn
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/html-trn	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/html-trn	(revision 10506)
@@ -0,0 +1,214 @@
+# Starting with rtftohtml 2.7, all html-trans files have a version number
+# The version number must appear before any other tables.
+.Version,3
+
+# Paragraph Style Tags table
+# Format:
+#"name","starttag","endtag","col2mark","tabmark","parmark",allowtext,cannest,DeleteCol1,fold,TocStyl
+.PTag
+"Normal","","\n","\t","\t","<p>\n",1,0,0,1,0
+"h1","<h1>\n","</h1>\n","\t","\t","<br>\n",0,0,0,1,1
+"h2","<h2>\n","</h2>\n","\t","\t","<br>\n",0,0,0,1,2
+"h3","<h3>\n","</h3>\n","\t","\t","<br>\n",0,0,0,1,3
+"h4","<h4>\n","</h4>\n","\t","\t","<br>\n",0,0,0,1,4
+"h5","<h5>\n","</h5>\n","\t","\t","<br>\n",0,0,0,1,5
+"h6","<h6>\n","</h6>\n","\t","\t","<br>\n",0,0,0,1,6
+"ul","<ul>\n<li>","</ul>","\t","\t","\n<li>",1,1,0,1,0
+"ul-d","<ul>\n<li>","</ul>","\t","\t","\n<li>",1,1,1,1,0
+"ol","<ol>\n<li>","</ol>","\t","\t","\n<li>",1,1,0,1,0
+"ol-d","<ol>\n<li>","</ol>","\t","\t","\n<li>",1,1,1,1,0
+"dl","<dl>\n<dt>","</dl>","\n<dd>","\t","\n<dt>",1,1,0,1,0
+"TERM","<dl>\n<dt>","</dl>","\t","\t","\n<dt>",1,1,0,1,0
+"DEF","<dd>","","\t","\t","\n<br>",1,1,0,1,0
+"dir","<dir>\n<li>","</dir>","\n<li>","\n<li>","\n<li>",0,1,0,1,0
+"menu","<menu>\n<li>","</menu>\n","\n<li>","\n<li>","\n<li>",0,1,0,1,0
+"address","<address>","</address>\n","\t","\t","<br>\n",1,0,0,1,0
+"pre","\n<pre>\n","\n</pre>\n","\t","\t","\n",0,0,0,0,0
+"blockquote","<blockquote>","</blockquote>","\t","\t","\n",1,0,0,1,0
+"hr","<hr>","","","","",1,0,0,1,0
+# This is a required entry; tables will be formatted with this entry
+"_Table","\n<pre>\n","\n</pre>\n","\t","\t","\n",0,0,0,0,0
+
+# Text STyle Tags table
+# Format
+# "name","Starttag","Endtag"
+.TTag
+"b","<b>","</b>"
+"i","<i>","</i>"
+"u","<u>","</u>"
+"em","<em>","</em>"
+"cite","<cite>","</cite>"
+"tt","<tt>","</tt>"
+"strong","<strong>","</strong>"
+"code","<code>","</code>"
+"samp","<samp>","</samp>"
+"kbd","<kbd>","</kbd>"
+"var","<var>","</var>"
+"dfn","<dfn>","</dfn>"
+"sup","<sup>","</sup>"
+
+# Text Match Table
+# Format:
+# "Font",FontSize,Match,Mask,"TextStyleName"
+# "" is don't care for fonts
+# 0 is don't care for font size
+# Special names for TextStyleName
+# _Discard - text will not be output
+# _Name    - text will be used for an named anchor
+# _HRef    - text is an href
+# _Hot     - end of this text marks the end of hot text
+# _Literal - text is sent thorough without any translation
+# The order of bits for match and mask is:
+#    v^bDWUHACSOTIB - Bold
+#    v^bDWUHACSOTI - Italic
+#    v^bDWUHACSOT - StrikeThrough
+#    v^bDWUHACSO - Outline
+#    v^bDWUHACS - Shadow
+#    v^bDWUHAC - SmallCaps
+#    v^bDWUHA - AllCaps
+#    v^bDWUH - Hidden
+#    v^bDWU - Underline
+#    v^bDW - Word Underline
+#    v^bD - Dotted Underline
+#    v^b - Double Underline
+#    v^ - SuperScript
+#    v - SubScript
+#    v^bDWUIACSOTIB
+.TMatch
+#
+# First do specials, because they are higher priority than other matches
+# 
+# double-underline/not hidden -> hot text
+# double-underline/hidden -> href
+#    v^bDWUHACSOTIB,v^bDWUHACSOTIB
+"",0,00100000000000,00100010000000,"_Hot"
+"",0,00100010000000,00100010000000,"_HRef"
+
+# hidden/shadow -> literal
+#    v^bDWUHACSOTIB,v^bDWUHACSOTIB
+"",0,00000010010000,00000010010000,"_Literal"
+
+# hidden/outline -> Name
+#    v^bDWUHACSOTIB,v^bDWUHACSOTIB
+"",0,00000010001000,00000010001000,"_Name"
+
+# hidden/all other hiddens are discarded
+"",0,00000010000000,00000010000000,"_Discard"
+
+# All other Superscripts just superscripts
+#    v^bDWUHACSOTIB,v^bDWUHACSOTIB
+"",0,01000000000000,01000000000000,"sup"
+
+# Regular matches - You can have multiple of these active
+
+# monospace fonts -> tt
+"Courier",0,00000000000000,00000000000000,"tt"
+"Monoco",0,00000000000000,00000000000000,"tt"
+
+# bold -> bold
+#    v^bDWUHACSOTIB,v^bDWUHACSOTIB
+"",0,00000000000001,00000000000001,"b"
+
+# italic/underline -> cite, italic/nounderline -> italic
+#    v^bDWUHACSOTIB,v^bDWUHACSOTIB
+"",0,00000000000010,00000100000010,"i"
+"",0,00000100000010,00000100000010,"cite"
+
+# any underline without italic -> underline
+#    v^bDWUHACSOTIB,v^bDWUHACSOTIB
+"",0,00010000000000,00111100000010,"u"
+"",0,00001000000000,00111100000010,"u"
+"",0,00000100000000,00111100000010,"u"
+"",0,00100000000000,00111100000010,"u"
+
+# outline,shadow -> em
+#    v^bDWUHACSOTIB,v^bDWUHACSOTIB
+"",0,00000000001000,00000000001000,"em"
+"",0,00000000010000,00000000010000,"em"
+
+
+# Format:
+# "Paragraph Style",NestLevel,"ParagraphStyleName"
+# First Entry is the default if no style match. Should be level 0 
+# point to a Paragraph style with no markup
+.PMatch
+"Normal",0,"Normal"
+# This is a required entry; tables will be formatted with this entry
+"_Table",0,"_Table"
+"heading 1",0,"h1"
+"heading 2",0,"h2"
+"heading 3",0,"h3"
+"heading 4",0,"h4"
+"heading 5",0,"h5"
+"heading 6",0,"h6"
+"ol",0,"ol"
+"ol 1",1,"ol"
+"ol 2",2,"ol"
+"ol 3",3,"ol"
+"ol 4",4,"ol"
+"ol 5",5,"ol"
+"ul",0,"ul"
+"ul 1",1,"ul"
+"ul 2",2,"ul"
+"ul 3",3,"ul"
+"ul 4",4,"ul"
+"ul 5",5,"ul"
+"numbered list",0,"ol-d"
+"numbered list 1",1,"ol-d"
+"numbered list 2",2,"ol-d"
+"numbered list 3",3,"ol-d"
+"numbered list 4",4,"ol-d"
+"numbered list 5",5,"ol-d"
+"bullet list",0,"ul-d"
+"bullet list 1",1,"ul-d"
+"bullet list 2",2,"ul-d"
+"bullet list 3",3,"ul-d"
+"bullet list 4",4,"ul-d"
+"bullet list 5",5,"ul-d"
+"dir",0,"dir"
+"dir 1",1,"dir"
+"dir 2",2,"dir"
+"dir 3",3,"dir"
+"dir 4",4,"dir"
+"dir 5",5,"dir"
+"small gloss",0,"dl"
+"small gloss 1",1,"dl"
+"small gloss 2",2,"dl"
+"small gloss 3",3,"dl"
+"small gloss 4",4,"dl"
+"small gloss 5",5,"dl"
+"glossary",0,"dl"
+"glossary 1",1,"dl"
+"glossary 2",2,"dl"
+"glossary 3",3,"dl"
+"glossary 4",4,"dl"
+"glossary 5",5,"dl"
+"menu",0,"menu"
+"menu 1",1,"menu"
+"menu 2",2,"menu"
+"menu 3",3,"menu"
+"menu 4",4,"menu"
+"menu 5",5,"menu"
+"pre",0,"pre"
+"blockquote",0,"blockquote"
+"address",0,"address"
+"hr",0,"hr"
+# the following paragraph styles will be discarded
+"toc 1",0,"_Discard"
+"toc 2",0,"_Discard"
+"toc 3",0,"_Discard"
+"toc 4",0,"_Discard"
+"toc 5",0,"_Discard"
+"index 1",0,"_Discard"
+"index 2",0,"_Discard"
+"index 3",0,"_Discard"
+"index 4",0,"_Discard"
+"index 5",0,"_Discard"
+"TERM",0,"TERM"
+"DEF",1,"DEF"
+"TERM 1",1,"TERM"
+"DEF 1",2,"DEF"
+"TERM 2",2,"TERM"
+"DEF 2",3,"DEF"
+"HTML",0,"_Literal"
+"footnote text",0,"Normal"
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/mac.gen
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/mac.gen	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/mac.gen	(revision 10506)
@@ -0,0 +1,243 @@
+# RTF Macintosh character set (\mac) general map
+
+# Field 1 is the standard character name which the character value in
+# field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+# use the value in field 2.)
+
+# The character value may be given either as a single character (which will be
+# converted to the ASCII value of the character), or in numeric format, either
+# in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+# characters.
+
+# characters in ASCII range (00-127)
+
+formula		0x06
+nobrkhyphen	0x1e
+opthyphen	0x1f
+
+space		" "
+exclam		!
+quotedbl	'"'
+numbersign	#
+dollar		$
+percent		%
+ampersand	&
+quoteright	"'"
+parenleft	(
+parenright	)
+asterisk	*
+plus		+
+comma		,
+hyphen		-
+period		.
+slash		/
+zero		0
+one		1
+two		2
+three		3
+four		4
+five		5
+six		6
+seven		7
+eight		8
+nine		9
+colon		:
+semicolon	;
+less		<
+equal		=
+greater		>
+question	?
+at		@
+A		A
+B		B
+C		C
+D		D
+E		E
+F		F
+G		G
+H		H
+I		I
+J		J
+K		K
+L		L
+M		M
+N		N
+O		O
+P		P
+Q		Q
+R		R
+S		S
+T		T
+U		U
+V		V
+W		W
+X		X
+Y		Y
+Z		Z
+bracketleft	[
+backslash	\
+bracketright	]
+asciicircum	^
+underscore	_
+quoteleft	"`"
+a		a
+b		b
+c		c
+d		d
+e		e
+f		f
+g		g
+h		h
+i		i
+j		j
+k		k
+l		l
+m		m
+n		n
+o		o
+p		p
+q		q
+r		r
+s		s
+t		t
+u		u
+v		v
+w		w
+x		x
+y		y
+z		z
+braceleft	{
+bar		|
+braceright	}
+asciitilde	~
+
+# non-ASCII characters (128-255)
+
+# ?? Ygrave		0x07
+# ?? yacute		0x08
+Adieresis	0x80
+Aring		0x81
+Ccedilla	0x82
+Eacute		0x83
+Ntilde		0x84
+Odieresis	0x85
+Udieresis	0x86
+aacute		0x87
+agrave		0x88
+acircumflex	0x89
+adieresis	0x8a
+atilde		0x8b
+aring		0x8c
+ccedilla	0x8d
+eacute		0x8e
+egrave		0x8f
+ecircumflex	0x90
+edieresis	0x91
+iacute		0x92
+igrave		0x93
+icircumflex	0x94
+idieresis	0x95
+ntilde		0x96
+oacute		0x97
+ograve		0x98
+ocircumflex	0x99
+odieresis	0x9a
+otilde		0x9b
+uacute		0x9c
+ugrave		0x9d
+ucircumflex	0x9e
+udieresis	0x9f
+dagger		0xa0
+degree		0xa1
+cent		0xa2
+sterling	0xa3
+section		0xa4
+bullet		0xa5
+paragraph	0xa6
+germandbls	0xa7
+registered	0xa8
+copyright	0xa9
+trademark	0xaa
+acute		0xab
+dieresis	0xac
+notequal	0xad
+AE		0xae
+Oslash		0xaf
+infinity	0xb0
+plusminus	0xb1
+lessequal	0xb2
+greaterequal	0xb3
+yen		0xb4
+mu		0xb5
+partialdiff	0xb6
+Sigma		0xb7
+Pi		0xb8
+pi		0xb9
+integral	0xba
+ordfeminine	0xbb
+ordmasculine	0xbc
+Omega		0xbd
+ae		0xbe
+oslash		0xbf
+questiondown	0xc0
+exclamdown	0xc1
+logicalnot	0xc2
+radical		0xc3
+florin		0xc4
+approxequal	0xc5
+Delta		0xc6
+guillemotleft	0xc7
+guillemotright	0xc8
+ellipsis	0xc9
+nobrkspace	0xca
+Agrave		0xcb
+OE		0xce
+oe		0xcf
+endash		0xd0
+emdash		0xd1
+quotedblleft	0xd2
+quotedblright	0xd3
+quoteleft	0xd4
+quoteright	0xd5
+divide		0xd6
+lozenge		0xd7
+ydieresis	0xd8
+Ydieresis	0xd9
+fraction	0xda
+currency	0xdb
+guilsinglleft	0xdc
+guilsinglright	0xdd
+fi		0xde
+fl		0xdf
+daggerdbl	0xe0
+periodcentered	0xe1
+quotesinglbase	0xe2
+quotedblbase	0xe3
+perthousand	0xe4
+Acircumflex	0xe5
+Ecircumflex	0xe6
+Aacute		0xe7
+Edieresis	0xe8
+Egrave		0xe9
+Iacute		0xea
+Icircumflex	0xeb
+Idieresis	0xec
+Igrave		0xed
+Oacute		0xee
+Ocircumflex	0xef
+apple		0xf0
+Ograve		0xf1
+Uacute		0xf2
+Ucircumflex	0xf3
+Ugrave		0xf4
+dotlessi	0xf5
+circumflex	0xf6
+tilde		0xf7
+macron		0xf8
+breve		0xf9
+dotaccent	0xfa
+ring		0xfb
+cedilla		0xfc
+hungarumlaut	0xfd
+ogonek		0xfe
+caron		0xff
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/mac.sym
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/mac.sym	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/mac.sym	(revision 10506)
@@ -0,0 +1,241 @@
+# RTF Macintosh character set (\mac) Symbol font map
+
+# Field 1 is the standard character name which the character value in
+# field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+# use the value in field 2.)
+
+# The character value may be given either as a single character (which will be
+# converted to the ASCII value of the character), or in numeric format, either
+# in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+# characters.
+
+# characters in ASCII range (00-127)
+
+formula		0x06
+nobrkhyphen	0x1e
+opthyphen	0x1f
+
+space		" "
+exclam		!
+universal	'"'
+mathnumbersign	#
+existential	$
+percent		%
+ampersand	&
+suchthat	"'"
+parenleft	(
+parenright	)
+mathasterisk	*
+mathplus	+
+comma		,
+mathminus	-
+period		.
+slash		/
+zero		0
+one		1
+two		2
+three		3
+four		4
+five		5
+six		6
+seven		7
+eight		8
+nine		9
+colon		:
+semicolon	;
+less		<
+mathequal	=
+greater		>
+question	?
+congruent	@
+Alpha		A
+Beta		B
+Chi		C
+Delta		D
+Epsilon		E
+Phi		F
+Gamma		G
+Eta		H
+Iota		I
+# J		J
+Kappa		K
+Lambda		L
+Mu		M
+Nu		N
+Omicron		O
+Pi		P
+Theta		Q
+Rho		R
+Sigma		S
+Tau		T
+Upsilon		U
+varsigma	V
+Omega		W
+Xi		X
+Psi		Y
+Zeta		Z
+bracketleft	[
+backslash	\
+bracketright	]
+asciicircum	^
+underscore	_
+quoteleft	"`"
+alpha		a
+beta		b
+chi		c
+delta		d
+epsilon		e
+phi		f
+gamma		g
+eta		h
+iota		i
+# j		j
+kappa		k
+lambda		l
+mu		m
+nu		n
+omicron		o
+pi		p
+theta		q
+rho		r
+sigma		s
+tau		t
+upsilon		u
+# xxx		v
+omega		w
+xi		x
+psi		y
+zeta		z
+braceleft	{
+bar		|
+braceright	}
+mathtilde	~
+
+# non-ASCII characters (128-255)
+
+# Adieresis	0x80
+# Aring		0x81
+# Ccedilla	0x82
+# Eacute	0x83
+# Ntilde	0x84
+# Odieresis	0x85
+# Udieresis	0x86
+# aacute	0x87
+# agrave	0x88
+# acircumflex	0x89
+# adieresis	0x8a
+# atilde	0x8b
+# aring		0x8c
+# ccedilla	0x8d
+# eacute	0x8e
+# egrave	0x8f
+# ecircumflex	0x90
+# edieresis	0x91
+# iacute	0x92
+# igrave	0x93
+# icircumflex	0x94
+# idieresis	0x95
+# ntilde	0x96
+# oacute	0x97
+# ograve	0x98
+# ocircumflex	0x99
+# odieresis	0x9a
+# otilde	0x9b
+# uacute	0x9c
+# ugrave	0x9d
+# ucircumflex	0x9e
+# udieresis	0x9f
+# dagger	0xa0
+# degree	0xa1
+minute		0xa2
+lessequal	0xa3
+fraction	0xa4
+infinity	0xa5
+florin		0xa6
+club		0xa7
+diamond		0xa8
+heart		0xa9
+spade		0xaa
+arrowboth	0xab
+arrowleft	0xac
+arrowup		0xad
+arrowright	0xae
+arrowdown	0xaf
+degree		0xb0
+plusminus	0xb1
+second		0xb2
+greaterequal	0xb3
+multiply	0xb4
+proportional	0xb5
+partialdiff	0xb6
+bullet		0xb7
+divide		0xb8
+notequal	0xb9
+equivalence	0xba
+approxequal	0xbb
+ellipsis	0xbc
+arrowvertex	0xbd
+arrowhorizex	0xbe
+carriagereturn	0xbf
+aleph		0xc0
+Ifraktur	0xc1
+Rfraktur	0xc2
+weierstrass	0xc3
+circlemultiply	0xc4
+circleplus	0xc5
+emptyset	0xc6
+intersection	0xc7
+union		0xc8
+propersuperset	0xc9
+reflexsuperset	0xca
+notsubset	0xcb
+propersubset	0xce
+reflexsubset	0xcf
+angle		0xd0
+gradient	0xd1
+registered	0xd2
+copyright	0xd3
+trademark	0xd4
+product		0xd5
+radical		0xd6
+periodcentered	0xd7
+logicalnot	0xd8
+logicaland	0xd9
+logicalor	0xda
+arrowdblboth	0xdb
+arrowdblleft	0xdc
+arrowdblup	0xdd
+arrowdblright	0xde
+arrowdbldown	0xdf
+lozenge		0xe0
+angleleft	0xe1
+registersans	0xe2
+copyrightsans	0xe3
+trademarksans	0xe4
+Sigma		0xe5
+# Ecircumflex	0xe6
+# Aacute	0xe7
+# Edieresis	0xe8
+# Egrave	0xe9
+# Iacute	0xea
+# Icircumflex	0xeb
+# Idieresis	0xec
+# Igrave	0xed
+# Oacute	0xee
+# Ocircumflex	0xef
+apple		0xf0
+angleright	0xf1
+# Uacute	0xf2
+# Ucircumflex	0xf3
+# Ugrave	0xf4
+# dotlessi	0xf5
+# circumflex	0xf6
+# tilde		0xf7
+# macron	0xf8
+# breve		0xf9
+# dotaccent	0xfa
+# ring		0xfb
+# cedilla	0xfc
+# hungarumlaut	0xfd
+# ogonek	0xfe
+# caron		0xff
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pc.gen
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pc.gen	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pc.gen	(revision 10506)
@@ -0,0 +1,243 @@
+# RTF PC character set (\pc) general map
+
+# Field 1 is the standard character name which the character value in
+# field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+# use the value in field 2.)
+
+# The character value may be given either as a single character (which will be
+# converted to the ASCII value of the character), or in numeric format, either
+# in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+# characters.
+
+# characters in ASCII range (32-127)
+
+formula		0x06
+nobrkhyphen	0x1e
+opthyphen	0x1f
+
+space		" "
+exclam		!
+quotedbl	'"'
+numbersign	#
+dollar		$
+percent		%
+ampersand	&
+quoteright	"'"
+parenleft	(
+parenright	)
+asterisk	*
+plus		+
+comma		,
+hyphen		-
+period		.
+slash		/
+zero		0
+one		1
+two		2
+three		3
+four		4
+five		5
+six		6
+seven		7
+eight		8
+nine		9
+colon		:
+semicolon	;
+less		<
+equal		=
+greater		>
+question	?
+at		@
+A		A
+B		B
+C		C
+D		D
+E		E
+F		F
+G		G
+H		H
+I		I
+J		J
+K		K
+L		L
+M		M
+N		N
+O		O
+P		P
+Q		Q
+R		R
+S		S
+T		T
+U		U
+V		V
+W		W
+X		X
+Y		Y
+Z		Z
+bracketleft	[
+backslash	\
+bracketright	]
+asciicircum	^
+underscore	_
+quoteleft	"`"
+a		a
+b		b
+c		c
+d		d
+e		e
+f		f
+g		g
+h		h
+i		i
+j		j
+k		k
+l		l
+m		m
+n		n
+o		o
+p		p
+q		q
+r		r
+s		s
+t		t
+u		u
+v		v
+w		w
+x		x
+y		y
+z		z
+braceleft	{
+bar		|
+braceright	}
+asciitilde	~
+
+# non-ASCII characters (128-255)
+
+Ccedilla	0x80
+udieresis	0x81
+eacute		0x82
+acircumflex	0x83
+adieresis	0x84
+agrave		0x85
+aring		0x86
+ccedilla	0x87
+ecircumflex	0x88
+edieresis	0x89
+egrave		0x8a
+idieresis	0x8b
+icircumflex	0x8c
+igrave		0x8d
+Adieresis	0x8e
+Aring		0x8f
+Eacute		0x90
+ae		0x91
+AE		0x92
+ocircumflex	0x93
+odieresis	0x94
+ograve		0x95
+ucircumflex	0x96
+ugrave		0x97
+ydieresis	0x98
+Odieresis	0x99
+Udieresis	0x9a
+cent		0x9b
+sterling	0x9c
+yen		0x9d
+ucircumflex	0x9e
+florin		0x9f
+aacute		0xa0
+iacute		0xa1
+oacute		0xa2
+uacute		0xa3
+ntilde		0xa4
+Ntilde		0xa5
+ordfeminine	0xa6
+ordmasculine	0xa7
+questiondown	0xa8
+copyright	0xa9
+trademark	0xaa
+acute		0xab
+dieresis	0xac
+exclamdown	0xad
+guillemotleft	0xae
+guillemotright	0xaf
+space		0xb0
+plusminus	0xb1
+lessequal	0xb2
+bar		0xb3
+yen		0xb4
+mu		0xb5
+partialdiff	0xb6
+Sigma		0xb7
+Pi		0xb8
+pi		0xb9
+integral	0xba
+ordfeminine	0xbb
+ordmasculine	0xbc
+Omega		0xbd
+ae		0xbe
+logicalnot	0xbf
+questiondown	0xc0
+exclamdown	0xc1
+logicalnot	0xc2
+radical		0xc3
+emdash		0xc4
+approxequal	0xc5
+delta		0xc6
+guillemotleft	0xc7
+guillemotright	0xc8
+ellipsis	0xc9
+nobrkspace	0xca
+Agrave		0xcb
+Atilde		0xcc
+Otilde		0xcd
+OE		0xce
+oe		0xcf
+endash		0xd0
+emdash		0xd1
+quotedblleft	0xd2
+quotedblright	0xd3
+quoteleft	0xd4
+quoteright	0xd5
+divide		0xd6
+lozenge		0xd7
+ydieresis	0xd8
+Ydieresis	0xd9
+fraction	0xda
+Ydieresis	0xdb
+guilsinglleft	0xdc
+greater		0xdd
+less		0xde
+fl		0xdf
+a		0xe0
+germandbls	0xe1
+quotesinglbase	0xe2
+pi		0xe3
+Sigma		0xe4
+Acircumflex	0xe5
+mu		0xe6
+Aacute		0xe7
+Edieresis	0xe8
+Egrave		0xe9
+Omega		0xea
+partialdiff	0xeb
+infinity	0xec
+oslash		0xed
+e		0xee
+Ocircumflex	0xef
+equal		0xf0
+plusminus	0xf1
+greaterequal	0xf2
+lessequal	0xf3
+integral	0xf4
+integral	0xf5
+divide		0xf6
+approxequal	0xf7
+degree		0xf8
+bullet		0xf9
+bullet		0xfa
+radical		0xfb
+cedilla		0xfc
+hungarumlaut	0xfd
+ogonek		0xfe
+nobrkspace	0xff
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pc.sym
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pc.sym	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pc.sym	(revision 10506)
@@ -0,0 +1,115 @@
+# RTF PC character set (\pc) Symbol font map
+
+# Field 1 is the standard character name which the character value in
+# field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+# use the value in field 2.)
+
+# The character value may be given either as a single character (which will be
+# converted to the ASCII value of the character), or in numeric format, either
+# in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+# characters.
+
+# characters in ASCII range (00-127)
+
+formula		0x06
+nobrkhyphen	0x1e
+opthyphen	0x1f
+
+space		" "
+exclam		!
+universal	'"'
+mathnumbersign	#
+existential	$
+percent		%
+ampersand	&
+suchthat	"'"
+parenleft	(
+parenright	)
+mathasterisk	*
+mathplus	+
+comma		,
+mathminus	-
+period		.
+slash		/
+zero		0
+one		1
+two		2
+three		3
+four		4
+five		5
+six		6
+seven		7
+eight		8
+nine		9
+colon		:
+semicolon	;
+less		<
+mathequal	=
+greater		>
+question	?
+congruent	@
+Alpha		A
+Beta		B
+Chi		C
+Delta		D
+Epsilon		E
+Phi		F
+Gamma		G
+Eta		H
+Iota		I
+# J		J
+Kappa		K
+Lambda		L
+Mu		M
+Nu		N
+Omicron		O
+Pi		P
+Theta		Q
+Rho		R
+Sigma		S
+Tau		T
+Upsilon		U
+varsigma	V
+Omega		W
+Xi		X
+Psi		Y
+Zeta		Z
+bracketleft	[
+backslash	\
+bracketright	]
+asciicircum	^
+underscore	_
+quoteleft	"`"
+alpha		a
+beta		b
+chi		c
+delta		d
+epsilon		e
+phi		f
+gamma		g
+eta		h
+iota		i
+# j		j
+kappa		k
+lambda		l
+mu		m
+nu		n
+omicron		o
+pi		p
+theta		q
+rho		r
+sigma		s
+tau		t
+upsilon		u
+# xxx		v
+omega		w
+xi		x
+psi		y
+zeta		z
+braceleft	{
+bar		|
+braceright	}
+mathtilde	~
+
+# non-ASCII characters (128-255)
+
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pca.gen
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pca.gen	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pca.gen	(revision 10506)
@@ -0,0 +1,244 @@
+# RTF PC-A character set (\pca) general map
+
+# Field 1 is the standard character name which the character value in
+# field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+# use the value in field 2.)
+
+# The character value may be given either as a single character (which will be
+# converted to the ASCII value of the character), or in numeric format, either
+# in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+# characters.
+
+# characters in ASCII range (32-127)
+
+formula		0x06
+nobrkhyphen	0x1e
+opthyphen	0x1f
+
+space		" "
+exclam		!
+quotedbl	'"'
+numbersign	#
+dollar		$
+percent		%
+ampersand	&
+quoteright	"'"
+parenleft	(
+parenright	)
+asterisk	*
+plus		+
+comma		,
+hyphen		-
+period		.
+slash		/
+zero		0
+one		1
+two		2
+three		3
+four		4
+five		5
+six		6
+seven		7
+eight		8
+nine		9
+colon		:
+semicolon	;
+less		<
+equal		=
+greater		>
+question	?
+at		@
+A		A
+B		B
+C		C
+D		D
+E		E
+F		F
+G		G
+H		H
+I		I
+J		J
+K		K
+L		L
+M		M
+N		N
+O		O
+P		P
+Q		Q
+R		R
+S		S
+T		T
+U		U
+V		V
+W		W
+X		X
+Y		Y
+Z		Z
+bracketleft	[
+backslash	\
+bracketright	]
+asciicircum	^
+underscore	_
+quoteleft	"`"
+a		a
+b		b
+c		c
+d		d
+e		e
+f		f
+g		g
+h		h
+i		i
+j		j
+k		k
+l		l
+m		m
+n		n
+o		o
+p		p
+q		q
+r		r
+s		s
+t		t
+u		u
+v		v
+w		w
+x		x
+y		y
+z		z
+braceleft	{
+bar		|
+braceright	}
+asciitilde	~
+
+# non-ASCII characters (128-255)
+
+
+Ccedilla	0x80
+udieresis	0x81
+eacute		0x82
+acircumflex	0x83
+adieresis	0x84
+agrave		0x85
+aring		0x86
+ccedilla	0x87
+ecircumflex	0x88
+edieresis	0x89
+egrave		0x8a
+idieresis	0x8b
+icircumflex	0x8c
+igrave		0x8d
+Adieresis	0x8e
+Aring		0x8f
+Eacute		0x90
+ae		0x91
+AE		0x92
+ocircumflex	0x93
+odieresis	0x94
+ograve		0x95
+ucircumflex	0x96
+ugrave		0x97
+ydieresis	0x98
+Odieresis	0x99
+Udieresis	0x9a
+oslash		0x9b
+sterling	0x9c
+Oslash		0x9d
+# ???		0x9e
+florin		0x9f
+aacute		0xa0
+iacute		0xa1
+oacute		0xa2
+uacute		0xa3
+ntilde		0xa4
+Ntilde		0xa5
+ordfeminine	0xa6
+ordmasculine	0xa7
+questiondown	0xa8
+registered	0xa9
+logicalnot	0xaa
+# ???		0xab
+# ???		0xac
+exclamdown	0xad
+guillemotleft	0xae
+guillemotright	0xaf
+# ???		0xb0
+# ???		0xb1
+# ???		0xb2
+# ???		0xb3
+# ???		0xb4
+# ???		0xb5
+# ???		0xb6
+Agrave		0xb7
+copyright	0xb8
+# ???		0xb9
+# ???		0xba
+# ???		0xbb
+# ???		0xbc
+cent		0xbd
+yen		0xbe
+# ???		0xbf
+# ???		0xc0
+# ???		0xc1
+# ???		0xc2
+# ???		0xc3
+# ???		0xc4
+# ???		0xc5
+atilde		0xc6
+Atilde		0xc7
+# ???		0xc8
+# ???		0xc9
+# ???		0xca
+# ???		0xcb
+# ???		0xcc
+# ???		0xcd
+# ???		0xce
+# ???		0xcf
+partialdiff	0xd0
+# ???		0xd1
+# ???		0xd2
+# ???		0xd3
+# ???		0xd4
+# ???		0xd5
+# ???		0xd6
+# ???		0xd7
+# ???		0xd8
+# ???		0xd9
+# ???		0xda
+# ???		0xdb
+# ???		0xdc
+# ???		0xdd
+# ???		0xde
+# ???		0xdf
+# ???		0xe0
+germandbls	0xe1
+# ???		0xe2
+# ???		0xe3
+otilde		0xe4
+Otilde		0xe5
+mu		0xe6
+# ???		0xe7
+# ???		0xe8
+# ???		0xe9
+# ???		0xea
+# ???		0xeb
+# ???		0xec
+# ???		0xed
+# ???		0xee
+acute		0xef
+endash		0xf0
+plusminus	0xf1
+equal		0xf2
+# ???		0xf3
+paragraph	0xf4
+section		0xf5
+divide		0xf6
+# ???		0xf7
+degree		0xf8
+dieresis	0xf9
+bullet		0xfa
+# ???		0xfb
+# ???		0xfc
+# ???		0xfd
+# ???		0xfe
+nobrkspace	0xff
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pca.sym
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pca.sym	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/pca.sym	(revision 10506)
@@ -0,0 +1,115 @@
+# RTF PC-A character set (\pca) Symbol font map
+
+# Field 1 is the standard character name which the character value in
+# field 2 maps onto.  (It doesn't mean "to produce the character in field 1,
+# use the value in field 2.)
+
+# The character value may be given either as a single character (which will be
+# converted to the ASCII value of the character), or in numeric format, either
+# in decimal or 0xyy as hex yy.  Single or double quotes may be used to quote
+# characters.
+
+# characters in ASCII range (00-127)
+
+formula		0x06
+nobrkhyphen	0x1e
+opthyphen	0x1f
+
+space		" "
+exclam		!
+universal	'"'
+mathnumbersign	#
+existential	$
+percent		%
+ampersand	&
+suchthat	"'"
+parenleft	(
+parenright	)
+mathasterisk	*
+mathplus	+
+comma		,
+mathminus	-
+period		.
+slash		/
+zero		0
+one		1
+two		2
+three		3
+four		4
+five		5
+six		6
+seven		7
+eight		8
+nine		9
+colon		:
+semicolon	;
+less		<
+mathequal	=
+greater		>
+question	?
+congruent	@
+Alpha		A
+Beta		B
+Chi		C
+Delta		D
+Epsilon		E
+Phi		F
+Gamma		G
+Eta		H
+Iota		I
+# J		J
+Kappa		K
+Lambda		L
+Mu		M
+Nu		N
+Omicron		O
+Pi		P
+Theta		Q
+Rho		R
+Sigma		S
+Tau		T
+Upsilon		U
+varsigma	V
+Omega		W
+Xi		X
+Psi		Y
+Zeta		Z
+bracketleft	[
+backslash	\
+bracketright	]
+asciicircum	^
+underscore	_
+quoteleft	"`"
+alpha		a
+beta		b
+chi		c
+delta		d
+epsilon		e
+phi		f
+gamma		g
+eta		h
+iota		i
+# j		j
+kappa		k
+lambda		l
+mu		m
+nu		n
+omicron		o
+pi		p
+theta		q
+rho		r
+sigma		s
+tau		t
+upsilon		u
+# xxx		v
+omega		w
+xi		x
+psi		y
+zeta		z
+braceleft	{
+bar		|
+braceright	}
+mathtilde	~
+
+# non-ASCII characters (128-255)
+
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/rtf-ctrl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/rtf-ctrl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/rtftohtm/rtf-ctrl	(revision 10506)
@@ -0,0 +1,769 @@
+# number of control words
+766
+# control word table
+6 0 "vern"
+6 5 "edmins"
+6 6 "yr"
+6 7 "mo"
+6 8 "dy"
+6 9 "hr"
+6 10 "min"
+6 11 "sec"
+6 12 "nofpages"
+6 13 "nofwords"
+6 14 "nofchars"
+6 15 "id"
+6 16 "chdate"
+6 17 "chdpl"
+6 18 "chdpa"
+6 19 "chtime"
+6 20 "chpgn"
+6 21 "sectnum"
+6 22 "chftn"
+6 23 "chatn"
+6 24 "chftnsep"
+6 25 "chftnsepc"
+6 26 "cell"
+6 27 "row"
+6 28 "par"
+6 28 "\n"
+6 28 "\r"
+6 29 "sect"
+6 30 "page"
+6 31 "column"
+6 32 "line"
+6 33 "softpage"
+6 34 "softcol"
+6 35 "softline"
+6 36 "softlheight"
+6 37 "tab"
+6 38 "emdash"
+6 39 "endash"
+6 40 "emspace"
+6 41 "enspace"
+6 42 "bullet"
+6 43 "lquote"
+6 44 "rquote"
+6 45 "ldblquote"
+6 46 "rdblquote"
+6 47 "|"
+6 49 "~"
+6 50 "-"
+6 51 "_"
+6 52 "*"
+6 53 "ltrmark"
+6 54 "rtlmark"
+6 55 "zwj"
+6 56 "zwnj"
+6 57 "chpict"
+6 59 "version"
+12 0 "plain"
+12 1 "b"
+12 2 "caps"
+12 37 "cgrid"
+12 3 "deleted"
+12 4 "dn"
+12 5 "sub"
+12 6 "nosupersub"
+12 7 "expnd"
+12 8 "expndtw"
+12 9 "kerning"
+12 38 "langfe"
+12 39 "langfenp"
+12 35 "lang"
+12 40 "langnp"
+12 10 "f"
+12 11 "fs"
+12 12 "i"
+12 13 "outl"
+12 14 "revised"
+12 15 "revauth"
+12 16 "revdttm"
+12 17 "scaps"
+12 18 "shad"
+12 19 "strike"
+12 20 "ul"
+12 21 "uld"
+12 22 "uldb"
+12 23 "ulnone"
+12 24 "ulw"
+12 25 "up"
+12 26 "super"
+12 27 "v"
+12 28 "cf"
+12 29 "cb"
+12 30 "rtlch"
+12 31 "ltrch"
+12 32 "noproof"
+12 33 "cs"
+12 34 "cchs"
+12 36 "gray"
+11 0 "pard"
+11 1 "s"
+11 2 "hyphpar"
+11 3 "intbl"
+11 104 "itap"
+11 4 "keep"
+11 6 "keepn"
+11 7 "level"
+11 8 "noline"
+11 5 "nowidctlpar"
+11 105 "widctlpar"
+11 7 "outlinelevel"
+11 9 "pagebb"
+11 10 "sbys"
+11 11 "ql"
+11 12 "qr"
+11 13 "qj"
+11 14 "qc"
+11 15 "fi"
+11 16 "li"
+11 16 "lin"
+11 17 "ri"
+11 17 "rin"
+11 17 "curi"
+11 106 "adjustright"
+11 18 "sb"
+11 19 "sa"
+11 20 "sl"
+11 21 "slmult"
+11 22 "subdocument"
+11 23 "rtlpar"
+11 24 "ltrpar"
+11 25 "tx"
+11 26 "tql"
+11 27 "tqr"
+11 28 "tqc"
+11 29 "tqdec"
+11 30 "tb"
+11 31 "tldot"
+11 32 "tlhyph"
+11 33 "tlul"
+11 34 "tlth"
+11 35 "tleq"
+11 36 "pnlvl"
+11 37 "pnlvlblt"
+11 38 "pnlvlbody"
+11 39 "pnlvlcont"
+11 40 "pnnumonce"
+11 41 "pnacross"
+11 42 "pnhang"
+11 43 "pnrestart"
+11 44 "pncard"
+11 45 "pndec"
+11 46 "pnucltr"
+11 47 "pnucrm"
+11 48 "pnlcltr"
+11 49 "pnlcrm"
+11 50 "pnord"
+11 51 "pnordt"
+11 52 "pnb"
+11 53 "pni"
+11 54 "pncaps"
+11 55 "pnscaps"
+11 56 "pnul"
+11 57 "pnuld"
+11 58 "pnuldb"
+11 59 "pnulnone"
+11 60 "pnulw"
+11 61 "pnstrike"
+11 62 "pncf"
+11 63 "pnf"
+11 64 "pnfs"
+11 65 "pnindent"
+11 66 "pnsp"
+11 67 "pnprev"
+11 68 "pnqc"
+11 69 "pnql"
+11 70 "pnqr"
+11 71 "pnstart"
+11 72 "brdrt"
+11 73 "brdrb"
+11 74 "brdrl"
+11 75 "brdrr"
+11 76 "brdrbtw"
+11 77 "brdrbar"
+11 78 "box"
+11 79 "brdrs"
+11 80 "brdrth"
+11 81 "brdrsh"
+11 82 "brdrdb"
+11 83 "brdrdot"
+11 83 "brdrdash"
+11 85 "brdrhair"
+11 86 "brdrw"
+11 87 "brdrcf"
+11 88 "brsp"
+11 89 "shading"
+11 90 "bghoriz"
+11 91 "bgvert"
+11 92 "bgfdiag"
+11 93 "bgbdiag"
+11 94 "bgcross"
+11 95 "bgdcross"
+11 96 "bgdkhoriz"
+11 97 "bgdkvert"
+11 98 "bgdkfdiag"
+11 99 "bgdkbdiag"
+11 100 "bgdkcross"
+11 101 "bgdkdcross"
+11 102 "cfpat"
+11 103 "cbpat"
+11 39 "ls"
+11 40 "ilvl"
+9 0 "sectd"
+9 1 "endnhere"
+9 2 "binfsxn"
+9 3 "binsxn"
+9 4 "ds"
+9 5 "sbknone"
+9 6 "sbkcol"
+9 7 "sbkpage"
+9 8 "sbkeven"
+9 9 "sbkodd"
+9 10 "cols"
+9 11 "colsx"
+9 12 "colno"
+9 13 "colsr"
+9 14 "colw"
+9 15 "linebetcol"
+9 16 "linemod"
+9 17 "linex"
+9 18 "linestarts"
+9 19 "linerestart"
+9 20 "lineppage"
+9 21 "linecont"
+9 22 "pgwsxn"
+9 23 "pghsxn"
+9 24 "marglsxn"
+9 25 "margrsxn"
+9 26 "margtsxn"
+9 27 "margbsxn"
+9 28 "guttersxn"
+9 29 "lndscpsxn"
+9 30 "titlepg"
+9 31 "headery"
+9 32 "footery"
+9 33 "pgnstarts"
+9 34 "pgncont"
+9 35 "pgnrestart"
+9 36 "pgnx"
+9 37 "pgny"
+9 38 "pgndec"
+9 39 "pgnucrm"
+9 40 "pgnlcrm"
+9 41 "pgnucltr"
+9 42 "pgnlcltr"
+9 43 "pgnhnsh"
+9 44 "pgnhnsp"
+9 45 "pgnhnsc"
+9 46 "pgnhnsm"
+9 47 "pgnhnsn"
+9 48 "vertalt"
+9 49 "vertalb"
+9 50 "vertalc"
+9 51 "vertalj"
+9 52 "rtlsect"
+9 53 "ltrsect"
+9 54 "horzsect"
+9 55 "vertsect"
+9 100 "sectexpand"
+9 100 "sectlinegrid"
+9 100 "sectdefaultcl"
+9 100 "sectspecifycl"
+9 100 "sectspecifyl"
+9 100 "sectspecifygen"
+9 56 "pgnhn"
+9 57 "sectunlocked"
+8 160 "uc"
+8 0 "deftab"
+8 1 "hyphhotz"
+8 2 "hyphconsec"
+8 3 "hyphcaps"
+8 4 "hyphauto"
+8 5 "linestart"
+8 6 "fracwidth"
+8 7 "makeback"
+8 7 "makebackup"
+8 8 "defformat"
+8 9 "psover"
+8 10 "doctemp"
+8 11 "deflang"
+8 150 "deflangfe"
+8 151 "windowcaption"
+8 152 "doctype"
+8 153 "fromtext"
+8 154 "fromhtml"
+8 155 "horzdoc"
+8 156 "vertdoc"
+8 157 "jcompress"
+8 158 "jexpand"
+8 159 "lnongrid"
+8 78 "viewkind"
+8 79 "viewscale"
+8 79 "viewzk"
+8 12 "fet"
+8 13 "endnotes"
+8 14 "enddoc"
+8 15 "ftntj"
+8 16 "ftnbj"
+8 17 "aendnotes"
+8 18 "aenddoc"
+8 19 "aftntj"
+8 20 "aftnbj"
+8 21 "ftnstart"
+8 22 "aftnstart"
+8 23 "ftnrstpg"
+8 24 "ftnrestart"
+8 25 "ftnrstcont"
+8 26 "aftnrestart"
+8 27 "aftnrstcont"
+8 28 "ftnnar"
+8 29 "ftnnalc"
+8 30 "ftnnauc"
+8 31 "ftnnrlc"
+8 32 "ftnnruc"
+8 33 "ftnnchi"
+8 34 "aftnnar"
+8 35 "aftnnalc"
+8 36 "aftnnauc"
+8 37 "aftnnrlc"
+8 38 "aftnnruc"
+8 39 "aftnnchi"
+8 40 "paperw"
+8 41 "paperh"
+8 42 "psz"
+8 43 "margl"
+8 44 "margr"
+8 45 "margt"
+8 46 "margb"
+8 47 "facingp"
+8 48 "gutter"
+8 49 "margmirror"
+8 50 "landscape"
+8 51 "pgnstart"
+8 52 "widowctrl"
+8 53 "linkstyles"
+8 54 "notabind"
+8 55 "wraptrsp"
+8 56 "prcolbl"
+8 57 "noextrasprl"
+8 58 "nocolbal"
+8 59 "cvmme"
+8 60 "sprstsp"
+8 61 "sprsspbf"
+8 62 "otblrul"
+8 63 "transmf"
+8 64 "swpbdr"
+8 65 "brkfrm"
+8 82 "formprot"
+8 83 "allprot"
+8 84 "formshade"
+8 85 "formdisp"
+8 86 "printdata"
+8 87 "revprot"
+8 88 "revisions"
+8 89 "revprop"
+8 90 "revbar"
+8 91 "annotprot"
+8 92 "rtldoc"
+8 93 "ltrdoc"
+8 94 "cts"
+8 95 "dghspace"
+8 96 "dgvspace"
+8 97 "dghorigin"
+8 98 "dgvorigin"
+8 99 "dghshow"
+8 100 "dgvshow"
+8 101 "dgsnap"
+8 102 "dgmargin"
+8 103 "pgbrdrhead"
+8 104 "pgbrdrfoot"
+8 105 "aspalpha"
+8 106 "aspnum"
+8 107 "faauto"
+8 66 "truncex"
+8 67 "bdbfhdr"
+8 68 "dntblnsbdb"
+8 69 "expshrtn"
+8 70 "lytexcttp"
+8 71 "lytprtmet"
+8 72 "msmcap"
+8 73 "nolead"
+8 74 "nospaceforul"
+8 75 "noultrlspc"
+8 76 "noxlattoyen"
+8 77 "oldas"
+8 78 "lnbrkrule"
+8 79 "bdrrlswsix"
+8 81 "sprstsm"
+8 80 "nolnhtadjtbl"
+7 0 "additive"
+7 1 "sbasedon"
+7 2 "snext"
+7 3 "sautoupd"
+13 32 "emfblip"
+13 33 "pngblip"
+13 34 "jpegblip"
+13 36 "nonshppict"
+13 0 "macpict"
+13 1 "pmmetafile"
+13 2 "wmetafile"
+13 3 "dibitmap"
+13 4 "wbitmap"
+13 5 "wbmbitspixel"
+13 6 "wbmplanes"
+13 7 "wbmwidthbytes"
+13 8 "picw"
+13 9 "pich"
+13 10 "picwgoal"
+13 11 "pichgoal"
+13 10 "picwGoal"
+13 11 "pichGoal"
+13 12 "picscalex"
+13 13 "picscaley"
+13 14 "picscaled"
+13 15 "piccropt"
+13 16 "piccropb"
+13 17 "piccropl"
+13 18 "piccropr"
+13 19 "picbmp"
+13 20 "picbpp"
+13 21 "bin"
+13 22 "blipupi"
+13 24 "bliptag"
+15 0 "width"
+15 1 "height"
+3 0 "fonttbl"
+3 1 "falt"
+3 2 "fonteb"
+3 3 "fontfile"
+3 4 "filetbl"
+3 5 "file"
+3 6 "colortbl"
+3 7 "stylesheet"
+3 8 "keycode"
+3 9 "revtbl"
+3 10 "info"
+3 11 "title"
+3 12 "subject"
+3 13 "author"
+3 14 "operator"
+3 15 "keywords"
+3 16 "comment"
+3 18 "doccomm"
+3 19 "verscomm"
+3 20 "nextfile"
+3 21 "template"
+3 22 "ftnsep"
+3 23 "ftnsepc"
+3 24 "ftncn"
+3 25 "aftnsep"
+3 26 "aftnsepc"
+3 27 "aftncn"
+3 29 "pnseclvl"
+3 30 "header"
+3 31 "footer"
+3 32 "headerl"
+3 33 "headerr"
+3 34 "headerf"
+3 35 "footerl"
+3 36 "footerr"
+3 37 "footerf"
+3 38 "pntext"
+3 39 "pn"
+3 40 "pntxta"
+3 41 "pntxtb"
+3 42 "bkmkstart"
+3 43 "bkmkend"
+3 44 "pict"
+3 45 "object"
+3 46 "objclass"
+3 47 "objname"
+3 48 "objtime"
+3 49 "objdata"
+3 50 "objalias"
+3 51 "objsect"
+3 53 "objitem"
+3 54 "objtopic"
+3 52 "result"
+3 55 "do"
+3 56 "footnote"
+3 57 "atrfstart"
+3 58 "atrfend"
+3 59 "atnid"
+3 60 "atnauthor"
+3 61 "annotation"
+3 62 "atnref"
+3 63 "atntime"
+3 64 "atnicn"
+3 65 "field"
+3 66 "fldinst"
+3 67 "fldrslt"
+3 68 "datafield"
+3 69 "xe"
+3 70 "txe"
+3 71 "rxe"
+3 72 "tc"
+3 73 "NeXTGraphic"
+3 74 "NeXTHelpMarker"
+3 28 "NeXTHelpLink"
+3 75 "buptim"
+3 76 "creatim"
+3 77 "printim"
+3 78 "revtim"
+3 79 "dptxbxtext"
+3 80 "fontemb"
+3 81 "tcn"
+3 35 "shppict"
+3 41 "listtext"
+3 79 "private"
+3 82 "shpgrp"
+4 0 "fnil"
+4 1 "froman"
+4 2 "fswiss"
+4 3 "fmodern"
+4 4 "fscript"
+4 5 "fdecor"
+4 6 "ftech"
+4 7 "fbidi"
+23 0 "fcharset"
+23 1 "fprq"
+23 2 "cpg"
+23 3 "ftnil"
+23 4 "fttruetype"
+24 0 "fid"
+24 1 "frelative"
+24 2 "fosnum"
+25 0 "fvalidmac"
+25 1 "fvaliddos"
+25 2 "fvalidntfs"
+25 3 "fvalidhpfs"
+25 4 "fnetwork"
+5 0 "red"
+5 1 "green"
+5 2 "blue"
+2 2 "mac"
+2 0 "ansi"
+2 3 "pc"
+2 4 "pca"
+2 1 "ansicpg"
+10 0 "trowd"
+10 1 "trgaph"
+10 2 "cellx"
+10 3 "clmgf"
+10 4 "clmrg"
+10 5 "trql"
+10 6 "trqr"
+10 7 "trqc"
+10 8 "trleft"
+10 9 "trrh"
+10 10 "trhdr"
+10 11 "trkeep"
+10 12 "rtlrow"
+10 13 "ltrrow"
+10 14 "trbrdrt"
+10 15 "trbrdrl"
+10 16 "trbrdrb"
+10 17 "trbrdrr"
+10 18 "trbrdrh"
+10 19 "trbrdrv"
+10 20 "clbrdrb"
+10 21 "clbrdrt"
+10 22 "clbrdrl"
+10 23 "clbrdrr"
+10 42 "clvertalt"
+10 43 "clvertalc"
+10 44 "clvertalb"
+10 45 "cltxlrtb"
+10 46 "cltxlbrl"
+10 24 "clshdng"
+10 25 "clbghoriz"
+10 26 "clbgvert"
+10 27 "clbgfdiag"
+10 28 "clbgbdiag"
+10 29 "clbgcross"
+10 30 "clbgdcross"
+10 31 "clbgdkhoriz"
+10 31 "clbgdkhor"
+10 32 "clbgdkvert"
+10 33 "clbgdkfdiag"
+10 34 "clbgdkbdiag"
+10 35 "clbgdkcross"
+10 36 "clbgdkdcross"
+10 37 "clcfpat"
+10 38 "clcbpat"
+16 0 "flddirty"
+16 1 "fldedit"
+16 2 "fldlock"
+16 3 "fldpriv"
+16 4 "fldalt"
+18 0 "absw"
+18 1 "absh"
+18 2 "phmrg"
+18 3 "phpg"
+18 4 "phcol"
+18 5 "posx"
+18 6 "posnegx"
+18 7 "posxc"
+18 8 "posxi"
+18 9 "posxo"
+18 10 "posxr"
+18 11 "posxl"
+18 12 "pvmrg"
+18 13 "pvpg"
+18 14 "pvpara"
+18 15 "posy"
+18 16 "posnegy"
+18 17 "posyil"
+18 18 "posyt"
+18 19 "posyc"
+18 20 "posyb"
+18 21 "nowrap"
+18 22 "dxfrtext"
+18 23 "dfrmtxtx"
+18 24 "dfrmtxty"
+18 25 "dyfrtext"
+18 26 "dropcapli"
+18 27 "dropcapt"
+19 0 "objemb"
+19 1 "objlink"
+19 2 "objautlink"
+19 3 "objsub"
+19 4 "objpub"
+19 5 "objicemb"
+19 6 "linkself"
+19 7 "objupdate"
+19 8 "objlock"
+19 9 "objh"
+19 10 "objw"
+19 11 "objsetsize"
+19 12 "objalign"
+19 13 "objtransy"
+19 14 "objcropt"
+19 15 "objcropb"
+19 16 "objcropl"
+19 17 "objcropr"
+19 18 "objscalex"
+19 19 "objscaley"
+19 20 "rsltrtf"
+19 21 "rsltpict"
+19 22 "rsltbmp"
+19 23 "rslttxt"
+19 24 "rsltmerge"
+19 25 "bkmkpub"
+19 26 "pubauto"
+22 0 "ab"
+22 1 "acaps"
+22 2 "acf"
+22 3 "adn"
+22 4 "aexpnd"
+22 5 "af"
+22 6 "afs"
+22 7 "ai"
+22 8 "alang"
+22 9 "aoutl"
+22 10 "ascaps"
+22 11 "ashad"
+22 12 "astrike"
+22 13 "aul"
+22 14 "auld"
+22 15 "auldb"
+22 16 "aulnone"
+22 17 "aulw"
+22 18 "aup"
+20 0 "ftnalt"
+21 0 "alt"
+21 1 "shift"
+21 2 "ctrl"
+21 3 "fn"
+14 0 "bkmkcolf"
+14 1 "bkmkcoll"
+27 0 "xef"
+27 1 "bxe"
+27 2 "ixe"
+17 0 "tcf"
+17 1 "tcl"
+26 0 "dolock"
+26 1 "dobxpage"
+26 2 "dobxcolumn"
+26 3 "dobxmargin"
+26 4 "dobypage"
+26 6 "dobymargin"
+26 7 "dodhgt"
+26 8 "dpgroup"
+26 9 "dpcount"
+26 10 "dpendgroup"
+26 11 "dparc"
+26 12 "dpcallout"
+26 13 "dpellipse"
+26 14 "dpline"
+26 15 "dppolygon"
+26 16 "dppolyline"
+26 17 "dprect"
+26 18 "dptxbx"
+26 19 "dpx"
+26 20 "dpxsize"
+26 21 "dpy"
+26 22 "dpysize"
+26 23 "dpcoa"
+26 24 "dpcoaccent"
+26 25 "dpcobestfit"
+26 26 "dpcoborder"
+26 27 "dpcodabs"
+26 28 "dpcodbottom"
+26 29 "dpcodcenter"
+26 30 "dpcodtop"
+26 31 "dpcolength"
+26 32 "dpcominusx"
+26 33 "dpcominusy"
+26 34 "dpcooffset"
+26 35 "dpcosmarta"
+26 36 "dpcotdouble"
+26 37 "dpcotright"
+26 38 "dpcotsingle"
+26 39 "dpcottriple"
+26 40 "dptxbxmar"
+26 42 "dproundr"
+26 43 "dpptx"
+26 44 "dppty"
+26 45 "dppolycount"
+26 46 "dparcflipx"
+26 47 "dparcflipy"
+26 48 "dplinecob"
+26 49 "dplinecog"
+26 50 "dplinecor"
+26 51 "dplinepal"
+26 52 "dplinedado"
+26 53 "dplinedadodo"
+26 54 "dplinedash"
+26 55 "dplinedot"
+26 56 "dplinegray"
+26 57 "dplinehollow"
+26 58 "dplinesolid"
+26 59 "dplinew"
+26 60 "dpaendhol"
+26 61 "dpaendl"
+26 62 "dpaendsol"
+26 63 "dpaendw"
+26 64 "dpastarthol"
+26 65 "dpastartl"
+26 66 "dpastartsol"
+26 67 "dpastartw"
+26 68 "dpfillbgcb"
+26 69 "dpfillbgcg"
+26 70 "dpfillbgcr"
+26 71 "dpfillbgpal"
+26 72 "dpfillbggray"
+26 73 "dpfillfgcb"
+26 74 "dpfillfgcg"
+26 75 "dpfillfgcr"
+26 76 "dpfillfgpal"
+26 77 "dpfillfggray"
+26 78 "dpfillpat"
+26 79 "dpshadow"
+26 80 "dpshadx"
+26 81 "dpshady"
+26 82 "dobypara"
+0 -1 "rtf"
+1 -1 "deff"
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/wv/wvHtml.xml
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/wv/wvHtml.xml	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/wv/wvHtml.xml	(revision 10506)
@@ -0,0 +1,397 @@
+<main>
+<charentity>
+<begin>HTML</begin>
+</charentity>
+
+<document>
+<begin>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/REC-html40/loose.dtd&quot;&gt;
+&lt;html&gt; 
+&lt;head&gt; 
+&lt;META HTTP-EQUIV=&quot;Content-Type&quot; CONTENT=&quot;text/html; charset=<charset/>&quot;&gt;
+&lt;META NAME=&quot;GENERATOR&quot; CONTENT=&quot;wvWare/<version/>&quot;&gt;
+&lt;title&gt; 
+<title/>
+&lt;/title&gt; 
+&lt;/head&gt; 
+&lt;body bgcolor=&quot;#FFFFFF&quot; text=&quot;#000000&quot; link=&quot;#0000ee&quot; vlink=&quot;#551a8b&quot;&gt;
+</begin>
+<end>
+&lt;/body&gt;
+&lt;/html&gt;
+</end>
+</document>
+
+<section>
+<begin>
+&lt;!--Section Begins--&gt;&lt;br&gt;
+</begin>
+<end>
+&lt;!--Section Ends--&gt;
+</end>
+</section>
+
+<justification>
+<left>left</left>
+<right>right</right>
+<center>center</center>
+<block>justify</block>
+<asian>&lt;!--Could Someone who sees this tag tell me what was is this type of justification, asian languages only i thing--&gt;</asian>
+</justification>
+
+<numbering>
+<Arabic>type=&quot;1&quot;</Arabic>
+<UpperRoman>type=&quot;I&quot;</UpperRoman>
+<LowerRoman>type=&quot;i&quot;</LowerRoman>
+<UpperCaseN>type=&quot;A&quot;</UpperCaseN>
+<LowerCaseN>type=&quot;a&quot;</LowerCaseN>
+</numbering>
+
+<border>
+<noned>none</noned>
+<singled>solid</singled>
+<thickd>solid</thickd>
+<doubled>double</doubled>
+<number4d>double</number4d>
+<hairlined>solid</hairlined>
+<dotd>dotted</dotd>
+<dashlargegapd>dashed</dashlargegapd>
+<dotdashd>dotted</dotdashd>
+<dotdotdashd>dotted</dotdotdashd>
+<tripled>double</tripled>
+<thin-thicksmallgapd>dashed</thin-thicksmallgapd>
+<thick-thinsmallgapd>dashed</thick-thinsmallgapd>
+<thin-thick-thinsmallgapd>dashed</thin-thick-thinsmallgapd>
+<thin-thickmediumgapd>dashed</thin-thickmediumgapd>
+<thick-thinmediumgapd>dashed</thick-thinmediumgapd>
+<thin-thick-thinmediumgapd>dashed</thin-thick-thinmediumgapd>
+<thin-thicklargegapd>dashed</thin-thicklargegapd>
+<thick-thinlargegapd>dashed</thick-thinlargegapd>
+<thin-thick-thinlargegapd>dashed</thin-thick-thinlargegapd>
+<waved>solid</waved>
+<doublewaved>double</doublewaved>
+<dashsmallgapd>sashed</dashsmallgapd>
+<dashdotstrokedd>dashed</dashdotstrokedd>
+<emboss3Dd>ridge</emboss3Dd>
+<engrave3Dd>groove</engrave3Dd>
+<defaultd>ridge</defaultd>
+</border>
+
+<olist>
+<begin>&lt;ol <nfc/> start=&quot;<start/>&quot;&gt;
+</begin>
+<end>&lt;/ol&gt;</end>
+</olist>
+
+<ulist>
+<begin>&lt;ul&gt;
+</begin>
+<end>&lt;/ul&gt;</end>
+</ulist>
+
+<entry>
+<begin>&lt;li&gt;</begin>
+<end></end>
+</entry>
+
+
+<!-- 
+this tableoverride option can be used to turn off handling of
+these tags in tables, which I find is necessary for at least netscape
+-->
+<tableoverrides>
+<ParaBefore>0</ParaBefore>
+<ParaRight>0</ParaRight>
+<ParaAfter>0</ParaAfter>
+<ParaLeft>0</ParaLeft>
+<ParaLeft1>0</ParaLeft1>
+<VertMergedCells>0</VertMergedCells>
+</tableoverrides>
+
+<table>
+<begin>&lt;table width=&quot;<tablerelwidth/>%&quot; border=&quot;1&quot; cols=&quot;<no_cols/>&quot; rows=&quot;<no_rows/>&quot;&gt;</begin>
+<end>&lt;/table&gt;</end>
+</table>
+
+<row>
+<begin>&lt;tr&gt;</begin>
+<end>&lt;/tr&gt;</end>
+</row>
+
+<cell>
+<begin>&lt;td bgcolor=&quot;<cellbgcolor/>&quot; width=&quot;<cellrelwidth/>%&quot; rowspan=&quot;<rowspan/>&quot; colspan=&quot;<colspan/>&quot;&gt;</begin>
+<end>&lt;/td&gt;</end>
+</cell>
+
+<paragraph>
+<begin>
+<table.end/>
+<table.begin/>
+<row.begin/>
+<cell.begin/><olist.end/><olist.begin/><ulist.end/><ulist.begin/><entry.begin/>
+<text.begin/>
+</begin>
+<end>
+<text.end/>
+<entry.end/>
+<olist.end/>
+<ulist.end/>
+<cell.end/>
+<row.end/>
+</end>
+</paragraph>
+
+<!-- these are all the character properties that can show up in word -->
+<bold><begin>&lt;b&gt;</begin><end>&lt;/b&gt;</end></bold>
+<italic><begin>&lt;i&gt;</begin><end>&lt;/i&gt;</end></italic>
+
+<!--
+text that has been deleted and will be displayed with strikethrough when
+revision marked text is to be displayed
+
+use either this line...
+--> 
+<RMarkDel><begin>&lt;s&gt;</begin><end>&lt;/s&gt;&lt;a href=&quot;#author<ibstRMarkDel/>&quot;&gt;[Author ID<ibstRMarkDel/>: at <dttmRMarkDel/> ]&lt;/a&gt;</end></RMarkDel>
+
+<!--
+or uncomment below to make deleted text dissappear (well, become commented out)
+-->
+<!--
+<RMarkDel><begin>&lt;!-&#45;</begin><end>-&#45;&gt;</end></RMarkDel>
+-->
+
+<!-- I don't even know what outline means -->
+<outline><begin></begin><end></end></outline>
+<smallcaps><begin></begin><end></end></smallcaps>
+<caps><begin></begin><end></end></caps>
+<vanish><begin></begin><end></end></vanish>
+
+<!--If you uncomment this then the annotation text links will become commented out by html tags-->
+<!--
+<vanish><begin>&lt;!-&#45;</begin><end>-&#45;&gt;</end></vanish>
+-->
+
+<!--
+text that has been newly typed since the last time revision marks have been accepted
+and will be displayed with underline when revision marked text is to be displayed
+
+use either this line...
+-->
+<RMark><begin>&lt;u&gt;</begin><end>&lt;/u&gt;&lt;a href=&quot;#author<ibstRMark/>&quot;&gt;[Author ID<ibstRMark/>: at <dttmRMark/>]&lt;/a&gt;</end></RMark>
+
+<!--
+or uncomment below to make the underline dissappear
+-->
+<!--
+<RMark><begin></begin><end></end></RMark>
+-->
+
+
+<strike><begin>&lt;s&gt;</begin><end>&lt;/s&gt;</end></strike>
+<shadow><begin></begin><end></end></shadow>
+<lowercase><begin></begin><end></end></lowercase>
+<emboss><begin></begin><end></end></emboss>
+<imprint><begin></begin><end></end></imprint>
+<!--double strike-->
+<dstrike><begin>&lt;s&gt;</begin><end>&lt;/s&gt;</end></dstrike>
+
+<!--
+ftc's
+&
+hps
+
+keep them for font face and do that later.
+-->
+
+<super><begin>&lt;sup&gt;</begin><end>&lt;/sup&gt;</end></super>
+<sub><begin>&lt;sub&gt;</begin><end>&lt;/sub&gt;</end></sub>
+
+<singleu><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></singleu>
+<wordu><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></wordu>
+<doubleu><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></doubleu>
+<dottedu><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></dottedu>
+<hiddenu><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></hiddenu>
+<thicku><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></thicku>
+<dashu><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></dashu>
+<dotu><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></dotu>
+<dotdashu><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></dotdashu>
+<dotdotdashu><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></dotdotdashu>
+<waveu><begin>&lt;u&gt;</begin><end>&lt;/u&gt;</end></waveu>
+
+<!--
+text whose properties have been changed since the last time revision marks have been accepted
+and will be displayed with a note showing the change points.
+
+use either this line (which admit it a bit scary looking, but harmless)...
+--> 
+<PropRMark><begin>&lt;a href=&quot;#author<ibstPropRMark/>&quot;&gt;-&#45;&amp;gt;&lt;/a&gt;</begin><end>&lt;a href=&quot;#author<ibstPropRMark/>&quot;&gt;[Author ID<ibstPropRMark/>: at <dttmPropRMark/>]&lt;/a&gt;</end></PropRMark>
+
+<!--
+or uncomment below to make the notes dissappear
+-->
+<!--
+<PropRMark><begin></begin><end></end></PropRMark>
+-->
+
+<!--
+<color>
+-->
+<Black><begin>Black</begin><end></end></Black>
+<Blue><begin>Blue</begin><end></end></Blue>
+<Cyan><begin>Cyan</begin><end></end></Cyan>
+<Green><begin>Green</begin><end></end></Green>
+<Magenta><begin>Magenta</begin><end></end></Magenta>
+<Red><begin>Red</begin><end></end></Red>
+<Yellow><begin>Yellow</begin><end></end></Yellow>
+<White><begin>White</begin><end></end></White>
+<DkBlue><begin>DarkBlue</begin><end></end></DkBlue>
+<DkCyan><begin>DarkCyan</begin><end></end></DkCyan>
+<DkGreen><begin>DarkGreen</begin><end></end></DkGreen>
+<DkMagenta><begin>DarkMagenta</begin><end></end></DkMagenta>
+<DkRed><begin>DarkRed</begin><end></end></DkRed>
+<DkYellow><begin>#8b8b00</begin><end></end></DkYellow>
+<DkGray><begin>DarkGray</begin><end></end></DkGray>
+<LtGray><begin>LightGrey</begin><end></end></LtGray>
+<!--
+</color>
+-->
+
+<!--
+<animation>
+-->
+<LasVegas><begin>&lt;blink&gt;</begin><end>&lt;/blink&gt;</end></LasVegas>
+<BackgroundBlink><begin>&lt;blink&gt;</begin><end>&lt;/blink&gt;</end></BackgroundBlink>
+<SparkleText><begin>&lt;blink&gt;</begin><end>&lt;/blink&gt;</end></SparkleText>
+<MarchingAnts><begin>&lt;blink&gt;</begin><end>&lt;/blink&gt;</end></MarchingAnts>
+<MarchingRedAnts><begin>&lt;blink&gt;</begin><end>&lt;/blink&gt;</end></MarchingRedAnts>
+<Shimmer><begin>&lt;blink&gt;</begin><end>&lt;/blink&gt;</end></Shimmer>
+<!--
+</animation>
+-->
+
+<!--
+I dont understand what this one is, and ive never come across it
+
+use this sample line (which admit it a bit scary looking, but harmless)...
+-->
+<DispFldRMark><begin>&lt;a href=&quot;#author<ibstDispFldRMark/>&quot;&gt;--&amp;gt;&lt;/a&gt;</begin><end>&lt;a href=&quot;#author<ibstDispFldRMark/>&quot;&gt;[Author ID<ibstDispFldRMark/>: at <dttmDispFldRMark/> (<xstDispFldRMark/>)]&lt;/a&gt;</end></DispFldRMark>
+
+<!--
+or uncomment below to ignore it, the previous might even crash wv ?
+-->
+<!--
+<DispFldRMark><begin></begin><end></end></DispFldRMark>
+-->
+
+<animation>
+<begin><LasVegas.begin/><BackgroundBlink.begin/><SparkleText.begin/><MarchingAnts.begin/><MarchingRedAnts.begin/><Shimmer.begin/></begin>
+<end><Shimmer.end/><MarchingRedAnts.end/><MarchingAnts.end/><SparkleText.end/><BackgroundBlink.end/><LasVegas.end/></end>
+</animation>
+
+<fontstr>
+<begin>&lt;font color=&quot;<black.begin/><blue.begin/><cyan.begin/><green.begin/><magenta.begin/><red.begin/><yellow.begin/><white.begin/><dkblue.begin/><dkcyan.begin/><dkgreen.begin/><dkmagenta.begin/><dkred.begin/><dkyellow.begin/><dkgray.begin/><ltgray.begin/>&quot;&gt;</begin>
+<end><ltgray.end/><dkgray.end/><dkyellow.end/><dkred.end/><dkmagenta.end/><dkgreen.end/><dkcyan.end/><dkblue.end/><white.end/><yellow.end/><red.end/><magenta.end/><green.end/><cyan.end/><blue.end/><black.end/>&lt;/font&gt;</end>
+</fontstr>
+
+<comment>
+<begin>
+&lt;a href=&quot;#comment<ibstAnno/> &quot;&gt;-&#45;&amp;gt;&lt;/a&gt;
+</begin>
+<end>&lt;a href=&quot;#comment<ibstAnno/> &quot;&gt;[Author:<xstUsrInitl/>]&lt;/a&gt;
+</end>
+</comment>
+
+<style name="Normal">
+<character>
+<begin><PropRMark.begin/><DispFldRMark.begin/><animation.begin/><fontstr.begin/><bold.begin/><italic.begin/><strike.begin/><RMarkDel.begin/><outline.begin/><smallcaps.begin/><caps.begin/><vanish.begin/><RMark.begin/><shadow.begin/><lowercase.begin/><emboss.begin/><imprint.begin/><dstrike.begin/><super.begin/><sub.begin/><singleu.begin/><wordu.begin/><doubleu.begin/><dottedu.begin/><hiddenu.begin/><thicku.begin/><dashu.begin/><dotu.begin/><dotdashu.begin/><dotdotdashu.begin/><waveu.begin/></begin>
+<end><waveu.end/><dotdotdashu.end/><dotdashu.end/><dotu.end/><dashu.end/><thicku.end/><hiddenu.end/><dottedu.end/><doubleu.end/><wordu.end/><singleu.end/><sub.end/><super.end/><dstrike.end/><imprint.end/><emboss.end/><lowercase.end/><shadow.end/><RMark.end/><vanish.end/><caps.end/><smallcaps.end/><outline.end/><RMarkDel.end/><strike.end/><italic.end/><bold.end/><fontstr.end/><animation.end/><DispFldRMark.end/><PropRMark.end/></end>
+</character>
+
+<!-- Netscape does handle this correctly yet, here is how each different side of the border should work.
+border-top: thin <bordertopstyle/> <bordertopcolor/>;
+border-left: thin <borderleftstyle/> <borderleftcolor/>;
+border-right: thin <borderrightstyle/> <borderrightcolor/>;
+border-bottom: thin <borderbottomstyle/> <borderbottomcolor/>
+-->
+
+
+<pmargin>
+<begin>margin: <mmParaBefore/> <mmParaRight/> <mmParaAfter/> <mmParaLeft/>;</begin>
+</pmargin>
+
+<pborder>
+<begin>
+border: thin <borderleftstyle/> <borderleftcolor/>;
+<!--
+border-top: thin <bordertopstyle/> <bordertopcolor/>;
+border-left: thin <borderleftstyle/> <borderleftcolor/>;
+border-right: thin <borderrightstyle/> <borderrightcolor/>;
+border-bottom: thin <borderbottomstyle/> <borderbottomcolor/>
+-->
+</begin>
+</pborder>
+
+<text>	
+<begin>
+&lt;div align=&quot;<just/>&quot; style=&quot;<paramargin/> <paraborder/>
+padding: <mmPadTop/> <mmPadRight/> <mmPadBottom/> <mmPadLeft/>; &quot;&gt;
+&lt;p style=&quot;text-indent: <mmParaLeft1/>; text-align: <just/>; color: <parafgcolor/>; background-color: <parabgcolor/>; &quot;&gt;
+</begin>
+<end>
+&lt;/p&gt;
+&lt;/div&gt;
+</end>
+</text>
+
+<picture>
+<begin>
+&lt;img <htmlAlignGuess/> width=&quot;<pixPicWidth/>&quot; height=&quot;<pixPicHeight/>&quot; alt=&quot;0x01 graphic&quot; src=&quot;placeholder.png&quot;&gt;<htmlNextLineGuess/>
+</begin>
+</picture>
+
+</style>
+
+<!--we need to be override the character properties-->
+<!--
+<style name="Normal">
+<character>
+<begin><PropRMark.begin/><DispFldRMark.begin/><animation.begin/><fontstr.begin/><bold.begin/><italic.begin/><strike.begin/><RMarkDel.begin/><outline.begin/><smallcaps.begin/><caps.begin/><vanish.begin/><RMark.begin/><shadow.begin/><lowercase.begin/><emboss.begin/><imprint.begin/><dstrike.begin/><super.begin/><sub.begin/><singleu.begin/><wordu.begin/><doubleu.begin/><dottedu.begin/><hiddenu.begin/><thicku.begin/><dashu.begin/><dotu.begin/><dotdashu.begin/><dotdotdashu.begin/><waveu.begin/></begin>
+<end><waveu.end/><dotdotdashu.end/><dotdashu.end/><dotu.end/><dashu.end/><thicku.end/><hiddenu.end/><dottedu.end/><doubleu.end/><wordu.end/><singleu.end/><sub.end/><super.end/><dstrike.end/><imprint.end/><emboss.end/><lowercase.end/><shadow.end/><RMark.end/><vanish.end/><caps.end/><smallcaps.end/><outline.end/><RMarkDel.end/><strike.end/><italic.end/><bold.end/><fontstr.end/><animation.end/><DispFldRMark.end/><PropRMark.end/></end>
+</character>
+
+<text>	
+<begin>
+&lt;div align=&quot;<just/>&quot;&gt;
+&lt;p&gt;
+</begin>
+<end>
+&lt;/p&gt;
+&lt;/div&gt;
+</end>
+</text>
+
+</style>
+
+<style name="Heading 1">
+
+<character>
+<begin></begin>
+<end></end>
+</character>
+
+<text>	
+<begin>
+&lt;div align=&quot;<just/>&quot;&gt;
+&lt;H1&gt;
+</begin>
+<end>
+&lt;/H1&gt;
+&lt;/div&gt;
+</end>
+</text>
+
+
+
+</style>
+-->
+
+</main>
Index: /tags/gsdl-2_61-distribution/gsdl/etc/packages/z3950.cfg
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/etc/packages/z3950.cfg	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/etc/packages/z3950.cfg	(revision 10506)
@@ -0,0 +1,43 @@
+[GSDL2.1] # config file version
+#
+# This file specifies a list of z39.50 servers to use.
+# Each field is separated by white-space.
+# If you want a " character inside a string, escape it - ie \" or ""
+
+#
+# Each server configuration consists of a stanza. The items are described here:
+#	Item				Description
+#	###############			########################
+#	collectname			<GSDL internal name (alphanumeric) >
+#	servername:port			<Internet address (def. port is 210) >
+#	dbname				<z39.50 server database name>
+#	"humanname"			<Brief description>
+#	icon "url to icon"		<optional GSDL icon (eg collection) >
+#	smallicon "url to small icon"	<optional GSDL icon (eg homepage) >
+#	About "about text"		<optional>
+
+
+# For an exhaustive list of servers to try, have a look at
+#  http://www.indexdata.dk/targettest/
+
+
+#LOCtest
+#       ilssun2.loc.gov:7090
+#       Voyager
+#       "Library of Congress TEST z39.50 server"
+#       About "This database/server is provided by the US LoC for the testing
+#           of z39.50 clients. For server capabilities, look at
+#           <a href=\"http://lcweb.loc.gov/z3950/lcserver.html\">their web 
+#           pages</a>. Note that <b>no records will ever be returned</b> -
+#           this server is for testing the protocols only."
+
+
+#LOC
+#        z3950.loc.gov:7090
+#        Voyager
+#        "Library of Congress z39.50 server"
+#        About   "This is the z39.50 interface to the US LoC catalogue
+#           system. It contains approximately 12 million bibliographic records.
+#           For server capabilities, look at
+#           <a href=\"http://lcweb.loc.gov/z3950/lcserver.html\">their web 
+#           pages</a>."
Index: /tags/gsdl-2_61-distribution/gsdl/images/garish/style.css
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/images/garish/style.css	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/images/garish/style.css	(revision 10506)
@@ -0,0 +1,44 @@
+/* This style sheet is used only by the custom.dm macro as an
+  example of modifying the appearance */
+
+/* notes about style sheets.
+
+   Colours - The most portable way to specify colours is to use the
+     #xxxxxx notation, which is in hex for red, green, and blue.  eg black
+     is #000000, red is #ff0000, blue is #0000ff and white is #ffffff.
+     This may seem confusing at first, but you can't count on colour names
+     being the same across all browsers and platforms. For example,
+     linux/x11 has hundreds of colours with names such as DarkOliveGreen
+     and PaleVioletRed. However, simple colour names should work with most
+     browsers...
+
+*/
+   
+
+/* set defaults for the HTML body */
+body {
+ /* set the face. The first one in the list found will be used, so
+    have reasonable fall-backs */
+ /* use a serif font windows uses "times new roman", "times" on mac/linux */
+  font-family: times new roman, times, serif;
+ /* you can set a background colour, but a lot of the images/buttons are
+    designed to blend into a white background. */
+  background-color: pink;
+}
+
+
+/* paragraph text - this will override the settings above for text inside
+ <p>....</p> tags. Uncomment if you want to test it, although red text with
+ a pink background is pretty ugly :) */
+/*
+p {
+ color: red;
+}
+*/
+
+/* headings */
+h1, h2, h3, h4 {
+ /* use a sans-serif font - arial on windows, helvetica on mac/linux */
+ font-family: arial, helvetica, sans-serif;
+ color: blue;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/install-sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/install-sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/install-sh	(revision 10506)
@@ -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: /tags/gsdl-2_61-distribution/gsdl/lib/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/Makefile.in	(revision 10506)
@@ -0,0 +1,134 @@
+###########################################################################
+#
+# Makefile -- lib
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+AR = ar
+CC = @CC@
+CPP = @CXX@
+#CCFLAGS = @CFLAGS@ -Wall -Wunused -pedantic -W -Woverloaded-virtual
+CCFLAGS = @CFLAGS@
+MCFLAGS = -Wall -Wunused
+DEFS = @DEFS@
+INCLUDES = -I../packages/mg/lib -I..
+MICO_DIR = @MICO_DIR@
+ifeq ($(MICO_DIR), default)
+MICO_INC = -I../packages/mico/mico/include
+MICO_PATH = ../bin/linux/
+else
+ifeq ($(MICO_DIR), yes)
+MICO_INC =
+else
+MICO_INC = -I$(MICO_DIR)
+endif
+MICO_PATH =
+endif
+MINCLUDES = -I/usr/include/g++-2/ -I/usr/lib/gcc-lib/i386-slackware-linux/egcs-2.91.66/include/ -I/usr/include -I.  -I../packages/mg/lib $(MICO_INC) -I..
+RANLIB = @RANLIB@
+USE_CORBA = @USE_CORBA@
+
+COMPILE = $(CC) -c $(CCFLAGS) $(DEFS) $(INCLUDES)
+CPPCOMPILE = $(CPP) -c $(CCFLAGS) $(DEFS) $(INCLUDES)
+
+ifneq ($(USE_CORBA), 0)
+MCOMPILE = $(MICO_PATH)mico-c++ -x c++ $(MCFLAGS) $(DEFS) $(MINCLUDES) -c
+else
+MCOMPILE = $(COMPILE)
+endif
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CPPCOMPILE) $< 
+
+.SUFFIXES: .mpp .o
+.mpp.o:
+	$(MCOMPILE) $<
+
+
+
+
+ifneq ($(USE_CORBA), 0)
+CORBAHEADERS = \
+  corbaconv_text_t.h corbatext_t.h
+CORBASOURCES = \
+  corbaiface.mpp    corbatext_t.mpp  corbaconv_text_t.mpp corbaiface_skel.mpp
+CORBAOBJECTS = \
+  corbaiface.o      corbatext_t.o    corbaconv_text_t.o   corbaiface_skel.o 
+else
+CORBAHEADERS = 
+CORBASOURCE = 
+CORBAOBJECTS = 
+endif
+
+HEADERS = \
+  cfgread.h      fileutil.h     gsdlunicode.h  gsdltools.h text_t.h \
+  display.h      gsdlconf.h     gsdltimes.h    cnfgable.h  cnfgator.h \
+  $(CORBAHEADERS)
+
+
+SOURCES = \
+  cfgread.cpp      fileutil.cpp     text_t.cpp     cnfgable.cpp \
+  display.cpp      gsdlunicode.cpp  gsdltimes.cpp  gsdltools.cpp \
+  cnfgator.cpp     $(CORBASOURCES)
+
+OBJECTS = \
+  cfgread.o        fileutil.o       text_t.o     cnfgable.o \
+  display.o        gsdlunicode.o    gsdltimes.o  gsdltools.o \
+  cnfgator.o       $(CORBAOBJECTS)
+
+
+all: gsdllib.a
+corbaiface_skel.h: corbaiface.idl
+	LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH PATH=$(MICO_PATH):$(PATH) idl --boa --no-poa --c++-skel --c++-suffix=mpp $?
+corbaiface_skel.mpp: corbaiface.idl
+	LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH PATH=$(MICO_PATH):$(PATH) idl --boa --no-poa --c++-skel --c++-suffix=mpp $?
+corbaiface.mpp: corbaiface.idl
+	LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH PATH=$(MICO_PATH):$(PATH) idl --boa --no-poa --c++-skel --c++-suffix=mpp $?
+
+GSDLLIBOBJECTS = $(OBJECTS)
+
+gsdllib.a: $(GSDLLIBOBJECTS)
+	rm -f gsdllib.a
+	$(AR) cru gsdllib.a $(GSDLLIBOBJECTS)
+	$(RANLIB) gsdllib.a
+
+clean:
+	rm -f $(OBJECTS) gsdllib.a corbaiface_skel.mpp corbaiface.h corbaiface.mpp
+
+distclean: clean
+	rm -f Makefile
+install:
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/lib/cfgread.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/cfgread.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/cfgread.cpp	(revision 10506)
@@ -0,0 +1,220 @@
+/**********************************************************************
+ *
+ * cfgread.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "cfgread.h"
+#include <cctype> // for isspace()
+
+int write_ini_line (ofstream &fileout, const text_t &key, const text_t &value) {
+  if (key.empty() || value.empty()) return -1;
+  outconvertclass text_t2ascii;
+  fileout << text_t2ascii << key << "=" << value << "\n";
+  return 0;
+}
+
+int read_ini_line (ifstream &filein, text_t &key, text_t &value) {
+  if (filein.eof()) return -1;
+
+  key.clear();
+  value.clear();
+  char c;
+  filein.get(c);
+
+  int foundeq = 0;
+  while (!filein.eof() && c != '\n') {
+    if (!foundeq && c == '=') {foundeq = 1; filein.get(c);}
+
+    if (foundeq) value.push_back(c);
+    else key.push_back(c);
+    filein.get(c);
+  }
+  if (key.empty()) return 0; // blank line maybe?
+  return 0;
+} 
+
+// write out line of values to cfgfile
+// does nothing fancy - make sure no values contain carriage returns
+int write_cfg_line (ofstream &fileout, const text_tarray &values) {
+  outconvertclass text_t2ascii;
+
+  text_tarray::const_iterator here = values.begin();
+  text_tarray::const_iterator end = values.end();
+
+  bool first = true;
+  while (here != end) {
+    if (first) fileout << text_t2ascii << *here;
+    else fileout << text_t2ascii << "  \"" << *here << "\"";
+    first = false;
+    ++here;
+  }
+  fileout << "\n";
+  return 0;
+}
+
+// same, but use a file descriptor this time
+int write_cfg_line (int fileout, const text_tarray &values) {
+  outconvertclass text_t2ascii;
+
+  text_tarray::const_iterator here = values.begin();
+  text_tarray::const_iterator end = values.end();
+
+  if (here != end) {
+    char *s=here->getcstr();
+    write(fileout,s ,here->size());
+    delete []s;
+
+    ++here;
+  }
+  while (here != end) {
+    write(fileout, " \"", 2);
+    char *s=here->getcstr();
+    write(fileout,s ,here->size());
+    delete []s;
+    write(fileout, "\"", 1);
+
+    ++here;
+  }
+  write(fileout,"\n",1);
+  return 0;
+}
+
+
+// returns 0 on success, -1 on failure
+int read_cfg_line (ifstream &filein, text_tarray &values) {
+  // we split up the line into tokens, pushing each token into the
+  // values array. Quoted phrases are a single token. A "\" at the end
+  // of a line continues onto the next line.
+
+  values.erase(values.begin(), values.end());
+
+  if (!filein.good()) return -1;
+
+  text_t curvalue;
+  char c1;
+  filein.get(c1);
+
+  // skip white space
+  while (!filein.eof() && isspace((unsigned char) c1)) { filein.get(c1); }
+
+    // ignore comments
+  while (c1 == '#') {
+    while (!filein.eof() && c1!='\n' && c1!='\r') { filein.get(c1); }
+    // skip white space...
+    while (!filein.eof() && isspace((unsigned char) c1)) { filein.get(c1); }
+  }
+
+  // deal with all the records on this line (possibly multi-line)
+
+  while (!filein.eof()) {
+    if (c1=='\n' || c1=='\r') { // shouldn't happen?
+      break;
+    }
+
+    // get the next token
+    curvalue.clear();
+      
+    bool inquote=false;
+    char quotemark='"';
+    char preceding='\0'; // 1-char state to allow \" and \'
+    // see if this is a quoted phrase
+    if (c1=='\'' || c1=='\"') { // starts with a quote
+      inquote=true;
+      quotemark = c1;
+      preceding = c1; // just to initialise
+      filein.get(c1);
+    }
+
+    // get token or a whole phrase
+    while (!filein.eof()) {
+      if (isspace((unsigned char) c1)) {
+	if (! inquote) {
+	  // end of token, not inside quote marks
+	  break;
+	} else {
+	  // inside quote marks.
+	  /* Turn eol into space, in case other parsing bits expect eol to
+	     also mean end of parsing... */
+	  c1=' ';
+	}
+      }
+      if (c1 == quotemark && inquote && preceding != '\\') {
+	// end of quoted phrase found
+	inquote=false;
+	filein.get(c1);
+	continue;
+      }
+
+      // add current char to token/phrase
+      // see if current byte is part of a multibyte char (utf-8 only!)
+      unsigned short int c; // text_t uses 16bit unicode
+      unsigned char uc1=(unsigned)c1;
+      if (uc1 < 0x80) {
+	c=uc1;
+      } else if (uc1 >= 0xc0 && uc1 <= 0xdf) {
+	// 2-byte utf-8
+	unsigned char c2;
+	// two byte character
+	filein.get((char&)c2); // get takes a signed char
+	c = ((uc1 & 0x1f) << 6) + (c2 & 0x3f);
+      } else if (uc1 >= 0xe0 && uc1 <= 0xef) {
+	// 3-byte character
+	unsigned char c2, c3;
+	filein.get((char&)c2);
+	filein.get((char&)c3);
+	c = ((uc1 & 0xf) << 12) + ((c2 & 0x3f) << 6)
+	  + (c3 & 0x3f);
+      } else {c=uc1;} // we don't do group2/plane0 (4,5,6-byte utf-8)
+
+      curvalue.push_back(c); // 16bit unicode
+      if (inquote)
+	preceding = c1;
+
+      filein.get(c1);
+    }
+    // we now have a token or a phrase
+    
+    // see if we've reached the end of the line
+    if (c1 == '\n' || c1 == '\r') {
+      if (curvalue != "\\") { // the line DOESN'T continue. End of line.
+	values.push_back(curvalue);
+	break; // end of token/phrase
+      } else {
+	// swallow up the EOL chars
+	while (!filein.eof() && (c1=='\r' || c1=='\n')) filein.get(c1);
+	// the current token "\\" will be cleared below
+      }
+    } else { // no new line seen
+      values.push_back(curvalue);
+    }
+
+    curvalue.clear();
+
+    // remove whitespace (but not newline/CR chars) before next token
+    while (!filein.eof() && (c1==' ' || c1=='\t')) filein.get(c1);
+
+  } // while(1)
+  
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/lib/cfgread.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/cfgread.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/cfgread.h	(revision 10506)
@@ -0,0 +1,48 @@
+/**********************************************************************
+ *
+ * cfgread.h -- reads in configuration files
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef CFGREAD_H
+#define CFGREAD_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <fstream.h>
+#else
+#  include <fstream>
+#endif
+
+// return 0 on success, -1 on failure
+int write_ini_line (ofstream &fileout, const text_t &key, const text_t &value);
+int read_ini_line (ifstream &filein, text_t &key, text_t &value);
+int write_cfg_line (ofstream &fileout, const text_tarray &values);
+int write_cfg_line (int filedesc, const text_tarray &values);
+int read_cfg_line (ifstream &filein, text_tarray &values);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/cnfgable.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/cnfgable.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/cnfgable.cpp	(revision 10506)
@@ -0,0 +1,37 @@
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace/std/iostream>
+#  include <ospace/std/fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+#include "cnfgable.h"
+#include "cfgread.h"
+
+bool configurable::read_configfile (const text_t &filename) {
+  // read in the build configuration file
+  text_t key;
+  text_tarray cfgline;
+  char *cstr = filename.getcstr();
+  ifstream confin (cstr);
+  delete []cstr;
+
+  if (confin) {
+    while (read_cfg_line(confin, cfgline) >= 0) {
+      if (cfgline.size () >= 2) {
+	key = cfgline[0];
+	cfgline.erase(cfgline.begin());
+
+	// configure the collection server
+	this->configure (key, cfgline);
+      }
+    }
+    confin.close ();
+    return true;
+  }
+  return false;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/lib/cnfgable.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/cnfgable.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/cnfgable.h	(revision 10506)
@@ -0,0 +1,16 @@
+#ifndef CONFIGURABLE_H
+#define CONFIGURABLE_H
+
+#include "text_t.h"
+
+class configurable {
+ public:
+  virtual void configure (const text_t &key, const text_tarray &cfgline) = 0;
+  virtual ~configurable () {}
+
+  bool read_configfile (const text_t &filename);
+ protected:
+  configurable() {}
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/cnfgator.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/cnfgator.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/cnfgator.cpp	(revision 10506)
@@ -0,0 +1,52 @@
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace/std/iostream>
+#  include <ospace/std/fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+#include "cnfgator.h"
+
+configurator::configurator(configurable *configureobject) {
+  configureobjs.push_back(configureobject);
+}
+
+void configurator::add_configurable(configurable *configureobject) {
+  configureobjs.push_back(configureobject);
+}
+
+bool configurator::configure(const text_t &filename) {
+  // read in the build configuration file
+  text_t key;
+  text_tarray cfgline;
+  char *cstr = filename.getcstr();
+  ifstream confin (cstr);
+  delete []cstr;
+
+  if (confin) {
+    while (read_cfg_line(confin, cfgline) >= 0) {
+      if (cfgline.size () >= 2) {
+	key = cfgline[0];
+	cfgline.erase(cfgline.begin());
+
+	// configure the configurables
+	configurable *configureObject;
+	vector<configurable *>::iterator configureIter = configureobjs.begin();
+
+	while (configureIter != configureobjs.end()) {
+	  configureObject = *configureIter;
+	  ++configureIter;
+    
+	  configureObject->configure (key, cfgline);
+	}
+      }
+    }
+    confin.close ();
+    return true;
+  }
+  return false;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/lib/cnfgator.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/cnfgator.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/cnfgator.h	(revision 10506)
@@ -0,0 +1,18 @@
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace/std/vector>
+#else
+#  include <vector>
+#endif
+
+#include "cfgread.h"
+#include "cnfgable.h"
+
+class configurator
+{ 
+ private:
+  vector<configurable *> configureobjs;
+ public:
+  configurator(configurable *configureobject);
+  bool configure(const text_t &filename);
+  void add_configurable(configurable *configureobject);
+};
Index: /tags/gsdl-2_61-distribution/gsdl/lib/corbaconv_text_t.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/corbaconv_text_t.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/corbaconv_text_t.h	(revision 10506)
@@ -0,0 +1,68 @@
+/**********************************************************************
+ *
+ * corbaconv_text_t.mpp -- conversion support text_t <-> corba_text_t
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef CORBACONV_TEXT_T_H
+#define CORBACONV_TEXT_T_H
+
+#include "text_t.h"
+
+// Inherit from text_t
+// Provide support to convert from corba_text_t to text_t and vice versa
+
+class corbaconv_text_t : public text_t {
+  
+public:
+  // constructors
+  corbaconv_text_t (corbatext_t t);
+
+  void setCorbatext(corbatext_t ct);
+  void getCorbatext(corbatext_t &ct) const;
+  void fillUsString(usString *us) const;
+
+  static void setCorbatext(text_t& t, corbatext_t ct);
+  static void getCorbatext(const text_t& t, corbatext_t &ct);
+  static void fillUsString(const text_t& t, usString *us);
+};
+
+
+inline void corbaconv_text_t::setCorbatext(corbatext_t ct) 
+{ 
+  setCorbatext(*this,ct); 
+}
+
+inline void corbaconv_text_t::getCorbatext(corbatext_t& ct) const
+{ 
+  getCorbatext(*this,ct); 
+}
+
+inline void corbaconv_text_t::fillUsString(usString *us) const
+{
+  fillUsString(*this,us);
+}
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/corbaconv_text_t.mpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/corbaconv_text_t.mpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/corbaconv_text_t.mpp	(revision 10506)
@@ -0,0 +1,109 @@
+/**********************************************************************
+ *
+ * corbaconv_text_t.mpp -- conversion support text_t <-> corba_text_t
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+#if defined(GSDL_USE_STL_H) || defined(__APPLE__)
+#include <vector.h>
+#else
+#include <vector>
+#endif
+
+// protocol header
+#include "corbaiface.h"
+using namespace gsdlInterface;
+
+#include "corbatext_t.h"
+
+#include "corbaconv_text_t.h"
+
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\algorithm>
+#elif defined(GSDL_USE_STL_H)
+#  if defined(GSDL_USE_ALGO_H)
+#    include <algo.h>
+#  else
+#    include <algorithm.h>
+#  endif
+#else
+#  include <algorithm>
+#endif
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__
+#  include "WIN32cfg.h"
+# else
+#  include "mico/config.h"
+# endif
+#endif
+
+
+// #include "unitool.h" // ****
+
+////////////////////////////////////
+// corbaconv_text_t methods
+////////////////////////////////////
+
+corbaconv_text_t::corbaconv_text_t (corbatext_t t)
+{ 
+  setCorbatext(t);  
+}
+
+void corbaconv_text_t::getCorbatext(const text_t& t, corbatext_t &ct)
+{
+  ct.encoding = 0;
+  fillUsString(t,&ct.text);
+}
+
+void corbaconv_text_t::setCorbatext(text_t& t, corbatext_t ct)
+{
+  t.setencoding(0);
+  t.clear();
+  corbatext_usvector(ct, t.text_as_usvector());
+}
+
+void corbaconv_text_t::fillUsString(const text_t& t, usString *us)
+{
+  unsigned int i;
+  usvector::const_iterator here = t.text_as_usvector().begin();
+  usvector::const_iterator end = t.text_as_usvector().end();
+
+
+  if (end == here)
+    { 	
+      return;
+    }
+  (*us).length(end - here);
+  i = 0;
+
+  while (here != end)
+    {
+      (*us)[i] = *here;
+      i ++;
+      here ++;
+    }
+  
+}
Index: /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface.h	(revision 10506)
@@ -0,0 +1,613 @@
+/*
+ *  MICO --- a free CORBA implementation
+ *  Copyright (C) 1997-98 Kay Roemer & Arno Puder
+ *
+ *  This file was automatically generated. DO NOT EDIT!
+ */
+
+#if !defined(__CORBAIFACE_H__) || defined(MICO_NO_TOPLEVEL_MODULES)
+#define __CORBAIFACE_H__
+
+#ifndef MICO_NO_TOPLEVEL_MODULES
+#include <CORBA.h>
+#include <mico/throw.h>
+#endif
+
+#ifndef MICO_NO_TOPLEVEL_MODULES
+MICO_NAMESPACE_DECL gsdlInterface {
+#endif
+
+#if !defined(MICO_NO_TOPLEVEL_MODULES) || defined(MICO_MODULE_gsdlInterface)
+
+
+typedef SequenceTmpl<CORBA::UShort,MICO_TID_DEF> usString;
+#ifdef _WINDOWS
+static usString _dummy_usString;
+#endif
+typedef TSeqVar<SequenceTmpl<CORBA::UShort,MICO_TID_DEF> > usString_var;
+typedef TSeqOut<SequenceTmpl<CORBA::UShort,MICO_TID_DEF> > usString_out;
+
+typedef StringSequenceTmpl<CORBA::String_var> stringSeq;
+#ifdef _WINDOWS
+static stringSeq _dummy_stringSeq;
+#endif
+typedef TSeqVar<StringSequenceTmpl<CORBA::String_var> > stringSeq_var;
+typedef TSeqOut<StringSequenceTmpl<CORBA::String_var> > stringSeq_out;
+
+struct corbatext_t;
+typedef TVarVar<corbatext_t> corbatext_t_var;
+typedef TVarOut<corbatext_t> corbatext_t_out;
+
+struct corbatext_t {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbatext_t_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbatext_t();
+  ~corbatext_t();
+  corbatext_t( const corbatext_t& s );
+  corbatext_t& operator=( const corbatext_t& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  usString text;
+  CORBA::UShort encoding;
+  CORBA::ULong length;
+};
+
+typedef SequenceTmpl<corbatext_t,MICO_TID_DEF> corbatext_tarray;
+#ifdef _WINDOWS
+static corbatext_tarray _dummy_corbatext_tarray;
+#endif
+typedef TSeqVar<SequenceTmpl<corbatext_t,MICO_TID_DEF> > corbatext_tarray_var;
+typedef TSeqOut<SequenceTmpl<corbatext_t,MICO_TID_DEF> > corbatext_tarray_out;
+
+typedef corbatext_tarray corbatext_tset;
+#ifdef _WINDOWS
+static corbatext_tset _dummy_corbatext_tset;
+#endif
+typedef TSeqVar<corbatext_tarray > corbatext_tset_var;
+typedef TSeqOut<corbatext_tarray > corbatext_tset_out;
+
+struct corbatext_tmap;
+typedef TVarVar<corbatext_tmap> corbatext_tmap_var;
+typedef TVarOut<corbatext_tmap> corbatext_tmap_out;
+
+struct corbatext_tmap {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbatext_tmap_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbatext_tmap();
+  ~corbatext_tmap();
+  corbatext_tmap( const corbatext_tmap& s );
+  corbatext_tmap& operator=( const corbatext_tmap& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_tarray names;
+  corbatext_tarray values;
+};
+
+enum corbaComError {
+  corbaNoError = 0,
+  corbaAuthenticationFailure,
+  corbaProtocolError,
+  corbaConfigurationError,
+  corbaSystemProblem
+};
+
+typedef corbaComError& corbaComError_out;
+
+struct corbaShortColInfo;
+typedef TVarVar<corbaShortColInfo> corbaShortColInfo_var;
+typedef TVarOut<corbaShortColInfo> corbaShortColInfo_out;
+
+struct corbaShortColInfo {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaShortColInfo_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaShortColInfo();
+  ~corbaShortColInfo();
+  corbaShortColInfo( const corbaShortColInfo& s );
+  corbaShortColInfo& operator=( const corbaShortColInfo& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_t name;
+  corbatext_t host;
+  CORBA::Long response;
+};
+
+struct corbaColInfoResponse;
+typedef TVarVar<corbaColInfoResponse> corbaColInfoResponse_var;
+typedef TVarOut<corbaColInfoResponse> corbaColInfoResponse_out;
+
+struct corbaColInfoResponse {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaColInfoResponse_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaColInfoResponse();
+  ~corbaColInfoResponse();
+  corbaColInfoResponse( const corbaColInfoResponse& s );
+  corbaColInfoResponse& operator=( const corbaColInfoResponse& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbaShortColInfo shoftInfo;
+  CORBA::Boolean isPublic;
+  CORBA::Boolean isBeta;
+  CORBA::ULong buildDate;
+  corbatext_tarray ccsCols;
+  corbatext_tarray languages;
+  CORBA::ULong numDocs;
+  CORBA::ULong numWords;
+  CORBA::ULong numBytes;
+  corbatext_tmap collectionMeta;
+  corbatext_tmap format;
+  corbatext_tmap building;
+  corbatext_t httpdomain;
+  corbatext_t httpprefix;
+  corbatext_t receptionist;
+};
+
+struct corbaDocRequest;
+typedef TVarVar<corbaDocRequest> corbaDocRequest_var;
+typedef TVarOut<corbaDocRequest> corbaDocRequest_out;
+
+struct corbaDocRequest {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaDocRequest_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaDocRequest();
+  ~corbaDocRequest();
+  corbaDocRequest( const corbaDocRequest& s );
+  corbaDocRequest& operator=( const corbaDocRequest& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_t OID;
+  corbatext_t docType;
+  corbatext_t docFormat;
+};
+
+struct corbaDocResponse;
+typedef TVarVar<corbaDocResponse> corbaDocResponse_var;
+typedef TVarOut<corbaDocResponse> corbaDocResponse_out;
+
+struct corbaDocResponse {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaDocResponse_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaDocResponse();
+  ~corbaDocResponse();
+  corbaDocResponse( const corbaDocResponse& s );
+  corbaDocResponse& operator=( const corbaDocResponse& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_t doc;
+};
+
+enum corbaFilterType {
+  booleanType = 0,
+  integerType,
+  enumeratedType,
+  stringType
+};
+
+typedef corbaFilterType& corbaFilterType_out;
+
+enum corbaFilterRepeatable {
+  onePerQuery = 0,
+  onePerTerm,
+  nPerTerm
+};
+
+typedef corbaFilterRepeatable& corbaFilterRepeatable_out;
+
+struct corbaFilterOption;
+typedef TVarVar<corbaFilterOption> corbaFilterOption_var;
+typedef TVarOut<corbaFilterOption> corbaFilterOption_out;
+
+struct corbaFilterOption {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaFilterOption_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaFilterOption();
+  ~corbaFilterOption();
+  corbaFilterOption( const corbaFilterOption& s );
+  corbaFilterOption& operator=( const corbaFilterOption& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_t name;
+  corbaFilterType type;
+  corbaFilterRepeatable repeatable;
+  corbatext_t defaultValue;
+  corbatext_tarray validValues;
+};
+
+typedef SequenceTmpl<corbaFilterOption,MICO_TID_DEF> corbaFilterOptionList;
+#ifdef _WINDOWS
+static corbaFilterOptionList _dummy_corbaFilterOptionList;
+#endif
+typedef TSeqVar<SequenceTmpl<corbaFilterOption,MICO_TID_DEF> > corbaFilterOptionList_var;
+typedef TSeqOut<SequenceTmpl<corbaFilterOption,MICO_TID_DEF> > corbaFilterOptionList_out;
+
+struct corbaFilterOptionsResponse;
+typedef TVarVar<corbaFilterOptionsResponse> corbaFilterOptionsResponse_var;
+typedef TVarOut<corbaFilterOptionsResponse> corbaFilterOptionsResponse_out;
+
+struct corbaFilterOptionsResponse {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaFilterOptionsResponse_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaFilterOptionsResponse();
+  ~corbaFilterOptionsResponse();
+  corbaFilterOptionsResponse( const corbaFilterOptionsResponse& s );
+  corbaFilterOptionsResponse& operator=( const corbaFilterOptionsResponse& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbaFilterOptionList options;
+  corbatext_tarray names;
+};
+
+struct corbaOptionValue;
+typedef TVarVar<corbaOptionValue> corbaOptionValue_var;
+typedef TVarOut<corbaOptionValue> corbaOptionValue_out;
+
+struct corbaOptionValue {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaOptionValue_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaOptionValue();
+  ~corbaOptionValue();
+  corbaOptionValue( const corbaOptionValue& s );
+  corbaOptionValue& operator=( const corbaOptionValue& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_t name;
+  corbatext_t value;
+};
+
+typedef SequenceTmpl<corbaOptionValue,MICO_TID_DEF> corbaOptionValue_array;
+#ifdef _WINDOWS
+static corbaOptionValue_array _dummy_corbaOptionValue_array;
+#endif
+typedef TSeqVar<SequenceTmpl<corbaOptionValue,MICO_TID_DEF> > corbaOptionValue_array_var;
+typedef TSeqOut<SequenceTmpl<corbaOptionValue,MICO_TID_DEF> > corbaOptionValue_array_out;
+
+struct corbaFilterRequest;
+typedef TVarVar<corbaFilterRequest> corbaFilterRequest_var;
+typedef TVarOut<corbaFilterRequest> corbaFilterRequest_out;
+
+struct corbaFilterRequest {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaFilterRequest_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaFilterRequest();
+  ~corbaFilterRequest();
+  corbaFilterRequest( const corbaFilterRequest& s );
+  corbaFilterRequest& operator=( const corbaFilterRequest& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_t filter;
+  corbaOptionValue_array filterOptions;
+  corbatext_tarray docSet;
+  CORBA::Long filterResultOptions;
+  corbatext_t requestParams;
+  corbatext_t refParams;
+  corbatext_tset fields;
+  CORBA::Boolean getParents;
+};
+
+struct corbaTermInfo;
+typedef TVarVar<corbaTermInfo> corbaTermInfo_var;
+typedef TVarOut<corbaTermInfo> corbaTermInfo_out;
+
+struct corbaTermInfo {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaTermInfo_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaTermInfo();
+  ~corbaTermInfo();
+  corbaTermInfo( const corbaTermInfo& s );
+  corbaTermInfo& operator=( const corbaTermInfo& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_t term;
+  CORBA::Long frequency;
+  corbatext_tarray matchTerms;
+};
+
+typedef SequenceTmpl<corbaTermInfo,MICO_TID_DEF> corbaTermInfo_array;
+#ifdef _WINDOWS
+static corbaTermInfo_array _dummy_corbaTermInfo_array;
+#endif
+typedef TSeqVar<SequenceTmpl<corbaTermInfo,MICO_TID_DEF> > corbaTermInfo_array_var;
+typedef TSeqOut<SequenceTmpl<corbaTermInfo,MICO_TID_DEF> > corbaTermInfo_array_out;
+
+struct corbaMetadataInfo;
+typedef TVarVar<corbaMetadataInfo> corbaMetadataInfo_var;
+typedef TVarOut<corbaMetadataInfo> corbaMetadataInfo_out;
+
+struct corbaMetadataInfo {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaMetadataInfo_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaMetadataInfo();
+  ~corbaMetadataInfo();
+  corbaMetadataInfo( const corbaMetadataInfo& s );
+  corbaMetadataInfo& operator=( const corbaMetadataInfo& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_t params;
+  CORBA::Boolean isRef;
+  corbatext_tarray values;
+  CORBA::Long id;
+  CORBA::Long parentid;
+};
+
+typedef SequenceTmpl<corbaMetadataInfo,MICO_TID_DEF> corbaMetadataInfo_array;
+#ifdef _WINDOWS
+static corbaMetadataInfo_array _dummy_corbaMetadataInfo_array;
+#endif
+typedef TSeqVar<SequenceTmpl<corbaMetadataInfo,MICO_TID_DEF> > corbaMetadataInfo_array_var;
+typedef TSeqOut<SequenceTmpl<corbaMetadataInfo,MICO_TID_DEF> > corbaMetadataInfo_array_out;
+
+struct corbaMetadataInfo_map;
+typedef TVarVar<corbaMetadataInfo_map> corbaMetadataInfo_map_var;
+typedef TVarOut<corbaMetadataInfo_map> corbaMetadataInfo_map_out;
+
+struct corbaMetadataInfo_map {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaMetadataInfo_map_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaMetadataInfo_map();
+  ~corbaMetadataInfo_map();
+  corbaMetadataInfo_map( const corbaMetadataInfo_map& s );
+  corbaMetadataInfo_map& operator=( const corbaMetadataInfo_map& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_tarray names;
+  corbaMetadataInfo_array values;
+};
+
+typedef SequenceTmpl<CORBA::Long,MICO_TID_DEF> corbaDocFreq_array;
+#ifdef _WINDOWS
+static corbaDocFreq_array _dummy_corbaDocFreq_array;
+#endif
+typedef TSeqVar<SequenceTmpl<CORBA::Long,MICO_TID_DEF> > corbaDocFreq_array_var;
+typedef TSeqOut<SequenceTmpl<CORBA::Long,MICO_TID_DEF> > corbaDocFreq_array_out;
+
+struct corbaResultDocInfo;
+typedef TVarVar<corbaResultDocInfo> corbaResultDocInfo_var;
+typedef TVarOut<corbaResultDocInfo> corbaResultDocInfo_out;
+
+struct corbaResultDocInfo {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaResultDocInfo_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaResultDocInfo();
+  ~corbaResultDocInfo();
+  corbaResultDocInfo( const corbaResultDocInfo& s );
+  corbaResultDocInfo& operator=( const corbaResultDocInfo& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  corbatext_t OID;
+  CORBA::Long resultNum;
+  CORBA::Long ranking;
+  CORBA::Long termsMatched;
+  CORBA::Long phraseMatched;
+  corbaDocFreq_array docFreq;
+  corbaMetadataInfo_map metadata;
+  corbatext_t classifierMetadataType;
+  CORBA::Long classifierMetadataOffset;
+  corbaMetadataInfo_array metaparents;
+};
+
+typedef SequenceTmpl<corbaResultDocInfo,MICO_TID_DEF> corbaResultDocInfo_array;
+#ifdef _WINDOWS
+static corbaResultDocInfo_array _dummy_corbaResultDocInfo_array;
+#endif
+typedef TSeqVar<SequenceTmpl<corbaResultDocInfo,MICO_TID_DEF> > corbaResultDocInfo_array_var;
+typedef TSeqOut<SequenceTmpl<corbaResultDocInfo,MICO_TID_DEF> > corbaResultDocInfo_array_out;
+
+enum corbaIsApprox {
+  resultExact = 0,
+  resultApprox,
+  resultMany
+};
+
+typedef corbaIsApprox& corbaIsApprox_out;
+
+struct corbaFilterResponse;
+typedef TVarVar<corbaFilterResponse> corbaFilterResponse_var;
+typedef TVarOut<corbaFilterResponse> corbaFilterResponse_out;
+
+struct corbaFilterResponse {
+  #ifdef HAVE_TYPEDEF_OVERLOAD
+  typedef corbaFilterResponse_var _var_type;
+  #endif
+  #ifdef HAVE_EXPLICIT_STRUCT_OPS
+  corbaFilterResponse();
+  ~corbaFilterResponse();
+  corbaFilterResponse( const corbaFilterResponse& s );
+  corbaFilterResponse& operator=( const corbaFilterResponse& s );
+  #endif //HAVE_EXPLICIT_STRUCT_OPS
+
+  CORBA::Long numDocs;
+  corbaIsApprox isApprox;
+  corbaTermInfo_array termInfo;
+  corbaResultDocInfo_array docInfo;
+};
+
+class corbaiface;
+typedef corbaiface *corbaiface_ptr;
+typedef corbaiface_ptr corbaifaceRef;
+typedef ObjVar<corbaiface> corbaiface_var;
+typedef ObjOut<corbaiface> corbaiface_out;
+
+
+// Common definitions for interface corbaiface
+class corbaiface : 
+  virtual public CORBA::Object
+{
+  public:
+    virtual ~corbaiface();
+
+    #ifdef HAVE_TYPEDEF_OVERLOAD
+    typedef corbaiface_ptr _ptr_type;
+    typedef corbaiface_var _var_type;
+    #endif
+
+    static corbaiface_ptr _narrow( CORBA::Object_ptr obj );
+    static corbaiface_ptr _narrow( CORBA::AbstractBase_ptr obj );
+    static corbaiface_ptr _duplicate( corbaiface_ptr _obj )
+    {
+      CORBA::Object::_duplicate (_obj);
+      return _obj;
+    }
+
+    static corbaiface_ptr _nil()
+    {
+      return 0;
+    }
+
+    virtual void *_narrow_helper( const char *repoid );
+    static vector<CORBA::Narrow_proto> *_narrow_helpers;
+    static bool _narrow_helper2( CORBA::Object_ptr obj );
+
+    virtual CORBA::Boolean initialise( corbaComError& error ) = 0;
+    virtual void configure( const corbatext_t& key, const corbatext_tarray& cfgline, corbaComError& error ) = 0;
+    virtual void collectionList( corbatext_tarray& collist, corbaComError& error ) = 0;
+    virtual void hasCollection( const corbatext_t& corbaCollection, CORBA::Boolean& has, corbaComError& error ) = 0;
+    virtual void ping( const corbatext_t& collection, CORBA::Boolean& wasSuccess, corbaComError& error ) = 0;
+    virtual void getDocument( const corbatext_t& collection, corbaDocRequest& request, corbaDocResponse& response, corbaComError& error ) = 0;
+    virtual void getCollectInfo( const corbatext_t& collection, corbaColInfoResponse& response, corbaComError& error ) = 0;
+    virtual void getFilterInfo( const corbatext_t& collection, corbatext_tarray& filterNames, corbaComError& error ) = 0;
+    virtual void getFilterOptions( const corbatext_t& collection, const corbatext_t& option, corbaFilterOptionsResponse& response, corbaComError& error ) = 0;
+    virtual void filter( const corbatext_t& collection, const corbaFilterRequest& request, corbaFilterResponse& response, corbaComError& error ) = 0;
+
+  protected:
+    corbaiface() {};
+  private:
+    corbaiface( const corbaiface& );
+    void operator=( const corbaiface& );
+};
+
+// Stub for interface corbaiface
+class corbaiface_stub:
+  virtual public corbaiface
+{
+  public:
+    virtual ~corbaiface_stub();
+    CORBA::Boolean initialise( corbaComError& error );
+    void configure( const corbatext_t& key, const corbatext_tarray& cfgline, corbaComError& error );
+    void collectionList( corbatext_tarray& collist, corbaComError& error );
+    void hasCollection( const corbatext_t& corbaCollection, CORBA::Boolean& has, corbaComError& error );
+    void ping( const corbatext_t& collection, CORBA::Boolean& wasSuccess, corbaComError& error );
+    void getDocument( const corbatext_t& collection, corbaDocRequest& request, corbaDocResponse& response, corbaComError& error );
+    void getCollectInfo( const corbatext_t& collection, corbaColInfoResponse& response, corbaComError& error );
+    void getFilterInfo( const corbatext_t& collection, corbatext_tarray& filterNames, corbaComError& error );
+    void getFilterOptions( const corbatext_t& collection, const corbatext_t& option, corbaFilterOptionsResponse& response, corbaComError& error );
+    void filter( const corbatext_t& collection, const corbaFilterRequest& request, corbaFilterResponse& response, corbaComError& error );
+
+  private:
+    void operator=( const corbaiface_stub& );
+};
+
+class corbaiface_skel :
+  virtual public StaticMethodDispatcher,
+  virtual public corbaiface
+{
+  public:
+    corbaiface_skel( const CORBA::BOA::ReferenceData & = CORBA::BOA::ReferenceData() );
+    virtual ~corbaiface_skel();
+    corbaiface_skel( CORBA::Object_ptr obj );
+    virtual bool dispatch( CORBA::StaticServerRequest_ptr _req, CORBA::Environment &_env );
+    corbaiface_ptr _this();
+
+};
+
+#endif // !defined(MICO_NO_TOPLEVEL_MODULES) || defined(MICO_MODULE_gsdlInterface)
+
+#ifndef MICO_NO_TOPLEVEL_MODULES
+
+} MICO_NAMESPACE_END_DECL
+#endif
+
+
+
+#ifndef MICO_CONF_NO_POA
+
+#endif // MICO_CONF_NO_POA
+
+#if !defined(MICO_NO_TOPLEVEL_MODULES) || defined(MICO_MODULE__GLOBAL)
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbatext_t;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbatext_tmap;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaComError;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaShortColInfo;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaColInfoResponse;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaDocRequest;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaDocResponse;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterType;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterRepeatable;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterOption;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterOptionsResponse;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaOptionValue;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterRequest;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaTermInfo;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaMetadataInfo;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaMetadataInfo_map;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaResultDocInfo;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaIsApprox;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterResponse;
+
+extern CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaiface;
+
+extern CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbatext_t;
+
+extern CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbaFilterOption;
+
+extern CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbaOptionValue;
+
+extern CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbaTermInfo;
+
+extern CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbaMetadataInfo;
+
+extern CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbaResultDocInfo;
+
+#endif // !defined(MICO_NO_TOPLEVEL_MODULES) || defined(MICO_MODULE__GLOBAL)
+
+
+#if !defined(MICO_NO_TOPLEVEL_MODULES) && !defined(MICO_IN_GENERATED_CODE)
+#include <mico/template_impl.h>
+#endif
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface.idl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface.idl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface.idl	(revision 10506)
@@ -0,0 +1,230 @@
+// basic elements for text
+
+module gsdlInterface {
+
+typedef sequence<unsigned short> usString;
+
+typedef sequence<string> stringSeq;
+
+struct corbatext_t
+{ 
+  usString text;
+  unsigned short encoding;
+  unsigned long  length;
+};
+
+typedef sequence<corbatext_t> corbatext_tarray;
+
+typedef corbatext_tarray corbatext_tset;
+
+struct corbatext_tmap
+{
+  corbatext_tarray names;
+  corbatext_tarray values;
+};
+
+// standard error values
+
+enum corbaComError
+{ corbaNoError, 
+  corbaAuthenticationFailure, 
+  corbaProtocolError, 
+  corbaConfigurationError, 
+  corbaSystemProblem
+};
+
+//
+// getColInfo response
+//
+
+struct corbaShortColInfo
+{
+  corbatext_t name;
+  corbatext_t host;
+  long        response;
+};
+
+struct corbaColInfoResponse
+{
+  corbaShortColInfo shoftInfo;
+  boolean           isPublic;
+  boolean           isBeta;
+  unsigned long     buildDate;
+  corbatext_tarray  ccsCols;        // Added 05/04/2000
+  corbatext_tarray  languages;
+  unsigned long     numDocs;
+  unsigned long     numWords;
+  unsigned long     numBytes;
+  corbatext_tmap    collectionMeta;
+  corbatext_tmap    format;
+  corbatext_tmap    building;
+  corbatext_t       httpdomain ;    // Added 27/07/2000
+  corbatext_t       httpprefix;     // Added 27/07/2000
+  corbatext_t       receptionist;
+};
+
+//
+// getDocument request
+//
+
+struct corbaDocRequest
+{ 
+  corbatext_t OID;
+  corbatext_t docType;
+  corbatext_t docFormat;
+};
+
+//
+// getDocument response
+//
+
+struct corbaDocResponse
+{ 
+  corbatext_t doc;
+};
+
+enum corbaFilterType
+{
+  booleanType,
+  integerType,
+  enumeratedType,
+  stringType
+};
+
+enum corbaFilterRepeatable
+{
+  onePerQuery,
+  onePerTerm,
+  nPerTerm
+};
+
+struct corbaFilterOption
+{
+  corbatext_t           name;
+  corbaFilterType       type;
+  corbaFilterRepeatable repeatable;
+  corbatext_t           defaultValue;
+  corbatext_tarray      validValues;
+};
+
+typedef sequence<corbaFilterOption> corbaFilterOptionList;
+
+struct corbaFilterOptionsResponse
+{
+  corbaFilterOptionList options;
+  corbatext_tarray      names;
+};
+
+//
+// structures for filter call
+//
+
+struct corbaOptionValue
+{
+  corbatext_t name;
+  corbatext_t value;
+};
+
+typedef sequence<corbaOptionValue> corbaOptionValue_array;
+
+struct corbaFilterRequest
+{ 
+  corbatext_t            filter;
+  corbaOptionValue_array filterOptions;
+  corbatext_tarray       docSet;
+  long                   filterResultOptions;
+  corbatext_t            requestParams;
+  corbatext_t            refParams;
+  corbatext_tset         fields;
+  boolean                getParents;
+};
+
+struct corbaTermInfo
+{
+  corbatext_t      term;
+  long             frequency;
+  corbatext_tarray matchTerms;
+};
+
+typedef sequence<corbaTermInfo> corbaTermInfo_array;
+
+struct corbaMetadataInfo
+{
+  corbatext_t      params;
+  boolean          isRef;
+  corbatext_tarray values;
+  long             id;
+  long             parentid; // dodge for avoiding pointers for the moment
+};
+
+typedef sequence<corbaMetadataInfo> corbaMetadataInfo_array;
+
+struct corbaMetadataInfo_map
+{ 
+  corbatext_tarray        names;
+  corbaMetadataInfo_array values;
+};
+
+typedef sequence<long> corbaDocFreq_array;
+
+struct corbaResultDocInfo
+{
+  corbatext_t             OID;
+  long                    resultNum;
+  long                    ranking;
+  long                    termsMatched;
+  long                    phraseMatched;
+  corbaDocFreq_array      docFreq;
+  corbaMetadataInfo_map   metadata;
+  corbatext_t             classifierMetadataType;    // Added 05/04/2000
+  long                    classifierMetadataOffset;  // Added 05/04/2000
+  corbaMetadataInfo_array metaparents;
+};
+
+typedef sequence<corbaResultDocInfo> corbaResultDocInfo_array;
+
+enum corbaIsApprox
+{
+  resultExact,
+  resultApprox,
+  resultMany
+};
+
+struct corbaFilterResponse
+{
+  long                     numDocs;
+  corbaIsApprox            isApprox;
+  corbaTermInfo_array      termInfo;
+  corbaResultDocInfo_array docInfo;
+};
+
+interface corbaiface
+{
+  boolean   initialise(inout corbaComError error);
+  void      configure(in corbatext_t key, in corbatext_tarray cfgline,
+		      inout corbaComError error);
+  void      collectionList(inout corbatext_tarray collist,
+			   inout corbaComError error);
+  void      hasCollection(in corbatext_t corbaCollection, inout boolean has,
+		       inout corbaComError error);
+  void      ping(in corbatext_t collection, inout boolean wasSuccess, inout corbaComError error);
+  void      getDocument(in corbatext_t collection,
+			inout corbaDocRequest request, inout corbaDocResponse response,
+			inout corbaComError error);
+  void      getCollectInfo(in corbatext_t collection,
+			   inout corbaColInfoResponse response,
+			   inout corbaComError error);
+  void      getFilterInfo(in corbatext_t collection, 
+                          inout corbatext_tarray filterNames, 
+			  inout corbaComError error);
+  void      getFilterOptions(in corbatext_t collection,
+                             in corbatext_t option,
+                             inout corbaFilterOptionsResponse response,
+			     inout corbaComError error);
+  void      filter(in corbatext_t collection,
+		   in corbaFilterRequest request,
+                   inout corbaFilterResponse response,
+                   inout corbaComError error);
+};
+
+};
Index: /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface.mpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface.mpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface.mpp	(revision 10506)
@@ -0,0 +1,1996 @@
+/*
+ *  MICO --- a free CORBA implementation
+ *  Copyright (C) 1997-98 Kay Roemer & Arno Puder
+ *
+ *  This file was automatically generated. DO NOT EDIT!
+ */
+
+#include "corbaiface.h"
+
+//--------------------------------------------------------
+//  Implementation of stubs
+//--------------------------------------------------------
+
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbatext_t::corbatext_t()
+{
+}
+
+gsdlInterface::corbatext_t::corbatext_t( const corbatext_t& _s )
+{
+  text = ((corbatext_t&)_s).text;
+  encoding = ((corbatext_t&)_s).encoding;
+  length = ((corbatext_t&)_s).length;
+}
+
+gsdlInterface::corbatext_t::~corbatext_t()
+{
+}
+
+gsdlInterface::corbatext_t&
+gsdlInterface::corbatext_t::operator=( const corbatext_t& _s )
+{
+  text = ((corbatext_t&)_s).text;
+  encoding = ((corbatext_t&)_s).encoding;
+  length = ((corbatext_t&)_s).length;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbatext_t : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbatext_t _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbatext_t::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbatext_t::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbatext_t::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbatext_t::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    CORBA::_stcseq_ushort->demarshal( dc, &((_MICO_T*)v)->text ) &&
+    CORBA::_stc_ushort->demarshal( dc, &((_MICO_T*)v)->encoding ) &&
+    CORBA::_stc_ulong->demarshal( dc, &((_MICO_T*)v)->length ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbatext_t::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  CORBA::_stcseq_ushort->marshal( ec, &((_MICO_T*)v)->text );
+  CORBA::_stc_ushort->marshal( ec, &((_MICO_T*)v)->encoding );
+  CORBA::_stc_ulong->marshal( ec, &((_MICO_T*)v)->length );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbatext_t;
+
+
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbatext_tmap::corbatext_tmap()
+{
+}
+
+gsdlInterface::corbatext_tmap::corbatext_tmap( const corbatext_tmap& _s )
+{
+  names = ((corbatext_tmap&)_s).names;
+  values = ((corbatext_tmap&)_s).values;
+}
+
+gsdlInterface::corbatext_tmap::~corbatext_tmap()
+{
+}
+
+gsdlInterface::corbatext_tmap&
+gsdlInterface::corbatext_tmap::operator=( const corbatext_tmap& _s )
+{
+  names = ((corbatext_tmap&)_s).names;
+  values = ((corbatext_tmap&)_s).values;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbatext_tmap : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbatext_tmap _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbatext_tmap::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbatext_tmap::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbatext_tmap::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbatext_tmap::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->names ) &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->values ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbatext_tmap::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->names );
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->values );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbatext_tmap;
+
+
+class _Marshaller_gsdlInterface_corbaComError : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaComError _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaComError::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaComError::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaComError::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaComError::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::ULong ul;
+  if( !dc.enumeration( ul ) )
+    return FALSE;
+  *(_MICO_T*) v = (_MICO_T) ul;
+  return TRUE;
+}
+
+void _Marshaller_gsdlInterface_corbaComError::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.enumeration( (CORBA::ULong) *(_MICO_T *) v );
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaComError;
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaShortColInfo::corbaShortColInfo()
+{
+}
+
+gsdlInterface::corbaShortColInfo::corbaShortColInfo( const corbaShortColInfo& _s )
+{
+  name = ((corbaShortColInfo&)_s).name;
+  host = ((corbaShortColInfo&)_s).host;
+  response = ((corbaShortColInfo&)_s).response;
+}
+
+gsdlInterface::corbaShortColInfo::~corbaShortColInfo()
+{
+}
+
+gsdlInterface::corbaShortColInfo&
+gsdlInterface::corbaShortColInfo::operator=( const corbaShortColInfo& _s )
+{
+  name = ((corbaShortColInfo&)_s).name;
+  host = ((corbaShortColInfo&)_s).host;
+  response = ((corbaShortColInfo&)_s).response;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaShortColInfo : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaShortColInfo _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaShortColInfo::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaShortColInfo::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaShortColInfo::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaShortColInfo::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->name ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->host ) &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->response ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaShortColInfo::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->name );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->host );
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->response );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaShortColInfo;
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaColInfoResponse::corbaColInfoResponse()
+{
+}
+
+gsdlInterface::corbaColInfoResponse::corbaColInfoResponse( const corbaColInfoResponse& _s )
+{
+  shoftInfo = ((corbaColInfoResponse&)_s).shoftInfo;
+  isPublic = ((corbaColInfoResponse&)_s).isPublic;
+  isBeta = ((corbaColInfoResponse&)_s).isBeta;
+  buildDate = ((corbaColInfoResponse&)_s).buildDate;
+  ccsCols = ((corbaColInfoResponse&)_s).ccsCols;
+  languages = ((corbaColInfoResponse&)_s).languages;
+  numDocs = ((corbaColInfoResponse&)_s).numDocs;
+  numWords = ((corbaColInfoResponse&)_s).numWords;
+  numBytes = ((corbaColInfoResponse&)_s).numBytes;
+  collectionMeta = ((corbaColInfoResponse&)_s).collectionMeta;
+  format = ((corbaColInfoResponse&)_s).format;
+  building = ((corbaColInfoResponse&)_s).building;
+  httpdomain = ((corbaColInfoResponse&)_s).httpdomain;
+  httpprefix = ((corbaColInfoResponse&)_s).httpprefix;
+  receptionist = ((corbaColInfoResponse&)_s).receptionist;
+}
+
+gsdlInterface::corbaColInfoResponse::~corbaColInfoResponse()
+{
+}
+
+gsdlInterface::corbaColInfoResponse&
+gsdlInterface::corbaColInfoResponse::operator=( const corbaColInfoResponse& _s )
+{
+  shoftInfo = ((corbaColInfoResponse&)_s).shoftInfo;
+  isPublic = ((corbaColInfoResponse&)_s).isPublic;
+  isBeta = ((corbaColInfoResponse&)_s).isBeta;
+  buildDate = ((corbaColInfoResponse&)_s).buildDate;
+  ccsCols = ((corbaColInfoResponse&)_s).ccsCols;
+  languages = ((corbaColInfoResponse&)_s).languages;
+  numDocs = ((corbaColInfoResponse&)_s).numDocs;
+  numWords = ((corbaColInfoResponse&)_s).numWords;
+  numBytes = ((corbaColInfoResponse&)_s).numBytes;
+  collectionMeta = ((corbaColInfoResponse&)_s).collectionMeta;
+  format = ((corbaColInfoResponse&)_s).format;
+  building = ((corbaColInfoResponse&)_s).building;
+  httpdomain = ((corbaColInfoResponse&)_s).httpdomain;
+  httpprefix = ((corbaColInfoResponse&)_s).httpprefix;
+  receptionist = ((corbaColInfoResponse&)_s).receptionist;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaColInfoResponse : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaColInfoResponse _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaColInfoResponse::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaColInfoResponse::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaColInfoResponse::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaColInfoResponse::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller_gsdlInterface_corbaShortColInfo->demarshal( dc, &((_MICO_T*)v)->shoftInfo ) &&
+    CORBA::_stc_boolean->demarshal( dc, &((_MICO_T*)v)->isPublic ) &&
+    CORBA::_stc_boolean->demarshal( dc, &((_MICO_T*)v)->isBeta ) &&
+    CORBA::_stc_ulong->demarshal( dc, &((_MICO_T*)v)->buildDate ) &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->ccsCols ) &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->languages ) &&
+    CORBA::_stc_ulong->demarshal( dc, &((_MICO_T*)v)->numDocs ) &&
+    CORBA::_stc_ulong->demarshal( dc, &((_MICO_T*)v)->numWords ) &&
+    CORBA::_stc_ulong->demarshal( dc, &((_MICO_T*)v)->numBytes ) &&
+    _marshaller_gsdlInterface_corbatext_tmap->demarshal( dc, &((_MICO_T*)v)->collectionMeta ) &&
+    _marshaller_gsdlInterface_corbatext_tmap->demarshal( dc, &((_MICO_T*)v)->format ) &&
+    _marshaller_gsdlInterface_corbatext_tmap->demarshal( dc, &((_MICO_T*)v)->building ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->httpdomain ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->httpprefix ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->receptionist ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaColInfoResponse::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller_gsdlInterface_corbaShortColInfo->marshal( ec, &((_MICO_T*)v)->shoftInfo );
+  CORBA::_stc_boolean->marshal( ec, &((_MICO_T*)v)->isPublic );
+  CORBA::_stc_boolean->marshal( ec, &((_MICO_T*)v)->isBeta );
+  CORBA::_stc_ulong->marshal( ec, &((_MICO_T*)v)->buildDate );
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->ccsCols );
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->languages );
+  CORBA::_stc_ulong->marshal( ec, &((_MICO_T*)v)->numDocs );
+  CORBA::_stc_ulong->marshal( ec, &((_MICO_T*)v)->numWords );
+  CORBA::_stc_ulong->marshal( ec, &((_MICO_T*)v)->numBytes );
+  _marshaller_gsdlInterface_corbatext_tmap->marshal( ec, &((_MICO_T*)v)->collectionMeta );
+  _marshaller_gsdlInterface_corbatext_tmap->marshal( ec, &((_MICO_T*)v)->format );
+  _marshaller_gsdlInterface_corbatext_tmap->marshal( ec, &((_MICO_T*)v)->building );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->httpdomain );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->httpprefix );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->receptionist );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaColInfoResponse;
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaDocRequest::corbaDocRequest()
+{
+}
+
+gsdlInterface::corbaDocRequest::corbaDocRequest( const corbaDocRequest& _s )
+{
+  OID = ((corbaDocRequest&)_s).OID;
+  docType = ((corbaDocRequest&)_s).docType;
+  docFormat = ((corbaDocRequest&)_s).docFormat;
+}
+
+gsdlInterface::corbaDocRequest::~corbaDocRequest()
+{
+}
+
+gsdlInterface::corbaDocRequest&
+gsdlInterface::corbaDocRequest::operator=( const corbaDocRequest& _s )
+{
+  OID = ((corbaDocRequest&)_s).OID;
+  docType = ((corbaDocRequest&)_s).docType;
+  docFormat = ((corbaDocRequest&)_s).docFormat;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaDocRequest : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaDocRequest _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaDocRequest::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaDocRequest::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaDocRequest::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaDocRequest::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->OID ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->docType ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->docFormat ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaDocRequest::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->OID );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->docType );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->docFormat );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaDocRequest;
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaDocResponse::corbaDocResponse()
+{
+}
+
+gsdlInterface::corbaDocResponse::corbaDocResponse( const corbaDocResponse& _s )
+{
+  doc = ((corbaDocResponse&)_s).doc;
+}
+
+gsdlInterface::corbaDocResponse::~corbaDocResponse()
+{
+}
+
+gsdlInterface::corbaDocResponse&
+gsdlInterface::corbaDocResponse::operator=( const corbaDocResponse& _s )
+{
+  doc = ((corbaDocResponse&)_s).doc;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaDocResponse : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaDocResponse _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaDocResponse::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaDocResponse::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaDocResponse::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaDocResponse::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->doc ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaDocResponse::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->doc );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaDocResponse;
+
+
+class _Marshaller_gsdlInterface_corbaFilterType : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaFilterType _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaFilterType::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterType::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterType::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaFilterType::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::ULong ul;
+  if( !dc.enumeration( ul ) )
+    return FALSE;
+  *(_MICO_T*) v = (_MICO_T) ul;
+  return TRUE;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterType::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.enumeration( (CORBA::ULong) *(_MICO_T *) v );
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterType;
+
+
+class _Marshaller_gsdlInterface_corbaFilterRepeatable : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaFilterRepeatable _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaFilterRepeatable::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterRepeatable::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterRepeatable::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaFilterRepeatable::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::ULong ul;
+  if( !dc.enumeration( ul ) )
+    return FALSE;
+  *(_MICO_T*) v = (_MICO_T) ul;
+  return TRUE;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterRepeatable::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.enumeration( (CORBA::ULong) *(_MICO_T *) v );
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterRepeatable;
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaFilterOption::corbaFilterOption()
+{
+}
+
+gsdlInterface::corbaFilterOption::corbaFilterOption( const corbaFilterOption& _s )
+{
+  name = ((corbaFilterOption&)_s).name;
+  type = ((corbaFilterOption&)_s).type;
+  repeatable = ((corbaFilterOption&)_s).repeatable;
+  defaultValue = ((corbaFilterOption&)_s).defaultValue;
+  validValues = ((corbaFilterOption&)_s).validValues;
+}
+
+gsdlInterface::corbaFilterOption::~corbaFilterOption()
+{
+}
+
+gsdlInterface::corbaFilterOption&
+gsdlInterface::corbaFilterOption::operator=( const corbaFilterOption& _s )
+{
+  name = ((corbaFilterOption&)_s).name;
+  type = ((corbaFilterOption&)_s).type;
+  repeatable = ((corbaFilterOption&)_s).repeatable;
+  defaultValue = ((corbaFilterOption&)_s).defaultValue;
+  validValues = ((corbaFilterOption&)_s).validValues;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaFilterOption : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaFilterOption _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaFilterOption::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterOption::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterOption::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaFilterOption::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->name ) &&
+    _marshaller_gsdlInterface_corbaFilterType->demarshal( dc, &((_MICO_T*)v)->type ) &&
+    _marshaller_gsdlInterface_corbaFilterRepeatable->demarshal( dc, &((_MICO_T*)v)->repeatable ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->defaultValue ) &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->validValues ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaFilterOption::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->name );
+  _marshaller_gsdlInterface_corbaFilterType->marshal( ec, &((_MICO_T*)v)->type );
+  _marshaller_gsdlInterface_corbaFilterRepeatable->marshal( ec, &((_MICO_T*)v)->repeatable );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->defaultValue );
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->validValues );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterOption;
+
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaFilterOptionsResponse::corbaFilterOptionsResponse()
+{
+}
+
+gsdlInterface::corbaFilterOptionsResponse::corbaFilterOptionsResponse( const corbaFilterOptionsResponse& _s )
+{
+  options = ((corbaFilterOptionsResponse&)_s).options;
+  names = ((corbaFilterOptionsResponse&)_s).names;
+}
+
+gsdlInterface::corbaFilterOptionsResponse::~corbaFilterOptionsResponse()
+{
+}
+
+gsdlInterface::corbaFilterOptionsResponse&
+gsdlInterface::corbaFilterOptionsResponse::operator=( const corbaFilterOptionsResponse& _s )
+{
+  options = ((corbaFilterOptionsResponse&)_s).options;
+  names = ((corbaFilterOptionsResponse&)_s).names;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaFilterOptionsResponse : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaFilterOptionsResponse _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaFilterOptionsResponse::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterOptionsResponse::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterOptionsResponse::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaFilterOptionsResponse::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller__seq_gsdlInterface_corbaFilterOption->demarshal( dc, &((_MICO_T*)v)->options ) &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->names ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaFilterOptionsResponse::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller__seq_gsdlInterface_corbaFilterOption->marshal( ec, &((_MICO_T*)v)->options );
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->names );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterOptionsResponse;
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaOptionValue::corbaOptionValue()
+{
+}
+
+gsdlInterface::corbaOptionValue::corbaOptionValue( const corbaOptionValue& _s )
+{
+  name = ((corbaOptionValue&)_s).name;
+  value = ((corbaOptionValue&)_s).value;
+}
+
+gsdlInterface::corbaOptionValue::~corbaOptionValue()
+{
+}
+
+gsdlInterface::corbaOptionValue&
+gsdlInterface::corbaOptionValue::operator=( const corbaOptionValue& _s )
+{
+  name = ((corbaOptionValue&)_s).name;
+  value = ((corbaOptionValue&)_s).value;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaOptionValue : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaOptionValue _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaOptionValue::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaOptionValue::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaOptionValue::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaOptionValue::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->name ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->value ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaOptionValue::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->name );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->value );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaOptionValue;
+
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaFilterRequest::corbaFilterRequest()
+{
+}
+
+gsdlInterface::corbaFilterRequest::corbaFilterRequest( const corbaFilterRequest& _s )
+{
+  filter = ((corbaFilterRequest&)_s).filter;
+  filterOptions = ((corbaFilterRequest&)_s).filterOptions;
+  docSet = ((corbaFilterRequest&)_s).docSet;
+  filterResultOptions = ((corbaFilterRequest&)_s).filterResultOptions;
+  requestParams = ((corbaFilterRequest&)_s).requestParams;
+  refParams = ((corbaFilterRequest&)_s).refParams;
+  fields = ((corbaFilterRequest&)_s).fields;
+  getParents = ((corbaFilterRequest&)_s).getParents;
+}
+
+gsdlInterface::corbaFilterRequest::~corbaFilterRequest()
+{
+}
+
+gsdlInterface::corbaFilterRequest&
+gsdlInterface::corbaFilterRequest::operator=( const corbaFilterRequest& _s )
+{
+  filter = ((corbaFilterRequest&)_s).filter;
+  filterOptions = ((corbaFilterRequest&)_s).filterOptions;
+  docSet = ((corbaFilterRequest&)_s).docSet;
+  filterResultOptions = ((corbaFilterRequest&)_s).filterResultOptions;
+  requestParams = ((corbaFilterRequest&)_s).requestParams;
+  refParams = ((corbaFilterRequest&)_s).refParams;
+  fields = ((corbaFilterRequest&)_s).fields;
+  getParents = ((corbaFilterRequest&)_s).getParents;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaFilterRequest : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaFilterRequest _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaFilterRequest::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterRequest::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterRequest::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaFilterRequest::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->filter ) &&
+    _marshaller__seq_gsdlInterface_corbaOptionValue->demarshal( dc, &((_MICO_T*)v)->filterOptions ) &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->docSet ) &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->filterResultOptions ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->requestParams ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->refParams ) &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->fields ) &&
+    CORBA::_stc_boolean->demarshal( dc, &((_MICO_T*)v)->getParents ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaFilterRequest::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->filter );
+  _marshaller__seq_gsdlInterface_corbaOptionValue->marshal( ec, &((_MICO_T*)v)->filterOptions );
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->docSet );
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->filterResultOptions );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->requestParams );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->refParams );
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->fields );
+  CORBA::_stc_boolean->marshal( ec, &((_MICO_T*)v)->getParents );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterRequest;
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaTermInfo::corbaTermInfo()
+{
+}
+
+gsdlInterface::corbaTermInfo::corbaTermInfo( const corbaTermInfo& _s )
+{
+  term = ((corbaTermInfo&)_s).term;
+  frequency = ((corbaTermInfo&)_s).frequency;
+  matchTerms = ((corbaTermInfo&)_s).matchTerms;
+}
+
+gsdlInterface::corbaTermInfo::~corbaTermInfo()
+{
+}
+
+gsdlInterface::corbaTermInfo&
+gsdlInterface::corbaTermInfo::operator=( const corbaTermInfo& _s )
+{
+  term = ((corbaTermInfo&)_s).term;
+  frequency = ((corbaTermInfo&)_s).frequency;
+  matchTerms = ((corbaTermInfo&)_s).matchTerms;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaTermInfo : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaTermInfo _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaTermInfo::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaTermInfo::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaTermInfo::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaTermInfo::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->term ) &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->frequency ) &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->matchTerms ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaTermInfo::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->term );
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->frequency );
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->matchTerms );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaTermInfo;
+
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaMetadataInfo::corbaMetadataInfo()
+{
+}
+
+gsdlInterface::corbaMetadataInfo::corbaMetadataInfo( const corbaMetadataInfo& _s )
+{
+  params = ((corbaMetadataInfo&)_s).params;
+  isRef = ((corbaMetadataInfo&)_s).isRef;
+  values = ((corbaMetadataInfo&)_s).values;
+  id = ((corbaMetadataInfo&)_s).id;
+  parentid = ((corbaMetadataInfo&)_s).parentid;
+}
+
+gsdlInterface::corbaMetadataInfo::~corbaMetadataInfo()
+{
+}
+
+gsdlInterface::corbaMetadataInfo&
+gsdlInterface::corbaMetadataInfo::operator=( const corbaMetadataInfo& _s )
+{
+  params = ((corbaMetadataInfo&)_s).params;
+  isRef = ((corbaMetadataInfo&)_s).isRef;
+  values = ((corbaMetadataInfo&)_s).values;
+  id = ((corbaMetadataInfo&)_s).id;
+  parentid = ((corbaMetadataInfo&)_s).parentid;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaMetadataInfo : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaMetadataInfo _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaMetadataInfo::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaMetadataInfo::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaMetadataInfo::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaMetadataInfo::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->params ) &&
+    CORBA::_stc_boolean->demarshal( dc, &((_MICO_T*)v)->isRef ) &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->values ) &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->id ) &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->parentid ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaMetadataInfo::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->params );
+  CORBA::_stc_boolean->marshal( ec, &((_MICO_T*)v)->isRef );
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->values );
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->id );
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->parentid );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaMetadataInfo;
+
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaMetadataInfo_map::corbaMetadataInfo_map()
+{
+}
+
+gsdlInterface::corbaMetadataInfo_map::corbaMetadataInfo_map( const corbaMetadataInfo_map& _s )
+{
+  names = ((corbaMetadataInfo_map&)_s).names;
+  values = ((corbaMetadataInfo_map&)_s).values;
+}
+
+gsdlInterface::corbaMetadataInfo_map::~corbaMetadataInfo_map()
+{
+}
+
+gsdlInterface::corbaMetadataInfo_map&
+gsdlInterface::corbaMetadataInfo_map::operator=( const corbaMetadataInfo_map& _s )
+{
+  names = ((corbaMetadataInfo_map&)_s).names;
+  values = ((corbaMetadataInfo_map&)_s).values;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaMetadataInfo_map : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaMetadataInfo_map _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaMetadataInfo_map::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaMetadataInfo_map::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaMetadataInfo_map::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaMetadataInfo_map::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller__seq_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->names ) &&
+    _marshaller__seq_gsdlInterface_corbaMetadataInfo->demarshal( dc, &((_MICO_T*)v)->values ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaMetadataInfo_map::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller__seq_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->names );
+  _marshaller__seq_gsdlInterface_corbaMetadataInfo->marshal( ec, &((_MICO_T*)v)->values );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaMetadataInfo_map;
+
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaResultDocInfo::corbaResultDocInfo()
+{
+}
+
+gsdlInterface::corbaResultDocInfo::corbaResultDocInfo( const corbaResultDocInfo& _s )
+{
+  OID = ((corbaResultDocInfo&)_s).OID;
+  resultNum = ((corbaResultDocInfo&)_s).resultNum;
+  ranking = ((corbaResultDocInfo&)_s).ranking;
+  termsMatched = ((corbaResultDocInfo&)_s).termsMatched;
+  phraseMatched = ((corbaResultDocInfo&)_s).phraseMatched;
+  docFreq = ((corbaResultDocInfo&)_s).docFreq;
+  metadata = ((corbaResultDocInfo&)_s).metadata;
+  classifierMetadataType = ((corbaResultDocInfo&)_s).classifierMetadataType;
+  classifierMetadataOffset = ((corbaResultDocInfo&)_s).classifierMetadataOffset;
+  metaparents = ((corbaResultDocInfo&)_s).metaparents;
+}
+
+gsdlInterface::corbaResultDocInfo::~corbaResultDocInfo()
+{
+}
+
+gsdlInterface::corbaResultDocInfo&
+gsdlInterface::corbaResultDocInfo::operator=( const corbaResultDocInfo& _s )
+{
+  OID = ((corbaResultDocInfo&)_s).OID;
+  resultNum = ((corbaResultDocInfo&)_s).resultNum;
+  ranking = ((corbaResultDocInfo&)_s).ranking;
+  termsMatched = ((corbaResultDocInfo&)_s).termsMatched;
+  phraseMatched = ((corbaResultDocInfo&)_s).phraseMatched;
+  docFreq = ((corbaResultDocInfo&)_s).docFreq;
+  metadata = ((corbaResultDocInfo&)_s).metadata;
+  classifierMetadataType = ((corbaResultDocInfo&)_s).classifierMetadataType;
+  classifierMetadataOffset = ((corbaResultDocInfo&)_s).classifierMetadataOffset;
+  metaparents = ((corbaResultDocInfo&)_s).metaparents;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaResultDocInfo : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaResultDocInfo _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaResultDocInfo::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaResultDocInfo::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaResultDocInfo::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaResultDocInfo::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->OID ) &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->resultNum ) &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->ranking ) &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->termsMatched ) &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->phraseMatched ) &&
+    CORBA::_stcseq_long->demarshal( dc, &((_MICO_T*)v)->docFreq ) &&
+    _marshaller_gsdlInterface_corbaMetadataInfo_map->demarshal( dc, &((_MICO_T*)v)->metadata ) &&
+    _marshaller_gsdlInterface_corbatext_t->demarshal( dc, &((_MICO_T*)v)->classifierMetadataType ) &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->classifierMetadataOffset ) &&
+    _marshaller__seq_gsdlInterface_corbaMetadataInfo->demarshal( dc, &((_MICO_T*)v)->metaparents ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaResultDocInfo::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->OID );
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->resultNum );
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->ranking );
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->termsMatched );
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->phraseMatched );
+  CORBA::_stcseq_long->marshal( ec, &((_MICO_T*)v)->docFreq );
+  _marshaller_gsdlInterface_corbaMetadataInfo_map->marshal( ec, &((_MICO_T*)v)->metadata );
+  _marshaller_gsdlInterface_corbatext_t->marshal( ec, &((_MICO_T*)v)->classifierMetadataType );
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->classifierMetadataOffset );
+  _marshaller__seq_gsdlInterface_corbaMetadataInfo->marshal( ec, &((_MICO_T*)v)->metaparents );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaResultDocInfo;
+
+
+
+class _Marshaller_gsdlInterface_corbaIsApprox : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaIsApprox _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaIsApprox::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaIsApprox::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaIsApprox::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaIsApprox::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::ULong ul;
+  if( !dc.enumeration( ul ) )
+    return FALSE;
+  *(_MICO_T*) v = (_MICO_T) ul;
+  return TRUE;
+}
+
+void _Marshaller_gsdlInterface_corbaIsApprox::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.enumeration( (CORBA::ULong) *(_MICO_T *) v );
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaIsApprox;
+
+#ifdef HAVE_EXPLICIT_STRUCT_OPS
+gsdlInterface::corbaFilterResponse::corbaFilterResponse()
+{
+}
+
+gsdlInterface::corbaFilterResponse::corbaFilterResponse( const corbaFilterResponse& _s )
+{
+  numDocs = ((corbaFilterResponse&)_s).numDocs;
+  isApprox = ((corbaFilterResponse&)_s).isApprox;
+  termInfo = ((corbaFilterResponse&)_s).termInfo;
+  docInfo = ((corbaFilterResponse&)_s).docInfo;
+}
+
+gsdlInterface::corbaFilterResponse::~corbaFilterResponse()
+{
+}
+
+gsdlInterface::corbaFilterResponse&
+gsdlInterface::corbaFilterResponse::operator=( const corbaFilterResponse& _s )
+{
+  numDocs = ((corbaFilterResponse&)_s).numDocs;
+  isApprox = ((corbaFilterResponse&)_s).isApprox;
+  termInfo = ((corbaFilterResponse&)_s).termInfo;
+  docInfo = ((corbaFilterResponse&)_s).docInfo;
+  return *this;
+}
+#endif
+
+class _Marshaller_gsdlInterface_corbaFilterResponse : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaFilterResponse _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaFilterResponse::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterResponse::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller_gsdlInterface_corbaFilterResponse::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaFilterResponse::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  return
+    dc.struct_begin() &&
+    CORBA::_stc_long->demarshal( dc, &((_MICO_T*)v)->numDocs ) &&
+    _marshaller_gsdlInterface_corbaIsApprox->demarshal( dc, &((_MICO_T*)v)->isApprox ) &&
+    _marshaller__seq_gsdlInterface_corbaTermInfo->demarshal( dc, &((_MICO_T*)v)->termInfo ) &&
+    _marshaller__seq_gsdlInterface_corbaResultDocInfo->demarshal( dc, &((_MICO_T*)v)->docInfo ) &&
+    dc.struct_end();
+}
+
+void _Marshaller_gsdlInterface_corbaFilterResponse::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  ec.struct_begin();
+  CORBA::_stc_long->marshal( ec, &((_MICO_T*)v)->numDocs );
+  _marshaller_gsdlInterface_corbaIsApprox->marshal( ec, &((_MICO_T*)v)->isApprox );
+  _marshaller__seq_gsdlInterface_corbaTermInfo->marshal( ec, &((_MICO_T*)v)->termInfo );
+  _marshaller__seq_gsdlInterface_corbaResultDocInfo->marshal( ec, &((_MICO_T*)v)->docInfo );
+  ec.struct_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaFilterResponse;
+
+
+// Stub interface corbaiface
+gsdlInterface::corbaiface::~corbaiface()
+{
+}
+
+void *gsdlInterface::corbaiface::_narrow_helper( const char *_rid )
+{
+  if( strcmp( _rid, "IDL:gsdlInterface/corbaiface:1.0" ) == 0 )
+    return (void *)this;
+  return NULL;
+}
+
+bool gsdlInterface::corbaiface::_narrow_helper2( CORBA::Object_ptr _obj )
+{
+  if( strcmp( _obj->_repoid(), "IDL:gsdlInterface/corbaiface:1.0" ) == 0) {
+    return true;
+  }
+  for( vector<CORBA::Narrow_proto>::size_type _i = 0;
+       _narrow_helpers && _i < _narrow_helpers->size(); _i++ ) {
+    bool _res = (*(*_narrow_helpers)[ _i ])( _obj );
+    if( _res )
+      return true;
+  }
+  return false;
+}
+
+gsdlInterface::corbaiface_ptr gsdlInterface::corbaiface::_narrow( CORBA::Object_ptr _obj )
+{
+  gsdlInterface::corbaiface_ptr _o;
+  if( !CORBA::is_nil( _obj ) ) {
+    void *_p;
+    if( (_p = _obj->_narrow_helper( "IDL:gsdlInterface/corbaiface:1.0" )))
+      return _duplicate( (gsdlInterface::corbaiface_ptr) _p );
+    if( _narrow_helper2( _obj ) ||
+       ( _obj->_is_a_remote( "IDL:gsdlInterface/corbaiface:1.0" ) ) ) {
+      _o = new gsdlInterface::corbaiface_stub;
+      _o->MICO_SCOPE(CORBA,Object::operator=)( *_obj );
+      return _o;
+    }
+  }
+  return _nil();
+}
+
+gsdlInterface::corbaiface_ptr
+gsdlInterface::corbaiface::_narrow( CORBA::AbstractBase_ptr _obj )
+{
+  return _narrow (_obj->_to_object());
+}
+
+gsdlInterface::corbaiface_stub::~corbaiface_stub()
+{
+}
+
+CORBA::Boolean gsdlInterface::corbaiface_stub::initialise( gsdlInterface::corbaComError& error )
+{
+  CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+  CORBA::Boolean _res;
+  CORBA::StaticAny __res( CORBA::_stc_boolean, &_res );
+
+  CORBA::StaticRequest __req( this, "initialise" );
+  __req.add_inout_arg( &_error );
+  __req.set_result( &__res );
+
+  __req.invoke();
+
+  mico_sii_throw( &__req, 
+    0);
+  return _res;
+}
+
+
+void gsdlInterface::corbaiface_stub::configure( const gsdlInterface::corbatext_t& key, const gsdlInterface::corbatext_tarray& cfgline, gsdlInterface::corbaComError& error )
+{
+  CORBA::StaticAny _key( _marshaller_gsdlInterface_corbatext_t, &key );
+  CORBA::StaticAny _cfgline( _marshaller__seq_gsdlInterface_corbatext_t, &cfgline );
+  CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+  CORBA::StaticRequest __req( this, "configure" );
+  __req.add_in_arg( &_key );
+  __req.add_in_arg( &_cfgline );
+  __req.add_inout_arg( &_error );
+
+  __req.invoke();
+
+  mico_sii_throw( &__req, 
+    0);
+}
+
+
+void gsdlInterface::corbaiface_stub::collectionList( gsdlInterface::corbatext_tarray& collist, gsdlInterface::corbaComError& error )
+{
+  CORBA::StaticAny _collist( _marshaller__seq_gsdlInterface_corbatext_t, &collist );
+  CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+  CORBA::StaticRequest __req( this, "collectionList" );
+  __req.add_inout_arg( &_collist );
+  __req.add_inout_arg( &_error );
+
+  __req.invoke();
+
+  mico_sii_throw( &__req, 
+    0);
+}
+
+
+void gsdlInterface::corbaiface_stub::hasCollection( const gsdlInterface::corbatext_t& corbaCollection, CORBA::Boolean& has, gsdlInterface::corbaComError& error )
+{
+  CORBA::StaticAny _corbaCollection( _marshaller_gsdlInterface_corbatext_t, &corbaCollection );
+  CORBA::StaticAny _has( CORBA::_stc_boolean, &has );
+  CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+  CORBA::StaticRequest __req( this, "hasCollection" );
+  __req.add_in_arg( &_corbaCollection );
+  __req.add_inout_arg( &_has );
+  __req.add_inout_arg( &_error );
+
+  __req.invoke();
+
+  mico_sii_throw( &__req, 
+    0);
+}
+
+
+void gsdlInterface::corbaiface_stub::ping( const gsdlInterface::corbatext_t& collection, CORBA::Boolean& wasSuccess, gsdlInterface::corbaComError& error )
+{
+  CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+  CORBA::StaticAny _wasSuccess( CORBA::_stc_boolean, &wasSuccess );
+  CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+  CORBA::StaticRequest __req( this, "ping" );
+  __req.add_in_arg( &_collection );
+  __req.add_inout_arg( &_wasSuccess );
+  __req.add_inout_arg( &_error );
+
+  __req.invoke();
+
+  mico_sii_throw( &__req, 
+    0);
+}
+
+
+void gsdlInterface::corbaiface_stub::getDocument( const gsdlInterface::corbatext_t& collection, gsdlInterface::corbaDocRequest& request, gsdlInterface::corbaDocResponse& response, gsdlInterface::corbaComError& error )
+{
+  CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+  CORBA::StaticAny _request( _marshaller_gsdlInterface_corbaDocRequest, &request );
+  CORBA::StaticAny _response( _marshaller_gsdlInterface_corbaDocResponse, &response );
+  CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+  CORBA::StaticRequest __req( this, "getDocument" );
+  __req.add_in_arg( &_collection );
+  __req.add_inout_arg( &_request );
+  __req.add_inout_arg( &_response );
+  __req.add_inout_arg( &_error );
+
+  __req.invoke();
+
+  mico_sii_throw( &__req, 
+    0);
+}
+
+
+void gsdlInterface::corbaiface_stub::getCollectInfo( const gsdlInterface::corbatext_t& collection, gsdlInterface::corbaColInfoResponse& response, gsdlInterface::corbaComError& error )
+{
+  CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+  CORBA::StaticAny _response( _marshaller_gsdlInterface_corbaColInfoResponse, &response );
+  CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+  CORBA::StaticRequest __req( this, "getCollectInfo" );
+  __req.add_in_arg( &_collection );
+  __req.add_inout_arg( &_response );
+  __req.add_inout_arg( &_error );
+
+  __req.invoke();
+
+  mico_sii_throw( &__req, 
+    0);
+}
+
+
+void gsdlInterface::corbaiface_stub::getFilterInfo( const gsdlInterface::corbatext_t& collection, gsdlInterface::corbatext_tarray& filterNames, gsdlInterface::corbaComError& error )
+{
+  CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+  CORBA::StaticAny _filterNames( _marshaller__seq_gsdlInterface_corbatext_t, &filterNames );
+  CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+  CORBA::StaticRequest __req( this, "getFilterInfo" );
+  __req.add_in_arg( &_collection );
+  __req.add_inout_arg( &_filterNames );
+  __req.add_inout_arg( &_error );
+
+  __req.invoke();
+
+  mico_sii_throw( &__req, 
+    0);
+}
+
+
+void gsdlInterface::corbaiface_stub::getFilterOptions( const gsdlInterface::corbatext_t& collection, const gsdlInterface::corbatext_t& option, gsdlInterface::corbaFilterOptionsResponse& response, gsdlInterface::corbaComError& error )
+{
+  CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+  CORBA::StaticAny _option( _marshaller_gsdlInterface_corbatext_t, &option );
+  CORBA::StaticAny _response( _marshaller_gsdlInterface_corbaFilterOptionsResponse, &response );
+  CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+  CORBA::StaticRequest __req( this, "getFilterOptions" );
+  __req.add_in_arg( &_collection );
+  __req.add_in_arg( &_option );
+  __req.add_inout_arg( &_response );
+  __req.add_inout_arg( &_error );
+
+  __req.invoke();
+
+  mico_sii_throw( &__req, 
+    0);
+}
+
+
+void gsdlInterface::corbaiface_stub::filter( const gsdlInterface::corbatext_t& collection, const gsdlInterface::corbaFilterRequest& request, gsdlInterface::corbaFilterResponse& response, gsdlInterface::corbaComError& error )
+{
+  CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+  CORBA::StaticAny _request( _marshaller_gsdlInterface_corbaFilterRequest, &request );
+  CORBA::StaticAny _response( _marshaller_gsdlInterface_corbaFilterResponse, &response );
+  CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+  CORBA::StaticRequest __req( this, "filter" );
+  __req.add_in_arg( &_collection );
+  __req.add_in_arg( &_request );
+  __req.add_inout_arg( &_response );
+  __req.add_inout_arg( &_error );
+
+  __req.invoke();
+
+  mico_sii_throw( &__req, 
+    0);
+}
+
+
+#ifdef HAVE_NAMESPACE
+namespace gsdlInterface { vector<CORBA::Narrow_proto> * corbaiface::_narrow_helpers; }
+#else
+vector<CORBA::Narrow_proto> * gsdlInterface::corbaiface::_narrow_helpers;
+#endif
+
+class _Marshaller_gsdlInterface_corbaiface : public CORBA::StaticTypeInfo {
+    typedef gsdlInterface::corbaiface_ptr _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller_gsdlInterface_corbaiface::create() const
+{
+  return (StaticValueType) new _MICO_T( 0 );
+}
+
+void _Marshaller_gsdlInterface_corbaiface::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = ::gsdlInterface::corbaiface::_duplicate( *(_MICO_T*) s );
+}
+
+void _Marshaller_gsdlInterface_corbaiface::free( StaticValueType v ) const
+{
+  CORBA::release( *(_MICO_T *) v );
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller_gsdlInterface_corbaiface::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::Object_ptr obj;
+  if (!CORBA::_stc_Object->demarshal(dc, &obj))
+    return FALSE;
+  *(_MICO_T *) v = ::gsdlInterface::corbaiface::_narrow( obj );
+  CORBA::Boolean ret = CORBA::is_nil (obj) || !CORBA::is_nil (*(_MICO_T *)v);
+  CORBA::release (obj);
+  return ret;
+}
+
+void _Marshaller_gsdlInterface_corbaiface::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  CORBA::Object_ptr obj = *(_MICO_T *) v;
+  CORBA::_stc_Object->marshal( ec, &obj );
+}
+
+CORBA::StaticTypeInfo *_marshaller_gsdlInterface_corbaiface;
+
+class _Marshaller__seq_gsdlInterface_corbatext_t : public CORBA::StaticTypeInfo {
+    typedef SequenceTmpl<gsdlInterface::corbatext_t,MICO_TID_DEF> _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller__seq_gsdlInterface_corbatext_t::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller__seq_gsdlInterface_corbatext_t::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller__seq_gsdlInterface_corbatext_t::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller__seq_gsdlInterface_corbatext_t::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::ULong len;
+  if( !dc.seq_begin( len ) )
+    return FALSE;
+  ((_MICO_T *) v)->length( len );
+  for( CORBA::ULong i = 0; i < len; i++ ) {
+    if( !_marshaller_gsdlInterface_corbatext_t->demarshal( dc, &(*(_MICO_T*)v)[i] ) )
+      return FALSE;
+  }
+  return dc.seq_end();
+}
+
+void _Marshaller__seq_gsdlInterface_corbatext_t::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  CORBA::ULong len = ((_MICO_T *) v)->length();
+  ec.seq_begin( len );
+  for( CORBA::ULong i = 0; i < len; i++ )
+    _marshaller_gsdlInterface_corbatext_t->marshal( ec, &(*(_MICO_T*)v)[i] );
+  ec.seq_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbatext_t;
+
+class _Marshaller__seq_gsdlInterface_corbaFilterOption : public CORBA::StaticTypeInfo {
+    typedef SequenceTmpl<gsdlInterface::corbaFilterOption,MICO_TID_DEF> _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller__seq_gsdlInterface_corbaFilterOption::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller__seq_gsdlInterface_corbaFilterOption::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller__seq_gsdlInterface_corbaFilterOption::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller__seq_gsdlInterface_corbaFilterOption::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::ULong len;
+  if( !dc.seq_begin( len ) )
+    return FALSE;
+  ((_MICO_T *) v)->length( len );
+  for( CORBA::ULong i = 0; i < len; i++ ) {
+    if( !_marshaller_gsdlInterface_corbaFilterOption->demarshal( dc, &(*(_MICO_T*)v)[i] ) )
+      return FALSE;
+  }
+  return dc.seq_end();
+}
+
+void _Marshaller__seq_gsdlInterface_corbaFilterOption::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  CORBA::ULong len = ((_MICO_T *) v)->length();
+  ec.seq_begin( len );
+  for( CORBA::ULong i = 0; i < len; i++ )
+    _marshaller_gsdlInterface_corbaFilterOption->marshal( ec, &(*(_MICO_T*)v)[i] );
+  ec.seq_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbaFilterOption;
+
+class _Marshaller__seq_gsdlInterface_corbaOptionValue : public CORBA::StaticTypeInfo {
+    typedef SequenceTmpl<gsdlInterface::corbaOptionValue,MICO_TID_DEF> _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller__seq_gsdlInterface_corbaOptionValue::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller__seq_gsdlInterface_corbaOptionValue::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller__seq_gsdlInterface_corbaOptionValue::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller__seq_gsdlInterface_corbaOptionValue::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::ULong len;
+  if( !dc.seq_begin( len ) )
+    return FALSE;
+  ((_MICO_T *) v)->length( len );
+  for( CORBA::ULong i = 0; i < len; i++ ) {
+    if( !_marshaller_gsdlInterface_corbaOptionValue->demarshal( dc, &(*(_MICO_T*)v)[i] ) )
+      return FALSE;
+  }
+  return dc.seq_end();
+}
+
+void _Marshaller__seq_gsdlInterface_corbaOptionValue::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  CORBA::ULong len = ((_MICO_T *) v)->length();
+  ec.seq_begin( len );
+  for( CORBA::ULong i = 0; i < len; i++ )
+    _marshaller_gsdlInterface_corbaOptionValue->marshal( ec, &(*(_MICO_T*)v)[i] );
+  ec.seq_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbaOptionValue;
+
+class _Marshaller__seq_gsdlInterface_corbaTermInfo : public CORBA::StaticTypeInfo {
+    typedef SequenceTmpl<gsdlInterface::corbaTermInfo,MICO_TID_DEF> _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller__seq_gsdlInterface_corbaTermInfo::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller__seq_gsdlInterface_corbaTermInfo::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller__seq_gsdlInterface_corbaTermInfo::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller__seq_gsdlInterface_corbaTermInfo::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::ULong len;
+  if( !dc.seq_begin( len ) )
+    return FALSE;
+  ((_MICO_T *) v)->length( len );
+  for( CORBA::ULong i = 0; i < len; i++ ) {
+    if( !_marshaller_gsdlInterface_corbaTermInfo->demarshal( dc, &(*(_MICO_T*)v)[i] ) )
+      return FALSE;
+  }
+  return dc.seq_end();
+}
+
+void _Marshaller__seq_gsdlInterface_corbaTermInfo::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  CORBA::ULong len = ((_MICO_T *) v)->length();
+  ec.seq_begin( len );
+  for( CORBA::ULong i = 0; i < len; i++ )
+    _marshaller_gsdlInterface_corbaTermInfo->marshal( ec, &(*(_MICO_T*)v)[i] );
+  ec.seq_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbaTermInfo;
+
+class _Marshaller__seq_gsdlInterface_corbaMetadataInfo : public CORBA::StaticTypeInfo {
+    typedef SequenceTmpl<gsdlInterface::corbaMetadataInfo,MICO_TID_DEF> _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller__seq_gsdlInterface_corbaMetadataInfo::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller__seq_gsdlInterface_corbaMetadataInfo::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller__seq_gsdlInterface_corbaMetadataInfo::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller__seq_gsdlInterface_corbaMetadataInfo::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::ULong len;
+  if( !dc.seq_begin( len ) )
+    return FALSE;
+  ((_MICO_T *) v)->length( len );
+  for( CORBA::ULong i = 0; i < len; i++ ) {
+    if( !_marshaller_gsdlInterface_corbaMetadataInfo->demarshal( dc, &(*(_MICO_T*)v)[i] ) )
+      return FALSE;
+  }
+  return dc.seq_end();
+}
+
+void _Marshaller__seq_gsdlInterface_corbaMetadataInfo::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  CORBA::ULong len = ((_MICO_T *) v)->length();
+  ec.seq_begin( len );
+  for( CORBA::ULong i = 0; i < len; i++ )
+    _marshaller_gsdlInterface_corbaMetadataInfo->marshal( ec, &(*(_MICO_T*)v)[i] );
+  ec.seq_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbaMetadataInfo;
+
+class _Marshaller__seq_gsdlInterface_corbaResultDocInfo : public CORBA::StaticTypeInfo {
+    typedef SequenceTmpl<gsdlInterface::corbaResultDocInfo,MICO_TID_DEF> _MICO_T;
+  public:
+    StaticValueType create () const;
+    void assign (StaticValueType dst, const StaticValueType src) const;
+    void free (StaticValueType) const;
+    CORBA::Boolean demarshal (CORBA::DataDecoder&, StaticValueType) const;
+    void marshal (CORBA::DataEncoder &, StaticValueType) const;
+};
+
+
+CORBA::StaticValueType _Marshaller__seq_gsdlInterface_corbaResultDocInfo::create() const
+{
+  return (StaticValueType) new _MICO_T;
+}
+
+void _Marshaller__seq_gsdlInterface_corbaResultDocInfo::assign( StaticValueType d, const StaticValueType s ) const
+{
+  *(_MICO_T*) d = *(_MICO_T*) s;
+}
+
+void _Marshaller__seq_gsdlInterface_corbaResultDocInfo::free( StaticValueType v ) const
+{
+  delete (_MICO_T*) v;
+}
+
+CORBA::Boolean _Marshaller__seq_gsdlInterface_corbaResultDocInfo::demarshal( CORBA::DataDecoder &dc, StaticValueType v ) const
+{
+  CORBA::ULong len;
+  if( !dc.seq_begin( len ) )
+    return FALSE;
+  ((_MICO_T *) v)->length( len );
+  for( CORBA::ULong i = 0; i < len; i++ ) {
+    if( !_marshaller_gsdlInterface_corbaResultDocInfo->demarshal( dc, &(*(_MICO_T*)v)[i] ) )
+      return FALSE;
+  }
+  return dc.seq_end();
+}
+
+void _Marshaller__seq_gsdlInterface_corbaResultDocInfo::marshal( CORBA::DataEncoder &ec, StaticValueType v ) const
+{
+  CORBA::ULong len = ((_MICO_T *) v)->length();
+  ec.seq_begin( len );
+  for( CORBA::ULong i = 0; i < len; i++ )
+    _marshaller_gsdlInterface_corbaResultDocInfo->marshal( ec, &(*(_MICO_T*)v)[i] );
+  ec.seq_end();
+}
+
+CORBA::StaticTypeInfo *_marshaller__seq_gsdlInterface_corbaResultDocInfo;
+
+struct __tc_init_CORBAIFACE {
+  __tc_init_CORBAIFACE()
+  {
+    _marshaller_gsdlInterface_corbatext_t = new _Marshaller_gsdlInterface_corbatext_t;
+    _marshaller_gsdlInterface_corbatext_tmap = new _Marshaller_gsdlInterface_corbatext_tmap;
+    _marshaller_gsdlInterface_corbaComError = new _Marshaller_gsdlInterface_corbaComError;
+    _marshaller_gsdlInterface_corbaShortColInfo = new _Marshaller_gsdlInterface_corbaShortColInfo;
+    _marshaller_gsdlInterface_corbaColInfoResponse = new _Marshaller_gsdlInterface_corbaColInfoResponse;
+    _marshaller_gsdlInterface_corbaDocRequest = new _Marshaller_gsdlInterface_corbaDocRequest;
+    _marshaller_gsdlInterface_corbaDocResponse = new _Marshaller_gsdlInterface_corbaDocResponse;
+    _marshaller_gsdlInterface_corbaFilterType = new _Marshaller_gsdlInterface_corbaFilterType;
+    _marshaller_gsdlInterface_corbaFilterRepeatable = new _Marshaller_gsdlInterface_corbaFilterRepeatable;
+    _marshaller_gsdlInterface_corbaFilterOption = new _Marshaller_gsdlInterface_corbaFilterOption;
+    _marshaller_gsdlInterface_corbaFilterOptionsResponse = new _Marshaller_gsdlInterface_corbaFilterOptionsResponse;
+    _marshaller_gsdlInterface_corbaOptionValue = new _Marshaller_gsdlInterface_corbaOptionValue;
+    _marshaller_gsdlInterface_corbaFilterRequest = new _Marshaller_gsdlInterface_corbaFilterRequest;
+    _marshaller_gsdlInterface_corbaTermInfo = new _Marshaller_gsdlInterface_corbaTermInfo;
+    _marshaller_gsdlInterface_corbaMetadataInfo = new _Marshaller_gsdlInterface_corbaMetadataInfo;
+    _marshaller_gsdlInterface_corbaMetadataInfo_map = new _Marshaller_gsdlInterface_corbaMetadataInfo_map;
+    _marshaller_gsdlInterface_corbaResultDocInfo = new _Marshaller_gsdlInterface_corbaResultDocInfo;
+    _marshaller_gsdlInterface_corbaIsApprox = new _Marshaller_gsdlInterface_corbaIsApprox;
+    _marshaller_gsdlInterface_corbaFilterResponse = new _Marshaller_gsdlInterface_corbaFilterResponse;
+    _marshaller_gsdlInterface_corbaiface = new _Marshaller_gsdlInterface_corbaiface;
+    _marshaller__seq_gsdlInterface_corbatext_t = new _Marshaller__seq_gsdlInterface_corbatext_t;
+    _marshaller__seq_gsdlInterface_corbaFilterOption = new _Marshaller__seq_gsdlInterface_corbaFilterOption;
+    _marshaller__seq_gsdlInterface_corbaOptionValue = new _Marshaller__seq_gsdlInterface_corbaOptionValue;
+    _marshaller__seq_gsdlInterface_corbaTermInfo = new _Marshaller__seq_gsdlInterface_corbaTermInfo;
+    _marshaller__seq_gsdlInterface_corbaMetadataInfo = new _Marshaller__seq_gsdlInterface_corbaMetadataInfo;
+    _marshaller__seq_gsdlInterface_corbaResultDocInfo = new _Marshaller__seq_gsdlInterface_corbaResultDocInfo;
+  }
+};
+
+static __tc_init_CORBAIFACE __init_CORBAIFACE;
+
Index: /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface_skel.mpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface_skel.mpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/corbaiface_skel.mpp	(revision 10506)
@@ -0,0 +1,274 @@
+/*
+ *  MICO --- a free CORBA implementation
+ *  Copyright (C) 1997-98 Kay Roemer & Arno Puder
+ *
+ *  This file was automatically generated. DO NOT EDIT!
+ */
+#include "corbaiface.h"
+
+//--------------------------------------------------------
+//  Implementation of skeletons
+//--------------------------------------------------------
+
+gsdlInterface::corbaiface_skel::corbaiface_skel( const CORBA::BOA::ReferenceData &_id )
+{
+  CORBA::ImplementationDef_var _impl =
+    _find_impl( "IDL:gsdlInterface/corbaiface:1.0", "corbaiface" );
+  assert( !CORBA::is_nil( _impl ) );
+  _create_ref( _id,
+    0,
+    _impl,
+    "IDL:gsdlInterface/corbaiface:1.0" );
+  register_dispatcher( new StaticInterfaceDispatcherWrapper<corbaiface_skel>( this ) );
+}
+
+gsdlInterface::corbaiface_skel::corbaiface_skel( CORBA::Object_ptr _obj )
+{
+  CORBA::ImplementationDef_var _impl =
+    _find_impl( "IDL:gsdlInterface/corbaiface:1.0", "corbaiface" );
+  assert( !CORBA::is_nil( _impl ) );
+  _restore_ref( _obj,
+    CORBA::BOA::ReferenceData(),
+    0,
+    _impl );
+  register_dispatcher( new StaticInterfaceDispatcherWrapper<corbaiface_skel>( this ) );
+}
+
+gsdlInterface::corbaiface_skel::~corbaiface_skel()
+{
+}
+
+bool gsdlInterface::corbaiface_skel::dispatch( CORBA::StaticServerRequest_ptr _req, CORBA::Environment & /*_env*/ )
+{
+  #ifdef HAVE_EXCEPTIONS
+  try {
+  #endif
+    switch (mico_string_hash (_req->op_name(), 17)) {
+    case 0:
+      if( strcmp( _req->op_name(), "collectionList" ) == 0 ) {
+        corbatext_tarray collist;
+        CORBA::StaticAny _collist( _marshaller__seq_gsdlInterface_corbatext_t, &collist );
+        corbaComError error;
+        CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+
+        _req->add_inout_arg( &_collist );
+        _req->add_inout_arg( &_error );
+
+        if( !_req->read_args() )
+          return true;
+
+        collectionList( collist, error );
+        _req->write_results();
+        return true;
+      }
+      break;
+    case 3:
+      if( strcmp( _req->op_name(), "ping" ) == 0 ) {
+        corbatext_t collection;
+        CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+        CORBA::Boolean wasSuccess;
+        CORBA::StaticAny _wasSuccess( CORBA::_stc_boolean, &wasSuccess );
+        corbaComError error;
+        CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+
+        _req->add_in_arg( &_collection );
+        _req->add_inout_arg( &_wasSuccess );
+        _req->add_inout_arg( &_error );
+
+        if( !_req->read_args() )
+          return true;
+
+        ping( collection, wasSuccess, error );
+        _req->write_results();
+        return true;
+      }
+      break;
+    case 7:
+      if( strcmp( _req->op_name(), "filter" ) == 0 ) {
+        corbatext_t collection;
+        CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+        corbaFilterRequest request;
+        CORBA::StaticAny _request( _marshaller_gsdlInterface_corbaFilterRequest, &request );
+        corbaFilterResponse response;
+        CORBA::StaticAny _response( _marshaller_gsdlInterface_corbaFilterResponse, &response );
+        corbaComError error;
+        CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+
+        _req->add_in_arg( &_collection );
+        _req->add_in_arg( &_request );
+        _req->add_inout_arg( &_response );
+        _req->add_inout_arg( &_error );
+
+        if( !_req->read_args() )
+          return true;
+
+        filter( collection, request, response, error );
+        _req->write_results();
+        return true;
+      }
+      break;
+    case 9:
+      if( strcmp( _req->op_name(), "getFilterOptions" ) == 0 ) {
+        corbatext_t collection;
+        CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+        corbatext_t option;
+        CORBA::StaticAny _option( _marshaller_gsdlInterface_corbatext_t, &option );
+        corbaFilterOptionsResponse response;
+        CORBA::StaticAny _response( _marshaller_gsdlInterface_corbaFilterOptionsResponse, &response );
+        corbaComError error;
+        CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+
+        _req->add_in_arg( &_collection );
+        _req->add_in_arg( &_option );
+        _req->add_inout_arg( &_response );
+        _req->add_inout_arg( &_error );
+
+        if( !_req->read_args() )
+          return true;
+
+        getFilterOptions( collection, option, response, error );
+        _req->write_results();
+        return true;
+      }
+      break;
+    case 10:
+      if( strcmp( _req->op_name(), "getCollectInfo" ) == 0 ) {
+        corbatext_t collection;
+        CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+        corbaColInfoResponse response;
+        CORBA::StaticAny _response( _marshaller_gsdlInterface_corbaColInfoResponse, &response );
+        corbaComError error;
+        CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+
+        _req->add_in_arg( &_collection );
+        _req->add_inout_arg( &_response );
+        _req->add_inout_arg( &_error );
+
+        if( !_req->read_args() )
+          return true;
+
+        getCollectInfo( collection, response, error );
+        _req->write_results();
+        return true;
+      }
+      break;
+    case 11:
+      if( strcmp( _req->op_name(), "initialise" ) == 0 ) {
+        corbaComError error;
+        CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+
+        CORBA::Boolean _res;
+        CORBA::StaticAny __res( CORBA::_stc_boolean, &_res );
+        _req->add_inout_arg( &_error );
+        _req->set_result( &__res );
+
+        if( !_req->read_args() )
+          return true;
+
+        _res = initialise( error );
+        _req->write_results();
+        return true;
+      }
+      if( strcmp( _req->op_name(), "getFilterInfo" ) == 0 ) {
+        corbatext_t collection;
+        CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+        corbatext_tarray filterNames;
+        CORBA::StaticAny _filterNames( _marshaller__seq_gsdlInterface_corbatext_t, &filterNames );
+        corbaComError error;
+        CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+
+        _req->add_in_arg( &_collection );
+        _req->add_inout_arg( &_filterNames );
+        _req->add_inout_arg( &_error );
+
+        if( !_req->read_args() )
+          return true;
+
+        getFilterInfo( collection, filterNames, error );
+        _req->write_results();
+        return true;
+      }
+      break;
+    case 12:
+      if( strcmp( _req->op_name(), "hasCollection" ) == 0 ) {
+        corbatext_t corbaCollection;
+        CORBA::StaticAny _corbaCollection( _marshaller_gsdlInterface_corbatext_t, &corbaCollection );
+        CORBA::Boolean has;
+        CORBA::StaticAny _has( CORBA::_stc_boolean, &has );
+        corbaComError error;
+        CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+
+        _req->add_in_arg( &_corbaCollection );
+        _req->add_inout_arg( &_has );
+        _req->add_inout_arg( &_error );
+
+        if( !_req->read_args() )
+          return true;
+
+        hasCollection( corbaCollection, has, error );
+        _req->write_results();
+        return true;
+      }
+      break;
+    case 13:
+      if( strcmp( _req->op_name(), "configure" ) == 0 ) {
+        corbatext_t key;
+        CORBA::StaticAny _key( _marshaller_gsdlInterface_corbatext_t, &key );
+        corbatext_tarray cfgline;
+        CORBA::StaticAny _cfgline( _marshaller__seq_gsdlInterface_corbatext_t, &cfgline );
+        corbaComError error;
+        CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+
+        _req->add_in_arg( &_key );
+        _req->add_in_arg( &_cfgline );
+        _req->add_inout_arg( &_error );
+
+        if( !_req->read_args() )
+          return true;
+
+        configure( key, cfgline, error );
+        _req->write_results();
+        return true;
+      }
+      if( strcmp( _req->op_name(), "getDocument" ) == 0 ) {
+        corbatext_t collection;
+        CORBA::StaticAny _collection( _marshaller_gsdlInterface_corbatext_t, &collection );
+        corbaDocRequest request;
+        CORBA::StaticAny _request( _marshaller_gsdlInterface_corbaDocRequest, &request );
+        corbaDocResponse response;
+        CORBA::StaticAny _response( _marshaller_gsdlInterface_corbaDocResponse, &response );
+        corbaComError error;
+        CORBA::StaticAny _error( _marshaller_gsdlInterface_corbaComError, &error );
+
+        _req->add_in_arg( &_collection );
+        _req->add_inout_arg( &_request );
+        _req->add_inout_arg( &_response );
+        _req->add_inout_arg( &_error );
+
+        if( !_req->read_args() )
+          return true;
+
+        getDocument( collection, request, response, error );
+        _req->write_results();
+        return true;
+      }
+      break;
+    }
+  #ifdef HAVE_EXCEPTIONS
+  } catch( CORBA::SystemException_catch &_ex ) {
+    _req->set_exception( _ex->_clone() );
+    _req->write_results();
+    return true;
+  } catch( ... ) {
+    assert( 0 );
+    return true;
+  }
+  #endif
+  return false;
+}
+
+gsdlInterface::corbaiface_ptr gsdlInterface::corbaiface_skel::_this()
+{
+  return gsdlInterface::corbaiface::_duplicate( this );
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/lib/corbatext_t.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/corbatext_t.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/corbatext_t.h	(revision 10506)
@@ -0,0 +1,13 @@
+void corbatext_fillChar(corbatext_t *t, char *text);
+void corbatext_usvector(corbatext_t t, vector<unsigned short>& us);
+char *corbatext_string(corbatext_t t);
+#ifdef TEXT_T_H
+void corbatext_arrayToCorbaArray(text_tarray t, corbatext_tarray *ca);
+void corbatext_corbaArrayToArray(corbatext_tarray ca, text_tarray *ta);
+void corbatext_mapToCorbaMap(text_tmap tm, corbatext_tmap *cm);
+void corbatext_corbaMapToMap(corbatext_tmap cm, text_tmap &tm);
+void corbatext_setToCorbaArray(text_tset set, corbatext_tset *cset);
+void corbatext_corbaArrayToSet(corbatext_tset cset, text_tset *set);
+corbatext_t_var corbatext_corbatext(text_t t);
+int corbatext_corbatext(text_t t, corbatext_t_var ct);
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/corbatext_t.mpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/corbatext_t.mpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/corbatext_t.mpp	(revision 10506)
@@ -0,0 +1,179 @@
+// standard headers
+#if defined(GSDL_USE_STL_H)
+#include <iostream.h>
+#include <fstream.h>
+#include <vector.h>
+#else
+#include <iostream>
+#include <fstream>
+#include <vector>
+#endif
+
+// protocol headers
+#include "corbaiface.h"
+using namespace gsdlInterface;
+
+// greenstone headers
+#include "corbaconv_text_t.h"
+
+//local headers
+#include "corbatext_t.h"
+
+void corbatext_fillChar(corbatext_t *t, char *text)
+{
+  unsigned int i;
+
+  t->text.length(0);
+  if (text == NULL)
+      {
+	  return;
+      }
+  for (i = 0; i < strlen(text); i ++)
+      {
+	  t->text[i] = text[i];
+      }  
+  t->encoding = 0;
+}
+
+void corbatext_usvector(corbatext_t t, usvector& us)
+{
+  unsigned int i;
+
+  for (i = 0; i < t.text.length(); i ++)
+    {
+      us.push_back(t.text[i]);
+    }
+}
+
+char *corbatext_string(corbatext_t t)
+{ 
+  char *lcopy;
+  unsigned int i;
+    lcopy = (char *) malloc(t.text.length() + 1);
+    for (i = 0; i < t.text.length(); i ++)
+    {
+      lcopy[i] = (char) t.text[i];
+    }
+    lcopy[i] = '\0';
+    return lcopy;
+}
+
+corbatext_t_var corbatext_corbatext(text_t t)
+{ corbatext_t_var ct;
+// usString_var    us;
+
+  // cout << "Making text\n";
+  ct = new corbatext_t;
+  //  ct->text.length(20);
+  // us = new usString(20);
+  //  cout << ct->text.length() << endl;
+  //  cout << ct->text.maximum() << endl;
+  corbaconv_text_t::fillUsString(t,&ct->text);
+  //t.fillUsString(us);
+  // delete us;
+  // cout << "Encoding text\n";
+  ct->encoding = 0;
+  // cout << "Encoding text\n";
+  return ct;
+}
+
+int corbatext_corbatext(text_t t, corbatext_t_var ct)
+{
+  cout << "A" << endl;
+  corbaconv_text_t::fillUsString(t,&ct->text);
+  cout << "B" << endl;
+  ct->encoding = 0;
+  cout << "C" << endl;
+}
+
+void corbatext_corbaArrayToArray(corbatext_tarray ca, text_tarray *ta)
+{
+  unsigned int i;
+  corbaconv_text_t *cct;
+
+  ta->clear();
+  ta->reserve(ca.length());
+  for (i = 0; i < ca.length(); i ++)
+    {
+      cct = new corbaconv_text_t(ca[i]);
+      ta->push_back(*cct); // cast to text_t
+    }  
+}
+
+void corbatext_arrayToCorbaArray(text_tarray ta, corbatext_tarray *_ca)
+{
+  text_tarray::iterator here = ta.begin();
+  text_tarray::iterator end = ta.end();
+  corbatext_tarray ca(end - here);
+  unsigned int i;
+
+  i = 0;
+  (*_ca).length(end - here);
+
+  while (here != end)
+    {
+      corbatext_t_var ptr;
+      //      cout << "Array: " << (*_ca).maximum() << " " << (*_ca).length() << endl;
+      ptr = corbatext_corbatext(*here);
+      (*_ca)[i] = ptr;
+      here ++;
+      i++;      
+    }
+}
+
+void corbatext_corbaArrayToSet(corbatext_tarray t, text_tset *ts)
+{ unsigned int i;
+ 
+  for (i = 0; i < t.length(); i ++)
+    {
+      ts->insert((corbaconv_text_t) t[i]); // further typecast to text_t
+    } 
+
+  return;
+}
+
+void corbatext_setToCorbaArray(text_tset ts, corbatext_tarray *t)
+{
+  corbatext_t str;
+  text_tset::iterator here = ts.begin();
+  text_tset::iterator end = ts.end();
+  unsigned int i;
+
+  i = 0;
+  while (here != end)
+    {
+      (*t).length(i+1);
+      (*t)[i] = *corbatext_corbatext(*here);
+      here ++;
+      i ++;
+    }
+}
+
+void corbatext_mapToCorbaMap(text_tmap map, corbatext_tmap *cmap)
+{
+  text_tmap::iterator here = map.begin();
+  text_tmap::iterator end  = map.end();
+  unsigned int i = 0;
+
+  while (here != end)
+    {
+      (*cmap).names.length(i+1);
+      (*cmap).values.length(i+1);
+      cmap->names[i] = *corbatext_corbatext((*here).first);
+      cmap->values[i] = *corbatext_corbatext((*here).second);
+      here ++;
+      i ++;
+    }
+}
+
+void corbatext_corbaMapToMap(corbatext_tmap cmap, text_tmap &map)
+{
+  unsigned int i;
+
+  for (i = 0; i < cmap.names.length(); i ++)
+    {
+      map.insert(make_pair(*(new corbaconv_text_t(cmap.names[i])), 
+                           *(new corbaconv_text_t(cmap.values[i])))); // further typecast to text_t
+    }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/lib/display.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/display.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/display.cpp	(revision 10506)
@@ -0,0 +1,1833 @@
+/**********************************************************************
+ *
+ * display.cpp -- Context sensitive macro language
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "display.h"
+#include "gsdlunicode.h"
+#include "unitool.h"
+#include <assert.h>
+
+// include to get NULL
+#include <stdlib.h>
+
+text_t displayclass::defaultpackage = "Global";
+
+/////////////////////////////////////
+// misc classes
+/////////////////////////////////////
+
+
+// precedencetype defines a 'precedence value' for each parameter
+typedef map<text_t, double, lttext_t> precedencetype;
+
+
+
+inline bool operator==(const mvalue &x, const mvalue &y) {
+  return (x.filename==y.filename && x.value==y.value);
+}
+
+inline bool operator<(const mvalue &x, const mvalue &y) {
+  return (x.filename<y.filename ||
+	  (x.filename==y.filename && x.filename<y.filename));
+}
+
+
+
+/////////////////////////////////////
+// stuff for parammacros_t
+/////////////////////////////////////
+  
+typedef map<text_t, mvalue, lttext_t> defparammap;
+typedef map<text_t, defparammap, lttext_t> defmacromap;
+typedef map<text_t, defmacromap, lttext_t> defpackagemap;
+
+// all methods in parammacros_t assume the parameters
+// and packages in a standard form and not empty
+class parammacros_t
+{
+protected:
+  defpackagemap macros;
+
+public:
+  typedef defpackagemap::const_iterator const_package_iterator;
+  typedef defpackagemap::size_type package_size_type;
+
+  // setmacro returns 0 if there was no error,
+  //            -1 if it redefined a macro
+  //            -2 if it hid a Global macro
+  //            -3 if it redefined a macro and hid a Global macro
+  //            -4 if either a package, macroname, or params were not supplied
+  int setmacro(const text_t &package,
+	  const text_t &macroname, 
+	  const text_t &params, 
+	  const text_t &filename, 
+	  const text_t &macrovalue);
+
+  void delmacro(const text_t &package,
+	      const text_t &macroname, 
+	      const text_t &params);
+
+  void clear () {macros.erase(macros.begin(), macros.end());}
+
+  // top level stuff
+  const_package_iterator package_begin () const {return macros.begin();}
+  const_package_iterator package_end () const {return macros.end();}
+  bool package_empty () const {return macros.empty();}
+  package_size_type package_size() const {return macros.size();}
+
+  // methods to find things
+  defmacromap *package_find (const text_t &packagename);
+  defparammap *macro_find (const text_t &packagename, 
+			   const text_t &macroname);
+  mvalue *parameter_find (const text_t &packagename, 
+			  const text_t &macroname,
+			  const text_t &parametername);
+};
+
+
+// setmacro returns 0 if there was no error,
+//            -1 if it redefined a macro
+//            -2 if it hid a Global macro
+//            -3 if it redefined a macro and hid a Global macro
+//            -4 if either a package, macroname, or params were not supplied
+int parammacros_t::setmacro(const text_t &package,
+			 const text_t &macroname, 
+			 const text_t &params, 
+			 const text_t &filename, 
+			 const text_t &macrovalue)
+{
+  paramhashtype paramhash;
+
+  defmacromap *macromapptr;
+  defparammap *parammapptr;
+  mvalue *mvalueptr;
+
+  int warning = 0;
+
+  // check to see if we would be hiding a Global macro with the 
+  // same name. Note: it doesn't matter what parameters are used
+  // a Global macro will still be hid by a non-Global one with
+  // the same name.
+  if ((package != displayclass::defaultpackage) && 
+      (macro_find (displayclass::defaultpackage, macroname) != NULL))
+    {
+      warning -= 2; // found the macroname
+    }
+
+  // define this macro
+  macromapptr = &(macros[package]); // -- package
+  parammapptr = &((*macromapptr)[macroname]); // -- macro name
+  // -- parameters
+  if ((*parammapptr).find(params) != (*parammapptr).end()) {
+    warning -= 1; // found the parameters
+  }
+  mvalueptr = &((*parammapptr)[params]);
+
+  // -- value
+  (*mvalueptr).filename = filename;
+  (*mvalueptr).value = macrovalue;
+
+  return warning;
+}
+
+void parammacros_t::delmacro(const text_t &package,
+			     const text_t &macroname, 
+			     const text_t &params)
+{
+  // make sure everything was supplied
+  if (package.empty() || macroname.empty() || params.empty()) return;
+
+  // find the package and macroname
+  defparammap *parammapptr = macro_find(package, macroname);
+  if (parammapptr == NULL) return;
+
+  // find the parameters
+  defparammap::iterator parammapit = parammapptr->find(params);
+  if (parammapit == parammapptr->end()) return;
+
+  // finally delete this element
+  parammapptr->erase(parammapit);
+}
+
+defmacromap *parammacros_t::package_find (const text_t &packagename)
+{
+  if (packagename.empty()) return NULL;
+
+  defpackagemap::iterator it = macros.find(packagename);
+  if (it == macros.end()) return NULL;
+
+  return &((*it).second);
+}
+
+defparammap *parammacros_t::macro_find (const text_t &packagename, 
+					const text_t &macroname)
+{
+  defmacromap *macromapptr = package_find(packagename);
+  if (macromapptr == NULL || macroname.empty()) return NULL;
+  
+  defmacromap::iterator it = (*macromapptr).find(macroname);
+  if (it == (*macromapptr).end()) return NULL;
+
+  return &((*it).second);
+}
+
+mvalue *parammacros_t::parameter_find (const text_t &packagename, 
+					 const text_t &macroname,
+					 const text_t &parametername)
+{
+  defparammap *parammapptr = macro_find(packagename, macroname);
+  if (parammapptr == NULL || parametername.empty()) return NULL;
+
+  defparammap::iterator it = (*parammapptr).find(parametername);
+  if (it == (*parammapptr).end()) return NULL;
+
+  return &((*it).second);
+}
+
+
+
+/////////////////////////////////////
+// stuff for currentmacros_t
+/////////////////////////////////////
+
+typedef map<text_t, mvalue, lttext_t> curmacromap;
+typedef map<text_t, curmacromap, lttext_t> curpackagemap;
+
+// all methods in currentmacros_t assume the parameters
+// and packages in a standard form and not empty
+class currentmacros_t 
+{
+protected:
+  curpackagemap macros;
+
+public:
+  typedef curpackagemap::const_iterator const_package_iterator;
+  typedef curpackagemap::size_type package_size_type;
+
+  // setmacro returns 0 if there was no error,
+  //            -1 if it redefined a macro
+  //            -4 if either a package, or macroname were not supplied
+  int setmacro(const text_t &package,
+	  const text_t &macroname, 
+	  const text_t &filename, 
+	  const text_t &macrovalue);
+
+  void delmacro(const text_t &package,
+		const text_t &macroname);
+
+  void clear () {macros.erase(macros.begin(), macros.end());}
+
+  // top level stuff
+  const_package_iterator package_begin () const {return macros.begin();}
+  const_package_iterator package_end () const {return macros.end();}
+  bool package_empty () const {return macros.empty();}
+  package_size_type package_size() const {return macros.size();}
+
+  // methods to find things
+  curmacromap *package_find (const text_t &packagename);
+  mvalue *macro_find (const text_t &packagename, 
+		      const text_t &macroname);
+};
+
+
+// setmacro returns 0 if there was no error,
+//            -1 if it redefined a macro
+//            -4 if either a package, or macroname were not supplied
+int currentmacros_t::setmacro(const text_t &package,
+			 const text_t &macroname, 
+			 const text_t &filename, 
+			 const text_t &macrovalue)
+{
+  int warning = 0;
+
+  // make sure everything was supplied
+  if (package.empty() || macroname.empty()) return -4;
+
+  // define this macro
+  curmacromap *macromapptr = &(macros[package]);
+  if ((*macromapptr).find(macroname) != (*macromapptr).end()) 
+    {
+      warning -= 1; // found the macroname
+    }
+  mvalue *mvalueptr = &((*macromapptr)[macroname]);
+
+  // -- value
+  (*mvalueptr).filename = filename;
+  (*mvalueptr).value = macrovalue;
+
+  return warning;
+}
+
+void currentmacros_t::delmacro(const text_t &package,
+			     const text_t &macroname)
+{
+  // make sure everything was supplied
+  if (package.empty() || macroname.empty()) return;
+
+  // find the package
+  curmacromap *macromapptr = package_find(package);
+  if (macromapptr == NULL) return;
+
+  // find the macroname
+  curmacromap::iterator macromapit = macromapptr->find(macroname);
+  if (macromapit == macromapptr->end()) return;
+
+  // finally delete this element
+  macromapptr->erase(macromapit);
+}
+
+curmacromap *currentmacros_t::package_find (const text_t &packagename)
+{
+  if (packagename.empty()) return NULL;
+
+  curpackagemap::iterator it = macros.find(packagename);
+  if (it == macros.end()) return NULL;
+
+  return &((*it).second);
+}
+
+mvalue *currentmacros_t::macro_find (const text_t &packagename, 
+				     const text_t &macroname)
+{
+  curmacromap *macromapptr = package_find(packagename);
+  if (macromapptr == NULL || macroname.empty()) return NULL;
+
+  curmacromap::iterator it = (*macromapptr).find(macroname);
+  if (it == (*macromapptr).end()) return NULL;
+
+  return &((*it).second);
+}
+
+
+
+
+/////////////////////////////////////
+// support functions
+/////////////////////////////////////
+
+// this calculation of precedence will make one occurance of a high
+// precedence item override many occurances of lower precedence items
+void calcprecedence (const text_t &precedstr, precedencetype &precedhash) 
+{
+  text_t param;
+  double multiple = 5.0;
+  double nextprec = multiple;
+
+  text_t::const_iterator here, end;
+
+  // set precedhash to an empty hash
+  precedhash.erase(precedhash.begin(), precedhash.end());
+
+  // iterate through paramstring ignoring space and extracting
+  // out key value pairs.
+  here = precedstr.begin();
+  end = precedstr.end();
+  while (here != end) 
+    {
+      // get the next parameter
+      param.clear(); // set param to an empty string
+      
+      while (here != end) 
+	{
+	  if (*here == ',') 
+	    {
+	      // found the end of the parameter
+	      ++here;
+	      break;
+	    } 
+	  else if (*here == ' ') 
+	    {
+	      // do nothing (ignore spaces)
+	    } 
+	  else 
+	    {
+	      // character in parameter
+	      param.push_back (*here); // copy this character
+	    }
+	  
+	  ++here;
+	}
+
+      // if a parameter was found insert its value
+      if (!param.empty()) 
+	{
+	  precedhash[param] = nextprec;
+	  nextprec *= multiple;
+	}
+    }
+}
+
+
+// decides how specific any given parameter is to the page parameters. Returns 
+// negative if any options are different or else the sum of the precedence for
+// the options which match. 
+double getspecificness(const paramhashtype &pageparams, 
+		       const paramhashtype &theseparams, 
+		       const precedencetype &precedhash) 
+{
+  double specificness = 0.0;
+  paramhashtype::const_iterator here, pagevalueit;
+  precedencetype::const_iterator precedit;
+  text_t thesekey, thesevalue, constignore("ignore");
+  
+  here = theseparams.begin();
+  while (here != theseparams.end()) 
+    {
+      thesekey = (*here).first;
+      thesevalue = (*here).second;
+      
+      if (thesekey == constignore) 
+	{
+	  // do nothing, this is a placeholder
+	} 
+      else 
+	{
+	  pagevalueit = pageparams.find(thesekey);
+	  if ((pagevalueit != pageparams.end()) && 
+	      ((*pagevalueit).second == thesevalue)) 
+	    {
+	      // this parameter fits, add its precedence value
+	      precedit = precedhash.find(thesekey);
+	      if (precedit == precedhash.end()) 
+		specificness += 1.0; // no precedence defined
+	      else 
+		  specificness += (*precedit).second;
+	    }
+	  else 
+	    {
+	      return -1.0; // did not match
+	    }
+	}
+
+      ++here;
+    }
+  
+  return specificness;
+}
+
+
+void splitparams (const text_t &paramstring, paramhashtype &paramhash)
+{
+  text_t key;
+  text_t value;
+
+  text_t::const_iterator here, end;
+
+  // set paramhash to an empty hash
+  paramhash.erase(paramhash.begin(), paramhash.end());
+
+  // iterate through paramstring ignoring space and extracting
+  // out key value pairs.
+  here = paramstring.begin();
+  end  = paramstring.end();
+  while (here != end) 
+    {
+      // reset key and value
+      key.clear();
+      value.clear();
+
+      // get key
+      while (here != end) 
+	{
+	  if (*here == ',') 
+	    {
+	      // have a key with no value
+	      break;
+	    } 
+	  else if (*here == '=') 
+	    {
+	      // found the end of the key
+	      ++here; 
+	      break;
+	    } 
+	  else if (*here == ' ') 
+	    {
+	      // do nothing (ignore spaces)
+	    } 
+	  else 
+	    {
+	      // character in key
+	      key.push_back (*here); // copy this character
+	    }
+	  ++here;
+	}
+
+      // get value
+      while (here != end) 
+	{
+	  if (*here == '=') 
+	    {
+	      // multiple values for one key, ignore previous
+	      // values
+	      value.clear();
+	    } 
+	  else if (*here == ',') 
+	    {
+	      // found the end of the value
+	      ++here;
+	      break;
+	    } 
+	  else if (*here == ' ') 
+	    {
+	      // do nothing (ignore spaces)
+	    } 
+	  else 
+	    {
+	      // character in value
+	      value.push_back (*here); // copy this character
+	    }
+	  ++here;
+	}
+    
+      // if a key was found insert the key/value pair in 
+      // the map 
+      if (!key.empty()) 
+	{
+	  paramhash[key] = value;
+	}
+    }
+}
+
+
+void joinparams (const paramhashtype &paramhash, text_t &paramstring)
+{
+  //set paramstring to an empty string
+  paramstring.clear();
+
+  //iterate through the paramhash
+  paramhashtype::const_iterator thepair;
+  int firstparam = 1;
+
+  for (thepair=paramhash.begin();thepair!=paramhash.end(); ++thepair)
+    {
+      if (!firstparam) paramstring.push_back(',');
+      firstparam = 0;
+      
+      // insert pairs of "key=value"
+      text_t thevalue;
+      paramstring.append((*thepair).first);
+      paramstring.push_back('=');
+      paramstring.append((*thepair).second);
+    }
+}
+
+
+
+/////////////////////////////////////
+// parsing support functions
+/////////////////////////////////////
+
+inline int my_isalpha (unsigned short c) 
+{
+  return ((c >= 'A' && c <= 'Z') ||
+	  (c >= 'a' && c <= 'z'));
+} 
+
+inline int my_isalphanum (unsigned short c) 
+{
+  return ((c >= 'A' && c <= 'Z') ||
+	  (c >= 'a' && c <= 'z') || (c >='0' && c <= '9'));
+} 
+ 
+
+
+inline unsigned short my_ttnextchar (text_t::const_iterator &here, 
+				     text_t::const_iterator &end) 
+{
+  if (here != end) 
+    {
+      ++here;
+      if (here != end) return (*here);
+    }
+  return '\0';
+}
+
+
+
+/////////////////////////////////////
+// methods for display
+/////////////////////////////////////
+
+// public methods for display
+
+displayclass::displayclass ()
+{
+  defaultmacros    = new parammacros_t;
+  collectionmacros = new parammacros_t;
+  defaultfiles     = new fileinfomap;
+  
+  orderparamlist = new paramspeclist;
+  currentmacros = new currentmacros_t;
+
+  outc = NULL;
+
+  logout = NULL;
+
+  /* this is a bit of a hack, but if the displayclass has never seen this
+     parameter before when it does openpage() then macros with this set will
+     always be ignored. And we set collection-specific macros after doing
+     openpage() - jrm */
+  allparams.insert("l=en");
+}
+
+
+displayclass::~displayclass ()
+{
+  delete defaultmacros;
+  delete collectionmacros;
+  delete defaultfiles;
+  
+  delete orderparamlist;
+  delete currentmacros;
+}
+  
+// setdefaultmacro adds an entry to the list of default macros 
+// returns 0 if there was no error,
+//        -1 if it redefined a macro
+//        -2 if it hid a Global macro
+//        -3 if it redefined a macro and hid a Global macro
+//        -4 if no macroname was supplied
+int displayclass::setdefaultmacro (const text_t &package, const text_t &macroname, 
+				   const text_t &mparams, const text_t &macrovalue) 
+{
+  return setdefaultmacro (package, macroname, mparams, "memory", macrovalue);
+}
+
+
+
+// as we are using one character lookahead the
+// value of line might be off by one.
+// the input file must be in the utf-8 or unicode format
+// initially for each file isunicode should be set to 0 and 
+// bigendian should be set to 1
+// 0 will be returned when the end of the file has been found
+unsigned short my_uni_get (/*unistream*/ifstream &fin, int &line, 
+			   int &isunicode, int &bigendian) {
+  unsigned short c = 0;
+  
+  if (isunicode) {
+    // unicode text
+    // get the next two characters
+    unsigned char c1 = 0, c2 = 0;
+    
+    if (!fin.eof()) c1=fin.get();
+    if (!fin.eof()) c2=fin.get();
+    else c1 = 0;
+
+    // if they indicate the order get the next character
+    // otherwise just get these characters
+    if (c1 == 0xff && c2 == 0xfe) {
+      bigendian = 0;
+      c = my_uni_get (fin, line, isunicode, bigendian);
+    } else if (c1 == 0xfe && c2 == 0xff) {
+      bigendian = 1;
+      c = my_uni_get (fin, line, isunicode, bigendian);
+    } else c = (bigendian) ? (c1*256+c2) : (c2*256+c1);
+    
+  } else {
+    // utf-8 text
+    // how many characters we get depends on what we find
+    unsigned char c1 = 0, c2 = 0, c3 = 0;
+    while (!fin.eof()) {
+      c1=fin.get();
+      if (c1 == 0xfe || c1 == 0xff) {
+	// switch to unicode
+	isunicode = 1;
+	if (!fin.eof()) c2=fin.get();
+
+	if (c1 == 0xff && c2 == 0xfe) bigendian = 0;
+	else bigendian = 1;
+
+	c = my_uni_get (fin, line, isunicode, bigendian);
+	break;
+
+      } else if (c1 <= 0x7f) {
+	// one byte character
+	c = c1;
+	break;
+
+      } else if (c1 >= 0xc0 && c1 <= 0xdf) {
+	// two byte character
+	if (!fin.eof()) c2=fin.get();
+	c = ((c1 & 0x1f) << 6) + (c2 & 0x3f);
+	break;
+
+      } else if (c1 >= 0xe0 && c1 <= 0xef) {
+	// three byte character
+	if (!fin.eof()) c2=fin.get();
+	if (!fin.eof()) c3=fin.get();
+	c = ((c1 & 0xf) << 12) + ((c2 & 0x3f) << 6) + (c3 & 0x3f);
+	break;
+      }
+
+      // if we get here there was an error in the file, we should
+      // be able to recover from it however, maybe the file is in
+      // another encoding
+    }
+  }
+
+  if (c == '\n') ++line;
+  return c;
+}
+
+
+
+// loads a macro file into the specified macrotable datastructure
+// returns 0 if didn't need to load the file (it was already loaded)
+//         1 if was (re)loaded
+//        -1 an error occurred while trying to load the file
+int displayclass::loadparammacros (parammacros_t* macrotable, const text_t &thisfilename) {
+  // convert the filename to a C string
+  char *filenamestr = thisfilename.getcstr();
+  outconvertclass text_t2ascii;
+
+  // see if we need to open this file -- this isn't implemented yet
+  
+  // open the file
+  //  unistream fin (filenamestr);
+  ifstream fin (filenamestr);
+
+  if (fin.fail()) return -1; // read failed
+
+  text_t package = defaultpackage;
+  int line = 1;
+  int isunicode = 0, bigendian = 1;
+
+  // pre-fetch the next character
+  unsigned short c = my_uni_get(fin, line, isunicode, bigendian);
+
+  text_t macropackage, macroname, macroparameters, macrovalue;
+  int err; // for keeping track of whether an error occurred somewhere
+
+  while (!fin.eof()) {
+    // expect: white space, comment, "package", or macroname
+    if (is_unicode_space(c)) {
+      // found some white-space
+      c = my_uni_get(fin, line, isunicode, bigendian);
+
+    } else if (c == '#') {
+      // found the start of a comment
+      // skip all characters up to the end of the line
+      c = my_uni_get(fin, line, isunicode, bigendian); // skip the '#'
+      while (!fin.eof ()) {
+	if (c == '\n') break;
+	c = my_uni_get(fin, line, isunicode, bigendian);
+      }
+
+    } else if (c == 'p') {
+      // found the start of 'package' (hopefully)
+      // get everything up to the next space
+      text_t tmp;
+      while (!fin.eof() && my_isalpha(c)) {
+	tmp.push_back(c);
+	c = my_uni_get(fin, line, isunicode, bigendian);
+      }
+      // see if we have a package name
+      if (tmp == "package") {
+	// skip all white space
+	while (!fin.eof() && is_unicode_space(c)) 
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	
+	// get the package name
+	tmp.clear(); // init tmp
+	while (!fin.eof() && my_isalphanum(c)) {
+	  tmp.push_back(c);
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	}
+	package = tmp;
+	if (package.empty()) package = defaultpackage;
+
+      } else {
+	// error
+	if (logout != NULL) {
+	  (*logout) << text_t2ascii << text_t("Expected 'package' on line ") + line + text_t(" of ") + thisfilename + "\n";
+	}
+      }
+      
+    } else if (c == '_') {
+      // found the start of a macro (hopefully)
+      c = my_uni_get(fin, line, isunicode, bigendian); // skip the _
+
+      // init variables
+      err = 0;
+      macropackage = package;
+      macroname.clear(); // init macroname
+      macroparameters.clear(); // init macroname
+      macrovalue.clear(); // init macroname
+      
+      // get the macro name
+      while ((!fin.eof()) && (!is_unicode_space(c)) && 
+	     (c != '\\') && (c != '_') &&(c != ':') && 
+	     (macroname.size() < 80)) {
+	macroname.push_back(c);
+	c = my_uni_get(fin, line, isunicode, bigendian);
+      }
+	  
+      if (c == ':') {
+	// we actually had the macro package
+	c = my_uni_get(fin, line, isunicode, bigendian); // skip :
+	macropackage = macroname;
+	macroname.clear ();
+	
+	// get the macro name (honest!)
+	while ((!fin.eof()) && (!is_unicode_space(c)) && 
+	       (c != '\\') && (c != '_') &&(c != ':') && 
+	       (macroname.size() < 80)) {
+	  macroname.push_back(c);
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	}
+      }
+      
+      if (!err && c == '_') {
+	c = my_uni_get(fin, line, isunicode, bigendian); // skip the _
+	
+	// skip all white space
+	while (!fin.eof() && is_unicode_space(c)) c = my_uni_get(fin, line, isunicode, bigendian);
+      } else if (!err) err = 1;
+
+      // get the macro parameters (optional)
+      if (!err && c == '[') {
+	c = my_uni_get(fin, line, isunicode, bigendian); // skip the [
+	while ((!fin.eof()) && (c != '\n') && (c != '\\') && (c != ']')) {
+	  macroparameters.push_back(c);
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	}
+	
+	if (c == ']') {
+	  c = my_uni_get(fin, line, isunicode, bigendian); // skip the ]
+	  
+	  // skip all white space
+	  while (!fin.eof() && is_unicode_space(c)) c = my_uni_get(fin, line, isunicode, bigendian);
+	} 
+	else if (!err) err = 2;
+      }
+
+      // get the macro value
+      if (!err && c == '{') {
+	c = my_uni_get(fin, line, isunicode, bigendian); // skip the {
+	while ((!fin.eof()) && (c != '}')) {
+	  if (c == '\\') {
+	    macrovalue.push_back(c); // keep the '\'
+	    c = my_uni_get(fin, line, isunicode, bigendian); // store the *next* value regardless
+	    if (!fin.eof()) macrovalue.push_back(c);
+	    c = my_uni_get(fin, line, isunicode, bigendian);
+	  }
+	  macrovalue.push_back(c);
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	}
+	
+	if (c == '}') {
+	  c = my_uni_get(fin, line, isunicode, bigendian); // skip the }
+	  
+	  // define the macro
+	  err = setparammacro (macrotable, macropackage, macroname, macroparameters,
+			       thisfilename, macrovalue);
+	  if ((err == -1 || err == -3) && logout != NULL) {
+	    (*logout) << text_t2ascii << ("Warning: redefinition of _" + package + ":" + macroname + "_[" + macroparameters + "] on line " + line +  " of " + thisfilename + "\n");
+	    
+	  } else if (err == -2 && logout != NULL) {
+	    // I don't think we really want this warning since it's a very
+	    // common occurance - Stefan.
+
+	    //	    (*logout) << text_t2ascii << "Warning: _" << 
+	    //	      package << ":" << macroname << "_[" << macroparameters <<
+	    //	      "] on line ";
+	    //	    (*logout) << line;
+	    //	    (*logout) << text_t2ascii << " of " << 
+	    //	      thisfilename << " hides a Global macro with the same name\n";
+
+	  } else if (err == -4 && logout != NULL) {
+	    (*logout) << text_t2ascii << text_t("Error: macro name expected on line ") +  line + text_t(" of ") + thisfilename + "\n";
+	  }		  
+	  
+	  err = 0; // for the test below
+	}
+	else if (!err) err = 3;
+      }
+      else if (!err) err = 4;
+      
+      if (err) {
+	// found an error, skip to the end of the line
+	if (logout != NULL) {
+	  text_t message = "Error: ";
+	  if (err == 1) message += "'_'";
+	  else if (err == 2) message += "']'";
+	  else if (err == 3) message += "'}'";
+	  else if (err == 4) message += "'{'";
+	  message += " expected on line ";
+	  message += line;
+	  message += " of " + thisfilename + "\n";
+	  (*logout) << text_t2ascii << message;
+	  
+// 	  (*logout) << text_t2ascii << "Error: ";
+// 	  if (err == 1) (*logout) << text_t2ascii << "'_'";
+// 	  else if (err == 2) (*logout) << text_t2ascii << "']'";
+// 	  else if (err == 3) (*logout) << text_t2ascii << "'}'";
+// 	  else if (err == 4) (*logout) << text_t2ascii << "'{'";
+// 	  (*logout) << text_t2ascii << " expected on line ";
+// 	  (*logout) << line ;
+// 	  (*logout) << text_t2ascii << " of " << thisfilename << "\n";
+	}
+	while (!fin.eof ()) {
+	  if (c == '\n') break;
+	  c = my_uni_get(fin, line, isunicode, bigendian);
+	}
+      }
+      
+    } else {
+      // found an error, skip to the end of the line
+      if (logout != NULL) {
+	(*logout) << text_t2ascii << text_t("Error: Unexpected input on line ") + line + text_t(" of ") + thisfilename + "\n";
+      }
+      while (!fin.eof ()) {
+	if (c == '\n') break;
+	c = my_uni_get(fin, line, isunicode, bigendian);
+      }
+      
+    }
+  }
+  
+  fin.close ();
+  
+  // free up memory
+  delete []filenamestr;
+  return 0;
+}
+
+
+// loads a default macro file (if it isn't already loaded)
+// returns 0 if didn't need to load the file (it was already loaded)
+//         1 if was (re)loaded
+//        -1 an error occurred while trying to load the file
+int displayclass::loaddefaultmacros (const text_t &thisfilename) 
+{
+  return loadparammacros(defaultmacros,thisfilename);
+}
+
+// loads a collection specific macro file 
+// returns 0 if didn't need to load the file (it was already loaded)
+//         1 if was (re)loaded
+//        -1 an error occurred while trying to load the file
+int displayclass::loadcollectionmacros (const text_t &thisfilename) 
+{
+  return loadparammacros(collectionmacros,thisfilename);
+}
+
+
+void displayclass::unloaddefaultmacros () {
+  defaultmacros->clear();
+}
+
+void displayclass::unloadcollectionmacros () {
+  collectionmacros->clear();
+}
+
+// prepares to create a page.
+void displayclass::openpage (const text_t &thispageparams, 
+			const text_t &thisprecedence)
+{
+  // init variables
+  currentmacros->clear();
+
+  // reload any default macro files which have changed.
+  if (checkdefaultmacrofiles() < 0) 
+    {
+      // print error message
+    }
+
+  setpageparams (thispageparams, thisprecedence);
+}
+
+
+// changes the parameters for the current page.
+void displayclass::setpageparams (text_t thispageparams, 
+			     text_t thisprecedence)
+{
+  paramhashtype thissplitparams, splittheseparams;
+  precedencetype precedhash;
+  text_tset::iterator text_tsetit;
+  paramspec tmpps;
+
+  precedence = thisprecedence;
+  calcprecedence(thisprecedence, precedhash);
+
+  splitparams(thispageparams, thissplitparams);
+  joinparams(thissplitparams, thispageparams);
+  params = thispageparams;
+
+  // get a list of parameters with their specificness
+  orderparamlist->erase(orderparamlist->begin(), orderparamlist->end());
+  for (text_tsetit=allparams.begin();
+       text_tsetit!=allparams.end();
+       ++text_tsetit) 
+    {
+      tmpps.param = (*text_tsetit);
+      splitparams(tmpps.param, splittheseparams);
+      tmpps.spec = getspecificness(thissplitparams, splittheseparams, precedhash);
+      if (tmpps.spec >= 0) 
+	{
+	  orderparamlist->push_back (tmpps);
+	}
+    }
+
+  // sort the list
+  sort(orderparamlist->begin(), orderparamlist->end());
+
+#if 0 // debugging
+  outconvertclass text_t2ascii;
+
+  paramspeclist::iterator pshere = orderparamlist->begin();
+  paramspeclist::iterator psend = orderparamlist->end();
+  while (pshere != psend) 
+    {
+      cerr << text_t2ascii << "param=" << (*pshere).param;
+      cerr << " spec=" << (int)((*pshere).spec) << "\n";
+      ++pshere;
+    }
+#endif
+}
+
+
+// overrides (or sets) a macro for the current page.
+// returns 0 if there was no error,
+//        -1 if it redefined a macro
+//        -4 if no macroname was supplied
+int displayclass::setmacro (const text_t &macroname, 
+			    const text_t &package, 
+			    const text_t &macrovalue)
+{
+  // make sure a macroname was supplied
+  if (macroname.empty()) return -4;
+
+  // make package "Global" if it doesn't point to anything yet
+  if (package.empty()) 
+    return currentmacros->setmacro(defaultpackage, macroname, "memory", macrovalue);
+  
+  // set the macro
+  return currentmacros->setmacro(package, macroname, "memory", macrovalue);
+}
+
+int displayclass::setmacroif (const text_t &macro_to_set_and_test,
+			      const text_t &macro_to_set_if_macro_not_set, 
+			      const text_t &macroname, 	
+			      const text_t &package) {
+  
+  if (macroname.empty()) return -4;
+  if (macro_to_set_and_test.empty()) return -40;
+  
+  text_t temp;
+  expandstring(defaultpackage, macro_to_set_and_test, temp);
+  
+  if (package.empty()) {
+    if (temp == macro_to_set_and_test) return currentmacros->setmacro(defaultpackage, macroname, "memory", macro_to_set_if_macro_not_set);
+    return currentmacros->setmacro(defaultpackage, macroname, "memory", macro_to_set_and_test);
+  } else {
+    if (temp == macro_to_set_and_test) return currentmacros->setmacro(package, macroname, "memory", macro_to_set_if_macro_not_set);
+    return currentmacros->setmacro(package, macroname, "memory", macro_to_set_and_test);
+    
+  }
+}
+
+void displayclass::expandstring (const text_t &package, const text_t &inputtext,
+				 text_t &outputtext, int recursiondepth)
+{
+  text_t macroname, macropackage, macroargs;
+  text_t::const_iterator tthere = inputtext.begin();
+  text_t::const_iterator ttend = inputtext.end();
+  unsigned short c = '\0';
+  int openbrackets=0;
+
+  if (package.empty()) expandstring(defaultpackage, inputtext, outputtext, recursiondepth);
+
+  outputtext.clear();
+  // use one-character lookahead
+  if (tthere != ttend) c = (*tthere);
+  while (tthere != ttend) 
+    {
+      if (c == '\\')
+	{
+	  // found an escape character
+	  c = my_ttnextchar (tthere, ttend); // skip the escape character
+	  if (tthere != ttend) 
+	    {
+	      if (c == 'n') outputtext.push_back('\n');
+	      else if (c == 't') outputtext.push_back('\t');
+	      else outputtext.push_back(c);
+	    }
+	  c = my_ttnextchar (tthere, ttend);
+	  
+	} 
+      else if (c == '_') 
+	{
+	  // might have found the start of a macro
+      
+	  // embedded macros (macros within the names
+	  // of other macros) are no longer supported -- Rodger.
+      
+	  // save the current state (in case we need to back out)
+	  text_t::const_iterator savedtthere = tthere;
+	  unsigned short savedc = c;
+	  
+	  macroname.clear();
+	  macropackage = package;
+	  macroargs.clear();
+      
+	  c = my_ttnextchar (tthere, ttend); // skip the '_'
+	  
+	  // get the macroname
+	  while (tthere != ttend && (!is_unicode_space(c)) && 
+		 (c != '\\') && (c != '_') &&(c != ':') && 
+		 (macroname.size() < 80)) 
+	    {
+	      macroname.push_back((unsigned char)c);
+	      c = my_ttnextchar (tthere, ttend);
+	    }
+      
+	  if (c == ':') 
+	    {
+	      // we actually had the macro package
+	      c = my_ttnextchar (tthere, ttend);
+	      macropackage = macroname;
+	      macroname.clear ();
+	
+	      // get the macro name (honest!)
+	      while ((tthere != ttend) && (!is_unicode_space(c)) && 
+		     (c != '\\') && (c != '_') &&(c != ':') && 
+		     (macroname.size() < 80)) 
+		{
+		  macroname.push_back((unsigned char)c);
+		  c = my_ttnextchar (tthere, ttend);
+		}
+	    }
+      
+	  if ((tthere != ttend) && (c == '_') &&
+	      (macroname.size() > 0)) 
+	    {
+	      // found a macro!!!! (maybe)
+	      c = my_ttnextchar (tthere, ttend); // skip the '_'
+	
+	      // get the parameters (if there are any)
+	      if ((tthere != ttend) && (c == '(')) 
+		{
+		  c = my_ttnextchar (tthere, ttend); // skip '('
+	  	  ++openbrackets;
+		  // have to be careful of quotes
+		  unsigned short quote = '\0';
+		  while (tthere != ttend) 
+		    {
+		      if (c == '\\') 
+			{
+			  // have an escape character, save escape 
+			  // character and next character as well
+			  macroargs.push_back (c);
+			  c = my_ttnextchar (tthere, ttend); 
+	      
+			} 
+		      else if (quote == '\0') 
+			{
+			  // not in a quote at the moment
+			  if (c == '(')
+			    {
+			      ++openbrackets;
+////			      macroargs.push_back (c);
+////			      c = my_ttnextchar (tthere, ttend); 
+			    }
+			  else if (c == ')') 
+			    {
+			      --openbrackets;
+			      if (openbrackets==0) {
+				// found end of the arguments
+				c = my_ttnextchar (tthere, ttend); // skip ')'
+				break;
+			      } else {
+				// nested brackets
+			        macroargs.push_back (c);
+			        c = my_ttnextchar (tthere, ttend); 
+			      }
+			    } 
+			  else if (c == '\'' || c == '\"') 
+			    {
+			      // found a quote
+			      quote = c;
+			    }
+	      
+			} 
+		      else 
+			{
+			  // we are in a quote
+			  if (c == quote) quote = '\0';
+			}
+	    
+		      // save this character
+		      if (tthere != ttend) macroargs.push_back (c);
+		      c = my_ttnextchar (tthere, ttend);
+		    } // while (tthere != ttend)
+		}
+	
+	      //
+	      // we now have the macropackage, macroname, and macroargs
+	      //
+	
+	      // try to expand out this macro
+	      text_t expandedmacro;
+	      if (macro (macroname, macropackage.empty()?defaultpackage:macropackage, macroargs, expandedmacro, recursiondepth)) 
+		{
+		  // append the expanded macro
+		  outputtext += expandedmacro;
+		} 
+	      else
+		{
+		  // wasn't a macro
+		  tthere = savedtthere;
+		  c = savedc;
+		  outputtext.push_back(c); // the '_'
+		  c = my_ttnextchar (tthere, ttend);
+		}
+	
+
+	    }
+	  else
+	    {
+	      // wasn't a macro
+	      tthere = savedtthere;
+	      c = savedc;
+	      outputtext.push_back(c); // the '_'
+	      c = my_ttnextchar (tthere, ttend);
+	    }
+
+	}
+      else 
+	{
+	  // nothing of interest
+	  outputtext.push_back(c); // the '_'
+	  c = my_ttnextchar (tthere, ttend);
+	}
+    } // end of while (tthere != ttend)
+}
+
+ostream *displayclass::setlogout (ostream *thelogout) {
+
+  ostream *oldlogout = logout;
+  logout = thelogout;
+  return oldlogout;
+}
+
+// protected methods for display
+
+// reloads any default macro files which have changed
+// returns 0 no errors occurred
+//        -1 an error occurred while trying to load one of the files
+int displayclass::checkdefaultmacrofiles ()
+{
+  // this isn't implemented yet
+  return 0;
+}
+
+// isdefaultmacro sees if there is an entry in the list of
+// default macros with the given package and macro name
+// returns 0 if no macros in the package or in the global package
+//           were found
+//         1 if no macros in the package were found but a macro
+//           in the global package was found
+//         2 if a macro in the given package was found
+int displayclass::isdefaultmacro (const text_t &package, const text_t &macroname) {
+  // make sure a macroname was supplied
+  if (macroname.empty()) return 0;
+
+  if (!package.empty()) {
+    // check the given package
+    if (defaultmacros->macro_find(package, macroname) != NULL) return 2;
+  }
+    
+  // check the Global package
+  if (defaultmacros->macro_find(defaultpackage, macroname) != NULL) return 1;
+  // not found
+  return 0;
+}
+
+// havemacro sees if there is an entry in the list of macros or
+// default macros with the given package and macro name
+// returns 0 if no macros in the package or in the global package
+//           were found
+//         1 if no macros in the package were found but a macro
+//           in the global package was found
+//         2 if a macro in the given package was found
+//         4 if no macros in the package were found but a macro
+//           in the global package was found in default macros
+//         8 if a macro in the given package was found in default
+int displayclass::havemacro(const text_t &package, const text_t &macroname)
+{
+  // make sure a macroname was supplied
+  if (macroname.empty()) return 0;
+  
+  // make package "Global" if it doesn't point to anything yet
+  if (package.empty()) {
+    // check the Global package in current macros list
+    if (currentmacros->macro_find(defaultpackage, macroname) != NULL) return 1;
+    
+    // check the Global package in default macros list
+    if (defaultmacros->macro_find(defaultpackage, macroname) != NULL) return 4;
+  } else {
+    // check the given package in current macros list
+    if (currentmacros->macro_find(package, macroname) != NULL) return 2;
+    
+    // check the Global package in current macros list
+    if (currentmacros->macro_find(defaultpackage, macroname) != NULL) return 1;
+    
+    // check the given package in default macros list
+    if (defaultmacros->macro_find(package, macroname) != NULL) return 8;
+    
+    // check the Global package in default macros list
+    if (defaultmacros->macro_find(defaultpackage, macroname) != NULL) return 4;
+  }
+
+  // nothing was found
+  return 0;
+}
+  
+  
+// setparammacro adds an entry to the list of default macros 
+// returns 0 if there was no error,
+//        -1 if it redefined a macro
+//        -2 if it hid a Global macro
+//        -3 if it redefined a macro and hid a Global macro
+//        -4 if no macroname was supplied
+int displayclass::setparammacro (parammacros_t* macrotable, 
+				 const text_t &package, 
+				 const text_t &macroname, 
+				 text_t macroparams, 
+				 const text_t &filename,
+				 const text_t &macrovalue) 
+{
+  // make sure a macroname was supplied
+  if (macroname.empty()) return -4;
+
+  // put the parameters in a standard form
+  paramhashtype paramhash;
+  if (macroparams.empty()) macroparams = "ignore=yes";
+  splitparams (macroparams, paramhash);
+  joinparams (paramhash, macroparams);
+
+  // remember these parameters
+  allparams.insert (macroparams);
+
+  // remember this filename (this part isn't finished yet -- Rodger).
+
+  // set the macro
+  if (package.empty()) {
+    return macrotable->setmacro(defaultpackage, macroname, macroparams, filename, macrovalue);
+  } else {
+    return macrotable->setmacro(package, macroname, macroparams, filename, macrovalue);
+  }
+}
+
+// setdefaultmacro adds an entry to the list of default macros 
+// returns 0 if there was no error,
+//        -1 if it redefined a macro
+//        -2 if it hid a Global macro
+//        -3 if it redefined a macro and hid a Global macro
+//        -4 if no macroname was supplied
+int displayclass::setdefaultmacro (const text_t &package, 
+				   const text_t &macroname, 
+				   text_t macroparams, 
+				   const text_t &filename,
+				   const text_t &macrovalue) 
+{
+  return setparammacro(defaultmacros,package,macroname,
+		       macroparams,filename,macrovalue);
+}
+
+// public function
+int displayclass::setcollectionmacro(const text_t &package, 
+				     const text_t &macroname, 
+				     text_t mparams, 
+				     const text_t &macrovalue)
+{
+  return setcollectionmacro(package, macroname, mparams, "memory", macrovalue);
+}
+
+// setcollectionmacro adds an entry to the list of collection specific macros 
+// returns 0 if there was no error,
+//        -1 if it redefined a macro
+//        -2 if it hid a Global macro
+//        -3 if it redefined a macro and hid a Global macro
+//        -4 if no macroname was supplied
+int displayclass::setcollectionmacro (const text_t &package, 
+				      const text_t &macroname,
+				      text_t mparams, 
+				      const text_t &filename,
+				      const text_t &macrovalue) 
+{
+  return setparammacro(collectionmacros,package,macroname,mparams,
+		       filename,macrovalue);
+}
+
+
+// evaluates a boolean expression
+// returns false if expr equals "" or "0". 
+// otherwise returns true *unless* expr is 
+// format "XXXX" eq/ne "dddd" in which case
+// the two quoted strings are compared
+bool displayclass::boolexpr (const text_t &package, const text_t &expr, int recursiondepth) {
+
+  if (expr.empty()) return false;
+
+  text_t expexpr;
+  if (package.empty()) {
+    expandstring (defaultpackage, expr, expexpr, recursiondepth);
+  } else {
+    expandstring (package, expr, expexpr, recursiondepth);
+  }
+  if (expexpr.empty() || expexpr == "0") return false;
+  if (expr[0] != '\"') return true;
+
+  // don't use expexpr while separating quoted parts of
+  // expression just in case expanded out macros contain
+  // quotes
+  text_t::const_iterator here = expr.begin();
+  text_t::const_iterator end = expr.end();
+
+  int quotecount = 0;
+  text_t string1, expstring1;
+  text_t string2, expstring2;
+  text_t op;
+  text_t combineop;
+  bool result = false; // an empty string is false
+  bool result2 = false;
+
+  while (here != end) {
+    // get a comparison
+    quotecount = 0;
+    string1.clear();
+    string2.clear();
+    op.clear();
+    while (here != end) {
+      if (*here == '"') ++quotecount;
+      else if (quotecount == 1) string1.push_back(*here);
+      else if ((quotecount == 2) && !is_unicode_space (*here))
+	op.push_back(*here);
+      else if (quotecount == 3) string2.push_back(*here);
+      else if (quotecount >= 4) break;
+      ++here;
+    }
+    
+    expandstring (package, string1, expstring1, recursiondepth);
+    expandstring (package, string2, expstring2, recursiondepth);
+
+    // get next result
+    result2 = true; // any badly formatted string will return true
+    if (op == "eq") result2 = (expstring1 == expstring2);
+    else if (op == "ne") result2 = (expstring1 != expstring2);
+    else if (op == "gt") result2 = (expstring1 > expstring2);
+    else if (op == "ge") result2 = (expstring1 >= expstring2);
+    else if (op == "lt") result2 = (expstring1 < expstring2);
+    else if (op == "le") result2 = (expstring1 <= expstring2);
+    else if (op == "==") result2 = (expstring1.getint() == expstring2.getint());
+    else if (op == "!=") result2 = (expstring1.getint() != expstring2.getint());
+    else if (op == ">") result2 = (expstring1.getint() > expstring2.getint());
+    else if (op == ">=") result2 = (expstring1.getint() >= expstring2.getint());
+    else if (op == "<") result2 = (expstring1.getint() < expstring2.getint());
+    else if (op == "<=") result2 = (expstring1.getint() <= expstring2.getint());
+    else if (op == "sw") result2 = (starts_with(expstring1,expstring2));
+    else if (op == "ew") result2 = (ends_with(expstring1,expstring2));
+
+    // combine the results
+    if (combineop == "&&") result = (result && result2);
+    else if (combineop == "||") result = (result || result2);
+    else result = result2;
+
+    // get next combination operator
+    combineop.clear();
+    while (here != end && *here != '"') {
+      if (!is_unicode_space(*here)) combineop.push_back(*here);
+      ++here;
+    }
+  }
+
+  return result;
+}
+
+
+mvalue* displayclass::macro_find (parammacros_t* macrotable, 
+				  const text_t &packagename,
+				  const text_t &macroname)
+{
+  mvalue *macrovalue = NULL;
+
+  // next look in the named parammacros for the named package
+  if (macrotable->macro_find (packagename, macroname) != NULL)
+    {
+      paramspeclist::iterator paramhere, paramend;
+
+      paramhere = orderparamlist->begin(); paramend = orderparamlist->end();
+      while ((macrovalue == NULL) && (paramhere != paramend))
+	{
+	  macrovalue = macrotable->parameter_find(packagename, macroname,
+						  (*paramhere).param);
+	  ++paramhere;
+	}
+    }
+
+  return macrovalue;
+}
+
+
+// (recursively) expand out a macro
+// returns true  if the macro was found
+//         false if the macro was not found
+// macropackage should never be empty
+bool displayclass::macro (const text_t &macroname, 
+			  const text_t &macropackage, 
+			  const text_t &macroparam, 
+			  text_t &outputtext,
+			  int recursiondepth)
+{
+  assert(!macropackage.empty()); //???
+  //outconvertclass text_t2ascii;
+  text_tlist splitmacroparam;
+  text_t::const_iterator hereit, endit;
+  text_t aparam;
+  unsigned short c = '\0', quote = '\0';
+
+  //  cerr << "r: " << recursiondepth << "\n";
+  // check for deep recursion
+  if (recursiondepth >= MAXRECURSIONDEPTH)
+    {
+      if (logout != NULL)
+	(*logout) << "Warning: deep recursion, limiting macro expansion\n";
+      return false;
+    }
+
+  // check the macropackage
+  //if (macropackage.empty()) macropackage = "Global";
+
+  // get the parameters (but don't expand them)
+  if (macroparam.size() > 0) {
+    // set up for loop
+    hereit = macroparam.begin();
+    endit = macroparam.end();
+    if (hereit != endit) c = (*hereit);
+    int openbrackets=0; // keep track of bracket level eg _If_(1, _macro_(arg))
+			// this allows commas inside brackets (as arguments)
+    while (hereit != endit) {
+      // get the next parameter
+      aparam.clear();
+      quote = '\0'; // not-quoted unless proven quoted
+      
+      // ignore initial whitespace
+      while ((hereit!=endit)&&is_unicode_space(c)) c=my_ttnextchar(hereit,endit);
+      
+      // look for the end of the parameter
+      while (hereit != endit) {
+	if (c == '\\') {
+	  // found escape character, also get next character
+	  aparam.push_back(c);
+	  c = my_ttnextchar (hereit, endit);
+	  if (hereit != endit) aparam.push_back(c);
+	  
+	} else if (quote=='\0' && (c=='\'' /*|| c=='"'*/)) {
+	  // found a quoted section
+	  quote = c;
+	  if (openbrackets>0) aparam.push_back(c);
+
+	} else if (quote!='\0' && c==quote) {
+	  // found the end of a quote
+	  quote = '\0';
+	  if (openbrackets<0) aparam.push_back(c);
+
+	} else if (quote=='\0' && (c==',' || c==')') && openbrackets==0) {
+	  // found the end of a parameter
+	  c = my_ttnextchar (hereit, endit);
+	  break;
+
+	} else if (c=='(') {
+	  aparam.push_back(c);
+	  ++openbrackets;
+	} else if (c==')') {
+	  --openbrackets;
+	  aparam.push_back(c);
+	} else {
+	  // ordinary character
+	  aparam.push_back(c);
+	}
+
+	c = my_ttnextchar (hereit, endit);
+      }
+
+
+      // add this parameter to the list
+      splitmacroparam.push_back(aparam);
+    }
+  }
+
+  if (macroname == "If") {
+    // get the condition, then clause and else clause
+    text_tlist::iterator paramcond = splitmacroparam.begin();
+    text_tlist::iterator paramend = splitmacroparam.end();
+    text_tlist::iterator paramthen = paramend;
+    text_tlist::iterator paramelse = paramend;
+    
+    if (paramcond != paramend) {
+      paramthen = paramcond;
+      ++paramthen;
+    }
+    if (paramthen != paramend) {
+      paramelse = paramthen;
+      ++paramelse;
+    }
+    
+    // will always output something
+    outputtext.clear();
+
+
+    // expand out the first parameter
+    if (paramcond != paramend) {
+      /// text_t tmpoutput;
+      /// expandstring (macropackage, *paramcond, tmpoutput, recursiondepth+1);
+      /// lc (tmpoutput);
+      // test the expanded string
+      if (boolexpr (macropackage, *paramcond, recursiondepth+1)) {
+	//(tmpoutput.size()) && (tmpoutput != "false") && (tmpoutput != "0")) {
+	// true
+	if (paramthen != paramend)
+	  expandstring (macropackage, *paramthen, outputtext, recursiondepth+1);
+      } else {
+	// false
+	if (paramelse != paramend)
+	  expandstring (macropackage, *paramelse, outputtext, recursiondepth+1);
+      }
+    }
+    
+    return true;
+  }
+
+  // try and find this macro
+
+  // this list might be replaced by something a little more
+  // sophisticated in the future.
+  text_tlist packagelist;
+  packagelist.push_back (macropackage);
+  packagelist.push_back ("Global");
+
+  text_tlist::iterator packagehere = packagelist.begin();
+  text_tlist::iterator packageend = packagelist.end();
+  mvalue *macrovalue = NULL;
+  while (packagehere != packageend)
+    {
+      // first look in the currentmacros
+      macrovalue = currentmacros->macro_find(*packagehere, macroname);
+      if (macrovalue != NULL)
+	break;
+
+      macrovalue = currentmacros->macro_find("Style", macroname);
+      if (macrovalue != NULL)
+	break;
+
+      // look in the collection specific macros
+      macrovalue = macro_find(collectionmacros,*packagehere,macroname);
+      if (macrovalue != NULL)
+	break;
+
+      // and again in the collection specific package "Style"
+      macrovalue = macro_find(collectionmacros,(char*)"Style",macroname);
+      if (macrovalue != NULL)
+	break;
+
+      // look in the default macros
+      macrovalue = macro_find(defaultmacros,*packagehere,macroname);
+      if (macrovalue != NULL)
+	break;
+
+      // and again in the package "Style"
+      macrovalue = macro_find(defaultmacros,(char*)"Style",macroname);
+      if (macrovalue != NULL)
+	break;
+      ++packagehere;
+    }
+
+  if (macrovalue != NULL)
+    {
+      // we found a macro
+
+      // replace all the option macros (_1_, _2_, ...) in the value of this macro
+      // and decide if we need to expand the value of this macro
+      bool needsexpansion = false;
+      text_t tempmacrovalue;
+      tempmacrovalue.clear();
+      hereit = macrovalue->value.begin();
+      endit = macrovalue->value.end();
+      if (hereit != endit) c = (*hereit);
+      while (hereit != endit)
+	{
+	  if (c == '\\')
+	    {
+	      // found an escape character
+	      needsexpansion = true;
+	      tempmacrovalue.push_back(c);
+	      c = my_ttnextchar (hereit, endit);
+	      if (hereit != endit) tempmacrovalue.push_back(c);
+	      c = my_ttnextchar (hereit, endit);
+	    }
+	  else if (c == '_')
+	    {
+	      text_t::const_iterator savedhereit = hereit;
+
+	      // attempt to get a number
+	      int argnum = 0;
+	      unsigned short digc = my_ttnextchar (hereit, endit);
+	      while (digc >= '0' && digc <= '9') {
+		argnum = argnum*10 + digc - '0';
+		digc = my_ttnextchar (hereit, endit);
+	      }
+	      if (digc == '_' && argnum > 0) {
+		// found an option macro, append the appropriate text
+		text_tlist::iterator ttlisthere = splitmacroparam.begin();
+		text_tlist::iterator ttlistend = splitmacroparam.end();
+		while ((argnum > 1) && (ttlisthere != ttlistend)) {
+		  --argnum;
+		  ++ttlisthere;
+		}
+		if (ttlisthere != ttlistend) {
+		  tempmacrovalue.append(*ttlisthere);
+		  if (findchar((*ttlisthere).begin(), (*ttlisthere).end(), '_') != (*ttlisthere).end())
+		    needsexpansion = true;
+		}
+
+		c = my_ttnextchar (hereit, endit);
+
+	      } else {
+		// wasn't a option macro
+		needsexpansion = true;
+		tempmacrovalue.push_back(c);
+		hereit = savedhereit;
+		c = my_ttnextchar (hereit, endit);
+	      }
+	    }
+	  else
+	    {
+	      tempmacrovalue.push_back(c);
+	      c = my_ttnextchar (hereit, endit);
+	    }
+	}
+      
+      // recursively replace this macro (if we need to)
+      if (needsexpansion) {
+	expandstring (*packagehere, tempmacrovalue, outputtext, recursiondepth+1);
+      } else {
+	outputtext += tempmacrovalue;
+      }
+
+      return true;
+    }
+
+  // GRB: deal with remaining code properly as it faults
+  return false;
+  outconvertclass text_t2ascii;
+  if (logout != NULL) {
+    (*logout) << text_t2ascii << "Warning: _" << 
+      macropackage << ":" << macroname << "_ not found\n";
+  }
+  
+  return false; // didn't find the macro
+}
+
+
+void displayclass::printdefaultmacros ()
+{
+  defpackagemap::const_iterator packagemapit;
+  defmacromap::const_iterator macromapit;
+  defparammap::const_iterator parammapit;
+  const mvalue *mvalueptr;
+  outconvertclass text_t2ascii;
+
+  text_t packagename, macroname, macroparam;
+  
+  for (packagemapit = defaultmacros->package_begin();
+       packagemapit != defaultmacros->package_end();
+       ++packagemapit) 
+    {
+      packagename = (*packagemapit).first;
+      //     cerr << "***package   : \"" << packagename << "\"\n";
+    
+      for (macromapit = (*packagemapit).second.begin();
+	   macromapit != (*packagemapit).second.end();
+	   ++macromapit) 
+	{
+	  macroname = (*macromapit).first;
+	  //       cerr << "***macroname : \"" << macroname << "\"\n";
+
+	  for (parammapit = (*macromapit).second.begin();
+	       parammapit != (*macromapit).second.end();
+	       ++parammapit) 
+	    {
+	      macroparam = (*parammapit).first;
+	      mvalueptr = &((*parammapit).second);
+	      cerr << text_t2ascii << "package   : \"" << packagename << "\"\n";
+	      cerr << text_t2ascii << "macroname : \"" << macroname << "\"\n";
+	      cerr << text_t2ascii << "parameters: [" << macroparam << "]\n";
+	      cerr << text_t2ascii << "filename  : \"" << mvalueptr->filename << "\"\n";
+	      cerr << text_t2ascii << "value     : {" << mvalueptr->value << "}\n\n";
+	    }
+	}
+    }
+}
+
+void displayclass::printallparams ()
+{
+  text_tset::iterator text_tsetit;
+  outconvertclass text_t2ascii;
+
+  cerr << text_t2ascii << "** allparams\n";
+  for (text_tsetit=allparams.begin();
+       text_tsetit!=allparams.end();
+       ++text_tsetit) {
+    cerr << text_t2ascii << (*text_tsetit) << "\n";
+  }
+  cerr << text_t2ascii << "\n";
+}
+
+
+
+/////////////////////////////////////
+// stuff to do tricky output
+/////////////////////////////////////
+
+displayclass &operator<< (outconvertclass &theoutc, displayclass &display)
+{
+  display.setconvertclass (&theoutc);
+  return display;
+}
+
+displayclass &operator<< (displayclass &display, const text_t &t)
+{
+  outconvertclass *theoutc = display.getconvertclass();
+
+  if (theoutc == NULL) return display;
+  
+  text_t output;
+  display.expandstring (t, output);
+  (*theoutc) << output;
+
+  return display;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/lib/display.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/display.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/display.h	(revision 10506)
@@ -0,0 +1,341 @@
+/**********************************************************************
+ *
+ * display.h -- Context sensitive macro language
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef DISPLAY_H
+#define DISPLAY_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#  include <ospace\std\list>
+#  include <ospace\std\set>
+#  include <ospace\std\map>
+#  include <ospace\std\algorithm>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#  include <list.h>
+#  include <set.h>
+#  include <map.h>
+#  if defined(GSDL_USE_ALGO_H)
+#    include <algo.h>
+#  else
+#    include <algorithm.h>
+#  endif
+#else
+#  include <vector>
+#  include <list>
+#  include <set>
+#  include <map>
+#  include <algorithm>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+
+#define unistream ifstream
+#else
+#  include <iostream>
+#  include <fstream>
+
+typedef std::basic_ifstream<unsigned char> unistream;
+
+#endif
+
+
+// use the standard namespace
+#if defined(GSDL_USE_OBJECTSPACE)
+using namespace ospace::std;
+#elif !defined(GSDL_NAMESPACE_BROKEN)
+using namespace std;
+#endif
+
+
+
+// MAXRECURSIONDEPTH is a cutoff to catch
+// cyclic macros (a includes b and b includes a)
+#define MAXRECURSIONDEPTH 30
+
+// class prototypes
+class parammacros_t;
+class currentmacros_t;
+
+// a few supporting types
+// fileelement isn't finished yet, I have to find out
+// more about getting information about files
+struct fileinfoelement 
+{
+  int otherinfo;
+};
+
+// macro value structure
+struct mvalue
+{
+  text_t filename;
+  text_t value;
+};
+
+inline bool operator==(const fileinfoelement &x, const fileinfoelement &y) {
+  return (x.otherinfo==y.otherinfo);
+}
+
+inline bool operator<(const fileinfoelement &x, const fileinfoelement &y) {
+  return (x.otherinfo<y.otherinfo);
+}
+
+typedef map<text_t, fileinfoelement, lttext_t> fileinfomap;
+
+
+typedef map<text_t, text_t, lttext_t> paramhashtype;
+void splitparams (const text_t &paramstring, paramhashtype &paramhash);
+
+
+struct paramspec 
+{
+  double spec;
+  text_t param;
+};
+
+inline bool operator==(const paramspec& x, const paramspec& y) 
+{
+  return ((x.spec == y.spec) && (x.param == y.param));
+}
+
+inline bool operator!=(const paramspec& x, const paramspec& y) 
+{
+  return ((x.spec != y.spec) || (x.param != y.param));
+}
+
+// note: paramspec is sorted by reverse spec and then param
+
+inline bool operator<(const paramspec& x, const paramspec& y) 
+{
+  return ((x.spec > y.spec) ||
+	  ((x.spec == y.spec) && (x.param < y.param)));
+}
+
+inline bool operator>(const paramspec& x, const paramspec& y) 
+{
+  return ((x.spec < y.spec) ||
+	  ((x.spec == y.spec) && (x.param > y.param)));
+}
+
+typedef vector<paramspec> paramspeclist;
+
+
+
+// NOTE: when macros are used within text they should have
+// underscores '_' on both sides, however, in calls to
+// setdefaultmacro and setmacro they should not have the
+// underscores. So you might have
+//
+// setmacro ("aname", "query", " some text ");
+// expandstring ("_aname_", expandedtext);
+//
+// because the input to expandstring is a block of text, not
+// a macroname
+
+class displayclass 
+{
+public:
+  static text_t defaultpackage;
+
+  displayclass ();
+  ~displayclass ();
+  
+  // isdefaultmacro sees if there is an entry in the list of
+  // default macros with the given package and macro name
+  // returns 0 if no macros in the package or in the global package
+  //           were found
+  //         1 if no macros in the package were found but a macro
+  //           in the global package was found
+  //         2 if a macro in the given package was found
+  int isdefaultmacro (const text_t &package, const text_t &macroname);
+
+  // setdefaultmacro adds an entry to the list of default macros 
+  // returns 0 if there was no error,
+  //        -1 if it redefined a macro
+  //        -2 if it hid a Global macro
+  //        -3 if it redefined a macro and hid a Global macro
+  //        -4 if no macroname was supplied
+  int setdefaultmacro (const text_t &package, 
+		       const text_t &macroname, 
+		       const text_t &params, 
+		       const text_t &macrovalue);
+  
+  // loads a default macro file (if it isn't already loaded)
+  // returns 0 if didn't need to load the file (it was already loaded)
+  //         1 if was (re)loaded
+  //        -1 an error occurred while trying to load the file
+  int loaddefaultmacros (const text_t &thisfilename);
+
+
+  // overrides (or sets) a macro for the current page.
+  // returns 0 if there was no error,
+  //        -1 if it redefined a macro
+  //        -4 if no macroname was supplied
+  int setcollectionmacro (const text_t &package, 
+			  const text_t &macroname, 
+			  text_t params, 
+			  const text_t &macrovalue);
+
+  // loads a collection specific macro file 
+  // returns 0 if didn't need to load the file (it was already loaded)
+  //         1 if was (re)loaded
+  //        -1 an error occurred while trying to load the file
+  int loadcollectionmacros (const text_t &thisfilename);
+
+  // unloads all default macros
+  void unloaddefaultmacros ();
+
+  // unloads all collection specific macros
+  void unloadcollectionmacros ();
+  
+  // prepares to create a page: deletes all macros set with
+  // 'setmacro', checks all the default macro files to see
+  // if any need reloading, and sets the page parameters.
+  void openpage (const text_t &thispageparams, 
+		 const text_t &thisprecedence);
+  
+  // changes the parameters for the current page.
+  void setpageparams (text_t thispageparams, 
+		      text_t thisprecedence);
+  
+  // overrides (or sets) a macro for the current page.
+  // returns 0 if there was no error,
+  //        -1 if it redefined a macro
+  //        -4 if no macroname was supplied
+  int setmacro (const text_t &macroname, 
+		const text_t &package, 
+		const text_t &macrovalue);
+  
+// havemacro sees if there is an entry in the list of macros or
+// default macros with the given package and macro name
+// returns 0 if no macros in the package or in the global package
+//           were found
+//         1 if no macros in the package were found but a macro
+//           in the global package was found
+//         2 if a macro in the given package was found
+//         4 if no macros in the package were found but a macro
+//           in the global package was found in default macros
+//         8 if a macro in the given package was found in default
+  int havemacro(const text_t &package, const text_t &macroname);
+
+  int setmacroif (const text_t &macro_to_set_and_test, 
+		  const text_t &macro_to_set_if_macro_not_set,
+		  const text_t &macroname, 
+		  const text_t& package);
+  
+  inline void expandstring (const text_t &inputtext, text_t &outputtext) { expandstring(defaultpackage, inputtext, outputtext); }
+
+  void expandstring (const text_t &package, const text_t &inputtext,
+		     text_t &outputtext, int recursiondepth = 0);
+
+  // these functions are not ment to be used directly, they are used to permit 
+  // concise stream output like:
+  // cout << text_t2ascii << display << "_amacro_" << "_anothermacro_";
+  void setconvertclass (outconvertclass *theoutc) {outc = theoutc;}
+  outconvertclass *getconvertclass () {return outc;}
+
+  // say where any error logging goes, this can be NULL
+  // if no error logging is desired - returns previous value
+  ostream *displayclass::setlogout (ostream *thelogout);
+
+  // debug stuff
+  void printdefaultmacros ();
+  void printallparams ();
+
+protected:
+  // special variables to permit trickly output
+  outconvertclass *outc;
+
+  // general variables
+  text_tset        allparams;  // possible parameter combinations
+  parammacros_t *defaultmacros;
+  parammacros_t *collectionmacros;
+  fileinfomap     *defaultfiles;
+  
+  // variables to do with a page expansion
+  text_t params;
+  text_t precedence;
+  paramspeclist *orderparamlist; // ordered by specificness
+  currentmacros_t *currentmacros; // only macros set by setmacro
+
+  // logging variable
+  ostream *logout;
+
+  // reloads any default macro files which have changed
+  // returns 0 no errors occurred
+  //        -1 an error occurred while trying to load one of the files
+  int checkdefaultmacrofiles ();
+
+  int loadparammacros (parammacros_t* macrotable, const text_t &thisfilename);
+
+  int setparammacro (parammacros_t* macrotable,
+		     const text_t &package, 
+		     const text_t &macroname, 
+		     text_t params, const text_t &filename,
+		     const text_t &macrovalue); 
+
+  int setdefaultmacro (const text_t &package, 
+		       const text_t &macroname, 
+		       text_t params, const text_t &filename,
+		       const text_t &macrovalue); 
+
+  int setcollectionmacro(const text_t &package, 
+			 const text_t &macroname, 
+			 text_t params, 
+			 const text_t &filename,
+			 const text_t &macrovalue); 
+  
+  // evaluates a boolean expression
+  bool boolexpr (const text_t &package, const text_t &expr, 
+		 int recursiondepth);
+
+  mvalue* macro_find (parammacros_t* macrotable, 
+		      const text_t &packagename,
+		      const text_t &macroname);
+
+  // (recursively) expand out a macro
+  // returns true  if the macro was found
+  //         false if the macro was not found
+  bool macro (const text_t &macroname, 
+	      const text_t &macropackage, 
+	      const text_t &macroparam, text_t &outputtext,
+	      int recursiondepth);
+};
+
+
+displayclass &operator<< (outconvertclass &theoutc, displayclass &display);
+displayclass &operator<< (displayclass &display, const text_t &t);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/fileutil.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/fileutil.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/fileutil.cpp	(revision 10506)
@@ -0,0 +1,446 @@
+/**********************************************************************
+ *
+ * fileutil.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "fileutil.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+
+// returns the proper concatenation of the two paths
+text_t filename_cat (text_t path1, text_t path2) {
+  text_t::iterator here;
+  text_t::iterator begin;
+  text_t::iterator end;
+
+  // make sure there is just one slash, of the correct type,
+  // at the end of path1 (unless path1 is an empty string).
+  if (!path1.empty()) {
+    // remove all trailing slashes
+    here = path1.end();
+    --here;
+    begin = path1.begin();
+    while (here != begin && (*here == '/' || *here == '\\')) {
+      --here;
+    }
+    ++here;
+    path1.erase(here,path1.end());
+    
+    // add one final slash
+#ifdef __WIN32__
+    path1 += "\\";
+#else
+    path1 += "/";
+#endif 
+  }
+
+  // remove all slashes from the start of path2
+  here = path2.begin();
+  end = path2.end();
+  while (here != end && (*here == '/' || *here == '\\')) {
+    ++here;
+  }
+  path2.erase (path2.begin(), here);
+  
+  text_t fullpath = path1 + path2;
+  
+  // make sure all the right slashes are used
+  here = fullpath.begin();
+  end = fullpath.end();
+  while (here != end) {
+#ifdef __WIN32__
+    if (*here == '/') *here = '\\';
+#else
+    if (*here == '\\') *here = '/';
+#endif
+    ++here ;
+  }
+  return fullpath;
+}
+
+text_t filename_cat (text_t path1, text_t path2, text_t path3) {
+  return filename_cat(filename_cat(path1,path2),path3);
+}
+
+text_t filename_cat (text_t path1, text_t path2, text_t path3, text_t path4) {
+  return filename_cat(filename_cat(filename_cat(path1,path2),path3),path4);
+}
+
+text_t filename_cat (text_t path1, text_t path2, text_t path3, text_t path4, 
+		     text_t path5) {
+  return filename_cat(filename_cat(filename_cat(filename_cat(path1,path2),path3),
+				   path4),path5);
+}
+
+text_t filename_cat (text_t path1, text_t path2, text_t path3, text_t path4, 
+		     text_t path5, text_t path6) {
+  return filename_cat(filename_cat(path1,path2,path3,path4,path5),path6);
+}
+
+// returns true if filename can be opened
+bool file_exists (const text_t &filename) {
+  char *cstr = filename.getcstr();
+#ifdef GSDL_USE_IOS_H
+  ifstream filestream (cstr, ios::in | ios::nocreate);
+#else
+  ifstream filestream (cstr, ios::in);
+#endif
+  delete []cstr;
+  
+  if (filestream) {
+    // file exists
+    filestream.close ();
+    return true;
+  }
+  
+  // file does not exist
+  return false;
+}
+
+// returns true if filename can be opened
+bool file_writable (const text_t &filename) {
+  char *cstr = filename.getcstr();
+#ifdef GSDL_USE_IOS_H
+  ifstream filestream (cstr, ios::out | ios::nocreate);
+#else
+  ifstream filestream (cstr, ios::out);
+#endif
+  delete []cstr;
+  
+  if (filestream) {
+    // file exists
+    filestream.close ();
+    return true;
+  }
+  
+  // file does not exist
+  return false;
+}
+
+#if defined(__WIN32__) && !defined(__GNUC__)
+
+#include <windows.h>
+
+bool directory_exists (const text_t &dirname) {
+  
+  WIN32_FIND_DATA FileData;  
+  HANDLE hSearch; 
+
+  text_t dir = dirname + "\\*";
+  char *dirpath = dir.getcstr();
+  
+  hSearch = FindFirstFile(dirpath, &FileData);
+  if (hSearch == INVALID_HANDLE_VALUE) {
+    delete []dirpath;
+    return false;
+  }
+
+  FindClose (hSearch);
+  delete []dirpath;
+  return true;
+}
+
+bool read_dir (const text_t &dirname, text_tset &filelist) {
+  
+  WIN32_FIND_DATA FileData;  
+  HANDLE hSearch; 
+  
+  text_t dir = dirname + "\\*";
+  char *dirpath = dir.getcstr();
+  
+  hSearch = FindFirstFile(dirpath, &FileData); 
+  if (hSearch == INVALID_HANDLE_VALUE) {
+    delete []dirpath;
+    return false;
+  }
+  
+  text_t filename = FileData.cFileName;
+  if (filename != "." && filename != ".." && filename != "CVS")
+    filelist.insert (filename); 
+  
+  while (FindNextFile(hSearch, &FileData)) {
+    filename = FileData.cFileName;
+    if (filename == "." || filename == ".." || filename == "CVS")
+      continue;
+    filelist.insert (filename); 
+  }
+  
+  FindClose(hSearch);
+  delete []dirpath;
+  
+  return true;
+}
+
+bool read_dir (const text_t &dirname, text_tarray &filelist) {
+  
+  WIN32_FIND_DATA FileData;  
+  HANDLE hSearch; 
+  
+  text_t dir = dirname + "\\*";
+  char *dirpath = dir.getcstr();
+  
+  hSearch = FindFirstFile(dirpath, &FileData); 
+  if (hSearch == INVALID_HANDLE_VALUE) {
+    delete []dirpath;
+    return false;
+  }
+  
+  text_t filename = FileData.cFileName;
+  if (filename != "." && filename != ".." && filename != "CVS")
+    filelist.push_back (filename); 
+  
+  while (FindNextFile(hSearch, &FileData)) {
+    filename = FileData.cFileName;
+    if (filename == "." || filename == ".." || filename == "CVS")
+      continue;
+    filelist.push_back (filename); 
+  }
+  
+  FindClose(hSearch);
+  delete []dirpath;
+
+  return true;
+}
+
+#else
+
+#include <dirent.h>
+
+bool directory_exists (const text_t &dirname) {
+  
+  char *tmp = dirname.getcstr();
+  DIR *dirin = opendir (tmp);
+  delete []tmp;
+  
+  if (dirin == NULL) return false;
+  closedir (dirin);
+  return true;
+}
+
+bool read_dir (const text_t &dirname, text_tset &filelist) {
+  
+  char *tmp = dirname.getcstr();
+  DIR *dirin = opendir (tmp);
+  delete []tmp;
+  
+  if (dirin == NULL) return false;
+  
+  dirent *dirp; 
+  
+  text_t filename;
+  while ((dirp = readdir (dirin)) != NULL) {
+    filename = dirp->d_name;
+    if (filename == "." || filename == ".." || filename == "CVS")
+      continue;
+    filelist.insert (filename);
+  }
+  closedir (dirin);
+  return true;
+}
+
+bool read_dir (const text_t &dirname, text_tarray &filelist) {
+  
+  char *tmp = dirname.getcstr();
+  DIR *dirin = opendir (tmp);
+  delete []tmp;
+  
+  if (dirin == NULL) return false;
+  
+  dirent *dirp; 
+  
+  text_t filename;
+  while ((dirp = readdir (dirin)) != NULL) {
+    filename = dirp->d_name;
+    if (filename == "." || filename == ".." || filename == "CVS")
+      continue;
+    filelist.push_back (filename);
+  }
+  closedir (dirin);
+  return true;
+}
+
+#endif
+
+// returns true if things look like they happened ok
+bool file_copy (const text_t &fromfile, const text_t &tofile) {
+  
+  char *fromfilec = fromfile.getcstr();
+  char *tofilec = tofile.getcstr();
+  bool fail = false;
+
+#ifdef __WIN32__
+  if (CopyFile (fromfilec, tofilec, FALSE) == 0) fail = true;
+
+#else
+
+  ifstream from (fromfilec);
+  if (!from) {
+    fail = true;
+  } else {
+    ofstream to (tofilec);
+    if (!to) {
+      fail = true;
+      from.close();
+    } else {
+      from >> to.rdbuf();
+      from.close();
+      to.close();
+    }
+  }
+
+#endif
+
+  delete []fromfilec;
+  delete []tofilec;
+  if (fail) return false;
+  return true;
+}
+
+// This is a fairly quick and nasty attempt at doing a "tail" on a file
+// (i.e. returning the last numlines lines of filename).  It has one
+// important limitation in that it expects lines to be linelength
+// characters long on average.  This of course makes it possible that it
+// won't return numlines lines if there are some lines that are longer than
+// linelength.  It also makes it fairly inefficient as it always reads in
+// numlines*linelength characters when it most often doesn't need them all.
+// For current needs it's fine though.
+// -- Pass a linelength of 0 to use the default linelength (256 chars).
+// -- The maximum value of linelength is MAXLINELENGTH
+text_t file_tail (const text_t &filename, int numlines, int linelength) {
+
+#define MAXLINELENGTH 2048
+
+  if (numlines < 1) numlines = 1;
+  if (linelength < 1) linelength = 256;
+  if (linelength > MAXLINELENGTH) linelength = MAXLINELENGTH;
+
+  streampos numchars = linelength*numlines;
+
+  text_tarray lines;
+  text_t ret;
+
+  char *filenamec = filename.getcstr();
+  char linec[MAXLINELENGTH];
+  ifstream file_in (filenamec);
+  delete []filenamec;
+  if (file_in) {
+    file_in.seekg (0, ios::end);
+    streampos file_length = file_in.tellg();
+    if (file_length < numchars) numchars = file_length;
+    file_in.seekg (-numchars, ios::end);
+
+    while (!file_in.eof()) {
+      file_in.getline (linec, linelength);
+      ret.setcstr(linec);
+      text_t::const_iterator here = ret.begin();
+      text_t::const_iterator end = ret.end();
+      // make sure line has content
+      while (here != end) {
+	if (*here != '\n' && *here != ' ') {
+	  lines.push_back (ret);
+	  break;
+	}
+	++here;
+      }
+    }
+    file_in.close();
+  }
+
+  ret.clear();
+  int numlinesgot = lines.size();
+  int sindex = 0;
+  if (numlinesgot > numlines) sindex = numlinesgot - numlines;
+  for (int i = sindex; i < numlinesgot; ++i) {
+    ret += lines[i] + "\n";
+  }
+
+  return ret;
+}
+
+#ifdef __WIN32__
+
+#include <direct.h>
+// returns true if directory was created successfully
+bool mk_dir (const text_t &dirname) {
+  char *dirnamec = dirname.getcstr();
+  int rv = _mkdir (dirnamec);
+  delete []dirnamec;
+  if (rv == 0) return true;
+  return false;
+}
+
+#else
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+// returns true if directory was created successfully
+bool mk_dir (const text_t &dirname) {
+  mode_t mode = 0777;
+  char *dirnamec = dirname.getcstr();
+  int rv = mkdir (dirnamec, mode);
+  delete []dirnamec;
+  if (rv == 0) return true;
+  return false;
+}
+
+#endif
+
+// read in file from filename and load into content
+bool read_file (const text_t &filename, text_t &content) {
+
+  content.clear();
+
+  char *filenamec = filename.getcstr();
+#ifdef GSDL_USE_IOS_H
+  ifstream file_in (filenamec, ios::in | ios::nocreate);
+#else
+  ifstream file_in (filenamec, ios::in);
+#endif
+  delete []filenamec;
+
+  if (file_in) {
+    char c;
+    file_in.get(c);
+    while (!file_in.eof ()) {
+      // Casting c to an unsigned char is vital when reading non-ASCII documents
+      content.push_back((unsigned char) c);
+      file_in.get(c);
+    }
+    file_in.close();
+  } else {
+    return false;
+  }
+  return true;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/lib/fileutil.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/fileutil.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/fileutil.h	(revision 10506)
@@ -0,0 +1,65 @@
+/**********************************************************************
+ *
+ * fileutil.h -- a few useful file utilities
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef FILEUTIL_H
+#define FILEUTIL_H
+
+#include "text_t.h"
+
+
+// returns the proper concatenation of the two paths
+text_t filename_cat (text_t path1, text_t path2);
+text_t filename_cat (text_t path1, text_t path2, text_t path3);
+text_t filename_cat (text_t path1, text_t path2, text_t path3, text_t path4);
+text_t filename_cat (text_t path1, text_t path2, text_t path3, text_t path4, 
+		     text_t path5);
+text_t filename_cat (text_t path1, text_t path2, text_t path3, text_t path4, 
+		     text_t path5, text_t path6);
+
+// returns true if filename can be opened
+bool file_exists (const text_t &filename);
+
+// returns true if filename can be written to
+bool file_writable (const text_t &filename);
+
+// returns true if directory exists
+bool directory_exists (const text_t &dirname);
+
+// note that read_dir appends to filelist, it doesn't clear
+// it first
+bool read_dir (const text_t &dirname, text_tarray &filelist);
+bool read_dir (const text_t &dirname, text_tset &filelist);
+
+bool file_copy (const text_t &fromfile, const text_t &tofile);
+
+text_t file_tail (const text_t &filename, int numlines, int linelength);
+
+// returns true if directory created successfully
+bool mk_dir (const text_t &dirname);
+
+bool read_file (const text_t &filename, text_t &content);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/gsdlconf.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/gsdlconf.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/gsdlconf.h	(revision 10506)
@@ -0,0 +1,161 @@
+/**********************************************************************
+ *
+ * gsdlconf.h -- system specific includes
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef GSDLCONF_H
+#define GSDLCONF_H
+
+#define GSDL_VERSION "x.xx"
+
+#if defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_) || defined(WIN32)
+#ifndef __WIN32__
+#define __WIN32__ 1
+#endif
+#endif
+
+#if defined(__WIN32__) && !defined(__CYGWIN__)
+#include "../win32cfg.h"
+#else
+#include "../config.h"
+#endif
+
+// Note: all macros used in the gsdl software (except the _H macros) should
+// now start with GSDL_
+
+// GSDL_NEED_STRINGS_H should be defined if some string functions
+// needed (like strcasecmp) are in strings.h
+#if defined(__IBMCPP__)
+#  define GSDL_NEED_STRINGS_H
+#endif
+
+// GSDL_USE_IOS_H should be defined if the .h extension needs to
+// be used for the io stream headers
+#if (defined(__GNUG__)  && __GNUG__ + 0 < 3) || defined(__IBMCPP__)
+#  define GSDL_USE_IOS_H 1
+#endif
+
+// GSDL_USE_STL_H should be defined if the .h extension needs to
+// be used for the stl header files
+#if defined(__IBMCPP__)
+#  define GSDL_USE_STL_H 1
+#endif
+
+// GSDL_USE_ALGO_H should be defined if algo.h should be used 
+// instead of algorithm.h
+#if defined(__IBMCPP__)
+#  define GSDL_USE_ALGO_H 1
+#endif
+
+// GSDL_NAMESPACE_BROKEN should be defined if namespaces should
+// not be used
+#if (defined(__GNUG__)  && __GNUG__ + 0 < 3) || defined(__IBMCPP__)
+#  define GSDL_NAMESPACE_BROKEN 1
+#endif
+
+// GSDL_USE_OBJECTSPACE should now be used instead of USE_OBJECTSPACE
+#if defined(USE_OBJECTSPACE)
+#  define GSDL_USE_OBJECTSPACE
+#endif
+
+// GSDL_NEED_DESTROY_USHORT should be defined if the compiler needs
+// a definition for void destroy(short unsigned int *)
+#if defined(__IBMCPP__)
+# define GSDL_NEED_DESTROY_USHORT
+#endif
+
+// mktemp
+
+#if !defined(__WIN32__) || defined(__GNUC__)
+#include <unistd.h>
+#define GSDL_MKTEMP(str) mktemp(str)
+#else
+#include <io.h>
+#define GSDL_MKTEMP(str) _mktemp(str)
+#endif
+
+
+
+// file locking
+
+#if defined(__WIN32__)
+
+#if !defined(LK_UNLOCK) && defined(LK_UNLCK)
+#define LK_UNLOCK LK_UNLCK
+#endif
+
+#include <io.h>
+#include <sys/locking.h>
+
+#define GSDL_UNLOCK_FILE(fd) _locking(fd, LK_UNLCK, 200)
+#define GSDL_LOCK_FILE(fd) lock_val = _locking(fd, LK_NBLCK, 200)
+
+#else     /* not WIN32 */
+
+#if GSDL_USE_FLOCK
+#include <sys/lock.h>
+
+#ifndef LOCK_SH
+#define LOCK_SH	1
+#endif
+
+#ifndef LOCK_EX
+#define LOCK_EX	2
+#endif
+
+#ifndef LOCK_NB
+#define LOCK_NB 4
+#endif
+
+#ifndef LOCK_UN
+#define LOCK_UN 8
+#endif
+
+#define GSDL_UNLOCK_FILE(fd) flock (fd, LOCK_UN)
+#define GSDL_LOCK_FILE(fd) lock_val = flock (fd, LOCK_EX + LOCK_NB)
+
+#else  /* ! GSDL_USE_FLOCK */
+// use fcntl
+#include <fcntl.h>
+#define GSDL_UNLOCK_FILE(fd) \
+	{					\
+	  struct flock flock;			\
+	  flock.l_type = F_UNLCK;		\
+	  flock.l_whence = SEEK_SET;		\
+	  flock.l_start = flock.l_len = 0L;	\
+	  fcntl (fd, F_SETLK, &flock);	\
+	}
+#define GSDL_LOCK_FILE(fd) \
+	{					\
+	  struct flock flock;			\
+	  flock.l_type = F_WRLCK;		\
+	  flock.l_whence = SEEK_SET;			\
+	  flock.l_start = flock.l_len = 0L;	\
+	  lock_val = fcntl (fd, F_SETLK, &flock);	\
+	}
+
+#endif
+#endif
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/gsdltimes.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/gsdltimes.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/gsdltimes.cpp	(revision 10506)
@@ -0,0 +1,163 @@
+/**********************************************************************
+ *
+ * gsdltimes.cpp -- functions to deal with time
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdltimes.h"
+
+// returns a string of the form "YYYY/MM/DD hh:mm:ss" (expressed in
+// Coordinated Universal Time (UTC))
+// returns "" if an error occurs
+// !! Actually, we now return a string in localtime, as text2time returns
+//    a time in localtime (mktime assumes local timezone). - jrm21 Sep 2002
+text_t time2text (time_t time) {
+  // tm *tm_ptr = gmtime(&time);
+  tm *tm_ptr = localtime(&time);
+
+  if (tm_ptr == NULL) return g_EmptyText;
+
+  // year
+  text_t timestr(tm_ptr->tm_year+1900);
+  timestr.push_back('/');
+
+  // month (note the +1)
+  if ((tm_ptr->tm_mon+1) < 10) timestr.push_back('0');
+  timestr += (tm_ptr->tm_mon+1);
+  timestr.push_back('/');
+
+  // day
+  if (tm_ptr->tm_mday < 10) timestr.push_back('0');
+  timestr += tm_ptr->tm_mday;
+  timestr.push_back(' ');
+
+  // hour
+  if (tm_ptr->tm_hour < 10) timestr.push_back('0');
+  timestr += tm_ptr->tm_hour;
+  timestr.push_back(':');
+
+  // minutes
+  if (tm_ptr->tm_min < 10) timestr.push_back('0');
+  timestr += tm_ptr->tm_min;
+  timestr.push_back(':');
+
+  // seconds
+  if (tm_ptr->tm_sec < 10) timestr.push_back('0');
+  timestr += tm_ptr->tm_sec;
+
+  return timestr;
+}
+
+// takes a string like that returned by time2text and returns corresponding time_t
+// returns -1 if an error occurs
+time_t text2time (const text_t &timestr) {
+  tm timetm;
+  text_t tempstr;
+  
+  text_t::const_iterator time_here = timestr.begin();
+  text_t::const_iterator time_end = timestr.end();
+
+  // year
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, '/', tempstr);
+  timetm.tm_year = tempstr.getint() - 1900;
+  if (timetm.tm_year < 0) return (time_t) -1;
+
+  // month (note the -1)
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, '/', tempstr);
+  timetm.tm_mon = tempstr.getint() - 1;
+  if (timetm.tm_mon < 0 || timetm.tm_mon > 11)
+    return (time_t) -1;
+  
+  // day
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, ' ', tempstr);
+  timetm.tm_mday = tempstr.getint();
+  if (timetm.tm_mday < 1 || timetm.tm_mday > 31)
+    return (time_t) -1;
+  
+  // hour
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, ':', tempstr);
+  timetm.tm_hour = tempstr.getint();
+  if (timetm.tm_hour < 0 || timetm.tm_hour > 23)
+    return (time_t) -1;
+  
+  // min
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, ':', tempstr);
+  timetm.tm_min = tempstr.getint();
+  if (timetm.tm_min < 0 || timetm.tm_min > 59)
+    return (time_t) -1;
+  
+  // sec
+  if (time_here == time_end) return (time_t) -1;
+  time_here = getdelimitstr (time_here, time_end, ':', tempstr);
+  timetm.tm_sec = tempstr.getint();
+  if (timetm.tm_sec < 0 || timetm.tm_sec > 59)
+    return (time_t) -1;
+
+  timetm.tm_isdst=0;
+
+  /* This is for darwin - mktime seems to use this, so don't leave it
+     uninitialised!! Maybe the same on freebsd/netbsd?
+  */
+#if defined(__MACH__) && defined(__APPLE__)
+  timetm.tm_gmtoff=0;
+#endif
+
+  // mktime assumes timetm is localtime
+  return mktime (&timetm);
+}
+
+// returns current date and time formatted like "Thu Dec 07 23:43:38 GMT 2000"
+// if ltime is true return value will be expressed in local time, otherwise
+// it'll be Coordinated Universal Time (UTC) - no promises are made that the
+// resulting string will be formatted exactly as expected, especially on windows
+// returns "" if an error occurs
+text_t get_date (bool ltime) {
+
+  tm *tm_ptr = NULL;
+  time_t t = time(NULL);
+  if (ltime) tm_ptr = localtime (&t);
+  else tm_ptr = gmtime (&t);
+  if (tm_ptr == NULL) return g_EmptyText;
+  char *timestr = new char[128];
+  text_t ret;
+
+  // we do this in such an ugly way because windows is kind of flakey when
+  // it comes to timezones
+  if (ltime) {
+    strftime (timestr, 128, "%a %b %d %H:%M:%S %z %Y", tm_ptr);
+    ret.setcstr (timestr);
+  } else {
+    strftime (timestr, 128, "%a %b %d %H:%M:%S", tm_ptr);
+    ret.setcstr (timestr);
+    ret += " GMT ";
+    strftime (timestr, 128, "%Y", tm_ptr);
+    ret += timestr;
+  }
+
+  delete []timestr;
+  return ret;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/lib/gsdltimes.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/gsdltimes.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/gsdltimes.h	(revision 10506)
@@ -0,0 +1,46 @@
+/**********************************************************************
+ *
+ * gsdltimes.h -- functions to deal with time
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef GSDLTIMES_H
+#define GSDLTIMES_H
+
+#include <time.h>
+#include "text_t.h"
+
+// dates are stored in the format YYYY/MM/DD hh:mm:ss
+
+// returns "" if an error occurs
+text_t time2text (time_t time);
+
+// returns -1 if an error occurs
+time_t text2time (const text_t &timestr);
+
+
+// returns formatted date in local or UTC time
+// returns "" if an error occurs
+text_t get_date (bool ltime);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/gsdltools.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/gsdltools.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/gsdltools.cpp	(revision 10506)
@@ -0,0 +1,171 @@
+/**********************************************************************
+ *
+ * gsdltools.cpp -- 
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdltools.h"
+
+#if defined(__WIN32__)
+#include <windows.h>
+#include <process.h>
+#endif
+
+bool littleEndian() {
+  char s[2] = {'\xFE', '\xEF'};
+
+  if (sizeof(unsigned short) == 2)
+    return *(unsigned short*)s == 0xEFFE;
+  else if (sizeof(unsigned int) == 2)
+    return *(unsigned int*)s == 0xEFFE;
+}
+
+text_t dm_safe (const text_t &instring) {
+
+  text_t outstring;
+  text_t::const_iterator here = instring.begin();
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (*here == '_' || *here == '\\') outstring.push_back('\\');
+    outstring.push_back(*here);
+    ++here;
+  }
+  return outstring;
+}
+
+void dm_js_safe(const text_t &instring, text_t &outstring)
+{
+  text_t::const_iterator here = instring.begin();
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (*here == '_') outstring.push_back('\\');
+    else if (*here == '\\' || *here == '\'') {
+      outstring.push_back('\\');
+      outstring.push_back('\\');
+    }
+    outstring.push_back(*here);
+    ++here;
+  }
+}
+
+// gsdl_system creates a new process for the cmd command (which
+// may contain arguments).
+// cmd should contain the full path of the program to run.
+// The child process inherits the environment of the calling
+// process.
+// If sync is true a synchronous call will be made, otherwise
+// an asyncronous call.
+// If sync is true the return value will be the exit code of
+// the child process or -1 if the child process wasn't started.
+// If sync is false the return value will be 0 if the process
+// was started ok or -1 if it failed.
+int gsdl_system (const text_t &cmd, bool sync, ostream &logout) {
+  if (cmd.empty()) return -1;
+  char *cmd_c = cmd.getcstr();
+
+#if defined (__WIN32__)
+  // the windows version - this is implemented this way
+  // to prevent windows popping up all over the place when
+  // we call a console application (like perl)
+  STARTUPINFO ps = {sizeof(STARTUPINFO), NULL, NULL, NULL,
+                    0, 0, 0, 0, 0, 0,
+                    0, STARTF_USESHOWWINDOW,
+                    SW_HIDE, 0, NULL,
+		    NULL, NULL, NULL};
+  PROCESS_INFORMATION pi;
+  BOOL res = CreateProcess(NULL,
+                           cmd_c,
+                           NULL,
+                           NULL,
+                           FALSE,
+#if defined (GSDL_LOCAL_LIBRARY)
+			   NULL,
+#else
+			   DETACHED_PROCESS,
+#endif
+                           NULL,
+                           NULL,
+                           &ps,
+                           &pi);
+  if (!res) {
+    logout << "gsdl_system failed to start " << cmd_c 
+	   << " process, error code " << GetLastError();
+    delete []cmd_c;
+    return -1;
+  } 
+
+  DWORD ret = 0;
+  if (sync) { // synchronous system call
+    // wait until child process exits.
+    WaitForSingleObject(pi.hProcess, INFINITE);
+    // set ret to exit code of child process
+    GetExitCodeProcess(pi.hProcess, &ret);
+  }
+
+  CloseHandle(pi.hProcess);
+  CloseHandle(pi.hThread);
+
+#else
+  // the unix version
+  int ret = 0;
+  if (sync) { // synchronous system call
+    // make sure the command interpreter is found
+    if (system (NULL) == 0) {
+      logout << "gsdl_system failed to start " << cmd_c
+	     << " process, command interpreter not found\n";
+      delete []cmd_c;
+      return -1;
+    }
+    ret = system (cmd_c);
+
+  } else { // asynchronous system call
+    int pid = fork();
+    if (pid == -1) {
+      delete []cmd_c;
+      return -1;
+    }
+    if (pid == 0) {
+      // child process
+      char *argv[4];
+      argv[0] = "sh";
+      argv[1] = "-c";
+      argv[2] = cmd_c;
+      argv[3] = 0;
+      execv("/bin/sh", argv);
+    }
+  }
+#endif
+
+  delete []cmd_c;
+  return ret;
+}
+
+// attempts to work out if perl is functional
+bool perl_ok (ostream &logout) {
+#if defined(__WIN32__)
+  text_t cmd = "perl -e \"exit 0\"";
+#else 
+  text_t cmd = "perl -e 'exit 0'";
+#endif
+  int i = gsdl_system (cmd, true, logout);
+  return (i == 0);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/lib/gsdltools.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/gsdltools.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/gsdltools.h	(revision 10506)
@@ -0,0 +1,77 @@
+/**********************************************************************
+ *
+ * gsdltools.h -- 
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef GSDLTOOLS_H
+#define GSDLTOOLS_H
+
+// don't actually use this but some windows
+// versions of STL complain about use of 
+// bool keyword without it
+#include "text_t.h"
+
+// returns true if machine is little endian
+bool littleEndian();
+
+// escapes '\' and '_' characters with '\'
+// note that single '\' characters occurring 
+// naturally within text (or filenames!!) will
+// be removed by the dm macro language
+text_t dm_safe (const text_t &instring);
+
+// escapes "\", "'" and "_" characters with '\'
+// note that single '\' characters occurring 
+// naturally within text (or filenames!!) will
+// be removed by the dm macro language
+//WARNING: instring will be appended to outstring
+// so is your responsability to clean the outstring
+// before call this function;
+void dm_js_safe(const text_t &instring, text_t &outstring);
+inline text_t dm_js_safe (const text_t &instring) {text_t outstring; dm_js_safe(instring, outstring); return outstring;}
+
+// gsdl_system creates a new process for the cmd command (which
+// may contain arguments).
+// cmd should contain the full path of the program to run.
+// The child process inherits the environment of the calling
+// process.
+// If sync is true a synchronous call will be made, otherwise
+// an asyncronous call.
+// If sync is true the return value will be the exit code of
+// the child process or -1 if the child process wasn't started.
+// If sync is false the return value will be 0 if the process
+// was started ok or -1 if it failed.
+int gsdl_system (const text_t &cmd, bool sync, ostream &logout);
+
+// attempts to work out if perl is functional
+bool perl_ok (ostream &logout);
+
+#endif
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/lib/gsdlunicode.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/gsdlunicode.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/gsdlunicode.cpp	(revision 10506)
@@ -0,0 +1,671 @@
+/**********************************************************************
+ *
+ * gsdlunicode.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdlunicode.h"
+
+
+// unitool is currently in mg, if mg is not being used it should
+// be moved into GSDLHOME/lib 
+#include "unitool.h"
+
+#include "fileutil.h"
+
+#include <stdio.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+
+// converts a unicode encode text_t string to a utf-8
+// encoded text_t string
+text_t to_utf8 (text_t::const_iterator here, text_t::const_iterator end) {
+  text_t out;
+
+  unsigned char thischar[MAXUTF8CHARLEN];
+  int i, charlen;
+
+  while (here != end) {
+    charlen = output_utf8_char (*here, thischar, &thischar[MAXUTF8CHARLEN-1]);
+    for (i=0; i<charlen; ++i) out.push_back(thischar[i]);
+    ++here;
+  }
+
+  return out;
+}
+
+// converts a utf-8 encoded text_t string to a unicode
+// encoded text_t string
+text_t to_uni (const text_t &in) {
+  text_t out;
+  unsigned char *in_cstr = (unsigned char *)in.getcstr();
+  unsigned char *here = in_cstr;
+  unsigned char *end = in_cstr;
+
+  unsigned short unichar;
+  int charlen = 0;
+
+  // get the last valid character in the string
+  while (*end != '\0') ++end;
+  --end;
+
+  while ((charlen = parse_utf8_char (here, end, &unichar)) > 0) {
+    out.push_back(unichar);
+    here += charlen;
+  }
+
+  delete []in_cstr;
+
+  return out;
+}
+
+
+// this works for all unicode values < 65536...
+void utf16outconvertclass::convert (char *out, size_t maxlen, size_t &len, status_t &status) {
+  // we should already have text_t* input set...
+  if (input == NULL || out == NULL)
+  {
+    status = finished;
+    return;
+  }
+  unsigned char *output = (unsigned char *)out;
+  text_t::iterator textend = input->end();
+  len = 0;
+  if (maxlen % 2) --maxlen; // we need an even number of output bytes...
+  while ((len < maxlen) && (texthere != textend)) {
+    unsigned short int uni_char=(unsigned short int) *texthere;
+    // big endian utf-16...
+    if (uni_char < 256) {
+      out[len]=0;   
+      out[len+1]=uni_char;
+    } else {
+      out[len]=uni_char >> 8;
+      out[len+1]=uni_char & 255;
+    }
+    len+=2;
+    ++texthere;
+  }
+  if (texthere==textend)
+    status=finished;
+  else
+    status=unfinished;
+}
+
+
+utf8inconvertclass::utf8inconvertclass () {
+  utf8buflen = 0;
+}
+
+void utf8inconvertclass::reset () {
+  start = NULL;
+  len = 0;
+  utf8buflen=0;
+}
+
+void utf8inconvertclass::convert (text_t &output, status_t &status) {
+  output.clear();
+  output.reserve (len/3);
+  
+  if (start == NULL || len == 0) {
+    if (utf8buflen == 0) status = finished;
+    else status = stopped;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *here = (unsigned char *)start;
+  unsigned char *end = here+len-1;
+  unsigned short c;
+  size_t realcharlen;
+
+  size_t charlen = getutf8charlen ();
+  while (len > 0) {
+    if (charlen == 0) {
+      // start parsing a new character
+      utf8buflen = 0;
+
+      // fast common case
+      while (len > 3) {
+  	realcharlen = parse_utf8_char (here, end, &c);
+  	output.push_back (c);
+  	here += realcharlen;
+  	len -= realcharlen;
+      }
+
+      utf8buf[utf8buflen++] = *here;
+      ++here;
+      --len;
+      charlen = getutf8charlen ();
+
+    } else if (utf8buflen < charlen) {
+      // assumes charlen is always less than MAXUTF8CHARLEN
+      utf8buf[utf8buflen++] = *here;
+      ++here;
+      --len;
+    }
+
+    if (utf8buflen == charlen) {
+      // got a complete character
+      realcharlen = parse_utf8_char (utf8buf, &utf8buf[utf8buflen-1], &c);
+      output.push_back (c);
+      
+      // move any unparsed characters. If an error occurred some of
+      // the characters might be unused.
+      int i;
+      int diff = utf8buflen - realcharlen;
+      for (i=0; i < diff; ++i) utf8buf[i] = utf8buf[i+diff];
+      utf8buflen = diff;
+      charlen = getutf8charlen ();
+    }
+  }
+
+  start = (char *)here; // save current position
+
+  if (utf8buflen == 0) status = finished;
+  else status = stopped;
+}
+
+
+// returns the length that the current contents of the 
+// utf8buf should be
+size_t utf8inconvertclass::getutf8charlen () {
+  if (utf8buflen == 0) return 0;
+
+  // one byte character
+  if (utf8buf[0] < 0x80) return 1;
+
+  // error, is not the start of a utf-8 character
+  if (utf8buf[0] < 0xc0) return 1;
+
+  // two bute character
+  if (utf8buf[0] < 0xe0) return 2;
+
+  // three byte character
+  if (utf8buf[0] < 0xf0) return 3;
+
+  // error, character too long for unicode
+  return 1;
+}
+
+
+void utf8outconvertclass::reset () {
+  input = NULL;
+  outs = NULL;
+  utf8buflen = 0;
+  utf8bufhere = 0;
+}
+
+// note that convert does not null-terminate the
+// output array of characters
+void utf8outconvertclass::convert (char *output, size_t maxlen, 
+				   size_t &len, status_t &status) {
+  if (input == NULL || output == NULL) {
+    if (utf8buflen == 0) status = finished;
+    else status = unfinished;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *uoutput = (unsigned char *)output;
+  text_t::iterator textend = input->end();
+  len = 0;
+  while (len < maxlen) {
+    // empty the contents of the internal buffer
+    if (utf8buflen > 0) {
+      while (len < maxlen && utf8bufhere < utf8buflen) {
+	*uoutput = utf8buf[utf8bufhere];
+	++uoutput;
+	++len;
+	++utf8bufhere;
+      }
+
+      if (utf8bufhere == utf8buflen) {
+	utf8bufhere = 0;
+	utf8buflen = 0;
+      }
+    }
+
+    // fill up the buffer with the next character
+    if (utf8buflen == 0) {
+      if (texthere == textend) break; // finished!
+      if (!rzws || (*texthere != 0x200b))
+	utf8buflen = output_utf8_char (*texthere, utf8buf, 
+				       &utf8buf[MAXUTF8CHARLEN-1]);
+      ++texthere;
+      utf8bufhere = 0;
+    }
+  }
+  
+  if (texthere == textend && utf8buflen == 0) status = finished;
+  else status = unfinished;
+}
+
+
+
+
+
+
+mapdata_t::mapdata_t () {
+
+  // reset all the map ptrs to be NULL
+  for (int i=0; i<256; ++i) {
+    ptrs[i] = (unsigned short *)NULL;
+  }
+
+  // say nothing has been loaded
+  loaded = false;
+}
+
+
+mapconvert::mapconvert () {
+  absentc = 0;
+}
+
+// setmapfile will cause loadmapfile to be called when conversion is
+// needed
+bool mapconvert::setmapfile (const text_t &themapfile, unsigned short theabsentc) {
+  // check to see if the mapfile has been already loaded
+  if (mapdata.loaded && mapfile == themapfile && absentc == theabsentc) return true;
+
+  unloadmapfile ();
+  mapfile = themapfile;
+  absentc = theabsentc;
+  
+  return true;
+}
+
+
+
+// loadmapfile should be called before any conversion is done
+bool mapconvert::loadmapfile (const text_t &themapfile,
+			      unsigned short theabsentc) {
+  FILE *mapfilein = (FILE *)NULL;
+
+  // check to see if the mapfile has been already loaded
+  if (mapdata.loaded && mapfile == themapfile && absentc == theabsentc) return true;
+
+  unloadmapfile ();
+  mapfile = themapfile;
+  absentc = theabsentc;
+
+  // open the map file
+  char *cfilename = mapfile.getcstr();
+  if (cfilename == (char *)NULL) return false;
+  mapfilein = fopen(cfilename, "rb");
+  delete []cfilename; cfilename = NULL;
+
+  if (mapfilein == (FILE *)NULL) return false;
+
+  unsigned char c, n1, n2;
+  unsigned short *arrptr;
+  int i;
+  c = fgetc (mapfilein);
+  while (!feof (mapfilein)) {
+    if (mapdata.ptrs[c] == (unsigned short *)NULL) {
+      // allocate a new array
+      arrptr = new unsigned short[256];
+      mapdata.ptrs[c] = arrptr;
+    } else arrptr = mapdata.ptrs[c];
+
+    // clear the array
+    for (i=0; i<256; ++i) arrptr[i] = 0;
+    
+    // read in this block
+    n1 = fgetc (mapfilein);
+    n2 = fgetc (mapfilein);
+    i=0;
+    while (!feof (mapfilein)) {
+      arrptr[i] = ((unsigned short)n1 << 8) | (unsigned short)n2;
+
+      ++i;
+      if (i >= 256) break;
+      n1 = fgetc (mapfilein);
+      n2 = fgetc (mapfilein);
+    }
+
+    c = fgetc (mapfilein);
+  }
+
+  mapdata.loaded = true;
+
+  return true;
+}
+
+void mapconvert::unloadmapfile () {
+  if (!mapdata.loaded) return;
+
+  for (int i=0; i<256; ++i) {
+    if (mapdata.ptrs[i] != (unsigned short *)NULL) {
+      delete [] mapdata.ptrs[i];
+      mapdata.ptrs[i] = (unsigned short *)NULL;
+    }
+  }
+
+  mapdata.loaded = false;
+}
+
+
+unsigned short mapconvert::convert (unsigned short c) {
+  if (!mapdata.loaded) {
+    if (!mapfile.empty() && loadmapfile (mapfile, absentc)) {
+      // do nothing, successfully loaded database
+    } else return absentc;
+  }
+
+  if (c == 0) return 0; // 0 always maps to 0...
+
+  unsigned short n1 = c >> 8;
+  unsigned short n2 = c & 0xff;
+
+  unsigned short *arrptr = mapdata.ptrs[n1];
+  if (arrptr == (unsigned short *)NULL) return absentc;
+
+  if (arrptr[n2] == 0) return absentc;
+  return arrptr[n2];
+}
+
+text_t mapconvert::convert (const text_t &instr) {
+  if (!mapdata.loaded) return absentc;
+
+  text_t outstr;
+  text_t::const_iterator here = instr.begin();
+  text_t::const_iterator end = instr.end();
+
+  while (here != end) {
+    outstr.push_back(this->convert(*here));
+    ++here;
+  }
+  
+  return outstr;
+}
+
+
+
+
+mapinconvertclass::mapinconvertclass () {
+  m_multibyte = 0;
+  mapbuflen = 0;
+}
+
+void mapinconvertclass::reset () {
+  start = NULL;
+  len = 0;
+  mapbuflen=0;
+}
+
+void mapinconvertclass::convert (text_t &output, status_t &status) {
+  output.clear();
+
+  if (start == NULL || len == 0) {
+    if (mapbuflen == 0) status = finished;
+    else status = stopped;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *here = (unsigned char *)start;
+
+  size_t charlen = getmapcharlen ();
+  while (len > 0) {
+    if (charlen == 0) {
+      // start parsing a new character
+      mapbuflen = 0;
+      mapbuf[mapbuflen++] = *here;
+      ++here;
+      --len;
+      charlen = getmapcharlen ();
+
+    } else if (mapbuflen < charlen) {
+      // assumes charlen is always less than MAXMAPCHARLEN
+      mapbuf[mapbuflen++] = *here;
+      ++here;
+      --len;
+    }
+
+    if (mapbuflen == charlen) {
+      // got a complete character
+      if (charlen == 1) {
+	if (mapbuf[0] < 0x80) {
+	  // ascii character
+	  output.push_back (mapbuf[0]);
+	} else {
+	  output.push_back (converter.convert((unsigned short)mapbuf[0]));
+	}
+
+      } else {
+	// two byte character
+	output.push_back (converter.convert(((unsigned short)mapbuf[0] << 8) |
+					    (unsigned short)mapbuf[1]));
+      }
+
+      mapbuflen = 0;
+      charlen = 0;
+    }
+  }
+
+  start = (char *)here; // save current position
+
+  if (mapbuflen == 0) status = finished;
+  else status = stopped;
+}
+
+
+
+mapoutconvertclass::mapoutconvertclass () {
+  m_multibyte = 0;
+  mapbuflen=0; 
+  mapbufhere=0;
+}
+
+void mapoutconvertclass::reset () {
+  input = NULL;
+  outs = NULL;
+  mapbuflen = 0;
+  mapbufhere = 0;
+}
+
+// note that convert does not null-terminate the
+// output array of characters
+void mapoutconvertclass::convert (char *output, size_t maxlen, 
+				 size_t &len, status_t &status) {
+  unsigned short outc;
+
+  if (input == NULL || output == NULL) {
+    if (mapbuflen == 0) status = finished;
+    else status = unfinished;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *uoutput = (unsigned char *)output;
+  text_t::iterator textend = input->end();
+  len = 0;
+  while (len < maxlen) {
+    // empty the contents of the internal buffer
+    if (mapbuflen > 0) {
+      while (len < maxlen && mapbufhere < mapbuflen) {
+	*uoutput = mapbuf[mapbufhere];
+	++uoutput;
+	++len;
+	++mapbufhere;
+      }
+
+      if (mapbufhere == mapbuflen) {
+	mapbufhere = 0;
+	mapbuflen = 0;
+      }
+    }
+
+    // fill up the buffer with the next character
+    if (mapbuflen == 0) {
+      if (texthere == textend) break; // finished!
+      if (!rzws || (*texthere != 0x200b)) {
+	if (*texthere < 0x80) {
+	  mapbuf[0] = (unsigned char)*texthere;
+	  mapbuflen = 1;
+	} else {
+	  outc = converter.convert (*texthere);
+	  if (m_multibyte) {
+	    mapbuf[0] = (unsigned char)(outc >> 8);
+	    mapbuf[1] = (unsigned char)(outc & 0xff);
+	    mapbuflen = 2;
+	  } else {
+	    mapbuf[0] = outc;
+	    mapbuflen = 1;
+	  }
+	}
+      }
+
+      ++texthere;
+      mapbufhere = 0;
+    }
+  }
+  
+  if (texthere == textend && mapbuflen == 0) status = finished;
+  else status = unfinished;
+}
+
+
+bool simplemapconvert::loadmapfile (bool in) {
+  if (loaded) return true;
+  if (mapfile.empty()) return false;
+
+  char *cfilename = mapfile.getcstr();
+#ifdef GSDL_USE_IOS_H
+  ifstream mapfilein (cfilename, ios::in | ios::nocreate);
+#else
+  ifstream mapfilein (cfilename, ios::in);
+#endif
+  delete []cfilename;
+  if (!mapfilein) return false;
+
+  char cline[2048];
+  text_t line;
+
+  while (!mapfilein.eof()) {
+    mapfilein.getline (cline, 2048);
+    line.clear();
+    line.appendcstr (cline);
+    if (line.empty()) continue;
+    // remove comments
+    text_t::iterator end = line.end();
+    text_t::iterator here = findchar (line.begin(), end, '#');
+    if (here != end) {
+      line.erase (here, end);
+      if (line.empty()) continue;
+    }
+    
+    text_tarray parts;
+    splitchar (line.begin(), line.end(), '\t', parts);
+    
+    // do some simple sanity checks
+    if (parts.size() < 2) continue;
+    text_t::iterator begin1 = parts[0].begin();
+    text_t::iterator begin2 = parts[1].begin();
+    if (*begin1 != '0' || *(begin1+1) != 'x') continue;
+    if (*begin2 != '0' || *(begin2+1) != 'x') continue;
+    char *from = parts[0].getcstr();
+    char *to = parts[1].getcstr();
+    unsigned int f = 0, t = 0;
+    sscanf (from, "%i", &f);
+    sscanf (to, "%i", &t);
+    delete []from;
+    delete []to;
+    
+    if (in) mapping[(unsigned short)f] = (unsigned short)t;
+    else mapping[(unsigned short)t] = (unsigned short)f;
+  }
+
+  loaded = true;
+  return true;
+}
+
+unsigned short simplemapconvert::convert (unsigned short c, bool in) {
+
+  if (!loaded) 
+    if (!loadmapfile(in)) return absentc;
+  
+  return mapping[c];
+}
+
+
+void simplemapinconvertclass::convert (text_t &output, status_t &status) {
+  output.clear();
+  
+  if (start == NULL || len == 0) {
+    status = finished;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *here = (unsigned char *)start;
+  while (len > 0) {
+
+    if (*here < 0x80)
+      output.push_back (*here); // append this character
+    else 
+      output.push_back (converter.convert(*here, true));
+
+    ++here;
+    --len;
+  }
+
+  start = (char *)here; // save current position
+  status = finished;
+}
+
+
+void simplemapoutconvertclass::convert (char *output, size_t maxlen, 
+					size_t &len, status_t &status) {
+
+  if (input == NULL || output == NULL) {
+    status = finished;
+    return;
+  }
+
+  // don't want any funny sign conversions happening
+  unsigned char *uoutput = (unsigned char *)output;
+  text_t::iterator textend = input->end();
+  len = 0;
+  while ((len < maxlen) && (texthere != textend)) {
+
+    if (*texthere < 0x80) *uoutput = (unsigned char)(*texthere);
+    else *uoutput = converter.convert (*texthere, false);
+
+    ++uoutput;
+    ++len;
+    ++texthere;
+  }
+  
+  if (texthere == textend) status = finished;
+  else status = unfinished;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/lib/gsdlunicode.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/gsdlunicode.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/gsdlunicode.h	(revision 10506)
@@ -0,0 +1,277 @@
+/**********************************************************************
+ *
+ * gsdlunicode.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef GSDLUNICODE_H
+#define GSDLUNICODE_H
+
+#include "text_t.h"
+
+
+// converts a unicode encode text_t string to a utf-8
+// encoded text_t string
+text_t to_utf8 (text_t::const_iterator here, text_t::const_iterator end);
+inline text_t to_utf8 (const text_t &in) {return to_utf8 (in.begin(), in.end());}
+
+// converts a utf-8 encoded text_t string to a unicode
+// encoded text_t string
+text_t to_uni (const text_t &in);
+
+#define MAXUTF8CHARLEN 3
+
+// convert from a utf-8 char stream to the text_t class
+class utf8inconvertclass : public inconvertclass {
+public:
+  utf8inconvertclass();
+  void reset ();
+  void convert (text_t &output, status_t &status);
+
+protected:
+  // buffer to hold unconverted characters in a stream
+  unsigned char utf8buf[MAXUTF8CHARLEN];
+  size_t utf8buflen;
+
+  // returns the length that the current contents of the 
+  // utf8buf should be
+  size_t getutf8charlen ();
+};
+
+
+// This class provides the option of removing zero width
+// spaces (U+200B) during the output. By default this
+// option is turned off. The functionality is actually
+// implemented by the sub-classes, this class just provides
+// the framework for these classes. 
+//
+// Note: by convention reset() should not reset the rzws flag.
+class rzwsoutconvertclass : public outconvertclass {
+public:
+  rzwsoutconvertclass () {rzws = 0;};
+  void set_rzws (int new_rzws) {rzws = new_rzws;};
+
+protected:
+  int rzws;
+};
+
+// utf16 is almost the same as unicode, except for unicode values > 65535.
+class utf16outconvertclass : public rzwsoutconvertclass {
+public:
+  utf16outconvertclass () {};
+  void convert (char *out, size_t maxlen, size_t &len, status_t &status);
+};
+
+
+// Convert from a text_t class to a utf-8 char stream
+class utf8outconvertclass : public rzwsoutconvertclass {
+public:
+  utf8outconvertclass () {utf8buflen=0; utf8bufhere=0;};
+  void reset ();
+  // note that convert does not null-terminate the
+  // output array of characters
+  void convert (char *output, size_t maxlen, 
+		size_t &len, status_t &status);
+
+protected:
+  unsigned char utf8buf[MAXUTF8CHARLEN];
+  size_t utf8buflen;
+  size_t utf8bufhere;
+};
+
+
+// mapdata_t is used by mapconvert to hold the map file data
+class mapdata_t {
+public:
+  mapdata_t();
+  bool loaded;
+  unsigned short *ptrs[256];
+};
+
+// mapconvert is used in situations where conversion is best
+// done using a map file. The mapfile should reside in 
+// gsdlhome/unicode.
+class mapconvert {
+public:
+  mapconvert ();
+  ~mapconvert () {unloadmapfile();};
+
+  // setmapfile will cause loadmapfile to be called when conversion is
+  // needed
+  bool setmapfile (const text_t &themapfile, unsigned short theabsentc);
+
+  // loadmapfile should be called before any conversion is done
+  bool loadmapfile (const text_t &themapfile, unsigned short theabsentc);
+  void unloadmapfile ();
+
+  unsigned short convert (unsigned short c);
+
+  // note that this version of convert has different semantics to
+  // the convertclass version.
+  text_t convert (const text_t &instr);
+
+protected:
+  text_t mapfile;
+  unsigned short absentc;
+  mapdata_t mapdata;
+};
+
+
+
+#define MAXMAPCHARLEN 2
+
+// convert from a gb char stream to the unicode text_t class
+class mapinconvertclass : public inconvertclass {
+public:
+  mapinconvertclass();
+  virtual ~mapinconvertclass() {};
+
+  // setmapfile will cause loadmapfile to be called when conversion is needed
+  bool setmapfile (const text_t &themapfile, unsigned short theabsentc) {
+    return converter.setmapfile (themapfile, theabsentc);
+  };
+
+  // loadmapfile should be called before any conversion takes
+  // place
+  bool loadmapfile (const text_t &themapfile, unsigned short theabsentc) {
+    return converter.loadmapfile (themapfile, theabsentc);
+  };
+
+  void set_multibyte (int new_multibyte) {m_multibyte = new_multibyte;};
+
+  void reset ();
+  void convert (text_t &output, status_t &status);
+
+protected:
+  // buffer to hold unconverted characters in a stream
+  unsigned char mapbuf[MAXMAPCHARLEN];
+  size_t mapbuflen;
+  int m_multibyte;
+
+  // note: multiple instances of mapinconvert class are expensive
+  // as each will have its own copy of the map file data. This
+  // could be reduced by making map2unimap static, but then it
+  // wouldn't be thread safe.
+  mapconvert converter;
+
+  // returns the length that the current contents of the 
+  // mapbuf should be
+  inline size_t getmapcharlen () {
+    if (mapbuflen == 0) return 0;
+    if (mapbuf[0] < 0x80) return 1;
+    if (!m_multibyte) return 1;
+    return 2;
+  }
+};
+
+
+// Convert from a text_t class to a map char stream
+class mapoutconvertclass : public rzwsoutconvertclass {
+public:
+  mapoutconvertclass ();
+  virtual ~mapoutconvertclass() {};
+
+  // setmapfile will cause loadmapfile to be called when conversion is needed
+  bool setmapfile (const text_t &themapfile, unsigned short theabsentc) {
+    return converter.setmapfile (themapfile, theabsentc);
+  };
+
+  // loadmapfile should be called before any conversion takes
+  // place
+  bool loadmapfile (const text_t &themapfile, unsigned short theabsentc) {
+    return converter.loadmapfile (themapfile, theabsentc);
+  };
+
+  void set_multibyte (int new_multibyte) {m_multibyte = new_multibyte;};
+
+  void reset ();
+  void convert (char *output, size_t maxlen, 
+		size_t &len, status_t &status);
+
+protected:
+  unsigned char mapbuf[MAXMAPCHARLEN];
+  size_t mapbuflen;
+  size_t mapbufhere;
+  int m_multibyte;
+
+  mapconvert converter;
+};
+
+
+// Simple input and output converter classes for use with 8 bit encodings
+// using simple textual map files. Map files should contain (at least) two
+// tab-separated fields. The first field is the mapped value and the second
+// field is the unicode value.
+
+struct ltus_t 
+{
+  bool operator()(const unsigned short &t1, const unsigned short &t2) const
+  { return t1 < t2; }
+};
+
+
+class simplemapconvert {
+public:
+  simplemapconvert () {absentc=0; loaded=false;}
+  unsigned short convert (unsigned short c, bool in);
+  void setmapfile (const text_t &themapfile) {mapfile = themapfile;}
+
+protected:
+  bool loadmapfile (bool in);
+
+  map <unsigned short, unsigned short, ltus_t> mapping;
+  bool loaded;
+  text_t mapfile;
+  unsigned short absentc;
+};
+
+
+class simplemapinconvertclass : public inconvertclass {
+public:
+  virtual ~simplemapinconvertclass () {}
+
+  void convert (text_t &output, status_t &status);
+
+  void setmapfile (const text_t &themapfile) {converter.setmapfile(themapfile);}
+  
+protected:
+  simplemapconvert converter;
+};
+
+class simplemapoutconvertclass : public rzwsoutconvertclass {
+public:
+  virtual ~simplemapoutconvertclass () {}
+
+  void convert (char *output, size_t maxlen, 
+		size_t &len, status_t &status);
+
+  void setmapfile (const text_t &themapfile) {converter.setmapfile(themapfile);}
+  
+protected:
+  simplemapconvert converter;
+};
+
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/text_t.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/text_t.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/text_t.cpp	(revision 10506)
@@ -0,0 +1,939 @@
+/**********************************************************************
+ *
+ * text_t.cpp -- a simple 16-bit character string class
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+/*
+   $Log$
+   Revision 1.25  2005/06/16 22:49:44  kjdon
+   added starts_with and ends_with functions
+
+   Revision 1.24  2005/04/07 04:27:18  kjdon
+   added some x++ -> ++x changes submitted by Emanuel Dejanu
+
+   Revision 1.23  2004/12/02 22:21:34  kjdon
+   added some changes made by Emanuel Dejanu (Simple Words)
+
+   Revision 1.22  2004/05/24 03:43:22  mdewsnip
+   (Human Info) Added const text_t g_EmptyText("") to use instead of plain ol' "".
+
+   Revision 1.21  2001/06/01 02:51:28  sjboddie
+   Changes to get phind working under windows
+
+   Revision 1.20  2001/01/25 18:26:44  cs025
+   Included CORBA branch for first time
+
+   Revision 1.15.2.2  2000/04/05 10:19:38  syeates
+   added automatic conversion to allow text_t's to be <<'ed to ostreams
+
+   Revision 1.15.2.1  2000/04/04 15:02:29  cs025
+   Corba first commit
+
+   Revision 1.15  1999/10/14 22:52:39  sjboddie
+   joinchar can join using text_t string now too
+
+   Revision 1.14  1999/09/24 02:30:03  rjmcnab
+   added function has_unicode_letdig
+
+   Revision 1.13  1999/09/07 04:57:43  sjboddie
+   added gpl notice
+
+   Revision 1.12  1999/08/31 08:04:41  rjmcnab
+   Fixed a small but hard to find bug in getcarr
+
+   Revision 1.11  1999/07/01 04:05:09  rjmcnab
+   Optimised append functions slightly and added a reserve function.
+
+   Revision 1.10  1999/04/26 03:58:03  sjboddie
+   added is_number function
+
+   Revision 1.9  1999/04/06 22:17:24  rjmcnab
+   Added splits and joins using text_tset.
+
+   Revision 1.8  1999/02/28 23:14:41  rjmcnab
+
+   Added uc and lc to convert to uppercase and lowercase.
+
+   Revision 1.7  1999/02/21 22:26:39  rjmcnab
+
+   Made getint() a constant function.
+
+   Revision 1.6  1999/02/03 01:13:26  sjboddie
+
+   Got interface to handle subcollections and language subcollections -
+   committed changes made to some of the collections
+
+   Revision 1.5  1999/01/19 01:38:14  rjmcnab
+
+   Made the source more portable.
+
+   Revision 1.4  1999/01/12 01:51:00  rjmcnab
+
+   Standard header.
+
+   Revision 1.3  1999/01/08 02:33:16  rjmcnab
+
+   Added standard header to source files.
+
+ */
+
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\algorithm>
+#elif defined(GSDL_USE_STL_H)
+#  if defined(GSDL_USE_ALGO_H)
+#    include <algo.h>
+#  else
+#    include <algorithm.h>
+#  endif
+#else
+#  include <algorithm>
+#endif
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__
+#  include "WIN32cfg.h"
+# else
+#  include "config.h"
+# endif
+#endif
+
+
+#include "unitool.h"
+
+const text_t g_EmptyText("");
+
+////////////////////////////////////
+// text_t methods
+////////////////////////////////////
+
+// new stream converter ...
+ostream& operator<< (ostream &o, const text_t &text)
+{
+  text_t::const_iterator ithere = text.begin();
+  text_t::const_iterator itend = text.end();
+
+  while (ithere != itend)
+    {
+      if (*ithere < 256)
+	{
+	  o << (unsigned char)(*ithere);
+	}
+      else 
+	{
+	// put a space or a question mark depending on what
+	// the character is. Question marks tell the user that
+	// they are missing some information.
+	if (is_unicode_space (*ithere)) 
+	  o << ' ';
+	else 
+	  o << '?';
+      }
+      ++ithere;
+    }
+
+  return o;
+}
+
+text_t::text_t () 
+{
+  setencoding(0);
+  clear ();
+}
+
+text_t::text_t (int i) 
+{
+  setencoding(0);
+  clear ();
+  appendint (i);
+}
+
+text_t::text_t (const char *s) 
+{ 
+  setencoding(0);
+  clear ();
+  appendcstr (s);
+}
+
+text_t::text_t (const char *s, size_type nLength)
+{
+  setencoding(0);
+  clear ();
+  appendcarr(s, nLength);
+}
+
+
+void text_t::append (const text_t &t) 
+{
+  text.insert(text.end(), t.begin(), t.end());
+}
+
+void text_t::appendrange (iterator first, iterator last) 
+{
+  text.insert(text.end(), first, last);
+}
+
+void text_t::appendrange (const_iterator first, const_iterator last) 
+{
+  text.insert(text.end(), first, last);
+}
+
+void text_t::appendint (int i)
+{
+  // deal with zeros and negatives
+  if (i == 0) 
+    {
+      text.push_back('0');
+      return;
+    }
+  else if (i < 0)
+    {
+      text.push_back('-');
+      i *= -1;
+    }
+
+  // get a buffer for the conversion
+  int maxbuflen = sizeof(int)*3;
+  char *buf = new char[maxbuflen];
+  int len = 0;
+  
+  // get the number in reverse
+  while (i > 0)
+    {
+      buf[len++] = '0'+ (i%10);
+      i = i/10;
+    }
+
+  // reverse the number
+  while (len > 0)
+    {
+      text.push_back(buf[--len]);
+    }
+
+  delete []buf;
+}
+
+int text_t::getint () const
+{
+  int i = 0;
+  int mult = 1; // become -1 for negative numbers
+
+  const_iterator here = text.begin();
+  const_iterator end = text.end();
+  
+  // do plus and minus signs
+  if (here != end)
+    {
+      if (*here == '-')
+	{
+	  mult = -1;
+	  ++here;
+	}
+      else if (*here == '+')
+	{
+	  mult = 1;
+	  ++here;
+	}
+    }
+
+  // deal with the number
+  while ((here != end) && (*here >= '0') && (*here <= '9'))
+    {
+      i = 10*i + (*here - '0');
+      ++here;
+    }
+
+  i *= mult;
+  return i;
+}
+
+unsigned long text_t::getulong () const
+{
+  unsigned long i = 0;
+
+  const_iterator here = text.begin();
+  const_iterator end = text.end();
+
+  while ((here != end) && (*here >= '0') && (*here <= '9'))
+    {
+      i = 10*i + (*here - '0');
+      ++here;
+    }
+
+  return i;
+}
+
+void text_t::appendcarr (const char *s, size_type len)
+{
+  unsigned char *us = (unsigned char *)s;
+  if (text.capacity() < (text.size() + len + 2)) {
+    text.reserve(text.size() + len + 2);
+  }
+
+  while (len > 0) 
+    {
+      text.push_back (*us); // append this character
+      ++us;
+      --len;
+    }
+}
+
+void text_t::appendcstr (const char *s) 
+{
+  size_t len = strlen(s);
+  if (text.capacity() < (text.size() + len + 2)) {
+    text.reserve(text.size() + len + 2);
+  }
+  
+  unsigned char *us = (unsigned char *)s;
+  while (*us != '\0') 
+    {
+      text.push_back (*us); // append this character
+      ++us;
+    }
+}
+
+
+// strings returned from getcarr and getcstr become the callers 
+// responsibility and should be deallocated with "delete []"
+
+char *text_t::getcarr(size_type &len) const
+{
+  unsigned char *cstr = new unsigned char[size()];
+  len = 0;
+
+  const_iterator ithere = begin();
+  const_iterator itend = end();
+  while (ithere != itend)
+    {
+      if (*ithere < 256) cstr[len] = (unsigned char)(*ithere);
+      else {
+	// put a space or a question mark depending on what
+	// the character is. Question marks tell the user that
+	// they are missing some information.
+	if (is_unicode_space (*ithere)) cstr[len] = ' ';
+	else cstr[len] = '?';
+      }
+      ++len;
+      ++ithere;
+    }
+
+  return (char *)cstr;
+}
+
+char *text_t::getcstr() const
+{
+  unsigned char *cstr = new unsigned char[size() + 1];
+  const_iterator ithere = begin();
+  const_iterator itend = end();
+  int len = 0;
+
+  while (ithere != itend)
+    {
+      if (*ithere < 256) cstr[len] = (unsigned char)(*ithere);
+      else {
+	// put a space or a question mark depending on what
+	// the character is. Question marks tell the user that
+	// they are missing some information.
+	if (is_unicode_space (*ithere)) cstr[len] = ' ';
+	else cstr[len] = '?';
+      }
+      ++len;
+      ++ithere;
+    }
+
+  cstr[len] = '\0';
+
+  return (char *)cstr;
+}
+
+
+// general functions which work on text_ts
+
+// find a character within a range
+text_t::const_iterator findchar (text_t::const_iterator first, text_t::const_iterator last, 
+				 unsigned short c)
+{
+  while (first != last)
+    {
+      if (*first == c) break;
+      ++first;
+    }
+  return first;
+}
+
+text_t::iterator findchar (text_t::iterator first, text_t::iterator last, 
+			   unsigned short c)
+{
+  while (first != last)
+    {
+      if (*first == c) break;
+      ++first;
+    }
+  return first;
+}
+
+text_t::iterator findword (text_t::iterator first, 
+			   text_t::iterator last, 
+			   const text_t& word)
+{
+  text_t::const_iterator word_begin = word.begin();
+  text_t::const_iterator word_end = word.end();
+
+  while (first != last)
+    {
+      text_t::iterator char_match = first;
+      text_t::const_iterator word_here = word_begin;
+      while (word_here!=word_end)
+	{
+	  if (*char_match != *word_here)
+	    {
+	      break;
+	    }
+	  ++char_match;
+	  ++word_here;
+	}
+      if (word_here==word_end)
+	{
+	  return first;
+	}
+      ++first;
+    }
+  return last; // get to here only if there is no match
+}
+
+// get a string up to the next delimiter (which is skipped)
+text_t::const_iterator getdelimitstr (text_t::const_iterator first, 
+				      text_t::const_iterator last,
+				      unsigned short c, text_t &outstr)
+{
+  text_t::const_iterator here = first;
+  here = findchar (first, last, c);
+  outstr.clear();
+  outstr.appendrange (first, here);
+  if (here != last) ++here; // skip c
+  return here;
+}
+
+text_t::iterator getdelimitstr (text_t::iterator first, text_t::iterator last,
+				unsigned short c, text_t &outstr)
+{
+  text_t::iterator here = first;
+  here = findchar (first, last, c);
+  outstr.clear();
+  outstr.appendrange (first, here);
+  if (here != last) ++here; // skip c
+  return here;
+}
+
+// split a string with a character
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tset &outlist)
+{
+  outlist.erase(outlist.begin(), outlist.end());
+
+  text_t t;
+
+  while (first != last)
+    {
+      first = getdelimitstr (first, last, c, t);
+      outlist.insert (t);
+    }
+}
+
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tlist &outlist)
+{
+  outlist.erase(outlist.begin(), outlist.end());
+
+  text_t t;
+
+  while (first != last)
+    {
+      first = getdelimitstr (first, last, c, t);
+      outlist.push_back (t);
+    }
+}
+
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tarray &outlist)
+{
+  outlist.erase(outlist.begin(), outlist.end());
+
+  text_t t;
+
+  while (first != last)
+    {
+      first = getdelimitstr (first, last, c, t);
+      outlist.push_back (t);
+    }
+}
+
+// join a string using a character
+void joinchar (const text_tset &inlist, unsigned short c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tset::const_iterator here = inlist.begin ();
+  text_tset::const_iterator end = inlist.end ();
+
+  if (here != end) {
+    outtext += *here; ++here;
+    while (here != end) {
+      outtext.push_back (c);
+      outtext += *here;
+      ++here;
+    }
+  }
+}
+
+void joinchar (const text_tlist &inlist, unsigned short c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tlist::const_iterator here = inlist.begin ();
+  text_tlist::const_iterator end = inlist.end ();
+  if (here != end) {
+    outtext += *here; ++here;
+    while (here != end) {
+      outtext.push_back (c);
+      outtext += *here;
+      ++here;
+    }
+  }
+}
+
+void joinchar (const text_tarray &inlist, unsigned short c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tarray::const_iterator here = inlist.begin ();
+  text_tarray::const_iterator end = inlist.end ();
+  if (here != end) {
+    outtext += *here; ++here;
+    while (here != end) {
+      outtext.push_back (c);
+      outtext += *here;
+      ++here;
+    }
+  }
+}
+
+void joinchar (const text_tlist &inlist, const text_t &c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tlist::const_iterator here = inlist.begin ();
+  text_tlist::const_iterator end = inlist.end ();
+  if (here != end) {
+    outtext += *here; ++here;
+    while (here != end) {
+      outtext += c;
+      outtext += *here;
+      ++here;
+    }
+  }
+}
+
+void joinchar (const text_tset &inlist, const text_t &c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tset::const_iterator here = inlist.begin ();
+  text_tset::const_iterator end = inlist.end ();
+  if (here != end) {
+    outtext += *here; ++here;
+    while (here != end) {
+      outtext += c;
+      outtext += *here;
+      ++here;
+    }
+  }
+}
+
+void joinchar (const text_tarray &inlist, const text_t &c, text_t &outtext)
+{
+  outtext.clear ();
+
+  text_tarray::const_iterator here = inlist.begin ();
+  text_tarray::const_iterator end = inlist.end ();
+  if (here != end) {
+    outtext += *here; ++here;
+    while (here != end) {
+      outtext += c;
+      outtext += *here;
+      ++here;
+    }
+  }
+}
+
+// count the occurances of a character within a range
+int countchar (text_t::const_iterator first, text_t::const_iterator last,
+	       unsigned short c)
+{
+  int count = 0;
+  while (first != last) {
+    if (*first == c) ++count;
+    ++first;
+  }
+  return count;
+}
+
+// return a substring of string from first up to but not including last
+text_t substr (text_t::const_iterator first, text_t::const_iterator last) {
+
+  text_t substr; substr.reserve(last - first + 2);
+  while (first != last) {
+    substr.push_back(*first);
+    ++first;
+  }
+  return substr;
+}
+
+
+// convert to lowercase
+void lc (text_t::iterator first, text_t::iterator last) {
+  while (first != last) {
+    *first = unicode_tolower(*first);
+    ++first;
+  }
+}
+
+// convert to uppercase
+void uc (text_t::iterator first, text_t::iterator last) {
+  while (first != last) {
+    *first = unicode_toupper(*first);
+    ++first;
+  }
+}
+
+
+// checks to see if it is a number (i.e. contains only 0-9)
+bool is_number (const text_t &text) {
+
+  text_t::const_iterator here = text.begin();
+  text_t::const_iterator end = text.end();
+
+  while (here != end) {
+    if ((*here!='0') && (*here!='1') && (*here!='2') &&
+	(*here!='3') && (*here!='4') && (*here!='5') &&
+	(*here!='6') && (*here!='7') && (*here!='8') &&
+	(*here!='9')) return false;
+    ++here;
+  }
+  return true;
+}
+
+
+// checks to see if the text has any letters or digits
+bool has_unicode_letdig (const text_t &text) {
+  if (text.empty()) return false;
+  
+  text_t::const_iterator here = text.begin();
+  text_t::const_iterator end = text.end();
+  while (here != end) {
+    if (is_unicode_letdig (*here)) return true;
+    ++here;
+  }
+
+  return false;
+}
+
+// checks to see if a text_t starts with the specified prefix
+bool starts_with(const text_t& text, const text_t& prefix) {
+  if (prefix.empty()) return true;
+  if (text.empty() || text.size()<prefix.size()) return false;
+  text_t substring = substr(text.begin(), text.begin()+prefix.size());
+  return substring == prefix;
+}
+// checks to see if a text_t ends with the specified suffix
+bool ends_with(const text_t& text, const text_t& suffix) {
+  if (suffix.empty()) return true;
+  if (text.empty() || text.size() < suffix.size()) return false;
+  text_t substring = substr(text.end()-suffix.size(),text.end());
+  return substring == suffix;
+
+}
+
+
+////////////////////////////////////
+// convertclass methods
+////////////////////////////////////
+
+// conversion classes used for getting information in to and out of
+// the text_t class.
+
+convertclass::convertclass () 
+{
+  // nothing to do
+}
+
+void convertclass::reset ()
+{
+  // nothing to do
+}
+
+
+////////////////////////////////////
+// inconvertclass methods
+////////////////////////////////////
+
+// convert from a char stream to the text_t class
+// the default version assumes the input is a ascii
+// character array
+
+inconvertclass::inconvertclass () 
+{
+  start = NULL;
+  len = 0;
+}
+
+
+void inconvertclass::reset ()
+{
+  start = NULL;
+  len = 0;
+}
+
+void inconvertclass::setinput (char *thestart, size_t thelen)
+{
+  start = thestart;
+  len = thelen;
+}
+
+void inconvertclass::convert (text_t &output, status_t &status)
+{
+  output.clear();
+
+  if (start == NULL || len == 0)
+    {
+      status = finished;
+      return;
+    }
+
+  if (output.capacity() < len + 2)
+    output.reserve(len + 2);
+  
+  // don't want any funny sign conversions happening
+  unsigned char *here = (unsigned char *)start;
+  while (len > 0) 
+    {
+      output.push_back (*here); // append this character
+      ++here;
+      --len;
+    }
+
+  start = (char *)here; // save current position
+  status = finished;
+}
+
+// will treat the text_t as a 8-bit string and convert
+// it to a 16-bit string using the about convert method.
+text_t inconvertclass::convert (const text_t &t) {
+  text_t out;
+  text_t tmpout;
+  status_t status;
+  text_t::const_iterator here = t.begin();
+  text_t::const_iterator end = t.end();
+  unsigned char cbuf[256];
+  size_t cbuflen = 0;
+ 
+  out.clear();
+  if (out.capacity() < t.size() + 2)
+    out.reserve(t.size() + 2);
+  while (here != end) {
+    while (here != end && cbuflen < 256) {
+      cbuf[cbuflen++] = (unsigned char)(*here & 0xff);
+      ++here;
+    }
+
+    if (cbuflen > 0) {
+      setinput ((char *)cbuf, cbuflen);
+      status = unfinished;
+      while (status == unfinished) {
+	convert (tmpout, status);
+	out += tmpout;
+      }
+      cbuflen = 0;
+    }
+  }
+
+  out.setencoding (0); // unicode
+
+  return out;
+}
+
+// an instance of the default inconvertclass to do simple
+// conversions. Note that any functions that use this are
+// not reentrant. If a function needs to be reentrant it
+// should declare its own instance.
+inconvertclass ascii2text_t;
+
+
+////////////////////////////////////
+// outconvertclass methods
+////////////////////////////////////
+
+// Convert from a text_t class to a char stream
+// This default version assumes the output is a ascii
+// character array. If you set the output stream you
+// can use this class to output to a stream using the
+// << operator. The << operator can also be conveniently
+// used to set the output stream by doing something like
+//
+// cout << text_t2ascii << text_tstr << anothertext_tstr;
+//
+outconvertclass::outconvertclass ()
+{
+  input = NULL;
+  outs = NULL;
+}
+
+void outconvertclass::reset ()
+{
+  input = NULL;
+  outs = NULL;
+}
+
+void outconvertclass::setinput (text_t *theinput)
+{
+  input = theinput;
+  if (input != NULL) texthere = input->begin();
+}
+
+void outconvertclass::setdata(text_t *theinput, text_t::iterator thetexthere)
+{
+  input = theinput;     
+  texthere = thetexthere;
+}
+ 
+void outconvertclass::convert (char *output, size_t maxlen, 
+		      size_t &len, status_t &status)
+{
+  if (input == NULL || output == NULL)
+    {
+      status = finished;
+      return;
+    }
+
+  // don't want any funny sign conversions happening
+  unsigned char *uoutput = (unsigned char *)output;
+  text_t::iterator textend = input->end();
+  len = 0;
+  while ((len < maxlen) && (texthere != textend)) 
+    {
+      if (*texthere < 256) *uoutput = (unsigned char)(*texthere);
+      else {
+	// put a space or a question mark depending on what
+	// the character is. Question marks tell the user that
+	// they are missing some information.
+	if (is_unicode_space (*texthere)) *uoutput = ' ';
+	else *uoutput = '?';
+      }
+      ++uoutput;
+      ++len;
+      ++texthere;
+    }
+  
+  if (texthere == textend) status = finished;
+  else status = unfinished;
+}
+
+// will convert the 16-bit string to a 8-bit stream
+// and place the result in a text_t. This method uses
+// the above convert function.
+text_t outconvertclass::convert (const text_t &t) {
+  text_t out;
+  unsigned char cbuf[256];
+  size_t cbuflen = 0;
+  status_t status = unfinished;
+  
+  out.clear(); 
+  if (out.capacity() < t.size() + 2)
+    out.reserve(t.size() + 2);
+  setinput ((text_t *)&t); // discard constant
+  while (status == unfinished) {
+    convert ((char *)cbuf, 256, cbuflen, status);
+    out.appendcarr ((char *)cbuf, cbuflen);
+  }
+
+  out.setencoding (1); // other encoding
+  
+  return out;
+}
+
+
+void outconvertclass::setostream (ostream *theouts)
+{
+  outs = theouts;
+}
+
+ostream *outconvertclass::getostream ()
+{
+  return outs;
+}
+
+
+
+
+// an instance of the default outconvertclass to do simple
+// conversions
+outconvertclass text_t2ascii;
+
+
+
+// stream operators for the output class
+
+outconvertclass &operator<< (ostream &theouts, outconvertclass &outconverter)
+{
+  outconverter.setostream(&theouts);
+  return outconverter;
+}
+
+
+#define STREAMBUFSIZE 256
+outconvertclass &operator<< (outconvertclass &outconverter, const text_t &t)
+{
+  ostream *outstream = outconverter.getostream();
+
+  if (outstream == NULL) return outconverter;
+
+  char outbuf[STREAMBUFSIZE];
+  size_t len;
+  outconvertclass::status_t status = outconvertclass::unfinished;
+
+  // assume that there is no data needing converting
+  // left in the converter
+  outconverter.setinput ((text_t *)(&t)); // note the const -> nonconst conversion
+
+  while (status == outconvertclass::unfinished)
+    {
+      outconverter.convert (outbuf, STREAMBUFSIZE, len, status);
+      if (len > 0) outstream->write(outbuf, len);
+    }
+
+  return outconverter;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/lib/text_t.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/text_t.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/text_t.h	(revision 10506)
@@ -0,0 +1,375 @@
+/**********************************************************************
+ *
+ * text_t.h -- a simple 16-bit character string class
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef TEXT_T_H
+#define TEXT_T_H
+
+#include "gsdlconf.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#  include <ospace\std\list>
+#  include <ospace\std\set>
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#  include <list.h>
+#  include <set.h>
+#  include <map.h>
+#else
+#  include <vector>
+#  include <list>
+#  include <set>
+#  include <map>
+#endif
+
+// use the standard namespace
+#if !defined (GSDL_NAMESPACE_BROKEN)
+#if defined(GSDL_USE_OBJECTSPACE)
+using namespace ospace::std;
+#else
+using namespace std;
+#endif
+#endif
+
+// class prototypes
+class text_t;
+class inconvertclass;
+class outconvertclass;
+
+
+// for those stupid compilers which need it
+#if defined(GSDL_NEED_DESTROY_USHORT)
+inline void destroy(unsigned short *) {};
+inline void destroy(int *) {};
+#endif
+
+typedef vector<unsigned short> usvector;
+extern const text_t g_EmptyText;
+
+// The class text_t can handle long strings which may contain
+// null characters. It uses unsigned shorts to represent up to
+// 64K character values.
+class text_t {
+  public:
+  //type support for ucvector
+  typedef usvector::iterator iterator;
+  typedef usvector::const_iterator const_iterator;
+  typedef usvector::reference reference;
+  typedef usvector::const_reference const_reference;
+  typedef usvector::size_type size_type;
+  typedef usvector::difference_type difference_type;
+  typedef usvector::const_reverse_iterator const_reverse_iterator;
+  typedef usvector::reverse_iterator reverse_iterator;
+  
+protected:
+  usvector text;
+  unsigned short encoding; // 0 = unicode, 1 = other
+  
+public:
+  // constructors
+  text_t ();
+  text_t (int i);
+  text_t (const char *s); // assumed to be a normal c string
+  text_t (const char *s, size_type nLength); // support for arrays of chars
+  void setencoding (unsigned short theencoding) {encoding=theencoding;};
+  unsigned short getencoding () {return encoding;};
+
+  usvector& text_as_usvector() { return text ; };
+  const usvector& text_as_usvector() const { return text ; };
+
+  // basic container support
+  iterator begin () {return text.begin();}
+  const_iterator begin () const {return text.begin();}
+  iterator end () {return text.end();}
+  const_iterator end () const {return text.end();}
+
+  void erase(iterator pos) {text.erase(pos);}
+  void erase(iterator first, iterator last) {text.erase(first, last);}
+  void push_back(unsigned short c) {text.push_back(c);}
+  void pop_back() {text.pop_back();}
+  text_t &operator=(const text_t &x) {text=x.text; encoding=x.encoding; return *this;}
+  reference operator[](size_type n) {return text[n];};
+  const_reference operator[](size_type n) const {return text[n];};
+
+  void reserve (size_type n) {text.reserve(n);}
+  size_type capacity() const { return text.capacity(); }
+  
+  bool empty () const {return text.empty();}
+  size_type size() const {return text.size();}
+  friend inline bool operator!=(const text_t& x, const text_t& y)
+	{return (x.text != y.text);}
+  friend inline bool operator==(const text_t& x, const text_t& y) 
+	{return (x.text == y.text);}
+  friend inline bool operator<(const text_t& x, const text_t& y) 
+	{return (x.text < y.text);}
+  friend inline bool operator>(const text_t& x, const text_t& y) 
+	{return (x.text > y.text);}
+  friend inline bool operator>=(const text_t& x, const text_t& y) 
+	{return (x.text >= y.text);}
+  friend inline bool operator<=(const text_t& x, const text_t& y) 
+	{return (x.text <= y.text);}
+  
+  // added functionality
+  void clear () {text.erase(text.begin(),text.end());}
+  void append (const text_t &t);
+  void appendrange (iterator first, iterator last);
+  void appendrange (const_iterator first, const_iterator last);
+  text_t &operator+= (const text_t &t) {append(t);return *this;}
+
+  // support for integers
+  void appendint (int i);
+  void setint (int i) {clear();appendint(i);}
+  text_t &operator=(int i) {setint (i);return *this;}
+  text_t &operator+= (int i) {appendint(i);return *this;}
+  int getint () const;
+
+  // same as getint but returns an unsigned long
+  unsigned long getulong () const;
+
+  // support for arrays of chars
+  void appendcarr (const char *s, size_type len);
+  void setcarr (char *s, size_type len) {clear();appendcarr(s,len);}
+
+  // support for const null-terminated C strings
+  void appendcstr (const char *s);
+  void setcstr (const char *s) {clear();appendcstr(s);}
+  text_t &operator= (const char *s) {setcstr(s);return *this;} // c string
+  text_t &operator+= (const char *s) {appendcstr(s);return *this;} // c string
+
+  // strings returned from getcarr and getcstr become the callers 
+  // responsibility and should be deallocated with "delete []"
+  char *getcarr(size_type &len) const;
+  char *getcstr() const;
+
+};
+
+// new stream converter ...
+ostream& operator<< (ostream &o, const text_t &text);
+
+inline text_t operator+(const text_t &t1, const text_t &t2)
+{
+  text_t tnew = t1;
+  tnew.append(t2);
+  return tnew;
+}
+
+inline text_t operator+(const text_t &t1, int i1)
+{
+  text_t tnew = t1;
+  tnew.appendint(i1);
+  return tnew;
+}
+
+inline text_t operator+(const text_t &t1, char *s1)
+{
+  text_t tnew = t1;
+  tnew.appendcstr(s1);
+  return tnew;
+}
+
+
+
+
+struct eqtext_t 
+{
+  bool operator()(const text_t &t1, const text_t &t2) const
+  { return t1 == t2; }
+};
+
+struct lttext_t 
+{
+  bool operator()(const text_t &t1, const text_t &t2) const
+  { return t1 < t2; }
+};
+
+
+// frequently used derived types
+typedef set<text_t,lttext_t> text_tset;
+typedef list<text_t> text_tlist;  // more efficient for insertions/deletions
+typedef vector<text_t> text_tarray; // more space efficient than text_tlist
+typedef map<text_t, text_t, lttext_t> text_tmap;
+
+
+// general functions which work on text_ts
+
+// find a character within a range
+text_t::const_iterator findchar (text_t::const_iterator first, text_t::const_iterator last, 
+				 unsigned short c);
+text_t::iterator findchar (text_t::iterator first, text_t::iterator last, 
+			   unsigned short c);
+
+text_t::iterator findword (text_t::iterator first, text_t::iterator last,
+			   const text_t &word);
+
+// get a string up to the next delimiter (which is skipped)
+text_t::const_iterator getdelimitstr (text_t::const_iterator first, 
+				      text_t::const_iterator last,
+				      unsigned short c, text_t &outstr);
+text_t::iterator getdelimitstr (text_t::iterator first, text_t::iterator last,
+				unsigned short c, text_t &outstr);
+
+// split a string with a character
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tset &outlist);
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tlist &outlist);
+void splitchar (text_t::const_iterator first, text_t::const_iterator last,
+		unsigned short c, text_tarray &outlist);
+
+// join a string using a character
+void joinchar (const text_tset &inlist, unsigned short c, text_t &outtext);
+void joinchar (const text_tlist &inlist, unsigned short c, text_t &outtext);
+void joinchar (const text_tarray &inlist, unsigned short c, text_t &outtext);
+void joinchar (const text_tset &inlist, const text_t &c, text_t &outtext);
+void joinchar (const text_tlist &inlist, const text_t &c, text_t &outtext);
+void joinchar (const text_tarray &inlist, const text_t &c, text_t &outtext);
+
+// count the occurances of a character within a range
+int countchar (text_t::const_iterator first, text_t::const_iterator last,
+	       unsigned short c);
+
+// return a substring of string from first up to but not including last
+text_t substr (text_t::const_iterator first, text_t::const_iterator last);
+
+// convert to lowercase
+void lc (text_t::iterator first, text_t::iterator last);
+inline void lc (text_t &t) {lc (t.begin(), t.end());}
+
+// convert to uppercase
+void uc (text_t::iterator first, text_t::iterator last);
+inline void uc (text_t &t) {uc (t.begin(), t.end());}
+
+// checks to see if it is a number (i.e. contains only 0-9)
+bool is_number (const text_t &text);
+
+// checks to see if the text has any letters or digits
+bool has_unicode_letdig (const text_t &text);
+
+// checks to see if a text_t starts with the specified prefix
+bool starts_with(const text_t& text, const text_t& prefix);
+// checks to see if a text_t ends with the specified suffix
+bool ends_with(const text_t& text, const text_t& suffix);
+
+// conversion classes used for getting information in to and out of
+// the text_t class.
+
+class convertclass 
+{
+public:
+  enum status_t {finished, stopped, unfinished};
+  
+  convertclass ();
+  virtual void reset ();
+};
+
+
+
+// convert from a char stream to the text_t class
+// the default version assumes the input is a ascii
+// character array
+class inconvertclass : public convertclass
+{
+public:
+  inconvertclass ();
+  void reset ();
+  void setinput (char *thestart, size_t thelen);
+
+  // output will be cleared before the conversion
+  virtual void convert (text_t &output, status_t &status);
+
+  // will treat the text_t as a 8-bit string and convert
+  // it to a 16-bit string using the about convert method.
+  text_t convert (const text_t &t);
+
+protected:
+  char *start;
+  size_t len;
+};
+
+// to get something which will do the conversion
+// to ascii declare a (non global!) instance like
+// this
+// inconvertclass ascii2text_t;
+
+#if defined(GSDL_USE_IOS_H)
+#include <iostream.h> // darwin doesn't have ostream.h...
+#else
+#include <ostream>
+#endif
+
+// Convert from a text_t class to a char stream
+// This default version assumes the output is a ascii
+// character array. If you set the output stream you
+// can use this class to output to a stream using the
+// << operator. The << operator can also be conveniently
+// used to set the output stream by doing something like
+//
+// cout << text_t2ascii << textstr << anothertextstr;
+//
+// this class assumes that the input text doesn't change
+// while the conversion takes place
+class outconvertclass : public convertclass
+{
+public:
+  outconvertclass ();
+  virtual void reset ();
+  virtual void setinput (text_t *theinput);
+  virtual void setdata(text_t *input, text_t::iterator texthere);
+  // note that convert does not null-terminate the
+  // output array of characters
+  virtual void convert (char *output, size_t maxlen, 
+			size_t &len, status_t &status);
+
+  // will convert the 16-bit string to a 8-bit stream
+  // and place the result in a text_t. This method uses
+  // the above convert function.
+  text_t convert (const text_t &t);
+
+  virtual void setostream (ostream *theouts);
+  ostream *getostream ();
+
+protected:
+  text_t *input;
+  text_t::iterator texthere; // only valid if input is valid
+
+  ostream *outs;
+};
+
+// to get something which will do the conversion
+// to text_t declare a (non global!) instance like
+// this
+// outconvertclass text_t2ascii;
+
+
+// stream operators for the output class
+outconvertclass &operator<< (ostream &theouts, outconvertclass &outconverter);
+outconvertclass &operator<< (outconvertclass &outconverter, const text_t &t);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/lib/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/lib/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/lib/win32.mak	(revision 10506)
@@ -0,0 +1,93 @@
+###########################################################################
+#
+# win32 makefile -- lib
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..
+USE_STLPORT = 0
+LOCAL_LIBRARY = 0
+DLL = 0
+DLLDEBUG = 0
+STLPATH = "$(GSDLHOME)\packages\windows\stlport\stlport"
+
+AR = lib
+CC = cl
+
+CPPFLAGS = -GX
+!IF $(DLL)
+CPPFLAGS = $(CPPFLAGS) -MD
+!ELSE
+!IF ($(DLLDEBUG))
+CPPFLAGS = $(CPPFLAGS) -MDd
+!ENDIF
+!ENDIF
+
+DEFS = -D__WIN32__ -DHAVE_CONFIG_H -DPARADOCNUM -D_LITTLE_ENDIAN \
+       -DSHORT_SUFFIX
+INCLUDES = -I"$(GSDLHOME)" -I"$(GSDLHOME)\packages\mg\lib"
+!IF $(USE_STLPORT)
+DEFS = $(DEFS) -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = $(INCLUDES) -I$(STLPATH)
+!ENDIF
+!IF $(LOCAL_LIBRARY)
+DEFS = $(DEFS) -DGSDL_LOCAL_LIBRARY
+!ENDIF
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $< 
+
+HEADERS = cfgread.h fileutil.h gsdlunicode.h text_t.h display.h gsdlconf.h \
+	  gsdltimes.h gsdltools.h cnfgable.h cnfgator.h
+
+SOURCES = cfgread.cpp fileutil.cpp gsdlunicode.cpp text_t.cpp display.cpp \
+	  gsdltimes.cpp gsdltools.cpp cnfgable.cpp cnfgator.cpp
+
+OBJECTS = cfgread.obj fileutil.obj gsdlunicode.obj text_t.obj display.obj \
+	  gsdltimes.obj gsdltools.obj cnfgable.obj cnfgator.obj
+
+all: gsdllib.lib
+
+gsdllib.lib : $(OBJECTS)
+	if EXIST gsdllib.lib del gsdllib.lib
+	$(AR) /out:gsdllib.lib $(OBJECTS)
+
+# we want gsdltools to always be compiled in case the status of
+# GSDL_LOCAL_LIBRARY has changed
+gsdltools.obj: FORCE
+
+clean:
+	del *.obj 
+	del gsdllib.lib
+
+install:
+
+FORCE:
Index: /tags/gsdl-2_61-distribution/gsdl/macros/about.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/about.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/about.dm	(revision 10506)
@@ -0,0 +1,91 @@
+# this file must be UTF-8 encoded
+package about
+
+#######################################################################
+# Icons
+#######################################################################
+
+_imagethispage_ {<img src="_httpiconhabout_" width=_widthhabout_ height=_heighthabout_>}
+
+# don't want link to 'about' page
+_imagecollection_ {_If_("_iconcollection_" ne "",
+	<img src="_iconcollection_" border=0 title="_collectionname_">,<br><br><h2>_collectionname_</h2>)}
+_imagecollection_ [v=1] {<br><br><h2>_collectionname_</h2>}
+
+#######################################################################
+# about page content 
+#######################################################################
+
+_pagetitle_ {_collectionname_}
+
+_content_ {
+<center>
+_optnavigationbar_
+</center>
+
+_If_("_cgiargct_" eq "0",
+     _If_("_cgiargu_" ne "1",_aboutqueryform_)     
+    )
+_If_("_cgiargct__cgiargqto_" eq "11",
+    _If_("_cgiargu_" ne "1",_aboutqueryform_)
+    )
+_If_("_cgiargct__cgiargqto_" eq "21",
+    _If_("_cgiargu_" ne "1",_aboutqueryform_)
+    )
+
+_If_("_cgiargct__cgiargqto__cgiargqt_" eq "130",
+    _If_("_cgiargu_" ne "1",_aboutqueryform_)
+    )
+_If_("_cgiargct__cgiargqto__cgiargqt_" eq "230",
+    _If_("_cgiargu_" ne "1",_aboutqueryform_)
+    )
+_If_(_Global:collectionextra_,<p>_textabout_)
+_textsubcollections_
+<h3>_help:textsimplehelpheading_</h3>
+_help:simplehelp_
+}
+
+# _aboutqueryform_ is reset to "" in the server if the collection isn't
+# searchable
+_aboutqueryform_ {
+_query:queryform_
+<p>_iconblankbar_</p>
+}
+
+_textabout_ {
+<h3>_textabcol_</h3>
+_Global:collectionextra_
+}
+
+# set from within server
+_textsubcollections_ {}
+
+_aboutCollage_ {}
+_classifier_ {}
+_collageempty_ {There is no collage classifier defined for this collection!}
+_collageapplet_ {
+
+ <p>
+ <center>
+
+ <applet CODEBASE="_httpprefix_/bin/java" code="org.nzdl.gsdl.GsdlCollageApplet.GsdlCollageApplet.class" 
+         archive="GsdlCollageApplet.jar" width="445" height="250">
+ 
+	 <param name="gwcgi" value="_gwcgi_">
+         <param name="collection" value="_cgiargc_"> 
+     	 <param name="classifier" value="CL_classifier_.1">
+	   
+     	 <param name="hrefMustHave" value="cl=CL_classifier_.1">
+     	 <param name="imageMustNotHave" value="hl=%x=%gt=%gc=%.pr">
+
+     <param name="imageType" value=".jpg%.png">  
+     <param name="verbosity" value="5">
+     <param name="maxDepth" value="3">
+     <param name="refreshDelay" value="1500">
+     <param name="isJava2" value="auto">
+
+ </applet>
+
+ </center>
+ <p>
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/armenian.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/armenian.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/armenian.dm	(revision 10506)
@@ -0,0 +1,1365 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Armenian Language text and icon macros 
+# Many thanks to Tigran Zargaryan (translated January 2004)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=hy] {ÕÕ¡ÖÕ¢Õ¥ÖÕ¡Õ¯Õ¡Õ¶Õ¶Õ¥Ö}
+_textsource_ [l=hy] {Õ°Õ²ÕžÖÕŽ Õ¡Õ²Õ¢ÕµÕžÖÖÕ«Õ¶}
+_textdate_ [l=hy] {Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕŽÕ¡Õ¶ Õ¡ÕŽÕœÕ¡Õ©Õ«ÕŸ`}
+_textnumpages_ [l=hy] {Õ§Õ»Õ¥ÖÕ« ÖÕ¡Õ¶Õ¡Õ¯}
+
+_textsignin_ [l=hy] {ÕÕžÖÕ¿Ö}
+
+_textdefaultcontent_ [l=hy] {ÕÕ¶Õ¿ÖÕŸÕžÕ² Õ§Õ»Õš Õ¹Õ« Õ£Õ¿Õ¶ÕŸÕžÖÕŽ: ÕÕ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Ö
+Õ€Õ«Õ¿Õ¡Õ¯Õ« 'Õ°Õ¥Õ¿' Õ¯ÕžÕ³Õ¡Õ¯Õš Õ¯Õ¡ÕŽ ÕÕžÖÕ¶ Õ¯ÕžÕ³Õ¡Õ¯Õš` ÕŸÕ¥ÖÕ¡Õ€Õ¡ÕŒÕ¶Õ¡Õ¬ÕžÖ
+Ô³ÖÕ«Õ¶ÕœÕ©ÕžÕžÖÕ¶ Õ©ÕŸÕ¡ÕµÕ«Õ¶ Õ£ÖÕ¡Õ€Õ¡ÖÕ¡Õ¶:}
+
+_textdefaulttitle_ [l=hy] {GSDL ÕœÕ­Õ¡Õ¬}
+
+_textbadcollection_ [l=hy] {Ô±ÕµÕœ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶ (Õ¡Õ¶ÕžÖÕ¶Õš "_cvariable_") Õ¯Õ¡ÖÕ£Õ¡Õ¢Õ¥ÖÕŸÕ¡Õ® Õ¹Õ§ Õ©ÕŸÕ¡ÕµÕ«Õ¶ Õ£ÖÕ¡Õ€Õ¡ÖÕ¡Õ¶Õ« Õ¿ÕŸÕµÕ¬ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ« ÕŸÖÕ¡:}
+
+_textselectpage_ [l=hy] {ÔžÕ¶Õ¿ÖÕ«Ö Õ§Õ»}
+
+_collectionextra_ [l=hy] {Ô±ÕµÕœ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶ ÕºÕ¡ÖÕžÖÕ¶Õ¡Õ¯ÕžÖÕŽ Õ§ _about:numdocs_ ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©: 
+ÕÕ¥ÖÕ»Õ«Õ¶ Õ¡Õ¶Õ£Õ¡ÕŽ Õ¡ÕµÕ¶ ÕœÕ¿Õ¥Õ²Õ®ÕŸÕ¥Õ¬ Õ§ _about:builddate_ Ö
+Ö Õ¡ÕŒÕ¡Õ»:}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=hy] {<p>Ô±ÕµÕœ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶ ÕºÕ¡ÖÕžÖÕ¶Õ¡Õ¯ÕžÖÕŽ Õ§ _numdocs_ _If_("_numdocs_" Õ°Õ¡ÕŸÕ¡ÕœÕ¡Ö "1",ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©,/Õ¥Ö/), ÕšÕ¶Õ€Õ¡ÕŽÕ¥Õ¶Õš _numbytes_.
+<p><a href="_httppagex_(bsummary)">ÕÕ¥Õ²ÕŽÕ«Ö </a> Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ« ÕœÕ¿Õ¥Õ²Õ®ÕŽÕ¡Õ¶ Õ°Õ¡ÕŽÕ¡ÕŒÕžÕ¿Õ¡Õ£ÖÕžÖÕ©ÕµÕžÖÕ¶Õš Õ€Õ«Õ¿Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö:
+}
+
+_textimagecollection_ [l=hy] {}
+_textimageabout_ [l=hy] {Ô·Õ»Õ« ÕŽÕ¡ÕœÕ«Õ¶}
+_textimagehome_ [l=hy] {ÕÕ¶Õ¡ÕµÕ«Õ¶ Õ§Õ»}
+_textimagehelp_ [l=hy] {ÕÕ£Õ¶ÕžÖÕ©ÕµÕ¡Õ¶ Õ§Õ»}
+_textimagepref_ [l=hy] {ÕÕ¡Õ­ÕšÕ¶Õ¿ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ« Õ§Õ»}
+_textimagegreenstone_ [l=hy] {Ô³ÖÕ«Õ¶ÕœÕ©ÕžÕžÖÕ¶ Õ©ÕŸÕ¡ÕµÕ«Õ¶ Õ£ÖÕ¡Õ€Õ¡ÖÕ¡Õ¶Õ« Õ®ÖÕ¡Õ£ÖÕ¡Õ·Õ¡Ö}
+_textimageusab_ [l=hy] {Ô»Õ¶Õ¹ ÕžÖ Õ£Õ¿Õ¥Õ¬ Õ¥Õœ, Õ€ÕªÕŸÕ¡Ö Õ§ Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Õ¬}
+
+_textimagesearch_ [l=hy] {ÕÖÕžÕ¶Õ¥Õ¬ Õ°Õ¡Õ¿ÕžÖÕ¯ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥Ö Õ£Õ¿Õ¶Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ¥ÖÕ« Õ¡ÕµÕ¢Õ¢Õ¥Õ¶Õ¡Õ¯Õ¡Õ¶ ÖÕžÖÖÕ¡Õ¯Õ«}
+_textimageCreator_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ Õ°Õ¥Õ²Õ«Õ¶Õ¡Õ¯Õ¶Õ¥ÖÕ« Õ¡ÕµÕ¢Õ¢Õ¥Õ¶Õ¡Õ¯Õ¡Õ¶ ÖÕ¡Õ¶Õ¯Õš}
+_textimageSubject_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ¡ÕŒÕ¡ÖÕ¯Õ¡ÕµÕ¡Õ¯Õ¡Õ¶ Õ€Õ¡ÕœÕ¥ÖÕ«}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ¡ÕŽÕœÕ¡Õ©ÕŸÕ«}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ¶Õ¡Õ­Õ¶Õ¡Õ¯Õ¡Õ¶ ÖÕ¡ÕµÕ¬Õ« Õ¡Õ¶ÕŸÕ¡Õ¶}
+_textimageLanguage_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ¬Õ¥ÕŠÕŸÕ«}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ¯Õ¡ÕŠÕŽÕ¡Õ¯Õ¥ÖÕºÕžÖÕ©ÕµÕ¡Õ¶}
+_textimageKeyword_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ¢Õ¡Õ¶Õ¡Õ¬Õ« Õ¢Õ¡ÕŒÕ«}
+_textimageHowto_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ€Õ¡ÕœÕ¥ÖÕ«}
+_textimageList_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ« ÖÕ¡Õ¶Õ¯Õš}
+_textimageSeries_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ°Õ¡ÕŽÕ¡ÖÕ« }
+_textimageTo_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Ô±ÕµÕ¶Õ¿Õ¥Õ²Õ«Ö Õ€Õ¡Õ·Õ¿Õ«}
+_textimageFrom_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Ô±ÕµÕœÕ¿Õ¥Õ²Õ«Ö Õ€Õ¡Õ·Õ¿Õ«}
+_textimageTopic_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ°Õ¡Õ¿ÕžÖÕ¯ Õ­ÕžÖÕ¡Õ£ÖÕ¥ÖÕ«}
+_textimageBrowse_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕŽÕ¡ÖÕ€Õ¯Õ¡Õ¶Ö Õ¡ÕµÕ¢Õ¢Õ¥Õ¶Õ¡Õ¯Õ¡Õ¶ ÖÕžÖÖÕ¡Õ¯Õš}
+_textimageAcronym_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ Õ¡ÖÖÕžÕ¶Õ«ÕŽÕ¶Õ¥ÖÕš}
+_textimagePhrase_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ¡ÖÕ¿Õ¡Õ°Õ¡ÕµÕ¿ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«}
+_textimageArtist_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ Õ¡ÖÕ¿Õ«ÕœÕ¿Õ¶Õ¥ÖÕ«Õ¶}
+_textimageVolume_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ°Õ¡Õ¿ÕžÖÕ«}
+_textimageCountries_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ ÕšÕœÕ¿ Õ¥ÖÕ¯ÖÕ¶Õ¥ÖÕ«}
+_textimageCaptions_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬ Õ¶Õ¯Õ¡ÖÕ« ÕŽÕ¡Õ¯Õ¡Õ£ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš}
+
+
+_texticontabsearchgreen_ [l=hy] {ÕÖÕžÕ¶ÕžÖÕŽ}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=hy] {ÕÕ¥ÖÕ¶Õ¡Õ£ÖÕ¥Ö Ô±-Õ}
+_texticontabCreatorgreen_ [l=hy] {ÕÕ¥Õ²Õ«Õ¶Õ¡Õ¯Õ¶Õ¥Ö Ô±-Õ}
+_texticontabSubjectgreen_ [l=hy] {Ô±ÕŒÕ¡ÖÕ¯Õ¡Õ¶Õ¥Ö}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=hy] {Ô±ÕŽÕœÕ¡Õ©ÕŸÕ¥Ö}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=hy] {ÕÕ¡ÕµÕ¬Õ« Õ¡Õ¶ÕžÖÕ¶Õ¶Õ¥Ö}
+_texticontabLanguagegreen_ [l=hy] {ÔŒÕ¥ÕŠÕžÖ}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=hy] {Ô¿Õ¡ÕŠÕŽÕ¡Õ¯Õ¥ÖÕºÕžÖÕ©ÕµÕžÖÕ¶}
+_texticontabKeywordgreen_ [l=hy] {Ô²Õ¡Õ¶Õ¡Õ¬Õ« Õ¢Õ¡ÕŒÕ¥Ö}
+_texticontabhowgreen_ [l=hy] {Ô»Õ¶Õ¹ÕºÕ¥Õœ}
+_texticontabseriesgreen_ [l=hy] {ÕÕ¡Õ¿Õ¥Õ¶Õ¡Õ·Õ¡Ö}
+_texticontablistgreen_ [l=hy] {ÕÕžÖÖÕ¡Õ¯}
+_texticontabtogreen_ [l=hy] {Ô±ÕµÕ¶Õ¿Õ¥Õ²}
+_texticontabfromgreen_ [l=hy] {Ô±ÕµÕœÕ¿Õ¥Õ²Õ«Ö}
+_texticontabtopicgreen_ [l=hy] {ÔœÕžÖÕ¡Õ£ÖÕ¥Ö}
+_texticontabbrwsegreen_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬}
+_texticontabPeoplegreen_ [l=hy] {ÕÕ¡ÖÕ€Õ«Õ¯ Ô±-Õ}
+_texticontabAcronymgreen_ [l=hy] {Ô±ÖÖÕžÕ¶Õ«ÕŽÕ¶Õ¥Ö}
+_texticontabPhrasegreen_ [l=hy] {Ô²Õ¡ÕŒÕ¥Ö}
+_texticontabArtistgreen_ [l=hy] {Ô±ÖÕ¿Õ«ÕœÕ¿Õ¶Õ¥Ö}
+_texticontabVolumegreen_ [l=hy] {ÕÕ¡Õ¿ÕžÖÕ¶Õ¥Ö}
+_texticontabCaptionsgreen_ [l=hy] {ÕÕ¡Õ¯Õ¡Õ£ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö}
+_texticontabCountriesgreen_ [l=hy] {ÔµÖÕ¯ÖÕ¶Õ¥Ö}
+
+_texticontext_ [l=hy] {ÔŽÕ«Õ¿Õ¥Õ¬ ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš}
+_texticonclosedbook_ [l=hy] {Õ¢Õ¡ÖÕ¥Ö Õ¡ÕµÕœ ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš Ö Õ€Õ«Õ¿Õ¥Ö Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õš}
+_texticonnext_ [l=hy] {Õ°Õ¡Õ»ÕžÖÕ€ Õ¢Õ¡ÕªÕ«Õ¶}
+_texticonprev_ [l=hy] {Õ¶Õ¡Õ­ÕžÖÕ€ Õ¢Õ¡ÕªÕ«Õ¶}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=hy] {ÔŽÕ«Õ¿Õ¥Ö MIDI ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš}
+_texticonmsword_ [l=hy] {ÔŽÕ«Õ¿Õ¥Ö ÕÕ¡ÕµÖÖÕžÕœÕžÖÕ© ÕÖÕžÖÕ€ ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš:}
+_texticonmp3_ [l=hy] {ÔŽÕ«Õ¿Õ¥Ö MP3 ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš}
+_texticonpdf_ [l=hy] {ÔŽÕ«Õ¿Õ¥Ö PDF ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš}
+_texticonps_ [l=hy] {ÔŽÕ«Õ¿Õ¥Ö PostScript ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš}
+_texticonppt_ [l=hy] {ÔŽÕ«Õ¿Õ¥Ö PowerPoint ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš}
+_texticonrtf_ [l=hy] {ÔŽÕ«Õ¿Õ¥Ö RTF ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš}
+_texticonxls_ [l=hy] {ÔŽÕ«Õ¿Õ¥Õ¬ ÕÕ¡ÕµÖÖÕžÕœÕžÖÕ© Ô·ÖÕœÕ¥Õ¬  ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš}
+
+_page_ [l=hy] {Õ§Õ»}
+_pages_ [l=hy] {Õ§Õ»Õ¥Ö}
+_of_ [l=hy] {Õ«Ö}
+_vol_ [l=hy] {ÕÕ¡Õ¿ÕžÖ}
+_num_ [l=hy] {ÕÕŽ.}
+
+_textmonth00_ [l=hy] {}
+_textmonth01_ [l=hy] {ÕÕžÖÕ¶ÕŸÕ¡Ö}
+_textmonth02_ [l=hy] {ÕÕ¥Õ¿ÖÕŸÕ¡Ö}
+_textmonth03_ [l=hy] {ÕÕ¡ÖÕ¿}
+_textmonth04_ [l=hy] {Ô±ÕºÖÕ«Õ¬}
+_textmonth05_ [l=hy] {ÕÕ¡ÕµÕ«Õœ}
+_textmonth06_ [l=hy] {ÕÕžÖÕ¶Õ«Õœ}
+_textmonth07_ [l=hy] {ÕÕžÖÕ¬Õ«Õœ}
+_textmonth08_ [l=hy] {ÕÕ£ÕžÕœÕ¿ÕžÕœ}
+_textmonth09_ [l=hy] {ÕÕ¥ÕºÕ¿Õ¥ÕŽÕ¢Õ¥Ö}
+_textmonth10_ [l=hy] {ÕÕžÕ¯Õ¿Õ¥ÕŽÕ¢Õ¥Ö}
+_textmonth11_ [l=hy] {ÕÕžÕµÕ¥ÕŽÕ¢Õ¥Ö}
+_textmonth12_ [l=hy] {ÔŽÕ¥Õ¯Õ¿Õ¥ÕŽÕ¢Õ¥Ö}
+
+_textdocument_ [l=hy] {ÕÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©}
+_textsection_ [l=hy] {Ô²Õ¡ÕªÕ«Õ¶}
+_textparagraph_ [l=hy] {ÕÕ¡ÖÕ¡Õ£ÖÕ¡Ö}
+
+_magazines_ [l=hy] {Ô±ÕŽÕœÕ¡Õ£ÖÕ¥Ö}
+
+_nzdlpagefooter_ [l=hy] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">ÕÕžÖ Ô¶Õ¥Õ¬Õ¡Õ¶Õ€Õ«Õ¡ÕµÕ« Õ©ÕŸÕ¡ÕµÕ«Õ¶ Õ£ÖÕ¡Õ€Õ¡ÖÕ¡Õ¶Õ« Õ¶Õ¡Õ­Õ¡Õ£Õ«Õ®</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">ÕÕ¡ÕŽÕ¡Õ¯Õ¡ÖÕ£Õ¹Õ¡ÕµÕ«Õ¶ Õ£Õ«Õ¿ÕžÖÕ©ÕµÕ¡Õ¶ Õ¢Õ¡ÕªÕ¡Õ¶ÕŽÕžÖÕ¶Ö</a>, 
+<a href="http://www.waikato.ac.nz">ÕÕ¡ÕµÕ¯Õ¡Õ¿ÕžÕ« Õ°Õ¡ÕŽÕ¡Õ¬ÕœÕ¡ÖÕ¡Õ¶</a>, 
+ÕÕžÖ Ô¶Õ¥Õ¬Õ¡Õ¶Õ€Õ«Õ¡}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÕÕžÖÕ¶" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=hy] {_httpimg_/hy/chomeof.gif}
+_httpiconchomeon_ [l=hy] {_httpimg_/hy/chomeon.gif}
+
+## "ÕÕ£Õ¶ÕžÖÕ©ÕµÕžÖÕ¶" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=hy] {_httpimg_/hy/chelpof.gif}
+_httpiconchelpon_ [l=hy] {_httpimg_/hy/chelpon.gif}
+
+## "ÕÔ±ÔœÔ±ÕÔ±ÕÕÕÕÔ¹Õ
+ÕÕÕÕÔµÕ" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=hy] {_httpimg_/hy/cprefof.gif}
+_httpiconcprefon_ [l=hy] {_httpimg_/hy/cprefon.gif}
+
+## "ÕÖÕÔ±ÕÔ¿Ô»Õ Ô¿Ô±ÕÔŸÔ»Õ" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=hy] {_httpimg_/hy/cusabof.gif}
+_httpiconcusabon_ [l=hy] {_httpimg_/hy/cusabon.gif}
+
+
+## "ÕžÖÕžÕ¶ÕžÖÕŽ" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=hy] {_httpimg_/hy/tsrchgr.gif}
+_httpicontsrchof_ [l=hy] {_httpimg_/hy/tsrchof.gif}
+_httpicontsrchon_ [l=hy] {_httpimg_/hy/tsrchon.gif}
+_widthtsrchx_ [l=hy] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ¥Ö Õ¡-Ö" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=hy] {_httpimg_/hy/ttitlgr.gif}
+_httpiconttitleof_ [l=hy] {_httpimg_/hy/ttitlof.gif}
+_httpiconttitleon_ [l=hy] {_httpimg_/hy/ttitlon.gif}
+_widthttitlex_ [l=hy] {87}
+
+# Not true DC, kept for legacy reasons
+## "Õ°Õ¥Õ²Õ«Õ¶Õ¡Õ¯Õ¶Õ¥Ö Õ¡-Ö" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=hy] {_httpimg_/hy/tauthgr.gif}
+_httpicontcreatof_ [l=hy] {_httpimg_/hy/tauthof.gif}
+_httpicontcreaton_ [l=hy] {_httpimg_/hy/tauthon.gif}
+_widthtcreatx_ [l=hy] {110}
+
+## "Õ¡ÕŒÕ¡ÖÕ¯Õ¡Õ¶Õ¥Ö" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=hy] {_httpimg_/hy/tsubjgr.gif}
+_httpicontsubjon_ [l=hy] {_httpimg_/hy/tsubjon.gif}
+_httpicontsubjof_ [l=hy] {_httpimg_/hy/tsubjof.gif}
+_widthtsubjx_ [l=hy] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "Õ¡ÕŽÕœÕ¡Õ©ÕŸÕ¥Ö" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=hy] {_httpimg_/hy/tdategr.gif}
+_httpicontdateof_ [l=hy] {_httpimg_/hy/tdateof.gif}
+_httpicontdateon_ [l=hy] {_httpimg_/hy/tdateon.gif}
+_widthtdatex_ [l=hy] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "ÖÕ¡ÕµÕ¬Õ« Õ¡Õ¶ÕžÖÕ¶Õ¶Õ¥Ö" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=hy] {_httpimg_/hy/tsrcgr.gif}
+_httpicontsrcof_ [l=hy] {_httpimg_/hy/tsrcof.gif}
+_httpicontsrcon_ [l=hy] {_httpimg_/hy/tsrcon.gif}
+_widthtsrcx_ [l=hy] {87}
+
+## "Õ¬Õ¥ÕŠÕžÖ" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=hy] {_httpimg_/hy/tlanggr.gif}
+_httpicontlangon_ [l=hy] {_httpimg_/hy/tlangon.gif}
+_httpicontlangof_ [l=hy] {_httpimg_/hy/tlangof.gif}
+_widthtlangx_ [l=hy] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "ÕŽÕ¡Õ¿Õ¥Õ¶Õ¡Õ·Õ¡Ö" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=hy] {_httpimg_/hy/tsergr.gif}
+_httpicontserof_ [l=hy] {_httpimg_/hy/tserof.gif}
+_httpicontseron_ [l=hy] {_httpimg_/hy/tseron.gif}
+_widthtserx_ [l=hy] {87}
+
+## "Õ¡ÕµÕ¶Õ¿Õ¥Õ²" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=hy] {_httpimg_/hy/ttogr.gif}
+_httpiconttoon_ [l=hy] {_httpimg_/hy/ttoon.gif}
+_httpiconttoof_ [l=hy] {_httpimg_/hy/ttoof.gif}
+_widthttox_ [l=hy] {87}
+
+## "Õ¡ÕµÕœÕ¿Õ¥Õ²Õ«Ö" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=hy] {_httpimg_/hy/tfromgr.gif}
+_httpicontfromon_ [l=hy] {_httpimg_/hy/tfromon.gif}
+_httpicontfromof_ [l=hy] {_httpimg_/hy/tfromof.gif}
+_widthtfromx_ [l=hy] {87}
+
+## "Õ¯Õ¡ÕŠÕŽÕ¡Õ¯Õ¥ÖÕºÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=hy] {_httpimg_/hy/torggr.gif}
+_httpicontorgon_ [l=hy] {_httpimg_/hy/torgon.gif}
+_httpicontorgof_ [l=hy] {_httpimg_/hy/torgof.gif}
+_widthtorgx_ [l=hy] {114}
+
+## "Õ«Õ¶Õ¹ÕºÕ¥Õœ" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=hy] {_httpimg_/hy/thowgr.gif}
+_httpiconthowon_ [l=hy] {_httpimg_/hy/thowon.gif}
+_httpiconthowof_ [l=hy] {_httpimg_/hy/thowof.gif}
+_widththowx_ [l=hy] {87}
+
+## "Õ­ÕžÖÕ¡Õ£Õ«Ö" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=hy] {_httpimg_/hy/ttopicgr.gif}
+_httpiconttopicon_ [l=hy] {_httpimg_/hy/ttopicon.gif}
+_httpiconttopicof_ [l=hy] {_httpimg_/hy/ttopicof.gif}
+_widthttopicx_ [l=hy] {87}
+
+## "Õ©Õ¥ÖÕ©Õ¥Õ¬" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=hy] {_httpimg_/hy/tbrwsegr.gif}
+_httpicontbrwseon_ [l=hy] {_httpimg_/hy/tbrwseon.gif}
+_httpicontbrwseof_ [l=hy] {_httpimg_/hy/tbrwseof.gif}
+_widthtbrwsex_ [l=hy] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "ÕŽÕ¡ÖÕ€Õ«Õ¯" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=hy] {_httpimg_/hy/tpeopgr.gif}
+_httpicontpeopof_ [l=hy] {_httpimg_/hy/tpeopof.gif}
+_httpicontpeopon_ [l=hy] {_httpimg_/hy/tpeopon.gif}
+_widthtpeopx_ [l=hy] {97}
+
+## "Õ¡ÖÖÕžÕ¶Õ«ÕŽ" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=hy] {_httpimg_/hy/tacrogr.gif}
+_httpicontacroof_ [l=hy] {_httpimg_/hy/tacroof.gif}
+_httpicontacroon_ [l=hy] {_httpimg_/hy/tacroon.gif}
+_widthtacrox_ [l=hy] {87}
+
+## "Õ¡ÖÕ¿Õ¡Õ°Õ¡ÕµÕ¿ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=hy] {_httpimg_/hy/tphrsegr.gif}
+_httpicontphrseof_ [l=hy] {_httpimg_/hy/tphrseof.gif}
+_httpicontphrseon_ [l=hy] {_httpimg_/hy/tphrseon.gif}
+_widthtphrsex_ [l=hy] {87}
+
+## "Õ¡ÖÕ¿Õ«ÕœÕ¿Õ¶Õ¥Ö" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=hy] {_httpimg_/hy/tartstgr.gif}
+_httpicontartstof_ [l=hy] {_httpimg_/hy/tartstof.gif}
+_httpicontartston_ [l=hy] {_httpimg_/hy/tartston.gif}
+_widthtartstx_ [l=hy] {87}
+
+## "Õ¢Õ¡Õ¶Õ¡Õ¬Õ« Õ¢Õ¡ÕŒÕ¥Ö" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=hy] {_httpimg_/hy/tkwgr.gif}
+_httpicontkwof_ [l=hy] {_httpimg_/hy/tkwof.gif}
+_httpicontkwon_ [l=hy] {_httpimg_/hy/tkwon.gif}
+_widthtkwx_ [l=hy] {87}
+
+## "Õ°Õ¡Õ¿ÕžÖÕ¶Õ¥Ö" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=hy] {_httpimg_/hy/tvolgr.gif}
+_httpicontvolof_ [l=hy] {_httpimg_/hy/tvolof.gif}
+_httpicontvolon_ [l=hy] {_httpimg_/hy/tvolon.gif}
+_widthtvolx_ [l=hy] {87}
+
+## "ÕŽÕ¡Õ¯Õ¡Õ£ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=hy] {_httpimg_/hy/tcaptgr.gif}
+_httpicontcaptof_ [l=hy] {_httpimg_/hy/tcaptof.gif}
+_httpicontcapton_ [l=hy] {_httpimg_/hy/tcapton.gif}
+_widthtcaptx_ [l=hy] {87}
+
+## "Õ¥ÖÕ¯ÖÕ¶Õ¥Ö" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=hy] {_httpimg_/hy/tcountgr.gif}
+_httpicontcountof_ [l=hy] {_httpimg_/hy/tcountof.gif}
+_httpicontcounton_ [l=hy] {_httpimg_/hy/tcounton.gif}
+_widthtcountx_ [l=hy] {87}
+
+## "Ö
+Õ£Õ¶ÕžÖÕ©ÕµÕžÖÕ¶" ## green_title ## h_help ##
+_httpiconhhelp_ [l=hy] {_httpimg_/hy/h\_help.gif}
+_widthhhelp_ [l=hy] {200}
+_heighthhelp_ [l=hy] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=hy] {Ô±ÕµÕœ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ« ÕŽÕ¡ÕœÕ«Õ¶}
+
+_textsubcols1_ [l=hy] {<p>ÕÕ²Õ» Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶ ÕºÕ¡ÖÕžÖÕ¶Õ¡Õ¯ÕžÖÕŽ Õ§ _1_ Õ¥Õ¶Õ©Õ¡Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥Ö: 
+ÕÕ¡ÕœÕ¡Õ¶Õ¥Õ¬Õ«Õ¶Õ¥ÖÕ¶ Õ¥Õ¶`
+<blockquote>}
+
+_textsubcols2_ [l=hy] {</blockquote>
+ÔŽÕžÖ Õ¯Õ¡ÖÕžÕ² Õ¥Õœ ÕœÕ¿ÕžÖÕ£Õ¥Õ¬ Õ©Õ¥ ÕžÖ Õ¥Õ¶Õ©Õ¡Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥ÖÕ¶ Õ¥Õœ 
+Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®ÕžÖÕŽ ÕÕ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ« Õ§Õ»ÕžÖÕŽ:}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÕŽÕ¡ÕœÕ«Õ¶" ## green_title ## h_about ##
+_httpiconhabout_ [l=hy] {_httpimg_/hy/h\_about.gif}
+_widthhabout_ [l=hy] {200}
+_heighthabout_ [l=hy] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=hy] {ÕÕ¥ÖÕ¶Õ¡Õ£ÖÕ¥Ö Ô±-Õ}
+_texticonhcreat_ [l=hy] {ÕÕ¥Õ²Õ«Õ¶Õ¡Õ¯Õ¶Õ¥Ö Ô±-Õ}
+_texticonhsubj_ [l=hy] {Ô±ÕŒÕ¡ÖÕ¯Õ¡Õ¶Õ¥Ö}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=hy] {Ô±ÕŽÕœÕ¡Õ©ÕŸÕ¥Ö}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=hy] {ÕÕ¡ÕµÕ¬Õ« Õ¡Õ¶ÕžÖÕ¶Õ¶Õ¥Ö}
+_texticonhlang_ [l=hy] {ÔŒÕ¥ÕŠÕžÖÕ¶Õ¥Ö}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=hy] {Ô±ÕµÕ¶Õ¿Õ¥Õ²}
+_texticonhfrom_ [l=hy] {Ô±ÕµÕœÕ¿Õ¥Õ²Õ«Ö}
+_texticonhser_ [l=hy] {ÕÕ¡Õ¿Õ¥Õ¶Õ¡Õ·Õ¡Ö}
+_texticonhhow_ [l=hy] {Ô»Õ¶Õ¹ÕºÕ¥Õœ}
+_texticonhorg_ [l=hy] {Ô¿Õ¡ÕŠÕŽÕ¡Õ¯Õ¥ÖÕºÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö}
+_texticonhbrwse_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬}
+_texticonhbrows_ [l=hy] {Ô¹Õ¥ÖÕ©Õ¥Õ¬}
+_texticonhpeople_ [l=hy] {ÕÕ¡ÖÕ€Õ«Õ¯ Ô±-Õ}
+_texticonhacronym_ [l=hy] {Ô±ÖÖÕžÕ¶Õ«ÕŽÕ¶Õ¥Ö}
+_texticonhphrases_ [l=hy] {Ô±ÖÕ¿Õ¡Õ°Õ¡ÕµÕ¿ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö}
+_texticonhartist_ [l=hy] {Ô±ÖÕ¿Õ«ÕœÕ¿Õ¶Õ¥Ö}
+_texticonhkw_ [l=hy] {Ô²Õ¡Õ¶Õ¡Õ¬Õ« Õ¢Õ¡ÕŒÕ¥Ö}
+_texticonhvol_ [l=hy] {ÕÕ¡Õ¿ÕžÖÕ¶Õ¥Ö}
+_texticonhcapt_ [l=hy] {ÕÕ¡Õ¯Õ¡Õ£ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö}
+_texticonhcount_ [l=hy] {ÔµÖÕ¯ÖÕ¶Õ¥Ö}
+
+_texticonopenbookshelf_ [l=hy] {ÖÕ¡Õ¯Õ«Ö Õ£ÖÕ¡Õ€Õ¡ÖÕ¡Õ¶Õ« Õ¡ÕµÕœ Õ¢Õ¡ÕªÕ«Õ¶Õš}
+_texticonclosedbookshelf_ [l=hy] {Õ¢Õ¡ÖÕ«Ö Õ£ÖÕ¡Õ€Õ¡ÖÕ¡Õ¶Õ« Õ¡ÕµÕœ Õ¢Õ¡ÕªÕ«Õ¶Õš Ö Õ€Õ«Õ¿Õ«Ö Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õš}
+_texticonopenbook_ [l=hy] {ÖÕ¡Õ¯Õ«Ö Õ¡ÕµÕœ Õ£Õ«ÖÖÕš}
+_texticonclosedfolder_ [l=hy] {Ô²Õ¡ÖÕ«Ö Õ¡ÕµÕœ Õ©Õ²Õ©Õ¡ÕºÕ¡Õ¶Õ¡Õ¯Õš Ö Õ€Õ«Õ¿Õ«Ö Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õš}
+_texticonclosedfolder2_ [l=hy] {Õ¢Õ¡ÖÕ«Ö Õ¥Õ¶Õ©Õ¡Õ¢Õ¡ÕªÕ«Õ¶Õš}
+_texticonopenfolder_ [l=hy] {ÖÕ¡Õ¯Õ«Ö Õ¡ÕµÕœ Õ©Õ²Õ©Õ¡ÕºÕ¡Õ¶Õ¡Õ¯Õš}
+_texticonopenfolder2_ [l=hy] {ÖÕ¡Õ¯Õ«Ö Õ¥Õ¶Õ©Õ¡Õ¢Õ¡ÕªÕ«Õ¶Õš}
+_texticonsmalltext_ [l=hy] {Õ€Õ«Õ¿Õ«Ö Õ¿Õ¥ÖÕœÕ¿Õ« Õ¡ÕµÕœ Õ¢Õ¡ÕªÕ«Õ¶Õš}
+_texticonsmalltext2_ [l=hy] {Õ€Õ«Õ¿Õ«Ö Õ¿Õ¥ÖÕœÕ¿Õš}
+_texticonpointer_ [l=hy] {ÕšÕ¶Õ©Õ¡ÖÕ«Õ¯ Õ¢Õ¡ÕªÕ«Õ¶}
+_texticondetach_ [l=hy] {Ô²Õ¡ÖÕ«Ö Õ¡ÕµÕœ Õ§Õ»Õš Õ¶ÕžÖ ÕºÕ¡Õ¿ÕžÖÕ°Õ¡Õ¶ÕžÖÕŽ}
+_texticonhighlight_ [l=hy] {ÔžÕ¶Õ€Õ£Õ®Õ«Ö ÖÕ¶Õ¿ÖÕŸÕžÕ² Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥ÖÕš}
+_texticonnohighlight_ [l=hy] {ÕÕ« Õ£ÕžÖÕ¶Õ¡ÖÕžÕ­Õ«Ö ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥ÖÕš}
+_texticoncontracttoc_ [l=hy] {ÕÕ¥Õ²ÕŽÕ«Ö Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õš}
+_texticonexpandtoc_ [l=hy] {ÔžÕ¶Õ€Õ¬Õ¡ÕµÕ¶Õ«Ö Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õš}
+_texticonexpandtext_ [l=hy] {Ô±ÖÕ¿Õ¡Õ®Õ«Ö ÕžÕ²Õ» Õ¿Õ¥ÖÕœÕ¿Õš}
+_texticoncontracttext_ [l=hy] {Ô±ÖÕ¿Õ¡Õ®Õ«Ö ÕŽÕ«Õ¡ÕµÕ¶ ÕšÕ¶Õ¿ÖÕŸÕ¡Õ® ÕšÕ¶Õ©Õ¡ÖÕ«Õ¯ Õ¢Õ¡ÕªÕ¶Õ« Õ°Õ¡ÕŽÕ¡Ö}
+_texticonwarning_ [l=hy] {<b>Ô¶Õ£ÕžÖÕ·Õ¡ÖÕžÖÕŽ: </b>}
+_texticoncont_ [l=hy] {ÕÕ¡ÖÕžÖÕ¶Õ¡Õ¯Õ¥ÕÕ¬}
+
+_textltwarning_ [l=hy] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Ô±ÕµÕœÕ¿Õ¥Õ² Õ¿Õ¥ÖÕœÕ¿Õš ÕšÕ¶Õ€Õ¬Õ¡ÕµÕ¶Õ¥Õ¬ÕžÕŸ, Õ¯Õ°Õ¡Õ¶Õ£Õ¥ÖÕ¶Õ« Õ¿ÕŸÕµÕ¡Õ¬Õ¶Õ¥ÖÕ« 
+ÕŽÕ¥Õ® ÖÕ¡Õ¶Õ¡Õ¯Õ« Õ¡ÖÕ¿Õ¡Õ®ÕŽÕ¡Õ¶ _imagecont_
+</td></tr></table></center>}
+
+_textgoto_ [l=hy] {Õ£Õ¶Õ¡ Õ§Õ»}
+_textintro_ [l=hy] {<i>(Õ¶Õ¥ÖÕ¡Õ®Õ¡Õ¯Õ¡Õ¶ Õ¿Õ¥ÖÕœÕ¿)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ¥Ö Õ¡-Ö" ## green_title ## h_title ##
+_httpiconhtitle_ [l=hy] {_httpimg_/hy/h\_title.gif}
+_widthhtitle_ [l=hy] {200}
+_heighthtitle_ [l=hy] {57}
+
+# Not true DC, kept for legacy reasons
+## "Õ°Õ¥Õ²Õ«Õ¶Õ¡Õ¯Õ¶Õ¥Ö Õ¡-Ö" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=hy] {_httpimg_/hy/h\_auth.gif}
+_widthhcreat_ [l=hy] {200}
+_heighthcreat_ [l=hy] {57}
+
+## "Õ¡ÕŒÕ¡ÖÕ¯Õ¡Õ¶Õ¥Ö" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=hy] {_httpimg_/hy/h\_subj.gif}
+_widthhsubj_ [l=hy] {200}
+_heighthsubj_ [l=hy] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "Õ¡ÕŽÕœÕ¡Õ©ÕŸÕ¥Ö" ## green_title ## h_date ##
+_httpiconhdate_ [l=hy] {_httpimg_/hy/h\_date.gif}
+_widthhdate_ [l=hy] {200}
+_heighthdate_ [l=hy] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "ÖÕ¡ÕµÕ¬Õ« Õ¡Õ¶ÕžÖÕ¶Õ¶Õ¥Ö" ## green_title ## h_src ##
+_httpiconhsrc_ [l=hy] {_httpimg_/hy/h\_src.gif}
+_widthhsrc_ [l=hy] {200}
+_heighthsrc_ [l=hy] {57}
+
+## "Õ¬Õ¥ÕŠÕžÖÕ¶Õ¥Ö" ## green_title ## h_lang ##
+_httpiconhlang_ [l=hy] {_httpimg_/hy/h\_lang.gif}
+_widthhlang_ [l=hy] {200}
+_heighthlang_ [l=hy] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "Õ¡ÕµÕ¶Õ¿Õ¥Õ²" ## green_title ## h_to ##
+_httpiconhto_ [l=hy] {_httpimg_/hy/h\_to.gif}
+_widthhto_ [l=hy] {200}
+_heighthto_ [l=hy] {57}
+
+## "Õ¡ÕµÕœÕ¿Õ¥Õ²Õ«Ö" ## green_title ## h_from ##
+_httpiconhfrom_ [l=hy] {_httpimg_/hy/h\_from.gif}
+_widthhfrom_ [l=hy] {200}
+_heighthfrom_ [l=hy] {57}
+
+## "ÕŽÕ¡Õ¿Õ¥Õ¶Õ¡Õ·Õ¡Ö" ## green_title ## h_ser ##
+_httpiconhser_ [l=hy] {_httpimg_/hy/h\_ser.gif}
+_widthhser_ [l=hy] {200}
+_heighthser_ [l=hy] {57}
+
+## "Õ«Õ¶Õ¹ÕºÕ¥Õœ" ## green_title ## h_how ##
+_httpiconhhow_ [l=hy] {_httpimg_/hy/h\_how.gif}
+_widthhhow_ [l=hy] {200}
+_heighthhow_ [l=hy] {57}
+
+## "Õ­ÕžÖÕ¡Õ£ÖÕ¥Ö" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=hy] {_httpimg_/hy/h\_topic.gif}
+_widthhtopic_ [l=hy] {200}
+_heighthtopic_ [l=hy] {57}
+
+## "Õ¯Õ¡ÕŠÕŽÕ¡Õ¯Õ¥ÖÕºÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö" ## green_title ## h_org ##
+_httpiconhorg_ [l=hy] {_httpimg_/hy/h\_org.gif}
+_widthhorg_ [l=hy] {250}
+_heighthorg_ [l=hy] {57}
+
+## "Õ©Õ¥ÖÕ©Õ¥Õ¬" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=hy] {_httpimg_/hy/h\_brwse.gif}
+_widthhbrwse_ [l=hy] {200}
+_heighthbrwse_ [l=hy] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "ÕŽÕ¡ÖÕ€Õ«Õ¯" ## green_title ## h_people ##
+_httpiconhpeople_ [l=hy] {_httpimg_/hy/h\_people.gif}
+_widthhpeople_ [l=hy] {200}
+_heighthpeople_ [l=hy] {57}
+
+## "Õ¡ÖÖÕžÕ¶Õ«ÕŽÕ¶Õ¥Ö" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=hy] {_httpimg_/hy/h\_acro.gif}
+_widthhacronym_ [l=hy] {200}
+_heighthacronym_ [l=hy] {57}
+
+## "Õ¡ÖÕ¿Õ¡Õ°Õ¡ÕµÕ¿ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=hy] {_httpimg_/hy/h\_phrse.gif}
+_widthhphrse_ [l=hy] {200}
+_heighthphrse_ [l=hy] {57}
+
+## "Õ¡ÖÕ¿Õ«ÕœÕ¿Õ¶Õ¥Ö" ## green_title ## h_artist ##
+_httpiconhartist_ [l=hy] {_httpimg_/hy/h\_artist.gif}
+_widthhartist_ [l=hy] {200}
+_heighthartist_ [l=hy] {57}
+
+## "Õ¢Õ¡Õ¶Õ¡Õ¬Õ« Õ¢Õ¡ÕŒÕ¥Ö" ## green_title ## h_kw ##
+_httpiconhkw_ [l=hy] {_httpimg_/hy/h\_kw.gif}
+_widthhkw_ [l=hy] {200}
+_heighthkw_ [l=hy] {57}
+
+## "Õ°Õ¡Õ¿ÕžÖÕ¶Õ¥Ö" ## green_title ## h_vol ##
+_httpiconhvol_ [l=hy] {_httpimg_/hy/h\_vol.gif}
+_widthhvol_ [l=hy] {200}
+_heighthvol_ [l=hy] {57}
+
+## "Õ¥ÖÕ¯ÖÕ¶Õ¥Ö" ## green_title ## h_count ##
+_httpiconhcount_ [l=hy] {_httpimg_/hy/h\_count.gif}
+_widthhcount_ [l=hy] {200}
+_heighthcount_ [l=hy] {57}
+
+## "ÕŽÕ¡Õ¯Õ¡Õ£ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=hy] {_httpimg_/hy/h\_capt.gif}
+_widthhcapt_ [l=hy] {200}
+_heighthcapt_ [l=hy] {57}
+
+
+## "ÕÔ±ÕÕÕÕÔ±Ô¿ÔµÕÔŒ?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=hy] {_httpimg_/hy/contof.gif}
+_httpiconconton_ [l=hy] {_httpimg_/hy/conton.gif}
+
+## "ÔžÕÔŽÔŒÔ±Õ
+ÕÔµÔŒ\nÕÔµÕÕÕÔž" ## document_button ## eallt ##
+_httpiconealltof_ [l=hy] {_httpimg_/hy/ealltof.gif}
+_httpiconeallton_ [l=hy] {_httpimg_/hy/eallton.gif}
+
+## "ÕÔµÕÕÔµÔŒ\nÔ²ÕÕÔ±ÕÔŽÔ±Ô¿ÕÕÔ¹Õ
+ÕÕÕÔž" ## document_button ## econc ##
+_httpiconeconcof_ [l=hy] {_httpimg_/hy/econcof.gif}
+_httpiconeconcon_ [l=hy] {_httpimg_/hy/econcon.gif}
+
+## "Ô±ÕÔ±ÕÕÕÔ±ÕÕÔµÔŒ" ## document_button ## edtch ##
+_httpiconedtchof_ [l=hy] {_httpimg_/hy/edtchof.gif}
+_httpiconedtchon_ [l=hy] {_httpimg_/hy/edtchon.gif}
+
+## "ÔžÕÔŽÔŒÔ±Õ
+ÕÔµÔŒ\nÔ²ÕÕÔ±ÕÔŽÔ±Ô¿ÕÕÔ¹Õ
+ÕÕÕÔž" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=hy] {_httpimg_/hy/eexpcof.gif}
+_httpiconeexpcon_ [l=hy] {_httpimg_/hy/eexpcon.gif}
+
+## "ÕÔµÕÕÔµÔŒ ÕÔµÕÕÕÔž" ## document_button ## etsec ##
+_httpiconetsecof_ [l=hy] {_httpimg_/hy/etsecof.gif}
+_httpiconetsecon_ [l=hy] {_httpimg_/hy/etsecon.gif}
+
+## "Ô³ÕÕÕÔ±ÕÕÔœÕÕÕ" ## document_button ## ehl ##
+_httpiconehlof_ [l=hy] {_httpimg_/hy/ehlof.gif}
+_httpiconehlon_ [l=hy] {_httpimg_/hy/ehlon.gif}
+
+## "ÕÔ³ÕÕÕÔ±ÕÕÔœÔµÔŒ" ## document_button ## enhl ##
+_httpiconenhlof_ [l=hy] {_httpimg_/hy/enhlof.gif}
+_httpiconenhlon_ [l=hy] {_httpimg_/hy/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=hy] {_If_(_thislast_,results _thisfirst_ - _thislast_ Õ°Õ¡ÖÖÕŽÕ¡Õ¶ Õ°Õ¡ÕŽÕ¡Ö: _cgiargq_,ÕÕ¯Õ¡Õ¶ Õ°Õ¡ÕŽÕšÕ¶Õ¯Õ¶ÕžÖÕŽÕ¶Õ¥Ö Õ°Õ¡ÖÖÕŽÕ¡Õ¶Õš: _cgiargq_)}
+_textnoquerytitle_ [l=hy] {ÕÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ§Õ»}
+
+_texticonthispage_ [l=hy] {ÖÕ¶Õ¿ÖÕžÖÕŽ}
+_textsome_ [l=hy] {ÕžÖÕžÕ·}
+_textall_ [l=hy] {Õ¢ÕžÕ¬ÕžÖÕš}
+_textboolean_ [l=hy] {Õ¢ÕžÖÕ¬ÕµÕ¡Õ¶}
+_textranked_ [l=hy] {Õ£Õ¶Õ¡Õ°Õ¡Õ¿ÕŸÕ¡Õ®}
+_textnatural_ [l=hy] {Õ¢Õ¶Õ¡Õ¯Õ¡Õ¶}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=hy] {}
+_texticonsearchhistorybar_ [l=hy] {ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕŽÕžÖÕ©ÕµÕžÖÕ¶}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=hy] {Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ«Ö Õ¡ÕµÕœ Õ°Õ¡ÖÖÕžÖÕŽÕš}
+_textfreqmsg1_ [l=hy] {Ô²Õ¡ÕŒÕ« Õ°Õ¡Õ·ÕŸÕ«Õ¹}
+_textpostprocess_ [l=hy] {_If_(_quotedquery_,<br><i>Õ°Õ¥Õ¿-Õ£ÕžÖÕ®ÕšÕ¶Õ©Õ¡Ö, ÕžÖÕžÕ¶ÕŽÕ¡Õ¶ Õ°Õ¡ÕŽÕ¡Ö _quotedquery_</i>
+)}
+_textinvalidquery_ [l=hy] {Õ°Õ¡ÖÖÕŽÕ¡Õ¶ ÕœÕ­Õ¡Õ¬ Õ·Õ¡ÖÕ¡Õ°ÕµÕžÖÕœÕžÖÕ©ÕµÕžÖÕ¶}
+
+_textmorethan_ [l=hy] {Ô±ÕŸÕ¥Õ¬Õ«Õ¶}
+_textapprox_ [l=hy] {ÕÕ¡ÕœÕ«Õ¶}
+_textnodocs_ [l=hy] {ÕÕ¯Õ¡Õ¶ Õ°Õ¡ÕŽÕ¡ÕºÕ¡Õ¿Õ¡ÕœÕ­Õ¡Õ¶ÕžÕ² ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥Ö}
+_text1doc_ [l=hy] {1 ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ© Õ§ Õ°Õ¡ÕŽÕ¡ÕºÕ¡Õ¿Õ¡ÕœÕ­Õ¡Õ¶ÕžÖÕŽ Õ°Õ¡ÖÖÕŽÕ¡Õ¶Õš:}
+_textlotsdocs_ [l=hy] {ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš Õ°Õ¡ÕŽÕ¡ÕºÕ¡Õ¿Õ¡ÕœÕ­Õ¡Õ¶ÕžÖÕŽ Õ§ Õ°Õ¡ÖÖÕŽÕ¡Õ¶Õš}
+_textmatches_ [l=hy] {ÕÕ¡ÕŽÕ¡ÕºÕ¡Õ¿Õ¡ÕœÕ­Õ¡Õ¶ÕžÖÕŽ Õ§}
+_textbeginsearch_ [l=hy] {ÕÕ¯ÕœÕ«Ö ÖÕ¶Õ¿ÖÕžÖÕŽÕš}
+_textrunquery_ [l=hy] {Ô¿Õ¡Õ¿Õ¡ÖÕ«Ö Õ°Õ¡ÖÖÕžÖÕŽÕš}
+_textclearform_ [l=hy] {ÕÕ¡ÖÖÕ«Ö Õ±ÖÕš}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=hy] {Ô²Õ¡ÕŒ Õ¯Õ¡ÕŽ Õ¡ÖÕ¿Õ¡Õ°Õ¡ÕµÕ¿ÕžÖÕ©ÕµÕžÖÕ¶}
+_textinfield_ [l=hy] {âŠ Õ€Õ¡Õ·Õ¿ÕžÖÕŽ}
+_textfoldstem_ [l=hy] {(ÕœÕ¥Õ²ÕŽÕ«Õ¹, Õ£Õ¬Õ­Õ«Õ¯)}
+
+_textadvquery_ [l=hy] {Ô¿Õ¡ÕŽ ÕŽÕžÖÕ¿Ö Õ¡ÖÕ¡ Õ°Õ¡ÖÖÕžÖÕŽÕš ÕžÖÕ²Õ²Õ¡Õ¯Õ«ÕžÖÕ¥Õ¶}
+_textallfields_ [l=hy] {Õ¢ÕžÕ¬ÕžÖ Õ€Õ¡Õ·Õ¿Õ¥ÖÕš}
+_texttextonly_ [l=hy] {ÕŽÕ«Õ¡ÕµÕ¶ Õ¿Õ¥ÖÕœÕ¿}
+_textand_ [l=hy] {Ö}
+_textor_ [l=hy] {Õ¯Õ¡ÕŽ}
+_textandnot_ [l=hy] {Ö ÕžÕ¹}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=hy] {ÕÕ¶Õ¿ÖÕ«Ö _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_,  _gselection_ ÕŽÕ¡Õ¯Õ¡ÖÕ€Õ¡Õ¯) _If_(_nselection_, in _nselection_ Õ¬Õ¥ÕŠÕŸÕžÖÕŽ) ÕžÖÕš ÕºÕ¡ÖÕžÖÕ¶Õ¡Õ¯ÕžÖÕŽ Õ§ _querytypeselection_ Õ¢Õ¡ÕŒÕ¥Ö}
+
+_textadvancedsearch_ [l=hy] {ÕÕ¶Õ¿ÖÕžÖÕŽ _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, at _gselection_ level)_If_(_nselection_,  _nselection_ Õ¬Õ¥ÕŠÕŸÕ« ÕŽÕ¥Õ») Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Õ¬ÕžÕŸ _querytypeselection_ Õ°Õ¡ÖÖÕžÖÕŽÕš}
+
+_textformsimplesearch_ [l=hy] {ÕÕ¶Õ¿ÖÕ«Ö _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_, _nselection_ Õ¬Õ¥ÕŠÕŸÕžÖÕŽ) _formquerytypeselection_ Õ°Õ¡ÕŽÕ¡Ö}
+
+_textformadvancedsearch_ [l=hy] {ÕÕ¶Õ¿ÖÕ«Ö _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ Õ¬Õ¥ÕŠÕžÖ )Ö Õ¡ÖÕ¿Õ¡Õ®Õ«Ö Õ¡ÖÕ€ÕµÕžÖÕ¶ÖÕ¶Õ¥ÖÕš _formquerytypeselection_ Õ°Õ¥ÖÕ©Õ¡Õ¯Õ¡Õ¶ÕžÖÕ©ÕµÕ¡ÕŽÕ¢}
+
+
+_textnojsformwarning_ [l=hy] {Ô¶Õ£ÕžÖÕ·Õ¡ÖÕžÖÕŽ: ÕÕž ÕžÕœÕ¿Õ¡ÕµÕ¶Õ« Õ€Õ«Õ¿Õ¡Õ¯ÕžÖÕŽ ÕÕ¡ÕŸÕ¡ÕœÕ¯ÖÕ«ÕºÕ¿Õš Õ¡Õ¶Õ»Õ¡Õ¿ÕŸÕ¡Õ® Õ§: <br>ÕÖÕ¡Õ¹Õ¡ÖÕžÕŸ ÖÕ¶Õ¿ÖÕžÖÕŽ Õ¯Õ¡Õ¿Õ¡ÖÕ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö, ÕŽÕ«Õ¡ÖÖÕžÖ Õ¡ÕµÕ¶:}
+_textdatesearch_ [l=hy] {Ô±ÕµÕœ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶ Õ¯Õ¡ÖÕžÕ² Õ§ Õ®Õ¡ÕŒÕ¡ÕµÕ¥Õ¬ ÖÕ¶Õ¿ÖÕ¥Õ¬ÕžÖ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥Ö Õ¿ÖÕŸÕ¡Õ® Õ¡ÕŽÕœÕ¡Õ©ÕŸÕ¥ÖÕ« Õ¿Õ«ÖÕžÖÕµÕ©ÕžÖÕŽ, Õ¯Õ¡ÕŽ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥Ö ÕžÖÕžÕ¶Ö ÕºÕ¡ÖÕžÖÕ¶Õ¡Õ¯ÕžÖÕŽ Õ¥Õ¶ ÕžÖÕžÕ·Õ¡Õ¯Õ« Õ¡ÕŽÕœÕ¡Õ©Õ«ÕŸ: ÕÕ¡ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕžÕ¹ ÕºÕ¡ÖÕ¿Õ¡Õ€Õ«Ö Õ°Õ¶Õ¡ÖÕ¡ÕŸÕžÖÕžÖÕ©ÕµÕžÖÕ¶ Õ§:}
+_textstartdate_ [l=hy] {ÕÕ¯ÕŠÕ¢Õ« (Õ¯Õ¡ÕŽ ÕŽÕ«Õ¡Õ¯) Õ¡ÕŽÕœÕ¡Õ©Õ«ÕŸ:}
+_textenddate_ [l=hy] {Ô±ÕŽÕœÕ¡Õ©ÕŸÕ« ÕŸÕ¥ÖÕ»:}
+_textbc_ [l=hy] {B.C.E.}
+_textad_ [l=hy] {C.E.}
+_textexplaineras_ [l=hy] {C.E. Ö B.C.E Õ¡ÕµÕ¬ÕšÕ¶Õ¿ÖÕ¡Õ¶ÖÕ¶Õ¥Ö Õ¥Õ¶ ÕŽ.Õ©. Ö ÕŽ.Õ©.Õ¡ Õ°Õ¡ÕŽÕ¡Ö Õ°Õ¡ÕŽÕ¡ÕºÕ¡Õ¿Õ¡ÕœÕ­Õ¡Õ¶Õ¡Õ¢Õ¡Ö: Ô±ÕµÕœ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥ÖÕš ÕŽÕ·Õ¡Õ¯ÕžÖÕ©Õ¡ÕµÕ«Õ¶ Õ¡ÕŒÕžÖÕŽÕžÕŸ Õ­Õ¿ÖÕ¡Õ¯Õ¡Õ¶ÕžÖÕ©ÕµÕžÖÕ¶Õ«Ö ÕŠÕ¥ÖÕ® Õ¥Õ¶, Ö Õ°Õ¡ÕŽÕ¡ÕºÕ¡Õ¿ÕœÕ­Õ¡Õ¶ÕžÖÕŽ Õ¥Õ¶ "ÔžÕ¶Õ©Õ¡ÖÕ«Õ¯ Õ€Õ¡ÖÕ¡Õ·ÖÕ»Õ¡Õ¶" Ö "ÕÕ«Õ¶Õ¹ ÕšÕ¶Õ©Õ¡ÖÕ«Õ¯ Õ€Õ¡ÖÕ¡Õ·ÖÕ»Õ¡Õ¶Õš"}
+
+_textstemon_ [l=hy] {(Õ¡Õ¶Õ¿Õ¥ÕœÕ¥Õ¬ Õ¢Õ¡ÕŒÕ¥ÖÕ« ÕŸÕ¥ÖÕ»Õ¡ÕŸÕžÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš)}
+
+_textsearchhistory_ [l=hy] {ÕÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕŽÕžÖÕ©ÕµÕžÖÕ¶}
+
+#text macros for search history
+_textnohistory_ [l=hy] {ÕÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕŽÕžÖÕ©ÕµÕžÖÕ¶Õš ÕŽÕ¡Õ¿Õ¹Õ¥Õ¬Õ« Õ¹Õ§}
+_texthresult_ [l=hy] {Õ¡ÖÕ€ÕµÕžÖÕ¶Ö}
+_texthresults_ [l=hy] {Õ¡ÖÕ€ÕµÕžÖÕ¶ÖÕ¶Õ¥Ö}
+_texthallwords_ [l=hy] {Õ¢ÕžÕ¬ÕžÖ Õ¢Õ¡ÕŒÕ¥ÖÕš}
+_texthsomewords_ [l=hy] {ÕžÖÕžÕ· Õ¢Õ¡ÕŒÕ¥Ö}
+_texthboolean_ [l=hy] {Õ¢ÕžÖÕ¬ÕµÕ¡Õ¶}
+_texthranked_ [l=hy] {Õ£Õ¶Õ¡Õ°Õ¡Õ¿ÕŸÕ¡Õ®}
+_texthcaseon_ [l=hy] {Õ€Õ¥ÕºÖÕš ÕºÕ¥Õ¿Ö Õ§ Õ°Õ¡ÕŽÕšÕ¶Õ¯Õ¶Õ«}
+_texthcaseoff_ [l=hy] {Õ€Õ¥ÕºÖÕš Õ¡Õ¶Õ¿Õ¥ÕœÕŸÕ¡Õ®}
+_texthstemon_ [l=hy] {ÖÕ¡Õ¯ÕŸÕ¡Õ®}
+_texthstemoff_ [l=hy] {Õ¹ÖÕ¡Õ¯ÕŸÕ¡Õ®}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÖÕ¶Õ¿ÖÕžÖÕŽ" ## green_title ## h_search ##
+_httpiconhsearch_ [l=hy] {_httpimg_/hy/h\_search.gif}
+_widthhsearch_ [l=hy] {200}
+_heighthsearch_ [l=hy] {57}
+
+## "Õ¡ÖÕ€ÕµÕžÖÕ¶ÖÕ¶Õ¥Ö" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=hy] {_httpimg_/hy/qryresb.gif}
+_widthqryresb_ [l=hy] {_pagewidth_}
+_heightqryresb_ [l=hy] {17}
+
+## "ÕºÕ¡Õ¿ÕŽÕžÖÕ©ÕµÕžÖÕ¶" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=hy] {_httpimg_/hy/schhistb.gif}
+_widthsrchhistb_ [l=hy] {_pagewidth_}
+_heightsrchhistb_ [l=hy] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=hy] {ÕÕ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš Õ€ÖÕŸÕ¡Õ® Õ¥Õ¶ Õ°Õ¥Õ¿ÖÕµÕ¡Õ¬ Õ¯Õ¥ÖÕº: ÕÕ« Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ«Ö ÖÕž Õ€Õ«Õ¿Õ¡Õ¯Õ«
+"Õ°Õ¥Õ¿" Õ¯ÕžÕ³Õ¡Õ¯Õš - Õ¡ÕµÕ¶ Õ¯Õ»Õ¶Õ»Õ« Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš! ÕÕžÕ­Õ¡ÖÕ¥Õ¶Õš, ÕœÕ¥Õ²ÕŽÕ«Ö ÕœÕ¿ÕžÖÖ Õ¡ÕŒÕ¯Õ¡
+Õ¯ÕžÕ³Õ¡Õ¯Õ¶Õ¥ÖÕ«Ö ÕžÖÖÕ«ÖÕ¥ ÕŽÕ¥Õ¯Õ« ÕŸÖÕ¡:}
+_textsetprefs_ [l=hy] {Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ« Õ¯Õ¡ÖÕ£Õ¡Õ¢Õ¥ÖÕžÖÕŽ}
+_textsearchprefs_ [l=hy] {ÕÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö}
+_textcollectionprefs_ [l=hy] {ÕÕ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ« Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö}
+_textpresentationprefs_ [l=hy] {ÕÕžÖÖÕ¡Õ€ÖÕŽÕ¡Õ¶ Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö}
+_textpreferences_ [l=hy] {ÕÕ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö}
+_textcasediffs_ [l=hy] {ÔŽÕ¥ÕºÖÕ¥ÖÕ« Õ¿Õ¡ÖÕ¢Õ¥ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö:}
+_textignorecase_ [l=hy] {Õ¡Õ¶Õ¿Õ¥ÕœÕ«Ö Õ€Õ¥ÕºÖÕ¥ÖÕ« Õ¿Õ¡ÖÕ¢Õ¥ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš}
+_textmatchcase_ [l=hy] {ÕŸÕ¥ÖÕ«Õ¶/ÕœÕ¿ÕžÖÕ«Õ¶ Õ€Õ¥ÕºÖÕš ÕºÕ¥Õ¿Ö Õ§ Õ°Õ¡ÕŽÕšÕ¶Õ¯Õ¶Õ«}
+_textwordends_ [l=hy] {Ô²Õ¡ÕŒÕ¥ÖÕ« ÕŸÕ¥ÖÕ»Õ¡ÕŸÕžÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö:}
+_textstem_ [l=hy] {Õ¡Õ¶Õ¿Õ¥ÕœÕ«Ö Õ¢Õ¡ÕŒÕ¥ÖÕ« ÕŸÕ¥ÖÕ»Õ¡ÕŸÕžÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš}
+_textnostem_ [l=hy] {Õ¢Õ¡ÕŒÕš Õ¡ÕŽÕ¢ÕžÕ²Õ»ÕžÕŸÕ«Õ¶ ÕºÕ¥Õ¿Ö Õ§ Õ°Õ¡ÕŽÕšÕ¶Õ¯Õ¶Õ«}
+_textprefop_ [l=hy] {ÕÕ¥ÖÕ¡Õ€Õ¡ÖÕ±Õ«Ö _maxdocoption_ ÖÕ¡Õ¶Õ¡Õ¯Õ«Õ¶, Õ°Õ¡ÕŽÕ¡ÕºÕ¡Õ¿Õ¡ÕœÕ­Õ¡Õ¶Õ¡Õ¢Õ¡Ö _hitsperpageoption_ Õ¡ÖÕ€ÕµÕžÖÕ¶Ö ÕŽÕ¥Õ¯ Õ§Õ»ÕžÖÕŽ:}
+_textextlink_ [l=hy] {ÕÕžÖÕ¿Ö Õ¡ÖÕ¿Õ¡ÖÕ«Õ¶ ÕžÕœÕ¿Õ¡ÕµÕ¶Õ« Õ§Õ»Õ¥ÖÕ«Õ¶}
+_textintlink_ [l=hy] {ÕÕ«ÕŽÕ¶Õ¡Õ¯Õ¡Õ¶ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥Ö Õ£Õ¿Õ¶ÕŸÕ¡Õ®}
+_textlanguage_ [l=hy] {ÕÕ«Õ»Õ¥ÖÕ¥ÕœÕ« Õ¬Õ¥ÕŠÕžÖ:}
+_textencoding_ [l=hy] {Ô¿ÕžÕ€Õ¡ÕŸÕžÖÕžÖÕŽ:}
+_textformat_ [l=hy] {ÕÕ«Õ»Õ¥ÖÕ¥ÕœÕ« ÖÕžÖÕŽÕ¡Õ¿:}
+_textall_ [l=hy] {Õ¡ÕŽÕ¢ÕžÕ²Õ»Õš}
+_textquerymode_ [l=hy] {ÕÕ¡ÖÖÕŽÕ¡Õ¶ ÕŸÕ«Õ³Õ¡Õ¯:}
+_textsimplemode_ [l=hy] {ÕºÕ¡ÖÕŠ Õ°Õ¡ÖÖÕŽÕ¡Õ¶ ÕŸÕ«Õ³Õ¡Õ¯}
+_textadvancedmode_ [l=hy] {Õ­ÕžÖÕ¡ÖÕŸÕ¡Õ® Õ°Õ¡ÖÖÕŽÕ¡Õ¶ ÕŸÕ«Õ³Õ¡Õ¯ (Õ©ÕžÖÕµÕ¬Õ¡Õ¿ÖÕžÖÕŽ Õ§ Õ¢ÕžÖÕ¬ÕµÕ¡Õ¶ ÕžÖÕžÕ¶ÕžÖÕŽÕ¶Õ¥Ö !, &, |, Ö ÖÕ¡Õ¯Õ¡Õ£Õ®Õ¥ÖÕ« Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®ÕŽÕ¡ÕŽÕ¢)}
+_textlinkinterm_ [l=hy] {ÕŽÕ«Õ»Õ¡Õ¶Õ¯ÕµÕ¡Õ¬ Õ§Õ»Õ« ÕŽÕ«Õ»ÕžÕŸ}
+_textlinkdirect_ [l=hy] {ÕžÖÕ²Õ²Õ¡Õ¯Õ« Õ£Õ¶Õ¡ Õ¡ÕµÕ¶Õ¿Õ¥Õ²}
+_textdigitlib_ [l=hy] {Õ©ÕŸÕ¡ÕµÕ«Õ¶ Õ£ÖÕ¡Õ€Õ¡ÖÕ¡Õ¶}
+_textweb_ [l=hy] {ÕžÕœÕ¿Õ¡ÕµÕ¶}
+_textgraphical_ [l=hy] {Ô³ÖÕ¡ÖÕ«Õ¯Õ¡Õ¯Õ¡Õ¶}
+_texttextual_ [l=hy] {ÕÕ¥ÖÕœÕ¿Õ¡ÕµÕ«Õ¶}
+_textcollectionoption_ [l=hy] {<p>
+ÔžÕ¶Õ€Õ£ÖÕ¯ÕŽÕ¡Õ¶ Õ¥Õ¶Õ©Õ¡Õ¯Õ¡ Õ¥Õ¶Õ©Õ¡Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥Ö:
+<br>}
+
+_textrelateddocdisplay_ [l=hy] {Õ¡ÖÕ¿Õ¡Õ®Õ«Ö Õ¯Õ¡ÕºÕŸÕ¡Õ® ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš}
+_textsearchhistory_ [l=hy] {ÕÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕŽÕžÖÕ©ÕµÕžÖÕ¶:}
+_textnohistory_ [l=hy] {ÕÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕŽÕžÖÕ©ÕµÕžÖÕ¶Õ¶ Õ¡ÕŒÕ¯Õ¡ Õ¹Õ§}
+_texthistorydisplay_ [l=hy] {Õ¡ÖÕ¿Õ¡Õ®Õ«Ö _historynumrecords_ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕŽÕžÖÕ©ÕµÕ¡Õ¶ Õ£ÖÕ¡ÕŒÕžÖÕŽÕ¶Õ¥ÖÕš}
+_textnohistorydisplay_ [l=hy] {ÕŽÕ« Õ¡ÖÕ¿Õ¡Õ®Õ«Ö ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕŽÕžÖÕ©ÕµÕžÖÕ¶Õš}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=hy] {ÕÖÕžÕ¶ÕŽÕ¡Õ¶ Õ±Ö:}
+_textplainsearch_ [l=hy] {Ô±ÕŠÕ¡Õ¿ ÖÕ¶Õ¿ÖÕžÖÕŽ:}
+_textqueryboxsize_ [l=hy] {ÕÕ¡ÖÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕžÖÕ°Õ¡Õ¶Õ« Õ¹Õ¡ÖÕš:}
+_textregbox_ [l=hy] {Õ¯Õ¡Õ¶ÕžÕ¶Õ¡ÕŸÕžÖ Õ°Õ¡ÖÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕžÖÕ°Õ¡Õ¶}
+_textbigbox_ [l=hy] {Õ°Õ¡ÖÖÕŽÕ¡Õ¶ ÕŽÕ¥Õ® ÕºÕ¡Õ¿ÕžÖÕ°Õ¡Õ¶}
+_textformtype_ [l=hy] {ÕÕ¥ÕœÕ¡Õ¯Õ« Õ±Ö}
+_textsimple_ [l=hy] {ÕºÕ¡ÖÕŠ}
+_textadvanced_ [l=hy] {Õ­ÕžÖÕ¡ÖÕŸÕ¡Õ®}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=hy] {Õ°Õ¥Õ¿}
+_textfields_ [l=hy] {Õ€Õ¡Õ·Õ¿Õ¥Ö}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö:" ## green_title ## h_pref ##
+_httpiconhpref_ [l=hy] {_httpimg_/hy/h\_pref.gif}
+_widthhpref_ [l=hy] {200}
+_heighthpref_ [l=hy] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=hy] {ÕÕ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕ«Ö ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš ÕšÕœÕ¿}
+_textalsoshowing_ [l=hy] {Õ¶Õ¡Ö ÖÕžÖÕµÖ Õ¿Õ¡Õ¬}
+_textwith_ [l=hy] {Õ¡ÕŒÕ¶ÕŸÕ¡ÕŠÕ¶}
+_textdocsperpage_ [l=hy] {ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ© ÕšÕœÕ¿ Õ§Õ»Õ«}
+
+_textfilterby_ [l=hy] {Ô³Õ¿Õ«Ö ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥Ö` ÕºÕ¡ÖÕžÖÕ¶Õ¡Õ¯ÕžÕ²}
+_textall_ [l=hy] {Õ¢ÕžÕ¬ÕžÖÕš}
+_textany_ [l=hy] {Õ¯Õ¡ÕŽÕ¡ÕµÕ¡Õ¯Õ¡Õ¶}
+_textwords_ [l=hy] {Õ¢Õ¡ÕŒÕ¥Ö}
+_textleaveblank_ [l=hy] {Õ©ÕžÕ² Õ¡ÕµÕœ ÕŸÕ¡Õ¶Õ€Õ¡Õ¯Õš Õ€Õ¡Õ¿Õ¡ÖÕ¯, Õ¢ÕžÕ¬ÕžÖ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš ÕœÕ¿Õ¡Õ¶Õ¡Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö}
+
+_browsebuttontext_ [l=hy] {"ÕÕ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕ«Ö ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš"}
+
+_nodata_ [l=hy] {<i>Õ¿ÕŸÕµÕ¡Õ¬Õ¶Õ¥Ö Õ¹Õ¯Õ¡Õ¶</i>}
+_docs_ [l=hy] {ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥Ö}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=hy] {ÕÕ£Õ¶ÕžÖÕ©ÕµÕžÖÕ¶}
+_textSearchshort_ [l=hy] {ÖÕ¶Õ¿ÖÕžÖÕŽ ÕšÕœÕ¿ ÕžÖÕžÕ·Õ¡Õ¯Õ« Õ¢Õ¡ÕŒÕ¥ÖÕ«  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ«}
+_textCreatorshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ°Õ¥Õ²Õ«Õ¶Õ¡Õ¯Õ«}
+_textSubjectshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ¡ÕŒÕ¡ÖÕ¯Õ¡ÕµÕ«}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ¿Õ¡ÖÕ¥Õ©ÕŸÕ«}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ ÖÕ¡ÕµÕ¬Õ« Õ¡Õ¶ÕŸÕ¡Õ¶ÕžÖÕŽÕ¶Õ¥ÖÕ«}
+_textLanguageshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ¬Õ¥ÕŠÕŸÕ«}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ ÕŽÕ¡Õ¿Õ¥Õ¶Õ¡Õ·Õ¡ÖÕ«}
+_textToshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Ô±ÕµÕ¶Õ¿Õ¥Õ²Õ«Ö Õ€Õ¡Õ·Õ¿Õ«}
+_textFromshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Ô±ÕµÕœÕ¿Õ¥Õ²Õ«Ö Õ€Õ¡Õ·Õ¿Õ«}
+_textBrowseshort_ [l=hy] {Õ©Õ¥ÖÕ©Õ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš}
+_textOrganizationshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ¯Õ¡ÕŠÕŽÕ¡Õ¯Õ¥ÖÕºÕžÖÕ©ÕµÕ¡Õ¶}
+_textHowtoshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ "Õ«Õ¶Õ¹ÕºÕ¥Õœ" ÖÕžÖÖÕ¡Õ¯Õ«}
+_textTopicshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ©Õ¥ÕŽÕ¡ÕµÕ«}
+_textPeopleshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ ÕŽÕ¡ÖÕ€Õ¯Õ¡Õ¶Ö}
+_textAcronymshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ¡ÖÖÕžÕ¶Õ«ÕŽÕ¶Õ¥ÖÕ« Õ°Õ¡Õ¶Õ€Õ«ÕºÕŽÕ¡Õ¶}
+_textPhraseshort_ [l=hy] {Õ©Õ¥ÖÕ©Õ«Ö Õ¢Õ¡ÕŒÕ¥ÖÕš, ÕžÖÕžÕ¶Ö Õ°Õ¡Õ¶Õ€Õ«ÕºÕžÖÕŽ Õ¥Õ¶ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕžÖÕŽ}
+_textArtistshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ¡ÖÕ¿Õ«ÕœÕ¿Õ«}
+_textKeywordshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ¢Õ¡Õ¶Õ¡Õ¬Õ« Õ¢Õ¡ÕŒÕ«}
+_textVolumeshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ°Õ¡Õ¿ÕžÖÕ«}
+_textCountriesshort_ [l=hy] {ÕŽÕžÖÕ¿Ö Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö ÕšÕœÕ¿ Õ¥ÖÕ¯ÖÕ«}
+_textdefaultshorttext_ [l=hy] {Õ¹ÕœÕ¡Õ°ÕŽÕ¡Õ¶ÕŸÕ¡Õ® Õ€Õ¡ÕœÕ¡Õ¯Õ¡ÖÕ£ÕžÖÕŽ}
+
+_textSearchlong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>ÕžÖÕžÕ¶Õ¥Õ¬ ÕžÖÕžÕ·Õ¡Õ¯Õ« Õ¢Õ¡ÕŒÕ¥Ö</i> ÕžÖÕžÕ¶Ö
+Õ°Õ¡Õ¶Õ€Õ«ÕºÕžÖÕŽ Õ¥Õ¶ "ÕžÖÕžÕ¶Õ¥Õ¬" Õ§Õ»Õ« Õ¿Õ¥ÖÕœÕ¿ÕžÖÕŽ: ÕÕ¡ Õ¡ÕŒÕ¡Õ»Õ«Õ¶ Õ§Õ»Õ¶ Õ§, ÕžÖÕš
+Õ¡Õ¯Õ¿Õ«ÕŸÕ¡Õ¶ÕžÖÕŽ Õ§, Õ¥ÖÕ¢ ÕœÕ¯ÕœÕžÖÕŽ Õ¥Õœ Õ¡Õ·Õ­Õ¡Õ¿Õ¥Õ¬Õš, Ö Õ¯Õ¡ÖÕžÕ² Õ§ Õ°Õ¡ÕœÕ¡Õ¶Õ¥Õ¬Õ« Õ¬Õ«Õ¶Õ¥Õ¬ Õ¡ÕµÕ¬ Õ§Õ»Õ¥ÖÖ, ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ
+ <i>ÕžÖÕžÕ¶Õ¥Õ¬</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ¥Ö Õ¡-Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« Õ£ÖÖÕ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš,  
+Õ¿Õ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕŸÕ¡Õ® ÕšÕœÕ¿ Õ¡ÕµÕ¢Õ¢Õ¥Õ¶Õ¡Õ¯Õ¡Õ¶ Õ¯Õ¡ÖÕ£Õ«:  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Õ°Õ¥Õ²Õ«Õ¶Õ¡Õ¯Õ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ°Õ¥Õ²Õ«Õ¶Õ¡Õ¯Õ¶Õ¥Ö Õ¡-Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« Õ£ÖÖÕ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš,
+Õ¿Õ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕŸÕ¡Õ® ÕšÕœÕ¿ Õ°Õ¥Õ²Õ«Õ¶Õ¡Õ¯Õ« Õ¡Õ¶ÕŸÕ¡Õ¶:  }
+
+_textSubjectlong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Õ¡ÕŒÕ¡ÖÕ¯Õ¡ÕµÕ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ¡ÕŒÕ¡ÖÕ¯Õ¡Õ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« Õ¡ÕŒÕ¡ÖÕ¯Õ¡Õ¶Õ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš: }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Õ¿Õ¡ÖÕ¥Õ©ÕŸÕ¥ÖÕ«Õ</i> ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ
+<i>Õ¿Õ¡ÖÕ¥Õ©ÕŸÕ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« Õ¢ÕžÕ¬ÕžÖ Õ°Õ¡ÕŽÕ¡ÖÕ¶Õ¥ÖÕš, Õ¿Õ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕŸÕ¡Õ®
+ÕšÕœÕ¿ ÕªÕ¡ÕŽÕ¡Õ¶Õ¡Õ¯Õ¡Õ£ÖÕžÖÕ©ÕµÕ¡Õ¶:  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ ÖÕ¡ÕµÕ¬Õ« Õ¡Õ¶ÕŸÕ¡Õ¶,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>ÖÕ¡ÕµÕ¬Õ« Õ¡Õ¶ÕžÖÕ¶Õ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« ÕŽÕžÖÕ¿ÖÕ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš, 
+Õ¿Õ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕŸÕ¡Õ® ÕšÕœÕ¿ ÖÕ¡ÕµÕ¬Õ« Õ¡Õ¶ÕŸÕ¡Õ¶ÕžÖÕŽÕ¶Õ¥ÖÕ«:  }
+
+_textLanguagelong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Õ¬Õ¥ÕŠÕŸÕ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ¬Õ¥ÕŠÕžÖÕ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« ÕŽÕžÖÕ¿ÖÕ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš,  
+Õ¿Õ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕŸÕ¡Õ® ÕšÕœÕ¿ Õ¬Õ¥ÕŠÕŸÕ«:  }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿
+Õ¯Õ¡ÕŠÕŽÕ¡Õ¯Õ¥ÖÕºÕžÖÕ©ÕµÕ¡Õ¶,</i> ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ¯Õ¡ÕŠÕŽÕ¡Õ¯Õ¥ÖÕºÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ«
+Õ¯Õ¡ÕŠÕŽÕ¡Õ¯Õ¥ÖÕºÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš:  }
+
+_textHowtolong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ "Õ«Õ¶Õ¹ÕºÕ¥Õœ" ÖÕžÖÖÕ¡Õ¯Õ«,</i>
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ«Õ¶Õ¹ÕºÕ¥Õœ</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« Õ«Õ¶Õ¹ÕºÕ¥Õœ Õ¿ÕžÕ²Õ¥ÖÕ« 
+ÖÕžÖÖÕ¡Õ¯Õš:  }
+
+_textTopiclong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Õ©Õ¥ÕŽÕ¡ÕµÕ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ©Õ¥ÕŽÕ¡</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¥ÖÕ« Õ©Õ¥ÕŽÕ¡Õ¶Õ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš,
+Õ©Õ¥ÖÕ©Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö:  }
+
+_textTolong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Ô±ÕµÕ¶Õ¿Õ¥Õ²Õ«Ö Õ€Õ¡Õ·Õ¿Õ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ¡ÕµÕ¶Õ¿Õ¥Õ²Õ«Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¥ÖÕ« Õ°Õ¡ÕœÖÕ¥Õ¶Õ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš:  }
+
+_textFromlong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Ô±ÕµÕœÕ¿Õ¥Õ²Õ«Ö Õ€Õ¡Õ·Õ¿Õ«Õ</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ¡ÕµÕœÕ¿Õ¥Õ²Õ«Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« Õ¡ÕŒÕ¡ÖÕžÕ²Õ¶Õ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš:  }
+
+_textSerieslong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ ÕŽÕ¡Õ¿Õ¥Õ¶Õ¡Õ·Õ¡ÖÕ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>ÕŽÕ¡Õ¿Õ¥Õ¶Õ¡Õ·Õ¡Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« Õ¡ÕµÕ¶ ÕŽÕ¡Õ¿Õ¥Õ¶Õ¡Õ·Õ¡ÖÕ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš,  
+ÕžÖÕžÕ¶Ö Õ¡ÕŒÕ¯Õ¡ Õ¥Õ¶ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕžÖÕŽ:  }
+
+_textBrowselong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ Õ©Õ¥ÖÕ©Õ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕšÕ</i> ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ
+<i>Õ©Õ¥ÖÕ©Õ¥Õ¬</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  }
+
+_textPeoplelong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ ÕŽÕ¡ÖÕ€Õ¯Õ¡Õ¶Ö,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>ÕŽÕ¡ÖÕ€Õ«Õ¯ Õ¡-Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« ÕŽÕžÖÕ¿ÖÕ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš,
+Õ¿Õ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕŸÕ¡Õ® ÕšÕœÕ¿ Õ¡ÕŠÕ£Õ¡Õ¶ÕžÖÕ¶Õ¶Õ¥ÖÕ«:  }
+
+_textAcronymlong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Õ¡ÖÖÕžÕ¶Õ«ÕŽÕ¶Õ¥ÖÕ« Õ°Õ¡Õ¶Õ€Õ«ÕºÕŽÕ¡Õ¶Õ</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ¡ÖÖÕžÕ¶Õ«ÕŽÕ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  Ô¿Õ¢Õ¡ÖÕŸÕ« Õ¡ÖÖÕžÕ¶Õ«ÕŽÕ¶Õ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš,
+Õ€ÖÕ¡Ö Õ°Õ¡Õ¶Õ€Õ«ÕºÕ¥Õ¬ÕžÖ Õ¿Õ¥Õ²Õ¥ÖÕžÕŸ.  }
+
+_textPhraselong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ©Õ¥ÖÕ©Õ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕžÖÕŽ Õ°Õ¡Õ¶Õ€Õ«ÕºÕžÕ² Õ¢Õ¡ÕŒÕ¥ÖÕš,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ¢Õ¡ÕŒÕ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®ÕžÖÕŽ Õ§ Õ¢Õ¡ÕŒÕ¥ÖÕ« Õ©Õ¥ÖÕ©Õ«Õ¹Õš:  }
+
+_textArtistlong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Õ¡ÖÕ¿Õ«ÕœÕ¿Õ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ<i>Õ¡ÖÕ¿Õ«ÕœÕ¿Õ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  Ô¿Õ¢Õ¡ÖÕŸÕ« ÕŽÕžÖÕ¿ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš,
+Õ¿Õ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕŸÕ¡Õ® ÕšÕœÕ¿ Õ¡ÖÕ¿Õ«ÕœÕ¿Õ« Õ¡Õ¶ÕŸÕ¡Õ¶:  }
+
+_textKeywordlong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Õ¢Õ¡Õ¶Õ¡Õ¬Õ« Õ¢Õ¡ÕŒÕ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ¢Õ¡Õ¶Õ¡Õ¬Õ« Õ¢Õ¡ÕŒÕ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš:  ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« Õ¢Õ¡Õ¶Õ¡Õ¬Õ« Õ¢Õ¡ÕŒÕ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš: }
+
+_textVolumelong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Õ°Õ¡Õ¿ÕžÖÕ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ°Õ¡Õ¿ÕžÖÕ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš: ÕÕ¡ Õ¯Õ¢Õ¥ÖÕ« Õ°Õ¡Õ¿ÕžÖÕ¶Õ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš: }
+
+_textCaptionslong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ<i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ ÕŽÕ¡Õ¯Õ¡Õ£ÖÕžÖÕ©ÕµÕ¡Õ¶,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ<i>ÕŽÕ¡Õ¯Õ¡Õ£ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš: ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« ÕŽÕ¡Õ¯Õ¡Õ£ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš: }
+
+_textCountrieslong_ [l=hy] {<p>Ô¿Õ¡ÖÕžÕ² Õ¥Õœ <i>Õ€Õ«ÕŽÕ¥Õ¬ Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ«Õ¶ ÕšÕœÕ¿ Õ¥ÖÕ¯ÖÕ¶Õ¥ÖÕ«,</i> 
+ÕœÕ¥Õ²ÕŽÕ¥Õ¬ÕžÕŸ <i>Õ¥ÖÕ¯ÖÕ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš: ÕÕ¡ Õ¯Õ¢Õ¡ÖÕ« Õ¥ÖÕ¯ÖÕ¶Õ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õš: }
+
+
+_textdefaultlongtext_ [l=hy] {<p>ÕÕ¥Õ²ÕŽÕ«Ö <i>Õ¡Õ¶Õ°Õ¡ÕµÕ¿</i> Õ¯ÕžÕ³Õ¡Õ¯Õš, Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš
+Õ©Õ¥ÖÕ©Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö (ÖÕžÖÖÕ¡Õ¯Õš Õ¿Õ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕŸÕ¡Õ® Õ§ ÕšÕœÕ¿ Õ¡Õ¶Õ°Õ¡ÕµÕ¿ Õ€Õ¡Õ·Õ¿Õ«):  }
+
+_texthelptopics_ [l=hy] {<h2 align=left>ÔœÕžÖÕ¡Õ£ÖÕ¥Ö</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Ô»Õ¶Õ¹ÕºÕ¥Õœ ÖÕ¶Õ¿ÖÕ¥Õ¬ ÕžÖÕžÕ·Õ¡Õ¯Õ« Õ¢Õ¡ÕŒÕ¥ÖÕ« Õ°Õ¡ÕŽÕ¡Ö</a>
+<ul>
+  <li><a href="\#query-terms">ÕÖÕžÕ¶ÕŽÕ¡Õ¶ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥Ö</a>
+  <li><a href="\#query-type">ÕÕ¡ÖÖÕŽÕ¡Õ¶ Õ¿Õ¥ÕœÕ¡Õ¯</a>
+  <li><a href="\#scope-of-queries">ÕÕ¡ÖÖÕžÖÕŽÕ¶Õ¥ÖÕ« Õ¢Õ¡ÕŠÕŽÕžÖÕ©ÕµÕžÖÕ¶</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">ÕÕ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ« Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</a>
+  <li><a href="\#lang-prefs">ÔŒÕ¥ÕŠÕŸÕ¡Õ¯Õ¡Õ¶ Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</a>
+  <li><a href="\#pres-prefs">ÕÕžÖÖÕ¡Õ€ÖÕŽÕ¡Õ¶ Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</a>
+  <li><a href="\#search-prefs">ÕÖÕžÕ¶ÕŽÕ¡Õ¶ Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=hy] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=hy] {Ô»Õ¶Õ¹ÕºÕ¥Õœ Õ¯Õ¡ÖÕ€Õ¡Õ¬ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš}
+
+_texthelpreadingdocs_ [l=hy] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Ô¿Õ¡ÖÕžÕ² Õ¥Ö Õ¡ÕœÕ¥Õ¬, Õ©Õ¥ Õ¥ÖÕ¢ Õ¥Ö Õ°Õ¡ÕœÕ¥Õ¬ Õ¡Õ¶Õ°Õ¡Õ¿Õ¡Õ¯Õ¡Õ¶ Õ£ÖÖÕ« Õ¯Õ¡ÕŽ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ«,
+ÖÕ¡Õ¶ÕŠÕ« Õ€ÖÕ¡Õ¶Ö ÕŸÕ¥ÖÕ¶Õ¡Õ£Õ«ÖÕš, Õ¯Õ¡ÕŽ Õ¡ÕŒÕ¡Õ»Õ«Õ¶ Õ§Õ»Õ« Õ¶Õ¯Õ¡ÖÕš Õ¥ÖÖÕžÖÕŽ Õ¥Õ¶ Õ§Õ»Õ« ÕŸÕ¥ÖÕ«Õ¶ Õ±Õ¡Õ­
+ÕŽÕ¡ÕœÕžÖÕŽ: ÕÖÕžÕ· Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥ÖÕžÖÕŽ ÕœÕ¡ ÕžÖÕ²Õ¥Õ¯ÖÕŸÕžÖÕŽ Õ§ Õ¶Õ¡Ö Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕ¡ÕŽÕ¢,
+ÕŽÕ«Õ¶Õ¹ ÕžÖÖÕ«Õ·Õ¶Õ¥ÖÕžÖÕŽ Õ¯Õ¡ÖÕ¥Õ¬Õ« Õ§ Õ¿Õ¥ÕœÕ¶Õ¥Õ¬ ÕšÕ¶Õ©Õ¡ÖÕ«Õ¯ Õ§Õ»Õ« Õ°Õ¡ÕŽÕ¡ÖÕš Ö Õ¡ÕŒÕ¡Õ¶Õ±Õ«Õ¶ ÕºÕ¡Õ¿ÕžÖÕ°Õ¡Õ¶, 
+ÕžÖÕ¿Õ¥Õ²Õ«Ö Õ¯Õ¡ÖÕ¥Õ¬Õ« Õ§ ÕšÕ¶Õ¿ÖÕ¥Õ¬ Õ¶ÕžÖ Õ§Õ» Ö Õ£Õ¶Õ¡Õ¬ Õ¡ÕŒÕ¡Õ» Õ¯Õ¡ÕŽ Õ°Õ¥Õ¿: Ô²ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶ÕžÖÕŽ
+ÕšÕ¶Õ©Õ¡ÖÕ«Õ¯ ÕŽÕ¡ÕœÕ« ÕŸÕ¥ÖÕ¶Õ¡Õ£Õ«ÖÕš Õ©Õ¡ÕŸ Õ§, Ö Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õš ÕšÕ¶Õ€Õ¡ÖÕ±Õ¡Õ¯Õ¡ÕŸÕžÕ² Õ§,
+-- ÕœÕ¥Õ²ÕŽÕ¥Ö Õ©Õ²Õ©Õ¡ÕºÕ¡Õ¶Õ¡Õ¯Õ¶Õ¥ÖÕ« ÕŸÖÕ¡ Õ€ÖÕ¡Õ¶Ö Õ¢Õ¡ÖÕ¥Õ¬ÕžÖ Õ¯Õ¡ÕŽ ÖÕ¡Õ¯Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö. 
+ÕœÕ¥Õ²ÕŽÕ¥Ö Õ¢Õ¡ÖÕŸÕ¡Õ® Õ£ÖÖÕ« ÕºÕ¡Õ¿Õ¯Õ¥ÖÕ«Õ¯Õ« ÕŸÖÕ¡, Õ¡ÕµÕ¶ ÖÕ¡Õ¯Õ¥Õ¬ÕžÖ Õ¶ÕºÕ¡Õ¿Õ¡Õ¯ÕžÕŸ:</p>
+
+<p>ÕÕ¿ÕžÖÖ Õ¢Õ¥ÖÕŸÕ¡Õ® Õ§ ÕšÕ¶Õ©Õ¡ÖÕ«Õ¯ Õ¢Õ¡ÕªÕ¶Õ« Õ¢Õ¡ÖÕ¡Õ¿ÖÕžÖÕ©ÕµÕžÖÕ¶Õš: ÔµÖÕ¢ Õ¡ÕµÕ¶ Õ¯Õ¡ÖÕ€Õ¡Ö, 
+Õ¯Õ¿Õ¥ÕœÕ¶Õ¥Ö ÕœÕ¬Õ¡ÖÕ¶Õ¥Ö, Õ±Õ¥ÕŠ Õ°Õ¡Õ»ÕžÖÕ€ Õ¢Õ¡ÕªÕ«Õ¶Õ¶Õ¥Ö Õ¿Õ¡Õ¶Õ¥Õ¬ÕžÖ Õ¯Õ¡ÕŽ Õ°Õ¥Õ¿ Õ¿Õ¥Õ²Õ¡ÖÕžÕ­Õ¥Õ¬ÕžÖ 
+Õ°Õ¡ÕŽÕ¡Ö: </p>
+
+<p>ÕÕ¥ÖÕ¶Õ¡Õ£ÖÕ«Ö Õ¯Õ¡ÕŽ Õ¡ÕŒÕ¡Õ»Õ«Õ¶ Õ§Õ»Õ« Õ¶Õ¯Õ¡ÖÕ«Ö Õ¶Õ¥ÖÖÖ Õ¯Õ¡Õ¶ ÕŽÕ« ÖÕ¡Õ¶Õ« Õ¯ÕžÕ³Õ¡Õ¯Õ¶Õ¥Ö: ÕÕ¥Õ²ÕŽÕ«Ö
+<i>ÕšÕ¶Õ€Õ¬Õ¡ÕµÕ¶Õ«Ö Õ¿Õ¥ÖÕœÕ¿Õš</i> ÕšÕ¶Õ©Õ¡ÖÕ«Õ¯ Õ¢Õ¡ÕªÕ¶Õ« ÕžÕ²Õ» Õ¿Õ¥ÖÕœÕ¿Õš Õ¢Õ¡ÖÕ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö:
+ÔµÕ©Õ¥ ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš ÕšÕ¶Õ€Õ¡ÖÕ±Õ¡Õ¯ Õ§, ÕœÕ¡ Õ¯Õ¡ÖÕžÕ² Õ§ Õ¥ÖÕ¯Õ¡Ö Õ¿ÖÕ¥Õ¬ Ö Õ¯Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®ÕŸÕ« 
+ÕŽÕ¥ÖÕ¥Õ¶Õ¡ÕµÕ¡Õ¯Õ¡Õ¶ ÕŽÕ¥Õ® Õ°Õ«Õ·ÕžÕ²ÕžÖÕ©ÕµÕžÖÕ¶: ÕÕ¥Õ²ÕŽÕ«Ö <i>ÕšÕ¶Õ€Õ¬Õ¡ÕµÕ¶Õ«Ö Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õš</i> 
+ÕžÕ²Õ» Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õš Õ¡ÕµÕ¶ÕºÕ¥Õœ ÕšÕ¶Õ€Õ¬Õ¡ÕµÕ¶Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö, ÕžÖ Õ¯Õ¡ÖÕžÕ²Õ¡Õ¶Õ¡Õœ Õ€Õ«Õ¿Õ¥Õ¬ Õ¢ÕžÕ¬ÕžÖ
+Õ£Õ¬ÕžÖÕ­Õ¶Õ¥ÖÕ« ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ¥ÖÕš Ö Õ¥Õ¶Õ©Õ¡Õ£Õ¬ÕžÖÕ­Õ¶Õ¥ÖÕš: ÕÕ¥Õ²ÕŽÕ«Ö <i>Õ¡ÕŒÕ¡Õ¶Õ±Õ¶Õ¡ÖÕ¶Õ¥Õ¬</i> Õ€Õ«Õ¿ÕŽÕ¡Õ¶ Õ¶ÕžÖ
+ÕºÕ¡Õ¿ÕžÖÕ°Õ¡Õ¶ Õ¢Õ¡ÖÕ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö: (ÕÕ¡ Ö
+Õ£Õ¿Õ¡Õ¯Õ¡Ö Õ§, Õ¥Õ©Õ¥ ÖÕ¡Õ¶Õ¯Õ¡Õ¶ÕžÖÕŽ Õ¥Ö Õ°Õ¡ÕŽÕ¥ÕŽÕ¡Õ¿Õ¥Õ¬ Õ«ÖÕ¡Ö Õ°Õ¥Õ¿
+ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš, Õ¯Õ¡ÕŽ ÕŽÕ«Õ¡Õ¶Õ£Õ¡ÕŽÕ«Ö Õ¯Õ¡ÖÕ€Õ¡Õ¬ Õ¥ÖÕ¯ÕžÖ ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©): ÕÕ¥ÖÕ»Õ¡ÕºÕ¥Õœ, Õ¥ÖÕ¢ Õ¯Õ¡Õ¿Õ¡ÖÕžÖÕŽ Õ¥Õœ 
+ÖÕ¶Õ¿ÖÕžÖÕŽ, ÕžÖÕžÕ¶ÕŸÕžÕ² Õ¢Õ¡ÕŒÕ¥ÖÕš Õ¶Õ¥ÖÕ¯ÕŸÕ¡Õ® Õ¥Õ¶ Õ¬Õ«Õ¶ÕžÖÕŽ: ÕÕ¥Õ²ÕŽÕ«Ö <i>Õ¹Õ¶Õ¥ÖÕ¯Õ¥Õ¬</i> ÕœÕ¡ Õ¡Õ¶Õ»Õ¡Õ¿Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö:</p>
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Ô²Õ¡ÖÕ«Ö Õ¡ÕµÕœ Õ£ÖÖÕ¡Õ€Õ¡ÖÕ¡Õ¯Õš</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Ô²Õ¡ÖÕ«Ö/ÖÕ¡Õ¯Õ«Ö Õ¡ÕµÕœ Õ£Õ«ÖÖÕš</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>ÔŽÕ«Õ¿Õ«Ö Õ¿Õ¥ÖÕœÕ¿Õ« Õ¡ÕµÕœ Õ¢Õ¡ÕªÕ«Õ¶Õš</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Ô±ÖÕ¿Õ¡Õ®Õ«Ö Õ¯Õ¡ÕŽ ÕžÕ¹ Õ¬ÖÕ«ÕŸ` Õ¿Õ¥ÖÕœÕ¿Õš</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>ÔžÕ¶Õ€Õ¬Õ¡ÕµÕ¶Õ«Ö Õ¯Õ¡ÕŽ ÕžÕ¹Õ Õ¢ÕžÕŸÕ¡Õ¶Õ€Õ¡Õ¯ÕžÖÕ©ÕµÕžÖÕ¶Õš</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Ô²Õ¡ÖÕ«Ö Õ¡ÕµÕœ Õ§Õ»Õš Õ¶ÕžÖ ÕºÕ¡Õ¿ÕžÖÕ°Õ¡Õ¶ÕžÖÕŽ</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>ÕÕ¥ÖÕ¯Õ«Ö Õ¯Õ¡ÕŽ ÕžÕ¹` ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥ÖÕš</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>ÕÕ¥Õ²ÕŽÕ«Ö ÕœÕ¬Õ¡ÖÕš, Õ°Õ¡Õ»ÕžÖÕ€ Õ¢Õ¡ÕªÕ¶Õ«Õ¶ Õ£Õ¶Õ¡Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... Õ¯Õ¡ÕŽ Õ°Õ¥Õ¿, Õ¶Õ¡Õ­ÕžÖÕ€ Õ¢Õ¡ÕªÕ«Õ¶</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=hy] {<h2>Ô»Õ¶Õ¹ÕºÕ¥Õœ ÕžÖÕžÕ¶Õ¥Õ¬ ÕšÕœÕ¿ ÕžÖÕžÕ·Õ¡Õ¯Õ« Õ¢Õ¡ÕŒÕ¥ÖÕ«</h2>
+<p>
+  ÕÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕžÖÕ°Õ¡Õ¶Õ«Ö, Õ¯Õ¡Õ¿Õ¡ÖÕ«Ö Õ°Õ¥Õ¿ÖÕµÕ¡Õ¬ ÖÕ¡ÕµÕ¬Õ¥ÖÕš:<p>
+  
+  <ol><li>ÕÖÕžÕ·Õ«Ö Õ©Õ¥ Õ«Õ¶Õ¹ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥Ö Õ¥Õœ ÕžÖÕŠÕžÖÕŽ ÖÕ¶Õ¿ÖÕ¥Õ¬
+      <li>ÕÕœÕ¿Õ¡Õ¯Õ¥ÖÖÕžÖ, ÕžÖÕŠÕžÖÕŽ Õ¥Õœ ÖÕ¶Õ¿ÖÕ¥Õ¬ ÕšÕœÕ¿ Õ¢ÕžÕ¬ÕžÖ Õ©Õ¥ ÕŽÕ«Õ¡ÕµÕ¶ ÕžÖÕžÕ· Õ¢Õ¡ÕŒÕ¥ÖÕ«:
+      <li>ÕÕžÖÕ¿Ö Õ¡ÖÕ¡ ÖÕ¶Õ¿ÖÕžÕŸÕ« Õ¢Õ¡ÕŒÕ¥ÖÕš
+      <li>ÕÕ¥Õ²ÕŽÕ«Ö <i>ÕÕ¯ÕœÕ«Ö ÖÕ¶Õ¿ÖÕžÖÕŽÕš</i> Õ¯ÕžÕ³Õ¡Õ¯Õš
+  </ol>
+
+<p> <p>ÔµÖÕ¢ Õ°Õ¡ÖÖÕžÖÕŽÕš Õ¯Õ¡Õ¿Õ¡ÖÕŸÕ¡Õ® Õ§, Õ¡ÕŒÕ¡Õ»Õ«Õ¶ ÖÕœÕ¡Õ¶ Õ°Õ¡ÕŽÕšÕ¶Õ¯Õ¶ÕžÕ² ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕ« ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ¥ÖÕš Õ¯Õ¡ÖÕ¿Õ¡Õ®ÕŸÕ¥Õ¶: ÕÕ¥ÖÖÖÕ« ÕŽÕ¡ÕœÕžÖÕŽ Õ¯Õ¡ Õ¯ÕžÕ³Õ¡Õ¯, ÕžÖÕš Õ¢Õ¡ÖÕžÖÕŽ Õ§ Õ°Õ¡Õ»ÕžÖÕ€ ÖÕœÕ¡Õ¶ ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš: Ô±ÕµÕœÕ¿Õ¥Õ² Õ¯Õ¡Õ¶ Õ¯ÕžÕ³Õ¡Õ¯Õ¶Õ¥Ö, ÕžÖÕžÕ¶Ö Ö
+Õ£Õ¶ÕžÖÕ©ÕµÕ¡ÕŽÕ¢ Õ¯Õ¡ÖÕžÕ² Õ¥Ö Õ¿Õ¥Õ²Õ¡Õ·Õ¡ÖÕªÕŸÕ¥Õ¬ Õ€Õ¥ÕºÕ« Õ°Õ¡Õ»ÕžÖÕ€ ÖÕœÕ¡Õ¶ Õ£ÖÕ¡ÕŒÕžÖÕŽÕš, Ö Õ¯Õ¡ÕŽ Õ°Õ¥Õ¿ ÕŸÕ¥ÖÕ¡Õ€Õ¡ÕŒÕ¶Õ¡Õ¬ Õ€Õ¥ÕºÕ« Õ¡ÕŒÕ¡Õ»Õ«Õ¶ ÖÕœÕ¡Õ¶ÕµÕ¡Õ¯Õ«Õ¶: ÔµÕŸ Õ¡ÕµÕœÕºÕ¥Õœ Õ·Õ¡ÖÕžÖÕ¶Õ¡Õ¯: ÕÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš Õ€Õ«Õ¿Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö, ÕœÕ¥Õ²ÕŽÕ«Ö ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ« ÕŸÖÕ¡, Õ¯Õ¡ÕŽ Õ¯ÕžÕ²ÖÕ« ÖÕžÖÖÕ«Õ¯ Õ¯ÕžÕ³Õ¡Õ¯Õš:
+
+<p>Ô±ÕŽÕ¥Õ¶Õ¡Õ·Õ¡Õ¿Õš Õ°Õ¶Õ¡ÖÕ¡ÕŸÕžÖ Õ§ 100 ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ© Õ£Õ¿Õ¶Õ¥Õ¬: ÔµÕ©Õ¥ Õ¡ÕµÕœ Õ©Õ«ÕŸÕš ÖÕ¡Õ¶Õ¯Õ¡Õ¶ÕžÖÕŽ Õ¥Ö ÖÕžÕ­Õ¥Õ¬, Õ¡ÕºÕ¡ ÕœÕ¥Õ²ÕŽÕ¥Ö
+  <i>Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš, ÕžÖÕš Õ£Õ¿Õ¶ÕŸÕžÖÕŽ Õ§ Õ§Õ»Õ« ÕŸÕ¥ÖÖÕžÖÕŽ:<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>ÕÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥Ö</h3>
+
+<p>Ô»Õ¶Õ¹ Õ§Õ¬ ÕŽÕžÖÕ¿Ö Õ¡Õ¶Õ¥Ö Õ°Õ¡ÖÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕžÖÕ°Õ¡Õ¶ÕžÖÕŽ, Õ€ÖÕ¡Õ¶Ö Õ¯Õ¶Õ¥ÖÕ¯Õ¡ÕµÕ¡ÖÕŸÕ¥Õ¶ Õ¢Õ¡ÕŒÕ¥ÖÕ« ÖÕžÖÖÕ¡Õ¯Õ« Õ¿Õ¥ÕœÖÕžÕŸ, ÕžÖÕžÕ¶Ö Õ¯ÕžÕ¹ÕŸÕžÖÕŽ Õ¥Õ¶ âÖÕ¶ÖÕŽÕ¡Õ¶ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥Öâ: Ô±ÕŽÕ¥Õ¶ Õ¿Õ¥ÖÕŽÕ«Õ¶ Õ¯Õ¡ÕŠÕŽÕŸÕ¡Õ® Õ§ Õ¡ÕµÕ¢Õ¢Õ¥Õ¶Õ¡Õ¯Õ¡Õ¶ Ö Õ©ÕŸÕ¡ÕµÕ«Õ¶ Õ¶Õ«Õ·Õ¥ÖÕ«Ö: ÕÕ¥ÖÕŽÕ«Õ¶Õ¶Õ¥ÖÕš Õ¢Õ¡ÕªÕ¡Õ¶ÕŸÕ¡Õ® Õ¥Õ¶ Õ«ÖÕ¡ÖÕ«Ö Õ¢Õ¡ÖÕ¡Õ¿Õ¶Õ¥ÖÕžÕŸ: Õ¥Õ©Õ¥ Õ¡ÕŒÕ¯Õ¡ Õ§ ÕžÖÖÕ§ Õ¯Õ¥Õ¿Õ¡Õ€ÖÕ¡Õ¯Õ¡Õ¶ Õ¶Õ·Õ¡Õ¶, Õ¡ÕºÕ¡ ÕœÖÕ¡Õ¶Ö Õ®Õ¡ÕŒÕ¡ÕµÕžÖÕŽ Õ¥Õ¶ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥ÖÕš Õ«ÖÕ¡ÖÕ«Ö Õ¡Õ¶Õ»Õ¡Õ¿Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö, Õ¡ÕµÕœÕ«Õ¶ÖÕ¶ Õ¯Õ¡Õ¿Õ¡ÖÕžÖÕŽ Õ¥Õ¶ Õ¢Õ¡ÖÕ¡Õ¿Õ« Õ€Õ¥Ö: ÔµÕŸ ÕœÖÕ¡Õ¶Ö Õ¡Õ¶Õ¿Õ¥ÕœÕŸÕžÖÕŽ Õ¥Õ¶: ÕÕ¶Õ¡ÖÕ¡ÕŸÕžÖ Õ¹Õ§ ÖÕ¶Õ¿ÖÕ¥Õ¬ ÕšÕœÕ¿ Õ¢Õ¡ÕŒÕ¥ÖÕ«, ÕžÖÕžÕ¶Ö ÕšÕ¶Õ€Õ£ÖÕ¯ÕžÖÕŽ Õ¥Õ¶ Õ¯Õ¥Õ¿Õ¡Õ€ÖÕ¡Õ¯Õ¡Õ¶ Õ¶Õ·Õ¡Õ¶Õ¶Õ¥Ö:
+
+<p>ÕÖÕ«Õ¶Õ¡Õ¯, Õ°Õ¥Õ¿ÖÕµÕ¡Õ¬ Õ°Õ¡ÖÖÕžÖÕŽÕš<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>Õ¯Õ¬Õ«Õ¶Õ« Õ¶ÕžÖÕµÕ¶Õš, Õ«Õ¶Õ¹<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>ÕÕ¡ÖÖÕŽÕ¡Õ¶ Õ¿Õ¥ÕœÕ¡Õ¯</h3>
+
+<p>Ô¿Õ¡Õ¶ Õ¥ÖÕ¯ÕžÖ Õ¿Õ¡ÖÕ¢Õ¥Ö Õ¿Õ¥ÕœÕ¡Õ¯Õ« Õ°Õ¡ÖÖÕžÖÕŽÕ¶Õ¥Ö.
+
+<ul>
+  <li>ÕÕ¡ÖÖÕžÖÕŽÕ¶Õ¥Ö <b>Õ¢ÕžÕ¬ÕžÖ</b> Õ¢Õ¡ÕŒÕ¥ÖÕ« Õ°Õ¡ÕŽÕ¡Ö: Ô±ÕµÕœ Õ€Õ¥ÕºÖÕžÖÕŽ ÖÕ¶Õ¿ÖÕŸÕžÖÕŽ Õ¥Õ¶ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš, (Õ¯Õ¡ÕŽ
+      Õ£Õ¬ÕžÖÕ­Õ¶Õ¥ÖÕš, Õ¯Õ¡ÕŽ ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ¥ÖÕš) ÕžÖÕžÕ¶Ö ÕºÕ¡ÖÕžÖÕ¶Õ¡Õ¯ÕžÖÕŽ Õ¥Õ¶ Õ±Õ¥Ö Õ¯ÕžÕ²ÕŽÕ«Ö Õ¶Õ·ÕŸÕ¡Õ® Õ¢ÕžÕ¬ÕžÖ Õ¢Õ¡ÕŒÕ¥ÖÕš:
+      Ô±ÕµÕ¶ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš, ÕžÖÕžÕ¶Ö Õ¢Õ¡ÕŸÕ¡ÖÕ¡ÖÕžÖÕŽ Õ¥Õ¶ Õ°Õ¡ÖÖÕŽÕ¡Õ¶Õš, Õ¡ÖÕ¿Õ¡Õ®ÕŸÕžÖÕŽ Õ¥Õ¶ Õ¿Õ¥ÕœÕ¡Õ¯Õ¡ÕŸÕžÖÕŸÕ¡Õ® ÕšÕœÕ¿   
+      Õ¡ÕµÕ¢Õ¢Õ¥Õ¶Õ¡Õ¯Õ¡Õ¶ 
+      Õ¯Õ¡ÖÕ£Õ«.<p>
+
+  <li>ÕÕ¡ÖÖÕžÖÕŽÕ¶Õ¥Ö <b>ÕžÖÕžÕ·</b> Õ¢Õ¡ÕŒÕ¥ÖÕ« Õ°Õ¡ÕŽÕ¡Ö: ÕÕ¡ÖÕŠÕ¡ÕºÕ¥Õœ Õ¶Õ·Õ¥Ö ÕŽÕ« ÖÕ¡Õ¶Õ« Õ¿Õ¥ÖÕŽÕ«Õ¶, ÕžÖ ÕžÖÕŠÕžÖÕŽ Õ¥Ö 
+      Õ£Õ¿Õ¶Õ¥Õ¬ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕžÖÕŽ:  
+      Ô¿Õ¡ÖÕ¿Õ¡Õ®ÕŸÕ¥Õ¶ Õ¡ÕµÕ¶ Õ°Õ¡Õ»ÕžÖÕ€Õ¡Õ¯Õ¡Õ¶ÕžÖÕ©ÕµÕ¡ÕŽÕ¢, Õ©Õ¥ Õ«Õ¶Õ¹ÖÕ¡Õ¶ ÕŽÕžÕ¿ Õ¥Õ¶ Õ¡ÕµÕ€ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥ÖÕš Õ°Õ¡ÖÖÕŽÕ¡Õ¶Õš: ÔµÖÕ¢ 
+      ÕžÖÕžÕ·ÕŸÕžÖÕŽ Õ§
+
+      ÕŽÕžÕ¿Õ«Õ¯ÕžÖÕ©ÕµÕ¡Õ¶ Õ¹Õ¡ÖÕš,
+
+      <p><ul>
+        <li> ÕžÖÖÕ¡Õ¶ Õ·Õ¡Õ¿ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥Ö Õ¯Õ¡Õ¶ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©ÕžÕšÕŽ, Õ¡ÕµÕ¶ÖÕ¶Õ¡ ÕŽÕ¥Õ® Õ§ Õ°Õ¡ÕŽÕšÕ¶Õ¯Õ¶Õ¥Õ¬Õ«ÕžÖÕ©ÕµÕžÖÕ¶Õš
+        <li> Õ°Õ¡ÕŠÕŸÕ¡Õ€Õ¥Õº Õ°Õ¡Õ¶Õ€Õ«ÕºÕžÕ² Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥ÖÕš Õ¡ÕŸÕ¥Õ¬Õ« Õ¯Õ¡ÖÖÕžÖ Õ¥Õ¶, ÖÕ¡Õ¶ Õ©Õ¥ Õ°Õ¡Õ³Õ¡Õ­ ÕºÕ¡Õ¿Õ¡Õ°ÕžÕ²Õ¶Õ¥ÖÕš
+        <li> Õ¯Õ¡ÖÕ³ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš Õ¡ÕŸÕ¥Õ¬Õ« Õ¬Õ¡ÕŸÕ¶ Õ¥Õ¶ ÖÕ¡Õ¶ Õ©Õ¥ Õ¥ÖÕ¯Õ¡ÖÕ¶Õ¥ÖÕš:
+      </ul>
+</ul>
+
+<p>ÕÕ£Õ¿Õ¡Õ£ÕžÖÕ®Õ«Ö Õ¡ÕµÕ¶ÖÕ¡Õ¶ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥Ö, ÕžÖÖÕ¡Õ¶ ÕžÖ ÕžÖÕŠÕžÖÕŽ Õ¥Õœ. Õ¡ÕŽÕ¢ÕžÕ²Õ»Õ¡Õ¯Õ¡Õ¶ 
+Õ¶Õ¡Õ­Õ¡Õ€Õ¡ÕœÕžÖÕ©ÕµÕžÖÕ¶ Õ¯Õ¡ÕŽ Õ§Õ¬ Õ¬ÖÕ«ÕŸ ÕºÕ¡ÖÕ¡Õ£ÖÕ¡Ö: Õ¥Õ©Õ¥ Õ¶Õ·Õ¥Ö ÕŽÕ«Õ¡ÕµÕ¶ ÕŽÕ¥Õ¯ Õ¿Õ¥ÖÕŽÕ«Õ¶, ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš
+Õ¯Õ€Õ¡ÕœÕ¡Õ¯Õ¡ÖÕ£ÕŸÕ¥Õ¶ ÕšÕœÕ¿ Õ€ÖÕ¡ Õ°Õ¡Õ¶Õ€Õ«ÕºÕŽÕ¡Õ¶ Õ°Õ¡Õ³Õ¡Õ­Õ¡Õ¯Õ¡Õ¶ÕžÖÕ©ÕµÕ¡Õ¶: <p>
+_texthelpscope_
+
+}
+
+_textdatesearch_ [l=hy] {ÕÖÕžÕ¶ÕžÖÕŽ ÕšÕœÕ¿ Ô±ÕŽÕœÕ¡Õ©ÕŸÕ¥ÖÕ«}
+
+_texthelpdatesearch_ [l=hy] {<h2>_textdatesearch_</h2>
+ÕÕ¶Õ¿ÖÕžÖÕŽÕš ÕšÕœÕ¿ Õ¿Õ¡ÖÕ¥Õ©ÕŸÕ¥ÖÕ« Õ©ÕžÖÕµÕ¬ Õ§ Õ¿Õ¡Õ¬Õ«Õœ Õ£Õ¿Õ¶Õ¥Õ¬ Õ¡ÕµÕ¶ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš, ÕžÖÕžÕ¶Ö 
+Õ£Õ¿Õ¶ÕŸÕžÖÕŽ Õ¥Õ¶ ÕºÕ¡Õ°Õ¡Õ¶Õ»ÕŸÕžÕ² ÕªÕ¡ÕŽÕ¡Õ¶Õ¡Õ¯Õ¡Õ°Õ¡Õ¿ÕŸÕ¡Õ®ÕžÖÕŽ: Ô¿Õ¡ÖÕžÕ² Õ¥Õœ ÖÕ¶Õ¿ÖÕ¥Õ¬  
+ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš,  ÕšÕœÕ¿ ÕžÖÕžÕ·Õ¡Õ¯Õ« Õ¿Õ¡ÖÕŸÕ¡ Õ¯Õ¡ÕŽ ÕªÕ¡ÕŽÕ¡Õ¶Õ¡Õ¯Õ¡Õ°Õ¡Õ¿ÕŸÕ¡Õ®Õ«: ÕÕ¯Õ¡Õ¿Õ« 
+ÕžÖÕ¶Õ¥ÖÕ¥Ö, ÕžÖ Õ¢Õ¡ÖÕ« Õ¿Õ¡ÖÕ¥Õ©ÕŸÕ«Ö, ÕžÖÕžÕ¶ÕŽÕ¡Õ¶ Õ¡ÕµÕ¬ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥Ö Õ¹Õ¥Ö Õ¯Õ¡ÖÕžÕ² Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Õ¬: 
+Ô²Õ¡ÖÕ« Õ¡ÕµÕ€, Õ¥Õ©Õ¥ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ°Õ¡ÕŽÕ¡Ö ÕžÕ¹ ÕŽÕ« Õ¡ÕŽÕœÕ¡Õ©Õ«ÕŸ ÕŽÕžÖÕ¿Ö Õ¹Õ¥Ö Õ¡ÖÕ¥Õ¬, Õ¡ÕºÕ¡  ÕœÕ¡
+Õ°Õ¡ÕŽÕ¡ÖÕªÕ¥Ö Õ§ ÕžÖ ÖÕ¶Õ¿ÖÕžÖÕŽ Õ¹Õ« Õ«ÖÕ¡Õ¯Õ¡Õ¶Õ¡ÖÕŸÕ«: <p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>Ô»Õ¶Õ¹ÕºÕ¥Õœ Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Õ¬ Õ¡ÕµÕœ Õ°Õ¶Õ¡ÖÕ¡ÕŸÕžÖÕžÖÕ©ÕµÕžÖÕ¶Õš:</h3>
+<ul>
+   <li>ÕÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕ« ÕžÖÕžÕ¶ÕžÖÕŽ ÕšÕœÕ¿ ÕŽÕ¥Õ¯ Õ¿Õ¡ÖÕŸÕ¡ Õ¯Õ¿ÖÕŸÕ¡Õ®ÖÕ«:<p>
+   <ul>
+       <li>ÕÕžÖÕ¿Ö Õ¡ÖÕ¡ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¡ÖÕ¿Õ¡Õ°Õ¡ÕµÕ¿ÕžÖÕ©ÕµÕžÖÕ¶Õš:
+       <li>ÕÕžÖÕ¿Ö Õ¡ÖÕ¡ ÕºÕ¡Õ°Õ¡Õ¶Õ»ÕŸÕžÕ² Õ¿Õ¡ÖÕ¥Õ©Õ«ÕŸÕš  "ÕÕ¯ÕŠÕ¢Õ« (Õ¯Õ¡ÕŽ ÕŽÕ«Õ¡Õ¯) Õ¡ÕŽÕœÕ¡Õ©Õ«ÕŸ" Õ€Õ¡Õ·Õ¿ÕžÖÕŽ:
+       <li>ÔµÕ©Õ¥ Õ¿Õ¡ÖÕ¥Õ©Õ«ÕŸÕš ÕŽÕ«Õ¶Õ¹ ÕšÕ¶Õ©Õ¡ÖÕ«Õ¯ ÕªÕ¡ÕŽÕ¡Õ¶Õ¡Õ¯Õ¡Õ·ÖÕ»Õ¡Õ¶Õ¶ Õ§, (Õ¯ÕžÕ¹ÕŸÕžÖÕŽ Õ§ Õ¶Õ¡Ö ÕŽÕ«Õ¶Õ¹ 
+           ÕÖÕ«ÕœÕ¿ÕžÕœÕš), Õ¢Õ¡ÖÕŸÕžÕ² ÕšÕ¶Õ¿ÖÕ¡ÖÕ¡Õ¶Õ¯Õ«Ö ÕšÕ¶Õ¿ÖÕ«Ö "B.C.E" 
+           Õ¡ÕŒÕ¡Õ»Õ¡ÖÕ¯Õš:
+       <li>ÕÕ¯ÕœÕ«Ö ÕžÖÕžÕ¶ÕžÖÕŽÕš:
+   </ul>
+<p><li>ÕÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕ« ÕžÖÕžÕ¶ÕžÖÕŽ ÕšÕœÕ¿ ÕžÖÕžÕ·Õ¡Õ¯Õ« ÕªÕ¡ÕŽÕ¡Õ¶Õ¡Õ¯Õ¡Õ°Õ¡Õ¿ÕŸÕ¡Õ®Õ«:<p>
+   <ul>
+       <li>ÕÕžÖÕ¿Ö Õ¡ÖÕ¡ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥ÖÕš, Õ«Õ¶Õ¹ÕºÕ¥Õœ Õ¯Õ¡ÖÕ£Õ¶ Õ§.
+       <li>ÕÕžÖÕ¿Ö Õ¡ÖÕ¡ ÕœÕ¯ÕŠÕ¢Õ¶Õ¡Õ¯Õ¡Õ¶ Õ¿Õ¡ÖÕ¥Õ©Õ«ÕŸÕš "ÕÕ¯ÕŠÕ¢Õ« (Õ¯Õ¡ÕŽ ÕŽÕ«Õ¡Õ¯) Õ¡ÕŽÕœÕ¡Õ©Õ«ÕŸ" Õ€Õ¡Õ·Õ¿ÕžÖÕŽ.
+       <li>ÕÕžÖÕ¿Ö Õ¡ÖÕ¡ ÕŸÕ¥ÖÕ»Õ« Õ¿Õ¡ÖÕ¥Õ©Õ«ÕŸÕš " Ô±ÕŽÕœÕ¡Õ©ÕŸÕ« ÕŸÕ¥ÖÕ»: " Õ€Õ¡Õ·Õ¿ÕžÖÕŽ.
+       <li>ÔžÕ¶Õ¿ÖÕ«Ö "B.C.E" Õ¡ÕŒÕ¡Õ»Õ¡ÖÕ¯Õš Õ¢Õ¡ÖÕŸÕžÕ² ÕšÕ¶Õ¿ÖÕ¡ÖÕ¡Õ¶Õ¯Õ«Ö 
+           (ÕœÕ¡ Õ°Õ¡ÕµÕ¿Õ¶Õ« Õ§ Õ¶Õ¡Ö ÕŽÕ«Õ¶Õ¹ ÕÖÕ«ÕœÕ¿ÕžÕœÕš):
+       <li>ÕÕ¯ÕœÕ«Ö ÕžÖÕžÕ¶ÕžÖÕŽÕš:
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>Ô»Õ¶Õ¹Õ¥Õœ Õ§ Õ¡Õ·Õ­Õ¡Õ¿ÕžÖÕŽ ÕžÖÕžÕ¶ÕžÖÕŽÕš</h3>
+
+ÔžÕ¶Õ€Õ°Õ¡Õ¶ÖÕ¡ÕºÕ¥Õœ Õ¡ÕœÕ¡Õ®, 1903 Õ©. ÕŽÕ¡ÕœÕ«Õ¶ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕ« ÕžÖÕžÕ¶ÕžÖÕŽÕš Õ¹Õ« ÕŸÕ¥ÖÕ¡Õ€Õ¡ÖÕ±Õ¶Õ« 1903 Õ©. Õ°ÖÕ¡Õ¿Õ¡ÖÕ¡Õ¯ÕŸÕ¡Õ® Õ¿Õ¥Õ²Õ¥Õ¯Õ¡Õ£ÖÖÕ¥ÖÕš: Ô±ÕµÕ¶ÕžÖÕ¡ÕŽÕ¥Õ¶Õ¡ÕµÕ¶Õ«ÕŸ Õ°Õ¡Õ·ÕŸÕ« Õ¡ÕŒÕ¶Õ¥Õ¬ÕžÕŸ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕ« ÕžÖÕžÕ¶ÕŽÕ¡Õ¶ Õ¿Õ¡ÖÕ¥Õ©ÕŸÕ¥ÖÕ« Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õš, Õ¯Õ¡ÖÕ¥Õ¬Õ« Õ§ Õ¡ÕœÕ¥Õ¬, ÕžÖ Õ¯Õ£Õ¿Õ¶ÕŸÕ¥Õ¶ Õ¡ÕµÕ¶ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš, ÕžÖÕžÕ¶Ö Õ¿Õ¡ÖÕ¥Õ©ÕŸÕ¥ÖÕ« Õ¿Õ«ÖÕžÖÕµÕ©ÕžÖÕŽ (Ö
+ÖÕ«Õ¶Õ¡Õ¯` 1899-1911) Õ¡ÕŒÕ¯Õ¡ Õ§ Õ¶Õ¡Ö 1903, Õ«Õ¶Õ¹ÕºÕ¥Õœ Õ¶Õ¡Ö Õ¶ÖÕ¡Õ¶Ö, ÕžÖÕžÕ¶ÖÕžÖÕŽ 1903 Õ©. Õ¿ÕŸÕµÕ¡Õ¬ Õ€Õ¡ÖÕ¡Õ·ÖÕ»Õ¡Õ¶Õ« ÕŽÕ¡ÕœÕ¶ Õ§ (Ö
+ÖÕ«Õ¶Õ¡Õ¯ 20ÖÕ€ Õ€Õ¡Ö Õ¯Õ¡ÕŽ ÖÕœÕ¡Õ¶Õ¥ÖÕžÖÕ€ Õ€Õ¡Ö): ÕÕ¡ Õ¶Õ·Õ¡Õ¶Õ¡Õ¯ÕžÖÕŽ Õ§, ÕžÖ ÕžÖÕžÕ· ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕ« Õ°Õ¡ÕŽÕ¡Ö ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¿Õ¡ÖÕ¥Õ©ÕŸÕ¥ÖÕš Õ¡ÕŒÕ¯Õ¡ Õ¹Õ¥Õ¶ Õ¬Õ«Õ¶Õ« ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ« Õ¿Õ¥ÖÕœÕ¿ÕžÖÕŽ: ÔžÕœÕ¿ Õ¿Õ«ÖÕžÖÕµÕ©Õ« ÕžÖÕžÕ¶ÕŽÕ¡Õ¶ ÕºÕ¡ÖÕ¡Õ£Õ¡ÕµÕžÖÕŽ, Õ¡ÕµÕœ Õ¡ÕŽÕ¥Õ¶Õš Õ¯Õ«ÖÕ¡ÕŒÕ¥Õ¬Õ« Õ§ Õ¿Õ«ÖÕžÖÕµÕ©Õ« ÖÕ¡Õ¶Õ¯Õ¡ÖÕ¡Õ® Õ¿Õ¡ÖÕ¥Õ©ÕŸÕ« Õ°Õ¡ÕŽÕ¡Ö:<p>
+
+}
+
+_textchangeprefs_ [l=hy] {ÕÕ¥Ö Õ¶Õ¡Õ­ÕšÕ¶Õ¿ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕ« ÖÕžÖÕžÕ­ÕžÖÕŽ:}
+
+_texthelppreferences_ [l=hy] {<h2>_textchangeprefs_</h2>
+
+<p>ÔµÖÕ¢ ÕœÕ¥Õ²ÕŽÕžÖÕŽ Õ¥Õœ Õ§Õ»Õ« ÕŸÕ¥ÖÖÕžÖÕŽ Õ¡ÕŒÕ¯Õ¡<i>Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</i> Õ¯ÕžÕ³Õ¡Õ¯Õš, Õ¡ÕºÕ¡ Õ¯Õ¡ÖÕžÕ² Õ¥Õœ ÖÕžÕ­Õ¥Õ¬ ÕŽÕ«Õ»Õ¥ÖÕ¥ÕœÕ« ÕžÖÕžÕ· Õ¡ÖÕªÕ¥ÖÕ¶Õ¥Ö, ÖÕž ÕºÕ¡Õ°Õ¡Õ¶Õ»Õ¶Õ¥ÖÕ«Õ¶ Õ¢Õ¡ÕŸÕ¡ÖÕ¡ÖÕ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö:
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>ÕÕ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ« Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</h3>
+
+ÕÖÕžÕ· Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥Ö ÕºÕ¡ÖÕžÖÕ¶Õ¡Õ¯ÕžÖÕŽ Õ¥Õ¶ Õ¥Õ¶Õ©Õ¡Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥Ö, ÕžÖÕžÕ¶ÖÕ«Ö ÕµÕžÖÖÕ¡ÖÕ¡Õ¶Õ¹ÕµÕžÖÖÕžÖÕŽ Õ¯Õ¡ÖÕ¥Õ¬Õ« Õ§ Õ¯Õ¡ÕŠÕŽÕ¡Õ¯Õ¥ÖÕºÕ¥Õ¬ Õ¡Õ¶Õ¯Õ¡Õ­ ÖÕ¶Õ¿ÖÕžÖÕŽ, Õ¯Õ¡ÕŽ Õ¯Õ¡ÖÕ¥Õ¬Õ« Õ§ ÖÕ¶Õ¿ÖÕ¥Õ¬ ÕžÕ²Õ» Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶: ÕÕ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö Õ§Õ»Õ«Ö Õ¯Õ¡ÖÕžÕ² Õ¥Ö ÕžÖÕžÕ·Õ¥Õ¬, Õ©Õ¥ ÕžÖ Õ¥Õ¶Õ©Õ¡Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥ÖÕš ÕšÕ¶Õ€Õ£ÖÕ¯Õ¥Õ¬ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕŽÕ¥Õ»:
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>ÔŒÕ¥ÕŠÕŸÕ¡Õ¯Õ¡Õ¶ Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</h3>
+
+Ô±ÕŽÕ¥Õ¶ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖ ÕžÖÕ¶Õ« Õ¶Õ¥ÖÕ¯Õ¡ÕµÕ¡ÖÕŽÕ¡Õ¶ Õ¬ÕŒÕ¡Õ¯ÕµÕ¡Ö Õ¬Õ¥ÕŠÕžÖ: Ô²Õ¡ÕµÖ Õ¥Õ©Õ¥ ÖÕ¡Õ¶Õ¯Õ¡Õ¶ÕžÖÕŽ Õ¥Ö, Õ¯Õ¡ÖÕžÕ² Õ¥Ö Õ¡Õ¶ÖÕ¶Õ¥Õ¬ ÕŽÕ¥Õ¯ Õ¡ÕµÕ¬ Õ¬Õ¥ÕŠÕŸÕ«: Ô²ÕžÕ¬ÕžÖ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥ÖÕš Õ©ÕžÖÕµÕ¬ Õ¥Õ¶ Õ¿Õ¡Õ¬Õ«Õœ Õ¡Õ¶ÖÕ¶Õ¥Õ¬ Õ£ÖÕ¡ÖÕ«Õ¯Õ¡Õ¯Õ¡Õ¶ ÕŽÕ«Õ»Õ¥ÖÕ¥ÕœÕ«Ö Õ¿Õ¥ÖÕœÕ¿Õ¡ÕµÕ«Õ¶Õ«: ÕÕ¡ Õ°Õ¡Õ¿Õ¯Õ¡ÕºÕ¥Õœ Ö
+Õ£Õ¿Õ¡Õ¯Õ¡Ö Õ§ Õ¿Õ¥ÕœÕžÕ²Õ¡Õ¯Õ¡Õ¶ Õ­Õ¡Õ¶Õ£Õ¡ÖÕžÖÕŽÕ¶Õ¥Ö ÕžÖÕ¶Õ¥ÖÕžÕ² ÕŽÕ¡ÖÕ€Õ¯Õ¡Õ¶Ö Õ°Õ¡ÕŽÕ¡Ö, Õ¥ÖÕ¢ ÕºÕ¥Õ¿Ö Õ§ Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Õ¬ ÕºÕ¡ÕœÕ¿Õ¡ÕŒÕ¡ÕµÕ«Õ¶ Õ¬Õ¡ÕµÕ¶ Õ¿Õ¡ÕŒÕ¡Õ¿Õ¥ÕœÕ¡Õ¯Õ¶Õ¥Ö Õ¯Õ¡ÕŽ Õ±Õ¡ÕµÕ¶Õ« ÕœÕ«Õ¶Õ©Õ¥ÕŠÕ¡Õ¿ÕžÖÕ¶Õ¥Ö:
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>ÕÕ¥ÖÕ¯Õ¡ÕµÕ¡ÖÕŽÕ¡Õ¶ Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</h3>
+
+Ô¿Õ¡Õ­ÕŸÕ¡Õ® Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ«Ö, Õ¯Õ¡ÖÕžÕ² Õ¥Ö ÕšÕ¶Õ¿ÖÕ¥Õ¬ Õ¶Õ¥ÖÕ¯Õ¡ÕµÕ¡ÖÕŽÕ¡Õ¶ ÕŸÕ¥ÖÕ¡Õ°ÕœÕ¯ÕŽÕ¡Õ¶ ÕºÕ¡ÕµÕŽÕ¡Õ¶Õ¶Õ¥ÖÕš:
+
+<p>ÕÕœÕ¿Õ¡ÕµÕ¶Õ« Õ§Õ»Õ¥ÖÕ« Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥ÖÕš ÕºÕ¡ÕœÕ«ÕŸÕ¡ÖÕ¶ÕžÖÕŽ Õ¥Õ¶ Õ¡ÕŽÕ¥Õ¶ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ« ÕŸÕ¥ÖÕ«Õ¶ ÕŽÕ¡ÕœÕžÖÕŽ Õ¡ÕŒÕ¯Õ¡   
+Ô³ÖÕ«Õ¶ÕœÕ©ÕžÕžÖÕ¶Õ« Õ¯Õ¡ÕŒÕ¡ÕŸÕ¡ÖÕŽÕ¡Õ¶ Õ¿ÕžÕ²Õš: Ô±ÕµÕœÕºÕ«ÕœÕžÕŸ ÕŽÕ¥Õ¯ Õ¡Õ¶Õ£Õ¡ÕŽ ÖÕ¶Õ¿ÖÕžÖÕŽ Õ¯Õ¡Õ¿Õ¡ÖÕ¥Õ¬ÕžÕŸ, ÕžÖÕ²Õ²Õ¡Õ¯Õ«ÕžÖÕ¥Õ¶  
+Õ¯Õ¡Õ¶Õ£Õ¶ÕžÖÕŽ Õ¥Ö ÕžÕœÕ¿Õ¡ÕµÕ¶Õ« Õ³Õ·Õ£ÖÕ«Õ¿ Õ§Õ»Õ« ÕŸÖÕ¡, Õ¡ÕŒÕ¡Õ¶Ö Ô³ÖÕ«Õ¶ÕœÕ©ÕžÕžÖÕ¶Õ« Õ²Õ¥Õ¯Õ¡ÕŸÕ¡ÖÕžÕ² Õ¿ÕžÕ²Õ«: ÕÕ¥Õ¯ Õ¡ÕµÕ¬ ÖÕ¶Õ¿ÖÕžÖÕŽ 
+Õ¯Õ¡Õ¿Õ¡ÖÕ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö ÕºÕ¥Õ¿Ö Õ§ Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Ö Õ€Õ«Õ¿Õ¡Õ¯Õ« âÕ°Õ¥Õ¿â Õ¯ÕžÕ³Õ¡Õ¯Õš: Ô±ÕµÕœ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥ÖÕš Õ¶Õ¡Ö Õ©ÕžÖÕµÕ¬ Õ¥Õ¶ 
+Õ¿Õ¡Õ¬Õ«Õœ ÕºÕ¡ÕœÕ«ÕŸÕ¡ÖÕ¶Õ¥Õ¬ Ô³ÖÕ«Õ¶ÕœÕ©ÕžÕžÖÕ¶Õ« ÕŠÕ£ÕžÖÕ·Õ¡ÖÕ¶ÕžÕ² Õ°Õ¡Õ²ÕžÖÕ€ÕžÖÕŽÕ¶Õ¥ÖÕš Õ¡ÕµÕ¶ Õ€Õ¥ÕºÖÕ¥ÖÕžÖÕŽ, Õ¥ÖÕ¢ ÕœÕ¥Õ²ÕŽÕžÖÕŽ Õ¥Ö 
+Õ¯Õ¡ÕºÕ¥ÖÕ« ÕŸÖÕ¡, ÕžÖÕžÕ¶Ö Õ¿Õ¡Õ¶ÕžÖÕŽ Õ¥Õ¶ Õ©ÕŸÕ¡ÕµÕ«Õ¶ Õ£ÖÕ¡Õ€Õ¡ÖÕ¡Õ¶Õ« Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥ÖÕ«Ö Õ€ÕžÖÖÕœ, Õ¯Õ¡ÕŽ ÕžÖÕ²Õ²Õ¡Õ¯Õ«ÕžÖÕ¥Õ¶ 
+ÕžÕœÕ¿Õ¡ÕµÕ¶Õ« ÕŸÖÕ¡: ÕÖÕžÕ· ÕÕœÕ¿Õ¡ÕµÕ¶Õ¡ÕµÕ«Õ¶ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥ÖÕ« Õ°Õ¡ÕŽÕ¡Ö Õ¯Õ¡ÖÕ¥Õ¬Õ« Õ§ ÕŸÕ¥ÖÕ¡Õ°ÕœÕ¯Õ¥Õ¬ Õ¡ÖÕ€ÕµÕžÖ Õ¯Õ¡ÕºÕ¥ÖÕš 
+âÕÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¡ÖÕ€ÕµÕžÖÕ¶ÖÕ¶Õ¥Öâ Õ§Õ»Õ«Ö Õ¿Õ¡Õ¶ÕžÖÕŽ Õ¥Õ¶ ÕžÖÕ²Õ²Õ¡Õ¯Õ«ÕžÖÕ¥Õ¶ Õ€Õ¥ÕºÕ« ÕÕ¡ÕŽÕšÕ¶Õ€Õ°Õ¡Õ¶ÕžÖÖ ÕºÕ¡Õ·Õ¡ÖÕ« ÕžÖÕœÕ«Õ¹Õ« ÕŸÖÕ¡ 
+Õ©Õ¥ Õ©ÕŸÕ¡ÕµÕ«Õ¶ Õ£ÖÕ¡Õ€Õ¡ÖÕ¡Õ¶Õ« Õ§Õ»Õ« ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ« ÕŸÖÕ¡:
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>ÕÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¶Õ¡Õ­Õ¡ÕºÕ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö</h3>
+<p>ÔµÖÕ¯ÕžÖ ÕŠÕžÖÕµÕ£ Õ¯ÕžÕ³Õ¡Õ¯Õ¶Õ¥Ö ÕŸÕ¥ÖÕ¡Õ°ÕœÕ¯ÕžÖÕŽ Õ¥Õ¶ Õ¿Õ¥ÖÕœÕ¿Õ« Õ¿Õ¥ÕœÕ¡Õ¯Õš ÕžÖÕš Õ¡ÕŒÕ¯Õ¡ Õ§ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕŽÕ¥Õ»: Ô±ÕŒÕ¡Õ»Õ«Õ¶ 
+Õ¢Õ¡ÕŠÕŽÕžÖÕ©ÕµÕžÖÕ¶Õš (ÕºÕ«Õ¿Õ¡Õ¯Õ¡ÕŸÕžÖÕŸÕ¡Õ® ÕžÖÕºÕ¥Õœ "ÕºÕ¡Õ¿Õ³Õ¡ÕŒÕ¡ÕµÕ«Õ¶ Õ¿Õ¡ÖÕ¢Õ¥ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö") ÕŸÕ¥ÖÕ¡Õ°ÕœÕ¯ÕžÖÕŽ Õ§, Õ¡ÖÕ€ÕµÕžÖ 
+ÕœÕ¿Õ¥Õ²Õ¶Õ¡Õ·Õ¡ÖÕ« ÕŸÕ¥ÖÕ«Õ¶ Ö ÕœÕ¿ÕžÖÕ«Õ¶ Õ¶Õ«Õ·Õ¥ÖÕš Õ°Õ¡ÕŽÕšÕ¶Õ¯Õ¶ÕžÖÕŽ Õ¥Õ¶: ÔµÖÕ¯ÖÕžÖÕ€Õš ("Õ¢Õ¡ÕŒÕ« ÕŸÕ¥ÖÕ»Õ¡ÕŸÕžÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥Ö") 
+ÕŸÕ¥ÖÕ¡Õ°ÕœÕ¯ÕžÖÕŽ Õ§ Õ¡ÖÕ€ÕµÕžÖ Õ¡Õ¶Õ¿Õ¥ÕœÕ¥Õ¬ Õ¢Õ¡ÕŒÕ¥ÖÕ« ÕŸÕ¥ÖÕ»Õ¡ÕŸÕžÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš Õ©Õ¥ ÕžÕ¹: ÕÕ¶Õ¡ÖÕ¡ÕŸÕžÖ Õ§ ÕœÕ¿Õ¡Õ¶Õ¡Õ¬ Õ°Õ¡ÖÖÕŽÕ¡Õ¶ 
+Õ¬Õ¡ÕµÕ¶ ÕºÕ¡Õ¿ÕžÖÕ°Õ¡Õ¶, Õ¡ÕµÕ¶ÕºÕ¥Õœ ÕžÖ  Õ¯Õ¡ÖÕ¥Õ¬Õ« Õ§ Õ«ÖÕ¡Õ¯Õ¡Õ¶Õ¡ÖÕ¶Õ¥Õ¬ ÕºÕ¡ÖÕ¡Õ£ÖÕ¡ÖÕ¡ÕµÕ«Õ¶-Õ°Õ«ÕŽÕ¶ÕŸÕ¡Õ® ÕžÖÕžÕ¶ÕžÖÕŽÕ¶Õ¥Ö: 
+
+<p>ÕÖÕ«Õ¶Õ¡Õ¯, Õ¥Õ©Õ¥ <i>Õ¡Õ¶Õ¿Õ¥ÕœÕ¥Õ¬ Õ€Õ¥ÕºÖÕ¥ÖÕ« Õ¿Õ¡ÖÕ¢Õ¥ÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš</i> Ö
+<i>Õ¡Õ¶Õ¿Õ¥ÕœÕ¥Õ¬ Õ¢Õ¡ÕŒÕ¥ÖÕ« ÕŸÕ¥ÖÕ»Õ¡ÕŸÕžÖÕžÖÕ©ÕµÕžÖÕ¶Õ¶Õ¥ÖÕš</i> Õ¯ÕžÕ³Õ¡Õ¯Õ¶Õ¥ÖÕš ÕšÕ¶Õ¿ÖÕŸÕ¡Õ® Õ¥Õ¶, Õ°Õ¥Õ¿ÖÕµÕ¡Õ¬ Õ°Õ¡ÖÖÕžÖÕŽÕš<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>Õ¯ÕšÕ¶Õ¯Õ¡Õ¬ÕŸÕ« ÕžÖÕºÕ¥Õœ Õ¶ÕžÖÕµÕ¶Õš, Õ«Õ¶Õ¹<p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      ÖÕ¡Õ¶ÕŠÕ« "African" Õ¢Õ¡ÕŒÕ« ÕŽÕ¥Õ®Õ¡Õ¿Õ¡ÕŒ A Õ¿Õ¡ÕŒÕš Õ¯Õ±ÖÕ¡ÖÕžÕ­ÕŸÕ« Õ«Ö ÖÕžÖÖÕ¡Õ¿Õ¡ÕŒÕ«Õ¶, Ö "n" ÕžÖ "ing" 
+      ÕŸÕ¥ÖÕ»Õ¡Õ®Õ¡Õ¶ÖÕ¶Õ¥ÖÕš Õ€ÕžÖÖÕœ Õ¯ÕŽÕ²ÕŸÕ¥Õ¶ "African" Ö "building" Õ¢Õ¡ÕŒÕ¥ÖÕ«Ö: ÕÕ¡Ö  "s" Õ¯Õ°Õ¡Õ¶ÕŸÕ«
+      "builds" Õ¢Õ¡ÕŒÕ«Ö):
+
+<p>Ô¿Õ¡ÖÕ¥Õ¬Õ« Õ§ Õ¡Õ¶ÖÕ¶Õ¥Õ¬ "Õ­ÕžÖÕ¡ÖÕŸÕ¡Õ®" Õ°Õ¡ÖÖÕŽÕ¡Õ¶ ÕŸÕ«Õ³Õ¡Õ¯Õ«Õ¶, ÕžÖÕš Õ©ÕžÖÕµÕ¬ Õ§ Õ¿Õ¡Õ¬Õ«Õœ Ö
+Õ£Õ¿Õ¡Õ£ÕžÖÕ®Õ¥Õ¬
+AND (&), OR (|), NOT (!) Õ¿Õ¥ÖÕŽÕ«Õ¶Õ¶Õ¥ÖÕš: ÕÕ¡ Õ©ÕžÖÕµÕ¬ Õ§ Õ¿Õ¡Õ¬Õ«Õœ Õ±ÖÕ¡Õ¯Õ¥ÖÕºÕ¥Õ¬ Õ¡ÕŸÕ¥Õ¬Õ« Õ³Õ·Õ£ÖÕ«Õ¿ Õ°Õ¡ÖÖÕžÖÕŽÕ¶Õ¥Ö: 
+Ô¿Õ¡ÖÕ¥Õ¬Õ« Õ§ ÕŽÕ«Õ¡ÖÕ¶Õ¥Õ¬ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ ÕºÕ¡Õ¿ÕŽÕžÖÕ©ÕµÕ¡Õ¶ Õ°Õ¶Õ¡ÖÕ¡ÕŸÕžÖÕžÖÕ©ÕµÕžÖÕ¶Õš, ÕžÖÕš ÖÕžÖÕµÖ Õ§ Õ¿Õ¡Õ¬Õ«Õœ ÕŸÕ¥ÖÕ»Õ«Õ¶ ÕŽÕ« ÖÕ¡Õ¶Õ« 
+Õ°Õ¡ÖÖÕžÖÕŽÕ¶Õ¥ÖÕš: ÕÕ¡ Õ°Õ¥Õ·Õ¿Õ¡ÖÕ¶ÕžÖÕŽ Õ§ Ö
+Õ£Õ¿ÕŸÕ¥Õ¬ÕžÕŸ Õ¶Õ¡Õ­ÕžÖÕ€ ÖÕ¶Õ¿ÖÕžÖÕŽÕ¶Õ¥ÖÕ«Ö, Õ«ÖÕ¡Õ¯Õ¡Õ¶Õ¡ÖÕ¶Õ¥Õ¬ Õ€ÖÕ¡Õ¶Ö ÕŽÕ« 
+ÖÕ«Õ¹ Õ±ÖÕ¡ÖÕžÕ­ÕŸÕ¡Õ® Õ¿Õ¡ÖÕ¢Õ¥ÖÕ¡Õ¯Õ¶Õ¥ÖÕš: ÕÕ¥ÖÕ»Õ¡ÕºÕ¥Õœ, ÕµÕžÖÖÕ¡ÖÕ¡Õ¶Õ¹ÕµÕžÖÖ ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ°Õ¡ÕŽÕ¡Ö Õ¯Õ¡ÖÕ¥Õ¬Õ« Õ§ ÕŸÕ¥ÖÕ¡Õ°ÕœÕ¯Õ¥Õ¬ 
+ÕŸÕ¥ÖÕ¡Õ€Õ¡ÖÕ±ÕŸÕ¡Õ® ÖÕ¶Õ¿ÖÕŽÕ¡Õ¶ Õ¢Õ¡ÕŠÕŽÕžÖÕ©ÕµÕžÖÕ¶Õš:
+}
+
+_texttanumbrowseoptions_ [l=hy] {Ô±ÕŒÕ¯Õ¡ Õ¥Õ¶ _numbrowseoptions_ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õ¶Õ¥Ö Õ¡ÕµÕœ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ« ÕŽÕ¥Õ» Õ¿Õ¥Õ²Õ¥Õ¯Õ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶ Õ£Õ¿Õ¶Õ¥Õ¬ÕžÖ Õ°Õ¡ÕŽÕ¡Ö: }
+
+_textsimplehelpheading_ [l=hy] {Ô»Õ¶Õ¹ÕºÕ¥Õœ Õ£Õ¿Õ¶Õ¥Õ¬ Õ¿Õ¥Õ²Õ¥Õ¯Õ¡Õ¿ÕŸÕžÖÕ©ÕµÕžÖÕ¶ _collectionname_ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ« ÕŽÕ¥Õ»}
+
+_texthelpscope_ [l=hy] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>ÕÕ¡ÖÖÕŽÕ¡Õ¶ Õ¿Õ«ÖÕžÖÕµÕ©</h3>
+
+<p>
+ÕÕ¡Õ¿ Õ°Õ¡ÕŸÕ¡ÖÕ¡Õ®ÕžÖÕ¶Õ¥ÖÕžÖÕŽ ÕžÖÕžÕ¶ÕŽÕ¡Õ¶ Õ°Õ¡ÕŽÕ¡Ö Õ¯Õ¡ÖÕžÕ² Õ¥Ö ÕšÕ¶Õ¿ÖÕ¥Õ¬ Õ¿Õ¡ÖÕ¢Õ¥Ö ÖÕžÖÖÕ«Õ¹Õ¶Õ¥Ö: 
+ÕÖÕ«Õ¶Õ¡Õ¯, Õ¯Õ¡ÖÕžÕ² Õ¥Õ¶ Õ¬Õ«Õ¶Õ¥Õ¬ Õ°Õ¥Õ²Õ«Õ¶Õ¡Õ¯Õ¶Õ¥ÖÕ« Õ¯Õ¡ÕŽ ÕŸÕ¥ÖÕ¶Õ¡Õ£ÖÕ¥ÖÕ« ÖÕžÖÖÕ«Õ¹Õ¶Õ¥Ö: Ô¿Õ¡ÕŽ ÕºÕ¡ÖÕ¡Õ£ÖÕ¡ÖÕ¶Õ¥ÖÕ«  
+ÖÕžÖÖÕ«Õ¹Õ¶Õ¥Ö:
+ÔžÕ¶Õ€Õ°Õ¡Õ¶ÖÕ¡ÕºÕ¥Õœ, ÖÕ¡ÕœÕ¿Õ¡Õ©ÕžÖÕ²Õ©Õš Õ£Õ¿Õ¶ÕŸÕžÖÕŽ Õ§, Õ¡Õ¶Õ¯Õ¡Õ­ Õ©Õ¥ Õ«Õ¶Õ¹ ÖÕžÖÖÕ«Õ¹ÕžÕŸ Õ¥Õœ ÖÕ¶Õ¿ÖÕžÖÕŽ:
+<p>ÔµÕ©Õ¥ ÖÕ¡ÕœÕ¿Õ¡Õ©Õ²Õ©Õ¥ÖÕš Õ£ÖÖÕ¥Ö Õ¥Õ¶, Õ¶ÖÕ¡Õ¶Ö Õ¯Õ¢Õ¡ÖÕŸÕ¥Õ¶ Õ°Õ¡ÕŽÕ¡ÕºÕ¡Õ¿Õ¡ÕœÕ­Õ¡Õ¶ Õ¿Õ¥Õ²ÕžÖÕŽ:
+
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/authen.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/authen.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/authen.dm	(revision 10506)
@@ -0,0 +1,66 @@
+# this file must be UTF-8 encoded
+
+package authen
+
+#######################################################################
+# page content                     
+#######################################################################
+
+_pagetitle_ {_textGSDLtitle_}
+_imagethispage_ {_imagegreenstone_}
+
+_content_ {
+<br><br><br><br>
+<form name="login" method="get" action="_gwcgi_">
+<input type=hidden name="e" value="_If_(_cgiarger_,_cgiarger_,_decodedcompressedoptions_)">
+_hiddenargs_
+<center><table width=_pagewidth_>
+<tr><td>
+_messagestatus_
+</td></tr>
+
+<tr><td>
+<table><tr><td>_textusername_</td>
+<td><input type="text" name="un" value="_cgiargun_" size=10></td>
+<td></td></tr>
+<tr><td>_textpassword_</td>
+<td><input type="password" name="pw" size=10></td>
+<td><input type="submit" value="_textsignin_"></td>
+</tr>
+</table>
+</td></tr>
+</table>
+</form>
+}
+
+
+_messageinvalid_ {_textmessageinvalid_}
+
+_messagefailed_ {_textmessagefailed_}
+
+_messageenabled_ {}
+
+_messagedisabled_ {_textmessagedisabled_}
+
+_messagepermissiondenied_ {_textmessagepermissiondenied_}
+
+_messagestalekey_ {_textmessagestalekey_}
+
+
+#################################
+# when authentication is accepted
+#################################
+
+package authenok
+
+
+#######################################################################
+# page content                     
+#######################################################################
+
+_pagetitle_ {_authen:textGSDLtitle_}
+_imagethispage_ {_imagegreenstone_}
+
+_content_ {
+_authen:messagestatus_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/base.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/base.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/base.dm	(revision 10506)
@@ -0,0 +1,878 @@
+# this file must be UTF-8 encoded
+#######################################################################
+# GLOBAL MACROS 
+#######################################################################
+
+package Global
+
+##########
+
+_optsite_ {}
+
+
+##########
+
+_htmlextra_ {}
+
+#_starthighlight_ {<b><u>}
+#_endhighlight_ {</u></b>}
+
+_starthighlight_ {<span style="background: #FFFF77">}
+_endhighlight_ {</span>}
+
+#######################################################################
+# page content
+#
+# these should always be overridden for each page/collection 
+#######################################################################
+
+_content_ {<p><h2>oops</h2>
+_textdefaultcontent_}
+_pagetitle_ {_textdefaulttitle_}
+_imagethispage_ {}
+_iconcollection_ {}
+_collectionname_ {}
+
+package Usability
+
+_content_ {
+<h2>_textaboutusabilitytitle_</h2>
+<p>_textaboutusability_
+}
+_pagetitle_{_textaboutusabilitypagetitle_}
+
+package Privacy
+_content_ {
+<h2>_textaboutprivacytitle_</h2>
+<p>_textaboutprivacy_
+}
+_pagetitle_{_textaboutprivacypagetitle_}
+
+package Global
+  
+
+_imagecollection_ {_If_("_iconcollection_" ne "",
+<a href="_httppageabout_"><img src="_iconcollection_" border=0 title="_collectionname_"></a>,
+_imagecollectionv_)}
+_imagecollection_ [v=1] {_imagecollectionv_}
+_imagecollectionv_ {_If_(_collectionname_,<br><br><h2><a href="_httppageabout_">_collectionname_</a></h2>)}
+
+#######################################################################
+# these width macros are read in by the server when calculating 
+# width of navigation bar etc. There should be one for each 
+# classification that this receptionist supports, one for the 
+# search button, and the _pagewidth_ macro which is the total width
+# of the page
+#######################################################################
+
+# width of tabs when displaying tables of contents
+_tabwidth_ {25}
+
+_pagewidth_ {537}
+# defaultwidth is the width buttons default to if not included in this list
+# but you need to define a _METAwidth_ tag as the server tests that it exists!
+_defaultwidth_ {87}
+_searchwidth_ {_widthtsrchx_}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_Titlewidth_ {_widthttitlex_}
+_Creatorwidth_ {_widthtcreatx_}
+_Subjectwidth_ {_widthtsubjx_}
+_Descriptionwidth_ {_widthtdescx_}
+_Publisherwidth_ {_widthtpublx_}
+_Contributorwidth_ {_widthtcontrx_}
+_Datewidth_ {_widthtdatex_}
+_Typewidth_ {_widthttypex_}
+_Formatwidth_ {_widthtformx_}
+_Identifierwidth_ {_widthtidentx_}
+_Sourcewidth_ {_widthtsrcx_}
+_Languagewidth_ {_widthtlangx_}
+_Relationwidth_ {_widthtrelx_}
+_Coveragewidth_ {_widthtcoverx_}
+_Rightswidth_ {_widthtrightx_}
+
+_Collagewidth_ {_widthtcollx_}
+_Listwidth_ {_widthtlistx_}
+_Serieswidth_ {_widthtserx_}
+_Towidth_ {_widthttox_}
+_Fromwidth_ {_widthtfromx_}
+_Organizationwidth_ {_widthtorgx_}
+_Howtowidth_ {_widththowx_}
+_Topicwidth_ {_widthttopicx_}
+_Browsewidth_ {_widthtbrwsex_}
+_Peoplewidth_ {_widthtpeopx_}
+_Acronymwidth_ {_widthtacrox_}
+_Phrasewidth_ {_widthtphrsex_}
+_Artistwidth_ {_widthtartstx_}
+_Keywordwidth_ {_widthtkwx_}
+_Volumewidth_ {_widthtvolx_}
+_Captionswidth_ {_widthtcaptx_}
+_Countrieswidth_ {_widthcountx_}
+
+#######################################################################
+# Macros whose values are set from within the server at runtime. These 
+# are here only for reference and to set default values if required.           
+#######################################################################
+
+# _win32_ will be set to 1 if we're on windows
+_win32_ {}
+
+_navigationbar_ {}
+_widthtspace_ {2}
+
+# The following is useful if collection specific macro.  Override
+# _optnavigationbar_ to be empty if you don't want the navigation bar to
+# appear in the standard place, and then specify _navigationbar_ elsewhere
+# in a collection specific macro file(s) to be where you do want it.
+_optnavigationbar_{_navigationbar_} 
+
+_usability_ {}
+
+# all cgi args are set as _cgiargX_ macros - those I've put here 
+# are those that need to default to something
+_cgiargd_ {}
+_cgiargcl_ {}
+
+# set from within the query action
+_hselection_ {}
+_jselection_ {}
+_nselection_ {}
+#level (granularity) selection for mgpp
+_gselection_ {}
+#level selection for form searching - dont have paragraph
+_gformselection_ {_gselection_} 
+_fqfselection_ {}
+
+#######################################################################
+# flashy rollover image macro
+#
+#######################################################################
+
+# imagescript should always be included in html header if there are
+# flashy images on the page
+_imagescript_ {
+var loaded = new Array();
+function gbutton (image, onimage) \{
+  if (image && image.src && (image.out == null || typeof(image.out) == typeof(void(0)))) \{
+    s = image.src;
+    image.out = new Image();
+    image.out.src = s;
+    image.over = new Image();
+    image.over.src = onimage;
+    loaded[image.name] = image;
+  \}
+\}
+
+function roll (imagename, over) \{
+  if (document.images) \{
+    if (over) i = "over";
+    else i = "out";
+    image = loaded[imagename];
+    if (image) image.src = eval("image."+i+".src");
+  \}
+\}
+}
+
+# gsimage should be used to define an instance of a flashy image
+# parameters are:
+# 1. the url to go to when the button is clicked
+# 2. the url of the "off" image
+# 3. the url of the "on" image
+# 4. the name of the image (must be unique)
+# 5. image alt text
+_gsimage_ {<a href="_1_" onMouseover="roll('_4_',1);" onMouseOut="roll('_4_',0);"><img
+name="_4_" src="_2_" onLoad="gbutton(this,'_3_');" border=0 alt="_5_" title="_5_"></a>}
+
+_gsimage_ [v=1] {<a href="_1_">_5_</a><br>}
+
+_usabilityscript_ {}
+
+_usabshowscript_ {
+
+//this is for where something goes wrong and an error message has to be shown.
+function failnicely(message,usabwindow)\{
+  var errhtml='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">';
+  errhtml+='<head><title>_greenstoneusabilitytext__texterror_</title><meta http-equiv="Content-Type" content="text/html; charset=_cgiargw_"></head><body bgcolor="#FFFFFF">';
+  errhtml+='_usabbanner_';	
+  errhtml+=message;
+  errhtml+='<p><form action=""><input type="button" value="_textclosewindow_" onClick="window.close();"></form>';
+  errhtml+='</body></html>';
+  usabwindow.document.write(errhtml);
+  usabwindow.document.close();
+\} 
+
+function usabilityfunction()\{
+
+  checkusab=window.open("","checkusab","scrollbars=1,toolbars=0,height=600,width=420");
+
+  //set up the window
+  var winhtml='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">';
+  winhtml += '<html><head><title>_greenstoneusabilitytext_</title>';
+  winhtml += '<script type="text/javascript">\\n';
+  
+  //this function is for getting the time when the complaint data is sent
+  winhtml += 'function gettime()\\{\\n';
+  winhtml += 'document.usabform.sendtime.value = (new Date()).toString();\\n'
+  winhtml+='\\}\\n';
+
+  //this function is to allow the user to track the usability report	
+  winhtml+='function viewdetails()\\{\\n';
+  winhtml+='\\t alert(\\'_textunderdev_\\');\\}';	
+
+  //this function is to show the privacy/about data in a new window
+  winhtml+='function infowindow(url)\\{  \\
+   infowin = window.open(url,\\'infowin\\',\\'toolbars=0, height=600, width=600\\'); \\
+ \\}';
+ 
+  winhtml += '</script>';
+  if(navigator.appName!="Netscape" || parseInt(navigator.appVersion)>=5)\{
+	winhtml += '_usabstyle_';
+  \}
+
+  //need a character type for valid html
+  winhtml+='<meta http-equiv="Content-Type" content="text/html; charset=_cgiargw_"></head><body bgcolor=\"#FFFFFF\">';
+
+  //get the location of the cgi program
+  cgiloc='_gwcgi_';
+  if(cgiloc.lastIndexOf("/")<0)\{
+     failnicely('_cannotfindcgierror_', checkusab);
+     return;
+  \}   
+  cgiloc=cgiloc.substring(0,(cgiloc.lastIndexOf("/")+1));	
+  cgiloc+='perl.cgi';
+   
+  //adds the banner with the koru-thing and the links to about and privacy 
+  //information 
+  winhtml+='_usabbanner_';
+  winhtml+='_aboutprivacylinks_';
+	
+
+  // set up the form	
+  winhtml += '<form name="usabform" method="post" action="'+cgiloc+'" onSubmit="gettime();">';
+  winhtml += '_usabinterface_';
+
+
+  //get javascript environment variables
+
+  // to replace &s in the URL with &amp;s
+  urlgs=new String(window.location);
+  a=urlgs.split("&");
+  urlgs=a.join("&amp;"); 
+  winhtml+=('<input type="hidden" name="URL" value="'+urlgs+'">');
+  
+  winhtml+=('<input type="hidden" name="resolution" value="'+window.screen.width+'x'+window.screen.height+'">');
+  winhtml+=('<input type="hidden" name="screencolour" value="'+window.screen.color+'">');
+
+  //colordepth and pixeldepth are NS and IE versions of the same thing. 
+   if(screen.colorDepth)\{
+	winhtml+=('<input type="hidden" name="pixeldepth" value="'+window.screen.colorDepth+'">');
+   \}
+  else\{
+	winhtml+=('<input type="hidden" name="pixeldepth" value="'+window.screen.pixelDepth+'">');
+   \}
+	
+  winhtml+=('<input type="hidden" name="browser" value="'+navigator.platform+' ,'+navigator.appName+', '+navigator.appVersion+', '+navigator.appCodeName+', '+navigator.appUserAgent+'">');
+  winhtml+=('<input type="hidden" name="language" value="'+navigator.language+'">');		
+  winhtml+=('<input type="hidden" name="opentime" value="'+(new Date()).toString()+'">');	
+  winhtml+=('<input type="hidden" name="sendtime" value="None">');
+  winhtml+=('<input type="hidden" name="collection" value="_cgiargc_">');
+  if(document.getElementsByTagName)\{	
+   //get interface variables
+   if(document.getElementsByTagName("form"))\{
+     docarray=document.getElementsByTagName("input");
+     if(docarray.length>0)\{
+       for(i=0; i<docarray.length; i++)\{
+          //this leaves out uninteresting inputs, such as buttons 
+	  //and unchecked checkboxes
+         if(docarray[i].type!='reset' && docarray[i].type!='button' && 
+	    docarray[i].type!='image' && docarray[i].type!='submit'
+	    && !((docarray[i].type=='radio'|| docarray[i].type=='checkbox') && 
+	    !docarray[i].checked))\{
+	       winhtml+=('<input type="hidden" name="'+docarray[i].type+'-'+docarray[i].name+'" value="'+docarray[i].value+'">');
+	 \}     
+       \}
+     \} 
+     docarray=document.getElementsByTagName("select")
+     if(docarray.length>0)\{
+        for(i=0; i<docarray.length; i++)\{
+           winhtml+=('<input type="hidden" name="'+docarray[i].type+'-'+docarray[i].name+'" value="'+docarray[i].value+'">');
+         \} 
+      \}
+      docarray=document.getElementsByTagName("textarea")
+      if(docarray.length>0)\{
+        for(i=0; i<docarray.length; i++)\{
+           winhtml+=('<input type="hidden" name="'+docarray[i].type+'-'+docarray[i].name+'" value="'+docarray[i].value+'">');
+         \} 
+      \}
+   \}
+ \}	
+  //finish the form
+  winhtml += '</form>';
+  
+  winhtml +='</body></html>'
+
+	
+  //write to the window	
+  checkusab.document.write(winhtml);
+  checkusab.document.close();	
+  return;	
+
+\}
+}
+
+#####################################################################
+#
+#  These macros are for use by the usability logging (I'd like to
+#  complain)  functionality - they are to be included in a JavaScript
+#  string, hence the \s 
+#
+#####################################################################
+
+_usabinterface_{}
+
+#the banner to "brand" any boxes as part of the usability interface
+_usabbanner_{<table width=\"100%\"><tr><td><h1>_greenstoneusabilitytext_</h1></td><td align="right" width="135"><img src=\"_httpusabbanner_\" title=\"_textusabbanner_\" alt=\"_textusabbanner_\"></td></tr></table>}
+
+#the about and privacy lins separated by a mid dot.
+_aboutprivacylinks_ {<p class="label"><a href="javascript:infowindow(\\'http://nzdl2.cs.waikato.ac.nz/dana/gsdl/about.html\\')">_textabout_</a> &#8226; <a href="javascript:infowindow(\\'http://nzdl2.cs.waikato.ac.nz/dana/gsdl/privacy.html\\')">_textprivacy_</a>}
+
+#gives a text only interface with some guff about privacy
+_usabtextonly_{ \\
+_textwhy_\\
+_textprivacybasic_\\
+_textstillsend_\\
+_usabyesnosubmit_}
+
+_usabyesnosubmit_{<p><input type="submit" value="_textyes_"><input type="button" value="_textno_" onClick="window.close();">}
+
+#gives an interface with the privacy guff at the bottom, and 
+#steps to describe the problem
+_usabstepwise_{\\
+<p>_textwhatdoing_<br> \\
+<textarea name="doingwhat" rows="3" cols="40"></textarea> \\
+<p>_textwhatexpected_<br> \\
+<textarea name="whatexpected" rows="6" cols="40"></textarea> \\
+<p>_textwhathappened_<br> \\
+<textarea name="whathappened" rows="6" cols="40"></textarea> \\
+_usabtextonly_}
+
+#gives a multipart interface allowing the user to fill out less or more.
+_usabmulti_{\\
+_textwhy__textextraforform_\\
+<h2>_textoptionally_:</h2>\\
+<p class="label">_textmoredetails_:<br>\\
+<textarea name="moredetails" rows="6" cols="45"></textarea>\\
+<table><tr><td>\\
+<p class="label">_textcharacterise_? </td>\\
+<td><select name="probtype">\\
+<option>\\
+<option>_textbadrender_\\
+<option>_textcontenterror_\\
+<option>_textstrangebehaviour_\\
+<option>_textunexpected_\\
+<option>_textfunctionality_\\
+<option>_textother_\\
+</select></td></tr>\\
+<tr><td><p class="label">_textseverity_? </td>\\
+<td><select name="severity">\\
+<option>\\
+<option>_textcritical_\\
+<option>_textmajor_\\
+<option>_textmedium_\\
+<option>_textminor_\\
+<option>_texttrivial_\\
+</select>\\
+</td></tr></table>\\
+_textprivacybasic__textstillsend_\\
+<table width="100%"><tr><td><a href="javascript:viewdetails()"><p class="label">_textviewdetails_</a></td><td align="right"><button type="button" onClick="window.close()"><b>_textdontsend_</b></button></td><td align="right"><button type="submit"><b>_textsend_</b></button></td></tr></table>\\
+}
+
+#style definitions to please NS 4.7
+_usabstyle_{\\
+<style type="text/css">\\
+\\
+table \{ width: 100% \} \\
+td.right \{ align:right \} \\
+\\
+h1 \{font-size:20px; font-family: sans-serif; vertical-align:middle\\} \\
+h2 \{font-size:14px; color: #009966; font-family: sans-serif; font-weight:bold \}\\
+p.label \{ font-family:sans-serif; \}\\
+</style>\\
+}
+
+
+
+#######################################################################
+# navigation bar images
+#
+#######################################################################
+
+# the spacer image - the width of this is set from server
+_imagespacer_ {<img 
+src="_httpicontspace_" width="_widthtspace_" height="_heighttspace_">}
+_imagespacer_[v=1] {<br>
+}
+
+# image macros for all the classifications currently supported by
+# this receptionist.
+
+_imagesearch_ {_If_("_cgiargu_" ne "1",_imagesearch2_,_iconnosearch_)}
+_imagesearch2_ {_gsimage_(_httpquery_,_httpicontsrchof_,_httpicontsrchon_,srch,_textimagesearch_)}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_imageTitle_ {_gsimage_(_httpbrowseTitle_,_httpiconttitleof_,_httpiconttitleon_,titles,_textimageTitle_)}
+_imageCreator_ {_gsimage_(_httpbrowseCreator_,_httpicontcreatof_,_httpicontcreaton_,creators,_textimageCreator_)}
+_imageSubject_ {_gsimage_(_httpbrowseSubject_,_httpicontsubjof_,_httpicontsubjon_,subjects,_textimageSubject_)}
+_imageDescription_ {_gsimage_(_httpbrowseDescription_,_httpicontdescof_,_httpicontdescon_,descriptions,_textimageDescription_)}
+_imagePublisher_ {_gsimage_(_httpbrowsePublisher_,_httpicontpublof_,_httpicontpublon_,publishers,_textimagePublisher_)}
+_imageContributor_ {_gsimage_(_httpbrowseContributor_,_httpicontcontrof_,_httpicontcontron_,contributors,_textimageContributor_)}
+_imageDate_ {_gsimage_(_httpbrowseDate_,_httpicontdateof_,_httpicontdateon_,dates,_textimageDate_)}
+_imageType_ {_gsimage_(_httpbrowseType_,_httpiconttypeof_,_httpiconttypeon_,types,_textimageType_)}
+_imageFormat_ {_gsimage_(_httpbrowseFormat_,_httpicontformof_,_httpicontformon_,formats,_textimageFormat_)}
+_imageIdentifier_ {_gsimage_(_httpbrowseIdentifier_,_httpicontidentof_,_httpicontidenton_,identifiers,_textimageIdentifier_)}
+_imageSource_ {_gsimage_(_httpbrowseSource_,_httpicontsrcof_,_httpicontsrcon_,source,_textimageSource_)}
+_imageLanguage_ {_gsimage_(_httpbrowseLanguage_,_httpicontlangof_,_httpicontlangon_,language,_textimageLanguage_)}
+_imageRelation_ {_gsimage_(_httpbrowseRelation_,_httpicontrelof_,_httpicontrelon_,relations,_textimageRelation_)}
+_imageCoverage_ {_gsimage_(_httpbrowseCoverage_,_httpicontcoverof_,_httpicontcoveron_,coverage,_textimageCoverage_)}
+_imageRights_ {_gsimage_(_httpbrowseRights_,_httpicontrightof_,_httpicontrighton_,rights,_textimageRights_)}
+
+_imageSeries_ {_gsimage_(_httpbrowseSeries_,_httpicontserof_,_httpicontseron_,series,_textimageSeries_)}
+_imageTo_ {_gsimage_(_httpbrowseTo_,_httpiconttoof_,_httpiconttoon_,to,_textimageTo_)}
+_imageFrom_ {_gsimage_(_httpbrowseFrom_,_httpicontfromof_,_httpicontfromon_,from,_textimageFrom_)}
+_imageOrganization_ {_gsimage_(_httpbrowseOrganization_,_httpicontorgof_,_httpicontorgon_,org,_textimageOrganization_)}
+_imageHowto_ {_gsimage_(_httpbrowseHowto_,_httpiconthowof_,_httpiconthowon_,how,_textimageHowto_)}
+_imageTopic_ {_gsimage_(_httpbrowseTopic_,_httpiconttopicof_,_httpiconttopicon_,topic,_textimageTopic_)}
+_imageBrowse_ {_gsimage_(_httpbrowseBrowse_,_httpicontbrwseof_,_httpicontbrwseon_,browse,_textimageBrowse_}
+_imagePeople_ {_gsimage_(_httpbrowsePeople_,_httpicontpeopof_,_httpicontpeopon_,people,_textimagePeople_)}
+_imageAcronym_ {_gsimage_(_httpbrowseAcronym_,_httpicontacroof_,_httpicontacroon_,acronym,_textimageAcronym_)}
+_imageCollage_ {_gsimage_(_httpbrowseCollage_,_httpicontcollof_,_httpicontcollon_,collage,_textimageCollage_)}
+_imagePhrase_ {_gsimage_(_httpbrowsePhrase_,_httpicontphrseof_,_httpicontphrseon_,phrase,_textimagePhrase_)}
+_imageArtist_ {_gsimage_(_httpbrowseArtist_,_httpicontartstof_,_httpicontartston_,artist,_textimageArtist_)}
+_imageKeyword_ {_gsimage_(_httpbrowseKeyword_,_httpicontkwof_,_httpicontkwon_,kw,_textimageKeyword_)}
+_imageVolume_ {_gsimage_(_httpbrowseVolume_,_httpicontvolof_,_httpicontvolon_,volume,_textimageVolume_)}
+_imageCaptions_ {_gsimage_(_httpbrowseCaptions_,_httpicontcaptof_,_httpicontcapton_,captions,_textimageCaptions_)}
+_imageCountries_ {_gsimage_(_httpbrowseCountries_,_httpicontcountof_,_httpicontcounton_,countries,_textimageCountries_)}
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. 
+
+_javalinks_ {_imagehome_ _imagehelp_ _imagepref_ _usability_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+_imagehelp_<br>
+_imagepref_<br>
+_usability_<br>
+}
+
+
+#######################################################################
+# general web macros 
+#######################################################################
+
+_mailaddr_ {greenstone@cs.waikato.ac.nz}
+
+_gsdltop_ {_top}
+
+#######################################################################
+# http macros 
+#
+# These contain the url without any quotes
+#######################################################################
+
+_httpcimages_ {_httpcollection_/images}
+_httpcollimg_ {_httpcollection_/index/assoc}
+_httpdocimg_ {_httpcollimg_/_thisOID_}
+
+_httpcollection_ {_httpprefix_/collect/_cgiargc_}
+
+_httppagex_ {_gwcgi_?e=_compressedoptions_&a=p&p=_1_}
+_httppagestatus_ {_gwcgi_?e=_compressedoptions_&a=status&p=frameset}
+_httppagetranslator_ {_gwcgi_?e=_compressedoptions_&a=gti&p=home}
+_httppagecollector_ {_gwcgi_?e=_compressedoptions_&a=collector&p=intro}
+_httppagegli_ {_httppagex_(gli)}
+_httppageabout_ {_httppagex_(about)}
+#_httppagehome_ {_httppagex_(home)}
+###_httppagehome_ {http://www.nzdl.org/cgi-bin/dblibrary?a=p&p=home}
+_httppagehome_ {_gwcgi_?a=p&p=home&l=_cgiargl_&w=_cgiargw_}
+_httppagehelp_ {_httppagex_(help)}
+_httppagepref_ {_httppagex_(preferences)}
+_httppagedocs_ {_httppagex_(docs)}
+_httpclearhistory_ {_gwcgi_?e=_compressedoptions_&a=dh}
+
+_httppageusab_ {javascript:usabilityfunction()}
+_httpgreenstone_ {_httppagex_(gsdl)}
+_httpdownload_ {http://www.nzdl.org/download}
+_httppublications_ {_httpdownload_/greenstone/publications}
+
+_httpcurrentdocument_ {_gwcgi_?e=_compressedoptions_&cl=_cgiargcl_&d=_cgiargd_}
+_httpquery_ {_gwcgi_?e=_compressedoptions_&a=q}
+_httpBrowse_ {_gwcgi_?e=_compressedoptions_&a=br}
+
+# _httpdoc_ is the same as _httpdocument_ - _httpdocument_
+# may occasionally be altered by the server however
+_httpdocument_ {_gwcgi_?e=_compressedoptions_&a=d}
+_httpdoc_  {_gwcgi_?e=_compressedoptions_&a=d}
+
+_httpextlink_ {_gwcgi_?e=_compressedoptions_&a=extlink}
+_httpbuild_ {_gwcgi_?e=_compressedoptions_&a=bc}
+
+_httpiconchalk_ {_httpimg_/chalk.gif}
+_widthchalk_ {2000}
+_heightchalk_ {10}
+
+_httpicondivb_ {_httpimg_/divb.gif}
+_widthdivb_ {_pagewidth_}
+_heightdivb_ {17}
+
+_httpicongsdl_ {_httpimg_/gsdl.gif}
+_widthgsdl_ {140}
+_heightgsdl_ {77}
+
+_httpusabbanner_ {_httpimg_/usabbnr.gif}
+
+_httpiconitext_ {_httpimg_/itext.gif}
+_widthitext_ {16}
+_heightitext_ {21}
+
+_httpiconiworld_ {_httpimg_/iworld.gif}
+_widthiworld_ {16}
+_heightiworld_ {21}
+
+_httpiconiunknown_ {_httpimg_/iunknown.gif}
+_widthiunknown_ {16}
+_heightiunknown_ {21}
+
+_httpiconibtext_ {_httpimg_/ibtext.gif}
+_widthibtext_ {16}
+_heightibtext_ {21}
+
+_httpiconimpegvideo_ {_httpimg_/impegvid.gif}
+_widthimpegvideo_ {29}
+_heightimpegvideo_ {32}
+
+_httpiconiqtvideo_ {_httpimg_/iqtvideo.gif}
+_widthiqtvideo_ {29}
+_heightiqtvideo_ {32}
+
+_httpiconirmvideo_ {_httpimg_/irmvideo.gif}
+_widthirmvideo_ {29}
+_heightirmvideo_ {32}
+
+_httpiconless_ {_httpimg_/less.gif}
+_widthless_ {30}
+_heightless_ {16}
+
+_httpiconmore_ {_httpimg_/more.gif}
+_widthmore_ {30}
+_heightmore_ {16}
+
+_httpiconspacer_ {_httpimg_/spacer.gif}
+_widthspacer_ {42}
+_heightspacer_ {4}
+
+_httpicontabspace_ {_httpimg_/tabspace.gif}
+_widthtabspace_ {23}
+_heighttabspace_ {1}
+
+_httpicontspace_ {_httpimg_/tspace.gif}
+_heighttspace_ {17}
+
+_httpiconwarning_ {_httpimg_/warning.gif}
+_widthwarning_ {30}
+_heightwarning_ {29}
+
+_httpiconhhome_ {_httpimg_/h\_home.gif}
+_widthhhome_ {200}
+_heighthhome_ {57}
+
+_httpiconarrrght_ {_httpimg_/arrrght.gif}
+_widtharrrght_ {23}
+_heightarrrght_ {15}
+
+_httpiconopenbook_ {_httpimg_/openbook.gif}
+_widthopenbook_ {28}
+_heightopenbook_ {23}
+
+_httpiconaopenbk_ {_httpimg_/aopenbk.gif}
+_widthaopenbk_ {28}
+_heightaopenbk_ {23}
+
+_httpiconopenfldr_ {_httpimg_/openfldr.gif}
+_widthopenfldr_ {23}
+_heightopenfldr_ {15}
+
+_httpiconaopenfdr_ {_httpimg_/aopenfdr.gif}
+_widthaopenfdr_ {23}
+_heightaopenfdr_ {15}
+
+_httpiconbook_ {_httpimg_/book.gif}
+_widthbook_ {18}
+_heightbook_ {11}
+
+_httpiconabook_ {_httpimg_/abook.gif}
+_widthabook_ {18}
+_heightabook_ {11}
+
+_httpiconbshelf_ {_httpimg_/bshelf.gif}
+_widthbshelf_ {20}
+_heightbshelf_ {16}
+
+_httpiconabshelf_ {_httpimg_/abshelf.gif}
+_widthabshelf_ {20}
+_heightabshelf_ {16}
+
+_httpiconsmtext_ {_httpimg_/smtext.gif}
+_widthsmtext_ {23}
+_heightsmtext_ {15}
+
+_httpiconasmtext_ {_httpimg_/asmtext.gif}
+_widthasmtext_ {23}
+_heightasmtext_ {15}
+
+_httpiconclsdfldr_ {_httpimg_/clsdfldr.gif}
+_widthclsdfldr_ {23}
+_heightclsdfldr_ {15}
+
+_httpiconaclsdfdr_ {_httpimg_/aclsdfdr.gif}
+_widthaclsdfdr_ {23}
+_heightaclsdfdr_ {15}
+
+_httpiconimidi_ {_httpimg_/imidi.gif}
+_widthimidi_ {16}
+_heightimidi_ {21}
+
+_httpiconimsword_ {_httpimg_/imsword.gif}
+_widthimsword_ {26}
+_heightimsword_ {26}
+
+_httpiconimp3_ {_httpimg_/mp3icon.gif}
+_widthimp3_ {25}
+_heightimp3_ {20}
+
+_httpiconipdf_ {_httpimg_/ipdf.gif}
+_widthipdf_ {26}
+_heightipdf_ {26}
+
+_httpiconips_ {_httpimg_/ips.gif}
+_widthips_ {25}
+_heightips_ {32}
+
+_httpiconippt_ {_httpimg_/ippt.gif}
+_widthippt_ {32}
+_heightippt_ {30}
+
+_httpiconirtf_ {_httpimg_/irtf.gif}
+_widthirtf_ {29}
+_heightirtf_ {32}
+
+_httpiconixls_ {_httpimg_/iexcel.gif}
+_widthixls_ {32}
+_heightixls_ {30}
+
+#######################################################################
+# Icons 
+#
+# Must not include links (so they can be used as links). If you want to
+# include links use _image
+#######################################################################
+
+_iconnext_{<img src="_httpiconmore_" align=absbottom 
+width=_widthmore_ height=_heightmore_ border=0 alt="_texticonnext_" title="_texticonnext_">}
+_iconnext_[v=1] {_texticonnext_}
+
+_iconprev_{<img src="_httpiconless_" align=absbottom 
+width=_widthless_ height=_heightless_ border=0 alt="_texticonprev_" title="_texticonprev_">}
+_iconprev_[v=1] {_texticonprev_}
+
+_icontabsearchgreen_ {<img 
+src="_httpicontsrchgr_" width=_widthtsrchx_ border=0>}
+_icontabsearchgreen_[v=1] {_texticontabsearchgreen_}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_icontabTitlegreen_ {<img src="_httpiconttitlegr_" width=_widthttitlex_ border=0>}
+_icontabTitlegreen_[v=1] {_texticontabTitlegreen_}
+
+_icontabCreatorgreen_ {<img src="_httpicontcreatgr_" width=_widthtcreatx_ border=0>}
+_icontabCreatorgreen_[v=1] {_texticontabCreatorgreen_}
+
+_icontabSubjectgreen_ {<img src="_httpicontsubjgr_" width=_widthtsubjx_ border=0>}
+_icontabSubjectgreen_[v=1] {_texticontabSubjectgreen_}
+
+_icontabDescriptiongreen_ {<img src="_httpicontdescgr_" width=_widthtdescx_ border=0>}
+_icontabDescriptiongreen_[v=1] {_texticontabDescriptiongreen_}
+
+_icontabPublishergreen_ {<img src="_httpicontpublgr_" width=_widthtpublx_ border=0>}
+_icontabPublishergreen_[v=1] {_texticontabPublishergreen_}
+
+_icontabContributorgreen_ {<img src="_httpicontcontrgr_" width=_widthtcontrx_ border=0>}
+_icontabContributorgreen_[v=1] {_texticontabContributorgreen_}
+
+_icontabDategreen_ {<img src="_httpicontdategr_" width=_widthtdatex_ border=0>}
+_icontabDategreen_[v=1] {_texticontabDategreen_}
+
+_icontabTypegreen_ {<img src="_httpiconttypegr_" width=_widthttypex_ border=0>}
+_icontabTypegreen_[v=1] {_texticontabTypegreen_}
+
+_icontabFormatgreen_ {<img src="_httpicontformgr_" width=_widthtformx_ border=0>}
+_icontabFormatgreen_[v=1] {_texticontabFormatgreen_}
+
+_icontabIdentifiergreen_ {<img src="_httpicontidentgr_" width=_widthtidentx_ border=0>}
+_icontabIdentifiergreen_[v=1] {_texticontabIdentifiergreen_}
+
+_icontabSourcegreen_ {<img src="_httpicontsrcgr_" width=_widthtsrcx_ border=0>}
+_icontabSourcegreen_[v=1] {_texticontabSourcegreen_}
+
+_icontabLanguagegreen_ {<img src="_httpicontlanggr_" width=_widthtlangx_ border=0>}
+_icontabLanguagegreen_[v=1] {_texticontabLanguagegreen_}
+
+_icontabRelationgreen_ {<img src="_httpicontrelgr_" width=_widthtrelx_ border=0>}
+_icontabRelationgreen_[v=1] {_texticontabRelationgreen_}
+
+_icontabCoveragegreen_ {<img src="_httpicontcovergr_" width=_widthtcoverx_ border=0>}
+_icontabCoveragegreen_[v=1] {_texticontabCoveragegreen_}
+
+_icontabRightsgreen_ {<img src="_httpicontrightgr_" width=_widthtrightx_ border=0>}
+_icontabRightsgreen_[v=1] {_texticontabRightsgreen_}
+
+
+
+_icontabListgreen_ {<img
+src="_httpicontlistgr_" width=_widthtlistx_ border=0>}
+_icontablistgreen_ [v=1] {_texticontablistgreen_}
+
+_icontabCollagegreen_ {<img 
+src="_httpicontcollgr_" width=_widthtcollx_ border=0>}
+_icontabCollagegreen_[v=1] {_texticontabCollagegreen_}
+
+_icontabSeriesgreen_ {<img 
+src="_httpicontsergr_" width=_widthtserx_ border=0>}
+_icontabSeriesgreen_[v=1] {_texticontabseriesgreen_}
+
+_icontabTogreen_ {<img 
+src="_httpiconttogr_" width=_widthttox_ border=0>}
+_icontabTogreen_[v=1] {_texticontabtogreen_}
+
+_icontabFromgreen_ {<img 
+src="_httpicontfromgr_" width=_widthtfromx_ border=0>}
+_icontabFromgreen_[v=1] {_texticontabfromgreen_}
+
+_icontabHowtogreen_ {<img 
+src="_httpiconthowgr_" width=_widththowx_ border=0>}
+_icontabHowtogreen_[v=1] {_texticontabhowgreen_}
+
+_icontabTopicgreen_ {<img 
+src="_httpiconttopicgr_" width=_widthttopicx_ border=0>}
+_icontabTopicgreen_[v=1] {_texticontabtopicgreen_}
+
+_icontabBrowsegreen_ {<img 
+src="_httpicontbrwsegr_" width=_widthtbrwsex_ border=0>}
+_icontabBrowsegreen_[v=1] {_texticontabbrwsegreen_}
+
+_icontabOrganizationgreen_ {<img 
+src="_httpicontorggr_" width=_widthtorgx_ border=0>}
+_icontabOrganizationgreen_[v=1] {_texticontaborggreen_}
+
+_icontabPeoplegreen_ {<img
+src="_httpicontpeopgr_" width=_widthtpeopx_ border=0>}
+_icontabPeoplegreen_[v=1] {_texticontabPeoplegreen_}
+
+_icontabAcronymgreen_ {<img
+src="_httpicontacrogr_" width=_widthtacrox_ border=0>}
+_icontabAcronymgreen_[v=1] {_texticontabAcronymgreen_}
+
+_icontabPhrasegreen_ {<img
+src="_httpicontphrsegr_" width=_widthtphrsex_ border=0>}
+_icontabPhrasegreen_[v=1] {_texticontabPhrasegreen_}
+
+_icontabArtistgreen_ {<img
+src="_httpicontartstgr_" width=_widthtartstx_ border=0>}
+_icontabArtistgreen_[v=1] {_texticontabArtistgreen_}
+
+_icontabKeywordgreen_ {<img 
+src="_httpicontkwgr_" width=_widthtkwx_ border=0>}
+_icontabKeywordgreen_[v=1] {_texticontabKeywordgreen_}
+
+_icontabVolumegreen_ {<img 
+src="_httpicontvolgr_" width=_widthtvolx_ border=0>}
+_icontabVolumegreen_[v=1] {_texticontabVolumegreen_}
+
+_icontabCaptionsgreen_ {<img
+src="_httpicontcaptgr_" width=_widthtcaptx_ border=0>}
+_icontabCaptionsgreen_[v=1] {_texticontabCaptionsgreen_}
+
+_icontabCountriesgreen_ {<img 
+src="_httpicontcountgr_" width=_widthtcountx_ border=0>}
+_icontabCountriesgreen_[v=1] {_texticontabCountriesgreen_}
+
+
+_iconblankbar_ {<center><img src="_httpicondivb_" width=_widthdivb_ height=_heightdivb_></center>}
+_iconblankbar_[v=1] {<br><hr><br>}
+
+_icontext_ {<img border=0 align=absmiddle src="_httpiconitext_" width=_widthitext_ height=_heightitext_ alt="_texticontext_" title="_texticontext_">}
+_icontext_[v=1] {_texticontext_}
+
+_iconworld_ {<img border=0 align=absmiddle src="_httpiconiworld_" width=_widthiworld_ height=_heightiworld_ alt="_texticonworld_" title="_texticonworld_">}
+_iconworld_[v=1] {_texticonworld_}
+
+_iconunknown_ {<img border=0 align=absmiddle src="_httpiconiunknown_" width=_widthiunknown_ height=_heightiunknown_ alt="_texticonunknown_" title="_texticonunknown_">}
+_iconunknown_[v=1] {_texticonunknown_}
+
+_iconblanktext_ {<img border=0 align=absmiddle src="_httpiconibtext_" width=_widthibtext_ height=_heightibtext_>}
+_iconblanktext_[v=1] {}
+
+_iconclosedbook_ {<img src="_httpiconbook_" width=_widthbook_ height=_heightbook_ border=0 alt="_texticonclosedbook_" title="_texticonclosedbook_">}
+_iconclosedbook_ [v=1] {<small><b>_texticonclosedbook_: </b></small>}
+_iconclosedbook_ [v=1,l=zh]{<small><_font_><b>_texticonclosedbook_: </b></font></small>}
+
+_icondoc_ {<img border=0 align=absmiddle src="_httpiconimsword_" width=_widthimsword_ height=_heightimsword_ alt="_texticonmsword_" title="_texticonmsword_">}
+_icondoc_[v=1] {_texticonmsword_}
+
+_iconmp3_ {<img border=0 align=absmiddle src="_httpiconimp3_" width=_widthimp3_ height=_heightimp3_ alt="_texticonmp3_" title="_texticonmp3_">}
+_iconmp3_[v=1] {_texticonmp3_}
+
+_iconmidi_ {<img border=0 align=absmiddle src="_httpiconimidi_" width=_widthimidi_ height=_heightimidi_ alt="_texticonmidi_" title="_texticonmidi_">}
+_iconmidi_[v=1] {_texticonmidi_}
+
+_iconpdf_ {<img border=0 align=absmiddle src="_httpiconipdf_" width=_widthipdf_ height=_heightipdf_ alt="_texticonpdf_" title="_texticonpdf_">}
+_iconpdf_[v=1] {_texticonpdf_}
+
+_iconps_ {<img border=0 align=absmiddle src="_httpiconips_" width=_widthips_ height=_heightips_ alt="_texticonps_" title="_texticonps_">}
+_iconps_[v=1] {_texticonps_}
+
+_iconppt_ {<img border=0 align=absmiddle src="_httpiconippt_" width=_widthippt_ height=_heightippt_ alt="_texticonppt_" title="_texticonppt_">}
+_iconppt_[v=1] {_texticonppt_}
+
+_iconrtf_ {<img border=0 align=absmiddle src="_httpiconirtf_" width=_widthirtf_ height=_heightirtf_ alt="_texticonrtf_" title="_texticonrtf_">}
+_iconrtf_[v=1] {_texticonrtf_}
+
+_iconxls_ {<img border=0 align=absmiddle src="_httpiconixls_" width=_widthixls_ height=_heightixls_ alt="_texticonxls_" title="_texticonxls_">}
+_iconxls_[v=1] {_texticonxls_}
+
+_iconnosearch_ {<img src="_httpimg_/nosearch.gif">}
+
+#######################################################################
+# Image links 
+#
+# These might include a link (not like an _icon_
+#######################################################################
+
+_imagehome_ {_If_("_cgiargu_" ne "1",_imagehome2_)}
+_imagehome2_ {_gsimage_(_httppagehome_,_httpiconchomeof_,_httpiconchomeon_,homer,_textimagehome_)}
+
+_imagehelp_ {_gsimage_(_httppagehelp_,_httpiconchelpof_,_httpiconchelpon_,help,_textimagehelp_)}
+
+_imagepref_ {_If_("_cgiargu_" ne "1",_imagepref2_)}
+_imagepref2_ {_gsimage_(_httppagepref_,_httpiconcprefof_,_httpiconcprefon_,pref,_textimagepref_)}
+
+_imageusab_ {_gsimage_(_httppageusab_,_httpiconcusabof_,_httpiconcusabon_,usab,_textimageusab_)}
+
+_imagegreenstone_ {<img src="_httpicongsdl_" width="_widthgsdl_" height="_heightgsdl_" border="0" alt="_textimagegreenstone_" title="_textimagegreenstone_" hspace=0>}
+
+_imagegreenstone_[v=1] {_textimagegreenstone_}
+
Index: /tags/gsdl-2_61-distribution/gsdl/macros/browse.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/browse.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/browse.dm	(revision 10506)
@@ -0,0 +1,115 @@
+# this file must be UTF-8 encoded
+
+package browse
+
+#######################################################################
+# headers
+# these are overridden so we can put an onLoad event handler
+# in the <body> tag of this page - for mgpp, form search pages
+#######################################################################
+
+#copied from prefs 
+
+_header_ {_cgihead_
+_htmlhead_(onLoad="ccont(0)")_startspacer__pagebanner_
+}
+
+
+_content_{
+	
+	
+
+	_optnavigationbar_
+	
+	_browseinterface_
+
+	_iconblankbar_
+
+	_classifications_
+	
+
+	<div id="mydiv"></div>
+	<div><layer id="mylayer"top=350 left=280 width="100%"></layer></div>	
+
+}
+
+
+_runtimebrowsescript_{}
+
+_browseinterface_{
+
+<form name=BrowseForm method=get action="_gwcgi_">
+
+<input type=hidden name="a" value="br">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+       <p>
+       _textfilterby_ _anyallselect_ _textwords_<br> 
+       _filterbox_<br>
+ 
+	<font size=-1><i>(_textleaveblank_)</i></font><p>	      	      
+       
+       _textsortby_ _browsebox1_, _textalsoshowing_ _browsebox2_ _textwith_ 
+       _docnum_ _textdocsperpage_
+       <span align = right> _browsebutton_ </span><p>
+</form>  
+
+}
+
+_browsebutton_{<input type=submit value=_browsebuttontext_ align=right>}
+
+_docnum_{
+<select name="bnu">
+	<option _If_("_cgiargbnu_" eq "5", selected)>5
+	<option _If_("_cgiargbnu_" eq "10", selected)>10
+	<option _If_("_cgiargbnu_" eq "20", selected)>20
+	<option _If_("_cgiargbnu_" eq "50", selected)>50
+	<option value="-1" _If_("_cgiargbnu_" eq "-1", selected)>max
+</select>
+}
+
+_filterbox_{<input type=text name="bft" value="_cgiargbft_" size=60>}
+
+
+_anyallselect_{
+<select name="bt">
+	<option value="0"_If_(_cgiargbt_,, selected)>_textany_
+	<option value="1"_If_(_cgiargbt_, selected)>_textall_
+</select>
+}
+
+_classifications_{
+}
+ 	
+_pagescriptextra_ {
+var tbl = new Array()
+
+function ccont(current)\{
+  if(document.getElementById) \{
+    document.getElementById("mydiv").innerHTML = tbl[current]; 
+   \}	
+  else if(document.all)\{
+    mydiv.innerHTML=tbl[current]
+  \}
+  else if(document.layers)\{
+    document.mylayer.document.write(tbl[current])
+    document.mylayer.document.close()
+   \}
+  
+\}      
+
+_runtimebrowsescript_
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/macros/bsummary.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/bsummary.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/bsummary.dm	(revision 10506)
@@ -0,0 +1,18 @@
+# this file must be UTF-8 encoded
+
+package bsummary
+
+_pagetitle_ {_collectionname_}
+
+_content_ {
+<center>
+_optnavigationbar_
+<h3>_textbsummary_</h3>
+</center>
+<p>_importlog_
+
+<center>
+<h3>_textflog_</h3>
+</center>
+<p>_faillog_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/catalan2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/catalan2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/catalan2.dm	(revision 10506)
@@ -0,0 +1,918 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Catalan Language text and icon macros 
+# -- this file contains text that is of less importance
+# -- to translate when creating a new interface language
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=ca] {documents. }
+_lastupdate_ [l=ca] {Ãltima actualitzaciÃ³}
+_ago_ [l=ca] {dies enrere.}
+_colnotbuilt_ [l=ca] {ColÂ·lecciÃ³ no construÃ¯da.}
+
+_textpagetitle_ [l=ca] {Biblioteca Digital Greenstone}
+_textadmin_ [l=ca] {PÃ gina d'administraciÃ³}
+_textabgs_ [l=ca] {Sobre Greenstone}
+_textgsdocs_ [l=ca] {DocumentaciÃ³ de Greenstone}
+
+_textimagegli_ [l=ca] {Us ajuda a crear noves colÂ·leccions, modificar elements de les existents o afegir-n'hi, i suprimir colÂ·leccions}
+
+_textimagecollector_ [l=ca] {Aquest programa de recopilaciÃ³ Ã©s anterior a la interfÃ­cie del bibliotecari, i per qÃŒestions prÃ ctiques Ã©s millor fer servir aquesta darrera}
+
+_textimagetranslator_ [l=ca] {Us ajuda a mantenir actualitzades les versions plurilingÃŒes de la interfÃ­cie de Greenstone}
+
+_textimageadmin_ [l=ca] {Us permet afegir nous usuaris, resumeix les colÂ·leccions presents en el sistema i ofereix informaciÃ³ tÃšcnica sobre la instalÂ·laciÃ³ de Greenstone}
+
+_textimagegogreenstone_ [l=ca] {Proporciona informaciÃ³ sobre el programari de Greenstone i el Projecte de Biblioteca Digital de Nova Zelanda, d'on va sorgir}
+
+_textimagegodocs_ [l=ca] {Manuals de Greenstone}
+
+_textpoem_ [l=ca] {<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+
+<p>que la pau i la calma t'envoltin,
+<br>que visquis en la calidesa de la calitja d'estiu,
+<br>que l'oceÃ  dels teus viatges sigui tan llis com la pedra verda polida.
+}
+
+_textgreenstone_ [l=ca] {<p>Greenstone (pedra verda) Ã©s una pedra semipreciosa que (com aquest programari) procedeix de Nova Zelanda. A la societat tradicional dels maoris, era la substÃ ncia mÃ©s preuada i cobejada de totes. Pot absorbir i conservar el <i>wairua</i>, que Ã©s un esperit o forÃ§a vital, i estÃ  dotada de virtuts tradicionals que la converteixen en un emblema escaient per a un projecte de biblioteca digital de domini pÃºblic. La seva brillantor representa la caritat; la seva transparÃšncia, l'honestedat; la seva duresa, el coratge; i el tall esmolat que pot adquirir, la justÃ­cia. La talla de pedra que apareix en el logotip de la Biblioteca Digital de Greenstone Ã©s un <i>patu</i>, una mena de porra de lluita, i una herÃšncia familiar d'un dels components del projecte. En un combat cos a cos, la seva escomesa era molt rÃ pida, precisa i completa. Hem volgut conferir aquestes mateixes qualitats al nostre programari, i que el tall esmolat del <i>patu</i> simbolitzi l'aspecte avanÃ§at i avantguardista de la tecnologia.  }
+
+_textaboutgreenstone_ [l=ca] {<p>Greenstone Ã©s un conjunt de programes informÃ tics per a la construcciÃ³ i difusiÃ³ de colÂ·leccions de biblioteca digital. Proporciona una nova forma d'organitzar la informaciÃ³ i de publicar-la a Internet o en cd-rom. Elaborat pel <b>Projecte de Biblioteca Digital de Nova Zelanda</b> a la <b>Universitat de Waikato</b>, es distribueix en colÂ·laboraciÃ³ amb la <b>UNESCO</b> i la <b>ONG Human Info </b>.  Ãs un programari de codi font obert que es pot obtenir a <a
+href="http://greenstone.org">http://greenstone.org</a> d'acord amb les condicions de la LlicÃšncia PÃºblica General GNU. 
+<p>L'objectiu del programari Ã©s que els usuaris, especialment en universitats, biblioteques i altres institucions de servei pÃºblic, puguin crear les seves prÃ²pies biblioteques digitals. Aquestes biblioteques estan transformant radicalment el mÃštode de distribuciÃ³ i adquisiciÃ³ de coneixements utilitzat per la UNESCO amb els seus interlocutors en els camps de l'educaciÃ³, la ciÃšncia i la cultura arreu del mÃ³n, i molt especialment als paÃ¯sos en vies de desenvolupament.  El nostre desig Ã©s que aquest programari estimuli l'Ãºs efectiu de les biblioteques digitals per compartir informaciÃ³ i posar-la a disposiciÃ³ del pÃºblic en general. 
+
+
+<p>Aquest programari s'elabora i es distribueix grÃ cies a una iniciativa de cooperaciÃ³ internacional acordada l'agost del 2000 entre tres institucions.
+
+<table border="0">
+<tr valign="top">
+<td>
+<a href="http://nzdl.org"><b>Projecte de Biblioteca Digital de Nova Zelanda a la Universitat de Waikato</b></a>
+<br>
+El programari de Greenstone ha sorgit d'aquest projecte i la iniciativa ha rebut el suport de la SubcomissiÃ³ de ComunicaciÃ³ de la ComissiÃ³ Nacional de Nova Zelanda per a la UNESCO com a part de la contribuciÃ³ de Nova Zelanda al programa de la UNESCO. 
+</td>
+<td></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://www.unesco.org"><b>OrganitzaciÃ³ de Nacions Unides per a l'EducaciÃ³, la CiÃšncia i la Cultura (UNESCO)</b></a>
+<br>
+La difusiÃ³ mundial d'informaciÃ³ en matÃšria d'educaciÃ³, ciÃšncia i cultura, especialment en els paÃ¯sos en vies de desenvolupament, Ã©s un dels objectius principals de la UNESCO, que la duu a terme mitjanÃ§ant el programa intergovernamental "InformaciÃ³ per a tothom". Amb aquest fi, es consideren eines importants la informaciÃ³ apropiada i de fÃ cil accÃ©s i la tecnologia de la comunicaciÃ³.
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/unesco.gif"
+border="0"></a></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://humaninfo.org"><b>L'ONG Human Info, amb seu a Anvers, BÃšlgica</b></a>
+<br>
+Aquest projecte, impulsat per organismes de l'ONU i altres ONG, gaudeix de prestigi mundial per la seva tasca de digitalitzar documentaciÃ³ d'interÃšs per al desenvolupament humÃ  i donar-hi difusiÃ³ pÃºblica, de manera gratuÃ¯ta per als paÃ¯sos en desenvolupament i a preu de cost per als paÃ¯sos desenvolupats.  </td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "seleccioneu una colÂ·lecciÃ³" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ [l=ca] {_httpimg_/ca/selcolgr.gif}
+_widthselcolgr_ [l=ca] {537}
+_heightselcolgr_ [l=ca] {17}
+_altselcolgr_ [l=ca] {"Select a collection"}
+
+
+## "La interfÃ­cie\ndel bibliotecari" ## home_page_button ## cgli ##
+_httpiconcgliof_ [l=ca] {_httpimg_/ca/cgliof.gif}
+_httpiconcglion_ [l=ca] {_httpimg_/ca/cglion.gif}
+_widthcgli_ [l=ca] {100}
+
+## "El colÂ·leccionista" ## home_page_button ## ccol ##
+_httpiconccolof_ [l=ca] {_httpimg_/ca/ccolof.gif}
+_httpiconccolon_ [l=ca] {_httpimg_/ca/ccolon.gif}
+_widthccol_ [l=ca] {100}
+
+## "El traductor" ## home_page_button ## ctrans ##
+_httpiconctransof_ [l=ca] {_httpimg_/ca/ctransof.gif}
+_httpiconctranson_ [l=ca] {_httpimg_/ca/ctranson.gif}
+_widthctrans_ [l=ca] {100}
+
+## "PÃ gina\nd'administraciÃ³" ## home_page_button ## cadmin ##
+_httpiconcadminof_ [l=ca] {_httpimg_/ca/cadminof.gif}
+_httpiconcadminon_ [l=ca] {_httpimg_/ca/cadminon.gif}
+_widthcadmin_ [l=ca] {100}
+
+## "Sobre\nGreenstone" ## home_page_button ## cabgs ##
+_httpiconcabgsof_ [l=ca] {_httpimg_/ca/cabgsof.gif}
+_httpiconcabgson_ [l=ca] {_httpimg_/ca/cabgson.gif}
+_widthcabgs_ [l=ca] {100}
+
+## "DocumentaciÃ³\nde Greenstone" ## home_page_button ## cgsdoc ##
+_httpiconcgsdocof_ [l=ca] {_httpimg_/ca/cgsdocof.gif}
+_httpiconcgsdocon_ [l=ca] {_httpimg_/ca/cgsdocon.gif}
+_widthcgsdoc_ [l=ca] {100}
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=ca] {Hi ha quatre botons mÃ©s a la pÃ gina principal}
+
+_textnocollections_ [l=ca] {<p>Actualment no hi ha cap colÂ·lecciÃ³ disponible en aquesta instalÂ·laciÃ³ de Greenstone.  
+Per afegir colÂ·leccions, podeu: 
+<ul><li>Utilitzar<a href="_httppagecollector_">el colÂ·leccionista</a> per construir noves colÂ·leccions
+    <li>Si teniu un cd-rom de Greenstone, podeu instalÂ·lar colÂ·leccions des del cd-rom 
+</ul>
+}
+
+_text1coll_ [l=ca] {Aquesta instalÂ·laciÃ³ de Greenstone contÃ© 1 colÂ·lecciÃ³}
+
+_textmorecolls_ [l=ca] {Aquesta instalÂ·laciÃ³ de Greenstone contÃ© _1_ colÂ·leccions}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=ca] {EnllaÃ§ extern}
+_textlinknotfound_ [l=ca] {No s'ha trobat l'enllaÃ§ intern}
+
+_textextlinkcontent_ [l=ca] {L'enllaÃ§ que heu seleccionat Ã©s extern a qualsevol de les vostres colÂ·leccions seleccionades actualment.
+    Si encara voleu visualitzar aquest enllaÃ§ i el vostre navegador tÃ© accÃ©s a la web, podeu <a href="_nexturl_">avanÃ§ar</a> fins a aquesta pÃ gina; en cas contrari, pitgeu el botÃ³ "retrocÃ©s" per tornar al document anterior. }
+
+_textlinknotfoundcontent_ [l=ca] {L'enllaÃ§ intern que heu seleccionat no existeix. AixÃ² es deu segurament a un error a la colÂ·lecciÃ³ font. Pitgeu el botÃ³ "retrocÃ©s" per tornar al document anterior. }
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=ca] {<h3>EnllaÃ§ amb la colÂ·lecciÃ³ "_2_" </h3>
+
+<p> L'enllaÃ§ que heu seleccionat Ã©s extern a la colÂ·lecciÃ³ "_collectionname_"
+    (connecta amb la colÂ·lecciÃ³ "_2_").
+    Si voleu visualitar aquest enllaÃ§ a la colÂ·lecciÃ³ "_2_" podeu  
+    <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">avanÃ§ar</a> fins a aquesta pÃ gina; 
+    en cas contrari, pitgeu el botÃ³ "retrocÃ©s" del vostre navegador per tornar al document anterior.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=ca] {Biblioteca Digital de Greenstone}
+
+_textusername_ [l=ca] {nom d'usuari}
+_textpassword_ [l=ca] {contrasenya}
+
+_textmustbelongtogroup_ [l=ca] {AvÃ­s: heu de pertÃ nyer al grup "_cgiargug_" per entrar a aquesta pÃ gina}
+
+_textmessageinvalid_ [l=ca] {La pÃ gina que heu demanat exigeix que us identifiqueu.<br>
+_If_(_cgiargug_,[_textmustbelongtogroup_]<br>)
+IntroduÃ¯u el nom d'usuari i la contrasenya de Greenstone.}
+
+_textmessagefailed_ [l=ca] {Hi ha un error en el nom d'usuari o la contrasenya.}
+
+_textmessagedisabled_ [l=ca] {Disculpeu, el vostre compte ha estat inhabilitat. Poseu-vos en contacte amb l'administrador d'aquest lloc web.}
+
+_textmessagepermissiondenied_ [l=ca] {Disculpeu, perÃ² no teniu permÃ­s per entrar a aquesta pÃ gina.}
+
+_textmessagestalekey_ [l=ca] {L'enllaÃ§ que heu seguit ja no Ã©s vÃ lid. IntroduÃ¯u la contrasenya per entrar a aquesta pÃ gina. }
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=ca] {<p>Aquesta instalÂ·laciÃ³ de Greenstone no contÃ© cap tipus de documentaciÃ³. AixÃ² pot ser perquÃš: 
+<ol>
+ <li>Greenstone es va instalÂ·lar a partir d'un cd-rom en versiÃ³ compacta.
+ <li>Greenstone es va instalÂ·lar a partir d'una distribuciÃ³ baixada d'Internet.
+</ol>
+En qualsevol cas, podeu obtenir la documentaciÃ³ al directori <i>docs</i>
+d'un cd-rom de Greenstone o a la web <a
+href="http://www.greenstone.org">http://www.greenstone.org</a>.
+}
+
+_textuserguide_ [l=ca] {Guia de l'usuari}
+_textinstallerguide_ [l=ca] {Guia de l'instalÂ·lador}
+_textdeveloperguide_ [l=ca] {Guia del programador}
+_textpaperguide_ [l=ca] {Del paper a la colÂ·lecciÃ³ }
+_textorganizerguide_ [l=ca] {Ãs de l'organitzador}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "documentaciÃ³ de Greenstone" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=ca] {_httpimg_/ca/gsdocsgr.gif}
+_widthgsdocsgr_ [l=ca] {_pagewidth_}
+_heightgsdocsgr_ [l=ca] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ [l=ca] {estructura per defecte}
+_textmore_ [l=ca] {mÃ©s}
+_textcollector_ [l=ca] {El colÂ·leccionista}
+_textinfo_ [l=ca] {Dades de la colÂ·lecciÃ³}
+_textsrce_ [l=ca] {Dades font}
+_textconf_ [l=ca] {Configura la colÂ·lecciÃ³}
+_textbild_ [l=ca] {ConstrucciÃ³}
+_textview_ [l=ca] {visualitza}
+_textdel_ [l=ca] {suprimeix la colÂ·lecciÃ³}
+_textexpt_ [l=ca] {exporta la colÂ·lecciÃ³}
+
+_textdownloadingfiles_ [l=ca] {EstÃ  baixant fitxers...}
+_textimportingcollection_ [l=ca] {EstÃ  important la colÂ·lecciÃ³...}
+_textbuildingcollection_ [l=ca] {EstÃ  construint la colÂ·lecciÃ³... }
+_textcreatingcollection_ [l=ca] {estÃ  creant la colÂ·lecciÃ³...}
+
+_textcollectorblurb_ [l=ca] {<i>La ploma tÃ© mÃ©s forÃ§a que l'espasa!
+<br>Construir i distribuir colÂ·leccions d'informaciÃ³ implica responsabilitats que cal plantejar-se detingudament abans de comenÃ§ar. Hi ha qÃŒestions legals de drets d'autor: tenir accÃ©s a documents no significa necessÃ riament que els pugueu posar a disposiciÃ³ de terceres persones. 
+Hi ha qÃŒestions socials: les colÂ·leccions han de respectar els costums de la societat de la qual provenen els documents.
+I hi ha qÃŒestions Ãštiques: hi ha coses que simplement no es poden posar a disposiciÃ³ de terceres persones. 
+<br>Tingueu molt en compte el poder de la informaciÃ³ i feu-la servir amb prudÃšncia.
+</i>
+}
+
+_textcb1_ [l=ca] {El "colÂ·leccionista" us ajuda a crear noves colÂ·leccions, modificar les que ja existeixen o afegir-hi elements i suprimir colÂ·leccions. Per dur a terme aquestes tasques, us guiarÃ  per una seqÃŒÃšncia de pÃ gines web que us demanaran la informaciÃ³ necessÃ ria. }
+
+_textcb2_ [l=ca] {Primer heu de decidir si}
+_textcnc_ [l=ca] {crea una nova colÂ·lecciÃ³}
+_textwec_ [l=ca] {treballar amb una d'existent, afegint-hi dades o suprimint-la. }
+
+_textcb3_ [l=ca] {Per construir o modificar colÂ·leccions de la biblioteca digital, us heu d'identificar. AixÃ² Ã©s per protegir-vos d'altres persones que vulguin entrar al vostre ordinador i alterar-ne la informaciÃ³. Nota: per raons de seguretat, us haureu d'identificar cada 30 minuts. Quan passi aixÃ², no us preocupeu!  Una vegada identificats, podreu continuar allÃ  on ho havÃ­eu deixat. }
+
+_textcb4_ [l=ca] {IntroduÃ¯u els vostre nom d'usuari i la contrasenya de Greenstone i pitgeu el botÃ³ per entrar.}
+
+_textfsc_ [l=ca] {En primer lloc, seleccioneu la colÂ·lecciÃ³ amb quÃš voleu treballar (les colÂ·leccions protegides contra escriptura no apareixeran en aquesta llista). }
+
+_textwtc_ [l=ca] {Amb la colÂ·lecciÃ³ que heu seleccionat, podeu}
+_textamd_ [l=ca] {Afegeix mÃ©s dades i torna a construir la colÂ·lecciÃ³}
+_textetc_ [l=ca] {Modificar el fitxer de configuraciÃ³ de la colÂ·lecciÃ³ i tornar-la a construir }
+_textdtc_ [l=ca] {Suprimeix tota la colÂ·lecciÃ³}
+_textetcfcd_ [l=ca] {Exportar la colÂ·lecciÃ³ per gravar-la en un cd-rom que s'instalÂ·li automÃ ticament a Windows}
+_textcaec_ [l=ca] {Canviar una colÂ·lecciÃ³ existent}
+_textnwec_ [l=ca] {No hi ha disponible per a modificaciÃ³ cap colÂ·lecciÃ³ que permeti l'escriptura }
+_textcianc_ [l=ca] {Crear una nova colÂ·lecciÃ³}
+_texttsosn_ [l=ca] {La seqÃŒÃšncia de passos necessaris per crear una nova colÂ·lecciÃ³ a la biblioteca digital Ã©s:}
+_textsin_ [l=ca] {N'especifica el nom (i dades associades)}
+_textswts_ [l=ca] {Especifica d'on procedeixen les dades font}
+_textatco_ [l=ca] {Ajusta les opcions de configuraciÃ³ (nomÃ©s per a usuaris avanÃ§ats)}
+_textbtc_ [l=ca] {"Construir" la colÂ·lecciÃ³ (vegeu mÃ©s avall)}
+_textpvyh_ [l=ca] {Admireu la vostra obra!}
+
+_texttfsiw_ [l=ca] {El quart pas Ã©s quan l'ordinador fa tota la feina. Durant el procÃ©s de "construcciÃ³", l'ordinador crea tots els Ã­ndexs i recopila tota la informaciÃ³ necessÃ ria perquÃš el sistema funcioni. PerÃ² primer cal que especifiqueu la informaciÃ³. }
+
+_textadab_ [l=ca] {A sota apareix un diagrama que us ajudarÃ  a saber on us trobeu. Pitgeu el botÃ³ verd per continuar avanÃ§ant per la seqÃŒÃšncia. Quan avanceu, els botons es tornaran de color groc. Podeu tornar a la pÃ gina anterior pitjant el botÃ³ groc corresponent al diagrama. }
+
+_textwyar_ [l=ca] {Quan estigueu a punt, pitgeu el botÃ³ verd "informaciÃ³ de la colÂ·lecciÃ³" per comenÃ§ar a crear la nova colÂ·lecciÃ³ de la biblioteca digital. }
+
+_textcnmbs_ [l=ca] {Cal especificar el nom de la colÂ·lecciÃ³}
+_texteambs_ [l=ca] {Cal especificar l'adreÃ§a de correu electrÃ²nic}
+_textpsea_ [l=ca] {Comproveu que l'adreÃ§a de correu electrÃ²nic correspongui al format usuari@domini}
+_textdocmbs_ [l=ca] {Cal especificar la descripciÃ³ de la colÂ·lecciÃ³}
+
+_textwcanc_ [l=ca] {En crear una nova colÂ·lecciÃ³ caldrÃ  incorporar algunes informacions preliminars sobre les dades font. Aquest procÃ©s estÃ  estructurat en forma d'una sÃšrie de pÃ gines web, supervisades pel colÂ·leccionista. La barra al peu de la pÃ gina us mostra la seqÃŒÃšncia de pÃ gines que s'han d'emplenar.}
+
+_texttfc_ [l=ca] {TÃ­tol de la colÂ·lecciÃ³:}
+
+_texttctiasp_ [l=ca] {El tÃ­tol de la colÂ·lecciÃ³ Ã©s una frase curta que servirÃ  per identificar el contingut de la colÂ·lecciÃ³ en tota la biblioteca digital. Per exemple, "Informes tÃšcnics d'informÃ tica" o "Biblioteca per al desenvolupament de la humanitat".}
+
+_textcea_ [l=ca] {AdreÃ§a electrÃ²nica de contacte:}
+
+_textteas_ [l=ca] {Aquesta adreÃ§a de correu electrÃ²nic constitueix el primer punt de contacte per a la colÂ·lecciÃ³. Si el programari de Greenstone detecta un problema, envia un informe diagnÃ²stic a aquesta adreÃ§a. Escriviu una adreÃ§a de correu electrÃ²nic en la seva forma completa: <tt>nom@domini</tt>.}
+
+_textatc_ [l=ca] {Sobre aquesta colÂ·lecciÃ³:}
+
+_texttiasd_ [l=ca] {AixÃ² Ã©s un enunciat que descriu els principis que regeixen els elements que formen part d'aquesta colÂ·lecciÃ³. ApareixerÃ  a la pimera pÃ gina de presentaciÃ³ de la colÂ·lecciÃ³.   }
+
+_textypits_ [l=ca] {La vostra posiciÃ³ a la seqÃŒÃšncia s'indica amb una fletxa per sota--en aquest cas, la fase d'"informaciÃ³ de la colÂ·lecciÃ³". Per continuar, pitgeu el botÃ³ verd "dades font". }
+
+_srcebadsources_ [l=ca] {<p>Un o mÃ©s dels fitxers font que heu especificat no estÃ  disponible (marcats _iconcross_ a sota).
+
+<p>AixÃ² pot ser perquÃš <ul>
+<li>El fitxer, el lloc FTP o l'URL no existeixen.
+<li>Primer us heu de connectar a Internet.
+<li>Esteu intentant accedir a un URL protegit per un tallafoc (aixÃ² passa si normalment heu de donar un nom d'usuari i una contrasenya per accedir a Internet).
+</ul>
+
+<p>Si aquest Ã©s un URL que podeu veure en el vostre navegador, el problema podria venir d'una cÃ²pia que es trobi a la memÃ²ria cau local. Malauradament, aquestes cÃ²pies sÃ³n invisibles per al procÃ©s de rÃšplica de Greenstone. En aquest cas, us recomanem que baixeu les pÃ gines des del vostre navegador. 
+}
+
+_textymbyco_ [l=ca] {<p>Podeu basar la colÂ·lecciÃ³ en:
+<ul>
+<li>L'estructura per defecte 
+<dl><dd>La nova colÂ·lecciÃ³ pot contenir documents html (.htm, .html), documents de text (.txt, .text), documents de MS Word (.doc), documents PDF (.pdf) o documents
+de correu electrÃ²nic amb el format "m-box" (.mbx).</dd></dl>
+<li>Una colÂ·lecciÃ³ existent
+<dl><dd>Els fitxers de la nova colÂ·lecciÃ³ han de ser exactament del mateix tipus que els que es varen utilitzar per construir la colÂ·lecciÃ³ existent.</dd></dl>
+</ul>
+}
+
+_textbtco_ [l=ca] {Basa la colÂ·lecciÃ³ en}
+_textand_ [l=ca] {Afegeix noves dades}
+_textad_ [l=ca] {Afegir dades:}
+
+_texttftysb_ [l=ca] {Els fitxers que especifiqueu a sota s'afegiran a la colÂ·lecciÃ³. Comproveu que no torneu a especificar fitxers que ja es troben a la colÂ·lecciÃ³, perquÃš, si no, se'n faran dues cÃ²pies. Els fitxers s'identifiquen pel nom complet i el directori on estan guardats; les pÃ gines web, per la seva adreÃ§a web absoluta. }
+
+_textis_ [l=ca] {Fonts de dades:}
+
+_textddd1_ [l=ca] {<p>Si utilitzeu file:// o ftp:// per especificar un fitxer, aquest baixarÃ . 
+
+<p>Si utilitzeu http:// el resultat dependrÃ  del fet que l'URL us mostri una pÃ gina web normal al vostre navegador o una llista de fitxers. Si us mostra una pÃ gina, aquesta baixarÃ  juntament amb  totes les pÃ gines amb quÃš estigui vinculada mitjanÃ§ant enllaÃ§os, sempre que es trobin en el mateix lloc web, a l'URL inicial.
+
+<p>Si utilitzeu file:// o ftp:// per especificar una carpeta o un directori, o introduÃ¯u un 
+http:// URL que dugui a una llista de fitxers, tot el que contingui la carpeta i totes les subcarpetes s'inclouran a la colÂ·lecciÃ³. 
+
+<p>Pitgeu el botÃ³ "mÃ©s fonts" per obtenir mÃ©s quadres d'introducciÃ³.
+}
+
+_textddd2_ [l=ca] {<p>Pitgeu un dels botons verds. Si sou un usuari avanÃ§at, potser voldreu ajustar la configuraciÃ³ de la colÂ·lecciÃ³.  Una altra possibilitat Ã©s anar directament a la fase de construcciÃ³. Recordeu que sempre podeu tornar a una fase anterior del procÃ©s pitjant el botÃ³ groc corresponent. 
+}
+
+_textconf1_ [l=ca] {<p>La construcciÃ³ i la presentaciÃ³ de la vostra colÂ·lecciÃ³ estan controlades per les especificacions contingudes en un "fitxer de configuraciÃ³" especial. Els usuaris avanÃ§ats que ho desitgin, poden modificar els parÃ metres de configuraciÃ³. 
+
+<center><p><b>Si no sou un usuari avanÃ§at, aneu al final de la pÃ gina.</b></center> 
+
+<p>Per modificar els parÃ metres de configuraciÃ³, canvieu les dades que apareixen a sota. Si cometeu un error, pitgeu "Restaurar" per restablir els parÃ metres originals de la configuraciÃ³.
+}
+
+_textreset_ [l=ca] {Restaura}
+
+_textbild1_ [l=ca] {S'estÃ  construint la colÂ·lecciÃ³. AixÃ² pot durar una estona. La lÃ­nia d'estat que apareix mÃ©s avall indica com progressa l'operaciÃ³.  }
+
+_textbild2_ [l=ca] {Per aturar el procÃ©s de construcciÃ³ en qualsevol moment, pitgeu aquÃ­. 
+<br>La colÂ·lecciÃ³ amb quÃš esteu treballant restarÃ  intacta.
+}
+
+_textstopbuild_ [l=ca] {interromp la construcciÃ³}
+
+_textbild3_ [l=ca] {Si sortiu d'aquesta pÃ gina (i no heu cancelÂ·lat el procÃ©s de construcciÃ³ amb el botÃ³ "interromp la construcciÃ³"), es continuarÃ  construint la colÂ·lecciÃ³ i s'instalÂ·larÃ  un cop completat el procÃ©s.}
+
+_textbuildcancelled_ [l=ca] {ConstrucciÃ³ cancelÂ·lada}
+
+_textbildcancel1_ [l=ca] {S'ha cancelÂ·lat el procÃ©s de construcciÃ³ de la colÂ·lecciÃ³. Amb els botons grocs que apareixen a sota podeu modificar la colÂ·lecciÃ³ o tornar a iniciar el procÃ©s de construcciÃ³. }
+
+_textbsupdate1_ [l=ca] {ActualitzaciÃ³ d'estat de construcciÃ³ d'aquÃ­ a 1 segon}
+_textbsupdate2_ [l=ca] {ActualitzaciÃ³ d'estat de construcciÃ³ d'aquÃ­ a }
+_textseconds_ [l=ca] {segons}
+_textbildsuc_ [l=ca] {La colÂ·lecciÃ³ s'ha construÃ¯t satisfactÃ²riament. }
+
+_textviewbildsummary_ [l=ca] {Per a mÃ©s informaciÃ³, podeu<a href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>visualitzar el resum de construcciÃ³</a> d'aquesta colÂ·lecciÃ³. }
+
+_textfailmsg11_ [l=ca] {La colÂ·lecciÃ³ no s'ha pogut construir perquÃš no contÃ© cap dada. Comproveu que existeixi almenys un dels directoris o fitxers que heu especificat a la pÃ gina <i>dades font</i> i que sigui d'un tipus o  (si es tracta d'un directori) que contingui fitxers d'un tipus que Greenstone pugui processar.
+}
+
+_textfailmsg21_ [l=ca] {No s'ha pogut construir la colÂ·lecciÃ³ (import.pl ha fallat). }
+_textblcont_ [l=ca] {El registre de construcciÃ³ contÃ© la informaciÃ³ segÃŒent:}
+
+_texttryagain_ [l=ca] {Per favor, <a href="_httppagecollector_" target=_top>torneu a fer arrencar el colÂ·leccionista</a>
+i  intenteu-ho de nou. 
+}
+
+_textfailmsg31_ [l=ca] {No s'ha pogut construir la colÂ·lecciÃ³ (buildcol.pl ha fallat).}
+_textfailmsg41_ [l=ca] {La colÂ·lecciÃ³ s'ha construÃ¯t satisfactÃ²riament perÃ² no s'ha pogut instalÂ·lar. }
+_textfailmsg71_ [l=ca] {S'ha produÃ¯t un error inesperat quan s'intentava construir la colÂ·lecciÃ³  }
+_textretcoll_ [l=ca] {Torna al colÂ·leccionista}
+
+_textdelperm_ [l=ca] {No s'ha pogut suprimir tota o una part de la colÂ·lecciÃ³ _cgiargbc1dirname_ . AixÃ² pot ser perquÃš:
+<ul>
+<li> Greenstone no tÃ© permÃ­s per suprimir el directori _gsdlhome_/collect/_cgiargbc1dirname_.<br>
+Potser haureu d'eliminar aquest directori manualment per completar la supressiÃ³ de la colÂ·lecciÃ³ _cgiargbc1dirname_ d'aquest ordinador.</li>
+<li>Greenstone no pot executar el programa _gsdlhome_/bin/script/delcol.pl. Comproveu que aquest fitxer es pugui llegir i executar.</li>
+</ul>
+}
+
+_textdelinv_ [l=ca] {La colÂ·lecciÃ³  _cgiargbc1dirname_ estÃ  protegida o no Ã©s vÃ lida. S'ha cancelÂ·lat la supressiÃ³. 
+}
+
+_textdelsuc_ [l=ca] {La colÂ·lecciÃ³  _cgiargbc1dirname_ s'ha suprimit satisfactÃ²riament.}
+
+_textclonefail_ [l=ca] {La colÂ·lecciÃ³  _cgiargclonecol_ no s'ha pogut clonar. AixÃ² pot ser perquÃš: 
+<ul>
+<li> La colÂ·lecciÃ³ _cgiargclonecol_ no existeix
+<li> La colÂ·lecciÃ³  _cgiargclonecol_ no tÃ© el fitxer de configuraciÃ³ collect.cfg 
+<li> Greenstone no tÃ© permÃ­s per llegir el fitxer de configuraciÃ³ collect.cfg 
+</ul>
+}
+
+_textcolerr_ [l=ca] {Error en el colÂ·leccionista.}
+
+_texttmpfail_ [l=ca] {El colÂ·leccionista no ha pogut realitzar cap operaciÃ³ de lectura o escriptura en el fitxer o directori temporal. AixÃ² pot ser perquÃš: <ul>
+<li> Greenstone no tÃ© accÃ©s de lectura/escriptura al directori _gsdlhome_/tmp.
+   </ul>}
+
+_textmkcolfail_ [l=ca] {El colÂ·leccionista no ha pogut crear l'estructura de directori que requereix la nova colÂ·lecciÃ³ (mkcol.pl ha fallat). AixÃ² pot ser perquÃš:
+<ul>
+<li> Greenstone no tÃ© permÃ­s per escriure al directori _gsdlhome_/tmp.
+<li> Hi ha errors en el guiÃ³ Perl mkcol.pl.
+</ul>
+}
+
+_textnocontent_ [l=ca] {Error en el colÂ·leccionista: no s'ha donat nom a la nova colÂ·lecciÃ³. Proveu de tornar a fer arrencar el colÂ·leccionista des del principi. }
+
+_textrestart_ [l=ca] {Torna a fer arrencar el colÂ·leccionista}
+
+_textreloaderror_ [l=ca] {S'ha produÃ¯t un error durant la creaciÃ³ de la nova colÂ·lecciÃ³. Podria ser que Greenstone s'haguÃ©s confÃ³s pel vostre Ãºs dels botons "tornar a carregar" o "retrocÃ©s" del vostre navegador (procureu no fer servir aquests botons durant la creaciÃ³ d'una colÂ·lecciÃ³ amb el colÂ·leccionista). Ãs recomanable tornar a fer arrencar el colÂ·leccionista des del principi. }
+
+_textexptsuc_ [l=ca] {La colÂ·lecciÃ³  _cgiargbc1dirname_ s'ha exportat satisfactÃ²riament al directori _gsdlhome_/tmp/exported\__cgiargbc1dirname_. }
+
+_textexptfail_ [l=ca] {<p>No s'ha pogut exportar la colÂ·lecciÃ³ _cgiargbc1dirname_ .
+
+<p>Ãs probable que sigui perquÃš Greenstone es va instalÂ·lar sense els components necessaris per a la funciÃ³ "Exportar colÂ·lecciÃ³".  
+<ul>
+
+ <li>Si vÃ reu instalÂ·lar Greenstone des d'un cd-rom, aquests components no s'hauran instalÂ·lat llevat que els haguÃ©ssiu seleccionat durant una instalÂ·laciÃ³ "personalitzada". Els podeu afegir a la instalÂ·laciÃ³ tornant a executar el procediment d'instalÂ·laciÃ³.
+
+ <li>Si vÃ reu instalÂ·lar Greenstone des d'una distribuciÃ³ a Internet, haureu de baixar i instalÂ·lar un paquet addicional per poder habilitar aquesta funciÃ³. Podeu obtenir mÃ©s informaciÃ³ a <a href="http://www.greenstone.org">http://www.greenstone.org</a> o enviant un correu a <a  href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>.
+
+</ul>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "El colÂ·leccionista" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=ca] {_httpimg_/ca/h\_colect.gif}
+
+## "informaciÃ³ de\nla colÂ·lecciÃ³" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=ca] {_httpimg_/ca/gcinfoof.gif}
+_httpicongcinfoon_ [l=ca] {_httpimg_/ca/gcinfoon.gif}
+_httpiconycinfoof_ [l=ca] {_httpimg_/ca/ycinfoof.gif}
+_httpiconycinfoon_ [l=ca] {_httpimg_/ca/ycinfoon.gif}
+_httpiconncinfoof_ [l=ca] {_httpimg_/ca/ncinfoof.gif}
+
+## "dades font" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=ca] {_httpimg_/ca/gcsrceof.gif}
+_httpicongcsrceon_ [l=ca] {_httpimg_/ca/gcsrceon.gif}
+_httpiconycsrceof_ [l=ca] {_httpimg_/ca/ycsrceof.gif}
+_httpiconycsrceon_ [l=ca] {_httpimg_/ca/ycsrceon.gif}
+_httpiconncsrceof_ [l=ca] {_httpimg_/ca/ncsrceof.gif}
+
+## "configura\nla colÂ·lecciÃ³" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=ca] {_httpimg_/ca/gcconfof.gif}
+_httpicongcconfon_ [l=ca] {_httpimg_/ca/gcconfon.gif}
+_httpiconycconfof_ [l=ca] {_httpimg_/ca/ycconfof.gif}
+_httpiconycconfon_ [l=ca] {_httpimg_/ca/ycconfon.gif}
+_httpiconncconfof_ [l=ca] {_httpimg_/ca/ncconfof.gif}
+
+## "construeix\nla colÂ·lecciÃ³" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=ca] {_httpimg_/ca/gcbildof.gif}
+_httpicongcbildon_ [l=ca] {_httpimg_/ca/gcbildon.gif}
+_httpiconycbildof_ [l=ca] {_httpimg_/ca/ycbildof.gif}
+_httpiconycbildon_ [l=ca] {_httpimg_/ca/ycbildon.gif}
+_httpiconncbildof_ [l=ca] {_httpimg_/ca/ncbildof.gif}
+
+## "visualitza\nla colÂ·lecciÃ³" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=ca] {_httpimg_/ca/gcviewof.gif}
+_httpicongcviewon_ [l=ca] {_httpimg_/ca/gcviewon.gif}
+_httpiconycviewof_ [l=ca] {_httpimg_/ca/ycviewof.gif}
+_httpiconycviewon_ [l=ca] {_httpimg_/ca/ycviewon.gif}
+_httpiconncviewof_ [l=ca] {_httpimg_/ca/ncviewof.gif}
+
+## "suprimeix\nla colÂ·lecciÃ³" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=ca] {_httpimg_/ca/gcdelof.gif}
+_httpicongcdelon_ [l=ca] {_httpimg_/ca/gcdelon.gif}
+
+## "exporta\nla colÂ·lecciÃ³" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=ca] {_httpimg_/ca/gcexptof.gif}
+_httpicongcexpton_ [l=ca] {_httpimg_/ca/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=ca] {Greenstone Ã©s un conjunt de programes informÃ tics que serveix per accedir a les colÂ·leccions de biblioteques digitals i per crear noves colÂ·leccions. Ofereix una nova manera d'organitzar la informaciÃ³ i de publicar-la a Internet o en cd-rom. Creat pel Projecte de Biblioteca Digital de Nova Zelanda a la Universitat de Waikato, aquest programari es distribueix en colÂ·laboraciÃ³ amb la UNESCO i l'ONG Human Info. Ãs un programari de codi font obert i es pot obtenir a <i>http://greenstone.org</i> d'acord amb les condicions de la LlicÃšncia PÃºblica General GNU. }
+
+_textgreenstone2_ [l=ca] {El lloc web de la Biblioteca Digital de Nova Zelanda (<a
+href="http://nzdl.org">http://nzdl.org</a>) contÃ© nombrosos exemples de colÂ·leccions creades amb el programari de Greenstone i que es poden consultar lliurement. Ofereixen exemples de diverses opcions de cerca i navegaciÃ³ i inclouen colÂ·leccions en Ã rab, xinÃšs, francÃšs, maori i castellÃ , a mÃ©s d'anglÃšs. TambÃ© hi ha algunes colÂ·leccions de mÃºsica.  }
+
+_textplatformtitle_ [l=ca] {plataforma}
+_textgreenstone3_ [l=ca] {Greenstone funciona amb Windows, Unix i Mac OS X. La distribuciÃ³ inclou binaris a punt d'utilitzar per a totes les versions de Windows, Linux i Mac OS X. TambÃ© contÃ© un codi font complet per al sistema, que es pot compilar amb Microsoft C++ o gcc.  Greenstone funciona amb un programari associat que tambÃ© es pot obtenir de forma gratuÃ¯ta: el servidor web Apache i el PERL. La interfÃ­cie d'usuari utilitza un navegador web com ara Netscape Navigator o Internet Explorer.
+}
+
+_textgreenstone4_ [l=ca] {Moltes colÂ·leccions de documents es distribueixen en cd-rom amb el programari de Greenstone. Per exemple, la <i>Biblioteca per al desenvolupament de la humanitat</i> contÃ© 1.230 publicacions que tracten temes tan diversos com la comptabilitat o la depuraciÃ³ d'aigÃŒes. S'hi pot accedir des d'ordinadors molt senzills, com els que se solen trobar als paÃ¯sos en vies de desenvolupament. La informaciÃ³ es pot trobar mitjanÃ§ant cerques o consultes per tema, tÃ­tols, organitzacions, llistes Com o per visualitzaciÃ³ aleatÃ²ria de portades de llibres. }
+
+_textcustomisationtitle_ [l=ca] {personalitzaciÃ³}
+_textgreenstone5_ [l=ca] {Greenstone estÃ  especialment dissenyat perquÃš es pugui personalitzar i ampliar a voluntat. Greenstone pot tractar nous formats de documents i metadades escrivint "connectors" (<i>plugins</i>), en
+llenguatge Perl. TambÃ© es poden aplicar noves estructures de navegaciÃ³ en les metadades escrivint "classificadors". La interfÃ­cie d'usuari i la presentaciÃ³ es poden modificar utilitzant les "macros" escrites en un senzill llenguatge de macros. El protocol Corba permet que els agents (per exemple en llenguatge Java) utilitzin totes les funcions disponibles a les colÂ·leccions de documents. Finalment, es pot modificar el codi font en C++ i Perl.
+}
+
+_textdocumentationtitle_ [l=ca] {documentaciÃ³}
+_textdocuments_ [l=ca] {EstÃ  disponible la documentaciÃ³ completa del programari de Greenstone.}
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+_textmailinglisttitle_ [l=ca] {llista de correu electrÃ²nic}
+_textmailinglist_ [l=ca] {Exsteix una llista de correu electrÃ²nic pensada especialment per al debat sobre el programari de la biblioteca digital de Greenstone. Ãs recomanable i desitjable que els usuaris actius de Greenstone participin en aquest debat. Us hi podeu inscriure a  <a href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.
+
+Per enviar un missatge a la llista, adreceu-lo a <a
+href="mailto:greenstone-users@list.scms.waikato.ac.nz"
+>greenstone-users@list.scms.waikato.ac.nz</a>.
+}
+
+_textbugstitle_ [l=ca] {errors lÃ²gics o de programaciÃ³}
+_textreport_ [l=ca] {El nostre desig Ã©s que aquest programari funcioni correctament. Per aixÃ² us preguem que ens informeu de qualsevol problema que hi detecteu a <a href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+}
+
+_textgs3title_ [l=ca] {en fase d'elaboraciÃ³}
+# -- Missing translation: _textgs3_
+
+_textcreditstitle_ [l=ca] {crÃšdits}
+
+_textwhoswho_ [l=ca] {El programari de Greenstone Ã©s el fruit de la colÂ·laboraciÃ³ de moltes persones. Rodger McNab i Stefan Boddie en sÃ³n els principals arquitectes i programadors. TambÃ© hi han fet aportacions David Bainbridge, George Buchanan, Hong Chen, Michael Dewsnip, Katherine Don, Elke Duncker, Carl Gutwin, Geoff Holmes, Dana McKay, John McPherson, Craig Nevill-Manning, Dynal Patel, Gordon Paynter, Bernhard Pfahringer, Todd Reed, Bill Rogers, John Thompson i Stuart Yeates. Altres membres del Projecte de Biblioteca Digital de Nova Zelanda han aportat valuoses idees i suggeriments al disseny del sistema: Mark Apperley, Sally Jo Cunningham, Matt Jones, Steve Jones, Te Taka
+Keegan, Michel Loots, Malika Mahoui, Gary Marsden, Dave Nichols i Lloyd Smith. TambÃ© volem donar les grÃ cies a tots aquells que han contribuÃ¯t als paquets amb llicÃšncia de GNU que s'inclouen en aquesta dstribuciÃ³: MG, GDBM, PDFTOHTML, PERL, WGET, WVWARE i XLHTML.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "sobre el programari de Greenstone" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=ca] {_httpimg_/ca/abgsgr.gif}
+_widthabgsgr_ [l=ca] {_pagewidth_}
+_heightabgsgr_ [l=ca] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=ca] {Llista d'usuaris actuals}
+_textuser_ [l=ca] {usuari
+}
+_textas_ [l=ca] {estat del compte}
+_textgroups_ [l=ca] {grups}
+_textcomment_ [l=ca] {comentari}
+_textadduser_ [l=ca] {afegeix un nou usuari}
+_textedituser_ [l=ca] {edita}
+_textdeleteuser_ [l=ca] {suprimeix}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=ca] {Edita informaciÃ³ d'usuari}
+_textadduser_ [l=ca] {Afegeix un nou usuari}
+
+_textaboutusername_ [l=ca] {Els noms d'usuari han de ser d'entre 2 i 30 carÃ cters. Poden contenir carÃ cters alfanumÃšrics,  '.' i '_'.}
+
+_textaboutpassword_ [l=ca] {Les contrasenyes han de ser d'entre 3 i 8 carÃ cters. Poden contenir tots els carÃ cters normals d'ASCII que es poden imprimir. }
+
+_textoldpass_ [l=ca] {Si aquest camp estÃ  en blanc, es conservarÃ  l'antiga contrasenya. }
+_textenabled_ [l=ca] {habilitat}
+_textdisabled_ [l=ca] {inhabilitat}
+
+_textaboutgroups_ [l=ca] {Els grups sÃ³n llistes que se separen amb comes, no poseu espais desprÃ©s de les comes. }
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=ca] {Suprimeix un usuari}
+_textremwarn_ [l=ca] {Segur que voleu suprimir permanentment l'usuari <b>_cgiargumun_</b>?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=ca] {Canvia la contrasenya}
+_textoldpw_ [l=ca] {antiga contrasenya}
+_textnewpw_ [l=ca] {nova contrasenya}
+_textretype_ [l=ca] {torneu a escriure la nova contrasenya}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=ca] {La vostra contrasenya ha estat canviada. }
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=ca] {El nom d'usuari no Ã©s vÃ lid.}
+_textinvalidpassword_ [l=ca] {La contrasenya no Ã©s vÃ lida.}
+_textemptypassword_ [l=ca] {Per favor, escriviu una contrasenya inicial per a aquest usuari}
+_textuserexists_ [l=ca] {Aquest usuari ja existeix; per favor, escriviu un altre nom d'usuari.}
+
+_textusernameempty_ [l=ca] {Per favor, escriviu el vostre nom d'usuari.}
+_textpasswordempty_ [l=ca] {Heu d'introduir la contrasenya antiga.}
+_textnewpass1empty_ [l=ca] {IntroduÃ¯u la nova contrasenya i desprÃ©s torneu-la a escriure.}
+_textnewpassmismatch_ [l=ca] {Les dues versions de la nova contrasenya no coincideixen.}
+_textnewinvalidpassword_ [l=ca] {Heu escrit una contrasenya no vÃ lida.}
+_textfailed_ [l=ca] {Hi ha un error en el nom d'usuari o la contrasenya.}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=ca] {NÃºmero de versiÃ³ de Greenstone}
+_textframebrowser_ [l=ca] {Per visualitzar aixÃ² us cal un navegador que accepti marcs ("frames").}
+_textusermanage_ [l=ca] {AdministraciÃ³ d'usuaris}
+_textlistusers_ [l=ca] {llista d'usuaris}
+_textaddusers_ [l=ca] {afegeix un nou usuari}
+_textchangepasswd_ [l=ca] {canvia la contrasenya}
+_textinfo_ [l=ca] {InformaciÃ³ tÃšcnica}
+_textgeneral_ [l=ca] {general}
+_textarguments_ [l=ca] {arguments}
+_textactions_ [l=ca] {accions}
+_textbrowsers_ [l=ca] {navegadors}
+_textprotocols_ [l=ca] {protocols}
+_textconfigfiles_ [l=ca] {Fitxers de configuraciÃ³}
+_textlogs_ [l=ca] {Registres}
+_textusagelog_ [l=ca] {resgistre d'Ãºs}
+_textinitlog_ [l=ca] {registre d'inicialitzaciÃ³}
+_texterrorlog_ [l=ca] {registre d'errors}
+_textadminhome_ [l=ca] {pÃ gina principal de l'administraciÃ³}
+_textreturnhome_ [l=ca] {PÃ gina principal de Greenstone}
+_titlewelcome_ [l=ca] {AdministraciÃ³ }
+_textmaas_ [l=ca] {Els serveis de manteniment i administraciÃ³ sÃ³n els segÃŒents:}
+_textvol_ [l=ca] {visualitza els registres en lÃ­nia}
+_textcmuc_ [l=ca] {crea, mantÃ© i actualitza colÂ·leccions}
+_textati_ [l=ca] {accedeix a informaciÃ³ tÃšcnica com ara arguments CGI}
+
+_texttsaa_ [l=ca] {Es pot accedir a aquests serveis mitjanÃ§ant la barra de navegaciÃ³ situada a  l'esquerra de la pÃ gina.}
+
+_textcolstat_ [l=ca] {Estat de la colÂ·lecciÃ³}
+
+_textcwoa_ [l=ca] {Una colÂ·lecciÃ³ nomÃ©s apareixerÃ  com a "running" (en funcionament) si el fitxer build.cfg existeix, es pot llegir i contÃ© un camp vÃ lid de "builddate" (data de construcciÃ³), Ã©s a dir, > 0, i Ã©s al directori Ã­ndex de la colÂ·lecciÃ³ (Ã©s a dir, NO al directori de construcciÃ³). }
+
+_textcafi_ [l=ca] {pitgeu <i>abrev.</i> per obtenir informaciÃ³ sobre la colÂ·lecciÃ³}
+_textcctv_ [l=ca] {pitgeu <i>colÂ·lecciÃ³</i> per visualitzar una colÂ·lecciÃ³}
+_textsubc_ [l=ca] {Aplica canvis}
+_texteom_ [l=ca] {Error en obrir main.cfg}
+_textftum_ [l=ca] {No s'ha pogut actualitzar main.cfg}
+_textmus_ [l=ca] {s'ha actualitzat satisfactÃ²riament el fitxer main.cfg }
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=ca] {Resum de construcciÃ³ de la colÂ·lecciÃ³  _collectionname_ }
+_textflog_ [l=ca] {Error en el registre de la colÂ·lecciÃ³  _collectionname_ }
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=ca] {Capacitat d'Ãºs de Greenstone}
+
+_textwhy_ [l=ca] {<p>Enviar aquest informe Ã©s una manera d'indicar que la pÃ gina que mirÃ veu us ha semblat difÃ­cil d'utilitzar o frustrant.}
+_textextraforform_ [l=ca] {No cal que empleneu el formulari -- qualsevol informaciÃ³ serÃ  d'utilitat.}
+_textprivacybasic_ [l=ca] {<p>L'informe nomÃ©s contindrÃ  informaciÃ³ sobre la pÃ gina web de Greenstone que estÃ veu visualitzant i sobre la tecnologia que emprÃ veu per visualitzar-la (a mÃ©s de qualsevol informaciÃ³ opcional que doneu). }
+_textstillsend_ [l=ca] {Encara voleu enviar aquest informe?}
+
+_texterror_ [l=ca] {error}
+_textyes_ [l=ca] {SÃ­}
+_textno_ [l=ca] {No}
+_textclosewindow_ [l=ca] {Tanca la finestra}
+_textabout_ [l=ca] {Sobre}
+_textprivacy_ [l=ca] {Privadesa}
+_textsend_ [l=ca] {Envia}
+_textdontsend_ [l=ca] {No enviÃ¯s}
+_textoptionally_ [l=ca] {Opcionalment}
+
+_textunderdev_ [l=ca] {La vista preliminar dels detalls estarÃ  disponible a la versiÃ³ final.}
+
+_textviewdetails_ [l=ca] {Mostra els detalls de l'informe}
+_textmoredetails_ [l=ca] {MÃ©s detalls}
+_texttrackreport_ [l=ca] {Segueix el recorregut d'aquest informe}
+_textcharacterise_ [l=ca] {Quina mena de problema Ã©s}
+_textseverity_ [l=ca] {Com Ã©s de greu el problema?}
+ 
+_textbadrender_ [l=ca] {La pÃ gina es veu rara}
+_textcontenterror_ [l=ca] {Error de contingut}
+_textstrangebehaviour_ [l=ca] {Comportament estrany}
+_textunexpected_ [l=ca] {S'ha produÃ¯t un fet inesperat}
+_textfunctionality_ [l=ca] {DifÃ­cil d'utilitzar}
+_textother_ [l=ca] {Altre}
+
+_textcritical_ [l=ca] {CrÃ­tic}
+_textmajor_ [l=ca] {Greu}
+_textmedium_ [l=ca] {MitjÃ }
+_textminor_ [l=ca] {Lleu}
+_texttrivial_ [l=ca] {Trivial}
+
+_textwhatdoing_ [l=ca] {QuÃš intentÃ veu fer?}
+_textwhatexpected_ [l=ca] {QuÃš pensÃ veu que passaria?}
+_textwhathappened_ [l=ca] {QuÃš ha passat realment?}
+
+_cannotfindcgierror_ [l=ca] {<h2>Disculpeu!</h2>No\\ s'han trobat els programes del servidor per al botÃ³ "Vull\\ formular una queixa".}
+
+_textusabbanner_ [l=ca] {el rÃštol d'estil koru de Greenstone }
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+_textgli_ [l=ca] {La interfÃ­cie del bibliotecari}
+_textglihelp_ [l=ca] {La InterfÃ­cie del Bibliotecari de Greenstone (GLI) us facilita l'accÃ©s a les funcions de Greenstone mitjanÃ§ant una interfÃ­cie fÃ cil d'utilitzar en la qual nomÃ©s cal "apuntar i pitjar". AixÃ² us permet recopilar grups de documents, importar o assignar metadades i incorporar-les a una colÂ·lecciÃ³ de Greenstone. 
+ <p>
+Recordeu que la GLI s'executa juntament amb Greenstone i que suposa que estÃ  instalÂ·lada en un subdirectori de la vostra instalÂ·laciÃ³ de Greenstone. Aquest serÃ  el cas si heu baixat una de les distribucions de Greenstone d'Internet, o si l'heu instalÂ·lada a partir d'un cd-rom de Greenstone.
+ 
+ 
+<h4>Executar la GLI des de Windows</h4>
+ 
+Si treballeu amb Windows, feu arrencar la interfÃ­cie del bibliotecari seleccionant <i>Biblioteca Digital Greenstone</i> a la secciÃ³ <i>Programes</i> del menÃº <i>Inici</i> i triant <i>InterfÃ­cie del bibliotecari</i>. 
+
+ 
+<h4>Excutar la GLI des d'Unix</h4>
+ 
+Per executar la GLI des d'Unix, canvieu al directori <i>gli</i> de la vostra instalÂ·laciÃ³ de Greenstone i llavors executeu el guiÃ³ <i>gli.sh</i>. 
+ 
+<h4>Executar la GLI des de Mac OS X</h4>
+
+En el cercador, aneu a <i>Aplicacions</i> i d'allÃ  a <i>Greenstone</i>
+(si heu instalÂ·lat Greenstone a la ubicaciÃ³ per defecte), i llavors feu arrencar l'aplicaciÃ³ <i>GLI</i>.
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "la interficie del bibliotecari de Greenstone" ## green_bar_left_aligned ## gligr ##
+_httpicongligr_ [l=ca] {_httpimg_/ca/gligr.gif}
+_widthgligr_ [l=ca] {_pagewidth_}
+_heightgligr_ [l=ca] {17}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/chinese-trad.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/chinese-trad.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/chinese-trad.dm	(revision 10506)
@@ -0,0 +1,1384 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Traditional Chinese Language text and icon macros
+# Many thanks to Shu-Jen Show and team (translated November 2004) 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=zh-tr] {éèª}
+_textsource_ [l=zh-tr] {åèäŸæºïŒ}
+_textdate_ [l=zh-tr] {åºçæ¥æïŒ}
+_textnumpages_ [l=zh-tr] {çžœé æžïŒ}
+
+_textsignin_ [l=zh-tr] {ç»å
+¥}
+
+_textdefaultcontent_ [l=zh-tr] {æŸäžå°ç¶²é ïŒè«æ"äžäžé "æ"éŠé ",åå°Geeenstone æžäœåæžé€šã}
+
+_textdefaulttitle_ [l=zh-tr] {Greenstoneç³»çµ±é¯èª€}
+
+_textbadcollection_ [l=zh-tr] {éåè³æåº«(called "_cvariable_") æ²æå®è£åšæ­€Greenstoneæžäœåæžé€šç³»çµ±è£¡ã}
+
+_textselectpage_ [l=zh-tr] {-- éžåçé æž --}
+
+_collectionextra_ [l=zh-tr] {éåè³æåº«å
+å« _about:numdocs_ ä»œæä»¶ã
+æåŸæŽæ°çº _about:builddate_ å€©ä¹åã}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=zh-tr] {<p>éåè³æåº«å
+å« _numdocs_ _If_("_numdocs_" eq "1",ä»œæä»¶,ä»œæä»¶)ïŒå
+±æ _numbytes_.
+<p><a href="_httppagex_(bsummary)">é»éžæ­€è</a> äŸæª¢èŠå»ºç«è³æåº«æçæèŠã
+}
+
+_textimagecollection_ [l=zh-tr] {}
+_textimageabout_ [l=zh-tr] {éæŒé }
+_textimagehome_ [l=zh-tr] {éŠé }
+_textimagehelp_ [l=zh-tr] {åž®å©é¡µ}
+_textimagepref_ [l=zh-tr] {åäººåå¥œèš­å®é }
+_textimagegreenstone_ [l=zh-tr] {Greenstone æžäœåæžé€šè»é«}
+_textimageusab_ [l=zh-tr] {äœ åšäœ¿çšäžæç¢°å°ä»éºŒå°é£åïŒ}
+
+_textimagesearch_ [l=zh-tr] {æŸå°æŽç²Ÿç¢ºçå­äž²}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=zh-tr] {äŸæšé¡å­é åºçèŠœ}
+_textimageCreator_ [l=zh-tr] {äŸäœè
+å­æ¯é åºçèŠœ}
+_textimageSubject_ [l=zh-tr] {äŸäž»é¡åé¡çèŠœ}
+_textimageDescription_ [l=zh-tr] {äŸæè¿°çèŠœ}
+_textimagePublisher_ [l=zh-tr] {äŸåºçè
+çèŠœ}
+_textimageContributor_ [l=zh-tr] {äŸè²¢ç»è
+çèŠœ}
+_textimageDate_ [l=zh-tr] {äŸæ¥æçèŠœ}
+_textimageType_ [l=zh-tr] {äŸè³æºé¡åçèŠœ}
+_textimageFormat_ [l=zh-tr] {äŸæ ŒåŒçèŠœ}
+_textimageIdentifier_ [l=zh-tr] {äŸè³æºç¢ºèªè
+çèŠœ}
+_textimageSource_ [l=zh-tr] {äŸåå§æªåçèŠœ}
+_textimageLanguage_ [l=zh-tr] {äŸèªèšçèŠœ}
+_textimageRelation_ [l=zh-tr] {äŸéä¿çèŠœ}
+_textimageCoverage_ [l=zh-tr] {äŸç¯åçèŠœ}
+_textimageRights_ [l=zh-tr] {äŸæ¬å©çèŠœ}
+
+_textimageOrganization_ [l=zh-tr] {äŸçµç¹çèŠœ}
+_textimageKeyword_ [l=zh-tr] {äŸééµå­çèŠœ}
+_textimageHowto_ [l=zh-tr] {äŸ âåŠäœ..âæ¹åŒäŸçèŠœ}
+_textimageList_ [l=zh-tr] {äŸæä»¶æž
+å®çèŠœ}
+_textimageSeries_ [l=zh-tr] {äŸå·æçèŠœ}
+_textimageTo_ [l=zh-tr] {äŸæªæ­¢æŒæ¬äœçèŠœ}
+_textimageFrom_ [l=zh-tr] {äŸéå§æ¬äœçèŠœ}
+_textimageTopic_ [l=zh-tr] {äŸç¹å¥è­°é¡å·æçèŠœ}
+_textimageBrowse_ [l=zh-tr] {çèŠœ}
+_textimageCollage_ [l=zh-tr] {äŸåœ±åéçèŠœ}
+_textimagePeople_ [l=zh-tr] {äŸäººåå­æ¯é åºçèŠœ}
+_textimageAcronym_ [l=zh-tr] {äŸçž®å¯«å­çèŠœ}
+_textimagePhrase_ [l=zh-tr] {äŸçèªçèŠœ}
+_textimageArtist_ [l=zh-tr] {äŸèè¡å®¶çèŠœ}
+_textimageVolume_ [l=zh-tr] {äŸå·æçèŠœ}
+_textimageCountries_ [l=zh-tr] {äŸåå®¶å¥çèŠœ}
+_textimageCaptions_ [l=zh-tr] {äŸåçæšé¡çèŠœ}
+
+
+_texticontabsearchgreen_ [l=zh-tr] {æå°}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=zh-tr] {æšé¡ A-Z}
+_texticontabCreatorgreen_ [l=zh-tr] {äœè
+ A-Z}
+_texticontabSubjectgreen_ [l=zh-tr] {äž»é¡}
+_texticontabDescriptiongreen_ [l=zh-tr] {æè¿°}
+_texticontabPublishergreen_ [l=zh-tr] {åºçè
+}
+_texticontabContributorgreen_ [l=zh-tr] {è²¢ç»è
+}
+_texticontabDategreen_ [l=zh-tr] {æ¥æ}
+_texticontabTypesgreen_ [l=zh-tr] {çš®é¡}
+_texticontabFormatgreen_ [l=zh-tr] {æ ŒåŒ}
+_texticontabIdentifiergreen_ [l=zh-tr] {ç¢ºèªè
+}
+_texticontabSourcegreen_ [l=zh-tr] {æªæ¡å}
+_texticontabLanguagegreen_ [l=zh-tr] {èªèš}
+_texticontabRelationgreen_ [l=zh-tr] {éä¿}
+_texticontabCoveragegreen_ [l=zh-tr] {ç¯å}
+_texticontabRightsgreen_ [l=zh-tr] {æ¬å©}
+
+_texticontaborggreen_ [l=zh-tr] {çµç¹}
+_texticontabKeywordgreen_ [l=zh-tr] {ééµå­}
+_texticontabhowgreen_ [l=zh-tr] {åŠäœ..}
+_texticontabseriesgreen_ [l=zh-tr] {éå¢å}
+_texticontablistgreen_ [l=zh-tr] {æž
+å®}
+_texticontabtogreen_ [l=zh-tr] {æªæ­¢æŒ}
+_texticontabfromgreen_ [l=zh-tr] {éå§æŒ}
+_texticontabtopicgreen_ [l=zh-tr] {äž»æš}
+_texticontabbrwsegreen_ [l=zh-tr] {çèŠœ+B165}
+_texticontabCollagegreen_ [l=zh-tr] {åèŒ¯}
+_texticontabbrowsgreen_ [l=zh-tr] {çèŠœ}
+_texticontabPeoplegreen_ [l=zh-tr] {äººå A-Z}
+_texticontabAcronymgreen_ [l=zh-tr] {çž®å¯«å­}
+_texticontabPhrasegreen_ [l=zh-tr] {çèª}
+_texticontabArtistgreen_ [l=zh-tr] {èè¡å®¶}
+_texticontabVolumegreen_ [l=zh-tr] {å¢æž}
+_texticontabCaptionsgreen_ [l=zh-tr] {æšé¡}
+_texticontabCountriesgreen_ [l=zh-tr] {åå®¶}
+
+_texticontext_ [l=zh-tr] {åé±æä»¶}
+_texticonclosedbook_ [l=zh-tr] {æéæ­€æä»¶äžŠäžæª¢èŠå
+§å®¹}
+_texticonnext_ [l=zh-tr] {å°äžäžæ®µèœ}
+_texticonprev_ [l=zh-tr] {ååäžæ®µèœ}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=zh-tr] {æª¢èŠMIDIæä»¶}
+_texticonmsword_ [l=zh-tr] {æª¢èŠMicrosoft Wordæä»¶}
+# -- Missing translation: _texticonmp3_
+_texticonpdf_ [l=zh-tr] {æª¢èŠ PDF æä»¶}
+_texticonps_ [l=zh-tr] {æª¢èŠPostScriptæä»¶}
+_texticonppt_ [l=zh-tr] {æª¢èŠPowerPointæä»¶}
+_texticonrtf_ [l=zh-tr] {æª¢èŠRTFæä»¶}
+_texticonxls_ [l=zh-tr] {æª¢èŠMicrosoft Excel æä»¶}
+
+_page_ [l=zh-tr] {é }
+_pages_ [l=zh-tr] {é }
+_of_ [l=zh-tr] {ç}
+_vol_ [l=zh-tr] {å}
+_num_ [l=zh-tr] {åŠ}
+
+_textmonth00_ [l=zh-tr] {}
+_textmonth01_ [l=zh-tr] {äžæ}
+_textmonth02_ [l=zh-tr] {äºæ}
+_textmonth03_ [l=zh-tr] {äžæ}
+_textmonth04_ [l=zh-tr] {åæ}
+_textmonth05_ [l=zh-tr] {äºæ}
+_textmonth06_ [l=zh-tr] {å
+­æ}
+_textmonth07_ [l=zh-tr] {äžæ}
+_textmonth08_ [l=zh-tr] {å
+«æ}
+_textmonth09_ [l=zh-tr] {ä¹æ}
+_textmonth10_ [l=zh-tr] {åæ}
+_textmonth11_ [l=zh-tr] {åäžæ}
+_textmonth12_ [l=zh-tr] {åäºæ}
+
+_textdocument_ [l=zh-tr] {æä»¶}
+_textsection_ [l=zh-tr] {åæ®µ}
+_textparagraph_ [l=zh-tr] {æ®µèœ}
+
+_magazines_ [l=zh-tr] {æå}
+
+_nzdlpagefooter_ [l=zh-tr] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">çŽè¥¿è­æžäœåæžé€šèšç«</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">è³èšç§å­žç³»æ</a>, 
+<a href="http://www.waikato.ac.nz">Waikatoå€§å­ž</a>, 
+çŽè¥¿è­}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "éŠé " ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=zh-tr] {_httpimg_/zh-tr/chomeof.gif}
+_httpiconchomeon_ [l=zh-tr] {_httpimg_/zh-tr/chomeon.gif}
+
+## "å¹«å©" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=zh-tr] {_httpimg_/zh-tr/chelpof.gif}
+_httpiconchelpon_ [l=zh-tr] {_httpimg_/zh-tr/chelpon.gif}
+
+## "åäººåå¥œèš­å®é " ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=zh-tr] {_httpimg_/zh-tr/cprefof.gif}
+_httpiconcprefon_ [l=zh-tr] {_httpimg_/zh-tr/cprefon.gif}
+
+## "å°åèŠéåº" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=zh-tr] {_httpimg_/zh-tr/cusabof.gif}
+_httpiconcusabon_ [l=zh-tr] {_httpimg_/zh-tr/cusabon.gif}
+
+
+## "æ¥è©¢" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=zh-tr] {_httpimg_/zh-tr/tsrchgr.gif}
+_httpicontsrchof_ [l=zh-tr] {_httpimg_/zh-tr/tsrchof.gif}
+_httpicontsrchon_ [l=zh-tr] {_httpimg_/zh-tr/tsrchon.gif}
+_widthtsrchx_ [l=zh-tr] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "æšé¡ a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=zh-tr] {_httpimg_/zh-tr/ttitlgr.gif}
+_httpiconttitleof_ [l=zh-tr] {_httpimg_/zh-tr/ttitlof.gif}
+_httpiconttitleon_ [l=zh-tr] {_httpimg_/zh-tr/ttitlon.gif}
+_widthttitlex_ [l=zh-tr] {87}
+
+# Not true DC, kept for legacy reasons
+## "äœè
+ A-Z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=zh-tr] {_httpimg_/zh-tr/tauthgr.gif}
+_httpicontcreatof_ [l=zh-tr] {_httpimg_/zh-tr/tauthof.gif}
+_httpicontcreaton_ [l=zh-tr] {_httpimg_/zh-tr/tauthon.gif}
+_widthtcreatx_ [l=zh-tr] {87}
+
+## "äž»é¡" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=zh-tr] {_httpimg_/zh-tr/tsubjgr.gif}
+_httpicontsubjon_ [l=zh-tr] {_httpimg_/zh-tr/tsubjon.gif}
+_httpicontsubjof_ [l=zh-tr] {_httpimg_/zh-tr/tsubjof.gif}
+_widthtsubjx_ [l=zh-tr] {87}
+
+## "æè¿°" ## nav_bar_button ## tdesc ##
+_httpicontdescgr_ [l=zh-tr] {_httpimg_/zh-tr/tdescgr.gif}
+_httpicontdescon_ [l=zh-tr] {_httpimg_/zh-tr/tdescon.gif}
+_httpicontdescof_ [l=zh-tr] {_httpimg_/zh-tr/tdescof.gif}
+_widthtdescx_ [l=zh-tr] {90}
+
+## "åºçè
+" ## nav_bar_button ## tpubl ##
+_httpicontpublgr_ [l=zh-tr] {_httpimg_/zh-tr/tpublgr.gif}
+_httpicontpublon_ [l=zh-tr] {_httpimg_/zh-tr/tpublon.gif}
+_httpicontpublof_ [l=zh-tr] {_httpimg_/zh-tr/tpublof.gif}
+_widthtpublx_ [l=zh-tr] {87}
+
+## "è²¢ç»è
+" ## nav_bar_button ## tcontr ##
+_httpicontcontrgr_ [l=zh-tr] {_httpimg_/zh-tr/tcontrgr.gif}
+_httpicontcontron_ [l=zh-tr] {_httpimg_/zh-tr/tcontron.gif}
+_httpicontcontrof_ [l=zh-tr] {_httpimg_/zh-tr/tcontrof.gif}
+_widthtcontrx_ [l=zh-tr] {89}
+
+## "æ¥æ" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=zh-tr] {_httpimg_/zh-tr/tdategr.gif}
+_httpicontdateof_ [l=zh-tr] {_httpimg_/zh-tr/tdateof.gif}
+_httpicontdateon_ [l=zh-tr] {_httpimg_/zh-tr/tdateon.gif}
+_widthtdatex_ [l=zh-tr] {87}
+
+## "é¡å" ## nav_bar_button ## ttype ##
+_httpiconttypegr_ [l=zh-tr] {_httpimg_/zh-tr/ttypegr.gif}
+_httpiconttypeof_ [l=zh-tr] {_httpimg_/zh-tr/ttypeof.gif}
+_httpiconttypeon_ [l=zh-tr] {_httpimg_/zh-tr/ttypeon.gif}
+_widthttypex_ [l=zh-tr] {87}
+
+## "æ ŒåŒ" ## nav_bar_button ## tform ##
+_httpicontformgr_ [l=zh-tr] {_httpimg_/zh-tr/tformgr.gif}
+_httpicontformof_ [l=zh-tr] {_httpimg_/zh-tr/tformof.gif}
+_httpicontformon_ [l=zh-tr] {_httpimg_/zh-tr/tformon.gif}
+_widthtformx_ [l=zh-tr] {87}
+
+## "ç¢ºèªè
+" ## nav_bar_button ## tident ##
+_httpicontidentgr_ [l=zh-tr] {_httpimg_/zh-tr/tidentgr.gif}
+_httpicontidentof_ [l=zh-tr] {_httpimg_/zh-tr/tidentof.gif}
+_httpicontidenton_ [l=zh-tr] {_httpimg_/zh-tr/tidenton.gif}
+_widthtidentx_ [l=zh-tr] {87}
+
+# Not true DC, kept for legacy reasons
+## "æªæ¡åçš±" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=zh-tr] {_httpimg_/zh-tr/tsrcgr.gif}
+_httpicontsrcof_ [l=zh-tr] {_httpimg_/zh-tr/tsrcof.gif}
+_httpicontsrcon_ [l=zh-tr] {_httpimg_/zh-tr/tsrcon.gif}
+_widthtsrcx_ [l=zh-tr] {87}
+
+## "èªèš" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=zh-tr] {_httpimg_/zh-tr/tlanggr.gif}
+_httpicontlangon_ [l=zh-tr] {_httpimg_/zh-tr/tlangon.gif}
+_httpicontlangof_ [l=zh-tr] {_httpimg_/zh-tr/tlangof.gif}
+_widthtlangx_ [l=zh-tr] {87}
+
+## "éä¿" ## nav_bar_button ## trel ##
+_httpicontrelgr_ [l=zh-tr] {_httpimg_/zh-tr/trelgr.gif}
+_httpicontrelon_ [l=zh-tr] {_httpimg_/zh-tr/trelon.gif}
+_httpicontrelof_ [l=zh-tr] {_httpimg_/zh-tr/trelof.gif}
+_widthtrelx_ [l=zh-tr] {87}
+
+## "ç¯å" ## nav_bar_button ## tcover ##
+_httpicontcovergr_ [l=zh-tr] {_httpimg_/zh-tr/tcovergr.gif}
+_httpicontcoveron_ [l=zh-tr] {_httpimg_/zh-tr/tcoveron.gif}
+_httpicontcoverof_ [l=zh-tr] {_httpimg_/zh-tr/tcoverof.gif}
+_widthtcoverx_ [l=zh-tr] {87}
+
+## "æ¬å©" ## nav_bar_button ## tright ##
+_httpicontrightgr_ [l=zh-tr] {_httpimg_/zh-tr/trightgr.gif}
+_httpicontrighton_ [l=zh-tr] {_httpimg_/zh-tr/trighton.gif}
+_httpicontrightof_ [l=zh-tr] {_httpimg_/zh-tr/trightof.gif}
+_widthtrightx_ [l=zh-tr] {87}
+
+
+
+## "éå¢å" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=zh-tr] {_httpimg_/zh-tr/tsergr.gif}
+_httpicontserof_ [l=zh-tr] {_httpimg_/zh-tr/tserof.gif}
+_httpicontseron_ [l=zh-tr] {_httpimg_/zh-tr/tseron.gif}
+_widthtserx_ [l=zh-tr] {87}
+
+## "æªæ­¢æŒ" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=zh-tr] {_httpimg_/zh-tr/ttogr.gif}
+_httpiconttoon_ [l=zh-tr] {_httpimg_/zh-tr/ttoon.gif}
+_httpiconttoof_ [l=zh-tr] {_httpimg_/zh-tr/ttoof.gif}
+_widthttox_ [l=zh-tr] {87}
+
+## "éå§æŒ" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=zh-tr] {_httpimg_/zh-tr/tfromgr.gif}
+_httpicontfromon_ [l=zh-tr] {_httpimg_/zh-tr/tfromon.gif}
+_httpicontfromof_ [l=zh-tr] {_httpimg_/zh-tr/tfromof.gif}
+_widthtfromx_ [l=zh-tr] {87}
+
+## "çµç¹" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=zh-tr] {_httpimg_/zh-tr/torggr.gif}
+_httpicontorgon_ [l=zh-tr] {_httpimg_/zh-tr/torgon.gif}
+_httpicontorgof_ [l=zh-tr] {_httpimg_/zh-tr/torgof.gif}
+_widthtorgx_ [l=zh-tr] {98}
+
+## "åŠäœïœ¥ïœ¥" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=zh-tr] {_httpimg_/zh-tr/thowgr.gif}
+_httpiconthowon_ [l=zh-tr] {_httpimg_/zh-tr/thowon.gif}
+_httpiconthowof_ [l=zh-tr] {_httpimg_/zh-tr/thowof.gif}
+_widththowx_ [l=zh-tr] {87}
+
+## "è­°é¡" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=zh-tr] {_httpimg_/zh-tr/ttopicgr.gif}
+_httpiconttopicon_ [l=zh-tr] {_httpimg_/zh-tr/ttopicon.gif}
+_httpiconttopicof_ [l=zh-tr] {_httpimg_/zh-tr/ttopicof.gif}
+_widthttopicx_ [l=zh-tr] {87}
+
+## "çèŠœ" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=zh-tr] {_httpimg_/zh-tr/tbrwsegr.gif}
+_httpicontbrwseon_ [l=zh-tr] {_httpimg_/zh-tr/tbrwseon.gif}
+_httpicontbrwseof_ [l=zh-tr] {_httpimg_/zh-tr/tbrwseof.gif}
+_widthtbrwsex_ [l=zh-tr] {87}
+
+## "åèŒ¯" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=zh-tr] {_httpimg_/zh-tr/tcollgr.gif}
+_httpicontcollof_ [l=zh-tr] {_httpimg_/zh-tr/tcollof.gif}
+_httpicontcollon_ [l=zh-tr] {_httpimg_/zh-tr/tcollon.gif}
+_widthtcollx_ [l=zh-tr] {87}
+
+## "äººå" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=zh-tr] {_httpimg_/zh-tr/tpeopgr.gif}
+_httpicontpeopof_ [l=zh-tr] {_httpimg_/zh-tr/tpeopof.gif}
+_httpicontpeopon_ [l=zh-tr] {_httpimg_/zh-tr/tpeopon.gif}
+_widthtpeopx_ [l=zh-tr] {97}
+
+## "çž®å¯«è©" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=zh-tr] {_httpimg_/zh-tr/tacrogr.gif}
+_httpicontacroof_ [l=zh-tr] {_httpimg_/zh-tr/tacroof.gif}
+_httpicontacroon_ [l=zh-tr] {_httpimg_/zh-tr/tacroon.gif}
+_widthtacrox_ [l=zh-tr] {87}
+
+## "çèª" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=zh-tr] {_httpimg_/zh-tr/tphrsegr.gif}
+_httpicontphrseof_ [l=zh-tr] {_httpimg_/zh-tr/tphrseof.gif}
+_httpicontphrseon_ [l=zh-tr] {_httpimg_/zh-tr/tphrseon.gif}
+_widthtphrsex_ [l=zh-tr] {87}
+
+## "èè¡å®¶" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=zh-tr] {_httpimg_/zh-tr/tartstgr.gif}
+_httpicontartstof_ [l=zh-tr] {_httpimg_/zh-tr/tartstof.gif}
+_httpicontartston_ [l=zh-tr] {_httpimg_/zh-tr/tartston.gif}
+_widthtartstx_ [l=zh-tr] {87}
+
+## "ééµè©" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=zh-tr] {_httpimg_/zh-tr/tkwgr.gif}
+_httpicontkwof_ [l=zh-tr] {_httpimg_/zh-tr/tkwof.gif}
+_httpicontkwon_ [l=zh-tr] {_httpimg_/zh-tr/tkwon.gif}
+_widthtkwx_ [l=zh-tr] {87}
+
+## "å¢æž" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=zh-tr] {_httpimg_/zh-tr/tvolgr.gif}
+_httpicontvolof_ [l=zh-tr] {_httpimg_/zh-tr/tvolof.gif}
+_httpicontvolon_ [l=zh-tr] {_httpimg_/zh-tr/tvolon.gif}
+_widthtvolx_ [l=zh-tr] {87}
+
+## "æšé¡" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=zh-tr] {_httpimg_/zh-tr/tcaptgr.gif}
+_httpicontcaptof_ [l=zh-tr] {_httpimg_/zh-tr/tcaptof.gif}
+_httpicontcapton_ [l=zh-tr] {_httpimg_/zh-tr/tcapton.gif}
+_widthtcaptx_ [l=zh-tr] {87}
+
+## "åå®¶" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=zh-tr] {_httpimg_/zh-tr/tcountgr.gif}
+_httpicontcountof_ [l=zh-tr] {_httpimg_/zh-tr/tcountof.gif}
+_httpicontcounton_ [l=zh-tr] {_httpimg_/zh-tr/tcounton.gif}
+_widthtcountx_ [l=zh-tr] {87}
+
+## "å¹«å©" ## green_title ## h_help ##
+_httpiconhhelp_ [l=zh-tr] {_httpimg_/zh-tr/h\_help.gif}
+_widthhhelp_ [l=zh-tr] {200}
+_heighthhelp_ [l=zh-tr] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=zh-tr] {éæŒéåè³æåº«}
+
+_textsubcols1_ [l=zh-tr] {<p>éåè³æåº«ç± _1_ å­è³æåº«çµæïŒä»åäœæŒïŒ
+<blockquote>
+}
+
+_textsubcols2_ [l=zh-tr] {</blockquote>
+äœ å¯ä»¥åšåäººåå¥œèš­å®é æ¥è©¢ïŒäžŠä¿®æ¹ïŒç®åæ­£åšäœ¿çšäž­çè³æåº«ã}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "éæŒ" ## green_title ## h_about ##
+_httpiconhabout_ [l=zh-tr] {_httpimg_/zh-tr/h\_about.gif}
+_widthhabout_ [l=zh-tr] {200}
+_heighthabout_ [l=zh-tr] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=zh-tr] {æšé¡ A-Z}
+_texticonhcreat_ [l=zh-tr] {äœè
+ A-Z}
+_texticonhsubj_ [l=zh-tr] {äž»é¡}
+_texticonhdesc_ [l=zh-tr] {æè¿°}
+_texticonhpubl_ [l=zh-tr] {åºçè
+}
+_texticonhcontr_ [l=zh-tr] {è²¢ç»è
+}
+_texticonhdate_ [l=zh-tr] {æ¥æ}
+_texticonhtype_ [l=zh-tr] {é¡å}
+_texticonhform_ [l=zh-tr] {æ ŒåŒ}
+_texticonhident_ [l=zh-tr] {ç¢ºèªè
+}
+_texticonhsrc_ [l=zh-tr] {æªæ¡åçš±}
+_texticonhlang_ [l=zh-tr] {èªèš}
+_texticonhrel_ [l=zh-tr] {éä¿}
+_texticonhcover_ [l=zh-tr] {ç¯å}
+_texticonhright_ [l=zh-tr] {æ¬å©}
+
+_texticonhcoll_ [l=zh-tr] {åèŒ¯}
+_texticonhto_ [l=zh-tr] {æªæ­¢æŒ}
+_texticonhfrom_ [l=zh-tr] {éå§æŒ}
+_texticonhser_ [l=zh-tr] {éå¢å}
+_texticonhhow_ [l=zh-tr] {åŠäœïœ¥ïœ¥}
+_texticonhorg_ [l=zh-tr] {çµç¹}
+_texticonhbrwse_ [l=zh-tr] {çèŠœ}
+_texticonhbrows_ [l=zh-tr] {çèŠœ}
+_texticonhpeople_ [l=zh-tr] {äººå A-Z}
+_texticonhacronym_ [l=zh-tr] {çž®å¯«å­}
+_texticonhphrases_ [l=zh-tr] {çèª}
+_texticonhartist_ [l=zh-tr] {èè¡å®¶}
+_texticonhkw_ [l=zh-tr] {ééµå­}
+_texticonhvol_ [l=zh-tr] {å¢æž}
+_texticonhcapt_ [l=zh-tr] {æšé¡}
+_texticonhcount_ [l=zh-tr] {åå®¶}
+
+_texticonopenbookshelf_ [l=zh-tr] {ééæ¬æ®µèœ}
+_texticonclosedbookshelf_ [l=zh-tr] {éåæ¬æ®µèœäžŠæª¢èŠå
+¶å
+§å®¹}
+_texticonopenbook_ [l=zh-tr] {ééæ¬æž}
+_texticonclosedfolder_ [l=zh-tr] {éåæ­€è³æå€ŸäžŠæª¢èŠç®é}
+_texticonclosedfolder2_ [l=zh-tr] {éåæ­€å­åæ®µïŒ}
+_texticonopenfolder_ [l=zh-tr] {ééæ­€è³æå€Ÿ}
+_texticonopenfolder2_ [l=zh-tr] {ééæ­€å­åæ®µïŒ}
+_texticonsmalltext_ [l=zh-tr] {æª¢èŠæ­€æ®µæå­}
+_texticonsmalltext2_ [l=zh-tr] {æª¢èŠæå­ïŒ }
+_texticonpointer_ [l=zh-tr] {ç®åæ®µèœ}
+_texticondetach_ [l=zh-tr] {åšæ°èŠçªéåæ­€é }
+_texticonhighlight_ [l=zh-tr] {æšç€ºæå°ä¹ééµå­}
+_texticonnohighlight_ [l=zh-tr] {äžèŠæšç€ºæå°ä¹ééµå­}
+_texticoncontracttoc_ [l=zh-tr] {ééç®æ¬¡åè¡š}
+_texticonexpandtoc_ [l=zh-tr] {å±éç®æ¬¡}
+_texticonexpandtext_ [l=zh-tr] {é¡¯çŸæä»¶å
+šæ}
+_texticoncontracttext_ [l=zh-tr] {éå°æéžåçæ®µèœåªé¡¯ç€ºæå­}
+_texticonwarning_ [l=zh-tr] {<b>è­ŠåïŒ</b>}
+_texticoncont_ [l=zh-tr] {æ¯åŠç¹ŒçºïŒ}
+
+_textltwarning_ [l=zh-tr] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_è¥èŠå±éæ­€æä»¶ä¹å
+šæåå°æåšäœ ççèŠœåšäžæ¬¡é¡¯ç€ºå€§éçè³æ _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=zh-tr] {å°è©²é }
+_textintro_ [l=zh-tr] {<i>(åèšæå­)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "æšé¡ a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=zh-tr] {_httpimg_/zh-tr/h\_title.gif}
+_widthhtitle_ [l=zh-tr] {200}
+_heighthtitle_ [l=zh-tr] {57}
+
+# Not true DC, kept for legacy reasons
+## "äœè
+ a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=zh-tr] {_httpimg_/zh-tr/h\_auth.gif}
+_widthhcreat_ [l=zh-tr] {200}
+_heighthcreat_ [l=zh-tr] {57}
+
+## "äž»é¡" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=zh-tr] {_httpimg_/zh-tr/h\_subj.gif}
+_widthhsubj_ [l=zh-tr] {200}
+_heighthsubj_ [l=zh-tr] {57}
+
+## "æè¿°" ## green_title ## h_desc ##
+_httpiconhdesc_ [l=zh-tr] {_httpimg_/zh-tr/h\_desc.gif}
+_widthhdesc_ [l=zh-tr] {200}
+_heighthdesc_ [l=zh-tr] {57}
+
+## "åºçè
+" ## green_title ## h_publ ##
+_httpiconhpubl_ [l=zh-tr] {_httpimg_/zh-tr/h\_publ.gif}
+_widthhpubl_ [l=zh-tr] {200}
+_heighthpubl_ [l=zh-tr] {57}
+
+## "è²¢ç»è
+" ## green_title ## h_contr ##
+_httpiconhcontr_ [l=zh-tr] {_httpimg_/zh-tr/h\_contr.gif}
+_widthhcontr_ [l=zh-tr] {200}
+_heighthcontr_ [l=zh-tr] {57}
+
+## "æ¥æ" ## green_title ## h_date ##
+_httpiconhdate_ [l=zh-tr] {_httpimg_/zh-tr/h\_date.gif}
+_widthhdate_ [l=zh-tr] {200}
+_heighthdate_ [l=zh-tr] {57}
+
+## "é¡å" ## green_title ## h_type ##
+_httpiconhtype_ [l=zh-tr] {_httpimg_/zh-tr/h\_type.gif}
+_widthhtype_ [l=zh-tr] {200}
+_heighthtype_ [l=zh-tr] {57}
+
+## "æ ŒåŒ" ## green_title ## h_form ##
+_httpiconhform_ [l=zh-tr] {_httpimg_/zh-tr/h\_form.gif}
+_widthhform_ [l=zh-tr] {200}
+_heighthform_ [l=zh-tr] {57}
+
+## "ç¢ºèªè
+" ## green_title ## h_ident ##
+_httpiconhident_ [l=zh-tr] {_httpimg_/zh-tr/h\_ident.gif}
+_widthhident_ [l=zh-tr] {200}
+_heighthident_ [l=zh-tr] {57}
+
+# Not true DC, kept for legacy reasons
+## "æªæ¡åçš±" ## green_title ## h_src ##
+_httpiconhsrc_ [l=zh-tr] {_httpimg_/zh-tr/h\_src.gif}
+_widthhsrc_ [l=zh-tr] {200}
+_heighthsrc_ [l=zh-tr] {57}
+
+## "èªèš" ## green_title ## h_lang ##
+_httpiconhlang_ [l=zh-tr] {_httpimg_/zh-tr/h\_lang.gif}
+_widthhlang_ [l=zh-tr] {200}
+_heighthlang_ [l=zh-tr] {57}
+
+## "éä¿" ## green_title ## h_rel ##
+_httpiconhrel_ [l=zh-tr] {_httpimg_/zh-tr/h\_rel.gif}
+_widthhrel_ [l=zh-tr] {200}
+_heighthrel_ [l=zh-tr] {57}
+
+## "ç¯å" ## green_title ## h_cover ##
+_httpiconhcover_ [l=zh-tr] {_httpimg_/zh-tr/h\_cover.gif}
+_widthhcover_ [l=zh-tr] {200}
+_heighthcover_ [l=zh-tr] {57}
+
+## "æ¬å©" ## green_title ## h_right ##
+_httpiconhright_ [l=zh-tr] {_httpimg_/zh-tr/h\_right.gif}
+_widthhright_ [l=zh-tr] {200}
+_heighthright_ [l=zh-tr] {57}
+
+
+
+## "æªæ­¢æŒ" ## green_title ## h_to ##
+_httpiconhto_ [l=zh-tr] {_httpimg_/zh-tr/h\_to.gif}
+_widthhto_ [l=zh-tr] {200}
+_heighthto_ [l=zh-tr] {57}
+
+## "éå§æŒ" ## green_title ## h_from ##
+_httpiconhfrom_ [l=zh-tr] {_httpimg_/zh-tr/h\_from.gif}
+_widthhfrom_ [l=zh-tr] {200}
+_heighthfrom_ [l=zh-tr] {57}
+
+## "éå¢å" ## green_title ## h_ser ##
+_httpiconhser_ [l=zh-tr] {_httpimg_/zh-tr/h\_ser.gif}
+_widthhser_ [l=zh-tr] {200}
+_heighthser_ [l=zh-tr] {57}
+
+## "åŠäœïœ¥ïœ¥" ## green_title ## h_how ##
+_httpiconhhow_ [l=zh-tr] {_httpimg_/zh-tr/h\_how.gif}
+_widthhhow_ [l=zh-tr] {200}
+_heighthhow_ [l=zh-tr] {57}
+
+## "äž»æš" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=zh-tr] {_httpimg_/zh-tr/h\_topic.gif}
+_widthhtopic_ [l=zh-tr] {200}
+_heighthtopic_ [l=zh-tr] {57}
+
+## "çµç¹" ## green_title ## h_org ##
+_httpiconhorg_ [l=zh-tr] {_httpimg_/zh-tr/h\_org.gif}
+_widthhorg_ [l=zh-tr] {200}
+_heighthorg_ [l=zh-tr] {57}
+
+## "çèŠœ" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=zh-tr] {_httpimg_/zh-tr/h\_brwse.gif}
+_widthhbrwse_ [l=zh-tr] {200}
+_heighthbrwse_ [l=zh-tr] {57}
+
+## "åèŒ¯" ## green_title ## h_coll ##
+_httpiconhcoll_ [l=zh-tr] {_httpimg_/zh-tr/h\_coll.gif}
+_widthhcoll_ [l=zh-tr] {200}
+_heighthcoll_ [l=zh-tr] {57}
+
+## "äºº" ## green_title ## h_people ##
+_httpiconhpeople_ [l=zh-tr] {_httpimg_/zh-tr/h\_people.gif}
+_widthhpeople_ [l=zh-tr] {200}
+_heighthpeople_ [l=zh-tr] {57}
+
+## "çž®å¯«" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=zh-tr] {_httpimg_/zh-tr/h\_acro.gif}
+_widthhacronym_ [l=zh-tr] {200}
+_heighthacronym_ [l=zh-tr] {57}
+
+## "çèª" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=zh-tr] {_httpimg_/zh-tr/h\_phrse.gif}
+_widthhphrse_ [l=zh-tr] {200}
+_heighthphrse_ [l=zh-tr] {57}
+
+## "èè¡å®¶" ## green_title ## h_artist ##
+_httpiconhartist_ [l=zh-tr] {_httpimg_/zh-tr/h\_artist.gif}
+_widthhartist_ [l=zh-tr] {200}
+_heighthartist_ [l=zh-tr] {57}
+
+## "ééµè©" ## green_title ## h_kw ##
+_httpiconhkw_ [l=zh-tr] {_httpimg_/zh-tr/h\_kw.gif}
+_widthhkw_ [l=zh-tr] {200}
+_heighthkw_ [l=zh-tr] {57}
+
+## "å¢æž" ## green_title ## h_vol ##
+_httpiconhvol_ [l=zh-tr] {_httpimg_/zh-tr/h\_vol.gif}
+_widthhvol_ [l=zh-tr] {200}
+_heighthvol_ [l=zh-tr] {57}
+
+## "åå®¶" ## green_title ## h_count ##
+_httpiconhcount_ [l=zh-tr] {_httpimg_/zh-tr/h\_count.gif}
+_widthhcount_ [l=zh-tr] {200}
+_heighthcount_ [l=zh-tr] {57}
+
+## "æšé¡" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=zh-tr] {_httpimg_/zh-tr/h\_capt.gif}
+_widthhcapt_ [l=zh-tr] {200}
+_heighthcapt_ [l=zh-tr] {57}
+
+
+## "ç¹ŒçºïŒ?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=zh-tr] {_httpimg_/zh-tr/contof.gif}
+_httpiconconton_ [l=zh-tr] {_httpimg_/zh-tr/conton.gif}
+
+## "å±éæå­" ## document_button ## eallt ##
+_httpiconealltof_ [l=zh-tr] {_httpimg_/zh-tr/ealltof.gif}
+_httpiconeallton_ [l=zh-tr] {_httpimg_/zh-tr/eallton.gif}
+
+## "ééç®æ¬¡" ## document_button ## econc ##
+_httpiconeconcof_ [l=zh-tr] {_httpimg_/zh-tr/econcof.gif}
+_httpiconeconcon_ [l=zh-tr] {_httpimg_/zh-tr/econcon.gif}
+
+## "éåæ°èŠçª" ## document_button ## edtch ##
+_httpiconedtchof_ [l=zh-tr] {_httpimg_/zh-tr/edtchof.gif}
+_httpiconedtchon_ [l=zh-tr] {_httpimg_/zh-tr/edtchon.gif}
+
+## "éåç®æ¬¡" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=zh-tr] {_httpimg_/zh-tr/eexpcof.gif}
+_httpiconeexpcon_ [l=zh-tr] {_httpimg_/zh-tr/eexpcon.gif}
+
+## "ééæå­" ## document_button ## etsec ##
+_httpiconetsecof_ [l=zh-tr] {_httpimg_/zh-tr/etsecof.gif}
+_httpiconetsecon_ [l=zh-tr] {_httpimg_/zh-tr/etsecon.gif}
+
+## "åçœé¡¯ç€º" ## document_button ## ehl ##
+_httpiconehlof_ [l=zh-tr] {_httpimg_/zh-tr/ehlof.gif}
+_httpiconehlon_ [l=zh-tr] {_httpimg_/zh-tr/ehlon.gif}
+
+## "äžåçœé¡¯ç€º" ## document_button ## enhl ##
+_httpiconenhlof_ [l=zh-tr] {_httpimg_/zh-tr/enhlof.gif}
+_httpiconenhlon_ [l=zh-tr] {_httpimg_/zh-tr/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=zh-tr] {_If_(_thislast_,results _thisfirst_ - _thislast_ éå°æ¥è©¢: _cgiargq_ïŒæå°äžå°ç¬Šåçæ¢ä»¶: _cgiargq_)}
+_textnoquerytitle_ [l=zh-tr] {æå°é é¢}
+
+_texticonthispage_ [l=zh-tr] {æå°}
+_textsome_ [l=zh-tr] {éšå}
+_textall_ [l=zh-tr] {å
+šéš}
+_textboolean_ [l=zh-tr] {åžæéèŒ¯}
+_textranked_ [l=zh-tr] {æå}
+_textnatural_ [l=zh-tr] {èªç¶}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=zh-tr] {}
+_texticonsearchhistorybar_ [l=zh-tr] {æå°æ­·å²çŽé}
+
+_textifeellucky_ [l=zh-tr] {æèŠºåŸå¹žé!}
+
+#alt text for query buttons
+_textusequery_ [l=zh-tr] {äœ¿çšéåæ¥è©¢é 
+ç®}
+_textfreqmsg1_ [l=zh-tr] {ç¬Šåçå­æž: }
+_textpostprocess_ [l=zh-tr] {_If_(_quotedquery_,<br><i> åŸèçå»çŒçŸ _quotedquery_</i>
+)}
+_textinvalidquery_ [l=zh-tr] {é¯èª€çæ¥è©¢èªæ³}
+
+_textmorethan_ [l=zh-tr] {å€§æŒ}
+_textapprox_ [l=zh-tr] {éæŒ}
+_textnodocs_ [l=zh-tr] {æ²ææä»¶ç¬Šåæ¥è©¢çæ¢ä»¶ã}
+_text1doc_ [l=zh-tr] {äžä»œæä»¶ç¬Šåæ¥è©¢çæ¢ä»¶ã}
+_textlotsdocs_ [l=zh-tr] {ç¬Šåæ¥è©¢æ¢ä»¶ä¹æä»¶ã}
+_textmatches_ [l=zh-tr] {åç¬Šå}
+_textbeginsearch_ [l=zh-tr] {éå§æå°}
+_textrunquery_ [l=zh-tr] {éå§æå°}
+_textclearform_ [l=zh-tr] {æž
+é€}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=zh-tr] {å­è©æçèª}
+_textinfield_ [l=zh-tr] {... åšé å}
+_textfoldstem_ [l=zh-tr] {(è³æå€Ÿ, çµå°Ÿ)}
+
+_textadvquery_ [l=zh-tr] {æçŽæ¥èŒžå
+¥æ¥è©¢é 
+ç®:}
+_textallfields_ [l=zh-tr] {å
+šéšæ¬äœ}
+_texttextonly_ [l=zh-tr] {åªéæå­}
+_textand_ [l=zh-tr] {äž}
+_textor_ [l=zh-tr] {æ}
+_textandnot_ [l=zh-tr] {äžäžå
+æ¬}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=zh-tr] {æç
+§ _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_, at _gselection_ level )_If_(_nselection_,in _nselection_ language ) æ¥è©¢ïŒæä»¶äž­å
+å« _querytypeselection_ çééµå­}
+
+_textadvancedsearch_ [l=zh-tr] {_indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_,at _gselection_ level )_If_(_nselection_,in _nselection_ language )äœ¿çš _querytypeselection_ èªæ³æ¥è©¢}
+
+_textformsimplesearch_ [l=zh-tr] {_If_(_jselection_, _jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )ä»¥ _formquerytypeselection_ æ¥è©¢}
+
+_textformadvancedsearch_ [l=zh-tr] {_If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )æ¥è©¢äžŠäžä»¥ _formquerytypeselection_ é åºé¡¯ç€ºæ¥è©¢çµæ}
+
+
+_textnojsformwarning_ [l=zh-tr] {è­Šå: Javascript å·è¡ç°å¢è¢«çèŠœåšééäºïŒ<br>çºäºèŠå·è¡è¡šæ Œæ¥è©¢è«éåJavascriptã}
+_textdatesearch_ [l=zh-tr] {éåè³æåº«åšæ¥è©¢æå¯ä»¥åŠå€åå äžæéæ¢ä»¶}
+_textstartdate_ [l=zh-tr] {éå§ (æéå¶) æ¥æ:}
+_textenddate_ [l=zh-tr] {çµææ¥æ:}
+_textbc_ [l=zh-tr] {è¥¿å
+å}
+_textad_ [l=zh-tr] {è¥¿å
+}
+_textexplaineras_ [l=zh-tr] {C.E. å B.C.E çºè¥¿å
+(A.D)èè¥¿å
+å(B.C)ä¹åçŸ©è©ïŒåå¥ä»£è¡š"Common Era"è"Before the Common Era"}
+
+_textstemon_ [l=zh-tr] {(å¿œç¥å­å°Ÿ)}
+
+_textsearchhistory_ [l=zh-tr] {æ¥è©¢æ­·å²èšé}
+
+#text macros for search history
+_textnohistory_ [l=zh-tr] {æ¥è©¢æ­·å²çŽéäžå­åš}
+_texthresult_ [l=zh-tr] {çµæ}
+_texthresults_ [l=zh-tr] {çµæ}
+_texthallwords_ [l=zh-tr] {ææå­æž}
+_texthsomewords_ [l=zh-tr] {äžäºå­}
+_texthboolean_ [l=zh-tr] {åžæéèŒ¯}
+_texthranked_ [l=zh-tr] {æå}
+_texthcaseon_ [l=zh-tr] {å€§å°å¯«éäžèŽ}
+_texthcaseoff_ [l=zh-tr] {å¿œç¥å€§å°å¯«}
+_texthstemon_ [l=zh-tr] {å¿œç¥æå­çµå°Ÿ}
+_texthstemoff_ [l=zh-tr] {æå­çµå°ŸéäžèŽ}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "æ¥è©¢" ## green_title ## h_search ##
+_httpiconhsearch_ [l=zh-tr] {_httpimg_/zh-tr/h\_search.gif}
+_widthhsearch_ [l=zh-tr] {200}
+_heighthsearch_ [l=zh-tr] {57}
+
+## "çµæ" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=zh-tr] {_httpimg_/zh-tr/qryresb.gif}
+_widthqryresb_ [l=zh-tr] {_pagewidth_}
+_heightqryresb_ [l=zh-tr] {17}
+
+## "æ­·å²çŽé" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=zh-tr] {_httpimg_/zh-tr/schhistb.gif}
+_widthsrchhistb_ [l=zh-tr] {_pagewidth_}
+_heightsrchhistb_ [l=zh-tr] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=zh-tr] {ä»¥äžå°èš­å®åäººåå¥œïŒè«å¿äœ¿çšçèŠœåšçåå°äžäžé æéïŒä»¥å
+ç¡æ³å®æåäººåå¥œèš­å®ïŒè«äœ¿çšäžæ¹å·¥å
+·åçæéã}
+_textsetprefs_ [l=zh-tr] {èš­å®åäººåå¥œ}
+_textsearchprefs_ [l=zh-tr] {æ¥è©¢åäººåå¥œ}
+_textcollectionprefs_ [l=zh-tr] {èéåäººåå¥œ}
+_textpresentationprefs_ [l=zh-tr] {é¡¯ç€ºåäººåå¥œèš­å®}
+_textpreferences_ [l=zh-tr] {åäººåå¥œ}
+_textcasediffs_ [l=zh-tr] {å€§å°å¯«èŠçºäžå:}
+_textignorecase_ [l=zh-tr] {å€§å°å¯«èŠçºçžå}
+_textmatchcase_ [l=zh-tr] {å€§å°å¯«éå®å
+šäžèŽ}
+_textwordends_ [l=zh-tr] {æå­çµå°Ÿ:}
+_textstem_ [l=zh-tr] {å¿œç¥æå­çµå°Ÿ}
+_textnostem_ [l=zh-tr] {æŽåæå­å¿
+é äžèŽ}
+_textprefop_ [l=zh-tr] {æå€åå³ _maxdocoption_ åæ¥è©¢çµæïŒäžé é¡¯ç€º _hitsperpageoption_ åæ¥è©¢çµæã}
+_textextlink_ [l=zh-tr] {è®åå€éšç¶²é :}
+_textintlink_ [l=zh-tr] {éæ°åå°åå§æä»¶:}
+_textlanguage_ [l=zh-tr] {ä»é¢èªèš:}
+_textencoding_ [l=zh-tr] {ç·šç¢Œæ¹åŒ:}
+_textformat_ [l=zh-tr] {ä»é¢æ ŒåŒ:}
+_textall_ [l=zh-tr] {å
+šéš}
+_textquerymode_ [l=zh-tr] {æ¥è©¢æš¡åŒ:}
+_textsimplemode_ [l=zh-tr] {ç°¡å®æ¥è©¢æš¡åŒ}
+_textadvancedmode_ [l=zh-tr] {é²éæ¥è©¢æš¡åŒ (å¯äœ¿çš åžæåŒ !, &, |, åéç®åŒ)}
+_textlinkinterm_ [l=zh-tr] {éééæ¥ç¶²é }
+_textlinkdirect_ [l=zh-tr] {çŽæ¥é£å°}
+_textdigitlib_ [l=zh-tr] {æžäœåæžé€š}
+_textweb_ [l=zh-tr] {ç¶²ç«}
+_textgraphical_ [l=zh-tr] {ååœ¢}
+_texttextual_ [l=zh-tr] {æå­}
+_textcollectionoption_ [l=zh-tr] {<p>
+å­è³æåº«æä»¶å
+æ¬:
+<br>}
+
+_textrelateddocdisplay_ [l=zh-tr] {ååºçžéæä»¶}
+_textsearchhistory_ [l=zh-tr] {æ¥è©¢çŽé:}
+_textnohistory_ [l=zh-tr] {äžèŠæ¥è©¢çŽé}
+_texthistorydisplay_ [l=zh-tr] {ååº_historynumrecords_ æ¥è©¢çæ­·å²çŽé}
+_textnohistorydisplay_ [l=zh-tr] {äžèŠååºæ¥è©¢çæ­·å²çŽé}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=zh-tr] {è¡šæ Œæ¥è©¢:}
+_textplainsearch_ [l=zh-tr] {å®äžæ¥è©¢:}
+_textqueryboxsize_ [l=zh-tr] {æ¥è©¢èŒžå
+¥æ¡å€§å°:}
+_textregbox_ [l=zh-tr] {äžè¬æ¥è¯¢æ¡}
+_textbigbox_ [l=zh-tr] {å å€§å°ºå¯ž}
+_textformtype_ [l=zh-tr] {è¡šæ Œç±»åïŒ}
+_textsimple_ [l=zh-tr] {ç°¡å®}
+_textadvanced_ [l=zh-tr] {é²é}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=zh-tr] {è}
+_textfields_ [l=zh-tr] {é å}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "åå¥œèš­å®" ## green_title ## h_pref ##
+_httpiconhpref_ [l=zh-tr] {_httpimg_/zh-tr/h\_pref.gif}
+_widthhpref_ [l=zh-tr] {200}
+_heighthpref_ [l=zh-tr] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=zh-tr] {æä»¶æåºäŸ}
+_textalsoshowing_ [l=zh-tr] {äžèµ·é¡¯ç€º}
+_textwith_ [l=zh-tr] {æå€ä»¥}
+_textdocsperpage_ [l=zh-tr] {æä»¶äž­çæ¯äžé }
+
+_textfilterby_ [l=zh-tr] {ååŸæä»¶å
+§å®¹}
+_textall_ [l=zh-tr] {å
+šéš}
+_textany_ [l=zh-tr] {ä»»äœ}
+_textwords_ [l=zh-tr] {å±¬æŒäžæ®µè©±}
+_textleaveblank_ [l=zh-tr] {äžéžææ­€é 
+ç®å¯ä»¥åŸå°æææä»¶}
+
+_browsebuttontext_ [l=zh-tr] {"æä»¶æåº"}
+
+_nodata_ [l=zh-tr] {<i>æ²æè³æ</i>}
+_docs_ [l=zh-tr] {æä»¶}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=zh-tr] {å¹«å©}
+_textSearchshort_ [l=zh-tr] {æå°ç¹å®æå­}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=zh-tr] {ä»¥æšé¡çºçŽ¢åŒæ¥è©¢æä»¶}
+_textCreatorshort_ [l=zh-tr] {ä»¥äœè
+çºçŽ¢åŒæ¥è©¢æä»¶}
+_textSubjectshort_ [l=zh-tr] {ä»¥äž»é¡çºçŽ¢åŒæ¥è©¢æä»¶}
+_textDescriptionshort_ [l=zh-tr] {ä»¥æè¿°çºçŽ¢åŒæ¥è©¢æä»¶}
+_textPublishershort_ [l=zh-tr] {ä»¥åºçè
+çºçŽ¢åŒæ¥è©¢æä»¶}
+_textContributorshort_ [l=zh-tr] {ä»¥è²¢ç»è
+çºçŽ¢åŒæ¥è©¢æä»¶}
+_textDateshort_ [l=zh-tr] {ä»¥æ¥æçºçŽ¢åŒæ¥è©¢æä»¶}
+_textTypeshort_ [l=zh-tr] {ä»¥é¡å¥çºçŽ¢åŒæ¥è©¢æä»¶}
+_textFormatshort_ [l=zh-tr] {ä»¥æ ŒåŒçºçŽ¢åŒæ¥è©¢æä»¶}
+_textIdentifiershort_ [l=zh-tr] {ä»¥ç¢ºèªè
+åèœæåæ¥é
+æä»¶}
+_textSourceshort_ [l=zh-tr] {ä»¥æªæ¡åçš±çºçŽ¢åŒæ¥è©¢æä»¶}
+_textLanguageshort_ [l=zh-tr] {ä»¥èªèšçºçŽ¢åŒæ¥è©¢æä»¶}
+_textRelationshort_ [l=zh-tr] {ä»¥éä¿çºçŽ¢åŒæ¥è©¢æä»¶}
+_textCoverageshort_ [l=zh-tr] {ä»¥ç¯åçºçŽ¢åŒæ¥è©¢æä»¶}
+_textRightsshort_ [l=zh-tr] {ä»¥æ¬å©çºçŽ¢åŒæ¥è©¢æä»¶}
+
+_textSeriesshort_ [l=zh-tr] {ä»¥éå¢åçºçŽ¢åŒæ¥è©¢æä»¶}
+_textToshort_ [l=zh-tr] {ä»¥toçºçŽ¢åŒæ¥è©¢æä»¶}
+_textFromshort_ [l=zh-tr] {ä»¥Fromæ¬äœçºçŽ¢åŒæ¥è©¢æä»¶}
+_textBrowseshort_ [l=zh-tr] {çèŠœæä»¶}
+_textOrganizationshort_ [l=zh-tr] {ä»¥çµç¹çºçŽ¢åŒæ¥è©¢æä»¶}
+_textHowtoshort_ [l=zh-tr] {ä»¥âåŠäœ..âåèœæåæ¥é
+æä»¶}
+_textTopicshort_ [l=zh-tr] {ä»¥äž»æšçºçŽ¢åŒæ¥è©¢æä»¶}
+_textPeopleshort_ [l=zh-tr] {ä»¥PeopleçºçŽ¢åŒæ¥è©¢æä»¶}
+_textAcronymshort_ [l=zh-tr] {ä»¥çž®å¯«å­æ¯åŠåºçŸäŸæ¥è©¢æä»¶}
+_textPhraseshort_ [l=zh-tr] {ä»¥çèªçºçŽ¢åŒæ¥è©¢æä»¶}
+_textArtistshort_ [l=zh-tr] {ä»¥èè¡å®¶çºçŽ¢åŒæ¥è©¢æä»¶}
+_textKeywordshort_ [l=zh-tr] {ä»¥ééµå­çºçŽ¢åŒæ¥è©¢æä»¶}
+_textVolumeshort_ [l=zh-tr] {ä»¥å¢æžçºçŽ¢åŒæ¥è©¢æä»¶}
+_textCountriesshort_ [l=zh-tr] {ä»¥åå®¶çºçŽ¢åŒæ¥è©¢æä»¶}
+_textdefaultshorttext_ [l=zh-tr] {æªå®çŸ©çåé¡}
+
+_textSearchlong_ [l=zh-tr] {<p>äœ å¯ä»¥ <i>ä»¥ç¹å®çè©èªæå°</i>èéäºæå­å°æåšæå°çæä»¶äž­åçŸãæšå¯ä»¥åš"æ¥è©¢"é é¢å
+§çäŸç¹å®è©èªæ¥è©¢ãæ­€é æ¯éå§çç¬¬äžé ïŒæšä¹å¯ä»¥åšå
+¶å®é ææ¥è©¢éµåå°æ¥è©¢é ã}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥æšé¡çºçŽ¢åŒæ¥è©¢æä»¶</i> 
+èç±æäž <i>æšé¡a-z</i>æéãå°æžæ¬ä»¥æšé¡ä¹è±æå­æ¯é åºååºã}
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥äœè
+çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>äœè
+ a-z</i>æéãååºä»¥äœè
+æåºçæä»¶æž
+å®ã }
+
+_textSubjectlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥äž»é¡çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>äž»é¡</i>æéãäžåäž»é¡ä¹æä»¶å°æè¢«æ­žé¡åšäžåæžæ«å
+§ã}
+
+_textDescriptionlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥æè¿°çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>æè¿°</i> æéãååºä»¥æè¿°äŸåé¡çææç®éã }
+
+_textPublisherlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥åºçè
+çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>åºçè
+</i>æéãååºä»¥åºçè
+äŸåé¡çç®éã}
+
+_textContributorlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥è²¢ç»è
+çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>è²¢ç»è
+</i>æéãååºè²¢ç»è
+ç®éã}
+
+_textDatelong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥æ¥æçºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>æ¥æ</i> æéãååºä»¥å¹Žä»£äŸåé¡çææç®éã }
+
+_textTypelong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥é¡å¥çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>é¡å¥</i> æéãååºé¡å¥ä»¥äŸçèŠœã}
+
+_textFormatlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥æ ŒåŒçºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>æ ŒåŒ</i> æéãååºä»¥æ ŒåŒäŸåé¡çææç®éã }
+
+_textIdentifierlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥ç¢ºèªè
+çºçŽ¢åŒæ¥è©¢æä»¶</i>
+èç±æäž<i>ç¢ºèªè
+</i>æéãååºä»¥ç¢ºèªè
+æåºçæä»¶æž
+å®ã 
+}
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥æªæ¡åçš±çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>æªå</i>æéãååºä»¥æªæ¡åçš±æåºçç®éã}
+
+_textLanguagelong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥èªèšçºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>èªèš</i>æéãååºä»¥èªèšåé¡çç®éã}
+
+_textRelationlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥éä¿çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>éä¿</i>æéãååºä»¥éä¿äŸåé¡çç®éã}
+
+_textCoveragelong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥ç¯åçºçŽ¢åŒæ¥è©¢æä»¶</i> bèç±æäž<i>ç¯å</i>æéãååºç¯åç®éã}
+
+_textRightslong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥æ¬å©çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>æ¬å</i>æéãååºä»¥æ¬å©äŸåé¡çç®éã}
+
+
+
+_textOrganizationlong_ [l=zh-tr] {<p>äœ èœå€ <i>ä»¥çµç¹çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>çµç¹</i> æéãååºä»¥çµç¹æåºå°æä»¶æž
+å®ã}
+
+_textHowtolong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥âåŠäœ..âçºçŽ¢åŒæ¥è©¢æä»¶</i>
+èç±æäž<i>åŠäœ..</i>æéãååºä»¥âåŠäœ..âæåºçæä»¶æž
+å®ã 
+}
+
+_textTopiclong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥äž»æšçºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>äž»æš</i> æéãååºäž»æšä»¥äŸçèŠœã}
+
+_textTolong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥toçºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>to</i>æéã  ååºæ¶ä¿¡äººå°åæž
+å®ã}
+
+_textFromlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥Fromæ¬äœæ¥è©¢æä»¶</i>èç±æäž<i>From</i>æéãååºéåºäººæž
+å®ã }
+
+_textSerieslong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥éå¢åçºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>éå¢å</i>æéãååºäœæŒè³æåº«äž­ææçéå¢ååè¡šã }
+
+_textBrowselong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>çèŠœæä»¶</i>èç±æäž
+<i>çèŠœ</i>æéã}
+
+_textPeoplelong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥PeopleçºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>People a-z</i>æéãååºä»¥PeopleäŸåé¡çç®éã}
+
+_textAcronymlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥çž®å¯«å­æ¯åŠåºçŸäŸæ¥è©¢æä»¶</i>ïŒè«æ
+<i>çž®å¯«å­</i>æéãéæš£å°æååºçž®å¯«å­çåè¡šïŒäžŠæšç€ºä»ååºçŸçäœçœ®ã  }
+
+_textPhraselong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥çèªçºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>çèª</i>æéãéé 
+æäœäœ¿çšPhine phraseçèŠœåšã }
+
+_textArtistlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥èè¡å®¶çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>èè¡å®¶</i>æéãååºä»¥èè¡å®¶å§ååé¡çç®éã}
+
+_textKeywordlong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥ééµå­çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>ééµå­</i>æéãååºä»¥ééµå­åé¡çç®éã}
+
+_textVolumelong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥å¢æžçºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>å¢æž</i>æéãååºå¢æžç®éã}
+
+_textCaptionslong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥æšé¡çºçŽ¢åŒæ¥è©¢æä»¶</i>èç±æäž<i>æšé¡</i>æéãååºæšé¡ç®éã}
+
+_textCountrieslong_ [l=zh-tr] {<p>äœ å¯ä»¥<i>ä»¥åå®¶çºçŽ¢åŒæ¥è©¢æä»¶</i> bèç±æäž<i>åå®¶</i>æéãååºåå®¶ç®éã}
+
+
+_textdefaultlongtext_ [l=zh-tr] {<p>æäž <i>æªç¥</i> æé. ååºæªç¥é ååé¡ã}
+
+_texthelptopics_ [l=zh-tr] {<h2 align=left>ç®é</h2>
+
+
+<ul>
+ <li><a href="\#finding-information">_textsimplehelpheading_</a>
+ _topicreadingdocs_
+ <li><a href="\#searching">åŠäœå°æŸç¹å¥å­</a>
+<ul>
+ <li><a href="\#query-terms">æå°é 
+ç®</a>
+ <li><a href="\#query-type">æ¥è©¢é¡å</a>
+ <li><a href="\#scope-of-queries">æ¥è©¢ç¯å</a>
+</ul>
+ <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+ <li><a href="\#col-prefs">åå¥œçèé</a>
+ <li><a href="\#lang-prefs">èªèšåå¥œ</a>
+ <li><a href="\#pres-prefs">é¡¯ç€ºåå¥œ</a>
+ <li><a href="\#search-prefs">æå°åå¥œ</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=zh-tr] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=zh-tr] {åŠäœé±è®æä»¶}
+
+_texthelpreadingdocs_ [l=zh-tr] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>è®åæäžæä»¶æïŒééå°é¢æåçå°±ç¥éè¢å¹æ­£åšé¡¯ç€ºåªäžåæä»¶ãæäºéåçå°é¢æéæ¯ç®éè¡šïŒèæäºéåå
+å
+æ¬ç®åçé ç¢Œåå¯ä»¥éžæåé²åŸéçéžé 
+ãç®éè¡šæ¯å¯å±éçïŒæäžç®éè¡šå¯æéæééæä»¶ïŒæäžæéæä»¶çäžæ¹å¯ä»¥ééå®ã</p>
+
+<p>åšäžé¢æ¯ç®åéšåçæ¬æïŒç¶äœ å·²ç¶è®éæïŒåºéšæäžåç®­é ­å¯ä»¥è®äœ å°äžäžç« ç¯ææ¯åå°åäžç« ç¯ã</p>
+
+<p>åšæšé¡æå°é¢äžçæéïŒæäž
+<i>å±é</i> å±éæç« ææžæ¬å
+§å®¹. åŠææä»¶å€ªå€§å°æè±è²»èš±å€æéèèšæ¶é«! æäž <i>å±éå
+§å®¹</i>å°å±éæŽä»œç®éïŒäœ èœçèŠå
+šéšç« ç¯åæšé¡ãæäž<i>éåæ°èŠçª</i>ä»¥æ°èŠçªéåæä»¶ïŒ(ç¶äœ æ³æ¯èŒæåæè®å
+©ç¯æç« ïŒéååèœåŸæçšã) æåŸïŒç¶äœ æå°æïŒææå°çæå­æè¢«åçœæšç€ºïŒæäž <i>äžæšç€º</i> åæç§»é€æå­åçœæšç€ºã</p>
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>éåæžæ«</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>æé/éäžéæ¬æž</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>çéæ®µæå­çç« ç¯</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>ååºæäžååºæå­</td></tr>
+
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>å±éæäžå±éå
+§å®¹</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>ä»¥æ°èŠçªéåéäžé </td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>æšç€ºæäžæšç€ºæå°é 
+ç®</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>æäžç®­é ­å°äžäžç« ç¯ ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... æåå°åäžç« ç¯</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=zh-tr] {<h2>åŠäœæå°ç¹å®æç« </h2>
+<p>
+ åšæå°é é¢å¯ä»¥åç°¡å®çæ¥è©¢æ­¥é©:<p>
+ 
+ <ol><li>æå®èŠæå°çé 
+ç®
+     <li>æå°æŽæ®µéæ¯éšåæå­
+     <li>èŒžå
+¥æèŠæå°çæå­
+     <li>æäž <i>éå§æå°</i> æé
+ </ol>
+
+<p>ç¶æå°å®ææïŒæ¯é æé¡¯ç€º20ç­ç¬Šåçè³æïŒäœ å¯ä»¥ææéé¡¯ç€ºäž20ç­è³æ.æé¡¯ç€ºå20ç­è³æïŒææ¯ç­è³ææçæéïŒå¯ä»¥çèŠè³æçå
+§å®¹
+
+<p>æå€å¯ä»¥é¡¯ç€º100ç­è³æïŒäœ å¯ä»¥æ¹è®é¡¯ç€ºæžéç¶äœ æäžæäžæ¹
+ <i>åäººåå¥œ</i> çæéã<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Search terms</h3>
+
+<p>èŒžå
+¥çä»»äœè³æçš±çº"æª¢çŽ¢é 
+ç®." æ¯åæª¢çŽ¢é 
+ç®åªå¯æ¯å­æ¯ææ¯æžå­ïŒæª¢çŽ¢æ¢ä»¶ä¹éçšç©ºçœåéïŒæšé»ç¬Šèæè¢«èŠçºç©ºçœèè¢«å¿œç¥ïŒæä»¥äžå¯å°æå°æ¢ä»¶èš­çºæšé»ç¬Šè
+
+<p>æ¥è©¢çç¯äŸ<p>
+   <ul><kbd> Agro-forestry in the Pacific Islands. Systems for Sustainability(1993)</kbd></ul>
+     <p>åä»¥äžèŠçºçžå<p>
+     <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>æ¥è©¢é¡å</h3>
+
+<p>å
+©çš®äžåé¡åçæ¥è©¢ã
+
+<ul>
+ <li>æ¥è©¢ <b>èæ¥è©¢é 
+ç®å®å
+š</b> çžåïŒæ¥è©¢å°çè³æ(æè
+ 
+ç« æè
+æšé¡)å
+å«äœ å·²ç¶æå®çå
+šéšééµè©å°äŸå­æ¯æåºèååº
+ã<p>
+
+ <li>æ¥è©¢<b>èæ¥è©¢é 
+ç®éšå</b> çžåïŒå°æ¥è©¢å°çæä»¶ååºïŒäžŠäŸèæ¥è©¢é 
+ç®ççžäŒŒåºŠæåºã
+
+     <p><ul>
+       <li>æ¥è©¢é 
+ç®æå€æåŸå°çæå°çµææè¶æ¥è¿æèŠç;
+       <li> çšçšç¹çæ¥è©¢é 
+ç®ææ¯äžè¬çæ¥è©¢é 
+ç®æå°èŒäœ³;
+       <li> èŒç­çæ¥è©¢é 
+ç®ææ¯èŒé·çæ¥è©¢é 
+ç®æŽææŒç¬Šåæä»¶å
+§å®¹ã
+     </ul>
+</ul>
+
+<p>äœ¿çšå€äžé»æ¥è©¢é 
+ç®ïŒåæ¯æŽæ®µå¥å­ææç« ïŒåŠæäœ åªäœ¿çšäžåæ¥è©¢é 
+ç®ïŒæå°ççµæå°äŸæ¥è©¢é 
+ç®åšæä»¶äž­åºçŸçé »çæåºã<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=zh-tr] {æ¥è©¢æå¯ä»¥åŠå€åå äžæéæ¢ä»¶}
+
+_texthelpdatesearch_ [l=zh-tr] {<h2>_textdatesearch_</h2>
+äŸæ¥ææå°å¯ä»¥æŸåºç¬Šåæäžæéæ¢ä»¶çæä»¶ïŒå¯ä»¥åªèŒžå
+¥æéäŸæå°ïŒæéå¯ä»¥æ¯æç¢ºçæéé»ææ¯äžæ®µåéçæéã<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>åŠäœäœ¿çš:</h3>
+<ul>
+  <li>çšæç¢ºçæéæ¢ä»¶æå°:<p>
+  <ul>
+      <li>èŒžå
+¥æ¢ä»¶ã
+      <li>åš "éå§æé" æ¬èŒžå
+¥æéã
+      <li>åŠæäœ èŒžå
+¥çæéæ¯è¥¿å
+åååšéžå®äž­éžæ"B.C.E"éžé 
+ã
+      <li>éå§äŸæ¢ä»¶æå°ã
+  </ul>
+<p><li>å°æŸäžåæç¢ºæéæäžæ®µæéçè³æ:<p>
+  <ul>
+      <li>èŒžå
+¥æ¢ä»¶ã
+      <li>åš"éå§(å¯äž)æé"æ¬äœäž­èŒžå
+¥éå§æéã
+      <li>åš"çµææé"æ¬äœäž­èŒžå
+¥çµææéã
+      <li>åŠæäœ èŒžå
+¥çæéæ¯è¥¿å
+åååšéžå®äž­éžæ"B.C.E"éžé 
+ã
+      <li>éå§äŸæ¢ä»¶æå°ã   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>The way results of your search work</h3>
+åŠææå°1903å¹Žçæä»¶äžŠéæå°1903å¹Žå¯«çæä»¶èæ¯æå°è1903æéçæä»¶ïŒåŠæç¡æ³æå°å°æç¢ºæ¥æççžéæä»¶ïŒæèš±å¯ä»¥çšåéæå°ïŒäŸåŠ:1903å°±ä»æŒ20è21äžçŽçåéå
+§ã<p>
+}
+
+_textchangeprefs_ [l=zh-tr] {æŽæ¹åäººåå¥œ}
+
+_texthelppreferences_ [l=zh-tr] {<h2>_textchangeprefs_</h2>
+
+<p>ç¶äœ æäžåšé é¢æäžæ¹ç <i>åäººåå¥œ</i> æéïŒå¯ä»¥æ¹è®åå¥œèš­å®ã
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>è³æåº«åäººåå¥œèš­å®</h3>
+
+äžäºæä»¶éåå
+æ¬äžäºå­éåïŒéäºéåå¯åå¥æå°ææ¯äžèµ·æå°ïŒæä»¥å¯ä»¥åšåå¥œçæå°é é¢äž­éžææå°å­éåéžé 
+ã
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>èªèšåå¥œ</h3>
+æ¯åæ¶èéœæé èš­çèªèšïŒäœæ¯å¯ä»¥æ¹æåå¥œçèªèšã æšéå¯ä»¥æ¹è®Greenstoneè»é«çºèŒžåºå°çèŠœåšææ¡çšçé èš­çç·šç¢Œç³»çµ±é
+çœ®ïŒäœæ¯æäºçèŠœåšæå æ¡çšäžåçç·šç¢Œç³»çµ±é
+çœ®èç²åŸæŽå¥œçèŠèŠºææïŒæçšçæ¶èå
+èš±æšåŸæšæºçååœ¢çé¢èœå°æå­çé¢ïŒéé»å°æŒæèŠèŠºéç€èäœ¿çšå€§åå­é«æèªèšè­å¥åšççšæ¶ç¹å¥æçšã
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>æå°åå¥œèš­å®</h3>
+æ ¹æäžåçæä»¶éåçæå°ïŒå¯ä»¥èš­å®äžåçæå°åå¥œã
+
+<p>ç¶²é æ¶èå
+èš±åšæ¯åé éŠäžé¡¯ç€ºGreenstoneè»é«çå°èªåïŒéæš£æšå¯ä»¥çŽæ¥çèŠœæéåç¶²é ïŒäžæé¡¯ç€ºä»»äœGreenstoneè»é«çé éŠãæšå¯ä»¥çšçèŠœåšç"åå°äžäžé "æéé²è¡åŠå€çæ¥è©¢ãç¶æšæäžæåè¶
+é£çµèé¢éæžäœåæžé€šçæåïŒéäºè³æåº«éå¯å
+èš±æšäžé¡¯ç€ºGreenstoneè»é«çè­Šåèšæ¯ãåšæäºç¶²é è³æåº«äž­æšå¯ä»¥æ§å¶åš"æ¥è©¢çµæ"é æ¯åŠçŽæ¥é£æ¥å°å¯ŠéçURLïŒéæ¯æžäœåæžé€šçåä»œã
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>æå°çåå¥œ</h3>
+<p>æå
+©åæéå¯å°æå°çæå­æ¢ä»¶åèš­å®ïŒç¬¬äžåæ¯èš­å®æ¯åŠå¿œç¥å€§å°å¯«ïŒç¬¬äºåæ¯èš­å®æ¯åŠå¿œç¥æå­çµå°ŸïŒéçšæ®µèœæå°å°ææå¿«éçæå°å€§éæå­è³æã
+<p>äŸåŠïŒåŠææé <i>å¿œç¥å€§å°å¯«</i> å
+<i>å¿œç¥æå­çµå°Ÿ</i> åšæéžæçæ¢ä»¶<p>
+   <ul><kbd>African building</kbd></ul>
+     <p>å°èŠçº<p>
+     <ul><kbd>africa builds</kbd></ul><p>
+å çºå€§å¯«å­"African"æè¢«èœçºå°å¯«ïŒå­å°Ÿ"n" å "ing"æåå¥åŸ"African" and "building"äž­ç§»é€ïŒ "s"ä¹æåŸ"builds"äž­ç§»é€ã
+     <p>äœ å¯ä»¥äœ¿æ¹çšé²éæ¥è©¢æš¡åŒïŒå¯äœ¿çšAND (&)ïŒ OR (|)ïŒ and NOT (!)æ¢ä»¶å­ïŒç¢çæŽç²Ÿç¢ºçæ¥è©¢ïŒä¹å¯ä»¥æ¥è©¢æŸç¶æ¥è©¢éçæ­·å²çŽéïŒå°æååºæè¿æ¥è©¢éçäžäºçŽéïŒäœ¿åŸæŽæ¹äŸ¿æ¹è®å
+åçæ¥è©¢æ¢ä»¶ïŒæåŸïŒäœ ä¹å¯ä»¥æ¹è®ç¬Šåè³æååºçç­æžèæ¯é ååºçç­æžã
+}
+
+_texttanumbrowseoptions_ [l=zh-tr] {çš _numbrowseoptions_ çš®æ¹åŒäŸæå°è³æåº«äž­çæä»¶è³æ:}
+
+_textsimplehelpheading_ [l=zh-tr] {åŠäœåš_collectionname_è³æåº«äž­æŸè³æ}
+
+_texthelpscope_ [l=zh-tr] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>æ¥è©¢çç¯å</h3>
+
+<p>
+åšå€§å€æžçæä»¶éåäž­å¯ä»¥çšäžåçæå°æ¢ä»¶æå°ïŒäŸåŠïŒå¯ä»¥çšäœè
+ææ¯æšé¡äŸæå°ïŒææ¯ä»¥ç« ç¯ææ®µèœäŸæå°ïŒäžè¬äŸèªªïŒäœ¿çšèŒçšç¹çæ¥è©¢æ¢ä»¶æææŸå°å®å
+šçžç¬Šçæä»¶ã
+<p>åŠææä»¶æ¯äžæ¬æžïŒåå°æåšå°æžæ¬éåšåé©çé æžã
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/chinese-trad2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/chinese-trad2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/chinese-trad2.dm	(revision 10506)
@@ -0,0 +1,1351 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Traditional Chinese Language text and icon macros 
+# -- this file contains text that is of less importance
+# -- to translate when creating a new interface language
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=zh-tr] {æä»¶ã}
+_lastupdate_ [l=zh-tr] {æåŸæŽæ°}
+_ago_ [l=zh-tr] {å€©åã}
+_colnotbuilt_ [l=zh-tr] {æ¬²å»ºç«çè³æåº«ã}
+
+_textpagetitle_ [l=zh-tr] {Greenstone æžäœåæžé€š}
+_textadmin_ [l=zh-tr] {ç®¡çé é¢}
+_textabgs_ [l=zh-tr] {éæŒGreenstone}
+_textgsdocs_ [l=zh-tr] {Greenstone æä»¶}
+
+_textimagegli_ [l=zh-tr] {åå©äœ å»ºç«æ°çè³æåº«ïŒå°å·²æçè³æåº«åä¿®æ¹æ°å¢æä»¶ïŒæåªé€è³æåº«ã}
+
+_textimagecollector_ [l=zh-tr] {è³æåº«å
+žèä»é¢èŒæ©æŒåæžé€šå¡ä»é¢çŒå±ïŒåæçºäºå€§éšåå¯Šéçç®çïŒç¶­è­·è³æåº«å»ºè­°ééåæžé€šå¡ä»é¢ã}
+
+_textimagetranslator_ [l=zh-tr] {åå©äœ ç¶­æææ°çGreenstonå€èªèšçæ¬ã}
+
+_textimageadmin_ [l=zh-tr] {å
+èš±äœ æ°å¢æ°çäœ¿çšè
+ïŒåœæŽç³»çµ±è£¡çè³æåº«å
+žèè³èšïŒæäŸGreenstoneå®è£çæè¡è³èšã}
+
+_textimagegogreenstone_ [l=zh-tr] {åèšŽäœ æéGreenstoneè»é«åçŽè¥¿è­æžäœåæžé€šèšç«çæ²¿é©ã}
+
+_textimagegodocs_ [l=zh-tr] {Greenstone æå}
+
+_textpoem_ [l=zh-tr] {<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,  
+<br>kia tere te karohirohi, 
+<br>kia papapounamu te moana 
+
+<p>may peace and calmness surround you,  
+<br>may you reside in the warmth of a summer's haze,  
+<br>may the ocean of your travels be as smooth as the polished greenstone. 
+}
+
+_textgreenstone_ [l=zh-tr] {<p>Greenstoneæ¯äžçš®ç¢æŒçŽè¥¿è­çç¶ å¯¶ç³(å°±åéå¥è»é«)ãåšå³çµ±çæ¯å©ç€ŸæïŒå®
+æ¯åšææç©è³ªäž­æçè²Žååæ­¡è¿çãå®å¯ä»¥åžæ¶åä¿æ<i>wairua</i>ïŒäžçš®é­é­æçåœå, äžè³Šæå³çµ±çŸåŸ·çç¹æ§äœ¿å®æçºå
+¬å
+±é åæžäœåæžé€šèšç«çåŸœç« ïŒå®çå
+åœ©
+ä»£è¡šæ
+æïŒå®çééä»£è¡šèª å¯ŠïŒå®çå 
+ç¡¬ä»£è¡šåæ°£ïŒå®æèœæ¿åçå©åä»£è¡šæ­£
+çŸ©ã Greenstoneæžäœåæžé€šè»é«æšèªäž­éå»ç<i>patu</i>ææææ£æ¯æåæ­€èšç«äž­æ
+æå¡çå³å®¶å¯¶ãåšåŸææ°åœ¹äž­å®çè¡šçŸæ¯éåžžå¿«éãæ­£ç¢ºåå®å
+šçãæååžæ
+æåçè»é«ä¹æéäºç¹è³ªïŒ<i>patu</i>éå©çéç·£è±¡åŸµèç§æçåç·£ã
+}
+
+_textaboutgreenstone_ [l=zh-tr] {<p> Greenstoneæ¯å»ºç«åå³äœæžäœåæžé€šå
+žèçè»é«çšåŒïŒå®
+æäŸäºäžåæŽç·šè³èšäžçŒè¡šæŒç¶²è·¯æCD-ROMçæ°æ¹æ³ãGreenstoneæ¯<b>Waikato
+å€§å­ž</b>è<b>çŽè¥¿è­æžäœåæžé€šèšç«å°çµ</b>å»ºæ§ïŒåæå<b>UNESCO</b>å<b>Human Info NGO</b>æåäœçŒå±åå³äœãå®æ¯open-sourceçè»é«ïŒåš<a herf="http://greenstone.org">http://greenstone.org</a> äžéµå
+¥æ¢ä»¶
+GNU General Public LicenseïŒ å³å¯ç²åŸäŸèªhttp://greenstone.org under the terms of 
+the GNUäžè¬æ§å
+¬éææ¬ã 
+
+
+<p>æ­€è»é«çç®çæ¯èŠè®äœ¿çšè
+ïŒå°€å
+¶æ¯åšå€§å­žã åæžé€šãåå
+¶ä»å
+¬å
+±æåæ©æ§è£¡
+çäœ¿çšè
+ïŒå»å»ºæ§å±¬æŒä»åèªå·±çæžäœåæžé€šïŒæžäœåæžé€šæ­£è¢«åŸ¹åºå°æ¹è¯åŠ
+äœè®äžçåå°å°€å
+¶æ¯éçŒäž­åå®¶åèUNESCOåäœçæç§æé åçç€Ÿåèæ©æ§
+æ£æ­åçŽ¢æ±è³èšïŒæååææ­€è»é«èœæ¿åµæžäœåæžé€šææçéçŒïŒä»¥åäº«è³èšäžŠ
+å°å
+¶æŸçœ®åšå
+¬å
+±ç¶²åã 
+
+
+<p>æ­€è»é«æ¯ç±ä»¥äžäžæ¹é¢æŒ2000å¹Ž8æåéå
+±ååäœéçŒç: 
+
+<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>
+<p> Greenstoneè»é«ç¶ç±æ­€èšç«èªç,äžŠç±unescoçŽè¥¿è­åå®¶å§å¡æç¶²è·¯å­å§å¡æèæžïŒåçºçŽè¥¿è­å°UNESCOèšåçè²¢ç»ã
+
+</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>
+å
+šçæç§æè³èšçå³æ­ïŒå°€å
+¶æ¯å°éçŒäž­åå®¶çå©çïŒ æ¯UNESCOåšå
+æ¿åºéè¿œæ±çäž­å¿ç®æšãèåšæ­€è­°é¡äž,é©åå¯åŸçå³æ­ç§æå·¥å
+·äºŠæ¯åç­
+éèŠã 
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/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>
+æ­€èšååè¯ååæ©æ§åå
+¶ä»éæ¿åºçµç¹åäœïŒåšæžäœåäººé¡çŒå±è­°é¡æä»¶äž
+å»ºç«äºäžçè²è­œïŒäžäœå°å
+šäººé¡ççŠç¥çŒå±å ä»¥æžäœåèšéïŒè³æå¯å»£æ³
+å°ååŸïŒåæéçŒäž­åå®¶äžçšè±äžåé¢ïŒèå
+¶ä»çåå®¶ä¹ç¯çäºç¶è²»ã 
+</td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "éžæå
+žèè³æåº«" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ [l=zh-tr] {_httpimg_/zh-tr/selcolgr.gif}
+_widthselcolgr_ [l=zh-tr] {537}
+_heightselcolgr_ [l=zh-tr] {17}
+_altselcolgr_ [l=zh-tr] {"Select a collection"}
+
+
+## "åæžé€šå¡ç®¡çä»é¢" ## home_page_button ## cgli ##
+_httpiconcgliof_ [l=zh-tr] {_httpimg_/zh-tr/cgliof.gif}
+_httpiconcglion_ [l=zh-tr] {_httpimg_/zh-tr/cglion.gif}
+_widthcgli_ [l=zh-tr] {100}
+
+## "å
+žèè³æåº«" ## home_page_button ## ccol ##
+_httpiconccolof_ [l=zh-tr] {_httpimg_/zh-tr/ccolof.gif}
+_httpiconccolon_ [l=zh-tr] {_httpimg_/zh-tr/ccolon.gif}
+_widthccol_ [l=zh-tr] {100}
+
+## "ç¿»è­¯è
+" ## home_page_button ## ctrans ##
+_httpiconctransof_ [l=zh-tr] {_httpimg_/zh-tr/ctransof.gif}
+_httpiconctranson_ [l=zh-tr] {_httpimg_/zh-tr/ctranson.gif}
+_widthctrans_ [l=zh-tr] {100}
+
+## "ç³»çµ±ç®¡çé é¢" ## home_page_button ## cadmin ##
+_httpiconcadminof_ [l=zh-tr] {_httpimg_/zh-tr/cadminof.gif}
+_httpiconcadminon_ [l=zh-tr] {_httpimg_/zh-tr/cadminon.gif}
+_widthcadmin_ [l=zh-tr] {100}
+
+## "éæŒ\nGreenstone" ## home_page_button ## cabgs ##
+_httpiconcabgsof_ [l=zh-tr] {_httpimg_/zh-tr/cabgsof.gif}
+_httpiconcabgson_ [l=zh-tr] {_httpimg_/zh-tr/cabgson.gif}
+_widthcabgs_ [l=zh-tr] {100}
+
+## "Greenstone\nç³»çµ±æä»¶" ## home_page_button ## cgsdoc ##
+_httpiconcgsdocof_ [l=zh-tr] {_httpimg_/zh-tr/cgsdocof.gif}
+_httpiconcgsdocon_ [l=zh-tr] {_httpimg_/zh-tr/cgsdocon.gif}
+_widthcgsdoc_ [l=zh-tr] {100}
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=zh-tr] {åšéŠé æååäžäžæ­¥æé}
+
+_textnocollections_ [l=zh-tr] {<p>ç®ååšGreenstoneå
+§ç¡ä»»äœå
+žèè³æåº«ïŒæ¬²å å
+¥å
+žèè³æåº«å¯çšäžåä»»äžæ¹æ³ïŒ 
+<ul><li>â¢	äœ¿çš<a href="_httppagecollector_">è³æåº«å
+žèä»é¢</a>äŸå»ºç«æ°çå
+žèã
+<li>â¢	åŠææšæGreenston cd-romïŒå¯åŸ cd-romäŸå®è£å
+žèã</ul> 
+}
+
+_text1coll_ [l=zh-tr] {Greenstonå®è£å
+å«äžé 
+å
+žè}
+
+_textmorecolls_ [l=zh-tr] {Greenstonå®è£å
+å«äžé 
+å
+žè}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=zh-tr] {å€éšé£çµ}
+_textlinknotfound_ [l=zh-tr] {æªçŒçŸå
+§éšé£çµ}
+
+_textextlinkcontent_ [l=zh-tr] {äœ æéžæçåçºç®åæéžå
+žèè³æåº«çå€éšé£çµã
+åŠæäœ ä»ç¶åžæé¡¯ç€ºæ­€é£çµèäžäœ ççèŠœåšä»¥é²å
+¥æ­€ç¶²
+ç«ïŒäœ å¯ä»¥âåé²âå°æ­€é é¢ ïŒ 
+åŠåäœ¿çšçèŠœåšç<a href="_nexturl_">âåäžé â</a>éµïŒåå°å
+åçé é¢
+}
+
+_textlinknotfoundcontent_ [l=zh-tr] {ç±æŒè¶
+éå¯æ§å¶ç¯åä¹æ
+ïŒäœ æéžæçå
+§éšé£çµäžŠäž
+å­åšïŒéå¯èœæ¯ç±æŒäŸæºæä»¶çé¯èª€ïŒäœ å¯äœ¿çšçèŠœåšçâåäžé âéµïŒåå°å
+
+åçé é¢ã}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=zh-tr] {<h3>é£å° "_2_" å
+žèè³æåº«</h3>
+
+<p> äœ æéžæçé£çµçº "_collectionname_" å
+žèè³æåº«çå€éšé£çµïŒ
+    ä»å°æè¢«é£å° "_2_" å
+žèè³æåº«ã
+     åŠæäœ éèŠæª¢èŠäœæŒ "_2_" å
+žèè³æåº«çé£çµïŒäœ å¯ä»¥æäž
+    <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">ååŸ</a> é£çµå°è©²é ; 
+    ææ¯äœ¿çšçèŠœåšç "åå°äžäžé " æéåå°åäžé ã
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=zh-tr] {Greenstone æžäœåæžé€š}
+
+_textusername_ [l=zh-tr] {äœ¿çšè
+åçš±}
+_textpassword_ [l=zh-tr] {å¯ç¢Œ}
+
+_textmustbelongtogroup_ [l=zh-tr] {æ³šæïŒäœ å¿
+é å±¬æŒ "_cgiargug_" éåçŸ€çµæèœçå°æ­€é }
+
+_textmessageinvalid_ [l=zh-tr] {äœ æè«æ±é²å
+¥çé é¢éèŠç»å
+¥ïŒ<br>
+_If_(_cgiargug_,[è«æ³šæäœ å¿
+é å±¬æŒ "_cgiargug_" çŸ€çµæèœé²å
+¥æ­€ç¶²é ] <br>)
+è«èŒžå
+¥äœ ç Greenstone äœ¿çšè
+åçš±åå¯ç¢ŒïŒ}
+
+_textmessagefailed_ [l=zh-tr] {äœ¿çšè
+åçš±æå¯ç¢Œé¯èª€ïŒ}
+
+_textmessagedisabled_ [l=zh-tr] {æ±æ­ïŒäœ çåž³èç¡æïŒè«èæ¬ç«çç¶²ç«ç®¡çå¡é£çµ¡ã}
+
+_textmessagepermissiondenied_ [l=zh-tr] {æ±æ­ïŒäœ æ²ææ¬éé²å
+¥æ­€ç¶²é ïŒ}
+
+_textmessagestalekey_ [l=zh-tr] {é£çµå€±æïŒè«èŒžå
+¥äœ çå¯ç¢Œä»¥é²å
+¥æ­€ç¶²é }
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=zh-tr] {<p>Greenstoneå®è£æ²æå
+å«ä»»äœæä»¶ä¹å¯èœåå çºïŒ 
+<ol>
+<li>1.	äœ¿çšGreenstone CD-ROM çç°¡æå®è£ã
+<li>2.	åŸinternetäœ¿çšGreenstone äžèŒå®è£ã
+</ol>
+ä»¥äžå
+©çš®æ¹åŒå¯ä»¥ç²åŸæä»¶ïŒåŸ Greenstone CD-ROMç<i>docs</i>ç®éæå° 
+ <a href="http://www.greenstone.org">http://www.greenstone.org</a>
+}
+
+_textuserguide_ [l=zh-tr] {äœ¿çšè
+æå}
+_textinstallerguide_ [l=zh-tr] {å®è£è
+æå}
+_textdeveloperguide_ [l=zh-tr] {éçŒè
+æå}
+_textpaperguide_ [l=zh-tr] {åŸçŽæ¬å°å
+žè}
+_textorganizerguide_ [l=zh-tr] {äœ¿çšOrganizer}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Greenstone ç³»çµ±æä»¶ã" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=zh-tr] {_httpimg_/zh-tr/gsdocsgr.gif}
+_widthgsdocsgr_ [l=zh-tr] {_pagewidth_}
+_heightgsdocsgr_ [l=zh-tr] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ [l=zh-tr] {é èš­æ¶æ§}
+_textmore_ [l=zh-tr] {æŽå€}
+_textcollector_ [l=zh-tr] {è³æåº«å
+žèä»é¢}
+_textinfo_ [l=zh-tr] {è³æåº«å
+žèè³èš}
+_textsrce_ [l=zh-tr] {äŸæºè³æ}
+_textconf_ [l=zh-tr] {èš­å®å
+žèè³æåº«}
+_textbild_ [l=zh-tr] {å»ºç«}
+_textview_ [l=zh-tr] {æª¢èŠ}
+_textdel_ [l=zh-tr] {åªé€å
+žèè³æåº«}
+_textexpt_ [l=zh-tr] {å¯åºå
+žèè³æåº«âŠ}
+
+_textdownloadingfiles_ [l=zh-tr] {äžèŒæªæ¡âŠ}
+_textimportingcollection_ [l=zh-tr] {å¯å
+¥å
+žèè³æåº«âŠ}
+_textbuildingcollection_ [l=zh-tr] {å»ºç«å
+žèè³æåº«âŠ}
+_textcreatingcollection_ [l=zh-tr] {å»ºç«å
+žèè³æåº«âŠ}
+
+_textcollectorblurb_ [l=zh-tr] {<i>ç­éæŒåïŒ
+<br>å»ºç«åå³éæä»¶å
+žèéåž¶èäœ å¿
+é åšäžéå§åå³é æ·±æçè²¬ä»»ïŒå­åšæŒè€è£œç
+æ³åŸåé¡: å¯ä»¥åçšæä»¶äžŠäžè¡šç€ºäœ äžå®å¯ä»¥å³éçµŠä»äººïŒå­åšæŒç€Ÿæäžçç­è­°: 
+ææçæä»¶å¿
+é å°éå®äŸæºèçå°æ¹é¢šä¿ïŒåæä¹å­åšéåŸ·çåé¡ : æäºäºäžæ
+èŒæå°è®å¥äººå¯ä»¥å©çšïŒ
+<br>å°è³èšçåœ±é¿åå¿
+é æé³ïŒåæææºæ
+§å°äœ¿çšå®ã
+</i>
+}
+
+_textcb1_ [l=zh-tr] {è³æåº«å
+žèä»é¢å¯åå©äœ å»ºç«æ°çå
+žèè³æåº«ïŒæŽæ°åå¢å çŸå­çå
+žèè³æåº«ïŒæåªé€å
+žèè³æåº«ïŒèŠåå°åè¿°çåèœïŒå¯äŸåŸªç¶²é è³èšçæåŒã
+}
+
+_textcb2_ [l=zh-tr] {éŠå
+, äœ å¿
+é æ±ºå®æ¯åŠ}
+_textcnc_ [l=zh-tr] {å»ºç«æ°çå
+žèè³æåº«}
+_textwec_ [l=zh-tr] {æŒå·²å­åšçå
+žèè³æåº«äž­æ°å¢æåªé€è³æ}
+
+_textcb3_ [l=zh-tr] {äœ å¿
+é ç°œçœ²ä»¥äŸ¿å»ºç«
+ææŽæ°æžäœåæžé€šå
+žèïŒæ­€èå¯ä»¥ä¿è­·äœ äŸèªå
+¶å®å°æ¹ç»å
+¥äœ çé»è
+ŠäžŠæ¹è®è³
+èšçè¡çºãæ³šæïŒåºæŒå®å
+šçç±ïŒæ¯30åéæééåŸïŒäœ å°è¢«èªåç»åºïŒåŠæ
+çŒçæ­€çæ³ïŒå¥æå¿ïŒ è«åç»å
+¥ïŒåæå¯ä»¥åŸå
+åé¢éä¹èç¹Œçºå·è¡ã
+}
+
+_textcb4_ [l=zh-tr] {è«èŒžå
+¥äœ åšGreenston çäœ¿çšè
+åçš±åå¯ç¢ŒäžŠé»éžæéµäœ¿ç»å
+¥ã}
+
+_textfsc_ [l=zh-tr] {éŠå
+éžæå·è¡å
+åéžéçå
+žèè³æåº« (é²æ­¢å¯«å
+¥çå
+žèè³æåº«äžæé¡¯ç€ºåšæ­€ç®éäž) }
+
+_textwtc_ [l=zh-tr] {æŒäœ å·²éžæçå
+žèè³æåº«äž­ïŒäœ å¯ä»¥
+}
+_textamd_ [l=zh-tr] {å¢å æŽå€æä»¶åéå»ºå
+žèè³æåº«}
+_textetc_ [l=zh-tr] {ç·šèŒ¯å
+žèè³æåº«çµæ§æªæ¡äžŠéå»ºè³æåº«}
+_textdtc_ [l=zh-tr] {å®å
+šåªé€å
+žèè³æåº«}
+_textetcfcd_ [l=zh-tr] {å¯åºå
+žèè³æåº«ïŒå¯«å
+¥å°self-installing Windows CD-ROM}
+_textcaec_ [l=zh-tr] {æŽæ¹å·²å­åšçå
+žèè³æåº«}
+_textnwec_ [l=zh-tr] {æ²æå¯å¯«å
+¥çè³æåº«å
+žèå¯æ¿äŸä¿®æ¹}
+_textcianc_ [l=zh-tr] {å»ºç«æ°çå
+žèè³æåº«}
+_texttsosn_ [l=zh-tr] {å»ºç«æ°çæžäœåæžé€š
+å
+žèè³æåº«æéçæ­¥é©é åºïŒ}
+_textsin_ [l=zh-tr] {æå®åçš± (åçžéè³èš)}
+_textswts_ [l=zh-tr] {æå®äŸæºè³ææçä»¶è·¯åŸæç¶²å}
+_textatco_ [l=zh-tr] {èª¿æŽè³æåº«èš­å®æª (é²éäœ¿çšè
+)}
+_textbtc_ [l=zh-tr] {"å»ºç«"å
+žèè³æåº« (åŠ
+äž)}
+_textpvyh_ [l=zh-tr] {æª¢èŠææ}
+
+_texttfsiw_ [l=zh-tr] {ç¬¬ååæ­¥é©æ¯ééé»è
+Šå·è¡ææå·¥äœïŒåš "å»ºç«è³æåº«"çéçšäž­ïŒé»è
+Šå»ºç«æææä»¶ççŽ¢åŒäžŠæ¶éä»»äœå»ºç«ææéèŠçè³èšå°ãäœéŠå
+äœ å¿
+é æç¢ºæåºæä»¶è³èšã
+}
+
+_textadab_ [l=zh-tr] {åå»ºç«çéçšäž­äžæ¹çåç€ºååºçŸå°åå©äœ è¿œè¹€
+ç®åçæåšäœçœ®ïŒäœ å¿
+é é»éžç¶ è²çéµä»¥ç¹Œçº.ïŒå®ææïŒæ­€éµæè®æé»è²ïŒé»
+éžåç€ºäž­çžæçé»è²éµäœ å¯ä»¥åå°äžäžé ã
+}
+
+_textwyar_ [l=zh-tr] {ç¶æºåå®æåŸïŒé»éžâå
+žèè³æåº«è³èšâæéå¯ä»¥éå§å»ºç«äœ çæ°æžäœåæžé€šå
+žèè³æåº«! }
+
+_textcnmbs_ [l=zh-tr] {ç¢ºç«å
+žèè³æåº«åçš±}
+_texteambs_ [l=zh-tr] {ç¢ºç«é»å­éµä»¶å°å}
+_textpsea_ [l=zh-tr] {è«ç¢ºç«æ­€è¡šäž­é»å­éµä»¶å°åïŒäœ¿çšè
+åçš±@ç¶²å }
+_textdocmbs_ [l=zh-tr] {ç¢ºç«å
+žèè³æåº«çæè¿°}
+
+_textwcanc_ [l=zh-tr] {ç¶å»ºç«äžæ°çå
+žèè³æåº«äœ éèŠèŒžå
+¥äžäºæéäŸæºè³æçå
+æ±ºè³èšïŒæ­€æ­¥é©æ¯ç±äžç³»åç¶²é å»ºæ§æçïŒç±æ¶èè
+ç£çé é¢äžæ¹çæ©«åé¡¯ç€ºæéå®æé æžçé åºã
+}
+
+_texttfc_ [l=zh-tr] {å
+žèè³æåº«åçš±:}
+
+_texttctiasp_ [l=zh-tr] {å
+žèå
+žèè³æåº«åçš±æ¯äžç°¡ç­çèªïŒåšæžäœåæžé€šäž­çšäŸåèŸšå
+žèå
+§å®¹çïŒ
+äŸåŠâé»è
+Šæè¡å ±åâåâäººé¡çŒå±åæžé€šâ
+}
+
+_textcea_ [l=zh-tr] {é»å­éµä»¶è¯çµ¡å°åïŒ }
+
+_textteas_ [l=zh-tr] {æ­€é»å­éµä»¶å°åçºçç¬¬äžéè¯çµ¡çªå£ïŒè¥Greenstoneè»é«è¥åµæž¬å°
+åé¡ïŒèšºæ·å ±åæéå°æ­€å°åïŒèŒžå
+¥å®æŽçé»å­éµä»¶å°å:<tt>åçš±@ç¶²å</tt>. 
+}
+
+_textatc_ [l=zh-tr] {éæŒéåå
+žèè³æåº«:}
+
+_texttiasd_ [l=zh-tr] {çºæè¿°æ­€å
+žèè³æåº«çå®æšïŒç¶é²å
+¥å
+žèè³æåº«æïŒå®æ¯ç¬¬äžåè¢«é¡¯ç€ºåºäŸçç«é¢ã 
+}
+
+_textypits_ [l=zh-tr] {äžæ¹çç®­é ­è¡šç€ºäœ æåšçé åº--åšç®åçæ
+æ³äžæ¯âå
+žèè³æåº«è³èšâéæ®µïŒæç¶ è²çâäŸæºè³æâéµå³å¯ç¹Œçº.. 
+}
+
+_srcebadsources_ [l=zh-tr] {<p>äžåæå€åèŒžå
+¥ä¹äŸæºè³ææä»¶ç¡æ³è¢«åèå° (æšç€º _iconcross_ åŠäž) :
+
+<p>å¯èœé æçåå  
+<ul>
+<li>â¢	æªæ¡è·¯åŸ, FTPç«æç¶²åäžå­åšã
+<li>â¢	ç¢ºèªé»è
+Šç¶²è·¯éèšæ¯åŠæ­£åžžã
+<li>â¢	äœ èŠæ±åç
+§çç¶²è·¯æä»¶éééåž³èå¯ç¢Œæèœå€ å­åã
+</ul>
+
+<p>éç¶è©²ç¶²åäžçæä»¶å¯ä»¥åšäœ ççèŠœåšäžçå°ïŒäœå®æå¯èœåªæ¯äœ é»è
+Šå
+§çæ«å­æªïŒåŸäžå¹žçæ¬å°ç«¯æ«å­æªå°ç¡æ³åšè³æåº«å»ºç«çéçšäž­è¢«åç
+§å°ïŒåšéçš®æ
+æ³äžæåå»ºè­°å
+å°è©²æä»¶äžèŒå°æ¬å°ç«¯å²å­åŸïŒåé²è¡è³æåº«çå»ºç«ã
+}
+
+_textymbyco_ [l=zh-tr] {<p>äœ çå
+žèè³æåº«å¯ä»¥å»ºç«åšä»¥äžä»»äžçš®åºç€äž 
+<ul>
+<li>â¢	åå§æ¶æ§ 
+<dl><dd>æ°çå
+žèå¯å
+å« htmlæª (.htm, .html)ïŒçŽæå­æª (.txt, .text)ïŒMS Word æª 
+(.doc)ïŒ PDF æª (.pdf) æ "m-box" æ ŒåŒé»å­éµä»¶æª (.mbx)ã<dd><dl>
+<li>â¢	å·²å­åšçå
+žè 
+<dl><dd>åšæ°æ¶èå
+§çæªæ¡å¿
+é åçŸææ¶èäžæš¡äžæš£ã<dd><dl>
+</ul>
+}
+
+_textbtco_ [l=zh-tr] {å
+žèè³æåº«åºç€}
+_textand_ [l=zh-tr] {å¢å æ°è³æ}
+_textad_ [l=zh-tr] {å¢å è³æïŒ}
+
+_texttftysb_ [l=zh-tr] {å¢å äžåæå®æªæ¡æŒå
+žèè³æåº«å
+§ïŒè«ç¢ºèªæªæ¡æªéèŠæå®ïŒåŠåå°æå
+©
+ä»œåæš£çæªæ¡ïŒè«äœ¿çšå®æŽçè·¯åŸåçš±äŸèŸšè­æªæ¡ïŒç¶²é èŠçšçšäžç¡äºçç¶²
+åã 
+}
+
+_textis_ [l=zh-tr] {èŒžå
+¥è³ææä»¶äŸæºïŒ}
+
+_textddd1_ [l=zh-tr] {<p>è¥äœ äœ¿çš file:// æ ftp:// äŸæå®äžåæªæ¡ïŒå³å¯äžèŒè©²æª.
+
+<p>è¥äœ äœ¿çš http://ååæ±ºæŒURLæ¯åŠåšäœ ççèŠœåšäžçµŠäœ äžåæ­£åžžçç¶²é ææªæ¡
+ç®éïŒè¥çºäžç¶²é ,åæäžèŒè©²ç¶²é âè¥å®(å)é£çµèš±å€ç¶²é åææç¶²é éœæè¢«äž
+èŒ.â å³URLäžåäžç¶²ç«å
+§çç¶²é éœæè¢«äžèŒã 
+
+<p>è¥äœ äœ¿çš file:// æftp:// äŸæå®äžæªæ¡å€Ÿæç®é,ææ¯http:// URLçµŠäºäœ æªæ¡ç®
+éïŒåæªæ¡å€Ÿåå®ä¹äžçå­æªæ¡å€Ÿéœæè¢«å
+å«åšå
+žèè³æåº«å
+§ã
+ 
+<p>é»éžâæŽå€è³ææä»¶äŸæºâéµå¯åŸå°æŽå€èŒžå
+¥æ¬äœã 
+}
+
+_textddd2_ [l=zh-tr] {<p>é»éžä»»äžç¶ éµïŒè¥äœ æ¯é²éäœ¿çšè
+äœ å¯ä»¥èª¿æŽå
+žèè³æåº«çµæ§æè
+çŽæ¥å°å»ºæ§éæ®µãèšåŸïŒåªèŠé»éžé»éµå°±å¯åå°åäžéæ®µã
+}
+
+_textconf1_ [l=zh-tr] {<p>å
+žèè³æåº«çå»ºæ§ååçŸéœæ¯ç±âçµæ§æªâæ§å¶ïŒé²éäœ¿çšè
+å¯æ¹è®å
+¶èš­å®ã 
+<center><p><b>è¥äœ äžæ¯é²éäœ¿çšè
+, è«çŽæ¥å°ç¶²é åºéš..</b></center> 
+<p>ä¿®æ¹äžåè³æå³å¯æŽæ¹çµæ§èš­å®ïŒè¥èŒžå
+¥é¯èª€åé»éžâååŸ©âéµåå°åèš­å®
+}
+
+_textreset_ [l=zh-tr] {åŸ©å}
+
+_textbild1_ [l=zh-tr] {çŸæ­£åšå»ºæ§å
+žè:éå¯èœéèŠäžäºæéïŒäžæ¹çå»ºæ§çæ
+åé¡¯ç€ºç®åé²åºŠã
+}
+
+_textbild2_ [l=zh-tr] {åæ­¢å»ºæ§ïŒé»éžéè£¡ïŒ  
+<br>äœ æ­£åšå·¥äœçå
+žèäžæååœ±é¿ã 
+}
+
+_textstopbuild_ [l=zh-tr] {åæ­¢å»ºæ§}
+
+_textbild3_ [l=zh-tr] {è¥äœ çåšéé (äžæ²ææâåæ­¢å»ºæ§âéµäŸåæ¶å»ºæ§éçš)åæç¹Œçºå»ºæ§å
+žèè³æåº«äžŠåšå®æåŸå®è£ã}
+
+_textbuildcancelled_ [l=zh-tr] {å»ºæ§å·²åæ¶}
+
+_textbildcancel1_ [l=zh-tr] {å»ºæ§å
+žèè³æåº«éçšå·²è¢«åæ¶ïŒäœ¿çšé»è²éµæŽæ¹å
+žèæéæ°éå§å»ºæ§çšåºã }
+
+_textbsupdate1_ [l=zh-tr] {äžç§éå
+§æŽæ°å»ºæ§çæ
+}
+_textbsupdate2_ [l=zh-tr] {æŽæ°å»ºæ§çæ
+åš}
+_textseconds_ [l=zh-tr] {ç§}
+_textbildsuc_ [l=zh-tr] {å
+žèè³æåº«å»ºæ§æå}
+
+_textviewbildsummary_ [l=zh-tr] {äœ å¯ä»¥<a href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>æª¢èŠå»ºæ§æèŠ</a>åŸå°æŽå€å»ºæ§çŽ°ç¯ã
+}
+
+_textfailmsg11_ [l=zh-tr] {å
+žèè³æåº«å
+§è¥ç¡äŸæºè³ææä»¶åç¡æ³è¢«å»ºæ§ïŒè«ç¢ºå®<i>äŸæºè³ææä»¶</i>é é¢æäœ æå®çäžåæäžåä»¥äžçç®éææªæ¡ïŒäžæ¯Greenstoneå¯ä»¥èççæªæ¡é¡åã 
+}
+
+_textfailmsg21_ [l=zh-tr] {ç¡æ³å»ºæ§å
+žèè³æåº«(import.plå€±æ).}
+_textblcont_ [l=zh-tr] {å»ºæ§æ¥èªå
+å«äžåè³èšïŒ}
+
+_texttryagain_ [l=zh-tr] {è«<a href="_httppagecollector_" target=_top>éæ°ååå
+žèè³æåº«ä»é¢</a>äžŠéè©Š
+}
+
+_textfailmsg31_ [l=zh-tr] {æ³å»ºæ§å
+žèè³æåº«(buildcol.plå€±æ)}
+_textfailmsg41_ [l=zh-tr] {æåå»ºæ§å
+žèè³æåº«äœç¡æ³å®è£}
+_textfailmsg71_ [l=zh-tr] {å»ºæ§å
+žèè³æåº«æçŒçç¡æ³é æçé¯èª€}
+_textretcoll_ [l=zh-tr] {åå°å
+žèè³æåº«ä»é¢}
+
+_textdelperm_ [l=zh-tr] {éšåæå
+šéš _cgiargbc1dirname_ å
+žèè³æåº«ç¡æ³åªé€ïŒå¯èœåå çºïŒ
+<ul> 
+<li>â¢	Greenstone ç¡åªé€_gsdlhome_/collect/_cgiargbc1dirname_ ç®éçèš±å¯ã 
+äœ éèŠäººå·¥ç§»é€_cgiargbc1dirname_å
+žèè³æåº«ã</li>
+<li>â¢	Greenstone ç¡æ³å·è¡_gsdlhome_/bin/script/delcol.plçšåŒïŒè«ç¢ºå®æ­€æªæ¡å¯
+è®å¯«åå·è¡ã</li>
+</ul>
+}
+
+_textdelinv_ [l=zh-tr] {_cgiargbc1dirname_ å
+žèè³æåº«è¢«ä¿è­·æç¡æïŒåæ¶åªé€ã 
+}
+
+_textdelsuc_ [l=zh-tr] {æååªé€_cgiargbc1dirname_å
+žèè³æåº«ã}
+
+_textclonefail_ [l=zh-tr] {ç¡æ³è€è£œ _cgiargclonecol_ å
+žèè³æåº«ïŒå¯èœåå çºïŒ
+<ul>
+<li>â¢	_cgiargclonecol_ collection äžå­åšã 
+<li>â¢	_cgiargclonecol_ collection æ²æ collect.cfg è®æžæªã 
+<li>â¢	Greenstone æ²æè®åcollect.cfg è®æžæªçèš±å¯ã 
+</ul>
+}
+
+_textcolerr_ [l=zh-tr] {å
+žèè³æåº«ä»é¢é¯èª€}
+
+_texttmpfail_ [l=zh-tr] {å
+žèè³æåº«ä»é¢ç¡æ³è®åæå¯«å
+¥äžèšææªæç®é.ïŒå¯èœåå çºïŒ 
+<ul>
+<li>â¢	Greenstone åš_gsdlhome_/tmpç®éç¡è®/å¯«æ¬éã 
+</ul>
+}
+
+_textmkcolfail_ [l=zh-tr] {åšæ°å
+žèäžå
+žèè³æåº«ä»é¢ç¡æ³å»ºç«ç®éçµæ§ (mkcol.pl å€±æ)å¯èœåå çºïŒ
+<ul>
+<li>â¢	Greenstone æ²æå¯«å
+¥ _gsdlhome_/tmp ç®éçèš±å¯ã
+<li>â¢	mkcol.pl perlæè¿°é¯èª€ã 
+</ul>
+}
+
+_textnocontent_ [l=zh-tr] {å
+žèè³æåº«ä»é¢é¯èª€ïŒæ°å
+žèè³æåº«ç¡åçš±ïŒåŸé ­éå§éæ°ååå
+žèè³æåº«ä»é¢ã}
+
+_textrestart_ [l=zh-tr] {éæ°ååå
+žèè³æåº«ä»é¢}
+
+_textreloaderror_ [l=zh-tr] {å»ºç«æ°å
+žèè³æåº«ææèª€ïŒéå¯èœæ¯
+å çºGreenstoneå·²è¢«çèŠœåšäœ¿çšâéæ°èŒå
+¥âæâè¿åâéµæ··æ·(è«æŒå»ºç«æ°å
+žèè³æåº«æé¿å
+äœ¿çšæ­€äºéµ)ïŒå»ºè­°äœ éæ°ååå
+žèè³æåº«ä»é¢ã
+}
+
+_textexptsuc_ [l=zh-tr] {æåèŒžåº _cgiargbc1dirname_å
+žèè³æåº« è³ _gsdlhome_/tmp/exported\__cgiargbc1dirname_ ç®éã 
+}
+
+_textexptfail_ [l=zh-tr] {<p>ç¡æ³èŒžåº _cgiargbc1dirname_ å
+žèè³æåº«ã
+ 
+<p>éå¯èœæ¯å çºGreenstoneæ²æå®è£å°æ¯æŽâèŒžåºå
+žèè³æåº«âåèœçå¿
+èŠå
+ä»¶. 
+<ul>
+<li>â¢	è¥äœ äœ¿çš CD-ROM å®è£GreenstoneïŒé€éäœ åšâé²ééžé 
+âå®è£ææéžæïŒåŠ
+åæ­€äºå
+ä»¶äžæè¢«å®è£ïŒäœ å¿
+é èŠéæ°å®è£äžŠèšåŸå å
+¥ã
+<li>â¢	è¥äœ äœ¿çšç¶²è·¯å®è£ïŒäœ å¿
+é äžèŒåå®è£é¡å€å¥ä»¶æå¯äœ¿çšæ­€åèœïŒè©³æ
+
+è«è³<a href="http://www.greenstone.org">http://www.greenstone.org</a> æ é»éµ<a
+ href="mailto:greenstone@cs.waikato.ac.nz">
+email greenstone@cs.waikato.ac.nz</a>.
+</ul>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "å
+žèè³æåº«" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=zh-tr] {_httpimg_/zh-tr/h\_colect.gif}
+
+## "å
+žèè³æåº«è³èš" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=zh-tr] {_httpimg_/zh-tr/gcinfoof.gif}
+_httpicongcinfoon_ [l=zh-tr] {_httpimg_/zh-tr/gcinfoon.gif}
+_httpiconycinfoof_ [l=zh-tr] {_httpimg_/zh-tr/ycinfoof.gif}
+_httpiconycinfoon_ [l=zh-tr] {_httpimg_/zh-tr/ycinfoon.gif}
+_httpiconncinfoof_ [l=zh-tr] {_httpimg_/zh-tr/ncinfoof.gif}
+
+## "äŸæºæä»¶è³æ" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=zh-tr] {_httpimg_/zh-tr/gcsrceof.gif}
+_httpicongcsrceon_ [l=zh-tr] {_httpimg_/zh-tr/gcsrceon.gif}
+_httpiconycsrceof_ [l=zh-tr] {_httpimg_/zh-tr/ycsrceof.gif}
+_httpiconycsrceon_ [l=zh-tr] {_httpimg_/zh-tr/ycsrceon.gif}
+_httpiconncsrceof_ [l=zh-tr] {_httpimg_/zh-tr/ncsrceof.gif}
+
+## "èš­å®å
+žèè³æåº«" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=zh-tr] {_httpimg_/zh-tr/gcconfof.gif}
+_httpicongcconfon_ [l=zh-tr] {_httpimg_/zh-tr/gcconfon.gif}
+_httpiconycconfof_ [l=zh-tr] {_httpimg_/zh-tr/ycconfof.gif}
+_httpiconycconfon_ [l=zh-tr] {_httpimg_/zh-tr/ycconfon.gif}
+_httpiconncconfof_ [l=zh-tr] {_httpimg_/zh-tr/ncconfof.gif}
+
+## "å»ºç«å
+žèè³æåº«" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=zh-tr] {_httpimg_/zh-tr/gcbildof.gif}
+_httpicongcbildon_ [l=zh-tr] {_httpimg_/zh-tr/gcbildon.gif}
+_httpiconycbildof_ [l=zh-tr] {_httpimg_/zh-tr/ycbildof.gif}
+_httpiconycbildon_ [l=zh-tr] {_httpimg_/zh-tr/ycbildon.gif}
+_httpiconncbildof_ [l=zh-tr] {_httpimg_/zh-tr/ncbildof.gif}
+
+## "æª¢èŠå
+žèè³æåº«" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=zh-tr] {_httpimg_/zh-tr/gcviewof.gif}
+_httpicongcviewon_ [l=zh-tr] {_httpimg_/zh-tr/gcviewon.gif}
+_httpiconycviewof_ [l=zh-tr] {_httpimg_/zh-tr/ycviewof.gif}
+_httpiconycviewon_ [l=zh-tr] {_httpimg_/zh-tr/ycviewon.gif}
+_httpiconncviewof_ [l=zh-tr] {_httpimg_/zh-tr/ncviewof.gif}
+
+## "åªé€å
+žèè³æåº«" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=zh-tr] {_httpimg_/zh-tr/gcdelof.gif}
+_httpicongcdelon_ [l=zh-tr] {_httpimg_/zh-tr/gcdelon.gif}
+
+## "å¯åºå
+žèè³æåº«" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=zh-tr] {_httpimg_/zh-tr/gcexptof.gif}
+_httpicongcexpton_ [l=zh-tr] {_httpimg_/zh-tr/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=zh-tr] {Greenstoneæ¯äžå¥æææåæžäœåæžé€šå
+žèåå»ºæ§å
+žèèœåçè»é«ïŒå®æäŸäºæŽåè³èšçæ°æ¹æ³åçšç¶²è·¯æCD-ROMå
+¬éè³èšãGreenstone æ¯ç±Waikatoå€§å­žççŽè¥¿è­æžäœåæžé€šèšç«è£œé ïŒåUNESCOåHuman Info NGOåäœçŒè¡çãå®æ¯open-sourceè»é«ïŒ
+åš<i>http://greenstone.org</i> äžéµå
+¥GNU General Public License å¯ååŸã 
+}
+
+_textgreenstone2_ [l=zh-tr] {çŽè¥¿è­æžäœåæžé€šç¶²ç« (<a href="http://nzdl.org">http://nzdl.org</a>) å
+å«äºç¡æžçš
+Greenstoneè»é«å»ºç«å¯äŸç²Ÿè®çæ¶èç¯æ¬ïŒå®åæ¯åçš®æå°åçèŠœéžæçç¯äŸ,
+å
+¶äž­å
+æ¬äºé¿æäŒ¯ãäž­åãæ³åãæ¯å©ãè¥¿ç­çåè±åçå
+žèïŒéæäžäºé³æšç
+å
+žèã
+}
+
+_textplatformtitle_ [l=zh-tr] {å¹³å°}
+_textgreenstone3_ [l=zh-tr] {Greenstoneå¯åš WindowsãUnix å Mac OS Xäžå·è¡ãå
+¶åäœæ¶µèäºWindowsã LinuxåMac OS X çå¯å·è¡æªïŒå®ä¹å
+å«äºå¯è¢«Microsoft C++ægccç·šè­¯çå®æŽç³»çµ±åå§ç¢Œã
+Greenstoneäœ¿çšå
+è²»ççžéè»ïŒApache Webserver å PERLïŒäœ¿çšè
+ä»é¢æçšçç¶²é çèŠœåšïŒå
+žåç Netscape Navigator æ Internet Explorerã 
+}
+
+_textgreenstone4_ [l=zh-tr] {æåŸå€å
+žèè³æåº«çæä»¶ééGreenstoneè»é«å
+ç¢çæ£äœïŒäŸåŠ
+<i>Humanity Development Library</i>å
+§å«1,230ä»œåçšæ°Žè¡çççžéçµ±èšæä»¶ïŒ
+ä»åªéèŠåšç¡¬é«ç­çŽèŠæ±äžé«å°é»è
+Šäžå·è¡ïŒéäºé»è
+Šä¹åŸå®¹æåšéçŒäž­åå®¶å
+§ååŸïŒ
+æä»¶å¯ééå
+šæçééµå­æ¥è©¢ïŒææ¯ä»¥äžåçæ¹åŒäŸçèŠœæŽåå
+žèè³æåº«å
+§çæä»¶
+(äŸäž»é¡ïŒäŸæšé¡ïŒäŸåºçåçµç¹ïŒäŸ "åŠäœ..")ïŒçè³ä¹å¯çèŠœæ¯äžæ¬æžçå°é¢ã}
+
+_textcustomisationtitle_ [l=zh-tr] {é¡§å®¢å°å}
+_textgreenstone5_ [l=zh-tr] {Greenstone å
+·æé«æŽå
+
+æ§åä»¥é¡§å®¢çºå°åçè§å¿µèèš­èšãæ°çæä»¶åè©®éè³ææ ŒåŒèç±èš­èš "plugins" (in Perl)äŸæäŸãåçïŒæ°çä»¥äžåè©®éè³æçèŠœçæ¶æ§èœå€ èç±èš­èš"classifiers" äŸå·è¡ãçšç°¡å®çå·šéèªèšå¯«âå·šéâïŒå¯è®æŽäœ¿çšè
+ä»é¢çåçŸæ¹åŒãCorbaåå®è®ä»£çäºº(äŸåŠJava)äœ¿çšåæä»¶å
+žèè³æåº«æéçèš­åïŒæåŸïŒ å¯çšC++åPerlçäŸä¿®å®åå§ç¢Œã
+}
+
+_textdocumentationtitle_ [l=zh-tr] {æä»¶}
+_textdocuments_ [l=zh-tr] {Greenstoneä¹æäŸå€§éå€æš£çç³»çµ±æä»¶ã}
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+_textmailinglisttitle_ [l=zh-tr] {éµå¯æž
+å®}
+_textmailinglist_ [l=zh-tr] {éµå¯æž
+å®äž»èŠæ¯çºäºèšè«Greenstoneæžäœåæžé€šè»é«ãGreenstoneçç¶åžžäœ¿çš
+è
+æèæ
+®å å
+¥éµå¯æž
+å®åå å
+¥èšè«ãèšé±è«è³<a href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">
+https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.
+
+å¯éèšæ¯å°æž
+å®ç
+å°åçº<a href="mailto:greenstone-users@list.scms.waikato.ac.nz"
+greenstone-users@list.scms.waikato.ac.n</a>z. 
+}
+
+_textbugstitle_ [l=zh-tr] {Bugs}
+_textreport_ [l=zh-tr] {æåèŠç¢ºä¿æ­€è»é«å·¥äœæ­£åžžïŒæbugsè«éå ±<a href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+}
+
+_textgs3title_ [l=zh-tr] {åšç¢åäž­}
+_textgs3_ [l=zh-tr] {Greenstone 3 æ¯ä¿çGreenston 2(ç®åç)çåªé»åŸéæ°èš­èšåå·è¡ççæ¬-äŸåŠïŒå®æ¯å€èªèšãå€å¹³å°åé«åºŠåœæ§é
+çœ®ïŒå®å
+å«äºçŸæç³»çµ±çç¹è²äžåäžçžå®¹ïŒä¹å°±æ¯èªªïŒå®äžéä¿®æ¹å³å¯å»ºæ§åå·è¡çŸæå
+žèè³æåº«ïŒå®æ¯çšJavaå¯«çïŒç±äœ¿çšXMLæºéççšç«æš¡çµç¶²è·¯æå»ºæ§ïŒå æ­€å®æ¯äœ¿çšæŽŸéçæš¡åŒäžå¿
+èŠæå¯æŽå±å°äžåçäŒºæ
+åšãéçš®æš¡çµèš­èšå¢å äºGreenstoneçåœæ§åæŽå
+
+æ§.ïŒæ°çé èšæŒ2003å¹Ž12æ23æ¥éå§è©ŠçšïŒç³»çµ±çèµ·å§èš­èšç¥è¿°æŒâGreenstone 3çèš­èš:ïŒä»¥ä»£çäººçšåŒçºåºç€çâåæ
+æžäœåæžé€š" (äžèŒ<a href="http://www.greenstone.org/manuals/gs3design.pdf">PDF</a>).
+}
+
+_textcreditstitle_ [l=zh-tr] {è®æ}
+
+_textwhoswho_ [l=zh-tr] {Greenstoneè»é«æ¯èš±å€äººéååäœæç¢ççã Rodger McNab å Stefan Boddie 
+æ¯äž»èŠçèš­èšåž«åå·è¡è
+ïŒ David Bainbridgeã George Buchananã Hong Chenã
+Michael DewsnipãKatherine DonãElke DunckerãCarl GutwinãGeoff Holmesã
+Dana McKayã John McPhersonã Craig Nevill-Manningã Dynal PatelãGordon 
+Paynterã Bernhard Pfahringerã Todd Reedã Bill RogersãJohn Thompsonå Stuart 
+Yeatesä¹æèš±å€è²¢ç»ãçŽè¥¿è­æžäœåæžé€šçæå¡ä¹æäŸäºå¯¶è²Žçå»ºè­°åç³»çµ±èš­
+èšçéæïŒ Mark ApperleyãSally Jo Cunninghamã Matt JonesãSteve Jonesã Te 
+Taka Keeganã Michel Lootsã Malika Mahouiã Gary Marsdenã Dave Nichols å 
+Lloyd Smithã æåä¹èŠæè¬å°å
+å«åšæ­€çæ¬å
+§çGNU-èš±å¯å¥è£ïŒ MGã 
+GDBMã PDFTOHTMLãPERLã WGETãWVWARE å XLHTMLæè²¢ç»çäºº. 
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "éæŒ Greenstone è»é«" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=zh-tr] {_httpimg_/zh-tr/abgsgr.gif}
+_widthabgsgr_ [l=zh-tr] {_pagewidth_}
+_heightabgsgr_ [l=zh-tr] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=zh-tr] {é¡¯ç€ºç®åäœ¿çšè
+}
+_textuser_ [l=zh-tr] {äœ¿çšè
+}
+_textas_ [l=zh-tr] {ç®ååž³èçæ
+}
+_textgroups_ [l=zh-tr] {çŸ€çµ}
+_textcomment_ [l=zh-tr] {èš»è§£}
+_textadduser_ [l=zh-tr] {å å
+¥æ°äœ¿çšè
+}
+_textedituser_ [l=zh-tr] {ç·šèŒ¯}
+_textdeleteuser_ [l=zh-tr] {åªé€}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=zh-tr] {ç·šèŒ¯äœ¿çšè
+è³èš}
+_textadduser_ [l=zh-tr] {å¢å æ°äœ¿çšè
+}
+
+_textaboutusername_ [l=zh-tr] {äœ¿çšè
+åçš±é çº2~30åå­ïŒå¯å
+æ¬ææžå­ïŒ '.'ïŒ å '_'. 
+}
+
+_textaboutpassword_ [l=zh-tr] {å¯ç¢Œé çº3~8åASCIIå­}
+
+_textoldpass_ [l=zh-tr] {è¥æ­€æ¬ç©ºçœïŒå°ä¿çèå¯ç¢Œã}
+_textenabled_ [l=zh-tr] {çæ}
+_textdisabled_ [l=zh-tr] {ç¡æ}
+
+_textaboutgroups_ [l=zh-tr] {çŸ€çµçºäžéèåéçè¡šå®ïŒéèåŸäžå¯æç©ºæ Œã}
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=zh-tr] {åªé€äœ¿çšè
+}
+_textremwarn_ [l=zh-tr] {äœ ç¢ºå®èŠæ°žä¹
+åªé€äœ¿çšè
+_cgiargumun_?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=zh-tr] {æŽæ¹å¯ç¢Œ}
+_textoldpw_ [l=zh-tr] {èå¯ç¢Œ}
+_textnewpw_ [l=zh-tr] {æ°å¯ç¢Œ}
+_textretype_ [l=zh-tr] {åèŒžå
+¥äžæ¬¡æ°å¯ç¢Œ}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=zh-tr] {äœ çå¯ç¢ŒæŽæ¹æåïŒ}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=zh-tr] {äœ¿çšè
+åçš±é¯èª€}
+_textinvalidpassword_ [l=zh-tr] {å¯ç¢Œé¯èª€.}
+_textemptypassword_ [l=zh-tr] {è«èŒžå
+¥äœ¿çšè
+æåèš­å®çå¯ç¢Œ}
+_textuserexists_ [l=zh-tr] {äœ¿çšè
+åçš±å·²å­åšïŒè«èŒžå
+¥å
+¶ä»äœ¿çšè
+åçš±ã}
+
+_textusernameempty_ [l=zh-tr] {è«èŒžå
+¥äœ¿çšè
+åçš±.}
+_textpasswordempty_ [l=zh-tr] {è«èŒžå
+¥èå¯ç¢Œ}
+_textnewpass1empty_ [l=zh-tr] {èŒžå
+¥äœ çæ°å¯ç¢ŒåŸïŒååšéè€èŒžå
+¥äžæ¬¡}
+_textnewpassmismatch_ [l=zh-tr] {èŒžå
+¥äºæ¬¡çæ°å¯ç¢Œäžçžå}
+_textnewinvalidpassword_ [l=zh-tr] {èŒžå
+¥å¯ç¢Œé¯èª€}
+_textfailed_ [l=zh-tr] {äœ¿çšè
+åçš±æå¯ç¢ŒèŒžå
+¥é¯èª€}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=zh-tr] {Greenstone çæ¬}
+_textframebrowser_ [l=zh-tr] {äœ ççèŠœåšéèŠæ¯æŽåèœæèœå»è§çå®ã}
+_textusermanage_ [l=zh-tr] {äœ¿çšè
+ç®¡ç}
+_textlistusers_ [l=zh-tr] {ååºäœ¿çšè
+}
+_textaddusers_ [l=zh-tr] {å å
+¥æ°çäœ¿çšè
+}
+_textchangepasswd_ [l=zh-tr] {è®æŽå¯ç¢Œ}
+_textinfo_ [l=zh-tr] {ç³»çµ±è³èš}
+_textgeneral_ [l=zh-tr] {äžè¬è³èš}
+_textarguments_ [l=zh-tr] {ç³»çµ±åæž}
+_textactions_ [l=zh-tr] {Actionè³èš}
+_textbrowsers_ [l=zh-tr] {çèŠœåšè³èš}
+_textprotocols_ [l=zh-tr] {åå®è³èš}
+_textconfigfiles_ [l=zh-tr] {èš­å®æª}
+_textlogs_ [l=zh-tr] {æ¥èª}
+_textusagelog_ [l=zh-tr] {äœ¿çšäž­ä¹æ¥èª}
+_textinitlog_ [l=zh-tr] {èµ·å§æ¥èª}
+_texterrorlog_ [l=zh-tr] {é¯èª€æ¥èª}
+_textadminhome_ [l=zh-tr] {ç®¡çè
+éŠé }
+_textreturnhome_ [l=zh-tr] {GreenstoneéŠé }
+_titlewelcome_ [l=zh-tr] {ç®¡çè
+ }
+_textmaas_ [l=zh-tr] {ç¶­è­·åç®¡çæåçå
+å«åšå
+§ïŒ}
+_textvol_ [l=zh-tr] {è§çç·äžæ¥èª}
+_textcmuc_ [l=zh-tr] {ç¢çïŒç¶­è­·åæŽæ°å
+žèè³æåº«}
+_textati_ [l=zh-tr] {å­åç³»çµ±è³èšïŒäŸåŠCGI åŒæž}
+
+_texttsaa_ [l=zh-tr] {éäºæåå­åæ¯äœ¿çšåšå·Šæéé é¢ä¹æ¹åèªè¡æ£ }
+
+_textcolstat_ [l=zh-tr] {å
+žèè³æåº«çæ
+}
+
+_textcwoa_ [l=zh-tr] {å
+žèæåªæåºçŸâå·è¡äž­âïŒç¶å®åå»ºç« ä¹cfgæªæ¡å­åšäž
+å¯è®åïŒäžŠäžåšå
+žèè³æåº«ä¹çŽ¢åŒå­å
+žäž­ã(ä¹å°±æ¯äžåšå»ºç«äž­ä¹ç®éãïŒ
+_textcafi_ [l=zh-tr] {æ abbrevéµ. å¯ä»¥æª¢èŠå
+žèè³æåº«è³èš}
+
+_textcafi_ [l=zh-tr] {æ<i>abbrev.</i>å¯ä»¥æª¢èŠå
+žèè³æåº«çç°¡ä»}
+_textcctv_ [l=zh-tr] {æå
+žèè³æåº«éµå»è§çè³æåº«æ
+åœ¢}
+_textsubc_ [l=zh-tr] {ç¢ºèªè®æŽ}
+_texteom_ [l=zh-tr] {éå main.cfgé¯èª€}
+_textftum_ [l=zh-tr] {æŽæ° main.cfgå€±æ}
+_textmus_ [l=zh-tr] {æŽæ°main.cfg æå}
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=zh-tr] {å»ºç«_collectionname_è³æåº«ä¹éçšçŽé}
+_textflog_ [l=zh-tr] {_collectionname_è³æåº«ä¹å€±ææ¥èª}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=zh-tr] {Greenstone ä¹å¯çšæ§}
+
+_textwhy_ [l=zh-tr] {<p>éåºæ­€ä»œå ±åæ¯åæ¹æ³ïŒå¯ä»¥æåºäœ æŸçŒçŸæè§çå°é£æå€±æä¹ç¶²é ã}
+_textextraforform_ [l=zh-tr] {äœ ç¡é å¡«å®è¡šæ Œ â ä»»äœèšæ¯éœæå¹«å©ã}
+_textprivacybasic_ [l=zh-tr] {<p>æ­€ä»œå ±ååªå
+å«äœ æè§çæéGreenstone ç¶²é ä¹èšæ¯ïŒä»¥åäœ æäœ¿çšçè§çæè¡ 
+(å äžäœ ææäŸä¹éžææ§è³èš)ã
+}
+_textstillsend_ [l=zh-tr] {äœ æ¯åŠä»èèŠéåºæ­€ä»œå ±å?}
+
+_texterror_ [l=zh-tr] {é¯èª€}
+_textyes_ [l=zh-tr] {æ¯}
+_textno_ [l=zh-tr] {åŠ}
+_textclosewindow_ [l=zh-tr] {ééèŠçª}
+_textabout_ [l=zh-tr] {æé}
+_textprivacy_ [l=zh-tr] {ç§äž}
+_textsend_ [l=zh-tr] {éåº}
+_textdontsend_ [l=zh-tr] {äžèŠéåº}
+_textoptionally_ [l=zh-tr] {å¯éžææ§ç}
+
+_textunderdev_ [l=zh-tr] {äºå
+é èŠœå ±åæçŽ°çåèœïŒå°åšæ­£åŒçæ¬äž­å
+æ¬ã}
+
+_textviewdetails_ [l=zh-tr] {è§çå ±å}
+_textmoredetails_ [l=zh-tr] {æŽè©³çŽ°}
+_texttrackreport_ [l=zh-tr] {è¿œè¹€æ­€ä»œå ±å}
+_textcharacterise_ [l=zh-tr] {éæ¯å±¬æŒåªäžé¡åé¡}
+_textseverity_ [l=zh-tr] {æ­€åé¡åŸç³ç³}
+ 
+_textbadrender_ [l=zh-tr] {é é¢çèµ·äŸåŸå¥æª}
+_textcontenterror_ [l=zh-tr] {å
+§å®¹é¯èª€}
+_textstrangebehaviour_ [l=zh-tr] {å¥æªçè¡çº}
+_textunexpected_ [l=zh-tr] {çŒçäžé æä¹æ
+åœ¢}
+_textfunctionality_ [l=zh-tr] {åŸé£äœ¿çš}
+_textother_ [l=zh-tr] {å
+¶ä»}
+
+_textcritical_ [l=zh-tr] {è©è«ç}
+_textmajor_ [l=zh-tr] {åŽé}
+_textmedium_ [l=zh-tr] {äž­ç­}
+_textminor_ [l=zh-tr] {èŒå°ç}
+_texttrivial_ [l=zh-tr] {ç£ç¢ç}
+
+_textwhatdoing_ [l=zh-tr] {äœ è©Šèå»äœä»éºŒ?}
+_textwhatexpected_ [l=zh-tr] {äœ æåŸ
+äœäºçŒç?}
+_textwhathappened_ [l=zh-tr] {å¯ŠéäžçŒçäœäº?}
+
+_cannotfindcgierror_ [l=zh-tr] {<h2>Sorry!</h2> Can\\'t find the server programs for the "I\\'d Like to Complain" button.}
+
+_textusabbanner_ [l=zh-tr] {the Greenstone koru-é¡å æšèª}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+_textgli_ [l=zh-tr] {åæžé€šå¡ä»é¢}
+_textglihelp_ [l=zh-tr] {Greenstoneåæžé€šå¡ä»é¢ (GLI)
+çµŠäœ äºäœ¿çšGreenstone's åèœæå®¹æäœ¿çš- 'é»éžåæéµ' ä»é¢ïŒéæå
+èš±äœ æ¶éæ
+ä»¶ïŒåœå
+¥æèš­èšmetadataïŒä»¥ååšGreenstoneå»ºç«å
+žèè³æåº«ã 
+<p>
+æ³šæGLIæ¯åGreenstoneåšäŒºæåšç«¯äžèµ·å·è¡çïŒåšäœ çGreenstoneå®è£äž­GLIæ¯å®è£åšæ¬¡ç®éïŒäžç®¡äœ æ¯äžèŒå
+¶äž­äžåGreenstoneå
+ä»¶ïŒææ¯åŸGreenstoneå
+ç¢çäž­å®è£å®ïŒå
+¶å¯Šéœæ¯çžåçã
+
+<h4>åšWindows äžå·è¡ GLI</h4>
+
+åšWindowsäžïŒåš<i>éå§å·¥å
+·å</i>éžæ<i>çšåŒé</i>æ¥äžäŸé²å
+¥<i> Greenstone æžäœåæžé€š</i>ç®éäžéžæ<i>åæžé€šå¡ä»é¢</i>ã
+
+<h4>åšUnixäžå·è¡GLI </h4>
+
+åšUnixäžå·è¡GLIïŒåšäœ çGreenstone å®è£äž­æ¹è®æ<i>gli</i>ç®éïŒå·è¡<i>gli.sh</i> scriptã
+
+<h4>åšMac OS X äžå·è¡GLI</h4>
+
+çèŠœ<i>æçšçšåŒ</i>ïŒ<i>Greenstone</i> (ååŠäœ åšé èš­ä¹èå®è£Greenstone)å·è¡<i>GLI</i>æçšçšåŒ. 
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "Greenstone åæžé€šå¡ç¶­è­·ä»é¢" ## green_bar_left_aligned ## gligr ##
+_httpicongligr_ [l=zh-tr] {_httpimg_/zh-tr/gligr.gif}
+_widthgligr_ [l=zh-tr] {_pagewidth_}
+_heightgligr_ [l=zh-tr] {17}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/collect.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/collect.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/collect.dm	(revision 10506)
@@ -0,0 +1,904 @@
+# this file must be UTF-8 encoded
+
+package collector
+
+_imagethispage_ {<a href="_httppagecollector_">_iconhcolect_</a>}
+
+# _pagescriptextra_ will be set to the appropriate _***scriptextra_
+# macro from within the server
+_pagescriptextra_ {}
+
+# this is just like the _gsimage_ macro but it calls the check_submit() javascript
+# function instead of linking directly to the page (_1_ argument isn't used)
+_gsjimage_ {<a href="javascript:check\_submit('_4_');" onMouseover="roll('_4_',1);" onMouseOut="roll('_4_',0);" target=_top><img
+name="_4_" src="_2_" onLoad="gbutton(this,'_3_');" border=0 alt="_5_" title="_5_"></a>}
+_gsjimage_ [v=1] {<a href="javascript:check\_submit('_4_');" target=_top>_5_</a><br>}
+
+# _gstimage_ is also similar to _gsimage_ but is used where buttons occur in a sub-frame and
+# require target=_top
+_gstimage_ {<a href="_1_" onMouseover="roll('_4_',1);" onMouseOut="roll('_4_',0);" target="\_top"><img
+name="_4_" src="_2_" onLoad="gbutton(this,'_3_');" border=0 alt="_5_" title="_5_"></a>}
+_gstimage_ [v=1] {<a href="_1_" target="\_top">_5_</a><br>}
+
+# a plain header for those pages that need it (the _pagebanner_ macro
+# will be set to this by the server for those pages.
+_plainbanner_ {}
+
+# dont want links to "help" or "preferences" pages from within
+# collector
+_javalinks_ {_imagehome_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+}
+
+
+#######################################################################
+# icons
+
+_iconcross_ {<img src="_httpimg_/cross.gif">}
+_iconcross_ [v=1] {<b>no</b>}
+_icontick_ {<img src="_httpimg_/tick.gif">}
+_icontick_ [v=1] {<b>yes</b>}
+_iconblank_ {<img src="_httpimg_/blank.gif">}
+_iconblank_ [v=1] {}
+
+_imagemore_ {<a href="javascript:more()" onMouseover="roll('more',1);" onMouseOut="roll('more',0);"><img
+name="more" src="_httpimg_/moreof.gif" onLoad="gbutton(this,'_httpimg_/moreon.gif');" border=0 alt="_textmore_"
+title="_textmore_" align=top></a>}
+_imagemore_ [v=1] {_textmore_}
+
+_iconhcolect_ {<img src="_httpiconhcolect_" alt="_textcollector_" title="_textcollector_" border=0>}
+_icongreyarrow_ {<img src="_httpimg_/grarrow.gif">}
+_icongreyuparrow_ {<img src="_httpimg_/guarrow.gif">}
+_iconstop_ {<img src="_httpimg_/stop.gif" border=0>}
+
+_icongcinfoof_ {<img src="_httpicongcinfoof_" alt="_textinfo_" title="_textinfo_">}
+_icongcinfoon_ {<img src="_httpicongcinfoon_" alt="_textinfo_" title="_textinfo_">}
+_iconycinfoof_ {<img src="_httpiconycinfoof_" alt="_textinfo_" title="_textinfo_">}
+_iconycinfoon_ {<img src="_httpiconycinfoon_" alt="_textinfo_" title="_textinfo_">}
+_iconncinfoof_ {<img src="_httpiconncinfoof_" alt="_textinfo_" title="_textinfo_">}
+
+_icongcsrceof_ {<img src="_httpicongcsrceof_" alt="_textsrce_" title="_textsrce_">}
+_icongcsrceon_ {<img src="_httpicongcsrceon_" alt="_textsrce_" title="_textsrce_">}
+_iconycsrceof_ {<img src="_httpiconycsrceof_" alt="_textsrce_" title="_textsrce_">}
+_iconycsrceon_ {<img src="_httpiconycsrceon_" alt="_textsrce_" title="_textsrce_">}
+_iconncsrceof_ {<img src="_httpiconncsrceof_" alt="_textsrce_" title="_textsrce_">}
+
+_icongcconfof_ {<img src="_httpicongcconfof_" alt="_textconf_" title="_textconf_">}
+_icongcconfon_ {<img src="_httpicongcconfon_" alt="_textconf_" title="_textconf_">}
+_iconycconfof_ {<img src="_httpiconycconfof_" alt="_textconf_" title="_textconf_">}
+_iconycconfon_ {<img src="_httpiconycconfon_" alt="_textconf_" title="_textconf_">}
+_iconncconfof_ {<img src="_httpiconncconfof_" alt="_textconf_" title="_textconf_">}
+
+_icongcbildof_ {<img src="_httpicongcbildof_" alt="_textbild_" title="_textbild_">}
+_icongcbildon_ {<img src="_httpicongcbildon_" alt="_textbild_" title="_textbild_">}
+_iconycbildof_ {<img src="_httpiconycbildof_" alt="_textbild_" title="_textbild_">}
+_iconycbildon_ {<img src="_httpiconycbildon_" alt="_textbild_" title="_textbild_">}
+_iconncbildof_ {<img src="_httpiconncbildof_" alt="_textbild_" title="_textbild_">}
+
+_icongcviewof_ {<img src="_httpicongcviewof_" alt="_textview_" title="_textview_">}
+_icongcviewon_ {<img src="_httpicongcviewon_" alt="_textview_" title="_textview_">}
+_iconycviewof_ {<img src="_httpiconycviewof_" alt="_textview_" title="_textview_">}
+_iconycviewon_ {<img src="_httpiconycviewon_" alt="_textview_" title="_textview_">}
+_iconncviewof_ {<img src="_httpiconncviewof_" alt="_textview_" title="_textview_">}
+
+_icongcdelof_ {<img src="_httpicongcdelof_" alt="_textdel_" title="_textdel_">}
+_icongcdelon_ {<img src="_httpicongcdelon_" alt="_textdel_" title="_textdel_">}
+
+# these buttons fixed width 77x26 fontsize 13 bgcolor #96c19b
+
+_icongcexptof_ {<img src="_httpicongcexptof_" alt="_textexpt_" title="_textexpt_">}
+_icongcexpton_ {<img src="_httpicongcexpton_" alt="_textexpt_" title="_textexpt_">}
+
+#######################################################################
+# http macros 
+
+_httpinfo_ {_gwcgi_?e=_compressedoptions_&p=info}
+_httpsrce_ {_gwcgi_?e=_compressedoptions_&p=srce}
+_httpconf_ {_gwcgi_?e=_compressedoptions_&p=conf}
+_httpbild_ {_gwcgi_?e=_compressedoptions_&p=bild}
+_httpview_ {_gwcgi_?a=p&p=about&c=_cgiargbc1dirname_}
+_httpdel_  {javascript:do\_delete();}
+_httpexpt_ {_gwcgi_?e=_compressedoptions_&p=expt}
+
+
+#######################################################################
+# intro
+#######################################################################
+
+_introscriptextra_ {}
+
+_introcontent_ {
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_iconblankbar_
+<center>
+<h2>_textcollector_</h2>
+<p>_textcollectorblurb_
+</center>
+<p>_iconblankbar_
+<p>_textcb1_
+<p>_textcb2_
+<ul>
+<input type=radio name=p value=new checked>
+_textcnc_
+<br>
+<input type=radio name=p value=existing>
+_textwec_
+</ul>
+<p>_iconblankbar_
+<p>_textcb3_
+<p>_textcb4_
+
+<table><tr><td width=80>_authen:textusername_</td>
+<td><input type="text" name="un" value="" size=10></td>
+<td></td></tr>
+<tr><td>_authen:textpassword_</td>
+<td><input type="password" name="pw" size=10></td>
+<td><input type="submit" value="_textsignin_"></td>
+</tr>
+</table>
+<p>_iconblankbar_
+</td></tr>
+</table></center>
+
+</form>
+}
+
+
+#######################################################################
+# existing (Changing an existing collection page)
+#######################################################################
+
+_existingscriptextra_ {
+function check\_submit (gotopage) \{
+  var form = document.collectorform;
+  if (gotopage == "srce") \{
+    form.bc1esrce.value = "1";
+  \}
+  if (gotopage == "conf") \{
+    form.bc1econf.value = "1";
+  \}
+  form.p.value = gotopage;
+  form.submit();
+\}
+
+function do\_delete () \{
+  var form = document.collectorform;  
+  var i = form.bc1dirname.selectedIndex;
+  var del = confirm ("Confirm deletion of " + form.bc1dirname.options[i].value + " collection?");
+  if (del) \{
+    form.bc1dodelete.value = "1";
+    form.submit();
+  \}
+\}
+}
+
+_changeexisting_ {
+<p>_textfsc_
+<br>_fullnamemenu_<br>
+<p>_textwtc_
+
+<table cellspacing=6>
+<tr><td width=20 align=right valign=bottom>1.</td>
+<td valign=bottom>_gsjimage_( ,_collector:httpicongcsrceof_,_collector:httpicongcsrceon_,srce,_collector:textsrce_)</td>
+<td valign=bottom>_textamd_</td></tr>
+<tr><td align=right valign=bottom>2.</td>
+<td valign=bottom>_gsjimage_(_,_collector:httpicongcconfof_,_collector:httpicongcconfon_,conf,_collector:textconf_)</td>
+<td valign=bottom>_textetc_</td></tr>
+<tr><td align=right valign=bottom>3.</td>
+<td valign=bottom>_gsimage_(_collector:httpdel_,_collector:httpicongcdelof_,_collector:httpicongcdelon_,del,_collector:textdel_)</td>
+<td valign=bottom>_textdtc_</td></tr>
+<tr><td align=right valign=bottom>4.</td>
+<td valign=bottom>_gsjimage_( ,_collector:httpicongcexptof_,_collector:httpicongcexpton_,expt,_collector:textexpt_)</td>
+<td valign=bottom>_textetcfcd_</td></tr>
+</table>
+}
+
+_existingcontent_ {
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="p" value="_cgiargp_">
+<input type=hidden name="bc1dodelete" value="0">
+<input type=hidden name="bc1esrce" value="0">
+<input type=hidden name="bc1econf" value="0">
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_iconblankbar_
+<center><h2>_textcaec_</h2></center>
+_iconblankbar_
+_If_("_fullnamemenu_" eq "",<p>_textnwec_,_changeexisting_)
+<p>_iconblankbar_
+</td></tr>
+</table></center>
+</form>
+}
+
+
+#######################################################################
+# new (Create a new collection page)
+#######################################################################
+
+_newscriptextra_ {}
+
+_newcontent_ {
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_iconblankbar_
+<center><h2>_textcianc_</h2></center>
+_iconblankbar_
+
+<p>_texttsosn_
+<table cellspacing=6>
+<tr><td width=20 align=right valign=bottom>1.</td>
+    <td valign=bottom>_iconncinfoof_</td>
+    <td valign=bottom>_textsin_</td></tr>
+<tr><td align=right valign=bottom>2.</td>
+    <td valign=bottom>_iconncsrceof_</td>
+    <td valign=bottom>_textswts_</td></tr>
+<tr><td align=right valign=bottom>3.</td>
+    <td valign=bottom>_iconncconfof_</td>
+    <td valign=bottom>_textatco_</td></tr>
+<tr><td align=right valign=bottom>4.</td>
+    <td valign=bottom>_iconncbildof_</td>
+    <td valign=bottom>_textbtc_</td></tr>
+<tr><td align=right valign=bottom>5.</td>
+    <td valign=bottom>_iconncviewof_</td>
+    <td valign=bottom>_textpvyh_</td></tr>
+</table>
+
+<p>_texttfsiw_
+<p>_iconblankbar_
+<p>_textadab_
+<p>_textwyar_
+<p><center>
+_collectorbar_
+</center>
+
+</td></tr>
+</table></center>
+}
+
+
+#######################################################################
+# info (Collection information page)
+#######################################################################
+
+_infoscriptextra_ {
+function check\_submit (gotopage) \{
+  var form = document.collectorform;
+  if (form.bc1fullname.value.match(/^\\s*$/))
+  \{
+    alert("_textcnmbs_");
+    form.bc1fullname.focus();
+    return;
+  \}
+  else if (form.bc1contactemail.value.match(/^\\s*$/))
+  \{     
+    alert("_texteambs_");
+    form.bc1contactemail.focus();
+    return;
+  \}
+  else if (!form.bc1contactemail.value.match(/^([^@]+)@(.+)$/))
+  \{
+    alert("_textpsea_");
+    form.bc1contactemail.focus();
+    return;
+  \}
+  else if (form.bc1aboutdesc.value.match(/^\\s*$/))
+  \{
+    alert("_textdocmbs_");
+    form.bc1aboutdesc.focus();
+    return;
+  \}
+  form.p.value = gotopage;
+  form.submit();
+\}
+}
+
+_infocontent_ {
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="p" value="_cgiargp_">
+<input type=hidden name="bc1infochanged" value="0">
+
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_iconblankbar_
+<center>
+<h2>_textinfo_</h2>
+</center>
+<p>_iconblankbar_
+
+<p>_textwcanc_
+<h4>_texttfc_</h4>
+<input type="text" name="bc1fullname" value="_cgiargbc1fullname_"
+onChange="document.collectorform.bc1infochanged.value=1;") size=72>
+<br>_texttctiasp_
+<h4>_textcea_</h4>
+<input type="text" name="bc1contactemail" value="_cgiargbc1contactemail_"
+onChange="document.collectorform.bc1infochanged.value=1;" size=72>
+<br>
+_textteas_
+
+<h4>_textatc_</h4>
+<textarea name="bc1aboutdesc"  cols=72 rows=6 wrap=physical
+onChange="document.collectorform.bc1infochanged.value=1;">
+_cgiargbc1aboutdesc_
+</textarea>
+<br>_texttiasd_
+
+<p>_iconblankbar_
+
+<p>_textypits_
+<p><center>
+_collectorbar_
+</center>
+
+</td></tr>
+</table></center>
+
+</form>
+}
+
+
+#######################################################################
+# srce (Source data page)
+#######################################################################
+
+# _fullnamemenu is set from within the server. If it's empty there are
+# no valid collections 
+_fullnamemenu_ {}
+
+_srcescriptextra_ {
+var selectedindex = _selectedindex_;
+
+function check\_submit (gotopage) \{
+  var form = document.collectorform;
+  form.p.value = gotopage;
+  form.bc1fromsrce.value = "1";
+  form.submit();
+\}
+
+function menuchange () \{
+  var form = document.collectorform;
+  var warnlist = new Array (_warnindex_);
+
+  if (warnlist[form.bc1clonecol.selectedIndex] == 1) \{
+    alert ("The collection you are cloning has a non-standard input file\\n" +
+           "format, and/or uses metadata specified in auxiliary files.  If your\\n" +
+	   "new input lacks this information, some browsing facilities may not\\n" +
+           "work properly.");
+  \}
+
+  if (form.bc1clonecol.selectedIndex == 0) \{
+    form.bc1clone.value = "0";
+  \} else \{
+    form.bc1clone.value = "1";
+  \}
+
+  if (form.bc1clonecol.selectedIndex == selectedindex) \{
+    form.bc1clonechanged.value = "0";
+  \} else \{
+    form.bc1clonechanged.value = "1";
+  \}
+\}
+
+function more () \{
+  var form = document.collectorform;
+  form.bc1inputnum.value = parseInt(form.bc1inputnum.value) + 3;
+  form.p.value = "srce";
+  if (!form.action.match(/sources$/)) \{
+    form.action += "#sources";
+  \}
+  form.submit();
+\}
+}
+
+_srcenew_ {
+<center>
+<h2>_textsrce_</h2>
+</center>
+<p>_iconblankbar_
+_If_("_badsources_" eq "1",_srcebadsources_,_srcenewcontent_)
+}
+
+_srcenewcontent_ {
+_textymbyco_
+<p>_textbtco_
+_fullnamemenu_
+<p>_iconblankbar_
+}
+
+_srceappend_ {
+<center>
+<h2>_textand_</h2>
+</center>
+<p>_iconblankbar_
+<h4>_textad_</h4>
+_texttftysb_
+}
+
+_srcecontent_ {
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="p" value="_cgiargp_">
+<input type=hidden name="bc1fromsrce" value="0">
+<input type=hidden name="bc1clonechanged" value="0">
+<input type=hidden name="bc1clone" value="_cgiargbc1clone_">
+<input type=hidden name="bc1inputnum" value="_cgiargbc1inputnum_">
+
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_iconblankbar_
+_If_("_cgiargbc1esrce_" eq "1",_srceappend_,_srcenew_)
+
+<a name=sources>
+<h4>_textis_</h4>
+_sourcelist_
+
+_textddd1_
+<p>_iconblankbar_
+_textddd2_
+<p><center>
+_collectorbar_
+</center>
+
+</td></tr>
+</table></center>
+
+</form>
+}
+
+
+#######################################################################
+# conf (Configure collection page)
+#######################################################################
+
+_confscriptextra_ {
+var changed = 0;
+
+function check\_submit (gotopage) \{
+  var form = document.collectorform;
+  form.bc1cfgchanged.value = changed;
+  form.p.value = gotopage;
+  form.submit();
+\}
+
+function reset\_button () \{
+  document.collectorform.reset();
+  changed = 0;
+\}
+}
+
+_confcontent_ {
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="p" value="_cgiargp_">
+<input type=hidden name="bc1cfgchanged" value="_cgiargbc1cfgchanged_">
+
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_iconblankbar_
+<center>
+<h2>_textconf_</h2>
+</center>
+<p>_iconblankbar_
+_textconf1_
+
+<p><textarea name="cfgfile" cols=72 rows=18 wrap=off onChange="changed=1;">
+_cfgfile_
+</textarea>
+<table><tr valign=top>
+<td><a href="javascript:reset\_button();">_iconstop_</a></td>
+<td><a href="javascript:reset\_button();">_textreset_</a></td>
+</tr></table>
+
+<p><center>
+_collectorbar_
+</center>
+
+</td></tr>
+</table></center>
+
+</form>
+}
+
+
+#######################################################################
+# bild (main frameset for build page)
+#######################################################################
+
+_bildcontent_ {
+<html>
+<head>
+<script>
+<!--
+function check\_submit (gotopage) \{
+  var form = document.collectorform;
+  form.p.value = gotopage;
+  form.submit();
+\}
+// -->
+</script>
+</head>
+
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="p" value="_cgiargp_">
+
+<frameset rows="*,160" border=0>
+  <noframes><body bgcolor="#ffffff">
+  <p>You must have a frame enabled browser to obtain feedback
+  on how the building process is progressing. The collection <i>will</i>
+  continue to build as normal however.
+
+  <table>
+  <tr valign=center><td>
+  To stop the building process at any time, click here.
+  <br>The collection you are working on will remain intact.
+  </td>
+  <td><input type="submit" value="stop building"></td>
+  </table>
+
+  </body>
+  </noframes>
+  <frame src="_gwcgi_?e=_compressedoptions_&p=bildframe1">
+  <frame src="_gwcgi_?e=_compressedoptions_&p=bildstatus">
+</frameset>
+</html>
+}
+
+#######################################################################
+# bildframe1
+#######################################################################
+
+# header overridden to allow base target to be set
+# also no page banner to maximise what we can fit in the frame without scrolling
+_bildframe1header_ {_cgihead_
+<html>
+<head>
+<base target=_top>
+<title>_pagetitle_</title>
+_globalscripts_
+</head>
+<body bgcolor="\#ffffff" text="\#000000" link="\#006666" 
+      alink="\#cc9900" vlink="\#666633" background="_httpiconchalk_">
+_startspacer_
+}
+_bildframe1header_[v=1] {_cgihead_
+<html>
+<head>
+<base target=_top>
+<title>_pagetitle_</title>
+_globalscripts_
+</head>
+<body bgcolor="\#ffffff" text="\#000000" link="\#006666" 
+      alink="\#cc9900" vlink="\#666633" background="_httpiconchalk_">
+}
+_bildframe1scriptextra_ {}
+_bildframe1content_ {
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="p" value="bildcancel">
+
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_iconblankbar_
+<center>
+<h2>_textbild_</h2>
+</center>
+<p>_iconblankbar_
+<p>
+_textbild1_
+<p>
+
+<table>
+<tr valign=center><td>
+_textbild2_
+</td>
+<td><input type="submit" value="_textstopbuild_"></td>
+</table>
+
+<p>
+_textbild3_
+</td></tr>
+</table></center>
+</form>
+}
+
+
+#######################################################################
+# bildcancel
+#######################################################################
+
+_bildcancelscriptextra_ {
+function check\_submit (gotopage) \{
+  var form = document.collectorform;
+  form.p.value = gotopage;
+  form.submit();
+\}
+}
+_bildcancelcontent_ {
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="p" value="_cgiargp_">
+
+</form>
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_iconblankbar_
+<center>
+<h2>_textbuildcancelled_</h2>
+</center>
+<p>_iconblankbar_
+<p>
+_textbildcancel1_
+<p><center>
+_collectorbar_
+</center>
+
+</td></tr>
+</table></center>
+}
+
+
+#######################################################################
+# bildstatus
+#######################################################################
+
+# special header for status page
+_bildstatusheader_ {_cgihead_
+_htmlhead_(background="_httpiconchalk_" onLoad="initialize();")_startspacer_
+}
+_bildstatusheader_[v=1] {_cgihead_
+_htmlhead_(onLoad="initialize();")
+}
+
+_bildstatusscriptextra_ {
+var timer = 5;
+function initialize() \{
+  setTimeout("count_down()",1000);
+\}
+
+function count_down() \{
+  if (timer==0) \{
+    window.status = "";
+    document.collectorform.submit();
+  \} else \{
+    if (timer==1) \{
+	window.status = "_textbsupdate1_";
+    \} else \{
+	window.status = "_textbsupdate2_ "+timer+" _textseconds_";
+    \}
+    timer--;
+    setTimeout("count_down()",1000);
+  \}	
+\}
+}
+
+_bildstatuscontent_ {
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_statusline_
+</td></tr>
+</table></center>
+</form>
+}
+
+
+#######################################################################
+# bilddone
+#######################################################################
+
+_bilddoneheader_ {_cgihead_
+_htmlhead_(background="_httpiconchalk_")_startspacer_
+}
+_bilddonescriptextra_ {}
+_bilddonecontent_ {
+<center>
+<table width=_pagewidth_>
+<tr><td>
+<p>_textbildsuc_
+
+<p>_textviewbildsummary_
+
+<p><center>
+_collectorbar_
+</center>
+
+</td></tr>
+</table></center>
+}
+
+
+#######################################################################
+# bildfail
+#######################################################################
+
+_bildfailheader_ {_cgihead_
+_htmlhead_(background="_httpiconchalk_")_startspacer_
+}
+_bildfailscriptextra_ {
+function check\_submit (gotopage) \{
+  var form = document.collectorform;
+  form.p.value = gotopage;
+  form.submit();
+\}
+}
+_bildfailcontent_ {
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="p" value="_cgiargp_">
+
+</form>
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_textfailmsg_
+</td></tr>
+</table></center>
+}
+
+# _textfailmsg_ will be set to one of the following macros from within
+# the server
+
+_textfailmsg1_ {
+_textfailmsg11_
+<p><center>
+_collectorbar_
+</center>
+}
+
+_textfailmsg6_ {_textfailmsg1_}
+
+_textfailmsg2_ {
+_textfailmsg21_
+<p>_textblcont_
+<p>_faillog_
+<p>_texttryagain_
+}
+
+_textfailmsg3_ {
+_textfailmsg31_
+<p>_textblcont_
+<p>_faillog_
+<p>_texttryagain_
+}
+
+_textfailmsg4_ {
+_textfailmsg41_
+<p>_textblcont_
+<p>_faillog_
+}
+
+_textfailmsg5_ {_textfailmsg4_}
+
+_textfailmsg7_ {
+_textfailmsg71_
+<p>_texttryagain_
+}
+
+#######################################################################
+# Error and message pages
+#######################################################################
+
+_messagehead_ {
+<form name="collectorform" method=post action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+
+<center>
+<table width=_pagewidth_>
+<tr><td>
+_iconblankbar_
+}
+
+_messagefoot_ {
+<p>
+<a href="javascript:document.collectorform.submit();">_textretcoll_</a>
+<p>_iconblankbar_
+</td></tr>
+</table></center>
+</form>
+}
+
+_messagefootnolink_ {
+<p>_iconblankbar_
+</td></tr>
+</table></center>
+</form>
+}
+
+_delpermissioncontent_ {
+_messagehead_
+<p>
+_textdelperm_
+_messagefoot_
+}
+
+_delinvalidcontent_ {
+_messagehead_
+<p>
+_textdelinv_
+_messagefoot_
+}
+
+_delsuccesscontent_ {
+_messagehead_
+<p>
+_textdelsuc_
+_messagefoot_
+}
+
+_clonefailcontent_ {
+_messagehead_
+<input type=hidden name="bc1clone" value="0">
+<p>_textclonefail_
+_messagefoot_
+}
+
+_genericcontent_ {
+_messagehead_
+<p>_textcolerr_
+_messagefoot_
+}
+
+_tmpfailcontent_ {
+_messagehead_
+<p>
+_texttmpfail_
+_messagefoot_
+}
+
+_mkcolfailcontent_ {
+_messagehead_
+<p>_textmkcolfail_
+_messagefoot_
+}
+
+_nocollectioncontent_ {
+_messagehead_
+<p>_textnocontent_
+<br><a href="_httppagecollector_">_textrestart_</a>
+<p>
+_messagefootnolink_
+}
+
+_reloaderrorcontent_ {
+_messagehead_
+<p>_textreloaderror_
+<br><a href="_httppagecollector_">_textrestart_</a>
+<p>
+_messagefootnolink_
+}
+
+_exptscriptextra_ {}
+
+_exptsuccesscontent_ {
+_messagehead_
+<input type=hidden name=p value=existing>
+<p>_textexptsuc_
+_messagefoot_
+}
+
+_exptfailcontent_ {
+_messagehead_
+<input type=hidden name=p value=existing>
+_textexptfail_
+_messagefoot_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/croatian.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/croatian.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/croatian.dm	(revision 10506)
@@ -0,0 +1,1273 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Croatian Language text and icon macros 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=hr] {Serijske publikacije}
+_textsource_ [l=hr] {izvor: }
+_textdate_ [l=hr] {datum izdavanja: }
+_textnumpages_ [l=hr] {broj stranica: }
+
+_textsignin_ [l=hr] {prijavi se}
+
+_textdefaultcontent_ [l=hr] {TraÅŸena stranica nije pronaÄena. Molimo vas koristite funkciju 
+"back" na vaÅ¡em pregledniku ili funkciju "home" za povratak u Greenstone Digital Library.}
+
+_textdefaulttitle_ [l=hr] {GSDL PogreÅ¡ka}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=hr] {Ova zbirka sadrÅŸi _about:numdocs_ dokumen(a)ta. 
+Zadnji put je bila aÅŸurirana prije _about:builddate_ dana.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=hr] {<p>Ova zbirka se sastoji od _numdocs_ _If_("_numdocs_" eq "1",dokumenta,dokumenta), sa ukupno _numbytes_.
+<p><a href="_httppagex_(bsummary)">Klikni ovdje</a> za pristup sistemskim podacima o zbirci.}
+
+_textimagecollection_ [l=hr] {}
+_textimageabout_ [l=hr] {O zbirci}
+_textimagehome_ [l=hr] {Naslovna stranica}
+_textimagehelp_ [l=hr] {PomoÄ}
+_textimagepref_ [l=hr] {Postavke}
+_textimagegreenstone_ [l=hr] {Greenstone Digital Library Softver}
+# -- Missing translation: _textimageusab_
+
+_textimagesearch_ [l=hr] {TraÅŸi prema odreÄenim pojmovima}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=hr] {Pregledaj abecedni popis naslova}
+_textimageCreator_ [l=hr] {Pregledaj abecedni popis autora}
+_textimageSubject_ [l=hr] {Pregledaj prema podruÄjima po kojima je razvrstana graÄa}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=hr] {Pregledaj prema datumu}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=hr] {Pregledaj prema izvornom nazivu datoteke}
+_textimageLanguage_ [l=hr] {Pregledaj prema jeziku}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=hr] {Pregledaj prema nazivu organizacije}
+_textimageKeyword_ [l=hr] {Pregledaj prema kljuÄnim rijeÄima}
+_textimageHowto_ [l=hr] {Pregledaj "Kako da" kategoriju}
+_textimageList_ [l=hr] {Pregledaj popis dokumenata ukljuÄenih u zbirku}
+_textimageSeries_ [l=hr] {Pregledaj prema izdanju}
+# -- Missing translation: _textimageTo_
+# -- Missing translation: _textimageFrom_
+_textimageTopic_ [l=hr] {Pregledaj specijalni izbor tema}
+_textimageBrowse_ [l=hr] {Pregledaj}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=hr] {Pregledaj abecedni popis osoba}
+_textimageAcronym_ [l=hr] {Pregled akronima}
+_textimagePhrase_ [l=hr] {Pregled fraza}
+_textimageArtist_ [l=hr] {Pregled umjetnika}
+# -- Missing translation: _textimageVolume_
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=hr] {TraÅŸi}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=hr] {Naslovi A-Z}
+_texticontabCreatorgreen_ [l=hr] {Autori A-Z}
+_texticontabSubjectgreen_ [l=hr] {PodruÄja}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=hr] {Datumi}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=hr] {Datoteke}
+_texticontabLanguagegreen_ [l=hr] {Jezik}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=hr] {Organizacije}
+_texticontabKeywordgreen_ [l=hr] {KljuÄne rijeÄi}
+_texticontabhowgreen_ [l=hr] {Kako da}
+_texticontabseriesgreen_ [l=hr] {Nizovi}
+_texticontablistgreen_ [l=hr] {Ispis}
+# -- Missing translation: _texticontabtogreen_
+# -- Missing translation: _texticontabfromgreen_
+_texticontabtopicgreen_ [l=hr] {Teme}
+_texticontabbrwsegreen_ [l=hr] {Pregled}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=hr] {Pregled}
+_texticontabPeoplegreen_ [l=hr] {Ljudi A-Z}
+_texticontabAcronymgreen_ [l=hr] {Akronimi}
+_texticontabPhrasegreen_ [l=hr] {Fraze}
+_texticontabArtistgreen_ [l=hr] {Umjetnici}
+# -- Missing translation: _texticontabVolumegreen_
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=hr] {Pogledaj dokument}
+_texticonclosedbook_ [l=hr] {otvori ovaj dokument i pogledaj njegov sadrÅŸaj}
+_texticonnext_ [l=hr] {sljedeÄi odjeljak}
+_texticonprev_ [l=hr] {prethodni odjeljak}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=hr] {Pogledaj dokument u MIDI formatu}
+_texticonmsword_ [l=hr] {Pogledaj dokument u Microsoft Word formatu}
+_texticonmp3_ [l=hr] {Pogledaj dokument u MP3 formatu}
+_texticonpdf_ [l=hr] {Pogledaj dokument u PDF formatu}
+_texticonps_ [l=hr] {Pogledaj dokument u PostScript formatu}
+_texticonppt_ [l=hr] {Pogledaj dokument PowerPoint formatu}
+_texticonrtf_ [l=hr] {Pogledaj dokument u RTF formatu}
+_texticonxls_ [l=hr] {Pogledaj dokument u Microsoft Excel formatu}
+
+_page_ [l=hr] {stranica }
+_pages_ [l=hr] {stranice}
+_of_ [l=hr] {od }
+_vol_ [l=hr] {Br.}
+_num_ [l=hr] {Br.}
+
+_textmonth00_ [l=hr] {}
+_textmonth01_ [l=hr] {SijeÄanj}
+_textmonth02_ [l=hr] {VeljaÄa}
+_textmonth03_ [l=hr] {OÅŸujak}
+_textmonth04_ [l=hr] {Travanj}
+_textmonth05_ [l=hr] {Svibanj}
+_textmonth06_ [l=hr] {Lipanj}
+_textmonth07_ [l=hr] {Srpanj}
+_textmonth08_ [l=hr] {Kolovoz}
+_textmonth09_ [l=hr] {Rujan}
+_textmonth10_ [l=hr] {Listopad}
+_textmonth11_ [l=hr] {Studeni}
+_textmonth12_ [l=hr] {Prosinac}
+
+# -- Missing translation: _textdocument_
+# -- Missing translation: _textsection_
+# -- Missing translation: _textparagraph_
+
+_magazines_ [l=hr] {Äasopisi}
+
+_nzdlpagefooter_ [l=hr] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "NASLOVNA" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=hr] {_httpimg_/hr/chomeof.gif}
+_httpiconchomeon_ [l=hr] {_httpimg_/hr/chomeon.gif}
+
+## "POMOÄ" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=hr] {_httpimg_/hr/chelpof.gif}
+_httpiconchelpon_ [l=hr] {_httpimg_/hr/chelpon.gif}
+
+## "POSTAVKE" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=hr] {_httpimg_/hr/cprefof.gif}
+_httpiconcprefon_ [l=hr] {_httpimg_/hr/cprefon.gif}
+
+# -- Missing translation: cusab
+# -- Missing translation: _httpiconcusabof_
+# -- Missing translation: _httpiconcusabon_
+
+
+## "traÅŸi" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=hr] {_httpimg_/hr/tsrchgr.gif}
+_httpicontsrchof_ [l=hr] {_httpimg_/hr/tsrchof.gif}
+_httpicontsrchon_ [l=hr] {_httpimg_/hr/tsrchon.gif}
+_widthtsrchx_ [l=hr] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "naslovi a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=hr] {_httpimg_/hr/ttitlgr.gif}
+_httpiconttitleof_ [l=hr] {_httpimg_/hr/ttitlof.gif}
+_httpiconttitleon_ [l=hr] {_httpimg_/hr/ttitlon.gif}
+_widthttitlex_ [l=hr] {90}
+
+# Not true DC, kept for legacy reasons
+## "autori a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=hr] {_httpimg_/hr/tauthgr.gif}
+_httpicontcreatof_ [l=hr] {_httpimg_/hr/tauthof.gif}
+_httpicontcreaton_ [l=hr] {_httpimg_/hr/tauthon.gif}
+_widthtcreatx_ [l=hr] {87}
+
+## "podruÄja" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=hr] {_httpimg_/hr/tsubjgr.gif}
+_httpicontsubjon_ [l=hr] {_httpimg_/hr/tsubjon.gif}
+_httpicontsubjof_ [l=hr] {_httpimg_/hr/tsubjof.gif}
+# -- Missing translation: _widthtsubjx_
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "datumi" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=hr] {_httpimg_/hr/tdategr.gif}
+_httpicontdateof_ [l=hr] {_httpimg_/hr/tdateof.gif}
+_httpicontdateon_ [l=hr] {_httpimg_/hr/tdateon.gif}
+_widthtdatex_ [l=hr] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "nazivi datoteka" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=hr] {_httpimg_/hr/tsrcgr.gif}
+_httpicontsrcof_ [l=hr] {_httpimg_/hr/tsrcof.gif}
+_httpicontsrcon_ [l=hr] {_httpimg_/hr/tsrcon.gif}
+_widthtsrcx_ [l=hr] {130}
+
+## "jezici" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=hr] {_httpimg_/hr/tlanggr.gif}
+_httpicontlangon_ [l=hr] {_httpimg_/hr/tlangon.gif}
+_httpicontlangof_ [l=hr] {_httpimg_/hr/tlangof.gif}
+_widthtlangx_ [l=hr] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "nizovi" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=hr] {_httpimg_/hr/tsergr.gif}
+_httpicontserof_ [l=hr] {_httpimg_/hr/tserof.gif}
+_httpicontseron_ [l=hr] {_httpimg_/hr/tseron.gif}
+_widthtserx_ [l=hr] {87}
+
+# -- Missing translation: tto
+# -- Missing translation: _httpiconttogr_
+# -- Missing translation: _httpiconttoon_
+# -- Missing translation: _httpiconttoof_
+# -- Missing translation: _widthttox_
+
+# -- Missing translation: tfrom
+# -- Missing translation: _httpicontfromgr_
+# -- Missing translation: _httpicontfromon_
+# -- Missing translation: _httpicontfromof_
+# -- Missing translation: _widthtfromx_
+
+## "organizacije" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=hr] {_httpimg_/hr/torggr.gif}
+_httpicontorgon_ [l=hr] {_httpimg_/hr/torgon.gif}
+_httpicontorgof_ [l=hr] {_httpimg_/hr/torgof.gif}
+_widthtorgx_ [l=hr] {102}
+
+## "kako da" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=hr] {_httpimg_/hr/thowgr.gif}
+_httpiconthowon_ [l=hr] {_httpimg_/hr/thowon.gif}
+_httpiconthowof_ [l=hr] {_httpimg_/hr/thowof.gif}
+_widththowx_ [l=hr] {87}
+
+## "teme" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=hr] {_httpimg_/hr/ttopicgr.gif}
+_httpiconttopicon_ [l=hr] {_httpimg_/hr/ttopicon.gif}
+_httpiconttopicof_ [l=hr] {_httpimg_/hr/ttopicof.gif}
+_widthttopicx_ [l=hr] {87}
+
+## "pregled" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=hr] {_httpimg_/hr/tbrwsegr.gif}
+_httpicontbrwseon_ [l=hr] {_httpimg_/hr/tbrwseon.gif}
+_httpicontbrwseof_ [l=hr] {_httpimg_/hr/tbrwseof.gif}
+_widthtbrwsex_ [l=hr] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "osobe" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=hr] {_httpimg_/hr/tpeopgr.gif}
+_httpicontpeopof_ [l=hr] {_httpimg_/hr/tpeopof.gif}
+_httpicontpeopon_ [l=hr] {_httpimg_/hr/tpeopon.gif}
+_widthtpeopx_ [l=hr] {87}
+
+## "akronimi" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=hr] {_httpimg_/hr/tacrogr.gif}
+_httpicontacroof_ [l=hr] {_httpimg_/hr/tacroof.gif}
+_httpicontacroon_ [l=hr] {_httpimg_/hr/tacroon.gif}
+_widthtacrox_ [l=hr] {87}
+
+## "fraze" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=hr] {_httpimg_/hr/tphrsegr.gif}
+_httpicontphrseof_ [l=hr] {_httpimg_/hr/tphrseof.gif}
+_httpicontphrseon_ [l=hr] {_httpimg_/hr/tphrseon.gif}
+_widthtphrsex_ [l=hr] {87}
+
+## "umjetnici" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=hr] {_httpimg_/hr/tartstgr.gif}
+_httpicontartstof_ [l=hr] {_httpimg_/hr/tartstof.gif}
+_httpicontartston_ [l=hr] {_httpimg_/hr/tartston.gif}
+_widthtartstx_ [l=hr] {87}
+
+## "kljuÄne rijeÄi" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=hr] {_httpimg_/hr/tkwgr.gif}
+_httpicontkwof_ [l=hr] {_httpimg_/hr/tkwof.gif}
+_httpicontkwon_ [l=hr] {_httpimg_/hr/tkwon.gif}
+# -- Missing translation: _widthtkwx_
+
+# -- Missing translation: tvol
+# -- Missing translation: _httpicontvolgr_
+# -- Missing translation: _httpicontvolof_
+# -- Missing translation: _httpicontvolon_
+# -- Missing translation: _widthtvolx_
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "POMOÄ" ## green_title ## h_help ##
+_httpiconhhelp_ [l=hr] {_httpimg_/hr/h_help.gif}
+_widthhhelp_ [l=hr] {200}
+_heighthhelp_ [l=hr] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=hr] {O zbirci}
+
+_textsubcols1_ [l=hr] {<p>Cijela zbirka sadrÅŸi _1_ podzbirk(i)e. 
+Trenutno su dostupne: 
+<blockquote>}
+
+_textsubcols2_ [l=hr] {</blockquote>
+MoÅŸeÅ¡ provjeriti (i promijeniti) podzbirku koju trenutno koristiÅ¡ na stranici Postavke.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "o zbirci" ## green_title ## h_about ##
+_httpiconhabout_ [l=hr] {_httpimg_/hr/h_about.gif}
+_widthhabout_ [l=hr] {200}
+_heighthabout_ [l=hr] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=hr] {Naslovi A-Z}
+_texticonhcreat_ [l=hr] {Autori A-Z}
+_texticonhsubj_ [l=hr] {PodruÄja}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=hr] {Datumi}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=hr] {Datoteke}
+_texticonhlang_ [l=hr] {Jezici}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+# -- Missing translation: _texticonhto_
+# -- Missing translation: _texticonhfrom_
+_texticonhser_ [l=hr] {Äasopisi}
+_texticonhhow_ [l=hr] {Kako da}
+_texticonhorg_ [l=hr] {Organizacije}
+_texticonhbrwse_ [l=hr] {Pregled}
+_texticonhbrows_ [l=hr] {Pregled}
+_texticonhpeople_ [l=hr] {Osobe A-Z}
+_texticonhacronym_ [l=hr] {Akronimi}
+_texticonhphrases_ [l=hr] {Fraze}
+_texticonhartist_ [l=hr] {Umjetnici}
+_texticonhkw_ [l=hr] {KljuÄne rijeÄi}
+# -- Missing translation: _texticonhvol_
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=hr] {zatvori ovaj odjeljak zbirke}
+_texticonclosedbookshelf_ [l=hr] {otvori ovaj odjeljak zbirke i pogledaj sadrÅŸaj}
+_texticonopenbook_ [l=hr] {zatvori dokument}
+_texticonclosedfolder_ [l=hr] {otvori ovu mapu i pogledaj sadrÅŸaj}
+_texticonclosedfolder2_ [l=hr] {otvori pod-odjeljak: }
+_texticonopenfolder_ [l=hr] {zatvori mapu}
+_texticonopenfolder2_ [l=hr] {zatvori pod-odjeljak: }
+_texticonsmalltext_ [l=hr] {Pogledaj tekst ovog odjeljka}
+_texticonsmalltext2_ [l=hr] {pogledaj tekst: }
+_texticonpointer_ [l=hr] {trenutni odjeljak}
+_texticondetach_ [l=hr] {Otvori ovu stranicu u novom prozoru}
+_texticonhighlight_ [l=hr] {OznaÄi traÅŸene pojmove}
+_texticonnohighlight_ [l=hr] {Nemoj oznaÄavati traÅŸene pojmove}
+_texticoncontracttoc_ [l=hr] {SaÅŸmi prikaz sadrÅŸaja}
+_texticonexpandtoc_ [l=hr] {PrikaÅŸi sadrÅŸaj}
+_texticonexpandtext_ [l=hr] {PrikaÅŸi cijeli tekst}
+_texticoncontracttext_ [l=hr] {PrikaÅŸi tekst samo trenutno oznaÄenog odjeljka}
+_texticonwarning_ [l=hr] {<b>Upozorenje: </b>}
+_texticoncont_ [l=hr] {nastavak?}
+
+_textltwarning_ [l=hr] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Dodavanje novog teksta Äe generirati veliku koliÄinu podataka 
+za prikaz u VaÅ¡em pregledniku _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=hr] {idi na stranicu}
+_textintro_ [l=hr] {<i>(uvodni tekst)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "naslovi a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=hr] {_httpimg_/hr/h_title.gif}
+_widthhtitle_ [l=hr] {200}
+_heighthtitle_ [l=hr] {57}
+
+# Not true DC, kept for legacy reasons
+## "autori a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=hr] {_httpimg_/hr/h\_auth.gif}
+_widthhcreat_ [l=hr] {200}
+_heighthcreat_ [l=hr] {57}
+
+## "podruÄja" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=hr] {_httpimg_/hr/h\_subj.gif}
+_widthhsubj_ [l=hr] {200}
+_heighthsubj_ [l=hr] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "datumi" ## green_title ## h_date ##
+_httpiconhdate_ [l=hr] {_httpimg_/hr/h\_date.gif}
+_widthhdate_ [l=hr] {200}
+_heighthdate_ [l=hr] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "datoteke" ## green_title ## h_src ##
+_httpiconhsrc_ [l=hr] {_httpimg_/hr/h_src.gif}
+_widthhsrc_ [l=hr] {200}
+_heighthsrc_ [l=hr] {57}
+
+## "jezici" ## green_title ## h_lang ##
+_httpiconhlang_ [l=hr] {_httpimg_/hr/h\_lang.gif}
+_widthhlang_ [l=hr] {200}
+_heighthlang_ [l=hr] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+# -- Missing translation: h_to
+# -- Missing translation: _httpiconhto_
+# -- Missing translation: _widthhto_
+# -- Missing translation: _heighthto_
+
+# -- Missing translation: h_from
+# -- Missing translation: _httpiconhfrom_
+# -- Missing translation: _widthhfrom_
+# -- Missing translation: _heighthfrom_
+
+## "nizovi" ## green_title ## h_ser ##
+_httpiconhser_ [l=hr] {_httpimg_/hr/h\_ser.gif}
+_widthhser_ [l=hr] {200}
+_heighthser_ [l=hr] {57}
+
+## "kako da" ## green_title ## h_how ##
+_httpiconhhow_ [l=hr] {_httpimg_/hr/h\_how.gif}
+_widthhhow_ [l=hr] {200}
+_heighthhow_ [l=hr] {57}
+
+## "teme" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=hr] {_httpimg_/hr/h\_topic.gif}
+_widthhtopic_ [l=hr] {200}
+_heighthtopic_ [l=hr] {57}
+
+## "organizacije" ## green_title ## h_org ##
+_httpiconhorg_ [l=hr] {_httpimg_/hr/h\_org.gif}
+_widthhorg_ [l=hr] {250}
+_heighthorg_ [l=hr] {57}
+
+## "metapregled" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=hr] {_httpimg_/hr/h\_brwse.gif}
+_widthhbrwse_ [l=hr] {200}
+_heighthbrwse_ [l=hr] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "ljudi" ## green_title ## h_people ##
+_httpiconhpeople_ [l=hr] {_httpimg_/hr/h\_people.gif}
+_widthhpeople_ [l=hr] {200}
+_heighthpeople_ [l=hr] {57}
+
+## "akronimi" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=hr] {_httpimg_/hr/h\_acro.gif}
+_widthhacronym_ [l=hr] {200}
+_heighthacronym_ [l=hr] {57}
+
+## "fraze" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=hr] {_httpimg_/hr/h\_phrse.gif}
+_widthhphrse_ [l=hr] {200}
+_heighthphrse_ [l=hr] {57}
+
+## "umjetnici" ## green_title ## h_artist ##
+_httpiconhartist_ [l=hr] {_httpimg_/hr/h\_artist.gif}
+_widthhartist_ [l=hr] {200}
+_heighthartist_ [l=hr] {57}
+
+## "kljuÄne rijeÄi" ## green_title ## h_kw ##
+_httpiconhkw_ [l=hr] {_httpimg_/hr/h_kw.gif}
+_widthhkw_ [l=hr] {200}
+_heighthkw_ [l=hr] {57}
+
+# -- Missing translation: h_vol
+# -- Missing translation: _httpiconhvol_
+# -- Missing translation: _widthhvol_
+# -- Missing translation: _heighthvol_
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+## "NASTAVAK?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=hr] {_httpimg_/hr/contof.gif}
+_httpiconconton_ [l=hr] {_httpimg_/hr/conton.gif}
+
+## "PRIKAÅœI\nTEKST" ## document_button ## eallt ##
+_httpiconealltof_ [l=hr] {_httpimg_/hr/ealltof.gif}
+_httpiconeallton_ [l=hr] {_httpimg_/hr/eallton.gif}
+
+## "SAÅœMI\nSADRÅœAJ" ## document_button ## econc ##
+_httpiconeconcof_ [l=hr] {_httpimg_/hr/econcof.gif}
+_httpiconeconcon_ [l=hr] {_httpimg_/hr/econcon.gif}
+
+## "NOVI\nPROZOR" ## document_button ## edtch ##
+_httpiconedtchof_ [l=hr] {_httpimg_/hr/edtchof.gif}
+_httpiconedtchon_ [l=hr] {_httpimg_/hr/edtchon.gif}
+
+## "PRIKAÅœI\nSADRÅœAJ" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=hr] {_httpimg_/hr/eexpcof.gif}
+_httpiconeexpcon_ [l=hr] {_httpimg_/hr/eexpcon.gif}
+
+## "SAÅœMI\nTEKST" ## document_button ## etsec ##
+_httpiconetsecof_ [l=hr] {_httpimg_/hr/etsecof.gif}
+_httpiconetsecon_ [l=hr] {_httpimg_/hr/etsecon.gif}
+
+## "OZNAÄAVANJE" ## document_button ## ehl ##
+_httpiconehlof_ [l=hr] {_httpimg_/hr/ehlof.gif}
+_httpiconehlon_ [l=hr] {_httpimg_/hr/ehlon.gif}
+
+## "BEZ\nOZNAÄAVANJA" ## document_button ## enhl ##
+_httpiconenhlof_ [l=hr] {_httpimg_/hr/enhlof.gif}
+_httpiconenhlon_ [l=hr] {_httpimg_/hr/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=hr] {_If_(_thislast_,results _thisfirst_ - _thislast_ za upit: _cgiargq_, Ne zadovoljava upit: _cgiargq_)}
+_textnoquerytitle_ [l=hr] {PretraÅŸivanje}
+
+_texticonthispage_ [l=hr] {traÅŸi}
+_textsome_ [l=hr] {_If_(_cgiargb_,nizane,neke)}
+_textall_ [l=hr] {_If_(_cgiargb_,booleove,sve)}
+# -- Missing translation: _textboolean_
+# -- Missing translation: _textranked_
+# -- Missing translation: _textnatural_
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=hr] {}
+_texticonsearchhistorybar_ [l=hr] {Popis prethodnih pretraÅŸivanja}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=hr] {koristi ovaj upit}
+_textfreqmsg1_ [l=hr] {Broj rijeÄi: }
+# -- Missing translation: _textpostprocess_
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=hr] {ViÅ¡e od }
+_textapprox_ [l=hr] {O }
+_textnodocs_ [l=hr] {Nijedan dokument ne zadovoljava upit.}
+_text1doc_ [l=hr] {1 dokument zadovoljava upit.}
+_textlotsdocs_ [l=hr] {dokumenta zadovoljavaju upit.}
+_textmatches_ [l=hr] {Zadovoljava }
+_textbeginsearch_ [l=hr] {PoÄetak pretraÅŸivanja}
+_textrunquery_ [l=hr] {IzvrÅ¡i upit}
+_textclearform_ [l=hr] {Novi upit}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=hr] {RijeÄ ili frazu}
+_textinfield_ [l=hr] {... u polju}
+# -- Missing translation: _textfoldstem_
+
+_textadvquery_ [l=hr] {Ili unesi upit izravno:}
+_textallfields_ [l=hr] {Sva polja}
+# -- Missing translation: _texttextonly_
+_textand_ [l=hr] {i}
+_textor_ [l=hr] {ili}
+_textandnot_ [l=hr] {i ne}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=hr] {TraÅŸi prema _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, at _gselection_ level) _If_(_nselection_, in _nselection_ language) koji sadrÅŸi _querytypeselection_ rijeÄi}
+
+_textadvancedsearch_ [l=hr] {TraÅŸi _indexselection_ _If_(_jselection_,of _jselection_) _If_(_gselection_, at _gselection_ level)_If_(_nselection_, in _nselection_ language) koristeÄi _querytypeselection_ upite}
+
+_textformsimplesearch_ [l=hr] {TraÅŸi prema _If_(_jselection_, _jselection_) _If_(_gselection_, at _gselection_ level) _If_(_nselection_, in _nselection_ language)
+koji sadrÅŸi _formquerytypeselection_ of}
+
+_textformadvancedsearch_ [l=hr] {TraÅŸi _If_(_jselection_,_jselection_) _If_(_gselection_, at _gselection_ level)_If_(_nselection_, in _nselection_ language) 
+i prikaÅŸi rezultate po _formquerytypeselection_ redu}
+
+
+# -- Missing translation: _textnojsformwarning_
+# -- Missing translation: _textdatesearch_
+# -- Missing translation: _textstartdate_
+# -- Missing translation: _textenddate_
+# -- Missing translation: _textbc_
+# -- Missing translation: _textad_
+# -- Missing translation: _textexplaineras_
+
+_textstemon_ [l=hr] {(ne uzima u obzir krajeve rijeÄi)}
+
+_textsearchhistory_ [l=hr] {Popis prethodnih pretraÅŸivanja}
+
+#text macros for search history
+_textnohistory_ [l=hr] {Popis prethodnih pretraÅŸivanja nije dostupan}
+_texthresult_ [l=hr] {rezultat}
+_texthresults_ [l=hr] {rezultata}
+_texthallwords_ [l=hr] {sve rijeÄi}
+_texthsomewords_ [l=hr] {neke rijeÄi}
+_texthboolean_ [l=hr] {booleov}
+_texthranked_ [l=hr] {nizan}
+_texthcaseon_ [l=hr] {prepoznaje velika slova}
+_texthcaseoff_ [l=hr] {ne prepoznaje velika slova}
+_texthstemon_ [l=hr] {nepotpuna rijeÄ}
+_texthstemoff_ [l=hr] {potpuna rijeÄ}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "traÅŸi" ## green_title ## h_search ##
+_httpiconhsearch_ [l=hr] {_httpimg_/hr/h_search.gif}
+_widthhsearch_ [l=hr] {200}
+_heighthsearch_ [l=hr] {57}
+
+## "rezultati" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=hr] {_httpimg_/hr/qryresb.gif}
+_widthqryresb_ [l=hr] {_pagewidth_}
+_heightqryresb_ [l=hr] {17}
+
+## "popis prethodnih pretraÅŸivanja" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=hr] {_httpimg_/hr/schhistb.gif}
+_widthsrchhistb_ [l=hr] {_pagewidth_}
+_heightsrchhistb_ [l=hr] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=hr] {Postavke su podeÅ¡ene kako slijedi. Ne koristite gumb za povratak u pregledniku
+kako bi postavljene vrijednosti i saÄuvali! Umjesto toga, kliknite na 
+jednu od gornjih poveznica za nastavak. }
+_textsetprefs_ [l=hr] {podesi postavke}
+_textsearchprefs_ [l=hr] {Postavke pretraÅŸivanja}
+_textcollectionprefs_ [l=hr] {Postavke zbirke}
+_textpresentationprefs_ [l=hr] {Postavke prezentacije ili prikaza}
+_textpreferences_ [l=hr] {Postavke}
+_textcasediffs_ [l=hr] {Razlika izmeÄu malih i velikih slova:}
+_textignorecase_ [l=hr] {ne uzimaj u obzir razliku izmeÄu malih i velikih slova}
+_textmatchcase_ [l=hr] {razlika izmeÄu malih i velikih slova mora biti uzeta u obzir:}
+_textwordends_ [l=hr] {Krajevi rijeÄi:}
+_textstem_ [l=hr] {ne uzimaj u obzir krajeve rijeÄi}
+_textnostem_ [l=hr] {cijela rijeÄ mora biti uzeta u obzir}
+_textprefop_ [l=hr] {Vrati do _maxdocoption_ zadovoljavajuÄih odgovora na upit i prikaÅŸi ih _hitsperpageoption_ po stranici.}
+_textextlink_ [l=hr] {Pristup vanjskim mreÅŸnim stranicama:}
+_textintlink_ [l=hr] {Izvorni dokumenti pronaÄeni u:}
+_textlanguage_ [l=hr] {Jezik suÄelja:}
+_textencoding_ [l=hr] {Kodiranje:}
+_textformat_ [l=hr] {Format suÄelja:}
+_textall_ [l=hr] {sve}
+_textquerymode_ [l=hr] {NaÄini pretraÅŸivanja:}
+_textsimplemode_ [l=hr] {jednostavno pretraÅŸivanje}
+_textadvancedmode_ [l=hr] {napredno pretraÅŸivanje (dopuÅ¡tena uporaba Booleovih operatora !, &, |, i zagrada)}
+_textlinkinterm_ [l=hr] {kroz posredniÄku stranicu}
+_textlinkdirect_ [l=hr] {idi izravno tamo}
+_textdigitlib_ [l=hr] {digitalna knjiÅŸnica}
+_textweb_ [l=hr] {web}
+_textgraphical_ [l=hr] {GrafiÄko}
+_texttextual_ [l=hr] {Tekstualno}
+_textcollectionoption_ [l=hr] {<p>
+Subcollections to include:
+<br>}
+
+_textrelateddocdisplay_ [l=hr] {prikaÅŸi srodne dokumente}
+_textsearchhistory_ [l=hr] {Popis prethodnih pretraÅŸivanja:}
+# -- Missing translation: _textnohistory_
+_texthistorydisplay_ [l=hr] {prikaÅŸi _historynumrecords_ popis prethodnih pretraÅŸivanja}
+_textnohistorydisplay_ [l=hr] {nemoj prikazati popis prethodnih pretraÅŸivanja}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=hr] {obrazac pretraÅŸivanja}
+# -- Missing translation: _textplainsearch_
+_textqueryboxsize_ [l=hr] {VeliÄina okvira za upit:}
+_textregbox_ [l=hr] {obiÄni okvir za upit}
+_textbigbox_ [l=hr] {veliki okvir za upit}
+_textformtype_ [l=hr] {Tip obrasca:}
+_textsimple_ [l=hr] {jednostavno}
+_textadvanced_ [l=hr] {napredno}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=hr] {sa}
+_textfields_ [l=hr] {polja}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "POSTAVKE" ## green_title ## h_pref ##
+_httpiconhpref_ [l=hr] {_httpimg_/hr/h_pref.gif}
+_widthhpref_ [l=hr] {200}
+_heighthpref_ [l=hr] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+# -- Missing translation: _textsortby_
+# -- Missing translation: _textalsoshowing_
+# -- Missing translation: _textwith_
+# -- Missing translation: _textdocsperpage_
+
+# -- Missing translation: _textfilterby_
+# -- Missing translation: _textall_
+# -- Missing translation: _textany_
+# -- Missing translation: _textwords_
+# -- Missing translation: _textleaveblank_
+
+# -- Missing translation: _browsebuttontext_
+
+# -- Missing translation: _nodata_
+# -- Missing translation: _docs_
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=hr] {PomoÄ}
+_textSearchshort_ [l=hr] {pretraÅŸivanjem prema pojedinim rijeÄima}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=hr] {pristupom traÅŸenoj graÄi putem naslova}
+_textCreatorshort_ [l=hr] {pristupom traÅŸenoj graÄi putem imena autora}
+_textSubjectshort_ [l=hr] {pristupom traÅŸenoj graÄi preko podruÄja po kojima je razvrstana}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=hr] {pristupom traÅŸenoj graÄi odabirom vremena njenog nastanka}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=hr] {pristupom traÅŸenoj graÄi putem naziva datoteka}
+_textLanguageshort_ [l=hr] {pristupom traÅŸenoj graÄi putem odabira jezika}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=hr] {pristupom traÅŸenoj graÄi putem naziva nizova}
+# -- Missing translation: _textToshort_
+# -- Missing translation: _textFromshort_
+_textBrowseshort_ [l=hr] {pregledavanjem digitalne graÄe}
+_textOrganizationshort_ [l=hr] {pristupom traÅŸenoj graÄi putem naziva organizacija}
+_textHowtoshort_ [l=hr] {pristupom traÅŸenoj graÄi putem "Kako da" kategorije}
+_textTopicshort_ [l=hr] {pristupom traÅŸenoj graÄi putem naziva tema}
+_textPeopleshort_ [l=hr] {pristupom traÅŸenoj graÄi putem imena osoba}
+_textAcronymshort_ [l=hr] {pristupom traÅŸenoj graÄi putem akronima}
+_textPhraseshort_ [l=hr] {pregledavanjem fraza koje se javljaju u digitalnoj graÄi}
+_textArtistshort_ [l=hr] {pristupom traÅŸenoj graÄi putem imena umjetnika}
+_textKeywordshort_ [l=hr] {pristupom traÅŸenoj graÄi putem kljuÄnih rijeÄi}
+# -- Missing translation: _textVolumeshort_
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=hr] {klasifikacijom koja nije definirana}
+
+_textSearchlong_ [l=hr] {<p>MoÅŸete <i>pretraÅŸivati prema pojedinim rijeÄima</i> koje se pojavljuju u tekstu
+ na stranici "traÅŸi". To je prva stranica koja se prikazuje kod otvaranja zbirke 
+, a kojoj se moÅŸe pristupiti sa drugih stranica zbirke pritiskom na gumb 
+ <i>traÅŸi</i>.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem naslova dokumenta i odjeljaka unutar dokumenta</i> pritiskom na gumb
+ <i>naslovi a-z</i>.  Prikazuje se popis naslova prema abecednom redu.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem imena autora</i> pritiskom na gumb
+ <i>autori a-z</i>.  Prikazuje se popis knjiga sortiran prema imenu autora.  }
+
+_textSubjectlong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi preko podruÄja u kojima je razsvrstana</i> pritiskom na gumb
+ <i>podruÄja</i>.  Prikazuje se popis podruÄja po kojima je graÄa razvrstana, reprezentirana tzv. policama za knjige.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi odabirom datuma odnosno vremena njenog nastanka </i> pritiskom na gumb
+ <i>datumi</i>.  Prikazuje se popis svih izdanja sortiran kronoloÅ¡ki.  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=hr] {<p>MoÅŸete <i>pristupiti traÅŸenoj graÄi putem naziva datoteka</i> pritiskom na gumb
+ <i>datoteke</i>.  Prikazuje se popis izvornih datoteka ukljuÄenih u zbirku prema abecednom redu.  }
+
+_textLanguagelong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem odabira jezika</i> pritiskom na gumb
+ <i>jezici</i>.  Prikazuje se popis jezika kojima je zbirka zastupljena.  }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem naziva organizacija
+</i> pritiskom na gumb <i>organizacije</i>.  Prikazuje se popis naziva organizacija. }
+
+_textHowtolong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem "Kako da" kategorije</i>
+pritiskom na gumb <i>kako da</i>.  Prikazuje se popis "Kako da" fraza.  }
+
+_textTopiclong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem naziva tema</i> pritiskom na gumb
+ <i>teme</i>.  Prikazuje se popis zastupljenih tema.  }
+
+# -- Missing translation: _textTolong_
+
+# -- Missing translation: _textFromlong_
+
+_textSerieslong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem naziva nizova</i> pritiskom na gumb
+ <i>nizovi</i>.  Prikazuje se popis nizova koji su trenutno zastupljeni u zbirci.  }
+
+_textBrowselong_ [l=hr] {<p>MoÅŸete <i>pregledavati graÄu</i> pritiskom na gumb
+<i>pregled</i>.  }
+
+_textPeoplelong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem imena osoba</i> pritiskom na gumb
+ <i>ljudi a-z</i>.  Prikazuje se popis osoba sortiran prema njihovim prezimenima.  }
+
+_textAcronymlong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem akronima koji se u njoj javljaju</i> pritiskom na gumb
+ <i>akronimi</i>.  Prikazuje se popis akronima i mjesta gdje se pojavljuju.  }
+
+_textPhraselong_ [l=hr] {<p>MoÅŸete <i>pregledavati fraze koje se javljaju u graÄi</i> pritiskom na gumb
+ <i>fraze</i>.  Prikazuje se popis fraza zastupljenih u zbirci.  }
+
+_textArtistlong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem imena umjetnika</i> pritiskom na gumb
+ <i>umjetnici</i>.  Prikazuje se popis imena umjetnika.  }
+
+_textKeywordlong_ [l=hr] {<p>MoÅŸete <i>pristupiti graÄi putem kljuÄnih rijeÄi</i> pritiskom na gumb <i>kljuÄne rijeÄi</i>. 
+Prikazuje se lista kljuÄnih rijeÄi u obliku kazala. }
+
+# -- Missing translation: _textVolumelong_
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=hr] {<p>Kliknite na gumb <i>nepoznato</i> da pregledavate
+ graÄu (sortiranu prema nepoznatom polju).  }
+
+_texthelptopics_ [l=hr] {<h2 align=left>Teme</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Kako pretraÅŸivati prema pojedinim rijeÄima</a>
+<ul>
+  <li><a href="\#query-terms">TraÅŸeni pojmovi</a>
+  <li><a href="\#query-type">Vrste upita</a>
+  <li><a href="\#scope-of-queries">Opseg upita</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Postavke zbirke</a>
+  <li><a href="\#lang-prefs">JeziÄne postavke</a>
+  <li><a href="\#pres-prefs">Postavke prikaza</a>
+  <li><a href="\#search-prefs">Postavke pretraÅŸivanja</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=hr] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=hr] {Kako Äitati dokumente}
+
+_texthelpreadingdocs_ [l=hr] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Kada otvorite zasebni dokument njegov naslov i autor se pojavljuju u lijevom gornjem kutu stranice 
+(Ponekad to moze biti i slika, naprimjer dobivena skeniranjem korica knjige, koja reprezentira dokument).   
+Pored njih se nalazi podatak o stranici na kojoj se trenutno nalazite, te se nudi moguÄnost odabira sljedeÄe stranice ili povratak na prethodnu. 
+Ove moguÄnosti su opcionalne i moraju se posebno definirati u konfiguracijskim postavkama.
+
+<p>Ispod se prikazuje tekst odjeljka na kojem se trenutno nalazite. Na dnu svake stranice moguÄe je postaviti vodiÄe u obliku strelica 
+koji vode na narednu ili prethodnu stranicu odjeljka.
+
+<p>Ispod naslova i autora odnosno zasebne slike koja predstavlja dokument nalaze se tri gumba. Klikom na <i>prikaÅŸi 
+tekst</i> prikazat Äe se cijeli tekst dokumenta. 
+Ako je rijeÄ o velikom dokumentu moÅŸda Äe trebati vremena da se on uÄita u preglednik. 
+Klikom na <i>novi prozor</i> dokument Äe se otvoriti u novom prozoru preglednika (Ovo je korisno ako ÅŸelite uporediti dokumente ili ih Äitati istovremeno.)  
+KonaÄno, kod pretraÅŸivanja traÅŸeni pojam je u tekstu oznaÄen ÅŸutom bojom.
+Klikom na <i>bez oznacavanja</i> otklanjate ovu moguÄnost.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Klikni na strelicu za prikaz narednog odjeljka...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... ili prikaz prethodnog odjeljka</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>PrikaÅŸi cijeli tekst, ili ne</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Otvori stranicu u novom prozoru</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>OznaÄi traÅŸene pojmove, ili ne</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=hr] {<h2>Kako pretraÅŸivati prema pojedinim rijeÄima</h2>
+<p>
+  Na stranici za pretraÅŸivanje, moÅŸete oblikovati upit na osnovu ovih jednostavnih koraka:<p>
+  
+  <ol><li>PobliÅŸe oznaÄiti traÅŸeni pojam
+      <li>Odrediti hoÄe li se pretraÅŸivanje obaviti prema svim ili samo nekim rijeÄima zadanim u prethodnom koraku
+      <li>Upisati rijeÄi koje ÅŸelite pronaÄi
+      <li>Kliknuti na gumb <i>PoÄetak pretraÅŸivanja</i>
+  </ol>
+
+<p>Na zaslonu Äe se potom prikazati najviÅ¡e dvadeset naslova koji prema definiranim kriterijima 
+zadovoljavaju upit. Pri dnu stranice se nalazi gumb koji omoguÄuje prikaz narednih dvadeset dokumenata itd.
+Klikom na naslov dokumenta prikazuje se tekst dokumenta.
+
+<p>NajviÅ¡e 100 dokumenta koji prema odabranim kriterijima zadovoljavaju upit mogu biti vraÄeni kao rezultati pretrage. 
+Broj prikazanih rezultata moÅŸete takoÄer promijeniti na stranici <i>postavke</i> digitalne zbirke.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>TraÅŸeni pojmovi</h3>
+
+<p>Å to god da unesete u okvir za upit interpretira se kao niz rijeÄi poznat pod nazivom "traÅŸeni pojmovi".
+ Svaki traÅŸeni pojam se moÅŸe sastojati od slova i brojki. Pojmovi su odvojeni razmakom. 
+ Znakovi interpunkcije se zanemaruju te se tretiraju kao razmaci. 
+ To znaÄi da ne moÅŸete pretraÅŸivati putem rijeÄi koje u sebi sadrÅŸe znakove interpunkcije.
+
+<p>Naprimjer, upit<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>biti Äe tretiran kao da ste upisali:<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Vrste upita</h3>
+
+<p>Postoje dvije vrste upita.
+
+<ul>
+  <li>Upiti za <b>sve</b> rijeÄi.  Ova vrsta upita pretraÅŸuje dokumente (ili
+      poglavlja, ili naslove) koji sadrÅŸe sve rijeÄi navedene u upitu.
+      Dokumenti koji zadovoljavaju upit prikazuju se prema abecednom redu.<p>
+
+  <li>Upiti za <b>neke</b> rijeÄi.  Upiti ove vrste vraÄaju popis pojmova koji se najvjerojatnije pojavljuju u dokumentima koji se pretraÅŸuju.
+  Dokumenti se prikazuju prema stupnju zadovoljenja upita. 
+  Kod odreÄivanja stupnja zadovoljenja upita:
+      <p><ul>
+        <li> dokument sadrÅŸi viÅ¡e traÅŸenih pojmova, stupanj je viÅ¡i;
+        <li> rijetki pojmovi su mnogo vaÅŸniji od onih koji se ÄeÅ¡Äe upotrebljavaju;
+        <li> kraÄi dokumenti su bolje rjeÅ¡enje od duljih.
+        </ul>
+</ul>
+
+<p>MoÅŸete koristiti onoliko traÅŸenih pojmova koliko ÅŸelite - cijele reÄenice,
+ili Äak cijele odlomke. Ako specificirate samo jedan pojam, dokumenti u odgovoru Äe biti prikazani u redosljedu prema
+uÄestalosti pojavljivanja traÅŸenog pojma u njima.<p>
+
+_texthelpscope_
+}
+
+# -- Missing translation: _textdatesearch_
+
+# -- Missing translation: _texthelpdatesearch_
+
+_textchangeprefs_ [l=hr] {Izmjena VaÅ¡ih postavki}
+
+_texthelppreferences_ [l=hr] {<h2>_textchangeprefs_</h2>
+
+<p>Ako kliknete na gumb <i>postavke</i> na vrhu svake stranice, moÄi Äe te  
+mijenjati neka svojstva prikaza zbirke u suÄelju, te prema VaÅ¡im ÅŸeljama i potrebama utjecati na neke postavke pretraÅŸivanja.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Postavke zbirki</h3>
+
+Neke zbirke ukljuÄuju viÅ¡e pojedinaÄnih zbirki, koje se onda mogu pretraÅŸivati ili zasebno ili zajedno.
+MoÅŸete odabrati koju pojedinaÄnu zbirku ÅŸelite ukljuÄiti u VaÅ¡e pretraÅŸivanje na stranici Postavke.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>JeziÄne postavke</h3>
+
+Iako svaka zbirka ima odreÄenu vrijednost jezika koji se upotrebljava za predstavljanje zbirke, 
+moÅŸete odabrati i neki drugi jezik.
+Isto tako, moÅŸete promjeniti i kodnu stranicu za zadovoljavajuÄi prikaz znakova u pregledniku.
+Sve zbirke dopuÅ¡taju odabir izmeÄu standardnog grafiÄkog i tekstualnog suÄelja.
+Ovo je naroÄito pogodno za korisnike sa posebnim potrebama koji rabe veÄe ekrane ili 
+sintetizatore govora kao krajnje izlaze.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Postavke prikaza</h3>
+
+Ovisno o pojedinoj zbirci, postoji nekoliko naÄina uspostavljanja nadzora njenog prikaza.
+
+<p>Zbirke mreÅŸnih stranica dopuÅ¡taju neprikazivanje 
+Greenstone navigacijskih gumba na vrhu stranice dokumenata koji zadovoljavaju upit. 
+Drugim rijeÄima, nakon zavrÅ¡enog pretraÅŸivanja moÅŸete uÄitati mreÅŸnu stranicu koja zadovoljava upit 
+bez pojavljivanja bilo kakvog Greenstone zaglavlja na uÄitanoj stranici. 
+Za naredno pretraÅŸivanje prisiljeni ste koristiti opciju preglednika 
+za povratak na prethodnu stranicu (klikom na "back" gumb).  
+Isto tako, ove su zbirke u moguÄnosti sprijeÄiti pojavljivanje Greenstone upozoravajuÄe poruke 
+u sluÄaju klika na poveznicu koja vas vodi izvan zbirke digitalne knjiÅŸnice odnosno na sam Web. 
+U nekim mreÅŸnim zbirkama moÅŸete uÄiniti da poveznice sa stranica izlistanih rezultata 
+vode ravno na pripadajuÄe URL-ove mreÅŸnih stranica koje zadovoljavaju upit a ne na kopije tih 
+dokumenata pohranjenih u digitalnoj zbirci. 
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Postavke pretraÅŸivanja</h3>
+<p>
+Dva para radio-gumba kontroliraju oblik teksta zadanog u upitu. Prvi par 
+(nazvan "Razlika izmeÄu malih i velikih slova") odreÄuje da li je razlikovanje malih i velikih slova u 
+postavljenom upitu vaÅŸna. Drugi par ("Krajevi rijeÄi") odreÄuje hoÄe li krajevi rijeÄi u postavljenom upitu
+biti ignorirani ili ne. Isto tako, postoji moguÄnost postavljanja upita u velikom okviru za upit Å¡to pruÅŸa
+moguÄnost oblikovanja upita putem cijelih odlomaka. To naroÄito pomaÅŸe kod pretraÅŸivanja velike koliÄine 
+teksta.
+
+<p>Naprimjer, ako su odabrane postavke pretraÅŸivanja <i>ignoriraj razliku izmeÄu malih i velikih slova</i> i
+<i>ignoriraj krajeve rijeÄi</i> upit<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>bio bi tretiran isto kao i <p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      jer se veliko slovo u "African", ovim odabranim postavkama pretraÅŸivanja, pretvara u malo slovo
+      , dok se nastavci "n" i "ing" potpuno uklanjaju (naravno, kao i nastavak "s" u rijeÄi "builds").
+
+<p>MoÅŸete odabrati i moguÄnost naprednog pretraÅŸivanja koja dopuÅ¡ta u upitu kombinaciju pojmova i Booleovih operatora AND (&),
+OR (|) i NOT (!). Ovo pridonosi uspjeÅ¡nijem oblikovanju upita.
+Isto tako, moÅŸete ukljuÄiti i Popis prethodnih pretraÅŸivanja Å¡to vam daje moguÄnost 
+laganog preoblikovanja prethodnih upita s ciljem dobivanja Å¡to toÄnijih odgovora. KonaÄno, moÅŸete kontrolirati i broj 
+ vraÄenih odgovora na postavljeni upit jednostavnim odabirom ponuÄenih brojeva u padajuÄem izborniku.
+}
+
+_texttanumbrowseoptions_ [l=hr] {Postoji _numbrowseoptions_ naÄina kako pronaÄi traÅŸenu informaciju u zbirci:}
+
+_textsimplehelpheading_ [l=hr] {Kako pronaÄi traÅŸenu informaciju u _collectionname_ }
+
+_texthelpscope_ [l=hr] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Opseg upita</h3>
+
+<p>
+U veÄini zbirki moÅŸete odabrati pretraÅŸivanje prema razliÄitim indeksima. Primjerice, moÅŸete pretraÅŸivati prema 
+indeksu autora ili naslova. Isto tako, moÅŸete pretraÅŸivati prema indeksima odjeljka ili odlomka. OpÄenito govoreÄi, 
+traÅŸeni dokument je moguÄe pronaÄi neovisno o tome koji se indeks koristi. 
+<p>Ako su dokumenti knjige, otvoriti Äe se upravo na odgovarajuÄim mjestima.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/czech.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/czech.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/czech.dm	(revision 10506)
@@ -0,0 +1,1329 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Czech Language text and icon macros 
+# Many thanks to Roman Chyla and Jakub Rehan (translated 2003 & 2004)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=cs] {Periodika}
+_textsource_ [l=cs] {zdroj }
+_textdate_ [l=cs] {datum publikovÃ¡nÃ­: }
+_textnumpages_ [l=cs] {poÄet stran: }
+
+_textsignin_ [l=cs] {pÅihlÃ¡sit se}
+
+_textdefaultcontent_ [l=cs] {PoÅŸadovanÃ¡ strÃ¡nka nemohla bÃœt nalezena. ProsÃ­me, pouÅŸijte tlaÄÃ­tko 'zpÄt' pro nÃ¡vrat do digitÃ¡lnÃ­ knihovny Greenstone .}
+
+_textdefaulttitle_ [l=cs] {Chyba GSDL}
+
+_textbadcollection_ [l=cs] {Tato kolekce (nazvanÃ¡ "_cvariable_") nenÃ­ nainstalovÃ¡na na tomto systÃ©mu knihovny Greenstone.}
+
+_textselectpage_ [l=cs] {-- Select Page --}
+
+_collectionextra_ [l=cs] {Tato kolekce obsahuje _about:numdocs_ dokumentÅ¯. Byla vytvoÅena pÅed _about:builddate_ dny.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=cs] {<p>Tato kolekce obsahuje _numdocs_ _If_("_numdocs_" eq "1",dokument,documentÅ¯), celkem _numbytes_ B.
+<p><a href="_httppagex_(bsummary)">KliknÄte sem!</a> - souhrn ÃºdajÅ¯ o tÃ©to kolekci.
+}
+
+_textimagecollection_ [l=cs] {}
+_textimageabout_ [l=cs] {O tÃ©to kolekci}
+_textimagehome_ [l=cs] {Homepage}
+_textimagehelp_ [l=cs] {NÃ¡povÄda}
+_textimagepref_ [l=cs] {NastavenÃ­}
+_textimagegreenstone_ [l=cs] {Greenstone Digital Library Software}
+_textimageusab_ [l=cs] {Co se VÃ¡m zdÃ¡lo obtÃ­ÅŸnÃ©?}
+
+_textimagesearch_ [l=cs] {Hledej urÄitÃ© vÃœrazy}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=cs] {ProchÃ¡zej abecednÃ­ seznam nÃ¡zvÅ¯}
+_textimageCreator_ [l=cs] {Listuj abecednÃ­m seznamem autorÅ¯}
+_textimageSubject_ [l=cs] {Listuj pÅedmÄtovÃœmi kategoriemi}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=cs] {ProchÃ¡zej podle data}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=cs] {ProchÃ¡zej podle pÅ¯vodnÃ­ch jmen}
+_textimageLanguage_ [l=cs] {ProchÃ¡zej podle jazyka}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=cs] {ProchÃ¡zej organizace}
+_textimageKeyword_ [l=cs] {ProchÃ¡zej klÃ­ÄovÃ¡ slova}
+_textimageHowto_ [l=cs] {ProchÃ¡zej kategorie 'Jak na to'}
+_textimageList_ [l=cs] {Listuj seznamem dokumentÅ¯}
+_textimageSeries_ [l=cs] {Listuj ÄÃ­sly}
+_textimageTo_ [l=cs] {ProchÃ¡zej podle pole 'Pro:'}
+_textimageFrom_ [l=cs] {ProchÃ¡zej podle pole 'Od'}
+_textimageTopic_ [l=cs] {ProchÃ¡zej speciÃ¡lnÃ­mi kategoriemi}
+_textimageBrowse_ [l=cs] {ProchÃ¡zej}
+_textimageCollage_ [l=cs] {ProchÃ¡zej podle kolÃ¡ÅŸÃ­ obrÃ¡zkÅ¯}
+_textimagePeople_ [l=cs] {Listuj abecednÃ­m seznamem osob}
+_textimageAcronym_ [l=cs] {ProchÃ¡zej zkratky}
+_textimagePhrase_ [l=cs] {ProchÃ¡zej frÃ¡ze}
+_textimageArtist_ [l=cs] {ProchÃ¡zej jmÃ©na umÄlcÅ¯}
+_textimageVolume_ [l=cs] {ProchÃ¡zej podle roÄnÃ­ku}
+_textimageCountries_ [l=cs] {ProchÃ¡zej podle zemÃ­}
+_textimageCaptions_ [l=cs] {ProchÃ¡zej podle popiskÅ¯ fotografiÃ­}
+
+
+_texticontabsearchgreen_ [l=cs] {Hledej}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=cs] {NÃ¡zvy A-Z}
+_texticontabCreatorgreen_ [l=cs] {AutoÅi A-Z}
+_texticontabSubjectgreen_ [l=cs] {PÅedmÄt}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=cs] {Datumy}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=cs] {NÃ¡zvy souborÅ¯}
+_texticontabLanguagegreen_ [l=cs] {Jazyk}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=cs] {Organizace}
+_texticontabKeywordgreen_ [l=cs] {KlÃ­ÄovÃ¡ slova}
+_texticontabhowgreen_ [l=cs] {Jak na to}
+_texticontabseriesgreen_ [l=cs] {ÄÃ­sla}
+_texticontablistgreen_ [l=cs] {Seznam}
+_texticontabtogreen_ [l=cs] {Pro}
+_texticontabfromgreen_ [l=cs] {Od}
+_texticontabtopicgreen_ [l=cs] {TÃ©mata}
+_texticontabbrwsegreen_ [l=cs] {ProchÃ¡zej}
+_texticontabCollagegreen_ [l=cs] {KolÃ¡ÅŸe}
+_texticontabbrowsgreen_ [l=cs] {ProchÃ¡zej}
+_texticontabPeoplegreen_ [l=cs] {LidÃ© A-Z}
+_texticontabAcronymgreen_ [l=cs] {Zkratky}
+_texticontabPhrasegreen_ [l=cs] {FrÃ¡ze}
+_texticontabArtistgreen_ [l=cs] {UmÄlci}
+_texticontabVolumegreen_ [l=cs] {RoÄnÃ­ky}
+_texticontabCaptionsgreen_ [l=cs] {Popisky}
+_texticontabCountriesgreen_ [l=cs] {ZemÄ}
+
+_texticontext_ [l=cs] {Zobraz dokument}
+_texticonclosedbook_ [l=cs] {OtevÅi dokument a ukaÅŸ obsah}
+_texticonnext_ [l=cs] {dalÅ¡Ã­ oddÃ­l}
+_texticonprev_ [l=cs] {pÅedchozÃ­ oddÃ­l}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=cs] {UkaÅŸ MIDI dokument}
+_texticonmsword_ [l=cs] {UkaÅŸ Microsoft Word document}
+_texticonmp3_ [l=cs] {UkaÅŸ MP3 dokument}
+_texticonpdf_ [l=cs] {UkaÅŸ PDF dokument}
+_texticonps_ [l=cs] {UkaÅŸ PostScript dokument}
+_texticonppt_ [l=cs] {UkaÅŸ PowerPoint dokument}
+_texticonrtf_ [l=cs] {UkaÅŸ RTF dokument}
+_texticonxls_ [l=cs] {UkaÅŸ Microsoft Excel dokument}
+
+_page_ [l=cs] {strana }
+_pages_ [l=cs] {strany}
+_of_ [l=cs] {z }
+_vol_ [l=cs] {RoÄ.}
+_num_ [l=cs] {Ä.}
+
+_textmonth00_ [l=cs] {}
+_textmonth01_ [l=cs] {Leden}
+_textmonth02_ [l=cs] {Ãnor}
+_textmonth03_ [l=cs] {BÅezen}
+_textmonth04_ [l=cs] {Duben}
+_textmonth05_ [l=cs] {KvÄten}
+_textmonth06_ [l=cs] {Äerven}
+_textmonth07_ [l=cs] {Äervenec}
+_textmonth08_ [l=cs] {Srpen}
+_textmonth09_ [l=cs] {ZÃ¡ÅÃ­}
+_textmonth10_ [l=cs] {ÅÃ­jen}
+_textmonth11_ [l=cs] {Listopad}
+_textmonth12_ [l=cs] {Prosinec}
+
+_textdocument_ [l=cs] {Dokument}
+_textsection_ [l=cs] {Sekce}
+_textparagraph_ [l=cs] {Odstavec}
+
+_magazines_ [l=cs] {Äasopisy}
+
+_nzdlpagefooter_ [l=cs] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">Projekt New Zealand Digital Library </a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Ãstav poÄÃ­taÄovÃ© vÄdy</a>, 
+<a href="http://www.waikato.ac.nz">Universita Waikato</a>, 
+NovÃœ ZÃ©land}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "DOMÅ®" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=cs] {_httpimg_/cs/chomeof.gif}
+_httpiconchomeon_ [l=cs] {_httpimg_/cs/chomeon.gif}
+
+## "NÃPOVÄDA" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=cs] {_httpimg_/cs/chelpof.gif}
+_httpiconchelpon_ [l=cs] {_httpimg_/cs/chelpon.gif}
+
+## "NASTAVENÃ" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=cs] {_httpimg_/cs/cprefof.gif}
+_httpiconcprefon_ [l=cs] {_httpimg_/cs/cprefon.gif}
+
+## "ODESLAT ZPRÃVU" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=cs] {_httpimg_/cs/cusabof.gif}
+_httpiconcusabon_ [l=cs] {_httpimg_/cs/cusabon.gif}
+
+
+## "hledej" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=cs] {_httpimg_/cs/tsrchgr.gif}
+_httpicontsrchof_ [l=cs] {_httpimg_/cs/tsrchof.gif}
+_httpicontsrchon_ [l=cs] {_httpimg_/cs/tsrchon.gif}
+_widthtsrchx_ [l=cs] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "nÃ¡zvy a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=cs] {_httpimg_/cs/ttitlgr.gif}
+_httpiconttitleof_ [l=cs] {_httpimg_/cs/ttitlof.gif}
+_httpiconttitleon_ [l=cs] {_httpimg_/cs/ttitlon.gif}
+_widthttitlex_ [l=cs] {87}
+
+# Not true DC, kept for legacy reasons
+## "autoÅi a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=cs] {_httpimg_/cs/tauthgr.gif}
+_httpicontcreatof_ [l=cs] {_httpimg_/cs/tauthof.gif}
+_httpicontcreaton_ [l=cs] {_httpimg_/cs/tauthon.gif}
+_widthtcreatx_ [l=cs] {110}
+
+## "pÅedmÄt" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=cs] {_httpimg_/cs/tsubjgr.gif}
+_httpicontsubjon_ [l=cs] {_httpimg_/cs/tsubjon.gif}
+_httpicontsubjof_ [l=cs] {_httpimg_/cs/tsubjof.gif}
+_widthtsubjx_ [l=cs] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "datum" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=cs] {_httpimg_/cs/tdategr.gif}
+_httpicontdateof_ [l=cs] {_httpimg_/cs/tdateof.gif}
+_httpicontdateon_ [l=cs] {_httpimg_/cs/tdateon.gif}
+_widthtdatex_ [l=cs] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "nÃ¡zvy souborÅ¯" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=cs] {_httpimg_/cs/tsrcgr.gif}
+_httpicontsrcof_ [l=cs] {_httpimg_/cs/tsrcof.gif}
+_httpicontsrcon_ [l=cs] {_httpimg_/cs/tsrcon.gif}
+_widthtsrcx_ [l=cs] {87}
+
+## "jazyk" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=cs] {_httpimg_/cs/tlanggr.gif}
+_httpicontlangon_ [l=cs] {_httpimg_/cs/tlangon.gif}
+_httpicontlangof_ [l=cs] {_httpimg_/cs/tlangof.gif}
+_widthtlangx_ [l=cs] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "ÄÃ­sla" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=cs] {_httpimg_/cs/tsergr.gif}
+_httpicontserof_ [l=cs] {_httpimg_/cs/tserof.gif}
+_httpicontseron_ [l=cs] {_httpimg_/cs/tseron.gif}
+_widthtserx_ [l=cs] {87}
+
+## "pro" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=cs] {_httpimg_/cs/ttogr.gif}
+_httpiconttoon_ [l=cs] {_httpimg_/cs/ttoon.gif}
+_httpiconttoof_ [l=cs] {_httpimg_/cs/ttoof.gif}
+_widthttox_ [l=cs] {87}
+
+## "od" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=cs] {_httpimg_/cs/tfromgr.gif}
+_httpicontfromon_ [l=cs] {_httpimg_/cs/tfromon.gif}
+_httpicontfromof_ [l=cs] {_httpimg_/cs/tfromof.gif}
+_widthtfromx_ [l=cs] {87}
+
+## "organizace" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=cs] {_httpimg_/cs/torggr.gif}
+_httpicontorgon_ [l=cs] {_httpimg_/cs/torgon.gif}
+_httpicontorgof_ [l=cs] {_httpimg_/cs/torgof.gif}
+_widthtorgx_ [l=cs] {114}
+
+## "jak na to" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=cs] {_httpimg_/cs/thowgr.gif}
+_httpiconthowon_ [l=cs] {_httpimg_/cs/thowon.gif}
+_httpiconthowof_ [l=cs] {_httpimg_/cs/thowof.gif}
+_widththowx_ [l=cs] {87}
+
+## "tÃ©mata" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=cs] {_httpimg_/cs/ttopicgr.gif}
+_httpiconttopicon_ [l=cs] {_httpimg_/cs/ttopicon.gif}
+_httpiconttopicof_ [l=cs] {_httpimg_/cs/ttopicof.gif}
+_widthttopicx_ [l=cs] {87}
+
+## "prochÃ¡zet" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=cs] {_httpimg_/cs/tbrwsegr.gif}
+_httpicontbrwseon_ [l=cs] {_httpimg_/cs/tbrwseon.gif}
+_httpicontbrwseof_ [l=cs] {_httpimg_/cs/tbrwseof.gif}
+_widthtbrwsex_ [l=cs] {87}
+
+## "kolÃ¡ÅŸe" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=cs] {_httpimg_/cs/tcollgr.gif}
+_httpicontcollof_ [l=cs] {_httpimg_/cs/tcollof.gif}
+_httpicontcollon_ [l=cs] {_httpimg_/cs/tcollon.gif}
+_widthtcollx_ [l=cs] {87}
+
+## "lidÃ©" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=cs] {_httpimg_/cs/tpeopgr.gif}
+_httpicontpeopof_ [l=cs] {_httpimg_/cs/tpeopof.gif}
+_httpicontpeopon_ [l=cs] {_httpimg_/cs/tpeopon.gif}
+_widthtpeopx_ [l=cs] {97}
+
+## "zkratky" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=cs] {_httpimg_/cs/tacrogr.gif}
+_httpicontacroof_ [l=cs] {_httpimg_/cs/tacroof.gif}
+_httpicontacroon_ [l=cs] {_httpimg_/cs/tacroon.gif}
+_widthtacrox_ [l=cs] {87}
+
+## "frÃ¡ze" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=cs] {_httpimg_/cs/tphrsegr.gif}
+_httpicontphrseof_ [l=cs] {_httpimg_/cs/tphrseof.gif}
+_httpicontphrseon_ [l=cs] {_httpimg_/cs/tphrseon.gif}
+_widthtphrsex_ [l=cs] {87}
+
+## "umÄlci" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=cs] {_httpimg_/cs/tartstgr.gif}
+_httpicontartstof_ [l=cs] {_httpimg_/cs/tartstof.gif}
+_httpicontartston_ [l=cs] {_httpimg_/cs/tartston.gif}
+_widthtartstx_ [l=cs] {87}
+
+## "klÃ­ÄovÃ¡ slova" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=cs] {_httpimg_/cs/tkwgr.gif}
+_httpicontkwof_ [l=cs] {_httpimg_/cs/tkwof.gif}
+_httpicontkwon_ [l=cs] {_httpimg_/cs/tkwon.gif}
+_widthtkwx_ [l=cs] {87}
+
+## "svazky" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=cs] {_httpimg_/cs/tvolgr.gif}
+_httpicontvolof_ [l=cs] {_httpimg_/cs/tvolof.gif}
+_httpicontvolon_ [l=cs] {_httpimg_/cs/tvolon.gif}
+_widthtvolx_ [l=cs] {87}
+
+## "popisky" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=cs] {_httpimg_/cs/tcaptgr.gif}
+_httpicontcaptof_ [l=cs] {_httpimg_/cs/tcaptof.gif}
+_httpicontcapton_ [l=cs] {_httpimg_/cs/tcapton.gif}
+_widthtcaptx_ [l=cs] {87}
+
+## "zemÄ" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=cs] {_httpimg_/cs/tcountgr.gif}
+_httpicontcountof_ [l=cs] {_httpimg_/cs/tcountof.gif}
+_httpicontcounton_ [l=cs] {_httpimg_/cs/tcounton.gif}
+_widthtcountx_ [l=cs] {87}
+
+## "nÃ¡povÄda" ## green_title ## h_help ##
+_httpiconhhelp_ [l=cs] {_httpimg_/cs/h\_help.gif}
+_widthhhelp_ [l=cs] {200}
+_heighthhelp_ [l=cs] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=cs] {O tÃ©to kolekci}
+
+_textsubcols1_ [l=cs] {<p>KompletnÃ­ sbÃ­rka obsahuje urÄitÃœ poÄet kolekcÃ­: _1_ . 
+V souÄasnosti pÅÃ­stupnÃ© jsou:
+<blockquote>}
+
+_textsubcols2_ [l=cs] {</blockquote>
+Na strÃ¡nce 'NastavenÃ­' mÅ¯ÅŸete zkontrolovat (a mÄnit) aktuÃ¡lnÃ­ (sub)kolekce.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "o nÃ¡s" ## green_title ## h_about ##
+_httpiconhabout_ [l=cs] {_httpimg_/cs/h\_about.gif}
+_widthhabout_ [l=cs] {200}
+_heighthabout_ [l=cs] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=cs] {NÃ¡zvy A-Z}
+_texticonhcreat_ [l=cs] {AutoÅi A-Z}
+_texticonhsubj_ [l=cs] {PÅedmÄty}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=cs] {Data}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=cs] {NÃ¡zvy souborÅ¯}
+_texticonhlang_ [l=cs] {Jazyky}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+_texticonhcoll_ [l=cs] {KolÃ¡ÅŸe}
+_texticonhto_ [l=cs] {Pro}
+_texticonhfrom_ [l=cs] {Od}
+_texticonhser_ [l=cs] {ÄÃ­sla}
+_texticonhhow_ [l=cs] {Jak na to}
+_texticonhorg_ [l=cs] {Organizace}
+_texticonhbrwse_ [l=cs] {ProchÃ¡zet}
+_texticonhbrows_ [l=cs] {ProchÃ¡zet}
+_texticonhpeople_ [l=cs] {LidÃ© A-Z}
+_texticonhacronym_ [l=cs] {Zkratky}
+_texticonhphrases_ [l=cs] {FrÃ¡ze}
+_texticonhartist_ [l=cs] {UmÄlci}
+_texticonhkw_ [l=cs] {KlÃ­ÄovÃ¡ slova}
+_texticonhvol_ [l=cs] {RoÄnÃ­ky}
+_texticonhcapt_ [l=cs] {Popisky}
+_texticonhcount_ [l=cs] {ZemÄ}
+
+_texticonopenbookshelf_ [l=cs] {ZavÅi tuto sekci knihovny}
+_texticonclosedbookshelf_ [l=cs] {OtevÅÃ­t tuto sekci knihovny a ukÃ¡zat obsah}
+_texticonopenbook_ [l=cs] {ZavÅi tuto knihu}
+_texticonclosedfolder_ [l=cs] {OtevÅÃ­t tuto sloÅŸku a ukÃ¡zat obsah}
+_texticonclosedfolder2_ [l=cs] {OtevÅÃ­t podsekci: }
+_texticonopenfolder_ [l=cs] {ZavÅi tuto sloÅŸku}
+_texticonopenfolder2_ [l=cs] {ZavÅi tuto podsekci: }
+_texticonsmalltext_ [l=cs] {UkaÅŸ tuto sekci textu}
+_texticonsmalltext2_ [l=cs] {UkaÅŸ text: }
+_texticonpointer_ [l=cs] {AktuÃ¡lnÃ­ sekce}
+_texticondetach_ [l=cs] {OtevÅÃ­t tuto strÃ¡nku v novÃ©m oknÄ}
+_texticonhighlight_ [l=cs] {ZvÃœrazni hledanÃ© termÃ­ny}
+_texticonnohighlight_ [l=cs] {NezvÃœrazÅuj hledanÃ© termÃ­ny}
+_texticoncontracttoc_ [l=cs] {Sbalit obsah}
+_texticonexpandtoc_ [l=cs] {Rozvinout obsah}
+_texticonexpandtext_ [l=cs] {UkÃ¡zat veÅ¡kerÃœ text}
+_texticoncontracttext_ [l=cs] {UkÃ¡zat text pouze pro aktuÃ¡lnÃ­ sekci}
+_texticonwarning_ [l=cs] {<b>UpozornÄnÃ­: </b>}
+_texticoncont_ [l=cs] {PokraÄovat?}
+
+_textltwarning_ [l=cs] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_VÃ¡Å¡ prohlÃ­ÅŸeÄ bude muset zobrazit velkÃ© mnoÅŸstvÃ­ textu. _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=cs] {jÃ­t na stranu}
+_textintro_ [l=cs] {<i>(ÃºvodnÃ­ text)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "nÃ¡zvy a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=cs] {_httpimg_/cs/h\_title.gif}
+_widthhtitle_ [l=cs] {200}
+_heighthtitle_ [l=cs] {57}
+
+# Not true DC, kept for legacy reasons
+## "autoÅi a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=cs] {_httpimg_/cs/h\_auth.gif}
+_widthhcreat_ [l=cs] {200}
+_heighthcreat_ [l=cs] {57}
+
+## "pÅedmÄty" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=cs] {_httpimg_/cs/h\_subj.gif}
+_widthhsubj_ [l=cs] {200}
+_heighthsubj_ [l=cs] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "datum" ## green_title ## h_date ##
+_httpiconhdate_ [l=cs] {_httpimg_/cs/h\_date.gif}
+_widthhdate_ [l=cs] {200}
+_heighthdate_ [l=cs] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "nÃ¡zvy souborÅ¯" ## green_title ## h_src ##
+_httpiconhsrc_ [l=cs] {_httpimg_/cs/h\_src.gif}
+_widthhsrc_ [l=cs] {200}
+_heighthsrc_ [l=cs] {57}
+
+## "jazyk" ## green_title ## h_lang ##
+_httpiconhlang_ [l=cs] {_httpimg_/cs/h\_lang.gif}
+_widthhlang_ [l=cs] {200}
+_heighthlang_ [l=cs] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "pro" ## green_title ## h_to ##
+_httpiconhto_ [l=cs] {_httpimg_/cs/h\_to.gif}
+_widthhto_ [l=cs] {200}
+_heighthto_ [l=cs] {57}
+
+## "od" ## green_title ## h_from ##
+_httpiconhfrom_ [l=cs] {_httpimg_/cs/h\_from.gif}
+_widthhfrom_ [l=cs] {200}
+_heighthfrom_ [l=cs] {57}
+
+## "ÄÃ­sla" ## green_title ## h_ser ##
+_httpiconhser_ [l=cs] {_httpimg_/cs/h\_ser.gif}
+_widthhser_ [l=cs] {200}
+_heighthser_ [l=cs] {57}
+
+## "jak na to" ## green_title ## h_how ##
+_httpiconhhow_ [l=cs] {_httpimg_/cs/h\_how.gif}
+_widthhhow_ [l=cs] {200}
+_heighthhow_ [l=cs] {57}
+
+## "tÃ©mata" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=cs] {_httpimg_/cs/h\_topic.gif}
+_widthhtopic_ [l=cs] {200}
+_heighthtopic_ [l=cs] {57}
+
+## "organizace" ## green_title ## h_org ##
+_httpiconhorg_ [l=cs] {_httpimg_/cs/h\_org.gif}
+_widthhorg_ [l=cs] {250}
+_heighthorg_ [l=cs] {57}
+
+## "prochÃ¡zet" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=cs] {_httpimg_/cs/h\_brwse.gif}
+_widthhbrwse_ [l=cs] {200}
+_heighthbrwse_ [l=cs] {57}
+
+# -- Missing translation: h_coll
+_httpiconhcoll_ [l=cs] {_httpimg_/cs/h\_coll.gif}
+_widthhcoll_ [l=cs] {200}
+_heighthcoll_ [l=cs] {57}
+
+## "lidÃ©" ## green_title ## h_people ##
+_httpiconhpeople_ [l=cs] {_httpimg_/cs/h\_people.gif}
+_widthhpeople_ [l=cs] {200}
+_heighthpeople_ [l=cs] {57}
+
+## "zkratky" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=cs] {_httpimg_/cs/h\_acro.gif}
+_widthhacronym_ [l=cs] {200}
+_heighthacronym_ [l=cs] {57}
+
+## "frÃ¡ze" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=cs] {_httpimg_/cs/h\_phrse.gif}
+_widthhphrse_ [l=cs] {200}
+_heighthphrse_ [l=cs] {57}
+
+## "umÄlci" ## green_title ## h_artist ##
+_httpiconhartist_ [l=cs] {_httpimg_/cs/h\_artist.gif}
+_widthhartist_ [l=cs] {200}
+_heighthartist_ [l=cs] {57}
+
+## "klÃ­ÄovÃ¡ slova" ## green_title ## h_kw ##
+_httpiconhkw_ [l=cs] {_httpimg_/cs/h\_kw.gif}
+_widthhkw_ [l=cs] {200}
+_heighthkw_ [l=cs] {57}
+
+## "roÄnÃ­ky" ## green_title ## h_vol ##
+_httpiconhvol_ [l=cs] {_httpimg_/cs/h\_vol.gif}
+_widthhvol_ [l=cs] {200}
+_heighthvol_ [l=cs] {57}
+
+## "zemÄ" ## green_title ## h_count ##
+_httpiconhcount_ [l=cs] {_httpimg_/cs/h\_count.gif}
+_widthhcount_ [l=cs] {200}
+_heighthcount_ [l=cs] {57}
+
+## "popisky" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=cs] {_httpimg_/cs/h\_capt.gif}
+_widthhcapt_ [l=cs] {200}
+_heighthcapt_ [l=cs] {57}
+
+
+## "POKRAÄOVAT??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=cs] {_httpimg_/cs/contof.gif}
+_httpiconconton_ [l=cs] {_httpimg_/cs/conton.gif}
+
+## "ROZVINOUT\nTEXT" ## document_button ## eallt ##
+_httpiconealltof_ [l=cs] {_httpimg_/cs/ealltof.gif}
+_httpiconeallton_ [l=cs] {_httpimg_/cs/eallton.gif}
+
+## "SBALIT\nOBSAH" ## document_button ## econc ##
+_httpiconeconcof_ [l=cs] {_httpimg_/cs/econcof.gif}
+_httpiconeconcon_ [l=cs] {_httpimg_/cs/econcon.gif}
+
+## "OTEVÅÃT V\nNOVÃM OKNÄ" ## document_button ## edtch ##
+_httpiconedtchof_ [l=cs] {_httpimg_/cs/edtchof.gif}
+_httpiconedtchon_ [l=cs] {_httpimg_/cs/edtchon.gif}
+
+## "ROZVINOUT\nOBSAH" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=cs] {_httpimg_/cs/eexpcof.gif}
+_httpiconeexpcon_ [l=cs] {_httpimg_/cs/eexpcon.gif}
+
+## "SBALIT\nTEXT" ## document_button ## etsec ##
+_httpiconetsecof_ [l=cs] {_httpimg_/cs/etsecof.gif}
+_httpiconetsecon_ [l=cs] {_httpimg_/cs/etsecon.gif}
+
+## "ZVÃRAZNÄNÃ" ## document_button ## ehl ##
+_httpiconehlof_ [l=cs] {_httpimg_/cs/ehlof.gif}
+_httpiconehlon_ [l=cs] {_httpimg_/cs/ehlon.gif}
+
+## "BEZ\nZVÃRAZNÄNÃ" ## document_button ## enhl ##
+_httpiconenhlof_ [l=cs] {_httpimg_/cs/enhlof.gif}
+_httpiconenhlon_ [l=cs] {_httpimg_/cs/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=cs] {_If_(_thislast_,vÃœsledky _thisfirst_ - _thislast_ na dotaz: _cgiargq_,ÅœÃ¡dnÃ© vÃœsledky na dotaz: _cgiargq_)}
+_textnoquerytitle_ [l=cs] {VyhledÃ¡vacÃ­ strana}
+
+_texticonthispage_ [l=cs] {hledej}
+_textsome_ [l=cs] {nÄkterÃ¡}
+_textall_ [l=cs] {vÅ¡echny}
+_textboolean_ [l=cs] {booleovskÃ©}
+_textranked_ [l=cs] {klasifikovanÃœ}
+_textnatural_ [l=cs] {pÅirozenÃœ}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=cs] {}
+_texticonsearchhistorybar_ [l=cs] {historie dotazÅ¯}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=cs] {pouÅŸij tento dotaz}
+_textfreqmsg1_ [l=cs] {PoÄet slov: }
+_textpostprocess_ [l=cs] {_If_(_quotedquery_,<br><i>zpracovÃ¡no kvÅ¯li vyhledÃ¡nÃ­ _quotedquery_</i>
+)}
+_textinvalidquery_ [l=cs] {Å patnÃ¡ syntaxe dotazu}
+
+_textmorethan_ [l=cs] {VÃ­ce neÅŸ }
+_textapprox_ [l=cs] {Kolem }
+_textnodocs_ [l=cs] {Nebyl nalezen ÅŸÃ¡dnÃœ dokument. Zkontrolujte prosÃ­m dotaz a nastavenÃ­.}
+_text1doc_ [l=cs] {Nalezen  1  dokument.}
+_textlotsdocs_ [l=cs] {dokument(Å¯) souhlasÃ­ s dotazem.}
+_textmatches_ [l=cs] {VÃœsledky}
+_textbeginsearch_ [l=cs] {Hledej}
+_textrunquery_ [l=cs] {SpusÅ¥ dotaz}
+_textclearform_ [l=cs] {VymaÅŸ formulÃ¡Å}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=cs] {Slovo nebo frÃ¡zi}
+_textinfield_ [l=cs] {... v poli}
+_textfoldstem_ [l=cs] {(velikost znakÅ¯, stemming)}
+
+_textadvquery_ [l=cs] {Nebo zadejte dotaz pÅÃ­mo:}
+_textallfields_ [l=cs] {VÅ¡echna pole}
+_texttextonly_ [l=cs] {poue text}
+_textand_ [l=cs] {a}
+_textor_ [l=cs] {nebo}
+_textandnot_ [l=cs] {a ne}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=cs] {Hledej _indexselection_ _If_(_jselection_, z _jselection_) _If_(_gselection_, na _gselection_ Ãºrovni) _If_(_nselection_, v jazyce _nselection_ ) obsahujÃ­cÃ­ _querytypeselection_ ze slov}
+
+_textadvancedsearch_ [l=cs] {Hledej _indexselection_ _If_(_jselection_,z _jselection_) _If_(_gselection_, na Ãºrovni _gselection_ )_If_(_nselection_, v jazyce _nselection_) pomocÃ­ _querytypeselection_ dotazÅ¯}
+
+_textformsimplesearch_ [l=cs] {Hledej _If_(_jselection_, _jselection_) _If_(_gselection_, na Ãºrovni _gselection_) _If_(_nselection_, v jazyce _nselection_)
+obsahujÃ­cÃ­ _formquerytypeselection_ z}
+
+_textformadvancedsearch_ [l=cs] {Hledej _If_(_jselection_,_jselection_) _If_(_gselection_, na Ãºrovni _gselection_)_If_(_nselection_, v jazyce _nselection_) 
+a zobraz vÃœsledky v _formquerytypeselection_ poÅadÃ­}
+
+
+_textnojsformwarning_ [l=cs] {UpozoznÄnÃ­: Javascript nenÃ­ ve vaÅ¡em prohlÃ­ÅŸeÄÃ­ povolen.<br>Chcete-li pouÅŸÃ­t prohledÃ¡vÃ¡nÃ­ podle polÃ­, prosÃ­m povolte jeho spouÅ¡tÄnÃ­.}
+_textdatesearch_ [l=cs] {V tÃ©to kolekci mÅ¯ÅŸete hledat dokumenty podle urÄitÃ©ho data, a nebo dokumenty v rÃ¡mci urÄitÃ©ho ÄasovÃ©ho rozmezÃ­. Je to volitelnÃ¡ moÅŸnost vyhledÃ¡vÃ¡nÃ­.}
+_textstartdate_ [l=cs] {PoÄÃ¡teÄnÃ­ (nebo jedinÃ©) datum:}
+_textenddate_ [l=cs] {KoncovÃ© datum:}
+_textbc_ [l=cs] {pÅ.n.l.}
+_textad_ [l=cs] {n.l.}
+_textexplaineras_ [l=cs] {C.E. a B.C.E pÅedstavujÃ­ alternativu pro A.D.(naÅ¡eho letopoÄtu) a B.C.(PÅed Kristem).  C.E. a B.C.E. jsou poklÃ¡dÃ¡ny za kulturnÄ nezÃ¡vislÃ¡ ÄasovÃ¡ vymezenÃ­. Zkratky jsou rozepsÃ¡ny jako 'Common Era' a 'Before the Common Era'}
+
+_textstemon_ [l=cs] {(ignoruj (anglickÃ©) koncovky)}
+
+_textsearchhistory_ [l=cs] {Historie dotazÅ¯}
+
+#text macros for search history
+_textnohistory_ [l=cs] {Historie dotazÅ¯ nenÃ­ dostupnÃ¡}
+_texthresult_ [l=cs] {vÃœsledek}
+_texthresults_ [l=cs] {zÃ¡znamÅ¯}
+_texthallwords_ [l=cs] {vÅ¡echna slova}
+_texthsomewords_ [l=cs] {nejmÃ©nÄ 1 slovo}
+_texthboolean_ [l=cs] {booleovskÃœ}
+_texthranked_ [l=cs] {klasifikovanÃœ}
+_texthcaseon_ [l=cs] {zÃ¡leÅŸÃ­ na velikosti pÃ­sma}
+_texthcaseoff_ [l=cs] {nezÃ¡leÅŸÃ­ na velikosti pÃ­sma}
+_texthstemon_ [l=cs] {automatickÃ© doplnÄnÃ­ koncovek }
+_texthstemoff_ [l=cs] {celÃ© slovo musÃ­ souhlasit}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "hledej" ## green_title ## h_search ##
+_httpiconhsearch_ [l=cs] {_httpimg_/cs/h\_search.gif}
+_widthhsearch_ [l=cs] {200}
+_heighthsearch_ [l=cs] {57}
+
+## "vÃœsledky" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=cs] {_httpimg_/cs/qryresb.gif}
+_widthqryresb_ [l=cs] {_pagewidth_}
+_heightqryresb_ [l=cs] {17}
+
+## "historie" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=cs] {_httpimg_/cs/schhistb.gif}
+_widthsrchhistb_ [l=cs] {_pagewidth_}
+_heightsrchhistb_ [l=cs] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=cs] {NastavenÃ­ bya zmÄnÄna. NepouÅŸÃ­vejte tlaÄÃ­tka "zpÄt" - zmÄna by se neprojevila! PouÅŸijte nÄkterÃ© z tlaÄÃ­tek na naÅ¡em navigaÄnÃ­m panelu.
+}
+_textsetprefs_ [l=cs] {uloÅŸ nastavenÃ­}
+_textsearchprefs_ [l=cs] {NastavenÃ­ vyhledÃ¡vÃ¡nÃ­}
+_textcollectionprefs_ [l=cs] {NastavenÃ­ pro kolekce}
+_textpresentationprefs_ [l=cs] {NastavenÃ­ prezentace}
+_textpreferences_ [l=cs] {NastavenÃ­}
+_textcasediffs_ [l=cs] {VELKÃ,malÃ¡ pÃ­smena:}
+_textignorecase_ [l=cs] {ignoruj velikost znakÅ¯}
+_textmatchcase_ [l=cs] {velkÃ¡/malÃ¡ pÃ­smena musÃ­ souhlasit}
+_textwordends_ [l=cs] {AnglickÃ© koncovky:}
+_textstem_ [l=cs] {automaticky doplÅ}
+_textnostem_ [l=cs] {celÃ¡ slova musÃ­ souhlasit}
+_textprefop_ [l=cs] {Vyhledej _maxdocoption_ zÃ¡znamÅ¯. Zobraz _hitsperpageoption_ na jednÃ© strÃ¡nce.}
+_textextlink_ [l=cs] {PÅÃ­stup k externÃ­m webovÃœm strÃ¡nkÃ¡m:}
+_textintlink_ [l=cs] {ZdrojovÃ© dokumenty zÃ­skÃ¡ny z:}
+_textlanguage_ [l=cs] {Jazyk rozhranÃ­:}
+_textencoding_ [l=cs] {KÃ³dovÃ¡nÃ­:}
+_textformat_ [l=cs] {FormÃ¡t rozhranÃ­:}
+_textall_ [l=cs] {vÅ¡echny}
+_textquerymode_ [l=cs] {MÃ³d dotazu:}
+_textsimplemode_ [l=cs] {jednoduchÃœ dotaz}
+_textadvancedmode_ [l=cs] {rozÅ¡Ã­ÅenÃœ dotaz (booleovskÃ© operÃ¡tory &, |, ! a zÃ¡vorky)}
+_textlinkinterm_ [l=cs] {pÅes vloÅŸenou strÃ¡nku}
+_textlinkdirect_ [l=cs] {jdi tam pÅÃ­mo}
+_textdigitlib_ [l=cs] {digitÃ¡lnÃ­ knihovna}
+_textweb_ [l=cs] {web}
+_textgraphical_ [l=cs] {GrafickÃœ}
+_texttextual_ [l=cs] {TextovÃœ}
+_textcollectionoption_ [l=cs] {<p>
+Subkolekce k zobrazenÃ­:
+<br>}
+
+_textrelateddocdisplay_ [l=cs] {zobraz pÅÃ­buznÃ© dokumenty}
+_textsearchhistory_ [l=cs] {Historie dotazÅ¯}
+_textnohistory_ [l=cs] {Historie dotazÅ¯ nenÃ­ dostupnÃ¡}
+_texthistorydisplay_ [l=cs] {ukaÅŸ _historynumrecords_ poslednÃ­ch dotazÅ¯}
+_textnohistorydisplay_ [l=cs] {nozobrazuj historii dotazÅ¯}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=cs] {Do polÃ­:}
+_textplainsearch_ [l=cs] {JednoduchÃ© hledÃ¡nÃ­:}
+_textqueryboxsize_ [l=cs] {Velikost formulÃ¡Åe:}
+_textregbox_ [l=cs] {normÃ¡lnÃ­}
+_textbigbox_ [l=cs] {zvÄtÅ¡enÃœ}
+_textformtype_ [l=cs] {Forma dotazu:}
+_textsimple_ [l=cs] {jednoduchÃœ}
+_textadvanced_ [l=cs] {rozÅ¡Ã­ÅenÃœ}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=cs] {s}
+_textfields_ [l=cs] {pole}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "nastavenÃ­" ## green_title ## h_pref ##
+_httpiconhpref_ [l=cs] {_httpimg_/cs/h\_pref.gif}
+_widthhpref_ [l=cs] {200}
+_heighthpref_ [l=cs] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=cs] {SetÅiÄ dokumenty podle}
+_textalsoshowing_ [l=cs] {ukazujÃ­cÃ­ takÃ©}
+_textwith_ [l=cs] {nejvÃœÅ¡e s}
+_textdocsperpage_ [l=cs] {dokumenty na strÃ¡nce}
+
+_textfilterby_ [l=cs] {Jen dokumenty obsahujÃ­cÃ­}
+_textall_ [l=cs] {vÅ¡echny}
+_textany_ [l=cs] {jakÃ¡koliv}
+_textwords_ [l=cs] {ze slov}
+_textleaveblank_ [l=cs] {ponechte toto pole prÃ¡zdnÃ©, chcete-li obdrÅŸet vÅ¡echny dokumenty}
+
+_browsebuttontext_ [l=cs] {"SetÅiÄ dokumenty"}
+
+_nodata_ [l=cs] {<i>ÅŸÃ¡dnÃ¡ data</i>}
+_docs_ [l=cs] {dokumenty}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=cs] {NÃ¡povÄda}
+_textSearchshort_ [l=cs] {hledÃ¡nÃ­ konkrÃ©tnÃ­ch slov}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=cs] {prochÃ¡zet dokumenty podle nÃ¡zvÅ¯}
+_textCreatorshort_ [l=cs] {prochÃ¡zet dokumenty podle autorÅ¯}
+_textSubjectshort_ [l=cs] {prochÃ¡zet dokumenty podle pÅedmÄtÅ¯}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=cs] {prochÃ¡zet dokumenty podle datumÅ¯}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=cs] {prochÃ¡zet dokumenty podle nÃ¡zvÅ¯ souborÅ¯}
+_textLanguageshort_ [l=cs] {prochÃ¡zet dokumenty podle jazykÅ¯}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=cs] {prochÃ¡zet dokumenty podle ÄÃ­sel}
+_textToshort_ [l=cs] {prochÃ¡zet dokumenty podle pole 'Pro'}
+_textFromshort_ [l=cs] {prochÃ¡zet dokumenty podle pole 'Od'}
+_textBrowseshort_ [l=cs] {prochÃ¡zet dokumenty}
+_textOrganizationshort_ [l=cs] {prochÃ¡zet dokumenty podle organizacÃ­}
+_textHowtoshort_ [l=cs] {prochÃ¡zenÃ­ dokumentÅ¯ pomocÃ­ poloÅŸek 'jak na to'}
+_textTopicshort_ [l=cs] {prochÃ¡zet dokumenty podle tÃ©mat}
+_textPeopleshort_ [l=cs] {prochÃ¡zet dokumenty podle lidÃ­}
+_textAcronymshort_ [l=cs] {prochÃ¡zet dokumenty podle vÃœskytu zkratky}
+_textPhraseshort_ [l=cs] {prochÃ¡zet frÃ¡ze vyskytujÃ­cÃ­ se v dokumentech}
+_textArtistshort_ [l=cs] {prochÃ¡zet dokumenty podle umÄlcÅ¯}
+_textKeywordshort_ [l=cs] {prochÃ¡zet dokumenty podle klÃ­ÄovÃœch slov}
+_textVolumeshort_ [l=cs] {pÅÃ­stup k dokumentÅ¯ podle roÄnÃ­ku/svazku}
+_textCountriesshort_ [l=cs] {prochÃ¡zet dokumenty podle zemÃ­}
+_textdefaultshorttext_ [l=cs] {nedefinovanÃ¡ klasifikace}
+
+_textSearchlong_ [l=cs] {<p>MÅ¯ÅŸete <i>hledat konkrÃ©tnÃ­ slova</i>, kterÃ¡ se vyskytujÃ­ v textu,
+na strÃ¡nce "hledej". Je to prvnÃ­ strÃ¡nka, kterÃ¡ se zobrazÃ­ kdyÅŸ otevÅete kolekci
+a lze ji kdykoliv pozdÄji otevÅÃ­t  stisknutÃ­m tlaÄÃ­tka <i>hledej</i>.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle nÃ¡zvÅ¯</i>
+stisknutÃ­m tlaÄÃ­tka <i>nÃ¡zvy a-z</i>. TÃ­m zobrazÃ­te seznam dokumentÅ¯ setÅÃ­dÄnÃœch podle nÃ¡zvu.}
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle jejich autorÅ¯</i>
+stisknutÃ­m tlaÄÃ­tka <i>autoÅÃ­ a-z</i>. TÃ­m zobrazÃ­te seznam dokumentÅ¯ setÅÃ­dÄnÃœch podle jmÃ©n autorÅ¯.}
+
+_textSubjectlong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle pÅedmÄtÅ¯</i>
+stisknutÃ­m tlaÄÃ­tka <i>pÅedmety</i>. TÃ­m zobrazÃ­te seznam pÅedmÄtÅ¯, reprezentovanÃœch pomocÃ­ polic knihovny.}
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle datumÅ¯</i>
+stisknutÃ­m tlaÄÃ­tka <i>datumy</i>. TÃ­m zobrazÃ­te seznam vÅ¡ech dokumentÅ¯, setÅÃ­dÄnÃœch podle datumÅ¯ vytvoÅenÃ­.}
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle nÃ¡zvÅ¯ souborÅ¯</i>
+stisknutÃ­m tlaÄÃ­tka <i>nÃ¡zvy souborÅ¯</i>. TÃ­m zobrazÃ­te seznam poloÅŸek setÅÃ­dÄnÃœch podle nÃ¡zvÅ¯ souborÅ¯.}
+
+_textLanguagelong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle jazykÅ¯</i>
+stisknutÃ­m tlaÄÃ­tka <i>jazyky</i>. TÃ­m zobrazÃ­te seznam ploÅŸek setÅÃ­dÄnÃœch podle jazyka.}
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle organizacÃ­</i>
+stisknutÃ­m tlaÄÃ­tka <i>organizace</i>. TÃ­m zobrazÃ­te seznam organizacÃ­.}
+
+_textHowtolong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty pomocÃ­ vÃœpisu poloÅŸek 'Jak na to'</i>
+stisknutÃ­m tlaÄÃ­tka <i>Jak na to</i>. TÃ­m zobrazÃ­te seznam ÅetÄzcÅ¯ 'jak na to'.}
+
+_textTopiclong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle tÃ©mat</i>
+stisknutÃ­m tlaÄÃ­tka <i>tÃ©mata</i>. TÃ­m zobrazÃ­te seznam tÃ©mat k prochÃ¡zenÃ­.}
+
+_textTolong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle obsahu pole 'Pro'</i>
+stisknutÃ­m tlaÄÃ­tka <i>pro</i>. TÃ­m zobrazÃ­te seznam adres.}
+
+_textFromlong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle pole 'Od'</i>
+stisknutÃ­m tlaÄÃ­tka <i>Od</i>. TÃ­m zobrazÃ­te seznam odesilatelÅ¯.}
+
+_textSerieslong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle ÄÃ­sel</i>
+stisknutÃ­m tlaÄÃ­tka <i>ÄÃ­sla</i>. TÃ­m zobrazÃ­te seznam tÄch ÄÃ­sel, kterÃ© jsou aktuÃ¡lnÄ v kolekci.}
+
+_textBrowselong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty</i> stisknutÃ­m tlaÄÃ­tka
+<i>prochÃ¡zet</i>.  }
+
+_textPeoplelong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle lidÃ­</i>
+stisknutÃ­m tlaÄÃ­tka <i>lidÃ©</i>. TÃ­m zobrazÃ­te seznam poloÅŸek setÅÃ­dÄnÃœ podle pÅÃ­jmÄnÃ­.}
+
+_textAcronymlong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle vÃœskytÅ¯ zkratky</i> stisknutÃ­m tlaÄÃ­tka <i>zkratky</i>. 
+TÃ­m zobrazÃ­te seznam zkratek a mÃ­st, ve kterÃœch se vyskytujÃ­.}
+
+_textPhraselong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet frÃ¡ze kterÃ© se vyskytujÃ­ v dokumentech</i>
+stisknutÃ­m tlaÄÃ­tka <i>frÃ¡ze</i>. TÃ­m zobrazÃ­te prohlÃ­ÅŸeÄ frÃ¡zÃ­ Phind.}
+
+_textArtistlong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenety podle umÄlcÅ¯</i> stisknutÃ­m tlaÄÃ­tka <i>umÄlci</i>.
+TÃ­m zobrazÃ­te seznam poloÅŸech setÅÃ­dÄnÃœch podle jmÃ©na umÄlce.}
+
+_textKeywordlong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle klÃ­ÄovÃœch slov</i>
+stisknutÃ­m tlaÄÃ­tka <i>klÃ­ÄovÃ¡ slova</i>. TÃ­m zobrazÃ­te seznam klÃ­ÄovÃœch slov.}
+
+_textVolumelong_ [l=cs] {<p> MÅ¯ÅŸete <i>zobrazit dokumenty podle roÄnÃ­ku</i>. KdyÅŸ zmÃ¡Äknete tlaÄÃ­tko <i>roÄnÃ­kÅ¯</i>, objevÃ­ se seznam roÄnÃ­kÅ¯/svazkÅ¯.}
+
+_textCaptionslong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle popiskÅ¯</i> stisknutÃ­m tlaÄÃ­tka <i>popisky</i>.
+TÃ­m zobrazÃ­te seznam popiskÅ¯.}
+
+_textCountrieslong_ [l=cs] {<p>MÅ¯ÅŸete <i>prochÃ¡zet dokumenty podle zemÃ­</i>
+stisknutÃ­m tlaÄÃ­tka <i>zemÄ</i>. TÃ­m zobrazÃ­te seznam zemÃ­.}
+
+
+_textdefaultlongtext_ [l=cs] {<p>StisknÄte tlaÄÃ­tko <i>neznÃ¡mÃ©</i> pro prochÃ¡zenÃ­ dokumentÅ¯
+(seznam je tÅÃ­dÄn podle neznÃ¡mÃ©ho pole)}
+
+_texthelptopics_ [l=cs] {<h2 align=left>TÃ©mata</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Jak hledat konkrÃ©tnÃ­ slova</a>
+<ul>
+  <li><a href="\#query-terms">VyhledÃ¡vacÃ­ vÃœrazy</a>
+  <li><a href="\#query-type">Druhy dotazÅ¯</a>
+  <li><a href="\#scope-of-queries">Rozsah dotazÅ¯</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">NastavenÃ­ pro kolekce</a>
+  <li><a href="\#lang-prefs">NastavenÃ­ jazyka</a>
+  <li><a href="\#pres-prefs">NastavenÃ­ prezentace</a>
+  <li><a href="\#search-prefs">NastavenÃ­ vyhledÃ¡vÃ¡nÃ­</a>
+</ul>
+</ul>}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=cs] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=cs] {Jak ÄÃ­st dokumenty}
+
+_texthelpreadingdocs_ [l=cs] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>KdyÅŸ se vÃ¡m v hornÃ­ ÄÃ¡sti strÃ¡nky zobrazÃ­ nÃ¡zev dokumentu, fotografie
+nebo pÅebal knihy, poznÃ¡te, ÅŸe jste se dostali ke konkrÃ©tnÃ­mu dokumentu Äi knize.
+V nÄkterÃœch kolekcÃ­ch je zobrazen takÃ© obsah, kdeÅŸto jinÃ© mohou obsahovat
+napÅÃ­klad jen ÄÃ­slo aktuÃ¡lnÃ­ strÃ¡nky spolu s textovÃœm polem pro pÅÃ­mÃœ vÃœbÄr
+strÃ¡nky a Å¡ipkami pro pÅechod na pÅedchozÃ­/nÃ¡sledujÃ­cÃ­ strÃ¡nku. V obsahu
+je aktuÃ¡lnÄ zobrazenÃ¡ strÃ¡nka zvÃœraznÄna tuÄnÄ a obsah lze rovÃ­jet --
+kliknutÃ­ na sloÅŸky je otevÃ­rÃ¡ a zavÃ­rÃ¡; kliknutÃ­ na otevÅenou knihu na vrcholu
+obsahu ji zavÅe.</p>
+
+<p>Pod obsahem (pÅÃ­padnÄ navigacÃ­ mezi strÃ¡nkami) se nachÃ¡zÃ­ text
+vybranÃ© sekce. Jakmile jej pÅeÄtete, mÅ¯ÅŸete pomocÃ­ Å¡ipek v dolnÃ­ ÄÃ¡sti strÃ¡nky
+pÅejÃ­t na dalÅ¡Ã­ sekci nebo se vrÃ¡tit zpÄt k pÅedchozÃ­.</p>
+
+<p>Pod nÃ¡zvem nebo pÅebalem se nachÃ¡zÃ­ nÄkolik tlaÄÃ­tek. KliknutÃ­m na
+<i>rozvinout text</i> se v oknÄ zobrazÃ­ celÃœ text aktuÃ¡lnÃ­ sekce nebo
+knihy. Pokud je dokument velkÃœ, mÅ¯ÅŸe to zabrat dlouhou dobu a spotÅebovat
+znaÄnou ÄÃ¡st operaÄnÃ­ pamÄti! KliknutÃ­m na <i>rozvinout obsah</i> se
+zobrazÃ­ vÅ¡echny ÃºrovnÄ obsahu dokumentu, takÅŸe jsou vidÄt nÃ¡zvy vÅ¡ech 
+kapitol a sekcÃ­. KliknutÃ­m na <i>zobrazit v novÃ©m oknÄ</i> se prohlÃ­ÅŸenÃœ
+dokument otevÅe v novÃ©m oknÄ prohlÃ­ÅŸeÄe (coÅŸ je uÅŸiteÄnÃ©, chcete-li dokumenty
+porovnÃ¡vat nebo ÄÃ­st dva zÃ¡roveÅ). A koneÄnÄ, hledanÃ¡ slova jsou zvÃœraznÄna
+(kliknutÃ­m na <i>bez zvÃœraznÄnÃ­</i> lze zvÃœrazÅovÃ¡nÃ­ slov zruÅ¡it).</p>
+ 
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>OtevÅit tuto polici</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>OtevÅÃ­t/zavÅÃ­t tuto knihu</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>ProhlÃ­ÅŸet tuto sekci textu</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Zobrazit nebo nezobrazovat celÃœ text</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Rozvinout nebo sbalit obsah</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>OtevÅÃ­t strÃ¡nku v novÃ©m onkÄ</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>ZvÃœraznit nebo nezvÃœraÅovat hledanÃ¡ slova</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>KliknutÃ­m na Å¡ipku se dostanete do dalÅ¡Ã­ sekce ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... nebo do pÅedchozÃ­ sekce</td></tr>
+</table>}
+
+_texthelpsearching_ [l=cs] {<h2>Jak hledat konkrÃ©tnÃ­ slova</h2>
+<p>
+  HledÃ¡nÃ­ lze uskuteÄnit pomocÃ­ strÃ¡nky "hledej" provedenÃ­m nÃ¡sledujÃ­ch 
+  jednoduchÃœch krokÅ¯:
+  
+  <ol><li>UrÄete, jakÃ© vÃœrazy chcete vyhledÃ¡vat
+      <li>RozhodnÄte se, zda chcete hledat vÅ¡echna slova vÃœrazu nebo jen nÄkterÃ¡
+      <li>NapiÅ¡te slova, kterÃ¡ chcete vyhledat
+      <li>KliknÄte na tlaÄÃ­tko <i>Hledej</i>
+  </ol>
+
+<p>Po vyhodnocenÃ­ dotazu se na strÃ¡nce zobrazÃ­ nÃ¡zvy prvnÃ­ch dvaceti odpovÃ­dajÃ­cÃ­ch
+dokumentÅ¯. Na konci seznamu je tlaÄÃ­tko, kterÃ© zobrazÃ­ dalÅ¡Ã­ch dvacet vÃœsledkÅ¯.
+Odtamtud mÃ¡te moÅŸnost zobrazit tÅetÃ­ dvacÃ­tku vÃœsledkÅ¯ nebo se vrÃ¡tit k tÃ© prvnÃ­ ...
+a tak podobnÄ pro ostatnÃ­ strÃ¡nky s vÃœsledky. KliknutÃ­ na nÃ¡zev dokumentu nebo na malÃ©
+tlaÄÃ­tko umÃ­stÄnÃ© vedle nÃ¡zvu danÃœ dokument zobrazÃ­.
+
+<p>StandardnÄ je nastaveno nabÃ­dnutÃ­ prvnÃ­ch 100 nalezenÃœch vÃœsledkÅ¯, 
+tento limit lze zmÄnit na strÃ¡nce <i>nastavenÃ­</i> (na kterou se lze
+dostat kliknutÃ­m na stejnojmennÃ© tlaÄÃ­tko umÃ­stÄnÃ© na vrcholu strÃ¡nky)<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>VyhledÃ¡vacÃ­ vÃœrazy</h3>
+
+<p>VÅ¡e co napÃ­Å¡ete do pole pro zadÃ¡vÃ¡nÃ­ dotazÅ¯ je interpretovÃ¡no jako
+seznam slov, nazÃœvanÃœch "vyhledÃ¡vacÃ­ vÃœrazy". KaÅŸdÃœ vÃœraz obsahuje pouze
+znaky abecedy a ÄÃ­slice. VÃœrazy jsou oddÄleny mezerami. VÅ¡echny ostatnÃ­
+znaky (jako je napÅÃ­klad interpunkce) slouÅŸÃ­ jako oddÄlovaÄe vÃœrazÅ¯ stejnÄ jako 
+by to byly mezery a jsou ignorovÃ¡ny. NenÃ­ moÅŸnÃ© hledat slova, kterÃ¡ obsahujÃ­
+interpunkci.
+
+<p>NapÅÃ­klad dotaz<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>bude vyhodnocen stejnÄ jako<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Druhy dotazÅ¯</h3>
+
+<p>ExistujÃ­ dva rÅ¯znÃ© druhy dotazÅ¯.
+
+<ul>
+  <li>Dotazy na <b>vÅ¡echna</b> slova.  PÅi jejich vyhodnocovÃ¡nÃ­ jsou
+      hledÃ¡ny dokumenty, kterÃ© obsahujÃ­ vÅ¡echna zadanÃ¡ slova. VyhovujÃ­cÃ­
+      dokumenty jsou zobrazeny setÅÃ­dÄnÃ© podle abecedy.<p>
+
+  <li>Dotazy na <b>nÄkterÃ¡</b> ze slov. ZadÃ¡te slova, u nichÅŸ je pravdÄpodobnÃ©,
+      ÅŸe se objevÃ­ v odkumentech, kterÃ© hledÃ¡te. Dokumenty jsou potÃ© zobrazeny
+      v poÅadÃ­, kterÃ© odpovÃ­dÃ¡ tomu, do jakÃ© mÃ­ry odpovÃ­dajÃ­ dotazu. PÅi urÄovÃ¡nÃ­ stupnÄ
+      shody,
+
+      <p><ul>
+        <li> ÄÃ­m vÃ­ce hledanÃœch vÃœrazÅ¯ dokument obsahuje, tÃ­m vÃ­ce souhlasÃ­ s dotazem;
+        <li> ojedinÄlÃ© vÃœrazy jsou dÅ¯leÅŸitÄjÅ¡Ã­ neÅŸ ty obvyklÃ©;
+        <li> krÃ¡tkÃ© dokumenty se shodujÃ­ lÃ©pe neÅŸ ty dlouhÃ©.
+      </ul>
+</ul>
+
+<p>PouÅŸÃ­vejte tolik vyhledÃ¡vacÃ­ch vÃœrazÅ¯ kolik uznÃ¡te za vhodnÃ© -- celou vÄtu
+nebo i celÃœ odstavec. Pokud urÄÃ­te pouze jeden vÃœraz, dokumenty budou seÅazeny
+podle frekvence jeho vÃœskytu<p>
+_texthelpscope_}
+
+_textdatesearch_ [l=cs] {ProhledÃ¡vÃ¡nÃ­ v tÃ©to kolekci lze omezit na urÄitÃ© datum v dokumentech obsaÅŸenÃ©, a nebo na urÄitÃ© ÄasovÃ© rozmezÃ­. Toto je nepovinnÃ¡ volba.}
+
+_texthelpdatesearch_ [l=cs] {<h2>_textdatesearch_</h2>
+HledÃ¡nÃ­ podle datumÅ¯ umoÅŸÅuje nalÃ©zt dokumenty, kterÃ© odpovÃ­dajÃ­ hledanÃœm
+vÃœrazÅ¯m a zÃ¡roveÅ spadajÃ­ do urÄitÃ©ho ÄasovÃ©ho obdobÃ­. MÅ¯ÅŸete hledat 
+dokumenty od urÄitÃ©ho roku nebo rozsahu let. VÅ¡imnÄte si, ÅŸe nemusÃ­te
+zadat ÅŸÃ¡dnÃ© hledanÃ© vÃœrazy -- mÅ¯ÅŸete vyhledÃ¡vat jen podle samotnÃ©ho datumu;
+a takÃ© ÅŸe nemusÃ­te pÅi svÃ©m vyhledÃ¡vÃ¡nÃ­ datumy pouÅŸÃ­vat. Pokud nezadÃ¡te
+ÅŸÃ¡dnÃ© datumy, je to stejnÃ©, jako by prohledÃ¡vÃ¡nÃ­ podle datumÅ¯ neexistovalo.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>Jak vyuÅŸÃ­vat tÃ©to moÅŸnosti:</h3>
+<ul>
+   <li>Pro hledÃ¡nÃ­ dokumentÅ¯ tÃœkajÃ­cÃ­ch se jednoho roku:<p>
+   <ul>
+       <li>NapiÅ¡te jakÃœkoliv hledanÃœ vÃœraz stejnÄ jako byste to dÄlali obyÄejnÄ.
+       <li>NapiÅ¡te hledanÃœ rok do pole "Start (or only) date".
+       <li>Pokud vaÅ¡e datum sahÃ¡ do obdobÃ­ pÅed Kristem, vyberte moÅŸnost "B.C.E"
+             z vÃœbÄrovÃ©ho seznamu umÃ­stÄnÃ©ho vedle pole.
+       <li>SpusttÄ vyhledÃ¡vÃ¡nÃ­ jako to dÄlÃ¡te obyÄejnÄ.
+   </ul>
+<p><li>Pro hledÃ¡nÃ­ dokumentÅ¯ tÃœkajÃ­cÃ­ch se ÄasovÃ©ho obdobÃ­ nebo rozsahu let:<p>
+   <ul>
+       <li>NapiÅ¡te jakÃœkoliv hledanÃœ vÃœraz stejnÄ jako byste to dÄlali obyÄejnÄ.
+       <li>NapiÅ¡te dÅÃ­vÄjÅ¡Ã­ hledanÃœ rok do pole "Start (or only) date".
+       <li>NapiÅ¡tÄ pozdÄjÅ¡Ã­ hledanÃœ rok do pole "End date".
+       <li>Vyberte moÅŸnost "B.C.E" vedle polÃ­ s rokem pÅed Kristem.
+       <li>SpusttÄ vyhledÃ¡vÃ¡nÃ­ jako to dÄlÃ¡te obyÄejnÄ.
+   </ul>
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>JakÃœm zpÅ¯sobem jsou hledÃ¡ny vÃœsledky na uvedenÃ© dotazy</h3>
+
+ObecnÄ ÅeÄeno, hledÃ¡nÃ­ dokumentÅ¯ o roce 1903 nevrÃ¡tÃ­ dokumenty, kterÃ© odkazujÃ­ knihy napsanÃ© v roce 1903, ale pouze dokumenty o 1903. NicmÃ©nÄ za pouÅŸÃ­tÃ­ zpÅ¯sobu, kterÃœm jsou hledÃ¡ny datumy dokumentÅ¯, vrÃ¡tÃ­ uvedenÃœ dotaz  dokumenty, kterÃ© majÃ­ pÅiÅazen rozsah datumÅ¯ (napÅÃ­klad 1899-1911) do nejÅŸ spadÃ¡ i hledanÃ© datum. StejnÄ tak budou nalezeny dokumenty, jejichÅŸ textovÃ© nÃ¡zvy obsahujÃ­ stoletÃ­, do nejÅŸ rok 1903 patÅÃ­ (napÅÃ­klad "20th century" nebo "twentieth century"). To znamenÃ¡, ÅŸe pro nÄkterÃ© dokumenty se hledanÃ© datumy nebudou nachÃ¡zet v textu dokumentu. PÅi hledÃ¡nÃ­ ÄasovÃ©ho obdobÃ­ se vÅ¡e co bylo uvedeno vztahuje na kaÅŸdÃœ rok zadanÃ©ho ÄasovÃ©ho rozmezÃ­.<p>
+}
+
+_textchangeprefs_ [l=cs] {ZmÄna vaÅ¡ich nastavenÃ­}
+
+_texthelppreferences_ [l=cs] {<h2>_textchangeprefs_</h2>
+
+<p>KdyÅŸ stisknete tlaÄÃ­tko <i>nastavenÃ­</i>, kterÃ© se nachÃ¡zÃ­ v hornÃ­ ÄÃ¡sti strÃ¡nky,
+budete mÃ­t moÅŸnost mÄnit nÄkterÃ© vlastnosti rozhranÃ­ tak, aby vyhovovaly vaÅ¡Ã­m poÅŸadavkÅ¯m.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>NastavenÃ­ pro kolekce</h3>
+
+NÄkterÃ© kolekce se sklÃ¡dajÃ­ z vÃ­ce podkolekcÃ­, kterÃ© mohou bÃœt prohledÃ¡vÃ¡ny
+nezÃ¡visle nebo najednou jako celek. V takovÃ©m pÅÃ­padÄ mÅ¯ÅŸete na strÃ¡nce
+NastavenÃ­ zvolit, kterÃ© podkolekce majÃ­ bÃœt zahrnuty do vyhledÃ¡vÃ¡nÃ­.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>NastavenÃ­ jazyka</h3>
+
+KaÅŸdÃ¡ kolekce mÃ¡ nastaven vÃœchozÃ­ jazyk, v nÄmÅŸ je zobrazena, ale je moÅŸnÃ©
+zvolit i jazyk jinÃœ. StejnÄ tak je moÅŸnÃ© mÄnit schÃ©ma kÃ³dovÃ¡nÃ­ pouÅŸÃ­vanÃ©
+v rÃ¡mci Greenstone pro zobrazovÃ¡nÃ­ vÃœstupu v prohlÃ­ÅŸeÄi -- software vybere
+smyslupnou vÃœchozÃ­ hodnotu, u nÄkterÃœch prohlÃ­ÅŸeÄÅ¯ je vÅ¡ak lepÅ¡Ã­ zvolit
+kÃ³dovacÃ­ schÃ©ma manuÃ¡lnÄ. VÅ¡echny kolekce vÃ¡m umoÅŸÅujÃ­ zmÄnit standardnÃ­
+grafickÃ© rozhranÃ­ na textovÃ©. To je zvlÃ¡Å¡tÄ uÅŸiteÄnÃ© pro zrakovÄ postiÅŸenÃ©
+uÅŸivatele, kteÅÃ­ pak mohou pouÅŸÃ­vat velkÃ© fonty nebo vÃœstup z hlasovÃ©ho 
+syntetizÃ¡toru.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>NastavenÃ­ prezentace</h3>
+
+V zÃ¡vislosti na kolekcÃ­ch mohou bÃœt k dispozici nÄkterÃ¡ nastavenÃ­, kterÃ¡ ovlivnÃ­
+zpÅ¯sob prezentace.
+
+<p>Kolekce internetovÃœch strÃ¡nek umoÅŸÅujÃ­ zruÅ¡it navigaÄnÃ­ panel Greenstone, kterÃœ je
+umÃ­stÄnÃœ v hornÃ­ ÄÃ¡sti kaÅŸdÃ© strÃ¡nky s dokumentem, takÅŸe po ukonÄenÃ­ vyhledÃ¡vÃ¡nÃ­
+a vÃœbÄru z vÃœsledkÅ¯ se dostanete na konkrÃ©tnÃ­ internetovou strÃ¡nku, kterÃ¡ vÅ¡ak nebude
+obsahovat hlaviÄku Greenstone. Pro dalÅ¡Ã­ vyhledÃ¡vÃ¡nÃ­ musÃ­te ve vaÅ¡em prohlÃ­ÅŸeÄi pouÅŸÃ­t
+tlaÄÃ­tko "zpÃ¡tky". Tyto kolekce takÃ© umoÅŸÅujÃ­ potlaÄit varovnÃ© vÃœpisy systÃ©mu
+Greenstone ve chvÃ­li, kdyÅŸ zvolÃ­te odkaz, kterÃœ vÃ¡s zavede mimo kolekci digitÃ¡lnÃ­
+knihovny - na strÃ¡nky umÃ­stÄnÃ© na internetu. A v nÄkterÃœch internetovÃ© kolekcÃ­ch
+mÅ¯ÅŸete kontrolovat, zda vÃ¡s odkazy na strÃ¡nce vÃœsledkÅ¯ vyhledÃ¡vÃ¡nÃ­ dostanou 
+pÅÃ­mo na danÃ© URL a ne na kopii dokumentu uloÅŸenou v digitÃ¡lnÃ­ knihovnÄ.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>NastavenÃ­ vyhledÃ¡vÃ¡nÃ­</h3>
+<p>ZpÅ¯sob porovnÃ¡vÃ¡nÃ­ textu pÅi vyhledÃ¡vÃ¡nÃ­ ÅÃ­dÃ­ dva pÃ¡ry tlaÄÃ­tek. PrvnÃ­ dvojice
+(oznaÄenÃ¡ "VELKÃ,malÃ¡ pÃ­smena") urÄuje, zda musÃ­ souhlasit velikost pÃ­smen.
+DruhÃ¡ dvojice ("anglickÃ© koncovky" (<i>word endings</i>)) urÄuje, budou ignorovÃ¡ny anglickÃ©
+ koncovky slov. Je moÅŸnÃ© zvolit vÄtÅ¡Ã­ rozmÄr oblasti pro zadÃ¡vÃ¡nÃ­ dotazÅ¯, takÅŸe
+lze snadno provÃ¡dÄt i prohledÃ¡vÃ¡nÃ­ podle obsahu celÃœch odstavcÅ¯. Pro velkÃ© objemy textu
+je pÅekvapivÄ rychlÃ©.
+
+<p>Jsou-li napÅÃ­klad vybrÃ¡na tlaÄÃ­tka <i>ignoruj velikost znakÅ¯</i> a
+<i>automaticky doplÅ</i>, dotaz<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>bude zpracovÃ¡n stejnÄ jako<p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      protoÅŸe velkÃ© pÃ­smeno ve slovÄ "African" bude transformovÃ¡no na
+      malÃ© a ze slov "African" a "building" budou odstranÄny pÅÃ­pony "n" a "ing" (stejnÄ tak bude "s"
+      odstranÄno ze slova "builds").
+
+<p>Je moÅŸnÃ© zvolit "rozÅ¡Ã­ÅenÃœ" mÃ³d vyhledÃ¡vÃ¡nÃ­, kterÃœ dovoluje kombinovat vÃœrazy pomocÃ­
+logickÃœch operÃ¡torÅ¯ AND (&), OR (|), a NOT (!). DÃ­ky tomu je moÅŸnÃ© zadÃ¡vat pÅesnÄjÅ¡Ã­ dotazy.
+Lze takÃ© zapnout moÅŸnost zobrazovÃ¡nÃ­ historie hledÃ¡nÃ­, kterÃ¡ ukazuje nÄkolik poslednÃ­ch dotazÅ¯
+a umoÅŸÅuje snadno opakovat mÃ­rnÄ pozmÄnÄnÃ© dotazy znovu. A koneÄne lze takÃ© urÄit maximÃ¡lnÃ­ poÄet
+vÃœsledkÅ¯, vrÃ¡cenÃœch pÅi hledÃ¡nÃ­ vÃœrazu.}
+
+_texttanumbrowseoptions_ [l=cs] {Existuje _numbrowseoptions_ zpÅ¯sob(Å¯), jak hledat informace v tÃ©to kolekci:}
+
+_textsimplehelpheading_ [l=cs] {Jak hledat informace v kolekci _collectionname_}
+
+_texthelpscope_ [l=cs] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Rozsah dotazÅ¯</h3>
+
+<p>
+Ve vÄtÅ¡inÄ kolekcÃ­ mÅ¯ÅŸete vybrat prohledÃ¡vÃ¡nÃ­ rÅ¯znÃœch indexÅ¯. NapÅÃ­klad mohou existovat
+indexy autorÅ¯ nebo nÃ¡zvÅ¯. Nebo to mohou bÃœt indexy kapitol a odstavcÅ¯. VÃœsledkem
+hledÃ¡nÃ­ jsou vÅŸdy dokumenty, kterÃ© plnÄ odpovÃ­dajÃ­ dotazu - to platÃ­ nezÃ¡visle na 
+prohledÃ¡vanÃ©m indexu.
+<p>JestliÅŸe dokumenty jsou knihami, budou otevÅeny na sprÃ¡vnÃ©m mÃ­stÄ.}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/czech2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/czech2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/czech2.dm	(revision 10506)
@@ -0,0 +1,982 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Czech Language text and icon macros 
+# Many thanks to Roman Chyla and Jakub Rehan (translated 2003 & 2004)
+#
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=cs] {dokumentÅ¯.}
+_lastupdate_ [l=cs] {Naposledy aktualizovÃ¡no}
+_ago_ [l=cs] {dny.}
+_colnotbuilt_ [l=cs] {Kolekce nebyla vytvoÅena.}
+
+_textpagetitle_ [l=cs] {DigitÃ¡lnÃ­ knihovna Greenstone}
+_textadmin_ [l=cs] {StrÃ¡nka administrÃ¡tora}
+_textabgs_ [l=cs] {O Greenstone}
+_textgsdocs_ [l=cs] {Dokumentace Greenstone}
+
+_textimagegli_ [l=cs] {PomÃ¡hÃ¡ vytvÃ¡Ået novÃ© kolekce, upravovat existujÃ­cÃ­ nebo je mazat.}
+
+_textimagecollector_ [l=cs] {PÅedchldce rozhranÃ­ Libraran - pro vÄtÅ¡inu ÃºÄelÅ¯ by mÄlo bÃœt vyuÅŸÃ­vÃ¡no rozhranÃ­ Librarian.}
+
+_textimagetranslator_ [l=cs] {PomÃ¡hÃ¡ udrÅŸet jazykovÃ© mutace Greenstone aktuÃ¡lnÃ­}
+
+_textimageadmin_ [l=cs] {Dovoluje pÅidÃ¡vat novÃ© uÅŸivatele, vytvÃ¡Ået souhrny o kolekcÃ­ch v systÃ©mu a podÃ¡vat technickÃ© informace o instalaci}
+
+_textimagegogreenstone_ [l=cs] {PovÃ­ vÃ¡m o programu Greenstone a o projektu NovozÃ©landskÃ© digitÃ¡lnÃ­ knihovny, kde Greenstone vzniknul}
+
+_textimagegodocs_ [l=cs] {PÅÃ­ruÄky Greenstone}
+
+_textpoem_ [l=cs] {<br>
+<h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino, 
+<br>kia tere te karohirohi, 
+<br>kia papapounamu te moana
+
+<p>kÃ©ÅŸ mÃ­r a vÃ¡nek tÄ provÃ¡zÃ­,
+<br>kÃ©ÅŸ zÅ¯stÃ¡vÃ¡Å¡ ve slunci letnÃ­ho oparu,
+<br>a oceÃ¡n tvÃœch poutÃ­ aÅ¥ je hladkÃœ jako greenstone.}
+
+_textgreenstone_ [l=cs] {<p>
+Greenstone je polodrahokam, kterÃœ (stejnÄ jako tento program) pochÃ¡zÃ­ z NovÃ©ho ZÃ©landu.
+V tradiÄnÃ­ maorskÃ© spoleÄnosti je povaÅŸovÃ¡n za najcennÄjÅ¡Ã­ latku. MÅ¯ÅŸe do sebe pÅijmout
+a podrÅŸet <i>wairua</i>, coÅŸ je "duch" a nebo taky "ÅŸivotnÃ­ sÃ­la". Greenstone je opÅeden
+tradiÄnÃ­mi ctnostmi, kterÃ© z nÄj dÄlajÃ­ vhodnÃœ emblÃ©m pro vÄÅejnÄ-pÅÃ­stupnÃœ projekt digitÃ¡lnÃ­ knihovny
+. Jeho lesk je dobrotivÃœ; jeho prÅ¯svitnost je vzneÅ¡enÃ¡; jeho pevnost odvÃ¡ÅŸnÃ¡ a jeho ostrÃ© hrany spravedlivÃ©. 
+VyÅezÃ¡vanÃœ kÃ¡men, kterÃœ vidÃ­te v logu Greenstone, je <i>patu</i> - bojovÃ¡ zbraÅ. Je to rodinnÃ© dÄdictvÃ­ jednoho
+ze zaklÃ¡dajÃ­cÃ­ch ÄlenÅ¯ Greenstone. V boji mÅ¯ÅŸe proti muÅŸi jsou argumenty <i>patu</i>  velmi rychlÃ©, pÃ¡dnÃ© a zdrcujÃ­cÃ­. 
+RÃ¡di bychom si mysleli, ÅŸe tyto kvality se pÅenÃ¡Å¡ejÃ­ i na nÃ¡Å¡ program; ostÅÃ­ <i>patu</i> je rozhranÃ­m naÅ¡Ã­ technologie.}
+
+_textaboutgreenstone_ [l=cs] {<p>
+Greenstone je balÃ­kem programÅ¯ pro vytvÃ¡ÅenÃ­ a distribuci digitÃ¡lnÃ­ kolekcÃ­. NabÃ­zÃ­ novÃœ zpÅ¯sob organizace
+a publikovÃ¡nÃ­ informacÃ­ na internetu a na discÃ­ch CD-ROM.
+
+<p>Greenstone je vyvÃ­jen v rÃ¡mci projektu <b>New Zealand Digital Library</b> a distribuovÃ¡n v kooperaci
+s <b>UNESCO</b> a s nevlÃ¡dnÃ­ organizacÃ­ <b>Human Info NGO</b>. 
+
+Je to program s otevÅenÃœm kÃ³dem a distribuuje se pod licencÃ­ GNU General Public License
+z <a href"http://greenstone.org">http://greenstone.org</a>.
+<p>
+Tento projekt chce dÃ¡t uÅŸivatelÅ¯m nÃ¡stroje pro vytvÃ¡ÅenÃ­ vlastnÃ­ch digitÃ¡lnÃ­ch kolekcÃ­ (a to zejmÃ©na uÅŸivatelÅ¯ z univerzit,
+knihoven a dalÅ¡Ã­ch veÅejnÄ prospÄÅ¡nÃœch institucÃ­). V ÄlenskÃœch zemÃ­ch UNESCO, ale takÃ© v rozvojovÃœch zemÃ­ch hrajÃ­
+digitÃ¡lnÃ­ knihovny dÅ¯leÅŸitou roli pÅi rozÅ¡iÅovÃ¡nÃ­ iformacÃ­ v oblastech vzdÄlÃ¡vÃ¡nÃ­, vÄdy a kultury. VÄÅÃ­me, ÅŸe tento projekt
+podpoÅÃ­ efektivnÃ­ vyuÅŸitÃ­ digitÃ¡lnÃ­ knihoven v jejich Ãºkolu sdÃ­let a rozÅ¡iÅovat informace ve spoleÄnosti.<p>Tento software
+je vyvÃ­jen a distribuovÃ¡n od srpna 2000 v rÃ¡mci mezinÃ¡rodnÃ­ spoluprÃ¡ce mezi:
+<table border="0">
+<tr valign="top">
+<td>
+<a href="http://nzdl.org"><b>projekt New Zealand Digital Library na UniversitÄ Waikato</b></a> 
+<br>
+Zde Greenstone vznikl. Byl podporovÃ¡n KomisÃ­ pro komunikaci, kterÃ¡ je souÄÃ¡stÃ­ novozÃ©landskÃ©ho NÃ¡rodnÃ­ho sekretariÃ¡tu pro UNESCO (jako souÄÃ¡st pÅÃ­spÄvku NovÃ©ho ZÃ©landu do programu UNESCO).
+</td>
+<td></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://www.unesco.org"><b>United Nations Educational, Scientific and Cultural Organization</b></a> 
+
+KlÃ­ÄovÃœm cÃ­lem UNESCO je rozÅ¡iÅovÃ¡nÃ­ informacÃ­ pro vÄdu, vzdÄlÃ¡vÃ¡nÃ­ a kulturnÃ­ rozvoj. ZvlÃ¡Å¡tÄ dostupnost tÄchto informacÃ­ v rozvojovÃœch zemÃ­ch, je centrÃ¡lnÃ­m bodem mezivlÃ¡dnÃ­ho programu "Informace pro vÅ¡echny"; kvalitnÃ­ a dostupnÃ¡ informaÄnÃ­ a komunikaÄnÃ­ technologie se v tomto kontextu jevÃ­ jako dÅ¯leÅŸitÃœ nÃ¡stroj.
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/unesco.gif"
+border="0"></a></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://humaninfo.org"><b>NevlÃ¡dnÃ­ organizace Human Info, se sÃ­dlem v AntverpÃ¡ch, Belgie</b></a> 
+
+Tento projekt, spolupracujÃ­cÃ­ s agenturami SpojenÃœch nÃ¡rodÅ¯ (UN) a s dalÅ¡Ã­mi nevlÃ¡dnÃ­mi organizacemi, si zÃ­skal svÄtovÃ© uznÃ¡nÃ­ dÃ­ky digitalizaci a zpÅÃ­stupnÄnÃ­ dokumentÅ¯ pro rozvoj zemÃ­ tÅetÃ­ho svÄta. SbÃ­rky jsou distribuovÃ¡ny rozvojovÃœm zemÃ­m zdarma, ostatnÃ­m za Ãºhradu nÃ¡kladÅ¯ na vÃœrobu.
+</td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table> 
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "zvolit kolekci" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ [l=cs] {_httpimg_/cs/selcolgr.gif}
+_widthselcolgr_ [l=cs] {537}
+_heightselcolgr_ [l=cs] {17}
+_altselcolgr_ [l=cs] {"Select a collection"}
+
+
+## "RozhranÃ­\nLibrarian" ## home_page_button ## cgli ##
+_httpiconcgliof_ [l=cs] {_httpimg_/cs/cgliof.gif}
+_httpiconcglion_ [l=cs] {_httpimg_/cs/cglion.gif}
+_widthcgli_ [l=cs] {100}
+
+# -- Missing translation: ccol
+# -- Missing translation: _httpiconccolof_
+# -- Missing translation: _httpiconccolon_
+# -- Missing translation: _widthccol_
+
+## "PÅekladatel" ## home_page_button ## ctrans ##
+_httpiconctransof_ [l=cs] {_httpimg_/cs/ctransof.gif}
+_httpiconctranson_ [l=cs] {_httpimg_/cs/ctranson.gif}
+_widthctrans_ [l=cs] {100}
+
+# -- Missing translation: cadmin
+# -- Missing translation: _httpiconcadminof_
+# -- Missing translation: _httpiconcadminon_
+# -- Missing translation: _widthcadmin_
+
+# -- Missing translation: cabgs
+# -- Missing translation: _httpiconcabgsof_
+# -- Missing translation: _httpiconcabgson_
+# -- Missing translation: _widthcabgs_
+
+# -- Missing translation: cgsdoc
+# -- Missing translation: _httpiconcgsdocof_
+# -- Missing translation: _httpiconcgsdocon_
+# -- Missing translation: _widthcgsdoc_
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=cs] {Na domovskÃ© strÃ¡nce jsou dalÅ¡Ã­ ÄtyÅi tlaÄÃ­tka}
+
+_textnocollections_ [l=cs] {<p>V souÄasnÃ© dobÄ nejsou v rÃ¡mci tÃ©to instalace Greenstone k dispozici ÅŸÃ¡dnÃ© kolekce.
+Pro pÅÃ­dÃ¡nÃ­ kolekcÃ­ mÅ¯ÅŸete
+<ul>
+ <li>pouÅŸÃ­t <a href="_httppagecollector_">Collector</a> pro vytvoÅenÃ­ novÃœch kolekcÃ­</li>
+ <li>pokud mÃ¡te CD-ROM Greenstone, mÅ¯ÅŸete naisntalovat kolekce z CD-ROM
+</ul>}
+
+_text1coll_ [l=cs] {Tato instalace Greenstone obsahuje 1 kolekci}
+
+_textmorecolls_ [l=cs] {PoÄet kolekcÃ­ v rÃ¡mci tÃ©to instalace Greenstone: _1_}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=cs] {ExternÃ­ odkaz}
+_textlinknotfound_ [l=cs] {InternÃ­ odkaz nenalezen}
+
+_textextlinkcontent_ [l=cs] {ZvolenÃœ odkaz vede k externÃ­mu dokumentu (vzhledem k vaÅ¡im souÄasnÃœm kolekcÃ­m).
+PÅejete-li si zobrazit odkazovanou strÃ¡nku a vÃ¡Å¡ prohlÃ­ÅŸeÄ mÃ¡ pÅÃ­stup k internetu, mÅ¯ÅŸete
+<a href"_nexturl_">pouÅŸÃ­t tento odkaz</a>; v opaÄnÃ©m pÅÃ­padÄ se vraÅ¥te pomocÃ­ tlaÄÃ­tka "zpÄt" ve vaÅ¡em prohlÃ­ÅŸeÄi.}
+
+_textlinknotfoundcontent_ [l=cs] {InternÃ­ odkaz, kterÃœ jste zvolili, neexistuje. PÅÃ­Äiny tÃ©to chyby jsou mimo naÅ¡e pole pÅ¯sobnostÃ­.
+NejpravdÄpodobnÄjÅ¡Ã­ pÅÃ­Äinou je chyba ve zdrojovÃœch dokumentech kolekce.
+Pro nÃ¡vrat k poslednÃ­mu dokumentu pouÅŸijte ve vaÅ¡em prohlÃ­ÅŸeÄi tlaÄÃ­tko "zpÄt".}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=cs] {<h3>Odkaz ke kolekci "_2_" </h3>
+
+<p>
+Odkaz, kterÃœ jste zvolili je externÃ­. Odkazuje na kolekci "_2_". PÅejete-li si zobrazit dokument z kolece "_2_" mÅ¯ÅŸete pouÅŸÃ­t <a href"_httpdoc_&c_1_&cl_cgiargcl_&d_3_">tento odkaz</a>; v opaÄnÃ©m pÅÃ­padÄ pouÅŸijte tlaÄÃ­tka "zpÄt" ve vaÅ¡em prohlÃ­ÅŸeÄi.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=cs] {DigitÃ¡lnÃ­ knihovna Greenstone}
+
+_textusername_ [l=cs] {pÅihlaÅ¡ovacÃ­ jmÃ©no}
+_textpassword_ [l=cs] {heslo}
+
+_textmustbelongtogroup_ [l=cs] {Pozn. MusÃ­te patÅit do skupiny "_cgiargug_"}
+
+_textmessageinvalid_ [l=cs] {PoÅŸadovanÃ¡ strÃ¡nka vyÅŸaduje autentifikaci.<br> 
+_If_(_cgiargug_, [_textmustbelongtogroup_])<br>
+ProsÃ­m zadejte pÅihlaÅ¡ovacÃ­ jmÃ©ho a heslo. }
+
+_textmessagefailed_ [l=cs] {BuÄ VaÅ¡e pÅihlaÅ¡ovacÃ­ jmÃ©no, nebo heslo jsou neplatnÃ©.}
+
+_textmessagedisabled_ [l=cs] {PromiÅte, VÃ¡Å¡ ÃºÄet byl zablokovÃ¡n. ProsÃ­m kontaktujte sprÃ¡vce tÃ©to sÃ­tÄ.}
+
+_textmessagepermissiondenied_ [l=cs] {PromiÅte, nemÃ¡te oprÃ¡vnÄnÃ­ pÅistupovat k tÃ©to strÃ¡nce.}
+
+_textmessagestalekey_ [l=cs] {Odkaz je zastaralÃœ, prosÃ­m zadejte VaÅ¡e heslo.}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=cs] {<p>
+Tato instalace Greenstone neobsahuje ÅŸÃ¡dnou dokumentaci. 
+MoÅŸnÃ© pÅÃ­Äiny:
+<ol>
+ <li>Greenstone byl nainstalovÃ¡n v kompaktnÃ­ verzi (z disku CD-ROM ).
+ <li>Greenstone byl nainstalovÃ¡n z internetu.
+</ol>
+V obou pÅÃ­padech mÅ¯ÅŸete zÃ­skat dokumentaci buÄ z adresÃ¡Åe <i>docs</i> na disku
+Greenstone CD-ROM, a nebo z <a href"http://www.greenstone.org">http://www.greenstone.org</a>. }
+
+_textuserguide_ [l=cs] {PÅÃ­ruÄka uÅŸivatele}
+_textinstallerguide_ [l=cs] {InstalaÄnÃ­ pÅÃ­ruÄka}
+_textdeveloperguide_ [l=cs] {"PÅÃ­ruÄka administrÃ¡tora"}
+_textpaperguide_ [l=cs] {PÅÃ­ruÄka 'Od papÃ­ru ke kolekci'}
+_textorganizerguide_ [l=cs] {PouÅŸÃ­vÃ¡nÃ­ nÃ¡stroje 'Organizer'}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Dokumentace Greenstone" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=cs] {_httpimg_/cs/gsdocsgr.gif}
+_widthgsdocsgr_ [l=cs] {_pagewidth_}
+_heightgsdocsgr_ [l=cs] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ [l=cs] {vÃœchozÃ­ nastavenÃ­}
+_textmore_ [l=cs] {vÃ­ce}
+_textcollector_ [l=cs] {Collector}
+_textinfo_ [l=cs] {Informace o kolekci}
+_textsrce_ [l=cs] {ZdrojovÃ¡ data}
+_textconf_ [l=cs] {Konfigurovat kolekci}
+_textbild_ [l=cs] {VytvÃ¡Ået}
+_textview_ [l=cs] {ukÃ¡zat}
+_textdel_ [l=cs] {smazat kolekci}
+_textexpt_ [l=cs] {exportovat kolekci}
+
+_textdownloadingfiles_ [l=cs] {Stahuji soubory...}
+_textimportingcollection_ [l=cs] {Importuji kolekci...}
+_textbuildingcollection_ [l=cs] {VytvÃ¡ÅÃ­m kolekci...}
+_textcreatingcollection_ [l=cs] {vytvÃ¡ÅenÃ­ kolekce...}
+
+_textcollectorblurb_ [l=cs] {<i>Pero je mocnÄjÅ¡Ã­ neÅŸ meÄ!
+<br>
+Tvorba a distrubuce informacÃ­ s sebou pÅinÃ¡Å¡Ã­ zodpovÄdnost, kterou byste si mÄli uvÄdomit jeÅ¡tÄ pÅed tÃ­m,
+neÅŸ zaÄnete. Nejsou to pouze prÃ¡vnÃ­ problÃ©my kolem autorskÃœch prÃ¡v (to, ÅŸe mÃ¡te pÅÃ­stup k dokumentÅ¯m
+jeÅ¡tÄ neznamenÃ¡, ÅŸe je mÅ¯ÅŸete dÃ¡t druhÃœm); existujÃ­ i dalÅ¡Ã­ otÃ¡zky sociÃ¡lnÃ­ a etickÃ© povahy. ZohledÅuje
+kolekce zvyky komunity, kterÃ¡ vytvoÅila dokumenty? Jsou vÅ¡echny texty vhodnÃ© k tomu, aby byly dÃ¡ny
+k dispozici druhÃœm? 
+<br> 
+BuÄte vnÃ­mavÃ­ k sÃ­le informacÃ­ a pouÅŸÃ­vejte ji moudÅe.</i>}
+
+_textcb1_ [l=cs] {Collector VÃ¡m pomÅ¯ÅŸe vytvoÅit novÃ© nebo zmÄnit Äi smazat  existujÃ­cÃ­ kolekce.
+CelÃœm procesem VÃ¡s provedede soubor strÃ¡nek, kterÃ© budou postupnÄ vyÅŸadovat zadÃ¡nÃ­ potÅebnÃœch informacÃ­.}
+
+_textcb2_ [l=cs] {NejdÅÃ­ve musÃ­te rozhodnout jestli}
+_textcnc_ [l=cs] {vytvoÅit novou kolekci}
+_textwec_ [l=cs] {pracovat s existujÃ­cÃ­mi kolekcemi, pÅidÃ¡vat do nich data nebo kolekci smazat.}
+
+_textcb3_ [l=cs] {Chcete-li vytvÃ¡Ået nebo mÄnit digitÃ¡lnÃ­ kolekce, musÃ­te se pÅihlÃ¡sit. TÃ­mto zabrÃ¡nÃ­me ostatnÃ­m, aby se pÅihlÃ¡sili k vaÅ¡emu poÄÃ­taÄi a zmÄnili vaÅ¡e sbÃ­rky.
+UpozornÄnÃ­: kvÅ¯li bezpeÄnostnÃ­m dÅ¯vodÅ¯m budete kaÅŸdÃœch 30 minut poÅŸÃ¡dÃ¡nÃ­ o znovu-zadÃ¡nÃ­ hesla. Po pÅihlÃ¡Å¡enÃ­ budete moci pokraÄovat prÃ¡vÄ z
+toho mÃ­sta, kde byla vaÅ¡e prÃ¡ce pÅeruÅ¡ena.}
+
+_textcb4_ [l=cs] {ProsÃ­m zadejte pÅihlaÅ¡ovacÃ­ jmÃ©no a heslo pro Greenstone a stisknÄte tlaÄÃ­tko pro pÅihlÃ¡Å¡enÃ­.}
+
+_textfsc_ [l=cs] {NejdÅÃ­ve vyberte kolekci, se kterou chcete pracovat (kolekce se zapnutou ochranou proti zÃ¡pisu se v tomto seznamu neobjevÃ­).}
+
+_textwtc_ [l=cs] {S kolekcÃ­, kterou jste zvolili, mÅ¯ÅŸete}
+_textamd_ [l=cs] {PÅidat dalÅ¡Ã­ data a znovu vytvoÅit kolekci}
+_textetc_ [l=cs] {Upravit konfiguraÄnÃ­ soubor a znovu vytvoÅit kolekci}
+_textdtc_ [l=cs] {ÃplnÄ smazat kolekci}
+_textetcfcd_ [l=cs] {Exportovat kolekci a vytvoÅit instalaÄnÃ­ CD-ROM pro Windows}
+_textcaec_ [l=cs] {MÄnÃ­m existujÃ­cÃ­ kolekci}
+_textnwec_ [l=cs] {NenÃ­ k dispozici ÅŸÃ¡dnÃ¡ kolekce, do nÃ­ÅŸ je povolen zÃ¡pis.}
+_textcianc_ [l=cs] {VytvÃ¡ÅÃ­m novou kolekci}
+_texttsosn_ [l=cs] {PoÅadÃ­ krokÅ¯ potÅebnÃœch pro vytvoÅenÃ­ novÃ© kolekce digitÃ¡lnÃ­ knihovny je nÃ¡sledujÃ­cÃ­:}
+_textsin_ [l=cs] {Zadejte jejÃ­ jmÃ©no (a doplÅujÃ­cÃ­ informace)}
+_textswts_ [l=cs] {UrÄit odkud pochÃ¡zejÃ­ zdrojovÃ¡ data}
+_textatco_ [l=cs] {Upravit konfiguraÄnÃ­ nastavenÃ­ (pouze pro zkuÅ¡enÃ©h uÅŸivatele)}
+_textbtc_ [l=cs] {"VytvoÅit" kolekci (viz. nÃ­ÅŸe)}
+_textpvyh_ [l=cs] {Zobrazit vÃœsledek }
+
+_texttfsiw_ [l=cs] {Ve ÄtvrtÃ©m kroku uÅŸ bude pracovat jenom poÄÃ­taÄ.
+PÅi budovÃ¡nÃ­ jsou vytvoÅeny indexy a shromÃ¡ÅŸdÄny
+vÅ¡echny informace potÅebnÃ© pro fungovÃ¡nÃ­ kolekce.
+Nejprve ale musÃ­te urÄit, kterÃ© informace to budou.}
+
+_textadab_ [l=cs] {Diagram ve spodnÃ­ ÄÃ¡sti strÃ¡nky VÃ¡m pomÅ¯ÅŸe urÄit mÃ­sto, kde se prÃ¡vÄ nachÃ¡zÃ­te. ZelenÃ© tlaÄÃ­tko VÃ¡s posunuje do nÃ¡sledujÃ­cÃ­ fÃ¡ze, ÅŸlutÃ© tlaÄÃ­tko zase do fÃ¡ze pÅedchozÃ­.
+ZÃ¡roveÅ s tÃ­m, jak postupujete jednotlivÃœmi fÃ¡zemi, se tlaÄÃ­tka obarvovujÃ­ ÅŸlutÄ.}
+
+_textwyar_ [l=cs] {AÅŸ budete hotovi, zmÃ¡ÄknÄte zelenÃ© tlaÄÃ­tko "informace o kolekci". Proces tvorby zaÄne.}
+
+_textcnmbs_ [l=cs] {JmÃ©no kolekce musÃ­ bÃœt specifikovÃ¡no}
+_texteambs_ [l=cs] {EmailovÃ¡ adresa musÃ­ bÃœt vyplnÄna}
+_textpsea_ [l=cs] {ProsÃ­m specifikujte emailovou adresu ve tvaru: jmenouzivatele@domena}
+_textdocmbs_ [l=cs] {Popis kolekce mustÃ­ bÃœt doplnÄn}
+
+_textwcanc_ [l=cs] {PÅi vytvÃ¡ÅenÃ­ novÃ© kolekce musÃ­te zadat nÄkterÃ© dÅ¯leÅŸitÃ© informace o zdrojovÃœch datech.
+Tento proces je strukturovÃ¡n do sÃ©rie strÃ¡nek, nad nimiÅŸ mÃ¡ dohled Collector.
+LiÅ¡ta ve spodnÃ­ ÄÃ¡sti strÃ¡nky vÃ¡m ukÃ¡ÅŸe, ve kterÃ© fÃ¡zi se prÃ¡vÄ nachÃ¡zÃ­te.}
+
+_texttfc_ [l=cs] {NÃ¡zev kolekce:}
+
+_texttctiasp_ [l=cs] {KaÅŸdÃ¡ kolekce mÃ¡ nÃ¡zev; je to krÃ¡tkÃ¡ frÃ¡ze, kterÃ¡ identifikuje obsah kolekce.
+NapÅ. "Computer Science Technical Reports" nebo "Humanity Development Library".}
+
+_textcea_ [l=cs] {KontaktnÃ­ emailovÃ¡ adresa:}
+
+_textteas_ [l=cs] {Tato emailovÃ¡ adresa urÄuje, kdo je kontaktnÃ­ osobou pro danou sbÃ­rku.
+Jestli Greenstone objevÃ­ nÄjakÃœ problÃ©m, zaÅ¡le diagnostickou zprÃ¡vu na tuto adresu.
+Zadejte emailovou adresu v plnÃ©m tvaru: <tt>jmeno@domena</tt>.}
+
+_textatc_ [l=cs] {O tÃ©to kolekci:}
+
+_texttiasd_ [l=cs] {Toto je prohlÃ¡Å¡enÃ­, kterÃ© popisuje celou kolekci. PÅi zobrazenÃ­ kolekce je zobrazeno na ÃºvodnÃ­ strÃ¡nce.}
+
+_textypits_ [l=cs] {VaÅ¡e aktuÃ¡lnÃ­ pozice je naznaÄena pomocÃ­ Å¡ipky -- v tomto pÅÃ­padÄ je to fÃ¡ze "informace o kolekci".
+Chcete-li pokraÄovat, zmÃ¡ÄknÄte zelenÃ© tlaÄÃ­tko "zdrojovÃ¡ data"}
+
+_srcebadsources_ [l=cs] {<p>
+Jeden nebo i nÄkolik zdrojÅ¯, kterÃ© jste zadali, jsou nedosaÅŸitelnÃ© (znaÄeny _iconcross_ ).<p>MoÅŸnÃ© pÅÃ­Äiny <u><li>Soubor, FTP server nebo URL adresa neexistujÃ­. <li>Nejste pÅipojeni na internet. <li>PokouÅ¡Ã­te se pÅistoupit ke strÃ¡nce zpoza firewallu (kdyÅŸ musÃ­te zadÃ¡vat pÅihlaÅ¡ovacÃ­ jmÃ©no a heslo, abyste se dostali do internetu). </ul><p>Pokud vidÃ­te strÃ¡nku s touto URL adresou ve VaÅ¡em prohlÃ­ÅŸeÄi, mÅ¯ÅŸe pochÃ¡zet i z doÄasnÃ© lokÃ¡lnÄ uloÅŸenÃ© kopie. LokÃ¡lnÃ­ kopie (cache) jsou bohuÅŸel pro nÃ¡Å¡ importovacÃ­ program neviditelnÃ©. DoporuÄujeme strÃ¡nky stÃ¡hnout a uloÅŸit pomocÃ­ VaÅ¡eho prohlÃ­ÅŸeÄe.}
+
+_textymbyco_ [l=cs] {<p>
+MÅ¯ÅŸete zaloÅŸit svoji kolekci buÄ
+<ul>
+<li> na standardnÃ­m nastavenÃ­
+<dl><dd>NovÃ¡ kolekce mÅ¯ÅŸe obsahovat html dokumenty (.htm, .html), jednoduchÃœ text(.txt, .text),
+dokumenty MS Word (.doc), PDF dokumenty (.pdf) nebo formÃ¡t "m-box" emailovÃœch souborÅ¯ (.mbx)</dd></dl>
+<li>na nÄkterÃ© z existujÃ­cÃ­ch sbÃ­rek
+<dl><dd> Soubory ve vaÅ¡Ã­ novÃ© kolekci musejÃ­ bÃœt stejnÃ©ho typu jako ty, kterÃ© byly pouÅŸity v existujÃ­cÃ­ sbÃ­rce.</dd></dl>
+</ul> }
+
+_textbtco_ [l=cs] {ZaloÅŸit kolekci na}
+_textand_ [l=cs] {PÅidat novÃ¡ data}
+_textad_ [l=cs] {PÅidÃ¡vat data:}
+
+_texttftysb_ [l=cs] {Soubory, kterÃ© urÄÃ­te niÅŸe na tÃ©to strÃ¡nce, budou pÅidÃ¡ny do kolekce. UjistÄte se, ÅŸe existujÃ­ v kolekci pouze
+jednou; v opaÄnÃ©m pÅÃ­padÄ se v kolekci objevÃ­ duplikÃ¡ty. Soubory jsou identifikovÃ¡ny podle svÃ©
+plnÃ© cesty, webovÃ© strÃ¡nky podle svÃ© absolutnÃ­ adresy.}
+
+_textis_ [l=cs] {Zdroje pro import:}
+
+_textddd1_ [l=cs] {<p>
+Pokud pouÅŸijete <b>file://</b> nebo <b>ftp://</b>, abyste urÄili jeden soubor, potom bude staÅŸen pouze ten jedinÃœ soubor.
+
+<p>Pokud pouÅŸijete  <b>http://</b>, vÃœsledek bude zÃ¡viset na tom, jestli zadanÃ¡ URL adresa odkazuje na normÃ¡lnÃ­ web. strÃ¡nku,
+jak ji vidÃ­te v prohlÃ­ÅŸeÄi, a nebo na adresÃ¡Å strÃ¡nek. JestliÅŸe je to normÃ¡lnÃ­ strÃ¡nka, bude importovÃ¡na a spolu s nÃ­ takÃ© dokumenty,
+na kterÃ© odkazuje (stahovÃ¡nÃ­ se nezastavÃ­ u prvnÃ­ch odkazÅ¯, ale bude sledovat dalÅ¡Ã­ odkazy a stÃ¡hne vÅ¡echny odkazovanÃ© dokumenty
+z <b>danÃ©ho</b> serveru (URL).
+<p>JestliÅŸe pouÅŸijete URL, kterÃ© odkazuje na adresÃ¡Å <b>http://</b>  (<b>ftp://</b>, <b>file://</b>), tak potom bude importovÃ¡n veÅ¡kerÃœ
+obsah danÃ© sloÅŸky (vÄetnÄ podsloÅŸek).<p>
+Chcete-li vÃ­ce polÃ­Äek pro zadÃ¡nÃ­ adresy, zmÃ¡ÄknÄte tlaÄÃ­tko "vÃ­ce zdrojÅ¯".}
+
+_textddd2_ [l=cs] {<p>
+ZmÃ¡ÄknÄte jedno ze zelenÃœch tlaÄÃ­tek. Nejste-li zkuÅ¡enÃœmi uÅŸivateli, pokraÄujte do dalÅ¡Ã­ho kroku.
+Zapamatujte si, ÅŸe se mÅ¯ÅŸete vÅŸdy do pÅedchozÃ­ho kroku tÃ­m, ÅŸe zmÃ¡Äknete ÅŸlutÃ© tlaÄÃ­tko.}
+
+_textconf1_ [l=cs] {<p>
+Tvorba a zpÅ¯sob zobrazenÃ­ vaÅ¡Ã­ kolekce je kontrolovÃ¡n nastavenÃ­m
+ve speciÃ¡lnÃ­m konfiguraÄnÃ­m souboru. ZkuÅ¡enÃ­ uÅŸivatelÃ© jej pravdÄpodobnÄ
+budou chtÃ­t zmÄnit.
+<center><p>
+<b>Pokud nejste zkuÅ¡enÃœmi uÅŸivateli, jednoduÅ¡e pÅejdÄte na dalÅ¡Ã­ strÃ¡nku.</b></center>
+<p>Chcete-li zmÄnit nastavenÃ­, upravte ÅÃ¡dky, kterÃ© jsou zobrazeny nÃ­ÅŸe.
+Pokud udÄlÃ¡te chybu, mÅ¯ÅŸete pouÅŸÃ­t tlaÄÃ­tka "Reset" - objevÃ­ se pÅ¯vodnÃ­ konfiguraÄnÃ­ soubor.}
+
+_textreset_ [l=cs] {Reset}
+
+_textbild1_ [l=cs] {Kolekce se nynÃ­ vytvÃ¡ÅÃ­: mÅ¯ÅŸe to chvÃ­li trvat. ÅÃ¡dek ve spodnÃ­ ÄÃ¡sti obrazovky naznaÄuje prÃ¡vÄ probÃ­hajÃ­cÃ­ operace.}
+
+_textbild2_ [l=cs] {Pokud chcete ukonÄit proces tvorby, mÅ¯ÅŸete kdykoli kliknout zde. <br> 
+Kolekce na kterÃ© se prÃ¡vÄ pracuje zÅ¯stane nezmÄnÄna.}
+
+_textstopbuild_ [l=cs] {zastavit tvorbu}
+
+_textbild3_ [l=cs] {Pokud tuto strÃ¡nku opustÃ­te (a nezruÅ¡Ã­te tvorbu kolekce pomocÃ­ tlaÄÃ­tka "stop"), proces bude pokraÄovat a po ÃºspÄÅ¡nÃ©m dokonÄenÃ­ bude kolekce automaticky nainstalovÃ¡na.}
+
+_textbuildcancelled_ [l=cs] {Tvorba zruÅ¡ena}
+
+_textbildcancel1_ [l=cs] {Tvorba kolekce byla zruÅ¡ena. PouÅŸijte ÅŸlutÃ©ho tlaÄÃ­tka vespodu, pokud chcete zmÄnit konfiguraci, a nebo spusÅ¥te tvorbu znovu.}
+
+_textbsupdate1_ [l=cs] {IndikÃ¡tor tvorby se akturalizuje za 1 sekundu}
+_textbsupdate2_ [l=cs] {IndikÃ¡tor tvorby aktualizovÃ¡n v }
+_textseconds_ [l=cs] {sekund}
+_textbildsuc_ [l=cs] {Kolekce byla ÃºspÄÅ¡nÄ vytvoÅena.}
+
+_textviewbildsummary_ [l=cs] {MÅ¯ÅŸete zobrazit<a href"_httppagex_(bsummary)&c_cgiargbc1dirname_" target_top>detailnÃ­ zprÃ¡vu</a> o tvorbÄ kolekce.}
+
+_textfailmsg11_ [l=cs] {Kolekce nemohla bÃœt vytvoÅena, protoÅŸe neobsahuje ÅŸÃ¡dnÃ¡ data. UjistÄte se, ÅŸe alespoÅ
+jeden adresÃ¡Å nebo soubor, kterÃœ jste zadali na strÃ¡nce <i>zdrojovÃ¡ data</i>, existuje
+a obsahuje typ informacÃ­, kterÃ© Greenstone dokÃ¡ÅŸe zpracovat.}
+
+_textfailmsg21_ [l=cs] {Kolekce nemohla bÃœt vytvoÅena (chyba import.pl).}
+_textblcont_ [l=cs] {ZprÃ¡va obsahuje nÃ¡sledujÃ­cÃ­ informace:}
+
+_texttryagain_ [l=cs] {ProsÃ­m <a href"_httppagecollector_" target_top>znovu spusÅ¥te Collector</a> a zkuste vÅ¡e znovu.}
+
+_textfailmsg31_ [l=cs] {Kolekce nemohla bÃœt vytvoÅena (chyba buildcol.pl).}
+_textfailmsg41_ [l=cs] {Kolekce byla ÃºspÄÅ¡nÄ vytvoÅena, ale nemohla bÃœt nainstalovÃ¡na.}
+_textfailmsg71_ [l=cs] {BÄhem pokusu o vytvoÅenÃ­ kolekce nastala neoÄekÃ¡vanÃ¡ chyba.}
+_textretcoll_ [l=cs] {VrÃ¡tit se do Collector}
+
+_textdelperm_ [l=cs] {NÄkterÃ© z _cgiargbc1dirname_ kolekcÃ­ nemohly bÃœt smazÃ¡ny. MoÅŸnÃ© pÅÃ­Äiny jsou:<ul>
+<li>Greenstone nemÃ¡ oprÃ¡vnÄnÃ­ mazat adresÃ¡Å _gsdlhome_/collect/_cgiargbc1dirname_.<br>
+Budete muset odstranit tuto kolekci ruÄnÄ, aby zmizela ÃºplnÄ z tohoto poÄÃ­taÄe.</li>
+<li>Greenstone nemÅ¯ÅŸe spustit program _gsdlhome_/bin/script/delcol.pl UjistÄte se,
+ÅŸe soubor mÃ¡ nastaveny atributy "ke ÄtenÃ­" a "spustitelnÃœ".</li></ul>}
+
+_textdelinv_ [l=cs] {Kolekce _cgiargbc1dirname_ je uzamÄena, a nebo je naplatnÃ¡. SmazÃ¡nÃ­ bylo zruÅ¡eno.}
+
+_textdelsuc_ [l=cs] {Kolekce _cgiargbc1dirname_ byla ÃºspÄÅ¡nÄ smazÃ¡na.}
+
+_textclonefail_ [l=cs] {_cgiargclonecol_ kolekce nemohla bÃœt zkopÃ­rovÃ¡na. MoÅŸnÃ© pÅÃ­Äiny jsou:
+<ul>
+<li>Kolekce _cgiargclonecol_ neexistuje</li>
+<li>Kolekce _cgiargclonecol_ postrÃ¡dÃ¡ konfiguraÄnÃ­ soubor (collect.cfg)</li>
+<li>Greenstone nemÃ¡ oprÃ¡vnÄnÃ­ ÄÃ­st z collect.cfg</li>
+</ul>}
+
+_textcolerr_ [l=cs] {Chyba Collector}
+
+_texttmpfail_ [l=cs] {Collector hlÃ¡sÃ­, ÅŸe nemohl ÄÃ­st nebo zapisovat dovnitÅ doÄasnÃ©ho adresÃ¡Åe (souboru).
+MoÅŸnÃ© pÅÃ­Äiny jsou:
+<ul>
+<li>Greenstone nemÃ¡ oprÃ¡vnÄnÃ­ zapisovat/ÄÃ­st do adressÃ¡Åe _gsdlhome_/tmp.<./li>
+</ul>}
+
+_textmkcolfail_ [l=cs] {Collector hlÃ¡sÃ­ chybu pÅi vytvÃ¡ÅenÃ­ adresÃ¡ÅovÃ© struktury (chyba mkcol.pl).
+MoÅŸnÃ© pÅÃ­Äiny jsou:
+<ul>
+<li>Greenstone nemÃ¡ oprÃ¡vnÄnÃ­ zapisovat do adresÃ¡Åe _gsdlhome_/tmp</li>
+<li>chyba v perl skriptu mkcol.pl</li>
+</ul> 
+}
+
+_textnocontent_ [l=cs] {Chyba Collector: pro novou kolekci nebylo specifikovÃ¡no ÅŸÃ¡dnÃ© jmÃ©no. Restartujte Collector od zaÄÃ¡tku.}
+
+_textrestart_ [l=cs] {Restartovat Collector}
+
+_textreloaderror_ [l=cs] {BÄhem tvorby novÃ© kolekce se objevila chyba. Greenstone mohl bÃœt zmaten tÃ­m,
+ÅŸe jste ve VaÅ¡em prohlÃ­ÅŸeÄi pouÅŸili tlaÄÃ­tka "aktualizuj" a nebo "zpÄt"i. Vyvarujte se prosÃ­m
+pouÅŸÃ­vÃ¡nÃ­ tÄchto tlaÄÃ­tek bÄhem procesu tvorby kolekce. DoporuÄujeme
+restartovat Collector od zaÄÃ¡tku.}
+
+_textexptsuc_ [l=cs] {Kolekce _cgiargbc1dirname_ byla ÃºspÄÅ¡nÄ exportovÃ¡na do adresÃ¡Åe _gsdlhome_/tmp/exported\__cgiargbc1dirname_ }
+
+_textexptfail_ [l=cs] {<p>
+Chyba pÅi exportu kolekce _cgiargbc1dirname_ .<p>
+Tato chyba je pravdÄpodobnÄ zpÅ¯sobena tÃ­m, ÅŸe Greenstone byl nainstalovÃ¡n bez komponent nezbytnÃœch
+pro fungovÃ¡nÃ­ funkce exportovÃ¡nÃ­ kolekce.
+<ul>
+<li>Pokud jste instalovali Greenstone z disku CD-ROM, tyto balÃ­Äky nebyly pÅidÃ¡ny. Volba je dostupnÃ¡ pouze
+pÅi typu instalace "Custom". MÅ¯ÅŸete vÅ¡ak spustit instalaci znovu a vybrat Custom - "Export Collection".</li>
+
+<li>Jestli jste instalovali Greenstone z jinÃ©ho zdroje, budete si muset stÃ¡hnout pÅÃ­davnÃœ balÃ­Äek. ProsÃ­m navÅ¡tivte
+<a href"http://www.greenstone.org">http://www.greenstone.org</a> a nebo napiÅ¡te na
+<a href"mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>, poskytneme vÃ¡m dalÅ¡Ã­ informace.</li>
+
+</ul>}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Collector" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=cs] {_httpimg_/cs/h\_colect.gif}
+
+## "informace o\n    kolekci" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=cs] {_httpimg_/cs/gcinfoof.gif}
+_httpicongcinfoon_ [l=cs] {_httpimg_/cs/gcinfoon.gif}
+_httpiconycinfoof_ [l=cs] {_httpimg_/cs/ycinfoof.gif}
+_httpiconycinfoon_ [l=cs] {_httpimg_/cs/ycinfoon.gif}
+_httpiconncinfoof_ [l=cs] {_httpimg_/cs/ncinfoof.gif}
+
+## "zdrojovÃ¡\n    data" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=cs] {_httpimg_/cs/gcsrceof.gif}
+_httpicongcsrceon_ [l=cs] {_httpimg_/cs/gcsrceon.gif}
+_httpiconycsrceof_ [l=cs] {_httpimg_/cs/ycsrceof.gif}
+_httpiconycsrceon_ [l=cs] {_httpimg_/cs/ycsrceon.gif}
+_httpiconncsrceof_ [l=cs] {_httpimg_/cs/ncsrceof.gif}
+
+## "konfigurovat\n     kolekci" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=cs] {_httpimg_/cs/gcconfof.gif}
+_httpicongcconfon_ [l=cs] {_httpimg_/cs/gcconfon.gif}
+_httpiconycconfof_ [l=cs] {_httpimg_/cs/ycconfof.gif}
+_httpiconycconfon_ [l=cs] {_httpimg_/cs/ycconfon.gif}
+_httpiconncconfof_ [l=cs] {_httpimg_/cs/ncconfof.gif}
+
+## "vytvoÅit\nkolekci" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=cs] {_httpimg_/cs/gcbildof.gif}
+_httpicongcbildon_ [l=cs] {_httpimg_/cs/gcbildon.gif}
+_httpiconycbildof_ [l=cs] {_httpimg_/cs/ycbildof.gif}
+_httpiconycbildon_ [l=cs] {_httpimg_/cs/ycbildon.gif}
+_httpiconncbildof_ [l=cs] {_httpimg_/cs/ncbildof.gif}
+
+## "ukÃ¡zat\nkolekci" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=cs] {_httpimg_/cs/gcviewof.gif}
+_httpicongcviewon_ [l=cs] {_httpimg_/cs/gcviewon.gif}
+_httpiconycviewof_ [l=cs] {_httpimg_/cs/ycviewof.gif}
+_httpiconycviewon_ [l=cs] {_httpimg_/cs/ycviewon.gif}
+_httpiconncviewof_ [l=cs] {_httpimg_/cs/ncviewof.gif}
+
+## "smazat\nkolekci" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=cs] {_httpimg_/cs/gcdelof.gif}
+_httpicongcdelon_ [l=cs] {_httpimg_/cs/gcdelon.gif}
+
+## "exportovat\n   kolekci" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=cs] {_httpimg_/cs/gcexptof.gif}
+_httpicongcexpton_ [l=cs] {_httpimg_/cs/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=cs] {Greenstone je balÃ­kem programÅ¯, kterÃ© majÃ­ schopnost vytvÃ¡Ået a prezentovat kolekce v rÃ¡mci digitÃ¡lnÃ­ch knihoven.
+NabÃ­zÃ­ novÃœ zpÅ¯sob organizovÃ¡nÃ­ a publikovÃ¡nÃ­ informacÃ­ na internetu i na CD-ROM. Greenstone je vyvÃ­jen
+v rÃ¡mci projektu New Zealand Digital Library na universitÄ Waikato, a je distribuovÃ¡n ve spoluprÃ¡ci s UNESCO
+a nevlÃ¡dnÃ­ organizacÃ­ Human Info. Je to otevÅenÃœ systÃ©m (open-source), dostupnÃœ z <i>http://greenstone.org</i>
+za podmÃ­nek GNU General Public License.}
+
+_textgreenstone2_ [l=cs] {InternetovÃ© strÃ¡nky projektu New Zealand Digital library (<a href"http://nzdl.org">http://nzdl.org</a>)
+obsahujÃ­ mnoÅŸstvÃ­ ukÃ¡zek hotovÃœch kolekcÃ­. VÅ¡echny byly vytvoÅeny v programu Greenstone
+a pÅedvÃ¡dÄjÃ­ jeho moÅŸnosti vyhledÃ¡vÃ¡nÃ­ a prohlÃ­ÅŸenÃ­. Naleznete tam kolekce arabskÃ©, ÄÃ­nskÃ©,
+francouzskÃ©, v jazyce Maori nebo ve Å panÄlÅ¡tinÄ Äi AngliÄtinÄ a takÃ© nÄkolik kolekcÃ­ hudebnÃ­ch.}
+
+_textplatformtitle_ [l=cs] {platforma}
+_textgreenstone3_ [l=cs] {Greenstone funguje v operaÄnÃ­ch systÃ©mech Windows i Unix a Mac OS X. DistrubuÄnÃ­ balÃ­Äky obsahujÃ­
+hotovÃ© binÃ¡rnÃ­ instalace pro Windows a pro Linux a Mac OS X. K dipozici je takÃ© kompletnÃ­ zdrojovÃœ
+kÃ³d, kterÃœ lze kompilovat pomocÃ­ Microsoft C++ nebo gcc. Greenstone pouÅŸÃ­vÃ¡ volnÄ Å¡iÅitelnÃ© programy,
+kterÃ© jsou takÃ© k dispozici: webserver Apache a PERL. RozhranÃ­ pro Greenstone vyuÅŸÃ­vÃ¡ webovÃœ prohlÃ­ÅŸeÄ
+(napÅ. Netscape Navigator nebo Internet Explorer).}
+
+_textgreenstone4_ [l=cs] {Mnoho kolekcÃ­ je distribuovÃ¡no na CD-ROM discÃ­ch s programem Greenstone. NapÅ. <i>Humanity Development Library</i>,
+kterÃ¡ obsahuje 1 230 publikacÃ­ sahajÃ­cÃ­ od oblasti ÃºÄetnictvÃ­ k hygienÄ pitnÃ© vody. 
+Distribuce majÃ­ minimÃ¡lnÃ­ nÃ¡roky na vÃœkon poÄÃ­taÄe a proto se hodÃ­ i do podmÃ­nek,
+kterÃ© jsou v rozvojovÃœch zemÃ­ch. Dokumenty lze prohledÃ¡vat, ale i prohlÃ­ÅŸet podle pÅedmÄtovÃœch hesel,
+nÃ¡zvÅ¯, organizacÃ­, seznamÅ¯ "Jak na .." Äi nÃ¡hodnÄ podle kniÅŸnÃ­ch pÅebalÅ¯.}
+
+_textcustomisationtitle_ [l=cs] {pÅizpÅ¯sobenÃ­}
+_textgreenstone5_ [l=cs] {Greenstone je speciÃ¡lnÄ navrÅŸen tak, aby se dal rozÅ¡iÅovat a upravovat. NovÃ© formÃ¡ty
+dokumentÅ¯ i metadat se pÅipojujÃ­ pomocÃ­ (Perl) "pluginÅ¯" a "klasifikÃ¡torÅ¯". Vzhled
+uÅŸivatelskÃ©ho rozhranÃ­ lze mÄnit pomocÃ­ "maker" napsanÃœch pomocÃ­ jednoduchÃ©ho makrojazyka.
+Protokol Corba dovoluje programÅ¯m (agenti - napsanÃ­ napÅÃ­klad v programovacÃ­m jazyce Java),
+aby vyuÅŸÃ­vali procedur pÅipojenÃœch ke sbÃ­rkÃ¡m. A koneÄnÄ, zdrojovÃœ kÃ³d napsanÃœ v C++ a v Perl je
+k dispozici pro dalÅ¡Ã­ Ãºpravy.}
+
+_textdocumentationtitle_ [l=cs] {dokumentace}
+_textdocuments_ [l=cs] {K dispozici je rozsÃ¡hlÃ¡ dokumentace software Greenstone.}
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+_textmailinglisttitle_ [l=cs] {e-mailovÃ¡ konference}
+_textmailinglist_ [l=cs] {Pro diskuse o pouÅŸÃ­vÃ¡nÃ­ digitÃ¡lnÃ­ knihovny Greenstone existujÃ­ emailovÃ¡ konference.
+K pÅihlÃ¡Å¡enÃ­ pouÅŸijte strÃ¡nky <a href"https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.
+Chcete-li odeslat zprÃ¡vu, zaÅ¡lete ji na <a href"mailto:greenstone-users@list.scms.waikato.ac.nz" >greenstone-users@list.scms.waikato.ac.nz</a>. }
+
+_textbugstitle_ [l=cs] {chyby}
+_textreport_ [l=cs] {Chceme se ujistit, ÅŸe tento program dÄlÃ¡ svou prÃ¡ci dobÅe. ProsÃ­me hlaste jakoukoliv
+chybu na <a href"mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>.  }
+
+_textgs3title_ [l=cs] {v pracÃ­ch}
+_textgs3_ [l=cs] {Greenstone 3 je kompletnÃ­m pÅepracovÃ¡nÃ­m a novou implementacÃ­, kterÃ¡
+zachovÃ¡vÃ¡ vÅ¡echny vÃœhody Greenstone 2 (souÄasnÃ¡ verze). NapÅÃ­klad je
+vÃ­cejazyÄnÃœ, multiplatformnÃ­ a znaÄnÄ konfigurovatelnÃœ. SluÄuje vÅ¡echny
+rysy existujÃ­cÃ­ho systÃ©mu a zachovÃ¡vÃ¡ zpÄtnou kompatibilitu: to znamenÃ¡,
+ÅŸe umoÅŸÅuje vytvÃ¡Ået a provozovat existujÃ­cÃ­ kolekce bez nutnosti jejich Ãºpravy.
+SystÃ©m je naprogramovÃ¡n v jazyce Java a je strukturovÃ¡n jako sÃ­t nezÃ¡vislÃœch modulÅ¯
+komunikujÃ­cÃ­ch za pouÅŸitÃ­ XML: dÃ­ky tomu mÅ¯ÅŸe fungovat v distribuovanÃ© podobÄ a
+v pÅÃ­padÄ potÅeby mÅ¯ÅŸe bÃœt umÃ­stÄn na nÄkolika rÅ¯znÃœch serverech. Toto modulÃ¡rnÃ­
+pojetÃ­ zvÄtÅ¡uje pÅizpÅ¯sobivost a rozÅ¡iÅitelnost systÃ©mu Greenstone. NovÃ¡ verze
+by mÄla bÃœt pro experimentÃ¡lnÃ­ vyuÅŸitÃ­ k dipozici od 23. prosince 2003.
+ZÃ¡kladnÃ­ nÃ¡vrh systÃ©mu je nestÃ­nÄn v dokumentu "The design of Greenstone 3:
+An agent based dynamic digital library" (nahrÃ¡t  <a href="http://www.greenstone.org/manuals/gs3design.pdf">PDF</a>).}
+
+_textcreditstitle_ [l=cs] {o autorech}
+
+_textwhoswho_ [l=cs] {Greenstone je vÃœsledkem tÃœmovÃ© prÃ¡ce mnoha lidÃ­. HlavnÃ­mi architekty systÃ©mu jsou Rodger McNab a Stefan Boddie.
+DalÅ¡Ã­mi pÅispÄvatali byli David Bainbridge, George Buchanan, Hong Chen, Michael Dewsnip, Katherine Don, Elke Duncker,
+Carl Gutwin, Geoff Holmes, Dana McKay, John McPherson, Craig Nevill-Manning, Dynal Patel, Gordon Paynter, Bernhard Pfahringer,
+Todd Reed, Bill Rogers, John Thompson, and Stuart Yeates. OstatnÃ­ ÄlenovÃ© projektu poskytovali rady a inspiraci pro design systÃ©mu :
+Mark Apperley, Sally Jo Cunningham, Matt Jones, Steve Jones, Te Taka Keegan, Michel Loots, Malika Mahoui, Gary Marsden, Dave Nichols
+a Lloyd Smith. A chceme takÃ© upozornit na vÅ¡echny ty, kteÅÃ­ pÅispÄli do GNU programÅ¯ zahrnutÃœch v tÃ©to distribuci:
+MG, GDBM, PDFTOHTML, PERL, WGET, WVWARE a XLHTML.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "o programu Greenstone" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=cs] {_httpimg_/cs/abgsgr.gif}
+_widthabgsgr_ [l=cs] {_pagewidth_}
+_heightabgsgr_ [l=cs] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=cs] {Skupina aktuÃ¡lnÃ­ch uÅŸivatelÅ¯}
+_textuser_ [l=cs] {uÅŸivatel
+}
+_textas_ [l=cs] {stav ÃºÄtu}
+_textgroups_ [l=cs] {skupiny}
+_textcomment_ [l=cs] {poznÃ¡mky}
+_textadduser_ [l=cs] {pÅidat novÃ©ho uÅŸivatele}
+_textedituser_ [l=cs] {editovat}
+_textdeleteuser_ [l=cs] {smazat}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=cs] {Editovat informace o uÅŸivateli}
+_textadduser_ [l=cs] {PÅidat novÃ©ho uÅŸivatele}
+
+_textaboutusername_ [l=cs] {UÅŸivatelskÃ© jmÃ©no musÃ­ mÃ­t dÃ©lku 2-30 znakÅ¯. MÅ¯ÅŸe obsahovat alfanumerickÃ© znaky, teÄku(.) a podtrÅŸÃ­tko ( _ ).}
+
+_textaboutpassword_ [l=cs] {Heslo musÃ­ mÃ­t dÃ©lku 3-8 znakÅ¯. MÅ¯ÅŸe obsahovat tisknutelnÃ© znaky ASCII.}
+
+_textoldpass_ [l=cs] {Pokud je toto pole prÃ¡zdnÃ©, bude zachovÃ¡no starÃ© heslo.}
+_textenabled_ [l=cs] {povoleno}
+_textdisabled_ [l=cs] {zakÃ¡zÃ¡no}
+
+_textaboutgroups_ [l=cs] {ÄlenovÃ© skupiny se oddÄlujÃ­ ÄÃ¡rkou, prosÃ­m nevklÃ¡dejte ÅŸÃ¡dnÃ© mezery.}
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=cs] {smazat uÅŸivatele}
+_textremwarn_ [l=cs] {SkuteÄnÄ chcete zcela odstranit uÅŸivatele <b>_cgiargumun_</b>?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=cs] {ZmÄnit heslo}
+_textoldpw_ [l=cs] {starÃ© heslo}
+_textnewpw_ [l=cs] {novÃ© heslo}
+_textretype_ [l=cs] {zadejte heslo jeÅ¡tÄ jednou}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=cs] {VaÅ¡e heslo bylo ÃºspÄÅ¡nÄ zmÄnÄno.}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=cs] {UÅŸivatelskÃ© jmÃ©no nenÃ­ platnÃ©.}
+_textinvalidpassword_ [l=cs] {Heslo nenÃ­ platnÃ©.}
+_textemptypassword_ [l=cs] {Zadejte prosÃ­m vÃœchozÃ­ heslo pro tohoto uÅŸivatele.}
+_textuserexists_ [l=cs] {Tento uÅŸivatel uÅŸ existuje, prosÃ­m zvolte jinÃ© jmÃ©no.}
+
+_textusernameempty_ [l=cs] {ProsÃ­m, vloÅŸte vaÅ¡e uÅŸivatelskÃ© jmÃ©ho.}
+_textpasswordempty_ [l=cs] {MusÃ­te zadat pÅ¯vodnÃ­ heslo.}
+_textnewpass1empty_ [l=cs] {Zadejte vaÅ¡e novÃ© heslo a potvrÄte jej jeÅ¡tÄ jednou.}
+_textnewpassmismatch_ [l=cs] {DvÄ verze vaÅ¡eho hesla se od sebe liÅ¡Ã­.}
+_textnewinvalidpassword_ [l=cs] {Zadali jste neplatnÃ© heslo.}
+_textfailed_ [l=cs] {UÅŸivatelskÃ© jmÃ©no nebo heslo nebylo sprÃ¡vnÃ©.}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=cs] {Verze Greenstone}
+_textframebrowser_ [l=cs] {VÃ¡Å¡ prohlÃ­ÅŸeÄ musÃ­ bÃœt schopen zobrazovat rÃ¡mce (frames).}
+_textusermanage_ [l=cs] {SprÃ¡va uÅŸivatelÅ¯}
+_textlistusers_ [l=cs] {seznam uÅŸivatelÅ¯}
+_textaddusers_ [l=cs] {pÅidat novÃ©ho uÅŸivatele}
+_textchangepasswd_ [l=cs] {zmÄnit heslo}
+_textinfo_ [l=cs] {TechnickÃ© informace}
+_textgeneral_ [l=cs] {vÅ¡eobecnÄ}
+_textarguments_ [l=cs] {argumenty}
+_textactions_ [l=cs] {akce}
+_textbrowsers_ [l=cs] {prohlÃ­ÅŸeÄ}
+_textprotocols_ [l=cs] {protokoly}
+_textconfigfiles_ [l=cs] {Soubory s konfiguracÃ­}
+_textlogs_ [l=cs] {Protokol o aktivitÃ¡ch}
+_textusagelog_ [l=cs] {protokol o pouÅŸitÃ­}
+_textinitlog_ [l=cs] {protokol o vstupech}
+_texterrorlog_ [l=cs] {soubor o chybÃ¡ch}
+_textadminhome_ [l=cs] {domov sprÃ¡vce}
+_textreturnhome_ [l=cs] {Greenstone home}
+_titlewelcome_ [l=cs] {Administrace}
+_textmaas_ [l=cs] {DostupnÃ© sluÅŸby pro administraci a ÃºdrÅŸbu zahrnujÃ­:}
+_textvol_ [l=cs] {zobrazit on-line pÅÃ­stupy}
+_textcmuc_ [l=cs] {vytvoÅit, udrÅŸovat a aktualizovat kolekce}
+_textati_ [l=cs] {pÅÃ­stup k technickÃœm informacÃ­, jako napÅ. CGI argumenty}
+
+_texttsaa_ [l=cs] {Tyto sluÅŸby se aktivujÃ­ pouÅŸitÃ­m krajnÃ­ navigaÄnÃ­ liÅ¡ty na levÃ© stranÄ obrazovky.}
+
+_textcolstat_ [l=cs] {Status kolekce}
+
+_textcwoa_ [l=cs] {Kolekce budou mÃ­t atribut "spuÅ¡tÄnÃ¡", pouze pokud jejich konfiguraÄnÃ­ soubory existujÃ­
+(build.cfg), jsou ÄitelnÃ©, obsahujÃ­ platnÃ¡ pole data vytvoÅenÃ­ (tj. > 0) a jsou v adresÃ¡Åi index
+(tzn. ne uvnitÅ adresÃ¡Åe building). }
+
+_textcafi_ [l=cs] {kliknÄte na <i>abbrev.</i> pro informace o danÃ© kolekci}
+_textcctv_ [l=cs] {kliknÄte na <i>kolekci<i> pro zobrazenÃ­}
+_textsubc_ [l=cs] {UloÅŸit zmÄny}
+_texteom_ [l=cs] {Chyba pÅi otevÃ­rÃ¡nÃ­ main.cfg}
+_textftum_ [l=cs] {ZmÄna main.cfg se nezdaÅila}
+_textmus_ [l=cs] {main.cfg ÃºspÄÅ¡nÄ aktualizovÃ¡n}
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=cs] {VytvoÅit souhrn o kolekci _collectionname_}
+_textflog_ [l=cs] {Soubor se zprÃ¡vou o ztracenÃœch souborech _collectionname_}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=cs] {PouÅŸitelnost Greenstone}
+
+_textwhy_ [l=cs] {<p>
+TÃ­m, ÅŸe odeÅ¡lete tuto zprÃ¡vu, nÃ¡m dÃ¡te najevo, ÅŸe prohlÃ­ÅŸenÃ¡ strÃ¡nka byla sloÅŸitÃ¡ Äi odrazujÃ­cÃ­.}
+_textextraforform_ [l=cs] {NemusÃ­te vyplnit celÃœ formulÃ¡Å -- jakÃ©koliv informace pomohou.}
+_textprivacybasic_ [l=cs] {<p>
+ZprÃ¡va bude obsahovat pouze informace o webovÃ© strÃ¡nce, kterou jste prÃ¡vÄ vidÄli a informace o technice, kterou jste k jejÃ­mu zobrazenÃ­ pouÅŸÃ­vali (plus dodateÄnÃ© informace, kterÃ© nÃ¡m napÃ­Å¡ete).}
+_textstillsend_ [l=cs] {PÅejete si odeslat tuto zprÃ¡vu?}
+
+_texterror_ [l=cs] {chyba}
+_textyes_ [l=cs] {Ano}
+_textno_ [l=cs] {Ne}
+_textclosewindow_ [l=cs] {ZavÅÃ­t okno}
+_textabout_ [l=cs] {O}
+_textprivacy_ [l=cs] {SoukromÃ©}
+_textsend_ [l=cs] {Odeslat}
+_textdontsend_ [l=cs] {NeodesÃ­lat}
+_textoptionally_ [l=cs] {VolitelnÄ}
+
+_textunderdev_ [l=cs] {DetailnÃ­ pÅehled bude k dispozici ve finÃ¡lnÃ­ verzi.}
+
+_textviewdetails_ [l=cs] {UkÃ¡zat detailnÃ­ zprÃ¡vu}
+_textmoredetails_ [l=cs] {VÃ­ce podrobnostÃ­}
+_texttrackreport_ [l=cs] {Sledovat tuto zprÃ¡vu}
+_textcharacterise_ [l=cs] {Co to je za problÃ©m}
+_textseverity_ [l=cs] {Jak zÃ¡vaÅŸnÃœ je to problÃ©m}
+ 
+_textbadrender_ [l=cs] {StrÃ¡nka vypadÃ¡ divnÄ}
+_textcontenterror_ [l=cs] {Chyba obsahu}
+_textstrangebehaviour_ [l=cs] {PodivnÃ© chovÃ¡nÃ­}
+_textunexpected_ [l=cs] {Stalo se nÄco neoÄekÃ¡vanÃ©ho}
+_textfunctionality_ [l=cs] {ObtÃ­ÅŸnÃ© pouÅŸÃ­vÃ¡nÃ­}
+_textother_ [l=cs] {JinÃ©}
+
+_textcritical_ [l=cs] {KrickÃœ}
+_textmajor_ [l=cs] {ZÃ¡vaÅŸnÃœ}
+_textmedium_ [l=cs] {StÅednÃ­}
+_textminor_ [l=cs] {OkrajovÃœ}
+_texttrivial_ [l=cs] {NicotnÃœ}
+
+_textwhatdoing_ [l=cs] {Co jste chtÄli udÄlat?}
+_textwhatexpected_ [l=cs] {Co jste oÄekÃ¡vali?}
+_textwhathappened_ [l=cs] {Co se stalo?}
+
+_cannotfindcgierror_ [l=cs] {<h2>OmlouvÃ¡me se.</h2>Nelze najÃ­t pÅÃ­sluÅ¡nÃ© programy na serveru (pro sluÅŸbu "RÃ¡d bych poznamenal...").}
+
+_textusabbanner_ [l=cs] {koru-style baner pro Greenstone}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+_textgli_ [l=cs] {RozhranÃ­ Librarian}
+_textglihelp_ [l=cs] {RozhranÃ­ Librarian (zkracovÃ¡no jako GLI polde <i>Greenstone Librarian Interface</i>) poskytuje
+snadno pouÅŸitelnÃœ pÅÃ­stup k funkcÃ­m systÃ©mu Greenstone formou grafickÃ©ho uÅŸivatelskÃ©ho rozhranÃ­.
+To umoÅŸÅuje shormaÅŸÄovat skupiny dokumentÅ¯, importovat a pÅiÅazovat metadata a vytvÃ¡Ået kolekce
+digitÃ¡lnÃ­ knihovny Greenstone.
+<p>
+GLI pracuje ve spojenÃ­ s Greenstone a pÅedpoklÃ¡dÃ¡ se, ÅŸe je nainstalovÃ¡n v podadresÃ¡Åi
+instalace Greenstone. To platÃ­ pokud jste nahrÃ¡li jednu z distirbucÃ­ Greenstone z internetu nebo
+jste ji nainstalovali z CD-ROM.
+
+
+<h4>SpuÅ¡tÄnÃ­ GLI ve Windows</h4>
+
+Ve Windows spustÃ­te Librarian pÅes hlavnÃ­ menu (<i>Start</i>) a poloÅŸky
+ <i>Programy</i>, <i>Greenstone Digital Library</i> vÃœbÄrem <i>Greenstone Librarian Interface</i>.
+
+ 
+<h4>SpuÅ¡tÄnÃ­ GLI pod Unixem</h4>
+
+Pro spuÅ¡tÄnÃ­ GLI pod Unixem otevÅete podadresÃ¡Å <i>gli</i> adresÃ¡Åe instalace Greenstone 
+a spusÅ¥te skript <i>gli.sh</i>.}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "rohranÃ­ Greenstone Librarian" ## green_bar_left_aligned ## gligr ##
+_httpicongligr_ [l=cs] {_httpimg_/cs/gligr.gif}
+_widthgligr_ [l=cs] {_pagewidth_}
+_heightgligr_ [l=cs] {17}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/dateqry.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/dateqry.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/dateqry.dm	(revision 10506)
@@ -0,0 +1,148 @@
+# this file must be UTF-8 encoded
+
+package query
+
+
+#######################################################################
+# Macros whose values are set from within the server at runtime. These 
+# are here only for reference and to set default values if required.           
+#######################################################################
+
+_quotedquery_ {}
+_freqmsg_ {}
+_resultline_ {}
+_thisfirst_ {}
+_thislast_ {}
+_nextfirst_ {}
+_nextlast_ {}
+_prevfirst_ {}
+_prevlast_ {}
+_searchhistorylist_ {}
+
+#######################################################################
+# icons
+#######################################################################
+
+_iconthispage_ {<img src="_httpiconhsearch_" alt="_texticonthispage_" title="_texticonthispage_" width="_widthhsearch_" height="_heighthsearch_">}
+_iconthispage_ [v=1] {<h2>_texticonthispage_</h2>}
+
+_iconqueryresultsbar_ {<img src="_httpiconqryresb_" width="_widthqryresb_" height="_heightqryresb_" alt="_texticonqueryresultsbar_" title="_texticonqueryresultsbar_">}
+_iconqueryresultsbar_[v=1] {_texticonqueryresultsbar_}
+
+# _iconnext_ and _iconprev_ are overridden in this package as we
+# don't want alt text here
+_iconnext_{<img src="_httpiconmore_" width=_widthmore_ height=_heightmore_ border=0 align=top>}
+_iconnext_ [v=1] {}
+_iconprev_{<img src="_httpiconless_" width=_widthless_ height=_heightless_ border=0 align=top>}
+_iconprev_ [v=1] {}
+
+#######################################################################
+# images
+#######################################################################
+
+_imagethispage_ {_iconthispage_}
+
+
+#######################################################################
+# page content
+#######################################################################
+
+_pagetitle_ {_If_(_cgiargq_,_textquerytitle_,_textnoquerytitle_)}
+
+_content_ {
+<center>
+_optnavigationbar_
+</center>
+_queryform_
+_If_(_searchhistorylist_,<center>
+_searchhistorylist_
+</center>)
+_If_(_cgiargq_,<center>_iconqueryresultsbar_</center><br>
+<small>
+_freqmsg_
+_textpostprocess_</small><br>
+,<center>_iconblankbar_</center>)<br>
+_resultline_<p>
+}
+
+_queryform_ {
+<!-- query form -->
+<form name=QueryForm method=get action="_gwcgi_">
+
+<input type=hidden name="a" value="q">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="r" value="1">
+<input type=hidden name="hs" value="1">
+<input type=hidden name="g" value="Document" 
+<center>
+<table><tr><td>
+<nobr>
+	_textselect_<br>
+<nobr>	
+</tr></td>
+<tr><td>
+<nobr>
+	<center>
+	<input type="text" name="q" value="_cgiargq_" size="50">
+	<input type="submit" value="_textbeginsearch_">
+	</center>
+</nobr>
+</tr></td>
+<tr><td>
+	_textdatesearch_<br>
+</tr></td>
+<tr><td>
+	<center>
+_textstartdate_
+<input type="text" name="ds" value = "_cgiargds_"size="4" maxlength="4">
+<select name="dsbc" value="_cgiargdsbc_" size="1">
+	<option value = "0"_If_(_cgiargdsbc_,, selected)>_textad_
+	<option value = "1"_If_(_cgiargdsbc_, selected)>_textbc_
+</select> 
+_textenddate_
+<input type="text" name="de" value = "_cgiargde_" size="4" maxlength="4"> 
+<select name="debc" size="1">
+	<option value = "0" _If_(_cgiargdebc_,, selected)>_textad_
+	<option value = "1" _If_(_cgiargdebc_, selected)>_textbc_
+</select> 
+</center>	  
+</tr></td>
+<tr><td>
+_textexplaineras_
+</tr></td>
+</table>
+</center>
+</form>
+<!-- end of query form -->
+}
+
+_textselect_ {_If_(_cgiargb_,_textadvancedsearch_,_textsimplesearch_)}
+
+# we want to put the links to previous/next pages of results
+# in the footer
+_pagefooterextra_ {
+<center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr>
+<td align=left>_If_(_prevfirst_,<a href="_httpquery_&r=_prevfirst_">_iconprev__textmatches__prevfirst_ - _prevlast_</a>)</td>
+<td align=right>_If_(_nextfirst_,<a href="_httpquery_&r=_nextfirst_">_textmatches__nextfirst_ - _nextlast__iconnext_</a>)</td>
+</tr></table>
+</center>
+}
+
+_querytypeselection_ {
+<select name="t">
+<option value="1"_If_(_cgiargt_, selected)>_textsome_
+<option value="0"_If_(_cgiargt_,, selected)>_textall_
+</select>
+}
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/macros/docs.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/docs.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/docs.dm	(revision 10506)
@@ -0,0 +1,37 @@
+# this file must be UTF-8 encoded
+
+package docs
+
+# set from within server
+_documentation_ {}
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. 
+
+_javalinks_ {_imagehome_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+}
+
+#######################################################################
+# page content
+#######################################################################
+
+_icongsdocsgr_ {<img src="_httpicongsdocsgr_">}
+_httpiconpdf_ {_httpimg_/pdf.gif}
+_iconpdf_ {<img src="_httpiconpdf_" border=0>}
+
+_httpdocs_ {_httpprefix_/docs}
+
+_pagetitle_ {_textimagegreenstone_}
+
+_content_ {
+_icongsdocsgr_
+_If_(_documentation_,_documentation_,_textnodocumentation_)
+
+_nzdlpagefooter_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/document.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/document.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/document.dm	(revision 10506)
@@ -0,0 +1,387 @@
+# this file must be UTF-8 encoded
+
+package document
+
+#######################################################################
+# macros set from within the server
+#######################################################################
+
+_imagethispage_ {}
+_httpprevarrow_ {}
+_httpnextarrow_ {}
+_pagetitle_ {}
+_phindclassifier_ {}
+_collageclassifier_ {}
+
+#######################################################################
+# page content
+#######################################################################
+
+_content_ {
+<center>
+_optnavigationbar_
+<p>
+_phindclassifier_
+_collageclassifier_
+</center>
+}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitlepage_ {_texticonhtitle_}
+_textCreatorpage_ {_texticonhcreat_}
+_textSubjectpage_ {_texticonhsubj_}
+_textDescriptionpage_ {_texticonhdesc_}
+_textPublisherpage_ {_texticonhpubl_}
+_textContributorpage_ {_texticonhcontr_}
+_textDatepage_ {_texticonhdate_}
+_textTypepage_ {_texticonhtype_}
+_textFormatpage_ {_texticonhform_}
+_textIdentifierpage_ {_texticonhident_}
+_textSourcepage_ {_texticonhsrc_}
+_textLanguagepage_ {_texticonhlang_}
+_textRelationpage_ {_texticonhrel_}
+_textCoveragepage_ {_texticonhcover_}
+_textRightspage_ {_texticonhright_}
+
+_textTopage_ {_texticonhto_}
+_textFrompage_ {_texticonhfrom_}
+_textSeriespage_ {_texticonhser_}
+_textHowtopage_ {_texticonhhow_}
+_textOrganizationpage_ {_texticonhorg_}
+_textBrowsepage_ {_texticonhbrwse_}
+_textCollagepage_ {_texticonhcoll_}
+_textPeoplepage_ {_texticonhpeople_}
+_textAcronympage_ {_texticonhacronym_}
+_textPhrasepage_ {_texticonhphrases_}
+_textArtistpage_ {_texticonhartist_}
+_textKeywordpage_ {_texticonhkw_}
+_textVolumepage_ {_texticonhvol_}
+_textCaptionspage_ {_texticonhcapt_}
+_textCountriespage_ {_texticonhcount_}
+
+#######################################################################
+# navigation arrows
+#
+#######################################################################
+
+# these two may be reset to "" by the server
+_navarrowsbottom_ {_navarrows_}
+_navarrowstop_ {_navarrows_}
+
+_navarrows_ {<center>
+<table width=_pagewidth_ cellpadding=0 cellspacing=0 border=0>
+<tr><td align=left valign=top>
+_prevarrow_
+</td><td align=right valign=top>
+_nextarrow_
+</td></tr></table>
+</center>
+}
+
+_prevarrow_ {_If_(_httpprevarrow_,<a href="_httpprevarrow_">_iconprev_</a>)}
+_nextarrow_ {_If_(_httpnextarrow_,<a href="_httpnextarrow_">_iconnext_</a>)}
+
+_navarrows_ [v=1] {<p>
+_prevarrow_<br>
+_nextarrow_
+}
+
+#######################################################################
+# the goto form
+#######################################################################
+
+_gotoform_ {
+<form name="GotoForm" method="get" action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="d" value="_cgiargd_">
+<input type=hidden name="cl" value="_cgiargcl_">
+<input type="text" name="gp" size="3" maxlength="4">
+<input type="submit" value="_textgoto_">
+</form>
+}
+
+_textnumpages_ {&nbsp;<i>(_1_ _pages_)</i>}
+_parentarrow_ {}
+
+
+#######################################################################
+# the phind applet
+#
+# The phind applet is only required on phind classifier pages.
+# Consequently, the _phindclassifier_ macro is not usually set.  On screens
+# where it is required, _phindclassifier_ resolves to _phindapplet_, and
+# the following macro is loaded into the web page.
+#######################################################################
+
+_phindapplet_ {
+<APPLET CODEBASE="_httpprefix_/bin/java" CODE="org.nzdl.gsdl.Phind.Phind.class" ARCHIVE="Phind.jar" WIDTH=500 HEIGHT=400>
+  <PARAM NAME=library      VALUE="_gwcgi_?e=_compressedoptions_">
+  <PARAM NAME=phindcgi     VALUE="_gwcgi_?a=phind">
+  <PARAM NAME=collection   VALUE="_cgiargc_">
+  <PARAM NAME=classifier   VALUE="_phindnumber_">
+
+  <PARAM NAME=orientation  VALUE="vertical">
+  <PARAM NAME=depth        VALUE="2">
+  <PARAM NAME=resultorder VALUE="L,l,E,e,D,d">
+
+  <PARAM NAME=backdrop     VALUE="_httpimg_/phindbg1.jpg">
+  <PARAM NAME=fontsize     VALUE="10">
+  <PARAM NAME=blocksize    VALUE="10">
+
+  The Phind java applet.
+</APPLET>
+}
+
+_collageapplet_ {
+ <applet CODEBASE="_httpprefix_/bin/java" 
+     code="org.nzdl.gsdl.GsdlCollageApplet.GsdlCollageApplet.class"
+     archive="GsdlCollageApplet.jar" 
+     width="_collagexdim_" height="_collageydim_">
+
+        <param name="gwcgi" value="_gwcgi_">
+        <param name="collection" value="_cgiargc_">
+        <param name="classifier" value="_cgiargcl_.1">
+
+        <param name="hrefMustHave" value="cl=_cgiargcl_.1">
+        <param name="imageMustNotHave" value="hl=\%x=\%gt=\%gc=\%.pr">
+
+        <param name="imageType" value="_collageimageType_">
+        <param name="verbosity" value="_collageverbosity_">
+        <param name="maxDepth" value="_collagemaxDepth_">
+        <param name="maxDisplay" value="_collagemaxDisplay_">
+        <param name="refreshDelay" value="_collagerefreshDelay_">
+        <param name="isJava2" value="_collageisJava2_">
+        <param name="bgcolor" value="_collagebgcolor_">
+
+ </applet>
+
+<center>
+_collagecaption_
+</center>
+
+}
+
+
+#######################################################################
+# icons
+#######################################################################
+
+# title images - there should be one of these for each classification
+# supported by this receptionist
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_iconTitlepage_ {<img src="_httpiconhtitle_" width="_widthhtitle_" height="_heighthtitle_">}
+_iconTitlepage_ [v=1] {<h2>_texticonhtitle_</h2>}
+
+_iconCreatorpage_ {<img src="_httpiconhcreat_" width="_widthhcreat_" height="_heighthcreat_">}
+_iconCreatorpage_ [v=1] {<h2>_texticonhcreat_</h2>}
+
+_iconSubjectpage_ {<img src="_httpiconhsubj_" width="_widthhsubj_" height="_heighthsubj_">}
+_iconSubjectpage_ [v=1] {<h2>_texticonhsubj_</h2>}
+
+_iconDescriptionpage_ {<img src="_httpiconhdesc_" width="_widthhdesc_" height="_heighthdesc_">}
+_iconDescriptionpage_ [v=1] {<h2>_texticonhdesc_</h2>}
+
+_iconPublisherpage_ {<img src="_httpiconhpubl_" width="_widthhpubl_" height="_heighthpubl_">}
+_iconPublisherpage_ [v=1] {<h2>_texticonhpubl_</h2>}
+
+_iconContributorpage_ {<img src="_httpiconhcontr_" width="_widthhcontr_" height="_heighthcontr_">}
+_iconContributorpage_ [v=1] {<h2>_texticonhcontr_</h2>}
+
+_iconDatepage_ {<img src="_httpiconhdate_" width="_widthhdate_" height="_heighthdate_">}
+_iconDatepage_ [v=1] {<h2>_texticonhdate_</h2>}
+
+_iconTypepage_ {<img src="_httpiconhtype_" width="_widthhtype_" height="_heighthtype_">}
+_iconTypepage_ [v=1] {<h2>_texticonhtype_</h2>}
+
+_iconFormatpage_ {<img src="_httpiconhform_" width="_widthhform_" height="_heighthform_">}
+_iconFormatpage_ [v=1] {<h2>_texticonhform_</h2>}
+
+_iconIdentifierpage_ {<img src="_httpiconhident_" width="_widthhident_" height="_heighthident_">}
+_iconIdentifierpage_ [v=1] {<h2>_texticonhident_</h2>}
+
+_iconSourcepage_ {<img src="_httpiconhsrc_" width="_widthhsrc_" height="_heighthsrc_">}
+_iconSourcepage_ [v=1] {<h2>_texticonhsrc_</h2>}
+
+_iconLanguagepage_ {<img src="_httpiconhlang_" width="_widthhlang_" height="_heighthlang_">}
+_iconLanguagepage_ [v=1] {<h2>_texticonhlang_</h2>}
+
+_iconRelationpage_ {<img src="_httpiconhrel_" width="_widthhrel_" height="_heighthrel_">}
+_iconRelationpage_ [v=1] {<h2>_texticonhrel_</h2>}
+
+_iconCoveragepage_ {<img src="_httpiconhcover_" width="_widthhcover_" height="_heighthcover_">}
+_iconCoveragepage_ [v=1] {<h2>_texticonhcover_</h2>}
+
+_iconRightspage_ {<img src="_httpiconhright_" width="_widthhright_" height="_heighthright_">}
+_iconRightspage_ [v=1] {<h2>_texticonhright_</h2>}
+
+
+
+_iconCollagepage_ {<img src="_httpiconhcoll_" width="_widthhcoll_"
+height="_heighthcoll_">}
+_iconCollagepage_ [v=1] {<h2>_texticonhcoll_</h2>}
+
+_iconListpage_ {<img src="_httpiconhlist_" width="_widthhlist_"
+height="_heighthlist_">}
+_iconListpage_ [v=1] {<h2>_texticonhlist_</h2>}
+
+_iconTopage_ {<img src="_httpiconhto_" width="_widthhto_"
+height="_heighthto_">}
+_iconTopage_ [v=1] {<h2>_texticonhto_</h2>}
+
+_iconFrompage_ {<img src="_httpiconhfrom_" width="_widthhfrom_"
+height="_heighthfrom_">}
+_iconFrompage_ [v=1] {<h2>_texticonhfrom_</h2>}
+
+_iconSeriespage_ {<img src="_httpiconhser_" width="_widthhser_"
+height="_heighthser_">}
+_iconSeriespage_ [v=1] {<h2>_texticonhser_</h2>}
+
+_iconHowtopage_ {<img src="_httpiconhhow_" width="_widthhhow_"
+height="_heighthhow_">}
+_iconHowtopage_ [v=1] {<h2>_texticonhhow_</h2>}
+
+_iconTopicpage_ {<img src="_httpiconhtopic_" width="_widthhtopic_"
+height="_heighthtopic_">}
+_iconTopicpage_ [v=1] {<h2>_texticonhtopic_</h2>}
+
+_iconOrganizationpage_ {<img src="_httpiconhorg_" width="_widthhorg_"
+height="_heighthorg_">}
+_iconOrganizationpage_ [v=1] {<h2>_texticonhorg_</h2>}
+
+_iconBrowsepage_ {<img src="_httpiconhbrwse_" width="_widthhbrwse_"
+height="_heighthbrwse_">}
+_iconBrowsepage_ [v=1] {<h2>_texticonhbrwse_</h2>}
+
+_iconPeoplepage_ {<img src="_httpiconhpeople_" width="_widthhpeople_"
+height="_heighthpeople_">}
+_iconPeoplepage_ [v=1] {<h2>_texticonhpeople_</h2>}
+
+_iconAcronympage_ {<img src="_httpiconhacronym_" width="_widthhacronym_"
+height="_heighthacronym_">}
+_iconAcronympage_ [v=1] {<h2>_texticonhacronym_</h2>}
+
+_iconPhrasepage_ {<img src="_httpiconhphrse_" width="_widthhphrse_"
+height="_heighthphrse_">}
+_iconPhrasepage_ [v=1] {<h2>_texticonhphrse_</h2>}
+
+_iconArtistpage_ {<img src="_httpiconhartist_" width="_widthhartist_"
+height="_heighthartist_">}
+_iconArtistpage_ [v=1] {<h2>_texticonhartist_</h2>}
+
+_iconKeywordpage_ {<img src="_httpiconhkw_" width="_widthhkw_"
+height="_heighthkw_">}
+_iconKeywordpage_ [v=1] {<h2>_texticonhkw_</h2>}
+
+_iconVolumepage_ {<img src="_httpiconhvol_" width="_widthhvol_"
+height="_heighthvol_">}
+_iconVolumepage_ [v=1] {<h2>_texticonhvol_</h2>}
+
+_iconCaptionspage_ {<img src="_httpiconhcapt_" width="_widthhcapt_"
+height="_heighthcapt_">}
+_iconCaptionspage_ [v=1] {<h2>_texticonhcapt_</h2>}
+
+_iconCountriespage_ {<img src="_httpiconhcount_" width="_widthhcount_"
+height="_heighthcount_">}
+_iconCountriespage_ [v=1] {<h2>_texticonhcount_</h2>}
+
+
+_iconsmalltext_ {<img src="_httpiconsmtext_" border=0 width=_widthsmtext_ height=_heightsmtext_ alt="_texticonsmalltext_" title="_texticonsmalltext_">}
+_iconsmalltext_ [v=1] {<small><b>_texticonsmalltext2_</b></small>}
+
+_iconarrowsmalltext_ {<img src="_httpiconasmtext_" border=0 width=_widthasmtext_ height=_heightasmtext_ alt="_texticonsmalltext_" title="_texticonsmalltext_">}
+_iconarrowsmalltext_ [v=1] {<small><b>->_texticonsmalltext2_</b></small>}
+
+_iconclosedfolder_ {<img src="_httpiconclsdfldr_" border=0 width=_widthclsdfldr_ height=_heightclsdfldr_ alt="_texticonclosedfolder_" title="_texticonclosedfolder_">}
+_iconclosedfolder_ [v=1] {<small><b>_texticonclosedfolder2_</b></small>}
+
+_iconarrowclosedfolder_ {<img src=_httpiconaclsdfdr_" border=0 width=_widthaclsdfdr_ height=_heightaclsdfdr_ alt="_texticonclosedfolder_" title="_texticonclosedfolder_">}
+_iconarrowclosedfolder_ [v=1] {<small><b>->_texticonclosedfolder2_</b></small>}
+
+_iconopenfolder_ {<img src="_httpiconopenfldr_" border=0 width=_widthopenfldr_ height=_heightopenfldr_ alt="_texticonopenfolder_" title="_texticonopenfolder_">}
+_iconopenfolder_ [v=1] {<small><b>_texticonopenfolder2_</b></small>}
+
+_iconarrowopenfolder_ {<img src="_httpiconaopenfdr_" border=0 width=_widthaopenfdr_ height=_heightaopenfdr_ alt="_texticonopenfolder_" title="_texticonopenfolder_">}
+_iconarrowopenfolder_ [v=1] {<small><b>->_texticonopenfolder2_</b></small>}
+
+_iconarrowclosedbook_ {<img src="_httpiconabook_" width=_widthabook_ height=_heightabook_ border=0 alt="_texticonclosedbook_" title="_texticonclosedbook_">}
+_iconarrowclosedbook_ [v=1] {<small><b>->_texticonclosedbook_: </b></small>}
+
+_iconopenbook_ {<img src="_httpiconopenbook_" width=_widthopenbook_ height=_heightopenbook_ border=0 alt="_texticonopenbook_" title="_texticonopenbook_">}
+_iconopenbook_ [v=1] {<small><b>_texticonopenbook_: </b></small>}
+
+_iconarrowopenbook_ {<img src="_httpiconaopenbk_" width=_widthaopenbk_ height=_heightaopenbk_ border=0 alt="_texticonopenbook_" title="_texticonopenbook_">}
+_iconarrowopenbook_ [v=1] {<small><b>->_texticonopenbook_: </b></small>}
+
+_iconopenbookshelf_ {<img src="_httpiconbshelf_" border=0 width=_widthbshelf_ height=_heightbshelf_ alt="_texticonopenbookshelf_" title="_texticonopenbookshelf_">}
+_iconopenbookshelf_ [v=1] {<small><b>_texticonopenbookshelf_: </b></small>}
+
+_iconarrowopenbookshelf_ {<img src="_httpiconabshelf_" border=0 width=_widthabshelf_ height=_heightabshelf_ alt="_texticonopenbookshelf_" title="_texticonopenbookshelf_">}
+_iconarrowopenbookshelf_ [v=1] {<small><b>->_texticonopenbookshelf_: </b></small>}
+
+_iconclosedbookshelf_ {<img src="_httpiconbshelf_" border=0 width=_widthbshelf_ height=_heightbshelf_ alt="_texticonclosedbookshelf_" title="_texticonclosedbookshelf_">}
+_iconclosedbookshelf_ [v=1] {<small><b>_texticonclosedbookshelf_: </b></small>}
+
+_iconarrowclosedbookshelf_ {<img src="_httpiconabshelf_" border=0 width=_widthabshelf_ height=_heightabshelf_ alt="_texticonclosedbookshelf_" title="_texticonclosedbookshelf_">}
+_iconarrowclosedbookshelf_ [v=1] {<small><b>->_texticonclosedbookshelf_: </b></small>}
+
+_iconpointer_ {<img src="_httpiconarrrght_" border=0 width=_widtharrrght_ height=_heightarrrght_>}
+_iconpointer_ [v=1] {<small><b>_texticonpointer_-> </b></small>}
+
+_icontab_ {<img src="_httpicontabspace_" width=_widthtabspace_ height=_heighttabspace_>}
+_tab_ {<td>_icontab_</td>}
+
+_iconwarning_ {<img src="_httpiconwarning_" width=_widthwarning_ height=_heightwarning_ border=0 align=left>}
+_iconwarning_ [v=1] {_texticonwarning_}
+
+
+#######################################################################
+# images
+#######################################################################
+
+# can't use _gsimage_ macro for detach button as we need to include target
+_imagedetach_ {<a href="_httpcurrentdocument_&x=1" target=\_blank onMouseover="roll('detach',1);" onMouseOut="roll('detach',0);"><img
+name="detach" src="_httpiconedtchof_" onLoad="gbutton(this,'_httpiconedtchon_');" border=0 alt="_texticondetach_" title="_texticondetach_"></a>}
+_imagedetach_ [v=1] {<a href="_httpcurrentdocument_&x=1" target=\_blank>_texticondetach_</a><br>}
+
+_imagehighlight_ {_gsimage_(_httpcurrentdocument_&hl=1&gc=_cgiarggc_&amp;gt=_cgiarggt_,_document:httpiconehlof_,_document:httpiconehlon_,hl,_document:texticonhighlight_)}
+
+_imagenohighlight_ {_gsimage_(_httpcurrentdocument_&hl=0&gc=_cgiarggc_&amp;gt=_cgiarggt_,_document:httpiconenhlof_,_document:httpiconenhlon_,nhl,_document:texticonnohighlight_)}
+
+_imagecontracttoc_ {_gsimage_(_httpcurrentdocument_&gc=0,_document:httpiconeconcof_,_document:httpiconeconcon_,concon,_document:texticoncontracttoc_)}
+
+_imageexpandtoc_ {_gsimage_(_httpcurrentdocument_&gc=1,_document:httpiconeexpcof_,_document:httpiconeexpcon_,expcon,_document:texticonexpandtoc_)}
+
+_imagecontracttext_ {_gsimage_(_httpcurrentdocument_&amp;gt=0,_document:httpiconetsecof_,_document:httpiconetsecon_,thissec,_document:texticoncontracttext_)}
+
+_imageexpandtext_ {_gsimage_(_httpcurrentdocument_&amp;gt=1,_document:httpiconealltof_,_document:httpiconeallton_,alltext,_document:texticonexpandtext_)}
+
+_imagecont_ {_gsimage_(_httpcurrentdocument_&amp;gt=2,_document:httpiconcontoff_,_document:httpiconconton_,cont,_document:texticoncont_)}
+
+
+#######################################################################
+# headers/footers
+#######################################################################
+
+
+# header overridden for text pages
+# the tabspace is there because netscape refuses to let our flashy button
+# javacript stuff work on a button that is the first image in the page
+_textheader_ {_cgihead_
+_htmlhead_
+<center>
+<table width=_pagewidth_><tr><td align=right>
+_icontab__javalinks_</td></tr></table>
+</center>
+}
+_textheader_ [v=1] {_cgihead_
+_htmlhead_
+_javalinks_
+}
+
+_footer_ {
+<p>
+_navarrowsbottom_
+_endspacer__htmlfooter_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/dutch.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/dutch.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/dutch.dm	(revision 10506)
@@ -0,0 +1,1267 @@
+ # this file must be UTF-8 encoded
+######################################################################
+#
+# Dutch Language text and icon macros, translated 8.9.2000
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textperiodicals_
+# -- Missing translation: _textsource_
+# -- Missing translation: _textdate_
+# -- Missing translation: _textnumpages_
+
+# -- Missing translation: _textsignin_
+
+_textdefaultcontent_ [l=nl] {De vereisde pagina kon niet worden gevonden. 
+Gebruik de terug knop van de browser of de home knop om naar de hoofdpagina 
+van de Greenstone Digitale Bibliotheek terug te keren.}
+
+_textdefaulttitle_ [l=nl] {GSDL Error}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=nl] {Deze collectie bevat _about:numdocs_ documenten. 
+De collectie werd _about:builddate_ dagen geleden vervaardigd.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+# -- Missing translation: _collectorextra_
+
+_textimagecollection_ [l=nl] {}
+_textimageabout_ [l=nl] {Informatie-pagina}
+_textimagehome_ [l=nl] {Hoofdpagina}
+_textimagehelp_ [l=nl] {Helppagina}
+_textimagepref_ [l=nl] {Preferenctie-pagina}
+_textimagegreenstone_ [l=nl] {Greenstone Digital Library Software}
+# -- Missing translation: _textimageusab_
+
+_textimagesearch_ [l=nl] {Zoeken specifieke termen}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=nl] {Browsen titels in alfabetische orde}
+_textimageCreator_ [l=nl] {Browsen alfabeitsche lijst van auteurs}
+_textimageSubject_ [l=nl] {Browsen volgens onderwerpen}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=nl] {Browsen volgens datum}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+# -- Missing translation: _textimageSource_
+_textimageLanguage_ [l=nl] {Browsen volgens taal}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=nl] {Browsen volgens organisaties}
+# -- Missing translation: _textimageKeyword_
+_textimageHowto_ [l=nl] {Browsen volgens help onderwerpen}
+_textimageList_ [l=nl] {Browsen documenten lijst}
+_textimageSeries_ [l=nl] {Browsen volgens uitgaven}
+_textimageTo_ [l=nl] {Browsen volgens geadresseerde}
+_textimageFrom_ [l=nl] {Browsen volges afzender}
+_textimageTopic_ [l=nl] {Browsen volgens speciale themas}
+_textimageBrowse_ [l=nl] {Browsen}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=nl] {Browsen alfabetische personenlijst}
+_textimageAcronym_ [l=nl] {Browsen volgens afkortingen}
+# -- Missing translation: _textimagePhrase_
+# -- Missing translation: _textimageArtist_
+# -- Missing translation: _textimageVolume_
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=nl] {Zoeken}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=nl] {Titels A-Z}
+_texticontabCreatorgreen_ [l=nl] {Auteurs A-Z}
+_texticontabSubjectgreen_ [l=nl] {Onderwerpen}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=nl] {Datums}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+# -- Missing translation: _texticontabSourcegreen_
+_texticontabLanguagegreen_ [l=nl] {Taalen}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=nl] {Organisatie}
+# -- Missing translation: _texticontabKeywordgreen_
+_texticontabhowgreen_ [l=nl] {Help}
+_texticontabseriesgreen_ [l=nl] {Reeksen}
+_texticontablistgreen_ [l=nl] {Lijsten}
+_texticontabtogreen_ [l=nl] {Geadresseerde}
+_texticontabfromgreen_ [l=nl] {Afzender}
+_texticontabtopicgreen_ [l=nl] {Themas}
+_texticontabbrwsegreen_ [l=nl] {Browsen}
+# -- Missing translation: _texticontabCollagegreen_
+# -- Missing translation: _texticontabbrowsgreen_
+_texticontabPeoplegreen_ [l=nl] {Personen A-Z}
+_texticontabAcronymgreen_ [l=nl] {Afkortingen}
+# -- Missing translation: _texticontabPhrasegreen_
+# -- Missing translation: _texticontabArtistgreen_
+# -- Missing translation: _texticontabVolumegreen_
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=nl] {Documenten weergeven}
+_texticonclosedbook_ [l=nl] {Dokument openen en inhoud op het scherm brengen}
+_texticonnext_ [l=nl] {naar de volgende sectie}
+_texticonprev_ [l=nl] {naar de vooafgaande sectie}
+
+# -- Missing translation: _texticonworld_
+
+# -- Missing translation: _texticonmidi_
+# -- Missing translation: _texticonmsword_
+# -- Missing translation: _texticonmp3_
+# -- Missing translation: _texticonpdf_
+# -- Missing translation: _texticonps_
+# -- Missing translation: _texticonppt_
+# -- Missing translation: _texticonrtf_
+# -- Missing translation: _texticonxls_
+
+_page_ [l=nl] {pagina }
+_pages_ [l=nl] {paginas}
+_of_ [l=nl] {uit }
+_vol_ [l=nl] {Deel}
+_num_ [l=nl] {Nummer}
+
+_textmonth00_ [l=nl] {}
+_textmonth01_ [l=nl] {Januari}
+_textmonth02_ [l=nl] {Februari}
+_textmonth03_ [l=nl] {Maart}
+_textmonth04_ [l=nl] {April}
+_textmonth05_ [l=nl] {Mei}
+_textmonth06_ [l=nl] {Juni}
+_textmonth07_ [l=nl] {Juli}
+_textmonth08_ [l=nl] {Augustus}
+_textmonth09_ [l=nl] {September}
+_textmonth10_ [l=nl] {Oktober}
+_textmonth11_ [l=nl] {November}
+_textmonth12_ [l=nl] {December}
+
+_textdocument_ [l=nl] {Document}
+_textsection_ [l=nl] {Sectie}
+_textparagraph_ [l=nl] {Alinea}
+
+_magazines_ [l=nl] {tijdschriften}
+
+_nzdlpagefooter_ [l=nl] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "HOOFDPAGINA" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=nl] {_httpimg_/nl/chomeof.gif}
+_httpiconchomeon_ [l=nl] {_httpimg_/nl/chomeon.gif}
+
+## "HELP" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=nl] {_httpimg_/nl/chelpof.gif}
+_httpiconchelpon_ [l=nl] {_httpimg_/nl/chelpon.gif}
+
+## "PREFERENTIES" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=nl] {_httpimg_/nl/cprefof.gif}
+_httpiconcprefon_ [l=nl] {_httpimg_/nl/cprefon.gif}
+
+# -- Missing translation: cusab
+# -- Missing translation: _httpiconcusabof_
+# -- Missing translation: _httpiconcusabon_
+
+
+## "zoeken" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=nl] {_httpimg_/nl/tsrchgr.gif}
+_httpicontsrchof_ [l=nl] {_httpimg_/nl/tsrchof.gif}
+_httpicontsrchon_ [l=nl] {_httpimg_/nl/tsrchon.gif}
+_widthtsrchx_ [l=nl] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "titels a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=nl] {_httpimg_/nl/ttitlgr.gif}
+_httpiconttitleof_ [l=nl] {_httpimg_/nl/ttitlof.gif}
+_httpiconttitleon_ [l=nl] {_httpimg_/nl/ttitlon.gif}
+_widthttitlex_ [l=nl] {87}
+
+# Not true DC, kept for legacy reasons
+## "auteurs a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=nl] {_httpimg_/nl/tauthgr.gif}
+_httpicontcreatof_ [l=nl] {_httpimg_/nl/tauthof.gif}
+_httpicontcreaton_ [l=nl] {_httpimg_/nl/tauthon.gif}
+_widthtcreatx_ [l=nl] {100}
+
+## "onderwerpen" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=nl] {_httpimg_/nl/tsubjgr.gif}
+_httpicontsubjon_ [l=nl] {_httpimg_/nl/tsubjon.gif}
+_httpicontsubjof_ [l=nl] {_httpimg_/nl/tsubjof.gif}
+_widthtsubjx_ [l=nl] {110}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "datums" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=nl] {_httpimg_/nl/tdategr.gif}
+_httpicontdateof_ [l=nl] {_httpimg_/nl/tdateof.gif}
+_httpicontdateon_ [l=nl] {_httpimg_/nl/tdateon.gif}
+_widthtdatex_ [l=nl] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: tsrc
+# -- Missing translation: _httpicontsrcgr_
+# -- Missing translation: _httpicontsrcof_
+# -- Missing translation: _httpicontsrcon_
+# -- Missing translation: _widthtsrcx_
+
+## "taal" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=nl] {_httpimg_/nl/tlanggr.gif}
+_httpicontlangon_ [l=nl] {_httpimg_/nl/tlangon.gif}
+_httpicontlangof_ [l=nl] {_httpimg_/nl/tlangof.gif}
+_widthtlangx_ [l=nl] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "reksen" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=nl] {_httpimg_/nl/tsergr.gif}
+_httpicontserof_ [l=nl] {_httpimg_/nl/tserof.gif}
+_httpicontseron_ [l=nl] {_httpimg_/nl/tseron.gif}
+_widthtserx_ [l=nl] {87}
+
+## "geadresseerde" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=nl] {_httpimg_/nl/ttogr.gif}
+_httpiconttoon_ [l=nl] {_httpimg_/nl/ttoon.gif}
+_httpiconttoof_ [l=nl] {_httpimg_/nl/ttoof.gif}
+_widthttox_ [l=nl] {122}
+
+## "afzender" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=nl] {_httpimg_/nl/tfromgr.gif}
+_httpicontfromon_ [l=nl] {_httpimg_/nl/tfromon.gif}
+_httpicontfromof_ [l=nl] {_httpimg_/nl/tfromof.gif}
+_widthtfromx_ [l=nl] {87}
+
+## "organisatie" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=nl] {_httpimg_/nl/torggr.gif}
+_httpicontorgon_ [l=nl] {_httpimg_/nl/torgon.gif}
+_httpicontorgof_ [l=nl] {_httpimg_/nl/torgof.gif}
+_widthtorgx_ [l=nl] {94}
+
+## "help onderwerpen" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=nl] {_httpimg_/nl/thowgr.gif}
+_httpiconthowon_ [l=nl] {_httpimg_/nl/thowon.gif}
+_httpiconthowof_ [l=nl] {_httpimg_/nl/thowof.gif}
+_widththowx_ [l=nl] {151}
+
+## "thema" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=nl] {_httpimg_/nl/ttopicgr.gif}
+_httpiconttopicon_ [l=nl] {_httpimg_/nl/ttopicon.gif}
+_httpiconttopicof_ [l=nl] {_httpimg_/nl/ttopicof.gif}
+_widthttopicx_ [l=nl] {87}
+
+## "browsen" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=nl] {_httpimg_/nl/tbrwsegr.gif}
+_httpicontbrwseon_ [l=nl] {_httpimg_/nl/tbrwseon.gif}
+_httpicontbrwseof_ [l=nl] {_httpimg_/nl/tbrwseof.gif}
+_widthtbrwsex_ [l=nl] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "personen" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=nl] {_httpimg_/nl/tpeopgr.gif}
+_httpicontpeopof_ [l=nl] {_httpimg_/nl/tpeopof.gif}
+_httpicontpeopon_ [l=nl] {_httpimg_/nl/tpeopon.gif}
+_widthtpeopx_ [l=nl] {87}
+
+## "afkortingen" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=nl] {_httpimg_/nl/tacrogr.gif}
+_httpicontacroof_ [l=nl] {_httpimg_/nl/tacroof.gif}
+_httpicontacroon_ [l=nl] {_httpimg_/nl/tacroon.gif}
+_widthtacrox_ [l=nl] {98}
+
+# -- Missing translation: tphrse
+# -- Missing translation: _httpicontphrsegr_
+# -- Missing translation: _httpicontphrseof_
+# -- Missing translation: _httpicontphrseon_
+# -- Missing translation: _widthtphrsex_
+
+# -- Missing translation: tartst
+# -- Missing translation: _httpicontartstgr_
+# -- Missing translation: _httpicontartstof_
+# -- Missing translation: _httpicontartston_
+# -- Missing translation: _widthtartstx_
+
+# -- Missing translation: tkw
+# -- Missing translation: _httpicontkwgr_
+# -- Missing translation: _httpicontkwof_
+# -- Missing translation: _httpicontkwon_
+# -- Missing translation: _widthtkwx_
+
+# -- Missing translation: tvol
+# -- Missing translation: _httpicontvolgr_
+# -- Missing translation: _httpicontvolof_
+# -- Missing translation: _httpicontvolon_
+# -- Missing translation: _widthtvolx_
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "help" ## green_title ## h_help ##
+_httpiconhhelp_ [l=nl] {_httpimg_/nl/h\_help.gif}
+_widthhhelp_ [l=nl] {200}
+_heighthhelp_ [l=nl] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=nl] {informatie over deze collectie}
+
+_textsubcols1_ [l=nl] {<p>De volledige collectie bevat _1_ subcollecties:
+<blockquote>}
+
+_textsubcols2_ [l=nl] {</blockquote>
+Voor het controleren en veranderen van subcollecties in gebruik 
+ga naar de preferentie pagina.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "informatie" ## green_title ## h_about ##
+_httpiconhabout_ [l=nl] {_httpimg_/nl/h\_about.gif}
+_widthhabout_ [l=nl] {200}
+_heighthabout_ [l=nl] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=nl] {Titels A-Z}
+_texticonhcreat_ [l=nl] {Auteurs A-Z}
+_texticonhsubj_ [l=nl] {Onderwerpen}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=nl] {Datums}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+# -- Missing translation: _texticonhsrc_
+_texticonhlang_ [l=nl] {Taalen}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=nl] {Geadresseerde}
+_texticonhfrom_ [l=nl] {Afzender}
+_texticonhser_ [l=nl] {Reeksen}
+_texticonhhow_ [l=nl] {Help onderwerpen}
+_texticonhorg_ [l=nl] {Organizaties}
+_texticonhbrwse_ [l=nl] {Browsen}
+# -- Missing translation: _texticonhbrows_
+_texticonhpeople_ [l=nl] {Personen A-Z}
+_texticonhacronym_ [l=nl] {Afkortingen}
+# -- Missing translation: _texticonhphrases_
+# -- Missing translation: _texticonhartist_
+# -- Missing translation: _texticonhkw_
+# -- Missing translation: _texticonhvol_
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=nl] {Sluit dit gedeelte van de bibliotheek}
+_texticonclosedbookshelf_ [l=nl] {Open dit tgedeelte van de bibliotheek en bring de inhoud op het scherm.}
+_texticonopenbook_ [l=nl] {Sluit dit boek}
+_texticonclosedfolder_ [l=nl] {Open deze map en breng de inhoud op het scherm}
+_texticonclosedfolder2_ [l=nl] {Open deze onder-sectie:}
+_texticonopenfolder_ [l=nl] {Sluit deze map: }
+_texticonopenfolder2_ [l=nl] {Sluit deze onder sectie: }
+_texticonsmalltext_ [l=nl] {Geef deze sectie van de tekst weer}
+_texticonsmalltext2_ [l=nl] {Geef tekst weer: }
+_texticonpointer_ [l=nl] {Actueele sectie}
+_texticondetach_ [l=nl] {Open en nieuw venster voor deze pagina}
+_texticonhighlight_ [l=nl] {Accentueer zoek termen}
+_texticonnohighlight_ [l=nl] {Accentueer zoek termen niet}
+_texticoncontracttoc_ [l=nl] {Inhoudsopgave inkorten}
+_texticonexpandtoc_ [l=nl] {Inhouds opgave uitbreiden}
+_texticonexpandtext_ [l=nl] {Hele tekst weergeven}
+_texticoncontracttext_ [l=nl] {Alleen maar geselecteerde tekst weergeven}
+_texticonwarning_ [l=nl] {<b>Waarschuiving: </b>}
+_texticoncont_ [l=nl] {Voortzetten?}
+
+_textltwarning_ [l=nl] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Het Uitbreiden van deze tekst zal 
+een grote hoeveelheid data produceeren om _imagecont_ door de browser 
+weer te geven.
+</td></tr></table></center>
+}
+
+_textgoto_ [l=nl] {Ga naar pagina}
+_textintro_ [l=nl] {<i>(Inleidende tekst)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "titels a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=nl] {_httpimg_/nl/h\_title.gif}
+_widthhtitle_ [l=nl] {200}
+_heighthtitle_ [l=nl] {57}
+
+# Not true DC, kept for legacy reasons
+## "auteurs a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=nl] {_httpimg_/nl/h\_auth.gif}
+_widthhcreat_ [l=nl] {200}
+_heighthcreat_ [l=nl] {57}
+
+## "onderwerpen" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=nl] {_httpimg_/nl/h\_subj.gif}
+_widthhsubj_ [l=nl] {200}
+_heighthsubj_ [l=nl] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "datums" ## green_title ## h_date ##
+_httpiconhdate_ [l=nl] {_httpimg_/nl/h\_date.gif}
+_widthhdate_ [l=nl] {200}
+_heighthdate_ [l=nl] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_src
+# -- Missing translation: _httpiconhsrc_
+# -- Missing translation: _widthhsrc_
+# -- Missing translation: _heighthsrc_
+
+## "taalen" ## green_title ## h_lang ##
+_httpiconhlang_ [l=nl] {_httpimg_/nl/h\_lang.gif}
+_widthhlang_ [l=nl] {200}
+_heighthlang_ [l=nl] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "geadresseerde" ## green_title ## h_to ##
+_httpiconhto_ [l=nl] {_httpimg_/nl/h\_to.gif}
+_widthhto_ [l=nl] {200}
+_heighthto_ [l=nl] {57}
+
+## "afzenders" ## green_title ## h_from ##
+_httpiconhfrom_ [l=nl] {_httpimg_/nl/h\_from.gif}
+_widthhfrom_ [l=nl] {200}
+_heighthfrom_ [l=nl] {57}
+
+## "reeksen" ## green_title ## h_ser ##
+_httpiconhser_ [l=nl] {_httpimg_/nl/h\_ser.gif}
+_widthhser_ [l=nl] {200}
+_heighthser_ [l=nl] {57}
+
+## "help onderwerpen" ## green_title ## h_how ##
+_httpiconhhow_ [l=nl] {_httpimg_/nl/h\_how.gif}
+_widthhhow_ [l=nl] {200}
+_heighthhow_ [l=nl] {57}
+
+## "themas" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=nl] {_httpimg_/nl/h\_topic.gif}
+_widthhtopic_ [l=nl] {200}
+_heighthtopic_ [l=nl] {57}
+
+## "organisaties" ## green_title ## h_org ##
+_httpiconhorg_ [l=nl] {_httpimg_/nl/h\_org.gif}
+_widthhorg_ [l=nl] {250}
+_heighthorg_ [l=nl] {57}
+
+## "browsen" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=nl] {_httpimg_/nl/h\_brwse.gif}
+_widthhbrwse_ [l=nl] {200}
+_heighthbrwse_ [l=nl] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "personen" ## green_title ## h_people ##
+_httpiconhpeople_ [l=nl] {_httpimg_/nl/h\_people.gif}
+_widthhpeople_ [l=nl] {200}
+_heighthpeople_ [l=nl] {57}
+
+## "afkortingen" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=nl] {_httpimg_/nl/h\_acro.gif}
+_widthhacronym_ [l=nl] {200}
+_heighthacronym_ [l=nl] {57}
+
+# -- Missing translation: h_phrse
+# -- Missing translation: _httpiconhphrse_
+# -- Missing translation: _widthhphrse_
+# -- Missing translation: _heighthphrse_
+
+# -- Missing translation: h_artist
+# -- Missing translation: _httpiconhartist_
+# -- Missing translation: _widthhartist_
+# -- Missing translation: _heighthartist_
+
+# -- Missing translation: h_kw
+# -- Missing translation: _httpiconhkw_
+# -- Missing translation: _widthhkw_
+# -- Missing translation: _heighthkw_
+
+# -- Missing translation: h_vol
+# -- Missing translation: _httpiconhvol_
+# -- Missing translation: _widthhvol_
+# -- Missing translation: _heighthvol_
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+## "VOORTZETTEN?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=nl] {_httpimg_/nl/contof.gif}
+_httpiconconton_ [l=nl] {_httpimg_/nl/conton.gif}
+
+## "TEKST\nUITBREIDEN" ## document_button ## eallt ##
+_httpiconealltof_ [l=nl] {_httpimg_/nl/ealltof.gif}
+_httpiconeallton_ [l=nl] {_httpimg_/nl/eallton.gif}
+
+## "INHOUD\nINKRIMPEN" ## document_button ## econc ##
+_httpiconeconcof_ [l=nl] {_httpimg_/nl/econcof.gif}
+_httpiconeconcon_ [l=nl] {_httpimg_/nl/econcon.gif}
+
+## "NIEUW\nVENSTER" ## document_button ## edtch ##
+_httpiconedtchof_ [l=nl] {_httpimg_/nl/edtchof.gif}
+_httpiconedtchon_ [l=nl] {_httpimg_/nl/edtchon.gif}
+
+## "INHOUD\nUITBREIDEN" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=nl] {_httpimg_/nl/eexpcof.gif}
+_httpiconeexpcon_ [l=nl] {_httpimg_/nl/eexpcon.gif}
+
+## "TEKST\nINKRIMPEN" ## document_button ## etsec ##
+_httpiconetsecof_ [l=nl] {_httpimg_/nl/etsecof.gif}
+_httpiconetsecon_ [l=nl] {_httpimg_/nl/etsecon.gif}
+
+## "ACCENTUEREN" ## document_button ## ehl ##
+_httpiconehlof_ [l=nl] {_httpimg_/nl/ehlof.gif}
+_httpiconehlon_ [l=nl] {_httpimg_/nl/ehlon.gif}
+
+## "NIET\nACCENTUEREN" ## document_button ## enhl ##
+_httpiconenhlof_ [l=nl] {_httpimg_/nl/enhlof.gif}
+_httpiconenhlon_ [l=nl] {_httpimg_/nl/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=nl] {_If_(_thislast_, _thisfirst_ - _thislast_ resultaten voor de zoekactie: _cgiargq_,geen resultaat voor de zoekactie: _cgiargq_)}
+_textnoquerytitle_ [l=nl] {Zoek pagina}
+
+_texticonthispage_ [l=nl] {doorzoeken van}
+_textsome_ [l=nl] {somige}
+_textall_ [l=nl] {alle}
+_textboolean_ [l=nl] {boolse}
+_textranked_ [l=nl] {gestaffelde}
+# -- Missing translation: _textnatural_
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=nl] {}
+# -- Missing translation: _texticonsearchhistorybar_
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+# -- Missing translation: _textusequery_
+_textfreqmsg1_ [l=nl] {aantal woorden: }
+_textpostprocess_ [l=nl] {_If_(_quotedquery_,<br><i>verder verwerkt om _quotedquery_ te vinden</i>
+)}
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=nl] {Meer dan }
+_textapprox_ [l=nl] {Ongeveer }
+_textnodocs_ [l=nl] {Geen documenten gevonden.}
+_text1doc_ [l=nl] {1 document gevonden.}
+_textlotsdocs_ [l=nl] {documenten gevonden.}
+_textmatches_ [l=nl] {passende teksten }
+_textbeginsearch_ [l=nl] {Begin zoekactie}
+# -- Missing translation: _textrunquery_
+# -- Missing translation: _textclearform_
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+# -- Missing translation: _textwordphrase_
+# -- Missing translation: _textinfield_
+# -- Missing translation: _textfoldstem_
+
+# -- Missing translation: _textadvquery_
+# -- Missing translation: _textallfields_
+# -- Missing translation: _texttextonly_
+# -- Missing translation: _textand_
+# -- Missing translation: _textor_
+# -- Missing translation: _textandnot_
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=nl] {Doorzoek _indexselection__If_(_jselection_,of _jselection_)_If_(_gselection_, op het _gselection_ niveau)_If_(_nselection_, in _nselection_ taal) naar _querytypeselection_ van de volgende woorden}
+
+_textadvancedsearch_ [l=nl] {Doorzoek _indexselection_ _If_(_jselection_,of _jselection_)_If_(_gselection_, op het _gselection_ niveau)_If_(_nselection_, in _nselection_ taal) met een _querytypeselection_ zoekvraag}
+
+# -- Missing translation: _textformsimplesearch_
+
+# -- Missing translation: _textformadvancedsearch_
+
+
+# -- Missing translation: _textnojsformwarning_
+# -- Missing translation: _textdatesearch_
+# -- Missing translation: _textstartdate_
+# -- Missing translation: _textenddate_
+# -- Missing translation: _textbc_
+# -- Missing translation: _textad_
+# -- Missing translation: _textexplaineras_
+
+_textstemon_ [l=nl] {(Woord einden negeeren)}
+
+_textsearchhistory_ [l=nl] {Vroegere zoekacties doorzoeken}
+
+#text macros for search history
+_textnohistory_ [l=nl] {Vroegere zoekacties zijn niet beschikbaar}
+# -- Missing translation: _texthresult_
+# -- Missing translation: _texthresults_
+# -- Missing translation: _texthallwords_
+# -- Missing translation: _texthsomewords_
+# -- Missing translation: _texthboolean_
+# -- Missing translation: _texthranked_
+# -- Missing translation: _texthcaseon_
+# -- Missing translation: _texthcaseoff_
+# -- Missing translation: _texthstemon_
+# -- Missing translation: _texthstemoff_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "zoeken" ## green_title ## h_search ##
+_httpiconhsearch_ [l=nl] {_httpimg_/nl/h\_search.gif}
+_widthhsearch_ [l=nl] {200}
+_heighthsearch_ [l=nl] {57}
+
+## "resultaten" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=nl] {_httpimg_/nl/qryresb.gif}
+_widthqryresb_ [l=nl] {_pagewidth_}
+_heightqryresb_ [l=nl] {17}
+
+# -- Missing translation: schhistb
+# -- Missing translation: _httpiconsrchhistb_
+# -- Missing translation: _widthsrchhistb_
+# -- Missing translation: _heightsrchhistb_
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textprefschanged_
+# -- Missing translation: _textsetprefs_
+_textsearchprefs_ [l=nl] {Zoek preferenties}
+_textcollectionprefs_ [l=nl] {Collectie preferenties}
+_textpresentationprefs_ [l=nl] {Presentatie preferenties}
+_textpreferences_ [l=nl] {Preferenties}
+# -- Missing translation: _textcasediffs_
+_textignorecase_ [l=nl] {Negeer Hoofdletters}
+_textmatchcase_ [l=nl] {Kleine letters en hoofdletters moeten exact overeenstemmen}
+# -- Missing translation: _textwordends_
+_textstem_ [l=nl] {Negeer woord einden }
+_textnostem_ [l=nl] {Geheel woord moet overeenstemmen}
+_textprefop_ [l=nl] {Weergeven van maximaal _maxdocoption_ treffers met maximaal _hitsperpageoption_ treffers per pagina.}
+_textextlink_ [l=nl] {Toegang tot externe Web paginas: }
+_textintlink_ [l=nl] {Bronnen documenten opgevraagd van:}
+_textlanguage_ [l=nl] {Interface taal: }
+_textencoding_ [l=nl] {Encodering: }
+_textformat_ [l=nl] {Interface formaat: }
+_textall_ [l=nl] {alle}
+# -- Missing translation: _textquerymode_
+_textsimplemode_ [l=nl] {Eenvoudige zoek modus}
+_textadvancedmode_ [l=nl] {Geavanceerde zoek modus (zoek termen gekombineerd met boolse termen mogelijk b.v. !, &, |, en parentheses)}
+_textlinkinterm_ [l=nl] {via tussen pagina}
+_textlinkdirect_ [l=nl] {Ga direct naar de Webpagina}
+_textdigitlib_ [l=nl] {de digitale bibliotheek}
+_textweb_ [l=nl] {Het Web}
+_textgraphical_ [l=nl] {Grafisch}
+_texttextual_ [l=nl] {Tekst}
+_textcollectionoption_ [l=nl] {<p>
+Ondercollecties die ingesloten moeten worden:
+<br>}
+
+# -- Missing translation: _textrelateddocdisplay_
+# -- Missing translation: _textsearchhistory_
+# -- Missing translation: _textnohistory_
+# -- Missing translation: _texthistorydisplay_
+# -- Missing translation: _textnohistorydisplay_
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+# -- Missing translation: _textformsearch_
+# -- Missing translation: _textplainsearch_
+# -- Missing translation: _textqueryboxsize_
+# -- Missing translation: _textregbox_
+# -- Missing translation: _textbigbox_
+# -- Missing translation: _textformtype_
+# -- Missing translation: _textsimple_
+# -- Missing translation: _textadvanced_
+
+# used in "with 4 fields" in the form search box
+# -- Missing translation: _textwith_
+# -- Missing translation: _textfields_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferenties" ## green_title ## h_pref ##
+_httpiconhpref_ [l=nl] {_httpimg_/nl/h\_pref.gif}
+_widthhpref_ [l=nl] {200}
+_heighthpref_ [l=nl] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+# -- Missing translation: _textsortby_
+# -- Missing translation: _textalsoshowing_
+# -- Missing translation: _textwith_
+# -- Missing translation: _textdocsperpage_
+
+# -- Missing translation: _textfilterby_
+# -- Missing translation: _textall_
+# -- Missing translation: _textany_
+# -- Missing translation: _textwords_
+# -- Missing translation: _textleaveblank_
+
+# -- Missing translation: _browsebuttontext_
+
+# -- Missing translation: _nodata_
+# -- Missing translation: _docs_
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=nl] {Help}
+_textSearchshort_ [l=nl] {naar bepaalde woorden zoeken}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=nl] {publicaties gesorteerd volgens titels}
+_textCreatorshort_ [l=nl] {publicaties gesorteerd volgens auteurs}
+_textSubjectshort_ [l=nl] {publicaties gesorteerd volgens onderwerpen}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=nl] {publicaties gesorteerd volgens datum}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+# -- Missing translation: _textSourceshort_
+_textLanguageshort_ [l=nl] {publicaties gesorteerd volgens taalen}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=nl] {publicaties gesorteerd volgens reksen}
+_textToshort_ [l=nl] {publicaties gesorteerd volgens geadresseerden}
+_textFromshort_ [l=nl] {publicaties gesorteerd volgens afzenders}
+_textBrowseshort_ [l=nl] {alle publicaties}
+_textOrganizationshort_ [l=nl] {publicaties gesorteerd volgens organisaties}
+_textHowtoshort_ [l=nl] {publicaties gesorteerd volgens help onderwerpen}
+_textTopicshort_ [l=nl] {publicaties gesorteerd volgens themas}
+_textPeopleshort_ [l=nl] {publicaties gesorteerd volgens personen}
+_textAcronymshort_ [l=nl] {publicaties gesorteerd volgens afkortingen}
+# -- Missing translation: _textPhraseshort_
+# -- Missing translation: _textArtistshort_
+# -- Missing translation: _textKeywordshort_
+# -- Missing translation: _textVolumeshort_
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=nl] {ongedefineerde classificatie}
+
+_textSearchlong_ [l=nl] {<p>U kunt <i>naar bepalde woorden zoeken</i> die in de tekst 
+van de zoek pagina voorkomen. De zoekpagina komt op het scherm als U begint 
+en kan vanuit andere paginas opgezocht worden door op de knop <i>zoeken</i> te clicken. }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens titels</i> opzoeken door op 
+de knop <i>titels a-z</i> te clicken.  Deze actie zal een lijst met alfabetisch gesorteerde 
+boekentitels op het scherm brengen.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens auteurs</i> opzoeken door op de knop <i>auteurs a-z</i> te clicken.  Deze actie zal een lijst met 
+met boeken gesorteerd volgens de auteur op het scherm brengen.  }
+
+_textSubjectlong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens onderwerpen</i> opzoeken door op de knop <i>onderwerpen</i> te clicken.  Deze actie zal een lijst met 
+onderwerpen op het scherm brengen gerepresenteerd door boekenkasten.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens datum</i> opzoeken door op de knop <i>datums</i> te clicken.  Deze actie zal een lijst met chronologisch gesorteerde
+publicaties op het scherm brengen.  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: _textSourcelong_
+
+_textLanguagelong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens taalen</i> opzoeken door op de knop <i>taalen</i> te clicken.  Deze actie zal een lijst met 
+publicaties op het scherm brengen gesorteerd volgens taalen.  }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens organisaties</i>  opzoeken door op 
+de knop <i>organisaties</i> te clicken.  Deze actie zal een lijst met 
+organisaties op het scherm brengen.  }
+
+_textHowtolong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens help onderwerpen</i>
+opzoeken door op de knop <i>help onderwerpen</i> te clicken.  Deze actie zal een lijst met 
+help onderwerpen op het scherm brengen.  }
+
+_textTopiclong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens themas</i> opzoeken door op de knop <i>themas</i> te clicken.  Deze actie zal een lijst met 
+themas op het scherm brengen om te browsen.  }
+
+_textTolong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens geadresseerden</i> opzoeken door op de knop <i>geadresseerde</i> te clicken.  Deze actie zal een lijst met 
+geadresseerden op het scherm brengen.  }
+
+_textFromlong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens afzenders</i> opzoeken door op de knop <i>afzenders</i> te clicken.  Deze actie zal een lijst met 
+help onderwerpen op het scherm brengen.  }
+
+_textSerieslong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens reksen</i> opzoeken door op de knop <i>reeksen</i> te clicken.  Deze actie zal een lijst met 
+reeksen op het scherm brengen die op dit moment in de collectie aanwezig zijn.  }
+
+_textBrowselong_ [l=nl] {<p>U kunt <i>alle publicaties</i> opzoeken door op de knop <i>alle publicaties</i> te clicken.  }
+
+_textPeoplelong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens personen</i> opzoeken door op de knop <i>personen a-z</i> te clicken.  Deze actie zal een lijst met 
+personen op het scherm brengen alfabetisch gesorteerd volgens familie naam.  }
+
+_textAcronymlong_ [l=nl] {<p>U kunt <i>publicaties gesorteerd volgens afkortingen</i> opzoeken door op de knop <i>afkortingen</i> te clicken.  Deze actie zal een lijst met 
+afkortingen op het scherm brengen en de tekst stukken waarin deze voorkomen.  }
+
+# -- Missing translation: _textPhraselong_
+
+# -- Missing translation: _textArtistlong_
+
+# -- Missing translation: _textKeywordlong_
+
+# -- Missing translation: _textVolumelong_
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=nl] {<p>Click de knop <i>ongedefineerd</i> om publicaties te browsen die volgens een onbekend veld gesorteerd zijn.}
+
+_texthelptopics_ [l=nl] {<h2 align=left>Topics</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Hoe kan ik voor bepaalde woorden zoeken?</a>
+<ul>
+  <li><a href="\#query-terms">Zoek termen</a>
+  <li><a href="\#query-type">Type zoek vraag</a>
+  <li><a href="\#scope-of-queries">Omvang zoek vraag</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Collectie preferenties</a>
+  <li><a href="\#pres-prefs">Weergave preferenties</a>
+  <li><a href="\#search-prefs">Zoek preferenties</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=nl] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=nl] {Hoe can ik documenten lezen?}
+
+_texthelpreadingdocs_ [l=nl] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>U bent bij een document aangekomen, als de titel en de auteur links boovenaan de pagina 
+verschijnen.  Daarnaast bevinden zich het pagina nummer van de actuele pagina, een box om 
+een nieuwe pagina nummer te kiezen en pijlen om de volgende of voorafgaande pagina te kiezen. 
+
+<p>Onder de pagina nummers bevind zich de tekst van de sectie.  U kunt gebruik maken van de 
+pijlen onderaan de pagina om naar de volgende of voorafgaande sectie komen.
+
+<p>Onder de titel en de auteur bevinden zich drie knoppen. Click op de knop <i>tekst uitbreiden</i> 
+om de hele tekst te zien.  Als U groote documenten uitbreid, zou dit heel wat tijd en geheugen in 
+beslag kunnen nemen!
+Click op de knop <i>nieuw venster</i> om een nieuw venster voer een document te opeuen.  
+(Dit zou handig kunnen zijn, als U twee documenten wilt lezen of als U twee documenten wilt 
+vergelijken.) Na het uitvoeren van een zoekactie, worden de woorden waarnaar U gezocht hebt 
+geaccentueerd. Wilt U dit ongedaan maken, dan clickt U op de knop <i>niet accentueren</i>.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Druk op de pijl om naar de volgende sectie te gaan ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... of terug naar de voorafgaande sectie.</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Geef de hele tekst weer, of niet</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>pen een nieuw venster voor deze pagina</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Accentueer zoektermen of niet</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=nl] {<h2>Zoeken naar bepaalde worden</h2>
+<p>
+  Vanuit de zoek pagina moeten volgende stappen uitgevoerd worden:<p>
+  
+  <ol><li>Kies de documenten die doorzocht moeten worden.
+      <li>Kies of U naar somige of alle woorden wilt zoeken.
+      <li>Typ in de woorden waarnaar gezocht moet worden.
+      <li>Click op de knop <i>Begin zoeken<i>
+  </ol>
+
+<p>Na het uitvoeren van een zoekactie worden de titels van maximaal 20 gevonden documenten 
+per pagina weergengeven. Er is een knop onderaan de pagina om naar de volgende 20 titels te gaan.  
+Vandaar kunt U of terug naar de vooafgaande pagina of  vooruit naar de volgende pagina gaan. 
+Click op de titel of op het knopje ernaast om een document weer te geven.
+
+<p>Er wordt een maximum van 100 gevonden documenten weergengeven.  U kunt het maximum gwonden 
+documenten veranderen via de knop <i>preferenties</I> bovenaan de pagina.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Zoektermen</h3>
+
+<p>Alle woorden in de zoekvraag box worden als zoektermen geinterpreteerd Zoektermen mogen alleen 
+letters en nummers bevatten. Zoektermen worden gesepareerd door een spatie. Alle anderen tekens 
+(zoals kommas of vraagtekens) worden als seperatoren geinterpreteerd.  Ze zijn dus identiek met 
+spaties en worden genegeerd als onderdeel van zoektermen.  Het is dus niet mogelijk om naar 
+worden te zoeken die dit soort tekens bevatten.
+
+<p>Bij voorbeeld de zoekvraag <p>
+    <ul><kbd>s'Maandags</kbd></ul>
+      <p>s het zelfde als <p>
+      <ul><kbd>s Maandags</kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>ypen zoekvragen</h3>
+
+<p>Er zijn twee sorten zoekvragen.
+<ul>
+  <li>Zoekvragen haar <b>alle</b> woorden.  Deze zoekvragen zoeken naar documenten die alle 
+gespecificeerde zoektermen bevatten.  Documenten die aan deze zoekvraag voldoen worden in 
+alphabetische orde weergengeven..<p>
+
+  <li>Zoekvragen naar <b>somige woorden</b>.  Deze zoekvragen zoeken naar documenten die een of 
+merdere zoektermen bevatten.  Voer woorden in, die waarschiijnlijk in de gewensde documenten aanwezig 
+zijn.  Documenten worden weergegeven naar mate zij aan de zoekvraag voldoen.  
+
+      <p><ul>
+        <li> Hoe meer zoektermen een dokument bevat, hoe beter het maat van voldoening met dit soort zoekvragen.
+        <li> Rare woorden werken beter dan gebruiklijke woorden.
+        <li> Korte documenten voeldoen beter aan zoekvragen dan omvangrijke documenten.
+      </ul>
+</ul>
+
+<p>U kunt elk aantal zoektermen invoeren, hele zinnen en hele alineas.  Als U maar een zoekterm 
+invoert zullen de gevonden documenten worden weergegeven in orde van het aantal keren dat de 
+zoekterm werd aangetroffen in een document.<p>
+
+_texthelpscope_
+}
+
+# -- Missing translation: _textdatesearch_
+
+# -- Missing translation: _texthelpdatesearch_
+
+_textchangeprefs_ [l=nl] {Het veranderen van preferenties}
+
+_texthelppreferences_ [l=nl] {<h2>_textchangeprefs_</h2>
+
+<p>Bovenaan de pagina bevindt zich de knop <i>preferenties</i>.  Als U deze knop drukt kunt U de 
+eigensdrappen van het interface veranderen zodat het aan Uw eisen voldoet.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Collectie preferenties</h3>
+
+SoSomige collecties bevatten meerdene sub-collecties.  Deze kunnen individueel doorzocht worden of 
+als een geheel.  Op de preferentie pagina kunt U kiezen welke sub-collecties in de zoekacties 
+inbegrepen moeten worden.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Presentatie preferenties</h3>
+
+Afhankelijk van de type collectie bestaan veschillende opties om de presentatie van 
+de collectie te veranderen.
+
+In collecties van Web paginas kan de Greenstone navigatie lijst onderdrukt worden.  De Greenstone 
+navigatie lijst wordt normaliter bavenaan de dokumenten pagina weergengeven.  Als U kiest om 
+deze lijst te verwijderen zal een zoekactie U naar een Webpagina zonder Greenstone navigatie 
+lijst brengen. 	Om in deze situatie een nieuwe zoek actie uit te voeren moet U gebruik maken van 
+de 'terug'-knop van de browser. Greenstone brengt waarschuings-boodschappen op het scherm als 
+U op een link clickt dat buiten de digitale bibliotheek en op het Web gaat.  Deze 
+waarschuings-boodschappen kunnen onderdrukt worden. In somige Web collecties is het mogelijk 
+om te kiezen of de links van de zoek resultaten pagina direct naar de URL verwijzen of naar de 
+kopie in de digitale bibliotheek.
+
+Collecties, die in verschillende taalen kunnen worden weergegeven, bieden de mogelijkheid om een 
+interface taal te kiezen.  In het geval van Chinees kunt U, degene standard Chinees encodering 
+kiezen die door Uw browser wordt gebruikt.
+
+In alle collecties kunt U kiezen tussen een tekst interface en een graphisch interface.  
+Deze optie is bijzonder helpful voor visueel gehandicapten die extra groote letters willen gebruiken.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Zoek preferenties</h3>
+Met twee paaren van knoppen kunt U het gbruik van Hoofdletters/kleine letters en het gebruik van 
+woordstammen controleren. Met het eeste paar knoppen kunt U kiezen of Hoofdletters in zoektermen 
+in acht genomen moeten worden of niet. Met het tweede paar knoppen kunt U regelen of woordeinden 
+genegeerd moeten worden, of niet.
+
+
+<p>Als b.v. de knoppen <i>negeer hoofdletters</i> en <i>negeer woordeinden</i> geselecteerd zijn, 
+dan zal de zoekvraag <p>
+	<ul><kbd>Africaanse gebouwen</kbd></ul>
+	<p>net zo worden behandelt als de zoekvraag<p>
+	<ul><kbd>Africa gebouw</kbd></ul><p>
+Dit is so, omdat de hoofdletter 'A' naar de kleine letter 'a' word veranderd en de woordeinden 
+"anse" en "en" worden weggelaten.
+
+<p>U kunt ook voor een geavanceerde form van zoekvragen kiezen.  In de geavanceerde zoekvraag 
+kunt U termen combineren door AND (&), OR (I), and NOT (!) te gebruiken.  Op die manier kunt U 
+precisesere zoekvragen formuleren. 
+
+<p>U kunt ook het maximum aantal gevonden documenten en het 
+maximum aantal documenten per pagina veranderen.
+
+}
+
+_texttanumbrowseoptions_ [l=nl] {Er zijn _numbrowseoptions_ moglijkheden om informatie in 
+deze collectie op te sporen:}
+
+_textsimplehelpheading_ [l=nl] {Het opsporen van informatie}
+
+_texthelpscope_ [l=nl] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Omvang van zoekvragen</h3>
+
+<p>
+In de meeste collecties kunt U verschillende indicees kiezen voor Uw zoekacties.  Er zouden auteurs- 
+en titel indicees aanwezig kunnen zijn of hoofdstuk- en alinea indecees. Geheel passende documenten 
+zullen altijd worden gevonden onafhankelijk van de gebruikte index.  
+<p> Boeken worden geopened op het relevante stuk tekst.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/english.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/english.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/english.dm	(revision 10506)
@@ -0,0 +1,1413 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# English Language text and icon macros 
+#
+######################################################################
+#
+# This is the main macro file for translation when creating an 
+# interface in another language.
+
+# Under the 'text macros' comments are text macros of the form:
+# _macroname_ {macro value}
+# Everything between the {} is the text to be translated. This text 
+# may itself contain macros (i.e. characters other than space between
+# underscore characters, e.g. _about:numdocs_ or _textpage_). These
+# macro names occurring within text shouldn't be translated but should
+# be left as they are. Underscores or curly brackets occurring 
+# naturally within the text should be escaped with a leading backslash
+# (i.e. '\_', '\{' or '\}).
+#
+# Under the 'icons' comments are macros concerned with displaying
+# icons which themselves contain text.
+# Above each macro (or group of macros) for an icon is a comment line
+# that looks something like '## "HOME" ## top_nav_button ## chome ##'.
+# The first field of the comment ("HOME" in this case) is the text
+# that appears in the english version of the icon. This is the text
+# that must be translated, nothing needs to be done to the macros 
+# themselves. The other two fields of the comments are used by 
+# automatic icon generating software which reads the newly translated
+# file and generates appropriate icons.
+#
+# Comment lines (other than those described above) need not be 
+# translated (i.e. any lines beginning with '#', like this line).
+#
+# The simplest way to translate this file is to save it as something
+# else (e.g. french.dm) and work through translating all the text
+# macro values and icon comments.
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ {Periodicals}
+_textsource_ {source ref: }
+_textdate_ {publication date: }
+_textnumpages_ {no. of pages: }
+
+_textsignin_ {sign in}
+
+_textdefaultcontent_ {The requested page could not be found. Please use
+your browsers 'back' button or the above home button to return to the
+Greenstone Digital Library.}
+
+_textdefaulttitle_ {GSDL Error}
+
+_textbadcollection_ {This collection (called "_cvariable_") is not installed on this Greenstone digital library system.}
+
+_textselectpage_ {-- Select Page --}
+
+_collectionextra_ {This collection contains _about:numdocs_ documents. 
+It was last built _about:builddate_ days ago.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ {
+<p>This collection contains _numdocs_ _If_("_numdocs_" eq "1",document,documents), a total of _numbytes_.
+<p><a href="_httppagex_(bsummary)">Click here</a> to view the build summary for this collection.
+}
+
+_textimagecollection_ {}
+_textimageabout_ {About page}
+_textimagehome_ {Home page}
+_textimagehelp_ {Help page}
+_textimagepref_ {Preferences page}
+_textimagegreenstone_ {Greenstone Digital Library Software}
+_textimageusab_ {What did you find hard to use?}
+
+_textimagesearch_ {Search for specific terms}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ {Browse alphabetical list of titles}  # Not true DC, kept for legacy reasons
+_textimageCreator_ {Browse alphabetical list of authors}  # Not true DC, kept for legacy reasons
+_textimageSubject_ {Browse by subject}
+_textimageDescription_ {Browse by description}
+_textimagePublisher_ {Browse by publisher}
+_textimageContributor_ {Browse by contributor}
+_textimageDate_ {Browse by date}
+_textimageType_ {Browse by resource type}
+_textimageFormat_ {Browse by format}
+_textimageIdentifier_ {Browse by resource identifier}
+_textimageSource_ {Browse by original filename}  # Not true DC, kept for legacy reasons
+_textimageLanguage_ {Browse by language}
+_textimageRelation_ {Browse by relation}
+_textimageCoverage_ {Browse by coverage}
+_textimageRights_ {Browse by rights}
+
+_textimageOrganization_ {Browse by organization}
+_textimageKeyword_ {Browse by keyword}
+_textimageHowto_ {Browse how to categories}
+_textimageList_ {Browse document listing}
+_textimageSeries_ {Browse by issue}
+_textimageTo_ {Browse by To field}
+_textimageFrom_ {Browse by From field}
+_textimageTopic_ {Browse special topic issues}
+_textimageBrowse_ {Browse}
+_textimageCollage_ {Browse by image collage}
+_textimagePeople_ {Browse alphabetical list of people}
+_textimageAcronym_ {Browse acronyms}
+_textimagePhrase_ {Browse phrases}
+_textimageArtist_ {Browse artists}
+_textimageVolume_ {Browse by volume}
+_textimageCountries_ {Browse by countries}
+_textimageCaptions_ {Browse by photo captions}
+
+
+_texticontabsearchgreen_ {Search}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ {Titles A-Z}  # Not true DC, kept for legacy reasons
+_texticontabCreatorgreen_ {Authors A-Z}  # Not true DC, kept for legacy reasons
+_texticontabSubjectgreen_ {Subjects}
+_texticontabDescriptiongreen_ {Descriptions}
+_texticontabPublishergreen_ {Publishers}
+_texticontabContributorgreen_ {Contributors}
+_texticontabDategreen_ {Dates}
+_texticontabTypesgreen_ {Types}
+_texticontabFormatgreen_ {Formats}
+_texticontabIdentifiergreen_ {Identifiers}
+_texticontabSourcegreen_ {Filenames}  # Not true DC, kept for legacy reasons
+_texticontabLanguagegreen_ {Languages}
+_texticontabRelationgreen_ {Relations}
+_texticontabCoveragegreen_ {Coverage}
+_texticontabRightsgreen_ {Rights}
+
+_texticontaborggreen_ {Organization}
+_texticontabKeywordgreen_ {Keywords}
+_texticontabhowgreen_ {How to}
+_texticontabseriesgreen_ {Series}
+_texticontablistgreen_ {Listing}
+_texticontabtogreen_ {To}
+_texticontabfromgreen_ {From}
+_texticontabtopicgreen_ {Topics}
+_texticontabbrwsegreen_ {Browse}
+_texticontabCollagegreen_ {Collage}
+_texticontabbrowsgreen_ {Browse}
+_texticontabPeoplegreen_ {People A-Z}
+_texticontabAcronymgreen_ {Acronyms}
+_texticontabPhrasegreen_ {Phrases}
+_texticontabArtistgreen_ {Artists}
+_texticontabVolumegreen_ {Volumes}
+_texticontabCaptionsgreen_ {Captions}
+_texticontabCountriesgreen_ {Countries}
+
+_texticontext_ {View the document}
+_texticonclosedbook_ {open this document and view contents}
+_texticonnext_ {to next section}
+_texticonprev_ {to previous section}
+
+_texticonworld_ {View the web document}
+
+_texticonmidi_ {View the MIDI document}
+_texticonmsword_ {View the Microsoft Word document}
+_texticonmp3_ {View the MP3 document}
+_texticonpdf_ {View the PDF document}
+_texticonps_ {View the PostScript document}
+_texticonppt_ {View the PowerPoint document}
+_texticonrtf_ {View the RTF document}
+_texticonxls_ {View the Microsoft Excel document}
+
+_page_ {page }
+_pages_ {pages}
+_of_ { of }
+_vol_ {Vol.}
+_num_ {No.}
+
+_textmonth00_ {}
+_textmonth01_ {January}
+_textmonth02_ {February}
+_textmonth03_ {March}
+_textmonth04_ {April}
+_textmonth05_ {May}
+_textmonth06_ {June}
+_textmonth07_ {July}
+_textmonth08_ {August}
+_textmonth09_ {September}
+_textmonth10_ {October}
+_textmonth11_ {November}
+_textmonth12_ {December}
+
+_textdocument_ {Document}
+_textsection_ {Section}
+_textparagraph_ {Paragraph}
+
+_magazines_ {Magazines}
+
+_nzdlpagefooter_ {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "HOME" ## top_nav_button ## chome ##
+_httpiconchomeof_ {_httpimg_/chomeof.gif}
+_httpiconchomeon_ {_httpimg_/chomeon.gif}
+
+## "HELP" ## top_nav_button ## chelp ##
+_httpiconchelpof_ {_httpimg_/chelpof.gif}
+_httpiconchelpon_ {_httpimg_/chelpon.gif}
+
+## "PREFERENCES" ## top_nav_button ## cpref ##
+_httpiconcprefof_ {_httpimg_/cprefof.gif}
+_httpiconcprefon_ {_httpimg_/cprefon.gif}
+
+## "SEND FEEDBACK" ## top_nav_button ## cusab ##
+_httpiconcusabof_ {_httpimg_/cusabof.gif}
+_httpiconcusabon_ {_httpimg_/cusabon.gif}
+
+
+## "search" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ {_httpimg_/tsrchgr.gif}
+_httpicontsrchof_ {_httpimg_/tsrchof.gif}
+_httpicontsrchon_ {_httpimg_/tsrchon.gif}
+_widthtsrchx_ {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "titles a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ {_httpimg_/ttitlgr.gif}
+_httpiconttitleof_ {_httpimg_/ttitlof.gif}
+_httpiconttitleon_ {_httpimg_/ttitlon.gif}
+_widthttitlex_ {87}
+
+# Not true DC, kept for legacy reasons
+## "authors a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ {_httpimg_/tauthgr.gif}
+_httpicontcreatof_ {_httpimg_/tauthof.gif}
+_httpicontcreaton_ {_httpimg_/tauthon.gif}
+_widthtcreatx_ {87}
+
+## "subjects" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ {_httpimg_/tsubjgr.gif}
+_httpicontsubjon_ {_httpimg_/tsubjon.gif}
+_httpicontsubjof_ {_httpimg_/tsubjof.gif}
+_widthtsubjx_ {87}
+
+## "descriptions" ## nav_bar_button ## tdesc ##
+_httpicontdescgr_ {_httpimg_/tdescgr.gif}
+_httpicontdescon_ {_httpimg_/tdescon.gif}
+_httpicontdescof_ {_httpimg_/tdescof.gif}
+_widthtdescx_ {90}
+
+## "publishers" ## nav_bar_button ## tpubl ##
+_httpicontpublgr_ {_httpimg_/tpublgr.gif}
+_httpicontpublon_ {_httpimg_/tpublon.gif}
+_httpicontpublof_ {_httpimg_/tpublof.gif}
+_widthtpublx_ {87}
+
+## "contributors" ## nav_bar_button ## tcontr ##
+_httpicontcontrgr_ {_httpimg_/tcontrgr.gif}
+_httpicontcontron_ {_httpimg_/tcontron.gif}
+_httpicontcontrof_ {_httpimg_/tcontrof.gif}
+_widthtcontrx_ {89}
+
+## "dates" ## nav_bar_button ## tdate ##
+_httpicontdategr_ {_httpimg_/tdategr.gif}
+_httpicontdateof_ {_httpimg_/tdateof.gif}
+_httpicontdateon_ {_httpimg_/tdateon.gif}
+_widthtdatex_ {87}
+
+## "types" ## nav_bar_button ## ttype ##
+_httpiconttypegr_ {_httpimg_/ttypegr.gif}
+_httpiconttypeof_ {_httpimg_/ttypeof.gif}
+_httpiconttypeon_ {_httpimg_/ttypeon.gif}
+_widthttypex_ {87}
+
+## "formats" ## nav_bar_button ## tform ##
+_httpicontformgr_ {_httpimg_/tformgr.gif}
+_httpicontformof_ {_httpimg_/tformof.gif}
+_httpicontformon_ {_httpimg_/tformon.gif}
+_widthtformx_ {87}
+
+## "identifiers" ## nav_bar_button ## tident ##
+_httpicontidentgr_ {_httpimg_/tidentgr.gif}
+_httpicontidentof_ {_httpimg_/tidentof.gif}
+_httpicontidenton_ {_httpimg_/tidenton.gif}
+_widthtidentx_ {87}
+
+# Not true DC, kept for legacy reasons
+## "filenames" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ {_httpimg_/tsrcgr.gif}
+_httpicontsrcof_ {_httpimg_/tsrcof.gif}
+_httpicontsrcon_ {_httpimg_/tsrcon.gif}
+_widthtsrcx_ {87}
+
+## "languages" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ {_httpimg_/tlanggr.gif}
+_httpicontlangon_ {_httpimg_/tlangon.gif}
+_httpicontlangof_ {_httpimg_/tlangof.gif}
+_widthtlangx_ {87}
+
+## "relations" ## nav_bar_button ## trel ##
+_httpicontrelgr_ {_httpimg_/trelgr.gif}
+_httpicontrelon_ {_httpimg_/trelon.gif}
+_httpicontrelof_ {_httpimg_/trelof.gif}
+_widthtrelx_ {87}
+
+## "coverage" ## nav_bar_button ## tcover ##
+_httpicontcovergr_ {_httpimg_/tcovergr.gif}
+_httpicontcoveron_ {_httpimg_/tcoveron.gif}
+_httpicontcoverof_ {_httpimg_/tcoverof.gif}
+_widthtcoverx_ {87}
+
+## "rights" ## nav_bar_button ## tright ##
+_httpicontrightgr_ {_httpimg_/trightgr.gif}
+_httpicontrighton_ {_httpimg_/trighton.gif}
+_httpicontrightof_ {_httpimg_/trightof.gif}
+_widthtrightx_ {87}
+
+
+
+## "series" ## nav_bar_button ## tser ##
+_httpicontsergr_ {_httpimg_/tsergr.gif}
+_httpicontserof_ {_httpimg_/tserof.gif}
+_httpicontseron_ {_httpimg_/tseron.gif}
+_widthtserx_ {87}
+
+## "to" ## nav_bar_button ## tto ##
+_httpiconttogr_ {_httpimg_/ttogr.gif}
+_httpiconttoon_ {_httpimg_/ttoon.gif}
+_httpiconttoof_ {_httpimg_/ttoof.gif}
+_widthttox_ {87}
+
+## "from" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ {_httpimg_/tfromgr.gif}
+_httpicontfromon_ {_httpimg_/tfromon.gif}
+_httpicontfromof_ {_httpimg_/tfromof.gif}
+_widthtfromx_ {87}
+
+## "organisations" ## nav_bar_button ## torg ##
+_httpicontorggr_ {_httpimg_/torggr.gif}
+_httpicontorgon_ {_httpimg_/torgon.gif}
+_httpicontorgof_ {_httpimg_/torgof.gif}
+_widthtorgx_ {98}
+
+## "how to" ## nav_bar_button ## thow ##
+_httpiconthowgr_ {_httpimg_/thowgr.gif}
+_httpiconthowon_ {_httpimg_/thowon.gif}
+_httpiconthowof_ {_httpimg_/thowof.gif}
+_widththowx_ {87}
+
+## "topic" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ {_httpimg_/ttopicgr.gif}
+_httpiconttopicon_ {_httpimg_/ttopicon.gif}
+_httpiconttopicof_ {_httpimg_/ttopicof.gif}
+_widthttopicx_ {87}
+
+## "browse" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ {_httpimg_/tbrwsegr.gif}
+_httpicontbrwseon_ {_httpimg_/tbrwseon.gif}
+_httpicontbrwseof_ {_httpimg_/tbrwseof.gif}
+_widthtbrwsex_ {87}
+
+## "collage" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ {_httpimg_/tcollgr.gif}
+_httpicontcollof_ {_httpimg_/tcollof.gif}
+_httpicontcollon_ {_httpimg_/tcollon.gif}
+_widthtcollx_ {87}
+
+## "people" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ {_httpimg_/tpeopgr.gif}
+_httpicontpeopof_ {_httpimg_/tpeopof.gif}
+_httpicontpeopon_ {_httpimg_/tpeopon.gif}
+_widthtpeopx_ {97}
+
+## "acronyms" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ {_httpimg_/tacrogr.gif}
+_httpicontacroof_ {_httpimg_/tacroof.gif}
+_httpicontacroon_ {_httpimg_/tacroon.gif}
+_widthtacrox_ {87}
+
+## "phrases" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ {_httpimg_/tphrsegr.gif}
+_httpicontphrseof_ {_httpimg_/tphrseof.gif}
+_httpicontphrseon_ {_httpimg_/tphrseon.gif}
+_widthtphrsex_ {87}
+
+## "artists" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ {_httpimg_/tartstgr.gif}
+_httpicontartstof_ {_httpimg_/tartstof.gif}
+_httpicontartston_ {_httpimg_/tartston.gif}
+_widthtartstx_ {87}
+
+## "keywords" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ {_httpimg_/tkwgr.gif}
+_httpicontkwof_ {_httpimg_/tkwof.gif}
+_httpicontkwon_ {_httpimg_/tkwon.gif}
+_widthtkwx_ {87}
+
+## "volumes" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ {_httpimg_/tvolgr.gif}
+_httpicontvolof_ {_httpimg_/tvolof.gif}
+_httpicontvolon_ {_httpimg_/tvolon.gif}
+_widthtvolx_ {87}
+
+## "captions" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ {_httpimg_/tcaptgr.gif}
+_httpicontcaptof_ {_httpimg_/tcaptof.gif}
+_httpicontcapton_ {_httpimg_/tcapton.gif}
+_widthtcaptx_ {87}
+
+## "countries" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ {_httpimg_/tcountgr.gif}
+_httpicontcountof_ {_httpimg_/tcountof.gif}
+_httpicontcounton_ {_httpimg_/tcounton.gif}
+_widthtcountx_ {87}
+
+## "help" ## green_title ## h_help ##
+_httpiconhhelp_ {_httpimg_/h\_help.gif}
+_widthhhelp_ {200}
+_heighthhelp_ {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ {About this collection}
+
+_textsubcols1_ {<p>The complete collection comprises _1_ subcollections. 
+Those currently available are:
+<blockquote>}
+
+_textsubcols2_ {</blockquote>
+You can check (and alter) which subcollections you are 
+currently using on the Preferences page.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "about" ## green_title ## h_about ##
+_httpiconhabout_ {_httpimg_/h\_about.gif}
+_widthhabout_ {200}
+_heighthabout_ {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ {Titles A-Z}  # Not true DC, kept for legacy reasons
+_texticonhcreat_ {Authors A-Z}  # Not true DC, kept for legacy reasons
+_texticonhsubj_ {Subjects}
+_texticonhdesc_ {Descriptions}
+_texticonhpubl_ {Publishers}
+_texticonhcontr_ {Contributors}
+_texticonhdate_ {Dates}
+_texticonhtype_ {Types}
+_texticonhform_ {Formats}
+_texticonhident_ {Identifiers}
+_texticonhsrc_ {Filenames}  # Not true DC, kept for legacy reasons
+_texticonhlang_ {Languages}
+_texticonhrel_ {Relations}
+_texticonhcover_ {Coverage}
+_texticonhright_ {Rights}
+
+_texticonhcoll_ {Collage}
+_texticonhto_ {To}
+_texticonhfrom_ {From}
+_texticonhser_ {Series}
+_texticonhhow_ {How to}
+_texticonhorg_ {Organizations}
+_texticonhbrwse_ {Browse}
+_texticonhbrows_ {Browse}
+_texticonhpeople_ {People A-Z}
+_texticonhacronym_ {Acronyms}
+_texticonhphrases_ {Phrases}
+_texticonhartist_ {Artists}
+_texticonhkw_ {Keywords}
+_texticonhvol_ {Volumes}
+_texticonhcapt_ {Captions}
+_texticonhcount_ {Countries}
+
+_texticonopenbookshelf_ {close this section of the library}
+_texticonclosedbookshelf_ {open this section of the library and view contents}
+_texticonopenbook_ {close this book}
+_texticonclosedfolder_ {Open this folder and view contents}
+_texticonclosedfolder2_ {open sub-section: }
+_texticonopenfolder_ {close this folder}
+_texticonopenfolder2_ {close sub-section: }
+_texticonsmalltext_ {View this section of the text}
+_texticonsmalltext2_ {view text: }
+_texticonpointer_ {current section}
+_texticondetach_ {Open this page in a new window}
+_texticonhighlight_ {Highlight search terms}
+_texticonnohighlight_ {Don't highlight search terms}
+_texticoncontracttoc_ {Collapse table of contents}
+_texticonexpandtoc_ {Expand table of contents}
+_texticonexpandtext_ {Display all text}
+_texticoncontracttext_ {Display text only for currently selected section}
+_texticonwarning_ {<b>Warning: </b>}
+_texticoncont_ {continue?}
+
+_textltwarning_ {
+<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Expanding the text here will generate a large 
+amount of data for your browser to display _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ {go to page}
+_textintro_ { <i>(introductory text)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "titles a-z" ## green_title ## h_title ##
+_httpiconhtitle_ {_httpimg_/h\_title.gif}
+_widthhtitle_ {200}
+_heighthtitle_ {57}
+
+# Not true DC, kept for legacy reasons
+## "authors a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ {_httpimg_/h\_auth.gif}
+_widthhcreat_ {200}
+_heighthcreat_ {57}
+
+## "subjects" ## green_title ## h_subj ##
+_httpiconhsubj_ {_httpimg_/h\_subj.gif}
+_widthhsubj_ {200}
+_heighthsubj_ {57}
+
+## "descriptions" ## green_title ## h_desc ##
+_httpiconhdesc_ {_httpimg_/h\_desc.gif}
+_widthhdesc_ {200}
+_heighthdesc_ {57}
+
+## "publishers" ## green_title ## h_publ ##
+_httpiconhpubl_ {_httpimg_/h\_publ.gif}
+_widthhpubl_ {200}
+_heighthpubl_ {57}
+
+## "contributors" ## green_title ## h_contr ##
+_httpiconhcontr_ {_httpimg_/h\_contr.gif}
+_widthhcontr_ {200}
+_heighthcontr_ {57}
+
+## "dates" ## green_title ## h_date ##
+_httpiconhdate_ {_httpimg_/h\_date.gif}
+_widthhdate_ {200}
+_heighthdate_ {57}
+
+## "types" ## green_title ## h_type ##
+_httpiconhtype_ {_httpimg_/h\_type.gif}
+_widthhtype_ {200}
+_heighthtype_ {57}
+
+## "formats" ## green_title ## h_form ##
+_httpiconhform_ {_httpimg_/h\_form.gif}
+_widthhform_ {200}
+_heighthform_ {57}
+
+## "identifiers" ## green_title ## h_ident ##
+_httpiconhident_ {_httpimg_/h\_ident.gif}
+_widthhident_ {200}
+_heighthident_ {57}
+
+# Not true DC, kept for legacy reasons
+## "filenames" ## green_title ## h_src ##
+_httpiconhsrc_ {_httpimg_/h\_src.gif}
+_widthhsrc_ {200}
+_heighthsrc_ {57}
+
+## "languages" ## green_title ## h_lang ##
+_httpiconhlang_ {_httpimg_/h\_lang.gif}
+_widthhlang_ {200}
+_heighthlang_ {57}
+
+## "relations" ## green_title ## h_rel ##
+_httpiconhrel_ {_httpimg_/h\_rel.gif}
+_widthhrel_ {200}
+_heighthrel_ {57}
+
+## "coverage" ## green_title ## h_cover ##
+_httpiconhcover_ {_httpimg_/h\_cover.gif}
+_widthhcover_ {200}
+_heighthcover_ {57}
+
+## "rights" ## green_title ## h_right ##
+_httpiconhright_ {_httpimg_/h\_right.gif}
+_widthhright_ {200}
+_heighthright_ {57}
+
+
+
+## "to" ## green_title ## h_to ##
+_httpiconhto_ {_httpimg_/h\_to.gif}
+_widthhto_ {200}
+_heighthto_ {57}
+
+## "from" ## green_title ## h_from ##
+_httpiconhfrom_ {_httpimg_/h\_from.gif}
+_widthhfrom_ {200}
+_heighthfrom_ {57}
+
+## "series" ## green_title ## h_ser ##
+_httpiconhser_ {_httpimg_/h\_ser.gif}
+_widthhser_ {200}
+_heighthser_ {57}
+
+## "how to" ## green_title ## h_how ##
+_httpiconhhow_ {_httpimg_/h\_how.gif}
+_widthhhow_ {200}
+_heighthhow_ {57}
+
+## "topics" ## green_title ## h_topic ##
+_httpiconhtopic_ {_httpimg_/h\_topic.gif}
+_widthhtopic_ {200}
+_heighthtopic_ {57}
+
+## "organization" ## green_title ## h_org ##
+_httpiconhorg_ {_httpimg_/h\_org.gif}
+_widthhorg_ {200}
+_heighthorg_ {57}
+
+## "browse" ## green_title ## h_brwse ##
+_httpiconhbrwse_ {_httpimg_/h\_brwse.gif}
+_widthhbrwse_ {200}
+_heighthbrwse_ {57}
+
+## "collage" ## green_title ## h_coll ##
+_httpiconhcoll_ {_httpimg_/h\_coll.gif}
+_widthhcoll_ {200}
+_heighthcoll_ {57}
+
+## "people" ## green_title ## h_people ##
+_httpiconhpeople_ {_httpimg_/h\_people.gif}
+_widthhpeople_ {200}
+_heighthpeople_ {57}
+
+## "acronyms" ## green_title ## h_acro ##
+_httpiconhacronym_ {_httpimg_/h\_acro.gif}
+_widthhacronym_ {200}
+_heighthacronym_ {57}
+
+## "phrases" ## green_title ## h_phrse ##
+_httpiconhphrse_ {_httpimg_/h\_phrse.gif}
+_widthhphrse_ {200}
+_heighthphrse_ {57}
+
+## "artists" ## green_title ## h_artist ##
+_httpiconhartist_ {_httpimg_/h\_artist.gif}
+_widthhartist_ {200}
+_heighthartist_ {57}
+
+## "keywords" ## green_title ## h_kw ##
+_httpiconhkw_ {_httpimg_/h\_kw.gif}
+_widthhkw_ {200}
+_heighthkw_ {57}
+
+## "volumes" ## green_title ## h_vol ##
+_httpiconhvol_ {_httpimg_/h\_vol.gif}
+_widthhvol_ {200}
+_heighthvol_ {57}
+
+## "countries" ## green_title ## h_count ##
+_httpiconhcount_ {_httpimg_/h\_count.gif}
+_widthhcount_ {200}
+_heighthcount_ {57}
+
+## "captions" ## green_title ## h_capt ##
+_httpiconhcapt_ {_httpimg_/h\_capt.gif}
+_widthhcapt_ {200}
+_heighthcapt_ {57}
+
+
+## "CONTINUE?" ## top_nav_button ## cont ##
+_httpiconcontoff_ {_httpimg_/contof.gif}
+_httpiconconton_ {_httpimg_/conton.gif}
+
+## "EXPAND\nTEXT" ## document_button ## eallt ## 
+_httpiconealltof_ {_httpimg_/ealltof.gif}
+_httpiconeallton_ {_httpimg_/eallton.gif}
+
+## "CONTRACT\nCONTENTS" ## document_button ## econc ##
+_httpiconeconcof_ {_httpimg_/econcof.gif}
+_httpiconeconcon_ {_httpimg_/econcon.gif}
+
+## "DETACH" ## document_button ## edtch ##
+_httpiconedtchof_ {_httpimg_/edtchof.gif}
+_httpiconedtchon_ {_httpimg_/edtchon.gif}
+
+## "EXPAND\nCONTENTS" ## document_button ## eexpc ##
+_httpiconeexpcof_ {_httpimg_/eexpcof.gif}
+_httpiconeexpcon_ {_httpimg_/eexpcon.gif}
+
+## "CONTRACT\nTEXT" ## document_button ## etsec ##
+_httpiconetsecof_ {_httpimg_/etsecof.gif}
+_httpiconetsecon_ {_httpimg_/etsecon.gif}
+
+## "HIGH-\nLIGHTING" ## document_button ## ehl ##
+_httpiconehlof_ {_httpimg_/ehlof.gif}
+_httpiconehlon_ {_httpimg_/ehlon.gif}
+
+## "NO HIGH-\nLIGHTING" ## document_button ## enhl ##
+_httpiconenhlof_ {_httpimg_/enhlof.gif}
+_httpiconenhlon_ {_httpimg_/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ {_If_(_thislast_,results _thisfirst_ - _thislast_ for query: _cgiargq_,No matches for query: _cgiargq_)}
+_textnoquerytitle_ {Search page}
+
+_texticonthispage_ {search}
+_textsome_ {some}
+_textall_ {all}
+_textboolean_ {boolean}
+_textranked_ {ranked}
+_textnatural_ {natural}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ {}
+_texticonsearchhistorybar_ {search history}
+
+_textifeellucky_ {I'm feeling lucky!}
+
+#alt text for query buttons
+_textusequery_ {use this query}
+_textfreqmsg1_ {Word count: }
+_textpostprocess_ {_If_(_quotedquery_,<br><i>post-processed to find _quotedquery_</i>
+)}
+_textinvalidquery_ {Invalid query syntax}
+
+_textmorethan_ {More than }
+_textapprox_ {About }
+_textnodocs_ {No documents matched the query.}
+_text1doc_ {1 document matched the query.}
+_textlotsdocs_ {documents matched the query.}
+_textmatches_ {Matches }
+_textbeginsearch_ {Begin Search}
+_textrunquery_ {Run Query}
+_textclearform_ {Clear Form}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ {Word or phrase}
+_textinfield_ {... in field}
+_textfoldstem_ {(fold, stem)}
+
+_textadvquery_ {Or enter a query directly:}
+_textallfields_ {all fields}
+_texttextonly_ {text only}
+_textand_ {and}
+_textor_ {or}
+_textandnot_ {and not}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ {Search for _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_, at _gselection_ level )_If_(_nselection_,in _nselection_ language )that contain _querytypeselection_ of the words}
+
+_textadvancedsearch_ {Search _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_,at _gselection_ level )_If_(_nselection_,in _nselection_ language )using _querytypeselection_ query}
+
+_textformsimplesearch_ {Search _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )for _formquerytypeselection_ of}
+
+_textformadvancedsearch_ {Search _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )and display results in _formquerytypeselection_ order}
+
+
+_textnojsformwarning_ {Warning: Javascript is disabled in your web browser. <br>To use form searching, please enable it.}
+_textdatesearch_ {This collection can be searched for documents within a date range, or documents that contain a particular date. This is an optional feature of the search.}
+_textstartdate_ {Start (or only) date:}
+_textenddate_ {End date:}
+_textbc_ {B.C.E.}
+_textad_ {C.E.}
+_textexplaineras_ {C.E. and B.C.E are alternatives for A.D. and B.C. respectively.  These terms are considered to be culture indiscriminate, and stand for "Common Era" and "Before the Common Era"} 
+
+_textstemon_ { (ignoring word endings)}
+
+_textsearchhistory_ {Search History}
+
+#text macros for search history
+_textnohistory_ {No entries in the search history}
+_texthresult_ {result}
+_texthresults_ {results}
+_texthallwords_ {all words}
+_texthsomewords_ {some words}
+_texthboolean_ {boolean}
+_texthranked_ {ranked}
+_texthcaseon_ {case must match}
+_texthcaseoff_ {casefolded}
+_texthstemon_ {stemmed}
+_texthstemoff_ {unstemmed}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "search" ## green_title ## h_search ##
+_httpiconhsearch_ {_httpimg_/h\_search.gif}
+_widthhsearch_ {200}
+_heighthsearch_ {57}
+
+## "results" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ {_httpimg_/qryresb.gif}
+_widthqryresb_ {_pagewidth_}
+_heightqryresb_ {17}
+
+## "history" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ {_httpimg_/schhistb.gif}
+_widthsrchhistb_ {_pagewidth_}
+_heightsrchhistb_ {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ {
+Preferences have been set as follows. Do not use your browser's
+"back" button - it will unset them! Instead, click one of the
+buttons on the access bar above.
+}
+_textsetprefs_ {set preferences}
+_textsearchprefs_ {Search preferences}
+_textcollectionprefs_ {Collection preferences}
+_textpresentationprefs_ {Presentation preferences}
+_textpreferences_ {Preferences}
+_textcasediffs_ {Case differences:}
+_textignorecase_ { ignore case differences}
+_textmatchcase_ { upper/lower case must match}
+_textwordends_ {Word endings:}
+_textstem_ { ignore word endings}
+_textnostem_ { whole word must match}
+_textprefop_ {Return up to _maxdocoption_ hits with _hitsperpageoption_ hits per page.}
+_textextlink_ {Access to external Web pages:}
+_textintlink_ {Source documents retrieved from:}
+_textlanguage_ {Interface language:}
+_textencoding_ {Encoding:}
+_textformat_ {Interface format:}
+_textall_ {all}
+_textquerymode_ {Query mode:}
+_textsimplemode_ { simple query mode}
+_textadvancedmode_ { advanced query mode (allows boolean searching using !, &, |, and parentheses)}
+_textlinkinterm_ {through intermediate page}
+_textlinkdirect_ {go directly there}
+_textdigitlib_ {the digital library}
+_textweb_ {the web}
+_textgraphical_ {Graphical}
+_texttextual_ {Textual}
+_textcollectionoption_ {<p>
+Subcollections to include:
+<br>}
+
+_textrelateddocdisplay_ {display related documents}
+_textsearchhistory_ {Search history:}
+_textnohistory_ { No search history}
+_texthistorydisplay_ { display _historynumrecords_ search history records}
+_textnohistorydisplay_ { do not display search history}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ {Form search:}
+_textplainsearch_ {Plain search:}
+_textqueryboxsize_ {Query box size:}
+_textregbox_ { regular query box}
+_textbigbox_ { large query box}
+_textformtype_ {Form type:}
+_textsimple_ { simple}
+_textadvanced_ { advanced}
+
+# used in "with 4 fields" in the form search box
+_textwith_ {with}
+_textfields_ {fields}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferences" ## green_title ## h_pref ##
+_httpiconhpref_ {_httpimg_/h\_pref.gif}
+_widthhpref_ {200}
+_heighthpref_ {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ {Sort documents by}
+_textalsoshowing_ {also showing}
+_textwith_ {with at most}
+_textdocsperpage_ {documents per page}
+
+_textfilterby_ {Get documents containing}
+_textall_ {all}
+_textany_ {any}
+_textwords_ {of the words}
+_textleaveblank_ {leave this box blank to get all the documents}	    
+
+_browsebuttontext_ {"Sort Documents"}
+
+_nodata_ {<i>no data</i>}
+_docs_ {documents}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ {Help}
+_textSearchshort_ {search for particular words}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ {access publications by title}
+_textCreatorshort_ {access publications by author}  # Not true DC, kept for legacy reasons
+_textSubjectshort_ {access publications by subject}
+_textDescriptionshort_ {access publications by description}
+_textPublishershort_ {access publications by publisher}
+_textContributorshort_ {access publications by contributor}
+_textDateshort_ {access publications by date}
+_textTypeshort_ {access publications by type}
+_textFormatshort_ {access publications by format}
+_textIdentifiershort_ {access publications by identifier}
+_textSourceshort_ {access publications by filename}  # Not true DC, kept for legacy reasons
+_textLanguageshort_ {access publications by language}
+_textRelationshort_ {access publications by relation}
+_textCoverageshort_ {access publications by coverage}
+_textRightsshort_ {access publications by rights}
+
+_textSeriesshort_ {access publications by series}
+_textToshort_ {access publications by To field}
+_textFromshort_ {access publications by From field}
+_textBrowseshort_ {browse publications}
+_textOrganizationshort_ {access publications by organization}
+_textHowtoshort_ {access publications by "how to" listing}
+_textTopicshort_ {access publications by topic}
+_textPeopleshort_ {access publications by people}
+_textAcronymshort_ {access publications by acronym occurrence}
+_textPhraseshort_ {browse phrases occurring in publications}
+_textArtistshort_ {access publications by artist}
+_textKeywordshort_ {access publications by keyword}
+_textVolumeshort_ {access publications by volume}
+_textCountriesshort_ {access publications by country}
+_textdefaultshorttext_ {undefined classification}
+
+_textSearchlong_ { <p>You can <i>search for particular words</i> that
+appear in the text from the "search" page. This is the first page that
+comes up when you begin, and can be reached from other pages by pressing
+the <i>search</i> button.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ { <p>You can <i>access publications by title</i> by
+pressing the <i>titles a-z</i> button.  This brings up a list of books in
+alphabetic order.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ { <p>You can <i>access publications by author</i> by
+pressing the <i>authors a-z</i> button.  This brings up a list of books,
+sorted by author name.  }
+
+_textSubjectlong_ { <p>You can <i>access publications by subject</i> by
+pressing the <i>subjects</i> button.  This brings up a list of subjects,
+represented by bookshelves.  }
+
+_textDescriptionlong_ { <p>You can <i>access publications by description</i> by
+pressing the <i>descriptions</i> button.  This brings up a list of descriptions to
+browse.  }
+
+_textPublisherlong_ { <p>You can <i>access publications by publisher</i> by
+pressing the <i>publishers</i> button.  This brings up a list of publishers to
+browse.  }
+
+_textContributorlong_ { <p>You can <i>access publications by contributor</i> by
+pressing the <i>contributors</i> button.  This brings up a list of contributors to
+browse.  }
+
+_textDatelong_ { <p>You can <i>access publications by date</i> by pressing
+the <i>dates</i> button.  This brings up a list of all the issues, sorted
+chronologically.  }
+
+_textTypelong_ { <p>You can <i>access publications by type</i> by
+pressing the <i>types</i> button.  This brings up a list of types to
+browse.  }
+
+_textFormatlong_ { <p>You can <i>access publications by format</i> by
+pressing the <i>formats</i> button.  This brings up a list of formats to
+browse.  }
+
+_textIdentifierlong_ { <p>You can <i>access publications by identifier</i> by
+pressing the <i>identifiers</i> button.  This brings up a list of identifiers to
+browse.  }
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ { <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.  }
+
+_textLanguagelong_ { <p>You can <i>access publications by language</i> by
+pressing the <i>languages</i> button.  This brings up a list of entries,
+sorted by language.  }
+
+_textRelationlong_ { <p>You can <i>access publications by relation</i> by
+pressing the <i>relations</i> button.  This brings up a list of relations to
+browse.  }
+
+_textCoveragelong_ { <p>You can <i>access publications by coverage</i> by
+pressing the <i>coverage</i> button.  }
+
+_textRightslong_ { <p>You can <i>access publications by rights</i> by
+pressing the <i>rights</i> button.  }
+
+
+
+_textOrganizationlong_ { <p>You can <i>access publications by
+organisation</i> by pressing the <i>organisations</i> button.  This brings
+up a list of organisations.  }
+
+_textHowtolong_ { <p>You can <i>access publications by "how to" listing</i>
+by pressing the <i>how to</i> button.  This brings up a list of how to
+strings.  }
+
+_textTopiclong_ { <p>You can <i>access publications by topic</i> by
+pressing the <i>topic</i> button.  This brings up a list of topics to
+browse.  }
+
+_textTolong_ { <p>You can <i>access publications by To field</i> by
+pressing the <i>to</i> button.  This brings up a list of addressees.  }
+
+_textFromlong_ { <p>You can <i>access publications by From field</i> by
+pressing the <i>from</i> button.  This brings up a list of senders.  }
+
+_textSerieslong_ { <p>You can <i>access publications by series</i> by
+pressing the <i>series</i> button.  This brings up a list of those series
+which are currently in the collection.  }
+
+_textBrowselong_ { <p>You can <i>browse publications</i> by pressing the
+<i>browse</i> button.  }
+
+_textPeoplelong_ { <p>You can <i>access publications by people</i> by
+pressing the <i>people a-z</i> button.  This brings up a list of entries,
+sorted by surname.  }
+
+_textAcronymlong_ { <p>You can <i>access publications by acronym occurrence</i> by
+pressing the <i>acronyms</i> button.  This brings up a list of the acronyms,
+and the places that they occur.  }
+
+_textPhraselong_ { <p>You can <i>browse phrases occurring in publications</i> by
+pressing the <i>phrases</i> button.  This uses the phind phrase browser.  }
+
+_textArtistlong_ { <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.  }
+
+_textKeywordlong_ { <p>You can <i>access publications by keyword</i> by
+pressing the <i>keywords</i> button.  This brings up a list of keywords. }
+
+_textVolumelong_ { <p>You can <i>access publications by volume</i> by
+pressing the <i>volumes</i> button. This brings up a list of volumes. }
+
+_textCaptionslong_ { <p>You can <i>access publications by caption</i> by
+pressing the <i>captions</i> button. This brings up a list of captions. }
+
+_textCountrieslong_ { <p>You can <i>access publications by country</i> by
+pressing the <i>countries</i> button. This brings up a list of countries. }
+
+
+_textdefaultlongtext_ { <p>Click on the <i>unknown</i> button to browse
+publications (listing is sorted by an unknown field).  }
+
+_texthelptopics_ {
+<h2 align=left>Topics</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">How to search for particular words</a>
+<ul>
+  <li><a href="\#query-terms">Search terms</a>
+  <li><a href="\#query-type">Query type</a>
+  <li><a href="\#scope-of-queries">Scope of queries</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Collection preferences</a>
+  <li><a href="\#lang-prefs">Language preferences</a>
+  <li><a href="\#pres-prefs">Presentation preferences</a>
+  <li><a href="\#search-prefs">Search preferences</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ {How to read the documents}
+
+_texthelpreadingdocs_ {
+<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>You can tell when you have arrived at an individual book or document
+because its title, or a photograph of the front cover, appears at the top
+left of the page. In some collections this is accompanied by a table of
+contents, while others contain just the number of the current page along
+with a box that allows you to select a new page and go forward and
+backward. In the table of contents, the current section heading is in bold
+face, and the table is expandable -- click on the folders to open or close
+them; click on the open book at the top to close it.</p>
+
+<p>Underneath is the text of the current section. When you have read
+through it, there are arrows at the bottom to take you on to the next
+section or back to the previous one.</p>
+
+<p>Below the title or front-cover photograph are some buttons. Click on
+<i>expand text</i> to expand out the whole text of the current section, or
+book. If the document is large, this could take a long time and use a lot
+of memory! Click on <i>expand contents</i> to expand out the whole table of
+contents so that you can see the titles of all chapters and
+subsections. Click on <i>detach</i> to make a new browser window for this
+document. (This is useful if you want to compare documents, or read two at
+once.) Finally, when you do a search the words you search for are
+highlighted. Click on <i>no highlighting</i> to remove highlighting.</p>
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Open this bookshelf</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Open/close this book</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>View this section of the text</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Display all text, or not</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Expand table of contents, or not</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Click the arrow to go to the next section ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... or back to the previous section</td></tr>
+</table>
+}
+
+_texthelpsearching_ {
+<h2>How to search for particular words</h2>
+<p>
+  From the search page, you make a query in these simple steps:<p>
+  
+  <ol><li>Specify what items you want to search
+      <li>Say whether you want to search for all or just some of the words
+      <li>Type in the words you want to search for
+      <li>Click the <i>Begin Search</i> button
+  </ol>
+
+<p>When you make a query, the titles of twenty matching documents will be shown.
+There is a button at the end to take you on to the next twenty documents.  From
+there you will find buttons to take you on to the third twenty or back to the
+first twenty, and so on.  Click the title of any document, or the little button
+beside it, to see it.
+
+<p>A maximum of 100 is imposed on the number of
+  documents returned.  You can change this number by clicking the
+  <i>preferences</i> button at the top of the page.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Search terms</h3>
+
+<p>Whatever you type into the query box is interpreted as a list of words
+called "search terms."  Each term contains nothing but alphabetic characters
+and digits.  Terms are separated by white space.  If any other characters such
+as punctuation appear, they serve to separate terms just as though they were
+spaces.  And then they are ignored.  You can't search for words that include
+punctuation.
+
+<p>For example, the query<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>will be treated the same as<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Query type</h3>
+
+<p>There are two different kinds of query.
+
+<ul>
+  <li>Queries for <b>all</b> of the words.  These look for documents (or
+      chapters, or titles) that contain all the words you have specified.
+      Documents that satisfy the query are displayed, in alphabetical
+      order.<p>
+
+  <li>Queries for <b>some</b> of the words.  Just list some terms that are
+      likely to appear in the documents you are looking for.  Documents are
+      displayed in order of how closely they match the query.  When determining
+
+      the degree of match,
+
+      <p><ul>
+        <li> the more search terms a document contains, the closer it matches;
+        <li> rare terms are more important than common ones;
+        <li> short documents match better than long ones.
+      </ul>
+</ul>
+
+<p>Use as many search terms as you like--a whole sentence, or even a
+whole paragraph.  If you specify only
+one term, documents will be ordered by its frequency of occurrence.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ {Searching with Dates}
+
+_texthelpdatesearch_ {<h2>_textdatesearch_</h2>
+Date search lets you find documents that, as well as matching your search 
+terms, are about events within a certain timeframe.  You can search for 
+documents from a certain year or from a range of years.  Note that you do not 
+have to have any search terms -- you can search by date alone; and also that 
+you do not have to use dates in your search, if you do not type any dates in it
+ is just the same as if the date search didn't exist.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>How to use this feature:</h3>
+<ul>
+   <li>To search for documents about a single year:<p>
+   <ul>
+       <li>Type in any ordinary search terms as you normally would.
+       <li>Type the year you want into the "Start (or only) date" box.
+       <li>If your date is from before the common era (also known as before 
+           Christ), choose the "B.C.E" option from the pulldown menu next to that
+           box.
+       <li>Begin your search as you ordinarily would.
+   </ul>
+<p><li>To search for documents about a time period or range of years:<p>
+   <ul>
+       <li>Type in any ordinary search terms as you normally would.
+       <li>Type the earlier date into the "Start (or only) date" box.
+       <li>Type the later date into the "End date" box.
+       <li>Select "B.C.E" option from the pulldown menu next to any date from before 
+           the common era (also known as before Christ).
+       <li>Begin your search as you ordinarily would.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>The way results of your search work</h3>
+
+Generally speaking a search for documents about the year 1903 will not return documents that, say, reference books written in 1903, just documents about 1903.  However, the way that the documents' dates are found, it will return documents that have a date range (for example 1899-1911) that includes 1903, and also those documents which, as part of their text name the century that 1903 is a part of (for example 20th century or twentieth century).  This means that for some documents, the dates in your search will not actually appear in the document text.  For a range search, all of this applies to every date in the range.<p>
+}
+
+_textchangeprefs_ {Changing your preferences}
+
+_texthelppreferences_ {<h2>_textchangeprefs_</h2>
+
+<p>When you click the <i>preferences</i> button at the top of the page you will
+be able to change some features of the interface to suit your own requirements.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Collection preferences</h3>
+
+Some collections comprise several subcollections, which can be searched
+independently or together, as one unit.  If so, you can select which
+subcollections to include in your searches on the Preferences page.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Language preferences</h3>
+
+Each collection has a default presentation language, but you can switch to
+a different language if you like.  You can also alter the encoding scheme
+used by Greenstone for output to the browser -- the software chooses
+sensible defaults, but with some browsers better visual results can be used
+by switching to a different encoding scheme. All collections allow you to
+switch from the standard graphical interface format to a textual one. This
+is particularly useful for visually impaired users who use large screen
+fonts or speech synthesizers for output.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Presentation preferences</h3>
+
+Depending on the particular collection, there may be several options you can
+set that control the presentation.
+
+<p>Collections of Web pages allow you to suppress the Greenstone navigation bar at
+the top of each document page, so that once you have done a search you land at
+the exact Web page that matches without any Greenstone header.  To do another
+search you will have to use your browser's "back" button.  These collections
+also allow you to suppress Greenstone's warning message when you click a link
+that takes you out of the digital library collection and on to the Web itself.
+And in some Web collections you can control whether the links on the "Search
+Results" page take you straight to the actual URL in question, rather than to
+the digital library's copy of the page.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Search preferences</h3>
+<p>Two pairs of buttons control the kind of text matching in the searches that
+you make. The first set (labeled "case differences") controls whether upper and
+lower case must match.  The second ("word endings") controls whether to ignore
+word endings or not.  It is possible to get a large query box, so that you can
+easily do paragraph-sized searching. It is surprisingly quick to search for
+large amounts of text.
+
+<p>For example, if the buttons <i>ignore case differences</i> and
+<i>ignore word endings</i> are selected, the query<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>will be treated the same as<p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      because the uppercase letter in "African" will be transformed to
+      lowercase, and  the suffixes "n" and "ing" will be removed from
+      "African" and "building" respectively (also, "s" would be removed from
+      "builds").
+
+<p>You can switch to an "advanced" query mode which allows you to combine terms
+using AND (&), OR (|), and NOT (!). This allows you to specify more precise
+queries. You can turn the search history feature, which shows you your last few
+queries.  This makes it easy to repeat slightly modified versions of previous
+queries. Finally, you can control the number of hits returned, and the
+number presented on each screenful.
+}
+
+_texttanumbrowseoptions_ {There are _numbrowseoptions_ ways to find information in this collection:}
+
+_textsimplehelpheading_ {How to find information in the _collectionname_ collection}
+
+_texthelpscope_ {
+<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Scope of queries</h3>
+
+<p>
+In most collections you can choose different indexes to search. For example, there might
+be author or title indexes. Or there might be chapter or paragraph indexes. Generally,
+the full matching document is returned regardless of which index you search.
+<p>If documents are books, they will be opened at the appropriate place.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/english2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/english2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/english2.dm	(revision 10506)
@@ -0,0 +1,1242 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# English Language text and icon macros 
+# -- this file contains text that is of less importance
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ { documents. }
+_lastupdate_ {Last updated}
+_ago_ {days ago.}
+_colnotbuilt_ {Collection not built.}
+
+_textpagetitle_ {Greenstone Digital Library}
+_textadmin_ {Administration Page}
+_textabgs_ {About Greenstone}
+_textgsdocs_ {Greenstone Documentation}
+
+_textimagegli_ {
+Helps you create new collections, modify or add to existing ones, or delete
+collections
+}
+
+_textimagecollector_ {
+This predates the librarian interface, and for most practical purposes the librarian interface should be used instead
+}
+
+_textimagetranslator_ {
+Helps you keep the multilingual versions of the Greenstone interface
+up to date
+}
+
+_textimageadmin_ {
+Allows you to add new users, summarizes the collections in the system,
+gives technical information on the Greenstone installation
+}
+
+_textimagegogreenstone_ {
+Tells you about the Greenstone software and the New Zealand Digital Library
+Project where it originated
+}
+
+_textimagegodocs_ {Greenstone manuals}
+
+_textpoem_ {
+<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+
+<p>may peace and calmness surround you,
+<br>may you reside in the warmth of a summer's haze,
+<br>may the ocean of your travels be as smooth as the polished greenstone.
+}
+
+_textgreenstone_ { 
+<p>Greenstone is a semi-precious stone that (like this software) is sourced
+in New Zealand.  In traditional Maori society it was the most highly prized
+and sought after of all substances.  It can absorb and hold <i>wairua</i>,
+which is a spirit or life force, and is endowed with traditional virtues
+that make it an appropriate emblem for a public-domain digital library
+project.  Its lustre shows charity; its translucence, honesty; its
+toughness, courage; and the sharp edge it can take, justice.  The carved
+piece used in the Greenstone Digital Library Software logo is a <i>patu</i>
+or fighting club, and is a family heirloom of one of our project members.
+In hand-to-hand combat its delivery is very quick, very accurate, and very
+complete.  We like to think these qualities also apply to our software, the
+razor sharp edge of the <i>patu</i> symbolizing the leading edge of
+technology.
+}
+
+_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="_httpimg_/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="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "select a collection" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ {_httpimg_/selcolgr.gif}
+_widthselcolgr_ {537}
+_heightselcolgr_ {17}
+_altselcolgr_ {"Select a collection"}
+
+
+## "The Librarian\nInterface" ## home_page_button ## cgli ##
+_httpiconcgliof_ {_httpimg_/cgliof.gif}
+_httpiconcglion_ {_httpimg_/cglion.gif}
+_widthcgli_ {100}
+
+## "The Collector" ## home_page_button ## ccol ##
+_httpiconccolof_ {_httpimg_/ccolof.gif}
+_httpiconccolon_ {_httpimg_/ccolon.gif}
+_widthccol_ {100}
+
+## "The Translator" ## home_page_button ## ctrans ##
+_httpiconctransof_ {_httpimg_/ctransof.gif}
+_httpiconctranson_ {_httpimg_/ctranson.gif}
+_widthctrans_ {100}
+
+## "Administration\nPage" ## home_page_button ## cadmin ##
+_httpiconcadminof_ {_httpimg_/cadminof.gif}
+_httpiconcadminon_ {_httpimg_/cadminon.gif}
+_widthcadmin_ {100}
+
+## "About\nGreenstone" ## home_page_button ## cabgs ##
+_httpiconcabgsof_ {_httpimg_/cabgsof.gif}
+_httpiconcabgson_ {_httpimg_/cabgson.gif}
+_widthcabgs_ {100}
+
+## "Greenstone\nDocumentation" ## home_page_button ## cgsdoc ##
+_httpiconcgsdocof_ {_httpimg_/cgsdocof.gif}
+_httpiconcgsdocon_ {_httpimg_/cgsdocon.gif}
+_widthcgsdoc_ {100}
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ {There are four further buttons on the home page}
+
+_textnocollections_ {
+<p>There are currently no collections available to this Greenstone installation. 
+To add some collections you may either
+<ul><li>Use <a href="_httppagecollector_">The Collector</a> to build new collections
+    <li>If you have a Greenstone cd-rom you may install collections from cd-rom
+</ul>
+}
+
+_text1coll_ {This Greenstone installation contains 1 collection}
+
+_textmorecolls_ {This Greenstone installation contains _1_ collections}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ {External Link}
+_textlinknotfound_ {Internal Link not Found}
+
+_textextlinkcontent_ {The link you have selected is external to any of your currently selected collections.
+    If you still wish to view this link and your browser has access to 
+    the Web, you can <a href="_nexturl_">go forward</a> to this page; otherwise 
+    use your browsers "back" button to return to the previous document.}
+
+_textlinknotfoundcontent_ {For reasons beyond our control, the internal link you have selected 
+    does not exist.  This is probably due to an error in the source collection.
+    Use your browsers "back" button to return to the previous document.}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ {
+
+<h3>Link to "_2_" collection</h3>
+
+<p> The link you have selected is external to the "_collectionname_"
+    collection (it links to the "_2_" collection).
+    If you wish to view this link in the "_2_" collection you can 
+    <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">go forward</a> to this page; 
+    otherwise use your browsers "back" button to return to the previous document.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ {Greenstone Digital Library}
+
+_textusername_ {username}
+_textpassword_ {password}
+
+_textmustbelongtogroup_ {Note that you must belong to the "_cgiargug_" group to access this page}
+
+_textmessageinvalid_ {The page you have requested requires you to sign in.<br>
+_If_(_cgiargug_,[_textmustbelongtogroup_]<br>)
+Please enter your Greenstone username and password.}
+
+_textmessagefailed_ {Either your username or password was incorrect.}
+
+_textmessagedisabled_ {Sorry, your account has been disabled. Please contact
+the webmaster for this site.}
+
+_textmessagepermissiondenied_ {Sorry, you do not have permission to access this page.}
+
+_textmessagestalekey_ {The link you have followed is now stale. 
+Please enter your password to access this page.}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ {
+<p>This Greenstone installation does not include any documentation. This
+may be because:
+<ol>
+ <li>Greenstone was installed from CD-ROM using a compact installation.
+ <li>Greenstone was installed from a distribution downloaded from the
+ internet.
+</ol>
+In either case you may obtain the documentation either from the <i>docs</i>
+directory of a Greenstone CD-ROM or by visiting <a
+href="http://www.greenstone.org">http://www.greenstone.org</a>.
+}
+
+_textuserguide_ {User's Guide}
+_textinstallerguide_ {Installer's Guide}
+_textdeveloperguide_ {Developer's Guide}
+_textpaperguide_ {From Paper to Collection}
+_textorganizerguide_ {Using the Organizer}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "greenstone documentation" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ {_httpimg_/gsdocsgr.gif}
+_widthgsdocsgr_ {_pagewidth_}
+_heightgsdocsgr_ {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ {default structure}
+_textmore_ {more}
+_textcollector_ {The Collector}
+_textinfo_ {Collection information}
+_textsrce_ {Source data}
+_textconf_ {Configure collection}
+_textbild_ {Build}
+_textview_ {view}
+_textdel_ {delete collection}
+_textexpt_ {export collection}
+
+_textdownloadingfiles_ {Downloading files ...}
+_textimportingcollection_ {Importing collection ...}
+_textbuildingcollection_ {Building collection ...}
+_textcreatingcollection_ {creating collection ...}
+
+_textcollectorblurb_ {
+<i>The pen is mightier than the sword!
+<br>Building and distributing information collections carries responsibilities
+that you may want to reflect on before you begin.
+There are legal issues of copyright: being able to access documents doesn't
+mean you can necessarily give them to others.
+There are social issues:  collections should respect the customs of the
+community out of which the documents arise.
+And there are ethical issues: some things simply should not be made 
+available to others.
+<br>Be sensitive to the power of information and use it wisely.
+</i>
+}
+
+_textcb1_ {
+The Collector helps you to create new collections, modify or add to
+existing ones, or delete collections.  To do this you will be guided through a
+sequence of Web pages which request the information that is needed.
+}
+
+_textcb2_ {First, you must decide whether to}
+_textcnc_ {create a new collection}
+_textwec_ {work with an existing one, adding data to it or deleting it.}
+
+_textcb3_ {
+In order to build or modify digital library collections you must sign in.
+This is to protect you from others logging in to your computer and altering
+the information on it.  Note: for security reasons you will be
+automatically logged out once a 30 minute period has elapsed since you
+logged in.  If this happens, don't worry! -- you will be invited to log in
+again and can continue from where you left off.
+}
+
+_textcb4_ {
+Please enter your Greenstone username and password, and click the button to
+sign in.
+}
+
+_textfsc_ {
+First select the collection that you want to work with (write protected
+collections won't appear in this list).
+}
+
+_textwtc_ {With the collection you have selected, you can}
+_textamd_ {Add more data and rebuild the collection}
+_textetc_ {Edit the collection configuration file and rebuild the collection}
+_textdtc_ {Delete the collection entirely}
+_textetcfcd_ {Export the collection for writing to a self-installing Windows CD-ROM}
+_textcaec_ {Changing an existing collection}
+_textnwec_ {No write-enabled collections are available for modifying}
+_textcianc_ {Creating a new collection}
+_texttsosn_ {The sequence of steps needed to create a new digital library collection is:}
+_textsin_ {Specify its name (and associated information)}
+_textswts_ {Specify where the source data comes from}
+_textatco_ {Adjust the configuration options (advanced users only)}
+_textbtc_ {"Build" the collection (see below)}
+_textpvyh_ {Proudly view your handiwork.}
+
+_texttfsiw_ {
+The fourth step is where the computer does all the work.  In the "building"
+process the computer makes all the indexes and gathers together any other
+information that is required to make things work.  But first you have to
+specify the information.
+}
+
+_textadab_ {
+A diagram appears below that will help you keep track of where you are.
+The green button is the one that you click to carry on in the sequence.  As
+you go through the sequence, the buttons will change to yellow.  You can
+return to a previous page by clicking on the corresponding yellow button in
+the diagram.
+}
+
+_textwyar_ {
+When you are ready, click the green "collection information" button to
+begin creating your new digital library collection!
+}
+
+_textcnmbs_ {Collection name must be specified}
+_texteambs_ {Email address must be specified}
+_textpsea_ {Please specify email address in the form: username@domain}
+_textdocmbs_ {Description of collection must be specified}
+
+_textwcanc_ {
+When creating a new collection you need to enter some preliminary
+information about the source data.  This process is structured as a series
+of Web pages, overseen by The Collector.  The bar at the bottom of the page
+shows you the sequence of pages to be completed.
+}
+
+_texttfc_ {Title for collection:}
+
+_texttctiasp_ {
+The collection title is a short phrase used throughout the digital library
+to identify the content of the collection.  Example titles include
+"Computer Science Technical Reports" and "Humanity Development Library."
+}
+
+_textcea_ {Contact email address:}
+
+_textteas_ {
+This email address specifies the first point of contact for the collection.
+If the Greenstone software detects a problem, a diagnostic report is sent
+to this address.  Enter an email address in its full form:
+<tt>name@domain</tt>.
+}
+
+_textatc_ {About this collection:}
+
+_texttiasd_ {
+This is a statement describing the principles governing what is included in
+the collection.  It appears on the first page when the collection is
+presented.
+}
+
+_textypits_ {
+Your position in the sequence is indicated by an arrow underneath--in this
+case, the "collection information" stage.  To proceed, click the green
+"source data" button.
+}
+
+_srcebadsources_ {
+<p>One or more of the input sources you specified is unavailable (marked
+_iconcross_ below).
+
+<p>This might be because
+<ul>
+<li>The file, FTP site or URL does not exist.
+<li>You need to dial up your ISP first.
+<li>You are trying to access a URL from behind a firewall (this is the case
+if you normally have to present a username and password to access the
+internet).
+</ul>
+
+<p>If this is a URL that you can see in your browser, it may be coming from
+a locally cached copy. Unfortunately, locally cached copies are invisible
+to our mirroring process. In this case we recommend that you download the
+pages using your browser first.
+}
+
+_textymbyco_ {
+<p>You may base your collection on either
+<ul>
+<li>The default structure
+<dl><dd>The new collection may contain html documents (.htm, .html), plain text
+documents (.txt, .text), MS Word documents (.doc), PDF documents (.pdf) or
+"m-box" format email documents (.mbx).</dd></dl>
+<li>An existing collection
+<dl><dd>The files in your new collection must be exactly the same type as those
+used to build the existing one.</dd></dl>
+</ul>
+}
+
+_textbtco_ {Base the collection on}
+_textand_ {Add new data}
+_textad_ {Adding data:}
+
+_texttftysb_ {
+The files that you specify below will be added to the collection. Make sure
+that you do not re-specify files that are already in the collection:
+otherwise two copies will be included. Files are identified by their full
+pathname, Web pages by their absolute Web address.
+}
+
+_textis_ {Input sources:}
+
+_textddd1_ {
+<p>If you use file:// or ftp:// to specify a file, that file will be
+downloaded.
+
+<p>If you use http:// it depends on whether the URL gives you a normal web
+page in your browser, or a list of files.  If a page, that page will be
+downloaded -- and so will all pages it links to, and all pages they link
+to, etc. -- provided they reside on the same site, below the URL.
+
+<p>If you use file:// or ftp:// to specify a folder or directory, or give a
+http:// URL that leads to a list of files, everything in the folder and all
+its sub-folders will be included in the collection.
+
+<p>Click the "more sources" button to get more input boxes.
+}
+
+_textddd2_ {
+<p>Click one of the green buttons. If you are an advanced user you may want
+to adjust the collection configuration. Alternatively, go straight to the
+building stage. Remember, you can always revisit an earlier stage by
+clicking its yellow button.
+}
+
+_textconf1_ {
+<p>The building and presentation of your collection are controlled by
+specifications in a special "configuration file".  Advanced users may want
+to alter the configuration settings.
+
+<center><p><b>If you are not an advanced user, just go to the bottom of the
+page.</b></center> 
+
+<p>To alter the configuration settings, edit the data that appears below.
+If you make a mistake, click on "Reset" to reinstate the original
+configuration settings.
+}
+
+_textreset_ {Reset}
+
+_textbild1_ {
+The collection is now being built: this might take some time. The building
+status line below gives feedback on how the operation is progressing.
+}
+
+_textbild2_ {
+To stop the building process at any time, click here.
+<br>The collection you are working on will remain intact.
+}
+
+_textstopbuild_ {stop building}
+
+_textbild3_ {
+If you leave this page (and have not cancelled the building process with
+the "stop building" button) the collection will continue to build and will
+be installed upon successful completion.
+}
+
+_textbuildcancelled_ {Build cancelled}
+
+_textbildcancel1_ {
+The collection building process was cancelled. Use the yellow buttons below
+to make changes to your collection or restart the building process.
+}
+
+_textbsupdate1_ {Building status update in 1 second}
+_textbsupdate2_ {Building status update in}
+_textseconds_ {seconds}
+_textbildsuc_ {Collection built successfully.}
+
+_textviewbildsummary_ {
+You may <a href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>view the build
+summary</a> of this collection for further details.
+}
+
+_textfailmsg11_ {
+The collection could not be built as it contains no data. Make sure that at
+least one of the directories or files you specified on the <i>source
+data</i> page exists and is of a type or (in the case of a directory)
+contains files of a type, that Greenstone can process.
+}
+
+_textfailmsg21_ {The collection could not be built (import.pl failed).}
+_textblcont_ {The build log contains the following information:}
+
+_texttryagain_ {
+Please <a href="_httppagecollector_" target=_top>restart the collector</a>
+and try again.
+}
+
+_textfailmsg31_ {The collection could not be built (buildcol.pl failed).}
+_textfailmsg41_ {The collection was built successfully but could not be installed.}
+_textfailmsg71_ {An unexpected error occurred while attempting to build your collection}
+_textretcoll_ {Return to the collector}
+
+_textdelperm_ {
+Some or all of the _cgiargbc1dirname_ collection could not be
+deleted. Possible causes are:
+<ul>
+<li> Greenstone does not have permission to delete the _gsdlhome_/collect/_cgiargbc1dirname_
+directory.<br>
+You may need to remove this directory manually to complete the removal of the _cgiargbc1dirname_
+collection from this computer.</li>
+<li>Greenstone can not run the program _gsdlhome_/bin/script/delcol.pl. Make sure that this file is readable and executable.</li>
+</ul>
+}
+
+_textdelinv_ {
+The _cgiargbc1dirname_ collection is protected or invalid. Deletion was cancelled.
+}
+
+_textdelsuc_ {The _cgiargbc1dirname_ collection was successfully deleted.}
+
+_textclonefail_ {
+The _cgiargclonecol_ collection cound not be cloned. Possible causes are:
+<ul>
+<li> The _cgiargclonecol_ collection doesn't exist
+<li> The _cgiargclonecol_ collection has no collect.cfg configuration file
+<li> Greenstone does not have permission to read the collect.cfg configuration file
+</ul>
+}
+
+_textcolerr_ {Collector error.}
+
+_texttmpfail_ {
+The collector failed to read from or write to a temporary file or
+directory. Possible causes are:
+<ul>
+<li> Greenstone does not have read/write access to the _gsdlhome_/tmp
+     directory.
+</ul>
+}
+
+_textmkcolfail_ {
+The collector failed to create the directory structure required by the new
+collection (mkcol.pl failed). Possible causes are:
+<ul>
+<li> Greenstone does not have permission to write to the _gsdlhome_/tmp
+     directory.
+<li> mkcol.pl perl script errors.
+</ul>
+}
+
+_textnocontent_ {
+Collector error: no collection name was provided for the new collection. Try 
+restarting the Collector from the beginning.
+}
+
+_textrestart_ {Restart the Collector}
+
+_textreloaderror_ {
+An error occurred while creating the new collection. This may have been due
+to Greenstone getting confused by the use of your browser's "reload" or
+"back" buttons (please try to avoid using these buttons while creating a
+collection with the Collector).  It is recommended that you restart the
+Collector from the beginning.
+}
+
+_textexptsuc_ {
+The _cgiargbc1dirname_ collection was successfully exported to the
+_gsdlhome_/tmp/exported\__cgiargbc1dirname_ directory.
+}
+
+_textexptfail_ {
+<p>Failed to export the _cgiargbc1dirname_ collection.
+
+<p>This is likely to be because Greenstone was installed without the
+necessary components to support the "Export Collection" function.
+<ul>
+
+ <li>If you installed Greenstone from a CD-ROM these components won't have
+ been installed unless you selected them during a "Custom" install.
+ You may add them to your installation by re-running the installation 
+ procedure.
+
+ <li>If you installed Greenstone from a web distribution you will need to
+ download and install an additional package to enable this function. Please
+ visit <a href="http://www.greenstone.org">http://www.greenstone.org</a> or
+ email <a
+ href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+ for further details.
+
+</ul>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "The collector" ## green_title ## h_colect ##
+_httpiconhcolect_ {_httpimg_/h\_colect.gif}
+
+## "collection\ninformation" ## collector_bar_button ## info ##
+_httpicongcinfoof_ {_httpimg_/gcinfoof.gif}
+_httpicongcinfoon_ {_httpimg_/gcinfoon.gif}
+_httpiconycinfoof_ {_httpimg_/ycinfoof.gif}
+_httpiconycinfoon_ {_httpimg_/ycinfoon.gif}
+_httpiconncinfoof_ {_httpimg_/ncinfoof.gif}
+
+## "source\ndata" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ {_httpimg_/gcsrceof.gif}
+_httpicongcsrceon_ {_httpimg_/gcsrceon.gif}
+_httpiconycsrceof_ {_httpimg_/ycsrceof.gif}
+_httpiconycsrceon_ {_httpimg_/ycsrceon.gif}
+_httpiconncsrceof_ {_httpimg_/ncsrceof.gif}
+
+## "configure\ncollection" ## collector_bar_button ## conf ##
+_httpicongcconfof_ {_httpimg_/gcconfof.gif}
+_httpicongcconfon_ {_httpimg_/gcconfon.gif}
+_httpiconycconfof_ {_httpimg_/ycconfof.gif}
+_httpiconycconfon_ {_httpimg_/ycconfon.gif}
+_httpiconncconfof_ {_httpimg_/ncconfof.gif}
+
+## "build\ncollection" ## collector_bar_button ## bild ##
+_httpicongcbildof_ {_httpimg_/gcbildof.gif}
+_httpicongcbildon_ {_httpimg_/gcbildon.gif}
+_httpiconycbildof_ {_httpimg_/ycbildof.gif}
+_httpiconycbildon_ {_httpimg_/ycbildon.gif}
+_httpiconncbildof_ {_httpimg_/ncbildof.gif}
+
+## "view\ncollection" ## collector_bar_button ## view ##
+_httpicongcviewof_ {_httpimg_/gcviewof.gif}
+_httpicongcviewon_ {_httpimg_/gcviewon.gif}
+_httpiconycviewof_ {_httpimg_/ycviewof.gif}
+_httpiconycviewon_ {_httpimg_/ycviewon.gif}
+_httpiconncviewof_ {_httpimg_/ncviewof.gif}
+
+## "delete\ncollection" ## collector_bar_button ## del ##
+_httpicongcdelof_ {_httpimg_/gcdelof.gif}
+_httpicongcdelon_ {_httpimg_/gcdelon.gif}
+
+## "export\ncollection" ## collector_bar_button ## expt ##
+_httpicongcexptof_ {_httpimg_/gcexptof.gif}
+_httpicongcexpton_ {_httpimg_/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_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.
+}
+
+_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.
+}
+
+_textplatformtitle_ {platform}
+_textgreenstone3_ {
+Greenstone runs on Windows, Unix and Mac OS X. The distribution includes ready-to-use
+binaries for all versions of Windows, and for Linux and Mac OS X. 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.
+}
+
+_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.
+}
+
+_textcustomisationtitle_ {customisation}
+_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.
+}
+
+_textdocumentationtitle_ {documentation}
+_textdocuments_ {Extensive documentation for the Greenstone software is available.}
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+_textmailinglisttitle_ {mailing list}
+_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>.
+}
+
+_textbugstitle_ {bugs}
+_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>
+}
+
+_textgs3title_ {in the works}
+_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. Documentation and experimental releases of Greenstone 3 can be downloaded from the <a href="http://www.greenstone.org/greenstone3.html">Greenstone 3 home page</a>.}
+
+_textcreditstitle_ {credits}
+
+_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, Hong Chen, Michael Dewsnip, Katherine Don, Elke Duncker, Carl Gutwin, Geoff Holmes, Dana McKay, 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, PERL, WGET, WVWARE and XLHTML.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "about the greenstone software" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ {_httpimg_/abgsgr.gif}
+_widthabgsgr_ {_pagewidth_}
+_heightabgsgr_ {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ {List of current users}
+_textuser_ {user}
+_textas_ {account status}
+_textgroups_ {groups}
+_textcomment_ {comment}
+_textadduser_ {add a new user}
+_textedituser_ {edit}
+_textdeleteuser_ {delete}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ {Edit user information}
+_textadduser_ {Add a new user}
+
+_textaboutusername_ {
+Usernames must be between 2 and 30 characters long. They can contain
+alphanumeric characters, '.', and '_'.
+}
+
+_textaboutpassword_ {
+Passwords must be between 3 and 8 characters long. They can contain any
+normal printable ASCII characters.
+}
+
+_textoldpass_ {If this field is blank the old password will be kept.}
+_textenabled_ {enabled}
+_textdisabled_ {disabled}
+
+_textaboutgroups_ {
+Groups is a comma separated list, do not put spaces after the commas.
+}
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ {Delete a user}
+_textremwarn_ {Do you really want to permanently remove user <b>_cgiargumun_</b>?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ {Change password}
+_textoldpw_ {old password}
+_textnewpw_ {new password}
+_textretype_ {retype new password}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ {Your password was successfully changed.}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ {The username is invalid.}
+_textinvalidpassword_ {The password is invalid.}
+_textemptypassword_ {Please enter an initial password for this user.}
+_textuserexists_ {This user already exists, please enter another username.}
+
+_textusernameempty_ {Please enter your username.}
+_textpasswordempty_ {You must enter your old password.}
+_textnewpass1empty_ {Enter your new password and then retype it.}
+_textnewpassmismatch_ {The two versions of your new password did not match.}
+_textnewinvalidpassword_ {You entered an invalid password.}
+_textfailed_ {Either your username or password was incorrect.}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ {Greenstone version number}
+_textframebrowser_ {You must have a frame enabled browser to view this.}
+_textusermanage_ {User management}
+_textlistusers_ {list users}
+_textaddusers_ {add a new user}
+_textchangepasswd_ {change password}
+_textinfo_ {Technical information}
+_textgeneral_ {general}
+_textarguments_ {arguments}
+_textactions_ {actions}
+_textbrowsers_ {browsers}
+_textprotocols_ {protocols}
+_textconfigfiles_ {Configuration files}
+_textlogs_ {Logs}
+_textusagelog_ {usage log}
+_textinitlog_ {init log}
+_texterrorlog_ {error log}
+_textadminhome_ {admin home}
+_textreturnhome_ {Greenstone home}
+_titlewelcome_ { Administration }
+_textmaas_ {Maintenance and administration services available include:}
+_textvol_ {view on-line logs}
+_textcmuc_ {create, maintain and update collections}
+_textati_ {access technical information such as CGI arguments}
+
+_texttsaa_ {
+These services are accessed using the side navigation bar on the lefthand
+side of the page.
+}
+
+_textcolstat_ {Collection Status}
+
+_textcwoa_ {
+Collections will only appear as "running" if their build.cfg
+files exist, are readable, contain a valid builddate field (i.e. > 0),
+and are in the collection's index directory (i.e. NOT the building
+directory).
+}
+
+_textcafi_ {click <i>abbrev.</i> for information on a collection}
+_textcctv_ {click <i>collection</i> to view a collection}
+_textsubc_ {Submit Changes}
+_texteom_ {Error opening main.cfg}
+_textftum_ {Failed to update main.cfg}
+_textmus_ {main.cfg updated successfully}
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ {Build summary for _collectionname_ collection}
+_textflog_ {Fail log for _collectionname_ collection}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ {Greenstone Usability}
+
+_textwhy_ {<p>Sending this report is a way of indicating you have found the web page you were viewing difficult or frustrating.}
+_textextraforform_ {You do not have to fill out the form -- any information will help.}
+_textprivacybasic_ {<p>The report will contain only information about the Greenstone web page you were viewing, and the technology you were using to view it (plus any optional information you provide).}
+_textstillsend_ {Would you still like to send this report?}
+
+_texterror_ {error}
+_textyes_ {Yes}
+_textno_ {No}
+_textclosewindow_ {Close Window}
+_textabout_ {About}
+_textprivacy_ {Privacy}
+_textsend_ {Send}
+_textdontsend_ {Don\\'t Send}
+_textoptionally_ {Optionally}
+
+_textunderdev_ {Details preview will be available in the final version.}
+
+_textviewdetails_ {View report details}
+_textmoredetails_ {More details}
+_texttrackreport_ {Track this report}
+_textcharacterise_ {What kind of problem is it}
+_textseverity_ {How bad is the problem}
+ 
+_textbadrender_ {Page looks strange}
+_textcontenterror_ {Content error}
+_textstrangebehaviour_ {Strange behaviour}
+_textunexpected_ {Something unexpected happened}
+_textfunctionality_ {Hard to use}
+_textother_ {Other}
+
+_textcritical_ {Critical}
+_textmajor_ {Serious}
+_textmedium_ {Medium}
+_textminor_ {Minor}
+_texttrivial_ {Trivial}
+
+_textwhatdoing_ {What were you trying to do?}
+_textwhatexpected_ {What did you expect to happen?}
+_textwhathappened_ {What actually happened?}
+
+_cannotfindcgierror_ {<h2>Sorry!</h2>Can\\'t find the server programs for the "I\\'d Like to Complain" button.}
+
+_textusabbanner_ {the Greenstone koru-style banner}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+_textgti_ {The Greenstone Translator Interface}
+
+_textgtierror_ {An error has occurred}
+
+_textgtihome_ {
+These pages help you improve Greenstone's foreign language support. Using them, you can
+<ul>
+  <li>translate parts of Greenstone into a new language
+  <li>update an existing language interface to reflect new Greenstone facilities
+  <li>correct errors in existing translations
+</ul>
+
+You will be presented with a series of web pages, each containing
+several phrases to translate.
+You proceed by translating the language interface phrase by phrase.
+Many phrases contain HTML formatting commands: you should not
+attempt to translate these but preserve them intact in the translated
+version. Words flanked by underscores (like _this_) should not be
+translated either (they're Greenstone "macro" names).
+<p>
+If you are updating an existing translation, you will not be presented
+with phrases for which a translation already exists. Sometimes a translation
+exists but the English text has since been changed. In this case the current
+translation will be provided and you should check and update this if necessary.
+<p>
+Each page ends with a "_textgtisubmit_" button. When you press it, changes are
+made immediately to a separate Greenstone installation at nzdl.org. A button
+is provided on each page to access this site.
+}
+
+_textgtiselecttlc_ {Please select your language}
+
+_textgtiselecttfk_ {Please select a file to work on}
+
+_textgticoredm_ {Core Macrofile}
+_textgtiauxdm_ {Auxiliary Macrofile}
+_textgtiglidict_ {GLI Dictionary}
+_textgtiperlmodules_ {Perl Modules}
+_textgtigreenorg_ {Greenstone.org}
+
+_textgtienter_ {ENTER}
+
+_textgticorrectexistingtranslations_ {Correct existing translations}
+_textgtidownloadtargetfile_ {Download file}
+_textgtiviewtargetfileinaction_ {View this file in action}
+
+_textgtinumchunksmatchingquery_ {Number of text fragments matching the query}
+
+_textgtinumchunkstranslated_ {translations done}
+_textgtinumchunksrequiringupdating_ {Of these, _1_ require updating}
+_textgtinumchunksrequiringtranslation_ {translations remaining}
+
+_textgtienterquery_ {Enter a word or phrase from the text fragment you want to correct}
+_textgtifind_ {FIND}
+
+_textgtitranslatingchunk_ {Translating text fragment <i>_1_</i>}
+_textgtiupdatingchunk_ {Updating text fragment <i>_1_</i>}
+_textgtisubmit_ {SUBMIT}
+
+_textgtilastupdated_ {Last updated}
+
+_textgtitranslationfilecomplete_ {Thank you for updating this file -- it is now complete!<p>You can download a copy of this file using the link above, and it will also be included in future releases of Greenstone.}
+
+
+############
+# gli page
+############
+package gli
+
+_textgli_ {The Librarian Interface}
+_textglihelp_ {
+
+The Greenstone Librarian Interface (GLI) gives you access to Greenstone's 
+functionality from an easy-to-use, 'point and click' interface. This allows you to collect sets of documents, import or assign metadata, and build them into a Greenstone collection.
+ <p>
+Note that the GLI is run in conjunction with Greenstone, and assumes that
+it is installed in a subdirectory of your Greenstone installation. If you
+have downloaded one of the Greenstone distributions, or installed from a
+Greenstone CD-ROM, this will be the case.
+ 
+ 
+<h4>Running the GLI under Windows</h4>
+ 
+Launch the librarian interface under Windows by selecting <i>Greenstone Digital Library</i> from the <i>Programs</i> section of the <i>Start</i> menu and choosing <i>Librarian Interface</i>. 
+
+ 
+<h4>Running the GLI under Unix</h4>
+ 
+To run the GLI under Unix, change to the <i>gli</i> directory in your Greenstone
+installation, then run the <i>gli.sh</i> script. 
+ 
+<h4>Running the GLI under Mac OS X</h4>
+
+In the finder, browse to <i>Applications</i> then <i>Greenstone</i>
+(if you installed Greenstone into the default location), and then
+launch the <i>GLI</i> application.
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "the greenstone librarian interface" ## green_bar_left_aligned ## gligr ##
+_httpicongligr_ {_httpimg_/gligr.gif}
+_widthgligr_ {_pagewidth_}
+_heightgligr_ {17}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/exported_home.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/exported_home.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/exported_home.dm	(revision 10506)
@@ -0,0 +1,137 @@
+# this file must be UTF-8 encoded
+
+package home
+
+# This file is used as the homepage for collections exported to CD-ROM - the CDs dont contain the functionality to run the collector etc, so we remove that stuff from the home page.
+
+# set the title of the home page to be "greenstone digital library"
+# in the currently chosen language
+
+_pagetitle_ {_textimagegreenstone_}
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. this is overridden here as we don't want 'home' 
+# links on this page
+
+_javalinks_ {_imagehelp_ _imagepref_}
+_javalinks_ [v=1] {_imagehelp_<br>_imagepref_}
+
+#######################################################################
+# icons
+#######################################################################
+
+_iconselectcollection_ {<img align=texttop src="_httpiconselcolgr_" width=_widthselcolgr_ height=_heightselcolgr_ alt="_altselcolgr_" title="_altselcolgr_">}
+_iconmusiclibrary_ {<img align=texttop src="_httpicontmusic_" border=1 alt="meldex music library" title="meldex music library">}
+
+_imagecollection_ {<img src="_httpimg_/gsdlhead.gif">}
+
+#######################################################################
+# http macros 
+#
+# These contain the url without any quotes
+#######################################################################
+
+_httppagegsdl_ {_httppagex_(gsdl)}
+_httppagehomehelp_ {_httppagex_(homehelp)}
+_httppagehomepref_ {_httppagex_(homepref)}
+
+#######################################################################
+# images
+#######################################################################
+
+_imagehelp_ {_gsimage_(_home:httppagehomehelp_,_httpiconchelpof_,_httpiconchelpon_,help,_textimagehelp_)}
+_imagepref_ {_gsimage_(_home:httppagehomepref_,_httpiconcprefof_,_httpiconcprefon_,pref,_textimagepref_)}
+
+#######################################################################
+# page content                     
+#######################################################################
+
+_content_ {
+<center>
+<p>_iconselectcollection_
+</center>
+<p>_homeextra_
+
+<center>
+<p>_iconblankbar_
+</center>
+}
+
+package homehelp
+
+_imagecollection_ {<a href="_httppagehome_"><img src="_httpimg_/gsdlhead.gif" border="0"></a>}
+
+_collectionlist_ {}
+
+_javalinks_ {_imagehome_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+}
+
+_content_ {
+<center>
+<p>_iconblankbar_
+</center>
+<p>
+<table border=0 cellspacing=0 cellpadding=0>
+ <tr>
+  <td valign=top align=center>_imagegreenstone_</td>
+  <td valign=top>_gsdl:textgreenstone1_
+  <br><br>
+  </td>
+ </tr>
+</table>
+
+<center>
+<p>_iconblankbar_
+</center>
+_If_(_collectionlist_,_collectionlist_,_textnocollections_)
+
+<center>
+<p>_iconblankbar_
+</center>
+}
+
+
+package homepref
+
+_imagecollection_ {<a href="_httppagehome_"><img src="_httpimg_/gsdlhead.gif" border="0"></a>}
+
+_javalinks_ {_homepref:imagehome_}
+_javalinks_ [v=1] {
+_homepref:imagehome_<br>
+}
+
+_pagescriptextra_ {_preferences:pagescriptextra_}
+
+
+_imagehome_ {_gsimage_(_homepref:httppagehome_,_httpiconchomeof_,_httpiconchomeon_,homer,_textimagehome_)}
+_httppagehome_ {_httppagex_(home)}
+
+_content_ {
+<center>
+<p>_iconblankbar_
+</center>
+
+<form name=PrefForm method=get action="_gwcgi_">
+<h3>_preferences:textpresentationprefs_</h3>
+
+<table border="0">
+<tr valign="top">
+<td>_preferences:textlanguage_</td>
+<td>_languageoption_</td>
+</tr>
+<tr valign="top">
+<td>_preferences:textencoding_</td>
+<td>_encodingoption_</td>
+</tr>
+<tr valign="top">
+_preferences:formatoption_
+</tr>
+</table>
+<p>_iconblankbar_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/extlink.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/extlink.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/extlink.dm	(revision 10506)
@@ -0,0 +1,19 @@
+# this file must be UTF-8 encoded
+
+package extlink
+
+_header_ {_htmlhead_}
+
+_foundcontent_ {
+
+<h3>_textextlink_</h3>
+
+<p> _textextlinkcontent_
+}
+
+_notfoundcontent_ {
+
+<h3>_textlinknotfound_</h3>
+
+<p> _textlinknotfoundcontent_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/extra.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/extra.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/extra.dm	(revision 10506)
@@ -0,0 +1,7 @@
+
+
+# The intention of this file is to provide a placeholder for collection
+# specific new macros (it is therefore intentionally empty).  For a given
+# collection, is the collection designer setups up an 'extra.dm' file in
+# the collection's macro directory then any macros defined within it will
+# be available for that collection.
Index: /tags/gsdl-2_61-distribution/gsdl/macros/farsi.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/farsi.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/farsi.dm	(revision 10506)
@@ -0,0 +1,1994 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Farsi Language text and icon macros 
+# Many thanks to Mohammed Karimi Yazdi (translated February 2004)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=fa] {Ú¯Ø§ÙÙØ§Ù
+Ù ÙØ§}
+_textsource_ [l=fa] {Ù
+ÙØšØ¹ :}
+_textdate_ [l=fa] {ØªØ§Ø±ÙØ® ÙØŽØ± :}
+_textnumpages_ [l=fa] {ØªØ¹Ø¯Ø§Ø¯ ØµÙØ­Ø§Øª :}
+
+_textsignin_ [l=fa] {ÙØ±ÙØ¯ }
+
+_textdefaultcontent_ [l=fa] {ØµÙØ­Ù Ù
+ÙØ±Ø¯ Ø¯Ø±Ø®ÙØ§Ø³Øª ØŽÙ
+Ø§ ÙØ§ÙØª ÙØŽØ¯. ÙØ·ÙØ§ Ø§Ø² Ø¯ÙÙ
+Ù ØšØ§Ø²Ú¯ØŽØª ÙØ§ÙØŽÚ¯Ø± Ø®ÙØ¯ Ø§Ø³ØªÙØ§Ø¯Ù ÙÙ
+Ø§ÙÙØ¯ ÙØ§ ØšØ± Ø±ÙÙ Ø¯ÙÙ
+Ù Ø®Ø§ÙÙ ØšØ±Ø§Ù ØšØ§Ø²Ú¯ØŽØª ØšÙ ÙØªØ§ØšØ®Ø§ÙÙ Ø¯ÙØ¬ÙØªØ§Ù Ú¯Ø±ÙÙ Ø§Ø³ØªÙÙ ÙÙÙÙ ÙÙÙØ¯ .}
+
+_textdefaulttitle_ [l=fa] {Ø®Ø·Ø§Ù GSDL}
+
+_textbadcollection_ [l=fa] {Ø§ÙÙ Ù
+Ø¬Ù
+ÙØ¹Ù (ØšÙØ§Ù
+ "_cvariable_") Ø¯Ø± Ø³ÙØ³ØªÙ
+ ÙØªØ§ØšØ®Ø§ÙÙ Ø¯ÙØ¬ÙØªØ§Ù Ú¯Ø±ÙÙ Ø§Ø³ØªÙÙ ÙØµØš ÙØŽØ¯Ù Ø§Ø³Øª.}
+
+_textselectpage_ [l=fa] {ØµÙØ¬Ù Ø§ÙØªØ®Ø§Øš}
+
+_collectionextra_ [l=fa] {Ø¯Ø± Ø§ÙÙ Ù
+Ø¬Ù
+ÙØ¹Ù ØªØ¹Ø¯Ø§Ø¯ _about:numdocs_  Ø³ÙØ¯ ÙØ¬ÙØ¯ Ø¯Ø§Ø±Ø¯ .
+Ø§ÙÙ Ù
+Ø¬Ù
+ÙØ¹Ù _about:builddate_ Ø±ÙØ² ÙØšÙ Ø³Ø§Ø®ØªÙ ØŽØ¯Ù Ø§Ø³Øª .}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=fa] {<p>Ø¯Ø± Ø§ÙÙ Ù
+Ø¬Ù
+ÙØ¹Ù  _numdocs_ _If_("_numdocs_" eq "1",Ø³ÙØ¯,Ø³ÙØ¯), ØšÙ ØžØ±ÙÙØª  _numbytes_.
+<p><a href="_httppagex_(bsummary)">Ø§ÙÙØ¬Ø§ ÙÙÙÙ ÙÙÙØ¯</a>ØšØ±Ø§Ù Ø§ÙØ¬Ø§Ø¯ Ú¯Ø²Ø§Ø±ØŽ Ø®ÙØ§ØµÙ Ø§Ø·ÙØ§Ø¹Ø§Øª Ù
+Ø¬Ù
+ÙØ¹Ù.
+}
+
+_textimagecollection_ [l=fa] {}
+_textimageabout_ [l=fa] {Ø¯Ø±ØšØ§Ø±Ù}
+_textimagehome_ [l=fa] {Ø®Ø§ÙÙ}
+_textimagehelp_ [l=fa] {Ø±Ø§ÙÙÙ
+Ø§ÙÙ}
+_textimagepref_ [l=fa] {ØªÙØžÙÙ
+Ø§Øª}
+_textimagegreenstone_ [l=fa] {ÙØ±Ù
+ Ø§ÙØ²Ø§Ø± ÙØªØ§ØšØ®Ø§ÙÙ Ø¯ÙØ¬ÙØªØ§Ù Ú¯Ø±ÙÙ Ø§Ø³ØªÙÙ}
+_textimageusab_ [l=fa] {Ø§Ø³ØªÙØ§Ø¯Ù Ø§Ø² ÙØ¯Ø§Ù
+ Ù
+ÙØ±Ø¯ Ø±Ø§ Ø¯ØŽÙØ§Ø± ÙØ§ÙØªÙØ¯ Ø}
+
+_textimagesearch_ [l=fa] {Ø¬Ø³ØªØ¬Ù ØšØ±Ø§Ù Ø¹ØšØ§Ø±Ø§Øª Ø®Ø§Øµ}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=fa] {ÙÙØ±Ø³Øª Ø§ÙÙØšØ§ÙÙ Ø¹ÙØ§ÙÙÙ}
+_textimageCreator_ [l=fa] {Ù
+Ø±ÙØ± ÙÙØ±Ø³Øª Ø§ÙÙØšØ§ÙÙ ÙÙÙØ³ÙØ¯Ú¯Ø§Ù}
+_textimageSubject_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø­Ø³Øš Ø¯Ø³ØªÙ ØšÙØ¯Ù Ù
+ÙØ¶ÙØ¹Ù}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø­Ø³Øš ØªØ§Ø±ÙØ®}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø§Ø³Ø§Ø³ ÙØ§Ù
+ Ø§ØµÙÙ ÙŸØ±ÙÙØ¯Ù}
+_textimageLanguage_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø­Ø³Øš Ø²ØšØ§Ù}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø­Ø³Øš Ø³Ø§Ø²Ù
+Ø§Ù}
+_textimageKeyword_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø­Ø³Øš ÙÙÙ
+Ù ÙÙÙØ¯Ù}
+_textimageHowto_ [l=fa] {Ù
+Ø±ÙØ± Ø¯Ø³ØªÙ ÙØ§Ù ÚÚ¯ÙÙÚ¯Ù Ø§ÙØ¬Ø§Ù
+ ÙØ§Ø±ÙØ§}
+_textimageList_ [l=fa] {Ù
+Ø±ÙØ± ÙÙØ±Ø³Øª Ø§Ø³ÙØ§Ø¯}
+_textimageSeries_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø­Ø³Øš ØŽÙ
+Ø§Ø±Ù ÙØŽØ±}
+_textimageTo_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø­Ø³Øš ÙØšÙØ¯ ØªØ§}
+_textimageFrom_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø­Ø³Øš ÙÙÙØ¯ Ø§Ø²}
+_textimageTopic_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø­Ø³Øš Ù
+ÙØ¶ÙØ¹Ø§Øª Ø®Ø§Øµ}
+_textimageBrowse_ [l=fa] {Ù
+Ø±ÙØ±}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=fa] {Ù
+Ø±ÙØ± ÙÙØ±Ø³Øª Ø§ÙÙØšØ§ÙÙ Ø§ÙØ±Ø§Ø¯}
+_textimageAcronym_ [l=fa] {Ù
+Ø±ÙØ± Ù
+ØªØ¶Ø§Ø¯ÙØ§}
+_textimagePhrase_ [l=fa] {Ù
+Ø±ÙØ± Ø¹ØšØ§Ø±Ø§Øª}
+_textimageArtist_ [l=fa] {Ù
+Ø±ÙØ± ÙÙØ²Ù
+ÙØ¯Ø§Ù}
+_textimageVolume_ [l=fa] {Ù
+Ø±ÙØ± ØšØ± Ø­Ø³Øš Ø¬ÙØ¯}
+_textimageCountries_ [l=fa] {Ù
+Ø±ÙØ± ÙÙ ØªÙÙÙÙ ÙØ§Ù
+ ÙØŽÙØ±ÙØ§}
+_textimageCaptions_ [l=fa] {Ù
+Ø±ÙØ± Ø¹ÙØ§ÙÙÙ Ø¹ÙØ³ ÙØ§}
+
+
+_texticontabsearchgreen_ [l=fa] {Ø¬Ø³ØªØ¬Ù}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=fa] {Ø¹ÙÙØ§Ù Ø§-Ù}
+_texticontabCreatorgreen_ [l=fa] {ÙÙÙØ³ÙØ¯Ú¯Ø§Ù Ø§-Ù}
+_texticontabSubjectgreen_ [l=fa] {Ù
+ÙØ¶ÙØ¹Ø§Øª}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=fa] {ØªØ§Ø±ÙØ® ÙØ§}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=fa] {ÙØ§Ù
+ ÙŸØ±ÙÙØ¯Ù ÙØ§}
+_texticontabLanguagegreen_ [l=fa] {Ø²ØšØ§Ù}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=fa] {Ø³Ø§Ø²Ù
+Ø§Ù}
+_texticontabKeywordgreen_ [l=fa] {ÙÙÙ
+Ø§Øª ÙÙÙØ¯Ù}
+_texticontabhowgreen_ [l=fa] {ÚÚ¯ÙÙÙ }
+_texticontabseriesgreen_ [l=fa] {Ø³Ø±Ù ÙØ§}
+_texticontablistgreen_ [l=fa] {ÙÙØ±Ø³Øª}
+_texticontabtogreen_ [l=fa] {ØªØ§}
+_texticontabfromgreen_ [l=fa] {Ø§Ø²}
+_texticontabtopicgreen_ [l=fa] {Ù
+ÙØ¶ÙØ¹Ø§Øª}
+_texticontabbrwsegreen_ [l=fa] {ÙØ§ÙØŽ}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=fa] {ÙØ§ÙØŽ}
+_texticontabPeoplegreen_ [l=fa] {Ø§ÙØ±Ø§Ø¯ Ø§-Ù}
+_texticontabAcronymgreen_ [l=fa] {Ù
+ØªØ¶Ø§Ø¯ÙØ§}
+_texticontabPhrasegreen_ [l=fa] {Ø¹ØšØ§Ø±Ø§Øª}
+_texticontabArtistgreen_ [l=fa] {ÙÙØ±Ù
+ÙØ¯Ø§Ù}
+_texticontabVolumegreen_ [l=fa] {Ù
+Ø¬ÙØ¯Ø§Øª}
+_texticontabCaptionsgreen_ [l=fa] {Ø¹ÙØ§ÙÙÙ}
+_texticontabCountriesgreen_ [l=fa] {ÙØŽÙØ±ÙØ§}
+
+_texticontext_ [l=fa] {Ø±ÙÙØª Ø³ÙØ¯}
+_texticonclosedbook_ [l=fa] {ØšØ§Ø²ÙØ±Ø¯Ù Ø³ÙØ¯ Ù Ø±ÙÙØª Ù
+Ø­ØªÙÙØ§Øª Ø¢Ù}
+_texticonnext_ [l=fa] {ØšØ®ØŽ ØšØ¹Ø¯Ù}
+_texticonprev_ [l=fa] {ØšØ®ØŽ ÙØšÙÙ}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=fa] {Ø±ÙÙØª Ø³ÙØ¯ MIDI}
+_texticonmsword_ [l=fa] {Ø±ÙÙØª Ø³ÙØ¯ Ù
+Ø§ÙÙØ±ÙØ³Ø§ÙØª ÙØ±Ø¯}
+_texticonmp3_ [l=fa] {Ø±ÙÙØª Ø³ÙØ¯ MP3}
+_texticonpdf_ [l=fa] {Ø±ÙÙØª Ø³ÙØ¯ PDF}
+_texticonps_ [l=fa] {Ø±ÙÙØª Ø³ÙØ¯ ÙŸØ³Øª Ø§Ø³ÙØ±ÙÙŸØª}
+_texticonppt_ [l=fa] {Ø±ÙÙØª Ø³ÙØ¯ PowerPoint}
+_texticonrtf_ [l=fa] {Ø±ÙÙØª Ø³ÙØ¯ RTF}
+_texticonxls_ [l=fa] {Ø±ÙÙØª Ø³ÙØ¯ Ù
+Ø§ÙÙØ±ÙØ³Ø§ÙØª Ø§ÙØ³Ù}
+
+_page_ [l=fa] {ØµÙØ­Ù}
+_pages_ [l=fa] {ØµÙØ­Ø§Øª}
+_of_ [l=fa] {Ø§Ø²}
+_vol_ [l=fa] {Ø¬ÙØ¯ }
+_num_ [l=fa] {ØŽÙ
+Ø§Ø±Ù }
+
+_textmonth00_ [l=fa] {}
+_textmonth01_ [l=fa] {ÚØ§ÙÙÙÙ}
+_textmonth02_ [l=fa] {ÙÙØ±ÙÙ}
+_textmonth03_ [l=fa] {Ù
+Ø§Ø±Ø³}
+_textmonth04_ [l=fa] {Ø¢ÙØ±ÙÙ}
+_textmonth05_ [l=fa] {Ù
+Ù}
+_textmonth06_ [l=fa] {Ø¬ÙØŠÙ}
+_textmonth07_ [l=fa] {Ø¬ÙÙØ§Ù}
+_textmonth08_ [l=fa] {Ø¢Ú¯ÙØ³Øª}
+_textmonth09_ [l=fa] {Ø³ÙŸØªØ§Ù
+ØšØ±}
+_textmonth10_ [l=fa] {Ø§ÙØªØšØ±}
+_textmonth11_ [l=fa] {ÙÙØ§Ù
+ØšØ±}
+_textmonth12_ [l=fa] {Ø¯Ø³Ø§Ù
+ØšØ±}
+
+_textdocument_ [l=fa] {Ø³ÙØ¯}
+_textsection_ [l=fa] {ØšØ®ØŽ}
+_textparagraph_ [l=fa] {ÙŸØ§Ø±Ø§Ú¯Ø±Ø§Ù}
+
+_magazines_ [l=fa] {Ù
+Ø¬ÙØ§Øª}
+
+_nzdlpagefooter_ [l=fa] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">ÙŸØ±ÙÚÙ ÙØªØ§ØšØ®Ø§ÙÙ Ø¯ÙØ¬ÙØªØ§Ù ÙÙÙØ²ÙÙÙØ¯</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Ù
+Ø±ÙØ² Ø¹ÙÙÙ
+ Ø±Ø§ÙØ§ÙÙ </a>, 
+<a href="http://www.waikato.ac.nz">Ø¯Ø§ÙØŽÚ¯Ø§Ù ÙØ§ÙÙØ§ØªÙ</a>, 
+ÙÙÙØ²ÙÙÙØ¯}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Ø®Ø§ÙÙ" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=fa] {_httpimg_/fa/chomeof.gif}
+_httpiconchomeon_ [l=fa] {_httpimg_/fa/chomeon.gif}
+
+## "Ø±Ø§ÙÙÙ
+Ø§ÙÙ" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=fa] {_httpimg_/fa/chelpof.gif}
+_httpiconchelpon_ [l=fa] {_httpimg_/fa/chelpon.gif}
+
+## "ØªÙØžÙÙ
+Ø§Øª" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=fa] {_httpimg_/fa/cprefof.gif}
+_httpiconcprefon_ [l=fa] {_httpimg_/fa/cprefon.gif}
+
+## "Ø§Ø±Ø³Ø§Ù ØšØ§Ø²Ø®ÙØ±Ø¯" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=fa] {_httpimg_/fa/cusabof.gif}
+_httpiconcusabon_ [l=fa] {_httpimg_/fa/cusabon.gif}
+
+
+## "Ø¬Ø³ØªØ¬Ù" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=fa] {_httpimg_/fa/tsrchgr.gif}
+_httpicontsrchof_ [l=fa] {_httpimg_/fa/tsrchof.gif}
+_httpicontsrchon_ [l=fa] {_httpimg_/fa/tsrchon.gif}
+_widthtsrchx_ [l=fa] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "Ø¹ÙØ§ÙÙÙ Ø§-Ù" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=fa] {_httpimg_/fa/ttitlgr.gif}
+_httpiconttitleof_ [l=fa] {_httpimg_/fa/ttitlof.gif}
+_httpiconttitleon_ [l=fa] {_httpimg_/fa/ttitlon.gif}
+_widthttitlex_ [l=fa] {87}
+
+# Not true DC, kept for legacy reasons
+## "ÙÙÙØ³ÙØ¯Ú¯Ø§Ù Ø§-Ù" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=fa] {_httpimg_/fa/tauthgr.gif}
+_httpicontcreatof_ [l=fa] {_httpimg_/fa/tauthof.gif}
+_httpicontcreaton_ [l=fa] {_httpimg_/fa/tauthon.gif}
+_widthtcreatx_ [l=fa] {110}
+
+## "Ù
+ÙØ¶ÙØ¹Ø§Øª" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=fa] {_httpimg_/fa/tsubjgr.gif}
+_httpicontsubjon_ [l=fa] {_httpimg_/fa/tsubjon.gif}
+_httpicontsubjof_ [l=fa] {_httpimg_/fa/tsubjof.gif}
+_widthtsubjx_ [l=fa] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "ØªØ§Ø±ÙØ® ÙØ§" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=fa] {_httpimg_/fa/tdategr.gif}
+_httpicontdateof_ [l=fa] {_httpimg_/fa/tdateof.gif}
+_httpicontdateon_ [l=fa] {_httpimg_/fa/tdateon.gif}
+_widthtdatex_ [l=fa] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "ÙØ§Ù
+ ÙŸØ±ÙÙØ¯Ù ÙØ§" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=fa] {_httpimg_/fa/tsrcgr.gif}
+_httpicontsrcof_ [l=fa] {_httpimg_/fa/tsrcof.gif}
+_httpicontsrcon_ [l=fa] {_httpimg_/fa/tsrcon.gif}
+_widthtsrcx_ [l=fa] {87}
+
+## "Ø²ØšØ§Ù" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=fa] {_httpimg_/fa/tlanggr.gif}
+_httpicontlangon_ [l=fa] {_httpimg_/fa/tlangon.gif}
+_httpicontlangof_ [l=fa] {_httpimg_/fa/tlangof.gif}
+_widthtlangx_ [l=fa] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "Ø³Ø±Ù ÙØ§" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=fa] {_httpimg_/fa/tsergr.gif}
+_httpicontserof_ [l=fa] {_httpimg_/fa/tserof.gif}
+_httpicontseron_ [l=fa] {_httpimg_/fa/tseron.gif}
+_widthtserx_ [l=fa] {87}
+
+## "ØªØ§" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=fa] {_httpimg_/fa/ttogr.gif}
+_httpiconttoon_ [l=fa] {_httpimg_/fa/ttoon.gif}
+_httpiconttoof_ [l=fa] {_httpimg_/fa/ttoof.gif}
+_widthttox_ [l=fa] {87}
+
+## "Ø§Ø²" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=fa] {_httpimg_/fa/tfromgr.gif}
+_httpicontfromon_ [l=fa] {_httpimg_/fa/tfromon.gif}
+_httpicontfromof_ [l=fa] {_httpimg_/fa/tfromof.gif}
+_widthtfromx_ [l=fa] {87}
+
+## "Ø³Ø§Ø²Ù
+Ø§ÙÙØ§" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=fa] {_httpimg_/fa/torggr.gif}
+_httpicontorgon_ [l=fa] {_httpimg_/fa/torgon.gif}
+_httpicontorgof_ [l=fa] {_httpimg_/fa/torgof.gif}
+_widthtorgx_ [l=fa] {114}
+
+## "ÚÚ¯ÙÙÙ Ø" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=fa] {_httpimg_/fa/thowgr.gif}
+_httpiconthowon_ [l=fa] {_httpimg_/fa/thowon.gif}
+_httpiconthowof_ [l=fa] {_httpimg_/fa/thowof.gif}
+_widththowx_ [l=fa] {87}
+
+## "Ù
+ÙØ¶ÙØ¹" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=fa] {_httpimg_/fa/ttopicgr.gif}
+_httpiconttopicon_ [l=fa] {_httpimg_/fa/ttopicon.gif}
+_httpiconttopicof_ [l=fa] {_httpimg_/fa/ttopicof.gif}
+_widthttopicx_ [l=fa] {87}
+
+## "Ù
+Ø±ÙØ±" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=fa] {_httpimg_/fa/tbrwsegr.gif}
+_httpicontbrwseon_ [l=fa] {_httpimg_/fa/tbrwseon.gif}
+_httpicontbrwseof_ [l=fa] {_httpimg_/fa/tbrwseof.gif}
+_widthtbrwsex_ [l=fa] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "Ø§ÙØ±Ø§Ø¯" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=fa] {_httpimg_/fa/tpeopgr.gif}
+_httpicontpeopof_ [l=fa] {_httpimg_/fa/tpeopof.gif}
+_httpicontpeopon_ [l=fa] {_httpimg_/fa/tpeopon.gif}
+_widthtpeopx_ [l=fa] {97}
+
+## "Ù
+ØªØ¶Ø§Ø¯" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=fa] {_httpimg_/fa/tacrogr.gif}
+_httpicontacroof_ [l=fa] {_httpimg_/fa/tacroof.gif}
+_httpicontacroon_ [l=fa] {_httpimg_/fa/tacroon.gif}
+_widthtacrox_ [l=fa] {87}
+
+## "Ø¹ØšØ§Ø±Ø§Øª" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=fa] {_httpimg_/fa/tphrsegr.gif}
+_httpicontphrseof_ [l=fa] {_httpimg_/fa/tphrseof.gif}
+_httpicontphrseon_ [l=fa] {_httpimg_/fa/tphrseon.gif}
+_widthtphrsex_ [l=fa] {87}
+
+## "ÙÙØ±Ù
+ÙØ¯Ø§Ù" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=fa] {_httpimg_/fa/tartstgr.gif}
+_httpicontartstof_ [l=fa] {_httpimg_/fa/tartstof.gif}
+_httpicontartston_ [l=fa] {_httpimg_/fa/tartston.gif}
+_widthtartstx_ [l=fa] {87}
+
+## "ÙÙÙ
+Ø§Øª ÙÙÙØ¯Ù" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=fa] {_httpimg_/fa/tkwgr.gif}
+_httpicontkwof_ [l=fa] {_httpimg_/fa/tkwof.gif}
+_httpicontkwon_ [l=fa] {_httpimg_/fa/tkwon.gif}
+_widthtkwx_ [l=fa] {87}
+
+## "Ù
+Ø¬ÙØ¯Ø§Øª" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=fa] {_httpimg_/fa/tvolgr.gif}
+_httpicontvolof_ [l=fa] {_httpimg_/fa/tvolof.gif}
+_httpicontvolon_ [l=fa] {_httpimg_/fa/tvolon.gif}
+_widthtvolx_ [l=fa] {87}
+
+## "Ø¹ÙØ§ÙÙÙ" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=fa] {_httpimg_/fa/tcaptgr.gif}
+_httpicontcaptof_ [l=fa] {_httpimg_/fa/tcaptof.gif}
+_httpicontcapton_ [l=fa] {_httpimg_/fa/tcapton.gif}
+_widthtcaptx_ [l=fa] {87}
+
+## "ÙØŽÙØ±ÙØ§" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=fa] {_httpimg_/fa/tcountgr.gif}
+_httpicontcountof_ [l=fa] {_httpimg_/fa/tcountof.gif}
+_httpicontcounton_ [l=fa] {_httpimg_/fa/tcounton.gif}
+_widthtcountx_ [l=fa] {87}
+
+## "ÙÙ
+Ù" ## green_title ## h_help ##
+_httpiconhhelp_ [l=fa] {_httpimg_/fa/h\_help.gif}
+_widthhhelp_ [l=fa] {200}
+_heighthhelp_ [l=fa] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=fa] {Ø¯Ø±ØšØ§Ø±Ù Ø§ÙÙ Ù
+Ø¬Ù
+ÙØ¹Ù}
+
+_textsubcols1_ [l=fa] {<p>ÙÙ Ø§ÙÙ Ù
+Ø¬Ù
+ÙØ¹Ù ØŽØ§Ù
+Ù _1_ Ø²ÙØ±Ù
+Ø¬Ù
+ÙØ¹Ù Ù
+Ù ØšØ§ØŽØ¯. 
+Ø¢ÙÙØ§ÙÙ ÙÙ ÙØ§ØšÙ Ø¯Ø³ØªØ±Ø³Ù ÙØ³ØªÙØ¯ Ø¹ØšØ§Ø±ØªÙØ¯ Ø§Ø²::
+<blockquote>}
+
+_textsubcols2_ [l=fa] {</blockquote>
+ØŽÙ
+Ø§ Ø§Ø² Ø·Ø±ÙÙ ØµÙØ­Ù ØªÙØžÙÙ
+Ø§Øª Ù
+Ù ØªÙØ§ÙÙØ¯ Ø²ÙØ±Ù
+Ø¬Ù
+ÙØ¹Ù ÙØ§Ù Ù
+ÙØ±Ø¯ Ø§Ø³ØªÙØ§Ø¯Ù Ø®ÙØ¯ Ø±Ø§ ØšØšÙÙÙØ¯ ÙØ§ ØªØºÙÙØ± Ø¯ÙÙØ¯.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Ø¯Ø±ØšØ§Ø±Ù" ## green_title ## h_about ##
+_httpiconhabout_ [l=fa] {_httpimg_/fa/h\_about.gif}
+_widthhabout_ [l=fa] {200}
+_heighthabout_ [l=fa] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=fa] {Ø¹ÙØ§ÙÙÙ Ø§-Ù}
+_texticonhcreat_ [l=fa] {ÙÙÙØ³ÙØ¯ÙØ§Ù Ø§-Ù}
+_texticonhsubj_ [l=fa] {Ù
+ÙØ¶ÙØ¹Ø§Øª}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=fa] {ØªØ§Ø±ÙØ® ÙØ§}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=fa] {ÙØ§Ù
+ ÙŸØ±ÙÙØ¯Ù ÙØ§}
+_texticonhlang_ [l=fa] {Ø²ØšØ§ÙÙØ§}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=fa] {ØªØ§}
+_texticonhfrom_ [l=fa] {Ø§Ø²}
+_texticonhser_ [l=fa] {Ø³Ø±Ù ÙØ§}
+_texticonhhow_ [l=fa] {ÚÚ¯ÙÙÙØ}
+_texticonhorg_ [l=fa] {Ø³Ø§Ø²Ù
+Ø§ÙÙØ§}
+_texticonhbrwse_ [l=fa] {Ù
+Ø±ÙØ±}
+_texticonhbrows_ [l=fa] {Ù
+Ø±ÙØ±}
+_texticonhpeople_ [l=fa] {Ø§ÙØ±Ø§Ø¯ Ø§-Ù}
+_texticonhacronym_ [l=fa] {Ù
+ØªØ¶Ø§Ø¯ÙØ§}
+_texticonhphrases_ [l=fa] {Ø¹ØšØ§Ø±Ø§Øª}
+_texticonhartist_ [l=fa] {ÙÙØ±Ù
+ÙØ¯Ø§Ù}
+_texticonhkw_ [l=fa] {ÙÙÙ
+Ø§Øª ÙÙÙØ¯Ù}
+_texticonhvol_ [l=fa] {Ù
+Ø¬ÙØ¯Ø§Øª}
+_texticonhcapt_ [l=fa] {Ø¹ÙØ§ÙÙÙ}
+_texticonhcount_ [l=fa] {ÙØŽÙØ±ÙØ§}
+
+_texticonopenbookshelf_ [l=fa] {ØšØ³ØªÙ Ø§ÙÙ ØšØ®ØŽ ÙØªØ§ØšØ®Ø§ÙÙ}
+_texticonclosedbookshelf_ [l=fa] {ØšØ§Ø²ÙØ±Ø¯Ù Ø§ÙÙ ØšØ®ØŽ Ø§Ø² ÙØªØ§ØšØ®Ø§ÙÙ Ù Ø±ÙÙØª Ù
+Ø­ØªÙÙØ§Øª}
+_texticonopenbook_ [l=fa] {ØšØ³ØªÙ ÙØªØ§Øš}
+_texticonclosedfolder_ [l=fa] {ØšØ§Ø²ÙØ±Ø¯Ù ÙŸÙØŽÙ Ù Ø±ÙÙØª Ù
+Ø­ØªÙÙØ§Øª}
+_texticonclosedfolder2_ [l=fa] {ÙØ§Ø²ÙØ±Ø¯Ù Ø²ÙØ±ØšØ®ØŽ}
+_texticonopenfolder_ [l=fa] {ØšØ³ØªÙ ÙŸÙØŽÙ}
+_texticonopenfolder2_ [l=fa] {ØšØ³ØªÙ Ø²ÙØ± ØšØ®ØŽ }
+_texticonsmalltext_ [l=fa] {Ø±ÙÙØª Ø§ÙÙ ØšØ®ØŽ Ø§Ø² Ù
+ØªÙ }
+_texticonsmalltext2_ [l=fa] {Ø±ÙÙØª Ù
+ØªÙ :}
+_texticonpointer_ [l=fa] {ØšØ®ØŽ ÙØ¹ÙÙ}
+_texticondetach_ [l=fa] {ØšØ§Ø²ÙØ±Ø¯Ù ØµÙØ­Ù Ø¯Ø± ÙŸÙØ¬Ø±Ù Ø¬Ø¯ÙØ¯}
+_texticonhighlight_ [l=fa] {ØšØ±Ø¬Ø³ØªÙ ÙØ±Ø¯Ù Ø¹ØšØ§Ø±Ø§Øª Ø¬Ø³ØªØ¬ÙØŽØ¯Ù}
+_texticonnohighlight_ [l=fa] {Ø¹ØšØ§Ø±Ø§Øª Ø¬Ø³ØªØ¬Ù ØšØ±Ø¬Ø³ØªÙ ÙØŽÙØ¯}
+_texticoncontracttoc_ [l=fa] {Ø¬Ù
+Ø¹ ÙØ±Ø¯Ù ÙÙØ±Ø³Øª Ù
+Ø­ØªÙÙØ§Øª}
+_texticonexpandtoc_ [l=fa] {ØšØ§Ø²ÙØ±Ø¯Ù ÙÙØ±Ø³Øª Ù
+Ø­ØªÙÙØ§Øª}
+_texticonexpandtext_ [l=fa] {ÙÙ
+Ø§ÙØŽ ÙÙ
+Ù Ù
+ØªÙ}
+_texticoncontracttext_ [l=fa] {ØšØ±Ø§Ù ØšØ­ØŽ Ø§ÙØªØ®Ø§Ù ÙÙØ· Ù
+ØªÙ ÙÙ
+Ø§ÙØŽ Ø¯Ø§Ø¯Ù ØŽÙØ¯}
+_texticonwarning_ [l=fa] {<b>Ø§Ø®Ø·Ø§Ø±: </b>}
+_texticoncont_ [l=fa] {Ø§Ø¯Ø§Ù
+Ù Ø}
+
+_textltwarning_ [l=fa] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Ø§ÙÙ Ù
+ØªÙ Ø­Ø§ÙÙ Ø§Ø·ÙØ§Ø¹Ø§Øª ØšØ³ÙØ§Ø±Ù Ø²ÙØ§Ø¯Ù ØšØ±Ø§Ù Ù
+Ø±ÙØ±Ú¯Ø± ØŽÙ
+Ø§ Ø§Ø³Øª _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=fa] {ØšØ±Ù ØšÙ ØµÙØ­Ù}
+_textintro_ [l=fa] {<i>(Ù
+Ø¹Ø±ÙÙ)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "Ø¹ÙØ§ÙÙÙ Ø§-Ù" ## green_title ## h_title ##
+_httpiconhtitle_ [l=fa] {_httpimg_/fa/h\_title.gif}
+_widthhtitle_ [l=fa] {200}
+_heighthtitle_ [l=fa] {57}
+
+# Not true DC, kept for legacy reasons
+## "ÙÙÙØ³ÙÚ¯Ø§Ù Ø§-Ù" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=fa] {_httpimg_/fa/h\_auth.gif}
+_widthhcreat_ [l=fa] {200}
+_heighthcreat_ [l=fa] {57}
+
+## "Ù
+ÙØ¶ÙØ¹Ø§Øª" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=fa] {_httpimg_/fa/h\_subj.gif}
+_widthhsubj_ [l=fa] {200}
+_heighthsubj_ [l=fa] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "ØªØ§Ø±ÙØ® ÙØ§" ## green_title ## h_date ##
+_httpiconhdate_ [l=fa] {_httpimg_/fa/h\_date.gif}
+_widthhdate_ [l=fa] {200}
+_heighthdate_ [l=fa] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "ÙØ§Ù
+ ÙŸØ±ÙÙØ¯Ù ÙØ§" ## green_title ## h_src ##
+_httpiconhsrc_ [l=fa] {_httpimg_/fa/h\_src.gif}
+_widthhsrc_ [l=fa] {200}
+_heighthsrc_ [l=fa] {57}
+
+## "Ø²ØšØ§ÙÙØ§" ## green_title ## h_lang ##
+_httpiconhlang_ [l=fa] {_httpimg_/fa/h\_lang.gif}
+_widthhlang_ [l=fa] {200}
+_heighthlang_ [l=fa] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "ØªØ§" ## green_title ## h_to ##
+_httpiconhto_ [l=fa] {_httpimg_/fa/h\_to.gif}
+_widthhto_ [l=fa] {200}
+_heighthto_ [l=fa] {57}
+
+## "Ø§Ø²" ## green_title ## h_from ##
+_httpiconhfrom_ [l=fa] {_httpimg_/fa/h\_from.gif}
+_widthhfrom_ [l=fa] {200}
+_heighthfrom_ [l=fa] {57}
+
+## "Ø³Ø±Ù ÙØ§" ## green_title ## h_ser ##
+_httpiconhser_ [l=fa] {_httpimg_/fa/h\_ser.gif}
+_widthhser_ [l=fa] {200}
+_heighthser_ [l=fa] {57}
+
+## "ÚÚ¯ÙÙÙ" ## green_title ## h_how ##
+_httpiconhhow_ [l=fa] {_httpimg_/fa/h\_how.gif}
+_widthhhow_ [l=fa] {200}
+_heighthhow_ [l=fa] {57}
+
+## "Ù
+ÙØ¶ÙØ¹Ø§Øª" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=fa] {_httpimg_/fa/h\_topic.gif}
+_widthhtopic_ [l=fa] {200}
+_heighthtopic_ [l=fa] {57}
+
+## "Ø³Ø§Ø²Ù
+Ø§Ù" ## green_title ## h_org ##
+_httpiconhorg_ [l=fa] {_httpimg_/fa/h\_org.gif}
+_widthhorg_ [l=fa] {250}
+_heighthorg_ [l=fa] {57}
+
+## "Ù
+Ø±ÙØ±" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=fa] {_httpimg_/fa/h\_brwse.gif}
+_widthhbrwse_ [l=fa] {200}
+_heighthbrwse_ [l=fa] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "Ø§ÙØ±Ø§Ø¯" ## green_title ## h_people ##
+_httpiconhpeople_ [l=fa] {_httpimg_/fa/h\_people.gif}
+_widthhpeople_ [l=fa] {200}
+_heighthpeople_ [l=fa] {57}
+
+## "Ù
+ØªØ¶Ø§Ø¯ÙØ§" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=fa] {_httpimg_/fa/h\_acro.gif}
+_widthhacronym_ [l=fa] {200}
+_heighthacronym_ [l=fa] {57}
+
+## "Ø¹ØšØ§Ø±Ø§Øª" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=fa] {_httpimg_/fa/h\_phrse.gif}
+_widthhphrse_ [l=fa] {200}
+_heighthphrse_ [l=fa] {57}
+
+## "ÙÙØ±Ù
+ÙØ¯Ø§Ù" ## green_title ## h_artist ##
+_httpiconhartist_ [l=fa] {_httpimg_/fa/h\_artist.gif}
+_widthhartist_ [l=fa] {200}
+_heighthartist_ [l=fa] {57}
+
+## "ÙÙÙ
+Ø§Øª ÙÙÙØ¯Ù" ## green_title ## h_kw ##
+_httpiconhkw_ [l=fa] {_httpimg_/fa/h\_kw.gif}
+_widthhkw_ [l=fa] {200}
+_heighthkw_ [l=fa] {57}
+
+## "Ù
+Ø¬ÙØ¯Ø§Øª" ## green_title ## h_vol ##
+_httpiconhvol_ [l=fa] {_httpimg_/fa/h\_vol.gif}
+_widthhvol_ [l=fa] {200}
+_heighthvol_ [l=fa] {57}
+
+## "ÙØŽÙØ±ÙØ§" ## green_title ## h_count ##
+_httpiconhcount_ [l=fa] {_httpimg_/fa/h\_count.gif}
+_widthhcount_ [l=fa] {200}
+_heighthcount_ [l=fa] {57}
+
+## "Ø¹ÙØ§ÙÙÙ" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=fa] {_httpimg_/fa/h\_capt.gif}
+_widthhcapt_ [l=fa] {200}
+_heighthcapt_ [l=fa] {57}
+
+
+## "Ø§Ø¯Ø§Ù
+Ù" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=fa] {_httpimg_/fa/contof.gif}
+_httpiconconton_ [l=fa] {_httpimg_/fa/conton.gif}
+
+## "ØšØ§Ø²ÙØ±Ø¯Ù Ù
+ØªÙ" ## document_button ## eallt ##
+_httpiconealltof_ [l=fa] {_httpimg_/fa/ealltof.gif}
+_httpiconeallton_ [l=fa] {_httpimg_/fa/eallton.gif}
+
+## "Ø¬Ù
+Ø¹ ÙØ±Ø¯Ù\nÙ
+Ø­ØªÙÙØ§Øª" ## document_button ## econc ##
+_httpiconeconcof_ [l=fa] {_httpimg_/fa/econcof.gif}
+_httpiconeconcon_ [l=fa] {_httpimg_/fa/econcon.gif}
+
+## "Ø¬Ø¯Ø§Ø³Ø§Ø²Ù" ## document_button ## edtch ##
+_httpiconedtchof_ [l=fa] {_httpimg_/fa/edtchof.gif}
+_httpiconedtchon_ [l=fa] {_httpimg_/fa/edtchon.gif}
+
+## "ØšØ§Ø²ÙØ±Ø¯Ù\nÙ
+Ø­ØªÙÙØ§Øª" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=fa] {_httpimg_/fa/eexpcof.gif}
+_httpiconeexpcon_ [l=fa] {_httpimg_/fa/eexpcon.gif}
+
+## "Ø¬Ù
+Ø¹\nÙØ±Ø¯Ù Ù
+ØªÙ" ## document_button ## etsec ##
+_httpiconetsecof_ [l=fa] {_httpimg_/fa/etsecof.gif}
+_httpiconetsecon_ [l=fa] {_httpimg_/fa/etsecon.gif}
+
+## "ØšØ±Ø¬Ø³ØªÙ\nÙÙ
+Ø§ÙÙ" ## document_button ## ehl ##
+_httpiconehlof_ [l=fa] {_httpimg_/fa/ehlof.gif}
+_httpiconehlon_ [l=fa] {_httpimg_/fa/ehlon.gif}
+
+## "ØšØ¯ÙÙ ØšØ±Ø¬Ø³ØªÙ\nÙÙ
+Ø§ÙÙ" ## document_button ## enhl ##
+_httpiconenhlof_ [l=fa] {_httpimg_/fa/enhlof.gif}
+_httpiconenhlon_ [l=fa] {_httpimg_/fa/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=fa] {_If_(_thislast_,results _thisfirst_ - _thislast_ for query: _cgiargq_,ØªØ·Ø§ØšÙÛ ÛØ§ÙØª ÙØŽØ¯: _cgiargq_)}
+_textnoquerytitle_ [l=fa] {ØµÙØ¬Ù Ø¬Ø³ØªØ¬Ù}
+
+_texticonthispage_ [l=fa] {Ø¬Ø³ØªØ¬Ù}
+_textsome_ [l=fa] {ØšØ¹Ø¶Ù}
+_textall_ [l=fa] {ÙÙ
+Ù}
+_textboolean_ [l=fa] {Ù
+ÙØ·ÙÛ}
+_textranked_ [l=fa] {Ø¯Ø±Ø¬Ù ØšÙØ¯Û ØŽØ¯Ù}
+_textnatural_ [l=fa] {Ø·ØšÛØ¹Û}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=fa] {}
+_texticonsearchhistorybar_ [l=fa] {Ø³Ø§ØšÙÙ Ø¬Ø³ØªØ¬Ù}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=fa] {Ø§Ø² Ø§ÙÙ ÙŸØ±Ø³ Ù Ø¬Ù Ø§Ø³ØªÙØ§Ø¯Ù ÙÙÙØ¯}
+_textfreqmsg1_ [l=fa] {ØªØ¹Ø¯Ø§Ø¯ Ú©ÙÙ
+Ù :}
+_textpostprocess_ [l=fa] {_If_(_quotedquery_,<br><i>ÙŸØ±Ø¯Ø§Ø²ØŽ ØŽØ¯Ù ØšØ±Ø§Û ÛØ§ÙØªÙ _quotedquery_</i>
+)}
+_textinvalidquery_ [l=fa] {Ø¯Ø³ØªÙØ± ÙŸØ±Ø³ Ù Ø¬ÙÛ Ø§ØŽØªØšØ§Ù}
+
+_textmorethan_ [l=fa] {ØšÛØŽØªØ± Ø§Ø²}
+_textapprox_ [l=fa] {Ø¯Ø±ØšØ§Ø±Ù }
+_textnodocs_ [l=fa] {Ø³ÙØ¯Û Ù
+Ø·Ø§ØšÙ Ø¬Ø³ØªØ¬Ù ÛØ§ÙØª ÙØŽØ¯ .}
+_text1doc_ [l=fa] {1 Ø³ÙØ¯ ØšØ§ ÙŸØ±Ø³ Ù Ø¬Ù ØªØ·ØšÛÙ Ø¯Ø§Ø±Ø¯ .}
+_textlotsdocs_ [l=fa] {Ø§Ø³ÙØ§Ø¯Û Ú©Ù ØšØ§ ÙŸØ±Ø³ Ù Ø¬Ù ØªØ·ØšÛÙ Ú©Ø±Ø¯Ù Ø§ÙØ¯ .}
+_textmatches_ [l=fa] {ØªØ·ØšÛÙ Ù
+Û Ú©ÙØ¯}
+_textbeginsearch_ [l=fa] {Ø¢ØºØ§Ø² Ø¬Ø³ØªØ¬Ù}
+_textrunquery_ [l=fa] {Ø§Ø¬Ø±Ø§Û ÙŸØ±Ø³ Ù Ø¬Ù}
+_textclearform_ [l=fa] {ÙŸØ§Ú© Ú©Ø±Ø¯Ù ÙØ±Ù
+}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=fa] {ÙÙÙ
+Ù ÙØ§ Ø¹ØšØ§Ø±Øª}
+_textinfield_ [l=fa] {... Ø¯Ø± ÙÛÙØ¯ }
+# -- Missing translation: _textfoldstem_
+
+_textadvquery_ [l=fa] {ÛØ§ Ù
+Ø³ØªÙÛÙ
+Ø§ ÙØ§Ø±Ø¯ Ú©ÙÛØ¯ :}
+_textallfields_ [l=fa] {ÙÙ
+Ù ÙÛÙØ¯ÙØ§}
+_texttextonly_ [l=fa] {ÙÙØ· Ù
+ØªÙÙ}
+_textand_ [l=fa] {Ù}
+_textor_ [l=fa] {ÛØ§}
+_textandnot_ [l=fa] {Ù ÙÙ }
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=fa] {Ø¬Ø³ØªØ¬Ù ØšØ±Ø§Û Ù
+ÙØ§Ø±Ø¯Û _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_, at _gselection_ level )_If_(_nselection_,in _nselection_ language ) Ú©Ù ØŽØ§Ù
+Ù _querytypeselection_ ØšØ§ØŽØ¯}
+
+_textadvancedsearch_ [l=fa] {Ø¬Ø³ØªØ¬Ù _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_,at _gselection_ level )_If_(_nselection_,Ø¯Ø± Ø²ØšØ§Ù _nselection_ )ØšØ§ Ø§Ø³ØªÙØ§Ø¯Ù Ø§Ø² ÙŸØ±Ø³ Ù Ø¬ÙÛ _querytypeselection_ }
+
+_textformsimplesearch_ [l=fa] {Ø¬Ø³ØªØ¬ÙÛ _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,Ø¯Ø± Ø²ØšØ§Ù _nselection_  )ØšØ±Ø§Û _formquerytypeselection_ of}
+
+_textformadvancedsearch_ [l=fa] {Ø¬Ø³ØªØ¬ÙÛ _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,Ø¯Ø± Ø²ØšØ§Ù  _nselection_  )Ù ÙÙ
+Ø§ÛØŽ ÙØªØ§ÛØ¬ ØšÙ ØªØ±ØªÛØš _formquerytypeselection_ }
+
+
+_textnojsformwarning_ [l=fa] {ØªØ°Ú¯Ø± : Ø¬Ø§ÙØ§ Ø§Ø³Ú©Ø±ÛÙŸØª Ø¯Ø± Ù
+Ø±ÙØ±Ú¯Ø± ØŽÙ
+Ø§ ØºÛØ± ÙØ¹Ø§Ù ØŽØ¯Ù Ø§Ø³Øª  <br>ØšØ±Ø§Û Ø§Ø³ØªÙØ§Ø¯Ù Ø§Ø² Ø¬Ø³ØªØ¬Ù Ø¢Ù Ø±Ø§ ÙØ¹Ø§Ù ÙÙ
+Ø§ÛÛØ¯.}
+_textdatesearch_ [l=fa] {Ø¯Ø± Ø§ÛÙ Ù
+Ø¬Ù
+ÙØ¹Ù Ù
+Û ØªÙØ§Ù Ø¯Ø± ØšØ§Ø²Ù Ø²Ù
+Ø§ÙÛ ÛØ§ Ø§Ø³ÙØ§Ø¯Û Ú©Ù ØªØ§Ø±ÛØ® Ø®Ø§ØµÛ Ø¯Ø± Ø¢ÙÙØ§ ÙØ¬ÙØ¯ Ø¯Ø§Ø±Ø¯ Ø¬Ø³ØªØ¬Ù Ú©Ø±Ø¯ . Ø§ÛÙ ÙÛÚÚ¯Û Ø§Ø®ØªÛØ§Ø±Û Ø¬Ø³ØªØ¬Ù Ù
+Û ØšØ§ØŽØ¯ .}
+_textstartdate_ [l=fa] {ØªØ§Ø±ÙØ® ØŽØ±ÙØ¹(ÙØ§ ÙÙØ·)}
+_textenddate_ [l=fa] {ØªØ§Ø±ÛØ® ÙŸØ§ÛØ§Ù :}
+_textbc_ [l=fa] {B.C.E.}
+_textad_ [l=fa] {C.E.}
+# -- Missing translation: _textexplaineras_
+
+_textstemon_ [l=fa] {(ÚØŽÙ
+ ÙŸÙØŽÙ Ø§Ø² Ø§ÙØªÙØ§Ù ÙÙÙ
+Ø§Øª)}
+
+_textsearchhistory_ [l=fa] {Ø³Ø§ØšÙÙ Ø¬Ø³ØªØ¬Ù}
+
+#text macros for search history
+_textnohistory_ [l=fa] {Ø³Ø§ØšÙÙ Ø¬Ø³ØªØ¬Ù Ù
+ÙØ¬ÙØ¯ ÙÛØ³Øª}
+_texthresult_ [l=fa] {ÙØªÛØ¬Ù}
+_texthresults_ [l=fa] {ÙØªØ§ÛØ¬}
+_texthallwords_ [l=fa] {ØªÙ
+Ø§Ù
+ Ú©ÙÙ
+Ø§Øª}
+_texthsomewords_ [l=fa] {ØšØ¹Ø¶Û Ú©ÙÙ
+Ø§Øª}
+_texthboolean_ [l=fa] {Ù
+ÙØ·ÙÛ}
+_texthranked_ [l=fa] {Ø¯Ø±Ø¬Ù ØšÙØ¯Û ØŽØ¯Ù}
+_texthcaseon_ [l=fa] {Ù
+ÙØ±Ø¯ ØšØ§ÛØ¯ ØªØ·ØšÛÙ Ú©ÙØ¯}
+# -- Missing translation: _texthcaseoff_
+_texthstemon_ [l=fa] {Ù
+ØŽØªÙ ØŽØ¯Ù }
+_texthstemoff_ [l=fa] {ØºÛØ± Ù
+ØŽØªÙ}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Ø¬Ø³ØªØ¬Ù" ## green_title ## h_search ##
+_httpiconhsearch_ [l=fa] {_httpimg_/fa/h\_search.gif}
+_widthhsearch_ [l=fa] {200}
+_heighthsearch_ [l=fa] {57}
+
+## "ÙØªØ§ÙØ¬" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=fa] {_httpimg_/fa/qryresb.gif}
+_widthqryresb_ [l=fa] {_pagewidth_}
+_heightqryresb_ [l=fa] {17}
+
+## "Ø³Ø§ØšÙÙ" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=fa] {_httpimg_/fa/schhistb.gif}
+_widthsrchhistb_ [l=fa] {_pagewidth_}
+_heightsrchhistb_ [l=fa] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=fa] {ØªÙØžÛÙ
+Ø§Øª Ø°Ø®ÛØ±Ù ØŽØ¯Ù Ø§ÙØ¯ . Ø§Ø² Ø¯Ú©Ù
+Ù ØšØ§Ø²Ú¯ØŽØª Ù
+Ø±ÙØ±Ú¯Ø± Ø®ÙØ¯ Ø§Ø³ØªÙØ§Ø¯Ù ÙÚ©ÙÛØ¯ Ø²ÛØ±Ø§ ØªÙØžÛÙ
+Ø§Øª Ø±Ø§ ØšØ± Ù
+Û Ú¯Ø±Ø¯Ø§ÙØ¯ Ø¯Ø± Ø¹ÙØ¶ Ø±ÙÛ ÛÚ©Û Ø§Ø² Ø¯Ú©Ù
+Ù ÙØ§Û ÙÙØ§Ø± Ø¯Ø³ØªØ±Ø³Û ØšØ§ÙØ§ Ú©ÙÛÚ© Ú©ÙÛØ¯ .}
+_textsetprefs_ [l=fa] {Ø°Ø®ÛØ±Ù ØªÙØžÛÙ
+Ø§Øª}
+_textsearchprefs_ [l=fa] {ØªÙØžÛÙ
+Ø§Øª Ø¬Ø³ØªØ¬Ù}
+_textcollectionprefs_ [l=fa] {ØªÙØžÛÙ
+Ø§Øª Ù
+Ø¬Ù
+ÙØ¹Ù}
+_textpresentationprefs_ [l=fa] {Ø§Ø±Ø§ØŠÙ ØªÙØžÛÙ
+Ø§Øª}
+_textpreferences_ [l=fa] {ØªÙØžÛÙ
+Ø§Øª}
+_textcasediffs_ [l=fa] {ØšØ²Ø±Ú¯ Ù Ú©ÙÚÚ©Û Ø­Ø±ÙÙ :}
+_textignorecase_ [l=fa] {ÚØŽÙ
+ ÙŸÙØŽÛ Ø§Ø² ØšØ²Ø±Ú¯Û Ù Ú©ÙÚÚ©Û Ø­Ø±ÙÙ}
+_textmatchcase_ [l=fa] {Ú©ÙÚÚ©Û Ù ØšØ²Ø±Ú¯Û Ø­Ø±ÙÙ ØšØ§ÛØ¯ ÙØ­Ø§Øž ØŽÙØ¯}
+_textwordends_ [l=fa] {Ø§ÙØªÙØ§Û Ú©ÙÙ
+Ø§Øª :}
+_textstem_ [l=fa] {ÚØŽÙ
+ ÙŸÙØŽÛ Ø§Ø² Ø§ÙØªÙØ§Û Ú©ÙÙ
+Ø§Øª}
+_textnostem_ [l=fa] {ØªÙ
+Ø§Ù
+ Ú©ÙÙ
+Ù ØšØ§ÛØ¯ ØªØ·ØšÛÙ Ú©ÙØ¯}
+_textprefop_ [l=fa] {Ø­Ø¯Ø§Ú©Ø«Ø± _maxdocoption_ Ù
+ÙØ±Ø¯ ÙØŽØ§Ù Ø¯Ø§Ø¯Ù ØŽÙØ¯ ØšØ§ _hitsperpageoption_ Ù
+ÙØ±Ø¯ Ø¯Ø± ÙØ± ØµÙØ­Ù .}
+_textextlink_ [l=fa] {Ø¯Ø³ØªØ±Ø³Û ØšÙ ØµÙØ­Ø§Øª ÙØš Ø®Ø§Ø±Ø¬Û :}
+_textintlink_ [l=fa] {Ø§Ø³ÙØ§Ø¯ Ø§ØµÙÛ ØšØ§Ø²ÛØ§ØšÛ ØŽØ¯Ù Ø§Ø³Øª Ø§Ø² :}
+_textlanguage_ [l=fa] {Ø²ØšØ§Ù Ø±Ø§ØšØ· :}
+_textencoding_ [l=fa] {Ú©Ø¯ Ø²ØšØ§Ù ØµÙØ­Ù :}
+_textformat_ [l=fa] {ÙØ§ÙØš Ø±Ø§ØšØ·:}
+_textall_ [l=fa] {ÙÙ
+Ù}
+_textquerymode_ [l=fa] {ÙÙØ¹ ÙŸØ±Ø³ ÙØ¬Ù :}
+_textsimplemode_ [l=fa] {Ø­Ø§ÙØª ÙŸØ±Ø³ Ù Ø¬ÙÛ Ø³Ø§Ø¯Ù}
+_textadvancedmode_ [l=fa] {Ø­Ø§ÙØª ÙŸØ±Ø³ Ù Ø¬ÙÛ ÙŸÛØŽØ±ÙØªÙ ( Ù
+Û ØªÙØ§ÙÛØ¯ Ø§Ø² Ø¹Ù
+ÙÚ¯Ø±ÙØ§Û Ù
+ÙØ·ÙÛ ØšØ§ Ø§Ø³ØªÙØ§Ø¯Ù Ø§Ø² ! Ø & Ø | Ù ÙŸØ±Ø§ÙØªØ² Ø§Ø³ØªÙØ§Ø¯Ù ÙÙ
+Ø§ÛÛØ¯ )}
+_textlinkinterm_ [l=fa] {Ø§Ø² Ø·Ø±ÛÙ ØµÙØ­Ù ÙØ§Ø³Ø· }
+_textlinkdirect_ [l=fa] {Ù
+Ø³ØªÙÛÙ
+ ØšØ±Ù ØšÙ :}
+_textdigitlib_ [l=fa] {Ú©ØªØ§ØšØ®Ø§ÙÙ Ø¯ÛØ¬ÛØªØ§Ù}
+_textweb_ [l=fa] {ÙØš}
+_textgraphical_ [l=fa] {Ú¯Ø±Ø§ÙÛÚ©Û}
+_texttextual_ [l=fa] {Ù
+ØªÙÛ}
+_textcollectionoption_ [l=fa] {<p>
+Ø²ÛØ±Ù
+Ø¬Ù
+ÙØ¹Ù ÙØ§ÛÛ Ú©Ù ØŽØ§Ù
+Ù Ù
+Û ØŽÙØ¯ :
+<br>}
+
+_textrelateddocdisplay_ [l=fa] {ÙÙ
+Ø§ÛØŽ Ø§Ø³ÙØ§Ø¯ Ù
+Ø±ØªØšØ·}
+_textsearchhistory_ [l=fa] {Ø³Ø§ØšÙÙ Ø¬Ø³ØªØ¬Ù :}
+_textnohistory_ [l=fa] {Ø³Ø§ØšÙÙ Ø¬Ø³ØªØ¬ÙÛÛ ÙØ¬ÙØ¯ ÙØ¯Ø§Ø±Ø¯}
+_texthistorydisplay_ [l=fa] {ÙÙ
+Ø§ÛØŽ _historynumrecords_ ØªØ¹Ø¯Ø§Ø¯ Ø³Ø§ØšÙÙ Ø¬Ø³ØªØ¬Ù }
+_textnohistorydisplay_ [l=fa] {ÙØŽØ§Ù ÙØ¯Ø§Ø¯Ù Ø³Ø§ØšÙÙ Ø¬Ø³ØªØ¬Ù}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=fa] {ÙØ±Ù
+ Ø¬Ø³ØªØ¬Ù :}
+_textplainsearch_ [l=fa] {Ø¬Ø³ØªØ¬ÙÛ Ø³Ø§Ø¯Ù :}
+_textqueryboxsize_ [l=fa] {Ø§ÙØ¯Ø§Ø²Ù Ø¬Ø¹ØšÙ ÙŸØ±Ø³ ÙØ¬Ù :}
+_textregbox_ [l=fa] {Ø¬Ø¹ØšÙ ÙŸØ±Ø³ Ù Ø¬ÙÛ Ù
+Ø¹Ù
+ÙÙÛ}
+_textbigbox_ [l=fa] {Ø¬Ø¹ØšÙ ÙŸØ±Ø³ Ù Ø¬ÙÛ ØšØ²Ø±Ú¯}
+_textformtype_ [l=fa] {ÙÙØ¹ ÙØ±Ù
+ :}
+_textsimple_ [l=fa] {Ø³Ø§Ø¯Ù}
+_textadvanced_ [l=fa] {ÙŸÛØŽØ±ÙØªÙ}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=fa] {ØšØ§}
+_textfields_ [l=fa] {ÙÛÙØ¯ÙØ§}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ØªÙØžÛÙ
+Ø§Øª" ## green_title ## h_pref ##
+_httpiconhpref_ [l=fa] {_httpimg_/fa/h\_pref.gif}
+_widthhpref_ [l=fa] {200}
+_heighthpref_ [l=fa] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=fa] {Ù
+Ø±ØªØš Ø³Ø§Ø²Ù Ø§Ø³ÙØ§Ø¯ ØšØ± Ø­Ø³Øš }
+_textalsoshowing_ [l=fa] {ØšØ¹ÙØ§ÙÙ ÙÙ
+Ø§ÙØŽ }
+_textwith_ [l=fa] {ØšØ§ ØšÙØŽØªØ±ÙÙ }
+_textdocsperpage_ [l=fa] {Ø³ÙØ¯ Ø¯Ø± ØµÙØ­Ù}
+
+_textfilterby_ [l=fa] {Ø§Ø³ÙØ§Ø¯Ù ÙÙ Ø­Ø§ÙÙ }
+_textall_ [l=fa] {ÙÙ
+Ù}
+_textany_ [l=fa] {ÙØ±}
+_textwords_ [l=fa] {Ø§Ø² ÙÙÙ
+Ù}
+_textleaveblank_ [l=fa] {ØšØ±Ø§Ù ØšÙ Ø¯Ø³Øª Ø¢ÙØ±Ø¯Ù ÙÙ
+Ù Ø§Ø³ÙØ§Ø¯ Ø§ÙÙ ÙØ³Ù
+Øª Ø±Ø§ Ø®Ø§ÙÙ ØšÚ¯Ø°Ø§Ø±ÙØ¯ }
+
+_browsebuttontext_ [l=fa] {"Ù
+Ø±ØªØš Ø³Ø§Ø²Ù Ø§Ø³ÙØ§Ø¯"}
+
+_nodata_ [l=fa] {<i>ØšØ¯ÙÙ Ø§Ø·ÙØ§Ø¹Ø§Øª</i>}
+_docs_ [l=fa] {Ø§Ø³ÙØ§Ø¯}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=fa] {ÙÙ
+Ù}
+_textSearchshort_ [l=fa] {Ø¬Ø³ØªØ¬Ù ØšØ±Ø§Ù ÙÙÙ
+Ø§Øª Ø®Ø§Øµ}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØªÙØ³Ø· Ø¹ÙÙØ§Ù}
+_textCreatorshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ÙÙÙØ³ÙØ¯Ù}
+_textSubjectshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ù
+ÙØ¶ÙØ¹}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ØªØ§Ø±ÙØ® }
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØªÙØ³Ø· ÙØ§Ù
+ ÙŸØ±ÙÙØ¯Ù}
+# -- Missing translation: _textLanguageshort_
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØªÙØ³Ø· Ø³Ø±Ù ÙØ§}
+_textToshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ú¯ÙØ±ÙØ¯Ù}
+_textFromshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ÙØ±Ø³ØªÙØ¯Ù}
+_textBrowseshort_ [l=fa] {Ù
+Ø±ÙØ± ÙØŽØ±ÙØ§Øª}
+_textOrganizationshort_ [l=fa] {ØšØ§Ø²ÙØ§ØšÙ ÙØŽØ±ÙØ§Øª ØšÙØ³ÙÙÙ ÙØ§Ù
+ Ø³Ø§Ø²Ù
+Ø§Ù}
+_textHowtoshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª Ø§Ø² Ø·Ø±ÙÙ ÙÙØ±Ø³Øª Ø±Ø§ÙÙÙ
+Ø§ÙÙ ÙØ§}
+_textTopicshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ù
+ÙØ¶ÙØ¹}
+_textPeopleshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØªÙØ³Ø· ÙØ§Ù
+ Ø§ÙØ±Ø§Ø¯}
+_textAcronymshort_ [l=fa] {Ø¯Ø³ØªÙØ§ØšÙ ØšÙ Ø§ÙØªØŽØ§Ø±Ø§Øª ØšØ± Ø­Ø³Øš Ø¯Ø§ØŽØªÙ Ù
+ØªØ¶Ø§Ø¯ÙØ§}
+_textPhraseshort_ [l=fa] {Ø¯Ø³ØªÙØ§ØšÙ ØšÙ ÙØŽØ±ÙØ§Øª ØšØ§ Ø¹ØšØ§Ø±Ø§Øª}
+_textArtistshort_ [l=fa] {Ø¯Ø±Ø³ØªØ±Ø³Ù ØšÙ Ø§ÙØªØŽØ§Ø±Ø§Øª Ø§Ø² Ø·Ø±ÙÙ ÙØ§Ù
+ ÙÙØ±Ù
+ÙØ¯}
+_textKeywordshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØšÙØ³ÙÙÙ ÙÙÙ
+Ù ÙÙÙØ¯Ù}
+_textVolumeshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ø¬ÙØ¯}
+_textCountriesshort_ [l=fa] {Ø¯Ø³ØªØ±Ø³Ù ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ÙØŽÙØ±}
+_textdefaultshorttext_ [l=fa] {Ø·ØšÙÙ ØšÙØ¯Û ØªØ¹Ø±ÛÙ ÙØŽØ¯Ù}
+
+_textSearchlong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯  <i>ÙÙÙ
+Ø§Øª Ø®Ø§ØµÙ Ø±Ø§ Ø¬Ø³ØªØ¬Ù ÙÙÙØ¯</i> ÙÙ Ø¯Ø± Ù
+ØªÙ ØµÙØ­Ù Ø¬Ø³ØªØ¬Ù Ù
+ØŽØ§ÙØ¯Ù Ù
+Ù ØŽÙØ¯. Ø§ÙÙÙÙ ØµÙØ­Ù Ø§Ù ÙÙ Ø¯Ø± Ø¢ØºØ§Ø² ÙØ§Ø± ÙØ§ ÙŸØ³ Ø§Ø² Ø²Ø¯Ù Ø¯ÙÙ
+Ù <i>Ø¬Ø³ØªØ¬Ù</i> Ù
+Ù ØšÙÙÙØ¯ 
+}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ø¹ÙÙØ§Ù   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø¹ÙØ§ÙÙÙ Ø§-Ù</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ø¹ÙØ§ÙÙÙ Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª Ø§Ø² Ø·Ø±ÙÙ ÙÙÙØ³ÙØ¯Ù  </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø¹ÙØ§ÙÙÙ</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² ÙÙÙØ³ÙØ¯Ú¯Ø§Ù Ø§-Ù Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textSubjectlong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ù
+ÙØ¶ÙØ¹   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ù
+ÙØ¶ÙØ¹Ø§Øª</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ù
+ÙØ¶ÙØ¹Ø§Øª Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ØªØ§Ø±ÙØ®   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø¹ÙØ§ÙÙÙ</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ØªØ§Ø±ÙØ® Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ÙØ§Ù
+ ÙŸØ±ÙÙØ¯Ù   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>ÙØ§Ù
+ ÙŸØ±ÙÙØ¯Ù ÙØ§</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² ÙØ§Ù
+ ÙŸØ±ÙÙØ¯Ù ÙØ§ Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textLanguagelong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ø²ØšØ§Ù   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø²ØšØ§ÙÙØ§</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ø²ØšØ§ÙÙØ§ Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ÙØ§Ù
+ Ø³Ø§Ø²Ù
+Ø§Ù   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø³Ø§Ø²Ù
+Ø§ÙÙØ§</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ø³Ø§Ø²Ù
+Ø§ÙÙØ§ Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textHowtolong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ÙÙØ±Ø³Øª Ø±Ø§ÙÙÙ
+Ø§ÙÙ   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø±Ø§ÙÙÙ
+Ø§ÙÙ</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ø±Ø§ÙÙÙ
+Ø§ÙÙ ÙØ§ Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textTopiclong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ø¹ÙÙØ§Ù Ù
+ÙØ¶ÙØ¹   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ù
+ÙØ¶ÙØ¹</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ù
+ÙØ¶ÙØ¹Ø§Øª Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textTolong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ú¯ÙØ±ÙØ¯Ù   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ú¯ÙØ±ÙØ¯Ù</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ú¯ÙØ±ÙØ¯Ú¯Ø§Ù Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textFromlong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ÙØ±Ø³ØªÙØ¯Ù   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø¹ÙØ§ÙÙÙ</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² ÙØ±Ø³ØªÙØ¯Ú¯Ø§Ù Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textSerieslong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ø³Ø±Ù ÙØ§   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø³Ø±Ù ÙØ§</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ø³Ø±Ù ÙØ§ Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textBrowselong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>Ø§ÙØªØŽØ§Ø±Ø§Øª Ø±Ø§</i> ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù
+<i>Ù
+Ø±ÙØ±</i> Ù
+Ø±ÙØ± ÙÙÙØ¯.  }
+
+_textPeoplelong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ÙØ§Ù
+ Ø§ÙØ±Ø§Ø¯   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø§ÙØ±Ø§Ø¯ Ø§-Ù</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ø§ÙØ±Ø§Ø¯ Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textAcronymlong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ Ø§ÙØªØŽØ§Ø±Ø§Øª ØšØ± Ø­Ø³Øš Ù
+ØªØ¶Ø§Ø¯ ÙØ§ Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯</i>ØšØ§ ÙÙÙÙ ØšØ± Ø±ÙÙ Ø¯ÙÙ
+Ù <i>Ù
+ØªØ¶Ø§Ø¯ÙØ§</i> . ÙÙØ±Ø³ØªÙ Ø§Ø² Ù
+ØªØ¶Ø§Ø¯ÙØ§ Ù Ù
+Ø­Ù Ø¢ÙÙØ§ ÙØŽØ§Ù Ø¯Ø§Ø¯Ù Ù
+Ù ØŽÙØ¯.  }
+
+_textPhraselong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ø¹ØšØ§Ø±Ø§Øª   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø¹ØšØ§Ø±Ø§Øª</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ø¹ØšØ§Ø±Ø§Øª Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textArtistlong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ Ø§ÙØªØŽØ§Ø±Ø§Øª ØšØ± Ø­Ø³Øš ÙØ§Ù
+ ÙÙØ±Ù
+ÙØ¯Ø§Ù</i> by
+ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù <i>ÙÙØ±Ù
+ÙØ¯Ø§Ù</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯.  Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ù
+Ø±ØªØš ØŽØ¯Ù ØšØ± Ø­Ø³Øš ÙØ§Ù
+ ÙÙØ±Ù
+ÙØ¯Ø§Ù Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯ .}
+
+_textKeywordlong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš ÙÙÙ
+Ù ÙÙÙØ¯Ù   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>ÙÙÙ
+Ø§Øª ÙÙÙØ¯Ù</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² ÙÙÙ
+Ø§Øª ÙÙÙØ¯Ù Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textVolumelong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª ØšØ± Ø­Ø³Øš Ø¬ÙØ¯   </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø¬ÙØ¯</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ù
+Ø¬ÙØ¯Ø§Øª Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textCaptionslong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª Ø§Ø² Ø·Ø±ÙÙ Ø¹ÙÙØ§Ù </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø¹ÙØ§ÙÙÙ</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² Ø¹ÙØ§ÙÙÙ Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+_textCountrieslong_ [l=fa] {<p>ØŽÙ
+Ø§ Ù
+Ù ØªÙØ§ÙÙØ¯ <i>ØšÙ ÙØŽØ±ÙØ§Øª Ø§Ø² Ø·Ø±ÙÙ ÙØŽÙØ± </i>ØšØ§ ÙØŽØ§Ø± Ø¯ÙÙ
+Ù  <i>Ø¹ÙØ§ÙÙÙ</i> Ø¯Ø³ØªØ±Ø³Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÙØ¯. Ø§ÙÙ Ø¯ÙÙ
+Ù ÙÙØ±Ø³ØªÙ Ø§Ø² ÙØŽÙØ±ÙØ§ Ø±Ø§ ÙÙ
+Ø§ÙØŽ Ù
+Ù Ø¯ÙØ¯. }
+
+
+_textdefaultlongtext_ [l=fa] {<p>ØšØ± Ø±ÙÛ Ø¯Ú©Ù
+Ù  <i>ÙØ§Ù
+ØŽØ®Øµ</i> ØªØ§ ÙÙØ±Ø³Øª ÙØŽØ±ÛØ§Øª Ø±Ø§ ÙÙ
+Ø§ÛØŽ Ø¯ÙØ¯)Ù
+Ø±ØªØš ØŽØ¯Ù ØšØ± Ø­Ø³Øš ÙÛÙØ¯ ÙØ§Ù
+ØŽØ®Øµ( }
+
+# -- Missing translation: _texthelptopics_
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=fa] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=fa] {ÚÚ¯ÙÙÙ Ø§Ø³ÙØ§Ø¯ Ø±Ø§ ØšØ®ÙØ§ÙÛÙ
+}
+
+_texthelpreadingdocs_ [l=fa] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>
+Ø§Ø² Ø¢ÙØ¬Ø§ÛÛ Ú©Ù Ø¯Ø± ÙØ³Ù
+Øª ØšØ§ÙØ§ Ø³Ù
+Øª ÚÙŸ ÙØ± ØµÙØ­Ù Ø¹ÙÙØ§Ù Ø³ÙØ¯ ÛØ§ Ø¹Ú©Ø³ Ø¬ÙØ¯ Ø¢Ù Ø¯Ø±Ø¬ ØŽØ¯Ù Ø§Ø³Øª
+Ù
+Û ØªÙØ§ÙÛØ¯ ØšØšÛÙÛØ¯ ØšÙ Ú©ØªØ§Øš ÛØ§ Ø³ÙØ¯ Ø®Ø§ØµÛ Ø¯Ø³Øª ÛØ§ÙØªÙ Ø§ÛØ¯ . Ø¯Ø± ØšØ¹Ø¶Û Ø§Ø² Ù
+Ø¬Ù
+ÙØ¹Ù ÙØ§
+ØšÙ ÙÙ
+Ø±Ø§Ù ÙÙØ±Ø³Øª Ù
+Ø­ØªÙÛØ§Øª Ø¯ÛØ¯Ù Ù
+ØŽ ÙØ¯ Ù Ø¯Ø± ØšØ¹Ø¶Û ØŽØ§Ù
+Ù ØŽÙ
+Ø§Ø±Ù ØµÙØ­Ù ÙØ¹ÙÛ Ù ÙØ³Ù
+ØªÛ ØšØ±Ø§Û
+ØªØ¹ÛÛÙ ØµÙØ­Ù Ù Ø±ÙØªÙ ØšÙ ØµÙØ­Ù Ù
+ØŽØ®ØµÛ ÙØ¬ÙØ¯ Ø¯Ø§Ø±Ø¯ . Ø¯Ø± ÙÙØ±Ø³Øª Ù
+Ø­ØªÙÛØ§Øª ØšØ®ØŽ Ø¬Ø§Ø±Û ÙŸØ±Ø±ÙÚ¯ 
+Ù
+Û ØšØ§ØŽØ¯ Ù Ø¬Ø¯ÙÙ ÙÛØ² ÙØ§ØšÙ ØšØ§Ø² ØŽØ¯Ù Ø§Ø³Øª . ØšØ§ Ú©ÙÛÚ© ØšØ± Ø±ÙÛ ÙŸÙØŽÙ ÙØ§ Ù
+Û ØªÙØ§Ù ØšØ§Ø² ÛØ§ ØšØ³ØªÙ ØŽØ§Ù Ú©Ø±Ø¯ .
+</p>
+
+<p>Ø¯Ø± ÙØ³Ù
+Øª ÙŸØ§ÛÛÙ Ù
+ØªÙ ØšØ®ØŽ ÙØ±Ø§Ø± Ø¯Ø§Ø±Ø¯. Ú©Ù ÙÙØªÛ Ø®ÙØ§ÙØ¯Ù ØŽØ¯Ù ÙÙØŽ ÙØ§ÛÛ ØšØ±Ø§Û 
+Ø±ÙØªÙ ØšÙ ØšØ®ØŽ ØšØ¹Ø¯ ÛØ§ ÙØšÙ ÙØ¬Ù Ø¯Ø§Ø±Ø¯ </p>
+
+<p>Ø¯Ø± Ø²ÛØ± Ø¹ÙÙØ§Ù ÛØ§ Ø¹Ú©Ø³ ØªØ¹Ø¯Ø§Ø¯ Ø¯Ú©Ù
+Ù ÙØ¬ÙØ¯ Ø¯Ø§Ø±Ø¯. ØšØ±Ø±ÙÛ 
+<i>ØšØ§Ø²Ú©Ø±Ø¯Ù Ù
+ØªÙ</i> Ú©ÙÛÚ© Ú©ÙÛØ¯ ØªØ§ ØªÙ
+Ø§Ù
+ Ù
+ØªÙ ØšØ®ØŽ ÛØ§ Ú©ØªØ§Øš Ø¬Ø§Ø±Û ÙÙ
+Ø§ÛØŽ Ø¯Ø§Ø¯Ù ØŽÙØ¯. 
+Ø§ÙØšØªÙ Ø§Ú¯Ø± Ø³ÙØ¯ ØšØ²Ø±Ú¯ ØšØ§ØŽØ¯ ÙÙØª Ú¯ÛØ± Ù Ø­Ø§ÙØžÙ Ú¯ÛØ± Ø®ÙØ§ÙØ¯ ØšÙØ¯ . 
+ØšØ§ Ú©ÙÛÚ© ØšØ±Ø±ÙÛ  <i>ØšØ§Ø²Ú©Ø±Ø¯Ù Ù
+Ø­ØªÙÛØ§Øª</i> ÙÙØ±Ø³Øª Ù
+Ø­ØªÙÛØ§Øª ÙØŽØ§Ù Ø¯Ø§Ø¯Ù Ø®ÙÙØ¯ ØŽØ¯ 
+Ù Ù
+Û ØªÙØ§ÙÛØ¯ Ø¹ÙØ§ÙÛÙ ØªÙ
+Ø§Ù
+ ÙØµÙÙ Ù Ø²ÛØ± ÙØµÙ ÙØ§ Ø±Ø§ ØšØšÛÙÛØ¯ .ØšØ§ Ú©ÙÛÚ© ØšØ±Ø±ÙÛ 
+ <i>ÙØ·Ø¹</i> ÙŸÙØ¬Ø±Ù Ø¬Ø¯ÛØ¯Û ØšØ±Ø§Û Ø§ÛÙ Ø³ÙØ¯ ØšØ§Ø² Ø®ÙØ§ÙØ¯ ØŽØ¯ . (ØšØ®ØµÙØµ ÙÙØªÛ Ù
+ÙÛØ¯ Ø§Ø³Øª Ú©Ù ØšØ®ÙØ§ÙÛØ¯ Ø¯Ù Ø³ÙØ¯ Ø±Ø§ Ù
+ÙØ§ÛØ³Ù Ú©ÙÛØ¯ Ù ÛØ§ ØšØ§ ÙÙ
+ ØšØ®ÙØ§ÙÛØ¯ 
+ .) ØšØ§ÙØ§Ø®Ø±Ù ÙÙØªÛ Ø¬Ø³ØªØ¬Ù Ù
+Û Ú©ÙÛØ¯ Ú©ÙÙ
+Ø§Øª Ù
+ÙØ±Ø¯ Ø¬Ø³ØªØ¬Ù ØšØ±Ø¬Ø³ØªÙ Ù
+Û ØŽÙØ¯ Ù ØšØ§ Ú©ÛÚ© Ø±ÙØ³ <i>ØšØ¯ÙÙ ØšØ±Ø¬Ø³ØªÙ Ø³Ø§Ø²Û</i> 
+ Ø§ÛÙ ØšØ±Ø¬Ø³ØªÙ Ø³Ø§Ø²Û ØŽØ¯Ù ÙØ§ Ø­Ø°Ù Ù
+Û ØŽÙÙØ¯.</p>
+
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>ØšØ§Ø² Ú©Ø±Ø¯Ù Ø§ÛÙ ÙÙØ³Ù Ú©ØªØ§Øš</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>ØšØ§Ø²Ú©Ø±Ø¯Ù/ØšØ³ØªÙ Ú©ØªØ§Øš</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>Ø±ÙÛØª Ø§ÛÙ ØšØ®ØŽ Ø§Ø² Ù
+ØªÙ</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>ÙÙ
+Ø§ÛØŽ ÛØ§ Ø¹Ø¯ Ù
+ÙÙ
+Ø§ÛØŽ ØªÙ
+Ø§Ù
+ Ù
+ØªÙ</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>ØšØ§Ø²Ú©Ø±Ø¯Ù ÙÙØ±Ø³Øª Ù
+Ø­ØªÙÛØ§Øª ÛØ§ ØšØ³ØªÙ Ø¢Ù</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>ØšØ§Ø² Ú©Ø±Ø¯Ù Ø§ÛÙ ØµÙØ­Ù Ø¯Ø± ÛÚ© ØµÙØ­Ù Ø¬Ø¯ÛØ¯</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>ØšØ±Ø¬Ø³ØªÙ Ø³Ø§Ø²Û Ú©ÙÙ
+Ø§Øª Ù
+ÙØ±Ø¯ Ø¬Ø³ØªØ¬Ù ÛØ§ Ø¹Ø¯Ù
+ ØšØ±Ø¬Ø³ØªÙ Ø³Ø§Ø²Û</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>ØšØ±Ø±ÙÛ ÙÙØŽ Ú©ÙÛÚ© Ú©ÙÛØ¯ ØªØ§ ØšÙ ØšØ®ØŽ ØšØ¹Ø¯Û ØšØ±ÙÛØ¯</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>ÛØ§ ØšØ±Ø§Û ØšØ§Ø²Ú¯ØŽØª ØšÙ ØšØ®ØŽ ÙØšÙÛ</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=fa] {<h2>ÚÚ¯ÙÙÙ Ú©ÙÙ
+Ø§Øª Ø®Ø§ØµÛ Ø±Ø§ Ø¬Ø³ØªØ¬Ù Ú©ÙÛÙ
+</h2>
+<p>
+  Ø§Ø² ØµÙØ­Ù Ø¬Ø³ØªØ¬Ù ØšÙ Ø±Ø§Ø­ØªÛ Ù
+Û ØªÙØ§ÙÛØ¯ ØšÙ Ø±ÙØŽ Ø²ÛØ± Ø§Ø³ØªÙØ§Ø¯Ù ÙÙ
+Ø§ÛÛØ¯:<p>
+  
+  <ol><li>Ù
+ÙØ§Ø±Ø¯ Ù
+ÙØ±Ø¯ Ø¬Ø³ØªØ¬ÙÛ Ø®ÙØ¯ Ø±Ø§ Ø³Ø§Ø¯Ù Ú©ÙÛØ¯
+      <li>Ø¢ÙÚÙ Ù
+Û Ø®ÙØ§ÙÛØ¯ ØšÛØ§ØšÛØ¯ ØšØ§ ÙÙ
+Ù ÛØ§ ØšØ±Ø®Û Ú©ÙÙ
+Ø§Øª Ø¢Ù Ù
+Ø±ÙØ± Ú©ÙÛØ¯
+      <li>Ú©ÙÙ
+Ø§ØªÛ Ú©Ù Ù
+Û Ø®ÙØ§ÙÛØ¯ ØšÛØ§ØšÛØ¯ ÙØ§Ø±Ø¯ ÙÙ
+Ø§ÛÛØ¯
+      <li>Ø±ÙÛ Ø¯Ú©Ù
+Ù <i>Ø¢ØºØ§Ø² Ø¬Ø³ØªØ¬Ù</i> Ú©ÙÛÚ© Ú©ÙÛØ¯
+  </ol>
+
+<p>
+ÙÙØªÛ Ø¬Ø³ØªØ¬Ù Ø§ÙØ¬Ø§Ù
+ Ù
+Û ØŽÙØ¯ Ø¹ÙØ§ÙÛÙ Ø§Ø³ÙØ§Ø¯ Ù
+Ø·Ø§ØšÙ ÙØŽØ§Ù Ø¯Ø§Ø¯Ù Ø®ÙØ§ÙØ¯ ØŽØ¯ .Ø¯Ø± Ø§ÙØªÙØ§ Ø¯Ú©Ù
+Ù Ø§Û
+ØšØ±Ø§Û Ø¯ÛØ¯Ù ØšÛØ³Øª ÙØªÛØ¬Ù ØšØ¹Ø¯Û ÙØ¬ÙØ¯ Ø¯Ø§Ø±Ø¯ Ù Ø¯Ø± Ø¢ÙØ¬Ø§ Ø¯Ú©Ù
+Ù ÙØ§ÛÛ ØšØ±Ø§Û Ø¯ÛØ¯Ù ÙØªØ§ÛØ¬ ØšØ¯Û Ù ÙØšÙÛ Ù ÙØžØ§ÛØ± 
+Ø¢Ù Ø®ÙØ§ÙØ¯ ØšÙØ¯ . ØšØ§ Ú©ÙÛÚ© ØšØ± Ø±ÙÛ Ø¹ÙÙØ§Ù ÙØ± Ø³ÙØ¯ ÛØ§ Ø¯Ú©Ù
+Ù Ú©ÙÚÚ© Ú©Ø§Ø± Ø¢Ù Ù
+Û ØªÙØ§ÙÛØ¯ Ø³ÙØ¯ Ø±Ø§ ØšØšÛÙÛØ¯
+<p>Ø­Ø¯Ø§Ú©Ø«Ø± ØµØ¯ ÙØªÛØ¬Ù Ø¯ÛØ¯Ù Ù
+Û ØŽÙØ¯.  ØŽÙ
+Ø§ Ù
+Û ØªÙØ§ÙÛØ¯ ØšØ§ Ú©ÙÛÚ© ØšØ±Ø±ÙÛ Ø¯Ú©Ù
+Ù
+  <i>ØªÙØžÛÙ
+Ø§Øª</i> Ø¯Ø± ØšØ§ÙØ§Û ØµÙØ­Ù Ø§ÛÙ Ø¹Ø¯Ø¯ Ø±Ø§ ØªØºÛÛØ± Ø¯ÙÛØ¯.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Ø¬Ø³ØªØ¬ÙÛ Ø¹ØšØ§Ø±Ø§Øª</h3>
+
+<p>
+ÙØ± ÚÛØ²Û Ú©Ù Ø¯Ø± Ø¬Ø¹ÛÙ Ø³ÙØ§Ù ÙØ§Ø±Ø¯ Ú©ÙÛØ¯ ØšÙ Ø¹ÙÙØ§Ù ÙÙØ±Ø³ØªÛ Ø§Ø² Ú©ÙÙ
+Ø§Øª Ø¹ØšØ§Ø±Ø§Øª Ø¬Ø³ØªØ¬Ù ÙØ§Ù
+ Ø¯Ø§Ø±Ø¯ .
+ÙØ± Ø¹ØšØ§Ø±Øª ÚÛØ²Û Ø¬Ø² Ø­Ø±ÙÙ Ù Ø§Ø¹Ø¯Ø§Ø¯ ÙÛØ³Øª . ÙØšØ§Ø±Ø§Øª ØšØ§ ÙØ¶Ø§Û Ø®Ø§ÙÛ Ø§Ø² ÙÙ
+ Ø¬Ø¯Û Ù
+ÛØŽÙÙØ¯ . Ø§Ú¯Ø±
+ÙØ± Ú©Ø§Ø±Ø§Ú©ØªØ± Ø¯ÛÚ¯Ø±Û Ù
+Ø§ÙÙØ¯ ÙÙØ·Ù Ú¯Ø°Ø§Ø±Û Ø§Ø³ØªÙØ§Ø¯Ù ØŽÙØ¯ ØšÙ Ø¹ÙÙØ§Ù ÙØ¶Ø§Û Ø®Ø§ÙÛ ØšØ±Ø§Û Ø¬Ø¯Ø§Ú©Ø±Ø¯Ù 
+Ø¹ØšØ§Ø±Ø§Øª Ø¯Ø± ÙØžØ± Ú¯Ø±ÙØªÙ Ø®ÙØ§ÙØ¯ ØŽØ¯ Ù Ø­Ø±Ù Ø®ÙØ§ÙÙØ¯ ØŽØ¯ . Ø¹ØšØ§Ø±Ø§ØªÛ Ú©Ù ØŽØ§Ù
+Ù Ø¹ÙØ§ØŠÙ
+ ÙÙØ·Ù Ú¯Ø°Ø§Ø±Û ØšØ§ØŽÙØ¯ 
+ÙØ§ØšÙ Ø¬Ø³ØªØ¬Ù ÙÛØ³ØªÙØ¯ .
+<p>ØšØ±Ø§Û Ù
+Ø«Ø§Ù Ø³ÙØ§Ù<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p> Ù
+Ø§ÙÙØ¯ Ø§ÛÙ Ù
+ÙØ±Ø¯ Ø®ÙØ§ÙØ¯ ØšÙØ¯: <p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Query type</h3>
+
+<p>Ø¯Ù ÙÙØ¹ ÙŸØ±Ø³ Ù Ø¬Ù ÙØ¬ÙØ¯ Ø¯Ø§Ø±Ø¯ :
+
+<ul>
+  <li>Ø¬Ø³ØªØ¬Ù ØšØ±Ø§Û  <b>ÙÙ
+Ù</b> Ú©ÙÙ
+Ø§Øª.  ØŽØ§Ù
+Ù Ø§Ø³ÙØ§Ø¯Û Ù
+Û ØŽÙØ¯ (ÛØ§ ÙØµÙÙ ÛØ§ Ø¹ÙØ§ÙÛÙ)
+   Ú©Ù ØªÙ
+Ø§Ù
+ Ú©ÙÙ
+Ø§Øª Ù
+ÙØ±Ø¯ ÙØžØ± ØŽÙ
+Ø§ Ø¯Ø± Ø¢Ù ÙØ¬ÙØ¯ Ø¯Ø§Ø±ÙØ¯ .
+      Ø§Ø³ÙØ§Ø¯Û Ú©Ù ØªØ·ØšÛÙ Ú©ÙÙØ¯ ØšÙ ØªØ±ØªÛØš Ø§ÙÙØšØ§ÛÛ ÙØŽØ§Ù Ø¯Ø§Ø¯Ù Ø®ÙØ§ÙØ¯ ØŽØ¯.<p>
+
+  <li>Ø¬Ø³ØªØ¬ÙÛ ØšØ±Ø§Û  <b>ØšØ¹Ø¶Û </b> Ø§Ø² Ú©ÙÙ
+Ø§Øª.  ÙÙØ±Ø³ØªÛ Ø§Ø² Ø¹ØšØ§Ø±Ø§Øª Ú©Ù Ù
+Ù
+Ú©Ù Ø§Ø³Øª Ø¯Ø± Ø³ÙØ¯ ÙØ¬ÙØ¯ Ø¯Ø§ØŽØªÙ 
+  ØšØ§ØŽÙØ¯.  ÙØªØ§ÛØ¬ ØšØ± Ø§Ø³Ø§Ø³ Ù
+ÛØ²Ø§Ù ØªØ·Ø§ØšÙ ØšØ§ Ø¬Ø³ØªØ¬Ù ÙØŽØ§Ù Ø¯Ø§Ø¯Ù Ù
+Û ØŽÙÙØ¯ .  
+  Ø¯Ø± ØªØ¹ÛÛÙ Ù
+ÛØ²Ø§Ù ØªØ·Ø§ØšÙ,
+
+      <p><ul>
+        <li> ÙØ±ÚÙ ØšÛØŽØªØ± Ø§Ø² Ø¹ØšØ§Ø±Ø§Øª Ø¬Ø³ØªØ¬Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽØ¯ ØšÛØŽØªØ± ØªØ·Ø§ØšÙ Ø¯Ø§Ø±Ø¯
+        <li> Ø¹ØšØ§Ø±Ø§Øª ÙØ§Ø¯Ø± ØšÛØŽØªØ± Ø§Ø² Ø¹ØšØ§Ø±Ø§Øª Ø¹Ù
+ÙÙ
+Û Ù
+ÙÙ
+ ÙØ³ØªÙØ¯
+        <li> Ø§Ø³ÙØ§Ø¯ Ú©ÙØªØ§Ù Ù
+ÙÙ
+ØªØ± Ø§Ø² Ø§Ø³ÙØ§Ø¯ ØšÙÙØ¯ ÙØ³ØªÙØ¯.
+      </ul>
+</ul>
+
+<p>ÙØ± ØªØ¹Ø¯Ø§Ø¯ ÙØšØ§Ø±Øª Ú©Ù Ù
+Û Ø®ÙØ§ÙÛØ¯ ØšØ±Ø§Û Ø¬Ø³ØªØ¬Ù ÙØ§Ø±Ø¯ Ú©ÙÛØ¯ ÛÚ© Ø¬Ù
+ÙÙ ÛØ§ Ø­ØªÛ ÛÚ© ÙŸØ§Ø±Ø§Ú¯Ø±Ø§Ù.
+Ø§Ú¯Ø± ØªÙÙØ§ ÛÚ© Ø¹ØšØ§Ø±Øª ÙØ§Ø±Ø¯ Ú©ÙÛØ¯ ØšØ± Ø­Ø³Øš ØªÚ©Ø±Ø§Ø± Ø¢Ù Ø¹ØšØ§Ø±Øª ÙØªØ§ÛØ¬ Ù
+Ø±ØªØš Ø®ÙØ§ÙÙØ¯ ØŽØ¯.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=fa] {Ø¬Ø³ØªØ¬Ù ØšØ§ ØªØ§Ø±ÙØ®}
+
+_texthelpdatesearch_ [l=fa] {"<h2>_textdatesearch_</h2>
+Ø¬Ø³ØªØ¬ÙÛ ØšÙ Ú©Ù
+Ú© ØªØ§Ø±ÛØ® Ø§Ø³ÙØ§Ø¯Û Ø±Ø§ ØšÛØ§ØšÛØ¯ Ú©Ù Ø¹ÙØ§ÙÙ ØšØ± Ø§ÛÙÚ©Ù Ø¹ØšØ§Ø±Ø§Øª Ù
+ÙØ±Ø¯ Ø¬Ø³ØªØ¬ÙÛ ØŽÙ
+Ø§ 
+Ø¯Ø± Ø¢Ù ÙØ¬ÙØ¯ Ø¯Ø§Ø±Ø¯ Ø¯Ø± ÛÚ© ØšØ§Ø²Ù Ø²Ù
+Ø§ÙÛ Ø®Ø§Øµ ÙÙ
+ ÙØ±Ø§Ø± Ú¯Ø±ÙØªÙ Ø§Ø³Øª . ØŽÙ
+Ø§ Ù
+Û ØªÙØ§ÙÛØ¯ Ø§Ø³ÙØ§Ø¯Û Ø±Ø§ Ø¯Ø± ÛÚ© Ø³Ø§Ù 
+Ù
+ØŽØ®Øµ ÛØ§ Ø¯Ø± Ù
+Ø­Ø¯ÙØ¯Ù Ø§Û Ø§Ø² Ø³Ø§ÙÙØ§ ÙØ±Ø§Ø± Ø¯Ø§Ø±ÙØ¯ . ØªÙØ¬Ù Ø¯Ø§ØŽØªÙ ØšØ§ØŽÛØ¯ Ú©Ù Ù
+Ø¬ØšÙØ± ÙÛØ³ØªÛØ¯ Ø®ØªÙ
+Ø§ Ø¹ØšØ§Ø±ØªÛ 
+ØšØ±Ø§Û Ø¬Ø³ØªØ¬Ù ÙØ§Ø±Ø¯ Ú©ÙÛØ¯ ØšÙÚ©Ù Ù
+Û ØªÙØ§ÙÛØ¯ ØªÙÙØ§ ØšØ§ Ù
+ØŽØ®Øµ Ú©Ø±Ø¯Ù ØªØ§Ø±ÛØ® Ø¬Ø³ØªØ¬Ù ÙÙ
+Ø§ÛÛØ¯ .
+ÙÙ
+ÚÙÛÙ ÙØ§Ø²Ù
+ ÙÛØ³Øª Ú©Ù Ø§Ø² ØªØ§Ø±ÛØ® Ø¯Ø± Ø¬Ø³ØªØ¬Ù Ø§Ø³ØªÙØ§Ø¯Ù ÙÙ
+Ø§ÛÛØ¯ Ù Ø§Ú¯Ø± ØªØ§Ø±ÛØ®Û ÙØ§Ø±Ø¯ ÙÚ©ÙÛØ¯
+Ù
+Ø§ÙÙØ¯ Ø§ÛÙ Ø§Ø³Øª Ú©Ù Ø§ØµÙØ§ Ø¬Ø³ØªØ¬ÙÛ ØªØ§Ø±ÛØ® ÙØ¬ÙØ¯ ÙØ¯Ø§Ø±Ø¯ .
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>ÚÚ¯ÙÙÚ¯Û Ø§Ø³ØªÙØ§Ø¯Ù Ø§Ø² Ø§ÛÙ ÙÛÚÚ¯Û</h3>
+<ul>
+   <li>ØšØ±Ø§Û Ø¬Ø³ØªØ¬ÙÛ Ø§Ø³ÙØ§Ø¯ Ø¯Ø± ÛÚ© Ø³Ø§Ù Ù
+Ø¹ÛÙ :<p>
+   <ul>
+       <li>Ø¹ØšØ§Ø±Ø§Øª Ù
+ÙØ±Ø¯ Ø¬Ø³ØªØ¬Ù Ø®ÙØ¯ Ø±Ø§ ØšÙ ØŽÛÙÙ Ù
+Ø¹Ù
+ÙÙ ÙØ§Ø±Ø¯ Ú©ÙÛØ¯ 
+       <li>Ø¯Ø± ÙØ³Ù
+Øª "ØªØ§Ø±ÛØ® Ø¢ØºØ§Ø² (ÛØ§ ÙÙØ·)" Ø³Ø§Ù Ù
+ÙØ±Ø¯ ÙØžØ± Ø±Ø§ ÙØ§Ø±Ø¯ Ú©ÙÛØ¯.
+       <li>Ø§Ú¯Ø± ØªØ§Ø±ÛØ® Ù
+ÙØ±Ø¯ ÙØžØ± ØŽÙ
+Ø§ ÙØšÙ Ø§Ø² Ø¹ØµØ± Ø­Ø§Ø¶Ø± Ø§Ø³Øª (ÙØšÙ Ø§Ø² Ù
+Ø³ÛØ­) 
+ Ú¯Ø²ÛÙÙ ÙŸÛØŽ Ø§Ø² Ù
+ÛÙØ§Ø¯ Ù
+Ø³ÛØ­ Ø±Ø§ Ø§Ø² Ù
+ÙÙÛ Ú©ÙØ§Ø± ÙØ³Ù
+Øª ØªØ§Ø±ÛØ® Ø§ÙØªØ®Ø§Øš Ú©ÙÛØ¯.
+       <li>Ù
+Ø§ÙÙØ¯ ÙÙ
+ÛØŽÙ Ø¬Ø³ØªØ¬ÙÛ Ø®ÙØ¯ Ø±Ø§ Ø¢ØºØ§Ø² Ú©ÙÛØ¯
+   </ul>
+<p><li>ØšØ±Ø§Û Ø¬Ø³ØªØ¬Ù Ø¯Ø± ÛÚ© ØšØ§Ø²Ù Ø²Ù
+Ø§ÙÛ ÛØ§ ØšÛÙ Ø¯ÙØ³Ø§Ù :<p>
+   <ul>
+       <li>Ø¹ØšØ§Ø±Ø§Øª Ù
+ÙØ±Ø¯ Ø¬Ø³ØªØ¬Ù Ø®ÙØ¯ Ø±Ø§ ØšÙ ØŽÛÙÙ Ù
+Ø¹Ù
+ÙÙ ÙØ§Ø±Ø¯ Ú©ÙÛØ¯
+       <li>ØªØ§Ø±ÛØ® Ø§ØšØªØ¯Ø§ Ø±Ø§ Ø¯Ø± ÙØ³Ù
+Øª "ØªØ§Ø±ÛØ® Ø¢ØºØ§Ø²(ÛØ§ÙÙØ·)" ÙØ§Ø±Ø¯ Ú©ÙÛØ¯
+       <li>ØªØ§Ø±ÛØ® Ø§ÙØªÙØ§ Ø±Ø§ Ø¯Ø± ÙØ³Ù
+Øª "ØªØ§Ø±ÛØ® Ø§ÙØªÙØ§" ÙØ§Ø±Ø¯ Ú©ÙÛØ¯.
+       <li>Ø§Ú¯Ø± ØªØ§Ø±ÛØ® Ù
+ÙØ±Ø¯ ÙØžØ± ØŽÙ
+Ø§ ÙØšÙ Ø§Ø² Ø¹ØµØ± Ø­Ø§Ø¶Ø± Ø§Ø³Øª (ÙØšÙ Ø§Ø² Ù
+Ø³ÛØ­) 
+ Ú¯Ø²ÛÙÙ ÙŸÛØŽ Ø§Ø² Ù
+ÛÙØ§Ø¯ Ù
+Ø³ÛØ­ Ø±Ø§ Ø§Ø² Ù
+ÙÙÛ Ú©ÙØ§Ø± ÙØ³Ù
+Øª ØªØ§Ø±ÛØ® Ø§ÙØªØ®Ø§Øš Ú©ÙÛØ¯.
+       <li>Ù
+Ø§ÙÙØ¯ ÙÙ
+ÛØŽÙ Ø¬Ø³ØªØ¬ÙÛ Ø®ÙØ¯ Ø±Ø§ Ø¢ØºØ§Ø² Ú©ÙÛØ¯
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>ÚÚ¯ÙÙÙ ÙØªØ§ÛØ¬ Ø¬Ø³ØªØ¬ÙÛ ØŽÙ
+Ø§ ÛØ§ÙØª Ù
+Û ØŽÙØ¯</h3>
+
+Ù
+Ø¹Ù
+ÙÙØ§ Ø¬Ø³ØªØ¬ÙÛ Ø§Ø³ÙØ§Ø¯ Ø¯Ø±ØšØ§Ø±Ù 1903 Ø§Ø³ÙØ§Ø¯Û Ø±Ø§ Ø¯Ø± Ø§ÛÙ Ø³Ø§Ù ÙÙØŽØªÙ ØŽØ¯Ù Ø§ÙØ¯ ØšØ± ÙÙ
+Û Ú¯Ø±Ø¯Ø§ÙØ¯ ØšÙÚ©Ù Ø§Ø³ÙØ§Ø¯Û Ø¯Ø±ØšØ§Ø±Ù 1903 Ø±Ø§ ØšØ±Ù
+Û Ú¯Ø±Ø¯Ø§ÙØ¯ . ÙÙÛ ØšØ§ ØªÙØ¬Ù ØšÙ Ø­Ø§ÙØªÛ Ú©Ù Ø¯Ø± Ø§Ø³ÙØ§Ø¯ ØªØ§Ø±ÛØ® ÙØ§ ÙØ¬ÙØ¯ Ø¯Ø§Ø±ÙØ¯  Ø§Ø³ÙØ§Ø¯Û Ø±Ø§ Ú©Ù ØšØ§Ø²Ù Ø²Ù
+Ø§ÙÛ Ø®Ø§ØµÛ Ù
+Ø«ÙØ§ 1899-1911 Ú©Ù ØŽØ§Ù
+Ù 1903 ÙÙ
+ Ù
+Û ØŽÙØ¯ Ù Ø§Ø³ÙØ§Ø¯Û Ú©Ù Ù
+Ø«ÙØ§ Ø­Ø§ÙÛ ÙØ±ÙÛ Ú©Ù Ø³Ø§Ù 1903 Ø¯Ø± Ø¢Ù Ø§Ø³Øª Ù
+Ø§ÙÙØ¯ ÙØ±Ù ØšÛØ³ØªÙ
+ ÛØ§ Ø¯ÙØ§Ø²Ø¯ÙÙ
+ ØªØŽØ®ÛØµ Ø¯Ø§Ø¯Ù Ù
+Û ØŽÙØ¯ . ØªÙØ¬Ù Ú©ÙÛØ¯ Ú©Ù Ø¯Ø± ØšØ¹Ø¶Û Ø§Ø³ÙØ§Ø¯ ØªØ§Ø±ÛØ® ÙØ§ ÙØ§ÙØ¹Ø§ Ø¯Ø± Ù
+ØªÙ ÙÛØ³ØªÙØ¯ . ØšØ±Ø§Û ÛÚ© Ø¬Ø³ØªØ¬ÙÛ Ù
+Ø­Ø¯ÙØ¯Ù Ø§Û ØŽØ§Ù
+Ù ÙÙ
+Ù ØªØ§Ø±ÛØ® ÙØ§ Ø¯Ø± Ø§ÛÙ Ù
+Ø­Ø¯ÙØ¯Ù Ù
+Û ØŽÙØ¯ .<p>
+"
+}
+
+_textchangeprefs_ [l=fa] {ØªØºÙÙØ± ØªÙØžÙÙ
+Ø§Øª}
+
+_texthelppreferences_ [l=fa] {<h2>_textchangeprefs_</h2>
+
+<p>ØšØ§ Ú©ÙÛÚ© ØšØ± Ø±ÙÛ Ø¯Ú©Ù
+Ù <i>ØªÙØžÛÙ
+Ø§Øª</i> Ø¯Ø± ØšØ§ÙØ§Û ØµÙØ­Ù ØŽÙ
+Ø§ Ù
+Û ØªÙØ§ÙÛØ¯ ØªØ§ ØšØ¹Ø¶Û ÙÛÚÚ¯ÛÙØ§Û Ø±Ø§ØšØ· Ú©Ø§Ø±ØšØ±Û
+Ø±Ø§ ØšØ§ ØªÙØ¬Ù ØšÙ ÙÛØ§Ø² Ø®ÙØ¯ ØªØºÛÛØ± Ø¯ÙÛØ¯. 
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>ØªÙØžÛÙ
+Ø§Øª Ù
+Ø¬Ù
+ÙØ¹Ù</h3>
+
+ØšØ¹Ø¶Û Ø§Ø² Ù
+Ø¬Ù
+ÙØ¹ ÙØ§ ØŽØ§Ù
+Ù ÚÙØ¯ÛÙ Ø²ÛØ± Ù
+Ø¬Ù
+ÙØ¹Ù ÙØ³ØªÙØ¯ Ú©Ù Ù
+ÛØªÙØ§Ù ØšÙ ØµÙØ±Øª Ù
+Ø³ØªÙÙ ÛØ§ ØšØ§ÙÙ
+
+Ø¬Ø³ØªØ¬Ù ØŽÙÙØ¯ . Ú©Ù Ø¯Ø± Ø§ÛÙ ÙØ³Ù
+Øª Ù
+Û ØªÙØ§ÙÛØ¯ Ù
+ØŽØ®Øµ Ú©ÙÛØ¯ ÚÙ Ø²ÛØ± Ù
+Ø¬Ù
+ÙØ¹Ù ÙØ§ÛÛ Ø¯Ø± Ø¬Ø³ØªØ¬ÙÛ
+ØŽÙ
+Ø§ ØšØ§ØŽÙØ¯ .
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>ØªÙØžÛÙ
+Ø§Øª Ø²ØšØ§Ù</h3>
+ ÙØ± Ù
+Ø¬Ù
+ÙØ¹Ù ÛÚ© Ø²ØšØ§Ù ÙŸÛØŽ Ú¯Ø²ÛØ¯Ù Ø¯Ø§Ø±Ø¯ Ø§Ù
+Ø§ Ø¯Ø± ØµÙØ±Øª ØªÙ
+Ø§ÛÙ Ù
+Û ØªÙØ§ÙÛØ¯ ØšÙ Ø²ØšØ§Ù Ø¯ÛÚ¯Ø±Û 
+Ø¢Ù Ø±Ø§ ØªØºÛÛØ± Ø¯ÙÛØ¯ . ØŽÙ
+Ø§ Ù
+Û ØªÙØ§ÙÛØ¯ Ø±ÙØŽ Ú©Ø¯Ú¯Ø°Ø§Ø±Û ÙØ±Ù
+ Ø§ÙØ²Ø§Ø± ØšØ±Ø§Û Ø®Ø±ÙØ¬Û Ù
+Ø±ÙØ±Ú¯Ø± Ø±Ø§ ØªØºÛÛØ± Ø¯ÙÛØ¯ .
+Ø§ÙØšØªÙ ÙØ±Ù
+ Ø§ÙØ²Ø§Ø± ØšÙ ØµÙØ±Øª ÙŸÛØŽ Ú¯Ø²ÛØ¯Ù Ø±ÙØŽ Ù
+ÙØ§Ø³Øš Ø±Ø§ Ø§ÙØªØ®Ø§Øš Ù
+Û Ú©ÙØ¯ Ø§Ù
+Ø§ Ø¯Ø± ØšØ¹Ø¶Û Ù
+Ø±ÙØ±Ú¯Ø± ÙØ§
+Ù
+Û ØªÙØ§Ù ØšØ§ Ø³Ø§ÛØ± Ø±ÙØŽ ÙØ§ ÙØªÛØ¬Ù ØšÙØªØ±Û Ú¯Ø±ÙØª . Ø¯Ø± ØªÙ
+Ø§Ù
+ Ù
+Ø¬Ù
+ÙØ¹Ù ÙØ§ Ù
+Û ØªÙØ§Ù ÙØ§ÙØš Ú¯Ø±Ø§ÙÛÚ©Û Ø±Ø§ØšØ· Ø±Ø§ ØšÙ Ù
+ØªÙÛ 
+ØªØºÛÛØ± Ø¯Ø§Ø±Ø¯ Ú©Ù ØšÙ Ø®ØµÙØµ ØšØ±Ø§Û Ø§ÙØ±Ø§Ø¯Û Ú©Ù Ø¯Ø± Ø¯ÛØ¯ Ù
+ØŽÚ©Ù Ø¯Ø§Ø±ÙØ¯ ØšØ³ÛØ§Ø± Ù
+ÙÛØ¯ Ø§Ø³Øª Ø²ÛØ±Ø§ Ù
+Û ØªÙØ§ÙÙØ¯ Ø§Ø² Ø®Ø·ÙØ· 
+Ø¯Ø±ØŽØª ØªØ± ÛØ§ Ø®ÙØ§ÙÙØ¯Ù ÙØ§Û Ù
+ØªÙ Ø§Ø³ØªÙØ§Ø¯Ù ÙÙ
+Ø§ÛÙØ¯ .
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>ØªÙØžÛÙ
+Ø§Øª Ø§Ø±Ø§ØŠÙ</h3>
+
+Depending on the particular collection, there may be several options you can
+set that control the presentation.
+ØšØ§ ØªÙØ¬Ù ØšÙ ÙØ± Ù
+Ø¬Ù
+ÙØ¹Ù Ù
+Û ØªÙØ§Ù ÚÙØ¯ÛÙ Ú¯Ø²ÛÙÙ Ù
+Ø±ØªØšØ· ØšØ§ Ø§Ø±Ø§ØŠÙ Ø±Ø§ ØªÙØžÛÙ
+ ÙÙ
+ÙØ¯.
+<p>
+Ù
+Ø¬Ù
+ÙØ¹Ù Ø§Û Ø§Ø² ØµÙØ­Ø§Øª ÙØš ØŽÙ
+Ø§ Ø±Ø§ ÙØ§Ø¯Ø± Ù
+Û Ø³Ø§Ø²Ø¯ ØªØ§ ÙÙØ§Ø± ÙØ±Ø§Ù
+ÛÙ ØšØ§ÙØ§Û ÙØ± ØµÙØ­Ù Ø±Ø§ ØªØºÛÛØ± Ø¯ÙÛØ¯  ØšÙØ§ØšØ±Ø§ÛÙ
+Ù
+Û ØªÙØ§ÙÛØ¯ ØµÙØ­Ø§Øª Ù
+ÙØ±Ø¯ ÙØžØ± Ø®ÙØ¯ Ø±Ø§ ØšØ¯ÙÙ Ø³Ø±ØµÙØ­Ù ÙØ§Û Ø§Ø³ØªØ§ÙØ¯Ø§Ø±Ø¯ Ø·Ø±Ø§Ø­Û ÙÙ
+Ø§ÛÛØ¯ . 
+Ø­ØªÛ Ù
+Û ØªÙØ§ÙØ¯ ÙŸÛØ§Ù
+ ÙØ§Û Ø§Ø®Ø·Ø§Ø± Ø³ÛØ³ØªÙ
+ Ø±Ø§ ØªØºÛÛØ± Ø¯ÙÛØ¯ Ù Ø­ØªÛ Ø¯Ø± ØšØ¹Ø¶Û ØµÙØ­Ø§Øª Ù
+Û ØªÙØ§ÙÛØ¯ Ø¯Ø± ØµÙØ­Ù
+ÙØªØ§ÛØ¬ Ø¬Ø³ØªØ¬Ù Ø·ÙØ±Û ØªÙØžÛÙ
+ Ú©ÙÛØ¯ Ú©Ù ØšÙ Ø¬Ø§Û ÙÙ
+Ø§ÛØŽ ÙØ³Ø®Ù Ø°Ø®ÛØ±Ù ØŽØ¯Ù Ø¯Ø± ØšØ±ÙØ§Ù
+Ù ÙØ³Ø®Ù ÙØ§ÙØ¹Û ÙÙ
+Ø§ÛØŽ ÛØ§ØšØ¯ .
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>ØªÙØžÛÙ
+Ø§Øª Ø¬Ø³ØªØ¬Ù</h3>
+<p>
+Ø¯Ù Ø¬ÙØª Ø¯Ú©Ù
+Ø® ÙØ­ÙÙ ØªØ·ØšÛÙ Ù
+ØªÙÙ Ø±Ø§ Ø¯Ø± Ø¬Ø³ØªØ¬ÙÙØ§ Ú©ÙØªØ±Ù Ù
+Û Ú©ÙÙØ¯ . Ø§ÙÙÛÙ Ú¯Ø²ÛÙÙ(ØªÙØ§ÙØª Ø­Ø§ÙØª Ø­Ø±ÙÙ) ØªØ¹ÛÛÙ Ù
+Û Ú©ÙØ¯ Ú©Ù
+Ú©ÙÚÚ© Ù ØšØ²Ø±Ú¯Û Ø­Ø±ÙÙ Ù
+Ø¯ ÙØžØ± ÙØ±Ø§Ø± Ú¯ÛØ±Ø¯ ÛØ§ Ø®ÛØ± . Ø¯ÙÙ
+ÛÙ Ú¯Ø²ÛÙÙ(Ø§ÙØªÙØ§Û Ú©ÙÙ
+Ø§Øª) ØªØ¹ÛÛÙ Ù
+Û Ú©ÙØ¯ Ú©Ù Ø§Ø² Ø§ÙØªÙØ§Û Ú©ÙÙ
+Ø§Øª
+ÚØŽÙ
+ ÙŸÙØŽÛ ØŽÙØ¯ ÛØ§ Ø®ÛØ± . Ù
+Ù
+Ú©Ù Ø§Ø³Øª Ø¬Ø¹ØšÙ ÙŸØ±Ø³ Ù Ø¬ÙÛ ØšØ²Ø±Ú¯Û ÙØ§Ø²Ù
+ Ø¯Ø§ØŽØªÙ ØšØ§ØŽØ¯ Ú©Ù ØšØªÙØ§ÙÛØ¯ Ø¬Ø³ØªØ¬ÙÛ Ù
+ØªÙÙ ÙŸØ§Ø±Ø§Ú¯Ø±Ø§ÙÛ
+Ø§ÙØ¬Ø§Ù
+ Ø¯ÙÛØ¯ . Ø¬Ø³ØªØ¬ÙÛ Ù
+ÙØ§Ø¯ÛØ± Ø²ÛØ§Ø¯Û Ù
+ØªÙ ØšØ³ÛØ§Ø± Ø³Ø±ÛØ¹ Ø§Ø³Øª .
+
+<p>ØšØ±Ø§Û Ù
+Ø«Ø§Ù Ø§Ú¯Ø±  <i>ÚØŽÙ
+ ÙŸÙØŽÛ Ø§Ø² Ø­Ø§ÙØª Ø­Ø±ÙÙ</i> Ù
+<i>ÚØŽÙ
+ ÙŸÙØŽÛ Ø§Ø² Ø§ÙØªÙØ§Û Ú©ÙÙ
+Ø§Øª</i> Ø§ÙØªØ®Ø§Øš ØŽØ¯Ù ØšØ§ØŽÙØ¯ , Ø¬Ø³ØªØ¬ÙÛ<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>Ø¯Ø±Ø³Øª Ù
+Ø§ÙÙØ¯<p>
+      <ul><kbd>africa builds</kbd></ul> Ø®ÙØ§ÙØ¯ ØšÙØ¯<p>
+      Ø²ÛØ±Ø§ Ø­Ø±Ù ØšØ²Ø±Ú¯ "African" ØšÙ Ú©ÙÚÚ© ØªØšØ¯ÛÙ Ø®ÙØ§ÙØ¯ ØŽØ¯, 
+  Ù ÙŸØ³ÙÙØ¯  "n" Ù "ing" Ø­Ø°Ù Ø®ÙØ§ÙÙØ¯ ØŽØ¯
+      "African" Ù "building" ÙÙ
+ ØšÙ ÙÙ
+ÛÙ ØªØ±ØªÛØš (ÙÙ
+ÚÙÛÙ, "s" Ø§Ø²
+      "builds" Ø­Ø°Ù Ø®ÙØ§ÙØ¯ ØŽØ¯).
+
+<p>
+ØŽÙ
+Ø§ Ù
+Û ØªÙØ§ÙÛØ¯ ØšÙ Ø­Ø§ÙØª ÙŸØ±Ø³ Ù Ø¬ÙÛ ÙŸÛØŽØ±ÙØªÙ ØšØ±ÙÛØ¯ Ú©Ù Ø¯Ø± Ø¢Ù ÙØ§Ø¯Ø± Ø®ÙØ§ÙÛØ¯ ØšÙØ¯ Ø§Ø² Ø¹Ù
+ÙÚ¯Ø±ÛÙØ§Û Ù& ÛØ§ | Ù ÙÙ! 
+Ø§Ø³ØªÙØ§Ø¯Ù Ú©ÙÛØ¯ ØªØ§ ÙŸØ±Ø³ Ù Ø¬ÙÛÙØ§Û Ø¯ÙÛÙ ØªØ±Û Ø¯Ø§ØŽØªÙ ØšØ§ØŽÛØ¯ . ØŽÙ
+Ø§ Ù
+Û ØªÙØ§ÙÛØ¯ Ø³Ø§ØšÙÙ Ø¬Ø³ØªØ¬Ù Ø±Ø§ ÙØ¹Ø§Ù Ú©ÙÛØ¯ 
+ØªØ§ Ø¢Ø®Ø±ÛÙ Ø¬Ø³ØªØ¬ÙÙØ§Û Ø®ÙØ¯ Ø±Ø§ ØšØšÛÙÛØ¯ . ØšÙ Ø§ÛÙ Ø·Ø±ÛÙ Ù
+Û ØªÙØ§ÙÛØ¯ Ø¬Ø³ØªØ¬ÙÙØ§Û Ø®ÙØ¯ Ø±Ø§ Ø§ØµÙØ§Ø­ Ù Ù
+ÙØ±Ø¯ 
+Ø§Ø³ØªÙØ§Ø¯Ù Ù
+Ø¬Ø¯Ø¯ ÙØ±Ø§Ø± Ø¯ÙÛØ¯ . Ø¯Ø± Ø¢Ø®Ø± ØŽÙ
+Ø§ Ù
+Û ØªÙØ§ÙÛØ¯ ØªØ¹Ø¯Ø§Ø¯ ÙØªØ§ÛØ¬ ØšØ±Ú¯ØŽØªÛ Ù ØªØ¹Ø¯Ø§Ø¯ ÙÙ
+Ø§ÛØŽ ÙØŽØ§Ù Ø¯Ø§Ø¯Ù ØŽØ¯Ù Ø¯Ø± 
+ÙØ± ØµÙØ­Ù Ø±Ø§ Ù
+Ø¹ÛÙ Ú©ÙÛØ¯ .}
+
+_texttanumbrowseoptions_ [l=fa] {ØšØ±Ø§Û ÛØ§ÙØªÙ Ø§Ø·ÙØ§Ø¹Ø§Øª Ø¯Ø± Ø§ÛÙ Ù
+Ø¬Ù
+ÙØ¹Ù _numbrowseoptions_ Ø±Ø§Ù ÙØ¬ÙØ¯ Ø¯Ø§Ø±Ø¯ .}
+
+_textsimplehelpheading_ [l=fa] {ÚÚ¯ÙÙÙ Ø§Ø·ÙØ§Ø¹Ø§ØªÛ Ø¯Ø±Ù
+Ø¬Ù
+ÙØ¹Ù _collectionname_ ØšÛØ§ØšÛÙ
+ }
+
+_texthelpscope_ [l=fa] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Ù
+Ø­Ø¯ÙØ¯Ù ÙŸØ±Ø³ Ù Ø¬ÙÙØ§</h3>
+
+<p>
+ Ø¯Ø± Ø§ØºÙØš Ù
+Ø¬Ù
+ÙØ¹Ù ÙØ§Û ØŽÙ
+Ø§ Ù
+Û ØªÙØ§ÙÛØ¯ Ø§ÛÙØ¯Ú©Ø³ ÙØ§Û Ù
+Ø®ØªÙÙÛ Ø±Ø§ ØšØ±Ø§Û Ø¬Ø³ØªØ¬Ù Ø§ÙØªØ®Ø§Øš Ú©ÙÛØ¯ . ØšØ±Ø§Û Ù
+Ø«Ø§Ù
+Ø§ÛÙØ¯Ú©Ø³ ÙØ§Û ÙÙÛØ³ÙØ¯Ù ÛØ§ Ø¹ÙÙØ§Ù . ÛØ§ ØŽØ§ÛØ¯ ÙØµÙ Ù ÙŸØ§Ø±Ø§Ú¯Ø±Ø§Ù . Ù
+Ø¹Ù
+ÙÙØ§ 
+Ù
+ØªÙ Ú©Ø§Ù
+ÙØ§ Ù
+Ø·Ø§ØšÙ ØšØ¯ÙÙ ØªÙØ¬Ù ØšÙ Ø§ÛÙØ¯Ú©Ø³ Ù
+ÙØ±Ø¯ ÙØžØ± ØŽÙ
+Ø§ ØšÙ Ø¯Ø³Øª Ù
+Û Ø¢ÛØ¯ .
+<p>Ø§Ú¯Ø± Ø§Ø³ÙØ§Ø¯ Ú©ØªØ§Øš ØšØ§ØŽÙØ¯ Ø¯Ø± Ù
+Ø­Ù Ù
+ÙØ§Ø³Øš ØšØ§Ø² Ø®ÙØ§ÙÙØ¯ ØŽØ¯.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/finnish.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/finnish.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/finnish.dm	(revision 10506)
@@ -0,0 +1,1295 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Finnish Language text and icon macros 
+# Many thanks to Steve Legrand (translated October 2003)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=fi] {Aikakausjulkaisut}
+_textsource_ [l=fi] {lÃ€hdeviite:}
+_textdate_ [l=fi] {julkaisupÃ€ivÃ€mÃ€Ã€rÃ€:}
+_textnumpages_ [l=fi] {sivumÃ€Ã€rÃ€:}
+
+_textsignin_ [l=fi] {kirjoittaudu sisÃ€Ã€n}
+
+_textdefaultcontent_ [l=fi] {Haettua sivua ei lÃ¶ytynyt. PÃ€Ã€set takaisin Greenstone digitaaliseen kirjastoon napsauttamalla selaajan 'Edellinen'-painiketta tai yllÃ€olevaa 'Alkuun'-painiketta.}
+
+_textdefaulttitle_ [l=fi] {GSDL virhe}
+
+_textbadcollection_ [l=fi] {TÃ€tÃ€ kokoelmaa (nimeltÃ€Ã€n "_cvariable_ ) ei ole asennettu Greenstone digitaaliseen kirjastosysteemiin.}
+
+_textselectpage_ [l=fi] {-- Valitse Sivu --}
+
+_collectionextra_ [l=fi] {TÃ€mÃ€ kokoelma sisÃ€ltÃ€Ã€ _about:numdocs_ dokumenttia.
+Kokoelmaa on viimeksi muokattu _about:builddate_.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=fi] {<p>TÃ€mÃ€ kokoelma sisÃ€ltÃ€Ã€ _numdocs_ _If_("_numdocs_" on "1", dokumenttia), yhteensÃ€  _numbytes_.
+<p><a href="_httppagex_(bsummary)">Napsauttamalla tÃ€hÃ€n hiirellÃ€</a> saat nÃ€kyviin koostetun yhteenvedon kokoelmasta.}
+
+_textimagecollection_ [l=fi] {}
+_textimageabout_ [l=fi] {Versiotiedot sivu}
+_textimagehome_ [l=fi] {Alkusivu}
+_textimagehelp_ [l=fi] {Ohje sivu}
+_textimagepref_ [l=fi] {Asetukset-sivu}
+_textimagegreenstone_ [l=fi] {Greenstone Digitaalinen Kirjasto -ohjelma}
+_textimageusab_ [l=fi] {MikÃ€ on mielestÃ€si vaikeakÃ€yttÃ¶istÃ€?}
+
+_textimagesearch_ [l=fi] {Erikoistermien haku}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=fi] {Selaa nimikkeitÃ€ aakkosittain}
+_textimageCreator_ [l=fi] {Selaa tekijÃ¶itÃ€ aakkosittain}
+_textimageSubject_ [l=fi] {Selaa aihealueittain}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=fi] {Selaa pÃ€ivÃ€mÃ€Ã€rittÃ€in}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=fi] {Selaa alkuperÃ€isellÃ€ tiedostonimellÃ€}
+_textimageLanguage_ [l=fi] {Selaa kielen perusteella}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=fi] {Selaa organisaatioittain}
+_textimageKeyword_ [l=fi] {Selaa avainsanoittain}
+_textimageHowto_ [l=fi] {Selaa How to -luokkia}
+_textimageList_ [l=fi] {Selaa dokumenttiluetteloa}
+_textimageSeries_ [l=fi] {Selaa julkaisunumeroita}
+_textimageTo_ [l=fi] {Selaa kohteittain}
+_textimageFrom_ [l=fi] {Selaa lÃ€hdekentittÃ€in}
+_textimageTopic_ [l=fi] {Selaa erikoisaiheittain}
+_textimageBrowse_ [l=fi] {Selaa}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=fi] {Selaa henkilÃ¶itÃ€ aakkosittain}
+_textimageAcronym_ [l=fi] {Selaa akronyymejÃ€}
+_textimagePhrase_ [l=fi] {Selaa lausekkeita}
+_textimageArtist_ [l=fi] {Selaa taiteilijoita}
+_textimageVolume_ [l=fi] {Selaa volyymeittain}
+_textimageCountries_ [l=fi] {Selaa maitten nimiÃ€ kÃ€yttÃ€en}
+_textimageCaptions_ [l=fi] {Selaa kuvatekstejÃ€ kÃ€yttÃ€en}
+
+
+_texticontabsearchgreen_ [l=fi] {Haku}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=fi] {Nimikkeet A-Z}
+_texticontabCreatorgreen_ [l=fi] {TekijÃ€t A-Z}
+_texticontabSubjectgreen_ [l=fi] {Aiheet}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=fi] {PÃ€ivÃ€mÃ€Ã€rÃ€t}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=fi] {Tiedostonimet}
+_texticontabLanguagegreen_ [l=fi] {Kieli}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=fi] {Organisaatio}
+_texticontabKeywordgreen_ [l=fi] {Avainsanat}
+_texticontabhowgreen_ [l=fi] {How to}
+_texticontabseriesgreen_ [l=fi] {Sarjat}
+_texticontablistgreen_ [l=fi] {Listaus}
+_texticontabtogreen_ [l=fi] {Kohde}
+_texticontabfromgreen_ [l=fi] {LÃ€hde}
+_texticontabtopicgreen_ [l=fi] {Aihealueet}
+_texticontabbrwsegreen_ [l=fi] {Selaus}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=fi] {Selaa}
+_texticontabPeoplegreen_ [l=fi] {HenkilÃ¶t A-Z}
+_texticontabAcronymgreen_ [l=fi] {Akronyymit}
+_texticontabPhrasegreen_ [l=fi] {Lausekkeet}
+_texticontabArtistgreen_ [l=fi] {Taiteilijat}
+_texticontabVolumegreen_ [l=fi] {Volyymit}
+_texticontabCaptionsgreen_ [l=fi] {Selitteet}
+_texticontabCountriesgreen_ [l=fi] {Maat}
+
+_texticontext_ [l=fi] {Tarkastele dokumenttia}
+_texticonclosedbook_ [l=fi] {avaa tÃ€mÃ€ dokumentti ja tarkastele sen sisÃ€ltÃ¶Ã€}
+_texticonnext_ [l=fi] {seuraavaan osaan}
+_texticonprev_ [l=fi] {edelliseen osaan}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=fi] {Tarkastele MIDI dokumenttia}
+_texticonmsword_ [l=fi] {Tarkastele Microsoft Word dokumenttia}
+_texticonmp3_ [l=fi] {Tarkastele MP3 dokumenttia}
+_texticonpdf_ [l=fi] {Tarkastele PDF dokumenttia}
+_texticonps_ [l=fi] {Tarkastele PostScript dokumenttia}
+_texticonppt_ [l=fi] {Tarkastele PowerPoint dokumenttia}
+_texticonrtf_ [l=fi] {Tarkastele RTF dokumenttia}
+_texticonxls_ [l=fi] {Tarkastele Microsoft Excel dokumenttia}
+
+_page_ [l=fi] {sivu}
+_pages_ [l=fi] {sivua}
+# -- Missing translation: _of_
+_vol_ [l=fi] {Vol.}
+_num_ [l=fi] {No.}
+
+_textmonth00_ [l=fi] {}
+_textmonth01_ [l=fi] {Tammikuu}
+_textmonth02_ [l=fi] {Helmikuu}
+_textmonth03_ [l=fi] {Maaliskuu}
+_textmonth04_ [l=fi] {Huhtikuu}
+_textmonth05_ [l=fi] {Toukokuu}
+_textmonth06_ [l=fi] {KesÃ€kuu}
+_textmonth07_ [l=fi] {HeinÃ€kuu}
+_textmonth08_ [l=fi] {Elokuu}
+_textmonth09_ [l=fi] {Syyskuu}
+_textmonth10_ [l=fi] {Lokakuu}
+_textmonth11_ [l=fi] {Marraskuu}
+_textmonth12_ [l=fi] {Joulukuu}
+
+_textdocument_ [l=fi] {Dokumentti}
+_textsection_ [l=fi] {Osa}
+_textparagraph_ [l=fi] {Kappale}
+
+_magazines_ [l=fi] {Aikakauslehdet}
+
+_nzdlpagefooter_ [l=fi] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ALKU" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=fi] {_httpimg_/fi/chomeof.gif}
+_httpiconchomeon_ [l=fi] {_httpimg_/fi/chomeon.gif}
+
+## "OHJE" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=fi] {_httpimg_/fi/chelpof.gif}
+_httpiconchelpon_ [l=fi] {_httpimg_/fi/chelpon.gif}
+
+## "ASETUKSET" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=fi] {_httpimg_/fi/cprefof.gif}
+_httpiconcprefon_ [l=fi] {_httpimg_/fi/cprefon.gif}
+
+## "LÃHETÃ PALUTETTA" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=fi] {_httpimg_/fi/cusabof.gif}
+_httpiconcusabon_ [l=fi] {_httpimg_/fi/cusabon.gif}
+
+
+## "haku" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=fi] {_httpimg_/fi/tsrchgr.gif}
+_httpicontsrchof_ [l=fi] {_httpimg_/fi/tsrchof.gif}
+_httpicontsrchon_ [l=fi] {_httpimg_/fi/tsrchon.gif}
+_widthtsrchx_ [l=fi] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "nimikkeet a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=fi] {_httpimg_/fi/ttitlgr.gif}
+_httpiconttitleof_ [l=fi] {_httpimg_/fi/ttitlof.gif}
+_httpiconttitleon_ [l=fi] {_httpimg_/fi/ttitlon.gif}
+_widthttitlex_ [l=fi] {87}
+
+# Not true DC, kept for legacy reasons
+## "tekijÃ€t a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=fi] {_httpimg_/fi/tauthgr.gif}
+_httpicontcreatof_ [l=fi] {_httpimg_/fi/tauthof.gif}
+_httpicontcreaton_ [l=fi] {_httpimg_/fi/tauthon.gif}
+_widthtcreatx_ [l=fi] {110}
+
+## "aiheet" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=fi] {_httpimg_/fi/tsubjgr.gif}
+_httpicontsubjon_ [l=fi] {_httpimg_/fi/tsubjon.gif}
+_httpicontsubjof_ [l=fi] {_httpimg_/fi/tsubjof.gif}
+_widthtsubjx_ [l=fi] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "pÃ€ivÃ€mÃ€Ã€rÃ€t" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=fi] {_httpimg_/fi/tdategr.gif}
+_httpicontdateof_ [l=fi] {_httpimg_/fi/tdateof.gif}
+_httpicontdateon_ [l=fi] {_httpimg_/fi/tdateon.gif}
+_widthtdatex_ [l=fi] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "tiedostonimet" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=fi] {_httpimg_/fi/tsrcgr.gif}
+_httpicontsrcof_ [l=fi] {_httpimg_/fi/tsrcof.gif}
+_httpicontsrcon_ [l=fi] {_httpimg_/fi/tsrcon.gif}
+_widthtsrcx_ [l=fi] {87}
+
+## "kieli" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=fi] {_httpimg_/fi/tlanggr.gif}
+_httpicontlangon_ [l=fi] {_httpimg_/fi/tlangon.gif}
+_httpicontlangof_ [l=fi] {_httpimg_/fi/tlangof.gif}
+_widthtlangx_ [l=fi] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "sarjat" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=fi] {_httpimg_/fi/tsergr.gif}
+_httpicontserof_ [l=fi] {_httpimg_/fi/tserof.gif}
+_httpicontseron_ [l=fi] {_httpimg_/fi/tseron.gif}
+_widthtserx_ [l=fi] {87}
+
+## "kohde" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=fi] {_httpimg_/fi/ttogr.gif}
+_httpiconttoon_ [l=fi] {_httpimg_/fi/ttoon.gif}
+_httpiconttoof_ [l=fi] {_httpimg_/fi/ttoof.gif}
+_widthttox_ [l=fi] {87}
+
+## "lÃ€hde" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=fi] {_httpimg_/fi/tfromgr.gif}
+_httpicontfromon_ [l=fi] {_httpimg_/fi/tfromon.gif}
+_httpicontfromof_ [l=fi] {_httpimg_/fi/tfromof.gif}
+_widthtfromx_ [l=fi] {87}
+
+## "organisaatiot" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=fi] {_httpimg_/fi/torggr.gif}
+_httpicontorgon_ [l=fi] {_httpimg_/fi/torgon.gif}
+_httpicontorgof_ [l=fi] {_httpimg_/fi/torgof.gif}
+_widthtorgx_ [l=fi] {114}
+
+## "how to" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=fi] {_httpimg_/fi/thowgr.gif}
+_httpiconthowon_ [l=fi] {_httpimg_/fi/thowon.gif}
+_httpiconthowof_ [l=fi] {_httpimg_/fi/thowof.gif}
+_widththowx_ [l=fi] {87}
+
+## "aihealue" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=fi] {_httpimg_/fi/ttopicgr.gif}
+_httpiconttopicon_ [l=fi] {_httpimg_/fi/ttopicon.gif}
+_httpiconttopicof_ [l=fi] {_httpimg_/fi/ttopicof.gif}
+_widthttopicx_ [l=fi] {87}
+
+## "selaa" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=fi] {_httpimg_/fi/tbrwsegr.gif}
+_httpicontbrwseon_ [l=fi] {_httpimg_/fi/tbrwseon.gif}
+_httpicontbrwseof_ [l=fi] {_httpimg_/fi/tbrwseof.gif}
+_widthtbrwsex_ [l=fi] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "henkilÃ¶t" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=fi] {_httpimg_/fi/tpeopgr.gif}
+_httpicontpeopof_ [l=fi] {_httpimg_/fi/tpeopof.gif}
+_httpicontpeopon_ [l=fi] {_httpimg_/fi/tpeopon.gif}
+_widthtpeopx_ [l=fi] {97}
+
+## "akronyymi" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=fi] {_httpimg_/fi/tacrogr.gif}
+_httpicontacroof_ [l=fi] {_httpimg_/fi/tacroof.gif}
+_httpicontacroon_ [l=fi] {_httpimg_/fi/tacroon.gif}
+_widthtacrox_ [l=fi] {87}
+
+## "lausekkeet" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=fi] {_httpimg_/fi/tphrsegr.gif}
+_httpicontphrseof_ [l=fi] {_httpimg_/fi/tphrseof.gif}
+_httpicontphrseon_ [l=fi] {_httpimg_/fi/tphrseon.gif}
+_widthtphrsex_ [l=fi] {87}
+
+## "taiteilijat" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=fi] {_httpimg_/fi/tartstgr.gif}
+_httpicontartstof_ [l=fi] {_httpimg_/fi/tartstof.gif}
+_httpicontartston_ [l=fi] {_httpimg_/fi/tartston.gif}
+_widthtartstx_ [l=fi] {87}
+
+## "avainsanat" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=fi] {_httpimg_/fi/tkwgr.gif}
+_httpicontkwof_ [l=fi] {_httpimg_/fi/tkwof.gif}
+_httpicontkwon_ [l=fi] {_httpimg_/fi/tkwon.gif}
+_widthtkwx_ [l=fi] {87}
+
+## "volyymit" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=fi] {_httpimg_/fi/tvolgr.gif}
+_httpicontvolof_ [l=fi] {_httpimg_/fi/tvolof.gif}
+_httpicontvolon_ [l=fi] {_httpimg_/fi/tvolon.gif}
+_widthtvolx_ [l=fi] {87}
+
+## "selitteet" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=fi] {_httpimg_/fi/tcaptgr.gif}
+_httpicontcaptof_ [l=fi] {_httpimg_/fi/tcaptof.gif}
+_httpicontcapton_ [l=fi] {_httpimg_/fi/tcapton.gif}
+_widthtcaptx_ [l=fi] {87}
+
+## "maat" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=fi] {_httpimg_/fi/tcountgr.gif}
+_httpicontcountof_ [l=fi] {_httpimg_/fi/tcountof.gif}
+_httpicontcounton_ [l=fi] {_httpimg_/fi/tcounton.gif}
+_widthtcountx_ [l=fi] {87}
+
+## "ohje" ## green_title ## h_help ##
+_httpiconhhelp_ [l=fi] {_httpimg_/fi/h\_help.gif}
+_widthhhelp_ [l=fi] {200}
+_heighthhelp_ [l=fi] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=fi] {Tietoja tÃ€stÃ€ kokoelmasta}
+
+_textsubcols1_ [l=fi] {<p>TÃ€ydelliseen kokoelmaan sisÃ€ltyy _1_ osakokoelmaa. 
+TÃ€llÃ€ hetkellÃ€ ovat saatavissa:
+<blockquote>}
+
+_textsubcols2_ [l=fi] {</blockquote>
+Voit tarkistaa (ja muokata) niitÃ€ osakokoelmia, joita kÃ€ytÃ€t tÃ€llÃ€ hetkellÃ€ Asetukset-sivulla.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "YleistÃ€" ## green_title ## h_about ##
+_httpiconhabout_ [l=fi] {_httpimg_/fi/h\_about.gif}
+_widthhabout_ [l=fi] {200}
+_heighthabout_ [l=fi] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=fi] {Nimikkeet A-Z}
+_texticonhcreat_ [l=fi] {TekijÃ€t A-Z}
+_texticonhsubj_ [l=fi] {Aiheet}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=fi] {PÃ€ivÃ€mÃ€Ã€rÃ€t}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=fi] {Tiedostonimet}
+_texticonhlang_ [l=fi] {Kielet}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=fi] {Kohde}
+_texticonhfrom_ [l=fi] {LÃ€hde}
+_texticonhser_ [l=fi] {Sarjat}
+_texticonhhow_ [l=fi] {How to}
+_texticonhorg_ [l=fi] {Organisaatiot}
+_texticonhbrwse_ [l=fi] {Selaaminen}
+_texticonhbrows_ [l=fi] {Selaaminen}
+_texticonhpeople_ [l=fi] {HenkilÃ¶t A-Z}
+_texticonhacronym_ [l=fi] {Akronyymit}
+_texticonhphrases_ [l=fi] {Lausekkeet}
+_texticonhartist_ [l=fi] {Taiteilijat}
+_texticonhkw_ [l=fi] {Avainsanat}
+_texticonhvol_ [l=fi] {Volyymit}
+_texticonhcapt_ [l=fi] {Selitteet}
+_texticonhcount_ [l=fi] {Maat}
+
+_texticonopenbookshelf_ [l=fi] {sulje tÃ€mÃ€ kirjaston osa}
+_texticonclosedbookshelf_ [l=fi] {avaa tÃ€mÃ€ kirjaston osa ja tarkastele sen sisÃ€ltÃ¶Ã€}
+_texticonopenbook_ [l=fi] {sulje tÃ€mÃ€ kirja}
+_texticonclosedfolder_ [l=fi] {Avaa tÃ€mÃ€ kansio ja tarkastele sen sisÃ€ltÃ¶Ã€}
+_texticonclosedfolder2_ [l=fi] {avaa alaosasto:}
+_texticonopenfolder_ [l=fi] {sulje tÃ€mÃ€ kansio}
+_texticonopenfolder2_ [l=fi] {sulje alaosasto:}
+_texticonsmalltext_ [l=fi] {Tarkastele tekstin tÃ€tÃ€ osaa}
+_texticonsmalltext2_ [l=fi] {tarkastele tekstiÃ€:}
+_texticonpointer_ [l=fi] {nykyinen osa-alue}
+_texticondetach_ [l=fi] {Avaa tÃ€mÃ€ sivu uudessa ikkunassa}
+_texticonhighlight_ [l=fi] {Korosta hakutermejÃ€}
+_texticonnohighlight_ [l=fi] {ÃlÃ€ korosta hakutermejÃ€}
+_texticoncontracttoc_ [l=fi] {TiivistÃ€ sisÃ€llysluetteloa}
+_texticonexpandtoc_ [l=fi] {Laajenna sisÃ€llysluetteloa}
+_texticonexpandtext_ [l=fi] {NÃ€ytÃ€ koko teksti}
+_texticoncontracttext_ [l=fi] {NÃ€ytÃ€ teksti vain valitulle osalle}
+_texticonwarning_ [l=fi] {<b>Huom! </b>}
+_texticoncont_ [l=fi] {jatka?}
+
+_textltwarning_ [l=fi] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Jos laajennat tekstiÃ€ tÃ€ssÃ€ kohden, selaajan nÃ€yttÃ¶alueeseen tulee suuri mÃ€Ã€rÃ€ tietoja _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=fi] {sivulle}
+_textintro_ [l=fi] {<i>(johdanto)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "nimikkeet a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=fi] {_httpimg_/fi/h\_title.gif}
+_widthhtitle_ [l=fi] {200}
+_heighthtitle_ [l=fi] {57}
+
+# Not true DC, kept for legacy reasons
+## "tekijÃ€t a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=fi] {_httpimg_/fi/h\_auth.gif}
+_widthhcreat_ [l=fi] {200}
+_heighthcreat_ [l=fi] {57}
+
+## "aiheet" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=fi] {_httpimg_/fi/h\_subj.gif}
+_widthhsubj_ [l=fi] {200}
+_heighthsubj_ [l=fi] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "pÃ€ivÃ€mÃ€Ã€rÃ€t" ## green_title ## h_date ##
+_httpiconhdate_ [l=fi] {_httpimg_/fi/h\_date.gif}
+_widthhdate_ [l=fi] {200}
+_heighthdate_ [l=fi] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "tiedostonimet" ## green_title ## h_src ##
+_httpiconhsrc_ [l=fi] {_httpimg_/fi/h\_src.gif}
+_widthhsrc_ [l=fi] {200}
+_heighthsrc_ [l=fi] {57}
+
+## "kielet" ## green_title ## h_lang ##
+_httpiconhlang_ [l=fi] {_httpimg_/fi/h\_lang.gif}
+_widthhlang_ [l=fi] {200}
+_heighthlang_ [l=fi] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "kohde" ## green_title ## h_to ##
+_httpiconhto_ [l=fi] {_httpimg_/fi/h\_to.gif}
+_widthhto_ [l=fi] {200}
+_heighthto_ [l=fi] {57}
+
+## "lÃ€hde" ## green_title ## h_from ##
+_httpiconhfrom_ [l=fi] {_httpimg_/fi/h\_from.gif}
+_widthhfrom_ [l=fi] {200}
+_heighthfrom_ [l=fi] {57}
+
+## "sarjat" ## green_title ## h_ser ##
+_httpiconhser_ [l=fi] {_httpimg_/fi/h\_ser.gif}
+_widthhser_ [l=fi] {200}
+_heighthser_ [l=fi] {57}
+
+## "how to" ## green_title ## h_how ##
+_httpiconhhow_ [l=fi] {_httpimg_/fi/h\_how.gif}
+_widthhhow_ [l=fi] {200}
+_heighthhow_ [l=fi] {57}
+
+## "aihealueet" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=fi] {_httpimg_/fi/h\_topic.gif}
+_widthhtopic_ [l=fi] {200}
+_heighthtopic_ [l=fi] {57}
+
+## "organisaatio" ## green_title ## h_org ##
+_httpiconhorg_ [l=fi] {_httpimg_/fi/h\_org.gif}
+_widthhorg_ [l=fi] {250}
+_heighthorg_ [l=fi] {57}
+
+## "selaaminen" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=fi] {_httpimg_/fi/h\_brwse.gif}
+_widthhbrwse_ [l=fi] {200}
+_heighthbrwse_ [l=fi] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "henkilÃ¶t" ## green_title ## h_people ##
+_httpiconhpeople_ [l=fi] {_httpimg_/fi/h\_people.gif}
+_widthhpeople_ [l=fi] {200}
+_heighthpeople_ [l=fi] {57}
+
+## "akronyymit" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=fi] {_httpimg_/fi/h\_acro.gif}
+_widthhacronym_ [l=fi] {200}
+_heighthacronym_ [l=fi] {57}
+
+## "lausekkeet" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=fi] {_httpimg_/fi/h\_phrse.gif}
+_widthhphrse_ [l=fi] {200}
+_heighthphrse_ [l=fi] {57}
+
+## "taiteilijat" ## green_title ## h_artist ##
+_httpiconhartist_ [l=fi] {_httpimg_/fi/h\_artist.gif}
+_widthhartist_ [l=fi] {200}
+_heighthartist_ [l=fi] {57}
+
+## "avainsanat" ## green_title ## h_kw ##
+_httpiconhkw_ [l=fi] {_httpimg_/fi/h\_kw.gif}
+_widthhkw_ [l=fi] {200}
+_heighthkw_ [l=fi] {57}
+
+## "volyymit" ## green_title ## h_vol ##
+_httpiconhvol_ [l=fi] {_httpimg_/fi/h\_vol.gif}
+_widthhvol_ [l=fi] {200}
+_heighthvol_ [l=fi] {57}
+
+## "maat" ## green_title ## h_count ##
+_httpiconhcount_ [l=fi] {_httpimg_/fi/h\_count.gif}
+_widthhcount_ [l=fi] {200}
+_heighthcount_ [l=fi] {57}
+
+## "selitteet" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=fi] {_httpimg_/fi/h\_capt.gif}
+_widthhcapt_ [l=fi] {200}
+_heighthcapt_ [l=fi] {57}
+
+
+## "JATKA??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=fi] {_httpimg_/fi/contof.gif}
+_httpiconconton_ [l=fi] {_httpimg_/fi/conton.gif}
+
+## "LAAJENNA\nTEKSTIÃ" ## document_button ## eallt ##
+_httpiconealltof_ [l=fi] {_httpimg_/fi/ealltof.gif}
+_httpiconeallton_ [l=fi] {_httpimg_/fi/eallton.gif}
+
+## "TIIVISTÃ\nSISÃLTÃÃ" ## document_button ## econc ##
+_httpiconeconcof_ [l=fi] {_httpimg_/fi/econcof.gif}
+_httpiconeconcon_ [l=fi] {_httpimg_/fi/econcon.gif}
+
+## "UUTEEN\nIKKUNAAN" ## document_button ## edtch ##
+_httpiconedtchof_ [l=fi] {_httpimg_/fi/edtchof.gif}
+_httpiconedtchon_ [l=fi] {_httpimg_/fi/edtchon.gif}
+
+## "LAAJENNA\nSISÃLTÃÃ" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=fi] {_httpimg_/fi/eexpcof.gif}
+_httpiconeexpcon_ [l=fi] {_httpimg_/fi/eexpcon.gif}
+
+## "TIIVISTÃ\nTEKSTIÃ" ## document_button ## etsec ##
+_httpiconetsecof_ [l=fi] {_httpimg_/fi/etsecof.gif}
+_httpiconetsecon_ [l=fi] {_httpimg_/fi/etsecon.gif}
+
+## "KOROSTUS" ## document_button ## ehl ##
+_httpiconehlof_ [l=fi] {_httpimg_/fi/ehlof.gif}
+_httpiconehlon_ [l=fi] {_httpimg_/fi/ehlon.gif}
+
+## "EI\nKOROSTUSTA" ## document_button ## enhl ##
+_httpiconenhlof_ [l=fi] {_httpimg_/fi/enhlof.gif}
+_httpiconenhlon_ [l=fi] {_httpimg_/fi/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=fi] {_If_(_thislast_,antaa tuloksen _thisfirst_ - _thislast_ kyselylle: _cgiargq_,Kysely ei tÃ€smÃ€Ã€: _cgiargq_)}
+_textnoquerytitle_ [l=fi] {Hakusivu}
+
+_texticonthispage_ [l=fi] {haku}
+_textsome_ [l=fi] {joitain}
+_textall_ [l=fi] {kaikki}
+_textboolean_ [l=fi] {boolen logiikan mukainen}
+_textranked_ [l=fi] {asetettu jÃ€rjestykseen}
+_textnatural_ [l=fi] {luonnollinen}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=fi] {}
+_texticonsearchhistorybar_ [l=fi] {hakuhistoria}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=fi] {kÃ€ytÃ€ tÃ€tÃ€ kyselyÃ€}
+_textfreqmsg1_ [l=fi] {Sanojen lukumÃ€Ã€rÃ€: }
+_textpostprocess_ [l=fi] {_If_(_quotedquery_,<br><i>jÃ€lkikÃ€siteltynÃ€ lÃ¶ytÃ€Ã€ _quotedquery_:n</i>
+)}
+_textinvalidquery_ [l=fi] {VÃ€Ã€rÃ€ kyselysyntaksi}
+
+_textmorethan_ [l=fi] {EnemmÃ€n kuin}
+_textapprox_ [l=fi] {Noin}
+_textnodocs_ [l=fi] {YksikÃ€Ã€n dokumentti ei vastaa kyselyÃ€.}
+_text1doc_ [l=fi] {1 dokumentti vastaa kyselyÃ€.}
+_textlotsdocs_ [l=fi] {dokumenttia vastaa kyselyÃ€.}
+_textmatches_ [l=fi] {Tulokset }
+_textbeginsearch_ [l=fi] {Aloita Haku}
+_textrunquery_ [l=fi] {Suorita Kysely}
+_textclearform_ [l=fi] {TyhjennÃ€ lomake}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=fi] {Sana tai lause}
+_textinfield_ [l=fi] {... kentÃ€ssÃ€}
+_textfoldstem_ [l=fi] {(kokoerojen poisto, sanojen vartalot)}
+
+_textadvquery_ [l=fi] {Tai kirjoita kysely suoraan:}
+_textallfields_ [l=fi] {kaikki kentÃ€t}
+_texttextonly_ [l=fi] {vain tekstiÃ€}
+_textand_ [l=fi] {ja}
+_textor_ [l=fi] {tai}
+_textandnot_ [l=fi] {ja ei}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=fi] {Hae _indexselection_ _If_(_jselection_, _jselection_) _If_(_gselection_, _gselection_-tasolla) _If_(_nselection_, _nselection_ -kielellÃ€) jotka sisÃ€ltÃ€vÃ€t _querytypeselection_ sanoista}
+
+_textadvancedsearch_ [l=fi] {Hae _indexselection_ _If_(_jselection_, _jselection_) _If_(_gselection_, _gselection_-tasolla)_If_(_nselection_,  _nselection_-kielellÃ€) kÃ€yttÃ€mÃ€llÃ€ _querytypeselection_-kyselyÃ€}
+
+_textformsimplesearch_ [l=fi] {Hae _If_(_jselection_,_jselection_ )_If_(_gformselection_,_gformselection_-tasolla )_If_(_nselection_,in _nselection_-kielellÃ€ )_formquerytypeselection_}
+
+_textformadvancedsearch_ [l=fi] {Hae _If_(_jselection_,_jselection_ )_If_(_gformselection_, _gformselection_-tasolla )_If_(_nselection_, _nselection_-kielellÃ€ )ja nÃ€ytÃ€ tulokset _formquerytypeselection_-jÃ€rjestyksessÃ€.}
+
+
+_textnojsformwarning_ [l=fi] {Huom: JavascriptiÃ€ ei ole aktivoitu selaimessasi. <br>Aktivoimalla sen voit kÃ€yttÃ€Ã€ lomakehakua.}
+_textdatesearch_ [l=fi] {TÃ€stÃ€ kokoelmasta voidaan hakea dokumentteja tiettyjen pÃ€ivÃ€mÃ€Ã€rien sisÃ€ltÃ€ tai dokumentteja, jotka sisÃ€ltÃ€vÃ€t tietyn pÃ€ivÃ€mÃ€Ã€rÃ€n. TÃ€mÃ€ on hakuvaihtoehto.}
+_textstartdate_ [l=fi] {Aloitus (tai ainoa) pÃ€ivÃ€mÃ€Ã€rÃ€}
+_textenddate_ [l=fi] {Viimeinen pÃ€ivÃ€:}
+_textbc_ [l=fi] {eKr.}
+_textad_ [l=fi] {jKr.}
+_textexplaineras_ [l=fi] {jKr ja eKr vastaavat englanninkielisiÃ€ termejÃ€ A.D. ja B.C. NÃ€mÃ€ termit ovat kulttuurisidonnaisia ja merkitsevÃ€t suunnilleen "nykyistÃ€ aikakautta" ja "ennen nykyistÃ€ aikakautta".}
+
+_textstemon_ [l=fi] {(sanojen loppuja ei otettu huomioon)}
+
+_textsearchhistory_ [l=fi] {Hakuhistoria}
+
+#text macros for search history
+_textnohistory_ [l=fi] {Hakuhistoriaa ei ole.}
+_texthresult_ [l=fi] {tulos}
+_texthresults_ [l=fi] {tulokset}
+_texthallwords_ [l=fi] {kaikki sanat}
+_texthsomewords_ [l=fi] {jotkut sanat}
+_texthboolean_ [l=fi] {boolen logiikan mukainen}
+_texthranked_ [l=fi] {asetettu jÃ€rjestykseen}
+_texthcaseon_ [l=fi] {kirjainten kokojen tÃ€ytyy tÃ€smÃ€tÃ€}
+_texthcaseoff_ [l=fi] {kirjainten kokoerojen poisto}
+_texthstemon_ [l=fi] {vartaloidut sanat}
+_texthstemoff_ [l=fi] {sanat ilman vartaloa}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "haku" ## green_title ## h_search ##
+_httpiconhsearch_ [l=fi] {_httpimg_/fi/h\_search.gif}
+_widthhsearch_ [l=fi] {200}
+_heighthsearch_ [l=fi] {57}
+
+## "tulokset" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=fi] {_httpimg_/fi/qryresb.gif}
+_widthqryresb_ [l=fi] {_pagewidth_}
+_heightqryresb_ [l=fi] {17}
+
+## "historia" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=fi] {_httpimg_/fi/schhistb.gif}
+_widthsrchhistb_ [l=fi] {_pagewidth_}
+_heightsrchhistb_ [l=fi] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=fi] {Asetukset on tehty seuraavalla tavalla. ÃlÃ€ kÃ€ytÃ€ selaajasi
+"Edellinen"-painiketta - tÃ€mÃ€ poistaa asetukset! Sen sijaan, napsauta
+jotain ylÃ€puolella olevan kÃ€yttÃ¶palkin painikkeista.
+}
+_textsetprefs_ [l=fi] {voimassa olevat asetukset}
+_textsearchprefs_ [l=fi] {Haun asetukset}
+_textcollectionprefs_ [l=fi] {Kokoelman asetukset}
+_textpresentationprefs_ [l=fi] {Esityksen asetukset}
+_textpreferences_ [l=fi] {Asetukset}
+_textcasediffs_ [l=fi] {Kirjainten kokoerot}
+_textignorecase_ [l=fi] {Ã€lÃ€ ota huomioon kirjainten kokoeroja}
+_textmatchcase_ [l=fi] {isojen/pienten kirjaimien tÃ€ytyy tÃ€smÃ€tÃ€}
+_textwordends_ [l=fi] {Sanojen loput:}
+_textstem_ [l=fi] {Ã€lÃ€ ota huomioon sanojen loppuja}
+_textnostem_ [l=fi] {koko sanan tÃ€ytyy tÃ€smÃ€tÃ€}
+_textprefop_ [l=fi] {Palauta enintÃ€Ã€n _maxdocoption_ hakutulosta,  _hitsperpageoption_ sivua kohden.}
+_textextlink_ [l=fi] {Ulkopuolisten verkkosivujen kÃ€yttÃ¶:}
+_textintlink_ [l=fi] {LÃ€hdedokumenttien alkuperÃ€:}
+_textlanguage_ [l=fi] {KÃ€yttÃ¶liittymÃ€n kieli:}
+_textencoding_ [l=fi] {MerkintÃ€jÃ€rjestelmÃ€:}
+_textformat_ [l=fi] {KÃ€yttÃ¶liittymÃ€muoto:}
+_textall_ [l=fi] {kaikki}
+_textquerymode_ [l=fi] {Kyselymuoto:}
+_textsimplemode_ [l=fi] {yksinkertainen kyselymuoto}
+_textadvancedmode_ [l=fi] {edistynyt kyselykÃ€ytÃ€ntÃ¶ (mahdollistaa boolen logiikan mukaisen haun !-, &- ja | -operaattoreilla, ja sulkumerkkien kÃ€ytÃ¶n)}
+_textlinkinterm_ [l=fi] {vÃ€lisivun kautta}
+_textlinkdirect_ [l=fi] {mene sinne suoraan}
+_textdigitlib_ [l=fi] {digitaalinen kirjasto}
+_textweb_ [l=fi] {Internet-verkko}
+_textgraphical_ [l=fi] {Graafinen}
+_texttextual_ [l=fi] {Tekstuaalinen}
+_textcollectionoption_ [l=fi] {<p>
+Alikokoelmat sisÃ€ltÃ€vÃ€t:
+<br>}
+
+_textrelateddocdisplay_ [l=fi] {nÃ€ytÃ€ yhteenkuuluvat dokumentit}
+_textsearchhistory_ [l=fi] {Hakuhistoria:}
+_textnohistory_ [l=fi] {Ei hakuhistoriaa}
+_texthistorydisplay_ [l=fi] {nÃ€ytÃ€ _historynumrecords_ hakuhistoriatietuetta}
+_textnohistorydisplay_ [l=fi] {Ã€lÃ€ nÃ€ytÃ€ hakuhistoriaa}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=fi] {Lomakehaku:}
+_textplainsearch_ [l=fi] {Tavallinen haku:}
+_textqueryboxsize_ [l=fi] {Kyselyruudun koko:}
+_textregbox_ [l=fi] {tavallinen kyselyruutu}
+_textbigbox_ [l=fi] {iso kyselyruutu}
+_textformtype_ [l=fi] {Lomaketyyppi:}
+_textsimple_ [l=fi] {yksinkertainen}
+_textadvanced_ [l=fi] {edistynyt}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=fi] {kanssa}
+_textfields_ [l=fi] {kentÃ€t}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Asetukset" ## green_title ## h_pref ##
+_httpiconhpref_ [l=fi] {_httpimg_/fi/h\_pref.gif}
+_widthhpref_ [l=fi] {200}
+_heighthpref_ [l=fi] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=fi] {JÃ€rjestÃ€ dokumentit}
+_textalsoshowing_ [l=fi] {nÃ€kyvillÃ€ myÃ¶s}
+_textwith_ [l=fi] {enintÃ€Ã€n}
+_textdocsperpage_ [l=fi] {dokumenttia sivua kohden+B450}
+
+_textfilterby_ [l=fi] {Hae dokumentit jotka sisÃ€ltÃ€vÃ€t}
+_textall_ [l=fi] {kaikki}
+_textany_ [l=fi] {mikÃ€ tahansa}
+_textwords_ [l=fi] {sanoista}
+_textleaveblank_ [l=fi] {jÃ€ttÃ€mÃ€llÃ€ tÃ€mÃ€n ruudun tyhjÃ€ksi saat kaikki dokumentit}
+
+_browsebuttontext_ [l=fi] {"JÃ€rjestÃ€ dokumentit"}
+
+_nodata_ [l=fi] {<i>ei tietoja</i>}
+_docs_ [l=fi] {dokumentit}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=fi] {Ohje}
+_textSearchshort_ [l=fi] {hakemalla tiettyjÃ€ sanoja}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=fi] {hakemalla julkaisuja nimikkeiden perusteella}
+_textCreatorshort_ [l=fi] {hakemalla julkaisuja tekijÃ¶ittÃ€in}
+_textSubjectshort_ [l=fi] {hakemalla julkaisuja aiheittain}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=fi] {hakemalla julkaisuja pÃ€ivÃ€mÃ€Ã€rittÃ€in}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=fi] {hakemalla julkaisuja tiedostonimien perusteella}
+_textLanguageshort_ [l=fi] {hakemalla julkaisuja kielilajituksen avulla}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=fi] {hakemalla julkaisuja sarjoittain}
+_textToshort_ [l=fi] {hakemalla julkaisuja Kohde-kenttien avulla}
+_textFromshort_ [l=fi] {hakemalla julkaisuja lÃ€hteittÃ€in}
+_textBrowseshort_ [l=fi] {selaa julkaisuja}
+_textOrganizationshort_ [l=fi] {hakemalla julkaisuja organisaatioden avulla}
+_textHowtoshort_ [l=fi] {hakemalla julkaisuja "How to"-luettelon avulla}
+_textTopicshort_ [l=fi] {hakemalla julkaisuja aihealueittain}
+_textPeopleshort_ [l=fi] {hakemalla julkaisuja henkilÃ¶iden nimien avulla}
+_textAcronymshort_ [l=fi] {hakemalla julkaisuja akronyymeittÃ€in}
+_textPhraseshort_ [l=fi] {selaa julkaisuissa esiintyviÃ€ lausekkeita}
+_textArtistshort_ [l=fi] {hakemalla julkaisuja taiteilijoittain}
+_textKeywordshort_ [l=fi] {hakemalla julkaisuja avainsanojen avulla}
+_textVolumeshort_ [l=fi] {hakemalla julkaisuja volyymien perusteella}
+_textCountriesshort_ [l=fi] {hakemalla julkaisuja maittain}
+_textdefaultshorttext_ [l=fi] {mÃ€Ã€rittelemÃ€tÃ¶n luokitus}
+
+_textSearchlong_ [l=fi] {<p><i>Hae tiettyjÃ€ sanoja, </i> jotka
+esiintyvÃ€t tekstissÃ€, "haku"-sivun avulla. TÃ€mÃ€ on se sivu, joka tulee nÃ€yttÃ¶Ã¶n,
+kun aloitat. Sivulle pÃ€Ã€see muilta sivuilta napsauttamalla
+ <i>haku</i>-painiketta.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=fi] {<p><i>Hae julkaisuja nimikkeiden avulla</i> 
+napsauttamalla <i>nimikkeet a-z</i>-painiketta  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n
+luettelon kirjoista aakkosjÃ€rjestyksessÃ€.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=fi] {<p><i>Hae julkaisuja tekijÃ¶iden nimien perusteella</i> 
+napsauttamalla <i>authors a-z</i>-painiketta  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n tekijÃ¶iden nimien avulla
+jÃ€rjestetyn luettelon kirjoista.  }
+
+_textSubjectlong_ [l=fi] {<p><i>Hae julkaisuja aiheittain</i> 
+napsauttamalla <i>aiheet</i>-painiketta.  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n
+kirjahyllyjen avulla esitettÃ€vÃ€n aiheluettelon. }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=fi] {<p><i>Hae julkaisuja pÃ€ivÃ€mÃ€Ã€rien avulla</i> napsauttamalla
+ <i>dates</i>-painiketta.  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n luettelon kaikista aiheista aikajÃ€rjestyksessÃ€.  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=fi] {<p><i>Hae julkaisuja tiedostonimien perusteella</i> 
+napsauttamalla <i>filenames</i>-painiketta  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n
+alkuperÃ€isiin tiedostonimiin perustuvan lajittelun..  }
+
+_textLanguagelong_ [l=fi] {<p><i>Hae julkaisuja kielten perusteella</i> 
+napsauttamalla <i>languages</i>-painiketta  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n
+kieliin perustuvan lajittelun.  }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=fi] {<p><i>Hae julkaisuja organisaatioiden
+perusteella</i> napsauttamalla <i>organisaatiot</i>-painiketta. 
+TÃ€mÃ€ tue nÃ€yttÃ¶Ã¶n organisaatioihin perustuvan luettelon.  }
+
+_textHowtolong_ [l=fi] {<p><i>Hae julkaisuja "How to"-luettelon avulla</i>
+napsauttamalla <i>how to</i>-painiketta.  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n
+luettelon How to -ohjeista.  }
+
+_textTopiclong_ [l=fi] {<p><i>Hae julkaisuja aihealueittain</i> 
+napsauttamalla <i>topic</i>-painiketta.  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n
+selattavaksi aihealueet.  }
+
+_textTolong_ [l=fi] {<p><i>Hae julkaisuja Kohde-kentÃ€n avulla</i> 
+napsauttamalla <i>to</i>-painiketta  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n kohteiden osoitteisiin perustuvan listan.  }
+
+_textFromlong_ [l=fi] {<p><i>Hae julkaisuja LÃ€hteen avulla</i> 
+napsauttamalla <i>from</i>-painiketta.  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n luettelon lÃ€hettÃ€jistÃ€.  }
+
+_textSerieslong_ [l=fi] {<p><i>Hae julkaisuja sarjojen perusteella</i> 
+napsauttamalla <i>series</i>-painiketta.  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n sarjat,
+jotka ovat kokoelmassa.  }
+
+_textBrowselong_ [l=fi] {<p><i>Selaa julkaisuja</i> napsauttamalla
+<i>browse</i>-painiketta.  }
+
+_textPeoplelong_ [l=fi] {<p><i>Hae eri henkilÃ¶iden julkaisuja</i> 
+napsauttamalla <i>people a-z</i>-painiketta.  
+TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n sukunimiin perustuvan lajittelun. }
+
+_textAcronymlong_ [l=fi] {<p><i>Hae julkaisuja akronyymien avulla</i> napsauttamalla<i>acronyms</i>-painiketta.  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n luettelon akronyymeistÃ€
+ja niiden esiintymispaikoista.  }
+
+_textPhraselong_ [l=fi] {<p><i>Selaa julkaisuissa esiintyviÃ€ lausekkeita</i>
+napsauttamalla <i>phrases</i>-painiketta. TehtÃ€vÃ€Ã€n kÃ€ytetÃ€Ã€n phind-lausekeselainta. }
+
+_textArtistlong_ [l=fi] {<p><i>Hae julkaisuja taiteilijoiden nimien perusteella</i> 
+napsauttamalla <i>taiteilijat</i>-painiketta  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n
+taiteilijoittain jÃ€rjestetyn luettelon.  }
+
+_textKeywordlong_ [l=fi] {<p><i>Hae julkaisuja avainsanojen avulla</i> 
+napsauttamalla <i>keywords</i>-painiketta.  TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n luettelon avainsanoista. }
+
+_textVolumelong_ [l=fi] {<p><i>Hae julkaisuja volyymien perusteella</i> 
+napsauttamalla <i>volumes</i>-painiketta TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n volyymiluettelon. }
+
+_textCaptionslong_ [l=fi] {<p><i>Hae julkaisuja selitteiden avulla</i> napsauttamalla
+<i>captions</i>-painiketta. TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n luettelon selitteistÃ€. }
+
+_textCountrieslong_ [l=fi] {<p><i>Hae julkaisuja maittain</i> napsauttamalla
+<i>countries</i>-painiketta. TÃ€mÃ€ tuo nÃ€yttÃ¶Ã¶n luettelon maista. }
+
+
+_textdefaultlongtext_ [l=fi] {<p>Napsauttamalla <i>unknown</i>-painiketta voit
+selata julkaisuja (tuntemattoman kentÃ€n perusteella).  }
+
+_texthelptopics_ [l=fi] {<h2 align=left>Aihealueet</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Kuinka haetaan tietyllÃ€  sanalla</a>
+<ul>
+  <li><a href="\#query-terms">Hakutermit</a>
+  <li><a href="\#query-type">Kyselytyyppi</a>
+  <li><a href="\#scope-of-queries">Kyselyn laajuus</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Kokoelman asetukset</a>
+  <li><a href="\#lang-prefs">Kielen asetukset</a>
+  <li><a href="\#pres-prefs">Esityksen asetukset</a>
+  <li><a href="\#search-prefs">Haun asetukset</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=fi] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=fi] {Miten dokumentteja luetaan}
+
+_texthelpreadingdocs_ [l=fi] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>TiedÃ€t, minkÃ€ kirjan tai dokumentin kohdalla kulloinkin olet, 
+tarkastelemalla sivun vasenta ylÃ€laitaa, missÃ€ kirjan tai dokumentin
+nimen tai sen kansilehden kuvan pitÃ€isi nÃ€kyÃ€. Joissakin kokoelmissa
+on vain sisÃ€llysluettelo, kun taas joissakin nÃ€kyy  sivunumero,
+jonka viereisen ruudun avulla voit valita uuden sivun eteen- tai taakse pÃ€in.
+Valitun osan otsake on lihavoitu sisÃ€llysluettelossa, jota voi laajentaa:
+voit avata ja sulkea kansioita niitÃ€ napsauttamalla, voit myÃ¶s sulkea
+avatun kirjan napsauttamalla sen ylÃ€osaan.</p>
+
+<p>Alapuolella on valitun osan teksti. Kun olet sen lukenut, 
+pÃ€Ã€set seuraavaan tai edelliseen osaan kÃ€yttÃ€mÃ€llÃ€ alalaidassa olevia nuolia.</p>
+
+<p> Kirjan tai dokumentin nimen tai sen kansilehden kuvan alapuolella
+on joitain painikkeita. Voit laajentaa valitun osan koko tekstin tai kirjan
+napsauttamalla <i>laajenna tekstiÃ€</i> painiketta. Jos dokumentti on suuri, 
+voi aikaa ja muistia kulua paljon. Saat osien otsakkeet ja aliosat nÃ€yttÃ¶Ã¶n, 
+kun laajennat koko sisÃ€llysluetteloa napsauttamalla <i>tiivistÃ€ tekstiÃ€</i>
+-painiketta. Uuden dokumentin selainikkunan saat esiin napsauttamalla
+<i>uuteen ikkunaan</i>-painiketta. (TÃ€stÃ€ on hyÃ¶tyÃ€ dokumentteja vertailtaessa
+tai kahta dokumenttia yhtaikaa luettaessa.) Lopuksi, suoritettuasi sanahaun, 
+sanat, joita hait, nÃ€kyvÃ€t korostettuina. Voit hÃ€vittÃ€Ã€ korostuksen 
+halutessasi napsauttamalla <i>ei korostusta</i>-painiketta.</p>
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Avaa tÃ€mÃ€ kirjahylly</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Avaa/sulje tÃ€mÃ€ kirja</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>Tarkastele tÃ€tÃ€ tekstin osaa</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>NÃ€ytÃ€ koko teksti?</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Laajenna sisÃ€llysluetteloa?</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Avaa tÃ€mÃ€ sivu uudessa ikkunassa</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Korosta hakutermejÃ€?</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Seuraavaan osaan nuolta napsauttamalla ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>...tai takaisin edelliseen osaan</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=fi] {<h2>Miten haetaan tiettyjÃ€ sanoja?</h2>
+<p>
+  Haun tekeminen hakusivulta onnistuu helposti seuraavin toimenpitein:<p>
+  
+  <ol><li>MÃ€Ã€rittele haun kohteet
+      <li>Kerro, haluatko etsiÃ€ kaikilla sanoilla vai vain joillakin niistÃ€
+      <li>Kirjoita sanat, joilla haluat suorittaa haun
+      <li>Napsauta <i>Aloita Haku</i>-painiketta
+  </ol>
+
+<p>Kun suoritat haun, kahdenkymmenen tÃ€smÃ€Ã€vÃ€n dokumentin nimet tulevat
+nÃ€yttÃ¶Ã¶n. Seuraavat kaksikymmentÃ€ dokumenttia saat esiin alapuolella olevan
+painikkeen avulla. EdettyÃ€si lÃ¶ydÃ€t painikkeet kahdellekymmenelle
+dokumentille sekÃ€ eteen ettÃ€ taaksepÃ€in. Dokumentin saat nÃ€yttÃ¶Ã¶n
+napsauttamalla dokumentin nimeÃ€ tai sen vieressÃ€ olevaa pientÃ€ painiketta.
+
+<p>Palautettujen dokumenttien mÃ€Ã€rÃ€ on rajoitettu sataan. Voit muuttaa tÃ€tÃ€
+  lukua napsauttamalla <i>asetukset</i>-painiketta sivun ylÃ€reunassa.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Hakutermit</h3>
+
+<p>"Hakutermeiksi" tulkitaan kaikki ne termit, mitkÃ€ kirjoitat ruutuun.}
+
+_textdatesearch_ [l=fi] {Haku pÃ€ivÃ€mÃ€Ã€rien perusteella}
+
+_texthelpdatesearch_ [l=fi] {<h2>_textdatesearch_</h2>
+PÃ€ivÃ€mÃ€Ã€rÃ€haun avulla voit etsiÃ€ dokumentteja, jotka vastaavat hakutermejÃ€
+ja kÃ€sittelevÃ€t tapahtumia tietyn ajanjakson ajalta. Voit hakea dokumentteja
+tietyltÃ€ vuodelta tai tiettyjen vuosien jaksolta. Et kuitenkaan vÃ€lttÃ€mÃ€ttÃ€ tarvitse
+hakutermejÃ€ - voit hakea pelkÃ€stÃ€Ã€n pÃ€ivÃ€mÃ€Ã€rien avulla; jos taas et kÃ€ytÃ€ 
+pÃ€ivÃ€mÃ€Ã€riÃ€, pÃ€ivÃ€mÃ€Ã€rÃ€haku ei aktivoidu.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>PÃ€ivÃ€mÃ€Ã€rÃ€haun kÃ€yttÃ¶tapa:</h3>
+<ul>
+   <li>Tiettyyn vuoteen keskittyvien dokumenttien haku:<p>
+   <ul>
+       <li>Kirjoita hakutermit tavalliseen tapaan.
+       <li>NÃ€ppÃ€ile haluamasi vuosi "Aloitus (tai ainoa) pÃ€ivÃ€mÃ€Ã€rÃ€" ruutuun.
+       <li>Jos pÃ€ivÃ€mÃ€Ã€rÃ€ on ennen nykyisen ajanlaskun alkua (eKr), 
+             valitse "eKr" vaihtoehto ruudun viereisestÃ€ pudotusvalikosta.
+       <li>Aloita haku tavalliseen tapaan.
+   </ul>
+<p><li>Dokumenttien haku useiden vuosien jaksolta:<p>
+   <ul>
+       <li>Kirjoita hakutermit tavalliseen tapaan.
+       <li>NÃ€ppÃ€ile aloituspÃ€ivÃ€mÃ€Ã€rÃ€ "Aloitus (tai ainoa) pÃ€ivÃ€mÃ€Ã€rÃ€" -ruutuun.
+       <li>NÃ€ppÃ€ile pÃ€Ã€ttymispÃ€ivÃ€mÃ€Ã€rÃ€ "Viimeinen pÃ€ivÃ€mÃ€Ã€rÃ€" -ruutuun
+       <li>Jos pÃ€ivÃ€mÃ€Ã€rÃ€ on ennen nykyisen ajanlaskun alkua (eKr), 
+             valitse "eKr" vaihtoehto ruudun viereisestÃ€ pudotusvalikosta.
+       <li>Aloita haku tavalliseen tapaan.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>The way results of your search work</h3>
+
+Yleisesti ottaen esimerkiksi vuoteen 1903 keskittyvÃ€ dokumenttihaku ei palauta vuonna 1903 kirjoitettuihin hakuteoksiin viittaavia dokumentteja, vaan  tÃ€hÃ€n vuoteen liittyviÃ€ dokumentteja vuoden molemmin puolin. Toisin sanoen, dokumentit voivat olla vaikkapa vuosijaksolta 1899-1911 ja sisÃ€ltÃ€vÃ€t vuoden 1903. Mutta on huomattava, ettÃ€ myÃ¶s dokumentit, joiden tekstissÃ€ esiintyy se vuosisata, johon vuosi 1903 kuuluu (esimerkiksi 20. vuosisata tai kahdeskymmenes vuosisata) tulevat haetuksi. TÃ€mÃ€ merkitsee sitÃ€, ettÃ€ joissakin palautetuissa dokumenteissa ei hakupÃ€ivÃ€mÃ€Ã€rÃ€Ã€ esiinny. Hauissa, joissa keskitytÃ€Ã€n useiden vuosien jaksoon, kaikki pÃ€ivÃ€mÃ€Ã€rÃ€t kÃ€sitellÃ€Ã€n yllÃ€kuvatun prosessin mukaisesti.
+<p>
+}
+
+_textchangeprefs_ [l=fi] {Asetusten vaihto}
+
+_texthelppreferences_ [l=fi] {<h2>_textchangeprefs_</h2>
+
+<p>Napsauttamalla <i>asetukset</i>-painiketta sivun ylÃ€osassa
+voit muokata joitain kÃ€yttÃ¶liittymÃ€n ominaisuuksia tarkoitukseesi sopivaksi.
+ 
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Kokoelman asetukset</h3>
+
+Jotkut kokoelmat koostuvat useista osakokoelmista, joihin haku voidaan
+kohdistaa kuhunkin erikseen tai jotka voidaan kÃ€sitellÃ€ yhtenÃ€ kokonaisuutena.
+TÃ€llaisissa tapauksissa, kÃ€yttÃ€mÃ€llÃ€ Asetukset-sivua, voit valita ne osakokoelmat, jotka haluat sisÃ€llyttÃ€Ã€
+haun piiriin.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Kielen asetukset</h3>
+
+Jokaisella kokoelmalla on oma esityskielensÃ€ oletuksena, mutta voit vaihtaa
+kieltÃ€ halutessasi. Voit myÃ¶s muuttaa Greenstonen kÃ€yttÃ€mÃ€Ã€ merkintÃ€jÃ€rjestelmÃ€Ã€
+selainta varten -- ohjelmisto valitsee jÃ€rkevÃ€ltÃ€ tuntuvat oletukset, mutta
+joidenkin selainten kohdalla niiden visuaalista esitystapaa voi parantaa
+kÃ€yttÃ€mÃ€llÃ€ jotain toista merkintÃ€jÃ€rjestelmÃ€Ã€. Kukin kokoelma voidaan
+esittÃ€Ã€ joko standardinmukaisen graafisen kÃ€yttÃ¶liittymÃ€formaatin avulla
+tai tekstinÃ€. NÃ€kÃ¶vammaisia ajatellen tÃ€mÃ€ on erittÃ€in hyÃ¶dyllinen piirre,  
+koska suurien nÃ€yttÃ¶jen fontteja ja puhesyntetisaattoreja voidaan tÃ€llÃ¶in kÃ€yttÃ€Ã€.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Esityksen asetukset</h3>
+
+Kokoelmasta riippuen, kÃ€ytettÃ€vissÃ€si voi olla useita vaihtoehtoja esityksen kontrolloimiseksi.
+
+<p>Internetin verkkosivukokoelmia kÃ€sitellessÃ€ voit hÃ€vittÃ€Ã€ Greenstone navigointipalkin
+dokumentin ylÃ€osasta: tÃ€llÃ¶in haun jÃ€lkeen pÃ€Ã€dyt hakemallesi sivulle,
+eikÃ€ Greenstone palkkia enÃ€Ã€ nÃ€y sillÃ€. Jos aiot suorittaa uuden haun tÃ€mÃ€n jÃ€lkeen,
+kÃ€ytÃ€ selaimen "Edellinen"-painiketta. Voit myÃ¶s poistaa varoitusviestin, jonka 
+Greenstone antaa aina, kun napsautat linkkiÃ€, joka ohjaa kÃ€yttÃ€jÃ€n digitaalisen
+kirjaston ulkopuoliseen internet-maailmaan. Joidenkin verkkosivukokoelmien
+kohdalla voit pÃ€Ã€ttÃ€Ã€, seuraatko "Haun Tulokset" -sivun linkkejÃ€ suoraan
+kyseenomaiseen URLiin, vai sen kopioon digitaalisessa kirjastossa.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Haun asetukset</h3>
+ <p>Tekstin mallihaussa kÃ€ytetÃ€Ã€n kahdenlaisia painikkeita: "Kirjainkoot"
+-painikkeita kÃ€ytetÃ€Ã€n isojen ja pienten kirjainten eroja ja "Sanojen pÃ€Ã€tteet" 
+-painikkeita sanojen pÃ€Ã€tteitÃ€ huomioonotettaessa. Voit myÃ¶s kÃ€yttÃ€Ã€
+suurta hakuruutua, mikÃ€ mahdollistaa jopa kappaleen laajuiset haut.
+Suurtenkin tekstikokonaisuuksien haku onnistuu hÃ€mmÃ€styttÃ€vÃ€n nopeasti.
+
+<p>Voit kÃ€yttÃ€Ã€ "edistyneempÃ€Ã€" hakumuotoa, jossa voit yhdistellÃ€ hakutermejÃ€
+loogisten operaattoreiden, AND (&), OR (|) ja NOT (!), avulla. NÃ€in saat
+tehtyÃ€ tarkempia hakuja. Voit myÃ¶s kÃ€yttÃ€Ã€ hakuhistoria-ominaisuutta, joka
+nÃ€yttÃ€Ã€ viimeisimmÃ€t suoritetut haut. TÃ€mÃ€n avulla on helppo muokata ja
+toistaa jo tehtyjÃ€ hakuja. On myÃ¶s mahdollista rajoittaa palautettujen hakutulosten
+mÃ€Ã€rÃ€Ã€, samoin kuin esitettÃ€vien hakutulosten mÃ€Ã€rÃ€Ã€.}
+
+_texttanumbrowseoptions_ [l=fi] {Tietoja tÃ€stÃ€ kokoelmasta voi hakea viidellÃ€ eri tavalla:}
+
+_textsimplehelpheading_ [l=fi] {Miten voit etsiÃ€ tietoja _collectionname_-kokoelmasta}
+
+_texthelpscope_ [l=fi] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Haun laajuus</h3>
+
+<p>Useimmissa kokoelmissa voit valita erilaisia hakuindeksejÃ€, esimerkiksi
+tekijÃ€nindeksin tai nimekeindeksin. Joissain tapauksissa myÃ¶s osa- ja
+kappaleindeksit tulevat kysymykseen. YleensÃ€ koko dokumentti palautetaan
+haun tuloksena, oli kÃ€ytetty indeksi mikÃ€ tahansa.
+<p>Jos dokumentit ovat kirjan muodossa, ne avataan sopivasta paikasta. 
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/french.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/french.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/french.dm	(revision 10506)
@@ -0,0 +1,1454 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# French Language text and icon macros 
+# Translated by UNESCO for the UNESCO CD-ROMs
+# Contributions made by Vincent Dubuc
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=fr] {PÃ©riodiques}
+_textsource_ [l=fr] {source: }
+_textdate_ [l=fr] {date de publication: }
+_textnumpages_ [l=fr] {nombre de pages: }
+
+_textsignin_ [l=fr] {se connecter}
+
+_textdefaultcontent_ [l=fr] {La page demandÃ©e n'a pu Ãªtre trouvÃ©e.
+Utilisez s'il-vous-plaÃ®t le bouton Â«RetourÂ» de votre navigateur, ou le
+bouton Â«AccueilÂ» pour retourner Ã  la BibliothÃšque NumÃ©rique Greenstone.}
+
+_textdefaulttitle_ [l=fr] {Erreur GSDL}
+
+_textbadcollection_ [l=fr] {Cette collection (appelÃ©e "_cvariable_") n'est pas installÃ©e sur ce systÃšme de bibliothÃšque numÃ©rique Greenstone}
+
+_textselectpage_ [l=fr] {-- SÃ©lectionner Page --}
+
+_collectionextra_ [l=fr] {Cette collection contient _about:numdocs_
+documents. Sa derniÃšre mise a jour a Ã©tÃ© faite il y a _about:builddate_
+jours.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=fr] {<p>Cette collection comprend _numdocs_ _If_("_numdocs_" eq
+"1",document,documents), pour un total de _numbytes_.
+<p><a href="_httppagex_(bsummary)">Cliquer ici</a> pour visualiser le
+rapport de construction de cette collection. 
+}
+
+_textimagecollection_ [l=fr] {}
+_textimageabout_ [l=fr] {Page Ã  propos}
+_textimagehome_ [l=fr] {Page d'accueil}
+_textimagehelp_ [l=fr] {Page d'aide}
+_textimagepref_ [l=fr] {Page de prÃ©fÃ©rences}
+_textimagegreenstone_ [l=fr] {Logiciel de BibliothÃšque NumÃ©rique Greenstone}
+_textimageusab_ [l=fr] {Qu'avez vous trouvÃ© difficile Ã  utiliser?}
+
+_textimagesearch_ [l=fr] {Recherche de termes spÃ©cifiques}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=fr] {Naviguer Ã  travers la liste alphabÃ©tique des titres}
+_textimageCreator_ [l=fr] {Naviguer Ã  travers la liste alphabÃ©tique des auteurs}
+_textimageSubject_ [l=fr] {Naviguer par catÃ©gorie de thÃšme}
+_textimageDescription_ [l=fr] {Recherche par description}
+_textimagePublisher_ [l=fr] {Recherche par Ã©diteur}
+_textimageContributor_ [l=fr] {Recherche par collaborateur}
+_textimageDate_ [l=fr] {Naviguer par dates}
+_textimageType_ [l=fr] {Recherche par type de ressource}
+_textimageFormat_ [l=fr] {Recherche par format}
+_textimageIdentifier_ [l=fr] {Recherche par identifiant de ressource}
+_textimageSource_ [l=fr] {Naviguer par noms de fichiers originaux}
+_textimageLanguage_ [l=fr] {Naviguer par langue}
+_textimageRelation_ [l=fr] {Recherche par rÃ©fÃ©rence}
+_textimageCoverage_ [l=fr] {Recherche par couverture}
+_textimageRights_ [l=fr] {Recherche par droits}
+
+_textimageOrganization_ [l=fr] {Naviguer par organisation}
+_textimageKeyword_ [l=fr] {Naviguer par mots-clefs}
+_textimageHowto_ [l=fr] {Naviguer en utilisant les rubriques Â«Comment faireÂ»}
+_textimageList_ [l=fr] {Naviguer Ã  travers la liste des documents}
+_textimageSeries_ [l=fr] {Naviguer Ã  travers les diffÃ©rentes publications}
+_textimageTo_ [l=fr] {Naviguer par champ Â«ÃÂ»}
+_textimageFrom_ [l=fr] {Naviguer par champ Â«DeÂ»}
+_textimageTopic_ [l=fr] {Naviguer en utilisant les Ã©ditions spÃ©ciales a thÃšme}
+_textimageBrowse_ [l=fr] {Naviguer}
+_textimageCollage_ [l=fr] {Naviguer par collage d'images}
+_textimagePeople_ [l=fr] {Naviguer par liste alphabÃ©tique de personnes}
+_textimageAcronym_ [l=fr] {Naviguer Ã  travers les acronymes}
+_textimagePhrase_ [l=fr] {Naviguer Ã  travers les groupes de mots}
+_textimageArtist_ [l=fr] {Naviguer Ã  travers les artistes}
+_textimageVolume_ [l=fr] {Naviguer par volume}
+_textimageCountries_ [l=fr] {Balayer par pays}
+_textimageCaptions_ [l=fr] {Parcourir par les lÃ©gendes de photos}
+
+
+_texticontabsearchgreen_ [l=fr] {Rechercher}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=fr] {Titres A-Z}
+_texticontabCreatorgreen_ [l=fr] {Auteurs A-Z}
+_texticontabSubjectgreen_ [l=fr] {ThÃšmes}
+_texticontabDescriptiongreen_ [l=fr] {Descriptions}
+_texticontabPublishergreen_ [l=fr] {Editeurs}
+_texticontabContributorgreen_ [l=fr] {Collaborateurs}
+_texticontabDategreen_ [l=fr] {Dates}
+_texticontabTypesgreen_ [l=fr] {Genres}
+_texticontabFormatgreen_ [l=fr] {Formats}
+_texticontabIdentifiergreen_ [l=fr] {Identifiants}
+_texticontabSourcegreen_ [l=fr] {Noms de fichiers}
+_texticontabLanguagegreen_ [l=fr] {Langue}
+_texticontabRelationgreen_ [l=fr] {RÃ©fÃ©rences}
+_texticontabCoveragegreen_ [l=fr] {Couvertures}
+_texticontabRightsgreen_ [l=fr] {Droits}
+
+_texticontaborggreen_ [l=fr] {Organisation}
+_texticontabKeywordgreen_ [l=fr] {Mots-clefs}
+_texticontabhowgreen_ [l=fr] {Comment faire}
+_texticontabseriesgreen_ [l=fr] {SÃ©ries}
+_texticontablistgreen_ [l=fr] {Listes}
+_texticontabtogreen_ [l=fr] {Ã}
+_texticontabfromgreen_ [l=fr] {De}
+_texticontabtopicgreen_ [l=fr] {ThÃšmes}
+_texticontabbrwsegreen_ [l=fr] {Naviguer}
+_texticontabCollagegreen_ [l=fr] {Collage}
+_texticontabbrowsgreen_ [l=fr] {Naviguer}
+_texticontabPeoplegreen_ [l=fr] {Personnes A-Z}
+_texticontabAcronymgreen_ [l=fr] {Acronymes}
+_texticontabPhrasegreen_ [l=fr] {Phrases}
+_texticontabArtistgreen_ [l=fr] {Artistes}
+_texticontabVolumegreen_ [l=fr] {Volumes}
+_texticontabCaptionsgreen_ [l=fr] {Sous-titres}
+_texticontabCountriesgreen_ [l=fr] {Pays}
+
+_texticontext_ [l=fr] {Afficher le document}
+_texticonclosedbook_ [l=fr] {ouvrir ce document et afficher son contenu}
+_texticonnext_ [l=fr] {vers la section suivante}
+_texticonprev_ [l=fr] {vers la section prÃ©cÃ©dente}
+
+_texticonworld_ [l=fr] {Voir le document Web}
+
+_texticonmidi_ [l=fr] {Voir le document au format MIDI}
+_texticonmsword_ [l=fr] {Voir le document au format Microsoft Word}
+_texticonmp3_ [l=fr] {Voir le document au format MP3}
+_texticonpdf_ [l=fr] {Voir le document au format PDF}
+_texticonps_ [l=fr] {Voir le document au format PostScript}
+_texticonppt_ [l=fr] {Voir le document au format PowerPoint}
+_texticonrtf_ [l=fr] {Voir le document au format RTF}
+_texticonxls_ [l=fr] {Voir le document au format Microsoft Excel}
+
+_page_ [l=fr] {page }
+_pages_ [l=fr] {pages}
+_of_ [l=fr] {sur }
+_vol_ [l=fr] {Volume }
+_num_ [l=fr] {numÃ©ro }
+
+_textmonth00_ [l=fr] {}
+_textmonth01_ [l=fr] {janvier}
+_textmonth02_ [l=fr] {fÃ©vrier}
+_textmonth03_ [l=fr] {mars}
+_textmonth04_ [l=fr] {avril}
+_textmonth05_ [l=fr] {mai}
+_textmonth06_ [l=fr] {juin}
+_textmonth07_ [l=fr] {juillet}
+_textmonth08_ [l=fr] {aoÃ»t}
+_textmonth09_ [l=fr] {septembre}
+_textmonth10_ [l=fr] {octobre}
+_textmonth11_ [l=fr] {novembre}
+_textmonth12_ [l=fr] {dÃ©cembre}
+
+_textdocument_ [l=fr] {Document}
+_textsection_ [l=fr] {Section}
+_textparagraph_ [l=fr] {Paragraphe}
+
+_magazines_ [l=fr] {Magazines}
+
+_nzdlpagefooter_ [l=fr] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">Projet de bibliothÃšque numÃ©rique de
+Nouvelle-ZÃ©lande</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">DÃ©partement d'informatique</a>, 
+<a href="http://www.waikato.ac.nz">UniversitÃ© de Waikato</a>, 
+Nouvelle-ZÃ©lande}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ACCUEIL" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=fr] {_httpimg_/fr/chomeof.gif}
+_httpiconchomeon_ [l=fr] {_httpimg_/fr/chomeon.gif}
+
+## "AIDE" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=fr] {_httpimg_/fr/chelpof.gif}
+_httpiconchelpon_ [l=fr] {_httpimg_/fr/chelpon.gif}
+
+## "PRÃFÃRENCES" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=fr] {_httpimg_/fr/cprefof.gif}
+_httpiconcprefon_ [l=fr] {_httpimg_/fr/cprefon.gif}
+
+## "ENVOYER FEEDBACK" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=fr] {_httpimg_/fr/cusabof.gif}
+_httpiconcusabon_ [l=fr] {_httpimg_/fr/cusabon.gif}
+
+
+## "recherche" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=fr] {_httpimg_/fr/tsrchgr.gif}
+_httpicontsrchof_ [l=fr] {_httpimg_/fr/tsrchof.gif}
+_httpicontsrchon_ [l=fr] {_httpimg_/fr/tsrchon.gif}
+_widthtsrchx_ [l=fr] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "titres a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=fr] {_httpimg_/fr/ttitlgr.gif}
+_httpiconttitleof_ [l=fr] {_httpimg_/fr/ttitlof.gif}
+_httpiconttitleon_ [l=fr] {_httpimg_/fr/ttitlon.gif}
+_widthttitlex_ [l=fr] {87}
+
+# Not true DC, kept for legacy reasons
+## "auteurs a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=fr] {_httpimg_/fr/tauthgr.gif}
+_httpicontcreatof_ [l=fr] {_httpimg_/fr/tauthof.gif}
+_httpicontcreaton_ [l=fr] {_httpimg_/fr/tauthon.gif}
+_widthtcreatx_ [l=fr] {87}
+
+## "thÃšmes" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=fr] {_httpimg_/fr/tsubjgr.gif}
+_httpicontsubjon_ [l=fr] {_httpimg_/fr/tsubjon.gif}
+_httpicontsubjof_ [l=fr] {_httpimg_/fr/tsubjof.gif}
+_widthtsubjx_ [l=fr] {87}
+
+## "Descriptions" ## nav_bar_button ## tdesc ##
+_httpicontdescgr_ [l=fr] {_httpimg_/fr/tdescgr.gif}
+_httpicontdescon_ [l=fr] {_httpimg_/fr/tdescon.gif}
+_httpicontdescof_ [l=fr] {_httpimg_/fr/tdescof.gif}
+_widthtdescx_ [l=fr] {90}
+
+## "Ãditeurs" ## nav_bar_button ## tpubl ##
+_httpicontpublgr_ [l=fr] {_httpimg_/fr/tpublgr.gif}
+_httpicontpublon_ [l=fr] {_httpimg_/fr/tpublon.gif}
+_httpicontpublof_ [l=fr] {_httpimg_/fr/tpublof.gif}
+_widthtpublx_ [l=fr] {87}
+
+## "Collaborateurs" ## nav_bar_button ## tcontr ##
+_httpicontcontrgr_ [l=fr] {_httpimg_/fr/tcontrgr.gif}
+_httpicontcontron_ [l=fr] {_httpimg_/fr/tcontron.gif}
+_httpicontcontrof_ [l=fr] {_httpimg_/fr/tcontrof.gif}
+_widthtcontrx_ [l=fr] {89}
+
+## "dates" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=fr] {_httpimg_/fr/tdategr.gif}
+_httpicontdateof_ [l=fr] {_httpimg_/fr/tdateof.gif}
+_httpicontdateon_ [l=fr] {_httpimg_/fr/tdateon.gif}
+_widthtdatex_ [l=fr] {87}
+
+## "Genres" ## nav_bar_button ## ttype ##
+_httpiconttypegr_ [l=fr] {_httpimg_/fr/ttypegr.gif}
+_httpiconttypeof_ [l=fr] {_httpimg_/fr/ttypeof.gif}
+_httpiconttypeon_ [l=fr] {_httpimg_/fr/ttypeon.gif}
+_widthttypex_ [l=fr] {87}
+
+## "Formats" ## nav_bar_button ## tform ##
+_httpicontformgr_ [l=fr] {_httpimg_/fr/tformgr.gif}
+_httpicontformof_ [l=fr] {_httpimg_/fr/tformof.gif}
+_httpicontformon_ [l=fr] {_httpimg_/fr/tformon.gif}
+_widthtformx_ [l=fr] {87}
+
+## "Identifiants" ## nav_bar_button ## tident ##
+_httpicontidentgr_ [l=fr] {_httpimg_/fr/tidentgr.gif}
+_httpicontidentof_ [l=fr] {_httpimg_/fr/tidentof.gif}
+_httpicontidenton_ [l=fr] {_httpimg_/fr/tidenton.gif}
+_widthtidentx_ [l=fr] {87}
+
+# Not true DC, kept for legacy reasons
+## "noms de fichiers" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=fr] {_httpimg_/fr/tsrcgr.gif}
+_httpicontsrcof_ [l=fr] {_httpimg_/fr/tsrcof.gif}
+_httpicontsrcon_ [l=fr] {_httpimg_/fr/tsrcon.gif}
+_widthtsrcx_ [l=fr] {87}
+
+## "langue" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=fr] {_httpimg_/fr/tlanggr.gif}
+_httpicontlangon_ [l=fr] {_httpimg_/fr/tlangon.gif}
+_httpicontlangof_ [l=fr] {_httpimg_/fr/tlangof.gif}
+_widthtlangx_ [l=fr] {87}
+
+## "RÃ©fÃ©rences" ## nav_bar_button ## trel ##
+_httpicontrelgr_ [l=fr] {_httpimg_/fr/trelgr.gif}
+_httpicontrelon_ [l=fr] {_httpimg_/fr/trelon.gif}
+_httpicontrelof_ [l=fr] {_httpimg_/fr/trelof.gif}
+_widthtrelx_ [l=fr] {87}
+
+## "Couverture" ## nav_bar_button ## tcover ##
+_httpicontcovergr_ [l=fr] {_httpimg_/fr/tcovergr.gif}
+_httpicontcoveron_ [l=fr] {_httpimg_/fr/tcoveron.gif}
+_httpicontcoverof_ [l=fr] {_httpimg_/fr/tcoverof.gif}
+_widthtcoverx_ [l=fr] {87}
+
+## "Droits" ## nav_bar_button ## tright ##
+_httpicontrightgr_ [l=fr] {_httpimg_/fr/trightgr.gif}
+_httpicontrighton_ [l=fr] {_httpimg_/fr/trighton.gif}
+_httpicontrightof_ [l=fr] {_httpimg_/fr/trightof.gif}
+_widthtrightx_ [l=fr] {87}
+
+
+
+## "sÃ©ries" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=fr] {_httpimg_/fr/tsergr.gif}
+_httpicontserof_ [l=fr] {_httpimg_/fr/tserof.gif}
+_httpicontseron_ [l=fr] {_httpimg_/fr/tseron.gif}
+_widthtserx_ [l=fr] {87}
+
+## "Ã " ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=fr] {_httpimg_/fr/ttogr.gif}
+_httpiconttoon_ [l=fr] {_httpimg_/fr/ttoon.gif}
+_httpiconttoof_ [l=fr] {_httpimg_/fr/ttoof.gif}
+_widthttox_ [l=fr] {87}
+
+## "de" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=fr] {_httpimg_/fr/tfromgr.gif}
+_httpicontfromon_ [l=fr] {_httpimg_/fr/tfromon.gif}
+_httpicontfromof_ [l=fr] {_httpimg_/fr/tfromof.gif}
+_widthtfromx_ [l=fr] {87}
+
+## "organisation" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=fr] {_httpimg_/fr/torggr.gif}
+_httpicontorgon_ [l=fr] {_httpimg_/fr/torgon.gif}
+_httpicontorgof_ [l=fr] {_httpimg_/fr/torgof.gif}
+_widthtorgx_ [l=fr] {98}
+
+## "comment faire" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=fr] {_httpimg_/fr/thowgr.gif}
+_httpiconthowon_ [l=fr] {_httpimg_/fr/thowon.gif}
+_httpiconthowof_ [l=fr] {_httpimg_/fr/thowof.gif}
+_widththowx_ [l=fr] {87}
+
+## "thÃšmes" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=fr] {_httpimg_/fr/ttopicgr.gif}
+_httpiconttopicon_ [l=fr] {_httpimg_/fr/ttopicon.gif}
+_httpiconttopicof_ [l=fr] {_httpimg_/fr/ttopicof.gif}
+_widthttopicx_ [l=fr] {87}
+
+## "naviguer" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=fr] {_httpimg_/fr/tbrwsegr.gif}
+_httpicontbrwseon_ [l=fr] {_httpimg_/fr/tbrwseon.gif}
+_httpicontbrwseof_ [l=fr] {_httpimg_/fr/tbrwseof.gif}
+_widthtbrwsex_ [l=fr] {87}
+
+## "collage" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=fr] {_httpimg_/fr/tcollgr.gif}
+_httpicontcollof_ [l=fr] {_httpimg_/fr/tcollof.gif}
+_httpicontcollon_ [l=fr] {_httpimg_/fr/tcollon.gif}
+_widthtcollx_ [l=fr] {87}
+
+## "personnes" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=fr] {_httpimg_/fr/tpeopgr.gif}
+_httpicontpeopof_ [l=fr] {_httpimg_/fr/tpeopof.gif}
+_httpicontpeopon_ [l=fr] {_httpimg_/fr/tpeopon.gif}
+_widthtpeopx_ [l=fr] {97}
+
+## "acronyme" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=fr] {_httpimg_/fr/tacrogr.gif}
+_httpicontacroof_ [l=fr] {_httpimg_/fr/tacroof.gif}
+_httpicontacroon_ [l=fr] {_httpimg_/fr/tacroon.gif}
+_widthtacrox_ [l=fr] {87}
+
+## "groupes de mots" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=fr] {_httpimg_/fr/tphrsegr.gif}
+_httpicontphrseof_ [l=fr] {_httpimg_/fr/tphrseof.gif}
+_httpicontphrseon_ [l=fr] {_httpimg_/fr/tphrseon.gif}
+_widthtphrsex_ [l=fr] {87}
+
+## "artistes" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=fr] {_httpimg_/fr/tartstgr.gif}
+_httpicontartstof_ [l=fr] {_httpimg_/fr/tartstof.gif}
+_httpicontartston_ [l=fr] {_httpimg_/fr/tartston.gif}
+_widthtartstx_ [l=fr] {87}
+
+## "mots-clefs" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=fr] {_httpimg_/fr/tkwgr.gif}
+_httpicontkwof_ [l=fr] {_httpimg_/fr/tkwof.gif}
+_httpicontkwon_ [l=fr] {_httpimg_/fr/tkwon.gif}
+_widthtkwx_ [l=fr] {87}
+
+## "volumes" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=fr] {_httpimg_/fr/tvolgr.gif}
+_httpicontvolof_ [l=fr] {_httpimg_/fr/tvolof.gif}
+_httpicontvolon_ [l=fr] {_httpimg_/fr/tvolon.gif}
+_widthtvolx_ [l=fr] {87}
+
+## "lÃ©gendes" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=fr] {_httpimg_/fr/tcaptgr.gif}
+_httpicontcaptof_ [l=fr] {_httpimg_/fr/tcaptof.gif}
+_httpicontcapton_ [l=fr] {_httpimg_/fr/tcapton.gif}
+_widthtcaptx_ [l=fr] {87}
+
+## "pays" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=fr] {_httpimg_/fr/tcountgr.gif}
+_httpicontcountof_ [l=fr] {_httpimg_/fr/tcountof.gif}
+_httpicontcounton_ [l=fr] {_httpimg_/fr/tcounton.gif}
+_widthtcountx_ [l=fr] {87}
+
+## "aide" ## green_title ## h_help ##
+_httpiconhhelp_ [l=fr] {_httpimg_/fr/h\_help.gif}
+_widthhhelp_ [l=fr] {200}
+_heighthhelp_ [l=fr] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=fr] {Ã propos de cette collection}
+
+_textsubcols1_ [l=fr] {<p>La collection comprend _1_ sous-collections au total:
+<blockquote>}
+
+_textsubcols2_ [l=fr] {</blockquote>
+Vous pouvez vÃ©rifier (et modifier) la collection que vous
+utilisez couramment en utilisant la page des prÃ©fÃ©rences.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Ã propos" ## green_title ## h_about ##
+_httpiconhabout_ [l=fr] {_httpimg_/fr/h\_about.gif}
+_widthhabout_ [l=fr] {200}
+_heighthabout_ [l=fr] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=fr] {Titres A-Z}
+_texticonhcreat_ [l=fr] {Auteurs A-Z}
+_texticonhsubj_ [l=fr] {ThÃšmes}
+_texticonhdesc_ [l=fr] {Descriptions}
+_texticonhpubl_ [l=fr] {Editeurs}
+_texticonhcontr_ [l=fr] {Collaborateurs}
+_texticonhdate_ [l=fr] {Dates}
+_texticonhtype_ [l=fr] {Genres}
+_texticonhform_ [l=fr] {Formats}
+_texticonhident_ [l=fr] {Identifiants}
+_texticonhsrc_ [l=fr] {Noms de fichiers}
+_texticonhlang_ [l=fr] {Langues}
+_texticonhrel_ [l=fr] {RÃ©fÃ©rences}
+_texticonhcover_ [l=fr] {Couverture}
+_texticonhright_ [l=fr] {Droits}
+
+_texticonhcoll_ [l=fr] {Collage}
+_texticonhto_ [l=fr] {Ã}
+_texticonhfrom_ [l=fr] {De}
+_texticonhser_ [l=fr] {SÃ©ries}
+_texticonhhow_ [l=fr] {Comment faire}
+_texticonhorg_ [l=fr] {Organisations}
+_texticonhbrwse_ [l=fr] {Naviguer}
+_texticonhbrows_ [l=fr] {Naviguer}
+_texticonhpeople_ [l=fr] {Personnes A-Z}
+_texticonhacronym_ [l=fr] {Acronymes}
+_texticonhphrases_ [l=fr] {Phrases}
+_texticonhartist_ [l=fr] {Artistes}
+_texticonhkw_ [l=fr] {Mots-clefs}
+_texticonhvol_ [l=fr] {Volumes}
+_texticonhcapt_ [l=fr] {LÃ©gendes}
+_texticonhcount_ [l=fr] {Pays}
+
+_texticonopenbookshelf_ [l=fr] {fermer cette partie de la bibliothÃšque}
+_texticonclosedbookshelf_ [l=fr] {ouvrir cette partie de la bibliothÃšque et afficher son contenu}
+_texticonopenbook_ [l=fr] {fermer ce livre}
+_texticonclosedfolder_ [l=fr] {ouvrir ce rÃ©pertoire et afficher son contenu}
+_texticonclosedfolder2_ [l=fr] {ouvrir la sous-partie: }
+_texticonopenfolder_ [l=fr] {fermer ce rÃ©pertoire}
+_texticonopenfolder2_ [l=fr] {fermer la sous-partie: }
+_texticonsmalltext_ [l=fr] {afficher cette portion de texte}
+_texticonsmalltext2_ [l=fr] {afficher le texte: }
+_texticonpointer_ [l=fr] {partie active}
+_texticondetach_ [l=fr] {Ouvrir cette page dans une nouvelle fenÃªtre}
+_texticonhighlight_ [l=fr] {Mettre en Ã©vidence les termes de recherche}
+_texticonnohighlight_ [l=fr] {Supprimer la mise en Ã©vidence des termes de recherche}
+_texticoncontracttoc_ [l=fr] {RÃ©duire la table des matiÃšres}
+_texticonexpandtoc_ [l=fr] {DÃ©velopper la table des matiÃšres}
+_texticonexpandtext_ [l=fr] {Afficher tout le texte}
+_texticoncontracttext_ [l=fr] {Afficher le texte uniquement pour la partie sÃ©lectionnÃ©e active}
+_texticonwarning_ [l=fr] {<b>Attention: </b>}
+_texticoncont_ [l=fr] {Souhaitez-vous continuer?}
+
+_textltwarning_ [l=fr] {<p><center>
+   <table cellspacing=0 cellpadding=0 width=_pagewidth_>
+    <tr valign=top><td>_iconwarning_ DÃ©velopper le texte 
+    Ã  ce niveau gÃ©nÃ©rera une importante quantitÃ© d'informations 
+    Ã  traiter par votre navigateur _imagecont_
+   </td></tr></table></center>
+}
+
+_textgoto_ [l=fr] {aller Ã  la page}
+_textintro_ [l=fr] {<i>(texte d'introduction)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "titres a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=fr] {_httpimg_/fr/h\_title.gif}
+_widthhtitle_ [l=fr] {200}
+_heighthtitle_ [l=fr] {57}
+
+# Not true DC, kept for legacy reasons
+## "auteurs a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=fr] {_httpimg_/fr/h\_auth.gif}
+_widthhcreat_ [l=fr] {200}
+_heighthcreat_ [l=fr] {57}
+
+## "thÃšmes" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=fr] {_httpimg_/fr/h\_subj.gif}
+_widthhsubj_ [l=fr] {200}
+_heighthsubj_ [l=fr] {57}
+
+## "Descriptions" ## green_title ## h_desc ##
+_httpiconhdesc_ [l=fr] {_httpimg_/fr/h\_desc.gif}
+_widthhdesc_ [l=fr] {200}
+_heighthdesc_ [l=fr] {57}
+
+## "Ãditeurs" ## green_title ## h_publ ##
+_httpiconhpubl_ [l=fr] {_httpimg_/fr/h\_publ.gif}
+_widthhpubl_ [l=fr] {200}
+_heighthpubl_ [l=fr] {57}
+
+## "Collaborateurs" ## green_title ## h_contr ##
+_httpiconhcontr_ [l=fr] {_httpimg_/fr/h\_contr.gif}
+_widthhcontr_ [l=fr] {200}
+_heighthcontr_ [l=fr] {57}
+
+## "dates" ## green_title ## h_date ##
+_httpiconhdate_ [l=fr] {_httpimg_/fr/h\_date.gif}
+_widthhdate_ [l=fr] {200}
+_heighthdate_ [l=fr] {57}
+
+## "Genres" ## green_title ## h_type ##
+_httpiconhtype_ [l=fr] {_httpimg_/fr/h\_type.gif}
+_widthhtype_ [l=fr] {200}
+_heighthtype_ [l=fr] {57}
+
+## "Formats" ## green_title ## h_form ##
+_httpiconhform_ [l=fr] {_httpimg_/fr/h\_form.gif}
+_widthhform_ [l=fr] {200}
+_heighthform_ [l=fr] {57}
+
+## "Identifiants" ## green_title ## h_ident ##
+_httpiconhident_ [l=fr] {_httpimg_/fr/h\_ident.gif}
+_widthhident_ [l=fr] {200}
+_heighthident_ [l=fr] {57}
+
+# Not true DC, kept for legacy reasons
+## "noms de fichiers" ## green_title ## h_src ##
+_httpiconhsrc_ [l=fr] {_httpimg_/fr/h\_src.gif}
+_widthhsrc_ [l=fr] {200}
+_heighthsrc_ [l=fr] {57}
+
+## "langues" ## green_title ## h_lang ##
+_httpiconhlang_ [l=fr] {_httpimg_/fr/h\_lang.gif}
+_widthhlang_ [l=fr] {200}
+_heighthlang_ [l=fr] {57}
+
+## "RÃ©fÃ©rences" ## green_title ## h_rel ##
+_httpiconhrel_ [l=fr] {_httpimg_/fr/h\_rel.gif}
+_widthhrel_ [l=fr] {200}
+_heighthrel_ [l=fr] {57}
+
+## "Couverture" ## green_title ## h_cover ##
+_httpiconhcover_ [l=fr] {_httpimg_/fr/h\_cover.gif}
+_widthhcover_ [l=fr] {200}
+_heighthcover_ [l=fr] {57}
+
+## "Droits" ## green_title ## h_right ##
+_httpiconhright_ [l=fr] {_httpimg_/fr/h\_right.gif}
+_widthhright_ [l=fr] {200}
+_heighthright_ [l=fr] {57}
+
+
+
+## "Ã " ## green_title ## h_to ##
+_httpiconhto_ [l=fr] {_httpimg_/fr/h\_to.gif}
+_widthhto_ [l=fr] {200}
+_heighthto_ [l=fr] {57}
+
+## "de" ## green_title ## h_from ##
+_httpiconhfrom_ [l=fr] {_httpimg_/fr/h\_from.gif}
+_widthhfrom_ [l=fr] {200}
+_heighthfrom_ [l=fr] {57}
+
+## "sÃ©ries" ## green_title ## h_ser ##
+_httpiconhser_ [l=fr] {_httpimg_/fr/h\_ser.gif}
+_widthhser_ [l=fr] {200}
+_heighthser_ [l=fr] {57}
+
+## "comment faire" ## green_title ## h_how ##
+_httpiconhhow_ [l=fr] {_httpimg_/fr/h\_how.gif}
+_widthhhow_ [l=fr] {200}
+_heighthhow_ [l=fr] {57}
+
+## "thÃšmes" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=fr] {_httpimg_/fr/h\_topic.gif}
+_widthhtopic_ [l=fr] {200}
+_heighthtopic_ [l=fr] {57}
+
+## "organisation" ## green_title ## h_org ##
+_httpiconhorg_ [l=fr] {_httpimg_/fr/h\_org.gif}
+_widthhorg_ [l=fr] {200}
+_heighthorg_ [l=fr] {57}
+
+## "naviguer" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=fr] {_httpimg_/fr/h\_brwse.gif}
+_widthhbrwse_ [l=fr] {200}
+_heighthbrwse_ [l=fr] {57}
+
+## "collage" ## green_title ## h_coll ##
+_httpiconhcoll_ [l=fr] {_httpimg_/fr/h\_coll.gif}
+_widthhcoll_ [l=fr] {200}
+_heighthcoll_ [l=fr] {57}
+
+## "personnes" ## green_title ## h_people ##
+_httpiconhpeople_ [l=fr] {_httpimg_/fr/h\_people.gif}
+_widthhpeople_ [l=fr] {200}
+_heighthpeople_ [l=fr] {57}
+
+## "acronymes" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=fr] {_httpimg_/fr/h\_acro.gif}
+_widthhacronym_ [l=fr] {200}
+_heighthacronym_ [l=fr] {57}
+
+## "groupes de mots" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=fr] {_httpimg_/fr/h\_phrse.gif}
+_widthhphrse_ [l=fr] {200}
+_heighthphrse_ [l=fr] {57}
+
+## "artistes" ## green_title ## h_artist ##
+_httpiconhartist_ [l=fr] {_httpimg_/fr/h\_artist.gif}
+_widthhartist_ [l=fr] {200}
+_heighthartist_ [l=fr] {57}
+
+## "mots-clefs" ## green_title ## h_kw ##
+_httpiconhkw_ [l=fr] {_httpimg_/fr/h\_kw.gif}
+_widthhkw_ [l=fr] {200}
+_heighthkw_ [l=fr] {57}
+
+## "volumes" ## green_title ## h_vol ##
+_httpiconhvol_ [l=fr] {_httpimg_/fr/h\_vol.gif}
+_widthhvol_ [l=fr] {200}
+_heighthvol_ [l=fr] {57}
+
+## "pays" ## green_title ## h_count ##
+_httpiconhcount_ [l=fr] {_httpimg_/fr/h\_count.gif}
+_widthhcount_ [l=fr] {200}
+_heighthcount_ [l=fr] {57}
+
+## "lÃ©gendes" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=fr] {_httpimg_/fr/h\_capt.gif}
+_widthhcapt_ [l=fr] {200}
+_heighthcapt_ [l=fr] {57}
+
+
+## "CONTINUER ??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=fr] {_httpimg_/fr/contof.gif}
+_httpiconconton_ [l=fr] {_httpimg_/fr/conton.gif}
+
+## "DÃVELOPPER\nLE TEXTE" ## document_button ## eallt ##
+_httpiconealltof_ [l=fr] {_httpimg_/fr/ealltof.gif}
+_httpiconeallton_ [l=fr] {_httpimg_/fr/eallton.gif}
+
+## "RÃDUIRE\nLE CONTENU" ## document_button ## econc ##
+_httpiconeconcof_ [l=fr] {_httpimg_/fr/econcof.gif}
+_httpiconeconcon_ [l=fr] {_httpimg_/fr/econcon.gif}
+
+## "DÃTACHER" ## document_button ## edtch ##
+_httpiconedtchof_ [l=fr] {_httpimg_/fr/edtchof.gif}
+_httpiconedtchon_ [l=fr] {_httpimg_/fr/edtchon.gif}
+
+## "DÃVELOPPER\nLE CONTENU" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=fr] {_httpimg_/fr/eexpcof.gif}
+_httpiconeexpcon_ [l=fr] {_httpimg_/fr/eexpcon.gif}
+
+## "RÃDUIRE\nLE TEXTE" ## document_button ## etsec ##
+_httpiconetsecof_ [l=fr] {_httpimg_/fr/etsecof.gif}
+_httpiconetsecon_ [l=fr] {_httpimg_/fr/etsecon.gif}
+
+## "METTRE EN\nÃVIDENCE" ## document_button ## ehl ##
+_httpiconehlof_ [l=fr] {_httpimg_/fr/ehlof.gif}
+_httpiconehlon_ [l=fr] {_httpimg_/fr/ehlon.gif}
+
+## "SUPPRIMER LA\nMISE EN ÃVIDENCE" ## document_button ## enhl ##
+_httpiconenhlof_ [l=fr] {_httpimg_/fr/enhlof.gif}
+_httpiconenhlon_ [l=fr] {_httpimg_/fr/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=fr] {_If_(_thislast_,resultats _thisfirst_ - _thislast_ pour la recherche: _cgiargq_,Pas de documents contenant: _cgiargq_)}
+_textnoquerytitle_ [l=fr] {Page de recherche}
+
+_texticonthispage_ [l=fr] {Recherche}
+_textsome_ [l=fr] {quelques uns des}
+_textall_ [l=fr] {tous les}
+_textboolean_ [l=fr] {booleen}
+_textranked_ [l=fr] {ranked}
+_textnatural_ [l=fr] {natural}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=fr] {}
+_texticonsearchhistorybar_ [l=fr] {historique de la recherche}
+
+_textifeellucky_ [l=fr] {Je me sent chanceux!}
+
+#alt text for query buttons
+_textusequery_ [l=fr] {utiliser cette requÃªte}
+_textfreqmsg1_ [l=fr] {Nombre de mots: }
+_textpostprocess_ [l=fr] {_If_(_quotedquery_,<br><i>post-traitÃ©s Ã  retrouver _quotedquery_</i>
+)}
+_textinvalidquery_ [l=fr] {Syntaxe de requÃªte invalide}
+
+_textmorethan_ [l=fr] {Plus de }
+_textapprox_ [l=fr] {Ã propos }
+_textnodocs_ [l=fr] {Aucun document ne satisfait la requÃªte.}
+_text1doc_ [l=fr] {1 document satisfait la requÃªte.}
+_textlotsdocs_ [l=fr] {documents satisfont la requÃªte.}
+_textmatches_ [l=fr] {RÃ©sultats }
+_textbeginsearch_ [l=fr] {DÃ©marrer la recherche}
+_textrunquery_ [l=fr] {ExÃ©cuter la requÃªte}
+_textclearform_ [l=fr] {Effacer le formulaire}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=fr] {Mot ou groupe de mots}
+_textinfield_ [l=fr] {... dans le champ}
+_textfoldstem_ [l=fr] {(casse, fin des mots)}
+
+_textadvquery_ [l=fr] {Ou tapez une requÃªte directement:}
+_textallfields_ [l=fr] {Tous les champs}
+_texttextonly_ [l=fr] {texte seulement
+}
+_textand_ [l=fr] {et}
+_textor_ [l=fr] {ou}
+_textandnot_ [l=fr] {et pas}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=fr] {Rechercher des _indexselection_ _If_(_jselection_, of _jselection_)_If_(_nselection_, in _nselection_ language) contenant _querytypeselection_ mots
+}
+
+_textadvancedsearch_ [l=fr] {Rechercher _indexselection_ _If_(_jselection_, of _jselection_)_If_(_nselection_, in _nselection_ language) en utilisant _querytypeselection_ requÃªte}
+
+_textformsimplesearch_ [l=fr] {Rechercher _If_(_jselection_, _jselection_) _If_(_gformselection_, at
+_gformselection_ level) _If_(_nselection_, in _nselection_ language)
+contenant _formquerytypeselection_}
+
+_textformadvancedsearch_ [l=fr] {Rechercher _If_(_jselection_,_jselection_)
+_If_(_gformselection_, at _gformselection_ level)_If_(_nselection_, in
+_nselection_ language) et afficher les rÃ©sultats dans l'ordre
+_formquerytypeselection_}
+
+
+_textnojsformwarning_ [l=fr] {Attention: Javascript est dÃ©sactivÃ© dans votre navigateur web. <br> Pour utiliser la recherche par formulaire, veuillez l'activer.}
+_textdatesearch_ [l=fr] {On peut effectuer des recherches de documents compris
+dans un certain intervalle de dates, ou des documents comprenant une
+date particuliÃšre. C'est une fonctionnalitÃ© facultative de la
+recherche.}
+_textstartdate_ [l=fr] {Date de dÃ©but (ou unique):}
+_textenddate_ [l=fr] {Date de fin:}
+_textbc_ [l=fr] {avant notre Ãšre}
+_textad_ [l=fr] {de notre Ãšre}
+_textexplaineras_ [l=fr] {Â«avant notre ÃšreÂ» et Â«de notre ÃšreÂ» sont une autre
+faÃ§on d'exprimer respectivement, Â«av. J.-C.Â» et Â«ap. J.-C.Â». Ce sont des
+termes moins marquÃ©s culturellement. }
+
+_textstemon_ [l=fr] {(ignorer la fin des mots)}
+
+_textsearchhistory_ [l=fr] {Recherche dans l'historique}
+
+#text macros for search history
+_textnohistory_ [l=fr] {Historique de recherche sans entrÃ©e
+}
+_texthresult_ [l=fr] {rÃ©sultat}
+_texthresults_ [l=fr] {rÃ©sultats}
+_texthallwords_ [l=fr] {tous les mots}
+_texthsomewords_ [l=fr] {quelques mots}
+_texthboolean_ [l=fr] {boolÃ©en}
+_texthranked_ [l=fr] {avec score}
+_texthcaseon_ [l=fr] {la casse doit correspondre}
+_texthcaseoff_ [l=fr] {ne pas tenir compte de la casse}
+_texthstemon_ [l=fr] {racines des mots}
+_texthstemoff_ [l=fr] {totalitÃ© des mots}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "recherche" ## green_title ## h_search ##
+_httpiconhsearch_ [l=fr] {_httpimg_/fr/h\_search.gif}
+_widthhsearch_ [l=fr] {200}
+_heighthsearch_ [l=fr] {57}
+
+## "rÃ©sultats" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=fr] {_httpimg_/fr/qryresb.gif}
+_widthqryresb_ [l=fr] {_pagewidth_}
+_heightqryresb_ [l=fr] {17}
+
+## "historique" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=fr] {_httpimg_/fr/schhistb.gif}
+_widthsrchhistb_ [l=fr] {_pagewidth_}
+_heightsrchhistb_ [l=fr] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=fr] {Les prÃ©fÃ©rences ont Ã©tÃ© appliquÃ©es comme suit. N'utilisez pas le bouton
+'PrÃ©cÃ©dent' de votre navigateur, sinon elles seront annulÃ©es. Utilisez plutÃŽt l'un des boutons
+de la barre d'accÃšs ci-dessus.}
+_textsetprefs_ [l=fr] {Appliquer}
+_textsearchprefs_ [l=fr] {PrÃ©fÃ©rences de recherche}
+_textcollectionprefs_ [l=fr] {PrÃ©fÃ©rences de collection}
+_textpresentationprefs_ [l=fr] {PrÃ©fÃ©rences de prÃ©sentation}
+_textpreferences_ [l=fr] {PrÃ©fÃ©rences}
+_textcasediffs_ [l=fr] {Respecter la casse:}
+_textignorecase_ [l=fr] {ignorer la casse}
+_textmatchcase_ [l=fr] {les majuscules et les minuscules doivent correspondre}
+_textwordends_ [l=fr] {La fin des mots:}
+_textstem_ [l=fr] {ignorer la fin des mots}
+_textnostem_ [l=fr] {le mot entier doit correspondre}
+_textprefop_ [l=fr] {Afficher jusqu'Ã  _maxdocoption_ rÃ©sultats avec _hitsperpageoption_ rÃ©sultats par page.}
+_textextlink_ [l=fr] {AccÃšs aux pages web externes: }
+_textintlink_ [l=fr] {Documents source rÃ©cupÃ©rÃ©s de:}
+_textlanguage_ [l=fr] {Langue de l'interface: }
+_textencoding_ [l=fr] {Encodage: }
+_textformat_ [l=fr] {Format de l'interface: }
+_textall_ [l=fr] {tous}
+_textquerymode_ [l=fr] {Mode de recherche:}
+_textsimplemode_ [l=fr] {mode de recherche simple}
+_textadvancedmode_ [l=fr] {mode de recherche avancÃ©e (autoriser les recherches boolÃ©ennes utilisant !, &, |, et les parenthÃšses)}
+_textlinkinterm_ [l=fr] {Ã  travers les pages intermÃ©diaires}
+_textlinkdirect_ [l=fr] {aller directement lÃ -bas}
+_textdigitlib_ [l=fr] {la bibliothÃšque numÃ©rique}
+_textweb_ [l=fr] {le web}
+_textgraphical_ [l=fr] {Graphique}
+_texttextual_ [l=fr] {Textuel}
+_textcollectionoption_ [l=fr] {<p>
+Sous-collections Ã  inclure:
+<br>}
+
+_textrelateddocdisplay_ [l=fr] {Affiche les documents proches}
+_textsearchhistory_ [l=fr] {Rechercher l'historique}
+_textnohistory_ [l=fr] {L'historique de recherche n'est pas disponible}
+_texthistorydisplay_ [l=fr] {Afficher les _historynumrecords_ derniÃšres requÃªtes}
+_textnohistorydisplay_ [l=fr] {Ne pas afficher l'historique }
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=fr] {Recherche par formulaire}
+_textplainsearch_ [l=fr] {Recherche simple}
+_textqueryboxsize_ [l=fr] {Champ de saisie:}
+_textregbox_ [l=fr] {Champ normal}
+_textbigbox_ [l=fr] {Champ Ã©tendu}
+_textformtype_ [l=fr] {Type de formulaires:}
+_textsimple_ [l=fr] {simple}
+_textadvanced_ [l=fr] {avancÃ©}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=fr] {avec}
+_textfields_ [l=fr] {champs}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "prÃ©fÃ©rences" ## green_title ## h_pref ##
+_httpiconhpref_ [l=fr] {_httpimg_/fr/h\_pref.gif}
+_widthhpref_ [l=fr] {200}
+_heighthpref_ [l=fr] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=fr] {Trier les documents par}
+_textalsoshowing_ [l=fr] {comprenant Ã©galement}
+_textwith_ [l=fr] {comprenant au plus}
+_textdocsperpage_ [l=fr] {documents par page}
+
+_textfilterby_ [l=fr] {Obtenir les documents contenant}
+_textall_ [l=fr] {tous les}
+_textany_ [l=fr] {certains des}
+_textwords_ [l=fr] {mots}
+_textleaveblank_ [l=fr] {laisser cette boÃ®te vide pour obtenir tous les documents}
+
+_browsebuttontext_ [l=fr] {"Trier les documents"}
+
+_nodata_ [l=fr] {<i>pas de donnÃ©es</i>}
+_docs_ [l=fr] {documents}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=fr] {Aide}
+_textSearchshort_ [l=fr] {Chercher certains mots en particulier}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=fr] {AccÃšs aux publications par titre}
+_textCreatorshort_ [l=fr] {AccÃšs aux publications par auteur}
+_textSubjectshort_ [l=fr] {AccÃšs aux publications par thÃšme}
+_textDescriptionshort_ [l=fr] {Acceder aux publications par description}
+_textPublishershort_ [l=fr] {acceder aux publications par Ã©diteur}
+_textContributorshort_ [l=fr] {Acceder aux publications par collaborateur}
+_textDateshort_ [l=fr] {AccÃšs aux publications par date}
+_textTypeshort_ [l=fr] {AccÃ©der aux publications par genre}
+_textFormatshort_ [l=fr] {acceder aux publications par format}
+_textIdentifiershort_ [l=fr] {acceder aux publications par identifiant}
+_textSourceshort_ [l=fr] {AccÃšs aux publications par nom de fichier}
+_textLanguageshort_ [l=fr] {AccÃšs aux publications par langue}
+_textRelationshort_ [l=fr] {acceder aux publications par rÃ©fÃ©rence}
+_textCoverageshort_ [l=fr] {acceder aux publications par couverture}
+_textRightsshort_ [l=fr] {acceder aux publications par droits}
+
+_textSeriesshort_ [l=fr] {AccÃšs aux publications par sÃ©rie}
+_textToshort_ [l=fr] {AccÃšs aux publications par champ Â«ÃÂ»}
+_textFromshort_ [l=fr] {AccÃšs aux publications par champ Â«DeÂ»}
+_textBrowseshort_ [l=fr] {Naviguer Ã  travers les publications}
+_textOrganizationshort_ [l=fr] {AccÃšs aux publications par organisation}
+_textHowtoshort_ [l=fr] {accÃšs aux publications par listing "how to"}
+_textTopicshort_ [l=fr] {AccÃšs aux publications par thÃšme}
+_textPeopleshort_ [l=fr] {AccÃšs aux publications par personne}
+_textAcronymshort_ [l=fr] {AccÃšs aux publications par occurrences d'acronymes}
+_textPhraseshort_ [l=fr] {Naviguer dans les groupes de mots
+  apparaissant dans les publications}
+_textArtistshort_ [l=fr] {AccÃšs aux publications par artiste}
+_textKeywordshort_ [l=fr] {AccÃšs aux publications par mot-clef}
+_textVolumeshort_ [l=fr] {AccÃšs aux publications par volume}
+_textCountriesshort_ [l=fr] {AccÃ©der aux publications par pays}
+_textdefaultshorttext_ [l=fr] {classification indÃ©finie}
+
+_textSearchlong_ [l=fr] {<p>Vous pouvez <i>rechercher certains mots</i>
+prÃ©sents dans le texte Ã  partir de la page de recherche. C'est la
+premiÃšre page Ã  s'afficher lorsque vous dÃ©butez une recherche. Elle
+peut aussi Ãªtre atteinte Ã  partir des autres pages en cliquant sur le
+bouton <i>Recherche</i>. }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=fr] {<p>Vous pouvez avoir <i>accÃšs aux publications
+par titre</i> en cliquant sur le bouton <i>Titres a-z</i>. Ceci
+affichera la liste alphabÃ©tique des livres. }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=fr] {<p>Vous pouvez avoir<i>accÃšs aux publications
+par auteur</i> en cliquant sur le bouton <i>Auteurs a-z</i>. Ceci
+affichera la liste des livres, classÃ©s par nom d'auteur. }
+
+_textSubjectlong_ [l=fr] {<p>Vous pouvez avoir <i>accÃšs aux
+publications par thÃšme</i> en cliquant sur le bouton <i>ThÃšmes</i>. Ceci
+affichera une liste de thÃšmes, reprÃ©sentÃ©e par rayons de livres.  }
+
+_textDescriptionlong_ [l=fr] {<p> Vous pouvez<i>accÃ©der aux publications classÃ©es par descriptions</i> en cliquant le bouton <i>descriptions</i> ce qui fait apparaÃ®tre une liste des descriptions}
+
+_textPublisherlong_ [l=fr] {<p> Vous pouvez<i>accÃ©der aux publications classÃ©es par Ã©diteurs</i> en cliquant le bouton <i>Ã©diteurs</i> ce qui fait apparaÃ®tre une liste des Ã©diteurs.}
+
+_textContributorlong_ [l=fr] {<p> Vous pouvez<i>accÃ©der aux publications classÃ©es par collaborateurs</i> en cliquant le bouton <i>collaborateurs</i> ce qui fait apparaÃ®tre une liste des collaborateurs }
+
+_textDatelong_ [l=fr] {<p>Vous pouvez <i>avoir accÃšs aux publications
+par date</i> en cliquant sur le bouton <i>Dates</i>. Ceci affichera la
+liste des Ã©ditions, triÃ©es chronologiquement. }
+
+_textTypelong_ [l=fr] {<p> Vous pouvez<i>accÃ©der aux publications classÃ©es par genres</i> en cliquant le bouton <i>genres</i> ce qui fait apparaÃ®tre une liste des types de publications }
+
+_textFormatlong_ [l=fr] {<p> Vous pouvez<i>accÃ©der aux publications classÃ©es par format</i> en cliquant le bouton <i>formats</i> ce qui fait apparaÃ®tre une liste des formats de publication}
+
+_textIdentifierlong_ [l=fr] {<p> Vous pouvez<i>accÃ©der aux publications classÃ©es par identifiants</i> en cliquant le bouton <i>identifiants</i> ce qui fait apparaÃ®tre une liste des identifiants }
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=fr] {<p>Vous pouvez <i>accÃ©der aux publications par 
+nom de fichier</i> en cliquant sur le bouton <i>noms de fichiers</i>.
+Ceci affichera une liste d'entrÃ©es, triÃ©es par nom de fichier original.  }
+
+_textLanguagelong_ [l=fr] {<p>Vous pouvez avoir <i>accÃšs aux
+publications par langue</i> en cliquant sur le bouton
+<i>langues</i> button. Ceci affichera une liste d'entrÃ©es, triÃ©es par
+langue.  }
+
+_textRelationlong_ [l=fr] {<p> Vous pouvez<i>accÃ©der aux publications classÃ©es par rÃ©fÃ©rence</i> en cliquant le bouton <i>rÃ©fÃ©rence</i> ce qui fait apparaÃ®tre une liste des rÃ©fÃ©rences . }
+
+_textCoveragelong_ [l=fr] {<p> Vous pouvez<i>accÃ©der aux publications classÃ©es par couverture</i> en cliquant le bouton <i>couvertures</i>}
+
+_textRightslong_ [l=fr] {<p> Vous pouvez<i>accÃ©der aux publications classÃ©es par droits</i> en cliquant le bouton <i>droits</i> ce qui fait apparaÃ®tre une liste des droits.}
+
+
+
+_textOrganizationlong_ [l=fr] {<p>Vous pouvez avoir<i>accÃšs aux
+publications par organisation</i> en cliquant sur le bouton
+<i>Organisations</i>. Ceci affichera une liste alphabÃ©tique des
+organisations.  }
+
+_textHowtolong_ [l=fr] {<p>Vous pouvez <i>accÃ©der Ã  des publications
+Ã  travers un listing "howto"</i> en cliquant sur le bouton <i>"howto</i>. Ceci affichera une liste de rubriques howto.  }
+
+_textTopiclong_ [l=fr] {<p>Vous pouvez avoir<i>accÃšs aux publications
+par thÃšme</i> en cliquant sur le bouton <i>ThÃšmes</i>. Ceci affichera
+une liste thÃ©matique dans laquelle naviguer.  }
+
+_textTolong_ [l=fr] {<p>Vous pouvez avoir <i>accÃšs aux publications par champ
+Â«ÃÂ»</i> en cliquant sur le bouton <i>Ã </i> button.  Ceci affichera une
+liste de rÃ©cipiendaires. }
+
+_textFromlong_ [l=fr] {<p>Vous pouvez avoir <i>accÃšs aux publications par
+champ Â«DeÂ»</i> en cliquant sur le bouton <i>de</i>. Ceci affichera une
+liste d'expÃ©diteurs. .  }
+
+_textSerieslong_ [l=fr] {<p>Vous pouvez avoir<i>accÃšs aux publications
+par sÃ©ries</i> en cliquant sur le bouton <i>SÃ©ries</i>.  Ceci
+affichera la liste des sÃ©ries contenues actuellement dans la
+collection.  }
+
+_textBrowselong_ [l=fr] {<p>Vous pouvez <i>naviguer parmi les
+publications</i> en cliquant sur le bouton <i>Naviguer</i>.  }
+
+_textPeoplelong_ [l=fr] {<p>Vous pouvez avoir <i>accÃšs aux
+publications par personne</i> en cliquant sur le bouton <i>Personnes
+a-z</i>. Ceci affichera une liste d'entrÃ©es, triÃ©es par nom de
+famille. }
+
+_textAcronymlong_ [l=fr] {<p>Vous pouvez avoir <i>accÃšs aux publications par
+occurrences d'acronymes</i> en cliquant sur le bouton 
+<i>acronymes</i> button. Ceci affichera une liste des acronymes et des
+endroits oÃ¹ ils interviennent. }
+
+_textPhraselong_ [l=fr] {<p> Vous pouvez<i>parcourir des expressions prÃ©sentes dans les publications</i> en appuyant le bouton des <i>expressions</i>, Cela utilise le navigateur d'expression phind.}
+
+_textArtistlong_ [l=fr] {<p>Vous pouvez <i>accÃ©der aux publications par
+artiste</i> en cliquant sur le bouton <i>artistes</i>. Ceci affichera
+une liste d'entrÃ©es, triÃ©es par nom d'artiste. }
+
+_textKeywordlong_ [l=fr] {<p>Vous pouvez <i>accÃ©der aux publications
+par mot-clef</i> en cliquant sur le bouton <i>mots-clefs</i>. Ceci
+affichera une liste de mots-clefs. }
+
+_textVolumelong_ [l=fr] {<p>Vous pouvez <i>accÃ©der aux publications
+par volume</i> en cliquant sur le bouton <i>volumes</i>. Ceci
+affichera une liste de volumes. }
+
+_textCaptionslong_ [l=fr] {<p>Vous pouvez<i>accÃ©der aux publications selon les lÃ©gendes<i> en appuyant sur le bouton <i>lÃ©gendes<i>. Cela fait apparaÃ®tre une liste de lÃ©gendes. }
+
+_textCountrieslong_ [l=fr] {<p>Vous pouvez <i>accÃ©der aux publications selon les pays</i>en appuyant sur le bouton </i>pays</i>. Cela fait apparaÃ®tre une liste de pays. }
+
+
+_textdefaultlongtext_ [l=fr] {<p>Cliquez sur le bouton  <i>inconnu</i> pour parcourir des publications (le listing est triÃ© par un champ inconnu).}
+
+_texthelptopics_ [l=fr] {<h2 align=left>ThÃšmes</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Comment rechercher certains mots en particulier</a>
+<ul>
+  <li><a href="\#query-terms">Termes de recherche</a>
+  <li><a href="\#query-type">Type de recherche</a>
+  <li><a href="\#scope-of-queries">Ãtendue des recherches</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">PrÃ©fÃ©rences de collection</a>
+  <li><a href="\#lang-prefs">PrÃ©fÃ©rences de langue</a>
+  <li><a href="\#pres-prefs">PrÃ©fÃ©rences de prÃ©sentation</a>
+  <li><a href="\#search-prefs">PrÃ©fÃ©rences de recherche</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=fr] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=fr] {Comment lire les documents}
+
+_texthelpreadingdocs_ [l=fr] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Lorsqu'un document particulier est affichÃ©, vous pouvez voir son
+titre et ses auteurs en haut Ã  gauche de la page. A cÃŽtÃ©, vous
+pouvez voir le numÃ©ro de la page en cours, et une boÃ®te contenant des
+boutons qui vous permettent soit de sÃ©lectionner une nouvelle page,
+soit de passer Ã  la page suivante ou prÃ©cÃ©dente.
+
+<p>En dessous, on trouve le texte de la partie en cours. A la fin de
+votre lecture, vous pouvez utiliser l'une des deux flÃšches Ã  votre
+disposition, soit pour passer Ã  la partie suivante, soit pour revenir Ã 
+la partie prÃ©cÃ©dente.
+
+<p>Sous le titre et l'auteur se trouvent trois boutons. Cliquez sur
+<i>DÃ©velopper le texte</i> pour dÃ©velopper le texte entier du document
+actif. Si le document est volumineux, le chargement peut Ãªtre long et
+peut nÃ©cessiter beaucoup de mÃ©moire! Cliquez sur <i>DÃ©tacher</i> pour
+crÃ©er une nouvelle fenÃªtre de navigateur pour ce document (c'est trÃšs
+utile si vous voulez comparer des documents, ou lire deux documents Ã  la
+fois.) Finalement, lorsque vous faites une requÃªte, les mots utilisÃ©s
+dans la recherche sont mis en Ã©vidence. Cliquez sur <i>Supprimer la mise
+en Ã©vidence</i> pour supprimer la mise en Ã©vidence.
+
+<p>
+
+<table cellspacing="0" cellpadding="2" border="0">
+<tr>
+  <td colspan=2><img src="_httpiconmore_" border="0"></td>
+  <td>Cliquez sur la flÃšche pour passer Ã  la partie suivante ...</td>
+</tr>
+<tr>
+  <td colspan=2><img src="_httpiconless_" border="0"></td>
+  <td>... ou retourner Ã  la partie prÃ©cÃ©dente</td>
+</tr>
+<tr>
+  <td><img src="_document:httpiconealltof_" border="0"></td>
+  <td><img src="_document:httpiconetsecof_" border="0"></td>
+  <td>Afficher tout le texte, ou pas</td></tr>
+<tr>
+  <td colspan=2><img src="_document:httpiconedtchof_" border="0"></td>
+  <td>Ouvrir cette page dans une nouvelle fenÃªtre</td></tr>
+<tr>
+  <td><img src="_document:httpiconehlof_" border="0"></td>
+  <td><img src="_document:httpiconenhlof_" border="0"></td>
+  <td>Mettre en Ã©vidence les mots recherchÃ©s, ou pas</td>
+</tr>
+ <tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Cliquez sur la flÃªche pour passer Ã  la section suivante ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... ou retourner Ã  la section prÃ©cÃ©dente</td></tr></table>
+
+}
+
+_texthelpsearching_ [l=fr] {<h2>Comment faire une requÃªte pour certains mots en particulier</h2>
+<p>
+Ã partir de la page de recherche, vous pouvez formuler votre recherche
+en suivant le mode d'emploi suivant:<p>
+
+  <ol>
+      <li>SpÃ©cifiez sur quels documents vous souhaitez faire la recherche
+      <li>Indiquez si vous voulez rechercher tous les mots ou seulement 
+          certains mots
+      <li>Tapez les mots pour lesquels vous souhaitez faire la recherche
+      <li>Cliquez sur le bouton <i>Commencer la recherche</i>
+  </ol>
+
+<p>Lorsque vous faites une recherche, les titres des vingt premiers
+documents qui satisfont la requÃªte sont affichÃ©s. Il y a un bouton Ã 
+la fin de la liste qui vous permet d'avoir accÃšs aux vingt documents
+suivants. Ã partir de lÃ  vous pourrez Ã  nouveau avoir accÃšs aux
+vingt documents suivants, et ainsi de suite. Cliquez sur le titre d'un
+document, ou sur le petit bouton situÃ© derriÃšre lui, pour l'afficher.
+
+
+<p>Le nombre de documents retournÃ©s est limitÃ© Ã  100 par dÃ©faut.
+Vous pouvez changer ce nombre en cliquant sur le bouton
+<i>"PrÃ©fÃ©rences"</i> en haut de la page.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Termes de la recherche</h3>
+
+
+<p>Tout ce que vous tapez dans la boÃ®te de recherche est interprÃ©tÃ©
+comme une liste de mots appelÃ©e Â«termes de la rechercheÂ». Chaque terme
+doit Ãªtre alphanumÃ©rique et ne peut contenir que des lettres ou des
+chiffres. Les termes de la recherche sont supposÃ©s Ãªtre sÃ©parÃ©s par des
+espaces: si des caractÃšres de ponctuation sont tapÃ©s, ils sont
+considÃ©rÃ©s comme des espaces servant Ã  sÃ©parer les termes et sont
+ignorÃ©s lors de la recherche. Il n'est pas possible d'effectuer une
+recherche sur des mots contenants des caractÃšres de ponctuation.
+
+
+<p>Par exemple, la recherche<p>
+
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>est Ã©quivalente Ã <p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Type de recherche</h3>
+
+<p>Il y a deux types de recherche.
+
+<ul>
+
+<li>Recherches sur <b>tous</b> les mots.  Ce type de recherche restitue
+les documents qui contiennent tous les mots spÃ©cifiÃ©s. Les documents qui
+satisfont Ã  la recherche sont affichÃ©s dans l'ordre alphabÃ©tique.<p>
+
+<li>Recherches sur <b>certains</b> mots en particulier. Vous pouvez
+donner une liste de certains mots qui ont de grandes chances
+d'apparaÃ®tre dans les documents que vous recherchez. Les documents sont
+alors affichÃ©s dans un ordre qui reflÃšte avec quelle pertinence ils
+satisfont la requÃªte. Lors de la dÃ©termination du degrÃ© de pertinence
+d'un document, il est tenu compte des critÃšres suivants:
+
+<p><ul>
+
+<li>Plus il y a de termes de la recherche dans le document, et plus le
+document est pertinent;
+
+<li>les termes rares sont considÃ©rÃ©s comme plus importants que ceux qui
+sont courants;
+
+<li>les petits documents sont considÃ©rÃ©s comme plus pertinents que
+les documents plus volumineux.
+
+</ul>
+
+</ul>
+
+<p>Vous pouvez utiliser autant de termes de recherche que vous le
+souhaitez -- une phrase entiÃšre, oÃ¹ mÃªme un paragraphe entier. Si
+vous spÃ©cifiez un seul terme, alors les documents qui satisfont Ã  la
+requÃªte seront classÃ©s en fonction du nombre d'occurrences du terme
+dans chaque document.
+
+<p>
+
+_texthelpscope_
+
+}
+
+_textdatesearch_ [l=fr] {Rechercher des dates}
+
+_texthelpdatesearch_ [l=fr] {<h2>_textdatesearch_</h2>
+La recherche par date vous permet de trouver des documents qui non
+seulement remplissent vos critÃšres de recherche, mais traitent aussi
+d'Ã©vÃ©nements situÃ©s dans un intervale temporel particulier. Vous pouvez
+rechercher des documents d'une annÃ©e particuliÃšre d'un intervalle particulier d'annÃ©es. Remarquez qu'il n'est pas nÃ©cessaire de
+fournir des critÃšres de recherche: on peut se contenter d'une recherche
+par date. De mÃªme, il n'est pas nÃ©cessaire d'utiliser des dates dans la
+recherche: si vous ne prÃ©cisez aucune date tout se dÃ©roule comme si la
+recherche par date n'existait pas.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>Comment utiliser cette fonctionnalitÃ©:</h3>
+<ul>
+   <li>Pour rechercher des documents traitant d'une annÃ©e prÃ©cise:<p>
+   <ul>
+       <li>Tapez les critÃšres de recherche comme vous le faites habituellement.
+       <li>Tapez l'annÃ©e souhaitÃ©e dans la boÃ®te "Date de dÃ©but (ou unique)".
+       <li>Si votre date est antÃ©rieure Ã  notre Ãšre (avant
+           JÃ©sus-Christ), choisissez l'option "avant notre Ãšre" dans le menu dÃ©roulant
+           situÃ© prÃšs de cette boÃ®te.
+       <li>DÃ©marrez la recherche comme vous le faites habituellement.
+   </ul>
+<p><li>Pour rechercher des documents couvrant une pÃ©riode ou un intervalle d'annÃ©es:<p>
+   <ul>
+       <li>Tapez les critÃšres de recherche comme vous le faites habituellement.
+       <li>Tapez l'annÃ©e de dÃ©but dans la boÃ®te "Date de dÃ©but (ou unique)".
+       <li>Tapez l'annÃ©e de fin dans la boÃ®te "Date de fin".
+       <li>SÃ©lectionez l'option "avant notre Ãšre" dans le menu dÃ©roulant situÃ©
+           prÃšs de la boÃ®te de saisie pour toute date antÃ©rieure Ã  notre Ãšre (avant
+           JÃ©sus-Christ).
+       <li>DÃ©marrez la recherche comme vous le faites habituellement.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>Fonctionnement de cette recherche</h3>
+
+De maniÃšre gÃ©nÃ©rale, une recherche de documents traitant de l'an 1903 ne
+renverra pas des documents qui rÃ©fÃ©rencent des livres Ã©crits en 1903,
+mais uniquement des documents traitant de l'an 1903. Cependant, Ã©tant
+donnÃ©e la maniÃšre dont les dates des documents sont recherchÃ©es, cela
+renverra les documents dans un intervalle d'annÃ©es (comme par exemple
+1899-1911) incluant 1903, ainsi que les documents citant dans leur texte
+le siÃšcle auquel l'annÃ©e 1903 appartient (par exemple, le XXÃšme siÃšcle,
+ou le vingtiÃšme siÃšcle). Cela signifie que pour certains documents, les
+dates spÃ©cifiÃ©es dans la recherche n'apparaÃ®tront pas effectivement dans
+le texte du document. Pour une recherche par intervalles, tout ce qui
+prÃ©cÃšde s'applique Ã  toutes les dates de l'intervalle.<p>
+}
+
+_textchangeprefs_ [l=fr] {Changement des prÃ©fÃ©rences}
+
+_texthelppreferences_ [l=fr] {<h2>_textchangeprefs_</h2>
+
+<p>Si vous cliquez sur le bouton <i>PrÃ©fÃ©rences</i> en haut de la page,
+vous pourrez alors changer certaines fonctionnalitÃ©s de l'interface
+utilisateur afin que celles-ci conviennent Ã  vos propres besoins.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>PrÃ©fÃ©rences de collection</h3>
+
+Certaines collections sont constituÃ©es de plusieurs sous-collections,
+qui peuvent Ãªtre recherchÃ©es individuellement ou globalement comme un
+tout. Si vous le souhaitez, vous pouvez spÃ©cifier quelles sont les
+sous-collections qui doivent Ãªtre recherchÃ©es dans la page
+Â«PrÃ©fÃ©renceÂ».
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>PrÃ©fÃ©rences de langue</h3>
+
+Une langue de prÃ©sentation est associÃ©e Ã  chaque collection par dÃ©faut, mais vous pouvez la changer si vous le souhaitez. Vous pouvez aussi changer la codification des caractÃšres utilisÃ©e par Greenstone pour lâaffichage dans le navigateur. â le systÃšme utilise des options par dÃ©faut, mais avec certain navigateurs, on peut obtenir de meilleurs rÃ©sultats visuels en changeant 
+la codification des caractÃšres.
+Finalement quelle que soit la collection, vous pouvez choisir d'avoir
+une prÃ©sentation qui utilise une interface textuelle Ã  la place de
+l'interface graphique standard. Cela peut Ãªtre utile pour les
+utilisateurs qui ont des problÃšmes de vue et qui utilisent des grandes
+polices ou bien pour la sortie sur des synthÃ©tiseurs vocaux.
+
+
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>PrÃ©fÃ©rences de prÃ©sentation</h3>
+
+Pour chaque collection, vous pouvez spÃ©cifier plusieurs options
+qui contrÃŽlent la prÃ©sentation.
+
+<p>Â«Collection de pages webÂ» permet de masquer la barre de navigation
+Greenstone qui apparaÃ®t en haut de chaque page d'un document, de telle
+faÃ§on que lorsque vous avez fait une recherche, la page qui satisfait Ã 
+la requÃªte est affichÃ©e directement sans l'en-tÃªte Greenstone. Pour
+effectuer une autre recherche, vous devrez alors utiliser le bouton
+Â«PrÃ©cÃ©denteÂ» de votre navigateur. Ce type de collection vous permet
+aussi de supprimer le message d'avertissement affichÃ© par Greenstone
+lorsqu'un lien hypertexte vous renvoie en dehors de la collection de la
+bibliothÃšque numÃ©rique, quelque part ailleurs sur la toile (web). Pour
+certaines collections vous pouvez aussi contrÃŽler les liens qui
+apparaissent sur la page Â«RÃ©sultats de la rechercheÂ» de telle faÃ§on que
+ces liens vous renvoient directement sur l'URL en question, plutÃŽt que
+sur la copie qui se trouve dans la bibliothÃšque numÃ©rique.
+
+
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>PrÃ©fÃ©rences de recherche</h3>
+
+Deux paires de boutons permettent le contrÃŽle des majuscules/minuscules
+et des racines des mots. Les premiers permettent de contrÃŽler la prise
+en compte des majuscules/minuscules lors de la recherche de documents
+qui doivent satisfaire Ã  la requÃªte. Les deux autres permettent de
+contrÃŽler la prise en compte des fins de mot lors d'une telle mÃªme
+recherche.
+
+<p>Par exemple, si les boutons<i>Ignorer les diffÃ©rences dues aux
+majuscules/minuscules</i> et <i>Ignorer les fins de mots</i> sont
+actifs, la recherche
+
+<p><ul><kbd>African building</kbd></ul>
+
+<p>sera traitÃ©e de la mÃªme faÃ§on que
+
+<p><ul><kbd>africa builds</kbd></ul>
+
+<p> 
+La lettre majuscule de Â«AfricanÂ» sera convertie en minuscule, et les
+suffixes Â«nÂ» and Â«ingÂ» seront supprimÃ©s de Â«AfricanÂ» et Â«buildingÂ»
+respectivement (le Â«sÂ» sera lui aussi supprimÃ© de Â«buildsÂ»).
+
+<p>Vous pouvez aussi choisir le mode recherche Â«avancÃ©eÂ» qui vous
+permet de combiner des termes en utilisant les opÃ©rateurs boolÃ©en AND
+(&), OR (|), et NOT (!). Cela vous permettra d'affiner les
+recherches.
+
+<p>Finalement, vous pouvez aussi contrÃŽler le nombre de documents
+pertinents restituÃ©s ainsi que le nombre de documents prÃ©sentÃ©s sur
+chaque page.
+
+}
+
+_texttanumbrowseoptions_ [l=fr] {Il y a _numbrowseoptions_ faÃ§ons de
+trouver des informations dans cette collection:}
+
+_textsimplehelpheading_ [l=fr] {Comment trouver les informations qui
+vous intÃ©ressent}
+
+_texthelpscope_ [l=fr] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Domaine d'application des recherches</h3>
+
+<p>
+Dans la plupart des collections, vous pouvez choisir diffÃ©rents index
+pour la recherche. Par exemple, il y aura peut-Ãªtre un index pour les
+auteurs et un autre pour les titres. Ou bien mÃªme un index pour les
+chapitres ou paragraphes. GÃ©nÃ©ralement, le document entier est
+retournÃ© quel que soit l'index utilisÃ©.
+
+<p>
+Si les documents sont des livres, ils seront ouverts Ã  l'endroit
+appropriÃ©.
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/french2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/french2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/french2.dm	(revision 10506)
@@ -0,0 +1,1328 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# French Language text and icon macros 
+# -- this file contains text that is of less importance
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=fr] {documents. }
+_lastupdate_ [l=fr] {DerniÃšre mise Ã  jour}
+_ago_ [l=fr] {jours.}
+_colnotbuilt_ [l=fr] {Collection non construite.}
+
+_textpagetitle_ [l=fr] {BibliothÃšque NumÃ©rique Greenstone}
+_textadmin_ [l=fr] {Page d'Administration}
+_textabgs_ [l=fr] {Ã Propos de Greenstone}
+_textgsdocs_ [l=fr] {Documentation Greenstone}
+
+_textimagegli_ [l=fr] {Vous aide Ã  crÃ©er de nouvelles collections, Ã  modifier ou supprimer des
+collections, ou bien encore Ã  ajouter des documents Ã  une collection
+}
+
+_textimagecollector_ [l=fr] {Dans la plupart des cas, le "Librarian Interface" 
+(l'Interface BibliothÃ©caire), plus recent, devrait Ãªtre utilisÃ© en lieu et place du collecteur.}
+
+_textimagetranslator_ [l=fr] {Vous aide Ã  mettre Ã  jour les versions multilingues de Greenstone}
+
+_textimageadmin_ [l=fr] {Vous permet d'ajouter de nouveaux utilisateurs, de connaÃ®tre les
+collections qui se trouvent sur le systÃšme, et de connaÃ®tre les
+informations techniques concernant l'installation de Greenstone
+
+}
+
+_textimagegogreenstone_ [l=fr] {Vous informe sur le logiciel Greenstone et le projet de BibliothÃšque
+NumÃ©rique de Nouvelle-ZÃ©lande, d'oÃ¹ il provient
+
+}
+
+_textimagegodocs_ [l=fr] {Manuels de Greenstone}
+
+_textpoem_ [l=fr] {<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+
+<p>puisse la paix et le calme vous entourer,
+<br>puissiez vous Ãªtre dans la chaleur d'une brume d'Ã©tÃ©,
+<br>puisse l'ocÃ©an de vos voyages Ãªtre aussi lisse que la pierre verte polie.
+
+}
+
+_textgreenstone_ [l=fr] {<p>Greenstone est une pierre semi-prÃ©cieuse qui (comme ce logiciel) a
+pris naissance en Nouvelle-ZÃ©lande. Dans la sociÃ©tÃ© traditionnelle
+Maori, c'Ã©tait l'objet le plus recherchÃ© et celui auquel on attachait le
+plus d'importance. Cette pierre a le pouvoir d'emmagasiner et retenir
+<i>wairua</i>, qui est l'esprit de la force de vie, elle est aussi dotÃ©e
+de vertus traditionnelles qui en font un excellent emblÃšme pour un
+projet de bibliothÃšque numÃ©rique du domaine public. Son Ã©clat symbolise
+la charitÃ©; sa transluciditÃ©, l'honnÃªtetÃ©; sa duretÃ©, le courage; et le
+cÃŽtÃ© tranchant qu'elle peut prendre, la justice. L'objet sculptÃ© et
+utilisÃ© comme logo du logiciel est appelÃ© <i>patu</i>, c'est une sorte
+de matraque utilisÃ©e pour combattre. Un des participants au projet
+Greenstone a hÃ©ritÃ© cet objet de sa famille. Lors des combats, son
+lancer Ã©tait d'une rapiditÃ© et d'une prÃ©cision phÃ©nomÃ©nale ce qui en
+faisait une arme redoutable et complÃšte. Nous souhaiterions que ces
+qualitÃ©s soient aussi celles de ce logiciel, le cÃŽtÃ© tranchant comme un
+rasoir symbolisant l'aspect avancÃ© et pointu de la technologie utilisÃ©e. 
+
+}
+
+_textaboutgreenstone_ [l=fr] {<p>Greenstone est un ensemble de logiciels dont le but est de donner
+accÃšs Ã  des collections d'informations constituant une bibliothÃšque
+numÃ©rique et de construire de nouvelles collections. Greenstone permet
+d'organiser les informations d'une faÃ§on innovante et de les publier
+soit sur l'Internet soit sur un CD-ROM. Greenstone fait partie du
+<b>Projet de BibliothÃšque NumÃ©rique de Nouvelle-ZÃ©lande</b> Ã 
+<b>l'UniversitÃ© de Waikato</b>, il est dÃ©veloppÃ© et distribuÃ© en
+coopÃ©ration avec <b>l'UNESCO</b> et le Projet de <b>BibliothÃšques
+Humanitaires et de dÃ©veloppement</b>. C'est un logiciel libre (Open
+Source) et qui est disponible pour tÃ©lÃ©chargement sur le site web <a
+href="http://greenstone.org">http://greenstone.org</a>, la licence
+d'utilisation est la licence publique gÃ©nÃ©rale de GNU (GPL).
+
+<p>Le but de ce logiciel est de permettre aux utlisateurs, appartenant
+en particulier aux universitÃ©s, biblothÃšques, et autres institutions du
+service public, de construire leurs propres bibliothÃšques numÃ©riques.
+Les bibliothÃšques numÃ©riques sont en train de rÃ©volutionner la mÃ©thode
+de distribution et d'acquisition des connaissances utilisÃ©e par l'UNESCO
+avec ses partenaires habituels, dont les institutions qui travaillent
+dans le domaine de la l'Ã©ducation, de la science et de la culture. Ceci,
+dans le monde entier, et en particulier dans les pays en voie de
+dÃ©veloppement. Nous espÃ©rons que ce logiciel servira Ã  encourager la
+construction et la diffusion de biblothÃšques numÃ©riques dans le domaine
+public afin de partager l'information et le savoir.
+
+<p>Ce logiciel est dÃ©veloppÃ© et distribuÃ© grÃ¢ce Ã  un effort de
+collaboration internationale qui prit naissance en aoÃ»t 2000 avec trois
+acteurs:
+
+<table border="0">
+<tr valign="top">
+<td>
+<a href="http://nzdl.org"><b>Le projet de BibliothÃšque NumÃ©rique de
+Nouvelle-ZÃ©lande Ã  l'UniversitÃ© de Waikato</b></a>
+<br>
+Le logiciel Greenstone s'est dÃ©veloppÃ© Ã  partir de ce projet, cette
+initiative a ensuite Ã©tÃ© soutenue et prÃ©sentÃ©e par la Sous-Commision
+pour la Communication de la Commission Nationale de Nouvelle-ZÃ©lande
+auprÃšs de l'UNESCO en tant que contribution de la Nouvelle-ZÃ©lande aux
+programmes de l'UNESCO.
+</td>
+<td></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://www.unesco.org"><b>Organisation des Nations Unies pour
+l'Ã©ducation, la science et la culture</b></a>
+<br>
+La diffusion mondiale d'information et de savoir dans les domaines de
+l'Ã©ducation, de la science et de la culture, et en particulier dans les
+pays en voie de dÃ©veloppement, est une des missions du programme
+intergouvernemental Â«Information pour tousÂ». D'autre part, une
+technologie de l'information et de la communication accessible est
+considÃ©rÃ©e comme un outil essentiel dans ce contexte.
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/unesco.gif"
+border="0"></a></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://humaninfo.org"><b>L'ONG Â«Human InfoÂ» situÃ©e Ã 
+Anvers, en Belgique</b></a>
+<br>
+Ce projet de bibliothÃšques humanitaires et de dÃ©veloppement crÃ©Ã©
+par des agences des Nations Unies et d'autres ONG s'est forgÃ© une
+solide rÃ©pution mondiale en ce qui concerne la numÃ©risation de
+documents relatifs au dÃ©veloppement humanitaire et aussi pour leur
+diffusion publique, gratuite pour les pays en voie de dÃ©veloppement et
+Ã  prix coÃ»tant pour les autres.
+</td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "sÃ©lectionnez une collection" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ [l=fr] {_httpimg_/fr/selcolgr.gif}
+_widthselcolgr_ [l=fr] {537}
+_heightselcolgr_ [l=fr] {17}
+_altselcolgr_ [l=fr] {"Select a collection"}
+
+
+## "l'Interface\nBibliothÃ©caire\nde Greenstone" ## home_page_button ## cgli ##
+_httpiconcgliof_ [l=fr] {_httpimg_/fr/cgliof.gif}
+_httpiconcglion_ [l=fr] {_httpimg_/fr/cglion.gif}
+_widthcgli_ [l=fr] {100}
+
+## "Le Collector" ## home_page_button ## ccol ##
+_httpiconccolof_ [l=fr] {_httpimg_/fr/ccolof.gif}
+_httpiconccolon_ [l=fr] {_httpimg_/fr/ccolon.gif}
+_widthccol_ [l=fr] {100}
+
+## "Le Traducteur" ## home_page_button ## ctrans ##
+_httpiconctransof_ [l=fr] {_httpimg_/fr/ctransof.gif}
+_httpiconctranson_ [l=fr] {_httpimg_/fr/ctranson.gif}
+_widthctrans_ [l=fr] {100}
+
+## "Page\nd'Administration" ## home_page_button ## cadmin ##
+_httpiconcadminof_ [l=fr] {_httpimg_/fr/cadminof.gif}
+_httpiconcadminon_ [l=fr] {_httpimg_/fr/cadminon.gif}
+_widthcadmin_ [l=fr] {100}
+
+## "Ã Propos\nde Greenstone" ## home_page_button ## cabgs ##
+_httpiconcabgsof_ [l=fr] {_httpimg_/fr/cabgsof.gif}
+_httpiconcabgson_ [l=fr] {_httpimg_/fr/cabgson.gif}
+_widthcabgs_ [l=fr] {100}
+
+## "Documentation\nGreenstone" ## home_page_button ## cgsdoc ##
+_httpiconcgsdocof_ [l=fr] {_httpimg_/fr/cgsdocof.gif}
+_httpiconcgsdocon_ [l=fr] {_httpimg_/fr/cgsdocon.gif}
+_widthcgsdoc_ [l=fr] {100}
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=fr] {Il y a quatre autres boutons sur la page d'accueil}
+
+_textnocollections_ [l=fr] {<p>Aucune collection n'est disponible pour cette installation de
+Greenstone. Pour ajouter des collections, vous pouvez:
+
+<ul>
+<li>soit utiliser <a href="_httppagecollector_">Le Collector</a> pour
+construire de nouvelles collections
+
+<li>soit installer des collections Ã  partir du CD-ROM si vous avez le
+CD-ROM de Greenstone
+
+</ul>
+}
+
+_text1coll_ [l=fr] {Cette installation de Greenstone contient 1 collection}
+
+_textmorecolls_ [l=fr] {Cette installation de Greenstone contient _1_
+collections}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=fr] {Lien externe}
+_textlinknotfound_ [l=fr] {Lien interne introuvable}
+
+_textextlinkcontent_ [l=fr] {Le lien sÃ©lectionnÃ© est extÃ©rieur Ã  toutes
+vos collections sÃ©lectionnÃ©es actuellement, Si vous souhaitez quand mÃªme
+afficher ce lien et si vous avez accÃšs au web, vous pouvez <a
+href="_nexturl_">vous dÃ©placer</a> sur cette page; dans le cas
+contraire, utilisez le bouton Â«PrÃ©cÃ©dentÂ» du navigateur pour revenir au
+document prÃ©cÃ©dent.
+
+}
+
+_textlinknotfoundcontent_ [l=fr] {Le lien interne sÃ©lectionnÃ©  n'existe
+pas. C'est certainement dÃ» Ã  une erreur dans collection source de base.
+Utilisez le bouton Â«PrÃ©cÃ©dentÂ» du navigateur pour revenir au document
+prÃ©cÃ©dent. 
+
+}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=fr] {<h3>Lien sur la collection "_2_"</h3>
+
+<p> Le lien sÃ©lectionnÃ© est externe Ã  la collection Â«_collectionname_Â»
+(il renvoie sur la collection Â«_2_Â»). Si vous souhaitez afficher le
+document qui correspond Ã  ce lien dans la collection Â«_2_Â», vous pouvez
+<a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">vous rendre</a> sur cette
+page; dans le cas contraire, utilisez le bouton Â«PrÃ©cÃ©dentÂ» du
+navigateur pour revenir au document prÃ©cÃ©dent. 
+
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=fr] {BibliothÃšque NumÃ©rique Greenstone}
+
+_textusername_ [l=fr] {nom d'utilisateur}
+_textpassword_ [l=fr] {mot de passe}
+
+_textmustbelongtogroup_ [l=fr] {Remarquez qu'il vous faut appartenir au groupe "_cgiargug_" pour accÃ©der Ã  cette page}
+
+_textmessageinvalid_ [l=fr] {La page que vous avez demandÃ©e nÃ©cessite
+que vous vous enregistriez.<br>
+_If_(_cgiargug_,[_textmustbelongtogroup_]<br>) Veuillez saisir
+votre identifiant Greenstone et votre mot de passe.}
+
+_textmessagefailed_ [l=fr] {Votre nom d'utilisateur ou votre mot de passe est incorrect.}
+
+_textmessagedisabled_ [l=fr] {DÃ©solÃ©, votre compte a Ã©tÃ© mis
+hors service. Veuillez contacter l'administrateur de ce site.}
+
+_textmessagepermissiondenied_ [l=fr] {DÃ©solÃ©, vous n'avez pas la
+permission d'accÃ©der a cette page.}
+
+_textmessagestalekey_ [l=fr] {Le lien que vous avez choisi est
+maintenant pÃ©rimÃ©. Veuillez entrer votre mot de passe pour accÃ©der Ã 
+cette page.
+
+}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=fr] {<p>Cette installation de Greenstone ne contient pas de documentation.
+Ceci est peut-Ãªtre dÃ» au fait que:
+
+<ol>
+
+<li>vous avez installÃ© Greenstone Ã  partir du CD-ROM en utilisant
+une option compacte.
+
+<li>vous avez installÃ© Greenstone Ã  partir d'une distribution
+tÃ©lÃ©chargÃ©e sur un site Internet.
+
+</ol>
+
+Dans les deux cas, vous pouvez obtenir la documentation Ã  partir du
+rÃ©pertoire <i>docs</i> de Greenstone sur le CD-ROM, ou en visitant le
+site web <a href="http://www.greenstone.org">http://www.greenstone.org</a>.
+
+}
+
+_textuserguide_ [l=fr] {Guide de l'utilisateur}
+_textinstallerguide_ [l=fr] {Guide d'installation}
+_textdeveloperguide_ [l=fr] {Guide du dÃ©veloppeur}
+_textpaperguide_ [l=fr] {Du papier Ã  la collection}
+_textorganizerguide_ [l=fr] {Utilisation de L'organizer}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "documentation de greenstone" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=fr] {_httpimg_/fr/gsdocsgr.gif}
+_widthgsdocsgr_ [l=fr] {_pagewidth_}
+_heightgsdocsgr_ [l=fr] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ [l=fr] {structure par dÃ©faut}
+_textmore_ [l=fr] {plus}
+_textcollector_ [l=fr] {Le Collector}
+_textinfo_ [l=fr] {Informations sur la collection}
+_textsrce_ [l=fr] {DonnÃ©es source}
+_textconf_ [l=fr] {Configuration de la collection}
+_textbild_ [l=fr] {Construction}
+_textview_ [l=fr] {Affichage}
+_textdel_ [l=fr] {Suppression de la collection}
+_textexpt_ [l=fr] {Exportr la collection}
+
+_textdownloadingfiles_ [l=fr] {TÃ©lÃ©chargement de fichiers âŠ}
+_textimportingcollection_ [l=fr] {Importation de la collection âŠ}
+_textbuildingcollection_ [l=fr] {Construction de la collection âŠ}
+_textcreatingcollection_ [l=fr] {CrÃ©ation de la collection âŠ}
+
+_textcollectorblurb_ [l=fr] {<i>Le crayon et la plume ont plus de pouvoir que l'Ã©pÃ©e!
+
+<br>La construction et la distribution de collections d'information
+comportent certaines responsabilitÃ©s qu'il est prÃ©fÃ©rable d'Ã©tudier
+avant de commencer.
+
+Il y a des aspects juridiques et lÃ©gaux concernant le copyright: le fait
+que l'on puisse avoir accÃšs librement Ã  certains documents ne signifie
+pas forcÃ©ment que l'on peut les distribuer aux autres. Il y a des
+aspects sociaux: les collections doivent respecter la culture et les
+coutumes de la communautÃ© dont les documents proviennent. Et il y a des
+aspects Ã©thiques: tout simplement, certaines informations ne doivent pas
+Ãªtre divulguÃ©es aux autres.
+
+<br>Soyez sensibilisÃ© au pouvoir de l'information et utilisez-le avec
+prudence.
+
+</i>
+
+}
+
+_textcb1_ [l=fr] {Le Collector vous aide Ã  crÃ©er de nouvelles collections, Ã  modifier ou
+supprimer des collections, et Ã  ajouter des documents. Pour cela, vous
+serez guidÃ© par une sÃ©quence de pages web qui vous demanderont les
+informations nÃ©cessaires.
+
+}
+
+_textcb2_ [l=fr] {PremiÃšrement, vous devez dÃ©cider si vous voulez}
+_textcnc_ [l=fr] {crÃ©er une nouvelle collection}
+_textwec_ [l=fr] {travailler avec une collection dÃ©jÃ  existante, pour ajouter des donnÃ©es ou la supprimer.}
+
+_textcb3_ [l=fr] {Le systÃšme doit d'abord vÃ©rifier votre signature pour pouvoir construire
+ou modifier des collections de la bibliothÃšque numÃ©rique. Cela permet de
+protÃ©ger les informations contenues dans votre bibliothÃšque numÃ©rique en
+empÃªchant les autres de se connecter sur votre ordinateur et de changer
+les informations. Note: pour des raisons de sÃ©curitÃ©, vous serez
+automatiquement dÃ©connectÃ© aprÃšs une pÃ©riode d'inactivitÃ© de 30 minutes.
+Si cela vous arrive, ne vous en faites pas! -- vous pouvez Ã  nouveau
+entrer votre signature et continuer Ã  partir de l'endroit oÃ¹ vous Ã©tiez
+lors de la dÃ©connexion. 
+
+}
+
+_textcb4_ [l=fr] {Veuillez entrer votre nom d'utilisateur et votre mot de passe, puis
+cliquer sur le bouton pour vÃ©rifier votre signature.
+
+}
+
+_textfsc_ [l=fr] {Tout d'abord, sÃ©lectionnez la collection sur laquelle vous souhaitez
+travailler (les collections protÃ©gÃ©es en Ã©criture n'apparaissent pas
+dans cette liste).
+
+}
+
+_textwtc_ [l=fr] {Avec la collection sÃ©lectionnÃ©e, vous pouvez}
+_textamd_ [l=fr] {Ajouter plus de donnÃ©es et reconstruire la collection}
+_textetc_ [l=fr] {Ãditer le fichier de configuration de la collection et reconstruire la collection}
+_textdtc_ [l=fr] {Supprimer entiÃšrement la collection}
+_textetcfcd_ [l=fr] {Exporter la collection pour l'enregistrer sur un CD-ROM auto-installable sous Windows}
+_textcaec_ [l=fr] {Changer une collection existante}
+_textnwec_ [l=fr] {Aucune collection permettant l'Ã©criture n'est disponible pour modification}
+_textcianc_ [l=fr] {CrÃ©ation d'une nouvelle collection}
+_texttsosn_ [l=fr] {La suite logique des Ã©tapes Ã  suivre pour crÃ©er une nouvelle bibliothÃšque numÃ©rique est la suivante:}
+_textsin_ [l=fr] {SpÃ©cifier son nom (et autres informations associÃ©es)}
+_textswts_ [l=fr] {SpÃ©cifier l'origine des donnÃ©es source}
+_textatco_ [l=fr] {Ajuster les options pour la configuration (uniquement pour les utilisateurs avancÃ©s)}
+_textbtc_ [l=fr] {Â«ConstructionÂ» de la collection (voir ci-dessous)}
+_textpvyh_ [l=fr] {Consulter avec fiertÃ© votre Åuvre d'art.}
+
+_texttfsiw_ [l=fr] {C'est dans la quatriÃšme Ã©tape que Greenstone effectue tout le travail.
+Au cours du processus de Â«ConstructionÂ», Greenstone construit tous les
+fichiers d'index et rassemble toutes les informations nÃ©cessaires pour
+que la bibliothÃšque numÃ©rique puisse fonctionner. Mais vous devez en
+premier lieu prÃ©ciser les informations.
+
+}
+
+_textadab_ [l=fr] {Un diagramme apparaÃ®t ci-dessous, qui vous aidera Ã  vous situer dans la
+sÃ©quence. Le bouton vert est celui sur lequel vous devez cliquer pour
+continuer la sÃ©quence. Lorsque vous allez vous dÃ©placer dans la
+sÃ©quence, la couleur du bouton va changer et devenir jaune. Vous pouvez
+vous dÃ©placer sur une page prÃ©cÃ©dente en cliquant sur le bouton jaune
+correspondant dans le diagramme.
+
+}
+
+_textwyar_ [l=fr] {Lorsque vous Ãªtes prÃªts, cliquez sur le bouton vert Â«informations sur
+la collectionÂ» pour commencer Ã  crÃ©er la nouvelle collection de la
+bibliothÃšque numÃ©rique.
+
+}
+
+_textcnmbs_ [l=fr] {Le nom de la collection est obligatoire}
+_texteambs_ [l=fr] {L'adresse Ã©lectronique est obligatoire}
+_textpsea_ [l=fr] {Veuillez spÃ©cifier l'adresse Ã©lectronique sous la forme : nomutilisateur@domaine}
+_textdocmbs_ [l=fr] {Une description de la collection est obligatoire}
+
+_textwcanc_ [l=fr] {Lorsque vous crÃ©ez une nouvelle collection, il est nÃ©cessaire de saisir
+certaines informations prÃ©liminaires concernant les donnÃ©es sources. Ce
+processus est structurÃ© sous la forme d'une sÃ©rie de pages web,
+contrÃŽlÃ©es par le Collector. La barre en bas de page affiche la sÃ©quence
+des pages qui doivent Ãªtre complÃ©tÃ©es.
+
+}
+
+_texttfc_ [l=fr] {Titre pour la collection:}
+
+_texttctiasp_ [l=fr] {Le titre de la collection est une phrase courte qui est utilisÃ©e dans
+la bibliothÃšque numÃ©rique pour identifier le contenu de la collection.
+Par exemple: Â«Rapports techniques en informatiqueÂ» ou
+Â«BibliothÃšque sur le dÃ©veloppement humanitaireÂ».
+
+}
+
+_textcea_ [l=fr] {Contact, adresse Ã©lectronique:}
+
+_textteas_ [l=fr] {Cette adresse Ã©lectronique donne le point de contact principal pour la
+collection. Si le logiciel Greenstone rencontre un problÃšme, un rapport
+sur le problÃšme est envoyÃ© Ã  cette adresse. Veuillez taper cette adresse
+en entier, au format suivant: <tt>nom@domaine</tt>
+
+}
+
+_textatc_ [l=fr] {Ã propos de cette collection:}
+
+_texttiasd_ [l=fr] {C'est une dÃ©claration dÃ©crivant les principes qui rÃ©gissent les donnÃ©es
+faisant partie de cette collection. Elle sera affichÃ©e sur la premiÃšre
+page lorsque la collection sera prÃ©sentÃ©e.
+
+}
+
+_textypits_ [l=fr] {La position dans la sÃ©quence est indiquÃ©e par une flÃšche en
+dessous--dans ce cas, l'Ã©tape Â«informations de collectionÂ». Pour
+continuer, cliquez sur le bouton Â«donnÃ©es sourceÂ».
+
+}
+
+_srcebadsources_ [l=fr] {<p>Une ou plusieurs donnÃ©es source spÃ©cifiÃ©es en entrÃ©e ne sont pas
+disponibles (marquÃ©e(s) _iconcross_ ci-dessous).
+
+<p>La cause peut Ãªtre:
+<ul>
+<li>le fichier, le site FTP ou bien l'URL n'existe pas.
+<li>vous n'Ãªtes pas connectÃ© Ã  l'Internet (vous devez d'abord vous connecter chez votre fournisseur).
+<li>vous essayez d'accÃ©der Ã  une URL qui se trouve derriÃšre un pare-feu 
+(C'est en gÃ©nÃ©ral le cas si vous devez donner un nom d'utilisateur et un
+mot de passe pour accÃ©der Ã  l'Internet).
+</ul>
+
+<p>Si vous pouvez afficher l'URL dans votre navigateur, le problÃšme peut
+venir d'une copie qui se trouve dans la mÃ©moire tampon (cache) locale.
+Malheureusement, de telles copies ne sont pas visibles par le processus
+de miroir de Greenstone. Dans ce cas, il est recommandÃ© de commencer par
+tÃ©lÃ©charger les pages Ã  l'aide du navigateur.
+
+}
+
+_textymbyco_ [l=fr] {<p>Vous pouvez dÃ©finir votre collection soit Ã  partir:
+<ul>
+<li>de la structure par dÃ©faut
+<dl><dd>La nouvelle collection peut contenir des documents html (.htm, .html),
+des documents contenant du texte simple, (.txt, .text), des documents en
+format MS WORD (.doc), des documents en format PDF (.pdf) ou des
+documents de type courrier Ã©lectronique (.email).</dd></dl>
+<li>d'une collection dÃ©jÃ  existante
+<dl><dd>Dans ce cas, les fichiers (documents) de la nouvelle collection
+doivent Ãªtre exactement du mÃªme type que ceux qui ont Ã©tÃ© utilisÃ©s pour
+construire la collection existante.
+</dd></dl>
+</ul>
+}
+
+_textbtco_ [l=fr] {DÃ©finir la collection Ã  partir de}
+_textand_ [l=fr] {Ãjouter de nouvelles donnÃ©es}
+_textad_ [l=fr] {Ãjout de donnÃ©es:}
+
+_texttftysb_ [l=fr] {Les fichiers que vous allez spÃ©cifier ci-dessous seront ajoutÃ©s Ã  la
+collection. Faites attention Ã  ne pas spÃ©cifier de nouveau des fichiers
+qui se trouvent dÃ©jÃ  dans la collection, sinon la collection comportera
+deux copies de ces fichiers. Les fichiers sont spÃ©cifiÃ©s en indiquant le
+nom du fichier prÃ©cÃ©dÃ© du chemin complet, et les pages web par leur
+adresse web absolue. 
+
+}
+
+_textis_ [l=fr] {DonnÃ©es en entrÃ©e:}
+
+_textddd1_ [l=fr] {<p>Si vous utilisez file:// ou ftp:// pour spÃ©cifier un fichier, ce
+fichier sera tÃ©lÃ©chargÃ©.
+
+<p>Si vous utilisez http:// le rÃ©sultat dÃ©pendra de l'URL et sera
+diffÃ©rent si celle-ci affiche une page web  ou bien une liste de
+fichiers dans votre navigateur. Si l'URL affiche une page web, alors
+cette page et toutes les autres pages sur lesquelles elle pointe par
+l'intermÃ©diaire de liens hypertexte seront tÃ©lÃ©chargÃ©es -- il en sera
+de mÃªme pour ces pages et ainsi de suite, etc.. -- tant que ces pages
+rÃ©sident sur le mÃªme site web, sous l'URL initiale.
+
+
+<p>Si vous utilisez file:// ou ftp:// pour spÃ©cifier un dossier ou un
+rÃ©pertoire, ou bien http:// et que cette URL affiche une liste de
+fichiers, tous les fichiers qui se trouvent dans ce dossier et ses
+sous-dossiers seront inclus dans la collection.
+
+<p>Cliquez sur le bouton Â«Plus de donnÃ©esÂ» pour obtenir davantage de
+champs de saisie.
+
+}
+
+_textddd2_ [l=fr] {<p>Cliquez sur l'un des boutons verts. Si vous Ãªtes un utilisateur
+avancÃ©, vous pouvez affiner la configuration de la collection.
+Autrement, passez directement Ã  l'Ã©tape de construction. N'oubliez pas
+que vous pouvez toujours avoir accÃšs Ã  une Ã©tape prÃ©cÃ©dente en cliquant
+sur le bouton jaune correspondant.
+
+}
+
+_textconf1_ [l=fr] {<p>La construction et la prÃ©sentation d'une collection sont contrÃŽlÃ©es
+par des spÃ©cifications enregistrÃ©es dans un Â«fichier de configurationÂ»
+spÃ©cial. Les utilisateurs avancÃ©s peuvent modifier les paramÃštres de
+configuration contenus dans ce fichier.
+
+
+<center><p><b>Si vous n'Ãªtes pas un utilisateur avancÃ©, allez
+directement en bas de la page.</b></center> 
+
+<p>Pour changer les paramÃštres de configuration, Ã©ditez les paramÃštres
+qui apparaissent ci-dessous. Si vous faites une erreur, vous pouvez
+toujours cliquer sur le bouton Â«RÃ©initialiserÂ» pour revenir aux
+paramÃštres de configuration initiaux.
+
+}
+
+_textreset_ [l=fr] {RÃ©initialiser}
+
+_textbild1_ [l=fr] {La collection est maintenant en cours de construction: cette opÃ©ration
+peut Ãªtre longue. La ligne ci-dessous affiche l'Ã©tat du processus de
+construction et donne des informations sur son dÃ©roulement.
+
+}
+
+_textbild2_ [l=fr] {Vous pouvez arrÃªter le processus de construction Ã  tout instant, pour
+cela, cliquez ici. <br>La collection sur laquelle vous travaillez
+restera intacte.
+
+}
+
+_textstopbuild_ [l=fr] {ArrÃªt de la construction}
+
+_textbild3_ [l=fr] {Si vous quittez cette page sans avoir interrompu le processus de
+construction (en cliquant sur le bouton Â«ArrÃªt de la constructionÂ»),
+celui-ci va continuer et la collection sera installÃ©e dans la
+bibliothÃšque numÃ©rique une fois le processus terminÃ© avec succÃšs. 
+
+}
+
+_textbuildcancelled_ [l=fr] {Construction interrompue}
+
+_textbildcancel1_ [l=fr] {Le processus de construction de la collection a Ã©tÃ© interrompu. Utilisez
+les boutons jaunes pour faire des changements concernant la collection,
+ou bien redÃ©marrez le processus de construction.
+
+}
+
+_textbsupdate1_ [l=fr] {Nouvel Ã©tat de la construction dans 1 seconde}
+_textbsupdate2_ [l=fr] {Nouvel Ã©tat de la construction dans}
+_textseconds_ [l=fr] {secondes}
+_textbildsuc_ [l=fr] {La collection a Ã©tÃ© construite avec succÃšs.}
+
+_textviewbildsummary_ [l=fr] {Vous pouvez <a href="_httppagex_(bsummary)&c=_cgiargbc1dirname_"
+target=_top>afficher un rÃ©sumÃ© du processus de construction</a> de cette
+collection pour obtenir plus de dÃ©tails.
+
+}
+
+_textfailmsg11_ [l=fr] {La collection n'a pas pu Ãªtre construite car elle ne contient aucune
+donnÃ©e. Assurez-vous qu'au moins l'un des rÃ©pertoires ou fichiers
+spÃ©cifiÃ©s dans la page <i>DonnÃ©es initiales</i> existe et que le fichier
+ou bien (dans le cas d'un rÃ©pertoire) l'un des fichiers est d'un type
+reconnu par Greenstone.  
+
+}
+
+_textfailmsg21_ [l=fr] {La collection n'a pas pu Ãªtre construite
+(import.pl a Ã©chouÃ©).}
+_textblcont_ [l=fr] {Le fichier journal de la construction contient
+les informations suivantes:}
+
+_texttryagain_ [l=fr] {Veuillez svp <a href="_httppagecollector_" target=_top>redÃ©marrer le
+Collector</a> et essayer Ã  nouveau.
+
+}
+
+_textfailmsg31_ [l=fr] {La collection n'a pas pu Ãªtre construite
+(buildcol.pl a Ã©chouÃ©).}
+_textfailmsg41_ [l=fr] {La collection a Ã©tÃ© construite avec succÃšs mais
+n'a pu Ãªtre installÃ©e.}
+_textfailmsg71_ [l=fr] {Une erreur inattendue s'est produite lors de la
+construction de la collection}
+_textretcoll_ [l=fr] {Retour au Collector}
+
+_textdelperm_ [l=fr] {Certains Ã©lÃ©ments ou toute la collection _cgiargbc1dirname_ n'ont pu
+Ãªtre supprimÃ©s. Les causes possibles sont:
+
+<ul>
+<li> Greenstone n'a pas la permission de supprimer le rÃ©pertoire _gsdlhome_/collect/_cgiargbc1dirname_
+.<br>
+
+Vous pouvez avoir Ã  supprimer manuellement le rÃ©pertoire pour achever la
+suppression de la collection _cgiargbc1dirname_ de cet ordinateur.
+<li>Greenstone ne peut pas lancer le programme  _gsdlhome_/bin/script/delcol.pl. Assurez vous que ce fichier est lisible et exÃ©cutable.</li>
+
+</ul>
+
+}
+
+_textdelinv_ [l=fr] {La collection _cgiargbc1dirname_ est protÃ©gÃ©e ou invalide. La
+suppression a Ã©tÃ© annulÃ©e.
+
+}
+
+_textdelsuc_ [l=fr] {La collection _cgiargbc1dirname_ a Ã©tÃ© supprimÃ©e.}
+
+_textclonefail_ [l=fr] {La collection _cgiargclonecol_ n'a pu Ãªtre clonÃ©e. Les causes possibles sont:
+
+<ul>
+
+<li> La collection _cgiargclonecol_ n'existe pas
+
+<li> La collection _cgiargclonecol_ ne possÃšde pas de fichier de
+configuration collect.cfg
+
+<li> Greenstone n'a pas la permission de lire le fichier de
+configuration collect.cfg
+
+</ul>
+
+}
+
+_textcolerr_ [l=fr] {Erreur du Collector.}
+
+_texttmpfail_ [l=fr] {Le Collector a Ã©chouÃ© lors de la lecture ou de l'Ã©criture sur un fichier
+temporaire ou dans un rÃ©pertoire temporaire. Les causes possibles sont:
+
+<ul>
+
+<li> Greenstone n'a pas la permission de lire/Ã©crire dans le rÃ©pertoire _gsdlhome_/tmp
+     
+</ul>
+
+}
+
+_textmkcolfail_ [l=fr] {Le Collector a Ã©chouÃ© lors de la crÃ©ation de la structure hiÃ©rarchique
+des rÃ©pertoires qui est nÃ©cessaire Ã  la crÃ©ation d'une nouvelle
+collection (mkcol.pl a Ã©chouÃ©). Les causes possibles sont:
+
+<ul>
+
+<li> Greenstone n'a pas la permission de lire/Ã©crire dans le rÃ©pertoire
+_gsdlhome_/tmp
+
+<li> Erreurs dans le script Perl mkcol.pl
+
+</ul>
+
+}
+
+_textnocontent_ [l=fr] {Erreur Collector: aucune collection n'a Ã©tÃ© saisie pour la nouvelle
+collection. Essayez de redÃ©marrer le Collector Ã  partir du dÃ©but.
+
+}
+
+_textrestart_ [l=fr] {RedÃ©marrer le Collector}
+
+_textreloaderror_ [l=fr] {Une erreur s'est produite lors de la crÃ©ation de la nouvelle collection.
+Il se peut que Greenstone ait Ã©tÃ© perturbÃ© par l'utilisation des boutons
+Â«RechargerÂ» ou Â«PrÃ©cÃ©dentÂ» du navigateur (veuillez essayer d'Ã©viter
+l'utilisation de ces boutons au moment de la crÃ©ation d'une collection
+avec le Collector). Il est recommandÃ© de redÃ©marrer le Collector Ã 
+partir du dÃ©but.
+
+}
+
+_textexptsuc_ [l=fr] {La collection _cgiargbc1dirname_ a Ã©tÃ© exportÃ©e dans le rÃ©pertoire
+_gsdlhome_/tmp/exported\__cgiargbc1dirname_ .
+
+}
+
+_textexptfail_ [l=fr] {<p>L'exportation de la collection _cgiargbc1dirname_ a Ã©chouÃ©.
+
+<p>Il est probable que ce problÃšme provient du fait que Greenstone a Ã©tÃ©
+installÃ© sans les composants qui permettent la fonction Â«Export de la
+collectionÂ».
+ <ul>
+
+ <li>
+ Si vous avez installÃ© Greenstone Ã  partir du CD-ROM, ces composants
+ n'ont pas Ã©tÃ© installÃ©s Ã  moins que vous ne les ayez sÃ©lectionnÃ©s dans
+ le cadre d'une installation Â«PersonnalisÃ©eÂ». Vous pouvez les ajouter Ã 
+ votre installation en redÃ©marrant la procÃ©dure d'installation.
+
+ <li>Si vous avez installÃ© Greenstone Ã  partir d'une distribution tÃ©lÃ©chargÃ©e
+ sur le web, il vous faudra alors tÃ©lÃ©charger les composants 
+ dont vous avez besoin pour permettre cette fonctionnalitÃ©. Vous pouvez visiter
+ <a href="http://www.greenstone.org">http://www.greenstone.org</a> ou bien
+ envoyer un courrier Ã©lectronique Ã  
+ <a href="mailto:greenstone@cs.waikato.ac.nz">
+ greenstone@cs.waikato.ac.nz</a> pour plus de dÃ©tails. 
+ </ul> 
+
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Le collector" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=fr] {_httpimg_/fr/h\_colect.gif}
+
+## "informations\nsur la collection" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=fr] {_httpimg_/fr/gcinfoof.gif}
+_httpicongcinfoon_ [l=fr] {_httpimg_/fr/gcinfoon.gif}
+_httpiconycinfoof_ [l=fr] {_httpimg_/fr/ycinfoof.gif}
+_httpiconycinfoon_ [l=fr] {_httpimg_/fr/ycinfoon.gif}
+_httpiconncinfoof_ [l=fr] {_httpimg_/fr/ncinfoof.gif}
+
+## "donnÃ©es\n source" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=fr] {_httpimg_/fr/gcsrceof.gif}
+_httpicongcsrceon_ [l=fr] {_httpimg_/fr/gcsrceon.gif}
+_httpiconycsrceof_ [l=fr] {_httpimg_/fr/ycsrceof.gif}
+_httpiconycsrceon_ [l=fr] {_httpimg_/fr/ycsrceon.gif}
+_httpiconncsrceof_ [l=fr] {_httpimg_/fr/ncsrceof.gif}
+
+## "configurer\nla collection" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=fr] {_httpimg_/fr/gcconfof.gif}
+_httpicongcconfon_ [l=fr] {_httpimg_/fr/gcconfon.gif}
+_httpiconycconfof_ [l=fr] {_httpimg_/fr/ycconfof.gif}
+_httpiconycconfon_ [l=fr] {_httpimg_/fr/ycconfon.gif}
+_httpiconncconfof_ [l=fr] {_httpimg_/fr/ncconfof.gif}
+
+## "construire\nla collection" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=fr] {_httpimg_/fr/gcbildof.gif}
+_httpicongcbildon_ [l=fr] {_httpimg_/fr/gcbildon.gif}
+_httpiconycbildof_ [l=fr] {_httpimg_/fr/ycbildof.gif}
+_httpiconycbildon_ [l=fr] {_httpimg_/fr/ycbildon.gif}
+_httpiconncbildof_ [l=fr] {_httpimg_/fr/ncbildof.gif}
+
+## "afficher\nla collection" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=fr] {_httpimg_/fr/gcviewof.gif}
+_httpicongcviewon_ [l=fr] {_httpimg_/fr/gcviewon.gif}
+_httpiconycviewof_ [l=fr] {_httpimg_/fr/ycviewof.gif}
+_httpiconycviewon_ [l=fr] {_httpimg_/fr/ycviewon.gif}
+_httpiconncviewof_ [l=fr] {_httpimg_/fr/ncviewof.gif}
+
+## "supprimer\nla collection" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=fr] {_httpimg_/fr/gcdelof.gif}
+_httpicongcdelon_ [l=fr] {_httpimg_/fr/gcdelon.gif}
+
+## "exporter\nla collection" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=fr] {_httpimg_/fr/gcexptof.gif}
+_httpicongcexpton_ [l=fr] {_httpimg_/fr/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=fr] {Greenstone est un ensemble de logiciels dont le but est de fournir un
+accÃšs Ã  des collections d'informations constituant une bibliothÃšque
+numÃ©rique et de construire de nouvelles collections. Greenstone permet
+d'organiser les informations d'une faÃ§on innovante et de les publier
+soit sur l'Internet soit sur un CD-ROM. Greenstone fait partie du Projet
+de BibliothÃšque NumÃ©rique de Nouvelle-ZÃ©lande Ã  l'UniversitÃ© de Waikato,
+il est distribuÃ© en coopÃ©ration avec l'UNESCO et le Projet de
+BibliothÃšques sur le DÃ©veloppement Humanitaire. C'est un logiciel libre
+(Open Source), disponible pour tÃ©lÃ©chargement Ã  d'adresse web suivante:
+<i>http://greenstone.org</i>, sous les termes de la licence publique
+gÃ©nÃ©rale de GNU (GPL). 
+
+}
+
+_textgreenstone2_ [l=fr] {Le site web de la bibliothÃšque numÃ©rique de Nouvelle-ZÃ©lande (<a
+href="http://nzdl.org">http://nzdl.org</a>) contient de nombreux
+exemples de collections, qui ont toutes Ã©tÃ© crÃ©Ã©es avec le logiciel
+Greenstone et que vous pouvez parcourir Ã  votre grÃ© car elles sont dans
+le domaine public. Elles montrent les diffÃ©rentes options de recherche
+et de parcours. Certaines collections sont en arabe, chinois, franÃ§ais,
+maori, espagnol et anglais. Il y a aussi quelques collections de
+morceaux de musique.
+
+}
+
+_textplatformtitle_ [l=fr] {plate-forme}
+_textgreenstone3_ [l=fr] {Greenstone s'exÃ©cute sous Windows, Unix ou Mac OS X. La distribution contient des
+versions exÃ©cutables pour toutes les versions de Windows, ainsi que pour
+Linux. Elle contient aussi l'ensemble du code source pour le systÃšme qui
+peut Ãªtre compilÃ© avec MS VC++ ou Gnu GCC. Greenstone fonctionne avec
+d'autres logiciels qui eux aussi sont des logiciels libres et
+tÃ©lÃ©chargables: le serveur web Apache et PERL. L'interface utilisateur
+utilise un navigateur web: gÃ©nÃ©ralement Netscape Navigator ou Internet
+Explorer.
+
+}
+
+_textgreenstone4_ [l=fr] {Bon nombre de collections sont distribuÃ©es sur CD-ROM avec le logiciel
+Greenstone. Par exemple, le <i>Projet de BibliothÃšques sur le
+DÃ©velopement Humanitaire</i> contient 1230 publications qui couvrent des
+sujets allant de la comptabilitÃ© jusqu'aux conditions d'hygiÃšne liÃ©es Ã 
+l'eau. L'accÃšs Ã  cette collection peut se faire Ã  partir d'un ordinateur
+aux capacitÃ©s modestes tels que ceux que l'on trouve dans les pays en
+voie de dÃ©veloppement. On peut accÃ©der aux informations en recherchant
+des mots ou une phrase en particulier, en parcourant les publications
+par sujet, en parcourant les publications par titre, en parcourant les
+publications par organisation, en parcourant une liste de Â«Comment
+faireÂ», ou et en affichant au hasard des pages de couverture de
+publications.
+
+}
+
+_textcustomisationtitle_ [l=fr] {Personnalisation}
+_textgreenstone5_ [l=fr] {Greenstone est spÃ©cialement conÃ§u pour Ãªtre Ã©largi et adaptÃ© Ã  des
+besoins particuliers. De nouveaux formats de documents et de
+mÃ©ta-donnÃ©es peuvent Ãªtre facilement traitÃ©s par Greenstone en Ã©crivant
+des Â«connecteursÂ» (plug-ins), en Perl. De la mÃªme faÃ§on, de nouvelles
+structures de parcours des mÃ©ta-donnÃ©es peuvent Ãªtre mises en Åuvre en Ã©crivant des Â«classificateursÂ». L'interface utilisateur
+et la prÃ©sentation peuvent Ãªtre facilement modifiÃ©es car elles sont
+dÃ©finies par l'intermÃ©diaire d'un langage de macros simple. Le protocole
+CORBA permet aux agents (Ã©crits en Java, par exemple) d'utiliser toutes
+les fonctionnalitÃ©s disponibles dans les collections de documents.
+Finalement, le code source en C++ et Perl, est disponible et accessible
+pour modification.
+
+}
+
+_textdocumentationtitle_ [l=fr] {documentation}
+_textdocuments_ [l=fr] {Une large documentation pour le logiciel Greenstone est disponible.}
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+_textmailinglisttitle_ [l=fr] {liste de diffusion}
+_textmailinglist_ [l=fr] {Il existe une liste de diffusion dÃ©diÃ©e au logiciel Greenstone de
+bibliothÃšque numÃ©rique. Il serait bon que les utilisateurs actifs de
+Greenstone se joignent Ã  cette liste et contribuent aux discussions.
+Pour souscrire, cliquez <a href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.
+Pour envoyer un message Ã  cette liste, adressez-le Ã  <a
+href="mailto:greenstone-users@list.scms.waikato.ac.nz">greenstone-users@list.scms.waikato.ac.nz</a>.
+}
+
+_textbugstitle_ [l=fr] {bugs}
+_textreport_ [l=fr] {Nous voulons nous assurer que ce logiciel fonctionne correctement et
+qu'il convient Ã  vos besoins. Veuillez nous faire part des bogues Ã  <a
+href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+
+}
+
+_textgs3title_ [l=fr] {dans les ouvrages}
+_textgs3_ [l=fr] {Greenstone 3 est une refonte complÃšte et une rÃ©-implÃ©mentation qui conserve les avantages de  
+Greenstone 2 (la version actuelle)--par exemple, il est multilingue, 
+multi-plateforme, et hautement configurable. il incorpore toutes les fonctionalitÃ©s du systÃšme existent et il est compatible avec les versions antÃ©rieures: c'est-Ã -dire qu'il peut construire et lancer des collections existentes sans aucune modification. Ecrit en Java, il est structure en rÃ©seau de modules indÃ©pendants qui communique en utilisant XML : ainsi, il s'exÃ©cute d'une maniÃšre distribuÃ©e et peut Ãªtre rÃ©parti sur diffÃ©rents serveurs si nÃ©cessaire. Cette conception modulaire augmente la flexibilitÃ© et l'extensibilitÃ© de de Greenstone. La nouvelle version devrait Ãªtre disponible d'ici le 23 DÃ©cembre 2003 pour un usage expÃ©rimental. Une conception initiatiale du systÃšme est dÃ©crite dans "The design of Greenstone 3: An agent based 
+dynamic digital library" (tÃ©lÃ©chargement 
+<a href="http://www.greenstone.org/manuals/gs3design.pdf">PDF</a>).
+}
+
+_textcreditstitle_ [l=fr] {crÃ©dits}
+
+_textwhoswho_ [l=fr] {Le logiciel Greenstone a vu le jour grÃ¢ce Ã  un effort de collaboration
+entre de nombreuses personnes. Rodger McNab et Stefan Boddie en sont les
+principaux architectes et dÃ©veloppeurs. Des contributions ont Ã©tÃ© faites
+par David Bainbridge, George Buchanan, Hong Chen, Michael Dewsnip, Katherine Don, Elke Duncker, Carl
+Gutwin, Geoff Holmes, Dana McKay, John McPherson, Craig Nevill-Manning, Dynal Patel, Gordon
+Paynter, Bernhard Pfahringer, Todd Reed, Bill Rogers, John Thompson, et Stuart Yeates. 
+D'autres membres du Projet de bibliothÃšque numÃ©rique de Nouvelle-ZÃ©lande
+ont Ã©galement donnÃ© des conseils et inspirÃ© les concepteurs du systÃšme:
+Mark Apperley, Sally Jo Cunningham, Steve Jones, Te Taka Keegan, Michel
+Loots, Malika Mahoui, et Lloyd Smith. Nous remercions aussi tous ceux
+qui ont contribuÃ© au dÃ©veloppement des modules sous licence
+GNU GPL qui font partie de cette distribution: MG, GDBM, PDFTOHTML, PERL, WGET,
+WVWARE, XLHTML.
+
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "Ã  propos du logiciel Greenstone" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=fr] {_httpimg_/fr/abgsgr.gif}
+_widthabgsgr_ [l=fr] {_pagewidth_}
+_heightabgsgr_ [l=fr] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=fr] {Liste des utilisateurs actifs}
+_textuser_ [l=fr] {Utilisateur}
+_textas_ [l=fr] {Ãtat du compte}
+_textgroups_ [l=fr] {Groupes}
+_textcomment_ [l=fr] {Commentaires}
+_textadduser_ [l=fr] {Ajouter un nouvel utilisateur}
+_textedituser_ [l=fr] {Ãditer}
+_textdeleteuser_ [l=fr] {Supprimer}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=fr] {Ãditer les informations utilisateur}
+_textadduser_ [l=fr] {Ajouter un nouvel utilisateur}
+
+_textaboutusername_ [l=fr] {Les noms d'utilisateur doivent comporter entre 2 et 30 caractÃšres. Ils
+peuvent aussi contenir les caractÃšres alphanumÃ©riques Â«.Â» et Â«_Â».
+
+}
+
+_textaboutpassword_ [l=fr] {Les mots de passe doivent comporter entre 3 et 8 caractÃšres. Ils peuvent
+contenir n'importe quel caractÃšre ASCII imprimable.
+
+}
+
+_textoldpass_ [l=fr] {Si ce champ est blanc, l'ancien mot de place sera
+conservÃ©.}
+_textenabled_ [l=fr] {activÃ©}
+_textdisabled_ [l=fr] {dÃ©sactivÃ©}
+
+_textaboutgroups_ [l=fr] {Les groupes sont des listes dont les Ã©lÃ©ments sont sÃ©parÃ©s par des virgules,
+ne mettez pas de blancs aprÃšs les virgules.
+
+}
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=fr] {Supprimer un utilisateur}
+_textremwarn_ [l=fr] {Ãtes vous sÃ»r de vouloir supprimer
+l'utilisateur <b>_cgiargumun_</b>?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=fr] {Changer le mot de passe}
+_textoldpw_ [l=fr] {Ancien mot de passe}
+_textnewpw_ [l=fr] {Nouveau mot de passe}
+_textretype_ [l=fr] {Veuillez retaper le nouveau mot de passe}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=fr] {Votre mot de passe a Ã©tÃ© changÃ©.}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=fr] {Le nom d'utilisateur est incorrect.}
+_textinvalidpassword_ [l=fr] {Le mot de passe est incorrect.}
+_textemptypassword_ [l=fr] {Veuillez saisir un mot de passe initial pour cet utilisateur.}
+_textuserexists_ [l=fr] {Cet utilisateur existe dÃ©jÃ , veuillez saisir un autre nom d'utilisateur.}
+
+_textusernameempty_ [l=fr] {Veuillez saisir votre nom d'utilisateur.}
+_textpasswordempty_ [l=fr] {Vous devez saisir votre ancien mot de passe.}
+_textnewpass1empty_ [l=fr] {Entrez votre nouveau mot de passe, puis retapez-le.}
+_textnewpassmismatch_ [l=fr] {Les deux versions de votre nouveau mot de passe ne correspondent pas.}
+_textnewinvalidpassword_ [l=fr] {Vous avez entrÃ© un mot de passe incorrect.}
+_textfailed_ [l=fr] {Le nom d'utilisateur, le mot de passe, ou les deux sont incorrects.}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=fr] {NumÃ©ro de version de Greenstone}
+_textframebrowser_ [l=fr] {Vous devez avoir un navigateur acceptant les cadres (frames) pour l'affichage.}
+_textusermanage_ [l=fr] {Gestion des utilisateurs}
+_textlistusers_ [l=fr] {Liste des utilisateurs}
+_textaddusers_ [l=fr] {Ajouter un nouvel utilisateur}
+_textchangepasswd_ [l=fr] {Changer le mot de passe}
+_textinfo_ [l=fr] {Informations techniques}
+_textgeneral_ [l=fr] {GÃ©nÃ©ral}
+_textarguments_ [l=fr] {Arguments}
+_textactions_ [l=fr] {Actions}
+_textbrowsers_ [l=fr] {Navigateurs}
+_textprotocols_ [l=fr] {Protocoles}
+_textconfigfiles_ [l=fr] {Fichiers de configuration}
+_textlogs_ [l=fr] {Journaux}
+_textusagelog_ [l=fr] {Journal de l'utilisation}
+_textinitlog_ [l=fr] {Journal d'initialisation}
+_texterrorlog_ [l=fr] {Journal des erreurs}
+_textadminhome_ [l=fr] {Page d'accueil de l'administration}
+_textreturnhome_ [l=fr] {Page d'accueil de Greenstone}
+_titlewelcome_ [l=fr] {Administration }
+_textmaas_ [l=fr] {Les services de maintenance et d'administration sont:}
+_textvol_ [l=fr] {Afficher les journaux en ligne}
+_textcmuc_ [l=fr] {CrÃ©ation, maintenance et mise Ã  jour des collections}
+_textati_ [l=fr] {AccÃšs aux informations techniques telles que les arguments CGI}
+
+_texttsaa_ [l=fr] {L'accÃšs Ã  ces services peut se faire en utilisant la barre de navigation
+sur le cÃŽtÃ© gauche de la page.
+
+}
+
+_textcolstat_ [l=fr] {Situation de la collection}
+
+_textcwoa_ [l=fr] {Les collections ne sont considÃ©rÃ©es comme "actives" que si leurs fichiers build.cfg
+existent, s'ils sont lisibles, et s'ils contiennent une date de construction valide
+(c-Ã -d >  0), et s'ils se trouvent dans le rÃ©pertoire index de
+la collection (c-Ã -d PAS dans le rÃ©pertoire
+build).
+
+}
+
+_textcafi_ [l=fr] {Cliquez sur <i>abrÃ©gÃ©</i> pour obtenir des informations sur la collection}
+_textcctv_ [l=fr] {Cliquez sur <i>collection</i> pour afficher une collection}
+_textsubc_ [l=fr] {Soumettre les changements}
+_texteom_ [l=fr] {Erreur lors de l'ouverture du fichier main.cfg}
+_textftum_ [l=fr] {La mise Ã  jour du fichier main.cfg a Ã©chouÃ©}
+_textmus_ [l=fr] {La mise Ã  jour du fichier main.cfg est faite}
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=fr] {RÃ©sumÃ© de la construction pour la collection _collectionname_}
+_textflog_ [l=fr] {Journal des opÃ©rations qui ont Ã©chouÃ©e pour la collection _collectionname_}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=fr] {EfficacitÃ© de Greenstone}
+
+_textwhy_ [l=fr] {<p>L'envoi de ce rapport est une maniÃšre d'indiquer que vous avez trouvÃ© la page web que vous Ã©tiez entrain de visionner difficile ou frustrant}
+_textextraforform_ [l=fr] {Vous n'avez pas Ã  remplir le formulaire -- toute information sera utile}
+_textprivacybasic_ [l=fr] {<p> Le rapport contiendra uniquement des informations concernant la page web Greenstone que vous Ãªtes en train de consulter, ainsi que la technologie que vous avez utilisÃ©e pour la visionner (plus toute autre information facultative que vous aurez donnÃ©e)}
+_textstillsend_ [l=fr] {Voulez vous toujours envoyer ce rapport?}
+
+_texterror_ [l=fr] {erreur}
+_textyes_ [l=fr] {Oui}
+_textno_ [l=fr] {Non}
+_textclosewindow_ [l=fr] {Fermer la fenÃªtre}
+_textabout_ [l=fr] {A propos}
+_textprivacy_ [l=fr] {IntimitÃ©}
+_textsend_ [l=fr] {Envoyer}
+_textdontsend_ [l=fr] {Ne pas envoyer}
+_textoptionally_ [l=fr] {Optionnellement}
+
+_textunderdev_ [l=fr] {Un aperÃ§u des dÃ©tails sera disponible dans la version finale}
+
+_textviewdetails_ [l=fr] {Afficher les dÃ©tails du rapport}
+_textmoredetails_ [l=fr] {Plus de dÃ©tails}
+_texttrackreport_ [l=fr] {Suivre ce rapport}
+_textcharacterise_ [l=fr] {Quel genre de problÃšme est-ce}
+_textseverity_ [l=fr] {Quelle est la gravitÃ© du problÃšme}
+ 
+_textbadrender_ [l=fr] {La page semble Ã©trange}
+_textcontenterror_ [l=fr] {Erreur de contenu}
+_textstrangebehaviour_ [l=fr] {Comportement Ã©trange}
+_textunexpected_ [l=fr] {Quelque chose d'inattendu est arrivÃ©e}
+_textfunctionality_ [l=fr] {Difficile Ã  utiliser}
+_textother_ [l=fr] {Autre}
+
+_textcritical_ [l=fr] {Critique}
+_textmajor_ [l=fr] {SÃ©rieux}
+_textmedium_ [l=fr] {Moyen}
+_textminor_ [l=fr] {Secondaire}
+_texttrivial_ [l=fr] {Trivial}
+
+_textwhatdoing_ [l=fr] {Qu'essayiez-vous de faire?}
+_textwhatexpected_ [l=fr] {A quoi vous attendiez vous?}
+_textwhathappened_ [l=fr] {Que s'est-il rÃ©ellement passÃ©?}
+
+_cannotfindcgierror_ [l=fr] {<h2>DÃ©solÃ©!</h2>Impossible de trouver les programmes du serveur pour le bouton ''J\\'aimerais me plaindre''}
+
+_textusabbanner_ [l=fr] {la banniÃšre koru-style de Greenstone}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+_textgli_ [l=fr] {l'Interface BibliothÃ©caire de Greenstone}
+_textglihelp_ [l=fr] {L'Interface du BibliothÃ©caire de Greenstone (GLI) vous donne accÃšs aux fonctions de Greenstone Ã  
+partir d'une interce 'pointer et cliquer' facile Ã  utiliser.
+Cela vous permet de rassembler une sÃ©rie de documents, importer ou 
+assigner des mÃ©ta-donnÃ©es, de les intÃ©grer dans une 
+collection Greenstone.
+<p>
+Notez que GLI est lancÃ© avec Greenstone et suppose qu'il est 
+installÃ© dans un sous-rÃ©pertoire de votre installation 
+Greenstone. Si vous avez tÃ©lÃ©chargÃ© une des 
+distributions de Greenstone ou si vous avez installÃ© Ã  
+partir d'un CD-ROM, ceci sera le cas.
+
+<h4>ExÃ©cuter GLI sous Windows</h4>
+
+Lancer le "Librarian Interface" (l'Interface BibliothÃ©caire) sous 
+Windows en sÃ©lectionnant <i>Greenstone Digital Library</i>
+(BibliothÃšque numÃ©rique de Greenstone) dans la section 
+des Programmes du menu <i>DÃ©marrer</i> et en choisissant <i>Librarian 
+Interface</i>.
+
+<h4>ExÃ©cuter GLI sous Unix</h4>
+
+Pour exÃ©cuter GLI sous Unix, aller au rÃ©pertoire <i>gli</i> de votre installation Greenstone et lancer le script <i>gli.sh</i>.
+
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "l'Interface BibliothÃ©caire de Greenstone" ## green_bar_left_aligned ## gligr ##
+_httpicongligr_ [l=fr] {_httpimg_/fr/gligr.gif}
+_widthgligr_ [l=fr] {_pagewidth_}
+_heightgligr_ [l=fr] {17}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/galician.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/galician.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/galician.dm	(revision 10506)
@@ -0,0 +1,1418 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Galician Language text and icon macros
+# TraducciÃ³n Ã³ galego feita por XaquÃ­n Lores xaquin@udc.es
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=gl] {PublicaciÃ³ns periÃ«dicas}
+_textsource_ [l=gl] {fonte: }
+_textdate_ [l=gl] {data de publicaciÃ³n: }
+_textnumpages_ [l=gl] {nÃºmero de pÃ¡xinas: }
+
+_textsignin_ [l=gl] {conectar}
+
+_textdefaultcontent_ [l=gl] {Non se atopa a pÃ¡xina solicitada. Por favor prema o
+botÃ³n "AtrÃ¡s" do seu navegador ou o botÃ³n "Principal" para regresar Ã¡ Biblioteca Dixital Greenstone}
+
+_textdefaulttitle_ [l=gl] {Erro en GSDL}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=gl] {Esta coleciÃ³n contÃ©n _about:numdocs_ documentos, e foi creada hai _about:builddate_ dÃ­as.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=gl] {<p>Esta colecciÃ³n contÃ©n _numdocs_ _If_("_numdocs_" eq
+"1",documento,documentos) e un total de _numbytes_.
+<p><a href="_httppagex_(bsummary)">Prema aquÃ­</a> para visualizar o
+informe de creaciÃ³n desta colecciÃ³n.
+}
+
+_textimagecollection_ [l=gl] {}
+_textimageabout_ [l=gl] {PÃ¡xina Acerca de}
+_textimagehome_ [l=gl] {PÃ¡xina Principal}
+_textimagehelp_ [l=gl] {PÃ¡xina de axuda}
+_textimagepref_ [l=gl] {PÃ¡xina de Preferencias}
+_textimagegreenstone_ [l=gl] {Programa da Biblioteca Dixital Greenstone}
+# -- Missing translation: _textimageusab_
+
+_textimagesearch_ [l=gl] {Buscar termos especÃ­ficos}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=gl] {Lista alfabÃ©tica de tÃ­tulos}
+_textimageCreator_ [l=gl] {Lista de autores por orde alfabÃ©tica}
+_textimageSubject_ [l=gl] {Lista por materias}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=gl] {Lista por data}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=gl] {Lista por nome de ficheiro orixinal}
+_textimageLanguage_ [l=gl] {Lista por lingua}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=gl] {Lista por organizaciÃ³n}
+_textimageKeyword_ [l=gl] {Lista por palabra clave}
+_textimageHowto_ [l=gl] {Lista por "Como..."}
+_textimageList_ [l=gl] {Lista de documentos}
+_textimageSeries_ [l=gl] {Lista por nÃºmero de publicaciÃ³n}
+_textimageTo_ [l=gl] {Lista por campo "Para:"}
+_textimageFrom_ [l=gl] {Lista por campo "De:"}
+_textimageTopic_ [l=gl] {Lista por temas especiais}
+_textimageBrowse_ [l=gl] {Navegar}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=gl] {Lista de persoas por orde alfabÃ©tica}
+_textimageAcronym_ [l=gl] {Lista de siglas}
+_textimagePhrase_ [l=gl] {Lista de frases}
+_textimageArtist_ [l=gl] {Lista de artistas}
+_textimageVolume_ [l=gl] {Lista por volume}
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=gl] {Buscar}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=gl] {TÃ­tulos A-Z}
+_texticontabCreatorgreen_ [l=gl] {Autores A-Z}
+_texticontabSubjectgreen_ [l=gl] {Materias}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=gl] {Datas}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=gl] {Nomes de ficheiros}
+_texticontabLanguagegreen_ [l=gl] {Lingua}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=gl] {OrganizaciÃ³n}
+_texticontabKeywordgreen_ [l=gl] {Palabras clave}
+_texticontabhowgreen_ [l=gl] {CÃ³mo...}
+_texticontabseriesgreen_ [l=gl] {Series}
+_texticontablistgreen_ [l=gl] {Listas}
+_texticontabtogreen_ [l=gl] {Para}
+_texticontabfromgreen_ [l=gl] {De}
+_texticontabtopicgreen_ [l=gl] {Temas}
+_texticontabbrwsegreen_ [l=gl] {Navegar}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=gl] {Navegar}
+_texticontabPeoplegreen_ [l=gl] {Persoas A-Z}
+_texticontabAcronymgreen_ [l=gl] {Siglas}
+_texticontabPhrasegreen_ [l=gl] {Frases}
+_texticontabArtistgreen_ [l=gl] {Artistas}
+_texticontabVolumegreen_ [l=gl] {Volumes}
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=gl] {Ver o documento}
+_texticonclosedbook_ [l=gl] {Abrir este documento e ver o seu Ã­ndice de contido}
+_texticonnext_ [l=gl] {Ir Ã¡ seguinte secciÃ³n}
+_texticonprev_ [l=gl] {Ir Ã¡ secciÃ³n anterior}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=gl] {Ver o documento no formato MIDI}
+_texticonmsword_ [l=gl] {Ver o documento no formato Microsoft Word}
+_texticonmp3_ [l=gl] {Ver o documento no formato MP3}
+_texticonpdf_ [l=gl] {Ver o documento no formato PDF}
+_texticonps_ [l=gl] {Ver o documento no formato PostScript}
+_texticonppt_ [l=gl] {Ver o documento no formato PowerPoint}
+_texticonrtf_ [l=gl] {Ver o documento no formato RTF}
+_texticonxls_ [l=gl] {Ver o documento no formato Microsoft Excel}
+
+_page_ [l=gl] {pÃ¡xina }
+_pages_ [l=gl] {pÃ¡xinas}
+_of_ [l=gl] {de }
+_vol_ [l=gl] {Vol.}
+_num_ [l=gl] {NÂº}
+
+_textmonth00_ [l=gl] {}
+_textmonth01_ [l=gl] {xaneiro}
+_textmonth02_ [l=gl] {febreiro}
+_textmonth03_ [l=gl] {marzo}
+_textmonth04_ [l=gl] {abril}
+_textmonth05_ [l=gl] {maio}
+_textmonth06_ [l=gl] {xuÃ±o}
+_textmonth07_ [l=gl] {xullo}
+_textmonth08_ [l=gl] {agosto}
+_textmonth09_ [l=gl] {setembro}
+_textmonth10_ [l=gl] {outubro}
+_textmonth11_ [l=gl] {novembro}
+_textmonth12_ [l=gl] {decembro}
+
+_textdocument_ [l=gl] {Documento}
+_textsection_ [l=gl] {SecciÃ³n}
+_textparagraph_ [l=gl] {Paragrafo}
+
+_magazines_ [l=gl] {Revistas}
+
+_nzdlpagefooter_ [l=gl] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">Proxecto de Biblioteca Dixital de Nova
+Celandia</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Departamento de informÃ¡tica</a>,
+<a href="http://www.waikato.ac.nz">Universidade de Waikato</a>,
+Nova Celandia}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "PRINCIPAL" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=gl] {_httpimg_/gl/chomeof.gif}
+_httpiconchomeon_ [l=gl] {_httpimg_/gl/chomeon.gif}
+
+## "AXUDA" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=gl] {_httpimg_/gl/chelpof.gif}
+_httpiconchelpon_ [l=gl] {_httpimg_/gl/chelpon.gif}
+
+## "PREFERENCIAS" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=gl] {_httpimg_/gl/cprefof.gif}
+_httpiconcprefon_ [l=gl] {_httpimg_/gl/cprefon.gif}
+
+# -- Missing translation: cusab
+# -- Missing translation: _httpiconcusabof_
+# -- Missing translation: _httpiconcusabon_
+
+
+## "buscar" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=gl] {_httpimg_/gl/tsrchgr.gif}
+_httpicontsrchof_ [l=gl] {_httpimg_/gl/tsrchof.gif}
+_httpicontsrchon_ [l=gl] {_httpimg_/gl/tsrchon.gif}
+_widthtsrchx_ [l=gl] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tÃ­tulos a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=gl] {_httpimg_/gl/ttitlgr.gif}
+_httpiconttitleof_ [l=gl] {_httpimg_/gl/ttitlof.gif}
+_httpiconttitleon_ [l=gl] {_httpimg_/gl/ttitlon.gif}
+_widthttitlex_ [l=gl] {87}
+
+# Not true DC, kept for legacy reasons
+## "autores a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=gl] {_httpimg_/gl/tauthgr.gif}
+_httpicontcreatof_ [l=gl] {_httpimg_/gl/tauthof.gif}
+_httpicontcreaton_ [l=gl] {_httpimg_/gl/tauthon.gif}
+_widthtcreatx_ [l=gl] {87}
+
+## "materias" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=gl] {_httpimg_/gl/tsubjgr.gif}
+_httpicontsubjon_ [l=gl] {_httpimg_/gl/tsubjon.gif}
+_httpicontsubjof_ [l=gl] {_httpimg_/gl/tsubjof.gif}
+_widthtsubjx_ [l=gl] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "datas" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=gl] {_httpimg_/gl/tdategr.gif}
+_httpicontdateof_ [l=gl] {_httpimg_/gl/tdateof.gif}
+_httpicontdateon_ [l=gl] {_httpimg_/gl/tdateon.gif}
+_widthtdatex_ [l=gl] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "nomes de ficheiros" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=gl] {_httpimg_/gl/tsrcgr.gif}
+_httpicontsrcof_ [l=gl] {_httpimg_/gl/tsrcof.gif}
+_httpicontsrcon_ [l=gl] {_httpimg_/gl/tsrcon.gif}
+_widthtsrcx_ [l=gl] {118}
+
+## "lingua" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=gl] {_httpimg_/gl/tlanggr.gif}
+_httpicontlangon_ [l=gl] {_httpimg_/gl/tlangon.gif}
+_httpicontlangof_ [l=gl] {_httpimg_/gl/tlangof.gif}
+_widthtlangx_ [l=gl] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "series" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=gl] {_httpimg_/gl/tsergr.gif}
+_httpicontserof_ [l=gl] {_httpimg_/gl/tserof.gif}
+_httpicontseron_ [l=gl] {_httpimg_/gl/tseron.gif}
+_widthtserx_ [l=gl] {87}
+
+## "para" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=gl] {_httpimg_/gl/ttogr.gif}
+_httpiconttoon_ [l=gl] {_httpimg_/gl/ttoon.gif}
+_httpiconttoof_ [l=gl] {_httpimg_/gl/ttoof.gif}
+_widthttox_ [l=gl] {87}
+
+## "de" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=gl] {_httpimg_/gl/tfromgr.gif}
+_httpicontfromon_ [l=gl] {_httpimg_/gl/tfromon.gif}
+_httpicontfromof_ [l=gl] {_httpimg_/gl/tfromof.gif}
+_widthtfromx_ [l=gl] {87}
+
+## "organizaciÃ³ns" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=gl] {_httpimg_/gl/torggr.gif}
+_httpicontorgon_ [l=gl] {_httpimg_/gl/torgon.gif}
+_httpicontorgof_ [l=gl] {_httpimg_/gl/torgof.gif}
+_widthtorgx_ [l=gl] {87}
+
+## "como..." ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=gl] {_httpimg_/gl/thowgr.gif}
+_httpiconthowon_ [l=gl] {_httpimg_/gl/thowon.gif}
+_httpiconthowof_ [l=gl] {_httpimg_/gl/thowof.gif}
+_widththowx_ [l=gl] {87}
+
+## "temas" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=gl] {_httpimg_/gl/ttopicgr.gif}
+_httpiconttopicon_ [l=gl] {_httpimg_/gl/ttopicon.gif}
+_httpiconttopicof_ [l=gl] {_httpimg_/gl/ttopicof.gif}
+_widthttopicx_ [l=gl] {87}
+
+## "navegar" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=gl] {_httpimg_/gl/tbrwsegr.gif}
+_httpicontbrwseon_ [l=gl] {_httpimg_/gl/tbrwseon.gif}
+_httpicontbrwseof_ [l=gl] {_httpimg_/gl/tbrwseof.gif}
+_widthtbrwsex_ [l=gl] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "persoas" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=gl] {_httpimg_/gl/tpeopgr.gif}
+_httpicontpeopof_ [l=gl] {_httpimg_/gl/tpeopof.gif}
+_httpicontpeopon_ [l=gl] {_httpimg_/gl/tpeopon.gif}
+_widthtpeopx_ [l=gl] {87}
+
+## "sigla" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=gl] {_httpimg_/gl/tacrogr.gif}
+_httpicontacroof_ [l=gl] {_httpimg_/gl/tacroof.gif}
+_httpicontacroon_ [l=gl] {_httpimg_/gl/tacroon.gif}
+_widthtacrox_ [l=gl] {87}
+
+## "frases" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=gl] {_httpimg_/gl/tphrsegr.gif}
+_httpicontphrseof_ [l=gl] {_httpimg_/gl/tphrseof.gif}
+_httpicontphrseon_ [l=gl] {_httpimg_/gl/tphrseon.gif}
+_widthtphrsex_ [l=gl] {87}
+
+## "artistas" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=gl] {_httpimg_/gl/tartstgr.gif}
+_httpicontartstof_ [l=gl] {_httpimg_/gl/tartstof.gif}
+_httpicontartston_ [l=gl] {_httpimg_/gl/tartston.gif}
+_widthtartstx_ [l=gl] {87}
+
+## "palabras clave" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=gl] {_httpimg_/gl/tkwgr.gif}
+_httpicontkwof_ [l=gl] {_httpimg_/gl/tkwof.gif}
+_httpicontkwon_ [l=gl] {_httpimg_/gl/tkwon.gif}
+_widthtkwx_ [l=gl] {91}
+
+## "volumes" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=gl] {_httpimg_/gl/tvolgr.gif}
+_httpicontvolof_ [l=gl] {_httpimg_/gl/tvolof.gif}
+_httpicontvolon_ [l=gl] {_httpimg_/gl/tvolon.gif}
+_widthtvolx_ [l=gl] {87}
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "axuda" ## green_title ## h_help ##
+_httpiconhhelp_ [l=gl] {_httpimg_/gl/h\_help.gif}
+_widthhhelp_ [l=gl] {200}
+_heighthhelp_ [l=gl] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=gl] {Acerca desta colecciÃ³n}
+
+_textsubcols1_ [l=gl] {<p>A colecciÃ³n completa comprende _1_ subcolecciÃ³ns. As dispoÃ±ibles actualmente son:
+<blockquote>}
+
+_textsubcols2_ [l=gl] {</blockquote>
+Na pÃ¡xina de Preferencias pode vostede seleccionar (e cambiar) as
+subcolecciÃ³ns en uso.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "acerca de" ## green_title ## h_about ##
+_httpiconhabout_ [l=gl] {_httpimg_/gl/h\_about.gif}
+_widthhabout_ [l=gl] {200}
+_heighthabout_ [l=gl] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=gl] {TÃ­tulos A-Z}
+_texticonhcreat_ [l=gl] {Autores A-Z}
+_texticonhsubj_ [l=gl] {Materias}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=gl] {Datas}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=gl] {Nomes de ficheiros}
+_texticonhlang_ [l=gl] {Linguas}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=gl] {Para}
+_texticonhfrom_ [l=gl] {De}
+_texticonhser_ [l=gl] {Series}
+_texticonhhow_ [l=gl] {Como...}
+_texticonhorg_ [l=gl] {OrganizaciÃ³n}
+_texticonhbrwse_ [l=gl] {Navegar}
+_texticonhbrows_ [l=gl] {Navegar}
+_texticonhpeople_ [l=gl] {Persoas A-Z}
+_texticonhacronym_ [l=gl] {Siglas}
+_texticonhphrases_ [l=gl] {Frases}
+_texticonhartist_ [l=gl] {Artistas}
+_texticonhkw_ [l=gl] {Palabras clave}
+_texticonhvol_ [l=gl] {Volumes}
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=gl] {pechar esta secciÃ³n da biblioteca}
+_texticonclosedbookshelf_ [l=gl] {abrir esta secciÃ³n da biblioteca e ver o seu contido}
+_texticonopenbook_ [l=gl] {pechar este libro}
+_texticonclosedfolder_ [l=gl] {Abrir esta carpeta e ver o seu contido}
+_texticonclosedfolder2_ [l=gl] {abrir subsecciÃ³n: }
+_texticonopenfolder_ [l=gl] {pechar esta carpeta}
+_texticonopenfolder2_ [l=gl] {pechar subsecciÃ³n: }
+_texticonsmalltext_ [l=gl] {Ver esta secciÃ³n do texto}
+_texticonsmalltext2_ [l=gl] {ver texto: }
+_texticonpointer_ [l=gl] {secciÃ³n en curso}
+_texticondetach_ [l=gl] {Abrir esta PÃ¡xina nunha nova ventÃ¡}
+_texticonhighlight_ [l=gl] {Resaltar os termos da busca}
+_texticonnohighlight_ [l=gl] {Non resaltar os termos da busca}
+_texticoncontracttoc_ [l=gl] {Contraer o Ã­ndice de contido}
+_texticonexpandtoc_ [l=gl] {Expandir o Ã­ndice de contido}
+_texticonexpandtext_ [l=gl] {Mostrar o texto completo}
+_texticoncontracttext_ [l=gl] {Mostrar unicamente o texto da secciÃ³n seleccionada}
+_texticonwarning_ [l=gl] {<b>Advertencia: </b>}
+_texticoncont_ [l=gl] {Â¿desexa continuar?}
+
+_textltwarning_ [l=gl] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Expandir o texto aquÃ­ xerarÃ¡ unha gran
+cantidade de datos que o seu navegador terÃ¡ que procesar _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=gl] {ir Ã¡ pÃ¡xina}
+_textintro_ [l=gl] {<i>(texto introductorio)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tÃ­tulos a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=gl] {_httpimg_/gl/h\_title.gif}
+_widthhtitle_ [l=gl] {200}
+_heighthtitle_ [l=gl] {57}
+
+# Not true DC, kept for legacy reasons
+## "autores a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=gl] {_httpimg_/gl/h\_auth.gif}
+_widthhcreat_ [l=gl] {200}
+_heighthcreat_ [l=gl] {57}
+
+## "materias" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=gl] {_httpimg_/gl/h\_subj.gif}
+_widthhsubj_ [l=gl] {200}
+_heighthsubj_ [l=gl] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "datas" ## green_title ## h_date ##
+_httpiconhdate_ [l=gl] {_httpimg_/gl/h\_date.gif}
+_widthhdate_ [l=gl] {200}
+_heighthdate_ [l=gl] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "nomes de ficheiros" ## green_title ## h_src ##
+_httpiconhsrc_ [l=gl] {_httpimg_/gl/h\_src.gif}
+_widthhsrc_ [l=gl] {200}
+_heighthsrc_ [l=gl] {57}
+
+## "linguas" ## green_title ## h_lang ##
+_httpiconhlang_ [l=gl] {_httpimg_/gl/h\_lang.gif}
+_widthhlang_ [l=gl] {200}
+_heighthlang_ [l=gl] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "para" ## green_title ## h_to ##
+_httpiconhto_ [l=gl] {_httpimg_/gl/h\_to.gif}
+_widthhto_ [l=gl] {200}
+_heighthto_ [l=gl] {57}
+
+## "de" ## green_title ## h_from ##
+_httpiconhfrom_ [l=gl] {_httpimg_/gl/h\_from.gif}
+_widthhfrom_ [l=gl] {200}
+_heighthfrom_ [l=gl] {57}
+
+## "series" ## green_title ## h_ser ##
+_httpiconhser_ [l=gl] {_httpimg_/gl/h\_ser.gif}
+_widthhser_ [l=gl] {200}
+_heighthser_ [l=gl] {57}
+
+## "como..." ## green_title ## h_how ##
+_httpiconhhow_ [l=gl] {_httpimg_/gl/h\_how.gif}
+_widthhhow_ [l=gl] {200}
+_heighthhow_ [l=gl] {57}
+
+## "temas" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=gl] {_httpimg_/gl/h\_topic.gif}
+_widthhtopic_ [l=gl] {200}
+_heighthtopic_ [l=gl] {57}
+
+## "organizacion" ## green_title ## h_org ##
+_httpiconhorg_ [l=gl] {_httpimg_/gl/h\_org.gif}
+_widthhorg_ [l=gl] {250}
+_heighthorg_ [l=gl] {57}
+
+## "navegar" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=gl] {_httpimg_/gl/h\_brwse.gif}
+_widthhbrwse_ [l=gl] {200}
+_heighthbrwse_ [l=gl] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "persoas" ## green_title ## h_people ##
+_httpiconhpeople_ [l=gl] {_httpimg_/gl/h\_people.gif}
+_widthhpeople_ [l=gl] {200}
+_heighthpeople_ [l=gl] {57}
+
+## "siglas" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=gl] {_httpimg_/gl/h\_acro.gif}
+_widthhacronym_ [l=gl] {200}
+_heighthacronym_ [l=gl] {57}
+
+## "frases" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=gl] {_httpimg_/gl/h\_phrse.gif}
+_widthhphrse_ [l=gl] {200}
+_heighthphrse_ [l=gl] {57}
+
+## "artistas" ## green_title ## h_artist ##
+_httpiconhartist_ [l=gl] {_httpimg_/gl/h\_artist.gif}
+_widthhartist_ [l=gl] {200}
+_heighthartist_ [l=gl] {57}
+
+## "palabras clave" ## green_title ## h_kw ##
+_httpiconhkw_ [l=gl] {_httpimg_/gl/h\_kw.gif}
+_widthhkw_ [l=gl] {200}
+_heighthkw_ [l=gl] {57}
+
+## "volumes" ## green_title ## h_vol ##
+_httpiconhvol_ [l=gl] {_httpimg_/gl/h\_vol.gif}
+_widthhvol_ [l=gl] {200}
+_heighthvol_ [l=gl] {57}
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+## "Â¿DESEXA CONTINUAR?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=gl] {_httpimg_/gl/contof.gif}
+_httpiconconton_ [l=gl] {_httpimg_/gl/conton.gif}
+
+## "TEXTO\nCOMPLETO" ## document_button ## eallt ##
+_httpiconealltof_ [l=gl] {_httpimg_/gl/ealltof.gif}
+_httpiconeallton_ [l=gl] {_httpimg_/gl/eallton.gif}
+
+## "CONTRAER\nÃ­NDICE" ## document_button ## econc ##
+_httpiconeconcof_ [l=gl] {_httpimg_/gl/econcof.gif}
+_httpiconeconcon_ [l=gl] {_httpimg_/gl/econcon.gif}
+
+## "SEPARAR" ## document_button ## edtch ##
+_httpiconedtchof_ [l=gl] {_httpimg_/gl/edtchof.gif}
+_httpiconedtchon_ [l=gl] {_httpimg_/gl/edtchon.gif}
+
+## "EXPANDIR\nÃ­NDICE" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=gl] {_httpimg_/gl/eexpcof.gif}
+_httpiconeexpcon_ [l=gl] {_httpimg_/gl/eexpcon.gif}
+
+## "CONTRAER\nTEXTO" ## document_button ## etsec ##
+_httpiconetsecof_ [l=gl] {_httpimg_/gl/etsecof.gif}
+_httpiconetsecon_ [l=gl] {_httpimg_/gl/etsecon.gif}
+
+## "RESALTAR" ## document_button ## ehl ##
+_httpiconehlof_ [l=gl] {_httpimg_/gl/ehlof.gif}
+_httpiconehlon_ [l=gl] {_httpimg_/gl/ehlon.gif}
+
+## "NON\nRESALTAR" ## document_button ## enhl ##
+_httpiconenhlof_ [l=gl] {_httpimg_/gl/enhlof.gif}
+_httpiconenhlon_ [l=gl] {_httpimg_/gl/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=gl] {_If_(_thislast_,resultados _thisfirst_ - _thislast_ para a consulta:_cgiargq_,Non se atoparon resultados correspondentes Ã¡ consulta: _cgiargq_)}
+_textnoquerytitle_ [l=gl] {PÃ¡xina de busca}
+
+_texticonthispage_ [l=gl] {buscar}
+_textsome_ [l=gl] {algunhas das}
+_textall_ [l=gl] {todas as}
+_textboolean_ [l=gl] {boolean0}
+_textranked_ [l=gl] {ordenado}
+_textnatural_ [l=gl] {natural}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=gl] {}
+_texticonsearchhistorybar_ [l=gl] {historial de buscas}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=gl] {utilizar esta consulta}
+_textfreqmsg1_ [l=gl] {Palabras contadas: }
+_textpostprocess_ [l=gl] {_If_(_quotedquery_,<br><i>postprocesado para encontrar _quotedquery_</i>
+)}
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=gl] {MÃ¡is de }
+_textapprox_ [l=gl] {Acerca de }
+_textnodocs_ [l=gl] {Non hai documentos que correspondan Ã¡ consulta.}
+_text1doc_ [l=gl] {1 documento corresponde Ã¡ consulta.}
+_textlotsdocs_ [l=gl] {documentos corresponden Ã¡ consulta.}
+_textmatches_ [l=gl] {Resultados }
+_textbeginsearch_ [l=gl] {Iniciar a busca}
+_textrunquery_ [l=gl] {Executar a busca}
+_textclearform_ [l=gl] {Borrar o formulario}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=gl] {Palabra ou frase}
+_textinfield_ [l=gl] {... no campo}
+_textfoldstem_ [l=gl] {(maiÃºsculas e minÃºsculas, terminaciÃ³ns de palabras)}
+
+_textadvquery_ [l=gl] {Ou teclee directamente unha consulta:}
+_textallfields_ [l=gl] {Todos os campos}
+# -- Missing translation: _texttextonly_
+_textand_ [l=gl] {e}
+_textor_ [l=gl] {ou}
+_textandnot_ [l=gl] {e non}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=gl] {Buscar _indexselection__If_(_jselection_, de _jselection_)_If_(_nselection_, en idioma _nselection_) que conteÃ±an _querytypeselection_  palabras}
+
+_textadvancedsearch_ [l=gl] {Buscar _indexselection__If_(_jselection_, de _jselection_)_If_(_nselection_, en idioma _nselection_) utilizando a consulta _querytypeselection_}
+
+_textformsimplesearch_ [l=gl] {Buscar _If_(_jselection_, _jselection_) _If_(_gformselection_, at _gformselection_
+level) _If_(_nselection_, in _nselection_ language) que conteÃ±an
+_formquerytypeselection_ de}
+
+_textformadvancedsearch_ [l=gl] {Buscar _If_(_jselection_,_jselection_) _If_(_gformselection_,
+at _gformselection_ level)_If_(_nselection_, in _nselection_ language) e
+ presentar os resultados por orde _formquerytypeselection_ }
+
+
+# -- Missing translation: _textnojsformwarning_
+_textdatesearch_ [l=gl] {<p>Podense buscar nesta colecciÃ³n
+documentos comprendidos nun intervalo de datas, ou documentos que
+conteÃ±an unha data en particular. Esta Ã© unha caracterÃ­stica
+facultativa da busca.}
+_textstartdate_ [l=gl] {Data inicial (ou Ãºnica):}
+_textenddate_ [l=gl] {Data final:}
+_textbc_ [l=gl] {Antes da nosa era}
+_textad_ [l=gl] {Da nosa era}
+_textexplaineras_ [l=gl] {"Da nosa era" e "Antes da nosa era" son formas alternativas de expresar "despois de Cristo" e "antes de Cristo", respectivamente. Son expresiÃ³ns con menos connotaciÃ³ns culturais}
+
+_textstemon_ [l=gl] {(ignorar as terminaciÃ³ns das palabras)}
+
+_textsearchhistory_ [l=gl] {Historial de buscas}
+
+#text macros for search history
+_textnohistory_ [l=gl] {Non estÃ¡ disponible o historial de buscas}
+_texthresult_ [l=gl] {resultado}
+_texthresults_ [l=gl] {resultados}
+_texthallwords_ [l=gl] {todas as palabras}
+_texthsomewords_ [l=gl] {algunhas palabras}
+_texthboolean_ [l=gl] {booleano}
+_texthranked_ [l=gl] {ordenado}
+_texthcaseon_ [l=gl] {ter en conta maiÃºsculas e minÃºsculas}
+_texthcaseoff_ [l=gl] {non ter en conta maiÃºsculas e minÃºsculas}
+_texthstemon_ [l=gl] {non ter en conta as terminaciÃ³ns das palabras}
+_texthstemoff_ [l=gl] {ter en conta as terminaciÃ³ns das palabras}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "buscar" ## green_title ## h_search ##
+_httpiconhsearch_ [l=gl] {_httpimg_/gl/h\_search.gif}
+_widthhsearch_ [l=gl] {200}
+_heighthsearch_ [l=gl] {57}
+
+## "resultados" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=gl] {_httpimg_/gl/qryresb.gif}
+_widthqryresb_ [l=gl] {_pagewidth_}
+_heightqryresb_ [l=gl] {17}
+
+## "historial" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=gl] {_httpimg_/gl/schhistb.gif}
+_widthsrchhistb_ [l=gl] {_pagewidth_}
+_heightsrchhistb_ [l=gl] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=gl] {As preferencias fixÃ¡ronse da seguinte maneira. Non prema o botÃ³n "AtrÃ¡s" do seu navegador, porque non quedarÃ­an gravadas.
+Utilice mellor un dos botÃ³ns da barra de acceso superior.
+}
+_textsetprefs_ [l=gl] {fixar preferencias}
+_textsearchprefs_ [l=gl] {Preferencias de busca}
+_textcollectionprefs_ [l=gl] {Preferencias de colecciÃ³n}
+_textpresentationprefs_ [l=gl] {Preferencias de presentaciÃ³n}
+_textpreferences_ [l=gl] {Preferencias}
+_textcasediffs_ [l=gl] {RecoÃ±ecemento de maiÃºsculas e minÃºsculas:}
+_textignorecase_ [l=gl] {ignorar diferencias entre maiÃºsculas e minÃºsculas}
+_textmatchcase_ [l=gl] {deben corresponder maiÃºsculas e minÃºsculas}
+_textwordends_ [l=gl] {TerminaciÃ³ns das palabras:}
+_textstem_ [l=gl] {ignorar as terminaciÃ³ns das palabras}
+_textnostem_ [l=gl] {debe corresponder a palabra completa}
+_textprefop_ [l=gl] {Presentar ata _maxdocoption_ resultados con _hitsperpageoption_ resultados por pÃ¡xina.}
+_textextlink_ [l=gl] {Acceder a PÃ¡xinas Web externas: }
+_textintlink_ [l=gl] {Documentos fonte recuperados de:}
+_textlanguage_ [l=gl] {Idioma da interface: }
+_textencoding_ [l=gl] {CodificaciÃ³n: }
+_textformat_ [l=gl] {Formato da interface: }
+_textall_ [l=gl] {todos}
+_textquerymode_ [l=gl] {Tipo de busca:}
+_textsimplemode_ [l=gl] {busca simple}
+_textadvancedmode_ [l=gl] {busca avanzada (permite efectuar buscas booleanas utilizando os caracteres !, &, | e os parÃ©nteses)}
+_textlinkinterm_ [l=gl] {a travÃ©s dunha pÃ¡xina intermedia}
+_textlinkdirect_ [l=gl] {ir directamente aÃ­}
+_textdigitlib_ [l=gl] {a biblioteca dixital}
+_textweb_ [l=gl] {o Web}
+_textgraphical_ [l=gl] {GrÃ¡fico}
+_texttextual_ [l=gl] {Textual}
+_textcollectionoption_ [l=gl] {<p>
+SubcolecciÃ³ns para incluÃ­r:
+<br>}
+
+_textrelateddocdisplay_ [l=gl] {mostrar documentos relacionados }
+_textsearchhistory_ [l=gl] {Historial de buscas:}
+_textnohistory_ [l=gl] {O historial de buscas non estÃ¡ dispoÃ±ible }
+_texthistorydisplay_ [l=gl] {mostrar as _historynumrecords_ Ãºltimas buscas}
+_textnohistorydisplay_ [l=gl] {non mostrar o historial de buscas }
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=gl] {busca con formulario}
+# -- Missing translation: _textplainsearch_
+_textqueryboxsize_ [l=gl] {TamaÃ±o do cadro de busca:}
+_textregbox_ [l=gl] {cadro de busca normal}
+_textbigbox_ [l=gl] {cadro de busca grande}
+_textformtype_ [l=gl] {Tipo de formulario:}
+_textsimple_ [l=gl] {simple}
+_textadvanced_ [l=gl] {avanzado}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=gl] {con}
+_textfields_ [l=gl] {campos}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferencias" ## green_title ## h_pref ##
+_httpiconhpref_ [l=gl] {_httpimg_/gl/h\_pref.gif}
+_widthhpref_ [l=gl] {200}
+_heighthpref_ [l=gl] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=gl] {Ordenar os documentos por}
+_textalsoshowing_ [l=gl] {mostra tamÃ©n}
+_textwith_ [l=gl] {cun mÃ¡ximo de}
+_textdocsperpage_ [l=gl] {documentos por pÃ¡xina}
+
+_textfilterby_ [l=gl] {Buscar documentos que conteÃ±an}
+_textall_ [l=gl] {todas as}
+_textany_ [l=gl] {algunhas das}
+_textwords_ [l=gl] {as palabras}
+_textleaveblank_ [l=gl] {deixar este cadro baleiro para obter todos os documentos}
+
+_browsebuttontext_ [l=gl] {"Ordenar os documentos"}
+
+_nodata_ [l=gl] {<i>sen datos</i>}
+_docs_ [l=gl] {documentos}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=gl] {Axuda}
+_textSearchshort_ [l=gl] {buscar determinadas palabras}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por tÃ­tulo}
+_textCreatorshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por autor}
+_textSubjectshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por materia}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por data}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por nome de ficheiro}
+_textLanguageshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por lingua}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por series}
+_textToshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por campo "para:"}
+_textFromshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por campo "de:"}
+_textBrowseshort_ [l=gl] {Lista das publicaciÃ³ns}
+_textOrganizationshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por OrganizaciÃ³n}
+_textHowtoshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por lista de "Como..."}
+_textTopicshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por tema}
+_textPeopleshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por persoas}
+_textAcronymshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por apariciÃ³n de siglas}
+_textPhraseshort_ [l=gl] {Lista das frases que aparecen nas publicaciÃ³ns}
+_textArtistshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por artista}
+_textKeywordshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por palabra clave}
+_textVolumeshort_ [l=gl] {Acceder Ã¡s publicaciÃ³ns por volume}
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=gl] {ClasificaciÃ³n non definida}
+
+_textSearchlong_ [l=gl] {<p>PÃ³dese <i>buscar determinadas
+palabras</i> que aparecen no texto desde a pÃ¡xina de "busca". Esta
+Ã© a primeira pÃ¡xina que aparece Ã³ principio e Ã¡ que se pode
+acceder desde outras pÃ¡xinas pulsando o botÃ³n <i>buscar</i>. }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+tÃ­tulo</i> pulsando o botÃ³n <i>tÃ­tulos a-z</i>. O resultado serÃ¡ unha
+lista de libros por orde alfabÃ©tica. }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=gl] {<p>PÃ³dese <i>acceder as publicaciÃ³ns por
+autor</i> pulsando o botÃ³n <i>autores a-z</i>. O resultado serÃ¡ unha
+lista de libros ordenados por nome do autor. }
+
+_textSubjectlong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns
+por materia</i> presionando o botÃ³n de <i>materias</i>. O resultado serÃ¡ unha
+lista de materias, representadas por librerÃ­as. }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+data</i> pulsando o botÃ³n <i>datas</i>. O resultado serÃ¡ unha lista
+de todas las publicaciÃ³ns, ordenadas cronoloxicamente. }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+nome de ficheiro</i> pulsando o botÃ³n <i>nomes de ficheiros</i>. O
+resultado serÃ¡ unha lista ordenada por nome de ficheiro orixinal. }
+
+_textLanguagelong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+lingua</i> presionando o botÃ³n <i>linguas</i>. O resultado serÃ¡ una
+lista ordenada por lingua. }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns
+por organizaciÃ³n</i> pulsando o botÃ³n <i>organizaciÃ³n</i>. O resultado
+serÃ¡ unha lista de organizaciÃ³ns. }
+
+_textHowtolong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por unha
+lista de "como..."</i> pulsando o botÃ³n <i>como</i>.
+O resultado serÃ¡ unha lista de categorÃ­as "como...". }
+
+_textTopiclong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+tema</i> pulsando o botÃ³n <i>tema</i>. O resultado serÃ¡ unha lista de
+temas. }
+
+_textTolong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns polo
+campo "Para:"</i> pulsando o botÃ³n <i>para</i>. O resultado serÃ¡ unha lista de
+destinatarios. }
+
+_textFromlong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns polo
+campo "De:"</i> pulsando o botÃ³n <i>de</i>. O resultado serÃ¡ unha lista
+de remitentes. }
+
+_textSerieslong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+series</i> pulsando o botÃ³n <i>series</i>. O resultado serÃ¡ unha lista
+das series que se atopen na colecciÃ³n. }
+
+_textBrowselong_ [l=gl] {<p>PÃ³dese <i>navegar nas publicaciÃ³ns</i>
+pulsando o botÃ³n <i>navegar</i>. }
+
+_textPeoplelong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+persoas</i> pulsando o botÃ³n <i>persoas a-z</i>. O resultado serÃ¡ una
+lista ordenada por apelido. }
+
+_textAcronymlong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+apariciÃ³n de siglas</i> pulsando o botÃ³n <i>siglas</i>. O resultado
+serÃ¡ unha lista de siglas e os lugares onde aparecen. }
+
+_textPhraselong_ [l=gl] {<p>PÃ³dese <i>navegar nas frases que aparecen
+nas publicaciÃ³ns</i> pulsando o botÃ³n <i>frases</i>. UtilizÃ¡ndose o navegador "phind phrase". }
+
+_textArtistlong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+artista</i> pulsando o botÃ³n <i>artistas</i>. O resultado serÃ¡ unha
+lista ordenada por nome do artista. }
+
+_textKeywordlong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+palabra clave</i> pulsando o botÃ³n <i>palabras clave</i>. O resultado
+serÃ¡ unha lista de palabras clave. }
+
+_textVolumelong_ [l=gl] {<p>PÃ³dese <i>acceder Ã¡s publicaciÃ³ns por
+volume</i> pulsando o botÃ³n <i>volumes</i>. O resultado
+serÃ¡ unha lista de volumes. }
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=gl] {<p>Prema o botÃ³n <i>descoÃ±ecido</i> para
+consultar as publicaciÃ³ns (a lista ordÃ©nase segundo un campo
+descoÃ±ecido). }
+
+_texthelptopics_ [l=gl] {<h2 align=left>Temas</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Â¿Como buscar determinadas palabras?</a>
+<ul>
+  <li><a href="\#query-terms">Termos da busca</a>
+  <li><a href="\#query-type">Tipo de consulta</a>
+  <li><a href="\#scope-of-queries">Campo de acciÃ³n das buscas</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Preferencias de colecciÃ³n</a>
+  <li><a href="\#lang-prefs">Preferencias de lingua</a>
+  <li><a href="\#pres-prefs">Preferencias de presentaciÃ³n</a>
+  <li><a href="\#search-prefs">Preferencias de busca</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=gl] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=gl] {Â¿Como ler os documentos?}
+
+_texthelpreadingdocs_ [l=gl] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p> Cando aparece en pantalla un documento individual, o seu tÃ­tulo e o seu
+autor pÃ³dense ver na parte superior esquerda da pÃ¡xina. Ã³ lado
+destes pÃ³dese ver
+o nÃºmero da pÃ¡xina en curso, un cadro que permite seleccionar unha nova pÃ¡xina e
+as frechas que permiten pasar Ã¡ pÃ¡xina seguinte ou Ã¡ anterior.
+
+<p>Abaixo aparece o texto da secciÃ³n en curso. Ã³ final da lectura, pÃ³dense
+empregar as frechas que estÃ¡n na parte inferior para pasar Ã¡ secciÃ³n seguinte ou
+Ã¡ anterior.
+
+<p>Debaixo do tÃ­tulo e autor hai tres botÃ³ns. Prema <i>texto completo</i> para
+ver todo o texto do documento en curso. Â¡Se o documento Ã© grande, pode levar
+moito tempo e facer uso de moita memoria! Prema <i>separar</i> para crear unha
+nova ventÃ¡ no seu navegador para este documento (esto Ã© Ãºtil se desexa comparar
+documentos ou ler dous Ã¡ vez.) Por Ãºltimo, cando se fai unha busca, as palabras
+buscadas aparecen resaltadas. Prema <i>sen resaltar</i> para eliminar esto.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Prema a frecha
+para ir Ã¡ secciÃ³n seguinte ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>...ou regresar Ã¡ secciÃ³n anterior</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img
+src="_document:httpiconetsecof_" border="0"></td><td>Abrir ou non o texto completo</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Abrir esta
+pÃ¡xina nunha nova ventÃ¡</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Resaltar ou non os termos buscados</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=gl] {<h2>Â¿CÃ³mo buscar determinadas palabras?</h2>
+
+<p>Desde a pÃ¡xina de busca, pÃ³dese facer unha consulta seguindo
+estes pasos:
+
+<ol>
+
+<li>Especificar quÃ© documentos quere buscar
+
+<li>Indicar se quere buscar todas as palabras o sÃ³ algunhas
+
+<li>Escribir as palabras que quere buscar
+
+<li>Pulsar o botÃ³n <i>Iniciar a busca</i>
+
+</ol>
+
+<p> Cando se fai unha consulta, aparecen os tÃ­tulos dos vinte primeiros
+documentos correspondentes. Ã³ final da lista hai un botÃ³n que permite acceder Ã³s
+vinte seguintes, e asÃ­ sucesivamente. Prema o tÃ­tulo de calquer documento ou no
+botonciÃ±o que aparece Ã³ lado.
+
+<p>O nÃºmero mÃ¡ximo de documentos obtidos Ã© 100. Pode cambiar este nÃºmero
+pulsando o botÃ³n <i>preferencias</i> na parte superior da pÃ¡xina.
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Termos da busca</h3>
+
+<p> O que se dixita no cadro de consulta interprÃ©tase como unha lista de
+palabras chamadas "termos da busca". Cada termo debe conter somente letras e
+dÃ­xitos. Os termos sepÃ¡ranse por un espacio en branco. Se aparecen outros
+caracteres, coma os de puntuaciÃ³n, interprÃ©tanse como espacios e a busca non os
+ten en conta. Non se poden efectuar buscas con palabras que inclÃºan puntuaciÃ³n.
+
+
+<p>Por exemplo, a consulta:<p>
+
+<ul><kbd>Agro-forestry in the Pacific Islands: Systems for
+Sustainability (1993)</kbd></ul>
+
+<p>tratarÃ¡se de igual xeito que:<p>
+
+<ul><kbd>Agro forestry in the Pacific Islands Systems for Sustainability
+1993</kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Tipo de consulta</h3>
+
+<p>Existen dous tipos de consulta.
+
+<ul>
+
+<li>busca de <b>todas</b> as palabras. BÃºscanse os documentos que
+conteÃ±en todas as palabras especificadas. Os documentos que respondan
+Ã¡ consulta presÃ©ntanse por orde alfabÃ©tica.
+
+<li>busca de <b>algunha(s)</b> palabra(s). Basta con enumerar os termos que
+poden aparecer nos documentos buscados. os documentos aparecerÃ¡n nunha orde que
+corresponde Ã³ seu grao de pertinencia con respecto Ã¡ consulta. Para determinar o
+grao de pertinencia aplÃ­canse os criterios seguintes:
+
+<ul>
+
+<li>cantos mÃ¡is termos buscados conteÃ±a o documento, maior serÃ¡ a sÃºa
+pertinencia;
+
+<li>os termos pouco usuais consideraranse mÃ¡is importantes cÃ³s
+comÃºns;
+
+<li>os documentos mÃ¡is curtos consideraranse mÃ¡is pertinentes cÃ³s
+documentos mÃ¡is voluminosos.
+
+</ul>
+
+</ul>
+
+<p>Pode utilizar tantos termos de busca como desexe: unha oraciÃ³n
+completa, ou incluso un parÃ¡grafo enteiro.  Se sÃ³ se especifica un
+termo, os documentos ordenaranse por frecuencia de apariciÃ³n do
+termo buscado.
+
+<p>_texthelpscope_
+
+}
+
+_textdatesearch_ [l=gl] {Buscar con datas}
+
+_texthelpdatesearch_ [l=gl] {<h2>_textdatesearch_</h2>
+
+<p>A busca por data permite atopar documentos que, ademais de corresponder Ã³s
+criterios de busca, fan referencia a acontecementos situados nun intervalo de
+tempo determinado. PÃ³dense buscar documentos relativos a un ano en particular ou
+comprendidos nun intervalo particular de anos. ObsÃ©rvese que non Ã© necesario
+proporcionar termos de busca, pÃ³dese buscar unicamente por data. Tampouco Ã©
+preciso indicar datas na busca: se non se indica ningunha data Ã© como se non
+existise a busca por data.
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3> CÃ³mo utilizar esta funciÃ³n:</h3>
+
+<ul>
+
+<li>Para buscar documentos referentes a un ano en particular:
+
+<ul>
+
+<li>Teclear os termos da busca coma sempre.
+
+<li>Indicar o ano desexado no  cadro "Data inicial (ou Ãºnica)".
+
+<li> Se a data Ã© anterior Ã¡ nosa era (antes de Cristo), hai que
+escoller a opciÃ³n "
+antes da nosa era" no menÃº situado cerca dese cadro.
+
+<li>Iniciar a busca coma sempre.
+
+</ul>
+
+<li>Para buscar documentos referentes a un perÃ­odo ou a un intervalo de
+anos:
+
+<ul>
+
+<li>Teclear os termos da busca coma sempre.
+
+<li>Indicar o ano inicial no cadro "Data inicial (ou Ãºnica)".
+
+<li>Indicar o ano final no cadro "Data final".
+
+<li>Seleccionar a opciÃ³n "antes da nosa era" no menÃº situado
+cerca do cadro onde se teclea a data anterior Ã¡ nosa era (antes
+de Cristo).
+
+<li>Iniciar a busca como sempre.
+
+</ul>
+
+</ul>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>Como interpretar os resultados das buscas</h3>
+
+<p> Xeralmente, unha  busca de documentos referentes Ã³ ano 1903 non permitirÃ¡
+obter documentos que, por exemplo, tratan de libros escritos no 1903, senÃ³n sÃ³
+documentos referentes Ã³ ano 1903. Sen embargo, dado o xeito no que se buscan as
+datas dos documentos, obteranse documentos referentes a un intervalo de anos (por
+exemplo 1899-1911) que  comprende o ano 1903 (por exemplo o sÃ©culo XX, ou o
+sÃ©culo vinte). Esto significa que, para algÃºns documentos, as datas indicadas na
+busca non aparecerÃ¡n realmente no texto do documento. Para unha busca por
+intervalo de tempo, todo o anterior aplÃ­case a todas as datas do intervalo.
+
+}
+
+_textchangeprefs_ [l=gl] {Cambio de preferencias}
+
+_texthelppreferences_ [l=gl] {<h2>_textchangeprefs_</h2>
+
+<p> Se desexa cambiar algunhas caracterÃ­sticas da interface para adaptala Ã¡s sÃºas
+propias necesidades, prema o botÃ³n <i>preferencias</i> situado na parte superior
+da pÃ¡xina.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Preferencias da colecciÃ³n</h3>
+<p>
+Algunhas colecciÃ³ns compÃ³Ã±ense de varias subcolecciÃ³ns, nas cales se poden
+efectuar operaciÃ³ns de busca de forma individual ou no seu conxunto, coma un
+todo. Se o desexa, pode vostede seleccionar na pÃ¡xina de <i>preferencias</i> quÃ©
+subcolecciÃ³ns incluÃ­r nas sÃºas buscas.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Preferencias de lingua</h3>
+<p> Cada colecciÃ³n ten unha lingua de presentaciÃ³n por defecto, pero se o desexa
+pode vostede cambiar de idioma. Pode modificar tamÃ©n o sistema de codificaciÃ³n
+que utiliza Greenstone: o programa Greenstone soe escoller os parÃ¡metros
+por defecto, pero con algÃºns navegadores pÃ³dense conseguir mellores resultados
+grÃ¡ficos cambiando de sistema de codificaciÃ³n. En todas as colecciÃ³ns pÃ³dese
+escoller entre unha interface grÃ¡fica normalizada e unha interface textual. Ã©sta
+resulta especialmente Ãºtil para os usuarios con problemas de vista que utilizan
+tipos de letra grandes ou para a saÃ­da a sintetizadores de voz.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Preferencias de presentaciÃ³n</h3>
+
+<p>SegÃºn a colecciÃ³n, pÃ³dense especificar varias opciÃ³ns que controlan
+a presentaciÃ³n.
+
+<p> As colecciÃ³ns de pÃ¡xinas Web permiten eliminar a barra de navegaciÃ³n de
+Greenstone que aparece na parte superior de cada pÃ¡xina dun documento, de tal
+modo que unha vez terminada a busca visualÃ­zase directamente a pÃ¡xina
+correspondente sen os encabezados de Greenstone. Para efectuar outra busca terÃ¡
+que utilizar o botÃ³n "AtrÃ¡s" do seu navegador. Estas colecciÃ³ns permÃ­tenlle
+tamÃ©n eliminar a mensaxe de advertencia de Greenstone que aparece cando un
+hipervinculo apunta fora da colecciÃ³n da biblioteca dixital. Nalgunhas
+colecciÃ³ns de pÃ¡xinas Web pÃ³dese determinar tamÃ©n se os enlaces que aparecen na
+pÃ¡xina de "Resultados da busca" remitirÃ¡n directamente Ã³ URL en cuestiÃ³n ou Ã¡
+copia da pÃ¡xina que estÃ¡ na biblioteca dixital.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Preferencias de busca</h3>
+
+Dous pares de botÃ³ns controlan a diferencia entre maiÃºsculas e minÃºsculas e as
+raÃ­ces das buscas que fai. O primeiro conxunto de botÃ³ns controlan se deben
+coincidir maiÃºsculas ou minÃºsculas. O segundo conxunto controla se se ignoran ou
+non as terminaciÃ³ns das palabras na busca.
+
+<p> Por exemplo, se se activan os botÃ³ns <i>ignorar diferencias entre
+maiÃºsculas e minÃºsculas</i> e <i>ignorar terminaciÃ³ns de palabras</i>, a busca:
+
+<p><ul><kbd>African building</kbd></ul>
+
+<p>tratarase do mesmo modo que:
+
+<p><ul><kbd>africa builds</kbd></ul>
+
+<p>porque a letra maiÃºscula de "African" transformarase en minÃºscula e
+os sufixos "n" e "ing" eliminaranse de "African" e "building",
+respectivamente (suprimirase tamÃ©n a "s" de "builds").
+
+<p>PÃ³dese tamÃ©n optar polo modo de busca "avanzado" que permite combinar termos
+utilizando os operadores booleanos AND (&), OR (|), y NOT (!). Esto
+permitiralle efectuar buscas mÃ¡is precisas. PÃ³dese activar o historial de buscas,
+no que aparecen as Ãºltimas buscas efectuadas. Esto facilita a repeticiÃ³n de
+versiÃ³ns levemente modificadas de buscas anteriores.
+
+<p>Por Ãºltimo, pÃ³dese controlar o nÃºmero de acertos obtidos e a sÃºa
+presentaciÃ³n en pantalla.
+
+}
+
+_texttanumbrowseoptions_ [l=gl] {Existen _numbrowseoptions_ maneira(s) de atopar informaciÃ³n
+nesta colecciÃ³n:}
+
+_textsimplehelpheading_ [l=gl] {Â¿CÃ³mo encontrar informaciÃ³n?}
+
+_texthelpscope_ [l=gl] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Campo de acciÃ³n das buscas</h3>
+
+<p>Na maiorÃ­a das colecciÃ³ns pode vostede escoller diferentes Ã­ndices para a
+busca. Por exemplo, pode haber Ã­ndices por autor ou por tÃ­tulo. TamÃ©n pode haber
+Ã­ndices por capÃ­tulo ou por parÃ¡grafo. Normalmente obtense o documento
+correspondente sexa o que for o Ã­ndice utilizado.
+
+<p>Se os documentos son libros, estos abriranse no lugar
+adecuado.
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/galician2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/galician2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/galician2.dm	(revision 10506)
@@ -0,0 +1,1285 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# English Language text and icon macros
+# -- this file contains english text that is of less importance
+# -- to translate when creating a new interface language
+#
+#   TraducciÃ³n Ã³ galego feita for XaquÃ­n Lores xaquin@udc.es
+#
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=gl] {documentos. }
+_lastupdate_ [l=gl] {Ãºltima actualizaciÃ³n }
+_ago_ [l=gl] {dÃ­as.}
+_colnotbuilt_ [l=gl] {ColecciÃ³n non creada.}
+
+_textpagetitle_ [l=gl] {Biblioteca Dixital Greenstone}
+_textadmin_ [l=gl] {PÃ¡xina de administraciÃ³n}
+_textabgs_ [l=gl] {Acerca de Greenstone}
+_textgsdocs_ [l=gl] {DocumentaciÃ³n de Greenstone}
+
+_textimagegli_ [l=gl] {AxÃºdalle a crear novas colecciÃ³ns, modificar ou suprimir colecciÃ³ns existentes,
+ou engadir documentos nunha colecciÃ³n.
+}
+
+# -- Missing translation: _textimagecollector_
+
+# -- Missing translation: _textimagetranslator_
+
+_textimageadmin_ [l=gl] {PermÃ­telle engadir novos usuarios, dÃ¡ un resume das colecciÃ³ns que hai no
+sistema e proporciona informaciÃ³ns tÃ©cnicas sobre a instalaciÃ³n de Greenstone.
+}
+
+_textimagegogreenstone_ [l=gl] {ProporciÃ³nalle informaciÃ³n sobre o programa Greenstone e o proxecto de biblioteca
+Dixital de Nova Celandia, de onde provÃ©n
+}
+
+_textimagegodocs_ [l=gl] {Manuais de Greenstone}
+
+_textpoem_ [l=gl] {<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+
+<p>que a paz e a tranquilidade te rodeen,
+<br>que vivas no calor dunha calixe estival,
+<br>que o ocÃ©ano das tÃºas viaxes sexa liso como a pedra verde pulida.
+
+}
+
+_textgreenstone_ [l=gl] {<p>Greenstone (pedra verde) Ã© unha pedra semipreciosa que, como este programa
+provÃ©n de Nova Celandia. Na sociedade maorÃ­ tradicional era a materia mÃ¡is
+prezada e buscada. Este pedra ten o poder de absorber e encerrar o <i>wairua</i>
+que Ã© o espÃ­rito da forza da vida e estÃ¡ dotada de virtudes tradicionais que
+fan dela un emblema moi axeitado para un proxecto de biblioteca dixital de
+dominio pÃºblico. o seu lustre simboliza a caridade; a sÃºa transparencia, a
+honradez; a sÃºa dureza, o coraxe e o gume que pode coller, a xustiza.
+O obxecto tallado utilizado como emblema do programa Greenstone Ã© un <i>patu</i>,
+unha maza de combate. Esta arma de combate Ã© unha reliquia da familia dun dos
+membros do noso proxecto. No combate corpo a corpo, o seu lanzamento Ã©
+moi rÃ¡pido, preciso e definitivo. GÃºstanos pensar que esas calidades tamÃ©n se
+aplican Ã³ noso programa e que o afiado gume do <i>patu</i> simboliza a punta de
+lanza da tecnoloxÃ­a
+
+}
+
+_textaboutgreenstone_ [l=gl] {<p>Greenstone Ã© un conxunto de programas informÃ¡ticos destinado Ã¡ creaciÃ³n e
+difusiÃ³n de colecciÃ³ns documentais electrÃ³nicas que fornece unha nova forma de
+organizar a informaciÃ³n e publicala en Internet ou en CD-ROM. Greenstone Ã©
+producido polo <b> Proxecto de Biblioteca Dixital de Nova Celandia</b> da <b>
+Universidade de Waikato</b>, este producto distribÃºese en colaboraciÃ³n coa <b>
+UNESCO</b> e a <b>ONG Human Info</b>. Ã© un programa de cÃ³digo fonte aberto, que
+pode descarregarse no enderezo <a href="http://greenstone.org">http://greenstone.
+org</a> segundo as condiciÃ³ns estipuladas na Licencia PÃºblica Xeral de GNU.
+
+<p>A finalidade deste programa Ã© que os usuarios, en particular nas universidades,
+bibliotecas e outros establecementos pÃºblicos, poidan crear as sÃºas propias
+bibliotecas dixitais. As bibliotecas dixitais estÃ¡n transformando radicalmente
+o mÃ©todo de distribuciÃ³n e adquisiciÃ³n de coÃ±ecementos utilizado pola UNESCO
+cos seus interlocutores nas esferas da educaciÃ³n, a ciencia, e a cultura  en
+todo o mundo, a particularmente nos paÃ­ses en desenvolvemento. Agardamos que
+este programa contribÃºa a fomentar a creaciÃ³n e difusiÃ³n de bibliotecas
+dixitais co fin de compartir a informaciÃ³n e poÃ±ela a disposiciÃ³n do pÃºblico en
+xeral.
+
+<p>Este programa elabÃ³rase e distribÃºese gracias Ã³ esforzo de colaboraciÃ³n
+internacional iniciado en Agosto de 2000 por tres participantes:
+
+<table border="0">
+<tr valign="top">
+<td>
+O proxecto <a href="http://nzdl.org"><b>Biblioteca Dixital de
+Nova Celandia na Universidade de Waikato</b></a>
+<br>
+
+O programa Greenstone naceu deste proxecto e a iniciativa recibiu o respaldo da
+SubcomisiÃ³n de ComunicaciÃ³n da ComisiÃ³n Nacional Neocelandesa para a UNESCO,
+como parte da contribuciÃ³n de Nova Celandia Ã³ programa da UNESCO.
+</td>
+<td></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://www.unesco.org"><b>OrganizaciÃ³n das NaciÃ³ns Unidas
+para a ComunicaciÃ³n, a Ciencia e a Cultura</b></a>
+<br>
+
+A difusiÃ³n mundial de informaciÃ³n en materia de educaciÃ³n, ciencia e cultura, en
+particular nos paÃ­ses en desenvolvemento, Ã© un dos cometidos principais  do
+programa intergubernamental da UNESCO "InformaciÃ³n para todos". Por outra parte,
+considÃ©rase que unha tecnoloxÃ­a da informaciÃ³n e a comunicaciÃ³n apropiada e
+accesible constitÃºe un instrumento esencial a este proxecto.
+
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/unesco.gif"
+border="0"></a></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://humaninfo.org"><b>A ONG Human Info, con sede en Amberes,
+BÃ©lxica</b></a>
+<br>
+
+Este proxecto, que traballa con Axencias de NaciÃ³ns Unidas e outras ONG, fÃ­xose
+unha reputaciÃ³n a nivel mundial na dixitalizaciÃ³n de documentos relativos o
+desenvolvemento humano, e a sÃºa difusiÃ³n, gratuÃ­ta nos paises en desenvolvemento
+e a prezo de custo nos demais paÃ­ses.
+
+</td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "seleccionar unha colecciÃ³n" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ [l=gl] {_httpimg_/gl/selcolgr.gif}
+_widthselcolgr_ [l=gl] {537}
+_heightselcolgr_ [l=gl] {17}
+_altselcolgr_ [l=gl] {"Seleccionar unha colecciÃ³n"}
+
+
+# -- Missing translation: cgli
+# -- Missing translation: _httpiconcgliof_
+# -- Missing translation: _httpiconcglion_
+# -- Missing translation: _widthcgli_
+
+# -- Missing translation: ccol
+# -- Missing translation: _httpiconccolof_
+# -- Missing translation: _httpiconccolon_
+# -- Missing translation: _widthccol_
+
+# -- Missing translation: ctrans
+# -- Missing translation: _httpiconctransof_
+# -- Missing translation: _httpiconctranson_
+# -- Missing translation: _widthctrans_
+
+# -- Missing translation: cadmin
+# -- Missing translation: _httpiconcadminof_
+# -- Missing translation: _httpiconcadminon_
+# -- Missing translation: _widthcadmin_
+
+# -- Missing translation: cabgs
+# -- Missing translation: _httpiconcabgsof_
+# -- Missing translation: _httpiconcabgson_
+# -- Missing translation: _widthcabgs_
+
+# -- Missing translation: cgsdoc
+# -- Missing translation: _httpiconcgsdocof_
+# -- Missing translation: _httpiconcgsdocon_
+# -- Missing translation: _widthcgsdoc_
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=gl] {Hai outros catro botÃ³ns na pÃ¡xina principal }
+
+_textnocollections_ [l=gl] {<p>Non hai actualmente ningunha colecciÃ³n dispoÃ±ible para esta instalaciÃ³n de
+Greenstone. Para engadir colecciÃ³ns, vostede pode:
+
+<ul>
+
+<li>utilizar o Coleccionista para crear novas colecciÃ³ns
+
+<li>ou ben instalar colecciÃ³ns a partir do CD-ROM de Greenstone, se dispÃ³n dun
+
+</ul>
+
+}
+
+_text1coll_ [l=gl] {Esta instalaciÃ³n de Greenstone contÃ©n 1 colecciÃ³n }
+
+_textmorecolls_ [l=gl] {Esta instalaciÃ³n de Greenstone contÃ©n _1_ colecciÃ³ns }
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=gl] {Enlace externo }
+_textlinknotfound_ [l=gl] {Non se atopou o enlace interno }
+
+_textextlinkcontent_ [l=gl] {O enlace que vostede seleccionou Ã© externo a todas as colecciÃ³ns actualmente
+seleccionadas. Se desexa de todos os xeitos activas este enlace e se o seu
+navegador estÃ¡ conectado a internet, pode vostede  <a
+href="_nexturl_">acceder</a> a esta pÃ¡xina; en caso contrario, prema o botÃ³n "
+AtrÃ¡s" do seu navegador para volver Ã³ documento anterior.
+
+}
+
+_textlinknotfoundcontent_ [l=gl] {O enlace interno que vostede seleccionou non existe. Esto dÃ©bese probablemente a
+un erro na colecciÃ³n fonte. Prema o botÃ³n "AtrÃ¡s" do seu navegador para volver Ã³
+documento anterior.
+
+}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=gl] {<h3>Enlace coa colecciÃ³n "_2_"</h3>
+
+<p>O enlace que vostede seleccionou Ã© externo Ã¡ colecciÃ³n "_collectionname_" (
+remite Ã¡ colecciÃ³n "_2_"). Se desexa ver o documento que corresponde a este
+enlace na colecciÃ³n "_2_",pode <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">
+acceder</a> a esa pÃ¡xina; en caso contrario, prema o botÃ³n "AtrÃ¡s" do seu
+navegador para volver Ã³ documento anterior.
+
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=gl] {Biblioteca Dixital Greenstone }
+
+_textusername_ [l=gl] {nome de usuario}
+_textpassword_ [l=gl] {contrasinal}
+
+_textmustbelongtogroup_ [l=gl] {AdvÃ­rtese que para acceder a esta pÃ¡xina vostede debe pertenecer Ã³ grupo "_cgiargug_"}
+
+_textmessageinvalid_ [l=gl] {Para acceder Ã¡ pÃ¡xina que vostede solicitou Ã© necesario conectarse.<br>
+_If_(_cgiargug_, [_textmustbelongtogroup_]<br>) Teclee por favor o seu nome de usuario de
+Greenstone e o seu contrasinal.
+
+}
+
+_textmessagefailed_ [l=gl] {Erro no nome de usuario ou no contrasinal}
+
+_textmessagedisabled_ [l=gl] {SentÃ­molo, pero a sÃºa conta foi invalidada. Por favor contacte co administrador
+deste sitio.
+
+}
+
+_textmessagepermissiondenied_ [l=gl] {SentÃ­molo, pero vostede non ten permiso para acceder a esta pÃ¡xina.
+
+}
+
+_textmessagestalekey_ [l=gl] {O enlace que vostede seleccionou xa non Ã© vÃ¡lido. Teclee por favor o seu
+contrasinal para ter acceso a esta pÃ¡xina.
+
+}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=gl] {<p<Esta instalaciÃ³n de Greenstone non inclÃºe ningunha documentaciÃ³n. Esto pode
+ser porque:
+
+<ol>
+
+<li>Greenstone instalouse a partir dun CD-ROM nunha versiÃ³n compacta.
+
+<li>Greenstone instalouse a partir dunha distribuciÃ³n descargada de Internet.
+
+</ol>
+
+<p>En ambos casos pode vostede obter a documentaciÃ³n no directorio<i>docs</i>
+dun CD-ROM de Greenstone ou visitando <a href="http://www.greenstone.org">
+http://www.greenstone.org</a>.
+
+}
+
+_textuserguide_ [l=gl] {GuÃ­a do usuario }
+_textinstallerguide_ [l=gl] {GuÃ­a de instalaciÃ³n }
+_textdeveloperguide_ [l=gl] {GuÃ­a do programador }
+_textpaperguide_ [l=gl] {Do papel Ã¡ colecciÃ³n }
+# -- Missing translation: _textorganizerguide_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "documentaciÃ³n de greenstone" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=gl] {_httpimg_/gl/gsdocsgr.gif}
+_widthgsdocsgr_ [l=gl] {_pagewidth_}
+_heightgsdocsgr_ [l=gl] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ [l=gl] {Estructura por defecto}
+_textmore_ [l=gl] {mÃ¡is}
+_textcollector_ [l=gl] {O Coleccionista}
+_textinfo_ [l=gl] {InformaciÃ³ns sobre a colecciÃ³n}
+_textsrce_ [l=gl] {Datos fonte}
+_textconf_ [l=gl] {Configurar a colecciÃ³n}
+_textbild_ [l=gl] {CreaciÃ³n}
+_textview_ [l=gl] {Visualizar}
+_textdel_ [l=gl] {Suprimir a colecciÃ³n}
+_textexpt_ [l=gl] {Exportar a colecciÃ³n}
+
+# -- Missing translation: _textdownloadingfiles_
+# -- Missing translation: _textimportingcollection_
+# -- Missing translation: _textbuildingcollection_
+# -- Missing translation: _textcreatingcollection_
+
+_textcollectorblurb_ [l=gl] {<i>Â¡A pluma Ã© mÃ¡is poderosa que a espada!
+
+<br>
+Crear e distribuÃ­r colecciÃ³ns de informaciÃ³n, implica responsabilidades nas que
+poida que vostede queira reflexionar antes de seguir adiante.
+Hai cuestiÃ³ns xurÃ­dicas sobre o dereito de autor: ter acceso a documentos non
+quere dicir que se poida comunicalos a terceiros. Hai tamÃ©n cuestiÃ³ns sociais:
+no manexo dos documentos dÃ©bense respectar os usos e costumes da comunidade da
+que proceden os documentos. E hai tamÃ©n cuestiÃ³ns Ã©ticas: algÃºns documentos non
+se deben poÃ±er a disposiciÃ³n de ninguÃ©n.
+
+<br>Sexa consciente do poder da informaciÃ³n e utilÃ­ceo con prudencia.
+
+</i>
+
+}
+
+_textcb1_ [l=gl] {O Coleccionista axÃºdalle a crear novas colecciÃ³ns e a modificar, engadir ou
+suprimir colecciÃ³ns existentes. Para facelo, serÃ¡ guiado por unha secuencia de
+pÃ¡xinas Web na que se lle pedirÃ¡ a informaciÃ³n necesaria.
+
+}
+
+_textcb2_ [l=gl] {Primeiro, debe decidir se}
+_textcnc_ [l=gl] {Crear unha nova colecciÃ³n }
+_textwec_ [l=gl] {Traballar cunha colecciÃ³n existente, engadÃ­ndolle datos o
+suprimindoa }
+
+_textcb3_ [l=gl] {Para crear ou modificar colecciÃ³ns Ã© necesario rexistrarse. Esto permite evitar
+que outras persoas entren no seu ordenador e alteren a informaciÃ³n. Nota: por
+razÃ³ns de seguridade terÃ¡ que conectarse de novo cada media hora. Se esto sucede,
+ Â¡Non se preocupe! -convidarÃ¡selle a abrir unha nova sesiÃ³n e poderÃ¡ vostede
+ continuar a partires de onde estaba no momento da desconexiÃ³n.
+
+}
+
+_textcb4_ [l=gl] {Dixite o seu nome de usuario de Greenstone e o seu contrasinal, e prema o botÃ³n
+para conectarse.
+
+}
+
+_textfsc_ [l=gl] {Primeiro seleccione a colecciÃ³n coa cal desexa vostede traballar (as colecciÃ³ns
+protexidas contra escritura non aparecerÃ¡n nesta lista).
+
+}
+
+_textwtc_ [l=gl] {coa colecciÃ³n seleccionada, vostede pode
+
+}
+_textamd_ [l=gl] {Engadir mÃ¡is datos e recrear a colecciÃ³n
+
+}
+_textetc_ [l=gl] {Modificar o ficheiro de configuraciÃ³n da colecciÃ³n e recrear a colecciÃ³n
+
+}
+_textdtc_ [l=gl] {Suprimir a colecciÃ³n definitivamente
+
+}
+_textetcfcd_ [l=gl] {Exportar a colecciÃ³n para gravala nun CD-ROM que se instala automaticamente en
+Windows
+
+}
+_textcaec_ [l=gl] {Cambiar unha colecciÃ³n existente
+
+}
+_textnwec_ [l=gl] {Non estÃ¡ dispoÃ±ible para a sÃºa modificaciÃ³n ningunha colecciÃ³n que permita a
+escritura
+
+}
+_textcianc_ [l=gl] {Crear unha nova colecciÃ³n
+
+}
+_texttsosn_ [l=gl] {A secuencia das fases necesarias para crear unha nova colecciÃ³n de biblioteca
+dixital Ã© a seguinte:
+
+}
+_textsin_ [l=gl] {Especificar o seu nome (e outras informaciÃ³ns asociadas)
+
+}
+_textswts_ [l=gl] {Especificar de onde proveÃ±en os datos fonte
+
+}
+_textatco_ [l=gl] {Axustar as opciÃ³ns de configuraciÃ³n (sÃ³ para usuarios experimentados)
+
+}
+_textbtc_ [l=gl] {"Crear" a colecciÃ³n (vÃ©xase mÃ¡is abaixo)
+
+}
+_textpvyh_ [l=gl] {Â¡Admire a sÃºa obra!
+
+}
+
+_texttfsiw_ [l=gl] {A cuarta fase Ã© cando o ordenador fai todo o traballo. No proceso de "creaciÃ³n"
+o ordenador elabora todos os Ã­ndices e recompila todas as informaciÃ³ns necesarias
+para o bo funcionamento da biblioteca dixital. Pero primeiro ten vostede que
+especificar as informaciÃ³ns.
+
+}
+
+_textadab_ [l=gl] {Abaixo aparece un diagrama que lle axudarÃ¡ a controlar onde estÃ¡. O botÃ³n verde
+Ã© o que vostede pulsarÃ¡ para continuar a secuencia. Despois de cada paso na
+secuencia, os botÃ³ns cambiarÃ¡n Ã³ amarelo. PÃ³dese volver a unha pÃ¡xina anterior
+premendo o botÃ³n amarelo correspondente no diagrama.
+
+}
+
+_textwyar_ [l=gl] {Cando estea listo, prema o botÃ³n verde "informaciÃ³ns sobre a colecciÃ³n" para
+comezar a crear a sÃºa nova colecciÃ³n.
+
+}
+
+_textcnmbs_ [l=gl] {DÃ©bese especificar o nome da colecciÃ³n}
+_texteambs_ [l=gl] {DÃ©bese especificar o enderezo de correo electrÃ³nico}
+_textpsea_ [l=gl] {Comprobe que o enderezo de correo electrÃ³nico corresponde Ã³ formato usuario@dominio}
+_textdocmbs_ [l=gl] {DÃ©bese especificar a descriciÃ³n da colecciÃ³n}
+
+_textwcanc_ [l=gl] {Ã³ crear unha nova colecciÃ³n, Ã© necesario incorporar algunhas informaciÃ³ns
+preliminares sobre os datos fonte. Este proceso estructÃºrase en forma dunha
+serie de pÃ¡xinas Web, supervisadas polo Coleccionista. A barra na parte inferior
+da pÃ¡xina mostra a secuencia de pÃ¡xinas que quedan.
+
+}
+
+_texttfc_ [l=gl] {TÃ­tulo da colecciÃ³n:
+
+}
+
+_texttctiasp_ [l=gl] {O tÃ­tulo da colecciÃ³n Ã© unha frase corta que se utiliza na biblioteca dixital
+para identificar o contido da colecciÃ³n.
+Por exemplo:  "Informes tÃ©cnicos de informÃ¡tica" ou "Humanity Development Library".
+
+}
+
+_textcea_ [l=gl] {Enderezo de correo electrÃ³nico de contacto:
+
+}
+
+_textteas_ [l=gl] {Este enderezo electrÃ³nico constitÃºe o primeiro punto de contacto para a
+colecciÃ³n. Se o programa Greenstone detecta un problema, enviase un informe de
+diagnostico a ese enderezo. Teclee un enderezo electrÃ³nico na sÃºa forma completa:
+<tt>nome@dominio</tt>.
+
+}
+
+_textatc_ [l=gl] {Acerca desta colecciÃ³n:
+
+}
+
+_texttiasd_ [l=gl] {Esta Ã© unha declaraciÃ³n na que se enuncian os principios que definen que elementos
+que son incluÃ­dos nesta colecciÃ³n. AparecerÃ¡ na primeira pÃ¡xina de presentaciÃ³n
+da colecciÃ³n.
+
+}
+
+_textypits_ [l=gl] {A sÃºa posiciÃ³n na secuencia indÃ­case cunha frecha por debaixo--neste caso, a
+etapa das "informaciÃ³ns de colecciÃ³n". Para continuar, prema o botÃ³n verde "
+datos fonte".
+
+}
+
+_srcebadsources_ [l=gl] {<p> Un ou mÃ¡is dos ficheiros fonte que vostede especificou non estÃ¡ dispoÃ±ible (
+marcados _iconcross_ abaixo).
+
+<p>Esto pode ser porque:
+
+<ul>
+
+<li>Non existe o ficheiro, o sitio FTP ou o URL.
+
+<li>Hai que conectarse primeiro a Internet.
+
+<li>Vostede estÃ¡ intentando acceder a un URL que estÃ¡ detrÃ¡s dun cortalume (esto
+ocorre normalmente cando vostede ten que proporcionar un nome de usuario e un
+contrasinal para acceder a Internet).
+
+</ul>
+
+<p>Se este Ã© un URL que vostede pode ver no seu navegador, o problema pode vir
+dunha copia que se atopa na memoria cache local. Desafortunadamente, estas
+copias son invisibles para o noso proceso de copiado. Neste caso recomendamos
+que descargue as pÃ¡xinas mediante o seu navegador.
+
+}
+
+_textymbyco_ [l=gl] {Vostede pode basear a sÃºa colecciÃ³n en:
+
+<ul>
+
+<li>A estructura por defecto
+
+</ul>
+
+<dl><dd> A nova colecciÃ³n pode conter documentos HTML (.htm,.html), documentos
+de texto (.txt,.text), documentos MS-Word (.doc), documentos PDF (.pdf), ou
+documentos de correo electrÃ³nico no formato "m-box" (.mbx).</dd></dl>
+
+<li>Unha colecciÃ³n existente
+
+<dl><dd>Os ficheiros da sÃºa nova colecciÃ³n deben ser exactamente do mesmo tipo
+que os utilizados para crear a colecciÃ³n existente. </dd></dl>
+
+</ul>
+
+}
+
+_textbtco_ [l=gl] {Basear a colecciÃ³n en:}
+_textand_ [l=gl] {Engadir novos datos}
+_textad_ [l=gl] {Engadir datos:}
+
+_texttftysb_ [l=gl] {os ficheiros que vostede especifique mais abaixo engadiranse Ã¡ colecciÃ³n.
+AsegÃºrese de non volver a especificar ficheiros que xa estÃ¡n na colecciÃ³n, pois
+de facelo haberÃ¡ dÃºas copias. Os ficheiros especifÃ­canse indicando o seu nome
+completo e o directorio no que estÃ¡n almacenados, as pÃ¡xinas Web identifÃ­canse
+polo seu enderezo Internet absoluto.
+
+}
+
+_textis_ [l=gl] {Datos de entrada: }
+
+_textddd1_ [l=gl] {<p>Se vostede utiliza file:// ou ftp:// para especificar un ficheiro, este
+descargarase.
+
+<p>Se vostede utiliza http://, o resultado dependerÃ¡ do URL e serÃ¡ diferente
+se
+este abre no seu navegador unha pÃ¡xina WEb ou unha lista de ficheiros. Se se
+trata dunha pÃ¡xina, descargarase estÃ¡, e tamÃ©n todas as pÃ¡xinas coas que este
+vinculada mediante enlaces, sempre que pertenzan Ã³ mesmo sitio inicial.
+
+<p>Se vostede utiliza file:// ou ftp:// para especificar un directorio, ou se
+indica un URL http:// que conduce a unha lista de ficheiros, todos os ficheiros
+que se encontren nesa carpeta e nas sÃºas subcarpetas serÃ¡n incluÃ­
+dos na colecciÃ³n.
+
+<p>Prema o botÃ³n "mais datos" para obter mais cadros de introducciÃ³n de datos.
+
+}
+
+_textddd2_ [l=gl] {<p>Prema un dos botÃ³ns verdes. Se Ã© vostede un usuario experimentado, pode
+desexar axustar a configuraciÃ³n da colecciÃ³n. outra posibilidade Ã© ir
+directamente Ã¡ etapa de creaciÃ³n. Lembre, pode volver Ã¡ etapa anterior premendo
+o botÃ³n amarelo correspondente.
+
+}
+
+_textconf1_ [l=gl] {<p>A creaciÃ³n e a presentaciÃ³n da sÃºa colecciÃ³n son controladas por
+especificaciÃ³ns nun "ficheiro de configuraciÃ³n" especial. Os usuarios
+experimentados que o desexen poden modificar os parÃ¡metros da configuraciÃ³n.
+
+<center><p><b>Se vostede non Ã© un usuario experimentado, vaia Ã¡ parte inferior
+da pÃ¡xina.</b></center>
+
+<p>Para modificar os parÃ¡metros de configuraciÃ³n, corrixa os datos que aparecen
+mais abaixo. Se se equivoca, prema o botÃ³n "Reiniciar" para restablecer os
+parÃ¡metros orixinais de configuraciÃ³n.
+
+}
+
+_textreset_ [l=gl] {Reiniciar}
+
+_textbild1_ [l=gl] {A colecciÃ³n estase creando: esta operaciÃ³n pode ser longa. A liÃ±a de estado que
+aparece mais abaixo indica como estÃ¡ progresando a operaciÃ³n.
+}
+
+_textbild2_ [l=gl] {Para interromper o proceso de creaciÃ³n en calquera momento, prema aquÃ­. <br> A
+colecciÃ³n coa que estÃ¡ traballando quedarÃ¡ intacta.
+
+}
+
+_textstopbuild_ [l=gl] {Interromper a creaciÃ³n }
+
+_textbild3_ [l=gl] {Se vostede sae desta pÃ¡xina (e non cancelou o proceso de creaciÃ³n co botÃ³n "
+interromper a creaciÃ³n"), a colecciÃ³n continuarÃ¡ creÃ¡ndose e instalarase cando o
+proceso teÃ±a rematado.
+
+}
+
+_textbuildcancelled_ [l=gl] {CreaciÃ³n cancelada
+
+}
+
+_textbildcancel1_ [l=gl] {Cancelouse o proceso de creaciÃ³n da colecciÃ³n. Utilice os botÃ³ns amarelos para
+efectuar cambios na sÃºa colecciÃ³n ou para reiniciar o proceso de creaciÃ³n.
+
+}
+
+_textbsupdate1_ [l=gl] {ActualizaciÃ³n do estado da creaciÃ³n dentro de 1 segundo}
+_textbsupdate2_ [l=gl] {ActualizaciÃ³n do estado da creaciÃ³n dentro de}
+_textseconds_ [l=gl] {segundos}
+_textbildsuc_ [l=gl] {ColecciÃ³n creada satisfactoriamente.}
+
+_textviewbildsummary_ [l=gl] {Para obter mais detalles, vostede pode  <a
+href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>visualizar o
+resume da creaciÃ³n </a> desta colecciÃ³n.
+
+}
+
+_textfailmsg11_ [l=gl] {A colecciÃ³n non se puido crear porque non conten ningÃºn dato. Comprobe que existe
+polo menos un dos directorios ou ficheiros que vostede especificou na pÃ¡xina <i>
+datos fonte</i> e de que Ã© dun tipo ou, no caso de directorios, de que contÃ©n
+ficheiros dun tipo que Greenstone pode procesar.
+
+}
+
+_textfailmsg21_ [l=gl] {Non se puido crear a colecciÃ³n (fallou o script import.pl).
+
+}
+_textblcont_ [l=gl] {O rexistro de creaciÃ³n contÃ©n as informaciÃ³ns seguintes:
+}
+
+_texttryagain_ [l=gl] {Por favor <a href="_httppagecollector_" target=_top>volva a arrancar o
+Coleccionista</a> e intenteo de novo.
+}
+
+_textfailmsg31_ [l=gl] {Non se puido crear a colecciÃ³n (fallou o script buildcol.pl).
+
+}
+_textfailmsg41_ [l=gl] {Creouse a colecciÃ³n pero non se puido instalar.
+
+}
+_textfailmsg71_ [l=gl] {Produciuse un erro inesperado cando se intentaba crear a colecciÃ³n
+
+}
+_textretcoll_ [l=gl] {Volver Ã³ Coleccionista
+
+}
+
+_textdelperm_ [l=gl] {<p>Non se puido suprimir parte da colecciÃ³n  _cgiargbc1dirname_ ou toda ela. As
+causas posibles son:
+
+<ul>
+
+<li>Greenstone non ten permiso para suprimir o directorio _gsdlhome_/collect/_cgiargbc1dirname_. <
+br> Para suprimir definitivamente a colecciÃ³n _cgiargbc1dirname_ neste ordenador,
+ pode ser necesario suprimir manualmente este directorio.
+
+</ul>
+
+}
+
+_textdelinv_ [l=gl] {A colecciÃ³n  _cgiargbc1dirname_ estÃ¡ protexida ou non Ã© vÃ¡lida. A supresiÃ³n
+cancelouse.
+
+}
+
+_textdelsuc_ [l=gl] {suprimiuse a colecciÃ³n _cgiargbc1dirname_.
+
+}
+
+_textclonefail_ [l=gl] {Non se puido clonar a colecciÃ³n  _cgiargbc1dirname_. As causas posibles son:
+
+<ul>
+
+<li>A colecciÃ³n _cgiargclonecol_ non existe
+
+<li>A colecciÃ³n _cgiargclonecol_ non ten ningÃºn ficheiro collect.cfg
+
+<li>Greenstone non ten permiso para ler o ficheiro de configuraciÃ³n
+collect.cfg
+
+</ul>
+
+}
+
+_textcolerr_ [l=gl] {Erro no Coleccionista. }
+
+_texttmpfail_ [l=gl] {O Coleccionista non puido efectuar ningunha operaciÃ³n de lectura ou de escritura
+no ficheiro temporal. As causas posibles son:
+<ul>
+
+<li>Greenstone non ten acceso de lectura/escritura Ã³ directorio _gsdlhome_/tmp.
+
+</ul>
+
+}
+
+_textmkcolfail_ [l=gl] {O Coleccionista non puido crear a estructura de directorios que require a nova
+colecciÃ³n (fallou o script mkcol.pl). As causas posibles son:
+
+<ul>
+
+<li>Greenstone non ten permiso para escribir no directorio _gsdlhome_/tmp.
+
+<li>Erros no guiÃ³n Perl mkcol.pl.
+
+</ul>
+
+}
+
+_textnocontent_ [l=gl] {Erros do Coleccionista: non se proporcionou ningÃºn nome para a nova colecciÃ³n.
+Intente volver a arrancar o Coleccionista.
+
+}
+
+_textrestart_ [l=gl] {Volver a arrancar o Coleccionista
+
+}
+
+_textreloaderror_ [l=gl] {Produciuse un erro cando se creaba a nova colecciÃ³n. Ã© posible que o uso dos
+botÃ³ns "Actualizar" ou "AtrÃ¡s" do seu navegador perturbara a Greenstone (trate
+de evitar o uso deses botÃ³ns durante a creaciÃ³n dunha colecciÃ³n co Coleccionista).
+ RecomÃ©ndase volver a arrincar o Coleccionista.
+
+}
+
+_textexptsuc_ [l=gl] {A colecciÃ³n de _cgiargbc1dirname_ exportouse Ã³ directorio _gsdlhome_/tmp/exported\__cgiargbc1dirname_.
+
+}
+
+_textexptfail_ [l=gl] {<p>Non se puido exportar a colecciÃ³n _cgiargbc1dirname_.
+
+>p>Ã© probable  que esto se deba a que Greenstone instalouse sen os compoÃ±entes
+necesarios para posibilitar a funciÃ³n "Exportar a colecciÃ³n".
+
+<ul>
+
+<li>Se vostede instalou Greenstone a partires dun CD-ROM, estos compoÃ±entes non
+se terÃ¡n instalado a menos que vostede os seleccionara durante unha instalaciÃ³n
+"personalizada". Pode engadilos Ã¡ sÃºa instalaciÃ³n volvendo a efectuar o
+procedemento de instalaciÃ³n.
+
+<li>Se vostede instalou Greenstone a partires dun programa distribuÃ­do por
+Internet, serÃ¡ necesario descargar e instalar un paquete adicional para activar
+esta funciÃ³n. Visite por favor <a href="http://www.greenstone.org">http://www.greenstone.org</a>
+ou envÃ­e un correo electrÃ³nico a  <a href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+para obter mais detalles.
+
+</ul>
+
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "O coleccionista" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=gl] {_httpimg_/gl/h\_colect.gif}
+
+## "informaciÃ³ns\nsobre a colecciÃ³n" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=gl] {_httpimg_/gl/gcinfoof.gif}
+_httpicongcinfoon_ [l=gl] {_httpimg_/gl/gcinfoon.gif}
+_httpiconycinfoof_ [l=gl] {_httpimg_/gl/ycinfoof.gif}
+_httpiconycinfoon_ [l=gl] {_httpimg_/gl/ycinfoon.gif}
+_httpiconncinfoof_ [l=gl] {_httpimg_/gl/ncinfoof.gif}
+
+## "datos\nfonte" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=gl] {_httpimg_/gl/gcsrceof.gif}
+_httpicongcsrceon_ [l=gl] {_httpimg_/gl/gcsrceon.gif}
+_httpiconycsrceof_ [l=gl] {_httpimg_/gl/ycsrceof.gif}
+_httpiconycsrceon_ [l=gl] {_httpimg_/gl/ycsrceon.gif}
+_httpiconncsrceof_ [l=gl] {_httpimg_/gl/ncsrceof.gif}
+
+## "configurar\na colecciÃ³n" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=gl] {_httpimg_/gl/gcconfof.gif}
+_httpicongcconfon_ [l=gl] {_httpimg_/gl/gcconfon.gif}
+_httpiconycconfof_ [l=gl] {_httpimg_/gl/ycconfof.gif}
+_httpiconycconfon_ [l=gl] {_httpimg_/gl/ycconfon.gif}
+_httpiconncconfof_ [l=gl] {_httpimg_/gl/ncconfof.gif}
+
+## "crear\na colecciÃ³n" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=gl] {_httpimg_/gl/gcbildof.gif}
+_httpicongcbildon_ [l=gl] {_httpimg_/gl/gcbildon.gif}
+_httpiconycbildof_ [l=gl] {_httpimg_/gl/ycbildof.gif}
+_httpiconycbildon_ [l=gl] {_httpimg_/gl/ycbildon.gif}
+_httpiconncbildof_ [l=gl] {_httpimg_/gl/ncbildof.gif}
+
+## "visualizar\na colecciÃ³n" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=gl] {_httpimg_/gl/gcviewof.gif}
+_httpicongcviewon_ [l=gl] {_httpimg_/gl/gcviewon.gif}
+_httpiconycviewof_ [l=gl] {_httpimg_/gl/ycviewof.gif}
+_httpiconycviewon_ [l=gl] {_httpimg_/gl/ycviewon.gif}
+_httpiconncviewof_ [l=gl] {_httpimg_/gl/ncviewof.gif}
+
+## "suprimir\na colecciÃ³n" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=gl] {_httpimg_/gl/gcdelof.gif}
+_httpicongcdelon_ [l=gl] {_httpimg_/gl/gcdelon.gif}
+
+## "exportar\na colecciÃ³n" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=gl] {_httpimg_/gl/gcexptof.gif}
+_httpicongcexpton_ [l=gl] {_httpimg_/gl/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=gl] {<P>Greenstone Ã© un conxunto de programas que posibilitan fornecer e construÃ­r
+bibliotecas dixitais. Ofrece un novo xeito de organizar a informaciÃ³n e
+publicala en Internet ou en CD-ROM. Elaborado dentro do proxecto de Biblioteca
+Dixital de Nova Celandia da Universidade de Waikato, este producto distribÃºese en
+colaboraciÃ³n coa UNESCO e a ONG Human Info. Ã© un programa informÃ¡tico de cÃ³digo
+fonte aberto, que pode descargarse no enderezo <a href="http://greenstone.org">http://greenstone.org</a>,
+segundo as condiciÃ³ns estipuladas na Licencia PÃºblica Xeral de GNU.
+
+}
+
+_textgreenstone2_ [l=gl] {O sitio web da Biblioteca Dixital de Nova Celandia (<a href="http://nzdl.org">http://nzdl.org</a>)
+contÃ©n numerosos exemplos de colecciÃ³ns, creados con Greenstone, que se poden
+consultar libremente. Mostran varias opciÃ³ns de busca e navegaciÃ³n, e inclÃºen
+colecciÃ³ns en Ã¡rabe, chinÃ©s, francÃ©s, maorÃ­ e espaÃ±ol, asÃ­ como en inglÃ©s. Hai
+tamÃ©n algunhas colecciÃ³ns de mÃºsica.
+
+}
+
+# -- Missing translation: _textplatformtitle_
+_textgreenstone3_ [l=gl] {Greenstone funciona con Windows e Unix. A distribuciÃ³n inclÃºe binarios listos
+para o seu uso en todas as versiÃ³ns de Windows e Linux. InclÃºe tamÃ©n o cÃ³digo
+fonte completo para o sistema, que se pode compilar usando Microsoft C++ ou GCC.
+Greenstone funciona con outros programas libres que se poden descargar de
+Internet: o servidor web Apache e Perl. A interfaz utiliza un navegador web,
+como Netscape Navigator ou Internet Explorer.
+
+}
+
+_textgreenstone4_ [l=gl] {Moitas colecciÃ³ns de documentos distribÃºense en CD-ROM con Greenstone.Por
+exemplo, o proxecto de <i>Bibliotecas para o Desenvolvemento da Humanidade</i>
+conten 1.230 publicaciÃ³ns con temÃ¡tica moi variada (dende a contabilidade ata a
+depuraciÃ³n de auga). PÃ³dese acceder a esta colecciÃ³n con ordenadores de escas
+potencia, como as que se soen ver en paÃ­ses en desenvolvemento. A informaciÃ³n
+pode obterse mediante buscas ou consultas por tema, por tÃ­tulos de publicaciÃ³ns,
+por organizaciÃ³n, consultando unha lista de "como..." ou visualizando de forma
+aleatoria as portadas dos libros.
+
+}
+
+# -- Missing translation: _textcustomisationtitle_
+_textgreenstone5_ [l=gl] {Greenstone estÃ¡ especialmente concibido para poder ampliarse e personalizarse a
+vontade. Greenstone pode tratar novos formatos de documentos e de metadatos
+escribindo "conectores" (<i>plugins</i>), na linguaxe Perl. TamÃ©n se poden
+implementar novas estructuras de navegaciÃ³n nos metadatos escribindo "
+clasificadores". a interfaz de usuario e a presentaciÃ³n poden modificarse
+utilizando as "macros" escritas nunha linguaxe de macros simple. O protocolo
+CORBA permite que os axentes (por exemplo en linguaxe Java) utilicen todas as
+funciÃ³ns dispoÃ±ibles nas colecciÃ³ns de documentos. Por Ãºltimo, pÃ³dese modificar o
+cÃ³digo fonte en C++ e Perl.
+
+}
+
+# -- Missing translation: _textdocumentationtitle_
+# -- Missing translation: _textdocuments_
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+# -- Missing translation: _textmailinglisttitle_
+_textmailinglist_ [l=gl] {Existe unha lista de correo electrÃ³nico para os debates sobre Greenstone. Ã©
+desexable que os usuarios activos de Greenstone participen nela.
+Para subscribirse, envÃ­e un correo
+electrÃ³nico a <a href="mailto:greenstone-users-request@list.scms.waikato.ac.nz?subject=subscribe">greenstone-users-request@list.scms.waikato.ac.nz?subject=subscribe</a>.
+Para enviar unha mensaxe a lista, utilice o enderezo <a href="mailto:greenstone-users@list.scms.waikato.ac.nz">greenstone-users@list.scms.waikato.ac.nz</a>.
+
+}
+
+# -- Missing translation: _textbugstitle_
+_textreport_ [l=gl] {O noso desexo Ã© garantir o correcto funcionamento deste programa, polo
+que animamos Ã³s seus usuarios a notificar calquera problema que detecten a: <a
+href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>.
+
+}
+
+# -- Missing translation: _textgs3title_
+# -- Missing translation: _textgs3_
+
+# -- Missing translation: _textcreditstitle_
+
+_textwhoswho_ [l=gl] {O programa Greenstone Ã© froito da colaboraciÃ³n de moitas persoas. Rodger McNab e
+Stefan bodie son os principais arquitectos e programadores. Aportaron
+contribuciÃ³ns David Bainbridge, George Buchanan, Hong Chen, Elke Duncker, Carl Gutwin, Geoff Holmes, John
+McPherson, Craig Nevill-Manning, Gordon Paynter, Bernhard Pfahringer,
+Todd Reed, Bill Rogers e Stuart Yeates. Outros membros do proxecto de Biblioteca
+Dixital de Nova Celandia, que contribuÃ­ron co seu asesoramento e as sÃºas
+inspiradas ideas Ã¡ concepciÃ³n do sistema son: Mark Apperley, Sally Jo Cunningham, Steve Jones, Te Taka Keegan, Michel
+Loots, Malika Mahoui e Lloyd Smith. Damos tamÃ©n as gracias a quen contribuÃ­u Ã³s
+paquetes de programas incluÃ­dos nesta distribuciÃ³n: MG, GDBM, PDFTOHTML, WVWARE
+e XLHTML.
+
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "acerca do programa greenstone" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=gl] {_httpimg_/gl/abgsgr.gif}
+_widthabgsgr_ [l=gl] {_pagewidth_}
+_heightabgsgr_ [l=gl] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=gl] {Lista dos usuarios actuais}
+_textuser_ [l=gl] {usuario}
+_textas_ [l=gl] {estado da conta}
+_textgroups_ [l=gl] {grupos}
+_textcomment_ [l=gl] {comentario}
+_textadduser_ [l=gl] {engadir un novo usuario }
+_textedituser_ [l=gl] {modificar}
+_textdeleteuser_ [l=gl] {suprimir}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=gl] {Modificar as informaciÃ³ns relativas Ã³s usuarios}
+_textadduser_ [l=gl] {Engadir un novo usuario}
+
+_textaboutusername_ [l=gl] {Os nomes de usuario deben ter entre 2 e 30 caracteres. Poden estar compostos de
+caracteres alfanumÃ©ricos, '.', e '_'.
+}
+
+_textaboutpassword_ [l=gl] {Os contrasinais deben ser de entre 3 e 8 caracteres, e poden comprender todos os
+caracteres ASCII imprimibles.
+}
+
+_textoldpass_ [l=gl] {Se este campo se deixa baleiro, utilizarase o antigo
+contrasinal }
+_textenabled_ [l=gl] {activado }
+_textdisabled_ [l=gl] {desactivado }
+
+_textaboutgroups_ [l=gl] {Os grupos son listas cuxos elementos estÃ¡n separados por comas, non teclee
+espacios despois das comas.}
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=gl] {Suprimir un usuario}
+_textremwarn_ [l=gl] {Â¿Confirma vostede que desexa suprimir definitivamente o usuario <b>_cgiargumun_</b>?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=gl] {Cambiar o contrasinal}
+_textoldpw_ [l=gl] {antigo contrasinal}
+_textnewpw_ [l=gl] {novo contrasinal}
+_textretype_ [l=gl] {volva a teclear o seu novo contrasinal}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=gl] {Rexistrouse o seu novo contrasinal}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=gl] {O nome de usuario non Ã© vÃ¡lido.}
+_textinvalidpassword_ [l=gl] {O contrasinal non Ã© vÃ¡lido.}
+_textemptypassword_ [l=gl] {Teclee un contrasinal inicial para este usuario.}
+_textuserexists_ [l=gl] {Este usuario xa existe, teclee por favor outro
+nome de usuario.}
+
+_textusernameempty_ [l=gl] {Teclee por favor o seu nome de usuario.}
+_textpasswordempty_ [l=gl] {Ten que teclear o seu antigo contrasinal.}
+_textnewpass1empty_ [l=gl] {Teclee o seu novo contrasinal e volva a teclealo.}
+_textnewpassmismatch_ [l=gl] {As dÃºas versiÃ³ns do seu novo contrasinal son distintas.}
+_textnewinvalidpassword_ [l=gl] {O contrasinal Ã© incorrecto.}
+_textfailed_ [l=gl] {Ã© incorrecto o nome de usuario ou o contrasinal.}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=gl] {NÃºmero de versiÃ³n de Greenstone}
+_textframebrowser_ [l=gl] {Para visualizar esto requÃ­rese un navegador que acepte os marcos ("frames").}
+_textusermanage_ [l=gl] {XestiÃ³n dos usuarios}
+_textlistusers_ [l=gl] {lista dos usuarios}
+_textaddusers_ [l=gl] {engadir un novo usuario}
+_textchangepasswd_ [l=gl] {cambiar de contrasinal}
+_textinfo_ [l=gl] {InformaciÃ³ns tÃ©cnicas}
+_textgeneral_ [l=gl] {xeral}
+_textarguments_ [l=gl] {argumentos}
+_textactions_ [l=gl] {acciÃ³ns}
+_textbrowsers_ [l=gl] {navegadores}
+_textprotocols_ [l=gl] {protocolos}
+_textconfigfiles_ [l=gl] {Ficheiros de configuraciÃ³n}
+_textlogs_ [l=gl] {Rexistros}
+_textusagelog_ [l=gl] {rexistro de uso}
+_textinitlog_ [l=gl] {rexistro de inicializaciÃ³n}
+_texterrorlog_ [l=gl] {rexistro de erros}
+_textadminhome_ [l=gl] {pÃ¡xina principal da administraciÃ³n}
+_textreturnhome_ [l=gl] {pÃ¡xina principal de Greenstone}
+_titlewelcome_ [l=gl] {AdministraciÃ³n }
+_textmaas_ [l=gl] {Os servicios de mantemento e de administraciÃ³n son os seguintes:}
+_textvol_ [l=gl] {mostrar os rexistros en liÃ±a}
+_textcmuc_ [l=gl] {crear, manter e actualizar colecciÃ³ns}
+_textati_ [l=gl] {acceder a informaciÃ³ns tÃ©cnicas tales como os argumentos CGI}
+
+_texttsaa_ [l=gl] {PÃ³dese acceder a estes servicios mediante a barra de navegaciÃ³n situada na parte
+esquerda da pÃ¡xina.
+}
+
+_textcolstat_ [l=gl] {Estado da colecciÃ³n}
+
+_textcwoa_ [l=gl] {Unha colecciÃ³n sÃ³ aparecerÃ¡ como "running" (funcionando) se o ficheiro build.cfg
+existe, se Ã© lexible, se conten un campo vÃ¡lido "builddate" (data de creaciÃ³n),
+Ã© dicir > 0, e se estÃ¡ no directorio "index" da colecciÃ³n (Ã© dicir NON no
+directorio "build").
+
+}
+
+_textcafi_ [l=gl] {Prema <i>abbrev.</i> para obter informaciÃ³ns sobre unha colecciÃ³n}
+_textcctv_ [l=gl] {Prema <i>collection</i> para visualizar unha colecciÃ³n}
+_textsubc_ [l=gl] {Someter cambios }
+_texteom_ [l=gl] {Erro de lectura do ficheiro main.cfg}
+_textftum_ [l=gl] {Non se puido actualizar o ficheiro main.cfg }
+_textmus_ [l=gl] {Logrouse actualizar o ficheiro main.cfg }
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=gl] {Resumo da creaciÃ³n da colecciÃ³n _collectionname_
+
+}
+_textflog_ [l=gl] {Erros no rexistro da colecciÃ³n _collectionname_
+
+}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+# -- Missing translation: _greenstoneusabilitytext_
+
+# -- Missing translation: _textwhy_
+# -- Missing translation: _textextraforform_
+# -- Missing translation: _textprivacybasic_
+# -- Missing translation: _textstillsend_
+
+# -- Missing translation: _texterror_
+# -- Missing translation: _textyes_
+# -- Missing translation: _textno_
+# -- Missing translation: _textclosewindow_
+# -- Missing translation: _textabout_
+# -- Missing translation: _textprivacy_
+# -- Missing translation: _textsend_
+# -- Missing translation: _textdontsend_
+# -- Missing translation: _textoptionally_
+
+# -- Missing translation: _textunderdev_
+
+# -- Missing translation: _textviewdetails_
+# -- Missing translation: _textmoredetails_
+# -- Missing translation: _texttrackreport_
+# -- Missing translation: _textcharacterise_
+# -- Missing translation: _textseverity_
+ 
+# -- Missing translation: _textbadrender_
+# -- Missing translation: _textcontenterror_
+# -- Missing translation: _textstrangebehaviour_
+# -- Missing translation: _textunexpected_
+# -- Missing translation: _textfunctionality_
+# -- Missing translation: _textother_
+
+# -- Missing translation: _textcritical_
+# -- Missing translation: _textmajor_
+# -- Missing translation: _textmedium_
+# -- Missing translation: _textminor_
+# -- Missing translation: _texttrivial_
+
+# -- Missing translation: _textwhatdoing_
+# -- Missing translation: _textwhatexpected_
+# -- Missing translation: _textwhathappened_
+
+# -- Missing translation: _cannotfindcgierror_
+
+# -- Missing translation: _textusabbanner_
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+# -- Missing translation: _textgli_
+# -- Missing translation: _textglihelp_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+# -- Missing translation: gligr
+# -- Missing translation: _httpicongligr_
+# -- Missing translation: _widthgligr_
+# -- Missing translation: _heightgligr_
Index: /tags/gsdl-2_61-distribution/gsdl/macros/garish.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/garish.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/garish.dm	(revision 10506)
@@ -0,0 +1,264 @@
+# this file must be UTF-8 encoded
+
+## Introduction to customising the appearance of a Greenstone Collection.
+##
+## You will need to know some basic HTML coding to edit this file.
+##
+## This file overrides some of the default macros used by greenstone. I've
+## tried to explain what each custom macro does, so hopefully it is
+## straight-forward. I'm sure it looks a little daunting at first, but the
+## use of macros gives you lots of flexibility for modifying pages, once
+## you get the hang of it.
+
+##   -- John McPherson, 18 June 2003
+
+######################################################
+## General comments and hints
+
+## In these macro files, the '#' is the start of a comment. Greenstone will
+## ignore everything after a '#' until the end of the line, unless it
+## is part of a macro.
+
+## In the file gsdl/etc/main.cfg, add this file (garish.dm) to the
+## "macrofiles" list so that greenstone starts including this file.
+## (You can add a "\" at the end of the line to continue onto the next one.)
+## You could also have a look at the "yourhome.dm" macro file for
+## customising the main home page.
+
+## Every page action in greenstone has a name. We call it a "package".
+## So the default action is the "about" package. (This is the p=about cgi
+## argument). Other common actions are "document" and "help".
+## If a macro isn't found that is specific to that action, then greenstone
+## will fall back to macros defined in the "Global" package.
+## All macros in this file belong to whichever package was the most recently
+## mentioned one, with a line such as "package Global".
+
+## macros can have optional parameters, that make them more specific.
+## For example, you could have _macro_ {general case} as well as
+## _macro_ [c=garish] {For garish only} for when the "c" argument (which means
+## the collection) is set to "garish".
+
+## Don't refer to a macro's name inside the same macro, otherwise greenstone
+## will go into a recursive loop printing out the macro...
+
+## I've put HTML comments like <!-- end of custom header --> in the macros
+## so that you can see them when you do "view source" on a web page, to
+## help see the effect of changes of these macros.
+
+## _httpimg_ is a macro that expands to the correct directory where images
+## are stored. I suggest you make a subdirectory in the images directory
+## specific for your collection. Or create a directory "gsdl/images/custom"
+## for all your customisations.
+
+## The macros below modify the appearance of a specific greenstone collection.
+## It makes all the pages include a style-sheet, so that you can put
+## html-related appearance stuff (such as font colours and faces) in there,
+## rather than editing the macros for each piece of text.
+## mozilla has excellent CSS support - Netscape 4 and IE both have
+## incomplete implementations, but mostly work with the simple CSS I've used
+## here as a demonstration.
+##
+## Edit the file images/garish/style.css to change the colours and fonts.
+
+
+##############################################################################
+package Global
+##############################################################################
+## default macros - can be overridden by specific packages. The normal versions
+## of these macros are in the file base.dm (and in the language-specific
+## macro files such as english.dm and french.dm)
+
+
+## These 2 macros are used for highlighting text that matched a query when
+## displaying a document. The default is to set the background to yellow.
+##
+## Note - this is a joke. Please don't ever use the blink tag in real life :)
+#_starthighlight_ [c=garish] {<blink>}
+#_endhighlight_ [c=garish] {</blink>}
+
+
+## imagespacer - this is what goes between the search button and the
+## classifier buttons in the navigation bar.  The default is the
+## horizontal green bar.  You can put any html in here, and you can use
+## the _widthtspace_ macro if you want the calculated gap between the
+## buttons.
+
+## Unfortunately the internally-defined _navigationbar_ macro has no-break tags
+## around it, so we'll close the nobr tags for each button.
+## This stacks the buttons vertically, one above the other.
+#
+## Note - netscape 4.x needs a space between the br and the /
+#_imagespacer_ [c=garish] { </nobr><br /><nobr> }
+
+## If you don't like the look of that, you could comment the above line out
+## and uncomment one of the following definitions for imagespacer:
+
+## This will stack the buttons one above the other (they are in a table) with
+## our image as separator. This closes the current row and starts a new one.
+## This will use our custom image in the images/garish directory.
+
+_imagespacer_ [c=garish] { </nobr>
+<br /><img src="_httpimg_/garish/horzline.gif" width="87" height="17">
+<br />
+<nobr>
+}
+
+## This uses our custom image instead of the green bar, but otherwise has the
+## buttons horizontally, just like the default.
+#
+#_imagespacer_ [c=garish] {
+# <img src="_httpimg_/garish/horzline.gif" width="_widthtspace_"
+# height="17"> 
+#}
+
+
+## In the language-specific macro files, there are definitions for all of
+## the buttons. Unfortunately they have rather cryptic names. For example,
+## the "Titles A-Z" button has three macros, one for "green" (ie when it is
+## the selected button), one for "off" (when it isn't the selected page),
+## and one for "on" (when the mouse is over the image). It gets prepended
+## "httpicon", so we could override them here. Uncomment the following 3
+## macros to use the custom "title a-z" buttons (and the width macro).
+
+_httpiconttitlegr_ [c=garish] {_httpimg_/garish/title_gr.gif}
+## make it the same as off
+_httpiconttitleon_ [c=garish] {_httpiconttitleof_}
+_httpiconttitleof_ [c=garish] {_httpimg_/garish/title_bn.gif}
+
+## We also need to specify the width of the icons
+_widthttitlx_ [c=garish] {59}
+
+##
+## Note that the above is only for English - if you want custom icons for
+## other languages, you need (eg for French, which is l=fr):
+##
+##_httpiconttitlegr_ [c=garish,l=fr] {_httpimg_/garish/fr_title_green.gif}
+##_httpiconttitleon_ [c=garish,l=fr] {_..._}
+##_httpiconttitleof_ [c=garish,l=fr] {_httpimg_/garish/fr_title_button.gif}
+
+## See english.dm for a list of graphical button names - they all start
+## with "_httpicon".
+
+
+##############################################################################
+package Style
+##############################################################################
+
+## Style package is responsible for creating the header and footer of every
+## page. This is special as there is no style action as such - the other
+## actions include macros from here.
+
+## htmlhead is used by the default _header_ macros. It prints out the
+## beginning of an html file, including the header. We can override it here
+## so that all pages will use our custom style sheet. Includes some javascript
+## functions for rollover of images.
+_htmlhead_ [c=garish] {<html>
+<head>
+   <title>_pagetitle_</title>
+   <link rel="stylesheet" href="_httpimg_/garish/style.css" type="text/css"/>
+   _globalscripts_
+ </head>
+<body>
+<!-- end of custom style:htmlhead -->
+}
+
+
+## The default _pagebanner_ includes the collection's logo, the
+## home/help/preferences buttons, and a large image that says whether
+## you're viewing the about page, the search page, the titles page, etc.
+
+## Uncomment this or define style:pagebanner to something else if you don't
+## want any of those images appearing
+
+_pagebanner_ [c=garish] {}
+
+##############################################################################
+package about
+##############################################################################
+## "about" is page you see when you first go to a collection. The default
+## versions of these macros are in the about.dm file.
+
+## content by default has the navigationbar (links to Search and classifiers),
+## and "About this collection" and "how to find information" text.
+## The _navigationbar_ macro is defined internally by the greenstone server,
+## and uses the _imagespacer_ macro defined in the Global section.
+##
+## This is similar to the default, except we don't centre the _navigationbar_
+## and we don't include a search box on the collection's about page.
+_content_ [c=garish] {
+<!-- start of custom about:content -->
+_optnavigationbar_
+
+_textabout_
+
+<h3>_help:textsimplehelpheading_</h3>
+_help:simplehelp_
+
+<!-- end of custom about:content -->
+}
+
+
+##############################################################################
+package query
+##############################################################################
+## These are macros related to creating the search page. The default versions
+## are in the file query.dm
+
+
+## This is similar to the default, except we don't centre the _navigationbar_
+## and we've removed the green bars.
+_content_ [c=garish] {
+<!-- start of custom query:content -->
+_navigationbar_
+
+<center>
+_If_(_cgiargct_,_selectqueryform_,_queryform_)
+</center>
+_If_(_searchhistorylist_,<center>_iconsearchhistorybar_</center><br>
+<center>
+_searchhistorylist_
+</center>)
+_If_(_cgiargq_,<small>_freqmsg_ _textpostprocess_</small><br>_resultline_,)
+<br>
+<!-- end of custom query:content -->
+}
+
+
+##############################################################################
+package document
+##############################################################################
+## These are macros related to creating a document page. The default versions
+## are in the file document.dm. Note that technically, the classifiers are
+## also document pages (eg the title lists).
+
+## Note that the server overrides the _header_ macro if we are "not at the
+## top level", which basically means that when viewing a document (and not
+## a classifier), there won't be a heading.
+##
+## We can get around this by re-defining the textheader macro to output
+## what we want (instead of the normal version in document.dm). We copy the 
+## Global version of _header_ (from style.dm) and add it as the content of
+## _textheader_. Note that we can't just use 
+## _textheader_ [c=garish] {_Global:header_}
+## as any package specific macros (eg _pagetitle_) will no longer be used.
+
+_textheader_ [c=garish] {
+_cgihead_
+_htmlhead_(background="_httpiconchalk_")_startspacer__pagebanner_
+}
+
+
+
+
+## Override the default so that we are not centering the navigation bar.
+## The library will automatically output the document after this.
+_content_ [c=garish] {
+<!-- start of custom document:content -->
+_navigationbar_
+<p>
+<center>
+_phindclassifier_
+_collageclassifier_
+</center>
+<!-- end of custom document:content -->
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/georgian.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/georgian.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/georgian.dm	(revision 10506)
@@ -0,0 +1,1241 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Georgian Language text and icon macros 
+# Many thanks to George Varamishvili (translated June 2004)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=ka] {ááá áááááá}
+_textsource_ [l=ka] {á¬á§áá á:}
+_textdate_ [l=ka] {áááááªáááá¡ ááá ááŠá}
+_textnumpages_ [l=ka] {áááá ááááá¡ á áááááááá: }
+
+_textsignin_ [l=ka] {ášáá¡ááá}
+
+_textdefaultcontent_ [l=ka] {áááá®áááááá áááá áá áá  áááá«áááá áááá á£áááá <a href="javascript:history.back()">á£ááá</a>}
+
+_textdefaulttitle_ [l=ka] {ášááªáááá}
+
+_textbadcollection_ [l=ka] {ááááá¥áªáá  ("_cvariable_") áá  áá áá¡ ááááá¡á¢áááá ááá£áá áá ááá¡á¢áá£ááá¡ áªáá€á á£áá ááááááááááá¡ á¡áá¡á¢áááášá}
+
+_textselectpage_ [l=ka] {-- ááá á©ááá áááá áá  --}
+
+_collectionextra_ [l=ka] {ááááá¥áªáá ášáááªááá¡ _about:numdocs_ áááá£áááá¢á¡. 
+ááá  _about:builddate_ ááŠáá¡ á¬áá áááá.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=ka] {<p>ááááá¥áªáá ášáááªááá¡_numdocs_ _If_("_numdocs_" eq "1",áááá£áááá¢á¡,áááá£áááá¢á¡), á¡ááá áá áááªá£ááááá : _numbytes_.
+<p><a href="_httppagex_(bsummary)">áááá­áá áá </a>Â  ááááá¥áªááá¡ ášáá¥áááá¡ á ááá£ááá¡ á¡áááá®áááá.
+}
+
+_textimagecollection_ [l=ka] {}
+_textimageabout_ [l=ka] {áá ááá¥á¢áá¡ ášáá¡áá®áá}
+_textimagehome_ [l=ka] {áááááá á áááá áá}
+_textimagehelp_ [l=ka] {ááá®ááá áááá¡ áááá áá}
+_textimagepref_ [l=ka] {ááá áááá¢á ááá}
+_textimagegreenstone_ [l=ka] {áá ááá¡á¢áá£ááá¡ áªáá€á á£áá ááááááááááá¡ áá ááá ááá£áá á£áá á£ááááá§áá€á}
+_textimageusab_ [l=ka] {á£áá£áááášáá á: á áá¡á ááááá§ááááá ááááá­áá ááá?}
+
+_textimagesearch_ [l=ka] {á«áááá á¢áá ááááááá}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=ka] {á¡áááá£á áááá¡ á¡ááá¡ ááááááááá ááá ááááááá¡ ááá®ááááá}
+_textimageCreator_ [l=ka] {ááá¢áá áááá¡ ááááááá¡ ááá®ááááá ááááááááá ááá}
+_textimageSubject_ [l=ka] {ááááááááá ááá á¡áááááá ááá á á£áá áááááá}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=ka] {ááá ááŠáá¡ ááá®ááááá ááááááááá ááá }
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=ka] {ááááááááá ááá á€ááááááá¡ á¡áá®áááááá}
+_textimageLanguage_ [l=ka] {ááááááááá ááá áááááá¡ ááá®ááááá}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=ka] {ááááááááá ááá áá áááááááªááááá¡ ááá®ááááá}
+_textimageKeyword_ [l=ka] {ááááááááá ááá á¡áááááá«á á¡áá¢á§ááá¡ ááá®ááááá}
+_textimageHowto_ [l=ka] {ááááááááá ááá  á¡áášá£áááááááá¡ ááá¢áááá ááááá¡ ááá®ááááá}
+_textimageList_ [l=ka] {áááá£áááá¢áááá¡ á¡ááá¡ ááááááááá ááá }
+_textimageSeries_ [l=ka] {áááááªáááááá¡ ááááááááá ááá}
+_textimageTo_ [l=ka] {ááááááááá áááâááá¡â ááááá}
+_textimageFrom_ [l=ka] {ááááááááá ááá  âááá¡áááâ ááááá}
+_textimageTopic_ [l=ka] {ááááááááá ááá á¡áááªáááá£á á ááááááá¡ ááá®ááááá}
+_textimageBrowse_ [l=ka] {ááááááááá ááá}
+_textimageCollage_ [l=ka] {á¡á£á áááááá¡ ááááááá¡ ááá®ááááá ááááááááá ááá}
+_textimagePeople_ [l=ka] {ááá á¡ááááááá¡ á¡ááá¡ ááááááááá ááá }
+_textimageAcronym_ [l=ka] {ááá áááááááá¡ ááááááááá ááá}
+_textimagePhrase_ [l=ka] {ááááááááá ááá á€á áááááá¡ ááá®ááááá}
+_textimageArtist_ [l=ka] {á®áááááááá á¡ááá¡ ááááááááá ááá}
+_textimageVolume_ [l=ka] {ááááááááá ááá á¢áááááá¡ ááá®ááááá}
+_textimageCountries_ [l=ka] {á¥ááá§ááááá¡ ááá®ááááá ááááááááá ááá}
+_textimageCaptions_ [l=ka] {á€áá¢ááááá¡ ááááááááá ááá á¬áá á¬áá áááá}
+
+
+_texticontabsearchgreen_ [l=ka] {á«áááá}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=ka] {á¡áááá£á ááá ááááááá¡ ááá®ááááá}
+_texticontabCreatorgreen_ [l=ka] {ááá¢áá ááá ááááááá¡ ááá®ááááá}
+_texticontabSubjectgreen_ [l=ka] {á¡áááááá ááá á á£áá ááááá }
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=ka] {ááá ááŠá}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=ka] {á€ááááááá¡ á¡áá®ááááá}
+_texticontabLanguagegreen_ [l=ka] {ááá}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=ka] {áá áááááááªáá}
+_texticontabKeywordgreen_ [l=ka] {á¡áááááá«á á¡áá¢á§áááá}
+_texticontabhowgreen_ [l=ka] {á¡áášá£ááááááá}
+_texticontabseriesgreen_ [l=ka] {á¡áá áááá}
+_texticontablistgreen_ [l=ka] {á©áááááááááá}
+_texticontabtogreen_ [l=ka] {âááá¡â}
+_texticontabfromgreen_ [l=ka] {âááá¡áááâ}
+_texticontabtopicgreen_ [l=ka] {áááááá}
+_texticontabbrwsegreen_ [l=ka] {ááááááááá ááá}
+_texticontabCollagegreen_ [l=ka] {áááááá}
+_texticontabbrowsgreen_ [l=ka] {ááááááááá ááá}
+_texticontabPeoplegreen_ [l=ka] {ááá á¡áááááá ááááááá¡ ááá®ááááá}
+_texticontabAcronymgreen_ [l=ka] {ááá ááááááá}
+_texticontabPhrasegreen_ [l=ka] {á€á ááááá}
+_texticontabArtistgreen_ [l=ka] {á®ááááááá}
+_texticontabVolumegreen_ [l=ka] {á¢ááááá}
+_texticontabCaptionsgreen_ [l=ka] {á¬áá á¬áá ááá}
+_texticontabCountriesgreen_ [l=ka] {á¥ááá§áááá}
+
+_texticontext_ [l=ka] {áááá£áááá¢áá¡ ááá®áá}
+_texticonclosedbook_ [l=ka] {áááá£áááá¢áá¡ ášááááá á¡áá¡ ááá®áá}
+_texticonnext_ [l=ka] {ášáááááá áááá§áá€ááááá}
+_texticonprev_ [l=ka] {á¬ááá áááá§áá€ááááá}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=ka] {MIDI áááá£áááá¢áá¡ ááá®áá}
+_texticonmsword_ [l=ka] {Microsoft Word  áááá£áááá¢áá¡ ááá®áá}
+_texticonmp3_ [l=ka] {MP3 áááá£áááá¢áá¡ ááá®áá}
+_texticonpdf_ [l=ka] {PDF áááá£áááá¢áá¡ ááá®áá}
+_texticonps_ [l=ka] {PostScript  áááá£áááá¢áá¡ ááá®áá}
+_texticonppt_ [l=ka] {PowerPoint-áá¡  áááá£áááá¢áá¡ ááá®áá}
+_texticonrtf_ [l=ka] {RTF áááá£áááá¢áá¡ ááá®áá}
+_texticonxls_ [l=ka] {Microsoft Excel áááá£áááá¢áá¡ ááá®áá}
+
+_page_ [l=ka] {áááá áá}
+_pages_ [l=ka] {áááá áááá}
+_of_ [l=ka] {ááá}
+_vol_ [l=ka] {á¢ááá}
+_num_ [l=ka] {áá á}
+
+_textmonth00_ [l=ka] {}
+_textmonth01_ [l=ka] {áááááá á}
+_textmonth02_ [l=ka] {ááááá áááá}
+_textmonth03_ [l=ka] {ááá á¢á}
+_textmonth04_ [l=ka] {ááá ááá}
+_textmonth05_ [l=ka] {áááá¡á}
+_textmonth06_ [l=ka] {ááááá¡á}
+_textmonth07_ [l=ka] {ááááá¡á}
+_textmonth08_ [l=ka] {ááááá¡á¢á}
+_textmonth09_ [l=ka] {á¡áá¥á¢ááááá á}
+_textmonth10_ [l=ka] {áá¥á¢ááááá á}
+_textmonth11_ [l=ka] {ááááááá á}
+_textmonth12_ [l=ka] {áááááááá á}
+
+_textdocument_ [l=ka] {áááá£áááá¢á}
+_textsection_ [l=ka] {áááá§áá€ááááá}
+_textparagraph_ [l=ka] {ááá ááá áá€á}
+
+_magazines_ [l=ka] {áá£á áááááá}
+
+_nzdlpagefooter_ [l=ka] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">áá®ááá ááááááááá¡ áªáá€á á£áá ááááááááááá¡ áá ááá¥á¢á</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">áááááá£á¢áá á£á áááªáááá ááááá áááááá á</a>, 
+<a href="http://www.waikato.ac.nz">áááááá¢áá¡ á£ááááá á¡á¢áá¢á</a>, 
+áá®ááá áááááááá}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "áááááá á áááá áá" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=ka] {_httpimg_/ka/chomeof.gif}
+_httpiconchomeon_ [l=ka] {_httpimg_/ka/chomeon.gif}
+
+## "ááá®ááá ááá" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=ka] {_httpimg_/ka/chelpof.gif}
+_httpiconchelpon_ [l=ka] {_httpimg_/ka/chelpon.gif}
+
+## "ááá áááá¢á ááá" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=ka] {_httpimg_/ka/cprefof.gif}
+_httpiconcprefon_ [l=ka] {_httpimg_/ka/cprefon.gif}
+
+## "á£áá£áááášáá á" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=ka] {_httpimg_/ka/cusabof.gif}
+_httpiconcusabon_ [l=ka] {_httpimg_/ka/cusabon.gif}
+
+
+## "á«áááá" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=ka] {_httpimg_/ka/tsrchgr.gif}
+_httpicontsrchof_ [l=ka] {_httpimg_/ka/tsrchof.gif}
+_httpicontsrchon_ [l=ka] {_httpimg_/ka/tsrchon.gif}
+_widthtsrchx_ [l=ka] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "á¡áááá£á ááá ááááááá¡ á¡á®ááááá" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=ka] {_httpimg_/ka/ttitlgr.gif}
+_httpiconttitleof_ [l=ka] {_httpimg_/ka/ttitlof.gif}
+_httpiconttitleon_ [l=ka] {_httpimg_/ka/ttitlon.gif}
+_widthttitlex_ [l=ka] {211}
+
+# Not true DC, kept for legacy reasons
+## "ááá¢áá ááá ááááááá¡ á¡á®ááááá" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=ka] {_httpimg_/ka/tauthgr.gif}
+_httpicontcreatof_ [l=ka] {_httpimg_/ka/tauthof.gif}
+_httpicontcreaton_ [l=ka] {_httpimg_/ka/tauthon.gif}
+_widthtcreatx_ [l=ka] {202}
+
+## "á¡áááááá ááá á á£áá ááááá" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=ka] {_httpimg_/ka/tsubjgr.gif}
+_httpicontsubjon_ [l=ka] {_httpimg_/ka/tsubjon.gif}
+_httpicontsubjof_ [l=ka] {_httpimg_/ka/tsubjof.gif}
+_widthtsubjx_ [l=ka] {174}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "ááá ááŠá" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=ka] {_httpimg_/ka/tdategr.gif}
+_httpicontdateof_ [l=ka] {_httpimg_/ka/tdateof.gif}
+_httpicontdateon_ [l=ka] {_httpimg_/ka/tdateon.gif}
+_widthtdatex_ [l=ka] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "á€ááááááá¡ á¡áá®ááááá" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=ka] {_httpimg_/ka/tsrcgr.gif}
+_httpicontsrcof_ [l=ka] {_httpimg_/ka/tsrcof.gif}
+_httpicontsrcon_ [l=ka] {_httpimg_/ka/tsrcon.gif}
+_widthtsrcx_ [l=ka] {148}
+
+## "ááá" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=ka] {_httpimg_/ka/tlanggr.gif}
+_httpicontlangon_ [l=ka] {_httpimg_/ka/tlangon.gif}
+_httpicontlangof_ [l=ka] {_httpimg_/ka/tlangof.gif}
+_widthtlangx_ [l=ka] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "á¡áá áááá" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=ka] {_httpimg_/ka/tsergr.gif}
+_httpicontserof_ [l=ka] {_httpimg_/ka/tserof.gif}
+_httpicontseron_ [l=ka] {_httpimg_/ka/tseron.gif}
+_widthtserx_ [l=ka] {87}
+
+## "âááá¡â" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=ka] {_httpimg_/ka/ttogr.gif}
+_httpiconttoon_ [l=ka] {_httpimg_/ka/ttoon.gif}
+_httpiconttoof_ [l=ka] {_httpimg_/ka/ttoof.gif}
+_widthttox_ [l=ka] {87}
+
+## "âááá¡áááâ" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=ka] {_httpimg_/ka/tfromgr.gif}
+_httpicontfromon_ [l=ka] {_httpimg_/ka/tfromon.gif}
+_httpicontfromof_ [l=ka] {_httpimg_/ka/tfromof.gif}
+_widthtfromx_ [l=ka] {87}
+
+## "áá áááááááªáááá" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=ka] {_httpimg_/ka/torggr.gif}
+_httpicontorgon_ [l=ka] {_httpimg_/ka/torgon.gif}
+_httpicontorgof_ [l=ka] {_httpimg_/ka/torgof.gif}
+_widthtorgx_ [l=ka] {113}
+
+## "á¡áášá£ááááááá" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=ka] {_httpimg_/ka/thowgr.gif}
+_httpiconthowon_ [l=ka] {_httpimg_/ka/thowon.gif}
+_httpiconthowof_ [l=ka] {_httpimg_/ka/thowof.gif}
+_widththowx_ [l=ka] {98}
+
+## "áááá" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=ka] {_httpimg_/ka/ttopicgr.gif}
+_httpiconttopicon_ [l=ka] {_httpimg_/ka/ttopicon.gif}
+_httpiconttopicof_ [l=ka] {_httpimg_/ka/ttopicof.gif}
+_widthttopicx_ [l=ka] {87}
+
+## "ááááááááá ááá" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=ka] {_httpimg_/ka/tbrwsegr.gif}
+_httpicontbrwseon_ [l=ka] {_httpimg_/ka/tbrwseon.gif}
+_httpicontbrwseof_ [l=ka] {_httpimg_/ka/tbrwseof.gif}
+_widthtbrwsex_ [l=ka] {113}
+
+## "áááááá" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=ka] {_httpimg_/ka/tcollgr.gif}
+_httpicontcollof_ [l=ka] {_httpimg_/ka/tcollof.gif}
+_httpicontcollon_ [l=ka] {_httpimg_/ka/tcollon.gif}
+_widthtcollx_ [l=ka] {87}
+
+## "ááá á¡áááááá ááááááá¡ á¡á®ááááá" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=ka] {_httpimg_/ka/tpeopgr.gif}
+_httpicontpeopof_ [l=ka] {_httpimg_/ka/tpeopof.gif}
+_httpicontpeopon_ [l=ka] {_httpimg_/ka/tpeopon.gif}
+_widthtpeopx_ [l=ka] {219}
+
+## "ááá ááááá" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=ka] {_httpimg_/ka/tacrogr.gif}
+_httpicontacroof_ [l=ka] {_httpimg_/ka/tacroof.gif}
+_httpicontacroon_ [l=ka] {_httpimg_/ka/tacroon.gif}
+_widthtacrox_ [l=ka] {87}
+
+## "á€á ááááá" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=ka] {_httpimg_/ka/tphrsegr.gif}
+_httpicontphrseof_ [l=ka] {_httpimg_/ka/tphrseof.gif}
+_httpicontphrseon_ [l=ka] {_httpimg_/ka/tphrseon.gif}
+_widthtphrsex_ [l=ka] {87}
+
+## "á®ááááááá" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=ka] {_httpimg_/ka/tartstgr.gif}
+_httpicontartstof_ [l=ka] {_httpimg_/ka/tartstof.gif}
+_httpicontartston_ [l=ka] {_httpimg_/ka/tartston.gif}
+_widthtartstx_ [l=ka] {87}
+
+## "á¡áááááá«á á¡áá¢á§áááá" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=ka] {_httpimg_/ka/tkwgr.gif}
+_httpicontkwof_ [l=ka] {_httpimg_/ka/tkwof.gif}
+_httpicontkwon_ [l=ka] {_httpimg_/ka/tkwon.gif}
+_widthtkwx_ [l=ka] {139}
+
+## "á¢ááááá" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=ka] {_httpimg_/ka/tvolgr.gif}
+_httpicontvolof_ [l=ka] {_httpimg_/ka/tvolof.gif}
+_httpicontvolon_ [l=ka] {_httpimg_/ka/tvolon.gif}
+_widthtvolx_ [l=ka] {87}
+
+## "á¬áá á¬áá ááá" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=ka] {_httpimg_/ka/tcaptgr.gif}
+_httpicontcaptof_ [l=ka] {_httpimg_/ka/tcaptof.gif}
+_httpicontcapton_ [l=ka] {_httpimg_/ka/tcapton.gif}
+_widthtcaptx_ [l=ka] {87}
+
+## "á¥ááá§áááá" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=ka] {_httpimg_/ka/tcountgr.gif}
+_httpicontcountof_ [l=ka] {_httpimg_/ka/tcountof.gif}
+_httpicontcounton_ [l=ka] {_httpimg_/ka/tcounton.gif}
+_widthtcountx_ [l=ka] {87}
+
+## "ááá®ááá ááá" ## green_title ## h_help ##
+_httpiconhhelp_ [l=ka] {_httpimg_/ka/h\_help.gif}
+_widthhhelp_ [l=ka] {258}
+_heighthhelp_ [l=ka] {74}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=ka] {ááááá¥áªááá¡ ášáá¡áá®áá}
+
+_textsubcols1_ [l=ka] {<p>ááááá¥áªáá ášáááªááá¡_1_  á¥ááááááá¥áªáááá¡:
+<blockquote>}
+
+_textsubcols2_ [l=ka] {</blockquote>
+áá¥ááá ášáááá«áááá ášááááá¬ááá (ášááá¡á¬áá áá) á¥ááááááá¥áªáááá ááá áááá¢á áááá¡ áááá ááá¡ ááá®ááá áááá.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ášáá¡áá®áá" ## green_title ## h_about ##
+_httpiconhabout_ [l=ka] {_httpimg_/ka/h\_about.gif}
+_widthhabout_ [l=ka] {258}
+_heighthabout_ [l=ka] {74}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=ka] {á¡áááá£á ááá ááááááá¡ ááá®ááááá}
+_texticonhcreat_ [l=ka] {ááá¢áá ááá ááááááá¡ ááá®ááááá}
+_texticonhsubj_ [l=ka] {á¡áááááá ááá á á£áá ááááá }
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=ka] {ááá ááŠááá}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=ka] {á€áááááá}
+_texticonhlang_ [l=ka] {ááá}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+_texticonhcoll_ [l=ka] {áááááá}
+_texticonhto_ [l=ka] {âááá¡â}
+_texticonhfrom_ [l=ka] {âááá¡áááâ}
+_texticonhser_ [l=ka] {á¡áá áááá}
+_texticonhhow_ [l=ka] {á¡áášá£ááááááá}
+_texticonhorg_ [l=ka] {áá áááááááªáááá}
+_texticonhbrwse_ [l=ka] {ááááááááá ááá}
+_texticonhbrows_ [l=ka] {ááááááááá ááá}
+_texticonhpeople_ [l=ka] {ááá á¡áááááá ááááááá¡ ááá®ááááá}
+_texticonhacronym_ [l=ka] {ááá ááááááá}
+_texticonhphrases_ [l=ka] {á€á ááááá}
+_texticonhartist_ [l=ka] {á®ááááááá}
+_texticonhkw_ [l=ka] {á¡áááááá«á á¡áá¢á§áá}
+_texticonhvol_ [l=ka] {á¢ááááá}
+_texticonhcapt_ [l=ka] {á¬áá á¬áá ááá}
+_texticonhcount_ [l=ka] {á¥ááá§áááá}
+
+_texticonopenbookshelf_ [l=ka] {áááá§áá€áááááá¡ ááá®á£á áá}
+_texticonclosedbookshelf_ [l=ka] {áááá§áá€áááááá¡ ááá®á¡áá áá ášáá¥áááá¡áá¡ ááá®áá}
+_texticonopenbook_ [l=ka] {á¬ááááá¡ ááá®á£á áá}
+_texticonclosedfolder_ [l=ka] {á€ááááá áá¡ ááá®áá áá á¡áá á©áááá¡ ááá®áá}
+_texticonclosedfolder2_ [l=ka] {á¥áááááá§áá€áááááá¡ ááá®á¡áá: }
+_texticonopenfolder_ [l=ka] {á€ááááá áá¡ ááá®á£á áá}
+_texticonopenfolder2_ [l=ka] {á¥áááááá§áá€áááááá¡ ááá®á£á áá: }
+_texticonsmalltext_ [l=ka] {á¢áá¥á¡á¢áá¡ áááá§áá€áááááá¡ ááá®áá}
+_texticonsmalltext2_ [l=ka] {á¢áá¥á¡á¢áá¡ ááá®áá: }
+_texticonpointer_ [l=ka] {áááááááá á áááá§áá€ááááá}
+_texticondetach_ [l=ka] {áááá ááá¡ ááá®á¡áá áá®áá á€ááá¯áá áášá}
+_texticonhighlight_ [l=ka] {á¡áá«áááá á¡áá¢á§ááááá¡ ááááá§áá€á}
+_texticonnohighlight_ [l=ka] {áá  ááááá§áá¡ á¡áá«áááá á¡áá¢á§áááá}
+_texticoncontracttoc_ [l=ka] {á¡áá á©áááá¡ ááááªáá}
+_texticonexpandtoc_ [l=ka] {á¡áá á©áááá¡ ááá€áá ááááá}
+_texticonexpandtext_ [l=ka] {ááááá á¢áá¥á¡á¢áá¡ ááááá¢ááá}
+_texticoncontracttext_ [l=ka] {á¢áá¥á¡á¢áá¡ ááááá¢ááá áá®áááá áá®ááá áá á©áá£áá áááá§áá€áááááááá}
+_texticonwarning_ [l=ka] {<b>ááá€á áá®ááááá: </b>}
+_texticoncont_ [l=ka] {áááá á«ááááá?}
+
+_textltwarning_ [l=ka] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_ááášáááá á¢áá¥á¡á¢á áááá áááªá£ááááá¡áá áá¥áááá áá áá£áááá¡áááá¡ _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=ka] {ááááá¡ááá áááá ááá}
+_textintro_ [l=ka] {<i>(ášáá¡ááááá á¢áá¥á¡á¢á)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "á¡áááá£á ááá\nááááááá¡ á¡á®ááááá" ## green_title ## h_title ##
+_httpiconhtitle_ [l=ka] {_httpimg_/ka/h\_title.gif}
+_widthhtitle_ [l=ka] {258}
+_heighthtitle_ [l=ka] {74}
+
+# Not true DC, kept for legacy reasons
+## "ááá¢áá ááá\nááááááá¡ á¡á®ááááá" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=ka] {_httpimg_/ka/h\_auth.gif}
+_widthhcreat_ [l=ka] {258}
+_heighthcreat_ [l=ka] {74}
+
+## "á¡áááááá ááá\ná á£áá ááááá" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=ka] {_httpimg_/ka/h\_subj.gif}
+_widthhsubj_ [l=ka] {258}
+_heighthsubj_ [l=ka] {74}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "ááá ááŠá" ## green_title ## h_date ##
+_httpiconhdate_ [l=ka] {_httpimg_/ka/h\_date.gif}
+_widthhdate_ [l=ka] {258}
+_heighthdate_ [l=ka] {74}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "á€ááááááá¡\ná¡áá®ááááá" ## green_title ## h_src ##
+_httpiconhsrc_ [l=ka] {_httpimg_/ka/h\_src.gif}
+_widthhsrc_ [l=ka] {258}
+_heighthsrc_ [l=ka] {74}
+
+## "ááá" ## green_title ## h_lang ##
+_httpiconhlang_ [l=ka] {_httpimg_/ka/h\_lang.gif}
+_widthhlang_ [l=ka] {258}
+_heighthlang_ [l=ka] {74}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "âááá¡â" ## green_title ## h_to ##
+_httpiconhto_ [l=ka] {_httpimg_/ka/h\_to.gif}
+_widthhto_ [l=ka] {258}
+_heighthto_ [l=ka] {74}
+
+## "âááá¡áááâ" ## green_title ## h_from ##
+_httpiconhfrom_ [l=ka] {_httpimg_/ka/h\_from.gif}
+_widthhfrom_ [l=ka] {258}
+_heighthfrom_ [l=ka] {74}
+
+## "á¡áá áááá" ## green_title ## h_ser ##
+_httpiconhser_ [l=ka] {_httpimg_/ka/h\_ser.gif}
+_widthhser_ [l=ka] {258}
+_heighthser_ [l=ka] {74}
+
+## "á¡áášá£ááááááá" ## green_title ## h_how ##
+_httpiconhhow_ [l=ka] {_httpimg_/ka/h\_how.gif}
+_widthhhow_ [l=ka] {258}
+_heighthhow_ [l=ka] {74}
+
+## "ááá¡áá" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=ka] {_httpimg_/ka/h\_topic.gif}
+_widthhtopic_ [l=ka] {258}
+_heighthtopic_ [l=ka] {74}
+
+## "áá áááááááªáá" ## green_title ## h_org ##
+_httpiconhorg_ [l=ka] {_httpimg_/ka/h\_org.gif}
+_widthhorg_ [l=ka] {258}
+_heighthorg_ [l=ka] {74}
+
+## "ááááááááá ááá" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=ka] {_httpimg_/ka/h\_brwse.gif}
+_widthhbrwse_ [l=ka] {258}
+_heighthbrwse_ [l=ka] {74}
+
+# -- Missing translation: h_coll
+_httpiconhcoll_ [l=ka] {_httpimg_/ka/h\_coll.gif}
+_widthhcoll_ [l=ka] {258}
+_heighthcoll_ [l=ka] {74}
+
+## "ááá á¡áááááá" ## green_title ## h_people ##
+_httpiconhpeople_ [l=ka] {_httpimg_/ka/h\_people.gif}
+_widthhpeople_ [l=ka] {258}
+_heighthpeople_ [l=ka] {74}
+
+## "ááá ááááááá" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=ka] {_httpimg_/ka/h\_acro.gif}
+_widthhacronym_ [l=ka] {258}
+_heighthacronym_ [l=ka] {74}
+
+## "á€á ááááá" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=ka] {_httpimg_/ka/h\_phrse.gif}
+_widthhphrse_ [l=ka] {258}
+_heighthphrse_ [l=ka] {74}
+
+## "á®ááááááá" ## green_title ## h_artist ##
+_httpiconhartist_ [l=ka] {_httpimg_/ka/h\_artist.gif}
+_widthhartist_ [l=ka] {258}
+_heighthartist_ [l=ka] {74}
+
+## "á¡áááááá«á\ná¡áá¢á§áááá" ## green_title ## h_kw ##
+_httpiconhkw_ [l=ka] {_httpimg_/ka/h\_kw.gif}
+_widthhkw_ [l=ka] {258}
+_heighthkw_ [l=ka] {74}
+
+## "á¢ááááá" ## green_title ## h_vol ##
+_httpiconhvol_ [l=ka] {_httpimg_/ka/h\_vol.gif}
+_widthhvol_ [l=ka] {258}
+_heighthvol_ [l=ka] {74}
+
+## "á¥ááá§áááá" ## green_title ## h_count ##
+_httpiconhcount_ [l=ka] {_httpimg_/ka/h\_count.gif}
+_widthhcount_ [l=ka] {258}
+_heighthcount_ [l=ka] {74}
+
+## "á¬áá á¬áá ááá" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=ka] {_httpimg_/ka/h\_capt.gif}
+_widthhcapt_ [l=ka] {258}
+_heighthcapt_ [l=ka] {74}
+
+
+## "áááá á«ááááá?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=ka] {_httpimg_/ka/contof.gif}
+_httpiconconton_ [l=ka] {_httpimg_/ka/conton.gif}
+
+## "á¢áá¥á¡á¢áá¡\nááášáá" ## document_button ## eallt ##
+_httpiconealltof_ [l=ka] {_httpimg_/ka/ealltof.gif}
+_httpiconeallton_ [l=ka] {_httpimg_/ka/eallton.gif}
+
+## "á®ááášááá á£ááááá¡\nášááááá á¡á" ## document_button ## econc ##
+_httpiconeconcof_ [l=ka] {_httpimg_/ka/econcof.gif}
+_httpiconeconcon_ [l=ka] {_httpimg_/ka/econcon.gif}
+
+## "áá®ááá\ná€ááá¯áá á" ## document_button ## edtch ##
+_httpiconedtchof_ [l=ka] {_httpimg_/ka/edtchof.gif}
+_httpiconedtchon_ [l=ka] {_httpimg_/ka/edtchon.gif}
+
+## "á¡áá á©áááá¡\nááášáá" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=ka] {_httpimg_/ka/eexpcof.gif}
+_httpiconeexpcon_ [l=ka] {_httpimg_/ka/eexpcon.gif}
+
+## "á®ááášááá á£ááááá¡\ná¢áá¥á¡á¢á" ## document_button ## etsec ##
+_httpiconetsecof_ [l=ka] {_httpimg_/ka/etsecof.gif}
+_httpiconetsecon_ [l=ka] {_httpimg_/ka/etsecon.gif}
+
+## "ááááášááá" ## document_button ## ehl ##
+_httpiconehlof_ [l=ka] {_httpimg_/ka/ehlof.gif}
+_httpiconehlon_ [l=ka] {_httpimg_/ka/ehlon.gif}
+
+## "ááááášáááá¡\ná£áá á§áá€á" ## document_button ## enhl ##
+_httpiconenhlof_ [l=ka] {_httpimg_/ka/enhlof.gif}
+_httpiconenhlon_ [l=ka] {_httpimg_/ka/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=ka] {_If_(_thislast_,results _thisfirst_ - _thislast_ for query: _cgiargq_,No matches for query: _cgiargq_)}
+_textnoquerytitle_ [l=ka] {á«ááááá¡ áááá áá}
+
+_texticonthispage_ [l=ka] {á«áááá}
+_textsome_ [l=ka] {á ááááááááá}
+_textall_ [l=ka] {á§áááá}
+_textboolean_ [l=ka] {áá£ááá¡}
+_textranked_ [l=ka] {á ááááá ááá£áá}
+_textnatural_ [l=ka] {á©ááá£áááá ááá}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=ka] {}
+_texticonsearchhistorybar_ [l=ka] {á«áááá áá á¥ááášá}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=ka] {ášááááá®ááá¡ ááááá§ááááá}
+_textfreqmsg1_ [l=ka] {á¡áá¢á§ááááá¡ á áááááááá: }
+_textpostprocess_ [l=ka] {áá£_(_áá á­á§ááááášá á©áá¡áá£áá ášááááá®ááá_,<br><i>ášááááááá áááá£ášááááá áá á­á§ááááášá á©áá¡áá£áá ášááááá®ááá¡ á¡áááá®áááá_</i>
+)
+}
+_textinvalidquery_ [l=ka] {ášááááá®ááá¡ áá áá¡á¬áá á á€áá áá !!!!}
+
+_textmorethan_ [l=ka] {ááá¢á áááá á}
+_textapprox_ [l=ka] {ášáá¡áá®áá}
+_textnodocs_ [l=ka] {ášááááá®ááá¡ ášáá¡áááááá¡á áááá£áááá¢ááá áá  áá á¡ááááá¡}
+_text1doc_ [l=ka] {ášááááá®ááá¡  ášááá¡áááááááá1 áááá£áááá¢á.}
+_textlotsdocs_ [l=ka] {ášááááá®ááá¡ ášáá¡áááááá¡á áááá£áááá¢ááá.}
+_textmatches_ [l=ka] {ášáá¡áááááá¡á áááá£áááá¢ááá}
+_textbeginsearch_ [l=ka] {á«ááááá¡ ááá¬á§ááá}
+_textrunquery_ [l=ka] {ášááááá®ááá¡ ááášáááá}
+_textclearform_ [l=ka] {ášááááá®ááá¡ ááášáááá}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=ka] {á¡áá¢á§áá áá á€á ááá}
+_textinfield_ [l=ka] {... áááášá}
+_textfoldstem_ [l=ka] {(áááááªá, á€á£á«á)}
+
+_textadvquery_ [l=ka] {ášááááá®ááá¡ ášáá¢ááá}
+_textallfields_ [l=ka] {á§áááá áááá}
+_texttextonly_ [l=ka] {áá®áááá á¢áá¥á¡á¢á}
+_textand_ [l=ka] {áá}
+_textor_ [l=ka] {áá}
+_textandnot_ [l=ka] {áá áá á}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=ka] {á«áááá _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_, at _gselection_ level )_If_(_nselection_,in _nselection_ language )á ááááááª ášáááªááá¡ _querytypeselection_ á¡áá«áááá á€á áááá¡}
+
+_textadvancedsearch_ [l=ka] {ááá«ááááá¡ _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_,at _gselection_ level )_If_(_nselection_,in _nselection_ language ) _querytypeselection_  ášááááá®ááá¡ ááááá§áááááá}
+
+_textformsimplesearch_ [l=ka] {á«áááá  _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language ) -ášá _formquerytypeselection_ }
+
+_textformadvancedsearch_ [l=ka] {á«áááá _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )ášá áá áááááªáááááá¡_formquerytypeselection_ order ááá®ááááá ááááá¢ááá}
+
+
+_textnojsformwarning_ [l=ka] {ááá€á áá®ááááá: áá¥ááá áá áá£ááá ášá ááááá áá£ááá JavaScript. <br> áááá¡áááá¡ á áá áááá®áá áªáááááá¡ á«áááá á©áá ááá JavaScript.}
+_textdatesearch_ [l=ka] {áá ááááá¥áªááášá áááá£áááá¢áááá¡ á«áááá  ášáá¡áá«ááááááá ááá ááŠáááá¡  ášá£ááááášá  áá áááá£áááá¢áááá¡ á«áááá ááááá áá¢á£áá ááá ááŠáá.}
+_textstartdate_ [l=ka] {á¡áá¬á§áá¡á ( áá áá®áááá) ááá ááŠá:}
+_textenddate_ [l=ka] {áááá ááá ááŠá:}
+_textbc_ [l=ka] {B.C.E.}
+_textad_ [l=ka] {C.E.}
+_textexplaineras_ [l=ka] {C.E. áá  B.C.E áá áá¡ ááá¢áá ááá¢áá£áá A.D. áá B.C. á¡áááá¡. á©ááá á¬áááááŠá ááªá®ááááá áá á©áááá á¬áááááŠá ááªá®ááá}
+
+_textstemon_ [l=ka] {(á¡áá¢á§ááááá¡ ááááááááááá ááááá áá ááá)}
+
+_textsearchhistory_ [l=ka] {á«ááááá¡ áá á¥ááá}
+
+#text macros for search history
+_textnohistory_ [l=ka] {áá á¥ááášá á«áááá áá áá ášáá¡áá«áááááá}
+_texthresult_ [l=ka] {ášááááá}
+_texthresults_ [l=ka] {ášááááá  (ááá£ááá¡á®áááá Found Results:)}
+_texthallwords_ [l=ka] {á§áááá á¡áá¢á§áá}
+_texthsomewords_ [l=ka] {á áááááááá á¡áá¢á§áá}
+_texthboolean_ [l=ka] {áá£ááá¡}
+_texthranked_ [l=ka] {á ááááá ááá£áá}
+_texthcaseon_ [l=ka] {á áááá¡á¢á áá¡ ááááá®áááá}
+_texthcaseoff_ [l=ka] {áááááá¡ ááááªáá}
+_texthstemon_ [l=ka] {á¬áááááááá }
+_texthstemoff_ [l=ka] {á¬áá£ááááááá}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "á«áááá" ## green_title ## h_search ##
+_httpiconhsearch_ [l=ka] {_httpimg_/ka/h\_search.gif}
+_widthhsearch_ [l=ka] {258}
+_heighthsearch_ [l=ka] {74}
+
+## "ášááááá" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=ka] {_httpimg_/ka/qryresb.gif}
+_widthqryresb_ [l=ka] {_pagewidth_}
+_heightqryresb_ [l=ka] {17}
+
+## "áá á¥ááá" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=ka] {_httpimg_/ka/schhistb.gif}
+_widthsrchhistb_ [l=ka] {_pagewidth_}
+_heightsrchhistb_ [l=ka] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=ka] {ááá áááá¢á ááá ááá§ááááá£ááá. áá£ áááááá§ááááá áá áá£ááá áá¡ âá£áááâ áŠááááá¡ áá¡ ááááá£áááá¡ ááá áááá¢á ááá¡.áááá­áá áá áá á-áá á áŠááááá¡ ááááá ááááááááá£á áááááášá.}
+_textsetprefs_ [l=ka] {ááá áááá¢á áááá¡ ááá§ááááá}
+_textsearchprefs_ [l=ka] {ááá áááá¢á áááá¡ á«áááá}
+_textcollectionprefs_ [l=ka] {ááááá¥áªááá¡ ááá áááá¢á ááá}
+_textpresentationprefs_ [l=ka] {áá ááááá¢ááªááá¡ ááá áááá¢á ááá}
+_textpreferences_ [l=ka] {ááá áááá¢á ááá}
+_textcasediffs_ [l=ka] {áááá¡á®áááááá£áá á áááá¡á¢á á:}
+_textignorecase_ [l=ka] {á áááá¡á¢á áá¡ áááá¡á®ááááááááá¡ ááááá áá ááá}
+_textmatchcase_ [l=ka] {á áááá¡á¢á áá¡ ááááá®áááá}
+_textwordends_ [l=ka] {á¡áá¢á§ááá¡ ááááááááá:}
+_textstem_ [l=ka] {á¡áá¢á§ááá¡ áááááááááá¡ ááááá áá ááá}
+_textnostem_ [l=ka] {ááááááá á¡áá¢á§ááá¡ ááááá®áááá}
+_textprefop_ [l=ka] {ááááá á£áááá¡ _maxdocoption_ á ááá£áá¢áá¢á¡ _hitsperpageoption_ á«ááááá¡ áááááá£á áááá ááá.}
+_textextlink_ [l=ka] {ááá á ááá áááá ááááá ááááá ááá:}
+_textintlink_ [l=ka] {áááá£áááá¢áááá¡ á¬á§áá á:}
+_textlanguage_ [l=ka] {ááá¢áá á€ááá¡áá¡ ááá:}
+_textencoding_ [l=ka] {ááááá ááá:}
+_textformat_ [l=ka] {ááá¢áá á€ááá¡áá¡ á€áá ááá¢á:}
+_textall_ [l=ka] {á§áááá}
+_textquerymode_ [l=ka] {ášááááá®ááá¡  á ááááá:}
+_textsimplemode_ [l=ka] {ááá á¢ááá á«áááá}
+_textadvancedmode_ [l=ka] {áááááááá ááá£áá á«áááá (ášáá¡áá«ááááááá áááááá£á á á«áááá !,&, |, áá áá á­á§áááááá¡ ááááá§áááááá)}
+_textlinkinterm_ [l=ka] {ášá£ááááá£á á áá áááááá áááá áá}
+_textlinkdirect_ [l=ka] {ááááá¡ááá}
+_textdigitlib_ [l=ka] {áªáá€á á£áá áááááááááá}
+_textweb_ [l=ka] {www}
+_textgraphical_ [l=ka] {áá áá€ááá£áá}
+_texttextual_ [l=ka] {á¢áá¥á¡á¢á£á á}
+_textcollectionoption_ [l=ka] {<p>
+ á¥ááááááá¥áªáá ášáááªááá¡:
+<br>}
+
+_textrelateddocdisplay_ [l=ka] {áá¡áááá¡á áááá£áááá¢áááá¡ ááááá¢ááá}
+_textsearchhistory_ [l=ka] {á«ááááá¡ áá á¥ááá:}
+_textnohistory_ [l=ka] {á«ááááá¡ áá á¥ááá áá  áá á¡ááááá¡}
+_texthistorydisplay_ [l=ka] {á«áááá¡ áá á¥áááááá _historynumrecords_ á©áááá¬áá áá¡ ááááá¢ááá}
+_textnohistorydisplay_ [l=ka] {á«ááááá¡ áá á¥áááá¡ ááá£á¥áááá}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=ka] {á«ááááá¡ á€áá áá:}
+_textplainsearch_ [l=ka] {ááá á¢ááá á«áááá:}
+_textqueryboxsize_ [l=ka] {á«ááááá¡ á£á¯á áá¡ áááá:}
+_textregbox_ [l=ka] {ááá áááá£á á á«ááááá¡ á£á¯á á}
+_textbigbox_ [l=ka] {áááá á«ááááá¡ á£á¯á á}
+_textformtype_ [l=ka] {á€áá ááá¡ á¢ááá:}
+_textsimple_ [l=ka] {ááá á¢ááá}
+_textadvanced_ [l=ka] {áááááááá ááá£áá}
+
+# used in "with 4 fields" in the form search box
+# -- Missing translation: _textwith_
+_textfields_ [l=ka] {áááááá}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ááá áááá¢á ááá" ## green_title ## h_pref ##
+_httpiconhpref_ [l=ka] {_httpimg_/ka/h\_pref.gif}
+_widthhpref_ [l=ka] {258}
+_heighthpref_ [l=ka] {74}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=ka] {áááá£áááá¢áááá¡ áááááááá}
+_textalsoshowing_ [l=ka] {áá¡ááá}
+_textwith_ [l=ka] {ááá¥á¡ááá£á}
+_textdocsperpage_ [l=ka] {áááá£áááá¢á áááá ááá}
+
+_textfilterby_ [l=ka] {áá áááá£áááá¢áááá¡ áááŠááá, á áááááááª ášáááªááá¡}
+_textall_ [l=ka] {á§áááá}
+_textany_ [l=ka] {ááááá¡áááá á}
+_textwords_ [l=ka] {á¡áá¢á§ááááá}
+_textleaveblank_ [l=ka] {áááá¡áááá¡ á áá ááá®áá á§áááá áááá£ááááá¢á, ááá¢áááá áá¡ á£á¯á á áªáá áááá}
+
+_browsebuttontext_ [l=ka] {"áááá£áááá¢áááá¡ ááá®áá áá¡á®ááá"}
+
+_nodata_ [l=ka] {<i>áááááªááááá áá  áá á¡ááááá¡</i>}
+_docs_ [l=ka] {áááá£áááá¢ááá}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=ka] {ááá®ááá ááá}
+_textSearchshort_ [l=ka] {áªááááá£áá á¡áá¢á§ááááá á«áááá}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=ka] {áááááªáááááá¡ ááá®áá á¡áááá£á áá}
+_textCreatorshort_ [l=ka] {áááááªáááááá¡ ááá®áá ááá¢áá áááá¡ ááá®ááááá}
+_textSubjectshort_ [l=ka] {áááááªáááááá¡ ááá®áá á¡áááááá ááá á á£áá áááá}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=ka] {áááááªáááááá¡ ááá®áá ááá ááŠáááá¡ ááá®ááááá}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=ka] {áááááªáááááá¡ ááá®áá  á€ááááá¡ á¡áá®áááá¡ ááá®ááááá}
+_textLanguageshort_ [l=ka] {áááááªáááááá¡ ááá®áá áááááá¡ ááá®ááááá}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=ka] {áááááªáááááá¡ ááá®áá á¡áá ááá¡ ááá®ááááá}
+_textToshort_ [l=ka] {áááááªáááááá¡ ááá®áá âááá¡â  ááááááá¡  ááá®ááááá}
+_textFromshort_ [l=ka] {áááááªáááááá¡ ááá®áá ááááááá¡ âááá¡áááâ  ááá®ááááá}
+_textBrowseshort_ [l=ka] {áááááªáááááá¡ ááááááááá ááá}
+_textOrganizationshort_ [l=ka] {áááááªáááááá¡ ááá®áá áá áááááááªááááá¡ ááá®ááááá}
+_textHowtoshort_ [l=ka] {áááááªáááááá¡ ááá®áá âá¡áášá£áááááááá¡â ááá®ááááá}
+_textTopicshort_ [l=ka] {áááááªáááááá¡ ááá®áá ááááááá¡ ááá®ááááá }
+_textPeopleshort_ [l=ka] {áááááªáááááá¡ ááá®áá ááá á¡ááááááá¡ ááá®ááááá}
+_textAcronymshort_ [l=ka] {áááááªáááááá¡ ááá®áá áááášá ááá áááááááá¡ áá á¡áááááá¡ ááá®ááááá}
+_textPhraseshort_ [l=ka] {áááááªáááááá¡ ááá®áá  á€á áááááá¡ ááá®ááááá}
+_textArtistshort_ [l=ka] {áááááªáááááá¡ ááá®áá á®áááááááá¡ ááá®ááááá}
+_textKeywordshort_ [l=ka] {áááááªáááááá¡ ááá®áá  á¡áááááá«á á¡áá¢á§ááá¡ ááá®ááááá}
+_textVolumeshort_ [l=ka] {áááááªáááááá¡ ááá®áá  á¢áááááá¡ ááá®ááááá}
+_textCountriesshort_ [l=ka] {áááááªáááááá¡ á¥ááá§ááááá¡ ááá®ááááá ááá®áá}
+_textdefaultshorttext_ [l=ka] {áááá£á¡ááá áá ááá áááá¡áá€ááááªáá}
+
+_textSearchlong_ [l=ka] {<p>ášáááá«áááá <i>á«áááá áªááááá£áá á¡áá¢á§ááááá</i>. áááá¢áá¥á¡á¢áááá á¡áá¢á§ááá¡ ááá«áááá âá«ááááá¡âáááá ááá¡ ááááá§áááááá. ááá á©ááááá ááá ááá áááá ááá. ášáááá«áááá á¡á®áá áááá ááááááá ááááá®ááááá áá áááá ááá  <i>á«ááááá¡</i> áŠáááááá¡ ááááá§áááááá. 
+ }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=ka] {<p>ášáááá«áááá<i>áááááªáááááá¡ ááá®áá á¡áááá£á áá</i>. <i>á¡áááá£á ááá</i> áŠáááááá ááá­áá á áááááá¢ááá¡ á¬ááááááá¡ á¡áááá£á áááá¡ á¡ááá¡ áááááááá£áá¡ ááááááá¡ ááá®ááááá }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=ka] {áááááªáááááá¡ ááá®áá ááá¢áá áááá¡ ááá®ááááá. <i>ááá¢áá ááá</i> áŠáááááá ááá­áá á áááááá¢ááá¡ á¬ááááááá¡ á¡ááá¡ áááááááá£áá¡ ááá¢áá áá áááá áááá¡ ááá®ááááá
+}
+
+_textSubjectlong_ [l=ka] {<i>áááááªáááááá¡ ááá®áá á¡áááááá ááá á á£áá áááá</i>. <i>á¡áááááá ááá á á£áá ááááá</i> áŠáááááá ááá­áá á áááááá¢ááá¡ áá á¡áááááá ááá á á£áá áááááá¡ á¡ááá¡, á áááááááááª á¬áááááá áááááááá£ááá ááá ááááá.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=ka] {<i>áááááªáááááá¡ ááá®áá ááá ááŠáááá¡ ááá®ááááá</i> <i>ááá ááŠááá</i> áŠáááááá ááá­áá á áááááá¢ááá¡ á¥á áááááááá£á áá áááááááá£á áááááªáááááá¡ á¡ááá¡ }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=ka] {<i>á€ááááá¡ á¡áá®ááá </i> áŠááááá. áááááá¢ááá¡ áááááááá£á á¡ááá¡ á€ááááá¡ áááááááá á¡áá®áááááá¡ ááá®ááááá.  }
+
+_textLanguagelong_ [l=ka] {<i>ááá</i> áŠááááá. áááááá¢ááá¡ áááááªáááááá¡ á¡ááá¡ áááááááá£áá¡ áááááá¡ ááá®ááááá.  }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=ka] {<i>áá áááááááªáááá </i> áŠááááá. (áááááá¢ááá¡  áá áááááááªááááá¡ á¡ááá¡)}
+
+_textHowtolong_ [l=ka] {<i> á¡áášá£ááááááá</i> áŠááááá.  áááááá á¡áášá£áááááááá¡ á¡áá}
+
+_textTopiclong_ [l=ka] {<i>áááá</i> áŠááááá. áááááá¢ááá¡ ááááááá¡ á¡ááá¡
+ }
+
+_textTolong_ [l=ka] {<i>ááá¡</i> áŠááááá. áááááá¢ááá¡ ááá¡áááá ááááá¡ á¡ááá¡.  }
+
+_textFromlong_ [l=ka] {<i>. ááá¡ááá áŠááááá </i> áŠááááá. áááááá¢ááá¡ ááááááááááá¡ ááá®ááááá.  }
+
+_textSerieslong_ [l=ka] {<i>áááááªáááááá¡ ááá®áá á¡áá ááá¡ ááá®ááááá</i>.  <i>á¡áá ááá¡ </i> áŠáááááá ááá­áá á ááááá¢ááá¡ áá á¡áá áá£áá áááááªáááááá¡ á¡ááá¡, á áááááááª ááááááá ášáá¡á£ááá  ááááá¥áªááášá. }
+
+_textBrowselong_ [l=ka] {<i>ááááááááá ááá </i> áŠááááá.  }
+
+_textPeoplelong_ [l=ka] {<i>áááááªáááááá¡ ááá®áá ááá á¡ááááááá¡ ááá®ááááá</i>. <i>ááá á¡áááááá</i> áŠáááááá ááá­áá á áááááá¢ááá¡ ááá á¡ááááááá¡ á¡ááá¡ áááááá£á áá áááááááá£áá¡ áááá áááá¡ ááá®ááááá.  }
+
+_textAcronymlong_ [l=ka] {<i>áááááªáááááá¡ ááá®áá áááášá ááá áááááááá¡ áá á¡áááááá¡ ááá®ááááá</i> áŠááááá.  áá£ áááá­áá á áŠááááá¡ <i>ááá ááááááá</i> ááááŠááá ááá áááááááá¡ á¡ááá¡ áá á¢áá¥á¡á¢ášá áááá áááááááááá¡ áááááááá¡.  }
+
+_textPhraselong_ [l=ka] {<i>á€á ááááá </i> áŠááááá. áááááá§ááááá á€á áááááá¡ ááááááááá áááá¡áááá¡.  }
+
+_textArtistlong_ [l=ka] {<i>á®ááááááá </i> áŠááááá. áááááá¢ááá¡ ááááááá¡ ááá®ááááá á®áááááááá á¡ááá¡. }
+
+_textKeywordlong_ [l=ka] {<i>.á¡áááááá«á á¡áá¢á§áá </i> áŠááááá. áááááá¢ááá¡ á¡áááááá«á á¡áá¢á§ááááá¡ á¡ááá¡. }
+
+_textVolumelong_ [l=ka] {<i>á¢ááááá</i> áŠááááá. áááááá¢ááá¡ á¢áááááá¡ á¡ááá¡. }
+
+_textCaptionslong_ [l=ka] {<p>ášáááá«áááá <i>áááááªáááááá¡ á¬áá á¬áá áááá¡ ááá®ááááá ááá®áá</i> <i>á¬áá á¬á áá ááá</i> áŠáááááá ááá­áá áá. áááááá  á¬áá á¬áá ááá á¡áá. }
+
+_textCountrieslong_ [l=ka] {<p>ášáááá«áááá <i>áááááªáááááá¡ á¥ááá§ááááá¡ ááá®ááááá ááá®áá</i> 
+<i>á¥ááá§áááá</i> áŠáááááá ááá­áá áá. áááááá á¥ááá§ááááá¡ á¡áá}
+
+
+_textdefaultlongtext_ [l=ka] {<p>áááá¬áá¥áá <i>"á£áªáááá"</i> áŠááááá¡ á ááá áááááááááá áá
+áááááªááááá (á¡áá áááááááá£ááá "á£áªáááá" ááááá¡ ááá®ááááá).  }
+
+_texthelptopics_ [l=ka] {<h2 align=left>Topics</h2>
+<ul>
+  <li><a href="#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="#searching">áªááááá£áá á¡áá¢á§ááááá¡ ááá«ááááá¡ á¬áá¡ááá</a>
+<ul>
+
+  <li><a href="#query-type">ášááááá®ááá¡ á¢ááá</a>
+  </ul>
+  <li><a href="#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="#col-prefs">ááááá¥áªááá¡ ááá áááá¢á ááá</a>
+  <li><a href="#lang-prefs">áááá¡ ááá áááá¢á ááá</a>
+  <li><a href="#pres-prefs">ááá¢áá á€ááá¡áá¡ ááá áááá¢á ááá</a>
+  <li><a href="#search-prefs">á«ááááá¡ ááá áááá¢á ááá</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=ka] {<li><a href="#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=ka] {á áááá  á¬ááááááá®áá áááá£áááá¢á}
+
+# -- Missing translation: _textreadingdocs_
+
+_texthelpreadingdocs_ [l=ka] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>.áá¥ááá ášáááá«áááá  áá¥ááá  á áááá¡ ááááŠá¬ááá áááááááá£ááá£á  á¬ááááááá áá áááá£áááá¢áááá á ááááá, áááá á¡áááá£á á áá  á€áá¢áá¡á£á ááá ááááá©ááááá áááá ááá¡  ááááá ááá áªá®ááá .
+ááá ááááá¥áªááá¡ ááá áá®áááá¡ á¡áá á©ááá,á áááá¡ááª ááááá á©ááááá ášáááªáááá áááááááá á áááá ááááá¡ á ááááááááá¡ ááááááá  áá ááá, á¡ááááª áá¥ááá ááá«ááááá á¡áášá£ááááá ááááášááá áá®ááá áááá áá áá ááááá®ááááá á¬áá áá á£ááá. 
+á¡áá á©ááášá áááááááá á áááá§áá€áááááá¡ á¡áááá£á á ááááá§áá€áááá .</p>
+
+<p>á¥áááááá ááááááá¡ááá£ááá áááááááá á áááá§áá€áááááá¡ á¢áá¥á¡á¢á.
+á ááááá¡  ášááááá ááááááá¡ááá£ááá  áŠááááá á áááááááª ááááá¡áá®á£ááá áá¡á ááá, 
+áááá ááááá§áááááá áá¥ááá ááá«ááááá á¡áášá£ááááá  ááááá®ááááá ášááááá áá  á¬ááá áááá§áá€áááááášá.</p>
+
+<p>á¥áááááá ááááááá¡ááá£ááá á¡áááá£á á áá á€áá¢áá¡á£á ááááá.  ááááááááá£ááá á ááááááááá áŠááááá .
+ááá­áá áá <i>á¢áá¥á¡á¢áá¡ ááá€áá ááááááá</i> áááá¡áááá¡ ,á áá ,áááá€áá áááá¡ ááááááá á¢áá¥á¡á¢á áááááááá á áááá§áá€áááááášá áá á¬áááášá. 
+áá ášáááá®ááááášá ,áá£, áááá£áááá¢á áááá áááªá£ááááá¡ áá¥áááá, ááááááá á¢áá¥á¡á¢áá¡ ááá¡áá®á¡ááááá ááá¡ ááá¡á­áá áááá áááá áá á áááá¡ááá ááááááááá¡ ááá®á¡ááá áááá¡ ááá ááá¬ááá¡!
+ áááá­áá áá <i>á¡áá á©áááá¡ ááá€áá ááááááá</i>  , áááá¡áááá¡ á áá ááá®á¡ááá áááááááá á¡áá á©ááá.</p>
+
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Open this bookshelf</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Open/close this book</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>View this section of the text</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Display all text, or not</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Expand table of contents, or not</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Click the arrow to go to the next section ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... or back to the previous section</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=ka] {<h2>á áááá  ááááááá áªááááá£áá á¡áá¢á§áááá</h2>
+<p>
+  á«ááááá¡ áááá ááááá áá¥ááá ááááááááá áááá®ááááá¡ ááá á¢ááá á¡á¢áá¢ááááá¡ ááá®ááááá:<p>
+  
+  <ol><li>áá£á¡á¢áá ááááááááá á ááááá ááá ááá áá€áá¡ ááá«áááá áá¡á£á á
+      <li>áááá¡áááŠáá áá á áá¡á ááá«áááá áá¡á£á á, áááááááá ááá ááá áá€áá¡  áá á ááááááááá á¡áá¢á§ááá¡ 
+      <li>ášááá¢áááá á«ááááá¡áááá¡ á¡áá¡á£á áááá á¡áá¢á§áá 
+      <li>áááá­áá áá <i>á«ááááá¡ ááá¬á§ááá</i> áŠááááá¡
+ </ol>
+
+<p>ášááááá®ááá¡ ášáá¡á á£ááááá¡ ášááááá áááááá ášááááá®ááá¡  ášáá¡áááááá¡á ááªá áááá£áááá¢áá¡ á¡áááá£á ááá.
+ ááááášá ááááááá¡ááá£ááá áŠááááá, á ááááááª ááááááá§áááá ášááááá ááª ášáá¡áááááá¡ áááá£áááá¢áá .
+
+<p>ááá¥á¡ááááá£á á á áááááááá áááá á£áááá£áá áááá£áááá¢áááá¡á 100-áá¡  á¢áááá.  áá¥ááá ášáááá«áááá ášááªááááá 
+áá¡ á áááááááá <i>ááá áááá¢á ááá</i>-áá ááá­áá áá á áááááª ááááááááá£ááá áááá ááá¡ ááááá.<p>
+
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>ášááááá®ááá¡ á¢ááá</h3>
+
+<p>áá á¡ááááá¡ áá á áááá¡á®áááááá£áá á¢áááá¡ ášááááá®áá.
+
+<ul>
+  <li>ášááááá®áá <b>á§áááá</b> á¡áá¢á§ááá¡áááá¡. áá«ááá¡ áááá£áááá¢ááá¡ (áááááá¡ áá á¡áááá£á ááá¡),
+     á áááááááª ášáááªáááá á¢á¥áááá¡ áááá  áááááááá£á á§áááá á¡áá¢á§ááá¡.
+      ášáá¡áááááá¡á áááá£áááá¢ááá ááááááá¡ ááá®ááááá ááááááá¡ ááá áááá.<p>
+
+  <li>ášááááá®áá <b> á áááááááá</b>á¡áá¢á§ááá¡áááá¡. 
+      áááááá¢ááá¡ ááááá á á¢áá áááá¡ áááá£áááá¢ááášá á áááááá¡ááª áá¥ááá áá«ááá.  
+
+      <p><ul>
+        <li>  áááá£áááá¢áá¡ ášááááá á¡áá¡ á«áááá , á ááááááª ááá£áá®ááááááá  á¡ááá¡;
+        <li> áášááááá ááá ááá á ááááááª, á£á€á á áááášáááááááááá áááá á á¡ááá áá ááá ááá;
+        <li> ááááá áááá£áááá¢áááá¡ ášáá¡áááááá¡ááá  á£á€á á ááá á¢áááá áá á«áá áááá£áááá¢áááá¡ááá áááá¡á®ááááááá.  
+      </ul>
+</ul>
+
+<p>ášáááá«áááá áááááá§áááá á ááááá áááá á  á¡áá«áááá á¢áá áááá--ááááááá á¬ááááááááá áá ááááá ááá ááá áá€á. áá ášáááá®ááááášá  áá£,
+ áá¥ááá ášááá¢áááá áá®áááá áá áá á¡áá«áááá á¢áá áááá, ááášáá áááá£áááá¢ááá ááááááááá áá á¢áá ááááá¡  ášáá®áááá áá¡ á¡áá®ášáá áá¡ áááááá¡ ááá®ááááá.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=ka] {á«áááá ááá ááŠáááá¡ ááá®ááááá}
+
+_texthelpdatesearch_ [l=ka] {<h2>_textdatesearch_</h2>
+ááá ááŠáá¡ á«áááá ááá«áááá á¡áášá£áááááá¡  áááá«ááá áá¡ááá áááá£áááá¢ááá , á áááááááª ááááá§áá€áááááá áá¥áááá¡ ášááááá®ááá¡ á áááá áª á¡áá«áááá á¢áá ááááááá¡ ááá®ááááá
+ ááá áááá áááášá ááŠá¬áá ááá áááááááááá¡ áá ááá¡ áááá¡áá«áŠáá á£áá ááá¢áá ááááá¡ ááá®ááááá. áá¥ááá ášáááá«áááá ááá«ááááá áááá£áááá¢ááá ááá áááá£áá á¬ááááá á¬áááá ášá£ááááášá. ášááááášááá, á áá ášááááá®ááášá áá  áá áá¡ áá£áªááááááá á¡áá«áááá á¢áá ááááááá¡ ášáá¢ááá, á ááááá áá¥ááá ášáááá«áááá á«ááááá¡ á©áá¢áá ááá áá®áááá ááá ááŠáá¡ ááá®ááááá.
+ áá¡ááá ááá áá¥áá, áá  áá áá¡ áá£áªááááááá ášááááá®ááášá ááá ááŠáá¡ ášáá¢ááá, áá ášáááá®ááááášá, á£áá áááá, ááá ááŠáá á«áááá áá  á©áá¢áá áááá.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>>á áááá  ááááááá§ááá áá¡ á¡áášá£ááááá:</h3>
+<ul>
+   <li>áááá£áááá¢áááá¡ á«áááá áá®áááá áá áá á¬ááá¡ ááááááááá:<p>
+   <ul>
+       <li>á£áá áááá  ášááá¢áááá  á¡áá«áááá á¢áá áááááá á áááá áª áá¥ááá á©ááá£áááá áá ááááááá. 
+       <li>ášááá¢áááá  á¡áá¡á£á áááá á¬ááá  âá¡áá¬á§áá¡á (áá áá®áááá) ááá ááŠáâ-á¡ á£á¯á áášá.
+       <li>áá ášáááá®ááááášá áá£ áááááá áá£áá ááá ááŠá á©áááá¡ á¬ááá ááŠááªá®áááááá,
+           ááášáá ááá á©ááá âá©áááá¡ á¬ááá ááŠááªá®áááááâ áá á£á¯á áá¡ áááá á«á áá§áá€á áááá£áá ááááá£ááá.
+       <li>áááá¬á§áá á«áááá á áááá áª áá¥ááá áááá¡ á©ááá£áááá áá ááááááá.
+   </ul>
+<p><li>áááá£áááá¢áá¡ á«áááá áªáááááá áá áá¡ ááá ááááá¡ áá á¬ááááá¡ ášá£áááááááá¡ ááá®ááááá:<p>
+   <ul>
+       <li>á£áá áááá ášááá¢áááá á¡áá«áááá á¢áá áááá á áááá áª áá¥ááá á©ááá£áááá áá ááááááá.
+       <li>ááá áááááá ááá ááŠá â á¡á¬á§áá¡á (áá áá®áááá )ááá ááŠáâ á£á¯á áášá.
+       <li>ášááá¢áááá áááá ááá ááŠá âá¡áááááá ááá ááŠáâ á£á¯á áášá.
+       <li>ááá á©ááá ááá ááŠá âá©áááá¡ á¬ááá ááŠá ááªá®áááááâ áááá£áá ááááá£ááá 
+      <li>áááá¬á§áá á«áááá á áááá áª áá¥ááá áááá¡ á©ááá£áááá áá ááááááá.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+}
+
+_textchangeprefs_ [l=ka] {ááá áááá¢á áááá¡ ášááªááá}
+
+_texthelppreferences_ [l=ka] {<h2>_textchangeprefs_</h2> 
+
+<p><i>ááá áááá¢á áááá¡</i> áŠáááááá ááá­áá áá ášáááá«áááá áááá§áááá áá ááá¡á¢áá£ááá¡ ááá¢áá á€ááá¡á , áá¥áááá ášáá®ááá£ááááááá¡áá¡áááá 
+
+
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>áááá¡ ááá áááá¢á ááá</h3>
+
+á§áááá  ááááá¥áªááášá ááá§ááááá£ááá á¡áá¡á¢ááá£á áá áááá¡áááŠáá á£áá ááá, áááá áá  ášáááá«áááá ááááá®ááááá á¡áá¡á£á ááá ááááá.
+ááá áááá á¢áááá¡ áááá ááá¡ ááá®ááá áááá.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>ááá¢áá á€ááá¡áá¡ ááá áááá¢á ááá</h3>
+
+ááááá áá¢á£á ááááá¥áªáááá ášááá«áááá áá§áá¡ áááááááááá£áá ááá¢áá á€ááá¡áá¡ áááá¢á áááá¡ á áááááááá áá á©ááááá  á áááááá ááá§ááááá 
+ááá áááá ááááá¡  ááááá¥áªáá ááá«áááá á¡áášá£áááááá¡  áááášáá áá áá ááá¡á¢áá£ááá¡ áááááááªááá¡ áááááá , á ááááááª ááááááááá£ááá á§ááááá áááá£áááá¢áá¡ ááááá áá ášáá¡áááááá¡á  ááá áááá áá  áááááá áá ááá¡á¢áá£ááá¡ áááá¡áá ááá¡ ááá áášá. 
+áááá¡ááááá¡ á áá ááááá®áá áªááááá áá®ááá á«áááá áá¥ááá ááááá¬ááá áá áá£ááá áá¡ âá£áááâ áŠáááááá¡  ááááá§ááááá. 
+<p>ááá áááá ááááá¡  ááááá¥áªáááá ááá áááá áá«áááá á¡áášá£áááááá¡ áááá®ášáá áá ááá¡á¢áá£ááá¡ ááá€á áá®ááááá,
+ á ááááááª á©ááááá ááášáá  á áááá¡ááª  áá¥ááá áááá­áá á ááá£áá¡, á ááááááª ááááááá¡ ááááá¥áªáá¡á¡ ááá áá, áááášá.
+ ááášáá¡ááááá, áááá ááá ááááá¥áªááá¡ ášáááá®ááááášá áá¥ááá ášáááá«ááá á©áá ááá á«ááááá¡ ášáááááááá¡ áááá áá, á ááááášááª 
+ ááá§áááááá ááá£áááá áá¥áááá áááááááá URL - á , áá£ ááááá¥áªááá¡.
+
+
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>á«ááááá¡ ááá áááá¢á ááá</h3>
+<p>áá á á¬á§áááá áŠááááá ááááá¢á ááááá¡  ášáá¡áááááá¡á á¢áá¥á¡á¢áá¡ á¢ááá¡ . ááá áááá áá§ááááá¡ á áááá¡á¢á áá¡ áááá¢á ááá¡ 
+(áá®áááá áááá, áá®áááá á¥áááá, áááášááááááá áá  áá¥áá¡ ).  áááá á ááááá¢á ááááá¡ á¡áá¢á§ááááá¡ áááááááááá¡
+(áááááááááá¡ ááááá áá ááá) ášááááá®ááá¡ á£á¯á áá¡ ááááááááá¡ ášáá¡áá«ááááááá, áá á¡ááááá¡, áááá¢áá áá¥áááá ášááááá®áá ááááááá ááá ááá áá€ááª ášááá«áááá áá§áá¡. 
+ááá á¡áááááá á¡á¬á áá€áá áááá áááªá£ááááá¡ á¢áá¥á¡á¢áá¡ ááá¡áá«ááááá
+
+
+
+<p>áá¥ááá ášáááá«áááá ááááá®ááááá âáááááááá ááá£áá ášááááá®ááá¡â á ááááášá,á ááááááª  ááá«áááá á¡áášá£áááááá¡ ááááááášáá áá á¢áá áááááá áááá áá¢áá áááá 
+ áá(&) , áá (|)  áá á (!) . áá¡ ááá«áááá á¡áášá£áááááá¡ á£á€á á áá£á¡á¢áá á©ááááá§áááááá ášááááá®áá. ášáááá«áááá á©áá ááá á«ááááá¡ áá á¥ááá,
+ á ááááááª áááááá¢ááá¡ áá¥áááá¡ áááá  ášááááá®áááá¡ . áá ááááá¡,áá¥ááá ášáááá«áááá ááááááá¢á áááá  ášáááááááá¡ áá ááá áááá ááááá¢ááááá
+ áááá£áááá¢áááá¡ á áááááááá. 
+}
+
+_texttanumbrowseoptions_ [l=ka] {ááááá¥áªááášá ááá€áá áááªáá¡á¡ ááá«ááááá¡ _numbrowseoptions_  ááá áá á¡áááá¡áá¡:}
+
+_textsimplehelpheading_ [l=ka] {á áááá  áááá«ááááá ááá€áá áááªáá  -  ááááá¥áªááášá}
+
+_texthelpscope_ [l=ka] {<p> ášááááá®ááá¡ ááá¥ááááááá¡ áá á  á£ááá¢áá¡ ááááá¥áªáááášá á«ááááá¡ á©áá¡áá¢áá ááááá áá¥ááá ášáááá«áááá á¡á®áááá¡á®áá ááááá¥á¡áááá¡ áá á©ááá. ááááááááá ášááá«áááá áá§áá¡ ááá¢áá áááá¡ áá á¡áááá£á áááá¡ áááá¥á¡ááá. áá ášááá«áááá áá§áá¡ ááááááá¡ áá ááá ááá áá€áááá¡ ááááá¥á¡ááá. á¡ááá ááá áá ááá£á®áááááá áá á©áá£áá ááááá¥á¡áá¡á áááá«áááááá áá¡ááá áááá£áááá¢ááá, á áááááááª ášááá¡ááááááá ášááááá®ááá¡. <p>áá£ ááá«áááá£áá áááá£áááá¢á á¬ááááá, ááášáá ááá áááááášáááá ášáá¡áááááá¡ ááááááá. }
Index: /tags/gsdl-2_61-distribution/gsdl/macros/georgian2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/georgian2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/georgian2.dm	(revision 10506)
@@ -0,0 +1,961 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Georgian Language text and icon macros 
+# -- this file contains text that is of less importance
+# -- to translate when creating a new interface language
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=ka] {áááá£áááá¢ááá }
+_lastupdate_ [l=ka] {ááááá¡ ááááá®ááá}
+_ago_ [l=ka] {ááŠáá¡ á¬áá.}
+_colnotbuilt_ [l=ka] {ááááá¥áªáá áá  áá áá¡ ášáááááááá.}
+
+_textpagetitle_ [l=ka] {áá ááá¡á¢áá£ááá¡ áªáá€á á£áá áááááááááá}
+_textadmin_ [l=ka] {ááááááá¡á¢á ááªáá£áá áááá áá}
+_textabgs_ [l=ka] {áá ááá¡á¢áá£ááá¡ ášáá¡áá®áá}
+_textgsdocs_ [l=ka] {áá ááá¡á¢áá£ááá¡ áááá£áááá¢ááªáá}
+
+_textimagegli_ [l=ka] {ááá®ááá áááá áá®ááá ááááá¥áªááá¡ ášáá¥áááášá, ááááá€ááªáá áááášá, á£ááá áá á¡ááá£á ááááá¥áªááá¡ááá áááá áááááááášá áá ááááá¥áªááá¡ á¬áášááášá}
+
+_textimagecollector_ [l=ka] {ááá ááááááááááá áá¡ ááá¢áá á€ááá¡áá á£á€á á ááá á áá§á ášáá¥ááááá áá á£ááá¢áá¡á áá áá¥á¢ááá£áá áááááááá¡áááá¡ ááá¡ áááááá áá á£ááá áá§áá¡ ááááá§ááááá£áá ááááááááááá áá¡ ááá¢áá á€ááá¡á.  }
+
+_textimagetranslator_ [l=ka] {áá ááá¡á¢áá£ááá¡ ááá¢áá á€ááá¡áá¡ áá®ááá áá áááááááááá ááá á¡áááá.
+}
+
+_textimageadmin_ [l=ka] {ááá«áááá áá®ááá  áááá®ááá ááááááá¡ ááááá¢áááá¡ á¡áášá£áááááá¡, áááá¡ á£á§á áá¡ ááááá¥áªáááá¡ á¡áá¡á¢áááášá, áá«áááá áá ááá¡á¢áá£ááá¡ ááá¡á¢ááááªáá¡áááá¡ á¡áá­áá á á¢áá¥áááá£á  ááá€áá áááªááá¡.
+}
+
+_textimagegogreenstone_ [l=ka] {ááááááá®á ááá¡ áá ááá¡á¢áá£ááá¡ áá ááá ááá£á á£áá á£ááááá§áá€ááá áá áá®ááá ááááááááá¡ áªáá€á á£á áááááááááááá,  á¡ááááª áá¡ áá ááá¥á¢á ášááá¥ááá.}
+
+_textimagegodocs_ [l=ka] {áá ááá¡á¢áá£ááá¡ á¡áá®áááá«áŠááááááááá.}
+
+_textpoem_ [l=ka] {<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+
+<p>may peace and calmness surround you,
+<br>may you reside in the warmth of a summer's haze,
+<br>may the ocean of your travels be as smooth as the polished greenstone.
+}
+
+_textgreenstone_ [l=ka] {<p>áá ááá¡á¢áá£áá áá áá¡ ááá®ááá áá á«ááá á€áá¡á á¥áá, á áááááá¡ (áá áá ááá ááá£áá á£áá á£ááááá§áá€áá¡ áá¡áááá¡áá) ááááááááá áá®áá ááááááááášá. áááá áá¡ á¢á ááááªáá£á á¡ááááááááááášá ááá á§áááááá á£á€á á á«ááá áá áŠáá ááá£áá áá á¡áá¡á£á áááá á¡á£áá¡á¢áááªáá áá áá¡. ááá¡ ášáá£á«ááá ááá¡áá ááá ááá áá áááááá ááá  <i>wairua</i>, ááá áá áá¡ á¡á£ááá¡á áá á¡ááªááªá®ááá¡ á«ááá áá ááá¯ááááááá£ááá á¢á ááááªáá£áá á¡áááááááá áá áááááášáááááááá. áááá¢áá ááá ááá®áá á¡áááááááááá ááá áªáá€á á£áá ááááááááááá¡ áá ááá¥á¢áá¡ ááááááá. ááá¡á áá á¬á§áááááááá áá€á á¥áááá¡ ááá¬á§áááááá¡, ááá¡á áááá­ááá áááááá - ááá¢ááá¡ááááá¡, ááá¡á á¡ááá¢áááªá - á¡ááááááªáá¡ áá ááá¡á ááá¡á á ááá á, á ááááááª ááá¡ ášáá£á«ááá ááááŠáá¡ - á¡áááá ááááááááá¡. ááá¡á áááá­á ááá ááá­áá¢á á, á ááááááª ááááá§ááááá£ááá á áááá áª áá ááá¡áá£ááá¡ áªáá€á á£áá ááááááááááá¡ áááá áá áá¡ <i>patu</i> áá á¡ááá á«ááá á®ááááá¢á áá á¬áá áááááááá¡ á©áááá áá ááá¥á¢áá¡ áá á-áá áá á¬ááá áá¡ áá¯áá®á£á  áááá«á¡. á®ááá©áá áá£á áá á«áááášá ááá¡á ááááá§ááááá áá«áááá á«ááááá á¡á¬á áá€, áá£á¡á¢ áá á¡áááááá ášááááá¡. á©ááá ááá¡á£á á¡ ááá€áá¥á áá á áá áá¡ áááá¡ááááá áááá¡ááááááá á©áááá¡ áá ááá ááá£á á£áá á£ááááá§áá€áá¡, á®ááá ááá¡á ááá¡á á ááá á <i>patu</i> ááá£áááááá¡ áááááááá ááá á¢áá¥áááááááááá¡ á¬ááá§ááá á áááá.
+}
+
+_textaboutgreenstone_ [l=ka] {<p>áá ááá¡á¢áá£áá á¬áá áááááááá¡ áá ááá áááááá¡ ááááááá¥á¢á¡ á ááááááª ááááá£ááááááá áªáá€á á£áá ááááááááááá¡ ááááá¥áªááááá¡ ášáá¥áááá¡á áá áááá áªáááááá¡ááááá¡. ááá áá«áááá ááá€áá áááªááá¡ áá ááááááááá¡á áá ááá¢áá ááá¢áá áá CD-ROM-áá ááááá¥ááá§ááááá¡ áá®áá áááá¡. áá ááá¡á¢áá£áá  ášáá¥áááááá   
+<b>New Zealand Digital Library Project</b> at the <b>University of
+Waikato</b> áááá , áá ááá¡á áááááááá ááá áá áááá áªááááá á®áááá áá  áá áááááááªááá¡ááá áááááášá ááááááá: 
+<b>UNESCO</b> áá <b>Human Info NGO</b>.  ááá áá áá¡ áŠáá áá ááá ááá£áá á£áá á£ááááá§áá€á áá á®ááááá¡áá¬áááááá ášááááá ááá¡áááá ááá:  <a href="http://greenstone.org">http://greenstone.org</a> 
+the GNU General Public License ááá áááááá¡ áááªááá.
+
+<p>áá áá ááá ááá£áá á£áá á£ááááá§áá€áá¡ ááááááá ášáá¡áá«ááááááá ááá¡áªáá¡ áááá®ááá áááááá¡, ááá á«áá á£ááááá á¡áá¢áá¢ááá¡, áááááááááááá¡ áá á¡á®áá á¡áá¯áá á áááá¡áá®á£á áááá¡ ááá¬áá¡ááá£áááááá¡ ášáá¥áááá á¡ááá£ááá á áªáá€á á£áá áááááááááááá. áªáá€á á£áá áááááááááááá á ááááááá£á áá áªááááá áªááááá ááá€áá áááªááá¡ áááá áªáááááá¡á áá áááŠáááá¡ áááááááá¡  UNESCO-á¡ ááá á¢áááá  á¡áááááááááááá¡á áá ááá¬áá¡ááá£áááááášá áááááááááá¡, áááªáááá áááá¡á áá áá£áá¢á£á áá¡ á¡á€áá áááášá ááááá¡ áá¡áá€áááášá áá ááá á«áá, áááááááá áááá á¥ááá§áááášá. á©ááá ááááá áááá¥áá¡, á áá áá¡ áá ááá ááá£áá á£áá á£ááááá§áá€á á®ááá¡ ášáá£á¬á§ááá¡ áªáá€á á£áá ááááááááááááá¡ áá€áá¥á¢á£á  ááááá áááá¡ ááááá¡ áá¡áá€áááášá áá á©ááá§ááááá¡ ááá€áá áááªááá¡ á®ááá®áá¡ á¡ááá¡áá®á£á ášá. 
+
+
+<p>áá áá ááá ááá£áá á£áá á£ááááá§áá€áá¡ ášáá¥ááá áá áááá áªááááá áá áá¡ á¡ááá ááášáá áá¡á áááááášá ááááááá¡ ášááááá á¡áá áá®áá áá¡ ášáá áá¡ 2000 á¬ááá¡ ááááá¡á¢áášá.  
+
+<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>
+áá ááá¡á¢áá£ááá¡ áá ááá ááá£áá á£áá á£ááááá§áá€á áá áá ááá¥á¢áá¡ ááá§áá€áá, á ááááááª áá¥áá áá®áá ááá­áá ááá áá®ááá ááááááááá¡ UNESCO-á¡ ááááá¡ááá¡ áááá£áááááªááááá¡ á¥ááááááá¡ááá¡ áááá , á áááá áª áá®ááá ááááááááá¡ á¬ááááá UNESCO-á¡ áá ááá áááášá. 
+</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>
+ááá€áá áááªááá¡ áááá áªááááá áááááááááá¡, áááªáááá áááá¡á áá áá£áá¢á£á áá¡ á¡á€áá áááášá ááááá¡ áá¡áá€áááášá áá ááá á«áá, áá ááá€áá áááªááá¡ á®ááááá¡áá¬ááááááá áááááááá áááá á¥ááá§áááášá á¬áá áááááááá¡ UNESCO-á¡ áááááá  áááááá¡, á ááááá¡ááª ááá áá®áá áªáááááá¡ á§áááá ááááá¡ áá ááá áááášá áá áááá¢áá, ášáá¡áááááá¡á áá á§ááááá¡ááááá¡ á®ááááá¡áá¬ááááá á¡áááá€áá áááªáá áá á¡ááááá£áááááªáá á¢áá¥ááááááá á¬áá áááááááá¡  áááášáááááááá ááá ááŠá¡ áááªááá£á áááá¢áá¥á¡á¢ášá. 
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/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>
+áá¡ áá ááá¥á¢á áá£ášáááá¡ áááá áá¡ á¡ááááááá¢áááá¡á áá á¡á®áá áá áá¡áááááá ááá áá áááááááªáááášá áá ááááá¡ áá¡áá€áááášá ááááááá ááŠááá ááá áá á¡áááááááááá ááá ááá¢áá áá¡á áááá£áááá¢áááá¡ áááªáá€á áááá¡ááááá¡. ááá á£á€áá¡áá áááááááá áááá á¥ááá§ááááá¡ááááá¡, á®ááá á¡á®ááááá¡ááá ááááá®ááá¡ ááááá®áá á¯áááá¡ áááááŠáá£á áááá¡.  
+</td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ááá á©ááá ááááá¥áªáá" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ [l=ka] {_httpimg_/ka/selcolgr.gif}
+_widthselcolgr_ [l=ka] {537}
+_heightselcolgr_ [l=ka] {17}
+_altselcolgr_ [l=ka] {"Select a collection"}
+
+
+## "á¡ááááááááááá\nááá¢áá á€ááá¡á" ## home_page_button ## cgli ##
+_httpiconcgliof_ [l=ka] {_httpimg_/ka/cgliof.gif}
+_httpiconcglion_ [l=ka] {_httpimg_/ka/cglion.gif}
+_widthcgli_ [l=ka] {100}
+
+# -- Missing translation: ccol
+# -- Missing translation: _httpiconccolof_
+# -- Missing translation: _httpiconccolon_
+# -- Missing translation: _widthccol_
+
+## "á¢á ááá¡ááá¢áá á" ## home_page_button ## ctrans ##
+_httpiconctransof_ [l=ka] {_httpimg_/ka/ctransof.gif}
+_httpiconctranson_ [l=ka] {_httpimg_/ka/ctranson.gif}
+_widthctrans_ [l=ka] {100}
+
+# -- Missing translation: cadmin
+# -- Missing translation: _httpiconcadminof_
+# -- Missing translation: _httpiconcadminon_
+# -- Missing translation: _widthcadmin_
+
+# -- Missing translation: cabgs
+# -- Missing translation: _httpiconcabgsof_
+# -- Missing translation: _httpiconcabgson_
+# -- Missing translation: _widthcabgs_
+
+# -- Missing translation: cgsdoc
+# -- Missing translation: _httpiconcgsdocof_
+# -- Missing translation: _httpiconcgsdocon_
+# -- Missing translation: _widthcgsdoc_
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=ka] {áááááá  áááá ááá ááááááááá£ááá ááá®á ááááá¢ááááá áŠááááá}
+
+_textnocollections_ [l=ka] {<p> áá ááá¡áá£ááá¡ á¡áááá¡á¢ááááªáá ááááá¢á áá  ášáááªáááá ááááá¥áªáááá¡<ul><li>áááááá§áááá<a href="_httppagecollector_">ááááá¥á¢áá á</a> áá®ááá ááááá¥áªááááá¡ ášáá¡ááááááá    </ul>
+}
+
+_text1coll_ [l=ka] {áá ááá¡á¢áá£ááá¡ á¡áááá¡á¢áááááªáá ááááá¢á ášáááªááá¡ 1 ááááá¥áªááá¡}
+
+_textmorecolls_ [l=ka] {áá ááá¡á¢áá£ááá¡ á¡áááá¡á¢áááááªáá ááááá¢á ášáááªááá¡  _1_ ááááá¥áªááá¡}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=ka] {ááá á ááá£áá }
+_textlinknotfound_ [l=ka] {ášááá ááá£áá  áá  áááááá®á }
+
+_textextlinkcontent_ [l=ka] {áá á©áá£áá ááá£áá  áá áá¡ ááá á  ááááá¡áááá á áá á©áá£áá  ááááá¥áªááááá¡áááá¡.
+ áá£ ááááááá áá®áááá ááá£áá , ášáááá«áááá <a href="_nexturl_">ááááá¡ááá</a> á áááá ááá; 
+áá áááááá§áááá áá áá£ááá áá¡   âá£áááâ áŠááááá, áááá¡áááá¡ ,á áá áááá á£áááá á¬ááá áááá£áááá¢áá.}
+
+_textlinknotfoundcontent_ [l=ka] {ášááá ááá£áá áá  áááááá§áááá. ášáá¡áá«ááááááá áá§áá¡ ášááªáááá ááááá¥áªááášá.
+<a href="javascript:history.back()">âá£áááâ</a> áááá á£áááá 
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=ka] {
+
+<h3>ááá£áá "_2_" ááááá¥áªáááá</h3>
+
+<p> áá¥áááá¡ áááá  áá á©áá£áá ááá£áá áá áá¡ ááá á  "_collectionname_" ááááá¥áªááá¡áááá¡
+   (áá¡ ááá£áááááá¡ "_2_" ááááá¥áªáááá).
+    áá£ ááááá áá¡á£á á áá®áááá ááá£áá "_2_" ááááá¥áªáááá, 
+    <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">áá¥ áááá­áá áá </a>áá áááááá§áááá áá¥áááá áá áá£ááá áá¡ 
+<a href=javascript:history.back()> "back" </a> áŠááááá á£ááá ááá¡ááá á£áááááá. }
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=ka] {<h3>ááá£áá "_2_" ááááá¥áªáááá</h3>
+
+<p> ááá£áá, á ááááááª ááá á©ááá, áá áá¡ ááá á "_collectionname_"
+    ááááá¥ááá¡áááá¡  (áá¡ ááá£áááááá¡ "_2_" ááááá¥áªáááá).
+   áá£ áá¡á£á á áá ááá£ááá¡  "_2_" ááááá¥áªááášá ááá®áá 
+    <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">ááááááá</a> áá áááá ááá; 
+    áá áááá á£áááá "á£ááá" á¬ááá áááá£áááá¢áá áá¥áááá áá áá£ááá áá¡ "Back" áŠáááááá¡ ááááá§áááááá
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=ka] {áá ááá¡á¢áá£ááá¡ áªáá€á á£áá áááááááááá}
+
+_textusername_ [l=ka] {áááá®ááá ááááá}
+_textpassword_ [l=ka] {ááá ááá}
+
+_textmustbelongtogroup_ [l=ka] {áá¥ááá á£ááá ááááá£ááááááááá áááá®ááá áááááá "_cgiargug_" á¯áá£á€á¡ áááá ááá¡ á¡áááá®áááá.}
+
+_textmessageinvalid_ [l=ka] {áááá ááá¡ á¡áááá®áááá á£ááá ááááá áá ááá¢áá ááááªáá <br>
+_If_(_cgiargug_,[_textmustbelongtogroup_]<br>)ášááá¢áááá  áááá®ááá ááááá¡ á¡áá®ááá áá ááá ááá.}
+
+_textmessagefailed_ [l=ka] {áááá®ááá ááááá¡ á¡áá®ááá  áá ááá ááá áá áá¡á¬áá áá .}
+
+_textmessagedisabled_ [l=ka] {áá¥áááá áááá®ááá ááááá¡ á¡áá®ááá ááááášá£ááá. ááá£áááášáá ááá áá áááá ááá¡ ááá ááá¡á¢áá á¡.}
+
+_textmessagepermissiondenied_ [l=ka] {áá¥ááá áá  ááááá©áááá áá áááá ááá¡ ááá®ááá¡ á£á€áááá.}
+
+_textmessagestalekey_ [l=ka] {ášááá¢áááá ááá ááá áááá ááá¡ á¡áááá®áááá.}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=ka] {<p>áá ááá¡á¢áá£ááá¡ á¡áááá¡á¢áááááªáá ááááá¢á áá  ášáááªááá¡ áááá£áááá¢ááªááá¡.
+ášááªááááá¡ áááááá ášááá«áááá áá§áá¡:
+ <ol><li> áá ááá¡á¢áá£ááá¡ á¡áááá¡á¢áááááªáá ááááá¢á   ááááá¡á¢áááá ááá£ááá  cd-rom  áááááá¥á¢ ááá¡ááááá áááááááá£á á á áá¡á£á á¡áááá.
+ <li>áá ááá¡á¢áá£ááá¡ á¡áááá¡á¢ááááªáá ááááá¢á ááááá¡á¢áááá ááá£ááá ááá¢áá ááá¢áááá 
+</ol>
+  áááá£áááá¢ááªááá¡ ááááá¢ááá  ášáá¡áá«ááááááá áá <i>docs</i> ááá áá¥á¢áá ááááá, á ááááááª áááááá¡ááá£ááá áá ááá¡á¢áá£ááá¡  cd rom  áá, áá ááá áááá ááááá <a href="http://www.greenstone.org" target="_blank">http://www.greenstone.org</a>
+}
+
+_textuserguide_ [l=ka] {áááá®ááá ááááá¡ á¡áá®áááá«áŠáááááá }
+_textinstallerguide_ [l=ka] {ááá¡á¢ááááªááá¡  á¡áá®áááá«áŠáááááá }
+_textdeveloperguide_ [l=ka] {ááááááá¡á¢á áá¢áá áá¡ á¡áá®áááá«áŠáááááá }
+_textpaperguide_ [l=ka] {âá¥ááŠááááááá ááááá¥áªááááâ á¡áá®áááá«áŠáááááá }
+_textorganizerguide_ [l=ka] {áá áááááááá áá¡ ááááá§ááááá}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "áá ááá¡á¢áá£ááá¡ áááá£áááá¢ááªáá" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=ka] {_httpimg_/ka/gsdocsgr.gif}
+_widthgsdocsgr_ [l=ka] {_pagewidth_}
+_heightgsdocsgr_ [l=ka] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ [l=ka] {á«áá ááááá (á¡áá¡á¢ááá£á áá áááá£ááá¡á®áááá) á¡á¢á á£á¥á¢á£á á}
+_textmore_ [l=ka] {ááá¢á}
+_textcollector_ [l=ka] {ááááá¥á¢áá á}
+_textinfo_ [l=ka] {ááá€áá áááªáá ááááá¥áªááá¡ ášáá¡áá®áá }
+_textsrce_ [l=ka] {áááááªáááááá¡ á¬á§áá á}
+_textconf_ [l=ka] {ááááá¥áªááá¡ áááá€ááá£á ááªáá}
+_textbild_ [l=ka] {ášáá¥ááá}
+_textview_ [l=ka] {ááá®áá}
+_textdel_ [l=ka] {ááááá¥áªááá¡ á¬áášáá}
+_textexpt_ [l=ka] {ááááá¥áªááá¡ áá¥á¡ááá á¢áá ááá}
+
+_textdownloadingfiles_ [l=ka] {á€ááááááá¡ á©áá¢ááá ááá...}
+_textimportingcollection_ [l=ka] {ááááá¥áªááá¡ ááááá á¢áá áááá...}
+_textbuildingcollection_ [l=ka] {ááááá¥áªáá ááááá...}
+_textcreatingcollection_ [l=ka] {ááááá¥áªáá áá¥ááááá...}
+
+_textcollectorblurb_ [l=ka] {<i>áááááá¡ á£á€á á ááá¢á ášáá£á«ááá áááá á á®áááá¡!
+<br>ááááá¥áªááá¡ ášáá¡áá®áá ááá€áá áááªááá¡ ášáááááá áá áááá áªááááá áá¡áá®ááá¡ áá ááá¡á£á®áá¡ááááááááá¡ á ááááááª áá¥ááá áááá¡á£á ááá ááá¬á§áááááá.
+áá á¡ááááá¡ áá£á áááá£áá á¡ááááá®á á¡áááá¢áá á á£á€ááááá¡ ášáá¡áá®áá: áááá£áááá¢áá¡ á®ááááá¡áá¬ááááááá áá  ááášáááá¡, á áá áá¥ááá ášáááá«áááá ááá¡á áááááªááá á¡á®ááá¡áááá¡.
+áá á¡ááááá¡ á¡ááªáááá£á á á¡ááááá®ááááª:  ááááá¥áªáááá á£ááá ášááá¡áááááááááá¡ áá á¡ááááááááááá¡ áááá-á©áááááá¡, á¡ááááª á¬áá áááášáá áá¡ áááá£áááá¢ááá.
+ááá áá áááá¡á áá á¡ááááá¡ ááááá£á á á¡ááááá®ááá: áááá á áá á£áá áááá áá  á£ááá áá¥ááá¡ á®ááááá¡áá¬ááááá á¡á®ááááá¡áááá¡.  
+<br>ááá®á¡ááááá ááá€áá áááªááá¡ á«ááá áá áááááá§áááá áá¡ áááááá á£ááá. 
+</i> }
+
+_textcb1_ [l=ka] {ááááá¥á¢áá á ááááá®ááá áááá ášáá¥áááá áá®áá ááááá¥áªáá, áááááááááá áá á¡ááá£áá ááááá¥áªáá ,áááááá¢áá  áá á¬áášáááá ááááá¥áªáááá. áááá¡ áááá¡áá®áá áªáááááá áá¥ááá ááááá¬ááá áá®áááá«áŠááááááá ááá  áááá ááááá á áááááááª ááááá®áááá á¡áá­áá á ááá€áá áááªááá¡.}
+
+_textcb2_ [l=ka] {ááá á©ááá á áá¡á áááááááá áá¡á£á á}
+_textcnc_ [l=ka] {áá®ááá ááááá¥áªááá¡ ášáá¥ááá }
+_textwec_ [l=ka] {áá á¡ááá£á ááááá¥áªááá¡ááá áá£ášáááá, ááááá¥áªááášá áááááªáááááá¡ áááááá¢ááá áá á¬áášááá.}
+
+_textcb3_ [l=ka] {áááá¡ááá¡ á áá ášáá¥áááá áá áááááááááá ááááá¥áªáááá áªáá€á á£á ááááááááááášá áá¥ááá á£ááá ááááá áá ááá¢áá ááááªáá. áá¡ áááááªááá áá¥áááá¡ áááááá£á¢áá áá  á¡á®áá áááá®ááá ááááááá¡ ášáá¡áááá¡ááá  áá ááá¡ášá ááá€áá áááªááá¡ ášááªáááá¡ááá.
+<br>
+<i><b>ášáááášááá:</b></i>  ááá¢áá ááááªááá¡ áááááááá áá¥ááá 30 á¬á£ááá¡ ááááááááááášá, áá¥ááá ááá¢áááá¢áá£á áá ááááá®áááá .áá ášáááá®ááááášá, áá¥ááá ášáá«áááá  ááááá áá ááá¢áá ááááªáá ááááááá áá ááááá á«áááá áá¡ áá ááááááááá á¡ááááª ášáá©áá ááá. 
+}
+
+_textcb4_ [l=ka] {ášááá¢áááá áá ááá¡á¢áá£ááá¡ áááá®ááá ááááá¡ á¡áá®ááá áá ááá ááá áá áááá­áá áá áŠááááá¡ âášáá¡áááâ.
+}
+
+_textfsc_ [l=ka] {ááá á©ááá ááááá¥áªáá á ááááááá áá£ášááááá¡ááª áááá ááá.
+}
+
+_textwtc_ [l=ka] {áá á©áá£á  ááááá¥áªááá¡ááá áá£ášáááá.}
+_textamd_ [l=ka] {áááááªáááááá¡ ááááá¢ááá áá ááááá¥áªááá¡ ááááááá ášáááááá.}
+_textetc_ [l=ka] {ááááá¥áªááá¡  áááá€ááá£á ááªááá¡ á€ááááá¡  á áááá¥á¢áá ááá áá ááááá¥áªááá¡ ááááááá ášáááááá.}
+_textdtc_ [l=ka] {ááááááá ááááá¥áªááá¡ á¬áášáá}
+_textetcfcd_ [l=ka] {Windows-á¡áááá¡ áááá ááá¡á¢áááá ááááá áááááá¥á¢ ááá¡ááá¡ ášáá¥ááá}
+_textcaec_ [l=ka] {áá á¡ááá£áá ááááá¥áªááá¡ ášááªááá}
+_textnwec_ [l=ka] {ááááá¥áªááá¡ á©áá¡á¬áá ááá ášáá£á«ááááááá.}
+_textcianc_ [l=ka] {áá®ááá ááááá¥áªááá¡ ášáá¥ááá.}
+_texttsosn_ [l=ka] {áªáá€á á£áá ááááááááááá¡ áá®ááá ááááá¥áªááá¡ ášáá¥ááá á¡áá­áá áááá¡ ášááááá ááááá¯ááá¡.}
+_textsin_ [l=ka] {ááá£ááááá á¡áá®ááá (áá áááááášáá ááá£áá ááá€áá áááªáá)}
+_textswts_ [l=ka] {ááá£ááááá áááááªáááá á¬á§áá áá¡ á¬áá ááášááá.}
+_textatco_ [l=ka] {áááá€ááá£á ááªááá¡ ááá áááá¢á áááá¡ ášáá¡á¬áá ááá (áá®áááá ááªáááá áááá®ááá ááááááá¡áááá¡)}
+_textbtc_ [l=ka] {ááááá¥áªááá¡ âáááááâ}
+_textpvyh_ [l=ka] {á¡ááááá§áá ášáá®áááá áá¥áááá¡ á¥áááááááá¡.}
+
+_texttfsiw_ [l=ka] {áááá ááááá¯á  - âááááá¥áªááá¡ áááááâ , ááááááá¡ ááááá¥á¡ááá¡, áá ááá ááá ááááá¡ ááááá¥áªááá¡ ášáá¡áá®áá ááá€áá áááªááá¡.
+ááááááá, ááá®ááá ááá£ááááá ááá€áá áááªáá}
+
+_textadab_ [l=ka] {ááááá©ááááá ááááá ááá ááá®ááá áááá áááá¡ áááá¡áááŠáá áášá áá£ á¡áá ááá§áá€áááá. áá¬áááá áŠáááááá ááá­áá á ááááááá§áááá ááááááááááá áááá¡ ášááááá ááááá¯áá. áááááááá ááááá¯áá ááááá¡áááá¡ ášááááá áŠáááááá¡ á€áá á ášáááªááááá áá áá¥áááá á§áááááá. á¬ááá áááá ááá ááá¡ááá á£áááááá á¡áá­áá áá á§ááááá áŠáááááá ááá­áá á.  }
+
+_textwyar_ [l=ka] {áááá­áá áá âááá€áá áááªááá¡ ášáá¢áááâ áŠááááá¡, áá®ááá áªáá€á á£áá ááááááááááá¡ ášáá¥áááá¡ áá ááªáá¡áá¡ ááá¡áá¬á§áááá}
+
+_textcnmbs_ [l=ka] {áááááááá£áá á£ááá áá§áá¡ ááááá¥áªááá¡ á¡áá®ááá}
+_texteambs_ [l=ka] {áááááááá£áá á£ááá áá§áá¡ áá-á€áá¡á¢áá¡ ááá¡áááá áá }
+_textpsea_ [l=ka] {ááá£ááááá áá á€áá¡á¢áá¡ ááá¡áááá áá ášáááááá á€áá ááá¢áá: username@domain}
+_textdocmbs_ [l=ka] {áááááááá£áá á£ááá áá§áá¡ ááááá¥áªááá¡ ááŠá¬áá á}
+
+_textwcanc_ [l=ka] {áá®ááá ááááá¥áªááá¡ ášáá¥áááá¡áá¡, á¬áááá¡á¬áá  á£ááá ááá£ááááá  ááá€áá áááªáá áááááªáááá á¬á§áá áá¡ ášáá¡áá®áá. 
+}
+
+_texttfc_ [l=ka] {ááááá¥áªááá¡ á¡áááá£á á:}
+
+_texttctiasp_ [l=ka] {ááááá¥áªááá¡ á¡áááá£á á á£ááá áá§áá¡ ááááá á€á ááá, áááááášáá ááá£áá ááááá¥áªááá¡ ášááááá á¡ááá.}
+
+_textcea_ [l=ka] {á¡ááááá¢áá¥á¢á áá-á€áá¡á¢áá¡ ááá¡áááá áá:}
+
+_textteas_ [l=ka] {áá¡ áá-á€áá¡á¢áá¡ ááá¡áááá áá áá áá¡ ááá áááááá á¡ááááá¢áá¥á¢á ááá¡áááá áá :ááŠááášáá£á ááááá¥áªááá¡ááá áááááášáá áááá ááááá¡áááá á ášáááášáááááá¡á áá£ á¬áááááááááááá¡ ááá¡áááááááá. ášáááá¡áá á€áá áá ášáááááá á€áá ááá¢áá:
+<tt>name@domain</tt>.
+}
+
+_textatc_ [l=ka] {ááá€áá áááªáá ááááá¥áªááá¡ ášáá¡áá®áá:}
+
+_texttiasd_ [l=ka] {áá ááá¡á¢á á£á¥áªááášá ááŠá¬áá áááá áá áááªááááá á áááááá ááááá§ááááááááª  áá§á ášáá¢ááááá áááááªááááá ááááá¥áªááášá.
+ áá¡ ááá€áá áááªáá ááááááá¡áááá ááááá¥áªááá¡ ááá ááá áááá ááá.
+}
+
+_textypits_ [l=ka] {áá¥áááá áááá®ááááá¡ áááááªáá áááááááá£ááá áá¡á áá âááá€áá áááªááâ á áááá¡á¢á ášá.
+  ááá¡ááá«ááááááá áááá­áá áá âáááááªáááá á¬á§áá áâ áá¬áááá áŠááááá¡ 
+  }
+
+_srcebadsources_ [l=ka] {<p>áá¥áááá¡ áááá   áááááááá£áá  á¬á§áá áááá ááá£á¬áááááááá.(ááááášáá£ááá 
+_iconcross_ á¯áá áá).
+
+
+<p>áá¡ ášáá¡áá«ááááááá ášáááááá ááááááá¡ áááá.
+ <ul><li> ftp ááááá«á áá url ááá£á¬áááááááá
+<li>ášááááá¬ááá áá¥áááá ášááá áááá ááá¢áá ááá¢ááá ( á£ááá ááá£ááá¥áášáá ááá  ááá¢áá ááá¢ á¡áá ááá¡ áá ááááááá á¡ ISP).
+<li> áá¥ááá á£ááá á¡áªáááá ááá£áááášáá ááá url á ááááááª FIREWALL  áá áá áá¡ áááªá£áá ( áá£ ááá áááá£á áá á¬áá á£ááááá áááá®ááá ááááá¡ á¡áá®ááá¡ áá ááá ááá¡ ááá£áááášáá ááááá ááá¢áá ááá¢á¡ áá á áááá¡á¢á áá.)
+
+<p> url á ááááá¡ááª áá¥ááá á®ááááá áá áá£ááá ášá ášáá¡áá«ááááááá áááááá£á á áááš á©áááá¬áá áááá áááááááá¡.á¡ááá¬á£á®áá áá áááááá£á á áááš á©áááá¬áá á á©ááá áá ááªáá¡ášá á£á®áááááá. áá á áááá¡á¢á ášá á áááááááááá£ááá á¯áá  á©áá¢ááá ááá ááááá§ááááá£áá áááá áááá áá¥áááá¡ áá áá£ááá ášá.
+
+}
+
+_textymbyco_ [l=ka] {<p>ášáá¡áá«ááááááá ášáááááá á¡á¢á á£á¥á¢á£á áá¡ ááááá¥áªááááá¡ ááááá.
+<ul>
+   <li>á«áá ááááá á¡á¢á á£á¥á¢á£á á
+         <dl><dd> áá®ááá ááááá¥áªáá ášááá«áááá ášáááªááááá¡ html áááá£áááá¢ááá¡(.htm. html), á©ááá£áááá ááá á¢áá¥á¡á¢á£á á   áááá£áááá¢ááá (.txt,.text), ms word áááá£áááá¢ááá (.doc),pdf áááá£áááá¢ááá(.pdf)âm-boxâ áá-á€áá¡á¢áá¡ á€áá ááá¢áá áááá¡ áááá£áááá¢ááá(.mbx) </dd></dl>
+    <li> áá á¡áá¡áá£áá ááááá¥áªáá
+           <dd>áá®ááá ááááá¥áªááá¡ á€áááááá á£ááá áá£á¡á¢áá ášááá¡ááááááááááá á¢ááá¡ á áááááááª ááááá§ááááá£áá áá§á áá á¡ááá£áá ááááá¥áªááá¡ ášáá¥áááá¡áá¡.
+   </dd></dl>
+</ul> }
+
+_textbtco_ [l=ka] {ááááá¥áªááá¡  áááá}
+_textand_ [l=ka] {áá®ááá áááááªáááááá¡ ááááá¢ááá}
+_textad_ [l=ka] {áááááªáááááá¡ ááááá¢ááá:}
+
+_texttftysb_ [l=ka] {áá¥áááá¡ áááá  áááá¡áááŠáá á£áá á€áááá áááááá¢ááá ááááá¥áªááá¡. ááá á¬áá£áááá áááášá, á áá  á®áááá®áá áá  ášáááá¥áá á£ááá ááááá¢ááá£áá á€áááá ááááá¥áªááášá: á¬áááááŠáááá ášáááá®ááááášá ááááá¥áªááášá áááááá¡ááá£ááá áá¥áááá áá á áá¡áá . }
+
+_textis_ [l=ka] {á¬á§áá á:}
+
+_textddd1_ [l=ka] {<p> áá£ áá§ááááá file:// áá ftp:// ááášáá ááá£ááááá á©áá¡áá¢ááá áá á€ááá.
+      <p> áá£ áá§ááááá http://  ááášáá á€ááááááá¡ á©áá¢ááá ááá áááááááááá£ááá ááááá áá£ á áááá áá á¬áá ááááááááá áááªááá£áá URL - áá©áááááá¡ áá á áááá áá¡, áá£ ááá áá¥á¢áá ááášá á€ááááááá¡ á¡ááá¡. 
+
+áááá­áá áá More Sources áŠááááá¡, áá£ áá¡á£á á ááá¢á á¬á§áá áá¡ áááááááá}
+
+_textddd2_ [l=ka] {áá£ áááááªáááá áááá®ááá ááááá á®áá á, áá¬áááá áŠáááááá áááá­áá áá,  ášáááá«áááá ášááá¡á¬áá áá áááá€ááá£á ááªáá. ááá¢áá ááá¢áá£áá ááá áááá¢á áá£ ááááá®áááá ááááá¥áªááá¡ ášáá¥ááá¡ á¡áá€áá®á£á áá. ááá®á¡ááááá, áá¥ááá ášáááá«áááá  ááá£áá á£áááá ááá ááááá á¡áá€áá®á£á áá á§áááááá áŠáááááá¡ ááá­áá áá.}
+
+_textconf1_ [l=ka] {ááááá¥áªááá¡ ášáá¥ááá áá á¬áá ááááááá áááá¢á áááááá á¡áááªáááá£á  âáááá€ááá£á ááªááá¡ á€áááášáâ. 
+ áááááªááá áááá®ááá ááááá¡ ášáá£á«ááá áááá€ááá£á ááªááá¡ ášááªááá.   
+ <center><p><b>áá£ áá  á®áá á áááááªáááá áááá®ááá ááááá, ááááááá áááá ááá</b></center>
+<p>áááá€ááá£á ááªááá¡ ášááªáááá¡áááá¡  áááá§áááá áááááªáááááá¡ á áááá¥á¢áá ááááá. áá ášáááá®ááááášá áá£ ááášáááá£áá ášááªáááá áááá­áá áá áŠááááá¡ âáááááááâ áááá¡áááá¡, á áá, áá®áááááá ášáá«ááá áááá€ááá£á ááªááá¡ ááá§ááááá.
+}
+
+_textreset_ [l=ka] {ááááááá}
+
+_textbild1_ [l=ka] {ááááá¥áªáá ááááá: áá ááªáá¡á á¡áá­áá áááá¡ ááá áááá£á áá áá¡. 
+}
+
+_textbild2_ [l=ka] {áááá¡áááá¡ á áá, ášááá©áá áá ášáá¥áááá¡ áá ááªáá¡á áá¥ áááá­áá áá.
+<br>ááááá¥áªáá á áááááááª áá¥ááá áá£ášáááááá á®ááášáá£á®ááááá ááá á©ááá
+}
+
+_textstopbuild_ [l=ka] {ááááá¥áªááá¡ ášáá¥áááá¡ ášáá©áá ááá.}
+
+_textbild3_ [l=ka] {áá£ áá¥ááá ááááá®ááááá áááá ááááá (áá áá  á£áá á§ááá áá ááªáá¡á¡ âáááááá¡ ášáá©áá áááâ áŠáááááá¡ á¡áášá£áááááá) ááááá¥áªáá ááááá á«ááááá¡ ášáá¥áááá¡ áá ááªáá¡á¡ áá áááááá¡á¢áááá ááá¡ ááá¡ .
+}
+
+_textbuildcancelled_ [l=ka] {ááááá¥áªááá¡ ááááá ášáá¬á§áá}
+
+_textbildcancel1_ [l=ka] {ááááá¥áªááá¡ áááááá¡ áá ááªáá¡á ášáá©áá ááá£ááá . 
+áááááá§áááá á§áááááá áŠááááá áááá¡áááá¡, á áá ášááªááááá ááááá¥áªáá áá  ááááááá ááá£ášááá áááááá¡ áá ááªáá¡á.}
+
+_textbsupdate1_ [l=ka] {áááááá¡ á¡á¢áá¢á£á¡áá¡ ááááá®áááá á®áááá 1 á¬ááášá}
+_textbsupdate2_ [l=ka] {áááááá¡ á¡á¢áá¢á£á¡áá¡ ááááá®áááá }
+_textseconds_ [l=ka] {á¬ááááá}
+_textbildsuc_ [l=ka] {ááááá¥áªáá á¬áá ááá¢áááá ášááá¥ááá.}
+
+_textviewbildsummary_ [l=ka] {ááááá¥áªááá¡ áááááá¡ ááááá¢ááááá ááá¢ááááá ášáááá«áááá ááá®áá ááááá¥áªááá¡ 
+<a href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>ášáá¥áááá¡ á áááá£ááášá 
+</a> .
+}
+
+_textfailmsg11_ [l=ka] {ááááá¥áªááá¡ ášáá¥ááá ášáá£á«ááááááá á ááááá áá¡ áá  ášáááªááá¡ áááááªááááá¡. ááá á¬áá£áááá á áá, <i> áááááªáááá á¬á§áá áá¡</i>áááá áášá áááá¡áááŠáá á£áá ááá áá¥á¢áá ááááááá áá á€ááááááááá  áá áá áááááª áá á¡ááááá¡ áá á áááá á€áááášá áá¡ááá á¢áááá¡áá á áááááááª áá ááá¡á¢áá£áá  ááá£ášáááá¡. }
+
+_textfailmsg21_ [l=ka] {ááááá¥áªáá ááá  ášááá¥ááááá(import.pl ášááªáááá).}
+_textblcont_ [l=ka] {ášáá¥áááá¡ áááá ášáááªááá¡ ášááááá ááá€áá áááªááá¡:}
+
+_texttryagain_ [l=ka] {<a href="_httppagecollector_" target=_top>ááááá¢ááá ááá ááááá¥á¢áá á </a> áá 
+á¡áªáááá ááááááá.
+}
+
+_textfailmsg31_ [l=ka] {ááááá¥áªáá ááá  ášááá¥ááááá (buildcol.pl ášááªáááá)}
+_textfailmsg41_ [l=ka] {ááááá¥áªáá á¬áá ááá¢ááá£ááá ášááá¥ááá, ááá áá ááá  ááááá¡á¢áááá áá.}
+_textfailmsg71_ [l=ka] {ááááá¥áªááá¡ ášáá¥áááá¡ ááªááááááá¡ áá áá¡  á¬áá áááášáá ááá£ááááááá ášááªáááá.}
+_textretcoll_ [l=ka] {ááááá¥á¢áá áá áááá á£áááá }
+
+_textdelperm_ [l=ka] {á§áááá áá á ááááááááá  _cgiargbc1dirname_ ááááá¥áªáá ááá  á¬ááášáááá. . áá¡ ášáá¡áá«ááááááá ášáááááá ááááááááá¡ áááá.:
+<ul>
+<li> áá ááá¡á¢áá£áá¡ áá  áááá©ááá  _gsdlhome_/collect/_cgiargbc1dirname_
+ááá áá¥á¢áá ááá¡ á¬áášááá¡ á£á€áááá.<br>
+ášáááá«áááá áááááá¢áááá áá ááá áá¥á¢áá ááá¡ ááá¡á¢á á£á¥áªáá áááá¡áááá¡ ,á áá _cgiargbc1dirname_
+ááááá¥áªáá áááášáá áá áá áááááá£á¢áá áááá .<li>
+<li>áá ááá¡á¢áá£áá¡ áá  ášáá£á«ááá áá ááá áááá¡ ááášáááá _gsdlhome_/bin/script/delcol.pl. ááá á¬áá£áááá áááášá á áá á€áááá ááááá®ááá áá ášáá¡áá«ááááááá ááá¡á ááášáááá.</li>
+</ul>
+}
+
+_textdelinv_ [l=ka] {ááááá¥áªáá _cgiargbc1dirname_ áááªá£ááá áá áá áá¡á¬áá áá. á¬áášáá á£áá á§áá€áááá.
+}
+
+_textdelsuc_ [l=ka] {ááááá¥áªáá _cgiargbc1dirname_ á¬áá ááá¢ááá£ááá á¬ááášááá.}
+
+_textclonefail_ [l=ka] {ááááá¥áªááá  _cgiargclonecol_ ááá  á£áá á£ááááá§á ááá¡ááá£á¢á£á á  ášááááá¡ááá. <br> áá¡ ášáá¡áá«ááááááá ášáááááá ááááááááá¡ áááá:<ul>
+<li> ááááá¥áªáá _cgiargclonecol_ áá  áá á¡ááááá¡
+<li> ááááá¥áªáá _cgiargclonecol_ áá  áááá©ááá collect.cfg áááá€ááá£á ááªááá¡ á€áááá
+<li> áá ááá¡á¢áá£áá¡ áá  áááá©ááá  collect.cfg áááá€ááá£á ááªááá¡ á€ááááá¡ á¬ááááá®ááá¡   á£á€áááá.
+</ul>
+}
+
+_textcolerr_ [l=ka] {ááááá¥á¢áá áá¡ ášááªáááá.}
+
+_texttmpfail_ [l=ka] {ááááá¥á¢áá áá¡ á¬ááááá®ááá¡ áá á©áá¬áá áá¡ ášááªáááá ášá£ááááá£á  á€áááášá áá ááá áá¥á¢áá ááášá. 
+áá¡ ášáá¡áá«ááááááá ášáááááá ááááááááá¡ áááá: 
+<ul>
+<li> áá ááá¡á¢áá£áá¡ áá  áááá©ááá á¬ááááá®ááá¡ /á©áá¬áá áá¡ á£á€áááá gsdlhome_/tmp ááá áá¥á¢áá ááášá.</ul>
+}
+
+_textmkcolfail_ [l=ka] {áá®ááá   ááááá¥áªááá¡áááá¡ ááá áá¥á¢áá ááá¡ ášáá¥áááá¡áá¡  (mkcol.pl failed) ááááá¥á¢áá áá¡ ášááªáááá. áá¡ ášáá¡áá«ááááááá ášáááááá ááááááááá¡ áááá.
+       
+ <ul><li>áá ááá¡á¢áá£áá¡ áá  áááá©ááá ááá áá¥á¢áá ááášá _gsdlhome_/tmp á©áá¬áá áá¡ á£á€áááá 
+  <li> mkcol.pl -á¡ ášááªáááá ášááªáááá.</ul>
+ 
+
+}
+
+_textnocontent_ [l=ka] {ááááá¥á¢áá áá¡ ášááªáááá : áá®ááá áááá¥áªááá¡áááá¡ á¡áá®ááá  áá  áááááááá£áá. ááááá¢ááá ááá ááááá¥á¢áá á.
+}
+
+_textrestart_ [l=ka] {ááááá¥á¢áá áá¡ ááááá¢ááá ááá}
+
+_textreloaderror_ [l=ka] {áá®ááá ááááá¥áªááá¡ ášáá¥áááá¡ áá áá¡ á¬áá áááášáá ášááªáááá.  áááááá§áááá  áá áá£ááá áá¡ âááááá®ááááâ  áá âá£áááâ (ááªáááá áá  áááááá§áááá áá¡ áŠááááááá á áááá¡ááª á¥áááá ááááá¥áªááá¡ áááá¥á¢áá áá¡ ááááá§áááááá). á áááááááááá£ááá ááááá¢ááá ááá ááááá¥á¢áá á .}
+
+_textexptsuc_ [l=ka] {ááááá¥áªáá_cgiargbc1dirname_ á¬áá ááá¢ááá£ááá ááááááááááá  
+_gsdlhome_/tmp/exported__cgiargbc1dirname_ ááá áá¥á¢áá ááášá.
+}
+
+_textexptfail_ [l=ka] {<p> ááááá¥áªááá¡_cgiargbc1dirname_ áááá á¥á¢áá ááášá áá®á¡ááá á¢áá¡ áá áááááá.
+
+<p>áá¡ ášáá¡áá«ááááááá ááá®áá áááá¡ áááá, á áá áá ááá¡á¢áá£áá áá§á ááááá¡á¢áááá ááá£áá
+ â ááááá¥áªááá¡ áá¥á¡ááá á¢áá¡â á€á£áá¥áªááá¡ áá£áªááááááá ááááááááá¢áááá¡ á£áá á£ááááá§áá€áá¡ ááá áášá.<ul>
+
+ <li>áá£ áá ááá¡á¢áá£áá ááááá¡á¢áááá áá ááááááá¢ ááá¡ááááá áá¡ ááááááááá¢ááá áá  ááááá¡á¢áááá áááá á¡áááá áá¥ááá áá  ááááá á©ááá  áááâCustomâ-áá¡  ááá¡á¢ááááªááá¡ áá áá¡. ášáááá«áááá áááááá¢áá áá¡ááá ááá¡á¢ááááªááášá, ááá¡á¢ááááªááá¡  áá ááªááá£á áá¡ ááááááá ááášááááá.
+
+ <li>áá£ áá ááá¡á¢áá£ááá¡ á¡áááá¡á¢ááááªáá ááááá¢á ááááá¡á¢áááá ááá£ááá ááá¢áá ááá¢áááá ,ááááá¬ááá á©áá¢ááá ááá áá áááááá¡á¢áááá áá   á€á£áá¥áªááá¡ ááááá¢á. ááááá ááá
+<a href="http://www.greenstone.org">http://www.greenstone.org</a>
+ áá áá ááá¡áááá áá¡ <a
+ href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+ ááááá¢ááááá ááá¢áááááá¡áááá¡.
+</ul>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ááááá¥á¢áá á" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=ka] {_httpimg_/ka/h\_colect.gif}
+
+## "ááá€áá áááªáá\nááááá¥áªááá¡\nášá¬á¡áá®áá" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=ka] {_httpimg_/ka/gcinfoof.gif}
+_httpicongcinfoon_ [l=ka] {_httpimg_/ka/gcinfoon.gif}
+_httpiconycinfoof_ [l=ka] {_httpimg_/ka/ycinfoof.gif}
+_httpiconycinfoon_ [l=ka] {_httpimg_/ka/ycinfoon.gif}
+_httpiconncinfoof_ [l=ka] {_httpimg_/ka/ncinfoof.gif}
+
+## "áááááªáááááá¡\ná¬á§áá á" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=ka] {_httpimg_/ka/gcsrceof.gif}
+_httpicongcsrceon_ [l=ka] {_httpimg_/ka/gcsrceon.gif}
+_httpiconycsrceof_ [l=ka] {_httpimg_/ka/ycsrceof.gif}
+_httpiconycsrceon_ [l=ka] {_httpimg_/ka/ycsrceon.gif}
+_httpiconncsrceof_ [l=ka] {_httpimg_/ka/ncsrceof.gif}
+
+## "ááááá¥áªááá¡\náááá€ááá£á ááªáá" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=ka] {_httpimg_/ka/gcconfof.gif}
+_httpicongcconfon_ [l=ka] {_httpimg_/ka/gcconfon.gif}
+_httpiconycconfof_ [l=ka] {_httpimg_/ka/ycconfof.gif}
+_httpiconycconfon_ [l=ka] {_httpimg_/ka/ycconfon.gif}
+_httpiconncconfof_ [l=ka] {_httpimg_/ka/ncconfof.gif}
+
+## "ááááá¥áªááá¡\nááááá" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=ka] {_httpimg_/ka/gcbildof.gif}
+_httpicongcbildon_ [l=ka] {_httpimg_/ka/gcbildon.gif}
+_httpiconycbildof_ [l=ka] {_httpimg_/ka/ycbildof.gif}
+_httpiconycbildon_ [l=ka] {_httpimg_/ka/ycbildon.gif}
+_httpiconncbildof_ [l=ka] {_httpimg_/ka/ncbildof.gif}
+
+## "ááááá¥áªááá¡\nááá®áá" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=ka] {_httpimg_/ka/gcviewof.gif}
+_httpicongcviewon_ [l=ka] {_httpimg_/ka/gcviewon.gif}
+_httpiconycviewof_ [l=ka] {_httpimg_/ka/ycviewof.gif}
+_httpiconycviewon_ [l=ka] {_httpimg_/ka/ycviewon.gif}
+_httpiconncviewof_ [l=ka] {_httpimg_/ka/ncviewof.gif}
+
+## "ááááá¥áªááá¡\ná¬áášáá" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=ka] {_httpimg_/ka/gcdelof.gif}
+_httpicongcdelon_ [l=ka] {_httpimg_/ka/gcdelon.gif}
+
+## "ááááá¥áªáá¡á¡\náá¥ááá á¢áá ááá" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=ka] {_httpimg_/ka/gcexptof.gif}
+_httpicongcexpton_ [l=ka] {_httpimg_/ka/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=ka] {132. áá ááá¡á¢áá£áá ášááá¡ááááááá áá ááá ááá£á á£áá á£ááááá§áá€áá¡ á ááááááª ááá¡áá®á£á ááá áªáá€á á£á ááááááááááá¡ ááááá¥áªáááá¡ áá áá®áá ááááá¥áªááááá¡ ášáá¥áááá¡. áá¡ á£áá á£ááááá§áá€á¡ áá®áá ááááá¡ ááá€áá áááªááá¡ áá áááááááªááá¡áááá¡ áá ááááá¥á§ááááááá¡áááá¡ ááá¢áá ááá¢ášá áá ááááááá¢ ááá¡ááá. áá ááá¡á¢áá£áá ááááášáááá£ááá áááááá¢áá¡ á£ááááá á¡áá¢áá¢áá¡ áááá  áá®áá ááááááááá¡ áªáá€á á£áá ááááááááááá¡ áá ááá¥á¢áá¡áááá¡ áá  ááá áªáááááá  áááá ááá ááªááášá UNESCO-á¡á áá HUMAN INFO NGO-ááá áá ááá. áá ááá¡á¢áá£ááá¡ áá ááá ááá£áá á£áá á£ááááá§áá€áá¡ á¬á§áá áá¡  <i> http:// greenstone. org </i>  GNU General Public License ááá áááááá¡ ááááá§áááááá.
+}
+
+_textgreenstone2_ [l=ka] {áá®ááá ááááááááá¡   áªáá€á á£áá ááááááááááá¡ ááá á¡ááá¢á(<a
+href="http://nzdl.org">http://nzdl.org</a>) ášáááªááá¡ á£ááá ááá ááááá¥áªááá¡ áááááááá¡ ,á áááááááª ášáá¥áááááá áá ááá¡á¢áá£ááá¡ áá ááá ááá£áá á£áá á£ááááá§áá€áá¡ ááááá§áááááá áá ááááá¥ááá§áááá£ááá áááá¡áááá¡ á áá  á§á£á áááŠáááá ááááªááá ááá.  ááááá¥ááá§áááá£ááá  á¡á®ááááá¡á®áá á«ááááá¡ áá ááá¢áá ááá¢áá£áá ááááááááá áááá¡ áááááááááá, áá áá¡ááá ášáááªáááá ááááá¥áªáááá¡ áá ááá£á ,á©ááá£á , á€á áááá£á, áááá áá£á, áá¡áááá£á   áááááá  áá¡ááá á áááá áª áááááá¡á£á áá. áá¡ááá áááá©áááá á áááááááá áá£á¡ááááá£á á ááááá¥áªáá.}
+
+_textplatformtitle_ [l=ka] {ááááá€áá áá}
+_textgreenstone3_ [l=ka] {134. áá ááá¡á¢áá£áá áá£ášáááá¡ Windows-ášá áá Unix-ášá. ááá¡ááá áªááááááá ááá á¡áá ášáááªááá¡ ááááá§áááááá¡  áá áááá áááá¡ Windows á§áááá ááá á¡ááá¡áááá¡ áá linux- á¡áá¡áááá¡. áá¡ááá ášáááªááá¡ ááááááá¡ á¬á§áá áá¡ á§áááá á¡áá¡á¢áááá¡áááá¡ á ááááááª ááááááááá£ááá Microsoft C++ áá gcc  ááááá§áááááá¡áááá¡. áá ááá¡á¢áá£áá áá£ášáááá¡ áááá ááááááá£á áá ááá ááá£á á£áá á£ááááá§áá€áá¡ááá, á ááááááª áá¡ááá á®ááááá¡áá¬áááááá : Apache Webserver áá PERL -á¡ááááá¡. áá¡ ááááá§ááááááá ááá¢áá á€ááá¡á áá§ááááá¡ ááá áá áá£ááá á¡; á¢áááá£á áá Netscape Navigator áá Internet Explorer.  }
+
+_textgreenstone4_ [l=ka] {ááááá¥áªááááá¡  áááá£áááá¢áááá¡ á£áá ááááá¡ááá áááá áªááááá£ááá ááááááá¢ ááá¡ááá áá ááá¡á¢áá£ááá¡ áá ááá ááá£áá á£áá á£ááááá§áá€áá¡ ááááá§áááááá. ááááááááá¡áááá¡ <i> Humanity Development Library</i>ášáááªááá¡ 1,230 áá£ááááááªáááá¡. áá¡ áá£ášáááá¡ áááááááá£á  áááá áá¢á£á á£á áááá®áááááááá á ááª á¢áááá£á áá áááááááá áááá á¥ááá§áááášá. ááá€áá áááªááá¡ ááá¡ááŠáááá ášááá«áááá áááááá§áááá á«áááá , ááááááá¡, á¡áááá£á áááá¡ áá áááááááªááááá¡ ááááááááá ááá ,á¡ááá¡ ááááááááá ááá áá á¬ááááááá¡ á§ááááá¡ ášáááá®áááááá ááááááááá ááá.}
+
+_textcustomisationtitle_ [l=ka] {áááááá€ááá£á áá ááá}
+_textgreenstone5_ [l=ka] {áá ááá¡á¢áá£áá áá¡áá ášááá£ášááááá£áá á áá ááá«áááá á¡áášá£áááááá¡ ááá¥á¡ááááá£á áá áááá€áá ááááá áá ááááááá€ááá£á áá áá ááá. áá®ááá áááá£áááá¢ááá áá ááá¢áááá¢áá¡ á€áá ááá¢ááá ááá¬áá áááá  âáá ááá áááá¡ ááááá¢ááááâ (perl ááááá) . áááááááá£á áá  áá®ááá ááá¢áááá¢áá¡ ááááááááá áááá¡ á¡á¢á á£á¥á¢á£á ááá ááá¬áá áááá âáááá¡áá€áááá¢áá áááá¡â á¡áášá£áááááá.  áááá®ááá ááááá¡ ááááá§ááááááá ááá¢áá á€ááá¡á ášááá«áááá ášáááªááááá¡ âáááá áá¡áááá¡â á¡áášá£áááááá ,á ááááááª ááá¬áá áááá áááá áá¡ ááá á¢ááá ááááá. Cobra áá áá¢ááááá ááááá¢ááá¡ áá«áááá¡ á¡áášá£áááááá¡  áááááá§áááá á§áááá á¡áášá£ááááááá á áááááááª áááááášáá ááá£ááá ááááá¥áªááááá¡ áááá£áááá¢ááá (áá.Java-ášá).  á¡ááááááá  ááááá¡ááááá áá ááá ááá C++-ášá áá Perl-ášá ááááá€ááªáá áááá.
+}
+
+_textdocumentationtitle_ [l=ka] {áááá£áááá¢ááªáá}
+_textdocuments_ [l=ka] {á®ááááá¡áá¬áááááá áá ááá¡á¢áá£ááá¡ ááá¬áá ááááááá áááá£áááá¢ááªáá}
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+_textmailinglisttitle_ [l=ka] {ááááááá ááá¡á¢á}
+_textmailinglist_ [l=ka] {áá á¡ááááá¡ á¡áááá¡áá£á¡áá ááááááááá¡ áá£á¡á®á (mail list)  , á ááááááª ááááá£ááááááá  áá ááá¡á¢áá£ááá¡ áªáá€á á£áá ááááááááááá¡ áá ááá ááá£á á£áá á£ááááá§áá€áá¡ ášáá¡áá®áá  áá¡á¯áááááá¡áááá¡. áá ááá¡á¢áá£ááá¡ áá¥á¢áá£á á  áááá®ááá ááááááá á£ááá ááááá®áááá ááááááááá¡ áá£á¡á®áá¡ááá áááá áááá áá ášááááááá ááá¡áá£á¡ááášá.
+ááá¬ááá ááááááá¡áááá¡ ááááááá <a href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.
+
+á¡ááá¡áááá¡ ášáá¢á§ááááááá ááááááááá ášááááá ááá¡áááá ááá <a
+href="mailto:greenstone-users@list.scms.waikato.ac.nz"
+>greenstone-users@list.scms.waikato.ac.nz</a>.
+}
+
+_textbugstitle_ [l=ka] {ášááªáááááá}
+_textreport_ [l=ka] {ááá¡á£á á¡ áááá á¬áá£áááá áááášá , á áá , áá¡ áá ááá ááá£áá á£áá á£ááááá§áá€á áá¥ááááááá¡ ááááá¡áá§áááááááá. áááááááááááááá ááááá¡áááá á ášááªáááááá áá ááá¡áááá ááá
+<a href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+}
+
+_textgs3title_ [l=ka] {ááášá ááááášá}
+# -- Missing translation: _textgs3_
+
+_textcreditstitle_ [l=ka] {áá ááá¡á¢áá£ááá¡ ášááá¥áááááá á¡áá }
+
+_textwhoswho_ [l=ka] {áá ááá¡á¢áá£ááá¡ áá ááá ááá£áá á£áá á£ááááá§áá€á á¬áá áááááááá¡ áááá á ááááááááá¡ ááááá¥á¢áá£á  ááášá ááá¡. á áá¯áá  ááááááá áá á¡á¢áá€áá áááá áá ááá áááááá á áá á¥áá¢áá¥á¢áá ááá áá ášáááá¥áááááá. ááááá¬áááááá ááááŠáá¡ ááá áááá ááááá áááááá áá¯áá, á¯áá á¯ áá£á®áááááá, á°ááá á©áááá, ááááá ááá£á¡ááááá, ááá¢áá áá ááááá, áááá áááááá áá, ááá á áá£á¢ááááá, á¯áá€ á°áááá¡áá, áááá áááá€áá á¡áááá, áá ááá ááááá-áááááááá, ááááá ááá¢áááá, ááá ááá ááááá¢áá áá, ááá áá°áá á áá€áá ááááá áá, á¢áá á áááá, ááá á áá¯áá á¡áá, á¯áá á¢ááá¡áááá áá á¡á¢áá£áá á¢ áááá¢á¡áá. áá®ááá ááááááááá¡ áªáá€á á£áá ááááááááááá¡ áá ááá¥á¢áá¡ á¡á®áá á¬ááá áááá: ááá á áááá ááá, á¡ááá á¯á áááááááááá, ááá¢ á¯áá£áá¡áá, á¡á¢áá á¯áá£áá¡áá, á¢á á¢ááá ááááááá, ááááá áá£á¢á¡áá, áááááá ááá°áá£áá, ááá á ááá á¡ááááá, áááá áááááá¡áá áá áááá á¡ááááá ááááá¬áááááá ááááŠáá¡ áááááááá á á©áááááá á¡áá¡á¢áááá¡ ášáá¥áááá¡ áá áá¡. á©ááá ááá áááá ááááááááá ááá á á§ááááá¡á ááááª ááááá¬áááááá ááááŠá MG, GDBM, PDFTOHTML, PERL, WGET, WVWARE áá XLHTML ááááá¢áááá¡ áááªááááá áááášá áá áááá áªáááááášá. }
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "áá ááá¡á¢áá£ááá¡ ášáá¡áá®áá" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=ka] {_httpimg_/ka/abgsgr.gif}
+_widthabgsgr_ [l=ka] {_pagewidth_}
+_heightabgsgr_ [l=ka] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=ka] {áááá®ááá áááááá á¡áá }
+_textuser_ [l=ka] {áááá®ááá ááááá
+
+}
+_textas_ [l=ka] {ááááá áášáá¡ á¡á¢áá¢á£á¡á}
+_textgroups_ [l=ka] {á¯áá£á€ááá}
+_textcomment_ [l=ka] {áááááá¢áá á}
+_textadduser_ [l=ka] {áá®ááá áááá®ááá ááááá¡  ááááá¢ááá}
+_textedituser_ [l=ka] {ášáá¡á¬áá ááá}
+_textdeleteuser_ [l=ka] {á¬áášáá}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=ka] {áááá®ááá ááááá¡ ášáá¡áá®áá ááá€áá áááªááá¡ á áááá¥á¢áá ááá}
+_textadduser_ [l=ka] {áá®ááá áááá®ááá ááááá¡ ááááá¢ááá}
+
+_textaboutusername_ [l=ka] {áááá®ááá ááááá¡ á¡áá®áááá¡ á¡ááá á«á á£ááá áá§áá¡ 2 -30 á¡ááááááááá. ááá ášááá«áááá ášáááªááááá¡ á áááá áª ááááááá¡ áá¡ááá áªáá€á áááá¡ áá â.âáá â_â á¡ááááááááá¡.
+}
+
+_textaboutpassword_ [l=ka] {ááá áááá¡ á¡ááá á«á á£ááá áá§áá¡ 3-8 á¡áááááá. ááá ášááá«áááá ášáááªááááá¡ á©ááá£áááá áá ASCII  á¡ááááááááá¡.
+}
+
+_textoldpass_ [l=ka] {áá£ áááªááá£áá áááá áªáá ááááá , áá ášáááá®ááááášá á«áááá ááá ááá áááááá§ááááá.}
+_textenabled_ [l=ka] {ááášáááá£áá}
+_textdisabled_ [l=ka] {ááá£ášáááááá}
+
+_textaboutgroups_ [l=ka] {á¯áá£á€ááá ááááá§áá€áááá áá«ááááááá áá ááá ášááááá áá  áá¡áááá âášá£áááááâ.
+}
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=ka] {áááá®ááá ááááá¡ á¬áášáá}
+_textremwarn_ [l=ka] {ááááááááá áá¡á£á á á¡ááááááá áááá®ááá áááááá¡ á¬áášáá <b>_cgiargumun_</b>?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=ka] {ááá áááá¡ ášááªááá}
+_textoldpw_ [l=ka] {á«áááá ááá ááá}
+_textnewpw_ [l=ka] {áá®ááá ááá áááá¡ }
+_textretype_ [l=ka] {áá®ááá ááá áááá¡  á®áááá®áá ášáá¢ááá}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=ka] {ááá ááá á¬áá ááá¢ááá£ááá ášáááªáááá.}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=ka] {áááá®ááá ááááá¡ á¡áá®ááá áá áá¡á¬áá áá.}
+_textinvalidpassword_ [l=ka] {ááá ááá áá áá¡á¬áá áá.}
+_textemptypassword_ [l=ka] {ááá®ááá ášááá¢áááá áááá®ááá ááááá¡ áááááááá áááá ááá ááá.}
+_textuserexists_ [l=ka] {áááá®ááá ááááá¡ á¡áá®ááá áááááááá£ááá, ááá®ááá , ášááá¢áááá á¡á®áá á¡áá®ááá.}
+
+_textusernameempty_ [l=ka] {ášááá¢áááá áááá®ááá ááááá¡ á¡áá®ááá.}
+_textpasswordempty_ [l=ka] {á£ááá ášááá¢áááá á«áááá ááá ááá.}
+_textnewpass1empty_ [l=ka] {ášááá¢áááá áá®ááá ááá ááá áá ááááááá áá ááá.}
+_textnewpassmismatch_ [l=ka] {áá¥áááá ááá ááá áá áá¡á¬áá áááá áááááá ááá£áá.}
+_textnewinvalidpassword_ [l=ka] {ášáá¢ááááá ááá ááá áá áá¡á¬áá áá.}
+_textfailed_ [l=ka] {áááá®ááá ááááá¡ á¡áá®ááá áá ááá ááá áá áá¡á¬áá áá.}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=ka] {áá áá¡áá¢áá£ááá¡ ááá á¡áá #}
+_textframebrowser_ [l=ka] {áááá¡áááá¡ á áá áá¡ áááá áá ááá®áá, áá¥ááá áá áá£ááá á¡ á£ááá á°á¥ááááá¡ âá€á ááááááá¡â áá®áá ááá­áá á.}
+# -- Missing translation: _textframebrowser_
+_textusermanage_ [l=ka] {áááá®ááá áááááá ááá ááá}
+_textlistusers_ [l=ka] {áááá®ááá áááááá á¡áá}
+_textaddusers_ [l=ka] {áá®ááá áááá®ááá ááááá¡ ááááá¢ááá}
+_textchangepasswd_ [l=ka] {ááá áááá¡ ášááªááá}
+_textinfo_ [l=ka] {á¢áá¥áááá£á á ááá€áá áááªáá}
+_textgeneral_ [l=ka] {áááááá áá ááá€áá áááªáá }
+_textarguments_ [l=ka] {áá áá£áááá¢ááá}
+_textactions_ [l=ka] {áááá ááªáááá }
+_textbrowsers_ [l=ka] {áá áá£ááá ááá}
+_textprotocols_ [l=ka] {áá áá¢ááááááá }
+_textconfigfiles_ [l=ka] {á¡ááááá€ááá£á ááªáá á€áááááá}
+_textlogs_ [l=ka] {áááááá}
+_textusagelog_ [l=ka] {ááááá§áááááá¡ áááá}
+_textinitlog_ [l=ka] {ááááªáááááááªááá¡ áááá }
+_texterrorlog_ [l=ka] {ášááªááááááá¡ áááá}
+_textadminhome_ [l=ka] {ááááááá¡á¢á ááªáá£áá ááá¬áááá¡ áááááá á áááá áá}
+_textreturnhome_ [l=ka] {áááááá á áááá áá}
+_titlewelcome_ [l=ka] {ááááááá¡á¢á ááªáá£áá ááá¬ááá }
+_textmaas_ [l=ka] {á®ááááá¡áá¬áááááá áááá¡áá®á£á áááá¡ áá ááááááá¡á¢á ááªááá¡ ášáááááá á¡áá ááá¡ááá: }
+_textvol_ [l=ka] {âááááááâ ááááááá¡ ááááááááá ááá }
+_textcmuc_ [l=ka] {ááááá¥áªááááá¡ ášáá¥ááá, ááááá®áááá áá áááá¡áá®á£á ááá}
+_textati_ [l=ka] {áá¡ááá á¢áá¥áááá£á á ááá€áá áááªááá¡ ááá®áá, á áááá ááªáá CGI áá áá£áááá¢ááá}
+
+_texttsaa_ [l=ka] {á¡áá ááá¡áááá¡ ááá®áá ášááá«áááá áááááááªááá¡ ááááááá¡ á¡áášá£áááááá, á ááááááª ááááááááá£ááá  áááá ááá¡ ááá áªá®ááá áá®áá áá¡.
+}
+
+_textcolstat_ [l=ka] {ááááá¥áªááá¡ á¡á¢áá¢á£á¡á}
+
+_textcwoa_ [l=ka] {ááááá¥áªáááá áá®áááá áá ášáááá®ááááášá áá¥áááá âáá£ášá ááááááá ááááášáâ, áá£ áááá ášáá¡áááááá¡á á¡ááááá€ááá£á ááªáá á€áááááá build.cfg áá á¡ááááá¡, áááá á¬ááááá®áá ášáá¡áá«ááááááá, áá ášáááªáááá á¡á¬áá  builddate áááá¡ áá ááááááá¡ááá£ááá áá ááá ááááá¥áªááá¡ áááááá  ááá áá¥á¢áá ááášá (áá áá á ášáá¥áááá¡ ááá áá¥á¢áá ááášá). 
+}
+
+_textcafi_ [l=ka] {áááá­áá áá  <i>abbrev.</i> áŠááááá¡,  ááááá¥áªááá¡ ášáá¡áá®áá ááá€áá áááªááá¡ á¡áááá®áááá.}
+_textcctv_ [l=ka] {áááá­áá áá <i>collection</i> ááááá¥áªááá¡ á¡áááá®áááá.}
+_textsubc_ [l=ka] {áªáááááááááá¡ ášáááá®áá}
+_texteom_ [l=ka] {main.cfg-á¡ ááá®á¡áá ášáá£á«ááááááá}
+_textftum_ [l=ka] {main.cfg-á¡  ááááá®áááá ášáá£á«ááááááá}
+_textmus_ [l=ka] {main.cfg á¬áá ááá¢áááá ááááá®ááá}
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=ka] {ááááá¥áªááá¡ _collectionname_ ášáá¥áááá¡ á ááá£áá}
+_textflog_ [l=ka] {ááááá¥áªááá¡ _collectionname_ ášááªááááááá¡ áááá}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=ka] {á áááá  áááá«ááááá ááá€áá áááªáá- ááááá¥áªááášá}
+
+_textwhy_ [l=ka] {<p>áá ááá€áá áááªááá¡ ááááááááá áá¥ááá ááŠááášáááá, á áá ááá®áá á«ááááá ááá¡áááááááá ááááá áá á£á¡ááááááá ááá áááá áá.}
+_textextraforform_ [l=ka] {áá¥ááá áá  áááá­áá ááááá á€áá ááá¡ ášááá¡ááá -- ááááá¡áááá á ááá€áá áááªáá ááááá®ááá áááá.}
+_textprivacybasic_ [l=ka] {<p>áá¡ ášáá¢á§ááááááá  ášáááªááá¡ áá®áááá ááá€áá áááªááá¡ -- áááá ááá¡ ášáá¡áá®áá á ááááá¡ááª áá¥ááá áááááááá ááá  
+áá áá¥áááá¡ áááá  ááááá§ááááá£áá á¢áá¥áááááááá¡ ášáá¡áá®áá, á áááááááª  áá áááá ááá¡  ááá®á£áááá.}
+_textstillsend_ [l=ka] {ááááááá ááááááááá ášáá¢á§ááááááá?}
+
+_texterror_ [l=ka] {ášááªáááá}
+_textyes_ [l=ka] {áá}
+_textno_ [l=ka] {áá á}
+_textclosewindow_ [l=ka] {á€ááá¯á áá¡ ááá®á£á áá}
+_textabout_ [l=ka] {ášáá¡áá®áá
+}
+_textprivacy_ [l=ka] {áááá€áááááªáááá£á ááá}
+_textsend_ [l=ka] {áááááááá}
+_textdontsend_ [l=ka] {ááááááááá¡ ášáá¬á§ááá¢á}
+_textoptionally_ [l=ka] {áá ááá£áªááááááá}
+
+_textunderdev_ [l=ka] {ááá¢áááááá¡ ááááááááá ááá ášáá¡áá«áááááá áá¥áááá á€ááááá£á  ááá á¡ááášá.}
+
+_textviewdetails_ [l=ka] {ášáá¢á§áááááááá¡ ááá¢áááááá¡ ááááááááá ááá}
+_textmoredetails_ [l=ka] {á¡á®áá ááá¢ááááá}
+_texttrackreport_ [l=ka] {ášáá¢á§áááááááá¡ááá áááášáá á}
+_textcharacterise_ [l=ka] {áá ááááááá¡ á¢ááá}
+_textseverity_ [l=ka] {áá ááááááá¡ á¡ááá«ááá}
+ 
+_textbadrender_ [l=ka] {áááá áá á£áªááá£á áá áááááá§á£á ááá}
+_textcontenterror_ [l=ka] {ášáááªááá¡ ášááªááááá¡}
+_textstrangebehaviour_ [l=ka] {á£áªááá£á á ááá¥áªááá}
+_textunexpected_ [l=ka] {ááá£áááááá¡á¬ááááááá ášááªáááá}
+_textfunctionality_ [l=ka] {ááááá§áááááá¡áááá¡ á áá£áá}
+_textother_ [l=ka] {á¡á®áá}
+
+_textcritical_ [l=ka] {áá áá¢ááá£áá}
+_textmajor_ [l=ka] {á¡áá áááá£áá}
+_textmedium_ [l=ka] {á¡áášá£ááá áááášáááááááá¡}
+_textminor_ [l=ka] {á£áááášááááá}
+_texttrivial_ [l=ka] {á¢á áááááá£á á}
+
+_textwhatdoing_ [l=ka] {á áá¡ ááááááááá¡ áªáááááá?}
+_textwhatexpected_ [l=ka] {á áá¡ áááááááá ?}
+_textwhathappened_ [l=ka] {á á ááá®áá á¡áááááááááášá?}
+
+_cannotfindcgierror_ [l=ka] {<h2>Sorry!</h2>Can't find the server programs for the "I'd Like to Complain" button.}
+
+_textusabbanner_ [l=ka] {áá ááá¡á¢áá£ááá¡ ááááá á}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+_textgli_ [l=ka] {á¡ááááááááááá ááá¢áá á€ááá¡á}
+_textglihelp_ [l=ka] {áá ááá¡á¢áá£ááá¡ ááááááááááá áá¡ ááá¢áá á€ááá¡á (GLI) á®ááááá¡áá¬ááááá¡ á®ááá¡ áá ááá¡á¢áá£ááá¡ á€á£áá¥áªááááá¡ ááááááá ááááá§áááááá¡ ááááá¡á ááá á¢ááá ááá¢áá á€ááá¡áá¡ á¬á§áááááá. ááá áá«áááá áááá£áááá¢áááá¡ ášááá áááááá¡, ááááá á¢áá¡, ááááááá¡ ááá¢ááááááªáááááá¡ ááá¬áá áá¡á áá ášááááá áá ááá¡á¢áá£ááá¡ ááááá¥áªááá¡ ášáá¥áááá¡ á¡áášá£áááááá¡. 
+ <p>
+ášááááášááá, á áá GLI á£ááá áá§áá¡ ááášáááá£áá áá ááá¡á¢áá£ááá¡ á«áá áááá áá ááá áááá¡ááá áá ááá áá áá£ááá¡á®áááá¡, á áá ááá á£ááá áá§áá¡ ááá¡á¢áááá ááá£áá áá ááá¡á¢áá£ááá¡ áá¥áááá ááá¡á¢ááááªááá¡ á¥ááááá áá¥á¢áá ááášá. áááá¡ááááá¡ á¡áá­áá áá áá ááá¡á¢áá£ááá¡ á ááááááá ááá¡á¢á ááá£áªááá¡ áááááá¢ááá ááá áá ááá§ááááá áá ááá¡á¢áá£ááá¡ CD-ROM-ááá.
+ 
+ 
+<h4>GLI-áá¡ ááášáááá Windows-áá</h4>
+ 
+áááá¡ááááá¡ á áá á©áá ááá ááááááááááá áá¡ ááá¢áá á€ááá¡á Windows-áá ááá á©ááá <i>Greenstone Digital Library</i> á¡áá¥áªááááá <i>Programs</i>, á ááááááª áááááá¡ááá£ááá i>Start</i> ááááá£ášá áá ášááááá ááá á©ááá <i>Librarian Interface</i>. 
+
+ 
+<h4>GLI-áá¡ ááášáááá Unix-áá</h4>
+ 
+áááá¡ááááá¡ á áá á©áá ááá ááááááááááá áá¡ ááá¢áá á€ááá¡á Unix-áá, ááááááá <i>gli</i> ááá áá¥á¢áá ááášá áá ááá¡á¢áá£ááá¡ áá¥áááá¡ ááá¡á¢ááááªááášá áá ášááááá ááá£ášááá <i>gli.sh</i> á¡áá ááá¢á. 
+ 
+<h4>GLI-áá¡ ááášáááá Mac OS X-áá</h4>
+
+ááááá®áá <i>Applications</i> ášááááá <i>Greenstone</i>
+(áá ášáááá®ááááášá áá£ áá ááá¡á¢áá£áá ááááá¡á¢áááá ááá£áá ááá¥áá á¡áá¡á¢ááá£á áá áááá£ááá¡á®ááá ááááááá), áá ášááááá ááá£ášááá  <i>GLI</i> áá ááá ááá.}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "áá ááá¡á¢áá£ááá¡ á¡ááááááááááá ááá¢áá á€ááá¡á" ## green_bar_left_aligned ## gligr ##
+_httpicongligr_ [l=ka] {_httpimg_/ka/gligr.gif}
+_widthgligr_ [l=ka] {_pagewidth_}
+_heightgligr_ [l=ka] {17}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/german.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/german.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/german.dm	(revision 10506)
@@ -0,0 +1,1325 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# German Language text and icon macros (translated from english.dm
+# 9 March 2000)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textperiodicals_
+# -- Missing translation: _textsource_
+# -- Missing translation: _textdate_
+# -- Missing translation: _textnumpages_
+
+# -- Missing translation: _textsignin_
+
+_textdefaultcontent_ [l=de] {Die angegebene Seite konnte nicht gefunden
+werden. Bitte benutzen sie den "ZurÃŒck" Knopf ihres Browsers oder
+den obigen "Home" Knopf um zur Hauptseite der elektronischen
+Bibliothek zurÃŒckzukehren.}
+
+_textdefaulttitle_ [l=de] {GSDL Fehler}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=de] {Diese Sammlung enthÃ€lt _about:numdocs_
+Dokumente.  Sie wurde vor _about:builddate_ Tagen erstellt.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+# -- Missing translation: _collectorextra_
+
+_textimagecollection_ [l=de] {}
+_textimageabout_ [l=de] {Info}
+_textimagehome_ [l=de] {Hauptseite}
+_textimagehelp_ [l=de] {Hilfe}
+_textimagepref_ [l=de] {Voreinstellungen}
+_textimagegreenstone_ [l=de] {Greenstone Digital Library Software}
+# -- Missing translation: _textimageusab_
+
+_textimagesearch_ [l=de] {Suche nach einem bestimmten Begriff}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=de] {Alphabetische Liste der Titel}
+_textimageCreator_ [l=de] {Alphabetische Liste der Autoren}
+_textimageSubject_ [l=de] {Sortiert nach Sparte}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=de] {Sortiert nach Datum}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+# -- Missing translation: _textimageSource_
+# -- Missing translation: _textimageLanguage_
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=de] {Sortiert nach Organisation}
+# -- Missing translation: _textimageKeyword_
+_textimageHowto_ [l=de] {"Wie geht das?"-Kategorien}
+_textimageList_ [l=de] {Liste der Dokumente}
+_textimageSeries_ [l=de] {Sortiert nach Ausgaben}
+# -- Missing translation: _textimageTo_
+# -- Missing translation: _textimageFrom_
+_textimageTopic_ [l=de] {StÃ¶bern in Ausgaben zu speziellen Themen}
+_textimageBrowse_ [l=de] {StÃ¶bern}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=de] {Alphabetische Liste der Personen}
+# -- Missing translation: _textimageAcronym_
+# -- Missing translation: _textimagePhrase_
+# -- Missing translation: _textimageArtist_
+# -- Missing translation: _textimageVolume_
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=de] {Suche}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=de] {Titel A-Z}
+_texticontabCreatorgreen_ [l=de] {Autoren A-Z}
+_texticontabSubjectgreen_ [l=de] {Sparten}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=de] {Daten}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+# -- Missing translation: _texticontabSourcegreen_
+# -- Missing translation: _texticontabLanguagegreen_
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=de] {Organisation}
+# -- Missing translation: _texticontabKeywordgreen_
+_texticontabhowgreen_ [l=de] {Wie geht das?}
+_texticontabseriesgreen_ [l=de] {Serien}
+_texticontablistgreen_ [l=de] {Auflistung}
+# -- Missing translation: _texticontabtogreen_
+# -- Missing translation: _texticontabfromgreen_
+_texticontabtopicgreen_ [l=de] {Themen}
+_texticontabbrwsegreen_ [l=de] {StÃ¶bern}
+# -- Missing translation: _texticontabCollagegreen_
+# -- Missing translation: _texticontabbrowsgreen_
+_texticontabPeoplegreen_ [l=de] {Personen A-Z}
+# -- Missing translation: _texticontabAcronymgreen_
+# -- Missing translation: _texticontabPhrasegreen_
+# -- Missing translation: _texticontabArtistgreen_
+# -- Missing translation: _texticontabVolumegreen_
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=de] {Sichten des Dokuments}
+_texticonclosedbook_ [l=de] {Ã¶ffnen dieses Dokuments und Sichten des Inhalts}
+_texticonnext_ [l=de] {zur nÃ€chsten Sektion}
+_texticonprev_ [l=de] {zur vorhergehenden Sektion}
+
+# -- Missing translation: _texticonworld_
+
+# -- Missing translation: _texticonmidi_
+# -- Missing translation: _texticonmsword_
+# -- Missing translation: _texticonmp3_
+# -- Missing translation: _texticonpdf_
+# -- Missing translation: _texticonps_
+# -- Missing translation: _texticonppt_
+# -- Missing translation: _texticonrtf_
+# -- Missing translation: _texticonxls_
+
+_page_ [l=de] {Seite }
+_pages_ [l=de] {Seiten}
+_of_ [l=de] {of }
+_vol_ [l=de] {Volume}
+_num_ [l=de] {Number}
+
+_textmonth00_ [l=de] {}
+_textmonth01_ [l=de] {Januar}
+_textmonth02_ [l=de] {Februar}
+_textmonth03_ [l=de] {MÃ€rz}
+_textmonth04_ [l=de] {April}
+_textmonth05_ [l=de] {Mai}
+_textmonth06_ [l=de] {Juni}
+_textmonth07_ [l=de] {Juli}
+_textmonth08_ [l=de] {August}
+_textmonth09_ [l=de] {September}
+_textmonth10_ [l=de] {Oktober}
+_textmonth11_ [l=de] {November}
+_textmonth12_ [l=de] {Dezember}
+
+# -- Missing translation: _textdocument_
+# -- Missing translation: _textsection_
+# -- Missing translation: _textparagraph_
+
+_magazines_ [l=de] {Magazine}
+
+# -- Missing translation: _nzdlpagefooter_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "HAUPTSEITE" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=de] {_httpimg_/de/chomeof.gif}
+_httpiconchomeon_ [l=de] {_httpimg_/de/chomeon.gif}
+
+## "HILFE" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=de] {_httpimg_/de/chelpof.gif}
+_httpiconchelpon_ [l=de] {_httpimg_/de/chelpon.gif}
+
+## "VOREINSTELLUNGEN" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=de] {_httpimg_/de/cprefof.gif}
+_httpiconcprefon_ [l=de] {_httpimg_/de/cprefon.gif}
+
+# -- Missing translation: cusab
+# -- Missing translation: _httpiconcusabof_
+# -- Missing translation: _httpiconcusabon_
+
+
+## "suche" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=de] {_httpimg_/de/tsrchgr.gif}
+_httpicontsrchof_ [l=de] {_httpimg_/de/tsrchof.gif}
+_httpicontsrchon_ [l=de] {_httpimg_/de/tsrchon.gif}
+_widthtsrchx_ [l=de] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "titel a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=de] {_httpimg_/de/ttitlgr.gif}
+_httpiconttitleof_ [l=de] {_httpimg_/de/ttitlof.gif}
+_httpiconttitleon_ [l=de] {_httpimg_/de/ttitlon.gif}
+_widthttitlex_ [l=de] {87}
+
+# Not true DC, kept for legacy reasons
+## "autoren a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=de] {_httpimg_/de/tauthgr.gif}
+_httpicontcreatof_ [l=de] {_httpimg_/de/tauthof.gif}
+_httpicontcreaton_ [l=de] {_httpimg_/de/tauthon.gif}
+_widthtcreatx_ [l=de] {102}
+
+## "sparten" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=de] {_httpimg_/de/tsubjgr.gif}
+_httpicontsubjon_ [l=de] {_httpimg_/de/tsubjon.gif}
+_httpicontsubjof_ [l=de] {_httpimg_/de/tsubjof.gif}
+_widthtsubjx_ [l=de] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "daten" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=de] {_httpimg_/de/tdategr.gif}
+_httpicontdateof_ [l=de] {_httpimg_/de/tdateof.gif}
+_httpicontdateon_ [l=de] {_httpimg_/de/tdateon.gif}
+_widthtdatex_ [l=de] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: tsrc
+# -- Missing translation: _httpicontsrcgr_
+# -- Missing translation: _httpicontsrcof_
+# -- Missing translation: _httpicontsrcon_
+# -- Missing translation: _widthtsrcx_
+
+# -- Missing translation: tlang
+# -- Missing translation: _httpicontlanggr_
+# -- Missing translation: _httpicontlangon_
+# -- Missing translation: _httpicontlangof_
+# -- Missing translation: _widthtlangx_
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "serien" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=de] {_httpimg_/de/tsergr.gif}
+_httpicontserof_ [l=de] {_httpimg_/de/tserof.gif}
+_httpicontseron_ [l=de] {_httpimg_/de/tseron.gif}
+_widthtserx_ [l=de] {87}
+
+# -- Missing translation: tto
+# -- Missing translation: _httpiconttogr_
+# -- Missing translation: _httpiconttoon_
+# -- Missing translation: _httpiconttoof_
+# -- Missing translation: _widthttox_
+
+# -- Missing translation: tfrom
+# -- Missing translation: _httpicontfromgr_
+# -- Missing translation: _httpicontfromon_
+# -- Missing translation: _httpicontfromof_
+# -- Missing translation: _widthtfromx_
+
+## "organisation" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=de] {_httpimg_/de/torggr.gif}
+_httpicontorgon_ [l=de] {_httpimg_/de/torgon.gif}
+_httpicontorgof_ [l=de] {_httpimg_/de/torgof.gif}
+_widthtorgx_ [l=de] {105}
+
+## "wie geht das?" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=de] {_httpimg_/de/thowgr.gif}
+_httpiconthowon_ [l=de] {_httpimg_/de/thowon.gif}
+_httpiconthowof_ [l=de] {_httpimg_/de/thowof.gif}
+_widththowx_ [l=de] {115}
+
+## "thema" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=de] {_httpimg_/de/ttopicgr.gif}
+_httpiconttopicon_ [l=de] {_httpimg_/de/ttopicon.gif}
+_httpiconttopicof_ [l=de] {_httpimg_/de/ttopicof.gif}
+_widthttopicx_ [l=de] {87}
+
+## "stÃ¶bern" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=de] {_httpimg_/de/tbrwsegr.gif}
+_httpicontbrwseon_ [l=de] {_httpimg_/de/tbrwseon.gif}
+_httpicontbrwseof_ [l=de] {_httpimg_/de/tbrwseof.gif}
+_widthtbrwsex_ [l=de] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "personen" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=de] {_httpimg_/de/tpeopgr.gif}
+_httpicontpeopof_ [l=de] {_httpimg_/de/tpeopof.gif}
+_httpicontpeopon_ [l=de] {_httpimg_/de/tpeopon.gif}
+_widthtpeopx_ [l=de] {87}
+
+# -- Missing translation: tacro
+# -- Missing translation: _httpicontacrogr_
+# -- Missing translation: _httpicontacroof_
+# -- Missing translation: _httpicontacroon_
+# -- Missing translation: _widthtacrox_
+
+# -- Missing translation: tphrse
+# -- Missing translation: _httpicontphrsegr_
+# -- Missing translation: _httpicontphrseof_
+# -- Missing translation: _httpicontphrseon_
+# -- Missing translation: _widthtphrsex_
+
+# -- Missing translation: tartst
+# -- Missing translation: _httpicontartstgr_
+# -- Missing translation: _httpicontartstof_
+# -- Missing translation: _httpicontartston_
+# -- Missing translation: _widthtartstx_
+
+# -- Missing translation: tkw
+# -- Missing translation: _httpicontkwgr_
+# -- Missing translation: _httpicontkwof_
+# -- Missing translation: _httpicontkwon_
+# -- Missing translation: _widthtkwx_
+
+# -- Missing translation: tvol
+# -- Missing translation: _httpicontvolgr_
+# -- Missing translation: _httpicontvolof_
+# -- Missing translation: _httpicontvolon_
+# -- Missing translation: _widthtvolx_
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "hilfe" ## green_title ## h_help ##
+_httpiconhhelp_ [l=de] {_httpimg_/de/h\_help.gif}
+_widthhhelp_ [l=de] {200}
+_heighthhelp_ [l=de] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=de] {ÃŒber diese Sammlung}
+
+_textsubcols1_ [l=de] {<p>Die komplette Sammlung umfaÃt _1_ individuelle
+Kollektionen:
+<blockquote>}
+
+_textsubcols2_ [l=de] {</blockquote>
+Auf der Seite mit den Einstellugen kÃ¶nnen sie prÃŒfen (und
+ Ã€Yndern) welche individuellen Kollektionen sie momentan benutzen.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "info" ## green_title ## h_about ##
+_httpiconhabout_ [l=de] {_httpimg_/de/h\_about.gif}
+_widthhabout_ [l=de] {200}
+_heighthabout_ [l=de] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=de] {Titel A-Z}
+_texticonhcreat_ [l=de] {Autoren A-Z}
+_texticonhsubj_ [l=de] {Sparten}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=de] {Daten}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+# -- Missing translation: _texticonhsrc_
+# -- Missing translation: _texticonhlang_
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+# -- Missing translation: _texticonhto_
+# -- Missing translation: _texticonhfrom_
+_texticonhser_ [l=de] {Serien}
+_texticonhhow_ [l=de] {Wie geht das?}
+_texticonhorg_ [l=de] {Organisationen}
+_texticonhbrwse_ [l=de] {StÃ¶bern}
+# -- Missing translation: _texticonhbrows_
+_texticonhpeople_ [l=de] {Personen A-Z}
+# -- Missing translation: _texticonhacronym_
+# -- Missing translation: _texticonhphrases_
+# -- Missing translation: _texticonhartist_
+# -- Missing translation: _texticonhkw_
+# -- Missing translation: _texticonhvol_
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=de] {Schliessen dieser Sektion der Bibliothek}
+_texticonclosedbookshelf_ [l=de] {Ã¶ffnen dieser Sektion der Bibliothek und Sichten des Inhalts}
+_texticonopenbook_ [l=de] {Schliessen dieses Buches}
+_texticonclosedfolder_ [l=de] {Ã¶ffnen dieses Ordners und Sichten des Inhalts}
+_texticonclosedfolder2_ [l=de] {Ã¶ffnen der individuellen Kollektion: }
+_texticonopenfolder_ [l=de] {Schliessen dieses Ordners}
+_texticonopenfolder2_ [l=de] {Schliessen der individuellen Kollektion: }
+_texticonsmalltext_ [l=de] {Sichten des Textabschnittes}
+_texticonsmalltext2_ [l=de] {Sichten des Texts: }
+_texticonpointer_ [l=de] {Augenblickliche Sektion}
+_texticondetach_ [l=de] {Ã¶ffnen dieser Seite in einem neuen Fenster}
+_texticonhighlight_ [l=de] {Suchbegriffe werden hervorgehoben}
+_texticonnohighlight_ [l=de] {Suchbegriffe werden nicht hervorgehoben}
+_texticoncontracttoc_ [l=de] {Verkleinerte Version des Inhaltsverzeichnisses}
+_texticonexpandtoc_ [l=de] {Expandierte Version des Inhaltsverzeichnisses}
+_texticonexpandtext_ [l=de] {Anzeigen des gesamten Texts}
+_texticoncontracttext_ [l=de] {Anzeigen des Textes nur fÃŒr die augenblicklich ausgewÃ€hlte Sektion}
+_texticonwarning_ [l=de] {<b>Warnung: </b>}
+_texticoncont_ [l=de] {Weitermachen?}
+
+_textltwarning_ [l=de] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Wenn der Text hier expandiert wird, wird eine sehr grosse Menge an Daten dargestellt werden mÃŒssen _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=de] {Gehe zur Seite}
+_textintro_ [l=de] {<i>(EinfÃŒhrender Text)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "titel a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=de] {_httpimg_/de/h\_title.gif}
+_widthhtitle_ [l=de] {200}
+_heighthtitle_ [l=de] {57}
+
+# Not true DC, kept for legacy reasons
+## "autoren a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=de] {_httpimg_/de/h\_auth.gif}
+_widthhcreat_ [l=de] {200}
+# -- Missing translation: _heighthcreat_
+
+## "sparten" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=de] {_httpimg_/de/h\_subj.gif}
+_widthhsubj_ [l=de] {200}
+_heighthsubj_ [l=de] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "daten" ## green_title ## h_date ##
+_httpiconhdate_ [l=de] {_httpimg_/de/h\_date.gif}
+_widthhdate_ [l=de] {200}
+_heighthdate_ [l=de] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_src
+# -- Missing translation: _httpiconhsrc_
+# -- Missing translation: _widthhsrc_
+# -- Missing translation: _heighthsrc_
+
+# -- Missing translation: h_lang
+# -- Missing translation: _httpiconhlang_
+# -- Missing translation: _widthhlang_
+# -- Missing translation: _heighthlang_
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+# -- Missing translation: h_to
+# -- Missing translation: _httpiconhto_
+# -- Missing translation: _widthhto_
+# -- Missing translation: _heighthto_
+
+# -- Missing translation: h_from
+# -- Missing translation: _httpiconhfrom_
+# -- Missing translation: _widthhfrom_
+# -- Missing translation: _heighthfrom_
+
+## "serien" ## green_title ## h_ser ##
+_httpiconhser_ [l=de] {_httpimg_/de/h\_ser.gif}
+_widthhser_ [l=de] {200}
+_heighthser_ [l=de] {57}
+
+## "wie geht das?" ## green_title ## h_how ##
+_httpiconhhow_ [l=de] {_httpimg_/de/h\_how.gif}
+_widthhhow_ [l=de] {200}
+_heighthhow_ [l=de] {57}
+
+## "themen" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=de] {_httpimg_/de/h\_topic.gif}
+_widthhtopic_ [l=de] {200}
+_heighthtopic_ [l=de] {57}
+
+## "organisation" ## green_title ## h_org ##
+_httpiconhorg_ [l=de] {_httpimg_/de/h\_org.gif}
+_widthhorg_ [l=de] {250}
+_heighthorg_ [l=de] {57}
+
+## "stÃ¶bern" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=de] {_httpimg_/de/h\_brwse.gif}
+_widthhbrwse_ [l=de] {200}
+_heighthbrwse_ [l=de] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "personen" ## green_title ## h_people ##
+_httpiconhpeople_ [l=de] {_httpimg_/de/h\_people.gif}
+_widthhpeople_ [l=de] {200}
+_heighthpeople_ [l=de] {57}
+
+# -- Missing translation: h_acro
+# -- Missing translation: _httpiconhacronym_
+# -- Missing translation: _widthhacronym_
+# -- Missing translation: _heighthacronym_
+
+# -- Missing translation: h_phrse
+# -- Missing translation: _httpiconhphrse_
+# -- Missing translation: _widthhphrse_
+# -- Missing translation: _heighthphrse_
+
+# -- Missing translation: h_artist
+# -- Missing translation: _httpiconhartist_
+# -- Missing translation: _widthhartist_
+# -- Missing translation: _heighthartist_
+
+# -- Missing translation: h_kw
+# -- Missing translation: _httpiconhkw_
+# -- Missing translation: _widthhkw_
+# -- Missing translation: _heighthkw_
+
+# -- Missing translation: h_vol
+# -- Missing translation: _httpiconhvol_
+# -- Missing translation: _widthhvol_
+# -- Missing translation: _heighthvol_
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+## "WEITERMACHEN?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=de] {_httpimg_/de/contof.gif}
+_httpiconconton_ [l=de] {_httpimg_/de/conton.gif}
+
+## "EXPANDIEREN\nDES TEXTS" ## document_button ## eallt ##
+_httpiconealltof_ [l=de] {_httpimg_/de/ealltof.gif}
+_httpiconeallton_ [l=de] {_httpimg_/de/eallton.gif}
+
+## "KONTRAKTIONDES\nINHALTS" ## document_button ## econc ##
+_httpiconeconcof_ [l=de] {_httpimg_/de/econcof.gif}
+_httpiconeconcon_ [l=de] {_httpimg_/de/econcon.gif}
+
+## "SEPARATES\nFENSTER" ## document_button ## edtch ##
+_httpiconedtchof_ [l=de] {_httpimg_/de/edtchof.gif}
+_httpiconedtchon_ [l=de] {_httpimg_/de/edtchon.gif}
+
+## "EXPANDIEREN\nDES INHALTS" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=de] {_httpimg_/de/eexpcof.gif}
+_httpiconeexpcon_ [l=de] {_httpimg_/de/eexpcon.gif}
+
+## "KONTRAKTION\nDES TEXTS" ## document_button ## etsec ##
+_httpiconetsecof_ [l=de] {_httpimg_/de/etsecof.gif}
+_httpiconetsecon_ [l=de] {_httpimg_/de/etsecon.gif}
+
+## "HERVORHEBUNG" ## document_button ## ehl ##
+_httpiconehlof_ [l=de] {_httpimg_/de/ehlof.gif}
+_httpiconehlon_ [l=de] {_httpimg_/de/ehlon.gif}
+
+## "KEINE\nHERVORHEBUNG" ## document_button ## enhl ##
+_httpiconenhlof_ [l=de] {_httpimg_/de/enhlof.gif}
+_httpiconenhlon_ [l=de] {_httpimg_/de/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=de] {_If_(_thislast_,Treffer _thisfirst_ - _thislast_ zur Anfrage: _cgiargq_,Keine Treffer fÃŒr die Anfrage: _cgiargq_)}
+_textnoquerytitle_ [l=de] {Suchseite}
+
+_texticonthispage_ [l=de] {Suche}
+_textsome_ [l=de] {einige}
+_textall_ [l=de] {alle}
+_textboolean_ [l=de] {boolsch}
+_textranked_ [l=de] {gestaffelt}
+# -- Missing translation: _textnatural_
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=de] {}
+# -- Missing translation: _texticonsearchhistorybar_
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+# -- Missing translation: _textusequery_
+_textfreqmsg1_ [l=de] {Zahl der WÃ¶rter: }
+_textpostprocess_ [l=de] {_If_(_quotedquery_,<br><i>weiterverarbeitet um _quotedquery_ zu finden</i>
+)}
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=de] {Mehr als }
+_textapprox_ [l=de] {ÃŒber }
+_textnodocs_ [l=de] {Keine Dokumente zur Anfrage passenden Dokumente gefunden.}
+_text1doc_ [l=de] {Eins zur Anfrage passendes Dokument gefunden.}
+_textlotsdocs_ [l=de] {zur Anfrage passenden Dokumente gefunden.}
+_textmatches_ [l=de] {Passende Dokumente }
+_textbeginsearch_ [l=de] {Suche beginnen}
+# -- Missing translation: _textrunquery_
+# -- Missing translation: _textclearform_
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+# -- Missing translation: _textwordphrase_
+# -- Missing translation: _textinfield_
+# -- Missing translation: _textfoldstem_
+
+# -- Missing translation: _textadvquery_
+# -- Missing translation: _textallfields_
+# -- Missing translation: _texttextonly_
+# -- Missing translation: _textand_
+# -- Missing translation: _textor_
+# -- Missing translation: _textandnot_
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=de] {Suche nach _indexselection__If_(_jselection_, aus _jselection_) _If_(_gselection_, at _gselection_ level) _If_(_nselection_, in der _nselection_ Sprache) die _querytypeselection_ der WÃ¶rter enthalten}
+
+_textadvancedsearch_ [l=de] {Suche nach _indexselection_ _If_(_jselection_, aus _jselection_) _If_(_gselection_, at _gselection_ level)_If_(_nselection_, in der _nselection_ Sprache) mit einer _querytypeselection_ Anfrage}
+
+# -- Missing translation: _textformsimplesearch_
+
+# -- Missing translation: _textformadvancedsearch_
+
+
+# -- Missing translation: _textnojsformwarning_
+# -- Missing translation: _textdatesearch_
+# -- Missing translation: _textstartdate_
+# -- Missing translation: _textenddate_
+# -- Missing translation: _textbc_
+# -- Missing translation: _textad_
+# -- Missing translation: _textexplaineras_
+
+_textstemon_ [l=de] {(Wortendungen werden ignoriert)}
+
+_textsearchhistory_ [l=de] {Alte Suchresultate}
+
+#text macros for search history
+_textnohistory_ [l=de] {Alte Suchresultate nicht verfÃŒgbar}
+# -- Missing translation: _texthresult_
+# -- Missing translation: _texthresults_
+# -- Missing translation: _texthallwords_
+# -- Missing translation: _texthsomewords_
+# -- Missing translation: _texthboolean_
+# -- Missing translation: _texthranked_
+# -- Missing translation: _texthcaseon_
+# -- Missing translation: _texthcaseoff_
+# -- Missing translation: _texthstemon_
+# -- Missing translation: _texthstemoff_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "suche" ## green_title ## h_search ##
+_httpiconhsearch_ [l=de] {_httpimg_/de/h\_search.gif}
+_widthhsearch_ [l=de] {200}
+_heighthsearch_ [l=de] {57}
+
+## "resultate" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=de] {_httpimg_/de/qryresb.gif}
+_widthqryresb_ [l=de] {_pagewidth_}
+_heightqryresb_ [l=de] {17}
+
+# -- Missing translation: schhistb
+# -- Missing translation: _httpiconsrchhistb_
+# -- Missing translation: _widthsrchhistb_
+# -- Missing translation: _heightsrchhistb_
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textprefschanged_
+# -- Missing translation: _textsetprefs_
+_textsearchprefs_ [l=de] {Suchvoreinstellungen}
+_textcollectionprefs_ [l=de] {Voreinstellungen zu Kollektionen}
+_textpresentationprefs_ [l=de] {Voreinstellungen zur PrÃ€sentation}
+_textpreferences_ [l=de] {Voreinstellungen}
+# -- Missing translation: _textcasediffs_
+_textignorecase_ [l=de] {ignoriere GroÃ-/Kleinschreibung}
+_textmatchcase_ [l=de] {GroÃ-/Kleinschreibung muÃ passen}
+# -- Missing translation: _textwordends_
+_textstem_ [l=de] {ignoriere Wortendungen}
+_textnostem_ [l=de] {das vollstÃ€ndige Wort muÃ passen}
+_textprefop_ [l=de] {Zeige maximal _maxdocoption_ hits Treffer an, mit _hitsperpageoption_ Treffern per Seite.}
+_textextlink_ [l=de] {Zugang zu externen Seiten: }
+_textintlink_ [l=de] {Quelldokumente aufgefunden in:}
+_textlanguage_ [l=de] {Schnittstellensprache: }
+_textencoding_ [l=de] {Kodierung: }
+_textformat_ [l=de] {Schnittstellenformat: }
+_textall_ [l=de] {alle}
+# -- Missing translation: _textquerymode_
+_textsimplemode_ [l=de] {einfache Anfragen}
+_textadvancedmode_ [l=de] {komplexe Anfragen (ermÃ¶glicht boolsche Suche mit !, &, |, und Klammern)}
+_textlinkinterm_ [l=de] {via einer dazwischenliegenden Seite}
+_textlinkdirect_ [l=de] {gehe direkt dorthin}
+_textdigitlib_ [l=de] {die elektronische Bibliothek}
+_textweb_ [l=de] {das Web}
+_textgraphical_ [l=de] {Graphisch}
+_texttextual_ [l=de] {Textuell}
+_textcollectionoption_ [l=de] {<p>
+Individuelle Sammlungen die eingebunden werden sollen:
+<br>}
+
+# -- Missing translation: _textrelateddocdisplay_
+# -- Missing translation: _textsearchhistory_
+# -- Missing translation: _textnohistory_
+# -- Missing translation: _texthistorydisplay_
+# -- Missing translation: _textnohistorydisplay_
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+# -- Missing translation: _textformsearch_
+# -- Missing translation: _textplainsearch_
+# -- Missing translation: _textqueryboxsize_
+# -- Missing translation: _textregbox_
+# -- Missing translation: _textbigbox_
+# -- Missing translation: _textformtype_
+# -- Missing translation: _textsimple_
+# -- Missing translation: _textadvanced_
+
+# used in "with 4 fields" in the form search box
+# -- Missing translation: _textwith_
+# -- Missing translation: _textfields_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "voreinstellungen" ## green_title ## h_pref ##
+_httpiconhpref_ [l=de] {_httpimg_/de/h\_pref.gif}
+_widthhpref_ [l=de] {200}
+_heighthpref_ [l=de] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+# -- Missing translation: _textsortby_
+# -- Missing translation: _textalsoshowing_
+# -- Missing translation: _textwith_
+# -- Missing translation: _textdocsperpage_
+
+# -- Missing translation: _textfilterby_
+# -- Missing translation: _textall_
+# -- Missing translation: _textany_
+# -- Missing translation: _textwords_
+# -- Missing translation: _textleaveblank_
+
+# -- Missing translation: _browsebuttontext_
+
+# -- Missing translation: _nodata_
+# -- Missing translation: _docs_
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=de] {Help}
+_textSearchshort_ [l=de] {Suche nach bestimmten WÃ¶rtern}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=de] {Zugriff auf Publikationen nach Titel}
+_textCreatorshort_ [l=de] {Zugriff auf Publikationen nach Autor}
+_textSubjectshort_ [l=de] {Zugriff auf Publikationen nach Sparten}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=de] {Zugriff auf Publikationen nach Zeit}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+# -- Missing translation: _textSourceshort_
+# -- Missing translation: _textLanguageshort_
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=de] {Zugriff auf Publikationen nach Serien}
+# -- Missing translation: _textToshort_
+# -- Missing translation: _textFromshort_
+_textBrowseshort_ [l=de] {StÃ¶bern in Publikationen}
+_textOrganizationshort_ [l=de] {Zugriff auf Publikationen nach Organisation}
+_textHowtoshort_ [l=de] {Zugriff auf Publikationen nach "Wie geht das?" Kategorien}
+_textTopicshort_ [l=de] {Zugriff auf Publikationen nach Thema}
+_textPeopleshort_ [l=de] {Zugriff auf Publikationen nach Personen}
+# -- Missing translation: _textAcronymshort_
+# -- Missing translation: _textPhraseshort_
+# -- Missing translation: _textArtistshort_
+# -- Missing translation: _textKeywordshort_
+# -- Missing translation: _textVolumeshort_
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=de] {Klassifikation is nicht definiert}
+
+_textSearchlong_ [l=de] {<p>Sie kÃ¶nnen <i>nach bestimmten Begriffen
+suchen</i>, die im Text der Suchseite erscheinen. Das ist die erste
+Seite, die angezeigt wird, wenn sie anfangen. Sie kann von allen
+anderen Seiten durch Anklicken des <i>Suche</i> Knopfes erreicht
+werden.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=de] {<p>Sie kÃ¶nnen auf <i> Publikationen geordnet
+nach Titel zugreifen</i> indem sie den <i>Titel A-Z</i> Knopf
+anklicken. Dann wird ihnen eine alphabetisch geordnete Liste der
+BÃŒcher angezeigt.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=de] {<p>Sie kÃ¶nnen auf <i> Publikationen geordnet
+nach Autor zugreifen</i> indem sie den <i>Autor</i> Knopf
+anklicken. Dann wird ihnen eine nach Autor geordnete Liste der
+BÃŒcher angezeigt.  }
+
+_textSubjectlong_ [l=de] {<p>Sie kÃ¶nnen auf <i> Publikationen geordnet
+nach Sparte zugreifen</i> indem sie den <i>Sparte</i> Knopf
+anklicken. Dann wird ihnen eine Liste der Sparten angezeigt,
+dargestellt durch BÃŒcherregale.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=de] {<p>Sie kÃ¶nnen auf <i> Publikationen geordnet
+nach Datum zugreifen</i> indem sie den <i>Datum</i> Knopf
+anklicken. Dann wird ihnen eine chronologisch geordnete Liste aller
+Ausgaben angezeigt.  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: _textSourcelong_
+
+# -- Missing translation: _textLanguagelong_
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=de] {<p>Sie kÃ¶nnen auf <i> Publikationen
+geordnet nach Organisation zugreifen</i> indem sie den
+<i>Organisationen</i> Knopf anklicken. Dann wird ihnen eine Liste der
+Organisationen angezeigt.  }
+
+_textHowtolong_ [l=de] {<p>Sie kÃ¶nnen auf <i> Publikationen
+geordnet nach "Wie geht das?" Kategorie zugreifen</i> indem sie den
+<i>Wie geht das?</i> Knopf anklicken. Dann wird ihnen eine Liste der
+"Wie geht das?" Kategorien angezeigt.  }
+
+_textTopiclong_ [l=de] {<p>Sie kÃ¶nnen auf <i> Publikationen geordnet
+nach Thema zugreifen</i> indem sie den <i>Thema</i> Knopf
+anklicken. Dann wird ihnen eine Liste der Themen angezeigt.  }
+
+# -- Missing translation: _textTolong_
+
+# -- Missing translation: _textFromlong_
+
+_textSerieslong_ [l=de] {<p>Sie kÃ¶nnen auf <i> Publikationen geordnet
+nach Serie zugreifen</i> indem sie den <i>Serie</i> Knopf
+anklicken. Dann wird ihnen eine Liste der Serien angezeigt, die sich momentan in der Sammlung befinden.  }
+
+_textBrowselong_ [l=de] {<p>Sie kÃ¶nnen durch <i>Publikationen
+stÃ¶bern</i> indem sie den <i>StÃ¶bern</i> Knopf anklicken.  }
+
+_textPeoplelong_ [l=de] {<p>Sie kÃ¶nnen auf <i> Publikationen geordnet
+nach Personen zugreifen</i> indem sie den <i>Personen A-Z</i> Knopf
+anklicken. Dann wird ihnen eine Liste aller EintrÃ€ge angezeigt,
+die nach Nachnamen geordnet ist.  }
+
+# -- Missing translation: _textAcronymlong_
+
+# -- Missing translation: _textPhraselong_
+
+# -- Missing translation: _textArtistlong_
+
+# -- Missing translation: _textKeywordlong_
+
+# -- Missing translation: _textVolumelong_
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=de] {<p>Klicken sie auf den <i>Unbekannt</i> Knopf
+um durch die Publikationen zu stÃ¶bern. In diesem Fall wird die
+Liste nach einem unbekannten Feld sortiert.  }
+
+_texthelptopics_ [l=de] {<h2 align=left>Themen</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Wie man nach bestimmten WÃ¶rtern suchen kann</a>
+<ul>
+  <li><a href="\#query-terms">Suchbegriffe</a>
+  <li><a href="\#query-type">Typ der Anfrage</a>
+  <li><a href="\#scope-of-queries">Reichweite der Anfragen</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Voreinstellungen zu den Sammlungen</a>
+  <li><a href="\#pres-prefs">Voreinstellungen zur PrÃ€sentation</a>
+  <li><a href="\#search-prefs">Suchvoreinstellungen</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=de] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=de] {Wie Dokumente gelesen werden kÃ¶nnen}
+
+_texthelpreadingdocs_ [l=de] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p> Sie kÃ¶onnen feststellem, dass sie bei einem einzelnen
+Dokument angekommen sind, wenn dessen Titel und Autor links oben auf
+der Seite angezeigt werden. Daneben ist die aktuelle Seitennummer, ein
+KÃ€stchen welches ihnen die Auswahl einer neuen Seite erlaubt und
+vorwÃ€rts und rÃŒckwÃ€ts Pfeile.
+
+<p>Darunter ist der Text des aktuellen Abschnitts. Unten befinden befinden
+sich Pfeile, die sie zum nÃ€chsten Abschnitt oder zum vorherigen
+bringen nachdem sie den aktuellen Abschnitt gelesen haben.
+
+<p>Unter dem Titel und dem Namen des Autors befinden sich drei KnÃ¶pfe.
+DrÃŒcken sie auf <i>ganzes Dokument</i>, um den gesamten Text des
+aktuellen Dokuments anzuzeigen. Ist 
+das Dokument umfangreich, so kann der Ladevorgang einige Zeit in
+Anspruch nehmen und es wird viel Arbeitsspeicher bennÃ¶tigt!
+DrÃŒcken sie auf <i>neues Fenster</i>, um das Dokument in einem neuen
+Browserfenster zu Ã¶ffnen. (Dies is sinnvoll, wenn sie Dokumente
+vergleichen oder zwei auf einmal lesen wollen.) Wenn sie das Dokument
+aufgrund einer Suche erhalten haben sind die Suchbegriffe
+hervorgehoben. DrÃŒcken sie auf <i>nicht hervorheben</i>, um die
+Suchbegriffe normal darzustellen.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_"
+border="0"></td><td>DrÃŒcken sie auf den Pfeil, um zum nÃ€chsten
+Abschnitt zu gelangen ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... oder
+zurÃŒck zum vorigen Abschnitt</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Gesamten Text
+darstellen, oder nicht</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_"
+border="0"></td><td>Diese Seite in einem neuen Fenster Ã¶ffnen</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Suchbegriffe
+hervorheben, oder nicht</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=de] {<h2>Wie sie nach bestimmten Worten suchen kÃ¶nnen</h2>
+<p>
+  Ausgehend von der Suchseite starten sie eine Suchanfrage in den folgenden
+  einfachen Schritten::<p>
+  
+  <ol><li>Spezifizieren sie welche Dokumente sie durchsuchen wollen
+      <li>Sagen sie, ob sie nach allen oder lediglich einigen der
+      Suchbegriffe suchen wollen
+      <li>Geben sie die Suchbegriffe ein
+      <li>DrÃŒcken sie den Knopf <i>Starte Anfrage</i>
+  </ol>
+
+<p> Wenn sie eine Anfrage durchfÃŒhren werden die Titel von zwanzig
+dazu gefundenen Dokumenten angezeigt. Am Ende der Seite befindet sich ein
+Knopf mit dem sie die nÃ€chsten zwanzig Seiten dargestellt
+bekommen. Dort finden sie einen Knopf, der sie zu den nÃ€chsten Zwanzig
+und einen der sie zu den ersten zwanzig bringt, und so fort. Um ein
+beliebiges Dokument zu sehen drÃŒcken sie auf seinen Titel  oder den
+kleinen Knopf daneben. 
+
+<p> GemÃ€ss der Voreinstellungen werden maximal bis zu 100 Dokumente zu
+einer Anfrage zurÃŒckgegeben. Sie kÃ¶nnen diese Anzahl Ã€ndern
+inden sie auf den Knopf <i>Voreinstellungen</i> am Kopf der Seite
+drÃŒcken.<p> 
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Suchbegriffe</h3>
+
+<p> Was immer sie in das Suchfeld eingeben wird als Liste von Worten
+interpretiert, die "Suchbegriffe" genannt werden. Jeder Begriff darf
+ausschliesslich alphabetische Zeichen und Zahlen enthalten. Begriffe werden
+durch Leerzeichen getrennt. Falls Interpunktionszeichen wie Punkte oder Kommata
+auftauchen, dienen diese dazu, genau wie Leerzeichen, Begriffe zu
+trennen. Im weiteren werden sie nicht weiter beachtet. Sie kÃ¶nnen
+nicht nach Worten suchen die Interpunktionszeichen enthalten!
+
+<p>Beispiel: die Anfrage<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>wird genauso interpretiert wie<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Anfragearten</h3>
+
+<p>Es gibt zwei unterschiedliche Arten von Anfragen.
+
+<ul>
+  <li>Anfragen nach <b>allen</b> eingegebenen Suchbegriffen. Anfragen
+  dieser Art suchen nach Dokumenten, die alle eingegebenen Suchbegriffe
+  beinhalten. Dokumente, die der Anfrage genÃŒgen werden in
+  alphabetischer Reihenfolge dargestellt.<p>
+
+  <li>Anfragen nach <b>einigen</b> der eingegebenen Suchbegriffen. Geben
+      sie einfach einige der Begriffe an, die mÃ¶glicherweise in den
+      Dokumenten enthalten sind nach denen sie suchen. Die Dokumente werden
+      in der Reihenfolge dargestellt je nachdem wie stark sie die
+      Suchanfrage erfÃŒllen. Der Grad des ErfÃŒllens der
+      Suchanfrage wird folgendermassen bestimmt.
+      <p><ul>
+        <li> Je mehr Suchbegriffe ein Dokument enthÃ€lt desto besser
+      erfÃŒllt es die Anfrage.
+        <li> Seltene Begriffe sind wichtiger als sehr oft vorkommende.
+        <li> Kurze Dokumente erfÃŒllen Anfragen besser als lange.
+      </ul>
+</ul>
+
+<p> Benutzen sie so viele Suchbegriffe wie sie wollen -- einen ganzen Satz
+oder gar einen ganzen Absatz. Falls sie nur einen einzigen Suchbegriff
+angeben werden die Dokumente nach der HÃ€ufigkeit dessen Auftauchens
+sortiert.<p>
+_texthelpscope_
+}
+
+# -- Missing translation: _textdatesearch_
+
+# -- Missing translation: _texthelpdatesearch_
+
+_textchangeprefs_ [l=de] {Ã€ndern ihrer Voreinstellungen}
+
+_texthelppreferences_ [l=de] {<h2>_textchangeprefs_</h2>
+
+<p>Wenn sie den Knopf <i>Voreinstellungen</i> am Kopf der Seite
+drÃŒcken, kÃ¶nnen sie einige Eigenschaften der
+Benutzerschnittstelle so verÃ€ndern, dass sie ihren Anforderungen
+entspricht. 
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Kollektionsvoreinstellungen</h3>
+
+Einige Kollektionen enthalten mehrere Unterkollektionen welche entwerder
+unabhÃ€ngig oder gemeinsam als eine Einheit durchsucht werden
+kÃ¶nnen. Falls dem so ist, kÃ¶nnen sie auf der Voreinstellungsseite
+festlegen, welche der Unterkollektionen im Rahmen ihrer Anfragen
+berÃŒcksichtigt werden sollen.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Darstellungsvoreinstellungen</h3>
+
+Je nach vorliegender Kollektion kÃ¶nnen verschiedene Optionen
+eingestellt werden, die die Art der Darstellung beeinflussen.
+
+Kollektionen von Webseiten gestatten es ihnen die Darstellung der 
+Greenstonenavigationsleiste, die sich am Kopf jeder Dokumentseite befindet
+zu unterdrÃŒcken. Auf diese Weise endet ihre Anfrage direkt auf der
+Webseite, die ihre Anfrage erfÃŒllt, ohne dass der Greenstoneseitenkopf
+dargestellt wird. Um in diesem Falle eine weitere Suche durchfÃŒhren zu
+kÃ¶nnen mÃŒssen sie den "ZurÃŒck" Knopf ihres Browsers
+betÃ€tigen. Diese Art der Kollektionen erlaubt es ihnen auch die
+Greenstonewarnmeldungen zu unterdrÃŒcken, die gezeigt werden, wenn sie
+einen Link verfolgen, der aus der Greenstonekollektion in das World-Wide
+Web fÃŒhrt. Weiterhin kÃ¶nnen sie in manchen Webkollektionen
+einstellen, ob sie die Links auf der Ergebnisseite anstatt zur lokal in
+der Kollektion gespeicherten Kopie direkt zur Originalwebseite fÃŒhren
+sollen. 
+
+Kollektionen, die in verschiedenen Sprachen dargestellt werden kÃ¶nnen,
+erlauben ihnen die Wahl der in der Benutzerschnittstelle zu verwendenden
+Sprache. Ist die gewÃ€hlte Sprache Chinesisch, so kÃ¶nnen sie
+ausserdem feststellen, welche der Standardkodierungen fÃŒr Chinesisch
+ihr Browser verwendet.
+
+Schliesslich erlauben ihnen alle Kollektionen anstatt der graphischen
+Standardschnittstelle eine textuelle Schnittstelle zu verwenden. Dies ist
+besonders fÃŒr sehbehinderte Benutzer, die auf die Verwendung grosser
+ZeichensÃ€tze oder von GerÃ€ten zur Sprachausgabe angewiesen sind,
+sinnvoll.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Suchvoreinstellungen</h3>
+Zwei Knopfpaare steuern, ob bei ihren Anfragen Gross- und Kleinschreibung
+beachtet wird, und ob WortstÃ€mme Verwendung finden. Die ersten beiden
+KnÃ¶pfe steuern, ob Gross- und Kleinbuchstanben zwischen ihrer Anfrage
+und den Dokumententextem ÃŒbereinstimmen mÃŒssen. Die zweiten
+beiden KnÃ¶pfe bestimmen, ob Wortenden bei der Suche ignoriert werden
+oder nicht. 
+
+<p>Beispiel: wenn die KnÃ¶pfe <i>ignoriere Gross-/Kleinschreibung</i> und
+<i>ignoriere Wortendungen</i> angewÃ€hlt sind, wird die Anfrage<p>
+    <ul><kbd>African buildings</kbd></ul>
+      <p>genauso behandelt wie die Anfrage<p>
+      <ul><kbd>africa build</kbd>,</ul><p>
+      da der Grossbuchstabe in "African" zu einem Kleinbuchstaben
+      transformiert wird und die Endungen "n" and "ing" von
+      "African" und "building" entfernt werden (ausserdem wird "s" von
+      "builds" entfernt).
+
+<p>Sie kÃ¶nnen auch auf einen komplexeren Anfragemodus umschalten,
+welcher es ihnen gestattet Begriffe zu kombinieren indem sie sie mittels
+der Operatoren AND (&), OR (|), und NOT (!) verknÃŒpfen. Dies erlaubt
+es ihnen prÃ€zisere Anfragen zu spezifizieren.
+
+<p>Schliesslich kÃ¶nnen sie die Anzahl der als Antwort
+zurÃŒckgegebenen passenden Dokumente und  der
+auf einer Seite dargestellten Dokumente einstellen.
+
+}
+
+_texttanumbrowseoptions_ [l=de] {Es gibt _numbrowseoptions_ Arten Informationen in
+dieser Kollektion zu finden:}
+
+_textsimplehelpheading_ [l=de] {Wie man Informationen findet}
+
+_texthelpscope_ [l=de] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Reichweite der Anfragen</h3>
+
+<p> In den meisten Kollektionen kÃ¶nnen sie in verschiedenen Indexen
+suchen. Es kann zum Beispiel einen Autoren- und einen Titelindex
+geben. Oder es gibt einen Kapitel- und einen Paragraphenindex. In jedem
+Fall wird zu ihrer Anfrage passendes Dokument immer vollstÃ€ndig
+zurÃŒckgegeben egal welchen Index sie zur Suche verwendet haben.
+<p>Sollte es sich bei Dokumenten um BÃŒcher handeln, so werden sie immer
+an der passenden Stelle (in der Kollektion) geÃ¶ffnet.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/gli.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/gli.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/gli.dm	(revision 10506)
@@ -0,0 +1,100 @@
+# this file must be UTF-8 encoded
+
+package gli
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. 
+
+_javalinks_ {_imagehome_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+}
+#######################################################################
+# page content
+#######################################################################
+
+_icongligr_ {<img src="_httpicongligr_">}
+
+_pagetitle_ {_textgli_}
+
+_content_ {
+_icongligr_
+
+<p>_gliapplet_
+
+<p>
+_textglihelp_
+
+_nzdlpagefooter_
+}
+
+
+
+_gliapplet_ {
+
+<!--
+ <applet CODEBASE="_httpprefix_/bin/java" 
+    ARCHIVE="SignedGatherer.jar"
+    CODE = "org.greenstone.gatherer.GathererApplet"
+    name = "gatherer"
+    type="application/x-java-applet;version=1.4"
+    pluginspage="http://java.sun.com/products/plugin/1.4/plugin-install.html"
+    width = "380"
+    height = "50" >
+
+        <param name="httpprefix" value="_httpprefix_">
+        <param name="gwcgi" value="_gwcgi_">
+        <param name="collection" value="_cgiargc_">
+ </applet>
+
+-->
+
+
+<object 
+  classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
+
+  width="380" height="50"  name ="gatherer"
+
+  codebase="http://java.sun.com/products/plugin/autodl/jinstall-1_4-windows-i586.cab#Version=1,4,0,0"
+>
+    <param name="type"   value="application/x-java-applet;version=1.4">
+    <param name="scriptable" value="false">
+
+    <param name=code     value="org.greenstone.gatherer.GathererApplet" >
+    <param name=archive  value="_httpprefix_/bin/java/SignedGatherer.jar" >
+    <param name=name     value="gatherer" >
+
+    <param name="httpprefix" value="_httpprefix_">
+    <param name="gwcgi"      value="_gwcgi_">
+    <param name="collection" value="_cgiargc_">
+
+    <comment>
+
+      <embed
+        pluginspage="http://java.sun.com/products/plugin/index.html#download"
+        type="application/x-java-applet;version=1.4"
+        scriptable="false"
+
+        archive  = "_httpprefix_/bin/java/SignedGatherer.jar"
+        code     = "org.greenstone.gatherer.GathererApplet"
+        name     = "gatherer"
+        width    = "380"
+        height   = "50" 
+
+        httpprefix = "_httpprefix_"
+        gwcgi      = "_gwcgi_"
+        collection = "_cgiargc_"
+      >
+
+
+      </embed>
+      <noembed></noembed>
+
+    </comment>
+</object>
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/greek.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/greek.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/greek.dm	(revision 10506)
@@ -0,0 +1,1659 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Greek Language text and icon macros 
+# Many thanks to Dimitris Gavrilis (translated November 2003)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=el] {Î ÎµÏÎ¹Î¿ÎŽÎ¹ÎºÎ­Ï ÎµÎºÎŽÏÏÎµÎ¹Ï /Periodicals}
+_textsource_ [l=el] {Î±ÎœÎ±ÏÎ¿ÏÎ¬ ÏÎ·Î³Î®Ï/ ÏÎ·Î³Î®}
+_textdate_ [l=el] {Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î± Î­ÎºÎŽÎ¿ÏÎ·Ï: }
+_textnumpages_ [l=el] {Î±ÏÎ¹ÎžÎŒÏÏ ÏÎµÎ»Î¯ÎŽÏÎœ:}
+
+_textsignin_ [l=el] {ÎÎ³Î³ÏÎ±ÏÎ®}
+
+_textdefaultcontent_ [l=el] {ÎÎµÎœ ÎºÎ±ÏÎ­ÏÏÎ· ÎŽÏ
+ÎœÎ±ÏÎ¿Îœ ÎœÎ± Î²ÏÎµÎžÎµÎ¯ Î· ÏÎµÎ»Î¯ÎŽÎ± ÏÎ¿Ï
+ Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎ±ÏÎµ. Î Î±ÏÎ±ÎºÎ±Î»Î¿ÏÎŒÎµ ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ÏÏÎµ ÏÎ·Îœ ÎµÏÎ¹Î»Î¿Î³Î® "ÏÎ¯ÏÏ" Î® ÏÎ·Îœ ÎµÏÎ¹Î»Î¿Î³Î® "Î±ÏÏÎ¹ÎºÎ® ÏÎµÎ»Î¯ÎŽÎ±" Î³Î¹Î± ÎœÎ± Î³Ï
+ÏÎ¯ÏÎµÏÎµ ÏÏÎ·Îœ ÏÎ·ÏÎ¹Î±ÎºÎ® Î²Î¹Î²Î»Î¹Î¿ÎžÎ®ÎºÎ· ÏÎ¿Ï
+ Greenstone.}
+
+_textdefaulttitle_ [l=el] {GSDL Error}
+
+# -- Missing translation: _textbadcollection_
+
+_textselectpage_ [l=el] {-- ÎÏÎ¹Î»Î¿Î³Î® Î£ÎµÎ»Î¯ÎŽÎ±Ï --}
+
+_collectionextra_ [l=el] {ÎÏ
+ÏÎ® Î· ÏÏ
+Î»Î»Î¿Î³Î® ÏÎµÏÎ¹Î­ÏÎµÎ¹ _about:numdocs_ Î­Î³Î³ÏÎ±ÏÎ±. 
+Î€ÏÎ¿ÏÎ¿ÏÎ¿Î¹Î®ÎžÎ·ÎºÎµ ÏÎµÎ»ÎµÏ
+ÏÎ±Î¯Î± ÏÎ¿ÏÎ¬ ÏÏÎ¹Ï _ .}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=el] {<p>ÎÏ
+ÏÎ® Î· ÏÏ
+Î»Î»Î¿Î³Î® ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎµÎ¹ _numdocs_ _If_("_numdocs_" eq "1",document,documents), ÏÏÎœÎ¿Î»Î¿ _numbytes_.
+<p><a href="_httppagex_(bsummary)">Î Î±ÏÎ®ÏÏÎµ ÎµÎŽÏ</a> Î³Î¹Î± ÎœÎ± ÎŽÎµÎ¯ÏÎµ Î­ÎœÎ±Îœ  ÏÎµÏÎ¹Î»Î·ÏÏÎ¹ÎºÏ ÏÎ¯ÎœÎ±ÎºÎ± Î±Ï
+ÏÎ®Ï ÏÎ·Ï ÏÏ
+Î»Î»Î¿Î³Î®Ï.
+}
+
+_textimagecollection_ [l=el] {}
+_textimageabout_ [l=el] {Î Î»Î·ÏÎ¿ÏÎ¿ÏÎ¯ÎµÏ (Î³Î¹Î±)}
+_textimagehome_ [l=el] {ÎÏÏÎ¹ÎºÎ® ÏÎµÎ»Î¯ÎŽÎ±}
+_textimagehelp_ [l=el] {ÎÎ¿Î®ÎžÎµÎ¹Î±}
+_textimagepref_ [l=el] {ÎÏÎ¹Î»Î¿Î³Î­Ï}
+_textimagegreenstone_ [l=el] {(ÏÎ¿) Software ÏÎ·Ï ÎšÎ·ÏÎ¹Î±ÎºÎ®Ï ÎÎ¹Î²Î»Î¹Î¿ÎžÎ®ÎºÎ·Ï ÏÎ¿Ï
+ Greenstone}
+_textimageusab_ [l=el] {Î€Î¹ ÏÎ±Ï ÏÎ¬ÎœÎ·ÎºÎµ ÎŽÏÏÎºÎ¿Î»Î¿ ÎœÎ± ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹Î®ÏÎµÏÎµ;}
+
+_textimagesearch_ [l=el] {ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ· Î³Î¹Î± ÎµÎ¹ÎŽÎ¹ÎºÎ¿ÏÏ ÏÏÎ¿Ï
+Ï}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=el] {ÎÎ»ÏÎ±Î²Î·ÏÎ¹ÎºÏ ÎµÏ
+ÏÎµÏÎ®ÏÎ¹Î¿ ÏÎ¯ÏÎ»ÏÎœ.}
+_textimageCreator_ [l=el] {ÎÎ»ÏÎ±Î²Î·ÏÎ¹ÎºÏ ÎµÏ
+ÏÎµÏÎ®ÏÎ¹Î¿ ÏÏ
+Î³Î³ÏÎ±ÏÎ­ÏÎœ}
+_textimageSubject_ [l=el] {Î£Î¬ÏÏÏÎ· Î±ÎœÎ¬ ÎžÎµÎŒÎ±ÏÎ¹ÎºÎ® ÎºÎ±ÏÎ·Î³Î¿ÏÎ¯Î±}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=el] {ÎÏ
+ÏÎµÏÎ®ÏÎ¹Î¿ Î±ÎœÎ¬ Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=el] {Î£Î¬ÏÏÏÎ· Î±ÎœÎ¬ Î±ÏÏÎ¹ÎºÏ ÏÎœÎ¿ÎŒÎ± Î±ÏÏÎµÎ¯Î¿Ï
+}
+_textimageLanguage_ [l=el] {Î£Î¬ÏÏÏÎ· Î±ÎœÎ¬ Î³Î»ÏÏÏÎ±}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=el] {Î£Î¬ÏÏÏÎ· Î±ÎœÎ¬ Î¿ÏÎ³Î±ÎœÎ¹ÏÎŒÏ}
+_textimageKeyword_ [l=el] {Î£Î¬ÏÏÏÎ· ÎŒÎµ Î»Î­ÎŸÎ· ÎºÎ»ÎµÎ¹ÎŽÎ¯}
+_textimageHowto_ [l=el] {ÎÏ
+ÏÎµÏÎ®ÏÎ¹Î¿ ÎºÎ±ÏÎ·Î³Î¿ÏÎ¹ÏÎœ Î ÏÏ ÎœÎ±}
+_textimageList_ [l=el] {ÎÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÎÎ³Î³ÏÎ¬ÏÏÎœ}
+_textimageSeries_ [l=el] {Î£Î¬ÏÏÏÎ· Î±ÎœÎ¬ ÏÎµÏÏÎ¿Ï}
+_textimageTo_ [l=el] {Î£Î¬ÏÏÏÎ· Î±ÎœÎ¬ Î Î­ÏÎ±ÏÎŒÎ± ÏÎµ ÏÎµÎŽÎ¯Î¿}
+_textimageFrom_ [l=el] {Î£Î¬ÏÏÏÎ· Î±ÎœÎ¬ ÏÎ¿ÎŒÎ­Î±}
+_textimageTopic_ [l=el] {ÎÏ
+ÏÎµÏÎ®ÏÎ¹Î¿ ÏÎµÏ
+ÏÏÎœ Î³Î¹Î± ÎµÎ¹ÎŽÎ¹ÎºÎ¬ ÎžÎ­ÎŒÎ±ÏÎ±.}
+_textimageBrowse_ [l=el] {ÎÏ
+ÏÎµÏÎ®ÏÎ¹Î¿}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=el] {ÎÎ»ÏÎ±Î²Î·ÏÎ¹ÎºÏ ÎµÏ
+ÏÎµÏÎ®ÏÎ¹Î¿ Î±ÎœÎžÏÏÏÏÎœ}
+_textimageAcronym_ [l=el] {ÎÏ
+ÏÎµÏÎ®ÏÎ¹Î¿ Î±ÎºÏÎ¿ÎœÏ
+ÎŒÎ¯ÏÎœ}
+_textimagePhrase_ [l=el] {Î£Î¬ÏÏÏÎ· ÏÏÎ¬ÏÎµÏÎœ}
+_textimageArtist_ [l=el] {ÎÏ
+ÏÎµÏÎ®ÏÎ¹Î¿  ÎºÎ±Î»Î»Î¹ÏÎµÏÎœÏÎœ}
+_textimageVolume_ [l=el] {Î£Î¬ÏÏÏÎ· Î±ÎœÎ¬ ÏÏÎŒÎ¿}
+# -- Missing translation: _textimageCountries_
+_textimageCaptions_ [l=el] {ÎÏ
+ÏÎµÏÎ®ÏÎ¹Î¿ ÏÏÏÎ¿Î³ÏÎ±ÏÎ¹ÏÎœ}
+
+
+_texticontabsearchgreen_ [l=el] {ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ·}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=el] {Î€Î¯ÏÎ»Î¿Î¹ (Î-Î©)}
+_texticontabCreatorgreen_ [l=el] {Î£Ï
+Î³Î³ÏÎ±ÏÎµÎ¯Ï (Î-Î©)}
+_texticontabSubjectgreen_ [l=el] {ÎÎµÎŒÎ±ÏÎ¹ÎºÎ­Ï ÎµÎœÏÏÎ·ÏÎµÏ}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=el] {ÎÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯ÎµÏ}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=el] {ÎÎœÏÎŒÎ±ÏÎ± Î±ÏÏÎµÎ¯ÏÎœ}
+_texticontabLanguagegreen_ [l=el] {ÎÎ»ÏÏÏÎ±}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=el] {ÎÏÎ³Î±ÎœÎ¹ÏÎŒÏÏ}
+_texticontabKeywordgreen_ [l=el] {ÎÎ­ÎŸÎµÎ¹Ï - ÎºÎ»ÎµÎ¹ÎŽÎ¹Î¬}
+_texticontabhowgreen_ [l=el] {Î ÏÏ ÎœÎ±}
+_texticontabseriesgreen_ [l=el] {Î£ÎµÎ¹ÏÎ­Ï}
+_texticontablistgreen_ [l=el] {Î€Î±ÎŸÎ¹ÎœÏÎŒÎ¹ÏÎ·}
+_texticontabtogreen_ [l=el] {ÏÎ­ÏÎ±ÏÎŒÎ± ÏÎµ}
+_texticontabfromgreen_ [l=el] {Î±ÏÏ}
+_texticontabtopicgreen_ [l=el] {ÎÎ­ÎŒÎ±ÏÎ±}
+_texticontabbrwsegreen_ [l=el] {Î£Î¬ÏÏÏÎ·}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=el] {Î£Î¬ÏÏÏÎ·}
+_texticontabPeoplegreen_ [l=el] {ÎÎœÎžÏÏÏÎ¿Î¹ (Î-Î©)}
+_texticontabAcronymgreen_ [l=el] {ÎÎºÏÎ¿ÎœÏÎŒÎ¹Î±}
+_texticontabPhrasegreen_ [l=el] {ÎŠÏÎ¬ÏÎµÎ¹Ï}
+_texticontabArtistgreen_ [l=el] {ÎÎ±Î»Î»Î¹ÏÎ­ÏÎœÎµÏ}
+_texticontabVolumegreen_ [l=el] {Î€ÏÎŒÎ¿Î¹}
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=el] {ÎÎœÎ¿Î¹Î³ÎŒÎ± ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+}
+_texticonclosedbook_ [l=el] {Î¬ÎœÎ¿Î¹Î³ÎŒÎ± Î±Ï
+ÏÎ¿Ï ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ ÎºÎ±Î¹ ÎµÏÎ¹ÏÎºÏÏÎ¹ÏÎ· ÏÏÎœ ÏÎµÏÎ¹ÎµÏÎ¿ÎŒÎ­ÎœÏÎœ.}
+_texticonnext_ [l=el] {ÏÎ­ÏÎ±ÏÎŒÎ± ÏÏÎ·Îœ ÎµÏÏÎŒÎµÎœÎ· ÎµÎœÏÏÎ·ÏÎ±}
+_texticonprev_ [l=el] {ÏÎ­ÏÎ±ÏÎŒÎ± ÏÏÎ·Îœ ÏÏÎ¿Î·Î³Î¿ÏÎŒÎµÎœÎ· ÎµÎœÏÏÎ·ÏÎ±}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=el] {ÎÎœÎ¿Î¹Î³ÎŒÎ± ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ ÏÎµ ÎŒÎ¿ÏÏÎ® MIDI }
+_texticonmsword_ [l=el] {ÎÎœÎ¿Î¹Î³ÎŒÎ± ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ ÏÎµ ÎŒÎ¿ÏÏÎ® Microsoft Word }
+_texticonmp3_ [l=el] {ÎÎœÎ¿Î¹Î³ÎŒÎ± ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ ÏÎµ ÎŒÎ¿ÏÏÎ® MP3 }
+_texticonpdf_ [l=el] {ÎÎœÎ¿Î¹Î³ÎŒÎ± ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ ÏÎµ ÎŒÎ¿ÏÏÎ® PDF}
+_texticonps_ [l=el] {ÎÎœÎ¿Î¹Î³ÎŒÎ± ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ ÏÎµ ÎŒÎ¿ÏÏÎ® PostScript }
+_texticonppt_ [l=el] {ÎÎœÎ¿Î¹Î³ÎŒÎ± ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ ÏÎµ ÎŒÎ¿ÏÏÎ® PowerPoint }
+_texticonrtf_ [l=el] {ÎÎœÎ¿Î¹Î³ÎŒÎ± ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ ÏÎµ ÎŒÎ¿ÏÏÎ® RTF }
+_texticonxls_ [l=el] {ÎÎœÎ¿Î¹Î³ÎŒÎ± ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ ÏÎµ ÎŒÎ¿ÏÏÎ® Microsoft Excel }
+
+_page_ [l=el] {ÏÎµÎ»Î¯ÎŽÎ±}
+_pages_ [l=el] {ÏÎµÎ»Î¯ÎŽÎµÏ}
+_of_ [l=el] {Î±ÏÏ}
+_vol_ [l=el] {ÏÏÎŒÎ¿Ï}
+_num_ [l=el] {ÎÏ.}
+
+_textmonth00_ [l=el] {}
+_textmonth01_ [l=el] {ÎÎ±ÎœÎ¿Ï
+Î¬ÏÎ¹Î¿Ï}
+_textmonth02_ [l=el] {ÎŠÎµÎ²ÏÎ¿Ï
+Î¬ÏÎ¹Î¿Ï}
+_textmonth03_ [l=el] {ÎÎ¬ÏÏÎ¹Î¿Ï}
+_textmonth04_ [l=el] {ÎÏÏÎ¯Î»Î¹Î¿Ï}
+_textmonth05_ [l=el] {ÎÎ¬Î¹Î¿Ï}
+_textmonth06_ [l=el] {ÎÎ¿ÏÎœÎ¹Î¿Ï}
+_textmonth07_ [l=el] {ÎÎ¿ÏÎ»Î¹Î¿Ï}
+_textmonth08_ [l=el] {ÎÏÎ³Î¿Ï
+ÏÏÎ¿Ï}
+_textmonth09_ [l=el] {Î£ÎµÏÏÎ­ÎŒÎ²ÏÎ¹Î¿Ï}
+_textmonth10_ [l=el] {ÎÎºÏÏÎ²ÏÎ¹Î¿Ï}
+_textmonth11_ [l=el] {ÎÎ¿Î­ÎŒÎ²ÏÎ¹Î¿Ï}
+_textmonth12_ [l=el] {ÎÎµÎºÎ­ÎŒÎ²ÏÎ¹Î¿Ï}
+
+_textdocument_ [l=el] {ÎÎ³ÏÎ±ÏÎ¿}
+_textsection_ [l=el] {ÎÎœÏÏÎ·ÏÎ±}
+_textparagraph_ [l=el] {Î Î±ÏÎ¬Î³ÏÎ±ÏÎ¿Ï}
+
+_magazines_ [l=el] {Î ÎµÏÎ¹Î¿ÎŽÎ¹ÎºÎ¬}
+
+_nzdlpagefooter_ [l=el] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÎÎ¡Î§ÎÎÎ Î£ÎÎÎÎÎ" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=el] {_httpimg_/el/chomeof.gif}
+_httpiconchomeon_ [l=el] {_httpimg_/el/chomeon.gif}
+
+## "ÎÎÎÎÎÎÎ" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=el] {_httpimg_/el/chelpof.gif}
+_httpiconchelpon_ [l=el] {_httpimg_/el/chelpon.gif}
+
+## "ÎÎ ÎÎÎÎÎÎ£" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=el] {_httpimg_/el/cprefof.gif}
+_httpiconcprefon_ [l=el] {_httpimg_/el/cprefon.gif}
+
+## "Î£Î€ÎÎÎÎ€Î ÎÎÎ£ Î€Î ÎÎÎ©ÎÎ Î£ÎÎ£" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=el] {_httpimg_/el/cusabof.gif}
+_httpiconcusabon_ [l=el] {_httpimg_/el/cusabon.gif}
+
+
+## "Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=el] {_httpimg_/el/tsrchgr.gif}
+_httpicontsrchof_ [l=el] {_httpimg_/el/tsrchof.gif}
+_httpicontsrchon_ [l=el] {_httpimg_/el/tsrchon.gif}
+_widthtsrchx_ [l=el] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ÏÎ¯ÏÎ»Î¿Î¹ Î±- Ï" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=el] {_httpimg_/el/ttitlgr.gif}
+_httpiconttitleof_ [l=el] {_httpimg_/el/ttitlof.gif}
+_httpiconttitleon_ [l=el] {_httpimg_/el/ttitlon.gif}
+_widthttitlex_ [l=el] {87}
+
+# Not true DC, kept for legacy reasons
+## "ÏÏ
+Î³Î³ÏÎ±ÏÎµÎ¯Ï (Î±-Ï)" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=el] {_httpimg_/el/tauthgr.gif}
+_httpicontcreatof_ [l=el] {_httpimg_/el/tauthof.gif}
+_httpicontcreaton_ [l=el] {_httpimg_/el/tauthon.gif}
+_widthtcreatx_ [l=el] {110}
+
+## "ÎžÎµÎŒÎ±ÏÎ¹ÎºÎ­Ï ÎºÎ±ÏÎ·Î³Î¿ÏÎ¯ÎµÏ" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=el] {_httpimg_/el/tsubjgr.gif}
+_httpicontsubjon_ [l=el] {_httpimg_/el/tsubjon.gif}
+_httpicontsubjof_ [l=el] {_httpimg_/el/tsubjof.gif}
+_widthtsubjx_ [l=el] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯ÎµÏ" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=el] {_httpimg_/el/tdategr.gif}
+_httpicontdateof_ [l=el] {_httpimg_/el/tdateof.gif}
+_httpicontdateon_ [l=el] {_httpimg_/el/tdateon.gif}
+_widthtdatex_ [l=el] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "Î¿ÎœÏÎŒÎ±ÏÎ± Î±ÏÏÎµÎ¯ÏÎœ" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=el] {_httpimg_/el/tsrcgr.gif}
+_httpicontsrcof_ [l=el] {_httpimg_/el/tsrcof.gif}
+_httpicontsrcon_ [l=el] {_httpimg_/el/tsrcon.gif}
+_widthtsrcx_ [l=el] {87}
+
+## "Î³Î»ÏÏÏÎ±" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=el] {_httpimg_/el/tlanggr.gif}
+_httpicontlangon_ [l=el] {_httpimg_/el/tlangon.gif}
+_httpicontlangof_ [l=el] {_httpimg_/el/tlangof.gif}
+_widthtlangx_ [l=el] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "ÏÎµÎ¹ÏÎ­Ï" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=el] {_httpimg_/el/tsergr.gif}
+_httpicontserof_ [l=el] {_httpimg_/el/tserof.gif}
+_httpicontseron_ [l=el] {_httpimg_/el/tseron.gif}
+_widthtserx_ [l=el] {87}
+
+## "ÏÏÎµÏÎ¹ÎºÎ¬ ÎŒÎµ" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=el] {_httpimg_/el/ttogr.gif}
+_httpiconttoon_ [l=el] {_httpimg_/el/ttoon.gif}
+_httpiconttoof_ [l=el] {_httpimg_/el/ttoof.gif}
+_widthttox_ [l=el] {87}
+
+## "Î±ÏÏ" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=el] {_httpimg_/el/tfromgr.gif}
+_httpicontfromon_ [l=el] {_httpimg_/el/tfromon.gif}
+_httpicontfromof_ [l=el] {_httpimg_/el/tfromof.gif}
+_widthtfromx_ [l=el] {87}
+
+## "Î¿ÏÎ³Î±ÎœÎ¹ÏÎŒÎ¿Î¯" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=el] {_httpimg_/el/torggr.gif}
+_httpicontorgon_ [l=el] {_httpimg_/el/torgon.gif}
+_httpicontorgof_ [l=el] {_httpimg_/el/torgof.gif}
+_widthtorgx_ [l=el] {114}
+
+## "ÏÏÏ ÎœÎ±" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=el] {_httpimg_/el/thowgr.gif}
+_httpiconthowon_ [l=el] {_httpimg_/el/thowon.gif}
+_httpiconthowof_ [l=el] {_httpimg_/el/thowof.gif}
+_widththowx_ [l=el] {87}
+
+## "ÎžÎ­ÎŒÎ±" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=el] {_httpimg_/el/ttopicgr.gif}
+_httpiconttopicon_ [l=el] {_httpimg_/el/ttopicon.gif}
+_httpiconttopicof_ [l=el] {_httpimg_/el/ttopicof.gif}
+_widthttopicx_ [l=el] {87}
+
+## "ÏÎ¬ÏÏÏÎ·" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=el] {_httpimg_/el/tbrwsegr.gif}
+_httpicontbrwseon_ [l=el] {_httpimg_/el/tbrwseon.gif}
+_httpicontbrwseof_ [l=el] {_httpimg_/el/tbrwseof.gif}
+_widthtbrwsex_ [l=el] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "Î¬ÎœÎžÏÏÏÎ¿Î¹" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=el] {_httpimg_/el/tpeopgr.gif}
+_httpicontpeopof_ [l=el] {_httpimg_/el/tpeopof.gif}
+_httpicontpeopon_ [l=el] {_httpimg_/el/tpeopon.gif}
+_widthtpeopx_ [l=el] {97}
+
+## "Î±ÎºÏÎ¿ÎœÏÎŒÎ¹Î¿" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=el] {_httpimg_/el/tacrogr.gif}
+_httpicontacroof_ [l=el] {_httpimg_/el/tacroof.gif}
+_httpicontacroon_ [l=el] {_httpimg_/el/tacroon.gif}
+_widthtacrox_ [l=el] {87}
+
+## "ÏÏÎ¬ÏÎµÎ¹Ï" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=el] {_httpimg_/el/tphrsegr.gif}
+_httpicontphrseof_ [l=el] {_httpimg_/el/tphrseof.gif}
+_httpicontphrseon_ [l=el] {_httpimg_/el/tphrseon.gif}
+_widthtphrsex_ [l=el] {87}
+
+## "ÎºÎ±Î»Î»Î¹ÏÎ­ÏÎœÎµÏ" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=el] {_httpimg_/el/tartstgr.gif}
+_httpicontartstof_ [l=el] {_httpimg_/el/tartstof.gif}
+_httpicontartston_ [l=el] {_httpimg_/el/tartston.gif}
+_widthtartstx_ [l=el] {87}
+
+## "Î»Î­ÎŸÎµÎ¹Ï ÎºÎ»ÎµÎ¹ÎŽÎ¹Î¬" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=el] {_httpimg_/el/tkwgr.gif}
+_httpicontkwof_ [l=el] {_httpimg_/el/tkwof.gif}
+_httpicontkwon_ [l=el] {_httpimg_/el/tkwon.gif}
+_widthtkwx_ [l=el] {87}
+
+## "ÏÏÎŒÎ¿Î¹" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=el] {_httpimg_/el/tvolgr.gif}
+_httpicontvolof_ [l=el] {_httpimg_/el/tvolof.gif}
+_httpicontvolon_ [l=el] {_httpimg_/el/tvolon.gif}
+_widthtvolx_ [l=el] {87}
+
+## "Î»ÎµÎ¶Î¬ÎœÏÎµÏ" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=el] {_httpimg_/el/tcaptgr.gif}
+_httpicontcaptof_ [l=el] {_httpimg_/el/tcaptof.gif}
+_httpicontcapton_ [l=el] {_httpimg_/el/tcapton.gif}
+_widthtcaptx_ [l=el] {87}
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "Î²Î¿Î®ÎžÎµÎ¹Î±" ## green_title ## h_help ##
+_httpiconhhelp_ [l=el] {_httpimg_/el/h\_help.gif}
+_widthhhelp_ [l=el] {200}
+_heighthhelp_ [l=el] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=el] {ÏÏÎµÏÎ¹ÎºÎ¬ ÎŒÎµ Î±Ï
+ÏÎ®Îœ ÏÎ· ÏÏ
+Î»Î»Î¿Î³Î®}
+
+_textsubcols1_ [l=el] {<p>Î ÏÏ
+Î»Î»Î¿Î³Î® ÏÎµÏÎ¹Î­ÏÎµÎ¹ ÏÏ
+ÎœÎ¿Î»Î¹ÎºÎ¬ _1_ Ï
+ÏÎ¿ÏÏ
+Î»Î»Î¿Î³Î­Ï. 
+ÎÏ
+ÏÎ® ÏÎ· ÏÏÎ¹Î³ÎŒÎ® ÎµÎ¯ÎœÎ±Î¹ ÎŽÎ¹Î±ÎžÎ­ÏÎ¹ÎŒÎµÏ:
+<blockquote>}
+
+_textsubcols2_ [l=el] {</blockquote>
+ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÎµÎ»Î­Î³ÎŸÎµÏÎµ ÏÎ¿Î¹ÎµÏ ÏÏ
+Î»Î»Î¿Î³Î­Ï ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ÏÎµ Î±Ï
+ÏÎ® ÏÎ· ÏÏÎ¹Î³ÎŒÎ® (Î® ÎœÎ± ÏÎ¹Ï Î±Î»Î»Î¬ÎŸÎµÏÎµ) ÏÏÎ· ÏÎµÎ»Î¯ÎŽÎ± ÏÏÎœ ÎÏÎ¹Î»Î¿Î³ÏÎœ.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÏÎ»Î·ÏÎ¿ÏÎ¿ÏÎ¯ÎµÏ" ## green_title ## h_about ##
+_httpiconhabout_ [l=el] {_httpimg_/el/h\_about.gif}
+_widthhabout_ [l=el] {200}
+_heighthabout_ [l=el] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=el] {Î€Î¯ÏÎ»Î¿Î¹ Î-Î©}
+_texticonhcreat_ [l=el] {Î£Ï
+Î³Î³ÏÎ±ÏÎµÎ¯Ï (Î-Î©)}
+_texticonhsubj_ [l=el] {ÎžÎ­ÎŒÎ±ÏÎ±}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=el] {ÎÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯ÎµÏ}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=el] {ÎÎœÏÎŒÎ±ÏÎ± Î±ÏÏÎµÎ¯ÏÎœ}
+_texticonhlang_ [l=el] {ÎÎ»ÏÏÏÎµÏ}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=el] {Î ÏÎ¿Ï}
+_texticonhfrom_ [l=el] {Î±ÏÏ }
+_texticonhser_ [l=el] {Î£ÎµÎ¹ÏÎ­Ï}
+_texticonhhow_ [l=el] {Î ÏÏ ÎœÎ±}
+_texticonhorg_ [l=el] {ÎÏÎ³Î±ÎœÎ¹ÏÎŒÎ¿Î¯}
+_texticonhbrwse_ [l=el] {Î£Î¬ÏÏÏÎ· }
+_texticonhbrows_ [l=el] {Î£Î¬ÏÏÏÎ· }
+_texticonhpeople_ [l=el] {ÎÎœÎžÏÏÏÎ¿Î¹ (Î- Î©)}
+_texticonhacronym_ [l=el] {ÎÎºÏÎ¿ÎœÏÎŒÎ¹Î±}
+_texticonhphrases_ [l=el] {ÎŠÏÎ¬ÏÎµÎ¹Ï}
+_texticonhartist_ [l=el] {ÎÎ±Î»Î»Î¹ÏÎ­ÏÎœÎµÏ}
+_texticonhkw_ [l=el] {ÎÎ­ÎŸÎµÎ¹Ï -ÎºÎ»ÎµÎ¹ÎŽÎ¹Î¬}
+_texticonhvol_ [l=el] {Î€ÏÎŒÎ¿Î¹}
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=el] {ÎºÎ»ÎµÎ¯ÏÎµ Î±Ï
+ÏÎ® ÏÎ·Îœ ÎµÎœÏÏÎ·ÏÎ± ÏÎ·Ï Î²Î¹Î²Î»Î¹Î¿ÎžÎ®ÎºÎ·Ï}
+_texticonclosedbookshelf_ [l=el] {Î¬ÎœÎ¿Î¹ÎŸÎµ Î±Ï
+ÏÎ® ÏÎ·Îœ ÎµÎœÏÏÎ·ÏÎ± ÏÎ·Ï Î²Î¹Î²Î»Î¹Î¿ÎžÎ®ÎºÎ·Ï ÎºÎ±Î¹ ÎŽÎµÏ ÏÎ± ÏÎµÏÎ¹ÎµÏÏÎŒÎµÎœÎ±}
+_texticonopenbook_ [l=el] {ÎºÎ»ÎµÎ¯ÏÎµ Î±Ï
+ÏÏ ÏÎ¿ Î²Î¹Î²Î»Î¯Î¿}
+_texticonclosedfolder_ [l=el] {ÎÎœÎ¿Î¹ÎŸÎµ Î±Ï
+ÏÏÎœ ÏÎ¿ ÏÎ¬ÎºÎµÎ»Î¿ ÎºÎ±Î¹ ÎŽÎµÏ ÏÎ± ÏÎµÏÎ¹ÎµÏÏÎŒÎµÎœÎ±.}
+_texticonclosedfolder2_ [l=el] {Î¬ÎœÎ¿Î¹ÎŸÎµ ÏÎ·Îœ Ï
+ÏÎ¿ÎµÎœÏÏÎ·ÏÎ±:}
+_texticonopenfolder_ [l=el] {ÎºÎ»ÎµÎ¯ÏÎµ Î±Ï
+ÏÏÎœ ÏÎ¿ ÏÎ¬ÎºÎµÎ»Î¿}
+_texticonopenfolder2_ [l=el] {ÎºÎ»ÎµÎ¯ÏÎµ ÏÎ·Îœ Ï
+ÏÎ¿ÎµÎœÏÏÎ·ÏÎ±:}
+_texticonsmalltext_ [l=el] {ÏÏÎ¿Î²Î¿Î»Î® Î±Ï
+ÏÎ¿Ï ÏÎ¿Ï
+ ÏÎŒÎ®ÎŒÎ±ÏÎ¿Ï ÏÎ¿Ï
+ ÎºÎµÎ¹ÎŒÎ­ÎœÎ¿Ï
+}
+_texticonsmalltext2_ [l=el] {ÏÏÎ¿Î²Î¿Î»Î® ÎºÎµÎ¹ÎŒÎ­ÎœÎ¿Ï
+}
+_texticonpointer_ [l=el] {ÏÏÎ­ÏÎ¿Ï
+ÏÎ± ÎµÎœÏÏÎ·ÏÎ± }
+_texticondetach_ [l=el] {ÎÎœÎ¿Î¹ÎŸÎµ Î±Ï
+ÏÎ® ÏÎ· ÏÎµÎ»Î¯ÎŽÎ± ÏÎµ ÎœÎ­Î¿ ÏÎ±ÏÎ¬ÎžÏ
+ÏÎ¿}
+_texticonhighlight_ [l=el] {Î¥ÏÎ¿Î³ÏÎ¬ÎŒÎŒÎ¹ÏÎ· ÏÏÏÎœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+_texticonnohighlight_ [l=el] {ÎÎ· ÎµÏÎ¹ÏÎ®ÎŒÎ±ÎœÏÎ· ÏÏÏÎœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+_texticoncontracttoc_ [l=el] {Î£ÏÎŒÏÏÎ·ÎŸÎ· ÏÎ¿Ï
+ ÏÎ¯ÎœÎ±ÎºÎ± ÏÎµÏÎ¹ÎµÏÎ¿ÎŒÎ­ÎœÏÎœ}
+_texticonexpandtoc_ [l=el] {ÎÎœÎ¬ÏÏÏ
+ÎŸÎ· ÏÎ¿Ï
+ ÏÎ¯ÎœÎ±ÎºÎ± ÏÎµÏÎ¹ÎµÏÎ¿ÎŒÎ­ÎœÏÎœ}
+_texticonexpandtext_ [l=el] {ÎÎŒÏÎ¬ÎœÎ¹ÏÎµ Î¿Î»ÏÎºÎ»Î·ÏÎ¿ ÏÎ¿ ÎºÎµÎ¯ÎŒÎµÎœÎ¿}
+_texticoncontracttext_ [l=el] {ÎÎŒÏÎ¬ÎœÎ¹ÏÎ· ÎºÎµÎ¹ÎŒÎ­ÎœÎ¿Ï
+ ÎŒÏÎœÎ¿ Î³Î¹Î± ÏÎ·Îœ ÏÏÎ¿ÎµÏÎ¹Î»ÎµÎ³ÎŒÎ­ÎœÎ· ÎµÎœÏÏÎ·ÏÎ±}
+_texticonwarning_ [l=el] {<b>Î ÏÎ¿ÎµÎ¹ÎŽÎ¿ÏÎ¿Î¯Î·ÏÎ·: </b>}
+_texticoncont_ [l=el] {ÎžÎ­Î»ÎµÏÎµ ÎœÎ± ÏÏ
+ÎœÎµÏÎ¯ÏÎµÏÎµ;}
+
+_textltwarning_ [l=el] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_ÎÎµÎ³Î­ÎœÎžÏ
+ÏÎ· ÏÎ¿Ï
+ ÎºÎµÎ¹ÎŒÎ­ÎœÎ¿Ï
+ ÎµÎŽÏ ÎžÎ± ÏÏÎ¿ÎºÎ±Î»Î­ÏÎµÎ¹ ÏÎ·Îœ ÎµÎŒÏÎ¬ÎœÎ¹ÏÎ· Ï
+ÏÎµÏÎ²Î¿Î»Î¹ÎºÎ¬ ÎŒÎµÎ³Î¬Î»Î¿Ï
+ Î±ÏÎ¹ÎžÎŒÎ¿Ï ÎŽÎµÎŽÎ¿ÎŒÎ­ÎœÏÎœ _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=el] {ÏÎ®Î³Î±Î¹ÎœÎµ ÏÏÎ· ÏÎµÎ»Î¯ÎŽÎ±}
+_textintro_ [l=el] {<i>(ÎµÎ¹ÏÎ±Î³ÏÎ³Î¹ÎºÏ ÎºÎµÎ¯ÎŒÎµÎœÎ¿)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ÏÎ¯ÏÎ»Î¿Î¹ Î±-Ï" ## green_title ## h_title ##
+_httpiconhtitle_ [l=el] {_httpimg_/el/h\_title.gif}
+_widthhtitle_ [l=el] {200}
+_heighthtitle_ [l=el] {57}
+
+# Not true DC, kept for legacy reasons
+## "ÏÏ
+Î³Î³ÏÎ±ÏÎµÎ¯Ï (Î±-Ï)" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=el] {_httpimg_/el/h\_auth.gif}
+_widthhcreat_ [l=el] {200}
+_heighthcreat_ [l=el] {57}
+
+## "ÎžÎµÎŒÎ±ÏÎ¹ÎºÎ­Ï ÎºÎ±ÏÎ·Î³Î¿ÏÎ¯ÎµÏ" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=el] {_httpimg_/el/h\_subj.gif}
+_widthhsubj_ [l=el] {200}
+_heighthsubj_ [l=el] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯ÎµÏ" ## green_title ## h_date ##
+_httpiconhdate_ [l=el] {_httpimg_/el/h\_date.gif}
+_widthhdate_ [l=el] {200}
+_heighthdate_ [l=el] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "Î¿ÎœÏÎŒÎ±ÏÎ± Î±ÏÏÎµÎ¯ÏÎœ" ## green_title ## h_src ##
+_httpiconhsrc_ [l=el] {_httpimg_/el/h\_src.gif}
+_widthhsrc_ [l=el] {200}
+_heighthsrc_ [l=el] {57}
+
+## "Î³Î»ÏÏÏÎµÏ" ## green_title ## h_lang ##
+_httpiconhlang_ [l=el] {_httpimg_/el/h\_lang.gif}
+_widthhlang_ [l=el] {200}
+_heighthlang_ [l=el] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "ÏÏÎ¿Ï" ## green_title ## h_to ##
+_httpiconhto_ [l=el] {_httpimg_/el/h\_to.gif}
+_widthhto_ [l=el] {200}
+_heighthto_ [l=el] {57}
+
+## "Î±ÏÏ" ## green_title ## h_from ##
+_httpiconhfrom_ [l=el] {_httpimg_/el/h\_from.gif}
+_widthhfrom_ [l=el] {200}
+_heighthfrom_ [l=el] {57}
+
+## "ÏÎµÎ¹ÏÎ­Ï" ## green_title ## h_ser ##
+_httpiconhser_ [l=el] {_httpimg_/el/h\_ser.gif}
+_widthhser_ [l=el] {200}
+_heighthser_ [l=el] {57}
+
+## "ÏÏÏ ÎœÎ±" ## green_title ## h_how ##
+_httpiconhhow_ [l=el] {_httpimg_/el/h\_how.gif}
+_widthhhow_ [l=el] {200}
+_heighthhow_ [l=el] {57}
+
+## "ÎžÎ­ÎŒÎ±ÏÎ±" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=el] {_httpimg_/el/h\_topic.gif}
+_widthhtopic_ [l=el] {200}
+_heighthtopic_ [l=el] {57}
+
+## "Î¿ÏÎ³Î±ÎœÎ¹ÏÎŒÏÏ" ## green_title ## h_org ##
+_httpiconhorg_ [l=el] {_httpimg_/el/h\_org.gif}
+_widthhorg_ [l=el] {250}
+_heighthorg_ [l=el] {57}
+
+## "ÏÎ¬ÏÏÏÎ·" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=el] {_httpimg_/el/h\_brwse.gif}
+_widthhbrwse_ [l=el] {200}
+_heighthbrwse_ [l=el] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "Î¬ÎœÎžÏÏÏÎ¿Î¹" ## green_title ## h_people ##
+_httpiconhpeople_ [l=el] {_httpimg_/el/h\_people.gif}
+_widthhpeople_ [l=el] {200}
+_heighthpeople_ [l=el] {57}
+
+## "Î±ÎºÏÎ¿ÎœÏÎŒÎ¹Î±" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=el] {_httpimg_/el/h\_acro.gif}
+_widthhacronym_ [l=el] {200}
+_heighthacronym_ [l=el] {57}
+
+## "ÏÏÎ¬ÏÎµÎ¹Ï" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=el] {_httpimg_/el/h\_phrse.gif}
+_widthhphrse_ [l=el] {200}
+_heighthphrse_ [l=el] {57}
+
+## "ÎºÎ±Î»Î»Î¹ÏÎ­ÏÎœÎµÏ" ## green_title ## h_artist ##
+_httpiconhartist_ [l=el] {_httpimg_/el/h\_artist.gif}
+_widthhartist_ [l=el] {200}
+_heighthartist_ [l=el] {57}
+
+## "Î»Î­ÎŸÎµÎ¹Ï ÎºÎ»ÎµÎ¹ÎŽÎ¹Î¬" ## green_title ## h_kw ##
+_httpiconhkw_ [l=el] {_httpimg_/el/h\_kw.gif}
+_widthhkw_ [l=el] {200}
+_heighthkw_ [l=el] {57}
+
+## "ÏÏÎŒÎ¿Î¹" ## green_title ## h_vol ##
+_httpiconhvol_ [l=el] {_httpimg_/el/h\_vol.gif}
+_widthhvol_ [l=el] {200}
+_heighthvol_ [l=el] {57}
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+## "ÎµÏÎ¹ÎºÎµÏÎ±Î»Î¯ÎŽÎµÏ" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=el] {_httpimg_/el/h\_capt.gif}
+_widthhcapt_ [l=el] {200}
+_heighthcapt_ [l=el] {57}
+
+
+## "ÎÎ­Î»ÎµÏÎµ ÎœÎ± ÏÏ
+ÎœÎµÏÎ¯ÏÎµÏÎµ;?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=el] {_httpimg_/el/contof.gif}
+_httpiconconton_ [l=el] {_httpimg_/el/conton.gif}
+
+## "ÎÎÎÎÎÎÎ¥Î£Î\nÎÎÎÎÎÎÎÎ¥" ## document_button ## eallt ##
+_httpiconealltof_ [l=el] {_httpimg_/el/ealltof.gif}
+_httpiconeallton_ [l=el] {_httpimg_/el/eallton.gif}
+
+## "Î ÎÎ¡ÎÎÎ§ÎÎÎÎÎ\nÎ£Î¥ÎÎÎÎÎÎÎÎ¥" ## document_button ## econc ##
+_httpiconeconcof_ [l=el] {_httpimg_/el/econcof.gif}
+_httpiconeconcon_ [l=el] {_httpimg_/el/econcon.gif}
+
+## "ÎÎ ÎÎ£Î ÎÎ£Î" ## document_button ## edtch ##
+_httpiconedtchof_ [l=el] {_httpimg_/el/edtchof.gif}
+_httpiconedtchon_ [l=el] {_httpimg_/el/edtchon.gif}
+
+## "ÎÎÎÎÎÎÎ¥Î£Î Î€Î©Î\nÎ ÎÎ¡ÎÎÎ§ÎÎÎÎÎ©Î" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=el] {_httpimg_/el/eexpcof.gif}
+_httpiconeexpcon_ [l=el] {_httpimg_/el/eexpcon.gif}
+
+## "ÎÎÎÎÎÎÎ\nÎ£Î¥ÎÎÎÎÎÎÎÎ¥" ## document_button ## etsec ##
+_httpiconetsecof_ [l=el] {_httpimg_/el/etsecof.gif}
+_httpiconetsecon_ [l=el] {_httpimg_/el/etsecon.gif}
+
+## "Î¥Î ÎÎÎ¡ÎÎÎÎÎ£Î" ## document_button ## ehl ##
+_httpiconehlof_ [l=el] {_httpimg_/el/ehlof.gif}
+_httpiconehlon_ [l=el] {_httpimg_/el/ehlon.gif}
+
+## "Î§Î©Î¡ÎÎ£\nÎ¥Î ÎÎÎ¡ÎÎÎÎÎ£Î" ## document_button ## enhl ##
+_httpiconenhlof_ [l=el] {_httpimg_/el/enhlof.gif}
+_httpiconenhlon_ [l=el] {_httpimg_/el/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=el] {_If_(_thislast_,results _thisfirst_ - _thislast_ for query: _cgiargq_,No matches for query: _cgiargq_)}
+_textnoquerytitle_ [l=el] {Î£ÎµÎ»Î¯ÎŽÎ± Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+
+_texticonthispage_ [l=el] {Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·}
+_textsome_ [l=el] {ÎŒÎµÏÎ¹ÎºÎ­Ï}
+_textall_ [l=el] {ÏÎ»Î± /all}
+_textboolean_ [l=el] {ÏÎµÎ»ÎµÏÏÎ­Ï boolean}
+_textranked_ [l=el] {ÏÎ±ÎŸÎ¹ÎœÏÎŒÎ·ÏÎ·}
+_textnatural_ [l=el] {ÏÏ
+ÏÎ¹ÎºÏ}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=el] {}
+_texticonsearchhistorybar_ [l=el] {ÎÏÏÎ¿ÏÎ¹ÎºÏ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=el] {ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¯Î·ÏÎµ Î±Ï
+ÏÎ® ÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·}
+_textfreqmsg1_ [l=el] {ÎÎ­ÏÏÎ·ÏÎ· ÎÎ­ÎŸÎµÏÎœ: }
+_textpostprocess_ [l=el] {_If_(_quotedquery_,<br><i>post-processed to find _quotedquery_</i>
+)}
+_textinvalidquery_ [l=el] {Î ÏÏÎœÏÎ±ÎŸÎ· ÏÎ·Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ®Ï ÏÎ±Ï ÎŽÎµÎœ ÎµÎ¯ÎœÎ±Î¹ Î­Î³ÎºÏ
+ÏÎ·}
+
+_textmorethan_ [l=el] {Î ÎµÏÎ¹ÏÏÏÏÎµÏÎ± Î±ÏÏ}
+_textapprox_ [l=el] {Î£ÏÎµÏÎ¹ÎºÎ¬ ÎŒÎµ /About }
+_textnodocs_ [l=el] {ÎÎµÎœ Î²ÏÎ­ÎžÎ·ÎºÎµ ÎºÎ±ÎœÎ­ÎœÎ± Î­Î³Î³ÏÎ±ÏÎ¿ ÏÎ¿Ï
+ ÎœÎ± ÏÎ±Î¹ÏÎ¹Î¬Î¶ÎµÎ¹ ÏÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ® ÏÎ±Ï.}
+_text1doc_ [l=el] {1 Î­Î³Î³ÏÎ±ÏÎ¿ ÏÎ±Î¹ÏÎ¹Î¬Î¶ÎµÎ¹ ÏÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·.}
+_textlotsdocs_ [l=el] {Î±ÏÎ¿ÏÎµÎ»Î­ÏÎŒÎ±ÏÎ± ÏÎ¿Ï
+ ÏÎ±Î¹ÏÎ¹Î¬Î¶Î¿Ï
+Îœ ÏÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ® ÏÎ±Ï.}
+_textmatches_ [l=el] {ÎÏÎ¿ÏÎµÎ»Î­ÏÎŒÎ±ÏÎ±}
+_textbeginsearch_ [l=el] {ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ· ÏÏÏÎ±}
+_textrunquery_ [l=el] {ÎÎºÏÎ­Î»ÎµÏÎ· ÎÏÏÏÎ®ÎŒÎ±ÏÎ¿Ï}
+_textclearform_ [l=el] {ÎÎ¹Î±Î³ÏÎ±ÏÎ® ÏÎ·Ï ÏÏÏÎŒÎ±Ï}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=el] {Î»Î­ÎŸÎ· Î® ÏÏÎ¬ÏÎ·}
+_textinfield_ [l=el] {... ÏÎµ ÏÎµÎŽÎ¯Î¿ }
+_textfoldstem_ [l=el] {(fold, stem)}
+
+_textadvquery_ [l=el] {Î ÎµÎ¹ÏÎ¬Î³ÎµÏÎµ ÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· ÎºÎ±ÏÎµÏ
+ÎžÎµÎ¯Î±Îœ:}
+_textallfields_ [l=el] {ÏÎ»Î± ÏÎ± ÏÎµÎŽÎ¯Î± / all fields}
+_texttextonly_ [l=el] {ÎŒÏÎœÎ¿ ÎºÎµÎ¯ÎŒÎµÎœÎ¿}
+_textand_ [l=el] {ÎºÎ±Î¹ /and}
+_textor_ [l=el] {Î®}
+_textandnot_ [l=el] {ÎºÎ±Î¹ ÏÏÎ¹ / and not}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=el] {ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ· Î³Î¹Î± _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, at _gselection_ level) _If_(_nselection_, in _nselection_ language) ÏÎ¿Ï
+ ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎµÎ¹ _querytypeselection_ (Î±ÏÏ ÏÎ¹Ï) Î»Î­ÎŸÎµÎ¹Ï}
+
+_textadvancedsearch_ [l=el] {ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ· _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, at _gselection_ level)_If_(_nselection_, in _nselection_ language) using _querytypeselection_ query}
+
+_textformsimplesearch_ [l=el] {ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ· _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )for _formquerytypeselection_ of}
+
+_textformadvancedsearch_ [l=el] {ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ· _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )ÎºÎ±Î¹ ÎµÏÎ¯ÎŽÎµÎ¹ÎŸÎ· Î±ÏÎ¿ÏÎµÎ»ÎµÏÎŒÎ¬ÏÏÎœ ÏÎ±ÎŸÎ¹ÎœÎ¿ÎŒÎ·ÎŒÎ­ÎœÎ± Î±ÎœÎ¬ _formquerytypeselection_ }
+
+
+_textnojsformwarning_ [l=el] {Î ÏÎ¿ÎµÎ¹ÎŽÎ¿ÏÎ¿Î¯Î·ÏÎ·: ÏÏÎ¿Îœ web browser ÏÎ±Ï ÎµÎŒÏÎ±ÎœÎ¯Î¶ÎµÏÎ±Î¹ ÎºÎµÎ¯ÎŒÎµÎœÎ¿ Java. <br>ÎÎ¹Î± ÎœÎ± ÏÎ¿ ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹Î®ÏÎµÏÎµ Î±ÏÏ ÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· , ÏÎ±ÏÎ±ÎºÎ±Î»Î¿ÏÎŒÎµ ÎµÎœÎµÏÎ³Î¿ÏÎ¿Î¹Î®ÏÏÎµ ÏÎ·Îœ.}
+_textdatesearch_ [l=el] {Î£Îµ Î±Ï
+ÏÎ®Îœ ÏÎ· ÏÏ
+Î»Î»Î¿Î³Î® ÎŒÏÎ¿ÏÎµÎ¯ ÎœÎ± Î³Î¯ÎœÎµÎ¹ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· Î³Î¹Î± Î­Î³Î³ÏÎ±ÏÎ± ÎŒÎ¹Î±Ï ÏÏÎ¿ÎœÎ¹ÎºÎ®Ï ÏÎµÏÎ¹ÏÎŽÎ¿Ï
+, Î® Î³Î¹Î± Î­Î³Î³ÏÎ±ÏÎ± ÏÎ¿Ï
+ ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎ¿Ï
+Îœ ÎºÎ¬ÏÎ¿Î¹Î± ÏÏ
+Î³ÎºÎµÎºÏÎ¹ÎŒÎ­ÎœÎ· Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±. ÎÏ
+ÏÎ® ÎµÎ¯ÎœÎ±Î¹ ÎŒÎ¹Î± ÏÏÎ¿Î±Î¹ÏÎµÏÎ¹ÎºÎ® ÎµÏÎ¹Î»Î¿Î³Î® Î±Ï
+ÏÎ®Ï ÏÎ·Ï ÏÏ
+Î»Î»Î¿Î³Î®Ï.}
+_textstartdate_ [l=el] {ÎÏÏÎ¹ÎºÎ® (Î® ÎŒÎ¿ÎœÎ±ÎŽÎ¹ÎºÎ®) Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±:}
+_textenddate_ [l=el] {Î€ÎµÎ»Î¹ÎºÎ® Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±:}
+_textbc_ [l=el] {Ï.Î§.}
+_textad_ [l=el] {C.E.}
+_textexplaineras_ [l=el] {Î€Î± Î±ÏÏÎ¹ÎºÎ¬ Î.Î. ( C.E.) ÎºÎ±Î¹ Î .Î.Î.(B.C.E.) ÎµÎ¯ÎœÎ±Î¹ ÎµÎœÎ±Î»Î»Î±ÎºÏÎ¹ÎºÎ¬ ÏÏÎœ ÎŒ.Î§.(ÎŒÎµÏÎ¬ Î§ÏÎ¹ÏÏÎ¿Ï) ÎºÎ±Î¹ Ï.Î§. (ÏÏÎ¿ Î§ÏÎ¹ÏÏÎ¿Ï) ÎÏ
+ÏÎ® Î¿Î¹ ÏÏÎ¿Î¹ ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹Î¿ÏÎœÏÎ±Î¹ Î¿ÏÏÏÏ ÏÏÏÎµ ÎœÎ± ÎŒÎ·Îœ Î³Î¯ÎœÎ¿ÎœÏÎ±Î¹ ÎŽÎ¹Î±ÎºÎÏÎ¹ÏÎµÎ¹Ï ÎŒÎµÏÎ±ÎŸÏ ÎŽÎ¹Î±ÏÎ¿ÏÎµÏÎ¹ÎºÏÎœ ÏÎ¿Î»Î¹ÏÎ¹ÏÎŒÏÎœ/ ÎžÏÎ·ÏÎºÎ¹ÏÎœ ÎºÎ±Î¹ Î±ÎœÏÎ¹ÏÏÎ¿ÏÏÏÎµÏÎ¿Ï
+Îœ ÏÎ¹Ï ÏÏÎ¬ÏÎµÎ¹Ï "ÎÎ¿Î¹ÎœÎ® ÎÏÎ¿ÏÎ®" ÎºÎ±Î¹ "Î ÏÎ¹Îœ ÏÎ·Îœ ÎÎ¿Î¹ÎœÎ® ÎÏÎ¿ÏÎ®". }
+
+_textstemon_ [l=el] {(Î±Î³ÏÎ·ÏÎµ ÏÎ¹Ï ÎºÎ±ÏÎ±Î»Î®ÎŸÎµÎ¹Ï ÏÏÎœ Î»Î­ÎŸÎµÏÎœ)}
+
+_textsearchhistory_ [l=el] {ÎÏÏÎ¿ÏÎ¹ÎºÏ ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+
+#text macros for search history
+_textnohistory_ [l=el] {Î€Î¿ Î¹ÏÏÎ¿ÏÎ¹ÎºÏ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï ÎŽÎµÎœ ÎµÎ¯ÎœÎ±Î¹ ÎŽÎ¹Î±ÎžÎ­ÏÎ¹ÎŒÎ¿.}
+_texthresult_ [l=el] {Î±ÏÎ¿ÏÎ­Î»ÎµÏÎŒÎ±}
+_texthresults_ [l=el] {Î±ÏÎ¿ÏÎµÎ»Î­ÏÎŒÎ±ÏÎ±}
+_texthallwords_ [l=el] {ÏÎ»ÎµÏ Î¿Î¹ Î»Î­ÎŸÎµÎ¹Ï}
+_texthsomewords_ [l=el] {ÎŒÎµÏÎ¹ÎºÎ­Ï Î»Î­ÎŸÎµÎ¹Ï}
+_texthboolean_ [l=el] {Î§Î±ÏÎ±ÎºÏÎ®ÏÎµÏ boolean}
+_texthranked_ [l=el] {ÏÎ±ÎŸÎ¹ÎœÏÎŒÎ·ÏÎ·}
+_texthcaseon_ [l=el] {ÏÎ±Î¯ÏÎ¹Î±ÏÎŒÎ± ÏÎµÎ¶ÏÎœ- ÎºÎµÏÎ±Î»Î±Î¯ÏÎœ}
+_texthcaseoff_ [l=el] {casefolded}
+_texthstemon_ [l=el] {ÎŒÏÎœÎ¿ ÏÎ¯Î¶Î± Î»Î­ÎŸÎ·Ï}
+_texthstemoff_ [l=el] {unstemmed}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·" ## green_title ## h_search ##
+_httpiconhsearch_ [l=el] {_httpimg_/el/h\_search.gif}
+_widthhsearch_ [l=el] {200}
+_heighthsearch_ [l=el] {57}
+
+## "Î±ÏÎ¿ÏÎµÎ»Î­ÏÎŒÎ±ÏÎ±" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=el] {_httpimg_/el/qryresb.gif}
+_widthqryresb_ [l=el] {_pagewidth_}
+_heightqryresb_ [l=el] {17}
+
+## "Î¹ÏÏÎ¿ÏÎ¹ÎºÏ" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=el] {_httpimg_/el/schhistb.gif}
+_widthsrchhistb_ [l=el] {_pagewidth_}
+_heightsrchhistb_ [l=el] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=el] {ÎÎ¹ ÎµÏÎ¹Î»Î¿Î³Î­Ï Î­ÏÎ¿Ï
+Îœ ÏÏ
+ÎžÎŒÎ¹ÏÏÎµÎ¯ ÏÏ ÎµÎŸÎ®Ï. ÎÎ·Îœ ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ÏÎµ ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ "ÏÎ¯ÏÏ"- ÎžÎ± ÏÎ¹Ï Î±ÏÎ¿ÏÏÏ
+ÎžÎŒÎ¯ÏÎµÎ¹! ÎÎœÏ' Î±Ï
+ÏÎ¿Ï ÏÎ±ÏÎ®ÏÏÎµ Î­ÎœÎ± Î±ÏÏ ÏÎ± ÎºÎ¿Ï
+ÎŒÏÎ¹Î¬ ÏÎ·Ï ÎŒÏÎ¬ÏÎ±Ï ÏÏÏÏÎ²Î±ÏÎ·Ï Î±ÏÏ ÏÎ¬ÎœÏ.
+}
+_textsetprefs_ [l=el] {Î¡ÏÎžÎŒÎ¹ÏÎ· ÎµÏÎ¹Î»Î¿Î³ÏÎœ}
+_textsearchprefs_ [l=el] {ÂšÎÏÎ¹Î»Î¿Î³Î­Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+_textcollectionprefs_ [l=el] {ÎÏÎ¹Î»Î¿Î³Î­Ï Î£Ï
+Î»Î»Î¿Î³Î®Ï}
+_textpresentationprefs_ [l=el] {ÎÏÎ¹Î»Î¿Î³Î­Ï ÏÎ±ÏÎ¿Ï
+ÏÎ¯Î±ÏÎ·Ï}
+_textpreferences_ [l=el] {ÎÏÎ¹Î»Î¿Î³Î­Ï}
+_textcasediffs_ [l=el] {ÎÎ¹Î±ÏÎ¿ÏÎ¬ ÏÎµÎ¶ÏÎœ - ÎºÎµÏÎ±Î»Î±Î¯ÏÎœ:}
+_textignorecase_ [l=el] {Î±Î³ÎœÏÎ·ÏÎµ ÏÎ· ÎŽÎ¹Î±ÏÎ¿ÏÎ¬ ÏÎµÎ¶ÏÎœ -ÎºÎµÏÎ±Î»Î±Î¯ÏÎœ}
+_textmatchcase_ [l=el] {Î ÎµÎ¶Î¬- ÎºÎµÏÎ±Î»Î±Î¯Î± Î³ÏÎ¬ÎŒÎŒÎ±ÏÎ± ÏÏÎ­ÏÎµÎ¹ ÎœÎ± ÏÎ±Î¹ÏÎ¹Î¬Î¶Î¿Ï
+Îœ}
+_textwordends_ [l=el] {ÎºÎ±ÏÎ±Î»Î®ÎŸÎµÎ¹Ï Î»Î­ÎŸÎµÏÎœ:}
+_textstem_ [l=el] {Î±Î³ÎœÏÎ·ÏÎµ ÏÎ¹Ï ÎºÎ±ÏÎ±Î»Î®ÎŸÎµÎ¹Ï ÏÏÎœ Î»Î­ÎŸÎµÏÎœ}
+_textnostem_ [l=el] {ÏÎ±Î¯ÏÎ¹Î±ÏÎŒÎ± Î¿Î»ÏÎºÎ»Î·ÏÎ·Ï ÏÎ·Ï Î»Î­ÎŸÎ·Ï}
+_textprefop_ [l=el] {_maxdocoption_ hits with _hitsperpageoption_ Î±ÏÎ¿ÏÎµÎ»Î­ÏÎŒÎ±ÏÎ± Î±ÎœÎ¬ ÏÎµÎ»Î¯ÎŽÎ±.}
+_textextlink_ [l=el] {Î ÏÏÏÎ²Î±ÏÎ· ÏÎµ ÎµÎŸÏÏÎµÏÎ¹ÎºÎ­Ï ÏÎµÎ»Î¯ÎŽÎµÏ ÏÏÎ¿ Web:}
+_textintlink_ [l=el] {Î ÏÎ·Î³Î® ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ Î­ÏÎµÎ¹ Î±ÎœÎ±ÎºÏÎ·ÎžÎµÎ¯ Î±ÏÏ:}
+_textlanguage_ [l=el] {Î³Î»ÏÏÏÎ± ÎµÏÎ¹ÏÎ¬ÎœÎµÎ¹Î±Ï ÎµÏÎ³Î±ÏÎ¯Î±Ï:}
+_textencoding_ [l=el] {ÎÏÎŽÎ¹ÎºÎ¿ÏÎ¿Î¯Î·ÏÎ·:}
+_textformat_ [l=el] {ÎŠÏÏÎŒÎ± ÎµÏÎ¹ÏÎ¬ÎœÎµÎ¹Î±Ï ÎµÏÎ³Î±ÏÎ¯Î±Ï:}
+_textall_ [l=el] {ÏÎ»Î±}
+_textquerymode_ [l=el] {Î€ÏÏÏÎ¿Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï:}
+_textsimplemode_ [l=el] {Î±ÏÎ»Î® Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·}
+_textadvancedmode_ [l=el] {ÏÏÎœÎžÎµÏÎ¿Ï ÏÏÏÏÎ¿Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï (ÏÎ±Ï ÎµÏÎ¹ÏÏÎ­ÏÎµÎ¹ ÎœÎ± ÎºÎ¬ÎœÎµÏÎµ Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÎ¹Ï ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÏÎœÏÎ±Ï Î»Î¿Î³Î¹ÎºÎ¿ÏÏ ÏÎµÎ»ÎµÏÏÎ­Ï: !, &, |, ÎºÎ±Î¹ ÏÎ±ÏÎ­ÎœÎžÎµÏÎ·)}
+_textlinkinterm_ [l=el] {ÎŒÎ­ÏÏ ÎµÎœÎŽÎ¹Î¬ÎŒÎµÏÎ·Ï ÏÎµÎ»Î¯ÎŽÎ±Ï}
+_textlinkdirect_ [l=el] {ÏÎ®Î³Î±Î¹ÎœÎµ ÎºÎ±ÏÎµÏ
+ÎžÎµÎ¯Î±Îœ ÎµÎºÎµÎ¯}
+_textdigitlib_ [l=el] {Î ÎšÎ·ÏÎ¹Î±ÎºÎ® ÎÎ¹Î²Î»Î¹Î¿ÎžÎ®ÎºÎ·}
+_textweb_ [l=el] {Î ÏÎ¿Ï ÎÏÏÎ¿ÏÎµÎ»Î¯ÎŽÎ±}
+_textgraphical_ [l=el] {ÎÏÎ±ÏÎ¹ÎºÎ¬ }
+_texttextual_ [l=el] {ÎÎ¿ÏÏÎ® ÎºÎµÎ¹ÎŒÎ­ÎœÎ¿Ï
+}
+_textcollectionoption_ [l=el] {<p>
+ÎÎ¹ Ï
+ÏÎ¿ÏÏ
+Î»Î»Î¿Î³Î­Ï ÎœÎ± ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎ¿Ï
+Îœ: 
+<br>}
+
+_textrelateddocdisplay_ [l=el] {ÎÏÎ¯ÎŽÎµÎ¹ÎŸÎ· ÏÏ
+ÎœÎ±ÏÏÎœ ÎµÎ³Î³ÏÎ¬ÏÏÎœ}
+_textsearchhistory_ [l=el] {ÎÏÏÎ¿ÏÎ¹ÎºÏ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï:}
+_textnohistory_ [l=el] {ÎÎµÎœ Ï
+ÏÎ¬ÏÏÎµÎ¹ Î¹ÏÏÎ¿ÏÎ¹ÎºÏ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+_texthistorydisplay_ [l=el] {ÎÏÎ¯ÎŽÎµÎ¹ÎŸÎ· _historynumrecords_ ÏÏÎœ Î±ÏÏÎµÎ¯ÏÎœ Î¹ÏÏÎ¿ÏÎ¹ÎºÎ¿Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+_textnohistorydisplay_ [l=el] {ÎÎ± ÎŒÎ·Îœ ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î¬Î¶ÎµÏÎ±Î¹ ÏÎ¿ Î¹ÏÏÎ¿ÏÎ¹ÎºÏ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=el] {ÎŠÏÏÎŒÎ± Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï:}
+_textplainsearch_ [l=el] {ÎÏÎ»Î® Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·}
+_textqueryboxsize_ [l=el] {ÎÎ­Î³ÎµÎžÎ¿Ï ÎºÎ¿Ï
+ÏÎ¹Î¿Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï:}
+_textregbox_ [l=el] {ÎºÎ±ÎœÎ¿ÎœÎ¹ÎºÏ ÎºÎ¿Ï
+ÏÎ¯ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+_textbigbox_ [l=el] {ÎŒÎµÎ³Î¬Î»Î¿ ÎºÎ¿Ï
+ÏÎ¯ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï}
+_textformtype_ [l=el] {ÎÏÏ ÏÏÏÎ¿:}
+_textsimple_ [l=el] {Î±ÏÎ»Î®}
+_textadvanced_ [l=el] {ÏÏÎœÎžÎµÏÎ¿Ï}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=el] {ÎŒÎµ}
+_textfields_ [l=el] {ÏÎµÎŽÎ¯Î±}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÎµÏÎ¹Î»Î¿Î³Î­Ï" ## green_title ## h_pref ##
+_httpiconhpref_ [l=el] {_httpimg_/el/h\_pref.gif}
+_widthhpref_ [l=el] {200}
+_heighthpref_ [l=el] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=el] {Î€Î±ÎŸÎ¹ÎœÏÎŒÎ·ÏÎ· ÎµÎ³Î³ÏÎ¬ÏÏÎœ Î±ÎœÎ¬}
+_textalsoshowing_ [l=el] {ÎµÎŒÏÎ¬ÎœÎ¹ÏÎ·}
+_textwith_ [l=el] {ÎŒÎµ ÏÎ¹Ï ÏÎµÏÎ¹ÏÏÏÏÎµÏÎµÏ}
+_textdocsperpage_ [l=el] {Î­Î³Î³ÏÎ±ÏÎ± Î±ÎœÎ¬ ÏÎµÎ»Î¯ÎŽÎ±}
+
+_textfilterby_ [l=el] {ÎÏ
+ÏÎµÏÎ· ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+ ÏÎ¿Ï
+ ÎœÎ± ÏÎµÏÎ¹Î­ÏÎµÎ¹}
+_textall_ [l=el] {ÏÎ»Î±}
+_textany_ [l=el] {ÎŒÎµÏÎ¹ÎºÎ¬}
+_textwords_ [l=el] {Î±ÏÏ ÏÎ¹Ï Î»Î­ÎŸÎµÎ¹Ï}
+_textleaveblank_ [l=el] {Î±ÏÎ®ÏÏÎµ Î±Ï
+ÏÏ ÏÎ¿ ÎºÎ¿Ï
+ÏÎ¯ ÎºÎµÎœÏ Î³Î¹Î± ÎœÎ± Î±ÎœÎ±ÎºÏÎ®ÏÎµÏÎµ ÏÎ»Î± ÏÎ± Î­Î³Î³ÏÎ±ÏÎ±}
+
+_browsebuttontext_ [l=el] {"Î€Î±ÎŸÎ¹ÎœÏÎŒÎ·ÏÎ· ÎÎ³Î³ÏÎ¬ÏÏÎœ" }
+
+_nodata_ [l=el] {<i>no data</i>}
+_docs_ [l=el] {Î­Î³Î³ÏÎ±ÏÎ±}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=el] {ÎÎ¿Î®ÎžÎµÎ¹Î±}
+_textSearchshort_ [l=el] {Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· ÎŒÎµ ÏÏ
+Î³ÎºÎµÎºÏÎ¹ÎŒÎ­ÎœÎµÏ Î»Î­ÎŸÎµÎ¹Ï}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÏÎ¯ÏÎ»Î¿}
+_textCreatorshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÏÏ
+Î³Î³ÏÎ±ÏÎ­Î±}
+_textSubjectshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÎžÎ­ÎŒÎ±}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÎŒÎµ ÏÎœÎ¿ÎŒÎ± Î±ÏÏÎµÎ¯Î¿Ï
+}
+_textLanguageshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ Î³Î»ÏÏÏÎ±}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÏÎµÎ¹ÏÎ¬}
+_textToshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± by To field}
+_textFromshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ Î±ÏÎ¿ÏÏÎ¿Î»Î­Î±/ access publications by From field}
+_textBrowseshort_ [l=el] {ÏÎ¬ÏÏÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î±}
+_textOrganizationshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ Î¿ÏÎ³Î±ÎœÎ¹ÏÎŒÏ}
+_textHowtoshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÏÏ ÏÎ¿Îœ ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿ "ÏÏÏ ÎœÎ±"// by "how to" listing}
+_textTopicshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÎžÎµÎŒÎ±ÏÎ¹ÎºÎ® ÎµÎœÏÏÎ·ÏÎ±}
+_textPeopleshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÎŒÎµ Î¿ÎœÏÎŒÎ±ÏÎ± Î±ÎœÎžÏÏÏÏÎœ/ access publications by people}
+_textAcronymshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ Î±ÎºÏÎ¿ÎœÏÎŒÎ¹Î¿}
+_textPhraseshort_ [l=el] {ÏÎ¬ÏÏÏÎ· ÏÏÎ¬ÏÎµÏÎœ ÏÎ¿Ï
+ Ï
+ÏÎ¬ÏÏÎ¿Ï
+Îœ ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î±}
+_textArtistshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÎºÎ±Î»Î»Î¹ÏÎ­ÏÎœÎ·}
+_textKeywordshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÎŒÎµ Î»Î­ÎŸÎµÎ¯Ï-ÎºÎ»ÎµÎ¹ÎŽÎ¹Î¬}
+_textVolumeshort_ [l=el] {ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÏÏÎŒÎ¿}
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=el] {ÎŒÎ· Î¿ÏÎ¹ÏÎŒÎ­ÎœÎ· ÏÎ±ÎŸÎ¹ÎœÏÎŒÎ·ÏÎ·}
+
+_textSearchlong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ <i>ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÏÎµ ÎŒÎµÎŒÎ¿ÎœÏÎŒÎ­ÎœÎµÏ Î»Î­ÎŸÎµÎ¹Ï</i> ÏÎ¿Ï
+ ÎµÎŒÏÎ±ÎœÎ¯Î¶Î¿ÎœÏÎ±Î¹ ÏÏÎ¿ ÎºÎµÎ¯ÎŒÎµÎœÎ¿ Î±ÏÏ ÏÎ· ÏÎµÎ»Î¯ÎŽÎ± 'Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï'. ÎÏ
+ÏÎ® ÎµÎ¯ÎœÎ±Î¹ Î· ÏÏÏÏÎ· ÏÎµÎ»Î¯ÎŽÎ± ÏÎ¿Ï
+ ÎµÎŒÏÎ±ÎœÎ¯Î¶ÎµÏÎ±Î¹ Î±Î»Î»Î¬ ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÎµ Î±Ï
+ÏÎ®Îœ ÎºÎ±Î¹ Î±ÏÏ ÏÎ¹Ï Ï
+ÏÏÎ»Î¿Î¹ÏÎµÏ ÏÎµÎ»Î¯ÎŽÎµÏ ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·</i> .  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=el] {<p>ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± <i>Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÏÎ¯ÏÎ»Î¿</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯
+<i>ÏÎ¯ÏÎ»Î¿Î¹ Î±-Ï</i>.  ÎÎ± ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï Î²Î¹Î²Î»Î¯ÏÎœ ÎŒÎµ Î±Î»ÏÎ±Î²Î·ÏÎ¹ÎºÎ® ÏÎµÎ¹ÏÎ¬.}
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=el] {<p>ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ <i>ÎœÎ± Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÏÏ
+Î³Î³ÏÎ±ÏÎ­Î± </i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÏÏ
+Î³Î³ÏÎ±ÏÎµÎ¹Ï Î±-Ï</i> ÎÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î±ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï Î²Î¹Î²Î»Î¯ÏÎœ ÏÎ±ÎŸÎ¹ÎœÎ¿ÎŒÎ·ÎŒÎ­ÎœÎ¿Ï Î²Î¬ÏÎµÎ¹ ÏÎ¿Ï
+ Î¿ÎœÏÎŒÎ±ÏÎ¿Ï ÏÎ¿Ï
+ ÏÏ
+Î³Î³ÏÎ±ÏÎ­Î±.}
+
+_textSubjectlong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± <i>Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÎžÎ­ÎŒÎ±</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÎžÎ­ÎŒÎ±ÏÎ±</i> .  ÎÎ± ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÎžÎµÎŒÎ¬ÏÏÎœ ÎŒÎµ ÏÎ· ÎŒÎ¿ÏÏÎ® ÏÎ±ÏÎ¹ÏÎœ Î²Î¹Î²Î»Î¹Î¿ÎžÎ®ÎºÎ·Ï.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=el] {<p>ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ <i>ÎœÎ± Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯ÎµÏ</i> .  ÎÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î±ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÏÎµÏ
+ÏÏÎœ ÏÎ±ÎŸÎ¹ÎœÎ¿ÎŒÎ·ÎŒÎ­ÎœÏÎœ ÏÏÎ¿ÎœÎ¿Î»Î¿Î³Î¹ÎºÎ¬.}
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± <i>Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÏÎœÏÎ±Ï Î¿ÎœÏÎŒÎ±ÏÎ± Î±ÏÏÎµÎ¯ÏÎœ</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>Î¿ÎœÏÎŒÎ±ÏÎ± Î±ÏÏÎµÎ¯ÏÎœ</i> .  ÎÎ± ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÎµÎ³Î³ÏÎ±ÏÏÎœ ÏÎ±ÎŸÎ¹ÎœÎ¿ÎŒÎ·ÎŒÎ­ÎœÎ¿Ï Î±ÎœÎ¬ Î±ÏÏÎ¹ÎºÏ (original) ÏÎœÎ¿ÎŒÎ± Î±ÏÏÎµÎ¯Î¿Ï
+.}
+
+_textLanguagelong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ <i>ÎœÎ± Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ Î³Î»ÏÏÏÎ±</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>Î³Î»ÏÏÏÎµÏ</i> .  ÎÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î±ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÎµÎ¹ÏÎ±Î³ÏÎ³ÏÎœ ÏÎ±ÎŸÎ¹ÎœÎ¿ÎŒÎ·ÎŒÎ­ÎœÏÎœ Î±ÎœÎ¬ Î³Î»ÏÏÏÎ±.}
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ <i>ÎœÎ± Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ Î¿ÏÎ³Î±ÎœÎ¹ÏÎŒÏ</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>Î¿ÏÎ³Î±ÎœÎ¹ÏÎŒÎ¿Î¯</i> .  ÎÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î±ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï Î¿ÏÎ³Î±ÎœÎ¹ÏÎŒÏÎœ}
+
+_textHowtolong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± <i>Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÏÏ ÏÎ¿Îœ ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿ "ÏÏÏ ÎœÎ±"/ by "how to" listing</i>
+ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÏÏÏ ÎœÎ±</i> .  ÎÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î±ÏÏÎµÎ¯ ÎŒÎ¹Î± Î»Î¯ÏÏÎ± Î±ÏÏ.../ a list of how to
+strings.  }
+
+_textTopiclong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ±  <i>Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÎžÎµÎŒÎ±ÏÎ¹ÎºÎ® ÎµÎœÏÏÎ·ÏÎ±/ by topic</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÎžÎµÎŒÎ±ÏÎ¹ÎºÎ® ÎµÎœÏÏÎ·ÏÎ±</i> .  ÎÎ± ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÎžÎµÎŒÎ±ÏÎ¹ÎºÏÎœ ÎµÎœÎ¿ÏÎ®ÏÏÎœ ÏÏÎ¹Ï Î¿ÏÎ¿Î¯ÎµÏ ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÎºÎ¬ÎœÎµÏÎµ ÏÎ¬ÏÏÏÎ·.}
+
+_textTolong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± <i>Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± by To field</i> ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>to</i> .ÎÎ± ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï Î±ÏÏÎµÎ¯ÏÎœ.  }
+
+_textFromlong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± <i>Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ Î±ÏÎ¿ÏÏÎ¿Î»Î­Î±</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>Î±ÏÏ</i> .  ÎÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î±ÏÏÎµÎ¯ Î¿ ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÏÏÎœ Î±ÏÎ¿ÏÏÎ¿Î»Î­ÏÎœ.  }
+
+_textSerieslong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± <i>Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÏÎµÎ¹ÏÎ¬/ by series</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÏÎµÎ¹ÏÎ­Ï</i> .  ÎÎ± ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÏÏÎœ ÏÎµÎ¹ÏÏÎœ ÏÎ¿Ï
+ Ï
+ÏÎ¬ÏÏÎ¿Ï
+Îœ Î±Ï
+ÏÎ® ÏÎ· ÏÏÎ¹Î³ÎŒÎ® ÏÏÎ· ÏÏ
+Î»Î»Î¿Î³Î®.}
+
+_textBrowselong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ <i>ÎœÎ± ÎºÎ¬ÎœÎµÏÎµ ÏÎ¬ÏÏÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î±</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯
+<i>ÏÎ¬ÏÏÏÎ·</i>.}
+
+_textPeoplelong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ <i>ÎœÎ± Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÏÎœÏÎ±Ï Î¿ÎœÏÎŒÎ±ÏÎ± Î±ÎœÎžÏÏÏÏÎœ</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>Î¬ÎœÎžÏÏÏÎ¿Î¹</i> .  ÎÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î±ÏÏÎµÎ¯ Î­ÎœÎ±Ï Î±Î»ÏÎ±Î²Î·ÏÎ¹ÎºÏÏ ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÎŒÎµ Î¿ÎœÏÎŒÎ±ÏÎ± Î±ÎœÎžÏÏÏÏÎœ.}
+
+_textAcronymlong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ <i>ÎœÎ± Î­ÏÎµÏÎµ ÏÏÎ¿ÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ Î±ÎºÏÎ¿ÎœÏÎŒÎ¹Î¿</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>Î±ÎºÏÎ¿ÎœÏÎŒÎ¹Î±</i>.  ÎÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î±ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï Î±ÎºÏÎ¿ÎœÏÎŒÎ¹ÏÎœ ÎºÎ±Î¹ ÏÎ¿ ÏÎ·ÎŒÎµÎ¯Î¿ ÏÎ¿Ï
+ Î±Ï
+ÏÎ¬ ÎµÎŒÏÎ±ÎœÎ¯Î¶Î¿ÎœÏÎ±Î¹.  }
+
+_textPhraselong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± <i>ÎºÎ¬ÎœÎµÏÎµ ÏÎ¬ÏÏÏÎ· ÏÎµ ÏÏÎ¬ÏÎµÎ¹Ï ÏÎ¿Ï
+ ÎµÎŒÏÎ±ÎœÎ¯Î¶Î¿ÎœÏÎ±Î¹ ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î±</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÏÏÎ¬ÏÎµÎ¹Ï</i> . ÎÏÏÎ¹ ÎžÎ­ÏÎµÏÎµ ÏÎµ Î»ÎµÎ¹ÏÎ¿Ï
+ÏÎ³Î¯Î± ÏÎ¿Îœ phind phrase browser.  }
+
+_textArtistlong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ <i>ÎœÎ± Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÎºÎ±Î»Î»Î¹ÏÎ­ÏÎœÎ·</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÎºÎ±Î»Î»Î¹ÏÎ­ÏÎœÎµÏ</i> ÎÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î±ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÎµÎ³Î³ÏÎ±ÏÏÎœ ÏÎ±ÎŸÎ¹ÎœÎ¿ÎŒÎ·ÎŒÎ­ÎœÎ¿Ï Î²Î¬ÏÎµÎ¹ ÏÎ¿Ï
+ Î¿ÎœÏÎŒÎ±ÏÎ¿Ï ÏÎ¿Ï
+ ÎºÎ±Î»Î»Î¹ÏÎ­ÏÎœÎ·.  }
+
+_textKeywordlong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ <i>ÎœÎ± Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÏÎœÏÎ±Ï Î»Î­ÎŸÎµÎ¹Ï ÎºÎ»ÎµÎ¹ÎŽÎ¹Î¬</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>Î»Î­ÎŸÎµÎ¹Ï ÎºÎ»ÎµÎ¹ÎŽÎ¹Î¬</i> . ÎÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¹Î±ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÎŒÎµ Î»Î­ÎŸÎµÎ¹Ï ÎºÎ»ÎµÎ¹ÎŽÎ¹Î¬. }
+
+_textVolumelong_ [l=el] {<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± <i>Î­ÏÎµÏÎµ ÏÏÏÏÎ²Î±ÏÎ· ÏÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î±ÎœÎ¬ ÏÏÎŒÎ¿</i> ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÏÏÎŒÎ¿Î¹</i> . ÎÎ± ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎµÎ¯ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï ÏÏÎŒÏÎœ.}
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=el] {<p>Î Î±ÏÎ®ÏÏÎµ ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>Î¬Î³ÎœÏÏÏÎ¿</i> Î³Î¹Î± ÎœÎ± ÎºÎ¬ÎœÎµÏÎµ ÏÎ¬ÏÏÏÎ· ÏÎµ ÎŽÎ·ÎŒÎ¿ÏÎ¹ÎµÏÏÎµÎ¹Ï (Î· ÏÎ±ÎŸÎ¹ÎœÏÎŒÎ·ÏÎ· ÎµÎ¯ÎœÎ±Î¹ Î²Î¬ÏÎµÎ¹ Î¬Î³ÎœÏÏÏÎ¿Ï
+ ÏÎµÎŽÎ¯Î¿Ï
+.}
+
+_texthelptopics_ [l=el] {<h2 align=left>Topics</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Î ÏÏ ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÏÎµ ÏÏ
+Î³ÎºÎµÎºÏÎ¹ÎŒÎ­ÎœÎµÏ Î»Î­ÎŸÎµÎ¹Ï</a>
+<ul>
+  <li><a href="\#query-terms">ÎÏÎ¿Î¹ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï</a>
+  <li><a href="\#query-type">ÎÎ¯ÎŽÎ¿Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï</a>
+  <li><a href="\#scope-of-queries">ÎÏÏÎ¿Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">ÎÏÎ¹Î»Î¿Î³Î­Ï Î£Ï
+Î»Î»Î¿Î³Î®Ï</a>
+  <li><a href="\#lang-prefs">ÎÏÎ¹Î»Î¿Î³Î® Î³Î»ÏÏÏÎ±Ï</a>
+  <li><a href="\#pres-prefs">ÎÏÎ¹Î»Î¿Î³Î­Ï ÏÎ±ÏÎ¿Ï
+ÏÎ¯Î±ÏÎ·Ï</a>
+  <li><a href="\#search-prefs">ÎÏÎ¹Î»Î¿Î³Î­Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=el] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=el] {Î ÏÏ ÎœÎ± ÎŽÎ¹Î±Î²Î¬ÏÎµÏÎµ ÏÎ± Î­Î³Î³ÏÎ±ÏÎ±}
+
+_texthelpreadingdocs_ [l=el] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÎºÎ±ÏÎ±Î»Î¬Î²ÎµÏÎµ ÏÏÏÎµ ÎµÎœÏÎ¿ÏÎ¯ÏÎ±ÏÎµ Î­ÎœÎ± ÏÏ
+Î³ÎºÎµÎºÏÎ¹ÎŒÎ­ÎœÎ¿ Î²Î¹Î²Î»Î¯Î¿ Î® Î­Î³Î³ÏÎ±ÏÎ¿ ÏÏÎ±Îœ ÎŽÎµÎ¯ÏÎµ ÏÎ¿Îœ ÏÎ¯ÏÎ»Î¿ Î® ÏÎ·Îœ ÏÏÏÎ¿Î³ÏÎ±ÏÎ¯Î± ÎµÎŸÏÏÏÎ»Î»Î¿Ï
+ ÏÏÎ¿ ÏÎ¬ÎœÏ Î±ÏÎ¹ÏÏÎµÏÎ¬ ÎŒÎ­ÏÎ¿Ï ÏÎ·Ï ÏÎµÎ»Î¯ÎŽÎ±Ï. Î£Îµ Î¿ÏÎ¹ÏÎŒÎ­ÎœÎµÏ ÏÏ
+Î»Î»Î¿Î³Î­Ï Î±Ï
+ÏÏ ÏÏ
+ÎœÎ¿ÎŽÎµÏÎµÏÎ±Î¹ ÎºÎ±Î¹ Î±ÏÏ Î­ÎœÎ±Îœ ÏÎ¯ÎœÎ±ÎºÎ± ÏÎµÏÎ¹ÎµÏÎ¿ÎŒÎ­ÎœÏÎœ, ÎµÎœÏ Î¬Î»Î»ÎµÏ ÏÎµÏÎ¹Î­ÏÎ¿Ï
+Îœ Î±ÏÎ»ÏÏ ÏÎ¿Îœ Î±ÏÎ¹ÎžÎŒÏ ÏÎ·Ï ÏÏÎ­ÏÎ¿Ï
+ÏÎ±Ï ÏÎµÎ»Î¯ÎŽÎ±Ï ÎŒÎ±Î¶Î¯ ÎŒÎµ Î­ÎœÎ± ÎºÎ¿Ï
+ÏÎ¯ ÏÎ¿Ï
+ ÏÎ±Ï ÎµÏÎ¹ÏÏÎ­ÏÎµÎ¹ ÎœÎ± ÎµÏÎ¹Î»Î­ÎŸÎµÏÎµ ÎœÎ­Î± ÏÎµÎ»Î¯ÎŽÎ± ÎºÎ±Î¹ ÎœÎ± ÏÎ¬ÏÎµ ÎŒÏÏÎ¿ÏÏÎ¬ Î® ÏÎ¯ÏÏ. Î£ÏÎ¿Îœ ÏÎ¯ÎœÎ±ÎºÎ± ÏÎµÏÎ¹ÎµÏÎ¿ÎŒÎ­ÎœÏÎœ, Î· ÎµÎœÏÏÎ·ÏÎ± ÏÏÎ·Îœ Î¿ÏÎ¿Î¯Î± Î²ÏÎ¯ÏÎºÎµÏÏÎµ Ï
+ÏÎ¿ÎŽÎµÎ¹ÎºÎœÏÎµÏÎ±Î¹ ÎŒÎµ Î­ÎœÏÎ¿ÎœÎ± Î³ÏÎ¬ÎŒÎŒÎ±ÏÎ± ÎºÎ±Î¹ Î¿ ÏÎ¯ÎœÎ±ÎºÎ±Ï ÎŒÏÎ¿ÏÎµÎ¯ ÎœÎ± ÎµÏÎµÎºÏÎ±ÎžÎµÎ¯- Î±ÏÎ»ÏÏ ÏÎ±ÏÎ®ÏÏÎµ ÏÎ¬ÎœÏ ÏÏÎ¿Ï
+Ï ÏÎ±ÎºÎ­Î»Î¿Ï
+Ï Î³Î¹Î± ÎœÎ± ÏÎ¿Ï
+Ï Î±ÎœÎ¿Î¯ÎŸÎµÏÎµ Î® ÎœÎ± ÏÎ¿Ï
+Ï ÎºÎ»ÎµÎ¯ÏÎµÏÎµ. Î Î±ÏÎ®ÏÏÎµ ÏÎ¬ÎœÏ ÏÏÎ¿ Î±ÎœÎ¿Î¹ÏÏÏ Î²Î¹Î²Î»Î¯Î¿ ÏÏÎ¿ ÏÎ¬ÎœÏ ÎŒÎ­ÏÎ¿Ï ÏÎ·Ï ÏÎµÎ»Î¯ÎŽÎ±Ï Î³Î¹Î± ÎœÎ± ÏÎ¿ ÎºÎ»ÎµÎ¯ÏÎµÏÎµ.</p>
+
+<p>ÎÏÏ ÎºÎ¬ÏÏ ÎµÎ¯ÎœÎ±Î¹ ÏÎ¿ ÎºÎµÎ¯ÎŒÎµÎœÎ¿ ÏÎ·Ï ÎµÎœÏÏÎ·ÏÎ±Ï ÏÏÎ·Îœ Î¿ÏÎ¿Î¯Î± Î²ÏÎ¯ÏÎºÎµÏÏÎµ. Î£ÏÎ¿ ÏÎ­Î»Î¿Ï ÏÎ¿Ï
+ Ï
+ÏÎ¬ÏÏÎ¿Ï
+Îœ ÎºÎ¿Ï
+ÎŒÏÎ¹Î¬ ÏÎ¿Ï
+ ÎžÎ± ÏÎ±Ï ÏÎ¬ÎœÎµ ÏÏÎ·Îœ ÎµÏÏÎŒÎµÎœÎ· ÎµÎœÏÏÎ·ÏÎ± Î® ÏÎ¯ÏÏ ÏÏÎ·Îœ ÏÏÎ¿Î·Î³Î¿ÏÎŒÎµÎœÎ·.</p>
+
+<p>ÎÎ¬ÏÏ Î±ÏÏ ÏÎ¿Îœ ÏÎ¯ÏÎ»Î¿ Î® ÏÎ¿ ÎµÎŸÏÏÏ
+Î»Î¿ Ï
+ÏÎ¬ÏÏÎ¿Ï
+Îœ ÎŒÎµÏÎ¹ÎºÎ¬ ÎºÎ¿Ï
+ÎŒÏÎ¹Î¬. Î Î±ÏÎ®ÏÏÎµ ÏÎ¬ÎœÏ ÏÏÎ¿
+<i>Î±ÎœÎ¬ÏÏÏ
+ÎŸÎµ ÎºÎµÎ¯ÎŒÎµÎœÎ¿</i> ÏÏÎ¿ÎºÎµÎ¹ÎŒÎ­ÎœÎ¿Ï
+ ÎœÎ± Î±ÎœÎ±ÏÏÏÎŸÎµÏÎµ ÏÎ»Î¿ ÏÎ¿ ÎºÎµÎ¯ÎŒÎµÎœÎ¿ ÏÎ·Ï ÏÏÎ­ÏÎ¿Ï
+ÏÎ±Ï ÎµÎœÏÏÎ·ÏÎ±Ï Î® ÏÎ¿Ï
+ Î²Î¹Î²Î»Î¯Î¿Ï
+. ÎÎœ ÏÎ¿ Î­Î³Î³ÏÎ±ÏÎ¿ ÎµÎ¯ÎœÎ±Î¹ ÎŒÎµÎ³Î¬Î»Î¿, Î±Ï
+ÏÏ ÎžÎ± ÏÎ¬ÏÎµÎ¹ ÏÎ¿Î»Ï ÏÏÎ± ÎºÎ±Î¹ ÎœÎ± ÏÏÎµÎ¹Î±ÏÏÎµÎ¯ ÏÎ¿Î»Ï ÎŒÎœÎ®ÎŒÎ·! Î Î±ÏÎ®ÏÏÎµ ÏÎ¬ÎœÏ ÏÏÎ¿ <i>Î±ÎœÎ¬ÏÏÏ
+ÎŸÎµ ÏÎµÏÎ¹ÎµÏÏÎŒÎµÎœÎ±</i> Î³Î¹Î± ÎœÎ± Î±ÎœÎ±ÏÏÏÎŸÎµÏÎµ ÏÎ»Î¿Îœ ÏÎ¿Îœ ÏÎ¯ÎœÎ±ÎºÎ± ÏÎµÏÎ¹ÎµÏÎ¿ÎŒÎ­ÎœÏÎœ Î­ÏÏÎ¹ ÏÏÏÎµ ÎœÎ± ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÎŽÎµÎ¯ÏÎµ ÏÎ»Î¿Ï
+Ï ÏÎ¿Ï
+Ï ÏÎ¯ÏÎ»Î¿Ï
+Ï ÏÏÎœ ÎºÎµÏÎ±Î»Î±Î¯ÏÎœ ÎºÎ±Î¹ Ï
+ÏÎ¿ÎºÎµÏÎ±Î»Î±Î¯ÏÎœ. Î Î±ÏÎ®ÏÏÎµ ÏÎ¬ÎœÏ ÏÏÎ¿ <i>Î±ÏÏÏÏÎ±ÏÎµ</i> Î³Î¹Î± ÎœÎ± Î±ÎœÎ¿Î¯ÎŸÎµÏÎµ Î­ÎœÎ± ÎœÎ­Î¿ ÏÎ±ÏÎ¬ÎžÏ
+ÏÎ¿ Î³Î¹Î± ÏÎ¿ Î­Î³Î³ÏÎ±ÏÎ¿. (ÎÏ
+ÏÏ ÎµÎ¯ÎœÎ±Î¹ Î¹ÎŽÎ¹Î±Î¹ÏÎ­ÏÏÏ ÏÏÎ®ÏÎ¹ÎŒÎ¿ ÏÏÎ±Îœ ÎžÎ­Î»ÎµÏÎµ ÎœÎ± ÏÏ
+Î³ÎºÏÎ¯ÎœÎµÏÎµ Î­Î³Î³ÏÎ±ÏÎ±, Î® ÎœÎ± ÎŽÎ¹Î±Î²Î¬ÏÎµÏÎµ ÎŽÏÎ¿ ÎŒÎ±Î¶Î¯). Î€Î­Î»Î¿Ï, ÏÏÎ±Îœ ÎºÎ¬ÎœÎµÏÎµ ÎŒÎ¹Î± Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·, Î¿Î¹ ÏÏÎ¿Î¹ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ®Ï ÏÎ±Ï ÎµÏÎ¹ÏÎ·ÎŒÎ±Î¯ÎœÎ¿ÎœÏÎ±Î¹ ÎŒÎµ Î­ÎœÏÎ¿ÎœÎ· Î³ÏÎ±ÏÎ®. Î Î±ÏÎ®ÏÏÎµ ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÏÏÏÎ¯Ï ÎµÏÎ¹ÏÎ®ÎŒÎ±ÎœÏÎ·</i> Î³Î¹Î± ÎœÎ± Î±ÏÎµÏÎµÎžÎµÎ¯ Î· ÎµÏÎ¹ÏÎ®ÎŒÎ±ÎœÏÎ·.</p>
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Open this bookshelf</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Open/close this book</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>View this section of the text</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Display all text, or not</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Expand table of contents, or not</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Click the arrow to go to the next section ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... or back to the previous section</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=el] {<h2>Î ÏÏ ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÏÎµ ÏÏ
+Î³ÎºÎµÎºÏÎ¹ÎŒÎ­ÎœÎµÏ Î»Î­ÎŸÎµÎ¹Ï</h2>
+<p>
+  ÎÏÏ ÏÎ· ÏÎµÎ»Î¯ÎŽÎ± Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï, ÎºÎ¬ÎœÎµÏÎµ ÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· ÎŒÎµ ÏÎ± ÎµÎŸÎ®Ï Î±ÏÎ»Î¬ Î²Î®ÎŒÎ±ÏÎ±:<p>
+  
+  <ol><li>ÎÎ±ÎžÎ¿ÏÎ¯ÏÏÎµ ÏÎ± ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÏÎ¿Ï
+ ÎžÎ­Î»ÎµÏÎµ ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ·ÎžÎ¿ÏÎœ
+      <li>ÎÏÎ¹Î»Î­ÎŸÏÎµ Î±Îœ ÎžÎ­Î»ÎµÏÎµ ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ·ÎžÎ¿ÏÎœ ÏÎ»ÎµÏ Î® ÎŒÎµÏÎ¹ÎºÎ­Ï Î±ÏÏ ÏÎ¹Ï Î»Î­ÎŸÎµÎ¹Ï ÏÎ¿Ï
+ ÎžÎ± Î¿ÏÎ¯ÏÎµÏÎµ
+      <li>Î Î»Î·ÎºÏÎ¿Î»Î¿Î³Î®ÏÏÎµ ÏÎ¹Ï Î»Î­ÎŸÎµÎ¹Ï ÏÎ¿Ï
+ ÎžÎ­Î»ÎµÏÎµ ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÏÎµ
+      <li>Î Î±ÏÎ®ÏÏÎµ ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ·</i> 
+  </ol>
+
+<p>ÎÏÎ±Îœ ÎºÎ¬ÎœÎµÏÎµ ÎŒÎ¹Î± Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·, ÎžÎ± ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎ¿ÏÎœ ÎµÎ¯ÎºÎ¿ÏÎ¹ ÏÎ¯ÏÎ»Î¿Î¹ ÎµÎ³Î³ÏÎ¬ÏÏÎœ ÏÎ¿Ï
+ ÏÎ±Î¹ÏÎ¹Î¬Î¶Î¿Ï
+Îœ ÏÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·. Î¥ÏÎ¬ÏÏÎµÎ¹ Î­ÎœÎ± ÎºÎ¿Ï
+ÎŒÏÎ¯ ÏÏÎ¿ ÏÎ­Î»Î¿Ï ÏÎ¿Ï
+ ÎºÎ±ÏÎ±Î»ÏÎ³Î¿Ï
+ ÏÎ¿Ï
+ ÎžÎ± ÏÎ±Ï ÏÎ¬ÎµÎ¹ ÏÏÎ± ÎµÏÏÎŒÎµÎœÎ± ÎµÎ¯ÎºÎ¿ÏÎ¹ Î­Î³Î³ÏÎ±ÏÎ±. ÎÏÏ ÎµÎºÎµÎ¯ ÎžÎ± Î²ÏÎµÎ¯ÏÎµ ÎºÎ¿Ï
+ÎŒÏÎ¹Î¬ ÏÎ¿Ï
+ ÎžÎ± ÏÎ±Ï ÏÎ¬ÎœÎµ ÎºÎ±Î¹ ÏÏÎ± ÎµÏÏÎŒÎµÎœÎ± Î® ÏÎ± ÏÏÎ¿Î·Î³Î¿ÏÎŒÎµÎœÎ± ÎµÎ¯ÎºÎ¿ÏÎ¹. Î Î±ÏÎ®ÏÏÎµ ÏÎ¬ÎœÏ ÏÏÎ¿Îœ ÏÎ¯ÏÎ»Î¿ Î¿ÏÎ¿Î¹Î¿Ï
+ÎŽÎ®ÏÎ¿ÏÎµ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+, Î® ÏÏÎ¿ ÎŒÎ¹ÎºÏÏ ÎºÎ¿Ï
+ÏÎ¬ÎºÎ¹ ÎŽÎ¯ÏÎ»Î± ÏÎ¿Ï
+, Î³Î¹Î± ÎœÎ± ÏÎ¿ Î±ÎœÎ¿Î¯ÎŸÎµÏÎµ.
+
+<p>Î ÎŒÎ­Î³Î¹ÏÏÎ¿Ï Î±ÏÎ¹ÎžÎŒÏÏ ÎµÎ³Î³ÏÎ¬ÏÏÎœ ÏÎ¿Ï
+ ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÏÎ¬ÏÎµÏÎµ ÏÏ Î±ÏÎ¿ÏÎ­Î»ÎµÏÎŒÎ± ÎµÎ¯ÎœÎ±Î¹, ÏÏÎŒÏÏÎœÎ± ÎŒÎµ ÏÎ¹Ï ÏÏÎ¿ÎµÏÎ¹Î»Î¿Î³Î­Ï, 100. ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± Î±Î»Î»Î¬ÎŸÎµÏÎµ Î±Ï
+ÏÏÎœ ÏÎ¿Îœ Î±ÏÎ¹ÎžÎŒÏ ÏÎ±ÏÏÎœÏÎ±Ï ÏÎ¬ÎœÏ ÏÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÎµÏÎ¹Î»Î¿Î³Î­Ï</i> ÏÏÎ¿ ÏÎ¬ÎœÏ ÎŒÎ­ÏÎ¿Ï ÏÎ·Ï ÏÎµÎ»Î¯ÎŽÎ±Ï.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>ÏÏÎ¿Î¹ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï</h3>
+
+<p>ÎÏÎ¹ÎŽÎ®ÏÎ¿ÏÎµ ÏÎ»Î·ÎºÏÏÎ¿Î»Î¿Î³ÎµÎ¯ÏÎ±Î¹ ÎŒÎ­ÏÎ± ÏÏÎ¿ ÎºÎ¿Ï
+ÏÎ¯ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï ÎµÎºÎ»Î±ÎŒÎ²Î¬ÎœÎµÏÎ±Î¹ ÏÏ Î­ÎœÎ±Ï ÎºÎ±ÏÎ¬Î»Î¿Î³Î¿Ï Î»Î­ÎŸÎµÏÎœ ÏÎ¿Ï
+ Î¿ÎœÎ¿ÎŒÎ¬Î¶ÎµÏÎ±Î¹ "ÏÏÎ¿Î¹ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï". ÎÎ¬ÎžÎµ ÏÎµÎºÎŒÎ®ÏÎ¹Î¿ ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎµÎ¹ ÎŒÏÎœÎ¿ Î±Î»ÏÎ±Î²Î·ÏÎ¹ÎºÎ¿ÏÏ ÏÎ±ÏÎ±ÎºÏÎ®ÏÎµÏ ÎºÎ±Î¹ ÏÎ·ÏÎ¯Î±. ÎÎ¹ ÏÏÎ¿Î¹ ÎŽÎ¹Î±ÏÏÏÎ¯Î¶Î¿ÎœÏÎ±Î¹ ÎŒÎµÏÎ±ÎŸÏ ÏÎ¿Ï
+Ï Î±ÏÏ Î»ÎµÏ
+ÎºÏ ÎºÎµÎœÏ. ÎÏÎ¿Î¹Î¿ÏÎŽÎ®ÏÎ¿ÏÎµ Î¬Î»Î»Î¿Ï ÏÎ±ÏÎ±ÎºÏÎ®ÏÎ±Ï ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎµÎ¯, Ï.Ï., ÏÎ·ÎŒÎµÎ¯Î± ÏÏÎ¯ÎŸÎ·Ï, ÎµÎŸÏ
+ÏÎ·ÏÎµÏÎ¿ÏÎœ Î±ÏÎ»ÏÏ ÏÎ¿Îœ ÎŽÎ¹Î±ÏÏÏÎ¹ÏÎŒÏ ÏÏÎœ Î»Î­ÎŸÎµÏÎœ, Î±ÎºÏÎ¹Î²ÏÏ ÏÎ± ÎœÎ± Î®ÏÎ±Îœ ÎºÎµÎœÎ¬. ÎÎ±Î¹ ÎŒÎµÏÎ¬ Î±Î³ÎœÎ¿Î¿ÏÎœÏÎ±Î¹. ÎÎµÎœ ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÏÎµ ÏÏÎ¿Ï
+Ï ÏÎ¿Ï
+ ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎ¿Ï
+Îœ ÏÎ·ÎŒÎµÎ¯Î± ÏÏÎ¯ÎŸÎ·Ï.
+
+<p>ÎÎ¹Î± ÏÎ±ÏÎ¬ÎŽÎµÎ¹Î³ÎŒÎ±, Î· Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·<p>
+      <ul><kbd>Î¡Î®Î³Î±Ï ÎÎµÎ»ÎµÏÏÎ¹ÎœÎ»Î®Ï: Î ÎÎ¿ÏÏÎ¹Î¿Ï (1821)</kbd></ul>
+      <p>ÎžÎ± Î±ÎœÏÎ¹ÎŒÎµÏÏÏÎ¹ÏÏÎµÎ¯ ÏÎ¿ Î¯ÎŽÎ¹Î¿, ÏÎ±Îœ ÎœÎ± Î­Î»ÎµÎ³Îµ<p>
+      <ul><kbd>Î¡Î®Î³Î±Ï ÎÎµÎ»ÎµÏÏÎ¹ÎœÎ»Î®Ï Î ÎÎ¿ÏÏÎ¹Î¿Ï 1821</kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>ÎÎ¯ÎŽÎ¿Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï</h3>
+
+<p>Î¥ÏÎ¬ÏÏÎ¿Ï
+Îœ ÎŽÏÎ¿ ÎŽÎ¹Î±ÏÎ¿ÏÎµÏÎ¹ÎºÎ¬ ÎµÎ¯ÎŽÎ· Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï.
+
+<ul>
+  <li>ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ· Î³Î¹Î± <b>ÏÎ»ÎµÏ</b> ÏÎ¹Ï Î»Î­ÎŸÎµÎ¹Ï.  ÎÏ
+ÏÎ® ÎžÎ± Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÎ¹ ÏÎµÎºÎŒÎ®ÏÎ¹Î± (Î® ÎºÎµÏÎ¬Î»Î±Î¹Î± Î® ÏÎ¯ÏÎ»Î¿Ï
+Ï) ÏÎ¿Ï
+ ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎ¿Ï
+Îœ ÎÎÎÎ£ ÏÎ¹Ï Î»Î­ÎŸÎµÎ¹Ï ÏÎ¿Ï
+ Î­ÏÎµÏÎµ Î¿ÏÎ¯ÏÎµÎ¹. Î€Î± ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÏÎ¿Ï
+ Î¹ÎºÎ±ÎœÎ¿ÏÎ¿Î¹Î¿ÏÎœ ÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· ÎµÎŒÏÎ±ÎœÎ¯Î¶Î¿ÎœÏÎ±Î¹ ÏÎµ Î±Î»ÏÎ±Î²Î·ÏÎ¹ÎºÎ® ÏÎµÎ¹ÏÎ¬.<p>
+
+  <li>ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ· Î³Î¹Î± <b>ÎŒÎµÏÎ¹ÎºÎ­Ï</b> Î±ÏÏ ÏÎ¹Ï Î»Î­ÎŸÎµÎ¹Ï.  ÎÏÎ»ÏÏ ÏÎ±ÏÎ±ÎžÎ­ÏÏÎµ ÎŒÎµÏÎ¹ÎºÎ¿ÏÏ ÏÏÎ¿Ï
+Ï ÏÎ¿Ï
+ ÎµÎ¯ÎœÎ±Î¹ ÏÎ¹ÎžÎ±ÎœÏ ÎœÎ± ÎµÎŒÏÎ±ÎœÎ¯Î¶Î¿ÎœÏÎ±Î¹ ÏÏÎ± Î­Î³Î³ÏÎ±ÏÎ± ÏÎ¿Ï
+ Î±ÎœÎ±Î¶Î·ÏÎ¬ÏÎµ. Î€Î± Î­Î³Î³ÏÎ±ÏÎ± ÎžÎ± ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎ¿ÏÎœ ÏÎ±ÎŸÎ¹ÎœÎ¿ÎŒÎ·ÎŒÎ­ÎœÎ± Î±ÎœÎ¬Î»Î¿Î³Î± ÎŒÎµ ÏÎ¿ ÏÏÏÎ¿ Î¹ÎºÎ±ÎœÎ¿ÏÎ¿Î¹Î¿ÏÎœ ÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·. Î€Î¿ ÎºÎ±ÏÎ¬ ÏÏÏÎ¿ Î­ÎœÎ± Î­Î³Î³ÏÎ±ÏÎ¿ ÏÎ±Î¹ÏÎ¹Î¬Î¶ÎµÎ¹ ÏÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ® ÏÎ±Ï Î¿ÏÎ¯Î¶ÎµÏÎ±Î¹ ÎŒÎµ Î²Î¬ÏÎµÎ¹ ÏÎ± ÏÎ±ÏÎ±ÎºÎ¬ÏÏ ÎºÏÎ¹ÏÎ®ÏÎ¹Î±:
+
+      <p><ul>
+        <li> ÏÏÎ¿ ÏÎµÏÎ¹ÏÏÏÏÎµÏÎ¿Î¹ Î±ÏÏ ÏÎ¿Ï
+Ï ÏÏÎ¿Ï
+Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎ¿ÎœÏÎ±Î¹ ÏÎµ Î­ÎœÎ± Î­Î³Î³ÏÎ±ÏÎ¿, ÏÏÏÎ¿ ÏÎµÏÎ¹ÏÏÏÏÎµÏÎ¿ Î±Ï
+ÏÏ ÏÎ±Î¹ÏÎ¹Î¬Î¶ÎµÎ¹.
+        <li> Î¿Î¹ ÏÏÎ±ÎœÎ¹ÏÏÎµÏÎ¿Î¹ ÏÏÎ¿Î¹ ÎµÎ¯ÎœÎ±Î¹ ÏÎ¹Î¿ ÏÎ·ÎŒÎ±ÎœÏÎ¹ÎºÎ¿Î¯ Î±ÏÏ ÏÎ¿Ï
+Ï ÎºÎ¿Î¹ÎœÎ¿ÏÏ.
+        <li> ÏÎ± ÎŒÎ¹ÎºÏÎ¬ Î­Î³Î³ÏÎ±ÏÎ± ÎžÎµÏÏÎµÎ¯ÏÎ±Î¹ ÏÏÎ¹ ÏÎ±Î¹ÏÎ¹Î¬Î¶Î¿Ï
+Îœ ÎºÎ±Î»ÏÏÎµÏÎ± Î±ÏÏ ÏÎ± ÎŒÎµÎ³Î¬Î»Î±.
+      </ul>
+</ul>
+
+<p>Î§ÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ÏÏÎµ ÏÏÎ¿ ÏÎµÏÎ¹ÏÏÏÏÎµÏÎ¿Ï
+Ï ÏÏÎ¿Ï
+Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï ÎžÎ­Î»ÎµÏÎµ, ÎŒÎ¹Î± Î¿Î»ÏÎºÎ»Î·ÏÎ· ÏÏÏÏÎ±ÏÎ·, Î±ÎºÏÎŒÎ± ÎºÎ±Î¹ ÏÎ±ÏÎ¬Î³ÏÎ±ÏÎ¿. ÎÎœ Î¿ÏÎ¯ÏÎµÏÎµ ÎŒÏÎœÎ¿ Î­ÎœÎ±Îœ ÏÏÎ¿ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï, ÏÎ± Î­Î³Î³ÏÎ±ÏÎ± ÎžÎ± ÏÎ±ÎŸÎ¹ÎœÎ¿ÎŒÎ·ÎžÎ¿ÏÎœ Î±ÎœÎ¬Î»Î¿Î³Î± ÎŒÎµ ÏÎ¿ ÏÏÏÎ¿ ÏÏ
+ÏÎœÎ¬ Î±Ï
+ÏÏÏ Î¿ ÏÏÎ¿Ï ÎµÎŒÏÎ±ÎœÎ¯Î¶ÎµÏÎ±Î¹.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=el] {ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ· ÎŒÎµ ÎÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯ÎµÏ}
+
+_texthelpdatesearch_ [l=el] {<h2>_textdatesearch_</h2>
+Î Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· Î²Î¬ÏÎµÎ¹ Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±Ï, ÏÎ±Ï ÎµÏÎ¹ÏÏÎ­ÏÎµÎ¹ ÎœÎ± Î²ÏÎµÎ¯ÏÎµ ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÏÎ¿Ï
+ ÏÎ±Î¹ÏÎ¹Î¬Î¶Î¿Ï
+Îœ ÎŒÎµ ÏÎ¿Ï
+Ï ÏÏÎ¿Ï
+Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï ÏÎ¿Ï
+ ÎžÎ­ÏÎ±ÏÎµ ÎºÎ±Î¹ ÏÎ±ÏÎ¬Î»Î»Î·Î»Î±, Î±ÏÎ¿ÏÎ¿ÏÎœ Î³ÎµÎ³Î¿ÎœÏÏÎ± ÏÎ¿Ï
+ Î­Î»Î±Î²Î±Îœ ÏÏÏÎ± ÏÎµ ÏÏ
+Î³ÎºÎµÎºÏÎ¹ÎŒÎ­ÎœÎ¿ ÏÏÎ¿ÎœÎ¹ÎºÏ ÎŽÎ¹Î¬ÏÏÎ·ÎŒÎ±. ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÏÎµ ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÎµÎ¯ÏÎµ Î³Î¹Î± Î­ÎœÎ± ÏÏ
+Î³ÎºÎµÎºÏÎ¹ÎŒÎ­ÎœÎ¿ Î­ÏÎ¿Ï ÎµÎ¯ÏÎµ Î³Î¹Î± ÎŒÎ¹Î± ÏÏÎ¿ÎœÎ¹ÎºÎ® ÏÎµÏÎ¯Î¿ÎŽÎ¿. ÎÎ± ÏÎ·ÎŒÎµÎ¹ÏÏÎ¿Ï
+ÎŒÎµ ÏÏÎ¹ ÎŽÎµÎœ ÏÏÎµÎ¹Î¬Î¶ÎµÏÎ±Î¹ ÎœÎ± Î­ÏÎµÏÎµ ÎžÎ­ÏÎµÎ¹ Î¬Î»Î»Î¿Ï
+Ï ÏÏÎ¿Ï
+Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï -- ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÏÎ¬ÎŸÎµÏÎµ ÎŒÏÎœÎ¿ ÎŒÎµ Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±. ÎÏÎ¯ÏÎ·Ï, ÏÏÎ¹ ÎŽÎµÎœ ÏÏÎµÎ¹Î¬Î¶ÎµÏÎ±Î¹ ÎœÎ± ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ÏÎµÏÎµ Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯ÎµÏ ÏÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ® ÏÎ±Ï - Î±Îœ ÎŽÎµÎœ ÏÎ»Î·ÎºÏÏÎ¿Î»Î¿Î³Î®ÏÎµÏÎµ ÎºÎ±ÎžÏÎ»Î¿Ï
+ Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î± ÎµÎ¯ÎœÎ±Î¹ ÏÎ¿ Î¯ÎŽÎ¹Î¿ ÏÎ±Îœ ÎœÎ± ÎŒÎ·Îœ Ï
+ÏÎ®ÏÏÎµ Î· Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· Î²Î¬ÏÎµÎ¹ Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±Ï.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>Î ÏÏ ÎœÎ± ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ÏÎµÏÎµ Î±Ï
+ÏÎ® ÏÎ·Îœ ÎµÏÎ¹Î»Î¿Î³Î®:</h3>
+<ul>
+   <li>ÎÎ¹Î± ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÏÎµ ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î³Î¹Î± Î­ÎœÎ± ÏÏ
+Î³ÎºÎµÎºÏÎ¹ÎŒÎ­ÎœÎ¿ Î­ÏÎ¿Ï:<p>
+   <ul>
+       <li>Î Î»Î·ÎºÏÏÎ¿Î»Î¿Î³Î®ÏÏÎµ Î¿ÏÎ¿Î¹Î¿ÎœÎŽÎ®ÏÎ¿ÏÎµ ÏÏÎ¿ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï ÎžÎ­Î»ÎµÏÎµ ÎœÎ± ÎžÎ­ÏÎµÏÎµ. 
+       <li>Î Î»Î·ÎºÏÏÎ¿Î»Î¿Î³Î®ÏÏÎµ ÏÎ¿ Î­ÏÎ¿Ï ÏÎ¿Ï
+ ÎžÎ­Î»ÎµÏÎµ ÎŒÎ­ÏÎ± ÏÏÎ¿ ÎºÎ¿Ï
+ÏÎ¯ "ÎÏÏÎ¹ÎºÎ® Î® ÎŒÎ¿ÎœÎ±ÎŽÎ¹ÎºÎ® Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±".
+       <li>ÎÎœ Î· Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î± ÏÎ¿Ï
+ Î±ÎœÎ±Î¶Î·ÏÎ¬ÏÎµ ÎµÎ¯ÎœÎ±Î¹ ÏÏÎ¿ Î§ÏÎ¹ÏÏÎ¿Ï, ÎµÏÎ¹Î»Î­ÎŸÏÎµ ÏÎ·Îœ ÎµÏÎ¹Î»Î¿Î³Î® "Ï.Î§."Î±ÏÏ ÏÎ¿ ÎŒÎµÎœÎ¿Ï ÎµÏÎ¹Î»Î¿Î³ÏÎœ ÎŽÎ¯ÏÎ»Î± ÏÏÎ¿ ÎºÎ¿Ï
+ÏÎ¯.        <li>ÎÎµÎºÎ¹ÎœÎ®ÏÏÎµ ÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ® ÏÎ±Ï ÏÏÏÏ ÎžÎ± ÎºÎ¬ÎœÎ±ÏÎµ ÎºÎ±ÎœÎ¿ÎœÎ¹ÎºÎ¬.
+   </ul>
+<p><li>ÎÎ¹Î± ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÏÎµ Î­Î³ÏÎ±ÏÎ± Î³Î¹Î± ÎŒÎ¹Î± ÏÎµÏÎ¯Î¿ÎŽÎ¿ Î® ÎŒÎ¹Î± Î±ÎºÏÎ¯ÎœÎ± ÎµÏÏÎœ:<p>
+   <ul>
+       <li>Î Î»Î·ÎºÏÏÎ¿Î»Î¿Î³Î®ÏÏÎµ Î¿ÏÎ¿Î¹Î¿ÎœÎŽÎ®ÏÎ¿ÏÎµ ÏÏÎ¿ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï ÎžÎ­Î»ÎµÏÎµ ÎœÎ± ÎžÎ­ÏÎµÏÎµ.
+       <li>Î Î»Î·ÎºÏÏÎ¿Î»Î¿Î³Î®ÏÏÎµ ÏÎ·Îœ ÏÎ±Î»Î±Î¹ÏÏÎµÏÎ· Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î± ÏÏÎ¿ ÎºÎ¿Ï
+ÏÎ¯ "ÎÏÏÎ¹ÎºÎ® (Î® ÎŒÎ¿ÎœÎ±ÎŽÎ¹ÎºÎ®) ÎÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±" /"ÎÎœÎ±ÏÎŸÎ· Î ÎµÏÎ¹ÏÎŽÎ¿Ï
+ Î® Î£Ï
+Î³ÎºÎµÎºÏÎ¹ÎŒÎ­ÎœÎ¿ ÎÏÎ¿Ï"/ "Start (or only) date".
+       <li>Î Î»Î·ÎºÏÏÎ¿Î»Î¿Î³Î®ÏÏÎµ ÏÎ·Îœ ÏÎ¹Î¿ ÏÏÏÏÏÎ±ÏÎ· Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î± ÏÏÎ¿ ÎºÎ¿Ï
+ÏÎ¯ "Î€ÎµÎ»Î¹ÎºÎ® Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î±".
+       <li>ÎÏÎ¹Î»Î­ÎŸÏÎµ ÏÎ·Îœ ÎµÏÎ¹Î»Î¿Î³Î® "Ï.Î§." Î³Î¹Î± Î¿ÏÎ¿Î¹Î±ÎŽÎ®ÏÎ¿ÏÎµ Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯Î± ÎµÎ¯ÎœÎ±Î¹ ÏÏÎ¿ Î§ÏÎ¹ÏÏÎ¿Ï Î±ÏÏ ÏÎ¿ ÎŒÎµÎœÎ¿Ï ÎµÏÎ¹Î»Î¿Î³ÏÎœ ÎŽÎ¯ÏÎ»Î± Î±ÏÏ ÏÎ¿ ÎºÎ¿Ï
+ÏÎ¯ (ÎÎœÎ±Î»Î»Î±ÎºÏÎ¹ÎºÎ¬ ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ÏÎµÏÎ±Î¹ ÏÎ·Îœ ÎµÏÎ¹Î»Î¿Î³Î® "Î.Î."(ÎÎ¿Î¹ÎœÎ® ÎÏÎ¿ÏÎ®), Î±ÎœÏÎ¯ ÏÎ¿Ï
+ ÎŒ.Î§. ÎºÎ±Î¹ Î .Î.Î. Î³Î¹Î± ÏÎ·Îœ ÎµÏÎ¹Î»Î¿Î³Î® Ï.Î§.).
+       <li>ÎÎµÎºÎ¹ÎœÎ®ÏÏÎµ ÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ® ÏÎ±Ï ÏÏÏÏ ÎžÎ± ÎºÎ¬ÎœÎ±ÏÎµ ÎºÎ±ÎœÎ¿ÎœÎ¹ÎºÎ¬.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>Î ÏÏ ÎµÎŒÏÎ±ÎœÎ¯Î¶Î¿ÎœÏÎ±Î¹ ÏÎ± Î±ÏÎ¿ÏÎµÎ»Î­ÏÎŒÎ±ÏÎ± ÏÎ·Ï Î­ÏÎµÏ
+ÎœÎ¬Ï ÏÎ±Ï</h3>
+
+ÎÎµÎœÎ¹ÎºÎ¬, Î· Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· Î³Î¹Î± ÏÎµÎºÎŒÎ®ÏÎ¹Î± Î²Î¬ÏÎµÎ¹ Î­ÏÎ¿Ï
+Ï Ï.Ï. 1903, ÎŽÎµÎœ ÎžÎ± ÏÎ±Ï ÎµÎŒÏÎ±ÎœÎ¯ÏÎµÎ¹ ÏÎµÎºÎŒÎ®ÏÎ¹Î± ÏÎ¿Ï
+ Î±ÏÎ¿ÏÎ¿ÏÎœ, Î³Î¹Î± ÏÎ±ÏÎ¬ÎŽÎµÎ¹Î³ÎŒÎ±, Î²Î¹Î²Î»Î¯Î± Î±ÎœÎ±ÏÎ¿ÏÏÎœ ÏÎ¿Ï
+ Î³ÏÎ¬ÏÏÎ·ÎºÎ±Îœ ÏÎ¿1903, Î±Î»Î»Î¬ Î­Î³Î³ÏÎ±ÏÎ± ÏÏÎµÏÎ¹ÎºÎ¬ ÎŒÎµ ÏÎ¿ 1903. ÎÏÎ¹ÏÎ»Î­Î¿Îœ, ÎžÎ± ÏÎ±Ï ÎµÎŒÏÎ±ÎœÎ¹ÏÏÎ¿ÏÎœ Î­Î³Î³ÏÎ±ÏÎ± ÏÎ¿Ï
+ Î±ÏÎ¿ÏÎ¿ÏÎœ ÎŒÎ¹Î± ÏÏÎ¿ÎœÎ¹ÎºÎ® ÏÎµÏÎ¯Î¿ÎŽÎ¿ (Ï.Ï. 1899-1911) ÏÎ¿Ï
+ ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎµÎ¹ ÏÎ¿ Î­ÏÎ¿Ï 1903, ÎºÎ±Î¹ ÎµÏÎ¯ÏÎ·Ï Î­Î³Î³ÏÎ±ÏÎ± ÏÎ¿Ï
+ ÎŒÎ­ÏÎ± ÏÏÎ¿ ÎºÎµÎ¯ÎŒÎµÎœÎ¿ ÏÎ¿Ï
+Ï Î¿ÎœÎ¿ÎŒÎ±ÏÎ¯Î¶Î¿Ï
+Îœ ÏÎ¿Îœ Î±Î¹ÏÎœÎ± ÏÏÎ¿Îœ Î¿ÏÎ¿Î¯Î¿ ÏÎ¿ 1903 Î±ÎœÎ®ÎºÎµÎ¹ (Î³ÏÎ¬ÏÎ¿Ï
+Îœ, Î³Î¹Î± ÏÎ±ÏÎ¬ÎŽÎµÎ¹Î³ÎŒÎ±, "ÏÎ¿Îœ 20Î¿ Î±Î¹ÏÎœÎ±" Î® "ÏÎ¿Îœ ÎµÎ¹ÎºÎ¿ÏÏÏ Î±Î¹ÏÎœÎ±"). ÎÏ
+ÏÏ ÏÎ·ÎŒÎ±Î¯ÎœÎµÎ¹ ÏÏÎ¹, ÏÎµ ÎŒÎµÏÎ¹ÎºÎ¬ Î­Î³Î³ÏÎ±ÏÎ±, Î¿Î¹ ÏÏ
+Î³ÎºÎµÎºÏÎ¹ÎŒÎ­ÎœÎµÏ Î·ÎŒÎµÏÎ¿ÎŒÎ·ÎœÎ¯ÎµÏ ÏÎ·Ï ÏÏÏÎŒÎ±Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï ÎŽÎµÎœ ÎžÎ± ÎµÎŒÏÎ±ÎœÎ¯Î¶Î¿ÎœÏÎ±Î¹ ÏÏÎ¿ ÎºÎµÎ¯ÎŒÎµÎœÎ¿. ÎÎ¹Î± Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· ÏÏÎµÏÎ¹ÎºÎ¬ ÎŒÎµ ÎŒÎ¹Î± ÏÏÎ¿ÎœÎ¹ÎºÎ® ÏÎµÏÎ¯Î¿ÎŽÎ¿, ÏÎ»Î± ÏÎ± ÏÎ±ÏÎ±ÏÎ¬ÎœÏ Î±ÏÎ¿ÏÎ¿ÏÎœ ÎºÎ¬ÎžÎµ Î­ÏÎ¿Ï ÏÎ·Ï ÏÏÎ¿ÎœÎ¹ÎºÎ®Ï ÏÎµÏÎ¹ÏÎŽÎ¿Ï
+.<p>
+}
+
+_textchangeprefs_ [l=el] {ÎÎ»Î»Î¬Î¶Î¿ÎœÏÎ±Ï ÏÎ¹Ï ÎÏÎ¹Î»Î¿Î³Î­Ï ÏÎ±Ï/ preferences}
+
+_texthelppreferences_ [l=el] {<h2>_textchangeprefs_</h2>
+
+<p>Î Î±ÏÏÎœÏÎ±Ï ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ <i>ÎµÏÎ¹Î»Î¿Î³Î­Ï</i> ÏÏÎ¿ ÏÎ¬ÎœÏ ÎŒÎ­ÏÎ¿Ï ÏÎ·Ï ÏÎµÎ»Î¯ÎŽÎ±Ï ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± Î±Î»Î»Î¬ÎŸÎµÏÎµ Î¿ÏÎ¹ÏÎŒÎ­ÎœÎ± ÏÎ±ÏÎ±ÎºÏÎ·ÏÎ¹ÏÏÎ¹ÎºÎ¬ ÏÎ·Ï ÎµÏÎ¹ÏÎ¬ÎœÎµÎ¹Î±Ï ÎµÏÎ³Î±ÏÎ¯Î±Ï, ÏÏÏÎµ ÎœÎ± ÎµÎŸÏ
+ÏÎ·ÏÎµÏÎ¿ÏÎœ ÎºÎ±Î»ÏÏÎµÏÎ± ÏÎ¹Ï Î±ÏÎ±Î¹ÏÎ®ÏÎµÎ¹Ï ÏÎ±Ï                                                                                                                                                                                                                                                                                                                                                                                                                                             
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>ÎÏÎ¹Î»Î¿Î³Î­Ï ÏÎ·Ï Î£Ï
+Î»Î»Î¿Î³Î®Ï</h3>
+
+ÎÎµÏÎ¹ÎºÎ­Ï ÏÏ
+Î»Î»Î¿Î³Î­Ï ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎ¿Ï
+Îœ Ï
+ÏÎ¿-ÏÏ
+Î»Î»Î¿Î³Î­Ï ÏÏÎ¹Ï Î¿ÏÎ¿Î¯ÎµÏ ÎŒÏÎ¿ÏÎµÎ¯ ÎœÎ± Î³Î¯ÎœÎµÎ¹ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·, ÎµÎ¯ÏÎµ ÎŒÎµÎŒÎ¿ÎœÏÎŒÎ­ÎœÎ±, Î® ÏÎ¿Î»Î»Î­Ï ÎŒÎ±Î¶Î¯ ÏÏ ÎŒÎ¹Î± ÎµÎœÏÏÎ·ÏÎ±. ÎÏÎ¿ÏÎµÎ¯ÏÎµ, ÎµÏÎ¿ÎŒÎ­ÎœÏÏ, ÎœÎ± ÎµÏÎ¹Î»Î­ÎŸÎµÏÎµ ÏÎ¿Î¹Î­Ï Ï
+ÏÎ¿ÏÏ
+Î»Î»Î¿Î³Î­Ï ÎžÎ­Î»ÎµÏÎµ ÎœÎ± ÏÎµÏÎ¹Î»Î±ÎŒÎ²Î¬ÎœÎ¿Ï
+Îœ Î¿Î¹ Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÎ¹Ï ÏÎ±Ï ÎŒÎ­ÏÏ ÏÎ·Ï ÏÎµÎ»Î¯ÎŽÎ±Ï ÎµÏÎ¹Î»Î¿Î³ÏÎœ.  
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>ÎÏÎ¹Î»Î¿Î³Î® ÎÎ»ÏÏÏÎ±Ï</h3>
+
+ÎÎ¬ÎžÎµ ÏÏ
+Î»Î»Î¿Î³Î® Î­ÏÎµÎ¹ ÎŒÎ¹Î± ÏÏÎ¿ÎµÏÎ¹Î»ÎµÎ³ÎŒÎ­ÎœÎ· Î³Î»ÏÏÏÎ± ÏÎ±ÏÎ¿Ï
+ÏÎ¯Î±ÏÎ·Ï, Î±Î»Î»Î¬ ÎµÏÎµÎ¯Ï ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± Î±Î»Î»Î¬ÎŸÎµÏÎµ ÏÎ·Îœ Î³Î»ÏÏÏÎ± Î±Ï
+ÏÎ®. ÎÏÎ¿ÏÎµÎ¯ÏÎµ Î±ÎºÏÎŒÎ± ÎœÎ± Î±Î»Î»Î¬ÎŸÎµÏÎµ ÏÎ¿ ÏÏÎ®ÎŒÎ± ÎºÏÎŽÎ¹ÎºÎ¿ÏÎ¿Î¯Î·ÏÎ·Ï ÏÎ¿Ï
+ ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ Î· Greenstone for output to the browser -- ÏÎ¿ Î»ÎµÎ¹ÏÎ¿Ï
+ÏÎ³Î¹ÎºÏ ÏÏÏÏÎ·ÎŒÎ± / the software ÎµÏÎ¹Î»Î­Î³ÎµÎ¹
+sensible defaults, Î±Î»Î»Î¬ ÎŒÎµ Î¿ÏÎ¹ÏÎŒÎ­ÎœÎ¿Ï
+Ï browsers ÎºÎ±Î»ÏÏÎµÏÎ± Î¿ÏÏÎ¹ÎºÎ¬ Î±ÏÎ¿ÏÎµÎ»Î­ÏÎŒÎ±ÏÎ± ÎŒÏÎ¿ÏÎ¿ÏÎœ ÎœÎ± ÎµÏÎ¹ÏÎµÏ
+ÏÎžÎ¿ÏÎœ ÎŒÎµ ÎŽÎ¹Î±ÏÎ¿ÏÎµÏÎ¹ÎºÏ ÏÏÎ®ÎŒÎ± ÎºÏÎŽÎ¹ÎºÎ¿ÏÎ¿Î¯Î·ÏÎ·Ï. ÎÎ»ÎµÏ Î¿Î¹ ÏÏ
+Î»Î»Î¿Î³Î­Ï ÏÎ±Ï ÎµÏÎ¹ÏÏÎ­ÏÎ¿Ï
+Îœ ÎœÎ± Î±Î»Î»Î¬ÎŸÎµÏÎµ ÏÎ± ÏÏÎ¿ÎµÏÎ¹Î»ÎµÎ³ÎŒÎ­ÎœÎ± Î³ÏÎ±ÏÎ¹ÎºÎ¬ ÏÎ·Ï ÎµÏÎ¹ÏÎ¬ÎœÎµÎ¹Î±Ï ÎµÏÎ³Î±ÏÎ¯Î±Ï ÏÎµ ÏÏÏÎŒÎ± ÎºÎµÎ¹ÎŒÎ­ÎœÎ¿Ï
+. ÎÏ
+ÏÏ ÎµÎ¯ÎœÎ±Î¹ Î¹ÎŽÎ¹Î±Î¹ÏÎ­ÏÏÏ ÏÏÎ®ÏÎ¹ÎŒÎ¿ Î³Î¹Î± ÏÏÎ®ÏÏÎµÏ ÎŒÎµ ÏÏÎ¿Î²Î»Î®ÎŒÎ±ÏÎ± ÏÏÎ±ÏÎ·Ï ÏÎ¿Ï
+ ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹Î¿ÏÎœ ÎµÎ¯ÏÎµ ÎŒÎµÎ³Î¬Î»Î¿Ï
+Ï ÏÎ±ÏÎ±ÎºÏÎ®ÏÎµÏ ÏÏÎ·Îœ Î¿ÎžÏÎœÎ·, Î® ÏÏ
+ÎœÎžÎ­ÏÎµÏ ÏÏÎœÎ®Ï 
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>ÎÏÎ¹Î»Î¿Î³Î­Ï Î Î±ÏÎ¿Ï
+ÏÎ¯Î±ÏÎ·Ï</h3>
+
+ÎÎœÎ¬Î»Î¿Î³Î± ÎŒÎµ ÏÎ·Îœ ÏÏ
+Î»Î»Î¿Î³Î® ÏÎ¿Ï
+ ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ÏÎ±Î¹, ÎŒÏÎ¿ÏÎµÎ¯ ÎœÎ± Ï
+ÏÎ¬ÏÏÎ¿Ï
+Îœ ÎµÎœÎ±Î»Î»Î±ÎºÏÎ¹ÎºÎ­Ï ÎµÎºÎŽÎ¿ÏÎ­Ï ÏÏÎ·ÏÎ¯ÎŒÎ±ÏÎ¿Ï Î³Î¹Î± ÏÎ¿Îœ Î­Î»ÎµÎ³ÏÎ¿ ÏÎ·Ï ÏÎ±ÏÎ¿Ï
+ÏÎ¯Î±ÏÎ·Ï/several options you can
+set that control the presentation.
+
+<p>ÎÎ¹ ÏÏ
+Î»Î»Î¿Î³Î­Ï ÏÎµÎ»Î¯ÎŽÏÎœ Web ÏÎ±Ï ÎµÏÎ¹ÏÏÎ­ÏÎ¿Ï
+Îœ ÎœÎ± ÏÏ
+ÎŒÏÎ¹Î­ÏÎµÏÎµ ÏÎ·Îœ ÎŒÏÎ¬ÏÎ± ÏÎ»Î¿Î®Î³Î·ÏÎ·Ï ÏÎ¿Ï
+ Greenstone/ suppress the Greenstone navigation bar ÏÏÎ¿ ÏÎ¬ÎœÏ ÎŒÎ­ÏÎ¿Ï ÎºÎ¬ÎžÎµ ÏÎµÎ»Î¯ÎŽÎ±Ï ÏÎ¿Ï
+ ÎµÎ³Î³ÏÎ¬ÏÎ¿Ï
+, Î­ÏÏÎ¹ ÏÏÏÎµ, ÎŒÎµÏÎ¬ Î±ÏÏ ÎºÎ¬ÎžÎµ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·, ÎœÎ± ÏÎ·Î³Î±Î¯ÎœÎµÏÎ±Î¹ Î±Ï
+ÏÎ¿ÎŒÎ¬ÏÏÏ ÏÏÎ·Îœ ÏÎµÎ»Î¯ÎŽÎ± ÏÎ¿Ï
+ ÏÎ±Î¹ÏÎ¹Î¬Î¶ÎµÎ¹ ÏÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ® ÏÎ±Ï ÏÏÏÎ¯Ï ÎœÎ± ÎµÎŒÏÎ±ÎœÎ¯Î¶Î¿ÎœÏÎ±Î¹ Î¿Î¹ ÎµÏÎ¹ÎºÎµÏÎ±Î»Î¯ÎŽÎµÏ ÏÎ·Ï Greenstone / without any Greenstone header. ÎÎ¹Î± ÎœÎ± ÎŸÎµÎºÎ¹ÎœÎ®ÏÎµÏÎµ ÎºÎ±Î¹ÎœÎ¿ÏÏÎ³Î¹Î± Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· ÎžÎ± ÏÏÎ­ÏÎµÎ¹ ÎœÎ± ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ÏÎµÏÎµ ÏÎ¿ ÎºÎ¿Ï
+ÎŒÏÎ¯ "ÏÎ¯ÏÏ" Î±ÏÏ ÏÎ¿Îœ browser ÏÎ±Ï. ÎÏ
+ÏÎ­Ï Î¿Î¹ ÏÏ
+Î»Î»Î¿Î³Î­Ï ÏÎ±Ï ÎµÏÎ¹ÏÏÎ­ÏÎ¿Ï
+Îœ Î±ÎºÏÎŒÎ± ÎœÎ± ÏÏ
+ÎŒÏÎ¹Î­ÏÎµÏÎµ ÏÎ¿ ÏÏÎ¿ÎµÎ¹ÎŽÎ¿ÏÎ¿Î¹Î·ÏÎ¹ÎºÏ ÎŒÎ®ÎœÏ
+ÎŒÎ± ÏÎ·Ï Greenstone ÏÏÎ±Îœ ÎµÏÎ¹Î»Î­Î³ÎµÏÎµ Î­ÎœÎ± ÏÏÎœÎŽÎµÏÎŒÎ¿ ÏÎ¿Ï
+ ÏÎ±Ï Î²Î³Î¬Î¶ÎµÎ¹ ÎµÎºÏÏÏ ÏÎ·Ï ÏÎ·ÏÎ¹Î±ÎºÎ®Ï Î²Î¹Î²Î»Î¹Î¿ÎžÎ®ÎºÎ·Ï, ÏÏÎ¿ Web. ÎÏÎ¯ÏÎ·Ï, ÏÎµ ÎŒÎµÏÎ¹ÎºÎ­Ï ÏÏ
+Î»Î»Î¿Î³Î­Ï, ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÎµÏÎ¹Î»Î­ÎŸÎµÏÎµ ÎµÎ¬Îœ Î¿ ÏÏÎœÎŽÎµÏÎŒÎ¿Ï ÏÏÎ± "Î±ÏÎ¿ÏÎµÎ»Î­ÏÎŒÎ±ÏÎ± Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï" ÎžÎ± ÏÎ±Ï ÏÎ·Î³Î±Î¯ÎœÎµÎ¹ ÎºÎ±ÏÎµÏ
+ÎžÎµÎ¯Î±Îœ ÏÏÎ¿ ÏÏÎ±Î³ÎŒÎ±ÏÎ¹ÎºÏ URL ÏÎ¿Ï
+ Î±ÎœÎ±Î¶Î·ÏÎ¬ÏÎµ, Î±ÎœÏÎ¯ Î³Î¹Î± ÏÎ¿ Î±ÎœÏÎ¯Î³ÏÎ±ÏÎ¿ ÏÎ·Ï Î²Î¹Î²Î»Î¹Î¿ÎžÎ®ÎºÎ·Ï.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>ÎÏÎ¹Î»Î¿Î³Î­Ï ÎÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï</h3>
+<p>ÎÏÎ¿ Î¶ÎµÏ
+Î³Î¬ÏÎ¹Î± ÎºÎ¿Ï
+ÎŒÏÎ¹ÏÎœ ÎµÎ»Î­Î³ÏÎ¿Ï
+Îœ ÏÎ¿ ÎµÎ¯ÎŽÎ¿Ï ÏÎ¿Ï
+ ÎºÎµÎ¹ÎŒÎ­ÎœÎ¿Ï
+ ÏÎ¿Ï
+ ÏÎ±Î¹ÏÎ¹Î¬Î¶ÎµÎ¹ ÏÏÎ¹Ï Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÎ¹Ï ÏÎ¿Ï
+ ÎºÎ¬ÎœÎµÏÎµ. Î€Î¿ ÏÏÏÏÎ¿ ÏÎµÏ (ÎŒÎµ ÏÎ¿ ÏÎœÎ¿ÎŒÎ± "ÎŽÎ¹Î±ÏÎ¿ÏÎ¬ ÏÎµÎ¶ÏÎœ - ÎºÎµÏÎ±Î»Î±Î¯ÏÎœ"/ "case differences") ÎµÎ»Î­Î³ÏÎµÎ¹ ÎµÎ¬Îœ ÏÎ± ÏÎµÎ¶Î¬ ÎºÎ±Î¹ ÏÎ± ÎºÎµÏÎ±Î»Î±Î¯Î± Î³ÏÎ¬ÎŒÎŒÎ±ÏÎ± ÏÎ±Î¹ÏÎ¹Î¬Î¶Î¿Ï
+Îœ/ whether upper and
+lower case must match.  Î€Î¿ ÎŽÎµÏÏÎµÏÎ¿ ("ÎºÎ±ÏÎ±Î»Î®ÎŸÎµÎ¹Ï Î»Î­ÎŸÎµÏÎœ") ÎµÎ»Î­Î³ÏÎµÎ¹ Î±Îœ ÎžÎ± ÏÏÎ­ÏÎµÎ¹ ÎœÎ± Î±Î³ÎœÎ¿Î®ÏÎµÎ¹ ÏÎ¹Ï ÎºÎ±ÏÎ±Î»Î®ÎŸÎµÎ¹Ï ÏÏÎœ ÏÏÏÎœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï Î® ÏÏÎ¹. ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎµÏÎ¯ÏÎ·Ï ÎœÎ± ÎµÏÎ¹Î»Î­ÎŸÎµÏÎµ Î­ÎœÎ± ÎŒÎµÎ³Î¬Î»Î¿Ï
+ ÎŒÎµÎ³Î­ÎžÎ¿Ï
+Ï ÎºÎ¿Ï
+ÏÎ¯ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï ÏÏÏÎµ ÎœÎ± Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÏÎµ ÎµÏ
+ÎºÎ¿Î»ÏÏÎµÏÎ± ÎºÎµÎ¯ÎŒÎµÎœÎ¿ ÏÎµ ÎŒÎ­Î³ÎµÎžÎ¿Ï ÏÎ±ÏÎ±Î³ÏÎ¬ÏÎ¿Ï
+. Î Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· ÎŒÎµÎ³Î¬Î»ÏÎœ ÎºÎµÎ¹ÎŒÎ­ÎœÏÎœ ÎµÎ¯ÎœÎ±Î¹ ÎµÎœÏÏ
+ÏÏÏÎ¹Î±ÎºÎ¬ Î³ÏÎ®Î³Î¿ÏÎ·.                                                                                                                                     
+<p>ÎÎ¹Î± ÏÎ±ÏÎ¬ÎŽÎµÎ¹Î³ÎŒÎ±, Î±Îœ ÎµÏÎ¹Î»ÎµÎ³Î¿ÏÎœ ÏÎ± ÎºÎ¿Ï
+ÎŒÏÎ¹Î¬ <i>Î±Î³ÎœÏÎ·ÏÎµ ÏÎ¹Ï ÎŽÎ¹Î±ÏÎ¿ÏÎ­Ï ÏÎµÎ¶ÏÎœ -ÎºÎµÏÎ±Î»Î±Î¯ÏÎœ/ignore case differences</i> ÎºÎ±Î¹
+<i>Î±Î³ÎœÏÎ·ÏÎµ ÏÎ¹Ï ÎºÎ±ÏÎ±Î»Î®ÎŸÎµÎ¹Ï Î»Î­ÎŸÎµÏÎœ</i>, Î· Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·<p>
+    <ul><kbd>ÎÏÏÎ¹ÎºÎ±ÎœÎ¹ÎºÏ KÏÎ¯ÏÎ¹Î¿</kbd></ul>
+      <p>ÎžÎ± Î±ÎœÏÎ¹ÎŒÎµÏÏÏÎ¹ÏÏÎµÎ¯ ÎŒÎµ ÏÎ¿Îœ Î¯ÎŽÎ¹Î¿ ÏÏÏÏÎ¿ ÏÏÏÏ Î· Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· Î³Î¹Î±<p>
+      <ul><kbd>Î±ÏÏÎ¹ÎºÎ® ÎºÏÎ¯ÏÎŒÎ±</kbd></ul><p>
+      ÎµÏÎµÎ¹ÎŽÎ® ÏÎ± ÎºÎµÏÎ±Î»Î±Î¯Î± Î³ÏÎ¬ÎŒÎŒÎ±ÏÎ± ÎžÎ± Î±Î»Î»Î¬ÎŸÎ¿Ï
+Îœ ÏÎµ ÏÎµÎ¶Î¬ ÎºÎ±Î¹ Î¿Î¹ ÎºÎ±ÏÎ±Î»Î®ÎŸÎµÎ¹Ï "-ÎœÎ¹ÎºÏ" ÎºÎ±Î¹ "-ÏÎ¹Î¿" ÎžÎ± ÏÏÎ³Î¿Ï
+Îœ Î±ÏÏ ÏÎ¹Ï Î»Î­ÎŸÎµÎ¹Ï "ÎÏÏÎ¹ÎºÎ±ÎœÎ¹ÎºÏ" ÎºÎ±Î¹ "ÎºÏÎ¯ÏÎ¹Î¿" Î±ÎœÏÎ¯ÏÏÎ¿Î¹ÏÎ±. 
+
+<p>ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÎµÏÎ¹Î»Î­ÎŸÎµÏÎµ ÏÎ·Îœ "ÏÏÎœÎžÎµÏÎ·" Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ· ÏÎ¿Ï
+ ÎžÎ± ÏÎ±Ï ÎµÏÎ¹ÏÏÎ­ÏÎµÎ¹ ÎœÎ± ÏÏ
+ÎœÎŽÏ
+Î¬ÏÎµÏÎµ ÏÏÎ¿Ï
+Ï ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÏÎœÏÎ±Ï ÏÎ¿Ï
+Ï ÏÏ
+ÎœÎŽÎ­ÏÎŒÎ¿Ï
+Ï AND (&), OR (|), ÎºÎ±Î¹ ÏÎ¿ NOT (!). ÎÏ
+ÏÏ ÎžÎ± ÏÎ±Ï ÎµÏÎ¹ÏÏÎ­ÏÎµÎ¹ ÎœÎ± ÎµÎŸÎµÎ¹ÎŽÎ¹ÎºÎµÏÏÎµÏÎµ ÏÎµÏÎ¹ÏÏÏÏÎµÏÎ¿ ÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ® ÏÎ±Ï. ÎÏÎ¿ÏÎµÎ¯ÏÎµ ÎµÏÎ¯ÏÎ·Ï ÎœÎ± ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹ÎµÎ¯ÏÎ±Î¹ ÏÎ·Îœ ÎµÏÎ¹Î»Î¿Î³Î® ÏÎ¿Ï
+ Î¹ÏÏÎ¿ÏÎ¹ÎºÎ¿Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï, Î³Î¹Î± ÎœÎ± ÎŽÎµÎ¯ÏÎµ ÏÎ¹Ï ÏÎµÎ»ÎµÏ
+ÏÎ±Î¯ÎµÏ ÏÎ±Ï Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÎ¹Ï. ÎÏ
+ÏÏ ÎŽÎ¹ÎµÏ
+ÎºÎ¿Î»ÏÎœÎµÎ¹ ÏÎ·Îœ ÎµÏÎ±ÎœÎ¬Î»Î·ÏÎ· ÎµÎ»Î±ÏÏÏÏ ÏÏÎ¿ÏÎ¿ÏÎ¿Î¹Î·ÎŒÎ­ÎœÏÎœ Î±ÎœÎ±Î¶Î·ÏÎ®ÏÎµÏÎœ. Î€Î­Î»Î¿Ï ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÎµÎ»Î­Î³ÎŸÎµÏÎµ ÏÎ¿Îœ Î±ÏÎ¹ÎžÎŒÏ ÏÏÎœ Î±ÏÎ¿ÏÎµÎ»ÎµÏÎŒÎ¬ÏÏÎœ ÏÎ¿Ï
+ ÎžÎ­Î»ÎµÏÎµ ÎœÎ± Î±ÎœÎ±ÎºÏÎ®ÏÎµÏÎµ ÎºÎ±Î¹ ÏÎ¿Îœ Î±ÏÎ¹ÎžÎŒÏ ÏÏÎœ Î±ÏÎ¿ÏÎµÎ»ÎµÏÎŒÎ¬ÏÏÎœ ÏÎ¿Ï
+ ÎžÎ­Î»ÎµÏÎµ ÎœÎ± Î²Î»Î­ÏÎµÏÎµ Î±ÎœÎ¬ Î¿ÎžÏÎœÎ·.
+}
+
+_texttanumbrowseoptions_ [l=el] {Î¥ÏÎ¬ÏÏÎ¿Ï
+Îœ _numbrowseoptions_ ÏÏÏÏÎ¿Î¹ ÎœÎ± Î²ÎµÎ¹ ÎºÎ±ÎœÎµÎ¯Ï ÏÎ»Î·ÏÎ¿ÏÎ¿ÏÎ¯ÎµÏ Î³Î¹' Î±Ï
+ÏÎ®Îœ ÏÎ· ÏÏ
+Î»Î»Î¿Î³Î®:}
+
+_textsimplehelpheading_ [l=el] {Î ÏÏ ÎœÎ± Î²ÏÎµÎ¯ÏÎµ ÏÎ»Î·ÏÎ¿ÏÎ¿ÏÎ¯ÎµÏ Î³Î¹Î± ÏÎ· ÏÏ
+Î»Î»Î¿Î³Î® _collectionname_ }
+
+_texthelpscope_ [l=el] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>ÎÏÏÎ¿Ï Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ·Ï/ Scope of queries</h3>
+
+<p>
+Î£ÏÎ¹Ï ÏÎµÏÎ¹ÏÏÏÏÎµÏÎµÏ ÏÏ
+Î»Î»Î¿Î³Î­Ï ÎŒÏÎ¿ÏÎµÎ¯ÏÎµ ÎœÎ± ÎµÏÎ¹Î»Î­ÎŸÎµÏÎµ ÎŽÎ¹Î±ÏÎ¿ÏÎµÏÎ¹ÎºÎ¬ ÎµÏ
+ÏÎµÏÎ®ÏÎ¹Î± Î³Î¹Î± ÏÎ·Îœ Î±ÎœÎ±Î¶Î®ÏÎ·ÏÎ® ÏÎ±Ï. ÎÎ¹Î± ÏÎ±ÏÎ¬ÎŽÎµÎ¹Î³ÎŒÎ±, ÎŒÏÎ¿ÏÎµÎ¯ ÎœÎ± Ï
+ÏÎ¬ÏÏÎ¿Ï
+Îœ ÎµÏ
+ÏÎµÏÎ®ÏÎ¹Î± Î³Î¹Î± ÏÏ
+Î³Î³ÏÎ±ÏÎµÎ¯Ï Î® Î³Î¹Î± ÏÎ¯ÏÎ»Î¿Ï
+Ï. Î ÎµÏ
+ÏÎµÏÎ®ÏÎ¹Î± Î³Î¹Î± ÎºÎµÏÎ±Î»Î±Î¯Î± Î® ÏÎ±ÏÎ±Î³ÏÎ¬ÏÎ¿Ï
+Ï. ÎÎµÎœÎ¹ÎºÎ¬ ÏÎ¿ Î­Î³Î³ÏÎ±ÏÎ¿ ÏÎ¿Ï
+ ÏÎ±Î¹ÏÎ¹Î¬Î¶ÎµÎ¹ Î±ÏÎ¿Î»ÏÏÏÏ ÎžÎ± Î²ÏÎµÎžÎµÎ¯, Î±ÎœÎµÎŸÎ¬ÏÏÎ·ÏÎ± Î±ÏÏ ÏÎ¿ ÎµÏ
+ÏÎµÏÎ®ÏÎ¹Î¿ ÏÎ¿Ï
+ ÎžÎ± ÏÏÎ·ÏÎ¹ÎŒÎ¿ÏÎ¿Î¹Î®ÏÎµÏÎµ.
+<p>ÎÎœ ÏÎ± Î­Î³Î³ÏÎ±ÏÎ± ÏÎ¿Ï
+ Î±ÎœÎ±Î¶Î·ÏÎ¬ÏÎµ ÎµÎ¯ÎœÎ±Î¹ Î²Î¹Î²Î»Î¯Î±, ÎžÎ± ÎµÎ¯ÎœÎ±Î¹ Î±ÎœÎ¿Î¹Î³ÎŒÎ­ÎœÎ± ÏÏÎ·Îœ ÎºÎ±ÏÎ¬Î»Î»Î·Î»Î· ÏÎµÎ»Î¯ÎŽÎ±.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/gsdl.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/gsdl.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/gsdl.dm	(revision 10506)
@@ -0,0 +1,120 @@
+# this file must be UTF-8 encoded
+
+package gsdl
+
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. 
+
+_javalinks_ {_imagehome_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+}
+
+#######################################################################
+# page content
+#######################################################################
+
+_iconabgsgr_ {<img src="_httpiconabgsgr_">}
+
+_pagetitle_ {_textimagegreenstone_}
+
+_content_ {
+_iconabgsgr_
+
+<p>
+
+
+<table border=0 cellspacing=0 cellpadding=0>
+ <tr>
+  <td valign=top align=center>_imagegreenstone_</td>
+  <td valign=top>_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>_textgreenstone2_
+  <br><br>
+  </td>
+ </tr>
+ <tr>
+  <td valign=top align=center>
+  <h2>_textplatformtitle_</h2>
+  </td>
+  <td valign=top>_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="_httpimg_/hdlimg.jpg"></a>
+  </td>
+  <td valign=top>
+  _textgreenstone4_
+  <br><br>
+  </td>
+ </tr>
+ <tr>
+  <td valign=top align=center>
+  <h2>_textcustomisationtitle_</h2>
+  </td>
+  <td valign=top>_textgreenstone5_
+  <br><br>
+  </td>
+ </tr>
+ <tr>
+  <td valign=top align=center>
+  <h2><a href="http://www.greenstone.org/english/docs.html">_textdocumentationtitle_</a></h2>
+  </td>
+  <td valign=top> _textdocuments_
+<br><br>
+</tr>
+ <tr>
+  <td valign=top align=center>
+  <h2>_textmailinglisttitle_</h2>
+  </td>
+  <td valign=top>_textmailinglist_
+  <br><br>
+ </tr>
+ <tr>
+  <td valign=top align=center>
+   <h2>_textbugstitle_</h2>
+  </td>
+  <td valign=top>_textreport_
+  <br><br>
+  </td>
+ </tr>
+ <tr>
+  <td valign=top align=center>
+   <h2>_textgs3title_</h2>
+  </td>
+  <td valign=top>_textgs3_
+   <br><br></td>
+ </tr>
+ <tr>
+  <td valign=top align=center>
+   <h2>_textcreditstitle_</h2>
+  </td>
+  <td valign=top>_textwhoswho_
+  </td>
+ </tr>
+</table>
+
+<p>_iconblankbar_
+<p>
+<table>
+<tr valign=top>
+<td>_home:textpoem_</td>
+<td>_imagegreenstone_</td>
+</tr></table>
+<p>_home:textgreenstone_
+
+_nzdlpagefooter_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/gti.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/gti.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/gti.dm	(revision 10506)
@@ -0,0 +1,213 @@
+# this file must be UTF-8 encoded
+
+package gti
+
+#######################################################################
+# page content
+#######################################################################
+
+_pagetitle_ {_textgti_}
+
+_imagecollection_ {<a href="_gwcgi_?a=gti&p=home&e=_compressedoptions_"><img src="_httpimg_/gti.gif"></a>}
+
+# The preferences button must go to the "homepref" page, since we are not in a collection
+_imagepref_ {_gsimage_(_home:httppagehomepref_,_httpiconcprefof_,_httpiconcprefon_,pref,_textimagepref_)}
+
+_content_ {
+<img src="_httpimg_/divb.gif">
+<p>
+<form method="post" action="_gwcgi_">
+  <input type="hidden" name="a" value="gti"/>
+  <input type="hidden" name="e" value="_compressedoptions_">
+  _gtiformcontent_
+</form>
+<p>
+<img src="_httpimg_/divb.gif">
+}
+
+# Content of the GTI "error" page
+_gtierror_ {
+<strong>_textgtierror_:</strong>
+<p>
+<tt>_gtierrormessage_</tt>
+}
+
+# Content of the GTI "home" page
+_gtihome_ {
+_textgtihome_
+<p>
+<table border="0" width="100%">
+  <td>_textgtiselecttlc_:</td><td align="right">_gtitlcselection_</td>
+</table>
+<p>
+<center>
+  <input type="hidden" name="p" value="lang"/><input type="submit" value="_textgtienter_"/>
+</center>
+}
+
+# Content of the GTI "language status" page
+_gtilang_ {
+<h2>_gtitargetlanguagename_</h2>
+<p>
+_textgtiselecttfk_:
+<p>
+_gtitfkselection_
+<p>
+<center>
+  <input type="hidden" name="p" value="core"/><input type="submit" value="_textgtienter_"/>
+</center>
+}
+
+# Content of the GTI "find text fragments" page
+_gtifind_ {
+<h2><a href="_gwcgi_?a=gti&p=lang&e=_compressedoptions_">_gtitargetlanguagename_</a> -- <a href="_gwcgi_?a=gti&p=core&e=_compressedoptions_">_gtitranslationfiledesc_</a></h2>
+<p>
+_textgtienterquery_:
+<p>
+<nobr>
+<input type="text" name="q" value="_cgiargq_" size="_gtitextareawidth_"/>
+<input type="hidden" name="p" value="find"/><input type="submit" value="_textgtifind_"/>
+</nobr>
+_gtifindformcontent_
+}
+
+# Content of the GTI "core" page (with text areas for entering and updating translations)
+_gticore_ {
+<h2><a href="_gwcgi_?a=gti&p=lang&e=_compressedoptions_">_gtitargetlanguagename_</a> -- _gtitranslationfiledesc_</h2>
+<p>
+<center>
+  _gtitranslationfilestatus_(_gtinumchunkstranslated_, _gtinumchunksrequiringtranslation_, _gtinumchunksrequiringupdating_, _gtitargetfilepath_)
+</center>
+<p>
+_gticoreformcontent_
+<p>
+<center>
+  <input type="hidden" name="p" value="submit"/><input type="submit" value="_textgtisubmit_"/>
+</center>
+}
+
+# Content of the GTI "done" page, thanking the translation for completing the file
+_gtidone_ {
+<h2><a href="_gwcgi_?a=gti&p=lang&e=_compressedoptions_">_gtitargetlanguagename_</a> -- _gtitranslationfiledesc_</h2>
+<p>
+<center>
+  _gtitranslationfilestatus_(_gtinumchunkstranslated_, _gtinumchunksrequiringtranslation_, _gtinumchunksrequiringupdating_, _gtitargetfilepath_)
+</center>
+<p>
+<hr>
+<p>
+_textgtitranslationfilecomplete_
+}
+
+_gtifindformheader_ {
+<hr><p>_textgtinumchunksmatchingquery_: _gtinumchunksmatchingquery_
+}
+
+_gtifindformfooter_ {
+<p>
+<center>
+  <input type="submit" name="sp" value="_textgtisubmit_"/>
+</center>
+}
+
+_gtitextareawidth_ {70}
+
+# --------------------------------------------------------------------------------
+#   Displays the status of a translation file
+#
+#   Used on the GTI "lang" and "core" pages
+#
+#   Parameters: 1 -- Number of chunks translated
+#               2 -- Number of chunks requiring translation
+#               3 -- Number of chunks requiring updating
+#		4 -- Relative URL of target file
+# --------------------------------------------------------------------------------
+_gtitranslationfilestatus_ {
+<table border="0">
+  <tr><td align="right">_1_</td><td>_textgtinumchunkstranslated_ (_textgtinumchunksrequiringupdating_(_3_))</td></tr>
+  <tr><td align="right">_2_</td><td>_textgtinumchunksrequiringtranslation_</td></tr>
+  _If_(_4_,<tr><td align="right">&nbsp;</td><td>
+     <a href="_gwcgi_?a=gti&p=find&e=_compressedoptions_">_textgticorrectexistingtranslations_</a><br>
+     <a href="_httpprefix_/_4_">_textgtidownloadtargetfile_</a><br>
+     _gtiviewtranslationfileinaction_
+  </td></tr>)
+</table>
+}
+
+# --------------------------------------------------------------------------------
+#   Displays text area for correcting a chunk
+#
+#   Used on the GTI "find" page
+#
+#   Parameters: 1 -- Chunk key
+#               2 -- Target file chunk text
+# --------------------------------------------------------------------------------
+_gtichunkmatchingquery_ {
+<p>
+<center>
+  <table dir="_gtitextdirection_">
+    <tr><td><strong>_1_</strong></td></tr>
+    <tr><td><textarea name="_cgiargtlc_::_1_" rows="4" cols="_gtitextareawidth_">_2_</textarea></td></tr>
+  </table>
+</center>
+}
+
+# --------------------------------------------------------------------------------
+#   Displays text areas for translating a chunk
+#
+#   Used on the GTI "core" page
+#
+#   Parameters: 1 -- Chunk key
+#               2 -- Source file chunk text
+#               3 -- Source file chunk date
+# --------------------------------------------------------------------------------
+_gtichunkrequiringtranslation_ {
+<hr>
+_textgtitranslatingchunk_(_1_)
+<p>
+<center>
+  <table dir="_gtitextdirection_">
+    <tr><td><strong>English</strong></td><td align="right"><font size="-1"><i>_textgtilastupdated_ _3_</i></font></td></tr>
+    <tr><td colspan="2"><textarea name="en::_1_" rows="4" cols="_gtitextareawidth_" readonly="1">_2_</textarea></td></tr>
+  </table>
+  <table dir="_gtitextdirection_">
+    <tr><td><strong>_gtitargetlanguagename_</strong></td><td align="right">&nbsp;</td></tr>
+    <tr><td colspan="2"><textarea name="_cgiargtlc_::_1_" rows="4" cols="_gtitextareawidth_"></textarea></td></tr>
+  </table>
+</center>
+}
+
+# --------------------------------------------------------------------------------
+#   Displays text areas for updating a chunk
+#
+#   Used on the GTI "core" page
+#
+#   Parameters: 1 -- Chunk key
+#               2 -- Source file chunk text
+#               3 -- Source file chunk date
+#               4 -- Target file chunk text
+#               5 -- Target file chunk date
+# --------------------------------------------------------------------------------
+_gtichunkrequiringupdating_ {
+<hr>
+_textgtiupdatingchunk_(_1_)
+<p>
+<center>
+  <table dir="_gtitextdirection_">
+    <tr><td><strong>English</strong></td><td align="right"><font size="-1"><i>_textgtilastupdated_ _3_</i></font></td></tr>
+    <tr><td colspan="2"><textarea name="en::_1_" rows="4" cols="_gtitextareawidth_" readonly="1">_2_</textarea></td></tr>
+  </table>
+  <p>
+  <table dir="_gtitextdirection_">
+    <tr><td><strong>_gtitargetlanguagename_</strong></td><td align="right"><font size="-1"><i>_textgtilastupdated_ _5_</i></font></td></tr>
+    <tr><td colspan="2"><textarea name="_cgiargtlc_::_1_" rows="4" cols="_gtitextareawidth_">_4_</textarea></td></tr>
+  </table>
+</center>
+}
+
+# Links to see the translation files in action
+_gtiviewcoredminaction_ {<a href="_gwcgi_?a=p&p=about&c=demo&l=_cgiargtlc_&e=_compressedoptions_">_textgtiviewtargetfileinaction_</a>}
+_gtiviewauxdminaction_ {<a href="_gwcgi_?a=p&p=about&c=demo&l=_cgiargtlc_&e=_compressedoptions_">_textgtiviewtargetfileinaction_</a>}
+
+_gtiviewperlmodulesinaction_ {}
+_gtiviewglidictinaction_ {}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/hebrew.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/hebrew.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/hebrew.dm	(revision 10506)
@@ -0,0 +1,1319 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Hebrew Language text and icon macros 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textperiodicals_
+# -- Missing translation: _textsource_
+# -- Missing translation: _textdate_
+# -- Missing translation: _textnumpages_
+
+# -- Missing translation: _textsignin_
+
+_textdefaultcontent_ [l=he] {Greenstone Digital Library  ×××¡×× ×××××§×© ×× × ××Š×. × × ×××××¥ ×¢× ××€×ª××š "××××š×" ×××€××€× ×× ××€×ª××š ×"×××ª" ××× ×××××š × }
+
+_textdefaulttitle_ [l=he] {GSDL ××¢××ª }
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=he] {×××× _about:builddate_ ××××¡×£ × ×× × ××€× × 
+ ××¡×××× _about:numdocs_ ××××¡×£ ××××  }
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=he] {<p> ××ª×× _numbytes_ ×¡×"×    _If_("_numdocs_" eq "1",××¡××,××¡××××),_numdocs_ ××××¡×£ ×××× ××××¢ ××××× }
+
+_textimagecollection_ [l=he] {}
+_textimageabout_ [l=he] {×¢× ×××ª×š}
+_textimagehome_ [l=he] {×¢××× ××××ª}
+_textimagehelp_ [l=he] {××£ ×¢××š}
+_textimagepref_ [l=he] {××£ ××××š××ª}
+_textimagegreenstone_ [l=he] {Greenstone  ×¡×€×š×××ª }
+# -- Missing translation: _textimageusab_
+
+_textimagesearch_ [l=he] {××€×© ××× ××× ××××××§××}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=he] {××€××£ ×××ª×š××ª ××€× ×-×}
+_textimageCreator_ [l=he] {××€××£ ××××š×× ××€× ×-×}
+_textimageSubject_ [l=he] {××€××£ ××€× × ××©×××}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=he] {××€××£ ××€× ×ª××š××}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+# -- Missing translation: _textimageSource_
+_textimageLanguage_ [l=he] {××€××£ ××€× ×©×€×}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=he] {××€××£ ××€× ×××š××× ××}
+# -- Missing translation: _textimageKeyword_
+_textimageHowto_ [l=he] {××€××£ ××€× ×¡××š ×××Š×}
+_textimageList_ [l=he] {××€××£ ××š×©×××ª ××¡××××}
+_textimageSeries_ [l=he] {××€××£ ××€× ×¡××××š××}
+_textimageTo_ [l=he] {××€××£ ××€× ×¡××š ×××¢×}
+_textimageFrom_ [l=he] {××€××£ ××€× ×¡××š ××§××š××ª}
+_textimageTopic_ [l=he] {××€××£ ××€× ×¡××××š×× ×××××××}
+_textimageBrowse_ [l=he] {××€××£}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=he] {××€××£ ×š×©×××ª ×× ×©×× ××€× ×-×}
+_textimageAcronym_ [l=he] {××€××£ ×š××©× ×ª××××ª}
+_textimagePhrase_ [l=he] {××€××£ ××××××××}
+# -- Missing translation: _textimageArtist_
+# -- Missing translation: _textimageVolume_
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=he] {××€×©}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=he] {×××ª×š××ª ×-×ª}
+_texticontabCreatorgreen_ [l=he] {××××š×× ×-×ª}
+_texticontabSubjectgreen_ [l=he] {× ××©×××}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=he] {×ª××š××××}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+# -- Missing translation: _texticontabSourcegreen_
+_texticontabLanguagegreen_ [l=he] {×©×€×}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=he] {×××š×××}
+# -- Missing translation: _texticontabKeywordgreen_
+_texticontabhowgreen_ [l=he] {×××Š×}
+_texticontabseriesgreen_ [l=he] {×¡××š××ª}
+_texticontablistgreen_ [l=he] {×š×©××××ª}
+_texticontabtogreen_ [l=he] {××¢×}
+_texticontabfromgreen_ [l=he] {××§××š}
+_texticontabtopicgreen_ [l=he] {×××ª×š××ª}
+_texticontabbrwsegreen_ [l=he] {××€××£}
+# -- Missing translation: _texticontabCollagegreen_
+# -- Missing translation: _texticontabbrowsgreen_
+_texticontabPeoplegreen_ [l=he] {×× ×©×× ×-×ª}
+_texticontabAcronymgreen_ [l=he] {×š××©× ×ª××××ª}
+_texticontabPhrasegreen_ [l=he] {×××××××}
+# -- Missing translation: _texticontabArtistgreen_
+# -- Missing translation: _texticontabVolumegreen_
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=he] {××Š× ××ª ×××¡××}
+_texticonclosedbook_ [l=he] {×€×ª× ××ª ×××¡×× ×××Š× ××ª ×ª××× ×}
+_texticonnext_ [l=he] {××××§ ×××}
+_texticonprev_ [l=he] {××××§ ××§×××}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=he] {MIDI - ××Š× ××ª ××¡×× ×}
+_texticonmsword_ [l=he] {Word - ××Š× ××ª ××¡×× ×}
+_texticonmp3_ [l=he] {MP3 - ××Š× ××ª ××¡×× ×}
+_texticonpdf_ [l=he] {PDF - ××Š× ××ª ××¡×× × }
+_texticonps_ [l=he] {PS - ××Š× ××ª ××¡×× ×}
+_texticonppt_ [l=he] {PPT - ××Š× ××ª ××¡×× ×}
+_texticonrtf_ [l=he] {RTF - ××Š× ××ª ××¡×× ×}
+_texticonxls_ [l=he] {XLS - ××Š× ××ª ××¡×× ×}
+
+_page_ [l=he] {×¢×××}
+_pages_ [l=he] {×¢×××××}
+_of_ [l=he] {×××§××š ×××}
+_vol_ [l=he] {××š×}
+_num_ [l=he] {××¡×€×š}
+
+_textmonth00_ [l=he] {}
+_textmonth01_ [l=he] {×× ×××š}
+_textmonth02_ [l=he] {×€××š×××š}
+_textmonth03_ [l=he] {××š×¥}
+_textmonth04_ [l=he] {××€×š××}
+_textmonth05_ [l=he] {×××}
+_textmonth06_ [l=he] {××× ×}
+_textmonth07_ [l=he] {××××}
+_textmonth08_ [l=he] {×××××¡×}
+_textmonth09_ [l=he] {×¡×€××××š}
+_textmonth10_ [l=he] {×××§××××š}
+_textmonth11_ [l=he] {× ×××××š}
+_textmonth12_ [l=he] {××Š×××š}
+
+_textdocument_ [l=he] {××¡××}
+_textsection_ [l=he] {×××§}
+_textparagraph_ [l=he] {×€××¡×§×}
+
+_magazines_ [l=he] {××š×××}
+
+_nzdlpagefooter_ [l=he] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "××××¢ ×ª×××" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=he] {_httpimg_/he/chomeof.gif}
+_httpiconchomeon_ [l=he] {_httpimg_/he/chomeon.gif}
+
+## "××š××¢" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=he] {_httpimg_/he/chelpof.gif}
+_httpiconchelpon_ [l=he] {_httpimg_/he/chelpon.gif}
+
+## "×ª××××€×××¢" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=he] {_httpimg_/he/cprefof.gif}
+_httpiconcprefon_ [l=he] {_httpimg_/he/cprefon.gif}
+
+# -- Missing translation: cusab
+# -- Missing translation: _httpiconcusabof_
+# -- Missing translation: _httpiconcusabon_
+
+
+## "×©×€×" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=he] {_httpimg_/he/tsrchgr.gif}
+_httpicontsrchof_ [l=he] {_httpimg_/he/tsrchof.gif}
+_httpicontsrchon_ [l=he] {_httpimg_/he/tsrchon.gif}
+_widthtsrchx_ [l=he] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "×ª-× ×ª××š×ª××" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=he] {_httpimg_/he/ttitlgr.gif}
+_httpiconttitleof_ [l=he] {_httpimg_/he/ttitlof.gif}
+_httpiconttitleon_ [l=he] {_httpimg_/he/ttitlon.gif}
+_widthttitlex_ [l=he] {100}
+
+# Not true DC, kept for legacy reasons
+## "×××š××× ×ª-×" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=he] {_httpimg_/he/tauthgr.gif}
+_httpicontcreatof_ [l=he] {_httpimg_/he/tauthof.gif}
+_httpicontcreaton_ [l=he] {_httpimg_/he/tauthon.gif}
+_widthtcreatx_ [l=he] {100}
+
+## "××××©×× " ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=he] {_httpimg_/he/tsubjgr.gif}
+_httpicontsubjon_ [l=he] {_httpimg_/he/tsubjon.gif}
+_httpicontsubjof_ [l=he] {_httpimg_/he/tsubjof.gif}
+_widthtsubjx_ [l=he] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "×××××š××ª" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=he] {_httpimg_/he/tdategr.gif}
+_httpicontdateof_ [l=he] {_httpimg_/he/tdateof.gif}
+_httpicontdateon_ [l=he] {_httpimg_/he/tdateon.gif}
+_widthtdatex_ [l=he] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: tsrc
+# -- Missing translation: _httpicontsrcgr_
+# -- Missing translation: _httpicontsrcof_
+# -- Missing translation: _httpicontsrcon_
+# -- Missing translation: _widthtsrcx_
+
+## "××€×©" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=he] {_httpimg_/he/tlanggr.gif}
+_httpicontlangon_ [l=he] {_httpimg_/he/tlangon.gif}
+_httpicontlangof_ [l=he] {_httpimg_/he/tlangof.gif}
+_widthtlangx_ [l=he] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "×ª××š××¡" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=he] {_httpimg_/he/tsergr.gif}
+_httpicontserof_ [l=he] {_httpimg_/he/tserof.gif}
+_httpicontseron_ [l=he] {_httpimg_/he/tseron.gif}
+_widthtserx_ [l=he] {87}
+
+## "×š××§×" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=he] {_httpimg_/he/ttogr.gif}
+_httpiconttoon_ [l=he] {_httpimg_/he/ttoon.gif}
+_httpiconttoof_ [l=he] {_httpimg_/he/ttoof.gif}
+_widthttox_ [l=he] {87}
+
+## "××¢×" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=he] {_httpimg_/he/tfromgr.gif}
+_httpicontfromon_ [l=he] {_httpimg_/he/tfromon.gif}
+_httpicontfromof_ [l=he] {_httpimg_/he/tfromof.gif}
+_widthtfromx_ [l=he] {87}
+
+## "××××š×" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=he] {_httpimg_/he/torggr.gif}
+_httpicontorgon_ [l=he] {_httpimg_/he/torgon.gif}
+_httpicontorgof_ [l=he] {_httpimg_/he/torgof.gif}
+_widthtorgx_ [l=he] {87}
+
+## "××Š××" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=he] {_httpimg_/he/thowgr.gif}
+_httpiconthowon_ [l=he] {_httpimg_/he/thowon.gif}
+_httpiconthowof_ [l=he] {_httpimg_/he/thowof.gif}
+_widththowx_ [l=he] {87}
+
+## "×ª×š×ª××" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=he] {_httpimg_/he/ttopicgr.gif}
+_httpiconttopicon_ [l=he] {_httpimg_/he/ttopicon.gif}
+_httpiconttopicof_ [l=he] {_httpimg_/he/ttopicof.gif}
+_widthttopicx_ [l=he] {87}
+
+## "×£××€×" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=he] {_httpimg_/he/tbrwsegr.gif}
+_httpicontbrwseon_ [l=he] {_httpimg_/he/tbrwseon.gif}
+_httpicontbrwseof_ [l=he] {_httpimg_/he/tbrwseof.gif}
+_widthtbrwsex_ [l=he] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "×××©× ×" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=he] {_httpimg_/he/tpeopgr.gif}
+_httpicontpeopof_ [l=he] {_httpimg_/he/tpeopof.gif}
+_httpicontpeopon_ [l=he] {_httpimg_/he/tpeopon.gif}
+_widthtpeopx_ [l=he] {87}
+
+## "××©××š ×ª××××ª" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=he] {_httpimg_/he/tacrogr.gif}
+_httpicontacroof_ [l=he] {_httpimg_/he/tacroof.gif}
+_httpicontacroon_ [l=he] {_httpimg_/he/tacroon.gif}
+_widthtacrox_ [l=he] {99}
+
+# -- Missing translation: tphrse
+# -- Missing translation: _httpicontphrsegr_
+# -- Missing translation: _httpicontphrseof_
+# -- Missing translation: _httpicontphrseon_
+# -- Missing translation: _widthtphrsex_
+
+# -- Missing translation: tartst
+# -- Missing translation: _httpicontartstgr_
+# -- Missing translation: _httpicontartstof_
+# -- Missing translation: _httpicontartston_
+# -- Missing translation: _widthtartstx_
+
+# -- Missing translation: tkw
+# -- Missing translation: _httpicontkwgr_
+# -- Missing translation: _httpicontkwof_
+# -- Missing translation: _httpicontkwon_
+# -- Missing translation: _widthtkwx_
+
+# -- Missing translation: tvol
+# -- Missing translation: _httpicontvolgr_
+# -- Missing translation: _httpicontvolof_
+# -- Missing translation: _httpicontvolon_
+# -- Missing translation: _widthtvolx_
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "××š××¢" ## green_title ## h_help ##
+_httpiconhhelp_ [l=he] {_httpimg_/he/h\_help.gif}
+_widthhhelp_ [l=he] {200}
+_heighthhelp_ [l=he] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textabcol_
+
+# -- Missing translation: _textsubcols1_
+
+# -- Missing translation: _textsubcols2_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "××¢" ## green_title ## h_about ##
+_httpiconhabout_ [l=he] {_httpimg_/he/h\_about.gif}
+_widthhabout_ [l=he] {200}
+_heighthabout_ [l=he] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=he] {×××ª×š××ª ×-×ª}
+_texticonhcreat_ [l=he] {××××š×× ×-×ª}
+_texticonhsubj_ [l=he] {× ××©×××}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=he] {×ª××š××××}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+# -- Missing translation: _texticonhsrc_
+_texticonhlang_ [l=he] {×©×€××ª}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=he] {××¢×}
+_texticonhfrom_ [l=he] {××§××š}
+_texticonhser_ [l=he] {×¡××š××ª}
+_texticonhhow_ [l=he] {×××Š×}
+_texticonhorg_ [l=he] {×××š××× ××}
+_texticonhbrwse_ [l=he] {××€××£}
+# -- Missing translation: _texticonhbrows_
+_texticonhpeople_ [l=he] {×× ×©×× ×-×ª}
+_texticonhacronym_ [l=he] {×š××©× ×ª××××ª}
+_texticonhphrases_ [l=he] {×××××××}
+# -- Missing translation: _texticonhartist_
+# -- Missing translation: _texticonhkw_
+# -- Missing translation: _texticonhvol_
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=he] {×¡×××š ××ª ××××§ ××× ×©× ××¡×€×š×××}
+_texticonclosedbookshelf_ [l=he] {×€×ª× ××ª ××××§ ××× ×©× ××¡×€×š××× ×××Š× ××ª ×ª××× ×}
+_texticonopenbook_ [l=he] {×¡×××š ××ª ××¡×€×š}
+_texticonclosedfolder_ [l=he] {×€×ª× ××ª ××ª××§××× ×××Š× ××ª ×ª××× ×}
+_texticonclosedfolder2_ [l=he] {×€×ª× ××ª ××ª×ª-×××§}
+_texticonopenfolder_ [l=he] {×¡×××š ××ª ××ª××§×××}
+_texticonopenfolder2_ [l=he] {×¡×××š ××ª ××ª×ª-×××§}
+_texticonsmalltext_ [l=he] {××Š× ××ª ××××§ ××× ×©× ×××§×¡×}
+_texticonsmalltext2_ [l=he] {××Š× ××§×¡×}
+_texticonpointer_ [l=he] {×××§ × ××××}
+_texticondetach_ [l=he] {×€×ª× ××ª ××¢××× ××××× ×××©}
+_texticonhighlight_ [l=he] {××××© ××× ×× ×××€××©}
+_texticonnohighlight_ [l=he] {×× ×ª××××© ××× ×× ×××€××©}
+_texticoncontracttoc_ [l=he] {×Š××Š× ×ª××× ×¢×× ××× ××}
+_texticonexpandtoc_ [l=he] {××Š× ×ª××× ×¢×× ××× ××}
+_texticonexpandtext_ [l=he] {××Š× ××ª ×× ×××§×¡×}
+_texticoncontracttext_ [l=he] {××Š× ××§×¡× ×š×§ ×¢×××š ××××§ ×××¡×××}
+_texticonwarning_ [l=he] {<b> ××××š× : /<b>}
+_texticoncont_ [l=he] {?××××©××}
+
+_textltwarning_ [l=he] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_  ××Š××ª ×××§×¡× ××× ×××Š××š ××××ª ××××× 
+×©× × ×ª×× ×× ×××Š×× ×××€××€× _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=he] {×× ××¢×××}
+_textintro_ [l=he] {<i>  (××××) </i> }
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "×ª××š×ª×× ×ª-×" ## green_title ## h_title ##
+_httpiconhtitle_ [l=he] {_httpimg_/he/h\_title.gif}
+_widthhtitle_ [l=he] {200}
+_heighthtitle_ [l=he] {57}
+
+# Not true DC, kept for legacy reasons
+## "×××š××× ×ª-×" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=he] {_httpimg_/he/h\_auth.gif}
+_widthhcreat_ [l=he] {200}
+_heighthcreat_ [l=he] {57}
+
+## "××××©×× " ## green_title ## h_subj ##
+_httpiconhsubj_ [l=he] {_httpimg_/he/h\_subj.gif}
+_widthhsubj_ [l=he] {200}
+_heighthsubj_ [l=he] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "×××××š××ª" ## green_title ## h_date ##
+_httpiconhdate_ [l=he] {_httpimg_/he/h\_date.gif}
+_widthhdate_ [l=he] {200}
+_heighthdate_ [l=he] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_src
+# -- Missing translation: _httpiconhsrc_
+# -- Missing translation: _widthhsrc_
+# -- Missing translation: _heighthsrc_
+
+## "×ª××€×©" ## green_title ## h_lang ##
+_httpiconhlang_ [l=he] {_httpimg_/he/h\_lang.gif}
+_widthhlang_ [l=he] {200}
+_heighthlang_ [l=he] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "×š××§×" ## green_title ## h_to ##
+_httpiconhto_ [l=he] {_httpimg_/he/h\_to.gif}
+_widthhto_ [l=he] {200}
+_heighthto_ [l=he] {57}
+
+## "××¢×" ## green_title ## h_from ##
+_httpiconhfrom_ [l=he] {_httpimg_/he/h\_from.gif}
+_widthhfrom_ [l=he] {200}
+_heighthfrom_ [l=he] {57}
+
+## "×ª××š××¡" ## green_title ## h_ser ##
+_httpiconhser_ [l=he] {_httpimg_/he/h\_ser.gif}
+_widthhser_ [l=he] {200}
+_heighthser_ [l=he] {57}
+
+## "××Š××" ## green_title ## h_how ##
+_httpiconhhow_ [l=he] {_httpimg_/he/h\_how.gif}
+_widthhhow_ [l=he] {200}
+_heighthhow_ [l=he] {57}
+
+## "××××©×× " ## green_title ## h_topic ##
+_httpiconhtopic_ [l=he] {_httpimg_/he/h\_topic.gif}
+_widthhtopic_ [l=he] {200}
+_heighthtopic_ [l=he] {57}
+
+## "××××š×" ## green_title ## h_org ##
+_httpiconhorg_ [l=he] {_httpimg_/he/h\_org.gif}
+_widthhorg_ [l=he] {250}
+_heighthorg_ [l=he] {57}
+
+## "××Š×" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=he] {_httpimg_/he/h\_brwse.gif}
+_widthhbrwse_ [l=he] {200}
+_heighthbrwse_ [l=he] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "×××©× ×" ## green_title ## h_people ##
+_httpiconhpeople_ [l=he] {_httpimg_/he/h\_people.gif}
+_widthhpeople_ [l=he] {200}
+_heighthpeople_ [l=he] {57}
+
+## "××©××š ×ª××××ª" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=he] {_httpimg_/he/h\_acro.gif}
+_widthhacronym_ [l=he] {200}
+_heighthacronym_ [l=he] {57}
+
+# -- Missing translation: h_phrse
+# -- Missing translation: _httpiconhphrse_
+# -- Missing translation: _widthhphrse_
+# -- Missing translation: _heighthphrse_
+
+# -- Missing translation: h_artist
+# -- Missing translation: _httpiconhartist_
+# -- Missing translation: _widthhartist_
+# -- Missing translation: _heighthartist_
+
+# -- Missing translation: h_kw
+# -- Missing translation: _httpiconhkw_
+# -- Missing translation: _widthhkw_
+# -- Missing translation: _heighthkw_
+
+# -- Missing translation: h_vol
+# -- Missing translation: _httpiconhvol_
+# -- Missing translation: _widthhvol_
+# -- Missing translation: _heighthvol_
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+## " " ×××©×××" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=he] {_httpimg_/he/contoff.gif}
+_httpiconconton_ [l=he] {_httpimg_/he/conton.gif}
+
+## "××××š××\n××¡×§×" ## document_button ## eallt ##
+_httpiconealltof_ [l=he] {_httpimg_/he/ealltof.gif}
+_httpiconeallton_ [l=he] {_httpimg_/he/eallton.gif}
+
+## "×¥××××\n×ª× ××××ª×" ## document_button ## econc ##
+_httpiconeconcof_ [l=he] {_httpimg_/he/econcof.gif}
+_httpiconeconcon_ [l=he] {_httpimg_/he/econcon.gif}
+
+## "×§×ª× ×" ## document_button ## edtch ##
+_httpiconedtchof_ [l=he] {_httpimg_/he/edtchof.gif}
+_httpiconedtchon_ [l=he] {_httpimg_/he/edtchon.gif}
+
+## "××××š××\n×ª× ××××ª×" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=he] {_httpimg_/he/eexpcof.gif}
+_httpiconeexpcon_ [l=he] {_httpimg_/he/eexpcon.gif}
+
+## "×¥××××\n×ª× ××¡×§××" ## document_button ## etsec ##
+_httpiconetsecof_ [l=he] {_httpimg_/he/etsecof.gif}
+_httpiconetsecon_ [l=he] {_httpimg_/he/etsecon.gif}
+
+## "××©×××" ## document_button ## ehl ##
+_httpiconehlof_ [l=he] {_httpimg_/he/ehlof.gif}
+_httpiconehlon_ [l=he] {_httpimg_/he/ehlon.gif}
+
+## "×××\n××©×××" ## document_button ## enhl ##
+_httpiconenhlof_ [l=he] {_httpimg_/he/enhlof.gif}
+_httpiconenhlon_ [l=he] {_httpimg_/he/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=he] {_If_(thislast_,×ª××Š×××ª _thisfirst_ - _thislast_ ××©××××ª× : _cgiargq_, ×××  ××¡×××× ×××× ××©××××ª×: _cgiargq_)}
+_textnoquerytitle_ [l=he] {×××€××© ××£}
+
+_texticonthispage_ [l=he] {×××€××©}
+_textsome_ [l=he] {×××××}
+_textall_ [l=he] {××××× ×}
+_textboolean_ [l=he] {×××}
+_textranked_ [l=he] {×××§}
+_textnatural_ [l=he] {×××}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=he] {}
+_texticonsearchhistorybar_ [l=he] {××¡×××š×××ª ×××€××©}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=he] {×©×ª××© ××©××××ª× ××××ª}
+_textfreqmsg1_ [l=he] {:×¡×€××š×ª ×××××}
+_textpostprocess_ [l=he] {_If_(_quotedquery_,<br><i>××××š ×××××_quotedquery_</i>)}
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=he] {-  ×××ª×š × }
+_textapprox_ [l=he] {××}
+_textnodocs_ [l=he] {××©××××ª× ××× ×ª×©××××ª}
+_text1doc_ [l=he] {×ª×©××× ×××ª ××× ××©××××ª×}
+_textlotsdocs_ [l=he] {×ª×©××××ª ××ª×××××ª ××©××××ª×}
+_textmatches_ [l=he] {× ××Š×× ××ª××××ª}
+_textbeginsearch_ [l=he] {××ª×× ×××€××©}
+_textrunquery_ [l=he] {××š×¥ ×©××××ª×}
+_textclearform_ [l=he] {× ×§× ×××€×¡}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=he] {×××× ×× ×××××}
+_textinfield_ [l=he] {...××©××}
+_textfoldstem_ [l=he] {××××©×× ××××€××©, ××¢×Š××š }
+
+_textadvquery_ [l=he] {×× ××× ×¡ ××ª ××©××××ª× ××©××š××ª:}
+_textallfields_ [l=he] {×× × ×©×××ª}
+# -- Missing translation: _texttextonly_
+_textand_ [l=he] {×××}
+_textor_ [l=he] {××}
+_textandnot_ [l=he] {×××}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=he] {××€×© ××ª _indexselection_ _If_(_jselection_, ×©× _jselection_) _If_(_gselection_, _gselection_ ××š××) _If_(_nselection_, _nselection_ ××©×€×) _querytypeselection_ ××©×š ×××××ª ×××××}
+
+_textadvancedsearch_ [l=he] {××€×© ××ª _indexselection_ _If_(_jselection_, ×©×) _jselection_) _If_(_gselection_, _gselection_ ××š××)_If_(_nselection_, _nselection_ ××©×€×)  _querytypeselection_ ××©××××© ×©× ×©×××××}
+
+_textformsimplesearch_ [l=he] {××€×© ××ª _If_(_jselection_, _jselection_) _If_(_gformselection_, _gformselection_ ××š××) _If_(_nselection_, _nselection_ ××©×€×)
+_formquerytypeselection_ ××©×š ×××××ª ××ª}
+
+_textformadvancedsearch_ [l=he] {××€×© ××ª  _If_(_jselection_,_jselection_)
+_If_(_gformselection_, _gformselection_ × ××š×× _If_(_nselection_, _nselection_ ××©×€×)}
+
+
+# -- Missing translation: _textnojsformwarning_
+_textdatesearch_ [l=he] {××××€×¡ ××× × ××ª× ×××€×© ×××š ××¡×××× ××ª×§××€× ××¡×××××ª ×× ×××× ××××××× ×ª××š×× ××¡××××. ×× ×××§ ×××€×Š××× ×× ×××××€××©}
+_textstartdate_ [l=he] {×ª××š×× (×× ×š×§ ) ××ª×××}
+_textenddate_ [l=he] {×ª××š××  ×¡×××:}
+_textbc_ [l=he] {××€× × ××¡×€××š×}
+_textad_ [l=he] {××¡×€××š×}
+_textexplaineras_ [l=he] {×××ª××.C.E. -× B.C.E -×   A.D. -×  B.C. ××××¡×§×, ××©××× ×××× ××ª ××××××× ××ª×š×××ª× ×××¡×× ××ª ××€× × ××××š× ××¡×€××š× 
+ ××× ××©××©×× × -  "××¡×€××š×" ×-"××€× × ××¡×€××š×" ×××ª×××}
+
+_textstemon_ [l=he] {(××ª×¢××  ××¡××××ª ×©× ××××× )}
+
+_textsearchhistory_ [l=he] {××¡×××š×××ª ×××€××©}
+
+#text macros for search history
+_textnohistory_ [l=he] {×××¡×××š×××ª ×××€××© ×× ×××× ×}
+_texthresult_ [l=he] {×ª××Š××}
+_texthresults_ [l=he] {×ª××Š×××ª}
+_texthallwords_ [l=he] {×× ××××××}
+_texthsomewords_ [l=he] {××§ ×©× ××××××}
+_texthboolean_ [l=he] {××××× ×}
+_texthranked_ [l=he] {×××××}
+_texthcaseon_ [l=he] {×××× ×××ª×××  ×××× ××××ª×××ª}
+_texthcaseoff_ [l=he] {×©×××š ×¢× ×××× ×××××}
+_texthstemon_ [l=he] {× ×¢×Š×š}
+_texthstemoff_ [l=he] {×××©×× ××× ×¢×Š××š×}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "×©××€××" ## green_title ## h_search ##
+_httpiconhsearch_ [l=he] {_httpimg_/he/h\_search.gif}
+_widthhsearch_ [l=he] {200}
+_heighthsearch_ [l=he] {57}
+
+## "×ª×××Š××ª" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=he] {_httpimg_/he/qryresb.gif}
+_widthqryresb_ [l=he] {_pagewidth_}
+_heightqryresb_ [l=he] {17}
+
+## "×××š×××¡×" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=he] {_httpimg_/he/schhistb.gif}
+_widthsrchhistb_ [l=he] {_pagewidth_}
+_heightsrchhistb_ [l=he] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=he] {××¢×××€××××ª ×××××š× ××¡××š ××× :
+ ×©× ××€××€× "back" ×× ×ª×©×ª××© ×××€×××š 
+×× ×××× ×××ª× !  ×××§×× ×××ª ×ª×××Š× ×¢× ××€×ª××š×× ××¡×š×× ×××©× ×××¢××}
+_textsetprefs_ [l=he] {××××š×ª ×¢×××€××××ª}
+_textsearchprefs_ [l=he] {×××€××© ×¢×××€××××ª}
+_textcollectionprefs_ [l=he] {×××¡×£ ×¢×××€××××ª}
+_textpresentationprefs_ [l=he] {×ª×Š×××ª ×¢×××€××××ª}
+_textpreferences_ [l=he] {×¢×××€××××ª}
+_textcasediffs_ [l=he] {××××× ×××ª×××ª ×§×× ××ª/××××××ª}
+_textignorecase_ [l=he] {××ª×¢×× ×××××× ×××ª×××ª ×§×× ××ª/××××××ª}
+_textmatchcase_ [l=he] {×××× ×××ª×××ª ×Š×š×× ×××××ª ××ª×××}
+_textwordends_ [l=he] {×¡×××××ª ×××××}
+_textstem_ [l=he] {×××ª×¢×× ××¡××××ª ×××××}
+_textnostem_ [l=he] {×××× ×©××× ×Š×š××× ×××ª×××}
+_textprefop_ [l=he] {×§××©××š×× _maxdocoption_ ××××š ×¢× }
+_textextlink_ [l=he] {××××Š×× ××× Web ×××©× ×××€×× }
+_textintlink_ [l=he] {××§××š××ª ×××€×¡×× ×××××š× ×  }
+_textlanguage_ [l=he] {:×©×€×ª ×××©×§}
+_textencoding_ [l=he] {:×§××××}
+_textformat_ [l=he] {:×€××š×× ××××©×§}
+_textall_ [l=he] {×××}
+_textquerymode_ [l=he] {×¡×× ××©××××ª×}
+_textsimplemode_ [l=he] {×¡×× ×€×©×× ×©× ××©××××ª×}
+_textadvancedmode_ [l=he] {×¡×× ××ª×§×× ×©× ××©××××ª× ×××©×š ×©××××© ××××€××© ××××× × ×¢× ×©××××© ×- !,&,| ××¡×××š×××}
+_textlinkinterm_ [l=he] {××š× ××£ ×××ª×××}
+_textlinkdirect_ [l=he] {×¢×××š ××©×š ××©×}
+_textdigitlib_ [l=he] {×¡×€×š××× ××××××××ª}
+_textweb_ [l=he] {××š×©×ª}
+_textgraphical_ [l=he] {××š×€×}
+_texttextual_ [l=he] {×××××}
+_textcollectionoption_ [l=he] {<p>
+×ª×ª ××××¡×€××  ××××<br>}
+
+_textrelateddocdisplay_ [l=he] {××Š× ××€×¡×× ×§×©××š××}
+_textsearchhistory_ [l=he] {:××¡×××š×××ª ×××€××©}
+# -- Missing translation: _textnohistory_
+_texthistorydisplay_ [l=he] {×××Š×× ××¡×××š×××ª ×××€××©}
+_textnohistorydisplay_ [l=he] {×× ×××Š×× ××¡×××š×××ª ×××€××©}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=he] {×××€××©  ×Š××š××ª}
+# -- Missing translation: _textplainsearch_
+_textqueryboxsize_ [l=he] {×××× ×ª××š ××©××××ª××ª}
+_textregbox_ [l=he] {×ª××š ×š××× ×©× ××©××××ª××ª}
+_textbigbox_ [l=he] {×ª××š ××š×× ×©× ××©××××ª××ª}
+_textformtype_ [l=he] {×¡×× ××××××}
+_textsimple_ [l=he] {×€×©××}
+_textadvanced_ [l=he] {××ª×§××}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=he] {×¢×}
+_textfields_ [l=he] {×©×××ª}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "×ª×××€×××¢" ## green_title ## h_pref ##
+_httpiconhpref_ [l=he] {_httpimg_/he/h\_pref.gif}
+_widthhpref_ [l=he] {200}
+_heighthpref_ [l=he] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+# -- Missing translation: _textsortby_
+# -- Missing translation: _textalsoshowing_
+# -- Missing translation: _textwith_
+_textdocsperpage_ [l=he] {××€×¡×× ××£ ×××š× ××£}
+
+_textfilterby_ [l=he] {××€××£ ×š×§ ××ª ×××¡×××× ×××××××}
+_textall_ [l=he] {××ª ×××}
+_textany_ [l=he] {×××§}
+_textwords_ [l=he] {××××××}
+# -- Missing translation: _textleaveblank_
+
+_browsebuttontext_ [l=he] {××€××£}
+
+# -- Missing translation: _nodata_
+# -- Missing translation: _docs_
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=he] {×¢××š×}
+_textSearchshort_ [l=he] {×××€××© ××××× ××¡×××××ª}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=he] {××© ×××Š××š××ª ××€× ×××ª×š×ª}
+_textCreatorshort_ [l=he] {××© ×××Š××š××ª ××€× ××××š}
+_textSubjectshort_ [l=he] {××© ×××Š××š××ª ××€× × ××©×}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=he] {××© ×××Š××š××ª ××€× ×ª××š××}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+# -- Missing translation: _textSourceshort_
+_textLanguageshort_ [l=he] {××© ×××Š××š××ª ××€× ×©×€×}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=he] {××© ×××Š××š××ª ××€× ×¡××š××ª}
+_textToshort_ [l=he] {××© ×××Š××š××ª ××€× ×©×× "××¢×"}
+_textFromshort_ [l=he] {××© ×××Š××š××ª ××€× ×©×× "××§××š"}
+_textBrowseshort_ [l=he] {××Š××š××ª ×××× ××¡}
+_textOrganizationshort_ [l=he] {××© ×××Š××š××ª ××€× ×××š×××}
+_textHowtoshort_ [l=he] {××© ×××Š××š××ª ××€× ×š×©×××}
+_textTopicshort_ [l=he] {××© ×××Š××š××ª ××€× × ××©×}
+_textPeopleshort_ [l=he] {××© ×××Š××š××ª ××€× ×× ×©××}
+_textAcronymshort_ [l=he] {××© ×××Š××š××ª ××€× ×š××©× ×ª××××ª}
+_textPhraseshort_ [l=he] {××× ×¡ ×××××× ×××€××¢×× ×××Š××š××ª}
+# -- Missing translation: _textArtistshort_
+# -- Missing translation: _textKeywordshort_
+# -- Missing translation: _textVolumeshort_
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=he] {××××× ×× ×××××š}
+
+_textSearchlong_ [l=he] {<p> ×©××¢×××. <i> "×××€××©" </I> ××ª× ×××× ×××€×©  ×××××  ××¡××××××ª ×××§×¡××× ×××××Š× ×¢× ××€×ª××š 
+  ×× ×××£ ××š××©××  ××©×š ×¢×××  ×××©×š ××ª× ××ª×××  ×××€×©×š ×××××š ××××  ×××××Š×ª ××€×ª××š}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=he] {<p>  <i> ×××ª×š××ª </i> ××ª× ×××× ×××©×ª ×××Š××š××ª ××€× ×××ª×š××ª ×××××Š×  ×¢× ××€×ª××š
+×× ××¢×× ××ª ×š×©×××ª ×××Š××š××ª ××€× ×-× ×©× ×××ª×š××ª 
+}
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=he] {<p> <I> ××××š××  ×-×ª  </i>   ××ª× ×××× ×××©×ª ×××Š××š××ª ××€× ××××š×× ×××××Š×  ×¢× ××€×ª××š
+×× ××¢×× ××ª ×š×©×××ª ×××Š××š××ª ×××××× ××ª ××€× ×-× ×©× ×©×××ª ××©×€×× ×©× ××××š××}
+
+_textSubjectlong_ [l=he] {<p>  <i> × ××©××× </I>  ××ª× ×××× ×××©×ª ×××Š××š××ª ××€× × ××©××× ×××××Š×  ×¢× ××€×ª××š ×× ××¢×× ××ª ×š×©×××ª ×× ××©×××, ××××Š××× ×¢"× ×××€× ×¡×€×š××
+}
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=he] {<p>  <i> ×ª××š×× </I>××ª× ×××× ×××©×ª ×××Š××š××ª ××€× ×ª××š×× ×××××Š×  ×¢× ××€×ª××š 
+×× ××¢×× ××ª ×š×©×××ª ×××Š××š××ª ××¡×××š××ª ××××€× ××š×× ××××× }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: _textSourcelong_
+
+_textLanguagelong_ [l=he] {<p>  <i> ×©×€× </I> ××ª× ×××× ×××©×ª ×××Š××š××ª ××€× ×©×€××ª ×××××Š×  ×¢× ××€×ª××š 
+ ×× ××¢×× ××ª ×š×©×××ª ××× ××¡××ª ××¡×××š××ª ××€× ×©×€××ª
+}
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=he] {<p> < i>×××š××× ××</i>  ××ª× ×××× ×××©×ª ×××Š××š××ª ××€×  ×××š××× ×× ×××××Š×  ×¢× ××€×ª××š
+ ×× ××¢×× ××ª ×š×©×××ª ×××Š××š××ª ××€× ×××š××× ××}
+
+_textHowtolong_ [l=he] {<p><I> ×××Š× </i>××ª× ×××× ×××©×ª ×××Š××š××ª ××€× ×¡××š ×××Š× ×××××Š×  ×¢×  ××€×ª××š 
+<I> ×××Š×</i>  ×× ××¢×× ××ª ×š×©×××ª ×××Š××š××ª ××€× ×¡××š 
+}
+
+_textTopiclong_ [l=he] {<p>  <i> ×¡××××š×× ×××××××  </I> ××ª× ×××× ×××©×ª ×××Š××š××ª ××€× ×¡××××š×× ××××××× ×××××Š× ×¢× ××€×ª××š
+ ×× ××¢×× ××ª ×š×©×××ª ××¡××××š×× ×××€×××£
+}
+
+_textTolong_ [l=he] {<p>  <i> ××× </I>  ××ª× ×××× ×××©×ª ×××Š××š××ª ××€× ×©×× ××× ×××××Š×  ×¢× ××€×ª××š
+  ×× ××¢×× ××ª ×š×©×××ª  ××××ª×š××ª    
+}
+
+_textFromlong_ [l=he] {<p>  <i> ××¢× </I>  ××ª× ×××× ×××©×ª ×××Š××š××ª ××€× ××¢× ×× ×××××Š×  ×¢× ××€×ª××š
+×× ××¢×× ××ª ×š×©×××ª ××©××××× 
+}
+
+_textSerieslong_ [l=he] {<p>  <i> ×¡××š××ª </I> ××ª× ×××× ×××©×ª ×××Š××š××ª ××€× ×¡××š××ª ×××××Š×  ×¢× ××€×ª××š 
+  ×× ××¢×× ××ª ×š×©×××ª ××¡××š××ª ×©××© ××××¡×£
+}
+
+_textBrowselong_ [l=he] {<p> <i>××€××£</I> ××ª× ×××× ×××€××£ ×××Š××š××ª ×××××Š×  ×¢× ××€×ª××š  }
+
+_textPeoplelong_ [l=he] {<p>  <i> ×× ×©×× </I> ××ª× ×××× ×××©×ª ×××Š××š××ª ××€×  ×× ×©×× ×××××Š×  ×¢× ××€×ª××š 
+ ×× ××¢×× ××ª ×š×©×××ª ××× ××¡××ª ××€× ×©×××ª ××©×€××
+}
+
+_textAcronymlong_ [l=he] {<p>  <i> ×š××©× ×ª××××ª </I>  ××ª× ×××× ×××©×ª ×××Š××š××ª ××€× ×š××©× ×ª××××ª ×××××Š×  ×¢× ××€×ª××š  
+ ×× ××¢×× ××ª ×š××©× ×ª××××ª ×××§×× ××××Š××
+}
+
+_textPhraselong_ [l=he] {<p>  <i>××××××</I>  ××ª× ×××× ×××©×ª ××××××× ××¡××××× ××©×š ×××€×¢×× ×××Š××š××ª ×××××Š×  ×¢× ××€×ª××š </I> 
+   ×× ××¢×× ××€××€× ×©× ×××××× }
+
+# -- Missing translation: _textArtistlong_
+
+# -- Missing translation: _textKeywordlong_
+
+# -- Missing translation: _textVolumelong_
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=he] {<p> ××× ××š×××ª ××Š××š××ª ×¢× ×€×š××× ××¡×š×× ×× ×× ××××¢×× <i> ×× ××××¢</I>  ×××¥ ×¢× ××€×ª××š  
+  (××Š××ª ××××× ××€× ×©×××ª ×× ××××¢××)
+}
+
+_texthelptopics_ [l=he] {<h2 align=left>× ××©×××</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">××× ×××Š×× ××××× ××¡××××××ª</a>
+<ul>
+  <li><a href="\#query-terms">××× ×× ×××€××©</a>
+<li><a href="\#query-type">×¡×× ×©××××ª×</a>
+  <li><a href="\#scope-of-queries">×§×××Š×ª ×©××××ª××ª</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">×¢×××€××××ª ×©× ×××¡×£</a>
+<li><a href="\#lang-prefs"> ×¢×××€××××ª ×©× ×©×€×</a>
+<li><a href="\#pres-prefs"> ×¢×××€××××ª ×©× ×ª×Š××× </a>
+<li><a href="\#search-prefs"> ×¢×××€××××ª ×©× ×××€××©</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=he] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=he] {××× ××§×š×× ××¡××××}
+
+_texthelpreadingdocs_ [l=he] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+
+<p>××€×©×š ×××¢×ª ×× ×××¢×ª ×××¡×× ×××× ××××× ×©××××ª×š×ª ××××××š
+×××€××¢×× ××€×× × ×©×××××ª ×¢×××× × ×©× ××¢×××. ×××¥ ××× ××© ××ª ××¡×€×š  ××¢×××
+×× ××××, ×ª××× ××××€×©×š×ª ××××š×ª ×¢××× ×××© ×××Š×× ×§×××× ×××××š×
+
+<p> ××ª××ª ××© ××ª ×××§×¡× ×©× ××§××¢ ×× ××××. ××××š ×©×§×š××ª ×××ª×
+××ª××ª××ª ××¢××× ××©× × ××€×ª××š×× ×©××§×× ×××ª× ××¢××× ××× ×× ××¢××× ××§×××
+
+<p>××ª××ª ××××ª×š×ª ××××××š ××©× × ×©×××©× ××€×ª××š××. ×××¥ ×¢×
+ ××× ××€×ª×× ××ª ×× ×××§×¡× ×©×××¡××.<i> ××š×× ××§×¡× </i> 
+×× ×××¡×× ××××, ××××š ×××× ××§××ª ××š×× ××× ×××××š××!
+××× ××€×ª×× ×××× ×××© ×¢× ×××¡××..<i>××€×š×  </i> ×××¥ ×¢× 
+××××š ×©××××©× ×××©××××ª ××¡×××× ×× ×§×š××× ×©× ××× ×××§×××
+<i> ××× ××××©× </i> ×× ××¡×£ ×××××ª ××××€××© ×××××©××ª. ×××¥ ×¢×
+××× ×××€×¡××§ ××ª ×××××©×
+<p>
+
+
+
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>×××¥ ×¢× ×××¥ ××¢×××š ××××§ ××× ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... ×× ×××××š ××××§ ××§×××</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>××Š×/×× ×ª×Š×× ××ª ×××§×¡× ××××</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>×€×ª× ×¢××× ×× ××××× ×××©</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>××× ×× ×××€××© ×××××©××/×× ×××××©××</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=he] {<h2> ××× ×××Š×× ××××× ××¡××××××ª </h2>
+<p>
+ :××¢××× ××©××××ª× , ×××××š×× ××ª ××©××××ª× ×××¡×€×š ×Š×¢××× ×€×©××××<p>
+  
+<ol><li>××××š ×××× ×¡××× ×€×š×××× ××© ×××€×©
+<li>×¡×× ×× ××ª× ×š××Š× ×××€×© ××ª ×× ×××××× ×× ×š×§ ×××§ ×××
+      <li>××§×× ××ª ×××××ª ××××€××©
+      <li> <i> ××ª×× ×××€××© </i> ×××¥ ×¢× ××€×ª××š
+</ol>
+
+
+<p>××©××ª× ××€×¢×× ××ª ××©××××ª× , ××××ª×š××ª ×©× ×¢×©×š×× ××€×š×××× ××ª××××× ×××Š××.
+××©× ×××× 2 ××€×ª××š×× ×××× ××¢×©×š×× ××€×š×××× ××××× ×××©× × ××¢×©×š×× ××€×š×××× ××§××××× ××¡××£ ××¢××× ××©× × ××€×ª××š ×©××§× ×××ª× ××¢×©×š×× ××€×š×××× ×××××
+
+
+<p>×××§×¡×××× ×©× ×€×š×××× ×©×××××š× ××× 100
+<i> ×¢×××€××××ª</i> ××€×©×š ××©× ××ª ××ª ×××¡×€×š ×¢"× ××××Š× ×¢× ××€×ª××š
+××ª××××ª  ××¢×××<p>
+
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Search terms</h3>
+
+
+<p>×× ×©×××× ×¡ ×××§×¡× ××©××××ª× ×××¢×× ××š×©××× ×©× ××××× 
+×× ×§×š×××ª "××× ×× ×××€××©". ×× ××× × ×××× ×š×§ ×××ª×××ª ×××¡×€×š××. 
+×××× ××× ×××€×š××× ×¢"× ×š×××. ×× ×¡××× × ×€××¡××§ ×××€××¢××ª ××ª×× ××××××, ××
+××©××©××ª ××š×××, ×××××š ××× ××ª×¢×××× ×××. ×× ××€×©×š ×××€×© ××××× 
+×××××××ª ×¡××× × ×××€××© 
+
+
+<p>×××××× ××©××××ª×<p>
+<ul><kbd>××§××××ª ×××× ××××§×× ××¡ ××©×§×: ××¢×š×××ª × ×ª××××ª (1993)</kbd></ul>
+<p>×ª×¢××× ×××××§ ×××<p>
+<ul><kbd> ××§××××ª ×××× ××××§×× ××¡ ××©×§× ××¢×š×××ª × ×ª××××ª 1993</kbd></ul><p>
+
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Query type</h3>
+
+
+<p>××©× × ×©× × ×¡××× ×©××××ª××ª
+
+
+
+<ul>
+  <li> ××××××. ××©××××ª××ª <b> ××</b> ×©××××ª××ª ×¢×××š
+	×××× ×××€×©××ª ×××š ××€×š×××× ××××××× ××ª ×× ××××××
+	××€×š×××× ×××Š××× ××¡××š ×"×
+<p>
+
+<li> ×××××××. ××©××××ª××ª <b> ×××§</b> ×©××××ª××ª ×¢×××š
+	×××× ×××€×©××ª ×××š ××€×š×××× ××××××× ××ª ×× ××××××
+	××€×š×××× ×××Š××× ××¡××š ×××ª××× ××©××××ª×
+      <p><ul>
+<li> ×€×š×××× ××××××× ×××ª×š ××× ×× ×××€××© ×× ×××ª××××× ×××ª×š 
+<li> ××× ××× × ×××š×× ××©×××× ×××ª×§ ×××©×š ×š××××× 
+<li> ××¡×××× ×§×Š×š×× ××ª××××× ×××ª×š ×××©×š ××š××××
+</ul>
+</ul>
+
+<p>××©×ª××© ×××× ××× ×× ×××€××© ×©× ×× ××- ××©×€× ×× ××€××× ×€××¡×§×
+×× ×××× ×š×§ ××× × ×××€××© ××××, ×××¡×××× ××¡×××š× ××€× ××¡×€×š ××××€×¢×× ×©× ××× × ××××€××©
+<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=he] {×××€××© ×¢× ×ª××š××××}
+
+_texthelpdatesearch_ [l=he] {<h2>_textdatesearch_</h2>
+×××€××© ×¢× ×ª××š×××× × ××ª× ××€×©×š××ª ××§×× ×€×š×××× ××©×š ×××¥ ××× ×©××ª×××××
+×××× ×× ×××€××© ×× ××©×ª××××× ×××× ××¡××××. ××€×©×š ×××€×© ××€× ×©× × ××¡×××××ª ×× ×š×Š×£ ×©× ×©× ××
+××€×©×š ×××ª×©××© ××××€××© ××€× ×ª××š×× ×× ××× ××× ×× ×××€××©: ××€×š×××× ×©×××××š× ××©×ª×××× ××š×Š×£ ×××× ××××××š
+×× ××©×ª××©×× ××××€××© ×š××× ××× ×××€××© ××€× ×ª××š×× ××€×š×××× ×©×××××š× ×××××š× ××× ×ª×××ª ××ª××š××
+<p>
+
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>××× ×××©×ª××© ××××€××©</h3>
+<ul>
+<p><li>×××€×© ×××š ××¡×× ××©× × ××¡×××××ª
+<ul>
+<li>××× ×¡ ××× ×× ×××€××© ××š×××     
+<li>××× ×¡ ×©× × ×š×Š×××× × ×××× "××ª×××"
+<li>×× ××©× × ××× ××€× ×"×¡ , ×¡×× ××€× ×"×¡ ××š×©×××ª ×××××× 
+<li>××ª×× ××××€××© ××š×××
+</ul>
+<p><li>:×××€×© ××¡×× ××©× ××<p>
+   <ul>
+       <li> ××× ×¡ ××× ×× ×××€××© ××š×××
+<li> "××× ×¡ ×©× ×ª ××ª××× ×š×Š×××× × ×××× "××ª×××
+<li> ××× ×¡ ×©× ×ª ×¡××× ×š×Š×××× × ×××× "×¡××£"
+<li> ×× ××©× × ××× ××€× ×"×¡ , ×¡×× ××€× ×"×¡ ××š×©×××ª ××××××
+<li> ××ª×× ××××€××© ××š××× 
+</ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>××š× ×©×× ××××€××© ×€××¢×</h3>
+
+<p> ×××€×©×× ××¡×××× ×©× ××ª×× × - 1903, ××š×× × ×§×× ××¡×××× ×¢× ××©× × ××× ××× ××©×š × ××ª×× ××©× × ×× "×
+}
+
+_textchangeprefs_ [l=he] {×©×× ×× ×¢×××€××××ª}
+
+_texthelppreferences_ [l=he] {<h2>_textchangeprefs_</h2>
+
+
+<p>×× ×ª×××¥ ×¢× ××€×ª××š "×¢×××€××××ª" ××ª××××ª ×××£ , ×ª××× ×× ××€×©×š××ª ××©× ××ª
+××ª ×€×¢××××ª ×× ××××©×§ ×× ×©××ª××× ××Š×š×××
+
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>×¢×××€××××ª ××××¡×£</h3>
+
+
+××©× × ×××¡×€×× ××××š×××× ×××× ×ª×ª-×××¡×€×× , ××©×š × ××ª× ×× ××¢××× ×××××€××© 
+×× ×€×š× ×× ××××, ×××××× ×××ª. ×× ×× ××××š , ××¢××× ××¢×××€××××ª × ××ª×
+ ××¡×× ×××× ×××ª×ª-×××¡×€×× ××© ×××××× ××××€××©
+
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>×©×€× ×¢×××€××××ª </h3>
+
+×× ×××¡×£ × ×× × ×¢×××š ×©×€× ××¡×××××ª , ×× × ××ª× ××©× ××ª ×××ª
+××× ×× ××€×©×š ××©× ××ª ××× ×××Š×× ××š×€× ××××Š×× ××§×¡× ××š×××
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left> ×¢×××€××××ª ×ª×Š×××</h3>
+
+×××ª×× ××××¡×£ ×× ×ª×× ××©× × ××× ××š××× ××©× ××ª ××ª ×ª×Š×××ª×
+
+
+
+<p>  Greenstone×××¡×€×× ×©× ××€× ×š×©×ª ×××€×©×š×× ×× ×××× ××ª ××€×ª××š× ×× ×××× ×©×    
+××ª××××ª ××¢××× , ××  ×©××××š ××©××××ª× ××ª× ×ª×××¢ ××©××š××ª ××¢××× ××š×©×ª ×©×××ª× ×××€×©×ª ××× ××€×ª××š× ××××€××©. ×××× ×××Š×¢ 
+×××€××© ×××© ××© ×××©××© ×××€×ª××š "××××š×" . ××××¡×€×× ×× ×××€×©×š×× ×× ×××× ××ª ×××××š×  ×××××š ××××Š× ×¢× ×××××š ××××Š× ×××××¡×£ ××š×©×ª ×¢×Š××.
+××× ×× ×××× ×××¡×€×× ××€×©×š ××©××× ××× ××××××š×× ×××××× ×××€× ××š×©×ª ××š×©×ª ×× ××¢××ª×§×× ×©××× ×©× ××Š××× ××¡×€×š××
+
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>×¢×××€××××ª ×××€××© </h3>
+
+
+<p>×©× × ×××××ª ××€×ª××š×× ×©××××× ×¢× ×¢×××€××××ª ××××€××©:
+×××× ××š××©×× ××× × ×š×××× ×× ××©×€× ××¢××š××ª ( ×××ª×××ª ××××××ª ××§×× ××ª)
+×××× ××©× × ×©××× ××× ×¡×××××ª ×××××× ×××××× ××××€××©.
+ ××× ×× ××© ××€×©×š××ª ××§×× ×©×× ××× × ×××× ×××ª×š. ×××€××© ×¢× ××š××
+ ××× ××× ××× ×××€××© ××××š ××××
+
+
+<p>×××××× ×× ××€×ª××š "××ª×¢×× ××¡×××××ª ××××××" ×××× ××××§ ××××€××©
+<ul><kbd>××× ×× ××€×š××§×××× </kbd></ul>
+      <p>××ª×§×× ×××
+     <ul><kbd>××× × ××€×š××§×</kbd></ul><p>
+
+<p>××€×©×š ×××€×¢×× ×××€××© ××ª×§×× ×©× ××ª× ×××€×¢××××× ××× ×××××× ××× ×××
+××× & , ×× | , ××× !.
+××š××š×ª ×××××  ( ×š××× ) ××× ×××
+××××š ×××€×©×š ×××€××© ××××××§ ×××ª×š
+××€×©×š ×××€×¢×× ××ª ×××€×Š×××ª ×××××š××: ××××š ×××€×©×š ×××€×¢×× ×××€××©×× ×××©××
+×× ××š×¡×××ª ×©×× ××ª ×××§×Š×ª ×©× ×××€××©×× ×§×××××
+}
+
+_texttanumbrowseoptions_ [l=he] {××š××× ×××Š×× ××ª ×××××¢ ××××¡×£ ×× "×  _numbrowseoptions_ ××©
+}
+
+_textsimplehelpheading_ [l=he] {××× ×××Š×× ××××¢}
+
+_texthelpscope_ [l=he] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>×¡×××š×ª ×©××××ª××ª</h3>
+
+
+<p>
+××š×× ××××¡×€×× × ××ª× ×××××š ××× ××¡×€×š ××× ××§×¡×× ××××€××©. ×××××× ×××× ×××××ª ××× ××§×¡ ×©× ××××š××
+ ×× ×××ª×š××ª, ×× ×××× ×××××ª ××× ××§×¡ ×©× ×€×š×§××, ×× ×©× ×€×¡×§×××ª. ×××××ª, ×××××š× ×××¡×××× ××××××
+××× ×ª×××ª ×××š× ××××€××©. ×× ×××¡×× ××× ×¡×€×š, ××× ×××€×ª× ×××§×× ××ª××
+<p>   
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/help.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/help.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/help.dm	(revision 10506)
@@ -0,0 +1,33 @@
+# this file must be UTF-8 encoded
+
+package help
+
+_imagethispage_ {_iconthispage_}
+_iconthispage_ {<img src="_httpiconhhelp_" alt="_textHelp_" title="_textHelp_" width=_widthhhelp_ height=_heighthhelp_>}
+
+# don't want collection icon on help page as much of the text is not collection specific
+_imagecollection_ {}
+
+_textnumbrowseoptions_ {_If_("_numbrowseoptions_" != "1",<p>_texttanumbrowseoptions_)}
+
+_simplehelp_ {
+_textnumbrowseoptions_
+_textbrowseoptions_
+}
+
+_content_ {
+<center>_optnavigationbar_</center>
+_texthelptopics_
+<p>_iconblankbar_
+<a name=finding-information>
+<h2>_textsimplehelpheading_</h2>
+_simplehelp_
+_texthelpreadingdocs_
+<p>_iconblankbar_
+<a name=searching>
+_texthelpsearching_
+<p>_iconblankbar_
+<a name=preferences>
+_texthelppreferences_
+<p>_iconblankbar_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/hindi.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/hindi.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/hindi.dm	(revision 10506)
@@ -0,0 +1,1492 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Hindi Language text and icon macros (translated from english.dm
+# 2 July 2002)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textperiodicals_
+# -- Missing translation: _textsource_
+# -- Missing translation: _textdate_
+# -- Missing translation: _textnumpages_
+
+# -- Missing translation: _textsignin_
+
+# -- Missing translation: _textdefaultcontent_
+
+_textdefaulttitle_ [l=hi] {à€à€¿. à€à€žà¥. à€¡à€¿.
+à€à€²à¥. à€ à€Šà¥à€·}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+# -- Missing translation: _collectionextra_
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+# -- Missing translation: _collectorextra_
+
+_textimagecollection_ [l=hi] {}
+# -- Missing translation: _textimageabout_
+_textimagehome_ [l=hi] {à€®à¥à€ à€ªà¥à€·à¥à€ }
+_textimagehelp_ [l=hi] {à€žà€¹à€Ÿà€¯à€ à€ªà¥à€·à¥à€ }
+_textimagepref_ [l=hi] {à€à¥à€šà€Ÿà€µ à€ªà¥à€·à¥à€ }
+_textimagegreenstone_ [l=hi] {à€à¥à€°à¥à€šà¥ à€žà¥à€à¥à€šà¥
+à€¡à€¿à€à€¿à€à€²à¥ à€²à¥à€¬à¥à€°à€°à€¿ 
+à€žà€«à¥à€à€µà¥à€°à¥}
+# -- Missing translation: _textimageusab_
+
+_textimagesearch_ [l=hi] {à€šà€¿à€¶à¥à€à€¿à€€
+à€¶à€µà¥à€Šà¥à€à€à¥ à€à¥à€à€¿à€ à¥€}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=hi] {à€¶à¥à€°à¥à€·à€à€šà€Ÿ à€à¥ à€µà€°à¥à€£à€®à€Ÿà€²à€Ÿ
+à€à€¿ à€žà¥à€à¥ à€à¥ à€
+à€šà¥à€žà€Ÿà€° à€à€°à€šà€Ÿ
+à€à¥à€à€¿à€}
+_textimageCreator_ [l=hi] {à€²à¥à€à€à¥ à€à¥ à€µà€°à¥à€£à€®à€Ÿà€²à€Ÿ
+à€à€¿ à€žà¥à€à¥ à€à¥ à€
+à€šà¥à€žà€Ÿà€° à€à€°à€šà€Ÿ
+à€à¥à€à€¿à€ à¥€}
+_textimageSubject_ [l=hi] {à€µà€¿à€·à€¯ à€à¥ à€
+à€šà¥à€žà€Ÿà€° à€à€°à€šà€Ÿ
+à€à¥à€à€¿à€ à¥€}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=hi] {à€€à€Ÿà€°à¥à€ à€à¥ à€
+à€šà¥à€žà€Ÿà€° à€à€°à€šà€Ÿ
+à€à¥à€à€¿à€ à¥€}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+# -- Missing translation: _textimageSource_
+# -- Missing translation: _textimageLanguage_
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=hi] {à€žà€à€à€ à€š à€à¥ à€
+à€šà¥à€žà€Ÿà€° à€à€°à€šà€Ÿ
+à€à¥à€à€¿à€ à¥€}
+# -- Missing translation: _textimageKeyword_
+_textimageHowto_ [l=hi] {à€à¥à€žà¥ à€µà€°à¥à€à¥ à€à¥ à€à€°à€šà€Ÿ
+à€à¥à€à€¿à€ à¥€}
+_textimageList_ [l=hi] {à€Šà€žà¥à€€à€Ÿà€µà¥à€ à€žà¥à€à¥ à€à¥
+à€
+à€šà¥à€žà€Ÿà€° à€à€°à€šà€Ÿ à€à¥à€à€¿à€ à¥€}
+_textimageSeries_ [l=hi] {à€¶à¥à€°à¥à€£à¥ à€à¥ à€
+à€šà¥à€žà€Ÿà€° 
+à€à€°à€šà€Ÿ à€à¥à€à€¿à€ à¥€}
+# -- Missing translation: _textimageTo_
+# -- Missing translation: _textimageFrom_
+_textimageTopic_ [l=hi] {à€ªà¥à€°à€žà€à€ à€à¥ à€
+à€šà¥à€žà€Ÿà€° à€à€°à€šà€Ÿ
+à€à¥à€à€¿à€ à¥€}
+_textimageBrowse_ [l=hi] {à€à€°à€šà€Ÿ à€à¥à€à€¿à€ à¥€}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=hi] {à€²à¥à€ à€à¥
+à€µà€°à¥à€£à€®à€Ÿà€²à€Ÿ à€à€¿ à€žà¥à€à¥
+à€à¥ à€
+à€šà¥à€žà€Ÿà€° à€à€°à€šà€Ÿ
+à€à¥à€à€¿à€ à¥€}
+# -- Missing translation: _textimageAcronym_
+# -- Missing translation: _textimagePhrase_
+# -- Missing translation: _textimageArtist_
+# -- Missing translation: _textimageVolume_
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=hi] {à€à¥à€}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=hi] {à€¶à¥à€°à¥à€·à€à€šà€Ÿ A-Z}
+_texticontabCreatorgreen_ [l=hi] {à€²à¥à€à€ A-Z}
+_texticontabSubjectgreen_ [l=hi] {à€µà€¿à€·à€¯à¥}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=hi] {à€€à€Ÿà€°à¥à€}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+# -- Missing translation: _texticontabSourcegreen_
+# -- Missing translation: _texticontabLanguagegreen_
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=hi] {à€žà€à€à€ à€š}
+# -- Missing translation: _texticontabKeywordgreen_
+_texticontabhowgreen_ [l=hi] {à€à¥à€žà¥?}
+_texticontabseriesgreen_ [l=hi] {à€¶à¥à€°à¥à€£à¥}
+_texticontablistgreen_ [l=hi] {à€žà¥à€à¥}
+# -- Missing translation: _texticontabtogreen_
+# -- Missing translation: _texticontabfromgreen_
+_texticontabtopicgreen_ [l=hi] {à€ªà¥à€°à€žà€à€}
+_texticontabbrwsegreen_ [l=hi] {à€à€°à€šà€Ÿ}
+# -- Missing translation: _texticontabCollagegreen_
+# -- Missing translation: _texticontabbrowsgreen_
+_texticontabPeoplegreen_ [l=hi] {à€²à¥à€ A-Z}
+# -- Missing translation: _texticontabAcronymgreen_
+# -- Missing translation: _texticontabPhrasegreen_
+# -- Missing translation: _texticontabArtistgreen_
+# -- Missing translation: _texticontabVolumegreen_
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=hi] {à€Šà€žà¥à€€à€Ÿà€µà¥à€
+à€à¥ à€Šà¥à€à€¿à€}
+_texticonclosedbook_ [l=hi] {à€Šà€žà¥à€€à€Ÿà€µà¥à€
+à€à¥ à€à¥à€² à€à¥ à€Šà¥à€à€¿à€}
+_texticonnext_ [l=hi] {à€
+à€à€²à€Ÿ à€­à€Ÿà€à€šà€Ÿ à€à¥ à€²à€¿à€}
+_texticonprev_ [l=hi] {à€ªà€¹à€²à€Ÿ à€­à€Ÿà€à€šà€Ÿ à€à¥ à€²à€¿à€}
+
+# -- Missing translation: _texticonworld_
+
+# -- Missing translation: _texticonmidi_
+# -- Missing translation: _texticonmsword_
+# -- Missing translation: _texticonmp3_
+# -- Missing translation: _texticonpdf_
+# -- Missing translation: _texticonps_
+# -- Missing translation: _texticonppt_
+# -- Missing translation: _texticonrtf_
+# -- Missing translation: _texticonxls_
+
+_page_ [l=hi] {à€ªà¥à€·à¥à€  }
+_pages_ [l=hi] {à€ªà¥à€·à¥à€ }
+_of_ [l=hi] {à€®à¥à€}
+_vol_ [l=hi] {à€ªà¥à€¥à¥}
+_num_ [l=hi] {à€žà€à€à¥à€¯à€Ÿ}
+
+_textmonth00_ [l=hi] {}
+_textmonth01_ [l=hi] {à€à€šà€µà€°à€¿}
+_textmonth02_ [l=hi] {à€«à¥à€¬à¥à€°à€µà€°à€¿}
+_textmonth03_ [l=hi] {à€®à€Ÿà€°à¥à€}
+_textmonth04_ [l=hi] {à€
+à€ªà¥à€°à¥à€²à¥}
+_textmonth05_ [l=hi] {à€®à¥}
+_textmonth06_ [l=hi] {à€à¥à€šà¥}
+_textmonth07_ [l=hi] {à€à¥à€²à¥}
+_textmonth08_ [l=hi] {à€à€à€žà¥à€}
+_textmonth09_ [l=hi] {à€žà¥à€ªà¥à€à€à€¬à€°à¥}
+_textmonth10_ [l=hi] {à€
+à€à¥à€à¥à€¬à€°à¥}
+_textmonth11_ [l=hi] {à€šà€µà€à€¬à€°à¥}
+_textmonth12_ [l=hi] {à€Šà€¿à€žà€à€¬à€°à¥}
+
+# -- Missing translation: _textdocument_
+# -- Missing translation: _textsection_
+# -- Missing translation: _textparagraph_
+
+# -- Missing translation: _magazines_
+
+# -- Missing translation: _nzdlpagefooter_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: chome
+# -- Missing translation: _httpiconchomeof_
+# -- Missing translation: _httpiconchomeon_
+
+# -- Missing translation: chelp
+# -- Missing translation: _httpiconchelpof_
+# -- Missing translation: _httpiconchelpon_
+
+# -- Missing translation: cpref
+# -- Missing translation: _httpiconcprefof_
+# -- Missing translation: _httpiconcprefon_
+
+# -- Missing translation: cusab
+# -- Missing translation: _httpiconcusabof_
+# -- Missing translation: _httpiconcusabon_
+
+
+# -- Missing translation: tsrch
+# -- Missing translation: _httpicontsrchgr_
+# -- Missing translation: _httpicontsrchof_
+# -- Missing translation: _httpicontsrchon_
+# -- Missing translation: _widthtsrchx_
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: ttitl
+# -- Missing translation: _httpiconttitlegr_
+# -- Missing translation: _httpiconttitleof_
+# -- Missing translation: _httpiconttitleon_
+# -- Missing translation: _widthttitlex_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: tauth
+# -- Missing translation: _httpicontcreatgr_
+# -- Missing translation: _httpicontcreatof_
+# -- Missing translation: _httpicontcreaton_
+# -- Missing translation: _widthtcreatx_
+
+# -- Missing translation: tsubj
+# -- Missing translation: _httpicontsubjgr_
+# -- Missing translation: _httpicontsubjon_
+# -- Missing translation: _httpicontsubjof_
+# -- Missing translation: _widthtsubjx_
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+# -- Missing translation: tdate
+# -- Missing translation: _httpicontdategr_
+# -- Missing translation: _httpicontdateof_
+# -- Missing translation: _httpicontdateon_
+# -- Missing translation: _widthtdatex_
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: tsrc
+# -- Missing translation: _httpicontsrcgr_
+# -- Missing translation: _httpicontsrcof_
+# -- Missing translation: _httpicontsrcon_
+# -- Missing translation: _widthtsrcx_
+
+# -- Missing translation: tlang
+# -- Missing translation: _httpicontlanggr_
+# -- Missing translation: _httpicontlangon_
+# -- Missing translation: _httpicontlangof_
+# -- Missing translation: _widthtlangx_
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+# -- Missing translation: tser
+# -- Missing translation: _httpicontsergr_
+# -- Missing translation: _httpicontserof_
+# -- Missing translation: _httpicontseron_
+# -- Missing translation: _widthtserx_
+
+# -- Missing translation: tto
+# -- Missing translation: _httpiconttogr_
+# -- Missing translation: _httpiconttoon_
+# -- Missing translation: _httpiconttoof_
+# -- Missing translation: _widthttox_
+
+# -- Missing translation: tfrom
+# -- Missing translation: _httpicontfromgr_
+# -- Missing translation: _httpicontfromon_
+# -- Missing translation: _httpicontfromof_
+# -- Missing translation: _widthtfromx_
+
+# -- Missing translation: torg
+# -- Missing translation: _httpicontorggr_
+# -- Missing translation: _httpicontorgon_
+# -- Missing translation: _httpicontorgof_
+# -- Missing translation: _widthtorgx_
+
+# -- Missing translation: thow
+# -- Missing translation: _httpiconthowgr_
+# -- Missing translation: _httpiconthowon_
+# -- Missing translation: _httpiconthowof_
+# -- Missing translation: _widththowx_
+
+# -- Missing translation: ttopic
+# -- Missing translation: _httpiconttopicgr_
+# -- Missing translation: _httpiconttopicon_
+# -- Missing translation: _httpiconttopicof_
+# -- Missing translation: _widthttopicx_
+
+# -- Missing translation: tbrwse
+# -- Missing translation: _httpicontbrwsegr_
+# -- Missing translation: _httpicontbrwseon_
+# -- Missing translation: _httpicontbrwseof_
+# -- Missing translation: _widthtbrwsex_
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+# -- Missing translation: tpeop
+# -- Missing translation: _httpicontpeopgr_
+# -- Missing translation: _httpicontpeopof_
+# -- Missing translation: _httpicontpeopon_
+# -- Missing translation: _widthtpeopx_
+
+# -- Missing translation: tacro
+# -- Missing translation: _httpicontacrogr_
+# -- Missing translation: _httpicontacroof_
+# -- Missing translation: _httpicontacroon_
+# -- Missing translation: _widthtacrox_
+
+# -- Missing translation: tphrse
+# -- Missing translation: _httpicontphrsegr_
+# -- Missing translation: _httpicontphrseof_
+# -- Missing translation: _httpicontphrseon_
+# -- Missing translation: _widthtphrsex_
+
+# -- Missing translation: tartst
+# -- Missing translation: _httpicontartstgr_
+# -- Missing translation: _httpicontartstof_
+# -- Missing translation: _httpicontartston_
+# -- Missing translation: _widthtartstx_
+
+# -- Missing translation: tkw
+# -- Missing translation: _httpicontkwgr_
+# -- Missing translation: _httpicontkwof_
+# -- Missing translation: _httpicontkwon_
+# -- Missing translation: _widthtkwx_
+
+# -- Missing translation: tvol
+# -- Missing translation: _httpicontvolgr_
+# -- Missing translation: _httpicontvolof_
+# -- Missing translation: _httpicontvolon_
+# -- Missing translation: _widthtvolx_
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+# -- Missing translation: h_help
+# -- Missing translation: _httpiconhhelp_
+# -- Missing translation: _widthhhelp_
+# -- Missing translation: _heighthhelp_
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=hi] {à€¯à€¹ à€žà€à€à¥à€°à€¹
+à€à¥ à€žà€à€¬à€à€§ à€®à¥à€}
+
+_textsubcols1_ [l=hi] {<p>à€žà€®à¥à€ªà¥à€°à¥à€£
+à€žà€à€à¥à€°à€¹ _1_ à€à€ª à€žà€à€à¥à€°à€¹à¥à€
+à€žà¥ à€­à€šà€Ÿ à€¹à¥ à¥€:
+<blockquote>}
+
+_textsubcols2_ [l=hi] {</blockquote>
+à€
+à€ª à€à€¹à€¿à€ à€€à¥ à€à¥à€šà€Ÿà€µ
+à€ªà¥à€·à¥à€  à€®à¥à€ à€à¥à€
+à€à€ªà€žà€à€à¥à€°à€¹ à€à¥ à€ªà€°à¥à€à¥à€·
+à€à€° à€žà€à¥à€€à¥ à€¹à¥ à¥€}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_about
+# -- Missing translation: _httpiconhabout_
+# -- Missing translation: _widthhabout_
+# -- Missing translation: _heighthabout_
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=hi] {à€¶à¥à€°à¥à€·à€à€šà€Ÿ}
+_texticonhcreat_ [l=hi] {à€²à¥à€à€}
+_texticonhsubj_ [l=hi] {à€µà€¿à€·à€¯à¥}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=hi] {à€€à€Ÿà€°à¥à€}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+# -- Missing translation: _texticonhsrc_
+# -- Missing translation: _texticonhlang_
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+# -- Missing translation: _texticonhto_
+# -- Missing translation: _texticonhfrom_
+_texticonhser_ [l=hi] {à€¶à¥à€°à¥à€£à¥}
+_texticonhhow_ [l=hi] {à€à¥à€žà¥?}
+_texticonhorg_ [l=hi] {à€žà€à€à€ à€š}
+_texticonhbrwse_ [l=hi] {à€à€°à€šà€Ÿ}
+# -- Missing translation: _texticonhbrows_
+_texticonhpeople_ [l=hi] {à€²à¥à€}
+# -- Missing translation: _texticonhacronym_
+# -- Missing translation: _texticonhphrases_
+# -- Missing translation: _texticonhartist_
+# -- Missing translation: _texticonhkw_
+# -- Missing translation: _texticonhvol_
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=hi] {à€à¥ à€à€ž à€­à€Ÿà€ 
+à€à¥ à€¬à€šà¥à€Š à€à¥à€à€¿à€ à¥€}
+_texticonclosedbookshelf_ [l=hi] {à€à¥ à€à€ž à€­à€Ÿà€ 
+à€à¥ à€à¥à€² à€à¥ à€Šà¥à€à€¿à€ à¥€}
+_texticonopenbook_ [l=hi] {à€à€ž à€à€¿à€€à€Ÿà€¬
+à€à¥ à€¬à€šà¥à€Š à€à¥à€à€¿à€ à¥€}
+_texticonclosedfolder_ [l=hi] {à€à€ž à€ªà¥à€²à¥à€¡à€°à¥ à€à¥ 
+à€à¥à€² à€à¥ à€Šà¥à€à€¿à€ à¥€}
+_texticonclosedfolder2_ [l=hi] {à€à€ª-à€žà€à€à¥à€°à€¹
+à€à¥ à€à¥à€²à€¿à€ à¥€}
+_texticonopenfolder_ [l=hi] {à€à€ž à€ªà¥à€²à¥à€¡à€°à¥ à€à¥ 
+à€¬à€šà¥à€Š à€à¥à€à€¿à€ à¥€}
+_texticonopenfolder2_ [l=hi] {à€à€ª-à€žà€à€à¥à€°à€¹
+à€à¥ à€¬à€šà¥à€Š à€à¥à€à€¿à€ à¥€ }
+_texticonsmalltext_ [l=hi] {à€à€ž à€­à€Ÿà€ à€à¥ 
+à€®à¥à€²à€¶à€¬à¥à€Šà¥à€
+à€à¥ à€Šà¥à€à€¿à€ à¥€}
+_texticonsmalltext2_ [l=hi] {à€®à¥à€²à€¶à€¬à¥à€Šà¥à€
+à€à¥ à€Šà¥à€à€¿à€ à¥€ }
+_texticonpointer_ [l=hi] {à€ªà¥à€°à€à€²à€¿à€€ à€­à€Ÿà€ à¥€}
+_texticondetach_ [l=hi] {à€à€ž à€ªà¥à€·à¥à€ 
+à€à¥ à€šà€¯à€Ÿ à€à€¿à€¡à€à¥
+à€®à¥à€ à€à¥à€²à€¿à€ à¥€}
+_texticonhighlight_ [l=hi] {à€à¥à€ à€à¥à€¯à€Ÿ à€ªà€Šà¥à€ à€à¥
+à€¹à¥à€²à¥à€ à€à¥à€à€¿à€ à¥€}
+# -- Missing translation: _texticonnohighlight_
+# -- Missing translation: _texticoncontracttoc_
+# -- Missing translation: _texticonexpandtoc_
+# -- Missing translation: _texticonexpandtext_
+# -- Missing translation: _texticoncontracttext_
+_texticonwarning_ [l=hi] {<b> </b>}
+# -- Missing translation: _texticoncont_
+
+_textltwarning_ [l=hi] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_ _imagecont_
+</td></tr></table></center>
+}
+
+# -- Missing translation: _textgoto_
+_textintro_ [l=hi] {<i></i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_title
+# -- Missing translation: _httpiconhtitle_
+# -- Missing translation: _widthhtitle_
+# -- Missing translation: _heighthtitle_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_auth
+# -- Missing translation: _httpiconhcreat_
+# -- Missing translation: _widthhcreat_
+# -- Missing translation: _heighthcreat_
+
+# -- Missing translation: h_subj
+# -- Missing translation: _httpiconhsubj_
+# -- Missing translation: _widthhsubj_
+# -- Missing translation: _heighthsubj_
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+# -- Missing translation: h_date
+# -- Missing translation: _httpiconhdate_
+# -- Missing translation: _widthhdate_
+# -- Missing translation: _heighthdate_
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_src
+# -- Missing translation: _httpiconhsrc_
+# -- Missing translation: _widthhsrc_
+# -- Missing translation: _heighthsrc_
+
+# -- Missing translation: h_lang
+# -- Missing translation: _httpiconhlang_
+# -- Missing translation: _widthhlang_
+# -- Missing translation: _heighthlang_
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+# -- Missing translation: h_to
+# -- Missing translation: _httpiconhto_
+# -- Missing translation: _widthhto_
+# -- Missing translation: _heighthto_
+
+# -- Missing translation: h_from
+# -- Missing translation: _httpiconhfrom_
+# -- Missing translation: _widthhfrom_
+# -- Missing translation: _heighthfrom_
+
+# -- Missing translation: h_ser
+# -- Missing translation: _httpiconhser_
+# -- Missing translation: _widthhser_
+# -- Missing translation: _heighthser_
+
+# -- Missing translation: h_how
+# -- Missing translation: _httpiconhhow_
+# -- Missing translation: _widthhhow_
+# -- Missing translation: _heighthhow_
+
+# -- Missing translation: h_topic
+# -- Missing translation: _httpiconhtopic_
+# -- Missing translation: _widthhtopic_
+# -- Missing translation: _heighthtopic_
+
+# -- Missing translation: h_org
+# -- Missing translation: _httpiconhorg_
+# -- Missing translation: _widthhorg_
+# -- Missing translation: _heighthorg_
+
+# -- Missing translation: h_brwse
+# -- Missing translation: _httpiconhbrwse_
+# -- Missing translation: _widthhbrwse_
+# -- Missing translation: _heighthbrwse_
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+# -- Missing translation: h_people
+# -- Missing translation: _httpiconhpeople_
+# -- Missing translation: _widthhpeople_
+# -- Missing translation: _heighthpeople_
+
+# -- Missing translation: h_acro
+# -- Missing translation: _httpiconhacronym_
+# -- Missing translation: _widthhacronym_
+# -- Missing translation: _heighthacronym_
+
+# -- Missing translation: h_phrse
+# -- Missing translation: _httpiconhphrse_
+# -- Missing translation: _widthhphrse_
+# -- Missing translation: _heighthphrse_
+
+# -- Missing translation: h_artist
+# -- Missing translation: _httpiconhartist_
+# -- Missing translation: _widthhartist_
+# -- Missing translation: _heighthartist_
+
+# -- Missing translation: h_kw
+# -- Missing translation: _httpiconhkw_
+# -- Missing translation: _widthhkw_
+# -- Missing translation: _heighthkw_
+
+# -- Missing translation: h_vol
+# -- Missing translation: _httpiconhvol_
+# -- Missing translation: _widthhvol_
+# -- Missing translation: _heighthvol_
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+# -- Missing translation: cont
+# -- Missing translation: _httpiconcontoff_
+# -- Missing translation: _httpiconconton_
+
+# -- Missing translation: eallt
+# -- Missing translation: _httpiconealltof_
+# -- Missing translation: _httpiconeallton_
+
+# -- Missing translation: econc
+# -- Missing translation: _httpiconeconcof_
+# -- Missing translation: _httpiconeconcon_
+
+# -- Missing translation: edtch
+# -- Missing translation: _httpiconedtchof_
+# -- Missing translation: _httpiconedtchon_
+
+# -- Missing translation: eexpc
+# -- Missing translation: _httpiconeexpcof_
+# -- Missing translation: _httpiconeexpcon_
+
+# -- Missing translation: etsec
+# -- Missing translation: _httpiconetsecof_
+# -- Missing translation: _httpiconetsecon_
+
+# -- Missing translation: ehl
+# -- Missing translation: _httpiconehlof_
+# -- Missing translation: _httpiconehlon_
+
+# -- Missing translation: enhl
+# -- Missing translation: _httpiconenhlof_
+# -- Missing translation: _httpiconenhlon_
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=hi] {_If_(_thislast_,à€ªà€°à€¿à€£à€Ÿà€® _thisfirst_ - _thislast_ à€à€ž
+à€ªà¥à€°à€¶à¥à€š à€à¥: _cgiargq_,à€à€ž à€ªà¥à€°à€¶à¥à€š
+à€à€Ÿ à€à¥à€ à€®à¥à€² à€šà€¹à¥à€ à€¹à¥: _cgiargq_)}
+_textnoquerytitle_ [l=hi] {à€à¥à€ à€à€Ÿ à€ªà¥à€·à¥à€  à¥€}
+
+_texticonthispage_ [l=hi] {à€à¥à€}
+_textsome_ [l=hi] {_If_(_cgiargb_,à€ªà€à€à¥à€€à€¿, à€à¥à€)}
+_textall_ [l=hi] {_If_(_cgiargb_,à€¬à¥à€²à€¿à€¯à€šà¥, à€žà€¬)}
+# -- Missing translation: _textboolean_
+# -- Missing translation: _textranked_
+# -- Missing translation: _textnatural_
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=hi] {}
+# -- Missing translation: _texticonsearchhistorybar_
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+# -- Missing translation: _textusequery_
+_textfreqmsg1_ [l=hi] {à€ªà€Š à€à€£à€šà€Ÿ: }
+_textpostprocess_ [l=hi] {_If_(_quotedquery_,<br><i>à€ªà€¿à€à€²à€¿
+à€ªà¥à€°à€à¥à€°à¥à€¯à€Ÿ à€à¥
+à€à¥à€à€šà¥ à€à¥ à€²à€¿à€¯à¥ _quotedquery_ </i>)}
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=hi] {à€
+à€§à€¿à€ à€žà¥ }
+# -- Missing translation: _textapprox_
+_textnodocs_ [l=hi] {à€à€ž
+à€ªà¥à€°à€¶à¥à€š à€à¥ à€à¥à€
+à€®à¥à€² à€šà€¹à¥à€ à€¹à¥ à¥€}
+_text1doc_ [l=hi] {à€à€ž à€ªà¥à€°à€¶à¥à€š à€à¥ 
+1 à€Šà€žà¥à€€à€Ÿà€µà¥à€
+à€®à¥à€² à€¹à¥à€ à€¹à¥ à¥€}
+_textlotsdocs_ [l=hi] {à€à€ž à€ªà¥à€°à€¶à¥à€š à€à¥ à€Šà€žà¥à€€à€Ÿà€µà¥à€
+à€®à¥à€² à€¹à¥à€ à€¹à¥ à¥€}
+_textmatches_ [l=hi] {à€®à¥à€² }
+_textbeginsearch_ [l=hi] {à€à¥à€à€šà€Ÿ à€¶à¥à€°à¥ à€à€°à¥}
+# -- Missing translation: _textrunquery_
+# -- Missing translation: _textclearform_
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+# -- Missing translation: _textwordphrase_
+# -- Missing translation: _textinfield_
+# -- Missing translation: _textfoldstem_
+
+# -- Missing translation: _textadvquery_
+# -- Missing translation: _textallfields_
+# -- Missing translation: _texttextonly_
+# -- Missing translation: _textand_
+# -- Missing translation: _textor_
+# -- Missing translation: _textandnot_
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=hi] {à€à¥à€à€¿à€¯à¥ _indexselection__If_(_jselection_, à€žà¥ _jselection_)_If_(_nselection_, _nselection_) à€à€¿à€žà€®à¥ _querytypeselection_ à€¶à€¬à¥à€Š à€¹à¥à€ à¥€}
+
+_textadvancedsearch_ [l=hi] {à€à¥à€à€¿à€¯à¥ _indexselection_ _If_(_jselection_, à€žà¥ _jselection_)_If_(_nselection_, _nselection_ à€­à€Ÿà€·à€Ÿ) à€à€¿à€žà€®à¥ _querytypeselection_ à€¶à€¬à¥à€Š à€¹à¥à€ à¥€}
+
+# -- Missing translation: _textformsimplesearch_
+
+# -- Missing translation: _textformadvancedsearch_
+
+
+# -- Missing translation: _textnojsformwarning_
+# -- Missing translation: _textdatesearch_
+# -- Missing translation: _textstartdate_
+# -- Missing translation: _textenddate_
+# -- Missing translation: _textbc_
+# -- Missing translation: _textad_
+# -- Missing translation: _textexplaineras_
+
+_textstemon_ [l=hi] {(à€¶à€µà¥à€Šà€Ÿà€šà¥à€€à¥à€
+à€à¥ à€
+à€šà€Šà¥à€à€Ÿ à€à€°à¥ à¥€)}
+
+_textsearchhistory_ [l=hi] {à€à¥à€ à€à€Ÿ à€à€€à€¿à€¹à€Ÿà€ž à¥€}
+
+#text macros for search history
+_textnohistory_ [l=hi] {à€à¥à€ à€à€Ÿ à€à€€à€¿à€¹à€Ÿà€ž 
+à€®à€€ à€Šà€¿à€à€Ÿà€ à¥€}
+# -- Missing translation: _texthresult_
+# -- Missing translation: _texthresults_
+# -- Missing translation: _texthallwords_
+# -- Missing translation: _texthsomewords_
+# -- Missing translation: _texthboolean_
+# -- Missing translation: _texthranked_
+# -- Missing translation: _texthcaseon_
+# -- Missing translation: _texthcaseoff_
+# -- Missing translation: _texthstemon_
+# -- Missing translation: _texthstemoff_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_search
+# -- Missing translation: _httpiconhsearch_
+# -- Missing translation: _widthhsearch_
+# -- Missing translation: _heighthsearch_
+
+# -- Missing translation: qryresb
+# -- Missing translation: _httpiconqryresb_
+# -- Missing translation: _widthqryresb_
+# -- Missing translation: _heightqryresb_
+
+# -- Missing translation: schhistb
+# -- Missing translation: _httpiconsrchhistb_
+# -- Missing translation: _widthsrchhistb_
+# -- Missing translation: _heightsrchhistb_
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textprefschanged_
+_textsetprefs_ [l=hi] {à€ªà¥à€°à€Ÿà€¥à€®à€¿à€à€€à€Ÿà€¯à¥à€
+à€à¥à€šà€¿à€¯à¥}
+_textsearchprefs_ [l=hi] {à€à¥à€ à€ªà¥à€°à€Ÿà€¥à€®à€¿à€à€€à€Ÿà€¯à¥à€}
+_textcollectionprefs_ [l=hi] {à€žà€à€à¥à€°à€¹
+à€ªà¥à€°à€Ÿà€¥à€®à€¿à€à€€à€Ÿà€¯à¥à€}
+_textpresentationprefs_ [l=hi] {à€ªà¥à€°à€Šà€°à¥à€¶à€šà¥à€¯
+à€ªà¥à€°à€Ÿà€¥à€®à€¿à€à€€à€Ÿà€¯à¥à€}
+_textpreferences_ [l=hi] {à€ªà¥à€°à€Ÿà€¥à€®à€¿à€à€€à€Ÿà€¯à¥à€}
+# -- Missing translation: _textcasediffs_
+# -- Missing translation: _textignorecase_
+# -- Missing translation: _textmatchcase_
+_textwordends_ [l=hi] {à€¶à€µà¥à€Šà€Ÿà€šà¥à€€:}
+_textstem_ [l=hi] {à€¶à€µà¥à€Šà€Ÿà€šà¥à€€à¥à€
+à€à¥ à€
+à€šà€Šà¥à€à€Ÿ à€à€°à¥ à¥€}
+_textnostem_ [l=hi] {à€ªà¥à€°à¥à€£ à€¶à€¬à¥à€Š à€à€°à¥à€°
+à€®à€¿à€²à€Ÿà€ à¥€}
+_textprefop_ [l=hi] {à€à¥à€²_maxdocoption_ à€ªà€°à€¿à€£à€Ÿà€®à¥à€
+à€®à¥à€ à€žà¥ _hitsperpageoption_ à€ªà€°à€¿à€£à€Ÿà€®
+à€ªà¥à€°à€€à€¿ à€ªà¥à€·à¥à€  à€Šà€¿à€à€Ÿà€à¥€}
+_textextlink_ [l=hi] {à€¬à€¹à€°à¥
+à€µà¥à€¬ à€ªà¥à€·à¥à€ à¥à€
+à€à¥ à€ªà¥à€°à€Ÿà€ªà¥à€€
+à€à¥à€à€¿à€¯à¥ }
+_textintlink_ [l=hi] {à€®à¥à€² à€Šà€žà¥à€€à€Ÿà€µà¥à€
+à€à€ž à€žà¥ à€ªà€¯à€Ÿ à€¹à¥:}
+_textlanguage_ [l=hi] {à€à€šà¥à€à€°à€«à¥à€ž
+à€à¥ à€­à€Ÿà€·à€Ÿ: }
+_textencoding_ [l=hi] {à€à€šà¥à€à¥à€¡à€¿à€à€: }
+_textformat_ [l=hi] {à€à€šà¥à€à€°à€«à¥à€ž
+à€à¥ à€°à€à€šà€Ÿ: }
+_textall_ [l=hi] {à€žà€¬}
+_textquerymode_ [l=hi] {à€à¥à€
+à€à¥ à€ªà¥à€°à€à€Ÿà€°:}
+_textsimplemode_ [l=hi] {à€žà€°à€³ à€à¥à€ à¥€}
+_textadvancedmode_ [l=hi] {à€à€šà¥à€šà€€
+à€à¥à€ à€¬à¥à€²à€¿à€¯à€šà¥ à€à¥à€
+à€à€° à€žà€à€€à¥ à€¹à¥à€) à¥€}
+# -- Missing translation: _textlinkinterm_
+_textlinkdirect_ [l=hi] {à€žà€¿à€Š à€à€Šà€° à€à€Ÿà€¯à€¿à€¯à¥}
+_textdigitlib_ [l=hi] {à€¡à€¿à€à€¿à€à€² à€ªà¥à€žà¥à€€à€à€²à€¯}
+_textweb_ [l=hi] {à€µà¥à€¬}
+_textgraphical_ [l=hi] {à€žà¥à€à€¿à€€à¥à€°}
+_texttextual_ [l=hi] {à€®à¥à€²à€¿à€}
+_textcollectionoption_ [l=hi] {<p>
+à€à€ªà€žà€à€à¥à€°à€¹à¥à€
+à€à¥ à€žà€®à¥à€®à€¿à€²à€š
+à€à€°à¥:
+<br>}
+
+_textrelateddocdisplay_ [l=hi] {à€žà€®à¥à€¬à€šà¥à€§à€¿à€€
+à€Šà€žà¥à€€à€Ÿà€µà¥à€à¥à€
+à€à¥ à€Šà€¿à€à€Ÿà€ à¥€}
+_textsearchhistory_ [l=hi] {à€à¥à€
+à€à€Ÿ à€à€€à€¿à€¹à€Ÿà€ž}
+# -- Missing translation: _textnohistory_
+_texthistorydisplay_ [l=hi] {à€à¥à€ à€à¥ _historynumrecords_ à€à€€à€¿à€¹à€Ÿà€ž
+à€Šà€¿à€à€Ÿà€ à¥€}
+_textnohistorydisplay_ [l=hi] {à€à¥à€
+à€à€Ÿ à€à€€à€¿à€¹à€Ÿà€ž à€®à€€ à€Šà€¿à€à€Ÿà€ à¥€}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+# -- Missing translation: _textformsearch_
+# -- Missing translation: _textplainsearch_
+_textqueryboxsize_ [l=hi] {à€à¥à€ à€žà€šà¥à€Šà¥à€ 
+à€à¥ à€à€à€Ÿà€°:}
+_textregbox_ [l=hi] {à€šà€¿à€¯à€€ à€à¥à€ à€žà€šà¥à€Šà¥à€ à¥€}
+_textbigbox_ [l=hi] {à€¬à€¡à€Ÿ à€à¥à€ à€žà€šà¥à€Šà¥à€ à¥€}
+# -- Missing translation: _textformtype_
+_textsimple_ [l=hi] {à€žà€°à€³}
+_textadvanced_ [l=hi] {à€à€šà¥à€šà€€}
+
+# used in "with 4 fields" in the form search box
+# -- Missing translation: _textwith_
+# -- Missing translation: _textfields_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_pref
+# -- Missing translation: _httpiconhpref_
+# -- Missing translation: _widthhpref_
+# -- Missing translation: _heighthpref_
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+# -- Missing translation: _textsortby_
+# -- Missing translation: _textalsoshowing_
+# -- Missing translation: _textwith_
+# -- Missing translation: _textdocsperpage_
+
+# -- Missing translation: _textfilterby_
+# -- Missing translation: _textall_
+# -- Missing translation: _textany_
+# -- Missing translation: _textwords_
+# -- Missing translation: _textleaveblank_
+
+# -- Missing translation: _browsebuttontext_
+
+# -- Missing translation: _nodata_
+# -- Missing translation: _docs_
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textHelp_
+_textSearchshort_ [l=hi] {à€šà€¿à€¶à¥à€à€¿à€€
+à€ªà€Š à€à¥ à€à¥à€à€¿à€¯à¥ à¥€}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=hi] {à€¶à¥à€°à¥à€·à€
+à€à¥ à€
+à€šà¥à€žà€Ÿà€° à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€
+à€®à¥ à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+_textCreatorshort_ [l=hi] {à€à¥ à€
+à€šà¥à€žà€Ÿà€°
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€ à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+_textSubjectshort_ [l=hi] {à€µà€¿à€·à€¯ à€à¥ à€
+à€šà¥à€žà€Ÿà€°
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€ à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=hi] {à€€à€Ÿà€°à¥à€ à€à¥ à€
+à€šà¥à€žà€Ÿà€°
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€ à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=hi] {à€²à¥à€à€ªà€€à¥à€° à€à¥
+à€
+à€šà¥à€žà€Ÿà€° à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€
+à€®à¥ à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+# -- Missing translation: _textLanguageshort_
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=hi] {à€¶à¥à€°à¥à€£à¥ à€à¥
+à€
+à€šà¥à€žà€Ÿà€° à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€
+à€®à¥ à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+# -- Missing translation: _textToshort_
+# -- Missing translation: _textFromshort_
+_textBrowseshort_ [l=hi] {à€ªà¥à€°à€à€Ÿà€¶à€šà¥
+à€à¥ à€à€°à€šà€Ÿ à€à¥à€à€¿à€¯à¥ à¥€}
+_textOrganizationshort_ [l=hi] {à€žà€à€à€ à€šà¥ à€à¥
+à€
+à€šà¥à€žà€Ÿà€° à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€
+à€®à¥ à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+_textHowtoshort_ [l=hi] {à€à¥à€žà¥ à€žà¥à€à€¿
+à€à¥ à€
+à€šà¥à€žà€Ÿà€° à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€
+à€®à¥ à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+_textTopicshort_ [l=hi] {à€ªà¥à€°à€žà€à€ à€à¥
+à€
+à€šà¥à€žà€Ÿà€° à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€
+à€®à¥ à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+_textPeopleshort_ [l=hi] {à€à€šà€€à€Ÿ à€à¥ à€
+à€šà¥à€žà€Ÿà€°
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€ à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+# -- Missing translation: _textAcronymshort_
+# -- Missing translation: _textPhraseshort_
+_textArtistshort_ [l=hi] {à€à€²à€Ÿà€à€Ÿà€° à€à¥
+à€
+à€šà¥à€žà€Ÿà€° à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€
+à€®à¥ à€ªà¥à€°à€µà¥à€¶ à€à¥à€à€¿à€¯à¥ à¥€}
+# -- Missing translation: _textKeywordshort_
+# -- Missing translation: _textVolumeshort_
+# -- Missing translation: _textCountriesshort_
+# -- Missing translation: _textdefaultshorttext_
+
+_textSearchlong_ [l=hi] {<p>à€à€ª à€®à¥à€²à€à¥à€°à€šà¥à€¥
+à€žà¥ à€šà€¿à€¶à¥à€à€¿à€€ à€ªà€Š
+à€à¥ à€à¥à€ "à€à¥à€" à€ªà¥à€·à¥à€ 
+à€žà¥ à€à€° à€žà€à€€à¥ à€¹à¥
+à¥€ à€¯à€¹ à€µà¥ à€ªà€¹à€²à€Ÿ à€ªà¥à€·à¥à€ 
+à€¹à¥ à€à€¹à€Ÿà€žà¥ à€à€ª <b>à€à¥à€</b>, 
+à€¬à€à€š à€à€Ÿ
+à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€Šà¥à€žà€°à¥ à€ªà¥à€·à¥à€  à€à¥ à€à€° à€¬à€Œà€¢à€€à¥
+à€¹à¥ à¥€  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=hi] {<p>à€à€ª <b> à€¶à¥à€°à¥à€·à€</b>
+ à€¬à€à€š à€à€Ÿ à€à€ªà€¯à¥à€
+à€à€°à€à¥ à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥ à€ªà¥à€°à€µà¥à€¶
+à€à€° à€žà€à€€à¥ à€¹à¥ à¥€ à€¯à¥
+à€µà€°à¥à€£à€®à€Ÿà€²à€Ÿ à€žà€à€¬à€šà¥à€§à€¿ à€žà¥à€à€¿
+à€à¥ à€ªà¥à€¶ à€à€°à€€à¥ à€¹à¥ à¥€  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=hi] {<p>à€à€ª <b> à€²à¥à€à€</b> 
+à€¬à€à€š à€à€Ÿ à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€
+ à€¯à¥ à€µà€°à¥à€£à€®à€Ÿà€²à€Ÿ
+à€žà€à€¬à€šà¥à€§à€¿ à€²à¥à€à€
+à€žà¥à€à€¿ à€à¥ à€ªà¥à€¶
+à€à€°à€€à¥ à€¹à¥ à¥€  }
+
+_textSubjectlong_ [l=hi] {<p>à€à€ª <b> à€µà€¿à€·à€¯</b>
+ à€¬à€à€š à€à€Ÿ à€à€ªà€¯à¥à€
+à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥ à€ªà¥à€°à€µà¥à€¶
+à€à€° à€žà€à€€à¥
+à€¹à¥ à¥€ à€¯à¥ à€µà¥ à€µà€¿à€·à€¯ à€žà¥à€à€¿
+à€à¥ à€ªà¥à€¶ à€à€°à¥à€à€Ÿ à€à¥ à€à€¿à€€à€Ÿà€¬à¥ à€à¥
+à€€à€Ÿà€ à€à€Ÿ à€ªà¥à€°à€€à€¿à€šà€¿à€§à€¿à€€à¥à€µ
+à€à€°à€€à¥ à€¹à¥ à¥€ }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=hi] {<p>à€à€ª <b> à€€à€Ÿà€°à¥à€</b> 
+à€¬à€à€šà€à€Ÿ à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥ à€ªà¥à€°à€µà¥à€¶
+à€à€° à€žà€à€€à¥ à€¹à¥ à¥€ à€¯à¥à€à€µà¥à€€à¥à€€à€¿à€à¥
+à€žà¥à€à€¿à€à¥à€ªà¥à€¶à€à€°à€€à¥à€¹à¥ à¥€  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=hi] {<p>à€à€ª <i>à€²à¥à€à€ªà€€à¥à€°</i> à€¬à€à€š à€à€Ÿ
+à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€ 
+à€¯à¥ à€®à¥à€² à€²à¥à€à€ªà€€à¥à€° à€à¥ à€žà¥à€à€¿
+à€à¥ à€ªà¥à€¶ à€à€°à€€à¥ à€¹à¥ à¥€ }
+
+# -- Missing translation: _textLanguagelong_
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=hi] {<p>à€à€ª <b> à€žà€à€à€ à€šà¥</b> 
+à€¬à€à€š à€à€Ÿ à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥ à€ªà¥à€°à€µà¥à€¶
+à€à€° à€žà€à€€à¥ 
+à€¹à¥ à¥€ à€¯à¥ à€žà€à€à€ à€šà¥à€à¥
+à€žà¥à€à€¿ à€à¥ à€ªà¥à€¶ à€à€°à€€à¥ à€¹à¥ à¥€ }
+
+_textHowtolong_ [l=hi] {<p>à€à€ª <b> à€à¥à€žà¥</b> à€¬à€à€š à€à€Ÿ
+à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€
+ à€¯à¥ à€à¥à€žà¥ à€žà¥à€à€¿
+à€à¥ à€ªà¥à€¶ à€à€°à€€à¥ 
+à€¹à¥ à¥€  }
+
+_textTopiclong_ [l=hi] {<p>à€à€ª <b> à€ªà¥à€°à€žà€à€</b> 
+à€¬à€à€š à€à€Ÿ à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€
+ à€¯à¥ à€ªà¥à€°à€žà€à€
+à€žà¥à€à€¿ à€à¥ à€à€°à€š à€à¥ à€²à€¿à€
+à€ªà¥à€¶ à€à€°à€€à¥ à€¹à¥ à¥€ }
+
+_textTolong_ [l=hi] {<p>à€à€ª <b>à€ªà€€à€Ÿ</b> à€¬à€à€š à€à€Ÿ
+à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€
+à€¯à¥ à€
+à€²à€-à€
+à€²à€ à€ªà€€à¥à€ à€à¥ à€žà¥à€à€¿
+à€à¥ à€ªà¥à€¶ à€à€°à€€à¥ à€¹à¥ à¥€  }
+
+_textFromlong_ [l=hi] {<p>à€à€ª<b>à€žà¥</b> à€¬à€à€š à€à€Ÿ
+à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€
+à€¯à¥ à€ªà¥à€°à¥à€·à€ à€à¥ à€žà¥à€à€¿
+à€à¥ à€ªà¥à€¶ à€à€°à€€à¥
+à€¹à¥ à¥€  }
+
+_textSerieslong_ [l=hi] {<p>à€à€ª <b> à€¶à¥à€°à¥à€£à¥</b> 
+à€¬à€à€š à€à€Ÿ à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€
+à€¯à¥ à€¶à¥à€°à¥à€£à¥à€à€
+ à€à¥ à€žà¥à€à€¿ à€à¥ à€ªà¥à€¶ à€à€°à€€à¥
+à€¹à¥ à¥€ }
+
+_textBrowselong_ [l=hi] {<p>à€à€ª <b>à€à€°à€šà€Ÿ</b> 
+à€¬à€à€š à€à€Ÿ à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€ à€à€Ÿ
+à€à€°à€š à€à€° à€žà€à€€à¥ à€¹à¥ à¥€ }
+
+_textPeoplelong_ [l=hi] {<p>à€à€ª <b> à€à€šà€€à€Ÿ</b> 
+à€¬à€à€š à€à€Ÿ à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€
+à€¯à¥ à€à¥à€²à€šà€Ÿà€® à€à¥ à€žà¥à€à€¿ à€à¥ à€ªà¥à€¶
+à€à€°à€€à¥ à€¹à¥ à¥€  }
+
+# -- Missing translation: _textAcronymlong_
+
+# -- Missing translation: _textPhraselong_
+
+_textArtistlong_ [l=hi] {<p>à€à€ª <b>à€à€²à€Ÿà€à€Ÿà€°</b> à€¬à€à€š à€à€Ÿ
+à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€šà¥à€à€®à¥
+à€ªà¥à€°à€µà¥à€¶ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€ 
+à€¯à¥ à€à€²à€Ÿà€à€Ÿà€° à€à¥ à€žà¥à€à€¿
+à€à¥ à€ªà¥à€¶ à€à€°à€€à¥ à€¹à¥ à¥€  }
+
+# -- Missing translation: _textKeywordlong_
+
+# -- Missing translation: _textVolumelong_
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+# -- Missing translation: _textdefaultlongtext_
+
+_texthelptopics_ [l=hi] {<h2 align=left></h2>
+<ul>
+  <a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <a href="\#searching"></a>
+<ul>
+  <a href="\#query-terms"></a>
+  <a href="\#query-type"></a>
+  <a href="\#scope-of-queries"></a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <a href="\#col-prefs"></a>
+  <a href="\#pres-prefs"></a>
+  <a href="\#search-prefs"></a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=hi] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=hi] {à€Šà€žà¥à€€à€Ÿà€µà¥à€ à€à¥
+à€à¥à€žà¥ à€ªà€¢à¥à€ à¥€}
+
+_texthelpreadingdocs_ [l=hi] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p> à€à€ª à€à¥ à€ªà¥à€·à¥à€
+à€ªà¥ à€¶à¥à€°à¥à€·à€, à€²à¥à€à€ à€à€Ÿ à€šà€Ÿà€®
+à€¬à€Ÿà€¯à¥à€ à€€à€°à€« à€®à¥à€²à¥à€à€Ÿ à¥€ 
+à€€à€Šà¥à€ªà€°à€Ÿà€à€€ à€à€ª
+à€à¥ à€µà€°à¥à€€à€®à€Ÿà€š à€ªà¥à€·à¥à€
+à€žà¥ à€à€à¥ à€²à¥ à€à€Ÿà€šà¥à€µà€Ÿà€²à¥
+à€ªà¥à€·à¥à€, à€à€à¥ à€à€° à€ªà¥à€à¥ à€²à¥
+à€à€Ÿà€šà¥à€µà€Ÿà€²à¥ à€€à¥à€° à€®à¥à€²à¥à€à€à¥ à¥€
+
+<p>à€šà¥à€à¥
+à€µà€°à¥à€€à€®à€Ÿà€š à€µà€¿à€­à€Ÿà€
+à€à€Ÿ à€®à¥à€² à€®à¥à€²à¥à€à€Ÿ
+à¥€ à€à€žà¥ à€ªà€¢à€šà¥ à€à¥
+à€¬à€Ÿà€Š à€žà€¬à€žà¥ à€šà¥à€à¥
+à€à€à¥ à€à€° à€ªà¥à€à¥ à€²à¥
+à€à€Ÿà€šà¥à€µà€Ÿà€²à¥ à€€à¥à€° à€®à¥à€²à¥à€à€à¥ à¥€
+
+<p>à€¶à¥à€°à¥à€·à€ à€à€°
+à€²à¥à€à€ à€à¥ à€šà€Ÿà€®
+à€à¥ à€šà¥à€à¥ à€€à¥à€š
+à€¬à€à€š à€®à¥à€²à¥à€à€à¥ à¥€
+à€µà€°à¥à€€à€®à€Ÿà€š à€Šà€žà¥à€€à€Ÿà€µà¥à€ à€à€Ÿ
+à€ªà¥à€°à¥à€£ à€®à¥à€²
+à€«à¥à€²à€Ÿà€šà¥ à€à¥ à€²à€¿à€ <i>à€«à¥à€²à€Ÿà€šà€Ÿ à€à¥</i>, 
+à€à€¿à€ à€à€¿à€ à€à€°à¥à€ à¥€ 
+à€šà€¯à¥ à€à€¿à€¡à€à¥
+à€à¥à€²à€šà¥ à€à¥ à€²à€¿à€ <i>à€
+à€²à€</i>,
+ à€ªà€° à€à€¿à€ à€à€¿à€
+à€à€°à¥à€ à¥€ (à€Šà¥ à€Šà€žà¥à€€à€Ÿà€µà¥à€à¥à€
+à€à¥ à€€à¥à€²à€šà€Ÿ à€à€°à€šà¥
+à€à¥ à€²à€¿à€ à€šà€¯à¥ à€à€¿à€¡à€à¥
+à€žà€¹à€Ÿà€¯à€ à€¹à¥ à¥€) à€
+à€à€€ à€®à¥, à€à¥à€ à€à€¿à€¯à€Ÿ
+à€¹à¥à€ à€¶à€¬à¥à€Š à€ªà¥à€°à€à€Ÿà€¶à€¿à€€
+à€¹à¥à€à€Ÿ à¥€ à€
+à€ªà¥à€°à€à€Ÿà€¶à€¿à€€
+à€à€°à€šà¥ à€à¥ à€²à€¿à€ <i>à€
+à€ªà¥à€°à€à€Ÿà€¶à€¿à€€</i>, 
+à€¬à€à€š à€à¥ à€à€¿à€ à€à€¿à€ à€à€°à¥à€ à¥€
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_"
+border="0"></td><td>à€
+à€à€²à¥ à€µà€¿à€­à€Ÿà€
+à€®à¥ à€à€Ÿà€šà¥ à€à¥
+à€²à€¿à€ à€€à¥à€° à€ªà€°
+à€à€¿à€ à€à€¿à€ à€à€°à¥à€....</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>....à€ªà¥à€à€²à¥ à€µà€¿à€­à€Ÿà€
+à€®à¥ à€à€Ÿà€šà¥ à€à¥
+à€²à€¿à€ à€€à¥à€° à€ªà€°
+à€à€¿à€ à€à€¿à€ à€à€°à¥à€ à¥€</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>à€ªà¥à€°à¥à€£ à€®à¥à€² à€à¥
+à€ªà¥à€°à€°à¥à€Šà€·à€¿à€€
+à€à€°à¥à€, à€š à€à€°à¥à€ à¥€</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_"
+border="0"></td><td>à€à€ž à€ªà¥à€·à¥à€ à€à¥
+à€šà€¯à¥ à€à€¿à€¡à€à¥ à€®à¥
+à€à¥à€²à¥ à¥€</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>à€à¥à€à¥ à€¹à¥à€
+à€¶à€¬à¥à€Š à€à¥
+à€ªà¥à€°à€à€Ÿà€¶à€¿à€€ à€à€°à¥à€,
+à€š à€à€°à¥à€ à¥€</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=hi] {<h2>à€šà€¿à€¶à¥à€à€¿à€€
+à€ªà€Šà¥à€ à€à¥ à€à¥à€žà¥
+à€à¥à€à¥</h2>
+<p>
+  à€à¥à€ à€ªà¥à€·à¥à€ à€žà¥, à€à€ª
+à€à€ž à€ªà¥à€°à€à€Ÿà€° à€žà€°à€³
+à€µà€¿à€§à€Ÿà€š à€¬à€šà€Ÿà€¯à¥à€ :<p>
+  
+  <ol><li>à€à¥à€ à€à¥ à€šà€¿à€¶à¥à€à€¿à€€
+à€à€°à¥ à¥€
+      <li>à€à€ª à€žà€¬ à€
+à€¥à€µà€Ÿ
+à€à¥à€ à€ªà€Šà¥à€ à€à¥
+à€à¥à€ à€à¥ à€²à€¿à€ à€šà€¿à€¶à¥à€à€¿à€€
+à€à€°à¥ à¥€
+      <li>à€à¥à€ à€šà¥ à€µà€Ÿà€²à¥ à€ªà€Šà¥à€
+à€à¥ à€à€Ÿà€à€ª à€à€°à¥ à¥€
+      <li><i>à€à¥à€à€šà€Ÿ à€¶à¥à€°à¥
+à€à€°à¥</i> à€¬à€à€š à€ªà€° à€à€¿à€
+à€à€¿à€ à€à€°à¥ à¥€
+  </ol>
+
+<p> à€à€ª à€à¥ à€à¥à€ à€à¥
+à€¬à€Ÿà€Š, à€¬à¥à€ž à€žà€¹à¥
+à€®à¥à€² à€à¥ à€Šà€žà¥à€€à€Ÿà€µà¥à€
+à€à¥ à€¶à¥à€°à¥à€·à€
+à€Šà¥à€à¥à€à€à¥ à¥€ à€
+à€à€€
+
+à€®à¥ à€
+à€à€²à¥ à€¬à¥à€ž à€Šà€žà¥à€€à€Ÿà€µà¥à€
+à€®à¥ à€à€Ÿà€šà¥ à€à¥ à€²à€¿à€ à€¬à€à€š
+à€®à¥à€²à¥à€à€Ÿ à¥€ à€à€¹à€Ÿà€žà¥
+à€
+à€à€²à¥ à€¬à¥à€ž à€Šà€žà¥à€€à€Ÿà€µà¥à€
+à€®à¥ à€à€Ÿà€šà¥ à€à¥ à€²à€¿à€ à€à€° à€ªà¥à€à¥
+à€à€šà¥ à€à¥ à€²à€¿à€ à€­à¥ à€¬à€à€š
+à€®à¥à€²à¥à€à€Ÿ à¥€ à€à€ª à€¶à¥à€°à¥à€·à€
+à€
+à€¥à€µà€Ÿ à€¶à¥à€°à¥à€·à€ à€à¥ à€ªà€Ÿà€ž à€µà€Ÿà€²à€Ÿ
+à€¬à€à€š à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€à€ž à€Šà€žà¥à€€à€Ÿà€µà¥à€ à€à¥ à€Šà¥à€ à€žà€à€€à¥
+à€¹à¥ à¥€ 
+
+<p> à€à€ª à€à€°à¥à€°à€€ à€à¥ 
+à€
+à€šà¥à€žà€Ÿà€° à€ªà¥à€°à€Ÿà€¥à€®à€¿à€à€€à€Ÿà€¯à¥à€
+à€¬à€Šà€² à€žà€à€€à¥ à€¹à¥ à¥€<p> 
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>à€à¥à€ à€ªà€Š</h3>
+
+<p> à€à€ª à€à¥ à€ªà€Šà¥à€ à€à¥
+à€à¥à€ à€žà€šà¥à€Šà¥à€
+à€®à¥à€ à€à€Ÿà€à€ª
+à€à€°à¥à€à€à¥ à€à€žà€à€Ÿ
+à€
+à€°à¥à€¥à€à€à€š "à€à¥à€ à€ªà€Š" 
+à€¹à¥à€à€Ÿ à¥€ à€¹à€° à€à€ à€ªà€Š à€µà€°à¥à€£à€®à€Ÿà€²à€Ÿ
+à€à¥ à€à€¿à€šà¥à€¹ à€à€° à€
+à€à€à¥ à€žà¥ à€¬à€šà€€à€Ÿ
+à€¹à¥ à¥€ à€Šà¥ à€ªà€Šà¥à€ à€à¥ à€à€Ÿà€²à¥ à€à€à€¹
+à€žà¥ à€
+à€²à€ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€ à€µà€¿à€°à€Ÿà€®
+à€à€¿à€šà¥à€¹ à€à€Ÿ à€à€ªà€¯à¥à€ à€­à¥ à€Šà¥
+à€ªà€Šà¥à€ à€à¥ à€
+à€²à€ à€à€°à¥à€à€Ÿ à¥€ à€à€ž
+à€€à€°à€¹ à€µà€¿à€°à€Ÿà€® à€à€¿à€šà¥à€¹à¥à€ à€à¥
+à€à¥à€¡ à€Šà€¿à€¯à€Ÿ à€à€Ÿà€¯à¥à€à€Ÿ à¥€
+à€à€žà€²à€¿à€ à€à€ª à€µà€¿à€°à€Ÿà€® à€à€¿à€šà¥à€¹
+à€à€Ÿ à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€à¥à€ à€šà€¹à¥ à€à€° à€žà€à€€à¥ à¥€
+
+<p>à€à€Šà€Ÿà€¹à€°à€£: à€šà€¿à€®à¥à€šà€²à€¿à€à€¿à€€
+à€à¥à€<p>
+    <ul><kbd>à€
+à€¬à¥à€Šà¥à€² à€à€²à€Ÿà€®-
+à€à€ à€žà€à€€ à€µà¥à€à¥à€à€Ÿà€šà€¿à€
+(2002)</kbd></ul>
+      <p>à€à€Ÿ à€
+à€°à¥à€¥à€à€à€š<p>
+      <ul><kbd>à€
+à€¬à¥à€Šà¥à€² à€à€²à€Ÿà€®
+à€à€ à€žà€à€€ à€µà¥à€à¥à€à€Ÿà€šà€¿à€
+2002 </kbd></ul><p>
+<p>à€¹à¥à€à€Ÿ à¥€
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>à€à¥à€ à€à€Ÿ à€ªà¥à€°à€à€Ÿà€°</h3>
+
+<p>à€à¥à€ à€à¥ à€Šà¥
+à€ªà¥à€°à€à€Ÿà€° à€¹à¥ à¥€
+
+<ul>
+  <li>à€žà€¬ à€ªà€Šà¥à€ à€à¥ à€²à€¿à€
+à€à¥à€ à€à€°à€šà€Ÿ à¥€ à€à€ž
+à€®à¥à€ à€à€ª à€Šà¥à€¬à€Ÿà€°à€Ÿ
+à€µà€°à¥à€£à€¿à€€ à€ªà€Šà¥à€ à€à¥
+à€Šà€žà¥à€€à€Ÿà€µà¥à€, à€ªà¥à€°à€à€°à€£ à€à€°
+à€¶à¥à€°à¥à€·à€à¥à€ à€®à¥à€ à€¢à¥à€à€¢à¥à€à€Ÿ à¥€
+à€à€à€¿à€€ à€Šà€žà¥à€€à€Ÿà€µà¥à€à¥à€
+à€à¥ à€µà€°à¥à€£à€®à€Ÿà€²à€Ÿ à€žà€®à¥à€¬à€šà¥à€§à€¿
+à€à¥à€°à€® à€®à¥ à€Šà€°à¥à€¶à€Ÿà€¯à¥à€à€Ÿ à¥€<p>
+
+  <li>à€à¥à€ à€ªà€Šà¥à€ à€à¥ à€²à€¿à€
+à€à¥à€ à€à€°à€šà€Ÿ à¥€ à€à€ª à€¯à€¹à¥ à€à¥à€
+à€à¥à€¯à€Ÿà€Šà€Ÿ à€®à€¹à€€à¥à€€à¥à€µ
+à€à¥ à€ªà€Šà¥à€ à€à€Ÿ à€à€ªà€¯à¥à€ à€à€°à€à¥
+à€à¥à€ à€à€° à€žà€à€€à¥ à€¹à¥ à¥€ à€à¥à€ à€ªà€Š à€à¥
+à€šà€¿à€à€ à€µà€Ÿà€²à¥ à€Šà€žà¥à€€à€Ÿà€µà¥à€ à€à€Ÿ
+à€ªà¥à€°à€Šà€°à¥à€¶à€š à€žà€¬à€žà¥
+à€ªà€¹à€²à¥ à€¹à¥à€à€Ÿ à¥€ à€à€ªà€¯à¥à€à¥à€€à€¿
+à€à€Ÿ à€šà€¿à€°à¥à€£à€¯ à€šà€¿à€®à¥à€šà€²à€¿à€à€¿à€€
+à€¬à€Ÿà€€à¥à€ à€ªà¥ à€šà€¿à€°à¥à€­à€° à€¹à¥
+      <p>
+        
+</ul>
+
+}
+
+# -- Missing translation: _textdatesearch_
+
+# -- Missing translation: _texthelpdatesearch_
+
+# -- Missing translation: _textchangeprefs_
+
+# -- Missing translation: _texthelppreferences_
+
+_texttanumbrowseoptions_ [l=hi] {à€žà€à€à¥à€°à€¹ à€žà¥
+à€à€šà€à€Ÿà€°à¥ à€ªà¥à€°à€Ÿà€ªà¥à€€
+à€à€°à€šà¥ à€à¥ à€²à¥à€¯à¥
+à€šà€¿à€®à¥à€š _numbrowseoptions_ à€€à€°à¥à€à¥
+à€ªà¥à€°à€¯à¥à€ à€à€°à¥à€
+}
+
+_textsimplehelpheading_ [l=hi] {_collectionname_ à€žà€à€à¥à€°à€¹ à€žà¥ à€à€šà€à€Ÿà€°à¥ à€à¥à€žà¥
+à€ªà¥à€°à€Ÿà€ªà¥à€€ à€à¥ à€à€Ÿ
+à€žà€à€€à¥ à€¹à¥à€à¥€
+}
+
+# -- Missing translation: _texthelpscope_
Index: /tags/gsdl-2_61-distribution/gsdl/macros/home.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/home.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/home.dm	(revision 10506)
@@ -0,0 +1,224 @@
+# this file must be UTF-8 encoded
+
+package home
+
+# set the title of the home page to be "greenstone digital library"
+# in the currently chosen language
+
+_pagetitle_ {_textimagegreenstone_}
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. this is overridden here as we don't want 'home' 
+# links on this page
+
+_javalinks_ {_imagehelp_ _imagepref_}
+_javalinks_ [v=1] {_imagehelp_<br>_imagepref_}
+
+#######################################################################
+# icons
+#######################################################################
+
+_iconselectcollection_ {<img align=texttop src="_httpiconselcolgr_" width=_widthselcolgr_ height=_heightselcolgr_ alt="_altselcolgr_" title="_altselcolgr_">}
+_iconmusiclibrary_ {<img align=texttop src="_httpicontmusic_" border=1 alt="meldex music library" title="meldex music library">}
+
+_imagecollection_ {<img src="_httpimg_/gsdlhead.gif">}
+
+#######################################################################
+# http macros 
+#
+# These contain the url without any quotes
+#######################################################################
+
+_httppagegsdl_ {_httppagex_(gsdl)}
+_httppagehomehelp_ {_httppagex_(homehelp)}
+_httppagehomepref_ {_httppagex_(homepref)}
+
+#######################################################################
+# images
+#######################################################################
+
+_imagehelp_ {_gsimage_(_home:httppagehomehelp_,_httpiconchelpof_,_httpiconchelpon_,help,_textimagehelp_)}
+
+_imagepref_ {_gsimage_(_home:httppagehomepref_,_httpiconcprefof_,_httpiconcprefon_,pref,_textimagepref_)}
+
+# Buttons for the pane after the collections and before the text
+
+_imagegli_ {_gsimage_(_httppagegli_,_home:httpiconcgliof_,_home:httpiconcglion_,gli,_gli:textgli_)}
+
+_imagecollector_ {_gsimage_(_httppagecollector_,_home:httpiconccolof_,_home:httpiconccolon_,col,_collector:textcollector_)}
+
+_imagetranslator_ {_gsimage_(_httppagetranslator_,_home:httpiconctransof_,_home:httpiconctranson_,trans,_translang:texttranslator_)}
+
+_imageadmin_ {_gsimage_(_httppagestatus_,_home:httpiconcadminof_,_home:httpiconcadminon_,admin,_home:textadmin_)}
+
+_imagegogreenstone_ {_gsimage_(_home:httppagegsdl_,_home:httpiconcabgsof_,_home:httpiconcabgson_,gogs,_home:textabgs_)}
+
+_imagegodocs_ {_gsimage_(_home:httppagedocs_,_home:httpiconcgsdocof_,_home:httpiconcgsdocon_,docs,_home:textgsdocs_)}
+
+
+#######################################################################
+# page content                     
+#######################################################################
+
+_content_ {
+<center>
+<p>_iconselectcollection_
+</center>
+<p>_homeextra_
+
+<center>
+<p>_iconblankbar_
+</center>
+<p><table>
+_textgogli_
+_textgocollector_
+_textgotranslator_
+_textgoadmin_
+_textgogreenstone_
+_textgodocs_
+</table>
+<center>
+<p>_iconblankbar_
+</center>
+_textaboutgreenstone_
+<center>
+<p>_iconblankbar_
+</center>
+}
+
+# the _textgocollector_, _textgotranslator_, and _textgoadmin_ macros 
+# may be overridden to be empty from within the receptionist if the 
+# collector, translator, or admin facilities are disabled
+
+_textgogli_ {
+<tr valign=top>
+<td valign=top>_imagegli_</td>
+<td>_textimagegli_</td>
+</tr>
+}
+
+_textgocollector_ {
+<tr valign=top>
+<td valign=top>_imagecollector_</td>
+<td>_textimagecollector_</td>
+</tr>
+}
+
+_textgotranslator_ {
+<tr valign=top>
+<td valign=top>_imagetranslator_</td>
+<td>_textimagetranslator_</td>
+</tr>
+}
+
+_textgoadmin_ {
+<tr valign=top>
+<td valign=top>_imageadmin_</td>
+<td>_textimageadmin_</td>
+</tr>
+}
+
+_textgogreenstone_ {
+<tr valign=top>
+<td valign=top>_imagegogreenstone_</td>
+<td>_textimagegogreenstone_</td>
+</tr>
+}
+
+_textgodocs_ {
+<tr valign=top>
+<td valign=top>_imagegodocs_</td>
+<td>_textimagegodocs_</td>
+</tr>
+}
+
+package homehelp
+
+_imagecollection_ {<a href="_httppagehome_"><img src="_httpimg_/gsdlhead.gif" border="0"></a>}
+
+_collectionlist_ {}
+
+_javalinks_ {_imagehome_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+}
+
+_content_ {
+<center>
+<p>_iconblankbar_
+</center>
+<p>
+<table border=0 cellspacing=0 cellpadding=0>
+ <tr>
+  <td valign=top align=center>_imagegreenstone_</td>
+  <td valign=top>_gsdl:textgreenstone1_
+  <br><br>
+  </td>
+ </tr>
+</table>
+
+<center>
+<p>_iconblankbar_
+</center>
+_If_(_collectionlist_,_collectionlist_,_textnocollections_)
+
+<center>
+<p>_iconblankbar_
+</center>
+<p>_text4buts_
+<p><table>
+_home:textgogli_
+_home:textgocollector_
+_home:textgotranslator_
+_home:textgoadmin_
+_home:textgogreenstone_
+_home:textgodocs_
+</table>
+<center>
+<p>_iconblankbar_
+</center>
+}
+
+
+package homepref
+
+_imagecollection_ {<a href="_httppagehome_"><img src="_httpimg_/gsdlhead.gif" border="0"></a>}
+
+_javalinks_ {_homepref:imagehome_}
+_javalinks_ [v=1] {
+_homepref:imagehome_<br>
+}
+
+_pagescriptextra_ {_preferences:pagescriptextra_}
+
+
+_imagehome_ {_gsimage_(_homepref:httppagehome_,_httpiconchomeof_,_httpiconchomeon_,homer,_textimagehome_)}
+_httppagehome_ {_httppagex_(home)}
+
+_content_ {
+<center>
+<p>_iconblankbar_
+</center>
+
+<form name=PrefForm method=get action="_gwcgi_">
+<h3>_preferences:textpresentationprefs_</h3>
+
+<table border="0">
+<tr valign="top">
+<td>_preferences:textlanguage_</td>
+<td>_languageoption_</td>
+</tr>
+<tr valign="top">
+<td>_preferences:textencoding_</td>
+<td>_encodingoption_</td>
+</tr>
+<tr valign="top">
+_preferences:formatoption_
+</tr>
+</table>
+<p>_iconblankbar_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/html.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/html.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/html.dm	(revision 10506)
@@ -0,0 +1,59 @@
+# this file must be UTF-8 encoded
+
+package html
+
+_header_ {<html>
+<head></head>
+}
+
+_footer_ {</html>}
+
+_pagetitle_ {_collectionname_}
+
+_content_ {
+<frameset rows="68,*" noresize border=0>
+  <frame frameborder=0 src="_gwcgi_?e=_compressedoptions_&a=p&p=nav">
+  <frame frameborder=0 src="_cgiarghp_">
+  <noframes>
+  <p>_textframebrowser_</p>
+  </noframes>
+</frameset>
+}
+
+
+package nav
+
+_header_ {_cgihead_
+_htmlhead_
+<center>
+<table width=_pagewidth_><tr><td align=right>
+_javalinks_</td></tr></table>
+</center>
+}
+
+_faoheader_ [v=1] {_cgihead_
+_htmlhead_
+_javalinks_
+}
+
+_htmlhead_ {
+<html>
+<head>
+<title>_pagetitle_</title>
+<base target="_top">
+_globalscripts_
+</head>
+
+<body bgcolor="\#ffffff" text="\#000000" link="\#006666" 
+      alink="\#cc9900" vlink="\#666633">
+}
+
+_footer_ {</body>
+</html>
+}
+
+_content_ {
+<center>
+_optnavigationbar_
+</center>
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/indo.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/indo.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/indo.dm	(revision 10506)
@@ -0,0 +1,1236 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Indonesian Language text and icon macros 
+# Many thanks to Paul Mundy (updated November 2004)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=id] {Terbitan berkala}
+_textsource_ [l=id] {sumber:}
+_textdate_ [l=id] {tanggal terbitan:}
+_textnumpages_ [l=id] {jumlah halaman:}
+
+_textsignin_ [l=id] {login}
+
+_textdefaultcontent_ [l=id] {Halaman yang diminta tidak dapat ditemukan. Mohon gunakan tombol 'Back' (balik) di browser anda atau tombol Induk di atas untuk kembali ke Perpustakaan Digital Greenstone.}
+
+_textdefaulttitle_ [l=id] {Kesalahan GSDL }
+
+_textbadcollection_ [l=id] {Koleksi ini (namanya "_cvariable") belum diinstalasi pada sistem perpustakaan digital Greenstone ini.}
+
+_textselectpage_ [l=id] {-- Pilih Halaman --}
+
+_collectionextra_ [l=id] {Koleksi ini mengandung _about:numdocs_ dokumen. 
+Koleksi terbentuk _about:builddate_ hari yang lalu.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=id] {<p>Koleksi ini mengandung _numdocs_ _If_("_numdocs_" eq "1",dokumen,dokumen), dengan jumlah _numbytes_.
+<p><a href="_httppagex_(bsummary)">Klik di sini</a> untuk melihat ringkasan pembentukan koleksi ini.}
+
+_textimagecollection_ [l=id] {}
+_textimageabout_ [l=id] {Halaman Perihal}
+_textimagehome_ [l=id] {Halaman Induk}
+_textimagehelp_ [l=id] {Halaman Bantuan}
+_textimagepref_ [l=id] {Halaman Preferensi}
+_textimagegreenstone_ [l=id] {Perangkat Lunak Perpustakaan Digital Greenstone}
+_textimageusab_ [l=id] {Apa yang menurut anda sulit digunakan?}
+
+_textimagesearch_ [l=id] {Mencari istilah tertentu}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=id] {Melihat judul buku menurut abjad}
+_textimageCreator_ [l=id] {Melihat pengarang buku menurut abjad}
+_textimageSubject_ [l=id] {Melihat menurut kategori subyek}
+_textimageDescription_ [l=id] {Browse deskripsi}
+_textimagePublisher_ [l=id] {Browse penerbit}
+_textimageContributor_ [l=id] {Browse penyumbang}
+_textimageDate_ [l=id] {Melihat menurut tanggal}
+_textimageType_ [l=id] {Browse tipe sumberdaya}
+_textimageFormat_ [l=id] {Browse format}
+_textimageIdentifier_ [l=id] {Browse pengenal sumberdaya}
+_textimageSource_ [l=id] {Browse name file asli}
+_textimageLanguage_ [l=id] {Melihat menurut bahasa}
+_textimageRelation_ [l=id] {Browse hubungan}
+_textimageCoverage_ [l=id] {Browse pencakupan}
+_textimageRights_ [l=id] {Browse hak-hak}
+
+_textimageOrganization_ [l=id] {Melihat menurut organisasi}
+_textimageKeyword_ [l=id] {Browse kata kunci}
+_textimageHowto_ [l=id] {Melihat kategori Bagaimana}
+_textimageList_ [l=id] {Melihat daftar dokumen}
+_textimageSeries_ [l=id] {Melihat menurut terbitan}
+_textimageTo_ [l=id] {Melihat menurut bidang Kepada}
+_textimageFrom_ [l=id] {Melihat menurut bidang Dari}
+_textimageTopic_ [l=id] {Melihat terbitan khusus}
+_textimageBrowse_ [l=id] {Browse}
+_textimageCollage_ [l=id] {Browse susunan gambar}
+_textimagePeople_ [l=id] {Melihat daftar orang menurut abjad}
+_textimageAcronym_ [l=id] {Melihat singkatan lembaga}
+_textimagePhrase_ [l=id] {Melihat ungkapan}
+_textimageArtist_ [l=id] {Browse penggambar}
+_textimageVolume_ [l=id] {Browse jilid}
+_textimageCountries_ [l=id] {Browse negara}
+_textimageCaptions_ [l=id] {Browse penjelasan foto}
+
+
+_texticontabsearchgreen_ [l=id] {Mencari}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=id] {Judul A-Z}
+_texticontabCreatorgreen_ [l=id] {Pengarang A-Z}
+_texticontabSubjectgreen_ [l=id] {Subyek}
+_texticontabDescriptiongreen_ [l=id] {Deskripsi}
+_texticontabPublishergreen_ [l=id] {Penerbit}
+_texticontabContributorgreen_ [l=id] {Penyumbang}
+_texticontabDategreen_ [l=id] {Tanggal}
+_texticontabTypesgreen_ [l=id] {Tipe}
+_texticontabFormatgreen_ [l=id] {Format}
+_texticontabIdentifiergreen_ [l=id] {Pengenal}
+_texticontabSourcegreen_ [l=id] {Nama file}
+_texticontabLanguagegreen_ [l=id] {Bahasa}
+_texticontabRelationgreen_ [l=id] {Hubungan}
+_texticontabCoveragegreen_ [l=id] {Pencakupan}
+_texticontabRightsgreen_ [l=id] {Hak-hak}
+
+_texticontaborggreen_ [l=id] {Organisasi}
+_texticontabKeywordgreen_ [l=id] {Kata kunci}
+_texticontabhowgreen_ [l=id] {Bagaimana}
+_texticontabseriesgreen_ [l=id] {Berkala}
+_texticontablistgreen_ [l=id] {Daftar}
+_texticontabtogreen_ [l=id] {Kepada}
+_texticontabfromgreen_ [l=id] {Dari}
+_texticontabtopicgreen_ [l=id] {Topik}
+_texticontabbrwsegreen_ [l=id] {Browse}
+_texticontabCollagegreen_ [l=id] {Susunan gambar}
+_texticontabbrowsgreen_ [l=id] {Browse}
+_texticontabPeoplegreen_ [l=id] {Orang A-Z}
+_texticontabAcronymgreen_ [l=id] {Singkatan}
+_texticontabPhrasegreen_ [l=id] {Ungkapan}
+_texticontabArtistgreen_ [l=id] {Penggambar}
+_texticontabVolumegreen_ [l=id] {Jilid}
+_texticontabCaptionsgreen_ [l=id] {Penjelasan}
+_texticontabCountriesgreen_ [l=id] {Negara}
+
+_texticontext_ [l=id] {Menampilkan dokumen}
+_texticonclosedbook_ [l=id] {Membuka dokumen ini dan melihat isinya}
+_texticonnext_ [l=id] {ke bagian berikut}
+_texticonprev_ [l=id] {ke bagian sebelumnya}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=id] {Melihat dokumen MIDI}
+_texticonmsword_ [l=id] {Melihat dokumen Microsoft Word}
+_texticonmp3_ [l=id] {Melihat dokumen MP3}
+_texticonpdf_ [l=id] {Melihat dokumen PDF}
+_texticonps_ [l=id] {Melihat dokumen PostScript}
+_texticonppt_ [l=id] {Melihat dokumen PowerPoint}
+_texticonrtf_ [l=id] {Melihat dokumen RTF}
+_texticonxls_ [l=id] {Melihat dokumen XLS}
+
+_page_ [l=id] {halaman }
+_pages_ [l=id] {halaman}
+_of_ [l=id] {dari }
+_vol_ [l=id] {Vol.}
+_num_ [l=id] {Nomor}
+
+_textmonth00_ [l=id] {}
+_textmonth01_ [l=id] {Januari}
+_textmonth02_ [l=id] {Pebruari}
+_textmonth03_ [l=id] {Maret}
+_textmonth04_ [l=id] {April}
+_textmonth05_ [l=id] {Mei}
+_textmonth06_ [l=id] {Juni}
+_textmonth07_ [l=id] {Juli}
+_textmonth08_ [l=id] {Agustus}
+_textmonth09_ [l=id] {September}
+_textmonth10_ [l=id] {Oktober}
+_textmonth11_ [l=id] {Nopember}
+_textmonth12_ [l=id] {Desember}
+
+_textdocument_ [l=id] {Dokumen}
+_textsection_ [l=id] {Bagian}
+_textparagraph_ [l=id] {Alinea}
+
+_magazines_ [l=id] {Majalah}
+
+_nzdlpagefooter_ [l=id] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "INDUK" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=id] {_httpimg_/id/chomeof.gif}
+_httpiconchomeon_ [l=id] {_httpimg_/id/chomeon.gif}
+
+## "BANTUAN" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=id] {_httpimg_/id/chelpof.gif}
+_httpiconchelpon_ [l=id] {_httpimg_/id/chelpon.gif}
+
+## "PREFERENSI" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=id] {_httpimg_/id/cprefof.gif}
+_httpiconcprefon_ [l=id] {_httpimg_/id/cprefon.gif}
+
+## "KIRIM UMPAN BALIK" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=id] {_httpimg_/id/cusabof.gif}
+_httpiconcusabon_ [l=id] {_httpimg_/id/cusabon.gif}
+
+
+## "mencari" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=id] {_httpimg_/id/tsrchgr.gif}
+_httpicontsrchof_ [l=id] {_httpimg_/id/tsrchof.gif}
+_httpicontsrchon_ [l=id] {_httpimg_/id/tsrchon.gif}
+_widthtsrchx_ [l=id] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "judul a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=id] {_httpimg_/id/ttitlgr.gif}
+_httpiconttitleof_ [l=id] {_httpimg_/id/ttitlof.gif}
+_httpiconttitleon_ [l=id] {_httpimg_/id/ttitlon.gif}
+_widthttitlex_ [l=id] {87}
+
+# Not true DC, kept for legacy reasons
+## "pengarang a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=id] {_httpimg_/id/tauthgr.gif}
+_httpicontcreatof_ [l=id] {_httpimg_/id/tauthof.gif}
+_httpicontcreaton_ [l=id] {_httpimg_/id/tauthon.gif}
+_widthtcreatx_ [l=id] {87}
+
+## "subyek" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=id] {_httpimg_/id/tsubjgr.gif}
+_httpicontsubjon_ [l=id] {_httpimg_/id/tsubjon.gif}
+_httpicontsubjof_ [l=id] {_httpimg_/id/tsubjof.gif}
+_widthtsubjx_ [l=id] {87}
+
+## "deskripsi" ## nav_bar_button ## tdesc ##
+_httpicontdescgr_ [l=id] {_httpimg_/id/tdescgr.gif}
+_httpicontdescon_ [l=id] {_httpimg_/id/tdescon.gif}
+_httpicontdescof_ [l=id] {_httpimg_/id/tdescof.gif}
+_widthtdescx_ [l=id] {90}
+
+## "penerbit" ## nav_bar_button ## tpubl ##
+_httpicontpublgr_ [l=id] {_httpimg_/id/tpublgr.gif}
+_httpicontpublon_ [l=id] {_httpimg_/id/tpublon.gif}
+_httpicontpublof_ [l=id] {_httpimg_/id/tpublof.gif}
+_widthtpublx_ [l=id] {87}
+
+## "penyumbang" ## nav_bar_button ## tcontr ##
+_httpicontcontrgr_ [l=id] {_httpimg_/id/tcontrgr.gif}
+_httpicontcontron_ [l=id] {_httpimg_/id/tcontron.gif}
+_httpicontcontrof_ [l=id] {_httpimg_/id/tcontrof.gif}
+_widthtcontrx_ [l=id] {89}
+
+## "tanggal" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=id] {_httpimg_/id/tdategr.gif}
+_httpicontdateof_ [l=id] {_httpimg_/id/tdateof.gif}
+_httpicontdateon_ [l=id] {_httpimg_/id/tdateon.gif}
+_widthtdatex_ [l=id] {87}
+
+## "tipe" ## nav_bar_button ## ttype ##
+_httpiconttypegr_ [l=id] {_httpimg_/id/ttypegr.gif}
+_httpiconttypeof_ [l=id] {_httpimg_/id/ttypeof.gif}
+_httpiconttypeon_ [l=id] {_httpimg_/id/ttypeon.gif}
+_widthttypex_ [l=id] {87}
+
+## "format" ## nav_bar_button ## tform ##
+_httpicontformgr_ [l=id] {_httpimg_/id/tformgr.gif}
+_httpicontformof_ [l=id] {_httpimg_/id/tformof.gif}
+_httpicontformon_ [l=id] {_httpimg_/id/tformon.gif}
+_widthtformx_ [l=id] {87}
+
+## "pengenal" ## nav_bar_button ## tident ##
+_httpicontidentgr_ [l=id] {_httpimg_/id/tidentgr.gif}
+_httpicontidentof_ [l=id] {_httpimg_/id/tidentof.gif}
+_httpicontidenton_ [l=id] {_httpimg_/id/tidenton.gif}
+_widthtidentx_ [l=id] {87}
+
+# Not true DC, kept for legacy reasons
+## "nama file" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=id] {_httpimg_/id/tsrcgr.gif}
+_httpicontsrcof_ [l=id] {_httpimg_/id/tsrcof.gif}
+_httpicontsrcon_ [l=id] {_httpimg_/id/tsrcon.gif}
+_widthtsrcx_ [l=id] {87}
+
+## "bahasa" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=id] {_httpimg_/id/tlanggr.gif}
+_httpicontlangon_ [l=id] {_httpimg_/id/tlangon.gif}
+_httpicontlangof_ [l=id] {_httpimg_/id/tlangof.gif}
+_widthtlangx_ [l=id] {87}
+
+## "hubungan" ## nav_bar_button ## trel ##
+_httpicontrelgr_ [l=id] {_httpimg_/id/trelgr.gif}
+_httpicontrelon_ [l=id] {_httpimg_/id/trelon.gif}
+_httpicontrelof_ [l=id] {_httpimg_/id/trelof.gif}
+_widthtrelx_ [l=id] {87}
+
+## "pencakupan" ## nav_bar_button ## tcover ##
+_httpicontcovergr_ [l=id] {_httpimg_/id/tcovergr.gif}
+_httpicontcoveron_ [l=id] {_httpimg_/id/tcoveron.gif}
+_httpicontcoverof_ [l=id] {_httpimg_/id/tcoverof.gif}
+_widthtcoverx_ [l=id] {87}
+
+## "hak-hak" ## nav_bar_button ## tright ##
+_httpicontrightgr_ [l=id] {_httpimg_/id/trightgr.gif}
+_httpicontrighton_ [l=id] {_httpimg_/id/trighton.gif}
+_httpicontrightof_ [l=id] {_httpimg_/id/trightof.gif}
+_widthtrightx_ [l=id] {87}
+
+
+
+## "berkala" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=id] {_httpimg_/id/tsergr.gif}
+_httpicontserof_ [l=id] {_httpimg_/id/tserof.gif}
+_httpicontseron_ [l=id] {_httpimg_/id/tseron.gif}
+_widthtserx_ [l=id] {87}
+
+## "kepada" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=id] {_httpimg_/id/ttogr.gif}
+_httpiconttoon_ [l=id] {_httpimg_/id/ttoon.gif}
+_httpiconttoof_ [l=id] {_httpimg_/id/ttoof.gif}
+_widthttox_ [l=id] {87}
+
+## "dari" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=id] {_httpimg_/id/tfromgr.gif}
+_httpicontfromon_ [l=id] {_httpimg_/id/tfromon.gif}
+_httpicontfromof_ [l=id] {_httpimg_/id/tfromof.gif}
+_widthtfromx_ [l=id] {87}
+
+## "organisasi" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=id] {_httpimg_/id/torggr.gif}
+_httpicontorgon_ [l=id] {_httpimg_/id/torgon.gif}
+_httpicontorgof_ [l=id] {_httpimg_/id/torgof.gif}
+_widthtorgx_ [l=id] {98}
+
+## "bagaimana" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=id] {_httpimg_/id/thowgr.gif}
+_httpiconthowon_ [l=id] {_httpimg_/id/thowon.gif}
+_httpiconthowof_ [l=id] {_httpimg_/id/thowof.gif}
+_widththowx_ [l=id] {87}
+
+## "topik" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=id] {_httpimg_/id/ttopicgr.gif}
+_httpiconttopicon_ [l=id] {_httpimg_/id/ttopicon.gif}
+_httpiconttopicof_ [l=id] {_httpimg_/id/ttopicof.gif}
+_widthttopicx_ [l=id] {87}
+
+## "melihat" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=id] {_httpimg_/id/tbrwsegr.gif}
+_httpicontbrwseon_ [l=id] {_httpimg_/id/tbrwseon.gif}
+_httpicontbrwseof_ [l=id] {_httpimg_/id/tbrwseof.gif}
+_widthtbrwsex_ [l=id] {87}
+
+## "susunan gambar" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=id] {_httpimg_/id/tcollgr.gif}
+_httpicontcollof_ [l=id] {_httpimg_/id/tcollof.gif}
+_httpicontcollon_ [l=id] {_httpimg_/id/tcollon.gif}
+_widthtcollx_ [l=id] {87}
+
+## "orang" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=id] {_httpimg_/id/tpeopgr.gif}
+_httpicontpeopof_ [l=id] {_httpimg_/id/tpeopof.gif}
+_httpicontpeopon_ [l=id] {_httpimg_/id/tpeopon.gif}
+_widthtpeopx_ [l=id] {97}
+
+## "singkatan" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=id] {_httpimg_/id/tacrogr.gif}
+_httpicontacroof_ [l=id] {_httpimg_/id/tacroof.gif}
+_httpicontacroon_ [l=id] {_httpimg_/id/tacroon.gif}
+_widthtacrox_ [l=id] {87}
+
+## "ungkapan" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=id] {_httpimg_/id/tphrsegr.gif}
+_httpicontphrseof_ [l=id] {_httpimg_/id/tphrseof.gif}
+_httpicontphrseon_ [l=id] {_httpimg_/id/tphrseon.gif}
+_widthtphrsex_ [l=id] {87}
+
+## "penggambar" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=id] {_httpimg_/id/tartstgr.gif}
+_httpicontartstof_ [l=id] {_httpimg_/id/tartstof.gif}
+_httpicontartston_ [l=id] {_httpimg_/id/tartston.gif}
+_widthtartstx_ [l=id] {87}
+
+## "kata kunci" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=id] {_httpimg_/id/tkwgr.gif}
+_httpicontkwof_ [l=id] {_httpimg_/id/tkwof.gif}
+_httpicontkwon_ [l=id] {_httpimg_/id/tkwon.gif}
+_widthtkwx_ [l=id] {87}
+
+## "jilid" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=id] {_httpimg_/id/tvolgr.gif}
+_httpicontvolof_ [l=id] {_httpimg_/id/tvolof.gif}
+_httpicontvolon_ [l=id] {_httpimg_/id/tvolon.gif}
+_widthtvolx_ [l=id] {87}
+
+## "penjelasan" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=id] {_httpimg_/id/tcaptgr.gif}
+_httpicontcaptof_ [l=id] {_httpimg_/id/tcaptof.gif}
+_httpicontcapton_ [l=id] {_httpimg_/id/tcapton.gif}
+_widthtcaptx_ [l=id] {87}
+
+## "negara" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=id] {_httpimg_/id/tcountgr.gif}
+_httpicontcountof_ [l=id] {_httpimg_/id/tcountof.gif}
+_httpicontcounton_ [l=id] {_httpimg_/id/tcounton.gif}
+_widthtcountx_ [l=id] {87}
+
+## "bantuan" ## green_title ## h_help ##
+_httpiconhhelp_ [l=id] {_httpimg_/id/h\_help.gif}
+_widthhhelp_ [l=id] {200}
+_heighthhelp_ [l=id] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=id] {Mengenai koleksi ini}
+
+_textsubcols1_ [l=id] {<p>Koleksi lengkap mengandung _1_ subkoleksi. 
+Koleksi yang sedang tersedia adalah:
+<blockquote>}
+
+_textsubcols2_ [l=id] {</blockquote>
+Anda dapat mengecek (dan mengubah) subkoleksi yang sedang digunakan 
+pada halaman Preferensi.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "about" ## green_title ## h_about ##
+_httpiconhabout_ [l=id] {_httpimg_/id/h\_about.gif}
+_widthhabout_ [l=id] {200}
+_heighthabout_ [l=id] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=id] {Judul A-Z}
+_texticonhcreat_ [l=id] {Pengarang A-Z}
+_texticonhsubj_ [l=id] {Subyek}
+_texticonhdesc_ [l=id] {Deskripsi}
+_texticonhpubl_ [l=id] {Penerbit}
+_texticonhcontr_ [l=id] {Penyumbang}
+_texticonhdate_ [l=id] {Tanggal}
+_texticonhtype_ [l=id] {Tipe}
+_texticonhform_ [l=id] {Format}
+_texticonhident_ [l=id] {Pengenal}
+_texticonhsrc_ [l=id] {Nama file}
+_texticonhlang_ [l=id] {Bahasa}
+_texticonhrel_ [l=id] {Hubungan}
+_texticonhcover_ [l=id] {Pencakupan}
+_texticonhright_ [l=id] {Hak-hak}
+
+_texticonhcoll_ [l=id] {Susunan gambar}
+_texticonhto_ [l=id] {Kepada}
+_texticonhfrom_ [l=id] {Dari}
+_texticonhser_ [l=id] {Berkala}
+_texticonhhow_ [l=id] {Bagaimana}
+_texticonhorg_ [l=id] {Organisasi}
+_texticonhbrwse_ [l=id] {Melihat}
+_texticonhbrows_ [l=id] {Browse}
+_texticonhpeople_ [l=id] {Orang A-Z}
+_texticonhacronym_ [l=id] {Singkatan}
+_texticonhphrases_ [l=id] {Ungkapan}
+_texticonhartist_ [l=id] {Penggambar}
+_texticonhkw_ [l=id] {Kata kunci}
+_texticonhvol_ [l=id] {Jilid}
+_texticonhcapt_ [l=id] {Penjelasan}
+_texticonhcount_ [l=id] {Negara}
+
+_texticonopenbookshelf_ [l=id] {tutup bagian perpustakaan ini}
+_texticonclosedbookshelf_ [l=id] {buka bagian perpustakaan ini dan melihat isinya}
+_texticonopenbook_ [l=id] {tutup buku ini}
+_texticonclosedfolder_ [l=id] {Buka map ini dan melihat isinya}
+_texticonclosedfolder2_ [l=id] {buka sub-bagian: }
+_texticonopenfolder_ [l=id] {tutup map ini}
+_texticonopenfolder2_ [l=id] {tutup sub-bagian: }
+_texticonsmalltext_ [l=id] {Melihat bagian ini dari teks}
+_texticonsmalltext2_ [l=id] {melihat teks: }
+_texticonpointer_ [l=id] {bagian terpilih}
+_texticondetach_ [l=id] {Bukan halaman ini pada jendela baru}
+_texticonhighlight_ [l=id] {Menyoroti istilah yang dicari}
+_texticonnohighlight_ [l=id] {Jangan menyoroti istilah yang dicari}
+_texticoncontracttoc_ [l=id] {Tutup daftar isi}
+_texticonexpandtoc_ [l=id] {Buka daftar isi}
+_texticonexpandtext_ [l=id] {Tampilkan semua teks}
+_texticoncontracttext_ [l=id] {Tampilkan teks hanya di bagian yang terpilih}
+_texticonwarning_ [l=id] {<b>Perhatian: </b>}
+_texticoncont_ [l=id] {teruskan?}
+
+_textltwarning_ [l=id] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Membuka teks di sini akan menghasilkan sejumlah data besar untuk ditampilkan oleh browser anda _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=id] {ke halaman}
+_textintro_ [l=id] {<i>(teks pengantar)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "Judul A-Z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=id] {_httpimg_/id/h\_title.gif}
+_widthhtitle_ [l=id] {200}
+_heighthtitle_ [l=id] {57}
+
+# Not true DC, kept for legacy reasons
+## "pengarang a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=id] {_httpimg_/id/h\_auth.gif}
+_widthhcreat_ [l=id] {200}
+_heighthcreat_ [l=id] {57}
+
+## "subyek" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=id] {_httpimg_/id/h\_subj.gif}
+_widthhsubj_ [l=id] {200}
+_heighthsubj_ [l=id] {57}
+
+## "deskripsi" ## green_title ## h_desc ##
+_httpiconhdesc_ [l=id] {_httpimg_/id/h\_desc.gif}
+_widthhdesc_ [l=id] {200}
+_heighthdesc_ [l=id] {57}
+
+## "penerbit" ## green_title ## h_publ ##
+_httpiconhpubl_ [l=id] {_httpimg_/id/h\_publ.gif}
+_widthhpubl_ [l=id] {200}
+_heighthpubl_ [l=id] {57}
+
+## "penyumbang" ## green_title ## h_contr ##
+_httpiconhcontr_ [l=id] {_httpimg_/id/h\_contr.gif}
+_widthhcontr_ [l=id] {200}
+_heighthcontr_ [l=id] {57}
+
+## "tanggal" ## green_title ## h_date ##
+_httpiconhdate_ [l=id] {_httpimg_/id/h\_date.gif}
+_widthhdate_ [l=id] {200}
+_heighthdate_ [l=id] {57}
+
+## "tipe" ## green_title ## h_type ##
+_httpiconhtype_ [l=id] {_httpimg_/id/h\_type.gif}
+_widthhtype_ [l=id] {200}
+_heighthtype_ [l=id] {57}
+
+## "format" ## green_title ## h_form ##
+_httpiconhform_ [l=id] {_httpimg_/id/h\_form.gif}
+_widthhform_ [l=id] {200}
+_heighthform_ [l=id] {57}
+
+## "pengenal" ## green_title ## h_ident ##
+_httpiconhident_ [l=id] {_httpimg_/id/h\_ident.gif}
+_widthhident_ [l=id] {200}
+_heighthident_ [l=id] {57}
+
+# Not true DC, kept for legacy reasons
+## "nama file" ## green_title ## h_src ##
+_httpiconhsrc_ [l=id] {_httpimg_/id/h\_src.gif}
+_widthhsrc_ [l=id] {200}
+_heighthsrc_ [l=id] {57}
+
+## "bahasa" ## green_title ## h_lang ##
+_httpiconhlang_ [l=id] {_httpimg_/id/h\_lang.gif}
+_widthhlang_ [l=id] {200}
+_heighthlang_ [l=id] {57}
+
+## "hubungan" ## green_title ## h_rel ##
+_httpiconhrel_ [l=id] {_httpimg_/id/h\_rel.gif}
+_widthhrel_ [l=id] {200}
+_heighthrel_ [l=id] {57}
+
+## "pencakupan" ## green_title ## h_cover ##
+_httpiconhcover_ [l=id] {_httpimg_/id/h\_cover.gif}
+_widthhcover_ [l=id] {200}
+_heighthcover_ [l=id] {57}
+
+## "hak-hak" ## green_title ## h_right ##
+_httpiconhright_ [l=id] {_httpimg_/id/h\_right.gif}
+_widthhright_ [l=id] {200}
+_heighthright_ [l=id] {57}
+
+
+
+## "kepada" ## green_title ## h_to ##
+_httpiconhto_ [l=id] {_httpimg_/id/h\_to.gif}
+_widthhto_ [l=id] {200}
+_heighthto_ [l=id] {57}
+
+## "dari" ## green_title ## h_from ##
+_httpiconhfrom_ [l=id] {_httpimg_/id/h\_from.gif}
+_widthhfrom_ [l=id] {200}
+_heighthfrom_ [l=id] {57}
+
+## "berkala" ## green_title ## h_ser ##
+_httpiconhser_ [l=id] {_httpimg_/id/h\_ser.gif}
+_widthhser_ [l=id] {200}
+_heighthser_ [l=id] {57}
+
+## "bagaimana" ## green_title ## h_how ##
+_httpiconhhow_ [l=id] {_httpimg_/id/h\_how.gif}
+_widthhhow_ [l=id] {200}
+_heighthhow_ [l=id] {57}
+
+## "topik" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=id] {_httpimg_/id/h\_topic.gif}
+_widthhtopic_ [l=id] {200}
+_heighthtopic_ [l=id] {57}
+
+## "organisasi" ## green_title ## h_org ##
+_httpiconhorg_ [l=id] {_httpimg_/id/h\_org.gif}
+_widthhorg_ [l=id] {200}
+_heighthorg_ [l=id] {57}
+
+## "melihat" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=id] {_httpimg_/id/h\_brwse.gif}
+_widthhbrwse_ [l=id] {200}
+_heighthbrwse_ [l=id] {57}
+
+## "susunan gambar" ## green_title ## h_coll ##
+_httpiconhcoll_ [l=id] {_httpimg_/id/h\_coll.gif}
+_widthhcoll_ [l=id] {200}
+_heighthcoll_ [l=id] {57}
+
+## "orang" ## green_title ## h_people ##
+_httpiconhpeople_ [l=id] {_httpimg_/id/h\_people.gif}
+_widthhpeople_ [l=id] {200}
+_heighthpeople_ [l=id] {57}
+
+## "singkatan" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=id] {_httpimg_/id/h\_acro.gif}
+_widthhacronym_ [l=id] {200}
+_heighthacronym_ [l=id] {57}
+
+## "ungkapan" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=id] {_httpimg_/id/h\_phrse.gif}
+_widthhphrse_ [l=id] {200}
+_heighthphrse_ [l=id] {57}
+
+## "penggambar" ## green_title ## h_artist ##
+_httpiconhartist_ [l=id] {_httpimg_/id/h\_artist.gif}
+_widthhartist_ [l=id] {200}
+_heighthartist_ [l=id] {57}
+
+## "kata kunci" ## green_title ## h_kw ##
+_httpiconhkw_ [l=id] {_httpimg_/id/h\_kw.gif}
+_widthhkw_ [l=id] {200}
+_heighthkw_ [l=id] {57}
+
+## "jilid" ## green_title ## h_vol ##
+_httpiconhvol_ [l=id] {_httpimg_/id/h\_vol.gif}
+_widthhvol_ [l=id] {200}
+_heighthvol_ [l=id] {57}
+
+## "negara" ## green_title ## h_count ##
+_httpiconhcount_ [l=id] {_httpimg_/id/h\_count.gif}
+_widthhcount_ [l=id] {200}
+_heighthcount_ [l=id] {57}
+
+## "penjelasan" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=id] {_httpimg_/id/h\_capt.gif}
+_widthhcapt_ [l=id] {200}
+_heighthcapt_ [l=id] {57}
+
+
+## "TERUSKAN??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=id] {_httpimg_/id/contof.gif}
+_httpiconconton_ [l=id] {_httpimg_/id/conton.gif}
+
+## "BUKA TEKS" ## document_button ## eallt ##
+_httpiconealltof_ [l=id] {_httpimg_/id/ealltof.gif}
+_httpiconeallton_ [l=id] {_httpimg_/id/eallton.gif}
+
+## "TUTUP ISI" ## document_button ## econc ##
+_httpiconeconcof_ [l=id] {_httpimg_/id/econcof.gif}
+_httpiconeconcon_ [l=id] {_httpimg_/id/econcon.gif}
+
+## "PISAHKAN" ## document_button ## edtch ##
+_httpiconedtchof_ [l=id] {_httpimg_/id/edtchof.gif}
+_httpiconedtchon_ [l=id] {_httpimg_/id/edtchon.gif}
+
+## "BUKA ISI" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=id] {_httpimg_/id/eexpcof.gif}
+_httpiconeexpcon_ [l=id] {_httpimg_/id/eexpcon.gif}
+
+## "TUTUP TEKS" ## document_button ## etsec ##
+_httpiconetsecof_ [l=id] {_httpimg_/id/etsecof.gif}
+_httpiconetsecon_ [l=id] {_httpimg_/id/etsecon.gif}
+
+## "PENYOROTAN" ## document_button ## ehl ##
+_httpiconehlof_ [l=id] {_httpimg_/id/ehlof.gif}
+_httpiconehlon_ [l=id] {_httpimg_/id/ehlon.gif}
+
+## "TANPA\nPENYOROTAN" ## document_button ## enhl ##
+_httpiconenhlof_ [l=id] {_httpimg_/id/enhlof.gif}
+_httpiconenhlon_ [l=id] {_httpimg_/id/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=id] {_If_(_thislast_,hasil _thisfirst_ - _thislast_ untuk pertanyaan: _cgiargq_,Tidak ada yang memenuhi syarat: _cgiargq_)}
+_textnoquerytitle_ [l=id] {Halaman Pencarian}
+
+_texticonthispage_ [l=id] {mencari}
+_textsome_ [l=id] {beberapa}
+_textall_ [l=id] {semua}
+_textboolean_ [l=id] {logika}
+_textranked_ [l=id] {terurut}
+_textnatural_ [l=id] {alami}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=id] {}
+_texticonsearchhistorybar_ [l=id] {riwayat pencarian}
+
+_textifeellucky_ [l=id] {Saya lagi beruntung!}
+
+#alt text for query buttons
+_textusequery_ [l=id] {gunakan pertanyaan ini}
+_textfreqmsg1_ [l=id] {Jumlah kata: }
+_textpostprocess_ [l=id] {_If_(_quotedquery_,<br><i>diproses ulang untuk menemukan _quotedquery_</i>
+)}
+_textinvalidquery_ [l=id] {Susunan <i>query</i> (permintaan informasi) tidak laku}
+
+_textmorethan_ [l=id] {Lebih dari }
+_textapprox_ [l=id] {Sekitar }
+_textnodocs_ [l=id] {Tidak ada dokumen yang memenuhi syarat.}
+_text1doc_ [l=id] {1 dokumen memenuhi syarat.}
+_textlotsdocs_ [l=id] {dokumen memenuhi syarat.}
+_textmatches_ [l=id] {Penemuan }
+_textbeginsearch_ [l=id] {Mulai mencari}
+_textrunquery_ [l=id] {Menjalankan pertanyaan}
+_textclearform_ [l=id] {Menghapuskan formulir}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=id] {Kata atau ungkapan}
+_textinfield_ [l=id] {... dalam bidang}
+_textfoldstem_ [l=id] {(lipatan, kata dasar)}
+
+_textadvquery_ [l=id] {Atau masukkan pertanyaan secara langsung:}
+_textallfields_ [l=id] {semua bidang}
+_texttextonly_ [l=id] {hanya teks
+}
+_textand_ [l=id] {dan}
+_textor_ [l=id] {atau}
+_textandnot_ [l=id] {dan tidak}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=id] {Mencari _indexselection_ _If_(_jselection_, dari _jselection_) _If_(_gselection_, pada tingkat _gselection_) _If_(_nselection_, dalam bahasa _nselection_) yang mengandung _querytypeselection_ dari kata}
+
+_textadvancedsearch_ [l=id] {Mencari _indexselection_ _If_(_jselection_, dari _jselection_) _If_(_gselection_, pada tigkat _gselection_)_If_(_nselection_, dalam bahasa _nselection_) dengan menggunakan pertanyaan _querytypeselection_}
+
+_textformsimplesearch_ [l=id] {Mencari _If_(_jselection_, _jselection_) _If_(_gformselection_, pada tingkat _gformselection_) _If_(_nselection_, dalam bahasa _nselection_)
+yang mengandung _formquerytypeselection_ dari}
+
+_textformadvancedsearch_ [l=id] {Mencari _If_(_jselection_,_jselection_) _If_(_gformselection_, pada tingkat _gformselection_)_If_(_nselection_, dalam bahasa _nselection_) 
+dan menampilkan hasil dalam urutan _formquerytypeselection_}
+
+
+_textnojsformwarning_ [l=id] {Perhatian: Javascript dilumpuhkan di browser anda. <br>Untuk menggunakan pencarian dengan formulir, mohon diizinkan.}
+_textdatesearch_ [l=id] {Koleksi ini dapat diselidiki untuk dokumen yang mengandung tahun atau kisaran tahun tertentu. Kemungkinan ini merupakan pilihan tambahan.}
+_textstartdate_ [l=id] {Tahun mulai (atau tunggal):}
+_textenddate_ [l=id] {Tahun akhir:}
+_textbc_ [l=id] {SM}
+_textad_ [l=id] {TM}
+_textexplaineras_ [l=id] {C.E. (Common Era) = TM = Tarich (sesudah) Masehi. B.C.E. (Before Common Era) = SM = sebelum Masehi. }
+
+_textstemon_ [l=id] {(mengabaikan akhiran kata)}
+
+_textsearchhistory_ [l=id] {Riwayat pencarian}
+
+#text macros for search history
+_textnohistory_ [l=id] {Riwayat pencarian tidak tersedia}
+_texthresult_ [l=id] {hasil}
+_texthresults_ [l=id] {hasil}
+_texthallwords_ [l=id] {semua kata}
+_texthsomewords_ [l=id] {beberapa kata}
+_texthboolean_ [l=id] {pencarian logika}
+_texthranked_ [l=id] {terurut}
+_texthcaseon_ [l=id] {Huruf besar/kecil harus sama}
+_texthcaseoff_ [l=id] {Abaikan huruf besar/kecil}
+_texthstemon_ [l=id] {Abaikan awalan dan akhiran}
+_texthstemoff_ [l=id] {Dengan awalan dan akhiran}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Mencari" ## green_title ## h_search ##
+_httpiconhsearch_ [l=id] {_httpimg_/id/h\_search.gif}
+_widthhsearch_ [l=id] {200}
+_heighthsearch_ [l=id] {57}
+
+## "Hasil" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=id] {_httpimg_/id/qryresb.gif}
+_widthqryresb_ [l=id] {_pagewidth_}
+_heightqryresb_ [l=id] {17}
+
+## "Riwayat\n" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=id] {_httpimg_/id/schhistb.gif}
+_widthsrchhistb_ [l=id] {_pagewidth_}
+_heightsrchhistb_ [l=id] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=id] {Preferensi ditetapkan seperti berikut. Jangan menggunakan tombol "back" di browser anda - preferensi tersebut akan terhapus! Daripada itu, klik di salah satu tombol di atas.}
+_textsetprefs_ [l=id] {tetapkan preferensi}
+_textsearchprefs_ [l=id] {Preferensi pencarian}
+_textcollectionprefs_ [l=id] {Preferensi koleksi}
+_textpresentationprefs_ [l=id] {Preferensi penampilan}
+_textpreferences_ [l=id] {Preferensi}
+_textcasediffs_ [l=id] {Pembedaan huruf besar/kecil:}
+_textignorecase_ [l=id] {abaikan perbedaan}
+_textmatchcase_ [l=id] {huruf besar/kecil harus tepat sama}
+_textwordends_ [l=id] {Akhiran kata:}
+_textstem_ [l=id] {abaikan akhiran}
+_textnostem_ [l=id] {kata harus tepat sama}
+_textprefop_ [l=id] {Sediakan sampai dengan _maxdocoption_ penemuan dengan _hitsperpageoption_ penemuan per halaman.}
+_textextlink_ [l=id] {Akses ke halaman web di luar:}
+_textintlink_ [l=id] {Dokumen asli diperoleh dari:}
+_textlanguage_ [l=id] {Bahasa tampilan:}
+_textencoding_ [l=id] {Pengekodean:}
+_textformat_ [l=id] {Format tampilan:}
+_textall_ [l=id] {semua}
+_textquerymode_ [l=id] {Cara pertanyaan:}
+_textsimplemode_ [l=id] {sederhana}
+_textadvancedmode_ [l=id] {cara pertanyaan lanjutan (memungkinkan pencarian yang menggunakan !, &, |, dan tanda kurung) }
+_textlinkinterm_ [l=id] {melalui halaman pengantara}
+_textlinkdirect_ [l=id] {langsung tersedia}
+_textdigitlib_ [l=id] {perpustakaan digital}
+_textweb_ [l=id] {web}
+_textgraphical_ [l=id] {grafis}
+_texttextual_ [l=id] {teks}
+_textcollectionoption_ [l=id] {<p>
+Sub-koleksi yang tercantum:
+<br>}
+
+_textrelateddocdisplay_ [l=id] {tampilkan dokumen terkait}
+_textsearchhistory_ [l=id] {Riwayat pencarian:}
+_textnohistory_ [l=id] {Tidak ada pencarian sebelumnya}
+_texthistorydisplay_ [l=id] {tampilkan _historynumrecords_ butir riwayat pencarian}
+_textnohistorydisplay_ [l=id] {jangan tampilkan riwayat pencarian}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=id] {Formulir pencarian:}
+_textplainsearch_ [l=id] {Pencarian sederhana:}
+_textqueryboxsize_ [l=id] {Ukuran kotak pertanyaan:}
+_textregbox_ [l=id] {kotak pertanyaan biasa}
+_textbigbox_ [l=id] {kotak pertanyaan besar}
+_textformtype_ [l=id] {Tipe formulir:}
+_textsimple_ [l=id] {sederhana}
+_textadvanced_ [l=id] {lanjutan}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=id] {dengan}
+_textfields_ [l=id] {bidang}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferensi" ## green_title ## h_pref ##
+_httpiconhpref_ [l=id] {_httpimg_/id/h\_pref.gif}
+_widthhpref_ [l=id] {200}
+_heighthpref_ [l=id] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=id] {Susunkan dokumen menurut}
+_textalsoshowing_ [l=id] {juga menunjukkan}
+_textwith_ [l=id] {dengan paling banyak}
+_textdocsperpage_ [l=id] {dokumen per halaman}
+
+_textfilterby_ [l=id] {Melihat hanya dokumen yang mengandung}
+_textall_ [l=id] {semua}
+_textany_ [l=id] {apa saja}
+_textwords_ [l=id] {dari kata}
+_textleaveblank_ [l=id] {biarkan kotak ini kosong untuk memperoleh semua dokumen }
+
+_browsebuttontext_ [l=id] {Melihat}
+
+_nodata_ [l=id] {<i>tidak ada data</i>}
+_docs_ [l=id] {dokumen}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=id] {Bantuan}
+_textSearchshort_ [l=id] {mencari kata-kata tertentu}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=id] {mengakses publikasi menurut judul}
+_textCreatorshort_ [l=id] {mengakses publikasi menurut pengarang}
+_textSubjectshort_ [l=id] {mengakses publikasi menurut subyek}
+_textDescriptionshort_ [l=id] {mengakses publikasi menurut deskripsi}
+_textPublishershort_ [l=id] {mengakses publikasi menurut penerbit}
+_textContributorshort_ [l=id] {akses publikasi menurut penyumbang}
+_textDateshort_ [l=id] {mengakses publikasi menurut tanggal}
+_textTypeshort_ [l=id] {mengakses publikasi menurut tipe}
+_textFormatshort_ [l=id] {mengakses publikasi menurut format}
+_textIdentifiershort_ [l=id] {mengakses publikasi menurut pengenal}
+_textSourceshort_ [l=id] {mengakses publikasi menurut nama file}
+_textLanguageshort_ [l=id] {mengakses publikasi menurut bahasa}
+_textRelationshort_ [l=id] {mengakses publikasi menurut hubungan}
+_textCoverageshort_ [l=id] {akses publikasi menurut pencakupan}
+_textRightsshort_ [l=id] {mengakses publikasi menurut hak-hak}
+
+_textSeriesshort_ [l=id] {mengakses publikasi menurut judul berkala}
+_textToshort_ [l=id] {mengakses publikasi menurut bidang Kepada}
+_textFromshort_ [l=id] {mengakses publikasi menurut bidang Dari}
+_textBrowseshort_ [l=id] {melihat publikasi}
+_textOrganizationshort_ [l=id] {mengakses publikasi menurut organisasi}
+_textHowtoshort_ [l=id] {mengakses publikasi menurut daftar "Bagaimana"}
+_textTopicshort_ [l=id] {mengakses publikasi menurut topik}
+_textPeopleshort_ [l=id] {mengakses publikasi menurut orang}
+_textAcronymshort_ [l=id] {mengakses publikasi menurut keteradaan singkatan}
+_textPhraseshort_ [l=id] {melihat ungkapan yang berada di publikasi}
+_textArtistshort_ [l=id] {mengakses publikasi menurut penggambar}
+_textKeywordshort_ [l=id] {mengakses publikasi menurut kata kunci}
+_textVolumeshort_ [l=id] {mengakses publikasi menurut jilid}
+_textCountriesshort_ [l=id] {mengakses publikasi menurut negara}
+_textdefaultshorttext_ [l=id] {klasifikasi belum terdefinisi}
+
+_textSearchlong_ [l=id] {<p>Anda dapat <i>mencari kata-kata tertentu</i> yang berada di teks dari halaman "Pencarian". Halaman inilah yang pertama mencul bila program dimulai. Halaman tsb dapat ditampilkan dengan menekan tombol <i>Mencari</i>.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut judul</i> dengan menekan tombol <i>Judul A-Z</i>.  Tombol ini menampilkan daftar publikasi dalam urutan abjad.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut pengarang</i> dengan menekan tombol <i>pengarang a-z</i>.  Tombol ini menampilkan daftar publikasi yang diurutkan menurut nama pengarang.  }
+
+_textSubjectlong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut subyek</i> dengan menekan tombol <i>subyek</i>.  Tombol ini menampilkan daftar subyek, diwakili oleh rak buku.  }
+
+_textDescriptionlong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut deskripsi</i> dengan menekan tombol <i>deskripsi</i>. Tombol ini menampilkan daftar deskripsi.}
+
+_textPublisherlong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut penerbit</i> dengan menekan tombol <i>penerbit</i>.  Tombol ini menampilkan daftar penerbit.}
+
+_textContributorlong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut penyumbang</i> dengan menekan tombol <i>penyumbang</i>. Tombol ini menampilkan daftar penyumbang.}
+
+_textDatelong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut tanggal</i> dengan menekan tombol <i>tanggal</i>.  Tombol ini menampilkan daftar publikasi berurutan tanggalnya.  }
+
+_textTypelong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut tipe</i> dengan menekan tombol <i>tipe</i>.  Tombol ini menampilkan daftar tipe publikasi.}
+
+_textFormatlong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut format</i> dengan menekan tombol <i>format</i>. Tombol ini menampilkan daftar format.}
+
+_textIdentifierlong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut pengenal</i> dengan menekan tombol <i>pengenal</i>.  Tombol ini menampilkan daftar pengenal.  }
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut nama file</i> dengan menekan tombol <i>nama file</i>.  Tombol ini menampilkan daftar publikasi, diurut menurut nama file.}
+
+_textLanguagelong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut bahasa</i> dengan menekan tombol <i>bahasa</i>.  Tombol ini menampilkan daftar berurutan bahasa.  }
+
+_textRelationlong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut hubungan</i> dengan menekan tombol <i>hubungan</i>.  Tombol ini menampilkan daftar hubungan.}
+
+_textCoveragelong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut pencakupan</i> dengan menekan tombol <i>pencakupan</i>.  Tombol ini menampilkan daftar pencakupan.}
+
+_textRightslong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut hak-hak</i> dengan menekan tombol <i>hak-hak</i>.  Tombol ini menampilkan daftar hak-hak.}
+
+
+
+_textOrganizationlong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut organisasi</i> dengan menekan tombol <i>organisasi</i>.  Tombol ini menampilkan daftar organisasi.  }
+
+_textHowtolong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut daftar "Bagaimana"</i> dengan menekan tombol <i>bagaimana</i>.  Tombol ini menampilkan daftar cara mengerjakan sesuatu.  }
+
+_textTopiclong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut topik</i> dengan menekan tombol <i>topik</i>.  Tombol ini menampilkan daftar topik yang dapat dipilih.  }
+
+_textTolong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut bidang "Kepada"</i> dengan menekan tombol <i>kepada</i>.  Tombol ini menampilkan daftar alamat.  }
+
+_textFromlong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut bidang "Dari" </i> dengan menekan tombol <i>dari</i>.  Tombol ini menampilkan daftar pengirim. }
+
+_textSerieslong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut judul seri (publikasi berkala)</i> dengan menekan tombol <i>berkala</i>.  Tombol ini menampilkan daftar publikasi berkala yang ada dalam koleksi.  }
+
+_textBrowselong_ [l=id] {<p> Anda dapat <i>memilih dari daftar publikasi</i> dengan menekan tombol <i>melihat</i>.  }
+
+_textPeoplelong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut perorangan</i> dengan menekan tombol <i>orang</i>.  Tombol ini menampilkan daftar perorangan dalam urutan abjad.  }
+
+_textAcronymlong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut keteradaan singkatan</i> dengan menekan tombol <i>singkatan</i>.  Tombol ini menampilkan daftar singkatan dan letaknya.  }
+
+_textPhraselong_ [l=id] {<p>You can <i>melihat ungkapan yang berada dalam publikasi</i> dengan menekan tombol <i>ungkapan</i> button.  Tombol ini menggunakan browser untuk mencari ungkapan.  }
+
+_textArtistlong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut penggambar</i> dengan menekan tombol <i>penggambar</i>.  Tombol ini menampilkan daftar publikasi, diurut menurut nama penggambar.}
+
+_textKeywordlong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut kata kunci</i> dengan menekan tombol <i>kata kunci</i>.  Tombol ini menampilkan daftar kata kunci.}
+
+_textVolumelong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut jilid</i> dengan menekan tombol <i>jilid</i>. Tombol ini menampilkan daftar jilid.}
+
+_textCaptionslong_ [l=id] {<p>Anda dapat <i>mengakses publikasi menurut penjelasan gambar</i> dengan menekan tombol <penjelasan>. Tombol ini menampilkan daftar publikasi, diurut menurut penjelasan.}
+
+_textCountrieslong_ [l=id] {<p> Anda dapat <i>mengakses publikasi menurut negara</i> dengan menekan tombol <i>negara</i>.  Tombol ini menampilkan daftar negara.}
+
+
+_textdefaultlongtext_ [l=id] {<p>Klik pada tombol <i>tidak diketahui</i> untuk melihat publikasi (daftar diurutkan menurut bidang yang tidak diketahui).  }
+
+_texthelptopics_ [l=id] {<h2 align=left>Topik</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Bagaimana mencari kata-kata tertentu </a>
+<ul>
+  <li><a href="\#query-terms">Istilah pencarian</a>
+  <li><a href="\#query-type">Macam pertanyaan</a>
+  <li><a href="\#scope-of-queries">Jangkauan pertanyaan</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Preferensi koleksi</a>
+  <li><a href="\#lang-prefs">Preferensi bahasa</a>
+  <li><a href="\#pres-prefs">Preferensi penampilan</a>
+  <li><a href="\#search-prefs">Preferensi pencarian</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=id] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=id] {Bagaimana membaca dokumen}
+
+_texthelpreadingdocs_ [l=id] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Anda dapat mengetahui bahwa anda telah tiba di dokumen tertentu karena judul dan pengarangnya terlihat pada atas kiri halaman. Di sebelahnya ada nomor halaman yang ditampilkan, kotak yang memungkinkan anda untuk memilih halaman baru, dan panah maju dan mundur.
+
+<p>Di bawahnya ada teks dari bagian yang terpilih. Bila anda sudah selesai membaca teks itu, panah di bawah dapat digunakan untuk maju ke bagian berikut atau mundur ke yang sebelumnya. 
+
+<p>Di bawah judul dan pengarang terdapat tiga tombol. Klik pada <i>buka teks</i> untuk membuka semua teks dari dokumen terpilih. Bila dokumen besar, mungkin perlu menunggu lama dan banyak memori terpakai! Klik pada tombol <i>pisahkan</i> untuk membuka jendela baru untuk dokumen ini. (Hal ini dapat berguna bila anda ingin memperbandingkan dokumen, atau membaca dua dokumen sekaligus.)  Akhirnya, bila anda mencari kata tertentu, kata tersebut disoroti.  Klik pada tombol <i>tanpa penyorotan</i> untuk menghilangkan penyorotan.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Klik pada panah untuk maju ke bagian berikut ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... atau kembali ke bagian sebelumnya </td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Tampilkan semua teks, atau tidak</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Buka halaman ini dalam jendela baru</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Menyoroti istilah yang dicari, atau tidak</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=id] {<h2>Bagaimana mencari istilah tertentu</h2>
+<p>
+  Dari halaman Pencarian, anda dapat mengajukan pertanyaan dengan langkah berikut:<p>
+  
+  <ol><li>Memilih bahan yang ingin diselidiki 
+      <li>Menentukan apakah anda ingin mencari semua atau hanya beberapa dari istilah 
+      <li>Mengetik istilah yang dicari 
+      <li>Klik pada tombol <i>Mulai mencari</i> 
+  </ol>
+
+<p>Bila pertanyaan diajukan, judul dari 20 dokumen yang sesuai akan ditampilkan. Tombol di ujung daftar tersebut dapat ditekan untuk menampilkan 20 dokumen berikutnya, kemudian 20 dokumen lagi, dst. Untuk melihat isi dokumen, klik pada judul dokumen itu, atau pada lambang di sisiknya. 
+
+<p>Maksimal 100 dokumen dapat ditemukan. Jumlah ini dapat diganti dengan mengeklik pada tombol <i>preferensi</i> di atas halaman.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Istilah pencarian</h3>
+
+<p>Apa saja yang diketik dalam kotak pertanyaan dianggap sebagai daftar kata atau "istilah pencarian". Suatu istilah dapat mengandung hanya huruf A-Z dan angka 0-9. Istilah dipisahkan dengan spasi. Semua tanda lain (seperti tanda baca) dianggap sebagai spasi dan diabaikan. Kata yang mengandung tanda baca tidak dapat dicari.
+
+<p>Misalnya, pertanyaan<p>
+    <ul><kbd>Lada di Bangka-Belitung: Peluang untuk Agribisnis (1993)</kbd></ul>
+      <p>dianggap sebagai<p>
+      <ul><kbd> Lada di Bangka Belitung Peluang untuk Agribisnis 1993</kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Macam pertanyaan</h3>
+
+<p>Ada dua macam pertanyaan.
+
+<ul>
+  <li>Mencari <b>semua</b> kata. Pertanyaan ini mencari dokumen (atau bab atau 
+      judul) yang mengandung semua kata yang diketik dalam kotak pertanyaan.
+      Dokumen yang mengisi syarat itu ditampilkan dalan urutan abjad.<p>
+
+  <li>Mencari <b>beberapa</b> dari kata. Ketikkan saja daftar istilah yang
+      barangkali dimuat dalam dokumen yang dicari. Dokumen ditampilkan menurut
+      kesesuaiannya pada pertanyaan itu. Dalam menentukan dekatnya kesesuaian,
+
+      <p><ul>
+        <li> makin banyak istilah yang dikandung dokumen, makin dekat kesesuaiannya;
+        <li> istilah yang jarang dianggap lebih penting daripada istilah biasa;
+        <li> dokumen pendek dianggap lebih dekat kesesuaiannya daripada dokumen panjang.
+      </ul>
+</ul>
+
+<p>Anda dapat menggunakan sehendaknya banyak istilah pencarian--suatu kalimat penuh, atau bahkan alinea lengkap. Bila hanya satu istilah yang diketik, dokumen diurutkan menurut keseringan munculnya istilah itu.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=id] {Mencari menurut tanggal}
+
+_texthelpdatesearch_ [l=id] {<h2>_textdatesearch_</h2>
+Pencarian menurut tanggal memungkinkan pencarian dokumen yang sesuai dengan istilah yang dipilih dan juga mengenai peristiwa dalam kurung waktu tertentu. Dokumen dapat dicari dari tahun tertentu atau dari kisaran tahun. Istilah pencarian tidak perlu: dokumen juga dapat dicari menurut tanggal saja. Tidak perlu menggunakan tanggal dalam pencarian: bila tanggal tidak diketik, maka tanggal diabaikan.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>Bagaimana menggunakan fasilitas ini:</h3>
+<ul>
+   <li>Untuk mencari dokumen mengenai tahun tertentu:<p>
+   <ul>
+       <li>Masukkan istilah pencarian seperti biasa. 
+       <li>Ketikkan tahun yang dimaksud pada kotak "Tahun mulai (atau tunggal)". 
+       <li>Bila tahun yang dimaksud sebelum Masehi, pilihlah SM dari menu di sebelah. 
+       <li>Mulailah pencarian seperti biasa.
+   </ul>
+<p><li>Untuk mencari dokumen mengenai kisaran tahun:<p>
+   <ul>
+       <li>Masukkan istilah pencarian seperti biasa.
+       <li>Ketikkan tahun pertama pada kotak "Tahun mulai (atau tunggal)". 
+       <li>Ketikkan tahun terakhir pada kotak "Tahun akhir".
+       <li> Bila tahun yang dimaksud sebelum Masehi, pilihlah SM dari menu di sebelah. 
+       <li> Mulailah pencarian seperti biasa.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>Cara kerja pencarian</h3>
+
+Pada umumnya, pencarian dokumen mengenai tahun 1903 tidak akan menemukan dokumen yang mengutip buku yang tertulis pada tahun 1903, hanya dokumen mengenai 1903. Akan tetapi, dokumen ditemukan yang mengandung kisaran tahun (seperti 1899-1911) yang mencakupi 1903. Juga ditemukan dokumen yang menyebut abad itu (misalnya abad ke-20 atau abad keduapuluh). Hal ini berarti bahwa tahun yang dicari tidak muncul di teks. Cara kerja ini juga berlaku untuk setiap tahun dalam pencarian kisaran.<p>
+}
+
+_textchangeprefs_ [l=id] {Mengubah preferensi}
+
+_texthelppreferences_ [l=id] {<h2>_textchangeprefs_</h2>
+
+<p>Dengan mengeklik pada tombol <i>preferensi</i> di atas halaman, anda dapat mengubah beberapa fasilitas dari penampilan supaya cocok dengan kebutuhan anda.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Preferensi koleksi</h3>
+
+Koleksi dapat terdiri dari beberapa sub-koleksi, yang dapat dicari secara tersendiri atau bersamaan. Pada koleksi macam itu, anda dapat memilih sub-koleksi yang mana untuk diselidiki pada halaman Preferensi.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Preferensi bahasa</h3>
+
+Setiap koleksi ada bahasa penampilan yang standar, tetapi bahasa lain juga dapat dipilih. Anda juga dapat mengubah cara pengekodeaan yang digunakan oleh Greenstone untuk penyampaian hasil ke browser. Perangkat lunak memilih cara pengekodeaan secara otomatis, tetapi penampilan masih dapat diperbaiki di beberapa browser dengan memilih cara pengekodean yang lain. Semua koleksi memungkinkan pengantian penampilan grafis yang standar menjadi penampilan teks saja. Hal ini berguna untuk pengguna yang cacat mata yang memerlukan gaya huruf besar atau alat bicara untuk memperoleh keluaran.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Preferensi presentasi</h3>
+
+Dalam koleksi tertentu, beberapa pilihan dapat disetel yang mengendalikan presentasi. 
+
+<p>Di koleksi halaman web, mungkin menghilangkan menu navigasi Greenstone di atas setiap halaman, sehingga setelah menemukan halaman yang dicari, tidak ada kop Greenstone di atasnya. Untuk mencari lagi, harus menggunakan tombol "Back" (balik) di browser. Pada koleksi seperti itu juga mungkin menghilangkan pesan peringatan dari Greenstone yang ditampilkan bila anda klik pada link yang keluar dari koleksi dan masuk ke internet. Pada beberapa koleksi, mungkin mengendalikan apakah link di halaman "Hasil pencarian" meneruskan anda ke URL di internet, atau ke jiplakan halaman itu yang ada di koleksi. 
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Preferensi pencarian</h3>
+<p>Dua pasangan tombol mengendalikan macam penyesuaian teks yang dilakukan dalam pencarian. Pasangan pertama ("Pembedaan huruf besar/kecil") mengatur apakah huruf besar dan kecil harus persis sama dengan apa yang diketik. Pasangan kedua ("Akhiran kata") mengatur apakah akhiran kata diabaikan atau tidak. Mungkin menampilkan kotak pertanyaan besar untuk mencari kalimat atau alinea. Pencarian alinea cukup cepat. 
+
+<p>Misalnya, bila tombol <i>abaikan perbedaan</i> dan 
+<i>abaikan akhiran</i> dipilih, pertanyaan<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>akan dianggap sama dengan<p>
+      <ul><kbd>africa builds</kbd></ul><p>karena huruf besar di "African" akan
+      dijadikan huruf kecil, dan akhiran "n" dan "ing" dihapus dari "African"
+      dan "building" ("s" juga dihapus dari "builds").
+
+<p>Anda dapat pindah ke cara pencarian "lanjutan" yang memungkinkan penggunaan AND (&) [dan], OR (|) [atau], dan NOT (!) [tidak]. Hal ini memungkinkan pertanyaan lebih spesifik. Anda juga dapat menggunakan fasilitas riwayat pencarian, yang menampilkan beberapa pertanyaan yang terakhir ditampilkan. Fasilitas ini memungkinkan pengulangan dari pertanyaan dulu dengan nada sedikit berbeda. Anda juga dapat mengendalikan jumlah dokumen yang ditemukan, serta jumlah yang ditampilkan pada setiap layar. 
+}
+
+_texttanumbrowseoptions_ [l=id] {Ada _numbrowseoptions_ cara untuk menemukan informasi dalam koleksi ini:}
+
+_textsimplehelpheading_ [l=id] {Bagaimana mencari informasi}
+
+_texthelpscope_ [l=id] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Jangkauan pertanyaan</h3>
+
+<p>
+Dalam sebagian besar dari koleksi, anda dapat memilih di antara beberapa indeks. Misalnya, mungkin ada indeks pengarang atau judul. Atau indeks bab atau alinea. Pada umumnya, dokumen penuh ditampilkan, tanpa memperhatikan indeks yang digunakan.
+<p>Bila dokumen adalah buku, buku tsb dibuka pada tempat yang layak.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/italian.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/italian.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/italian.dm	(revision 10506)
@@ -0,0 +1,1338 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Italian Language text and icon macros 
+# Many thanks to Marco Michelino (translated August 2001)
+#            and Massimo Pesenti (updated March 2004) 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=it] {Periodici}
+_textsource_ [l=it] {Rif. fonte}
+_textdate_ [l=it] {data di pubblicazione:}
+_textnumpages_ [l=it] {n. di pagine}
+
+_textsignin_ [l=it] {Entra}
+
+_textdefaultcontent_ [l=it] {La pagina richiesta non Ãš disponibile.
+Usa il pulsante 'indietro' del tuo browser o il pulsante
+'Pagina principale' per tornare alla Greenstone Digital Library.}
+
+_textdefaulttitle_ [l=it] {Errore GSDL}
+
+_textbadcollection_ [l=it] {Questa collezione (denominata "_cvariable_") non Ãš installata in questa Greenstone Digital Library.}
+
+_textselectpage_ [l=it] {-- Seleziona la pagina --}
+
+_collectionextra_ [l=it] {Questa raccolta contiene _about:numdocs_ documenti.
+E' stata creata _about:builddate_ giorni fa.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=it] {<p>Questa raccolta contiene _numdocs_ _If_("_numdocs_" eq "1",documento,documenti), per un totale di _numbytes_.
+<p><a href="_httppagex_(bsummary)">Clicca qui</a> per visualizzare il sommario di questa collezione.}
+
+_textimagecollection_ [l=it] {}
+_textimageabout_ [l=it] {Informazioni su}
+_textimagehome_ [l=it] {Pagina principale}
+_textimagehelp_ [l=it] {Aiuto}
+_textimagepref_ [l=it] {Impostazioni}
+_textimagegreenstone_ [l=it] {Greenstone Digital Library Software}
+_textimageusab_ [l=it] {Cosa hai trovato difficile da usare?}
+
+_textimagesearch_ [l=it] {Cerca termini specifici}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=it] {Elenco alfabetico per titolo}
+_textimageCreator_ [l=it] {Elenco per autore}
+_textimageSubject_ [l=it] {Elenco per soggetto}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=it] {Elenco per data}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=it] {Elenco per nome originale del file}
+_textimageLanguage_ [l=it] {Elenco per lingua}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=it] {Elenco per organizzazione}
+_textimageKeyword_ [l=it] {Elenco per parola chiave}
+_textimageHowto_ [l=it] {Elenco per categorie di guide pratiche}
+_textimageList_ [l=it] {Elenco documenti}
+_textimageSeries_ [l=it] {Elenco per argomento}
+_textimageTo_ [l=it] {Elenco per destinatario}
+_textimageFrom_ [l=it] {Elenco per mittente}
+_textimageTopic_ [l=it] {Elenco argomenti particolari}
+_textimageBrowse_ [l=it] {Elenco}
+_textimageCollage_ [l=it] {Elenco per collage immagine}
+_textimagePeople_ [l=it] {Elenco per persone}
+_textimageAcronym_ [l=it] {Elenco acronimi}
+_textimagePhrase_ [l=it] {Elenco frasi}
+_textimageArtist_ [l=it] {Elenco artisti}
+_textimageVolume_ [l=it] {Elenco per volume}
+_textimageCountries_ [l=it] {Elenco per paese}
+_textimageCaptions_ [l=it] {Elenco per didascalia della foto}
+
+
+_texticontabsearchgreen_ [l=it] {Cerca}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=it] {Titoli A-Z}
+_texticontabCreatorgreen_ [l=it] {Autori A-Z}
+_texticontabSubjectgreen_ [l=it] {Soggetti}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=it] {Date}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=it] {Nomi dei file}
+_texticontabLanguagegreen_ [l=it] {Lingua}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=it] {Organizzazione}
+_texticontabKeywordgreen_ [l=it] {Parole chiave}
+_texticontabhowgreen_ [l=it] {Guide pratiche}
+_texticontabseriesgreen_ [l=it] {Serie}
+_texticontablistgreen_ [l=it] {Lista}
+_texticontabtogreen_ [l=it] {Destinatario}
+_texticontabfromgreen_ [l=it] {Mittente}
+_texticontabtopicgreen_ [l=it] {Argomento}
+_texticontabbrwsegreen_ [l=it] {Elenco}
+_texticontabCollagegreen_ [l=it] {Collage}
+_texticontabbrowsgreen_ [l=it] {Elenco}
+_texticontabPeoplegreen_ [l=it] {Persone A-Z}
+_texticontabAcronymgreen_ [l=it] {Acronimi}
+_texticontabPhrasegreen_ [l=it] {Frasi}
+_texticontabArtistgreen_ [l=it] {Artisti}
+_texticontabVolumegreen_ [l=it] {Volumi}
+_texticontabCaptionsgreen_ [l=it] {Didascalie}
+_texticontabCountriesgreen_ [l=it] {Paesi}
+
+_texticontext_ [l=it] {Visualizza il documento}
+_texticonclosedbook_ [l=it] {Apri questo documento e visualizza il contenuto}
+_texticonnext_ [l=it] {Prossima sezione}
+_texticonprev_ [l=it] {Sezione precedente}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=it] {Visualizza il documento MIDI}
+_texticonmsword_ [l=it] {Visualizza il documento Microsoft Word}
+_texticonmp3_ [l=it] {Visualizza il documento MP3}
+_texticonpdf_ [l=it] {Visualizza il documento PDF}
+_texticonps_ [l=it] {Visualizza il documento PS}
+_texticonppt_ [l=it] {Visualizza il documento PowerPoint}
+_texticonrtf_ [l=it] {Visualizza il documento RTF}
+_texticonxls_ [l=it] {Visualizza il documento Excel}
+
+_page_ [l=it] {pagina }
+_pages_ [l=it] {pagine}
+_of_ [l=it] {di }
+_vol_ [l=it] {Vol.}
+_num_ [l=it] {N.}
+
+_textmonth00_ [l=it] {}
+_textmonth01_ [l=it] {Gennaio}
+_textmonth02_ [l=it] {Febbraio}
+_textmonth03_ [l=it] {Marzo}
+_textmonth04_ [l=it] {Aprile}
+_textmonth05_ [l=it] {Maggio}
+_textmonth06_ [l=it] {Giugno}
+_textmonth07_ [l=it] {Luglio}
+_textmonth08_ [l=it] {Agosto}
+_textmonth09_ [l=it] {Settembre}
+_textmonth10_ [l=it] {Ottobre}
+_textmonth11_ [l=it] {Novembre}
+_textmonth12_ [l=it] {Dicembre}
+
+_textdocument_ [l=it] {Documento}
+_textsection_ [l=it] {Sezione}
+_textparagraph_ [l=it] {Paragrafo}
+
+_magazines_ [l=it] {Riviste}
+
+_nzdlpagefooter_ [l=it] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">Progetto New Zealand Digital Library</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Dipartimento di Informatica</a>,
+<a href="http://www.waikato.ac.nz">UniversitÃ  di Waikato</a>,
+Nuova Zelanda.}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "PAGINA PRINCIPALE" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=it] {_httpimg_/it/chomeof.gif}
+_httpiconchomeon_ [l=it] {_httpimg_/it/chomeon.gif}
+
+## "AIUTO" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=it] {_httpimg_/it/chelpof.gif}
+_httpiconchelpon_ [l=it] {_httpimg_/it/chelpon.gif}
+
+## "IMPOSTAZIONI" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=it] {_httpimg_/it/cprefof.gif}
+_httpiconcprefon_ [l=it] {_httpimg_/it/cprefon.gif}
+
+## "INVIA FEEDBACK" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=it] {_httpimg_/it/cusabof.gif}
+_httpiconcusabon_ [l=it] {_httpimg_/it/cusabon.gif}
+
+
+## "cerca" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=it] {_httpimg_/it/tsrchgr.gif}
+_httpicontsrchof_ [l=it] {_httpimg_/it/tsrchof.gif}
+_httpicontsrchon_ [l=it] {_httpimg_/it/tsrchon.gif}
+_widthtsrchx_ [l=it] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "titoli a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=it] {_httpimg_/it/ttitlgr.gif}
+_httpiconttitleof_ [l=it] {_httpimg_/it/ttitlof.gif}
+_httpiconttitleon_ [l=it] {_httpimg_/it/ttitlon.gif}
+_widthttitlex_ [l=it] {87}
+
+# Not true DC, kept for legacy reasons
+## "autori a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=it] {_httpimg_/it/tauthgr.gif}
+_httpicontcreatof_ [l=it] {_httpimg_/it/tauthof.gif}
+_httpicontcreaton_ [l=it] {_httpimg_/it/tauthon.gif}
+_widthtcreatx_ [l=it] {110}
+
+## "soggetti" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=it] {_httpimg_/it/tsubjgr.gif}
+_httpicontsubjon_ [l=it] {_httpimg_/it/tsubjon.gif}
+_httpicontsubjof_ [l=it] {_httpimg_/it/tsubjof.gif}
+_widthtsubjx_ [l=it] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "date" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=it] {_httpimg_/it/tdategr.gif}
+_httpicontdateof_ [l=it] {_httpimg_/it/tdateof.gif}
+_httpicontdateon_ [l=it] {_httpimg_/it/tdateon.gif}
+_widthtdatex_ [l=it] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "nomi dei file" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=it] {_httpimg_/it/tsrcgr.gif}
+_httpicontsrcof_ [l=it] {_httpimg_/it/tsrcof.gif}
+_httpicontsrcon_ [l=it] {_httpimg_/it/tsrcon.gif}
+_widthtsrcx_ [l=it] {87}
+
+## "lingue" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=it] {_httpimg_/it/tlanggr.gif}
+_httpicontlangon_ [l=it] {_httpimg_/it/tlangon.gif}
+_httpicontlangof_ [l=it] {_httpimg_/it/tlangof.gif}
+_widthtlangx_ [l=it] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "serie" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=it] {_httpimg_/it/tsergr.gif}
+_httpicontserof_ [l=it] {_httpimg_/it/tserof.gif}
+_httpicontseron_ [l=it] {_httpimg_/it/tseron.gif}
+_widthtserx_ [l=it] {87}
+
+## "destinatario" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=it] {_httpimg_/it/ttogr.gif}
+_httpiconttoon_ [l=it] {_httpimg_/it/ttoon.gif}
+_httpiconttoof_ [l=it] {_httpimg_/it/ttoof.gif}
+_widthttox_ [l=it] {87}
+
+## "mittente" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=it] {_httpimg_/it/tfromgr.gif}
+_httpicontfromon_ [l=it] {_httpimg_/it/tfromon.gif}
+_httpicontfromof_ [l=it] {_httpimg_/it/tfromof.gif}
+_widthtfromx_ [l=it] {87}
+
+## "organizzazione" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=it] {_httpimg_/it/torggr.gif}
+_httpicontorgon_ [l=it] {_httpimg_/it/torgon.gif}
+_httpicontorgof_ [l=it] {_httpimg_/it/torgof.gif}
+_widthtorgx_ [l=it] {114}
+
+## "guide pratiche" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=it] {_httpimg_/it/thowgr.gif}
+_httpiconthowon_ [l=it] {_httpimg_/it/thowon.gif}
+_httpiconthowof_ [l=it] {_httpimg_/it/thowof.gif}
+_widththowx_ [l=it] {87}
+
+## "argomento" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=it] {_httpimg_/it/ttopicgr.gif}
+_httpiconttopicon_ [l=it] {_httpimg_/it/ttopicon.gif}
+_httpiconttopicof_ [l=it] {_httpimg_/it/ttopicof.gif}
+_widthttopicx_ [l=it] {87}
+
+## "elenco" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=it] {_httpimg_/it/tbrwsegr.gif}
+_httpicontbrwseon_ [l=it] {_httpimg_/it/tbrwseon.gif}
+_httpicontbrwseof_ [l=it] {_httpimg_/it/tbrwseof.gif}
+_widthtbrwsex_ [l=it] {87}
+
+## "collage" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=it] {_httpimg_/it/tcollgr.gif}
+_httpicontcollof_ [l=it] {_httpimg_/it/tcollof.gif}
+_httpicontcollon_ [l=it] {_httpimg_/it/tcollon.gif}
+_widthtcollx_ [l=it] {87}
+
+## "persone" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=it] {_httpimg_/it/tpeopgr.gif}
+_httpicontpeopof_ [l=it] {_httpimg_/it/tpeopof.gif}
+_httpicontpeopon_ [l=it] {_httpimg_/it/tpeopon.gif}
+_widthtpeopx_ [l=it] {97}
+
+## "acronimi" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=it] {_httpimg_/it/tacrogr.gif}
+_httpicontacroof_ [l=it] {_httpimg_/it/tacroof.gif}
+_httpicontacroon_ [l=it] {_httpimg_/it/tacroon.gif}
+_widthtacrox_ [l=it] {87}
+
+## "frasi" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=it] {_httpimg_/it/tphrsegr.gif}
+_httpicontphrseof_ [l=it] {_httpimg_/it/tphrseof.gif}
+_httpicontphrseon_ [l=it] {_httpimg_/it/tphrseon.gif}
+_widthtphrsex_ [l=it] {87}
+
+## "artisti" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=it] {_httpimg_/it/tartstgr.gif}
+_httpicontartstof_ [l=it] {_httpimg_/it/tartstof.gif}
+_httpicontartston_ [l=it] {_httpimg_/it/tartston.gif}
+_widthtartstx_ [l=it] {87}
+
+## "parole chiave" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=it] {_httpimg_/it/tkwgr.gif}
+_httpicontkwof_ [l=it] {_httpimg_/it/tkwof.gif}
+_httpicontkwon_ [l=it] {_httpimg_/it/tkwon.gif}
+_widthtkwx_ [l=it] {87}
+
+## "volumi" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=it] {_httpimg_/it/tvolgr.gif}
+_httpicontvolof_ [l=it] {_httpimg_/it/tvolof.gif}
+_httpicontvolon_ [l=it] {_httpimg_/it/tvolon.gif}
+_widthtvolx_ [l=it] {87}
+
+## "didascalie" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=it] {_httpimg_/it/tcaptgr.gif}
+_httpicontcaptof_ [l=it] {_httpimg_/it/tcaptof.gif}
+_httpicontcapton_ [l=it] {_httpimg_/it/tcapton.gif}
+_widthtcaptx_ [l=it] {87}
+
+## "paesi" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=it] {_httpimg_/it/tcountgr.gif}
+_httpicontcountof_ [l=it] {_httpimg_/it/tcountof.gif}
+_httpicontcounton_ [l=it] {_httpimg_/it/tcounton.gif}
+_widthtcountx_ [l=it] {87}
+
+## "aiuto" ## green_title ## h_help ##
+_httpiconhhelp_ [l=it] {_httpimg_/it/h\_help.gif}
+_widthhhelp_ [l=it] {200}
+_heighthhelp_ [l=it] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=it] {Informazioni su questa raccolta}
+
+_textsubcols1_ [l=it] {<p>La raccolta completa comprende _1_ sottoraccolte.
+Quelle attualmente disponibili sono:
+<blockquote>}
+
+_textsubcols2_ [l=it] {</blockquote>
+Puoi controllare (e modificare) le sottoraccolte che stai
+correntemente utilizzando nella pagina Impostazioni.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "informazioni su" ## green_title ## h_about ##
+_httpiconhabout_ [l=it] {_httpimg_/it/h\_about.gif}
+_widthhabout_ [l=it] {200}
+_heighthabout_ [l=it] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=it] {Titoli A-Z}
+_texticonhcreat_ [l=it] {Autori A-Z}
+_texticonhsubj_ [l=it] {Soggetti}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=it] {Date}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=it] {Nomi dei file}
+_texticonhlang_ [l=it] {Lingua}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+_texticonhcoll_ [l=it] {Collage}
+_texticonhto_ [l=it] {Destinatario}
+_texticonhfrom_ [l=it] {Mittente}
+_texticonhser_ [l=it] {Serie}
+_texticonhhow_ [l=it] {Guide pratiche}
+_texticonhorg_ [l=it] {Organizzazione}
+_texticonhbrwse_ [l=it] {Elenco}
+_texticonhbrows_ [l=it] {Elenco}
+_texticonhpeople_ [l=it] {Persone A-Z}
+_texticonhacronym_ [l=it] {Acronimi}
+_texticonhphrases_ [l=it] {Frasi}
+_texticonhartist_ [l=it] {Artisti}
+_texticonhkw_ [l=it] {Parole chiave}
+_texticonhvol_ [l=it] {Volumi}
+_texticonhcapt_ [l=it] {Didascalie}
+_texticonhcount_ [l=it] {Paesi}
+
+_texticonopenbookshelf_ [l=it] {Chiudi questa sezione della biblioteca}
+_texticonclosedbookshelf_ [l=it] {apri questa sezione della biblioteca e mostra il contenuto}
+_texticonopenbook_ [l=it] {Chiudi questo libro}
+_texticonclosedfolder_ [l=it] {Apri questa cartella e mostra il contenuto}
+_texticonclosedfolder2_ [l=it] {apri la sottosezione: }
+_texticonopenfolder_ [l=it] {Chiudi questa cartella}
+_texticonopenfolder2_ [l=it] {Chiudi la sottosezione: }
+_texticonsmalltext_ [l=it] {Mostra questa sezione del testo}
+_texticonsmalltext2_ [l=it] {Mostra testo: }
+_texticonpointer_ [l=it] {Sezione corrente}
+_texticondetach_ [l=it] {Apri questa pagina in una nuova finestra}
+_texticonhighlight_ [l=it] {Evidenzia le parole cercate}
+_texticonnohighlight_ [l=it] {Non evidenziare le parole cercate}
+_texticoncontracttoc_ [l=it] {Nascondi indice}
+_texticonexpandtoc_ [l=it] {Mostra indice}
+_texticonexpandtext_ [l=it] {Mostra tutto il testo}
+_texticoncontracttext_ [l=it] {Mostra il testo solo per la sezione correntemente selezionata}
+_texticonwarning_ [l=it] {<b>Attenzione: </b>}
+_texticoncont_ [l=it] {continuare?}
+
+_textltwarning_ [l=it] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_ mostrare il testo qui significa una
+grande quantitÃ  di dati _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=it] {vai a pagina}
+_textintro_ [l=it] {<i>(introduzione)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "titoli a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=it] {_httpimg_/it/h\_title.gif}
+_widthhtitle_ [l=it] {200}
+_heighthtitle_ [l=it] {57}
+
+# Not true DC, kept for legacy reasons
+## "autori a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=it] {_httpimg_/it/h\_auth.gif}
+_widthhcreat_ [l=it] {200}
+_heighthcreat_ [l=it] {57}
+
+## "soggetto" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=it] {_httpimg_/it/h\_subj.gif}
+_widthhsubj_ [l=it] {200}
+_heighthsubj_ [l=it] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "date" ## green_title ## h_date ##
+_httpiconhdate_ [l=it] {_httpimg_/it/h\_date.gif}
+_widthhdate_ [l=it] {200}
+_heighthdate_ [l=it] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "nomi dei file" ## green_title ## h_src ##
+_httpiconhsrc_ [l=it] {_httpimg_/it/h\_src.gif}
+_widthhsrc_ [l=it] {200}
+_heighthsrc_ [l=it] {57}
+
+## "lingua" ## green_title ## h_lang ##
+_httpiconhlang_ [l=it] {_httpimg_/it/h\_lang.gif}
+_widthhlang_ [l=it] {200}
+_heighthlang_ [l=it] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "destinatario" ## green_title ## h_to ##
+_httpiconhto_ [l=it] {_httpimg_/it/h\_to.gif}
+_widthhto_ [l=it] {200}
+_heighthto_ [l=it] {57}
+
+## "mittente" ## green_title ## h_from ##
+_httpiconhfrom_ [l=it] {_httpimg_/it/h\_from.gif}
+_widthhfrom_ [l=it] {200}
+_heighthfrom_ [l=it] {57}
+
+## "serie" ## green_title ## h_ser ##
+_httpiconhser_ [l=it] {_httpimg_/it/h\_ser.gif}
+_widthhser_ [l=it] {200}
+_heighthser_ [l=it] {57}
+
+## "guide pratiche" ## green_title ## h_how ##
+_httpiconhhow_ [l=it] {_httpimg_/it/h\_how.gif}
+_widthhhow_ [l=it] {200}
+_heighthhow_ [l=it] {57}
+
+## "argomento" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=it] {_httpimg_/it/h\_topic.gif}
+_widthhtopic_ [l=it] {200}
+_heighthtopic_ [l=it] {57}
+
+## "organizzazione" ## green_title ## h_org ##
+_httpiconhorg_ [l=it] {_httpimg_/it/h\_org.gif}
+_widthhorg_ [l=it] {250}
+_heighthorg_ [l=it] {57}
+
+## "elenco" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=it] {_httpimg_/it/h\_brwse.gif}
+_widthhbrwse_ [l=it] {200}
+_heighthbrwse_ [l=it] {57}
+
+# -- Missing translation: h_coll
+_httpiconhcoll_ [l=it] {_httpimg_/it/h\_coll.gif}
+_widthhcoll_ [l=it] {200}
+_heighthcoll_ [l=it] {57}
+
+## "persone" ## green_title ## h_people ##
+_httpiconhpeople_ [l=it] {_httpimg_/it/h\_people.gif}
+_widthhpeople_ [l=it] {200}
+_heighthpeople_ [l=it] {57}
+
+## "acronimi" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=it] {_httpimg_/it/h\_acro.gif}
+_widthhacronym_ [l=it] {200}
+_heighthacronym_ [l=it] {57}
+
+## "frasi" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=it] {_httpimg_/it/h\_phrse.gif}
+_widthhphrse_ [l=it] {200}
+_heighthphrse_ [l=it] {57}
+
+## "artisti" ## green_title ## h_artist ##
+_httpiconhartist_ [l=it] {_httpimg_/it/h\_artist.gif}
+_widthhartist_ [l=it] {200}
+_heighthartist_ [l=it] {57}
+
+## "parole chiave" ## green_title ## h_kw ##
+_httpiconhkw_ [l=it] {_httpimg_/it/h\_kw.gif}
+_widthhkw_ [l=it] {200}
+_heighthkw_ [l=it] {57}
+
+## "volumi" ## green_title ## h_vol ##
+_httpiconhvol_ [l=it] {_httpimg_/it/h\_vol.gif}
+_widthhvol_ [l=it] {200}
+_heighthvol_ [l=it] {57}
+
+## "paesi" ## green_title ## h_count ##
+_httpiconhcount_ [l=it] {_httpimg_/it/h\_count.gif}
+_widthhcount_ [l=it] {200}
+_heighthcount_ [l=it] {57}
+
+## "didascalie" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=it] {_httpimg_/it/h\_capt.gif}
+_widthhcapt_ [l=it] {200}
+_heighthcapt_ [l=it] {57}
+
+
+## "CONTINUA??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=it] {_httpimg_/it/contof.gif}
+_httpiconconton_ [l=it] {_httpimg_/it/conton.gif}
+
+## "ESPANDI\nTESTO" ## document_button ## eallt ##
+_httpiconealltof_ [l=it] {_httpimg_/it/ealltof.gif}
+_httpiconeallton_ [l=it] {_httpimg_/it/eallton.gif}
+
+## "NASCONDI\nINDICE" ## document_button ## econc ##
+_httpiconeconcof_ [l=it] {_httpimg_/it/econcof.gif}
+_httpiconeconcon_ [l=it] {_httpimg_/it/econcon.gif}
+
+## "NUOVA\nFINESTRA" ## document_button ## edtch ##
+_httpiconedtchof_ [l=it] {_httpimg_/it/edtchof.gif}
+_httpiconedtchon_ [l=it] {_httpimg_/it/edtchon.gif}
+
+## "MOSTRA\nINDICE" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=it] {_httpimg_/it/eexpcof.gif}
+_httpiconeexpcon_ [l=it] {_httpimg_/it/eexpcon.gif}
+
+## "NASCONDI\nTESTO" ## document_button ## etsec ##
+_httpiconetsecof_ [l=it] {_httpimg_/it/etsecof.gif}
+_httpiconetsecon_ [l=it] {_httpimg_/it/etsecon.gif}
+
+## "EVIDENZIA" ## document_button ## ehl ##
+_httpiconehlof_ [l=it] {_httpimg_/it/ehlof.gif}
+_httpiconehlon_ [l=it] {_httpimg_/it/ehlon.gif}
+
+## "NON\nEVIDENZIARE" ## document_button ## enhl ##
+_httpiconenhlof_ [l=it] {_httpimg_/it/enhlof.gif}
+_httpiconenhlon_ [l=it] {_httpimg_/it/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=it] {_If_(_thislast_,risultati _thisfirst_ - _thislast_ della ricerca: _cgiargq_,Nessun risultato della ricerca: _cgiargq_)}
+_textnoquerytitle_ [l=it] {Pagina di ricerca}
+
+_texticonthispage_ [l=it] {cerca}
+_textsome_ [l=it] {almeno una delle}
+_textall_ [l=it] {tutte le}
+_textboolean_ [l=it] {booleano}
+_textranked_ [l=it] {posizione}
+_textnatural_ [l=it] {naturale}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=it] {}
+_texticonsearchhistorybar_ [l=it] {storico ricerca}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=it] {Cerca}
+_textfreqmsg1_ [l=it] {Conteggio parole: }
+_textpostprocess_ [l=it] {_If_(_quotedquery_,<br><i>trasformata in _quotedquery_</i>
+)}
+_textinvalidquery_ [l=it] {Invalida sintassi di ricerca}
+
+_textmorethan_ [l=it] {PiÃ¹ di }
+_textapprox_ [l=it] {Circa }
+_textnodocs_ [l=it] {Nessun documento soddisfa le condizioni.}
+_text1doc_ [l=it] {1 documento soddisfa le condizioni.}
+_textlotsdocs_ [l=it] {documenti soddisfano le condizioni.}
+_textmatches_ [l=it] {Trovati }
+_textbeginsearch_ [l=it] {Inizia ricerca}
+_textrunquery_ [l=it] {Esegui ricerca}
+_textclearform_ [l=it] {Pulisci maschera}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=it] {Parola o frase}
+_textinfield_ [l=it] {... nel campo}
+_textfoldstem_ [l=it] {(desinenza, radice)}
+
+_textadvquery_ [l=it] {O inserisci direttamente una query:}
+_textallfields_ [l=it] {Tutti i campi}
+_texttextonly_ [l=it] {solo testo}
+_textand_ [l=it] {e}
+_textor_ [l=it] {o}
+_textandnot_ [l=it] {e non}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=it] {Cerca _indexselection_ _If_(_jselection_,di _jselection_ )_If_(_gselection_, a livello _gselection_ )_If_(_nselection_,in lingua _nselection_ )contenenti _querytypeselection_ parole specificate}
+
+_textadvancedsearch_ [l=it] {Cerca _indexselection_ _If_(_jselection_,di _jselection_ )_If_(_gselection_, a livello _gselection_ )_If_(_nselection_,in lingua _nselection_ )secondo _querytypeselection_}
+
+_textformsimplesearch_ [l=it] {Cerca _If_(_jselection_,_jselection_ )_If_(_gformselection_,a livello _gformselection_ ) _If_(_nselection_,in lingua _nselection_ )contenenti _formquerytypeselection_ di}
+
+_textformadvancedsearch_ [l=it] {Cerca _If_(_jselection_,_jselection_ )_If_(_gformselection_,a livello di _gformselection_ )_If_(_nselection_,in lingua _nselection_ )e mostra i risultati in ordine _formquerytypeselection_}
+
+
+_textnojsformwarning_ [l=it] {Attenzione: Javascript Ãš disabilitato sul tuo browser. <br> Abilitalo per vuoi utilizzare il campo ricerca}
+_textdatesearch_ [l=it] {In questa raccolta si possono anche cercare documenti compresi in un intervallo di date o contenenti una particolare data. }
+_textstartdate_ [l=it] {Data iniziale (o  data):}
+_textenddate_ [l=it] {Data finale:}
+_textbc_ [l=it] {A.C.}
+_textad_ [l=it] {D.C.}
+_textexplaineras_ [l=it] {C.E. e B.C.E. sono alternativi rispettivamente a D.C. e A.C. Questi termini vengono impiegati per evitare discriminazioni culturali e stanno per "Common Era" e "Before Common Era"}
+
+_textstemon_ [l=it] {(ignora la declinazione delle parole)}
+
+_textsearchhistory_ [l=it] {Storico ricerca}
+
+#text macros for search history
+_textnohistory_ [l=it] {Storico ricerca non disponibile}
+_texthresult_ [l=it] {risultato}
+_texthresults_ [l=it] {risultati}
+_texthallwords_ [l=it] {tutte le parole}
+_texthsomewords_ [l=it] {almeno una parola}
+_texthboolean_ [l=it] {booleana}
+_texthranked_ [l=it] {classifica}
+_texthcaseon_ [l=it] {maiuscole e minuscole devono coincidere}
+_texthcaseoff_ [l=it] {maiuscole e minuscole non devono coincidere}
+_texthstemon_ [l=it] {radice}
+_texthstemoff_ [l=it] {parola intera}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "cerca" ## green_title ## h_search ##
+_httpiconhsearch_ [l=it] {_httpimg_/it/h\_search.gif}
+_widthhsearch_ [l=it] {200}
+_heighthsearch_ [l=it] {57}
+
+## "risultati" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=it] {_httpimg_/it/qryresb.gif}
+_widthqryresb_ [l=it] {_pagewidth_}
+_heightqryresb_ [l=it] {17}
+
+## "storico" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=it] {_httpimg_/it/schhistb.gif}
+_widthsrchhistb_ [l=it] {_pagewidth_}
+_heightsrchhistb_ [l=it] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=it] {Le impostazioni sono state fissate come riportato di seguito.
+Non usare il pulsante "indietro" del tuo browser - le cancellerebbe!
+Fai click invece su uno dei pulsanti della barra soprastante.
+}
+_textsetprefs_ [l=it] {modifica impostazioni}
+_textsearchprefs_ [l=it] {impostazioni di ricerca}
+_textcollectionprefs_ [l=it] {impostazioni della raccolta}
+_textpresentationprefs_ [l=it] {impostazioni di visualizzazione}
+_textpreferences_ [l=it] {Impostazioni}
+_textcasediffs_ [l=it] {Maiuscole:}
+_textignorecase_ [l=it] {ignora maiuscole}
+_textmatchcase_ [l=it] {maiuscole e minuscole devono corrispondere}
+_textwordends_ [l=it] {Parole:}
+_textstem_ [l=it] {ignora la declinazione delle parole}
+_textnostem_ [l=it] {la parola completa deve corrispondere}
+_textprefop_ [l=it] {Cerca fino a _maxdocoption_ risultati, _hitsperpageoption_ per pagina.}
+_textextlink_ [l=it] {Accesso a pagine web esterne:}
+_textintlink_ [l=it] {Documenti originali presi da:}
+_textlanguage_ [l=it] {Lingua dell'interfaccia:}
+_textencoding_ [l=it] {Codifica:}
+_textformat_ [l=it] {Formato dell'interfaccia:}
+_textall_ [l=it] {tutte}
+_textquerymode_ [l=it] {ModalitÃ  ricerca:}
+_textsimplemode_ [l=it] {ricerca semplice}
+_textadvancedmode_ [l=it] {ricerca avanzata (permette espressioni booleane che contengono !, &, |, e parentesi)}
+_textlinkinterm_ [l=it] {attraverso pagina intermedia}
+_textlinkdirect_ [l=it] {vai direttamente}
+_textdigitlib_ [l=it] {la biblioteca digitale}
+_textweb_ [l=it] {il web}
+_textgraphical_ [l=it] {Grafica}
+_texttextual_ [l=it] {Testuale}
+_textcollectionoption_ [l=it] {<p>
+Sottoraccolte da includere:
+<br>}
+
+_textrelateddocdisplay_ [l=it] {mostra documenti correlati}
+_textsearchhistory_ [l=it] {Storico della ricerca:}
+_textnohistory_ [l=it] {Storico ricerca non presente}
+_texthistorydisplay_ [l=it] {mostra _historynumrecords_ elementi dello storico}
+_textnohistorydisplay_ [l=it] {non mostrare lo storico della ricerca}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=it] {ricerca attraverso modulo:}
+_textplainsearch_ [l=it] {Ricerca base:}
+_textqueryboxsize_ [l=it] {Dimensioni della casella di ricerca:}
+_textregbox_ [l=it] {casella normale}
+_textbigbox_ [l=it] {casella grande}
+_textformtype_ [l=it] {Tipo di modulo:}
+_textsimple_ [l=it] {semplice}
+_textadvanced_ [l=it] {avanzato}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=it] {con}
+_textfields_ [l=it] {campi}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "impostazioni" ## green_title ## h_pref ##
+_httpiconhpref_ [l=it] {_httpimg_/it/h\_pref.gif}
+_widthhpref_ [l=it] {200}
+_heighthpref_ [l=it] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=it] {Elenca documenti per}
+_textalsoshowing_ [l=it] {mostrare anche}
+_textwith_ [l=it] {con al massimo}
+_textdocsperpage_ [l=it] {documenti per pagina}
+
+_textfilterby_ [l=it] {Elenca i documenti contenenti}
+_textall_ [l=it] {tutte le parole}
+_textany_ [l=it] {almeno una parola}
+_textwords_ [l=it] {delle parole}
+_textleaveblank_ [l=it] {lascia vuota questa casella per vedere tutti i documenti}
+
+_browsebuttontext_ [l=it] {Elenco}
+
+_nodata_ [l=it] {<i>nessun dato</i>}
+_docs_ [l=it] {documenti}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=it] {Aiuto}
+_textSearchshort_ [l=it] {ricerca per parole}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=it] {elenco per titolo}
+_textCreatorshort_ [l=it] {elenco per autore}
+_textSubjectshort_ [l=it] {elenco per soggetti}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=it] {elenco per data di pubblicazione}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=it] {elenco per nome del file}
+_textLanguageshort_ [l=it] {elenco per lingua}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=it] {elenco per serie}
+_textToshort_ [l=it] {elenco per destinatario}
+_textFromshort_ [l=it] {elenco per mittente}
+_textBrowseshort_ [l=it] {elenco pubblicazioni}
+_textOrganizationshort_ [l=it] {elenco per organizzazione}
+_textHowtoshort_ [l=it] {elenco per categorie di guide pratiche}
+_textTopicshort_ [l=it] {elenco per argomento}
+_textPeopleshort_ [l=it] {elenco per persone}
+_textAcronymshort_ [l=it] {elenco per acronimi utilizzati}
+_textPhraseshort_ [l=it] {elenco per occorrenza di frasi}
+_textArtistshort_ [l=it] {elenco per artisti}
+_textKeywordshort_ [l=it] {elenco per parole chiave}
+_textVolumeshort_ [l=it] {elenco per volume}
+_textCountriesshort_ [l=it] {elenco per paesi}
+_textdefaultshorttext_ [l=it] {classificatione non definita}
+
+_textSearchlong_ [l=it] {<p>Puoi effettuare la <i>ricerca per parole</i> nella pagina "ricerca".
+Questa Ãš la prima pagina che ti appare e puÃ² essere raggiunta premendo il
+pulsante <i>cerca</i>.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=it] {<p>Puoi <i>accedere alle publicazioni per titolo</i>
+premendo il pulsante <i>titoli a-z</i>. Questo ti mostra un elenco di
+ libri in ordine alfabetico. }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni per autore</i>
+premendo il pulsante <i>autori a-z</i>. Questo mostra l'elenco di libri
+ ordinati per autore. }
+
+_textSubjectlong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni per soggetto</i> premendo il pulsante
+<i>soggetti</i>. Questo mostra la lista dei soggetti. }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni per data</i>
+premendo il pulsante <i>date</i>. Questo mostrerÃ  l'elenco di tutti
+i documenti ordinati cronologicamente. }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni in base al nome del file</i>
+premendo il pulsante <i>nomi del file</i>. Questo mostrerÃ  la lista dei documenti ordinati in base
+al nome originale del file.}
+
+_textLanguagelong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni in base alla lingua</i>
+premendo il pulsante <i>lingue</i>. Questo mostrerÃ  la lista dei documenti ordinati in base
+alla lingua. }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni
+per organizzazione</i> premendo il pulsante <i>organizzazioni</i>.
+Questo mostrerÃ  l'elenco delle organizzazioni.  }
+
+_textHowtolong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni per categorie di guide pratiche</i>
+premendo il pulsante <i>guide pratiche</i>.
+Questo ti mostra una lista di di categorie di guide pratiche. }
+
+_textTopiclong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni per argomento</i>
+premendo il pulsante <i>argomento</i>.
+Questo mostra l'elenco di argomenti da scegliere. }
+
+_textTolong_ [l=it] {<p>Puoi <i>accedere alle email per destinatario</i> premendo il pulsante
+<i>destinatario</i>Questo mostrerÃ  un elenco di indirizzi.  }
+
+_textFromlong_ [l=it] {<p>Puoi <i>accedere alle email per mittente</i>
+premendo il pulsante <i>mittente</i>. Questo mostrerÃ  l'elenco dei mittenti. }
+
+_textSerieslong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni per serie</i>
+premendo il pulsante <i>serie</i>. Questo mostrerÃ  l'elenco delle serie
+presenti nella raccolta.  }
+
+_textBrowselong_ [l=it] {<p>Puoi <i>visualizzare l'elenco delle pubblicazioni</i>
+premendo il pulsante <i>elenco</i>.  }
+
+_textPeoplelong_ [l=it] {<p>Puoi <i>accedere alle publicazioni in base alle persone</i>
+premendo il pulsante <i>persone a-z</i>. Questo mostrerÃ  l'elenco delle persone
+ordinato per cognome.  }
+
+_textAcronymlong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni tramite gli acronimi che vi compaiono</i>
+premendo il pulsante <i>acronimi</i>. Questo mostrerÃ  un elenco di acronimi e dei punti nei quale essi compaiono.  }
+
+_textPhraselong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni tramite le frasi che vi occorrono</i>
+premendo il pulsante <i>frasi</i>.  }
+
+_textArtistlong_ [l=it] {<p>Puoi <i> accedere alle pubblicazioni tramite gli artisti</i> premendo il pulsante <i>artisti</i>. Questo mostrerÃ  un elenco di voci ordinate per nome di artista.}
+
+_textKeywordlong_ [l=it] {<p>Puoi <i> accedere alle pubblicazioni per parola chiave</i> premendo il pulsante <i>parole chiave</i>. Questo mostrerÃ  un elenco di parole chiave.}
+
+_textVolumelong_ [l=it] {<p>Puoi <i>accedere alle pubblicazioni per volume</i> premendo il pulsante <i>volumi</i>. Verra` presentata una lista per volume.}
+
+_textCaptionslong_ [l=it] {<p>Puoi <i> accedere alle pubblicazioni tramite didascalia</i> premendo il pulsante <i>didascalie</i>. Questo mostrerÃ  un elenco di didascalie.}
+
+_textCountrieslong_ [l=it] {<p>Puoi <i> accedere alle pubblicazioni tramite il paese</i> premendo il pulsante <i>paesi</i>. Questo mostrerÃ  un elenco di paesi.}
+
+
+_textdefaultlongtext_ [l=it] {<p>Premi il pulsante <i>sconosciuto</i> per navigare tra pubblicazioni
+ordinate in base ad un campo sconosciuto.  }
+
+_texthelptopics_ [l=it] {<h2 align=left>Argomenti</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Come cercare particolari parole</a>
+<ul>
+  <li><a href="\#query-terms">Ricerca parole</a>
+  <li><a href="\#query-type">Tipo di ricerca</a>
+  <li><a href="\#scope-of-queries">Documenti interessati dalla ricerca</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Impostazioni relative alla raccolta</a>
+  <li><a href="\#lang-prefs">Impostazioni della lingua</a>
+  <li><a href="\#pres-prefs">Impostazioni dell'interfaccia</a>
+  <li><a href="\#search-prefs">Impostazioni della ricerca</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=it] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=it] {Come leggere i documenti}
+
+_texthelpreadingdocs_ [l=it] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Puoi sapere quando sei arrivato ad uno specifico documento in quanto
+il titolo e l'autore appaiono in alto a sinistra nella pagina. Inoltre
+appare il numero della pagina corrente, una casella che ti permette
+di scegliere la pagina da visualizzare e delle frecce per andare avanti ed indietro.
+
+<p>Sotto c'Ãš il testo della sezione corrente. Sotto di esso ci sono delle
+frecce per tornare alla sezione precedente o per spostarsi alla successiva.
+
+<p>Sotto il titolo e l'autore ci sono tre pulsanti. Clicka su <i>espandi
+testo</i> per visualizzare tutto il testo del documento corrente. Se il
+documento Ãš molto grande questo richiederÃ  molto tempo e molta memoria!
+Clicka su <i>nuova finestra</i> per aprire una nuova finestra del browser contenente
+il documento. (Questo puÃ² essere utile se desideri confrontare due documenti o
+leggere piÃ¹ di un documento alla volta.) Infine quando effettui una ricerca
+le parole cercate appaiono evidenziate, clicka su <i>non evidenziaziare</i> per rimuovere la sottolineatura.
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Clicka sulla freccia per andare alla prossima sezione...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... o per tornare a quella precedente</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img
+src="_document:httpiconetsecof_" border="0"></td><td>Mostra (o no) tutto il testo</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Mostra questa pagina in una nuova finestra</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Evidenzia (o no) le parole cercate</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=it] {<h2>Come cercare parole particolari</h2>
+<p>
+  Dalla pagina di ricerca, puoi cercare tramite questi semplici passi:<p>
+
+  <ol><li>Specifica in che ambito effettuare la ricerca
+      <li>Specifica se vuoi cercare tutte o alcune delle parole
+      <li>Scrivi le parole che vuoi cercare
+      <li>Clicka il pulsante <i>Ricerca</i>
+  </ol>
+
+<p>Quando effettui una ricerca, appaiono i titoli di venti documenti.
+Il pulsante in basso ti permette di visualizzare i successivi venti.
+Una volta premuto appariranno i pulsanti che ti permettono di visualizzare i
+venti documenti successivi o quelli precedenti.
+Clicka sul titolo di un documento, o sul piccolo pulsante affianco ad esso,
+per visualizzarne il contenuto.
+
+<p>Il numero massimo di documenti elencati Ãš fissato a 100.
+Puoi modificare questo numero clickando sul pulsante <i>impostazioni</i>
+nella parte alta della pagina.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Parole da cercare</h3>
+
+<p>Qualsiasi cosa scrivi nella casella di ricerca viene interpretato come
+"parole da cercare". Ogni parola non contiene nient'altro che caratteri
+alfabetici e cifre numeriche. Le parole sono separate da spazi.
+Se altri caratteri (come i segni di punteggiatura) appaiono, questi verranno
+utilizzati per separare le parole come se fossero spazi. Non Ãš possibile
+ricercare parole che includono segni di punteggiatura.
+
+<p>Per esempio la ricerca:<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>verrÃ  trattata come se fosse:<p>
+      <ul><kbd>Agro forestry in the Pacific Islands Systems for Sustainability 1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Tipi di ricerca</h3>
+
+<p>Ci sono due differenti tipi di ricerca:
+
+<ul>
+  <li>Ricerca di <b>tutte</b> le parole. In questo caso si cercano documenti
+  (o capitoli o titoli) che contengano tutte le parole specificate.
+  I documenti che soddisfano questa condizine sono elencati in ordine alfabetico.<p>
+
+  <li>Ricerca di <b>alcune</b> delle parole. Scrivi alcune delle parole che
+  probabilmente compariranno nei documenti che stai cercando. I documenti verranno
+  elencati in base al grado di corrispondenza alla ricerca effettuata. Nella
+  determinazione del grado di corrispondenza,
+
+      <p><ul>
+        <li> piÃ¹ parole da cercare il documento contiene, piÃ¹ elevato Ãš il grado;
+        <li> le parole rare sono piÃ¹ importanti delle parole comuni;
+        <li> i documenti corti corrispondono meglio di quelli lunghi.
+      </ul>
+</ul>
+
+<p>Usa quante parole da cercare desideri - una intera frase o anche
+un intero paragrafo. Se specifichi una sola parola i documenti saranno ordinati
+in base al numero di volte in cui occorre quella parola in ognuno.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=it] {Ricerca per data}
+
+_texthelpdatesearch_ [l=it] {<h2>_textdatesearch_</h2>
+La ricerca per data permette di trovare documenti che, oltre a contenere parole da cercare,
+riguardano eventi avvenuti in un certo intervallo temporale.
+Puoi cercare documenti di un certo anno o in una serie di anni.
+Nota che non Ãš indispensabile inserire parole da cercare, puoi effettuare
+ricerche anche solo sulle date, cosÃ¬ come non Ãš necessario inserire delle date;
+se non scrivi alcuna data Ãš come se si effettuasse una ricerca non per data.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>Come utilizzare questa funzionalitÃ :</h3>
+<ul>
+   <li>Come cercare documenti riguardanti un singolo anno:<p>
+   <ul>
+       <li>Scrivi le parole da cercare come faresti normalmente.
+       <li>Scrivi l'anno nella casella "Data iniziale (o data)".
+       <li>Se la data Ãš Avanti Cristo,
+       scegli l'opzione A.C. dal menu a tendina a fianco.
+       <li>Avvia la ricerca come faresti normalmente.
+   </ul>
+<p><li>Per cercare documenti riguardanti un periodo di tempo o un intervallo di anni:<p>
+   <ul>
+       <li>Scrivi le parole da cercare come faresti normalmente.
+       <li>Scrivi la data di partenza nella casella "Data iniziale (o data)".
+       <li>Scrivi la data finale nella casella "Data finale".
+       <li>Seleziona A.C. dal menu a tendina per ogni data Avanti Cristo.
+       <li>Avvia la ricerca come faresti normalmente.
+   </ul>
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>Come funziona la ricerca</h3>
+
+Generalmente una ricerca di documenti riguardanti l'anno 1903 non mostrerÃ  quelli che, ad esempio,
+sono stati scritti nel 1903, solo i documenti che riguardano il 1903. In ogni modo, verranno trovati i documenti
+che hanno nel testo un'intervallo di date (ad esempio 1899-1911) in cui rientra il 1903, e tutti i documenti
+che hanno nel testo il nome del secolo di cui Ãš parte il 1903 (ad esempio 20th century o twentieth century).
+Questo significa che per alcuni documenti la data ricercata potrebbe non apparire nel testo. Se si effettua la ricerca
+su di un intervallo di date, questo si applica a tutte la date nell'intervallo.<p>
+}
+
+_textchangeprefs_ [l=it] {Modifica le impostazioni}
+
+_texthelppreferences_ [l=it] {<h2>_textchangeprefs_</h2>
+
+<p>Premendo il pulsante <i>impostazioni</i> in alto nella pagina puoi modificare
+alcune caratteristiche dell'interfaccia per adattarla alle tue esigenze.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Impostazioni relative alle raccolte</h3>
+
+Alcune raccolte comprendono diverse sottoraccolte, su cui Ãš possibile
+effettuare ricerche singolarmente o come un tutt'uno. In questi casi, nella pagina Impostazioni puoi
+scegliere quali sottoraccolte prendere in considerazione nelle ricerche.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Impostazioni della lingua</h3>
+
+Ogni raccolta ha una lingua di presentazione predefinita, ma puoi cambiare lingua se lo desideri.
+Puoi anche cambiare il set di caratteri utilizzato da Greenstone per l'output verso il tuo browser
+-- il software ha delle opportune impostazioni predefinite ma con alcuni browser puoi ottenere una
+visualizzazione migliore cambiando il set di caratteri. Tutte le raccolte permettono di passare dall'interfaccia
+grafica standard ad una testuale. Questa Ãš particolarmente utile per gli ipovedenti che utilizzano
+delle interfacce testuali con tipi di caratteri molto grandi oppure dei sintetizzatori vocali.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Impostazioni relative all'interfaccia</h3>
+
+A seconda della raccolta possono esserci numerose opzioni modificabili riguardanti l'interfaccia.
+
+<p>Le raccolte di pagine web ti permettono di eliminare la barra di navigazione di Greenstone che altrimenti
+appare sulla sommitÃ  di ogni pagina, in questo modo quando effettui una ricerca trovi esattamente la pagina
+cercata senza alcuna intestazione aggiuntiva. In questo caso, per effettuare una nuova ricerca
+dovrai utilizzare il pulsante "indietro" del browser.
+Queste raccolte ti permettono anche di eliminare il messaggio di avvertimento che appare quando fai click su
+di un collegamento che ti porta direttamente sul web, fuori dalla raccolta.
+Inoltre in alcune raccolte di pagine web puoi stabilire se i link presentati nella pagina "Risultati della ricerca"
+ti portano direttamente all'URL in questione piuttosto che alla copia della pagina web presente nella
+biblioteca digitale.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Impostazioni relative alla ricerca</h3>
+<p>Due coppie di pulsanti controlano il tipo di confronto tra parole nelle ricerche che effettui.
+La prima coppia ("sensibilitÃ  alle maiuscole") stabilisce se le maiuscole e le minuscole devono essere
+considerate differenti nel confronto tra le parole.
+La seconda coppia ("finali delle parole") stabilisce se ignorare la declinazione delle parole nelle operazioni
+di confronto.
+E' inoltre possibile ingrandire la casella in cui inserire le parole da cercare, in modo da rendere piÃ¹
+semplice cercare frasi lunghe. La ricerca di grandi porzioni di testo Ãš incredibilmente veloce.
+
+<p>Ad esempio, se i pulsanti <i>ignora maiuscole</i> ed
+<i>ignora la declinazione delle parole</i> sono selezionati, la ricerca<p>
+    <ul><kbd>Edifici africani</kbd></ul>
+      <p>sarÃ  trattata allo stesso modo di<p>
+      <ul><kbd>africa edificio</kbd></ul><p>
+      in quanto la maiuscola in "Edifici" sarÃ  trasformata in minuscola e le desinenze saranno rimosse
+      (NOTA DEL TRADUTTORE: quest'ultima funzionalitÃ  potrebbe non funzionare correttamente quando
+      applicata a parole non in lingua inglese).
+
+<p>Puoi passare ad una modalitÃ  di ricerca "avanzata" che ti permette di unire piÃ¹ condizioni
+usando AND (&), OR (|), e NOT (!).
+Questo permette di creare ricerche piÃ¹ precise.
+Puoi abilitare o disabilitare lo storico delle ricerche, questo ti mostrerÃ  le ultime
+ricerche effettuate rendendo piÃ¹ semplice la ripetizione di ricerche simili tra loro.
+Infine puoi stabilire il numero massimo di documenti da trovare ed il numero massimo di documenti
+da mostrare in una schermata.
+}
+
+_texttanumbrowseoptions_ [l=it] {Ci sono _numbrowseoptions_ modi per cercare le informazioni nell'ambito di questa raccolta:}
+
+_textsimplehelpheading_ [l=it] {Come cercare le informazioni}
+
+_texthelpscope_ [l=it] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Ambito delle ricerche</h3>
+
+<p>In alcune raccolte puoi scegliere tra diversi indici per effettuare le ricerche. Ad esempio, ci possono essere
+indici sugli autori e sui titoli, oppure ci possono essere indici sui nomi dei capitoli e dei paragrafi.
+Generalmente, viene ritornato comunque l'intero documento a prescindere dall'indice su cui si Ãš effettuata
+la ricerca.
+
+<p>Se il documento Ãš un libro, questo verrÃ  aperto in un punto specifico.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/italian2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/italian2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/italian2.dm	(revision 10506)
@@ -0,0 +1,928 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Italian Language text and icon macros 
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=it] {documenti. }
+_lastupdate_ [l=it] {Ultima modifica}
+_ago_ [l=it] {giorni fa.}
+_colnotbuilt_ [l=it] {Raccolta non costruita.}
+
+_textpagetitle_ [l=it] {Greenstone Digital Library}
+_textadmin_ [l=it] {Pagina di amministrazione}
+_textabgs_ [l=it] {Informazioni su Greenstone}
+_textgsdocs_ [l=it] {Documentazione Greenstone}
+
+_textimagegli_ [l=it] {Ti aiuta a creare nuove collezioni, modificarle o aggiungerne alle esistenti, oppure cancellarle.}
+
+_textimagecollector_ [l=it] {Questo precede l'interfaccia bibliotecario, e per la maggior parte degli scopi pratici dovrebbe essere usata preferibilmente}
+
+_textimagetranslator_ [l=it] {Ti aiuta a mantenere aggiornate le versioni multilingua dell'interfaccia Greenstone}
+
+_textimageadmin_ [l=it] {Ti permette di aggiungere nuovi utenti, raggruppare le collezioni nel sistema, dare informazioni tecniche sulla installazione di Greenstone.}
+
+_textimagegogreenstone_ [l=it] {Ti dÃ  informazioni a proposito del software Greenstone e del New Zealand Digital Library Project all'interno del quale Ãš stato creato}
+
+_textimagegodocs_ [l=it] {Manuali di Greenstone}
+
+_textpoem_ [l=it] {<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+
+<p>possano la pace e la calma circondarti,
+<br>possa tu vivere nel calore della foschia estiva,
+<br>possa l'oceano in cui tu viaggi essere levigato come la nefrite.
+}
+
+_textgreenstone_ [l=it] {<p>La nefrite (greenstone) Ãš una pietra semi-preziosa che (come questo software) viene dalla Nuova Zelanda.
+Nella societÃ  tradizionale dei Maori era la piÃ¹ costosa ed ambita di tutte le sostanze. Essa puÃ²
+assorbire e conservare lo <i>wairua</i>, lo spirito della forza vitale, ed Ãš dotata di virtÃ¹ tradizionali
+che la rendono un emblema appropriato per una biblioteca digitale di pubblico dominio.
+Il suo splendore Ãš simbolo di caritÃ ; la sua trasparenza, di onestÃ ; la sua durezza, di coraggio;
+ed i bordi taglienti che puÃ² avere, di giustizia.
+La pietra lavorata utilizzata come logo del software Greenstone Digital Library Ãš un <i>patu</i>
+o mazza da guerra, ed Ãš un cimelio di famiglia di uno dei membri del progetto.
+Nel combattimento corpo a corpo il suo colpo Ãš molto veloce e preciso. A noi piace pensare
+che queste qualitÃ  si applicano anche al nostro software, il bordo del <i>patu</i> tagliente come un rasoio
+simboleggia il vertice della tecnologia.
+}
+
+_textaboutgreenstone_ [l=it] {<p>Greenstone Ãš una suite di software adatti a gestire collezioni di biblioteche digitali ed a creare nuove collezioni. Fornisce un nuovo modo di organizzare informazioni e di pubblicarle su Internet o su CD-ROM.  Greenstone Ãš prodotto dal <b>New Zealand Digital Library Project</b> presso l'<b>UniversitÃ  di Waikato</b>, ed Ãš distribuito in cooperazione con l'<b>UNESCO</b> e lo <b>Human Info NGO</b>. E' un software open-source, disponibile da  <i>http://greenstone.org</i> sotto i termini della GNU General Public
+License.                                                                                                                                                                                                     <p>Lo scopo del sofware Ãš quello di dare la possibilitÃ  agli utenti, particolarmente in universitÃ , biblioteche ed altre istituzioni pubbliche, di creare proprie biblioteche digitali. Le biblioteche digitali stanno modificando radicalmente il modo in cui l'informazione viene disseminata ed acquisita nelle comunitÃ  e nelle istituzioni partner dell'UNESCO nei campi dell'educazione, della scienza e della cultura in tutto il mondo, e particolarmente nei paesi in via di sviluppo. Speriamo che questo software possa incoraggiare la diffusione effettiva delle biblioteche digitali al fine di condividere l'informazione e di porla nel pubblico dominio.  
+
+<p>Questo software Ãš sviluppato e distribuito come un'opera collaborativa internazionale avviata nell'agosto 2000 fra tre istituzioni.
+
+<table border="0">
+<tr valign="top">
+<td>
+<a href="http://nzdl.org"><b>New Zealand Digital Library Project presso l'UniversitÃ  di Waikato</b></a>
+<br>
+Il software Greenstone Ãš scaturito da questo progetto e l'iniziativa Ãš stata appoggiata dalla sub-commissione Comunicazione della Commissione della Nuova Zelanda per l'UNESCO, come parte del contributo della Nuova Zelanda al programma dell'UNESCO.
+</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>
+La disseminazione dell'informazione educativa, scientifica e culturale nel mondo, e particolarmente la sua disponibilitÃ  nei paesi in via di sviluppo,            Ãš centrale negli obiettivi dell'UNESCO, che la persegue all'interno del programma intergovernativo Infomation for All, ed una tecnologia dell'informazione e comunicazione appropriata ed accessibile Ãš vista come un importante strumento in questo contesto. 
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/unesco.gif"
+border="0"></a></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://humaninfo.org"><b>Lo Human Info NGO, fondato ad Anversa, Belgio</b></a>
+<br>
+Questo progetto collabora con agenzie ONU ed altre organizzazione non governative, ed ha conquistato una reputazione internazionale per la digitalizzazione di documentazione d'interesse per lo sviluppo umano e per averla resa ampiamente accessibile, gratuitamente per i paesi in via di sviluppo, a copertura dei costi per gli altri.
+</td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "scegli una collezione" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ [l=it] {_httpimg_/it/selcolgr.gif}
+_widthselcolgr_ [l=it] {537}
+_heightselcolgr_ [l=it] {17}
+_altselcolgr_ [l=it] {"Select a collection"}
+
+
+## "Interfaccia\nbibliotecario" ## home_page_button ## cgli ##
+_httpiconcgliof_ [l=it] {_httpimg_/it/cgliof.gif}
+_httpiconcglion_ [l=it] {_httpimg_/it/cglion.gif}
+_widthcgli_ [l=it] {100}
+
+# -- Missing translation: ccol
+# -- Missing translation: _httpiconccolof_
+# -- Missing translation: _httpiconccolon_
+# -- Missing translation: _widthccol_
+
+## "Il traduttore" ## home_page_button ## ctrans ##
+_httpiconctransof_ [l=it] {_httpimg_/it/ctransof.gif}
+_httpiconctranson_ [l=it] {_httpimg_/it/ctranson.gif}
+_widthctrans_ [l=it] {100}
+
+# -- Missing translation: cadmin
+# -- Missing translation: _httpiconcadminof_
+# -- Missing translation: _httpiconcadminon_
+# -- Missing translation: _widthcadmin_
+
+# -- Missing translation: cabgs
+# -- Missing translation: _httpiconcabgsof_
+# -- Missing translation: _httpiconcabgson_
+# -- Missing translation: _widthcabgs_
+
+# -- Missing translation: cgsdoc
+# -- Missing translation: _httpiconcgsdocof_
+# -- Missing translation: _httpiconcgsdocon_
+# -- Missing translation: _widthcgsdoc_
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=it] {Ci sono quattro pulsanti ulteriori sulla home page}
+
+_textnocollections_ [l=it] {<p>Non vi sono attualmente collezioni disponibili in questa installazione Greenstone. 
+Per aggiungerne alcune puoi 
+<ul><li>usare <a href="_httppagecollector_">Il Collector</a> per costruire nuove collezioni
+    <li>Se hai un cd-rom Greenstone cd-rom puoi installare collezioni dal cd-rom
+</ul>
+}
+
+_text1coll_ [l=it] {Questa installazione di Greenstone contiene 1 collezione}
+
+_textmorecolls_ [l=it] {Questa installazione Greenstone contiene _1_ collezioni}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=it] {Collegamento esterno}
+_textlinknotfound_ [l=it] {Collegamento interno non trovato}
+
+_textextlinkcontent_ [l=it] {Il collegamento che hai selezionato Ãš esterno alle raccolte correntemente selezionate da te.
+Se desideri ugualmente seguire questo collegamento ed il tuo browser ha accesso al web, puoi
+<a href="_nexturl_">proseguire</a> altrimenti usa il pulsante "indietro" del browser per tornare al documento
+precedente.}
+
+_textlinknotfoundcontent_ [l=it] {Per ragioni aldilÃ  del nostro controllo, il link interno che hai selezionato
+non esiste. Questo probabilmente Ãš dovuto ad un errore nel documento originale. Usa il pulsante "indietro" del
+browser per tornare al documento preccedente.}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=it] {<h3>Collegamento alla raccolta "_2_"</h3>
+
+<p> Il collegamento che hai selezionato Ãš esterno alla raccolta "_collectionname_" (esso porta alla raccolta
+"_2_"). Se desideri seguire questo collegamento verso la raccolta "_2_" puoi
+<a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">proseguire</a> verso questa pagina; altrimenti usa il pulsante "indietro"
+del browser per tornare al documento precedente.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=it] {Greenstone Digital Library}
+
+_textusername_ [l=it] {nome utente}
+_textpassword_ [l=it] {password}
+
+_textmustbelongtogroup_ [l=it] {Nota che devi appartenere al gruppo "_cgiargug_" per accedere a questa pagina}
+
+_textmessageinvalid_ [l=it] {La pagina che hai richiesto necessita di autenticazione.<br>
+_If_(_cgiargug_,[_textmustbelongtogroup_]<br>)
+Inserisci nome e password.}
+
+_textmessagefailed_ [l=it] {Il tuo nome o la tua password sono errati.}
+
+_textmessagedisabled_ [l=it] {Spiacente, il tuo account Ãš stato disabilitato. Contatta il webmaster di questo sito.}
+
+_textmessagepermissiondenied_ [l=it] {Spiacente, non hai il permesso di accedere a questa pagina.}
+
+_textmessagestalekey_ [l=it] {La pagina Ãš scaduta. Inserisci la password per accedere a questa pagina.}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=it] {<p>Questa installazione di Greenstone non include alcuna documentazione. CiÃ² puÃ² 
+essere perchÃ©:
+<ol>
+ <li>Greenstone Ãš stato installato da CD-ROM usando una installazione compatta.
+ <li>Greenstone Ãš stato installato da una distribuzione scaricata da internet.
+</ol>
+In entrambi i casi puoi ottenere la documentazione dalla directory <i>docs</i>
+di un CD-ROM Greenstone oppure visitando <a
+href="http://www.greenstone.org">http://www.greenstone.org</a>.
+}
+
+_textuserguide_ [l=it] {Guida utente}
+_textinstallerguide_ [l=it] {Guida dell'installatore}
+_textdeveloperguide_ [l=it] {Guida dello sviluppatore}
+_textpaperguide_ [l=it] {Guida dalla carta alla collezione}
+_textorganizerguide_ [l=it] {Usare l'Organizer}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "documentazione Greenstone" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=it] {_httpimg_/it/gsdocsgr.gif}
+_widthgsdocsgr_ [l=it] {_pagewidth_}
+_heightgsdocsgr_ [l=it] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ [l=it] {struttura di default}
+_textmore_ [l=it] {altro}
+_textcollector_ [l=it] {Il Collector}
+_textinfo_ [l=it] {Informazioni sulla collezione}
+_textsrce_ [l=it] {Origine dati}
+_textconf_ [l=it] {Configura la collezione}
+_textbild_ [l=it] {Crea}
+_textview_ [l=it] {vedi}
+_textdel_ [l=it] {cancella la collezione}
+_textexpt_ [l=it] {esporta la collezione}
+
+_textdownloadingfiles_ [l=it] {Scaricamento file in corsoâŠ}
+_textimportingcollection_ [l=it] {Importazione della collezione in corsoâŠ}
+_textbuildingcollection_ [l=it] {Creazione della collezione in corsoâŠ}
+_textcreatingcollection_ [l=it] {creazione della collezioneâŠ}
+
+_textcollectorblurb_ [l=it] {<i>La penna Ãš piÃ¹ potente della spada! <br>Creare e distribuire collezioni di informazioni comporta delle responsabilitÃ  sulle quali Ãš bene riflettere prima di iniziare. Esistono questioni legali connesse al copyright: la possibilitÃ  di accedere ai documenti non significa necessariamente che li puoi scambiare con altre persone. Vi sono questioni di natura sociale: le collezioni dovrebbero rispettare i costumi della comunitÃ  al di fuori della quale i documenti sono nati. E vi sono motivi etici: alcune cose semplicemente non dovrebbero essere rese disponibili ad altri. <br>Sii sensibile al potere dell'informazione ed usalo con saggezza. </i>}
+
+_textcb1_ [l=it] {Il Collector consente di creare nuove collezioni, di modificarle, aggiungerle o cancellarle. Per fare questo, sarai guidato attraverso una serie di pagine web che raccolgono le informazioni necessarie.}
+
+_textcb2_ [l=it] {Innanzitutto, devi decidere se}
+_textcnc_ [l=it] {crea una nuova collezione}
+_textwec_ [l=it] {lavorare con una esistente, aggiungervi dati o cancellarla.}
+
+_textcb3_ [l=it] {Per poter costruire o modificare le collezioni della biblioteca digitale devi identificarti. Questo al fine di proteggere da accessi non autorizzati al tuo computer e da alterazioni dei dati contenuti. }
+
+_textcb4_ [l=it] {Inserisci, per favore, il tuo nome utente Greenstone e la password, poi clicca sul pulsante per entrare.}
+
+_textfsc_ [l=it] {Per prima cosa seleziona la collezione su cui vuoi lavorare (le collezioni protette in scrittura non appariranno in questo elenco).}
+
+_textwtc_ [l=it] {Con la collezione che hai selezionato, puoi}
+_textamd_ [l=it] {Aggiungi altri dati e ricostruisci la collezione}
+_textetc_ [l=it] {Modifica il file di configurazione della collezione e ricostruisci la collezione}
+_textdtc_ [l=it] {Cancella la collezione interamente}
+_textetcfcd_ [l=it] {Esporta la collezione per la copia su un CD-ROM Windows autoinstallante.}
+_textcaec_ [l=it] {Modifica una collezione esistente}
+_textnwec_ [l=it] {Non Ãš disponibile nessuna collezione abilitata in scrittura per modifiche}
+_textcianc_ [l=it] {Crea una nuova collezione}
+_texttsosn_ [l=it] {La sequenza di passi necessari a creare una nuova collezione digitale Ãš:}
+_textsin_ [l=it] {Specifica il suo nome (e le informazioni connesse)}
+_textswts_ [l=it] {Specifica da dove provengono i dati di origine}
+_textatco_ [l=it] {Modifica le opzioni di configurazione (solo utenti avanzati)}
+_textbtc_ [l=it] {"Crea" la collezione (vedi sotto)}
+_textpvyh_ [l=it] {Vedi il lavoro fatto}
+
+_texttfsiw_ [l=it] {Il quarto passo Ãš la fase in cui il computer esegue tutto il lavoro. Nel processo di costruzione il computer crea tutti gli indici e combina ogni altra informazione necessaria al funzionamento. Ma prima di tutto devi specificare le informazioni.}
+
+_textadab_ [l=it] {Sotto appare un diagramma che consentirÃ  di mantenere la traccia del punto in cui ci si trova. Il pulsante verde Ãš quello che puoi cliccare per proseguire lungo la sequenza. I pulsanti cambieranno in giallo man mano che ci si sposta nella sequenza. E' possibile ritornare ad una pagina precedente cliccando sul pulsante giallo corrispondente nel diagramma.}
+
+_textwyar_ [l=it] {Quando sei pronto, clicca il bottone verde "informazioni sulla collezione" per avviare la creazione della nuova collezione digitale!}
+
+_textcnmbs_ [l=it] {Il nome della collezione deve essere specificato}
+_texteambs_ [l=it] {L'indirizzo email deve essere specificato}
+_textpsea_ [l=it] {Specifica l'indirizzo email nel campo: username@domain}
+_textdocmbs_ [l=it] {La descrizione della collezione deve essere specificata}
+
+_textwcanc_ [l=it] {Durante la creazione di una nuova collezione devi inserire alcune informazioni preliminari relative alla fonte dei dati. Questo processo Ãš strutturato come una serie di pagine web controllate dal Collector. La barra a piÃš di pagina mostra la sequenza di pagine che deve essere completata.}
+
+_texttfc_ [l=it] {Titolo della collezione:}
+
+_texttctiasp_ [l=it] {Il titolo della collezione Ãš una breve frase usata all'interno della biblioteca digitale per 
+identificare il contenuto della collezione. Titoli di esempio possono essere
+"Rapporti tecnici ed informatici" e "Biblioteca dello sviluppo dell'umanitÃ "
+}
+
+_textcea_ [l=it] {Contatta l'indirizzo mail.}
+
+_textteas_ [l=it] {Questo indirizzo email specifica il principale punto di contatto per la collezione.
+Se il software Greenstone individua un problema, invierÃ  un rapporto diagnostico a questo indirizzo.
+Inserisci un indirizzo email nella sua forma completa: <tt>name@domain</tt>.
+}
+
+_textatc_ [l=it] {Informazioni su questa collezione:}
+
+_texttiasd_ [l=it] {Questa Ãš una dichiarazione che illustra i principi che regolano ciÃ² che viene inserito nella collezione. Appare sulla prima pagina quando la collezione viene presentata.}
+
+_textypits_ [l=it] {La tua posizione nella sequenza Ãš indicata sotto da una freccia - in questo caso, la fase "informazioni sulla collezione". Per proseguire, clicca il bottone verde "origine dati".}
+
+_srcebadsources_ [l=it] {<p>Una o piÃ¹ delle fonti che hai specificato non Ãš disponibile (contrassegnata
+_iconcross_ sotto).
+
+<p>Questo puÃ² essere perchÃš
+<ul>
+<li>Il file, il sito FTP o l'URL non esiste.
+<li>Devi connetterti prima al tuo ISP.
+<li>Stai cercando di accedere ad un URL protetto da firewall (Ãš questo il caso se normalmente devi fornire username e password per accedere a Internet).
+</ul>
+
+<p>Se questo Ãš un URL che puoi visualizzare sul tuo browser, potrebbe provenire da una copia nella cache locale. Purtroppo le copie memorizzate nella cahe locale non sono visibili al nostro processo di mirroring. In questo caso, ti raccomandiamo di scaricare le pagine utilizzando direttamente il tuo browser.
+}
+
+_textymbyco_ [l=it] {<p>Puoi basare la tua collezione sia su
+<ul>
+<li>La struttura di default
+<dl><dd>La nuova collezione puÃ² contenere documenti html (.htm, .html), documenti solo testo
+(.txt, .text), documenti MS Word (.doc), documenti PDF (.pdf) oppure
+documenti email formato "m-box" (.mbx).</dd></dl>
+<li>Una collezione esistente
+<dl><dd>I file nella tua nuova collezione devono essere esattamente dello stesso tipo di quelli usati per creare quella esistente.</dd></dl>
+</ul>
+}
+
+_textbtco_ [l=it] {Basa la collezione su}
+_textand_ [l=it] {Aggiungi nuovi dati}
+_textad_ [l=it] {Aggiungere dati:}
+
+_texttftysb_ [l=it] {I file che hai indicato sotto saranno aggiunti alla collezione. Assicurati di non aver indicato file giÃ  presenti nella collezione, altrimenti verranno inserite due copie. I file sono identificati col loro percorso completo, le pagine web dal loro indirizzo web assoluto.}
+
+_textis_ [l=it] {Origine dati:}
+
+_textddd1_ [l=it] {<p>Se usi file:// o ftp:// per specificare un file, quel file verrÃ  scaricato. <p>Se usi http://, varia a seconda che l'URL indichi una normale pagina web nel tuo browser, oppure una lista di file. Se si tratta di una pagina, questa pagina verrÃ  scaricata - e cosÃ¬ avverrÃ  per tutte le pagine alle quali fa un link e dalle quali Ãš collegata etc. - ammesso che risiedano sullo stesso sito, secondo l'URL. <p>Se usi file:// o ftp:// per specificare una cartella o directory, oppure se fornisci un URL http:// che conduce ad una lista di file, ogni cosa contenuta nella cartella ed in tutte le sottocartelle verrÃ  inclusa nella collezione. <p>Clicca il pulsante "altri dettagli" per avere altre caselle di input.}
+
+_textddd2_ [l=it] {<p>Clicca uno dei pulsanti verdi. Se sei un utente avanzato, potresti avere la necessitÃ  di modificare la configurazione della collezione. Diversamente, vai direttamente alla fase di creazione. Ricorda che puoi sempre rivedere una fase precedente cliccando sul pulsante giallo.}
+
+_textconf1_ [l=it] {<p>La creazione e la presentazione della tua collezione sono controllate attraverso delle specifiche contenute in uno speciale "file di configurazione". Gli utenti avanzati potrebbero aver bisogno di modificare le impostazioni di configurazione. <center><p><b>Se non sei un utente avanzato, vai alla fine della pagina.</b></center> <p>Per cambiare le impostazione di configurazione, modifica i dati che appaiono sotto. Se fai un errore, clicca su "Reset" per ripristinare le impostazioni di configurazione originali.}
+
+_textreset_ [l=it] {Reset}
+
+_textbild1_ [l=it] {La collezione Ãš ora in fase di creazione: questa operazione potrebbe richiedere tempo. La linea di stato di avanzamento che appare sotto dÃ  informazioni su come sta procedendo l'operazione.}
+
+_textbild2_ [l=it] {Per bloccare il processo di costruzione in ogni momento, clicca qui. <br>La collezione sulla quale stai lavorando rimarrÃ  intatta.}
+
+_textstopbuild_ [l=it] {Arresta la creazione}
+
+_textbild3_ [l=it] {Se abbandoni questa pagina (senza aver annullato il processo di costruzione col pulsante "arresta costruzione") la collezione continuerÃ  ad essere costruita e verrÃ  installata dopo il completamento positivo dell'operazione.}
+
+_textbuildcancelled_ [l=it] {Costruzione annullata}
+
+_textbildcancel1_ [l=it] {Il processo di cotruzione della collezione Ãš stato annullato. Usa i pulsanti gialli sottostanti per fare delle modifiche alla collezione oppure riattiva il processo di costruzone.}
+
+_textbsupdate1_ [l=it] {Lo stato di costruzione viene aggiornato in 1 secondo}
+_textbsupdate2_ [l=it] {Lo stato di costruzione viene aggiornato in}
+_textseconds_ [l=it] {secondi}
+_textbildsuc_ [l=it] {La collezzione Ãš stata creata con successo.}
+
+_textviewbildsummary_ [l=it] {Puoi <a href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>vedere il sommario creato
+</a> per questa collezione per ulteriori dettagli.
+}
+
+_textfailmsg11_ [l=it] {La collezione non puÃ² essere creata perchÃš non contiene dati. Assicurati che almeno una delle directory o dei file 
+che hai specificato nella pagina <i>origine dati</i> esista e che sia del tipo (nel caso di una directory) o che contenga il tipo di file che 
+Greenstone puÃ² processare.
+}
+
+_textfailmsg21_ [l=it] {La collezione non puÃ² essere creata (import.pl fallito).}
+_textblcont_ [l=it] {Il log di costruzione contiene le seguenti informazioni:}
+
+_texttryagain_ [l=it] {Per favore<a href="_httppagecollector_" target=_top>riavvia il collector</a>
+e prova di nuovo.
+}
+
+_textfailmsg31_ [l=it] {La collezione non puÃ² essere creata (buildcol.pl fallito).}
+_textfailmsg41_ [l=it] {La collezione Ãš stata creata con successo ma non puÃ² essere installata.}
+_textfailmsg71_ [l=it] {Si Ãš verificato un errore imprevisto durante la creazione della collezione}
+_textretcoll_ [l=it] {Ritorna al Collector}
+
+_textdelperm_ [l=it] {Alcune o tutte le collezioni _cgiargbc1dirname_non possono essere cancellate. La cause possibili sono: <ul> <li> Greenstone non ha il permesso di cancellare la directory _gsdlhome_/collect/_cgiargbc1dirname_
+<br> Potrebbe essere necessario rimuovere manualmente questa directory per completare la cancellazione della collezione _gsdlhome_/collect/_cgiargbc1dirname_ da questo computer.</li> <li>Greenstone non puÃ² eseguire il programma _gsdlhome_/bin/script/delcol.pl. Assicurati che questo file sia leggibile ed eseguibile.</li></ul>}
+
+_textdelinv_ [l=it] {La collezione _cgiargbc1dirname_ Ãš protetta o invalida. La cancellazione Ãš stata annullata.}
+
+_textdelsuc_ [l=it] {La collezione _cgiargbc1dirname_ Ãš stata cancellata con successo.}
+
+_textclonefail_ [l=it] {La collezione _cgiargclonecol_ non puÃ² essere clonata.}
+
+_textcolerr_ [l=it] {Errore del Collector.}
+
+_texttmpfail_ [l=it] {Il collector non Ãš riuscito a leggere o scrivere su un file o directory temporanea.
+Cause possibili sono:
+<ul>
+<li> Greenstone non ha accesso in lettura/scrittura alla directory _gsdlhome_/tmp
+</ul>
+}
+
+_textmkcolfail_ [l=it] {Il collector ha fallito nel tentativo di creare la struttura della directory richiesta dalla nuova 
+collezione (mkcol.pl fallito). Possibili cause sono:
+<ul>
+<li> Greenstone non ha il permesso di scrittura nella directory _gsdlhome_/tmp
+     
+<li> errori nello script perl mkcol.pl 
+</ul>
+}
+
+_textnocontent_ [l=it] {Errore nel collector: non Ãš stato fornito alcun nome per la nuova collezione. Prova a riavviare il Collector dall'inizio.}
+
+_textrestart_ [l=it] {Riavvia il Collector}
+
+_textreloaderror_ [l=it] {Si Ãš verificato un errore durante la creazione della nuova collezione. CiÃ² puÃ² essere dovuto al fatto
+che Greenstone Ãš stato confuso dall'uso dei pulsanti "ricarica" e "indietro" del tuo browser  
+(cerca di evitare l'utilizzo di questi pulsanti mentre crei una collezione con il Collector). 
+Si consiglia di riavviare il Collector dall'inizio.
+}
+
+_textexptsuc_ [l=it] {La collezione _cgiargbc1dirname_ Ãš stata esportata con successo 
+nella direcoty _gsdlhome_/tmp/exported\__cgiargbc1dirname_ 
+}
+
+_textexptfail_ [l=it] {<p>L'esportazione della collezione _cgiargbc1dirname_ Ãš fallita.
+
+<p>Probabilmente questo dipende dal fatto che Greenstone Ãš stato installato senza le componenti
+necessarie a supportare la funzione "Esporta collezione".
+<ul>
+
+ <li>Se hai installato Greenstone da un CD-ROM, queste componenti non sono state installate a meno che 
+ non le abbia selezionate durante l'installazione "Personalizzata".
+ Puoi aggiungerle alla tua installazione ripetendo la procedura di installazione.
+
+ <li>Se hai installato Greenstone da una distribuzion web, devi scaricare ed installare i pacchetti addizionali 
+ necessari ad abilitare questa funzione. Consulta <a href="http://www.greenstone.org">http://www.greenstone.org</a> 
+ oppure spedisci un'e-mail a <a
+ href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+ per ulteriori informazioni.
+
+</ul>
+
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Il collector" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=it] {_httpimg_/it/h\_colect.gif}
+
+## "informazioni\nsulla collezione" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=it] {_httpimg_/it/gcinfoof.gif}
+_httpicongcinfoon_ [l=it] {_httpimg_/it/gcinfoon.gif}
+_httpiconycinfoof_ [l=it] {_httpimg_/it/ycinfoof.gif}
+_httpiconycinfoon_ [l=it] {_httpimg_/it/ycinfoon.gif}
+_httpiconncinfoof_ [l=it] {_httpimg_/it/ncinfoof.gif}
+
+## "origine\ndei dati" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=it] {_httpimg_/it/gcsrceof.gif}
+_httpicongcsrceon_ [l=it] {_httpimg_/it/gcsrceon.gif}
+_httpiconycsrceof_ [l=it] {_httpimg_/it/ycsrceof.gif}
+_httpiconycsrceon_ [l=it] {_httpimg_/it/ycsrceon.gif}
+_httpiconncsrceof_ [l=it] {_httpimg_/it/ncsrceof.gif}
+
+## "configura\nla collezione" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=it] {_httpimg_/it/gcconfof.gif}
+_httpicongcconfon_ [l=it] {_httpimg_/it/gcconfon.gif}
+_httpiconycconfof_ [l=it] {_httpimg_/it/ycconfof.gif}
+_httpiconycconfon_ [l=it] {_httpimg_/it/ycconfon.gif}
+_httpiconncconfof_ [l=it] {_httpimg_/it/ncconfof.gif}
+
+## "crea\nla collezione" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=it] {_httpimg_/it/gcbildof.gif}
+_httpicongcbildon_ [l=it] {_httpimg_/it/gcbildon.gif}
+_httpiconycbildof_ [l=it] {_httpimg_/it/ycbildof.gif}
+_httpiconycbildon_ [l=it] {_httpimg_/it/ycbildon.gif}
+_httpiconncbildof_ [l=it] {_httpimg_/it/ncbildof.gif}
+
+## "vedi\nla collezione" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=it] {_httpimg_/it/gcviewof.gif}
+_httpicongcviewon_ [l=it] {_httpimg_/it/gcviewon.gif}
+_httpiconycviewof_ [l=it] {_httpimg_/it/ycviewof.gif}
+_httpiconycviewon_ [l=it] {_httpimg_/it/ycviewon.gif}
+_httpiconncviewof_ [l=it] {_httpimg_/it/ncviewof.gif}
+
+## "cancella\nla collezione" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=it] {_httpimg_/it/gcdelof.gif}
+_httpicongcdelon_ [l=it] {_httpimg_/it/gcdelon.gif}
+
+## "esporta\nla collezione" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=it] {_httpimg_/it/gcexptof.gif}
+_httpicongcexpton_ [l=it] {_httpimg_/it/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=it] {Greenstone Ãš una suite di software adatti a gestire collezioni di biblioteche digitali ed a creare nuove collezioni. Fornisce un nuovo modo di organizzare informazioni e di pubblicarle su Internet o su CD-ROM.  Greenstone Ãš prodotto dal New Zealand Digital Library Project presso l'UniversitÃ  di Waikato, ed Ãš distribuito in cooperazione con l'UNESCO e lo Human Info NGO. E' un software open-source, disponibile da  <i>http://greenstone.org</i> sotto i termini della GNU General Public
+License.
+}
+
+_textgreenstone2_ [l=it] {Il sito della New Zealand Digital Library (<a
+href="http://nzdl.org">http://nzdl.org</a>) contiene numerose collezioni esempio, tutte create col software Greenstone, che sono disponibili pubblicamente per essere esaminate. Esemplificano diverse opzioni di ricerca e di consultazione ed includono collezioni in arabo, cinese, francese, maori e spagnolo, cosÃ¬ come in inglese. Vi sono anche alcune collezioni musicali. }
+
+_textplatformtitle_ [l=it] {piattaforma}
+_textgreenstone3_ [l=it] {Greenstone funziona sotto Windows, Unix e Mac OS X. La distribuzione include file binari pronti all'uso per ogni versione di Windows, per Linux e per Mac OSX. Contiene anche il codice sorgente completo del sistema che puÃ² essere compilato usando Microsoft C++ o gcc. Greenstone lavora con software associato che Ãš pure disponibile liberamente: il webserver Apache e PERL. L'interfaccia utente utilizza un browser web, tipicamente Netscape Navigator o Internet Explorer.}
+
+_textgreenstone4_ [l=it] {Molte collezioni di documenti sono distribuite su CD-ROM usando il software Greenstone. Ad esempio, la <i>Humanity Development Library</i>contiene 1.230 pubblicazioni che spaziano dalla contabilitÃ  alla bonifica delle acque. Funziona con minime configurazioni di computer, come quelli che di solito sono presenti nei paesi in via di sviluppo. Le informazioni possono essere consultate attraverso la ricerca, l'elenco per soggetti, per titolo, per organizzazione, con un elenco di guide e visualizzando casualmente le copertine del libro.}
+
+_textcustomisationtitle_ [l=it] {personalizzazione}
+_textgreenstone5_ [l=it] {Greenstone Ãš progettato in modo particolare per essere altamente estensibile e personalizzabile. Nuovi formati di documenti e di metadati vengono adottati scrivendo "plugins" (in Perl). Analogamente, nuove strutture di presentazione di metadati possono essere implementate scrivendo "classificatori". L'interfaccia utente puÃ² essere modifcata utilizzando "macro" scritte con un semplice linguaggio macro. Un protocollo Corba consente ad agenti (ad es. Java) di usare tutti i servizi associati alle collezioni di documenti. Infine, il codice sorgente, in C++ e Perl, Ãš disponibile ed accessibile per modifiche.}
+
+_textdocumentationtitle_ [l=it] {documentazione}
+_textdocuments_ [l=it] {E' disponibile una documentazione estesa per il software Greenstone.}
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+_textmailinglisttitle_ [l=it] {mailing list }
+_textmailinglist_ [l=it] {Vi Ãš una mailing list orientata primariamente alle discussioni sul software Greenstone digital library. Gli utenti attivi di Greenstone dovrebbero valutare di aggregarsi alla lista e di contribuire alle discussioni. Per iscriversi, vai a <a href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.
+
+Per spedire un messaggio alla lista, indirizzalo a  <a
+href="mailto:greenstone-users@list.scms.waikato.ac.nz"
+>greenstone-users@list.scms.waikato.ac.nz</a>.}
+
+_textbugstitle_ [l=it] {errori di programma}
+_textreport_ [l=it] {Vogliamo garantire che questo software funziona bene per te. Invia ogni errore di programma a <a href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>}
+
+_textgs3title_ [l=it] {nelle opere}
+_textgs3_ [l=it] {Greenstone 3 Ãš un progetto completamente riformulato ed implementato che mantiene tutti i vantaggi di Greenstone 2 (la versione corrente) - ad esempio, Ãš multilingua, multipiattaforma ed ampiamente configurabile. Incorpora tutte le caratteristiche del sistema esistente ed Ãš retrocompatibile, ossia puÃ² costruire e gestire collezioni esistente senza modifiche. Scritto in Java, Ãš strutturato come una rete di moduli indipendenti che comunicano usando XML: cosÃ¬ esso funziona in modo distribuito e puÃ² essere dislocato su diversi server se necessario. Questa struttura modulare aumenta la flessibilitÃ  e l'estensibilitÃ  di Greenstone. La nuova versione dovrebbe essere disponibile per uso sperimentale entro il 23 dicembre 2003. Una descrizione di base del sistema Ãš contenuta in "The design of Greenstone 3: An agent based 
+dynamic digital library" (scarica il PDF 
+<a href="http://www.greenstone.org/manuals/gs3design.pdf"> </a>).}
+
+_textcreditstitle_ [l=it] {credits}
+
+_textwhoswho_ [l=it] {Il software Greenstone Ãš un'opera collaborativa tra numerose persone. Rodger McNab e Stefan Boddie sono i principali architetti ed implementatori. Contributi sono stati dati da David Bainbridge, George
+Buchanan, Hong Chen, Michael Dewsnip, Katherine Don, Elke Duncker, Carl Gutwin, Geoff Holmes, Dana McKay, John
+McPherson, Craig Nevill-Manning, Dynal Patel, Gordon Paynter, Bernhard Pfahringer, Todd
+Reed, Bill Rogers, John Thompson e Stuart Yeates. Altri membri del New Zealand
+Digital Library project hanno fornito consigli ed ispirazione per il progetto del sistema: Mark Apperley, Sally Jo Cunningham, Matt Jones, Steve Jones, Te Taka
+Keegan, Michel Loots, Malika Mahoui, Gary Marsden, Dave Nichols e Lloyd Smith. Desideriamo anche manifestare la nostra riconoscenza a tutti coloro i quali hanno contribuito ai pacchetti sotto licenza GNU inclusi in questa distribuzione: MG, GDBM, PDFTOHTML, PERL, WGET, WVWARE e XLHTML.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "informazioni sul software greenstone" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=it] {_httpimg_/it/abgsgr.gif}
+_widthabgsgr_ [l=it] {_pagewidth_}
+_heightabgsgr_ [l=it] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=it] {Lista degli utenti correnti}
+_textuser_ [l=it] {utente
+}
+_textas_ [l=it] {stato dell'account}
+_textgroups_ [l=it] {gruppi}
+_textcomment_ [l=it] {commento}
+_textadduser_ [l=it] {aggiungi un nuovo utente}
+_textedituser_ [l=it] {modifica}
+_textdeleteuser_ [l=it] {cancella}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=it] {Modifica le informazioni utente}
+_textadduser_ [l=it] {Aggiungi un nuovo utente}
+
+_textaboutusername_ [l=it] {Gli username devono essere lunghi tra 2 e 30 caratteri. Essi possono contenere caratteri alfanumerici,  '.', e '_'.}
+
+_textaboutpassword_ [l=it] {La password deve essere lunga fra 3 e 8 caratteri. Essi possono contenere qualsiasi normale carattere ASCII stampabile.}
+
+_textoldpass_ [l=it] {Se questo campo Ãš vuoto la vecchia password sarÃ  mantenuta.}
+_textenabled_ [l=it] {abilitato}
+_textdisabled_ [l=it] {disabilitato}
+
+_textaboutgroups_ [l=it] {Gruppi Ãš una lista separata da virgola, non mettere spazi dopo la virgola}
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=it] {Cancella un utente}
+_textremwarn_ [l=it] {Vuoi davvero rimuovere definitivamente l'utente <b>_cgiargumun_</b>?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=it] {Cambia la password}
+_textoldpw_ [l=it] {vecchia password}
+_textnewpw_ [l=it] {nuova password}
+_textretype_ [l=it] {riscrivi la nuova password}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=it] {La tua password Ãš stata modificata con successo.}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=it] {Lo username Ãš invalido:}
+_textinvalidpassword_ [l=it] {La password non Ãš valida.}
+_textemptypassword_ [l=it] {Inserisci, per favore, una password per questo utente.}
+_textuserexists_ [l=it] {Questo utente esiste giÃ , inserisci un altro username.}
+
+_textusernameempty_ [l=it] {Inserisci il tuo username.}
+_textpasswordempty_ [l=it] {Devi inserire la tua vecchia password.}
+_textnewpass1empty_ [l=it] {Inserisci la tua nuova password e quindi riscrivila.}
+_textnewpassmismatch_ [l=it] {Le due versioni della tua nuova pasword non coincidono.}
+_textnewinvalidpassword_ [l=it] {Hai inserito una passvord non valida}
+_textfailed_ [l=it] {Il tuo username o password sono errati.}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=it] {Numero di versione Greenstone}
+_textframebrowser_ [l=it] {Devi avere un browser con frame abilitato per vedere questo.}
+_textusermanage_ [l=it] {Gestione utente}
+_textlistusers_ [l=it] {elenco utenti}
+_textaddusers_ [l=it] {aggiungi un nuovo utente}
+_textchangepasswd_ [l=it] {cambia password}
+_textinfo_ [l=it] {Informazioni tecniche}
+_textgeneral_ [l=it] {generale}
+_textarguments_ [l=it] {argomenti}
+_textactions_ [l=it] {azioni}
+_textbrowsers_ [l=it] {browsers}
+_textprotocols_ [l=it] {protocolli}
+_textconfigfiles_ [l=it] {Files di configurazione}
+_textlogs_ [l=it] {Logs}
+_textusagelog_ [l=it] {log di utilizzo}
+_textinitlog_ [l=it] {init log}
+_texterrorlog_ [l=it] {errore di log}
+_textadminhome_ [l=it] {admin home}
+_textreturnhome_ [l=it] {Home di Greenstone}
+_titlewelcome_ [l=it] {Amministrazione}
+_textmaas_ [l=it] {I servizi di manutenzione e amministrazione disponibili includono:}
+_textvol_ [l=it] {vedi logs on-line}
+_textcmuc_ [l=it] {crea, mantieni e aggiorna le collezioni}
+_textati_ [l=it] {accedi a informazioni tecniche come argomenti CGI}
+
+_texttsaa_ [l=it] {Questi servizi sono accessibili usando la barra di navigazione laterale sul margine sinistro della pagina.}
+
+_textcolstat_ [l=it] {Stato della collezione}
+
+_textcwoa_ [l=it] {Le collezioni appariranno come "running" solo se i loro file build.cfg esistono, sono leggibili, contengono un campo builddate valido (ad es. < 0), e sono nella directory dell'indice della collezione (ad es. NON la directory di creazione).}
+
+_textcafi_ [l=it] {clicca <i>abbrev.</i> per informazioni su una collezione}
+_textcctv_ [l=it] {clicca <i>collezione</i> per vedere una collezione}
+_textsubc_ [l=it] {Inserisci modifiche}
+_texteom_ [l=it] {Errore in apertura di main.cfg}
+_textftum_ [l=it] {Aggiornamento di main.cfg fallito}
+_textmus_ [l=it] {main.cfg aggiornato con successo}
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=it] {Visualizza il sommario della collezione _collectionname_ }
+_textflog_ [l=it] {Accesso fallito alla collezione _collectionname_}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=it] {UsabilitÃ  di Greenstone}
+
+_textwhy_ [l=it] {<p>L'invio del rapporto Ãš un modo per segnalare che hai trovato difficile o deludente la pagina web che stavi visualizzando.}
+_textextraforform_ [l=it] {Non devi riempire il modulo -- ogni informazione sarÃ  di aiuto.}
+_textprivacybasic_ [l=it] {<p>Il rapporto conterrÃ  solamente informazioni sulle pagine web di Greenstone che stavi visualizzando, nonchÃ© sulla tecnologia che stavi utilizzando per vederle (oltre ad ogni altra informazione facoltativa che fornisci).}
+_textstillsend_ [l=it] {Vuoi inviare ancora questo rapporto?}
+
+_texterror_ [l=it] {errore}
+_textyes_ [l=it] {SÃ¬}
+_textno_ [l=it] {No}
+_textclosewindow_ [l=it] {Chiudi la finestra}
+_textabout_ [l=it] {Informazioni}
+_textprivacy_ [l=it] {Riservatezza}
+_textsend_ [l=it] {Spedisci}
+_textdontsend_ [l=it] {Non spedire}
+_textoptionally_ [l=it] {Facoltativamente}
+
+_textunderdev_ [l=it] {L'anteprima dei dettagli sarÃ  disponibile nella versione finale.}
+
+_textviewdetails_ [l=it] {Visualizza i dettagli del rapporto}
+_textmoredetails_ [l=it] {Maggiori dettagli}
+_texttrackreport_ [l=it] {Tieniti informato su questo rapporto}
+_textcharacterise_ [l=it] {Di quale tipo di problema si tratta}
+_textseverity_ [l=it] {Quanto Ãš grave il problema}
+ 
+_textbadrender_ [l=it] {La pagina appare strana}
+_textcontenterror_ [l=it] {Errore di contenuto}
+_textstrangebehaviour_ [l=it] {Comportamento strano}
+_textunexpected_ [l=it] {E' accaduto qualcosa di inaspettato}
+_textfunctionality_ [l=it] {Difficile da usare}
+_textother_ [l=it] {Altro}
+
+_textcritical_ [l=it] {Critico}
+_textmajor_ [l=it] {Serio}
+_textmedium_ [l=it] {Medio}
+_textminor_ [l=it] {Minore}
+_texttrivial_ [l=it] {Insignificante}
+
+_textwhatdoing_ [l=it] {Cosa stavi cercando di fare?}
+_textwhatexpected_ [l=it] {Cosa ti aspettavi che accadesse?}
+_textwhathappened_ [l=it] {Cosa Ãš accaduto effettivamente?}
+
+_cannotfindcgierror_ [l=it] {<h2>Spiacente!</h2>Non Ãš possibile localizzare il server dei programmi per il pulsante "Segnalazioni".}
+
+_textusabbanner_ [l=it] {il banner stile koru di Greenstone}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+_textgli_ [l=it] {Interfaccia bibliotecario}
+_textglihelp_ [l=it] {L'interfaccia bibliotecario (GLI) ti dÃ  accesso alle funzionalitÃ  di Greenstone attraverso un'interfaccia facile da usare ed immediata. Ti permette di raccogliere serie di documenti, importare o assegnare metadati e di crearli all'interno di una collezione Greenstone.
+  <p>
+Nota che la GLI funziona congiuntamente a Greenstone, ammeso che sia installata in una sottodirectory della tua installazione Greenstone. Questo avviene se hai scaricato una delle distribuzioni Greenstone, oppure  installato da un CD-ROM Greenstone.
+
+ <h4>Funzionamento della GLI sotto Windows</h4>
+
+Lancia l'interfaccia bibliotecario sotto Windows selezionando <i>Greenstone Digital Library</i> dalla sezione <i>Programmi</i> del menu <i>Start</i> e scegliendo <i>Interfaccia bibliotecario</i>.
+
+ <h4>Funzionamento della GLI sotto Unix</h4>
+
+Per attivare la GLI sotto Unix, vai alla directory <i>gli</i> nella tua installazione Greenstone, quindi esegui lo script <i>gli.sh</i>.
+
+ <h4>Usare GLI sotto Mac OS X</h4>
+
+Nel Finder, visualizza <i>Applicazioni</i> quindi <i>Greenstone</i> (se hai installato Greenstone nella localizzazione di default), poi lancia l'applicazione <i>GLI</i>.}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "Interfaccia bibliotecario Greenstone" ## green_bar_left_aligned ## gligr ##
+_httpicongligr_ [l=it] {_httpimg_/it/gligr.gif}
+_widthgligr_ [l=it] {_pagewidth_}
+_heightgligr_ [l=it] {17}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/japanese.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/japanese.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/japanese.dm	(revision 10506)
@@ -0,0 +1,1296 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Japanese Language text and icon macros 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=ja] {å®æåè¡}
+_textsource_ [l=ja] {åæåç
+§}
+_textdate_ [l=ja] {çºè¡æ¥}
+_textnumpages_ [l=ja] {ææ°}
+
+_textsignin_ [l=ja] {ãµã€ã³ã€ã³}
+
+_textdefaultcontent_ [l=ja] {èŠæ±ãããããŒãžãèŠã€ããããªãã£ããã°ãªãŒã³ã¹ããŒã³é»å­å³æžé€šãžæ»ãæã¯ãã©ãŠã¶ã®âBackâãã¿ã³ããŸãã¯äžã®âããŒã âãã¿ã³ãã¯ãªãã¯ããŠäžããã}
+
+_textdefaulttitle_ [l=ja] {GSDL ãšã©ãŒ}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=ja] {ãã®ã³ã¬ã¯ã·ã§ã³ã«ã¯ã_about:numdocs_ããã­ã¥ã¡ã³ããããŸãã
+ããã¯ã_about:builddate_ãæ¥éåã«äœããã}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=ja] {<p>ãã®åéã«ã¯ _numdocs_ _If_("_numdocs_" eq "1",ãã­ã¥ã¡ã³ã,ãã­ã¥ã¡ã³ã),  _numbytes_ããã€ãã®åèšããããŸãã
+<p><a href="_httppagex_(bsummary)">ãããž</a>ã¯ãªãã¯ãããšããã®åéã®æŠèŠãè¡šç€ºããããšãã§ããŸãã
+}
+
+_textimagecollection_ [l=ja] {}
+_textimageabout_ [l=ja] {ããŒãžã«é¢ããŠ}
+_textimagehome_ [l=ja] {ããŒã ããŒãž}
+_textimagehelp_ [l=ja] {ãã«ãããŒãž}
+_textimagepref_ [l=ja] {ããªãã¡ã¬ã³ã¹ããŒãž}
+_textimagegreenstone_ [l=ja] {ã°ãªãŒã³ã¹ããŒã³é»å­å³æžé€šãœãããŠãšã¢}
+_textimageusab_ [l=ja] {äœãäœ¿ãé£ãã§ããïŒ}
+
+_textimagesearch_ [l=ja] {ç¹å®ã®ã­ãŒã¯ãŒãã®æ€çŽ¢}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=ja] {ã¿ã€ãã«ã®æå­é ãªã¹ãããã©ãŠãºãã}
+_textimageCreator_ [l=ja] {äœå®¶ã®æå­é ãªã¹ãããã©ãŠãºãã}
+_textimageSubject_ [l=ja] {Subject ã«ããŽãªãŒããã©ãŠãºãã}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=ja] {æ¥ä»ã«ãŠãã£ãšãã©ãŠãºãã}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=ja] {å
+ã®ãã¡ã€ã«åã«ãŠãã©ãŠãºãã}
+_textimageLanguage_ [l=ja] {èšèªã«ãŠãã£ãšãã©ãŠãºãã}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=ja] {ãªãŒã¬ãã€ãŒã·ã§ã³ããã©ãŠãºãã}
+_textimageKeyword_ [l=ja] {ã­ãŒã¯ãŒãã«ãŠãã£ãšãã©ãŠãºãã}
+_textimageHowto_ [l=ja] {HowãToãã«ããŽãªãŒã«ãŠãã£ãšãã©ãŠãºãã}
+_textimageList_ [l=ja] {ãã­ã¥ã¡ã³ãªã¹ãã€ã³ã°ããã©ãŠãºãã}
+_textimageSeries_ [l=ja] {çºè¡ïŒã€ã·ã¥ãŒïŒããã©ãŠãºãã}
+_textimageTo_ [l=ja] {Toããã£ãŒã«ãã«ãŠãã©ãŠãºãã}
+_textimageFrom_ [l=ja] {Fromããã£ãŒã«ãã«ãŠãã£ãšãã©ãŠãºãã}
+_textimageTopic_ [l=ja] {ç¹å¥ãããã¯ã€ã·ã¥ãŒããã©ãŠãºãã}
+_textimageBrowse_ [l=ja] {ãã©ãŠãº}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=ja] {æ°åã®ãªã¹ãããã©ãŠãºãã}
+_textimageAcronym_ [l=ja] {é ­å­èªããã©ãŠãºãã}
+_textimagePhrase_ [l=ja] {ãã¬ãŒãºããã©ãŠãºãã}
+_textimageArtist_ [l=ja] {ã¢ãŒãã¹ãããã©ãŠãºãã}
+_textimageVolume_ [l=ja] {volumeã§ãã©ãŠãºãã}
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=ja] {æ€çŽ¢}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=ja] {ã¿ã€ãã«ïŒèŸæžé ïŒ}
+_texticontabCreatorgreen_ [l=ja] {äœå®¶ïŒèŸæžé ïŒ}
+# -- Missing translation: _texticontabSubjectgreen_
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=ja] {æ¥ä»}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=ja] {ãã¡ã€ã«å}
+_texticontabLanguagegreen_ [l=ja] {èšèª}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=ja] {ãªã¬ãã€ãŒã·ã§ã³}
+_texticontabKeywordgreen_ [l=ja] {ã­ãŒã¯ãŒã}
+# -- Missing translation: _texticontabhowgreen_
+_texticontabseriesgreen_ [l=ja] {ã·ãªãŒãº}
+_texticontablistgreen_ [l=ja] {ãªã¹ãã€ã³ã°}
+# -- Missing translation: _texticontabtogreen_
+# -- Missing translation: _texticontabfromgreen_
+_texticontabtopicgreen_ [l=ja] {ãããã¯}
+_texticontabbrwsegreen_ [l=ja] {ãã©ãŠãº}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=ja] {ãã©ãŠãº}
+_texticontabPeoplegreen_ [l=ja] {äººåïŒèŸæžé ïŒ}
+_texticontabAcronymgreen_ [l=ja] {é ­å­èª}
+_texticontabPhrasegreen_ [l=ja] {ãã¬ãŒãº}
+_texticontabArtistgreen_ [l=ja] {ã¢ãŒãã¹ã}
+_texticontabVolumegreen_ [l=ja] {ããªã¥ãŒã }
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=ja] {ãã­ã¥ã¡ã³ããèŠã}
+_texticonclosedbook_ [l=ja] {ãã­ã¥ã¡ã³ããéã}
+_texticonnext_ [l=ja] {æ¬¡ã®ã»ã¯ã·ã§ã³ãž}
+_texticonprev_ [l=ja] {åã»ã¯ã·ã§ã³ãž}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=ja] {MIDIããã­ã¥ã¡ã³ããèŠã}
+_texticonmsword_ [l=ja] {MicrosoftãWordãã­ã¥ã¡ã³ããèŠã}
+_texticonmp3_ [l=ja] {MP3ããã­ã¥ã¡ã³ããèŠã}
+_texticonpdf_ [l=ja] {PDFããã­ã¥ã¡ã³ããèŠã}
+_texticonps_ [l=ja] {PostScriptããã­ã¥ã¡ã³ããèŠã}
+_texticonppt_ [l=ja] {PowerPointããã­ã¥ã¡ã³ããèŠã}
+_texticonrtf_ [l=ja] {RTFããã­ã¥ã¡ã³ããèŠã}
+_texticonxls_ [l=ja] {MicrosoftãExcelããã­ã¥ã¡ã³ããèŠã}
+
+_page_ [l=ja] {ããŒãž}
+_pages_ [l=ja] {ããŒãž}
+_of_ [l=ja] {ã®}
+_vol_ [l=ja] {Vol.}
+_num_ [l=ja] {ãã³ããŒ}
+
+_textmonth00_ [l=ja] {}
+_textmonth01_ [l=ja] {äžæ}
+_textmonth02_ [l=ja] {äºæ}
+_textmonth03_ [l=ja] {äžæ}
+_textmonth04_ [l=ja] {åæ}
+_textmonth05_ [l=ja] {äºæ}
+_textmonth06_ [l=ja] {å
+­æ}
+_textmonth07_ [l=ja] {äžæ}
+_textmonth08_ [l=ja] {å
+«æ}
+_textmonth09_ [l=ja] {ä¹æ}
+_textmonth10_ [l=ja] {åæ}
+_textmonth11_ [l=ja] {åäžæ}
+_textmonth12_ [l=ja] {åäºæ}
+
+_textdocument_ [l=ja] {ãã­ã¥ã¡ã³ã}
+_textsection_ [l=ja] {ã»ã¯ã·ã§ã³}
+_textparagraph_ [l=ja] {ãã©ã°ã©ã}
+
+_magazines_ [l=ja] {éèª}
+
+_nzdlpagefooter_ [l=ja] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ããŒã " ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=ja] {_httpimg_/ja/chomeof.gif}
+_httpiconchomeon_ [l=ja] {_httpimg_/ja/chomeon.gif}
+
+## "ãã«ã" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=ja] {_httpimg_/ja/chelpof.gif}
+_httpiconchelpon_ [l=ja] {_httpimg_/ja/chelpon.gif}
+
+## "ããªãã¡ã¬ã³ã¹" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=ja] {_httpimg_/ja/cprefof.gif}
+_httpiconcprefon_ [l=ja] {_httpimg_/ja/cprefon.gif}
+
+## "ãã£ãŒãããã¯ãéã" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=ja] {_httpimg_/ja/cusabof.gif}
+_httpiconcusabon_ [l=ja] {_httpimg_/ja/cusabon.gif}
+
+
+## "æ€çŽ¢" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=ja] {_httpimg_/ja/tsrchgr.gif}
+_httpicontsrchof_ [l=ja] {_httpimg_/ja/tsrchof.gif}
+_httpicontsrchon_ [l=ja] {_httpimg_/ja/tsrchon.gif}
+_widthtsrchx_ [l=ja] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ã¿ã€ãã«ïŒèŸæžé ïŒ" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=ja] {_httpimg_/ja/ttitlgr.gif}
+_httpiconttitleof_ [l=ja] {_httpimg_/ja/ttitlof.gif}
+_httpiconttitleon_ [l=ja] {_httpimg_/ja/ttitlon.gif}
+_widthttitlex_ [l=ja] {87}
+
+# Not true DC, kept for legacy reasons
+## "èè
+ïŒèŸæžé ïŒ" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=ja] {_httpimg_/ja/tauthgr.gif}
+_httpicontcreatof_ [l=ja] {_httpimg_/ja/tauthof.gif}
+_httpicontcreaton_ [l=ja] {_httpimg_/ja/tauthon.gif}
+_widthtcreatx_ [l=ja] {110}
+
+## "äž»é¡" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=ja] {_httpimg_/ja/tsubjgr.gif}
+_httpicontsubjon_ [l=ja] {_httpimg_/ja/tsubjon.gif}
+_httpicontsubjof_ [l=ja] {_httpimg_/ja/tsubjof.gif}
+_widthtsubjx_ [l=ja] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "æ¥ä»" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=ja] {_httpimg_/ja/tdategr.gif}
+_httpicontdateof_ [l=ja] {_httpimg_/ja/tdateof.gif}
+_httpicontdateon_ [l=ja] {_httpimg_/ja/tdateon.gif}
+_widthtdatex_ [l=ja] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "ãã¡ã€ã«å" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=ja] {_httpimg_/ja/tsrcgr.gif}
+_httpicontsrcof_ [l=ja] {_httpimg_/ja/tsrcof.gif}
+_httpicontsrcon_ [l=ja] {_httpimg_/ja/tsrcon.gif}
+_widthtsrcx_ [l=ja] {87}
+
+## "èšèª" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=ja] {_httpimg_/ja/tlanggr.gif}
+_httpicontlangon_ [l=ja] {_httpimg_/ja/tlangon.gif}
+_httpicontlangof_ [l=ja] {_httpimg_/ja/tlangof.gif}
+_widthtlangx_ [l=ja] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "ã·ãªãŒãº" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=ja] {_httpimg_/ja/tsergr.gif}
+_httpicontserof_ [l=ja] {_httpimg_/ja/tserof.gif}
+_httpicontseron_ [l=ja] {_httpimg_/ja/tseron.gif}
+_widthtserx_ [l=ja] {87}
+
+# -- Missing translation: tto
+# -- Missing translation: _httpiconttogr_
+# -- Missing translation: _httpiconttoon_
+# -- Missing translation: _httpiconttoof_
+# -- Missing translation: _widthttox_
+
+# -- Missing translation: tfrom
+# -- Missing translation: _httpicontfromgr_
+# -- Missing translation: _httpicontfromon_
+# -- Missing translation: _httpicontfromof_
+# -- Missing translation: _widthtfromx_
+
+## "çµç¹" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=ja] {_httpimg_/ja/torggr.gif}
+_httpicontorgon_ [l=ja] {_httpimg_/ja/torgon.gif}
+_httpicontorgof_ [l=ja] {_httpimg_/ja/torgof.gif}
+_widthtorgx_ [l=ja] {114}
+
+## "ã©ã®ããã«" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=ja] {_httpimg_/ja/thowgr.gif}
+_httpiconthowon_ [l=ja] {_httpimg_/ja/thowon.gif}
+_httpiconthowof_ [l=ja] {_httpimg_/ja/thowof.gif}
+_widththowx_ [l=ja] {87}
+
+## "ãããã¯" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=ja] {_httpimg_/ja/ttopicgr.gif}
+_httpiconttopicon_ [l=ja] {_httpimg_/ja/ttopicon.gif}
+_httpiconttopicof_ [l=ja] {_httpimg_/ja/ttopicof.gif}
+_widthttopicx_ [l=ja] {87}
+
+## "ãã©ãŠãº" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=ja] {_httpimg_/ja/tbrwsegr.gif}
+_httpicontbrwseon_ [l=ja] {_httpimg_/ja/tbrwseon.gif}
+_httpicontbrwseof_ [l=ja] {_httpimg_/ja/tbrwseof.gif}
+_widthtbrwsex_ [l=ja] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "äººã
+" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=ja] {_httpimg_/ja/tpeopgr.gif}
+_httpicontpeopof_ [l=ja] {_httpimg_/ja/tpeopof.gif}
+_httpicontpeopon_ [l=ja] {_httpimg_/ja/tpeopon.gif}
+_widthtpeopx_ [l=ja] {97}
+
+## "é ­å­èª" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=ja] {_httpimg_/ja/tacrogr.gif}
+_httpicontacroof_ [l=ja] {_httpimg_/ja/tacroof.gif}
+_httpicontacroon_ [l=ja] {_httpimg_/ja/tacroon.gif}
+_widthtacrox_ [l=ja] {87}
+
+## "ãã¬ãŒãº" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=ja] {_httpimg_/ja/tphrsegr.gif}
+_httpicontphrseof_ [l=ja] {_httpimg_/ja/tphrseof.gif}
+_httpicontphrseon_ [l=ja] {_httpimg_/ja/tphrseon.gif}
+_widthtphrsex_ [l=ja] {87}
+
+## "ã¢ãŒãã¹ã" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=ja] {_httpimg_/ja/tartstgr.gif}
+_httpicontartstof_ [l=ja] {_httpimg_/ja/tartstof.gif}
+_httpicontartston_ [l=ja] {_httpimg_/ja/tartston.gif}
+_widthtartstx_ [l=ja] {87}
+
+## "ã­ãŒã¯ãŒã" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=ja] {_httpimg_/ja/tkwgr.gif}
+_httpicontkwof_ [l=ja] {_httpimg_/ja/tkwof.gif}
+_httpicontkwon_ [l=ja] {_httpimg_/ja/tkwon.gif}
+_widthtkwx_ [l=ja] {87}
+
+# -- Missing translation: tvol
+# -- Missing translation: _httpicontvolgr_
+# -- Missing translation: _httpicontvolof_
+# -- Missing translation: _httpicontvolon_
+# -- Missing translation: _widthtvolx_
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "ãã«ã" ## green_title ## h_help ##
+_httpiconhhelp_ [l=ja] {_httpimg_/ja/h\_help.gif}
+_widthhhelp_ [l=ja] {200}
+_heighthhelp_ [l=ja] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=ja] {ãã®ã³ã¬ã¯ã·ã§ã³ã«ã€ããŠ}
+
+_textsubcols1_ [l=ja] {<p>ãã®å®å
+šãªã³ã¬ã¯ã·ã§ã³ã¯éšåã³ã¬ã¯ã·ã§ã³ _1_ ãå«ã¿ãŸãããããã¯æ¬¡ã«å©çšå¯èœã§ãïŒ  <blockquote>}
+
+_textsubcols2_ [l=ja] {</blockquote>
+ããªãã¡ã¬ã³ã¹ããŒãžã§çŸåšããªããä»æ§ããŠãããµãã³ã¬ã¯ã·ã§ã³ãã©ããªã®ããæ žã«ããããšãã§ããŸãã}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_about
+# -- Missing translation: _httpiconhabout_
+# -- Missing translation: _widthhabout_
+# -- Missing translation: _heighthabout_
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=ja] {ã¿ã€ãã«ïŒèŸæžé ïŒ}
+_texticonhcreat_ [l=ja] {äœè
+ïŒèŸæžé ïŒ}
+_texticonhsubj_ [l=ja] {äž»é¡}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=ja] {æ¥ä»}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=ja] {ãã¡ã€ã«å}
+_texticonhlang_ [l=ja] {èšèª}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=ja] {To}
+_texticonhfrom_ [l=ja] {From}
+_texticonhser_ [l=ja] {ã·ãªãŒãº}
+_texticonhhow_ [l=ja] {How to}
+_texticonhorg_ [l=ja] {çµç¹}
+_texticonhbrwse_ [l=ja] {é²èŠ§}
+_texticonhbrows_ [l=ja] {é²èŠ§}
+_texticonhpeople_ [l=ja] {äººåïŒèŸæžé ïŒ}
+_texticonhacronym_ [l=ja] {é ­å­èª}
+_texticonhphrases_ [l=ja] {ãã¬ãŒãº}
+_texticonhartist_ [l=ja] {ã¢ãŒãã¹ã}
+_texticonhkw_ [l=ja] {ã­ãŒã¯ãŒã}
+_texticonhvol_ [l=ja] {Volumes}
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=ja] {ãã®ã©ã€ãã©ãªã®ã»ã¯ã·ã§ã³ãéãã}
+_texticonclosedbookshelf_ [l=ja] {ãã®ã»ã¯ã·ã§ã³ãéããã³ã³ãã³ããèŠã}
+_texticonopenbook_ [l=ja] {ãã®æ¬ãéãã}
+_texticonclosedfolder_ [l=ja] {ãã©ã«ããŒãéããã³ã³ãã³ããèŠã}
+_texticonclosedfolder2_ [l=ja] {ãµãã»ã¯ã·ã§ã³ãéã}
+_texticonopenfolder_ [l=ja] {ãã©ã«ããéãã}
+_texticonopenfolder2_ [l=ja] {ãµãã»ã¯ã·ã§ã³ãéããïŒ}
+_texticonsmalltext_ [l=ja] {ãã®ã»ã¯ã·ã§ã³ã®ãã­ã¹ããèŠãïŒ}
+_texticonsmalltext2_ [l=ja] {ãã­ã¹ããèŠãïŒ}
+_texticonpointer_ [l=ja] {çŸåšã®ã»ã¯ã·ã§ã³}
+_texticondetach_ [l=ja] {ãã®ããŒãžãæ°ãããŠã£ã³ããŠã§éã}
+_texticonhighlight_ [l=ja] {æ€çŽ¢èªããã€ã©ã€ã}
+_texticonnohighlight_ [l=ja] {æ€çŽ¢èªããã€ã©ã€ããããªã}
+_texticoncontracttoc_ [l=ja] {ã³ã³ãã³ãã®ããŒãã«ãçµãããã}
+_texticonexpandtoc_ [l=ja] {ã³ã³ãã³ãã®ããŒãã«ãæ¡åŒµãã}
+_texticonexpandtext_ [l=ja] {ãã¹ãŠã®ãã­ã¹ããè¡šç€ºãã}
+_texticoncontracttext_ [l=ja] {çŸåšéžæããã»ã¯ã·ã§ã³ã®ãã­ã¹ãã ããèŠã}
+_texticonwarning_ [l=ja] {<b>è­Šå: </b>}
+_texticoncont_ [l=ja] {ç¶ããŸããïŒ}
+
+_textltwarning_ [l=ja] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Expanding ãã®ãã­ã¹ãã¯ãããªãã®ãã©ãŠã¶ã§è¡šç€ºãããããã«ã¯ãéåžžã«å€§ããªããŒã¿ãšãªã£ãŠããŸããŸãã _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=ja] {ããŒãžã«è¡ã}
+_textintro_ [l=ja] {<i>(introductory text)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ã¿ã€ãã«ïŒèŸæžé ïŒ" ## green_title ## h_title ##
+_httpiconhtitle_ [l=ja] {_httpimg_/ja/h\_title.gif}
+_widthhtitle_ [l=ja] {200}
+_heighthtitle_ [l=ja] {57}
+
+# Not true DC, kept for legacy reasons
+## "äœå®¶ïŒèŸæžé ïŒ" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=ja] {_httpimg_/ja/h\_auth.gif}
+_widthhcreat_ [l=ja] {200}
+_heighthcreat_ [l=ja] {57}
+
+# -- Missing translation: h_subj
+# -- Missing translation: _httpiconhsubj_
+# -- Missing translation: _widthhsubj_
+# -- Missing translation: _heighthsubj_
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "æ¥ä»" ## green_title ## h_date ##
+_httpiconhdate_ [l=ja] {_httpimg_/ja/h\_date.gif}
+_widthhdate_ [l=ja] {200}
+_heighthdate_ [l=ja] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "ãã¡ã€ã«å" ## green_title ## h_src ##
+_httpiconhsrc_ [l=ja] {_httpimg_/ja/h\_src.gif}
+_widthhsrc_ [l=ja] {200}
+_heighthsrc_ [l=ja] {57}
+
+## "èšèª" ## green_title ## h_lang ##
+_httpiconhlang_ [l=ja] {_httpimg_/ja/h\_lang.gif}
+_widthhlang_ [l=ja] {200}
+_heighthlang_ [l=ja] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+# -- Missing translation: h_to
+# -- Missing translation: _httpiconhto_
+# -- Missing translation: _widthhto_
+# -- Missing translation: _heighthto_
+
+# -- Missing translation: h_from
+# -- Missing translation: _httpiconhfrom_
+# -- Missing translation: _widthhfrom_
+# -- Missing translation: _heighthfrom_
+
+## "ã·ãªãŒãº" ## green_title ## h_ser ##
+_httpiconhser_ [l=ja] {_httpimg_/ja/h\_ser.gif}
+_widthhser_ [l=ja] {200}
+_heighthser_ [l=ja] {57}
+
+# -- Missing translation: h_how
+# -- Missing translation: _httpiconhhow_
+# -- Missing translation: _widthhhow_
+# -- Missing translation: _heighthhow_
+
+## "ãããã¯" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=ja] {_httpimg_/ja/h\_topic.gif}
+_widthhtopic_ [l=ja] {200}
+_heighthtopic_ [l=ja] {57}
+
+# -- Missing translation: h_org
+# -- Missing translation: _httpiconhorg_
+# -- Missing translation: _widthhorg_
+# -- Missing translation: _heighthorg_
+
+## "ãã©ãŠãº" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=ja] {_httpimg_/ja/h\_brwse.gif}
+_widthhbrwse_ [l=ja] {200}
+_heighthbrwse_ [l=ja] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "äººå" ## green_title ## h_people ##
+_httpiconhpeople_ [l=ja] {_httpimg_/ja/h\_people.gif}
+_widthhpeople_ [l=ja] {200}
+_heighthpeople_ [l=ja] {57}
+
+## "é ­å­èª" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=ja] {_httpimg_/ja/h\_acro.gif}
+_widthhacronym_ [l=ja] {200}
+_heighthacronym_ [l=ja] {57}
+
+## "ãã¬ãŒãº" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=ja] {_httpimg_/ja/h\_phrse.gif}
+_widthhphrse_ [l=ja] {200}
+_heighthphrse_ [l=ja] {57}
+
+## "ã¢ãŒãã¹ã" ## green_title ## h_artist ##
+_httpiconhartist_ [l=ja] {_httpimg_/ja/h\_artist.gif}
+_widthhartist_ [l=ja] {200}
+_heighthartist_ [l=ja] {57}
+
+## "ã­ãŒã¯ãŒã" ## green_title ## h_kw ##
+_httpiconhkw_ [l=ja] {_httpimg_/ja/h\_kw.gif}
+_widthhkw_ [l=ja] {200}
+_heighthkw_ [l=ja] {57}
+
+# -- Missing translation: h_vol
+# -- Missing translation: _httpiconhvol_
+# -- Missing translation: _widthhvol_
+# -- Missing translation: _heighthvol_
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+## "ç¶ããŸããïŒ?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=ja] {_httpimg_/ja/contof.gif}
+_httpiconconton_ [l=ja] {_httpimg_/ja/conton.gif}
+
+# -- Missing translation: eallt
+# -- Missing translation: _httpiconealltof_
+# -- Missing translation: _httpiconeallton_
+
+# -- Missing translation: econc
+# -- Missing translation: _httpiconeconcof_
+# -- Missing translation: _httpiconeconcon_
+
+# -- Missing translation: edtch
+# -- Missing translation: _httpiconedtchof_
+# -- Missing translation: _httpiconedtchon_
+
+# -- Missing translation: eexpc
+# -- Missing translation: _httpiconeexpcof_
+# -- Missing translation: _httpiconeexpcon_
+
+# -- Missing translation: etsec
+# -- Missing translation: _httpiconetsecof_
+# -- Missing translation: _httpiconetsecon_
+
+# -- Missing translation: ehl
+# -- Missing translation: _httpiconehlof_
+# -- Missing translation: _httpiconehlon_
+
+# -- Missing translation: enhl
+# -- Missing translation: _httpiconenhlof_
+# -- Missing translation: _httpiconenhlon_
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=ja] {_If_(_thislast_,results _thisfirst_ - _thislast_ for query: _cgiargq_,No matches for query: _cgiargq_)}
+_textnoquerytitle_ [l=ja] {æ€çŽ¢ããŒãž}
+
+_texticonthispage_ [l=ja] {æ€çŽ¢}
+# -- Missing translation: _textsome_
+# -- Missing translation: _textall_
+# -- Missing translation: _textboolean_
+# -- Missing translation: _textranked_
+# -- Missing translation: _textnatural_
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=ja] {}
+_texticonsearchhistorybar_ [l=ja] {æ€çŽ¢å±¥æ­Ž}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=ja] {ãã®åãåãããäœ¿ã}
+_textfreqmsg1_ [l=ja] {Word count: }
+_textpostprocess_ [l=ja] {_If_(_quotedquery_,<br><i>post-processed to find _quotedquery_</i>
+)}
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=ja] {More than }
+_textapprox_ [l=ja] {About }
+_textnodocs_ [l=ja] {åãåããã«åèŽããæç« ããããŸãã}
+_text1doc_ [l=ja] {1 document matched the query.}
+_textlotsdocs_ [l=ja] {documents matched the query.}
+_textmatches_ [l=ja] {åèŽæ°}
+_textbeginsearch_ [l=ja] {Begin Search}
+_textrunquery_ [l=ja] {åãåããå®è¡}
+_textclearform_ [l=ja] {Clear Form}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=ja] {èªãŸãã¯ãã¬ãŒãº}
+_textinfield_ [l=ja] {... in field}
+_textfoldstem_ [l=ja] {(fold, stem)}
+
+_textadvquery_ [l=ja] {Or enter a query directly:}
+# -- Missing translation: _textallfields_
+# -- Missing translation: _texttextonly_
+_textand_ [l=ja] {and}
+_textor_ [l=ja] {or}
+_textandnot_ [l=ja] {and not}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+# -- Missing translation: _textsimplesearch_
+
+# -- Missing translation: _textadvancedsearch_
+
+# -- Missing translation: _textformsimplesearch_
+
+# -- Missing translation: _textformadvancedsearch_
+
+
+# -- Missing translation: _textnojsformwarning_
+_textdatesearch_ [l=ja] {This collection can be searched for documents within a date range, or documents that contain a particular date. This is an optional feature of the search.}
+_textstartdate_ [l=ja] {æ¥ä»ïŒæéã®å Žåã¯éå§å¹Žææ¥ïŒïŒ}
+_textenddate_ [l=ja] {End date:}
+_textbc_ [l=ja] {B.C.E.}
+_textad_ [l=ja] {C.E.}
+_textexplaineras_ [l=ja] {C.E. and B.C.E are alternatives for A.D. and B.C. respectively.  These terms are considered to be culture indiscriminate, and stand for "Common Era" and "Before the Common Era"}
+
+_textstemon_ [l=ja] {(èªæ«åœ¢åŒãç¡èŠããŠããŸã)}
+
+_textsearchhistory_ [l=ja] {æ€çŽ¢å±¥æ­Ž}
+
+#text macros for search history
+_textnohistory_ [l=ja] {æ€çŽ¢å±¥æ­ŽããããŸãã}
+_texthresult_ [l=ja] {result}
+_texthresults_ [l=ja] {results}
+_texthallwords_ [l=ja] {all words}
+_texthsomewords_ [l=ja] {some words}
+_texthboolean_ [l=ja] {boolean}
+_texthranked_ [l=ja] {ranked}
+_texthcaseon_ [l=ja] {case must match}
+_texthcaseoff_ [l=ja] {casefolded}
+_texthstemon_ [l=ja] {stemmed}
+_texthstemoff_ [l=ja] {unstemmed}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "æ€çŽ¢" ## green_title ## h_search ##
+_httpiconhsearch_ [l=ja] {_httpimg_/ja/h\_search.gif}
+_widthhsearch_ [l=ja] {200}
+_heighthsearch_ [l=ja] {57}
+
+## "çµæ" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=ja] {_httpimg_/ja/qryresb.gif}
+_widthqryresb_ [l=ja] {_pagewidth_}
+_heightqryresb_ [l=ja] {17}
+
+## "å±¥æ­Ž" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=ja] {_httpimg_/ja/schhistb.gif}
+_widthsrchhistb_ [l=ja] {_pagewidth_}
+_heightsrchhistb_ [l=ja] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=ja] {ããªãã¡ã¬ã³ã¹ã®èš­å®ã¯ä»¥äžã®éãã§ãããã©ãŠã¶ã®ããã¯ãã¿ã³ã¯æŒããªãã§ãã ããã}
+_textsetprefs_ [l=ja] {set preferences}
+_textsearchprefs_ [l=ja] {æ€çŽ¢ããªãã¡ã¬ã³ã¹}
+_textcollectionprefs_ [l=ja] {ã³ã¬ã¯ã·ã§ã³ããªãã¡ã¬ã³ã¹}
+_textpresentationprefs_ [l=ja] {Presentation ããªãã¡ã¬ã³ã¹}
+_textpreferences_ [l=ja] {ããªãã¡ã¬ã³ã¹}
+_textcasediffs_ [l=ja] {Case differences:}
+_textignorecase_ [l=ja] {å€§æå­ã»å°æå­ãåºå¥ããªã}
+_textmatchcase_ [l=ja] {å€§æå­ã»å°æå­ãåºå¥ãã}
+_textwordends_ [l=ja] {Word endings:}
+_textstem_ [l=ja] {ignore word endings}
+_textnostem_ [l=ja] {å®å
+šèªäžèŽ}
+_textprefop_ [l=ja] {Return up to _maxdocoption_ hits with _hitsperpageoption_ hits per page.}
+_textextlink_ [l=ja] {Access to external Web pages:}
+_textintlink_ [l=ja] {Source documents retrieved from:}
+_textlanguage_ [l=ja] {ã€ã³ã¿ãŒãã§ãŒã¹èšèªïŒ}
+_textencoding_ [l=ja] {æå­ã³ãŒãïŒ}
+_textformat_ [l=ja] {ã€ã³ã¿ãŒãã§ãŒã¹ format:}
+_textall_ [l=ja] {all}
+_textquerymode_ [l=ja] {åãåããã¢ãŒãïŒ}
+_textsimplemode_ [l=ja] {simple query mode}
+_textadvancedmode_ [l=ja] {advancedåãåããã¢ãŒã (æŒç®å­ !, &, |,ãäœ¿ããŸã)}
+_textlinkinterm_ [l=ja] {through intermediate page}
+_textlinkdirect_ [l=ja] {go directly there}
+_textdigitlib_ [l=ja] {é»å­å³æžé€š}
+_textweb_ [l=ja] {the web}
+_textgraphical_ [l=ja] {ã°ã©ãã£ãã¯}
+_texttextual_ [l=ja] {Textual}
+_textcollectionoption_ [l=ja] {<p>
+ãµãã³ã¬ã¯ã·ã§ã³ãå«ãã:
+<br>}
+
+_textrelateddocdisplay_ [l=ja] {é¢é£ããæç« ãè¡šç€ºãã}
+_textsearchhistory_ [l=ja] {æ€çŽ¢å±¥æ­ŽïŒ}
+_textnohistory_ [l=ja] {æ€çŽ¢å±¥æ­Žã¯ãããŸãã}
+_texthistorydisplay_ [l=ja] {display _historynumrecords_ search history records}
+_textnohistorydisplay_ [l=ja] {æ€çŽ¢å±¥æ­ŽãèŠããªã}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+# -- Missing translation: _textformsearch_
+# -- Missing translation: _textplainsearch_
+_textqueryboxsize_ [l=ja] {åãåããé åã®å€§ããïŒ}
+_textregbox_ [l=ja] {æšæºã®åãåããé å}
+_textbigbox_ [l=ja] {å€§ããªåãåããé å}
+_textformtype_ [l=ja] {Form type:}
+_textsimple_ [l=ja] {simple}
+_textadvanced_ [l=ja] {advanced}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=ja] {with}
+_textfields_ [l=ja] {fields}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_pref
+# -- Missing translation: _httpiconhpref_
+# -- Missing translation: _widthhpref_
+# -- Missing translation: _heighthpref_
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=ja] {äžŠã¹æ¿ãã®æ¹æ³}
+_textalsoshowing_ [l=ja] {also showing}
+_textwith_ [l=ja] {æå€§ã§ã}
+_textdocsperpage_ [l=ja] {ãã­ã¥ã¡ã³ãïŒïŒããŒãžæ¯ïŒ}
+
+_textfilterby_ [l=ja] {å«ãã§ãããã­ã¥ã¡ã³ããååŸ}
+_textall_ [l=ja] {ãã¹ãŠ}
+_textany_ [l=ja] {any}
+_textwords_ [l=ja] {èªæ°}
+_textleaveblank_ [l=ja] {ãã¹ãŠã®ãã­ã¥ã¡ã³ããååŸããããã«ã¯ããã®ããã¯ã¹ãç©ºã®ãŸãŸã«ããŠãã ãã}
+
+_browsebuttontext_ [l=ja] {"äžŠã¹æ¿ã"}
+
+_nodata_ [l=ja] {<i>ããŒã¿ããããŸãã</i>}
+_docs_ [l=ja] {ãã­ã¥ã¡ã³ã}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=ja] {Help}
+_textSearchshort_ [l=ja] {ç¹å®ã®èªã«ããæ€çŽ¢}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=ja] {ã¿ã€ãã«ã«ããã¢ã¯ã»ã¹}
+_textCreatorshort_ [l=ja] {èè
+åã«ããã¢ã¯ã»ã¹}
+_textSubjectshort_ [l=ja] {äž»é¡ã«ããã¢ã¯ã»ã¹}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=ja] {åºçæ¥ã«ããã¢ã¯ã»ã¹}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=ja] {ãã¡ã€ã«åã«ããã¢ã¯ã»ã¹}
+_textLanguageshort_ [l=ja] {èšèªã«ããã¢ã¯ã»ã¹}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=ja] {ã·ãªãŒãºã«ããã¢ã¯ã»ã¹}
+_textToshort_ [l=ja] {toé 
+ç®ã«ããã¢ã¯ã»ã¹}
+_textFromshort_ [l=ja] {Fromé 
+ç®ã«ããã¢ã¯ã»ã¹}
+_textBrowseshort_ [l=ja] {äœåã®é²èŠ§}
+_textOrganizationshort_ [l=ja] {çµç¹ã«ããã¢ã¯ã»ã¹}
+_textHowtoshort_ [l=ja] {how to listing ã«ããã¢ã¯ã»ã¹}
+_textTopicshort_ [l=ja] {ãããã¯ã«ããã¢ã¯ã»ã¹}
+_textPeopleshort_ [l=ja] {äººåã«ããã¢ã¯ã»ã¹}
+_textAcronymshort_ [l=ja] {é ­å­èªã«ããã¢ã¯ã»ã¹}
+_textPhraseshort_ [l=ja] {ãã¬ãŒãºã«ããé²èŠ§}
+_textArtistshort_ [l=ja] {ã¢ãŒãã¹ãã«ããã¢ã¯ã»ã¹}
+_textKeywordshort_ [l=ja] {ã­ãŒã¯ãŒãã«ããã¢ã¯ã»ã¹}
+_textVolumeshort_ [l=ja] {volumeã«ããã¢ã¯ã»ã¹}
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=ja] {èš­å®ãããŠããªãåé¡ã§ã}
+
+_textSearchlong_ [l=ja] {<p><I>search</I>ãã¿ã³ã§ãç¹å®ã®åèªã«ããæ€çŽ¢ãã§ããŸãã}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=ja] {<p><i>ã¿ã€ãã«ïŒèŸæžé ïŒ</i>ãã¿ã³ã§ãã¿ã€ãã«ã«ããã¢ã¯ã»ã¹ãã§ããŸãã}
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=ja] {<p><i>äœè
+ïŒèŸæžé ïŒ</i>ã«ãã£ãŠäœåã«ã¢ã¯ã»ã¹ããããšãã§ããŸãã
+<i>äœå®¶ïŒèŸæžé ïŒ</i>ãã¿ã³ãæŒãããªã¹ããè¡šç€ºãããŠãã ããã}
+
+_textSubjectlong_ [l=ja] {<i>subjects</i>ãã¿ã³ã«ãããäž»é¡ã«ããã¢ã¯ã»ã¹ãã§ããŸãã}
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=ja] {<p><i>åºçæ¥</i>ã«ãã£ãŠäœåã«ã¢ã¯ã»ã¹ããããšãã§ããŸãã
+<i>æ¥ä»</i>ãã¿ã³ãæŒãããªã¹ããè¡šç€ºãããŠãã ããã}
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=ja] {<p><i>filenames</i>ãã¿ã³ã§ããã¡ã€ã«åã«ããæ€çŽ¢ãã§ããŸãã}
+
+_textLanguagelong_ [l=ja] {<p> <i>èšèª</i>ãã¿ã³ã«ãããèšèªã«ããäœåãžã®ã¢ã¯ã»ã¹ãã§ããŸãã}
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=ja] {<i>organisation</i>ãã¿ã³ã«ãããçµç¹ããšã«äœåã«ã¢ã¯ã»ã¹ã§ããŸãã}
+
+_textHowtolong_ [l=ja] {<p><i>how to</i>ãã¿ã³ã«ãããã©ã®ããã«é 
+ç®ãäžŠã¹ããã«ãã£ãŠäœåã«ã¢ã¯ã»ã¹ã§ããŸãã}
+
+_textTopiclong_ [l=ja] {<p><i>ãããã¯</i>ãã¿ã³ã§ãšãŽã£ãã«ããã¢ã¯ã»ã¹ãã§ããŸãã}
+
+_textTolong_ [l=ja] {<p><i>to</i>ãã¿ã³ã§ãtoé 
+ç®ã«é¢é£ããã¢ã¯ã»ã¹ãã§ããŸãã}
+
+_textFromlong_ [l=ja] {<p><i>Fromé 
+ç®</i>ã«ãã£ãŠäœåã«ã¢ã¯ã»ã¹ããããšãã§ããŸãã
+<i>from</i>ãã¿ã³ãæŒãããªã¹ããè¡šç€ºãããŠãã ããã}
+
+_textSerieslong_ [l=ja] {<i>series</i>ãã¿ã³ã«ãããã·ãªãŒãºããšã«äœåã«ã¢ã¯ã»ã¹ããããšãã§ããŸãã}
+
+_textBrowselong_ [l=ja] {<p>äœåãé²èŠ§ããããã«ã¯<I>browse</I>ãã¿ã³ãæŒããŠãã ããã}
+
+_textPeoplelong_ [l=ja] {<i>äººåïŒèŸæžé ïŒ</i>ãã¿ã³ã«ãããäººåã«ããäœåã«ã¢ã¯ã»ã¹ã§ããŸãã}
+
+_textAcronymlong_ [l=ja] {<p>ããªãã¯ã<i>é ­å­èª</i>ã«ãã£ãŠãã­ã¥ã¡ã³ãã«ã¢ã¯ã»ã¹ããããšãã§ããŸãã
+ãã®ããã«ã¯ã<i>é ­å­èª</i> ãã¿ã³ãæŒããé ­å­èªã®ãªã¹ããè¡šç€ºãããŠãã ããã
+}
+
+_textPhraselong_ [l=ja] {<p><i>phrases</i>ãã¿ã³ã«ããããã¬ãŒãºæ€çŽ¢ãã§ããŸãã}
+
+_textArtistlong_ [l=ja] {<p><i>ã¢ãŒãã£ã¹ã</i>ã«ãã£ãŠäœåã«ã¢ã¯ã»ã¹ããããšãã§ããŸãã
+<i>ã¢ãŒãã¹ã</i>ãã¿ã³ãæŒãããªã¹ããè¡šç€ºãããŠãã ããã
+}
+
+_textKeywordlong_ [l=ja] {<p><i>ã­ãŒã¯ãŒã</i>ãã¿ã³ã«ãããã­ãŒã¯ãŒãã«ããäœåãžã®ã¢ã¯ã»ã¹ãã§ããŸãã}
+
+_textVolumelong_ [l=ja] {<p><i>volumes</i>ãã¿ã³ã«ããvolumeã«ããã¢ã¯ã»ã¹ãã§ããŸãã}
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=ja] {<p><i>unknown</i>ãã¿ã³ã§ãunknowïœé 
+ç®ãã€ãã£ãäœåã®é²èŠ§ãã§ããŸãã}
+
+_texthelptopics_ [l=ja] {<h2 align=left>Topics</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching"æ€çŽ¢èªã®æ€çŽ¢æ¹æ³</a>
+<ul>
+  <li><a href="\#query-terms">Search terms</a>
+  <li><a href="\#query-type">Query type</a>
+  <li><a href="\#scope-of-queries">Scope of queries</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Collection preferences</a>
+  <li><a href="\#lang-prefs">Language preferences</a>
+  <li><a href="\#pres-prefs">Presentation preferences</a>
+  <li><a href="\#search-prefs">Search preferences</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=ja] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=ja] {ã©ã®ããã«æç« ãèª­ãã}
+
+_texthelpreadingdocs_ [l=ja] {<p>_iconblankbar_
+ <a name=reading-docs>
+ <h2>_textreadingdocs_</h2>
+ 
+ <p>åã
+ã®ææžã®ã¿ã€ãã«ãšèè
+ã¯ãããŒãžã®äžéšå·Šã«ç€ºãããã
+ãããã®æšªã«ããæ°å­ã¯ãçŸåšã®ããŒãžã§ãç®±ã¯ãæ°ããéžæã§ããããŒãžããããŠãå·Šå³ã®ç¢å°ã¯åã®ããŒãžãåŸãã®ããŒãžãç€ºãã
+
+<p>ç»é¢äžéšã¯ãçŸåšã®ã»ã¯ã·ã§ã³ã®ãã­ã¹ãã§ããã
+ãã­ã¹ããæåŸãŸã§èª­ããšããã®äžã«åã®ããŒãžãåŸãã®ããŒãžãžã®ç¢å°ãããã
+
+<p>ã¿ã€ãã«ãšèè
+ã®äžã«ã¯ïŒã€ã®ãã¿ã³ãããã
+<i>expand text</i>ãæŒããšãçŸåšã®æç« ã®ãã­ã¹ãå
+šäœãæ¡å€§ããã
+ãããæç« ãå€§ãããªãããã®åŠçã«ã¯é·ãæéãšå€ãã®ã¡ã¢ãªãå¿
+èŠãšãªãã®ã§æ³šæããŠãã ããã
+<i>detach</i> ãæŒããšããã®æç« ã®ããã«æ°ãããã©ãŠã¶ãŠã£ã³ããŠãéããŸãã
+ããã¯ãæç« åå£«ãæ¯ã¹ãæã«äŸ¿å©ã§ãããã
+<i>no highlighting</i>ã¯ãæ€çŽ¢èªã®ãã€ã©ã€ãããããããšãã§ããŸãã
+ <p>
+ <table cellspacing="0" cellpadding="2" border="0">
+ <tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Click on the arrow to go to the next section ...</td></tr>
+ <tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... or back to the previous section</td></tr>
+ <tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+ src="_document:httpiconetsecof_" border="0"></td><td>Display all text, or not</td></tr>
+ <tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+ <tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+ src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+</table>}
+
+_texthelpsearching_ [l=ja] {<h2>ããã«ãç¹å®ã®èªãæ€çŽ¢ããã</h2>
+<p>
+æ€çŽ¢ããŒãžãããæ¬¡ã®ãããªã¹ãããã§è³ªåããã :<p>
+<ol><li>ã©ã®ãããªã¢ã€ãã ãæãããæå®ããã
+   <li>ãã¹ãŠã®èªãå«ãã®ããããã€ãã®èªã ãã§ããã®ããæ±ºããã
+   <li>æ€çŽ¢ãããèªãå
+¥åããã
+   <li><i>Begin Search</i>ãã¿ã³ãã¯ãªãã¯ããã
+</ol>
+
+<p>
+è³ªåããããšãè©²åœãã20ã®ææžã®ã¿ã€ãã«ãè¡šç€ºãããã§ãããã
+ãã®äžçªäžã«ã¯ãæ¬¡ã®20ã®ææžãååŸãããã¿ã³ããããŸãã
+æ¬¡ã®ç»é¢ã§ãåæ§ã«ã3çªç®ã®20ææžããŸãã¯ãæåã®20ææžã«æ»ããã¿ã³ããããŸãã
+ã©ã®ææžã®ãã¿ã³ãããã®æšªã«ããå°ããªãã¿ã³ãæŒããŠãããã®æç« ãã¿ãããšãã§ããŸãã
+
+<p>
+æ€çŽ¢ã®æå€§æ°ã¯100ã§äž­æ­ãããŸãã
+ãã®æ°å­ãå€ããããã«ã¯ã
+æåã®ããŒãžã®<i>preferences</i>ãã¿ã³ãæŒããŠãã ããã
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>æ€çŽ¢èª</h3>
+
+<p>
+æ€çŽ¢ããã¯ã¹ã®å
+¥åãã¹ãŠã¯ãæ€çŽ¢èªãšåŒã°ããèªã®ãªã¹ããšè§£éãããŸãã
+ããããã®æ€çŽ¢èªã¯è±å­ãšæ°å­ã§ãããç©ºçœã§åºåãããã
+å¥èª­ç¹ã¯ãç©ºçœãšåæ§ã«æ€çŽ¢èªãåºåããšèŠãªãããç¡èŠãããã
+ãã®ãããå¥èª­ç¹ãå«ãèªãæ€çŽ¢ããããšã¯ã§ããªãã
+
+<p>åãåããã®äŸ<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>ã¯æ¬¡ãšåæ§ã«èŠãªããã<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>åãåããã®ã¿ã€ã</h3>
+
+<p>åãåããã«ã¯ïŒã€ã®ã¿ã€ããããã
+
+<ul>
+  <li>æ€çŽ¢èª<b>ãã¹ãŠãšã®</b>äžèŽïŒæ€çŽ¢èªã®ãã¹ãŠãå«ãæç« ïŒæã«ã¯ç« ãã¿ã€ãã«ïŒãæ¢ããæ¡ä»¶ã«åèŽããæç« ã¯èŸæžé ã«è¡šç€ºãããã<p>
+
+  <li>æ€çŽ¢èªã®<b>äžéšãšã®</b>äžèŽïŒæ€çŽ¢èªã®äžéšãšã®äžèŽã«ããæ€çŽ¢ããããçµæã¯æ€çŽ¢èªãšäžèŽåºŠãé«ããã®ããé ã«è¡šç€ºãããã
+      <p><ul>
+        <li>æ°å€ãã®æ€çŽ¢èªãšäžèŽããã»ã©ãããåèŽãããšã¿ãªã
+        <li>åžã«åºçŸããèªãåºçŸããã»ã©ããåèŽãããšã¿ãªãã
+        <li>é·ãæç« ãããç­ãæç« ã®æ¹ãããåèŽãããšããã
+      </ul>
+</ul>
+
+<p>æ€çŽ¢èªã¯å¥œããªã ãå€ãå«ããŠããããäŸãã°æãããã©ã°ã©ãã§ãã£ãŠãããã
+ïŒåèªã ããæå®ãããšãçµæã¯æç« äž­ã®ãã®åèªã®åºçŸé »åºŠãå€ãé ã«äžŠã¹ãããŠåºåãããã<p>
+}
+
+_textdatesearch_ [l=ja] {æ¥ä»ã«ããæ€çŽ¢}
+
+_texthelpdatesearch_ [l=ja] {<h2>_textdatesearch_</h2>
+æ¥ä»æ€çŽ¢ã¯ãèªã«ããæ€çŽ¢ãšåæ§ã«æéé 
+ç®ãæ€çŽ¢ããŸãã
+ãã®å Žåãããå¹Žããããããã¯ãæ°å¹Žã®ç¯å²ããã®ææžãæ¢ããšãã£ãããšãã§ããŸãã
+æ¥ä»ã«ããæ€çŽ¢ãªã®ã§ãæ¥ä»é 
+ç®ã«å­åšããªããããªèªãå
+¥åããŠãé©åœãªæ€çŽ¢ãè¡ãªããªãããšã«æ³šæããŠãã ããã
+<p>
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>ãã®æ©èœã®äœ¿ãæ¹:</h3>
+<ul>
+   <li>åå¹Žã«å¯ŸããŠã®æ€çŽ¢:<p>
+   <ul>
+       <li>å
+¥åã¯æ®éã«è¡ããŸãã 
+       <li>æ€çŽ¢å¹Žã""Start (or only) date""ã«å
+¥åããã
+       <li>æ¥ä»ã«çŽå
+åãæå®ããããšãã¯ããã«ããŠã³ã¡ãã¥ãŒãã ""B.C.E""ãéžãã§ãã ããã.
+   </ul>
+<p><li>æéãæå®ããŠã®æ€çŽ¢ïŒ<p>
+   <ul>
+       <li>å
+¥åã¯æ®éã«è¡ããŸãã
+       <li>æéã®å§ãã ""Start (or only) date"" ã«å
+¥åããã
+       <li>æéã®çµããã ""End date"" ã«å
+¥åããã
+       <li>çŽå
+åã®å Žåã¯ã""B.C.E"" ããã«ããŠã³ã¡ãã¥ãŒããéžæããŠãã ããã
+   </ul>
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>æ€çŽ¢ã®çµæ</h3>
+æ¥ä»ã«é¢ããç¯å²ã®æå®ã¯ãäŸãã°1899-1911ãšããå Žåã«ããã®æéã®éã®ãããã®æ¥ä»ãã«ãé©åãããŸã<p>
+}
+
+_textchangeprefs_ [l=ja] {ããªãã¡ã¬ã³ã¹ãå€æŽãã}
+
+_texthelppreferences_ [l=ja] {<h2>_textchangeprefs_</h2>
+
+<p>ããŒãžã®å
+é ­ã«ãã<i>preferences</i>ãã¿ã³ãæŒããšãã€ã³ã¿ãŒãã§ãŒã¹ã®æ©èœãå€æŽããããšãã§ããŸãã
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Collection preferences</h3>
+ãµãã³ã¬ã¯ã·ã§ã³ãç¬ç«ããŠæ€çŽ¢ããããäžã€ã®éåã§ããããã«æ€çŽ¢ããããéžæããããšãã§ããŸãã
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Language preferences</h3>
+ã©ã®ã³ã¬ã¯ã·ã§ã³ãæšæºã®è¡šç€ºèšèªããã£ãŠããŸãããèªåã®èŠããç°ãªãèšèªã«å€æŽããããšãå¯èœã§ãã
+ãã®å ŽåãGreenstoreã®ã¢ãŠããããã«çšããŠãããã©ãŠã¶ã®èšèªã³ãŒãäœç³»ã®èš­å®ãå€æŽããããšã«æ³šæããŠãã ããã
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Presentation preferences</h3>
+ã³ã¬ã¯ã·ã§ã³ã«ãã£ãŠã¯ãæšæºçãªè¡šç€ºæ¹æ³ã®å€æŽãã§ããŸãã
+<p>WebããŒãžã®ã³ã¬ã¯ã·ã§ã³ã«ã€ããŠã¯ãGreenstoneã®ããã²ãŒã·ã§ã³ããŒãé ãããšãã§ããŸãã
+ãã®å Žåãä»ã®æ€çŽ¢ãããããã«ã¯ããã©ãŠã¶ã®ããã¯ãã¿ã³ãäœ¿çšããŠãã ããã
+ãã®ãããªã³ã¬ã¯ã·ã§ã³ãäœ¿ãå Žåã¯ãé»å­å³æžé€šã®ã³ã¬ã¯ã·ã§ã³ãWebãã®ãã®ã®ãªã³ã¯ãã¯ãªãã¯ãããšãã«ãGreenstoneã®è­Šåãåºããªãããã«ããããšãã§ããŸãã
+ãŸããé»å­å³æžé€šã®ã³ããŒã§ã¯ãªããå®éã®URLã«çŽæ¥ãç§»åãããã©ãããæç€ºããããšãã§ããŸãã
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Search preferences</h3>
+<p>
+Two pairs of buttons control the kind of text matching in the searches that you make.
+æ€çŽ¢ããªãã¡ã¬ã³ã¹ã®ãã¿ã³ã¯ãæ€çŽ¢ãšããããããã­ã¹ãã®çš®é¡ãã³ã³ãã­ãŒã«ããããšãã§ããŸãã
+""case differences""ã¯å€§æå­ã»å°æå­ã®åèŽæ¡ä»¶ãèš­å®ã§ããŸãã
+""word endings""ã¯èªæ«åœ¢åŒãç¡èŠãããã©ãããèš­å®ã§ããŸãã
+ãã©ã°ã©ãåäœã®æ€çŽ¢ããããããªãå€§ããªæ€çŽ¢æ¡ä»¶å
+¥åããã¯ã¹ãæå®ããããšãã§ããŸããé·ãæ€çŽ¢æ¡ä»¶ãæå®ãããšãæ©ãå€ãã®æã®ãã­ã¹ããæ€çŽ¢ããããšãã§ããŸãã
+<p>
+äŸãã°ã<i>ignore case differences</i> ãš <i>ignore word endings</i>ã®ãã¿ã³ãéžæãããŠããã°ã<p>
+<ul><kbd>African building</kbd></ul>
+ãšããæå­åã¯ã
+<ul><kbd>africa builds</kbd></ul><p>
+ãšåæ§ã«æ±ãããŸãã
+ãªããªãã""African""ã®""A""ã¯""a""ã«ã
+æ«å°Ÿã® ""n"" ãš ""ing"" ã¯åãããããããã§ãã
+
+<p>ãŸãã""advanced"" æ€çŽ¢ã¢ãŒããæå®ã§ããŸãã
+""advanced"æ€çŽ¢ã¢ãŒãã§ã¯ãè«çæŒç®ãAND (&), OR (|), and NOT (!)ãçšããŠè€éãªæ€çŽ¢ãè¡ãªãããšãã§ããŸãã
+æ€çŽ¢å±¥æ­Žæ©èœãå€ããããšãã§ããŸãã
+ããã«ããããããåã®è³ªåãå°ãä¿®æ­£ããŠãŸãè¡ãªãããšãç¹°ãè¿ãæããªããŸãã
+æ€æ»çµæãšããŠæå€§æ°ãç»é¢äžã«è¡šç€ºã§ããæå€§çµææ°ãå€æŽããããšãã§ããŸãã
+}
+
+_texttanumbrowseoptions_ [l=ja] {ãã®ã³ã¬ã¯ã·ã§ã³ããæ
+å ±ãæ¢ãããã®_numbrowseoptions_ ã ãã®æ¹æ³ããããŸãïŒ}
+
+_textsimplehelpheading_ [l=ja] {ã³ã¬ã¯ã·ã§ã³ _collectionname_ ã«ããæ
+å ±ãã©ã®ããã«èŠã€ããã}
+
+_texthelpscope_ [l=ja] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Scope of queries</h3>
+
+<p>
+å€§éšåã³ã¬ã¯ã·ã§ã³ã«ãããŠæ€çŽ¢ã®ããã®ã€ã³ããã¯ã¹ãå©çšã§ããŸãã
+äŸãã°ãèè
+ãã¿ã€ãã«ã®ã€ã³ããã¯ã¹ãæãã¯ãç« ããã©ã°ã©ãã®ã€ã³ããã¯ã¹ããããŸãã
+ããã«å¯Ÿããæç« å
+šäœãžã®æ€çŽ¢ã¯ãã©ã®ã€ã³ããã¯ã¹ãå©çšãããã«é¢ä¿ãªãå®è¡ãããŸãã<p>
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/japanese2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/japanese2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/japanese2.dm	(revision 10506)
@@ -0,0 +1,741 @@
+# this file must be UTF-8 encoded
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+# -- Missing translation: _documents_
+# -- Missing translation: _lastupdate_
+# -- Missing translation: _ago_
+# -- Missing translation: _colnotbuilt_
+
+# -- Missing translation: _textpagetitle_
+# -- Missing translation: _textadmin_
+# -- Missing translation: _textabgs_
+# -- Missing translation: _textgsdocs_
+
+# -- Missing translation: _textimagegli_
+
+# -- Missing translation: _textimagecollector_
+
+# -- Missing translation: _textimagetranslator_
+
+# -- Missing translation: _textimageadmin_
+
+# -- Missing translation: _textimagegogreenstone_
+
+# -- Missing translation: _textimagegodocs_
+
+# -- Missing translation: _textpoem_
+
+# -- Missing translation: _textgreenstone_
+
+# -- Missing translation: _textaboutgreenstone_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: selcolgr
+# -- Missing translation: _httpiconselcolgr_
+# -- Missing translation: _widthselcolgr_
+# -- Missing translation: _heightselcolgr_
+# -- Missing translation: _altselcolgr_
+
+
+# -- Missing translation: cgli
+# -- Missing translation: _httpiconcgliof_
+# -- Missing translation: _httpiconcglion_
+# -- Missing translation: _widthcgli_
+
+# -- Missing translation: ccol
+# -- Missing translation: _httpiconccolof_
+# -- Missing translation: _httpiconccolon_
+# -- Missing translation: _widthccol_
+
+# -- Missing translation: ctrans
+# -- Missing translation: _httpiconctransof_
+# -- Missing translation: _httpiconctranson_
+# -- Missing translation: _widthctrans_
+
+# -- Missing translation: cadmin
+# -- Missing translation: _httpiconcadminof_
+# -- Missing translation: _httpiconcadminon_
+# -- Missing translation: _widthcadmin_
+
+# -- Missing translation: cabgs
+# -- Missing translation: _httpiconcabgsof_
+# -- Missing translation: _httpiconcabgson_
+# -- Missing translation: _widthcabgs_
+
+# -- Missing translation: cgsdoc
+# -- Missing translation: _httpiconcgsdocof_
+# -- Missing translation: _httpiconcgsdocon_
+# -- Missing translation: _widthcgsdoc_
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _text4buts_
+
+# -- Missing translation: _textnocollections_
+
+# -- Missing translation: _text1coll_
+
+# -- Missing translation: _textmorecolls_
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textextlink_
+# -- Missing translation: _textlinknotfound_
+
+# -- Missing translation: _textextlinkcontent_
+
+# -- Missing translation: _textlinknotfoundcontent_
+
+# should have arguments of collection, collectionname and link
+# -- Missing translation: _foundintcontent_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textGSDLtitle_
+
+# -- Missing translation: _textusername_
+# -- Missing translation: _textpassword_
+
+# -- Missing translation: _textmustbelongtogroup_
+
+# -- Missing translation: _textmessageinvalid_
+
+# -- Missing translation: _textmessagefailed_
+
+# -- Missing translation: _textmessagedisabled_
+
+# -- Missing translation: _textmessagepermissiondenied_
+
+# -- Missing translation: _textmessagestalekey_
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textnodocumentation_
+
+# -- Missing translation: _textuserguide_
+# -- Missing translation: _textinstallerguide_
+# -- Missing translation: _textdeveloperguide_
+# -- Missing translation: _textpaperguide_
+# -- Missing translation: _textorganizerguide_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: gsdocsgr
+# -- Missing translation: _httpicongsdocsgr_
+# -- Missing translation: _widthgsdocsgr_
+# -- Missing translation: _heightgsdocsgr_
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textdefaultstructure_
+# -- Missing translation: _textmore_
+# -- Missing translation: _textcollector_
+# -- Missing translation: _textinfo_
+# -- Missing translation: _textsrce_
+# -- Missing translation: _textconf_
+# -- Missing translation: _textbild_
+# -- Missing translation: _textview_
+# -- Missing translation: _textdel_
+# -- Missing translation: _textexpt_
+
+# -- Missing translation: _textdownloadingfiles_
+# -- Missing translation: _textimportingcollection_
+# -- Missing translation: _textbuildingcollection_
+# -- Missing translation: _textcreatingcollection_
+
+# -- Missing translation: _textcollectorblurb_
+
+# -- Missing translation: _textcb1_
+
+# -- Missing translation: _textcb2_
+# -- Missing translation: _textcnc_
+# -- Missing translation: _textwec_
+
+# -- Missing translation: _textcb3_
+
+# -- Missing translation: _textcb4_
+
+# -- Missing translation: _textfsc_
+
+# -- Missing translation: _textwtc_
+# -- Missing translation: _textamd_
+# -- Missing translation: _textetc_
+# -- Missing translation: _textdtc_
+# -- Missing translation: _textetcfcd_
+# -- Missing translation: _textcaec_
+# -- Missing translation: _textnwec_
+# -- Missing translation: _textcianc_
+# -- Missing translation: _texttsosn_
+# -- Missing translation: _textsin_
+# -- Missing translation: _textswts_
+# -- Missing translation: _textatco_
+# -- Missing translation: _textbtc_
+# -- Missing translation: _textpvyh_
+
+# -- Missing translation: _texttfsiw_
+
+# -- Missing translation: _textadab_
+
+# -- Missing translation: _textwyar_
+
+# -- Missing translation: _textcnmbs_
+# -- Missing translation: _texteambs_
+# -- Missing translation: _textpsea_
+# -- Missing translation: _textdocmbs_
+
+# -- Missing translation: _textwcanc_
+
+# -- Missing translation: _texttfc_
+
+# -- Missing translation: _texttctiasp_
+
+# -- Missing translation: _textcea_
+
+# -- Missing translation: _textteas_
+
+# -- Missing translation: _textatc_
+
+# -- Missing translation: _texttiasd_
+
+# -- Missing translation: _textypits_
+
+# -- Missing translation: _srcebadsources_
+
+# -- Missing translation: _textymbyco_
+
+# -- Missing translation: _textbtco_
+# -- Missing translation: _textand_
+# -- Missing translation: _textad_
+
+# -- Missing translation: _texttftysb_
+
+# -- Missing translation: _textis_
+
+# -- Missing translation: _textddd1_
+
+# -- Missing translation: _textddd2_
+
+# -- Missing translation: _textconf1_
+
+# -- Missing translation: _textreset_
+
+# -- Missing translation: _textbild1_
+
+# -- Missing translation: _textbild2_
+
+# -- Missing translation: _textstopbuild_
+
+# -- Missing translation: _textbild3_
+
+# -- Missing translation: _textbuildcancelled_
+
+# -- Missing translation: _textbildcancel1_
+
+# -- Missing translation: _textbsupdate1_
+# -- Missing translation: _textbsupdate2_
+# -- Missing translation: _textseconds_
+# -- Missing translation: _textbildsuc_
+
+# -- Missing translation: _textviewbildsummary_
+
+# -- Missing translation: _textfailmsg11_
+
+# -- Missing translation: _textfailmsg21_
+# -- Missing translation: _textblcont_
+
+# -- Missing translation: _texttryagain_
+
+# -- Missing translation: _textfailmsg31_
+# -- Missing translation: _textfailmsg41_
+# -- Missing translation: _textfailmsg71_
+# -- Missing translation: _textretcoll_
+
+# -- Missing translation: _textdelperm_
+
+# -- Missing translation: _textdelinv_
+
+# -- Missing translation: _textdelsuc_
+
+# -- Missing translation: _textclonefail_
+
+# -- Missing translation: _textcolerr_
+
+# -- Missing translation: _texttmpfail_
+
+# -- Missing translation: _textmkcolfail_
+
+# -- Missing translation: _textnocontent_
+
+# -- Missing translation: _textrestart_
+
+# -- Missing translation: _textreloaderror_
+
+# -- Missing translation: _textexptsuc_
+
+# -- Missing translation: _textexptfail_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_colect
+# -- Missing translation: _httpiconhcolect_
+
+# -- Missing translation: info
+# -- Missing translation: _httpicongcinfoof_
+# -- Missing translation: _httpicongcinfoon_
+# -- Missing translation: _httpiconycinfoof_
+# -- Missing translation: _httpiconycinfoon_
+# -- Missing translation: _httpiconncinfoof_
+
+# -- Missing translation: srce
+# -- Missing translation: _httpicongcsrceof_
+# -- Missing translation: _httpicongcsrceon_
+# -- Missing translation: _httpiconycsrceof_
+# -- Missing translation: _httpiconycsrceon_
+# -- Missing translation: _httpiconncsrceof_
+
+# -- Missing translation: conf
+# -- Missing translation: _httpicongcconfof_
+# -- Missing translation: _httpicongcconfon_
+# -- Missing translation: _httpiconycconfof_
+# -- Missing translation: _httpiconycconfon_
+# -- Missing translation: _httpiconncconfof_
+
+# -- Missing translation: bild
+# -- Missing translation: _httpicongcbildof_
+# -- Missing translation: _httpicongcbildon_
+# -- Missing translation: _httpiconycbildof_
+# -- Missing translation: _httpiconycbildon_
+# -- Missing translation: _httpiconncbildof_
+
+# -- Missing translation: view
+# -- Missing translation: _httpicongcviewof_
+# -- Missing translation: _httpicongcviewon_
+# -- Missing translation: _httpiconycviewof_
+# -- Missing translation: _httpiconycviewon_
+# -- Missing translation: _httpiconncviewof_
+
+# -- Missing translation: del
+# -- Missing translation: _httpicongcdelof_
+# -- Missing translation: _httpicongcdelon_
+
+# -- Missing translation: expt
+# -- Missing translation: _httpicongcexptof_
+# -- Missing translation: _httpicongcexpton_
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+# -- Missing translation: _textgreenstone1_
+
+# -- Missing translation: _textgreenstone2_
+
+# -- Missing translation: _textplatformtitle_
+# -- Missing translation: _textgreenstone3_
+
+# -- Missing translation: _textgreenstone4_
+
+# -- Missing translation: _textcustomisationtitle_
+# -- Missing translation: _textgreenstone5_
+
+# -- Missing translation: _textdocumentationtitle_
+# -- Missing translation: _textdocuments_
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+# -- Missing translation: _textmailinglisttitle_
+# -- Missing translation: _textmailinglist_
+
+# -- Missing translation: _textbugstitle_
+# -- Missing translation: _textreport_
+
+# -- Missing translation: _textgs3title_
+# -- Missing translation: _textgs3_
+
+# -- Missing translation: _textcreditstitle_
+
+# -- Missing translation: _textwhoswho_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+# -- Missing translation: abgsgr
+# -- Missing translation: _httpiconabgsgr_
+# -- Missing translation: _widthabgsgr_
+# -- Missing translation: _heightabgsgr_
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textlocu_
+# -- Missing translation: _textuser_
+# -- Missing translation: _textas_
+# -- Missing translation: _textgroups_
+# -- Missing translation: _textcomment_
+# -- Missing translation: _textadduser_
+# -- Missing translation: _textedituser_
+# -- Missing translation: _textdeleteuser_
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+# -- Missing translation: _textedituser_
+# -- Missing translation: _textadduser_
+
+# -- Missing translation: _textaboutusername_
+
+# -- Missing translation: _textaboutpassword_
+
+# -- Missing translation: _textoldpass_
+# -- Missing translation: _textenabled_
+# -- Missing translation: _textdisabled_
+
+# -- Missing translation: _textaboutgroups_
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textdeleteuser_
+# -- Missing translation: _textremwarn_
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textchangepw_
+# -- Missing translation: _textoldpw_
+# -- Missing translation: _textnewpw_
+# -- Missing translation: _textretype_
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textsuccess_
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textinvalidusername_
+# -- Missing translation: _textinvalidpassword_
+# -- Missing translation: _textemptypassword_
+# -- Missing translation: _textuserexists_
+
+# -- Missing translation: _textusernameempty_
+# -- Missing translation: _textpasswordempty_
+# -- Missing translation: _textnewpass1empty_
+# -- Missing translation: _textnewpassmismatch_
+# -- Missing translation: _textnewinvalidpassword_
+# -- Missing translation: _textfailed_
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+# -- Missing translation: _textversion_
+# -- Missing translation: _textframebrowser_
+# -- Missing translation: _textusermanage_
+# -- Missing translation: _textlistusers_
+# -- Missing translation: _textaddusers_
+# -- Missing translation: _textchangepasswd_
+# -- Missing translation: _textinfo_
+# -- Missing translation: _textgeneral_
+# -- Missing translation: _textarguments_
+# -- Missing translation: _textactions_
+# -- Missing translation: _textbrowsers_
+# -- Missing translation: _textprotocols_
+# -- Missing translation: _textconfigfiles_
+# -- Missing translation: _textlogs_
+# -- Missing translation: _textusagelog_
+# -- Missing translation: _textinitlog_
+# -- Missing translation: _texterrorlog_
+# -- Missing translation: _textadminhome_
+# -- Missing translation: _textreturnhome_
+# -- Missing translation: _titlewelcome_
+# -- Missing translation: _textmaas_
+# -- Missing translation: _textvol_
+# -- Missing translation: _textcmuc_
+# -- Missing translation: _textati_
+
+# -- Missing translation: _texttsaa_
+
+# -- Missing translation: _textcolstat_
+
+# -- Missing translation: _textcwoa_
+
+# -- Missing translation: _textcafi_
+# -- Missing translation: _textcctv_
+# -- Missing translation: _textsubc_
+# -- Missing translation: _texteom_
+# -- Missing translation: _textftum_
+# -- Missing translation: _textmus_
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textbsummary_
+# -- Missing translation: _textflog_
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=ja] {ã°ãªãŒã³ã¹ããŒã³ã®å©çšæ§}
+
+_textwhy_ [l=ja] {è²Žæ¹ãèŠãŠããWeb PageãèŠã€ãããšããããšãç¥ãããããããã®ã¬ããŒãããéããã ãã}
+_textextraforform_ [l=ja] {Formãã«ã¯èšå
+¥ããªããŠãçµæ§ã§ã}
+_textprivacybasic_ [l=ja] {<p>ãã®ã¬ããŒãã¯ the Greenstone web pageãšããã«é¢é£ããæè¡ã«ã€ããŠè¿°ã¹ãŠãããŸãã}
+_textstillsend_ [l=ja] {ã¬ããŒãããéãã«ãªãããã§ãã}
+
+_texterror_ [l=ja] {ãšã©ãŒ}
+_textyes_ [l=ja] {ã¯ã}
+_textno_ [l=ja] {ããã}
+_textclosewindow_ [l=ja] {Windowããéãã}
+_textabout_ [l=ja] {ã«ã€ããŠ}
+_textprivacy_ [l=ja] {èªè²»åºç}
+_textsend_ [l=ja] {éã}
+_textdontsend_ [l=ja] {éããªã}
+_textoptionally_ [l=ja] {ãªãã·ã§ã³}
+
+_textunderdev_ [l=ja] {è©³çŽ°ãªãã¬ãã¥ãŒã¯æçµããŒãžã§ã³ã«ãã£ãŠæäŸãããŸã}
+
+_textviewdetails_ [l=ja] {ã¬ããŒããè©³çŽ°ã«èŠãŠãã ãã}
+_textmoredetails_ [l=ja] {çŽ°ããè©³çŽ°}
+_texttrackreport_ [l=ja] {ãã®ã¬ããŒããè¿œè·¡ãã}
+_textcharacterise_ [l=ja] {ã©ããªåé¡ã§ãã}
+_textseverity_ [l=ja] {åé¡ã®çšåºŠ}
+ 
+_textbadrender_ [l=ja] {ããŒãžããããã}
+_textcontenterror_ [l=ja] {ã³ã³ãã³ããšã©ãŒ}
+_textstrangebehaviour_ [l=ja] {ããããªæåã§ã}
+_textunexpected_ [l=ja] {äºæããªãäœããèµ·ãããŸãã}
+_textfunctionality_ [l=ja] {äœ¿çšãé£ãã}
+_textother_ [l=ja] {ãã®ä»}
+
+_textcritical_ [l=ja] {éå€§}
+_textmajor_ [l=ja] {å³ãã}
+_textmedium_ [l=ja] {ããã€ãŒã¢ã }
+_textminor_ [l=ja] {ãã€ããŒ}
+_texttrivial_ [l=ja] {ããããªåé¡}
+
+_textwhatdoing_ [l=ja] {ãªã«ããªãããããšããŸãããïŒ}
+_textwhatexpected_ [l=ja] {ã©ã®ãããªããšãããããšæãããŸãããïŒ}
+_textwhathappened_ [l=ja] {å®éã«ã¯äœãããããŸãããïŒ}
+
+_cannotfindcgierror_ [l=ja] {<h2>ãã¿ãŸããã!</h2>ãâComplainâãã¿ã³ã®ããã®ãµãŒããŒãã­ã°ã©ãã¯èŠã€ããããŸãã}
+
+_textusabbanner_ [l=ja] {Greenstoneã®koru-stykeã®ãããŒ}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+# -- Missing translation: _textgli_
+# -- Missing translation: _textglihelp_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+# -- Missing translation: gligr
+# -- Missing translation: _httpicongligr_
+# -- Missing translation: _widthgligr_
+# -- Missing translation: _heightgligr_
Index: /tags/gsdl-2_61-distribution/gsdl/macros/kannada.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/kannada.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/kannada.dm	(revision 10506)
@@ -0,0 +1,1799 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Kannada Language text and icon macros (translated from english.dm
+# 9 March 2000)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textperiodicals_
+# -- Missing translation: _textsource_
+# -- Missing translation: _textdate_
+# -- Missing translation: _textnumpages_
+
+# -- Missing translation: _textsignin_
+
+_textdefaultcontent_ [l=kn] {à²šà³à²µà³
+à²ªà³à²°à²¯à²€à³à²šà²¿à²žà²¿à²Š
+à²ªà³à² à²žà²¿à²à²²à²¿à²²à³à²².
+à²à²¿.à²à²žà³.à²¡à²¿.à²à²²à³.à²à³
+à²¹à²¿à²à²€à²¿à²°à³à²à²²à³
+à²šà²¿à²®à³à²®
+à²¬à³à²°à³à²žà²°à³ à²š
+à²¹à²¿à²à²Šà³ à²à³à²à²¡à²¿à²¯à²šà³à²šà²Ÿ
+à²à²²à²¿à²
+à²¥à²µà²Ÿ à²®à³à²²à²¿à²š
+à²®à³à²à²ªà³à² à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¿.}
+
+_textdefaulttitle_ [l=kn] {à²à²¿.à²à²žà³.à²¡à²¿.à²à²²à³}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=kn] {à²à²žà²à²à³à²°à²¹à²£à³à²¯
+à²²à³à²²à²¿ _about:numdocs_ à²Šà²Ÿà²à²²à³à²à²³à²¿à²µ
+à³. à²à²Šà²°à²žà²à²à³à²°à²¹à²£à³
+à²®à²Ÿà²¡à²¿à²Šà³à²Šà³ _about:builddate_ à²Šà²¿à²šà²à²³
+ à²¹à²¿à²à²Šà³.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+# -- Missing translation: _collectorextra_
+
+_textimagecollection_ [l=kn] {}
+_textimageabout_ [l=kn] {à²ªà³à²à²Š à²¬à²à³à²à³}
+_textimagehome_ [l=kn] {à²®à³à²à²ªà³à²}
+_textimagehelp_ [l=kn] {à²žà²¹à²Ÿà²¯ à²ªà³à²}
+_textimagepref_ [l=kn] {à²à²¯à³à²à³à²à²³ à²ªà³à²}
+_textimagegreenstone_ [l=kn] {à²à³à²°à³à²šà³à²žà³à²à³à²šà³
+à²¡à²¿à²à²¿à²à²²à³à²²à³à²¬à³à²°à²°à²¿
+à²€à²€à³à²°à²Ÿà²à²¶}
+# -- Missing translation: _textimageusab_
+
+_textimagesearch_ [l=kn] {à²šà²¿à²¶à³à²à²¿à²€ à²ªà²Šà²à²³à²š
+à³à²šà³à²
+à²šà³à²¶à³à²§à²¿à²žà²¿.}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=kn] {à²µà²°à³à²£à²®à²Ÿà²²à³à²¯à²ªà²à³à²
+à²¿à²¯à²à²€à³à²¶à³à²°à³à²·à²¿à²à³à²à²³à²šà³
+à²šà³à²¬à³à²°à³à²à³ à²®à²Ÿà²¡à²¿.}
+_textimageCreator_ [l=kn] {à²µà²°à³à²£à²®à²Ÿà²²à³à²¯à²ªà²à³à²
+à²¿à²¯à²à²€à³à²²à³à²à²à²°à²šà³à²šà³ à²¬à³à²°
+à³à²à³à²®à²Ÿà²¡à²¿.}
+_textimageSubject_ [l=kn] {à²µà²¿à²·à²¯à²à²³à²šà³à²šà³ à²¬à³à²°
+à³à²à³à²®à²Ÿà²¡à²¿.}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=kn] {à²Šà²¿à²šà²Ÿà²à²à²à²³à²šà³à²šà³
+à²¬à³à²°à³à²à³ à²®à²Ÿà²¡à²¿.}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=kn] {à²à²¡à²€à²à²³à²à²€à³
+à²¬à³à²°à³à²à³ à²®à²Ÿà²¡à²¿.}
+# -- Missing translation: _textimageLanguage_
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=kn] {à²žà²à²žà³à²¥à³à²à²³à³à²šà³à²šà³
+à²¬à³à²°à³à²žà³ à²®à²Ÿà²¡à²¿.}
+# -- Missing translation: _textimageKeyword_
+_textimageHowto_ [l=kn] {à²¹à³à²à³à²¬à²à³à²à²³à²šà³à²šà³ 
+à²¬à³à²°à³à²à³à²®à²Ÿà²¡à²¿.}
+_textimageList_ [l=kn] {à²Šà²Ÿà²à²²à³à²à²³à²ªà²à³à²à²¿à²¯
+à²šà³à²šà³ à²¬à³à²°à³à²à³à²®à²Ÿà²¡à²¿.}
+_textimageSeries_ [l=kn] {à²žà²à²à²¿à²à³à²à²³à²šà³à²šà³
+à²¬à³à²°à³à²à³ à²®à²Ÿà²¡à²¿.}
+# -- Missing translation: _textimageTo_
+# -- Missing translation: _textimageFrom_
+_textimageTopic_ [l=kn] {à²µà²¿à²¶à³à²·à²ªà³à²°à²à²°à²£à²à²³
+à²šà³à²šà³à²¬à³à²°à³à²à³ à²®à²Ÿà²¡à²¿.}
+_textimageBrowse_ [l=kn] {à²¬à³à²°à³à²à³}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=kn] {à²µà²°à³à²£à²®à²Ÿà²²à³à²¯à²ªà²à³à²
+à²¿à²¯à²à²€à³à²à²šà²°à²šà³à²šà³ à²¬à³à²°à³à²
+à³à²®à²Ÿà²¡à²¿.}
+# -- Missing translation: _textimageAcronym_
+# -- Missing translation: _textimagePhrase_
+# -- Missing translation: _textimageArtist_
+# -- Missing translation: _textimageVolume_
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=kn] {à²¶à³à²°à³à²·à²¿à²à³ A-Z}
+_texticontabCreatorgreen_ [l=kn] {à²²à³à²à²à²°à³ A-Z}
+_texticontabSubjectgreen_ [l=kn] {à²µà²¿à²·à²¯}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=kn] {à²Šà²¿à²šà²Ÿà²à²}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+# -- Missing translation: _texticontabSourcegreen_
+# -- Missing translation: _texticontabLanguagegreen_
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=kn] {à²žà²à²žà³à²¥à³à²à²³à³}
+# -- Missing translation: _texticontabKeywordgreen_
+_texticontabhowgreen_ [l=kn] {à²¹à³à²à³?}
+_texticontabseriesgreen_ [l=kn] {à²žà²°à²£à²¿}
+_texticontablistgreen_ [l=kn] {à²ªà²à³à²à²¿}
+# -- Missing translation: _texticontabtogreen_
+# -- Missing translation: _texticontabfromgreen_
+_texticontabtopicgreen_ [l=kn] {à²ªà³à²°à²à²°à²£à²à²³à³}
+_texticontabbrwsegreen_ [l=kn] {à²¬à³à²°à³à²à³}
+# -- Missing translation: _texticontabCollagegreen_
+# -- Missing translation: _texticontabbrowsgreen_
+_texticontabPeoplegreen_ [l=kn] {à²à²šà²°à³ A-Z}
+# -- Missing translation: _texticontabAcronymgreen_
+# -- Missing translation: _texticontabPhrasegreen_
+# -- Missing translation: _texticontabArtistgreen_
+# -- Missing translation: _texticontabVolumegreen_
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=kn] {à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà³
+à²µà²¿à²à³à²·à³à²žà²¿}
+_texticonclosedbook_ [l=kn] {à²Šà²Ÿà²à²²à³ à²€à³à²à³à²Šà³
+à²ªà²°à²¿à²µà²¿à²¡à²¿à²¯à²šà³à²šà³à²µà²¿à²à³
+à²·à³à²žà²¿}
+_texticonnext_ [l=kn] {à²®à³à²à²Šà²¿à²šà²­à²Ÿà²à²à³à²à³}
+_texticonprev_ [l=kn] {à²¹à²¿à²à²Šà²¿à²š à²­à²Ÿà²à²à³à²à³}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=kn] {à²®à²¿à²¡à²¿ à²Šà²Ÿà²à²²à³à²à²³à²šà³à²š
+à³à²µà²¿à²à³à²·à³à²žà²¿}
+_texticonmsword_ [l=kn] {à²à².à²à²žà³. à²µà²°à³à²¡ à²Šà²Ÿà²à²²
+à³à²à²³à²šà³à²šà³à²µà²¿à²à³à²·à³à²žà²¿}
+# -- Missing translation: _texticonmp3_
+_texticonpdf_ [l=kn] {à²ªà²¿.à²¡à²¿.à²à²ªà³ à²Šà²Ÿà²à²²à³à²à²³
+à²šà³à²šà³à²µà²¿à²à³à²·à³à²žà²¿}
+_texticonps_ [l=kn] {à²ªà²¿.à²à²žà³. à²Šà²Ÿà²à²²à³à²à²³à²šà³
+à²šà³à²µà²¿à²à³à²·à³à²žà²¿}
+# -- Missing translation: _texticonppt_
+_texticonrtf_ [l=kn] {à²à²°à³.à²à²¿.à²à²ªà³ à²Šà²Ÿà²à²²à³à²
+à²³à²šà³à²šà³à²µà²¿à²à³à²·à³à²žà²¿}
+# -- Missing translation: _texticonxls_
+
+_page_ [l=kn] {à²ªà³à²}
+_pages_ [l=kn] {à²ªà³à²à²à²³à³}
+_of_ [l=kn] {à²à²¡à³à²à³ }
+_vol_ [l=kn] {à²žà²à²ªà³à²}
+_num_ [l=kn] {à²šà²à²¬à²°à³}
+
+_textmonth00_ [l=kn] {}
+_textmonth01_ [l=kn] {à²à²šà²µà²°à²¿}
+_textmonth02_ [l=kn] {à²«à³à²¬à³à²°à²µà²°à²¿}
+_textmonth03_ [l=kn] {à²®à²Ÿà²°à³à²}
+_textmonth04_ [l=kn] {à²à²ªà³à²°à²¿à²²à³}
+_textmonth05_ [l=kn] {à²®à³}
+_textmonth06_ [l=kn] {à²à³à²šà³}
+_textmonth07_ [l=kn] {à²à³à²²à³}
+_textmonth08_ [l=kn] {à²à²à²žà³à²à³}
+_textmonth09_ [l=kn] {à²žà³à²ªà³à²à²à²¬à²°à³}
+_textmonth10_ [l=kn] {à²
+à²à³à²à³à²¬à²°à³}
+_textmonth11_ [l=kn] {à²šà²µà²à²¬à²°à³}
+_textmonth12_ [l=kn] {à²¡à²¿à²žà³à²à²¬à²°à³}
+
+# -- Missing translation: _textdocument_
+# -- Missing translation: _textsection_
+# -- Missing translation: _textparagraph_
+
+# -- Missing translation: _magazines_
+
+# -- Missing translation: _nzdlpagefooter_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: chome
+# -- Missing translation: _httpiconchomeof_
+# -- Missing translation: _httpiconchomeon_
+
+# -- Missing translation: chelp
+# -- Missing translation: _httpiconchelpof_
+# -- Missing translation: _httpiconchelpon_
+
+# -- Missing translation: cpref
+# -- Missing translation: _httpiconcprefof_
+# -- Missing translation: _httpiconcprefon_
+
+# -- Missing translation: cusab
+# -- Missing translation: _httpiconcusabof_
+# -- Missing translation: _httpiconcusabon_
+
+
+# -- Missing translation: tsrch
+# -- Missing translation: _httpicontsrchgr_
+# -- Missing translation: _httpicontsrchof_
+# -- Missing translation: _httpicontsrchon_
+# -- Missing translation: _widthtsrchx_
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: ttitl
+# -- Missing translation: _httpiconttitlegr_
+# -- Missing translation: _httpiconttitleof_
+# -- Missing translation: _httpiconttitleon_
+# -- Missing translation: _widthttitlex_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: tauth
+# -- Missing translation: _httpicontcreatgr_
+# -- Missing translation: _httpicontcreatof_
+# -- Missing translation: _httpicontcreaton_
+# -- Missing translation: _widthtcreatx_
+
+# -- Missing translation: tsubj
+# -- Missing translation: _httpicontsubjgr_
+# -- Missing translation: _httpicontsubjon_
+# -- Missing translation: _httpicontsubjof_
+# -- Missing translation: _widthtsubjx_
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+# -- Missing translation: tdate
+# -- Missing translation: _httpicontdategr_
+# -- Missing translation: _httpicontdateof_
+# -- Missing translation: _httpicontdateon_
+# -- Missing translation: _widthtdatex_
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: tsrc
+# -- Missing translation: _httpicontsrcgr_
+# -- Missing translation: _httpicontsrcof_
+# -- Missing translation: _httpicontsrcon_
+# -- Missing translation: _widthtsrcx_
+
+# -- Missing translation: tlang
+# -- Missing translation: _httpicontlanggr_
+# -- Missing translation: _httpicontlangon_
+# -- Missing translation: _httpicontlangof_
+# -- Missing translation: _widthtlangx_
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+# -- Missing translation: tser
+# -- Missing translation: _httpicontsergr_
+# -- Missing translation: _httpicontserof_
+# -- Missing translation: _httpicontseron_
+# -- Missing translation: _widthtserx_
+
+# -- Missing translation: tto
+# -- Missing translation: _httpiconttogr_
+# -- Missing translation: _httpiconttoon_
+# -- Missing translation: _httpiconttoof_
+# -- Missing translation: _widthttox_
+
+# -- Missing translation: tfrom
+# -- Missing translation: _httpicontfromgr_
+# -- Missing translation: _httpicontfromon_
+# -- Missing translation: _httpicontfromof_
+# -- Missing translation: _widthtfromx_
+
+# -- Missing translation: torg
+# -- Missing translation: _httpicontorggr_
+# -- Missing translation: _httpicontorgon_
+# -- Missing translation: _httpicontorgof_
+# -- Missing translation: _widthtorgx_
+
+# -- Missing translation: thow
+# -- Missing translation: _httpiconthowgr_
+# -- Missing translation: _httpiconthowon_
+# -- Missing translation: _httpiconthowof_
+# -- Missing translation: _widththowx_
+
+# -- Missing translation: ttopic
+# -- Missing translation: _httpiconttopicgr_
+# -- Missing translation: _httpiconttopicon_
+# -- Missing translation: _httpiconttopicof_
+# -- Missing translation: _widthttopicx_
+
+# -- Missing translation: tbrwse
+# -- Missing translation: _httpicontbrwsegr_
+# -- Missing translation: _httpicontbrwseon_
+# -- Missing translation: _httpicontbrwseof_
+# -- Missing translation: _widthtbrwsex_
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+# -- Missing translation: tpeop
+# -- Missing translation: _httpicontpeopgr_
+# -- Missing translation: _httpicontpeopof_
+# -- Missing translation: _httpicontpeopon_
+# -- Missing translation: _widthtpeopx_
+
+# -- Missing translation: tacro
+# -- Missing translation: _httpicontacrogr_
+# -- Missing translation: _httpicontacroof_
+# -- Missing translation: _httpicontacroon_
+# -- Missing translation: _widthtacrox_
+
+# -- Missing translation: tphrse
+# -- Missing translation: _httpicontphrsegr_
+# -- Missing translation: _httpicontphrseof_
+# -- Missing translation: _httpicontphrseon_
+# -- Missing translation: _widthtphrsex_
+
+# -- Missing translation: tartst
+# -- Missing translation: _httpicontartstgr_
+# -- Missing translation: _httpicontartstof_
+# -- Missing translation: _httpicontartston_
+# -- Missing translation: _widthtartstx_
+
+# -- Missing translation: tkw
+# -- Missing translation: _httpicontkwgr_
+# -- Missing translation: _httpicontkwof_
+# -- Missing translation: _httpicontkwon_
+# -- Missing translation: _widthtkwx_
+
+# -- Missing translation: tvol
+# -- Missing translation: _httpicontvolgr_
+# -- Missing translation: _httpicontvolof_
+# -- Missing translation: _httpicontvolon_
+# -- Missing translation: _widthtvolx_
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+# -- Missing translation: h_help
+# -- Missing translation: _httpiconhhelp_
+# -- Missing translation: _widthhhelp_
+# -- Missing translation: _heighthhelp_
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=kn] {à² à²žà²à²à³à²°à²¹à²£à³à²¯
+à²¬à²à³à²à³}
+
+_textsubcols1_ [l=kn] {<p>à²žà²à²ªà³à²°à³à²£à²žà²à²à³
+à²°à²¹à²£à³à²¯à³ _1_ à²à²ª à²žà²à²à³à²°à²¹à²£
+à³à²¯à²¿à²à²Šà²à³à²¡à²¿à²Šà³: <blockquote>}
+
+_textsubcols2_ [l=kn] {</blockquote>
+à²šà³à²µà³ à²¬à³à²à²Šà²°à³à²à²¯à³à²à³à²¯
+à²ªà³à²à²Šà²²à³à²²à²¿à²°à³à²µà²¯à²Ÿà²µ à²à²ª 
+à²žà²à²à³à²°à²¹à²£à³à²¯à²šà³à²šà²Ÿà²Šà²°à³
+à²ªà²°à³à²à³à²·à²¿à²žà²¬à²¹à³à²Šà³}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_about
+# -- Missing translation: _httpiconhabout_
+# -- Missing translation: _widthhabout_
+# -- Missing translation: _heighthabout_
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=kn] {à²¶à³à²°à³à²·à²¿à²à³à²à²³à³ A-Z}
+_texticonhcreat_ [l=kn] {à²²à³à²à²à²°à³ A-Z}
+_texticonhsubj_ [l=kn] {à²µà²¿à²·à²¯à²à²³à³}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=kn] {à²Šà²¿à²šà²Ÿà²à²}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=kn] {à²à²¡à²€à²à²³ à²¹à³à²žà²°à³}
+_texticonhlang_ [l=kn] {à²¬à²Ÿà²·à³à²à²³à³}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=kn] {à²à³}
+_texticonhfrom_ [l=kn] {à²¯à²¿à²à²Š}
+_texticonhser_ [l=kn] {à²žà²°à²£à²¿}
+_texticonhhow_ [l=kn] {à²¹à³à²à³?}
+_texticonhorg_ [l=kn] {à²žà²à²žà³à²¥à³à²à²³à³}
+_texticonhbrwse_ [l=kn] {à²¬à³à²°à³à²à³}
+# -- Missing translation: _texticonhbrows_
+_texticonhpeople_ [l=kn] {à²à²šà²°à³ A-Z}
+_texticonhacronym_ [l=kn] {à²žà²à²à³à²·à³à²ªà²à²³à³}
+_texticonhphrases_ [l=kn] {à²ªà²Šà²žà²®à³à²à³à²à²¯à²à²³à³}
+_texticonhartist_ [l=kn] {à²à²²à²Ÿà²µà²¿à²Šà²°à³}
+# -- Missing translation: _texticonhkw_
+# -- Missing translation: _texticonhvol_
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=kn] {à²à³à²°à²à²¥à²²à²¯à²Š à²
+à²­à²Ÿà²à²µà²šà³à²šà³à²®à³à²à³à²à²¿}
+_texticonclosedbookshelf_ [l=kn] {à²à³à²°à²à²¥à²²à²¯à²Š à²
+à²­à²Ÿà²à²µà²šà³à²šà³à²€à³à²°à³à²Šà³
+à²ªà²°à²¿à²µà²¿à²¡à²¿à²¯à²šà³à²šà³à²µà²¿à²
+à³à²·à³à²žà²¿}
+_texticonopenbook_ [l=kn] {à²à²ªà³à²žà³à²€à²à²µà²šà³à²šà³
+à²®à³à²à³à²à²¿}
+_texticonclosedfolder_ [l=kn] {à² à²ªà³à²²à³à²¡à²°à³à²šà³à²šà³ 
+à²€à³à²à³à²Šà³à²
+à²Šà²° à²ªà²°à²¿à²µà²¿à²¡à²¿à²¯
+à²šà³à²šà³à²µà²¿à²à³à²·à³à²žà²¿}
+_texticonclosedfolder2_ [l=kn] {à²žà²¹à²µà²¿à²­à²Ÿà²à²µà²šà³à²šà³
+à²€à³à²à³à²¯à²¿à²°à²¿: }
+_texticonopenfolder_ [l=kn] {à² à²ªà³à²²à³à²¡à²°à³à²šà³à²šà³ 
+à²®à³à²à³à²à²¿}
+_texticonopenfolder2_ [l=kn] {à²žà²¹à²µà²¿à²­à²Ÿà²à²µà²šà³à²šà³
+à²®à³à²à³à²à²¿: }
+_texticonsmalltext_ [l=kn] {à² à²­à²Ÿà²à²Šà²ªà² à³à²¯à²µà²šà³
+à²šà³ à²µà²¿à²à³à²·à³à²žà²¿}
+_texticonsmalltext2_ [l=kn] {à²ªà² à³à²¯à²µà²šà³à²šà³ à²µà²¿à²
+à³à²·à³à²žà²¿: }
+_texticonpointer_ [l=kn] {à²ªà³à²°à²à²²à²¿à²€ à²­à²Ÿà²}
+_texticondetach_ [l=kn] {à² à²ªà³à²à²µà²šà³à²šà³à²¹à³à²ž
+à²à²¿à²à²à²¿à²¯à²²à³à²²à²¿à²€à³à²à³à²¯à²¿à²°à²¿}
+_texticonhighlight_ [l=kn] {à²
+à²šà³à²¶à³à²§à²¿à²žà²¿à²Šà²ªà²Šà²à²³
+à²šà³à²šà³à²¹à³à²²à³à²à³ à²®à²Ÿà²¡à²¿}
+_texticonnohighlight_ [l=kn] {à²
+à²šà³à²¶à³à²§à²¿à²žà²¿à²Š
+à²ªà²Šà²à²³à²¿à²à³à²¹à³à²²à³à²à³ à²¬à³à²¡}
+_texticoncontracttoc_ [l=kn] {à²ªà²°à²¿à²µà²¿à²¡à²¿à²¯à²šà³à²šà³
+à²šà²Ÿà²¶à²ªà²¡à²¿à²žà³}
+_texticonexpandtoc_ [l=kn] {à²ªà²°à²¿à²µà²¿à²¡à²¿à²¯à²šà³à²šà³
+à²µà²¿à²žà³à²€à²°à²¿à²žà³}
+_texticonexpandtext_ [l=kn] {à²ªà² à³à²¯à²µà²šà³à²šà³à²ªà³à²°à²Š
+à²°à³à²¶à²¿à²žà³}
+_texticoncontracttext_ [l=kn] {à²ªà² à³à²¯à²µà²šà³à²šà³à²ªà³à²°à²
+à²²à²¿à²€à²µà²Ÿà²à²¿à²à²¯à³à²à³à²®à²Ÿà²¡à²¿à²
+à³à²à²¡ à²­à²Ÿà²à²à³à²à³à²®à²Ÿà²€à³à²° à²€à³
+à²°à²¿à²žà³}
+_texticonwarning_ [l=kn] {<b>à²à²à³à²à²°à²¿à²à³: </b>}
+_texticoncont_ [l=kn] {à²®à³à²à²Šà³à²µà²°à³à²žà³?}
+
+_textltwarning_ [l=kn] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_ à²à²²à³à²²à²¿à²šà²ªà² à³à²¯à²µà²š
+à³à²šà³à²µà²¿à²žà³à²€à²°à²¿à²žà²¿à²Šà²°à³
+à²¹à³à²à³à²à³ à²®à²Ÿà²¹à²¿à²€à²¿à²šà²¿à²®à³à²®
+à²¬à³à²°à³à²žà²°à³à²šà²²à³à²²à²¿à²ªà³à²°à²Šà²°
+à³à²¶à²¿à²žà²²à³à²žà²¿à²à³à²€à³à²€à²Šà³ _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=kn] {à² à²ªà³à²à²à³à²à³à²¹à³à²à²¿}
+_textintro_ [l=kn] {<i>(à²ªà²°à²¿à²à²Ÿà²¯à²€à³à²®à²Ÿà²
+à²ªà² à³à²¯)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_title
+# -- Missing translation: _httpiconhtitle_
+# -- Missing translation: _widthhtitle_
+# -- Missing translation: _heighthtitle_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_auth
+# -- Missing translation: _httpiconhcreat_
+# -- Missing translation: _widthhcreat_
+# -- Missing translation: _heighthcreat_
+
+# -- Missing translation: h_subj
+# -- Missing translation: _httpiconhsubj_
+# -- Missing translation: _widthhsubj_
+# -- Missing translation: _heighthsubj_
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+# -- Missing translation: h_date
+# -- Missing translation: _httpiconhdate_
+# -- Missing translation: _widthhdate_
+# -- Missing translation: _heighthdate_
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_src
+# -- Missing translation: _httpiconhsrc_
+# -- Missing translation: _widthhsrc_
+# -- Missing translation: _heighthsrc_
+
+# -- Missing translation: h_lang
+# -- Missing translation: _httpiconhlang_
+# -- Missing translation: _widthhlang_
+# -- Missing translation: _heighthlang_
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+# -- Missing translation: h_to
+# -- Missing translation: _httpiconhto_
+# -- Missing translation: _widthhto_
+# -- Missing translation: _heighthto_
+
+# -- Missing translation: h_from
+# -- Missing translation: _httpiconhfrom_
+# -- Missing translation: _widthhfrom_
+# -- Missing translation: _heighthfrom_
+
+# -- Missing translation: h_ser
+# -- Missing translation: _httpiconhser_
+# -- Missing translation: _widthhser_
+# -- Missing translation: _heighthser_
+
+# -- Missing translation: h_how
+# -- Missing translation: _httpiconhhow_
+# -- Missing translation: _widthhhow_
+# -- Missing translation: _heighthhow_
+
+# -- Missing translation: h_topic
+# -- Missing translation: _httpiconhtopic_
+# -- Missing translation: _widthhtopic_
+# -- Missing translation: _heighthtopic_
+
+# -- Missing translation: h_org
+# -- Missing translation: _httpiconhorg_
+# -- Missing translation: _widthhorg_
+# -- Missing translation: _heighthorg_
+
+# -- Missing translation: h_brwse
+# -- Missing translation: _httpiconhbrwse_
+# -- Missing translation: _widthhbrwse_
+# -- Missing translation: _heighthbrwse_
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+# -- Missing translation: h_people
+# -- Missing translation: _httpiconhpeople_
+# -- Missing translation: _widthhpeople_
+# -- Missing translation: _heighthpeople_
+
+# -- Missing translation: h_acro
+# -- Missing translation: _httpiconhacronym_
+# -- Missing translation: _widthhacronym_
+# -- Missing translation: _heighthacronym_
+
+# -- Missing translation: h_phrse
+# -- Missing translation: _httpiconhphrse_
+# -- Missing translation: _widthhphrse_
+# -- Missing translation: _heighthphrse_
+
+# -- Missing translation: h_artist
+# -- Missing translation: _httpiconhartist_
+# -- Missing translation: _widthhartist_
+# -- Missing translation: _heighthartist_
+
+# -- Missing translation: h_kw
+# -- Missing translation: _httpiconhkw_
+# -- Missing translation: _widthhkw_
+# -- Missing translation: _heighthkw_
+
+# -- Missing translation: h_vol
+# -- Missing translation: _httpiconhvol_
+# -- Missing translation: _widthhvol_
+# -- Missing translation: _heighthvol_
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+# -- Missing translation: cont
+# -- Missing translation: _httpiconcontoff_
+# -- Missing translation: _httpiconconton_
+
+# -- Missing translation: eallt
+# -- Missing translation: _httpiconealltof_
+# -- Missing translation: _httpiconeallton_
+
+# -- Missing translation: econc
+# -- Missing translation: _httpiconeconcof_
+# -- Missing translation: _httpiconeconcon_
+
+# -- Missing translation: edtch
+# -- Missing translation: _httpiconedtchof_
+# -- Missing translation: _httpiconedtchon_
+
+# -- Missing translation: eexpc
+# -- Missing translation: _httpiconeexpcof_
+# -- Missing translation: _httpiconeexpcon_
+
+# -- Missing translation: etsec
+# -- Missing translation: _httpiconetsecof_
+# -- Missing translation: _httpiconetsecon_
+
+# -- Missing translation: ehl
+# -- Missing translation: _httpiconehlof_
+# -- Missing translation: _httpiconehlon_
+
+# -- Missing translation: enhl
+# -- Missing translation: _httpiconenhlof_
+# -- Missing translation: _httpiconenhlon_
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=kn] {_If_(_thislast_,à²«à²²à²¿à²€à²Ÿà²à²¶à²à²³à³ _thisfirst_ - _thislast_ 
+à² à²ªà³à²°à²¶à³à²šà³à²à³: _cgiargq_,à² à²ªà³à²°à²¶à³à²šà³
+à²à³à²žà²°à²¿à²¯à²Ÿà²Šà²¹à³à²à²Šà²£à²¿à²à³à²à²³à²¿
+à²²à³à²²: _cgiargq_)}
+_textnoquerytitle_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³à²¯à²ªà³à²}
+
+_texticonthispage_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³}
+_textsome_ [l=kn] {_If_(_cgiargb_,à²¶à³à²°à³à²£à²¿à²¯,à²à³à²²à²µà³)}
+_textall_ [l=kn] {_If_(_cgiargb_,à²¬à³à²²à²¿à²¯à²šà³,à²à²²à³à²²à²Ÿ)}
+# -- Missing translation: _textboolean_
+# -- Missing translation: _textranked_
+# -- Missing translation: _textnatural_
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=kn] {}
+_texticonsearchhistorybar_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³à²¯à²à²°à²¿à²€à³à²°à³}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=kn] {à²à²ªà³à²°à²¶à³à²šà³à²¯à²šà³à²šà³
+à²à²ªà²¯à³à²à²¿à²žà²¿}
+_textfreqmsg1_ [l=kn] {à²ªà²Šà²à²³ à²à²£à²¿à²à³: }
+_textpostprocess_ [l=kn] {_If_(_quotedquery_,<br><i>à²¹à³à²¡à³à²à²²à³ à²¹à²¿à²à²Šà²¿à²š
+à²à²Ÿà²°à³à²¯ à²µà²¿à²§à²Ÿà²š _quotedquery_ à²¬à²³à²žà²¿</i>)}
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=kn] {à²¹à³à²à³à²à²¿à²šà²Šà²à³à²à²¿à²à²€}
+_textapprox_ [l=kn] {à²¬à²à³à²à³}
+_textnodocs_ [l=kn] {à²šà²®à³à²®à²ªà³à²°à²¶à³à²šà³à²à³
+à²¯à²Ÿà²µ à²Šà²Ÿà²à²²à³à²à²³à³à²žà²°à²¿ à²¹à³à²
+à²Šà²²à²¿à²²à³à²².}
+_text1doc_ [l=kn] {à²šà²¿à²®à³à²®à²ªà³à²°à²¶à³à²šà³à²à³
+à²à²à²Šà³ à²Šà²Ÿà²à²²à³à²žà²°à²¿à²¹à³à²à²Šà²¿à²Šà³.}
+_textlotsdocs_ [l=kn] {à²šà²¿à²®à³à²®à²ªà³à²°à²¶à³à²šà³à²à³
+à²Šà²Ÿà²à²²à³à²à²³à³à²žà²°à²¿à²¹à³à²à²Šà²¿à²µà³.}
+_textmatches_ [l=kn] {à²¹à³à²à²Šà²£à²¿à²à³ }
+_textbeginsearch_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³à²ªà³à²°à²Ÿà²°à²à²­à²¿à²žà²¿}
+_textrunquery_ [l=kn] {à²ªà³à²°à²¶à³à²šà³à²¯à²šà³à²šà³
+à²®à³à²à²Šà³à²µà²°à³à²žà³}
+_textclearform_ [l=kn] {à²šà²®à³à²šà³à²¯à²šà³à²šà³à²®à³à²à³à²€à²à³
+à²³à²¿à²žà³}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+# -- Missing translation: _textwordphrase_
+# -- Missing translation: _textinfield_
+# -- Missing translation: _textfoldstem_
+
+# -- Missing translation: _textadvquery_
+# -- Missing translation: _textallfields_
+# -- Missing translation: _texttextonly_
+# -- Missing translation: _textand_
+# -- Missing translation: _textor_
+# -- Missing translation: _textandnot_
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=kn] {à²
+à²šà³à²¶à³</nobr>à²§à²šà³à²¯à³ _indexselection_ _If_(_jselection_, _jselection_)_If_(_nselection_, à²¯à²Ÿà²µ à²­à²Ÿà²·à³à²¯à²
+à²à²°à³à²€à²à²€ _nselection_) _querytypeselection_ à²ªà²Šà²à²³à²¿à²à²Šà²à³à²¡à²¿à²Šà³}
+
+_textadvancedsearch_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³ _indexselection_ _If_(_jselection_, _jselection_)_If_(_nselection_, _nselection_ )à² à²­à²Ÿà²·à³à²¯à²
+à²à²°à³à²€à²à²µà²Ÿà²à²¿à²Šà³ _querytypeselection_}
+
+# -- Missing translation: _textformsimplesearch_
+
+# -- Missing translation: _textformadvancedsearch_
+
+
+# -- Missing translation: _textnojsformwarning_
+# -- Missing translation: _textdatesearch_
+# -- Missing translation: _textstartdate_
+# -- Missing translation: _textenddate_
+# -- Missing translation: _textbc_
+# -- Missing translation: _textad_
+# -- Missing translation: _textexplaineras_
+
+_textstemon_ [l=kn] {(à²ªà²Šà²à²³à²à³à²šà³à²¯à²šà³à²šà³
+à²à²¡à³à²à²£à²¿à²žà²¿)}
+
+_textsearchhistory_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³à²¯ à²à²°à²¿à²€à³à²°à³}
+
+#text macros for search history
+_textnohistory_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³à²¯ à²à²°à²¿à²€à³à²°à³
+à²Šà³à²°à³à²¯à³à²µà³à²Šà²¿à²²à³à²²}
+# -- Missing translation: _texthresult_
+# -- Missing translation: _texthresults_
+# -- Missing translation: _texthallwords_
+# -- Missing translation: _texthsomewords_
+# -- Missing translation: _texthboolean_
+# -- Missing translation: _texthranked_
+# -- Missing translation: _texthcaseon_
+# -- Missing translation: _texthcaseoff_
+# -- Missing translation: _texthstemon_
+# -- Missing translation: _texthstemoff_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_search
+# -- Missing translation: _httpiconhsearch_
+# -- Missing translation: _widthhsearch_
+# -- Missing translation: _heighthsearch_
+
+# -- Missing translation: qryresb
+# -- Missing translation: _httpiconqryresb_
+# -- Missing translation: _widthqryresb_
+# -- Missing translation: _heightqryresb_
+
+# -- Missing translation: schhistb
+# -- Missing translation: _httpiconsrchhistb_
+# -- Missing translation: _widthsrchhistb_
+# -- Missing translation: _heightsrchhistb_
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textprefschanged_
+_textsetprefs_ [l=kn] {à²à²¯à³à²à³à²à²³à²šà³à²šà³
+à²šà²¿à²¶à³à²à²¯à²¿à²žà²¿}
+_textsearchprefs_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³à²¯
+à²à²¯à³à²à³à²à²³à³}
+_textcollectionprefs_ [l=kn] {à²žà²à²à³à²°à²¹à²£à³à²¯ à²à²¯
+à³à²à³à²à²³à³}
+_textpresentationprefs_ [l=kn] {à²ªà³à²°à²Šà²°à³à²¶à²¿à²žà³à²µ
+à²à²¯à³à²à³à²à²³à³}
+_textpreferences_ [l=kn] {à²à²¯à³à²à³à²à²³à³}
+# -- Missing translation: _textcasediffs_
+# -- Missing translation: _textignorecase_
+# -- Missing translation: _textmatchcase_
+_textwordends_ [l=kn] {à²ªà²Šà²à²³ à²à³à²šà³:}
+_textstem_ [l=kn] {à²ªà²Šà²à²³ à²à³à²šà³à²¯à²šà³à²šà³ 
+à²à²¡à³à²à²£à²¿à²žà³}
+_textnostem_ [l=kn] {à²ªà²Šà²à²³ à²à³à²šà³à²¯à²šà³à²šà³
+à²à²¡à³à²à²£à²¿à²žà²Šà²¿à²°à³}
+_textprefop_ [l=kn] {à²ªà³à²°à²€à²¿ à²ªà³à²à²à³à²à³ _maxdocoption_ à²«à²²à²¿
+à²€à²Ÿà²à²¶à²à²³à²à²€à³_hitsperpageoption_ à²¹à²¿à²à²€à²¿à²°à³à²à²¿à²žà³.}
+_textextlink_ [l=kn] {à²¹à³à²°à²à²¿à²š à²µà³à²¬à³ à²ªà³à²à³ à²à²³à²šà³à²šà³
+à²žà²à²°à³à²ªà²à²¿à²žà³: }
+_textintlink_ [l=kn] {à²à²Šà²°à²¿à²à²Š à²®à³à²²à²ªà³à²°à²€à²¿à²à²³à²šà³à²šà³
+à²ªà²¡à³à²¯à²²à²Ÿà²à²¿à²Šà³:}
+_textlanguage_ [l=kn] {à²­à²Ÿà²·à³à²¯ à²à²à²à²°à³
+à²«à³à²žà³: }
+_textencoding_ [l=kn] {à²à²šà³ à²à³à²¡à²¿à²à²à³: }
+_textformat_ [l=kn] {à²à²à²à²°à³ à²«à³à²žà³
+à²°à²à²šà³: }
+_textall_ [l=kn] {à²à²²à³à²²à²Ÿ}
+_textquerymode_ [l=kn] {à²ªà³à²°à²¶à³à²šà²Ÿà²µà²³à²¿ à²°à³à²€à²¿:}
+_textsimplemode_ [l=kn] {à²žà²°à²³ à²ªà³à²°à²¶à³à²šà²Ÿà²µà²³à²¿
+à²°à³à²€à²¿}
+_textadvancedmode_ [l=kn] {à²à²šà³à²šà²€à²µà²Ÿà²Š à²ªà³à²°à²¶à³à²šà²Ÿà²µà²³à²¿
+à²°à³à²€à²¿ (à²¬à³à²²à²¿à²¯à²šà³ à²
+à²šà³à²¶à³à²§à²šà³à²¯à²šà³à²šà³
+à²à²³à²à³à²à²¡à²à²€à³)}
+_textlinkinterm_ [l=kn] {à²®à²§à³à²¯à²à²€à²° à²ªà³à²à²Šà²¿à²à²Š}
+_textlinkdirect_ [l=kn] {à²
+à²²à³à²²à²¿à²à³à²šà³à²°à²µà²Ÿà²à²¿ à²¹à³à²à³}
+_textdigitlib_ [l=kn] {à²¡à²¿à²à²¿à²à²²à³ à²à³à²°à²à²¥à²²à²¯}
+_textweb_ [l=kn] {à²µà³à²¬à³}
+_textgraphical_ [l=kn] {à²žà²à²¿à²€à³à²°à²µà²Ÿà²à²¿}
+_texttextual_ [l=kn] {à²®à³à²²à²ªà²Ÿà² }
+_textcollectionoption_ [l=kn] {<p>
+à²žà²¹à²žà²à²à³à²°à²¹à²£à³à²¯à²šà³à²šà³ 
+à²žà³à²°à²¿à²žà²²à²Ÿà²à²¿à²Šà³:
+<br>}
+
+_textrelateddocdisplay_ [l=kn] {à²žà²à²¬à²à²§à²¿à²žà²¿à²Š à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà³
+à²ªà³à²°à²Šà²°à³à²¶à²¿à²žà³}
+_textsearchhistory_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³à²¯
+à²à²°à²¿à²€à³à²°à³:}
+# -- Missing translation: _textnohistory_
+_texthistorydisplay_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³à²¯ à²à²°à²¿à²€à³à²°à³à²¯
+à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà³ _historynumrecords_à²ªà³à²°à²Šà²°à³à²¶à²¿à²žà³}
+_textnohistorydisplay_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³à²¯
+à²à²°à²¿à²€à³à²°à³à²¯à²šà³à²šà³ 
+à²ªà³à²°à²Šà²°à³à²¶à²¿à²žà²¬à³à²¡}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=kn] {à²šà²®à³à²šà³à²¯ à²
+à²šà³à²¶à³à²§à²šà³}
+# -- Missing translation: _textplainsearch_
+_textqueryboxsize_ [l=kn] {à²
+à²šà³à²¶à³à²§à²šà³
+à²ªà³à²à³à²à²¿à²à³à²¯  à²à²Ÿà²€à³à²°:}
+_textregbox_ [l=kn] {à²šà²¿à²¯à²®à²¿à²€ à²ªà³à²°à²¶à³à²šà³
+à²ªà³à²à³à²à²¿à²à³}
+_textbigbox_ [l=kn] {à²Šà³à²¡à³à²¡ à²ªà³à²°à²¶à³à²šà³ 
+à²ªà³à²à³à²à²¿à²à³}
+_textformtype_ [l=kn] {à²šà²®à³à²šà³à²¯ à²¬à²à³:}
+_textsimple_ [l=kn] {à²žà²°à²³}
+_textadvanced_ [l=kn] {à²à²šà³à²šà²€à²µà²Ÿà²Š}
+
+# used in "with 4 fields" in the form search box
+# -- Missing translation: _textwith_
+# -- Missing translation: _textfields_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_pref
+# -- Missing translation: _httpiconhpref_
+# -- Missing translation: _widthhpref_
+# -- Missing translation: _heighthpref_
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+# -- Missing translation: _textsortby_
+# -- Missing translation: _textalsoshowing_
+# -- Missing translation: _textwith_
+# -- Missing translation: _textdocsperpage_
+
+# -- Missing translation: _textfilterby_
+# -- Missing translation: _textall_
+# -- Missing translation: _textany_
+# -- Missing translation: _textwords_
+# -- Missing translation: _textleaveblank_
+
+# -- Missing translation: _browsebuttontext_
+
+# -- Missing translation: _nodata_
+# -- Missing translation: _docs_
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=kn] {à²žà²Ÿà²¹à²Ÿà²¯}
+_textSearchshort_ [l=kn] {à²šà²¿à²°à³à²Šà²¿à²·à³à² à²ªà²Šà²à²³à²šà³à²šà³
+à²
+à²šà³à²¶à³à²§à²¿à²žà²¿}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³ 
+à²¶à³à²°à³à²·à²¿à²à³à²à²³à²à²€à³ 
+à²ªà³à²°à²µà³à²¶à²¿à²žà²¿}
+_textCreatorshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³ 
+à²²à³à²à²à²°à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²¿}
+_textSubjectshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²µà²¿à²·à²¯à²à²³à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²¿}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²Šà²¿à²šà²Ÿà²à²à²Šà²à²€à³  à²ªà³à²°à²µà³à²¶à²¿à²žà²¿}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²à²¡à²€à²à²³à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²¿}
+# -- Missing translation: _textLanguageshort_
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²žà²°à²£à²¿à²¯à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²¿}
+# -- Missing translation: _textToshort_
+# -- Missing translation: _textFromshort_
+_textBrowseshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³ 
+à²¬à³à²°à³à²žà³ à²®à²Ÿà²¡à²¿}
+_textOrganizationshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²žà²à²žà³à²¥à³à²à²³à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²¿}
+_textHowtoshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²¹à³à²à³ à²ªà²à³à²à²¿à²¯à²à²€à³ 
+à²ªà³à²°à²µà³à²¶à²¿à²žà²¿}
+_textTopicshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³ 
+à²ªà³à²°à²à²°à²£à²à²³à²à²€à³ 
+à²ªà³à²°à²µà³à²¶à²¿à²žà²¿}
+_textPeopleshort_ [l=kn] {à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²à²šà²°à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²¿}
+# -- Missing translation: _textAcronymshort_
+# -- Missing translation: _textPhraseshort_
+# -- Missing translation: _textArtistshort_
+# -- Missing translation: _textKeywordshort_
+# -- Missing translation: _textVolumeshort_
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=kn] {à²žà³à²ªà²·à³à²à³à²à²°à²¿à²žà²Š 
+à²µà²°à³à²à³à²à²°à²£}
+
+_textSearchlong_ [l=kn] {<p>à²šà³à²µà³ <i>à²šà²¿à²°à³à²Šà²¿à²·à³à²
+à²ªà²Šà²à²³à²¿à²à³ à²
+à²šà³à²¶à³à²§à²¿à²žà²¿à²Šà²°à³</i>, 
+à²
+à²µà³
+à²
+à²šà³à²¶à³à²§à²šà³à²¯
+à²ªà³à²à²Šà²²à³à²²à²¿à²°à³à²µ
+à²ªà² à³à²¯à²Šà²²à³à²²à²¿
+à²à²Ÿà²£à²žà²¿à²à³à²€à³à²€à²Šà³.
+à²šà³à²µà³ à²ªà³à²°à²Ÿà²°à²à²­à²¿à²žà²¿à²Š
+à²®à³à²Šà²²à²šà³à²¯
+à²ªà³à²à²µà²¿à²Šà³, à²¬à³à²°à³
+à²ªà³à²à²à²³à²¿à²à²Š à²
+à²ªà³à² à²€à²²à³à²ªà²²à³ <b>à²
+à²šà³à²¶à³à²§à²šà³</b> 
+à²à³à²à²¡à²¿à²¯à²šà³à²šà³ 
+à²¬à²³à²žà²¿.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=kn] {<p>à²šà³à²µà³ <i> à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²¶à³à²°à³à²·à²¿à²à³à²à²³à²à²€à³
+à²ªà³à²°à²µà³à²¶à²¿à²žà²²à³</i> <b>à²¶à³à²°à³à²·à²¿à²à³à²à²³à³</b> 
+à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¿. à²à²Šà³ à²šà²¿à²®à²à³
+à²à²²à³à²²à²Ÿ
+à²ªà³à²žà³à²€à²à²à²³
+à²ªà²à³à²à²¿à²¯à²šà³à²šà³
+à²
+à²à³à²·à²°à²®à²Ÿà²²à³à²¯à²à²€à³
+à²€à³à²°à³à²Šà²¿à²¡à³à²€à³à²€à²Šà³.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=kn] {<p>à²šà³à²µà³ <i> à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²²à³à²à²à²°à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²²à³</i> 
+<b>à²²à³à²à²à²°à³</b> à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¿. à²à²Šà³ à²ªà³à²žà³à²€à²à²à²³
+à²ªà²à³à²à²¿à²¯à²šà³à²šà³ à²²à³à²à²à²°
+à²¹à³à²žà²°à²¿à²šà²à²€à³ à²µà²¿à²à²à²¡à²¿à²žà³à²€à³à²€à²Šà³.  }
+
+_textSubjectlong_ [l=kn] {<p>à²šà³à²µà³ <i> à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²µà²¿à²·à²¯à²à²³à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²²à³</i>
+<b>à²µà²¿à²·à²¯à²à²³à³</b> à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¿. 
+à²à²Šà³ à²µà²¿à²·à²¯à²à²³ à²ªà²à³à²à²¿à²¯à²šà³à²šà³
+à²¬à³à²à³ à²¶à³à²²à³à²«à³
+à²šà²²à³à²²à²¿ à²šà²¿à²°à³à²ªà²¿à²žà²¿à²Šà²à²€à³
+à²€à³à²°à³à²Šà²¿à²¡à³à²€à³à²€à²Šà³.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=kn] {<p>à²šà³à²µà³ <i> à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²Šà²¿à²šà²Ÿà²à²à²Šà²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²²à³</i> 
+<b>à²Šà²¿à²šà²Ÿà²à²</b> à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¿. 
+à²à²Šà³ à²à²²à³à²²à²Ÿ à²ªà³à²°à²€à²¿à²à²³
+à²ªà²à³à²à²¿à²¯à²šà³à²šà³
+à²à²Ÿà²²à²Ÿà²šà³à²žà²Ÿà²°à²µà²Ÿà²à²¿
+à²€à³à²°à³à²Šà²¿à²¡à³à²€à³à²€à²Šà³.  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=kn] {<p>à²šà³à²µà³ <i>à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²à²¡à²€à²à²³à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²²à³</i> 
+ <b>à²à²¡à²€à²à²³à³</b> à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¿. à²à²Šà³ à²à²¡à²€à²à²³
+à²ªà²à³à²à²¿à²¯à²šà³à²šà³
+à²€à³à²°à³à²Šà²¿à²¡à³à²€à³à²€à²Šà³.  }
+
+# -- Missing translation: _textLanguagelong_
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=kn] {<p>à²šà³à²µà³ <i> à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²žà²à²žà³à²¥à³à²à²³à²à²€à³
+à²ªà³à²°à²µà³à²¶à²¿à²žà²²à³</i> <b>à²žà²à²žà³à²¥à³à²à²³à³</b> 
+à²à²Šà³ à²žà²à²žà³à²¥à³à²à²³
+à²ªà²à³à²à²¿à²¯à²šà³à²šà³
+à²€à³à²°à³à²Šà²¿à²¡à³à²€à³à²€à²Šà³.  }
+
+_textHowtolong_ [l=kn] {<p>à²šà³à²µà³ <i> à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²¹à³à²à³
+à²ªà²à³à²à²¿à²¯à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²²à³
+</i> <b>à²¹à³à²à³?</b> à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¿. à²à²Šà³ à²¹à³à²à³
+à²ªà²à³à²à²¿à²¯à²šà³à²šà³
+à²€à³à²°à³à²Šà²¿à²¡à³à²€à³à²€à²Šà³.  }
+
+_textTopiclong_ [l=kn] {<p>à²šà³à²µà³ <i> #3242;à³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²ªà³à²°à²à²°à²£à²à²³à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²²à³</i>
+<b>à²ªà³à²°à²à²°à²£à²à²³à³</b> à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¿. 
+à²à²Šà³ à²ªà³à²°à²à²°à²£à²à²³
+à²ªà²à³à²à²¿à²¯à²šà³à²šà³
+à²¬à³à²°à³à²žà³ à²®à²Ÿà²¡à²²à³
+à²€à³à²°à³à²Šà²¿à²¡à³à²€à³à²€à²Šà³.  }
+
+# -- Missing translation: _textTolong_
+
+# -- Missing translation: _textFromlong_
+
+_textSerieslong_ [l=kn] {<p>à²šà³à²µà³ <i> à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²žà²°à²£à²¿à²¯à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²²à³</i> 
+<b>à²žà²°à²£à²¿</b> à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¿. 
+à²à²Šà³ à²ªà³à²°à²à²²à²¿à²€
+à²žà²°à²£à²¿ à²ªà²à³à²à²¿à²¯à²šà³à²šà³
+à²€à³à²°à³à²Šà²¿à²¡à³à²€à³à²€à²Šà³.  }
+
+_textBrowselong_ [l=kn] {<p>à²šà³à²µà³ <i>à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²¬à³à²°à³à²žà³ à²®à²Ÿà²¡à²²à³</i> <b>à²¬à³à²°à³à²žà³</b>
+ à²à³à²à²¡à²¿à²¯à²šà³à²šà³ à²¬à²³à²žà²¿.  }
+
+_textPeoplelong_ [l=kn] {<p>à²šà³à²µà³ <i> à²ªà³à²°à²à²Ÿà²¶à²¿à²€à²µà²šà³à²šà³
+à²à²šà²°à²à²€à³ à²ªà³à²°à²µà³à²¶à²¿à²žà²²à³</i> 
+<b>à²à²šà²°à³</b> à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¿. 
+à²à²Šà³ à²à²ªà²šà²Ÿà²®à²à²³
+à²ªà²à³à²à²¿à²¯à²šà³à²šà³
+à²€à³à²°à³à²Šà²¿à²¡à³à²€à³à²€à²Šà³. }
+
+# -- Missing translation: _textAcronymlong_
+
+# -- Missing translation: _textPhraselong_
+
+# -- Missing translation: _textArtistlong_
+
+# -- Missing translation: _textKeywordlong_
+
+# -- Missing translation: _textVolumelong_
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+# -- Missing translation: _textdefaultlongtext_
+
+_texthelptopics_ [l=kn] {<h2 align=left>à²žà²¹à²Ÿà²¯à²Š à²µà²¿à²·à²¯à²à²³à³</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">à²šà²¿à²°à³à²Šà²¿à²·à³à² 
+à²ªà²Šà²à²³à²šà³à²šà³ à²¹à³à²à³
+à²
+à²šà³à²¶à³à²§à²¿à²žà³à²µà²¿à²°à²¿</a>
+<ul>
+  <li><a href="\#query-terms">à²
+à²šà³à²¶à³à²§à²šà³à²¯ à²ªà²Šà²à²³à³</a>
+  <li><a href="\#query-type">à²
+à²šà³à²¶à³à²§à²šà³à²¯ à²°à³à²€à²¿</a>
+  <li><a href="\#scope-of-queries">à²
+à²šà³à²¶à³à²§à²šà³à²¯ à²à²Šà³à²Šà³à²¶</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">à²žà²à²à³à²°à²¹à²£à³à²¯ à²à²¯à³à²à³à²à²³à³</a>
+  <li><a href="\#pres-prefs">à²ªà³à²°à²Šà²°à³à²¶à²¿à²žà³à²µ à²à²¯à³à²à³à²à²³à³</a>
+  <li><a href="\#search-prefs">à²
+à²šà³à²¶à³à²§à²šà³à²¯ à²à²¯à³à²à³à²à²³à³</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=kn] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=kn] {à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà³ 
+à²¹à³à²à³ à²à²Šà³à²µà³à²Šà³}
+
+_texthelpreadingdocs_ [l=kn] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p> à²à²à²Šà³ à²Šà²Ÿà²à²²à³ 
+à²¬à²à²Š à²€à²à³à²·à²£
+à²šà³à²µà³ à²
+à²Šà²šà³à²šà³
+à²à³à²°à³à²€à²¿à²žà²¬à²¹à³à²Šà³,
+à²¹à³à²à³à²à²Šà²°à³ à²
+à²Šà²°
+à²¶à³à²°à³à²·à²¿à²à³
+à²®à²€à³à²€à³ à²²à³à²à²à²°
+à²¹à³à²žà²°à³ à² à²ªà³à²à²Š
+à²®à³à²²à²¿à²š à²à²¡
+à²­à²Ÿà²à²Šà²²à³à²²à²¿à²°à³à²€à³à²€à²Šà³.
+à²
+à²²à³à²²à²Šà³
+à²ªà³à²°à²à²²à²¿à²€ à²ªà³à²à²Š
+à²žà²à²à³à²¯à³ à²žà²¹
+à²à²°à³à²€à³à²€à²Šà³. à²¬à³à²°à³
+à²ªà³à²à²à²³à²¿à²à³
+à²¹à³à²à²²à³ à²¹à²¿à²à²Šà³
+à²®à²€à³à²€à³ à²®à³à²à²Šà³ à²à²¿à²¹à³à²šà³à²à²³à³
+à²žà²¹à²Ÿà²¯ à²®à²Ÿà²¡à³à²€à³à²€à²µà³.
+
+<p>à²
+à²Šà²° à²à³à²³à²à³
+à²ªà³à²°à²à²²à²¿à²€ à²­à²Ÿà²à²Š
+à²ªà² à³à²¯à²µà²¿à²°à³à²€à³à²€à²Šà³.
+à²šà³à²µà³ à²
+à²Šà²šà³à²šà³
+à²à²Šà²¿à²Šà²,
+à²
+à²²à³à²²à²¿à²°à³à²µ
+à²¬à²Ÿà²£à²Š à²à³à²°à³à²€à²¿à²š
+à²à²¿à²¹à³à²šà³à²à²³à³ à²®à³à²à²Šà²¿à²š
+à²
+à²¥à²µà²Ÿ à²¹à²¿à²à²Šà²¿à²š
+à²­à²Ÿà²à²à³à²à³
+à²¹à³à²à²²à³ à²žà²¹à²Ÿà²¯
+à²®à²Ÿà²¡à³à²€à³à²€à²µà³.
+
+<p>à²¶à³à²°à³à²·à²¿à²à³
+à²®à²€à³à²€à³ à²²à³à²à²à²°
+à²à³à²³à²à³ à²®à³à²°à³ à²à³à²à²¡à²¿à²à²³à²¿à²µà³.
+ <b>à²ªà² à³à²¯à²µà²šà³à²šà³ à²µà²¿à²žà³à²€à²°à²¿à²žà³</b>, 
+à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²à³à²²à²¿à²à³
+à²®à²Ÿà²¡à²¿à²Šà²°à³
+à²ªà³à²°à²à²²à²¿à²€
+à²Šà²Ÿà²à²²à³à²¯
+à²ªà³à²°à³à²€à²¿ à²ªà² à³à²¯
+à²µà²¿à²žà³à²€à²°à²à³à²³à³à²³à³à²€à³à²€à²Šà³.
+à²à²à²Šà³ à²µà³à²³à³ à²Šà²Ÿà²à²²à³
+à²€à³à²à²¬
+à²Šà³à²¡à³à²¡à²Šà²¿à²Šà³à²Šà²²à³à²²à²¿
+à²
+à²Šà³ à²¬à²¹à²³ à²žà²®à²¯
+à²€à³à²à³à²Šà³à²à³à²³à³à²³à²¬à²¹à³à²Šà³.
+<b>à²ªà³à²°à²€à³à²¯à³à²à²¿à²žà³</b>, 
+à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²à³à²²à²¿à²à³
+à²®à²Ÿà²¡à²¿à²Šà²°à³
+à²ªà³à²°à²à²²à²¿à²€
+à²Šà²Ÿà²à²²à³ à²¹à³à²ž
+à²à²¿à²à²à²¿à²¯à²²à³à²²à²¿ à²€à³à²°à³à²Šà³à²à³à²³à³à²³à³à²€à³à²€à²Šà³
+(à²à²Šà³ à²à²°à²¡à³
+à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà³
+à²¹à³à²²à²¿à²žà²¿,
+à²à²°à²¡à²šà³à²šà³ à²à²à³à²à²¿à²à³
+à²à²Šà²²à³
+à²žà²¹à²Ÿà²¯à²µà²Ÿà²à³à²€à³à²€à²Šà³.)
+à²
+à²à²€à²¿à²®à²µà²Ÿà²à²¿
+à²šà³à²µà³ à²
+à²šà³à²¶à³à²§à²¿à²žà²¿à²Š
+à²ªà²Šà²à²³à³ à²šà²¿à²®à³à²®
+à²
+à²šà³à²¶à³à²§à²šà³à²¯à²²à³à²²à²¿
+à²¹à³à²²à³à²à³
+à²à²à²¿à²°à³à²€à³à²€à²Šà³.
+à²šà²¿à²®à²à³ à²¹à³à²²à³à²à³
+à²¬à³à²¡à²Šà²¿à²Šà³à²Šà²²à³à²²à²¿ <i>à²¹à³à²²à³à²à³ à²¬à³à²¡</i>,
+à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²à³à²²à²¿à²à³ à²®à²Ÿà²¡à²¿.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_"
+border="0"></td><td>à²®à³à²à²Šà²¿à²š
+à²­à²Ÿà²à²à³à²à³
+à²¹à³à²à²²à³ à²¬à²Ÿà²£à²Š
+à²à²¿à²¹à³à²šà³à²¯à²šà³à²šà³
+à²à³à²²à²¿à²à³ à²®à²Ÿà²¡à²¿ ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... à²
+à²¥à²µà²Ÿ à²¹à²¿à²à²Šà²¿à²š
+à²­à²Ÿà²à²à³à²à³ à²¹à³à²à²¿</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>à²à²²à³à²²à²Ÿ à²ªà² à³à²¯
+à²µà²šà³à²šà³
+à²ªà³à²°à²Šà²°à³à²¶à²¿à²žà³,
+à²
+à²¥à²µà²Ÿ à²¬à³à²¡</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_"
+border="0"></td><td>à² à²ªà³à²à²µà²šà³à²šà³
+à²¹à³à²ž à²à²¿à²à²à²¿à²¯à²²à³à²²à²¿
+à²€à³à²à³</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>à²
+à²šà³à²¶à³à²§à²¿à²žà²¿à²Š
+à²ªà²Šà²à²³à²šà³à²šà³
+à²¹à³à²²à³à²à³ à²®à²Ÿà²¡à³</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=kn] {<h2>à²šà²¿à²°à³à²Šà²¿à²·à³à²
+à²ªà²Šà²à²³à²šà³à²šà³
+à²¹à³à²à³ à²
+à²šà³à²¶à³à²§à²¿à²žà³à²µà³à²Šà³</h2>
+<p>
+  à²
+à²šà³à²¶à³à²§à²šà³à²¯
+à²ªà³à²à²Šà²²à³à²²à²¿, à²šà²¿à²®à³à²®
+à²ªà³à²°à²¶à³à²šà³à²¯à²šà³à²šà³ à²žà²°à²³
+à²°à³à²€à²¿à²¯à²²à³à²²à²¿ à²žà³à²·à³à²à²¿à²žà²¿::<p>
+  
+  <ol><li>à²¯à²Ÿà²µ à²µà²¿à²·à²¯à²µà²šà³à²šà³
+à²
+à²šà³à²¶à³à²§à²¿à²žà²¬à³à²à³à²à²Šà³
+à²µà²¿à²¶à³à²·à²¿à²žà²¿
+      <li>à²šà²¿à²®à³à²®
+à²ªà³à²°à²¶à³à²šà³à²¯ à²à²²à³à²²à²Ÿ
+à²
+à²¥à²µà²Ÿ à²à³à²²à²µà³
+à²ªà²Šà²à²³à²šà³à²šà³
+à²®à²Ÿà²€à³à²° à²
+à²šà³à²¶à³à²§à²¿à²žà²¬à³à²à³à²à²Šà³
+à²€à²¿à²³à²¿à²žà²¿
+      <li>à²
+à²šà³à²¶à³à²§à²¿à²žà²¬à³à²à²Ÿà²Š
+à²ªà²Šà²à²³à²šà³à²šà³
+à²à³à²ªà³ à²®à²Ÿà²¡à²¿
+      <li><b>à²
+à²šà³à²¶à³à²§à²šà³</b> à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²à³à²²à²¿à²à³ à²®à²Ÿà²¡à²¿
+  </ol>
+
+<p> à²šà²¿à²®à³à²®
+à²ªà³à²°à²¶à³à²šà³à²¯à²šà³à²šà³
+à²žà³à²·à³à²à²¿à²žà²¿
+à²
+à²šà³à²¶à³à²§à²¿à²žà²¿à²Šà²°à³,
+à²
+à²Šà²° à²žà²à²¬à²à²§à²¿à²€
+à²®à³à²Šà²²
+à²à²ªà³à²ªà²€à³à²€à³
+à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà³
+à²€à³à²°à²¿à²žà²²à²Ÿà²à³à²€à³à²€à²Šà³.
+à²®à³à²à²Šà²¿à²š
+à²à²ªà³à²ªà²€à³à²€à³
+à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà³
+à²µà²¿à²à³à²·à³à²žà²²à³
+à²ªà³à²à²Š
+à²à³à²šà³à²¯à²²à³à²²à²¿à²°à³à²µ
+à²à³à²à²¡à²¿à²à²³à³
+à²žà²¹à²Ÿà²¯ à²®à²Ÿà²¡à³à²€à³à²€à²µà³.
+à² à²à³à²à²¡à²¿à²à²³à³
+à²®à²€à³à²€à³
+à²®à³à²à²Šà²¿à²°à³à²µ
+à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà²Ÿà²à²²à²¿
+à²
+à²¥à²µà²Ÿ à²¹à²¿à²à²Šà²¿à²š
+à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà²Ÿà²à²²à²¿
+à²µà²¿à²à³à²·à³à²žà²²à³
+à²žà²¹à²à²°à²¿à²žà³à²€à³à²€à²µà³.à²šà³à²µà³
+à²Šà²Ÿà²à²²à³à²¯à²šà³à²šà³
+à²µà²¿à²à³à²·à³à²žà²²à³ à²¶à³à²°à³à²·à²¿à²à³
+à²®à³à²²à²Ÿà²à²²à²¿ à²
+à²¥à²µà²Ÿ à²
+à²Šà²°
+à²®à³à²à²Šà²¿à²°à³à²µ
+à²à²¿à²¹à³à²šà³à²¯à²šà³à²šà²Ÿà²à²²à²¿
+à²à³à²²à²¿à²à³ à²®à²Ÿà²¡à²¿. 
+
+<p> à²¹à³à²à³à²à³à²à²Šà²°à³ 100
+à²«à²²à²¿à²€à²Ÿà²à²¶à²à²³à²šà³à²šà³
+à²¹à²¿à²à²€à²¿à²°à³à²à²¿à²žà²²à²Ÿà²à³à²€à³à²€à²Šà³,
+à²à²Šà²šà³à²šà³ à²šà³à²µà³
+à²à²¯à³à²à³à²à²³ à²ªà³à²à²Šà²²à³à²²à²¿
+à²¬à²Šà²²à²¿à²žà²¬à²¹à³à²Šà³.<p> 
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>à²
+à²šà³à²¶à³à²§à²šà³à²¯ à²ªà²Šà²à²³à³</h3>
+
+<p> à²šà³à²µà³
+à²ªà³à²°à²¶à³à²šà³à²ªà³à²à³à²à²¿à²à³à²¯à²²à³à²²à²¿
+à²à²šà²Ÿà²Šà²°à³ à²à³à²ªà³
+à²®à²Ÿà²¡à²¿à²Šà²°à³ à²
+à²Šà³
+à²
+à²šà³à²¶à³à²§à²šà³à²¯
+à²ªà²à³à²à²¿à²¯à³à²à²Šà³
+à²€à²¿à²³à²¿à²¯à³à²€à³à²€à²Šà³.
+à²ªà³à²°à²€à²¿à²¯à³à²à²Šà³
+à²ªà²Šà²µà³
+à²
+à²à³à²·à²°à²à²³à²¿à²à²Š
+à²
+à²¥à²µà²Ÿ
+à²
+à²à²à²¿à²à²³à²¿à²à²Š
+à²à³à²¡à²¿à²°à³à²€à³à²€à²Šà³.
+à² à²ªà²Šà²à²³à²šà³à²šà³ à²à²Ÿà²²à²¿
+à²à²Ÿà²à²Šà²¿à²à²Š
+à²¬à³à²°à³à²ªà²¡à²¿à²žà²²à²Ÿà²à²¿à²°à³à²€à³à²€à²Šà³.
+à²à²µà²²à³à²²à²Šà³ à²¬à³à²°à³
+à²¯à²Ÿà²µ à²µà²¿à²·à³à²¶
+à²
+à²à³à²·à²°à²µà²Ÿà²Šà²°à³ (
+à²µà²¿à²°à²Ÿà²®
+à²à²¿à²¹à³à²šà³à²à²³à³)
+à²¬à²à²Šà²²à³à²²à²¿
+à²
+à²µà³à²à²³à²šà³à²šà³
+à²à²Ÿà²²à²¿
+à²à²Ÿà²à²µà³à²à²Šà³
+à²ªà²°à²¿à²à²£à²¿à²žà²¿
+à²
+à²µà²šà³à²šà³
+à²à²¡à³à²à²£à²¿à²žà²²à²Ÿà²à³à²€à³à²€à²Šà³.
+à²šà³à²µà³ à²µà²¿à²°à²Ÿà²®
+à²à²¿à²¹à³à²šà³à²à²³à²šà³à²šà³
+à²¹à³à²à²Šà²¿à²°à³à²µ
+à²ªà²Šà²à²³à²šà³à²šà³
+à²
+à²šà³à²¶à³à²§à²¿à²žà²²à³
+à²à²à³à²µà³à²Šà²¿à²²à³à²²!
+
+<p>à²à²Šà²Ÿà²¹à²°à²£à³à²à³: à²
+à²ªà³à²°à²¶à³à²šà³<p>
+    <ul><kbd>à²«à³à²žà²¿à²«à²¿à²à³
+à²Šà³à²µà³à²ªà²à²³à²²à³à²²à²¿
+à²à²à³à²°à³-à²«à²Ÿà²°à³à²žà³à²à³à²°à²¿:
+ à²žà²à²°à²à³à²·à²£à³
+à²®à²Ÿà²¡à³à²µ à²ªà²Šà³à²Šà²€à²¿
+(1993)</kbd></ul>
+      <p>à²à²Šà²šà³à²šà³ à² à²°à³à²€à²¿
+à²ªà²°à²¿à²à²£à²¿à²žà²²à²Ÿà²à³à²€à³à²€à²Šà³<p>
+      <ul><kbd>à²«à³à²žà²¿à²«à²¿à²à³
+à²Šà³à²µà³à²ªà²à²³à²²à³à²²à²¿
+à²à²à³à²°à³ à²«à²Ÿà²°à³à²žà³à²à³à²°à²¿
+<span style='mso-spacerun:yes'> </span>à²žà²à²°à²à³à²·à²£à³
+à²®à²Ÿà²¡à³à²µ à²ªà²Šà³à²Šà²€à²¿ 1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>à²ªà³à²°à²¶à³à²šà³à²¯ à²®à²Ÿà²Šà²°à²¿</h3>
+
+<p>à²à²°à²¡à³ à²¬à²à³à²¯ 
+à²ªà³à²°à²¶à³à²šà³à²à²³à²¿à²µà³.
+
+<ul>
+  <li>à²ªà³à²°à²¶à³à²šà³à²à²³à²²à³à²²à²¿ <b>à²à²²à³à²²à²Ÿ</b> 
+à²à²µà³ à²šà³à²µà³
+à²µà²¿à²¶à³à²·à²¿à²žà²¿à²Š à²à²²à³à²²à²Ÿ
+à²ªà²Šà²à²³à²šà³à²šà³ à²à²²à³à²²à²Ÿ
+à²Šà²Ÿà²à²²à³à²à²³à²²à³à²²à²¿ (à²
+à²¥à²µà²Ÿ
+à²ªà²Ÿà² à²à²³à²²à³à²²à²¿ à²
+à²¥à²µà²Ÿ
+à²¶à³à²°à³à²·à²¿à²à³à²à²³à²²à³à²²à²¿)
+à²
+à²šà³à²¶à³à²§à²¿à²žà³à²€à³à²€à²Šà³.
+à²µà²¿à²¶à³à²·à²¿à²žà²¿à²Š à²ªà²Šà²à²³à²šà³à²šà³
+à²¹à³à²à²Šà³à²µ à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà³
+à²µà²°à³à²£à²®à²Ÿà²²à³à²¯à²à²€à³
+à²ªà³à²°à²Šà²°à³à²¶à²¿à²žà³à²€à³à²€à²Šà³.<p>
+
+  <li>à²ªà³à²°à²¶à³à²šà³à²à²³à²²à³à²²à²¿ <b>à²à³à²²à²µà³</b> 
+à²à²µà³ à²šà³à²µà³ à²¬à²¯à²žà³à²€à³à²€à²¿à²°à³à²µ
+à²à³à²²à²µà³ à²ªà²Šà²à²³à²¿à²à³ à²žà²à²¬à²à²§à³à²à³à²
+à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà³
+à²
+à²šà³à²¶à³à²§à²¿à²žà³à²€à³à²€à²Šà³.
+à²šà²à²€à²° à²žà²°à²¿à²¹à³à²à²Šà²¿à²Š
+à²Šà²Ÿà²à²²à³à²à²³à²šà³à²šà³
+à²ªà³à²°à²Šà²°à³à²¶à²¿à²žà³à²€à³à²€à²Šà³.
+à²žà²°à²¿à²¹à³à²à²Šà²£à²¿à²à³à²¯à²šà³à²šà³
+à²šà²¿à²¶à³à²à²¯à²¿à²žà³à²µà²Ÿà²
+à²à³à²³à²à²¿à²šà²à²€à³
+à²šà²¿à²¶à³à²à²¯à²¿à²žà³à²€à³à²€à²Šà³.
+      <p><ul>
+        <li> à²Šà²Ÿà²à²²à³à²¯à²²à³à²²à²¿
+à²
+à²šà³à²¶à³à²§à²¿à²žà²¿à²Š
+à²ªà²Šà²à²³à³ à²€à³à²à²¬à²Ÿ
+à²à²Šà³à²Šà²°à³ à²
+à²Šà³
+à²¹à²€à³à²€à²¿à²°à²Š
+à²žà²°à²¿à²¹à³à²à²Šà²£à²¿à²à³.
+        <li> à²žà²Ÿà²®à²šà³à²¯à²µà²Ÿà²Š
+à²ªà²Šà²à²³à²¿à²à²¿à²à²€ à²µà²¿à²°à²³à²µà²Ÿà²Š
+à²ªà²Šà²à²³à³ à²€à³à²à²¬à²Ÿ 
+à²ªà³à²°à²®à³à²à³à²¯à²µà²Ÿà²Šà²µà³.
+        <li> à²Šà³à²¡à³à²¡à²Šà²Ÿà²à²²à³à²à²³à²¿à²à²¿à²à²€
+à²à²¿à²à³à²à²Šà²Ÿà²à²²à³à²à²³à³
+à²€à³à²à²¬à²Ÿ à²à³à²šà³à²šà²Ÿà²à²¿
+à²žà²°à²¿à²¹à³à²à²Šà³à²€à³à²€à²µà³.
+      </ul>
+</ul>
+
+<p> à²šà³à²µà³ à²à²·à³à²à³ à²
+à²šà³à²¶à³à²§à²šà³
+à²ªà²Šà²à²³à²šà³à²šà²Ÿà²Šà²°à³
+à²à²ªà²¯à³à²à²¿à²žà²¬à²¹à³à²Šà³,
+à²à²Šà²Ÿà²¹à²°à²£à³à²à³ à²à²à²Šà³ à²µà²Ÿà²à³à²¯
+à²ªà³à²°à³à²€à²¿, à²à²à²Šà³ à²µà²Ÿà²à³à²¯à²µà³à²à²Š
+à²ªà³à²°à³à²€à²¿ à²®à³à²à²€à²Ÿà²Šà²µà³.
+à²à²à²Šà³ à²ªà²Šà²µà²šà³à²šà³ à²à²ªà²¯à³à²à²¿à²žà²¿à²Šà²°à³
+à²Šà²Ÿà²à²²à³à²à²³à²²à³à²²à²¿ à²
+à²Šà²°
+à²žà²à²­à²µà²¿à²šà²¿à²¯à²€à³à²¯à²à²€à³ à²ªà²à³à²à²¿
+à²®à²Ÿà²¡à³à²€à³à²€à²Šà³.<p>
+_texthelpscope_
+}
+
+# -- Missing translation: _textdatesearch_
+
+# -- Missing translation: _texthelpdatesearch_
+
+_textchangeprefs_ [l=kn] {à²šà²¿à²®à³à²® à²à²¯à³à²à³à²à²³à³}
+
+_texthelppreferences_ [l=kn] {<h2>_textchangeprefs_</h2>
+
+<p>à²ªà³à²à²Š à²®à³à²²à²¿à²°à³à²µ <b>à²à²¯à³à²à³à²à²³à³</b> 
+à²à³à²à²¡à²¿à²¯à²šà³à²šà³ à²à³à²²à²¿à²à³ à²®à²Ÿà²¡à²¿
+à²à²à²à²°à³ à²«à³à²žà³ à²à³à²£à²à²³à²šà³à²šà³
+à²šà²¿à²®à²à³ à²
+à²šà³à²à³à²²à²µà²Ÿà²à³à²µ
+à²°à³à²€à²¿à²¯à²²à³à²²à²¿
+à²¬à²Šà²²à²¿à²žà²¿à²à³à²³à³à²³
+à²¬à²¹à³à²Šà³. 
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>à²žà²à²à³à²°à²¹à²£à³à²¯ à²à²¯à³à²à³à²à²³à³</h3>
+
+à²à³à²²à²µà³
+à²žà²à²à³à²°à²¹à²£à³à²à²³à³
+à²à²ªà²žà²à²à³à²°à²¹à²£à³à²à²³à²¿à²à²Š
+à²à³à²¡à²¿à²°à³à²€à³à²€à²µà³.
+à²
+à²µà²šà³à²šà³ à²žà³à²µà²€à²à²€à³à²°à²µà²Ÿà²à²¿
+à²
+à²¥à²µà²Ÿ à²à³à²€à³à²¯à²Ÿà²à²¿
+à²
+à²šà³à²¶à³à²§à²¿à²žà²¬à²¹à³à²Šà³.
+à²šà³à²®à³à²®
+à²à²ªà²žà²à²à³à²°à²¹à²£à³à²¯à²šà³à²šà³
+à²à²¯à³à²à³à²à²³ à²ªà³à²à²Šà²²à³à²²à²¿
+à²žà³à²°à²¿à²žà²¬à²¹à³à²Šà³.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>à²¬à²Ÿà²·à³à²¯ à²à²¯à³à²à³à²à²³à³</h3>
+
+à²ªà³à²°à²€à²¿à²¯à³à²à²Šà³
+à²žà²à²à³à²°à²¹à²£à³à²¯à²šà³à²šà³
+à²ªà³à²°à²Šà²°à³à²¶à²¿à²žà²²à³
+à²à²Šà²°à²Šà³ à²à²Š
+à²¬à²Ÿà²·à³à²¯à²¿à²°à³à²€à³à²€à²Šà³,
+à²à²Šà²°à³ à²šà³à²µà³ à²
+à²Šà²šà³à²šà³ à²¬à³à²°à³
+à²¬à²Ÿà²·à³à²à²³à²¿à²à³ à²¬à²Šà²²à²¿à²žà²¬à²¹à³à²Šà³.
+à²à³à²°à³à²šà³ à²žà³à²à³à²šà³ à²à²ªà²¯à³à²à²¿à²žà³à²µ
+à²à²šà³ à²à³à²¡à²¿à²à²à³ à²µà²¿à²§à²Ÿà²šà²µà²šà³à²šà³
+à²žà²¹ à²¬à²Šà²²à²¿à²žà²¬à²¹à³à²Šà³.
+à²€à²€à³à²°à²Ÿà²à²¶à²µà³ à²¡à²¿à²«à²Ÿà²²à³à²à³
+à²à²šà³ à²à³à²¡à²¿à²à²à³
+à²¬à²³à²žà³à²µà³à²Šà³. à²¬à³à²°à³à²žà²°à³ à²šà²²à³à²²à²¿
+à²«à²²à²¿à²€à²Ÿà²à²¶à²à²³à³
+à²à³à²šà³à²šà²Ÿà²à²¿ à²®à³à²¡à²¿à²¬à²°à²²à³ à²à²šà³
+à²à³à²¡à²¿à²à²à³
+à²µà²¿à²§à²Ÿà²šà²µà²šà³à²šà³ à²¬à²Šà²²à²¿à²žà²¬à²¹à³à²Šà³.
+à²à²²à³à²²à²Ÿ à²žà²à²à³à²°à²¹à²£à³à²¯à³
+à²šà²¿à²®à²à³ à²žà²à²¿à²€à³à²°
+à²à²à²à²°à³ à²«à³à²žà³
+à²šà²¿à²à²Š à²®à³à²²à²ªà²Ÿà²  à²à²à²à²°à³
+à²«à³à²žà³ à²à³ à²¬à²Šà²²à²¿à²žà²²à³
+à²à²µà²à²Ÿà²¶ à²à²²à³à²ªà²¿à²žà³à²€à³à²€à²Šà³.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>à²ªà³à²°à²Šà²°à³à²¶à²šà³à²¯ à²à²¯à³à²à³à²à²³à³</h3>
+
+à²šà²¿à²°à³à²Šà²¿à²·à³à²
+à²žà²à²à³à²°à²¹à²£à³à²¯à²šà³à²šà³
+à²à²§à²°à²¿à²žà²¿, à²ªà³à²°à²Šà²°à³à²¶à²šà³à²¯
+à²à²¯à³à²à³à²à²³à²šà³à²šà³
+à²¹à²€à³à²à²¿à²¯à²²à³à²²à²¿à²¡à²¬à²¹à³à²Šà³.
+
+à²µà³à²¬à³ à²ªà³à²à²à²³ à²žà²à²à³à²°à²¹à²£à³à²¯,
+à²ªà³à²à²Š à²®à³à²²à²¿à²°à³à²µ à²à³à²°à³à²šà³
+à²žà³à²à³à²šà³ 
+à²šà³à²¯à²Ÿà²µà³à²¹à²¿à²à³à²¶à²šà³
+à²¬à²Ÿà²°à³ à²šà³à²šà³ à²®à³à²à³à²à²¿à²¡à³à²€à³à²€à²Šà³,
+à²à²Šà³à²Šà²°à²¿à²à²Š à²šà³à²µà³ à²à²à²Šà³
+à²¬à²Ÿà²°à²¿ à²µà³à²¬à³ à²ªà³à²à²µà²šà³à²šà³
+à²
+à²šà³à²¶à³à²§à²¿à²žà²¿à²Šà²°à³
+(à²à³à²°à³à²šà³ à²žà³à²à³à²šà³
+à²¹à³à²¡à³à²¡à²°à³ à²žà²¹à²Ÿà²¯à²µà²¿à²²à³à²²à²Šà³)
+à²žà²°à²¿à²¯à²Ÿà²Š à²ªà³à²
+à²€à²²à³à²ªà²¬à²¹à³à²Šà³. à²®à²€à³à²€à³
+à²šà³à²µà³ à²
+à²šà³à²¶à³à²§à²¿à²žà²²à³
+à²¬à³à²°à³à²žà²°à³ à²š à²¹à²¿à²à²Šà³
+à²à³à²à²¡à²¿à²¯à²šà³à²šà³
+à²¬à²³à²žà²¬à³à²à³. à² à²žà²à²à³à²°à²¹à²£à³à²à²³à³
+à²à³à²°à³à²šà³ à²žà³à²à³à²šà³
+à²à²à³à²à²°à²¿à²à³à²¯à²šà³à²šà³
+à²à²¡à³à²à²£à²¿à²žà²¿ à²¡à²¿à²à²¿à²à²²à³
+à²à³à²°à²à²¥à²²à²¯ à²¬à²¿à²à³à²à³
+à²¹à³à²°à²à²¿à²š à²µà³à²¬à³ à²žà²à²à³à²°à²¹à²£à³à²à³
+à²²à²¿à²à²à³ à²šà³à²¡à³à²€à³à²€à²Šà³.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>à²
+à²šà³à²¶à³à²§à²šà³à²¯ à²à²¯à³à²à³à²à²³à³</h3>
+
+à²à²°à²¡à³ à²à³à²¡à²¿
+à²à³à²à²¡à²¿à²à²³à³
+à²šà²¿à²®à³à²®<span style='mso-spacerun:yes'>  </span>à²
+à²šà³à²¶à³à²§à²šà³à²¯
+à²¹à³à²à²Šà²£à²¿à²à³à²à²³à²šà³à²šà³
+à²¹à²¿à²¡à²¿à²€à²Šà²²à³à²²à²¿à²¡à³à²€à³à²€à²µà³.
+à²®à³à²Šà²² à²à³à²¡à²¿ (à²µà²°à³à²£
+à²®à²Ÿà²²à³à²¯
+à²µà³à²€à³à²¯à²Ÿà²ž)
+à²
+à²à³à²·à²° à²®à²Ÿà²²à³à²¯
+à²µà³à²€à³à²¯à²Ÿà²žà²µà²šà³à²šà³
+à²žà²°à²¿à²¹à³à²à²Šà²¿à²žà³à²€à³à²€à²Šà³.
+à²à²°à²¡à²šà³ à²à³à²¡à²¿ à²ªà²Šà²à²³
+à²à³à²šà³à²¯à²šà³à²šà³ à²à²¡à³à²à²£à²¿à²žà²¬à³à²à³
+à²
+à²¥à²µà²Ÿ à²¬à³à²¡
+à²à²šà³à²šà³à²µà³à²Šà²šà³à²šà³
+à²šà²¿à²°à³à²§à²°à²¿à²žà³à²€à³à²€à²Šà³.
+à²µà²Ÿà²à³à²¯à²µà³à²à²Šà²µà²šà³à²šà³
+à²
+à²šà³à²¶à³à²§à²¿à²žà²²à³ à²Šà³à²¡à³à²¡
+à²ªà³à²°à²¶à³à²šà³
+à²ªà³à²à³à²à²¿à²à³ à²ªà²¡à³à²¯à²¬à²¹à³à²Šà³.
+
+}
+
+_texttanumbrowseoptions_ [l=kn] {_numbrowseoptions_ à²žà²à²à³à²°à²¹à²£à³à²¯à²²à³à²²à²¿
+à²®à²Ÿà²¹à²¿à²€à²¿ à²¹à³à²à³ à²ªà²¡à³à²¯à³à²µ
+à²¬à²à³à²à²³à³:}
+
+_textsimplehelpheading_ [l=kn] {à²žà²à²à³à²°à²¹à²£à³à²¯à²²à³à²²à²¿ _collectionname_ 
+à²®à²Ÿà²¹à²¿à²€à²¿ à²¹à³à²à³
+à²ªà²¡à³à²¯à³à²µà³à²Šà³}
+
+_texthelpscope_ [l=kn] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>à²ªà³à²°à²¶à³à²šà³à²à²³
+à²à²Šà³à²Šà³à²¶</h3>
+
+<p>
+à²šà³à²µà³ à²
+à²šà³à²¶à³à²§à²šà³à²à³ 
+à²à²²à³à²²à²Ÿ à²žà²à²à³à²°à²¹à²£à³à²¯
+à²¬à³à²°à³ à²¬à³à²°à³ à²žà³à²à²¿à²à³à²à²³à²šà³à²šà³
+à²à²°à²¿à²žà²¿à²à³à²³à³à²³à²¬à²¹à³à²Šà³.
+à²à²Šà²Ÿà²¹à²°à²£à³à²à³ à²²à³à²à²à²° à²žà³à²à²¿à²à³
+, à²¶à³à²°à³à²·à²¿à²à³à²à²³ à²žà³à²à²¿à²à³, à²ªà²Ÿà² à²à²³
+à²žà³à²à²¿à²à³ à²
+à²¥à²µà²Ÿ à²µà²à³à²¯à²µà³à²à²Šà²à²³
+à²žà³à²à²¿à²à³à²à²³à³. 
+à²žà²Ÿà²®à²Ÿà²šà³à²¯à²µà²Ÿà²à²¿
+à²Šà²Ÿà²à²²à³ à²ªà³à²°à³à²€à²¿ à²žà²°à²¿ à²¹à³à²à²Šà²¿à²Šà²°à³
+à²žà²Ÿà²à³, à²à²²à³à²²à²¿ à²¯à²Ÿà²µ à²žà³à²à²¿à²à³à²à²³à²šà³à²šà³
+à²ªà²°à²¿à²à²£à²¿à²žà²²à²Ÿà²à³à²µà³à²Šà²¿à²²à³à²².
+<p>à²à²à²Šà³ à²µà³à²³à³
+à²Šà²Ÿà²à²²à³à²à²³à³
+à²ªà³à²žà³à²€à²à²à²³à²Ÿà²à²¿à²Šà³à²Šà²²à³à²²à²¿,
+à²
+à²µà³à²à²³à²šà³à²šà³ à²žà²°à²¿à²¯à²Ÿà²Š
+à²à²Ÿà²à²Šà²²à³à²²à²¿
+à²€à³à²°à³à²¯à²Ÿà²²à²Ÿà²à³à²€à³à²€à²Šà³.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/kazakh.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/kazakh.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/kazakh.dm	(revision 10506)
@@ -0,0 +1,1250 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Kazakh Language text and icon macros 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=kk] {ÐÐµÑÐžÐŸÐŽÐžÐºÐ°}
+_textsource_ [l=kk] {ÐÒ±Ð»Ð°Ò: }
+_textdate_ [l=kk] {ÐÐ°ÑÐžÑÐ»Ð°ÐœÑ ÐÐ°ÑÐ°ÑÑ: }
+_textnumpages_ [l=kk] {ÐÐµÑ ÐÐŸÐŒÐµÑÑ}
+
+_textsignin_ [l=kk] {Ð°Ð²ÑÐŸÑÐžÐ·Ð°ÑÐžÑ}
+
+_textdefaultcontent_ [l=kk] {ÒÐ°Ð¶ÐµÑÑÑ Ð±ÐµÑ ÑÐ°Ð±ÑÐ»ÐŒÐ°ÐŽÑ. ÐÑÐ°ÑÐ·ÐµÑÑÒ£ÑÐ·ÐŽÐµÐ³Ñ 'back' ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ ÐœÐµÐŒÐµÑÐµ  
+ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°ÐœÑÒ£ Ò¯Ð¹ Ð±ÐµÑÑÐœÐµ ÑÑÐ»ÑÐµÐŒÐµÑÑÐœ Ð±Ð°ÑÑÒ£ÑÐ·.}
+
+_textdefaulttitle_ [l=kk] {ÒÐ°ÑÐµ}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=kk] {ÐÒ±Ð» ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑÒ£  _about:numdocs_ Ð±Ð°Ñ. 
+Ð¡ÐŸÒ£ÒÑ Ó©Ð·Ð³ÐµÑÑÑÑÐµÑ _about:builddate_ ÐºÒ¯Ðœ Ð±Ò±ÑÑÐœ Ð¶Ð°ÑÐ°Ð»ÒÐ°Ðœ.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=kk] {<p>ÐÒ±Ð»  ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° _numdocs_ If_(â_numdocs_â eq â1â, ÒÒ±Ð¶Ð°Ñ, ÒÒ±Ð¶Ð°ÑÑÐ°Ñ), Ð±Ð°ÑÐ»ÑÒÑ _numbytes_. 
+<p><a href=â_httppagex_(bsummary)â>ÐÑÑÐœÐŽÐ° Ð±Ð°ÑÑÒ£ÑÐ·<\a> ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ Ò¯ÑÐŽÑÑÑÐœÑÒ£ ÑÒ¯Ð¹ÑÐœÑÐœ ÒÐ°ÑÐ°Ñ Ò¯ÑÑÐœ.}
+
+_textimagecollection_ [l=kk] {}
+_textimageabout_ [l=kk] {ÐÑÐŸÐ³ÑÐ°ÐŒÐŒÐ° Ð¶Ð°Ð¹ÑÐœÐŽÐ°}
+_textimagehome_ [l=kk] {Ò®Ð¹ Ð±ÐµÑÑ}
+_textimagehelp_ [l=kk] {ÐÓ©ÐŒÐµÐº Ð±ÐµÑÑ}
+_textimagepref_ [l=kk] {ÐÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑ}
+_textimagegreenstone_ [l=kk] {Greenstone ÑÐ»ÐµÐºÑÑÐŸÐœÐŽÑÒ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°ÑÑ}
+# -- Missing translation: _textimageusab_
+
+_textimagesearch_ [l=kk] {ÐÐ·ÐŽÐµÑ}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=kk] {ÐÑÐ°ÑÐ»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+_textimageCreator_ [l=kk] {ÐÐ²ÑÐŸÑÐ»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+_textimageSubject_ [l=kk] {ÐÐ°ÑÑÑÒ ÐºÓ©ÑÑÐµÑÐºÑÑ}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=kk] {ÐÐ°ÑÐ°Ð»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+# -- Missing translation: _textimageSource_
+_textimageLanguage_ [l=kk] {Ð¢ÑÐ»ÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=kk] {Ò°Ð¹ÑÐŒÐŽÐ°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+# -- Missing translation: _textimageKeyword_
+_textimageHowto_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»Ñ ÑÓÑÑÐ»Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+_textimageList_ [l=kk] {ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑÒ£ Ð¶Ð°Ð»Ð¿Ñ ÑÑÐ·ÑÐŒÑ}
+_textimageSeries_ [l=kk] {ÐšÑÒÐ°ÑÑÐ»ÑÐŒ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+_textimageTo_ [l=kk] {ÐÐŽÑÐµÑÐ°ÑÑÐ°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+_textimageFrom_ [l=kk] {ÐÑÐ±ÐµÑÑÑÑÐ»ÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+_textimageTopic_ [l=kk] {Ð¢Ð°ÒÑÑÑÐ¿ÑÐ°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+_textimageBrowse_ [l=kk] {ÒÐ°ÑÐ°Ñ}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=kk] {ÐÐµÑÑÐŸÐœÐ°Ð»ÐžÐ»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+_textimageAcronym_ [l=kk] {ÐÐºÑÐŸÐœÐžÐŒÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+_textimagePhrase_ [l=kk] {Ð€ÑÐ°Ð·Ð°Ð»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+# -- Missing translation: _textimageArtist_
+# -- Missing translation: _textimageVolume_
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=kk] {ÐÐ·ÐŽÐµÑ}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=kk] {ÐÑÐ°ÑÐ»Ð°Ñ Ð-Ð¯}
+_texticontabCreatorgreen_ [l=kk] {ÐÐ²ÑÐŸÑÐ»Ð°Ñ Ð-Ð¯}
+_texticontabSubjectgreen_ [l=kk] {ÐÓ©ÑÑÐµÑÐºÑÑ}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=kk] {ÐÐ°ÑÐ°Ð»Ð°Ñ}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+# -- Missing translation: _texticontabSourcegreen_
+_texticontabLanguagegreen_ [l=kk] {Ð¢ÑÐ»ÐŽÐµÑ}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=kk] {Ò°Ð¹ÑÐŒÐŽÐ°Ñ}
+# -- Missing translation: _texticontabKeywordgreen_
+_texticontabhowgreen_ [l=kk] {Ð¢ÓÑÑÐ»ÐŽÐµÑ}
+_texticontabseriesgreen_ [l=kk] {ÐšÑÒÐ°ÑÑÐ»ÑÐŒÐŽÐ°Ñ}
+_texticontablistgreen_ [l=kk] {Ð¢ÑÐ·ÑÐŒ}
+_texticontabtogreen_ [l=kk] {ÐÑÐŒÐ³Ðµ}
+_texticontabfromgreen_ [l=kk] {ÐÑÐŒÐœÐµÐœ}
+_texticontabtopicgreen_ [l=kk] {Ð¢Ð°ÒÑÑÑÐ¿ÑÐ°Ñ}
+_texticontabbrwsegreen_ [l=kk] {ÒÐ°ÑÐ°Ñ}
+# -- Missing translation: _texticontabCollagegreen_
+# -- Missing translation: _texticontabbrowsgreen_
+_texticontabPeoplegreen_ [l=kk] {ÐÐµÑÑÐŸÐœÐ°Ð»ÐžÐ»ÐµÑ Ð-Ð¯}
+_texticontabAcronymgreen_ [l=kk] {ÐÐºÑÐŸÐœÐžÐŒÐŽÐµÑ}
+_texticontabPhrasegreen_ [l=kk] {Ð€ÑÐ°Ð·Ð°Ð»Ð°Ñ}
+# -- Missing translation: _texticontabArtistgreen_
+# -- Missing translation: _texticontabVolumegreen_
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=kk] {ÒÒ±Ð¶Ð°ÑÑÑ ÒÐ°ÑÐ°Ñ}
+_texticonclosedbook_ [l=kk] {ÒÒ±Ð¶Ð°ÑÑÑ ÐÑÑ Ð¶ÓÐœÐµ ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ ÒÐ°ÑÐ°Ñ}
+_texticonnext_ [l=kk] {ÐÐµÐ»ÐµÑÑ Ð±Ó©Ð»ÑÐŒ}
+_texticonprev_ [l=kk] {ÐÐ»ÐŽÑÒ£ÒÑ Ð±Ó©Ð»ÑÐŒ}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=kk] {MIDI ÒÒ±Ð¶Ð°ÑÑÐœ ÒÐ°ÑÐ°Ñ}
+_texticonmsword_ [l=kk] {Microsoft Word ÒÒ±Ð¶Ð°ÑÑÐœ ÒÐ°ÑÐ°Ñ}
+_texticonmp3_ [l=kk] {MP3 ÒÒ±Ð¶Ð°ÑÑÐœ ÒÐ°ÑÐ°Ñ}
+_texticonpdf_ [l=kk] {PDF ÒÒ±Ð¶Ð°ÑÑÐœ ÒÐ°ÑÐ°Ñ}
+_texticonps_ [l=kk] {PS ÒÒ±Ð¶Ð°ÑÑÐœ ÒÐ°ÑÐ°Ñ}
+_texticonppt_ [l=kk] {PPT ÒÒ±Ð¶Ð°ÑÑÐœ ÒÐ°ÑÐ°Ñ}
+_texticonrtf_ [l=kk] {RTF ÒÒ±Ð¶Ð°ÑÑÐœ ÒÐ°ÑÐ°Ñ}
+_texticonxls_ [l=kk] {XLS ÒÒ±Ð¶Ð°ÑÑÐœ ÒÐ°ÑÐ°Ñ}
+
+_page_ [l=kk] {ÐÐµÑ}
+_pages_ [l=kk] {ÐÐµÑÑÐµÑ}
+_of_ [l=kk] {ÑÐµÐœ }
+_vol_ [l=kk] {Ð¢ÐŸÐŒ}
+_num_ [l=kk] {ÐÓ©ÐŒÑÑ}
+
+_textmonth00_ [l=kk] {}
+_textmonth01_ [l=kk] {ÒÐ°Ò£ÑÐ°Ñ}
+_textmonth02_ [l=kk] {ÐÒÐ¿Ð°Ðœ}
+_textmonth03_ [l=kk] {ÐÐ°ÑÑÑÐ·}
+_textmonth04_ [l=kk] {ÐÓ©ÐºÐµÐº}
+_textmonth05_ [l=kk] {ÐÐ°ÐŒÑÑ}
+_textmonth06_ [l=kk] {ÐÐ°ÑÑÑÐŒ}
+_textmonth07_ [l=kk] {ÐšÑÐ»ÐŽÐµ}
+_textmonth08_ [l=kk] {Ð¢Ð°ÐŒÑÐ·}
+_textmonth09_ [l=kk] {ÒÑÑÐºÒ¯Ð¹ÐµÐº}
+_textmonth10_ [l=kk] {ÒÐ°Ð·Ð°Ðœ}
+_textmonth11_ [l=kk] {ÒÐ°ÑÐ°ÑÐ°}
+_textmonth12_ [l=kk] {ÐÐµÐ»ÑÐŸÒÑÐ°Ðœ}
+
+_textdocument_ [l=kk] {ÒÒ±Ð¶Ð°Ñ}
+_textsection_ [l=kk] {ÐÓ©Ð»ÑÐŒ}
+_textparagraph_ [l=kk] {ÐÐ±Ð·Ð°Ñ}
+
+_magazines_ [l=kk] {ÐÑÑÐœÐ°Ð»ÐŽÐ°Ñ}
+
+_nzdlpagefooter_ [l=kk] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐÐÐ¡Ð«" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=kk] {_httpimg_/kk/chomeof.gif}
+_httpiconchomeon_ [l=kk] {_httpimg_/kk/chomeon.gif}
+
+## "ÐÓšÐÐÐ" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=kk] {_httpimg_/kk/chelpof.gif}
+_httpiconchelpon_ [l=kk] {_httpimg_/kk/chelpon.gif}
+
+## "ÐÒ®ÐÐÐÐ ÐÐÐÐ¢ÐÐ Ð£ÐÐÐ " ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=kk] {_httpimg_/kk/cprefof.gif}
+_httpiconcprefon_ [l=kk] {_httpimg_/kk/cprefon.gif}
+
+# -- Missing translation: cusab
+# -- Missing translation: _httpiconcusabof_
+# -- Missing translation: _httpiconcusabon_
+
+
+## "ÑÐ·ÐŽÐµÑ" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=kk] {_httpimg_/kk/tsrchgr.gif}
+_httpicontsrchof_ [l=kk] {_httpimg_/kk/tsrchof.gif}
+_httpicontsrchon_ [l=kk] {_httpimg_/kk/tsrchon.gif}
+_widthtsrchx_ [l=kk] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "Ð°ÑÐ°ÑÐ»Ð°Ñ Ð°-Ñ" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=kk] {_httpimg_/kk/ttitlgr.gif}
+_httpiconttitleof_ [l=kk] {_httpimg_/kk/ttitlof.gif}
+_httpiconttitleon_ [l=kk] {_httpimg_/kk/ttitlon.gif}
+_widthttitlex_ [l=kk] {103}
+
+# Not true DC, kept for legacy reasons
+## "Ð°Ð²ÑÐŸÑÐ»Ð°Ñ Ð°-Ñ" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=kk] {_httpimg_/kk/tauthgr.gif}
+_httpicontcreatof_ [l=kk] {_httpimg_/kk/tauthof.gif}
+_httpicontcreaton_ [l=kk] {_httpimg_/kk/tauthon.gif}
+_widthtcreatx_ [l=kk] {115}
+
+## "ÐºÓ©ÑÑÐµÑÐºÑÑ" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=kk] {_httpimg_/kk/tsubjgr.gif}
+_httpicontsubjon_ [l=kk] {_httpimg_/kk/tsubjon.gif}
+_httpicontsubjof_ [l=kk] {_httpimg_/kk/tsubjof.gif}
+_widthtsubjx_ [l=kk] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "ÐŽÐ°ÑÐ°Ð»Ð°Ñ" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=kk] {_httpimg_/kk/tdategr.gif}
+_httpicontdateof_ [l=kk] {_httpimg_/kk/tdateof.gif}
+_httpicontdateon_ [l=kk] {_httpimg_/kk/tdateon.gif}
+_widthtdatex_ [l=kk] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: tsrc
+# -- Missing translation: _httpicontsrcgr_
+# -- Missing translation: _httpicontsrcof_
+# -- Missing translation: _httpicontsrcon_
+# -- Missing translation: _widthtsrcx_
+
+## "Ð°ÑÐ°ÑÐ»Ð°Ñ" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=kk] {_httpimg_/kk/tlanggr.gif}
+_httpicontlangon_ [l=kk] {_httpimg_/kk/tlangon.gif}
+_httpicontlangof_ [l=kk] {_httpimg_/kk/tlangof.gif}
+_widthtlangx_ [l=kk] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "ÑÑÒÐ°ÑÑÐ»ÑÐŒÐŽÐ°Ñ" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=kk] {_httpimg_/kk/tsergr.gif}
+_httpicontserof_ [l=kk] {_httpimg_/kk/tserof.gif}
+_httpicontseron_ [l=kk] {_httpimg_/kk/tseron.gif}
+_widthtserx_ [l=kk] {138}
+
+## "ÐºÑÐŒÐ³Ðµ" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=kk] {_httpimg_/kk/ttogr.gif}
+_httpiconttoon_ [l=kk] {_httpimg_/kk/ttoon.gif}
+_httpiconttoof_ [l=kk] {_httpimg_/kk/ttoof.gif}
+_widthttox_ [l=kk] {87}
+
+## "ÐºÑÐŒÐœÐµÐœ" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=kk] {_httpimg_/kk/tfromgr.gif}
+_httpicontfromon_ [l=kk] {_httpimg_/kk/tfromon.gif}
+_httpicontfromof_ [l=kk] {_httpimg_/kk/tfromof.gif}
+_widthtfromx_ [l=kk] {87}
+
+## "Ò±Ð¹ÑÐŒÐŽÐ°Ñ" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=kk] {_httpimg_/kk/torggr.gif}
+_httpicontorgon_ [l=kk] {_httpimg_/kk/torgon.gif}
+_httpicontorgof_ [l=kk] {_httpimg_/kk/torgof.gif}
+_widthtorgx_ [l=kk] {87}
+
+## "ÑÓÑÑÐ»ÐŽÐµÑ" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=kk] {_httpimg_/kk/thowgr.gif}
+_httpiconthowon_ [l=kk] {_httpimg_/kk/thowon.gif}
+_httpiconthowof_ [l=kk] {_httpimg_/kk/thowof.gif}
+_widththowx_ [l=kk] {87}
+
+## "ÑÐ°ÒÑÑÑÐ¿ÑÐ°Ñ" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=kk] {_httpimg_/kk/ttopicgr.gif}
+_httpiconttopicon_ [l=kk] {_httpimg_/kk/ttopicon.gif}
+_httpiconttopicof_ [l=kk] {_httpimg_/kk/ttopicof.gif}
+_widthttopicx_ [l=kk] {106}
+
+## "ÑÑÐ·ÑÐŒ" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=kk] {_httpimg_/kk/tbrwsegr.gif}
+_httpicontbrwseon_ [l=kk] {_httpimg_/kk/tbrwseon.gif}
+_httpicontbrwseof_ [l=kk] {_httpimg_/kk/tbrwseof.gif}
+_widthtbrwsex_ [l=kk] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐ»ÐµÑ" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=kk] {_httpimg_/kk/tpeopgr.gif}
+_httpicontpeopof_ [l=kk] {_httpimg_/kk/tpeopof.gif}
+_httpicontpeopon_ [l=kk] {_httpimg_/kk/tpeopon.gif}
+_widthtpeopx_ [l=kk] {125}
+
+## "Ð°ÐºÑÐŸÐœÐžÐŒÐŽÐµÑ" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=kk] {_httpimg_/kk/tacrogr.gif}
+_httpicontacroof_ [l=kk] {_httpimg_/kk/tacroof.gif}
+_httpicontacroon_ [l=kk] {_httpimg_/kk/tacroon.gif}
+_widthtacrox_ [l=kk] {108}
+
+## "ÑÑÐ°Ð·Ð°Ð»Ð°Ñ" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=kk] {_httpimg_/kk/tphrsegr.gif}
+_httpicontphrseof_ [l=kk] {_httpimg_/kk/tphrseof.gif}
+_httpicontphrseon_ [l=kk] {_httpimg_/kk/tphrseon.gif}
+_widthtphrsex_ [l=kk] {87}
+
+# -- Missing translation: tartst
+# -- Missing translation: _httpicontartstgr_
+# -- Missing translation: _httpicontartstof_
+# -- Missing translation: _httpicontartston_
+# -- Missing translation: _widthtartstx_
+
+# -- Missing translation: tkw
+# -- Missing translation: _httpicontkwgr_
+# -- Missing translation: _httpicontkwof_
+# -- Missing translation: _httpicontkwon_
+# -- Missing translation: _widthtkwx_
+
+# -- Missing translation: tvol
+# -- Missing translation: _httpicontvolgr_
+# -- Missing translation: _httpicontvolof_
+# -- Missing translation: _httpicontvolon_
+# -- Missing translation: _widthtvolx_
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "ÐºÓ©ÐŒÐµÐº" ## green_title ## h_help ##
+_httpiconhhelp_ [l=kk] {_httpimg_/kk/h\_help.gif}
+_widthhhelp_ [l=kk] {200}
+_heighthhelp_ [l=kk] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=kk] {ÐÐ·ÐŽÐ°Ð¿ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¶Ð°Ð¹Ð»Ñ}
+
+_textsubcols1_ [l=kk] {<p>ÐÐµÑÑÐ»Ð³ÐµÐœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° _1_ ÑÑÐºÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±Ð°Ñ:
+<blockquote>}
+
+_textsubcols2_ [l=kk] {</blockquote>
+Ð¡ÑÐ· ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑ Ð±ÐµÑÑÐœÐŽÐµ ÒÐ°Ð·ÑÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»ÑÐ¿ Ð¶Ò¯ÑÐ³ÐµÐœ ÑÑÐºÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ ÑÑÐ·ÑÐŒÑÐœ ÒÐ°ÑÐ°Ð¿/Ó©Ð·Ð³ÐµÑÑÐµ Ð°Ð»Ð°ÑÑÐ·.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÑÐžÐ¿Ð°ÑÑÐ°ÐŒÐ°" ## green_title ## h_about ##
+_httpiconhabout_ [l=kk] {_httpimg_/kk/h\_about.gif}
+_widthhabout_ [l=kk] {200}
+_heighthabout_ [l=kk] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=kk] {ÐÑÐ°ÑÐ»Ð°Ñ Ð-Ð¯}
+_texticonhcreat_ [l=kk] {ÐÐ²ÑÐŸÑÐ»Ð°Ñ Ð-Ð¯}
+_texticonhsubj_ [l=kk] {ÐÓ©ÑÑÐµÑÐºÑÑ}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=kk] {ÐÐ°ÑÐ°Ð»Ð°Ñ}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+# -- Missing translation: _texticonhsrc_
+_texticonhlang_ [l=kk] {Ð¢ÑÐ»ÐŽÐµÑ}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=kk] {ÐÑÐŒÐ³Ðµ}
+_texticonhfrom_ [l=kk] {ÐÑÐŒÐœÐµÐœ}
+_texticonhser_ [l=kk] {ÐšÑÒÐ°ÑÑÐ»ÑÐŒÐŽÐ°Ñ}
+_texticonhhow_ [l=kk] {Ð¢ÓÑÑÐ»ÐŽÐµÑ}
+_texticonhorg_ [l=kk] {Ò°Ð¹ÑÐŒÐŽÐ°Ñ}
+_texticonhbrwse_ [l=kk] {ÒÐ°ÑÐ°Ñ}
+# -- Missing translation: _texticonhbrows_
+_texticonhpeople_ [l=kk] {ÐÐµÑÑÐŸÐœÐ°Ð»ÐžÐ»ÐµÑ Ð-Ð¯}
+_texticonhacronym_ [l=kk] {ÐÐºÑÐŸÐœÐžÐŒÐŽÐµÑ}
+_texticonhphrases_ [l=kk] {Ð€ÑÐ°Ð·Ð°Ð»Ð°Ñ}
+# -- Missing translation: _texticonhartist_
+# -- Missing translation: _texticonhkw_
+# -- Missing translation: _texticonhvol_
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=kk] {ÐÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ° Ð±Ó©Ð»ÑÐŒÑÐœ Ð¶Ð°Ð±Ñ}
+_texticonclosedbookshelf_ [l=kk] {ÐÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ° Ð±Ó©Ð»ÑÐŒÑÐœ ÐÑÑ Ð¶ÓÐœÐµ ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ ÒÐ°ÑÐ°Ñ}
+_texticonopenbook_ [l=kk] {ÐÑÑÐ°Ð¿ÑÑ Ð¶Ð°Ð±Ñ}
+_texticonclosedfolder_ [l=kk] {ÐÐ°Ð¿ÐºÐ°ÐœÑ ÐÑÑ Ð¶ÓÐœÐµ ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ ÒÐ°ÑÐ°Ñ}
+_texticonclosedfolder2_ [l=kk] {ÐÑÐºÑ Ð±Ó©Ð»ÑÐŒÐŽÑ Ð°ÑÑ: }
+_texticonopenfolder_ [l=kk] {ÐÐ°Ð¿ÐºÐ°ÐœÑ Ð¶Ð°Ð±Ñ}
+_texticonopenfolder2_ [l=kk] {ÐÑÐºÑ Ð±Ó©Ð»ÑÐŒÐŽÑ Ð¶Ð°Ð±Ñ: }
+_texticonsmalltext_ [l=kk] {ÐÓÑÑÐœ Ð±Ó©Ð»ÑÐŒÑÐœ ÒÐ°ÑÐ°Ñ}
+_texticonsmalltext2_ [l=kk] {ÐÓÑÑÐœÐŽÑ ÒÐ°ÑÐ°Ñ: }
+_texticonpointer_ [l=kk] {ÐÒÑÐŒÐŽÐ°ÒÑ Ð±Ó©Ð»ÑÐŒ}
+_texticondetach_ [l=kk] {ÐÐµÑÑÑ Ð¶Ð°Ò£Ð° ÑÐµÑÐµÐ·ÐµÐŽÐµ Ð°ÑÑ}
+_texticonhighlight_ [l=kk] {ÐÐ·ÐŽÐµÐ»ÐµÑÑÐœ ÑÐµÑÐŒÐžÐœÐŽÐµÑÐŽÑ Ð±Ó©Ð»ÑÐ¿ ÐºÓ©ÑÑÐµÑÑ}
+_texticonnohighlight_ [l=kk] {ÐÐ·ÐŽÐµÐ»ÐµÑÑÐœ ÑÐµÑÐŒÐžÐœÐŽÐµÑÐŽÑ Ð±Ó©Ð»ÑÐ¿ ÐºÓ©ÑÑÐµÑÐ¿ÐµÑ}
+_texticoncontracttoc_ [l=kk] {ÐÐ°Ð·ÐŒÒ±ÐœÐŽÑ ÐŸÑÐ°Ñ}
+_texticonexpandtoc_ [l=kk] {ÐÐ°ÑÐ»ÑÒ ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ Ð°ÑÑÐ¿ ÐºÓ©ÑÑÐµÑÑ}
+_texticonexpandtext_ [l=kk] {ÐÐ°ÑÐ»ÑÒ ÐŒÓÑÑÐœÐŽÑ ÐºÓ©ÑÑÐµÑÑ}
+_texticoncontracttext_ [l=kk] {Ð¢ÐµÐº Ð±Ó©Ð»ÑÐ¿ ÐºÓ©ÑÑÐµÑÑÐ»Ð³ÐµÐœ Ð±Ó©Ð»ÑÐŒÐŽÐµÑ Ò¯ÑÑÐœ ÐŒÓÑÑÐœÐŽÑ ÐºÓ©ÑÑÐµÑÑ}
+_texticonwarning_ [l=kk] {<b>ÐÐµÐ¹ÑÐœ ÒÐŸÐ¹ÑÒ£ÑÐ·: </b>}
+_texticoncont_ [l=kk] {Ð¶Ð°Ð»ÒÐ°ÑÑÑÑÐ°Ð¹ÑÐœ Ð±Ð°?}
+
+_textltwarning_ [l=kk] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_ ÐÐ°ÑÐ»ÑÒ ÐŒÓÑÑÐœÐŽÑ Ð±ÐµÐ¹ÐœÐµÐ»ÐµÑ _imagecont_ Ð±ÑÐ°ÑÐ·ÐµÑÑÐœÐŽÐµ Ð±ÐµÐ¹ÐœÐµÐ»ÐµÐœÐµÑÑÐœ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÐŽÑÒ£ ÐºÓ©Ð±ÐµÑÑÐœÐµ ÓÐºÐµÐ»ÑÐ¿ ÑÐŸÒÐ°ÐŽÑ.
+</td></tr></table></center>
+}
+
+_textgoto_ [l=kk] {Ð±ÐµÑÐºÐµ ÐºÓ©ÑÑ}
+_textintro_ [l=kk] {<i>(ÐºÑÑÑÑÐ¿Ðµ)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "Ð°ÑÐ°ÑÐ»Ð°Ñ Ð°-Ñ" ## green_title ## h_title ##
+_httpiconhtitle_ [l=kk] {_httpimg_/kk/h\_title.gif}
+_widthhtitle_ [l=kk] {200}
+_heighthtitle_ [l=kk] {57}
+
+# Not true DC, kept for legacy reasons
+## "Ð°Ð²ÑÐŸÑÐ»Ð°Ñ Ð°-Ñ" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=kk] {_httpimg_/kk/h\_auth.gif}
+_widthhcreat_ [l=kk] {200}
+_heighthcreat_ [l=kk] {57}
+
+## "ÐºÓ©ÑÑÐµÑÐºÑÑ" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=kk] {_httpimg_/kk/h\_subj.gif}
+_widthhsubj_ [l=kk] {200}
+_heighthsubj_ [l=kk] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "ÐŽÐ°ÑÐ°Ð»Ð°Ñ" ## green_title ## h_date ##
+_httpiconhdate_ [l=kk] {_httpimg_/kk/h\_date.gif}
+_widthhdate_ [l=kk] {200}
+_heighthdate_ [l=kk] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_src
+# -- Missing translation: _httpiconhsrc_
+# -- Missing translation: _widthhsrc_
+# -- Missing translation: _heighthsrc_
+
+## "ÑÑÐ»ÐŽÐµÑ" ## green_title ## h_lang ##
+_httpiconhlang_ [l=kk] {_httpimg_/kk/h\_lang.gif}
+_widthhlang_ [l=kk] {200}
+_heighthlang_ [l=kk] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "ÐºÑÐŒÐ³Ðµ" ## green_title ## h_to ##
+_httpiconhto_ [l=kk] {_httpimg_/kk/h\_to.gif}
+_widthhto_ [l=kk] {200}
+_heighthto_ [l=kk] {57}
+
+## "ÐºÑÐŒÐœÐµÐœ" ## green_title ## h_from ##
+_httpiconhfrom_ [l=kk] {_httpimg_/kk/h\_from.gif}
+_widthhfrom_ [l=kk] {200}
+_heighthfrom_ [l=kk] {57}
+
+## "ÑÑÒÐ°ÑÑÐ»ÑÐŒÐŽÐ°Ñ" ## green_title ## h_ser ##
+_httpiconhser_ [l=kk] {_httpimg_/kk/h\_ser.gif}
+_widthhser_ [l=kk] {200}
+_heighthser_ [l=kk] {57}
+
+## "ÑÓÑÑÐ»ÐŽÐµÑ" ## green_title ## h_how ##
+_httpiconhhow_ [l=kk] {_httpimg_/kk/h\_how.gif}
+_widthhhow_ [l=kk] {200}
+_heighthhow_ [l=kk] {57}
+
+## "ÑÐ°ÒÑÑÑÐ¿ÑÐ°Ñ" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=kk] {_httpimg_/kk/h\_topic.gif}
+_widthhtopic_ [l=kk] {200}
+_heighthtopic_ [l=kk] {57}
+
+## "Ò±Ð¹ÑÐŒÐŽÐ°Ñ" ## green_title ## h_org ##
+_httpiconhorg_ [l=kk] {_httpimg_/kk/h\_org.gif}
+_widthhorg_ [l=kk] {250}
+_heighthorg_ [l=kk] {57}
+
+## "ÑÑÐ·ÑÐŒ" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=kk] {_httpimg_/kk/h\_brwse.gif}
+_widthhbrwse_ [l=kk] {200}
+_heighthbrwse_ [l=kk] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐ»ÐµÑ" ## green_title ## h_people ##
+_httpiconhpeople_ [l=kk] {_httpimg_/kk/h\_people.gif}
+_widthhpeople_ [l=kk] {200}
+_heighthpeople_ [l=kk] {57}
+
+## "Ð°ÐºÑÐŸÐœÐžÐŒÐŽÐµÑ" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=kk] {_httpimg_/kk/h\_acro.gif}
+_widthhacronym_ [l=kk] {200}
+_heighthacronym_ [l=kk] {57}
+
+## "ÑÑÐ°Ð·Ð°Ð»Ð°Ñ" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=kk] {_httpimg_/kk/h\_phrse.gif}
+_widthhphrse_ [l=kk] {200}
+_heighthphrse_ [l=kk] {57}
+
+# -- Missing translation: h_artist
+# -- Missing translation: _httpiconhartist_
+# -- Missing translation: _widthhartist_
+# -- Missing translation: _heighthartist_
+
+# -- Missing translation: h_kw
+# -- Missing translation: _httpiconhkw_
+# -- Missing translation: _widthhkw_
+# -- Missing translation: _heighthkw_
+
+# -- Missing translation: h_vol
+# -- Missing translation: _httpiconhvol_
+# -- Missing translation: _widthhvol_
+# -- Missing translation: _heighthvol_
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+## "ÐÐÐÒÐÐ¡Ð¢Ð«Ð ÐÐÐ«Ð ÐÐ?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=kk] {_httpimg_/kk/contof.gif}
+_httpiconconton_ [l=kk] {_httpimg_/kk/conton.gif}
+
+## "ÐÐÐ ÐÐ«Ò\nÐÓÐ¢ÐÐ" ## document_button ## eallt ##
+_httpiconealltof_ [l=kk] {_httpimg_/kk/ealltof.gif}
+_httpiconeallton_ [l=kk] {_httpimg_/kk/eallton.gif}
+
+## "ÐÐ ÐÐ£\nÐÐÐÐÒ°Ð" ## document_button ## econc ##
+_httpiconeconcof_ [l=kk] {_httpimg_/kk/econcof.gif}
+_httpiconeconcon_ [l=kk] {_httpimg_/kk/econcon.gif}
+
+## "ÐÐÒ¢Ð\nÐ¢ÐÐ ÐÐÐ" ## document_button ## edtch ##
+_httpiconedtchof_ [l=kk] {_httpimg_/kk/edtchof.gif}
+_httpiconedtchon_ [l=kk] {_httpimg_/kk/edtchon.gif}
+
+## "ÐÐÐ®\nÐÐÐÐÒ°Ð" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=kk] {_httpimg_/kk/eexpcof.gif}
+_httpiconeexpcon_ [l=kk] {_httpimg_/kk/eexpcon.gif}
+
+## "ÐÐ ÐÐ£\nÐÓÐ¢ÐÐ" ## document_button ## etsec ##
+_httpiconetsecof_ [l=kk] {_httpimg_/kk/etsecof.gif}
+_httpiconetsecon_ [l=kk] {_httpimg_/kk/etsecon.gif}
+
+## "ÐÓšÐÐ£\nÐ¡ÐÐÐÐ" ## document_button ## ehl ##
+_httpiconehlof_ [l=kk] {_httpimg_/kk/ehlof.gif}
+_httpiconehlon_ [l=kk] {_httpimg_/kk/ehlon.gif}
+
+## "ÐÓšÐÐ£ÐÐ ÐÐÐ«Ð\nÐ¢ÐÐ¡Ð¢ÐÐ£" ## document_button ## enhl ##
+_httpiconenhlof_ [l=kk] {_httpimg_/kk/enhlof.gif}
+_httpiconenhlon_ [l=kk] {_httpimg_/kk/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=kk] {_If_(_thislast_,ÐœÓÑÐžÐ¶ÐµÐ»ÐµÑÑ _thisfirst_ - _thislast_ Ð¿ÐŸÐžÑÐºÐ° Ð¿ÐŸ Ð·Ð°Ð¿ÑÐŸÑÑ: _cgiargq_,Ð¡Ò±ÑÐ°ÐœÑÐŒ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑ: _cgiargq_)}
+_textnoquerytitle_ [l=kk] {ÐÓ©ÐŒÐµÐº Ð±ÐµÑÑ}
+
+_texticonthispage_ [l=kk] {ÐÐ·ÐŽÐµÑ}
+_textsome_ [l=kk] {ÐºÐµÐ¹Ð±ÑÑ}
+_textall_ [l=kk] {Ð±Ð°ÑÐ»ÑÒÑ}
+_textboolean_ [l=kk] {Ð»ÐŸÐ³ÐžÐºÐ°Ð»ÑÒ}
+_textranked_ [l=kk] {Ð ÐµÑÑÐµÐ»Ð³ÐµÐœ}
+_textnatural_ [l=kk] {ÐºÓÐŽÑÐŒÐ³Ñ}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=kk] {}
+_texticonsearchhistorybar_ [l=kk] {ÐÐ·ÐŽÐµÑ ÑÐ°ÑÐžÑ
+Ñ}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=kk] {ÐÑÑ ÑÒ±ÑÐ°ÐœÑÐŒÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑ}
+_textfreqmsg1_ [l=kk] {ÐÐµÐ·ÐŽÐµÑÑ ÑÐ°ÐœÑ: }
+_textpostprocess_ [l=kk] {_If_(_quotedquery_,<br><i>ÑÐ·ÐŽÐµÑ Ò¯ÑÑÐœ Ó©Ò£ÐŽÐµÐ»ÐŽÑ _quotedquery_</i>
+)}
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=kk] {ÒÐ°ÑÐ°ÒÐ°ÐœÐŽÐ° Ð°ÑÑÑÒ}
+_textapprox_ [l=kk] {ÐÐ°Ò£ÑÐœÐŽÐ°}
+_textnodocs_ [l=kk] {Ð¡Ò±ÑÐ°ÐœÑÐŒÐŽÑ ÒÐ°ÐœÐ°ÒÐ°ÑÑÐ°ÐœÐŽÑÑÐ°ÑÑÐœ ÒÒ±Ð¶Ð°ÑÑÐ°Ñ ÑÐ°Ð±ÑÐ»ÐŒÐ°ÐŽÑ.}
+_text1doc_ [l=kk] {1 ÒÒ±Ð¶Ð°Ñ ÑÒ±ÑÐ°ÐœÑÐŒÐŽÑ ÒÐ°ÐœÐ°ÒÐ°ÑÑÐ°ÐœÐŽÑÑÐ°ÐŽÑ.}
+_textlotsdocs_ [l=kk] {ÒÒ±Ð¶Ð°ÑÑÐ°Ñ, ÑÒ±ÑÐ°ÐœÑÐŒÐŽÑ ÒÐ°ÐœÐ°ÒÐ°ÑÑÐ°ÐœÐŽÑÑÐ°ÑÑÐœ.}
+_textmatches_ [l=kk] {ÐÓÑÐžÐ¶ÐµÐ»ÐµÑ }
+_textbeginsearch_ [l=kk] {ÐÐ·ÐŽÐµÑÐŽÑ Ð±Ð°ÑÑÐ°Ñ}
+_textrunquery_ [l=kk] {Ð¡Ò±ÑÐ°ÐœÑÐŒÐŽÑ ÐŸÑÑÐœÐŽÐ°Ñ}
+_textclearform_ [l=kk] {Ð€ÐŸÑÐŒÐ°ÐœÑ ÑÐ°Ð·Ð°Ð»Ð°Ñ}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=kk] {Ð¡Ó©Ð· ÐœÐµÐŒÐµÑÐµ ÑÑÐ°Ð·Ð°}
+_textinfield_ [l=kk] {... Ð°Ð»Ð°Ò£ÐŽÐ°}
+_textfoldstem_ [l=kk] {(ÑÓ©Ð·, ÑÑÐ°Ð·Ð°)}
+
+_textadvquery_ [l=kk] {ÐœÐµÐŒÐµÑÐµ ÑÒ±ÑÐ°ÐœÑÐŒ ÐŒÓÑÑÐœÑÐœ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·:}
+_textallfields_ [l=kk] {Ð±Ð°ÑÐ»ÑÒ Ð°Ð»Ð°Ò£ÐŽÐ°Ñ}
+# -- Missing translation: _texttextonly_
+_textand_ [l=kk] {Ð¶ÓÐœÐµ}
+_textor_ [l=kk] {ÐœÐµÐŒÐµÑÐµ}
+_textandnot_ [l=kk] {Ð¶ÓÐœÐµ ÐµÐŒÐµÑ}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=kk] {ÐÐ·ÐŽÐµÑ Ð¿ÐŸ _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, ÐŽÐµÒ£Ð³ÐµÐ¹ _gselection_ Ð±ÐŸÐ¹ÑÐœÑÐ°) _If_(_nselection_, ÑÑÐ»ÑÐœÐŽÐµ  _nselection_  ),ÑÓ©Ð·ÐŽÐµÑÐŽÐµÐœ _querytypeselection_ ÑÒ±ÑÐ°ÑÑÐœ}
+
+_textadvancedsearch_ [l=kk] {ÐÐ·ÐŽÐµÑ _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, ÐŽÐµÒ£Ð³ÐµÐ¹ _gselection_ Ð±ÐŸÐ¹ÑÐœÑÐ°)_If_(_nselection_, ÑÑÐ»ÑÐœÐŽÐµ_nselection_ )  ÑÒ±ÑÐ°ÐœÑÐŒÐŽÑ  _querytypeselection_ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ¿}
+
+_textformsimplesearch_ [l=kk] {ÐÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑ _If_(_jselection_, _jselection_) _If_(_gformselection_, ÐŽÐµÒ£Ð³ÐµÐ¹ _gformselection_ Ð±ÐŸÐ¹ÑÐœÑÐ°)_If_(_nselection_, ÑÑÐ»ÑÐœÐŽÐµ _nselection_ )
+,Ð±Ð°Ñ Ð¶ÐµÑÑ _formquerytypeselection_ }
+
+_textformadvancedsearch_ [l=kk] {ÐÐ·ÐŽÐµÑ _If_(_jselection_,_jselection_) _If_(_gformselection_, ÐŽÐµÒ£Ð³ÐµÐ¹ _gformselection_ Ð±ÐŸÐ¹ÑÐœÑÐ°)_If_(_nselection_, ÑÑÐ»ÑÐœÐŽÐµ _nselection_ ) 
+Ð¶ÓÐœÐµ ÑÐµÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° Ð±ÐµÐ¹ÐœÐµÐ»ÐµÑ _formquerytypeselection_}
+
+
+# -- Missing translation: _textnojsformwarning_
+_textdatesearch_ [l=kk] {ÐÐµÑÑÐ»Ð³ÐµÐœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ Ð±ÐµÐ»Ð³ÑÐ»Ñ Ð±ÑÑ ÑÐ°ÒÑÑ Ð°ÑÐ°Ð»ÑÒÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑÐŒÐµÐœ ÒÐ°ÑÐ°Ñ ÐœÐ°ÒÑÑ ÑÐ°ÐœÐŽÑÒ ÐŽÐ°ÑÐ° Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÐ»ÑÐœÐµ Ð°Ð»Ð°ÐŽÑ.}
+_textstartdate_ [l=kk] {ÐÐ°ÑÑÐ°Ð¿ÒÑ (ÐœÐµÐŒÐµÑÐµ ÐœÐ°ÒÑÑ) ÐŽÐ°ÑÐ°:}
+_textenddate_ [l=kk] {Ð¡ÐŸÒ£ÒÑ ÐŽÐ°ÑÐ°:}
+_textbc_ [l=kk] {Ð.Ñ. ÐŽÐµÐ¹ÑÐœ}
+_textad_ [l=kk] {Ð±.Ñ.}
+_textexplaineras_ [l=kk] {Ð.Ñ. Ð¶ÓÐœÐµ Ð±.Ñ. ÐŽÐµÐ¹ÑÐœ ÑÐµÑÐŒÐžÐœÐŽÐµÑÑ âÐ±ÑÐ·ÐŽÑÒ£ ÑÑÐ°ÐŒÑÐ·â Ð¶ÓÐœÐµ âÐ±ÑÐ·ÐŽÑÒ£ ÑÑÐ°ÐŒÑÐ·ÒÐ° ÐŽÐµÐ¹ÑÐœâ ÐŽÑ Ð±ÑÐ»ÐŽÑÑÐµÐŽÑ}
+
+_textstemon_ [l=kk] {(ÑÓ©Ð· Ð¶Ð°Ð»ÒÐ°ÑÐ»Ð°ÑÑÐœ ÐµÐ»ÐµÐŒÐµÑ)}
+
+_textsearchhistory_ [l=kk] {Ð¡Ò±ÑÐ°ÐœÑÐŒ ÑÐ°ÑÐžÑ
+Ñ}
+
+#text macros for search history
+_textnohistory_ [l=kk] {ÒÐ°Ð·ÑÑÐ³Ñ ÐºÐµÐ·ÐŽÐµ ÑÒ±ÑÐ°ÐœÑÐŒ ÑÐ°ÑÐžÑ
+Ñ Ð¶ÐŸÒ}
+_texthresult_ [l=kk] {ÐºÐµÐ·ÐŽÐµÑÑÑ}
+_texthresults_ [l=kk] {ÐºÐµÐ·ÐŽÐµÑÑÐ»ÐµÑ}
+_texthallwords_ [l=kk] {Ð±Ð°ÑÐ»ÑÒ ÑÓ©Ð·ÐŽÐµÑ}
+_texthsomewords_ [l=kk] {ÐºÐµÐ¹Ð±ÑÑ ÑÓ©Ð·ÐŽÐµÑ}
+_texthboolean_ [l=kk] {Ð»ÐŸÐ³ÐžÑÐµÑÐºÐ°Ð»ÑÒ}
+_texthranked_ [l=kk] {ÑÐµÑÑÐµÐ»Ð³ÐµÐœ}
+_texthcaseon_ [l=kk] {ÑÐµÐ³ÐžÑÑÑÐŽÑ ÐµÑÐºÐµÑÐµ ÐŸÑÑÑÑÐ¿}
+_texthcaseoff_ [l=kk] {ÑÐµÐ³ÐžÑÑÑÐŽÑ ÐµÑÐºÐµÑÐŒÐµÐ¹}
+_texthstemon_ [l=kk] {Ð¶Ð°Ð»ÒÐ°ÑÐ»Ð°ÑÑÐŒÐµÐœ}
+_texthstemoff_ [l=kk] {Ð¶Ð°Ð»ÒÐ°ÑÐ»Ð°ÑÑÑÐ·}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÑÐ·ÐŽÐµÑ" ## green_title ## h_search ##
+_httpiconhsearch_ [l=kk] {_httpimg_/kk/h\_search.gif}
+_widthhsearch_ [l=kk] {200}
+_heighthsearch_ [l=kk] {57}
+
+## "ÐœÓÑÐžÐ¶ÐµÐ»ÐµÑ" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=kk] {_httpimg_/kk/qryresb.gif}
+_widthqryresb_ [l=kk] {_pagewidth_}
+_heightqryresb_ [l=kk] {17}
+
+## "ÑÐ°ÑÐžÑ
+" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=kk] {_httpimg_/kk/schhistb.gif}
+_widthsrchhistb_ [l=kk] {_pagewidth_}
+_heightsrchhistb_ [l=kk] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textprefschanged_
+# -- Missing translation: _textsetprefs_
+_textsearchprefs_ [l=kk] {ÐÐ·ÐŽÐµÑÐŽÑÒ£ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑÑ}
+_textcollectionprefs_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑÒ£ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑÑ}
+_textpresentationprefs_ [l=kk] {ÐÐœÑÐµÑÑÐµÐ¹ÑÑÑÒ£ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑÑ}
+_textpreferences_ [l=kk] {ÐÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑ}
+_textcasediffs_ [l=kk] {Ð ÐµÐ³ÐžÑÑÑÐ»ÐµÑ:}
+_textignorecase_ [l=kk] {ÑÐµÐ³ÐžÑÑÑÐ»ÐµÑÐŽÑ ÐµÐ»ÐµÐŒÐµÑ}
+_textmatchcase_ [l=kk] {Ð¶ÐŸÒÐ°ÑÒÑ Ð¶ÓÐœÐµ ÑÓ©ÐŒÐµÐœÐ³Ñ ÑÐµÐ³ÐžÑÑÑÐ»ÐµÑÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑ}
+_textwordends_ [l=kk] {Ð¡Ó©Ð·ÐŽÐµÑÐŽÑÒ£ Ð¶Ð°Ð»ÒÐ°ÑÐ»Ð°ÑÑ:}
+_textstem_ [l=kk] {ÑÓ©Ð·ÐŽÐµÑÐŽÑÒ£ Ð¶Ð°Ð»ÒÐ°ÑÐ»Ð°ÑÑÐœ ÐµÐ»ÐµÐŒÐµÑ}
+_textnostem_ [l=kk] {Ð¶Ð°Ð»ÒÐ°ÑÑ Ð±Ð°Ñ ÑÓ©Ð·ÐŽÐµÑÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑ}
+_textprefop_ [l=kk] {ÐÓ©ÑÑÐµÑÑ _maxdocoption_ ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ â ÑÐ·ÐŽÐµÑ ÐœÓÑÐžÐ¶ÐµÐ»ÐµÑÑÐœ  _hitsperpageoption_ Ð±ÐµÑÑÐµ ÒÒ±Ð¶Ð°ÑÑÐ°Ðœ.}
+_textextlink_ [l=kk] {Web-ÑÑÒ£ ÑÑÑÑÒÑ ÑÒ¯Ð¹ÑÐœÐŽÐµÑÑÐœÐµ ÐµÐœÑ}
+_textintlink_ [l=kk] {ÐÒ±Ð» ÒÒ±Ð¶Ð°Ñ Ð°Ð»ÑÐœÒÐ°Ðœ Ð¶ÐµÑ:}
+_textlanguage_ [l=kk] {ÐÐœÑÐµÑÑÐµÐ¹Ñ ÑÑÐ»Ñ:}
+_textencoding_ [l=kk] {ÐÐŸÐŽÐžÑÐŸÐ²ÐºÐ°:}
+_textformat_ [l=kk] {ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÑÐŸÑÐŒÐ°ÑÑ:}
+_textall_ [l=kk] {Ð±Ð°ÑÐ»ÑÒÑ}
+_textquerymode_ [l=kk] {Ð¡Ò±ÑÐ°ÐœÑÐŒ ÑÐžÐ¿Ñ:}
+_textsimplemode_ [l=kk] {Ð¡Ò±ÑÐ°ÐœÑÐŒÐœÑÒ£ ÒÐ°ÑÐ°Ð¿Ð°Ð¹ÑÐŒ ÑÒ¯ÑÑ}
+_textadvancedmode_ [l=kk] {Ð¡Ò±ÑÐ°ÐœÑÐŒÐœÑÒ£ ÐºÐµÒ£ÐµÐ¹ÑÑÐ»Ð³ÐµÐœ ÑÒ¯ÑÑ (! (ÐÐÐÐ¡) , & (ÐÓÐÐ), | (ÐÐÐÐÐ¡Ð) Ð¶ÓÐœÐµ Ð¶Ð°ÒÑÐ°Ð»Ð°Ñ) Ð°ÐŒÐ°Ð»ÐŽÐ°ÑÑ ÐŒÐµÐœ Ð»ÐŸÐ³ÐžÐºÐ°Ð»ÑÒ ÑÐ·ÐŽÐµÑ ÑÒ±ÒÑÐ°Ñ ÐµÑÑÐ»Ð³ÐµÐœ}
+_textlinkinterm_ [l=kk] {Ð°ÑÐ°Ð»ÑÒ Ð±ÐµÑ Ð°ÑÒÑÐ»Ñ}
+_textlinkdirect_ [l=kk] {ÑÑÐºÐµÐ»ÐµÐ¹ Ó©ÑÑ}
+_textdigitlib_ [l=kk] {ÑÐ»ÐµÐºÑÑÐŸÐœÐŽÑÒ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°}
+_textweb_ [l=kk] {Web}
+_textgraphical_ [l=kk] {ÐÑÐ°ÑÐžÐºÐ°Ð»ÑÒ}
+_texttextual_ [l=kk] {ÐÓÑÑÐœÐŽÑÐº}
+_textcollectionoption_ [l=kk] {<p> ÒÐŸÐ»ÐŽÐ°ÐœÑÒÐ° Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÑÑÐºÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ: <br>}
+
+_textrelateddocdisplay_ [l=kk] {Ò±ÒÑÐ°Ñ ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ Ð±ÐµÐ¹ÐœÐµÐ»ÐµÑ}
+_textsearchhistory_ [l=kk] {Ð¡Ò±ÑÐ°ÐœÑÐŒ ÑÐ°ÑÐžÑ
+Ñ:}
+# -- Missing translation: _textnohistory_
+_texthistorydisplay_ [l=kk] {ÑÒ±ÑÐ°ÐœÑÐŒ ÑÐ°ÑÐžÑ
+ÑÐœ _historynumrecords_ Ð±ÐµÐ¹ÐœÐµÐ»ÐµÑ Ð·Ð°Ð¿ÑÐŸÑÐ°}
+_textnohistorydisplay_ [l=kk] {ÑÒ±ÑÐ°ÐœÑÐŒ ÑÐ°ÑÐžÑ
+ÑÐœ Ð±ÐµÐ¹ÐœÐµÐ»ÐµÐŒÐµÑ}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=kk] {ÑÐŸÑÐŒÐ° Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑ}
+# -- Missing translation: _textplainsearch_
+_textqueryboxsize_ [l=kk] {ÐÐ·ÐŽÐµÑÐ³Ðµ Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ Ð¢ÐµÑÐµÐ·Ðµ Ó©Ð»ÑÐµÐŒÑ :}
+_textregbox_ [l=kk] {ÑÐ·ÐŽÐµÑÐ³Ðµ Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÓÐŽÐµÑÑÐµÐ³Ñ ÑÐµÑÐµÐ·Ðµ}
+_textbigbox_ [l=kk] {ÑÐ·ÐŽÐµÑÐ³Ðµ Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ Ò¯Ð»ÐºÐµÐœ ÑÐµÑÐµÐ·Ðµ}
+_textformtype_ [l=kk] {Ð€ÐŸÑÐŒÐ° ÑÐžÐ¿Ñ:}
+_textsimple_ [l=kk] {ÒÐ°ÑÐ°Ð¿Ð°Ð¹ÑÐŒ}
+_textadvanced_ [l=kk] {ÐºÐµÒ£ÐµÐ¹ÑÑÐ»Ð³ÐµÐœ}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=kk] {ÐœÐ°Ðœ}
+_textfields_ [l=kk] {Ð°Ð»Ð°Ò£ÐŽÐ°Ñ}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑ" ## green_title ## h_pref ##
+_httpiconhpref_ [l=kk] {_httpimg_/kk/h\_pref.gif}
+_widthhpref_ [l=kk] {200}
+_heighthpref_ [l=kk] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+# -- Missing translation: _textsortby_
+# -- Missing translation: _textalsoshowing_
+# -- Missing translation: _textwith_
+# -- Missing translation: _textdocsperpage_
+
+# -- Missing translation: _textfilterby_
+# -- Missing translation: _textall_
+# -- Missing translation: _textany_
+# -- Missing translation: _textwords_
+# -- Missing translation: _textleaveblank_
+
+# -- Missing translation: _browsebuttontext_
+
+# -- Missing translation: _nodata_
+# -- Missing translation: _docs_
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=kk] {ÐÓ©ÐŒÐµÐº}
+_textSearchshort_ [l=kk] {Ð°ÑÐœÐ°Ð¹Ñ ÑÐµÑÐŒÐžÐœÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑ}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=kk] {ÐÒ±ÐŒÑÑ Ð°ÑÐ°ÑÐ»Ð°ÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±Ðœ}
+_textCreatorshort_ [l=kk] {ÐÐ²ÑÐŸÑÐ»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+_textSubjectshort_ [l=kk] {ÐÐ°ÑÑÑÒ ÐºÓ©ÑÑÐµÑÐºÑÑ}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=kk] {ÐÐ°ÑÐ°Ð»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+# -- Missing translation: _textSourceshort_
+_textLanguageshort_ [l=kk] {Ð¢ÑÐ»ÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=kk] {ÐšÑÒÐ°ÑÑÐ»ÑÐŒÐŽÐ°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+_textToshort_ [l=kk] {ÐÐ»ÑÑÑÐ»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+_textFromshort_ [l=kk] {ÐÑÐ±ÐµÑÑÑÑÐ»ÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+_textBrowseshort_ [l=kk] {ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ ÒÐ°ÑÐ°Ñ}
+_textOrganizationshort_ [l=kk] {Ò°Ð¹ÑÐŒÐŽÐ°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+_textHowtoshort_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑ ÑÓÑÑÐ»Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+_textTopicshort_ [l=kk] {Ð¢Ð°ÒÑÑÑÐ¿ÑÐ°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+_textPeopleshort_ [l=kk] {ÐÐµÑÑÐŸÐœÐ°Ð»ÐžÐ»ÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+_textAcronymshort_ [l=kk] {ÐÐºÑÐŸÐœÐžÐŒÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑ}
+_textPhraseshort_ [l=kk] {ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° ÐºÐµÐ·ÐŽÐµÑÐµÑÑÐœ ÑÑÐ°Ð·Ð°Ð»Ð°ÑÐŽÑ ÒÐ°ÑÐ°Ñ}
+# -- Missing translation: _textArtistshort_
+# -- Missing translation: _textKeywordshort_
+# -- Missing translation: _textVolumeshort_
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=kk] {Ð°ÐœÑÒÑÐ°Ð»ÐŒÐ°ÒÐ°Ðœ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÑ}
+
+_textSearchlong_ [l=kk] {<p>Ð¡ÑÐ· ÑÐ·ÐŽÐµÑÐŽÑ <i>Ð°ÑÐœÐ°Ð¹Ñ ÑÐµÑÐŒÐžÐœÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° </i> ÑÐ·ÐŽÐµÑ Ð±ÐµÑÑÐœÐµÐœ Ð¶Ò¯ÑÐ³ÑÐ·Ðµ Ð°Ð»Ð°ÑÑÐ·. ÐÒ±Ð» Ð±ÐµÑ ÑÑÐ· ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒÐµÐœ ÑÑÑÐµÑÐŽÑ Ð±Ð°ÑÑÐ°ÒÐ°ÐœÐŽÐ° ÑÓ©ÑÐµÐ»ÑÐº Ð±ÐŸÐ»Ð°ÐŽÑ Ð¶ÓÐœÐµ ÐŸÒÐ°Ðœ ÐºÐµÐ· ÐºÐµÐ»Ð³ÐµÐœ Ð±ÐµÑÑÐµÑÐŽÐµÐœ <i>ÑÐ·ÐŽÐµÑ ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑ Ð°ÑÒÑÐ»Ñ ÐŸÑÐ°Ð»ÑÒÐ° Ð±ÐŸÐ»Ð°ÐŽÑ</i>.}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=kk] {<p>Ð¡ÑÐ· Ð°ÑÐ°ÑÐ»Ð°Ñ Ð-Ð¯ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ¿ </i> ÒÒ±Ð¶Ð°ÑÑÐ°Ñ Ð°ÑÐ°ÑÐ»Ð°ÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ <i>Ð°Ð»Ð° Ð°Ð»Ð°ÑÑÐ·</i>. ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÑÑÐ· Ð°ÑÐ°ÑÐ»Ð°ÑÑÐœÑÒ£ Ð°Ð»ÑÐ°Ð²ÐžÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŸÑÐœÐ°Ð»Ð°ÑÒÐ°Ðœ ÐºÑÑÐ°Ð¿ÑÐ°Ñ ÑÑÐ·ÑÐŒÑÐœ ÐºÓ©ÑÐµÑÑÐ·. }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=kk] {<p>Ð¡ÑÐ· Ð°Ð²ÑÐŸÑÐ»Ð°Ñ Ð-Ð¯ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑ Ð°ÑÒÑÐ»Ñ <i>Ð°Ð²ÑÐŸÑÐ»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÑÑÐ· Ð°Ð²ÑÐŸÑÐ»Ð°Ñ ÑÐ°ÐŒÐžÐ»ÐžÑÐ»Ð°ÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÒ±ÑÑÐ¿ÑÐ°Ð»ÒÐ°Ðœ ÒÒ±Ð¶Ð°ÑÑÐ°Ñ ÑÑÐ·ÑÐŒÑÐœ ÐºÓ©ÑÐµÑÑÐ·. }
+
+_textSubjectlong_ [l=kk] {<p> Ð¡ÑÐ· ÐºÓ©ÑÑÐµÑÐºÑÑ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑ Ð°ÑÒÑÐ»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑÒ£ Ð·Ð°ÑÑÑÒ ÐºÓ©ÑÑÐµÑÐºÑÑÑÐŒÐµÐœ Ð¶Ò±ÐŒÑÑ ÑÑÑÐµÐ¹ Ð°Ð»Ð°ÑÑÐ·</i>.  ÐÐ°ÑÑÑÒ ÐºÓ©ÑÑÐµÑÐºÑÑ ÐžÐµÑÐ°ÑÑ
+ÐžÑÐ»ÑÒ Ð¿ÑÐžÐœÑÐžÐ¿ÑÐµ ÒÒ±ÑÑÐ»ÑÐ¿, ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¶Ð°Ð¹Ð»Ñ ÐµÒ£ ÑÐŸÐ»ÑÒ ÐŒÓÐ»ÑÐŒÐµÑ Ð±ÐµÑÐµÐŽÑ. }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=kk] {<p> Ð¡ÑÐ· ÒÐ°ÑÐ°Ñ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑÐ¿ ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ ÒÐ°ÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ· <i>. }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: _textSourcelong_
+
+_textLanguagelong_ [l=kk] {<p> Ð¡ÑÐ· ÑÑÐ»ÐŽÐµÑ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑÐ¿ ÑÑÐ»ÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÑÑÐ· ÑÑÐ»ÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÒ±ÑÑÐ¿ÑÐ°Ð»ÒÐ°Ðœ ÐŒÐ°ÒÐ°Ð»Ð°Ð»Ð°Ñ ÑÑÐ·ÑÐŒÑÐœ ÐºÓ©ÑÐµÑÑÐ·.}
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=kk] {<p>Ð¡ÑÐ· Ò±Ð¹ÑÐŒÐŽÐ°Ñ<i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑ Ð°ÑÒÑÐ»Ñ<i>Ò±Ð¹ÑÐŒÐŽÐ°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ Ð°Ð»Ð° Ð°Ð»Ð°ÑÑÐ·</i>. ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÑÑÐ· Ò±Ð¹ÑÐŒÐŽÐ°Ñ ÑÑÐ·ÑÐŒÑÐœ ÐºÓ©ÑÐµÑÑÐ·. }
+
+_textHowtolong_ [l=kk] {<p>Ð¡ÑÐ· ÑÓÑÑÐ» <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑ 
+Ð°ÑÒÑÐ»Ñ <i>ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»Ñ ÑÓÑÑÐ»ÐŽÐµÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ Ð°Ð»Ð°ÑÑÐ·</i>.  ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÒÒ±Ð¶Ð°ÑÑÐ°ÑÑÐœÐŽÐ° Ð±Ð°Ñ Ð¿ÑÐ°ÐºÑÐžÐºÐ°Ð»ÑÒ Ò±ÑÑÐœÑÑÑÐ°ÑÐŽÑ ÐºÓ©ÑÐµÑÑÐ·.  }
+
+_textTopiclong_ [l=kk] {<p> Ð¡ÑÐ· ÑÐ°ÒÑÑÐ°Ð¿ÑÐ°Ñ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑ Ð°ÑÒÑÐ»Ñ<i>ÑÐ°ÒÑÑÑÐ¿ÑÐ°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÑÑÐ· ÑÐ°ÒÑÑÑÐ¿ÑÐ°Ñ ÑÑÐ·ÑÐŒÑÐœ ÐºÓ©ÑÐµÑÑÐ·. }
+
+_textTolong_ [l=kk] {<p> Ð¡ÑÐ· ÐºÑÐŒÐ³Ðµ<i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑ Ð°ÑÒÑÐ»Ñ<i>Ð°Ð»ÑÑÑÐ»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ Ð°Ð»Ð°ÑÑÐ·</i>.  ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÑÑÐ· Ð°Ð»ÑÑÑÐ»Ð°Ñ ÑÑÐ·ÑÐŒÑÐœ ÐºÓ©ÑÐµÑÑÐ·.  }
+
+_textFromlong_ [l=kk] {<p> Ð¡ÑÐ· ÐºÑÐŒÐœÐµÐœ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑ Ð°ÑÒÑÐ»Ñ <i>Ð¶ÑÐ±ÐµÑÑÑÑÐ»ÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°ÒÑ ÑÑÒÐ°ÑÑÐ»Ð°Ñ\ÑÐµÑÐžÑÐ»Ð°Ñ ÑÑÐ·ÑÐŒÑÐœ ÐºÓ©ÑÐµÑÑÐ·.  }
+
+_textSerieslong_ [l=kk] {<p> Ð¡ÑÐ· ÐŽÐ°ÑÐ°Ð»Ð°Ñ<i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑ Ð°ÑÒÑÐ»Ñ<i>ÐŽÐ°ÑÐ°Ð»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÐŒÐ°ÑÐµÑÐžÐ°Ð»ÐŽÐ°Ñ ÑÑÐ·ÑÐŒÑÐœ Ñ
+ÑÐŸÐœÐŸÐ»ÐŸÐ³ÐžÑÐ»ÑÒ ÑÐµÑÑÐµ ÐºÓ©ÑÐµÑÑÐ·. }
+
+_textBrowselong_ [l=kk] {<p>Ð¡ÑÐ· ÒÐ°ÑÐ°Ñ <i>browse publications</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ¿
+<i>ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ ÒÐ°ÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·</i>. }
+
+_textPeoplelong_ [l=kk] {<p> Ð¡ÑÐ· Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐž Ð-Ð¯ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑÐ¿ Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐ»ÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÑÑÐ· ÑÐ°ÐŒÐžÐ»ÐžÑÐ»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÒ±ÑÑÐ¿ÑÐ°Ð»ÒÐ°Ðœ ÐŒÐ°ÑÐµÑÐžÐ°Ð»ÐŽÐ°Ñ ÑÑÐ·ÑÐŒÑÐœ ÐºÓ©ÑÐµÑÑÐ·. }
+
+_textAcronymlong_ [l=kk] {<p> Ð¡ÑÐ· Ð°ÐºÑÐŸÐœÐžÐŒÐŽÐµÑ<i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑÐ¿ Ð°ÐºÑÐŸÐœÐžÐŒÐŽÐµÑÐŽÑÒ£ ÐºÐµÐ·ÐŽÐµÑÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÐŽÑ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÒ±Ð» ÐŒÐ°Ð·ÐŒÒ±ÐœÐœÐ°Ðœ ÑÑÐ· Ð°ÐºÑÐŸÐœÐžÐŒÐŽÐµÑ ÑÑÐ·ÑÐŒÑÐŒÐµÐœ ÐŸÐ»Ð°ÑÐŽÑÒ£ ÐºÐµÐ·ÐŽÐµÑÐµÑÑÐœ ÐŸÑÐœÑÐœ ÐºÓ©ÑÐµÑÑÐ·.}
+
+_textPhraselong_ [l=kk] {<p>Ð¡ÑÐ· ÑÑÐ°Ð·Ð°Ð»Ð°Ñ<i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑÐ¿ Ð±Ð°ÑÑÐ»ÑÐŒÐŽÐ°ÑÐŽÐ° ÐºÐµÐ·ÐŽÐµÑÐµÑÑÐœ ÑÑÐ°Ð·Ð°Ð»Ð°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÒ±ÐœÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>.  ÐÒ±Ð» Ò¯ÑÑÐœ phind phrase browser ÑÐŸÐ»ÑÑÑÑÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»Ð°ÐŽÑ.  }
+
+# -- Missing translation: _textArtistlong_
+
+# -- Missing translation: _textKeywordlong_
+
+# -- Missing translation: _textVolumelong_
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=kk] {<p>ÐÐœÑÒÑÐ°Ð»ÐŒÐ°ÒÐ°Ðœ Ð°Ð»Ð°Ò£ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÒ±ÑÑÐ¿ÑÐ°Ð»ÒÐ°Ðœ ÐŒÐ°ÒÐ°Ð»Ð°Ð»Ð°ÑÐŽÑ ÒÐ°ÑÐ°Ñ Ò¯ÑÑÐœ <i>Ð°ÐœÑÒÑÐ°Ð»ÐŒÐ°ÒÐ°Ðœ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÑ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÒ£ÑÐ·. }
+
+_texthelptopics_ [l=kk] {<h2 align=left>ÐÓ©Ð»ÑÐŒÐŽÐµÑ</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">ÐÑÐœÐ°Ð¹Ñ ÑÐµÑÐŒÐžÐœÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑÐŽÑ ÒÐ°Ð»Ð°Ð¹ Ð¶Ò¯ÑÐ³ÑÐ·Ñ ÐºÐµÑÐµÐº</a>
+<ul>
+  <li><a href="\#query-terms">ÐÐ·ÐŽÐµÑÐ³Ðµ Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÑÓ©Ð·ÐŽÐµÑ</a>
+  <li><a href="\#query-type">Ð¡Ò±ÑÐ°ÐœÑÐŒ ÑÐžÐ¿Ñ</a>
+  <li><a href="\#scope-of-queries">Ð¡Ò±ÑÐ°ÐœÑÐŒ ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐºÑÐµÑÑ</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑ</a>
+
+  <li><a href="\#lang-prefs">Ð¢ÑÐ»ÐŽÑ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑ</a>
+  <li><a href="\#pres-prefs">ÐÐœÑÐµÑÑÐµÐ¹ÑÑÑ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑ</a>
+  <li><a href="\#search-prefs">ÐÐ·ÐŽÐµÑÐŽÑ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑ</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=kk] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=kk] {ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŒÐµÐœ ÒÐ°Ð»Ð°Ð¹ ÑÑÑÐµÑ ÐºÐµÑÐµÐº}
+
+_texthelpreadingdocs_ [l=kk] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Ð¡ÑÐ· ÒÐ°ÐœÐŽÐ°Ð¹ÐŽÐ° Ð±ÑÑ ÒÒ±Ð¶Ð°ÑÑÑ Ð°ÑÒÐ°ÐœÐŽÐ° ÐŸÐœÑÒ£ Ð°ÑÑÐœ Ð¶ÓÐœÐµ Ð±ÐµÑÑÑÒ£ ÑÐŸÐ» Ð¶Ð°Ò Ð¶ÐŸÒÐ°ÑÒÑ Ð±Ò±ÑÑÑÑÐœÐŽÐ° Ð°Ð²ÑÐŸÑ Ð°ÑÑÐœ ÐºÓ©ÑÐµÑÑÐ·. ÐÒ±ÐŽÐ°Ðœ Ð±Ð°ÑÒÐ° ÑÑÐ· Ð±ÐµÑ ÐœÐŸÐŒÐµÑÑÐœ, Ð°Ð»ÒÐ° Ð¶ÓÐœÐµ Ð°ÑÑÒÐ° ÐºÓ©ÑÑ ÑÑÑÐµÐ»ÐºÐ°Ð»Ð°ÑÑÐœ, Ð¶Ð°Ò£Ð° Ð±ÐµÑÑÑ ÑÐ°Ò£ÐŽÐ°Ñ ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ ÑÐ°Ð±Ð° Ð°Ð»Ð°ÑÑÐ·. 
+
+<p>Ð¢Ó©ÐŒÐµÐœÐŽÐµ Ð°ÒÑÐŒÐŽÐ°ÒÑ Ð±Ó©Ð»ÑÐŒÐœÑÒ£ ÐŒÓÑÑÐœÑ Ð±ÐµÑÑÐ»Ð³ÐµÐœ. ÐÐœÑ ÐŸÒÑÒÐ°ÐœÐœÐ°Ðœ ÐºÐµÐ¹ÑÐœ, ÑÓ©ÐŒÐµÐœ Ð¶Ð°ÒÑÐœÐŽÐ° ÐºÐµÐ»ÐµÑÑ ÐœÐµÐŒÐµÑÐµ Ð°Ð»ÐŽÑÒ£ÒÑ Ð±Ó©Ð»ÑÐŒÐ³Ðµ ÐºÓ©ÑÑ ÑÑÑÐµÐ»ÐºÐ°Ð»Ð°ÑÑÐœ ÐºÓ©ÑÐµÑÑÐ·. 
+
+
+<p>ÒÒ±Ð¶Ð°Ñ Ð°ÑÑ ÐŒÐµÐœ ÐŸÐœÑÒ£ Ð°Ð²ÑÐŸÑÑÐœÑÒ£ Ð°ÑÑÑÐœÐŽÐ° Ò¯Ñ ÐºÐœÐŸÐ¿ÐºÐ° Ð±Ð°Ñ. ÐÐ°ÑÐ»ÑÒ ÐŒÓÑÑÐœ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ°Ò£ÑÐ· ÒÒ±Ð¶Ð°ÑÑÑÒ£ Ð±Ð°ÑÐ»ÑÒ ÐŒÓÑÑÐœÑÐœ ÑÐºÑÐ°ÐœÒÐ° ÑÑÒÐ°ÑÐ° Ð°Ð»Ð°ÑÑÐ·. ÐÐ³ÐµÑ ÒÒ±Ð¶Ð°Ñ Ð¶ÐµÑÐºÑÐ»ÑÐºÑÑ Ò¯Ð»ÐºÐµÐœ Ð±ÐŸÐ»ÑÐ°, ÐŸÐœÐŽÐ° ÐŸÐ» Ð±ÑÑÐ°Ð· ÑÐ°ÒÑÑ Ð¿ÐµÐœ ÐºÓ©Ð¿ Ð¶Ð°ÐŽÑÐœÑ ÒÐ°Ð¶ÐµÑ ÐµÑÐµÐŽÑ! </i> 
+ÐÐµÑÑÐ»Ð³ÐµÐœ ÒÒ±Ð¶Ð°ÑÑÑ Ð¶Ð°Ò£Ð° ÑÐµÑÐµÐ·ÐµÐ³Ðµ ÑÑÒÐ°ÑÑ Ò¯ÑÑÐœ (Ð±Ò±Ð» Ð±ÑÑÐŽÐµÐœ Ð±ÑÑÐœÐµÑÐµ ÒÒ±Ð¶Ð°ÑÑÑ ÑÐ°Ð»ÑÑÑÑÑÒÑÒ£ÑÐ· ÐºÐµÐ»ÑÐµ ÐœÐµÐŒÐµÑÐµ ÐµÐºÐµÑÑÐœ Ð±ÑÑÐŽÐµÐœ ÐŸÒÑÒÑÒ£ÑÐ· ÐºÐµÐ»ÑÐµ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ñ) <i>ÐÐ°Ò£Ð° ÑÐµÑÐµÐ·ÐµÐŽÐµ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÒ£ÑÐ·. ÐÐ³ÐµÑ ÑÑÐ· Ð±Ò±Ð» ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ Ð±ÐµÐ»Ð³ÑÐ»Ñ ÑÓ©Ð·ÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ°Ð¿ÒÐ°Ðœ Ð±ÐŸÐ»ÑÐ°Ò£ÑÐ·, ÐŸÐœÐŽÐ° ÐŸÐ»Ð°Ñ ÒÒ±Ð¶Ð°Ñ ÐŒÓÑÑÐœÑÐœÐŽÐµ Ð±Ó©Ð»ÑÐœÑÐ¿ ÑÒ±ÑÐ°ÐŽÑ. ÐÐ·ÐŽÐµÐ³ÐµÐœ ÑÓ©Ð·ÐŽÐµÑ ÒÒ±Ð¶Ð°Ñ ÐŒÓÑÑÐœÑÐœÐŽÐµ Ð±Ó©Ð»ÑÐœÑÐ¿ ÑÒ±ÑÐŒÐ°ÑÑ Ò¯ÑÑÐœ <i>Ð±Ó©Ð»ÑÐŽÑ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ñ </i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ ÑÐ°ÑÑÒ£ÑÐ·. 
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>ÐÐµÐ»ÐµÑÑ Ð±Ó©Ð»ÑÐŒÐ³Ðµ ÐºÓ©ÑÑ Ò¯ÑÑÐœ ÑÑÑÐµÐ»ÐºÐ°ÐœÑ Ð±Ð°ÑÑÒ£ÑÐ·...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... ÐœÐµÐŒÐµÑÐµ Ð°ÑÑÒÐ°, Ð°Ð»ÐŽÑÒ£ÒÑÒÐ° ÒÐ°Ð¹ÑÑÐ¿ ÐŸÑÐ°Ð»Ñ Ò¯ÑÑÐœ</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>ÐÐ°ÑÐ»ÑÒ ÐŒÓÑÑÐœÐŽÑ ÑÑÒÐ°ÑÐ°Ð¹ÑÐœÐ±Ð°, Ð¶ÐŸÒÐ¿Ð°</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>ÐÒ±Ð» Ð±ÐµÑÑÑ Ð¶Ð°Ò£Ð° ÑÐµÑÐµÐ·ÐµÐŽÐµ Ð°ÑÐ°Ð¹ÑÐœÐ±Ð°</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>ÐÐ·ÐŽÐµÐ»ÐµÑÑÐœ ÑÓ©Ð·ÐŽÐµÑÐŽÑ Ð±Ó©Ð»ÐµÐ¹ÑÐœ Ð±Ðµ Ð¶ÐŸÒ Ð¿Ð°</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=kk] {<h2>ÐÑÐœÐ°Ð¹Ñ ÑÐµÑÐŒÐžÐœÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑÐŽÑ ÒÐ°Ð»Ð°Ð¹ Ð¶Ò¯ÑÐ³ÑÐ·Ñ </h2>
+<p>
+  Ð¡ÑÐ· ÑÐ·ÐŽÐµÑ Ð±ÐµÑÑÐœÐµÐœ, ÐºÐµÐ»ÐµÑÑ ÒÐ°ÐŽÐ°ÐŒÐŽÐ°ÑÒÐ° ÑÓÐ¹ÐºÐµÑ ÒÐ°ÑÐ°Ð¿Ð°Ð¹ÑÐŒ ÑÒ±ÑÐ°ÐœÑÐŒ Ð¶Ð°ÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·. <p>
+  
+  <ol><li>ÐÐµÐœÑ ÑÐ·ÐŽÐµÐ¹ÑÑÐœÑÒ£ÑÐ·ÐŽÑ Ð°ÐœÑÒÑÐ°Ò£ÑÐ·
+      <li>ÐÐœÑ ÒÐ°Ð»Ð°Ð¹ ÑÐ·ÐŽÐµÐ¹ÑÑÐœÑÒ£ÑÐ·ÐŽÑ Ð°ÐœÑÒÑÐ°Ò£ÑÐ·: ÑÑÐ°Ð·Ð°ÐœÑ ÐœÐµÐŒÐµÑÐµ Ð¶ÐµÐºÐµ ÑÓ©Ð·ÐŽÐµÑÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ¿ 
+      <li>Ð¡Ò±ÑÐ°ÐœÑÐŒ ÐŒÓÑÑÐœÑÐœ ÑÐ·ÐŽÐµÑ Ð¶ÐŸÐ»ÑÐœÐ° ÑÐµÑÑÐ¿ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·
+      <li>ÐÐ·ÐŽÐµÑÐŽÑ Ð±Ð°ÑÑÐ°Ñ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÒ£ÑÐ·</i> 
+  </ol>
+
+<p>Ð¡Ò±ÑÐ°ÐœÑÐŒ ÐŸÑÑÐœÐŽÐ°Ð»ÒÐ°ÐœÐœÐ°Ðœ ÐºÐµÐ¹ÑÐœ ÑÐºÑÐ°ÐœÐŽÐ° ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑÒ£ 20 Ð°ÑÐ°ÑÑ Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»Ð°ÐŽÑ. Ð¢ÑÐ·ÑÐŒÐœÑÒ£ ÑÐŸÒ£ÑÐœÐŽÐ°, ÐºÐµÐ»ÐµÑÑ 20 ÒÒ±Ð¶Ð°ÑÒÐ° ÐºÓ©ÑÐµÑÑÐœ ÐºÐœÐŸÐ¿ÐºÐ° Ð±Ð°Ñ. ÐÓÑÐžÐ¶ÐµÐ»ÐµÑÐŽÑÒ£ ÐºÐµÐ»ÐµÑÑ Ð±ÐµÑÑÐµÑÑÐœÐŽÐµ ÐºÐµÐ»ÐµÑÑ 20 ÒÒ±Ð¶Ð°ÑÒÐ° ÐœÐµÐŒÐµÑÐµ ÐºÐµÑÑÑÑÐœÑÐµ Ð°Ð»ÐŽÑÒ£ÒÑ 20 ÒÒ±Ð¶Ð°ÑÒÐ° ÐºÓ©ÑÑÐ³Ðµ Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÐºÐœÐŸÐ¿ÐºÐ°ÐœÑ ÐºÓ©ÑÐµÑÑÐ·. ÐÐµÐ· ÐºÐµÐ»Ð³ÐµÐœ ÒÒ±Ð¶Ð°ÑÑÑÒ£ Ð°ÑÑÐœÐ° ÐœÐµÐŒÐµÑÐµ ÐŸÐœÑÒ£ Ð°Ð»ÐŽÑÐœÐŽÐ°ÒÑ Ð±ÐµÐ»Ð³ÑÐœÑ Ð±Ð°ÑÑÐ¿, ÐŸÐœÑ ÒÐ°ÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·. 
+
+<p>ÐÐ·ÐŽÐµÑ ÐœÓÑÐžÐ¶ÐµÑÑÐœÐŽÐµ ÐµÒ£ ÐºÓ©Ð¿ ÐŽÐµÐ³ÐµÐœÐŽÐµ -100 ÒÒ±Ð¶Ð°Ñ Ð±ÐŸÐ»Ð°ÐŽÑ. Ð¡ÑÐ· Ð±Ò±Ð» ÑÐ°ÐœÐŽÑ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑ Ð±ÐµÑÑÐœÐµÐœ Ó©Ð·Ð³ÐµÑÑÐµ Ð°Ð»Ð°ÑÑÐ· (ÐÐµÑÑÑÒ£ Ð±Ð°Ñ Ð¶Ð°ÒÑÐœÐŽÐ°ÒÑ <i> ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑ </i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑ). <p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>ÐÐ·ÐŽÐµÑÐ³Ðµ Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÑÓ©Ð·ÐŽÐµÑ</h3>
+
+<p>Ð¡ÑÐ·ÐŽÑÒ£ ÑÒ±ÑÐ°ÐœÑÐŒ Ð¶ÐŸÐ»ÑÐœÐŽÐ° ÐµÐœÐ³ÑÐ·ÐµÑÑÐœÑÒ£ÑÐ·ÐŽÑÒ£ Ð±ÓÑÑ, â ÑÐ·ÐŽÐµÑÐ³Ðµ Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÑÓ©Ð·ÐŽÐµÑâ ÐŽÐµÐ¿ Ð°ÑÐ°Ð»Ð°ÐŽÑ. ÓÑ ÑÓ©Ð· ÓÑÑÐ¿ÑÐµÑ ÐŒÐµÐœ ÑÐžÑÑÐ»Ð°ÑÐŽÐ°Ðœ ÑÒ±ÑÐ°ÐŽÑ. Ð¡Ó©Ð·ÐŽÐµÑ Ð±ÐŸÑ ÐŸÑÑÐœÐŒÐµÐœ Ð±Ó©Ð»ÑÐœÐ³ÐµÐœ. ÐÐ³ÐµÑ Ð±Ð°ÑÒÐ° Ð±ÑÑ Ð±ÐµÐ»Ð³Ñ Ð±ÐŸÐ»ÑÐ°, ÐŒÑÑÐ°Ð»Ñ Ð¿ÑÐœÐºÑÑÐ°ÑÐžÑ Ð±ÐµÐ»Ð³ÑÐ»ÐµÑÑ, ÐŸÐœÐŽÐ° ÐŸÐ»Ð°ÑÐŽÐ° Ð±ÐŸÑ Ð±ÐµÐ»Ð³Ñ ÑÐžÑÒÑÑ ÑÓ©Ð· Ð±Ó©Ð»Ð³ÑÑ ÒÑÐ·ÐŒÐµÑÑÐœ Ð°ÑÒÐ°ÑÑÐ¿ ÐµÑÐºÐµÑÑÐ»ÐŒÐµÐ¹ÐŽÑ. Ð¡ÑÐ· Ð¿ÑÐœÐºÑÑÐ°ÑÐžÑ Ð±ÐµÐ»Ð³ÑÐ»ÐµÑÑ Ð±Ð°Ñ ÑÓ©Ð·ÐŽÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑ Ð¶Ò¯ÑÐ³ÑÐ·Ðµ Ð°Ð»Ð°ÑÑÐ·. 
+
+
+<p>ÐÑÑÐ°Ð»Ñ, <p>
+    <ul><kbd>Ð¢ÑÐœÑÒ ÐŒÒ±Ñ
+ÐžÑ Ð°ÑÐ°Ð»ÐŽÐ°ÑÑÐœÐŽÐ°ÒÑ ÐÑÑÐ»-ÐŸÑÐŒÐ°Ðœ ÑÐ°ÑÑÐ°ÑÑÐ»ÑÒÑ: ÒÐŸÐ»ÐŽÐ°Ñ Ð¶Ò¯Ð¹ÐµÑÑ (1993)</kbd></ul>
+      <p>ÑÒ±ÑÐ°ÐœÑÐŒÑÐœ ÒÐ°ÑÐ°ÑÑÑÑÑÐ°Ò ÐŸÐ» ÐºÐµÐ»ÐµÑÑÐŒÐµÐœ Ð¿Ð°ÑÐ°-Ð¿Ð°Ñ<p>
+      <ul><kbd> Ð¢ÑÐœÑÒ ÐŒÒ±Ñ
+ÐžÑ Ð°ÑÐ°Ð»ÐŽÐ°ÑÑÐœÐŽÐ°ÒÑ Ð°ÑÑÐ»-ÐŸÑÐŒÐ°Ðœ ÑÐ°ÑÑÐ°ÑÑÐ»ÑÒÑ ÒÐŸÐ»ÐŽÐ°Ñ Ð¶Ò¯Ð¹ÐµÑÑ 1993</kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Ð¡Ò±ÑÐ°ÐœÑÐŒÐŽÐ°Ñ ÑÐžÐ¿Ñ</h3>
+
+<p>ÓšÐ·Ð³ÐµÑÐµ ÐµÐºÑ ÑÒ±ÑÐ°ÐœÑÐŒ ÑÐžÐ¿Ñ Ð±Ð°Ñ.
+
+<ul>
+  <li>ÐÐ°ÑÐ»ÑÒ <b>ÑÓ©Ð·ÐŽÐµÑ</b> Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÒ±ÑÐ°ÐœÑÐŒÐŽÐ°Ñ. ÐÒ±Ð» ÑÑÐ· ÑÐ·ÐŽÐµÑ Ð¶ÐŸÐ»ÑÐœÐ° ÐµÐœÐ³ÑÐ·Ð³ÑÒ£ÑÐ· ÐºÐµÐ»Ð³ÐµÐœ ÑÓ©Ð·ÐŽÐµÑÐŽÑÒ£ Ð±ÓÑÑ Ð±Ð°Ñ ÒÒ±Ð¶Ð°ÑÑÐ°Ñ Ò¯ÑÑÐœ Ð±ÐŸÐ»Ð°ÐŽÑ. Ð¡Ò±ÑÐ°ÐœÑÐŒÐŽÑ ÒÐ°ÐœÐ°ÒÐ°ÑÑÐ°ÐœÐŽÑÑÐ°ÑÑÐœ ÒÒ±Ð¶Ð°ÑÑÐ°Ñ ÐÐ»ÑÐ°Ð²ÐžÑÑÑÐº ÑÓÑÑÑÐ¿ÑÐµ ÑÑÒÐ°ÑÑÐ»Ð°ÐŽÑ. <p>
+
+  <li>ÐÐµÐ¹Ð±ÑÑ <b>ÑÓ©Ð·ÐŽÐµÑ</b> Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÒ±ÑÐ°ÐœÑÐŒÐŽÐ°Ñ. Ð¢ÐµÐº ÒÒ±Ð¶Ð°Ñ ÐŒÓÑÑÐœÑÐœÐŽÐµ ÐºÐµÐ·ÐŽÐµÑÑÑ ÐŒÒ¯ÐŒÐºÑÐœ Ð±ÑÑÐœÐµÑÐµ ÑÓ©Ð·ÐŽÑ Ð¶Ð°Ð·Ñ Ð¶ÐµÑÐºÑÐ»ÑÐºÑÑ. ÒÒ±Ð¶Ð°ÑÑÐ°Ñ ÑÒ±ÑÐ°ÐœÑÐŒÒÐ° ÑÓÐ¹ÐºÐµÑ ÐºÐµÐ»ÑÑÐœÑÒ£ ÑÓ©ÐŒÐµÐœÐŽÐµÑ ÑÐµÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÑÒÐ°ÑÑÐ»Ð°ÐŽÑ. Ð¡Ò±ÑÐ°ÐœÑÐŒÒÐ° ÑÓÐ¹ÐºÐµÑÑÑÐº Ð±ÑÐ»Ð°Ð¹ Ð°ÐœÑÒÑÐ°Ð»Ð°ÐŽÑ:  
+      <p><ul>
+        <li> ÒÒ±Ð¶Ð°ÑÑÐ° ÑÐ·ÐŽÐµÐ»ÑÐœÐµÑÑÐœ ÑÐµÑÐŒÐžÐœÐŽÐµÑ ÐºÓ©Ð±ÑÑÐµÐº ÐºÐµÐ·ÐŽÐµÑÐºÐµÐœ ÑÐ°Ð¹ÑÐœ, ÐŸÐ» ÐºÓ©Ð±ÑÑÐµÐº ÑÓÐ¹ÐºÐµÑ ÐºÐµÐ»ÐµÐŽÑ;
+        <li> Ð¶Ð°Ð»Ð¿Ñ ÑÓ©Ð·ÐŽÐµÑÐ³Ðµ ÒÐ°ÑÐ°ÒÐ°ÐœÐŽÐ°, ÑÐžÑÐµÐº ÑÓ©Ð·ÐŽÐµÑ ÐŒÐ°Ò£ÑÐ·ÐŽÑÑÐ°Ò;
+        <li> Ò¯Ð»ÐºÐµÐœ ÒÒ±Ð¶Ð°ÑÑÐ°ÑÒÐ° ÒÐ°ÑÐ°ÒÐ°ÐœÐŽÐ° ÐºÑÑÐºÐµÐœÑÐ°Ð¹Ð»Ð°ÑÑ Ð¶Ð°ÒÑÑ ÑÓÐ¹ÐºÐµÑ.
+      </ul>
+</ul>
+
+<p>ÐÐ·ÐŽÐµÑÐ³Ðµ ÒÐ°ÐœÑÐ° ÑÓ©Ð· ÒÐ°Ð¶ÐµÑ Ð±ÐŸÐ»ÑÐ° ÑÐŸÐœÑÐ° ÑÓ©Ð·ÐŽÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑÒ£ÑÐ· â Ð±Ò¯ÑÑÐœ ÑÓ©Ð¹Ð»ÐµÐŒ ÐœÐµÐŒÐµÑÐµ Ð¿Ð°ÑÐ°Ð³ÑÐ°Ñ Ð±ÐŸÐ»ÑÑ ÐŒÒ¯ÐŒÐºÑÐœ. ÐÐ³ÐµÑ ÑÑÐ· ÑÐµÐº Ð±ÑÑ ÑÓ©Ð· ÐµÐœÐ³ÑÐ·ÑÐµÒ£ÑÐ·, ÐŸÐœÐŽÐ° ÒÒ±Ð¶Ð°ÑÑÐ°Ñ ÐŸÐœÑÒ£ Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»Ñ Ð¶ÐžÑÐ»ÑÐ³ÑÐœÑÒ£ ÐºÐµÐŒÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÐŸÑÐœÐ°Ð»Ð°ÑÐ°ÐŽÑ. <p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=kk] {ÐŽÐ°ÑÐ° Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑ}
+
+_texthelpdatesearch_ [l=kk] {<h2>_textdatesearch_</h2>
+ÐÐ°ÑÐ° Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑ ÑÑÐ·Ð³Ðµ Ð±ÐµÐ»Ð³ÑÐ»Ñ Ð±ÑÑ ÑÐ°ÒÑÑ Ð°ÑÐ°Ð»ÑÒÑÐœÐŽÐ° Ð±ÐŸÐ»ÒÐ°Ðœ ÐŸÒÐžÒÐ°Ð»Ð°ÑÒÐ° ÒÐ°ÑÑÑÑÑ ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ, Ð±ÐµÐ»Ð³ÑÐ»Ñ Ð±ÑÑ ÑÐ·ÐŽÐµÑ ÑÐµÑÐŒÐžÐœÑÐŒÐµÐœ ÑÐ°Ð±ÑÐ»Ð°ÑÑÐœ ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ ÑÐ°Ð±Ñ ÑÐžÑÒÑÑ ÑÐ°Ð±ÑÒÐ° ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐº Ð±ÐµÑÐµÐŽÑ. Ð¡ÑÐ· ÑÐ·ÐŽÐµÑÐŽÑ Ð±ÐµÐ»Ð³ÑÐ»Ñ Ð±ÑÑ Ð¶ÑÐ»ÒÐ° ÒÐ°ÑÑÑÑÑ ÒÒ±Ð¶Ð°ÑÑÐ°Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° Ð¶ÓÐœÐµ Ð¶ÑÐ»ÐŽÐ°Ñ ÐºÐµÐ·ÐµÒ£ÑÐœÐµ ÒÐ°ÑÑÑÑÑÐ»Ð°ÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° Ð¶Ò¯ÑÐ³ÑÐ·Ðµ Ð°Ð»Ð°ÑÑÐ·.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>ÐÒ±ÐœÑ ÒÐ°Ð»Ð°Ð¹ ÒÐŸÐ»ÐŽÐ°ÐœÑ ÐºÐµÑÐµÐº:</h3>
+<ul>
+   <li>ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ ÐœÐ°ÒÑÑ ÐŽÐ°ÑÐ° Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑ:<p>
+   <ul>
+       <li>ÐÐ·ÐŽÐµÑÐ³Ðµ Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÐºÓÐŽÑÐŒÐ³Ñ ÑÓ©Ð·ÐŽÐµÑÐŽÑ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·.	
+       <li>ÒÐ°Ð¶ÐµÑÑÑ Ð¶ÑÐ»ÐŽÑ âÐÐ°ÑÑÐ°Ð¿ÒÑ (ÐœÐµÐŒÐµÑÐµ ÐœÐ°ÒÑÑ) ÐŽÐ°ÑÐ°â ÑÒ¯ÑÑÐœÐŽÐµ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·.
+       <li>ÐÐ³ÐµÑ ÑÑÐ·ÐŽÑÒ£ Ð¶ÑÐ»ÑÒ£ÑÐ· Ð±ÑÐ·ÐŽÑÒ£ ÑÑÐ°ÐŒÑÐ·ÒÐ° ÐŽÐµÐ¹ÑÐœÐ³Ñ (ÐœÐµÐŒÐµÑÐµ Ð¥ÑÐžÑÑÐŸÑ ÑÑÑÐ»ÒÐ°ÐœÒÐ° ÐŽÐµÐ¹ÑÐœÐ³Ñ) Ð°ÑÐ°Ð»ÑÒÑÐ° Ð¶Ð°ÑÑÐ°, ÐŸÐœÐŽÐ° Ð±Ò±ÐŽÐ°Ðœ Ð±ÑÐ»Ð°Ð¹ Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»Ð°ÑÑÐœ ÐŒÓÐ·ÑÑÐŽÐµÐœ âÐ.Ñ.ÐŽâ-ÐŽÑ ÑÐ°Ò£ÐŽÐ°Ò£ÑÐ·.
+       <li>ÐÐ·ÐŽÐµÑÐŽÑ Ð±Ð°ÑÑÐ°Ò£ÑÐ·.
+   </ul>
+<p><li>ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ ÑÐ°ÒÑÑ Ð°ÑÐ°Ð»ÑÒÑ Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑ:<p>
+   <ul>
+       <li>ÐÐ·ÐŽÐµÑÐ³Ðµ Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÐºÓÐŽÑÐŒÐ³Ñ ÑÓ©Ð·ÐŽÐµÑÐŽÑ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·.
+
+
+       <li>ÐÐ°ÑÑÐ°Ð¿ÒÑ Ð¶ÑÐ»ÐŽÑ âÐÐ°ÑÑÐ°Ð¿ÒÑ (ÐœÐµÐŒÐµÑÐµ ÐœÐ°ÒÑÑ) ÐŽÐ°ÑÐ°â ÑÒ¯ÑÑÐœÐŽÐµ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·. 
+       <li>ÐÑÒÒÑ Ð¶ÑÐ»ÐŽÑ âÐÑÒÒÑ ÐŽÐ°ÑÐ°â ÑÒ¯ÑÑÐœÐŽÐµ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·.
+       <li>ÐÐ°Ð¹ÐŽÐ° Ð±ÐŸÐ»Ð°ÑÑÐœ ÐŒÓÐ·ÑÑÐŽÐµÐœ âÐ.Ñ.ÐŽâ-ÐŽÑ ÐŸÑÑ ÐºÐµÐ·ÐµÒ£ÐœÑÒ£ ÐºÐµÐ· ÐºÐµÐ»Ð³ÐµÐœ ÐŽÐ°ÑÐ°ÑÑ Ò¯ÑÑÐœ (Ð¥ÑÐžÑÑÐŸÑÑ ÑÑÑÐ»ÒÐ°ÐœÒÐ° ÐŽÐµÐ¹ÑÐœÐ³Ñ ÐºÐµÐ·ÐµÒ£ ÐŽÐµÐ¿ ÑÐµ Ð°ÑÐ°Ð»Ð°ÐŽÑ) ÑÐ°Ò£ÐŽÐ°Ò£ÑÐ·. 
+       <li>ÐÐ·ÐŽÐµÑÐŽÑ Ð±Ð°ÑÑÐ°Ò£ÑÐ·.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>ÐÐ°ÑÐ° Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÐ·ÐŽÐµÑ ÒÐ°Ð»Ð°Ð¹ ÑÑÑÐµÐ¹ÐŽÑ</h3>
+
+Ð¡Ò±ÑÐ°ÐœÑÐŒÐœÑÒ£ ÑÐŸÐ»ÑÒÑÑÐ°Ò ÐœÓÑÐžÐ¶ÐµÑÑÐœ Ð°Ð»Ñ Ò¯ÑÑÐœ ÐžÐœÑÐµÑÐ²Ð°Ð»ÐŽÑÒ ÑÒ±ÑÐ°ÐœÑÐŒÐŽÑ, ÒÐŸÐ»ÐŽÐ°ÐœÑ Ò±ÑÑÐœÑÐ»Ð°ÐŽÑ, ÑÐµÐ±ÐµÐ±Ñ ÐºÐµÐ¹Ð±ÑÑ ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÐ° ÐŽÐ°ÑÐ°Ð»Ð°Ñ ÐœÐ°ÒÑÑ ÐºÓ©ÑÑÐµÑÑÐ»ÐŒÐµÐ³ÐµÐœ (ÐŒÑÑÐ°Ð»Ñ Ð¶ÑÐ» ÐµÐŒÐµÑ ÒÐ°ÑÑÑ ÐºÓ©ÑÑÐµÑÑÐ»ÑÑ ÐŒÒ¯ÐŒÐºÑÐœ). 
+<p>
+}
+
+_textchangeprefs_ [l=kk] {ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑÐŽÑ Ó©Ð·Ð³ÐµÑÑÑ}
+
+_texthelppreferences_ [l=kk] {<h2>_textchangeprefs_</h2>
+
+<p>ÐÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑ <i>Ð±ÐµÑÑÐœÐŽÐµ</i> (Ð±ÐµÑÑÑÒ£ Ð¶ÐŸÒÐ°ÑÒÑ Ð±Ó©Ð»ÑÐ³ÑÐœÐŽÐµÐ³Ñ ÐºÐœÐŸÐ¿ÐºÐ°) ÑÑÐ·ÐŽÐµÑ ÐžÐœÑÐµÑÑÐµÐ¹ÑÑÑÒ£ ÐºÐµÐ¹Ð±ÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐ»ÐµÑÑÐœ Ó©Ð·Ð³ÐµÑÑÐµ Ð°Ð»Ð°ÑÑÐ·. 
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑ</h3>
+
+ÐÐµÐ¹Ð±ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÐ° Ð±ÑÑÐœÐµÑÐµ ÑÑÐºÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ Ð±ÐŸÐ»Ð°ÐŽÑ, ÐŸÐ»Ð°ÑÐŽÐ° ÑÐ·ÐŽÐµÑ ÓÑÒÐ°Ð¹ÑÑÑÑÐœÐŽÐ° Ð¶ÐµÐºÐµ Ð¶ÓÐœÐµ Ð±Ð°ÑÐ»ÑÒÑÐœÐŽÐ° Ð±ÑÑÐ³Ðµ Ð¶Ò¯ÑÐ³ÑÐ·ÑÐ»Ðµ Ð°Ð»Ð°ÐŽÑ. ÐÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑ Ð±ÐµÑÑÐœÐŽÐµ ÑÑÐ· ÑÐ·ÐŽÐµÑÐ³Ðµ ÒÐŸÑÒÑÒ£ÑÐ· ÐºÐµÐ»Ð³ÐµÐœ ÑÑÐºÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑ ÑÐ°Ò£ÐŽÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Ð¢ÑÐ»ÐŽÑ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑ</h3>
+
+ÓÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° ÑÑÐ°ÐœÐŽÐ°ÑÑÑÑ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÑÑÐ»Ñ Ð±Ð°Ñ, Ð±ÑÑÐ°Ò ÑÑÐ· ÐºÐµÐ· ÐºÐµÐ»Ð³ÐµÐœ Ð±Ð°ÑÒÐ° ÑÑÐ»ÐŽÑ ÑÐ°Ò£ÐŽÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·. Ð¡ÐŸÐœÐŽÐ°Ð¹-Ð°Ò ÑÑÐ· ÐŸÑÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°ÐŽÐ° ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»Ð°ÑÑÐœ Ð±Ð°ÑÒÐ° ÐºÐŸÐŽÐžÑÐŸÐ²ÐºÐ°ÐœÑ ÑÐ°Ò£ÐŽÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·, ÑÑÐ·ÐŽÑÒ£ Ð±ÑÐ°ÑÐ·ÐµÑÐ³Ðµ ÑÑÑÐ° ÐºÐµÐ»ÐµÑÑÐœÑ Ð°Ð²ÑÐŸÐŒÐ°ÑÑÑ ÑÒ¯ÑÐŽÐµ ÑÑÐ°ÐœÐŽÐ°ÑÑÑÑ Ð±ÐŸÐ»Ð°ÐŽÑ, ÐµÒ£ ÐŽÒ±ÑÑÑÑ ÐºÐŸÐŽÐžÑÐŸÐ²ÐºÐ°ÐœÑ ÒÐŸÐ»ÐŒÐµÐœ ÑÐ°Ò£ÐŽÐ°ÒÐ°Ðœ. ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑÒ£ Ð±Ð°ÑÐ»ÑÒÑÐœÐŽÐ° ÒÐ°ÑÐ°ÑÐŽÑÒ£ Ð³ÑÐ°ÑÐžÐºÐ°Ð»ÑÒ ÑÐµÐ¶ÐžÐŒÑÐœÐµÐœ ÐŒÓÑÑÐœÐŽÑÐºÐºÐµ Ð¶ÓÐœÐµ ÐºÐµÑÑÑÑÐœÑÐµ ÐºÓ©ÑÑÐ³Ðµ Ð±ÐŸÐ»Ð°ÐŽÑ. 
+<p>_iconblankbar_
+
+<a name=pres-prefs>
+<h3 align=left>ÐÐœÑÐµÑÑÐµÐ¹ÑÑÑ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑ </h3>
+
+ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÒ£Ð° Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÑÑ ÐŸÐ»Ð°ÑÐŽÐ° ÓÑÑÒ¯ÑÐ»Ñ Ð±ÑÑÐœÐµÑÐµ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑ Ð±ÐŸÐ»Ð°ÐŽÑ. 
+
+<p>Web Ð±ÐµÑÑÐµÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑÑ ÓÑ ÒÒ±Ð¶Ð°ÑÑÑÒ£ Ð¶ÐŸÒÐ°ÑÒÑ Ð¶Ð°ÒÑÐœÐŽÐ°ÒÑ Ð±Ð°ÑÒÐ°ÑÑ Ð¿Ð°ÐœÐµÐ»ÑÐœ ÒÐŸÐ»ÐŽÐ°ÐœÑÒÐ° ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐº Ð±ÐµÑÐµÐŽÑ, ÑÐŸÐœÑÐŒÐµÐœ ÑÐ·ÐŽÐµÑÐŽÐµÐœ ÐºÐµÐ¹ÑÐœ Greenstone ÑÐ°ÒÑÑÑÐ±ÑÐœÑÑÐ· Ð±ÑÑÐŽÐµÐœ Web Ð±ÐµÑÐºÐµ ÑÒ¯ÑÐµÑÑÐ·.  ÐÐ°Ò£Ð° ÑÒ±ÑÐ°ÐœÑÐŒ Ð¶Ð°ÑÐ°Ñ Ò¯ÑÑÐœ Ó©Ð·ÑÒ£ÑÐ·ÐŽÑÒ£ Ð±ÑÐ°ÑÐ·ÐµÑÑÒ£ÑÐ·ÐŽÐµÐ³Ñ "back" ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ°Ò£ÑÐ· Ð±ÐŸÐ»ÒÐ°ÐœÑ. ÐÒ±ÐœÐŽÐ°Ð¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ WWW ÐŽÐ°ÒÑ ÑÐ»ÐµÐºÑÑÐŸÐœÐŽÑÒ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ° Ð°ÑÒÑÐŒÑÐœÐ°Ðœ ÑÑÒÐ°ÑÐ°ÑÑÐœ ÑÑÐ»ÑÐµÐŒÐµÐ»ÐµÑÐŽÑ Ð±Ð°ÑÒÐ°ÐœÐŽÐ° Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»Ð°ÑÑÐœ Ð¶Ò¯Ð¹ÐµÐ»ÑÐº ÒÐ°ÑÐµÐ»ÐµÑÐ³Ðµ ÑÑÐ¹ÑÐŒ ÑÐ°Ð»Ñ ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐ³ÑÐœ Ð±ÐµÑÐµÐŽÑ. 
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>ÐÐ·ÐŽÐµÑÐŽÑ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑ</h3>
+<p>ÐÐºÑ Ð°ÑÑÑÑÑÑÑÐ¿ ÒÐŸÑÒÑÑ ÐŒÓÑÑÐœÐŽÑ ÑÐ·ÐŽÐµÑ ÐŽÓÐ»ÐŽÑÐ³ÑÐœ Ð±Ð°ÑÒÐ°ÑÐ°ÐŽÑ. âÐ ÐµÐ³ÐžÑÑÑÐ»ÐµÑâ ÒÐ°Ð¹ÑÐ° ÒÐŸÑÒÑÑÑ ÑÐµÐ³ÐžÑÑÑÐŽÑ ÐµÑÐºÐµÑÑÐŽÑ Ó©ÑÑÑÐµÐŽÑ\ÑÑÐºÐµ ÒÐŸÑÐ°ÐŽÑ. âÐ¡Ó©Ð· Ð¶Ð°Ð»ÒÐ°ÑÐ»Ð°ÑÑâ ÒÐ°Ð¹ÑÐ° ÒÐŸÑÒÑÑÑÐ°ÑÑ ÑÓ©Ð·ÐŽÑÒ£ Ð¶Ð°Ð»ÒÐ°ÑÐ»Ð°ÑÑÐœ ÒÐŸÐ»ÐŽÐ°ÐœÑÐŽÑ ÐœÐµÐŒÐµÑÐµ ÐµÑÐºÐµÑÐŒÐµÑÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑ ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐ³ÑÐœ Ð±ÐµÑÐµÐŽÑ. âÐÐ·ÐŽÐµÑ ÑÐµÑÐµÐ·ÐµÑÑÐœÑÒ£ Ó©Ð»ÑÐµÐŒÑâ ÒÐ°Ð¹ÑÐ° ÒÐŸÑÒÑÑÑ ÑÒ±ÑÐ°ÐœÑÐŒ ÐŒÓÑÑÐœÑ ÑÐµÑÑÐœÐŽÐµ Ð±Ò¯ÑÑÐœÐŽÐµÐ¹ Ð±ÑÑ Ð°Ð±Ð·Ð°ÑÑÑ ÐµÐœÐ³ÑÐ·Ñ ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐ³ÑÐœ Ð±ÐµÑÐµÐŽÑ.  
+<p>ÐÑÑÐ°Ð»Ñ, ÐµÐ³ÐµÑ <i>ÑÐµÐ³ÐžÑÑÑÐ»ÐµÑÐŽÑ ÐµÐ»ÐµÐŒÐµÑ</i> Ð¶ÓÐœÐµ
+<i>ÑÓ©Ð· Ð¶Ð°Ð»ÒÐ°ÑÐ»Ð°ÑÑÐœ ÐµÑÐºÐµÑÐŒÐµÑ ÑÐ°Ò£ÐŽÐ°Ð»ÑÐ°</i>,ÐŸÐœÐŽÐ° ÑÒ±ÑÐ°ÐœÑÐŒ<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>ÐºÐµÐ»ÐµÑÑ ÑÒ¯ÑÐŽÐµ ÑÒ¯ÑÑÐœÑÐ»ÐµÐŽÑ<p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      Ð¡ÐµÐ±ÐµÐ±Ñ âAfricanâ ÑÓ©Ð·ÑÐœÐŽÐµÐ³Ñ Ð¶ÐŸÒÐ°ÑÒÑ ÑÐµÐ³ÐžÑÑÑ ÓÑÐ¿Ñ ÑÓ©ÐŒÐµÐœÐ³Ñ ÑÐµÐ³ÐžÑÑÑ ÓÑÐ¿ÑÐœÐµ Ó©Ð·Ð³ÐµÑÑÑÐ»ÑÐ¿, ânâ Ð¶ÓÐœÐµ âingâ Ð¶Ð°Ð»ÒÐ°ÑÐ»Ð°ÑÑ ÑÓ©Ð·ÐŽÐµÐœ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ð»ÑÐœÐ°ÐŽÑ.      "African" Ð¶ÓÐœÐµ "building" (ÑÐŸÐœÐŽÐ°Ð¹-Ð°Ò, "s" "builds" ÑÓ©Ð·ÑÐœÐµÐœ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ð»ÑÐœÐ°ÐŽÑ.).
+
+<p>Ð¡ÑÐ· ÐÓÐÐ (&), ÐÐÐÐÐ¡Ð (|), ÐÓÐÐ ÐÐÐÐ¡ Ð°ÐŒÐ°Ð»ÐŽÐ°ÑÑÐœ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ¿ ÑÒ±ÑÐ°ÐœÑÐŒÐœÑÒ£ ÐºÐµÒ£ÐµÐ¹ÑÑÐ»Ð³ÐµÐœ ÑÐŸÑÐŒÐ°ÑÑÐœÐ° ÐºÓ©ÑÐµ Ð°Ð»Ð°ÑÑÐ·. ÐÒ±Ð» ÐŽÓÐ» ÑÒ±ÑÐ°ÐœÑÐŒÐŽÐ°Ñ ÒÒ±ÑÑ ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐ³ÑÐœ Ð±ÐµÑÐµÐŽÑ. ÐÐ»ÐŽÑÒ£ÒÑ ÑÐ·ÐŽÐµÑ ÐœÓÑÐžÐ¶ÐµÐ»ÐµÑÑ ÐºÓ©ÑÑÐµÑÑÐ»Ð³ÐµÐœ ÐºÐµÐ·ÐŽÐµ ÑÒ±ÑÐ°ÐœÑÐŒ ÑÐ°ÑÐžÑ
+ÑÐœ ÐºÓ©ÑÑÐµÑÑÐŽÑ ÑÑÐºÐµ ÒÐŸÑÐ° Ð°Ð»Ð°ÑÑÐ·. ÐÒ±Ð» Ð°Ð·ÐŽÐ°Ð¿ Ó©Ð·Ð³ÐµÑÑÑÐ»Ð³ÐµÐœ ÑÒ±ÑÐ°ÐœÑÐŒÐŽÐ°Ñ ÑÒ¯ÑÑÐœ Ð¶Ð°ÑÐ°ÑÒÐ° ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐº Ð±ÐµÑÐµÐŽÑ. Ð¡ÑÐ· Ð±ÑÑ Ð±ÐµÑÑÐµÐ³Ñ ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑÒ£ Ð¶Ð°Ð»Ð¿Ñ ÑÐ°ÐœÑ ÐŒÐµÐœ ÑÐ·ÐŽÐµÑ ÐœÓÑÐžÐ¶ÐµÑÑÐœÑÒ£ Ð¶Ð°Ð»Ð¿Ñ ÑÐ°ÐœÑÐœ ÑÐµÑÑÐµÐ¹ Ð°Ð»Ð°ÑÑÐ·. 
+}
+
+_texttanumbrowseoptions_ [l=kk] {ÐÒ±Ð» ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° ÑÐ·ÐŽÐµÑÐŽÑÒ£ ÓÑ ÑÒ¯ÑÐ»Ñ ÑÓÑÑÐ»ÐŽÐµÑÑ Ð±Ð°Ñ (_numbrowseoptions_):}
+
+_textsimplehelpheading_ [l=kk] {ÐÒÐ¿Ð°ÑÐ°ÑÑÑ ÒÐ°Ð»Ð°Ð¹ ÑÐ·ÐŽÐµÑ ÐºÐµÑÐµÐº}
+
+_texthelpscope_ [l=kk] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>ÐÐ·ÐŽÐµÑ ÐŽÐžÐ°Ð¿Ð°Ð·ÐŸÐœÑ </h3>
+
+<p>
+ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑÒ£ ÐºÓ©Ð¿ÑÑÐ»ÑÐ³ÑÐœÐŽÐµ ÑÑÐ· ÓÑÑÒ¯ÑÐ»Ñ ÑÐ·ÐŽÐµÑ ÐžÐœÐŽÐµÐºÑÑÐµÑÑÐœ ÒÐŸÐ»ÐŽÐ°ÐœÐ° Ð°Ð»Ð°ÑÑÐ·. ÐÑÑÐ°Ð»Ñ, ÐºÑÑÐ°Ð¿ Ð°ÑÐ°ÑÐ»Ð°ÑÑÐœÑÒ£, Ð°Ð²ÑÐŸÑÐ»Ð°Ñ ÑÐ°ÐŒÐžÐ»ÐžÑÐ»Ð°ÑÑ ÐžÐœÐŽÐµÐºÑÑÐµÑÐŸÑÐœ. ÐÐ» ÑÐ°ÑÐ°Ñ ÐœÐµÐŒÐµÑÐµ Ð±Ó©Ð»ÑÐŒ Ð°ÑÐ°ÑÐ»Ð°ÑÑÐœÑÒ£ ÐžÐœÐŽÐµÐºÑÑÐµÑÑ ÐŽÐµ Ð±ÐŸÐ»ÑÑ ÐŒÒ¯ÐŒÐºÑÐœ. ÐÐ³ÐµÑ ÑÑÐ· ÒÐ°Ð¶ÐµÑÑÑ ÐžÐœÐŽÐµÐºÑÑÑ ÐºÓ©ÑÑÐµÑÐ¿ÐµÑÐµÒ£ÑÐ· ÐŸÐœÐŽÐ° ÑÐºÑÐ°ÐœÒÐ° ÒÒ±Ð¶Ð°ÑÑÑÒ£ Ð±ÓÑÑ ÑÑÒÐ°ÑÑÐ»Ð°ÐŽÑ. ÐÐ³ÐµÑ ÒÒ±Ð¶Ð°Ñ Ð±Ò¯ÑÑÐœÐŽÐµÐ¹ Ð±ÑÑ ÐºÑÑÐ°Ð¿ Ð±ÐŸÐ»ÑÐ° ÐŸÐœÐŽÐ° ÐŸÐ» ÑÓÐ¹ÐºÐµÑ ÐŸÑÑÐœÐŽÐ° Ð°ÑÑÐ»Ð°ÐŽÑ. 
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/kazakh2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/kazakh2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/kazakh2.dm	(revision 10506)
@@ -0,0 +1,853 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Kazakh Language text and icon macros 
+# -- this file contains text that is of less importance
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=kk] {ÒÒ±Ð¶Ð°ÑÑÐ°Ñ. }
+# -- Missing translation: _lastupdate_
+_ago_ [l=kk] {ÐºÒ¯Ðœ Ð±Ò±ÑÑÐœ.}
+_colnotbuilt_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÒÒ±ÑÑÐ»ÐŒÐ°ÐŽÑ.}
+
+# -- Missing translation: _textpagetitle_
+_textadmin_ [l=kk] {ÐÐŽÐŒÐžÐœÐžÑÑÑÐ°ÑÐžÐ²ÑÑÐº Ð±ÐµÑ}
+# -- Missing translation: _textabgs_
+# -- Missing translation: _textgsdocs_
+
+_textimagegli_ [l=kk] {ÐÐ°Ò£Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ Ð¶Ð°ÑÐ°ÑÐŽÐ°, ÑÒ¯ÑÐ»ÐµÐœÐŽÑÑÑÐŽÐµ ÐœÐµÐŒÐµÑÐµ ÒÐŸÑÑÐŽÐ° Ð¶ÓÐœÐµ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°ÑÐŽÐ° ÐºÓ©ÑÑÐµÑÑÐ»ÐµÑÑÐœ ÐºÓ©ÐŒÐµÐº }
+
+# -- Missing translation: _textimagecollector_
+
+# -- Missing translation: _textimagetranslator_
+
+# -- Missing translation: _textimageadmin_
+
+_textimagegogreenstone_ [l=kk] {Ð¡ÑÐ·Ð³Ðµ Greenstone Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒÑ ÐŒÐµÐœ ÐÐ°Ò£Ð°Ð·ÐµÐ»Ð°ÐœÐŽÐžÑ ÐŠÐžÑÑÐ»ÑÒ ÐÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°ÑÑ Ð¶ÓÐœÐµ ÐŸÐœÑÒ£ ÒÐ°Ð¹ÐŽÐ° Ð¶Ð°ÑÐ°Ð»ÒÐ°ÐœÐŽÑÒÑ ÐŒÐµÐœ ÒÐ°Ð¹ÐŽÐ° ÐŸÑÐœÐ°Ð»Ð°ÑÒÐ°ÐœÐŽÑÒÑ Ð¶Ð°Ð¹Ð»Ñ ÓÒ£Ð³ÑÐŒÐµÐ»ÐµÐ¹ÐŽÑ}
+
+_textimagegodocs_ [l=kk] {Greenstone Ð±Ð°ÑÑÑÐ»ÑÒÑ}
+
+_textpoem_ [l=kk] {<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+<p>ÑÑÐ·ÐŽÑ Ð±ÐµÐ¹Ð±ÑÑÑÑÐ»ÑÐº Ð¿ÐµÐœ ÑÑÐœÑÑÑÑÒ ÒÐŸÑÑÐ°ÑÑÐœ, 
+<p>ÑÑÐ· ÓÑÒÐ°ÑÐ°Ðœ Ð¶Ð°Ð·ÐŽÑÒ£ Ð¶ÑÐ»Ñ ÒÒ±ÑÐ°ÒÑÐœÐŽÐ° Ð±ÐŸÐ»ÑÒ£ÑÐ·, 
+<br>ÑÑÐ·ÐŽÑÒ£ ÐŒÒ±Ñ
+ÐžÑÑÐ°ÒÑ ÑÐ°ÑÑ
+Ð°ÑÑÒ£ÑÐ·ÐŽÑÒ£ ÑÑÐ»Ð°ÑÑ, Greenstone-ÐœÑÒ£ ÑÒ¯ÑÐ³ÑÐ»ÐµÐœÐ³ÐµÐœ ÒÑÑÑÐœÐŽÐ°Ð¹ ÑÐµÐ³ÑÑ Ð±ÐŸÐ»ÑÑÐœ.}
+
+_textgreenstone_ [l=kk] {<p>
+<i>Greenstone</i>  - ÐÐ°Ò£Ð°Ð·ÐµÐ»Ð°ÐœÐŽÐžÑÐŽÐ° ÑÐ°Ð±ÑÐ»ÒÐ°Ðœ (ÐŸÑÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒÒÐ° Ò±ÒÑÐ°Ñ) Ð¶Ð°ÑÑÑÐ»Ð°Ð¹ Ð±Ð°ÒÐ°Ð»Ñ ÑÐ°Ñ. ÐÐ°ÐŸÑÐžÐ»ÐµÑÐŽÑÒ£ ÐŽÓÑÑÒ¯ÑÐ»Ñ ÒÐŸÒÐ°ÐŒÑÐœÐŽÐ° ÐŸÐ» ÐµÒ£ ÒÑÐŒÐ±Ð°ÑÑÑ ÐµÐŽÑ. ÐÐ» ÑÑÑ
+Ñ ÐœÐµÐŒÐµÑÐµ Ó©ÐŒÑÑ ÐºÒ¯ÑÑ Ð±ÐŸÐ»ÑÐ¿ ÑÐ°Ð±ÑÐ»Ð°ÑÑÐœ <i> wairua-ÐœÑ,</i> Ð¶Ò±ÑÑÐ¿ Ð¶ÓÐœÐµ Ò±ÑÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐœ Ð¶ÓÐœÐµ ÐŽÓÑÑÒ¯ÑÐ»ÑÐº ÐœÐ°ÐŒÑÑ Ð¿ÐµÐœ ÒÐ°ÐŒÑÑÐ»ÒÐ°Ðœ, Ð±Ò±Ð» ÐŸÐœÑ Ð¶Ð°Ð»Ð¿Ñ ÒÐŸÐ»ÐŽÐ°ÐœÑÒÐ° Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÑÐžÑÑÐ»ÑÒ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ° Ð¶ÐŸÐ±Ð°ÑÑ Ó©ÐœÑÐŒÑÐœÐµ ÑÐŸÐ»ÑÒ ÑÐ°Ð¹ ÐºÐµÐ»ÐµÑÑÐœ ÑÐŒÐ±Ð»ÐµÐŒÐ° ÐµÑÐµÐŽÑ. ÐÐœÑÒ£ Ð¶ÑÐ»ÑÑÑÐ»ÑÒÑ ÒÐ°Ð¹ÑÑÑÐŒÐŽÑÐ»ÑÒÑÑ; ÐŸÐœÑÒ£ ÑÒ±ÐœÑÒÑÑÒÑ â Ð°ÐŽÐ°Ð»ÐŽÑÒÑÑ; ÐŸÐœÑÒ£ ÐºÑÑÑÐžÐ·ÐœÐ°ÑÑ â Ð±Ð°ÑÑÑÐ»ÑÒÑÑ; Ð°Ð» Ó©ÑÐºÑÑ ÒÑÑÑ - ÓÐŽÑÐ» ÑÓ©ÑÐµÐ»ÑÐºÑÑ Ð±ÑÐ»ÐŽÑÑÐµÐŽÑ. Greenstone ÑÐžÑÑÐ»Ñ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°ÑÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒÑ ÑÐŒÐ±Ð»ÐµÐŒÐ°ÑÑ ÑÐµÑÑÐœÐŽÐµ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»Ð°ÐŽÑ. ÐÐµÑÐµÑÑÐœ Ð±Ó©Ð»ÑÐ³Ñ â ÐŸÐ» <i>patu</i> ÐœÐµÐŒÐµÑÐµ ÐºÒ¯ÑÐµÑÑÑÑ ÐºÐ»ÑÐ± Ð¶ÓÐœÐµ Ð±ÑÐ·ÐŽÑÒ£ Ð¶ÐŸÐ±Ð° ÐŒÒ¯ÑÐµÐ»ÐµÑÑÐœÑÒ£ Ð±ÑÑÐµÑÑÐœÑÒ£ Ð¶Ð°ÐœÒ±ÑÑÑÐœÐŽÐ° ÐµÑÐµÐºÑÐµ ÒÐ°ÑÑÐµÑ ÑÒ±ÑÐ°ÑÑÐœ ÐœÓÑÑÐµÑÑ. ÐÐµÐºÐ¿Ðµ-Ð¶ÐµÐºÑÐµ ÐŸÐœÑÒ£ ÑÐµÐ°ÐºÑÐžÑÑÑ Ó©ÑÐµ Ð¶ÑÐ»ÐŽÐ°ÐŒ, Ó©ÑÐµ ÐŽÓÐ» Ð¶ÓÐœÐµ ÐœÐ°ÒÑÑ Ð°ÑÒÑÐ°Ð»ÒÐ°Ðœ. ÐÑÐ·Ð³Ðµ Ð¶ÐŸÒÐ°ÑÑÐŽÐ° Ð°Ð¹ÑÑÐ»ÒÐ°Ðœ ÒÐ°ÑÐžÐµÑÑÐµÑÐŽÑÒ£ Ð±Ð°ÑÐ»ÑÒÑ Ð±ÑÐ·ÐŽÑÒ£ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒÒÐ° ÒÐ°ÑÑÑÑÑ ÐŽÐµÐ¿ Ð°Ð» Ð±ÑÐžÑÐ²Ð°ÐœÑÒ£ Ó©ÑÐºÑÑ Ð¶Ð°ÒÑ -  <i>patu,</i>  Ð±ÑÐ·ÐŽÑÒ£ ÑÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÑÐ»Ð°ÑÐŽÑÒ£ ÑÐµÑÐºÑ ÑÐµÐ±ÑÐœÐŽÐµ ÑÒ±ÑÒÐ°ÐœÑÐŒÑÐ·ÐŽÑÒ£ ÑÐžÐŒÐ²ÐŸÐ»Ñ ÐŽÐµÐ¿ ÐŸÐ¹Ð»Ð°Ñ Ò±ÐœÐ°Ð¹ÐŽÑ. }
+
+_textaboutgreenstone_ [l=kk] {<p> Greenstone â ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°Ð»ÑÒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑÐ¿, ÑÐ°ÑÐ°ÑÑÒÐ° Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒ. ÐÒ±Ð» Ð¶Ò¯Ð¹ÐµÐŽÐµ Ð¶Ò±ÐŒÑÑ ÑÑÑÐµÑ ÑÑÐ·Ð³Ðµ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÐŽÑ Ò±Ð¹ÑÐŒÐŽÐ°ÑÑÑÑÑ ÐŒÐµÐœ ÐŸÐœÑ ÐÐœÑÐµÑÐœÐµÑ Ð¶ÐµÐ»ÑÑÑÐœÐŽÐµ ÐœÐµÐŒÐµÑÐµ CD-ROM-ÐŽÐ° Ð¶Ð°ÑÐžÑÐ»Ð°ÑÐŽÑÒ£ Ð¶Ð°Ò£Ð° ÑÓÑÑÐ»Ñ. Greenstone ÐÐ°Ð¹ÐºÐ°ÑÐŸ Ð£ÐœÐžÐ²ÐµÑÑÐžÑÐµÑÑÐœÐŽÐµ ÐÐ°Ò£Ð°Ð·ÐµÐ»Ð°ÐœÐŽÐžÑÐ»ÑÒ ÐŠÐžÑÑÐ»Ñ ÐÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ° Ð¶ÐŸÐ±Ð°ÑÑ Ð°ÑÒÑÐŒÑÐœÐŽÐ° Ð¶Ð°ÑÐ°Ð»ÒÐ°Ðœ Ð¶ÓÐœÐµ Ð®ÐÐÐ¡ÐÐ ÐŒÐµÐœ Info NGO ÒÐŸÐ»ÐŽÐ°ÑÑÐŒÐµÐœ ÑÐ°ÑÐ°ÑÑÐ»ÑÐŽÐ°. ÐÐ» ÐµÑÐºÑÐœ ÑÐ°ÑÐ°ÑÑÐ»Ð°ÑÑÐœ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒ ÐŸÐœÑ <a href="http://greenstone.org"> http://greenstone.org </a> Ð°ÐŽÑÐµÑÑÐœÐµÐœ GNU Ð»ÐžÑÐµÐœÐ·ÐžÑÑÑÐœÐ° ÑÓÐ¹ÐºÐµÑ Ð°Ð»ÑÒÐ° Ð±ÐŸÐ»Ð°ÐŽÑ.
+
+<br>ÐÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒÑÑÒ£ ÐŒÐ°ÒÑÐ°ÑÑ, ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»Ð°ÑÒÐ°, ÓÑÑÑÐµÑÐµ ÑÐœÐžÐ²ÐµÑÑÐžÑÐµÑÑÐµÑÐŽÐµ, ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°Ð»Ð°ÑÐŽÐ° Ð¶ÓÐœÐµ Ð±Ð°ÑÒÐ° ÒÑÐ·ÐŒÐµÑ ÐºÓ©ÑÑÐµÑÑÑÑ ÐŒÐµÐºÐµÐŒÐµÐ»ÐµÑÐŽÐµ ÐŸÐ»Ð°ÑÐŽÑÒ£ Ð¶ÐµÐºÐµ ÐŠÐžÑÑÐ»Ñ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°Ð»Ð°ÑÑÐœ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐ³ÑÐœ Ð±ÐµÑÑ. ÐŠÐžÑÑÐ»Ñ ÐÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°Ð»Ð°Ñ Ð®ÐÐÐ¡ÐÐ Ð°ÑÒÑÐŒÑÐœÐŽÐ° ÒÑÐ»ÑÐŒ, Ð±ÑÐ»ÑÐŒ Ð±ÐµÑÑ Ð¶ÓÐœÐµ ÐŒÓÐŽÐµÐœÐžÐµÑ ÑÐ°Ð»Ð°ÑÑÐœÐŽÐ° ÐŽÒ¯ÐœÐžÐµ Ð¶Ò¯Ð·Ñ Ð±ÐŸÐ¹ÑÐœÑÐ° ÓÑ ÑÒ¯ÑÐ»Ñ ÐŒÐµÐºÐµÐŒÐµÐ»ÐµÑÐŒÐµÐœ ÒÐ°ÑÑÐŒ ÒÐ°ÑÑÐœÐ°Ñ Ð¶Ð°ÑÐ°Ð¿ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÐŽÑ Ð°Ð»ÑÐ¿, ÑÐ°ÑÐ°ÑÑÐŽÑ ÑÐ°ÐŽÐžÐºÐ°Ð»ÐŽÑ ÑÒ¯ÑÐ»ÐµÐœÐŽÑÑÐµÐŽÑ. ÐÑÐ· Ð±Ò±Ð» Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒ ÐŠÐžÑÑÐ»Ñ ÐÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°Ð»Ð°ÑÐŽÑ, Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ¿ ÐŸÐ»Ð°ÑÒÐ° ÐºÓ©Ð¿ÑÑÐ»ÑÐºÑÑÒ£ ÒÐŸÐ»Ñ Ð¶ÐµÑÐµÑÑÐœÐŽÐµÐ¹ ÐµÑÑÐ¿ ÐŸÑÐœÐ°Ð»Ð°ÑÑÑÑÑ ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐ³ÑÐœ Ð±ÐµÑÑÐ³Ðµ ÓÑÐµÑ ÐµÑÐµÐŽÑ.
+
+<br>ÐÒ±Ð» Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒ 2000 Ð¶ÑÐ»Ñ ÑÐ°ÐŒÑÐ·ÐŽÐ° ÐŸÑÐœÐ°ÑÑÐ»ÒÐ°Ðœ Ò¯Ñ Ð¶Ð°ÒÑÑ Ñ
+Ð°Ð»ÑÒÐ°ÑÐ°Ð»ÑÒ Ó©Ð·Ð°ÑÐ° ÑÐžÑÐŒÐŽÑ ÒÐ°ÑÑÐœÐ°Ñ ÐœÓÑÐžÐ¶ÐµÑÑÐœÐŽÐµ Ð¶Ð°ÑÐ°Ð»ÒÐ°Ðœ Ó©ÐœÑÐŒ ÑÐµÑÑÐœÐŽÐµ ÑÐ°ÑÐ°ÑÑÐ»Ð°ÐŽÑ. 
+
+<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 Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒÑ ÐŸÑÑ Ð¶ÐŸÐ±Ð°ÐŽÐ°Ðœ Ó©ÑÐºÐµÐœ Ð¶ÓÐœÐµ ÐŸÐ» ÐÐ°Ò£Ð°Ð·ÐµÐ»Ð°ÐœÐŽÐžÑÐœÑÒ£ Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÑÐ°Ñ Ð¶Ó©ÐœÑÐœÐŽÐµÐ³Ñ Ò±Ð»ÑÑÑÒ ÐºÐŸÐŒÐžÑÑÐžÑÑÑÐœÑÒ£ ÒÐŸÑÐ°Ð»ÒÑ ÐºÐŸÐŒÐžÑÑÐžÑÑÑÐŒÐµÐœ Ð®ÐÐÐ¡ÐÐ Ò¯ÑÑÐœ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»ÒÐ°Ðœ Ð®ÐÐÐ¡ÐÐ Ð¶ÐŸÐ±Ð°ÑÑÐœÐ° ÐÐ°Ò£Ð°Ð·ÐµÐ»Ð°ÐœÐŽÐžÑÐœÑÒ£ ÒÐŸÑÒÐ°Ðœ Ò¯Ð»ÐµÑ Ð±Ó©Ð»ÑÐ³Ñ ÑÐµÑÑÐœÐŽÐµ. 
+</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> ÒÑÐ»ÑÐŒÐž, Ð±ÑÐ»ÑÐŒ Ð±ÐµÑÑ Ð¶ÓÐœÐµ ÐŒÓÐŽÐµÐœÐž Ð°ÒÐ¿Ð°ÑÐŽÑ ÐŽÒ¯ÐœÐžÐµ Ð¶Ò¯Ð·ÑÐœÐŽÐµ ÑÐ°ÑÐ°ÑÑ Ð¶ÓÐœÐµ ÓÑÑÑÐµÑÐµ ÐŽÐ°ÐŒÑÑÑ ÐµÐ»ÐŽÐµÑÐŽÐµ ÐŸÒÐ°Ðœ ÐµÑÐºÑÐœ ÐµÐœÑ Ð®ÐÐÐ¡ÐÐ-ÐœÑÒ£ Ð±Ð°ÑÑÑ ÐŒÐ°ÒÑÐ°ÑÑ Ð¶ÓÐœÐµ ÐŸÐ» âÐÐ°ÑÐ»ÑÒÑ Ò¯ÑÑÐœ Ð°ÒÐ¿Ð°ÑÐ°Ñâ Ò¯ÐºÑÐŒÐµÑÐ°ÑÐ°Ð»ÑÒ Ð¶ÐŸÐ±Ð° ÑÐµÒ£Ð±ÐµÑÑÐœÐŽÐµ ÒÐ°ÑÐ°ÑÑÑÑÑÐ»ÑÐ¿ ÑÓÐ¹ÐºÐµÑÑÐœÑÐµ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÒÐ° ÐµÐœÑ, Ð±Ð°Ð¹Ð»Ð°ÐœÑÑ ÑÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÑÐ»Ð°ÑÑ ÐŸÑÑÐœÐŽÐ° ÐŒÐ°Ò£ÑÐ·ÐŽÑ ÒÒ±ÑÐ°Ð» ÑÐµÑÑÐœÐŽÐµ Ð±ÐµÐ»Ð³ÑÐ»ÐµÐœÐ³ÐµÐœ.
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/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>
+ÐÒ±Ð» Ð¶ÐŸÐ±Ð° ÐÒ°Ò° Ð°Ð³ÐµÐœÑÑÑÐºÑÐµÑÑ ÐŒÐµÐœ Ð±Ð°ÑÒÐ°ÐŽÐ° Ò¯ÐºÑÐŒÐµÑÑÑÐº ÐµÐŒÐµÑ Ò±Ð¹ÑÐŒÐŽÐ°ÑÐŒÐµÐœ Ð¶Ò±ÐŒÑÑ ÑÑÑÐµÐ¹ÐŽÑ Ð¶ÓÐœÐµ ÑÐžÑÑÐ»Ñ ÒÒ±Ð¶Ð°ÑÑÐ°Ñ ÑÐ°Ð»Ð°ÑÑÐœÐŽÐ° ÐŽÒ¯ÐœÐžÐµ Ð¶Ò¯Ð·ÑÐ»ÑÐº Ð±ÐµÐŽÐµÐ»Ñ Ð±Ð°Ñ, Ð°ÐŽÐ°ÐŒÐ·Ð°Ñ ÐŽÐ°ÐŒÑÑÐœÐ° ÒÑÐ·ÑÒÑÑ Ð¶ÓÐœÐµ ÐµÑÐºÑÐœ ÒÐŸÐ» Ð¶ÐµÑÐºÑÐ·ÑÐ»ÐµÐŽÑ, ÐŽÐ°ÐŒÑÑÑ ÐµÐ»ÐŽÐµÑ Ò¯ÑÑÐœ ÑÐµÐ³ÑÐœ.
+</td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: selcolgr
+# -- Missing translation: _httpiconselcolgr_
+# -- Missing translation: _widthselcolgr_
+# -- Missing translation: _heightselcolgr_
+# -- Missing translation: _altselcolgr_
+
+
+# -- Missing translation: cgli
+# -- Missing translation: _httpiconcgliof_
+# -- Missing translation: _httpiconcglion_
+# -- Missing translation: _widthcgli_
+
+# -- Missing translation: ccol
+# -- Missing translation: _httpiconccolof_
+# -- Missing translation: _httpiconccolon_
+# -- Missing translation: _widthccol_
+
+# -- Missing translation: ctrans
+# -- Missing translation: _httpiconctransof_
+# -- Missing translation: _httpiconctranson_
+# -- Missing translation: _widthctrans_
+
+# -- Missing translation: cadmin
+# -- Missing translation: _httpiconcadminof_
+# -- Missing translation: _httpiconcadminon_
+# -- Missing translation: _widthcadmin_
+
+# -- Missing translation: cabgs
+# -- Missing translation: _httpiconcabgsof_
+# -- Missing translation: _httpiconcabgson_
+# -- Missing translation: _widthcabgs_
+
+# -- Missing translation: cgsdoc
+# -- Missing translation: _httpiconcgsdocof_
+# -- Missing translation: _httpiconcgsdocon_
+# -- Missing translation: _widthcgsdoc_
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=kk] {ÐÑÑÐœÐŽÐ° Ð¶ÓÐœÐµ Ð±Ò±ÐŽÐ°Ðœ Ð±ÑÐ»Ð°Ð¹ Ò¯Ð¹ Ð±ÐµÑÑÐœÐŽÐµ 4 ÐºÐœÐŸÐ¿ÐºÐ° ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»Ð°ÐŽÑ}
+
+# -- Missing translation: _textnocollections_
+
+_text1coll_ [l=kk] {Greenstone-ÐœÑÒ£ ÐŸÑÑ ÐŸÑÐœÐ°ÑÑÐ»ÑÐŒÑÐœÐŽÐ° 1 ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±Ð°Ñ}
+
+_textmorecolls_ [l=kk] {Greenstone-ÐœÑÒ£ ÐŸÑÑ ÐŸÑÐœÐ°ÑÑÐ»ÑÐŒÑÐœÐŽÐ°  _1_ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±Ð°Ñ}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=kk] {Ð¡ÑÑÑÒÑ ÑÑÐ»ÑÐµÐŒÐµ}
+# -- Missing translation: _textlinknotfound_
+
+_textextlinkcontent_ [l=kk] {<p>Ð¡ÑÐ·ÐŽÑÒ£ ÑÐ°Ò£ÐŽÐ°ÒÐ°Ðœ ÑÑÐ»ÑÐµÐŒÐµÒ£ÑÐ·, ÒÐ°Ð·ÑÑ ÑÐ°Ò£ÐŽÐ°Ð»ÒÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÒÐ° ÒÐ°ÑÐ°ÒÐ°ÐœÐŽÐ° ÑÑÑÑÒÑ Ð±ÐŸÐ»ÑÐ¿ ÑÐ°Ð±ÑÐ»Ð°ÐŽÑ. ÐÐ³ÐµÑ ÑÑÐ· ÐŸÑÑ ÑÑÐ»ÑÐµÐŒÐµ Ð±ÐŸÐ¹ÑÐœÑÐ° Ð±Ð°ÑÒÑÒ£ÑÐ· ÐºÐµÐ»ÑÐµ Ð¶ÓÐœÐµ ÑÑÐ·ÐŽÑÒ£ Ð±ÑÐ°ÑÐ·ÐµÑÑÒ£ÑÐ· ÐÐœÑÐµÑÐœÐµÑ Ð¶ÐµÐ»ÑÑÑÐœÐµ ÐµÐœÐµ Ð°Ð»Ð°ÑÑÐœ Ð±ÐŸÐ»ÑÐ°, ÑÑÐ· <a href="_nexturl_">  ÐŸÐŽÐ°Ðœ ÐºÐµÐ¹ÑÐœ ÐŸÑÑ Ð±ÐµÑÐºÐµ ÐºÓ©ÑÐµ Ð°Ð»Ð°ÑÑÐ· </a>; Ð±ÐŸÐ»ÐŒÐ°ÑÐ° "back/Ð°ÑÑÒÐ°" ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð°Ð»ÐŽÑÒ£ÒÑÒÐ° ÒÐ°Ð¹ÑÐ° ÐŸÑÐ°Ð»Ñ Ò¯ÑÑÐœ Ó©Ð· Ð±ÑÐ°ÑÐ·ÐµÑÑÒ£ÑÐ·ÐŽÐµ ÒÐŸÐ»ÐŽÐ°ÐœÑÒ£ÑÐ·.}
+
+# -- Missing translation: _textlinknotfoundcontent_
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=kk] {" _2 _ " ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑÑÐœÐ° ÑÑÐ»ÑÐµÐŒÐµ
+Ð¡ÑÐ· ÑÐ°Ò£ÐŽÐ°ÒÐ°Ðœ, ÑÑÐ»ÑÐµÐŒÐµ " _collectionname _ " ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑÑÐœÐ° ÑÑÑÑÒÑ Ð±ÐŸÐ»Ð°ÐŽÑ (ÐŸÐ» " _2 _ " ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑÑÐŒÐµÐœ Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÑÑÑÑÐ»Ð°ÐŽÑ). ÐÐ³ÐµÑ ÑÑÐ· ÐŸÑÑ ÑÑÐ»ÑÐµÐŒÐµ Ð±ÐŸÐ¹ÑÐœÑÐ° " _2 _ " ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑÑÐœÐ° ÐºÓ©ÑÐºÑÒ£ÑÐ· ÐºÐµÐ»ÑÐµ, ÐŸÐœÐŽÐ° ÑÑÐ· <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">    Ð±Ò±ÐŽÐ°Ðœ ÓÑÑ ÐŸÑÑ Ð±ÐµÑÐºÐµ Ð±Ð°ÑÐ° Ð°Ð»Ð°ÑÑÐ· </a>; Ð±ÐŸÐ»ÐŒÐ°ÑÐ° Ó©Ð· Ð±ÑÐ°ÑÐ·ÐµÑÑÒ£ÑÐ·ÐŽÐµÐ³Ñ "back/Ð°ÑÑÒÐ°" ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð°Ð»ÐŽÑÒ£ÒÑ ÒÒ±Ð¶Ð°ÑÒÐ° ÒÐ°Ð¹ÑÑÐ¿ ÐŸÑÐ°Ð»Ñ Ò¯ÑÑÐœ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑÒ£ÑÐ·. }
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=kk] {Greenstone ÐŠÐžÑÑÐ»Ñ ÐÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°ÑÑ}
+
+_textusername_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ Ð°ÑÑ}
+_textpassword_ [l=kk] {ÐÐ°ÑÐŸÐ»Ñ}
+
+_textmustbelongtogroup_ [l=kk] {ÐÓ©Ò£ÑÐ» Ð°ÑÐŽÐ°ÑÑÒ£ÑÐ·, Ð±Ò±Ð» Ð±ÐµÑÐºÐµ ÐµÐœÑ Ò¯ÑÑÐœ ÑÑÐ· "_cgiargug_" ÑÐŸÐ±ÑÐœÐ° Ð¶Ð°ÑÑÑÒ£ÑÐ· ÒÐ°Ð¶ÐµÑ}
+
+_textmessageinvalid_ [l=kk] {Ð¡ÑÐ· ÑÒ±ÑÐ°ÒÐ°Ðœ Ð±ÐµÑ Ð°Ð²ÑÐŸÑÐžÐ·Ð°ÑÐžÑÐ»Ð°ÑÐŽÑ ÑÐ°Ð»Ð°Ð¿ ÐµÑÐµÐŽÑ.
+_If_(_cgiargug_,[_textmustbelongtogroup_]<br>) Greenstone-ÒÐ° ÐµÐœÑ Ò¯ÑÑÐœ Ó©Ð·ÑÒ£ÑÐ·ÐŽÑÒ£ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»ÑÒ Ð°ÑÑÒ£ÑÐ·ÐŽÑ Ð¶ÓÐœÐµ Ð¿Ð°ÑÐŸÐ»ÑÒ£ÑÐ·ÐŽÑ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·. }
+
+_textmessagefailed_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ Ð°ÑÑ ÐœÐµÐŒÐµÑÐµ Ð¿Ð°ÑÐŸÐ»Ñ ÐŽÒ±ÑÑÑ ÐµÐœÐ³ÑÐ·ÑÐ»ÐŒÐµÐ³ÐµÐœ.}
+
+_textmessagedisabled_ [l=kk] {ÐÐµÑÑÑÑÒ£ÑÐ·, ÑÑÐ·ÐŽÑÒ£ ÐµÑÐµÐ¿ÑÑÐº Ð¶Ð°Ð·ÑÑÒ£ÑÐ·ÒÐ° Ð±Ð»ÐŸÐº ÒÐŸÐ¹ÑÐ»ÒÐ°Ðœ ÐŸÑÑ ÑÐ°Ð¹ÑÑÑÒ£ Web-ÑÐµÐ±ÐµÑÑÐŒÐµÐœ Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÑÒ£ÑÐ·.}
+
+_textmessagepermissiondenied_ [l=kk] {ÐÐµÑÑÑÑÒ£ÑÐ· ÑÑÐ· ÑÒ±ÑÐ°ÒÐ°Ðœ Ð±ÐµÑÐºÐµ ÐµÐœÑÐ³Ðµ ÒÐ°Ð¶ÐµÑÑÑ Ó©ÐºÑÐ»ÐµÑÑÑÐ»ÑÐ³ÑÒ£ÑÐ· Ð¶ÐŸÒ.}
+
+_textmessagestalekey_ [l=kk] {Ð¡ÑÐ· Ð¶Ò¯ÑÑÐ¿ Ó©ÑÐºÐµÐœ ÑÑÐ»ÑÐµÐŒÐµ Ð¶Ð°Ò£Ð°ÑÑÑÐ»ÒÐ°Ðœ. Ð¡Ò±ÑÐ°ÒÐ°Ðœ Ð±ÐµÑÑÒ£ÑÐ·Ð³Ðµ ÐµÐœÑ Ò¯ÑÑÐœ Ð¿Ð°ÑÐŸÐ»ÑÐŽÑ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·.}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=kk] {<br>
+Greenstone-ÐœÑÒ£ Ð±Ò±Ð» ÐŸÑÐœÐ°ÑÑÐ»ÑÐŒÑÐœÐŽÐ° ÐµÑÒÐ°ÐœÐŽÐ°Ð¹ ÒÒ±Ð¶Ð°Ñ Ð¶ÐŸÒ. ÐÒ±ÐœÑÒ£ Ð±ÐŸÐ»Ð°ÑÑÐœ ÑÐµÐ±ÐµÐ¿ÑÐµÑÑ:
+1. Greenstone ÑÒÑÐ°ÐŒÐŽÑ ÐŸÑÐœÐ°ÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑÐœ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ¿ CD-ROM-ÐœÐ°Ðœ ÐŸÑÐœÐ°ÑÑÐ»ÒÐ°Ðœ.
+2. Greenstone ÐÐœÑÐµÑÐœÐµÑ Ð¶ÐµÐ»ÑÑÑ Ð°ÑÒÑÐ»Ñ Ð¶Ò¯ÐºÑÐµÐ»Ð³ÐµÐœ ÐŽÐžÑÑÑÐžÐ±ÑÑÐžÐ²ÑÐµÑÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ¿ ÐŸÑÐœÐ°ÑÑÐ»ÒÐ°Ðœ. 
+ÐÒ±Ð» Ð¶Ð°ÒÐŽÐ°Ð¹Ð»Ð°ÑÐŽÑÒ£ ÒÐ°Ð¹-ÒÐ°Ð¹ÑÑÑÑÐœÐŽÐ° Ð±ÐŸÐ»ÐŒÐ°ÑÑÐœ ÑÑÐ· ÒÒ±Ð¶Ð°ÑÑÐ°ÑÐŽÑ docs ÐŽÐžÑÐµÐºÑÐŸÑÐžÑÐœÐµÐœ CD-ROM-ÐŽÐ°ÒÑ ÐŸÑÐœÐ°ÑÑÐ»ÑÐŒÑÐœÐ°Ðœ ÐœÐµÐŒÐµÑÐµ <a href=" http://www.greenstone.org "> http://www.greenstone.org. </a> ÑÐ°Ð¹ÑÑÐœÐ°Ðœ ÑÐ°Ð±Ð° Ð°Ð»Ð°ÑÑÐ·}
+
+_textuserguide_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÒÐ° Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÐœÒ±ÑÒÐ°Ñ}
+# -- Missing translation: _textinstallerguide_
+_textdeveloperguide_ [l=kk] {ÐÐ°ÑÐ°ÑÑÑÒÐ° Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ ÐœÒ±ÑÒÐ°Ñ}
+# -- Missing translation: _textpaperguide_
+# -- Missing translation: _textorganizerguide_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: gsdocsgr
+# -- Missing translation: _httpicongsdocsgr_
+# -- Missing translation: _widthgsdocsgr_
+# -- Missing translation: _heightgsdocsgr_
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textdefaultstructure_
+_textmore_ [l=kk] {ÐÓ©Ð±ÑÑÐµÐº}
+# -- Missing translation: _textcollector_
+_textinfo_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÑÑÐ°Ð»Ñ Ð°ÒÐ¿Ð°ÑÐ°Ñ}
+_textsrce_ [l=kk] {ÐÓÐ»ÑÐŒÐµÑÑÐµÑ Ð±Ò±Ð»Ð°ÒÑ}
+_textconf_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑÐ»Ð°Ñ}
+_textbild_ [l=kk] {ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ}
+_textview_ [l=kk] {ÒÐ°ÑÐ°Ñ}
+_textdel_ [l=kk] {ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ñ}
+# -- Missing translation: _textexpt_
+
+# -- Missing translation: _textdownloadingfiles_
+# -- Missing translation: _textimportingcollection_
+# -- Missing translation: _textbuildingcollection_
+# -- Missing translation: _textcreatingcollection_
+
+# -- Missing translation: _textcollectorblurb_
+
+_textcb1_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ ÑÑÐ·Ð³Ðµ Ð¶Ð°Ò£Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑ Ð¶Ð°ÑÐ°Ð¿, Ð±Ð°ÑÐ»Ð°ÑÑÐœ ÒÐŸÑÑÐ¿ Ð¶ÐµÑÑÐ»ÐŽÑÑÑÐ¿ ÐœÐµÐŒÐµÑÐµ Ó©Ð·Ð³ÐµÑÑÑÐ³Ðµ, ÐœÐµÐŒÐµÑÐµ ÐŸÐ»Ð°ÑÐŽÑ ÐŒÒ¯Ð»ÐŽÐµ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°ÑÒÐ° ÐºÓ©ÐŒÐµÐºÑÐµÑÐµÐŽÑ. ÐÒ±ÐœÑ ÑÑÑÐµÑ Ò¯ÑÑÐœ ÑÑÐ·Ð³Ðµ Ð±ÑÑÒÐ°ÑÐ°Ñ Web-Ð±ÐµÑÑÐµÑÐŽÐµÐœ Ó©ÑÑÐ¿ ÐŸÐ»Ð°Ñ ÑÒ±ÑÐ°ÒÐ°Ðœ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÐŽÑ Ð±ÐµÑÑÑÒ£ÑÐ· ÐºÐµÑÐµÐº. }
+
+_textcb2_ [l=kk] {ÐÒ£ Ð°Ð»ÐŽÑÐŒÐµÐœ ÑÑÐ·, ÐœÐµ ÑÑÑÐµÐ¹ÑÑÐœÐŽÑÐ³ÑÒ£ÑÐ·ÐŽÑ ÑÐµÑÑÑÒ£ÑÐ· ÐºÐµÑÐµÐº:}
+_textcnc_ [l=kk] {Ð¶Ð°Ò£Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¶Ð°ÑÐ°Ñ}
+_textwec_ [l=kk] {Ð±Ð°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŒÐµÐœ Ð¶Ò±ÐŒÑÑ Ð¶Ð°ÑÐ°Ñ, ÒÐŸÑÑ ÐœÐµÐŒÐµÑÐµ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ñ.}
+
+_textcb3_ [l=kk] {ÐÐ°Ò£Ð°ÐœÑ Ð¶Ð°ÑÐ°Ñ ÐœÐµÐŒÐµÑÐµ Ð±Ð°ÑÑÐœ ÐŒÐŸÐŽÐžÑÐžÐºÐ°ÑÐžÑÐ»Ð°Ñ Ð¶Ð°ÒÐŽÐ°Ð¹ÑÐœÐŽÐ°, ÑÑÐ·Ð³Ðµ Ð°Ð²ÑÐŸÑÐžÐ·Ð°ÑÐžÑÐ»Ð°Ñ Ð¿ÑÐŸÑÐµÐŽÑÑÐ°ÑÑ Ð°ÑÒÑÐ»Ñ Ó©ÑÑ ÐºÐµÑÐµÐº. ÐÒ±Ð» ÑÑÐ·ÐŽÑ ÑÑÐ·ÐŽÑÒ£ ÐºÐŸÐŒÐ¿ÑÑÑÐµÑÐ³Ðµ Ð±Ð°ÑÒÐ°Ð»Ð°ÑÐŽÑÒ£ ÐµÐœÑÑÐœÐµÐœ Ð¶ÓÐœÐµ ÑÑÐ·ÐŽÑÒ£ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÑÒ£ÑÐ·ÐŽÑ Ó©Ð·Ð³ÐµÑÑÑÐŽÐµÐœ ÑÐ°ÒÑÐ°Ð¹ÐŽÑ. ÐÐ°Ð·Ð°Ñ Ð°ÑÐŽÐ°ÑÑÒ£ÑÐ·ÐŽÐ°Ñ: ÒÐ°ÑÑÐ¿ÑÑÐ·ÐŽÑÐºÑÑ ÑÐ°ÒÑÐ°Ñ ÐŒÐ°ÒÑÐ°ÑÑÐœÐŽÐ° ÑÑÐ· Ð°Ð²ÑÐŸÐŒÐ°ÑÑÑ ÑÒ¯ÑÐŽÐµ ÑÑÑÐºÐµÐ»ÐµÑÑÐ·, ÑÑÐ· Ð°Ð²ÑÐŸÑÐžÐ·Ð°ÑÐžÑÐ»Ð°Ñ Ð¿ÑÐŸÑÐµÐŽÑÑÐ°ÑÑÐœ Ó©ÑÑÑÒ£ÑÐ· ÐºÐµÑÐµÐº. ÐÐ³ÐµÑ ÐŸÑÑÐ»Ð°Ð¹ Ð±ÐŸÐ»ÑÐ° ÒÐŸÐ±Ð°Ð»Ð¶ÑÐŒÐ°Ò£ÑÐ·! â Ð¡ÑÐ·ÐŽÑ ÐµÐœÑÐ³Ðµ ÒÐ°Ð¹ÑÐ°ÐŽÐ°Ðœ ÑÐ°ÒÑÑÐ°ÐŽÑ â ÑÑÐ· ÑÐŸÐ» ÑÐŸÒÑÐ°ÒÐ°Ðœ Ð¶ÐµÑÑÒ£ÑÐ·ÐŽÐµÐœ Ð¶Ð°Ð»ÒÐ°ÑÑÑÑÐ° Ð°Ð»Ð°ÑÑÐ·.
+}
+
+_textcb4_ [l=kk] {Greenstone Ò¯ÑÑÐœ Ó©Ð·ÑÒ£ÑÐ·ÐŽÑÒ£ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»ÑÒ Ð°ÑÑÒ£ÑÐ·ÐŽÑ Ð¶ÓÐœÐµ Ð¿Ð°ÑÐŸÐ»ÑÒ£ÑÐ·ÐŽÑ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·ÐŽÐµ ÑÐ°ÑÑÐ°Ñ ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÒ£ÑÐ·. }
+
+_textfsc_ [l=kk] {ÐÐ»ÐŽÑÐŒÐµÐœ ÑÑÐ· Ð¶Ò±ÐŒÑÑ ÑÑÑÐµÐ¹ÐŒÑÐœ ÐŽÐµÐ³ÐµÐœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑ ÐºÓ©ÑÑÐµÑÑÒ£ÑÐ· (Ð¶Ð°Ð·ÑÐŽÐ°Ðœ ÒÐŸÑÒÐ°Ð»ÒÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ Ð±Ò±Ð» ÑÑÐ·ÑÐŒÐŽÐµ Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»ÐŒÐ°Ð¹ÐŽÑ). }
+
+_textwtc_ [l=kk] {Ð¢Ð°Ò£ÐŽÐ°Ð»ÒÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒÐµÐœ ÑÑÐ· ÐºÐµÐ»ÐµÑÑ Ð°ÐŒÐ°Ð»ÐŽÐ°Ñ Ð¶Ð°ÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·:}
+_textamd_ [l=kk] {ÒÐŸÑÑÐŒÑÐ° ÐŒÐ°ÑÐµÑÐžÐ°Ð»ÐŽÐ°ÑÐŽÑ ÒÐŸÑÑÐ¿ Ð¶ÓÐœÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÒÐ°Ð¹ÑÐ° ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÐ° Ð°Ð»Ð°ÑÑÐ·}
+_textetc_ [l=kk] {ÐÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑÐ»ÑÒ ÑÐ°Ð¹Ð»ÐŽÐ°ÑÐŽÑ ÑÒ¯Ð·ÐµÑÑÐ¿ ÐºÐŸÐ»ÐµÐºÑÐžÑÐœÑ ÒÐ°Ð¹ÑÐ° ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÐ° Ð°Ð»Ð°ÑÑÐ· }
+_textdtc_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÑÐŸÐ»ÑÒÑÐŒÐµÐœ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·}
+_textetcfcd_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ Ó©Ð·Ñ ÐŸÑÐœÐ°ÑÑÐ»Ð°ÑÑÐœ Windows CD-ROM-ÒÐ° Ð¶Ð°Ð·Ñ Ò¯ÑÑÐœ ÑÐºÑÐ¿ÐŸÑÑÑÐ°Ñ}
+# -- Missing translation: _textcaec_
+_textnwec_ [l=kk] {ÐÐ°Ð·ÑÐŽÑ ÒÐŸÐ»ÐŽÐ°Ð¹ÑÑÐœ ÐµÑÐ±ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÒÐ° Ó©Ð·Ð³ÐµÑÑÑ Ò¯ÑÑÐœ ÐµÐœÑÐ³Ðµ Ð±ÐŸÐ»ÐŒÐ°Ð¹ÐŽÑ }
+# -- Missing translation: _textcianc_
+_texttsosn_ [l=kk] {ÐÐ°Ò£Ð° ÐŠÐžÑÑÐ»Ñ ÐÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°ÐœÑÒ£ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑÑÐœ Ð¶Ð°ÑÐ°ÑÒÐ° ÒÐ°Ð¶ÐµÑ ÒÐ°ÐŽÐ°ÐŒÐŽÐ°Ñ ÑÑÐ·Ð±ÐµÐ³Ñ:}
+_textsin_ [l=kk] {ÐÑÑÐœ ÐºÓ©ÑÑÐµÑÑÒ£ÑÐ· (Ð¶ÓÐœÐµ Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÒÐ°Ðœ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÑ)}
+_textswts_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÒÒ±ÑÑÐ»Ð°ÑÑÐœ ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑ Ð±Ò±Ð»Ð°ÒÑÐœ ÐºÓ©ÑÑÐµÑÑÒ£ÑÐ·}
+_textatco_ [l=kk] {ÐÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑ ÐŸÐ¿ÑÐžÑÐ»Ð°ÑÑÐœ ÑÒ¯Ð·ÐµÑÑ (ÑÐµÐº ÑÓÐ¶ÑÑÐžÐ±ÐµÐ»Ñ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»Ð°Ñ Ò¯ÑÑÐœ)}
+_textbtc_ [l=kk] {"ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ" ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ (ÑÓ©ÐŒÐµÐœÐœÐµÐœ ÒÐ°ÑÐ°)}
+_textpvyh_ [l=kk] {ÓšÐ·ÑÒ£ÑÐ·ÐŽÑÒ£ ÒÐŸÐ»ÑÒ£ÑÐ·Ð±ÐµÐœ ÑÑÑÐµÐ³ÐµÐœ Ð¶Ò±ÐŒÑÑ ÐœÓÑÐžÐ¶ÐµÑÑÐœÐµ ÐŒÐ°ÒÑÐ°ÐœÑÑÐ¿ÐµÐœ ÒÐ°ÑÐ°Ò£ÑÐ·.}
+
+_texttfsiw_ [l=kk] {Ð¢Ó©ÑÑÑÐœÑÑ ÒÐ°ÐŽÐ°ÐŒ â Ð±Ò±Ð» ÑÑÐ·ÐŽÑÒ£ ÐºÐŸÐŒÐ¿ÑÑÑÐµÑÑÒ£ÑÐ·ÐŽÑÒ£ Ð¶Ò±ÐŒÑÑÑ. "ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ" Ò¯ÑÐŽÑÑÑÐœÐŽÐµ ÐºÐŸÐŒÐ¿ÑÑÑÐµÑ Ð±Ð°ÑÐ»ÑÒ ÐžÐœÐŽÐµÐºÑÑÐµÑÐŽÑ Ð¶Ð°ÑÐ°Ð¿, ÐºÐµÐ·-ÐºÐµÐ»Ð³ÐµÐœ Ð±Ð°ÑÒÐ° Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÐŽÑ Ð±ÑÑÐ³Ðµ Ð¶ÐžÐœÐ°Ð¹ÐŽÑ. ÐÑÑÐ°Ò ÑÑÐ· ÐµÒ£ Ð°Ð»ÐŽÑÐŒÐµÐœ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÐŽÑ Ð°ÐœÑÒÑÐ°Ð¿ Ð°Ð»ÑÑÒ£ÑÐ· ÒÐ°Ð¶ÐµÑ. }
+
+_textadab_ [l=kk] {Ð¢Ó©ÐŒÐµÐœÐŽÐµ, ÑÑÐ·ÐŽÑÒ£ ÒÐ°Ð¹ ÐºÐµÐ·ÐµÒ£ÐŽÐµ Ð¶Ò¯ÑÐ³ÐµÐœÑÒ£ÑÐ·ÐŽÑ Ð°ÐœÑÒÑÐ°Ð¹ÑÑÐœ ÐŽÐžÐ°Ð³ÑÐ°ÐŒÐŒÐ° Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»Ð°ÐŽÑ. ÐÐ°ÑÑÐ» ÐºÐœÐŸÐ¿ÐºÐ°ÐœÑ â ÑÑÐ· Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°ÐœÑÒ£ ÐŸÑÑÐœÐŽÐ°Ð»Ñ ÑÑÐ·Ð±ÐµÐ³ÑÐœ Ð¶Ð°Ð»ÒÐ°ÑÑÑÑÑ Ò¯ÑÑÐœ Ð±Ð°ÑÐ°ÑÑÐ·. Ò®ÑÐŽÑÑÑÑÒ£ Ð¶Ò¯ÑÑÑÐœÐµ Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÑÑ ÐºÐœÐŸÐ¿ÐºÐ° ÑÒ¯ÑÑ ÑÐ°ÑÑÒÐ° Ó©Ð·Ð³ÐµÑÐµÐŽÑ. Ð¡ÑÐ· Ð°Ð»ÐŽÑÒ£ÒÑ Ð±ÐµÑÐºÐµ ÐŽÐžÐ°Ð³ÑÐ°ÐŒÐŒÐ°ÐŽÐ°ÒÑ ÑÓÐ¹ÐºÐµÑ ÑÐ°ÑÑ ÐºÐœÐŸÐ¿ÐºÐ°ÒÐ° Ð±Ð°ÑÑÐ¿ ÐŸÑÐ°Ð»Ð° Ð°Ð»Ð°ÑÑÐ·. }
+
+_textwyar_ [l=kk] {ÓšÐ·ÑÒ£ÑÐ·ÐŽÑÒ£ ÑÐžÑÑÐ»Ñ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°Ð»ÑÒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÒ£ÑÐ·ÐŽÑ Ð¶Ð°ÑÐ°ÑÐŽÑ Ð±Ð°ÑÑÐ°Ñ Ò¯ÑÑÐœ âÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÑâ Ð¶Ð°ÑÑÐ» ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÒ£ÑÐ·!}
+
+_textcnmbs_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð°ÑÑ Ð°ÐœÑÒÑÐ°Ð»ÒÐ°Ðœ Ð±ÐŸÐ»Ñ ÐºÐµÑÐµÐº}
+_texteambs_ [l=kk] {Email Ð°ÐŽÑÐµÑ ÐºÓ©ÑÑÐµÑÑÐ»Ð³ÐµÐœ Ð±ÐŸÐ»Ñ ÐºÐµÑÐµÐº}
+_textpsea_ [l=kk] {email Ð°ÐŽÑÐµÑÑÑ ÐºÐµÐ»ÐµÑÑ ÑÒ¯ÑÐŽÐµ: usename@domain ÐºÓ©ÑÑÐµÑÑÒ£ÑÐ·}
+_textdocmbs_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÐžÐ¿Ð°ÑÑÐ°ÐŒÐ°ÑÑÐœ Ð±ÐµÑÑÒ£ÑÐ·}
+
+_textwcanc_ [l=kk] {ÐÐ°Ò£Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ Ð¶Ð°ÑÐ°ÒÐ°ÐœÐŽÐ°, ÑÑÐ· Ð°Ð»ÐŽÑÐŒÐµÐœ Ð±Ð°ÑÑÐ°Ð¿ÒÑ ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑ Ð¶Ð°Ð¹Ð»Ñ Ð°Ð·ÐŽÐ°ÒÐ°Ðœ Ð°ÒÐ¿Ð°ÑÐ°Ñ Ð±ÐµÑÑÑÒ£ÑÐ· ÐºÐµÑÐµÐº. ÐÒ±Ð» Ò¯ÑÐŽÑÑ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ Ð±Ð°ÒÑÐ»Ð°Ð¹ÑÑÐœ Web-Ð±ÐµÑÑÐµÑ ÒÐ°ÑÐ°ÑÑ ÑÐµÑÑÐœÐŽÐµ ÒÒ±ÑÑÐ»ÑÐŒÐŽÐ°Ð»ÒÐ°Ðœ. ÐÐµÑÑÑÒ£ ÑÓ©ÐŒÐµÐœ Ð¶Ð°ÒÑÐœÐŽÐ° ÑÑÐ·Ð³Ðµ Ð±ÐµÑÑÐµÑ ÒÐ°ÑÐ°ÑÑÐœ Ò¯ÑÐŽÑÑÑÑÒ£ Ð°ÑÒÑÐ°Ð»ÒÐ°ÐœÑÐœÐ° ÐŽÐµÐ¹ÑÐœ ÐºÓ©ÑÑÐµÑÐµÐŽÑ. }
+
+# -- Missing translation: _texttfc_
+
+_texttctiasp_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÐ°ÒÑÑÑÐ±Ñ â ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŒÐ°Ð·ÐŒÒ±ÐœÑÐœ ÐžÐœÐŽÐµÐºÑÐ°ÑÐžÑÐ»Ð°Ñ Ò¯ÑÑÐœ ÑÐžÑÑÐ»Ñ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°ÐœÑÒ£ Ð±Ð°ÑÐ»ÑÒ Ð¶ÐµÑÑÐœÐŽÐµ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»Ð°ÑÑÐœ ÒÑÑÒÐ° ÑÑÐ°Ð·Ð°. ÐÑÑÐ°Ð»Ñ Ð¢Ð°ÒÑÑÑÐ¿: "Computer Science Technical Reports"  Ð¶ÓÐœÐµ  "Humanity Development Library" }
+
+_textcea_ [l=kk] {ÐÐ°Ð¹Ð»Ð°ÐœÑÑ Ð°ÐŽÑÐµÑÑ email:}
+
+_textteas_ [l=kk] {ÐÒ±Ð» ÑÐ»ÐµÐºÑÑÐŸÐœÐŽÑÒ Ð°ÐŽÑÐµÑ Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÑÑÒ£ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ò¯ÑÑÐœ Ð±ÑÑÑÐœÑÑ ÐœÒ¯ÐºÑÐµÑÑÐœ Ð°ÐœÑÒÑÐ°Ð¹ÐŽÑ. ÐÐ³ÐµÑ Greenstone Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒÑ Ð¿ÑÐŸÐ±Ð»ÐµÐŒÐ°ÐœÑ Ð°ÐœÑÒÑÐ°ÑÐ°, ÐŽÐžÐ°Ð³ÐœÐŸÑÑÐžÐºÐ°Ð»ÑÒ Ñ
+Ð°Ð±Ð°ÑÐ»Ð°ÐŒÐ° ÐŸÑÑ Ð°ÐŽÑÐµÑÐºÐµ Ð¶ÑÐ±ÐµÑÑÐ»ÐµÐŽÑ. Ð­Ð»ÐµÐºÑÑÐŸÐœÐŽÑÒ Ð°ÐŽÑÐµÑÑÑ ÐŸÐœÑÒ£ ÑÐŸÐ»ÑÒ ÑÐŸÑÐŒÐ°ÑÑÐœÐŽÐ° ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·: name@domain. }
+
+_textatc_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¶Ð°Ð¹Ð»Ñ:}
+
+_texttiasd_ [l=kk] {ÐÒ±Ð» â ÐœÒ±ÑÒÐ°Ñ ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑÐŽÑÒ£ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÒÐ° ÐµÐœÐ³ÑÐ·ÑÐ»Ñ Ð¿ÑÐžÐœÑÐžÐ¿ÑÐœ ÑÐžÐ¿Ð°ÑÑÐ°Ð¹ÐŽÑ. ÐÒ±Ð» Ð°ÒÐ¿Ð°ÑÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ Ò±ÑÑÐœÒÐ°Ðœ ÐºÐµÐ·ÐŽÐµ Ð±ÑÑÑÐœÑÑ Ð±ÐµÑÑÐµ Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»Ð°ÐŽÑ. }
+
+_textypits_ [l=kk] {Ð¡ÑÐ·ÐŽÑÒ£ Ð¿ÑÐŸÑÐµÑÑÐµÐ³Ñ Ð¿ÐŸÐ·ÐžÑÐžÑÒ£ÑÐ· ÑÓ©ÐŒÐµÐœÐŽÐµÐ³Ñ ÑÑÑÐµÐ»ÐºÐ°ÐŒÐµÐœ Ð±ÐµÐ»Ð³ÑÐ»ÐµÐœÐ³ÐµÐœ â Ð±Ò±Ð» Ð¶Ð°ÒÐŽÐ°Ð¹ÐŽÐ° "ÐºÐµÐ·ÐµÒ£ÐŽÐµÑ" ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑÑ. ÐÐ°Ð»ÒÐ°ÑÑÑÑÑ Ò¯ÑÑÐœ "source data/Ð±Ð°ÑÑÐ°Ð¿ÒÑ ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑ" Ð¶Ð°ÑÑÐ» ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÒ£ÑÐ·. }
+
+_srcebadsources_ [l=kk] {Ð¡ÑÐ· ÐºÓ©ÑÑÐµÑÐºÐµÐœ Ð±Ò±Ð»Ð°ÒÑÐ°ÑÐŽÑÒ£ Ð±ÑÑ ÐœÐµÐŒÐµÑÐµ ÐŸÐŽÐ°Ðœ ÐºÓ©Ð±ÑÐœÐµ ÒÐŸÐ» Ð¶ÐµÑÐºÑÐ·ÑÐ»Ðµ Ð°Ð»ÐŒÐ°Ð¹ÐŽÑ  (ÑÓ©ÐŒÐµÐœÐŽÐµ Ð±ÐµÐ»Ð³ÑÐ»ÐµÐœÐ³ÐµÐœ _iconcross_).
+<p>ÐÒ±Ð» ÐºÐµÐ»ÐµÑÑ ÑÐµÐ±ÐµÐ¿ÑÐµÑÐ³Ðµ Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÑÑ:
+<ul>
+<li>FTP ÑÐ°Ð¹Ð»Ñ,ÑÐ°Ð¹Ñ ÐœÐµÐŒÐµÑÐµ URL Ð¶ÐŸÒ.
+<li>ÐÒ£ Ð°Ð»ÐŽÑÐŒÐµÐœ ÑÑÐ· Ó©Ð·ÑÒ£ÑÐ·ÐŽÑÒ£ ÐÐœÑÐµÑÐœÐµÑ-ÒÑÐ·ÐŒÐµÑ Ð¿ÑÐŸÐ²Ð°Ð¹ÐŽÐµÑÑÒ£ÑÐ·Ð±ÐµÐœ dial up Ð±Ð°Ð¹Ð»Ð°ÐœÑÑ ÐŸÑÐœÐ°ÑÑÑÒ£ÑÐ· ÐºÐµÑÐµÐº.
+<li>Ð¡ÑÐ· Ð¶ÐµÐ»ÑÐ»ÑÐº ÒÐŸÑÒÐ°ÐœÑÑ Ð¶Ò¯Ð¹ÐµÑÑ â firewall Ð°ÑÒÑÐ»Ñ URL-ÒÐ° ÒÐ°ÑÑÐœÐ°Ñ Ð¶Ð°ÑÐ°Ð¿ ÐºÓ©ÑÐµÑÑÐ· (ÐÑÑÑÒ£ ÐŒÓÐœÑ ÐŒÑÐœÐ°ÐŽÐ° ÓÐŽÐµÑÑÐµ ÑÑÐ· ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ Ð°ÑÑÐœ Ð¶ÓÐœÐµ Ð¿Ð°ÑÐŸÐ»ÑÐŽÑ ÐžÐœÑÐµÑÐœÐµÑÐºÐµ ÐµÐœÑ Ò¯ÑÑÐœ ÐµÐœÐ³ÑÐ·ÑÑÒ£ÑÐ· ÐºÐµÑÐµÐº Ð±ÐŸÐ»Ð°ÑÑÐœ).
+</ul>
+<p>ÐÐ³ÐµÑ Ð±Ò±Ð» â ÑÑÐ· Ó©Ð· Ð±ÑÐ°ÑÐ·ÐµÑÑÒ£ÑÐ·ÐŽÐµÐœ ÐºÓ©ÑÐµ Ð°Ð»Ð°ÑÑÐœ URL Ð±ÐŸÐ»ÑÐ°, ÐŸÐœÐŽÐ° ÐŸÐ» Ð¶ÐµÑÐ³ÑÐ»ÑÐºÑÑ ÐºÑÑ-ÐºÓ©ÑÑÑÐŒÐµÐŽÐµÐœ ÑÑÒÑÑ ÐŒÒ¯ÐŒÐºÑÐœ. ÓšÐºÑÐœÑÑÐºÐµ ÐŸÑÐ°Ð¹, Ð±ÑÐ·ÐŽÑÒ£ Ð°Ð¹ÐœÐ°Ð»Ð°Ñ Ò¯ÑÐŽÑÑÑ Ò¯ÑÑÐœ Ð¶ÐµÑÐ³ÑÐ»ÑÐºÑÑ ÐºÑÑ-ÐºÓ©ÑÑÑÐŒÐµÐ»ÐµÑ ÐºÓ©ÑÑÐœÐ±ÐµÐ¹ÐŽÑ. ÐÒ±Ð» Ð¶Ð°ÒÐŽÐ°Ð¹ÐŽÐ° Ð±ÑÐ·, ÐµÒ£ Ð°Ð»ÐŽÑÐŒÐµÐœ ÑÑÐ·ÐŽÐµÐœ Ð±ÐµÑÑÐµÑÐŽÑ Ð±ÑÐ°ÑÐ·ÐµÑÑÒ£ÑÐ·ÐŽÑ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑÐ¿ Ð¶Ò¯ÐºÑÐµÑÐŽÑ ÑÒ±ÑÐ°Ð¹ÐŒÑÐ·.}
+
+# -- Missing translation: _textymbyco_
+
+_textbtco_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÒÒ±ÑÑÐ»ÒÐ°Ðœ }
+_textand_ [l=kk] {ÐÐ°Ò£Ð° ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑÐŽÑ ÒÐŸÑÑ}
+_textad_ [l=kk] {ÒÐŸÑÑÐŒÑÐ° ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑ:}
+
+_texttftysb_ [l=kk] {<p> ÑÑÐ· ÑÓ©ÐŒÐµÐœÐŽÐµ ÐºÓ©ÑÑÐµÑÐµÑÑÐœ ÑÐ°Ð¹Ð»ÐŽÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÒÐ° ÒÐŸÑÑÐ»Ð°ÐŽÑ. Ð¡ÑÐ· ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° Ð±Ð°Ñ Ð€Ð°Ð¹Ð»ÐŽÐ°ÑÐŽÑ ÒÐ°Ð¹ÑÐ° Ð°ÐœÑÒÑÐ°Ð¿ Ð¶Ð°ÑÐ¿Ð°ÒÐ°ÐœÑÒ£ÑÐ·ÒÐ° ÐºÓ©Ð· Ð¶ÐµÑÐºÑÐ·ÑÒ£ÑÐ·: ÓÐ¹ÑÐ¿ÐµÑÐµ ÐµÐºÑ Ð±ÑÑÐŽÐµÐ¹ ÐºÓ©ÑÑÑÐŒÐµ ÐµÐœÐŽÑÑÑÐ»ÑÑ ÐŒÒ¯ÐŒÐºÑÐœ. Ð€Ð°Ð¹Ð»ÐŽÐ°Ñ ÐŸÐ»Ð°ÑÐŽÑÒ£ Ð¶ÐŸÐ»ÐŽÐ°ÑÑÐœÑÒ£ ÑÐŸÐ»ÑÒ Ð°ÑÑÐŒÐµÐœ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÑÐ»Ð°ÐœÑÑ, Web-Ð±ÐµÑÑÐµÑ ÐŸÐ»Ð°ÑÐŽÑÒ£ Ð°Ð±ÑÐŸÐ»ÑÑÑÑÐº Web-Ð°ÐŽÑÐµÑÑÐµÑÑÐŒÐµÐœ Ð±ÐµÑÑÐ»ÑÑ ÐºÐµÑÐµÐº.
+}
+
+# -- Missing translation: _textis_
+
+# -- Missing translation: _textddd1_
+
+_textddd2_ [l=kk] {<p> ÐÐ°ÑÑÐ» ÐºÐœÐŸÐ¿ÐºÐ°Ð»Ð°ÑÐŽÑÒ£ Ð±ÑÑÑÐœ Ð±Ð°ÑÑÒ£ÑÐ·. ÐÐ³ÐµÑ ÑÑÐ· â ÑÓÐ¶ÑÑÐžÐ±ÐµÐ»Ñ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ Ð±ÐŸÐ»ÑÐ°Ò£ÑÐ·, ÐŸÐœÐŽÐ° ÑÑÐ·ÐŽÑÒ£ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐ»ÐµÑÑÐœ ÑÒ¯Ð·ÐµÑÐºÑÒ£ÑÐ· ÐºÐµÐ»ÑÑ ÐŒÒ¯ÐŒÐºÑÐœ. Ð¡ÑÐ·Ð³Ðµ Ð±Ð°Ð»Ð°ÐŒÐ° ÑÐµÑÑÐœÐŽÐµ Ð±ÑÑÐŽÐµÐœ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ ÐºÐµÐ·ÐµÒ£ÑÐœÐµ ÐºÓ©ÑÑ Ò±ÑÑÐœÑÐ»Ð°ÐŽÑ. ÐÑÑÒ£ÑÐ·ÐŽÐµ Ð±ÐŸÐ»ÑÑÐœ, ÑÑÐ· ÒÐ°Ð¹ÑÐ°ÐŽÐ°Ðœ ÐµÑÑÐµÑÐµÐºÑÐµÐ³Ñ ÐºÐµÐ·ÐµÒ£Ð³Ðµ ÐŸÑÐ°Ð»Ð° Ð°Ð»Ð°ÑÑÐ·, ÐŸÐ» Ò¯ÑÑÐœ ÑÓÐ¹ÐºÐµÑ ÑÐ°ÑÑ ÐºÐœÐŸÐ¿ÐºÐ°ÐœÑ Ð±Ð°ÑÑÑÒ£ÑÐ· ÒÐ°Ð¶ÐµÑ. }
+
+_textconf1_ [l=kk] {<p> Ð¡ÑÐ·ÐŽÑÒ£ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÑÒ£ÑÐ·ÐŽÑ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ ÐŒÐµÐœ Ò±ÑÑÐœÑ Ð°ÑÐœÐ°Ð¹Ñ âÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑÐ»Ð°Ñ ÑÐ°Ð¹Ð»ÑÐœÐŽÐ°ÒÑâ ÑÐžÐ¿Ð°ÑÑÐ°ÐŒÐ°Ð»Ð°ÑÐŒÐµÐœ Ð±Ð°ÑÒÐ°ÑÑÐ»Ð°ÐŽÑ. Ð¢ÓÐ¶ÑÑÐžÐ±ÐµÐ»Ñ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»Ð°Ñ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÒ£ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑÑÐœÑÒ£ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐ»ÐµÑÑÐœ Ó©Ð·Ð³ÐµÑÑÐºÑÑÑ ÐºÐµÐ»ÑÑ ÐŒÒ¯ÐŒÐºÑÐœ.
+<center><p><b> ÐÐ³ÐµÑ ÑÑÐ· Ð¶Ð°Ò£Ð°ÐŽÐ°Ðœ Ò¯Ð¹ÑÐµÐœÑÐ¿ Ð¶Ò¯ÑÐ³ÐµÐœ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ Ð±ÐŸÐ»ÑÐ°Ò£ÑÐ·, Ð¶ÓÐ¹ ÒÐ°ÐœÐ° Ð±ÐµÑÑÑÒ£ ÑÓ©ÐŒÐµÐœÐ³Ñ Ð¶Ð°ÒÑÐœÐ° Ð±Ð°ÑÑÒ£ÑÐ·.</b></center>
+<p> ÐÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÒ£ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐ»ÐµÑÑÐœ Ó©Ð·Ð³ÐµÑÑÑ Ò¯ÑÑÐœ, ÑÓ©ÐŒÐµÐœÐŽÐµ Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»Ð°ÑÑÐœ ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑÐŽÑ ÑÒ¯Ð·ÐµÑÑÒ£ÑÐ·. ÐÐ³ÐµÑ ÒÐ°ÑÐµ Ð¶ÑÐ±ÐµÑÑÐµÒ£ÑÐ· âÐ¢Ð°Ð·Ð°Ð»Ð°Ñâ ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ¿ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÒ£ ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑÑÐœÑÒ£ Ð±Ð°ÑÑÐ°Ð¿ÒÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐ»ÐµÑÑÐœ ÒÐ°Ð»Ð¿ÑÐœÐ° ÐºÐµÐ»ÑÑÑÐµÑÑÐ·. }
+
+# -- Missing translation: _textreset_
+
+_textbild1_ [l=kk] {<p> ÐÐœÐŽÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑÐ»ÑÐŽÐ°: Ð±Ò±Ð» Ð±ÑÑÐ°Ð· ÑÐ°ÒÑÑÑÑ Ð°Ð»Ð°ÐŽÑ. Ð¢Ó©ÐŒÐµÐœÐŽÐµ, ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ Ò¯ÑÐŽÑÑÑÐœÑÒ£ Ð¶Ð°ÒÐŽÐ°Ð¹ Ð¶ÐŸÐ»ÑÐœÐŽÐ°, ÐŸÑÑ Ð°ÐŒÐ°Ð»ÐŽÑÒ£ ÐŸÑÑÐœÐŽÐ°Ð»Ñ Ò¯ÑÐŽÑÑÑ Ð¶Ð°Ð¹Ð»Ñ ÐŒÓÐ»ÑÐŒÐµÑ Ð±ÐµÑÑÐ»Ð³ÐµÐœ. }
+
+# -- Missing translation: _textbild2_
+
+_textstopbuild_ [l=kk] {ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑÐŽÑ ÑÐŸÒÑÐ°ÑÑ}
+
+_textbild3_ [l=kk] {<p>  ÐÐ³ÐµÑ ÑÑÐ· ÐŸÑÑ Ð±ÐµÑÑÑ ÒÐ°Ð»ÐŽÑÑÑÐ°Ò£ÑÐ· (Ð¶ÓÐœÐµ ÐŽÐµ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ Ò¯ÑÐŽÑÑÑÐœÐµÐœ âÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑÐŽÑ ÑÐŸÒÑÐ°ÑÑâ ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐŒÐµÐœ Ð±Ð°Ñ ÑÐ°ÑÑÐ¿Ð°ÑÐ°Ò£ÑÐ·), ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ 0Ð°Ð»ÑÐ¿ÑÐ°ÑÑÑ Ð¶Ð°Ð»5Ð°ÑÑÑÑÑÐ»ÑÐ¿, Ò¯ÑÐŽÑÑ ÑÓÑÑÑ Ð°ÑÒÑÐ°Ð»ÒÐ°ÐœÐœÐ°Ðœ ÐºÐµÐ¹ÑÐœ ÐŸÑÐœÐ°ÑÑÐ»Ð°ÐŽÑ. }
+
+_textbuildcancelled_ [l=kk] {ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑÐŽÐ°Ðœ Ð±Ð°Ñ ÑÐ°ÑÑÑ}
+
+# -- Missing translation: _textbildcancel1_
+
+_textbsupdate1_ [l=kk] {ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ ÑÑÐ°ÑÑÑÑ 1 ÑÐµÐºÑÐœÐŽÑÐ°Ðœ ÐºÐµÐ¹ÑÐœ Ð¶Ð°Ò£Ð°ÑÐ°ÐŽÑ}
+# -- Missing translation: _textbsupdate2_
+_textseconds_ [l=kk] {ÐºÐµÐ¹ÑÐœ Ð¶Ð°Ò£Ð°ÑÐ°ÐŽÑ }
+_textbildsuc_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ ÑÓÑÑÑ Ð°ÑÒÑÐ°Ð»ÐŽÑ.}
+
+_textviewbildsummary_ [l=kk] {ÐÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑÒ£ <a href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>  ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ Ò¯ÑÐŽÑÑÑÐœÑÒ£ ÑÐµÐ·ÑÐŒÐµÑÑÐœ </a>   ÑÐŸÐ»ÑÒ Ð·ÐµÑÑÑÐµÑ Ò¯ÑÑÐœ ÒÐŸÐ»ÐŽÐ°ÐœÐ° Ð°Ð»Ð°ÑÑÐ·. }
+
+_textfailmsg11_ [l=kk] {<p>ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÒÒ±ÑÑÐ»ÐŒÐ°ÐŽÑ ÑÐµÐ±ÐµÐ±Ñ ÐŸÐœÐŽÐ° ÐµÑÒÐ°ÐœÐŽÐ°Ð¹ ÐŒÓÐ»ÑÐŒÐµÑ Ð¶ÐŸÒ. Greenstone Ó©Ò£ÐŽÐµÐ¹ Ð°Ð»Ð°ÑÑÐœ ÑÐ°Ð¹Ð»ÐŽÐ°Ñ ÑÐžÐ¿ÑÐœÑÒ£  Ð¶ÓÐœÐµ ÐºÐ°ÑÐ°Ð»ÐŸÐ³ÑÐ°ÑÑÐœÑÒ£ ÐµÒ£ Ð±ÐŸÐ»ÐŒÐ°ÒÐ°ÐœÐŽÐ° Ð±ÑÑÐµÑÑ ÑÑÐ· Ð°ÐœÑÒÑÐ°ÒÐ°Ðœ  Ð±Ð°ÑÑÐ°Ð¿ÒÑ ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑ <I>  Ð±ÐµÑÑÐœÐŽÐµ </i>, Ð±Ð°Ñ ÐµÐºÐµÐœÐŽÑÐ³ÑÐœÐµ ÐºÓ©Ð·ÑÒ£ÑÐ·ÐŽÑ Ð¶ÐµÑÐºÑÐ·ÑÒ£ÑÐ·.  }
+
+# -- Missing translation: _textfailmsg21_
+_textblcont_ [l=kk] {ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑÐŽÑ ÑÑÑÐºÐµÑ ÑÐ°Ð¹Ð»ÑÐœÐŽÐ° ÐºÐµÐ»ÐµÑÑ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°Ñ Ð±Ð°Ñ:}
+
+_texttryagain_ [l=kk] {ÒÐ°Ð¿Ñ ÐµÑÑÒ£ÑÐ·, <a href="_httppagecollector_" target=_top> ÐºÐŸÐ»Ð»ÐµÐºÑÐŸÑÐŽÑ ÒÐ°Ð¹ÑÐ° Ð¶ÑÐ±ÐµÑÑÒ£ÑÐ· </a>Ð¶ÓÐœÐµ ÒÐ°Ð¹ÑÐ° ÓÑÐµÐºÐµÑ Ð¶Ð°ÑÐ°Ò£ÑÐ·.  }
+
+_textfailmsg31_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑÐ»ÐŒÐ°ÐŽÑ(Ð¶Ð°Ò£ÑÐ»ÑÑ buildcol.pl).}
+_textfailmsg41_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÓÑÑÑ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑÐ»ÐŽÑ, Ð±ÑÑÐ°Ò ÐŸÑÐœÐ°ÑÑÐ»ÐŒÐ°ÐŽÑ.}
+_textfailmsg71_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ ÐºÐµÐ·ÑÐœÐŽÐµ Ð±ÐµÐ»Ð³ÑÑÑÐ· ÐœÓÑÑÐµ Ð±ÐŸÐ»ÐŽÑ}
+_textretcoll_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÒÐ° ÐŸÑÐ°Ð»Ñ}
+
+_textdelperm_ [l=kk] {<p> ÐÐµÐ¹Ð±ÑÑ Ð±Ó©Ð»ÑÐºÑÐµÑÑ ÐœÐµÐŒÐµÑÐµ Ð±Ð°ÑÐ»ÑÒ _cgiargbc1dirname_ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð°Ð»ÑÐœÑÐ¿ ÑÐ°ÑÑÐ°Ð»ÑÐœÐ° Ð°Ð»ÐŒÐ°ÐŽÑ. ÐÒ¯ÐŒÐºÑÐœ ÑÐµÐ±ÐµÐ¿ÑÐµÑ:
+<ul>
+<li> Greenstone-ÐœÑÒ£ gsdlhome_/collect/_cgiargbc1dirname_ ÐŽÐžÑÐµÐºÑÐŸÑÐžÑÐœ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°ÑÒÐ° ÑÒ±ÒÑÐ°ÑÑ Ð¶ÐŸÒ.
+<br> ÐÒ±Ð» ÐºÐ°ÑÐ°Ð»ÐŸÐ³ÑÑ Ó©Ð·ÑÒ£ÑÐ·ÐŽÑÒ£ ÐºÐŸÐŒÐ¿ÑÑÑÐµÑÑÒ£ÑÐ·ÐŽÐµÐœ ÒÐŸÐ»ÐŒÐµÐœ Ð¶Ð°ÑÐ°Ñ ÑÐµÐ¶ÐžÐŒÑÐœÐŽÐµ Ð°Ð»ÑÐ¿ÑÐ°ÑÑÐ°ÑÒÐ° ÑÑÑÑÑÑÐ¿ ÐºÓ©ÑÑÒ£ÑÐ·. }
+
+_textdelinv_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ _cgiargbc1dirname_ ÒÐŸÑÒÐ°Ð»ÒÐ°Ðœ ÐœÐµÐŒÐµÑÐµ Ð·Ð°ÒÑÐŒÐŽÐ°ÐœÒÐ°Ðœ. ÐÐ»ÑÐ¿ ÑÐ°ÑÑÐ°Ñ Ò¯ÑÐŽÑÑÑÐœÐµÐœ Ð±Ð°Ñ ÑÐ°ÑÑÑÐ»ÐŽÑ. }
+
+_textdelsuc_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ _cgiargbc1dirname_ ÑÓÑÑÑ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ð»ÑÐœÐŽÑ.}
+
+_textclonefail_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŽÑÐ±Ð»ÐžÐºÐ°ÑÑÐœ Ð¶Ð°ÑÐ°Ñ ÐŒÒ¯ÐŒÐºÑÐœ ÐµÐŒÐµÑ _cgiargclonecol_. ÐÒ¯ÐŒÐºÑÐœ Ð±ÐŸÐ»Ð°ÑÑÐœ ÑÐµÐ±ÐµÐ¿ÑÐµÑ:
+<ul>
+<li> ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ _cgiargclonecol_ Ð¶ÐŸÒ
+<li>  _cgiargclonecol_ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑÑÐœÑÒ£ collect.cfg ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑÐ»ÑÒ ÑÐ°Ð¹Ð»Ñ Ð¶ÐŸÒ
+<li> Greenstone-ÐœÑÒ£ collect.cfg ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑÐ»ÑÒ ÑÐ°Ð¹Ð»ÑÐœ ÐŸÒÑÒÐ° ÑÒ±ÒÑÐ°ÑÑ Ð¶ÐŸÒ</ul>}
+
+_textcolerr_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÐ° ÒÐ°ÑÐµÑÑ.}
+
+_texttmpfail_ [l=kk] {Ð£Ð°ÒÑÑÑÐ° ÑÐ°Ð¹Ð»ÒÐ° ÐœÐµÐŒÐµÑÐµ ÐºÐ°ÑÐ°Ð»ÐŸÐ³ÒÐ° ÐŸÒÑ ÐœÐµÐŒÐµÑÐµ Ð¶Ð°Ð·Ñ ÐºÐµÐ·ÑÐœÐŽÐµ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ Ð¶Ð°Ò£ÑÐ»ÑÑÑ Ð±ÐŸÐ»ÐŽÑ. ÐÒ¯ÐŒÐºÑÐœ Ð¶Ð°ÒÐŽÐ°Ð¹Ð»Ð°Ñ:
+<ul>
+<li> Greenstone-ÐœÑÒ£ _gsdlhome_/tmp ÐŽÐžÑÐµÐºÑÐŸÑÐžÑÐœÐµ ÐŸÒÑ\Ð¶Ð°Ð·ÑÒÐ° ÐµÐœÑ ÒÒ±ÒÑÒÑ Ð¶ÐŸÒ. </ul>}
+
+_textmkcolfail_ [l=kk] {ÐÐ°Ò£Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÒÐ° ÒÐ°Ð¶ÐµÑ ÐŽÐžÑÐµÐºÑÐžÐ²Ð°Ð»ÑÒ ÒÒ±ÑÑÐ»ÑÐŒ Ð¶Ð°ÑÐ°Ñ ÐºÐµÐ·ÑÐœÐŽÐµ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÐŽÐ° Ð¶Ð°Ò£ÑÐ»ÑÑÑ Ð±ÐŸÐ»ÐŽÑ (Ð¶Ð°Ò£ÑÐ»ÑÑÑ mkcol.pl). ÐÒ¯ÐŒÐºÑÐœ ÑÐµÐ±ÐµÐ¿ÑÐµÑ:
+<ul>
+<li> Greenstone-ÐœÑÒ£ _gsdlhome_/tmp ÐŽÐžÑÐµÐºÑÐŸÑÐžÑÐœÐµ Ð¶Ð°Ð·Ñ ÒÒ±ÒÑÒÑ Ð¶ÐŸÒ.
+<li> mkcol.pl perl-ÑÐºÑÐžÐ¿Ñ ÒÐ°ÑÐµÑÑ.
+</ul>}
+
+_textnocontent_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ ÒÐ°ÑÐµÑÑ: Ð¶Ð°Ò£Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ò¯ÑÑÐœ ÐµÑÒÐ°ÐœÐŽÐ°Ð¹ Ð°Ñ Ð±ÐµÑÑÐ»ÐŒÐµÐ³ÐµÐœ. ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÐŽÑ ÒÐ°Ð¹ÑÐ° Ð¶ÑÐ±ÐµÑÑÐ¿ ÐºÓ©ÑÑÒ£ÑÐ·. }
+
+_textrestart_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÐŽÑ ÒÐ°Ð¹ÑÐ° Ð¶ÑÐ±ÐµÑÑ}
+
+_textreloaderror_ [l=kk] {ÐÐ°Ò£Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ Ð¶Ð°ÑÐ°Ñ ÐºÐµÐ·ÑÐœÐŽÐµ ÒÐ°ÑÐµ Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»ÐŽÑ. ÐÒ±Ð» ÑÑÐ·ÐŽÑÒ£ Ð±ÑÐ°ÑÐ·ÐµÑÑÒ£ÑÐ·ÐŽÑÒ£ "reload/ÒÐ°Ð¹ÑÐ°Ð¶Ò¯ÐºÑÐµÑ" Ð¶ÓÐœÐµ "back/Ð°ÑÑÒÐ°" ÐºÐœÐŸÐ¿ÐºÐ°Ð»Ð°ÑÑÐœÐŽÐ°ÒÑ Ð¶Ð°Ò£ÑÐ»ÑÑÑÐ°ÑÒÐ° Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÑÑ Ð±ÐŸÐ»ÑÑ ÐŒÒ¯ÐŒÐºÑÐœ (Ð±Ò±Ð» ÐºÐœÐŸÐ¿ÐºÐ°Ð»Ð°ÑÐŽÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐŸÑ ÐºÓ©ÐŒÐµÐ³ÑÐŒÐµÐœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ Ð¶Ð°ÑÐ°ÒÐ°ÐœÐŽÐ° Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÐ±Ð°ÑÒÐ° ÑÑÑÑÑÑÒ£ÑÐ·). ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÐŽÑ ÒÐ°Ð¹ÑÐ°ÐŽÐ°Ðœ Ð¶ÑÐ±ÐµÑÐ³ÐµÐœ ÐŽÒ±ÑÑÑ. }
+
+_textexptsuc_ [l=kk] {_cgiargbc1dirname_ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑÑ _gsdlhome_/tmp/exported\__cgiargbc1dirname_ ÐŽÐžÑÐµÐºÑÐŸÑÐžÑÑÑÐœÐ° ÑÓÑÑÑ ÑÐºÑÐ¿ÐŸÑÑÑÐ°Ð»ÐŽÑ. }
+
+_textexptfail_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ _cgiargbc1dirname_ ÑÐºÑÐ¿ÐŸÑÑÑÐ°ÑÐŽÐ°ÒÑ Ð¶Ð°Ò£ÑÐ»ÑÑ.
+ÐÒ±Ð» Greenstone-ÐœÑÒ£ "Export Collection/ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÑÐºÑÐ¿ÐŸÑÑÐ°Ñ" ÑÑÐœÐºÑÐžÑÑÑÐœ ÒÐŸÐ»ÐŽÐ°ÑÐŽÑÒ£ ÒÐ°Ð¶ÐµÑÑÑ ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑÑÐµÑÑÐœÑÑÐ· ÐŸÑÐœÐ°ÑÑÐ»ÒÐ°ÐœÐŽÑÒÑÐœÐ°Ðœ Ð±ÐŸÐ»ÑÑ ÐŒÒ¯ÐŒÐºÑÐœ.
+<ul>
+<li> ÐÐ³ÐµÑ ÑÑÐ· Greenstone-ÐŽÑ CD-ROM-ÐœÐ°Ðœ ÐŸÑÐœÐ°ÑÒÐ°Ðœ Ð±ÐŸÐ»ÑÐ°Ò£ÑÐ· Ð¶ÓÐœÐµ "Custom/Ð¢Ð°Ò£ÐŽÐ°ÐŒÐ°Ð»Ñ" ÐŸÑÐœÐ°ÑÑ ÐºÐµÐ·ÑÐœÐŽÐµ ÑÐ°Ò£ÐŽÐ°Ð»ÐŒÐ°ÒÐ°Ðœ Ð±ÐŸÐ»ÑÐ° Ð±Ò±Ð» ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑÑÐµÑ ÐŸÑÐœÐ°ÑÑÐ»ÐŒÐ°Ð¹ÐŽÑ. Ð¡ÑÐ· ÐžÐœÑÑÐ°Ð»Ð»ÑÑÐžÑÐ»Ð°Ñ Ò¯ÑÐŽÑÑÑÐœ ÒÐ°Ð¹ÑÐ° Ð¶Ò¯ÑÐ³ÑÐ·ÑÐ¿ ÐŸÐœÑ ÒÐŸÑÐ° Ð°Ð»Ð°ÑÑÐ·.
+<li> ÐÐ³ÐµÑ ÑÑÐ· Greenstone-ÐŽÑ web-ÐŽÐžÑÑÑÐžÐ±ÑÑÐžÐ²ÑÐµÑÐŽÐµÐœ ÐŸÑÐœÐ°ÑÒÐ°Ðœ Ð±ÐŸÐ»ÑÐ°Ò£ÑÐ·, ÐŸÐœÐŽÐ° ÑÑÐ·Ð³Ðµ ÑÐºÑÐ¿ÐŸÑÑÑÐ°Ñ ÑÑÐœÐºÑÐžÑÑÑÐœ ÒÐ°ÐŒÑÐ°ÐŒÐ°ÑÑÐ· ÐµÑÐµÑÑÐœ ÒÐŸÑÑÐŒÑÐ° Ð¿Ð°ÐºÐµÑÑÑ Ð¶Ò¯ÐºÑÐµÐ¿ Ð¶ÓÐœÐµ ÐŸÑÐœÐ°ÑÑÑÒ£ÑÐ· ÐºÐµÑÐµÐº. <a href="http://www.greenstone.org"> http://www.greenstone.org ÑÐ°Ð¹ÑÑÐœÐ° ÐµÐœÑÒ£ÑÐ· </a> ÐœÐµÐŒÐµÑÐµ ÑÐ»ÐµÐºÑÑÐŸÐœÐŽÑÒ Ð¿ÐŸÑÑÐ° Ð±ÐŸÐ¹ÑÐœÑÐ° ÑÒ±ÑÐ°ÐœÑÐŒ Ð¶ÑÐ±ÐµÑÑÒ£ÑÐ· <a href="mailto:greenstone@cs.waikato.ac.nz">
+greenstone@cs.waikato.ac.nz </a>  ÑÐŸÐœÐŽÐ° Ð±Ò±ÐŽÐ°Ðœ Ð°ÑÒÑ ÐœÒ±ÑÒÐ°ÑÐ»Ð°Ñ Ð°Ð»Ð°ÑÑÐ·. }
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=kk] {_httpimg_/kz/h\_colect.gif}
+
+## "ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ\nÐ°ÒÐ¿Ð°ÑÐ°ÑÑ" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=kk] {_httpimg_/kz/gcinfoof.gif}
+_httpicongcinfoon_ [l=kk] {_httpimg_/kz/gcinfoon.gif}
+_httpiconycinfoof_ [l=kk] {_httpimg_/kz/ycinfoof.gif}
+_httpiconycinfoon_ [l=kk] {_httpimg_/kz/ycinfoon.gif}
+_httpiconncinfoof_ [l=kk] {_httpimg_/kz/ncinfoof.gif}
+
+## "Ð±Ð°ÑÑÐ°Ð¿ÒÑ\nÐŒÓÐ»ÑÐŒÐµÑÑÐµÑ" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=kk] {_httpimg_/kz/gcsrceof.gif}
+_httpicongcsrceon_ [l=kk] {_httpimg_/kz/gcsrceon.gif}
+_httpiconycsrceof_ [l=kk] {_httpimg_/kz/ycsrceof.gif}
+_httpiconycsrceon_ [l=kk] {_httpimg_/kz/ycsrceon.gif}
+_httpiconncsrceof_ [l=kk] {_httpimg_/kz/ncsrceof.gif}
+
+## "ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ\nÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑÑÑ" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=kk] {_httpimg_/kz/gcconfof.gif}
+_httpicongcconfon_ [l=kk] {_httpimg_/kz/gcconfon.gif}
+_httpiconycconfof_ [l=kk] {_httpimg_/kz/ycconfof.gif}
+_httpiconycconfon_ [l=kk] {_httpimg_/kz/ycconfon.gif}
+_httpiconncconfof_ [l=kk] {_httpimg_/kz/ncconfof.gif}
+
+## "ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ\nÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=kk] {_httpimg_/kz/gcbildof.gif}
+_httpicongcbildon_ [l=kk] {_httpimg_/kz/gcbildon.gif}
+_httpiconycbildof_ [l=kk] {_httpimg_/kz/ycbildof.gif}
+_httpiconycbildon_ [l=kk] {_httpimg_/kz/ycbildon.gif}
+_httpiconncbildof_ [l=kk] {_httpimg_/kz/ncbildof.gif}
+
+## "ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ\nÒÐ°ÑÐ°Ñ" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=kk] {_httpimg_/kz/gcviewof.gif}
+_httpicongcviewon_ [l=kk] {_httpimg_/kz/gcviewon.gif}
+_httpiconycviewof_ [l=kk] {_httpimg_/kz/ycviewof.gif}
+_httpiconycviewon_ [l=kk] {_httpimg_/kz/ycviewon.gif}
+_httpiconncviewof_ [l=kk] {_httpimg_/kz/ncviewof.gif}
+
+## "ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ\nÐ°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ñ" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=kk] {_httpimg_/kz/gcdelof.gif}
+_httpicongcdelon_ [l=kk] {_httpimg_/kz/gcdelon.gif}
+
+## "ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ\nÑÐºÑÐ¿ÐŸÑÑÐ°Ñ" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=kk] {_httpimg_/kz/gcexptof.gif}
+_httpicongcexpton_ [l=kk] {_httpimg_/kz/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=kk] {Greenstone â ÑÐžÑÑÐ»Ñ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°Ð»ÑÒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÒÐ° ÒÑÐ·ÐŒÐµÐœ ÐºÓ©ÑÑÐµÑÑ ÐŒÐµÐœ Ð¶Ð°Ò£Ð° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑÒÐ° Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒ. ÐÐ» ÐÐœÑÐµÑÐœÐµÑ ÐœÐµÐŒÐµÑÐµ CD-ROM-ÐŽÐ°ÑÐŽÐ° Ð°ÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÐŽÑ Ò±Ð¹ÑÐŒÐŽÐ°ÑÑÑÑÑ ÐŒÐµÐœ Ð¶Ð°ÑÐžÑÐ»Ð°ÑÐŽÑÒ£ Ð¶Ð°Ò£Ð° ÑÓÑÑÐ»ÑÐœ ÒÐ°ÐŒÑÐ°ÐŒÐ°ÑÑÐ· ÐµÑÐµÐŽÑ. Greenstone ÐÐ°Ð¹ÐºÐ°ÑÐŸ ÑÐœÐžÐ²ÐµÑÑÐžÑÐµÑÑÐœÑÒ£ Ð¶Ð°ÐœÑÐœÐŽÐ° New Zealand Digital Library Project Ð¶ÐŸÐ±Ð°ÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° Ð¶Ð°ÑÐ°Ð»ÑÐœÑÐ¿ Ð®ÐÐÐ¡ÐÐ ÐŒÐµÐœ Human info Ò¯ÐºÑÐŒÐµÑÑÑÐº ÐµÐŒÐµÑ Ò±Ð¹ÑÐŒÑÐœÑÒ£ ÒÐŸÐ»ÐŽÐ°ÑÑÐŒÐµÐœ ÑÐ°ÑÐ°ÑÑÐ»ÒÐ°Ðœ. ÐÐ» ÑÐµÐ³ÑÐœ ÑÐ°ÑÐ°ÑÑÐ»Ð°ÑÑÐœ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒ <i><a href="http://greenstone.org"> http://greenstone.org Ð°ÐŽÑÐµÑÑÐœÐŽÐµ  </a></i> GNU ÑÐ°ÑÑÑÐœÐ° ÑÓÐ¹ÐºÐµÑ ÐŸÑÐœÐ°Ð»Ð°ÑÒÐ°Ðœ.}
+
+_textgreenstone2_ [l=kk] {ÐÐ°Ò£Ð°Ð·ÐµÐ»Ð°ÐœÐŽÐžÑ ÐŠÐžÑÑÐ»Ñ ÐÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°ÑÑÐœÑÒ£ ÐÐµÐ±-ÑÐ°Ð¹ÑÑÐœÐŽÐ°  (<a href="http://nzdl.org">http://nzdl.org</a>)  Greenstone Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°ÑÑÐŒÐµÐœ Ð¶Ð°ÑÐ°Ð»ÒÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑÒ£ ÐºÓ©Ð¿ÑÐµÐ³ÐµÐœ ÐŒÑÑÐ°Ð»ÐŽÐ°ÑÑ Ð±Ð°Ñ Ð¶ÓÐœÐµ ÐŸÐ»Ð°ÑÒÐ° ÐµÑÐºÑÐœ ÐµÐœÑÐ³Ðµ Ð±ÐŸÐ»Ð°ÐŽÑ. ÐÐ»Ð°Ñ Ð°ÑÐ°Ð¿, ÒÑÑÐ°Ð¹, ÑÑÐ°ÐœÑÑÐ·, ÐžÑÐ¿Ð°Ðœ, Ð°ÒÑÐ»ÑÑÐœ Ð¶ÓÐœÐµ ÐŒÐ°ÐŸÑÐž ÑÑÐ»ÐŽÐµÑÑÐœÐŽÐµÐ³Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÐ°Ðœ ÑÒ±ÑÑÐ¿ ÑÐ·ÐŽÐµÑÐŽÑÒ£ ÓÑÑÒ¯ÑÐ»Ñ Ð²Ð°ÑÐžÐ°ÐœÑÑÐ°ÑÑÐœ ÐºÓ©ÑÑÐµÑÐµÐŽÑ. ÐÒ±ÐŽÐ°Ðœ Ð±Ð°ÑÒÐ° ÐŒÑÐ·ÑÐºÐ°Ð»ÑÒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÐ° Ð±ÐµÑÑÐ»Ð³ÐµÐœ.  }
+
+# -- Missing translation: _textplatformtitle_
+_textgreenstone3_ [l=kk] {Greenstone Ð¶Ò±ÐŒÑÑ ÑÑÑÐµÑ Ò¯ÑÑÐœ Windows Ð¶ÓÐœÐµ Unix Ð°ÑÑÑÐœÐŽÐ° ÐŸÑÐœÐ°ÑÑÐ»ÑÑ ÐºÐµÑÐµÐº. ÐÐžÑÑÑÐžÐ±ÑÑÐžÐ²ÑÐµ Windows Ð¿ÐµÐœ Linux Ð¶Ð°ÑÐ°Ð»ÑÐŒÐŽÐ°ÑÑÐœÐŽÐ° ÒÐŸÐ»ÐŽÐ°ÐœÑÒÐ° ÐŽÐ°Ð¹ÑÐœ ÑÐŸÐ¿ÑÐ°ÐŒÐ°Ð»Ð°Ñ Ð±Ð°Ñ. ÐÐ» Microsoft C++ ÐœÐµÐŒÐµÑÐµ GCC ÑÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ¿ ÐºÐŸÐ¿ÐžÐ»ÑÑÐžÑÐ»Ð°ÐœÐ° Ð°Ð»Ð°ÑÑÐœ ÐŽÐ°Ð¹ÑÐœ Ð±Ð°ÑÑÐ°Ð¿ÒÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°ÐŽÐ°Ðœ ÑÒ±ÑÐ°ÐŽÑ. Greenstone ÐµÑÐºÑÐœ ÑÐ°ÑÐ°ÑÑÐ»Ð°ÑÑÐœ: Apache Webserver Ð¶ÓÐœÐµ PERL Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»Ð°ÑÑÐŒÐµÐœ Ð¶Ò±ÐŒÑÑ ÑÑÑÐµÐ¹ Ð°Ð»Ð°ÐŽÑ. ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ ÐžÐœÑÐµÑÑÐµÐ¹ÑÑ Web-Ð±ÑÐ°ÑÐ·ÐµÑÐŽÑ: ÓÐŽÐµÑÑÐµ Netscape Navigator ÐœÐµÐŒÐµÑÐµ Internet Explorer-ÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÐ°ÑÑ. }
+
+_textgreenstone4_ [l=kk] {ÒÒ±Ð¶Ð°ÑÑÑÒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑÒ£ ÐºÓ©Ð¿ÑÑÐ»ÑÐ³Ñ Greenstone-ÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ¿ CD-ROM-ÐŽÐ° ÑÐ°ÑÐ°ÑÑÐ»Ð°ÐŽÑ. ÐÑÑÐ°Ð»Ñ <i> Humanity Development Library</i>ÐŽÐµ 1 230 Ð¶Ð°ÑÐžÐ°Ð»Ð°ÐœÑÐŒ Ð±Ð°Ñ. ÐÐ» Ð°Ð¿Ð¿Ð°ÑÐ°ÑÑÑÒ ÐµÒ£ Ð°Ð· ÑÐ°Ð»Ð°Ð¿ÑÐ°Ñ Ð¶Ð°ÒÐŽÐ°Ð¹ÑÐœÐŽÐ° Ð¶Ò±ÐŒÑÑ ÑÑÑÐµÐ¹ÐŽÑ. ÐÒÐ¿Ð°ÑÐ°ÑÑÐ°ÑÒÐ° ÑÐ·ÐŽÐµÑ Ð¿ÑÐŸÑÐµÐŽÑÑÐ°Ð»Ð°ÑÑÐœ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑÐ¿, ÑÐ°ÒÑÑÑÐ¿ÑÐ°ÑÐŽÑ , Ð°Ð¹ÐŽÐ°ÑÐ»Ð°ÑÐŽÑ  ÒÐ°ÑÐ°ÑÒÐ° Ð±ÐŸÐ»Ð°ÐŽÑ. }
+
+# -- Missing translation: _textcustomisationtitle_
+_textgreenstone5_ [l=kk] {Greenstone ÐŒÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐŽÑ ÐºÐµÒ£ÐµÐ¹ÑÑÐ»ÑÐ¿, ÐºÒ¯Ð¹ÑÐœÐµ ÐºÐµÐ»ÑÑÑÑÐ»ÐµÑÑÐœ ÐµÑÑÐ¿ Ð°ÑÐœÐ°Ð¹Ñ Ð¶Ð°ÑÐ°Ð»ÒÐ°Ðœ. ÐÐµÑÐ°ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑÐŽÑÒ£ ÑÐŸÑÐŒÐ°ÑÑÐ°ÑÑ ÐŒÐµÐœ Ð¶Ð°Ò£Ð° ÒÒ±Ð¶Ð°ÑÑÐ°Ñ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°ÒÐ° "plugins/ÒÐŸÑÑÐŒÑÐ°Ð»Ð°Ñ Ð¶Ð°Ð·Ñ Ð°ÑÒÑÐ»Ñ Ð±ÐµÑÑÐ»ÐµÐŽÑ(Perl ÑÑÐ»ÑÐœÐŽÐµ). ÐÑÑÒÐ°Ðœ Ò±ÒÑÐ°Ñ ÒÒ±ÑÑÐ»ÑÐŒÐŽÐ°ÑÐŽÑ ÒÐ°ÑÐ°Ð¹ÑÑÐœ ÐŒÐµÑÐ°ÐŒÓÐ»ÑÐŒÐµÑÑÐµÑ "classifiers/ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ»Ð°ÑÐŽÑ" Ð¶Ð°ÑÐ°Ð»ÑÐœÐ° Ð°Ð»Ð°ÐŽÑ. ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ ÐžÐœÑÐµÑÑÐµÐ¹ÑÑÐœÑÒ£ ÑÑÑÑÒÑ ÑÒ¯ÑÑÐœ ÒÐ°ÑÐ°Ð¿Ð°Ð¹ÑÐŒ ÐŒÐ°ÐºÑÐŸÑÑÐ»ÐŽÐµ Ð¶Ð°Ð·ÑÐ»ÒÐ°Ðœ âÐŒÐ°ÐºÑÐŸÑÑÐ°Ñâ-ÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ¿ Ó©Ð·Ð³ÐµÑÑÑÐ³Ðµ Ð±ÐŸÐ»Ð°ÐŽÑ. Corba Ð¿ÑÐŸÑÐŸÐºÐŸÐ»Ñ Ð°Ð³ÐµÐœÑÑÐµÑÐ³Ðµ (ÐŒÑÑÐ°Ð»Ñ Java-ÐŽÐ°) ÒÒ±Ð¶Ð°ÑÑÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑÑÐŒÐµÐœ Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÒÐ°Ðœ Ð±Ð°ÑÐ»ÑÒ ÒÒ±ÑÐ°Ð»ÐŽÐ°ÑÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑ ÐŒÒ¯ÐŒÐºÑÐœÐŽÑÐ³ÑÐœ Ð±ÐµÑÐµÐŽÑ. C++ Ð¶ÓÐœÐµ Perl ÑÑÐ»ÑÐœÐŽÐµ Ð¶Ð°Ð·ÑÐ»ÒÐ°Ðœ Ð±Ð°ÑÑÐ°Ð¿ÒÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»Ð°ÑÐŽÑ ÐŒÐŸÐŽÐžÑÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÒÐ° Ð±ÐŸÐ»Ð°ÐŽÑ. }
+
+# -- Missing translation: _textdocumentationtitle_
+# -- Missing translation: _textdocuments_
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+# -- Missing translation: _textmailinglisttitle_
+_textmailinglist_ [l=kk] {Greenstone ÑÐžÑÑÐ»ÑÒ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ°ÑÑÐœÑÒ£ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒÑÐœ ÑÐ°Ð»ÒÑÐ»Ð°ÑÒÐ° Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ Ð¶ÑÐ±ÐµÑÑÐ»ÐµÑ ÑÑÐ·ÑÐŒÑ Ð±Ð°Ñ. Greenstone-ÐœÑÒ£ Ð±ÐµÐ»ÑÐµÐœÐŽÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»Ð°ÑÑ ÐŸÑÑ ÑÑÐ·ÑÐŒÐ³Ðµ Ð¶ÓÐœÐµ ÑÐ°Ð»ÒÑÐ»Ð°ÑÐ»Ð°ÑÒÐ° ÒÐŸÑÑÐ»ÑÐ»Ð°ÑÑ ÐºÐµÑÐµÐº.ÐÐ°Ð·ÑÐ»Ñ Ò¯ÑÑÐœ ÑÐ»ÐµÐºÑÑÐŸÐœÐŽÑÒ Ð¿ÐŸÑÑÐ° Ð¶ÑÐ±ÐµÑÑÒ£ÑÐ· <a href="mailto:greenstone-users-request@list.scms.waikato.ac.nz?subject=subscribe">greenstone-users-request@list.scms.waikato.ac.nz?subject=subscribe</a>. Ð¥Ð°ÑÐ±Ð°ÑÐ»Ð°ÑÐŸÑÒ£ÑÐ·ÐŽÑ  <a href="mailto:greenstone-users@list.scms.waikato.ac.nz">greenstone-users@list.scms.waikato.ac.nz ÐÐŽÑÐµÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° Ð¶ÑÐ±ÐµÑÑÒ£ÑÐ·ÐŽÐµÑ</a>. }
+
+# -- Missing translation: _textbugstitle_
+_textreport_ [l=kk] {ÐÑÐ· Ó©Ð·ÑÐŒÑÐ·ÐŽÑÒ£ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒ Ð¶Ò±ÐŒÑÑÑÐœÑÒ£ ÑÑÐ·Ð³Ðµ ÐµÑ ÒÐŸÐ»Ð°Ð¹ÑÑÐ·ÐŽÑÒ ÑÑÐŽÑÑÐŒÐ°Ð¹ÑÑÐœÐŽÑÒÑÐœÐ° ÑÐµÐœÑÐŒÐŽÑ Ð±ÐŸÐ»ÒÑÐŒÑÐ· ÐºÐµÐ»ÐµÐŽÑ. Ð¡ÑÐ· Greenstone-ÐŽÐµ Ð¶Ò±ÐŒÑÑ ÑÑÑÐµÐ³ÐµÐœÐŽÐµ Ð±Ð°Ð¹ÒÐ°ÒÐ°Ðœ ÒÐ°ÑÐµÐ»ÐµÑÑÒ£ÑÐ·Ð±ÐµÐœ ÑÑÑÐœÐŽÐ°ÒÐ°Ðœ ÑÒ±ÑÐ°ÒÑÐ°ÑÑÒ£ÑÐ·ÐŽÑ <a href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a> Ð°ÐŽÑÐµÑÑÐœÐµ Ñ
+Ð°Ð±Ð°ÑÐ»Ð°Ò£ÑÐ·}
+
+# -- Missing translation: _textgs3title_
+# -- Missing translation: _textgs3_
+
+# -- Missing translation: _textcreditstitle_
+
+_textwhoswho_ [l=kk] {Greenstone Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°ÑÑ ÐºÓ©Ð¿ÑÐµÐ³ÐµÐœ Ð°ÐŽÐ°ÐŒÐŽÐ°ÑÐŽÑÒ£ Ð±ÑÑÐ»ÐµÑÐºÐµÐœ ÐµÒ£Ð±ÐµÐ³ÑÐœÑÒ£ Ð¶ÐµÐŒÑÑÑ. Ð ÐŸÐŽÐ¶ÐµÑ ÐÐ°ÐºÐÐ°Ð± Ðž Ð¡ÑÑÑÐ°Ðœ ÐÐŸÐŽÐŽÐž Ð¿ÑÐžÐœÑÐžÐ¿ÐžÐ°Ð»ÑÐŽÑ Ð¶Ð°ÑÐ°ÑÑÑÐ»Ð°Ñ. ÐÑÐ²ÐžÐŽ ÐÑÐ¹ÐœÐ±ÑÐžÐŽÐ¶, ÐÐ¶ÐŸÑÐŽÐ¶ ÐÑÑÐ°ÐœÐ°Ðœ, Ð¥ÐŸÐœÐ³ Ð§ÐµÐœ,Ð­Ð»ÑÐºÐµ ÐÐ°ÐœÐºÐµÑ, ÐÐ°ÑÐ» ÐÑÑÐ²ÐžÐœ, ÐÐ¶ÐµÑ Ð¥ÐŸÐ»ÐŒÑ, ÐÐ¶ÐŸÐœ ÐÐ°ÐºÐ€ÐµÑÑÐŸÐœ, ÐÑÐµÐ¹Ð³ ÐÑÐ²ÐžÐ»Ð»-ÐÑÐ¹ÐœÐžÐœÐ³, ÐÐŸÑÐŽÐŸÐœ ÐÐ°Ð¹ÐœÑÐµÑ, ÐÐµÑÐœÑ
+Ð°ÑÐŽ Ð€Ð°ÑÐžÐœÐ³ÐµÑ, Ð¢ÐŸÐŽÐŽ Ð ÐžÐŽ, ÐÐžÐ»Ð» Ð ÐŸÐŽÐ¶ÐµÑÑ Ðž Ð¡ÑÑÐ°ÑÑ ÐÐ°ÑÑ Ð±Ð°ÒÐ° Ð¶ÐµÑÐ¿ÐµÑ Ò¯Ð»ÐµÑ ÒÐŸÑÑÑ. ÐÐ°Ò£Ð°Ð·ÐµÐ»Ð°ÐœÐŽÐžÑÐ»ÑÒ ÑÐžÑÑÐ»Ñ ÐºÑÑÐ°Ð¿Ñ
+Ð°ÐœÐ° Ð¶ÐŸÐ±Ð°ÑÑÐœÑÒ£ Ð±Ð°ÑÒÐ° ÐŒÒ¯ÑÐµÐ»ÐµÑÑ Ð±Ò¯ÐºÑÐ» Ð¶Ò¯Ð¹ÐµÐœÑÒ£ ÐŽÐžÐ·Ð°Ð¹ÐœÑÐœ Ð¶Ð°ÑÐ°ÐŽÑ: ÐÐ°ÑÐº ÐÐ¿Ð¿ÐµÑÐ»ÐµÐ¹, Ð¡Ð°Ð»Ð»Ðž ÐÐ¶ÐŸ ÐÐ°ÐœÐœÐžÐœÐ³ÐµÐŒ, Ð¡ÑÐžÐ² ÐÐ¶ÐŸÐœÑ, Ð¢Ñ Ð¢Ð°ÐºÐ° ÐÐžÐ³Ð°Ðœ, ÐÐ°Ð¹ÐºÐ» ÐÑÑÑ, ÐÐ°Ð»ÐžÐºÐ° ÐÐ°Ñ
+ÐŸÑÐž Ðž ÐÐ»ÐŸÐ¹ÐŽ Ð¡ÐŒÐžÑ.
+ÐÑÐ· ÑÐŸÐœÐŽÐ°Ð¹-Ð°Ò GNU Ð»ÐžÑÐµÐœÐ·ÐžÑÑÑÐœÑÒ£ ÓÑÐµÑÑÐœÐµ ÑÒ¯ÑÐµÑÑÐœ Ð¿Ð°ÐºÐµÑÑÐµÑÐŽÑ Ð¶Ð°ÑÐ°ÑÑÑÐ»Ð°ÑÒÐ° Ó©Ð· Ð°Ð»ÒÑÑÑÐŒÑÐ·ÐŽÑ Ð°Ð¹ÑÐ°ÐŒÑÐ·: MG, GDBM, PDFTOHTML, WGET, WVWARE Ðž XLHTML. }
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "Greenstone Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°Ð»ÑÒ Ð¶Ð°Ð±ÐŽÑÒÑ Ð¶Ð°Ð¹Ð»Ñ" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=kk] {_httpimg_/kz/abgsgr.gif}
+_widthabgsgr_ [l=kk] {_pagewidth_}
+_heightabgsgr_ [l=kk] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=kk] {ÐÒÑÐŒÐŽÐ°ÒÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»Ð°Ñ ÑÑÐ·ÑÐŒÑ}
+_textuser_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ}
+_textas_ [l=kk] {ÐÑÐµÐ¿ ÐºÐ°ÑÑÐŸÑÐºÐ°ÑÑÐœÑÒ£ Ð¶Ð°ÒÐŽÐ°Ð¹Ñ}
+_textgroups_ [l=kk] {ÑÐŸÐ¿ÑÐ°Ñ}
+_textcomment_ [l=kk] {ÐºÐŸÐŒÐŒÐµÐœÑÐ°ÑÐžÐ»ÐµÑ}
+_textadduser_ [l=kk] {Ð¶Ð°Ò£Ð° ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐœÑ ÒÐŸÑÑ}
+_textedituser_ [l=kk] {ÑÒ¯Ð·ÐµÑÑ}
+_textdeleteuser_ [l=kk] {Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ñ}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ Ð¶Ð°Ð¹Ð»Ñ Ð°ÒÐ¿Ð°ÑÐ°ÑÑÑ ÑÒ¯Ð·ÐµÑÑ}
+_textadduser_ [l=kk] {ÐÐ°Ò£Ð° ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐœÑ ÒÐŸÑÑ}
+
+_textaboutusername_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ Ð°ÑÑÐœÑÒ£ Ò±Ð·ÑÐœÐŽÑÒÑ 2-30 ÑÐžÐŒÐ²ÐŸÐ» Ð°ÑÐ°Ð»ÑÒÑÐœÐŽÐ° Ð±ÐŸÐ»ÑÑ ÒÐ°Ð¶ÐµÑ. ÐÐ» ÓÑÑÐ¿ÑÑÐº-ÑÐžÑÑÐ»Ñ ÑÐžÐŒÐ²ÐŸÐ»ÐŽÐ°Ñ, '.', Ð¶ÓÐœÐµ '_' Ð±ÐµÐ»Ð³ÑÐ»ÐµÑÑÐœÐµÐœ ÑÒ±ÑÐ°ÐŽÑ. }
+
+_textaboutpassword_ [l=kk] {ÐÐ°ÑÐŸÐ»Ñ 3 ÑÐµÐœ 8 ÑÐžÐŒÐ²ÐŸÐ»ÐŸÐ²ÒÐ° ÐŽÐµÐ¹ÑÐœ. ÐÐ°ÑÐŸÐ»Ñ ÑÐµÑÑÐœÐŽÐµ ÓÐŽÐµÑÑÐµÐ³Ñ Ð±Ð°ÑÑÐ»Ð°ÑÑÐœ  ASCII ÑÐžÐŒÐ²ÐŸÐ»ÐŽÐ°Ñ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»Ð° Ð°Ð»Ð°ÐŽÑ. }
+
+_textoldpass_ [l=kk] {ÐÐ³ÐµÑ Ð±ÐµÑÑÐ»Ð³ÐµÐœ Ð°Ð»Ð°Ò£ Ð±ÐŸÑ Ð±ÐŸÐ»ÑÐ° ÐŸÐœÐŽÐ° ÐµÑÐºÑ Ð¿Ð°ÑÐŸÐ»Ñ ÒÐŸÐ»ÐŽÐ°ÐœÑÐ»Ð°ÐŽÑ.}
+_textenabled_ [l=kk] {ÑÒ±ÒÑÐ°Ñ ÐµÑÑÐ»Ð³ÐµÐœ }
+_textdisabled_ [l=kk] {ÑÑÐ¹ÑÐŒ ÑÐ°Ð»ÑÐœÒÐ°Ðœ}
+
+_textaboutgroups_ [l=kk] {Ð¢ÐŸÐ¿ÑÐ°Ñ â Ò¯ÑÑÑ Ð°ÑÒÑÐ»Ñ Ð±Ó©Ð»ÑÐœÐ³ÐµÐœ ÑÑÐ·ÑÐŒ, Ò¯ÑÑÑÐŽÐµÐœ ÐºÐµÐ¹ÑÐœ Ð¿ÑÐŸÐ±ÐµÐ» ÒÐŸÐ¹ÑÐ»ÐŒÐ°Ð¹ÐŽÑ! }
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐœÑ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ñ}
+_textremwarn_ [l=kk] {Ð¡ÑÐ· ÑÑÐœÑÐŒÐµÐœÐµÐœ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ _cgiargumun_ ÐŽÑ ÑÒ¯Ð¿ÐºÑÐ»ÑÐºÑÑ Ð°Ð»ÑÐ¿ ÑÐ°ÑÑÐ°Ð¹ÑÑÐ· Ð±Ð°?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=kk] {ÐÐ°ÑÐŸÐ»ÑÐŽÑ Ó©Ð·Ð³ÐµÑÑÑ}
+_textoldpw_ [l=kk] {ÐÑÐºÑ Ð¿Ð°ÑÐŸÐ»Ñ}
+_textnewpw_ [l=kk] {ÐÐ°Ò£Ð° Ð¿Ð°ÑÐŸÐ»Ñ}
+_textretype_ [l=kk] {ÐÐ°Ò£Ð° Ð¿Ð°ÑÐŸÐ»ÑÐŽÑ ÒÐ°Ð¹ÑÐ°Ð»Ð°Ð¿ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=kk] {Ð¡ÑÐ·ÐŽÑÒ£ Ð¿Ð°ÑÐŸÐ»ÑÒ£ÑÐ· ÑÓÑÑÑ Ó©Ð·Ð³ÐµÑÑÑÐ»ÐŽÑ.}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=kk] {ÐÐµÐ²ÐµÑÐœÐŸÐµ ÐžÐŒÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ.}
+_textinvalidpassword_ [l=kk] {ÒÐ°ÑÐµ Ð¿Ð°ÑÐŸÐ»Ñ.}
+_textemptypassword_ [l=kk] {ÐÑÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÒÐ° Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ Ð±Ð°ÑÑÐ°Ð¿ÒÑ Ð¿Ð°ÑÐŸÐ»ÑÐŽÑ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ·}
+_textuserexists_ [l=kk] {ÐÒ±ÐœÐŽÐ°Ð¹ Ð°ÑÑÑ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ Ð±Ð°Ñ, ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑ Ð°ÑÑÐœ Ó©Ð·Ð³ÐµÑÑÑÒ£ÑÐ·.}
+
+_textusernameempty_ [l=kk] {ÓšÐ·ÑÒ£ÑÐ·ÐŽÑÒ£ Ð¶Ð°Ò£Ð° Ð¿Ð°ÑÐŸÐ»ÑÒ£ÑÐ·ÐŽÑ ÐµÐœÐ³ÑÐ·ÑÒ£ÑÐ· Ð¶ÓÐœÐµ ÐŸÐœÑ ÑÐ°ÒÑÐŽÐ° Ð±ÑÑ ÑÐ°ÑÑÐ°Ò£ÑÐ·.}
+# -- Missing translation: _textpasswordempty_
+# -- Missing translation: _textnewpass1empty_
+_textnewpassmismatch_ [l=kk] {Ð¡ÑÐ·ÐŽÑÒ£ Ð¿Ð°ÑÐŸÐ»ÑÒ£ÑÐ·ÐŽÑÒ£ ÓÑÑÒ¯ÑÑ ÐµÐœÐ³ÑÐ·ÑÐ»Ð³ÐµÐœ.}
+_textnewinvalidpassword_ [l=kk] {Ð¡ÑÐ·ÐŽÑÒ£ ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»ÑÒ Ð°ÑÑÒ£ÑÐ· ÐœÐµÐŒÐµÑÐµ Ð¿Ð°ÑÐŸÐ»ÑÒ£ÑÐ· ÐŽÒ±ÑÑÑ ÐµÐœÐ³ÑÐ·ÑÐ»ÐŒÐµÐ³ÐµÐœ.}
+# -- Missing translation: _textfailed_
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=kk] {Greenstone Ð¶Ð°ÑÐ°Ð»ÑÐŒÑ}
+_textframebrowser_ [l=kk] {ÐÑÑÐœÐŽÐµÐ³ÑÐ»ÐµÑÐŽÑ ÒÐ°ÑÐ°Ñ Ò¯ÑÑÐœ ÑÑÐ·ÐŽÑÒ£ Ð±ÑÐ°ÑÐ·ÐµÑÑÒ£ÑÐ·Ð³Ðµ ÑÑÐµÐ¹ÐŒÐŽÐµÑÐŽÑ ÒÐŸÐ»ÐŽÐ°Ñ ÑÒ±ÒÑÐ°ÑÑÐœ ÐŸÑÐœÐ°ÑÑÑÒ£ÑÐ· ÐºÐµÑÐµÐº. }
+_textusermanage_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»Ð°ÑÐŽÑ Ð±Ð°ÑÒÐ°ÑÑ}
+_textlistusers_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»Ð°Ñ ÑÑÐ·ÑÐŒÑ}
+_textaddusers_ [l=kk] {ÐÐ°Ò£Ð° ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»Ð°ÑÐŽÑ ÒÐŸÑÑ}
+_textchangepasswd_ [l=kk] {ÐÐ°ÑÐŸÐ»ÑÐŽÑ Ó©Ð·Ð³ÐµÑÑÑ}
+_textinfo_ [l=kk] {Ð¢ÐµÑ
+ÐœÐžÑÐµÑÐºÐ°Ð»ÑÒ Ð°ÒÐ¿Ð°ÑÐ°Ñ}
+_textgeneral_ [l=kk] {ÐÐ°Ð»Ð¿Ñ}
+_textarguments_ [l=kk] {Ð°ÑÐ³ÑÐŒÐµÐœÑÑÐµÑ}
+_textactions_ [l=kk] {Ð°ÐŒÐ°Ð»ÐŽÐ°Ñ}
+_textbrowsers_ [l=kk] {ÒÐ°ÑÐ°ÑÐ»Ð°Ñ}
+_textprotocols_ [l=kk] {Ð¿ÑÐŸÑÐŸÐºÐŸÐ»ÐŽÐ°Ñ}
+_textconfigfiles_ [l=kk] {ÐÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÑÐ»Ð°Ñ ÑÐ°Ð¹Ð»Ñ}
+_textlogs_ [l=kk] {Ð¢ÑÑÐºÐµÑ}
+_textusagelog_ [l=kk] {ÒÐŸÐ»ÐŽÐ°ÐœÑÑÑÐ»ÑÒ ÑÑÑÐºÐµÑ}
+# -- Missing translation: _textinitlog_
+_texterrorlog_ [l=kk] {ÑÑÑÐºÐµÑ ÒÐ°ÑÐµÑÑ}
+_textadminhome_ [l=kk] {ÐÐŽÐŒÐžÐœÐžÑÑÑÐ°ÑÐŸÑÐŽÑÒ£ Ò¯Ð¹ Ð±ÐµÑÑ}
+_textreturnhome_ [l=kk] {Greenstone-ÐœÑÒ£ Ò¯Ð¹ Ð±ÐµÑÑ}
+_titlewelcome_ [l=kk] {ÐÐŽÐŒÐžÐœÐžÑÑÑÐ°ÑÐžÑÐ»Ð°Ñ }
+_textmaas_ [l=kk] {ÐÐŽÐŒÐžÐœÐžÑÑÑÐ°ÑÐŸÑ ÐŒÐµÐœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ò±ÑÑÐ°ÑÑÑÐœÑÒ£ ÒÐŸÐ» Ð¶ÐµÑÐµÑÑÐœ ÒÑÐ·ÐŒÐµÑÑÐµÑÑ:}
+_textvol_ [l=kk] {on-line ÑÑÑÐºÐµÑÑÐœ ÒÐ°ÑÐ°Ñ}
+_textcmuc_ [l=kk] {ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ Ð¶Ð°ÑÐ°Ñ, ÒÐŸÐ»ÐŽÐ°Ñ Ð¶ÓÐœÐµ Ð¶Ð°Ò£Ð°ÑÑÑ}
+# -- Missing translation: _textati_
+
+_texttsaa_ [l=kk] {ÐÒ±Ð» ÒÑÐ·ÐŒÐµÑÑÐµÑÐ³Ðµ Ð±ÐµÑÑÑÒ£ ÑÐŸÐ»ÐŽ Ð¶Ð°ÒÑÐœÐŽÐ°ÒÑ ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÑÐ»ÑÒ ÐŒÓÐ·ÑÑ Ð°ÑÒÑÐ»Ñ ÒÐŸÐ» Ð¶ÐµÑÐºÑÐ·ÑÐ³Ðµ Ð±ÐŸÐ»Ð°ÐŽÑ.  }
+
+_textcolstat_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð¡ÑÐ°ÑÑÑÑ}
+
+_textcwoa_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ ÐµÐ³ÐµÑ ÐŸÐ»Ð°ÑÐŽÑÒ£ build.cfg ÑÐ°Ð¹Ð»Ñ Ð±ÐŸÐ»ÑÐ° ÐŸÐœÐŽÐ° ÐŸÐ»Ð°ÑâÐŸÑÑÐœÐŽÐ°Ð»Ð°ÑÑÐœâ Ð±ÐŸÐ»ÑÐ¿ Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»Ð°ÐŽÑ ÐµÐ³ÐµÑ builddate Ð°Ð»Ð°Ò£Ñ (Ñ.e > 0), ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑÒ£ ÐžÐœÐŽÐµÐºÑÑÑÐº ÐºÐ°ÑÐ°Ð»ÐŸÐ³ÑÐœÐŽÐµ Ð±ÐŸÐ»ÑÐ° ( ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ ÐºÐ°ÑÐ°Ð»ÐŸÐ³Ñ ÐµÐŒÐµÑ). }
+
+_textcafi_ [l=kk] {<i> abbrev. </i>  Ð±Ð°ÑÑÐ°Ò£ÑÐ· ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¶Ð°Ð¹Ð»Ñ ÐŒÓÐ»ÑÐŒÐµÑ Ð°Ð»Ð°ÑÑÐ· }
+_textcctv_ [l=kk] {<i> collection </i>   Ð±Ð°ÑÑÐ°Ò£ÑÐ· ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÒÐ°ÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·}
+_textsubc_ [l=kk] {ÓšÐ·Ð³ÐµÑÑÑÐ»ÐµÑÐŽÑ ÑÐ°ÑÑÐ°Ò£ÑÐ·}
+_texteom_ [l=kk] {main.cfg Ð°ÑÒÐ°ÐœÐŽÐ°ÒÑ ÒÐ°ÑÐµ}
+_textftum_ [l=kk] {main.cfg Ð¶Ð°Ò£Ð°ÑÑÐŽÐ° Ð¶Ð°Ò£ÑÐ»ÑÑ}
+_textmus_ [l=kk] {main.cfg Ð¶Ð°Ò£Ð°ÑÑÑÐ»ÑÑ ÑÓÑÑÑ Ð°ÑÒÑÐ°Ð»ÐŽÑ}
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=kk] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÒÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑ Ð¿ÑÐŸÑÐµÑÑÐœÑÒ£ ÑÐµÐ·ÑÐŒÐµÑÑ _collectionname_ }
+_textflog_ [l=kk] {ÐÐ°Ò£ÑÐ»ÑÑÑÐ°ÑÐŽÑ ÑÑÑÐºÐµÑ ÑÐ°Ð¹Ð»Ñ  _collectionname_ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÑÐœÐ° Ð°ÑÐœÐ°Ð»ÒÐ°Ðœ}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+# -- Missing translation: _greenstoneusabilitytext_
+
+# -- Missing translation: _textwhy_
+# -- Missing translation: _textextraforform_
+# -- Missing translation: _textprivacybasic_
+# -- Missing translation: _textstillsend_
+
+# -- Missing translation: _texterror_
+# -- Missing translation: _textyes_
+# -- Missing translation: _textno_
+# -- Missing translation: _textclosewindow_
+# -- Missing translation: _textabout_
+# -- Missing translation: _textprivacy_
+# -- Missing translation: _textsend_
+# -- Missing translation: _textdontsend_
+# -- Missing translation: _textoptionally_
+
+# -- Missing translation: _textunderdev_
+
+# -- Missing translation: _textviewdetails_
+# -- Missing translation: _textmoredetails_
+# -- Missing translation: _texttrackreport_
+# -- Missing translation: _textcharacterise_
+# -- Missing translation: _textseverity_
+ 
+# -- Missing translation: _textbadrender_
+# -- Missing translation: _textcontenterror_
+# -- Missing translation: _textstrangebehaviour_
+# -- Missing translation: _textunexpected_
+# -- Missing translation: _textfunctionality_
+# -- Missing translation: _textother_
+
+# -- Missing translation: _textcritical_
+# -- Missing translation: _textmajor_
+# -- Missing translation: _textmedium_
+# -- Missing translation: _textminor_
+# -- Missing translation: _texttrivial_
+
+# -- Missing translation: _textwhatdoing_
+# -- Missing translation: _textwhatexpected_
+# -- Missing translation: _textwhathappened_
+
+# -- Missing translation: _cannotfindcgierror_
+
+# -- Missing translation: _textusabbanner_
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+# -- Missing translation: _textgli_
+# -- Missing translation: _textglihelp_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+# -- Missing translation: gligr
+# -- Missing translation: _httpicongligr_
+# -- Missing translation: _widthgligr_
+# -- Missing translation: _heightgligr_
Index: /tags/gsdl-2_61-distribution/gsdl/macros/kirghiz.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/kirghiz.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/kirghiz.dm	(revision 10506)
@@ -0,0 +1,1256 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Kirghiz Language text and icon macros 
+# Many thanks to Fedor Bakalov (translated February 2005)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=ky] {ÐÐµÑÐžÐŸÐŽÐžÐºÐ°}
+_textsource_ [l=ky] {Ð±ÑÐ»Ð°Ðº:}
+_textdate_ [l=ky] {Ð¶Ð°ÑÑÑÐ»Ð°ÐœÐ³Ð°Ðœ ÐºÒ¯ÐœÒ¯:}
+_textnumpages_ [l=ky] {ÐÐµÑÑÐžÐœ ÐœÐŸÐŒÐµÑÐž:}
+
+_textsignin_ [l=ky] {Ð°Ð²ÑÐŸÑÐžÐ·Ð°ÑÐžÑ}
+
+_textdefaultcontent_ [l=ky] {ÐÑÐ» Ð±ÐµÑ ÑÐ°Ð±ÑÐ»Ð³Ð°Ðœ Ð¶ÐŸÐº. ÐÑÐ°ÑÐ·ÐµÑÐŽÐžÐœ 'ÐºÐ°Ð¹ÑÑÑ' Ð¶Ðµ Ð±ÐŸÐ»ÑÐŸ  (home)  ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ  Ð±Ð°ÑÑÐ°Ò£ÑÐ· ÐºÐ°Ð¹ÑÐ°ÐŽÐ°Ðœ Ð±Ð°ÑÐºÑ Ð±ÐµÑÑÐµ Ð±ÐŸÐ»ÐŸÑÑÐ·.}
+
+_textdefaulttitle_ [l=ky] {GSDL ÐÐ°ÑÐ°}
+
+_textbadcollection_ [l=ky] {ÐÑÐ» ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ("_cvariable_") Greenstone ÑÐžÑÑÐµÐŒÐ°ÑÑÐœÐŽÐ° ÐŸÑÐœÐŸÑÑÐ»Ð³Ð°Ðœ ÑÐŒÐµÑ.}
+
+_textselectpage_ [l=ky] {-- Ð¢Ð°ÐœÐŽÐŸÐŸ Ð±Ð°ÑÐ°Ð³Ñ --}
+
+_collectionextra_ [l=ky] {ÐÑÐ» ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°  _about:numdocs_ ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð±Ð°Ñ. 
+ÐÐºÑÑÐºÑ Ó©Ð·Ð³Ó©ÑÑÒ¯Ò¯Ð»Ó©Ñ _about:builddate_ ÐºÒ¯Ðœ ÐŒÑÑÑÐœ Ð¶Ð°ÑÐ°Ð»Ð³Ð°Ðœ.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=ky] {<p>ÐÒ±Ð»  ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° _numdocs_ If_(â_numdocs_â eq â1â, ÐŽÐŸÐºÑÐŒÐµÐœÑ, ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ), Ð±Ð°ÑÐŽÑÐ³Ñ _numbytes_.
+ <p><a href=â_httppagex_(bsummary)â>ÐÑÐœÑ Ð±Ð°ÑÑÒ£ÑÐ·</a> ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ Ð°ÐºÑÑÐºÑ Ð¶ÑÐ¹ÑÐœÑÑÐºÑÐŸÐŸÑÑ ÑÒ¯Ð·Ò¯Ð»Ò¯ÑÒ¯Ðœ ÐºÑÑÑÑ Ò¯ÑÒ¯Ðœ.
+}
+
+_textimagecollection_ [l=ky] {}
+_textimageabout_ [l=ky] {ÐÑÐŸÐ³ÑÐ°ÐŒÐŒÐ° Ð¶Ó©ÐœÒ¯ÐœÐŽÓ©}
+_textimagehome_ [l=ky] {Ò®Ð¹ Ð±ÐµÑÐž}
+_textimagehelp_ [l=ky] {ÐÐ°ÑÐŽÐ°ÐŒ Ð±ÐµÑÐž}
+_textimagepref_ [l=ky] {Ð¢Ò¯Ð·Ó©ÑÒ¯Ò¯ Ð±ÐµÑÐž}
+_textimagegreenstone_ [l=ky] {Greenstone ÑÐ»ÐµÐºÑÑÐŸÐœÐŽÑÐº ÐºÐžÑÐµÐ¿ÐºÐ°ÐœÐ°ÑÑ}
+_textimageusab_ [l=ky] {ÐÐ·ÐŽÓ©Ó©ÐŽÓ© ÐºÐ°ÐœÐŽÐ°Ð¹ ÐºÑÐ¹ÑÐœÑÑÐ»ÑÐºÑÐ°ÑÐŽÑ ÐºÓ©ÑÐŽÒ¯Ò£Ò¯Ð·? }
+
+_textimagesearch_ [l=ky] {ÐÐœÑÐºÑÐŸÐŸÑÑ ÑÐµÑÐŒÐžÐœÐŽÐµÑÐŽÑ ÐžÐ·ÐŽÓ©Ó©}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=ky] {ÐÑÑÐœ Ð°Ð»ÑÐ°Ð²ÐžÑ ÑÐžÐ·ÐŒÐµÑÐž Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageCreator_ [l=ky] {ÐÐ²ÑÐŸÑÐ»ÐŸÑÐŽÑ Ð°Ð»ÑÐ°Ð²ÐžÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageSubject_ [l=ky] {ÐÐžÑÑÐžÐ¿Ð»ÐžÐœÐ°ÑÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageDescription_ [l=ky] {ÐÐ°ÑÐœÐŽÐ°ÐŒÐ°  Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimagePublisher_ [l=ky] {ÐÐ°ÑÐŒÐ°ÐºÐ°ÐœÐ°Ð»Ð°Ñ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageContributor_ [l=ky] {Ð­ÐŒÐ³ÐµÐºÑÐµÑÑÐµÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageDate_ [l=ky] {ÐÐ°ÑÐ° Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageType_ [l=ky] {Ð¢ÐžÐ¿ÑÐµÑÐŽÐžÐœ ÑÐµÑÑÑÑÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageFormat_ [l=ky] {Ð€ÐŸÑÐŒÐ°Ñ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageIdentifier_ [l=ky] {ÐÐµÐ»Ð³Ðž ÑÐµÑÑÑÑÑÐ°ÑÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageSource_ [l=ky] {Ð€Ð°Ð¹Ð»ÐŽÑÐœ Ð°ÑÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageLanguage_ [l=ky] {Ð¢ÐžÐ»ÐŽÐµÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageRelation_ [l=ky] {ÐÐ°ÐŒÐžÐ»ÐµÐ»ÐµÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageCoverage_ [l=ky] {ÐÑÐ»ÐŽÐ°Ñ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageRights_ [l=ky] {Ð£ÐºÑÐºÑÐ°Ñ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+
+_textimageOrganization_ [l=ky] {Ð£ÑÐŒ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageKeyword_ [l=ky] {ÐÐ°Ò£ÑÐ· ÑÓ©Ð·ÐŽÓ©Ñ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageHowto_ [l=ky] {ÐÐŸÐ»ÐŽÐŸÐœÑÑÑÑÐ»Ð°Ñ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageList_ [l=ky] {ÐÐŸÐºÑÐŒÐµÐœÑÑÐžÐœ ÑÐžÐ·ÐŒÐµÑÐžÐœ ÐºÓ©ÑÒ¯Ò¯}
+_textimageSeries_ [l=ky] {ÐÐ°ÑÑÑÐ»Ð°ÐœÑÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÑÑ}
+_textimageTo_ [l=ky] {ÐÐŽÑÐµÑÐ°ÑÑÐ°Ñ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageFrom_ [l=ky] {ÐÐžÐ±ÐµÑÒ¯Ò¯ÑÒ¯Ð»Ó©Ñ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageTopic_ [l=ky] {Ð¢ÐµÐŒÐ°Ð»Ð°Ñ  Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageBrowse_ [l=ky] {ÐÓ©ÑÒ¯Ò¯}
+_textimageCollage_ [l=ky] {Ð¡Ò¯ÑÓ©ÑÑÓ©ÑÐŽÒ¯Ðœ ÐºÐŸÐ»Ð»Ð°Ð¶Ñ Ð°ÑÐºÑÐ»ÑÑ  ÐºÓ©ÑÒ¯Ò¯}
+_textimagePeople_ [l=ky] {ÐÐµÑÑÐŸÐœÐ°Ð»ÐžÐ¹Ð»ÐµÑÐŽÐž Ð°Ð»ÑÐ°Ð²ÐžÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageAcronym_ [l=ky] {ÐÑÑÐºÐ°ÑÑÑÑÐ»Ð°ÑÐŽÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimagePhrase_ [l=ky] {Ð€ÑÐ°Ð·Ð°Ð»Ð°Ñ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageArtist_ [l=ky] {Ð¡Ò¯ÑÓ©ÑÑÒ¯Ð»Ó©ÑÐŽÒ¯ ÐºÓ©ÑÒ¯Ò¯}
+_textimageVolume_ [l=ky] {Ð¢ÐŸÐŒÐŽÐŸÑÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+_textimageCountries_ [l=ky] {ÓšÐ»ÐºÓ©Ð»Ó©Ñ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯ }
+_textimageCaptions_ [l=ky] {Ð€ÐŸÑÐŸ ÑÒ¯ÑÓ©ÑÑÓ©ÑÐŽÒ¯Ðœ Ð¶Ð°Ð·ÑÑÐ»Ð°ÑÑ Ð°ÑÐºÑÐ»ÑÑ ÐºÓ©ÑÒ¯Ò¯}
+
+
+_texticontabsearchgreen_ [l=ky] {ÐÐ·ÐŽÓ©Ó©}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=ky] {ÐÐ°Ñ Ð°ÑÑ Ð-Ð¯ }
+_texticontabCreatorgreen_ [l=ky] {ÐÐ²ÑÐŸÑÐ»ÐŸÑÑ Ð-Ð¯ }
+_texticontabSubjectgreen_ [l=ky] {ÐÐžÑÑÐžÐ¿Ð»ÐžÐœÐ°ÑÑ }
+_texticontabDescriptiongreen_ [l=ky] {ÐÐ°ÑÐœÐŽÐŸÐŸÐ»ÐŸÑ}
+_texticontabPublishergreen_ [l=ky] {ÐÐ°ÑÑÐ¿ ÑÑÐ³Ð°ÑÑÑÑÑÐ»Ð°Ñ}
+_texticontabContributorgreen_ [l=ky] {Ð­ÐŒÐ³ÐµÐºÑÐµÑÑÐµÑ}
+_texticontabDategreen_ [l=ky] {ÐÐ°ÑÐ°Ð»Ð°Ñ}
+_texticontabTypesgreen_ [l=ky] {Ð¢ÐžÐ¿ÑÐµÑÐž}
+_texticontabFormatgreen_ [l=ky] {Ð€ÐŸÑÐŒÐ°ÑÑÐ°Ñ}
+_texticontabIdentifiergreen_ [l=ky] {ÐÐµÐ»Ð³ÐžÐ»ÐµÑ}
+_texticontabSourcegreen_ [l=ky] {Ð€Ð°Ð¹Ð»ÐŽÑÐœ Ð°ÑÑ}
+_texticontabLanguagegreen_ [l=ky] {Ð¢ÐžÐ»ÐŽÐµÑ}
+_texticontabRelationgreen_ [l=ky] {ÐÐ°ÐŒÐžÐ»ÐµÐ»ÐµÑ}
+_texticontabCoveragegreen_ [l=ky] {ÐÑÐ»ÐŽÐ°Ñ}
+_texticontabRightsgreen_ [l=ky] {Ð£ÐºÑÐºÑÐ°ÑÑ}
+
+_texticontaborggreen_ [l=ky] {Ð£ÑÐŒ }
+_texticontabKeywordgreen_ [l=ky] {ÐÐ°Ò£ÑÐ·ÐŽÑÑ ÑÓ©Ð·ÐŽÓ©Ñ}
+_texticontabhowgreen_ [l=ky] {ÐÑÐ°ÐºÐµÑÑÐµÑ}
+_texticontabseriesgreen_ [l=ky] {Ð¡ÐµÑÐžÑÐ»Ð°Ñ}
+_texticontablistgreen_ [l=ky] {Ð¢ÐžÐ·ÐŒÐµ }
+_texticontabtogreen_ [l=ky] {ÐÐžÐŒÐ³Ðµ}
+_texticontabfromgreen_ [l=ky] {ÐÐžÐŒÐŽÐµÐœ}
+_texticontabtopicgreen_ [l=ky] {Ð¢ÐµÐŒÐ°Ð»Ð°Ñ}
+_texticontabbrwsegreen_ [l=ky] {ÐÓ©ÑÑÓ©ÑÒ¯Ò¯}
+_texticontabCollagegreen_ [l=ky] {ÐÐŸÐ»Ð»Ð°Ð¶}
+_texticontabbrowsgreen_ [l=ky] {ÐÓ©ÑÑÓ©ÑÒ¯Ò¯}
+_texticontabPeoplegreen_ [l=ky] {ÐÐµÑÑÐŸÐœÐ°Ð»ÐžÐ¹Ð»ÐµÑ Ð-Ð¯}
+_texticontabAcronymgreen_ [l=ky] {ÐÑÑÐºÐ°ÑÑÑÑÐ»Ð°Ñ}
+_texticontabPhrasegreen_ [l=ky] {Ð€ÑÐ°Ð·Ð°Ð»Ð°Ñ}
+_texticontabArtistgreen_ [l=ky] {Ð¡Ò¯ÑÓ©ÑÑÒ¯Ð»Ó©Ñ }
+_texticontabVolumegreen_ [l=ky] {Ð¢ÐŸÐŒÐŽÐŸÑÑ}
+_texticontabCaptionsgreen_ [l=ky] {ÐÐ°Ð·ÑÑÐ»Ð°Ñ}
+_texticontabCountriesgreen_ [l=ky] {ÓšÐ»ÐºÓ©Ð»Ó©Ñ}
+
+_texticontext_ [l=ky] {ÐÐŸÐºÑÐŒÐµÐœÑÑÐž ÐºÓ©ÑÒ¯Ò¯}
+_texticonclosedbook_ [l=ky] {ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐž Ð°ÑÑÑ Ð¶Ð°ÐœÐ° ÐŒÐ°Ð·ÐŒÑÐœÑÐœ ÐºÓ©ÑÒ¯Ò¯}
+_texticonnext_ [l=ky] {ÐºÐžÐ¹ÐžÐœÐºÐž Ð±Ó©Ð»Ò¯ÐŒÐ³Ó© Ó©ÑÒ¯Ò¯}
+_texticonprev_ [l=ky] {Ð°Ð»ÐŽÑÒ£ÐºÑ Ð±Ó©Ð»Ò¯ÐºÐºÓ© Ó©ÑÒ¯Ò¯}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=ky] {MIDI ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐž ÐºÓ©ÑÒ¯Ò¯}
+_texticonmsword_ [l=ky] {Microsoft Word ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐž ÐºÓ©ÑÒ¯Ò¯}
+# -- Missing translation: _texticonmp3_
+_texticonpdf_ [l=ky] {PDF ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐž ÐºÓ©ÑÒ¯Ò¯}
+_texticonps_ [l=ky] {PostScrip ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐž ÐºÓ©ÑÒ¯Ò¯}
+_texticonppt_ [l=ky] {PowerPoint ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐž ÐºÓ©ÑÒ¯Ò¯ }
+_texticonrtf_ [l=ky] {RTF ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐž ÐºÓ©ÑÒ¯Ò¯}
+_texticonxls_ [l=ky] {Microsoft Excel ÐŽÐŸÐºÑÐŒÐµÐœÑÐžÐœ ÐºÓ©ÑÒ¯Ò¯}
+
+_page_ [l=ky] {Ð±ÐµÑ}
+_pages_ [l=ky] {Ð±ÐµÑÑÐµÑ}
+_of_ [l=ky] {ÑÐµÐœ}
+_vol_ [l=ky] {Ð¢ÐŸÐŒ}
+_num_ [l=ky] {ÐÐŸÐŒÐµÑÐž}
+
+_textmonth00_ [l=ky] {}
+_textmonth01_ [l=ky] {ÐÐžÑÐŽÐžÐœ Ð°Ð¹Ñ}
+_textmonth02_ [l=ky] {ÐÐ°Ð»Ð³Ð°Ðœ ÐºÑÑÐ°Ðœ}
+_textmonth03_ [l=ky] {Ð§ÑÐœ ÐºÑÑÐ°Ðœ}
+_textmonth04_ [l=ky] {ÐÑÐ³Ñ}
+_textmonth05_ [l=ky] {ÐÑÐ»Ð¶Ð°}
+_textmonth06_ [l=ky] {Ð¢ÐµÐºÐµ}
+_textmonth07_ [l=ky] {ÐÐ°Ñ ÐŸÐŸÐœÐ°}
+_textmonth08_ [l=ky] {ÐÑÐº ÐŸÐŸÐœÐ°}
+_textmonth09_ [l=ky] {Ð¢ÐŸÐ³ÑÐ·ÐŽÑÐœ Ð°Ð¹Ñ}
+_textmonth10_ [l=ky] {ÐÐµÑÐžÐœÐžÐœ Ð°Ð¹Ñ}
+_textmonth11_ [l=ky] {ÐÐµÑÑÐžÐœ Ð°Ð¹Ñ}
+_textmonth12_ [l=ky] {Ò®ÑÑÒ¯Ðœ Ð°Ð¹Ñ}
+
+_textdocument_ [l=ky] {ÐÐŸÐºÑÐŒÐµÐœÑ}
+_textsection_ [l=ky] {ÐÓ©Ð»Ò¯ÐŒ}
+_textparagraph_ [l=ky] {ÐÐ°ÑÐ°Ð³ÑÐ°Ñ}
+
+_magazines_ [l=ky] {ÐÑÑÐœÐ°Ð»ÐŽÐ°Ñ}
+
+_nzdlpagefooter_ [l=ky] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">ÐÐ°Ò£Ñ ÐÐµÐ»Ð°ÐœÐŽÐžÑ Ð­Ð»ÐµÐºÑÑÐŸÐœÐŽÑÐº ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ° ÐÑÐŸÐµÐºÑÐž</a>
+<br><a href="http://www.cs.waikato.ac.nz">ÐÐœÑÐŸÑÐŒÐ°ÑÐžÐºÐ° Ð±Ó©Ð»Ò¯ÐŒÒ¯</a>, 
+<a href="http://www.waikato.ac.nz">ÐÐ°Ð¹ÐºÐ°ÑÐŸ Ð£ÐœÐžÐ²ÐµÑÑÐžÑÐµÑÐž</a>, 
+ÐÐ°Ò£Ñ ÐÐµÐ»Ð°ÐœÐŽÐžÑ}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Ò®Ð" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=ky] {_httpimg_/ky/chomeof.gif}
+_httpiconchomeon_ [l=ky] {_httpimg_/ky/chomeon.gif}
+
+## "ÐÐÐ ÐÐÐ" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=ky] {_httpimg_/ky/chelpof.gif}
+_httpiconchelpon_ [l=ky] {_httpimg_/ky/chelpon.gif}
+
+## "Ð¢Ò®ÐÓšÐ¢Ò®Ò®ÐÓšÐ " ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=ky] {_httpimg_/ky/cprefof.gif}
+_httpiconcprefon_ [l=ky] {_httpimg_/ky/cprefon.gif}
+
+## "ÐÐÐ¢ ÐÐÐÐ£Ð£" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=ky] {_httpimg_/ky/cusabof.gif}
+_httpiconcusabon_ [l=ky] {_httpimg_/ky/cusabon.gif}
+
+
+## "ÐžÐ·ÐŽÓ©Ó©" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=ky] {_httpimg_/ky/tsrchgr.gif}
+_httpicontsrchof_ [l=ky] {_httpimg_/ky/tsrchof.gif}
+_httpicontsrchon_ [l=ky] {_httpimg_/ky/tsrchon.gif}
+_widthtsrchx_ [l=ky] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ÑÐžÐ·ÐŒÐµÐ»ÐµÑ Ð°-Ñ" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=ky] {_httpimg_/ky/ttitlgr.gif}
+_httpiconttitleof_ [l=ky] {_httpimg_/ky/ttitlof.gif}
+_httpiconttitleon_ [l=ky] {_httpimg_/ky/ttitlon.gif}
+_widthttitlex_ [l=ky] {87}
+
+# Not true DC, kept for legacy reasons
+## "Ð°Ð²ÑÐŸÑÐ»ÐŸÑ Ð°-Ñ" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=ky] {_httpimg_/ky/tauthgr.gif}
+_httpicontcreatof_ [l=ky] {_httpimg_/ky/tauthof.gif}
+_httpicontcreaton_ [l=ky] {_httpimg_/ky/tauthon.gif}
+_widthtcreatx_ [l=ky] {87}
+
+## "ÐŽÐžÑÑÐžÐ¿Ð»ÐžÐœÐ°Ð»Ð°Ñ" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=ky] {_httpimg_/ky/tsubjgr.gif}
+_httpicontsubjon_ [l=ky] {_httpimg_/ky/tsubjon.gif}
+_httpicontsubjof_ [l=ky] {_httpimg_/ky/tsubjof.gif}
+_widthtsubjx_ [l=ky] {87}
+
+## "Ð±Ð°ÑÐœÐŽÐ°ÐŒÐ°Ð»Ð°Ñ" ## nav_bar_button ## tdesc ##
+_httpicontdescgr_ [l=ky] {_httpimg_/ky/tdescgr.gif}
+_httpicontdescon_ [l=ky] {_httpimg_/ky/tdescon.gif}
+_httpicontdescof_ [l=ky] {_httpimg_/ky/tdescof.gif}
+_widthtdescx_ [l=ky] {90}
+
+## "Ð±Ð°ÑÐŒÐ°ÐºÐ°ÐœÐ°Ð»Ð°Ñ" ## nav_bar_button ## tpubl ##
+_httpicontpublgr_ [l=ky] {_httpimg_/ky/tpublgr.gif}
+_httpicontpublon_ [l=ky] {_httpimg_/ky/tpublon.gif}
+_httpicontpublof_ [l=ky] {_httpimg_/ky/tpublof.gif}
+_widthtpublx_ [l=ky] {87}
+
+## "ÑÐŒÐ³ÐµÐºÑÐµÑÑÐµÑ" ## nav_bar_button ## tcontr ##
+_httpicontcontrgr_ [l=ky] {_httpimg_/ky/tcontrgr.gif}
+_httpicontcontron_ [l=ky] {_httpimg_/ky/tcontron.gif}
+_httpicontcontrof_ [l=ky] {_httpimg_/ky/tcontrof.gif}
+_widthtcontrx_ [l=ky] {89}
+
+## "ÐŽÐ°ÑÐ°Ð»Ð°Ñ" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=ky] {_httpimg_/ky/tdategr.gif}
+_httpicontdateof_ [l=ky] {_httpimg_/ky/tdateof.gif}
+_httpicontdateon_ [l=ky] {_httpimg_/ky/tdateon.gif}
+_widthtdatex_ [l=ky] {87}
+
+## "ÑÐžÐ¿ÑÐµÑ" ## nav_bar_button ## ttype ##
+_httpiconttypegr_ [l=ky] {_httpimg_/ky/ttypegr.gif}
+_httpiconttypeof_ [l=ky] {_httpimg_/ky/ttypeof.gif}
+_httpiconttypeon_ [l=ky] {_httpimg_/ky/ttypeon.gif}
+_widthttypex_ [l=ky] {87}
+
+## "ÑÐŸÑÐŒÐ°ÑÑÐ°Ñ" ## nav_bar_button ## tform ##
+_httpicontformgr_ [l=ky] {_httpimg_/ky/tformgr.gif}
+_httpicontformof_ [l=ky] {_httpimg_/ky/tformof.gif}
+_httpicontformon_ [l=ky] {_httpimg_/ky/tformon.gif}
+_widthtformx_ [l=ky] {87}
+
+## "Ð±ÐµÐ»Ð³ÐžÐ»ÐµÑ" ## nav_bar_button ## tident ##
+_httpicontidentgr_ [l=ky] {_httpimg_/ky/tidentgr.gif}
+_httpicontidentof_ [l=ky] {_httpimg_/ky/tidentof.gif}
+_httpicontidenton_ [l=ky] {_httpimg_/ky/tidenton.gif}
+_widthtidentx_ [l=ky] {87}
+
+# Not true DC, kept for legacy reasons
+## "ÑÐ°Ð¹Ð»ÐŽÑÐœ Ð°ÑÑ" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=ky] {_httpimg_/ky/tsrcgr.gif}
+_httpicontsrcof_ [l=ky] {_httpimg_/ky/tsrcof.gif}
+_httpicontsrcon_ [l=ky] {_httpimg_/ky/tsrcon.gif}
+_widthtsrcx_ [l=ky] {87}
+
+## "ÑÐžÐ»ÐŽÐµÑ" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=ky] {_httpimg_/ky/tlanggr.gif}
+_httpicontlangon_ [l=ky] {_httpimg_/ky/tlangon.gif}
+_httpicontlangof_ [l=ky] {_httpimg_/ky/tlangof.gif}
+_widthtlangx_ [l=ky] {87}
+
+## "ÐŒÐ°ÐŒÐžÐ»ÐµÐ»ÐµÑ" ## nav_bar_button ## trel ##
+_httpicontrelgr_ [l=ky] {_httpimg_/ky/trelgr.gif}
+_httpicontrelon_ [l=ky] {_httpimg_/ky/trelon.gif}
+_httpicontrelof_ [l=ky] {_httpimg_/ky/trelof.gif}
+_widthtrelx_ [l=ky] {87}
+
+## "ÐŽÐ°ÑÐ°Ð»Ð°Ñ" ## nav_bar_button ## tcover ##
+_httpicontcovergr_ [l=ky] {_httpimg_/ky/tcovergr.gif}
+_httpicontcoveron_ [l=ky] {_httpimg_/ky/tcoveron.gif}
+_httpicontcoverof_ [l=ky] {_httpimg_/ky/tcoverof.gif}
+_widthtcoverx_ [l=ky] {87}
+
+## "ÑÐºÑÐºÑÐ°Ñ" ## nav_bar_button ## tright ##
+_httpicontrightgr_ [l=ky] {_httpimg_/ky/trightgr.gif}
+_httpicontrighton_ [l=ky] {_httpimg_/ky/trighton.gif}
+_httpicontrightof_ [l=ky] {_httpimg_/ky/trightof.gif}
+_widthtrightx_ [l=ky] {87}
+
+
+
+## "ÑÐµÑÐžÑÐ»Ð°Ñ" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=ky] {_httpimg_/ky/tsergr.gif}
+_httpicontserof_ [l=ky] {_httpimg_/ky/tserof.gif}
+_httpicontseron_ [l=ky] {_httpimg_/ky/tseron.gif}
+_widthtserx_ [l=ky] {87}
+
+## "ÐºÐžÐŒÐ³Ðµ" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=ky] {_httpimg_/ky/ttogr.gif}
+_httpiconttoon_ [l=ky] {_httpimg_/ky/ttoon.gif}
+_httpiconttoof_ [l=ky] {_httpimg_/ky/ttoof.gif}
+_widthttox_ [l=ky] {87}
+
+## "ÐºÐžÐŒÐŽÐµÐœ" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=ky] {_httpimg_/ky/tfromgr.gif}
+_httpicontfromon_ [l=ky] {_httpimg_/ky/tfromon.gif}
+_httpicontfromof_ [l=ky] {_httpimg_/ky/tfromof.gif}
+_widthtfromx_ [l=ky] {87}
+
+## "ÑÑÐŒÐŽÐ°Ñ" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=ky] {_httpimg_/ky/torggr.gif}
+_httpicontorgon_ [l=ky] {_httpimg_/ky/torgon.gif}
+_httpicontorgof_ [l=ky] {_httpimg_/ky/torgof.gif}
+_widthtorgx_ [l=ky] {98}
+
+## "Ð°ÑÐ°ÐºÐµÑÑÐµÑ" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=ky] {_httpimg_/ky/thowgr.gif}
+_httpiconthowon_ [l=ky] {_httpimg_/ky/thowon.gif}
+_httpiconthowof_ [l=ky] {_httpimg_/ky/thowof.gif}
+_widththowx_ [l=ky] {87}
+
+## "ÑÐµÐŒÐ°" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=ky] {_httpimg_/ky/ttopicgr.gif}
+_httpiconttopicon_ [l=ky] {_httpimg_/ky/ttopicon.gif}
+_httpiconttopicof_ [l=ky] {_httpimg_/ky/ttopicof.gif}
+_widthttopicx_ [l=ky] {87}
+
+## "ÐºÓ©ÑÑÓ©ÑÒ¯Ò¯" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=ky] {_httpimg_/ky/tbrwsegr.gif}
+_httpicontbrwseon_ [l=ky] {_httpimg_/ky/tbrwseon.gif}
+_httpicontbrwseof_ [l=ky] {_httpimg_/ky/tbrwseof.gif}
+_widthtbrwsex_ [l=ky] {87}
+
+## "ÐºÐŸÐ»Ð»Ð°Ð¶" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=ky] {_httpimg_/ky/tcollgr.gif}
+_httpicontcollof_ [l=ky] {_httpimg_/ky/tcollof.gif}
+_httpicontcollon_ [l=ky] {_httpimg_/ky/tcollon.gif}
+_widthtcollx_ [l=ky] {87}
+
+## "Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐ¹Ð»ÐµÑ" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=ky] {_httpimg_/ky/tpeopgr.gif}
+_httpicontpeopof_ [l=ky] {_httpimg_/ky/tpeopof.gif}
+_httpicontpeopon_ [l=ky] {_httpimg_/ky/tpeopon.gif}
+_widthtpeopx_ [l=ky] {97}
+
+## "ÐºÑÑÐºÐ°ÑÑÑÑÐ»Ð°Ñ" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=ky] {_httpimg_/ky/tacrogr.gif}
+_httpicontacroof_ [l=ky] {_httpimg_/ky/tacroof.gif}
+_httpicontacroon_ [l=ky] {_httpimg_/ky/tacroon.gif}
+_widthtacrox_ [l=ky] {87}
+
+## "ÑÑÐ°Ð·Ð°Ð»Ð°Ñ" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=ky] {_httpimg_/ky/tphrsegr.gif}
+_httpicontphrseof_ [l=ky] {_httpimg_/ky/tphrseof.gif}
+_httpicontphrseon_ [l=ky] {_httpimg_/ky/tphrseon.gif}
+_widthtphrsex_ [l=ky] {87}
+
+## "ÑÒ¯ÑÓ©ÑÑÒ¯Ð»Ó©Ñ" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=ky] {_httpimg_/ky/tartstgr.gif}
+_httpicontartstof_ [l=ky] {_httpimg_/ky/tartstof.gif}
+_httpicontartston_ [l=ky] {_httpimg_/ky/tartston.gif}
+_widthtartstx_ [l=ky] {87}
+
+## "ÐŒÐ°Ò£ÑÐ· ÑÓ©Ð·ÐŽÓ©Ñ" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=ky] {_httpimg_/ky/tkwgr.gif}
+_httpicontkwof_ [l=ky] {_httpimg_/ky/tkwof.gif}
+_httpicontkwon_ [l=ky] {_httpimg_/ky/tkwon.gif}
+_widthtkwx_ [l=ky] {87}
+
+## "ÑÐŸÐŒÐŽÐŸÑ" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=ky] {_httpimg_/ky/tvolgr.gif}
+_httpicontvolof_ [l=ky] {_httpimg_/ky/tvolof.gif}
+_httpicontvolon_ [l=ky] {_httpimg_/ky/tvolon.gif}
+_widthtvolx_ [l=ky] {87}
+
+## "Ð¶Ð°Ð·ÑÑÐ»Ð°Ñ" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=ky] {_httpimg_/ky/tcaptgr.gif}
+_httpicontcaptof_ [l=ky] {_httpimg_/ky/tcaptof.gif}
+_httpicontcapton_ [l=ky] {_httpimg_/ky/tcapton.gif}
+_widthtcaptx_ [l=ky] {87}
+
+## "Ó©Ð»ÐºÓ©Ð»Ó©Ñ" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=ky] {_httpimg_/ky/tcountgr.gif}
+_httpicontcountof_ [l=ky] {_httpimg_/ky/tcountof.gif}
+_httpicontcounton_ [l=ky] {_httpimg_/ky/tcounton.gif}
+_widthtcountx_ [l=ky] {87}
+
+## "Ð¶Ð°ÑÐŽÐ°ÐŒ" ## green_title ## h_help ##
+_httpiconhhelp_ [l=ky] {_httpimg_/ky/h\_help.gif}
+_widthhhelp_ [l=ky] {200}
+_heighthhelp_ [l=ky] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=ky] {ÐÑÐ» ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¶Ó©ÐœÒ¯ÐœÐŽÓ©}
+
+_textsubcols1_ [l=ky] {<p>ÐÑÐ» ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° _1_ ÐžÑÐºÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±Ð°Ñ. 
+ <blockquote>}
+
+_textsubcols2_ [l=ky] {</blockquote>
+Ð¡ÐžÐ·  ÑÒ¯Ð·Ó©ÑÒ¯Ò¯Ð»Ó©Ñ Ð±ÐµÑÐžÐœÐŽÐµ Ð°Ð·ÑÑ ÐºÐŸÐ»ÐŽÐŸÐœÑÐ¿ Ð¶Ð°ÑÐºÐ°Ðœ ÐžÑÐºÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑÐœ ÑÐžÐ·ÐŒÐµÑÐžÐœ ÐºÓ©ÑÒ¯Ð¿ Ð¶Ðµ Ð±ÐŸÐ»ÑÐŸ Ó©Ð·Ð³Ó©ÑÑÓ© Ð°Ð»Ð°ÑÑÐ·.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Ð¶Ó©ÐœÒ¯ÐœÐŽÓ©" ## green_title ## h_about ##
+_httpiconhabout_ [l=ky] {_httpimg_/ky/h\_about.gif}
+_widthhabout_ [l=ky] {200}
+_heighthabout_ [l=ky] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=ky] {Ð¢ÐžÐ·ÐŒÐµÐ»ÐµÑ Ð-Ð¯ }
+_texticonhcreat_ [l=ky] {ÐÐ²ÑÐŸÑÐ»ÐŸÑ Ð-Ð¯}
+_texticonhsubj_ [l=ky] {ÐÐžÑÑÐžÐ¿Ð»ÐžÐœÐ°Ð»Ð°Ñ}
+_texticonhdesc_ [l=ky] {ÐÐ°ÑÐœÐŽÐ°ÐŒÐ°Ð»Ð°Ñ}
+_texticonhpubl_ [l=ky] {ÐÐ°ÑÑÑÑÑÐ¿ ÑÑÐ³Ð°ÑÑÑÑÑÐ»Ð°Ñ}
+_texticonhcontr_ [l=ky] {Ð­ÐŒÐ³ÐµÐºÑÐµÑÑÐµÑ}
+_texticonhdate_ [l=ky] {ÐÐ°ÑÐ°Ð»Ð°Ñ}
+_texticonhtype_ [l=ky] {Ð¢ÐžÐ¿ÑÐµÑÐž}
+_texticonhform_ [l=ky] {Ð€ÐŸÑÐŒÐ°ÑÑÐ°Ñ}
+_texticonhident_ [l=ky] {ÐÐµÐ»Ð³ÐžÐ»ÐµÑ}
+_texticonhsrc_ [l=ky] {Ð€Ð°Ð¹Ð»ÐŽÑÐœ Ð°ÑÑÐ°ÑÑ}
+_texticonhlang_ [l=ky] {Ð¢ÐžÐ»ÐŽÐµÑ}
+_texticonhrel_ [l=ky] {ÐÐ°ÐŒÐžÐ»ÐµÐ»ÐµÑ}
+_texticonhcover_ [l=ky] {ÐÐ°ÑÐ°Ð»Ð°Ñ}
+_texticonhright_ [l=ky] {Ð£ÐºÑÐºÑÐ°Ñ}
+
+_texticonhcoll_ [l=ky] {ÐÐŸÐ»Ð»Ð°Ð¶}
+_texticonhto_ [l=ky] {ÐÐžÐŒÐ³Ðµ}
+_texticonhfrom_ [l=ky] {ÐÐžÐŒÐŽÐµÐœ}
+_texticonhser_ [l=ky] {Ð¡ÐµÑÐžÑÐ»Ð°Ñ}
+_texticonhhow_ [l=ky] {ÐÑÐ°ÐºÐµÑÑÐµÑ}
+_texticonhorg_ [l=ky] {Ð£ÑÐŒÐŽÐ°Ñ}
+_texticonhbrwse_ [l=ky] {ÐÓ©ÑÑÓ©ÑÒ¯Ò¯}
+_texticonhbrows_ [l=ky] {ÐÓ©ÑÑÓ©ÑÒ¯Ò¯}
+_texticonhpeople_ [l=ky] {ÐÐµÑÑÐŸÐœÐ°Ð»ÐžÐ¹Ð»ÐµÑ Ð-Ð¯}
+_texticonhacronym_ [l=ky] {ÐÑÑÐºÐ°ÑÑÑÑÐ»Ð°Ñ}
+_texticonhphrases_ [l=ky] {Ð€ÑÐ°Ð·Ð°Ð»Ð°Ñ}
+_texticonhartist_ [l=ky] {Ð¡Ò¯ÑÓ©ÑÑÒ¯Ð»Ó©Ñ}
+_texticonhkw_ [l=ky] {ÐÐ°Ò£ÑÐ·ÐŽÑÑ ÑÓ©Ð·ÐŽÓ©Ñ}
+_texticonhvol_ [l=ky] {Ð¢ÐŸÐŒÐŽÐŸÑÑ}
+_texticonhcapt_ [l=ky] {ÐÐ°Ð·ÑÑÐ»Ð°Ñ}
+_texticonhcount_ [l=ky] {ÓšÐ»ÐºÓ©Ð»Ó©Ñ}
+
+_texticonopenbookshelf_ [l=ky] {ÐºÐžÑÐµÐ¿ÐºÐ°ÐœÐ° Ð±Ó©Ð»Ò¯ÐŒÒ¯Ðœ Ð¶Ð°Ð±ÑÑ}
+_texticonclosedbookshelf_ [l=ky] {ÐºÐžÑÐµÐ¿ÐºÐ°ÐœÐ° Ð±Ó©Ð»Ò¯ÐŒÒ¯Ðœ Ð°ÑÑÑ Ð¶Ð°ÐœÐ° ÐŒÐ°Ð·ÐŒÑÐœÑÐœ ÐºÓ©ÑÒ¯Ò¯ }
+_texticonopenbook_ [l=ky] {ÐºÐžÑÐµÐ¿ÑÐž Ð¶Ð°Ð±ÑÑ}
+_texticonclosedfolder_ [l=ky] {ÐÐ°Ð¿ÐºÐ°ÐœÑ Ð°ÑÑÑ Ð¶Ð°ÐœÐ° ÐŒÐ°Ð·ÐŒÑÐœÑÐœ ÐºÓ©ÑÒ¯Ò¯ }
+_texticonclosedfolder2_ [l=ky] {ÐžÑÐºÐž Ð±Ó©Ð»Ò¯ÐŒÐŽÒ¯ Ð°ÑÑÑ}
+_texticonopenfolder_ [l=ky] {Ð¿Ð°Ð¿ÐºÐ°ÐœÑ Ð¶Ð°Ð±ÑÑ}
+_texticonopenfolder2_ [l=ky] {ÐžÑÐºÐž Ð±Ó©Ð»Ò¯ÐŒÐŽÒ¯ Ð¶Ð°Ð±ÑÑ}
+_texticonsmalltext_ [l=ky] {Ð¢ÐµÐºÑÑÑÐžÐœ Ð±Ó©Ð»Ò¯ÐŒÒ¯Ðœ ÐºÓ©ÑÒ¯Ò¯}
+_texticonsmalltext2_ [l=ky] {ÑÐµÐºÑÑÑÐž ÐºÓ©ÑÒ¯Ò¯}
+_texticonpointer_ [l=ky] {ÐºÐµÐ·ÐµÐºÑÐµÐ³Ðž Ð±Ó©Ð»Ò¯ÐŒ}
+_texticondetach_ [l=ky] {ÐÐ°Ò£Ñ ÑÐµÑÐµÐ·ÐµÐŽÐµÐœ Ð±ÑÐ» Ð±ÐµÑÑÐž Ð°ÑÑÑ}
+_texticonhighlight_ [l=ky] {ÐÐ·ÐŽÐµÐ»Ò¯Ò¯ÑÒ¯ ÑÐµÑÐŒÐžÐœÐŽÐµÑÐŽÐž Ð±Ó©Ð»Ò¯Ð¿ ÐºÓ©ÑÑÓ©ÑÒ¯Ò¯}
+_texticonnohighlight_ [l=ky] {ÐÐ·ÐŽÐµÐ»Ò¯Ò¯ÑÒ¯ ÑÐµÑÐŒÐžÐœÐŽÐµÑÐŽÐž ÐºÓ©ÑÑÓ©ÑÐ¿Ó©Ó©}
+_texticoncontracttoc_ [l=ky] {ÐÐ°Ð·ÐŒÑÐœÐŽÑÑ ÑÒ¯ÑÒ¯Ò¯}
+_texticonexpandtoc_ [l=ky] {ÐÐ°Ð°ÑÐŽÑÐº ÐŒÐ°Ð·ÐŒÑÐœÐŽÑ Ð°ÑÑÐ¿ ÐºÓ©ÑÑÓ©ÑÒ¯Ò¯ }
+_texticonexpandtext_ [l=ky] {ÐÐ°Ð°ÑÐŽÑÐº ÑÐµÐºÑÑÑÐž ÐºÓ©ÑÑÓ©ÑÒ¯Ò¯}
+_texticoncontracttext_ [l=ky] {ÓšÐ·Ò¯ÐœÑÓ© Ð°Ð»ÑÐœÐ³Ð°Ðœ Ð±Ó©Ð»Ò¯ÐŒÐŽÓ©Ñ Ò¯ÑÒ¯Ðœ ÑÐµÐºÑÑÑÐž ÐºÓ©ÑÑÓ©ÑÒ¯Ò¯ }
+_texticonwarning_ [l=ky] {<b>ÐÐ°ÑÐ°: </b>}
+_texticoncont_ [l=ky] {ÑÐ»Ð°ÐœÑÑÐ»ÑÑÐœÐ±Ñ?}
+
+_textltwarning_ [l=ky] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_ ÐÑÐ» ÑÐµÐºÑÑÑÐžÐœ ÐºÓ©Ð»Ó©ÐŒÒ¯ÐœÓ© Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÑÑÑ _imagecont_ Ð±ÑÐ°ÑÐ·ÐµÑÐŽÐµÐœ ÐºÓ©ÑÒ¯Ò¯Ð³Ó© ÐŒÒ¯ÐŒÐºÒ¯Ðœ ÑÐŒÐµÑ.
+</td></tr></table></center>}
+
+_textgoto_ [l=ky] {Ð±ÐµÑÐºÐµ Ó©ÑÒ¯Ò¯}
+_textintro_ [l=ky] {<i>(ÐºÐžÑÐžÑÒ¯Ò¯)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ÑÐžÐ·ÐŒÐµÐ»ÐµÑ Ð-Ð¯" ## green_title ## h_title ##
+_httpiconhtitle_ [l=ky] {_httpimg_/ky/h\_title.gif}
+_widthhtitle_ [l=ky] {200}
+_heighthtitle_ [l=ky] {57}
+
+# Not true DC, kept for legacy reasons
+## "Ð°Ð²ÑÐŸÑÐ»ÐŸÑ Ð-Ð¯" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=ky] {_httpimg_/ky/h\_auth.gif}
+_widthhcreat_ [l=ky] {200}
+_heighthcreat_ [l=ky] {57}
+
+## "ÐŽÐžÑÑÐžÐ¿Ð»ÐžÐœÐ°Ð»Ð°Ñ" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=ky] {_httpimg_/ky/h\_subj.gif}
+_widthhsubj_ [l=ky] {200}
+_heighthsubj_ [l=ky] {57}
+
+## "Ð±Ð°ÑÐœÐŽÐ°ÐŒÐ°Ð»Ð°Ñ" ## green_title ## h_desc ##
+_httpiconhdesc_ [l=ky] {_httpimg_/ky/h\_desc.gif}
+_widthhdesc_ [l=ky] {200}
+_heighthdesc_ [l=ky] {57}
+
+## "Ð±Ð°ÑÑÐ¿ ÑÑÐ³Ð°ÑÑÑÑÑÐ»Ð°Ñ" ## green_title ## h_publ ##
+_httpiconhpubl_ [l=ky] {_httpimg_/ky/h\_publ.gif}
+_widthhpubl_ [l=ky] {200}
+_heighthpubl_ [l=ky] {57}
+
+## "ÑÐŒÐ³ÐµÐºÑÐµÑÑÐµÑ" ## green_title ## h_contr ##
+_httpiconhcontr_ [l=ky] {_httpimg_/ky/h\_contr.gif}
+_widthhcontr_ [l=ky] {200}
+_heighthcontr_ [l=ky] {57}
+
+## "ÐŽÐ°ÑÐ°Ð»Ð°Ñ" ## green_title ## h_date ##
+_httpiconhdate_ [l=ky] {_httpimg_/ky/h\_date.gif}
+_widthhdate_ [l=ky] {200}
+_heighthdate_ [l=ky] {57}
+
+## "ÑÐžÐ¿ÑÐµÑ" ## green_title ## h_type ##
+_httpiconhtype_ [l=ky] {_httpimg_/ky/h\_type.gif}
+_widthhtype_ [l=ky] {200}
+_heighthtype_ [l=ky] {57}
+
+## "ÑÐŸÑÐŒÐ°ÑÑÐ°Ñ" ## green_title ## h_form ##
+_httpiconhform_ [l=ky] {_httpimg_/ky/h\_form.gif}
+_widthhform_ [l=ky] {200}
+_heighthform_ [l=ky] {57}
+
+## "Ð±ÐµÐ»Ð³ÐžÐ»ÐµÑ" ## green_title ## h_ident ##
+_httpiconhident_ [l=ky] {_httpimg_/ky/h\_ident.gif}
+_widthhident_ [l=ky] {200}
+_heighthident_ [l=ky] {57}
+
+# Not true DC, kept for legacy reasons
+## "ÑÐ°Ð¹Ð»ÐŽÑÐœ Ð°ÑÑÐ°ÑÑ" ## green_title ## h_src ##
+_httpiconhsrc_ [l=ky] {_httpimg_/ky/h\_src.gif}
+_widthhsrc_ [l=ky] {200}
+_heighthsrc_ [l=ky] {57}
+
+## "ÑÐžÐ»ÐŽÐµÑ" ## green_title ## h_lang ##
+_httpiconhlang_ [l=ky] {_httpimg_/ky/h\_lang.gif}
+_widthhlang_ [l=ky] {200}
+_heighthlang_ [l=ky] {57}
+
+## "ÐŒÐ°ÐŒÐžÐ»ÐµÐ»ÐµÑ" ## green_title ## h_rel ##
+_httpiconhrel_ [l=ky] {_httpimg_/ky/h\_rel.gif}
+_widthhrel_ [l=ky] {200}
+_heighthrel_ [l=ky] {57}
+
+## "ÐŽÐ°ÑÐ°Ð»Ð°Ñ" ## green_title ## h_cover ##
+_httpiconhcover_ [l=ky] {_httpimg_/ky/h\_cover.gif}
+_widthhcover_ [l=ky] {200}
+_heighthcover_ [l=ky] {57}
+
+## "ÑÐºÑÐºÑÐ°Ñ" ## green_title ## h_right ##
+_httpiconhright_ [l=ky] {_httpimg_/ky/h\_right.gif}
+_widthhright_ [l=ky] {200}
+_heighthright_ [l=ky] {57}
+
+
+
+## "ÐºÐžÐŒÐ³Ðµ" ## green_title ## h_to ##
+_httpiconhto_ [l=ky] {_httpimg_/ky/h\_to.gif}
+_widthhto_ [l=ky] {200}
+_heighthto_ [l=ky] {57}
+
+## "ÑÐŸÑÐŒ" ## green_title ## h_from ##
+_httpiconhfrom_ [l=ky] {_httpimg_/ky/h\_from.gif}
+_widthhfrom_ [l=ky] {200}
+_heighthfrom_ [l=ky] {57}
+
+## "ÑÐµÑÐžÑÐ»Ð°Ñ" ## green_title ## h_ser ##
+_httpiconhser_ [l=ky] {_httpimg_/ky/h\_ser.gif}
+_widthhser_ [l=ky] {200}
+_heighthser_ [l=ky] {57}
+
+## "Ð°ÑÐ°ÐºÐµÑÑÐµÑ" ## green_title ## h_how ##
+_httpiconhhow_ [l=ky] {_httpimg_/ky/h\_how.gif}
+_widthhhow_ [l=ky] {200}
+_heighthhow_ [l=ky] {57}
+
+## "ÑÐµÐŒÐ°Ð»Ð°Ñ" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=ky] {_httpimg_/ky/h\_topic.gif}
+_widthhtopic_ [l=ky] {200}
+_heighthtopic_ [l=ky] {57}
+
+## "ÑÑÐŒÐŽÐ°Ñ" ## green_title ## h_org ##
+_httpiconhorg_ [l=ky] {_httpimg_/ky/h\_org.gif}
+_widthhorg_ [l=ky] {200}
+_heighthorg_ [l=ky] {57}
+
+## "ÐºÓ©ÑÑÓ©ÑÒ¯Ò¯" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=ky] {_httpimg_/ky/h\_brwse.gif}
+_widthhbrwse_ [l=ky] {200}
+_heighthbrwse_ [l=ky] {57}
+
+## "ÐºÐŸÐ»Ð»Ð°Ð¶" ## green_title ## h_coll ##
+_httpiconhcoll_ [l=ky] {_httpimg_/ky/h\_coll.gif}
+_widthhcoll_ [l=ky] {200}
+_heighthcoll_ [l=ky] {57}
+
+## "Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐ¹Ð»ÐµÑ" ## green_title ## h_people ##
+_httpiconhpeople_ [l=ky] {_httpimg_/ky/h\_people.gif}
+_widthhpeople_ [l=ky] {200}
+_heighthpeople_ [l=ky] {57}
+
+## "ÐºÑÑÐºÐ°ÑÑÑÑÐ»Ð°Ñ" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=ky] {_httpimg_/ky/h\_acro.gif}
+_widthhacronym_ [l=ky] {200}
+_heighthacronym_ [l=ky] {57}
+
+## "ÑÑÐ°Ð·Ð°Ð»Ð°Ñ" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=ky] {_httpimg_/ky/h\_phrse.gif}
+_widthhphrse_ [l=ky] {200}
+_heighthphrse_ [l=ky] {57}
+
+## "ÑÒ¯ÑÓ©ÑÑÒ¯Ð»Ó©Ñ" ## green_title ## h_artist ##
+_httpiconhartist_ [l=ky] {_httpimg_/ky/h\_artist.gif}
+_widthhartist_ [l=ky] {200}
+_heighthartist_ [l=ky] {57}
+
+## "ÐŒÐ°Ò£ÑÐ·ÐŽÑÑ ÑÓ©Ð·ÐŽÓ©Ñ" ## green_title ## h_kw ##
+_httpiconhkw_ [l=ky] {_httpimg_/ky/h\_kw.gif}
+_widthhkw_ [l=ky] {200}
+_heighthkw_ [l=ky] {57}
+
+## "ÑÐŸÐŒÐŽÐŸÑ" ## green_title ## h_vol ##
+_httpiconhvol_ [l=ky] {_httpimg_/ky/h\_vol.gif}
+_widthhvol_ [l=ky] {200}
+_heighthvol_ [l=ky] {57}
+
+## "Ó©Ð»ÐºÓ©Ð»Ó©Ñ" ## green_title ## h_count ##
+_httpiconhcount_ [l=ky] {_httpimg_/ky/h\_count.gif}
+_widthhcount_ [l=ky] {200}
+_heighthcount_ [l=ky] {57}
+
+## "Ð¶Ð°Ð·ÑÑÐ»Ð°Ñ" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=ky] {_httpimg_/ky/h\_capt.gif}
+_widthhcapt_ [l=ky] {200}
+_heighthcapt_ [l=ky] {57}
+
+
+## "Ð£ÐÐÐÐ¢Ð«ÐÐ¡Ð«ÐÐÐ«??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=ky] {_httpimg_/ky/contof.gif}
+_httpiconconton_ [l=ky] {_httpimg_/ky/conton.gif}
+
+## "ÐÐÐÐ ÐÐ«Ð\nÐ¢ÐÐÐ¡Ð¢" ## document_button ## eallt ##
+_httpiconealltof_ [l=ky] {_httpimg_/ky/ealltof.gif}
+_httpiconeallton_ [l=ky] {_httpimg_/ky/eallton.gif}
+
+## "ÐÐÐÐ£Ð£" ## document_button ## econc ##
+_httpiconeconcof_ [l=ky] {_httpimg_/ky/econcof.gif}
+_httpiconeconcon_ [l=ky] {_httpimg_/ky/econcon.gif}
+
+## "ÐÐÒ¢Ð«\nÐ¢ÐÐ ÐÐÐ" ## document_button ## edtch ##
+_httpiconedtchof_ [l=ky] {_httpimg_/ky/edtchof.gif}
+_httpiconedtchon_ [l=ky] {_httpimg_/ky/edtchon.gif}
+
+## "ÐÐ§Ð£Ð£" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=ky] {_httpimg_/ky/eexpcof.gif}
+_httpiconeexpcon_ [l=ky] {_httpimg_/ky/eexpcon.gif}
+
+## "ÐÐÐÐ£Ð£" ## document_button ## etsec ##
+_httpiconetsecof_ [l=ky] {_httpimg_/ky/etsecof.gif}
+_httpiconetsecon_ [l=ky] {_httpimg_/ky/etsecon.gif}
+
+## "ÐÓšÐÒ®Ò®" ## document_button ## ehl ##
+_httpiconehlof_ [l=ky] {_httpimg_/ky/ehlof.gif}
+_httpiconehlon_ [l=ky] {_httpimg_/ky/ehlon.gif}
+
+## "ÐÓšÐÐÓšÓš" ## document_button ## enhl ##
+_httpiconenhlof_ [l=ky] {_httpimg_/ky/enhlof.gif}
+_httpiconenhlon_ [l=ky] {_httpimg_/ky/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=ky] {_If_(_thislast_, ÐœÐ°ÑÑÐ¹Ð¶Ð°Ð»Ð°ÑÑ _thisfirst_ - _thislast_ ÑÑÑÐŸÐŸ Ð±ÐŸÑÐœÑÐ° ÐžÐ·ÐŽÓ©Ó©: _cgiargq_,ÑÑÑÐŸÐŸ Ð±ÐŸÑÐœÑÐ° ÑÐ»Ð³ÐŸÐŸÐ»ÐŸÑ Ð¶ÐŸÐº _cgiargq_)}
+_textnoquerytitle_ [l=ky] {ÐÐµÑÑÐž ÐžÐ·ÐŽÓ©Ó©}
+
+_texticonthispage_ [l=ky] {ÐžÐ·ÐŽÓ©Ó©}
+_textsome_ [l=ky] {ÐºÐ°Ð¹ÑÑ Ð±ÐžÑ}
+_textall_ [l=ky] {Ð±Ð°Ð°ÑÐŽÑÐ³Ñ}
+_textboolean_ [l=ky] {Ð»ÐŸÐ³ÐžÐºÐ°Ð»ÑÐº}
+_textranked_ [l=ky] {ÐžÑÐµÑÑÐµÐ»Ð³ÐµÐœ}
+_textnatural_ [l=ky] {ÐºÐ°ÐŽÐžÐŒÐºÐž}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=ky] {}
+_texticonsearchhistorybar_ [l=ky] {ÑÐ°ÑÑÑ
+ÑÑ ÐžÐ·ÐŽÓ©Ó©}
+
+_textifeellucky_ [l=ky] {ÐÐŸÐ»ÑÐŒ Ð±ÐŸÐ»ÐŽÑ!}
+
+#alt text for query buttons
+_textusequery_ [l=ky] {ÑÑÑÐŸÐŸ Ð±ÐµÑÒ¯Ò¯}
+_textfreqmsg1_ [l=ky] {ÐÐµÐ·ÐŽÐµÑÒ¯Ò¯ ÑÐ°ÐœÑ:}
+_textpostprocess_ [l=ky] {_If_(_quotedquery_,<br><i>ÐžÐ·ÐŽÓ©Ó©ÐœÒ¯Ðœ ÐºÐžÐ¹ÐžÐœÐºÐž ÐžÑÑÐµÐ¿ ÑÑÐ³Ð°ÑÑÐ»ÑÑÑÑ _quotedquery_</i>
+)}
+_textinvalidquery_ [l=ky] {Ð¡ÑÑÐŸÐŸÐœÑÐœ ÑÐžÐœÑÐ°ÐºÑÐžÑÐž ÑÑÑÑÐ° ÑÐŒÐµÑ}
+
+_textmorethan_ [l=ky] {ÐÑÐœÐŽÐ°Ðœ Ð°ÑÑÑÐº}
+_textapprox_ [l=ky] {ÐÓ©ÐœÒ¯ÐœÐŽÓ©}
+_textnodocs_ [l=ky] {Ð¡ÑÑÐŸÐŸ Ð±ÐŸÑÐœÑÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ ÑÐ°Ð±ÑÐ»Ð³Ð°Ðœ Ð¶ÐŸÐº}
+_text1doc_ [l=ky] {1 ÐŽÐŸÐºÑÐŒÐµÐœÑ ÑÑÑÐŸÐŸÐ³ÐŸ ÑÑÑÑÐ° ÐºÐµÐ»ÐŽÐž.}
+_textlotsdocs_ [l=ky] {ÑÑÑÐŸÐŸÐ³ÐŸ ÑÑÑÑÐ° ÐºÐµÐ»Ð³ÐµÐœ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ }
+_textmatches_ [l=ky] {ÐÐ°ÑÑÐ¹Ð¶Ð°Ð»Ð°Ñ}
+_textbeginsearch_ [l=ky] {ÐÐ·ÐŽÐµÐ¿ Ð±Ð°ÑÑÐŸÐŸ}
+_textrunquery_ [l=ky] {Ð¡ÑÑÐ°ÐœÑÐŒÐŽÑ Ð°ÑÐºÐ°ÑÑÑ}
+_textclearform_ [l=ky] {Ð€ÐŸÑÐŒÐ°ÐœÑ ÑÐ°Ð·Ð°Ð»ÐŸÐŸ}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=ky] {Ð¡Ó©Ð·ÐŽÓ©Ñ Ð¶Ðµ ÑÑÐ°Ð·Ð°Ð»Ð°Ñ}
+_textinfield_ [l=ky] {... Ð°ÑÐœÑÐ°}
+_textfoldstem_ [l=ky] {(ÑÓ©Ð·, ÑÑÐ°Ð·Ð°)}
+
+_textadvquery_ [l=ky] {ÐÐµ Ð±ÐŸÐ»ÑÐŸ ÑÑÑÐŸÐŸ ÐŽÐŸÐºÑÐŒÐµÑÑÐµÑÐžÐœ ÐºÐžÑÐ³ÐžÐ·ÐžÒ£ÐžÐ·:}
+_textallfields_ [l=ky] {Ð±Ð°Ð°ÑÐŽÑÐº Ð°ÑÐœÑÑÐ°Ñ}
+_texttextonly_ [l=ky] {ÑÐµÑÐºÑ Ð³Ð°ÐœÐ°}
+_textand_ [l=ky] {Ð¶Ð°ÐœÐ°}
+_textor_ [l=ky] {Ð¶Ðµ}
+_textandnot_ [l=ky] {Ð¶Ð°ÐœÐ° ÑÐŒÐµÑ}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=ky] {ÐÐ·ÐŽÓ©Ó©  _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, ÐŽÐµÒ£Ð³ÐµÐ¹ _gselection_ Ð±ÐŸÑÐœÑÐ°) _If_(_nselection_, ÑÐžÐ»ÐžÐœÐŽÐµ  _nselection_  ),ÑÓ©Ð·ÐŽÓ©ÑÐŽÓ©Ðœ _querytypeselection_ ÑÑÑÐ³Ð°Ðœ}
+
+_textadvancedsearch_ [l=ky] {ÐÐ·ÐŽÓ©Ó© _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, ÐŽÐµÒ£Ð³ÐµÐ¹ _gselection_ Ð±ÐŸÑÐœÑÐ°)_If_(_nselection_, ÑÐžÐ»ÐžÐœÐŽÐµ_nselection_ )  ÑÑÑÐŸÐŸÐœÑ  _querytypeselection_ ÐºÐŸÐ»ÐŽÐŸÐœÑÐ¿}
+
+_textformsimplesearch_ [l=ky] {ÐÐŸÑÐœÑÐ° ÐžÐ·ÐŽÓ©Ó© _If_(_jselection_, _jselection_) _If_(_gformselection_, ÐŽÐµÒ£Ð³ÐµÐ¹ _gformselection_ Ð±ÐŸÑÐœÑÐ°)_If_(_nselection_, ÑÐžÐ»ÐžÐœÐŽÐµ _nselection_ ), Ð±Ð°Ñ Ð¶ÐµÑÐž _formquerytypeselection_}
+
+_textformadvancedsearch_ [l=ky] {ÐÐ·ÐŽÓ©Ó© _If_(_jselection_,_jselection_) _If_(_gformselection_, ÐŽÐµÒ£Ð³ÐµÐ¹ _gformselection_ Ð±ÐŸÑÐœÑÐ°)_If_(_nselection_, ÑÐžÐ»ÐžÐœÐŽÐµ _nselection_ ) 
+Ð¶Ð°ÐœÐ° ÐžÑÐµÑÐž Ð±ÐŸÑÐœÑÐ° ÑÐžÐ·Ò¯Ò¯ _formquerytypeselection_}
+
+
+_textnojsformwarning_ [l=ky] {ÐÐ°ÑÐ°: Javascript ÑÐžÐ·ÐŽÐžÐœ Ð±ÑÐ°ÑÐ·ÐµÑÐŽÐµ Ó©ÑÒ¯ÑÒ¯Ð»Ð³Ó©Ðœ . <br>ÐÐ·ÐŽÓ©Ó© ÑÐŸÑÐŒÐ°ÑÑÐœ ÐºÐŸÐ»ÐŽÐŸÐœÑÑ Ò¯ÑÒ¯Ðœ Ð°ÐœÑ Ð°ÑÑÑ ÐºÐµÑÐµÐº. }
+_textdatesearch_ [l=ky] {ÐÑÐ» ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ Ð±ÐµÐ»Ð³ÐžÐ»Ò¯Ò¯ Ð±ÐžÑ ÑÐ±Ð°ÐºÑÑ Ð°ÑÐ°Ð»ÑÐ³Ñ Ð±ÐŸÑÐœÑÐ° ÐžÐ·ÐŽÓ©Ó© ÐºÐ°ÑÐ°ÑÑ ÐœÐ°ÐºÑÑ ÐŽÐ°ÑÐ° Ð±ÐŸÑÐœÑÐ° ÐžÐ·ÐŽÐµÐ¿ ÑÐ°Ð±Ð° Ð°Ð»Ð°ÑÑÐ·.}
+_textstartdate_ [l=ky] {ÐÐ°ÑÐºÑ (Ð¶Ðµ ÐœÐ°ÐºÑÐ°) ÐŽÐ°ÑÐ°}
+_textenddate_ [l=ky] {ÐÐºÑÑÐºÑ ÐŽÐ°ÑÐ°:}
+_textbc_ [l=ky] {Ð±.Ñ.Ñ.}
+_textad_ [l=ky] {Ð±.Ñ.}
+_textexplaineras_ [l=ky] {Ð.Ñ. Ð¶Ð°ÐœÐ° Ð±.Ñ. ÑÐµÐ¹ÐžÐœ ÑÐµÑÐŒÐžÐœÐŽÐµÑÐž âÐ±ÐžÐ·ÐŽÐžÐœ ÑÑÐ°Ð±ÑÐ·â Ð¶Ð°ÐœÐ° âÐ±ÐžÐ·ÐŽÐžÐœ ÑÑÐ°Ð±ÑÐ·Ð³Ð° ÑÐµÐ¹ÐžÐœâ ÐŽÐµÐ³ÐµÐœÐŽÐž Ð±ÐžÐ»ÐŽÐžÑÐµÑ}
+
+_textstemon_ [l=ky] {Ð¶Ó©ÐœÐŽÓ©ÐŒÓ©Ð»Ó©ÑÐŽÒ¯Ðœ Ð¶Ð°Ð»Ð³ÐŸÐŸÐ»ÐŸÑÑÑÑÐ·}
+
+_textsearchhistory_ [l=ky] {Ð¡ÑÑÐ°Ð»Ð³Ð°Ðœ ÑÐ°ÑÑÑ
+}
+
+#text macros for search history
+_textnohistory_ [l=ky] {ÐÐ·ÑÑ ÐžÐ·ÐŽÓ©Ó© ÑÐ°ÑÑÑ
+Ñ Ð¶ÐŸÐº}
+_texthresult_ [l=ky] {ÐºÐµÐ·ÐŽÐµÑÒ¯Ò¯}
+_texthresults_ [l=ky] {ÐºÐµÐ·ÐŽÐµÑÒ¯Ò¯Ð»Ó©Ñ}
+_texthallwords_ [l=ky] {Ð±Ð°Ð°ÑÐŽÑÐº ÑÓ©Ð·ÐŽÓ©Ñ}
+_texthsomewords_ [l=ky] {ÐºÑÑ Ð±ÐžÑ ÑÓ©Ð·ÐŽÓ©Ñ}
+_texthboolean_ [l=ky] {Ð»ÐŸÐ³ÐžÐºÐ°Ð»ÑÐº}
+_texthranked_ [l=ky] {ÐžÑÐµÑÑÐµÐ»Ð³ÐµÐœ}
+_texthcaseon_ [l=ky] {ÑÐµÐ³ÐžÑÑÑÐŽÐž ÑÑÐµÐ¿ÐºÐµ Ð°Ð»ÑÐ¿}
+_texthcaseoff_ [l=ky] {ÑÐµÐ³ÐžÑÑÑÐŽÐž ÑÑÐµÐ¿ÑÐµÐ±ÐµÐ¹}
+_texthstemon_ [l=ky] {ÐÓ©ÐœÐŽÓ©ÐŒÓ©Ð»Ó©ÑÐŽÒ¯Ðœ Ð¶Ð°Ð»Ð³ÐŸÐŸÐ»ÐŸÑÑ ÐŒÐµÐœÐµÐœ}
+_texthstemoff_ [l=ky] {Ð¶Ó©ÐœÐŽÓ©ÐŒÓ©Ð»Ó©ÑÐŽÒ¯Ðœ Ð¶Ð°Ð»Ð³ÐŸÐŸÐ»ÐŸÑÑÑÑÐ·}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐžÐ·ÐŽÓ©Ó©" ## green_title ## h_search ##
+_httpiconhsearch_ [l=ky] {_httpimg_/ky/h\_search.gif}
+_widthhsearch_ [l=ky] {200}
+_heighthsearch_ [l=ky] {57}
+
+## "ÐœÐ°ÑÑÐ¹Ð¶Ð°" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=ky] {_httpimg_/ky/qryresb.gif}
+_widthqryresb_ [l=ky] {_pagewidth_}
+_heightqryresb_ [l=ky] {17}
+
+## "ÑÐ°ÑÑÑ
+" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=ky] {_httpimg_/ky/schhistb.gif}
+_widthsrchhistb_ [l=ky] {_pagewidth_}
+_heightsrchhistb_ [l=ky] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=ky] {Ð¢Ò¯Ð·Ó©ÑÒ¯Ò¯ÐœÒ¯ ÑÓ©ÐŒÓ©ÐœÐºÒ¯ÐŽÓ©Ð¹ ÐºÐ°Ð»ÑÐ¿ÑÐ°ÑÑÑÑÑÐ»Ð³Ð°Ðœ. ÐÑÐ°ÑÐ·ÐµÑÐŽÐžÐœ "ÐºÐ°Ð¹ÑÑÑ" ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ ÐºÐŸÐ»ÐŽÐŸÐœÐ±ÐŸÐ³ÑÐ»Ð°, Ð°ÐœÑÐœ ÐŸÑÐŽÑÐœÐ° Ò¯ÑÑÒ¯Ò£ÐºÒ¯ ÐºÐœÐŸÐ¿ÐºÐ°Ð»Ð°ÑÐŽÑÐœ Ð±ÐžÑÐžÐœ Ð±Ð°ÑÐºÑÐ»Ð°.}
+_textsetprefs_ [l=ky] {ÑÒ¯Ð·Ó©ÑÒ¯Ð¿ ÐºÐŸÑÑ }
+_textsearchprefs_ [l=ky] {ÐÐ·ÐŽÓ©Ó©ÐœÒ¯Ò¯ ÑÒ¯Ð·Ó©ÑÒ¯Ò¯  }
+_textcollectionprefs_ [l=ky] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÑÒ¯Ð·Ó©ÑÒ¯Ò¯Ð»Ó©Ñ}
+_textpresentationprefs_ [l=ky] {ÐÐœÑÐµÑÑÐµÐ¹ÑÑÐž ÑÒ¯Ð·Ó©ÑÒ¯Ò¯Ð»Ó©ÑÒ¯}
+_textpreferences_ [l=ky] {Ð¢Ò¯Ð·Ó©ÑÒ¯Ò¯Ð»Ó©Ñ}
+_textcasediffs_ [l=ky] {Ð ÐµÐ³ÐžÑÑÑÐ»ÐµÑ:}
+_textignorecase_ [l=ky] {ÑÐµÐ³ÐžÑÑÑÐŽÐž ÑÑÐµÐ¿ÑÐµÐ±ÐµÐ¹}
+_textmatchcase_ [l=ky] {Ð¶ÐŸÐ³ÐŸÑÐºÑ Ð¶Ð°ÐœÐ° ÑÓ©ÐŒÓ©ÐœÐºÒ¯ ÑÐµÐ³ÐžÑÑÑÐ»ÐµÑÐŽÐž ÐºÐŸÐ»ÐŽÐŸÐœÑÑ}
+_textwordends_ [l=ky] {Ð¡Ó©Ð·ÐŽÓ©ÑÐŽÒ¯Ðœ Ð¶Ð°Ð»Ð³ÐŸÐŸÐ»ÐŸÑÑ:}
+_textstem_ [l=ky] {ÑÓ©Ð·ÐŽÓ©ÑÐŽÒ¯Ðœ Ð¶Ð°Ð»Ð³ÐŸÐŸÐ»ÐŸÑÑÑÑÐ·}
+_textnostem_ [l=ky] {ÑÓ©Ð·ÐŽÓ©Ñ ÑÐŸÐ»ÑÐ³Ñ ÐŒÐµÐœÐµÐœ ÑÑÑÐ°Ð° ÐºÐµÐ»Ò¯Ò¯}
+_textprefop_ [l=ky] {Return up to _maxdocoption_ hits with _hitsperpageoption_ hits per page.}
+_textextlink_ [l=ky] {Web-ÑÐžÐœ ÑÑÑÑÐºÑ Ð±ÐµÑÑÐµÑÐžÐœÐµ ÑÑÐ³ÑÑ}
+_textintlink_ [l=ky] {ÐÑÐ» ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð°Ð»ÑÐœÐ³Ð°Ðœ Ð¶ÐµÑ:}
+_textlanguage_ [l=ky] {ÐÐœÑÐµÑÑÐµÐ¹Ñ ÑÐžÐ»Ðž}
+_textencoding_ [l=ky] {ÐÐŸÐŽÐžÑÐŸÐ²ÐºÐ°:}
+_textformat_ [l=ky] {ÐÐœÑÐµÑÑÐµÐ¹ÑÑÐžÐœ ÑÐŸÑÐŒÐ°ÑÑ:}
+_textall_ [l=ky] {Ð±Ð°Ð°ÑÐŽÑÐ³Ñ}
+_textquerymode_ [l=ky] {Ð¡ÑÑÐŸÐŸÐœÑÐœ ÑÐžÐ±Ðž: }
+_textsimplemode_ [l=ky] {ÑÑÑÐŸÐŸÐœÑÐœ Ð¶Ó©ÐœÓ©ÐºÓ©Ð¹ ÑÒ¯ÑÒ¯}
+_textadvancedmode_ [l=ky] {ÑÑÑÐŸÐŸÐœÑÐœ ÑÐŸÒ£ÐŸÐ¹ÑÑÐ»Ð³Ð°Ðœ ÑÒ¯ÑÒ¯ (! (Ð­ÐÐÐ¡) , & (ÐÐÐÐ), | (ÐÐ) Ð¶Ð°ÐœÐ° ÐºÐ°ÑÐ°Ð°Ð»Ð°Ñ) ÑÑÑÐ»Ó©ÑÒ¯ ÐŒÐµÐœÐµÐœ Ð»ÐŸÐ³ÐžÐºÐ°Ð»ÑÐº ÐžÐ·ÐŽÓ©Ó©Ð³Ó© ÑÑÑÐºÑÐ°Ñ Ð±ÐµÑÐžÐ»Ð³ÐµÐœ}
+_textlinkinterm_ [l=ky] {Ð°ÑÐ°ÐŽÐ°Ð³Ñ Ð±ÐµÑ Ð°ÑÐºÑÐ»ÑÑ}
+_textlinkdirect_ [l=ky] {ÑÐžÑÐºÐµÐ»ÐžÐ¿ Ó©ÑÒ¯Ò¯}
+_textdigitlib_ [l=ky] {ÑÐ»ÐµÐºÑÑÐŸÐœÐŽÑÐº ÐºÐžÑÐµÐ¿ÐºÐ°ÐœÐ°}
+_textweb_ [l=ky] {Web}
+_textgraphical_ [l=ky] {ÐÑÐ°ÑÐžÐºÐ°Ð»ÑÐº}
+_texttextual_ [l=ky] {Ð¢ÐµÐºÑÑÑÐžÐº}
+_textcollectionoption_ [l=ky] {<p>
+ÐÑÐºÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ:
+<br>}
+
+_textrelateddocdisplay_ [l=ky] {ÐŸÐºÑÐŸÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐž ÐºÓ©ÑÑÓ©ÑÒ¯Ò¯}
+_textsearchhistory_ [l=ky] {ÐÐ·ÐŽÓ©Ó© ÑÐ°ÑÑÑ
+Ñ: }
+_textnohistory_ [l=ky] {Ð¢Ð°ÑÑÑ
+ÑÑ ÐžÐ·ÐŽÐµÐ±Ó©Ó©}
+_texthistorydisplay_ [l=ky] {ÑÑÑÐŸÐŸ ÑÐ°ÑÑÑ
+ÑÐœ _historynumrecords_ ÐºÓ©ÑÑÓ©ÑÒ¯Ò¯}
+_textnohistorydisplay_ [l=ky] {ÑÑÑÐŸÐŸ ÑÐ°ÑÑÑ
+ÑÐœ ÐºÓ©ÑÑÓ©ÑÐ¿Ó©Ó©}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=ky] {Ð€ÐŸÑÐŒÐ°ÐœÑ ÐžÐ·ÐŽÓ©Ó©:}
+_textplainsearch_ [l=ky] {ÐÓ©ÐœÓ©ÐºÓ©Ð¹ ÐžÐ·ÐŽÓ©Ó©:}
+_textqueryboxsize_ [l=ky] {ÐÐ·ÐŽÓ©Ó©Ð³Ó© Ð°ÑÐœÐ°Ð»Ð³Ð°Ðœ ÑÐµÑÐµÐ·Ðµ Ó©Ð»ÑÓ©ÐŒÒ¯:}
+_textregbox_ [l=ky] {ÐžÐ·ÐŽÓ©Ó©Ð³Ó© Ð°ÑÐœÐ°Ð»Ð³Ð°Ðœ ÐºÓ©ÐœÒ¯ÐºÐºÓ©Ðœ ÑÐµÑÐµÐ·Ðµ}
+_textbigbox_ [l=ky] {ÐžÐ·ÐŽÓ©Ó©Ð³Ó© Ð°ÑÐœÐ°Ð»Ð³Ð°Ðœ ÑÐŸÒ£ ÑÐµÑÐµÐ·Ðµ}
+_textformtype_ [l=ky] {Ð€ÐŸÑÐŒÐ°ÐœÑÐœ ÑÐžÐ±Ðž:}
+_textsimple_ [l=ky] {Ð¶Ó©ÐœÓ©ÐºÓ©Ð¹}
+_textadvanced_ [l=ky] {ÑÐŸÒ£ÐŸÐ¹ÑÑÐ»Ð³Ð°Ðœ}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=ky] {ÐŒÐµÐœÐµÐœ}
+_textfields_ [l=ky] {Ð°ÑÐœÑ}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÑÒ¯Ð·Ó©ÑÒ¯Ò¯Ð»Ó©Ñ" ## green_title ## h_pref ##
+_httpiconhpref_ [l=ky] {_httpimg_/ky/h\_pref.gif}
+_widthhpref_ [l=ky] {200}
+_heighthpref_ [l=ky] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=ky] {ÐÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐž  ÑÐŸÑÑÑÐŸÐŸ}
+_textalsoshowing_ [l=ky] {ÐŽÐ°Ð³Ñ ÐºÐ°ÑÐŸÐŸ}
+_textwith_ [l=ky] {ÑÒ£ ÑÐŸÒ£Ñ ÐŒÐµÐœÐµÐœ}
+_textdocsperpage_ [l=ky] {Ð±ÐµÑÑÐµÐ³Ðž ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐžÐœ ÑÐ°ÐœÑ}
+
+_textfilterby_ [l=ky] {ÐÐŸÐºÑÐŒÐµÐœÑÑÐžÐœ ÐŒÐ°Ð·ÐŒÑÐœÑÐœ Ð°Ð»ÑÑ}
+_textall_ [l=ky] {Ð±Ð°Ð°ÑÐŽÑÐ³Ñ}
+_textany_ [l=ky] {Ð°ÐœÐŽÐ°Ðœ Ð±Ð°ÑÐºÐ°}
+_textwords_ [l=ky] {ÑÓ©Ð·ÐŽÓ©Ñ Ð°ÑÐºÑÐ»ÑÑ }
+_textleaveblank_ [l=ky] {Ð±Ð°Ð°ÑÐŽÑÐº ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐž Ð°Ð»ÑÑ Ò¯ÑÒ¯Ðœ Ð±ÑÐ» ÑÐµÑÑÐž ÐºÐ°Ð»ÑÑÑÑÒ£ÑÐ·}
+
+_browsebuttontext_ [l=ky] {"ÐÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐž ÑÐŸÑÑÑÐŸÐŸ"}
+
+_nodata_ [l=ky] {<i>ÐŽÐ°ÑÐ°ÑÑ Ð¶ÐŸÐº</i>}
+_docs_ [l=ky] {ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=ky] {ÐÐ°ÑÐŽÐ°ÐŒ}
+_textSearchshort_ [l=ky] {Ð°ÑÐ°Ð¹ÑÐœ Ð°ÑÐœÐ°Ð»Ð³Ð°Ðœ ÑÐµÑÐŒÐžÐœÐŽÐµÑ Ð±ÐŸÑÐœÑÐ° ÐžÐ·ÐŽÓ©Ó©}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=ky] {ÑÐžÐ·ÐŒÐµÐ»ÐµÑ (Ð-Ð¯)  Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textCreatorshort_ [l=ky] {Ð°Ð²ÑÐŸÑÐ»ÐŸÑ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textSubjectshort_ [l=ky] {ÐÐžÑÑÐžÐ¿Ð»ÐžÐœÐ°Ð»Ð°Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textDescriptionshort_ [l=ky] {Ð±Ð°ÑÐœÐŽÐ°ÐŒÐŸÐŸ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textPublishershort_ [l=ky] {Ð±Ð°ÑÑÐ¿ ÑÑÐ³Ð°ÑÑÑÑÑÐ»Ð°Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textContributorshort_ [l=ky] {ÑÐŒÐ³ÐµÐºÑÐµÑÑÐµÑ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textDateshort_ [l=ky] {ÐŽÐ°ÑÐ°Ð»Ð°Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textTypeshort_ [l=ky] {ÑÐžÐ¿ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textFormatshort_ [l=ky] {ÑÐŸÑÐŒÐ°Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textIdentifiershort_ [l=ky] {Ð±ÐµÐ»Ð³ÐžÐ»ÐµÑ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textSourceshort_ [l=ky] {ÑÐ°Ð¹Ð»ÐŽÑÐœ Ð°ÑÑ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textLanguageshort_ [l=ky] {ÑÐžÐ»ÐŽÐµÑ  Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textRelationshort_ [l=ky] {ÐŒÐ°ÐŒÐžÐ»ÐµÐ»ÐµÑ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textCoverageshort_ [l=ky] {ÐŽÐ°ÑÐ°Ð»Ð°Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textRightsshort_ [l=ky] {ÑÐºÑÐºÑÐ°Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+
+_textSeriesshort_ [l=ky] {cÐµÑÐžÑÐ»Ð°Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textToshort_ [l=ky] {ÐºÐžÐŒÐ³Ðµ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textFromshort_ [l=ky] {"ÐºÐžÐŒÐŽÐµÐœ"  Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textBrowseshort_ [l=ky] {Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑ ÐºÓ©ÑÒ¯Ò¯}
+_textOrganizationshort_ [l=ky] {ÑÑÐŒÐŽÐ°Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textHowtoshort_ [l=ky] {Ð°ÑÐ°ÐºÐµÑÑÐžÐ»ÐµÑ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textTopicshort_ [l=ky] {ÑÐµÐŒÐ°Ð»Ð°Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textPeopleshort_ [l=ky] {Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐ¹Ð»ÐµÑ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textAcronymshort_ [l=ky] {ÐºÑÑÐºÐ°ÑÑÑÑÐ»Ð°Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ}
+_textPhraseshort_ [l=ky] {ÑÑÐ°Ð·Ð°Ð»Ð°Ñ  Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textArtistshort_ [l=ky] {ÑÒ¯ÑÓ©ÑÑÒ¯Ð»Ó©Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ}
+_textKeywordshort_ [l=ky] {ÐŒÐ°Ò£ÑÐ· ÑÓ©Ð·ÐŽÓ©Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textVolumeshort_ [l=ky] {ÑÐŸÐŒ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textCountriesshort_ [l=ky] {Ó©Ð»ÐºÓ©Ð»Ó©Ñ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÒ¯Ò¯}
+_textdefaultshorttext_ [l=ky] {Ð±ÐµÐ»Ð³ÐžÑÐžÐ· ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÑ}
+
+_textSearchlong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÐžÐ·ÐŽÓ©Ó©ÐœÒ¯ Ð°ÑÐ°Ð¹ÑÐœ Ð°ÑÐœÐ°Ð»Ð³Ð°Ðœ ÑÐµÑÐŒÐžÐœÐŽÐµÑ Ð±ÐŸÑÐœÑÐ°</i> ÐžÐ·ÐŽÓ©Ó© Ð±ÐµÑÐžÐœÐµÐœ Ð¶Ò¯ÑÐ³Ò¯Ð·Ó© Ð°Ð»Ð°ÑÑÐ·. ÐÑÐ» Ð±ÐµÑ ÑÐžÐ· ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŒÐµÐœÐµÐœ ÐžÐ·ÐŽÓ©Ó©ÐœÒ¯ Ð±Ð°ÑÑÐ°Ð³Ð°ÐœÐŽÐ° ÑÒ¯Ð¹Ò¯Ð»Ò¯Ò¯ Ð±ÐŸÐ»ÐŸÑ Ð¶Ð°ÐœÐ° Ð°Ð³Ð° Ð°Ñ ÐºÐ°Ð¹ÑÑ Ð±ÐµÑÑÐµÑÐŽÐµÐœ <i>ÐžÐ·ÐŽÓ©Ó© ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ¿ ÐºÐ°Ð¹ÑÑÐ¿ ÐºÐµÐ»Ò¯Ò¯Ð³Ó© Ð±ÐŸÐ»ÐŸÑ</i>.}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÐžÐ·ÐŒÐµÐ»ÐµÑ (Ð-Ð¯)</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ¿ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐžÐœ Ð±Ð°Ñ-Ð°ÑÑÐ°ÑÑ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœÐŽÑ <i>Ð°Ð»Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÑÐžÐ· Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÐœ Ð°ÑÑÐ°ÑÑÐœ Ð°Ð»ÑÐ°Ð²ÐžÑ Ð±ÐŸÑÐœÑÐ° ÐºÐžÑÐµÐ¿ÑÐµÑ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·. }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=ky] {<p>Ð¡ÐžÐ· Ð°Ð²ÑÐŸÑÐ»ÐŸÑ Ð-Ð¯ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð°Ð²ÑÐŸÑÐ»ÐŸÑ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœÐŽÑ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÑÐžÐ· Ð°Ð²ÑÐŸÑÐ»ÐŸÑ ÑÐ°ÐŒÐžÐ»ÐžÑÐ»Ð°ÑÑ Ð±ÐŸÑÐœÑÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐžÐœ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·. }
+
+_textSubjectlong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÐŽÐžÑÑÐžÐ¿Ð»ÐžÐœÐ°</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÓ© Ð°Ð»Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐžÐœ ÐŽÐžÑÑÐžÐ¿Ð»ÐžÐœÐ°Ð»Ð°ÑÑ Ð¶Ó©ÐœÒ¯ÐœÐŽÓ© ÐŒÐ°Ð°Ð»ÑÐŒÐ°Ñ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·.}
+
+_textDescriptionlong_ [l=ky] {<p>Ð¡ÐžÐ· <i>Ð±Ð°ÑÐœÐŽÐ°ÐŒÐŸÐŸ ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÐœ Ð±Ð°ÑÐœÐŽÐ°ÐŒÐ°ÑÑ</i> Ð¶Ó©ÐœÒ¯ÐœÐŽÓ© ÐŒÐ°Ð°Ð»ÑÐŒÐ°Ñ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·.   }
+
+_textPublisherlong_ [l=ky] {<p>Ð¡ÐžÐ· <i>Ð±Ð°ÑÑÐ¿ ÑÑÐ³Ð°ÑÑÑÑÑÐ»Ð°Ñ</i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð±Ð°ÑÑÐ¿ ÑÑÐ³Ð°ÑÑÑÑÑÐ»Ð°Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°Ð³Ñ Ð±Ð°ÑÑÐ¿ ÑÑÐ³Ð°ÑÑÑÑÑÐ»Ð°Ñ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·.  }
+
+_textContributorlong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÐŒÐ³ÐµÐºÑÐµÑÑÐµÑÐž</i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ¿.
+ <i>Ð­ÐŒÐ³ÐµÐºÑÐµÑÑÐµÑ</i> Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð°Ð»ÑÐŒÐ°Ñ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·ÐŽÐ°Ñ.  }
+
+_textDatelong_ [l=ky] {<p>Ð¡ÐžÐ· ÐŽÐ°ÑÐ° <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ </i>Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÐœ Ð±Ð°ÑÑÐ»ÑÐ¿ ÑÑÐºÐºÐ°Ðœ <i>ÐŽÐ°ÑÐ°Ð»Ð°ÑÑ</i> Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð°Ð»ÑÐŒÐ°Ñ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·ÐŽÐ°Ñ. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ° ÑÐžÐ· Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑ Ñ
+ÑÐŸÐœÐŸÐ»ÐŸÐ³ÐžÑÐ»ÑÐº ÑÐ°ÑÑÐžÐ¿ÐºÐµ Ð°Ð»ÑÐ¿ ÐºÐµÐ»ÐµÐ»Ð°ÑÑÐ·.  }
+
+_textTypelong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÐžÐ¿</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ<i>ÑÐžÐ¿ÑÐµÑ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœÐŽÑ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÑÐžÐ· ÑÐžÐ¿ÑÐµÑ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·. }
+
+_textFormatlong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÐŸÑÐŒÐ°Ñ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÐœ ÑÐŸÑÐŒÐ°ÑÑ</i> Ð¶Ó©ÐœÒ¯ÐœÐŽÓ© ÐŒÐ°Ð°Ð»ÑÐŒÐ°Ñ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·.   }
+
+_textIdentifierlong_ [l=ky] {<p>Ð¡ÐžÐ· <i>Ð±ÐµÐ»Ð³ÐžÐ»ÐµÑ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð±ÐµÐ»Ð³ÐžÐ»ÐµÑ (ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÐ»ÐŸÑ) Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°Ð³Ñ Ð±ÐµÐ»Ð³ÐžÐ»ÐµÑ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·.  }
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÐ°Ð¹Ð»ÐŽÑÐœ Ð°ÑÑ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐ³Ð° Ó©ÑÓ© Ð°Ð»Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÑÐ°Ð¹Ð»ÐŽÑÐœ Ð°ÑÑÐ°ÑÑÐœ ÐžÑÐµÑÑÐµÐ¹ Ð°Ð»Ð°ÑÑÐ·. }
+
+_textLanguagelong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÐžÐ»ÐŽÐµÑ</i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>ÑÐžÐ»ÐŽÐµÑÐž Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°Ð³Ñ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÐœ ÑÐžÐ»ÐŽÐµÑÐž Ð±ÐŸÑÐœÑÐ° ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð· Ð¶Ð°ÐœÐ° ÑÐŸÑÑÑÐŸÐ¹ Ð°Ð»Ð°ÑÑÐ·.  }
+
+_textRelationlong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÐŒÐ°ÐŒÐžÐ»ÐµÐ»ÐµÑ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>ÐŒÐ°ÐŒÐžÐ»ÐµÐ»ÐµÑ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°Ð³Ñ  ÐŒÐ°ÐŒÐžÐ»Ðµ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·.  }
+
+_textCoveragelong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÐŽÐ°ÑÐ°Ð»Ð°Ñ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑ Ð°ÑÐºÑÐ»ÑÑ </i>ÐÐ°ÑÐ°Ð»Ð°Ñ</i> Ð¶Ó©ÐœÒ¯ÐœÐŽÓ© ÐŒÐ°Ð°Ð»ÑÐŒÐ°Ñ ÐºÓ©ÑÓ© Ð°Ð»Ð°ÑÑÐ·.  }
+
+_textRightslong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÐºÑÐºÑÐ°Ñ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>ÑÐºÑÐºÑÐ°Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>.   }
+
+
+
+_textOrganizationlong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÑÐŒÐŽÐ°Ñ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>ÑÑÐŒÐŽÐ°Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°Ð³Ñ ÑÑÐŒÐŽÐ°Ñ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·.  }
+
+_textHowtolong_ [l=ky] {<p> Ð¡ÐžÐ· <i>Ð°ÑÐ°ÐºÐµÑÑÐµÑ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð°ÑÐ°ÐºÐµÑÑÐžÐ»ÐµÑ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°Ð³Ñ Ð°ÑÐ°ÐºÐµÑÑÐžÐ»ÐµÑ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·.  }
+
+_textTopiclong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÐµÐŒÐ°Ð»Ð°Ñ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ<i>ÑÐµÐŒÐ°Ð»Ð°Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœÐŽÑ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÑÐžÐ· ÑÐµÐŒÐ°Ð»Ð°Ñ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·. }
+
+_textTolong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÐºÐžÐŒÐ³Ðµ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð°Ð»ÑÑÑÑÐ»Ð°Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÑÐžÐ· Ð°Ð»ÑÑÑÑÐ»Ð°Ñ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·.  }
+
+_textFromlong_ [l=ky] {<p> Ð¡ÐžÐ· <i>ÐºÐžÐŒÐŽÐµÐœ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð¶ÐžÐ±ÐµÑÒ¯Ò¯Ð»Ó©Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°Ð³Ñ ÑÐµÑÐžÑÐ»Ð°Ñ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·.  }
+
+_textSerieslong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÐµÑÐžÑÐ»Ð°Ñ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ<i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÐœ ÑÐµÑÐžÑÐ»Ð°ÑÑ Ð±ÐŸÑÐœÑÐ°  ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÐŒÐ°ÑÐµÑÐžÐ°Ð»ÐŽÐ°Ñ ÑÐµÑÐžÑÐ»Ð°ÑÑÐœ Ñ
+ÑÐŸÐœÐŸÐ»ÐŸÐ³ÐžÑÐ»ÑÐº ÐžÑÐµÑÐžÐœÐŽÐµ ÐºÓ©ÑÓ©ÑÒ¯Ð·. }
+
+_textBrowselong_ [l=ky] {<p>Ð¡ÐžÐ·<i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑ ÐºÓ©ÑÒ¯Ò¯</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ¿
+<i>ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐž ÐºÐ°ÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·</i>. }
+
+_textPeoplelong_ [l=ky] {<p>Ð¡ÐžÐ· <i>Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐ¹Ð»ÐµÑ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>Ð°Ð»Ð°Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°Ð³Ñ Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐ¹Ð»ÐµÑ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·.  }
+
+_textAcronymlong_ [l=ky] {<p> Ð¡ÐžÐ· ÐºÑÑÐºÐ°ÑÑÑÑÐ»Ð°Ñ<i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑÐ¿ ÐºÑÑÐºÐ°ÑÑÑÑÐ»Ð°Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÑÐžÐ· ÐºÑÑÐºÐ°ÑÑÑÑÐ»Ð°Ñ ÐºÐµÐ·ÐŽÐµÑÐºÐµÐœ Ð¶ÐµÑÐ»ÐµÑÐŽÐž ÐºÓ©ÑÓ© Ð°Ð»Ð°ÑÑÐ·.}
+
+_textPhraselong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÑÐ°Ð·Ð°Ð»Ð°Ñ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ¿ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŽÐ°Ð³Ñ <i>ÑÑÐ°Ð·Ð°Ð»Ð°Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>.    }
+
+_textArtistlong_ [l=ky] {<p> Ð¡ÐžÐ· ÑÒ¯ÑÓ©ÑÑÒ¯Ð»Ó©Ñ<i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ</i> Ð±Ð°ÑÑÐ¿ ÑÒ¯ÑÓ©ÑÑÒ¯Ð»Ó©Ñ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÑÐžÐ· ÑÒ¯ÑÓ©ÑÑÒ¯Ð»Ó©ÑÐŽÒ¯ Ð°ÑÑ ÐŒÐµÐœÐµÐœ ÑÐŸÑÑÑÐŸÐ¹ Ð°Ð»Ð°ÑÑÐ·.}
+
+_textKeywordlong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÐŒÐ°Ò£ÑÐ· ÑÓ©Ð·ÐŽÓ©Ñ</i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>ÐŒÐ°Ò£ÑÐ· ÑÓ©Ð·ÐŽÓ©ÑÒ¯  Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœ Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ°Ð³Ñ ÐŒÐ°Ò£ÑÐ· ÑÓ©Ð·ÐŽÓ©ÑÒ¯ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·.  }
+
+_textVolumelong_ [l=ky] {<p>Ð¡ÐžÐ· <i>ÑÐŸÐŒ </i>  ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ </i> Ð±Ð°ÑÑÑ Ð°ÑÐºÑÐ»ÑÑ <i> ÑÐŸÐŒÐŽÐŸÑ Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð·ÐŒÑÐœÐŽÑ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·</i>. ÐÑÐ» ÐŒÐ°Ð·ÐŒÑÐœÐŽÐ°Ðœ ÑÐžÐ· ÐºÐžÑÐµÐ¿ÑÐžÐœ ÑÐŸÐŒÐŽÐŸÑÑ ÑÐžÐ·ÐžÐŒÐžÐœ ÐºÓ©ÑÓ©ÑÒ¯Ð·. }
+
+_textCaptionslong_ [l=ky] {<p>Ð¡ÐžÐ· <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÐœ Ð¶Ð°Ð·ÑÑÐ»Ð°ÑÑ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ¿
+ <i>ÐÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐ»Ð°ÑÐŽÑÐœ Ð¶Ð°Ð·ÑÑÑÑ</i> Ð±ÐŸÑÐœÑÐ° ÐŒÐ°Ð°Ð»ÑÐŒÐ°Ñ Ð°Ð»Ð°Ð»Ð°ÑÑÐ·ÐŽÐ°Ñ. }
+
+_textCountrieslong_ [l=ky] {<p>Ð¡ÐžÐ· <i>Ó©Ð»ÐºÓ©Ð»Ó©Ñ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑ Ð°ÑÐºÑÐ»ÑÑ <i>ÓšÐ»ÐºÓ©Ð»Ó©Ñ</i> Ð¶Ó©ÐœÒ¯ÐœÐŽÓ© ÐŒÐ°Ð°Ð»ÑÐŒÐ°Ñ ÐºÓ©ÑÓ© Ð°Ð»Ð°ÑÑÐ·.  }
+
+
+_textdefaultlongtext_ [l=ky] {<p>ÐÐµÐ»Ð³ÐžÑÐžÐ· ÑÐµÑ Ð±ÐŸÑÐœÑÐ° ÑÑÑÐ°Ð»Ð³Ð°Ðœ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐž ÐºÐ°ÑÐŸÐŸ Ò¯ÑÒ¯Ðœ <i>Ð±ÐµÐ»Ð³ÐžÑÐžÐ· ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÑ</i> ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÒ£ÑÐ·. }
+
+_texthelptopics_ [l=ky] {<h2 align=left>ÐÓ©Ð»Ò¯ÐŒÐŽÓ©Ñ</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">ÐÐ¹ÑÑÐºÑÐ° ÑÐµÑÐŒÐžÐœÐŽÐµÑ Ð±ÐŸÑÐœÑÐ° ÐžÐ·ÐŽÓ©Ó©ÐœÒ¯ ÐºÐ°ÐœÐŽÐ°Ð¹ ÐºÑÐ»ÑÑ ÐºÐµÑÐµÐº</a>
+<ul>
+  <li><a href="\#query-terms">ÐÐ·ÐŽÓ©Ó©Ð³Ó© Ð°ÑÐœÐ°Ð»Ð³Ð°Ðœ ÑÓ©Ð·ÐŽÓ©Ñ</a>
+  <li><a href="\#query-type">Ð¡ÑÑÐŸÐŸ ÑÐžÐ±Ðž</a>
+  <li><a href="\#scope-of-queries">Ð¡ÑÑÐŸÐŸ ÐŒÒ¯ÐŒÐºÒ¯ÐœÐŽÒ¯ÐºÑÓ©ÑÒ¯</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐœÑ ÑÒ¯Ð·Ó©ÑÒ¯Ò¯</a>
+
+  <li><a href="\#lang-prefs">Ð¢ÐžÐ»ÐŽÐž ÑÒ¯Ð·Ó©ÑÒ¯Ò¯ </a>
+  <li><a href="\#pres-prefs">ÐÐœÑÐµÑÑÐµÐ¹ÑÑÐž ÑÒ¯Ð·Ó©ÑÒ¯Ò¯ </a>
+  <li><a href="\#search-prefs">ÐÐ·ÐŽÓ©Ó©ÐœÒ¯ ÑÒ¯Ð·Ó©ÑÒ¯Ò¯ </a>
+</ul>
+</ul>"
+ }
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=ky] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=ky] {ÐÐŸÐºÑÐŒÐµÐœÑÑÐž ÐºÐ°ÐœÐŽÐ°Ð¹ ÐžÐ·ÐŽÓ©Ó© ÐºÐµÑÐµÐº}
+
+_texthelpreadingdocs_ [l=ky] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>You can tell when you have arrived at an individual book or document
+because its title, or a photograph of the front cover, appears at the top
+left of the page. In some collections this is accompanied by a table of
+contents, while others contain just the number of the current page along
+with a box that allows you to select a new page and go forward and
+backward. In the table of contents, the current section heading is in bold
+face, and the table is expandable -- click on the folders to open or close
+them; click on the open book at the top to close it.</p>
+
+<p>Underneath is the text of the current section. When you have read
+through it, there are arrows at the bottom to take you on to the next
+section or back to the previous one.</p>
+
+<p>Below the title or front-cover photograph are some buttons. Click on
+<i>expand text</i> to expand out the whole text of the current section, or
+book. If the document is large, this could take a long time and use a lot
+of memory! Click on <i>expand contents</i> to expand out the whole table of
+contents so that you can see the titles of all chapters and
+subsections. Click on <i>detach</i> to make a new browser window for this
+document. (This is useful if you want to compare documents, or read two at
+once.) Finally, when you do a search the words you search for are
+highlighted. Click on <i>no highlighting</i> to remove highlighting.</p>
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Open this bookshelf</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Open/close this book</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>View this section of the text</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Display all text, or not</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Expand table of contents, or not</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Open this page in a new window</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Highlight search terms, or not</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Click the arrow to go to the next section ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... or back to the previous section</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=ky] {<h2>ÐÑÐ°Ð¹ÑÐœ Ð°ÑÐœÐ°Ð»Ð³Ð°Ðœ ÑÐµÑÐŒÐžÐœÐŽÐµÑ Ð±ÐŸÑÐœÑÐ° ÐžÐ·ÐŽÓ©Ó©ÐœÒ¯ ÐºÐ°ÐœÐŽÐ°Ð¹ Ð¶Ò¯ÑÐ³Ò¯Ð·Ò¯Ò¯ ÐºÐµÑÐµÐº </h2> <p>
+  Ð¡ÐžÐ· ÐžÐ·ÐŽÓ©Ó© Ð±ÐµÑÐžÐœÐµÐœ, Ð¶Ó©ÐœÓ©ÐºÓ©Ð¹ ÑÑÑÐŸÐŸ Ð¶Ð°ÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·. <p>
+  
+  <ol><li>Ð­ÐŒÐœÐµÐœÐž ÐžÐ·ÐŽÐµÐ¹ÑÐžÐ· Ð°ÐœÑÐºÑÐ°Ò£ÑÐ·
+      <li>ÐÐœÑ ÐºÐ°ÐœÐŽÐ°Ð¹ ÐžÐ·ÐŽÓ©Ó©ÐœÒ¯ Ð°ÐœÑÐºÑÐ°Ò£ÑÐ·: ÑÑÐ°Ð·Ð°ÐœÑ  Ð¶Ðµ Ð¶ÐµÐºÐµ ÑÓ©Ð·ÐŽÓ©ÑÐŽÒ¯ ÐºÐŸÐ»ÐŽÐŸÐœÑÑ ÐŒÐµÐœÐµÐœ 
+      <li>Ð¡ÑÑÐŸÐŸÒ£ÑÐ·ÐŽÑ  ÐžÐ·ÐŽÓ©Ó© Ð¶ÐŸÐ»ÑÐœÐ° ÑÐµÑÐžÐ¿ ÐºÐžÑÐ³ÐžÐ·ÐžÒ£ÐžÐ·
+      <li>ÐÐ·ÐŽÓ©Ó©ÐœÒ¯ Ð±Ð°ÑÑÐŸÐŸ <i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÒ£ÑÐ·</i> 
+  </ol>
+
+<p>Ð¡ÑÑÐŸÐŸÐœÑÐœ Ð¶ÑÐ¹ÑÐœÑÑÐ³Ñ ÑÑÐºÐºÐ°ÐœÐŽÐ°Ðœ ÐºÐžÐ¹ÐžÐœ ÑÐºÑÐ°ÐœÐŽÐ°  20 ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐžÐœ Ð°ÑÐ°Ð»ÑÑÑ Ð¿Ð°Ð¹ÐŽÐ° Ð±ÐŸÐ»ÐŸÑ. Ð¢ÐžÐ·ÐžÐŒÐŽÐžÐœ Ð°ÑÐ³ÑÐœÐŽÐ°, ÐºÐžÐ¹ÐžÐœÐºÐž 20 ÐŽÐŸÐºÑÐŒÐµÐœÑÐºÐµ Ó©ÑÒ¯Ò¯ ÐºÐœÐŸÐ¿ÐºÐ°ÑÑ Ð±Ð°Ñ. ÐÐ°ÑÑÐ¹Ð¶Ð°Ð»Ð°ÑÐŽÑÐœ ÐºÐžÐ¹ÐžÐœÐºÐž Ð±ÐµÑÑÐµÑÐžÐœÐŽÐµ ÐŽÐ°Ð³Ñ 20 ÐŽÐŸÐºÑÐŒÐµÐœÑÐºÐµ Ð¶Ðµ Ð°Ð»ÐŽÑÒ£ÐºÑ 20 ÐŽÐŸÐºÑÐŒÐµÐœÑÐºÐµ ÐºÓ©ÑÒ¯Ò¯Ð³Ó© Ð°ÑÐœÐ°Ð»Ð³Ð°Ðœ ÐºÐœÐŸÐ¿ÐºÐ°ÐœÑ ÐºÓ©ÑÓ©ÑÒ¯Ð·. ÐÐŸÐºÑÐŒÐµÐœÑÑÐžÐœ Ð°ÑÑÐœÐ° Ð¶Ðµ Ð°ÐœÑÐœ Ð°Ð»ÐŽÑÐœÐŽÐ°Ð³Ñ Ð±ÐµÐ»Ð³ÐžÐœÐž Ð±Ð°ÑÑÐ¿, Ð°ÐœÑ ÐºÐ°ÑÐ°Ð¹ Ð°Ð»Ð°ÑÑÐ·. 
+
+<p>ÐÐ·ÐŽÓ©Ó©ÐœÒ¯Ðœ ÐœÐ°ÑÑÐ¹Ð¶Ð°ÑÑÐœÐŽÐ° ÑÒ£ ÐºÓ©Ð¿ ÐŽÐµÐ³ÐµÐœÐŽÐµ -100 ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð±ÐŸÐ»ÐŸÑ. Ð¡ÐžÐ· Ð±ÑÐ» ÑÐ°ÐœÐŽÑ ÑÒ¯Ð·Ó©ÑÒ¯Ò¯ Ð±ÐµÑÐžÐœÐµÐœ Ó©Ð·Ð³Ó©ÑÑÓ© Ð°Ð»Ð°ÑÑÐ· (ÐÐµÑÑÐžÐœ Ð±Ð°Ñ Ð¶Ð°Ð³ÑÐœÐŽÐ°Ð³Ñ <i> ÑÒ¯Ð·Ó©ÑÒ¯Ò¯Ð»Ó©Ñ</i>ÐºÐœÐŸÐ¿ÐºÐ°ÑÑ). <p>
+ <p>_iconblankbar_
+<a name=query-terms>
+<h3>ÐÐ·ÐŽÓ©Ó©Ð³Ó© Ð°ÑÐœÐ°Ð»Ð³Ð°Ðœ ÑÓ©Ð·ÐŽÓ©Ñ</h3>
+
+<p>Ð¡ÐžÐ·ÐŽÐžÐœ ÑÑÑÐŸÐŸ Ð¶ÐŸÐ»ÑÐœÐŽÐ° ÐºÐžÑÐ³ÐžÐ·Ð³ÐµÐœÐžÒ£ÐžÐ·ÐŽÐžÐœ Ð±Ð°Ð°ÑÑ, â ÐžÐ·ÐŽÓ©Ð³Ó©Ó© Ð°ÑÐœÐ°Ð»Ð³Ð°Ðœ ÑÓ©Ð·ÐŽÓ©Ñâ ÐŽÐµÐ¿ Ð°ÑÐ°Ð»Ð°Ñ. ÐÑ Ð±ÐžÑ ÑÓ©Ð· ÑÐ°ÐŒÐ³Ð°Ð»Ð°Ñ ÐŒÐµÐœÐµÐœ ÑÐžÑÑÐ°Ð»Ð°ÑÐŽÐ°Ðœ ÑÑÑÐ°Ñ. Ð¡Ó©Ð·ÐŽÓ©Ñ Ð±ÐŸÑ ÐŸÑÑÐœ ÐŒÐµÐœÐµÐœ Ð±Ó©Ð»Ò¯ÐœÐ³Ó©Ðœ. Ð­Ð³ÐµÑ Ð±Ð°ÑÐºÐ° Ð±ÐžÑ Ð±ÐµÐ»Ð³Ðž Ð±ÐŸÐ»ÑÐŸ, ÐŒÐžÑÐ°Ð»Ñ Ð¿ÑÐœÐºÑÑÐ°ÑÐžÑ Ð±ÐµÐ»Ð³ÐžÐ»ÐµÑÐž, Ð°ÐœÐŽÐ° Ð°Ð»Ð°Ñ ÐŽÐ° Ð±ÐŸÑ Ð±ÐµÐ»Ð³Ðž ÑÑÑÐºÑÑÑ ÑÓ©Ð· Ð±Ó©Ð»Ð³Ò¯Ñ ÐºÑÐ·ÐŒÐ°ÑÑÐœ Ð°ÑÐºÐ°ÑÐ°Ñ. Ð¡ÐžÐ· Ð¿ÑÐœÐºÑÑÐ°ÑÐžÑ Ð±ÐµÐ»Ð³ÐžÐ»ÐµÑÐž Ð±Ð°Ñ ÑÓ©Ð·ÐŽÓ©Ñ Ð±ÐŸÑÐœÑÐ° ÐžÐ·ÐŽÓ©Ó© Ð¶Ò¯ÑÐ³Ò¯Ð·Ó© Ð°Ð»Ð°ÑÑÐ·. 
+
+
+<p>ÐÐžÑÐ°Ð»Ñ, <p>
+    <ul><kbd>Ð§ÑÐœ Ð°ÑÐ°Ð»ÐŽÐ°ÑÑÐœÐŽÐ°Ð³Ñ ÐÐ¹ÑÐ»-ÑÐ°ÑÐ±Ð°ÑÑÐ»ÑÐ³Ñ: ÐÐŸÐ»ÐŽÐŸÐŸ ÑÐ°ÑÐŒÐ°Ð³Ñ (1993)</kbd></ul>
+      <p>ÑÑÑÐŸÐŸÐœÑ ÐºÐ°ÑÐ°ÑÑÑÑÑÐ°Ðº Ð°Ð» Ð°Ð»ÐŽÑÒ£ÐºÑ ÐŒÐµÐœÐµÐœ Ð±Ð°ÑÐ°Ð±Ð°Ñ<p>
+      <ul><kbd> Ð§ÑÐœ Ð°ÑÐ°Ð»ÐŽÐ°ÑÑÐœÐŽÐ°Ð³Ñ Ð°Ð¹ÑÐ»-ÑÐ°ÑÐ±Ð°ÑÑÐ»ÑÐ³Ñ ÐºÐŸÐ»ÐŽÐŸÐŸ ÑÐ°ÑÐŒÐ°Ð³Ñ 1993</kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Ð¡ÑÑÐŸÐŸ ÑÐžÐ¿ÑÐµÑÐž</h3>
+
+<p>ÓšÐ·Ð³Ó©ÑÓ© ÑÐºÐž ÑÑÑÐŸÐŸ ÑÐžÐ±Ðž Ð±Ð°Ñ.
+
+<ul>
+  <li>ÐÐ°ÑÐŽÑÐº <b>ÑÓ©Ð·ÐŽÓ©Ñ</b> Ð±ÐŸÑÐœÑÐ° ÑÑÑÐŸÐŸÐ»ÐŸÑ. ÐÑÐ» ÑÐžÐ· ÐžÐ·ÐŽÓ©Ó© Ð¶ÐŸÐ»ÑÐœÐ° ÐºÐžÑÐ³ÐžÐ·Ð³ÐžÒ£ÐžÐ· ÐºÐµÐ»Ð³ÐµÐœ ÑÓ©Ð·ÐŽÓ©ÑÐŽÒ¯Ðœ Ð±Ð°Ð°ÑÑ Ð±Ð°ÑÐŽÑÐº ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ Ò¯ÑÒ¯Ðœ Ð±ÐŸÐ»ÐŸÑ. Ð¢ÑÑÑÐ° ÐºÐµÐ»Ð³ÐµÐœ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ Ð°Ð»ÑÐ°Ð²ÐžÑÑÐžÐº ÑÐ°ÑÑÐžÐ¿ÑÐµ ÑÑÐ³Ð°ÑÑÐ»Ð°Ñ. <p>
+
+  <li>ÐÑÑ Ð±ÐžÑ <b>ÑÓ©Ð·ÐŽÓ©Ñ</b> Ð±ÐŸÑÐœÑÐ° ÑÑÑÐŸÐŸÐ»ÐŸÑ. ÐÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐžÐœ ÑÐµÐŒÐ°ÑÑÐœÐŽÐ°  ÐºÐµÐ·ÐŽÐµÑÒ¯Ò¯ ÐŒÒ¯ÐŒÐºÒ¯Ðœ Ð±ÐžÑ ÐœÐµÑÐµ ÑÓ©Ð·ÐŽÒ¯ Ð¶Ð°Ð·ÑÑ Ð¶ÐµÑÐºÐžÐ»ÐžÐºÑÒ¯Ò¯.  Ð¡ÑÑÐŸÐŸÐ³ÐŸ ÑÑÑÑÐ° ÐºÐµÐ»Ð³ÐµÐœÐž ÐŒÑÐœÐŽÐ°Ð¹ Ð°ÐœÑÐºÑÐ°Ð»Ð°Ñ:  
+      <p><ul>
+        <li> ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµ ÐžÐ·ÐŽÐµÐ»Ò¯Ò¯ÑÒ¯ ÑÐµÑÐŒÐžÐœÐŽÐµÑ ÐºÓ©Ð±Ò¯ÑÓ©Ó©Ðº ÐºÐµÐ·ÐŽÐµÑÐºÐµÐœ ÑÐ°Ð¹ÑÐœ, Ð°Ð» ÐºÓ©Ð±Ò¯ÑÓ©Ó©Ðº ÑÑÑÑÐ° ÐºÐµÐ»ÐµÑ;   <li> Ð¶Ð°Ð»Ð¿Ñ ÑÓ©Ð·ÐŽÓ©ÑÐ³Ó© ÐºÐ°ÑÐ°Ð³Ð°ÐœÐŽÐ°, ÑÐµÐ¹ÑÐµÐº ÑÓ©Ð·ÐŽÓ©Ñ ÐŒÐ°Ò£ÑÐ·ÐŽÑÑÑÐ°Ðº;
+        <li> ÑÐŸÒ£ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐ³Ðµ ÐºÐ°ÑÐ°Ð³Ð°ÐœÐŽÐ° ÐºÐžÑÐžÐœÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐ³Ðµ ÐºÓ©Ð±Ò¯ÑÓ©Ó©Ðº ÑÑÑÑÐ° ÐºÐµÐ»ÐµÑ.
+      </ul>
+</ul>
+
+<p>ÐÐ·ÐŽÓ©Ó©Ð³Ó© ÐºÐ°ÐœÑÐ° ÑÓ©Ð· ÐºÐµÑÐµÐº Ð±ÐŸÐ»ÑÐŸ ÐŸÑÐŸÐœÑÐŸ ÑÓ©Ð·ÐŽÒ¯ Ð¿Ð°Ð¹ÐŽÐ°Ð»Ð°ÐœÑÒ£ÑÐ· â ÐÐžÑ ÑÒ¯Ð¹Ð»Ó©ÐŒ Ð¶Ðµ Ð¿Ð°ÑÐ°Ð³ÑÐ°Ñ Ð±ÐŸÐ»ÑÑÑ ÐŒÒ¯ÐŒÐºÒ¯Ðœ.  <p>
+_texthelpscope_
+
+}
+
+_textdatesearch_ [l=ky] {ÐÐ°ÑÐ° Ð±ÐŸÑÐœÑÐ° ÐžÐ·ÐŽÓ©Ó©}
+
+_texthelpdatesearch_ [l=ky] {<h2>_textdatesearch_</h2>
+ÐÐ°ÑÐ° Ð±ÐŸÑÐœÑÐ° ÐžÐ·ÐŽÓ©Ó©, Ð±ÐµÐ»Ð³ÐžÐ»Ò¯Ò¯ Ð±ÐžÑ ÑÐ±Ð°ÐºÑÑ Ð°ÑÐ°Ð»ÑÐ³ÑÐœÐŽÐ° Ð±ÐŸÐ»Ð³ÐŸÐœ ÐŸÐºÑÑÐ»Ð°ÑÐ³Ð° ÐºÐ°ÑÑÑÑÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐž ÑÐ°Ð±ÑÑÐ³Ð° ÐŒÒ¯ÐŒÒ¯ÐœÑÒ¯Ð»Ò¯Ðº
+Ð±ÐµÑÐµÑ. Ð¡ÐžÐ· ÐžÐ·ÐŽÓ©Ó©ÐœÒ¯ Ð±ÐµÐ»Ð³ÐžÐ»Ò¯Ò¯ Ð±ÐžÑ Ð¶ÑÐ»Ð³Ð° ÐºÐ°ÑÑÑÑÑ Ð±Ð°Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ Ð±ÐŸÐ¹ÑÐœÑÐ° Ð¶Ð°ÐœÐ° Ð¶ÑÐ»ÐŽÐ°Ñ ÐŽÐžÐ°Ð¿Ð°Ð·ÐŸÐœÐŽÐŸÑÑ Ð±ÐŸÐ¹ÑÐœÑÐ° Ð¶Ò¯ÑÐ³Ò¯Ð·Ó© Ð°Ð»Ð°ÑÑÐ·.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>ÐÑÐ» ÑÑÐœÐºÑÐžÑÐœÑ ÐºÐ°ÐœÐŽÐ°Ð¹ ÐºÐŸÐ»ÐŽÐŸÐœÑÑ ÐºÐµÑÐµÐº:</h3>
+<ul>
+   <li>ÐÐžÑ Ð±ÐµÑÐžÐ»Ð³ÐµÐœ Ð¶ÑÐ»ÐŽÐ°Ðœ ÐžÐ·ÐŽÓ©Ó©:<p>
+   <ul>
+       <li>ÐÓ©ÐœÒ¯ÐºÐºÓ©Ðœ ÑÓ©Ð·ÐŽÓ©ÑÐŽÒ¯ ÐºÐžÑÐ³ÐžÐ·ÐžÒ£ÐžÐ·.
+       <li>Ð¡ÐžÐ·Ð³Ðµ ÐºÐµÑÐµÐºÑÒ¯Ò¯ Ð¶ÑÐ»ÐŽÑ "ÐÐ°ÑÐºÑ (Ð¶Ðµ ÐœÐ°ÐºÑÑ) ÐŽÐ°ÑÐ°" ÑÒ¯ÑÒ¯ÐœÐŽÓ© ÐºÐžÑÐ³ÐžÐ·ÐžÒ£ÐžÐ·.
+       <li>Ð¡ÐžÐ·ÐŽÐžÐœ ÐŽÐ°ÑÐ°Ò£ÑÐ· Ð±ÐžÐ·ÐŽÐžÐœ ÑÑÐ°Ð³Ð° ÑÐµÐžÐ¹Ðœ ÐŽÐµÐ¿ ÑÑÐµÐ¿ÑÐµÐ»ÑÐµ ÑÐžÐ· âÐ±.Ñ.Ñ.â ÐŽÐµÐ³ÐµÐœ ÐŸÐ¿ÑÐžÑÐœÑ ÑÐ°ÐœÐŽÐ°Ð¿ Ð°Ð»ÑÒ£ÑÐ·.
+       <li>ÐÐ·ÐŽÓ©Ó©ÐœÒ¯ Ð±Ð°ÑÑÐŸÐŸ.
+   </ul>
+<p><li>ÐÐµÑÐžÐ»Ð³ÐµÐœ ÐŽÐžÐ°Ð¿Ð°Ð·ÐŸÐœÐŽÐŸÐœ ÐžÐ·ÐŽÓ©Ó©:<p>
+   <ul>
+       <li>ÐÓ©ÐœÒ¯ÐºÐºÓ©Ðœ ÑÓ©Ð·ÐŽÓ©ÑÐŽÒ¯ ÐºÐžÑÐ³ÐžÐ·ÐžÒ£ÐžÐ·.
+       <li>ÐÐ°ÑÐºÑ ÐŽÐ°ÑÐ°ÑÑ "ÐÐ°ÑÐºÑ (Ð¶Ðµ ÐœÐ°ÐºÑÑ) ÐŽÐ°ÑÐ°" ÑÒ¯ÑÒ¯ÐœÐŽÓ© ÐºÐžÑÐ³ÐžÐ·ÐžÒ£ÐžÐ·.
+       <li>ÐÐºÑÑÐºÑ ÐŽÐ°ÑÐ°ÑÑ "ÐÐºÑÑÐºÑ ÐŽÐ°ÑÐ°ÑÑ" ÑÒ¯ÑÒ¯ÐœÐŽÓ© ÐºÐžÑÐ³ÐžÐ·ÐžÒ£ÐžÐ·.
+       <li>Ð¡ÐžÐ·ÐŽÐžÐœ ÐŽÐ°ÑÐ°Ò£ÑÐ· Ð±ÐžÐ·ÐŽÐžÐœ ÑÑÐ°Ð³Ð° ÑÐµÐžÐ¹Ðœ ÐŽÐµÐ¿ ÑÑÐµÐ¿ÑÐµÐ»ÑÐµ ÑÐžÐ· âÐ±.Ñ.Ñ.â ÐŽÐµÐ³ÐµÐœ ÐŸÐ¿ÑÐžÑÐœÑ ÑÐ°ÐœÐŽÐ°Ð¿ Ð°Ð»ÑÒ£ÑÐ·.
+       <li>ÐÐ·ÐŽÓ©Ó©ÐœÒ¯ Ð±Ð°ÑÑÐŸÐŸ.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>The way results of your search work</h3>
+
+ÐÐ°Ð»Ð¿Ñ Ð°Ð¹ÑÐºÐ°ÐœÐŽÐ°, Ð±ÑÐ» ÐžÐ·ÐŽÓ©Ó©ÐŽÓ© 1903 Ð¶ÑÐ» Ð¶Ó©ÐœÒ¯ÐœÐŽÓ© ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐž ÐžÐ·ÐŽÐµÑÐµÒ£ÐžÐ· ÑÐžÐ·Ð³Ðµ 1903 Ð¶ÑÐ»Ñ Ð¶Ð°Ð·ÑÐ»Ð³Ð°Ðœ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ ÑÑÐ³Ð°ÑÑÐ»Ð±Ð°Ð¹Ñ, Ð°ÐœÐŽÐ° 1903 Ð¶ÑÐ» Ð¶Ó©ÐœÒ¯ÐœÐŽÓ© Ð³Ð°ÐœÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ ÑÐ°Ð±ÑÐ»Ð°Ñ.ÐÐžÑÐŸÐº,ÐŽÐžÐ°Ð¿ÐŸÐ·ÐŸÐœÐŽÐŸÑ Ð±ÐŸÑÐœÑÐ° ÐžÐ·ÐŽÐµÑÐµÒ£ÐžÐ· (ÐŒÐžÑÐ°Ð»Ñ 1899-1911) ÑÐžÐ·Ð³Ðµ 1903 Ð¶ÑÐ»Ð³Ð° ÑÐžÐµÑÐµÑÐž Ð±Ð°Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐžÐœ Ð±Ð°Ð°ÑÐŽÑÐ³Ñ ÐŽÐ°Ð³Ñ ÐºÓ©ÑÑÓ©ÑÒ¯Ð»Ó©Ñ. ÐÑÐŸÐœÐŽÑÐºÑÐ°Ðœ ÑÐžÐ·Ð³Ðµ ÐºÓ©ÑÑÓ©Ò¯Ð»Ð³Ó©Ðœ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐžÐœ Ð°ÑÐ°ÑÑÐœÐŽÐ° ÐŽÐ°ÑÐ°ÑÑ ÑÐ°Ðº Ð¶Ð°Ð·ÑÐ»Ð±Ð°Ð³Ð°ÐœÑ ÐŽÐ° ÐŒÒ¯ÐŒÐºÒ¯Ðœ. ÐÐžÐ°Ð¿ÐŸÐ·ÐŸÐœÐŽÐŸÐ³Ñ Ð±Ð°Ð°ÑÐŽÑÐº ÐŽÐ°ÑÐ°Ð»Ð°ÑÐ³Ð° ÐºÐ°ÑÑÑÑ Ð±Ð°Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑ ÐºÓ©ÑÑÓ©ÑÒ¯Ð»Ó©Ñ.<p>
+}
+
+_textchangeprefs_ [l=ky] {Ð¢Ò¯Ð·Ó©ÑÒ¯Ò¯Ð»Ó©ÑÐŽÒ¯ Ó©Ð·Ð³Ó©ÑÑÒ¯Ò¯}
+
+_texthelppreferences_ [l=ky] {<h2>_textchangeprefs_</h2>
+ 
+ <p>Ð¢Ò¯Ð·Ó©ÑÒ¯Ò¯Ð»Ó©Ñ <i> Ð±ÐµÑÐžÐœÐŽÐµ</i> (Ð±ÐµÑÑÐžÐœ Ð¶ÐŸÐ³ÐŸÑÑ Ð±Ó©Ð»Ò¯Ð³Ò¯ÐœÐŽÓ©Ð³Ò¯ ÐºÐœÐŸÐ¿ÐºÐ°) ÑÐžÐ·ÐŽÐµÑ ÐžÐœÑÐµÑÑÐµÐ¹ÑÑÐžÐœ ÐºÑÑ Ð±ÐžÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐ»ÐµÑÐžÐœ Ó©Ð·Ð³Ó©ÑÑÓ© Ð°Ð»Ð°ÑÑÐ·. 
+ 
+ <p>_iconblankbar_
+ <a name=col-prefs>
+ <h3 align=left>ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑ ÑÒ¯Ð·Ó©ÑÒ¯Ò¯</h3>
+ 
+ ÐÑÑ Ð±ÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÐ° ÐºÓ©Ð¿ÑÓ©Ð³Ó©Ðœ ÐžÑÐºÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ Ð±ÐŸÐ»ÐŸÑ, Ð°Ð»Ð°ÑÐŽÐ° ÐžÐ·ÐŽÓ©Ó© Ð°ÑÐºÐ°Ð¹ÑÑÐœÑÑÑÐœÐŽÐ° Ð¶ÐµÐºÐµ Ð¶Ð°ÐœÐ° Ð±Ð°ÑÐŽÑÐ³ÑÐœ Ð±ÐžÑÐ³Ðµ Ð¶Ò¯ÑÐ³Ò¯Ð·Ó© Ð°Ð»Ð°ÑÑÐ·. Ò¯Ð¹Ò¯ÐœÓ© ÐºÐµÐ»ÑÐžÑÒ¯Ò¯ Ð±ÐµÑÐžÐœÐŽÐµ ÑÐžÐ· ÐžÐ·ÐŽÓ©Ó©Ð³Ó©  ÐºÐŸÑÐºÑÒ£ÑÐ· ÐºÐµÐ»Ð³ÐµÐœ ÐžÑÐºÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑ ÑÐ°ÐœÐŽÐ°Ð¿ Ð°Ð»ÑÐ°Ò£ÑÐ· Ð±ÐŸÐ»ÐŸÑ.
+ 
+ <p>_iconblankbar_
+ <a name=lang-prefs>
+ <h3 align=left>Ð¢ÐžÐ»ÐŽÐž ÑÒ¯Ð·Ó©ÑÒ¯Ò¯</h3>
+ 
+ ÐÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° ÑÑÐ°ÐœÐŽÐ°ÑÑÑÑÑ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÑÐžÐ»Ðž Ð±Ð°Ñ, Ð±ÐžÑÐŸÐº ÑÐžÐ· Ð±Ð°ÑÐºÐ° ÑÐžÐ»ÐŽÐž ÑÐ°ÐœÐŽÐ°Ð¿ Ð°Ð»ÑÐ°Ò£ÑÐ· Ð±ÐŸÐ»ÐŸÑ. ÐÑÐŸÐœÐŽÐŸÐ¹ ÑÐ»Ðµ ÑÐžÐ· Ð±ÑÐ» Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°ÐŽÐ° Ð±Ð°Ñ Ð±Ð°ÑÐºÐ° ÐºÐŸÐŽÐžÑÐŸÐ²ÐºÐ°ÐœÑ ÑÐ°ÐœÐŽÐ°Ð¿ Ð°Ð»ÑÐ°Ò£ÑÐ· Ð±ÐŸÐ»ÐŸÑ, ÑÐžÐ·ÐŽÐžÐœ Ð±ÑÐ°ÑÐ·ÐµÑÐ³Ðµ ÑÑÑÑÐ° ÐºÐµÐ»Ð³ÐµÐœ Ð°Ð²ÑÐŸÐŒÐ°Ñ ÑÒ¯ÑÐŽÓ© ÑÑÐ°ÐœÐŽÐ°ÑÑÑ Ð±ÐŸÐ»ÐŸÑ, ÑÑÑÑÐ° ÐºÐŸÐŽÐžÑÐŸÐ²ÐºÐ°ÐœÑ Ó©Ð·Ò¯Ò£Ò¯Ð· ÑÐ°ÐœÐŽÐ°Ð³Ð°Ðœ ÐŸÒ£. ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑÐœ Ð±Ð°Ð°ÑÐŽÑÐ³ÑÐœÐŽÐ° ÐºÐ°ÑÐŸÐŸÐœÑÐœ Ð³ÑÐ°ÑÐžÐºÐ°Ð»ÑÐº ÑÐµÐ¶ÐžÐŒÐžÐœÐµÐœ ÑÐµÐºÑÑ ÑÐµÐ¶ÐžÐŒÐžÐœÐµ Ó©ÑÒ¯Ò¯Ð³Ó© Ð¶Ð°ÐœÐ° ÑÐµÑÐºÐµÑÐžÐœÑÐµ ÐºÓ©ÑÒ¯Ò¯Ð³Ó© ÐŽÐ° Ð±ÐŸÐ»ÐŸÑ. 
+ <p>_iconblankbar_
+ 
+ <a name=pres-prefs>
+ <h3 align=left>ÐÐœÑÐµÑÑÐµÐ¹ÑÑÐž ÑÒ¯Ð·Ó©ÑÒ¯Ò¯ </h3>
+ 
+ ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐ³Ð° Ð±Ð°Ð¹Ð»Ð°ÐœÑÑÑÑÑ Ð°Ñ-ÑÒ¯ÑÐŽÒ¯Ò¯ ÑÒ¯Ð·Ó©ÑÒ¯Ò¯Ð»Ó©Ñ Ð±Ð°Ñ. 
+ 
+ <p>Web Ð±ÐµÑÑÐµÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÑÑ Ð°Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐžÐœ Ò¯ÑÑÒ¯ÐœÐŽÓ©Ð³Ò¯ Ð±Ð°ÑÐºÐ°ÑÑÑ Ð¿Ð°ÐœÐµÐ»ÐžÐœ ÐºÐŸÐ»ÐŽÐŸÐœÑÑÐ³Ð° ÐŒÒ¯ÐŒÐºÒ¯ÐœÐŽÒ¯Ðº Ð±ÐµÑÐµÑ, Ð°ÐœÑ ÐŒÐµÐœÐµÐœ ÐžÐ·ÐŽÓ©Ó©ÐŽÓ©Ðœ ÐºÐžÐ¹ÐžÐœ Greenstone ÑÐµÐŒÐ°Ò£ÑÐ·  Web Ð±ÐµÑÐºÐµ ÑÒ¯ÑÓ©Ñ.  ÐÐ°Ò£Ñ ÑÑÑÐŸÐŸ ÐºÐŸÐ¹ÑÑ Ò¯ÑÒ¯Ðœ Ó©Ð·Ò¯Ò£Ò¯Ð·ÐŽÒ¯Ðœ Ð±ÑÐ°ÑÐ·ÐµÑÐžÒ£ÐžÐ·ÐŽÐµÐ³Ðž "back" ÐºÐœÐŸÐ¿ÐºÐ°ÑÑÐœ Ð±Ð°ÑÑÐ°Ò£ÑÐ· Ð±ÐŸÐ»ÐŸÑ. ÐÑÐ» ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°Ñ WWW ÐŽÐµÐ³Ðž ÑÐ»ÐµÐºÑÑÐŸÐœÐŽÑÐº ÐºÐžÑÐµÐ¿ÐºÐ°ÐœÐ° ÑÐžÑÑÐµÐŒÐ°ÑÑÐœÑÐœ ÐºÐ°ÑÐ°Ð»Ð°ÑÑÐœÐ° ÑÑÐ¹ÑÐŒ ÑÐ°Ð»ÑÑ ÐŒÒ¯ÐŒÐºÒ¯ÐœÐŽÒ¯ÐºÑÓ©ÑÒ¯Ðœ Ð±ÐµÑÐµÑ. 
+<p>_iconblankbar_
+<a name=search-prefs>
+ <h3 align=left>ÐÐ·ÐŽÓ©Ó©ÐœÒ¯ ÑÒ¯Ð·Ó©ÑÒ¯Ò¯ </h3>
+ <p>Ð­ÐºÐž Ð°Ð»ÐŒÐ°ÑÑÑÑÑÐ¿  ÐºÐŸÑÐºÑÑ ÐºÐœÐŸÐ¿ÐºÐ°Ð»Ð°ÑÑ ÐžÐ·ÐŽÓ©Ó©  ÐºÐ°ÑÐžÐµÑÑÐµÑÐžÐœ Ð±Ð°ÑÐºÐ°ÑÐ°Ñ. âÐ ÐµÐ³ÐžÑÑÑÐ»ÐµÑâ ÑÐ°ÐŒÐ³Ð°Ð»Ð°ÑÐŽÑÐœ ÑÐµÐ³ÐžÑÑÐžÑÐ»ÐµÑÐžÐœ ÑÑÐµÐ¿ÑÓ©Ó© Ð¶Ðµ Ó©ÑÒ¯ÑÒ¯Ò¯ ÐŒÒ¯ÐŒÐºÒ¯ÐœÑÒ¯Ð»Ò¯ÑÒ¯Ðœ Ð±ÐµÑÐµÑ. âÐ¡Ó©Ð·ÐŽÓ©ÑÐŽÒ¯Ðœ Ð¶Ð°Ð»Ð³ÐŸÐŸÐ»ÐŸÑÑâ  ÑÓ©Ð·ÐŽÒ¯Ðœ Ð¶Ð°Ð»Ð³ÐŸÐŸÐ»ÐŸÑÑÐœ ÑÑÐµÐ¿ÑÓ©Ó© Ð¶Ðµ ÑÑÐµÐ¿ÑÐµÐ±Ó©Ó© ÐŒÒ¯ÐŒÐºÒ¯ÐœÑÒ¯Ð»Ò¯ÐºÑÓ©ÑÒ¯Ðœ Ð±ÐµÑÐµÑ. âÐÐ·ÐŽÓ©Ó© ÑÐµÑÐµÐ·ÐµÑÐžÐœÐžÐœ Ó©Ð»ÑÓ©ÐŒÒ¯â  Ð±Ò¯ÑÒ¯Ðœ Ð±ÐžÑ Ð°Ð±Ð·Ð°ÑÑÑ ÐºÐžÑÐ³ÐžÐ·Ò¯Ò¯ ÐŒÒ¯ÐŒÐºÒ¯ÐœÐŽÒ¯Ð³Ò¯Ðœ Ð±ÐµÑÐµÑ.  
+ <p>ÐÐžÑÐ°Ð»Ñ, ÑÐ³ÐµÑ <i>ÑÐµÐ³ÐžÑÑÑÐ»ÐµÑÐŽÐž ÑÑÐµÐ¿ÑÐµÐ±Ó©Ó©</i> Ð¶Ð°ÐœÐ°
+ <i>ÑÓ©Ð·ÐŽÓ©ÑÐŽÒ¯Ðœ Ð¶Ð°Ð»Ð³ÐŸÐŸÐ»ÐŸÑÑÐœ ÑÑÐµÐ¿ÑÐµÐ±Ó©Ó© ÑÐ°ÐœÐŽÐ°Ð»ÑÐ°</i>,Ð°ÐœÐŽÐ° ÑÑÑÐŸÐŸ<p>
+     <ul><kbd>African building</kbd></ul>
+       <p>Ð±ÑÐ» ÑÒ¯ÑÐŽÓ© ÐžÐ·ÐŽÐµÐ»ÐµÑ<p>
+       <ul><kbd>africa builds</kbd></ul><p>
+       Ð¡ÐµÐ±ÐµÐ±Ðž âAfricanâ ÑÓ©Ð·Ò¯ÐœÐŽÓ©Ð³Ò¯ Ð¶ÐŸÐ³ÐŸÑÐºÑ ÑÐµÐ³ÐžÑÑÑ ÑÐ°ÐŒÐ³Ð°ÑÑ ÑÓ©ÐŒÓ©ÐœÐºÒ¯ ÑÐµÐ³ÐžÑÑÑ ÑÐ°ÐŒÐ³Ð°ÑÑÐœÐ° Ó©Ð·Ð³Ó©ÑÑÒ¯Ð»Ò¯Ð¿, ânâ Ð¶Ð°ÐœÐ° âingâ Ð¶Ð°Ð»Ð³ÐŸÐŸÐ»ÐŸÑÑ ÑÓ©Ð·ÐŽÓ©Ðœ Ð°Ð»ÑÐœÐ°Ñ.      "African" Ð¶Ð°ÐœÐ° "building" ("s" "builds" ÑÓ©Ð·Ò¯ÐœÓ©Ðœ Ð°Ð»ÑÐœÐ°Ñ).
+ 
+ <p>Ð¡ÐžÐ· ÐÐÐÐ (&), ÐÐ(|), ÐÐÐÐ Ð­ÐÐÐ¡ ÐŒÐžÐ»ÐŽÐµÑÑÐµÑÐžÐœ ÐºÐŸÐ»ÐŽÐŸÐœÑÐ¿ ÑÑÑÐŸÐŸÐœÑÐœ ÑÐŸÒ£ÐŸÐ¹ÑÑÐ»Ð³Ð°Ðœ ÑÐŸÑÐŒÐ°ÑÑÐœÐ° Ó©ÑÓ© Ð°Ð»Ð°Ð»Ð°ÑÑÐ·. ÐÑÐ» ÑÐ°Ðº ÑÑÑÐŸÐŸÐ»ÐŸÑÐŽÑ ÐºÑÑÑÑ ÐŒÒ¯ÐŒÐºÒ¯ÐœÑÒ¯Ð»Ò¯Ð³Ò¯Ðœ Ð±ÐµÑÐµÑ. ÐÑÐ» ÐžÐ·ÐŽÓ©Ó© ÐœÐ°ÑÑÐ¹Ð¶Ð°Ð»Ð°ÑÑ ÐºÓ©ÑÑÓ©ÑÒ¯Ð»Ð³Ó©Ðœ  ÐºÐµÐ·ÐŽÐµ ÑÑÑÐŸÐŸ ÑÐ°ÑÑÑ
+ÑÐœ ÐºÓ©ÑÑÓ©ÑÒ¯Ò¯ÐœÒ¯ ÐžÑÐºÐµ ÐºÐŸÑÐŸ Ð°Ð»Ð°ÑÑÐ·. ÐÑÐ» Ó©Ð·Ð³Ó©ÑÑÒ¯Ð»Ð³Ó©Ðœ ÑÑÑÐŸÐŸ ÑÒ¯ÑÒ¯Ðœ Ð¶Ð°ÑÐŸÐŸÐ³ÐŸ ÐŒÒ¯ÐŒÐºÒ¯ÐœÐŽÒ¯Ðº Ð±ÐµÑÐµÑ. Ð¡ÐžÐ· Ð±ÐžÑ Ð±ÐµÑÑÐµÐ³Ðž ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐžÐœ Ð¶Ð°Ð»Ð¿Ñ ÑÐ°ÐœÑ ÐŒÐµÐœÐµÐœ ÐžÐ·ÐŽÓ©Ó© ÐœÐ°ÑÑÐ¹Ð¶Ð°ÑÑÐœÑÐœ Ð¶Ð°Ð»Ð¿Ñ ÑÐ°ÐœÑÐœ ÐžÑÐµÑÑÐµÐ¹ Ð°Ð»Ð°ÑÑÐ·. 
+}
+
+_texttanumbrowseoptions_ [l=ky] {ÐÑÐ» ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŽÐ° ÐžÐ·ÐŽÓ©Ó©Ð»Ó©ÑÐŽÒ¯Ðœ Ð°Ñ ÑÒ¯ÑÐŽÒ¯Ò¯ Ð¶ÐŸÐ»ÐŽÐŸÑÑ Ð±Ð°Ñ (_numbrowseoptions_):}
+
+_textsimplehelpheading_ [l=ky] {ÐÐœÑÐŸÑÐŒÐ°ÑÐžÑÐœÑ ÐºÐ°ÐœÐŽÐ°Ð¹ ÐžÐ·ÐŽÓ©Ó© ÐºÐµÑÐµÐº}
+
+_texthelpscope_ [l=ky] {<p>_iconblankbar_  <a name=scope-of-queries>  <h3 align=left>ÐÐ·ÐŽÓ©Ó© ÐŽÐžÐ°Ð¿Ð°Ð·ÐŸÐœÑ </h3>    <p>ÐÐŸÐ»Ð»ÐµÐºÑÐžÑÐ»Ð°ÑÐŽÑÐœ ÐºÓ©Ð¿ÑÒ¯Ð»Ò¯Ð³Ò¯ÐœÐŽÓ© ÑÐžÐ· Ð°Ñ ÑÒ¯ÑÐŽÒ¯Ò¯ ÐžÐ·ÐŽÓ©Ó© ÐžÐœÐŽÐµÐºÑÑÐµÑÐžÐœ ÐºÐŸÐ»ÐŽÐŸÐœÐŸ Ð°Ð»Ð°ÑÑÐ·. ÐÐžÑÐ°Ð»Ñ, ÐºÐžÑÐµÐ¿ Ð°ÑÐ°Ð»ÑÑÑ, Ð°Ð²ÑÐŸÑÐ»ÐŸÑ ÑÐ°ÐŒÐžÐ»ÐžÑÐ»Ð°ÑÑ ÐžÐœÐŽÐµÐºÑÑÐµÑÐž. ÐÐ» ÑÑÑÑÐ°Ð»ÑÑ Ð¶Ðµ Ð¿Ð°ÑÐ°Ð³ÑÐ°Ñ ÐžÐœÐŽÐµÐºÑÑÐµÑÐž ÐŽÐ° Ð±ÐŸÐ»ÑÑÑ ÐŒÒ¯ÐŒÐºÒ¯Ðœ. Ð­Ð³ÐµÑ ÑÐžÐ· ÐºÐµÑÐµÐºÑÒ¯Ò¯ ÐžÐœÐŽÐµÐºÑÑÐž ÐºÓ©ÑÑÓ©ÑÐ¿Ó©ÑÓ©Ò£Ò¯Ð· Ð°ÐœÐŽÐ° ÑÐºÑÐ°ÐœÐ³Ð° ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐµÑÐŽÐžÐœ Ð±Ð°Ð°ÑÐŽÑÐ³Ñ ÑÑÐ³Ð°ÑÑÐ»Ð°Ñ. Ð­Ð³ÐµÑ ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð±ÐžÑ ÐºÐžÑÐµÐ¿ Ð±ÐŸÐ»ÑÐŸ Ð°ÐœÐŽÐ° Ð°Ð» ÐŸÑÐŸÐ» ÐŸÑÑÐœÐŽÐ°Ðœ Ð°ÑÑÐ»Ð°Ñ.     }
Index: /tags/gsdl-2_61-distribution/gsdl/macros/maori.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/maori.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/maori.dm	(revision 10506)
@@ -0,0 +1,1357 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Maori Language text and icon macros 
+# Many thanks to Te Taka Keegan (translated May 2004)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=mi] {TÄnga Pukapuka}
+_textsource_ [l=mi] {tohutoro pÅ«take:}
+_textdate_ [l=mi] {rÄ tÄnga: }
+_textnumpages_ [l=mi] {e hia ngÄ whÄrangi:}
+
+_textsignin_ [l=mi] {whakauru mai}
+
+_textdefaultcontent_ [l=mi] {KÄore tÅ whÄrangi tono i kitea. PÄwhiritia te pÄtene 'back' i tÅ pÅ«manawa tirotiro, pÄwhiritia rÄnei te pÄtene kÄinga o runga ake kia hoki atu ai ki te
+Greenstone Digital Library.}
+
+_textdefaulttitle_ [l=mi] {He hÄ GSDL}
+
+_textbadcollection_ [l=mi] {KÄore te kohikohinga (called "_cvariable_") e noho mai ana i tÄnei pÅ«naha o Greenstone.}
+
+_textselectpage_ [l=mi] {âKÅwhirihia he WhÄrangiâ}
+
+_collectionextra_ [l=mi] {E _about:numdocs_ ngÄ  tuhinga kei tÄnei kohikohinga.
+He mea hanga _about:builddate_ ngÄ rÄ i mua.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=mi] {<p>Kei tÄnei kohikohinga _numdocs_ _If_("_numdocs_" eq "1",te tuhinga,ngÄ tuhinga), Ä, ko te rahi  _numbytes_ ngÄ bytes.
+<p><a href="_httppagex_(bsummary)">PÄwhiritia tÄnei</a> kia panui ai te pÅ«rongo hanga o tÄnei kohikohinga.
+}
+
+_textimagecollection_ [l=mi] {}
+_textimageabout_ [l=mi] {WhÄrangi whakamÄrama}
+_textimagehome_ [l=mi] {WhÄrangi kÄinga}
+_textimagehelp_ [l=mi] {WhÄrangi Äwhina}
+_textimagepref_ [l=mi] {Te whÄrangi o ngÄ kÅwhiringa}
+_textimagegreenstone_ [l=mi] {Greenstone Digital Library Software}
+_textimageusab_ [l=mi] {He aha ngÄ mea uaua hei whakamahi?}
+
+_textimagesearch_ [l=mi] {rapua he kupu}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=mi] {Tirotiro pÅ«rÄrangi taitara}
+_textimageCreator_ [l=mi] {Tirotiro pÅ«rÄrangi kaitito}
+_textimageSubject_ [l=mi] {Tirotiro kaupapa}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=mi] {Tirotiro whakarÄrangi wÄtaka}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=mi] {Tirotiro ingoa kÅnae taketake}
+_textimageLanguage_ [l=mi] {Tirotiro reo}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=mi] {Tirotiro rÅpÅ«}
+_textimageKeyword_ [l=mi] {Tirotiro kupu matua}
+_textimageHowto_ [l=mi] {Tirotiro Äpure PÄwhea Te}
+_textimageList_ [l=mi] {Tirotiro whakarÄrangi tuhinga}
+_textimageSeries_ [l=mi] {Tirotiro tÄnga pukapuka}
+_textimageTo_ [l=mi] {Tirotiro Äpure Ki a Wai}
+_textimageFrom_ [l=mi] {Tirotiro Äpure NÄ Wai}
+_textimageTopic_ [l=mi] {Tirotiro kaupapa motuhake}
+_textimageBrowse_ [l=mi] {Tirotiro}
+_textimageCollage_ [l=mi] {Tirotiro kÄpunupuni whakaahua}
+_textimagePeople_ [l=mi] {Tirotiro pÅ«rÄrangi tÄngata}
+_textimageAcronym_ [l=mi] {Tirotiro PÅ«tauÄkÄ«}
+_textimagePhrase_ [l=mi] {Tirotiro kÄ«waha}
+_textimageArtist_ [l=mi] {Tirotiro kaitito}
+_textimageVolume_ [l=mi] {Tirotiro pukapuka}
+_textimageCountries_ [l=mi] {Tirotiro whenua}
+_textimageCaptions_ [l=mi] {Tirotiro whakaahua rerekÅrero}
+
+
+_texticontabsearchgreen_ [l=mi] {Rapu}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=mi] {Taitara A-Z}
+_texticontabCreatorgreen_ [l=mi] {Kaitito A-Z}
+_texticontabSubjectgreen_ [l=mi] {Kaupapa}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=mi] {NgÄ RÄ}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=mi] {Ingoa KÅnae}
+_texticontabLanguagegreen_ [l=mi] {Reo}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=mi] {RÅpÅ«}
+_texticontabKeywordgreen_ [l=mi] {Kupu Matua}
+_texticontabhowgreen_ [l=mi] {PÄwhea te}
+_texticontabseriesgreen_ [l=mi] {TÄnga Pukapuka}
+_texticontablistgreen_ [l=mi] {WhakarÄrangi}
+_texticontabtogreen_ [l=mi] {Ki a Wai}
+_texticontabfromgreen_ [l=mi] {NÄ Wai}
+_texticontabtopicgreen_ [l=mi] {Kaupapa}
+_texticontabbrwsegreen_ [l=mi] {Tirotiro}
+_texticontabCollagegreen_ [l=mi] {KÄpunipuni Whakaahua}
+_texticontabbrowsgreen_ [l=mi] {Tirotiro}
+_texticontabPeoplegreen_ [l=mi] {TÄngata A-Z}
+_texticontabAcronymgreen_ [l=mi] {PÅ«tauÄkÄ«}
+_texticontabPhrasegreen_ [l=mi] {KÄ«waha}
+_texticontabArtistgreen_ [l=mi] {Kaitito}
+_texticontabVolumegreen_ [l=mi] {Pukapuka}
+_texticontabCaptionsgreen_ [l=mi] {RerekÅrero}
+_texticontabCountriesgreen_ [l=mi] {Whenua}
+
+_texticontext_ [l=mi] {Tirohia te tuhinga}
+_texticonclosedbook_ [l=mi] {whakatÅ«wheratia te tuhinga nei kia pÄnui ai ngÄ kÅrero}
+_texticonnext_ [l=mi] {titiro ki te whÄrangi o muri}
+_texticonprev_ [l=mi] {titiro ki te whÄrangi o mua}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=mi] {titiro ki te kÅnae MIDI}
+_texticonmsword_ [l=mi] {titiro ki te tuhinga Microsoft Word}
+_texticonmp3_ [l=mi] {titiro ki te kÅnae MP3}
+_texticonpdf_ [l=mi] {titiro ki te tuhinga PDF}
+_texticonps_ [l=mi] {titiro ki te tuhinga Postscript}
+_texticonppt_ [l=mi] {titiro ki te tuhinga PowerPoint}
+_texticonrtf_ [l=mi] {titiro ki te tuhinga RTF}
+_texticonxls_ [l=mi] {Tirohia te kÅnae Microsoft Excel}
+
+_page_ [l=mi] {whÄrangi }
+_pages_ [l=mi] {ngÄ whÄrangi}
+_of_ [l=mi] {i te }
+_vol_ [l=mi] {Pukapuka}
+_num_ [l=mi] {Nama}
+
+_textmonth00_ [l=mi] {}
+_textmonth01_ [l=mi] {Kohi-tÄtea}
+_textmonth02_ [l=mi] {Hui-tanguru}
+_textmonth03_ [l=mi] {PoutÅ«-te-rangi}
+_textmonth04_ [l=mi] {Paenga-whÄehÄ}
+_textmonth05_ [l=mi] {Haratua}
+_textmonth06_ [l=mi] {Pipiri}
+_textmonth07_ [l=mi] {HÅngongoi}
+_textmonth08_ [l=mi] {Here-turi-kÅkÄ}
+_textmonth09_ [l=mi] {Mahuru}
+_textmonth10_ [l=mi] {Whiringa-Ä-nuku}
+_textmonth11_ [l=mi] {Whiringa-Ä-rangi}
+_textmonth12_ [l=mi] {Hakihea}
+
+_textdocument_ [l=mi] {Tuhinga}
+_textsection_ [l=mi] {WÄhanga}
+_textparagraph_ [l=mi] {KÅwae}
+
+_magazines_ [l=mi] {Pukapuka}
+
+_nzdlpagefooter_ [l=mi] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Tari Rorohiko</a>, 
+<a href="http://www.waikato.ac.nz">Te Whare WÄnanga o Waikato</a>, 
+Aotearoa}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "KÄINGA" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=mi] {_httpimg_/mi/chomeof.gif}
+_httpiconchomeon_ [l=mi] {_httpimg_/mi/chomeon.gif}
+
+## "ÄWHINA" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=mi] {_httpimg_/mi/chelpof.gif}
+_httpiconchelpon_ [l=mi] {_httpimg_/mi/chelpon.gif}
+
+## "KÅWHIRINGA" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=mi] {_httpimg_/mi/cprefof.gif}
+_httpiconcprefon_ [l=mi] {_httpimg_/mi/cprefon.gif}
+
+## "WHAKAHOKI KÅRERO MAI" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=mi] {_httpimg_/mi/cusabof.gif}
+_httpiconcusabon_ [l=mi] {_httpimg_/mi/cusabon.gif}
+
+
+## "rapu" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=mi] {_httpimg_/mi/tsrchgr.gif}
+_httpicontsrchof_ [l=mi] {_httpimg_/mi/tsrchof.gif}
+_httpicontsrchon_ [l=mi] {_httpimg_/mi/tsrchon.gif}
+_widthtsrchx_ [l=mi] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "taitara a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=mi] {_httpimg_/mi/ttitlgr.gif}
+_httpiconttitleof_ [l=mi] {_httpimg_/mi/ttitlof.gif}
+_httpiconttitleon_ [l=mi] {_httpimg_/mi/ttitlon.gif}
+_widthttitlex_ [l=mi] {87}
+
+# Not true DC, kept for legacy reasons
+## "kaitito a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=mi] {_httpimg_/mi/tauthgr.gif}
+_httpicontcreatof_ [l=mi] {_httpimg_/mi/tauthof.gif}
+_httpicontcreaton_ [l=mi] {_httpimg_/mi/tauthon.gif}
+_widthtcreatx_ [l=mi] {110}
+
+## "kaupapa" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=mi] {_httpimg_/mi/tsubjgr.gif}
+_httpicontsubjon_ [l=mi] {_httpimg_/mi/tsubjon.gif}
+_httpicontsubjof_ [l=mi] {_httpimg_/mi/tsubjof.gif}
+_widthtsubjx_ [l=mi] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "ngÄ rÄ" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=mi] {_httpimg_/mi/tdategr.gif}
+_httpicontdateof_ [l=mi] {_httpimg_/mi/tdateof.gif}
+_httpicontdateon_ [l=mi] {_httpimg_/mi/tdateon.gif}
+_widthtdatex_ [l=mi] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "ingoa kÅnae" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=mi] {_httpimg_/mi/tsrcgr.gif}
+_httpicontsrcof_ [l=mi] {_httpimg_/mi/tsrcof.gif}
+_httpicontsrcon_ [l=mi] {_httpimg_/mi/tsrcon.gif}
+_widthtsrcx_ [l=mi] {87}
+
+## "reo" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=mi] {_httpimg_/mi/tlanggr.gif}
+_httpicontlangon_ [l=mi] {_httpimg_/mi/tlangon.gif}
+_httpicontlangof_ [l=mi] {_httpimg_/mi/tlangof.gif}
+_widthtlangx_ [l=mi] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "TÄnga Pukapuka" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=mi] {_httpimg_/mi/tsergr.gif}
+_httpicontserof_ [l=mi] {_httpimg_/mi/tserof.gif}
+_httpicontseron_ [l=mi] {_httpimg_/mi/tseron.gif}
+_widthtserx_ [l=mi] {87}
+
+## "ki a" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=mi] {_httpimg_/mi/ttogr.gif}
+_httpiconttoon_ [l=mi] {_httpimg_/mi/ttoon.gif}
+_httpiconttoof_ [l=mi] {_httpimg_/mi/ttoof.gif}
+_widthttox_ [l=mi] {87}
+
+## "nÄ wai" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=mi] {_httpimg_/mi/tfromgr.gif}
+_httpicontfromon_ [l=mi] {_httpimg_/mi/tfromon.gif}
+_httpicontfromof_ [l=mi] {_httpimg_/mi/tfromof.gif}
+_widthtfromx_ [l=mi] {87}
+
+## "rÅpÅ«" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=mi] {_httpimg_/mi/torggr.gif}
+_httpicontorgon_ [l=mi] {_httpimg_/mi/torgon.gif}
+_httpicontorgof_ [l=mi] {_httpimg_/mi/torgof.gif}
+_widthtorgx_ [l=mi] {114}
+
+## "pÄwhea te" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=mi] {_httpimg_/mi/thowgr.gif}
+_httpiconthowon_ [l=mi] {_httpimg_/mi/thowon.gif}
+_httpiconthowof_ [l=mi] {_httpimg_/mi/thowof.gif}
+_widththowx_ [l=mi] {87}
+
+## "kaupapa" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=mi] {_httpimg_/mi/ttopicgr.gif}
+_httpiconttopicon_ [l=mi] {_httpimg_/mi/ttopicon.gif}
+_httpiconttopicof_ [l=mi] {_httpimg_/mi/ttopicof.gif}
+_widthttopicx_ [l=mi] {87}
+
+## "tirotiro" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=mi] {_httpimg_/mi/tbrwsegr.gif}
+_httpicontbrwseon_ [l=mi] {_httpimg_/mi/tbrwseon.gif}
+_httpicontbrwseof_ [l=mi] {_httpimg_/mi/tbrwseof.gif}
+_widthtbrwsex_ [l=mi] {87}
+
+## "kÄpunipuni whakaahua" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=mi] {_httpimg_/mi/tcollgr.gif}
+_httpicontcollof_ [l=mi] {_httpimg_/mi/tcollof.gif}
+_httpicontcollon_ [l=mi] {_httpimg_/mi/tcollon.gif}
+_widthtcollx_ [l=mi] {87}
+
+## "tÄngata" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=mi] {_httpimg_/mi/tpeopgr.gif}
+_httpicontpeopof_ [l=mi] {_httpimg_/mi/tpeopof.gif}
+_httpicontpeopon_ [l=mi] {_httpimg_/mi/tpeopon.gif}
+_widthtpeopx_ [l=mi] {97}
+
+## "pÅ«tauÄkÄ«" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=mi] {_httpimg_/mi/tacrogr.gif}
+_httpicontacroof_ [l=mi] {_httpimg_/mi/tacroof.gif}
+_httpicontacroon_ [l=mi] {_httpimg_/mi/tacroon.gif}
+_widthtacrox_ [l=mi] {87}
+
+## "kÄ«waha" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=mi] {_httpimg_/mi/tphrsegr.gif}
+_httpicontphrseof_ [l=mi] {_httpimg_/mi/tphrseof.gif}
+_httpicontphrseon_ [l=mi] {_httpimg_/mi/tphrseon.gif}
+_widthtphrsex_ [l=mi] {87}
+
+## "kaitito" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=mi] {_httpimg_/mi/tartstgr.gif}
+_httpicontartstof_ [l=mi] {_httpimg_/mi/tartstof.gif}
+_httpicontartston_ [l=mi] {_httpimg_/mi/tartston.gif}
+_widthtartstx_ [l=mi] {87}
+
+## "kupu matua" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=mi] {_httpimg_/mi/tkwgr.gif}
+_httpicontkwof_ [l=mi] {_httpimg_/mi/tkwof.gif}
+_httpicontkwon_ [l=mi] {_httpimg_/mi/tkwon.gif}
+_widthtkwx_ [l=mi] {87}
+
+## "pukapuka" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=mi] {_httpimg_/mi/tvolgr.gif}
+_httpicontvolof_ [l=mi] {_httpimg_/mi/tvolof.gif}
+_httpicontvolon_ [l=mi] {_httpimg_/mi/tvolon.gif}
+_widthtvolx_ [l=mi] {87}
+
+## "rerekÅrero" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=mi] {_httpimg_/mi/tcaptgr.gif}
+_httpicontcaptof_ [l=mi] {_httpimg_/mi/tcaptof.gif}
+_httpicontcapton_ [l=mi] {_httpimg_/mi/tcapton.gif}
+_widthtcaptx_ [l=mi] {87}
+
+## "whenua" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=mi] {_httpimg_/mi/tcountgr.gif}
+_httpicontcountof_ [l=mi] {_httpimg_/mi/tcountof.gif}
+_httpicontcounton_ [l=mi] {_httpimg_/mi/tcounton.gif}
+_widthtcountx_ [l=mi] {87}
+
+## "Äwhina" ## green_title ## h_help ##
+_httpiconhhelp_ [l=mi] {_httpimg_/mi/h\_help.gif}
+_widthhhelp_ [l=mi] {200}
+_heighthhelp_ [l=mi] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=mi] {He kupu whakamÄrama i te kohikohinga nei}
+
+_textsubcols1_ [l=mi] {<p>Kei te kohinga-whÄnui nei e  _1_ ngÄ kohinga-whÄiti. 
+Ko ngÄ kohinga-whÄiti e wÄtea ana mÄu:
+<blockquote>}
+
+_textsubcols2_ [l=mi] {</blockquote>
+Kei te WhÄrangi Whiringa e taea ana e koe te whakarite ko Äwhea ngÄ kohinga-whÄiti mÄu.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "e pÄ ana" ## green_title ## h_about ##
+_httpiconhabout_ [l=mi] {_httpimg_/mi/h\_about.gif}
+_widthhabout_ [l=mi] {200}
+_heighthabout_ [l=mi] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=mi] {Taitara A-Z}
+_texticonhcreat_ [l=mi] {Kaitito A-Z}
+_texticonhsubj_ [l=mi] {Kaupapa}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=mi] {NgÄ RÄ}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=mi] {Ingoa KÅnae}
+_texticonhlang_ [l=mi] {NgÄ Reo}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+_texticonhcoll_ [l=mi] {KÄpunipuni Whakaahua}
+_texticonhto_ [l=mi] {Ki a Wai}
+_texticonhfrom_ [l=mi] {NÄ wai}
+_texticonhser_ [l=mi] {TÄnga Pukapuka}
+_texticonhhow_ [l=mi] {PÄwhea te}
+_texticonhorg_ [l=mi] {RÅpÅ«}
+_texticonhbrwse_ [l=mi] {Tirotiro}
+_texticonhbrows_ [l=mi] {Tirotiro}
+_texticonhpeople_ [l=mi] {TÄngata A-Z}
+_texticonhacronym_ [l=mi] {PÅ«tauÄkÄ«}
+_texticonhphrases_ [l=mi] {KÄ«waha}
+_texticonhartist_ [l=mi] {Kaitito}
+_texticonhkw_ [l=mi] {Kupu Matua}
+_texticonhvol_ [l=mi] {Pukapuka}
+_texticonhcapt_ [l=mi] {RerekÅrero}
+_texticonhcount_ [l=mi] {Whenua}
+
+_texticonopenbookshelf_ [l=mi] {kÄtia tÄnei wÄhanga}
+_texticonclosedbookshelf_ [l=mi] {whakatÅ«whera mai tÄnei wÄhanga hei tirotiro ai}
+_texticonopenbook_ [l=mi] {kÄtia tÄnei pukapuka}
+_texticonclosedfolder_ [l=mi] {whakatÅ«whera mai tÄnei kÅpaki hei tirotiro ai}
+_texticonclosedfolder2_ [l=mi] {whakatÅ«whera mai te wÄhanga iti nei}
+_texticonopenfolder_ [l=mi] {katia tÄnei kÅpaki}
+_texticonopenfolder2_ [l=mi] {katia tÄnei wÄhanga-iti}
+_texticonsmalltext_ [l=mi] {Tirohia tÄnei wÄhanga o ngÄ kupu tuhituhi}
+_texticonsmalltext2_ [l=mi] {tirohia kupu tuhituhi}
+_texticonpointer_ [l=mi] {wÄhanga e tiro ana}
+_texticondetach_ [l=mi] {Huakina mai he matapihi hou kia noho motuhake ai tÄnei kÅrero}
+_texticonhighlight_ [l=mi] {Kia pÅ«kaha ngÄ kupu rapu}
+_texticonnohighlight_ [l=mi] {Kia kore-pÅ«kaha ngÄ kupu rapu}
+_texticoncontracttoc_ [l=mi] {Whakaitihia te whakarÄrangi kaupapa}
+_texticonexpandtoc_ [l=mi] {Whakanuia te whakarÄrangi kaupapa}
+_texticonexpandtext_ [l=mi] {Titiro ki ngÄ kupu katoa}
+_texticoncontracttext_ [l=mi] {Titiro ki ngÄ kupu anakÄ o te wÄhanga kua kÅwhiritia}
+_texticonwarning_ [l=mi] {<b>Kia TÅ«pato: </b>}
+_texticoncont_ [l=mi] {haere tonu?}
+
+_textltwarning_ [l=mi] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Ki te whakanui koe i ngÄ kupu tuhituhi i konei ka nui rawa ngÄ kÅrero hei whakaatu mai ki runga i te mata o te rorohiko_imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=mi] {poka noa ki}
+_textintro_ [l=mi] {<i>(kÅrero whakataki)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "taitara a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=mi] {_httpimg_/mi/h\_title.gif}
+_widthhtitle_ [l=mi] {200}
+_heighthtitle_ [l=mi] {57}
+
+# Not true DC, kept for legacy reasons
+## "kaitito a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=mi] {_httpimg_/mi/h\_auth.gif}
+_widthhcreat_ [l=mi] {200}
+_heighthcreat_ [l=mi] {57}
+
+## "kaupapa" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=mi] {_httpimg_/mi/h\_subj.gif}
+_widthhsubj_ [l=mi] {200}
+_heighthsubj_ [l=mi] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "ngÄ rÄ" ## green_title ## h_date ##
+_httpiconhdate_ [l=mi] {_httpimg_/mi/h\_date.gif}
+_widthhdate_ [l=mi] {200}
+_heighthdate_ [l=mi] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "ingoa kÅnae" ## green_title ## h_src ##
+_httpiconhsrc_ [l=mi] {_httpimg_/mi/h\_src.gif}
+_widthhsrc_ [l=mi] {200}
+_heighthsrc_ [l=mi] {57}
+
+## "ngÄ reo" ## green_title ## h_lang ##
+_httpiconhlang_ [l=mi] {_httpimg_/mi/h\_lang.gif}
+_widthhlang_ [l=mi] {200}
+_heighthlang_ [l=mi] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "ki a" ## green_title ## h_to ##
+_httpiconhto_ [l=mi] {_httpimg_/mi/h\_to.gif}
+_widthhto_ [l=mi] {200}
+_heighthto_ [l=mi] {57}
+
+## "nÄ wai" ## green_title ## h_from ##
+_httpiconhfrom_ [l=mi] {_httpimg_/mi/h\_from.gif}
+_widthhfrom_ [l=mi] {200}
+_heighthfrom_ [l=mi] {57}
+
+## "tÄnga pukapuka" ## green_title ## h_ser ##
+_httpiconhser_ [l=mi] {_httpimg_/mi/h\_ser.gif}
+_widthhser_ [l=mi] {200}
+_heighthser_ [l=mi] {57}
+
+## "pÄwhea te" ## green_title ## h_how ##
+_httpiconhhow_ [l=mi] {_httpimg_/mi/h\_how.gif}
+_widthhhow_ [l=mi] {200}
+_heighthhow_ [l=mi] {57}
+
+## "kaupapa" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=mi] {_httpimg_/mi/h\_topic.gif}
+_widthhtopic_ [l=mi] {200}
+_heighthtopic_ [l=mi] {57}
+
+## "rÅpÅ«" ## green_title ## h_org ##
+_httpiconhorg_ [l=mi] {_httpimg_/mi/h\_org.gif}
+_widthhorg_ [l=mi] {250}
+_heighthorg_ [l=mi] {57}
+
+## "tirotiro" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=mi] {_httpimg_/mi/h\_brwse.gif}
+_widthhbrwse_ [l=mi] {200}
+_heighthbrwse_ [l=mi] {57}
+
+# -- Missing translation: h_coll
+_httpiconhcoll_ [l=mi] {_httpimg_/mi/h\_coll.gif}
+_widthhcoll_ [l=mi] {200}
+_heighthcoll_ [l=mi] {57}
+
+## "tÄngata" ## green_title ## h_people ##
+_httpiconhpeople_ [l=mi] {_httpimg_/mi/h\_people.gif}
+_widthhpeople_ [l=mi] {200}
+_heighthpeople_ [l=mi] {57}
+
+## "pÅ«tauÄkÄ«" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=mi] {_httpimg_/mi/h\_acro.gif}
+_widthhacronym_ [l=mi] {200}
+_heighthacronym_ [l=mi] {57}
+
+## "kÄ«waha" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=mi] {_httpimg_/mi/h\_phrse.gif}
+_widthhphrse_ [l=mi] {200}
+_heighthphrse_ [l=mi] {57}
+
+## "kaitito" ## green_title ## h_artist ##
+_httpiconhartist_ [l=mi] {_httpimg_/mi/h\_artist.gif}
+_widthhartist_ [l=mi] {200}
+_heighthartist_ [l=mi] {57}
+
+## "kupu matua" ## green_title ## h_kw ##
+_httpiconhkw_ [l=mi] {_httpimg_/mi/h\_kw.gif}
+_widthhkw_ [l=mi] {200}
+_heighthkw_ [l=mi] {57}
+
+## "pukapuka" ## green_title ## h_vol ##
+_httpiconhvol_ [l=mi] {_httpimg_/mi/h\_vol.gif}
+_widthhvol_ [l=mi] {200}
+_heighthvol_ [l=mi] {57}
+
+## "whenua" ## green_title ## h_count ##
+_httpiconhcount_ [l=mi] {_httpimg_/mi/h\_count.gif}
+_widthhcount_ [l=mi] {200}
+_heighthcount_ [l=mi] {57}
+
+## "rerekÅrero" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=mi] {_httpimg_/mi/h\_capt.gif}
+_widthhcapt_ [l=mi] {200}
+_heighthcapt_ [l=mi] {57}
+
+
+## "HAERE TONU??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=mi] {_httpimg_/mi/contof.gif}
+_httpiconconton_ [l=mi] {_httpimg_/mi/conton.gif}
+
+## "WHAKANUI\nKUPU TUHITUHI" ## document_button ## eallt ##
+_httpiconealltof_ [l=mi] {_httpimg_/mi/ealltof.gif}
+_httpiconeallton_ [l=mi] {_httpimg_/mi/eallton.gif}
+
+## "WHAKAITI\nWHAKARÄRANGI\nKAUPAPA" ## document_button ## econc ##
+_httpiconeconcof_ [l=mi] {_httpimg_/mi/econcof.gif}
+_httpiconeconcon_ [l=mi] {_httpimg_/mi/econcon.gif}
+
+## "WHAKAWEHE" ## document_button ## edtch ##
+_httpiconedtchof_ [l=mi] {_httpimg_/mi/edtchof.gif}
+_httpiconedtchon_ [l=mi] {_httpimg_/mi/edtchon.gif}
+
+## "WHAKANUI\nWHAKARÄRANGI\nKAUPAPA" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=mi] {_httpimg_/mi/eexpcof.gif}
+_httpiconeexpcon_ [l=mi] {_httpimg_/mi/eexpcon.gif}
+
+## "WHAKAITI\nKUPU TUHITUHI" ## document_button ## etsec ##
+_httpiconetsecof_ [l=mi] {_httpimg_/mi/etsecof.gif}
+_httpiconetsecon_ [l=mi] {_httpimg_/mi/etsecon.gif}
+
+## "PÅªKAHA" ## document_button ## ehl ##
+_httpiconehlof_ [l=mi] {_httpimg_/mi/ehlof.gif}
+_httpiconehlon_ [l=mi] {_httpimg_/mi/ehlon.gif}
+
+## "KORE-PÅªKAHA" ## document_button ## enhl ##
+_httpiconenhlof_ [l=mi] {_httpimg_/mi/enhlof.gif}
+_httpiconenhlon_ [l=mi] {_httpimg_/mi/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=mi] {_If_(_thislast_,kitenga _thisfirst_ - _thislast_ mÅ te rapu: _cgiargq_,kÄore he kitenga mÅ: _cgiargq_)}
+_textnoquerytitle_ [l=mi] {WhÄrangi rapu}
+
+_texticonthispage_ [l=mi] {rapu}
+_textsome_ [l=mi] {Ätehi}
+_textall_ [l=mi] {te katoa}
+_textboolean_ [l=mi] {te boolean}
+_textranked_ [l=mi] {ranked}
+_textnatural_ [l=mi] {aunoa}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=mi] {}
+_texticonsearchhistorybar_ [l=mi] {hÄ«tori rapu}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=mi] {whakamahia tÄnei rapunga}
+_textfreqmsg1_ [l=mi] {Kia hia ngÄ kupu: }
+_textpostprocess_ [l=mi] {_If_(_quotedquery_,<br><i>kua rapu tuaruatia kia puta ko te _quotedquery_</i>
+)}
+_textinvalidquery_ [l=mi] {kua hÄ te tuhi rapu}
+
+_textmorethan_ [l=mi] {Neke atu i te }
+_textapprox_ [l=mi] {E pÄ ana}
+_textnodocs_ [l=mi] {kÄore he kitenga e pÄ ana ki Äu kupu rapu.}
+_text1doc_ [l=mi] {1 te pukapuka e pÄ ana ki Äu kupu rapu.}
+_textlotsdocs_ [l=mi] {ngÄ pukapuka e pÄ ana ki Äu kupu rapu.}
+_textmatches_ [l=mi] {Kitenga }
+_textbeginsearch_ [l=mi] {Rapua}
+_textrunquery_ [l=mi] {Tukua te Rapu}
+_textclearform_ [l=mi] {Åªkui ngÄ kupu}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=mi] {he kupu, he kÄ«waha rÄnei}
+_textinfield_ [l=mi] {âŠ i te Äpure}
+_textfoldstem_ [l=mi] {(pÅ«matua/pÅ«titi, kÅ«muri)}
+
+_textadvquery_ [l=mi] {Me tuhi kau noa rÄnei i ngÄ kupu rapu:}
+_textallfields_ [l=mi] {ngÄ Äpure katoa}
+_texttextonly_ [l=mi] {kore-whakaahua}
+_textand_ [l=mi] {me te}
+_textor_ [l=mi] {rÄnei}
+_textandnot_ [l=mi] {me te kore}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=mi] {Tirohia ki _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, at _gselection_ level)_If_(_nselection_, in _nselection_ language) mÅ _querytypeselection_ o ngÄ kupu}
+
+_textadvancedsearch_ [l=mi] {"Rapu _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_,ki te _gselection_ level )_If_(_nselection_,in _nselection_ language )ki te _querytypeselection_ query}
+
+_textformsimplesearch_ [l=mi] {Rapu _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )mÅ _formquerytypeselection_ i te}
+
+_textformadvancedsearch_ [l=mi] {Rapu_If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language ) whakaatu mai ngÄ kitenga ki _formquerytypeselection_ order}
+
+
+_textnojsformwarning_ [l=mi] {Warning: Javascript is disabled in your web browser. <br>To use form searching, please enable it.}
+_textdatesearch_ [l=mi] {Kei tÄnei kohikohinga e taea ana te rapu i ngÄ tuhinga i puta mai ai i tÄtehi wÄ,i tÄtehi rÄ rÄnei. He Ähuatanga tÄnei e taea ana te whakaÅ« ki te mahi rapu.}
+_textstartdate_ [l=mi] {RÄ (tÄ«mata):}
+_textenddate_ [l=mi] {RÄ mutunga}
+_textbc_ [l=mi] {B.C.E.}
+_textad_ [l=mi] {C.E.}
+_textexplaineras_ [l=mi] {E Årite ana te C.E. me te B.C.E ki te A.D. me te B.C. arÄ i mua, i muri rÄnei i te whÄnau mai o Ihu Karaiti. He pÅ«tauÄkÄ« mÅ te "Common Era" me te "Before the Common Era", Ä, he mea kore whakararu i tÄtehi hÄhi o te ao.}
+
+_textstemon_ [l=mi] {(hei aha te kÅ«muri)}
+
+_textsearchhistory_ [l=mi] {HÄ«tori Rapu}
+
+#text macros for search history
+_textnohistory_ [l=mi] {kÄore he hÄ«tori rapu}
+_texthresult_ [l=mi] {kitenga}
+_texthresults_ [l=mi] {ngÄ kitenga}
+_texthallwords_ [l=mi] {kupu katoa}
+_texthsomewords_ [l=mi] {Ätehi kupu}
+_texthboolean_ [l=mi] {boolean}
+_texthranked_ [l=mi] {ranked}
+_texthcaseon_ [l=mi] {kia tika ngÄ pÅ« matua me ngÄ pÅ« iti}
+_texthcaseoff_ [l=mi] {hei aha te pÅ«matua me te pÅ«iti}
+_texthstemon_ [l=mi] {hei aha te kÅ«muri}
+_texthstemoff_ [l=mi] {kia tika te kÅ«muri}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "rapu" ## green_title ## h_search ##
+_httpiconhsearch_ [l=mi] {_httpimg_/mi/h\_search.gif}
+_widthhsearch_ [l=mi] {200}
+_heighthsearch_ [l=mi] {57}
+
+## "kitenga" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=mi] {_httpimg_/mi/qryresb.gif}
+_widthqryresb_ [l=mi] {_pagewidth_}
+_heightqryresb_ [l=mi] {17}
+
+## "hÄ«tori" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=mi] {_httpimg_/mi/schhistb.gif}
+_widthsrchhistb_ [l=mi] {_pagewidth_}
+_heightsrchhistb_ [l=mi] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=mi] {Kua whakaÅ« ngÄ kÅwhiringa engari kaua kÄ e whakamahia te pÄtene
+"back" i tÅ pÅ«tirotiro (browser) - i te mea ka ngaro aua kÅwhiringa! Me pÄwhiri kÄtia tÄtehi pÄtene o runga ake nei.
+}
+_textsetprefs_ [l=mi] {whakamaua kÅwhiringa}
+_textsearchprefs_ [l=mi] {KÅwhiringa Rapu}
+_textcollectionprefs_ [l=mi] {KÅwhiringa kohikohinga}
+_textpresentationprefs_ [l=mi] {KÅwhiringa Whakaaturanga}
+_textpreferences_ [l=mi] {KÅwhiringa}
+_textcasediffs_ [l=mi] {PÅ« matua me te pÅ« iti:}
+_textignorecase_ [l=mi] {hei aha te pÅ« matua me te pÅ« iti}
+_textmatchcase_ [l=mi] {me tika te pÅ« matua me te pÅ« iti}
+_textwordends_ [l=mi] {KÅ«muri:}
+_textstem_ [l=mi] {hei aha te kÅ«muri}
+_textnostem_ [l=mi] {me tika te kÅ«muri}
+_textprefop_ [l=mi] {Whakahokia mai te _maxdocoption_ kupu, Ä, kia _hitsperpageoption_ kupu ki ia whÄrangi.}
+_textextlink_ [l=mi] {WhakapÄ atu ki ngÄ whÄrangi WWW:}
+_textintlink_ [l=mi] {Kua tikina ngÄ tuhinga mai i te:}
+_textlanguage_ [l=mi] {reo tauwhiti }
+_textencoding_ [l=mi] {Whakatakotoranga pÅ«: }
+_textformat_ [l=mi] {Whakatakotoranga tauwhiti: }
+_textall_ [l=mi] {katoa}
+_textquerymode_ [l=mi] {TÅ«momo rapu:}
+_textsimplemode_ [l=mi] {te rapu ngÄwari}
+_textadvancedmode_ [l=mi] {te rapu matatau (ka taea te whakamahi i ngÄ pÅ« boolean, 
+pÄrÄ i te '!', '&', '|', me te '()' hoki)}
+_textlinkinterm_ [l=mi] {mÄ tÄtehi whÄrangi takawaenga}
+_textlinkdirect_ [l=mi] {haere tÅtika ki reira}
+_textdigitlib_ [l=mi] {te whare pukapuka hiko}
+_textweb_ [l=mi] {te web}
+_textgraphical_ [l=mi] {Whakaahua}
+_texttextual_ [l=mi] {kore-whakaahua}
+_textcollectionoption_ [l=mi] {<p>
+Kohikohinga-whÄiti hei rauika mai:
+<br>}
+
+_textrelateddocdisplay_ [l=mi] {whakaatu mai ngÄ tuhinga e hÄngai ana}
+_textsearchhistory_ [l=mi] {HÄ«tori rapu:}
+_textnohistory_ [l=mi] {KÄore he hÄ«tori rapu}
+_texthistorydisplay_ [l=mi] {whakaatu mai kia _historynumrecords_ ngÄ rapunga kua tukua}
+_textnohistorydisplay_ [l=mi] {kaua e whakaatu mai i te hÄ«tori rapu}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=mi] {Rapu me te Äta whakarite:}
+_textplainsearch_ [l=mi] {Rapu ngÄwari}
+_textqueryboxsize_ [l=mi] {Te rahi o te pouaka rapu:}
+_textregbox_ [l=mi] {pouaka rapu iti}
+_textbigbox_ [l=mi] {pouaka rapu nui}
+_textformtype_ [l=mi] {TÅ«momo Rapu:}
+_textsimple_ [l=mi] {ngÄwari}
+_textadvanced_ [l=mi] {matatau}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=mi] {me te}
+_textfields_ [l=mi] {ngÄ Äpure}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "kÅwhiringa" ## green_title ## h_pref ##
+_httpiconhpref_ [l=mi] {_httpimg_/mi/h\_pref.gif}
+_widthhpref_ [l=mi] {200}
+_heighthpref_ [l=mi] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=mi] {KÅmaka tuhinga ki te}
+_textalsoshowing_ [l=mi] {whakaatu mai ana hoki }
+_textwith_ [l=mi] {kaua e rahi ake i te}
+_textdocsperpage_ [l=mi] {tuhinga ki ia whÄrangi}
+
+_textfilterby_ [l=mi] {Rapua he tuhinga e mau ana i te}
+_textall_ [l=mi] {katoa}
+_textany_ [l=mi] {Ätehi}
+_textwords_ [l=mi] {o ngÄ kupu}
+_textleaveblank_ [l=mi] {waiho tÄnei pouaka e wÄtea ana kia puta mai te katoa o ngÄ tuhinga}
+
+_browsebuttontext_ [l=mi] {KÅmaka Tuhinga}
+
+_nodata_ [l=mi] {<i>kÄore he kÅrero</i>}
+_docs_ [l=mi] {tuhinga}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=mi] {Äwhina}
+_textSearchshort_ [l=mi] {rapua he kupu}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=mi] {tirohia te whakarÄrangi taitara}
+_textCreatorshort_ [l=mi] {tirohia whakarÄrangi kaitito}
+_textSubjectshort_ [l=mi] {tirohia te whakarÄrangi kaupapa}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=mi] {tirohia te whakarÄrangi e pÄ ana ki ngÄ rÄ}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=mi] {tirohia te whakarÄrangi ingoa kÅnae}
+_textLanguageshort_ [l=mi] {tirohia te whakarÄrangi reo}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=mi] {tirohia te whakarÄrangi tÄnga pukapuka}
+_textToshort_ [l=mi] {tirohia te whakarÄrangi Ki a Wai}
+_textFromshort_ [l=mi] {tirohia te whakarÄrangi NÄ Wai}
+_textBrowseshort_ [l=mi] {tirohia tÄnga pukapuka}
+_textOrganizationshort_ [l=mi] {tirohia te whakarÄrangi rÅpÅ«}
+_textHowtoshort_ [l=mi] {triohia te whakarÄrangi "pÄwhea te"}
+_textTopicshort_ [l=mi] {tirohia te whakarÄrangi kaupapa}
+_textPeopleshort_ [l=mi] {tirohia te whakarÄrangi tÄngata}
+_textAcronymshort_ [l=mi] {tirohia te whakarÄrangi pÅ«tauÄkÄ«}
+_textPhraseshort_ [l=mi] {tirotiro ngÄ kÄ«waha i ngÄ tuhinga}
+_textArtistshort_ [l=mi] {tirohia te whakarÄrangi kaitito}
+_textKeywordshort_ [l=mi] {tirohia te whakarÄrangi kupu matua}
+_textVolumeshort_ [l=mi] {tirohia te whakarÄrangi pukaupuka}
+_textCountriesshort_ [l=mi] {tirohia whakarÄrangi whenua}
+_textdefaultshorttext_ [l=mi] {tirohia te whakarÄrangi kore-mÅhio}
+
+_textSearchlong_ [l=mi] {<p>Ko te whÄrangi rapu te whÄrangi <i>e rapu atu ai ngÄ kupu</i> i roto i ngÄ tuhinga. Ka puta mai ai tÄnei whÄrangi i te tÄ«matanga, Ä, mehemea kua hipa te whÄrangi rapu pÄwhiritia te pÄtene <i>rapu</i> kia puta mai anÅ ai.
+}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi taitara</i> pÄwhiritia te pÄtene 
+<i>taitara a -z</i>. Ka puta mai te pÅ«rÄrangi o ngÄ
+tuhinga e pÄ ana ki ngÄ taitara.
+}
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=mi] {<p>Kia <i>tirohia ngÄ tuhinga e pÄ ana ki te kaitito</i> pÄwhiritia te
+pÄtene <i>kaitito</i>. Ka puta mai he whakarÄrangi e pÄ ana ki ngÄ ingoa kaitito.}
+
+_textSubjectlong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi kaupapa</i> pÄwhiritia te pÄtene 
+<i>kaupapa</i>. Ka puta mai te whakarÄrangi o ngÄ
+tuhinga e pÄ ana ki ngÄ kaupapa.
+}
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi e pÄ ana ki te wÄ</i> pÄwhiritia te
+pÄtene <i>wÄtaka</i>. Ka puta mai te whakarÄrangi o ngÄ tuhinga
+e pÄ ana ki te wÄ i puta mai ai aua tuhinga. }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi ingoa kÅnae</i> pÄwhiritia te pÄtene <i>ingoa kÅnae</i>. Ka puta mai te whakarÄrangi o ngÄ tuhinga e pÄ ana ki ngÄ ingoa kÅnae.
+}
+
+_textLanguagelong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi reo</i> pÄwhiritia te pÄtene <i>Reo</i>.  Ka puta mai te whakarÄrangi tuhinga e pÄ ana ki ngÄ reo.  }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi rÅpÅ«</i> pÄwhiritia te pÄtene <i>RÅpÅ«</i>.  Ka puta mai te whakarÄrangi tuhinga e pÄ ana ki ngÄ rÅpÅ«.  }
+
+_textHowtolong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi "pÄwhea te"</i> pÄwhiritia te pÄtene <i>PÄwhea te</i>.  Ka puta mai he whakarÄrangi e pÄ ana ki ngÄ whakamÄrama i ngÄ mahi.  }
+
+_textTopiclong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi kaupapa</i> pÄwhiritia te pÄtene 
+<i>kaupapa</i>. Ka puta mai te whakarÄrangi o ngÄ
+tuhinga e pÄ ana ki ngÄ kaupapa.
+}
+
+_textTolong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi Ki a Wai</i> pÄwhiritia te pÄtene 
+<i>Ki a Wai</i>. Ka puta mai te whakarÄrangi o ngÄ
+tuhinga e pÄ ana ki ngÄ kaiwhiwhi tuhinga.
+}
+
+_textFromlong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi kaituku</i> pÄwhiritia te pÄtene <i>NÄ wai</i>.  Ka puta mai te whakarÄrangi tuhinga e pÄ ana ki ngÄ kaituku.  }
+
+_textSerieslong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi tÄnga pukapuka</i> pÄwhiritia te pÄtene 
+<i>tÄnga pukapuka</i>. Ka puta mai te whakarÄrangi o ngÄ
+tuhinga e pÄ ana ki ngÄ tÄnga pukapuka.
+}
+
+_textBrowselong_ [l=mi] {<p>Kia <i>tirohia tÄnga pukapuka</i> pÄwhiritia te pÄtene
+<i>tirotiro</i>.  }
+
+_textPeoplelong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi tÄngata</i> pÄwhiritia te pÄtene <i>TÄngata</i>.  Ka puta mai te whakarÄrangi tuhinga e pÄ ana ki ngÄ ingoa whÄnau o ngÄ tÄngata.  }
+
+_textAcronymlong_ [l=mi] {<p>Kia <i>tirohia ngÄ tuhinga e pÄ ana ki te pÅ«tauÄkÄ«</i> pÄwhiritia te
+pÄtene <i>pÅ«tauÄkÄ«</i>. Ka puta mai te whakarÄrangi o ngÄ pÅ«tauÄkÄ«
+me te wÄhi e noho mai ai i te tuhinga nei.}
+
+_textPhraselong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi kÄ«waha</i> pÄwhiritia te pÄtene <i>KÄ«waha</i>.  Ka puta mai te whakarÄrangi tuhinga e pÄ ana ki ngÄ kÄ«waha.  }
+
+_textArtistlong_ [l=mi] {<p>Kia <i>tirohia ngÄ tuhinga e pÄ ana ki te kaitito</i> pÄwhiritia te
+pÄtene <i>kaitito</i>. Ka puta mai he whakarÄrangi e pÄ ana ki ngÄ ingoa kaitito.}
+
+_textKeywordlong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi kupu matua</i> pÄwhiritia te pÄtene <i>Kupu Matua</i>.  Ka puta mai te whakarÄrangi tuhinga e pÄ ana ki ngÄ kupu matua.  }
+
+_textVolumelong_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi pukapuka</i> pÄwhiritia te pÄtene 
+<i>pukapuka</i>. Ka puta mai te whakarÄrangi o ngÄ
+pukapuka.
+}
+
+_textCaptionslong_ [l=mi] {<p>Kia <i>tirohia ngÄ tuhinga e pÄ ana ki te rerekÅrero</i> pÄwhiritia te
+pÄtene <i>rerekÅrero</i>. Ka puta mai he whakarÄrangi e pÄ ana ki ngÄ rerekÅrero.}
+
+_textCountrieslong_ [l=mi] {<p>Kia <i>tirohia ngÄ tuhinga e pÄ ana ki te whenua</i> pÄwhiritia te
+pÄtene <i>whenua</i>. Ka puta mai he whakarÄrangi e pÄ ana ki ngÄ whenua.}
+
+
+_textdefaultlongtext_ [l=mi] {<p>Kia <i>tirohia te whakarÄrangi pukapuka</i> pÄwhiritia te pÄtene 
+<i>kore-mÅhio</i>. Ka puta mai te whakarÄrangi o ngÄ
+pukapuka.
+}
+
+_texthelptopics_ [l=mi] {<h2 align=left>Kaupapa</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">NgÄ Huarahi Rapu KÅrero</a>
+<ul>
+  <li><a href="\#query-terms">NgÄ Kupu Rapu</a>
+  <li><a href="\#query-type">NgÄ TÅ«momo Rapunga</a>
+  <li><a href="\#scope-of-queries">Te WhÄnui o te Rapu</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">NgÄ KÅwhiringa Kohikohinga</a>
+  <li><a href="\#lang-prefs">NgÄ KÅwhiringa Reo</a>
+  <li><a href="\#pres-prefs">NgÄ KÅwhiringa Whakaaturanga</a>
+  <li><a href="\#search-prefs">NgÄ KÅwhiringa Rapu</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=mi] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=mi] {NgÄ huarahi hei pÄnui tuhinga}
+
+_texthelpreadingdocs_ [l=mi] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Ka kite atu koe i tÄtehi taitara, i tÄtehi whakaahua iti rÄnei i 
+runga ake ki te taha mÄui ka mÅhio koe kei te pÄnui tuhinga. I 
+Ätehi kohikohinga ka kite atu hoki i te rÄrangi kaupapa, i Ätehi 
+atu kohinga ko ngÄ pÄtene haere whakamua (whakamuri) noa 
+iho rÄnei. I te rÄrangi kaupapa e pÅ«kaha ana te wÄhanga pÄnui, Ä, 
+e taea ana te whakatuwhera, te kÄti rÄnei i ngÄ kÅpaki. 
+PÄwhiritia te whakaahua pukapuka kia kÄti ai te tuhinga.</p>
+
+<p>Kei raro ko ngÄ kupu tuhituhi o taua wÄhanga o te tuhinga. 
+Kei raro rÄ anÅ ko te pÄtene haere whakamua i te tuhinga me 
+te pÄtene haere whakamuri i te tuhinga.</p>
+
+ <p>Kei runga ake Ätehi atu pÄtene whakahaere. PÄwhiritia te
+<i>WHAKANUI KUPU TUHITUHI</i> kia kite atu ai i ngÄ kupu 
+tuhituhi katoa. Kia tÅ«pato, i Ätehi wÄ he nui rawa Änei kupu! 
+PÄwhiritia te <i>WHAKANUI WHAKARÄRANGI KAUPAPA</i> 
+kia kite atu ai i ngÄ kaupapa me ngÄ taitara katoa o taua tuhinga. 
+PÄwhiritia te <i>WHAKAWEHE</i> kia puta mai ai ngÄ kÅrero nei
+ki tÄtehi matapihi hou. (He pai tÄnei mÅ te titiro ki ngÄ tuhinga e rua 
+i te wÄ kotahi.) Hei whakamutunga, mehemea ka rapu kupu, ka 
+noho pÅ«kaha aua kupu i roto i te tuhinga. PÄwhiritia te 
+<i>KORE PÅªKAHA</i> kia tango ai te pÅ«kaha o aua kupu.</p>
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>WhakatÅ«whera mai Änei pukapuka</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>WhakatÅ«whera/KÄti tÄnei pukapuka</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>Tirohia tÄnei wÄhanga tuhituhi</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Whakaatu mai ngÄ kupu tuhituhi katoa, kÄore rÄnei</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Whakanuia WhakarÄrangi Kaupapa, kÄore rÄnei</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>WhakatÅ«whera mai tÄnei whÄrangi ki te matapihi hou</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>PÅ«kaha ngÄ kupu rapu, kÄore rÄnei</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>PÄwhiritia tÄnei pere kia haere whakamua ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... pÄwhiritia tÄnei pere kia haere whakamuri</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=mi] {<h2>He whakamÄrama i te mahi Rapu Kupu</h2>
+<p>
+     Ko te whÄrangi rapu te whÄrangi hei rapu kupu. Ka puta mai taua whÄrangi ka
+  whai mai Änei kÅkiri kia rapu ai i (t)Ätehi kupu:<p>
+  
+  <ol><li>Whakaritea kia rapua ngÄ kupu ki whea
+      <li>Whakaritea kia rapua ngÄ kupu katoa, kia rapua Ätehi kupu noa iho rÄnei
+      <li>Tuhia ngÄ kupu rapu
+      <li>PÄwhiritia te pÄtene <i>Rapua</i> 
+  </ol>
+
+<p>Ka tukua te rapu ka puta mai ngÄ kitenga rua tekau e pÄ ana ki Äu kupu 
+rapu. He pÄtene kei raro rÄ o te whÄrangi hei titiro ai ki ngÄ kitenga 21 ki te
+40.  Ka pÄwhiri anÅ i taua pÄtene ka titiro ki Ätehi atu kitenga rua tekau. 
+NÅ reira, he pÄtene kei raro rÄ hei haere whakamua i ngÄ kitenga, hei haere 
+whakamuri rÄnei. 
+PÄwhiritia te taitara o te kitenga, .pÄwhiritia te whakaahua iti rÄnei i te taha o 
+te kitenga kia whakatÅ«whera mai ai taua kitenga.
+
+<p> Ka kore e nuku atu i te 100 o ngÄ pukapuka ka kitea i tÄtehi rapunga. Heoi anÅ
+ka taea te whakarerekÄ tÄnei nama i te pÄtene  <i>kÅwhiringa</i> i runga ake rÄ.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>NgÄ kupu rapu</h3>
+
+<p> Koia nei ngÄ kupu ka tuhia ki roto i te pouaka rapu. Me noho te 
+mokowÄ (wÄhi wÄtea) i waenganui i ngÄ kupu. Ko ngÄ reta me ngÄ 
+nama anakÄ ngÄ pÅ« ka rapua. Kaua e tuhi ngÄ tohutuhi (pÄrÄ i te "?" me 
+te "/"), ka tangohia aua tohu e te rorohiko nei, ka whakauru ko te mokowÄ.
+
+<p> tauira, ki te tuhi atu i Änei kupu rapu; <p>
+    <ul><kbd> huihuinga-a-motu / Whanganui (1860-1885) </kbd></ul>
+      <p>ka rapua kÄtia e te rorohiko Änei kupu;<p>
+      <ul><kbd> huihuinga a motu Whanganui 1860 1885 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>NgÄ tÅ«momo rapu</h3>
+
+<p>E rua ngÄ tÅ«momo rapu.
+
+<ul>
+  <li> Ka rapua te <b>katoa</b> o Äu kupu rapu. Ka rapua ngÄ 
+pukapuka e mau ana i te katoa o ngÄ kupu rapu kua tuhia e koe.
+Ka whakarÄrangitia mai aua kitenga e pÄ ana ki te pÅ«rÄrangi. <p>
+
+  <li> Ka rapua <b>Ätehi</b> o Äu kupu rapu. NÅ reira, me tuhi noa he kupu e pÄ
+      ana ki te kaupapa e hiahia ana koe. Ka whakarÄrangitia ngÄ kitenga e pÄ ana
+      ki te ritenga ki Äu kupu rapu. ArÄ, ka puta tuatahitia mai ngÄ kitenga;  
+
+
+      <p><ul>
+        <li> e mau ana i te maha o Äu kupu rapu;
+        <li> e mau ana i ngÄ kupu uaua te kite o Äu kupu rapu;
+        <li> e iti ana, ka whai mai ko ngÄ pukapuka nui.
+      </ul>
+</ul>
+
+<p> Me tuhi i te maha o ngÄ kupu rapu kia arahina te rapu ki tÅ ake hiahia.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=mi] {Rapu RÄ}
+
+_texthelpdatesearch_ [l=mi] {<h2>_textdatesearch_</h2>
+Ko te rapu rÄ tÄtehi rapu e taea ana te mahi motuhake, e taea ana rÄnei te 
+whakaÅ« ki tÄtehi rapunga kupu. He huarahi hei rapu tuhinga i puta mai i 
+tÄtehi tau, i Ätehi tau rÄnei.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>NgÄ Huarahi hei Rapu RÄ:</h3>
+<ul>
+   <li>Kia rapu ngÄ tuhinga e pÄ ana ki tÄtehi tau:<p>
+   <ul>
+       <li>Tuhia ngÄ kupu rapu (pÄra i te rapu kupu).
+       <li>Tuhia te tau ki te pouaka "RÄ (tÄ«mata)".
+       <li>Mehemea i mua tÅ tau rapu i te whÄnau mai o 
+             Ihu Karaiti kÅwhiritia te "B.C.E" i te rÄrangi tono
+            e tata ana ki te pouaka.
+       <li>Tukua te rapu.
+   </ul>
+<p><li>Kia rapu ngÄ tuhinga e pÄ ana ki tÄtehi wÄ, arÄ ki Ätehi tau:<p>
+   <ul>
+       <li> Tuhia ngÄ kupu rapu (pÄra i te rapu kupu).
+       <li> Tuhia te tau tÄ«mata ki te pouaka "RÄ (tÄ«mata)".
+       <li> Tuhia te tau mutunga ki te pouaka "RÄ mutunga".
+       <li> Mehemea i mua tÄtehi tau rapu i te whÄnau mai o 
+             Ihu Karaiti kÅwhiritia te "B.C.E" i te rÄrangi tono
+            e tata ana ki te pouaka.
+       <li>Tukua te rapu.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>He kÅrero mÅ te Rapu RÄ</h3>
+
+Mehemea i rapua e koe te tau 1907 ko ngÄ kitenga he 
+pukapuka kua tuhi kÅrero e pÄ ana ki 1907, kÄore he 
+pukapuka i tÄ ai i te tau 1907. He Ähua koi hoki te rapu 
+i te mea ka kitea ngÄ pukapuka e kÅrero ana mÅ taua 
+wÄ hoki, hei tauira; ka kitea ngÄ pukapuka e pÄ ana ki 
+te wÄ 1899-1921 (kei roto te 1907 i taua wÄ), ka kitea 
+hoki ngÄ pukapuka e pÄ ana ki te 20th century (kei roto 
+te 1907 i taua wÄ), ahakoa kÄore te tau 1907 i tuhia ake 
+i aua pukapuka.<p>
+}
+
+_textchangeprefs_ [l=mi] {Te whakarerekÄ Å kÅwhiringa}
+
+_texthelppreferences_ [l=mi] {<h2>_textchangeprefs_</h2>
+
+<p>Ko te pÄtene <i>kÅwhiringa</i> kei runga ake i te whÄrangi hei 
+whakarerekÄ ai ngÄ kÅwhiringa e pÄ ana ki Åu ake hiahia. 
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>KÅwhiringa Kohikohinga</h3>
+
+Kei roto i Ätehi kohikohinga he kohikohinga anÅ, he kohikohinga-whÄiti.  
+E taea te whakarite i te whÄrangi kÅwhiringa, ko Äwhea ngÄ 
+kohikohinga-whÄiti ka tirohia i te mahi rapu kupu, ko Äwhea ngÄ 
+kohikohinga-whÄiti ka kore e tirohia i te mahi rapu.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>KÅwhiringa Reo</h3>
+
+Kei ngÄ kohikohinga he reo tauwhiti. E taea ana te whakarite 
+kÅ tÄwhea te reo tauwhiti tuatahi ka kite atu ai te kaipÄnui. 
+E taea ana te whakarerekÄ hoki i te encoding scheme mehemea 
+kÄore e pai ana, kÄore e tika ana te puta mai o ngÄ pÅ« i tÅ reo.
+E taea ana hoki te whakarite kia kore-whakaahua te puta mai 
+o ngÄ kÅrero, arÄ kia text anakÄ, hei Äwhina i ngÄ tÄngata e Ähua 
+kÄpÅ ana.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>KÅwhiringa Whakaaturanga</h3>
+
+Ka rerekÄ ngÄ kÅwhiringa whakaaturanga e taea ana te whakarite 
+i ia tÅ«momo kohikohinga.
+
+<p>Kei Ätehi kohikohinga e taea ana te whakangaro ngÄ pÄtene
+whakahaere o runga ake, Ä ka riro mÄ ngÄ pÄtene whakahaere ake 
+o te pÅ«manawa tirotiro e tohutoro. Kei Ätehi atu kohikohinga e taea 
+ana te rapu kitenga i te ipurangi whÄnui, me te haere tÅtika ki reira,
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>KÅwhiringa Rapu</h3>
+<p>E rua ngÄ kÅwhiringa hei whakarite ai i te hÄngai pÅ« o te kupu
+rapu ki te kupu kite. Ko te kÅwhiringa tuatahi ko ngÄ pÅ« matua me 
+ngÄ pÅ« iti. Äe rÄnei, me tika te pÅ« matua me te pÅ« iti, kÄore rÄnei, 
+me rapu noa i te kupu hei aha te Äta titiro ki ngÄ pÅ« matua me ngÄ pÅ« iti. 
+Ko te kÅwhiringa tuarua ko te kÅ«muri. Äe rÄnei, me tino Årite 
+te kÅ«muri, kÄore rÄnei, hei aha te Äta titiro ki ngÄ kÅ«muri o ngÄ 
+kupu. MÅ ngÄ kupu rapu PÄkehÄ anakÄ te  kÅwhiringa kÅ«muri.
+
+<p>Hei tauira, mehemea ka kÅwhiritia te <i>hei aha te pÅ« matua me te pÅ«
+iti</i>, Ä, ka kÅwhiritia hoki te <i>hei aha te kÅ«muri o te kupu</i>
+kÄtahi ka tukua Änei kupu hei rapu;
+<p>
+  <ul><kbd>Aotearoa building</kbd></ul>
+    <p>ka Årite te whakahoki mai o ngÄ pukapuka ki Änei kupu rapu
+  <ul><kbd>aotearoa builds</kbd></ul>
+<p>ka pÄnei i te mea, kÄore te rapu i te Äta titiro mehemea he pÅ«
+matua, he pÅ« iti rÄnei, Ä, ka tangohia ngÄ kÅ«muri (pÄrÄ
+i te "ing", me te "s") i tÄnei kÅwhiringa.
+
+E taea ana te whakarite te pouaka rapu kia Ähua nui kia ngÄwari ai
+te tuhi i te maha o ngÄ kupu, kÅwae kÅrero rÄnei. He huarahi tere 
+tÄnei mÅ te rapu kÅrero.
+ 
+<p>E taea ana te whakarite i te tÅ«momo rapu kia matatau, arÄ 
+kia whakamahia ngÄ pÅ« Boolean pÄra i te  AND (&), OR (|), 
+me te NOT (!). Mehemea ka pÄna ka whakawhÄiti te nama o ngÄ 
+kitenga. E taea ana te whakarite i te hÄ«tori rapu kia maumahara ai 
+te rorohiko i ngÄ kupu kua rapua e koe. Ä, e taea ana hoki te 
+whakarite kia hia ngÄ kitenga ka puta mai ki runga i te mata 
+o tÅ rorohiko i te wÄ kotahi.
+"	}
+
+_texttanumbrowseoptions_ [l=mi] {E _numbrowseoptions_ ngÄ huarahi hei rapu kÅrero i te kohikohinga nei:}
+
+_textsimplehelpheading_ [l=mi] {NgÄ huarahi hei rapu kÅrero}
+
+_texthelpscope_ [l=mi] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>NgÄ TaupÅ« o te Rapu</h3>
+
+<p>
+Kei te nuinga o ngÄ kohikohinga e taea ana te whiriwhiri ki 
+tÄwhea taupÅ« e rapu atu ai ngÄ kupu. Hei tauira, me rapu 
+ngÄ kupu i te taupÅ« Kaitito, i te taupÅ« Taitara rÄnei; me rapu 
+ngÄ kupu i te taupÅ« wÄhanga, i te taupÅ« kÅwae rÄnei. 
+Ahakoa ko tÄwhea taupÅ« ka puta mai te katoa o ngÄ kupu tuhituhi.
+
+<p>Mehemea he pukapuka te kitenga, ka whakatÅ«whera mai
+ki te wÄhi e noho mai ai Äu kupu rapu.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/nzdlhome.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/nzdlhome.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/nzdlhome.dm	(revision 10506)
@@ -0,0 +1,418 @@
+# this file must be UTF-8 encoded
+
+# nzdlhome.dm
+#
+# This file defines the homepage of the New Zealand Digital Library Project
+# as it appears on Http://www.nzdl.org. It is designed to override the default
+# homepage (defined in home.dm), so it should appear last in the "macrofiles"
+# section of the main.cfg file.
+#
+
+package home
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. this is overridden here as we don't want 'home' 
+# links on this page
+
+_javalinks_ {}
+_javalinks_ [v=1] {}
+
+
+
+#######################################################################
+# icons
+#######################################################################
+
+_httpiconnzdl_ {_httpimg_/nzdl2gr.gif}
+_widthnzdl_ {457}
+_heightnzdl_ {181}
+
+_iconnzdl_ {<img src="_httpiconnzdl_" width=_widthnzdl_ height=_heightnzdl_ alt="The New Zealand Digital Library">}
+_icongbull_ {<img src="_httpicongbull_">}
+_iconpdf_ {<img src="_httpiconpdf_">}
+
+_iconselectcollection_ {<img src="_httpiconselcolgr_" width=_widthselcolgr_ height=_heightselcolgr_ alt=_altselcolgr_>}
+
+## "humanitarian and UN collections" ## green_bar_left_aligned ## selcolun ##
+_httpiconselcolun_ {_httpimg_/selcolun.gif}
+_widthselcolun_ {537}
+_heightselcolun_ {17}
+_altselcolun_ {"Humanitarian and UN collections"}
+
+## "demonstration collections" ## green_bar_left_aligned ## selcolde ##
+_httpiconselcolde_ {_httpimg_/selcolde.gif}
+_widthselcolde_ {537}
+_heightselcolde_ {17}
+_altselcolde_ {"Demonstration collections"}
+
+## "documented example collections" ## green_bar_left_aligned ## selcolec ##
+_httpiconselcolec_ {_httpimg_/selcolec.gif}
+_widthselcolec_ {537}
+_heightselcolec_ {17}
+_altselcolec_ {"Documented Example collections"}
+
+## "greenstone documentation collections" ## green_bar_left_aligned ## selcolgd ##
+_httpiconselcolgd_ {_httpimg_/selcolgd.gif}
+_widthselcolgd_ {537}
+_heightselcolgd_ {17}
+_altselcolgd_ {"Greenstone documentation collections"}
+
+
+_iconselectun_ {<img src="_httpiconselcolun_" width=_widthselcolun_ height=_heightselcolun_ alt=_altselcolun_>}
+_iconselectde_ {<img src="_httpiconselcolde_" width=_widthselcolde_ height=_heightselcolde_ alt=_altselcolde_>}
+_iconselectdec_ {<img src="_httpiconselcolec_" width=_widthselcolec_ height=_heightselcolec_ alt=_altselcolec_>}
+_iconselectgd_ {<img src="_httpiconselcolgd_" width=_widthselcolgd_ height=_heightselcolgd_ alt=_altselcolgd_>}
+_iconmusiclibrary_ {<img src="_httpicontmusic_" border=1 alt="meldex music library">}
+
+
+#######################################################################
+# http macros 
+#
+# These contain the url without any quotes
+#######################################################################
+
+_httpicongbull_ {_httpimg_/gbull.gif}
+
+_httpiconpdf_ {_httpimg_/pdf.gif}
+
+_httpicontmusic_ {_httpimg_/meldexsm.gif}
+
+
+#######################################################################
+# page content                     
+#######################################################################
+
+_pagetitle_ {_textpagetitle_}
+_imagethispage_ {}
+_imagecollection_ {<center>_iconnzdl_</center>}
+
+_content_ {
+_nzdlcollectionlist_
+<center>_iconblankbar_</center>
+
+<p><center><h2>_textprojhead_</h2></center>
+
+<table border=0 cellpadding=5>
+
+<tr valign=top>
+<td>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="mailto:_mailaddr_">Feedback</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/html/people.html">People</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</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>_icongbull_</td><td><a href="http://sadl.uleth.ca">Southern Alberta Digital Library Centre</a></td></tr></table>
+</td>
+<td>_textprojinfo_</td>
+</tr>
+
+<tr>
+<td></td>
+<th align=left>_titlesoftwareinfo_</th>
+</tr>
+<tr valign=top>
+<td>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="_httppagex_(gsdl)">About<br>Greenstone</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.greenstone.org/english/docs.html">Greenstone<br>Documentation</a></td></tr></table>
+</td>
+<td>_textsoftwareinfo_</td>
+</tr>
+
+<tr>
+<td></td>
+<th align=left>_titleresearchinfo_</th>
+</tr>
+<tr valign=top>
+<td>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/html/research.html">Research</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/html/projects.html">Projects</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/html/software.html">Software<br>Downloads</a></td></tr></table>
+<table><tr valign=middle><td>_icongbull_</td><td><a href="http://www.nzdl.org/cgi-bin/library?a=p&p=about&c=publicat">Publications</a></td></tr></table>
+</td>
+<td>_textresearchinfo_</td>
+</tr>
+
+<tr>
+<td></td>
+<th align=left>_titleaffiliateinfo_</th>
+</tr>
+<tr valign=top>
+<td>
+<img src="_httpimg_/ghproj.jpg" alt="Human Info NGO" width=100 height=90>
+</td>
+<td>_textaffiliatehumaninfo_</td></tr>
+<tr valign='top'>
+<td>
+<img src="_httpimg_/unesco.gif" alt="UNESCO" width=100 height=90>
+</td>
+<td>_textaffiliateunesco_</td>
+</tr></table></p>
+
+_iconblankbar_
+<table>
+<tr valign=top>
+<td>_textpoem_</td>
+<td>_imagegreenstone_</td>
+</tr></table>
+<p>_textgreenstone_
+
+<p>
+_nzdlpagefooter_ 
+<br>April 2000
+}
+
+
+
+#######################################################################
+# English language text macros
+#######################################################################
+_textpagetitle_ {New Zealand Digital Library}
+_textprojhead_ {The New Zealand Digital Library Project}
+
+_textprojinfo_ {
+<p>
+The New Zealand Digital Library project is a research programme at
+The University of Waikato whose aim is to develop the underlying
+technology for digital libraries and make it available publicly so that
+others can use it to create their own collections. 
+<p>
+Our web site provides several document collections, including historical
+documents, humanitarian and development information, computer
+science technical reports and bibliographies, literary works, and
+magazines. All are available over the Web, and can be accessed
+through searching and browsing 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!
+}
+
+_titlesoftwareinfo_ {The Greenstone software}
+
+_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="_httppagex_(gsdl)">More...</a>
+}
+
+_titleresearchinfo_ {Our research}
+
+_textresearchinfo_ {
+<p>
+The goal of our research program is to explore the potential of
+internet-based digital libraries. Our vision is to develop systems that
+automatically impose structure on anarchic, uncatalogued, distributed
+repositories of information, thereby providing information consumers
+with effective tools to locate what they need and to peruse it
+conveniently and comfortably. 
+<p>
+Project members are actively working on techniques for creating,
+managing, and and mainatining collections; extracting metadata from
+legacy documents; analysing library usage and user needs; Maori,
+Arabic and Chinese language systems; internationalising the library
+interface; optical music recognition and musical collections; novel
+interfaces for formulating queries and visualising results; novel
+interfaces for browsing metadata; text mining for keyphrases,
+acronyms, and other metadata; keyphrase extraction and
+phrase-based browsing; and other research topics. 
+<p align=right>
+<a href="http://www.nzdl.org/html/research.html">More...</a>
+}
+
+_titleaffiliateinfo_ {Our affiliates}
+
+_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. 
+}
+
+_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 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.
+}
+
+#######################################################################
+# The collection display
+# A hand-crafted alternative to the _homeextra_ macro
+#######################################################################
+
+_nzdlgwcgi_ {library}
+#_nzdlgwcgi_ {http://www.nzdl.org/cgi-bin/library}
+_nzdlhttpprefix_ {http://www.nzdl.org/gsdl}
+
+_nzdlcollection_ {library?a=p&p=about&c=_1_}
+#_nzdlcollection_ {http://www.nzdl.org/cgi-bin/library?a=p&p=about&c=_1_}
+_nzdlcollectionimage_ {<img width=150 border=1 src="_nzdlhttpprefix_/collect/_1_/images/_2_" alt=_3_>}
+
+_collectionlink_ {<a href="_nzdlcollection_(_4_)">_nzdlcollectionimage_(_1_,_2_,_3_)</a>}
+
+
+_nzdlcollectionlist_ {
+<center>
+<p>_iconselectun_
+<p>_collectfao_
+<p>_iconselectde_
+<p>_collectrest_
+<a name="greenstonedocumentationcollections"></a>
+<p>_iconselectgd_
+<p>_collectgd_
+<a name="documentedexamplecollections"></a>
+<p>_iconselectdec_
+<p>_collectdec_
+</center>
+}
+
+_collectfao_ {
+<table width=537>
+<tr valign=top>
+<td align=center>
+<p>_collectionlink_(hdl,  hdlsm.gif, "Humanity Development Library", hdl)
+<p>_collectionlink_(fnl,  fnlsm.gif,   "Food and Nutrition Library", fnl)
+<p>_collectionlink_(envl, welsm.gif, "World Environment Library", envl)
+<p>_collectionlink_(aginfo, aginfo.gif, "Agricultural Information Modules", aginfo)
+<p>_collectionlink_(gtz, gtz.gif, "Crystal", gtz)
+<p>_collectionlink_(cdl, cdl.gif, "Community Development Library", cdl)
+<p>_collectionlink_(edudev, edudevsm.gif, "Human Info NGO Library for Education and Development", edudev)
+<p>_collectionlink_(nigeria, nigeriasm.gif, "Revitalizing Technical and Vocational Education in Nigeria", nigeria)
+<p>_collectionlink_(safem, safemsm.gif, "Safe Motherhood Strategies", safem)
+<p><a href="/cgi-bin/firstaid/library?a=p&p=about&c=firstaid&cl=0&l=en&w=utf-8"><img src="/custom/firstaid/collect/firstaid/images/colicon.jpg" border="1"></a>
+</td>
+
+<td align=center>
+<p>_collectionlink_(mhl,  mhlsm.gif,   "Medical and Health Library", mhl)
+<p>_collectionlink_(fnl1\_1,  fnl1\_1.gif,   "Food and Nutrition Library 1.1", fnl1\_1)
+<p>_collectionlink_(paho, pahosml.gif, "Virtual Disaster Library", paho)
+<p>_collectionlink_(unesco, unescosm.gif, "Sahel point Doc", unesco)
+<p>_collectionlink_(muster, muster.gif, "The Multi-Site Teacher Education Research Project", muster)
+<p>_collectionlink_(unescoen, unescoensm.gif, "East African Development Library", unescoen)
+<p>_collectionlink_(dfid, dfidsm.gif, "Researching Education Development", dfid)
+<p>_collectionlink_(ewf, ewf.gif, "Education Work and the Future", ewf)
+<p>_collectionlink_(fi1998, faosm.gif, "FAO on the Internet &#40;1998&#41;", fi1998)
+<p>_collectionlink_(faodocs, faodrsm.gif, "FAO document repository", faodocs)</td>
+</td>
+
+<td align=center>
+<p>_collectionlink_(ccgi,   ccgism.gif,   "Collection on Critical Global Issues", ccgi)
+<p>_collectionlink_(fnl2.2,  fnl22.gif,   "Food and Nutrition Library 2.2", fnl2.2)
+<p>_collectionlink_(who, who.gif, "Biblioteca Virtual De Salud Para Desastres", who)
+<p>_collectionlink_(tulane, tulanesm.gif, "BibliothÃšque pour le dÃ©veloppement", tulane)
+<p>_collectionlink_(unaids, unaids.gif, "UNAIDS Library", unaids)
+<p>_collectionlink_(aedl, aedl.gif, "Africa Collection for Transition", aedl)
+<p>_collectionlink_(whoedm, whoedmsm.gif, "WHO Medicines Bookshelf 1.0", whoedm)
+<p>_collectionlink_(helid, helidsm.gif, "WHO Health Library for Disasters", helid)
+<p>_collectionlink_(ipc, ipcsm.gif, "Indigenous Peoples", ipc)
+<p>_collectionlink_(povsem, povsem_front.gif, "Poverty Alleviation", povsem)
+</tr>
+</table>
+}
+
+
+_collectrest_ {
+<table width=537>
+<tr valign=top>
+
+<td align=center>
+<p>_collectionlink_(acrodemo, acrodemosm.gif, "AGRIS: acronym extraction demo", acrodemo)
+<p><a href="library?a=p&p=about&c=niupepa&l=mi&nw=utf-8"><img width=150 border=1 src="_nzdlhttpprefix_/collect/niupepa/images/niupepsm.gif" alt="Niupepa: MÃ€ori Newspapers"></a>
+<p>_collectionlink_(arabic,  arabic.gif,  "Arabic text collection", arabic&l=ar&nw=windows-1256)
+<p>_collectionlink_(chinese, chinsm.jpg,  "Chinese text collection", chinese&l=zh&nw=utf-8)
+<p>_collectionlink_(folktale, folktale.gif, "Folktales: language extraction demo", folktale)
+<p>_collectionlink_(demooai, jcdl_logo_photo_tiled.gif, "OAI demo collection", demooai)
+<p>_collectionlink_(tidbits, tidbitsm.gif, "TidBITS", tidbits)
+</td>
+
+<td align=center>
+<p><a href="/musiclib"><img src="_nzdlhttpprefix_/images/meldexsm.gif" border=1 alt="Meldex music library"></a>
+<p>_collectionlink_(wordpdf, wordpdf.gif, "MSWord and PDF demo", wordpdf)
+<p>_collectionlink_(musvid, musvid\_frontpage.gif, "Music Videos", musvid)
+<p>_collectionlink_(gberg,   gbergsm.gif, "Project Gutenberg Collection", gberg)
+<p>_collectionlink_(allshake, shakefront.gif, "The Complete works of Shakespeare", allshake)
+<p>_collectionlink_(aircraft, logo.gif, "aircraft images collection", aircraft)
+<p>_collectionlink_(csbib, csbibsm.gif, "Computer Science Bibliographies", csbib)
+<p>_collectionlink_(coltbib, coltsm.gif, "COLT Bibliography", coltbib&ct=1&qto=3&qt=1)
+</td>
+
+<td align=center>
+<p><a href="cstrlibrary?a=p&p=about"><img width=150 border=1 src="_nzdlhttpprefix_/collect/cstr/images/cstrsm.gif" alt="Computer Science Technical Reports"></a>
+<p>_collectionlink_(ohist, ohist\_title\_small.gif, "Hamilton Public Library Youth Oral History Collection", ohist)
+<p>_collectionlink_(hcibib, hcibibsm.gif, "The HCI Bibliography", hcibib)
+<p>_collectionlink_(whist, whist\_logo\_small.gif, "Women's History Primary Source Documents", whist)
+<p>_collectionlink_(beowulf, beowulffront.jpg, "MARC Demonstration collection: Beowulf", beowulf)
+<p>_collectionlink_(tcc, tccsm.gif, "The Computists' Weekly", tcc)
+<p>_collectionlink_(jair, jair-sm.gif, "Journal of Artificial Intelligence Research", jair)
+</td>
+
+</tr>
+</table>
+}
+_collectgd_ {
+<table width=537>
+<tr valign=top>
+<td align=center>
+<p>_collectionlink_(publicat, nzdlpub.gif, "NZDL Publications collection", publicat)</td>
+<td align=center>
+<p>_collectionlink_(gsarch, gsarch.gif, "Greenstone mailing list archive", gsarch)
+<p><a href="/howto"><img width=150 height=110 border=1 src="/custom/howto/images/front_cover_tiled.gif" alt="How to build a digital library"></a></td>
+<td align=center>
+<p>_collectionlink_(gsdocs, gsdocs.gif, "Greenstone Documentation collection", gsdocs)</td>
+</tr></table>
+}
+
+_collectdec_ {
+<table width=537>
+<tr valign=top>
+
+<td align=center>
+<p>_collectionlink_(dls-e, dls-e.gif, "(Documented) Development Library Subset collection", dls-e)
+<p>_collectionlink_(wrdpdf-e, wrdpdf-e.gif, "(Documented) MSWord and PDF demonstration", wrdpdf-e)
+<p>_collectionlink_(gsarch-e, gsarch-e.gif, "(Documented) Greenstone Archives collection", gsarch-e)
+<p>_collectionlink_(isis-e, isis-e.gif, "(Documented) CDS/ISIS collection", isis-e&ct=1&qt=1&qto=3)
+
+</td>
+
+<td align=center>
+<p>_collectionlink_(cltbib-e, cltbib-e.gif, "(Documented) bibliography collection", cltbib-e&ct=1&qt=1)
+<p>_collectionlink_(MARC-e, MARC-e.gif, "(Documented) MARC example", MARC-e)
+<p>_collectionlink_(oai-e, oai-e.gif, "(Documented) OAI demo collection", oai-e)
+</td>
+
+<td align=center>
+<p>_collectionlink_(cltext-e, cltext-e.gif, "(Documented) bibliography supplement", cltext-e&ct=1&qt=1)
+<p>_collectionlink_(image-e, image-e.gif, "(Documented) simple image collection", image-e)
+<p>_collectionlink_(garish, garish.gif, "(Documented) Garish version of demo collection", garish)
+<p>_collectionlink_(authen-e, authen-e.gif, "(Documented) Formatting and authentication demo", authen-e)
+</td>
+
+</tr>
+</table>
+}
+
+
+# bbc no longer public
+#<p>_collectionlink_(bbc1, bbc_home.gif, "BBC archives (1900-1985)", bbc1)
Index: /tags/gsdl-2_61-distribution/gsdl/macros/polish.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/polish.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/polish.dm	(revision 10506)
@@ -0,0 +1,1597 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Polish Language text and icon macros 
+# Many thanks to Lech Borkowski (translated March 2005)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=pl] {Periodyki}
+_textsource_ [l=pl] {ÅºrÃ³dÅo:}
+_textdate_ [l=pl] {data publikacji:}
+_textnumpages_ [l=pl] {liczba stron}
+
+_textsignin_ [l=pl] {rejestracja}
+
+_textdefaultcontent_ [l=pl] {Nie znaleziono strony. Kliknij przycisk Wstecz przeglÄ
+darki
+internetowej lub przycisk Strona gÅÃ³wna, aby powrÃ³ciÄ do
+strony gÅÃ³wnej biblioteki cyfrowej Greenstone.}
+
+_textdefaulttitle_ [l=pl] {BÅÄ
+d GSDL}
+
+_textbadcollection_ [l=pl] {Ta kolekcja (zwana "_cvariable_") nie jest zainstalowana w tej bibliotece cyfrowej Greenstone.}
+
+_textselectpage_ [l=pl] {Wybierz stronÄ}
+
+_collectionextra_ [l=pl] {Kolekcja zawiera _about:numdocs_ dokumentÃ³w. 
+PowstaÅa _about:builddate_ dni temu. }
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=pl] {<p>Kolekcja zawiera _numdocs_ _If_("_numdocs_" eq "1",dokument,dokumentÃ³w), ÅÄ
+cznie _numbytes_.
+<p><a href="_httppagex_(bsummary)">Kliknij</a>, aby obejrzeÄ podsumowanie kolekcji.
+}
+
+_textimagecollection_ [l=pl] {}
+_textimageabout_ [l=pl] {Informacje}
+_textimagehome_ [l=pl] {Strona gÅÃ³wna}
+_textimagehelp_ [l=pl] {Pomoc}
+_textimagepref_ [l=pl] {Preferencje}
+_textimagegreenstone_ [l=pl] {Program Biblioteki Cyfrowej Greenstone}
+_textimageusab_ [l=pl] {KtÃ³re elementy biblioteki sprawiajÄ
+ trudnoÅci?}
+
+_textimagesearch_ [l=pl] {ZnajdÅº wyraÅŒenia}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=pl] {PrzeglÄ
+daj alfabetycznÄ
+ listÄ tytuÅÃ³w}
+_textimageCreator_ [l=pl] {PrzeglÄ
+daj alfabetycznÄ
+ listÄ autorÃ³w}
+_textimageSubject_ [l=pl] {PrzeglÄ
+daj wedÅug tematÃ³w}
+_textimageDescription_ [l=pl] {PrzeglÄ
+daj weÅug opisu}
+_textimagePublisher_ [l=pl] {PrzeglÄ
+daj wedÅug wydawcÃ³w}
+_textimageContributor_ [l=pl] {PrzeglÄ
+daj wedÅug wspÃ³ÅpracownikÃ³w}
+_textimageDate_ [l=pl] {PrzeglÄ
+daj wedÅug dat}
+_textimageType_ [l=pl] {PrzeglÄ
+daj wedÅug typu zasobÃ³w}
+_textimageFormat_ [l=pl] {PrzeglÄ
+daj wedÅug formatu}
+_textimageIdentifier_ [l=pl] {PrzeglÄ
+daj wedÅug identyfikatorÃ³w zasobÃ³w}
+_textimageSource_ [l=pl] {PrzeglÄ
+daj wedÅug pierwotnych nazw plikÃ³w}
+_textimageLanguage_ [l=pl] {PrzeglÄ
+daj wedÅug jÄzyka}
+_textimageRelation_ [l=pl] {PrzeglÄ
+daj wedÅug relacji}
+_textimageCoverage_ [l=pl] {PrzeglÄ
+daj wedÅug dziedziny}
+_textimageRights_ [l=pl] {PrzeglÄ
+daj wedÅug praw autorskich}
+
+_textimageOrganization_ [l=pl] {PrzeglÄ
+daj wedÅug organizacji}
+_textimageKeyword_ [l=pl] {PrzeglÄ
+daj wedÅug sÅÃ³w kluczowych}
+_textimageHowto_ [l=pl] {PrzeglÄ
+daj kategorie Jak...}
+_textimageList_ [l=pl] {PrzeglÄ
+daj wydruki dokumentÃ³w}
+_textimageSeries_ [l=pl] {PrzeglÄ
+daj wedÅug wydaÅ}
+_textimageTo_ [l=pl] {PrzeglÄ
+daj wedÅug zawartoÅci pola Do}
+_textimageFrom_ [l=pl] {PrzeglÄ
+daj wedÅug pola Od (nadawca)}
+_textimageTopic_ [l=pl] {PrzeglÄ
+daj wydania specjalne}
+_textimageBrowse_ [l=pl] {PrzeglÄ
+daj}
+_textimageCollage_ [l=pl] {PrzeglÄ
+daj wedÅug obrazÃ³w}
+_textimagePeople_ [l=pl] {PrzeglÄ
+daj alfabetycznÄ
+ listÄ osÃ³b}
+_textimageAcronym_ [l=pl] {PrzeglÄ
+daj skrÃ³ty}
+_textimagePhrase_ [l=pl] {PrzeglÄ
+daj wedÅug wyraÅŒeÅ}
+_textimageArtist_ [l=pl] {PrzeglÄ
+daj artystÃ³w}
+_textimageVolume_ [l=pl] {PrzeglÄ
+daj wedÅug wolumenÃ³w}
+_textimageCountries_ [l=pl] {PrzeglÄ
+daj wedÅug krajÃ³w}
+_textimageCaptions_ [l=pl] {PrzeglÄ
+daj podpisy fotografii}
+
+
+_texticontabsearchgreen_ [l=pl] {ZnajdÅº}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=pl] {TytuÅy A-Z}
+_texticontabCreatorgreen_ [l=pl] {Autorzy A-Z}
+_texticontabSubjectgreen_ [l=pl] {Tematy}
+_texticontabDescriptiongreen_ [l=pl] {Opisy}
+_texticontabPublishergreen_ [l=pl] {Wydawcy}
+_texticontabContributorgreen_ [l=pl] {WspÃ³Åpracownicy}
+_texticontabDategreen_ [l=pl] {Daty}
+_texticontabTypesgreen_ [l=pl] {Typy}
+_texticontabFormatgreen_ [l=pl] {Formaty}
+_texticontabIdentifiergreen_ [l=pl] {Identyfikatory}
+_texticontabSourcegreen_ [l=pl] {Nazwy plikÃ³w}
+_texticontabLanguagegreen_ [l=pl] {JÄzyki}
+_texticontabRelationgreen_ [l=pl] {Relacje}
+_texticontabCoveragegreen_ [l=pl] {Dziedzina}
+_texticontabRightsgreen_ [l=pl] {Prawa}
+
+_texticontaborggreen_ [l=pl] {Organizacja}
+_texticontabKeywordgreen_ [l=pl] {SÅowa kluczowe}
+_texticontabhowgreen_ [l=pl] {Jak...}
+_texticontabseriesgreen_ [l=pl] {Serie}
+_texticontablistgreen_ [l=pl] {Wydruk}
+_texticontabtogreen_ [l=pl] {Do}
+_texticontabfromgreen_ [l=pl] {Od (nadawca)}
+_texticontabtopicgreen_ [l=pl] {Tematy}
+_texticontabbrwsegreen_ [l=pl] {PrzeglÄ
+daj}
+_texticontabCollagegreen_ [l=pl] {KolaÅŒ}
+_texticontabbrowsgreen_ [l=pl] {PrzeglÄ
+daj}
+_texticontabPeoplegreen_ [l=pl] {Osoby A-Z}
+_texticontabAcronymgreen_ [l=pl] {SkrÃ³ty}
+_texticontabPhrasegreen_ [l=pl] {Zwroty}
+_texticontabArtistgreen_ [l=pl] {ArtyÅci}
+_texticontabVolumegreen_ [l=pl] {Wolumeny}
+_texticontabCaptionsgreen_ [l=pl] {Podpisy}
+_texticontabCountriesgreen_ [l=pl] {Kraje}
+
+_texticontext_ [l=pl] {PrzeglÄ
+daj dokument}
+_texticonclosedbook_ [l=pl] {otwÃ³rz dokument i przeglÄ
+daj}
+_texticonnext_ [l=pl] {nastÄpny rozdziaÅ}
+_texticonprev_ [l=pl] {poprzedni rozdziaÅ}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=pl] {PrzeglÄ
+daj dokument w formacie MIDI}
+_texticonmsword_ [l=pl] {PrzeglÄ
+daj dokument w formacie Microsoft Word}
+_texticonmp3_ [l=pl] {PrzeglÄ
+daj dokument w formacie MP3}
+_texticonpdf_ [l=pl] {PrzeglÄ
+daj dokument w formacie PDF}
+_texticonps_ [l=pl] {PrzeglÄ
+daj dokument w formacie PostScript}
+_texticonppt_ [l=pl] {PrzeglÄ
+daj dokument w formacie PowerPoint}
+_texticonrtf_ [l=pl] {PrzeglÄ
+daj dokument w formacie RTF}
+_texticonxls_ [l=pl] {PrzeglÄ
+daj dokument w formacie Microsoft Excel}
+
+_page_ [l=pl] {strona}
+_pages_ [l=pl] {stron}
+_of_ [l=pl] {z}
+_vol_ [l=pl] {Tom}
+_num_ [l=pl] {Nr}
+
+_textmonth00_ [l=pl] {}
+_textmonth01_ [l=pl] {StyczeÅ}
+_textmonth02_ [l=pl] {Luty}
+_textmonth03_ [l=pl] {Marzec}
+_textmonth04_ [l=pl] {KwiecieÅ}
+_textmonth05_ [l=pl] {Maj}
+_textmonth06_ [l=pl] {Czerwiec}
+_textmonth07_ [l=pl] {Lipiec}
+_textmonth08_ [l=pl] {SierpieÅ}
+_textmonth09_ [l=pl] {WrzesieÅ}
+_textmonth10_ [l=pl] {PaÅºdziernik}
+_textmonth11_ [l=pl] {Listopad}
+_textmonth12_ [l=pl] {GrudzieÅ}
+
+_textdocument_ [l=pl] {Dokument}
+_textsection_ [l=pl] {RozdziaÅ}
+_textparagraph_ [l=pl] {Akapit}
+
+_magazines_ [l=pl] {Czasopisma}
+
+_nzdlpagefooter_ [l=pl] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "STRONA GÅÃWNA" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=pl] {_httpimg_/pl/chomeof.gif}
+_httpiconchomeon_ [l=pl] {_httpimg_/pl/chomeon.gif}
+
+## "POMOC" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=pl] {_httpimg_/pl/chelpof.gif}
+_httpiconchelpon_ [l=pl] {_httpimg_/pl/chelpon.gif}
+
+## "PREFERENCJE" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=pl] {_httpimg_/pl/cprefof.gif}
+_httpiconcprefon_ [l=pl] {_httpimg_/pl/cprefon.gif}
+
+## "WYÅLIJ UWAGI" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=pl] {_httpimg_/pl/cusabof.gif}
+_httpiconcusabon_ [l=pl] {_httpimg_/pl/cusabon.gif}
+
+
+## "znajdÅº" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=pl] {_httpimg_/pl/tsrchgr.gif}
+_httpicontsrchof_ [l=pl] {_httpimg_/pl/tsrchof.gif}
+_httpicontsrchon_ [l=pl] {_httpimg_/pl/tsrchon.gif}
+_widthtsrchx_ [l=pl] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tytuÅy a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=pl] {_httpimg_/pl/ttitlgr.gif}
+_httpiconttitleof_ [l=pl] {_httpimg_/pl/ttitlof.gif}
+_httpiconttitleon_ [l=pl] {_httpimg_/pl/ttitlon.gif}
+_widthttitlex_ [l=pl] {87}
+
+# Not true DC, kept for legacy reasons
+## "autorzy a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=pl] {_httpimg_/pl/tauthgr.gif}
+_httpicontcreatof_ [l=pl] {_httpimg_/pl/tauthof.gif}
+_httpicontcreaton_ [l=pl] {_httpimg_/pl/tauthon.gif}
+_widthtcreatx_ [l=pl] {87}
+
+## "tematy" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=pl] {_httpimg_/pl/tsubjgr.gif}
+_httpicontsubjon_ [l=pl] {_httpimg_/pl/tsubjon.gif}
+_httpicontsubjof_ [l=pl] {_httpimg_/pl/tsubjof.gif}
+_widthtsubjx_ [l=pl] {87}
+
+## "opisy" ## nav_bar_button ## tdesc ##
+_httpicontdescgr_ [l=pl] {_httpimg_/pl/tdescgr.gif}
+_httpicontdescon_ [l=pl] {_httpimg_/pl/tdescon.gif}
+_httpicontdescof_ [l=pl] {_httpimg_/pl/tdescof.gif}
+_widthtdescx_ [l=pl] {90}
+
+## "wydawcy" ## nav_bar_button ## tpubl ##
+_httpicontpublgr_ [l=pl] {_httpimg_/pl/tpublgr.gif}
+_httpicontpublon_ [l=pl] {_httpimg_/pl/tpublon.gif}
+_httpicontpublof_ [l=pl] {_httpimg_/pl/tpublof.gif}
+_widthtpublx_ [l=pl] {87}
+
+## "wspÃ³Åpracownicy" ## nav_bar_button ## tcontr ##
+_httpicontcontrgr_ [l=pl] {_httpimg_/pl/tcontrgr.gif}
+_httpicontcontron_ [l=pl] {_httpimg_/pl/tcontron.gif}
+_httpicontcontrof_ [l=pl] {_httpimg_/pl/tcontrof.gif}
+_widthtcontrx_ [l=pl] {89}
+
+## "daty" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=pl] {_httpimg_/pl/tdategr.gif}
+_httpicontdateof_ [l=pl] {_httpimg_/pl/tdateof.gif}
+_httpicontdateon_ [l=pl] {_httpimg_/pl/tdateon.gif}
+_widthtdatex_ [l=pl] {87}
+
+## "typy" ## nav_bar_button ## ttype ##
+_httpiconttypegr_ [l=pl] {_httpimg_/pl/ttypegr.gif}
+_httpiconttypeof_ [l=pl] {_httpimg_/pl/ttypeof.gif}
+_httpiconttypeon_ [l=pl] {_httpimg_/pl/ttypeon.gif}
+_widthttypex_ [l=pl] {87}
+
+## "formaty" ## nav_bar_button ## tform ##
+_httpicontformgr_ [l=pl] {_httpimg_/pl/tformgr.gif}
+_httpicontformof_ [l=pl] {_httpimg_/pl/tformof.gif}
+_httpicontformon_ [l=pl] {_httpimg_/pl/tformon.gif}
+_widthtformx_ [l=pl] {87}
+
+## "identyfikatory" ## nav_bar_button ## tident ##
+_httpicontidentgr_ [l=pl] {_httpimg_/pl/tidentgr.gif}
+_httpicontidentof_ [l=pl] {_httpimg_/pl/tidentof.gif}
+_httpicontidenton_ [l=pl] {_httpimg_/pl/tidenton.gif}
+_widthtidentx_ [l=pl] {87}
+
+# Not true DC, kept for legacy reasons
+## "nazwy plikÃ³w" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=pl] {_httpimg_/pl/tsrcgr.gif}
+_httpicontsrcof_ [l=pl] {_httpimg_/pl/tsrcof.gif}
+_httpicontsrcon_ [l=pl] {_httpimg_/pl/tsrcon.gif}
+_widthtsrcx_ [l=pl] {87}
+
+## "jÄzyki" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=pl] {_httpimg_/pl/tlanggr.gif}
+_httpicontlangon_ [l=pl] {_httpimg_/pl/tlangon.gif}
+_httpicontlangof_ [l=pl] {_httpimg_/pl/tlangof.gif}
+_widthtlangx_ [l=pl] {87}
+
+## "relacje" ## nav_bar_button ## trel ##
+_httpicontrelgr_ [l=pl] {_httpimg_/pl/trelgr.gif}
+_httpicontrelon_ [l=pl] {_httpimg_/pl/trelon.gif}
+_httpicontrelof_ [l=pl] {_httpimg_/pl/trelof.gif}
+_widthtrelx_ [l=pl] {87}
+
+## "dziedzina" ## nav_bar_button ## tcover ##
+_httpicontcovergr_ [l=pl] {_httpimg_/pl/tcovergr.gif}
+_httpicontcoveron_ [l=pl] {_httpimg_/pl/tcoveron.gif}
+_httpicontcoverof_ [l=pl] {_httpimg_/pl/tcoverof.gif}
+_widthtcoverx_ [l=pl] {87}
+
+## "prawa" ## nav_bar_button ## tright ##
+_httpicontrightgr_ [l=pl] {_httpimg_/pl/trightgr.gif}
+_httpicontrighton_ [l=pl] {_httpimg_/pl/trighton.gif}
+_httpicontrightof_ [l=pl] {_httpimg_/pl/trightof.gif}
+_widthtrightx_ [l=pl] {87}
+
+
+
+## "serie" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=pl] {_httpimg_/pl/tsergr.gif}
+_httpicontserof_ [l=pl] {_httpimg_/pl/tserof.gif}
+_httpicontseron_ [l=pl] {_httpimg_/pl/tseron.gif}
+_widthtserx_ [l=pl] {87}
+
+## "do" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=pl] {_httpimg_/pl/ttogr.gif}
+_httpiconttoon_ [l=pl] {_httpimg_/pl/ttoon.gif}
+_httpiconttoof_ [l=pl] {_httpimg_/pl/ttoof.gif}
+_widthttox_ [l=pl] {87}
+
+## "od" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=pl] {_httpimg_/pl/tfromgr.gif}
+_httpicontfromon_ [l=pl] {_httpimg_/pl/tfromon.gif}
+_httpicontfromof_ [l=pl] {_httpimg_/pl/tfromof.gif}
+_widthtfromx_ [l=pl] {87}
+
+## "organizacje" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=pl] {_httpimg_/pl/torggr.gif}
+_httpicontorgon_ [l=pl] {_httpimg_/pl/torgon.gif}
+_httpicontorgof_ [l=pl] {_httpimg_/pl/torgof.gif}
+_widthtorgx_ [l=pl] {98}
+
+## "jak..." ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=pl] {_httpimg_/pl/thowgr.gif}
+_httpiconthowon_ [l=pl] {_httpimg_/pl/thowon.gif}
+_httpiconthowof_ [l=pl] {_httpimg_/pl/thowof.gif}
+_widththowx_ [l=pl] {87}
+
+## "temat" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=pl] {_httpimg_/pl/ttopicgr.gif}
+_httpiconttopicon_ [l=pl] {_httpimg_/pl/ttopicon.gif}
+_httpiconttopicof_ [l=pl] {_httpimg_/pl/ttopicof.gif}
+_widthttopicx_ [l=pl] {87}
+
+## "przeglÄ
+daj" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=pl] {_httpimg_/pl/tbrwsegr.gif}
+_httpicontbrwseon_ [l=pl] {_httpimg_/pl/tbrwseon.gif}
+_httpicontbrwseof_ [l=pl] {_httpimg_/pl/tbrwseof.gif}
+_widthtbrwsex_ [l=pl] {87}
+
+## "kolaÅŒ" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=pl] {_httpimg_/pl/tcollgr.gif}
+_httpicontcollof_ [l=pl] {_httpimg_/pl/tcollof.gif}
+_httpicontcollon_ [l=pl] {_httpimg_/pl/tcollon.gif}
+_widthtcollx_ [l=pl] {87}
+
+## "osoby" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=pl] {_httpimg_/pl/tpeopgr.gif}
+_httpicontpeopof_ [l=pl] {_httpimg_/pl/tpeopof.gif}
+_httpicontpeopon_ [l=pl] {_httpimg_/pl/tpeopon.gif}
+_widthtpeopx_ [l=pl] {97}
+
+## "skrÃ³ty" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=pl] {_httpimg_/pl/tacrogr.gif}
+_httpicontacroof_ [l=pl] {_httpimg_/pl/tacroof.gif}
+_httpicontacroon_ [l=pl] {_httpimg_/pl/tacroon.gif}
+_widthtacrox_ [l=pl] {87}
+
+## "wyraÅŒenia" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=pl] {_httpimg_/pl/tphrsegr.gif}
+_httpicontphrseof_ [l=pl] {_httpimg_/pl/tphrseof.gif}
+_httpicontphrseon_ [l=pl] {_httpimg_/pl/tphrseon.gif}
+_widthtphrsex_ [l=pl] {87}
+
+## "artyÅci" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=pl] {_httpimg_/pl/tartstgr.gif}
+_httpicontartstof_ [l=pl] {_httpimg_/pl/tartstof.gif}
+_httpicontartston_ [l=pl] {_httpimg_/pl/tartston.gif}
+_widthtartstx_ [l=pl] {87}
+
+## "sÅowa kluczowe" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=pl] {_httpimg_/pl/tkwgr.gif}
+_httpicontkwof_ [l=pl] {_httpimg_/pl/tkwof.gif}
+_httpicontkwon_ [l=pl] {_httpimg_/pl/tkwon.gif}
+_widthtkwx_ [l=pl] {87}
+
+## "wolumeny" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=pl] {_httpimg_/pl/tvolgr.gif}
+_httpicontvolof_ [l=pl] {_httpimg_/pl/tvolof.gif}
+_httpicontvolon_ [l=pl] {_httpimg_/pl/tvolon.gif}
+_widthtvolx_ [l=pl] {87}
+
+## "podpisy" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=pl] {_httpimg_/pl/tcaptgr.gif}
+_httpicontcaptof_ [l=pl] {_httpimg_/pl/tcaptof.gif}
+_httpicontcapton_ [l=pl] {_httpimg_/pl/tcapton.gif}
+_widthtcaptx_ [l=pl] {87}
+
+## "kraje" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=pl] {_httpimg_/pl/tcountgr.gif}
+_httpicontcountof_ [l=pl] {_httpimg_/pl/tcountof.gif}
+_httpicontcounton_ [l=pl] {_httpimg_/pl/tcounton.gif}
+_widthtcountx_ [l=pl] {87}
+
+## "pomoc" ## green_title ## h_help ##
+_httpiconhhelp_ [l=pl] {_httpimg_/pl/h\_help.gif}
+_widthhhelp_ [l=pl] {200}
+_heighthhelp_ [l=pl] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=pl] {Informacje o kolekcji}
+
+_textsubcols1_ [l=pl] {<p>CaÅa kolekcja obejmuje _1_ podzbiorÃ³w. 
+DostÄpne sÄ
+:
+<blockquote>}
+
+_textsubcols2_ [l=pl] {</blockquote>
+Na stronie Preferencje moÅŒna zaznaczyÄ (i zmieniÄ) 
+przeglÄ
+dane podzbiory kolekcji.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "informacje" ## green_title ## h_about ##
+_httpiconhabout_ [l=pl] {_httpimg_/pl/h\_about.gif}
+_widthhabout_ [l=pl] {200}
+_heighthabout_ [l=pl] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=pl] {TytuÅy A-Z}
+_texticonhcreat_ [l=pl] {Autorzy A-Z}
+_texticonhsubj_ [l=pl] {Tematy}
+_texticonhdesc_ [l=pl] {Opisy}
+_texticonhpubl_ [l=pl] {Wydawcy}
+_texticonhcontr_ [l=pl] {WspÃ³Åpracownicy}
+_texticonhdate_ [l=pl] {Daty}
+_texticonhtype_ [l=pl] {Typy}
+_texticonhform_ [l=pl] {Formaty}
+_texticonhident_ [l=pl] {Identyfikatory}
+_texticonhsrc_ [l=pl] {Nazwy plikÃ³w}
+_texticonhlang_ [l=pl] {JÄzyki}
+_texticonhrel_ [l=pl] {Relacje}
+_texticonhcover_ [l=pl] {Dziedzina}
+_texticonhright_ [l=pl] {Prawa}
+
+_texticonhcoll_ [l=pl] {KolaÅŒ}
+_texticonhto_ [l=pl] {Do}
+_texticonhfrom_ [l=pl] {Od}
+_texticonhser_ [l=pl] {Series}
+_texticonhhow_ [l=pl] {Jak...}
+_texticonhorg_ [l=pl] {Organizacje}
+_texticonhbrwse_ [l=pl] {PrzeglÄ
+daj}
+_texticonhbrows_ [l=pl] {PrzeglÄ
+daj}
+_texticonhpeople_ [l=pl] {Osoby A-Z}
+_texticonhacronym_ [l=pl] {SkrÃ³ty}
+_texticonhphrases_ [l=pl] {WyraÅŒenia}
+_texticonhartist_ [l=pl] {ArtyÅci}
+_texticonhkw_ [l=pl] {SÅowa kluczowe}
+_texticonhvol_ [l=pl] {Wolumeny}
+_texticonhcapt_ [l=pl] {Podpisy}
+_texticonhcount_ [l=pl] {Kraje}
+
+_texticonopenbookshelf_ [l=pl] {zamknij dziaÅ}
+_texticonclosedbookshelf_ [l=pl] {otwÃ³rz ten dziaÅ i przeglÄ
+daj zawartoÅÄ}
+_texticonopenbook_ [l=pl] {zamknij ksiÄ
+ÅŒkÄ}
+_texticonclosedfolder_ [l=pl] {OtwÃ³rz folder i przeglÄ
+daj}
+_texticonclosedfolder2_ [l=pl] {otwÃ³rz podrozdziaÅ:}
+_texticonopenfolder_ [l=pl] {zamknij folder}
+_texticonopenfolder2_ [l=pl] {zamknij podrozdziaÅ:}
+_texticonsmalltext_ [l=pl] {PrzeglÄ
+daj ten rozdziaÅ}
+_texticonsmalltext2_ [l=pl] {PrzeglÄ
+daj tekst:}
+_texticonpointer_ [l=pl] {rozdziaÅ bieÅŒÄ
+cy}
+_texticondetach_ [l=pl] {OtwÃ³rz stronÄ w nowym oknie}
+_texticonhighlight_ [l=pl] {WyrÃ³ÅŒniaj poszukiwane wyraÅŒenia}
+_texticonnohighlight_ [l=pl] {Nie wyrÃ³ÅŒniaj poszukiwanych wyraÅŒeÅ}
+_texticoncontracttoc_ [l=pl] {ZwiÅ spis treÅci}
+_texticonexpandtoc_ [l=pl] {RozwiÅ spis treÅci}
+_texticonexpandtext_ [l=pl] {WyÅwietlaj caÅy tekst}
+_texticoncontracttext_ [l=pl] {WyÅwietlaj tekst jedynie dla bieÅŒÄ
+cego rozdziaÅu}
+_texticonwarning_ [l=pl] {<b>OstrzeÅŒenie: </b>}
+_texticoncont_ [l=pl] {kontynuowaÄ?}
+
+_textltwarning_ [l=pl] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_RozwiniÄcie tekstu wymaga wyÅwietlenia 
+duÅŒej iloÅci danych w przeglÄ
+darce internetowej _imagecont_
+</td></tr></table></center>}
+
+_textgoto_ [l=pl] {przejdÅº do strony}
+_textintro_ [l=pl] {<i>(wstÄp)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tytuÅy a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=pl] {_httpimg_/pl/h\_title.gif}
+_widthhtitle_ [l=pl] {200}
+_heighthtitle_ [l=pl] {57}
+
+# Not true DC, kept for legacy reasons
+## "autorzy a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=pl] {_httpimg_/pl/h\_auth.gif}
+_widthhcreat_ [l=pl] {200}
+_heighthcreat_ [l=pl] {57}
+
+## "tematy" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=pl] {_httpimg_/pl/h\_subj.gif}
+_widthhsubj_ [l=pl] {200}
+_heighthsubj_ [l=pl] {57}
+
+## "opisy" ## green_title ## h_desc ##
+_httpiconhdesc_ [l=pl] {_httpimg_/pl/h\_desc.gif}
+_widthhdesc_ [l=pl] {200}
+_heighthdesc_ [l=pl] {57}
+
+## "wydawcy" ## green_title ## h_publ ##
+_httpiconhpubl_ [l=pl] {_httpimg_/pl/h\_publ.gif}
+_widthhpubl_ [l=pl] {200}
+_heighthpubl_ [l=pl] {57}
+
+## "wspÃ³Åpracownicy" ## green_title ## h_contr ##
+_httpiconhcontr_ [l=pl] {_httpimg_/pl/h\_contr.gif}
+_widthhcontr_ [l=pl] {200}
+_heighthcontr_ [l=pl] {57}
+
+## "daty" ## green_title ## h_date ##
+_httpiconhdate_ [l=pl] {_httpimg_/pl/h\_date.gif}
+_widthhdate_ [l=pl] {200}
+_heighthdate_ [l=pl] {57}
+
+## "typy" ## green_title ## h_type ##
+_httpiconhtype_ [l=pl] {_httpimg_/pl/h\_type.gif}
+_widthhtype_ [l=pl] {200}
+_heighthtype_ [l=pl] {57}
+
+## "formaty" ## green_title ## h_form ##
+_httpiconhform_ [l=pl] {_httpimg_/pl/h\_form.gif}
+_widthhform_ [l=pl] {200}
+_heighthform_ [l=pl] {57}
+
+## "identyfikatory" ## green_title ## h_ident ##
+_httpiconhident_ [l=pl] {_httpimg_/pl/h\_ident.gif}
+_widthhident_ [l=pl] {200}
+_heighthident_ [l=pl] {57}
+
+# Not true DC, kept for legacy reasons
+## "nazwy plikÃ³w" ## green_title ## h_src ##
+_httpiconhsrc_ [l=pl] {_httpimg_/pl/h\_src.gif}
+_widthhsrc_ [l=pl] {200}
+_heighthsrc_ [l=pl] {57}
+
+## "jÄzyki" ## green_title ## h_lang ##
+_httpiconhlang_ [l=pl] {_httpimg_/pl/h\_lang.gif}
+_widthhlang_ [l=pl] {200}
+_heighthlang_ [l=pl] {57}
+
+## "relacje" ## green_title ## h_rel ##
+_httpiconhrel_ [l=pl] {_httpimg_/pl/h\_rel.gif}
+_widthhrel_ [l=pl] {200}
+_heighthrel_ [l=pl] {57}
+
+## "dziedzina" ## green_title ## h_cover ##
+_httpiconhcover_ [l=pl] {_httpimg_/pl/h\_cover.gif}
+_widthhcover_ [l=pl] {200}
+_heighthcover_ [l=pl] {57}
+
+## "prawa autorskie" ## green_title ## h_right ##
+_httpiconhright_ [l=pl] {_httpimg_/pl/h\_right.gif}
+_widthhright_ [l=pl] {200}
+_heighthright_ [l=pl] {57}
+
+
+
+## "do" ## green_title ## h_to ##
+_httpiconhto_ [l=pl] {_httpimg_/pl/h\_to.gif}
+_widthhto_ [l=pl] {200}
+_heighthto_ [l=pl] {57}
+
+## "od" ## green_title ## h_from ##
+_httpiconhfrom_ [l=pl] {_httpimg_/pl/h\_from.gif}
+_widthhfrom_ [l=pl] {200}
+_heighthfrom_ [l=pl] {57}
+
+## "serie" ## green_title ## h_ser ##
+_httpiconhser_ [l=pl] {_httpimg_/pl/h\_ser.gif}
+_widthhser_ [l=pl] {200}
+_heighthser_ [l=pl] {57}
+
+## "jak..." ## green_title ## h_how ##
+_httpiconhhow_ [l=pl] {_httpimg_/pl/h\_how.gif}
+_widthhhow_ [l=pl] {200}
+_heighthhow_ [l=pl] {57}
+
+## "tematy" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=pl] {_httpimg_/pl/h\_topic.gif}
+_widthhtopic_ [l=pl] {200}
+_heighthtopic_ [l=pl] {57}
+
+## "organizacja" ## green_title ## h_org ##
+_httpiconhorg_ [l=pl] {_httpimg_/pl/h\_org.gif}
+_widthhorg_ [l=pl] {200}
+_heighthorg_ [l=pl] {57}
+
+## "przeglÄ
+daj" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=pl] {_httpimg_/pl/h\_brwse.gif}
+_widthhbrwse_ [l=pl] {200}
+_heighthbrwse_ [l=pl] {57}
+
+## "kolaÅŒ" ## green_title ## h_coll ##
+_httpiconhcoll_ [l=pl] {_httpimg_/pl/h\_coll.gif}
+_widthhcoll_ [l=pl] {200}
+_heighthcoll_ [l=pl] {57}
+
+## "ludzie" ## green_title ## h_people ##
+_httpiconhpeople_ [l=pl] {_httpimg_/pl/h\_people.gif}
+_widthhpeople_ [l=pl] {200}
+_heighthpeople_ [l=pl] {57}
+
+## "skrÃ³ty" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=pl] {_httpimg_/pl/h\_acro.gif}
+_widthhacronym_ [l=pl] {200}
+_heighthacronym_ [l=pl] {57}
+
+## "wyraÅŒenia" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=pl] {_httpimg_/pl/h\_phrse.gif}
+_widthhphrse_ [l=pl] {200}
+_heighthphrse_ [l=pl] {57}
+
+## "artyÅci" ## green_title ## h_artist ##
+_httpiconhartist_ [l=pl] {_httpimg_/pl/h\_artist.gif}
+_widthhartist_ [l=pl] {200}
+_heighthartist_ [l=pl] {57}
+
+## "sÅowa kluczowe" ## green_title ## h_kw ##
+_httpiconhkw_ [l=pl] {_httpimg_/pl/h\_kw.gif}
+_widthhkw_ [l=pl] {200}
+_heighthkw_ [l=pl] {57}
+
+## "wolumeny" ## green_title ## h_vol ##
+_httpiconhvol_ [l=pl] {_httpimg_/pl/h\_vol.gif}
+_widthhvol_ [l=pl] {200}
+_heighthvol_ [l=pl] {57}
+
+## "kraje" ## green_title ## h_count ##
+_httpiconhcount_ [l=pl] {_httpimg_/pl/h\_count.gif}
+_widthhcount_ [l=pl] {200}
+_heighthcount_ [l=pl] {57}
+
+## "podpisy" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=pl] {_httpimg_/pl/h\_capt.gif}
+_widthhcapt_ [l=pl] {200}
+_heighthcapt_ [l=pl] {57}
+
+
+## "KONTYNUOWAÄ??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=pl] {_httpimg_/pl/contof.gif}
+_httpiconconton_ [l=pl] {_httpimg_/pl/conton.gif}
+
+## "ROZWIÅ\nTEKST" ## document_button ## eallt ##
+_httpiconealltof_ [l=pl] {_httpimg_/pl/ealltof.gif}
+_httpiconeallton_ [l=pl] {_httpimg_/pl/eallton.gif}
+
+## "ZWIÅ\nSPIS TREÅCI" ## document_button ## econc ##
+_httpiconeconcof_ [l=pl] {_httpimg_/pl/econcof.gif}
+_httpiconeconcon_ [l=pl] {_httpimg_/pl/econcon.gif}
+
+## "NOWE OKNO" ## document_button ## edtch ##
+_httpiconedtchof_ [l=pl] {_httpimg_/pl/edtchof.gif}
+_httpiconedtchon_ [l=pl] {_httpimg_/pl/edtchon.gif}
+
+## "ROZWIÅ\nSPIS TREÅCI" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=pl] {_httpimg_/pl/eexpcof.gif}
+_httpiconeexpcon_ [l=pl] {_httpimg_/pl/eexpcon.gif}
+
+## "ZWIÅ\nTEKST" ## document_button ## etsec ##
+_httpiconetsecof_ [l=pl] {_httpimg_/pl/etsecof.gif}
+_httpiconetsecon_ [l=pl] {_httpimg_/pl/etsecon.gif}
+
+## "WYRÃÅ»NIANIE" ## document_button ## ehl ##
+_httpiconehlof_ [l=pl] {_httpimg_/pl/ehlof.gif}
+_httpiconehlon_ [l=pl] {_httpimg_/pl/ehlon.gif}
+
+## "BRAK\nWYRÃÅ»NIANIA" ## document_button ## enhl ##
+_httpiconenhlof_ [l=pl] {_httpimg_/pl/enhlof.gif}
+_httpiconenhlon_ [l=pl] {_httpimg_/pl/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=pl] {_If_(_thislast_,wynikÃ³w _thisfirst_ - _thislast_ dla kwerendy: _cgiargq_,Brak wynikÃ³w dla kwerendy: _cgiargq_)}
+_textnoquerytitle_ [l=pl] {Strona wyszukiwania}
+
+_texticonthispage_ [l=pl] {wyszukiwanie}
+_textsome_ [l=pl] {niektÃ³re}
+_textall_ [l=pl] {wszystkie}
+_textboolean_ [l=pl] {logiczne}
+_textranked_ [l=pl] {nr pozycji na liÅcie}
+_textnatural_ [l=pl] {naturalny}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=pl] {}
+_texticonsearchhistorybar_ [l=pl] {historia wyszukiwania}
+
+_textifeellucky_ [l=pl] {WyÅwietl pierwszy znaleziony dokument }
+
+#alt text for query buttons
+_textusequery_ [l=pl] {uÅŒyj tej kwerendy}
+_textfreqmsg1_ [l=pl] {Liczba sÅÃ³w: }
+_textpostprocess_ [l=pl] {_If_(_quotedquery_,<br><i>przetworzone w celu znalezienia _quotedquery_</i>
+)}
+_textinvalidquery_ [l=pl] {NieprawidÅowa skÅadnia kwerendy}
+
+_textmorethan_ [l=pl] {Ponad}
+_textapprox_ [l=pl] {Informacje}
+_textnodocs_ [l=pl] {Brak wynikÃ³w}
+_text1doc_ [l=pl] {znaleziono 1 dokument}
+_textlotsdocs_ [l=pl] {dokumentÃ³w speÅniajÄ
+cych warunki kwerendy.}
+_textmatches_ [l=pl] {Dopasowania}
+_textbeginsearch_ [l=pl] {Rozpocznij wyszukiwanie}
+_textrunquery_ [l=pl] {Uruchom kwerendÄ}
+_textclearform_ [l=pl] {WyczyÅÄ formularz}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=pl] {SÅowo lub wyraÅŒenie}
+_textinfield_ [l=pl] {... w polu}
+_textfoldstem_ [l=pl] {(zÅoÅŒenie, trzon)}
+
+_textadvquery_ [l=pl] {Lub wpisz kwerendÄ:}
+_textallfields_ [l=pl] {wszystkie pola}
+_texttextonly_ [l=pl] {tylko tekst}
+_textand_ [l=pl] {i}
+_textor_ [l=pl] {lub}
+_textandnot_ [l=pl] {i nie}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=pl] {ZnajdÅº _indexselection_ _If_(_jselection_,z _jselection_ )_If_(_gselection_, na poziomie _gselection_ )_If_(_nselection_,w jÄzyku _nselection_ ) zawierajÄ
+ce _querytypeselection_ sÅowa}
+
+_textadvancedsearch_ [l=pl] {ZnajdÅº _indexselection_ _If_(_jselection_,z _jselection_ )_If_(_gselection_,na poziomie _gselection_ )_If_(_nselection_,w jÄzyku _nselection_ )za pomocÄ
+ _querytypeselection_ kwerendy}
+
+_textformsimplesearch_ [l=pl] {ZnajdÅº _If_(_jselection_,_jselection_ )_If_(_gformselection_,na poziomie _gformselection_ )_If_(_nselection_,w jÄzyku _nselection_ ) dla _formquerytypeselection_}
+
+_textformadvancedsearch_ [l=pl] {ZnajdÅº _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )i pokaÅŒ wyniki w kolejnoÅci _formquerytypeselection_}
+
+
+_textnojsformwarning_ [l=pl] {Uwaga: wyÅÄ
+czono obsÅugÄ jÄzyka Javascript w przeglÄ
+darce. <br>Aby uÅŒyÄ formularza wyszukiwania, wÅÄ
+cz Javascript.}
+_textdatesearch_ [l=pl] {W tej kolekcji moÅŒna szukaÄ dokumentÃ³w pasujÄ
+cych do zakresu dat lub dokumenty zawierajÄ
+ce konkretnÄ
+ datÄ. Jest to opcja wyszukiwania.}
+_textstartdate_ [l=pl] {Data poczÄ
+tkowa (lub jedyna):}
+_textenddate_ [l=pl] {Data koÅcowa:}
+_textbc_ [l=pl] {p.n.e.}
+_textad_ [l=pl] {n.e.}
+_textexplaineras_ [l=pl] {SkrÃ³ty C.E. i B.C.E sÄ
+ alternatywnymi oznaczeniami skrÃ³tÃ³w A.D. i B.C.  WyraÅŒenia te sÄ
+ uwaÅŒane za neutralne pod wzglÄdem kulturowym i oznaczajÄ
+ "Common Era", czyli "naszej ery" oraz "Before the Common Era", czyli "przed naszÄ
+ erÄ
+"}
+
+_textstemon_ [l=pl] {(nie uwzglÄdniaj koÅcÃ³wek sÅÃ³w)}
+
+_textsearchhistory_ [l=pl] {Historia wyszukiwania}
+
+#text macros for search history
+_textnohistory_ [l=pl] {Brak wpisÃ³w w historii wyszukiwania}
+_texthresult_ [l=pl] {wynik}
+_texthresults_ [l=pl] {wyniki}
+_texthallwords_ [l=pl] {wszystkie sÅowa}
+_texthsomewords_ [l=pl] {niektÃ³re sÅowa}
+_texthboolean_ [l=pl] {logiczne}
+_texthranked_ [l=pl] {pozycja na liÅcie}
+_texthcaseon_ [l=pl] {uwzglÄdnij wielkoÅÄ liter}
+_texthcaseoff_ [l=pl] {nierozrÃ³ÅŒnianie wielkoÅci liter}
+_texthstemon_ [l=pl] {ograniczenie do trzonu sÅowa}
+_texthstemoff_ [l=pl] {caÅe sÅowa}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "wyszukiwanie" ## green_title ## h_search ##
+_httpiconhsearch_ [l=pl] {_httpimg_/pl/h\_search.gif}
+_widthhsearch_ [l=pl] {200}
+_heighthsearch_ [l=pl] {57}
+
+## "wyniki" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=pl] {_httpimg_/pl/qryresb.gif}
+_widthqryresb_ [l=pl] {_pagewidth_}
+_heightqryresb_ [l=pl] {17}
+
+## "historia" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=pl] {_httpimg_/pl/schhistb.gif}
+_widthsrchhistb_ [l=pl] {_pagewidth_}
+_heightsrchhistb_ [l=pl] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=pl] {Oto zapisane preferencje. Nie uÅŒywaj przycisku Wstecz przeglÄ
+darki
+internetowej, poniewaÅŒ ustawienia zostaÅyby anulowane!
+Kliknij jeden z przyciskÃ³w na pasku powyÅŒej.}
+_textsetprefs_ [l=pl] {zapisz preferencje}
+_textsearchprefs_ [l=pl] {Preferencje wyszukiwania}
+_textcollectionprefs_ [l=pl] {Ustawienia kolekcji}
+_textpresentationprefs_ [l=pl] {Preferencje prezentacji}
+_textpreferences_ [l=pl] {Preferencje}
+_textcasediffs_ [l=pl] {RozrÃ³ÅŒnianie wielkoÅci liter:}
+_textignorecase_ [l=pl] {nie uwzglÄdniaj wielkoÅci liter}
+_textmatchcase_ [l=pl] {uwzglÄdnij wielkoÅÄ liter}
+_textwordends_ [l=pl] {KoÅcÃ³wki sÅÃ³w:}
+_textstem_ [l=pl] {Nie uwzglÄdniaj koÅcÃ³wek sÅÃ³w}
+_textnostem_ [l=pl] {dopasowane musi byÄ caÅe sÅowo}
+_textprefop_ [l=pl] {PokaÅŒ do _maxdocoption_ trafieÅ, _hitsperpageoption_ trafieÅ na jednej stronie.}
+_textextlink_ [l=pl] {DostÄp do zewnÄtrznych stron WWW:}
+_textintlink_ [l=pl] {Lokalizacja dokumentÃ³w ÅºrÃ³dÅowych: }
+_textlanguage_ [l=pl] {JÄzyk interfejsu uÅŒytkownika}
+_textencoding_ [l=pl] {Kodowanie znakÃ³w:}
+_textformat_ [l=pl] {Format interfejsu:}
+_textall_ [l=pl] {wszystkie}
+_textquerymode_ [l=pl] {Tryb kwerendy:}
+_textsimplemode_ [l=pl] {tryb kwerendy prostej}
+_textadvancedmode_ [l=pl] {tryb kwerendy zaawansowanej (umoÅŒliwia wyszukiwanie logiczne za pomocÄ
+ operatorÃ³w !, &, | i nawiasÃ³w)}
+_textlinkinterm_ [l=pl] {przez stronÄ poÅredniÄ
+}
+_textlinkdirect_ [l=pl] {przejdÅº}
+_textdigitlib_ [l=pl] {biblioteka cyfrowa}
+_textweb_ [l=pl] {sieÄ WWW}
+_textgraphical_ [l=pl] {Graficzny}
+_texttextual_ [l=pl] {Tekstowy}
+_textcollectionoption_ [l=pl] {<p>
+UwzglÄdnij podzbiory kolekcji:
+<br>}
+
+_textrelateddocdisplay_ [l=pl] {wyÅwietl dokumenty pokrewne}
+_textsearchhistory_ [l=pl] {Historia wyszukiwania:}
+_textnohistory_ [l=pl] {Brak historii wyszukiwania}
+_texthistorydisplay_ [l=pl] {pokaÅŒ wpisy _historynumrecords_ ostatnich wyszukiwaÅ}
+_textnohistorydisplay_ [l=pl] {nie wyÅwietlaj historii wyszukiwania}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=pl] {Formularz wyszukiwania:}
+_textplainsearch_ [l=pl] {ZwykÅe wyszukiwanie:}
+_textqueryboxsize_ [l=pl] {Rozmiar pola kwerendy:}
+_textregbox_ [l=pl] {zwykÅe pole kwerendy}
+_textbigbox_ [l=pl] {duÅŒe pole kwerendy}
+_textformtype_ [l=pl] {Typ Formularza:}
+_textsimple_ [l=pl] {prosty}
+_textadvanced_ [l=pl] {zaawansowany}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=pl] {z}
+_textfields_ [l=pl] {pola}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferencje" ## green_title ## h_pref ##
+_httpiconhpref_ [l=pl] {_httpimg_/pl/h\_pref.gif}
+_widthhpref_ [l=pl] {200}
+_heighthpref_ [l=pl] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=pl] {Sortuj dokumenty wedÅug}
+_textalsoshowing_ [l=pl] {rÃ³wnieÅŒ}
+_textwith_ [l=pl] {zawierajÄ
+ce co najwyÅŒej}
+_textdocsperpage_ [l=pl] {dokumentÃ³w na stronie}
+
+_textfilterby_ [l=pl] {ZnajdÅº dokumenty zawierajÄ
+ce}
+_textall_ [l=pl] {wszystkie}
+_textany_ [l=pl] {niektÃ³re}
+_textwords_ [l=pl] {sÅowa}
+_textleaveblank_ [l=pl] {pozostaw pole nie zaznaczone, aby otrzymaÄ wszystkie dokumenty}
+
+_browsebuttontext_ [l=pl] {"Sortuj dokumenty"}
+
+_nodata_ [l=pl] {<i>brak danych</i>}
+_docs_ [l=pl] {dokumenty}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=pl] {Pomoc}
+_textSearchshort_ [l=pl] {znajdÅº sÅowa}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=pl] {przeglÄ
+daj wedÅug tytuÅÃ³w}
+_textCreatorshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug autorÃ³w}
+_textSubjectshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug tematu}
+_textDescriptionshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug opisu}
+_textPublishershort_ [l=pl] {przeglÄ
+daj publikacje wedÅug wydawcÃ³w}
+_textContributorshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug  wspÃ³ÅpracownikÃ³w}
+_textDateshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug dat}
+_textTypeshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug typÃ³w}
+_textFormatshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug formatÃ³w}
+_textIdentifiershort_ [l=pl] {przeglÄ
+daj publikacje wedÅug identifykatora}
+_textSourceshort_ [l=pl] {przeglÄ
+daj wedÅug nazw plikÃ³w}
+_textLanguageshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug jÄzyka}
+_textRelationshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug relacji}
+_textCoverageshort_ [l=pl] {przeglÄ
+daj wedÅug dziedziny}
+_textRightsshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug praw autorskich}
+
+_textSeriesshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug serii}
+_textToshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug pola Do (odbiorca)}
+_textFromshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug zawartoÅci pola Od (nadawca)}
+_textBrowseshort_ [l=pl] {przeglÄ
+daj publikacje}
+_textOrganizationshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug organizacji}
+_textHowtoshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug listy "jak..."}
+_textTopicshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug tematÃ³w}
+_textPeopleshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug nazwisk}
+_textAcronymshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug wystÄpujÄ
+cych skrÃ³tÃ³w}
+_textPhraseshort_ [l=pl] {przeglÄ
+daj wedÅug wyraÅŒeÅ w publikacjach}
+_textArtistshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug  nazwisk artystÃ³w}
+_textKeywordshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug sÅÃ³w kluczowych}
+_textVolumeshort_ [l=pl] {przeglÄ
+daj publikacje wedÅug wolumenÃ³w}
+_textCountriesshort_ [l=pl] {przeglÄ
+daj wedÅug krajÃ³w}
+_textdefaultshorttext_ [l=pl] {brak okreÅlonej klasyfikacji}
+
+_textSearchlong_ [l=pl] {<p>MoÅŒna <i>wyszukiwaÄ dokumenty zawierajÄ
+ce okreÅlone sÅowa</i>. 
+W tym celu naleÅŒy otworzyÄ stronÄ wyszukiwania. Jest to pierwsza strona
+pojawiajÄ
+ca siÄ po uruchomieniu programu. Aby otworzyÄ jÄ
+ z dowolnej
+innej strony programu, kliknij przycisk <i>znajdÅº</i>.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug tytuÅÃ³w</i>,
+kliknij przycisk <i>tytuÅy a-z</i>.  Pojawi siÄ lista ksiÄ
+ÅŒek
+w kolejnoÅci alfabetycznej.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug autorÃ³w</i>,
+kliknij przycisk <i>autorzy a-z</i>.  Pojawi siÄ lista ksiÄ
+ÅŒek
+uporzÄ
+dkowana wedÅug nazwisk autorÃ³w.  }
+
+_textSubjectlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug tematu</i>,
+kliknij przycisk <i>tematy</i>.  Pojawi siÄ lista tematÃ³w,
+kaÅŒdy przedstawiony jako pÃ³Åka z ksiÄ
+ÅŒkami.  }
+
+_textDescriptionlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug opisu</i>,
+kliknij przycisk <i>opisy</i>.  Pojawi siÄ lista opisÃ³w.  }
+
+_textPublisherlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug wydawcy</i>,
+kliknij przycisk <i>wydawcy</i>.  Pojawi siÄ lista wydawcÃ³w.  }
+
+_textContributorlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug nazwisk wspÃ³ÅpracownikÃ³w</i>,
+kliknij przycisk <i>wspÃ³Åpracownicy</i>.  Pojawi siÄ lista wspÃ³ÅpracownikÃ³w. }
+
+_textDatelong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug dat</i>, kliknij
+przycisk <i>daty</i>.  Pojawi siÄ lista wszystkich wydaÅ
+w kolejnoÅci chronologicznej.  }
+
+_textTypelong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug typu</i>,
+kliknij przycisk <i>typy</i>.  Pojawi siÄ lista typÃ³w.  }
+
+_textFormatlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug formatÃ³w</i>,
+kliknij przycisk <i>formaty</i>.  Pojawi siÄ lista formatÃ³w.}
+
+_textIdentifierlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug identyfikatora</i>,
+kliknij przycisk <i>identyfikatory</i>.  Pojawi siÄ lista identyfikatorÃ³w.  }
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug nazw plikÃ³w</i>,
+kliknij przycisk <i>nazwy plikÃ³w</i>.  Pojawi siÄ alfabetyczna lista
+plikÃ³w.  }
+
+_textLanguagelong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug jÄzyka</i>,
+kliknij przycisk <i>jÄzyki</i>.  Pojawi siÄ alfabetyczna lista
+jÄzykÃ³w.  }
+
+_textRelationlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug relacji</i>,
+kliknij przycisk <i>relacje</i>.  Pojawi siÄ lista relacji.}
+
+_textCoveragelong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug dziedzin</i>,
+kliknij przycisk <i>dziedzina</i>.  }
+
+_textRightslong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug praw autorskich</i>,
+kliknij przycisk <i>prawa autorskie</i>.  }
+
+
+
+_textOrganizationlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wg
+organizacji</i> kliknij przycisk <i>Organizacje</i>.  Pojawi siÄ
+lista organizacji.  }
+
+_textHowtolong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug listy "jak..." (jak to zrobiÄ)</i>,
+kliknij przycisk <i>jak...</i>.  Pojawi siÄ lista zagadnieÅ "jak to zrobiÄ".  }
+
+_textTopiclong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug tematÃ³w</i>,
+kliknij przycisk <i>temat</i>.  Pojawi siÄ lista tematÃ³w.  }
+
+_textTolong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug pola Do (odbiorca)</i>,
+kliknij przycisk <i>do</i>.  Pojawi siÄ lista odbiorcÃ³w.  }
+
+_textFromlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug zawartoÅci pola Od (nadawca)</i>,
+kliknij przycisk <i>od (nadawca)</i>.  Pojawi siÄ lista nadawcÃ³w.  }
+
+_textSerieslong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug serii</i>,
+kliknij przycisk <i>serie</i>.  Pojawi siÄ lista serii
+znajdujÄ
+cych siÄ w kolekcji.  }
+
+_textBrowselong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje</i>, kliknij
+przycisk <i>przeglÄ
+daj</i> .  }
+
+_textPeoplelong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug nazwiski</i>,
+kliknij przycisk <i>osoby a-z</i>.  Pojawi siÄ alfabetyczna
+lista nazwisk.  }
+
+_textAcronymlong_ [l=pl] {<p>Aby znaleÅºÄ <i>publikacje zawierajÄ
+ce wyszukiwane skrÃ³ty</i>,
+kliknij przycisk <i>skrÃ³ty</i> .  Pojawi siÄ lista skrÃ³tÃ³w
+i miejsc, w ktÃ³rych siÄ pojawiajÄ
+.  }
+
+_textPhraselong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug wyraÅŒeÅ</i>,
+kliknij przycisk <i>wyraÅŒenia</i>.  Pojawi siÄ przeglÄ
+darka wyraÅŒeÅ phind.  }
+
+_textArtistlong_ [l=pl] {<p>Aby znaleÅºÄ <i>publikacje dotyczÄ
+ce artysty</i>,
+kliknij przycisk <i>artysta</i>.  Pojawi siÄ alfabetyczna
+lista artystÃ³w.  }
+
+_textKeywordlong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug sÅÃ³w kluczowych</i>,
+kliknij przycisk <i>sÅowa kluczowe</i>.  Pojawi siÄ lista sÅÃ³w kluczowych. }
+
+_textVolumelong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug wolumenÃ³w</i>,
+kliknij przycisk <i>wolumeny</i>. Pojawi siÄ lista wolumenÃ³w. }
+
+_textCaptionslong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje zawierajÄ
+ce poszukiwany podpis pod grafikÄ
+</i>,
+kliknij przycisk <i>podpisy</i>. Pojawi siÄ lista podpisÃ³w. }
+
+_textCountrieslong_ [l=pl] {<p>Aby <i>przeglÄ
+daÄ publikacje wedÅug kraju pochodzenia</i>
+kliknij przycisk <i>kraje</i>. Pojawi siÄ lista krajÃ³w.}
+
+
+_textdefaultlongtext_ [l=pl] {<p>Kliknij przycisk <i>Nieznane</i>, aby
+przeglÄ
+daÄ publikacje uporzÄ
+dkowane wedÅug zawartoÅci pola Nieznane.  }
+
+_texthelptopics_ [l=pl] {<h2 align=left>Tematy</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Wyszukiwanie wyrazÃ³w</a>
+<ul>
+  <li><a href="\#query-terms">PostaÄ kwerendy</a>
+  <li><a href="\#query-type">Typ kwerendy</a>
+  <li><a href="\#scope-of-queries">Zakres kwerendy</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Preferencje kolekcji</a>
+  <li><a href="\#lang-prefs">Preferencje jÄzykowe</a>
+  <li><a href="\#pres-prefs">Preferencje prezentacji</a>
+  <li><a href="\#search-prefs">Preferencje wyszukiwania</a>
+</ul>
+</ul>}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=pl] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=pl] {Jak czytaÄ dokumenty}
+
+_texthelpreadingdocs_ [l=pl] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Po znalezieniu dokumentu w lewym gÃ³rnym rogu strony pojawia siÄ
+jego tytuÅ lub obraz strony tytuÅowej. W niektÃ³rych kolekcjach towarzysz temu spis treÅci,
+a w innych pojawia siÄ tylko numer strony bieÅŒÄ
+cej oraz pole umoÅŒliwiajÄ
+ce wybÃ³r
+nowej strony i przejÅcie do przodu lub wstecz. W spisie treÅci nagÅÃ³wek
+bieÅŒÄ
+cego rozdziaÅu jest drukowany czcionkÄ
+ pogrubionÄ
+, a spis jest rozwijalny --
+kliknij nazwÄ folderu, aby go otworzyÄ lub zamknÄ
+Ä; aby zamknÄ
+Ä ksiÄ
+ÅŒkÄ,
+kliknij u gÃ³ry ikonÄ otwartej ksiÄ
+ÅŒki.</p>
+
+<p>PoniÅŒej znajduje siÄ tekst bieÅŒÄ
+cego rozdziaÅu. StrzaÅki u doÅu strony
+umoÅŒliwiajÄ
+ przejÅcie do nastÄpnego lub poprzedniego rozdziaÅu.</p>
+
+<p>Pod tytuÅem lub fotografiÄ
+ znajduje siÄ kilka przyciskÃ³w. Aby rozwinÄ
+Ä
+caÅy tekst bieÅŒÄ
+cego rozdziaÅu lub ksiÄ
+ÅŒki, kliknij przycisk <i>RozwiÅ tekst</i>.
+Rozwijanie tekstu duÅŒego dokumentu moÅŒe trwaÄ dÅugo i zajÄ
+Ä sporo pamiÄci operacyjnej!
+Aby rozwinÄ
+Ä zawartoÅÄ spisu treÅci, kliknij przycisk<i>RozwiÅ spis treÅci</i>.
+Aby otworzyÄ nowe okno przeglÄ
+darki, kliknij przycisk <i>Nowe okno</i>
+(Jest to przydatne podczas porÃ³wnywania zawartoÅci lub jednoczesnego odczytywania dwÃ³ch dokumentÃ³w.)
+W wynikach wyszukiwania poszukiwane wyrazy sÄ
+ wyrÃ³ÅŒnione. Aby wyÅÄ
+czyÄ wyrÃ³ÅŒnianie, naleÅŒy kliknÄ
+Ä przycisk <i>Bez wyrÃ³ÅŒniania</i>.</p>
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>OtwÃ³rz pÃ³ÅkÄ z ksiÄ
+ÅŒkami</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>OtwÃ³rz/zamknij ksiÄ
+ÅŒkÄ</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>PrzeglÄ
+daj rozdziaÅ</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>WÅÄ
+cz/WyÅÄ
+cz wyÅwietlanie caÅego tekstu</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>RozwiÅ/ZwiÅ spis treÅci</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>OtwÃ³rz stronÄ w nowym oknie</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>WyrÃ³ÅŒniaj/Nie wyrÃ³ÅŒniaj wyszukiwane wyraÅŒenia</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Kliknij strzaÅkÄ, aby otworzyÄ nastÄpny rozdziaÅ ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... lub wrÃ³ciÄ do poprzedniego rozdziaÅu</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=pl] {<h2>Jak formuÅowaÄ kwerendÄ w poszukiwaniu konkretnych wyrazÃ³w</h2>
+<p>
+  Aby uruchomiÄ kwerendÄ, wykonaj na stronie wyszukiwania nastÄpujÄ
+ce czynnoÅci:<p>
+  
+  <ol><li>Wybierz rodzaj poszukiwanych wyraÅŒeÅ
+      <li>Zdecyduj, czy dopasowane majÄ
+ byÄ wszystkie sÅowa, czy tylko niektÃ³re sÅowa kwerendy
+      <li>Wpisz poszukiwane wyrazy
+      <li>Kliknij przycisk <i>Rozpocznij wyszukiwanie</i>
+  </ol>
+
+<p>Po zakoÅczeniu kwerendy pojawiÄ
+ siÄ tytuÅy 20 dokumentÃ³w.
+Przycisk u doÅu strony umoÅŒliwia przejÅcie do nastÄpnych 20 dokumentÃ³w.
+Na nastÄpnej stronie moÅŒna wybraÄ kolejnych 20 dokumentÃ³w
+lub powrÃ³ciÄ do poprzedniej dwudziestki itd.  Aby przejrzeÄ dokument, kliknij tytuÅ
+dokumentu lub maÅy przycisk obok niego.
+
+<p>Maksymalnie wynik wyszukiwania obejmuje 100 dokumentÃ³w.
+  Aby zmieniÄ tÄ liczbÄ, kliknij przycisk
+  <i>preferencje</i> u gÃ³ry strony.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>PostaÄ kwerendy</h3>
+
+<p>Wyszukiwane sa wszystkie wyraÅŒenia w polu kwerendy. 
+SÅowo moÅŒe zawieraÄ jedynie litery i cyfry. Wyrazy sÄ
+ oddzielone "biaÅymi" znakami
+(spacjami lub znakami tabulacji).  JeÅŒeli pojawiajÄ
+ siÄ inne znaki, np. interpunkcyjne,
+sÄ
+ traktowane jak spacje. Wyszukiwanie ciÄ
+gÃ³w znakÃ³w zawierajÄ
+cych znaki
+interpunkcyjne nie jest moÅŒliwe.
+
+<p>Na przykÅad, kwerenda<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>daje ten sam wynik, co<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Typ kwerendy</h3>
+
+<p>SÄ
+ dwa rodzaje kwerend.
+
+<ul>
+  <li>Wyszukiwanie <b>wszystkich</b> wyrazÃ³w.  Dokumenty majÄ
+ zawieraÄ
+      wszystkie wpisane sÅowa.  Wyniki sÄ
+ wyÅwietlane w kolejnoÅci alfabetycznej.<p>
+
+  <li>Wyszukiwanie dokumentÃ³w zawierajÄ
+cych <b>niektÃ³re</b> spoÅrÃ³d wpisanych wyrazÃ³w.
+      Dokumenty sÄ
+ wyÅwietlane w kolejnoÅci najlepszego dopasowania do kwerendy.
+      StopieÅ dopasowania zaleÅŒy od nastÄpujÄ
+cych czynnikÃ³w:
+
+      <p><ul>
+        <li> im wiÄcej poszukiwanych wyrazÃ³w w dokumencie, tym lepsze dopasowanie;
+        <li> rzadko spotykane wyrazy sÄ
+ waÅŒniejsze niÅŒ wyrazy popularne;
+        <li> krÃ³tkie dokumenty dajÄ
+ lepsze dopasowanie.
+      </ul>
+</ul>
+
+<p>MoÅŒna uÅŒyÄ dowolnie wielu wyrazÃ³w -- moÅŒe to byÄ caÅe zdanie
+lub nawet caÅy akapit.  W przypadku podania tylko jednego wyrazu
+dokumenty bÄdÄ
+ uÅoÅŒone wedÅug czÄstotliwoÅci wystÄpowania wyrazu w dokumencie.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=pl] {Przeszukiwanie wedÅug dat}
+
+_texthelpdatesearch_ [l=pl] {<h2>_textdatesearch_</h2>
+Wyszukiwanie wedÅug dat umoÅŒliwia znalezienie dokumentÃ³w
+dotyczÄ
+cych zdarzeÅ z pewnego okresu.  MogÄ
+ to byÄ dokumenty 
+z jednego roku lub z przedziaÅu lat.  Wpisanie poszukiwanych wyraÅŒeÅ 
+nie jest konieczne. Wpisywanie dat rÃ³wnieÅŒ nie jest obowiÄ
+zkowe.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>SposÃ³b uÅŒycia:</h3>
+<ul>
+   <li>W celu wyszukania dokumentÃ³w dotyczÄ
+cych jednego roku:<p>
+   <ul>
+       B970<li>Wpisz poszukiwane wyraÅŒenia
+       <li>Wpisz rok w polu "Data poczÄ
+tkowa (lub jedyna data)"
+       <li>JeÅŒeli data naleÅŒy do okresu przed naszÄ
+ erÄ
+ (przed Chrystusem), 
+           w menu rozwijalnym obok tego pola zaznacz opcjÄ "p.n.e."
+       <li>Uruchom wyszukiwanie
+   </ul>
+<p><li>W celu wyszukania dokumentÃ³w dotyczÄ
+cych zakresu dat:<p>
+   <ul>
+       <li>Wpisz poszukiwane wyraÅŒenia
+       <li>W polu "Data poczÄ
+tkowa (lub jedyna data)" wpisz datÄ poczÄ
+tkowÄ
+
+       <li>W polu "Data koÅcowa" wpisz datÄ koÅcowÄ
+
+       <li>W meniu rozwijalnym zaznacz opcjÄ "p.n.e." obok tej daty lub dat, ktÃ³rych to dotyczy
+       <li>Uruchom wyszukiwanie
+   </ul>    
+</ul><p>
+B939
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>ReguÅy wyszukiwania</h3>
+
+Wyszukiwanie dokumentÃ³w dotyczÄ
+cych roku 1903 oznacza wyszukiwanie dokumentÃ³w na temat roku 1903, a nie np. spisÃ³w literatury wydanych w 1903.  Wynik kwerendy moÅŒe zawieraÄ dokumenty dotyczÄ
+ce np. lat 1899-1911, poniewaÅŒ 1903 mieÅci siÄ w tym przedziale czasu oraz dokumenty z tytuÅem zawierajÄ
+cym wzmiankÄ o stuleciu, do ktÃ³rego naleÅŒy poszukiwany rok (np. 20 stulecie lub dwudziesty wiek).  Oznacza to, ÅŒe poszukiwane daty mogÄ
+ w ogÃ³le siÄ nie pojawiaÄ w dokumentach przedstawionych w wyniku kwerendy<p>
+}
+
+_textchangeprefs_ [l=pl] {Zmiana preferencji}
+
+_texthelppreferences_ [l=pl] {<h2>_textchangeprefs_</h2>
+
+<p>Aby dostosowaÄ interfejs do wÅasnych potrzeb, kliknij przycisk <i>preferencje</i> u gÃ³ry strony.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Preferencje kolekcji</h3>
+
+NiektÃ³re kolekcje skÅadajÄ
+ siÄ z podzbiorÃ³w, ktÃ³re moÅŒna przeszukiwaÄ
+niezaleÅŒnie od siebie lub ÅÄ
+cznie, jak jednÄ
+ caÅoÅÄ.  Na stronie Preferencje moÅŒna
+wybraÄ podkolekcje, ktÃ³re majÄ
+ byÄ uwzglÄdnione podczas przeszukiwania.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Preferencje jÄzykowe</h3>
+
+KaÅŒda kolekcja ma domyÅlny jÄzyk prezentacji, ale moÅŒna wÅÄ
+czyÄ inny jÄzyk.
+MoÅŒna takÅŒe zmieniÄ schemat kodowania znakÃ³w w bibliotece Greenstone, aby dostosowaÄ go
+do przeglÄ
+darki na swoim komputerze -- program wybiera wartoÅci domyÅlne,
+ktÃ³re zwykle dajÄ
+ dobre wyniki, ale w niektÃ³rych przeglÄ
+darkach lepiej jest wybraÄ
+inny schemat kodowania znakÃ³w. Wszystkie kolekcje umoÅŒliwiajÄ
+ zmianÄ domyÅlnego
+interfejsu graficznego na interfejs tekstowy. Jest to szczegÃ³lnie przydatne tym,
+ktÃ³rzy ze wzglÄdu na trudnoÅci wzrokowe uÅŒywajÄ
+ duÅŒych czcionek ekranowych
+lub syntezatorÃ³w mowy w celu prezentacji wynikÃ³w.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Preferencje prezentacji</h3>
+
+W zaleÅŒnoÅci od kolekcji moÅŒna ustawiÄ kilka opcji w celu polepszenia wizualnej jakoÅci
+prezentacji.
+
+<p>W kolekcjach stron WWW moÅŒna wyÅÄ
+czyÄ pasek nawigacyjny u gÃ³ry kaÅŒdej strony
+dokumentu, dziÄki czemu po zakoÅczeniu wyszukiwania wyÅwietlana jest poszukiwana
+strona WWW bez nagÅÃ³wka biblioteki Greenstone.  Aby ponownie uruchomiÄ
+wyszukiwanie, naleÅŒy w oknie przeglÄ
+darki internetowej kliknÄ
+Ä przycisk Wstecz. 
+MoÅŒna takÅŒe wyÅÄ
+czyÄ komunikaty diagnostyczne biblioteki, klikajÄ
+c odsyÅacz
+strony internetowej ulokowanej poza bibliotekÄ
+.  W niektÃ³rych kolekcjach
+stron WWW moÅŒna wybraÄ, czy odsyÅacze na stronie Wyniki wyszukiwania
+majÄ
+ wskazywaÄ URL strony, czy jej kopiÄ przechowywanÄ
+ w bibliotece cyfrowej.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Preferencje wyszukiwania</h3>
+<p>Rodzaj dopasowania podczas przeszukiwania tekstu moÅŒna wybraÄ za pomocÄ
+
+dwÃ³ch par przyciskÃ³w. Pierwsza para, WielkoÅÄ liter, okreÅla, czy dopasowanie
+ma uwzglÄdniaÄ wielkoÅÄ liter.  Druga, KoÅcÃ³wki sÅÃ³w, okreÅla, czy dopasowanie
+ma uwzglÄdniaÄ koÅcÃ³wki sÅÃ³w.  MoÅŒna takÅŒe wyszukiwaÄ za pomocÄ
+ duÅŒego
+okna kwerendy. DziÄki temu Åatwo jest wyszukaÄ tekst wielkoÅci caÅego akapitu.
+Czas przeszukiwania nawet znacznych iloÅci tekstu jest krÃ³tki.
+
+<p>Na przykÅad, jeÅŒeli wybrano przyciski <i>Nie uwzglÄdniaj wielkoÅci liter</i> i
+<i>Nie uwzglÄdniaj koÅcÃ³wek sÅÃ³w</i>, kwerenda<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>bÄdzie rÃ³wnowaÅŒna kwerendzie<p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      poniewaÅŒ wielka litera w wyrazie "African" bÄdzie zmieniona w maÅÄ
+,
+      a w wyrazach "African" i "building" zostanÄ
+ usuniÄte przyrostki "n" i "ing".
+      W sÅowie "builds" usuniÄta zostanie litera "s".
+
+<p>Zaawansowany tryb kwerendy umoÅŒliwia modyfikowanie wyraÅŒeÅ za pomocÄ
+
+koniunkcji AND (&), alternatywy OR (|), i zaprzeczenia NOT (!). MoÅŒna takÅŒe wÅÄ
+czyÄ 
+opcjÄ Historia wyszukiwania, ktÃ³ra pokazuje kilka ostatnich kwerend.
+UÅatwia to wykonywanie kwerend bÄdÄ
+cych niewielkÄ
+ modyfikacjÄ
+ wczeÅniejszych
+wyszukiwaÅ. UstawiÄ moÅŒna rÃ³wnieÅŒ maksymalnÄ
+ liczbÄ trafieÅ oraz liczbÄ trafieÅ
+prezentowanych jednorazowo w oknie.
+}
+
+_texttanumbrowseoptions_ [l=pl] {Jest _numbrowseoptions_ sposobÃ³w wyszukiwania informacji w tej kolekcji:}
+
+_textsimplehelpheading_ [l=pl] {Jak znaleÅºÄ informacje w kolekcji _collectionname_}
+
+_texthelpscope_ [l=pl] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Zakres kwerendy</h3>
+
+<p>
+W wiÄkszoÅci kolekcji moÅŒna wybraÄ rÃ³ÅŒne indeksy przeszukiwania, na przykÅad
+spis autorÃ³w lub tytuÅÃ³w. DostÄpne mogÄ
+ byÄ rÃ³wnieÅŒ indeksy dotyczÄ
+ce rozdziaÅÃ³w
+lub akapitÃ³w. Zwykle zwracany jest peÅny dokument, niezaleÅŒnie od rodzaju przeszukiwanego indeksu.
+<p>KsiÄ
+ÅŒki sÄ
+ otwierane automatycznie w miejscu wÅaÅciwym dla wykonanej kwerendy.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/port-br.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/port-br.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/port-br.dm	(revision 10506)
@@ -0,0 +1,1238 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Portuguese (Brasil) Language text and icon macros 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textperiodicals_
+# -- Missing translation: _textsource_
+# -- Missing translation: _textdate_
+# -- Missing translation: _textnumpages_
+
+# -- Missing translation: _textsignin_
+
+_textdefaultcontent_ [l=pt-br] {A pÃ¡gina requerida nÃ£o pode ser encontrada. Por favor,
+use o botÃ£o 'back' do seu browser ou o botÃ£o home para retornar para a Biblioteca Digital Greenstone.}
+
+_textdefaulttitle_ [l=pt-br] {GSDL Erro}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=pt-br] {Esta coleÃ§Ã£o contÃ©m _about:numdocs_ documentos. 
+Que foi montada _about:builddate_ dias atrÃ¡s.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+# -- Missing translation: _collectorextra_
+
+_textimagecollection_ [l=pt-br] {}
+_textimageabout_ [l=pt-br] {PÃ¡gina Sobre}
+_textimagehome_ [l=pt-br] {PÃ¡gina Principal}
+_textimagehelp_ [l=pt-br] {PÃ¡gina Ajuda}
+_textimagepref_ [l=pt-br] {PÃ¡gina PreferÃªncias}
+_textimagegreenstone_ [l=pt-br] {Greenstone Digital Library Software}
+# -- Missing translation: _textimageusab_
+
+_textimagesearch_ [l=pt-br] {Busca por termos especÃ­ficos}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=pt-br] {Lista alfabÃ©tica de tÃ­tulos}
+_textimageCreator_ [l=pt-br] {Lista alfabÃ©tica de autores}
+_textimageSubject_ [l=pt-br] {Listar categorias de assunto}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=pt-br] {Listar por data}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+# -- Missing translation: _textimageSource_
+# -- Missing translation: _textimageLanguage_
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=pt-br] {Listar por organizaÃ§Ã£o}
+# -- Missing translation: _textimageKeyword_
+_textimageHowto_ [l=pt-br] {Listar categorias como fazer }
+_textimageList_ [l=pt-br] {Lista de documentos}
+_textimageSeries_ [l=pt-br] {Listar por ediÃ§Ã£o}
+# -- Missing translation: _textimageTo_
+# -- Missing translation: _textimageFrom_
+_textimageTopic_ [l=pt-br] {Listar tÃ³picos de ediÃ§Ãµes especiais}
+_textimageBrowse_ [l=pt-br] {Listar}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=pt-br] {Lista alfabÃ©tica de pessoas}
+# -- Missing translation: _textimageAcronym_
+# -- Missing translation: _textimagePhrase_
+# -- Missing translation: _textimageArtist_
+# -- Missing translation: _textimageVolume_
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=pt-br] {Busca}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=pt-br] {TÃ­tulos A-Z}
+_texticontabCreatorgreen_ [l=pt-br] {Autors A-Z}
+_texticontabSubjectgreen_ [l=pt-br] {Assunto}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=pt-br] {Datas}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+# -- Missing translation: _texticontabSourcegreen_
+# -- Missing translation: _texticontabLanguagegreen_
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=pt-br] {OrganizaÃ§Ã£o}
+# -- Missing translation: _texticontabKeywordgreen_
+_texticontabhowgreen_ [l=pt-br] {Como fazer}
+_texticontabseriesgreen_ [l=pt-br] {SÃ©ries}
+_texticontablistgreen_ [l=pt-br] {Listagem}
+# -- Missing translation: _texticontabtogreen_
+# -- Missing translation: _texticontabfromgreen_
+_texticontabtopicgreen_ [l=pt-br] {TÃ³picos}
+_texticontabbrwsegreen_ [l=pt-br] {Listar}
+# -- Missing translation: _texticontabCollagegreen_
+# -- Missing translation: _texticontabbrowsgreen_
+_texticontabPeoplegreen_ [l=pt-br] {Pessoas A-Z}
+# -- Missing translation: _texticontabAcronymgreen_
+# -- Missing translation: _texticontabPhrasegreen_
+# -- Missing translation: _texticontabArtistgreen_
+# -- Missing translation: _texticontabVolumegreen_
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=pt-br] {Visualizar o documento}
+_texticonclosedbook_ [l=pt-br] {Abrir este documento e visualizar o conteÃºdo}
+_texticonnext_ [l=pt-br] {seÃ§Ã£o posterior}
+_texticonprev_ [l=pt-br] {seÃ§Ã£o anterior}
+
+# -- Missing translation: _texticonworld_
+
+# -- Missing translation: _texticonmidi_
+# -- Missing translation: _texticonmsword_
+# -- Missing translation: _texticonmp3_
+# -- Missing translation: _texticonpdf_
+# -- Missing translation: _texticonps_
+# -- Missing translation: _texticonppt_
+# -- Missing translation: _texticonrtf_
+# -- Missing translation: _texticonxls_
+
+_page_ [l=pt-br] {pÃ¡gina }
+_pages_ [l=pt-br] {pÃ¡ginas}
+_of_ [l=pt-br] {de }
+_vol_ [l=pt-br] {Volume}
+_num_ [l=pt-br] {NÃºmero}
+
+_textmonth00_ [l=pt-br] {}
+_textmonth01_ [l=pt-br] {Janeiro}
+_textmonth02_ [l=pt-br] {Fevereiro}
+_textmonth03_ [l=pt-br] {MarÃ§o}
+_textmonth04_ [l=pt-br] {Abril}
+_textmonth05_ [l=pt-br] {Maio}
+_textmonth06_ [l=pt-br] {Junho}
+_textmonth07_ [l=pt-br] {Julho}
+_textmonth08_ [l=pt-br] {Agosto}
+_textmonth09_ [l=pt-br] {Setembro}
+_textmonth10_ [l=pt-br] {Outubro}
+_textmonth11_ [l=pt-br] {Novembro}
+_textmonth12_ [l=pt-br] {Dezembro}
+
+# -- Missing translation: _textdocument_
+# -- Missing translation: _textsection_
+# -- Missing translation: _textparagraph_
+
+_magazines_ [l=pt-br] {Revistas}
+
+_nzdlpagefooter_ [l=pt-br] {<p>_iconblankbar_
+<p><a href="_gwcgi_">Projeto Biblioteca Digital Nova ZelÃ¢ndia</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Departamento de CiÃªncia da ComputaÃ§Ã£o</a>, 
+<a href="http://www.waikato.ac.nz">Universidade de Waikato</a>, 
+Nova ZelÃ¢ndia}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "PRINCIPAL" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=pt-br] {_httpimg_/pt-br/chomeof.gif}
+_httpiconchomeon_ [l=pt-br] {_httpimg_/pt-br/chomeon.gif}
+
+## "AJUDA" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=pt-br] {_httpimg_/pt-br/chelpof.gif}
+_httpiconchelpon_ [l=pt-br] {_httpimg_/pt-br/chelpon.gif}
+
+## "PREFERÃNCIAS" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=pt-br] {_httpimg_/pt-br/cprefof.gif}
+_httpiconcprefon_ [l=pt-br] {_httpimg_/pt-br/cprefon.gif}
+
+# -- Missing translation: cusab
+# -- Missing translation: _httpiconcusabof_
+# -- Missing translation: _httpiconcusabon_
+
+
+## "buscar" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=pt-br] {_httpimg_/pt-br/tsrchgr.gif}
+_httpicontsrchof_ [l=pt-br] {_httpimg_/pt-br/tsrchof.gif}
+_httpicontsrchon_ [l=pt-br] {_httpimg_/pt-br/tsrchon.gif}
+_widthtsrchx_ [l=pt-br] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tÃ­tulos a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=pt-br] {_httpimg_/pt-br/ttitlgr.gif}
+_httpiconttitleof_ [l=pt-br] {_httpimg_/pt-br/ttitlof.gif}
+_httpiconttitleon_ [l=pt-br] {_httpimg_/pt-br/ttitlon.gif}
+_widthttitlex_ [l=pt-br] {87}
+
+# Not true DC, kept for legacy reasons
+## "autores a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=pt-br] {_httpimg_/pt-br/tauthgr.gif}
+_httpicontcreatof_ [l=pt-br] {_httpimg_/pt-br/tauthof.gif}
+_httpicontcreaton_ [l=pt-br] {_httpimg_/pt-br/tauthon.gif}
+_widthtcreatx_ [l=pt-br] {95}
+
+## "assuntos" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=pt-br] {_httpimg_/pt-br/tsubjgr.gif}
+_httpicontsubjon_ [l=pt-br] {_httpimg_/pt-br/tsubjon.gif}
+_httpicontsubjof_ [l=pt-br] {_httpimg_/pt-br/tsubjof.gif}
+_widthtsubjx_ [l=pt-br] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "datas" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=pt-br] {_httpimg_/pt-br/tdategr.gif}
+_httpicontdateof_ [l=pt-br] {_httpimg_/pt-br/tdateof.gif}
+_httpicontdateon_ [l=pt-br] {_httpimg_/pt-br/tdateon.gif}
+_widthtdatex_ [l=pt-br] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: tsrc
+# -- Missing translation: _httpicontsrcgr_
+# -- Missing translation: _httpicontsrcof_
+# -- Missing translation: _httpicontsrcon_
+# -- Missing translation: _widthtsrcx_
+
+# -- Missing translation: tlang
+# -- Missing translation: _httpicontlanggr_
+# -- Missing translation: _httpicontlangon_
+# -- Missing translation: _httpicontlangof_
+# -- Missing translation: _widthtlangx_
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "sÃ©ries" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=pt-br] {_httpimg_/pt-br/tsergr.gif}
+_httpicontserof_ [l=pt-br] {_httpimg_/pt-br/tserof.gif}
+_httpicontseron_ [l=pt-br] {_httpimg_/pt-br/tseron.gif}
+_widthtserx_ [l=pt-br] {87}
+
+# -- Missing translation: tto
+# -- Missing translation: _httpiconttogr_
+# -- Missing translation: _httpiconttoon_
+# -- Missing translation: _httpiconttoof_
+# -- Missing translation: _widthttox_
+
+# -- Missing translation: tfrom
+# -- Missing translation: _httpicontfromgr_
+# -- Missing translation: _httpicontfromon_
+# -- Missing translation: _httpicontfromof_
+# -- Missing translation: _widthtfromx_
+
+## "organizaÃ§Ã£o" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=pt-br] {_httpimg_/pt-br/torggr.gif}
+_httpicontorgon_ [l=pt-br] {_httpimg_/pt-br/torgon.gif}
+_httpicontorgof_ [l=pt-br] {_httpimg_/pt-br/torgof.gif}
+_widthtorgx_ [l=pt-br] {103}
+
+## "como fazer" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=pt-br] {_httpimg_/pt-br/thowgr.gif}
+_httpiconthowon_ [l=pt-br] {_httpimg_/pt-br/thowon.gif}
+_httpiconthowof_ [l=pt-br] {_httpimg_/pt-br/thowof.gif}
+_widththowx_ [l=pt-br] {96}
+
+## "tÃ³pico" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=pt-br] {_httpimg_/pt-br/ttopicgr.gif}
+_httpiconttopicon_ [l=pt-br] {_httpimg_/pt-br/ttopicon.gif}
+_httpiconttopicof_ [l=pt-br] {_httpimg_/pt-br/ttopicof.gif}
+_widthttopicx_ [l=pt-br] {87}
+
+## "listar" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=pt-br] {_httpimg_/pt-br/tbrwsegr.gif}
+_httpicontbrwseon_ [l=pt-br] {_httpimg_/pt-br/tbrwseon.gif}
+_httpicontbrwseof_ [l=pt-br] {_httpimg_/pt-br/tbrwseof.gif}
+_widthtbrwsex_ [l=pt-br] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "pessoas" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=pt-br] {_httpimg_/pt-br/tpeopgr.gif}
+_httpicontpeopof_ [l=pt-br] {_httpimg_/pt-br/tpeopof.gif}
+_httpicontpeopon_ [l=pt-br] {_httpimg_/pt-br/tpeopon.gif}
+_widthtpeopx_ [l=pt-br] {87}
+
+# -- Missing translation: tacro
+# -- Missing translation: _httpicontacrogr_
+# -- Missing translation: _httpicontacroof_
+# -- Missing translation: _httpicontacroon_
+# -- Missing translation: _widthtacrox_
+
+# -- Missing translation: tphrse
+# -- Missing translation: _httpicontphrsegr_
+# -- Missing translation: _httpicontphrseof_
+# -- Missing translation: _httpicontphrseon_
+# -- Missing translation: _widthtphrsex_
+
+# -- Missing translation: tartst
+# -- Missing translation: _httpicontartstgr_
+# -- Missing translation: _httpicontartstof_
+# -- Missing translation: _httpicontartston_
+# -- Missing translation: _widthtartstx_
+
+# -- Missing translation: tkw
+# -- Missing translation: _httpicontkwgr_
+# -- Missing translation: _httpicontkwof_
+# -- Missing translation: _httpicontkwon_
+# -- Missing translation: _widthtkwx_
+
+# -- Missing translation: tvol
+# -- Missing translation: _httpicontvolgr_
+# -- Missing translation: _httpicontvolof_
+# -- Missing translation: _httpicontvolon_
+# -- Missing translation: _widthtvolx_
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "ajuda" ## green_title ## h_help ##
+_httpiconhhelp_ [l=pt-br] {_httpimg_/pt-br/h\_help.gif}
+_widthhhelp_ [l=pt-br] {200}
+_heighthhelp_ [l=pt-br] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=pt-br] {Sobre esta coleÃ§Ã£o}
+
+_textsubcols1_ [l=pt-br] {<p>A Completa coleÃ§Ã£o contÃ©m _1_ sub-coleÃ§Ãµes:
+<blockquote>}
+
+_textsubcols2_ [l=pt-br] {</blockquote>
+VocÃª pode checar (e alterar) a coleÃ§Ã£o que vocÃª estÃ¡ 
+atualmente usando na pÃ¡gina PreferÃªncias.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "sobre" ## green_title ## h_about ##
+_httpiconhabout_ [l=pt-br] {_httpimg_/pt-br/h\_about.gif}
+_widthhabout_ [l=pt-br] {200}
+_heighthabout_ [l=pt-br] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=pt-br] {TÃ­tulos A-Z}
+_texticonhcreat_ [l=pt-br] {Autores A-Z}
+_texticonhsubj_ [l=pt-br] {Assuntos}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=pt-br] {Datas}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+# -- Missing translation: _texticonhsrc_
+# -- Missing translation: _texticonhlang_
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+# -- Missing translation: _texticonhto_
+# -- Missing translation: _texticonhfrom_
+_texticonhser_ [l=pt-br] {SÃ©ries}
+_texticonhhow_ [l=pt-br] {Como fazer}
+_texticonhorg_ [l=pt-br] {OrganizaÃ§Ãµes}
+_texticonhbrwse_ [l=pt-br] {Listar}
+# -- Missing translation: _texticonhbrows_
+_texticonhpeople_ [l=pt-br] {Pessoas A-Z}
+# -- Missing translation: _texticonhacronym_
+# -- Missing translation: _texticonhphrases_
+# -- Missing translation: _texticonhartist_
+# -- Missing translation: _texticonhkw_
+# -- Missing translation: _texticonhvol_
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=pt-br] {feche esta seÃ§Ã£o da biblioteca}
+_texticonclosedbookshelf_ [l=pt-br] {abre esta seÃ§Ã£o da biblioteca e visualiza o conteÃºdo}
+_texticonopenbook_ [l=pt-br] {fecha este livro}
+_texticonclosedfolder_ [l=pt-br] {abre esta pasta e visualiza o conteÃºdo}
+_texticonclosedfolder2_ [l=pt-br] {abre sub-seÃ§Ã£o: }
+_texticonopenfolder_ [l=pt-br] {fecha esta pasta}
+_texticonopenfolder2_ [l=pt-br] {fecha sub-seÃ§Ã£o: }
+_texticonsmalltext_ [l=pt-br] {Visualiza esta seÃ§Ã£o de texto}
+_texticonsmalltext2_ [l=pt-br] {visualiza texto: }
+_texticonpointer_ [l=pt-br] {seÃ§Ã£o atual}
+_texticondetach_ [l=pt-br] {Abre esta pÃ¡gina numa nova janela}
+_texticonhighlight_ [l=pt-br] {Destaca termos buscados}
+_texticonnohighlight_ [l=pt-br] {NÃ£o destaca termos buscados}
+_texticoncontracttoc_ [l=pt-br] {Reduz tabela de conteÃºdo}
+_texticonexpandtoc_ [l=pt-br] {Amplia tabela de conteÃºdo}
+_texticonexpandtext_ [l=pt-br] {Exibir todo texto}
+_texticoncontracttext_ [l=pt-br] {Exibe texto somente das seÃ§Ãµes selecionadas}
+_texticonwarning_ [l=pt-br] {<b>Aviso: </b>}
+_texticoncont_ [l=pt-br] {continuar?}
+
+_textltwarning_ [l=pt-br] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Expanding o texto gerarÃ¡ uma grande 
+quantidade de dados para o seu browser exibir _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=pt-br] {ir para pÃ¡gina}
+_textintro_ [l=pt-br] {<i>(texto introdutÃ³rio)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tÃ­tulos a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=pt-br] {_httpimg_/pt-br/h\_title.gif}
+_widthhtitle_ [l=pt-br] {200}
+_heighthtitle_ [l=pt-br] {57}
+
+# Not true DC, kept for legacy reasons
+## "autores a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=pt-br] {_httpimg_/pt-br/h\_auth.gif}
+_widthhcreat_ [l=pt-br] {200}
+# -- Missing translation: _heighthcreat_
+
+## "assuntos" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=pt-br] {_httpimg_/pt-br/h\_subj.gif}
+_widthhsubj_ [l=pt-br] {200}
+_heighthsubj_ [l=pt-br] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "datas" ## green_title ## h_date ##
+_httpiconhdate_ [l=pt-br] {_httpimg_/pt-br/h\_date.gif}
+_widthhdate_ [l=pt-br] {200}
+_heighthdate_ [l=pt-br] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: h_src
+# -- Missing translation: _httpiconhsrc_
+# -- Missing translation: _widthhsrc_
+# -- Missing translation: _heighthsrc_
+
+# -- Missing translation: h_lang
+# -- Missing translation: _httpiconhlang_
+# -- Missing translation: _widthhlang_
+# -- Missing translation: _heighthlang_
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+# -- Missing translation: h_to
+# -- Missing translation: _httpiconhto_
+# -- Missing translation: _widthhto_
+# -- Missing translation: _heighthto_
+
+# -- Missing translation: h_from
+# -- Missing translation: _httpiconhfrom_
+# -- Missing translation: _widthhfrom_
+# -- Missing translation: _heighthfrom_
+
+## "sÃ©ries" ## green_title ## h_ser ##
+_httpiconhser_ [l=pt-br] {_httpimg_/pt-br/h\_ser.gif}
+_widthhser_ [l=pt-br] {200}
+_heighthser_ [l=pt-br] {57}
+
+## "como fazer" ## green_title ## h_how ##
+_httpiconhhow_ [l=pt-br] {_httpimg_/pt-br/h\_how.gif}
+_widthhhow_ [l=pt-br] {200}
+_heighthhow_ [l=pt-br] {57}
+
+## "tÃ³picos" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=pt-br] {_httpimg_/pt-br/h\_topic.gif}
+_widthhtopic_ [l=pt-br] {200}
+_heighthtopic_ [l=pt-br] {57}
+
+## "organizaÃ§Ã£o" ## green_title ## h_org ##
+_httpiconhorg_ [l=pt-br] {_httpimg_/pt-br/h\_org.gif}
+_widthhorg_ [l=pt-br] {250}
+_heighthorg_ [l=pt-br] {57}
+
+## "listar" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=pt-br] {_httpimg_/pt-br/h\_brwse.gif}
+_widthhbrwse_ [l=pt-br] {200}
+_heighthbrwse_ [l=pt-br] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "pessoas" ## green_title ## h_people ##
+_httpiconhpeople_ [l=pt-br] {_httpimg_/pt-br/h\_people.gif}
+_widthhpeople_ [l=pt-br] {200}
+_heighthpeople_ [l=pt-br] {57}
+
+# -- Missing translation: h_acro
+# -- Missing translation: _httpiconhacronym_
+# -- Missing translation: _widthhacronym_
+# -- Missing translation: _heighthacronym_
+
+# -- Missing translation: h_phrse
+# -- Missing translation: _httpiconhphrse_
+# -- Missing translation: _widthhphrse_
+# -- Missing translation: _heighthphrse_
+
+# -- Missing translation: h_artist
+# -- Missing translation: _httpiconhartist_
+# -- Missing translation: _widthhartist_
+# -- Missing translation: _heighthartist_
+
+# -- Missing translation: h_kw
+# -- Missing translation: _httpiconhkw_
+# -- Missing translation: _widthhkw_
+# -- Missing translation: _heighthkw_
+
+# -- Missing translation: h_vol
+# -- Missing translation: _httpiconhvol_
+# -- Missing translation: _widthhvol_
+# -- Missing translation: _heighthvol_
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+## "CONTINUAR?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=pt-br] {_httpimg_/pt-br/contof.gif}
+_httpiconconton_ [l=pt-br] {_httpimg_/pt-br/conton.gif}
+
+## "AMPLIAR\nTEXTO" ## document_button ## eallt ##
+_httpiconealltof_ [l=pt-br] {_httpimg_/pt-br/ealltof.gif}
+_httpiconeallton_ [l=pt-br] {_httpimg_/pt-br/eallton.gif}
+
+## "ABREVIAR\nCONTEÃºDO" ## document_button ## econc ##
+_httpiconeconcof_ [l=pt-br] {_httpimg_/pt-br/econcof.gif}
+_httpiconeconcon_ [l=pt-br] {_httpimg_/pt-br/econcon.gif}
+
+## "RESUMIR" ## document_button ## edtch ##
+_httpiconedtchof_ [l=pt-br] {_httpimg_/pt-br/edtchof.gif}
+_httpiconedtchon_ [l=pt-br] {_httpimg_/pt-br/edtchon.gif}
+
+## "AMPLIAR\nCONTEÃºDO" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=pt-br] {_httpimg_/pt-br/eexpcof.gif}
+_httpiconeexpcon_ [l=pt-br] {_httpimg_/pt-br/eexpcon.gif}
+
+## "ABREVIAR\nTEXTO" ## document_button ## etsec ##
+_httpiconetsecof_ [l=pt-br] {_httpimg_/pt-br/etsecof.gif}
+_httpiconetsecon_ [l=pt-br] {_httpimg_/pt-br/etsecon.gif}
+
+## "DESTACAR" ## document_button ## ehl ##
+_httpiconehlof_ [l=pt-br] {_httpimg_/pt-br/ehlof.gif}
+_httpiconehlon_ [l=pt-br] {_httpimg_/pt-br/ehlon.gif}
+
+## "NÃ£O\nDESTACAR" ## document_button ## enhl ##
+_httpiconenhlof_ [l=pt-br] {_httpimg_/pt-br/enhlof.gif}
+_httpiconenhlon_ [l=pt-br] {_httpimg_/pt-br/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=pt-br] {_If_(_thislast_,resultados _thisfirst_ - _thislast_ para a consulta: _cgiargq_,Nunhuma resposta encontrada: _cgiargq_)}
+_textnoquerytitle_ [l=pt-br] {PÃ¡gina busca}
+
+_texticonthispage_ [l=pt-br] {busca}
+_textsome_ [l=pt-br] {algumas}
+# -- Missing translation: _textall_
+# -- Missing translation: _textboolean_
+# -- Missing translation: _textranked_
+# -- Missing translation: _textnatural_
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=pt-br] {}
+# -- Missing translation: _texticonsearchhistorybar_
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+# -- Missing translation: _textusequery_
+_textfreqmsg1_ [l=pt-br] {Palavras contadas: }
+_textpostprocess_ [l=pt-br] {_If_(_quotedquery_,<br><i>encontrar pÃ³s-processadas _quotedquery_</i>
+)}
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=pt-br] {Mais que }
+_textapprox_ [l=pt-br] {Sobre }
+_textnodocs_ [l=pt-br] {Nenhum documento encontrado.}
+_text1doc_ [l=pt-br] {1 documento encontrado.}
+_textlotsdocs_ [l=pt-br] {documentos encontrados.}
+_textmatches_ [l=pt-br] {Consulta }
+_textbeginsearch_ [l=pt-br] {ComeÃ§ar a busca}
+# -- Missing translation: _textrunquery_
+# -- Missing translation: _textclearform_
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+# -- Missing translation: _textwordphrase_
+# -- Missing translation: _textinfield_
+# -- Missing translation: _textfoldstem_
+
+# -- Missing translation: _textadvquery_
+# -- Missing translation: _textallfields_
+# -- Missing translation: _texttextonly_
+# -- Missing translation: _textand_
+# -- Missing translation: _textor_
+# -- Missing translation: _textandnot_
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=pt-br] {Buscar por _indexselection_ _If_(_jselection_, de _jselection_)_If_(_gselection_, na _gselection_ nÃ­vel)_If_(_nselection_, na _nselection_ linguagem) que contenha _querytypeselection_ palavras}
+
+_textadvancedsearch_ [l=pt-br] {Search _indexselection_ _If_(_jselection_, de _jselection_)_If_(_gselection_, na _gselection_ nÃ­vel)_If_(_nselection_, na _nselection_ linguagem) usando _querytypeselection_ consulta}
+
+# -- Missing translation: _textformsimplesearch_
+
+# -- Missing translation: _textformadvancedsearch_
+
+
+# -- Missing translation: _textnojsformwarning_
+# -- Missing translation: _textdatesearch_
+# -- Missing translation: _textstartdate_
+# -- Missing translation: _textenddate_
+# -- Missing translation: _textbc_
+# -- Missing translation: _textad_
+# -- Missing translation: _textexplaineras_
+
+_textstemon_ [l=pt-br] {(ignorar final das palavras)}
+
+_textsearchhistory_ [l=pt-br] {Buscar HistÃ³ria}
+
+#text macros for search history
+_textnohistory_ [l=pt-br] {Buscar histÃ³ria nÃ£o disponÃ­vel}
+# -- Missing translation: _texthresult_
+# -- Missing translation: _texthresults_
+# -- Missing translation: _texthallwords_
+# -- Missing translation: _texthsomewords_
+# -- Missing translation: _texthboolean_
+# -- Missing translation: _texthranked_
+# -- Missing translation: _texthcaseon_
+# -- Missing translation: _texthcaseoff_
+# -- Missing translation: _texthstemon_
+# -- Missing translation: _texthstemoff_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "busca" ## green_title ## h_search ##
+_httpiconhsearch_ [l=pt-br] {_httpimg_/pt-br/h\_search.gif}
+_widthhsearch_ [l=pt-br] {200}
+_heighthsearch_ [l=pt-br] {57}
+
+## "resultados" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=pt-br] {_httpimg_/pt-br/qryresb.gif}
+_widthqryresb_ [l=pt-br] {_pagewidth_}
+_heightqryresb_ [l=pt-br] {17}
+
+# -- Missing translation: schhistb
+# -- Missing translation: _httpiconsrchhistb_
+# -- Missing translation: _widthsrchhistb_
+# -- Missing translation: _heightsrchhistb_
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textprefschanged_
+# -- Missing translation: _textsetprefs_
+_textsearchprefs_ [l=pt-br] {PreferÃªncias de busca}
+_textcollectionprefs_ [l=pt-br] {PreferÃªncias da coleÃ§Ã£o}
+_textpresentationprefs_ [l=pt-br] {PreferÃªncias da apresentaÃ§Ã£o}
+_textpreferences_ [l=pt-br] {PreferÃªncias}
+# -- Missing translation: _textcasediffs_
+_textignorecase_ [l=pt-br] {ignorar diferenÃ§as entre maiÃºsculas/minÃºsculas}
+_textmatchcase_ [l=pt-br] {maiÃºsculas/minÃºsculas devem corresponder}
+# -- Missing translation: _textwordends_
+_textstem_ [l=pt-br] {ignorar terminaÃ§Ãµes das palavras}
+_textnostem_ [l=pt-br] {palavra inteira deve corresponder}
+_textprefop_ [l=pt-br] {Retornar _maxdocoption_ resultados com _hitsperpageoption_ por pÃ¡gina.}
+_textextlink_ [l=pt-br] {Acesso Ã  Web Pages externas: }
+_textintlink_ [l=pt-br] {Origem dos documentos recebidos:}
+_textlanguage_ [l=pt-br] {Linguage da Interface: }
+_textencoding_ [l=pt-br] {CÃ³digo: }
+_textformat_ [l=pt-br] {Formato da Interface: }
+_textall_ [l=pt-br] {todos}
+# -- Missing translation: _textquerymode_
+_textsimplemode_ [l=pt-br] {modo de consultas simples}
+_textadvancedmode_ [l=pt-br] {mode de consultas avanÃ§adas (permite busca binÃ¡rias usando !, &, |, e parÃªntesis)}
+_textlinkinterm_ [l=pt-br] {direto para a pÃ¡gina intermediÃ¡ria}
+_textlinkdirect_ [l=pt-br] {ir diretamente para lÃ¡}
+_textdigitlib_ [l=pt-br] {a biblioteca digital}
+_textweb_ [l=pt-br] {a web}
+_textgraphical_ [l=pt-br] {GrÃ¡fico}
+_texttextual_ [l=pt-br] {Texto}
+_textcollectionoption_ [l=pt-br] {<p>
+SubcoleÃ§Ãµes Ã  incluir:
+<br>}
+
+# -- Missing translation: _textrelateddocdisplay_
+# -- Missing translation: _textsearchhistory_
+# -- Missing translation: _textnohistory_
+# -- Missing translation: _texthistorydisplay_
+# -- Missing translation: _textnohistorydisplay_
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+# -- Missing translation: _textformsearch_
+# -- Missing translation: _textplainsearch_
+# -- Missing translation: _textqueryboxsize_
+# -- Missing translation: _textregbox_
+# -- Missing translation: _textbigbox_
+# -- Missing translation: _textformtype_
+# -- Missing translation: _textsimple_
+# -- Missing translation: _textadvanced_
+
+# used in "with 4 fields" in the form search box
+# -- Missing translation: _textwith_
+# -- Missing translation: _textfields_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferÃªncias" ## green_title ## h_pref ##
+_httpiconhpref_ [l=pt-br] {_httpimg_/pt-br/h\_pref.gif}
+_widthhpref_ [l=pt-br] {200}
+_heighthpref_ [l=pt-br] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+# -- Missing translation: _textsortby_
+# -- Missing translation: _textalsoshowing_
+# -- Missing translation: _textwith_
+# -- Missing translation: _textdocsperpage_
+
+# -- Missing translation: _textfilterby_
+# -- Missing translation: _textall_
+# -- Missing translation: _textany_
+# -- Missing translation: _textwords_
+# -- Missing translation: _textleaveblank_
+
+# -- Missing translation: _browsebuttontext_
+
+# -- Missing translation: _nodata_
+# -- Missing translation: _docs_
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=pt-br] {Ajuda}
+_textSearchshort_ [l=pt-br] {busca por palavra especÃ­fica}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=pt-br] {acessar publicaÃ§Ãµes por tÃ­tulo}
+_textCreatorshort_ [l=pt-br] {acessar publicaÃ§Ãµes por autores}
+_textSubjectshort_ [l=pt-br] {acessar publicaÃ§Ãµes por assunto}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=pt-br] {acessar publicaÃ§Ãµes por data}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+# -- Missing translation: _textSourceshort_
+# -- Missing translation: _textLanguageshort_
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=pt-br] {acessar publicaÃ§Ãµes por sÃ©ries}
+# -- Missing translation: _textToshort_
+# -- Missing translation: _textFromshort_
+_textBrowseshort_ [l=pt-br] {listar publicaÃ§Ãµes}
+_textOrganizationshort_ [l=pt-br] {acessar publicaÃ§Ãµes por organizaÃ§Ã£o}
+_textHowtoshort_ [l=pt-br] {acessar publicaÃ§Ãµes por como fazer}
+_textTopicshort_ [l=pt-br] {acessar publicaÃ§Ãµes por tÃ³pico}
+_textPeopleshort_ [l=pt-br] {acessar publicaÃ§Ãµes por pessoas}
+# -- Missing translation: _textAcronymshort_
+# -- Missing translation: _textPhraseshort_
+# -- Missing translation: _textArtistshort_
+# -- Missing translation: _textKeywordshort_
+# -- Missing translation: _textVolumeshort_
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=pt-br] {classificaÃ§Ã£o indefinida}
+
+_textSearchlong_ [l=pt-br] {<p>VocÃª pode <i>buscar por palavras especÃ­ficas</i> que
+aparecem no texto da pÃ¡gina "busca". Esta Ã© a primeira pÃ¡gina que
+aparece quando vocÃª comeÃ§a, e podem ser encontradas nas outras pÃ¡ginas pressionando-se
+o botÃ£o <i>busca</i>.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=pt-br] {<p>VocÃª pode <i>acessar publicaÃ§Ãµes por tÃ­tulo</i> clicando
+no botÃ£o <i>tÃ­tulos a-z</i>.  O qual trarÃ¡ uma lista de livros em
+ordem alfabÃ©tica.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=pt-br] {<p>VocÃª pode <i>acessar publicaÃ§Ãµes por autor</i> 
+clicando no botÃ£o <i>autores a-z</i>.  O qual trarÃ¡ uma lista de livros,
+ordenada por nome de autores.  }
+
+_textSubjectlong_ [l=pt-br] {<p>VocÃª pode <i>acessar publicaÃ§Ãµes por assuntos</i> 
+clicando no botÃ£o <i>assuntos</i>.  O qual trarÃ¡ uma lista de assuntos,
+representandos por livros.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=pt-br] {<p>VocÃª pode <i>acessar publicaÃ§Ãµes por data</i> clicando
+no botÃ£o <i>datas</i>.  O qual trarÃ¡ uma lista de todos as ediÃ§Ãµes, ordenadas
+cronologicamente.  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+# -- Missing translation: _textSourcelong_
+
+# -- Missing translation: _textLanguagelong_
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=pt-br] {<p>VocÃª pode <i>acessar publicaÃ§Ãµes por
+organizaÃ§Ã£o</i> pressionando o botÃ£o <i>organizaÃ§Ã£o</i>.  O qual trarÃ¡
+uma lista por organizaÃ§Ãµes.  }
+
+_textHowtolong_ [l=pt-br] {<p>VocÃª pode <i>acessar publicaÃ§Ãµes por como fazer</i>
+pressionando o botÃ£o <i>como fazer</i>.  O qual trarÃ¡ uma lista de como fazer.  }
+
+_textTopiclong_ [l=pt-br] {<p>VocÃª pode <i>acessar publicaÃ§Ãµes por tÃ³pico</i> 
+clicando no botÃ£o <i>tÃ³pico</i>.  O qual trarÃ¡ uma lista de tÃ³picos
+para o Browser.  }
+
+# -- Missing translation: _textTolong_
+
+# -- Missing translation: _textFromlong_
+
+_textSerieslong_ [l=pt-br] {<p>VocÃª pode <i>acessar publicaÃ§Ãµes por sÃ©ries</i> 
+clicando no botÃ£o <i>sÃ©ries</i>.  O qual trarÃ¡ uma lista das sÃ©ries
+que estÃ£o atualmente na coleÃ§Ã£o.  }
+
+_textBrowselong_ [l=pt-br] {<p>VocÃª pode <i>folhear publicaÃ§Ãµes</i> clicando no
+botÃ£o <i>folhear</i>.  }
+
+_textPeoplelong_ [l=pt-br] {<p>VocÃª pode <i>acessar publicaÃ§Ãµes por pessoas</i> 
+clicando no botÃ£o <i>pessoas a-z</i>.  O qual trarÃ¡ uma lista ordenadas por nome.  }
+
+# -- Missing translation: _textAcronymlong_
+
+# -- Missing translation: _textPhraselong_
+
+# -- Missing translation: _textArtistlong_
+
+# -- Missing translation: _textKeywordlong_
+
+# -- Missing translation: _textVolumelong_
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=pt-br] {<p>Click no botÃ£o <i>nÃ£o encontrado</i> para listar
+publicaÃ§Ãµes (listando por ordem de um campo nÃ£o encontrado).  }
+
+_texthelptopics_ [l=pt-br] {<h2 align=left>TÃ³picos</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Como buscar por uma palavra especÃ­fica</a>
+<ul>
+  <li><a href="\#query-terms">Busca de termos</a>
+  <li><a href="\#query-type">Tipo de busca</a>
+  <li><a href="\#scope-of-queries">AbrangÃªncia da busca</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">PreferÃªncias da coleÃ§Ã£o</a>
+  <li><a href="\#pres-prefs">PreferÃªncias de apresentaÃ§Ã£o</a>
+  <li><a href="\#search-prefs">PreferÃªncias de busca</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=pt-br] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=pt-br] {Como ler documentos}
+
+_texthelpreadingdocs_ [l=pt-br] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>VocÃª pode saber quando vocÃª chegou em um documento especifico por que
+o tÃ­tulo e autor aparecem no topo esquerdo da pÃ¡gina. TambÃ©m haverÃ¡ o 
+nÃºmero da pÃ¡gina corrente, um box com setas de avanÃ§o e retrocesso dirÃ¡ a vocÃª para selecionar uma nova pÃ¡gina.
+
+<p>Sobre o texto da seÃ§Ã£o atual. Quando vocÃª tiver lido ele,
+haverÃ£o setas e botÃµes que trarÃ£o para vocÃª a prÃ³xima
+seÃ§Ã£o ou a seÃ§Ã£o anterior.
+
+<p>Abaixo do tÃ­tulo e autor hÃ¡ trÃªs botÃµes. Clique no <i>ampliar
+texto</i> para ampliar todo o texto do documento atual. Se o 
+documento for grande, isto poderÃ¡ levar muito tempo e usar muita memÃ³ria!
+Clique em <i>resumir</i> para fazer uma nova janela de busca para o
+documento. (Isto Ã© util se vocÃª quiser comparar documentos, ou ler dois ao
+mesmo tempo.)  Finalmente, quando vocÃª fizer uma busca por palavras as mesmas serÃ£o
+destacadas.  Clique em <i>nÃ£o destacar</i> para retirar os destaques.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Clique na seta para ir para a prÃ³xima seÃ§Ã£o ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... ou voltar para a seÃ§Ã£o anterior</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Exibir todo texto, ou nÃ£o</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Abrir esta pÃ¡gina em uma nova janela</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Destacar termos buscados, ou nÃ£o</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=pt-br] {<h2>Como buscar por palavras particulares </h2>
+<p>
+  Na pÃ¡gina de busca, vocÃª deverÃ¡ fazer uma consulta com estes simples passos:<p>
+  
+  <ol><li>Especifique quais documentos vocÃª quer buscar 
+      <li>Diga se vocÃª quer buscar por todas ou somente algumas palavras 
+      <li>Digite as palavras que vocÃª quer buscar 
+      <li>Clique no botÃ£o <i>ComeÃ§ar busca</i>
+  </ol>
+
+<p>Quando vocÃª fizer uma consulta, os tÃ­tulos de vinte documentos serÃ£o apresentados.
+HaverÃ¡ um botÃ£o no final da pÃ¡gina que apresentarÃ¡ os prÃ³ximos vinte documentos.  LÃ¡ vocÃª encontrarÃ¡ botÃµes para levÃ¡-lo para as terceiras vinte ou voltar para as primeiras vinte e assim continuarÃ¡. Clique no tÃ­tulo de qualquer documento, ou no pequeno botÃ£o ao lado dele para vÃª-lo.
+
+<p>Um mÃ¡ximo de 100 documentos sÃ£o retornados. VocÃª pode mudar este nÃºmero clicando no botÃ£o <i>preferÃªncias</i> no topo da pÃ¡gina.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Termos de busca </h3>
+
+<p>Qualquer coisa que vocÃª digitar na caixa de consulta Ã© interpretado como uma lista de palavras chamadas "termos de busca." Cada termo nÃ£o contÃ©m nada alÃ©m de caracteres e dÃ­gitos. Termos sÃ£o separados por espaÃ§os em branco. Se qualquer outro caracter como pontuaÃ§Ã£o aparecer, eles servirÃ£o apenas para separar termos mas continuarÃ£o sendo espaÃ§os. E entÃ£o eles serÃ£o ignorados. VocÃª nÃ£o pode buscar por palavras que incluem pontuaÃ§Ã£o. 
+
+<p>Por exemplo, a consulta <p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>SerÃ£o tratadas como<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Tipos de consultas</h3>
+
+<p>Existem dois tipos diferentes de consulta.
+
+<ul>
+  <li>Consultas por <b>todas</b> as palavras.  Esta opÃ§Ã£o busca por documentos 
+      que contenham todas as palavras que vocÃª especificou. Documentos que
+	satisfassam a consulta serÃ£o apresentados em ordem alfabÃ©tica .<p>
+
+  <li>Consultas por <b>algumas</b> das palavras.  Apenas listarÃ¡ alguns termos 
+      que provavelmente aparecem nos documentos que vocÃª esta buscando. 	Documentos sÃ£o apresentados na ordem mais prÃ³xima da consulta. Quando
+      determinado o grau de consulta,
+
+      <p><ul>
+        <li> quanto mais termos um documento contenha, mais combinarÃ¡;
+        <li> termos raros sÃ£o mais importantes que comuns;
+        <li> documentos menores combinam melhor que grandes.
+      </ul>
+</ul>
+
+<p>Use quantos termos vocÃª quiser-uma sentenÃ§a completa, ou um parÃ¡grafo completo. Se vocÃª especificar somente um termo, os documentos serÃ£o ordenados por frequÃªncia de ocorrÃªncia.<p>
+_texthelpscope_
+}
+
+# -- Missing translation: _textdatesearch_
+
+# -- Missing translation: _texthelpdatesearch_
+
+_textchangeprefs_ [l=pt-br] {Mudar suas preferÃªncias }
+
+_texthelppreferences_ [l=pt-br] {<h2>_textchangeprefs_</h2>
+
+<p>Quando vocÃª clica no botÃ£o de <i>preferÃªncias</i> no topo da pÃ¡gina, vocÃª serÃ¡ capaz de mudar alguns aspectos da interface para moldar em seus prÃ³prios requerimentos.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>PreferÃªncias da coleÃ§Ã£o</h3>
+
+Algumas coleÃ§Ãµes incluem vÃ¡rias sub-coleÃ§Ãµes, as quais podem ser buscadas independentemente ou juntas, como uma unidade. Assim, vocÃª pode selecionar quais sub-coleÃ§Ãµes incluir em suas buscas na pÃ¡gina de preferÃªncias. 
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>PreferÃªncias de apresentaÃ§Ã£o</h3>
+
+Dependendo de uma particular coleÃ§Ã£o, haverÃ¡ vÃ¡rias opÃ§Ãµes que vocÃª pode definir para controlar a apresentaÃ§Ã£o. 
+
+ColeÃ§Ãµes de Web pages permitirÃ£o a vocÃª suprimir a barra de navegaÃ§Ã£o Greenstone no topo de cada pÃ¡gina de documento, quando vocÃª fizer uma busca a pÃ¡gina com os documentos encontrados aparecerÃ£o sem nenhum cabeÃ§ario Greenstone. Para fazer outra busca vocÃª terÃ¡ que usar o botÃ£o "back" do seu browser. Estas coleÃ§Ãµes tambÃ©m possibilitarÃ£o a vocÃª suprimir as mensagens de avisos Greenstone quando vocÃª clicar em um link que levarÃ¡ vocÃª para fora da coleÃ§Ã£o digital.
+Em algumas coleÃ§Ãµes vocÃª pode controlar quaisquer links na pÃ¡gina de "Resultados de Busca" para levÃ¡-lo diretamente para a atual URL em questÃ£o, ao invÃ©s de copiar as pÃ¡ginas da biblioteca digital.
+
+ColeÃ§Ãµes que sÃ£o capazes de serem apresentadas em diferentes linguagens permitirÃ£o que vocÃª especifique a linguagem da interface. Se a linguagem Ã© chinÃªs, vocÃª tambÃ©m pode especificar quais cÃ³digos de padrÃµes chineses seu browser deve usar.
+
+Finalmente, todas as coleÃ§Ãµes dÃ£o a vocÃª a condiÃ§Ã£o de mudar para uma interface textual ao invÃ©s do padrÃ£o grÃ¡fico. Isto Ã© particularmente Ãºtil para visualizaÃ§Ã£o por usuÃ¡rios que usam fontes de tela largas ou escutam por sintetizadores. 
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>PreferÃªncias de busca </h3>
+Dois pares de botÃµes controlam a sensibilidade entre maiÃºsculas e minÃºsculas e terminaÃ§Ãµes das buscas que vocÃª fizer. O primeiro grupo de botÃµes controlam qualquer maiÃºsculas ou minÃºsculas que devem combinar (sensibilidade).  O segundo grupo ignorar qualquer final de palavras ou nÃ£o (terminaÃ§Ãµes).
+
+<p>Por exemplo, se os botÃµes <i>ignorar diferencas entre maÃ­usculas/minúsculas</i> e
+<i>ignorar terminaÃ§Ãµes de palavras </i> estiverem selecionados, a consulta <p>
+    <ul><kbd>African building</kbd></ul>
+      <p>serÃ¡ tratada como <p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      porque as letras maiÃºsculas em "African" serÃ£o transformadas para 
+      minÃºsculas, e os sufixos "n" e "ing" serÃ£o removidos de 
+      "African" e "building" respectivamente (tambÃ©m, "s" serÃ£o removidos de 
+      "builds").
+
+<p>VocÃª pode tambÃ©m mudar para o modo "avanÃ§ado" de consulta que possibilitarÃ¡ a vocÃª combinar termos usando AND (&), OR (|), e NOT (!). Isto darÃ¡ a vocÃª consultas mais precisas. 
+
+<p>Finalmente, vocÃª pode controlar o nÃºmero de pÃ¡ginas encontradas, e o nÃºmero de pÃ¡ginas que serÃ£o apresentadas em cada tela.
+
+}
+
+_texttanumbrowseoptions_ [l=pt-br] {Existem _numbrowseoptions_ formas de encontrar informaÃ§Ãµes nesta coleÃ§Ã£o:}
+
+_textsimplehelpheading_ [l=pt-br] {Como encontrar informaÃ§Ãµes}
+
+_texthelpscope_ [l=pt-br] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>AbrangÃªncia das consultas</h3>
+
+<p>
+Na maioria das coleÃ§Ãµes vocÃª pode escolher diferentes indices de busca. Por exemplo, poderiam ser indeces por autores ou por tÃ­tulos. Ou poderiam ser por capÃ­tulos ou parÃ¡grafos. Genericamente uma completa lista de documentos Ã© retornada apesar dos indeces de busca.
+<p>Se os documentos sÃ£o livros, eles serÃ£o abertos no local apropriado.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/port-pt.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/port-pt.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/port-pt.dm	(revision 10506)
@@ -0,0 +1,1293 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Portuguese (Portugal) Language text and icon macros 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=pt-pt] {PeriÃ³dicos}
+_textsource_ [l=pt-pt] {ref. da fonte:}
+_textdate_ [l=pt-pt] {data de publicaÃ§Ã£o:}
+_textnumpages_ [l=pt-pt] {no. de pÃ¡ginas:}
+
+_textsignin_ [l=pt-pt] {registar}
+
+_textdefaultcontent_ [l=pt-pt] {A pÃ¡gina requerida nÃ£o pode ser encontrada. Por favor,
+use o botÃ£o 'back' do seu browser ou o botÃ£o "home" para retornar para a Biblioteca Digital Greenstone.}
+
+_textdefaulttitle_ [l=pt-pt] {GSDL Erro}
+
+# -- Missing translation: _textbadcollection_
+
+_textselectpage_ [l=pt-pt] {-- Seleccionar PÃ¡gina --}
+
+_collectionextra_ [l=pt-pt] {Esta coleÃ§Ã£o contÃ©m _about:numdocs_ documentos. 
+Foi construÃ­da hÃ¡ _about:builddate_ dias.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=pt-pt] {<p>Esta colecÃ§Ã£o contÃ©m _numdocs_ _If_("_numdocs_" eq "1",documento,documentos), num total de _numbytes_.
+<p><a href="_httppagex_(bsummary)">Selecione aqui</a> para ver uma descriÃ§Ã£o desta colecÃ§Ã£o.}
+
+_textimagecollection_ [l=pt-pt] {}
+_textimageabout_ [l=pt-pt] {PÃ¡gina Sobre}
+_textimagehome_ [l=pt-pt] {PÃ¡gina Ãnicial}
+_textimagehelp_ [l=pt-pt] {PÃ¡gina de Ajuda}
+_textimagepref_ [l=pt-pt] {PÃ¡gina de PreferÃªncias}
+_textimagegreenstone_ [l=pt-pt] {Software da Biblioteca Digital Greenstone}
+_textimageusab_ [l=pt-pt] {O que acha difÃ­cil de usar?}
+
+_textimagesearch_ [l=pt-pt] {Busca por termos especÃ­ficos}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=pt-pt] {Ãndice alfabÃ©tico de tÃ­tulos}
+_textimageCreator_ [l=pt-pt] {Ãndice alfabÃ©tico de autores}
+_textimageSubject_ [l=pt-pt] {Ãndice de categorias de assunto}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=pt-pt] {Ãndice de datas}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=pt-pt] {Ãndice de nomes de ficheiros originais}
+_textimageLanguage_ [l=pt-pt] {Ãndice de lÃ­nguas}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=pt-pt] {Ãndice de organizaÃ§Ãµes}
+_textimageKeyword_ [l=pt-pt] {Ãndice de palavras-chave}
+_textimageHowto_ [l=pt-pt] {Ãndice de categorias como}
+_textimageList_ [l=pt-pt] {Ãndice da lista de documentos}
+_textimageSeries_ [l=pt-pt] {Ãndice de ediÃ§Ãµes}
+_textimageTo_ [l=pt-pt] {Ãndice do campo Para}
+_textimageFrom_ [l=pt-pt] {Indice do campo De}
+_textimageTopic_ [l=pt-pt] {Ãndice de ediÃ§Ãµes de tÃ³picos especiais}
+_textimageBrowse_ [l=pt-pt] {Listar}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=pt-pt] {Ãndice alfabÃ©tico de pessoas}
+_textimageAcronym_ [l=pt-pt] {Ãndice dos acrÃ³nimos}
+_textimagePhrase_ [l=pt-pt] {Ãndice de frases}
+_textimageArtist_ [l=pt-pt] {Ãndice dos artistas}
+_textimageVolume_ [l=pt-pt] {Ãndice de volumes}
+# -- Missing translation: _textimageCountries_
+_textimageCaptions_ [l=pt-pt] {Ãndice das legendas das fotos}
+
+
+_texticontabsearchgreen_ [l=pt-pt] {Pesquisa}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=pt-pt] {TÃ­tulos A-Z}
+_texticontabCreatorgreen_ [l=pt-pt] {Autors A-Z}
+_texticontabSubjectgreen_ [l=pt-pt] {Assuntos}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=pt-pt] {Datas}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=pt-pt] {Ficheiros}
+_texticontabLanguagegreen_ [l=pt-pt] {LÃ­ngua}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=pt-pt] {OrganizaÃ§Ã£o}
+_texticontabKeywordgreen_ [l=pt-pt] {Palavras-chave}
+_texticontabhowgreen_ [l=pt-pt] {Como}
+_texticontabseriesgreen_ [l=pt-pt] {SÃ©ries}
+_texticontablistgreen_ [l=pt-pt] {Listagem}
+_texticontabtogreen_ [l=pt-pt] {Para}
+_texticontabfromgreen_ [l=pt-pt] {De}
+_texticontabtopicgreen_ [l=pt-pt] {TÃ³picos}
+_texticontabbrwsegreen_ [l=pt-pt] {Listar}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=pt-pt] {Navegar}
+_texticontabPeoplegreen_ [l=pt-pt] {Pessoas A-Z}
+_texticontabAcronymgreen_ [l=pt-pt] {AcrÃ³nimos}
+_texticontabPhrasegreen_ [l=pt-pt] {Frases}
+_texticontabArtistgreen_ [l=pt-pt] {Artistas}
+_texticontabVolumegreen_ [l=pt-pt] {Volumes}
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=pt-pt] {Ver o documento}
+_texticonclosedbook_ [l=pt-pt] {Abrir este documento e visualizar o conteÃºdo}
+_texticonnext_ [l=pt-pt] {seÃ§Ã£o seguinte}
+_texticonprev_ [l=pt-pt] {seÃ§Ã£o anterior}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=pt-pt] {Ver o documento MIDI}
+_texticonmsword_ [l=pt-pt] {Ver o documento Microsoft Word}
+_texticonmp3_ [l=pt-pt] {Ver o documento MP3}
+_texticonpdf_ [l=pt-pt] {Ver o documento PDF}
+_texticonps_ [l=pt-pt] {Ver o documento PostScript}
+_texticonppt_ [l=pt-pt] {Ver o documento PowerPoint}
+_texticonrtf_ [l=pt-pt] {Ver o documento RTF}
+_texticonxls_ [l=pt-pt] {Ver o documento Microsoft Excell}
+
+_page_ [l=pt-pt] {pÃ¡gina }
+_pages_ [l=pt-pt] {pÃ¡ginas}
+_of_ [l=pt-pt] {de }
+_vol_ [l=pt-pt] {Vol.}
+_num_ [l=pt-pt] {No.}
+
+_textmonth00_ [l=pt-pt] {}
+_textmonth01_ [l=pt-pt] {Janeiro}
+_textmonth02_ [l=pt-pt] {Fevereiro}
+_textmonth03_ [l=pt-pt] {MarÃ§o}
+_textmonth04_ [l=pt-pt] {Abril}
+_textmonth05_ [l=pt-pt] {Maio}
+_textmonth06_ [l=pt-pt] {Junho}
+_textmonth07_ [l=pt-pt] {Julho}
+_textmonth08_ [l=pt-pt] {Agosto}
+_textmonth09_ [l=pt-pt] {Setembro}
+_textmonth10_ [l=pt-pt] {Outubro}
+_textmonth11_ [l=pt-pt] {Novembro}
+_textmonth12_ [l=pt-pt] {Dezembro}
+
+_textdocument_ [l=pt-pt] {Documento}
+_textsection_ [l=pt-pt] {SecÃ§Ã£o}
+_textparagraph_ [l=pt-pt] {ParÃ¡grafo}
+
+_magazines_ [l=pt-pt] {Revistas}
+
+_nzdlpagefooter_ [l=pt-pt] {<p>_iconblankbar_
+<p><a href="_gwcgi_">Projeto Biblioteca Digital da Nova ZelÃ¢ndia</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Departamento de CiÃªncia da ComputaÃ§Ã£o</a>, 
+<a href="http://www.waikato.ac.nz">Universidade de Waikato</a>, 
+Nova ZelÃ¢ndia}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÃNICIO" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=pt-pt] {_httpimg_/pt-pt/chomeof.gif}
+_httpiconchomeon_ [l=pt-pt] {_httpimg_/pt-pt/chomeon.gif}
+
+## "AJUDA" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=pt-pt] {_httpimg_/pt-pt/chelpof.gif}
+_httpiconchelpon_ [l=pt-pt] {_httpimg_/pt-pt/chelpon.gif}
+
+## "PREFERÃNCIAS" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=pt-pt] {_httpimg_/pt-pt/cprefof.gif}
+_httpiconcprefon_ [l=pt-pt] {_httpimg_/pt-pt/cprefon.gif}
+
+## "ENVIAR NOTA" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=pt-pt] {_httpimg_/pt-pt/cusabof.gif}
+_httpiconcusabon_ [l=pt-pt] {_httpimg_/pt-pt/cusabon.gif}
+
+
+## "buscar" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=pt-pt] {_httpimg_/pt-pt/tsrchgr.gif}
+_httpicontsrchof_ [l=pt-pt] {_httpimg_/pt-pt/tsrchof.gif}
+_httpicontsrchon_ [l=pt-pt] {_httpimg_/pt-pt/tsrchon.gif}
+_widthtsrchx_ [l=pt-pt] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tÃ­tulos a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=pt-pt] {_httpimg_/pt-pt/ttitlgr.gif}
+_httpiconttitleof_ [l=pt-pt] {_httpimg_/pt-pt/ttitlof.gif}
+_httpiconttitleon_ [l=pt-pt] {_httpimg_/pt-pt/ttitlon.gif}
+_widthttitlex_ [l=pt-pt] {87}
+
+# Not true DC, kept for legacy reasons
+## "autores a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=pt-pt] {_httpimg_/pt-pt/tauthgr.gif}
+_httpicontcreatof_ [l=pt-pt] {_httpimg_/pt-pt/tauthof.gif}
+_httpicontcreaton_ [l=pt-pt] {_httpimg_/pt-pt/tauthon.gif}
+_widthtcreatx_ [l=pt-pt] {95}
+
+## "assuntos" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=pt-pt] {_httpimg_/pt-pt/tsubjgr.gif}
+_httpicontsubjon_ [l=pt-pt] {_httpimg_/pt-pt/tsubjon.gif}
+_httpicontsubjof_ [l=pt-pt] {_httpimg_/pt-pt/tsubjof.gif}
+_widthtsubjx_ [l=pt-pt] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "datas" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=pt-pt] {_httpimg_/pt-pt/tdategr.gif}
+_httpicontdateof_ [l=pt-pt] {_httpimg_/pt-pt/tdateof.gif}
+_httpicontdateon_ [l=pt-pt] {_httpimg_/pt-pt/tdateon.gif}
+_widthtdatex_ [l=pt-pt] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "nomes de ficheiros" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=pt-pt] {_httpimg_/pt-pt/tsrcgr.gif}
+_httpicontsrcof_ [l=pt-pt] {_httpimg_/pt-pt/tsrcof.gif}
+_httpicontsrcon_ [l=pt-pt] {_httpimg_/pt-pt/tsrcon.gif}
+_widthtsrcx_ [l=pt-pt] {160}
+
+## "lÃ­ngua" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=pt-pt] {_httpimg_/pt-pt/tlanggr.gif}
+_httpicontlangon_ [l=pt-pt] {_httpimg_/pt-pt/tlangon.gif}
+_httpicontlangof_ [l=pt-pt] {_httpimg_/pt-pt/tlangof.gif}
+_widthtlangx_ [l=pt-pt] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "sÃ©ries" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=pt-pt] {_httpimg_/pt-pt/tsergr.gif}
+_httpicontserof_ [l=pt-pt] {_httpimg_/pt-pt/tserof.gif}
+_httpicontseron_ [l=pt-pt] {_httpimg_/pt-pt/tseron.gif}
+_widthtserx_ [l=pt-pt] {87}
+
+## "para" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=pt-pt] {_httpimg_/pt-pt/ttogr.gif}
+_httpiconttoon_ [l=pt-pt] {_httpimg_/pt-pt/ttoon.gif}
+_httpiconttoof_ [l=pt-pt] {_httpimg_/pt-pt/ttoof.gif}
+_widthttox_ [l=pt-pt] {87}
+
+## "de" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=pt-pt] {_httpimg_/pt-pt/tfromgr.gif}
+_httpicontfromon_ [l=pt-pt] {_httpimg_/pt-pt/tfromon.gif}
+_httpicontfromof_ [l=pt-pt] {_httpimg_/pt-pt/tfromof.gif}
+_widthtfromx_ [l=pt-pt] {87}
+
+## "organizaÃ§Ãµes" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=pt-pt] {_httpimg_/pt-pt/torggr.gif}
+_httpicontorgon_ [l=pt-pt] {_httpimg_/pt-pt/torgon.gif}
+_httpicontorgof_ [l=pt-pt] {_httpimg_/pt-pt/torgof.gif}
+_widthtorgx_ [l=pt-pt] {111}
+
+## "como" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=pt-pt] {_httpimg_/pt-pt/thowgr.gif}
+_httpiconthowon_ [l=pt-pt] {_httpimg_/pt-pt/thowon.gif}
+_httpiconthowof_ [l=pt-pt] {_httpimg_/pt-pt/thowof.gif}
+_widththowx_ [l=pt-pt] {87}
+
+## "tÃ³pico" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=pt-pt] {_httpimg_/pt-pt/ttopicgr.gif}
+_httpiconttopicon_ [l=pt-pt] {_httpimg_/pt-pt/ttopicon.gif}
+_httpiconttopicof_ [l=pt-pt] {_httpimg_/pt-pt/ttopicof.gif}
+_widthttopicx_ [l=pt-pt] {87}
+
+## "listar" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=pt-pt] {_httpimg_/pt-pt/tbrwsegr.gif}
+_httpicontbrwseon_ [l=pt-pt] {_httpimg_/pt-pt/tbrwseon.gif}
+_httpicontbrwseof_ [l=pt-pt] {_httpimg_/pt-pt/tbrwseof.gif}
+_widthtbrwsex_ [l=pt-pt] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "pessoas" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=pt-pt] {_httpimg_/pt-pt/tpeopgr.gif}
+_httpicontpeopof_ [l=pt-pt] {_httpimg_/pt-pt/tpeopof.gif}
+_httpicontpeopon_ [l=pt-pt] {_httpimg_/pt-pt/tpeopon.gif}
+_widthtpeopx_ [l=pt-pt] {87}
+
+## "acrÃ³nimo" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=pt-pt] {_httpimg_/pt-pt/tacrogr.gif}
+_httpicontacroof_ [l=pt-pt] {_httpimg_/pt-pt/tacroof.gif}
+_httpicontacroon_ [l=pt-pt] {_httpimg_/pt-pt/tacroon.gif}
+_widthtacrox_ [l=pt-pt] {87}
+
+## "frases" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=pt-pt] {_httpimg_/pt-pt/tphrsegr.gif}
+_httpicontphrseof_ [l=pt-pt] {_httpimg_/pt-pt/tphrseof.gif}
+_httpicontphrseon_ [l=pt-pt] {_httpimg_/pt-pt/tphrseon.gif}
+_widthtphrsex_ [l=pt-pt] {87}
+
+## "artistas" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=pt-pt] {_httpimg_/pt-pt/tartstgr.gif}
+_httpicontartstof_ [l=pt-pt] {_httpimg_/pt-pt/tartstof.gif}
+_httpicontartston_ [l=pt-pt] {_httpimg_/pt-pt/tartston.gif}
+_widthtartstx_ [l=pt-pt] {87}
+
+## "palavras-chave" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=pt-pt] {_httpimg_/pt-pt/tkwgr.gif}
+_httpicontkwof_ [l=pt-pt] {_httpimg_/pt-pt/tkwof.gif}
+_httpicontkwon_ [l=pt-pt] {_httpimg_/pt-pt/tkwon.gif}
+_widthtkwx_ [l=pt-pt] {124}
+
+## "volumes" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=pt-pt] {_httpimg_/pt-pt/tvolgr.gif}
+_httpicontvolof_ [l=pt-pt] {_httpimg_/pt-pt/tvolof.gif}
+_httpicontvolon_ [l=pt-pt] {_httpimg_/pt-pt/tvolon.gif}
+_widthtvolx_ [l=pt-pt] {87}
+
+## "legendas" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=pt-pt] {_httpimg_/pt-pt/tcaptgr.gif}
+_httpicontcaptof_ [l=pt-pt] {_httpimg_/pt-pt/tcaptof.gif}
+_httpicontcapton_ [l=pt-pt] {_httpimg_/pt-pt/tcapton.gif}
+_widthtcaptx_ [l=pt-pt] {87}
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "ajuda" ## green_title ## h_help ##
+_httpiconhhelp_ [l=pt-pt] {_httpimg_/pt-pt/h\_help.gif}
+_widthhhelp_ [l=pt-pt] {200}
+_heighthhelp_ [l=pt-pt] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=pt-pt] {Sobre esta coleÃ§Ã£o}
+
+_textsubcols1_ [l=pt-pt] {<p>A colecÃ§Ã£o completa contÃ©m _1_ sub-coleÃ§Ãµes:
+As disponÃ­veis actualmente sÃ£o:
+<blockquote>}
+
+_textsubcols2_ [l=pt-pt] {</blockquote>
+Pode verificar (e alterar) a sub-coleÃ§Ã£o que estÃ¡ 
+usando actualmente na pÃ¡gina de PreferÃªncias.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "sobre" ## green_title ## h_about ##
+_httpiconhabout_ [l=pt-pt] {_httpimg_/pt-pt/h\_about.gif}
+_widthhabout_ [l=pt-pt] {200}
+_heighthabout_ [l=pt-pt] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=pt-pt] {TÃ­tulos A-Z}
+_texticonhcreat_ [l=pt-pt] {Autores A-Z}
+_texticonhsubj_ [l=pt-pt] {Assuntos}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=pt-pt] {Datas}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=pt-pt] {Ficheiros}
+_texticonhlang_ [l=pt-pt] {LÃ­nguas}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=pt-pt] {Para}
+_texticonhfrom_ [l=pt-pt] {De}
+_texticonhser_ [l=pt-pt] {SÃ©ries}
+_texticonhhow_ [l=pt-pt] {Como}
+_texticonhorg_ [l=pt-pt] {OrganizaÃ§Ãµes}
+_texticonhbrwse_ [l=pt-pt] {Listar}
+_texticonhbrows_ [l=pt-pt] {Navegar}
+_texticonhpeople_ [l=pt-pt] {Pessoas A-Z}
+_texticonhacronym_ [l=pt-pt] {AcrÃ³nimos}
+_texticonhphrases_ [l=pt-pt] {Frases}
+_texticonhartist_ [l=pt-pt] {Artistas}
+_texticonhkw_ [l=pt-pt] {Palavras-chave}
+_texticonhvol_ [l=pt-pt] {Volumes}
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=pt-pt] {fechar esta secÃ§Ã£o da biblioteca}
+_texticonclosedbookshelf_ [l=pt-pt] {abre esta secÃ§Ã£o da biblioteca e visualiza o conteÃºdo}
+_texticonopenbook_ [l=pt-pt] {fechar este livro}
+_texticonclosedfolder_ [l=pt-pt] {abre esta pasta e visualiza o conteÃºdo}
+_texticonclosedfolder2_ [l=pt-pt] {abre sub-secÃ§Ã£o: }
+_texticonopenfolder_ [l=pt-pt] {fechar esta pasta}
+_texticonopenfolder2_ [l=pt-pt] {fechar sub-seÃ§Ã£o: }
+_texticonsmalltext_ [l=pt-pt] {Ver esta secÃ§Ã£o do texto}
+_texticonsmalltext2_ [l=pt-pt] {ver texto: }
+_texticonpointer_ [l=pt-pt] {secÃ§Ã£o actual}
+_texticondetach_ [l=pt-pt] {Abrir esta pÃ¡gina numa nova janela}
+_texticonhighlight_ [l=pt-pt] {Destacar termos de pesquisa}
+_texticonnohighlight_ [l=pt-pt] {NÃ£o destacar termos de pesquisa}
+_texticoncontracttoc_ [l=pt-pt] {Reduzir Ã­ndice de conteÃºdos}
+_texticonexpandtoc_ [l=pt-pt] {Expandir Ã­ndice de conteÃºdos}
+_texticonexpandtext_ [l=pt-pt] {Mostrar todo o texto}
+_texticoncontracttext_ [l=pt-pt] {Mostra texto apenas para as secÃ§Ãµes selecionadas}
+_texticonwarning_ [l=pt-pt] {<b>Aviso: </b>}
+_texticoncont_ [l=pt-pt] {continuar?}
+
+_textltwarning_ [l=pt-pt] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Expanding este texto irÃ¡ gerar uma grande 
+quantidade de dados para o seu browser mostrar _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=pt-pt] {ir para pÃ¡gina}
+_textintro_ [l=pt-pt] {<i>(texto introdutÃ³rio)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tÃ­tulos a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=pt-pt] {_httpimg_/pt-pt/h\_title.gif}
+_widthhtitle_ [l=pt-pt] {200}
+_heighthtitle_ [l=pt-pt] {57}
+
+# Not true DC, kept for legacy reasons
+## "autores a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=pt-pt] {_httpimg_/pt-pt/h\_auth.gif}
+_widthhcreat_ [l=pt-pt] {200}
+_heighthcreat_ [l=pt-pt] {57}
+
+## "assuntos" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=pt-pt] {_httpimg_/pt-pt/h\_subj.gif}
+_widthhsubj_ [l=pt-pt] {200}
+_heighthsubj_ [l=pt-pt] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "datas" ## green_title ## h_date ##
+_httpiconhdate_ [l=pt-pt] {_httpimg_/pt-pt/h\_date.gif}
+_widthhdate_ [l=pt-pt] {200}
+_heighthdate_ [l=pt-pt] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "ficheiros" ## green_title ## h_src ##
+_httpiconhsrc_ [l=pt-pt] {_httpimg_/pt-pt/h\_src.gif}
+_widthhsrc_ [l=pt-pt] {200}
+_heighthsrc_ [l=pt-pt] {57}
+
+## "lÃ­nguas" ## green_title ## h_lang ##
+_httpiconhlang_ [l=pt-pt] {_httpimg_/pt-pt/h\_lang.gif}
+_widthhlang_ [l=pt-pt] {200}
+_heighthlang_ [l=pt-pt] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "para" ## green_title ## h_to ##
+_httpiconhto_ [l=pt-pt] {_httpimg_/pt-pt/h\_to.gif}
+_widthhto_ [l=pt-pt] {200}
+_heighthto_ [l=pt-pt] {57}
+
+## "de" ## green_title ## h_from ##
+_httpiconhfrom_ [l=pt-pt] {_httpimg_/pt-pt/h\_from.gif}
+_widthhfrom_ [l=pt-pt] {200}
+_heighthfrom_ [l=pt-pt] {57}
+
+## "sÃ©ries" ## green_title ## h_ser ##
+_httpiconhser_ [l=pt-pt] {_httpimg_/pt-pt/h\_ser.gif}
+_widthhser_ [l=pt-pt] {200}
+_heighthser_ [l=pt-pt] {57}
+
+## "como" ## green_title ## h_how ##
+_httpiconhhow_ [l=pt-pt] {_httpimg_/pt-pt/h\_how.gif}
+_widthhhow_ [l=pt-pt] {200}
+_heighthhow_ [l=pt-pt] {57}
+
+## "tÃ³picos" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=pt-pt] {_httpimg_/pt-pt/h\_topic.gif}
+_widthhtopic_ [l=pt-pt] {200}
+_heighthtopic_ [l=pt-pt] {57}
+
+## "organizaÃ§Ã£o" ## green_title ## h_org ##
+_httpiconhorg_ [l=pt-pt] {_httpimg_/pt-pt/h\_org.gif}
+_widthhorg_ [l=pt-pt] {250}
+_heighthorg_ [l=pt-pt] {57}
+
+## "listar" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=pt-pt] {_httpimg_/pt-pt/h\_brwse.gif}
+_widthhbrwse_ [l=pt-pt] {200}
+_heighthbrwse_ [l=pt-pt] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "pessoas" ## green_title ## h_people ##
+_httpiconhpeople_ [l=pt-pt] {_httpimg_/pt-pt/h\_people.gif}
+_widthhpeople_ [l=pt-pt] {200}
+_heighthpeople_ [l=pt-pt] {57}
+
+## "acrÃ³nimos" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=pt-pt] {_httpimg_/pt-pt/h\_acro.gif}
+_widthhacronym_ [l=pt-pt] {200}
+_heighthacronym_ [l=pt-pt] {57}
+
+## "frases" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=pt-pt] {_httpimg_/pt-pt/h\_phrse.gif}
+_widthhphrse_ [l=pt-pt] {200}
+_heighthphrse_ [l=pt-pt] {57}
+
+## "artistas" ## green_title ## h_artist ##
+_httpiconhartist_ [l=pt-pt] {_httpimg_/pt-pt/h\_artist.gif}
+_widthhartist_ [l=pt-pt] {200}
+_heighthartist_ [l=pt-pt] {57}
+
+## "palavras-chave" ## green_title ## h_kw ##
+_httpiconhkw_ [l=pt-pt] {_httpimg_/pt-pt/h\_kw.gif}
+_widthhkw_ [l=pt-pt] {200}
+_heighthkw_ [l=pt-pt] {57}
+
+## "volumes" ## green_title ## h_vol ##
+_httpiconhvol_ [l=pt-pt] {_httpimg_/pt-pt/h\_vol.gif}
+_widthhvol_ [l=pt-pt] {200}
+_heighthvol_ [l=pt-pt] {57}
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+## "legendas" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=pt-pt] {_httpimg_/pt-pt/h\_capt.gif}
+_widthhcapt_ [l=pt-pt] {200}
+_heighthcapt_ [l=pt-pt] {57}
+
+
+## "CONTINUAR??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=pt-pt] {_httpimg_/pt-pt/contof.gif}
+_httpiconconton_ [l=pt-pt] {_httpimg_/pt-pt/conton.gif}
+
+## "EXPANDIR\nTEXTO" ## document_button ## eallt ##
+_httpiconealltof_ [l=pt-pt] {_httpimg_/pt-pt/ealltof.gif}
+_httpiconeallton_ [l=pt-pt] {_httpimg_/pt-pt/eallton.gif}
+
+## "CONTRAIR\nCONTEÃDO" ## document_button ## econc ##
+_httpiconeconcof_ [l=pt-pt] {_httpimg_/pt-pt/econcof.gif}
+_httpiconeconcon_ [l=pt-pt] {_httpimg_/pt-pt/econcon.gif}
+
+## "SEPARAR" ## document_button ## edtch ##
+_httpiconedtchof_ [l=pt-pt] {_httpimg_/pt-pt/edtchof.gif}
+_httpiconedtchon_ [l=pt-pt] {_httpimg_/pt-pt/edtchon.gif}
+
+## "EXPANDIR\nCONTEÃDO" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=pt-pt] {_httpimg_/pt-pt/eexpcof.gif}
+_httpiconeexpcon_ [l=pt-pt] {_httpimg_/pt-pt/eexpcon.gif}
+
+## "CONTRAIR\nTEXTO" ## document_button ## etsec ##
+_httpiconetsecof_ [l=pt-pt] {_httpimg_/pt-pt/etsecof.gif}
+_httpiconetsecon_ [l=pt-pt] {_httpimg_/pt-pt/etsecon.gif}
+
+## "DESTACAR" ## document_button ## ehl ##
+_httpiconehlof_ [l=pt-pt] {_httpimg_/pt-pt/ehlof.gif}
+_httpiconehlon_ [l=pt-pt] {_httpimg_/pt-pt/ehlon.gif}
+
+## "NÃO\nDESTACAR" ## document_button ## enhl ##
+_httpiconenhlof_ [l=pt-pt] {_httpimg_/pt-pt/enhlof.gif}
+_httpiconenhlon_ [l=pt-pt] {_httpimg_/pt-pt/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=pt-pt] {_If_(_thislast_,resultados _thisfirst_ - _thislast_ para a pesquisa: _cgiargq_,Nunhuma resposta encontrada: _cgiargq_)}
+_textnoquerytitle_ [l=pt-pt] {PÃ¡gina de pesquisa}
+
+_texticonthispage_ [l=pt-pt] {pesquisa}
+_textsome_ [l=pt-pt] {algumas}
+_textall_ [l=pt-pt] {todos}
+_textboolean_ [l=pt-pt] {booleano}
+_textranked_ [l=pt-pt] {ordenado}
+_textnatural_ [l=pt-pt] {natural}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=pt-pt] {}
+_texticonsearchhistorybar_ [l=pt-pt] {histÃ³rico de pesquisa}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=pt-pt] {usar esta pesquisa}
+_textfreqmsg1_ [l=pt-pt] {Palavras contadas: }
+_textpostprocess_ [l=pt-pt] {_If_(_quotedquery_,<br><i>pÃ³s-processadas para encontrar _quotedquery_</i>
+)}
+_textinvalidquery_ [l=pt-pt] {Pesquisa com sintaxe invÃ¡lida}
+
+_textmorethan_ [l=pt-pt] {Mais do que }
+_textapprox_ [l=pt-pt] {Sobre }
+_textnodocs_ [l=pt-pt] {NÃ£o foi encontrato nenhum documento.}
+_text1doc_ [l=pt-pt] {1 documento encontrado.}
+_textlotsdocs_ [l=pt-pt] {documentos encontrados.}
+_textmatches_ [l=pt-pt] {Resultados}
+_textbeginsearch_ [l=pt-pt] {Iniciar a Pesquisa}
+_textrunquery_ [l=pt-pt] {Pesquisar}
+_textclearform_ [l=pt-pt] {Limpar}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=pt-pt] {Palavra ou frase}
+_textinfield_ [l=pt-pt] {... no campo}
+_textfoldstem_ [l=pt-pt] {(dobra, eixo)}
+
+_textadvquery_ [l=pt-pt] {Ou introduza a pesquisa directamente:}
+_textallfields_ [l=pt-pt] {todos os campos}
+_texttextonly_ [l=pt-pt] {apenas texto}
+_textand_ [l=pt-pt] {e}
+_textor_ [l=pt-pt] {ou}
+_textandnot_ [l=pt-pt] {e nÃ£o}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=pt-pt] {Procurar por _indexselection_ _If_(_jselection_, de _jselection_)_If_(_gselection_, no _gselection_ nÃ­vel)_If_(_nselection_, na _nselection_ lÃ­ngua) que contenha _querytypeselection_ palavras}
+
+_textadvancedsearch_ [l=pt-pt] {Pesquisar _indexselection_ _If_(_jselection_, de _jselection_)_If_(_gselection_, no _gselection_ nÃ­vel)_If_(_nselection_, na _nselection_ lÃ­ngua) usando _querytypeselection_}
+
+_textformsimplesearch_ [l=pt-pt] {Procurar _If_(_jselection_, _jselection_) _If_(_gformselection_, no _gformselection_ level) _If_(_nselection_, na _nselection_ lÃ­ngua)
+for _formquerytypeselection_ of}
+
+_textformadvancedsearch_ [l=pt-pt] {Procurar _If_(_jselection_,_jselection_) _If_(_gformselection_, no _gformselection_ level)_If_(_nselection_, na _nselection_ lÃ­ngua) 
+e mostrar resultados ordenados por _formquerytypeselection_}
+
+
+_textnojsformwarning_ [l=pt-pt] {Aviso: O Javascript estÃ¡ desactivado no seu briwser. <br> Para usar formulÃ¡rios de pesquisa deve activÃ¡-lo.}
+_textdatesearch_ [l=pt-pt] {Nesta colecÃ§Ã£o podem-se pesquisar documentos contendo uma data ou que usando intervalos de datas. Esta opÃ§Ã£o de pesquisa Ã© opcional. }
+_textstartdate_ [l=pt-pt] {Data de inÃ­cio (ou Ãºnica):}
+_textenddate_ [l=pt-pt] {Data de inÃ­cio:}
+_textbc_ [l=pt-pt] {A.E.C.}
+_textad_ [l=pt-pt] {E.C.}
+_textexplaineras_ [l=pt-pt] {E.C. e A.E.C. sÃ£o alternativas para D.C. e A.C., respectivamente. Estes termos sÃ£o considerados culturalmente nÃ£o descriminatÃ³rios, significando "Era Comum" e "Antes da Era Comum"}
+
+_textstemon_ [l=pt-pt] {(ignorar final das palavras)}
+
+_textsearchhistory_ [l=pt-pt] {HistÃ³rial de Pesquisa}
+
+#text macros for search history
+_textnohistory_ [l=pt-pt] {HistÃ³rico de pesquisa nÃ£o disponÃ­vel}
+_texthresult_ [l=pt-pt] {resultado}
+_texthresults_ [l=pt-pt] {resultados}
+_texthallwords_ [l=pt-pt] {todas as palavras}
+_texthsomewords_ [l=pt-pt] {algumas palavras}
+_texthboolean_ [l=pt-pt] {booleano}
+_texthranked_ [l=pt-pt] {ordenado}
+_texthcaseon_ [l=pt-pt] {maiÃºsculas/minÃºsculas}
+_texthcaseoff_ [l=pt-pt] {"casefolded"}
+_texthstemon_ [l=pt-pt] {"stemmed"}
+_texthstemoff_ [l=pt-pt] {"unstemmed"}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "pesquisa" ## green_title ## h_search ##
+_httpiconhsearch_ [l=pt-pt] {_httpimg_/pt-pt/h\_search.gif}
+_widthhsearch_ [l=pt-pt] {200}
+_heighthsearch_ [l=pt-pt] {57}
+
+## "resultados" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=pt-pt] {_httpimg_/pt-pt/qryresb.gif}
+_widthqryresb_ [l=pt-pt] {_pagewidth_}
+_heightqryresb_ [l=pt-pt] {17}
+
+## "histÃ³rico" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=pt-pt] {_httpimg_/pt-pt/schhistb.gif}
+_widthsrchhistb_ [l=pt-pt] {_pagewidth_}
+_heightsrchhistb_ [l=pt-pt] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=pt-pt] {PreferÃªncias foram definidas como se segue. NÃ£o use o botÃ£o de "back" do seu browser
+- irÃ¡ desfazer as preferÃªncias! Em alternativa, seleccione um dos botÃµes na barra acima.
+}
+_textsetprefs_ [l=pt-pt] {definir preferÃªncias}
+_textsearchprefs_ [l=pt-pt] {PreferÃªncias de pesquisa}
+_textcollectionprefs_ [l=pt-pt] {PreferÃªncias da colecÃ§Ã£o}
+_textpresentationprefs_ [l=pt-pt] {PreferÃªncias de apresentaÃ§Ã£o}
+_textpreferences_ [l=pt-pt] {PreferÃªncias}
+_textcasediffs_ [l=pt-pt] {DiferenÃ§as maiÃºsculas/minÃºsculas}
+_textignorecase_ [l=pt-pt] {ignorar diferenÃ§as entre maiÃºsculas/minÃºsculas}
+_textmatchcase_ [l=pt-pt] {verificar maiÃºsculas/minÃºsculas}
+_textwordends_ [l=pt-pt] {TerminaÃ§Ãµes de palavras:}
+_textstem_ [l=pt-pt] {ignorar terminaÃ§Ãµes das palavras}
+_textnostem_ [l=pt-pt] {verificar palavra inteira}
+_textprefop_ [l=pt-pt] {Retornar atÃ© _maxdocoption_ resultados com _hitsperpageoption_ resultados por pÃ¡gina.}
+_textextlink_ [l=pt-pt] {Acesso pÃ¡ginas Web externas: }
+_textintlink_ [l=pt-pt] {Documentos recuperados de:}
+_textlanguage_ [l=pt-pt] {LÃ­ngua da Interface: }
+_textencoding_ [l=pt-pt] {CodificaÃ§Ã£o:}
+_textformat_ [l=pt-pt] {Formato da Interface: }
+_textall_ [l=pt-pt] {todos}
+_textquerymode_ [l=pt-pt] {Modo de pesquisa:}
+_textsimplemode_ [l=pt-pt] {modo de pesquisa simples}
+_textadvancedmode_ [l=pt-pt] {modo de pesquisas avanÃ§adas (permite pesquisas booleanas usando !, &, |, e parÃªntesis)}
+_textlinkinterm_ [l=pt-pt] {atravÃ©s de pÃ¡gina intermÃ©dia}
+_textlinkdirect_ [l=pt-pt] {ir directamente para lÃ¡}
+_textdigitlib_ [l=pt-pt] {a biblioteca digital}
+_textweb_ [l=pt-pt] {a web}
+_textgraphical_ [l=pt-pt] {GrÃ¡fico}
+_texttextual_ [l=pt-pt] {Textual}
+_textcollectionoption_ [l=pt-pt] {<p>
+Sub-colecÃ§Ãµes a incluir:
+<br>}
+
+_textrelateddocdisplay_ [l=pt-pt] {mostrar documentos relacionados}
+_textsearchhistory_ [l=pt-pt] {HistÃ³rico de pesquisa:}
+_textnohistory_ [l=pt-pt] {Sem histÃ³rico de pesquisa}
+_texthistorydisplay_ [l=pt-pt] {mostrar _historynumrecords_ pesquisas do histÃ³rico}
+_textnohistorydisplay_ [l=pt-pt] {nÃ£o mostrar histÃ³rico de pesquisa}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=pt-pt] {Pesquisa:}
+_textplainsearch_ [l=pt-pt] {Pesquisa simples:}
+_textqueryboxsize_ [l=pt-pt] {Tamanho da caixa de pesquisa:}
+_textregbox_ [l=pt-pt] {caixa d epesquisa normal}
+_textbigbox_ [l=pt-pt] {caixa de pesquisa grande}
+_textformtype_ [l=pt-pt] {Tipo:}
+_textsimple_ [l=pt-pt] {simples}
+_textadvanced_ [l=pt-pt] {avanÃ§ado}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=pt-pt] {com}
+_textfields_ [l=pt-pt] {campos}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferÃªncias" ## green_title ## h_pref ##
+_httpiconhpref_ [l=pt-pt] {_httpimg_/pt-pt/h\_pref.gif}
+_widthhpref_ [l=pt-pt] {200}
+_heighthpref_ [l=pt-pt] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=pt-pt] {Ordenar documentos por}
+_textalsoshowing_ [l=pt-pt] {apresentando tambÃ©m}
+_textwith_ [l=pt-pt] {com o mÃ¡ximo}
+_textdocsperpage_ [l=pt-pt] {documentos por pÃ¡gina}
+
+_textfilterby_ [l=pt-pt] {Documentos contendo}
+_textall_ [l=pt-pt] {todos}
+_textany_ [l=pt-pt] {qualquer um}
+_textwords_ [l=pt-pt] {das palavras}
+_textleaveblank_ [l=pt-pt] {deixe esta caixa em branco para recuperar todos os documentos}
+
+_browsebuttontext_ [l=pt-pt] {"Ordenar Documentos"}
+
+_nodata_ [l=pt-pt] {<i>nÃ£o hÃ¡ dados</i>}
+_docs_ [l=pt-pt] {documentos}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=pt-pt] {Ajuda}
+_textSearchshort_ [l=pt-pt] {Pesquisa por palavras}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por tÃ­tulo}
+_textCreatorshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por autores}
+_textSubjectshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por assunto}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por data}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por ficheiro}
+_textLanguageshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por lÃ­ngua}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por sÃ©ries}
+_textToshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes pelo campo Para}
+_textFromshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes pelo campo De}
+_textBrowseshort_ [l=pt-pt] {listar publicaÃ§Ãµes}
+_textOrganizationshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por organizaÃ§Ã£o}
+_textHowtoshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes pelas opÃ§Ãµes de "como"}
+_textTopicshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por tÃ³pico}
+_textPeopleshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por pessoas}
+_textAcronymshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por acrÃ³nimos}
+_textPhraseshort_ [l=pt-pt] {navegar por frases que ocorrem nas publicaÃ§Ãµes}
+_textArtistshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes pelos nomes dos artistas}
+_textKeywordshort_ [l=pt-pt] {acesso Ã s publicaÃ§Ãµes por palavra-chave}
+_textVolumeshort_ [l=pt-pt] {aceder Ã s publicaÃ§Ãµes por volume}
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=pt-pt] {classificaÃ§Ã£o indefinida}
+
+_textSearchlong_ [l=pt-pt] {<p><i>Pesquisar por palavras</i> que
+aparecem no texto da pÃ¡gina "busca". Esta Ã© a primeira pÃ¡gina que
+aparece quando no inÃ­cio, e pode ser acedida a partir das outras pÃ¡ginas pressionando-se
+o botÃ£o <i>pesquisa</i>.  }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=pt-pt] {<p>Para <i>aceder Ã s publicaÃ§Ãµes por tÃ­tulo</i> seleccionar
+o botÃ£o <i>tÃ­tulos a-z</i>.  SerÃ¡ apresnetada uma lista de livros por ordem alfabÃ©tica.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=pt-pt] {<p>Para <i>aceder Ã s publicaÃ§Ãµes por autor</i> 
+seleccione o botÃ£o <i>autores a-z</i>.  SerÃ¡ apresentada uma lista de livros,
+ordenada por nome de autores.  }
+
+_textSubjectlong_ [l=pt-pt] {<p>Para <i>aceder Ã s publicaÃ§Ãµes por assuntos</i> 
+seleccionar o botÃ£o <i>assuntos</i>.  SrÃ¡ apresentada uma lista de assuntos,
+representando por estantes de livros.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=pt-pt] {<p>Para <i>aceder Ã s publicaÃ§Ãµes por data</i> seleccioinar
+no botÃ£o <i>datas</i>.  SerÃ¡ apresentada uma lista de todas as ediÃ§Ãµes, ordenadas
+cronologicamente.  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=pt-pt] {<p>Pode <i>aceder Ã s publicaÃ§Ãµes por nome de ficheiro</i>
+seleccionando a opÃ§Ã£o <i>ficheiro</i>.  AparecerÃ¡ uma
+lista de nomes de ficheiros originais.  }
+
+_textLanguagelong_ [l=pt-pt] {<p>Pode <i>aceder Ã s publicaÃ§Ãµes por lÃ­ngua</i>
+seleccionando a opÃ§Ã£o <i>lÃ­ngua</i>.  AparecerÃ¡ uma
+lista ordenada de lÃ­nguas.  }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=pt-pt] {<p>Pode <i>aceder Ã s publicaÃ§Ãµes por organizaÃ§Ã£o</i>
+seleccionando a opÃ§Ã£o <i>organizaÃ§Ã£o</i>.  AparecerÃ¡ uma
+lista de organizaÃ§Ãµes.  }
+
+_textHowtolong_ [l=pt-pt] {<p>Pode <i>aceder Ã s publicaÃ§Ãµes pela lista de "Como"</i>
+seleccionando a opÃ§Ã£o <i>como</i>.  AparecerÃ¡ a lista de termos.  }
+
+_textTopiclong_ [l=pt-pt] {<p>Para <i>aceder Ã s publicaÃ§Ãµes por tÃ³pico</i> 
+selecionar o botÃ£o <i>tÃ³pico</i>.  SerÃ¡ apresentada uma lista de tÃ³picos
+para navegaÃ§Ã£o.  }
+
+_textTolong_ [l=pt-pt] {<p>Pode <i>acede Ã s publicaÃ§Ãµes pelo campo Para</i> 
+selecionando a opÃ§Ã£o <i>para</i>.  AparecerÃ¡ uma lista de endereÃ§os.  }
+
+_textFromlong_ [l=pt-pt] {<p>Pode <i>aceder Ã s publicaÃ§Ãµes pelo campo De</i>
+seleccionando a opÃ§Ã£o <i>de</i>.  AparecerÃ¡ a lista de remetentes.  }
+
+_textSerieslong_ [l=pt-pt] {<p>Para <i>aceder a publicaÃ§Ãµes por sÃ©ries</i> 
+seleccionar o botÃ£o <i>sÃ©ries</i>.  SerÃ¡ apresentada uma lista das sÃ©ries
+que existem na coleÃ§Ã£o.  }
+
+_textBrowselong_ [l=pt-pt] {<p>Para <i>listar publicaÃ§Ãµes</i> seleccione o
+botÃ£o <i>folhear</i>.  }
+
+_textPeoplelong_ [l=pt-pt] {<p>Para <i>aceder Ã s publicaÃ§Ãµes por pessoas</i> 
+seleccciona o botÃ£o <i>pessoas a-z</i>.  SerÃ¡ apresentada uma lista ordenadas por apelido.  }
+
+_textAcronymlong_ [l=pt-pt] {<p>Pode <i>aceder Ã s publicaÃ§Ãµes por acrÃ³nimos</i> 
+seleccionando a opÃ§Ã£o <i>acrÃ³nimos</i>.  SerÃ¡ apresentada a lista de acrÃ³nimos,
+e os locais onde eles ocorrem.  }
+
+_textPhraselong_ [l=pt-pt] {<p>Pode <i>navegar por frases que ocorrem nas publicaÃ§Ãµes</i> 
+seleccionando a opÃ§Ã£o <i>frases</i>.  Esta opÃ§Ã£o usa o navegador de frases phind.  }
+
+_textArtistlong_ [l=pt-pt] {<p>Pode <i>aceder Ã s publicaÃ§Ãµes pelos nomes dos artistas</i> 
+seleccionando a opÃ§Ã£o <i>artistas</i>.  SerÃ¡ apresentada uma lista
+ordenada pelo nomes do artista.  }
+
+_textKeywordlong_ [l=pt-pt] {<p>Pode <i>aceder Ã s publicaÃ§Ãµes por palavra-chave</i>
+seleccionando a opÃ§Ã£o <i>palavras-chave</i>.  AparecerÃ¡ a lista de palavras-chave.  }
+
+_textVolumelong_ [l=pt-pt] {<p>Pode <i>acede Ã s publicaÃ§Ãµes pelo volume</i> 
+selecionando a opÃ§Ã£o <i>volume</i>.  AparecerÃ¡ uma lista de volumes.  }
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=pt-pt] {<p>Selecione o botÃ£o <i>nÃ£o encontrado</i> para listar
+publicaÃ§Ãµes (a ordenaÃ§Ã£o Ã© feita por um campo nÃ£o conhecido).  }
+
+# -- Missing translation: _texthelptopics_
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=pt-pt] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=pt-pt] {Como ler os documentos}
+
+_texthelpreadingdocs_ [l=pt-pt] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Pode-se saber quando se chegou a um documento especifico quando
+o tÃ­tulo ou a imagem da capa aparecerem no topo esquerdo da pÃ¡gina.
+Nalgumas colecÃ§Ãµes aparece tambÃ©m o Ã­ndice, enquanto noutras aparecerÃ¡ 
+apenas o nÃºmero da pÃ¡gina com uma caixa para seleccionar uma nova pÃ¡gina e ir para a frente ou pare trÃ¡s.
+No Ã­ndice, o capÃ­tulo actual Ã© apresentado a negro, e o Ã­ndice Ã© expansÃ­vel.
+
+<p>O texto de cada secÃ§Ã£o aparece sob o Ã­ndice. No final hÃ¡ setas que permitem avanÃ§ar
+para a prÃ³xima secÃ§Ã£o ou recuar para a anterior
+
+<p>Abaixo do tÃ­tulo ou capa hÃ¡ alguns botÃµes. Seleccione <i>expandir
+texto</i> para ver todo o texto do documento actual. Se o 
+documento for grande, isto poderÃ¡ levar muito tempo e usar muita memÃ³ria!
+Seleccione em <i> expandir conteÃºdo</i> para ver todo o Ã­ndice.
+Seleccione em <i>separar</i> para abrir uma nova janela com o
+documento. (Isto Ã© Ãºtil se quiser comparar documentos, ou ler dois ao
+mesmo tempo.)  Finalmente, quando fizer uma pesquisa por palavras as mesmas serÃ£o
+destacadas.  Clique em <i>nÃ£o destacar</i> para retirar os destaques.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Seleccione a seta para ir para a prÃ³xima secÃ§Ã£o ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... ou voltar para a secÃ§Ã£o anterior</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Mostrar todo texto, ou nÃ£o</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Abrir esta pÃ¡gina numa nova janela</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Destacar termos pesquisados, ou nÃ£o</td></tr>
+</table>
+ }
+
+_texthelpsearching_ [l=pt-pt] {<h2>Como pesquisar por palavras</h2>
+<p>
+  Na pÃ¡gina de pesquisa poderÃ¡ fazer uma consulta com estes simples passos:<p>
+  
+  <ol><li>Especifique os itens que quer pesquisar 
+      <li>Diga se quer pesquisar por todas ou apenas algumas palavras 
+      <li>Digite as palavras que quer pesquisar 
+      <li>Seleccione no botÃ£o <i>ComeÃ§ar pesquisa</i>
+  </ol>
+
+<p>Quando fizer uma pesquisa, os tÃ­tulos de vinte documentos serÃ£o apresentados.
+HaverÃ¡ um botÃ£o no final da pÃ¡gina que apresentarÃ¡ os prÃ³ximos vinte documentos.  LÃ¡ encontrarÃ¡ botÃµes para mostrar os prÃ³ximos
+vinte ou voltar para os primeiros vinte, e assim sucessivamente. Para ver um documento seleccione o tÃ­tulo de qualquer documento, 
+ou no pequeno botÃ£o ao lado dele.
+
+<p>Podem ser retornados um mÃ¡ximo de 100 documentos. Pode mudar este nÃºmero nas <i>preferÃªncias</i> no topo da pÃ¡gina.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Termos de Pesquisa </h3>
+
+<p>Tudo o que digitar na caixa de consulta Ã© interpretado como uma lista de palavras chamada "termos de pesquisa." 
+Cada termo deve conter apenas caracteres e dÃ­gitos. Termos sÃ£o separados por espaÃ§os em branco. Se aparecer qualquer 
+outro caracter, como por exemplo pontuaÃ§Ã£o, ele serÃ¡ usado como separadores de termos, tal como se fossem espaÃ§os. 
+NÃ£o se pode pesquisar palavras que incluam pontuaÃ§Ã£o. 
+
+<p>Por exemplo, a consulta <p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>SerÃ¡ processada como<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Tipos de pesquisa</h3>
+
+<p>Existem dois tipos diferentes de pesquisa.
+
+<ul>
+  <li>Pesquisas por <b>todas</b> as palavras.  Esta opÃ§Ã£o procura documentos 
+      que contenham todas as palavras especificadas. Os documentos que
+ satisfaÃ§am a pesquisa serÃ£o apresentados por ordem alfabÃ©tica .<p>
+
+  <li> Pesquisas por <b>algumas</b> das palavras.  Podem-se indicar alguns termos 
+      que se espera existam nos documentos que se procuram. Os documentos sÃ£o apresentados na ordem mais prÃ³xima da pesquisa. 
+O grau de proximidade Ã© determinado
+
+      <p><ul>
+        <li> quanto mais termos um documento contenha, mais prÃ³ximo estarÃ¡;
+        <li> termos raros sÃ£o mais importantes que termos comuns;
+        <li> documentos menores sÃ£o mais relevantes que documentos grandes.
+      </ul>
+</ul>
+
+<p>Podem-se usar quantos termos se quiser - uma frase completa, ou mesmo um parÃ¡grafo completo. Se especificar apenas um termo, ~
+os documentos serÃ£o ordenados por frequÃªncia de ocorrÃªncia.<p>
+_texthelpscope_}
+
+_textdatesearch_ [l=pt-pt] {Pesquisa com Datas}
+
+_texthelpdatesearch_ [l=pt-pt] {<h2>_textdatesearch_</h2>
+A pesquisa por datas permite encontrar documentos que, alÃ©m de verificarem os termos de pesquisa, sÃ£o ainda sobre eventos dentro d eum determinado intervalo de tempo. Pode-se procurar por documentos de um determinado ano ou intervalo de anos. De notar que nÃ£o Ã© necessÃ¡rio usar nenhum termo de pesquisa -- pode-s epesquisar apenas por data; tambÃ©m Ã© possÃ­vel nÃ£o usar data na pesquisa, se tal acontecer a pesquisa serÃ¡ feita sem considerar datas.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>Como usar esta opÃ§Ã£o:</h3>
+<ul>
+   <li>Procurar documentos sobre um determinado ano:<p>
+   <ul>
+       <li>Escreva normalmente o termo de pesquisa. 
+       <li>Escreva a data mais antiga na caixa "Data inicial (ou Ãºnica)".
+       <li>Se a data Ã© antes da era comum (Antes de Cristo) escolha a opÃ§Ã£o E.A.C. no menu ao lado da caixa.
+       <li>Inicie a pesquisa como normalmente.
+   </ul>
+<p><li>Procurar documentos sobre um determinado perÃ­odo:<p>
+   <ul>
+       <li>Escreva normalmente o termo de pesquisa. 
+       <li>Escreva a data mais antiga na caixa "Data inicial (ou Ãºnica)".
+       <li>Escreva a data mais recente na caixa "Data Final".
+       <li>Selecione E.A.C no menu se a data Ã© antes da era comum (Antes de Cristo).
+       <li>Inicie a pesquisa como normalmente.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>Como funciona a pesquisa</h3>
+
+Regra geral, uma pesquisa por documentos sobre o ano 1903 nÃ£o encontra documentos sobre livros escritos em 1903, mas apenas documentos sobre o ano 1903. SerÃ£o encontrados ainda documentos que relativos a um intervalo de tempo que inclua 1903 (como por exemplo 1899-1911), assim como documentos relativos ao sÃ©culo (por exemplo, "sÃ©culo vinte" ou "sÃ©culo 20" para o ano 1903). Isto quer dizer que alguns documentos encontrados poderÃ£o nÃ£o referir explicitamente no texto a data de pesquisa. Para uma pesquisa com um intervalo de tempo, isto aplica-se a todas as data no intervalo.<p>
+}
+
+_textchangeprefs_ [l=pt-pt] {Mudar as preferÃªncias }
+
+_texthelppreferences_ [l=pt-pt] {<h2>_textchangeprefs_</h2>
+
+<p>Seleccionando o botÃ£o <i>preferÃªncias</i> no topo da pÃ¡gina, serÃ¡
+possÃ­vel mudar alguns aspectos da interface segundo as suas preferÃªncias.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>PreferÃªncias da colecÃ§Ã£o</h3>
+
+Algumas colecÃ§Ãµes incluem vÃ¡rias sub-colecÃ§Ãµes, as quais podem ser pesquisadas
+independentemente ou juntas, como uma Ãºnica unidade. Nesses casos pode seleccionar na
+pÃ¡gina de PreferÃªncias que sub-colecÃ§Ãµes incluir nas pesquisas.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>PreferÃªncia de LÃ­ngua</h3>
+
+Cada colecÃ§Ã£o tem uma lÃ­ngua de apresentaÃ§Ã£o por omissÃ£o, mas pode-se mudar 
+para outra lÃ­ngua se pretendido. Pode-se alterar tambÃ©m o esquema de codificaÃ§Ã£o 
+usado pelo Greenstone para enviar a informaÃ§Ã£o para o browser -- o software escolhe 
+omissÃµes normais, mas nalguns browsers podem-se obter melhores resultados visuais 
+seleccionando outros esquemas de codificaÃ§Ã£o. Todas as colecÃ§Ãµes permitem mudar da 
+interface grÃ¡fica normal para uma interface textual. Esta opÃ§Ã£o Ã© especialmente Ãºtil 
+para utilizadores com problemas de visÃ£o, que usem fontes grandes ou sintetizadores 
+de voz
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>PreferÃªncias de apresentaÃ§Ã£o</h3>
+
+Dependendo da colecÃ§Ã£o em causa, poderÃ£o existir opÃ§Ãµes que se podem definir para controlar a apresentaÃ§Ã£o. 
+
+As colecÃ§Ãµes de pÃ¡ginas Web permitem suprimir a barra de navegaÃ§Ã£o Greenstone no topo de cada pÃ¡gina, 
+pelo que quando uma pesquisa os documentos encontrados aparecerÃ£o sem nenhum cabeÃ§alho Greenstone. 
+Para fazer outra pesquisa terÃ¡ que usar o botÃ£o "back" do seu browser. Estas colecÃ§Ãµes tambÃ©m possibilitam
+suprimir as mensagens de avisos Greenstone quando seleccionar um link para fora da colecÃ§Ã£o da biblioteca digital.
+Nalgumas colecÃ§Ãµes podem-se controlar quaisquer links na pÃ¡gina de "Resultados de Pesquisa" para ir 
+directamente para a URL em questÃ£o, ao invÃ©s de ir para as cÃ³pias das pÃ¡ginas na biblioteca digital.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>PreferÃªncias de pesquisa </h3>
+Dois pares de botÃµes permitem controlar a forma como o texto Ã© interpretado na pesquisas. 
+O primeiro grupo de botÃµes ("maiÃºsculas/minÃºsculas) controlam quando se devem verificar 
+maiÃºsculas ou  minÃºsculas.  O segundo grupo ("terminaÃ§Ãµes de palavras") controla quando se deve ignorar ou nÃ£o qualquer final de palavras. 
+Ã espantosamente rÃ¡pido como se pode pesquisa em grandes quantidades de texto.
+
+<p>Por exemplo, se os botÃµes <i>ignorar maiÃºsculas/minÃºsculas/i> e
+<i>ignorar terminaÃ§Ãµes de palavras </i> estiverem seleccionados, a pesquisa <p>
+    <ul><kbd>African building</kbd></ul>
+      <p>serÃ¡ tratada como <p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      porque as letras maiÃºsculas em "African" serÃ£o transformadas para 
+      minÃºsculas, e os sufixos "n" e "ing" serÃ£o removidos de 
+      "African" e "building" respectivamente (os "s" serÃ£o tambÃ©m removidos de 
+      "builds").
+
+<p>TambÃ©m se pode mudar para o modo "avanÃ§ado" de consulta que possibilitarÃ¡ 
+combinar termos usando AND (&), OR (|), e NOT (!). Isto darÃ¡ resultados mais precisos. 
+Seleccionando a opÃ§Ã£o de histÃ³rico de pesquisa recuperam-se as Ãºltimas pesquisas.
+Finalmente, pode-se controlar o nÃºmero de resultados retornados, e o nÃºmero de
+resultados por pÃ¡gina.}
+
+_texttanumbrowseoptions_ [l=pt-pt] {Existem _numbrowseoptions_ formas de encontrar informaÃ§Ã£o nesta colecÃ§Ã£o:}
+
+_textsimplehelpheading_ [l=pt-pt] {Como encontrar informaÃ§Ã£o na colecÃ§Ã£o _collectionname_}
+
+_texthelpscope_ [l=pt-pt] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>AbrangÃªncia das consultas</h3>
+
+<p>
+Na maioria das coleÃ§Ãµes podem-se escolher diferentes indices de pesquisa. Por exemplo, podem existir indeces de autores ou de tÃ­tulos. Ou podem ser Ã­ndices de capÃ­tulos ou parÃ¡grafos. Geralmente sÃ£o retornados todos os documentos que verifiquem as condiÃ§Ãµes de pesquisa, dependendo do Ã­ndice.
+<p>Se os documentos sÃ£o livros, os mesmos serÃ£o abertos no local apropriado.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/pref.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/pref.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/pref.dm	(revision 10506)
@@ -0,0 +1,547 @@
+# this file must be UTF-8 encoded
+
+package preferences
+
+# set within server
+
+# collectionoption is only set when cross-collection searching is turned on
+_collectionoption_ {}
+
+# this macro will be set to "1" when the "source docs retrived from dl/web
+# button is required - i.e. whenever PreferenceDocsFromWeb isn't set to false
+# in collect.cfg
+_PreferenceDocsFromWeb_ {}
+
+# this macro will be set to _textprefschanged_ when the "set preferences"
+# button has been pressed
+_prefschanged_ {}
+
+#######################################################################
+# java images/scripts
+#######################################################################
+
+# the _javalinks_ macros are the flashy image links at the top right of
+# the page. this is overridden here as we don't want a 'preferences' 
+# link on this page
+
+_javalinks_ {_imagehome_ _imagehelp_}
+_javalinks_ [v=1] {
+_imagehome_<br>
+_imagehelp_<br>
+}
+
+
+#######################################################################
+# scripts
+# note that changing either the "m" or the "o" argument
+# from the preferences page necessitates reseting the "r"
+# argument to 1
+#######################################################################
+
+_ccsfunctions_ {argcc = "";
+savedccs = new Object();
+
+function initialize () \{
+  for (i = 0; i < document.links.length; i++)
+    savedhrefs[i] = document.links[i].href;
+
+  s = "_cgiargcc_";
+  a = s.split (",");
+  for (i = 0; i < a.length ;i++) \{
+    for (j = 0; j < document.PrefForm.cc.length; j++) \{
+      if (a[i] == document.PrefForm.elements["cc"][j].value) \{
+        document.PrefForm.elements["cc"][j].checked = true;
+        savedccs[a[i]] = 1;
+        argcc = argcc + "&cc=" + a[i];
+        break;
+      \} else \{
+        savedccs[a[i]] = 0;
+      \}
+    \}
+  \}
+  updatehrefs();
+\}
+
+function updatecc (collection) \{
+  if (savedccs[collection] == 1) savedccs[collection] = 0;
+  else savedccs[collection] = 1;
+       
+  var i;
+  argcc = "";
+  var changed = 0;
+  for (i in savedccs)
+    if (savedccs[i] == 1) \{
+       argcc += "&cc=" + i;
+       changed = 1;
+    \}
+  if (changed == 1) argcc += "&r=1";
+  updatehrefs();
+\}
+}
+
+_standardfunctions_ {
+function initialize () \{
+  for (i = 0; i < document.links.length; i++)
+    savedhrefs[i] = document.links[i].href;
+
+\}
+
+}
+
+_getargsfunction_ {
+function getargs () \{
+  return argk + args + argm + argo + argrd + arghd + argb + argqf + argqb + argfqn_If_(_collectionoption_,_ccsargs_)_If_(_htmloptions_,_htmlargs_);
+\}
+}
+
+_ccsargs_ {+ argcc}
+_htmlargs_ {+ argel + argil + argfc + arghl}
+
+_htmlfunctions_ {argel = "";
+argil = "";
+argfc = "";
+arghl = "";
+
+function updateel () \{
+  value = document.PrefForm.el.options[document.PrefForm.el.selectedIndex].value;
+  if (value != "_cgiargel_") argel = "&el=" + value;
+  else argel = "";
+  updatehrefs();
+\}
+
+function updateil () \{
+  value = document.PrefForm.il.options[document.PrefForm.il.selectedIndex].value;
+  if (value != "_cgiargil_") argil = "&il=" + value;
+  else argil = "";
+  updatehrefs();
+\}
+
+function updatefc(value) \{
+  if (value != _cgiargfc_) argfc = "&fc=" + value + "&f=" + value;
+  else argfc = "";
+  updatehrefs();
+\}
+
+function updatehl(value) \{
+  if (value != _cgiarghl_) arghl = "&hl=" + value;
+  else arghl = "";
+  updatehrefs();
+\}
+}
+
+_pagescriptextra_ {
+// preferences scripts generated from \_preferences:pagescriptextra\_
+
+savedhrefs = new Object();
+
+argk = "";
+args = "";		
+argm = "";
+argrd = "";
+argo = "";
+argb = "";
+argqf = "";
+arghd = "";
+argqb = "";
+argfqn = "";
+
+_If_(_collectionoption_,_ccsfunctions_,_standardfunctions_)
+_If_(_htmloptions_,_htmlfunctions_)
+_getargsfunction_
+function updatehrefs () \{
+  for (i = 0; i < document.links.length; i++)
+    document.links[i].href = savedhrefs[i] + getargs();
+\}
+
+function updatek (value) \{
+  if (value != _cgiargk_) argk = "&k=" + value;
+  else argk = "";
+  updatehrefs();
+\}
+
+function updates (value) \{
+  if (value != _cgiargs_) args = "&s=" + value;
+  else args = "";
+  updatehrefs();
+\}
+
+function updatem () \{
+  value = document.PrefForm.m.options[document.PrefForm.m.selectedIndex].value;
+  if (value != _cgiargm_) argm = "&r=1&m=" + value;
+  else argm = "";
+  updatehrefs();
+\}
+
+function updaterd () \{
+  if (document.PrefForm.rd.checked)
+    _If_("_cgiargrd_" eq "1",argrd="";,argrd="&rd=1";)
+  else 
+    _If_("_cgiargrd_" ne "1",argrd="";,argrd="&rd=0";)
+  updatehrefs();
+\}
+
+function updateo () \{
+  value = document.PrefForm.o.options[document.PrefForm.o.selectedIndex].value;
+  if (value != _cgiargo_) argo = "&r=1&o=" + value;
+  else argo = "";
+  updatehrefs();
+\}
+
+function updatefqn () \{
+  value = document.PrefForm.fqn.options[document.PrefForm.fqn.selectedIndex].value;
+  if (value != _cgiargfqn_) argfqn = "&fqn=" + value;
+  else argfqn = "";
+  updatehrefs();
+\}
+
+function updateb (value) \{
+  if (value != _cgiargb_) argb = "&b=" + value;
+  else argb = "";
+  updatehrefs();
+\}
+function updateqf (value) \{
+  if (value != _cgiargqf_) argqf = "&qf=" + value;
+  else argqf = "";
+  updatehrefs();
+\}
+
+function updatehd() \{
+  arghd="";
+  if (document.PrefForm.hd[0].checked) \{
+     if ("_cgiarghd_" != "0") arghd = "&hd=0";
+  \}
+  else \{
+     value = document.PrefForm.hdn[document.PrefForm.hdn.selectedIndex].value;
+     if (_cgiarghd_ != value) arghd = "&hd="+value;
+  \}
+  updatehrefs();
+\}
+
+function updateqb(value) \{
+  if (value != _cgiargqb_) argqb = "&qb=" + value;
+  else argqb = "";
+  updatehrefs();
+\}
+
+function updatel () \{
+  value = document.PrefForm.l.options[document.PrefForm.l.selectedIndex].value;
+  href = location.href;
+  if (href.match(/&l=[\\w\\-]+/)) href = href.replace(/&l=[\\w\\-]+/, "&l=" + value);
+  else href += "&l=" + value;
+  if (!location.href.match(/&nl=1$/)) href += "&nl=1";
+  while (href.match(/&cc=[\\w]+/)) href = href.replace(/&cc=[\\w]+/, "");
+  location.href = href + getargs();
+\}
+
+function updatev () \{
+  value = document.PrefForm.v.options[document.PrefForm.v.selectedIndex].value;
+  href = location.href;
+  if (href.match(/&v=\\d/)) href = href.replace(/&v=\\d/, "&v=" + value);
+  else href += "&v=" + value;
+  while (href.match(/&cc=[\\w]+/)) href = href.replace(/&cc=[\\w]+/, "");
+  location.href = href + getargs();
+\}
+
+function updatew () \{
+  value = document.PrefForm.w.options[document.PrefForm.w.selectedIndex].value;
+  href = location.href;
+  if (href.match(/&nw=[^&]+/)) href = href.replace(/&nw=[^&]+/, "&nw=" + value);
+  else href += "&nw=" + value;
+  if (!location.href.match(/&nl=0$/)) href += "&nl=0";
+  while (href.match(/&cc=[\\w]+/)) href = href.replace(/&cc=[\\w]+/, "");
+  location.href = href + getargs();
+\}
+
+function updateqt (value) \{
+  if (value != _cgiargqt_) \{
+    while (href.match(/&cc=[\\w]+/)) href = href.replace(/&cc=[\\w]+/, "");
+    location.href = location.href + "&qt=" + value + getargs();
+  \}	
+\}
+}
+
+
+#######################################################################
+# headers
+# these are overridden so we can put an onLoad event handler
+# in the <body> tag of this page
+#######################################################################
+
+
+_header_ {_cgihead_
+_htmlhead_(background="_httpiconchalk_" onLoad="initialize();")_startspacer__pagebanner_
+}
+
+# this declaration ends up being the same as style=restrict, never mind
+_header_[v=1] {_cgihead_
+_htmlhead_(onLoad="initialize();")_pagebanner_
+}
+
+
+#######################################################################
+# page content
+#######################################################################
+
+_pagetitle_ {_collectionname_: _textpreferences_}
+_imagethispage_ {_iconthispage_}
+
+_htmloptions_ {}
+
+_htmloptionson_ {
+<p>
+<tr>_fcoption_</tr>
+<p>
+<tr>_hloption_</tr>
+<p>
+<tr>_extlinkoption_</tr>
+_If_(_PreferenceDocsFromWeb_,<p>
+<tr>_intlinkoption_</tr>)
+}
+
+_fcoption_ {
+<td valign=baseline>Document page layout</td>
+<td><input type=radio name=fc value=1 onClick="updatefc(1);"
+		_If_(_cgiargfc_, checked)>navigation bar at top<br>
+<input type=radio name=fc value=0 onClick="updatefc(0);"
+		_If_(_cgiargfc_,, checked)>no navigation bar</td>
+}
+
+_hloption_ {
+<td valign=baseline>Search term highlighting</td>
+<td><input type=radio name=hl value=1 onClick="updatehl(1);"
+		_If_(_cgiarghl_, checked)>highlight search terms<br>
+<input type=radio name=hl value=0 onClick="updatehl(0);"
+		_If_(_cgiarghl_,, checked)>don't highlight search terms</td>
+}
+
+#search pref options
+_boxsizeoption_{
+<td valign=baseline>_textqueryboxsize_</td>
+<td><input type=radio name=qb value=0 onClick="updateqb(0);"
+		_If_(_cgiargqb_,, checked)>_textregbox_<br>
+<input type=radio name=qb value=1 onClick="updateqb(1);"
+		_If_(_cgiargqb_, checked)>_textbigbox_</td>
+}
+
+_caseoption_ {
+<td valign=baseline>_textcasediffs_</td>
+<td><input type=radio name=k value=1 onClick="updatek(1);"
+		_If_(_cgiargk_, checked)>_textignorecase_<br>
+<input type=radio name=k value=0 onClick="updatek(0);"
+		_If_(_cgiargk_,, checked)>_textmatchcase_</td>
+}
+
+_caseoption_ [l=ar] {}
+_caseoption_ [l=zh] {}
+
+_stemoption_ {
+<td valign=baseline>_textwordends_</td>
+<td><input type=radio name=s value=1 onClick="updates(1);"
+  _If_(_cgiargs_, checked)>_textstem_<br>
+<input type=radio name=s value=0 onClick="updates(0);"
+  _If_(_cgiargs_,, checked)>_textnostem_</td>
+}
+
+_stemoption_ [l=zh] {}
+
+
+_modeoption_ {
+<td valign=baseline>_textquerymode_</td>
+<td><input type=radio name=b value=0 onClick="updateb(0);"
+		_If_(_cgiargb_,, checked)>_textsimplemode_<br>
+<input type=radio name=b value=1 onClick="updateb(1);"
+		_If_(_cgiargb_, checked)>_textadvancedmode_</td>
+}
+
+_formmodeoption_{
+<td valign=baseline>_textformtype_</td>
+<td><input type=radio name=qf value=0 onClick="updateqf(0);"
+		_If_(_cgiargf_,, checked)>_textsimple_<br>
+<input type=radio name=qf value=1 onClick="updateqf(1);"
+		_If_(_cgiargqf_, checked)>_textadvanced_</td>
+}
+
+_formnumfieldoption_ {<td></td><td>_textwith_
+<select name="fqn" onChange="updatefqn();">
+  <option value="2"_If_("_cgiargfqn_" eq "2", selected)>2  
+  <option value="4"_If_("_cgiargfqn_" eq "4", selected)>4
+  <option value="6"_If_("_cgiargfqn_" eq "6", selected)>6
+  <option value="8"_If_("_cgiargfqn_" eq "8", selected)>8
+</select>_textfields_</td>
+}
+
+_searchhistoryop_ {
+<td valign=baseline>_textsearchhistory_</td>
+<td><input type=radio name="hd" value=0 onClick="updatehd();"
+                _If_("_cgiarghd_" eq "0", checked)>_textnohistorydisplay_<br>
+<input type=radio name="hd" value=1 onClick="updatehd();"
+		_If_("_cgiarghd_" eq "0",, checked)>_texthistorydisplay_</td>   
+}
+
+_relateddocop_ {
+<td colspan=2><nobr><input type=checkbox name="rd" value=1 onClick="updaterd();" _If_("_cgiargrd_" eq "1", checked)>
+Display related documents</nobr></td>
+}
+
+_historynumrecords_{<select name="hdn" onChange="updatehd();">
+    <option value="5"_If_("_cgiarghd_" eq "5", selected)>5
+    <option value="10"_If_("_cgiarghd_" eq "10", selected)>10
+    <option value="15"_If_("_cgiarghd_" eq "15", selected)>15
+    <option value="20"_If_("_cgiarghd_" eq "20", selected)>20
+</select>}
+
+_maxdocoption_ {
+<select name="m" onChange="updatem();">
+  <option value="50"_If_("_cgiargm_" eq "50", selected)>50
+  <option value="100"_If_("_cgiargm_" eq "100", selected)>100
+  <option value="200"_If_("_cgiargm_" eq "200", selected)>200
+</select>
+}
+
+_hitsperpageoption_ {
+<select name="o" onChange="updateo();">
+  <option value="10"_If_("_cgiargo_" eq "10", selected)>10  
+  <option value="20"_If_("_cgiargo_" eq "20", selected)>20
+  <option value="50"_If_("_cgiargo_" eq "50", selected)>50
+  <option value="100")_If_("_cgiargo_" eq "100", selected)>_textall_
+</select>
+}
+
+_extlinkoption_ {
+<td>_textextlink_</td>
+<td><select name="el" onChange="updateel();">
+  <option value="prompt"_If_("_cgiargel_" eq "prompt", selected)>
+     _textlinkinterm_
+  <option value="direct"_If_("_cgiargel_" eq "direct", selected)>
+     _textlinkdirect_
+</select></td>
+}
+
+_intlinkoption_ {
+<td>_textintlink_</td>
+<td><select name="il" onChange="updateil();">
+  <option value="l"_If_("_cgiargil_" eq "l", selected)>
+     _textdigitlib_
+  <option value="w"_If_("_cgiargil_" eq "w", selected)>
+     _textweb_
+</select></td>
+}
+
+# set from within pageaction
+_languageoption_ {}
+_encodingoption_ {}
+
+_formatoption_ {
+<td>_textformat_</td>
+<td><select name="v" onChange="updatev();">
+  <option value="0"_If_("_cgiargv_" eq "0", selected)>_textgraphical_
+  <option value="1"_If_("_cgiargv_" eq "1", selected)>_texttextual_
+</select></td>
+}
+
+_content_ {
+<center>
+_optnavigationbar_
+</center>
+_If_(_prefschanged_,<p>_prefschanged_<br><center>_iconblankbar_</center>)
+
+<blockquote>
+
+<form name=PrefForm method=get action="_gwcgi_">
+
+<input type="hidden" name="e" value="_decodedcompressedoptions_">
+_If_(_collectionoption_,_collectionprefs_)
+_presentationprefs_
+_searchprefs_
+</blockquote>
+</form>
+}
+
+#search prefs 
+_searchprefs_ {
+<center><table border=0 cellpadding=0 cellspacing=0 width=_pagewidth_><tr>
+<td><h3>_textsearchprefs_</h3></td>
+<td align=right><input type=submit name="bp" value="_textsetprefs_"></td>
+</tr></table></center>
+
+<table>
+_querytypedependantoptions_
+
+<tr>_caseoption_</tr>
+
+<tr>_stemoption_</tr>
+
+<tr>_searchhistoryop_</tr>
+
+<!--
+Don't include this for now
+<tr>_relateddocop_</tr>
+-->
+
+<tr><td colspan=2>_textprefop_</td></tr>
+</table>
+</blockquote>
+_iconblankbar_
+<blockquote>
+}
+
+_querytypedependantoptions_ {
+_If_("_cgiargct_" eq "0", _plainqueryoptions_,_mgppqueryoptions_)
+}
+
+_mgppqueryoptions_{
+  _If_("_cgiargqto_" eq "1", _plainqueryoptions_)
+  _If_("_cgiargqto_" eq "2", _formqueryoptions_)
+  _If_("_cgiargqto_" eq "3", _dualqueryoptions_)
+}
+
+#query options for mg colls and mgpp colls with only plain searching
+_plainqueryoptions_ {
+<tr>_modeoption_</tr>
+
+<tr>_boxsizeoption_</tr>
+}
+
+#query options for mgpp colls with only form searching
+_formqueryoptions_ {
+<noscript><tr><td colspan=2><b>_query:textnojsformwarning_</b></td></tr></noscript>
+<tr>_formmodeoption_</tr>
+<tr>_formnumfieldoption_</tr>
+}
+
+#query options for mgpp colls with both types of search available
+_dualqueryoptions_ {
+<tr><td colspan=2><input type=radio name=qt value=0 onClick="updateqt(0);" _If_(_cgiargqt_,, checked)>_textplainsearch_</td></tr>
+<tr><td></td><td><table>_plainqueryoptions_</table></td></tr>
+<tr><td colspan=2><input type=radio name=qt value=1 onClick="updateqt(1);" _If_(_cgiargqt_,checked)>_textformsearch_</td></tr>
+<tr><td></td><td><table>_formqueryoptions_</table></td></tr>
+}
+
+_collectionprefs_ {
+<h3>_textcollectionprefs_</h3>
+_collectionoption_
+</blockquote>
+_iconblankbar_
+<blockquote>
+}
+
+_presentationprefs_ {
+<h3>_textpresentationprefs_</h3>
+<table>_htmloptions_
+
+_If_(_languageoption_,<tr><td>_textlanguage_</td><td>_languageoption_</td></tr>)
+
+_If_(_encodingoption_,<tr><td>_textencoding_</td><td>_encodingoption_</td></tr>)
+
+<tr>_formatoption_</tr></table>
+</blockquote>
+_iconblankbar_
+<blockquote>
+}
+
+
+#######################################################################
+# icons
+#######################################################################
+
+_iconthispage_ {<img src="_httpiconhpref_" alt="_textpreferences_" title="_textpreferences_" width="_widthhpref_" height="_heighthpref_">}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/query.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/query.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/query.dm	(revision 10506)
@@ -0,0 +1,723 @@
+# this file must be UTF-8 encoded
+package query
+
+
+#######################################################################
+# Macros whose values are set from within the server at runtime. These 
+# are here only for reference and to set default values if required.           
+#######################################################################
+
+_quotedquery_ {}
+_freqmsg_ {}
+_resultline_ {}
+_thisfirst_ {}
+_thislast_ {}
+_nextfirst_ {}
+_nextlast_ {}
+_prevfirst_ {}
+_prevlast_ {}
+_searchhistorylist_ {}
+#_histvalue0_ to _histvalue19_
+_advformlist_ {}
+_regformlist_ {}
+#_fqfselection_ {}
+
+
+#######################################################################
+# icons
+#######################################################################
+
+_iconthispage_ {<img src="_httpiconhsearch_" alt="_texticonthispage_" title="_texticonthispage_" width="_widthhsearch_" height="_heighthsearch_">}
+_iconthispage_ [v=1] {<h2>_texticonthispage_</h2>}
+
+_iconqueryresultsbar_ {<img src="_httpiconqryresb_" width="_widthqryresb_" height="_heightqryresb_" alt="_texticonqueryresultsbar_" title="_texticonqueryresultsbar_">}
+_iconqueryresultsbar_[v=1] {_texticonqueryresultsbar_}
+
+_iconsearchhistorybar_ {<img src="_httpiconsrchhistb_" width="_widthsrchhistb_" height="_heightsrchhistb_" alt="_texticonsearchhistorybar_" title="_texticonsearchhistorybar_">}
+_iconsearchhistorybar_[v=1] {_texticonsearchhistorybar_}
+
+# _iconnext_ and _iconprev_ are overridden in this package as we
+# don't want alt text here
+_iconnext_{<img src="_httpiconmore_" width=_widthmore_ height=_heightmore_ border=0 align=top>}
+_iconnext_ [v=1] {}
+_iconprev_{<img src="_httpiconless_" width=_widthless_ height=_heightless_ border=0 align=top>}
+_iconprev_ [v=1] {}
+
+# the small squares for search history
+## " " ## handmade ## mstds ##
+_httpiconmstdsqrof_ {_httpimg_/mstdsof.gif}
+_httpiconmstdsqron_ {_httpimg_/mstdson.gif}
+_widthmstdsqrx_ {13}
+_heightmstdsqrx_ {13}
+
+#######################################################################
+# images
+#######################################################################
+
+_imagethispage_ {_iconthispage_}
+
+#the buttons for the search history entries
+# takes one arg - the entry number (0-num entries)
+_imagehistbutton_ {<a  href="_httpquery_" onMouseover="roll('histbutton_1_',1);" onMouseOut="roll('histbutton_1_',0);" onClick="inputQuery(histvalue_1_); return false;"><img name="histbutton_1_" src="_httpiconmstdsqrof_" onLoad="gbutton(this,'_httpiconmstdsqron_');" border=0 alt="_textusequery_" title="_textusequery_"></a>}
+
+
+#######################################################################
+# scripts (and some macros for the scripts)
+#######################################################################
+
+_pagescriptextra_ {_If_("_cgiargqt_" eq "1", _formpagescriptextra_, _selectpagescriptextra_)
+_If_("_cgiarghd_" ne "0",_historypagescriptextra_) }
+
+_selectpagescriptextra_{_If_("_cgiargqto_" eq "2", _formpagescriptextra_,_dummypagescriptextra_)}
+_dummypagescriptextra_{
+function initialize() \{
+\}
+}
+_formpagescriptextra_ {
+// query scripts generated by \_query:pagescriptextra\_
+
+_standardfunctions_
+_formfunctions_
+_searchfunctions_
+
+function getsearchargs () \{
+
+  var args="";
+  args = "&fqa=0&fqv="+argfqv+"&fqf="+argfqf;
+  _If_(_cgiargqf_,args += "&fqk="+argfqk+"&fqs="+argfqs+"&fqc="+argfqc;)
+
+  return args;
+\}
+
+
+
+function getqueryargs () \{
+  return "&fqa=1"+"&q="+argq+"&fqv="+argfqv+"&fqf="+argfqf+
+	 "&fqk="+argfqk+"&fqs="+argfqs+"&fqc="+argfqc ;
+\}
+
+}
+
+_historypagescriptextra_{
+
+var histvalue0='_histvalue0_';
+var histvalue1='_histvalue1_';
+var histvalue2='_histvalue2_';
+var histvalue3='_histvalue3_';
+var histvalue4='_histvalue4_';
+var histvalue5='_histvalue5_';
+var histvalue6='_histvalue6_';
+var histvalue7='_histvalue7_';
+var histvalue8='_histvalue8_';
+var histvalue9='_histvalue9_';
+var histvalue10='_histvalue10_';
+var histvalue11='_histvalue11_';
+var histvalue12='_histvalue12_';
+var histvalue13='_histvalue13_';
+var histvalue14='_histvalue14_';
+var histvalue15='_histvalue15_';
+var histvalue16='_histvalue16_';
+var histvalue17='_histvalue17_';
+var histvalue18='_histvalue18_';
+var histvalue19='_histvalue19_';
+
+function inputQuery(value) \{
+  if ("_cgiargqt_" == "0") \{ // text search
+     document.QueryForm.q.value += " "+value;
+     document.QueryForm.q.focus();
+  \}
+  else \{
+     if ("_cgiargqf_" == "1") \{ // advanced query
+        document.QueryForm.q.value += " "+value;
+	document.QueryForm.q.focus();	   
+	updateq();
+     \}
+     else \{ // simple form search
+	  // do something here, what??
+     \}
+  \}
+\}
+
+}
+
+_standardfunctions_{
+
+ function getstdargs() \{
+    
+    stdarg = "";
+    _If_(_gselection_,_getgarg_)	
+    _If_(_jselection_,_getjarg_)
+    _If_(_nselection_,_getnarg_)
+
+    value = document.QueryForm.t.options[document.QueryForm.t.selectedIndex].value;
+    if (value != "_cgiargt_") stdarg += "&t="+value;
+
+    stdarg += "&r=1&hs=1";    
+    return stdarg;
+  \}
+
+}
+
+_getgarg_{
+    if (document.QueryForm.g!= null) \{
+    value = document.QueryForm.g.options[document.QueryForm.g.selectedIndex].value;
+    if (value != "_cgiargg_") stdarg += "&g="+value;
+  \}
+}
+
+_getjarg_{
+    value = document.QueryForm.j.options[document.QueryForm.j.selectedIndex].value;
+    if (value != "_cgiargj_") stdarg += "&j="+value;
+}
+
+_getnarg_{
+    value = document.QueryForm.n.options[document.QueryForm.n.selectedIndex].value;
+    if (value != "_cgiargn_") stdarg += "&n="+value;
+}
+
+_formfunctions_{
+
+argfqf="_cgiargfqf_";	
+argfqv="_cgiargfqv_";
+argfqk="_cgiargfqk_";
+argfqs="_cgiargfqs_";
+argfqc="_cgiargfqc_";
+argq = "";
+
+function initialize () \{
+
+   if (document.QueryForm.fqf != null) \{initfqf();\}
+   initfqv();
+   if ( "_cgiargqf_" == "1") \{
+      initfqs();	    
+      initfqk();
+      initfqc();
+      initq();
+   \}
+   
+\}
+
+// fqf - the field selection box
+function initfqf() \{
+   var i;
+   fqf = argfqf.split(",");
+   num_opts = document.QueryForm.fqf[0].options.length; // assumes all have the same  options   
+   for (i=0; i<fqf.length; i++) \{			
+       for (j=0;j<num_opts;j++) \{
+	   if (fqf[i] != "" && fqf[i]== document.QueryForm.fqf[i].options[j].value) \{
+	      document.QueryForm.fqf[i].options[j].selected = true;
+	      break;	
+	   \}
+	\}
+   \}
+   if (fqf.length < document.QueryForm.fqf.length) \{ // initialize remaining ones
+      for (i=fqf.length;i<document.QueryForm.fqf.length;i++) \{
+	  var z=i;
+	  while (z >= num_opts) \{
+	     z = z-(num_opts);
+	  \}
+	  document.QueryForm.fqf[i].options[z].selected = true;
+	  
+      \}
+   \}
+   updatefqf();
+
+\}
+
+function updatefqf() \{
+
+   var i;
+   argfqf = "";
+   var j = document.QueryForm.fqf[0].selectedIndex;
+   argfqf += document.QueryForm.fqf[0].options[j].value;
+   for (i=1; i<document.QueryForm.fqf.length;i++) \{
+      j = document.QueryForm.fqf[i].selectedIndex;
+      argfqf += "," + document.QueryForm.fqf[i].options[j].value;
+   \}
+
+\}
+
+
+function clearfqf() \{
+   var i;
+   for (i=0;i<document.QueryForm.fqf.length;i++) \{
+       var z = i;
+       if (i >= document.QueryForm.fqf[i].options.length) z = z-document.QueryForm.fqf[i].options.length;
+       document.QueryForm.fqf[i].options[z].selected = true;
+   \}
+   updatefqf();
+\}
+
+// fqc - the boolean operator selection box
+function initfqc() \{
+   var i,j;
+   fqc = argfqc.split(",");
+   if (_cgiargfqn_ == 2) \{ // there will only be one fqc element
+       for (j=0;j<document.QueryForm.fqc.options.length;j++) \{
+	   if (fqc[0] == document.QueryForm.fqc.options[j].value) \{
+	      document.QueryForm.fqc.options[j].selected = true;
+	      break;
+	   \}
+       \}   
+   \}
+   else \{   
+   for (i=0; i<fqc.length;i++) \{
+       for (j=0;j<document.QueryForm.fqc[i].options.length;j++) \{
+	   if (fqc[i] == document.QueryForm.fqc[i].options[j].value) \{
+	      document.QueryForm.fqc[i].options[j].selected = true;
+	      break;
+	   \}
+       \}
+   \}
+   \}
+   updatefqc();
+
+\}
+
+function updatefqc() \{
+  
+   var i,j;
+   argfqc = "";
+   if (_cgiargfqn_ == 2) \{
+      j = document.QueryForm.fqc.selectedIndex;
+      argfqc += document.QueryForm.fqc.options[j].value;
+   \}
+   else \{
+	j = document.QueryForm.fqc[0].selectedIndex;
+	argfqc += document.QueryForm.fqc[0].options[j].value;
+	for (i=1;i<document.QueryForm.fqc.length;i++) \{
+	    j = document.QueryForm.fqc[i].selectedIndex;
+	    argfqc += "," + document.QueryForm.fqc[i].options[j].value;
+	\}
+   \}
+
+\}
+
+
+function clearfqc() \{
+   
+   var i;
+   if (_cgiargfqn_ == 2) \{
+       document.QueryForm.fqc.options[0].selected = true;
+   \}
+   else \{
+	for (i=0; i<document.QueryForm.fqc.length; i++) \{
+	    document.QueryForm.fqc[i].options[0].selected = true;
+	\}
+   \}
+   updatefqc();
+\}
+
+// fqv - the query word/phrase text box       
+function initfqv() \{
+
+   var i;
+   fqv= argfqv.split(",");
+   for (i=0; i<fqv.length; i++) \{
+       document.QueryForm.fqv[i].value = fqv[i];
+   \}
+   updatefqv();
+
+
+\}
+
+   //argfqv += escape(format(document.QueryForm.fqv[0].value));
+
+function updatefqv() \{
+
+   var i;
+   argfqv="";
+   argfqv += format(document.QueryForm.fqv[0].value);
+   for (i=1; i<document.QueryForm.fqv.length;i++) \{
+       argfqv += ",";
+       argfqv +=  format(document.QueryForm.fqv[i].value); 
+   \}
+\}
+
+function clearfqv() \{
+   var i;
+   for (i=0; i< document.QueryForm.fqv.length;i++) \{
+       document.QueryForm.fqv[i].value = "";
+   \}
+   updatefqv();
+\}
+
+// fqs - the stemming checkboxes
+function initfqs() \{
+
+   var i;
+   fqs = argfqs.split(",");
+   for (i=0; i<fqs.length; i++) \{
+       if (fqs[i]=="1") \{
+	  document.QueryForm.fqs[i].checked = true;
+       \}
+   \}
+   updatefqs();
+
+\}
+
+function updatefqs() \{
+   argfqs="";
+   if (document.QueryForm.fqs[0].checked) \{
+      argfqs += "1";
+   \}
+   else \{
+      argfqs += "0";	
+   \}
+   var i;
+   for (i=1; i<document.QueryForm.fqs.length; i++) \{
+       if (document.QueryForm.fqs[i].checked) \{
+	  argfqs += ",1";
+	\}
+	else \{
+	  argfqs += ",0";
+	\}
+   \}
+\}
+
+
+function clearfqs() \{
+   var i;
+   for (i=0; i<document.QueryForm.fqs.length; i++) \{
+       document.QueryForm.fqs[i].checked = false;
+   \}
+   updatefqs();
+\}
+
+// kqk - the casefolding checkboxes
+function initfqk() \{
+   var i;
+   fqk = argfqk.split(",");
+   for (i=0; i<fqk.length; i++) \{
+       if (fqk[i]=="1") \{
+	  document.QueryForm.fqk[i].checked = true;
+       \}
+   \}
+   updatefqk();
+
+\}
+
+
+function updatefqk() \{
+   argfqk="";
+   if (document.QueryForm.fqk[0].checked) \{
+      argfqk += "1";
+   \}
+   else \{
+      argfqk += "0";	
+   \}
+   var i;
+   for (i=1; i<document.QueryForm.fqk.length; i++) \{
+       if (document.QueryForm.fqk[i].checked) \{
+	  argfqk += ",1";
+	\}
+	else \{
+	  argfqk += ",0";
+	\}
+   \}
+\}
+
+function clearfqk() \{
+   var i;
+   for (i=0; i<document.QueryForm.fqk.length; i++) \{
+       document.QueryForm.fqk[i].checked = false;
+   \}
+   updatefqk();
+\}
+
+// q - the advanced query box
+function initq() \{
+   updateq();
+\}
+
+function updateq() \{
+   argq = "";
+   argq += format(document.QueryForm.q.value);
+\}
+
+function clearq() \{
+   document.QueryForm.q.value="";
+\}
+
+
+// convert commas and spaces to plus
+// also convert other illegal characters to %xx codes
+function format(string) \{
+   var str = "" + string;
+   var out = "", flag = 0;
+   var ch = "";
+   var j;
+   for (j = 0; j < str.length; j++) \{
+       ch=str.charAt(j);
+       if (ch == " "|| ch == ",") \{
+           if ( flag == 0) \{     
+	      out += "+";
+	      flag=1;
+	    \}
+	    continue;
+	\}
+	if (ch == ";" || ch == ":" || ch == "/" || ch == "?" ||
+            ch == "@" || ch == "&" || ch == "=" || ch == "#") \{
+	    out += escape(ch);
+	    flag=0;
+	    continue;
+	 \}	      
+	out += str.charAt(j);
+	flag=0;
+   \}
+   return out;
+\}
+
+}
+
+#_httpquery_ has a=q&e=compressedargs
+#if adv form, need to set k=0 and s=0
+_advformargs_{_If_(_cgiargqf_,&k=0&s=0)}
+
+_searchfunctions_ {
+
+function beginSearch() \{
+window.location="_httpquery_"+getstdargs()+"_advformargs_"+getsearchargs();
+\}
+
+function runQuery() \{
+window.location="_httpquery_"+getstdargs()+"_advformargs_"+getqueryargs();
+\}
+
+function clearForm() \{
+   clearfqf();
+   clearfqv();
+
+   if ("_cgiargqf_" == "1") \{
+      clearfqk();
+      clearfqs();
+      clearfqc();
+   \}
+
+\}
+
+}
+
+#######################################################################
+# headers
+# these are overridden so we can put an onLoad event handler
+# in the <body> tag of this page - for mgpp, form search pages
+#######################################################################
+
+#copied from prefs 
+
+_header_ {_cgihead_
+_htmlhead_(background="_httpiconchalk_" onLoad="initialize();")_startspacer__pagebanner_
+}
+
+# this declaration ends up being the same as style=restrict, never mind
+_header_[v=1] {_cgihead_
+_htmlhead_(onLoad="initialize();")_pagebanner_
+}
+
+#######################################################################
+# page content
+#######################################################################
+
+
+_pagetitle_ {_If_(_cgiargq_,_textquerytitle_,_textnoquerytitle_)}
+
+
+_content_ {
+<center>
+_optnavigationbar_
+</center>
+<center>
+_If_(_cgiargct_,_selectqueryform_,_queryform_)
+</center>
+_If_(_searchhistorylist_,<center>_iconsearchhistorybar_</center><br>
+<center>
+_searchhistorylist_
+</center>)
+_If_(_cgiargq_,<center>_iconqueryresultsbar_</center><br>
+<small>
+_freqmsg_
+_textpostprocess_</small><br>
+_resultline_
+,<center>_iconblankbar_</center>)<br>
+}
+
+_selectqueryform_{_If_("_cgiargqt_" eq "1",_fieldqueryform_,_selectqueryform2_)}
+_selectqueryform2_{_If_("_cgiargqto_" eq "2", _fieldqueryform_, _queryform_)}
+
+_queryform_ {
+<!-- query form (\_query:plainqueryform\_) -->
+<form name=QueryForm method=get action="_gwcgi_">
+<input type=hidden name="a" value="q">
+<input type=hidden name="r" value="1">
+<input type=hidden name="hs" value="1">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+_queryformcontent_
+_optdatesearch_
+
+</form>
+<!-- end of query form -->
+}
+
+_ifeellucky_ { <br><input type=checkbox name="ifl">_textifeellucky_ }
+_useifeellucky_ { }  # Set this to _ifeellucky_ if you want this functionality available
+
+_queryformcontent_{<table><tr><td>
+<nobr>_textselect_</nobr>
+</td></tr>
+<tr><td>
+_If_(_cgiargqb_,_largequerybox_,_smallquerybox_)
+_useifeellucky_
+</td></tr></table>
+}
+
+# Automatically set by receptionist if config file switches
+# date searching on
+_optdatesearch_ { } 
+
+
+_datesearch_
+{<table><tr><td>
+	<center>
+_textstartdate_
+<input type="text" name="ds" value = "_cgiargds_" size="4" maxlength="4">
+<select name="dsbc" value="_cgiargdsbc_" size="1">
+	<option value = "0"_If_(_cgiargdsbc_,, selected)>_textad_
+	<option value = "1"_If_(_cgiargdsbc_, selected)>_textbc_
+</select> 
+_textenddate_
+<input type="text" name="de" value = "_cgiargde_" size="4" maxlength="4"> 
+<select name="debc" size="1">
+	<option value = "0" _If_(_cgiargdebc_,, selected)>_textad_
+	<option value = "1" _If_(_cgiargdebc_, selected)>_textbc_
+</select> 
+</center>	  
+</tr></td>
+<tr><td>
+_textexplaineras_
+</tr></td>
+</table>
+</center>
+}
+
+_smallquerybox_ {<tr><td><nobr><input type="text" name="q" value="_cgiargq_" size="50">
+<input type="submit" value="_textbeginsearch_"></nobr>}
+
+_largequerybox_ {
+<tr><td><textarea name="q" cols=63 rows=10>
+_cgiargq_
+</textarea></td></tr>
+<tr align=right><td><table>
+<tr><td><input type="submit" value="_textbeginsearch_"></td>
+</tr></table></td></tr>}
+
+
+_fieldqueryform_ {
+<noscript>
+<p><b>_textnojsformwarning_</b><p>
+</noscript>
+<!-- field query form (\_query:fieldqueryform\_) -->
+<form name=QueryForm method=get action="_gwcgi_">
+
+<table><tr><td>
+<nobr>
+_textformselect_
+</nobr>
+</td></tr>
+_If_(_cgiargqf_,_advancedforms_,_simpleforms_)
+</table>
+_If_(_cgiargqf_,<center>_iconblankbar_</center><br>
+<center>_advancedformextra_</center>)
+
+</form>
+<!-- end of query form -->
+}
+
+_advancedforms_{
+<tr><td><center> <table border=0 cellspacing=0 cellpadding=0 width="90%">
+<tr><th></th><th align=left>_textwordphrase_</th><th colspan=2><nobr>_textfoldstem_</nobr></th><th align=center>&nbsp;&nbsp;_textinfield_</th></tr>	
+_advformlist_
+<tr><td colspan=2><input type=button value="_textclearform_" onClick="clearForm();"></td>
+<td colspan=3><table>
+<tr><td><input type=button value="_textbeginsearch_" onClick="beginSearch();"></td>
+</tr></table></td></tr>
+</table></td></tr>
+}
+
+_advancedformextra_{
+<table>
+<tr><td>_textadvquery_</td></tr>
+<tr><td><textarea name=q cols=57 rows=3 onChange="updateq();">_cgiargq_</textarea></td>
+<td valign=bottom>
+<input type="button" value="_textrunquery_" onClick="runQuery();"></td></tr>
+</table>
+}
+
+_simpleforms_{
+<tr><td><center> <table border=0 cellspacing=0 cellpadding=0 width="90%">
+<tr><th align=left>_textwordphrase_</th><th align=left>&nbsp;&nbsp;_textinfield_</th></tr>	
+_regformlist_
+<tr><td><input type=button value="_textclearform_" onClick="clearForm();"></td>
+<td><table>
+<tr><td><input type=button value="_textbeginsearch_" onClick="beginSearch();"></td>
+</tr>
+</table></td></tr>
+</table></td></tr>}
+
+_regformelement_{
+<td><input type=text size=39 name="fqv" onChange="updatefqv();"></td>
+<td>_fqfselection_</td>}
+
+#has no and/or/not selection box
+_firstadvformelement_{
+<td></td><td><input type=text size=31 name="fqv" onChange="updatefqv();"></td>
+<td align=center><input type=checkbox name="fqk" onClick="updatefqk();"></td>
+<td align-center><input type=checkbox name="fqs" onClick="updatefqs();"></td>
+<td align=right>_fqfselection_</td>}
+
+_advformelement_{
+<td>_fqcselection_</td>
+<td><input type=text size=31 name="fqv" onChange="updatefqv();"></td>
+<td align=center><input type=checkbox name="fqk" onClick="updatefqk();"></td>
+<td align-center><input type=checkbox name="fqs" onClick="updatefqs();"></td>
+<td align=right>_fqfselection_</td>}
+
+_fqcselection_ {
+<select name="fqc" onChange="updatefqc();">
+<option value="and">_textand_
+<option value="or">_textor_
+<option value="not">_textandnot_
+</select>}
+
+_textselect_ {_If_(_cgiargb_,_textadvancedsearch_,_textsimplesearch_)}
+_textformselect_ {_If_(_cgiargqf_,_textformadvancedsearch_,_textformsimplesearch_)}
+# mg uses hselection for index, mgpp uses fqfselection 
+_indexselection_{_If_(_cgiargct_,_fqfselection_,_hselection_)}
+
+# we want to put the links to previous/next pages of results
+# in the footer
+_pagefooterextra_ {
+<center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr>
+<td align=left>_If_(_prevfirst_,<a href="_httpquery_&r=_prevfirst_">_iconprev__textmatches__prevfirst_ - _prevlast_</a>)</td>
+<td align=right>_If_(_nextfirst_,<a href="_httpquery_&r=_nextfirst_">_textmatches__nextfirst_ - _nextlast__iconnext_</a>)</td>
+</tr></table>
+</center>
+}
+
+_querytypeselection_ {
+<select name="t">
+<option value="1"_If_(_cgiargt_, selected)>_If_(_cgiargb_,_textranked_,_textsome_)
+<option value="0"_If_(_cgiargt_,, selected)>_If_(_cgiargb_,_textboolean_,_textall_)
+</select>
+}
+
+_formquerytypeselection_ {
+<select name="t">
+<option value="1"_If_(_cgiargt_, selected)>_If_(_cgiargqf_,_textranked_,_textsome_)
+<option value="0"_If_(_cgiargt_,, selected)>_If_(_cgiargqf_,_textnatural_,_textall_)
+</select>
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/macros/russian.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/russian.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/russian.dm	(revision 10506)
@@ -0,0 +1,1304 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Russian Language text and icon macros 
+# Translated by UNESCO for the UNESCO CD-ROMs
+# Contributions made by Doug Carter
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=ru] {ÐÐµÑÐžÐŸÐŽÐžÐºÐ°}
+_textsource_ [l=ru] {ÐÑÑÐŸÑÐœÐžÐº: }
+_textdate_ [l=ru] {ÐÐ°ÑÐ° Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž: }
+_textnumpages_ [l=ru] {ÐÐŸÐŒÐµÑ ÑÑÑÐ°ÐœÐžÑÑ}
+
+_textsignin_ [l=ru] {ÐÐ²ÑÐŸÑÐžÐ·ÐŸÐ²Ð°ÐœÐœÑÐ¹ Ð²Ñ
+ÐŸÐŽ}
+
+_textdefaultcontent_ [l=ru] {ÐÐ°Ð¿ÑÐ°ÑÐžÐ²Ð°ÐµÐŒÐ°Ñ ÑÑÑÐ°ÐœÐžÑÐ° ÐœÐµ ÐœÐ°Ð¹ÐŽÐµÐœÐ°. ÐÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ° ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐºÐœÐŸÐ¿ÐºÑ 'ÐÐ°Ð·Ð°ÐŽ' Ð² Ð²Ð°ÑÐµÐŒ Ð±ÑÐ°ÑÐ·ÐµÑÐµ ÐžÐ»Ðž ÑÑÑÐ»ÐºÑ ÐœÐ° ÐŽÐŸÐŒÐ°ÑÐœÑÑ ÑÑÑÐ°ÐœÐžÑÑ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž.}
+
+_textdefaulttitle_ [l=ru] {ÐÑÐžÐ±ÐºÐ° ÐÑÐžÐœÑÑÐŸÑÐœ}
+
+_textbadcollection_ [l=ru] {Ð­ÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ (Ñ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµÐŒ "_cvariable _") ÐœÐµ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐ° Ð² ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐµ ÐÑÐžÐœÑÑÐŸÑÐœ.}
+
+_textselectpage_ [l=ru] {'ÐÑÐ±ÑÐ°ÑÑ ÑÑÑÐ°ÐœÐžÑÑ'}
+
+_collectionextra_ [l=ru] {ÐÐ°ÐœÐœÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÐŸÐŽÐµÑÐ¶ÐžÑ _about:numdocs_ ÐŽÐŸÐºÑÐŒÐµÐœÑ/ÐŸÐ². 
+ÐÐŸÑÐ»ÐµÐŽÐœÐžÐµ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ Ð±ÑÐ»Ðž Ð¿ÑÐŸÐžÐ·Ð²ÐµÐŽÐµÐœÑ _about:builddate_ ÐŽÐœÐµÐ¹ ÐœÐ°Ð·Ð°ÐŽ.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=ru] {<p>Ð­ÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÐŸÐŽÐµÑÐ¶ÐžÑ _numdocs_ If_(â_numdocs_â eq â1â, ÐŽÐŸÐºÑÐŒÐµÐœÑ, ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²), Ð²ÑÐµÐ³ÐŸ _numbytes_. 
+<p><a href=â_httppagex_(bsummary)â>ÐÐ°Ð¶ÐŒÐžÑÐµ ÑÑÐŽÐ°<\a> ÑÑÐŸÐ±Ñ Ð²ÐžÐŽÐµÑÑ ÐŸÑÑÐµÑ ÐŸ Ð¿ÑÐŸÑÐµÑÑÐµ ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.}
+
+_textimagecollection_ [l=ru] {}
+_textimageabout_ [l=ru] {Ð Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐµ}
+_textimagehome_ [l=ru] {ÐÐŸÐŒÐ°ÑÐœÑÑ ÑÑÑÐ°ÐœÐžÑÐ°}
+_textimagehelp_ [l=ru] {Ð¡ÑÑÐ°ÐœÐžÑÐ° Ð¿ÐŸÐŒÐŸÑÐž}
+_textimagepref_ [l=ru] {ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž}
+_textimagegreenstone_ [l=ru] {Ð­Ð»ÐµÐºÑÑÐŸÐœÐœÐ°Ñ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ° ÐÑÐžÐœÑÑÐŸÑÐœ}
+_textimageusab_ [l=ru] {ÐÐ°ÐºÐžÐµ Ð²ÐŸÐ·ÐœÐžÐºÐ»Ðž ÑÑÑÐŽÐœÐŸÑÑÐž Ð² ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐž?}
+
+_textimagesearch_ [l=ru] {ÐÐŸÐžÑÐº}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑÐŒ}
+_textimageCreator_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð°Ð²ÑÐŸÑÐ°ÐŒ}
+_textimageSubject_ [l=ru] {ÐÑÐµÐŽÐŒÐµÑÐœÑÐ¹ ÑÐºÐ°Ð·Ð°ÑÐµÐ»Ñ}
+_textimageDescription_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ }
+_textimagePublisher_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÐžÐ·ÐŽÐ°ÑÐµÐ»ÑÐŒ}
+_textimageContributor_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ Ð²ÐºÐ»Ð°ÐŽÑ }
+_textimageDate_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐŽÐ°ÑÐ°ÐŒ}
+_textimageType_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÑÐžÐ¿Ñ ÑÐµÑÑÑÑÐŸÐ²}
+_textimageFormat_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÑÐŸÑÐŒÐ°ÑÑ }
+_textimageIdentifier_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÑÐž Ð¿ÐŸÐŒÐŸÑÐž ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° ÑÐµÑÑÑÑÐŸÐ² }
+_textimageSource_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÐŸÑÐžÐ³ÐžÐœÐ°Ð»ÑÐœÐŸÐŒÑ ÐžÐŒÐµÐœÐž ÑÐ°Ð¹Ð»Ð°}
+_textimageLanguage_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐ·ÑÐºÐ°ÐŒ}
+_textimageRelation_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÑÐ²ÑÐ·ÑÐŒ}
+_textimageCoverage_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÐŸÑ
+Ð²Ð°ÑÑ }
+_textimageRights_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ Ð¿ÑÐ°Ð²Ð°ÐŒ}
+
+_textimageOrganization_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑÐŒ}
+_textimageKeyword_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÐºÐ»ÑÑÐµÐ²ÑÐŒ ÑÐ»ÐŸÐ²Ð°ÐŒ}
+_textimageHowto_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐ¿ÐŸÑÐŸÐ±Ð°ÐŒ Ð¿ÑÐžÐŒÐµÐœÐµÐœÐžÑ}
+_textimageList_ [l=ru] {ÐÐ±ÑÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²}
+_textimageSeries_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð²ÑÐ¿ÑÑÐºÐ°ÐŒ}
+_textimageTo_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð°ÐŽÑÐµÑÐ°ÑÐ°ÐŒ}
+_textimageFrom_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐŸÑÐ¿ÑÐ°Ð²ÐžÑÐµÐ»ÑÐŒ}
+_textimageTopic_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐµÐŒÐ°ÐŒ}
+_textimageBrowse_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ}
+_textimageCollage_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÐºÐŸÐ»Ð»Ð°Ð¶Ð°ÐŒ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐ¹}
+_textimagePeople_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÑÐŒ}
+_textimageAcronym_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð°ÐºÑÐŸÐœÐžÐŒÐ°ÐŒ}
+_textimagePhrase_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÑÐ°Ð·Ð°ÐŒ}
+_textimageArtist_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÑÐŸÐ·ÐŽÐ°ÑÐµÐ»ÑÐŒ/ÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐŒ}
+_textimageVolume_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÐžÐ·ÐŽÐ°ÐœÐžÑ}
+_textimageCountries_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð¿ÐŸ ÑÑÑÐ°ÐœÐ°ÐŒ}
+_textimageCaptions_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐŸÐ² ÑÐŸÑÐŸÐ³ÑÐ°ÑÐžÐ¹}
+
+
+_texticontabsearchgreen_ [l=ru] {ÐÐŸÐžÑÐº}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=ru] {ÐÐ°Ð·Ð²Ð°ÐœÐžÑ Ð-Ð¯}
+_texticontabCreatorgreen_ [l=ru] {ÐÐ²ÑÐŸÑÑ Ð-Ð¯}
+_texticontabSubjectgreen_ [l=ru] {Ð£ÐºÐ°Ð·Ð°ÑÐµÐ»Ñ}
+_texticontabDescriptiongreen_ [l=ru] {ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ}
+_texticontabPublishergreen_ [l=ru] {ÐÐ·ÐŽÐ°ÑÐµÐ»Ðž }
+_texticontabContributorgreen_ [l=ru] {Ð£ÑÐ°ÑÑÐœÐžÐºÐž}
+_texticontabDategreen_ [l=ru] {ÐÐ°ÑÑ}
+_texticontabTypesgreen_ [l=ru] {Ð¢ÐžÐ¿Ñ}
+_texticontabFormatgreen_ [l=ru] {ÑÐŸÑÐŒÐ°ÑÑ}
+_texticontabIdentifiergreen_ [l=ru] {ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÑ}
+_texticontabSourcegreen_ [l=ru] {ÐÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÐŸÐ²}
+_texticontabLanguagegreen_ [l=ru] {Ð¯Ð·ÑÐºÐž}
+_texticontabRelationgreen_ [l=ru] {Ð¡Ð²ÑÐ·Ðž}
+_texticontabCoveragegreen_ [l=ru] {ÐÑ
+Ð²Ð°Ñ}
+_texticontabRightsgreen_ [l=ru] {ÐÑÐ°Ð²Ð°}
+
+_texticontaborggreen_ [l=ru] {ÐÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÐž}
+_texticontabKeywordgreen_ [l=ru] {ÐÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð°}
+_texticontabhowgreen_ [l=ru] {Ð¡Ð¿ÐŸÑÐŸÐ±Ñ}
+_texticontabseriesgreen_ [l=ru] {ÐÑÐ¿ÑÑÐºÐž}
+_texticontablistgreen_ [l=ru] {Ð¡Ð¿ÐžÑÐŸÐº}
+_texticontabtogreen_ [l=ru] {ÐÐŸÐŒÑ}
+_texticontabfromgreen_ [l=ru] {ÐÑ ÐºÐŸÐ³ÐŸ}
+_texticontabtopicgreen_ [l=ru] {Ð¢ÐµÐŒÑ}
+_texticontabbrwsegreen_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ}
+_texticontabCollagegreen_ [l=ru] {ÐÐŸÐ»Ð»Ð°Ð¶}
+_texticontabbrowsgreen_ [l=ru] {ÐÑÐŸÑÐŒÐ°ÑÑÐžÐ²Ð°ÑÑ}
+_texticontabPeoplegreen_ [l=ru] {ÐÐµÑÑÐŸÐœÐ°Ð»ÐžÐž Ð-Ð¯}
+_texticontabAcronymgreen_ [l=ru] {ÐÐºÑÐŸÐœÐžÐŒÑ}
+_texticontabPhrasegreen_ [l=ru] {Ð€ÑÐ°Ð·Ñ}
+_texticontabArtistgreen_ [l=ru] {Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ/ÐÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ}
+_texticontabVolumegreen_ [l=ru] {ÐÐ·ÐŽÐ°ÐœÐžÑ}
+_texticontabCaptionsgreen_ [l=ru] {ÐÐ°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž}
+_texticontabCountriesgreen_ [l=ru] {Ð¡ÑÑÐ°ÐœÑ}
+
+_texticontext_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°}
+_texticonclosedbook_ [l=ru] {ÐÑÐºÑÑÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑ Ðž Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ}
+_texticonnext_ [l=ru] {Ð¡Ð»ÐµÐŽÑÑÑÐ°Ñ}
+_texticonprev_ [l=ru] {ÐÑÐµÐŽÑÐŽÑÑÐ°Ñ}
+
+_texticonworld_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑÐµÑÑ Ð²ÐµÐ±-ÑÑÑÐ°ÐœÐžÑÑ}
+
+_texticonmidi_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° MIDI}
+_texticonmsword_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° Microsoft Word}
+_texticonmp3_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° MP3}
+_texticonpdf_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÐÐºÑÐŸÐ±Ð°Ñ PDF}
+_texticonps_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° PS}
+_texticonppt_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° Ð¿ÑÐµÐ·ÐµÐœÑÐ°ÑÐžÐž PPT}
+_texticonrtf_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° RTF}
+_texticonxls_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° XLS}
+
+_page_ [l=ru] {Ð¡ÑÑÐ°ÐœÐžÑÐ°}
+_pages_ [l=ru] {Ð¡ÑÑÐ°ÐœÐžÑÑ}
+_of_ [l=ru] {ÐžÐ· }
+_vol_ [l=ru] {Ð¢ÐŸÐŒ}
+_num_ [l=ru] {ÐÐŸÐŒÐµÑ}
+
+_textmonth00_ [l=ru] {}
+_textmonth01_ [l=ru] {Ð¯ÐœÐ²Ð°ÑÑ}
+_textmonth02_ [l=ru] {Ð€ÐµÐ²ÑÐ°Ð»Ñ}
+_textmonth03_ [l=ru] {ÐÐ°ÑÑ}
+_textmonth04_ [l=ru] {ÐÐ¿ÑÐµÐ»Ñ}
+_textmonth05_ [l=ru] {ÐÐ°Ð¹}
+_textmonth06_ [l=ru] {ÐÑÐœÑ}
+_textmonth07_ [l=ru] {ÐÑÐ»Ñ}
+_textmonth08_ [l=ru] {ÐÐ²Ð³ÑÑÑ}
+_textmonth09_ [l=ru] {Ð¡ÐµÐœÑÑÐ±ÑÑ}
+_textmonth10_ [l=ru] {ÐÐºÑÑÐ±ÑÑ}
+_textmonth11_ [l=ru] {ÐÐŸÑÐ±ÑÑ}
+_textmonth12_ [l=ru] {ÐÐµÐºÐ°Ð±ÑÑ}
+
+_textdocument_ [l=ru] {ÐÐŸÐºÑÐŒÐµÐœÑ}
+_textsection_ [l=ru] {Ð¡ÐµÐºÑÐžÑ}
+_textparagraph_ [l=ru] {ÐÐ±Ð·Ð°Ñ}
+
+_magazines_ [l=ru] {ÐÑÑÐœÐ°Ð»Ñ}
+
+_nzdlpagefooter_ [l=ru] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">ÐÐŸÐ²ÐŸÐ·ÐµÐ»Ð°ÐœÐŽÑÐºÐžÐ¹ Ð¿ÑÐŸÐµÐºÑ ÐŠÐžÑÑÐŸÐ²ÐŸÐ¹ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">ÐÑÐŽÐµÐ» ÐºÐŸÐ¿ÑÑÑÐµÑÐœÑÑ
+ ÐœÐ°ÑÐº</a>, 
+<a href="http://www.waikato.ac.nz">Ð£ÐœÐžÐ²ÐµÑÑÐžÑÐµÑ ÐÐ°Ð¹ÐºÐ°ÑÐŸ</a>, 
+ÐÐŸÐ²Ð°Ñ ÐÐµÐ»Ð°ÐœÐŽÐžÑ}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐÐÐ§ÐÐÐ" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=ru] {_httpimg_/ru/chomeof.gif}
+_httpiconchomeon_ [l=ru] {_httpimg_/ru/chomeon.gif}
+
+## "ÐÐÐÐÐ©Ð¬" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=ru] {_httpimg_/ru/chelpof.gif}
+_httpiconchelpon_ [l=ru] {_httpimg_/ru/chelpon.gif}
+
+## "ÐÐÐ¡Ð¢Ð ÐÐÐÐ" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=ru] {_httpimg_/ru/cprefof.gif}
+_httpiconcprefon_ [l=ru] {_httpimg_/ru/cprefon.gif}
+
+## "ÐÐ¡ÐÐÐÐ¬ÐÐÐÐÐ¢Ð¬ ÐÐÐ ÐÐ¢ÐÐ£Ð® Ð¡ÐÐ¯ÐÐ¬" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=ru] {_httpimg_/ru/cusabof.gif}
+_httpiconcusabon_ [l=ru] {_httpimg_/ru/cusabon.gif}
+
+
+## "Ð¿ÐŸÐžÑÐº" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=ru] {_httpimg_/ru/tsrchgr.gif}
+_httpicontsrchof_ [l=ru] {_httpimg_/ru/tsrchof.gif}
+_httpicontsrchon_ [l=ru] {_httpimg_/ru/tsrchon.gif}
+_widthtsrchx_ [l=ru] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ Ð°-Ñ" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=ru] {_httpimg_/ru/ttitlgr.gif}
+_httpiconttitleof_ [l=ru] {_httpimg_/ru/ttitlof.gif}
+_httpiconttitleon_ [l=ru] {_httpimg_/ru/ttitlon.gif}
+_widthttitlex_ [l=ru] {87}
+
+# Not true DC, kept for legacy reasons
+## "Ð°Ð²ÑÐŸÑÑ Ð°-Ñ" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=ru] {_httpimg_/ru/tauthgr.gif}
+_httpicontcreatof_ [l=ru] {_httpimg_/ru/tauthof.gif}
+_httpicontcreaton_ [l=ru] {_httpimg_/ru/tauthon.gif}
+_widthtcreatx_ [l=ru] {87}
+
+## "ÑÐºÐ°Ð·Ð°ÑÐµÐ»Ñ" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=ru] {_httpimg_/ru/tsubjgr.gif}
+_httpicontsubjon_ [l=ru] {_httpimg_/ru/tsubjon.gif}
+_httpicontsubjof_ [l=ru] {_httpimg_/ru/tsubjof.gif}
+_widthtsubjx_ [l=ru] {87}
+
+## "ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ" ## nav_bar_button ## tdesc ##
+_httpicontdescgr_ [l=ru] {_httpimg_/ru/tdescgr.gif}
+_httpicontdescon_ [l=ru] {_httpimg_/ru/tdescon.gif}
+_httpicontdescof_ [l=ru] {_httpimg_/ru/tdescof.gif}
+_widthtdescx_ [l=ru] {90}
+
+## "ÐžÐ·ÐŽÐ°ÑÐµÐ»Ðž" ## nav_bar_button ## tpubl ##
+_httpicontpublgr_ [l=ru] {_httpimg_/ru/tpublgr.gif}
+_httpicontpublon_ [l=ru] {_httpimg_/ru/tpublon.gif}
+_httpicontpublof_ [l=ru] {_httpimg_/ru/tpublof.gif}
+_widthtpublx_ [l=ru] {87}
+
+## "ÑÑÐ°ÑÑÐœÐžÐºÐž" ## nav_bar_button ## tcontr ##
+_httpicontcontrgr_ [l=ru] {_httpimg_/ru/tcontrgr.gif}
+_httpicontcontron_ [l=ru] {_httpimg_/ru/tcontron.gif}
+_httpicontcontrof_ [l=ru] {_httpimg_/ru/tcontrof.gif}
+_widthtcontrx_ [l=ru] {89}
+
+## "ÐŽÐ°ÑÑ" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=ru] {_httpimg_/ru/tdategr.gif}
+_httpicontdateof_ [l=ru] {_httpimg_/ru/tdateof.gif}
+_httpicontdateon_ [l=ru] {_httpimg_/ru/tdateon.gif}
+_widthtdatex_ [l=ru] {87}
+
+## "ÑÐžÐ¿Ñ" ## nav_bar_button ## ttype ##
+_httpiconttypegr_ [l=ru] {_httpimg_/ru/ttypegr.gif}
+_httpiconttypeof_ [l=ru] {_httpimg_/ru/ttypeof.gif}
+_httpiconttypeon_ [l=ru] {_httpimg_/ru/ttypeon.gif}
+_widthttypex_ [l=ru] {87}
+
+## "ÑÐŸÑÐŒÐ°ÑÑ" ## nav_bar_button ## tform ##
+_httpicontformgr_ [l=ru] {_httpimg_/ru/tformgr.gif}
+_httpicontformof_ [l=ru] {_httpimg_/ru/tformof.gif}
+_httpicontformon_ [l=ru] {_httpimg_/ru/tformon.gif}
+_widthtformx_ [l=ru] {87}
+
+## "ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÑ" ## nav_bar_button ## tident ##
+_httpicontidentgr_ [l=ru] {_httpimg_/ru/tidentgr.gif}
+_httpicontidentof_ [l=ru] {_httpimg_/ru/tidentof.gif}
+_httpicontidenton_ [l=ru] {_httpimg_/ru/tidenton.gif}
+_widthtidentx_ [l=ru] {87}
+
+# Not true DC, kept for legacy reasons
+## "ÐžÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÐŸÐ²" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=ru] {_httpimg_/ru/tsrcgr.gif}
+_httpicontsrcof_ [l=ru] {_httpimg_/ru/tsrcof.gif}
+_httpicontsrcon_ [l=ru] {_httpimg_/ru/tsrcon.gif}
+_widthtsrcx_ [l=ru] {87}
+
+## "ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=ru] {_httpimg_/ru/tlanggr.gif}
+_httpicontlangon_ [l=ru] {_httpimg_/ru/tlangon.gif}
+_httpicontlangof_ [l=ru] {_httpimg_/ru/tlangof.gif}
+_widthtlangx_ [l=ru] {87}
+
+## "ÑÐ²ÑÐ·Ðž" ## nav_bar_button ## trel ##
+_httpicontrelgr_ [l=ru] {_httpimg_/ru/trelgr.gif}
+_httpicontrelon_ [l=ru] {_httpimg_/ru/trelon.gif}
+_httpicontrelof_ [l=ru] {_httpimg_/ru/trelof.gif}
+_widthtrelx_ [l=ru] {87}
+
+## "ÐŸÑ
+Ð²Ð°Ñ" ## nav_bar_button ## tcover ##
+_httpicontcovergr_ [l=ru] {_httpimg_/ru/tcovergr.gif}
+_httpicontcoveron_ [l=ru] {_httpimg_/ru/tcoveron.gif}
+_httpicontcoverof_ [l=ru] {_httpimg_/ru/tcoverof.gif}
+_widthtcoverx_ [l=ru] {87}
+
+## "Ð¿ÑÐ°Ð²Ð°" ## nav_bar_button ## tright ##
+_httpicontrightgr_ [l=ru] {_httpimg_/ru/trightgr.gif}
+_httpicontrighton_ [l=ru] {_httpimg_/ru/trighton.gif}
+_httpicontrightof_ [l=ru] {_httpimg_/ru/trightof.gif}
+_widthtrightx_ [l=ru] {87}
+
+
+
+## "Ð²ÑÐ¿ÑÑÐºÐž" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=ru] {_httpimg_/ru/tsergr.gif}
+_httpicontserof_ [l=ru] {_httpimg_/ru/tserof.gif}
+_httpicontseron_ [l=ru] {_httpimg_/ru/tseron.gif}
+_widthtserx_ [l=ru] {87}
+
+## "ÐºÐŸÐŒÑ" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=ru] {_httpimg_/ru/ttogr.gif}
+_httpiconttoon_ [l=ru] {_httpimg_/ru/ttoon.gif}
+_httpiconttoof_ [l=ru] {_httpimg_/ru/ttoof.gif}
+_widthttox_ [l=ru] {87}
+
+## "ÐŸÑ ÐºÐŸÐ³ÐŸ" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=ru] {_httpimg_/ru/tfromgr.gif}
+_httpicontfromon_ [l=ru] {_httpimg_/ru/tfromon.gif}
+_httpicontfromof_ [l=ru] {_httpimg_/ru/tfromof.gif}
+_widthtfromx_ [l=ru] {87}
+
+## "ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÐž" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=ru] {_httpimg_/ru/torggr.gif}
+_httpicontorgon_ [l=ru] {_httpimg_/ru/torgon.gif}
+_httpicontorgof_ [l=ru] {_httpimg_/ru/torgof.gif}
+_widthtorgx_ [l=ru] {98}
+
+## "ÑÐ¿ÐŸÑÐŸÐ±Ñ" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=ru] {_httpimg_/ru/thowgr.gif}
+_httpiconthowon_ [l=ru] {_httpimg_/ru/thowon.gif}
+_httpiconthowof_ [l=ru] {_httpimg_/ru/thowof.gif}
+_widththowx_ [l=ru] {87}
+
+## "ÑÐµÐŒÑ" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=ru] {_httpimg_/ru/ttopicgr.gif}
+_httpiconttopicon_ [l=ru] {_httpimg_/ru/ttopicon.gif}
+_httpiconttopicof_ [l=ru] {_httpimg_/ru/ttopicof.gif}
+_widthttopicx_ [l=ru] {87}
+
+## "ÑÐ¿ÐžÑÐŸÐº" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=ru] {_httpimg_/ru/tbrwsegr.gif}
+_httpicontbrwseon_ [l=ru] {_httpimg_/ru/tbrwseon.gif}
+_httpicontbrwseof_ [l=ru] {_httpimg_/ru/tbrwseof.gif}
+_widthtbrwsex_ [l=ru] {87}
+
+## "ÐºÐŸÐ»Ð»Ð°Ð¶" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=ru] {_httpimg_/ru/tcollgr.gif}
+_httpicontcollof_ [l=ru] {_httpimg_/ru/tcollof.gif}
+_httpicontcollon_ [l=ru] {_httpimg_/ru/tcollon.gif}
+_widthtcollx_ [l=ru] {87}
+
+## "Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐž" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=ru] {_httpimg_/ru/tpeopgr.gif}
+_httpicontpeopof_ [l=ru] {_httpimg_/ru/tpeopof.gif}
+_httpicontpeopon_ [l=ru] {_httpimg_/ru/tpeopon.gif}
+_widthtpeopx_ [l=ru] {97}
+
+## "Ð°ÐºÑÐŸÐœÐžÐŒÑ" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=ru] {_httpimg_/ru/tacrogr.gif}
+_httpicontacroof_ [l=ru] {_httpimg_/ru/tacroof.gif}
+_httpicontacroon_ [l=ru] {_httpimg_/ru/tacroon.gif}
+_widthtacrox_ [l=ru] {87}
+
+## "ÑÑÐ°Ð·Ñ" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=ru] {_httpimg_/ru/tphrsegr.gif}
+_httpicontphrseof_ [l=ru] {_httpimg_/ru/tphrseof.gif}
+_httpicontphrseon_ [l=ru] {_httpimg_/ru/tphrseon.gif}
+_widthtphrsex_ [l=ru] {87}
+
+## "ÑÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ/ÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=ru] {_httpimg_/ru/tartstgr.gif}
+_httpicontartstof_ [l=ru] {_httpimg_/ru/tartstof.gif}
+_httpicontartston_ [l=ru] {_httpimg_/ru/tartston.gif}
+_widthtartstx_ [l=ru] {87}
+
+## "ÐºÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð°" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=ru] {_httpimg_/ru/tkwgr.gif}
+_httpicontkwof_ [l=ru] {_httpimg_/ru/tkwof.gif}
+_httpicontkwon_ [l=ru] {_httpimg_/ru/tkwon.gif}
+_widthtkwx_ [l=ru] {87}
+
+## "ÐžÐ·ÐŽÐ°ÐœÐžÑ" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=ru] {_httpimg_/ru/tvolgr.gif}
+_httpicontvolof_ [l=ru] {_httpimg_/ru/tvolof.gif}
+_httpicontvolon_ [l=ru] {_httpimg_/ru/tvolon.gif}
+_widthtvolx_ [l=ru] {87}
+
+## "Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž(ÐœÐ°ÐŽÐ¿ÐžÑÐž)" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=ru] {_httpimg_/ru/tcaptgr.gif}
+_httpicontcaptof_ [l=ru] {_httpimg_/ru/tcaptof.gif}
+_httpicontcapton_ [l=ru] {_httpimg_/ru/tcapton.gif}
+_widthtcaptx_ [l=ru] {87}
+
+## "ÑÑÑÐ°ÐœÑ" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=ru] {_httpimg_/ru/tcountgr.gif}
+_httpicontcountof_ [l=ru] {_httpimg_/ru/tcountof.gif}
+_httpicontcounton_ [l=ru] {_httpimg_/ru/tcounton.gif}
+_widthtcountx_ [l=ru] {87}
+
+## "Ð¿ÐŸÐŒÐŸÑÑ" ## green_title ## h_help ##
+_httpiconhhelp_ [l=ru] {_httpimg_/ru/h\_help.gif}
+_widthhhelp_ [l=ru] {200}
+_heighthhelp_ [l=ru] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=ru] {ÐÐµÐŒÐœÐŸÐ³ÐŸ ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+
+_textsubcols1_ [l=ru] {<p>ÐÐ°ÐœÐœÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÐŸÐŽÐµÑÐ¶ÐžÑ _1_ Ð¿ÐŸÐŽÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹:
+<blockquote>}
+
+_textsubcols2_ [l=ru] {</blockquote>
+ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ/ÐžÐ·ÐŒÐµÐœÐžÑÑ ÑÐ¿ÐžÑÐŸÐº Ð¿ÐŸÐŽÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹, ÐºÐŸÑÐŸÑÑÐµ Ð²Ñ ÑÐµÐ¹ÑÐ°Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÐµ, ÐœÐ° ÑÑÑÐ°ÐœÐžÑÐµ ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ" ## green_title ## h_about ##
+_httpiconhabout_ [l=ru] {_httpimg_/ru/h\_about.gif}
+_widthhabout_ [l=ru] {200}
+_heighthabout_ [l=ru] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=ru] {ÐÐ°Ð·Ð²Ð°ÐœÐžÑ Ð-Ð¯}
+_texticonhcreat_ [l=ru] {ÐÐ²ÑÐŸÑÑ Ð-Ð¯}
+_texticonhsubj_ [l=ru] {Ð£ÐºÐ°Ð·Ð°ÑÐµÐ»Ñ}
+_texticonhdesc_ [l=ru] {ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ}
+_texticonhpubl_ [l=ru] {ÐžÐ·ÐŽÐ°ÑÐµÐ»Ðž}
+_texticonhcontr_ [l=ru] {Ð£ÑÐ°ÑÑÐœÐžÐºÐž}
+_texticonhdate_ [l=ru] {ÐÐ°ÑÑ}
+_texticonhtype_ [l=ru] {ÑÐžÐ¿Ñ}
+_texticonhform_ [l=ru] {ÑÐŸÑÐŒÐ°ÑÑ}
+_texticonhident_ [l=ru] {ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÑ}
+_texticonhsrc_ [l=ru] {ÐÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÐŸÐ²}
+_texticonhlang_ [l=ru] {Ð¯Ð·ÑÐºÐž}
+_texticonhrel_ [l=ru] {ÑÐ²ÑÐ·Ðž}
+_texticonhcover_ [l=ru] {ÐŸÑ
+Ð²Ð°Ñ}
+_texticonhright_ [l=ru] {Ð¿ÑÐ°Ð²Ð°}
+
+_texticonhcoll_ [l=ru] {ÐÐŸÐ»Ð»Ð°Ð¶}
+_texticonhto_ [l=ru] {ÐÐŸÐŒÑ}
+_texticonhfrom_ [l=ru] {ÐÑ ÐºÐŸÐ³ÐŸ}
+_texticonhser_ [l=ru] {ÐÑÐ¿ÑÑÐºÐž}
+_texticonhhow_ [l=ru] {Ð¡Ð¿ÐŸÑÐŸÐ±Ñ}
+_texticonhorg_ [l=ru] {ÐÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÐž}
+_texticonhbrwse_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ}
+_texticonhbrows_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ}
+_texticonhpeople_ [l=ru] {ÐÐµÑÑÐŸÐœÐ°Ð»ÐžÐž Ð-Ð¯}
+_texticonhacronym_ [l=ru] {ÐÐºÑÐŸÐœÐžÐŒÑ}
+_texticonhphrases_ [l=ru] {Ð€ÑÐ°Ð·Ñ}
+_texticonhartist_ [l=ru] {Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ðž/ÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ðž}
+_texticonhkw_ [l=ru] {ÐÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð°}
+_texticonhvol_ [l=ru] {ÐÐ·ÐŽÐ°ÐœÐžÑ}
+_texticonhcapt_ [l=ru] {ÐÐ°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž}
+_texticonhcount_ [l=ru] {Ð¡ÑÑÐ°ÐœÑ}
+
+_texticonopenbookshelf_ [l=ru] {ÐÐ°ÐºÑÑÑÑ ÑÐµÐºÑÐžÑ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž}
+_texticonclosedbookshelf_ [l=ru] {ÐÑÐºÑÑÑÑ ÑÐµÐºÑÐžÑ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž Ðž Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ}
+_texticonopenbook_ [l=ru] {ÐÐ°ÐºÑÑÑÑ ÐºÐœÐžÐ³Ñ}
+_texticonclosedfolder_ [l=ru] {ÐÑÐºÑÑÑÑ Ð¿Ð°Ð¿ÐºÑ Ðž Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ}
+_texticonclosedfolder2_ [l=ru] {ÐÑÐºÑÑÑÑ Ð¿ÐŸÐŽÑÐµÐºÑÐžÑ: }
+_texticonopenfolder_ [l=ru] {ÐÐ°ÐºÑÑÑÑ Ð¿Ð°Ð¿ÐºÑ}
+_texticonopenfolder2_ [l=ru] {ÐÐ°ÐºÑÑÑÑ Ð¿ÐŸÐŽÑÐµÐºÑÐžÑ: }
+_texticonsmalltext_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÑÐµÐºÑÐžÐž ÑÐµÐºÑÑÐ°}
+_texticonsmalltext2_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÑÐµÐºÑÑÐ°: }
+_texticonpointer_ [l=ru] {Ð¢ÐµÐºÑÑÐ°Ñ ÑÐµÐºÑÐžÑ}
+_texticondetach_ [l=ru] {ÐÑÐºÑÑÑÑ ÑÑÑÐ°ÐœÐžÑÑ Ð² ÐœÐŸÐ²ÐŸÐŒ ÐŸÐºÐœÐµ}
+_texticonhighlight_ [l=ru] {ÐÑÐŽÐµÐ»ÐžÑÑ ÐžÑÐºÐŸÐŒÑÐµ ÑÐµÑÐŒÐžÐœÑ}
+_texticonnohighlight_ [l=ru] {ÐÐµ Ð²ÑÐŽÐµÐ»ÑÑÑ ÐžÑÐºÐŸÐŒÑÐµ ÑÐµÑÐŒÐžÐœÑ}
+_texticoncontracttoc_ [l=ru] {Ð¡Ð²ÐµÑÐœÑÑÑ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ }
+_texticonexpandtoc_ [l=ru] {Ð Ð°ÑÐºÑÑÑÑ Ð²ÑÐµ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ}
+_texticonexpandtext_ [l=ru] {ÐÐŸÐºÐ°Ð·Ð°ÑÑ Ð²ÐµÑÑ ÑÐµÐºÑÑ}
+_texticoncontracttext_ [l=ru] {ÐÐŸÐºÐ°Ð·Ð°ÑÑ ÑÐµÐºÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐŽÐ»Ñ Ð²ÑÐŽÐµÐ»ÐµÐœÐœÑÑ
+ ÑÐµÐºÑÐžÐ¹}
+_texticonwarning_ [l=ru] {<b>ÐÐœÐžÐŒÐ°ÐœÐžÐµ: </b>}
+_texticoncont_ [l=ru] {Ð¿ÑÐŸÐŽÐŸÐ»Ð¶ÐžÑÑ?}
+
+_textltwarning_ [l=ru] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_ ÐÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ Ð²ÑÐµÐ³ÐŸ ÑÐµÐºÑÑÐ° Ð¿ÑÐžÐ²ÐµÐŽÐµÑ Ðº ÑÐ²ÐµÐ»ÐžÑÐµÐœÐžÑ  ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐŽÐ»Ñ ÐŸÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ Ð² Ð±ÑÐ°ÑÐ·ÐµÑÐµ _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=ru] {Ð¿ÐµÑÐµÐ¹ÑÐž ÐœÐ° ÑÑÑÐ°ÐœÐžÑÑ}
+_textintro_ [l=ru] {<i>(Ð²Ð²ÐµÐŽÐµÐœÐžÐµ)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ Ð°-Ñ" ## green_title ## h_title ##
+_httpiconhtitle_ [l=ru] {_httpimg_/ru/h\_title.gif}
+_widthhtitle_ [l=ru] {200}
+_heighthtitle_ [l=ru] {57}
+
+# Not true DC, kept for legacy reasons
+## "Ð°Ð²ÑÐŸÑÑ Ð°-Ñ" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=ru] {_httpimg_/ru/h\_auth.gif}
+_widthhcreat_ [l=ru] {200}
+_heighthcreat_ [l=ru] {57}
+
+## "ÑÐºÐ°Ð·Ð°ÑÐµÐ»Ñ" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=ru] {_httpimg_/ru/h\_subj.gif}
+_widthhsubj_ [l=ru] {200}
+_heighthsubj_ [l=ru] {57}
+
+## "ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ" ## green_title ## h_desc ##
+_httpiconhdesc_ [l=ru] {_httpimg_/ru/h\_desc.gif}
+_widthhdesc_ [l=ru] {200}
+_heighthdesc_ [l=ru] {57}
+
+## "ÐžÐ·ÐŽÐ°ÑÐµÐ»Ðž" ## green_title ## h_publ ##
+_httpiconhpubl_ [l=ru] {_httpimg_/ru/h\_publ.gif}
+_widthhpubl_ [l=ru] {200}
+_heighthpubl_ [l=ru] {57}
+
+## "ÑÑÐ°ÑÑÐœÐžÐºÐž" ## green_title ## h_contr ##
+_httpiconhcontr_ [l=ru] {_httpimg_/ru/h\_contr.gif}
+_widthhcontr_ [l=ru] {200}
+_heighthcontr_ [l=ru] {57}
+
+## "ÐŽÐ°ÑÑ" ## green_title ## h_date ##
+_httpiconhdate_ [l=ru] {_httpimg_/ru/h\_date.gif}
+_widthhdate_ [l=ru] {200}
+_heighthdate_ [l=ru] {57}
+
+## "ÑÐžÐ¿Ñ" ## green_title ## h_type ##
+_httpiconhtype_ [l=ru] {_httpimg_/ru/h\_type.gif}
+_widthhtype_ [l=ru] {200}
+_heighthtype_ [l=ru] {57}
+
+## "ÑÐŸÑÐŒÐ°ÑÑ" ## green_title ## h_form ##
+_httpiconhform_ [l=ru] {_httpimg_/ru/h\_form.gif}
+_widthhform_ [l=ru] {200}
+_heighthform_ [l=ru] {57}
+
+## "ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÑ" ## green_title ## h_ident ##
+_httpiconhident_ [l=ru] {_httpimg_/ru/h\_ident.gif}
+_widthhident_ [l=ru] {200}
+_heighthident_ [l=ru] {57}
+
+# Not true DC, kept for legacy reasons
+## "ÐžÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÐŸÐ²" ## green_title ## h_src ##
+_httpiconhsrc_ [l=ru] {_httpimg_/ru/h\_src.gif}
+_widthhsrc_ [l=ru] {200}
+_heighthsrc_ [l=ru] {57}
+
+## "ÑÐ·ÑÐºÐž" ## green_title ## h_lang ##
+_httpiconhlang_ [l=ru] {_httpimg_/ru/h\_lang.gif}
+_widthhlang_ [l=ru] {200}
+_heighthlang_ [l=ru] {57}
+
+## "ÑÐ²ÑÐ·Ðž" ## green_title ## h_rel ##
+_httpiconhrel_ [l=ru] {_httpimg_/ru/h\_rel.gif}
+_widthhrel_ [l=ru] {200}
+_heighthrel_ [l=ru] {57}
+
+## "ÐŸÑ
+Ð²Ð°Ñ" ## green_title ## h_cover ##
+_httpiconhcover_ [l=ru] {_httpimg_/ru/h\_cover.gif}
+_widthhcover_ [l=ru] {200}
+_heighthcover_ [l=ru] {57}
+
+## "Ð¿ÑÐ°Ð²Ð°" ## green_title ## h_right ##
+_httpiconhright_ [l=ru] {_httpimg_/ru/h\_right.gif}
+_widthhright_ [l=ru] {200}
+_heighthright_ [l=ru] {57}
+
+
+
+## "ÐºÐŸÐŒÑ" ## green_title ## h_to ##
+_httpiconhto_ [l=ru] {_httpimg_/ru/h\_to.gif}
+_widthhto_ [l=ru] {200}
+_heighthto_ [l=ru] {57}
+
+## "ÐŸÑ ÐºÐŸÐ³ÐŸ" ## green_title ## h_from ##
+_httpiconhfrom_ [l=ru] {_httpimg_/ru/h\_from.gif}
+_widthhfrom_ [l=ru] {200}
+_heighthfrom_ [l=ru] {57}
+
+## "Ð²ÑÐ¿ÑÑÐºÐž" ## green_title ## h_ser ##
+_httpiconhser_ [l=ru] {_httpimg_/ru/h\_ser.gif}
+_widthhser_ [l=ru] {200}
+_heighthser_ [l=ru] {57}
+
+## "ÑÐ¿ÐŸÑÐŸÐ±Ñ" ## green_title ## h_how ##
+_httpiconhhow_ [l=ru] {_httpimg_/ru/h\_how.gif}
+_widthhhow_ [l=ru] {200}
+_heighthhow_ [l=ru] {57}
+
+## "ÑÐµÐŒÑ" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=ru] {_httpimg_/ru/h\_topic.gif}
+_widthhtopic_ [l=ru] {200}
+_heighthtopic_ [l=ru] {57}
+
+## "ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÐž" ## green_title ## h_org ##
+_httpiconhorg_ [l=ru] {_httpimg_/ru/h\_org.gif}
+_widthhorg_ [l=ru] {200}
+_heighthorg_ [l=ru] {57}
+
+## "ÑÐ¿ÐžÑÐŸÐº" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=ru] {_httpimg_/ru/h\_brwse.gif}
+_widthhbrwse_ [l=ru] {200}
+_heighthbrwse_ [l=ru] {57}
+
+## "ÐºÐŸÐŒÐ±ÐžÐœÐ°ÑÐžÑ ÑÐ°Ð·ÐœÐŸÑÐŸÐŽÐœÑÑ
+ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐ²" ## green_title ## h_coll ##
+_httpiconhcoll_ [l=ru] {_httpimg_/ru/h\_coll.gif}
+_widthhcoll_ [l=ru] {200}
+_heighthcoll_ [l=ru] {57}
+
+## "Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÐž" ## green_title ## h_people ##
+_httpiconhpeople_ [l=ru] {_httpimg_/ru/h\_people.gif}
+_widthhpeople_ [l=ru] {200}
+_heighthpeople_ [l=ru] {57}
+
+## "Ð°ÐºÑÐŸÐœÐžÐŒÑ" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=ru] {_httpimg_/ru/h\_acro.gif}
+_widthhacronym_ [l=ru] {200}
+_heighthacronym_ [l=ru] {57}
+
+## "ÑÑÐ°Ð·Ñ" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=ru] {_httpimg_/ru/h\_phrse.gif}
+_widthhphrse_ [l=ru] {200}
+_heighthphrse_ [l=ru] {57}
+
+## "Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ðž/ÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ðž" ## green_title ## h_artist ##
+_httpiconhartist_ [l=ru] {_httpimg_/ru/h\_artist.gif}
+_widthhartist_ [l=ru] {200}
+_heighthartist_ [l=ru] {57}
+
+## "ÐºÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð°" ## green_title ## h_kw ##
+_httpiconhkw_ [l=ru] {_httpimg_/ru/h\_kw.gif}
+_widthhkw_ [l=ru] {200}
+_heighthkw_ [l=ru] {57}
+
+## "ÐžÐ·ÐŽÐ°ÐœÐžÑ" ## green_title ## h_vol ##
+_httpiconhvol_ [l=ru] {_httpimg_/ru/h\_vol.gif}
+_widthhvol_ [l=ru] {200}
+_heighthvol_ [l=ru] {57}
+
+## "ÑÑÑÐ°ÐœÑ" ## green_title ## h_count ##
+_httpiconhcount_ [l=ru] {_httpimg_/ru/h\_count.gif}
+_widthhcount_ [l=ru] {200}
+_heighthcount_ [l=ru] {57}
+
+## "Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž (ÐœÐ°ÐŽÐ¿ÐžÑÐž)" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=ru] {_httpimg_/ru/h\_capt.gif}
+_widthhcapt_ [l=ru] {200}
+_heighthcapt_ [l=ru] {57}
+
+
+## "ÐÐ ÐÐÐÐÐÐÐ¢Ð¬??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=ru] {_httpimg_/ru/contof.gif}
+_httpiconconton_ [l=ru] {_httpimg_/ru/conton.gif}
+
+## "ÐÐÐ¡Ð¬\nÐ¢ÐÐÐ¡Ð¢" ## document_button ## eallt ##
+_httpiconealltof_ [l=ru] {_httpimg_/ru/ealltof.gif}
+_httpiconeallton_ [l=ru] {_httpimg_/ru/eallton.gif}
+
+## "Ð¡ÐÐÐ ÐÐ£Ð¢Ð¬" ## document_button ## econc ##
+_httpiconeconcof_ [l=ru] {_httpimg_/ru/econcof.gif}
+_httpiconeconcon_ [l=ru] {_httpimg_/ru/econcon.gif}
+
+## "ÐÐÐÐÐ\nÐÐÐÐ" ## document_button ## edtch ##
+_httpiconedtchof_ [l=ru] {_httpimg_/ru/edtchof.gif}
+_httpiconedtchon_ [l=ru] {_httpimg_/ru/edtchon.gif}
+
+## "Ð ÐÐ¡ÐÐ Ð«Ð¢Ð¬" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=ru] {_httpimg_/ru/eexpcof.gif}
+_httpiconeexpcon_ [l=ru] {_httpimg_/ru/eexpcon.gif}
+
+## "Ð¡ÐÐÐ ÐÐ£Ð¢Ð¬" ## document_button ## etsec ##
+_httpiconetsecof_ [l=ru] {_httpimg_/ru/etsecof.gif}
+_httpiconetsecon_ [l=ru] {_httpimg_/ru/etsecon.gif}
+
+## "ÐÐ«ÐÐÐÐÐ¢Ð¬" ## document_button ## ehl ##
+_httpiconehlof_ [l=ru] {_httpimg_/ru/ehlof.gif}
+_httpiconehlon_ [l=ru] {_httpimg_/ru/ehlon.gif}
+
+## "Ð¡ÐÐ¯Ð¢Ð¬" ## document_button ## enhl ##
+_httpiconenhlof_ [l=ru] {_httpimg_/ru/enhlof.gif}
+_httpiconenhlon_ [l=ru] {_httpimg_/ru/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=ru] {_If_(_thislast_,ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÑ _thisfirst_ - _thislast_ Ð¿ÐŸÐžÑÐºÐ° Ð¿ÐŸ Ð·Ð°Ð¿ÑÐŸÑÑ: _cgiargq_,ÐÐžÑÐµÐ³ÐŸ ÐœÐµ ÐœÐ°Ð¹ÐŽÐµÐœÐŸ Ð¿ÐŸ Ð·Ð°Ð¿ÑÐŸÑÑ: _cgiargq_)}
+_textnoquerytitle_ [l=ru] {Ð¡ÑÑÐ°ÐœÐžÑÐ° Ð¿ÐŸÐŒÐŸÑÐž}
+
+_texticonthispage_ [l=ru] {ÐÐŸÐžÑÐº}
+_textsome_ [l=ru] {ÐœÐµÐºÐŸÑÐŸÑÑÐµ}
+_textall_ [l=ru] {Ð²ÑÐµ}
+_textboolean_ [l=ru] {Ð»ÐŸÐ³ÐžÑÐµÑÐºÐžÐ¹}
+_textranked_ [l=ru] {ÑÐ¿ÐŸÑÑÐŽÐŸÑÐµÐœÐœÑÐ¹}
+_textnatural_ [l=ru] {ÐŸÐ±ÑÑÐœÑÐ¹}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=ru] {}
+_texticonsearchhistorybar_ [l=ru] {ÐÑÑÐŸÑÐžÑ Ð¿ÐŸÐžÑÐºÐ°}
+
+_textifeellucky_ [l=ru] {Ð¯ ÑÑÐ²ÑÑÐ²ÑÑ ÑÐŽÐ°ÑÑ!}
+
+#alt text for query buttons
+_textusequery_ [l=ru] {ÐÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐŽÐ°ÐœÐœÑÐ¹ Ð·Ð°Ð¿ÑÐŸÑ}
+_textfreqmsg1_ [l=ru] {ÐÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸ Ð²Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÐ¹: }
+_textpostprocess_ [l=ru] {_If_(_quotedquery_,<br><i>ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÐœÐŸ ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ° _quotedquery_</i>
+)}
+_textinvalidquery_ [l=ru] {ÐÐµÐ¿ÑÐ°Ð²ÐžÐ»ÑÐœÑÐ¹ ÑÐžÐœÑÐ°ÐºÑÐžÑ Ð²ÐŸÐ¿ÑÐŸÑÐ°}
+
+_textmorethan_ [l=ru] {ÐÐŸÐ»ÑÑÐµ ÑÐµÐŒ}
+_textapprox_ [l=ru] {ÐÐºÐŸÐ»ÐŸ}
+_textnodocs_ [l=ru] {ÐÐŸÐºÑÐŒÐµÐœÑÐŸÐ² ÑÐŽÐŸÐ²Ð»ÐµÑÐ²ÐŸÑÑÑÑÐžÑ
+ Ð·Ð°Ð¿ÑÐŸÑÑ ÐœÐµ ÐœÐ°Ð¹ÐŽÐµÐœÐŸ.}
+_text1doc_ [l=ru] {1 ÐŽÐŸÐºÑÐŒÐµÐœÑ ÑÐŽÐŸÐ²Ð»ÐµÑÐ²ÐŸÑÑÐµÑ Ð·Ð°Ð¿ÑÐŸÑÑ.}
+_textlotsdocs_ [l=ru] {ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÑÐŽÐŸÐ²Ð»ÐµÑÐ²ÐŸÑÑÑÑÐžÑ
+ Ð·Ð°Ð¿ÑÐŸÑÑ.}
+_textmatches_ [l=ru] {Ð ÐµÐ·ÑÐ»ÑÑÐ°ÑÑ }
+_textbeginsearch_ [l=ru] {ÐÐ°ÑÐ°ÑÑ Ð¿ÐŸÐžÑÐº}
+_textrunquery_ [l=ru] {ÐÑÐ¿ÐŸÐ»ÐœÐžÑÑ Ð·Ð°Ð¿ÑÐŸÑ}
+_textclearform_ [l=ru] {ÐÑÐžÑÑÐžÑÑ ÑÐŸÑÐŒÑ}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=ru] {Ð¡Ð»ÐŸÐ²ÐŸ ÐžÐ»Ðž ÑÑÐ°Ð·Ð°}
+_textinfield_ [l=ru] {... Ð² Ð¿ÐŸÐ»Ðµ}
+_textfoldstem_ [l=ru] {(ÑÐ»ÐŸÐ²ÐŸ, ÑÑÐ°Ð·Ð°)}
+
+_textadvquery_ [l=ru] {ÐžÐ»Ðž Ð²Ð²ÐµÐŽÐžÑÐµ ÑÐµÐºÑÑ Ð·Ð°Ð¿ÑÐŸÑÐ°:}
+_textallfields_ [l=ru] {Ð²ÑÐµ Ð¿ÐŸÐ»Ñ}
+_texttextonly_ [l=ru] {ÑÐŸÐ»ÑÐºÐŸ ÑÐµÐºÑÑ
+}
+_textand_ [l=ru] {Ðž}
+_textor_ [l=ru] {ÐžÐ»Ðž}
+_textandnot_ [l=ru] {Ðž ÐœÐµ}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=ru] {ÐÐŸÐžÑÐº Ð¿ÐŸ _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, Ð¿ÐŸ _gselection_ ÑÑÐŸÐ²ÐœÑ) _If_(_nselection_, ÐœÐ°  _nselection_ ÑÐ·ÑÐºÐµ ),ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐžÐŒ _querytypeselection_ ÐžÐ· ÑÐ»ÐŸÐ²
+}
+
+_textadvancedsearch_ [l=ru] {ÐÐŸÐžÑÐº _indexselection_ _If_(_jselection_, Ð² _jselection_) _If_(_gselection_, Ð¿ÐŸ _gselection_ ÑÑÐŸÐ²ÐœÑ)_If_(_nselection_, Ðž ÑÐ·ÑÐº: _nselection_)  ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð·Ð°Ð¿ÑÐŸÑ _querytypeselection_ }
+
+_textformsimplesearch_ [l=ru] {ÐÐŸÐžÑÐº Ð¿ÐŸ _If_(_jselection_, _jselection_) _If_(_gformselection_, Ð¿ÐŸ _gformselection_ ÑÑÐŸÐ²ÐœÑ) _If_(_nselection_, in _nselection_ language)
+,Ð³ÐŽÐµ ÑÐŸÐŽÐµÑÐ¶ÐžÑÑÑ _formquerytypeselection_ }
+
+_textformadvancedsearch_ [l=ru] {ÐÐŸÐžÑÐº _If_(_jselection_,_jselection_) _If_(_gformselection_, Ð¿ÐŸ _gformselection_ ÑÑÐŸÐ²ÐœÑ)_If_(_nselection_, ÐœÐ° _nselection_ ÑÐ·ÑÐºÐµ) 
+Ðž ÐŸÑÐŸÐ±ÑÐ°Ð¶Ð°ÑÑ ÑÐµÐ·ÑÐ»ÑÑÐ°Ñ Ð² Ð¿ÐŸÑÑÐŽÐºÐµ _formquerytypeselection_}
+
+
+_textnojsformwarning_ [l=ru] {ÐÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐµÐœÐžÐµ: Javascript Ð¿ÐŸÐ²ÑÐµÐ¶ÐŽÐµÐœ ÐœÐ° ÐÐ°ÑÐµÐŒ Ð²ÐµÐ±-Ð±ÑÐ°ÑÐ·ÐµÑÐµ. <br>Ð§ÑÐŸÐ±Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÑÐŸÑÐŒÑ Ð¿ÐŸÐžÑÐºÐ°, Ð¿ÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ°, ÑÐ°Ð·ÑÐµÑÐžÑÐµ ÑÑÐŸ.}
+_textdatesearch_ [l=ru] {ÐÐŸÐžÑÐº ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Ð¿ÐŸ ÐŽÐ°ÐœÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŒÐŸÐ¶ÐµÑ ÐŸÑÑÑÐµÑÑÐ²Ð»ÑÑÑÑÑ ÐºÐ°Ðº Ð¿ÐŸ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÐŸÐŒÑ Ð²ÑÐµÐŒÐµÐœÐœÐŸÐŒÑ ÐžÐœÑÐµÑÐ²Ð°Ð»Ñ, ÑÐ°Ðº Ðž Ð¿ÐŸ ÐºÐŸÐœÐºÑÐµÑÐœÐŸÐ¹ ÑÐžÑÐ»ÐŸÐ²ÐŸÐ¹ ÐŽÐ°ÑÐµ.}
+_textstartdate_ [l=ru] {ÐÐ°ÑÐ°Ð»ÑÐœÐ°Ñ (ÐžÐ»Ðž ÐºÐŸÐœÐºÑÐµÑÐœÐ°Ñ) ÐŽÐ°ÑÐ°:}
+_textenddate_ [l=ru] {ÐÐŸÐœÐµÑÐœÐ°Ñ ÐŽÐ°ÑÐ°:}
+_textbc_ [l=ru] {ÐŽÐŸ Ðœ.Ñ.}
+_textad_ [l=ru] {Ðœ.Ñ.}
+_textexplaineras_ [l=ru] {Ð¢ÐµÑÐŒÐžÐœÑ Ð.Ð­. Ðž ÐÐŸ Ð.Ð­. ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐ°ÑÑ "ÐÐ°ÑÐµÐ¹ ÑÑÑ" Ðž "ÐÐŸ ÐœÐ°ÑÐµÐ¹ ÑÑÑ"}
+
+_textstemon_ [l=ru] {(ÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÑÑ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÑ ÑÐ»ÐŸÐ²)}
+
+_textsearchhistory_ [l=ru] {ÐÑÑÐŸÑÐžÑ Ð·Ð°Ð¿ÑÐŸÑÐ°}
+
+#text macros for search history
+_textnohistory_ [l=ru] {Ð ÐŽÐ°ÐœÐœÑÐ¹ ÐŒÐŸÐŒÐµÐœÑ ÐœÐµ ÑÑÑÐµÑÑÐ²ÑÐµÑ ÐžÑÑÐŸÑÐžÐž Ð·Ð°Ð¿ÑÐŸÑÐ°
+}
+_texthresult_ [l=ru] {Ð²Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÐµ}
+_texthresults_ [l=ru] {Ð²Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÐ¹}
+_texthallwords_ [l=ru] {Ð²ÑÐµ ÑÐ»ÐŸÐ²Ð°}
+_texthsomewords_ [l=ru] {ÐœÐµÐºÐŸÑÐŸÑÑÐµ ÑÐ»ÐŸÐ²Ð°}
+_texthboolean_ [l=ru] {Ð»ÐŸÐ³ÐžÑÐµÑÐºÐžÐ¹}
+_texthranked_ [l=ru] {ÑÐ¿ÐŸÑÑÐŽÐŸÑÐµÐœÐœÑÐ¹}
+_texthcaseon_ [l=ru] {Ñ ÑÑÐµÑÐŸÐŒ ÑÐµÐ³ÐžÑÑÑÐ°}
+_texthcaseoff_ [l=ru] {Ð±ÐµÐ· ÑÑÐµÑÐ° ÑÐµÐ³ÐžÑÑÑÐ°}
+_texthstemon_ [l=ru] {Ñ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÑÐŒÐž}
+_texthstemoff_ [l=ru] {Ð±ÐµÐ· ÐŸÐºÐŸÐœÑÐ°ÐœÐžÐ¹}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Ð¿ÐŸÐžÑÐº" ## green_title ## h_search ##
+_httpiconhsearch_ [l=ru] {_httpimg_/ru/h\_search.gif}
+_widthhsearch_ [l=ru] {200}
+_heighthsearch_ [l=ru] {57}
+
+## "ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÑ" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=ru] {_httpimg_/ru/qryresb.gif}
+_widthqryresb_ [l=ru] {_pagewidth_}
+_heightqryresb_ [l=ru] {17}
+
+## "ÐžÑÑÐŸÑÐžÑ" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=ru] {_httpimg_/ru/schhistb.gif}
+_widthsrchhistb_ [l=ru] {_pagewidth_}
+_heightsrchhistb_ [l=ru] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=ru] {ÐÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÑ Ð±ÑÐ»Ðž ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ ÑÐ»ÐµÐŽÑÑÑÐžÐŒ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ. ÐÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐœÐŸÐ¿ÐºÑ "ÐœÐ°Ð·Ð°ÐŽ" Ð²Ð°ÑÐµÐ³ÐŸ Ð±ÑÐ°ÑÐ·ÐµÑÐ° - Ð¿ÑÐŸÐžÐ·ÐŸÐ¹ÐŽÐµÑ ÑÐ±ÑÐŸÑ! ÐÐŒÐµÑÑÐŸ ÑÑÐŸÐ³ÐŸ ÑÐµÐ»ÐºÐœÐžÑÐµ ÐŸÐŽÐœÑ ÐžÐ· ÐºÐœÐŸÐ¿ÐŸÐº ÐœÐ°ÐŽ Ð»ÐžÐœÐµÐ¹ÐºÐŸÐ¹ ÐŽÐŸÑÑÑÐ¿Ð°.}
+_textsetprefs_ [l=ru] {ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ Ð¿ÑÐµÐŽÐ¿ÐŸÑÑÐµÐœÐžÑ}
+_textsearchprefs_ [l=ru] {ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž Ð¿ÐŸÐžÑÐºÐ°}
+_textcollectionprefs_ [l=ru] {ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+_textpresentationprefs_ [l=ru] {ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°}
+_textpreferences_ [l=ru] {ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž}
+_textcasediffs_ [l=ru] {Ð ÐµÐ³ÐžÑÑÑÑ:}
+_textignorecase_ [l=ru] {ÐžÐ³ÐœÐŸÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÐ³ÐžÑÑÑÑ}
+_textmatchcase_ [l=ru] {ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð²ÐµÑÑ
+ÐœÐžÐ¹ Ðž ÐœÐžÐ¶ÐœÐžÐ¹ ÑÐµÐ³ÐžÑÑÑÑ }
+_textwordends_ [l=ru] {ÐÐºÐŸÐœÑÐ°ÐœÐžÑ ÑÐ»ÐŸÐ²:}
+_textstem_ [l=ru] {ÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÑÑ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÑ ÑÐ»ÐŸÐ²}
+_textnostem_ [l=ru] {ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÑÐ»ÐŸÐ²Ð° Ñ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÐµÐŒ}
+_textprefop_ [l=ru] {ÐÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÑ _maxdocoption_ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² - ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°, Ð¿ÐŸ  _hitsperpageoption_ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² ÐœÐ° ÑÑÑÐ°ÐœÐžÑÐµ.}
+_textextlink_ [l=ru] {ÐÐŸÑÑÑÐ¿ Ðº Ð²ÐœÐµÑÐœÐžÐŒ ÑÐ·Ð»Ð°ÐŒ Web:}
+_textintlink_ [l=ru] {ÐÐ°ÐœÐœÑÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð²Ð·ÑÑ ÐžÐ·:}
+_textlanguage_ [l=ru] {Ð¯Ð·ÑÐº ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°:}
+_textencoding_ [l=ru] {ÐÐŸÐŽÐžÑÐŸÐ²ÐºÐ°:}
+_textformat_ [l=ru] {Ð€ÐŸÑÐŒÐ°Ñ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°:}
+_textall_ [l=ru] {Ð²ÑÐµ}
+_textquerymode_ [l=ru] {Ð¢ÐžÐ¿ Ð·Ð°Ð¿ÑÐŸÑÐ°:}
+_textsimplemode_ [l=ru] {Ð¿ÑÐŸÑÑÐ°Ñ ÑÐŸÑÐŒÐ° Ð·Ð°Ð¿ÑÐŸÑÐ°}
+_textadvancedmode_ [l=ru] {ÑÐ°ÑÑÐžÑÐµÐœÐœÐ°Ñ ÑÐŸÑÐŒÐ° Ð·Ð°Ð¿ÑÐŸÑÐ°(ÑÐ°Ð·ÑÐµÑÐµÐœ Ð»ÐŸÐ³ÐžÑÐµÑÐºÐžÐ¹ Ð¿ÐŸÐžÑÐº Ñ ÐŸÐ¿ÐµÑÐ°ÑÐžÑÐŒÐž ! (ÐÐ) , & (Ð), | (ÐÐÐ) , Ðž ÑÐºÐŸÐ±ÐºÐž)}
+_textlinkinterm_ [l=ru] {ÑÐµÑÐµÐ· Ð¿ÑÐŸÐŒÐµÐ¶ÑÑÐŸÑÐœÑÑ ÑÑÑÐ°ÐœÐžÑÑ}
+_textlinkdirect_ [l=ru] {Ð¿ÐµÑÐµÐ¹ÑÐž ÐœÐµÐ¿ÐŸÑÑÐµÐŽÑÑÐ²ÐµÐœÐœÐŸ Ðº}
+_textdigitlib_ [l=ru] {ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐ°Ñ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°}
+_textweb_ [l=ru] {Web}
+_textgraphical_ [l=ru] {ÐÑÐ°ÑÐžÑÐµÑÐºÐžÐ¹}
+_texttextual_ [l=ru] {TÐµÐºÑÑÐŸÐ²ÑÐ¹}
+_textcollectionoption_ [l=ru] {<p> ÐÐŸÐŽÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŽÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ: <br>}
+
+_textrelateddocdisplay_ [l=ru] {ÐŸÑÐŸÐ±ÑÐ°Ð¶Ð°ÑÑ ÑÑ
+ÐŸÐ¶ÐžÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ }
+_textsearchhistory_ [l=ru] {ÐÑÑÐŸÑÐžÑ Ð·Ð°Ð¿ÑÐŸÑÐ°:}
+_textnohistory_ [l=ru] {ÐÐžÐºÐ°ÐºÐŸÐ¹ ÐžÑÑÐŸÑÐžÐž Ð¿ÐŸÐžÑÐºÐ°}
+_texthistorydisplay_ [l=ru] {ÐŸÑÐŸÐ±ÑÐ°Ð¶Ð°ÑÑ _historynumrecords_ ÐžÑÑÐŸÑÐžÑ Ð·Ð°Ð¿ÑÐŸÑÐ°}
+_textnohistorydisplay_ [l=ru] {ÐœÐµ ÐŸÑÐŸÐ±ÑÐ°Ð¶Ð°ÑÑ ÐžÑÑÐŸÑÐžÑ Ð·Ð°Ð¿ÑÐŸÑÐ°}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=ru] {ÐÐŸÐžÑÐº Ð¿ÐŸ ÑÐŸÑÐŒÐµ}
+_textplainsearch_ [l=ru] {ÐÑÐŸÑÑÐŸÐ¹ Ð¿ÐŸÐžÑÐº:}
+_textqueryboxsize_ [l=ru] {Ð Ð°Ð·ÐŒÐµÑ ÐŸÐºÐœÐ° ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°:}
+_textregbox_ [l=ru] {ÐŸÐ±ÑÑÐœÐŸÐµ ÐŸÐºÐœÐŸ ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°}
+_textbigbox_ [l=ru] {Ð±ÐŸÐ»ÑÑÐŸÐµ ÐŸÐºÐœÐŸ ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°}
+_textformtype_ [l=ru] {Ð¢ÐžÐ¿ ÑÐŸÑÐŒÑ:}
+_textsimple_ [l=ru] {Ð¿ÑÐŸÑÑÐ°Ñ}
+_textadvanced_ [l=ru] {ÑÐ°ÑÑÐžÑÐµÐœÐœÐ°Ñ}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=ru] {ÐžÐ·}
+_textfields_ [l=ru] {Ð¿ÐŸÐ»Ñ}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐœÐ°ÑÑÑÐŸÐ¹ÐºÐž" ## green_title ## h_pref ##
+_httpiconhpref_ [l=ru] {_httpimg_/ru/h\_pref.gif}
+_widthhpref_ [l=ru] {200}
+_heighthpref_ [l=ru] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=ru] {Ð¡ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ð¿ÐŸ}
+_textalsoshowing_ [l=ru] {ÑÐ°ÐºÐ¶Ðµ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÑ}
+_textwith_ [l=ru] {Ñ ÑÐ°ÐŒÑÐŒ Ð±ÐŸÐ»ÑÑÐžÐŒ}
+_textdocsperpage_ [l=ru] {ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² ÐœÐ° ÑÑÑÐ°ÐœÐžÑÐµ}
+
+_textfilterby_ [l=ru] {ÐÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐžÐµ}
+_textall_ [l=ru] {Ð²ÑÐµ}
+_textany_ [l=ru] {Ð»ÑÐ±ÐŸÐ¹}
+_textwords_ [l=ru] {ÐžÐ· ÑÐ»ÐŸÐ²}
+_textleaveblank_ [l=ru] {ÐŸÑÑÐ°Ð²ÐžÑÑ ÑÑÐŸÑ Ð¿ÑÑÑÐŸÐ¹ ÑÑÐžÐº, ÑÑÐŸÐ±Ñ Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð²ÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ}
+
+_browsebuttontext_ [l=ru] {"ÐÐžÐŽ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²"}
+
+_nodata_ [l=ru] {<i>ÐœÐµÑ ÐŽÐ°ÐœÐœÑÑ
+</i>}
+_docs_ [l=ru] {ÐŽÐŸÐºÑÐŒÐµÐœÑÑ}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=ru] {ÐÐŸÐŒÐŸÑÑ}
+_textSearchshort_ [l=ru] {Ð¿ÐŸÐžÑÐº Ð¿ÐŸ ÑÐ¿ÐµÑÐžÐ°Ð»ÑÐœÑÐŒ ÑÐµÑÐŒÐžÐœÐ°ÐŒ}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ ÑÐ°Ð±ÐŸÑ}
+_textCreatorshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð°Ð²ÑÐŸÑÐ°ÐŒ}
+_textSubjectshort_ [l=ru] {ÐÑÐµÐŽÐŒÐµÑÐœÑÐ¹ ÑÐºÐ°Ð·Ð°ÑÐµÐ»Ñ}
+_textDescriptionshort_ [l=ru] {Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ}
+_textPublishershort_ [l=ru] {Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÐžÐ·ÐŽÐ°ÑÐµÐ»Ñ}
+_textContributorshort_ [l=ru] {ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÑÑÐ°ÑÑÐœÐžÐºÐ°ÐŒ}
+_textDateshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐŽÐ°ÑÐ°ÐŒ}
+_textTypeshort_ [l=ru] {Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÑÐžÐ¿Ð°ÐŒ}
+_textFormatshort_ [l=ru] {Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÑÐŸÑÐŒÐ°ÑÑ}
+_textIdentifiershort_ [l=ru] {Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°ÐŒ}
+_textSourceshort_ [l=ru] {ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÐžÐŒÐµÐœÐž ÑÐ°Ð¹Ð»Ð°}
+_textLanguageshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐ·ÑÐºÐ°ÐŒ}
+_textRelationshort_ [l=ru] {Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÑÐ²ÑÐ·ÑÐŒ}
+_textCoverageshort_ [l=ru] {Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÐŸÑ
+Ð²Ð°ÑÑ}
+_textRightsshort_ [l=ru] {Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ Ð¿ÑÐ°Ð²Ð°ÐŒ}
+
+_textSeriesshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð²ÑÐ¿ÑÑÐºÐ°ÐŒ}
+_textToshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð¿ÐŸÐ»ÑÑÐ°ÑÐµÐ»ÑÐŒ}
+_textFromshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐŸÑÐ¿ÑÐ°Ð²ÐžÑÐµÐ»ÑÐŒ}
+_textBrowseshort_ [l=ru] {ÐÑÐŸÑÐŒÐŸÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²}
+_textOrganizationshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑÐŒ}
+_textHowtoshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐ¿ÐŸÑÐŸÐ±Ñ Ð¿ÑÐžÐŒÐµÐœÐµÐœÐžÑ}
+_textTopicshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐµÐŒÐ°ÐŒ}
+_textPeopleshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÑÐŒ}
+_textAcronymshort_ [l=ru] {ÐÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð°ÐºÑÐŸÐœÐžÐŒÐ°ÐŒ}
+_textPhraseshort_ [l=ru] {Ð¿ÑÐŸÑÐŒÐŸÑÑ ÑÑÐ°Ð·, Ð²ÑÑÑÐµÑÐ°ÑÑÐžÑ
+ÑÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+_textArtistshort_ [l=ru] {ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÑÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ/ÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ñ}
+_textKeywordshort_ [l=ru] {ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÐºÐ»ÑÑÐµÐ²ÑÐŒ ÑÐ»ÐŸÐ²Ð°ÐŒ}
+_textVolumeshort_ [l=ru] {ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÐžÐ·ÐŽÐ°ÐœÐžÑÐŒ}
+_textCountriesshort_ [l=ru] {ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÑÑÑÐ°ÐœÐ°ÐŒ}
+_textdefaultshorttext_ [l=ru] {ÐœÐµÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÐ°Ñ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÑ}
+
+_textSearchlong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÑÑÑÐµÑÑÐ²ÐžÑÑ <i>Ð¿ÐŸÐžÑÐº Ð¿ÐŸ ÑÐ¿ÐµÑÐžÐ°Ð»ÑÐœÑÐŒ ÑÐµÑÐŒÐžÐœÐ°ÐŒ</i> ÑÐŸ ÑÑÑÐ°ÐœÐžÑÑ Ð¿ÐŸÐžÑÐºÐ°. Ð­ÑÐ° ÑÑÑÐ°ÐœÐžÑÐ° ÑÐ²Ð»ÑÐµÑÑÑ ÑÑÐ°ÑÑÐŸÐ²ÐŸÐ¹, ÐºÐŸÐ³ÐŽÐ° Ð²Ñ ÐœÐ°ÑÐžÐœÐ°ÐµÑÐµ ÑÐ°Ð±ÐŸÑÐ°ÑÑ Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹, Ðž ÐœÐ° ÐœÐµÐµ ÐŒÐŸÐ¶ÐœÐŸ Ð¿ÐŸÐ¿Ð°ÑÑÑ Ñ Ð»ÑÐ±ÑÑ
+ ÐŽÑÑÐ³ÐžÑ
+ ÑÑÑÐ°ÐœÐžÑ Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐœÐ°Ð¶Ð°ÑÐžÑ ÐºÐœÐŸÐ¿ÐºÐž <i>ÐÐŸÐžÑÐº</i>.}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑÐŒ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²</i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>ÐÐ°Ð·Ð²Ð°ÐœÐžÑ Ð-Ð¯</i>. Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº ÐºÐœÐžÐ³ Ð² Ð°Ð»ÑÐ°Ð²ÐžÑÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹. }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð°Ð²ÑÐŸÑÐ°ÐŒ</i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>ÐÐ²ÑÐŸÑÑ Ð-Ð¯</i>. Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ Ð¿ÐŸ ÑÐ°ÐŒÐžÐ»ÐžÑÐŒ Ð°Ð²ÑÐŸÑÐŸÐ². }
+
+_textSubjectlong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÑÐ°Ð±ÐŸÑÐ°ÑÑ Ñ <i>Ð¿ÑÐµÐŽÐŒÐµÑÐœÑÐŒ ÑÐºÐ°Ð·Ð°ÑÐµÐ»ÐµÐŒ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</i> , ÐœÐ°Ð¶Ð°Ð² ÐºÐœÐŸÐ¿ÐºÑ <i>Ð£ÐºÐ°Ð·Ð°ÑÐµÐ»Ñ</i>.  ÐÑÐµÐŽÐŒÐµÑÐœÑÐ¹ ÑÐºÐ°Ð·Ð°ÑÐµÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœ Ð¿ÐŸ ÐžÐµÑÐ°ÑÑ
+ÐžÑÐµÑÐºÐŸÐŒÑ Ð¿ÑÐžÐœÑÐžÐ¿Ñ, Ðž ÐŽÐ°ÐµÑ ÐœÐ°ÐžÐ±ÐŸÐ»ÐµÐµ Ð¿ÐŸÐ»ÐœÐŸÐµ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. }
+
+_textDescriptionlong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐžÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ</i> Ð¿ÑÐž ÐœÐ°Ð¶Ð°ÑÐžÐž ÐºÐœÐŸÐ¿ÐºÐž <i>ÐŸÐ¿ÐžÑÐ°ÐœÐžÐµ</i>. Ð­ÑÐŸ Ð²ÑÐŽÐ°ÑÑ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÑÐ¿ÐžÑÐŸÐº ÐŸÐ¿ÐžÑÐ°ÐœÐžÐ¹.}
+
+_textPublisherlong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐžÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÐžÐ·ÐŽÐ°ÑÐµÐ»ÑÐŒ</i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>ÐžÐ·ÐŽÐ°ÑÐµÐ»Ðž</i> . ÐÑÐŽÐµÑ Ð²ÑÐŽÐ°Ðœ ÑÐ¿ÐžÑÐŸÐº ÐžÐ·ÐŽÐ°ÑÐµÐ»ÐµÐ¹ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ°.}
+
+_textContributorlong_ [l=ru] {<p>ÐÐŸÐ»ÑÑÐžÑÑ <i>ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÑÑÐ°ÑÑÐœÐžÐºÑ</i> ÐœÐ°Ð¶Ð°Ð² ÐºÐœÐŸÐ¿ÐºÑ <i>ÑÑÐ°ÑÑÐœÐžÐºÐž</i>. Ð­ÑÐŸ Ð¿ÑÐžÐ²ÐµÐŽÐµÑ Ðº Ð²ÑÐŽÐ°ÑÐµ ÑÐ¿ÐžÑÐºÐ° ÑÑÐ°ÑÑÐœÐžÐºÐŸÐ².}
+
+_textDatelong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐŽÐ°ÑÐ°ÐŒ</i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>ÐÐ°ÑÑ</i>. Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº ÐŒÐ°ÑÐµÑÐžÐ°Ð»ÐŸÐ² Ð² Ñ
+ÑÐŸÐœÐŸÐ»ÐŸÐ³ÐžÑÐµÑÐºÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ. }
+
+_textTypelong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐžÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÑÐžÐ¿Ð°ÐŒ</i> Ð¿ÑÐž ÐœÐ°Ð¶Ð°ÑÐžÐž ÐºÐœÐŸÐ¿ÐºÐž <i>ÑÐžÐ¿Ñ</i> . Ð­ÑÐŸ Ð²ÑÐŽÐ°ÑÑ ÑÐ¿ÐžÑÐŸÐº ÑÐžÐ¿ÐŸÐ² ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ°.}
+
+_textFormatlong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐžÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÑÐŸÑÐŒÐ°ÑÑ</i> Ð¿ÑÐž ÐœÐ°Ð¶Ð°ÑÐžÐž ÐºÐœÐŸÐ¿ÐºÐž <i>ÑÐŸÑÐŒÐ°ÑÑ</i. Ð­ÑÐŸ Ð²ÑÐŽÐ°ÑÑ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÑÐ¿ÐžÑÐŸÐº ÑÐŸÑÐŒÐ°ÑÐŸÐ².}
+
+_textIdentifierlong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐžÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°ÐŒ</i> Ð¿ÑÐž ÐœÐ°Ð¶Ð°ÑÐžÐž ÐºÐœÐŸÐ¿ÐºÐž <i>ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÑ</i>.ÐÐŸÐ»ÑÑÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ² ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ°.}
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ<i>Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÑÑÑÐ¿ Ðº <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÐžÐŒÐµÐœÐ°ÐŒ ÑÐ°Ð¹Ð»ÐŸÐ²</i>  ÐœÐ°Ð¶ÐžÐŒÐ°Ñ ÐºÐœÐŸÐ¿ÐºÑ <i>ÐžÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÐŸÐ²</i>. Ð­ÑÐŸ Ð²ÑÐ²ÐŸÐŽÐžÑ ÑÐ¿ÐžÑÐŸÐº Ð·Ð°Ð¿ÐžÑÐµÐ¹, ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ Ð¿ÐŸ ÐŸÑÐžÐ³ÐžÐœÐ°Ð»ÑÐœÑÐŒ ÐžÐŒÐµÐœÐ°ÐŒ ÑÐ°Ð¹Ð»ÐŸÐ².  }
+
+_textLanguagelong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐ·ÑÐºÐ°ÐŒ</i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>Ð¯Ð·ÑÐºÐž</i>. Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº ÑÑÐ°ÑÐµÐ¹, ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ Ð¿ÐŸ ÑÐ·ÑÐºÐ°ÐŒ.}
+
+_textRelationlong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐžÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÑÐ²ÑÐ·ÑÐŒ</i> Ð¿ÑÐž ÐœÐ°Ð¶Ð°ÑÐžÐž ÐºÐœÐŸÐ¿ÐºÐž <i>ÑÐ²ÑÐ·Ðž</i> . Ð­ÑÐŸ Ð²ÑÐŽÐ°ÑÑ ÑÐ¿ÐžÑÐŸÐº ÑÐ²ÑÐ·ÐµÐ¹ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ°.}
+
+_textCoveragelong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐžÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ ÐŸÑ
+Ð²Ð°ÑÑ</i> Ð¿ÑÐž ÐœÐ°Ð¶Ð°ÑÐžÐž ÐºÐœÐŸÐ¿ÐºÐž </i>ÐŸÑ
+Ð²Ð°Ñ</i>. }
+
+_textRightslong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐžÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž Ð¿ÐŸ Ð¿ÑÐ°Ð²Ð°ÐŒ</i> Ð¿ÑÐž ÐœÐ°Ð¶Ð°ÑÐžÐž ÐºÐœÐŸÐ¿ÐºÐž <i>Ð¿ÑÐ°Ð²Ð°</i>.}
+
+
+
+_textOrganizationlong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑÐŒ</i>  ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>ÐÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÐž</i>. Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÐ¹. }
+
+_textHowtolong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐ¿ÐŸÑÐŸÐ±Ð°ÐŒ Ð¿ÑÐžÐŒÐµÐœÐµÐœÐžÑ</i> 
+ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>Ð¡Ð¿ÐŸÑÐŸÐ±Ñ</i>.  Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐžÑ
+ ÑÐµÐºÐŸÐŒÐµÐœÐŽÐ°ÑÐžÐ¹, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐžÑ
+ÑÑ Ð² ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°Ñ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.  }
+
+_textTopiclong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÐµÐŒÐ°ÐŒ</i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ  ÐºÐœÐŸÐ¿ÐºÐž <i>Ð¢ÐµÐŒÑ</i>. Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº ÑÐµÐŒ. }
+
+_textTolong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ<i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð¿ÐŸÐ»Ñ "ÐÐŸÐŒÑ"</i>, ÐœÐ°Ð¶Ð°Ð² ÐºÐœÐŸÐ¿ÐºÑ <i>ÐÐŸÐŒÑ</i>.  Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº Ð¿ÐŸÐ»ÑÑÐ°ÑÐµÐ»ÐµÐ¹.  }
+
+_textFromlong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð¿ÐŸÐ»Ñ "ÐŸÑÐ¿ÑÐ°Ð²ÐžÑÐµÐ»Ðž"</i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>ÐÑ ÐºÐŸÐ³ÐŸ</i>. Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº ÐŸÑÐ¿ÑÐ°Ð²ÐžÑÐµÐ»ÐµÐ¹.  }
+
+_textSerieslong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ<i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð²ÑÐ¿ÑÑÐºÐ°ÐŒ</i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>ÐÑÐ¿ÑÑÐºÐž</i>. Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº Ð²ÑÐ¿ÑÑÐºÐŸÐ²/ÑÐµÑÐžÐ¹, ÐºÐŸÑÐŸÑÑÐµ ÐžÐŒÐµÑÑÑÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. }
+
+_textBrowselong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ <i>Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž</i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÑ 
+<i>ÐÑÐŸÑÐŒÐŸÑÑ</i>. }
+
+_textPeoplelong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð¿ÐµÑÑÐŸÐœÐ°Ð»ÐžÑÐŒ</i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>ÐÐµÑÑÐŸÐœÐ°Ð»ÐžÐž Ð-Ð¯</i>. Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº ÐŒÐ°ÑÐµÑÐžÐ°Ð»ÐŸÐ², ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ Ð¿ÐŸ ÑÐ°ÐŒÐžÐ»ÐžÑÐŒ. }
+
+_textAcronymlong_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ<i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ Ð²Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÑ Ð°ÐºÑÐŸÐœÐžÐŒÐŸÐ² </i> ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>ÐÐºÑÐŸÐœÐžÐŒÑ</i>. Ð ÑÑÐŸÐŒ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐž Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÐ¿ÐžÑÐŸÐº Ð°ÐºÑÐŸÐœÐžÐŒÐŸÐ², Ðž ÐŒÐµÑÑ Ð³ÐŽÐµ ÐŸÐœÐž Ð²ÑÑÑÐµÑÐ°ÑÑÑÑ.}
+
+_textPhraselong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸ ÑÑÐ°Ð·Ð°ÐŒ, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐžÐŒÑÑ Ð² Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÑ
+</i> , ÐœÐ°Ð¶Ð°ÑÐžÐµÐŒ ÐºÐœÐŸÐ¿ÐºÐž <i>Ð€ÑÐ°Ð·Ñ</i>.  ÐÐ»Ñ ÑÑÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŸÐ±ÐŸÐ·ÑÐµÐ²Ð°ÑÐµÐ»Ñ ÑÑÐ°Ð·.  }
+
+_textArtistlong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ<i>ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ </i>
+ÐœÐ°Ð¶ÐžÐŒÐ°Ñ <i>ÐºÐœÐŸÐ¿ÐºÑ</i> ÑÐŸÐ·ÐŽÐ°ÑÐµÐ»Ðž/ÐžÑÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»Ðž. Ð­ÑÐŸ Ð²ÑÐŽÐ°ÐµÑ ÑÐ¿ÐžÑÐŸÐº Ð·Ð°Ð¿ÐžÑÐµÐ¹, ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÑ
+ Ð¿ÐŸ ÐžÑ
+ ÐžÐŒÐµÐœÐ°ÐŒ  }
+
+_textKeywordlong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ<i>Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÐºÐ»ÑÑÐµÐ²ÑÐŒ ÑÐ»ÐŸÐ²Ð°ÐŒ</i> ÐœÐ°Ð¶Ð°Ð² ÐºÐœÐŸÐ¿ÐºÑ <i>ÐºÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð°</i>. Ð ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐµ Ð±ÑÐŽÐµÑ Ð¿ÐŸÐ»ÑÑÐµÐœ ÑÐ¿ÐžÑÐŸÐº ÐºÐ»ÑÑÐµÐ²ÑÑ
+ ÑÐ»ÐŸÐ². }
+
+_textVolumelong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ <i>ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÐžÐ·ÐŽÐ°ÐœÐžÑÐŒ</i> ÐœÐ°Ð¶ÐžÐŒÐ°Ñ ÐºÐœÐŸÐ¿ÐºÑ <i>ÐžÐ·ÐŽÐ°ÐœÐžÑ</i>. ÐÑÐŽÐµÑ Ð²ÑÐŽÐ°Ðœ ÑÐ¿ÐžÑÐŸÐº ÐžÐ·ÐŽÐ°ÐœÐžÐ¹. }
+
+_textCaptionslong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ <i> ÐžÐŒÐµÑÑ ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐ°ÐŒ</i>, ÐœÐ°Ð¶ÐžÐŒÐ°Ñ ÐºÐœÐŸÐ¿ÐºÑ<i>Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž</i>. Ð­ÑÐŸ Ð¿ÑÐžÐ²ÐµÐŽÐµÑ Ðº Ð²ÑÐ²ÐŸÐŽÑ ÑÐ¿ÐžÑÐºÐ° Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐŸÐ². }
+
+_textCountrieslong_ [l=ru] {<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ <i>Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÑÑÑÐ¿ Ðº Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑÐŒ Ð¿ÐŸ ÑÑÑÐ°ÐœÐ°ÐŒ</i>,  ÐœÐ°Ð¶ÐžÐŒÐ°Ñ ÐºÐœÐŸÐ¿ÐºÑ<i>ÑÑÑÐ°ÐœÑ</i>. Ð­ÑÐŸ Ð¿ÑÐžÐ²ÐµÐŽÐµÑ Ðº Ð²ÑÐ²ÐŸÐŽÑ ÑÐ¿ÐžÑÐºÐ° ÑÑÑÐ°Ðœ. }
+
+
+_textdefaultlongtext_ [l=ru] {<p>ÐÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ°  ÐºÐœÐŸÐ¿ÐºÑ <i>ÐœÐµÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÐ°Ñ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÑ</i> ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÑÑÐ°ÑÐµÐ¹, ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÑ
+ Ð¿ÐŸ ÐœÐµÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÐŸÐŒÑ Ð¿ÐŸÐ»Ñ. }
+
+_texthelptopics_ [l=ru] {<h2 align=left>Ð Ð°Ð·ÐŽÐµÐ»Ñ</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">ÐÐ°Ðº ÐŸÑÑÑÐµÑÑÐ²Ð»ÑÑÑ Ð¿ÐŸÐžÑÐº Ð¿ÐŸ ÑÐ¿ÐµÑÐžÐ°Ð»ÑÐœÑÐŒ ÑÐµÑÐŒÐžÐœÐ°ÐŒ</a>
+<ul>
+  <li><a href="\#query-terms">Ð¡Ð»ÐŸÐ²Ð° ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°</a>
+  <li><a href="\#query-type">Ð¢ÐžÐ¿ Ð·Ð°Ð¿ÑÐŸÑÐ°</a>
+  <li><a href="\#scope-of-queries">ÐÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÐž Ð·Ð°Ð¿ÑÐŸÑÐ°</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</a>
+  <li><a href="\#lang-prefs">ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž ÑÐ·ÑÐºÐ°</a>
+  <li><a href="\#pres-prefs">ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°</a>
+  <li><a href="\#search-prefs">ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž Ð¿ÐŸÐžÑÐºÐ°</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=ru] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=ru] {ÐÐ°Ðº ÑÐ°Ð±ÐŸÑÐ°ÑÑ Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒÐž}
+
+_texthelpreadingdocs_ [l=ru] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>ÐÐŸÐ³ÐŽÐ° Ð²Ñ ÐŸÑÐºÑÐŸÐµÑÐµ ÐºÐ°ÐºÐŸÐ¹-ÐœÐžÐ±ÑÐŽÑ ÐŽÐŸÐºÑÐŒÐµÐœÑ, ÐÑ ÑÐ²ÐžÐŽÐžÑÐµ ÐµÐ³ÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ, Ð° ÑÐ°ÐºÐ¶Ðµ ÐžÐŒÑ Ð°Ð²ÑÐŸÑÐ° Ð² Ð»ÐµÐ²ÐŸÐŒ Ð²ÐµÑÑ
+ÐœÐµÐŒ ÑÐ³Ð»Ñ ÑÑÑÐ°ÐœÐžÑÑ. ÐÑÐŸÐŒÐµ ÑÑÐŸÐ³ÐŸ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐœÐ°Ð¹ÑÐž ÐœÐŸÐŒÐµÑ ÑÑÑÐ°ÐœÐžÑÑ, ÑÑÑÐµÐ»ÐºÐž Ð²Ð¿ÐµÑÐµÐŽ Ðž ÐœÐ°Ð·Ð°ÐŽ, ÐºÐœÐŸÐ¿ÐºÑ ÐŽÐ»Ñ Ð²ÑÐ±ÐŸÑÐ° ÐœÐŸÐ²ÐŸÐ¹ ÑÑÑÐ°ÐœÐžÑÑ.
+
+<p>ÐÐžÐ¶Ðµ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ ÑÐµÐºÑÑ ÑÐµÐºÑÑÐµÐ³ÐŸ ÑÐ°Ð·ÐŽÐµÐ»Ð°. ÐÐŸÑÐ»Ðµ ÑÐŸÐ³ÐŸ, ÐºÐ°Ðº Ð²Ñ Ð¿ÑÐŸÑÐžÑÐ°ÐµÑÐµ ÐµÐ³ÐŸ, Ð²ÐœÐžÐ·Ñ Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÑÑÑÐµÐ»ÐºÐž ÐŽÐ»Ñ Ð¿ÐµÑÐµÑ
+ÐŸÐŽÐ° Ðº ÑÐ»ÐµÐŽÑÑÑÐµÐŒÑ ÐžÐ»Ðž Ð¿ÑÐµÐŽÑÐŽÑÑÐµÐŒÑ ÑÐ°Ð·ÐŽÐµÐ»Ñ.
+
+<p>ÐÐžÐ¶Ðµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° Ðž ÐµÐ³ÐŸ Ð°Ð²ÑÐŸÑÐ° ÐœÐ°Ñ
+ÐŸÐŽÑÑÑ ÑÑÐž ÐºÐœÐŸÐ¿ÐºÐž. ÐÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° <i>ÐÐµÑÑ ÑÐµÐºÑÑ</i> ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ, ÑÑÐŸÐ±Ñ ÐŸÑÐŸÐ±ÑÐ°Ð·ÐžÑÑ ÐœÐ° ÑÐºÑÐ°ÐœÐµ Ð²ÐµÑÑ ÑÐµÐºÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°. ÐÑÐ»Ðž ÐŽÐŸÐºÑÐŒÐµÐœÑ ÐŽÐŸÑÑÐ°ÑÐŸÑÐœÐŸ Ð±ÐŸÐ»ÑÑÐŸÐ¹, ÑÐŸ ÑÑÐŸ ÐŒÐŸÐ¶ÐµÑ Ð·Ð°ÐœÑÑÑ ÐœÐµÐºÐŸÑÐŸÑÐŸÐµ Ð²ÑÐµÐŒÑ Ðž Ð¿ÑÐžÐ»ÐžÑÐœÑÐ¹ ÐŸÐ±ÑÐµÐŒ Ð¿Ð°ÐŒÑÑÐž!
+ÐÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° <i>Ð ÐœÐŸÐ²ÐŸÐŒ ÐŸÐºÐœÐµ</i>, ÑÑÐŸÐ±Ñ ÐŸÑÐŸÐ±ÑÐ°Ð·ÐžÑÑ ÐŽÐ°ÐœÐœÑÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð² ÐœÐŸÐ²ÐŸÐŒ ÐŸÐºÐœÐµ (ÑÑÐŸ Ð±ÑÐ²Ð°ÐµÑ Ð¿ÐŸÐ»ÐµÐ·ÐœÐŸ, ÐµÑÐ»Ðž Ð²Ñ Ñ
+ÐŸÑÐžÑÐµ ÑÑÐ°Ð²ÐœÐžÑÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² ÐžÐ»Ðž ÑÐžÑÐ°ÑÑ ÐŽÐ²Ð° ÑÑÐ°Ð·Ñ).  ÐÐ°ÐºÐŸÐœÐµÑ, ÐµÑÐ»Ðž Ð²Ñ ÐœÐ°ÑÐ»Ðž ÑÑÐŸÑ ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð¿ÐŸ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÐŒ ÑÐ»ÐŸÐ²Ð°ÐŒ, ÑÐŸ ÐŸÐœÐž Ð±ÑÐŽÑÑ Ð²ÑÐŽÐµÐ»ÐµÐœÑ Ð² ÑÐµÐºÑÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°.  ÐÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° <i>Ð¡ÐœÑÑÑ Ð²ÑÐŽÐµÐ»ÐµÐœÐžÐµ</i> ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ, ÑÑÐŸÐ±Ñ ÐžÑÐºÐŸÐŒÑÐµ ÑÐ»ÐŸÐ²Ð° ÐœÐµ Ð²ÑÐŽÐµÐ»ÑÐ»ÐžÑÑ Ð² ÑÐµÐºÑÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°.
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>ÐÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° ÑÑÑÐµÐ»ÐºÑ, ÑÑÐŸÐ±Ñ Ð¿ÐµÑÐµÐ¹ÑÐž Ðº ÑÐ»ÐµÐŽÑÑÑÐµÐŒÑ ÑÐ°Ð·ÐŽÐµÐ»Ñ ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... ÐžÐ»Ðž ÐœÐ°Ð·Ð°ÐŽ, ÑÑÐŸÐ±Ñ Ð²ÐµÑÐœÑÑÑÑÑ Ðº Ð¿ÑÐµÐŽÑÐŽÑÑÐµÐŒÑ</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>ÐÑÐŸÐ±ÑÐ°Ð·ÐžÑÑ Ð²ÐµÑÑ ÑÐµÐºÑÑ ÐžÐ»Ðž ÐœÐµÑ</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>ÐÑÐºÑÑÑÑ ÑÑÑ ÑÑÑÐ°ÐœÐžÑÑ Ð² ÐœÐŸÐ²ÐŸÐŒ ÐŸÐºÐœÐµ</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>ÐÑÐŽÐµÐ»ÑÑÑ ÐžÑÐºÐŸÐŒÑÐµ ÑÐ»ÐŸÐ²Ð° ÐžÐ»Ðž ÐœÐµÑ</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=ru] {<h2>ÐÐ°Ðº ÐŸÑÑÑÐµÑÑÐ²Ð»ÑÑÑ Ð¿ÐŸÐžÑÐº Ð¿ÐŸ ÑÐ¿ÐµÑÐžÐ°Ð»ÑÐœÑÐŒ ÑÐµÑÐŒÐžÐœÐ°ÐŒ</h2>
+<p>
+  ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐŽÐµÐ»Ð°ÑÑ Ð¿ÑÐŸÑÑÐŸÐ¹ Ð·Ð°Ð¿ÑÐŸÑ ÑÐŸ ÑÑÑÐ°ÐœÐžÑÑ Ð¿ÐŸÐžÑÐºÐ°, ÑÐŸÐ³Ð»Ð°ÑÐœÐŸ ÑÐ»ÐµÐŽÑÑÑÐžÐŒ ÑÐ°Ð³Ð°ÐŒ:
+<p> 
+  <ol>
+      <li>ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÐµ, ÑÑÐŸ Ð²Ñ Ñ
+ÐŸÑÐžÑÐµ ÐœÐ°Ð¹ÑÐž
+      <li>ÐÐ¿ÑÐµÐŽÐµÐ»ÐžÑÐµ, ÐºÐ°Ðº Ð²Ñ ÑÑÐŸ Ñ
+ÐŸÑÐžÑÐµ ÐžÑÐºÐ°ÑÑ: ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÑÑÐ°Ð·Ñ ÐžÐ»Ðž ÐŸÑÐŽÐµÐ»ÑÐœÑÐµ ÑÐ»ÐŸÐ²Ð°
+      <li>ÐÐ°Ð¿ÐµÑÐ°ÑÐ°Ð¹ÑÐµ ÑÐµÐºÑÑ Ð·Ð°Ð¿ÑÐŸÑÐ° Ð² ÑÑÑÐŸÐºÐµ Ð¿ÐŸÐžÑÐºÐ°
+      <li>ÐÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÑ <i>ÐÐ°ÑÐ°ÑÑ Ð¿ÐŸÐžÑÐº</i> 
+  </ol>
+
+<p>ÐÐŸÑÐ»Ðµ Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐžÑ Ð·Ð°Ð¿ÑÐŸÑÐ° ÐœÐ° ÑÐºÑÐ°ÐœÐµ Ð¿ÐŸÑÐ²ÐžÑÑÑ 20 ÐœÐ°ÐžÐŒÐµÐœÐŸÐ²Ð°ÐœÐžÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ². Ð ÐºÐŸÐœÑÐµ ÑÐ¿ÐžÑÐºÐ° ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ ÐºÐœÐŸÐ¿ÐºÐ°, Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐºÐŸÑÐŸÑÐŸÐ¹ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐµÑÐµÐ¹ÑÐž Ðº ÑÐ»ÐµÐŽÑÑÑÐžÐŒ 20.  ÐÐ° ÑÐ»ÐµÐŽÑÑÑÐžÑ
+ ÑÑÑÐ°ÐœÐžÑÐ°Ñ
+ ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐŸÐ² Ð²Ñ ÑÐ²ÐžÐŽÐžÑÐµ ÐºÐœÐŸÐ¿ÐºÐž ÐŽÐ»Ñ Ð¿ÐµÑÐµÑ
+ÐŸÐŽÐ° Ðº ÑÐ»ÐµÐŽÑÑÑÐžÐŒ 20 ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒ ÐžÐ»Ðž ÐŸÐ±ÑÐ°ÑÐœÐŸ Ðº Ð¿ÑÐµÐŽÑÐŽÑÑÐžÐŒ, Ðž Ñ.ÐŽ. ÐÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ Ð»ÑÐ±ÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÐžÐ»Ðž Ð·ÐœÐ°ÑÐŸÐº Ð¿ÐµÑÐµÐŽ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµÐŒ, ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ ÑÑÐŸÐ±Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ ÐµÐ³ÐŸ.
+
+<p>ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÑÐžÑÐ»ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐ° Ð¿ÐŸÐžÑÐºÐ° - 100. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÑÑÐŸ ÑÐžÑÐ»ÐŸ ÐœÐ° ÑÑÑÐ°ÐœÐžÑÐµ ÐœÐ°ÑÑÑÐŸÐµÐº ( ÐºÐœÐŸÐ¿ÐºÐ° <i>ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž</i> Ð²Ð²ÐµÑÑ
+Ñ ÑÑÑÐ°ÐœÐžÑÑ ).<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Ð¡Ð»ÐŸÐ²Ð° ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°</h3>
+
+<p>Ð¢ÐŸ, ÑÑÐŸ Ð²Ñ Ð²Ð²ÐŸÐŽÐžÑÐµ Ð² ÑÑÑÐŸÐºÐµ Ð·Ð°Ð¿ÑÐŸÑÐ°, ÐœÐ°Ð·ÑÐ²Ð°ÐµÑÑÑ "ÑÐ»ÐŸÐ²Ð°ÐŒÐž ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°". ÐÐ°Ð¶ÐŽÐŸÐµ ÑÐ»ÐŸÐ²ÐŸ ÑÐŸÐŽÐµÑÐ¶ÐžÑ Ð±ÑÐºÐ²Ñ Ðž ÑÐžÑÑÑ. Ð¡Ð»ÐŸÐ²Ð° ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÑ Ð¿ÑÐŸÐ±ÐµÐ»Ð°ÐŒÐž. ÐÑÐ»Ðž ÐžÐŒÐµÐµÑÑÑ ÐºÐ°ÐºÐŸÐ¹-Ð»ÐžÐ±ÐŸ ÐŽÑÑÐ³ÐŸÐ¹ Ð·ÐœÐ°Ðº, ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, Ð·ÐœÐ°ÐºÐž Ð¿ÑÐœÐºÑÑÐ°ÑÐžÐž, ÑÐŸ ÐŸÐœÐž ÑÐ»ÑÐ¶Ð°Ñ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÑÐ°Ð·ÐŽÐµÐ»ÐžÑÐµÐ»ÐµÐ¹ ÑÐ»ÐŸÐ², ÐºÐ°Ðº Ðž Ð¿ÑÐŸÐ±ÐµÐ»Ñ, ÑÐŸ ÐµÑÑÑ ÐžÐ³ÐœÐŸÑÐžÑÑÑÑÑÑ. ÐÑ ÐœÐµ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÑÑÑÐµÑÑÐ²ÐžÑÑ Ð¿ÐŸÐžÑÐº Ð¿ÐŸ ÑÐ»ÐŸÐ²Ð°ÐŒ, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐžÐŒ Ð·ÐœÐ°ÐºÐž Ð¿ÑÐœÐºÑÑÐ°ÑÐžÐž.
+
+<p>ÐÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐ°ÑÑÐŒÐŸÑÑÐžÐŒ Ð·Ð°Ð¿ÑÐŸÑ<p>
+    <ul><kbd>Ð¡ÐµÐ»ÑÑÐºÐŸ-Ð»ÐµÑÐœÐŸÐµ Ñ
+ÐŸÐ·ÑÐ¹ÑÑÐ²ÐŸ ÐœÐ° ÐŸÑÑÑÐŸÐ²Ð°Ñ
+ Ð¢ÐžÑ
+ÐŸÐ³ÐŸ ÐŸÐºÐµÐ°ÐœÐ°: Ð¡ÐžÑÑÐµÐŒÐ° Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÐž (1993)</kbd></ul>
+      <p>ÐŸÐœ Ð±ÑÐŽÐµÑ ÑÐ°Ð²ÐœÐŸÑÐžÐ»ÐµÐœ ÑÐ»ÐµÐŽÑÑÑÐµÐŒÑ<p>
+      <ul><kbd> Ð¡ÐµÐ»ÑÑÐºÐŸÐµ Ð»ÐµÑÐœÐŸÐµ Ñ
+ÐŸÐ·ÑÐ¹ÑÑÐ²ÐŸ ÐœÐ° ÐŸÑÑÑÐŸÐ²Ð°Ñ
+ Ð¢ÐžÑ
+ÐŸÐ³ÐŸ ÐŸÐºÐµÐ°ÐœÐ° Ð¡ÐžÑÑÐµÐŒÐ° Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÐž 1993</kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Ð¢ÐžÐ¿Ñ Ð·Ð°Ð¿ÑÐŸÑÐŸÐ²</h3>
+
+<p>Ð¡ÑÑÐµÑÑÐ²ÑÐµÑ ÐŽÐ²Ð° ÑÐ°Ð·Ð»ÐžÑÐœÑÑ
+ ÑÐžÐ¿Ð° Ð·Ð°Ð¿ÑÐŸÑÐ°.
+
+<ul>
+  <li>ÐÐ°Ð¿ÑÐŸÑÑ Ð¿ÐŸ <b>Ð²ÑÐµÐŒ</b> ÑÐ»ÐŸÐ²Ð°ÐŒ. Ð­ÑÐŸ Ð¿ÐŸÐŽÑ
+ÐŸÐŽÐžÑ ÐŽÐ»Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ Ð²ÑÐµ ÑÐ»ÐŸÐ²Ð°, ÐºÐŸÑÐŸÑÑÐµ Ð²Ñ Ñ
+ÐŸÑÐžÑÐµ Ð²ÐºÐ»ÑÑÐžÑÑ Ð² ÑÑÑÐŸÐºÑ Ð¿ÐŸÐžÑÐºÐ°.
+ÐÐŸÐºÑÐŒÐµÐœÑÑ, ÑÐŽÐŸÐ²Ð»ÐµÑÐ²ÐŸÑÑÑÑÐžÐµ Ð·Ð°Ð¿ÑÐŸÑÑ, Ð±ÑÐŽÑÑ Ð²ÑÐ²ÐµÐŽÐµÐœÑ Ð² Ð°Ð»ÑÐ°Ð²ÐžÑÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ.<p>
+
+  <li>ÐÐ°Ð¿ÑÐŸÑÑ Ð¿ÐŸ <b>ÐœÐµÐºÐŸÑÐŸÑÑÐŒ</b> ÑÐ»ÐŸÐ²Ð°ÐŒ. ÐÐŸÑÑÐ°ÑÐŸÑÐœÐŸ ÐœÐ°Ð¿ÐžÑÐ°ÑÑ Ð»ÐžÑÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÑÐ»ÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ, Ð²ÐµÑÐŸÑÑÐœÐŸ, ÐœÐ°Ñ
+ÐŸÐŽÑÑÑÑ Ð² ÑÐµÐºÑÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°.  ÐÐŸÐºÑÐŒÐµÐœÑÑ Ð±ÑÐŽÑÑ ÐŸÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÑ Ð² Ð¿ÐŸÑÑÐŽÐºÐµ ÑÐŒÐµÐœÑÑÐµÐœÐžÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÑ Ð·Ð°Ð¿ÑÐŸÑÑ. Ð¡ÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÐµ Ð·Ð°Ð¿ÑÐŸÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÑÑÑ ÑÐ°Ðº:
+      <p><ul>
+        <li> ÑÐµÐŒ Ð±ÐŸÐ»ÑÑÐµ ÐžÑÐºÐŸÐŒÑÑ
+ ÑÐµÑÐŒÐžÐœÐŸÐ² ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÐŽÐŸÐºÑÐŒÐµÐœÑ, ÑÐµÐŒ Ð±ÐŸÐ»ÑÑÐµ ÐŸÐœ Ð¿ÐŸÐŽÑ
+ÐŸÐŽÐžÑ;
+        <li> ÑÐµÐŽÐºÐžÐµ ÑÐ»ÐŸÐ²Ð° Ð±ÐŸÐ»ÐµÐµ Ð²Ð°Ð¶ÐœÑ, ÑÐµÐŒ ÐŸÐ±ÑÐžÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÑ;
+        <li> ÐŒÐ°Ð»ÐµÐœÑÐºÐžÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ð¿ÐŸÐŽÑ
+ÐŸÐŽÑÑ Ð»ÑÑÑÐµ, ÑÐµÐŒ Ð±ÐŸÐ»ÑÑÐžÐµ.
+      </ul>
+</ul>
+
+<p>ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÑÑÐŸÐ»ÑÐºÐŸ ÑÐ»ÐŸÐ² ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°, ÑÐºÐŸÐ»ÑÐºÐŸ Ð²Ð°ÐŒ ÑÐ³ÐŸÐŽÐœÐŸ - ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÑÐµÐ»ÐŸÐµ Ð¿ÑÐµÐŽÐ»ÐŸÐ¶ÐµÐœÐžÐµ, ÐžÐ»Ðž Ð¿Ð°ÑÐ°Ð³ÑÐ°Ñ.  ÐÑÐ»Ðž Ð²Ñ Ð²Ð²ÐµÐŽÐµÑÐµ ÑÐŸÐ»ÑÐºÐŸ ÐŸÐŽÐœÐŸ ÑÐ»ÐŸÐ²ÐŸ, ÑÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ð±ÑÐŽÑÑ ÑÐ°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÑ Ð¿ÐŸ ÑÐ±ÑÐ²Ð°ÐœÐžÑ ÑÐ°ÑÑÐŸÑÑ ÐµÐ³ÐŸ Ð¿ÐŸÑÐ²Ð»ÐµÐœÐžÑ.<p>_texthelpscope_}
+
+_textdatesearch_ [l=ru] {ÐÐŸÐžÑÐº Ð¿ÐŸ ÐŽÐ°ÑÐµ}
+
+_texthelpdatesearch_ [l=ru] {<h2>_textdatesearch_</h2>
+ÐÐŸÐžÑÐº Ð¿ÐŸ ÐŽÐ°ÑÐµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð²Ð°ÐŒ ÐœÐ°Ð¹ÑÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÑ, ÐŸÑÐœÐŸÑÑÑÐžÐµÑÑ Ðº ÑÐŸÐ±ÑÑÐžÑÐŒ, Ð¿ÑÐŸÑÐµÐŽÑÐžÐŒ Ð² ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÐŸÐŒ Ð²ÑÐµÐŒÐµÐœÐœÐŸÐŒ Ð¿ÑÐŸÐŒÐµÐ¶ÑÑÐºÐµ Ð¿ÐŸÐŽÐŸÐ±ÐœÐŸ ÑÐŸÐŒÑ, ÐºÐ°Ðº ÐœÐ°Ñ
+ÐŸÐŽÑÑÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ, ÑÐ²ÑÐ·Ð°ÐœÐœÑÐµ Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÐŒ Ð¿ÐŸÐžÑÐºÐŸÐ²ÑÐŒ ÑÐµÑÐŒÐžÐœÐŸÐŒ.  ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÑÑÑÐµÑÑÐ²ÐžÑÑ Ð¿ÐŸÐžÑÐº ÐºÐ°Ðº Ð¿ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒ, ÐŸÑÐœÐŸÑÑÑÐžÐŒÑÑ Ðº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÐŸÐŒÑ Ð³ÐŸÐŽÑ, ÑÐ°Ðº Ðž Ð¿ÐµÑÐžÐŸÐŽÑ Ð»ÐµÑ. <p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>ÐÐ°Ðº ÑÑÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ:</h3>
+<ul>
+   <li>ÐÐŸÐžÑÐº ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Ð¿ÐŸ ÐºÐŸÐœÐºÑÐµÑÐœÐŸÐ¹ ÐŽÐ°ÑÐµ:<p>
+   <ul>
+       <li>ÐÐ²ÐµÐŽÐžÑÐµ ÐŸÐ±ÑÐºÐœÐŸÐ²ÐµÐœÐœÑÐµ ÑÐ»ÐŸÐ²Ð° ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°. 
+       <li>ÐÐ²ÐµÐŽÐžÑÐµ ÐœÑÐ¶ÐœÑÐ¹ Ð³ÐŸÐŽ Ð² ÑÐŸÑÐŒÐµ "ÐÐ°ÑÐ°Ð»ÑÐœÐ°Ñ (ÐžÐ»Ðž ÐºÐŸÐœÐºÑÐµÑÐœÐ°Ñ) ÐŽÐ°ÑÐ°".
+       <li>ÐÑÐ»Ðž Ð²Ð°Ñ Ð³ÐŸÐŽ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ Ð² Ð¿ÐµÑÐžÐŸÐŽÐµ ÐŽÐŸ ÐœÐ°ÑÐµÐ¹ ÑÑÑ (ÐžÐ»Ðž ÐŽÐŸ Ð ÐŸÐ¶ÐŽÐµÑÑÐ²Ð° Ð¥ÑÐžÑÑÐŸÐ²Ð°), ÑÐŸ Ð²ÑÐ±ÐµÑÐžÑÐµ ÐŽÐ°Ð»ÐµÐµ "ÐÐŸ Ðœ.Ñ." ÐžÐ· Ð²ÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐ³ÐŸ ÐŒÐµÐœÑ.
+       <li>ÐÐ°ÑÐœÐžÑÐµ Ð¿ÐŸÐžÑÐº.
+   </ul>
+<p><li>ÐÐŸÐžÑÐº ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Ð¿ÐŸ Ð²ÑÐµÐŒÐµÐœÐœÐŸÐŒÑ Ð¿ÑÐŸÐŒÐµÐ¶ÑÑÐºÑ:<p>
+   <ul>
+       <li>ÐÐ²ÐµÐŽÐžÑÐµ ÐŸÐ±ÑÐºÐœÐŸÐ²ÐµÐœÐœÑÐµ ÑÐ»ÐŸÐ²Ð° ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°.
+       <li>ÐÐ²ÐµÐŽÐžÑÐµ ÐœÐ°ÑÐ°Ð»ÑÐœÑÐ¹ Ð³ÐŸÐŽ Ð² ÑÐŸÑÐŒÐµ "ÐÐ°ÑÐ°Ð»ÑÐœÐ°Ñ (ÐžÐ»Ðž ÐºÐŸÐºÑÐµÑÐœÐ°Ñ) ÐŽÐ°ÑÐ°". 
+       <li>ÐÐ²ÐµÐŽÐžÑÐµ ÐºÐŸÐœÐµÑÐœÑÐ¹ Ð³ÐŸÐŽ Ð² ÑÐŸÑÐŒÐµ "ÐÐŸÐœÐµÑÐœÐ°Ñ ÐŽÐ°ÑÐ°".
+       <li>ÐÑÐ±ÐµÑÐžÑÐµ "ÐÐŸ Ðœ.Ñ" ÐžÐ· Ð²ÑÐ¿Ð°ÐŽÐ°ÑÑÐµÐ³ÐŸ ÐŒÐµÐœÑ ÐŽÐ»Ñ Ð»ÑÐ±ÐŸÐ¹ ÐŽÐ°ÑÑ ÐžÐ· ÑÑÐŸÐ³ÐŸ Ð¿ÐµÑÐžÐŸÐŽÐ° (ÑÐ°ÐºÐ¶Ðµ ÐžÐ·Ð²ÐµÑÑÐœÐŸÐ³ÐŸ ÐºÐ°Ðº Ð¿ÐµÑÐžÐŸÐŽ ÐŽÐŸ Ð ÐŸÐ¶ÐŽÐµÑÑÐ²Ð° Ð¥ÑÐžÑÑÐŸÐ²Ð°).
+       <li>ÐÐ°ÑÐœÐžÑÐµ Ð¿ÐŸÐžÑÐº.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>ÐÐ°Ðº ÑÐ°Ð±ÐŸÑÐ°ÐµÑ Ð¿ÐŸÐžÑÐº Ð¿ÐŸ ÐŽÐ°ÑÐµ</h3>
+
+ÐÐ»Ñ Ð¿ÐŸÐ»ÑÑÐµÐœÐžÑ ÐœÐ°ÐžÐ±ÐŸÐ»ÐµÐµ Ð¿ÐŸÐ»ÐœÐŸÐ³ÐŸ ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐ° Ð·Ð°Ð¿ÑÐŸÑÐ° ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐžÐœÑÐµÑÐ²Ð°Ð»ÑÐœÑÐ¹ Ð·Ð°Ð¿ÑÐŸÑ, Ñ.Ðº. Ð² ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°Ñ
+ ÐŽÐ°ÑÐ° ÑÐ²ÐœÐŸ ÐœÐµ ÑÐºÐ°Ð·Ð°ÐœÐ° (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ ÐŒ.Ð±. ÑÐºÐ°Ð·Ð°Ðœ Ð²ÐµÐº, Ð° ÐœÐµ Ð³ÐŸÐŽ). 
+<p>
+}
+
+_textchangeprefs_ [l=ru] {ÐÐ·ÐŒÐµÐœÐµÐœÐžÐµ ÐœÐ°ÑÑÑÐŸÐµÐº}
+
+_texthelppreferences_ [l=ru] {<h2>_textchangeprefs_</h2>
+
+<p>ÐÐ° ÑÑÑÐ°ÐœÐžÑÐµ <i>ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž</i> (ÐºÐœÐŸÐ¿ÐºÐ° Ð² Ð²ÐµÑÑ
+ÐœÐµÐ¹ ÑÐ°ÑÑÐž ÑÑÑÐ°ÐœÐžÑÑ) Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÐœÐµÐºÐŸÑÐŸÑÑÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž</h3>
+
+ÐÐµÐºÐŸÑÐŸÑÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÑÐŸÐŽÐµÑÐ¶Ð°Ñ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ Ð¿ÐŸÐŽÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹, Ð¿ÐŸÐžÑÐº Ð¿ÐŸ ÐºÐŸÑÐŸÑÑÐŒ ÐŒÐŸÐ¶ÐµÑ ÐŸÑÑÑÐµÑÑÐ²Ð»ÑÑÑÑÑ ÐºÐ°Ðº Ð¿ÐŸ ÐºÐ°Ð¶ÐŽÐŸÐ¹ ÐžÐ· ÐœÐžÑ
+, ÑÐ°Ðº Ðž Ð¿ÐŸ Ð²ÑÐµÐŒ Ð²ÐŒÐµÑÑÐµ. ÐÐ° ÑÑÑÐ°ÐœÐžÑÐµ ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ ÑÐµ Ð¿ÐŸÐŽÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÐºÐŸÑÐŸÑÑÐµ Ð²Ñ Ñ
+ÐŸÑÐžÑÐµ Ð²ÐºÐ»ÑÑÐžÑÑ Ð² Ð¿ÐŸÐžÑÐº.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž ÑÐ·ÑÐºÐ°</h3>
+
+ÐÐ°Ð¶ÐŽÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐŒÐµÐµÑ ÑÑÐ°ÐœÐŽÐ°ÑÑÐœÑÐ¹ ÑÐ·ÑÐº ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°, ÐœÐŸ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ Ð»ÑÐ±ÐŸÐ¹ ÐŽÑÑÐ³ÐŸÐ¹.  Ð¢Ð°ÐºÐ¶Ðµ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ ÐŽÑÑÐ³ÑÑ ÐºÐŸÐŽÐžÑÐŸÐ²ÐºÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÑ Ð² ÐŽÐ°ÐœÐœÐŸÐ¹ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐµ, Ð¿ÐŸÐŽÑ
+ÐŸÐŽÑÑÑÑ ÐŽÐ»Ñ Ð²Ð°ÑÐµÐ³ÐŸ Ð±ÑÐ°ÑÐ·ÐµÑÐ° - Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž ÑÑÐ°Ð²ÐžÑÑÑ ÑÑÐ°ÐœÐŽÐ°ÑÑÐœÐ°Ñ, ÐœÐŸ ÐœÐ° ÐœÐµÐºÐŸÑÑÑÑ
+ Ð±ÑÐ°ÑÐ·ÐµÑÐ°Ñ
+ Ð»ÑÑÑÐµ Ð²ÑÐ±ÑÐ°ÑÑ ÐºÐŸÐŽÐžÑÐŸÐ²ÐºÑ Ð²ÑÑÑÐœÑÑ. ÐÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÑÑ ÑÐ°ÐºÐ¶Ðµ Ð¿ÐµÑÐµÐ¹ÑÐž ÐŸÑ Ð³ÑÐ°ÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÑÐµÐ¶ÐžÐŒÐ° Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° Ðº ÑÐµÐºÑÑÐŸÐ²ÐŸÐŒÑ, Ðž ÐœÐ°ÐŸÐ±ÐŸÑÐŸÑ. 
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°</h3>
+
+Ð Ð·Ð°Ð²ÐžÑÐžÐŒÐŸÑÑÐž ÐŸÑ ÐºÐ°Ð¶ÐŽÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ð² ÐœÐµÐ¹ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÑÐ°Ð·Ð»ÐžÑÐœÑÑ
+ ÐœÐ°ÑÑÑÐŸÐµÐº ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ°.
+
+<p>ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ Web ÑÑÑÐ°ÐœÐžÑ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð¿Ð°ÐœÐµÐ»Ñ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð²Ð²ÐµÑÑ
+Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°, ÑÐ°ÐºÐžÐŒ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ Ð¿ÐŸÑÐ»Ðµ Ð¿ÐŸÐžÑÐºÐ° Ð²Ñ ÑÑÐ°Ð·Ñ Ð¿ÐŸÐ¿Ð°ÐŽÐµÑÐµ ÐœÐ° Web-ÑÑÑÐ°ÐœÐžÑÑ Ð±ÐµÐ· Ð²ÑÑÐºÐŸÐ³ÐŸ Greenstone Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐ°.  Ð§ÑÐŸÐ±Ñ ÑÐŽÐµÐ»Ð°ÑÑ ÐœÐŸÐ²ÑÐ¹ Ð·Ð°Ð¿ÑÐŸÑ, ÐŽÐŸÑÑÐ°ÑÐŸÑÐœÐŸ ÐœÐ°Ð¶Ð°ÑÑ ÐºÐœÐŸÐ¿ÐºÑ "back" Ð² Ð²Ð°ÑÐµÐŒ Ð±ÑÐ°ÑÐ·ÐµÑÐµ. Ð¢Ð°ÐºÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÑÐ°ÐºÐ¶Ðµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÑÑ Ð·Ð°Ð¿ÑÐµÑÐ°ÑÑ ÑÐžÑÑÐµÐŒÐœÑÐµ ÐŸÑÐžÐ±ÐºÐž, ÐºÐŸÐ³ÐŽÐ° Ð²Ñ ÐœÐ°Ð¶ÐžÐŒÐ°ÐµÑÐµ ÐœÐ° ÑÑÑÐ»ÐºÐž, Ð²ÑÐ²ÐŸÐŽÑÑÐžÐµ Ð²Ð°Ñ Ð·Ð° ÑÐ°ÐŒÐºÐž ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž Ð² WWW. 
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>ÐÐ°ÑÑÑÐŸÐ¹ÐºÐž Ð¿ÐŸÐžÑÐºÐ°</h3>
+<p>ÐÐ²Ð° Ð¿ÐµÑÐµÐºÐ»ÑÑÐ°ÑÐµÐ»Ñ ÑÐ¿ÑÐ°Ð²Ð»ÑÑÑ ÑÐŸÑÐœÐŸÑÑÑÑ Ð¿ÐŸÐžÑÐºÐ° ÑÐµÐºÑÑÐ°. ÐÐµÑÐµÐºÐ»ÑÑÐ°ÑÐµÐ»Ñ ("Ð ÐµÐ³ÐžÑÑÑÑ") Ð²ÐºÐ»ÑÑÐ°ÐµÑ/ÐŸÑÐŒÐµÐœÑÐµÑ ÑÑÐµÑ ÑÐµÐ³ÐžÑÑÑÐ°. ÐÐµÑÐµÐºÐ»ÑÑÐ°ÑÐµÐ»Ñ "ÐÐºÐŸÐœÑÐ°ÐœÐžÑ ÑÐ»ÐŸÐ²" Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐžÐ»Ðž ÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÑÑ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÑ Ñ ÑÐ»ÐŸÐ².  ÐÐµÑÐµÐºÐ»ÑÑÐ°ÑÐµÐ»Ñ "Ð Ð°Ð·ÐŒÐµÑ ÐŸÐºÐœÐ° Ð¿ÐŸÐžÑÐºÐ°" Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð²Ð²ÐŸÐŽÐžÑÑ ÑÐµÐ»ÑÐ¹ Ð°Ð±Ð·Ð°Ñ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÑÐµÐºÑÑÐ° Ð·Ð°Ð¿ÑÐŸÑÐ°. 
+<p>ÐÐ°Ð¿ÑÐžÐŒÐµÑ, ÐµÑÐ»Ðž Ð²ÑÐ±ÑÐ°ÐœÐŸ <i>ÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÐ³ÐžÑÑÑÑ</i> Ðž
+<i>ÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÑÑ ÐŸÐºÐŸÐœÑÐ°ÐœÐžÑ ÑÐ»ÐŸÐ²</i>,ÑÐŸ Ð·Ð°Ð¿ÑÐŸÑ<p>
+    <ul><kbd>African building</kbd></ul>
+      <p>Ð±ÑÐŽÐµÑ ÑÑÐ°ÐºÑÐŸÐ²Ð°ÑÑÑÑ ÐºÐ°Ðº<p>
+      <ul><kbd>africa builds</kbd></ul><p>
+      Ð¿ÐŸÑÐŸÐŒÑ ÑÑÐŸ Ð±ÑÐºÐ²Ð° Ð²ÐµÑÑ
+ÐœÐµÐ³ÐŸ ÑÐµÐ³ÐžÑÑÑÐ° ÐžÐ· ÑÐ»ÐŸÐ²Ð° "African" Ð±ÑÐŽÐµÑ ÐžÐ·ÐŒÐµÐœÐµÐœÐ° ÐœÐ° Ð±ÑÐºÐ²Ñ ÐœÐžÐ¶ÐœÐµÐ³ÐŸ ÑÐµÐ³ÐžÑÑÑÐ°, Ð° ÑÑÑÑÐžÐºÑÑ "n" Ðž "ing" Ð±ÑÐŽÑÑ ÑÐŽÐ°Ð»ÐµÐœÑ ÐžÐ· ÑÐ»ÐŸÐ²
+      "African" Ðž "building" (ÑÐ°ÐºÐ¶Ðµ, "s" Ð±ÑÐŽÐµÑ ÑÐŽÐ°Ð»ÐµÐœÐ° ÐžÐ· "builds").
+
+<p>ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐµÑÐµÐºÐ»ÑÑÐžÑÑÑÑ Ð² ÑÐ°ÑÑÐžÑÐµÐœÐœÑÑ ÑÐŸÑÐŒÑ Ð·Ð°Ð¿ÑÐŸÑÐ°, ÐºÐŸÑÐŸÑÐ°Ñ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÑÐŸÑÐµÑÐ°ÑÑ ÑÐ»ÐŸÐ²Ð°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð (&), ÐÐÐ (|), Ð ÐÐ (!). Ð­ÑÐŸ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÑÑ Ð±ÐŸÐ»ÐµÐµ ÑÐŸÑÐœÑÐµ Ð·Ð°Ð¿ÑÐŸÑÑ. Ð¢Ð°ÐºÐ¶Ðµ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÐºÐ»ÑÑÐžÑÑ Ð¿ÐŸÐºÐ°Ð· ÐžÑÑÐŸÑÐžÐž Ð·Ð°Ð¿ÑÐŸÑÐ°, ÐºÐŸÐ³ÐŽÐ° Ð±ÑÐŽÑÑ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÑ Ð¿ÑÐµÐŽÑÐŽÑÑÐžÐµ ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÑ Ð¿ÐŸÐžÑÐºÐ°. Ð­ÑÐŸ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÑÑ ÑÐ»ÐµÐ³ÐºÐ° ÐžÐ·ÐŒÐµÐœÐµÐœÐœÑÐµ ÑÐŸÑÐŒÑ Ð·Ð°Ð¿ÑÐŸÑÐŸÐ². ÐÐ°ÐºÐŸÐœÐµÑ, Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐµÐ³ÑÐ»ÐžÑÐŸÐ²Ð°ÑÑ ÐŸÐ±ÑÐµÐµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² - ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°, Ð° ÑÐ°ÐºÐ¶Ðµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² ÐœÐ° ÐŸÐŽÐœÐŸÐ¹ ÑÑÑÐ°ÐœÐžÑÐµ.
+}
+
+_texttanumbrowseoptions_ [l=ru] {Ð¡ÑÑÐµÑÑÐ²ÑÑÑ (_numbrowseoptions_) Ð²ÐžÐŽÐ°/ÐŸÐ² Ð¿ÐŸÐžÑÐºÐ°  ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž Ð² ÑÑÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž:}
+
+_textsimplehelpheading_ [l=ru] {ÐÐ°Ðº ÐžÑÐºÐ°ÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ}
+
+_texthelpscope_ [l=ru] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>ÐÐžÐ°Ð¿Ð°Ð·ÐŸÐœ Ð¿ÐŸÐžÑÐºÐ° </h3>
+
+<p>
+Ð Ð±ÐŸÐ»ÑÑÐžÐœÑÑÐ²Ðµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ ÐžÐœÐŽÐµÐºÑÑ ÐŽÐ»Ñ Ð¿ÐŸÐžÑÐºÐ°. ÐÐ°Ð¿ÑÐžÐŒÐµÑ, ÐžÐœÐŽÐµÐºÑ Ð¿ÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑÐŒ ÐºÐœÐžÐ³, ÐžÐ»Ðž Ð¿ÐŸ ÑÐ°ÐŒÐžÐ»ÐžÑÐŒ Ð°Ð²ÑÐŸÑÐŸÐ². Ð­ÑÐŸ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐ°ÐºÐ¶Ðµ ÐžÐœÐŽÐµÐºÑÑ Ð¿ÐŸ Ð³Ð»Ð°Ð²Ð°ÐŒ ÐžÐ»Ðž Ð¿ÐŸ Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐ°ÐŒ ÑÐ°Ð·ÐŽÐµÐ»ÐŸÐ². ÐÑÐ»Ðž Ð²Ñ ÐœÐµ ÑÐºÐ°Ð¶ÐµÑÐµ  ÑÑÐµÐ±ÑÐµÐŒÑÐ¹ ÐžÐœÐŽÐµÐºÑ (Ð¿ÐŸ Ð³Ð»Ð°Ð²Ð°ÐŒ ÐžÐ»Ðž Ð¿ÐŸ ÑÐµÐºÑÐžÑÐŒ), ÑÐŸ ÐœÐ° ÑÐºÑÐ°Ðœ Ð±ÑÐŽÐµÑ Ð²ÑÐ²ÐµÐŽÐµÐœ Ð²ÐµÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑ<p> ÐÑÐ»Ðž ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐŒ ÑÐ²Ð»ÑÐµÑÑÑ ÑÐµÐ»Ð°Ñ ÐºÐœÐžÐ³Ð°, ÑÐŸ ÐŸÐœÐ° Ð±ÑÐŽÐµÑ ÐŸÑÐºÑÑÑÐ° Ð² ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐŒ ÐŒÐµÑÑÐµ.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/russian2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/russian2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/russian2.dm	(revision 10506)
@@ -0,0 +1,1005 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Russian Language text and icon macros 
+# -- this file contains text that is of less importance
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=ru] {ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ². }
+_lastupdate_ [l=ru] {ÐÐŸÑÐ»ÐµÐŽÐœÐµÐµ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ}
+_ago_ [l=ru] {ÐŽÐœÐµÐ¹ ÐœÐ°Ð·Ð°ÐŽ.}
+_colnotbuilt_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµ ÑÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐ°.}
+
+_textpagetitle_ [l=ru] {ÐŠÐžÑÑÐŸÐ²Ð°Ñ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ° ÐÑÐžÐœÑÑÐŸÑÐœ}
+_textadmin_ [l=ru] {ÐÐŽÐŒÐžÐœÐžÑÑÑÐ°ÑÐžÐ²ÐœÐ°Ñ ÑÑÑÐ°ÐœÐžÑÐ°}
+_textabgs_ [l=ru] {Ð ÐÑÐžÐœÑÑÐŸÑÐœ}
+_textgsdocs_ [l=ru] {ÐÐŸÐºÑÐŒÐµÐœÑÐ°ÑÐžÑ ÐÑÐžÐœÑÑÐŸÑÐœ}
+
+_textimagegli_ [l=ru] {ÐÐŸÐŒÐŸÑÑ Ð² ÑÐŸÐ·ÐŽÐ°ÐœÐžÐž ÐœÐŸÐ²ÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹, Ð¿ÑÐµÐŸÐ±ÑÐ°Ð·ÐŸÐ²Ð°ÐœÐžÐž ÐžÐ»Ðž ÐŽÐŸÐ¿ÐŸÐ»ÐœÐµÐœÐžÐž ÑÑÑÐµÑÑÐ²ÑÑÑÐžÑ
+, ÐžÐ»Ðž ÑÐŽÐ°Ð»ÐµÐœÐžÐž }
+
+_textimagecollector_ [l=ru] {Ð­ÑÐŸ Ð¿ÑÐµÐŽÑÐµÑÑÐ²ÐµÐœÐœÐžÐº ÐÐœÑÐµÑÑÐµÐ¹ÑÐ° ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°ÑÑ, Ðž ÐŽÐ»Ñ Ð±ÐŸÐ»ÑÑÐžÐœÑÑÐ²Ð° Ð¿ÑÐ°ÐºÑÐžÑÐµÑÐºÐžÑ
+ ÑÐµÐ»ÐµÐ¹ ÐÐœÑÐµÑÑÐµÐ¹Ñ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ°ÑÑ ÐŽÐŸÐ»Ð¶ÐµÐœ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ Ð²ÐŒÐµÑÑÐŸ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÐ°.}
+
+_textimagetranslator_ [l=ru] {ÐÐŸÐŒÐŸÐ³Ð°ÐµÑ ÐÐ°ÐŒ Ð¿ÐŸÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑ ÑÐŸÐ²ÑÐµÐŒÐµÐœÐœÑÐµ ÐŒÐœÐŸÐ³ÐŸÑÐ·ÑÑÐœÑÐµ Ð²ÐµÑÑÐžÐž ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° ÐÑÐžÐœÑÑÐŸÑÐœ Ð² Ð°ÐºÑÑÐ°Ð»ÑÐœÐŸÐŒ ÑÐŸÑÑÐŸÑÐœÐžÐž }
+
+_textimageadmin_ [l=ru] {ÐÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐÐ°ÐŒ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÑÑ ÐœÐŸÐ²ÑÑ
+ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÐµÐ¹,ÐŸÐ±ÑÐµÐŽÐžÐœÑÐµÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð² ÑÐžÑÑÐµÐŒÑ, ÐŽÐ°ÐµÑ ÑÐµÑ
+ÐœÐžÑÐµÑÐºÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸÑÐœÐŸÑÐžÑÐµÐ»ÑÐœÐŸ ÐžÐœÑÑÐ°Ð»Ð»ÑÑÐžÐž ÐÑÐžÐœÑÑÐŸÑÐœ }
+
+_textimagegogreenstone_ [l=ru] {ÐÐ±ÑÑÑÐœÑÐµÑ ÐŸ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐŒ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐž ÐÑÐžÐœÑÑÐŸÑÐœ Ðž ÐÐŸÐ²ÐŸÐ·ÐµÐ»Ð°ÐœÐŽÑÐºÐŸÐŒ ÐÑÐŸÐµÐºÑÐµ ÐŠÐžÑÑÐŸÐ²ÐŸÐ¹ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž, Ð³ÐŽÐµ ÐŸÐœÐŸ Ð±ÑÐ»ÐŸ ÑÐŸÐ·ÐŽÐ°ÐœÐŸ}
+
+_textimagegodocs_ [l=ru] {Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²Ð° ÐÑÐžÐœÑÑÐŸÑÐœ}
+
+_textpoem_ [l=ru] {<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+<p>Ð¿ÑÑÑÑ Ð²Ð°Ñ ÐŸÐºÑÑÐ¶Ð°ÑÑ ÐŒÐžÑ Ðž ÑÐ¿ÐŸÐºÐŸÐ¹ÑÑÐ²ÐžÐµ, 
+<p>Ð¿ÑÑÑÑ Ð¿ÐŸÑÑÐŸÑÐœÐœÐŸ Ð²Ñ Ð±ÑÐŽÐµÑÐµ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑÑ Ð² ÑÐµÐ¿Ð»ÑÑ
+ ÐŸÐ±ÑÑÑÐžÑÑ
+ Ð»ÐµÑÐ°, 
+<br>Ð¿ÑÑÑÑ Ð²ÐŸÐŽÑ ÐŸÐºÐµÐ°ÐœÐ° Ð²Ð°ÑÐžÑ
+ Ð¿ÑÑÐµÑÐµÑÑÐ²ÐžÐ¹ Ð±ÑÐŽÑÑ ÑÑÐŸÐ»Ñ Ð¶Ðµ Ð³Ð»Ð°ÐŽÐºÐžÐŒÐž, ÐºÐ°Ðº ÐŸÑÐ¿ÐŸÐ»ÐžÑÐŸÐ²Ð°ÐœÐœÑÐµ Ð³ÑÐ°ÐœÐž ÐÑÐžÐœÑÑÐŸÑÐœ.}
+
+_textgreenstone_ [l=ru] {<p>
+<i>ÐÑÐžÐœÑÑÐŸÑÐœ</i>  - Ð¿ÐŸÐ»ÑÐŽÑÐ°Ð³ÐŸÑÐµÐœÐœÑÐ¹ ÐºÐ°ÐŒÐµÐœÑ, ÐºÐŸÑÐŸÑÑÐ¹ (Ð¿ÐŸÐŽÐŸÐ±ÐœÐŸ ÑÑÐŸÐŒÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐŒÑ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ) Ð±ÑÐ» ÐŽÐŸÐ±ÑÑ Ð² ÐÐŸÐ²ÐŸÐ¹ ÐÐµÐ»Ð°ÐœÐŽÐžÐž. Ð ÑÑÐ°ÐŽÐžÑÐžÐŸÐœÐœÐŸÐŒ ÐŸÐ±ÑÐµÑÑÐ²Ðµ ÐŒÐ°ÐŸÑÐž ÐŸÐœ Ð±ÑÐ» ÑÐ°ÐŒÑÐŒ ÐŽÐŸÑÐŸÐ³ÐžÐŒ. ÐÐœ ÐŒÐŸÐ¶ÐµÑ Ð¿ÐŸÐ³Ð»ÐŸÑÐ°ÑÑ Ðž ÑÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑ <i>ÐÐ°Ð¹ÑÑÐ°,</i> ÑÐ²Ð»ÑÑÑÐžÐŒÑÑ ÐŽÑÑ
+ÐŸÐŒ ÐžÐ»Ðž ÑÐžÐ»ÐŸÐ¹ Ð¶ÐžÐ·ÐœÐž, ÐœÐ°ÐŽÐµÐ»ÐµÐœÐœÑÐ¹ ÑÑÐ°ÐŽÐžÑÐžÐŸÐœÐœÑÐŒÐž ÐŽÐŸÑÑÐŸÐžÐœÑÑÐ²Ð°ÐŒÐž, ÐºÐŸÑÐŸÑÑÐµ ÐŽÐµÐ»Ð°ÑÑ ÐµÐ³ÐŸ Ð²Ð¿ÐŸÐ»ÐœÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÐŸÐ¹ ÑÐŒÐ±Ð»ÐµÐŒÐŸÐ¹ ÐŽÐ»Ñ Ð¿ÑÐŸÐŽÑÐºÑÐ° ÐŸÐ±ÑÐµÐ³ÐŸ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ - Ð¿ÑÐŸÐµÐºÑÐ° ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐºÐž. ÐÐ³ÐŸ Ð±Ð»ÐµÑÐº ÐŸÐ·ÐœÐ°ÑÐ°ÐµÑ ÐŒÐžÐ»ÐŸÑÐµÑÐŽÐžÐµ; ÐµÐ³ÐŸ Ð¿ÑÐŸÐ·ÑÐ°ÑÐœÐŸÑÑÑ - ÑÐµÑÑÐœÐŸÑÑÑ; ÐµÐ³ÐŸ ÐºÑÑÑÐžÐ·ÐœÐ° - Ñ
+ÑÐ°Ð±ÑÐŸÑÑÑ; Ð° ÐŸÑÑÑÑÐ¹ ÐºÑÐ°Ð¹ ÐŒÐŸÐ¶ÐµÑ ÐŸÐ·ÐœÐ°ÑÐ°ÑÑ Ð¿ÑÐ°Ð²ÐŸÑÑÐŽÐžÐµ. Ð ÐµÐ·ÐœÐ°Ñ ÑÐ°ÑÑÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐ°Ñ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÑÐŒÐ±Ð»ÐµÐŒÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐ³ÐŸ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ ÐŠÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž ÐÑÐžÐœÑÑÐŸÑÐœ -ÑÑÐŸ <i>ÐÐ°ÑÑ</i>  ÐžÐ»Ðž Ð±ÐŸÑÑÐŸÐ²ÑÐºÐžÐ¹ ÐºÐ»ÑÐ±, Ðž  ÑÐµÐŒÐµÐ¹ÐœÐ°Ñ ÑÐµÐ»ÐžÐºÐ²ÐžÑ ÐŸÐŽÐœÐŸÐ³ÐŸ ÐžÐ· ÑÐ»ÐµÐœÐŸÐ² ÐœÐ°ÑÐµÐ³ÐŸ Ð¿ÑÐŸÐµÐºÑÐ°. Ð ÑÑÐºÐŸÐ¿Ð°ÑÐœÐŸÐŒ Ð±ÐŸÑ ÐµÐ³ÐŸ ÑÐµÐ°ÐºÑÐžÑ ÐŸÑÐµÐœÑ Ð±ÑÑÑÑÐ°, ÑÐŸÑÐœÐ°, Ðž ÐŸÑÐµÐœÑ Ð·Ð°ÐºÐŸÐœÑÐµÐœÐ°. ÐÐ°ÐŒ ÐœÑÐ°Ð²ÐžÑÑÑ ÐŽÑÐŒÐ°ÑÑ, ÑÑÐŸ ÑÑÐž ÐºÐ°ÑÐµÑÑÐ²Ð° ÑÐ°ÐºÐ¶Ðµ ÐŸÑÐœÐŸÑÑÑÑÑ Ðž Ðº ÐœÐ°ÑÐµÐŒÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐŒÑ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ, ÐŸÑÑÑÑÐ¹ ÐºÑÐ°Ð¹ Ð±ÑÐžÑÐ²Ñ -  <i>ÐÐ°ÑÑ,</i>  ÑÐžÐŒÐ²ÐŸÐ» ÑÐŸÐ³ÐŸ, ÑÑÐŸ ÐŒÑ ÐœÐ°Ñ
+ÐŸÐŽÐžÐŒÑÑ ÐœÐ° ÑÐ°ÐŒÐŸÐ¹ ÐºÑÐŸÐŒÐºÐµ ÑÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÐž. }
+
+_textaboutgreenstone_ [l=ru] {<p>ÐÑÐžÐœÑÑÐŸÑÐœ, ÐºÐŸÐŒÐ¿Ð»ÐµÐºÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐ³ÐŸ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž ÐŽÐ»Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ, Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ Ðž ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÐµÐœÐžÑ Ð¿ÐŸÐ»ÐœÐŸÑÐµÐºÑÑÐŸÐ²ÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹. Ð­ÑÐ° ÑÐžÑÑÐµÐŒÐ° ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°ÐµÑ ÐœÐŸÐ²ÑÐ¹ ÑÐ¿ÐŸÑÐŸÐ± ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÐž ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐŽÐ»Ñ ÐŸÐ¿ÑÐ±Ð»ÐžÐºÐŸÐ²Ð°ÐœÐžÑ ÐœÐ° ÐºÐŸÐŒÐ¿Ð°ÐºÑ ÐŽÐžÑÐºÐ°Ñ
+, Ð»ÐŸÐºÐ°Ð»ÑÐœÑÑ
+ ÑÐµÑÑÑ
+ Ðž ÐžÐœÑÐµÑÐœÐµÑ. ÐÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ Ð¿ÑÐŸÐžÐ·Ð²ÐµÐŽÐµÐœÐŸ Ð² ÑÐ°ÐŒÐºÐ°Ñ
+ Ð¿ÑÐŸÐµÐºÑÐ° ÐÐŸÐ²ÐŸÐ·ÐµÐ»Ð°ÐœÐŽÑÐºÐŸÐ¹ ÐŠÐžÑÑÐŸÐ²ÐŸÐ¹ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž Ð£ÐœÐžÐ²ÐµÑÑÐžÑÐµÑÐ° ÐÐ°Ð¹ÐºÐ°ÑÐŸ, Ð² ÑÐŸÑÑÑÐŽÐœÐžÑÐµÑÑÐ²Ðµ Ñ Ð®ÐÐÐ¡ÐÐ Ðž ÐÐÐ Ð§ÐµÐ»ÐŸÐ²ÐµÑÐµÑÐºÐ°Ñ ÐÐœÑÐŸÑÐŒÐ°ÑÐžÑ (Human Info). ÐÐœÑÐµÐ³ÑÐžÑÑÐµÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, Ð¿ÐŸÐ»ÐœÐŸÑÐµÐºÑÑÐŸÐ²ÑÐ¹ Ð¿ÐŸÐžÑÐº Ðž ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ, Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÑ ÐŒÐœÐŸÐ³ÐŸÑÐ·ÑÑÐžÑ, Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÑ ÐŒÐœÐŸÐ³ÐžÑ
+ ÐŸÐ±ÑÐµÑÐ¿ÐŸÑÑÐµÐ±ÐžÐŒÑÑ
+ ÑÐŸÑÐŒÐ°ÑÐŸÐ² Ðž Ð°ÐŽÐŒÐžÐœÐžÑÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒÐž. ÐÑÐžÐœÑÑÐŸÑÐœ ÑÐ²ÐŸÐ±ÐŸÐŽÐœÐŸÐµ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ, Ñ ÐŸÑÐºÑÑÑÑÐŒÐž ÐžÑÑ
+ÐŸÐŽÐœÑÐŒÐž ÐºÐŸÐŽÐ°ÐŒÐž, ÐŽÐŸÑÑÑÐ¿ÐœÐŸ Ð¿ÐŸ Ð°ÐŽÑÐµÑÑ <i><a href="http://greenstone.org"> http://greenstone.org </a>, ÐœÐ° ÑÑÐ»ÐŸÐ²ÐžÑÑ
+ <a href="http://www.gnu.org/copyleft/gpl.html">ÑÑÐ°ÐœÐŽÐ°ÑÑÐœÐŸÐ¹ ÐŸÐ±ÑÐµÑÑÐ²ÐµÐœÐœÐŸÐ¹ Ð»ÐžÑÐµÐœÐ·ÐžÐž</a> (GNU)</i>. 
+<br>ÐŠÐµÐ»Ñ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐ³ÐŸ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ ÑÐ°ÑÑÐžÑÐžÑÑ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÐž Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÐµÐ¹, Ð² ÑÐ°ÑÑÐœÐŸÑÑÐž ÑÐœÐžÐ²ÐµÑÑÐžÑÐµÑÐŸÐ², Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐº, Ðž ÐŽÑÑÐ³ÐžÑ
+ ÑÑÑÐµÐ¶ÐŽÐµÐœÐžÐ¹ ÐŸÐ±ÑÐµÑÑÐ²ÐµÐœÐœÑÑ
+ ÑÐ»ÑÐ¶Ð±, ÑÑÐŸÐ±Ñ Ð¿ÐŸÑÑÑÐŸÐžÑÑ ÑÐŸÐ±ÑÑÐ²ÐµÐœÐœÑÐµ ÑÐžÑÑÐŸÐ²ÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐŠÐžÑÑÐŸÐ²ÑÐµ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž ÑÐ°ÐŽÐžÐºÐ°Ð»ÑÐœÐŸ Ð¿ÑÐµÐŸÐ±ÑÐ°Ð·ÑÑÑ ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÐµÐœÐžÐµ Ðž ÐŽÐŸÑÑÑÐ¿ Ðº ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž Ð² ÑÐ°ÐŒÐºÐ°Ñ
+ Ð¿Ð°ÑÑÐœÐµÑÑÑÐ²Ð° Ñ Ð®ÐÐÐ¡ÐÐ Ðž ÑÐ°Ð·Ð»ÐžÑÐœÑÐŒÐž ÑÑÑÐµÐ¶ÐŽÐµÐœÐžÑÑ
+ Ð² ÐŸÐ±Ð»Ð°ÑÑÐž ÐŸÐ±ÑÐ°Ð·ÐŸÐ²Ð°ÐœÐžÑ, ÐœÐ°ÑÐºÐž Ðž ÐºÑÐ»ÑÑÑÑÑ Ð²ÐŸ Ð²ÑÐµÐŒ ÐŒÐžÑÐµ, Ðž ÐŸÑÐŸÐ±ÐµÐœÐœÐŸ Ð² ÑÐ°Ð·Ð²ÐžÐ²Ð°ÑÑÐžÑ
+ÑÑ ÑÑÑÐ°ÐœÐ°Ñ
+. ÐÑ ÐœÐ°ÐŽÐµÐµÐŒÑÑ, ÑÑÐŸ ÑÑÐŸ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ ÐŽÐ°ÑÑ ÑÐŸÐ»ÑÐŸÐº ÑÑÑÐµÐºÑÐžÐ²ÐœÐŸÐŒÑ ÑÐ°Ð·Ð²ÐµÑÑÑÐ²Ð°ÐœÐžÑ ÑÐžÑÑÐŸÐ²ÑÑ
+ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐº ÐŽÐ»Ñ Ð¿ÐŸÐ²ÑÐµÐŒÐµÑÑÐœÐŸÐ³ÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž Ðž ÐµÐµ ÑÐ°Ð·ÐŒÐµÑÐµÐœÐžÑ ÐŽÐ»Ñ ÐŽÐŸÑÑÑÐ¿Ð° ÑÐžÑÐŸÐºÐžÑ
+ ÑÐ»ÐŸÐµÐ² ÐŸÐ±ÑÐµÑÑÐ²ÐµÐœÐœÐŸÑÑÐž. 
+
+<br>Ð­ÑÐŸ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÐ°ÐœÐŸ Ðž ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÑÐµÑÑÑ ÐºÐ°Ðº Ð¿ÑÐŸÐŽÑÐºÑ  ÐŒÐµÐ¶ÐŽÑÐœÐ°ÑÐŸÐŽÐœÐŸÐ³ÐŸ ÑÑÐµÑ
+ÑÑÐŸÑÐŸÐœÐœÐµÐ³ÐŸ ÑÐŸÐ²ÐŒÐµÑÑÐœÐŸÐ³ÐŸ ÑÐŸÑÑÑÐŽÐœÐžÑÐµÑÑÐ²Ð°, Ñ Ð°Ð²Ð³ÑÑÑÐ° 2000 Ð³ÐŸÐŽÐ°. 
+
+<table border="0">
+<tr valign="top">
+<td>
+<a href="http://nzdl.org"><b>ÐÑÐŸÐµÐºÑ ÐÐŸÐ²ÐŸÐ·ÐµÐ»Ð°ÐœÐŽÑÐºÐŸÐ¹ ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž Ð£ÐœÐžÐ²ÐµÑÑÐžÑÐµÑÐ° ÐÐ°Ð¹ÐºÐ°ÑÐŸ</b></a>
+<br>
+ÐÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ ÐÑÐžÐœÑÑÐŸÑÐœ Ð²ÑÑÐŸÑÐ»ÐŸ ÐžÐ· ÑÑÐŸÐ³ÐŸ Ð¿ÑÐŸÐµÐºÑÐ°, Ðž ÑÑÐ° ÐžÐœÐžÑÐžÐ°ÑÐžÐ²Ð° Ð±ÑÐ»Ð° Ð¿ÐŸÐŽÐŽÐµÑÐ¶Ð°ÐœÐ° ÐºÐŸÐŒÐžÑÐµÑÐŸÐŒ Ð¿ÐŸ Ð¡Ð²ÑÐ·ÑÐŒ ÐÐŸÐ²ÐŸÐ·ÐµÐ»Ð°ÐœÐŽÑÐºÐŸÐ¹ ÐÐ°ÑÐžÐŸÐœÐ°Ð»ÑÐœÐŸÐ¹ ÐÐŸÐŒÐžÑÑÐžÐž Ð¿ÐŸ ÐŽÐµÐ»Ð°ÐŒ Ð®ÐÐÐ¡ÐÐ ÐºÐ°Ðº ÑÐ°ÑÑÑ Ð²ÐºÐ»Ð°ÐŽÐ° ÐÐŸÐ²ÐŸÐ¹ ÐÐµÐ»Ð°ÐœÐŽÐžÐž Ð² Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ Ð®ÐÐÐ¡ÐÐ.
+</td>
+<td></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://www.unesco.org"><b>ÐÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ ÐÐ±ÑÐµÐŽÐžÐœÐµÐœÐœÑÑ
+ ÐÐ°ÑÐžÐ¹ Ð¿ÐŸ Ð²ÐŸÐ¿ÑÐŸÑÐ°ÐŒ ÐÐ±ÑÐ°Ð·ÐŸÐ²Ð°ÐœÐžÑ, ÐÐ°ÑÐºÐž Ðž ÐÑÐ»ÑÑÑÑÑ</b></a>
+<br>Ð Ð°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÐµÐœÐžÐµ Ðž ÐŽÐŸÑÑÑÐ¿ Ðº ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐŸÐ± ÐŸÐ±ÑÐ°Ð·ÐŸÐ²Ð°ÐœÐžÐž, ÐœÐ°ÑÐºÐµ Ðž ÐºÑÐ»ÑÑÑÑÐµ Ð²ÐŸ Ð²ÑÐµÐŒ ÐŒÐžÑÐµ, ÐŸÑÐŸÐ±ÐµÐœÐœÐŸ Ð² ÑÐ°Ð·Ð²ÐžÐ²Ð°ÑÑÐžÑ
+ÑÑ ÑÑÑÐ°ÐœÐ°Ñ
+, ÑÐ²Ð»ÑÐµÑÑÑ ÐŸÑÐœÐŸÐ²ÐœÐŸÐ¹ ÑÐµÐ»ÑÑ Ð®ÐÐÐ¡ÐÐ, ÐŽÐŸÑÑÐžÐ³Ð°ÑÑÐµÐ¹ÑÑ Ð² ÑÐ°ÐŒÐºÐ°Ñ
+ ÐŒÐµÐ¶Ð¿ÑÐ°Ð²ÐžÑÐµÐ»ÑÑÑÐ²ÐµÐœÐœÐŸÐ¹ ÐÑÐŸÐ³ÑÐ°ÐŒÐŒÑ "ÐÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŽÐ»Ñ ÐÑÐµÑ
+". Ð¡ÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐ°Ñ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ Ðž ÐŽÐŸÑÑÑÐ¿ Ðº ÑÑÐµÐŽÑÑÐ²Ð°ÐŒ ÐÐœÑÐŸÑÐŒÐ°ÑÐžÐŸÐœÐœÐŸ-ÐÐŸÐŒÐŒÑÐœÐžÐºÐ°ÑÐžÐŸÐœÐœÑÑ
+ Ð¢ÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÐ¹, Ð² ÐŽÐ°ÐœÐœÐŸÐŒ ÐºÐŸÐœÑÐµÐºÑÑÐµ, ÑÐ²Ð»ÑÑÑÑÑ Ð²Ð°Ð¶ÐœÑÐŒÐž ÐžÐœÑÑÑÑÐŒÐµÐœÑÐ°ÐŒÐž .
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/unesco.gif"
+border="0"></a></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://humaninfo.org"><b>ÐÐÐ Ð§ÐµÐ»ÐŸÐ²ÐµÑÐµÑÐºÐ°Ñ ÐÐœÑÐŸÑÐŒÐ°ÑÐžÑ, ÐœÐ°Ñ
+ÐŸÐŽÑÑÐµÐµÑÑ Ð² ÐÐœÑÐ²ÐµÑÐ¿ÐµÐœÐµ, ÐÐµÐ»ÑÐ³ÐžÑ </b></a>
+<br>
+Ð­ÑÐŸÑ Ð¿ÑÐŸÐµÐºÑ ÑÐ°Ð±ÐŸÑÐ°ÐµÑ Ñ Ð°Ð³ÐµÐœÑÑÑÐ²Ð°ÐŒÐž ÐÐÐ Ðž ÐŽÑÑÐ³ÐžÐŒÐž ÐœÐµÐ¿ÑÐ°Ð²ÐžÑÐµÐ»ÑÑÑÐ²ÐµÐœÐœÑÐŒÐž ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑÐŒÐž, Ðž ÐžÐŒÐµÐµÑ Ð²ÑÑÐŸÐºÑÑ Ð²ÑÐµÐŒÐžÑÐœÑÑ ÑÐµÐ¿ÑÑÐ°ÑÐžÑ Ð² ÐŸÐ±Ð»Ð°ÑÑÐž ÑÐžÑÑÐŸÐ²ÐŸÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÑÐžÐž, Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÑÑÑÐµÐ¹ ÐžÐœÑÐµÑÐµÑ ÐŽÐ»Ñ ÑÐµÐ»ÐŸÐ²ÐµÑÐµÑÐºÐŸÐ³ÐŸ ÑÐ°Ð·Ð²ÐžÑÐžÑ, Ðž ÐŽÐµÐ»Ð°ÐµÑ ÐµÐµ ÑÐžÑÐŸÐºÐŸ-ÐŽÐŸÑÑÑÐ¿ÐœÐŸÐ¹ Ðž Ð±ÐµÑÐ¿Ð»Ð°ÑÐœÐŸÐ¹ ÐŽÐ»Ñ ÑÐ°Ð·Ð²ÐžÐ²Ð°ÑÑÐžÑ
+ÑÑ ÑÑÑÐ°Ðœ Ðž ÐŒÐµÑÐŸÐŽÐŸÐŒ Ð²ÐŸÐ·ÐŒÐµÑÐµÐœÐžÑ ÐžÐ·ÐŽÐµÑÐ¶ÐµÐº ÐŽÐ»Ñ ÐŽÑÑÐ³ÐžÑ
+.
+</td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐÑÐ±ÐµÑÐžÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ [l=ru] {_httpimg_/ru/selcolgr.gif}
+_widthselcolgr_ [l=ru] {537}
+_heightselcolgr_ [l=ru] {17}
+_altselcolgr_ [l=ru] {"Select a collection"}
+
+
+## "The Librarian\nInterface" ## home_page_button ## cgli ##
+_httpiconcgliof_ [l=ru] {_httpimg_/ru/cgliof.gif}
+_httpiconcglion_ [l=ru] {_httpimg_/ru/cglion.gif}
+_widthcgli_ [l=ru] {100}
+
+## "ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ" ## home_page_button ## ccol ##
+_httpiconccolof_ [l=ru] {_httpimg_/ru/ccolof.gif}
+_httpiconccolon_ [l=ru] {_httpimg_/ru/ccolon.gif}
+_widthccol_ [l=ru] {100}
+
+## "Ð¢ÑÐ°ÐœÑÐ»ÑÑÐŸÑ" ## home_page_button ## ctrans ##
+_httpiconctransof_ [l=ru] {_httpimg_/ru/ctransof.gif}
+_httpiconctranson_ [l=ru] {_httpimg_/ru/ctranson.gif}
+_widthctrans_ [l=ru] {100}
+
+## "Administration\nPage" ## home_page_button ## cadmin ##
+_httpiconcadminof_ [l=ru] {_httpimg_/ru/cadminof.gif}
+_httpiconcadminon_ [l=ru] {_httpimg_/ru/cadminon.gif}
+_widthcadmin_ [l=ru] {100}
+
+## "About\nGreenstone" ## home_page_button ## cabgs ##
+_httpiconcabgsof_ [l=ru] {_httpimg_/ru/cabgsof.gif}
+_httpiconcabgson_ [l=ru] {_httpimg_/ru/cabgson.gif}
+_widthcabgs_ [l=ru] {100}
+
+## "Greenstone\nDocumentation" ## home_page_button ## cgsdoc ##
+_httpiconcgsdocof_ [l=ru] {_httpimg_/ru/cgsdocof.gif}
+_httpiconcgsdocon_ [l=ru] {_httpimg_/ru/cgsdocon.gif}
+_widthcgsdoc_ [l=ru] {100}
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=ru] {ÐÐŽÐµÑÑ Ðž ÐœÐ° ÐŽÐŸÐŒÐ°ÑÐœÐµÐ¹ ÑÑÑÐ°ÐœÐžÑÐµ Ð±ÑÐŽÑÑ ÐŽÐ°Ð»ÐµÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ ÑÐµÑÑÑÐµ ÐºÐœÐŸÐ¿ÐºÐž}
+
+_textnocollections_ [l=ru] {<p> Ð ÑÑÐŸÐ¹ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐµ ÐÑÐžÐœÑÑÐŸÑÐœ ÐœÐµÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÑ
+ ÐºÐŸÐ»ÐµÐºÑÐžÐ¹. Ð§ÑÐŸÐ±Ñ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐµÐºÐŸÑÐŸÑÑÐµ, ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐžÐ»Ðž
+<ul><li>ÐÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ <href = "_httppagecollector _ ">ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ</a>, ÐŽÐ»Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ Ð¿ÑÐŸÑÑÐµÐ¹ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+<li>ÐžÐ»Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ñ ÐºÐŸÐŒÐ¿Ð°ÐºÑ ÐŽÐžÑÐº, ÐµÑÐ»Ðž ÐÑ Ñ ÐœÐµÐ³ÐŸ ÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÐµÑÐµ ÐÑÐžÐœÑÑÐŸÑÐœ</ul>}
+
+_text1coll_ [l=ru] {ÐÐ°ÑÑÐŸÑÑÐ°Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÐÑÐžÐœÑÑÐŸÑÐœ ÑÐŸÐŽÐµÑÐ¶ÐžÑ 1 ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ}
+
+_textmorecolls_ [l=ru] {ÐÐ°ÑÑÐŸÑÑÐ°Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÐÑÐžÐœÑÑÐŸÑÐœ ÑÐŸÐŽÐµÑÐ¶ÐžÑ _1_ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž/Ð¹}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=ru] {ÐÐœÐµÑÐœÑÑ ÑÑÑÐ»ÐºÐ°}
+_textlinknotfound_ [l=ru] {ÐÐœÑÑÑÐµÐœÐœÑÑ ÑÐ²ÑÐ·Ðž ÐœÐµ ÐœÐ°Ð¹ÐŽÐµÐœÑ}
+
+_textextlinkcontent_ [l=ru] {<p>Ð¡ÑÑÐ»ÐºÐ°, ÐºÐŸÑÐŸÑÑÑ Ð²Ñ Ð²ÑÐ±ÑÐ°Ð»Ðž, ÑÐ²Ð»ÑÐµÑÑÑ Ð²ÐœÐµÑÐœÐµÐ¹ Ð¿ÐŸ ÐŸÑÐœÐŸÑÐµÐœÐžÑ Ðº Ð»ÑÐ±ÐŸÐ¹ ÐžÐ· Ð²ÑÐ±ÑÐ°ÐœÐœÑÑ
+ Ð² ÐœÐ°ÑÑÐŸÑÑÐµÐµ Ð²ÑÐµÐŒÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹. ÐÑÐ»Ðž ÐÑ Ð¶ÐµÐ»Ð°ÐµÑÐµ Ð¿ÐŸÐ¹ÑÐž Ð¿ÐŸ ÑÑÐŸÐ¹ ÑÑÑÐ»ÐºÐµ Ðž Ð²Ð°Ñ Ð±ÑÐŸÑÐ·ÐµÑ ÐžÐŒÐµÐµÑ ÐŽÐŸÑÑÑÐ¿ Ðº ÑÐµÑÐž ÐÐœÑÐµÑÐœÐµÑ, ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ <a href="_nexturl_">   ÐŽÐ°Ð»ÐµÐµ Ð¿ÐµÑÐµÐ¹ÑÐž ÐœÐ° ÑÑÑ ÑÑÑÐ°ÐœÐžÑÑ </a>; ÐžÐœÐ°ÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐœÐŸÐ¿ÐºÑ "back/ÐœÐ°Ð·Ð°ÐŽ" Ð² Ð²Ð°ÑÐµÐŒ Ð±ÑÐŸÑÐ·ÐµÑÐµ, ÑÑÐŸÐ±Ñ Ð²ÐµÑÐœÑÑÑÑÑ Ðº Ð¿ÑÐµÐŽÑÐŽÑÑÐµÐŒÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ.}
+
+_textlinknotfoundcontent_ [l=ru] {ÐÐŸ Ð¿ÑÐžÑÐžÐœÐ°ÐŒ, ÐœÐ°Ñ
+ÐŸÐŽÑÑÐžÐŒÑÑ  Ð²ÐœÐµ ÐœÐ°ÑÐµÐ³ÐŸ ÐºÐŸÐœÑÑÐŸÐ»Ñ, Ð²ÐœÑÑÑÐµÐœÐœÑÑ ÑÑÑÐ»ÐºÐ°, ÐºÐŸÑÐŸÑÑÑ ÐÑ Ð²ÑÐ±ÑÐ°Ð»Ðž, ÐœÐµ ÑÑÑÐµÑÑÐ²ÑÐµÑ. ÐÐµÑÐŸÑÑÐœÐŸ ÑÑÐŸ ÐŸÐ±ÑÑÐ»ÐŸÐ²Ð»ÐµÐœÐŸ ÐŸÑÐžÐ±ÐºÐŸÐ¹ Ð² ÐžÑÑ
+ÐŸÐŽÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐºÐœÐŸÐ¿ÐºÑ  "back"  ÐÐ°ÑÐµÐ³ÐŸ Ð±ÑÐ°ÑÐ·ÐµÑÐ°, ÑÑÐŸÐ±Ñ Ð²ÐŸÐ·Ð²ÑÐ°ÑÐžÑÑÑÑ Ðº Ð¿ÑÐµÐŽÑÐŽÑÑÐµÐŒÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ.}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=ru] {Ð¡ÑÑÐ»ÐºÐ° ÐœÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ " _2 _ " 
+Ð¡ÑÑÐ»ÐºÐ°, ÐºÐŸÑÐŸÑÑÑ Ð²Ñ Ð²ÑÐ±ÑÐ°Ð»Ðž, ÑÐ²Ð»ÑÐµÑÑÑ Ð²ÐœÐµÑÐœÐµÐ¹ Ðº " _collectionname _ " ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ (ÐŸÐœÐ° ÑÐ²ÑÐ·ÑÐ²Ð°ÐµÑÑÑ Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹ " _2 _ " ). ÐÑÐ»Ðž Ð²Ñ Ð¶ÐµÐ»Ð°ÐµÑÐµ Ð¿ÐµÑÐµÐ¹ÑÐž Ð¿ÐŸ ÑÑÐŸÐ¹ ÑÑÑÐ»ÐºÐµ Ðº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž " _2 _ ", ÑÐŸ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">    ÐžÐŽÑÐž ÐŽÐ°Ð»ÑÑÐµ ÐœÐ° ÑÑÑ ÑÑÑÐ°ÐœÐžÑÑ </a>; ÐžÐœÐ°ÑÐµ Ð²ÐŸÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµÑÑ ÐºÐœÐŸÐ¿ÐºÐŸÐ¹ "back/ÐœÐ°Ð·Ð°ÐŽ" Ð² Ð²Ð°ÑÐµÐŒ Ð±ÑÐŸÑÐ·ÐµÑÐµ, ÑÑÐŸÐ±Ñ Ð²ÐµÑÐœÑÑÑÑÑ Ðº Ð¿ÑÐµÐŽÑÐŽÑÑÐµÐŒÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ. }
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=ru] {ÐŠÐžÑÑÐŸÐ²Ð°Ñ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ° ÐÑÐžÐœÑÑÐŸÑÐœ}
+
+_textusername_ [l=ru] {ÐÐŒÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ}
+_textpassword_ [l=ru] {ÐÐ°ÑÐŸÐ»Ñ}
+
+_textmustbelongtogroup_ [l=ru] {ÐÐ±ÑÐ°ÑÐžÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ, ÑÑÐŸ ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÑÐžÐœÐ°ÐŽÐ»ÐµÐ¶Ð°ÑÑ Ðº Ð³ÑÑÐ¿Ð¿Ðµ "_cgiargug_"   ÐŽÐŸÑÑÑÐ¿Ð° ÐœÐ° ÑÑÑ ÑÑÑÐ°ÐœÐžÑÑ.}
+
+_textmessageinvalid_ [l=ru] {Ð¡ÑÑÐ°ÐœÐžÑÐ° ÐºÐŸÑÑÑÑ Ð²Ñ Ð·Ð°Ð¿ÑÐ°ÑÐžÐ²Ð°ÐµÑÐµ ÑÑÐµÐ±ÑÐµÑ Ð°Ð²ÑÐŸÑÐžÐ·Ð°ÑÐžÐž<br>
+_If_(_cgiargug_,[textmustbelongtogroup_] <br>) ÐÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ°, Ð²Ð²ÐµÐŽÐžÑÐµ ÐÐ°ÑÐµ ÐžÐŒÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ Ðž Ð¿Ð°ÑÐŸÐ»Ñ ÐÑÐžÐœÑÑÐŸÑÐœ.}
+
+_textmessagefailed_ [l=ru] {ÐÐ²ÐµÐŽÐµÐœÐŸ ÐœÐµÐ²ÐµÑÐœÐŸÐµ ÐžÐŒÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ ÐžÐ»Ðž Ð¿Ð°ÑÐŸÐ»Ñ.}
+
+_textmessagedisabled_ [l=ru] {ÐÐ·Ð²ÐžÐœÐžÑÐµ, ÐœÐŸ Ð²Ð°ÑÐ° ÑÑÐµÑÐœÐ°Ñ Ð·Ð°Ð¿ÐžÑÑ Ð±ÑÐ»Ð° Ð·Ð°Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÐœÐ°. ÐÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ° ÑÐ²ÑÐ¶ÐžÑÐµÑÑ Ñ Ð²ÐµÐ±-ÐŒÐ°ÑÑÐµÑÐŸÐŒ ÑÑÐŸÐ³ÐŸ ÑÐ°Ð¹ÑÐ°.}
+
+_textmessagepermissiondenied_ [l=ru] {ÐÐ·Ð²ÐžÐœÐžÑÐµ, ÐœÐŸ Ð²Ñ ÐœÐµ ÐŸÐ±Ð»Ð°ÐŽÐ°ÐµÑÐµ Ð¿ÐŸÐ»ÐœÐŸÐŒÐŸÑÐžÑÐŒÐž ÐŽÐŸÑÑÐ°ÑÐŸÑÐœÑÐŒÐž ÐŽÐ»Ñ ÐŽÐŸÑÑÑÐ¿Ð° Ðº Ð·Ð°Ð¿ÑÐŸÑÐµÐœÐœÐŸÐ¹ Ð²Ð°ÐŒÐž ÑÑÑÐ°ÐœÐžÑÐµ.}
+
+_textmessagestalekey_ [l=ru] {Ð¡ÑÑÐ»ÐºÐ°, Ð¿ÐŸ ÐºÐŸÑÐŸÑÐŸÐ¹ Ð²Ñ Ð¿ÑÐŸÑÐ»ÐµÐŽÐŸÐ²Ð°Ð»Ðž, Ð² ÐœÐ°ÑÑÐŸÑÑÐµÐµ Ð²ÑÐµÐŒÑ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐ°. ÐÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ°, Ð²Ð²ÐµÐŽÐžÑÐµ Ð¿Ð°ÑÐŸÐ»Ñ ÐŽÐ»Ñ ÐŽÐŸÑÑÑÐ¿Ð° Ðº Ð·Ð°Ð¿ÑÐ°ÑÐžÐ²Ð°ÐµÐŒÐŸÐ¹ Ð²Ð°ÐŒÐž ÑÑÑÐ°ÐœÐžÑÐµ.}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=ru] {<br>
+ÐÐ°ÐœÐœÐ°Ñ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ°  ÐÑÐžÐœÑÑÐŸÑÐœ ÐœÐµ ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÐœÐžÐºÐ°ÐºÐŸÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÑÐžÐž. Ð­ÑÐŸ ÐŒÐŸÐ¶ÐµÑ ÑÐ»ÑÑÐžÑÑÑÑ Ð¿ÐŸ Ð¿ÑÐžÑÐžÐœÐµ: 
+1. ÐÑÐžÐœÑÑÐŸÑÐœ Ð±ÑÐ»Ð° ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐ° Ñ CD-ROM, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑ ÐºÐŸÐŒÐ¿Ð°ÐºÑÐœÐŸÐ¹ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž. 
+2. ÐÑÐžÐœÑÑÐŸÑÐœ Ð±ÑÐ»Ð° ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐ° Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐŽÐžÑÑÑÐžÐ±ÑÑÐžÐ²ÐŸÐ², Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÑÑ
+ ÑÐµÑÐµÐ· ÑÐµÑÑ ÐÐœÑÐµÑÐœÐµÑ. 
+Ð Ð»ÑÐ±ÐŸÐŒ ÑÐ»ÑÑÐ°Ðµ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÑÐžÑ Ð»ÐžÐ±ÐŸ Ð² ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž docs ÐœÐ° ÑÑÑÐ°ÐœÐŸÐ²ÐŸÑÐœÐŸÐŒ  CD-ROM Greenstone Ð»ÐžÐ±ÐŸ ÐœÐ° ÑÐ°Ð¹ÑÐµ <a href="http://www.greenstone.org">http://www.greenstone.org</a>.}
+
+_textuserguide_ [l=ru] {Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²ÐŸ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ}
+_textinstallerguide_ [l=ru] {Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²ÐŸ Ð¿ÐŸ ÐžÐœÑÑÐ°Ð»Ð»ÑÑÐžÐž}
+_textdeveloperguide_ [l=ru] {Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²ÐŸ ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐ°}
+_textpaperguide_ [l=ru] {Ð ÑÐºÐŸÐ²ÐŸÐŽÑÑÐ²ÐŸ "ÐÑ Ð±ÑÐŒÐ°Ð³Ðž Ðº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž"}
+_textorganizerguide_ [l=ru] {ÐÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµ ÐÑÐ³Ð°ÐœÐ°Ð¹Ð·ÐµÑÐ°}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐÐŸÐºÑÐŒÐµÐœÑÐ°ÑÐžÑ ÐÑÐžÐœÑÑÐŸÑÐœ" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=ru] {_httpimg_/ru/gsdocsgr.gif}
+_widthgsdocsgr_ [l=ru] {_pagewidth_}
+_heightgsdocsgr_ [l=ru] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ [l=ru] {Ð¡ÑÑÑÐºÑÑÑÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ}
+_textmore_ [l=ru] {ÐŽÐ°Ð»ÐµÐµ}
+_textcollector_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ}
+_textinfo_ [l=ru] {ÐÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+_textsrce_ [l=ru] {ÐÑÑÐŸÑÐœÐžÐº ÐŽÐ°ÐœÐœÑÑ
+}
+_textconf_ [l=ru] {ÐÐŸÐœÑÐžÐ³ÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+_textbild_ [l=ru] {Ð€ÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÐµ}
+_textview_ [l=ru] {Ð¿ÑÐŸÑÐŒÐŸÑÑ}
+_textdel_ [l=ru] {Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+_textexpt_ [l=ru] {Ð­ÐºÑÐ¿ÐŸÑÑÐžÑÑÐµÐŒÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ}
+
+_textdownloadingfiles_ [l=ru] {ÐÐ°Ð³ÑÑÐ·ÐºÐ° ÑÐ°Ð¹Ð»ÐŸÐ²...}
+_textimportingcollection_ [l=ru] {ÐÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž...}
+_textbuildingcollection_ [l=ru] {ÐÐŸÑÑÑÐŸÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž...}
+_textcreatingcollection_ [l=ru] {Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐºÐŸÐ»ÐµÐºÑÐžÐž...}
+
+_textcollectorblurb_ [l=ru] {<i>ÐÐµÑÐŸ ÑÐžÐ»ÑÐœÐµÐµ ÐŒÐµÑÐ°!
+<br> ÐÐŸÑÑÑÐŸÐµÐœÐžÐµ Ðž ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÐµÐœÐžÐµ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐŸÐœÐœÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÑÑÐµÐ±ÑÐµÑ ÐŸÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÐŸÑÑÐž, ÐºÐŸÑÐŸÑÑÑ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐÑ Ð¿ÐŸÐ¶ÐµÐ»Ð°ÐµÑÐµ ÐŸÑÑÐ°Ð·ÐžÑÑ ÐŽÐŸ ÐœÐ°ÑÐ°Ð»Ð° ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. 
+Ð¡ÑÑÐµÑÑÐ²ÑÑÑ Ð¿ÑÐ°Ð²ÐŸÐ²ÑÐµ Ð²ÐŸÐ¿ÑÐŸÑÑ Ð°Ð²ÑÐŸÑÑÐºÐŸÐ³ÐŸ Ð¿ÑÐ°Ð²Ð°: Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑ ÐŽÐŸÑÑÑÐ¿Ð° Ðº ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒ ÐœÐµ ÐŸÐ·ÐœÐ°ÑÐ°ÐµÑ, ÑÑÐŸ ÐÑ ÐžÐŒÐµÐµÑÐµ Ð¿ÐŸÐ»ÐœÐŸÐµ Ð¿ÑÐ°Ð²ÐŸ ÐžÑ
+ ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÑÑÑ. ÐÑÑÑ ÑÐŸÑÐžÐ°Ð»ÑÐœÑÐµ Ð²ÐŸÐ¿ÑÐŸÑÑ: ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŽÐŸÐ»Ð¶ÐœÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐŸÐ²Ð°ÑÑ Ð·Ð°ÐºÐ°Ð·Ñ ÑÐŸÐŸÐ±ÑÐµÑÑÐ²Ð°, Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²ÐžÐ²ÑÐµÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ.
+Ð¢Ð°ÐºÐ¶Ðµ ÐžÐŒÐµÑÑÑÑ ÑÑÐžÑÐµÑÐºÐžÐµ Ð°ÑÐ¿ÐµÐºÑÑ: ÐœÐµÐºÐŸÑÐŸÑÑÐµ Ð²ÐµÑÐž ÐœÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑ ÐŽÑÑÐ³ÐžÐŒ.
+<br> ÐÑÐŽÑÑÐµ ÐŸÑÐµÐœÑ Ð²ÐœÐžÐŒÐ°ÑÐµÐ»ÑÐœÑ Ðº ÑÐžÐ»Ðµ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÐµÐµ ÐŒÑÐŽÑÐŸ.
+</i>
+}
+
+_textcb1_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ Ð¿ÐŸÐŒÐŸÐ¶ÐµÑ Ð²Ð°ÐŒ ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÑÑ ÐœÐŸÐ²ÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÐŽÐŸÐ¿ÐŸÐ»ÐœÑÑÑ ÐžÐ»Ðž ÐžÐ·ÐŒÐµÐœÑÑÑ ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐµ, ÐžÐ»Ðž ÑÐŽÐ°Ð»ÐžÑÑ ÐžÑ
+ ÑÐŸÐ²ÑÐµÐŒ. ÐÐ»Ñ ÑÐŸÐ³ÐŸ ÑÑÐŸÐ±Ñ ÑÐŽÐµÐ»Ð°ÑÑ ÑÑÐŸ Ð²Ð°ÐŒ Ð¿ÑÐžÐŽÐµÑÑÑ Ð¿ÑÐŸÐ¹ÑÐž ÑÐµÑÐµÐ· Ð¿ÐŸÑÐ»ÐµÐŽÐŸÐ²Ð°ÑÐµÐ»ÑÐœÐŸÑÑÑ ÐÐµÐ±-ÑÑÑÐ°ÐœÐžÑ Ðž Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²ÐžÑÑ Ð·Ð°Ð¿ÑÐ°ÑÐžÐ²Ð°ÐµÐŒÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ. }
+
+_textcb2_ [l=ru] {Ð¡ÐœÐ°ÑÐ°Ð»Ð° Ð²Ñ ÐŽÐŸÐ»Ð¶ÐœÑ ÑÐµÑÐžÑÑ, ÑÑÐŸ Ð²Ñ Ñ
+ÐŸÑÐžÑÐµ Ð¿ÑÐµÐŽÐ¿ÑÐžÐœÑÑÑ:}
+_textcnc_ [l=ru] {ÑÐŸÐ·ÐŽÐ°ÑÑ ÐœÐŸÐ²ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ}
+_textwec_ [l=ru] {ÑÐ°Ð±ÐŸÑÐ°ÑÑ Ñ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹, ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ ÐŽÐ°ÐœÐœÑÐµ ÐžÐ»Ðž ÑÐŽÐ°Ð»ÐžÑÑ.}
+
+_textcb3_ [l=ru] {Ð ÑÐ»ÑÑÐ°Ðµ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐœÐŸÐ²ÐŸÐ¹ ÐžÐ»Ðž ÐŒÐŸÐŽÐžÑÐžÐºÐ°ÑÐžÐž ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ¹ Ð²Ð°ÐŒ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ Ð¿ÑÐŸÐ¹ÑÐž ÑÐµÑÐµÐ· Ð¿ÑÐŸÑÐµÐŽÑÑÑ Ð°Ð²ÑÐŸÑÐžÐ·Ð°ÑÐžÐž. Ð­ÑÐŸ Ð·Ð°ÑÐžÑÐžÑ Ð²Ð°Ñ ÐŸÑ Ð¿ÐŸÑÑÐŸÑÐŸÐœÐœÐµÐ³ÐŸ Ð²ÑÐŸÑÐ¶ÐµÐœÐžÑ ÐœÐ° Ð²Ð°Ñ ÐºÐŸÐŒÐ¿ÑÑÑÐµÑ Ðž ÐœÐµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÐžÑ ÐžÑÐ¿ÐŸÑÑÐžÑÑ ÐžÐ»Ðž ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð²Ð°ÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ. ÐÐ±ÑÐ°ÑÐžÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ: ÐžÐ· ÑÐŸÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐ¹ Ð±ÐµÐ·ÐŸÐ¿Ð°ÑÐœÐŸÑÑÐž Ð²Ñ Ð±ÑÐŽÐµÑÐµ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž Ð·Ð°ÑÐµÐ³ÐžÑÑÑÐžÑÐŸÐ²Ð°ÐœÑ, Ðž ÐºÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ Ð¿ÐµÑÐžÐŸÐŽ Ð² 30 ÐŒÐžÐœÑÑ ÐžÑÑÐµÐºÐ°ÐµÑ Ñ ÐŒÐŸÐŒÐµÐœÑÐ° Ð²Ð°ÑÐµÐ³ÐŸ Ð²Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÑ, Ð²Ñ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÐŽÐµÑÐµ Ð¿ÐŸÐ²ÑÐŸÑÐœÐŸ Ð¿ÑÐŸÐ¹ÑÐž Ð¿ÑÐŸÑÐµÐŽÑÑÑ Ð°Ð²ÑÐŸÑÐžÐ·Ð°ÑÐžÐž. ÐÑÐ»Ðž ÑÑÐŸ Ð¿ÑÐŸÐžÐ·ÐŸÑÐ»ÐŸ - ÐœÐµ Ð²ÐŸÐ»ÐœÑÐ¹ÑÐµÑÑ! - ÐÑ Ð±ÑÐŽÐµÑÐµ ÑÐœÐŸÐ²Ð° Ð¿ÑÐžÐ³Ð»Ð°ÑÐµÐœÑ Ð²ÐŸÐ¹ÑÐž Ðž ÑÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÑÐŸÐŽÐŸÐ»Ð¶ÐžÑÑ Ñ  ÑÐŸÐ³ÐŸ ÐŒÐŸÐŒÐµÐœÑÐ°, Ð³ÐŽÐµ ÐÑ ÐŸÑÑÐ°ÐœÐŸÐ²ÐžÐ»ÐžÑÑ. 
+}
+
+_textcb4_ [l=ru] {ÐÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ°, Ð²Ð²ÐµÐŽÐžÑÐµ ÑÐ²ÐŸÐµ ÐžÐŒÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ Ðž Ð¿Ð°ÑÐŸÐ»Ñ ÐŽÐ»Ñ ÐÑÐžÐœÑÑÐŸÑÐœ Ðž ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÑ Ð¿ÐŸÐŽÑÐ²ÐµÑÐ¶ÐŽÐµÐœÐžÑ. }
+
+_textfsc_ [l=ru] {Ð¡ÐœÐ°ÑÐ°Ð»Ð° ÑÐºÐ°Ð¶ÐžÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, Ñ ÐºÐŸÑÐŸÑÐŸÐ¹ Ð²Ñ Ñ
+ÐŸÑÐžÑÐµ ÑÐ°Ð±ÐŸÑÐ°ÑÑ (ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, Ð·Ð°ÑÐžÑÐµÐœÐœÑÐµ ÐŸÑ Ð·Ð°Ð¿ÐžÑÐž, ÐœÐµ Ð±ÑÐŽÑÑ Ð¿ÐŸÑÐ²Ð»ÑÑÑÑÑ Ð² ÑÑÐŸÐŒ ÑÐ¿ÐžÑÐºÐµ). }
+
+_textwtc_ [l=ru] {Ð¡ Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐµÐ¹ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ:}
+_textamd_ [l=ru] {ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÑÐµ ÐŒÐ°ÑÐµÑÐžÐ°Ð»Ñ Ðž Ð¿ÐµÑÐµÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ}
+_textetc_ [l=ru] {ÐÑÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐ°Ð¹Ð» ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž Ðž Ð¿ÐŸÑÑÑÐŸÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð·Ð°ÐœÐŸÐ²ÐŸ}
+_textdtc_ [l=ru] {ÐÐŸÐ»ÐœÐŸÑÑÑÑ ÑÐŽÐ°Ð»ÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ}
+_textetcfcd_ [l=ru] {Ð­ÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŽÐ»Ñ Ð·Ð°Ð¿ÐžÑÐž ÐœÐ° ÑÐ°ÐŒÐŸÐ·Ð°Ð¿ÑÑÐºÐ°ÑÑÐžÐ¹ÑÑ CD-ROM Ð¿ÐŸÐŽ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµÐŒ Windows }
+_textcaec_ [l=ru] {ÐÐ·ÐŒÐµÐœÐµÐœÐžÐµ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.}
+_textnwec_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÐž Ñ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑÑ Ð·Ð°Ð¿ÐžÑÐž ÐœÐµ ÐŽÐŸÑÑÑÐ¿ÐœÑ ÐŽÐ»Ñ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ }
+_textcianc_ [l=ru] {Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.}
+_texttsosn_ [l=ru] {ÐÐŸÑÐ»ÐµÐŽÐŸÐ²Ð°ÑÐµÐ»ÑÐœÐŸÑÑÑ ÑÐ°Ð³ÐŸÐ², ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÑÑ
+ ÐŽÐ»Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐœÐŸÐ²ÐŸÐ¹ ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž:}
+_textsin_ [l=ru] {Ð£ÐºÐ°Ð¶ÐžÑÐµ ÐžÐŒÑ (Ðž Ð»ÑÐ±ÑÑ ÑÐ²ÑÐ·Ð°ÐœÐœÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ)}
+_textswts_ [l=ru] {Ð£ÐºÐ°Ð¶ÐžÑÐµ ÐžÑÑÐŸÑÐœÐžÐº ÐŽÐ°ÐœÐœÑÑ
+, ÐžÐ· ÐºÐŸÑÐŸÑÑÑ
+ ÑÐŸÑÐŒÐžÑÑÐµÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ}
+_textatco_ [l=ru] {ÐÐŸÑÑÐµÐºÑÐžÑÐŸÐ²ÐºÐ° ÐŸÐ¿ÑÐžÐ¹ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž (ÑÐŸÐ»ÑÐºÐŸ ÐŽÐ»Ñ ÐŸÐ¿ÑÑÐœÑÑ
+ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÐµÐ¹)}
+_textbtc_ [l=ru] {"ÐÐŸÑÑÑÐŸÐžÑÑ" ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ (ÑÐŒ. ÐœÐžÐ¶Ðµ)}
+_textpvyh_ [l=ru] {Ð¡ Ð³ÐŸÑÐŽÐŸÑÑÑÑ ÑÐ°ÑÑÐŒÐŸÑÑÐžÑÐµ ÑÐµÐ·ÑÐ»ÑÑÐ°Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐœÑÐ¹ Ð²Ð°ÑÐžÐŒÐž ÑÑÐºÐ°ÐŒÐž.}
+
+_texttfsiw_ [l=ru] {Ð§ÐµÑÐ²ÐµÑÑÑÐ¹ ÑÐ°Ð³ - ÑÑÐŸ ÑÐ°Ð±ÐŸÑÐ° Ð²Ð°ÑÐµÐ³ÐŸ ÐºÐŸÐŒÐ¿ÑÑÑÐµÑÐ°. Ð Ð¿ÑÐŸÑÐµÑÑÐµ "ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÑ" ÐºÐŸÐŒÐ¿ÑÑÑÐµÑ ÑÐŸÐ·ÐŽÐ°ÐµÑ Ð²ÑÐµ ÐžÐœÐŽÐµÐºÑÑ Ðž ÑÐŸÐ±ÐžÑÐ°ÐµÑ Ð²ÐŒÐµÑÑÐµ Ð»ÑÐ±ÑÑ ÐŽÑÑÐ³ÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ. ÐÐŸ ÑÐœÐ°ÑÐ°Ð»Ð° ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ. }
+
+_textadab_ [l=ru] {ÐÐžÐ¶Ðµ Ð¿ÐŸÑÐ²ÐžÑÑÑ ÐŽÐžÐ°Ð³ÑÐ°ÐŒÐŒÐ°, ÐºÐŸÑÐŸÑÐ°Ñ Ð¿ÐŸÐŒÐŸÐ¶ÐµÑ Ð²Ð°ÐŒ Ð¿ÑÐŸÑÐ»ÐµÐŽÐžÑÑ, ÐœÐ° ÐºÐ°ÐºÐŸÐŒ ÑÑÐ°Ð¿Ðµ Ð²Ñ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÐµÑÑ. ÐÐµÐ»ÐµÐœÐ°Ñ ÐºÐœÐŸÐ¿ÐºÐ° - ÑÑÐŸ ÑÐ°, ÐºÐŸÑÐŸÑÑÑ Ð²Ñ ÐœÐ°Ð¶ÐžÐŒÐ°ÐµÑÐµ, ÑÑÐŸÐ±Ñ Ð¿ÑÐŸÐŽÐŸÐ»Ð¶ÐžÑÑ  Ð¿ÐŸÑÐ»ÐµÐŽÐŸÐ²Ð°ÑÐµÐ»ÑÐœÐŸÑÑÑ Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐžÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ. ÐÐŸ ÐŒÐµÑÐµ Ð¿ÑÐŸÐŽÐ²ÐžÐ¶ÐµÐœÐžÑ Ð¿ÑÐŸÑÐµÑÑÐ° ÑÐ²ÐµÑ ÐºÐœÐŸÐ¿ÐºÐž ÐžÐ·ÐŒÐµÐœÐžÑÑÑ ÐœÐ° Ð¶ÐµÐ»ÑÑÐ¹. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÐŸÐ·Ð²ÑÐ°ÑÐžÑÑÑÑ Ðº Ð¿ÑÐµÐŽÑÐŽÑÑÐµÐ¹ ÑÑÑÐ°ÐœÐžÑÐµ, ÐœÐ°Ð¶ÐžÐŒÐ°Ñ ÐœÐ° ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÑÑ Ð¶ÐµÐ»ÑÑÑ ÐºÐœÐŸÐ¿ÐºÑ Ð² ÐŽÐžÐ°Ð³ÑÐ°ÐŒÐŒÐµ. }
+
+_textwyar_ [l=ru] {ÐÐŸÐ³ÐŽÐ° ÐÑ Ð³ÐŸÑÐŸÐ²Ñ, ÐœÐ°Ð¶ÐŒÐžÑÐµ Ð·ÐµÐ»ÐµÐœÑÑ ÐºÐœÐŸÐ¿ÐºÑ "ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž", ÑÑÐŸÐ±Ñ ÐœÐ°ÑÐ°ÑÑ ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÑÑ Ð²Ð°ÑÑ ÐœÐŸÐ²ÑÑ ÑÐžÑÑÐŸÐ²ÑÑ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ!}
+
+_textcnmbs_ [l=ru] {ÐÐŒÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŽÐŸÐ»Ð¶ÐœÐŸ Ð±ÑÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐŸ}
+_texteambs_ [l=ru] {ÐÐŽÑÐµÑ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ ÐŽÐŸÐ»Ð¶ÐµÐœ Ð±ÑÑÑ ÑÐºÐ°Ð·Ð°Ðœ}
+_textpsea_ [l=ru] {ÐÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ°, ÑÐºÐ°Ð¶ÐžÑÐµ Ð°ÐŽÑÐµÑ ÑÐ».Ð¿ÐŸÑÑÑ Ð² Ð²ÐžÐŽÐµ: usename@domain}
+_textdocmbs_ [l=ru] {ÐÐ¿ÐžÑÐ°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŽÐŸÐ»Ð¶ÐœÐŸ Ð±ÑÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐŸ}
+
+_textwcanc_ [l=ru] {ÐÑÐž ÑÐŸÐ·ÐŽÐ°ÐœÐžÐž ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð²Ñ ÐŽÐŸÐ»Ð¶ÐœÑ Ð²Ð²ÐµÑÑÐž ÐœÐµÐŒÐœÐŸÐ³ÐŸ Ð¿ÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐŸÐ± ÐžÑÑ
+ÐŸÐŽÐœÑÑ
+ ÐŽÐ°ÐœÐœÑÑ
+. Ð­ÑÐŸÑ Ð¿ÑÐŸÑÐµÑÑ ÑÑÑÑÐºÑÑÑÐžÑÐŸÐ²Ð°Ðœ ÐºÐ°Ðº ÑÑÐŽ Ð²ÐµÐ±-ÑÑÑÐ°ÐœÐžÑ, Ð·Ð° ÐºÐŸÑÐŸÑÑÐŒÐž ÐœÐ°Ð±Ð»ÑÐŽÐ°ÐµÑ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ. ÐÐ±Ð»Ð°ÑÑÑ Ð²ÐœÐžÐ·Ñ ÑÑÑÐ°ÐœÐžÑÑ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÑ ÐÐ°ÐŒ Ð¿ÐŸÑÐ»ÐµÐŽÐŸÐ²Ð°ÑÐµÐ»ÑÐœÐŸÑÑÑ ÑÑÑÐ°ÐœÐžÑ ÐŽÐŸ ÐŒÐŸÐŒÐµÐœÑÐ° ÐŸÐºÐŸÐœÑÐ°ÐœÐžÑ Ð¿ÑÐŸÑÐµÑÑÐ°. }
+
+_texttfc_ [l=ru] {ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+
+_texttctiasp_ [l=ru] {ÐÐ°Ð³ÐŸÐ»ÐŸÐ²ÐŸÐº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž - ÐºÐŸÑÐŸÑÐºÐ°Ñ ÑÑÐ°Ð·Ð°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐ°Ñ Ð²ÑÑÐŽÑ Ð² ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐµ, ÑÑÐŸÐ±Ñ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑÐžÐŒÐµÑ ÐÐ°Ð³ÐŸÐ»ÐŸÐ²ÐºÐ°: "Ð¢ÐµÑ
+ÐœÐžÑÐµÑÐºÐžÐ¹ ÐŸÑÑÐµÑ Ð¿ÐŸ Ð¿ÑÐŸÐµÐºÑÐ°ÐŒ ÐŸÑÐŽÐµÐ»Ð°"  Ðž  "ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ° Ð³ÑÐŒÐ°ÐœÐžÑÐ°ÑÐœÐŸÐ³ÐŸ ÑÐ°Ð·Ð²ÐžÑÐžÑ" }
+
+_textcea_ [l=ru] {ÐÐŸÐœÑÐ°ÐºÑÐœÑÐ¹ Ð°ÐŽÑÐµÑ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ:}
+
+_textteas_ [l=ru] {Ð­ÑÐŸÑ Ð°ÐŽÑÐµÑ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÑ Ð¿ÐµÑÐ²ÑÑ ÑÐŸÑÐºÑ ÐºÐŸÐœÑÐ°ÐºÑÐ° ÐŽÐ»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÑÐ»Ðž Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ ÐÑÐžÐœÑÑÐŸÑÐœ ÐŸÐ±ÐœÐ°ÑÑÐ¶ÐžÐ²Ð°ÐµÑ Ð¿ÑÐŸÐ±Ð»ÐµÐŒÑ, ÐŽÐžÐ°Ð³ÐœÐŸÑÑÐžÑÐµÑÐºÐŸÐµ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐµ Ð¿ÐŸÑÑÐ»Ð°ÑÑ Ð¿ÐŸ ÑÑÐŸÐŒÑ Ð°ÐŽÑÐµÑÑ. ÐÐ²ÐµÐŽÐžÑÐµ Ð°ÐŽÑÐµÑ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ Ð² ÐµÐ³ÐŸ Ð¿ÐŸÐ»ÐœÐŸÐ¹ ÑÐŸÑÐŒÐµ: name@domain. }
+
+_textatc_ [l=ru] {Ð ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž:}
+
+_texttiasd_ [l=ru] {Ð­ÑÐŸ - ÐžÐœÑÑÑÑÐºÑÐžÑ, ÐŸÐ¿ÐžÑÑÐ²Ð°ÑÑÐ°Ñ Ð¿ÑÐžÐœÑÐžÐ¿Ñ, Ð¿ÐŸ ÐºÐŸÑÐŸÑÑÐŒ ÐŽÐ°ÐœÐœÑÐµ Ð±ÑÐ»Ðž Ð²ÐºÐ»ÑÑÐµÐœÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ. Ð­ÑÐ° ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ ÐœÐ° Ð¿ÐµÑÐ²ÐŸÐ¹ ÑÑÑÐ°ÐœÐžÑÐµ Ð¿ÑÐž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. }
+
+_textypits_ [l=ru] {ÐÐ°ÑÐ° Ð¿ÐŸÐ·ÐžÑÐžÑ Ð² Ð¿ÑÐŸÑÐµÑÑÐµ ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐ° ÑÑÑÐµÐ»ÐºÐŸÐ¹ Ð²ÐœÐžÐ·Ñ - Ð² ÑÑÐŸÐŒ ÑÐ»ÑÑÐ°Ðµ ÐœÐ° "ÑÑÐ°ÐŽÐžÐž" ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐ»Ñ Ð¿ÑÐŸÐŽÐŸÐ»Ð¶ÐµÐœÐžÑ ÐœÐ°Ð¶ÐŒÐžÑÐµ Ð·ÐµÐ»ÐµÐœÑÑ ÐºÐœÐŸÐ¿ÐºÑ "source data/ÐžÑÑ
+ÐŸÐŽÐœÑÐµ ÐŽÐ°ÐœÐœÑÐµ". }
+
+_srcebadsources_ [l=ru] {ÐÐŽÐžÐœ ÐžÐ»Ðž Ð±ÐŸÐ»ÐµÐµ ÑÐºÐ°Ð·Ð°ÐœÐœÑÑ
+ Ð²Ð°ÐŒÐž ÐžÑÑÐŸÑÐœÐžÐºÐŸÐ² ÐœÐµ ÐŽÐŸÑÑÑÐ¿ÐœÑ (ÐœÐžÐ¶Ðµ Ð¿ÐŸÐŒÐµÑÐµÐœÑ _iconcross_).
+<p>Ð­ÑÐŸ ÐŒÐŸÐ¶ÐµÑ ÑÐ»ÑÑÐžÑÑÑÑ Ð¿ÐŸ Ð¿ÑÐžÑÐžÐœÐµ:
+<ul>
+<li>Ð€Ð°Ð¹Ð»,FTP-ÑÐ°Ð¹Ñ ÐžÐ»Ðž URL ÐœÐµ ÑÑÑÐµÑÑÐ²ÑÑÑ. 
+
+<li>Ð¡ÐœÐ°ÑÐ°Ð»Ð° Ð²Ñ ÐŽÐŸÐ»Ð¶ÐœÑ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ dial up ÑÐŸÐµÐŽÐžÐœÐµÐœÐžÐµ Ñ Ð²Ð°ÑÐžÐŒ ÐžÐœÑÐµÑÐœÐµÑ-ÑÐµÑÐ²ÐžÑ Ð¿ÑÐŸÐ²Ð°Ð¹ÐŽÐµÑÐŸÐŒ. 
+<li>ÐÑ Ð¿ÑÐŸÐ±ÑÐµÑÐµ ÐŸÐ±ÑÐ°ÑÐžÑÑÑÑ Ðº URL ÑÐµÑÐµÐ· - ÑÐžÑÑÐµÐŒÑ ÑÐµÑÐµÐ²ÐŸÐ¹ Ð·Ð°ÑÐžÑÑ ÑÐ°Ð¹ÐµÑÐ²ÐŸÐ»Ð» (ÐŽÐµÐ»ÐŸ ÐŸÐ±ÑÑÐŸÐžÑ ÑÐ°Ðº, ÐµÑÐ»Ðž ÐŸÐ±ÑÑÐœÐŸ Ð²Ñ ÐŽÐŸÐ»Ð¶ÐœÑ Ð²Ð²ÐµÑÑÐž ÐžÐŒÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ Ðž Ð¿Ð°ÑÐŸÐ»Ñ ÐŽÐ»Ñ ÐŽÐŸÑÑÑÐ¿Ð° Ðº ÑÐµÑÐž ÐÐœÑÐµÑÐœÐµÑ). 
+</ul>
+<p>ÐÑÐ»Ðž ÑÑÐŸ - URL, ÐºÐŸÑÐŸÑÑÐ¹ Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÐžÐŽÐµÑÑ Ð² Ð²Ð°ÑÐµÐŒ Ð±ÑÐŸÑÐ·ÐµÑÐµ, ÑÐŸ ÐŸÐœ ÐŒÐŸÐ¶ÐµÑ ÐžÑÑ
+ÐŸÐŽÐžÑÑ ÐžÐ· Ð»ÐŸÐºÐ°Ð»ÑÐœÐŸÐ¹ ÐºÑÑ-ÐºÐŸÐ¿ÐžÐž. Ð ÑÐŸÐ¶Ð°Ð»ÐµÐœÐžÑ,  Ð»ÐŸÐºÐ°Ð»ÑÐœÑÐµ ÐºÑÑ-ÐºÐŸÐ¿ÐžÐž ÐœÐµÐ²ÐžÐŽÐžÐŒÑ ÐŽÐ»Ñ ÐœÐ°ÑÐµÐ³ÐŸ Ð¿ÑÐŸÑÐµÑÑÐ° Ð·ÐµÑÐºÐ°Ð»ÐžÑÐŸÐ²Ð°ÐœÐžÑ. Ð ÑÑÐŸÐŒ ÑÐ»ÑÑÐ°Ðµ ÐŒÑ ÑÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÐŒ, ÑÑÐŸÐ±Ñ ÑÐœÐ°ÑÐ°Ð»Ð° Ð²Ñ Ð·Ð°Ð³ÑÑÐ·ÐžÐ»Ðž ÑÑÑÐ°ÐœÐžÑÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð²Ð°Ñ Ð±ÑÐŸÑÐ·ÐµÑ .}
+
+_textymbyco_ [l=ru] {<p> ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŸÑÐœÐŸÐ²Ð°ÑÑ ÐÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐ»Ðž ÐœÐ°
+<ul>
+<li> Ð¡ÑÑÑÐºÑÑÑÐ° Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ   <dl><dd> ÐÐŸÐ²Ð°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŒÐŸÐ¶ÐµÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ HTML (.htm.html),  ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ð¿ÑÐŸÑÑÐŸÐ³ÐŸ ÑÐµÐºÑÑÐ° (.txt.text), ÐŽÐŸÐºÑÐŒÐµÐœÑÑ MS Word (.doc), ÐŽÐŸÐºÑÐŒÐµÐœÑÑ PDF (.pdf) ÐžÐ»Ðž ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ð² ÑÐŸÑÐŒÐ°ÑÐµ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ"m-box" (.mbx). </dd></dl>
+<li> Ð¡ÑÑÐµÑÑÐ²ÑÑÑÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ
+<dl><dd> Ð€Ð°Ð¹Ð»Ñ Ð² ÐÐ°ÑÐµÐ¹ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÑÐŸÑÐœÐŸ ÑÐ°ÐºÐŸÐ³ÐŸ Ð¶Ðµ ÑÐžÐ¿Ð°, ÐºÐ°Ðº ÑÐµ ÑÑÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÑ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. </dd> </dl>
+</ul>}
+
+_textbtco_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐŸÑÐœÐŸÐ²Ð°ÐœÐ° ÐœÐ°}
+_textand_ [l=ru] {ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÑÐµ ÐŽÐ°ÐœÐœÑÐµ}
+_textad_ [l=ru] {ÐÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÑÐµ ÐŽÐ°ÐœÐœÑÐµ:}
+
+_texttftysb_ [l=ru] {<p> Ð€Ð°Ð¹Ð»Ñ, ÐºÐŸÑÐŸÑÑÐµ Ð²Ñ ÑÐºÐ°Ð¶ÐžÑÐµ ÐœÐžÐ¶Ðµ, Ð±ÑÐŽÑÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÑ Ðº ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð£ÐŽÐŸÑÑÐŸÐ²ÐµÑÑÑÐµÑÑ, ÑÑÐŸ Ð²Ñ ÐœÐµ Ð¿ÐµÑÐµÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÑÐµ ÑÐ°Ð¹Ð»Ñ, ÐºÐŸÑÐŸÑÑÐµ ÐœÐ°Ñ
+ÐŸÐŽÑÑÑÑ ÑÐ¶Ðµ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž: ÐžÐœÐ°ÑÐµ Ð±ÑÐŽÑÑ Ð²ÐºÐ»ÑÑÐµÐœÑ ÐŽÐ²Ðµ ÐºÐŸÐ¿ÐžÐž. Ð€Ð°Ð¹Ð»Ñ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐžÐŽÐµÐœÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÐœÑ  Ð¿ÐŸÐ»ÐœÑÐŒ ÐžÐŒÐµÐœÐµÐŒ ÐžÑ
+ Ð¿ÑÑÐž, Web-ÑÑÑÐ°ÐœÐžÑÑ ÐžÑ
+ Ð°Ð±ÑÐŸÐ»ÑÑÐœÑÐŒ Ð²ÐµÐ±-Ð°ÐŽÑÐµÑÐŸÐŒ.
+}
+
+_textis_ [l=ru] {ÐÑ
+ÐŸÐŽÐœÑÐµ ÐžÑÑÐŸÑÐœÐžÐºÐž:}
+
+_textddd1_ [l=ru] {<p> ÐÑÐ»Ðž ÐÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÐµ  file:// ÐžÐ»Ðž ftp:// ÐŽÐ»Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ ÑÐ°Ð¹Ð»Ð°, ÑÑÐŸÑ ÑÐ°Ð¹Ð» Ð±ÑÐŽÐµÑ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœ.
+
+<p>ÐÑÐ»Ðž ÐÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÐµ http:// , ÑÑÐŸ Ð·Ð°Ð²ÐžÑÐžÑ ÐŸÑ ÑÐŸÐ³ÐŸ, ÐŽÐ°ÐµÑ Ð»Ðž ÐÐ°ÐŒ ÐŽÐ°ÐœÐœÑÐ¹ URL ÐœÐŸÑÐŒÐ°Ð»ÑÐœÐŸÐµ ÐŸÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ Ð²ÐµÐ±-ÑÑÑÐ°ÐœÐžÑÑ Ð¿ÑÐž ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐž ÐÐ°ÑÐµÐ³ÐŸ Ð±ÑÐ°ÑÐ·ÐµÑÐ° ÐžÐ»Ðž ÑÐ¿ÐžÑÐŸÐº ÑÐ°Ð¹Ð»ÐŸÐ². ÐÑÐ»Ðž ÑÑÑÐ°ÐœÐžÑÑ, ÑÐŸ ÑÑÐ° ÑÑÑÐ°ÐœÐžÑÐ° Ð±ÑÐŽÐµÑ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐ° - Ðž ÑÐ°Ðº ÑÐŸ Ð²ÑÐµÐŒÐž ÑÑÑÐ°ÐœÐžÑÐ°ÐŒÐž, Ñ ÐºÐŸÑÐŸÑÑÐŒÐž ÐŸÐœÐ° ÐžÐŒÐµÐµÑ ÑÑÑÐ»ÐºÐž, Ðž ÑÐŸ Ð²ÑÐµÐŒÐž ÑÑÑÐ°ÐœÐžÑÐ°ÐŒÐž, Ðº ÐºÐŸÑÐŸÑÑÐŒ ÐŸÐœÐž ÐžÐŒÐµÐµÑÑ ÑÐ²ÑÐ·Ðž, Ðž Ñ.ÐŽ. - ÑÐ°Ð·ÐŒÐµÑÐµÐœÐœÑÑ
+ ÐœÐ° ÑÐŸÐ¹ Ð¶Ðµ ÑÑÑÐ°ÐœÐžÑÐµ ÐœÐžÐ¶Ðµ ÑÐºÐ°Ð·Ð°ÐœÐœÐŸÐ³ÐŸ Ð°ÐŽÑÐµÑÐ° URL.
+
+<p>ÐÑÐ»Ðž ÐÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÐµ file:// ÐžÐ»Ðž ftp:// ÐŽÐ»Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ Ð¿Ð°Ð¿ÐºÐž ÐžÐ»Ðž ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž ÐžÐ»Ðž ÐŽÐ°ÐµÑÐµ http:// URL, ÐºÐŸÑÐŸÑÑÐ¹ Ð²ÑÐ·ÑÐ²Ð°ÐµÑ ÑÐ¿ÐžÑÐŸÐº ÑÐ°Ð¹Ð»ÐŸÐ², Ð²ÑÐµ ÑÑÐŸ ÐµÑÑÑ Ð² Ð¿Ð°Ð¿ÐºÐ°Ñ
+ Ðž Ð²ÑÐµÑ
+ ÐµÐµ Ð¿ÐŸÐŽÐ¿Ð°Ð¿ÐºÐ°Ñ
+, Ð±ÑÐŽÐµÑ Ð²ÐºÐ»ÑÑÐµÐœÐŸ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+
+<p> Ð©ÐµÐ»ÐºÐœÐžÑÐµ ÐºÐœÐŸÐ¿ÐºÑ "Ð±ÐŸÐ»ÑÑÐµ ÐžÑÑÐŸÑÐœÐžÐºÐŸÐ²" , ÑÑÐŸÐ±Ñ Ð¿ÐŸÐ»ÑÑÐžÑÑ Ð±ÐŸÐ»ÑÑÐµ Ð²Ñ
+ÐŸÐŽÐœÑÑ
+ Ð¿ÐŸÐ»ÐµÐ¹.}
+
+_textddd2_ [l=ru] {<p> ÐÐ°Ð¶ÐŒÐžÑÐµ ÐŸÐŽÐœÑ ÐžÐ· Ð·ÐµÐ»ÐµÐœÑÑ
+ ÐºÐœÐŸÐ¿ÐŸÐº. ÐÑÐ»Ðž Ð²Ñ  ÑÑÐ²ÑÑÐ²ÑÐµÑÐµ ÑÐµÐ±Ñ ÐŸÐ¿ÑÑÐœÑÐŒ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÐµÐŒ, ÑÐŸ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ Ð¿ÐŸÐ¶ÐµÐ»Ð°ÐµÑÐµ ÐŸÑÐºÐŸÑÑÐµÐºÑÐžÑÐŸÐ²Ð°ÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð ÐºÐ°ÑÐµÑÑÐ²Ðµ Ð°Ð»ÑÑÐµÑÐœÐ°ÑÐžÐ²Ñ Ð²Ð°ÐŒ Ð¿ÑÐµÐŽÐ»Ð°Ð³Ð°ÐµÑÑÑ Ð¿ÐµÑÐµÐ¹ÑÐž Ð¿ÑÑÐŒÐŸ Ð² ÑÑÐ°ÐŽÐžÑ ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÑ. ÐÐŸÐŒÐœÐžÑÐµ, Ð²Ñ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÑÐµÐ³ÐŽÐ° Ð¿ÐŸÐ²ÑÐŸÑÐœÐŸ Ð²ÐŸÐ¿ÐŸÑÐµÐ·Ð²ÑÐ°ÑÐžÑÑÑÑ ÐœÐ° ÑÐ°ÐœÐœÑÑ ÑÑÐ°ÐŽÐžÑ, ÑÐµÐ»ÐºÐ°Ñ Ð¿ÐŸ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐ¹ Ð¶ÐµÐ»ÑÐŸÐ¹ ÐºÐœÐŸÐ¿ÐºÐµ. }
+
+_textconf1_ [l=ru] {<p> Ð€ÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ðž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ Ð²Ð°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÐµÑÑÑ ÑÐ¿ÐµÑÐžÑÐžÐºÐ°ÑÐžÑÐŒÐž Ñ
+ÑÐ°ÐœÑÑÐžÐŒÐžÑÑ Ð² ÑÐ¿ÐµÑÐžÐ°Ð»ÑÐœÐŸÐŒ "ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÐŸÐŒ ÑÐ°Ð¹Ð»Ðµ". ÐÐ¿ÑÑÐœÑÐµ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ðž Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ Ð¿ÐŸÐ¶ÐµÐ»Ð°ÑÑ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž. 
+<center><p><b>ÐÑÐ»Ðž Ð²Ñ  ÑÑÐ²ÑÑÐ²ÑÐµÑÐµ ÑÐµÐ±Ñ ÐŸÐ¿ÑÑÐœÑÐŒ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÐµÐŒ, Ð¿ÑÐŸÑÑÐŸ Ð¿ÐµÑÐµÐ¹ÐŽÐžÑÐµ Ð² ÐœÐžÐ¶ÐœÑÑ ÑÐ°ÑÑÑ ÑÑÑÐ°ÐœÐžÑÑ.</b></center>
+<p> Ð§ÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž, ÐŸÑÑÐµÐŽÐ°ÐºÑÐžÑÑÐ¹ÑÐµ ÐŽÐ°ÐœÐœÑÐµ, ÐºÐŸÑÐŸÑÑÐµ Ð¿ÐŸÑÐ²ÑÑÑÑ ÐœÐžÐ¶Ðµ. ÐÑÐ»Ðž Ð²Ñ ÑÐŽÐµÐ»Ð°ÐµÑÐµ ÐŸÑÐžÐ±ÐºÑ, ÐœÐ°Ð¶ÐŒÐžÑÐµ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÑ "ÐÑÐžÑÑÐžÑÑ", ÑÑÐŸÐ±Ñ Ð²ÐŸÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ Ð¿ÐµÑÐ²ÐŸÐœÐ°ÑÐ°Ð»ÑÐœÑÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ ÐœÐ°ÑÑÑÐŸÐ¹ÐºÐž. }
+
+_textreset_ [l=ru] {Ð¡Ð±ÑÐŸÑÐžÑÑ}
+
+_textbild1_ [l=ru] {<p>ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ  ÑÐŸÑÐŒÐžÑÑÐµÑÑÑ: ÑÑÐŸ Ð·Ð°Ð¹ÐŒÐµÑ ÐœÐµÐºÐŸÑÐŸÑÐŸÐµ Ð²ÑÐµÐŒÑ. Ð ÑÑÑÐŸÐºÐµ ÑÐŸÑÑÐŸÑÐœÐžÑ Ð¿ÑÐŸÑÐµÑÑÐ° ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÑ, ÐŸÑÐŸÐ±ÑÐ°Ð¶Ð°ÐµÑÑÑ Ð¿ÑÐŸÐ³ÑÐµÑÑ ÐŸÐ¿ÐµÑÐ°ÑÐžÐž. }
+
+_textbild2_ [l=ru] {Ð§ÑÐŸÐ±Ñ ÐŸÑÑÐ°ÐœÐŸÐ²ÐžÑÑ Ð¿ÑÐŸÑÐµÑÑ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÑÐµÐ»ÐºÐœÐžÑÐµ Ð·ÐŽÐµÑÑ.
+<br> ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐœÐ°ÐŽ ÐºÐŸÑÐŸÑÐŸÐ¹ ÐÑ ÑÐ°Ð±ÐŸÑÐ°ÐµÑÐµ, ÐŸÑÑÐ°ÐœÐµÑÑÑ ÐœÐµÐ¿ÐŸÐ²ÑÐµÐ¶ÐŽÐµÐœÐœÐŸÐ¹.}
+
+_textstopbuild_ [l=ru] {ÐÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÐµ}
+
+_textbild3_ [l=ru] {<p>  ÐÑÐ»Ðž Ð²Ñ ÐŸÑÑÐ°Ð²Ð»ÑÐµÑÐµ ÑÑÑ ÑÑÑÐ°ÐœÐžÑÑ (Ðž ÐœÐµ ÐŸÑÐŒÐµÐœÐžÐ»Ðž Ð¿ÑÐŸÑÐµÑÑ ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÑ  ÐºÐœÐŸÐ¿ÐºÐŸÐ¹ "ÐÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÐµ"), ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¿ÑÐŸÐŽÐŸÐ»Ð¶ÐžÑ ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÑÑÑÑ Ðž Ð±ÑÐŽÐµÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐ° Ð¿ÐŸÑÐ»Ðµ ÑÑÐ¿ÐµÑÐœÐŸÐ³ÐŸ Ð·Ð°Ð²ÐµÑÑÐµÐœÐžÑ Ð¿ÑÐŸÑÐµÑÑÐ°. }
+
+_textbuildcancelled_ [l=ru] {ÐÑÐŒÐµÐœÐžÑÑ ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ}
+
+_textbildcancel1_ [l=ru] {ÐÑÐŸÑÐµÑÑ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð±ÑÐ» ÐŸÑÐŒÐµÐœÐµÐœ. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ Ð¶ÐµÐ»ÑÑÐµ ÐºÐœÐŸÐ¿ÐºÐž, ÑÐ°ÑÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐœÑÐµ ÐœÐžÐ¶Ðµ, ÑÑÐŸÐ±Ñ Ð²ÐœÐµÑÑÐž ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ Ð² ÐÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐ»Ðž Ð¿ÐŸÐ²ÑÐŸÑÐœÐŸ ÐœÐ°ÑÐ°ÑÑ Ð¿ÑÐŸÑÐµÑÑ ÐµÐµ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ.}
+
+_textbsupdate1_ [l=ru] {Ð¡ÑÐ°ÑÑÑ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐŸÐ±ÐœÐŸÐ²ÐžÑÑÑ ÑÐµÑÐµÐ· 1 ÑÐµÐºÑÐœÐŽÑ}
+_textbsupdate2_ [l=ru] {ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ ÑÑÐ°ÑÑÑÐ° Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ.}
+_textseconds_ [l=ru] {ÑÐµÐºÑÐœÐŽ}
+_textbildsuc_ [l=ru] {Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÑÑÐ¿ÐµÑÐœÐŸ Ð·Ð°Ð²ÐµÑÑÐµÐœÐŸ.}
+
+_textviewbildsummary_ [l=ru] {ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÑÐ°ÑÑÐŒÐŸÑÑÐµÑÑ <a href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>  ÑÐµÐ·ÑÐŒÐµ Ð¿ÑÐŸÑÐµÑÑÐ° ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÑ</a>   ÑÑÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŽÐ»Ñ ÐžÐ·ÑÑÐµÐœÐžÑ Ð¿ÐŸÐŽÑÐŸÐ±ÐœÐŸÑÑÐµÐ¹. }
+
+_textfailmsg11_ [l=ru] {<p>ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµ Ð±ÑÐ»Ð° Ð¿ÐŸÑÑÑÐŸÐµÐœÐ°, Ð¿ÐŸÑÐºÐŸÐ»ÑÐºÑ ÐŸÐœÐ° ÐœÐµ ÑÐŸÐŽÐµÑÐ¶Ð°Ð»Ð° ÐœÐžÐºÐ°ÐºÐžÑ
+ ÐŽÐ°ÐœÐœÑÑ
+. Ð£ÐŽÐŸÑÑÐŸÐ²ÐµÑÑÑÐµÑÑ Ð² ÑÐŸÐŒ, ÑÑÐŸ Ñ
+ÐŸÑÑ Ð±Ñ ÐŸÐŽÐžÐœ ÐžÐ· ÐºÐ°ÑÐ°Ð»ÐŸÐ³ÐŸÐ² ÐžÐ»Ðž ÑÐ°Ð¹Ð»ÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ Ð²Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÐ»Ðž ÐœÐ° ÑÑÑÐ°ÐœÐžÑÐµ  <i>ÐžÑÑ
+ÐŸÐŽÐœÑÑ
+ ÐŽÐ°ÐœÐœÑÑ
+</i>, ÑÑÑÐµÑÑÐ²ÑÐµÑ Ðž ÐžÐŒÐµÐµÑ ÑÐžÐ¿Ñ, ÐžÐ»Ðž (Ð² ÑÐ»ÑÑÐ°Ðµ ÐºÐ°ÑÐ°Ð»ÐŸÐ³Ð°) ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÑÐ°Ð¹Ð»Ñ ÑÐžÐ¿ÐŸÐ², ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÐŒÑÑ
+ ÐÑÐžÐœÑÑÐŸÑÐœ.  }
+
+_textfailmsg21_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ Ð¿ÐŸÑÑÑÐŸÐµÐœÐ° (ÐœÐµÑÐŽÐ°ÑÐœÑÐ¹ import.pl).}
+_textblcont_ [l=ru] {Ð€Ð°Ð¹Ð» ÑÐµÐ³ÐžÑÑÑÐ°ÑÐžÐž ÑÐŸÐ·ÐŽÐ°ÐœÐžÐžÑ ÐŸÐŽÐµÑÐ¶ÐžÑ ÑÐ»ÐµÐŽÑÑÑÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ:}
+
+_texttryagain_ [l=ru] {ÐÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ°, <a href="_httppagecollector_" target=_top>Ð¿ÐµÑÐµÐ·Ð°Ð¿ÑÑÑÐžÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐŸÑ </a>Ðž Ð¿ÐŸÐ¿ÑÑÐ°Ð¹ÑÐµÑÑ ÑÐœÐŸÐ²Ð°.  }
+
+_textfailmsg31_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµ Ð±ÑÐ»Ð° ÑÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐ°(ÑÐ±ÐŸÐ¹ buildcol.pl).}
+_textfailmsg41_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±ÑÐ»Ð° ÑÑÐ¿ÐµÑÐœÐŸ ÑÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐ°, ÐœÐŸ ÐœÐµ Ð±ÑÐ»Ð° ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐ°.}
+_textfailmsg71_ [l=ru] {ÐÐŸ Ð²ÑÐµÐŒÑ Ð¿ÐŸÐ¿ÑÑÐºÐž ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð¿ÑÐŸÐžÐ·ÐŸÑÐ»Ð° ÐœÐµÐžÐ·Ð²ÐµÑÑÐœÐ°Ñ ÐŸÑÐžÐ±ÐºÐ°}
+_textretcoll_ [l=ru] {ÐÐµÑÐœÑÑÑÑÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐŸÑ}
+
+_textdelperm_ [l=ru] {<p> ÐÐµÐºÐŸÑÐŸÑÑÐµ ÑÐ°ÑÑÐž ÐžÐ»Ðž Ð²ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ _cgiargbc1dirname_ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÑÐŽÐ°Ð»ÐµÐœÐ°. ÐÐŸÐ·ÐŒÐŸÐ¶ÐœÑÐµ Ð¿ÑÐžÑÐžÐœÑ: 
+<ul>
+<li> ÐÑÐžÐœÑÑÐŸÑÐœ ÐœÐµ ÐžÐŒÐµÐµÑ ÑÐ°Ð·ÑÐµÑÐµÐœÐžÑ ÐœÐ° ÑÐŽÐ°Ð»ÐµÐœÐžÐµ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž gsdlhome_/collect/_cgiargbc1dirname_.
+<br> ÐÐŸÐ¿ÑÐŸÐ±ÑÐ¹ÑÐµ Ð²ÑÑÑÐœÑÑ ÑÐŽÐ°Ð»ÐžÑÑ ÑÑÐŸÑ ÐºÐ°ÑÐ°Ð»ÐŸÐ³ Ñ Ð²Ð°ÑÐµÐ³ÐŸ ÐºÐŸÐŒÐ¿ÑÑÑÐµÑÐ°. }
+
+_textdelinv_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ _cgiargbc1dirname_ Ð·Ð°ÑÐžÑÐµÐœÐ° ÐžÐ»Ðž Ð¿ÐŸÐ²ÑÐµÐ¶ÐŽÐµÐœÐ°. ÐÑÐŸÑÐµÑÑ ÑÐŽÐ°Ð»ÐµÐœÐžÑ ÐŸÑÐŒÐµÐœÐµÐœ. }
+
+_textdelsuc_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ _cgiargbc1dirname_ Ð±ÑÐ»Ð° ÑÑÐ¿ÐµÑÐœÐŸ ÑÐŽÐ°Ð»ÐµÐœÐ°.}
+
+_textclonefail_ [l=ru] {ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐŽÑÐ±Ð»ÐžÐºÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž _cgiargclonecol_. ÐÐŸÐ·ÐŒÐŸÐ¶ÐœÑÐµ Ð¿ÑÐžÑÐžÐœÑ: 
+<ul>
+<li> ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ _cgiargclonecol_ ÐœÐµ ÑÑÑÐµÑÑÐ²ÑÐµÑ
+<li> ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ _cgiargclonecol_ ÐœÐµ ÐžÐŒÐµÐµÑ ÑÐ°Ð¹Ð»Ð° ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž collect.cfg 
+<li> ÐÑÐžÐœÑÑÐŸÑÐœ ÐœÐµ ÐžÐŒÐµÐµÑ ÑÐ°Ð·ÑÐµÑÐµÐœÐžÑ ÐŽÐ»Ñ ÑÑÐµÐœÐžÑ ÑÐ°Ð¹Ð»Ð° ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž collect.cfg </ul>}
+
+_textcolerr_ [l=ru] {ÐÑÐžÐ±ÐºÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐŸÑÐ°.}
+
+_texttmpfail_ [l=ru] {ÐÑÐŸÐžÐ·ÐŸÑÐµÐ» ÑÐ±ÐŸÐ¹ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÐ° Ð¿ÑÐž ÑÑÐµÐœÐžÐž  ÐžÐ»Ðž Ð·Ð°Ð¿ÐžÑÐž Ð²ÐŸ Ð²ÑÐµÐŒÐµÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» ÐžÐ»Ðž ÐºÐ°ÑÐ°Ð»ÐŸÐ³. ÐÐŸÐ·ÐŒÐŸÐ¶ÐœÑÐµ Ð¿ÑÐžÑÐžÐœÑ: 
+<ul>
+<li> ÐÑÐžÐœÑÑÐŸÑÐœ ÐœÐµ ÐžÐŒÐµÐµÑ Ð¿ÑÐ°Ð²Ð° ÐŽÐŸÑÑÑÐ¿Ð° ÐŽÐ»Ñ ÑÑÐµÐœÐžÑ/Ð·Ð°Ð¿ÐžÑÐž ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž _gsdlhome_/tmp. </ul>}
+
+_textmkcolfail_ [l=ru] {ÐÑÐŸÐžÐ·ÐŸÑÐµÐ» ÑÐ±ÐŸÐ¹ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÐ° Ð¿ÑÐž ÑÐŸÐ·ÐŽÐ°ÐœÐžÐž ÑÑÑÑÐºÑÑÑÑ Ð¿Ð°Ð¿ÐŸÐº, ÑÑÐµÐ±ÑÐµÐŒÐŸÐ¹ ÐŽÐ»Ñ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž (ÑÐ±ÐŸÐ¹ mkcol.pl). ÐÐŸÐ·ÐŒÐŸÐ¶ÐœÑÐµ Ð¿ÑÐžÑÐžÐœÑ: 
+<ul>
+<li> ÐÑÐžÐœÑÑÐŸÑÐœ ÐœÐµ ÐŸÐ±Ð»Ð°ÐŽÐ°ÐµÑ Ð¿ÑÐ°Ð²Ð°ÐŒÐž Ð·Ð°Ð¿ÐžÑÐž Ð² ÐŽÐžÑÐµÐºÑÐŸÑÐžÑ _gsdlhome_/tmp. 
+<li> ÐÑÐžÐ±ÐºÐ° Ð erl-ÑÐºÑÐžÐ¿ÑÐ° mkcol.pl.
+<li> ÐÐŒÑ ÐœÐ°Ð±ÑÐ°ÐœÐŸ ÐœÐ° ÐºÐžÑÐžÐ»Ð»ÐžÑÐµ. 
+</ul>}
+
+_textnocontent_ [l=ru] {ÐÑÐžÐ±ÐºÐ° ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÐ°: ÐœÐµ Ð±ÑÐ»ÐŸ Ð·Ð°ÐŽÐ°ÐœÐŸ ÐœÐžÐºÐ°ÐºÐŸÐ³ÐŸ ÐžÐŒÐµÐœÐž ÐŽÐ»Ñ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐŸÐ¿ÑÐŸÐ±ÑÐ¹ÑÐµ Ð¿ÐµÑÐµÐ·Ð°Ð¿ÑÑÑÐžÑÑ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ. }
+
+_textrestart_ [l=ru] {ÐÐµÑÐµÐ·Ð°Ð¿ÑÑÑÐžÑÑ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ}
+
+_textreloaderror_ [l=ru] {ÐÑÐŸÐžÐ·ÐŸÑÐ»Ð° ÐŸÑÐžÐ±ÐºÐ°  Ð¿ÑÐž ÑÐŸÐ·ÐŽÐ°ÐœÐžÐž ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð­ÑÐŸ, Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ, Ð¿ÑÐŸÐžÐ·ÐŸÑÐ»ÐŸ ÐžÐ·-Ð·Ð° Ð¿ÑÑÐ°ÐœÐžÑÑ Ð² ÐºÐœÐŸÐ¿ÐºÐ°Ñ
+ "Ð¿ÐµÑÐµÐ·Ð°Ð³ÑÑÐ·ÐºÐ°" Ðž "ÐœÐ°Ð·Ð°ÐŽ" Ð²Ð°ÑÐµÐ³ÐŸ Ð±ÑÐŸÑÐ·ÐµÑÐ° (Ð¿ÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ° Ð¿ÑÐŸÐ±ÑÐ¹ÑÐµ ÐžÐ·Ð±ÐµÐ¶Ð°ÑÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÑÐžÑ
+ ÐºÐœÐŸÐ¿ÐŸÐº Ð¿ÑÐž ÑÐŸÐ·ÐŽÐ°ÐœÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ñ Ð¿ÐŸÐŒÐŸÑÑÑ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑÐ°). Ð ÐµÐºÐŸÐŒÐµÐœÐŽÑÐµÑÑÑ Ð¿ÐµÑÐµÐ·Ð°Ð¿ÑÑÑÐžÑÑ ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ. }
+
+_textexptsuc_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ  _cgiargbc1dirname_ Ð±ÑÐ»Ð° ÑÑÐ¿ÐµÑÐœÐŸ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐ° Ð² ÐŽÐžÑÐµÐºÑÐŸÑÐžÑ _gsdlhome_/tmp/exported\__cgiargbc1dirname_. }
+
+_textexptfail_ [l=ru] {Ð¡Ð±ÐŸÐ¹ Ð¿ÑÐž ÑÐºÑÐ¿ÐŸÑÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž _cgiargbc1dirname_. 
+Ð­ÑÐŸ, Ð²ÐµÑÐŸÑÑÐœÐŸ, Ð¿ÑÐŸÐžÐ·ÐŸÑÐ»ÐŸ Ð¿ÐŸÑÐŸÐŒÑ, ÑÑÐŸ ÐÑÐžÐœÑÑÐŸÑÐœ Ð±ÑÐ» ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ Ð±ÐµÐ· ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÑÑ
+ ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑÐŸÐ² Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÐž ÑÑÐœÐºÑÐžÐž "Ð­ÐºÑÐ¿ÐŸÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž". 
+<ul>
+<li> ÐÑÐ»Ðž Ð²Ñ ÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°Ð»Ðž ÐÑÐžÐœÑÑÐŸÑÐœ Ñ CD-ROM, ÑÑÐž ÐºÐŸÐŒÐ¿ÐŸÐœÐµÐœÑÑ ÐœÐµ Ð±ÑÐŽÑÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ, ÐµÑÐ»Ðž Ð²Ñ ÐœÐµ Ð²ÑÐ±ÑÐ°Ð»Ðž ÐžÑ
+ Ð²ÐŸ Ð²ÑÐµÐŒÑ Ð²ÑÐ±ÐŸÑÐŸÑÐœÐŸÐ¹ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐž. ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ ÐŽÐŸÐ±Ð°Ð²ÐžÑÑ, Ð¿ÑÐŸÐ²ÐµÐŽÑ Ð¿ÐŸÐ²ÑÐŸÑÐœÑÑ ÑÑÑÐ°ÐœÐŸÐ²ÐºÑ.
+<li> ÐÑÐ»Ðž Ð²Ñ ÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°Ð»Ðž ÐÑÐžÐœÑÑÐŸÑÐœ Ñ Ð²ÐµÐ±-ÐŽÐžÑÑÑÐžÐ±ÑÑÐžÐ²ÐŸÐ², ÑÐŸ Ð²Ð°ÐŒ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ Ð±ÑÐŽÐµÑ Ð·Ð°Ð³ÑÑÐ·ÐžÑÑ Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÑÐ¹ Ð¿Ð°ÐºÐµÑ, ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°ÑÑÐžÐ¹ ÑÐ°Ð±ÐŸÑÑ ÑÑÐœÐºÑÐžÐž ÑÐºÑÐ¿ÐŸÑÑÐ°. ÐÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ°, Ð¿ÐŸÑÐµÑÐžÑÐµ ÑÐ°Ð¹Ñ  <a href="http://www.greenstone.org"> http://www.greenstone.org </a> ÐžÐ»Ðž Ð¿ÐŸÑÐ»ÐžÑÐµ Ð·Ð°Ð¿ÑÐŸÑ Ð¿ÐŸ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÐµ <a href="mailto:greenstone@cs.waikato.ac.nz">
+greenstone@cs.waikato.ac.nz </a>  ÐŽÐ»Ñ Ð¿ÐŸÐ»ÑÑÐµÐœÐžÑ ÐŽÐ°Ð»ÑÐœÐµÐ¹ÑÐžÑ
+ ÐžÐœÑÑÑÑÐºÑÐžÐ¹. }
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐÐŸÐ»Ð»ÐµÐºÑÐŸÑ" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=ru] {_httpimg_/ru/h\_colect.gif}
+
+## "collection\ninformation" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=ru] {_httpimg_/ru/gcinfoof.gif}
+_httpicongcinfoon_ [l=ru] {_httpimg_/ru/gcinfoon.gif}
+_httpiconycinfoof_ [l=ru] {_httpimg_/ru/ycinfoof.gif}
+_httpiconycinfoon_ [l=ru] {_httpimg_/ru/ycinfoon.gif}
+_httpiconncinfoof_ [l=ru] {_httpimg_/ru/ncinfoof.gif}
+
+## "source\ndata" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=ru] {_httpimg_/ru/gcsrceof.gif}
+_httpicongcsrceon_ [l=ru] {_httpimg_/ru/gcsrceon.gif}
+_httpiconycsrceof_ [l=ru] {_httpimg_/ru/ycsrceof.gif}
+_httpiconycsrceon_ [l=ru] {_httpimg_/ru/ycsrceon.gif}
+_httpiconncsrceof_ [l=ru] {_httpimg_/ru/ncsrceof.gif}
+
+## "configure\ncollection" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=ru] {_httpimg_/ru/gcconfof.gif}
+_httpicongcconfon_ [l=ru] {_httpimg_/ru/gcconfon.gif}
+_httpiconycconfof_ [l=ru] {_httpimg_/ru/ycconfof.gif}
+_httpiconycconfon_ [l=ru] {_httpimg_/ru/ycconfon.gif}
+_httpiconncconfof_ [l=ru] {_httpimg_/ru/ncconfof.gif}
+
+## "build\ncollection" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=ru] {_httpimg_/ru/gcbildof.gif}
+_httpicongcbildon_ [l=ru] {_httpimg_/ru/gcbildon.gif}
+_httpiconycbildof_ [l=ru] {_httpimg_/ru/ycbildof.gif}
+_httpiconycbildon_ [l=ru] {_httpimg_/ru/ycbildon.gif}
+_httpiconncbildof_ [l=ru] {_httpimg_/ru/ncbildof.gif}
+
+## "view\ncollection" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=ru] {_httpimg_/ru/gcviewof.gif}
+_httpicongcviewon_ [l=ru] {_httpimg_/ru/gcviewon.gif}
+_httpiconycviewof_ [l=ru] {_httpimg_/ru/ycviewof.gif}
+_httpiconycviewon_ [l=ru] {_httpimg_/ru/ycviewon.gif}
+_httpiconncviewof_ [l=ru] {_httpimg_/ru/ncviewof.gif}
+
+## "delete\ncollection" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=ru] {_httpimg_/ru/gcdelof.gif}
+_httpicongcdelon_ [l=ru] {_httpimg_/ru/gcdelon.gif}
+
+## "export\ncollection" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=ru] {_httpimg_/ru/gcexptof.gif}
+_httpicongcexpton_ [l=ru] {_httpimg_/ru/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=ru] {ÐÑÐžÐœÑÑÐŸÑÐœ, ÐºÐŸÐŒÐ¿Ð»ÐµÐºÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐ³ÐŸ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž ÐŽÐ»Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ, Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ Ðž ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÐµÐœÐžÑ Ð¿ÐŸÐ»ÐœÐŸÑÐµÐºÑÑÐŸÐ²ÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹. Ð­ÑÐ° ÑÐžÑÑÐµÐŒÐ° ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°ÐµÑ ÐœÐŸÐ²ÑÐ¹ ÑÐ¿ÐŸÑÐŸÐ± ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÐž ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐŽÐ»Ñ ÐŸÐ¿ÑÐ±Ð»ÐžÐºÐŸÐ²Ð°ÐœÐžÑ ÐœÐ° ÐºÐŸÐŒÐ¿Ð°ÐºÑ ÐŽÐžÑÐºÐ°Ñ
+, Ð»ÐŸÐºÐ°Ð»ÑÐœÑÑ
+ ÑÐµÑÑÑ
+ Ðž ÐžÐœÑÐµÑÐœÐµÑ. ÐÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ Ð¿ÑÐŸÐžÐ·Ð²ÐµÐŽÐµÐœÐŸ Ð² ÑÐ°ÐŒÐºÐ°Ñ
+ Ð¿ÑÐŸÐµÐºÑÐ° ÐÐŸÐ²ÐŸÐ·ÐµÐ»Ð°ÐœÐŽÑÐºÐŸÐ¹ ÐŠÐžÑÑÐŸÐ²ÐŸÐ¹ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž Ð£ÐœÐžÐ²ÐµÑÑÐžÑÐµÑÐ° ÐÐ°Ð¹ÐºÐ°ÑÐŸ, Ð² ÑÐŸÑÑÑÐŽÐœÐžÑÐµÑÑÐ²Ðµ Ñ Ð®ÐÐÐ¡ÐÐ Ðž ÐÐÐ Ð§ÐµÐ»ÐŸÐ²ÐµÑÐµÑÐºÐ°Ñ ÐÐœÑÐŸÑÐŒÐ°ÑÐžÑ (Human Info). ÐÐœÑÐµÐ³ÑÐžÑÑÐµÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, Ð¿ÐŸÐ»ÐœÐŸÑÐµÐºÑÑÐŸÐ²ÑÐ¹ Ð¿ÐŸÐžÑÐº Ðž ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ, Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÑ ÐŒÐœÐŸÐ³ÐŸÑÐ·ÑÑÐžÑ, Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÑ ÐŒÐœÐŸÐ³ÐžÑ
+ ÐŸÐ±ÑÐµÑÐ¿ÐŸÑÑÐµÐ±ÐžÐŒÑÑ
+ ÑÐŸÑÐŒÐ°ÑÐŸÐ² Ðž Ð°ÐŽÐŒÐžÐœÐžÑÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒÐž. ÐÑÐžÐœÑÑÐŸÑÐœ ÑÐ²ÐŸÐ±ÐŸÐŽÐœÐŸÐµ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ, Ñ ÐŸÑÐºÑÑÑÑÐŒÐž ÐžÑÑ
+ÐŸÐŽÐœÑÐŒÐž ÐºÐŸÐŽÐ°ÐŒÐž, ÐŽÐŸÑÑÑÐ¿ÐœÐŸ Ð¿ÐŸ Ð°ÐŽÑÐµÑÑ <i><a href="http://greenstone.org"> http://greenstone.org </a>, ÐœÐ° ÑÑÐ»ÐŸÐ²ÐžÑÑ
+ <a href="http://www.gnu.org/copyleft/gpl.html">ÑÑÐ°ÐœÐŽÐ°ÑÑÐœÐŸÐ¹ ÐŸÐ±ÑÐµÑÑÐ²ÐµÐœÐœÐŸÐ¹ Ð»ÐžÑÐµÐœÐ·ÐžÐž</a> (GNU)</i>.}
+
+_textgreenstone2_ [l=ru] {ÐÐµÐ±-ÑÐ°Ð¹Ñ ÐÐŸÐ²ÐŸÐ·ÐµÐ»Ð°ÐœÐŽÑÐºÐŸÐ¹ ÐŠÐžÑÑÐŸÐ²ÐŸÐ¹ ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž  (<a href="http://nzdl.org">http://nzdl.org</a>)  ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÐŒÐœÐŸÐ³ÐŸÑÐžÑÐ»ÐµÐœÐœÑÐµ Ð¿ÑÐžÐŒÐµÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹, ÐºÐŸÑÐŸÑÑÐµ  Ð±ÑÐ»Ðž ÑÐŸÐ·ÐŽÐ°ÐœÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ ÐÑÐžÐœÑÑÐŸÑÐœ, Ðž ÐºÐŸÑÐŸÑÑÐµ ÑÐ²Ð»ÑÑÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÑÐŒÐž ÐŽÐ»Ñ ÑÐ²ÐŸÐ±ÐŸÐŽÐœÐŸÐ³ÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ°. ÐÐœÐž ÐžÐ»Ð»ÑÑÑÑÐžÑÑÑÑ ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ Ð²Ð°ÑÐžÐ°ÐœÑÑ Ð¿ÐŸÐžÑÐºÐ° Ðž Ð¿ÑÐŸÑÐŒÐŸÑÑÐ°, Ðž Ð²ÐºÐ»ÑÑÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐœÐ° Ð°ÑÐ°Ð±ÑÐºÐŸÐŒ, ÐºÐžÑÐ°Ð¹ÑÐºÐŸÐŒ, ÑÑÐ°ÐœÑÑÐ·ÑÐºÐŸÐŒ, ÐžÑÐ¿Ð°ÐœÑÐºÐŸÐŒ,  Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐŸÐŒ ÑÐ·ÑÐºÐ°Ñ
+, Ð° ÑÐ°ÐºÐ¶Ðµ ÐœÐ° ÑÐ·ÑÐºÐµ ÐŒÐ°ÐŸÑÐž. ÐÐŸÐŒÐžÐŒÐŸ ÑÑÐŸÐ³ÐŸ, Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÑ ÐŒÑÐ·ÑÐºÐ°Ð»ÑÐœÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.}
+
+_textplatformtitle_ [l=ru] {ÐÐ»Ð°ÑÑÐŸÑÐŒÐ°}
+_textgreenstone3_ [l=ru] {ÐÑÐžÐœÑÑÐŸÑÐœ ÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÐµÑÑÑ ÐŽÐ»Ñ ÑÐ°Ð±ÐŸÑÑ Ð² ÑÑÐµÐŽÐµ Windows Ðž Ð² ÑÑÐµÐŽÐµ Unix. ÐÐžÑÑÑÐžÐ±ÑÑÐžÐ² Ð²ÐºÐ»ÑÑÐ°ÐµÑ Ð³ÐŸÑÐŸÐ²ÑÐµ Ðº ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÐœÐ°Ð±ÐŸÑÑ ÐŽÐ»Ñ Ð²ÑÐµÑ
+ Ð²ÐµÑÑÐžÐ¹ Windows, Linux Ðž Mac OS X. ÐÐœ ÑÐ°ÐºÐ¶Ðµ Ð²ÐºÐ»ÑÑÐ°ÐµÑ Ð³ÐŸÑÐŸÐ²ÑÑ ÐžÑÑ
+ÐŸÐŽÐœÑÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ ÐŽÐ»Ñ ÑÐžÑÑÐµÐŒÑ, ÐºÐŸÑÐŸÑÐ°Ñ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐŸÑÐºÐŸÐŒÐ¿ÐžÐ»ÐžÑÐŸÐ²Ð°ÐœÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Microsoft C++ ÐžÐ»Ðž gcc. ÐÑÐžÐœÑÑÐŸÑÐœ ÑÐ°Ð±ÐŸÑÐ°ÐµÑ ÑÐŸÐ²ÐŒÐµÑÑÐœÐŸ Ñ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÑÐŒ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµÐŒ, ÐºÐŸÑÐŸÑÐŸÐµ ÑÐ²Ð»ÑÐµÑÑÑ ÑÐ°ÐºÐ¶Ðµ ÑÐ²ÐŸÐ±ÐŸÐŽÐœÐŸ ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÑÐµÐŒÑÐŒ: ÐÐµÐ±ÑÐµÑÐ²ÐµÑ Apache Ðž ÑÐ·ÑÐº PERL. ÐÐœÑÐµÑÑÐµÐ¹Ñ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑ Ð²ÐµÐ±-Ð±ÑÐŸÑÐ·ÐµÑ: ÐŸÐ±ÑÑÐœÐŸ ÐœÐ°Ð²ÐžÐ³Ð°ÑÐŸÑ ÐÐŸÐ·ÐžÐ»Ð»Ð° ÐžÐ»Ðž Internet Explorer. }
+
+_textgreenstone4_ [l=ru] {ÐÐœÐŸÐ¶ÐµÑÑÐ²ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°Ð»ÑÐœÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÑÑÑÑÑ ÐœÐ° CD-ROM, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ ÐÑÐžÐœÑÑÐŸÑÐœ. ÐÐ°Ð¿ÑÐžÐŒÐµÑ <i>ÐÑÐŒÐ°ÐœÐžÑÐ°ÑÐœÐ°Ñ  ÐÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ° Ð Ð°Ð·Ð²ÐžÑÐžÑ</i> ÑÐŸÐŽÐµÑÐ¶ÐžÑ 1 230 Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐ¹. ÐÐœÐ° ÑÐ°Ð±ÐŸÑÐ°ÐµÑ Ð¿ÑÐž ÐŒÐžÐœÐžÐŒÐ°Ð»ÑÐœÑÑ
+ Ð°Ð¿Ð¿Ð°ÑÐ°ÑÐœÑÑ
+ ÑÑÐµÐ±ÐŸÐ²Ð°ÐœÐžÑÑ
+, ÑÑÐŸ ÑÐžÐ¿ÐžÑÐœÐŸ ÐŽÐ»Ñ ÑÐ°Ð·Ð²ÐžÐ²Ð°ÑÑÐžÑ
+ÑÑ ÑÑÑÐ°Ðœ. Ð ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐŒÐŸÐ¶ÐœÐŸ ÐŸÐ±ÑÐ°ÑÐžÑÑÑÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð¿ÑÐŸÑÐµÐŽÑÑÑ Ð¿ÐŸÐžÑÐºÐ°, Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÑÐµÐŒ, Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐŸÐ², Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÐŸÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÐ¹, Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÑÐ¿ÐžÑÐºÐ°  Ðž Ð±ÐµÑÐ¿ÐŸÑÑÐŽÐŸÑÐœÐŸÐ³ÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÐºÐœÐžÐ¶ÐœÑÑ
+ ÐŸÐ±Ð»ÐŸÐ¶ÐµÐº. }
+
+_textcustomisationtitle_ [l=ru] {ÐÐ°ÑÑÑÐŸÐ¹ÐºÐ°}
+_textgreenstone5_ [l=ru] {ÐÑÐžÐœÑÑÐŸÑÐœ ÑÐ¿ÐµÑÐžÐ°Ð»ÑÐœÐŸ ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÐ°ÐœÑ ÑÐ°Ðº, ÑÑÐŸÐ±Ñ Ð±ÑÑÑ ÐŒÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸ ÑÐ°ÑÑÐžÑÑÐµÐŒÑÐŒÐž Ðž ÐœÐ°ÑÑÑÐ°ÐžÐ²Ð°ÐµÐŒÑÐŒÐž. ÐÐŸÐ²ÑÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ Ðž ÑÐŸÑÐŒÐ°ÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÑÑÑÑ ÐœÐ°Ð¿ÐžÑÐ°ÐœÐžÐµÐŒ "plugins/Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÐ¹ Ðº Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐµ" (ÐœÐ° ÑÐ·ÑÐºÐµ Perl). ÐÐœÐ°Ð»ÐŸÐ³ÐžÑÐœÐŸ, ÐœÐŸÐ²ÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, Ð¿ÑÐŸÑÐŒÐ°ÑÑÐžÐ²Ð°ÑÑÐžÐµ ÑÑÑÑÐºÑÑÑÑ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐŸÐ·ÐŽÐ°ÐœÑ ÐœÐ°Ð¿ÐžÑÐ°ÐœÐžÐµÐŒ "classifiers/ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ²". ÐÐœÐµÑÐœÐžÐ¹ Ð²ÐžÐŽ ÐžÐœÑÐµÑÑÐµÐ¹ÑÐ° Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ ÐŒÐŸÐ¶ÐœÐŸ ÐžÐ·ÐŒÐµÐœÐžÑÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ "ÐŒÐ°ÐºÑÐŸÑÑ", ÐœÐ°Ð¿ÐžÑÐ°ÐœÐœÑÐµ ÐœÐ° Ð¿ÑÐŸÑÑÐŸÐŒ ÐŒÐ°ÐºÑÐŸÑÐ·ÑÐºÐµ. ÐÑÐŸÑÐŸÐºÐŸÐ» Corba  Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð°Ð³ÐµÐœÑÐ°ÐŒ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ Ð² Java) ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð²ÑÐµ ÑÑÐµÐŽÑÑÐ²Ð°, ÑÐ²ÑÐ·Ð°ÐœÐœÑÐµ Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°. ÐÐ°ÐºÐŸÐœÐµÑ, ÐžÑÑ
+ÐŸÐŽÐœÐ°Ñ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ°, ÐœÐ° C++ Ðž Perl, ÑÐ²Ð»ÑÐµÑÑÑ ÐŽÐŸÑÑÑÐ¿ÐœÐŸÐ¹ ÐŽÐ»Ñ ÐŒÐŸÐŽÐžÑÐžÐºÐ°ÑÐžÐž. }
+
+_textdocumentationtitle_ [l=ru] {ÐÐŸÐºÑÐŒÐµÐœÑÐ°ÑÐžÑ}
+_textdocuments_ [l=ru] {ÐÐ±ÑÐžÑÐœÐ°Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÑÐžÑ Ð¿ÐŸ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐŒÑ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ ÐÑÐžÐœÑÑÐŸÑÐœ ÐŽÐŸÑÑÑÐ¿ÐœÐ°.}
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+_textmailinglisttitle_ [l=ru] {ÑÐ¿ÐžÑÐŸÐº Ð°ÐŽÑÐµÑÐ°ÑÐŸÐ²}
+_textmailinglist_ [l=ru] {Ð­ÑÐŸÑ ÑÐ¿ÐžÑÐŸÐº ÑÐ°ÑÑÑÐ»ÐºÐž, Ð¿ÑÐµÐŽÐœÐ°Ð·ÐœÐ°ÑÐµÐœ Ð¿ÑÐµÐ¶ÐŽÐµ Ð²ÑÐµÐ³ÐŸ ÐŽÐ»Ñ ÐŸÐ±ÑÑÐ¶ÐŽÐµÐœÐžÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐ³ÐŸ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÑ ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž ÐÑÐžÐœÑÑÐŸÑÐœ. ÐÐºÑÐžÐ²ÐœÑÐµ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ðž ÐÑÐžÐœÑÑÐŸÑÐœ ÐŒÐŸÐ³ÑÑ Ð¿ÐŸÐŽÐºÐ»ÑÑÐ°ÑÑÑÑ Ðº ÑÐ¿ÐžÑÐºÑ ÑÐ°ÑÑÑÐ»ÐºÐž Ðž Ðº ÐŸÐ±ÑÑÐ¶ÐŽÐµÐœÐžÑÐŒ. Ð§ÑÐŸÐ±Ñ Ð¿ÐŸÐŽÐ¿ÐžÑÐ°ÑÑÑÑ, ÑÐµÐ»ÐºÐœÐžÑÐµ ÐœÐ° <a href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.
+ÐÑÑÐ»Ð°ÑÑ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐµ Ð² ÑÐ¿ÐžÑÐŸÐº ÐŒÐŸÐ¶ÐœÐŸ Ð¿ÐŸ ÐŽÐ°ÐœÐœÐŸÐŒÑ Ð°ÐŽÑÐµÑÑ <a
+href="mailto:greenstone-users@list.scms.waikato.ac.nz"
+>greenstone-users@list.scms.waikato.ac.nz</a>.
+}
+
+_textbugstitle_ [l=ru] {ÐÑÐžÐ±ÐºÐž}
+_textreport_ [l=ru] {ÐÑ Ñ
+ÐŸÑÐžÐŒ Ð±ÑÑÑ ÑÐ²ÐµÑÐµÐœÑ Ð² ÑÐŸÐŒ, ÑÑÐŸ ÑÐ°Ð±ÐŸÑÐ° Ñ ÐœÐ°ÑÐžÐŒ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÑÐŒ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµÐŒ ÐœÐµ ÐŽÐŸÑÑÐ°Ð²Ð»ÑÐµÑ Ð²Ð°ÐŒ ÐœÐµÑÐŽÐŸÐ±ÑÑÐ². ÐÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ°, ÑÐŸÐŸÐ±ÑÐ°Ð¹ÑÐµ ÐœÐ°ÐŒ ÐŸ Ð²ÑÐµÑ
+ Ð²ÑÑÐ²Ð»ÐµÐœÐœÑÑ
+ Ð² Ð¿ÑÐŸÑÐµÑÑÐµ ÑÐ°Ð±ÐŸÑÑ ÐŸÑÐžÐ±ÐºÐ°Ñ
+ Ð¿ÐŸ Ð°ÐŽÑÐµÑÑ <a href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>}
+
+_textgs3title_ [l=ru] {Ð² ÑÐ°Ð±ÐŸÑÐ°Ñ
+}
+_textgs3_ [l=ru] {Ð ÐÑÐžÐœÑÑÐŸÑÐœ 3  Ð¿ÐŸÐ»ÐœÐŸÑÑÑÑ Ð¿ÐµÑÐµÑÐ°Ð±ÐŸÑÐ°Ðœ ÐŽÐžÐ·Ð°Ð¹Ðœ Ðž ÐžÐœÑÑÑÑÐŒÐµÐœÑÐ°ÑÐžÐ¹, ÐºÐŸÑÐŸÑÑÐ¹ ÑÐŸÑ
+ÑÐ°ÐœÑÐµÑ Ð²ÑÐµ Ð¿ÑÐµÐžÐŒÑÑÐµÑÑÐ²Ð° ÐÑÐžÐœÑÑÐŸÑÐœ 2 (ÐœÐ°ÑÑÐŸÑÑÐµÐ¹ Ð²ÐµÑÑÐžÐž). Ð¢Ð°Ðº ÐŸÐœ ÑÐ²Ð»ÑÐµÑÑÑ ÐŒÐœÐŸÐ³ÐŸÑÐ·ÑÑÐœÑÐŒ, ÐŒÐœÐŸÐ³ÐŸÐ¿Ð»Ð°ÑÑÐŸÑÐŒÐµÐœÐœÑÐŒ Ðž ÐŸÑÐ»ÐžÑÐ°ÐµÑÑÑ Ð²ÑÑÐŸÐºÐŸÐ¹ ÐºÐŸÐœÑÐžÐ³ÑÑÐžÑÑÐµÐŒÐŸÑÑÑÑ. ÐÐœ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÑÑÐµÐŽÑÑÐ²Ð° ÐŽÐ°ÐœÐœÐŸÐ¹ ÑÐžÑÑÐµÐŒÑ Ðž ÐŸÐ±Ð»Ð°ÐŽÐ°ÐµÑ ÐŸÐ±ÑÐ°ÑÐœÐŸÐ¹ ÑÐŸÐ²ÐŒÐµÑÑÐžÐŒÐŸÑÑÑÑ.Ð­ÑÐŸ ÐŸÐ·ÐœÐ°ÑÐ°ÐµÑ, ÑÑÐŸ ÐŸÐœ ÐŒÐŸÐ¶ÐµÑ ÑÑÑÐŸÐžÑÑ Ðž Ð²Ð²ÐŸÐŽÐžÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð±ÐµÐ· ÐžÑ
+ ÐŒÐŸÐŽÐžÑÐžÐºÐ°ÑÐžÐž. ÐÐ°Ð¿ÐžÑÐ°ÐœÐœÑÐ¹ ÐœÐ° Java, ÐŸÐœ ÑÑÑÑÐºÑÑÑÐžÑÐŸÐ²Ð°Ðœ ÐºÐ°Ðº ÑÐµÐ¿Ñ ÐœÐµÐ·Ð°Ð²ÐžÑÐžÐŒÑÑ
+ ÐŒÐŸÐŽÑÐ»ÐµÐ¹, ÐºÐŸÑÐŸÑÑÐµ Ð²Ð·Ð°ÐžÐŒÐŸÐŽÐµÐ¹ÑÑÐ²ÑÑÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ XML. Ð¢Ð°ÐºÐžÐŒ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ ÐŸÐœ Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœ Ð² ÑÐŸÑÐŒÐµ ÐŽÐžÑÑÑÐžÐ±ÑÑÐžÐ²Ð° Ðž ÐŒÐŸÐ¶ÐµÑ ÑÐ°ÑÐ¿ÑÐŸÑÑÑÐ°ÐœÑÑÑÑÑ ÑÐµÑÐµÐ· ÑÐ°Ð·Ð»ÐžÑÐœÑÐµ ÑÐµÑÐ²ÐµÑÐ°. Ð­ÑÐŸ ÐŒÐŸÐŽÑÐ»ÑÐœÐŸÐµ ÑÐµÑÐµÐœÐžÐµ ÑÐ²ÐµÐ»ÐžÑÐžÐ²Ð°ÐµÑ Ð³ÐžÐ±ÐºÐŸÑÑÑ Ðž ÑÐ°ÑÑÐžÑÑÐµÐŒÐŸÑÑÑ ÐÑÐžÐœÑÑÐŸÑÐœ. ÐÐµÑÐ²ÐŸÐœÐ°ÑÐ°Ð»ÑÐœÑÐ¹ ÐŽÐžÐ·Ð°Ð¹Ðœ ÑÐžÑÑÐµÐŒÑ ÐžÐ·Ð»ÐŸÐ¶ÐµÐœ Ð² ÐŽÐŸÐºÑÐŒÐµÐœÑÐµ "ÐÐžÐ·Ð°Ð¹Ðœ ÐÑÐžÐœÑÑÐŸÑÐœ 3: ÐÐ³ÐµÐœÑ ÐŸÑÐžÐµÐœÑÐžÑÐŸÐ²Ð°ÐœÐœÐŸÐ¹ ÐŽÐžÐœÐ°ÐŒÐžÑÐµÑÐºÐŸÐ¹ ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž" ( ÐºÐŸÑÐŸÑÑÐ¹ ÐŒÐŸÐ¶ÐœÐŸ Ð¿ÑÐŸÑÐžÑÐ°ÑÑ Ð² <a href="http://www.greenstone.org/manuals/gs3design.pdf">PDF</a>).
+}
+
+_textcreditstitle_ [l=ru] {ÐÑÐµÐŽÐžÑÑ}
+
+_textwhoswho_ [l=ru] {ÐÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐµ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐµ ÐÑÐžÐœÑÑÐŸÑÐœ - Ð¿ÑÐŸÐŽÑÐºÑ ÑÐŸÐ²ÐŒÐµÑÑÐœÐŸÐ³ÐŸ ÑÑÑÐŽÐ° ÐŒÐœÐŸÐ¶ÐµÑÑÐ²Ð° Ð»ÑÐŽÐµÐ¹. Rodger McNab Ðž Stefan Boddie Ð³Ð»Ð°Ð²ÐœÑÐµ ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÑÐžÐºÐž ÑÐžÑÑÐµÐŒÑ. ÐÐµÐŸÑÐµÐœÐžÐŒÑÐ¹ Ð²ÐºÐ»Ð°ÐŽ Ð²ÐœÐµÑÐ»Ðž David Bainbridge, George Buchanan, Hong Chen, Michael Dewsnip, Katherine Don, Elke Duncker, Carl Gutwin, Geoff Holmes, Dana McKay, John McPherson, Craig Nevill-Manning, Dynal Patel, Gordon Paynter, Bernhard Pfahringer, Todd Reed, Bill Rogers, John Thompson, Ðž Stuart Yeates. ÐÑÑÐ°Ð»ÑÐœÑÐµ ÑÐ»ÐµÐœÑ ÐÑÐŸÐµÐºÑÐ° ÐÐŸÐ²ÐŸÐ·ÐµÐ»Ð°ÐœÐŽÑÐºÐŸÐ¹ ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž  ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÐ°Ð»Ðž Ð²ÐŽÐŸÑ
+ÐœÐŸÐ²ÐµÐœÐœÑÐ¹ ÐŽÐžÐ·Ð°Ð¹Ðœ Ð²ÑÐµÐ¹ ÑÐžÑÑÐµÐŒÑ: Mark Apperley, Sally Jo Cunningham, Matt Jones, Steve Jones, Te Taka Keegan, Michel Loots, Malika Mahoui, Gary Marsden, Dave Nichols Ðž Lloyd Smith. 
+ÐÑ ÑÐ°ÐºÐ¶Ðµ Ð²ÑÑÐ°Ð¶Ð°ÐµÐŒ ÑÐ²ÐŸÑ Ð¿ÑÐžÐ·ÐœÐ°ÑÐµÐ»ÑÐœÐŸÑÑÑ Ð²ÑÐµÐŒ ÑÐµÐŒ, ÐºÑÐŸ ÑÑÑÐŽÐžÐ»ÑÑ ÐœÐ°ÐŽ ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµÐŒ Ð¿Ð°ÐºÐµÑÐŸÐ², Ð¿ÐŸÐ¿Ð°ÐŽÐ°ÑÑÐžÑ
+ Ð¿ÐŸÐŽ ÐŽÐµÐ¹ÑÑÐ²ÐžÐµ Ð»ÐžÑÐµÐœÐ·ÐžÐž  GNU, Ðž Ð²ÐºÐ»ÑÑÐµÐœÐœÑÑ
+ Ð² ÐŽÐžÑÑÑÐžÐ±ÑÑÐžÐ²: MG, GDBM, PDFTOHTML, PERL, WGET, WVWARE Ðž XLHTML. }
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "ÐŸ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐœÐŸÐŒ ÐŸÐ±ÐµÑÐ¿ÐµÑÐµÐœÐžÐž ÐÑÐžÐœÑÑÐŸÑÐœ" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=ru] {_httpimg_/ru/abgsgr.gif}
+_widthabgsgr_ [l=ru] {_pagewidth_}
+_heightabgsgr_ [l=ru] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=ru] {Ð¡Ð¿ÐžÑÐŸÐº ÑÐµÐºÑÑÐžÑ
+ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÐµÐ¹}
+_textuser_ [l=ru] {Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ
+}
+_textas_ [l=ru] {ÑÐŸÑÑÐŸÑÐœÐžÐµ ÑÑÐµÑÐœÐŸÐ¹ Ð·Ð°Ð¿ÐžÑÐž}
+_textgroups_ [l=ru] {Ð³ÑÑÐ¿Ð¿Ñ}
+_textcomment_ [l=ru] {ÐºÐŸÐŒÐŒÐµÐœÑÐ°ÑÐžÐ¹}
+_textadduser_ [l=ru] {ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ ÐœÐŸÐ²ÐŸÐ³ÐŸ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ}
+_textedituser_ [l=ru] {ÑÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ}
+_textdeleteuser_ [l=ru] {ÑÐŽÐ°Ð»ÐµÐœÐžÐµ}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=ru] {Ð ÐµÐŽÐ°ÐºÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐŸ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ðµ}
+_textadduser_ [l=ru] {ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÐŸÐ³ÐŸ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ}
+
+_textaboutusername_ [l=ru] {ÐÐ»ÐžÐœÐ° ÐžÐŒÐµÐœÐž Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ ÐŽÐŸÐ»Ð¶ÐœÐ° ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑÑ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÐŸÑ 2 ÐŽÐŸ 30 ÑÐžÐŒÐ²ÐŸÐ»ÐŸÐ². ÐÐœÐŸ ÐŒÐŸÐ¶ÐµÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÑÑ Ð±ÑÐºÐ²ÐµÐœÐœÐŸ-ÑÐžÑÑÐŸÐ²ÑÐµ ÑÐžÐŒÐ²ÐŸÐ»Ñ, Ð·ÐœÐ°ÐºÐž '.', Ðž '_'. }
+
+_textaboutpassword_ [l=ru] {ÐÐ°ÑÐŸÐ»Ñ ÐŒÐŸÐ¶ÐµÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÑÑ ÐŸÑ 3 ÐŽÐŸ 8 ÑÐžÐŒÐ²ÐŸÐ»ÐŸÐ². Ð ÐºÐ°ÑÐµÑÑÐ²Ðµ Ð¿Ð°ÑÐŸÐ»Ñ ÐŒÐŸÐ³ÑÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ ÐŸÐ±ÑÑÐœÑÐµ Ð¿ÐµÑÐ°ÑÐ°ÐµÐŒÑÐµ ASCII ÑÐžÐŒÐ²ÐŸÐ»Ñ. }
+
+_textoldpass_ [l=ru] {ÐÑÐ»Ðž ÐŽÐ°ÐœÐœÐŸÐµ Ð¿ÐŸÐ»Ðµ Ð¿ÑÑÑÐŸÐµ, ÑÐŸ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÐµÑÑÑ ÑÑÐ°ÑÑÐ¹ Ð¿Ð°ÑÐŸÐ»Ñ.}
+_textenabled_ [l=ru] {ÑÐ°Ð·ÑÐµÑÐµÐœÐŸ}
+_textdisabled_ [l=ru] {Ð·Ð°Ð¿ÑÐµÑÐµÐœÐŸ}
+
+_textaboutgroups_ [l=ru] {ÐÑÑÐ¿Ð¿Ñ - ÑÐ¿ÐžÑÐŸÐº ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐœÑÐ¹ Ð·Ð°Ð¿ÑÑÑÐŒÐž, Ð¿ÑÐŸÐ±ÐµÐ»Ñ Ð¿ÐŸÑÐ»Ðµ Ð·Ð°Ð¿ÑÑÑÑ
+ ÐœÐµ ÑÑÐ°Ð²ÑÑÑÑ! }
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=ru] {Ð£ÐŽÐ°Ð»ÐžÑÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ}
+_textremwarn_ [l=ru] {ÐÑ  ÐŽÐµÐ¹ÑÑÐ²ÐžÑÐµÐ»ÑÐœÐŸ Ñ
+ÐŸÑÐžÑÐµ ÐŸÐºÐŸÐœÑÐ°ÑÐµÐ»ÑÐœÐŸ ÑÐŽÐ°Ð»ÐžÑÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ _cgiargumun_?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=ru] {ÐÐ·ÐŒÐµÐœÐžÑÑ Ð¿Ð°ÑÐŸÐ»Ñ}
+_textoldpw_ [l=ru] {Ð¡ÑÐ°ÑÑÐ¹ Ð¿Ð°ÑÐŸÐ»Ñ}
+_textnewpw_ [l=ru] {ÐÐŸÐ²ÑÐ¹ Ð¿Ð°ÑÐŸÐ»Ñ}
+_textretype_ [l=ru] {ÐÐ²ÐµÐŽÐžÑÐµ Ð¿ÐŸÐ²ÑÐŸÑÐœÐŸ ÐœÐŸÐ²ÑÐ¹ Ð¿Ð°ÑÐŸÐ»Ñ}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=ru] {ÐÐ°Ñ Ð¿Ð°ÑÐŸÐ»Ñ Ð±ÑÐ» ÑÑÐ¿ÐµÑÐœÐŸ ÐžÐ·ÐŒÐµÐœÐµÐœ.}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=ru] {ÐÐµÐ²ÐµÑÐœÐŸÐµ ÐžÐŒÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ.}
+_textinvalidpassword_ [l=ru] {ÐÐµÐ²ÐµÑÐœÑÐ¹ Ð¿Ð°ÑÐŸÐ»Ñ.}
+_textemptypassword_ [l=ru] {ÐÐŸÐ¶Ð°Ð»ÑÐ¹ÑÑÐ°, Ð²Ð²ÐµÐŽÐžÑÐµ ÐœÐ°ÑÐ°Ð»ÑÐœÑÐ¹ Ð¿Ð°ÑÐŸÐ»Ñ ÐŽÐ»Ñ ÐŽÐ°ÐœÐœÐŸÐ³ÐŸ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ.}
+_textuserexists_ [l=ru] {ÐÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ Ñ ÑÐ°ÐºÐžÐŒ ÐžÐŒÐµÐœÐµÐŒ ÑÐ¶Ðµ ÑÑÑÐµÑÑÐ²ÑÐµÑ, ÐžÐ·ÐŒÐµÐœÐžÑÐµ ÐžÐŒÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ.}
+
+_textusernameempty_ [l=ru] {ÐÐ²ÐµÐŽÐžÑÐµ ÑÐ²ÐŸÐ¹ ÐœÐŸÐ²ÑÐ¹ Ð¿Ð°ÑÐŸÐ»Ñ Ðž Ð¿ÐŸÐŽÑÐ²ÐµÑÐŽÐžÑÐµ ÐµÐ³ÐŸ ÐµÑÐµ ÑÐ°Ð·.}
+_textpasswordempty_ [l=ru] {ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð²Ð²ÐµÑÑÐž ÐÐ°Ñ ÑÑÐ°ÑÑÐ¹ Ð¿Ð°ÑÐŸÐ»Ñ.
+}
+_textnewpass1empty_ [l=ru] {ÐÐ²ÐµÐŽÐžÑÐµ ÐÐ°Ñ ÐœÐŸÐ²ÑÐ¹ Ð¿Ð°ÑÐŸÐ»Ñ Ðž Ð·Ð°ÑÐµÐŒ Ð¿ÐŸÐ²ÑÐŸÑÐžÑÐµ Ð²Ð²ÐŸÐŽ.}
+_textnewpassmismatch_ [l=ru] {ÐÐ²ÐµÐŽÐµÐœÑ ÑÐ°Ð·ÐœÑÐµ Ð²ÐµÑÑÐžÐž Ð²Ð°ÑÐµÐ³ÐŸ ÐœÐŸÐ²ÐŸÐ³ÐŸ Ð¿Ð°ÑÐŸÐ»Ñ.}
+_textnewinvalidpassword_ [l=ru] {ÐÐ°ÑÐµ ÐžÐŒÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ ÐžÐ»Ðž Ð¿Ð°ÑÐŸÐ»Ñ Ð±ÑÐ»Ðž Ð²Ð²ÐµÐŽÐµÐœÑ ÐœÐµÐ¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸ.}
+_textfailed_ [l=ru] {ÐÐžÐ±ÐŸ ÐÐ°ÑÐµ ÐžÐŒÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ ÐžÐ»Ðž Ð¿Ð°ÑÐŸÐ»Ñ Ð±ÑÐ»Ðž ÐœÐµÐºÐŸÑÑÐµÐºÑÐœÑ}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=ru] {ÐÐµÑÑÐžÑ ÐÑÐžÐœÑÑÐŸÑÐœ}
+_textframebrowser_ [l=ru] {ÐÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÑÐŸÐŽÐµÑÐ¶ÐžÐŒÐŸÐ³ÐŸ, ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ Ð² Ð²Ð°ÑÐµÐŒ Ð±ÑÐŸÑÐ·ÐµÑÐµ ÑÐ°Ð·ÑÐµÑÐµÐœÐžÐµ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÐž ÑÑÐµÐ¹ÐŒÐŸÐ². }
+_textusermanage_ [l=ru] {Ð£Ð¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÑÐŒÐž}
+_textlistusers_ [l=ru] {Ð¡Ð¿ÐžÑÐŸÐº Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÐµÐ¹}
+_textaddusers_ [l=ru] {ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐœÐŸÐ²ÐŸÐ³ÐŸ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ}
+_textchangepasswd_ [l=ru] {ÐÐ·ÐŒÐµÐœÐžÑÑ Ð¿Ð°ÑÐŸÐ»Ñ}
+_textinfo_ [l=ru] {Ð¢ÐµÑ
+ÐœÐžÑÐµÑÐºÐ°Ñ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ}
+_textgeneral_ [l=ru] {ÐÐ±ÑÐžÐµ}
+_textarguments_ [l=ru] {Ð°ÑÐ³ÑÐŒÐµÐœÑÑ}
+_textactions_ [l=ru] {ÐŽÐµÐ¹ÑÑÐ²ÐžÑ}
+_textbrowsers_ [l=ru] {Ð±ÑÐŸÑÐ·ÐµÑÑ}
+_textprotocols_ [l=ru] {Ð¿ÑÐŸÑÐŸÐºÐŸÐ»Ñ}
+_textconfigfiles_ [l=ru] {Ð€Ð°Ð¹Ð» ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐž}
+_textlogs_ [l=ru] {Ð ÐµÐ³ÐžÑÑÑÐ°ÑÐžÑ}
+_textusagelog_ [l=ru] {Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»ÑÑÐºÐ°Ñ ÑÐµÐ³ÐžÑÑÑÐ°ÑÐžÑ}
+_textinitlog_ [l=ru] {ÐÐ°ÑÐ°Ð»ÐŸ ÑÐµÐ³ÐžÑÑÑÐ°ÑÐžÐž}
+_texterrorlog_ [l=ru] {ÐŸÑÐžÐ±ÐºÐ° ÑÐµÐ³ÐžÑÑÑÐ°ÑÐžÐž}
+_textadminhome_ [l=ru] {ÐÐŸÐŒÐ°ÑÐœÑÑ ÑÑÑÐ°ÐœÐžÑÐ° Ð°ÐŽÐŒÐžÐœÐžÑÑÑÐ°ÑÐŸÑÐ°}
+_textreturnhome_ [l=ru] {ÐÐŸÐŒÐ°ÑÐœÑÑ ÑÑÑÐ°ÐœÐžÑÐ° ÐÑÐžÐœÑÑÐŸÑÐœ}
+_titlewelcome_ [l=ru] {ÐÐŽÐŒÐžÐœÐžÑÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ }
+_textmaas_ [l=ru] {Ð¡Ð»ÑÐ¶Ð±Ð° Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÐž Ðž Ð°ÐŽÐŒÐžÐœÐžÑÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð²ÐºÐ»ÑÑÐ°ÐµÑ:}
+_textvol_ [l=ru] {Ð¿ÑÐŸÑÐŒÐŸÑÑ Ð»ÐŸÐ³ÐŸÐ² Ð² ÑÐµÐ¶ÐžÐŒÐµ ÐŸÐœ-Ð»Ð°Ð¹Ðœ}
+_textcmuc_ [l=ru] {ÑÐŸÐ·ÐŽÐ°ÐœÐžÐµ, Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÐ° Ðž ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+_textati_ [l=ru] {ÐÐŸÑÑÑÐ¿ Ðº ÑÐµÑ
+ÐœÐžÑÐµÑÐºÐŸÐ¹ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž, ÑÐžÐ¿Ð° Ð¿Ð°ÑÐ°ÐŒÐµÑÑÐŸÐ² CGI ÑÐºÑÐžÐ¿ÑÐŸÐ²}
+
+_texttsaa_ [l=ru] {Ð ÑÑÐžÐŒ ÑÑÐ»ÑÐ³Ð°ÐŒ ÐŸÐ±ÑÐ°ÑÐ°ÑÑÑÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÐŸÐœÐœÐŸÐµ ÐŒÐµÐœÑ ÐœÐ° Ð»ÐµÐ²ÐŸÐ¹ ÑÑÐŸÑÐŸÐœÐµ ÑÑÑÐ°ÐœÐžÑÑ. }
+
+_textcolstat_ [l=ru] {Ð¡ÑÐ°ÑÑÑ ÐÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+
+_textcwoa_ [l=ru] {ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð¿ÐŸÑÐ²ÐžÑÑÑ Ðž Ð±ÑÐŽÐµÑ "Ð·Ð°Ð¿ÑÑÐµÐœÐ°", ÑÐŸÐ»ÑÐºÐŸ Ð¿ÑÐž ÑÑÐ»ÐŸÐ²ÐžÐž, ÐµÑÐ»Ðž Ð¿ÑÐžÑÑÑÑÑÐ²ÑÐµÑ ÐµÐµ ÑÐ°Ð¹Ð» build.cfg, ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ Ð¿ÑÐŸÑÐžÑÐ°Ðœ ÑÐžÑÑÐµÐŒÐŸÐ¹, ÑÐŸÐŽÐµÑÐ¶Ð°Ñ ÐŽÐŸÐ¿ÑÑÑÐžÐŒÐŸÐµ Ð¿ÐŸÐ»Ðµ  builddate ÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµÐŒ Ð±ÐŸÐ»ÑÑÐµ ÐœÑÐ»Ñ, Ðž ÐœÐ°Ñ
+ÐŸÐŽÑÑÑÑ Ð² Ð¿Ð°Ð¿ÐºÐµ index Ð²Ð°ÑÐµÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž (ÐÐ Ð² Ð¿Ð°Ð¿ÐºÐµ building). }
+
+_textcafi_ [l=ru] {ÐÐ°Ð¶ÐŒÐžÑÐµ <i>ÐÐ±Ð±ÑÐµÐ².</i> ÐŽÐ»Ñ Ð¿ÐŸÐ»ÑÑÐµÐœÐžÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐž ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+_textcctv_ [l=ru] {ÐÐ°Ð¶ÐŒÐžÑÐµ <i>ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ</i> ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+_textsubc_ [l=ru] {ÐÐŸÐŽÑÐ²ÐµÑÐŽÐžÑÑ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ}
+_texteom_ [l=ru] {ÐÑÐžÐ±ÐºÐ° ÐŸÑÐºÑÑÑÐžÑ main.cfg}
+_textftum_ [l=ru] {Ð¡Ð±ÐŸÐ¹ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÑ main.cfg}
+_textmus_ [l=ru] {Ð£ÑÐ¿ÐµÑÐœÐŸÐµ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ main.cfg}
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=ru] {Ð ÐµÐ·ÑÐŒÐµ Ð¿ÑÐŸÑÐµÑÑÐ° ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž _collectionname_ }
+_textflog_ [l=ru] {Ð€Ð°Ð¹Ð» ÑÐµÐ³ÐžÑÑÑÐ°ÑÐžÐž ÑÐ±ÐŸÐµÐ² ÐŽÐ»Ñ _collectionname_ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=ru] {ÐÑÐžÐŒÐµÐœÐžÐŒÐŸÑÑÑ ÐÑÐžÐœÑÑÐŸÑÐœ}
+
+_textwhy_ [l=ru] {<p> ÐÑÐ¿ÑÐ°Ð²ÐºÐ° ÑÑÐŸÐ³ÐŸ ÑÐŸÐŸÐ±ÑÐµÐœÐžÑ - ÑÐ¿ÐŸÑÐŸÐ± ÑÐºÐ°Ð·Ð°ÑÑ, ÑÑÐŸ ÐÑ ÐœÐ°ÑÐ»Ðž Ð²ÐµÐ±-ÑÑÑÐ°ÐœÐžÑÑ, ÐºÐŸÑÐŸÑÑÑ Ð±ÑÐ»ÐŸ ÑÑÑÐŽÐœÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ.}
+_textextraforform_ [l=ru] {ÐÑ ÐœÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð·Ð°Ð¿ÐŸÐ»ÐœÑÑÑ ÑÑÑ ÑÐŸÑÐŒÑ - Ð»ÑÐ±Ð°Ñ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ Ð¿ÐŸÐŒÐŸÐ¶ÐµÑ.}
+_textprivacybasic_ [l=ru] {<p> Ð­ÑÐŸ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐµ Ð±ÑÐŽÐµÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ Ð²ÐµÐ±-ÑÑÑÐ°ÐœÐžÑÐµ ÐÑÐžÐœÑÑÐŸÑÐœ, ÐºÐŸÑÐŸÑÑÑ ÐÑ ÑÐ°ÑÑÐŒÐ°ÑÑÐžÐ²Ð°Ð»Ðž, Ðž ÑÐµÑ
+ÐœÐŸÐ»ÐŸÐ³ÐžÐž, ÐºÐŸÑÐŸÑÑÑ ÐÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°Ð»Ðž ÐŽÐ»Ñ ÐµÐµ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° (ÑÐ°ÐºÐ¶Ðµ Ð»ÑÐ±Ð°Ñ ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐ°Ñ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ, ÐºÐŸÑÐŸÑÑÑ ÐÑ Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÑÐµÑÐµ).}
+_textstillsend_ [l=ru] {ÐÑ Ð²ÑÐµ ÐµÑÐµ Ñ
+ÐŸÑÐµÐ»Ðž Ð±Ñ Ð¿ÐŸÑÐ»Ð°ÑÑ ÑÑÐŸ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐµ?}
+
+_texterror_ [l=ru] {ÐÑÐžÐ±ÐºÐ°}
+_textyes_ [l=ru] {ÐÐ°}
+_textno_ [l=ru] {ÐÐµÑ}
+_textclosewindow_ [l=ru] {ÐÐ°ÐºÑÑÑÑ ÐŸÐºÐœÐŸ}
+_textabout_ [l=ru] {Ð}
+_textprivacy_ [l=ru] {Ð¡ÐµÐºÑÐµÑÐœÐŸ}
+_textsend_ [l=ru] {ÐÑÐ¿ÑÐ°Ð²ÐžÑÑ}
+_textdontsend_ [l=ru] {ÐÐµ Ð¿ÐŸÑÑÐ»Ð°ÑÑ}
+_textoptionally_ [l=ru] {ÐÑÐŸÐžÐ·Ð²ÐŸÐ»ÑÐœÐŸ}
+
+_textunderdev_ [l=ru] {ÐÑÐµÐŽÐ²Ð°ÑÐžÑÐµÐ»ÑÐœÑÐ¹ Ð¿ÑÐŸÑÐŒÐŸÑÑ ÐŽÐµÑÐ°Ð»ÐµÐ¹ Ð±ÑÐŽÐµÑ ÐŽÐŸÑÑÑÐ¿ÐµÐœ Ð² Ð·Ð°ÐºÐ»ÑÑÐžÑÐµÐ»ÑÐœÐŸÐ¹ Ð²ÐµÑÑÐžÐž.}
+
+_textviewdetails_ [l=ru] {ÐÐµÑÐ°Ð»Ðž ÑÐŸÐŸÐ±ÑÐµÐœÐžÑ ÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµ.}
+_textmoredetails_ [l=ru] {ÐÐŸÐ»ÑÑÐµ ÐŽÐµÑÐ°Ð»ÐµÐ¹}
+_texttrackreport_ [l=ru] {ÐÑÑÐ»ÐµÐŽÐžÑÑ ÑÑÐŸ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐµ}
+_textcharacterise_ [l=ru] {ÐÐ°ÐºÐŸÐ³ÐŸ Ð¿Ð»Ð°ÐœÐ° ÑÑÐ° Ð¿ÑÐŸÐ±Ð»ÐµÐŒÐ°}
+_textseverity_ [l=ru] {ÐÐ°ÑÐºÐŸÐ»ÑÐºÐŸ Ð¿Ð»ÐŸÑ
+Ð° ÑÑÐ° Ð¿ÑÐŸÐ±Ð»ÐµÐŒÐ°}
+ 
+_textbadrender_ [l=ru] {Ð¡ÑÑÐ°ÐœÐžÑÐ° Ð²ÑÐ³Ð»ÑÐŽÐžÑ ÑÑÑÐ°ÐœÐœÐŸ}
+_textcontenterror_ [l=ru] {ÐÑÐžÐ±ÐºÐ° ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ}
+_textstrangebehaviour_ [l=ru] {Ð¡ÑÑÐ°ÐœÐœÐŸÐµ Ð¿ÐŸÐ²ÐµÐŽÐµÐœÐžÐµ}
+_textunexpected_ [l=ru] {Ð¡Ð»ÑÑÐžÐ»ÐŸÑÑ ÑÑÐŸ-ÑÐŸ ÐœÐµÐŸÐ¶ÐžÐŽÐ°ÐœÐœÐŸÐµ.}
+_textfunctionality_ [l=ru] {Ð¢ÑÑÐŽÐœÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ}
+_textother_ [l=ru] {ÐÑÑÐ³ÐŸÐµ}
+
+_textcritical_ [l=ru] {ÐÑÐžÑÐžÑÐœÐŸ}
+_textmajor_ [l=ru] {Ð¡ÐµÑÑÐµÐ·ÐœÐŸ}
+_textmedium_ [l=ru] {Ð¡ÑÐµÐŽÐœÐµ}
+_textminor_ [l=ru] {ÐÐµÐœÑÑÐµ}
+_texttrivial_ [l=ru] {Ð¢ÑÐžÐ²ÐžÐ°Ð»ÑÐœÐŸ}
+
+_textwhatdoing_ [l=ru] {Ð§ÑÐŸ ÐÑ Ð¿ÑÐŸÐ±ÐŸÐ²Ð°Ð»Ðž ÑÐŽÐµÐ»Ð°ÑÑ?}
+_textwhatexpected_ [l=ru] {Ð§ÐµÐ³ÐŸ Ð²Ñ ÐŸÐ¶ÐžÐŽÐ°Ð»Ðž?}
+_textwhathappened_ [l=ru] {Ð§ÑÐŸ ÑÐ»ÑÑÐžÐ»ÐŸÑÑ ÑÐ°ÐºÑÐžÑÐµÑÐºÐž?}
+
+_cannotfindcgierror_ [l=ru] {<h2>Ð ÑÐŸÐ¶Ð°Ð»ÐµÐœÐžÑ</h2>ÐœÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐœÐ°Ð¹ÑÐž ÑÐµÑÐ²ÐµÑÐœÑÐµ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ ÐŽÐ»Ñ ÐºÐœÐŸÐ¿ÐºÐž "Ñ Ð±Ñ Ñ
+ÐŸÑÐµÐ» ÑÐŸÐŸÐ±ÑÐžÑÑ" }
+
+_textusabbanner_ [l=ru] {ÐÐ°ÐœÐœÐµÑ koru-ÑÑÐžÐ»Ñ ÐÑÐžÐœÑÑÐŸÑÐœ}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+_textgli_ [l=ru] {ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ}
+_textglihelp_ [l=ru] {ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐÑÐžÐœÑÑÐŸÑÐœ (GLI) ÐŽÐ°ÑÑ ÐÐ°ÐŒ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑ Ð¿ÐŸÐ»ÑÑÐžÑÑ ÐŽÐŸÑÑÑÐ¿ Ðº ÑÑÐœÐºÑÐžÐŸÐœÐ°Ð»ÑÐœÑÐŒ
+Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑÐŒ ÐÑÐžÐœÑÑÐŸÑÐœ, ÑÐŽÐŸÐ±ÐœÐŸÐŒÑ Ð² ÑÐ°Ð±ÐŸÑÐµ ÐžÐœÑÐµÑÑÐµÐ¹ÑÑ - ÑÐºÐ°Ð¶ÐžÑÐµ Ðž ÑÐµÐ»ÐºÐœÐžÑÐµ. ÐÐœ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐÐ°ÐŒ ÑÐŸÐ±ÐžÑÐ°ÑÑ Ð¿ÐŸÐŽÐ±ÐŸÑÐºÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐžÐ»Ðž Ð·Ð°ÐŽÐ°Ð²Ð°ÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ðž Ð²ÑÑÑÐ°ÐžÐ²Ð°ÑÑ ÐžÑ
+ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐÑÐžÐœÑÑÐŸÑÐœ.
+
+ÐÐ±ÑÐ°ÑÐžÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ, ÑÑÐŸ GLI ÑÐ²ÑÐ·Ð°ÐœÐ° Ñ ÐÑÐžÐœÑÑÐŸÑÐœ. ÐÑÐµÐŽÐ¿ÐŸÐ»Ð°Ð³Ð°ÐµÑÑÑ, ÑÑÐŸ ÐŸÐœÐ° ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐ° Ð² Ð¿ÐŸÐŽÐŽÐžÑÐµÐºÑÐŸÑÐžÐž Ð¿ÑÐž ÐžÐœÑÑÐ°Ð»Ð»ÑÑÐžÐž ÐÑÐžÐœÑÑÐŸÑÐœ. ÐÑÐ»Ðž ÐÑ Ð·Ð°Ð³ÑÑÐ·ÐžÐ»Ðž ÐŸÐŽÐžÐœ ÐžÐ· ÐŽÐžÑÑÑÐžÐ±ÑÑÐžÐ²ÐŸÐ² ÐÑÐžÐœÑÑÐŸÑÐœ ÐžÐ»Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐžÐ»Ðž ÐµÐ³ÐŸ Ñ CD-ROM, ÑÐŸ ÑÑÐŸ Ð±ÑÐŽÐµÑ ÐžÐŒÐµÑÑ ÐŒÐµÑÑÐŸ.
+
+
+<h4>ÐÐ°Ð¿ÑÑÐº GLI Ð¿ÐŸÐŽ Windows</h4>
+
+ÐÐŸÐŽ ÐÐžÐœÐŽÐŸÑÐ·, ÐÐ°Ð¿ÑÑÑÐžÑÐµ ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ, Ð²ÑÐ±ÐµÑÐžÑÐµ ÐŠÐžÑÑÐŸÐ²Ð°Ñ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐ° ÐÑÐžÐœÑÑÐŸÑÐœ ÐžÐ· Ð¿ÐŸÐŽÐŒÐµÐœÑ ÐÑÐŸÐ³ÑÐ°ÐŒÐŒÑ ÐŒÐµÐœÑ Ð¡ÑÐ°ÑÑ Ðž Ð² ÐœÐµÐŒ - ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ.     
+ 
+<h4>ÐÐ°Ð¿ÑÑÐº GLI Ð¿ÐŸÐŽ Unix</h4>
+
+Ð§ÑÐŸÐ±Ñ Ð·Ð°Ð¿ÑÑÑÐžÑÑ GLI Ð¿ÐŸÐŽ Unix, ÐŸÑÐºÑÐŸÐ¹ÑÐµ ÐŽÐžÑÐµÐºÑÐŸÑÐžÑ gli Ð² Ð²Ð°ÑÐµÐŒ
+ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐœÐŸÐŒ ÐÑÐžÐœÑÑÐŸÑÐœ, Ð·Ð°ÑÐµÐŒ Ð·Ð°Ð¿ÑÑÑÐžÑÐµ ÑÐºÑÐžÐ¿Ñ gli.sh.
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "ÐÐžÐ±Ð»ÐžÐŸÑÐµÑÐœÑÐ¹ ÐžÐœÑÐµÑÑÐµÐ¹Ñ ÐÑÐžÐœÑÑÐŸÑÐœ" ## green_bar_left_aligned ## gligr ##
+_httpicongligr_ [l=ru] {_httpimg_/ru/gligr.gif}
+_widthgligr_ [l=ru] {_pagewidth_}
+_heightgligr_ [l=ru] {17}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/serbian.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/serbian.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/serbian.dm	(revision 10506)
@@ -0,0 +1,1348 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Serbian (Latin version) Language text and icon macros 
+# Many thanks to Tamara Butigan (translated early 2004)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=sr] {PeriodiÄne publikacije}
+_textsource_ [l=sr] {izvor:}
+_textdate_ [l=sr] {datum izdavanja:}
+_textnumpages_ [l=sr] {broj strana:}
+
+_textsignin_ [l=sr] {prijavljivanje}
+
+_textdefaultcontent_ [l=sr] {TraÅŸena stranica ne moÅŸe biti pronaÄena.
+Molimo da koristite dugme za povratak na prethodnu stranicu u vaÅ¡em web ÄitaÄu ili
+ dugme "home" za povratak u Greenstone digitalnu biblioteku.}
+
+_textdefaulttitle_ [l=sr] {GSDL greÅ¡ka}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=sr] {Ova kolekcija sadrÅŸi _about:numdocs_ dokumenata.
+Poslednji put je aÅŸurirana pre _about:builddate_
+dana.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=sr] {<p>Ova kolekcija sadrÅŸi _numdocs_ _If_("_numdocs_" eq
+"1",dokument,dokumenata), ukupno _numbytes_.
+<p><a href="_httppagex_(bsummary)">Kliknite ovde</a> da bi videli kratak opis kreiranja ove kolekcije. 
+}
+
+_textimagecollection_ [l=sr] {}
+_textimageabout_ [l=sr] {O stranici}
+_textimagehome_ [l=sr] {Pristupna stranica}
+_textimagehelp_ [l=sr] {Stranica za pomoÄ}
+_textimagepref_ [l=sr] {Stranica za podeÅ¡avanja}
+_textimagegreenstone_ [l=sr] {Softver za digitalne biblioteke Greenstone}
+_textimageusab_ [l=sr] {Å ta vam je bilo teÅ¡ko za koriÅ¡Äenje?}
+
+_textimagesearch_ [l=sr] {PretraÅŸivanje specifiÄnih termina}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=sr] {Prelistavanje abecedne (azbuÄne) liste naslova}
+_textimageCreator_ [l=sr] {Prelistavanje abecedne (azbuÄne) liste autora}
+_textimageSubject_ [l=sr] {Prelistavanje predmetnih kategorija}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=sr] {Prelistavanje po datumima}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=sr] {Prelistavanje originalnih imena datoteka}
+_textimageLanguage_ [l=sr] {Prelistavanje prema jeziku}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=sr] {Prelistavanje po organizacijama}
+_textimageKeyword_ [l=sr] {Prelistavanje po kljuÄnim reÄima}
+_textimageHowto_ [l=sr] {Prelistavanje kategorija iz "kako da"}
+_textimageList_ [l=sr] {Prelistavanje liste dokumenata}
+_textimageSeries_ [l=sr] {Prelistavanje po izdanjima}
+_textimageTo_ [l=sr] {Prelistavanje po polju "Kome"}
+_textimageFrom_ [l=sr] {Prelistavanje po polju "Od koga"}
+_textimageTopic_ [l=sr] {Prelistavanje izdanja sa specijalnim temama}
+_textimageBrowse_ [l=sr] {Prelistavanje}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=sr] {Prelistavanje abecedne (azbuÄne) liste imena ljudi}
+_textimageAcronym_ [l=sr] {Prelistavanje akronima}
+_textimagePhrase_ [l=sr] {Prelistavanje fraza}
+_textimageArtist_ [l=sr] {Prelistavanje imena umetnika}
+_textimageVolume_ [l=sr] {Prelistavanje po sveskama
+}
+# -- Missing translation: _textimageCountries_
+_textimageCaptions_ [l=sr] {Prelistavanje natpisa ispod slika}
+
+
+_texticontabsearchgreen_ [l=sr] {PretraÅŸivanje}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=sr] {Naslovi A-Åœ/A-Ðš}
+_texticontabCreatorgreen_ [l=sr] {Autori A-Åœ/Ð-Ðš}
+_texticontabSubjectgreen_ [l=sr] {Oblasti}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=sr] {Datumi}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=sr] {Imena datoteka}
+_texticontabLanguagegreen_ [l=sr] {Jezik}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=sr] {Organizacija}
+_texticontabKeywordgreen_ [l=sr] {KljuÄne reÄi}
+_texticontabhowgreen_ [l=sr] {Kako da}
+_texticontabseriesgreen_ [l=sr] {Edicije}
+_texticontablistgreen_ [l=sr] {ListÐ°}
+_texticontabtogreen_ [l=sr] {Kome}
+_texticontabfromgreen_ [l=sr] {Od koga}
+_texticontabtopicgreen_ [l=sr] {Teme}
+_texticontabbrwsegreen_ [l=sr] {Prelistavanje}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=sr] {Prelistavanje}
+_texticontabPeoplegreen_ [l=sr] {LiÄnosti A-Åœ/A-Ðš}
+_texticontabAcronymgreen_ [l=sr] {Akronimi}
+_texticontabPhrasegreen_ [l=sr] {ReÄenice}
+_texticontabArtistgreen_ [l=sr] {Umetnici}
+_texticontabVolumegreen_ [l=sr] {Sveske  
+}
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=sr] {Prikazivanje dokumenta}
+_texticonclosedbook_ [l=sr] {otvaranje dokumenta i prikazivanje njegovog sadrÅŸaja}
+_texticonnext_ [l=sr] {na sledeÄi odeljak}
+_texticonprev_ [l=sr] {na prethodni odeljak}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=sr] {Prikazivanje dokumenta u MIDI formatu}
+_texticonmsword_ [l=sr] {Prikazivanje dokumenta u Word-u}
+_texticonmp3_ [l=sr] {Prikazivanje dokumenta u MP3 formatu}
+_texticonpdf_ [l=sr] {Prikazivanje dokumenta u PDF formatu}
+_texticonps_ [l=sr] {Prikazivanje dokumenta u PostScript formatu}
+_texticonppt_ [l=sr] {Prikazivanje dokumenta u PowerPoint-u}
+_texticonrtf_ [l=sr] {Prikazivanje dokumenta u RTF formatu}
+_texticonxls_ [l=sr] {Prikazivanje dokumenta u Excel-u}
+
+_page_ [l=sr] {stranica}
+_pages_ [l=sr] {stranice}
+_of_ [l=sr] {od}
+_vol_ [l=sr] {Sv.}
+_num_ [l=sr] {br.}
+
+_textmonth00_ [l=sr] {}
+_textmonth01_ [l=sr] {januar}
+_textmonth02_ [l=sr] {februar}
+_textmonth03_ [l=sr] {mart}
+_textmonth04_ [l=sr] {april}
+_textmonth05_ [l=sr] {maj}
+_textmonth06_ [l=sr] {jun}
+_textmonth07_ [l=sr] {jul}
+_textmonth08_ [l=sr] {avgust}
+_textmonth09_ [l=sr] {septembar}
+_textmonth10_ [l=sr] {oktobar}
+_textmonth11_ [l=sr] {novembar}
+_textmonth12_ [l=sr] {decembar}
+
+_textdocument_ [l=sr] {Dokument}
+_textsection_ [l=sr] {Odeljak}
+_textparagraph_ [l=sr] {Paragraf}
+
+_magazines_ [l=sr] {Äasopisi}
+
+_nzdlpagefooter_ [l=sr] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">Projekat digitalne biblioteke Novog Zelanda</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Odsek za raÄunarstvo</a>, 
+<a href="http://www.waikato.ac.nz">Univerzitet u Waikato-u</a>, 
+Novi Zeland}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "PRISTUPNA STRANICA" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=sr] {_httpimg_/sr/chomeof.gif}
+_httpiconchomeon_ [l=sr] {_httpimg_/sr/chomeon.gif}
+
+## "POMOÄ" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=sr] {_httpimg_/sr/chelpof.gif}
+_httpiconchelpon_ [l=sr] {_httpimg_/sr/chelpon.gif}
+
+## "PODEÅ AVANJA" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=sr] {_httpimg_/sr/cprefof.gif}
+_httpiconcprefon_ [l=sr] {_httpimg_/sr/cprefon.gif}
+
+## "POÅ ALJI POVRATNU INFORMACIJU" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=sr] {_httpimg_/sr/cusabof.gif}
+_httpiconcusabon_ [l=sr] {_httpimg_/sr/cusabon.gif}
+
+
+## "pretraÅŸivanje" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=sr] {_httpimg_/sr/tsrchgr.gif}
+_httpicontsrchof_ [l=sr] {_httpimg_/sr/tsrchof.gif}
+_httpicontsrchon_ [l=sr] {_httpimg_/sr/tsrchon.gif}
+_widthtsrchx_ [l=sr] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "naslovi a-ÅŸ/a-Ñ" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=sr] {_httpimg_/sr/ttitlgr.gif}
+_httpiconttitleof_ [l=sr] {_httpimg_/sr/ttitlof.gif}
+_httpiconttitleon_ [l=sr] {_httpimg_/sr/ttitlon.gif}
+_widthttitlex_ [l=sr] {87}
+
+# Not true DC, kept for legacy reasons
+## "autori a-ÅŸ/a-Ñ" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=sr] {_httpimg_/sr/tauthgr.gif}
+_httpicontcreatof_ [l=sr] {_httpimg_/sr/tauthof.gif}
+_httpicontcreaton_ [l=sr] {_httpimg_/sr/tauthon.gif}
+_widthtcreatx_ [l=sr] {110}
+
+## "oblasti" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=sr] {_httpimg_/sr/tsubjgr.gif}
+_httpicontsubjon_ [l=sr] {_httpimg_/sr/tsubjon.gif}
+_httpicontsubjof_ [l=sr] {_httpimg_/sr/tsubjof.gif}
+_widthtsubjx_ [l=sr] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "datumi" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=sr] {_httpimg_/sr/tdategr.gif}
+_httpicontdateof_ [l=sr] {_httpimg_/sr/tdateof.gif}
+_httpicontdateon_ [l=sr] {_httpimg_/sr/tdateon.gif}
+_widthtdatex_ [l=sr] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "imena datoteka" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=sr] {_httpimg_/sr/tsrcgr.gif}
+_httpicontsrcof_ [l=sr] {_httpimg_/sr/tsrcof.gif}
+_httpicontsrcon_ [l=sr] {_httpimg_/sr/tsrcon.gif}
+_widthtsrcx_ [l=sr] {87}
+
+## "jezik" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=sr] {_httpimg_/sr/tlanggr.gif}
+_httpicontlangon_ [l=sr] {_httpimg_/sr/tlangon.gif}
+_httpicontlangof_ [l=sr] {_httpimg_/sr/tlangof.gif}
+_widthtlangx_ [l=sr] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "edicije" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=sr] {_httpimg_/sr/tsergr.gif}
+_httpicontserof_ [l=sr] {_httpimg_/sr/tserof.gif}
+_httpicontseron_ [l=sr] {_httpimg_/sr/tseron.gif}
+_widthtserx_ [l=sr] {87}
+
+## "kome" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=sr] {_httpimg_/sr/ttogr.gif}
+_httpiconttoon_ [l=sr] {_httpimg_/sr/ttoon.gif}
+_httpiconttoof_ [l=sr] {_httpimg_/sr/ttoof.gif}
+_widthttox_ [l=sr] {87}
+
+## "od koga" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=sr] {_httpimg_/sr/tfromgr.gif}
+_httpicontfromon_ [l=sr] {_httpimg_/sr/tfromon.gif}
+_httpicontfromof_ [l=sr] {_httpimg_/sr/tfromof.gif}
+_widthtfromx_ [l=sr] {87}
+
+## "organizacije" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=sr] {_httpimg_/sr/torggr.gif}
+_httpicontorgon_ [l=sr] {_httpimg_/sr/torgon.gif}
+_httpicontorgof_ [l=sr] {_httpimg_/sr/torgof.gif}
+_widthtorgx_ [l=sr] {114}
+
+## "kako da" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=sr] {_httpimg_/sr/thowgr.gif}
+_httpiconthowon_ [l=sr] {_httpimg_/sr/thowon.gif}
+_httpiconthowof_ [l=sr] {_httpimg_/sr/thowof.gif}
+_widththowx_ [l=sr] {87}
+
+## "tema" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=sr] {_httpimg_/sr/ttopicgr.gif}
+_httpiconttopicon_ [l=sr] {_httpimg_/sr/ttopicon.gif}
+_httpiconttopicof_ [l=sr] {_httpimg_/sr/ttopicof.gif}
+_widthttopicx_ [l=sr] {87}
+
+## "prelistavanje" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=sr] {_httpimg_/sr/tbrwsegr.gif}
+_httpicontbrwseon_ [l=sr] {_httpimg_/sr/tbrwseon.gif}
+_httpicontbrwseof_ [l=sr] {_httpimg_/sr/tbrwseof.gif}
+_widthtbrwsex_ [l=sr] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "ljudi" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=sr] {_httpimg_/sr/tpeopgr.gif}
+_httpicontpeopof_ [l=sr] {_httpimg_/sr/tpeopof.gif}
+_httpicontpeopon_ [l=sr] {_httpimg_/sr/tpeopon.gif}
+_widthtpeopx_ [l=sr] {97}
+
+## "akronim" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=sr] {_httpimg_/sr/tacrogr.gif}
+_httpicontacroof_ [l=sr] {_httpimg_/sr/tacroof.gif}
+_httpicontacroon_ [l=sr] {_httpimg_/sr/tacroon.gif}
+_widthtacrox_ [l=sr] {87}
+
+## "fraze" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=sr] {_httpimg_/sr/tphrsegr.gif}
+_httpicontphrseof_ [l=sr] {_httpimg_/sr/tphrseof.gif}
+_httpicontphrseon_ [l=sr] {_httpimg_/sr/tphrseon.gif}
+_widthtphrsex_ [l=sr] {87}
+
+## "imena umetnika" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=sr] {_httpimg_/sr/tartstgr.gif}
+_httpicontartstof_ [l=sr] {_httpimg_/sr/tartstof.gif}
+_httpicontartston_ [l=sr] {_httpimg_/sr/tartston.gif}
+_widthtartstx_ [l=sr] {87}
+
+## "kljuÄne reÄi" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=sr] {_httpimg_/sr/tkwgr.gif}
+_httpicontkwof_ [l=sr] {_httpimg_/sr/tkwof.gif}
+_httpicontkwon_ [l=sr] {_httpimg_/sr/tkwon.gif}
+_widthtkwx_ [l=sr] {87}
+
+## "sveske" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=sr] {_httpimg_/sr/tvolgr.gif}
+_httpicontvolof_ [l=sr] {_httpimg_/sr/tvolof.gif}
+_httpicontvolon_ [l=sr] {_httpimg_/sr/tvolon.gif}
+_widthtvolx_ [l=sr] {87}
+
+## "natpisi" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=sr] {_httpimg_/sr/tcaptgr.gif}
+_httpicontcaptof_ [l=sr] {_httpimg_/sr/tcaptof.gif}
+_httpicontcapton_ [l=sr] {_httpimg_/sr/tcapton.gif}
+_widthtcaptx_ [l=sr] {87}
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "pomoÄ" ## green_title ## h_help ##
+_httpiconhhelp_ [l=sr] {_httpimg_/sr/h\_help.gif}
+_widthhhelp_ [l=sr] {200}
+_heighthhelp_ [l=sr] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=sr] {O ovoj kolekciji}
+
+_textsubcols1_ [l=sr] {<p>Kolekcija sadrÅŸi _1_ podkolekcija. Trenutno su dostupne:
+<blockquote>}
+
+_textsubcols2_ [l=sr] {</blockquote>
+MoÅŸete da proverite (i izmenite) koje podkolekcije trenutno koristite preko stranice
+za podeÅ¡avanja.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "o" ## green_title ## h_about ##
+_httpiconhabout_ [l=sr] {_httpimg_/sr/h\_about.gif}
+_widthhabout_ [l=sr] {200}
+_heighthabout_ [l=sr] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=sr] {Naslovi A-Åœ/A-Ðš}
+_texticonhcreat_ [l=sr] {Autori A-Åœ/A-Ðš}
+_texticonhsubj_ [l=sr] {Oblasti}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=sr] {Datumi}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=sr] {Imena datoteka}
+_texticonhlang_ [l=sr] {Jezici}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=sr] {Kome}
+_texticonhfrom_ [l=sr] {Od koga}
+_texticonhser_ [l=sr] {Edicije}
+_texticonhhow_ [l=sr] {Kako da}
+_texticonhorg_ [l=sr] {Organizacije}
+_texticonhbrwse_ [l=sr] {Prelistavanje}
+_texticonhbrows_ [l=sr] {Prelistavanje}
+_texticonhpeople_ [l=sr] {Ljudi  A-Åœ/Ð-Ðš}
+_texticonhacronym_ [l=sr] {Akronimi}
+_texticonhphrases_ [l=sr] {Fraze}
+_texticonhartist_ [l=sr] {Imena umetnika}
+_texticonhkw_ [l=sr] {KljuÄne reÄi}
+_texticonhvol_ [l=sr] {Sveske}
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=sr] {zatvaranje ovog odeljka biblioteke}
+_texticonclosedbookshelf_ [l=sr] {otvaranje ovog odeljka biblioteke i prikazivanje sadrÅŸaja}
+_texticonopenbook_ [l=sr] {zatvaranje ove knjige}
+_texticonclosedfolder_ [l=sr] {Otvaranje omotnice i prikazivanje sadrÅŸaja}
+_texticonclosedfolder2_ [l=sr] {otvaranje pododeljka:}
+_texticonopenfolder_ [l=sr] {zatvaranje omotnice}
+_texticonopenfolder2_ [l=sr] {zatvaranje pododeljka:}
+_texticonsmalltext_ [l=sr] {Prikazivanje ovog odeljka teksta}
+_texticonsmalltext2_ [l=sr] {Prikazivanje teksta:}
+_texticonpointer_ [l=sr] {aktivni odeljak}
+_texticondetach_ [l=sr] {Otvaranje stranice u novom prozoru}
+_texticonhighlight_ [l=sr] {Isticanje tremina za pretraÅŸivanje}
+_texticonnohighlight_ [l=sr] {Termini za pretraÅŸivanje se ne istiÄu}
+_texticoncontracttoc_ [l=sr] {SaÅŸimanje sadrÅŸaja}
+_texticonexpandtoc_ [l=sr] {Å irenje sadrÅŸaja}
+_texticonexpandtext_ [l=sr] {Prikazivanje celokupnog teksta}
+_texticoncontracttext_ [l=sr] {Prikazivanje teksta za trenutno odabrane odeljke}
+_texticonwarning_ [l=sr] {<b>PaÅŸnja: </b>}
+_texticoncont_ [l=sr] {Da li ÅŸelite da nastavite?}
+
+_textltwarning_ [l=sr] {<p><center>
+   <table cellspacing=0 cellpadding=0 width=_pagewidth_>
+    <tr valign=top><td>_iconwarning_ Prikazivanje celokupnog teksta predstavlja veliku  
+    koliÄinu podataka koju vaÅ¡ web ÄitaÄ treba da prikaÅŸe  _imagecont_
+   </td></tr></table></center>
+}
+
+_textgoto_ [l=sr] {idi na stranicu}
+_textintro_ [l=sr] {<i>(uvodni tekst)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "naslovi a-ÅŸ/a-Ñ" ## green_title ## h_title ##
+_httpiconhtitle_ [l=sr] {_httpimg_/sr/h\_title.gif}
+_widthhtitle_ [l=sr] {200}
+_heighthtitle_ [l=sr] {57}
+
+# Not true DC, kept for legacy reasons
+## "autori a-ÅŸ/a-Ñ" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=sr] {_httpimg_/sr/h\_auth.gif}
+_widthhcreat_ [l=sr] {200}
+_heighthcreat_ [l=sr] {57}
+
+## "oblasti" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=sr] {_httpimg_/sr/h\_subj.gif}
+_widthhsubj_ [l=sr] {200}
+_heighthsubj_ [l=sr] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "datumi" ## green_title ## h_date ##
+_httpiconhdate_ [l=sr] {_httpimg_/sr/h\_date.gif}
+_widthhdate_ [l=sr] {200}
+_heighthdate_ [l=sr] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "imena datoteka" ## green_title ## h_src ##
+_httpiconhsrc_ [l=sr] {_httpimg_/sr/h\_src.gif}
+_widthhsrc_ [l=sr] {200}
+_heighthsrc_ [l=sr] {57}
+
+## "jezici" ## green_title ## h_lang ##
+_httpiconhlang_ [l=sr] {_httpimg_/sr/h\_lang.gif}
+_widthhlang_ [l=sr] {200}
+_heighthlang_ [l=sr] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "kome" ## green_title ## h_to ##
+_httpiconhto_ [l=sr] {_httpimg_/sr/h\_to.gif}
+_widthhto_ [l=sr] {200}
+_heighthto_ [l=sr] {57}
+
+## "od koga" ## green_title ## h_from ##
+_httpiconhfrom_ [l=sr] {_httpimg_/sr/h\_from.gif}
+_widthhfrom_ [l=sr] {200}
+_heighthfrom_ [l=sr] {57}
+
+## "edicije" ## green_title ## h_ser ##
+_httpiconhser_ [l=sr] {_httpimg_/sr/h\_ser.gif}
+_widthhser_ [l=sr] {200}
+_heighthser_ [l=sr] {57}
+
+## "kako da" ## green_title ## h_how ##
+_httpiconhhow_ [l=sr] {_httpimg_/sr/h\_how.gif}
+_widthhhow_ [l=sr] {200}
+_heighthhow_ [l=sr] {57}
+
+## "teme" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=sr] {_httpimg_/sr/h\_topic.gif}
+_widthhtopic_ [l=sr] {200}
+_heighthtopic_ [l=sr] {57}
+
+## "organizacija" ## green_title ## h_org ##
+_httpiconhorg_ [l=sr] {_httpimg_/sr/h\_org.gif}
+_widthhorg_ [l=sr] {250}
+_heighthorg_ [l=sr] {57}
+
+## "prelistavanje" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=sr] {_httpimg_/sr/h\_brwse.gif}
+_widthhbrwse_ [l=sr] {200}
+_heighthbrwse_ [l=sr] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "ljudi" ## green_title ## h_people ##
+_httpiconhpeople_ [l=sr] {_httpimg_/sr/h\_people.gif}
+_widthhpeople_ [l=sr] {200}
+_heighthpeople_ [l=sr] {57}
+
+## "akronimi" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=sr] {_httpimg_/sr/h\_acro.gif}
+_widthhacronym_ [l=sr] {200}
+_heighthacronym_ [l=sr] {57}
+
+## "fraze" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=sr] {_httpimg_/sr/h\_phrse.gif}
+_widthhphrse_ [l=sr] {200}
+_heighthphrse_ [l=sr] {57}
+
+## "imena umetnika" ## green_title ## h_artist ##
+_httpiconhartist_ [l=sr] {_httpimg_/sr/h\_artist.gif}
+_widthhartist_ [l=sr] {200}
+_heighthartist_ [l=sr] {57}
+
+## "kljuÄne reÄi" ## green_title ## h_kw ##
+_httpiconhkw_ [l=sr] {_httpimg_/sr/h\_kw.gif}
+_widthhkw_ [l=sr] {200}
+_heighthkw_ [l=sr] {57}
+
+## "sveske" ## green_title ## h_vol ##
+_httpiconhvol_ [l=sr] {_httpimg_/sr/h\_vol.gif}
+_widthhvol_ [l=sr] {200}
+_heighthvol_ [l=sr] {57}
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+## "natpisi" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=sr] {_httpimg_/sr/h\_capt.gif}
+_widthhcapt_ [l=sr] {200}
+_heighthcapt_ [l=sr] {57}
+
+
+## "NASTAVAK ??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=sr] {_httpimg_/sr/contof.gif}
+_httpiconconton_ [l=sr] {_httpimg_/sr/conton.gif}
+
+## "PRIKAZIVANJE\nTEKSTA" ## document_button ## eallt ##
+_httpiconealltof_ [l=sr] {_httpimg_/sr/ealltof.gif}
+_httpiconeallton_ [l=sr] {_httpimg_/sr/eallton.gif}
+
+## "SUÅœAVANJE\nSADRÅœAJA" ## document_button ## econc ##
+_httpiconeconcof_ [l=sr] {_httpimg_/sr/econcof.gif}
+_httpiconeconcon_ [l=sr] {_httpimg_/sr/econcon.gif}
+
+## "NOVI\nPROZOR" ## document_button ## edtch ##
+_httpiconedtchof_ [l=sr] {_httpimg_/sr/edtchof.gif}
+_httpiconedtchon_ [l=sr] {_httpimg_/sr/edtchon.gif}
+
+## "PRIKAZIVANJE\nSADRÅœAJA" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=sr] {_httpimg_/sr/eexpcof.gif}
+_httpiconeexpcon_ [l=sr] {_httpimg_/sr/eexpcon.gif}
+
+## "SUÅœAVANJE\nTEKSTA" ## document_button ## etsec ##
+_httpiconetsecof_ [l=sr] {_httpimg_/sr/etsecof.gif}
+_httpiconetsecon_ [l=sr] {_httpimg_/sr/etsecon.gif}
+
+## "ISTICANJE\nTEKSTA" ## document_button ## ehl ##
+_httpiconehlof_ [l=sr] {_httpimg_/sr/ehlof.gif}
+_httpiconehlon_ [l=sr] {_httpimg_/sr/ehlon.gif}
+
+## "BEZ ISTICANJA\nTEKSTA" ## document_button ## enhl ##
+_httpiconenhlof_ [l=sr] {_httpimg_/sr/enhlof.gif}
+_httpiconenhlon_ [l=sr] {_httpimg_/sr/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=sr] {_If_(_thislast_,resultats _thisfirst_ - _thislast_ pour la recherche: _cgiargq_,Nema dokumenata koji zadovoljavaju upit: _cgiargq_)}
+_textnoquerytitle_ [l=sr] {Stranica za pretraÅŸivanje}
+
+_texticonthispage_ [l=sr] {PretraÅŸivanje}
+_textsome_ [l=sr] {neki}
+_textall_ [l=sr] {sve}
+_textboolean_ [l=sr] {Bulovi operatori}
+_textranked_ [l=sr] {rangirano}
+_textnatural_ [l=sr] {prirodni}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=sr] {}
+_texticonsearchhistorybar_ [l=sr] {prethodna pretraÅŸivanja}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=sr] {koristiti ovaj upit}
+_textfreqmsg1_ [l=sr] {Broj reÄi:}
+_textpostprocess_ [l=sr] {_If_(_quotedquery_,<br><i>naknadno obraÄeno da se pronaÄe _quotedquery_</i>
+)}
+_textinvalidquery_ [l=sr] {PogreÅ¡na sintaksa u upitu}
+
+_textmorethan_ [l=sr] {ViÅ¡e od}
+_textapprox_ [l=sr] {O}
+_textnodocs_ [l=sr] {Nijedan dokument nije zadovoljio upit.}
+_text1doc_ [l=sr] {1 dokument zadovoljava upit.}
+_textlotsdocs_ [l=sr] {dokumenata je zadovoljilo upit.}
+_textmatches_ [l=sr] {Rezultati}
+_textbeginsearch_ [l=sr] {PoÄetak pretraÅŸivanja}
+_textrunquery_ [l=sr] {IzvrÅ¡avanje upita}
+_textclearform_ [l=sr] {Obrisati obrazac}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=sr] {ReÄ ili fraza}
+_textinfield_ [l=sr] {... U polju}
+_textfoldstem_ [l=sr] {(prevoj, kraj reÄi)}
+
+_textadvquery_ [l=sr] {Ili ukucajte direktno upit:}
+_textallfields_ [l=sr] {sva polja}
+_texttextonly_ [l=sr] {samo tekst}
+_textand_ [l=sr] {i}
+_textor_ [l=sr] {ili}
+_textandnot_ [l=sr] {i ne}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=sr] {PretraÅŸivanje _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_, at _gselection_ level )_If_(_nselection_,in _nselection_ language )koji sadrÅŸi _querytypeselection_ reÄi}
+
+_textadvancedsearch_ [l=sr] {PretraÅŸivanje _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_, at _gselection_ level )_If_(_nselection_,in _nselection_ language )uz koriÅ¡Äenje _querytypeselection_ upita}
+
+_textformsimplesearch_ [l=sr] {PretraÅŸivanje _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )koji sadrÅŸi _formquerytypeselection_}
+
+_textformadvancedsearch_ [l=sr] {PretraÅŸivanje _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )i prikazivanje rezultata u redosledu _formquerytypeselection_}
+
+
+_textnojsformwarning_ [l=sr] {Upozorenje: VaÅ¡ web ÄitaÄ ne podrÅŸava Javascript. <br>Da bi koristili obrazac za pretraÅŸivanje, ukljuÄite tu opciju.}
+_textdatesearch_ [l=sr] {Kolekcija moÅŸe da se pretraÅŸuje po dokumentima u okviru jednog intervala vremena ili po dokumentima koji sadrÅŸe odreÄeni datum.}
+_textstartdate_ [l=sr] {Polazni (ili jedini) datum:}
+_textenddate_ [l=sr] {ZavrÅ¡ni datum:}
+_textbc_ [l=sr] {pre nove ere}
+_textad_ [l=sr] {nove ere}
+_textexplaineras_ [l=sr] {Â«pre nove ereÂ» i Â«nove ereÂ» su alternacije za PNE i NE.}
+
+_textstemon_ [l=sr] {(ignorisati krajeve reÄi)}
+
+_textsearchhistory_ [l=sr] {PretraÅŸivanje prethodnih pretraÅŸivanja}
+
+#text macros for search history
+_textnohistory_ [l=sr] {Prethodna pretraÅŸivanja nisu dostupna.}
+_texthresult_ [l=sr] {rezultat}
+_texthresults_ [l=sr] {rezultati}
+_texthallwords_ [l=sr] {sve reÄi}
+_texthsomewords_ [l=sr] {neke reÄi}
+_texthboolean_ [l=sr] {Bulovi operatori}
+_texthranked_ [l=sr] {rangirano}
+_texthcaseon_ [l=sr] {la casse doit correspondre}
+# -- Missing translation: _texthcaseoff_
+_texthstemon_ [l=sr] {racines des mots}
+_texthstemoff_ [l=sr] {totalitÃ© des mots}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "pretraÅŸivanje" ## green_title ## h_search ##
+_httpiconhsearch_ [l=sr] {_httpimg_/sr/h\_search.gif}
+_widthhsearch_ [l=sr] {200}
+_heighthsearch_ [l=sr] {57}
+
+## "rezultati" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=sr] {_httpimg_/sr/qryresb.gif}
+_widthqryresb_ [l=sr] {_pagewidth_}
+_heightqryresb_ [l=sr] {17}
+
+## "prethodna pretraÅŸivanja" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=sr] {_httpimg_/sr/schhistb.gif}
+_widthsrchhistb_ [l=sr] {_pagewidth_}
+_heightsrchhistb_ [l=sr] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=sr] {PodeÅ¡avanja su izvrÅ¡ena. Ne koristite dugme "back" vaÅ¡eg web ÄitaÄa jer Äe poremetiti podeÅ¡avanja! Umesto toga, kliknite na neko dugme za pristup kolekcijama.}
+_textsetprefs_ [l=sr] {PodeÅ¡avanja}
+_textsearchprefs_ [l=sr] {PodeÅ¡avanja pretraÅŸivanja}
+_textcollectionprefs_ [l=sr] {PodeÅ¡avanja kolekcije}
+_textpresentationprefs_ [l=sr] {PodeÅ¡avanja prezentacije}
+_textpreferences_ [l=sr] {PodeÅ¡avanja}
+_textcasediffs_ [l=sr] {Razlika izmeÄu velikih i malih slova:}
+_textignorecase_ [l=sr] {ne razlikuju se velika i mala slova}
+_textmatchcase_ [l=sr] {velika i mala slova moraju se slagati}
+_textwordends_ [l=sr] {Krajevi reÄi:}
+_textstem_ [l=sr] {ignorisanje krajeva reÄi}
+_textnostem_ [l=sr] {cela reÄ mora da odgovara}
+_textprefop_ [l=sr] {Povratak na _maxdocoption_ rezultate sa _hitsperpageoption_ rezultata po strani.}
+_textextlink_ [l=sr] {Pristup eksternim web stranicama:}
+_textintlink_ [l=sr] {Izvorni dokumenti pronaÄeni u:}
+_textlanguage_ [l=sr] {Jezik interfejsa:}
+_textencoding_ [l=sr] {Kodiranje:}
+_textformat_ [l=sr] {Oblik interfejsa:}
+_textall_ [l=sr] {sve}
+_textquerymode_ [l=sr] {NaÄin pretraÅŸivanja:}
+_textsimplemode_ [l=sr] {jednostavno pretraÅŸivanje}
+_textadvancedmode_ [l=sr] {napredno pretraÅŸivanje (Bulovo pretraÅŸivanje uz koriÅ¡Äenje znakova !, &, | i zagrada)}
+_textlinkinterm_ [l=sr] {kroz meÄustranicu}
+_textlinkdirect_ [l=sr] {idi pravo tamo}
+_textdigitlib_ [l=sr] {digitalna biblioteka}
+_textweb_ [l=sr] {web}
+_textgraphical_ [l=sr] {GrafiÄki}
+_texttextual_ [l=sr] {Tekstualni}
+_textcollectionoption_ [l=sr] {<p>
+Podkolekcija za ukljuÄivanje:
+<br>}
+
+_textrelateddocdisplay_ [l=sr] {Prikazivanje sliÄnih dokumenata}
+_textsearchhistory_ [l=sr] {Prethodna pretraÅŸivanja:}
+_textnohistory_ [l=sr] {Nema istorije pretraÅŸivanja}
+_texthistorydisplay_ [l=sr] {prikazivanje _historynumrecords_ prethodnih pretraÅŸivanja}
+_textnohistorydisplay_ [l=sr] {Bez prikazivanja prethodnih pretraÅŸivanja}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=sr] {Obrazac za pretraÅŸivanje:}
+_textplainsearch_ [l=sr] {Puno pretraÅŸivanje:}
+_textqueryboxsize_ [l=sr] {VeliÄina polja za upit:}
+_textregbox_ [l=sr] {Normalni okvir za upit}
+_textbigbox_ [l=sr] {proÅ¡ireni okvir za upit}
+_textformtype_ [l=sr] {Tip obrasca:}
+_textsimple_ [l=sr] {jednostavno}
+_textadvanced_ [l=sr] {napredno}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=sr] {sa}
+_textfields_ [l=sr] {polja}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "podeÅ¡avanja" ## green_title ## h_pref ##
+_httpiconhpref_ [l=sr] {_httpimg_/sr/h\_pref.gif}
+_widthhpref_ [l=sr] {200}
+_heighthpref_ [l=sr] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=sr] {Sortiranje dokumenata prema}
+_textalsoshowing_ [l=sr] {takoÄe prikazuje}
+_textwith_ [l=sr] {sa najviÅ¡e}
+_textdocsperpage_ [l=sr] {dokumenata po strani}
+
+_textfilterby_ [l=sr] {Dobijanje dokumenata koji sadrÅŸe}
+_textall_ [l=sr] {sve}
+_textany_ [l=sr] {bilo koji}
+_textwords_ [l=sr] {reÄi}
+_textleaveblank_ [l=sr] {ostaviti prazan okvir da bi se dobili svi dokumenti}
+
+_browsebuttontext_ [l=sr] {Sortiranje dokumenata}
+
+_nodata_ [l=sr] {<i>nema podataka</i>}
+_docs_ [l=sr] {dokumenata}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=sr] {PomoÄ}
+_textSearchshort_ [l=sr] {pretraÅŸivanje po pojedinim reÄima}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=sr] {pristup publikacijama po naslovu}
+_textCreatorshort_ [l=sr] {pristup publikacijama po autoru}
+_textSubjectshort_ [l=sr] {pristup publikacijama po oblastima}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=sr] {pristup publikacijama po datumu}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=sr] {pristup publikacijama po imenima datoteka}
+_textLanguageshort_ [l=sr] {pristup publikacijama po jeziku na kome su napisane}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=sr] {pristup publikacijama po edicijama}
+_textToshort_ [l=sr] {pristup publikacijama po polju "Kome"}
+_textFromshort_ [l=sr] {pristup publikacijama po polju "Od koga"}
+_textBrowseshort_ [l=sr] {Prelistavanje publikacija}
+_textOrganizationshort_ [l=sr] {pristup publikacijama prema organizacijama}
+_textHowtoshort_ [l=sr] {pristup publikacijama po spisku "kako da"}
+_textTopicshort_ [l=sr] {pristup publiakcijama po temi}
+_textPeopleshort_ [l=sr] {pristup publikacijama po imenima ljudi}
+_textAcronymshort_ [l=sr] {pristupanje publikacijama po akronimima}
+_textPhraseshort_ [l=sr] {prelistavanje fraza koje se pojavljuju u publikaciji}
+_textArtistshort_ [l=sr] {pristup publikacijama po imenu umetnika}
+_textKeywordshort_ [l=sr] {pristup publikacijama po kljuÄnim reÄima}
+_textVolumeshort_ [l=sr] {pristup publiakcijama po broju sveske
+}
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=sr] {nedefinisana klasifikacija}
+
+_textSearchlong_ [l=sr] {<p>MoÅŸete <i>pretraÅŸivati pojedine reÄi</i>
+prisutne u tekstu, polazeÄi od stranice sa pretraÅŸivanjem.
+To je prva stranica koja vam se pojavljuje kada poÄinjete da pretraÅŸujete.
+Sa drugih stranica do nje moÅŸete doÄi klikom na dugme
+<i>pretraÅŸivanje</i>.}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama
+po naslovu</i> klikom na dugme  <i>Naslovi a-ÅŸ/a-Ñ</i>. PojaviÄe 
+se abecedna (azbuÄna) lista naslova knjiga u kolekciji.}
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=sr] {<p>MoÅŸete<i>pristupiti publikacijama
+po autoru</i>klikom na dugme <i>Autori a-ÅŸ/a-Ñ</i>. PojaviÄe se lista knjiga,
+sortiranih prema imenima autora.}
+
+_textSubjectlong_ [l=sr] {<p>MoÅŸete<i>pristupiti publikacijama
+po oblastima</i> klikom na dugme <i>oblasti</i>.
+PojaviÄe se lista oblasti, predstavljena policama sa knjigama.}
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama 
+po datumu</i>klikom na dugme <i>datumi</i>. PojaviÄe se lista izdanja, sortiranih hronoloÅ¡ki.}
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=sr] {<p>MoÅŸete<i>pristupiti publikacijama po
+imenima datoteka</i>klikom na dugme<i>imena datoteka</i>.
+PojaviÄe se lista dokumenata sortiranih prema originalnim imenima datoteka.}
+
+_textLanguagelong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama po jeziku na kome su napisane
+</i> klikom na dugme
+<i>jezici</i>. PojaviÄe se lista dokumenata 
+sortiranih prema jeziku.}
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=sr] {<p>MoÅŸete<i>pristupiti publikacijama 
+prema organizacijama</i> klikom na dugme 
+<i>Organizacije</i>. PojaviÄe se abecedna (azbuÄna) lista organizacija.}
+
+_textHowtolong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama po spisku "kako da"</i>
+klikom na dugme<i>kako da</i>.  PojaviÄe se lista "kako da" 
+moguÄnosti.}
+
+_textTopiclong_ [l=sr] {<p>MoÅŸete<i>pristupiti publikacijama
+po temi</i>klikom na dugme <i>teme</i>. PojaviÄe se lista tema koju
+moÅŸete da prelistavate.}
+
+_textTolong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama po polju "Kome"
+</i>klikom na dugme <i>kome</i> .  PojaviÄe se lista primaoca sa e-mail adresama.}
+
+_textFromlong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama po polju "Od koga"
+</i> klikom na dugme <i>od koga</i>. PojaviÄe se lista poÅ¡iljalaca sa e-mail adresama.}
+
+_textSerieslong_ [l=sr] {<p>MoÅŸete<i>pristupati publikacijama 
+po edicijama </i>klikom na dugme <i>Edicije</i>.  PojaviÄe se lista edicija zastupljenih u 
+aktuelnoj kolekciji.}
+
+_textBrowselong_ [l=sr] {<p>MoÅŸete <i> prelistavati publikacije 
+</i>klikom na dugme<i>Prelistavanje</i>.}
+
+_textPeoplelong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama prema ljudima </i> klikom na dugme <i>ljudi a-ÅŸ/a-Ñ</i>.  PojaviÄe se lista 
+sortirana po prezimenima}
+
+_textAcronymlong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama po akronimu
+</i> klikom na dugme 
+<i>akronimi</i>. PojaviÄe se lista akronima, kao
+i mesta na kojima se pojavljuju.}
+
+_textPhraselong_ [l=sr] {<p>MoÅŸete <i>prelistavati fraze koje se pojavljuju 
+u publikacijama</i>klikom na dugme
+<i>fraze</i>. Ovde se koristi web ÄitaÄ za traÅŸenje fraza.}
+
+_textArtistlong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama po imenu umetnika
+</i> klikom na dugme<i>umetnici</i>. PojaviÄe se lista dokumenata,
+sortiranih prema imenima umetnika.}
+
+_textKeywordlong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama po kljuÄnim reÄima 
+</i>klikom na dugme<i>kljuÄne reÄi</i>. PojaviÄe se 
+lista kljuÄnih reÄi.}
+
+_textVolumelong_ [l=sr] {<p>MoÅŸete <i>pristupiti publikacijama
+po broju sveske</i> klikom na dugme <i>sveske</i>. PojaviÄe 
+se lista svezaka.
+}
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=sr] {<p>Kliknite na dugme <i>nepoznato</i>
+da bi prelistavali publikacije
+(dokumenti u listi su sortirani po nekom nepoznatom polju)}
+
+_texthelptopics_ [l=sr] {<h2 align=left>Teme</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Kako pretraÅŸivati po pojedinim reÄima</a>
+<ul>
+  <li><a href="\#query-terms">Termini za pretraÅŸivanje</a>
+  <li><a href="\#query-type">Vrste upita</a>
+  <li><a href="\#scope-of-queries">Opseg upita</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">PodeÅ¡avanja kolekcija</a>
+  <li><a href="\#lang-prefs">PodeÅ¡avanja jezika</a>
+  <li><a href="\#pres-prefs">PodeÅ¡avanja prikaza</a>
+  <li><a href="\#search-prefs">PodeÅ¡avanja pretraÅŸivanja</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=sr] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=sr] {Kako Äitati dokumente}
+
+# -- Missing translation: _texthelpreadingdocs_
+
+_texthelpsearching_ [l=sr] {<h2>Kako pretraÅŸivati po pojedinim reÄima?</h2>
+<p>
+Na stranici za pretraÅŸivanje formiraÄete upit sledeÄi ova tri koraka: <p>
+
+  <ol>
+      <li>NaznaÄite na kojim dokumentima ÅŸelite da primenite ovo pretraÅŸivanje
+      <li>NaznaÄite da li ÅŸelite da pretraÅŸujete po svim reÄima ili samo po nekim 
+      <li>Ukucajte reÄi po kojima ÅŸelite da pretraÅŸujete 
+      <li>Kliknite na dugme <i>PoÄetak pretraÅŸivanja</i>
+  </ol>
+
+<p>Kada obavite pretraÅŸivanje, naslovi prvih dvadeset dokumenata koji zadovoljavaju pretraÅŸivanje, 
+naÄi Äe se na ekranu. Na kraju liste su dugmiÄi za navigaciju, koji vam omoguÄavaju da pristupite 
+sledeÄoj grupi od dvadeset dokumenata. Da biste pogledali dokument treba da kliknete na naslov 
+ili malo dugme iza njega.  
+
+
+<p>Broj dokumenata koji se pojavljuju kao rezultati pretraÅŸivanja limitiran je na 100.
+MoÅŸete da izmenite ovaj broj, ako kliknete na dugme 
+<i>"PodeÅ¡avanja"</i> na vrhu stranice.<p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Termini za pretraÅŸivanje</h3>
+
+
+<p>Sve Å¡to ukucate u polje za pretraÅŸivanje tumaÄi se kao lista reÄi 
+nazvana Â«termini za pretraÅŸivanjeÂ». Svaki termin mora biti alfanumerik 
+i sme da sadrÅŸi samo slova i cifre. Termini za pretraÅŸivanje odvojeni su razmacima.
+Ako se u terminima za pretraÅŸivanje pojavi neki znak interpunkcije, biÄe ignorisan,  
+odnosno tretiran kao razmak. 
+
+<p>Na primer, upit<p>
+
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>daÄe iste rezultate kao i upit<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Vrste upita</h3>
+
+<p>Postoje dve vrste upita.
+
+<ul>
+
+<li>Upit po <b>svim</b> reÄima.  Ovaj vrsta upita 
+pretraÅŸuje dokumente koji sadrÅŸe sve navedene reÄi.
+Dokumenti koji zadovoljavaju upit, prikazuju se u abecednom (azbuÄnom) redu.<p>
+
+<li>Upit po <b>nekim</b> reÄima. MoÅŸete dati listu
+reÄi koje se vrlo verovatno nalaze u dokumentima koje traÅŸite. 
+U ovom sluÄaju dokumenti se prikazuju prema stepenu zadovoljavanja upita. 
+Kada se odreÄuje stepen zadovoljavanja upita, vaÅŸi sledeÄe 
+
+<p><ul>
+
+<li>ukoliko dokument sadrÅŸi viÅ¡e termina za pretraÅŸivanje, bolje zadovoljava upit ;
+
+<li>neuobiÄajeni termini vaÅŸniji su za pretraÅŸivanje od uobiÄajenih; 
+
+<li>manji dokumenti bolje zadovoljavaju upit od veÄih.
+
+</ul>
+
+</ul>
+
+<p>MoÅŸete koristiti koliko god hoÄete termina za pretraÅŸivanje: 
+Äitavu reÄenicu ili Äitav paragraf. 
+Ako koristite samo jedan termin za pretraÅŸivanje, dokumenti koji zadovoljavaju upit
+biÄe ureÄeni prema uÄestanosti pojavljivanja tog termina. 
+
+<p>
+
+_texthelpscope_
+
+}
+
+_textdatesearch_ [l=sr] {PretraÅŸivanje datuma}
+
+_texthelpdatesearch_ [l=sr] {<h2>_textdatesearch_</h2>
+
+PretraÅŸivanje po datumu omoguÄava vam da naÄete dokumente koji 
+ispunjavaju direktne kriterijume vaÅ¡eg pretraÅŸivanja, kao i dokumente koji se bave  
+dogaÄajima vremenski lociranim u zadati period. MoÅŸete da pretraÅŸujete
+dokumente vezane za jednu odreÄenu godinu ili za odreÄeni interval godina.UoÄite da nije neophodno imati ikakve termine za pretraÅŸivanje 
+kada se ima pretraÅŸivanje po datumu.
+S druge strane nije neophodno koriÅ¡Äenje datuma u pretraÅŸivanju: 
+ako ne precizirate niti jedan datum u dokumentu, to je kao da pretraÅŸivanje
+po datumu ne postoji. <p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>Kako da koristite ovu funkciju:</h3>
+<ul>
+   <li>Da biste pretraÅŸivali dokumente vezane za samo jednu godinu:<p>
+   <ul>
+       <li>Unesite kriterijume za pretraÅŸivanje kao obiÄno. 
+       <li>Unesite ÅŸeljenu godinu u prozorÄiÄ "Polazni (ili jedinstveni) datum".
+       <li>Ako je vaÅ¡ datum iz perioda pre nove ere 
+           odaberite opciju "pre nove ere" iz padajuÄeg menija 
+           pored prozorÄiÄa. 
+       <li>ZapoÄnite pretraÅŸivanje kako obiÄno i Äinite. 
+   </ul>
+<p><li>Da biste pretraÅŸivali dokumente koji pokrivaju odreÄeni period ili interval godina:<p>
+   <ul>
+       <li>Unesite kriterijume za pretraÅŸivanje kao obiÄno.
+       <li>Unesite poÄetnu godinu u prozorÄiÄ "Polazni datum".
+       <li>Unesite zavrÅ¡nu godinu u prozorÄiÄ "ZavrÅ¡ni datum".
+       <li>Odaberite opciju "pre nove ere" iz padajuÄeg menija pored prozorÄiÄa
+           za sve datume iz tog perioda.  
+       <li>ZapoÄnite pretraÅŸivanje kako obiÄno i Äinite. 
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>Kako ovo pretraÅŸivanje funkcioniÅ¡e?</h3>
+
+Generalno govoreÄi, pretraÅŸivanje dokumenata po godini 1903. 
+neÄe dati rezultate koji ukljuÄuju knjige napisane 1903. godine   
+veÄ jedino dokumente koji se bave godinom 1903. Ipak, zbog naÄina na koji se datumi pretraÅŸuju  
+u dokumentima, meÄu rezultatima Äe se naÄi i dokumenti u intervalu godina    
+(na primer  1899-1911), kao i dokumenti koji u tekstu navode vek kome godina 1903. pripada
+(na primer XX vek ili dvadeseti vek). To znaÄi da se u nekim dokumentima 
+ne mora eksplicitno pojavljivati datum zadat u pretraÅŸivanju. Ovo takoÄe vaÅŸi i za  
+pretraÅŸivanje po vremesnkim intervalima, za svaku godinu u intrevalu. 
+}
+
+_textchangeprefs_ [l=sr] {Promena podeÅ¡avanja}
+
+_texthelppreferences_ [l=sr] {<h2>_textchangeprefs_</h2>
+
+<p>Ako kliknete na dugme<i>podeÅ¡avanja</i> na vrhu stranice,
+moÄi Äete da izmenite neka svojstva interfejsa 
+da biste zadovoljili svoje zahteve. 
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Izbor kolekcije</h3>
+
+Neke kolekcije sastavljene su iz viÅ¡e podkolekcija. 
+One mogu da se pretraÅŸuju pojedinaÄno ili zajedno.  
+Ukoliko ÅŸelite, moÅŸete da precizirate koje podkolekcije treba da budu 
+ukljuÄene u pretraÅŸivanje na stranici Â«PodeÅ¡avanjaÂ».
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Izbor jezika</h3>
+
+Jezik intefejsa se takoÄe moÅŸe birati, kao i kodni raspored u kome Äe se prikazivati tekst. 
+
+<p>
+KonaÄno, s obzirom na kolekciju, moÅŸete da odaberete iskljuÄivo tekstualni interfejs 
+umesto standardnog grafiÄkog. To moÅŸe da bude od koristi za one koji imaju probleme
+sa vidom, pa koriste veÄa slova ili uredjaje za sintezu govora.
+
+
+
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>PodeÅ¡avanja prezentacije</h3>
+
+Za svaku kolekciju moÅŸete da izaberete nekoliko svojstava koji kontroliÅ¡u 
+njenu prezentaciju.  
+
+<p>Kolekcije web stranica dozvoljavaju vam da eliminisete trake za navigaciju samog Greenstone-a, koje se javljaju na vrhu svake stranice prelistavanog dokumenta. Za naredno pretraÅŸivanje prisiljeni ste da koristite opciju web ÄitaÄa za povratak na prethodnu stranicu (klikom na "back" dugme ili strelicu). Isto tako, zbirke su u moguÄnosti da spreÄe pojavljivanje Greenstone-ove upozoravajuÄe poruke u sluÄaju da kliknete na link koji vodi van digitalne kolekcije, odnosno na sam Web. 
+
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>PodeÅ¡avanja pretraÅŸivanja</h3>
+
+Dva para dugmiÄa omoguÄavaju podeÅ¡avanja pretraÅŸivanja. 
+Prvi ukljuÄuje ili iskljuÄuje osetljivost na velika i mala slova 
+a drugi ignoriÅ¡e ili uzima u obzir kraj reÄi. 
+MoÅŸe da se dobije i veliki prozor za pretraÅŸivanje tekstova veliÄine paragrafa. IznenaÄujuÄe brzo se pronalaze. 
+
+<p>Na primer, ako se aktivni dugmiÄi<i>Ignorisanje razlika u velikim i malim slovima 
+</i> i <i>Ignorisanje krajeva reÄi</i> 
+, pretraÅŸivanje
+
+<p><ul><kbd>AfriÄki ples</kbd></ul>
+
+<p>biÄe tretirano na isti naÄin kao i 
+
+<p><ul><kbd>afrika pleÅ¡e</kbd></ul>
+
+<p> 
+Veliko slovo A u reÄi "AfriÄki" biÄe konvertovano u malo, dok Äe se zanemariti 
+krajevi reÄi "Äki" i "s" u reÄima "AfriÄki" i "ples", kao i "ka" i "Å¡e" u reÄima 
+"afrika" i "pleÅ¡e" respektivno. 
+
+<p>MoÅŸete joÅ¡ odabrati i "napredni" naÄin pretraÅŸivanja koji omoguÄava
+da kombinujete termine za pretraÅŸivanje koriÅ¡Äenjem  Bulovih operatora AND
+(&), OR (|), i NOT (!). Tako moÅŸete sastaviti preciznije upite. 
+
+<p>KonaÄno, moÅŸete da zadate broj pogodaka, koje Äe vam pretraÅŸivanje vraÄati, kao 
+i broj dokumenata koji se prikazuju na jednoj stranici. 
+
+}
+
+_texttanumbrowseoptions_ [l=sr] {Ima _numbrowseoptions_ naÄina da
+pronaÄete informacije u ovoj kolkeciji:}
+
+_textsimplehelpheading_ [l=sr] {Kako pronaÄi informacije u _collectionname_ kolekciji}
+
+_texthelpscope_ [l=sr] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Domaine d'application des recherches</h3>
+
+<p>
+U veÄini kolekcija moÅŸete da odaberete razliÄite indekse za pretraÅŸivanje.
+Na primer, moguÄe je da imate jedan indeks za autore a drugi za naslove, 
+pa Äak i indeks za odeljke ili paragrafe. 
+Generalno, dobiÄete dokument koji zadovoljava upit, ma 
+koji indeks za pretraÅŸivanje koristili. 
+
+<p>
+Ukoliko su dokumenti knjige, biÄe otvoreni baÅ¡ na odgovarajuÄim mestima. 
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/spanish.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/spanish.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/spanish.dm	(revision 10506)
@@ -0,0 +1,1401 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Spanish Language text and icon macros 
+# Translated by UNESCO for the UNESCO CD-ROMs
+# Contributions made by Jesus Tramullas
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=es] {Publicaciones periÃ³dicas}
+_textsource_ [l=es] {ref. fuente: }
+_textdate_ [l=es] {fecha de publicaciÃ³n: }
+_textnumpages_ [l=es] {nÃºmero de pÃ¡ginas: }
+
+_textsignin_ [l=es] {conectarse}
+
+_textdefaultcontent_ [l=es] {La pÃ¡gina solicitada no se encontrÃ³. Por 
+favor pulse el botÃ³n "AtrÃ¡s" de su navegador o el botÃ³n 
+"Inicio" para regresar a la Biblioteca Digital Greenstone.}
+
+_textdefaulttitle_ [l=es] {Error en GSDL}
+
+_textbadcollection_ [l=es] {Esta colecciÃ³n (llamada "_cvariable_") no ha sido instalada en el sistema de esta biblioteca digital Greenstone.}
+
+_textselectpage_ [l=es] {-- Seleccionar pÃ¡gina --}
+
+_collectionextra_ [l=es] {Esta colecciÃ³n contiene _about:numdocs_ documentos. 
+La colecciÃ³n se creÃ³ hace _about:builddate_ dÃ­as.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=es] {<p>Esta colecciÃ³n contiene _numdocs_ _If_("_numdocs_" eq
+"1",document,documents) y un total de _numbytes_.
+<p><a href="_httppagex_(bsummary)">Pulse aquÃ­</a> para visualizar el
+informe de creaciÃ³n de esta colecciÃ³n.
+}
+
+_textimagecollection_ [l=es] {}
+_textimageabout_ [l=es] {PÃ¡gina Acerca de}
+_textimagehome_ [l=es] {PÃ¡gina Principal}
+_textimagehelp_ [l=es] {PÃ¡gina de ayuda}
+_textimagepref_ [l=es] {PÃ¡gina de Preferencias}
+_textimagegreenstone_ [l=es] {Programa de la Biblioteca Digital Greenstone}
+_textimageusab_ [l=es] {Â¿QuÃ© es lo que encontrÃ³ difÃ­cil de usar?}
+
+_textimagesearch_ [l=es] {Buscar tÃ©rminos especÃ­ficos}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=es] {Navegar en las listas de tÃ­tulos por orden alfabÃ©tico}
+_textimageCreator_ [l=es] {Navegar en las listas de creadores por orden alfabÃ©tico}
+_textimageSubject_ [l=es] {Mostrar por tema}
+_textimageDescription_ [l=es] {Mostrar por descripciÃ³n}
+_textimagePublisher_ [l=es] {Mostrar por editor}
+_textimageContributor_ [l=es] {Mostrar por colaborador}
+_textimageDate_ [l=es] {Mostrar por fecha}
+_textimageType_ [l=es] {Mostrar por tipo de recurso}
+_textimageFormat_ [l=es] {Mostrar por formato}
+_textimageIdentifier_ [l=es] {Mostrar por identificador del recurso}
+_textimageSource_ [l=es] {Mostrar por fuente}
+_textimageLanguage_ [l=es] {Mostrar por idioma}
+_textimageRelation_ [l=es] {Mostrar por relaciÃ³n}
+_textimageCoverage_ [l=es] {Mostrar por cobertura}
+_textimageRights_ [l=es] {Mostrar por derechos}
+
+_textimageOrganization_ [l=es] {Navegar por organizaciÃ³n}
+_textimageKeyword_ [l=es] {Navegar por palabra clave}
+_textimageHowto_ [l=es] {Navegar por categorÃ­as "cÃ³mo"}
+_textimageList_ [l=es] {Navegar en la lista de documentos}
+_textimageSeries_ [l=es] {Navegar por nÃºmero de publicaciÃ³n}
+_textimageTo_ [l=es] {Navegar por campo Â«AÂ»}
+_textimageFrom_ [l=es] {Navegar por campo Â«DeÂ»}
+_textimageTopic_ [l=es] {Navegar por temas especiales}
+_textimageBrowse_ [l=es] {Navegar}
+_textimageCollage_ [l=es] {Revisar vÃ­a collage de imÃ¡genes}
+_textimagePeople_ [l=es] {Navegar en las listas de personas por orden alfabÃ©tico}
+_textimageAcronym_ [l=es] {Navegar en la lista de siglas}
+_textimagePhrase_ [l=es] {Navegar en la lista de frases}
+_textimageArtist_ [l=es] {Navegar en la lista de artistas}
+_textimageVolume_ [l=es] {Navegar por volumen}
+_textimageCountries_ [l=es] {Navegar por paÃ­ses}
+_textimageCaptions_ [l=es] {Explorar por pies de foto}
+
+
+_texticontabsearchgreen_ [l=es] {BÃºsqueda}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=es] {TÃ­tulos A-Z}
+_texticontabCreatorgreen_ [l=es] {Creadores A-Z}
+_texticontabSubjectgreen_ [l=es] {Temas}
+_texticontabDescriptiongreen_ [l=es] {DescripciÃ³nes}
+_texticontabPublishergreen_ [l=es] {Editores}
+_texticontabContributorgreen_ [l=es] {Colaboradores}
+_texticontabDategreen_ [l=es] {Fechas}
+_texticontabTypesgreen_ [l=es] {Tipos}
+_texticontabFormatgreen_ [l=es] {Formatos}
+_texticontabIdentifiergreen_ [l=es] {Identificadores}
+_texticontabSourcegreen_ [l=es] {Fuente}
+_texticontabLanguagegreen_ [l=es] {Idiomas}
+_texticontabRelationgreen_ [l=es] {RelaciÃ³nes}
+_texticontabCoveragegreen_ [l=es] {Cobertura}
+_texticontabRightsgreen_ [l=es] {Derechos}
+
+_texticontaborggreen_ [l=es] {OrganizaciÃ³n}
+_texticontabKeywordgreen_ [l=es] {Palabras clave}
+_texticontabhowgreen_ [l=es] {CÃ³mo}
+_texticontabseriesgreen_ [l=es] {Series}
+_texticontablistgreen_ [l=es] {Listas}
+_texticontabtogreen_ [l=es] {A}
+_texticontabfromgreen_ [l=es] {De}
+_texticontabtopicgreen_ [l=es] {Temas}
+_texticontabbrwsegreen_ [l=es] {Navegar}
+_texticontabCollagegreen_ [l=es] {Collage}
+_texticontabbrowsgreen_ [l=es] {Navegar}
+_texticontabPeoplegreen_ [l=es] {Personas A-Z}
+_texticontabAcronymgreen_ [l=es] {Siglas}
+_texticontabPhrasegreen_ [l=es] {Frases}
+_texticontabArtistgreen_ [l=es] {Artistas}
+_texticontabVolumegreen_ [l=es] {VolÃºmenes}
+_texticontabCaptionsgreen_ [l=es] {TÃ­tulos}
+_texticontabCountriesgreen_ [l=es] {PaÃ­ses}
+
+_texticontext_ [l=es] {Ver el documento}
+_texticonclosedbook_ [l=es] {Abrir este documento y ver su Ã­ndice de contenido}
+_texticonnext_ [l=es] {Ir a la siguiente secciÃ³n}
+_texticonprev_ [l=es] {Ir a la secciÃ³n anterior}
+
+_texticonworld_ [l=es] {Ver el documento Web}
+
+_texticonmidi_ [l=es] {Ver el documento en el formato MIDI}
+_texticonmsword_ [l=es] {Ver el documento en el formato Microsoft Word}
+_texticonmp3_ [l=es] {Ver el documento en el formato MP3}
+_texticonpdf_ [l=es] {Ver el documento en el formato PDF}
+_texticonps_ [l=es] {Ver el documento en el formato PostScript}
+_texticonppt_ [l=es] {Ver el documento en el formato PowerPoint}
+_texticonrtf_ [l=es] {Ver el documento en el formato RTF}
+_texticonxls_ [l=es] {Ver el documento en el formato Microsoft Excel}
+
+_page_ [l=es] {pÃ¡gina }
+_pages_ [l=es] {pÃ¡ginas}
+_of_ [l=es] {de }
+_vol_ [l=es] {Vol.}
+_num_ [l=es] {nÃºmero}
+
+_textmonth00_ [l=es] {}
+_textmonth01_ [l=es] {enero}
+_textmonth02_ [l=es] {febrero}
+_textmonth03_ [l=es] {marzo}
+_textmonth04_ [l=es] {abril}
+_textmonth05_ [l=es] {mayo}
+_textmonth06_ [l=es] {junio}
+_textmonth07_ [l=es] {julio}
+_textmonth08_ [l=es] {agosto}
+_textmonth09_ [l=es] {septiembre}
+_textmonth10_ [l=es] {octubre}
+_textmonth11_ [l=es] {noviembre}
+_textmonth12_ [l=es] {diciembre}
+
+_textdocument_ [l=es] {Documento}
+_textsection_ [l=es] {SecciÃ³n}
+_textparagraph_ [l=es] {PÃ¡rrafo}
+
+_magazines_ [l=es] {Revistas}
+
+_nzdlpagefooter_ [l=es] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">Proyecto de biblioteca Digital de Nueva
+Zelandia</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Departamento de informÃ¡tica</a>, 
+<a href="http://www.waikato.ac.nz">Universidad de Waikato</a>,
+Nueva Zelandia}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "PRINCIPAL" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=es] {_httpimg_/es/chomeof.gif}
+_httpiconchomeon_ [l=es] {_httpimg_/es/chomeon.gif}
+
+## "AYUDA" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=es] {_httpimg_/es/chelpof.gif}
+_httpiconchelpon_ [l=es] {_httpimg_/es/chelpon.gif}
+
+## "PREFERENCIAS" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=es] {_httpimg_/es/cprefof.gif}
+_httpiconcprefon_ [l=es] {_httpimg_/es/cprefon.gif}
+
+## "ENVIAR COMENTARIOS" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=es] {_httpimg_/es/cusabof.gif}
+_httpiconcusabon_ [l=es] {_httpimg_/es/cusabon.gif}
+
+
+## "buscar" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=es] {_httpimg_/es/tsrchgr.gif}
+_httpicontsrchof_ [l=es] {_httpimg_/es/tsrchof.gif}
+_httpicontsrchon_ [l=es] {_httpimg_/es/tsrchon.gif}
+_widthtsrchx_ [l=es] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tÃ­tulos a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=es] {_httpimg_/es/ttitlgr.gif}
+_httpiconttitleof_ [l=es] {_httpimg_/es/ttitlof.gif}
+_httpiconttitleon_ [l=es] {_httpimg_/es/ttitlon.gif}
+_widthttitlex_ [l=es] {87}
+
+# Not true DC, kept for legacy reasons
+## "creadores a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=es] {_httpimg_/es/tauthgr.gif}
+_httpicontcreatof_ [l=es] {_httpimg_/es/tauthof.gif}
+_httpicontcreaton_ [l=es] {_httpimg_/es/tauthon.gif}
+_widthtcreatx_ [l=es] {87}
+
+## "temas" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=es] {_httpimg_/es/tsubjgr.gif}
+_httpicontsubjon_ [l=es] {_httpimg_/es/tsubjon.gif}
+_httpicontsubjof_ [l=es] {_httpimg_/es/tsubjof.gif}
+_widthtsubjx_ [l=es] {87}
+
+## "descripciÃ³nes" ## nav_bar_button ## tdesc ##
+_httpicontdescgr_ [l=es] {_httpimg_/es/tdescgr.gif}
+_httpicontdescon_ [l=es] {_httpimg_/es/tdescon.gif}
+_httpicontdescof_ [l=es] {_httpimg_/es/tdescof.gif}
+_widthtdescx_ [l=es] {90}
+
+## "editores" ## nav_bar_button ## tpubl ##
+_httpicontpublgr_ [l=es] {_httpimg_/es/tpublgr.gif}
+_httpicontpublon_ [l=es] {_httpimg_/es/tpublon.gif}
+_httpicontpublof_ [l=es] {_httpimg_/es/tpublof.gif}
+_widthtpublx_ [l=es] {87}
+
+## "colaboradores" ## nav_bar_button ## tcontr ##
+_httpicontcontrgr_ [l=es] {_httpimg_/es/tcontrgr.gif}
+_httpicontcontron_ [l=es] {_httpimg_/es/tcontron.gif}
+_httpicontcontrof_ [l=es] {_httpimg_/es/tcontrof.gif}
+_widthtcontrx_ [l=es] {89}
+
+## "fechas" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=es] {_httpimg_/es/tdategr.gif}
+_httpicontdateof_ [l=es] {_httpimg_/es/tdateof.gif}
+_httpicontdateon_ [l=es] {_httpimg_/es/tdateon.gif}
+_widthtdatex_ [l=es] {87}
+
+## "tipos" ## nav_bar_button ## ttype ##
+_httpiconttypegr_ [l=es] {_httpimg_/es/ttypegr.gif}
+_httpiconttypeof_ [l=es] {_httpimg_/es/ttypeof.gif}
+_httpiconttypeon_ [l=es] {_httpimg_/es/ttypeon.gif}
+_widthttypex_ [l=es] {87}
+
+## "formatos" ## nav_bar_button ## tform ##
+_httpicontformgr_ [l=es] {_httpimg_/es/tformgr.gif}
+_httpicontformof_ [l=es] {_httpimg_/es/tformof.gif}
+_httpicontformon_ [l=es] {_httpimg_/es/tformon.gif}
+_widthtformx_ [l=es] {87}
+
+## "identificadores" ## nav_bar_button ## tident ##
+_httpicontidentgr_ [l=es] {_httpimg_/es/tidentgr.gif}
+_httpicontidentof_ [l=es] {_httpimg_/es/tidentof.gif}
+_httpicontidenton_ [l=es] {_httpimg_/es/tidenton.gif}
+_widthtidentx_ [l=es] {87}
+
+# Not true DC, kept for legacy reasons
+## "fuente" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=es] {_httpimg_/es/tsrcgr.gif}
+_httpicontsrcof_ [l=es] {_httpimg_/es/tsrcof.gif}
+_httpicontsrcon_ [l=es] {_httpimg_/es/tsrcon.gif}
+_widthtsrcx_ [l=es] {87}
+
+## "idiomas" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=es] {_httpimg_/es/tlanggr.gif}
+_httpicontlangon_ [l=es] {_httpimg_/es/tlangon.gif}
+_httpicontlangof_ [l=es] {_httpimg_/es/tlangof.gif}
+_widthtlangx_ [l=es] {87}
+
+## "relaciÃ³nes" ## nav_bar_button ## trel ##
+_httpicontrelgr_ [l=es] {_httpimg_/es/trelgr.gif}
+_httpicontrelon_ [l=es] {_httpimg_/es/trelon.gif}
+_httpicontrelof_ [l=es] {_httpimg_/es/trelof.gif}
+_widthtrelx_ [l=es] {87}
+
+## "cobertura" ## nav_bar_button ## tcover ##
+_httpicontcovergr_ [l=es] {_httpimg_/es/tcovergr.gif}
+_httpicontcoveron_ [l=es] {_httpimg_/es/tcoveron.gif}
+_httpicontcoverof_ [l=es] {_httpimg_/es/tcoverof.gif}
+_widthtcoverx_ [l=es] {87}
+
+## "derechos" ## nav_bar_button ## tright ##
+_httpicontrightgr_ [l=es] {_httpimg_/es/trightgr.gif}
+_httpicontrighton_ [l=es] {_httpimg_/es/trighton.gif}
+_httpicontrightof_ [l=es] {_httpimg_/es/trightof.gif}
+_widthtrightx_ [l=es] {87}
+
+
+
+## "series" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=es] {_httpimg_/es/tsergr.gif}
+_httpicontserof_ [l=es] {_httpimg_/es/tserof.gif}
+_httpicontseron_ [l=es] {_httpimg_/es/tseron.gif}
+_widthtserx_ [l=es] {87}
+
+## "a" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=es] {_httpimg_/es/ttogr.gif}
+_httpiconttoon_ [l=es] {_httpimg_/es/ttoon.gif}
+_httpiconttoof_ [l=es] {_httpimg_/es/ttoof.gif}
+_widthttox_ [l=es] {87}
+
+## "de" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=es] {_httpimg_/es/tfromgr.gif}
+_httpicontfromon_ [l=es] {_httpimg_/es/tfromon.gif}
+_httpicontfromof_ [l=es] {_httpimg_/es/tfromof.gif}
+_widthtfromx_ [l=es] {87}
+
+## "organizaciÃ³n" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=es] {_httpimg_/es/torggr.gif}
+_httpicontorgon_ [l=es] {_httpimg_/es/torgon.gif}
+_httpicontorgof_ [l=es] {_httpimg_/es/torgof.gif}
+_widthtorgx_ [l=es] {98}
+
+## "cÃ³mo" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=es] {_httpimg_/es/thowgr.gif}
+_httpiconthowon_ [l=es] {_httpimg_/es/thowon.gif}
+_httpiconthowof_ [l=es] {_httpimg_/es/thowof.gif}
+_widththowx_ [l=es] {87}
+
+## "temas" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=es] {_httpimg_/es/ttopicgr.gif}
+_httpiconttopicon_ [l=es] {_httpimg_/es/ttopicon.gif}
+_httpiconttopicof_ [l=es] {_httpimg_/es/ttopicof.gif}
+_widthttopicx_ [l=es] {87}
+
+## "navegar" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=es] {_httpimg_/es/tbrwsegr.gif}
+_httpicontbrwseon_ [l=es] {_httpimg_/es/tbrwseon.gif}
+_httpicontbrwseof_ [l=es] {_httpimg_/es/tbrwseof.gif}
+_widthtbrwsex_ [l=es] {87}
+
+## "collage" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=es] {_httpimg_/es/tcollgr.gif}
+_httpicontcollof_ [l=es] {_httpimg_/es/tcollof.gif}
+_httpicontcollon_ [l=es] {_httpimg_/es/tcollon.gif}
+_widthtcollx_ [l=es] {87}
+
+## "personas" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=es] {_httpimg_/es/tpeopgr.gif}
+_httpicontpeopof_ [l=es] {_httpimg_/es/tpeopof.gif}
+_httpicontpeopon_ [l=es] {_httpimg_/es/tpeopon.gif}
+_widthtpeopx_ [l=es] {97}
+
+## "sigla" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=es] {_httpimg_/es/tacrogr.gif}
+_httpicontacroof_ [l=es] {_httpimg_/es/tacroof.gif}
+_httpicontacroon_ [l=es] {_httpimg_/es/tacroon.gif}
+_widthtacrox_ [l=es] {87}
+
+## "frases" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=es] {_httpimg_/es/tphrsegr.gif}
+_httpicontphrseof_ [l=es] {_httpimg_/es/tphrseof.gif}
+_httpicontphrseon_ [l=es] {_httpimg_/es/tphrseon.gif}
+_widthtphrsex_ [l=es] {87}
+
+## "artistas" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=es] {_httpimg_/es/tartstgr.gif}
+_httpicontartstof_ [l=es] {_httpimg_/es/tartstof.gif}
+_httpicontartston_ [l=es] {_httpimg_/es/tartston.gif}
+_widthtartstx_ [l=es] {87}
+
+## "palabras clave" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=es] {_httpimg_/es/tkwgr.gif}
+_httpicontkwof_ [l=es] {_httpimg_/es/tkwof.gif}
+_httpicontkwon_ [l=es] {_httpimg_/es/tkwon.gif}
+_widthtkwx_ [l=es] {87}
+
+## "volÃºmenes" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=es] {_httpimg_/es/tvolgr.gif}
+_httpicontvolof_ [l=es] {_httpimg_/es/tvolof.gif}
+_httpicontvolon_ [l=es] {_httpimg_/es/tvolon.gif}
+_widthtvolx_ [l=es] {87}
+
+## "TÃ­tulos de las ilustraciones" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=es] {_httpimg_/es/tcaptgr.gif}
+_httpicontcaptof_ [l=es] {_httpimg_/es/tcaptof.gif}
+_httpicontcapton_ [l=es] {_httpimg_/es/tcapton.gif}
+_widthtcaptx_ [l=es] {87}
+
+## "paÃ­ses" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=es] {_httpimg_/es/tcountgr.gif}
+_httpicontcountof_ [l=es] {_httpimg_/es/tcountof.gif}
+_httpicontcounton_ [l=es] {_httpimg_/es/tcounton.gif}
+_widthtcountx_ [l=es] {87}
+
+## "ayuda" ## green_title ## h_help ##
+_httpiconhhelp_ [l=es] {_httpimg_/es/h\_help.gif}
+_widthhhelp_ [l=es] {200}
+_heighthhelp_ [l=es] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=es] {Acerca de esta colecciÃ³n}
+
+_textsubcols1_ [l=es] {<p>La colecciÃ³n completa comprende _1_ subcolecciones: 
+<blockquote>}
+
+_textsubcols2_ [l=es] {</blockquote>
+Usted puede verificar (y modificar) las subcolecciones que estÃ¡ usando  
+actualmente en la pÃ¡gina de Preferencias.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "acerca de" ## green_title ## h_about ##
+_httpiconhabout_ [l=es] {_httpimg_/es/h\_about.gif}
+_widthhabout_ [l=es] {200}
+_heighthabout_ [l=es] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=es] {TÃ­tulos A-Z}
+_texticonhcreat_ [l=es] {Creadores A-Z}
+_texticonhsubj_ [l=es] {Temas}
+_texticonhdesc_ [l=es] {DescripciÃ³nes}
+_texticonhpubl_ [l=es] {Editores}
+_texticonhcontr_ [l=es] {Colaboradores}
+_texticonhdate_ [l=es] {Fechas}
+_texticonhtype_ [l=es] {Tipos}
+_texticonhform_ [l=es] {Formatos}
+_texticonhident_ [l=es] {Identificadores}
+_texticonhsrc_ [l=es] {Fuente}
+_texticonhlang_ [l=es] {Idiomas}
+_texticonhrel_ [l=es] {RelaciÃ³nes}
+_texticonhcover_ [l=es] {Cobertura}
+_texticonhright_ [l=es] {Derechos}
+
+_texticonhcoll_ [l=es] {Collage}
+_texticonhto_ [l=es] {A}
+_texticonhfrom_ [l=es] {De}
+_texticonhser_ [l=es] {Series}
+_texticonhhow_ [l=es] {CÃ³mo}
+_texticonhorg_ [l=es] {OrganizaciÃ³n}
+_texticonhbrwse_ [l=es] {Navegar}
+_texticonhbrows_ [l=es] {Navegar}
+_texticonhpeople_ [l=es] {Personas A-Z}
+_texticonhacronym_ [l=es] {Siglas}
+_texticonhphrases_ [l=es] {Frases}
+_texticonhartist_ [l=es] {Artistas}
+_texticonhkw_ [l=es] {Palabras clave}
+_texticonhvol_ [l=es] {VolÃºmenes}
+_texticonhcapt_ [l=es] {TÃ­tulos}
+_texticonhcount_ [l=es] {PaÃ­ses}
+
+_texticonopenbookshelf_ [l=es] {cerrar esta secciÃ³n de la biblioteca}
+_texticonclosedbookshelf_ [l=es] {abrir esta secciÃ³n de la biblioteca y ver su contenido}
+_texticonopenbook_ [l=es] {cerrar este libro}
+_texticonclosedfolder_ [l=es] {Abrir esta carpeta y ver su contenido}
+_texticonclosedfolder2_ [l=es] {abrir subsecciÃ³n: }
+_texticonopenfolder_ [l=es] {cerrar esta carpeta}
+_texticonopenfolder2_ [l=es] {cerrar subsecciÃ³n: }
+_texticonsmalltext_ [l=es] {Ver esta secciÃ³n del texto}
+_texticonsmalltext2_ [l=es] {ver texto: }
+_texticonpointer_ [l=es] {secciÃ³n en curso}
+_texticondetach_ [l=es] {Abrir esta pÃ¡gina en una nueva ventana}
+_texticonhighlight_ [l=es] {Resaltar los tÃ©rminos de la bÃºsqueda}
+_texticonnohighlight_ [l=es] {No resaltar los tÃ©rminos de la bÃºsqueda}
+_texticoncontracttoc_ [l=es] {Contraer el Ã­ndice de contenido}
+_texticonexpandtoc_ [l=es] {Expandir el Ã­ndice de contenido}
+_texticonexpandtext_ [l=es] {Mostrar el texto completo}
+_texticoncontracttext_ [l=es] {Mostrar Ãºnicamente el texto de la secciÃ³n seleccionada}
+_texticonwarning_ [l=es] {<b>Advertencia: </b>}
+_texticoncont_ [l=es] {Â¿desea continuar?}
+
+_textltwarning_ [l=es] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Expandir el texto aquÃ­ generarÃ¡ una gran
+cantidad de datos que su navegador deberÃ¡ procesar _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=es] {ir a la pÃ¡gina}
+_textintro_ [l=es] {<i>(texto inicial)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tÃ­tulos a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=es] {_httpimg_/es/h\_title.gif}
+_widthhtitle_ [l=es] {200}
+_heighthtitle_ [l=es] {57}
+
+# Not true DC, kept for legacy reasons
+## "creadores a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=es] {_httpimg_/es/h\_auth.gif}
+_widthhcreat_ [l=es] {200}
+_heighthcreat_ [l=es] {57}
+
+## "temas" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=es] {_httpimg_/es/h\_subj.gif}
+_widthhsubj_ [l=es] {200}
+_heighthsubj_ [l=es] {57}
+
+## "descripciÃ³nes" ## green_title ## h_desc ##
+_httpiconhdesc_ [l=es] {_httpimg_/es/h\_desc.gif}
+_widthhdesc_ [l=es] {200}
+_heighthdesc_ [l=es] {57}
+
+## "editores" ## green_title ## h_publ ##
+_httpiconhpubl_ [l=es] {_httpimg_/es/h\_publ.gif}
+_widthhpubl_ [l=es] {200}
+_heighthpubl_ [l=es] {57}
+
+## "colaboradores" ## green_title ## h_contr ##
+_httpiconhcontr_ [l=es] {_httpimg_/es/h\_contr.gif}
+_widthhcontr_ [l=es] {200}
+_heighthcontr_ [l=es] {57}
+
+## "fechas" ## green_title ## h_date ##
+_httpiconhdate_ [l=es] {_httpimg_/es/h\_date.gif}
+_widthhdate_ [l=es] {200}
+_heighthdate_ [l=es] {57}
+
+## "tipos" ## green_title ## h_type ##
+_httpiconhtype_ [l=es] {_httpimg_/es/h\_type.gif}
+_widthhtype_ [l=es] {200}
+_heighthtype_ [l=es] {57}
+
+## "formatos" ## green_title ## h_form ##
+_httpiconhform_ [l=es] {_httpimg_/es/h\_form.gif}
+_widthhform_ [l=es] {200}
+_heighthform_ [l=es] {57}
+
+## "identificadores" ## green_title ## h_ident ##
+_httpiconhident_ [l=es] {_httpimg_/es/h\_ident.gif}
+_widthhident_ [l=es] {200}
+_heighthident_ [l=es] {57}
+
+# Not true DC, kept for legacy reasons
+## "fuente" ## green_title ## h_src ##
+_httpiconhsrc_ [l=es] {_httpimg_/es/h\_src.gif}
+_widthhsrc_ [l=es] {200}
+_heighthsrc_ [l=es] {57}
+
+## "idiomas" ## green_title ## h_lang ##
+_httpiconhlang_ [l=es] {_httpimg_/es/h\_lang.gif}
+_widthhlang_ [l=es] {200}
+_heighthlang_ [l=es] {57}
+
+## "relaciÃ³nes" ## green_title ## h_rel ##
+_httpiconhrel_ [l=es] {_httpimg_/es/h\_rel.gif}
+_widthhrel_ [l=es] {200}
+_heighthrel_ [l=es] {57}
+
+## "cobertura" ## green_title ## h_cover ##
+_httpiconhcover_ [l=es] {_httpimg_/es/h\_cover.gif}
+_widthhcover_ [l=es] {200}
+_heighthcover_ [l=es] {57}
+
+## "derechos" ## green_title ## h_right ##
+_httpiconhright_ [l=es] {_httpimg_/es/h\_right.gif}
+_widthhright_ [l=es] {200}
+_heighthright_ [l=es] {57}
+
+
+
+## "a" ## green_title ## h_to ##
+_httpiconhto_ [l=es] {_httpimg_/es/h\_to.gif}
+_widthhto_ [l=es] {200}
+_heighthto_ [l=es] {57}
+
+## "de" ## green_title ## h_from ##
+_httpiconhfrom_ [l=es] {_httpimg_/es/h\_from.gif}
+_widthhfrom_ [l=es] {200}
+_heighthfrom_ [l=es] {57}
+
+## "series" ## green_title ## h_ser ##
+_httpiconhser_ [l=es] {_httpimg_/es/h\_ser.gif}
+_widthhser_ [l=es] {200}
+_heighthser_ [l=es] {57}
+
+## "cÃ³mo" ## green_title ## h_how ##
+_httpiconhhow_ [l=es] {_httpimg_/es/h\_how.gif}
+_widthhhow_ [l=es] {200}
+_heighthhow_ [l=es] {57}
+
+## "temas" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=es] {_httpimg_/es/h\_topic.gif}
+_widthhtopic_ [l=es] {200}
+_heighthtopic_ [l=es] {57}
+
+## "organizaciÃ³n" ## green_title ## h_org ##
+_httpiconhorg_ [l=es] {_httpimg_/es/h\_org.gif}
+_widthhorg_ [l=es] {200}
+_heighthorg_ [l=es] {57}
+
+## "navegar" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=es] {_httpimg_/es/h\_brwse.gif}
+_widthhbrwse_ [l=es] {200}
+_heighthbrwse_ [l=es] {57}
+
+## "collage" ## green_title ## h_coll ##
+_httpiconhcoll_ [l=es] {_httpimg_/es/h\_coll.gif}
+_widthhcoll_ [l=es] {200}
+_heighthcoll_ [l=es] {57}
+
+## "personas" ## green_title ## h_people ##
+_httpiconhpeople_ [l=es] {_httpimg_/es/h\_people.gif}
+_widthhpeople_ [l=es] {200}
+_heighthpeople_ [l=es] {57}
+
+## "siglas" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=es] {_httpimg_/es/h\_acro.gif}
+_widthhacronym_ [l=es] {200}
+_heighthacronym_ [l=es] {57}
+
+## "frases" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=es] {_httpimg_/es/h\_phrse.gif}
+_widthhphrse_ [l=es] {200}
+_heighthphrse_ [l=es] {57}
+
+## "artistas" ## green_title ## h_artist ##
+_httpiconhartist_ [l=es] {_httpimg_/es/h\_artist.gif}
+_widthhartist_ [l=es] {200}
+_heighthartist_ [l=es] {57}
+
+## "palabras clave" ## green_title ## h_kw ##
+_httpiconhkw_ [l=es] {_httpimg_/es/h\_kw.gif}
+_widthhkw_ [l=es] {200}
+_heighthkw_ [l=es] {57}
+
+## "volÃºmenes" ## green_title ## h_vol ##
+_httpiconhvol_ [l=es] {_httpimg_/es/h\_vol.gif}
+_widthhvol_ [l=es] {200}
+_heighthvol_ [l=es] {57}
+
+## "paÃ­ses" ## green_title ## h_count ##
+_httpiconhcount_ [l=es] {_httpimg_/es/h\_count.gif}
+_widthhcount_ [l=es] {200}
+_heighthcount_ [l=es] {57}
+
+## "tÃ­tulos de las ilustraciones" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=es] {_httpimg_/es/h\_capt.gif}
+_widthhcapt_ [l=es] {200}
+_heighthcapt_ [l=es] {57}
+
+
+## "Â¿DESEA CONTINUAR???" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=es] {_httpimg_/es/contof.gif}
+_httpiconconton_ [l=es] {_httpimg_/es/conton.gif}
+
+## "TEXTO\nCOMPLETO" ## document_button ## eallt ##
+_httpiconealltof_ [l=es] {_httpimg_/es/ealltof.gif}
+_httpiconeallton_ [l=es] {_httpimg_/es/eallton.gif}
+
+## "CONTRAER\nÃNDICE" ## document_button ## econc ##
+_httpiconeconcof_ [l=es] {_httpimg_/es/econcof.gif}
+_httpiconeconcon_ [l=es] {_httpimg_/es/econcon.gif}
+
+## "SEPARAR" ## document_button ## edtch ##
+_httpiconedtchof_ [l=es] {_httpimg_/es/edtchof.gif}
+_httpiconedtchon_ [l=es] {_httpimg_/es/edtchon.gif}
+
+## "EXPANDIR\nÃNDICE" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=es] {_httpimg_/es/eexpcof.gif}
+_httpiconeexpcon_ [l=es] {_httpimg_/es/eexpcon.gif}
+
+## "CONTRAER\nTEXTO" ## document_button ## etsec ##
+_httpiconetsecof_ [l=es] {_httpimg_/es/etsecof.gif}
+_httpiconetsecon_ [l=es] {_httpimg_/es/etsecon.gif}
+
+## "RESALTAR" ## document_button ## ehl ##
+_httpiconehlof_ [l=es] {_httpimg_/es/ehlof.gif}
+_httpiconehlon_ [l=es] {_httpimg_/es/ehlon.gif}
+
+## "NO\nRESALTAR" ## document_button ## enhl ##
+_httpiconenhlof_ [l=es] {_httpimg_/es/enhlof.gif}
+_httpiconenhlon_ [l=es] {_httpimg_/es/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=es] {_If_(_thislast_,resultados _thisfirst_ - _thislast_ para la consulta:_cgiargq_,No se encontraron resultados correspondientes a  la consulta: _cgiargq_)}
+_textnoquerytitle_ [l=es] {PÃ¡gina de bÃºsqueda}
+
+_texticonthispage_ [l=es] {buscar}
+_textsome_ [l=es] {algunas de}
+_textall_ [l=es] {todas}
+_textboolean_ [l=es] {booleano}
+_textranked_ [l=es] {clasificado}
+_textnatural_ [l=es] {natural}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=es] {}
+_texticonsearchhistorybar_ [l=es] {historial de bÃºsquedas}
+
+_textifeellucky_ [l=es] {Voy a tener suerte!}
+
+#alt text for query buttons
+_textusequery_ [l=es] {utilizar esta consulta}
+_textfreqmsg1_ [l=es] {Palabras contadas: }
+_textpostprocess_ [l=es] {_If_(_quotedquery_,<br><i>postprocesado para encontrar _quotedquery_</i>
+)}
+_textinvalidquery_ [l=es] {La sintaxis de la consulta no es vÃ¡lida}
+
+_textmorethan_ [l=es] {MÃ¡s que}
+_textapprox_ [l=es] {Acerca de }
+_textnodocs_ [l=es] {No hay documentos que correspondan a la consulta.}
+_text1doc_ [l=es] {1 documento corresponde a la consulta.}
+_textlotsdocs_ [l=es] {documentos corresponden a la consulta.}
+_textmatches_ [l=es] {Resultados }
+_textbeginsearch_ [l=es] {Iniciar la bÃºsqueda}
+_textrunquery_ [l=es] {Ejecutar la bÃºsqueda}
+_textclearform_ [l=es] {Borrar el formulario}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=es] {Palabra o frase}
+_textinfield_ [l=es] {... en el campo}
+_textfoldstem_ [l=es] {(mayÃºsculas y minÃºsculas, terminaciones de palabras)}
+
+_textadvquery_ [l=es] {O teclee directamente una consulta:}
+_textallfields_ [l=es] {todos los campos}
+_texttextonly_ [l=es] {sÃ³lo texto
+}
+_textand_ [l=es] {y}
+_textor_ [l=es] {o}
+_textandnot_ [l=es] {y no}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=es] {Buscar _indexselection_ _If_(_jselection_,of _jselection_ )_If_(_gselection_, at _gselection_ level )_If_(_nselection_,in _nselection_ language ) que contengan _querytypeselection_ de las palabras
+}
+
+_textadvancedsearch_ [l=es] {Buscar _indexselection_ _If_(_jselection_, de _jselection_) _If_(_gselection_, at _gselection_ level) _If_(_nselection_, en idioma _nselection_) utilizando la consulta _querytypeselection_}
+
+_textformsimplesearch_ [l=es] {Buscar _If_(_jselection_, _jselection_) _If_(_gformselection_, at _gformselection_
+level) _If_(_nselection_, in _nselection_ language) que contengan
+_formquerytypeselection_ de}
+
+_textformadvancedsearch_ [l=es] {Buscar _If_(_jselection_,_jselection_) _If_(_gformselection_,
+at _gformselection_ level)_If_(_nselection_, in _nselection_ language) y
+ presentar los resultados por orden _formquerytypeselection_ }
+
+
+_textnojsformwarning_ [l=es] {Advertencia: Javascript no estÃ¡ habilitado en su navegador. <br>Para usar la bÃºsqueda de formas, por favor habilÃ­telo.}
+_textdatesearch_ [l=es] {<p>Se pueden buscar en esta colecciÃ³n
+documentos comprendidos en un intervalo de fechas, o documentos que
+contengan una fecha en particular. Ãsta es una caracterÃ­stica
+facultativa de la bÃºsqueda.}
+_textstartdate_ [l=es] {Fecha inicial (o Ãºnica):}
+_textenddate_ [l=es] {Fecha final:}
+_textbc_ [l=es] {antes de nuestra era}
+_textad_ [l=es] {de nuestra era}
+_textexplaineras_ [l=es] {Â«de nuestra eraÂ» y Â«antes de nuestra eraÂ» son
+formas alternativas de expresar Â«despuÃ©s de JesucristoÂ» y Â«antes de
+JesucristoÂ», respectivamente. Son expresiones con menos connotaciones
+culturales.}
+
+_textstemon_ [l=es] {(ignorar las terminaciones de las palabras)}
+
+_textsearchhistory_ [l=es] {historial de bÃºsquedas}
+
+#text macros for search history
+_textnohistory_ [l=es] {No estÃ¡ disponible el historial de bÃºsquedas
+}
+_texthresult_ [l=es] {resultado}
+_texthresults_ [l=es] {resultados}
+_texthallwords_ [l=es] {todas las palabras}
+_texthsomewords_ [l=es] {algunas palabras}
+_texthboolean_ [l=es] {booleano}
+_texthranked_ [l=es] {clasificado}
+_texthcaseon_ [l=es] {tener en cuenta mayÃºsculas y minÃºsculas}
+_texthcaseoff_ [l=es] {no tener en cuenta mayÃºsculas y minÃºsculas}
+_texthstemon_ [l=es] {no tener en cuenta las terminaciones de las palabras}
+_texthstemoff_ [l=es] {tener en cuenta las terminaciones de las palabras}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "buscar" ## green_title ## h_search ##
+_httpiconhsearch_ [l=es] {_httpimg_/es/h\_search.gif}
+_widthhsearch_ [l=es] {200}
+_heighthsearch_ [l=es] {57}
+
+## "resultados" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=es] {_httpimg_/es/qryresb.gif}
+_widthqryresb_ [l=es] {_pagewidth_}
+_heightqryresb_ [l=es] {17}
+
+## "historial" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=es] {_httpimg_/es/schhistb.gif}
+_widthsrchhistb_ [l=es] {_pagewidth_}
+_heightsrchhistb_ [l=es] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=es] {Las preferencias se han fijado de la siguiente manera. Â¡No pulse el
+botÃ³n Â«AtrÃ¡sÂ» de su navegador, pues eso harÃ­a que no quedaran grabadas!
+Utilice mÃ¡s bien uno de los botones de la barra de acceso que aparece
+mÃ¡s arriba.
+
+}
+_textsetprefs_ [l=es] {fijar preferencias}
+_textsearchprefs_ [l=es] {Preferencias de bÃºsqueda}
+_textcollectionprefs_ [l=es] {Preferencias de colecciÃ³n}
+_textpresentationprefs_ [l=es] {Preferencias de presentaciÃ³n}
+_textpreferences_ [l=es] {Preferencias}
+_textcasediffs_ [l=es] {Reconocimiento de mayÃºsculas y minÃºsculas:}
+_textignorecase_ [l=es] {ignorar diferencias entre mayÃºsculas y minÃºsculas}
+_textmatchcase_ [l=es] {deben corresponder mayÃºsculas y minÃºsculas}
+_textwordends_ [l=es] {Terminaciones de las palabras:}
+_textstem_ [l=es] {ignorar las terminaciones de las palabras}
+_textnostem_ [l=es] {debe corresponder la palabra completa}
+_textprefop_ [l=es] {Presentar hasta _maxdocoption_ resultados con _hitsperpageoption_ resultados por pÃ¡gina.}
+_textextlink_ [l=es] {Acceder a pÃ¡ginas Web externas: }
+_textintlink_ [l=es] {Documentos fuente recuperados de:}
+_textlanguage_ [l=es] {Idioma de la interfaz: }
+_textencoding_ [l=es] {CodificaciÃ³n: }
+_textformat_ [l=es] {Formato de la interfaz: }
+_textall_ [l=es] {todos}
+_textquerymode_ [l=es] {Tipo de bÃºsqueda:}
+_textsimplemode_ [l=es] {bÃºsqueda simple}
+_textadvancedmode_ [l=es] {bÃºsqueda avanzada (permite efectuar bÃºsquedas booleanas utilizando los caracteres !, &amp;, | y los parÃ©ntesis)}
+_textlinkinterm_ [l=es] {a travÃ©s de una pÃ¡gina intermedia}
+_textlinkdirect_ [l=es] {ir directamente ahÃ­}
+_textdigitlib_ [l=es] {la biblioteca digital}
+_textweb_ [l=es] {la red mundial (web)}
+_textgraphical_ [l=es] {GrÃ¡fico}
+_texttextual_ [l=es] {Textual}
+_textcollectionoption_ [l=es] {<p>
+Subcolecciones por incluir:
+<br>}
+
+_textrelateddocdisplay_ [l=es] {mostrar documentos conexos }
+_textsearchhistory_ [l=es] {historial de bÃºsquedas:}
+_textnohistory_ [l=es] {el historial de bÃºsquedas no estÃ¡ disponible }
+_texthistorydisplay_ [l=es] {mostrar _historynumrecords_ historial de las Ãºltimas bÃºsquedas}
+_textnohistorydisplay_ [l=es] {no mostrar el historial de bÃºsquedas }
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=es] {BÃºsqueda de formas:}
+_textplainsearch_ [l=es] {BÃºsqueda sencilla de sÃ³lo texto:}
+_textqueryboxsize_ [l=es] {TamaÃ±o del cuadro de bÃºsqueda:}
+_textregbox_ [l=es] {cuadro de bÃºsqueda normal}
+_textbigbox_ [l=es] {cuadro de bÃºsqueda grande}
+_textformtype_ [l=es] {Tipo de formulario:}
+_textsimple_ [l=es] {simple}
+_textadvanced_ [l=es] {avanzado}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=es] {con}
+_textfields_ [l=es] {campos}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "preferencias" ## green_title ## h_pref ##
+_httpiconhpref_ [l=es] {_httpimg_/es/h\_pref.gif}
+_widthhpref_ [l=es] {200}
+_heighthpref_ [l=es] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=es] {Ordenar los documentos por}
+_textalsoshowing_ [l=es] {muestra tambiÃ©n}
+_textwith_ [l=es] {con un mÃ¡ximo de}
+_textdocsperpage_ [l=es] {documentos por pÃ¡gina}
+
+_textfilterby_ [l=es] {Buscar documentos que contengan}
+_textall_ [l=es] {todas}
+_textany_ [l=es] {algunas de}
+_textwords_ [l=es] {las palabras}
+_textleaveblank_ [l=es] {dejar este cuadro vacÃ­o para obtener todos los documentos}
+
+_browsebuttontext_ [l=es] {"Ordenar los documentos"}
+
+_nodata_ [l=es] {<i>no datos</i>}
+_docs_ [l=es] {documentos}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=es] {Ayuda}
+_textSearchshort_ [l=es] {Buscar determinadas palabras}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=es] {Acceder a las publicaciones por tÃ­tulo}
+_textCreatorshort_ [l=es] {Acceder a las publicaciones por creador}
+_textSubjectshort_ [l=es] {Acceder a las publicaciones por tema}
+_textDescriptionshort_ [l=es] {accede a las publicaciones por descripciÃ³n}
+_textPublishershort_ [l=es] {accede a las publicaciones por editor}
+_textContributorshort_ [l=es] {accede a las publicaciones por colaborador}
+_textDateshort_ [l=es] {Acceder a las publicaciones por fecha}
+_textTypeshort_ [l=es] {accede a las publicaciones por tipo}
+_textFormatshort_ [l=es] {accede a las publicaciones por formato}
+_textIdentifiershort_ [l=es] {accede a las publicaciones por identificador}
+_textSourceshort_ [l=es] {Acceder a las publicaciones por fuente}
+_textLanguageshort_ [l=es] {Acceder a las publicaciones por idioma}
+_textRelationshort_ [l=es] {acceder a las publicaciones por relaciÃ³n}
+_textCoverageshort_ [l=es] {accede a las publicaciones por cobertura}
+_textRightsshort_ [l=es] {acceder a las publicaciones por derechos}
+
+_textSeriesshort_ [l=es] {Acceder a las publicaciones por series}
+_textToshort_ [l=es] {Acceder a las publicaciones por campo Â«AÂ»}
+_textFromshort_ [l=es] {Acceder a las publicaciones por campo Â«DeÂ»}
+_textBrowseshort_ [l=es] {Navegar en las publicaciones}
+_textOrganizationshort_ [l=es] {Acceder a las publicaciones por organizaciÃ³n}
+_textHowtoshort_ [l=es] {Acceder a las publicaciones por lista de "cÃ³mo"}
+_textTopicshort_ [l=es] {Acceder a las publicaciones por tema}
+_textPeopleshort_ [l=es] {Acceder a las publicaciones por personas}
+_textAcronymshort_ [l=es] {Acceder a las publicaciones por apariciÃ³n de siglas}
+_textPhraseshort_ [l=es] {Navegar en las frases que aparecen en las publicaciones}
+_textArtistshort_ [l=es] {Acceder a las publicaciones por artista}
+_textKeywordshort_ [l=es] {Acceder a las publicaciones por palabra clave}
+_textVolumeshort_ [l=es] {Acceder a las publicaciones por volumen}
+_textCountriesshort_ [l=es] {obtener publicaciones por paÃ­s}
+_textdefaultshorttext_ [l=es] {clasificaciÃ³n indefinida}
+
+_textSearchlong_ [l=es] {<p>Se puede <i>buscar determinadas
+palabras</i> que aparecen en el texto desde la pÃ¡gina de "bÃºsqueda". Ãsta
+es la primera pÃ¡gina que aparece al principio y a la que se puede
+acceder desde otras pÃ¡ginas pulsando el botÃ³n <i>buscar</i>. }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+tÃ­tulo</i> pulsando el botÃ³n <i>tÃ­tulos a-z</i>. El resultado serÃ¡ una
+lista de libros por orden alfabÃ©tico. }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=es] {<p>Se puede <i>acceder a publicaciones por
+creador</i> pulsando el botÃ³n <i>creadores a-z</i>. El resultado serÃ¡ una
+lista de libros ordenados por nombre del autor. }
+
+_textSubjectlong_ [l=es] {<p>Se puede <i>acceder a las publicaciones
+por tema</i> presionando el botÃ³n de <i>temas</i>. El resultado serÃ¡ una
+lista de temas, representados por libreros. }
+
+_textDescriptionlong_ [l=es] {<p> Puede <i>acceder a las publicaciones por descripciÃ³n</i> pulsando el botÃ³n <i>descripciÃ³nes</i>. Muestra una lista de descripciones.}
+
+_textPublisherlong_ [l=es] {<p> Puede <i>acceder a las publicaciones por editor</i> pulsando el botÃ³n <i>editores</i>. Muestra una lista de editores.}
+
+_textContributorlong_ [l=es] {<p> Puede <i>acceder a las publicaciones por colaborador</i> pulsando el botÃ³n <i>colaboradores</i>. Muestra una lista de colaboradores.}
+
+_textDatelong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+fecha</i> pulsando el botÃ³n <i>fechas</i>. El resultado serÃ¡ una lista
+de todas las publicaciones, ordenadas cronolÃ³gicamente. }
+
+_textTypelong_ [l=es] {<p> Puede <i>acceder a las publicaciones por tipo</i> pulsando el botÃ³n <i>tipos</i>. Muestra una lista de tipos.}
+
+_textFormatlong_ [l=es] {<p> Puede <i>acceder a las publicaciones por formato</i> pulsando el botÃ³n <i>formatos</i>. Muestra una lista de formatos.}
+
+_textIdentifierlong_ [l=es] {<p> Puede <i>acceder a las publicaciones por identificador</i> pulsando el botÃ³n <i>identificadores</i>. Muestra una lista de identificadores.}
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+fuente</i> pulsando el botÃ³n <i>fuente</i>. El
+resultado serÃ¡ una lista ordenada por nombre de fichero original. }
+
+_textLanguagelong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+idioma</i> presionando el botÃ³n <i>idiomas</i>. El resultado serÃ¡ una
+lista ordenada por lengua. }
+
+_textRelationlong_ [l=es] {<p> Puede <i>acceder a las publicaciones por relaciÃ³n</i> pulsando el botÃ³n <i>relaciÃ³nes</i>. Muestra una lista de relaciones.}
+
+_textCoveragelong_ [l=es] {<p> Puede <i>acceder a las publicaciones por cobertura</i> pulsando el botÃ³n <i>coberturas</i>. Muestra una lista de coberturas.}
+
+_textRightslong_ [l=es] {<p> Puede <i>acceder a las publicaciones por derechos</i> pulsando el botÃ³n <i>derechos</i>.}
+
+
+
+_textOrganizationlong_ [l=es] {<p>Se puede <i>acceder a las publicaciones
+por organizaciÃ³n</i> pulsando el botÃ³n <i>organizaciÃ³n</i>. El resultado
+serÃ¡ una lista de organizaciones. }
+
+_textHowtolong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por una
+lista de "cÃ³mo"</i> pulsando el botÃ³n <i>cÃ³mo</i>.
+El resultado serÃ¡ una lista de categorÃ­as "cÃ³mo". }
+
+_textTopiclong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+tema</i> pulsando el botÃ³n <i>tema</i>. El resultado serÃ¡ una lista de
+temas. }
+
+_textTolong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+campo Â«AÂ»</i> pulsando el botÃ³n <i>a</i>. El resultado serÃ¡ una lista de
+destinatarios. }
+
+_textFromlong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+campo Â«DeÂ»</i> pulsando el botÃ³n <i>de</i>. El resultado serÃ¡ una lista
+de remitentes. }
+
+_textSerieslong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+series</i> pulsando el botÃ³n <i>series</i>. El resultado serÃ¡ una lista
+de las series que se encuentran en la colecciÃ³n. }
+
+_textBrowselong_ [l=es] {<p>Se puede <i>navegar en las publicaciones</i>
+pulsando el botÃ³n <i>navegar</i>. }
+
+_textPeoplelong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+personas</i> pulsando el botÃ³n <i>personas a-z</i>. El resultado serÃ¡ una
+lista ordenada por apellido. }
+
+_textAcronymlong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+apariciÃ³n de siglas</i> pulsando el botÃ³n <i>siglas</i>. El resultado
+serÃ¡ una lista de siglas y los lugares donde aparecen. }
+
+_textPhraselong_ [l=es] {<p>Se puede <i>navegar en las frases que aparecen
+en las publicaciones</i> pulsando el botÃ³n <i>frases</i>. Para ello se
+utiliza el navegador "phind phrase". }
+
+_textArtistlong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+artista</i> pulsando el botÃ³n <i>artistas</i>. El resultado serÃ¡ una
+lista ordenada por nombre de artista. }
+
+_textKeywordlong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+palabra clave</i> pulsando el botÃ³n <i>palabras clave</i>. El resultado
+serÃ¡ una lista de palabras clave. }
+
+_textVolumelong_ [l=es] {<p>Se puede <i>acceder a las publicaciones por
+volumen</i> pulsando el botÃ³n <i>volÃºmenes</i>. El resultado
+serÃ¡ una lista de volÃºmenes. }
+
+_textCaptionslong_ [l=es] {<p>Usted puede <i>tener acceso a los titulares de una publicaciÃ³n</i> haciendo click en el botÃ³n <i>titulares</i>. Esto le mostrarÃ¡ una lista de titulares. }
+
+_textCountrieslong_ [l=es] {<p>Usted puede <i>tener acceso a las publicaciones de cada paÃ­s</i> haciendo click en el botÃ³n <i>paÃ­ses</i>. Esto le mostrarÃ¡ una lista de paÃ­ses. }
+
+
+_textdefaultlongtext_ [l=es] {<p>Haga click en el botÃ³n <i>desconocido</i> para explorar las publicaciones 
+(el listado se organiza por medio de un campo desconocido).}
+
+_texthelptopics_ [l=es] {<h2 align=left>Temas</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Â¿CÃ³mo buscar determinadas palabras?</a>
+<ul>
+  <li><a href="\#query-terms">TÃ©rminos de la bÃºsqueda</a>
+  <li><a href="\#query-type">Tipo de consulta</a>
+  <li><a href="\#scope-of-queries">Campo de acciÃ³n de las bÃºsquedas</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Preferencias de colecciÃ³n</a>
+  <li><a href="\#lang-prefs">Preferencias de lengua</a>
+  <li><a href="\#pres-prefs">Preferencias de presentaciÃ³n</a>
+  <li><a href="\#search-prefs">Preferencias de bÃºsqueda</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=es] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=es] {Â¿CÃ³mo leer los documentos?}
+
+_texthelpreadingdocs_ [l=es] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Se puede decir que se ha localizado un libro o documento en particular cuando su tÃ­tulo o una fotografÃ­a de la portada aparece en la parte superior izquierda de la pÃ¡gina. En algunas colecciones esto se acompaÃ±a de una tabla de contenidos, mientras que otras contienen sÃ³lo el nÃºmero de la pÃ¡gina actual junto con un cuadro que le permite seleccionar una nueva pÃ¡gina y avanzar o retroceder. En la tabla de contenidos el encabezado de la secciÃ³n actual aparece en negritas y la tabla se puede extender. Haga click en las carpetas para abrirlas o cerrarlas. Haga click en la parte superior del libro abierto para cerrarlo.</p>
+
+<p>Debajo aparece el texto de la secciÃ³n actual. Al final de la lectura hay flechas en la parte inferior que lo llevarÃ¡n a la siguiente secciÃ³n o a la anterior.</p>
+
+<p>Abajo del tÃ­tulo o de la imagen de la portada hay algunos botones. Haga click en <i>texto completo</i> para abrir todo el texto de la secciÃ³n o libro actual. Â¡Si el documento es demasiado grande esto podrÃ­a llevar mucho tiempo y ocupar una gran cantidad de memoria! Haga click en <i>mostrar contenido</i> para que aparezca en pantalla toda la tabla de contenidos de tal manera que usted pueda ver el tÃ­tulo de todos los capÃ­tulos y secciones. Haga click en <i>separar</i> para abrir una nueva ventana para este documento (esto es particularmente Ãºtil si desea comparar documentos o leer dos a la vez). Por Ãºltimo, cuando se efectÃºa una bÃºsqueda las palabras que usted estÃ¡ buscando aparecen resaltadas. Haga click en <i>sin resaltar</i> para  que ya no aparezcan resaltadas.</p>
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Abrir este estante</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Abrir/cerrar este libro</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>Ver esta parte del texto</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Mostrar/No mostrar el texto completo</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Mostrar/No mostrar la tabla de contenidos</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Abrir esta pÃ¡gina en una nueva ventana</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Resaltar/No resaltar los tÃ©rminos de la bÃºsqueda</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Haga click en esta flecha para pasar a la siguiente secciÃ³n ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... o para regresar a la secciÃ³n anterior</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=es] {<h2>Â¿CÃ³mo buscar determinadas palabras?</h2>
+
+<p>Desde la pÃ¡gina de bÃºsqueda, se puede hacer una consulta siguiendo
+estos pasos:
+
+<ol>
+
+<li>Especificar quÃ© documentos quiere buscar
+
+<li>Indicar si quiere buscar todas las palabras o sÃ³lo algunas
+
+<li>Escribir las palabras que quiere buscar
+
+<li>Pulsar el botÃ³n <i>Iniciar la bÃºsqueda</i>
+
+</ol> 
+
+<p>Cuando se hace una consulta, aparecen los tÃ­tulos de los veinte
+primeros documentos correspondientes. Al final de la lista hay un botÃ³n
+que permite acceder a los veinte documentos siguientes, y asÃ­
+sucesivamente. Pulse el tÃ­tulo de cualquier documento o el botoncito que
+aparece al lado para verlo.
+
+<p>El nÃºmero mÃ¡ximo de documentos obtenidos es de 100. Puede cambiar
+este nÃºmero pulsando el botÃ³n <i>preferencias</i> que se encuentra en la
+parte superior de la pÃ¡gina.
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>TÃ©rminos de la bÃºsqueda</h3>
+
+<p>Lo que se teclea en el cuadro de consulta se interpreta como una
+lista de palabras llamadas "tÃ©rminos de la bÃºsqueda". Cada tÃ©rmino debe
+contener solamente letras y dÃ­gitos. Los tÃ©rminos se separan por un
+espacio en blanco. Si aparecen otros caracteres, como los de puntuaciÃ³n,
+se interpretan como espacios para separar los tÃ©rminos y la bÃºsqueda no
+los tiene en cuenta. No se pueden efectuar bÃºsquedas con palabras que
+incluyan puntuaciÃ³n.
+
+<p>Por ejemplo, la consulta:
+
+<ul><kbd>Agro-forestry in the Pacific Islands: Systems for
+Sustainability (1993)</kbd></ul>
+
+<p>se tratarÃ¡ de igual manera que:
+
+<ul><kbd>Agro forestry in the Pacific Islands Systems for Sustainability
+1993</kbd></ul><p>
+      
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Tipo de consulta</h3>
+
+<p>Existen dos tipos de consulta.
+
+<ul>
+
+<li>BÃºsqueda de <b>todas</b> las palabras. Se buscan los documentos que
+contienen todas las palabras especificadas. Los documentos que responden
+a la consulta se presentan por orden alfabÃ©tico.
+
+<li>BÃºsqueda de <b>determinada(s)</b> palabra(s). Basta con enumerar los
+tÃ©rminos que pueden aparecer en los documentos buscados. Los documentos
+aparecerÃ¡n en un orden que corresponde a su grado de pertinencia con
+respecto a la consulta. Para determinar el grado de pertinencia, se
+aplican los criterios siguientes:
+
+<ul>
+
+<li>cuantos mÃ¡s tÃ©rminos buscados contenga el documento, mayor serÃ¡ su
+pertinencia;
+
+<li>los tÃ©rminos poco usuales se considerarÃ¡n mÃ¡s importantes que los
+comunes;
+
+<li>los documentos mÃ¡s cortos se considerarÃ¡n mÃ¡s pertinentes que los
+documentos mÃ¡s voluminosos.
+
+</ul>
+
+</ul>
+
+<p>Puede utilizar tantos tÃ©rminos de bÃºsqueda como desee: una oraciÃ³n
+completa, o incluso un pÃ¡rrafo entero.  Si sÃ³lo se especifica un
+tÃ©rmino, los documentos se ordenarÃ¡n por frecuencia de apariciÃ³n del
+tÃ©rmino buscado.
+
+<p>_texthelpscope_
+
+}
+
+_textdatesearch_ [l=es] {Buscar con fechas}
+
+_texthelpdatesearch_ [l=es] {<h2>_textdatesearch_</h2>
+La bÃºsqueda por fecha le permite encontrar documentos que, ademÃ¡s de corresponder a los criterios de bÃºsqueda, se refieren a acontecimientos situados dentro de un intervalo de tiempo determinado. Se pueden buscar documentos relativos a un aÃ±o en particular o comprendidos dentro de un nÃºmero determinado de aÃ±os. Recuerde que no es estrictamente necesario proporcionar tÃ©rminos de bÃºsqueda, sino que tambiÃ©n se puede buscar Ãºnicamente por fecha. Tampoco es preciso indicar las fechas de la bÃºsqueda: si no escribe ninguna fecha es como si no existiera la bÃºsqueda por fecha.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>CÃ³mo utilizar esta funciÃ³n:</h3>
+<ul>
+   <li>Para buscar documentos referentes a un aÃ±o en particular:<p>
+   <ul>
+       <li>Escriba los tÃ©rminos de la bÃºsqueda como de costumbre.
+       <li>Escriba el aÃ±o en el cuadro "Fecha inicial (o Ãºnica)".
+       <li>Si la fecha es anterior a nuestra era (antes de Cristo),  
+           elija la opciÃ³n "a.C." en el menÃº situado a un lado de ese cuadro.
+       <li>Inicie la bÃºsqueda como de costumbre.
+   </ul>
+<p><li>Para buscar documentos referentes a un periodo de tiempo o un nÃºmero de aÃ±os en particular:<p>
+   <ul>
+       <li>Escriba los tÃ©rminos de la bÃºsqueda como de costumbre.
+       <li>Escriba la fecha anterior en el cuadro "Fecha inicial (o Ãºnica)".
+       <li>Escriba la fecha posterior en el cuadro "Fecha final".
+       <li>Seleccione la opciÃ³n "a.C." en el menÃº situado a un lado del cuadro donde  
+           se haya escrito cualquier fecha anterior a nuestra era (antes de Cristo).
+       <li>Inicie la bÃºsqueda como de costumbre.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>Como interpretar los resultados de su bÃºsqueda</h3>
+
+Por lo general una bÃºsqueda de documentos referentes al aÃ±o 1903 no permitirÃ¡ obtener documentos que, por ejemplo, tratan de libros escritos en 1903, sino sÃ³lo documentos referentes al aÃ±o 1903.  Sin embargo, dada la manera en que se buscan las fechas de los documentos, se obtendrÃ¡n documentos referentes a un intervalo de tiempo (por ejemplo 1899-1911) que comprenda el aÃ±o 1903, asÃ­ como los documentos que citan en su texto el siglo al que pertenece el aÃ±o 1903 (por ejemplo siglo XX o siglo veinte).  Esto significa que para algunos documentos las fechas indicadas en la bÃºsqueda no aparecerÃ¡n realmente en el texto del documento. En el caso de una bÃºsqueda por intervalo de tiempo, todo lo anterior se aplica a cada fecha del intervalo.<p>
+}
+
+_textchangeprefs_ [l=es] {Cambio de preferencias}
+
+_texthelppreferences_ [l=es] {<h2>_textchangeprefs_</h2>
+
+<p>Si desea cambiar algunas caracterÃ­sticas de la interfaz para
+adaptarla a sus propias necesidades, pulse el botÃ³n <i>preferencias</i>,
+situado en la parte superior de la pÃ¡gina.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Preferencias de colecciÃ³n</h3>
+<p>
+Algunas colecciones se componen de varias subcolecciones, en las cuales
+se pueden efectuar operaciones de bÃºsqueda de forma individual o en su
+conjunto, como un todo. Si lo desea, puede usted seleccionar en la
+pÃ¡gina de <i>preferencias</i> quÃ© subcolecciones incluir en sus
+bÃºsquedas.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Preferencias de lengua</h3>
+
+<p>Cada colecciÃ³n tiene una lengua de presentaciÃ³n por defecto, pero si
+lo desea puede usted cambiar de idioma. Puede usted modificar tambiÃ©n el
+sistema de codificaciÃ³n que utiliza su navegador: el programa Greenstone
+suele escoger los parÃ¡metros por defecto, pero con algunos navegadores
+se pueden conseguir mejores resultados grÃ¡ficos cambiando de sistema de
+codificaciÃ³n. En todas las colecciones se puede escoger entre una
+interfaz grÃ¡fica normalizada y una interfaz textual. Ãsta resulta
+particularmente Ãºtil para los usuarios con problemas de vista que
+utilizan tipos de letra grandes o para la salida a sintetizadores
+de voz.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Preferencias de presentaciÃ³n</h3>
+
+<p>SegÃºn la colecciÃ³n, se pueden especificar varias opciones que definen
+la presentaciÃ³n.
+
+<p>Las colecciones de pÃ¡ginas Web permiten eliminar la barra de
+navegaciÃ³n de Greenstone que aparece en la parte superior de cada pÃ¡gina
+de un documento, de tal modo que una vez terminada la bÃºsqueda se
+visualiza directamente la pÃ¡gina correspondiente sin los encabezados de
+Greenstone. Para efectuar otra bÃºsqueda tendrÃ¡ que utilizar el botÃ³n
+"AtrÃ¡s" de su navegador. Estas colecciones le permiten tambiÃ©n eliminar
+el mensaje de advertencia de Greenstone que aparece cuando un
+hipervÃ­nculo lo lleva a usted fuera de la colecciÃ³n de la biblioteca
+digital y hacia otra parte en Internet. En algunas colecciones de
+pÃ¡ginas Web, se puede determinar tambiÃ©n si los enlaces que aparecen en
+la pÃ¡gina de "Resultados de la bÃºsqueda" remitirÃ¡n directamente al URL
+en cuestiÃ³n o mÃ¡s bien a la copia de la pÃ¡gina que se encuentra en la
+biblioteca digital.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Preferencias de bÃºsqueda</h3>
+
+Dos pares de botones controlan la diferencia entre mayÃºsculas y
+minÃºsculas y las raÃ­ces de las bÃºsquedas que hace. El primer conjunto de
+botones controla si deben coincidir mayÃºsculas o minÃºsculas. El segundo
+conjunto controla si se ignoran o no las terminaciones de las palabras
+(raÃ­ces).
+
+<p>Por ejemplo, si se activan los botones <i>ignorar diferencias entre
+mayÃºsculas y minÃºsculas</i> e <i>ignorar terminaciones de palabras</i>,
+la bÃºsqueda:
+
+<p><ul><kbd>African building</kbd></ul>
+
+<p>se tratarÃ¡ del mismo modo que:
+
+<p><ul><kbd>africa builds</kbd></ul>
+
+<p>porque la letra mayÃºscula de "African" se transformarÃ¡ en minÃºscula y
+los sufijos "n" e "ing" se eliminaran de "African" y "building",
+respectivamente (se suprimirÃ¡ tambiÃ©n la "s" de "builds").
+
+<p>Se puede tambiÃ©n optar por el modo de bÃºsqueda "avanzado" que permite
+combinar tÃ©rminos utilizando los operadores booleanos AND (&amp;), OR
+(|), y NOT (!). Esto le permitirÃ¡ efectuar bÃºsquedas mÃ¡s precisas. Se
+puede activar el historial de bÃºsquedas, en el que aparecen las Ãºltimas
+bÃºsquedas efectuadas. Esto facilita la repeticiÃ³n de versiones levemente
+modificadas de bÃºsquedas anteriores.
+
+<p>Por Ãºltimo, se puede controlar el nÃºmero de aciertos obtenidos y su
+presentaciÃ³n en pantalla.
+
+}
+
+_texttanumbrowseoptions_ [l=es] {Existen _numbrowseoptions_ manera(s) de encontrar informaciÃ³n en esta colecciÃ³n:}
+
+_textsimplehelpheading_ [l=es] {Â¿CÃ³mo encontrar informaciÃ³n?}
+
+_texthelpscope_ [l=es] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Campo de acciÃ³n de las bÃºsquedas</h3> 
+
+<p>En la mayorÃ­a de las colecciones puede usted escoger diferentes
+Ã­ndices para la bÃºsqueda. Por ejemplo, puede haber Ã­ndices por autor o
+por tÃ­tulo. TambiÃ©n puede haber Ã­ndices por capÃ­tulo o por pÃ¡rrafo. Por
+lo general, se obtiene el documento correspondiente cualquiera que sea
+el Ã­ndice utilizado.
+
+<p>Si los documentos son libros, Ã©stos aparecerÃ¡n en el lugar
+predefinido.
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/spanish2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/spanish2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/spanish2.dm	(revision 10506)
@@ -0,0 +1,1336 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Spanish Language text and icon macros 
+# -- this file contains text that is of less importance
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=es] {documentos. }
+_lastupdate_ [l=es] {Ãltima actualizaciÃ³n }
+_ago_ [l=es] {dÃ­as.}
+_colnotbuilt_ [l=es] {ColecciÃ³n no creada.}
+
+_textpagetitle_ [l=es] {Biblioteca Digital Greenstone}
+_textadmin_ [l=es] {PÃ¡gina de administraciÃ³n}
+_textabgs_ [l=es] {Acerca de Greenstone}
+_textgsdocs_ [l=es] {DocumentaciÃ³n de Greenstone}
+
+_textimagegli_ [l=es] {Le ayuda a crear nuevas colecciones, modificar o suprimir colecciones
+existentes, o aÃ±adir documentos a una colecciÃ³n.
+}
+
+_textimagecollector_ [l=es] {Aunque este programa de recopilaciÃ³n antecede a la interfaz de la biblioteca digital, para fines prÃ¡cticos se recomienda usar esta Ãºltima en lugar del Colector. }
+
+_textimagetranslator_ [l=es] {Le ayuda a mantener actualizadas las versiones en varias lenguas de la interfaz Greenstone.}
+
+_textimageadmin_ [l=es] {Le permite aÃ±adir nuevos usuarios, da un resumen de las colecciones que
+hay en el sistema y proporciona informaciones tÃ©cnicas sobre la
+instalaciÃ³n de Greenstone
+}
+
+_textimagegogreenstone_ [l=es] {Le proporciona informaciÃ³n sobre el software Greenstone y el proyecto de
+Biblioteca Digital de Nueva Zelandia, de donde proviene
+}
+
+_textimagegodocs_ [l=es] {Manuales de Greenstone}
+
+_textpoem_ [l=es] {<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+
+<p>que la paz y la tranquilidad te rodeen,
+<br>que vivas en el calor de una calina estival,
+<br>que el ocÃ©ano de tus viajes sea tan terso como la piedra verde
+pulida.
+
+}
+
+_textgreenstone_ [l=es] {<p>Greenstone (piedra verde) es una piedra semipreciosa que, como este
+programa informÃ¡tico, proviene de Nueva Zelandia. En la sociedad maorÃ­
+tradicional era la materia mÃ¡s apreciada y buscada. Esta piedra tiene el
+poder de absorber y encerrar el <i>wairua</i>, que es el espÃ­ritu de la
+fuerza de vida, y estÃ¡ dotada de virtudes tradicionales que hacen de
+ella un emblema muy apropiado para un proyecto de biblioteca digital
+de dominio pÃºblico. Su lustre simboliza la caridad; su transparencia, la
+honradez; su dureza, el coraje, y el filo que puede cobrar, la justicia.
+El objeto tallado utilizado como emblema del programa de biblioteca
+digital de Greenstone es un <i>patu</i>, una especie de maza. Esta
+arma de combate es una reliquia de la familia de uno de los miembros de
+nuestro proyecto. En el combate cuerpo a cuerpo, su lanzamiento podÃ­a
+ser de una rapidez y una precisiÃ³n fenomenal; esto lo convertÃ­a en un
+arma temible y completa. QuisiÃ©ramos que esas cualidades fueran tambiÃ©n
+las de este programa informÃ¡tico y que el afilado borde del <i>patu</i>
+simbolizara el aspecto avanzado y de vanguardia de la tecnologÃ­a.
+
+}
+
+_textaboutgreenstone_ [l=es] {<p>Greenstone es un conjunto de programas informÃ¡ticos destinado a la
+creaciÃ³n y difusiÃ³n de colecciones documentales electrÃ³nicas que ofrece
+un nuevo procedimiento para organizar la informaciÃ³n y publicarla en
+Internet o en forma de CD-ROM. Elaborado dentro del proyecto de
+<b>Biblioteca Digital de Nueva Zelandia</b> de la <b>Universidad de
+Waikato</b>, este producto se distribuye en colaboraciÃ³n con la
+<b>UNESCO</b> y la <b>ONG Human Info</b>. Es un programa informÃ¡tico de
+cÃ³digo fuente abierto (open-source software), que puede descargarse en
+la direcciÃ³n <a href="http://greenstone.org">http://greenstone.org</a>
+segÃºn las condiciones estipuladas en la Licencia PÃºblica General de
+GNU.</b>
+
+<p>La finalidad de este programa es que los usuarios, en particular en
+las universidades, las bibliotecas y otros establecimientos pÃºblicos,
+puedan crear sus propias bibliotecas digitales. Las bibliotecas
+digitales estÃ¡n transformando radicalmente el mÃ©todo de distribuciÃ³n
+y adquisiciÃ³n de conocimientos utilizado por la UNESCO con sus
+interlocutores en las esferas de la educaciÃ³n, la ciencia y la cultura
+en todo el mundo, y particularmente en los paÃ­ses en desarrollo.
+Esperamos que este programa informÃ¡tico contribuya a fomentar la
+creaciÃ³n y difusiÃ³n de bibliotecas digitales a fin de compartir la
+informaciÃ³n y ponerla a disposiciÃ³n del pÃºblico en general.
+
+<p>Este programa se elabora y se distribuye gracias a un esfuerzo de
+colaboraciÃ³n internacional iniciado en agosto de 2000 por tres
+protagonistas:
+
+<table border="0">
+<tr valign="top">
+<td>
+El proyecto de <a href="http://nzdl.org"><b>Biblioteca Digital de
+Nueva Zelandia en la Universidad de Waikato</b></a>
+<br>
+El programa informÃ¡tico de Greenstone empezÃ³ a elaborarse con este
+proyecto y esta iniciativa recibiÃ³ el respaldo de la SubcomisiÃ³n de la
+ComunicaciÃ³n de la ComisiÃ³n Nacional Neozelandesa para la UNESCO, como
+parte de la contribuciÃ³n de Nueva Zelandia al programa de UNESCO.
+</td>
+<td></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://www.unesco.org"><b>OrganizaciÃ³n de las Naciones Unidas
+para la ComunicaciÃ³n, la Ciencia y la Cultura</b></a>
+<br>
+La difusiÃ³n mundial de informaciÃ³n en materia de educaciÃ³n, ciencia y
+cultura , en particular en los paÃ­ses en desarrollo, es uno de los
+cometidos principales del programa intergubernamental de la UNESCO
+"InformaciÃ³n para Todos". Por otra parte, se considera que una
+tecnologÃ­a de la informaciÃ³n y la comunicaciÃ³n apropiada y accesible
+constituye un instrumento esencial a este respecto.
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/unesco.gif"
+border="0"></a></td>
+</tr>
+<tr valign="top">
+<td>
+<a href="http://humaninfo.org"><b>La ONG Human Info, con sede en Amberes,
+BÃ©lgica</b></a>
+<br>
+Este proyecto, impulsado por organismos de
+las Naciones Unidas y otras ONG, se ha forjado una reputaciÃ³n mundial en
+cuanto a la informatizaciÃ³n de documentos relativos al desarrollo humano
+y su difusiÃ³n pÃºblica, en forma gratuita en los paÃ­ses en desarrollo y
+por el precio de costo en los demÃ¡s.
+</td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "seleccionar una colecciÃ³n" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ [l=es] {_httpimg_/es/selcolgr.gif}
+_widthselcolgr_ [l=es] {537}
+_heightselcolgr_ [l=es] {17}
+_altselcolgr_ [l=es] {"Select a collection"}
+
+
+## "Interfaz de la\nBiblioteca Digital\nGreenstone" ## home_page_button ## cgli ##
+_httpiconcgliof_ [l=es] {_httpimg_/es/cgliof.gif}
+_httpiconcglion_ [l=es] {_httpimg_/es/cglion.gif}
+_widthcgli_ [l=es] {100}
+
+## "El Colector" ## home_page_button ## ccol ##
+_httpiconccolof_ [l=es] {_httpimg_/es/ccolof.gif}
+_httpiconccolon_ [l=es] {_httpimg_/es/ccolon.gif}
+_widthccol_ [l=es] {100}
+
+## "El traductor" ## home_page_button ## ctrans ##
+_httpiconctransof_ [l=es] {_httpimg_/es/ctransof.gif}
+_httpiconctranson_ [l=es] {_httpimg_/es/ctranson.gif}
+_widthctrans_ [l=es] {100}
+
+## "PÃ¡gina de\nadministraciÃ³n" ## home_page_button ## cadmin ##
+_httpiconcadminof_ [l=es] {_httpimg_/es/cadminof.gif}
+_httpiconcadminon_ [l=es] {_httpimg_/es/cadminon.gif}
+_widthcadmin_ [l=es] {100}
+
+## "Acerca\nde Greenstone" ## home_page_button ## cabgs ##
+_httpiconcabgsof_ [l=es] {_httpimg_/es/cabgsof.gif}
+_httpiconcabgson_ [l=es] {_httpimg_/es/cabgson.gif}
+_widthcabgs_ [l=es] {100}
+
+## "DocumentaciÃ³n\nde Greenstone" ## home_page_button ## cgsdoc ##
+_httpiconcgsdocof_ [l=es] {_httpimg_/es/cgsdocof.gif}
+_httpiconcgsdocon_ [l=es] {_httpimg_/es/cgsdocon.gif}
+_widthcgsdoc_ [l=es] {100}
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=es] {Hay otros cuatro botones en la pÃ¡gina principal }
+
+_textnocollections_ [l=es] {<p>No hay actualmente ninguna colecciÃ³n disponible para esta instalaciÃ³n
+de Greenstone. Para aÃ±adir colecciones, usted puede:
+
+<ul>
+
+<li>utilizar el Colector para crear nuevas colecciones
+
+<li>o bien instalar colecciones a partir del CD-ROM de Greenstone, si
+dispone de uno
+
+</ul>
+
+}
+
+_text1coll_ [l=es] {Esta instalaciÃ³n de Greenstone contiene 1 colecciÃ³n }
+
+_textmorecolls_ [l=es] {Esta instalaciÃ³n de Greenstone contiene _1_ colecciones }
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=es] {Enlace externo }
+_textlinknotfound_ [l=es] {No se encontrÃ³ el enlace interno }
+
+_textextlinkcontent_ [l=es] {El enlace que usted ha seleccionado es externo a todas las colecciones
+actualmente seleccionadas. Si desea de todos modos activar este enlace y
+si su navegador estÃ¡ conectado a Internet, puede usted <a
+href="_nexturl_">acudir</a> a esta pÃ¡gina; en caso contrario, pulse el
+botÃ³n "AtrÃ¡s" de su navegador para volver al documento anterior.
+
+}
+
+_textlinknotfoundcontent_ [l=es] {El enlace interno que usted seleccionÃ³ no existe. Esto se debe
+probablemente a un error en la colecciÃ³n fuente. Pulse el botÃ³n "AtrÃ¡s"
+de su navegador para volver al documento anterior.
+
+}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=es] {<h3>Enlace con la colecciÃ³n "_2_"</h3>
+
+<p>El enlace que usted ha seleccionado es externo a la colecciÃ³n
+"_collectionname_" (remite a la colecciÃ³n "_2_"). Si desea ver el
+documento que corresponde a este enlace en la colecciÃ³n "_2_", puede
+<a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">acudir</a> a esa pÃ¡gina;
+en caso contrario, pulse el botÃ³n "AtrÃ¡s" de su navegador para volver al
+documento anterior.
+
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=es] {Biblioteca Digital Greenstone }
+
+_textusername_ [l=es] {nombre de usuario}
+_textpassword_ [l=es] {contraseÃ±a}
+
+_textmustbelongtogroup_ [l=es] {Se advierte que para acceder a esta pÃ¡gina usted debe
+pertenecer al grupo "_cgiargug_"}
+
+_textmessageinvalid_ [l=es] {Para acceder a la pÃ¡gina que usted ha solicitado es necesario conectarse.<br>
+_If_(_cgiargug_, [_textmustbelongtogroup_]<br>) Teclee por favor su nombre de
+usuario de Greenstone y su contraseÃ±a.
+
+}
+
+_textmessagefailed_ [l=es] {Error en el nombre de usuario o la contraseÃ±a}
+
+_textmessagedisabled_ [l=es] {Lo sentimos, pero se ha invalidado su cuenta. Por favor pÃ³ngase en
+contacto con el administrador de este sitio.
+
+}
+
+_textmessagepermissiondenied_ [l=es] {Lo sentimos, pero usted no tiene permiso de acceder a esta pÃ¡gina.
+
+}
+
+_textmessagestalekey_ [l=es] {El enlace que usted ha seleccionado ya no es vÃ¡lido. Teclee por favor su
+contraseÃ±a para tener acceso a esta pÃ¡gina.
+
+}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=es] {<p>Esta instalaciÃ³n de Greenstone no incluye ninguna documentaciÃ³n. Esto
+puede ser porque:
+
+<ol>
+
+<li>Greenstone se instalÃ³ a partir de un CD-ROM en una versiÃ³n compacta.
+
+<li>Greenstone se instalÃ³ a partir de una
+distribuciÃ³n descargada en un sitio Internet.
+
+</ol>
+
+<p>En ambos casos usted puede obtener la documentaciÃ³n en el directorio
+<i>docs</i> de un CD-ROM de Greenstone o visitando <a
+href="http://www.greenstone.org">http://www.greenstone.org</a>.
+
+}
+
+_textuserguide_ [l=es] {GuÃ­a del usuario}
+_textinstallerguide_ [l=es] {GuÃ­a de instalaciÃ³n}
+_textdeveloperguide_ [l=es] {GuÃ­a del programador}
+_textpaperguide_ [l=es] {Del papel a la colecciÃ³n}
+_textorganizerguide_ [l=es] {Uso del Organizador}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "documentaciÃ³n de greenstone" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=es] {_httpimg_/es/gsdocsgr.gif}
+_widthgsdocsgr_ [l=es] {_pagewidth_}
+_heightgsdocsgr_ [l=es] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ [l=es] {Estructura por defecto}
+_textmore_ [l=es] {mÃ¡s}
+_textcollector_ [l=es] {El Colector}
+_textinfo_ [l=es] {Informaciones sobre la colecciÃ³n}
+_textsrce_ [l=es] {Datos fuente}
+_textconf_ [l=es] {Configurar la colecciÃ³n}
+_textbild_ [l=es] {CreaciÃ³n}
+_textview_ [l=es] {Visualizar}
+_textdel_ [l=es] {Suprimir la colecciÃ³n}
+_textexpt_ [l=es] {Exportar la colecciÃ³n}
+
+_textdownloadingfiles_ [l=es] {Bajando archivos...}
+_textimportingcollection_ [l=es] {Importando una colecciÃ³n...}
+_textbuildingcollection_ [l=es] {Construyendo una colecciÃ³n...}
+_textcreatingcollection_ [l=es] {creando una colecciÃ³n...}
+
+_textcollectorblurb_ [l=es] {<i>Â¡La pluma es mÃ¡s poderosa que la espada!
+
+<br>
+Antes de crear y distribuir colecciones de informaciÃ³n, hay que
+reflexionar sobre las consecuencias y las responsabilidades que ello
+entraÃ±a. Hay cuestiones jurÃ­dicas de derecho de autor: poder tener
+acceso a documentos no significa necesariamente poder comunicarlos a
+terceros. Hay tambiÃ©n cuestiones de tipo social: en el manejo de las
+colecciones se deben respetar los usos y costumbres de la comunidad de
+la que proceden los documentos. Y hay tambiÃ©n cuestiones Ã©ticas: algunos
+documentos no deben ponerse a disposiciÃ³n de nadie.
+
+<br>Sea consciente del poder de la informaciÃ³n y utilÃ­celo con prudencia.
+
+</i>
+
+}
+
+_textcb1_ [l=es] {El Colector le ayuda a crear nuevas colecciones y modificar, aÃ±adir o
+suprimir colecciones. Para hacerlo, serÃ¡ guiado por una secuencia de
+pÃ¡ginas Web en que se le pedirÃ¡ la informaciÃ³n necesaria.
+
+}
+
+_textcb2_ [l=es] {Primero, debe decidir si }
+_textcnc_ [l=es] {Crear una nueva colecciÃ³n }
+_textwec_ [l=es] {Trabajar con una colecciÃ³n existente, aÃ±adiÃ©ndole datos o suprimiÃ©ndola }
+
+_textcb3_ [l=es] {Para crear o modificar colecciones de biblioteca digital es
+necesario registrarse. Esto permite evitar que otras personas entren en
+su computadora y alteren la informaciÃ³n. Nota: por razones de seguridad
+tendrÃ¡ que conectarse de nuevo cada media hora. Si esto sucede, Â¡no se
+preocupe! - se le invitarÃ¡ a abrir una nueva sesiÃ³n y podrÃ¡ usted
+continuar a partir de donde se encontraba en el momento de la
+desconexiÃ³n.
+
+}
+
+_textcb4_ [l=es] {Teclee por favor su nombre de usuario de Greenstone y su contraseÃ±a y
+pulse el botÃ³n para conectarse.
+
+}
+
+_textfsc_ [l=es] {Primero seleccione la colecciÃ³n con la cual desea usted trabajar (las
+colecciones protegidas contra la escritura no aparecerÃ¡n en esta lista).
+
+}
+
+_textwtc_ [l=es] {Con la colecciÃ³n seleccionada, usted puede
+
+}
+_textamd_ [l=es] {AÃ±adir mÃ¡s datos y recrear la colecciÃ³n
+
+
+}
+_textetc_ [l=es] {Modificar el fichero de configuraciÃ³n de la colecciÃ³n y recrear la
+colecciÃ³n
+
+}
+_textdtc_ [l=es] {Suprimir la colecciÃ³n definitivamente
+
+}
+_textetcfcd_ [l=es] {Exportar la colecciÃ³n para grabarla en un CD-ROM que se instala
+automÃ¡ticamente en Windows
+
+}
+_textcaec_ [l=es] {Cambiar una colecciÃ³n existente
+
+}
+_textnwec_ [l=es] {No estÃ¡ disponible para su modificaciÃ³n ninguna colecciÃ³n que permita la
+escritura
+
+}
+_textcianc_ [l=es] {Crear una nueva colecciÃ³n
+
+}
+_texttsosn_ [l=es] {La secuencia de las fases necesarias para crear una nueva colecciÃ³n de
+biblioteca digital es la siguiente:
+
+}
+_textsin_ [l=es] {Especificar su nombre (y otras informaciones asociadas)
+
+}
+_textswts_ [l=es] {Especificar de dÃ³nde provienen los datos fuente
+
+}
+_textatco_ [l=es] {Ajustar las opciones de configuraciÃ³n (sÃ³lo para usuarios
+experimentados)
+
+}
+_textbtc_ [l=es] {"Crear" la colecciÃ³n (vÃ©ase mÃ¡s abajo)
+
+}
+_textpvyh_ [l=es] {Â¡Admire su obra!
+
+}
+
+_texttfsiw_ [l=es] {La cuarta fase es cuando la computadora hace todo el trabajo. En el
+proceso de "creaciÃ³n" la computadora elabora todos los Ã­ndices y
+recopila todas las informaciones necesarias para el buen funcionamiento
+de la biblioteca digital. Pero primero tiene usted que especificar
+las informaciones.
+
+}
+
+_textadab_ [l=es] {MÃ¡s abajo aparece un diagrama que le ayudarÃ¡ ver dÃ³nde se encuentra. El
+botÃ³n verde es el que usted pulsarÃ¡ para continuar la secuencia. DespuÃ©s
+de cada paso en la secuencia, los botones cambiarÃ¡n al amarillo. Se
+puede volver a una pÃ¡gina anterior pulsando el botÃ³n amarillo
+correspondiente en el diagrama.
+
+}
+
+_textwyar_ [l=es] {Cuando estÃ© listo, pulse el botÃ³n verde "informaciones sobre la
+colecciÃ³n" para comenzar a crear su nueva colecciÃ³n de biblioteca
+digital.
+
+}
+
+_textcnmbs_ [l=es] {Se debe especificar el nombre de la colecciÃ³n}
+_texteambs_ [l=es] {Se debe especificar la direcciÃ³n de correo electrÃ³nico}
+_textpsea_ [l=es] {Compruebe por favor que la direcciÃ³n de correo electrÃ³nico corresponde al formato usuario@dominio}
+_textdocmbs_ [l=es] {Se debe especificar la descripciÃ³n de la colecciÃ³n}
+
+_textwcanc_ [l=es] {Al crear una nueva colecciÃ³n, es necesario incorporar algunas
+informaciones preliminares sobre los datos fuente. Este proceso se
+estructura en forma de una serie de pÃ¡ginas Web, supervisadas por el
+Colector. La barra en la parte inferior de la pÃ¡gina muestra la
+secuencia de las pÃ¡ginas que quedan.
+
+}
+
+_texttfc_ [l=es] {TÃ­tulo de la colecciÃ³n:
+
+}
+
+_texttctiasp_ [l=es] {El tÃ­tulo de la colecciÃ³n es una frase corta que se utiliza en la
+biblioteca digital para identificar el contenido de la colecciÃ³n.
+Por ejemplo: "Computer Science Technical Reports" (Informes tÃ©cnicos de
+informÃ¡tica) o "Humanity Development Library" (Biblioteca para el
+desarrollo de la humanidad).
+
+}
+
+_textcea_ [l=es] {DirecciÃ³n de correo electrÃ³nico de contacto:
+
+}
+
+_textteas_ [l=es] {Esta direcciÃ³n electrÃ³nica constituye el primer punto de contacto para
+la colecciÃ³n. Si el programa Greenstone detecta un problema, un informe
+de diagnÃ³stico se envÃ­a a esta direcciÃ³n. Teclee una direcciÃ³n
+electrÃ³nica en su forma completa: nombre@dominio.
+
+}
+
+_textatc_ [l=es] {Acerca de esta colecciÃ³n:
+
+}
+
+_texttiasd_ [l=es] {Ãsta es una declaraciÃ³n en que se enuncian los principios que rigen los
+elementos que forman parte de esta colecciÃ³n. AparecerÃ¡ en la primera
+pÃ¡gina de presentaciÃ³n de la colecciÃ³n.
+
+}
+
+_textypits_ [l=es] {Su posiciÃ³n en la secuencia se indica con una flecha por debajo - en
+este caso, la etapa de las "informaciones de colecciÃ³n". Para continuar,
+pulse el botÃ³n verde "datos fuente".
+
+}
+
+_srcebadsources_ [l=es] {<p>Uno o mÃ¡s de los ficheros fuente que usted especificÃ³ no estÃ¡ disponible
+(marcados _iconcross_ abajo).
+
+<p>Esto puede ser porque:
+
+<ul>
+
+<li>No existe el fichero, el sitio FTP o el URL.
+
+<li>Hay que conectarse primero a Internet.
+
+<li>Usted estÃ¡ intentando acceder a un URL que se encuentra detrÃ¡s de un
+cortafuego (esto ocurre normalmente cuando usted tiene que presentar un
+nombre de usuario y una contraseÃ±a para acceder a Internet).
+
+</ul>
+
+<p>Si Ã©ste es un URL que usted puede ver en su navegador, el problema
+puede provenir de una copia que se encuentra en la memoria cache local.
+Desafortunadamente, estas copias son invisibles para nuestro proceso de
+espejo de Greenstone. En este caso recomendamos que descargue las
+pÃ¡ginas mediante su navegador.
+
+}
+
+_textymbyco_ [l=es] {Usted puede basar su colecciÃ³n en:
+
+<ul>
+
+<li>La estructura por defecto
+
+</ul>
+
+<dl> <dd> La nueva colecciÃ³n puede contener documentos HTML (.htm,
+.html), documentos texto (.txt, .text), documentos MS-Word (.doc),
+documentos PDF (.pdf), o documentos de correo electrÃ³nico en el formato
+"m-box" (.mbx). </dd> </dl>
+
+<li>Una colecciÃ³n existente
+
+<dl> <dd> Los ficheros de su nueva colecciÃ³n deben ser exactamente del mismo
+tipo que los utilizados para crear la colecciÃ³n existente. </dd> </dl>
+
+</ul>
+
+}
+
+_textbtco_ [l=es] {Basar la colecciÃ³n en:}
+_textand_ [l=es] {AÃ±adir nuevos datos}
+_textad_ [l=es] {AÃ±adir datos:}
+
+_texttftysb_ [l=es] {Los ficheros que usted especifique mÃ¡s abajo se aÃ±adirÃ¡n a la colecciÃ³n.
+CerciÃ³rese de no volver a especificar ficheros que ya estÃ¡n en la
+colecciÃ³n, pues de hacerlo habrÃ¡ dos copias. Los ficheros se especifican
+indicando su nombre completo y el directorio en que estÃ¡n almacenados,
+las pÃ¡ginas Web se identifican por su direcciÃ³n Internet absoluta.
+
+}
+
+_textis_ [l=es] {Datos de entrada: }
+
+_textddd1_ [l=es] {<p>Si usted utiliza file:// o ftp:// para especificar un fichero, Ã©ste
+se descargarÃ¡.
+
+<p>Si usted utiliza HTTP://, el resultado dependerÃ¡ del URL y serÃ¡
+diferente si Ã©ste abre en su navegador una pÃ¡gina Web o una lista de
+ficheros. Si se trata de una pÃ¡gina, Ã©sta se descargarÃ¡, al igual que
+todas las pÃ¡ginas con las que estÃ¡ vinculada mediante hiperenlaces,-
+siempre que se encuentren en el mismo sitio Web, en el URL inicial.
+
+<p>Si usted utiliza file:// o ftp:// para especificar un directorio, o
+si indica un URL HTTP:// que conduce a una lista de ficheros, todos los
+ficheros que se encuentran en esa carpeta y en sus subcarpetas se
+incluirÃ¡n en la colecciÃ³n.
+
+<p>Pulse el botÃ³n "mÃ¡s datos" para obtener mÃ¡s cuadros de introducciÃ³n
+de datos.
+
+}
+
+_textddd2_ [l=es] {<p>Pulse uno de los botones verdes. Si es usted un usuario
+experimentado, puede desear ajustar la configuraciÃ³n de la colecciÃ³n.
+Otra posibilidad es ir directamente a la etapa de creaciÃ³n. Recuerde, se
+puede volver a un paso anterior pulsando el botÃ³n amarillo
+correspondiente.
+
+}
+
+_textconf1_ [l=es] {<p>La creaciÃ³n y la presentaciÃ³n de su colecciÃ³n son controladas por
+especificaciones en un "fichero de configuraciÃ³n" especial. Los usuarios
+experimentados que lo deseen pueden modificar los parÃ¡metros de la
+configuraciÃ³n.
+
+<center><p><b>Si no es usted un usuario experimentado, vaya a la parte
+inferior de la pÃ¡gina.</b></center> 
+
+<p>Para modificar los parÃ¡metros de la configuraciÃ³n, corrija los datos que
+aparecen mÃ¡s abajo. Si comete una equivocaciÃ³n, pulse el botÃ³n
+"Reinicio" para restablecer los parÃ¡metros originales de la
+configuraciÃ³n.
+
+}
+
+_textreset_ [l=es] {Reiniciar}
+
+_textbild1_ [l=es] {La colecciÃ³n se estÃ¡ creando: esta operaciÃ³n puede ser larga. La lÃ­nea
+de estado que aparece mÃ¡s abajo indica cÃ³mo estÃ¡ progresando la
+operaciÃ³n.
+
+}
+
+_textbild2_ [l=es] {Para interrumpir el proceso de creaciÃ³n en cualquier momento, pulse
+aquÃ­. <br> La colecciÃ³n con que estÃ¡ trabajando quedarÃ¡ intacta.
+
+}
+
+_textstopbuild_ [l=es] {Interrumpir la creaciÃ³n }
+
+_textbild3_ [l=es] {Si usted sale de esta pÃ¡gina (y no ha cancelado el proceso de creaciÃ³n
+con el botÃ³n "interrumpir la creaciÃ³n"), la colecciÃ³n
+continuarÃ¡ creÃ¡ndose y se instalarÃ¡ cuando el proceso haya concluido.
+
+}
+
+_textbuildcancelled_ [l=es] {CreaciÃ³n cancelada
+
+}
+
+_textbildcancel1_ [l=es] {Se ha cancelado el proceso de creaciÃ³n de la colecciÃ³n. Utilice los
+botones amarillos para efectuar cambios en su colecciÃ³n o para reiniciar
+el proceso de creaciÃ³n.
+
+}
+
+_textbsupdate1_ [l=es] {ActualizaciÃ³n del estado de la creaciÃ³n dentro de 1 segundo}
+_textbsupdate2_ [l=es] {ActualizaciÃ³n del estado de la creaciÃ³n dentro de}
+_textseconds_ [l=es] {segundos}
+_textbildsuc_ [l=es] {ColecciÃ³n creada satisfactoriamente.}
+
+_textviewbildsummary_ [l=es] {Para obtener mÃ¡s detalles, usted puede <a
+href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>visualizar
+el resumen de la creaciÃ³n</a> de esta colecciÃ³n.
+
+}
+
+_textfailmsg11_ [l=es] {La colecciÃ³n no se pudo crear porque no contiene ningÃºn dato. CerciÃ³rese
+de que existe por lo menos uno de los directorios o los ficheros que
+usted especificÃ³ en la pÃ¡gina <i>datos fuente</i> y de que es de un tipo
+o, en el caso de un directorio, de que contiene ficheros de un tipo que
+Greenstone puede procesar.
+
+}
+
+_textfailmsg21_ [l=es] {No se pudo crear la colecciÃ³n (import.pl fallÃ³).
+
+}
+_textblcont_ [l=es] {El registro de creaciÃ³n contiene las informaciones siguientes:
+
+}
+
+_texttryagain_ [l=es] {Por favor <a href="_httppagecollector_" target=_top>vuelva a
+arrancar el Colector</a> e intente de nuevo.
+
+}
+
+_textfailmsg31_ [l=es] {No se pudo crear la colecciÃ³n (buildcol.pl fallÃ³).
+
+}
+_textfailmsg41_ [l=es] {Se logrÃ³ crear la colecciÃ³n pero no se pudo instalar.
+
+}
+_textfailmsg71_ [l=es] {Se produjo un error inesperado cuando se intentaba crear la colecciÃ³n
+
+}
+_textretcoll_ [l=es] {Volver al Colector
+
+}
+
+_textdelperm_ [l=es] {No se pudo suprimir toda o una parte de la colecciÃ³n _cgiargbc1dirname_ . Las causas pueden ser las siguientes:
+<ul>
+<li> Greenstone no tiene permiso para suprimir el directorio _gsdlhome_/collect/_cgiargbc1dirname_.<br> 
+Es posible que usted necesite eliminar este directorio manualmente para poder suprimir completamente la colecciÃ³n _cgiargbc1dirname_ de esta computadora.</</li>
+<li>Greenstone no pudo correr el programa _gsdlhome_/bin/script/delcol.pl. AsegÃºrese de que este archivo se pueda leer y sea ejecutable.</li>
+</ul>
+}
+
+_textdelinv_ [l=es] {La colecciÃ³n _cgiargbc1dirname_ estÃ¡ protegida o no es vÃ¡lida. La
+supresiÃ³n se cancelÃ³.
+
+}
+
+_textdelsuc_ [l=es] {Se suprimiÃ³ la colecciÃ³n _cgiargbc1dirname_.
+
+}
+
+_textclonefail_ [l=es] {No se pudo clonar la colecciÃ³n _cgiargclonecol_. Las causas posibles
+son:
+
+<ul>
+
+<li>La colecciÃ³n _cgiargclonecol_ no existe
+
+<li>La colecciÃ³n _cgiargclonecol_ no tiene ningÃºn fichero collect.cfg
+
+<li>Greenstone no tiene permiso para leer el fichero de configuraciÃ³n
+collect.cfg
+
+</ul>
+
+}
+
+_textcolerr_ [l=es] {Error en el Colector. }
+
+_texttmpfail_ [l=es] {El Colector no pudo efectuar ninguna operaciÃ³n de lectura o de escritura
+en el fichero o directorio temporal. Las causas posibles son:
+
+<ul>
+
+<li>Greenstone no tiene acceso de lectura/escritura al directorio
+_gsdlhome_/tmp.
+
+</ul>
+
+}
+
+_textmkcolfail_ [l=es] {El Colector no pudo crear la estructura de directorios que requiere la
+nueva colecciÃ³n (mkcol.pl fallÃ³). Las causas posibles son:
+
+<ul>
+
+<li>Greenstone no tiene permiso para escribir en el directorio
+_gsdlhome_/tmp.
+
+<li>Errores en el guiÃ³n Perl mkcol.pl.
+
+</ul>
+
+}
+
+_textnocontent_ [l=es] {Error del Colector: no se proporcionÃ³ ningÃºn nombre para la nueva
+colecciÃ³n. Intente volver a arrancar el Colector.
+
+}
+
+_textrestart_ [l=es] {Volver a arrancar el Colector
+
+}
+
+_textreloaderror_ [l=es] {Se produjo un error cuando se creaba la nueva colecciÃ³n. Es posible que
+el uso de los botones "Volver a cargar" o "AtrÃ¡s" de su navegador haya
+perturbado a Greenstone (trate de evitar la utilizaciÃ³n de esos botones
+durante la creaciÃ³n de una colecciÃ³n con el Colector). Se recomienda
+volver a arrancar el Colector.
+
+}
+
+_textexptsuc_ [l=es] {La colecciÃ³n de _cgiargbc1dirname_ se exportÃ³ al directorio
+_gsdlhome_/tmp/exported\__cgiargbc1dirname_.
+
+}
+
+_textexptfail_ [l=es] {<p>No se pudo exportar la colecciÃ³n _cgiargbc1dirname_. 
+
+<p>Es probable que esto se deba a que Greenstone se instalÃ³ sin los
+componentes necesarios para posibilitar la funciÃ³n "Exportar la
+colecciÃ³n".
+
+<ul>
+
+<li>Si usted instalÃ³ Greenstone a partir de un CD-ROM, estos
+componentes no se habrÃ¡n instalado a menos que usted los haya
+seleccionado durante una instalaciÃ³n "personalizada". Puede agregarlos a
+su instalaciÃ³n volviendo a efectuar el procedimiento de instalaciÃ³n.
+
+<li>Si usted instalÃ³ Greenstone a partir de un programa distribuido por
+Internet, serÃ¡ necesario descargar e instalar un paquete adicional para
+activar esta funciÃ³n. Visite por favor <a
+href="http://www.greenstone.org">http://www.greenstone.org</a> o envÃ­e
+un correo electrÃ³nico a <a
+href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+para obtener mÃ¡s detalles.
+
+</ul>
+
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "El colector" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=es] {_httpimg_/es/h\_colect.gif}
+
+## "informaciones\nsobre la colecciÃ³n" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=es] {_httpimg_/es/gcinfoof.gif}
+_httpicongcinfoon_ [l=es] {_httpimg_/es/gcinfoon.gif}
+_httpiconycinfoof_ [l=es] {_httpimg_/es/ycinfoof.gif}
+_httpiconycinfoon_ [l=es] {_httpimg_/es/ycinfoon.gif}
+_httpiconncinfoof_ [l=es] {_httpimg_/es/ncinfoof.gif}
+
+## "datos\nfuente" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=es] {_httpimg_/es/gcsrceof.gif}
+_httpicongcsrceon_ [l=es] {_httpimg_/es/gcsrceon.gif}
+_httpiconycsrceof_ [l=es] {_httpimg_/es/ycsrceof.gif}
+_httpiconycsrceon_ [l=es] {_httpimg_/es/ycsrceon.gif}
+_httpiconncsrceof_ [l=es] {_httpimg_/es/ncsrceof.gif}
+
+## "configurar\nla colecciÃ³n" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=es] {_httpimg_/es/gcconfof.gif}
+_httpicongcconfon_ [l=es] {_httpimg_/es/gcconfon.gif}
+_httpiconycconfof_ [l=es] {_httpimg_/es/ycconfof.gif}
+_httpiconycconfon_ [l=es] {_httpimg_/es/ycconfon.gif}
+_httpiconncconfof_ [l=es] {_httpimg_/es/ncconfof.gif}
+
+## "crear\nla colecciÃ³n" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=es] {_httpimg_/es/gcbildof.gif}
+_httpicongcbildon_ [l=es] {_httpimg_/es/gcbildon.gif}
+_httpiconycbildof_ [l=es] {_httpimg_/es/ycbildof.gif}
+_httpiconycbildon_ [l=es] {_httpimg_/es/ycbildon.gif}
+_httpiconncbildof_ [l=es] {_httpimg_/es/ncbildof.gif}
+
+## "visualizar\nla colecciÃ³n" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=es] {_httpimg_/es/gcviewof.gif}
+_httpicongcviewon_ [l=es] {_httpimg_/es/gcviewon.gif}
+_httpiconycviewof_ [l=es] {_httpimg_/es/ycviewof.gif}
+_httpiconycviewon_ [l=es] {_httpimg_/es/ycviewon.gif}
+_httpiconncviewof_ [l=es] {_httpimg_/es/ncviewof.gif}
+
+## "suprimir\nla colecciÃ³n" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=es] {_httpimg_/es/gcdelof.gif}
+_httpicongcdelon_ [l=es] {_httpimg_/es/gcdelon.gif}
+
+## "exportar\nla colecciÃ³n" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=es] {_httpimg_/es/gcexptof.gif}
+_httpicongcexpton_ [l=es] {_httpimg_/es/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=es] {<p>Greenstone es un conjunto de programas informÃ¡ticos cuya
+finalidad es dar acceso a colecciones de informaciones que constituyen
+una biblioteca digital y crear nuevas colecciones. Ofrece
+una nueva manera de organizar la informaciÃ³n y de publicarla en
+Internet o en un CD-ROM.  Elaborado dentro del proyecto de Biblioteca
+Digital de Nueva Zelandia de la Universidad de Waikato, este producto
+se distribuye en colaboraciÃ³n con la UNESCO y la ONG Human
+Info. Es un programa informÃ¡tico de cÃ³digo fuente
+abierto (<i>open-source software</i>), que puede descargarse en la
+direcciÃ³n <a
+href="http://greenstone.org">http://greenstone.org</a>, segÃºn
+las condiciones estipuladas en la Licencia PÃºblica General de
+GNU.
+
+}
+
+_textgreenstone2_ [l=es] {El sitio web de la Biblioteca Digital de Nueva Zelandia (<a
+href="http://nzdl.org">http://nzdl.org</a>) contiene numerosos ejemplos
+de colecciones, creados con el programa Greenstone, que se pueden
+consultar libremente. Muestran varias opciones de bÃºsqueda y navegaciÃ³n,
+e incluyen colecciones en Ã¡rabe, chino, francÃ©s, maorÃ­ y espaÃ±ol, asÃ­
+como en inglÃ©s. Hay tambiÃ©n algunas colecciones de mÃºsica.
+
+}
+
+_textplatformtitle_ [l=es] {plataforma}
+_textgreenstone3_ [l=es] {Greenstone funciona con Windows, UNIX y Mac OS X. La distribuciÃ³n incluye binarios listos para usarse en todas las versiones de Windows, Linux y Mac OS X. TambiÃ©n incluye el cÃ³digo fuente completo para el sistema, el cual se puede compilar usando Microsoft C++ o GCC. Greenstone funciona con otros programas libres de software, incluyendo el servidor Web Apache y Perl. La interfaz de usuario utiliza navegadores Web como Netscape Navigator o Internet Explorer.
+}
+
+_textgreenstone4_ [l=es] {Muchas colecciones de documentos se distribuyen en CD-ROM con el
+programa Greenstone. Por ejemplo, el proyecto de <i>Bibliotecas para el
+desarrollo de la humanidad</i> contiene 1.230 publicaciones cuyos temas
+son muy variados (desde la contabilidad hasta la depuraciÃ³n del agua).
+Se puede acceder a esta colecciÃ³n con computadoras de escasa potencia,
+como las que se suelen encontrar en los paÃ­ses en desarrollo. La
+informaciÃ³n puede obtenerse mediante bÃºsquedas o consultas por tema, por
+tÃ­tulos de publicaciones, por organizaciÃ³n, consultando una lista de
+"CÃ³mo", o visualizando de forma aleatoria las portadas de los
+libros.
+
+}
+
+_textcustomisationtitle_ [l=es] {personalizaciÃ³n}
+_textgreenstone5_ [l=es] {Greenstone estÃ¡ especialmente concebido para poder ampliarse y
+personalizarse a voluntad. Greenstone puede tratar nuevos formatos de
+documentos y de metadatos escribiendo "conectores" (<i>plugins</i>), en
+lenguaje Perl. Asimismo, se pueden implementar nuevas estructuras de
+navegaciÃ³n en los metadatos escribiendo "clasificadores." La interfaz de
+usuario y la presentaciÃ³n se pueden modificar utilizando las "macros"
+escritas en un lenguaje de macros simple. El protocolo CORBA permite que
+los agentes (por ejemplo en lenguaje Java) utilicen todas las funciones
+disponibles en las colecciones de documentos. Por Ãºltimo, se puede
+modificar el cÃ³digo fuente en C++ y Perl.
+
+}
+
+_textdocumentationtitle_ [l=es] {documentaciÃ³n}
+_textdocuments_ [l=es] {La documentaciÃ³n completa del software Greenstone ya estÃ¡ disponible.}
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+_textmailinglisttitle_ [l=es] {lista de correo}
+_textmailinglist_ [l=es] {Existe una lista de correo electrÃ³nico para los debates sobre el
+programa de Biblioteca Digital Greenstone. Es deseable que los
+usuarios activos de Greenstone participen en estos debates.
+Para suscribirse, pulse <a href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.
+Para enviar un mensaje a la lista, utilice la direcciÃ³n <a
+href="mailto:greenstone-users@list.scms.waikato.ac.nz">greenstone-users@list.scms.waikato.ac.nz</a>.
+
+}
+
+_textbugstitle_ [l=es] {errores lÃ³gicos o de programaciÃ³n}
+_textreport_ [l=es] {Nuestro deseo es garantizar el correcto funcionamiento de este programa,
+por lo que alentamos a sus usuarios a notificar cualquier problema que
+detecten a: <a
+href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>.
+
+}
+
+_textgs3title_ [l=es] {en los trabajos}
+_textgs3_ [l=es] {Greenstone 3 es un diseÃ±o e implementaciÃ³n completamente nuevos, que conserva todas las ventajas de Greenstone 2 (la versiÃ³n actual). Por ejemplo, es multilingÃŒe, multiplataforma y altamente configurable. Incorpora todas las prestaciones del sistema actual y es compatible con versiones anteriores, es decir, que puede construir y presentar colecciones preexistentes sin modificarlas. Escrito en Java, estÃ¡ estructurado como una red de mÃ³dulos independientes que se comunican por medio de XML. De esta manera funciona de manera distribuida y puede extenderse a diferentes servidores segÃºn se necesite. Su diseÃ±o modular aumenta la flexibilidad y capacidad de Greenstone. La documentaciÃ³n y las versiones experimentales de Greenstone 3 pueden descargarse de la <a href="http://www.greenstone.org/greenstone3.html">pÃ¡gina principal de Greenstone 3</a>.
+}
+
+_textcreditstitle_ [l=es] {crÃ©ditos}
+
+_textwhoswho_ [l=es] {El programa Greenstone es fruto de la colaboraciÃ³n de muchas personas. Rodger McNab y Stefan Boddie son los principales arquitectos y programadores. TambiÃ©n han contribuido David Bainbridge, George Buchanan, Hong Chen, Michael Dewsnip, Katherine Don, Elke Duncker, Carl Gutwin, Geoff Holmes, Dana McKay, John McPherson, Craig Nevill-Manning, Dynal Patel, Gordon Paynter, Bernhard Pfahringer, Todd Reed, Bill Rogers, John Thompson y Stuart Yeates. Otros miembros del proyecto Biblioteca Digital de Nueva Zelanda que proporcionaron asesorÃ­a y valiosas ideas para la concepciÃ³n del sistema son: Mark Apperley, Sally Jo Cunningham, Matt Jones, Steve Jones, Te Taka Keegan, Michel Loots, Malika Mahoui, Gary Marsden, Dave Nichols y Lloyd Smith. TambiÃ©n queremos dar las gracias a todos aquellos que contribuyeron a los paquetes de programas con licencias GNU incluidos en esta distribuciÃ³n: MG, GDBM, PDFTOHTML, PERL, WGET, WVWARE y XLHTML.
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "acerca del programa greenstone" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=es] {_httpimg_/es/abgsgr.gif}
+_widthabgsgr_ [l=es] {_pagewidth_}
+_heightabgsgr_ [l=es] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=es] {Lista de los usuarios actuales}
+_textuser_ [l=es] {usuario}
+_textas_ [l=es] {estado de la cuenta}
+_textgroups_ [l=es] {grupos}
+_textcomment_ [l=es] {comentario}
+_textadduser_ [l=es] {aÃ±adir un nuevo usuario }
+_textedituser_ [l=es] {modificar}
+_textdeleteuser_ [l=es] {suprimir}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=es] {Modificar las informaciones relativas a los usuarios}
+_textadduser_ [l=es] {AÃ±adir un nuevo usuario}
+
+_textaboutusername_ [l=es] {Los nombres de usuarios deben tener entre 2 y 30 caracteres. Pueden
+estar compuestos de caracteres alfanumÃ©ricos, '.', y '_'.
+}
+
+_textaboutpassword_ [l=es] {Las contraseÃ±as deben ser de entre 3 y 8 caracteres, y pueden comprender
+todos los caracteres ASCII imprimibles.
+}
+
+_textoldpass_ [l=es] {Si este campo se deja vacÃ­o, se utilizarÃ¡ la antigua contraseÃ±a. }
+_textenabled_ [l=es] {activado }
+_textdisabled_ [l=es] {desactivado }
+
+_textaboutgroups_ [l=es] {Los grupos son listas cuyos elementos estÃ¡n separados por comas, no
+teclee espacios despuÃ©s de las comas.}
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=es] {Suprimir un usuario}
+_textremwarn_ [l=es] {Â¿Confirma usted que desea suprimir definitivamente el usuario <b>_cgiargumun_</b>?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=es] {Cambiar la contraseÃ±a}
+_textoldpw_ [l=es] {antigua contraseÃ±a}
+_textnewpw_ [l=es] {nueva contraseÃ±a}
+_textretype_ [l=es] {vuelva a teclear su nueva contraseÃ±a}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=es] {Se ha registrado su nueva contraseÃ±a}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=es] {El nombre de usuario no es vÃ¡lido.}
+_textinvalidpassword_ [l=es] {La contraseÃ±a no es vÃ¡lida.}
+_textemptypassword_ [l=es] {Teclee una contraseÃ±a inicial para este usuario.}
+_textuserexists_ [l=es] {Este usuario ya existe, teclee por favor otro
+nombre de usuario.}
+
+_textusernameempty_ [l=es] {Teclee por favor su nombre de usuario.}
+_textpasswordempty_ [l=es] {Tiene que teclear su antigua contraseÃ±a.}
+_textnewpass1empty_ [l=es] {Teclee su nueva contraseÃ±a y vuÃ©lvala a teclear.}
+_textnewpassmismatch_ [l=es] {Las dos versiones de su nueva contraseÃ±a son distintas.}
+_textnewinvalidpassword_ [l=es] {La contraseÃ±a es incorrecta.}
+_textfailed_ [l=es] {Es incorrecto el nombre de usuario o la contraseÃ±a.}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=es] {NÃºmero de versiÃ³n de Greenstone}
+_textframebrowser_ [l=es] {Para visualizar esto se requiere un navegador que acepte los marcos ("frames").}
+_textusermanage_ [l=es] {GestiÃ³n de los usuarios}
+_textlistusers_ [l=es] {lista de los usuarios}
+_textaddusers_ [l=es] {aÃ±adir un nuevo usuario}
+_textchangepasswd_ [l=es] {cambiar de contraseÃ±a}
+_textinfo_ [l=es] {Informaciones tÃ©cnicas}
+_textgeneral_ [l=es] {general}
+_textarguments_ [l=es] {argumentos}
+_textactions_ [l=es] {acciones}
+_textbrowsers_ [l=es] {navegadores}
+_textprotocols_ [l=es] {protocolos}
+_textconfigfiles_ [l=es] {Ficheros de configuraciÃ³n}
+_textlogs_ [l=es] {Registros}
+_textusagelog_ [l=es] {registro de uso}
+_textinitlog_ [l=es] {registro de inicializaciÃ³n}
+_texterrorlog_ [l=es] {registro de errores}
+_textadminhome_ [l=es] {pÃ¡gina principal de la administraciÃ³n}
+_textreturnhome_ [l=es] {pÃ¡gina principal de Greenstone}
+_titlewelcome_ [l=es] {AdministraciÃ³n }
+_textmaas_ [l=es] {Los servicios de mantenimiento y de administraciÃ³n son los siguientes:}
+_textvol_ [l=es] {mostrar los registros en lÃ­nea}
+_textcmuc_ [l=es] {crear, mantener y actualizar colecciones}
+_textati_ [l=es] {acceder a informaciones tÃ©cnicas tales como los argumentos CGI}
+
+_texttsaa_ [l=es] {Se puede acceder a estos servicios mediante la barra de navegaciÃ³n
+situada en la parte izquierda de la pÃ¡gina.
+}
+
+_textcolstat_ [l=es] {Estado de la colecciÃ³n}
+
+_textcwoa_ [l=es] {Una colecciÃ³n sÃ³lo aparecerÃ¡ como "running" (en funcionamiento) si el
+fichero build.cfg existe, si es legible, si contiene un campo vÃ¡lido
+"builddate" (fecha de creaciÃ³n), es decir &gt; 0, y si se encuentra en
+el directorio "index" de la colecciÃ³n (es decir NO en el directorio
+"build").
+
+}
+
+_textcafi_ [l=es] {Pulse <i>abbrev.</i> para obtener informaciones sobre una colecciÃ³n}
+_textcctv_ [l=es] {Pulse <i>collection</i> para visualizar una colecciÃ³n}
+_textsubc_ [l=es] {Someter cambios }
+_texteom_ [l=es] {Error de lectura del fichero main.cfg}
+_textftum_ [l=es] {No se pudo actualizar el fichero main.cfg }
+_textmus_ [l=es] {se logrÃ³ actualizar el fichero main.cfg }
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=es] {Resumen de la creaciÃ³n de la colecciÃ³n _collectionname_
+
+}
+_textflog_ [l=es] {Error en el registro de la colecciÃ³n  _collectionname_
+
+}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=es] {Capacidad de uso de Greenstone}
+
+_textwhy_ [l=es] {<p>Este reporte es una forma de indicar que la pÃ¡gina Web que usted estaba viendo era difÃ­cil de manejar o resultaba frustrante. }
+_textextraforform_ [l=es] {Usted no tiene que llenar la forma. Cualquier informaciÃ³n serÃ¡ de ayuda.}
+_textprivacybasic_ [l=es] {<p>El reporte consistirÃ¡ Ãºnicamente de informaciÃ³n acerca de la pÃ¡gina Web Greenstone que usted estÃ¡ viendo y de la tecnologÃ­a que estÃ¡ usando para verla (asÃ­ como cualquier informaciÃ³n adicional que usted proporcione).}
+_textstillsend_ [l=es] {Â¿Le gustarÃ­a enviar este reporte?}
+
+_texterror_ [l=es] {error}
+_textyes_ [l=es] {Si}
+_textno_ [l=es] {No}
+_textclosewindow_ [l=es] {Cerrar ventana}
+_textabout_ [l=es] {Acerca de}
+_textprivacy_ [l=es] {Confidencialidad}
+_textsend_ [l=es] {Enviar}
+_textdontsend_ [l=es] {No envÃ­e}
+_textoptionally_ [l=es] {De manera opcional}
+
+_textunderdev_ [l=es] {Una vista previa de los detalles estarÃ¡ disponible en la versiÃ³n final.}
+
+_textviewdetails_ [l=es] {Ver los detalles del reporte}
+_textmoredetails_ [l=es] {MÃ¡s detalles}
+_texttrackreport_ [l=es] {Dar seguimiento a este reporte}
+_textcharacterise_ [l=es] {Â¿QuÃ© clase de problema es?}
+_textseverity_ [l=es] {Â¿QuÃ© tan serio es el problema?}
+ 
+_textbadrender_ [l=es] {La pÃ¡gina se ve rara}
+_textcontenterror_ [l=es] {Error de contenido}
+_textstrangebehaviour_ [l=es] {Comportamiento extraÃ±o}
+_textunexpected_ [l=es] {PasÃ³ algo inesperado}
+_textfunctionality_ [l=es] {DifÃ­cil de usar}
+_textother_ [l=es] {Otro(s)}
+
+_textcritical_ [l=es] {CrÃ­tico}
+_textmajor_ [l=es] {Serio}
+_textmedium_ [l=es] {Medio}
+_textminor_ [l=es] {Menor}
+_texttrivial_ [l=es] {Trivial}
+
+_textwhatdoing_ [l=es] {Â¿QuÃ© estaba tratando de hacer?}
+_textwhatexpected_ [l=es] {Â¿QuÃ© esperaba usted que pasara?}
+_textwhathappened_ [l=es] {Â¿QuÃ© es lo que realmente pasÃ³?}
+
+_cannotfindcgierror_ [l=es] {<h2>Â¡Disculpe!</h2>Nose pudieron encontrar los programas del servidor para el botÃ³n "MegustarÃ­a poner una queja".}
+
+_textusabbanner_ [l=es] {el rÃ³tulo estilo koru de Greenstone}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+_textgli_ [l=es] {Interfaz de la Biblioteca Digital Greenstone}
+_textglihelp_ [l=es] {La Interfaz de Bibliotecario del Greenstone (GLI) le da acceso a la funcionalidad de Greenstone desde una interfaz fÃ¡cil de usar con la que solo tiene que apuntar y hacer click. Esto le permite reunir grupos de documentos, importar o asignar metadatos, e incluirlos en una colecciÃ³n de Greeenstone.
+<p>
+
+Recuerde que la GLI se ejecuta conjuntamente con Greenstone, por 
+lo que se asume que estarÃ¡ instalada en un subdirectorio de su instalaciÃ³n deGreenstone. 
+Si usted ya descargÃ³ una de las versiones de Greenstone o la instalÃ³  
+desde un CD-ROM, entonces Ã©ste serÃ¡ el caso.
+
+<h4>EjecuciÃ³n de la GLI en Windows</h4>
+
+Ponga en marcha la Interfaz de Bibliotecario en Windows seleccionando <i>Biblioteca Digital Greenstone</i> en el submenÃº de <i>Programas</i> del menÃº de <i>Inicio</i> y eligiendo <i>Interfaz de Bibliotecario de Greenstone</i>. 
+
+<h4>EjecuciÃ³n de la GLI en UNIX</h4>
+
+Para poner en marcha la Interfaz de Bibliotecario en UNIX cambie al directorio <i>gli</i> que se encuentra 
+en su instalaciÃ³n Greenstone y ejecute el guiÃ³n <i>gli.sh</i>.
+
+<h4>EjecuciÃ³n de la GLI en OS X</h4>
+
+En el Finder, despliegue <i>Aplicaciones</i> y <i>Greenstone</i>
+(si instalÃ³ Greenstone de la manera preestablecida), y lanze la aplicaciÃ³n <i>GLI</i>.}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "Interfaz de la Biblioteca Digital Greenstone" ## green_bar_left_aligned ## gligr ##
+_httpicongligr_ [l=es] {_httpimg_/es/gligr.gif}
+_widthgligr_ [l=es] {_pagewidth_}
+_heightgligr_ [l=es] {17}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/status.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/status.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/status.dm	(revision 10506)
@@ -0,0 +1,146 @@
+# this file must be UTF-8 encoded
+
+package status
+
+_header_ {<html>
+<head>
+<title>_1_</title>
+</head>
+<body bgcolor="\#90c098" text="\#000000" link="\#006666"
+      alink="\#cc9900" vlink="\#666633">
+}
+
+_footer_ {</body>
+</html>
+}
+
+_infoheader_ {<html>
+<head>
+<title>_1_</title>
+</head>
+<body bgcolor="\#ffffff" text="\#000000" link="\#006666"
+      alink="\#cc9900" vlink="\#666633">
+
+<table width=100%>
+  <tr>
+    <td><img src="_httpimg_/spacer.gif" width=2 height=77></td>
+    <td>_iconblankbar_
+        <center><h2>_1_</h2></center>
+        _iconblankbar_</td>
+  </tr>
+</table>
+<center>
+<table width=_pagewidth_><tr><td>
+}
+
+_infofooter_ {
+</td></tr></table>
+<p> _iconblankbar_
+</body>
+</html>
+}
+
+
+_frameset_ {
+<html>
+<head>
+<title>_titlewelcome_</title>
+</head>
+
+<frameset cols="180,*" border=0>
+  <noframes><body bgcolor="#ffffff">
+  <p>_textframebrowser_</p>
+  </body>
+  </noframes>
+  <frame src="_gwcgi_?e=_compressedoptions_&a=status&p=select" name=navframe>
+  <frame src="_gwcgi_?e=_compressedoptions_&a=status&p=welcome" name=infoframe>
+</frameset>
+
+</html>
+}
+
+_select_ {
+<a href="_httppagehome_" target=_top border=0><img src="_httpimg_/gsdl.gif"></a>
+<p>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&p=welcome" target=infoframe>_textadminhome_</a><br>
+<a href="_httppagehome_" target=\_top>_textreturnhome_</a>
+
+<p><b>_textconfigfiles_</b><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&p=gsdlsite" target=infoframe>_textgsdlsite_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&p=maincfg" target=infoframe>_textmaincfg_</a>
+
+<p><b>_textlogs_</b><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&p=usagelog" target=infoframe>_textusagelog_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&p=errorlog" target=infoframe>_texterrorlog_</a>
+
+_If_("_cgiarguma_" ne "\_cgiarguma\_", 
+<p><b>_textusermanage_</b><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=um&uma=listusers" target=infoframe>_textlistusers_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=um&uma=adduser" target=infoframe>_textaddusers_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=um&uma=changepasswd" target=infoframe>_textchangepasswd_</a>
+)
+
+<p><b>_textinfo_</b><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&p=generalinfo" target=infoframe>_textgeneral_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&p=argumentinfo" target=infoframe>_textarguments_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&p=actioninfo" target=infoframe>_textactions_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&p=browserinfo" target=infoframe>_textbrowsers_</a><br>
+<a href="_gwcgi_?e=_compressedoptions_&a=status&p=protocolinfo" target=infoframe>_textprotocols_</a>
+}
+
+_textgsdlsite_ {gsdlsite.cfg}
+_textmaincfg_ {main.cfg}
+
+_welcome_ {
+<center>
+<table width=_pagewidth_><tr><td>
+<b>_textversion_: _versionnum_</b>
+
+<p>_textmaas_
+<ul>
+<li>_textvol_
+<li>_textcmuc_
+<li>_textati_
+</ul>
+_texttsaa_
+<p>
+_iconblankbar_
+</td></tr>
+<tr><th align=left><br>_textcolstat_</th></tr>
+<tr><td>
+<font color=gray>
+_textcwoa_
+<p>
+_textcafi_
+<br>
+_textcctv_
+</font>
+</td></tr>
+</table>
+</center>
+}
+
+_maincfg_ {
+<form name="maincfgform" method=post action="_gwcgi_">
+<input type=hidden name="p" value="changemaincfg">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<p>_If_(_maincfgfile_,<textarea name="cfgfile" cols=72 rows=18 wrap=off>
+_maincfgfile_
+</textarea>
+<br><input type=submit value="_textsubc_"><input type=reset>,_texteom_)
+</form>
+}
+
+_changemaincfgfail_ {
+<html>
+<body bgcolor="\#ffffff" text="\#000000">
+_textftum_
+_footer_
+}
+
+_changemaincfgsuccess_ {
+<html>
+<body bgcolor="\#ffffff" text="\#000000">
+_textmus_
+_footer_
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/style.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/style.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/style.dm	(revision 10506)
@@ -0,0 +1,165 @@
+# this file must be UTF-8 encoded
+#######################################################################
+# PAGE STYLES 
+#######################################################################
+
+package Style
+
+# to use this style system output
+# _header_
+# all your page content, then
+# _footer_
+
+# use the page parameter 'style' to choose the appropriate style
+
+# the style system uses
+# _pagetitle_  - what gets displayed at the top of the browser window
+# _pagescriptextra_ - any extra javascript you want included in the header
+# _pagebannerextra_ - anything extra you want displayed in the page banner
+# _pagefooterextra_ - anything extra you want displayed in the footer
+
+# defaults for the above macros
+_pagetitle_ {_collectionname_}
+_pagescriptextra_ {}
+_pagebannerextra_ {}
+_pagefooterextra_ {}
+
+# it also relies on lots of Globals, the most important of these are:
+# _cookie_ - put in the cgi header
+# _globalscripts_ - javascript stuff
+# _httpiconchalk_ - the image down the left of the page
+# _imagecollection_
+# _imagehome_
+# _imagehelp_
+# _imagepref_
+# _imagethispage_
+# _linkotherversion_
+
+_header_ {_cgihead_
+_htmlhead_(background="_httpiconchalk_")_startspacer__pagebanner_
+}
+
+_header_[v=1] {_cgihead_
+_htmlhead__pagebanner_
+}
+
+# _cgihead_ {Content-type: text/html
+# _cookie_
+#
+# }	
+_cgihead_{}
+
+# htmlhead uses:
+# _1_ - extra parameters for the body tag
+# _pagetitle_
+# _globalscripts_
+_htmlhead_ {
+<html_htmlextra_>
+<head>
+<title>_pagetitle_</title>
+_globalscripts_
+</head>
+
+<body bgcolor="\#ffffff" text="\#000000" link="\#006666" 
+      alink="\#cc9900" vlink="\#666633" _1_>
+}
+
+
+_spacerwidth_ {65}
+
+# _startspacer_ is a spacer that gives pages a left-hand margin. 
+# It contains two open <table> tag which must eventually be closed 
+# by _endspacer_.
+_startspacer_ {
+<table border=0 cellspacing=0 cellpadding=0 width="100%">
+<tr><td valign=top width=_spacerwidth_><img src="_httpimg_/spacer.gif" width="_spacerwidth_" height="1" alt="" border="0"></td>
+<td><center><table width="_pagewidth_"><tr><td>
+}
+
+
+# pagebanner uses :
+# _imagecollection_ 
+# _imagehome_
+# _imagehelp_
+# _imagepref_
+# _imagethispage_
+# _pagebannerextra_
+_pagebanner_ {
+<!-- page banner (\_style:pagebanner\_) -->
+<center>
+<table width=_pagewidth_ cellspacing=0 cellpadding=0>
+  <tr valign=top>
+    <td rowspan=2 align=left>_imagecollection_</td>
+    <td align=right>_javalinks_</td>
+  </tr>
+
+  <tr>
+    <td align=right>_imagethispage_</td>
+  </tr>
+
+  <tr>
+    <td colspan=2>_pagebannerextra_</td>
+  </tr>
+</table>
+</center>
+<!-- end of page banner -->
+}
+
+_pagebanner_[v=1] {
+<!-- page banner - text version [v=1] (\_style:pagebanner\_) -->
+<center><h2><b><u>_imagecollection_</u></b></h2></center><p>
+_javalinks_
+_pagebannerextra_
+<p>
+<!-- end of page banner -->
+}
+
+# note we no longer close off one of the startspacer tables here!!
+_footer_ {
+<!-- page footer (\_style:footer\_) -->
+_pagefooterextra_
+_endspacer__htmlfooter_
+}
+
+# v=1 footer: not using startspacer in the header, so dont put it in the footer
+_footer_ [v=1]{
+<!-- page footer [v=1] (\_style:footer\_) -->
+_pagefooterextra_
+_htmlfooter_
+}
+
+# close off the tables opened by endspacer - note we close off both tables here
+_endspacer_ {	
+</td></tr></table></center>
+</td></tr></table>
+}	
+
+_htmlfooter_ {
+</body>
+</html>
+}
+
+_globalscripts_{
+<script>
+<!--
+_imagescript_
+_pagescriptextra_
+_usabilityscript_
+// -->
+</script>
+}
+
+_globalscripts_ [v=1] {
+<script>
+<!--
+_If_(_cgiargx_,_scriptdetach_)
+_pagescriptextra_
+// -->
+</script>
+}
+
+_scriptdetach_ {
+    function close\_detach() \{
+	close();
+    \}
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/thai.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/thai.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/thai.dm	(revision 10506)
@@ -0,0 +1,1237 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Thai Language text and icon macros 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=th] {àžàž²àž¡àžàž³àž«àžàžà¹àž§àž¥àž²}
+_textsource_ [l=th] {àž­à¹àž²àžàž­àžŽàžà¹àž«àž¥à¹àž}
+_textdate_ [l=th] {àž§àž±àžàžàžµàžàžŽàž¡àžà¹}
+_textnumpages_ [l=th] {à¹àž¡à¹àž¡àžµàžàž³àžàž§àžàž«àžà¹àž²}
+
+_textsignin_ [l=th] {àž¥àžàžàž°à¹àžàžµàž¢àž}
+
+_textdefaultcontent_ [l=th] {àž«àžà¹àž² àžàžµà¹àžàž­àž¡àž²à¹àž¡à¹àžªàž²àž¡àž²àž£àžà¹àžàžŽàžà¹àžà¹. àžàž£àžžàžàž²à¹àžà¹à¹àžàž£à¹àžàž£àž¡àžàžµà¹àžà¹àž§àž¢àžà¹àžàž«àž²àžàžàž­àžŽàžà¹àžàž­àž£à¹à¹àžàžàžàžµà¹àžàžžà¹àž¡ "àžàž­àž¢àž«àž¥àž±àž" àž«àž£àž·àž­à¹àž«àžàž·àž­àžàžžà¹àž¡à¹àž£àžŽà¹àž¡àžà¹àžà¹àžàž·à¹àž­àžàž¥àž±àžà¹àžàž¢àž±àžàž«à¹àž­àžàžªàž¡àžžàžàžàžŽàžàžŽàžàž­àž¥àžàž£àžµàžàžªà¹àžàž}
+
+_textdefaulttitle_ [l=th] {àžàžµà¹àž­àžªàžàžµà¹àž­àž¥àžàžŽàžàžàž¥àž²àž}
+
+# -- Missing translation: _textbadcollection_
+
+# -- Missing translation: _textselectpage_
+
+_collectionextra_ [l=th] {àžàž²àž£àž£àž§àž¡àžàž±àž§àžàž±àžàžàž£àž°àžàž­àžàžà¹àž§àž¢ _about:numdocs_ à¹àž­àžàžªàž²àž£. 
+àž¥à¹àž²àžªàžžàžàž¡àž±àžàžàž¹àžàžªàž£à¹àž²àžàžàž¶à¹àž _about:builddate_ àž«àž¥àž²àž¢àž§àž±àžàž¡àž²à¹àž¥à¹àž§.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=th] {<p>àžàž²àž£àž£àž§àž¡àžàž±àž§àžàž±àžàžàž£àž°àžàž­àžàžà¹àž§àž¢ _numdocs_ _If_("_numdocs_" eq "1",à¹àž­àžàžªàž²àž£,à¹àž­àžàžªàž²àž£), àžàž³àžàž§àžàžàž±à¹àžàž«àž¡àžàžàž­àž _numbytes_.
+<p><a href="_httppagex_(bsummary)">àžàž¥àžŽàžàžàžµà¹àžàžµà¹</a> à¹àžàž·à¹àž­àžàžŽàžàž²àž£àžàž²àžàž²àž£àžªàž£à¹àž²àžàžàž¥àžªàž£àžžàžàžàž­àžàžàž²àž£àž£àž§àž¡àžàž±àž§àžàž±àž
+}
+
+_textimagecollection_ [l=th] {}
+_textimageabout_ [l=th] {à¹àžàžµà¹àž¢àž§àžàž±àžàž«àžà¹àž²}
+_textimagehome_ [l=th] {àž«àžà¹àž²à¹àž£àž}
+_textimagehelp_ [l=th] {àž«àžà¹àž²àžà¹àž§àž¢à¹àž«àž¥àž·àž­}
+_textimagepref_ [l=th] {àž«àžà¹àž²àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©}
+_textimagegreenstone_ [l=th] {àžàž­àžàžà¹à¹àž§àž£à¹àž«à¹àž­àžàžªàž¡àžžàžàžàžŽàžàžŽàžàž­àž¥àžàž£àžµàžàžªà¹àžàž}
+_textimageusab_ [l=th] {àž­àž°à¹àž£àžàžµà¹àžàžžàžàžà¹àžàž«àž²à¹àž¥àž°àž¢àž²àžàžàžµà¹àžàž°à¹àžà¹}
+
+_textimagesearch_ [l=th] {àžªàž·àžàžà¹àžàž£àž°àž¢àž°à¹àž§àž¥àž²àžàžµà¹àžàž³àž«àžàžàž­àž¢à¹àž²àžà¹àžàžàž²àž°à¹àžàž²àž°àžàž}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=th] {àžà¹àžàž«àž²àžàž·à¹àž­à¹àž£àž·à¹àž­àžàžàž²àž¡àž£àž²àž¢àžàž·à¹àž­àžàž±àž§àž­àž±àžàž©àž£}
+_textimageCreator_ [l=th] {àžà¹àžàž«àž²àž£àž²àž¢àžàž·à¹àž­àžšàžŽàž¥àžàžŽàžàžàž²àž¡àžàž±àž§àž­àž±àžàž©àž£}
+_textimageSubject_ [l=th] {àžà¹àžàž«àž²à¹àžàž¢à¹àž¢àžàž«àž¡àž§àžàž«àž¡àž¹à¹àžàž²àž¡àž«àž±àž§àžà¹àž­}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=th] {àžà¹àžàž«àž²àž§àž±àžàžàžµà¹}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=th] {àžà¹àžàž«àž²à¹àžàž¢àžàž·à¹àž­à¹àž­àžàžªàž²àž£àžà¹àžàžàžàž±àž}
+_textimageLanguage_ [l=th] {àžà¹àžàž«àž²à¹àžàž¢àž àž²àž©àž²}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=th] {àžà¹àžàž«àž²àž­àžàžà¹àžàž£}
+_textimageKeyword_ [l=th] {àžà¹àžàž«àž²à¹àžàž¢àž£àž«àž±àžªàžàž³}
+_textimageHowto_ [l=th] {àžà¹àžàž«àž²àžàž²àž£à¹àž¢àžàž«àž¡àž§àžàž«àž¡àž¹à¹àž­àž¢à¹àž²àžà¹àž£}
+_textimageList_ [l=th] {àžà¹àžàž«àž²àž£àž²àž¢àžàž·à¹àž­à¹àž­àžàžªàž²àž£}
+_textimageSeries_ [l=th] {àžà¹àžàž«àž²à¹àžàž¢àžàž£àž°à¹àžà¹àž}
+_textimageTo_ [l=th] {àžà¹àžàž«àž²à¹àžàž¢àž­àž²àžàž²à¹àžàž}
+_textimageFrom_ [l=th] {àžà¹àžàž«àž²àžàž²àžàž­àž²àžàž²à¹àžàž}
+_textimageTopic_ [l=th] {àžà¹àžàž«àž²àžàž£àž°à¹àžà¹àžàž«àž±àž§àžà¹àž­àžàžŽà¹àžšàž©}
+_textimageBrowse_ [l=th] {àžà¹àžàž«àž²}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=th] {àžà¹àžàž«àž²àžàžàžàž²àž¡àž£àž²àž¢àžàž·à¹àž­àžàž±àž§àž­àž±àžàž©àž£}
+_textimageAcronym_ [l=th] {àžà¹àžàž«àž²àžàž±àž§àž¢à¹àž­}
+_textimagePhrase_ [l=th] {àžà¹àžàž«àž²àž§àž¥àžµ}
+_textimageArtist_ [l=th] {àžà¹àžàž«àž²àžšàžŽàž¥àžàžŽàž}
+_textimageVolume_ [l=th] {àžà¹àžàž«àž²à¹àžàž¢à¹àžªàžµàž¢àž}
+# -- Missing translation: _textimageCountries_
+# -- Missing translation: _textimageCaptions_
+
+
+_texticontabsearchgreen_ [l=th] {àžªàž·àžàžà¹àž}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=th] {àžàž·à¹àž­à¹àž£àž·à¹àž­àž à¹àž­àžàž¶àžà¹àžàž}
+_texticontabCreatorgreen_ [l=th] {àžàž±àžàžàž£àž°àžàž±àžàžà¹ à¹àž­àžàž¶àžà¹àžàž}
+_texticontabSubjectgreen_ [l=th] {àž«àž±àž§àžà¹àž­}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=th] {àž§àž±àžàžàžµà¹}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=th] {àžàž·à¹àž­à¹àžàž¥à¹}
+_texticontabLanguagegreen_ [l=th] {àž àž²àž©àž²}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=th] {àž­àžàžà¹àžàž£}
+_texticontabKeywordgreen_ [l=th] {àžàž³àž£àž«àž±àžª}
+_texticontabhowgreen_ [l=th] {àž­àž¢à¹àž²àžà¹àž£}
+_texticontabseriesgreen_ [l=th] {àž­àžàžžàžàž£àž¡}
+_texticontablistgreen_ [l=th] {àžàž²àž£àž£àž§àžàž£àž§àž¡àž£àž²àž¢àžàž·à¹àž­}
+_texticontabtogreen_ [l=th] {àžàž¶àž}
+_texticontabfromgreen_ [l=th] {àžàž²àž}
+_texticontabtopicgreen_ [l=th] {àž«àž±àž§àžà¹àž­}
+_texticontabbrwsegreen_ [l=th] {àžà¹àžàž«àž²}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=th] {àžà¹àžàž«àž²}
+_texticontabPeoplegreen_ [l=th] {àžàž à¹àž­àžàž¶àžà¹àžàž}
+_texticontabAcronymgreen_ [l=th] {àžàž±àž§àž¢à¹àž­}
+_texticontabPhrasegreen_ [l=th] {àž§àž¥àžµ}
+_texticontabArtistgreen_ [l=th] {àžšàžŽàž¥àžàžŽàž}
+_texticontabVolumegreen_ [l=th] {à¹àžªàžµàž¢àž}
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=th] {àžàžŽàžàž²àž£àžàž²à¹àž­àžàžªàž²àž£}
+_texticonclosedbook_ [l=th] {à¹àžàžŽàžà¹àž­àžàžªàž²àž£àžàžµà¹à¹àž¥àž°àžàžŽàžàž²àž£àžàž²à¹àžàž·à¹àž­àž«àž²}
+_texticonnext_ [l=th] {àž«àž¡àž§àžàžàž±àžà¹àž}
+_texticonprev_ [l=th] {àž«àž¡àž§àžàžà¹àž­àžàž«àžà¹àž²àžàžµà¹}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=th] {àžàžŽàžàž²àž£àžàž²à¹àž­àžàžªàž²àž£àž¡àžŽàžàžŽ}
+_texticonmsword_ [l=th] {àžàžŽàžàž²àž£àžàž²à¹àž­àžàžªàž²àž£à¹àž¡à¹àžàž£àžàž­àžàžà¹à¹àž§àžŽàž£à¹àž}
+# -- Missing translation: _texticonmp3_
+_texticonpdf_ [l=th] {àžàžŽàžàž²àž£àžàž²à¹àž­àžàžªàž²àž£àžàžµàžàžµà¹àž­àž}
+_texticonps_ [l=th] {àžàžŽàžàž²àž£àžàž²à¹àž­àžàžªàž²àž£àžàž³àž¥àžàžà¹àž²àž¢}
+_texticonppt_ [l=th] {àžàžŽàžàž²àž£àžàž²à¹àž­àžàžªàž²àž£àžàž²àž§à¹àž§àž­àž£à¹àžàž­àž¢àžà¹}
+_texticonrtf_ [l=th] {àžàžŽàžàž²àž£àžàž²à¹àž­àžàžªàž²àž£àž­àž²àž£à¹àžàžµà¹àž­àž}
+_texticonxls_ [l=th] {àžàžŽàžàž²àž£àžàž²à¹àž­àžàžªàž²àž£à¹àž¡à¹àžàž£àžàž­àžàžà¹à¹àž­àžà¹àžàž¥}
+
+_page_ [l=th] {àž«àžà¹àž²}
+_pages_ [l=th] {àž«àžà¹àž²}
+_of_ [l=th] {àžàž­àž}
+_vol_ [l=th] {à¹àžªàžµàž¢àž}
+_num_ [l=th] {àž«àž¡àž²àž¢à¹àž¥àž}
+
+_textmonth00_ [l=th] {}
+_textmonth01_ [l=th] {àž¡àžàž£àž²àžàž¡}
+_textmonth02_ [l=th] {àžàžžàž¡àž àž²àžàž±àžàžà¹}
+_textmonth03_ [l=th] {àž¡àžµàžàž²àžàž¡}
+_textmonth04_ [l=th] {à¹àž¡àž©àž²àž¢àž}
+_textmonth05_ [l=th] {àžàž€àž©àž àž²àžàž¡}
+_textmonth06_ [l=th] {àž¡àžŽàžàžžàžàž²àž¢àž}
+_textmonth07_ [l=th] {àžàž£àžàžàž²àžàž¡}
+_textmonth08_ [l=th] {àžªàžŽàžàž«àž²àžàž¡}
+_textmonth09_ [l=th] {àžàž±àžàž¢àž²àž¢àž}
+_textmonth10_ [l=th] {àžàžžàž¥àž²àžàž¡}
+_textmonth11_ [l=th] {àžàž€àžšàžàžŽàžàž²àž¢àž}
+_textmonth12_ [l=th] {àžàž±àžàž§àž²àžàž¡}
+
+# -- Missing translation: _textdocument_
+# -- Missing translation: _textsection_
+# -- Missing translation: _textparagraph_
+
+_magazines_ [l=th] {àžàžŽàžàž¢àžªàž²àž£}
+
+_nzdlpagefooter_ [l=th] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">à¹àžàž£àžàžàž²àž£àž«à¹àž­àžàžªàž¡àžžàžàžàžŽàžàžŽàžàž­àž¥àžàžŽàž§àžàžµà¹àž¥àžàžà¹</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">à¹àžàžàžàž§àžŽàžàž¢àž²àžšàž²àžªàžàž£à¹àžàž­àž¡àžàžŽàž§à¹àžàž­àž£à¹</a>, 
+<a href="http://www.waikato.ac.nz">àž¡àž«àž²àž§àžŽàžàž¢àž²àž¥àž±àž¢à¹àž§àžàž²à¹àžàž°</a>, 
+àžàžŽàž§àžàžµà¹àž¥àžàžà¹}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "àž«àžà¹àž²à¹àž£àž" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=th] {_httpimg_/th/chomeof.gif}
+_httpiconchomeon_ [l=th] {_httpimg_/th/chomeon.gif}
+
+## "àžà¹àž§àž¢à¹àž«àž¥àž·àž­" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=th] {_httpimg_/th/chelpof.gif}
+_httpiconchelpon_ [l=th] {_httpimg_/th/chelpon.gif}
+
+## "àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=th] {_httpimg_/th/cprefof.gif}
+_httpiconcprefon_ [l=th] {_httpimg_/th/cprefon.gif}
+
+## "àžªà¹àžàžàž¥àžªàž°àžà¹àž­àžàžàž¥àž±àž" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=th] {_httpimg_/th/cusabof.gif}
+_httpiconcusabon_ [l=th] {_httpimg_/th/cusabon.gif}
+
+
+## "àžªàž·àžàžà¹àž" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=th] {_httpimg_/th/tsrchgr.gif}
+_httpicontsrchof_ [l=th] {_httpimg_/th/tsrchof.gif}
+_httpicontsrchon_ [l=th] {_httpimg_/th/tsrchon.gif}
+_widthtsrchx_ [l=th] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "àžàž·à¹àž­à¹àž£àž·à¹àž­àž à¹àž­àžàž¶àžà¹àžàž" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=th] {_httpimg_/th/ttitlgr.gif}
+_httpiconttitleof_ [l=th] {_httpimg_/th/ttitlof.gif}
+_httpiconttitleon_ [l=th] {_httpimg_/th/ttitlon.gif}
+_widthttitlex_ [l=th] {98}
+
+# Not true DC, kept for legacy reasons
+## "àžàž±àžàžàž£àž°àžàž±àžàžà¹ à¹àž­àžàž¶àžà¹àžàž" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=th] {_httpimg_/th/tauthgr.gif}
+_httpicontcreatof_ [l=th] {_httpimg_/th/tauthof.gif}
+_httpicontcreaton_ [l=th] {_httpimg_/th/tauthon.gif}
+_widthtcreatx_ [l=th] {121}
+
+## "àž«àž±àž§àžà¹àž­" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=th] {_httpimg_/th/tsubjgr.gif}
+_httpicontsubjon_ [l=th] {_httpimg_/th/tsubjon.gif}
+_httpicontsubjof_ [l=th] {_httpimg_/th/tsubjof.gif}
+_widthtsubjx_ [l=th] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "àž§àž±àžàžàžµà¹" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=th] {_httpimg_/th/tdategr.gif}
+_httpicontdateof_ [l=th] {_httpimg_/th/tdateof.gif}
+_httpicontdateon_ [l=th] {_httpimg_/th/tdateon.gif}
+_widthtdatex_ [l=th] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "àžàž·à¹àž­à¹àžàž¥à¹" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=th] {_httpimg_/th/tsrcgr.gif}
+_httpicontsrcof_ [l=th] {_httpimg_/th/tsrcof.gif}
+_httpicontsrcon_ [l=th] {_httpimg_/th/tsrcon.gif}
+_widthtsrcx_ [l=th] {87}
+
+## "àž àž²àž©àž²" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=th] {_httpimg_/th/tlanggr.gif}
+_httpicontlangon_ [l=th] {_httpimg_/th/tlangon.gif}
+_httpicontlangof_ [l=th] {_httpimg_/th/tlangof.gif}
+_widthtlangx_ [l=th] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "àž­àžàžžàžàž£àž¡" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=th] {_httpimg_/th/tsergr.gif}
+_httpicontserof_ [l=th] {_httpimg_/th/tserof.gif}
+_httpicontseron_ [l=th] {_httpimg_/th/tseron.gif}
+_widthtserx_ [l=th] {87}
+
+## "àžàž¶àž" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=th] {_httpimg_/th/ttogr.gif}
+_httpiconttoon_ [l=th] {_httpimg_/th/ttoon.gif}
+_httpiconttoof_ [l=th] {_httpimg_/th/ttoof.gif}
+_widthttox_ [l=th] {87}
+
+## "àžàž²àž" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=th] {_httpimg_/th/tfromgr.gif}
+_httpicontfromon_ [l=th] {_httpimg_/th/tfromon.gif}
+_httpicontfromof_ [l=th] {_httpimg_/th/tfromof.gif}
+_widthtfromx_ [l=th] {87}
+
+## "àž­àžàžà¹àžàž£" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=th] {_httpimg_/th/torggr.gif}
+_httpicontorgon_ [l=th] {_httpimg_/th/torgon.gif}
+_httpicontorgof_ [l=th] {_httpimg_/th/torgof.gif}
+_widthtorgx_ [l=th] {87}
+
+## "àž­àž¢à¹àž²àžà¹àž£" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=th] {_httpimg_/th/thowgr.gif}
+_httpiconthowon_ [l=th] {_httpimg_/th/thowon.gif}
+_httpiconthowof_ [l=th] {_httpimg_/th/thowof.gif}
+_widththowx_ [l=th] {87}
+
+## "àž«àž±àž§àžà¹àž­" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=th] {_httpimg_/th/ttopicgr.gif}
+_httpiconttopicon_ [l=th] {_httpimg_/th/ttopicon.gif}
+_httpiconttopicof_ [l=th] {_httpimg_/th/ttopicof.gif}
+_widthttopicx_ [l=th] {87}
+
+## "àžà¹àžàž«àž²" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=th] {_httpimg_/th/tbrwsegr.gif}
+_httpicontbrwseon_ [l=th] {_httpimg_/th/tbrwseon.gif}
+_httpicontbrwseof_ [l=th] {_httpimg_/th/tbrwseof.gif}
+_widthtbrwsex_ [l=th] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "àžàž" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=th] {_httpimg_/th/tpeopgr.gif}
+_httpicontpeopof_ [l=th] {_httpimg_/th/tpeopof.gif}
+_httpicontpeopon_ [l=th] {_httpimg_/th/tpeopon.gif}
+_widthtpeopx_ [l=th] {87}
+
+## "àžàž±àž§àž¢à¹àž­" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=th] {_httpimg_/th/tacrogr.gif}
+_httpicontacroof_ [l=th] {_httpimg_/th/tacroof.gif}
+_httpicontacroon_ [l=th] {_httpimg_/th/tacroon.gif}
+_widthtacrox_ [l=th] {87}
+
+## "àž§àž¥àžµ" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=th] {_httpimg_/th/tphrsegr.gif}
+_httpicontphrseof_ [l=th] {_httpimg_/th/tphrseof.gif}
+_httpicontphrseon_ [l=th] {_httpimg_/th/tphrseon.gif}
+_widthtphrsex_ [l=th] {87}
+
+## "àžšàžŽàž¥àžàžŽàž" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=th] {_httpimg_/th/tartstgr.gif}
+_httpicontartstof_ [l=th] {_httpimg_/th/tartstof.gif}
+_httpicontartston_ [l=th] {_httpimg_/th/tartston.gif}
+_widthtartstx_ [l=th] {87}
+
+## "àž£àž«àž±àžªàžàž³" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=th] {_httpimg_/th/tkwgr.gif}
+_httpicontkwof_ [l=th] {_httpimg_/th/tkwof.gif}
+_httpicontkwon_ [l=th] {_httpimg_/th/tkwon.gif}
+_widthtkwx_ [l=th] {87}
+
+## "à¹àžªàžµàž¢àž" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=th] {_httpimg_/th/tvolgr.gif}
+_httpicontvolof_ [l=th] {_httpimg_/th/tvolof.gif}
+_httpicontvolon_ [l=th] {_httpimg_/th/tvolon.gif}
+_widthtvolx_ [l=th] {87}
+
+# -- Missing translation: tcapt
+# -- Missing translation: _httpicontcaptgr_
+# -- Missing translation: _httpicontcaptof_
+# -- Missing translation: _httpicontcapton_
+# -- Missing translation: _widthtcaptx_
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "àžà¹àž§àž¢à¹àž«àž¥àž·àž­" ## green_title ## h_help ##
+_httpiconhhelp_ [l=th] {_httpimg_/th/h\_help.gif}
+_widthhhelp_ [l=th] {200}
+_heighthhelp_ [l=th] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=th] {à¹àžàžµà¹àž¢àž§àžàž±àžàžàž²àž£àž£àž§àž¡àžàž±àž§àžàž±àž}
+
+_textsubcols1_ [l=th] {<p>àžàž²àž£àž£àž§àž¡àžàž±àž§àžàž±àžàžàžµà¹àžªàž¡àžàž¹àž£àžà¹àžàž£àž°àžàž­àžàžà¹àž§àž¢ _1_ àž«àž±àž§àžà¹àž­àž¢à¹àž­àž¢àžàž­àžàžàž²àž£àž£àž§àž¡àžàž±àž§àžàž±àž. 
+à¹àžàž§à¹àžà¹àž¡à¹àž«àž¥à¹àž²àžàž±à¹àžàžªàž²àž¡àž²àž£àžà¹àžà¹àžàž£àž°à¹àž¢àžàžà¹à¹àžà¹àžàž·àž­:
+<blockquote>}
+
+_textsubcols2_ [l=th] {</blockquote>
+àžàžžàžàžªàž²àž¡àž²àž£àžàžàž£àž§àžàžªàž­àž (à¹àž¥àž°àžàž£àž±àžà¹àžàž¥àžµà¹àž¢àž) àžàž¶à¹àžàž«àž±àž§àžà¹àž­àž¢à¹àž­àž¢àžàž­àžàžàž²àž£àž£àž§àž¡àžàž±àž§àžàž±àžàžàž±à¹àž àžàžžàžàžàž³àž¥àž±àžà¹àžà¹àž«àžà¹àž²àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©àž­àž¢àž¹à¹ 
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "à¹àžàžµà¹àž¢àž§àžàž±àž" ## green_title ## h_about ##
+_httpiconhabout_ [l=th] {_httpimg_/th/h\_about.gif}
+_widthhabout_ [l=th] {200}
+_heighthabout_ [l=th] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=th] {àžàž·à¹àž­à¹àž£àž·à¹àž­àž à¹àž­àžàž¶àžà¹àžàž}
+_texticonhcreat_ [l=th] {àžàž¹à¹à¹àžàžµàž¢àž à¹àž­àžàž¶àžà¹àžàž}
+_texticonhsubj_ [l=th] {à¹àž£àž·à¹àž­àž}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=th] {àž§àž±àžàžàžµà¹}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=th] {àžàž·à¹àž­à¹àžàž¥à¹}
+_texticonhlang_ [l=th] {àž àž²àž©àž²}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=th] {àžàž¶àž}
+_texticonhfrom_ [l=th] {àžàž²àž}
+_texticonhser_ [l=th] {àž­àžàžžàžàž£àž¡}
+_texticonhhow_ [l=th] {àž­àž¢à¹àž²àžà¹àž£}
+_texticonhorg_ [l=th] {àž­àžàžà¹àžàž£}
+_texticonhbrwse_ [l=th] {àžà¹àžàž«àž²}
+_texticonhbrows_ [l=th] {àžà¹àžàž«àž²}
+_texticonhpeople_ [l=th] {àžàž à¹àž­àžàž¶àžà¹àžàž}
+_texticonhacronym_ [l=th] {àžàž±àž§àž¢à¹àž­}
+_texticonhphrases_ [l=th] {àž§àž¥àžµ}
+_texticonhartist_ [l=th] {àžšàžŽàž¥àžàžŽàž}
+_texticonhkw_ [l=th] {àž£àž«àž±àžªàžàž³}
+_texticonhvol_ [l=th] {à¹àžªàžµàž¢àž}
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=th] {àžàžŽàžàž«à¹àž­àžàžªàž¡àžžàžàžàž­àžàž«àž¡àž§àžàžàžµà¹}
+_texticonclosedbookshelf_ [l=th] {à¹àžàžŽàžàž«à¹àž­àžàžªàž¡àžžàžàžàž­àžàžàž£àž°à¹àž àžàžàžµà¹à¹àž¥àž°àžàžŽàžàž²àž£àžàž²à¹àžàž·à¹àž­àž«àž²àžªàž²àž£àž°}
+_texticonopenbook_ [l=th] {àžàžŽàžàž«àžàž±àžàžªàž·àž­àžàžµà¹}
+_texticonclosedfolder_ [l=th] {à¹àžàžŽàžàžàžµà¹à¹àžà¹àžà¹àž­àžàžªàž²àž£àžàžµà¹à¹àž¥àž°àžàžŽàžàž²àž£àžàž²à¹àžàž·à¹àž­àž«àž²àžªàž²àž£àž°}
+_texticonclosedfolder2_ [l=th] {à¹àžàžŽàžàžàž£àž°à¹àž àžàž«àž±àž§àžà¹àž­àž¢à¹àž­àž¢}
+_texticonopenfolder_ [l=th] {àžàžŽàžàžàžµà¹à¹àžà¹àžà¹àž­àžàžªàž²àž£àžàžµà¹}
+_texticonopenfolder2_ [l=th] {àžàžŽàžàž«àž¡àž§àžàž«àž±àž§àžà¹àž­àž¢à¹àž­àž¢}
+_texticonsmalltext_ [l=th] {àžàžŽàžàž²àž£àžàž²àžàž³àžšàž±àžàžà¹àžàž­àžàž«àž¡àž§àžàžàžµà¹}
+_texticonsmalltext2_ [l=th] {àžàžŽàžàž²àž£àžàž²àžàž³àžšàž±àžàžà¹}
+_texticonpointer_ [l=th] {àž«àž¡àž§àžàžàž±àžàžàžžàžàž±àž}
+_texticondetach_ [l=th] {à¹àžàžŽàžàž«àžà¹àž²àžàžµà¹à¹àžàž«àžà¹àž²àžà¹àž²àžà¹àž«àž¡à¹}
+_texticonhighlight_ [l=th] {à¹àžà¹àžàžàž²àž£àžà¹àžàž«àž²àžàž³àžšàž±àžàžà¹}
+_texticonnohighlight_ [l=th] {à¹àž¡à¹à¹àžà¹àžàžàž²àž£àžà¹àžàž«àž²àžàž³àžšàž±àžàžà¹}
+_texticoncontracttoc_ [l=th] {àž¢àžžàžàžªàž²àž£àž°àžàž­àžàžàž²àž£àž²àž}
+_texticonexpandtoc_ [l=th] {àžàž¢àž²àž¢àžªàž²àž£àž°àžàž­àžàžàž²àž£àž²àž}
+_texticonexpandtext_ [l=th] {à¹àžªàžàžàžà¹àž­àž¢àžàž³àžàž±à¹àžàž«àž¡àž}
+_texticoncontracttext_ [l=th] {à¹àžªàžàžàžà¹àž­àž¢àžàž³à¹àžà¹àž²àžàž±à¹àžàžªàž³àž«àž£àž±àžàž«àž¡àž§àžàžàžµà¹à¹àž¥àž·àž­àžàžàž±àžàžàžžàžàž±àž}
+_texticonwarning_ [l=th] {<b>à¹àžàž·àž­àž: </b>}
+_texticoncont_ [l=th] {àžà¹àž­à¹àž«àž¡?}
+
+_textltwarning_ [l=th] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_àžàž¢àž²àž¢à¹àžàžàž§àž²àž¡àžàžµà¹àžàžµà¹àžàž°àžàž³à¹àž«à¹à¹àžàžŽàžàžà¹àž­àž¡àž¹àž¥àžàž±àž§à¹àž¥àžàžàž³àžàž§àžàž¡àž²àžàžàžµà¹àžàž°àžàž£àž²àžàžàžàžà¹àžàž£à¹àžàž£àž¡àžà¹àžàž«àž²àžà¹àž­àž¡àž¹àž¥ _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=th] {à¹àžàžàžµà¹àž«àžà¹àž²}
+_textintro_ [l=th] {<i>(àžàž³àžšàž±àžàžà¹àžàžµà¹à¹àžà¹àžàžàž²àž£à¹àžàž£àžŽà¹àžàžàž³)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "àžàž·à¹àž­à¹àž£àž·à¹àž­àž a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=th] {_httpimg_/th/h\_title.gif}
+_widthhtitle_ [l=th] {200}
+_heighthtitle_ [l=th] {57}
+
+# Not true DC, kept for legacy reasons
+## "àžàž¹à¹àžàž£àžàž±àžàžà¹ a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=th] {_httpimg_/th/h\_auth.gif}
+_widthhcreat_ [l=th] {200}
+_heighthcreat_ [l=th] {57}
+
+## "àžªàž²àžàž²àž§àžŽàžàž²" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=th] {_httpimg_/th/h\_subj.gif}
+_widthhsubj_ [l=th] {200}
+_heighthsubj_ [l=th] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "àž§àž±àžàžàžµà¹" ## green_title ## h_date ##
+_httpiconhdate_ [l=th] {_httpimg_/th/h\_date.gif}
+_widthhdate_ [l=th] {200}
+_heighthdate_ [l=th] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "àžàž·à¹àž­àž«àž¡àž§àžà¹àž­àžàžªàž²àž£" ## green_title ## h_src ##
+_httpiconhsrc_ [l=th] {_httpimg_/th/h\_src.gif}
+_widthhsrc_ [l=th] {200}
+_heighthsrc_ [l=th] {57}
+
+## "àž àž²àž©àž²" ## green_title ## h_lang ##
+_httpiconhlang_ [l=th] {_httpimg_/th/h\_lang.gif}
+_widthhlang_ [l=th] {200}
+_heighthlang_ [l=th] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "àžàž¶àž" ## green_title ## h_to ##
+_httpiconhto_ [l=th] {_httpimg_/th/h\_to.gif}
+_widthhto_ [l=th] {200}
+_heighthto_ [l=th] {57}
+
+## "àžàž²àž" ## green_title ## h_from ##
+_httpiconhfrom_ [l=th] {_httpimg_/th/h\_from.gif}
+_widthhfrom_ [l=th] {200}
+_heighthfrom_ [l=th] {57}
+
+## "àž¥àž³àžàž±àž" ## green_title ## h_ser ##
+_httpiconhser_ [l=th] {_httpimg_/th/h\_ser.gif}
+_widthhser_ [l=th] {200}
+_heighthser_ [l=th] {57}
+
+## "àžªàž­àžàž«àž£àž·àž­àž­àžàžŽàžàž²àž¢àž§àžŽàžàžµàžàž²àž£àžàž³" ## green_title ## h_how ##
+_httpiconhhow_ [l=th] {_httpimg_/th/h\_how.gif}
+_widthhhow_ [l=th] {200}
+_heighthhow_ [l=th] {57}
+
+## "àž«àž±àž§àžà¹àž­" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=th] {_httpimg_/th/h\_topic.gif}
+_widthhtopic_ [l=th] {200}
+_heighthtopic_ [l=th] {57}
+
+## "àž­àžàžà¹àžàž£" ## green_title ## h_org ##
+_httpiconhorg_ [l=th] {_httpimg_/th/h\_org.gif}
+_widthhorg_ [l=th] {250}
+_heighthorg_ [l=th] {57}
+
+## "à¹àž£àžµàž¢àžàžà¹àž­àž¡àž¹àž¥à¹àžàžàž²àž°àžªà¹àž§àžàžàž¶à¹àžàž¡àž²àžàž¹àž­àž¢à¹àž²àžàž£àž§àžà¹àž£à¹àž§" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=th] {_httpimg_/th/h\_brwse.gif}
+_widthhbrwse_ [l=th] {200}
+_heighthbrwse_ [l=th] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "àžàž£àž°àžàž²àžàž" ## green_title ## h_people ##
+_httpiconhpeople_ [l=th] {_httpimg_/th/h\_people.gif}
+_widthhpeople_ [l=th] {200}
+_heighthpeople_ [l=th] {57}
+
+## "àžàž³àž¢à¹àž­àžàž­àžàžàž¢àž±àžàžàžàž°àžàž±àž§à¹àž£àžàžàž­àžàž«àž¥àž²àž¢àžàž³àž¡àž²àž£àž§àž¡àžàž±àž" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=th] {_httpimg_/th/h\_acro.gif}
+_widthhacronym_ [l=th] {200}
+_heighthacronym_ [l=th] {57}
+
+## "àž§àž¥àžµ" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=th] {_httpimg_/th/h\_phrse.gif}
+_widthhphrse_ [l=th] {200}
+_heighthphrse_ [l=th] {57}
+
+## "àžàž±àžàžšàžŽàž¥àžàž°" ## green_title ## h_artist ##
+_httpiconhartist_ [l=th] {_httpimg_/th/h\_artist.gif}
+_widthhartist_ [l=th] {200}
+_heighthartist_ [l=th] {57}
+
+## "àžàž³à¹àžàž£àž«àž±àžª" ## green_title ## h_kw ##
+_httpiconhkw_ [l=th] {_httpimg_/th/h\_kw.gif}
+_widthhkw_ [l=th] {200}
+_heighthkw_ [l=th] {57}
+
+## "àžàž£àžŽàž¡àž²àž" ## green_title ## h_vol ##
+_httpiconhvol_ [l=th] {_httpimg_/th/h\_vol.gif}
+_widthhvol_ [l=th] {200}
+_heighthvol_ [l=th] {57}
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+# -- Missing translation: h_capt
+# -- Missing translation: _httpiconhcapt_
+# -- Missing translation: _widthhcapt_
+# -- Missing translation: _heighthcapt_
+
+
+## "àžà¹àž­à¹àžàž·à¹àž­àžàž«àž£àž·àž­à¹àž¡à¹?" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=th] {_httpimg_/th/contof.gif}
+_httpiconconton_ [l=th] {_httpimg_/th/conton.gif}
+
+## "àžàž¢àž²àž¢à¹àžàžàž§àž²àž¡" ## document_button ## eallt ##
+_httpiconealltof_ [l=th] {_httpimg_/th/ealltof.gif}
+_httpiconeallton_ [l=th] {_httpimg_/th/eallton.gif}
+
+## "à¹àžàž·à¹àž­àž«àž²àžàž­àžàžªàž±àžàžàž²" ## document_button ## econc ##
+_httpiconeconcof_ [l=th] {_httpimg_/th/econcof.gif}
+_httpiconeconcon_ [l=th] {_httpimg_/th/econcon.gif}
+
+## "àžàž­àžàž­àž­àž" ## document_button ## edtch ##
+_httpiconedtchof_ [l=th] {_httpimg_/th/edtchof.gif}
+_httpiconedtchon_ [l=th] {_httpimg_/th/edtchon.gif}
+
+## "àžàž¢àž²àž¢à¹àžàž·à¹àž­àž«àž²" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=th] {_httpimg_/th/eexpcof.gif}
+_httpiconeexpcon_ [l=th] {_httpimg_/th/eexpcon.gif}
+
+## "à¹àžàžàž§àž²àž¡àžàž­àžàžªàž±àžàžàž²" ## document_button ## etsec ##
+_httpiconetsecof_ [l=th] {_httpimg_/th/etsecof.gif}
+_httpiconetsecon_ [l=th] {_httpimg_/th/etsecon.gif}
+
+## "à¹àžà¹àž" ## document_button ## ehl ##
+_httpiconehlof_ [l=th] {_httpimg_/th/ehlof.gif}
+_httpiconehlon_ [l=th] {_httpimg_/th/ehlon.gif}
+
+## "à¹àž¡à¹à¹àžà¹àž" ## document_button ## enhl ##
+_httpiconenhlof_ [l=th] {_httpimg_/th/enhlof.gif}
+_httpiconenhlon_ [l=th] {_httpimg_/th/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=th] {_If_(_thislast_,results _thisfirst_ - _thislast_ for query: _cgiargq_,à¹àž¡à¹àž¡àžµàžàž³àžàž­àžàžàž£àžàžàž±àžàžàž³àžàž²àž¡: _cgiargq_)}
+_textnoquerytitle_ [l=th] {àžà¹àžàž«àž²àž«àžà¹àž²}
+
+_texticonthispage_ [l=th] {àžà¹àžàž«àž²}
+# -- Missing translation: _textsome_
+# -- Missing translation: _textall_
+# -- Missing translation: _textboolean_
+# -- Missing translation: _textranked_
+# -- Missing translation: _textnatural_
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=th] {}
+_texticonsearchhistorybar_ [l=th] {àžà¹àžàžàž£àž°àž§àž±àžàžŽ}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=th] {à¹àžà¹àžàž³àžàž²àž¡àžàžµà¹}
+_textfreqmsg1_ [l=th] {àžàž²àž£àžàž±àžàžàž³}
+_textpostprocess_ [l=th] {_If_(_quotedquery_,<br><i>àž§àžŽàžàžµàž¥à¹àž§àžàž«àžà¹àž²àžàžµà¹àžàž°àž«àž² _quotedquery_</i>
+)}
+# -- Missing translation: _textinvalidquery_
+
+_textmorethan_ [l=th] {àž¡àž²àžàžàž§à¹àž²}
+_textapprox_ [l=th] {à¹àžàžµàž¢àž§àžàž±àž}
+_textnodocs_ [l=th] {à¹àž¡à¹àž¡àžµà¹àž­àžàžªàž²àž£àžàž£àžàžàž±àžàžà¹àž­àžàž±àžàžàž²àž¡}
+_text1doc_ [l=th] {àž¡àžµà¹àž­àžàžªàž²àž£ 1 àžàžàž±àžàžàžµà¹àžàž£àžàžàž±àžàžà¹àž­àžàž±àžàžàž²àž¡}
+_textlotsdocs_ [l=th] {à¹àž­àžàžªàž²àž£àžàž£àžàžàž±àžàžà¹àž­àžàž±àžàžàž²àž¡}
+_textmatches_ [l=th] {àžàž£àžàžàž±àž}
+_textbeginsearch_ [l=th] {à¹àž£àžŽà¹àž¡àžàž²àž£àžà¹àžàž«àž²}
+_textrunquery_ [l=th] {à¹àž£àžµàž¢àžàž¥àž³àžàž±àžàžà¹àž­àžàž±àžàžàž²àž¡}
+_textclearform_ [l=th] {à¹àžàžàžàž­àž£à¹àž¡à¹àžàž¥à¹àž²}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=th] {àžàž³àž«àž£àž·àž­àž§àž¥àžµ}
+_textinfield_ [l=th] {âŠ à¹àžàžªàž²àžàž²}
+_textfoldstem_ [l=th] {(àžàž±àž àžà¹àž²àž)}
+
+_textadvquery_ [l=th] {àž«àž£àž·àž­à¹àžªà¹àžàž³àžàž²àž¡à¹àžàž¢àžàž£àž}
+_textallfields_ [l=th] {àžªàž²àžàž²àžàž±à¹àžàž«àž¡àž}
+# -- Missing translation: _texttextonly_
+_textand_ [l=th] {à¹àž¥àž°}
+_textor_ [l=th] {àž«àž£àž·àž­}
+_textandnot_ [l=th] {à¹àž¥àž°à¹àž¡à¹}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=th] {àžà¹àžàž«àž² _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, at _gselection_ level) _If_(_nselection_, in _nselection_ language) àžàž¶à¹àžàž¡àžµ _querytypeselection_ àžàž­àžàžàž³}
+
+_textadvancedsearch_ [l=th] {àžà¹àžàž«àž² _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, at _gselection_ level)_If_(_nselection_, in _nselection_ language) using _querytypeselection_ àžà¹àž­àžàž±àžàžàž²àž¡}
+
+# -- Missing translation: _textformsimplesearch_
+
+# -- Missing translation: _textformadvancedsearch_
+
+
+# -- Missing translation: _textnojsformwarning_
+_textdatesearch_ [l=th] {àžàž²àž£à¹àžà¹àžàž£àž§àžàž£àž§àž¡àžàžµà¹àžªàž²àž¡àž²àž£àžà¹àžà¹àžà¹àžàž«àž²à¹àž­àžàžªàž²àž£à¹àžà¹à¹àžàž¢àžàž§àž²àž¡àž«àž¥àž²àžàž«àž¥àž²àž¢àžàž­àžàž§àž±àžàžàžµà¹ àž«àž£àž·àž­à¹àž­àžàžªàž²àž£àžàžµà¹àž£àž°àžàžžàž§àž±àžàžàžµà¹à¹àžàžàž²àž°à¹àžàž²àž°àžàž àžàžµà¹àžàž·àž­àž¥àž±àžàž©àžàž°àž¢àžà¹àž§à¹àžàžàž­àžàžàž²àž£àžà¹àžàž«àž²}
+_textstartdate_ [l=th] {à¹àž£àžŽà¹àž¡ (àž«àž£àž·àž­à¹àžà¹à¹àžàžµàž¢àž) àž§àž±àžàžàžµà¹}
+_textenddate_ [l=th] {àž§àž±àžàžªàžŽà¹àžàžªàžžàž}
+_textbc_ [l=th] {àžàžµ àžàžµ àž­àžµ}
+_textad_ [l=th] {àžàžµ.àž­àžµ.}
+_textexplaineras_ [l=th] {C.E. à¹àž¥àž° B.C.E à¹àžà¹àžàžàž±àž§à¹àž¥àž·àž­àžàžªàž³àž«àž£àž±àž  A.D. à¹àž¥àž° B.C. àžàž²àž¡àž¥àž³àžàž±àž  àžàž³à¹àž«àž¥à¹àž²àžàžµà¹àžàž·àž­à¹àžà¹àžàž§àž±àžàžàžàž£àž£àž¡àžàžµà¹à¹àž¡à¹àž¡àžµàžàž§àž²àž¡à¹àžàžàžà¹àž²àž à¹àž¥àž°àž¢à¹àž­àž¡àž²àžàž²àž "Common Era" à¹àž¥àž° "Before the Common Era"These terms are considered to be culture indiscriminate, and stand for "Common Era" and "Before the Common Era"}
+
+_textstemon_ [l=th] {(à¹àž¡à¹àžà¹àž­àžàžªàžà¹àžàžàž³àž§à¹àž² endings)}
+
+_textsearchhistory_ [l=th] {àžà¹àžàžàž£àž°àž§àž±àžàžŽ}
+
+#text macros for search history
+_textnohistory_ [l=th] {à¹àž¡à¹àžªàž²àž¡àž²àž£àžà¹àž«à¹àžàž²àž£à¹àžà¹àžàž²àž£àžà¹àžàžàž£àž°àž§àž±àžàžŽà¹àžà¹}
+_texthresult_ [l=th] {àžàž¥àž¥àž±àžàžà¹}
+_texthresults_ [l=th] {àžàž¥àž¥àž±àžàžà¹}
+_texthallwords_ [l=th] {àžàž³àžàž±à¹àžàž«àž¡àž}
+_texthsomewords_ [l=th] {àžàž²àžàžàž³}
+# -- Missing translation: _texthboolean_
+_texthranked_ [l=th] {à¹àž£àžµàž¢àžàž¥àž³àžàž±àž}
+_texthcaseon_ [l=th] {àžàž£àžàžµàžà¹àž­àžàžàž£àžàžàž±àž}
+# -- Missing translation: _texthcaseoff_
+_texthstemon_ [l=th] {àžàž¶à¹àžàž¡àžµàžà¹àž²àž}
+_texthstemoff_ [l=th] {àžàž¶à¹àžà¹àž¡à¹àž¡àžµàžà¹àž²àž}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "àžà¹àžàž«àž²" ## green_title ## h_search ##
+_httpiconhsearch_ [l=th] {_httpimg_/th/h\_search.gif}
+_widthhsearch_ [l=th] {200}
+_heighthsearch_ [l=th] {57}
+
+## "àžàž¥àž¥àž±àžàžà¹" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=th] {_httpimg_/th/qryresb.gif}
+_widthqryresb_ [l=th] {_pagewidth_}
+_heightqryresb_ [l=th] {17}
+
+## "àžàž£àž°àž§àž±àžàžŽ" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=th] {_httpimg_/th/schhistb.gif}
+_widthsrchhistb_ [l=th] {_pagewidth_}
+_heightsrchhistb_ [l=th] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=th] {àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©à¹àžà¹àžàž¹àžàžàž±à¹àžà¹àž§à¹àžàž±àžàžàžµà¹  àž«à¹àž²àž¡à¹àžà¹àžàžžà¹àž¡ browser back à¹àžàžàž²àž£àžà¹àžàž«àž² àž¡àž±àžàžàž°àžàž³à¹àž«à¹àž£àž°àžàžàžàžµà¹àžàž±à¹àžà¹àž§à¹àžªàž¹àžàž«àž²àž¢
+à¹àžà¹à¹àž«à¹à¹àžà¹àžàž²àž£àžàžàžàžžà¹àž¡àž«àžàž¶à¹àžàžàž£àž±à¹àžàžàžµà¹ access bar àžà¹àž²àžàžàžà¹àžàž
+}
+_textsetprefs_ [l=th] {àžªàž£à¹àž²àžàžªàžŽàžàžàžŽàžàžŽà¹àžšàž©}
+_textsearchprefs_ [l=th] {àžà¹àžàž«àž²àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©}
+_textcollectionprefs_ [l=th] {àžàž²àž£à¹àžà¹àžàž£àž§àžàž£àž§àž¡àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©}
+_textpresentationprefs_ [l=th] {à¹àžªàžàžàžªàžŽàžàžàžŽàžàžŽà¹àžšàž©}
+_textpreferences_ [l=th] {àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©}
+_textcasediffs_ [l=th] {àžàž£àžàžµàžàžµà¹à¹àžàžàžà¹àž²àžàžàž±àž}
+_textignorecase_ [l=th] {à¹àž¡à¹àžªàžà¹àžàžàž£àžàžµàžàžµà¹à¹àžàžàžà¹àž²àžàžàž±àž}
+_textmatchcase_ [l=th] {àžàž£àžàžµàžàžµà¹àžªàž¹àžàžàž§à¹àž²àž«àž£àž·àž­àžà¹àž³àžàž§à¹àž²àžà¹àž­àžàžàž£àžàžàž±àž}
+_textwordends_ [l=th] {àžàž³àž¥àžàžà¹àž²àž¢}
+_textstem_ [l=th] {àž¡àž­àžàžà¹àž²àž¡àžàž³àž¥àžàžà¹àž²àž¢}
+_textnostem_ [l=th] {àžàž³àžàžžàžàžàž³àžà¹àž­àžàžàž£àžàžàž±àž}
+_textprefop_ [l=th] {àžàž¥àž±àžà¹àžàžàžµà¹ _maxdocoption_ hits with _hitsperpageoption_ hits à¹àžà¹àž¥àž°àž«àžà¹àž²}
+_textextlink_ [l=th] {à¹àžà¹àž²àžªàž¹à¹àž«àžà¹àž²àžàž­à¹àž§à¹àžà¹àžàžà¹}
+_textintlink_ [l=th] {à¹àž£àžµàž¢àžà¹àž«àž¥à¹àžà¹àž­àžàžªàž²àž£àžàž¥àž±àžàž¡àž²àžàž²àž}
+_textlanguage_ [l=th] {àž àž²àž©àž² Interface}
+_textencoding_ [l=th] {à¹àžªà¹àž£àž«àž±àžª}
+_textformat_ [l=th] {àžàž²àž£àžàž±àžàžà¹àž­àž¡àž¹àž¥à¹àžàž interface}
+_textall_ [l=th] {àžàž±à¹àžàž«àž¡àž}
+_textquerymode_ [l=th] {à¹àžàžàžà¹àž­àžàž±àžàžàž²àž¡}
+_textsimplemode_ [l=th] {à¹àžàžàžàž­àžàžà¹àž­àžàž±àžàžàž²àž¡àž­àž¢à¹àž²àžàžàž£àž£àž¡àžàž²}
+_textadvancedmode_ [l=th] {àž§àžŽàžà¹àžàž²àž£àžàž­àžàžà¹àž­àžàž±àžàžàž²àž¡à¹àžàžàž¥à¹àž³àž«àžà¹àž² ( àžªàž²àž¡àž²àž£àžà¹àžà¹àžàž²àž£àžà¹àžàž«àž²à¹àžàž boolean à¹àžà¹à¹àžàž¢à¹àžà¹ !, &, I à¹àž¥àž° àž§àžà¹àž¥à¹àž)}
+_textlinkinterm_ [l=th] {àžà¹àž²àžàž«àžà¹àž²àžàž¥àž²àž}
+_textlinkdirect_ [l=th] {à¹àžàžàžµà¹àžàž±à¹àžà¹àžàž¢àžàž£àž}
+_textdigitlib_ [l=th] {àž«à¹àž­àžàžªàž¡àžžàž digital}
+_textweb_ [l=th] {à¹àž§à¹àžà¹àžàžà¹}
+_textgraphical_ [l=th] {à¹àžàžµà¹àž¢àž§àžàž±àžàž àž²àž}
+_texttextual_ [l=th] {à¹àžàžµà¹àž¢àž§àžàž±àžàžà¹àžàžàžàž±àžàž«àž£àž·àž­àžà¹àž­àž¢àžàž³à¹àžàžŽàž¡}
+_textcollectionoption_ [l=th] {<p>
+àžàž²àž£à¹àžà¹àžàžªàž°àžªàž¡àž¢à¹àž­àž¢à¹àžàž·à¹àž­àž£àž§àž¡:
+<br>}
+
+_textrelateddocdisplay_ [l=th] {à¹àžªàžàžà¹àž­àžàžªàž²àž£àžàžµà¹à¹àžàžµà¹àž¢àž§àžà¹àž­àž}
+_textsearchhistory_ [l=th] {àžà¹àžàžàž£àž°àž§àž±àžàžŽ}
+_textnohistory_ [l=th] {à¹àž¡à¹àžà¹àžàžàž£àž°àž§àž±àžàžŽ}
+_texthistorydisplay_ [l=th] {à¹àžªàžàž _historynumrecords_ àžàž±àžàžàž¶àžàžàž²àž£àžà¹àžàž«àž²àžàž£àž°àž§àž±àžàžŽ}
+_textnohistorydisplay_ [l=th] {à¹àž¡à¹à¹àžªàžàžàžàž²àž£àžà¹àžàžàž£àž°àž§àž±àžàžŽ}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+# -- Missing translation: _textformsearch_
+# -- Missing translation: _textplainsearch_
+_textqueryboxsize_ [l=th] {àžàžàž²àžàžàž¥à¹àž­àžàžà¹àž­àžàž±àžàžàž²àž¡}
+_textregbox_ [l=th] {àžàž¥à¹àž­àžàžà¹àž­àžàž±àžàžàž²àž¡à¹àžàž¢àžàž£àž°àžàž³}
+_textbigbox_ [l=th] {àžàž¥à¹àž­àžàžà¹àž­àžàž±àžàžàž²àž¡àžàž¥à¹àž­àžà¹àž«àžà¹}
+_textformtype_ [l=th] {àžàžàžŽàžàžàž­àžàž£àž¹àžà¹àžàž}
+_textsimple_ [l=th] {àžàž£àž£àž¡àžàž²}
+_textadvanced_ [l=th] {àž¥à¹àž³àž«àžà¹àž²}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=th] {àžà¹àž§àž¢}
+_textfields_ [l=th] {àžªàž²àžàž²}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©" ## green_title ## h_pref ##
+_httpiconhpref_ [l=th] {_httpimg_/th/h\_pref.gif}
+_widthhpref_ [l=th] {200}
+_heighthpref_ [l=th] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=th] {à¹àž¢àžà¹àž­àžàžªàž²àž£à¹àžàž¢}
+_textalsoshowing_ [l=th] {à¹àžªàžàžà¹àžà¹àžàžàž±àž}
+_textwith_ [l=th] {àžàž±àžàžàžµà¹àžªàž³àžàž±àžàžàžµà¹àžªàžžàž}
+_textdocsperpage_ [l=th] {à¹àž­àžàžªàž²àž£àžà¹àž­àž«àžà¹àž²}
+
+_textfilterby_ [l=th] {à¹àž­àžàžªàž²àž£àžàž£àž°àžàž­àžàžà¹àž§àž¢}
+_textall_ [l=th] {àžàž±à¹àžàž«àž¡àž}
+_textany_ [l=th] {à¹àž¡à¹àžàž³àžàž±àž}
+_textwords_ [l=th] {àžàž­àžàžàž³}
+_textleaveblank_ [l=th] {à¹àž«àž¥àž·àž­àžàž¥à¹àž­àžà¹àžàž¥à¹àž²à¹àžàž·à¹àž­àž£àž±àžà¹àž­àžàžªàž²àž£àžàž±à¹àžàž«àž¡àž}
+
+_browsebuttontext_ [l=th] {àžàž£àž°à¹àž àžà¹àž­àžàžªàž²àž£}
+
+_nodata_ [l=th] {<i>à¹àž¡à¹àž¡àžµàžà¹àž­àž¡àž¹àž¥</i>}
+_docs_ [l=th] {à¹àž­àžàžªàž²àž£}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=th] {àžà¹àž§àž¢}
+_textSearchshort_ [l=th] {àžà¹àžàž«àž²àžàž³àžàžµà¹à¹àžàžàž²àž°à¹àžàž²àž°àžàž}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=th] {àžàž²àž£à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàžàž·à¹àž­à¹àž£àž·à¹àž­àž}
+_textCreatorshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àžàž·à¹àž­àžàž¹à¹àžàž£àž°àžàž±àžàžà¹}
+_textSubjectshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž§àžŽàžàž²}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž§àž±àžàžàžµà¹}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàžàž·à¹àž­à¹àž­àžàžªàž²àž£}
+_textLanguageshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž àž²àž©àž²}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž­àžàžžàžàž£àž¡}
+_textToshort_ [l=th] {àžàž²àž£à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàžªàž²àžàž²}
+_textFromshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢à¹àžà¹àž£àž°àžàžàžàž²àžàžªàž²àžàž²}
+_textBrowseshort_ [l=th] {àžàž²àž£àž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹àž­àž¢à¹àž²àžàžàž£à¹àž²àž§à¹}
+_textOrganizationshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž­àžàžà¹àžàž£}
+_textHowtoshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž§àžŽàžàžµ "how to" listing}
+_textTopicshort_ [l=th] {àžàž²àž£à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž«àž±àž§àžà¹àž­}
+_textPeopleshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàžàž}
+_textAcronymshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢à¹àžà¹àžàž³àž¢à¹àž­àžàž²àžàžàž¢àž±àžàžàžàž°àžàž±àž§à¹àž£àžàžàžµà¹àžàž³àž¡àž²àž£àž§àž¡àžàž±àž}
+_textPhraseshort_ [l=th] {àžà¹àžàž«àž²àž§àž¥àžµàžàžµà¹àž¡àžµàž­àž¢àž¹à¹à¹àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹}
+_textArtistshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢à¹àžà¹àž£àž°àžàž artist}
+_textKeywordshort_ [l=th] {à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàž keyword}
+_textVolumeshort_ [l=th] {àžàž²àž£à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàžàž£àžŽàž¡àž²àž}
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=th] {àžàž²àž£àžàž±àžà¹àžà¹àžàžàž£àž°à¹àž àžàž­àž¢à¹àž²àžà¹àž¡à¹àž£àž°àžàžž}
+
+_textSearchlong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>àžà¹àžàž«àž²àžàž³àžàžµà¹à¹àžàžàž²àž°à¹àžàž²àž°àžàž  </i>
+àžàžµà¹àžàž£àž²àžàžà¹àžà¹àžàžàž§àž²àž¡àžàž²àž "search" page  àžàžµà¹àžàž·àž­àž«àžà¹àž²à¹àž£àžàžàžµà¹àžàž°àžàž£àž²àžàžàžàž¶à¹àžà¹àž¡àž·à¹àž­àžàžžàžà¹àž£àžŽà¹àž¡àžà¹àžà¹àžà¹  à¹àž¥àž°àžªàž²àž¡àž²àž£àžàžàž¥àž±àžàž¡àž²àžàžµà¹àž«àžà¹àž²àžàžµà¹à¹àžà¹à¹àž¡àž·à¹àž­àž­àž¢àž¹à¹àž«àžà¹àž²àž­àž·à¹àžà¹àžàž¢àžàžàžàžžà¹àž¡ <i>search</i> }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž«àž±àž§à¹àž£àž·à¹àž­àž </i>
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>title a-z</i> àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž²àž£àž«àžàž±àžàžªàž·àž­à¹àž£àžµàž¢àžàž¥àž³àžàž±àžàžàž²àž¡àžàž±àž§àž­àž±àžàž©àž£}
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàžàž·à¹àž­àžàž¹à¹àžàž£àž°àžàž±àžàžà¹   </i> 
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>authors a-z</i>  àž§àžŽàžàžµàžàžµà¹àžàž°àžàž³à¹àž«à¹à¹àž«à¹àžàž£àž²àž¢àžàž·à¹àž­àžàž­àžàž«àžàž±àžàžªàž·àž­à¹àž¢àžà¹àžàž¢àž£àž°àžàžàžàž·à¹àž­àžàž¹à¹àžàž£àž°àžàž±àžàžà¹}
+
+_textSubjectlong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž§àžŽàžàž² 
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>subjects</i> àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž²àž£àžàž­àžàž§àžŽàžàž²àžàž²àž¡àžàžµà¹à¹àžªàžàžà¹àžàž¢àžàž±à¹àžàž«àžàž±àžàžªàž·àž­}
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž§àž±àžàžàžµà¹</i> à¹àžàž¢àžàžàžàžžà¹àž¡ <i>dates</i> àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž·à¹àž­àžàž­àžàžàž£àž°à¹àžà¹àžàžàž±à¹àžàž«àž¡àž à¹àž¢àžàžàž£àž°à¹àž àžàžàž²àž¡àž¥àž³àžàž±àž}
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàžàž·à¹àž­à¹àž­àžàžªàž²àž£</i> 
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>filename</i> àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž²àž£àžàžµà¹à¹àžàžµà¹àž¢àž§àžà¹àž­àžà¹àž¢àžàžàžàžŽàžà¹àžàž¢àžàž·à¹àž­à¹àž­àžàžªàž²àž£}
+
+_textLanguagelong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž àž²àž©àž²</i>
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>language</i>  àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž²àž£àžàžµà¹à¹àžàžµà¹àž¢àž§àžà¹àž­àžà¹àž¢àžàžàž²àž¡àž àž²àž©àž² }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàžàž£àž°àžàžàž­àžàžà¹àžàž£
+</i>à¹àžàž¢àžàžàžàžžà¹àž¡ <i>organisations</i>àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž²àž£àžàž­àžàž­àžàžà¹àžàž£}
+
+_textHowtolong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž§àžŽàžà¹" how to listing" </i>
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>"how to"</i>  àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž²àž£àžàž­àž how to string }
+
+_textTopiclong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž«àž±àž§àžà¹àž­</i> 
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>topic</i> àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž°àžàžàž£àž²àž¢àžàž·à¹àž­àž«àž±àž§àžà¹àž­à¹àžàž·à¹àž­àžàž²àž£àžà¹àžàž«àž²}
+
+_textTolong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàžªàž²àžàž²  </i> 
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>to</i> àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž²àž£àžàž­àžàžàž¹à¹àž£àž±àž }
+
+_textFromlong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹àžàž²àžàžªàž²àžàž²</i>
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>from</i>  àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž·à¹àž­àžàž¹à¹àžªà¹àž}
+
+_textSerieslong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàž­àžàžžàžàž£àž¡</i>
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>series</i>.  àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž²àž£àžàž­àžàž­àžàžžàžàž£àž¡àžàž¶à¹àžàžªàž°àžªàž¡àž­àž¢àž¹à¹à¹àžàžàžàž°àžàž±à¹àž}
+
+_textBrowselong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àžàžà¹àžàž«àž²àžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹<i></i> à¹àžàž¢àžàžàžàžžà¹àž¡ browse
+<i></i>}
+
+_textPeoplelong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢à¹àžà¹àž£àž°àžàžàžàž</i> 
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>people a-z</i> àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž·à¹àž­àžàž­àžàžàžàžàžµà¹à¹àžàžµà¹àž¢àž§àžà¹àž­àžà¹àž¢àžàžàž£àž°à¹àž àžàžàž²àž¡àžàž²àž¡àžªàžàžžàž¥}
+
+_textAcronymlong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž§àžŽàžàžµà¹àžà¹àžàž³àž¢à¹àž­àžàž²àžàžàž¢à¹àžàžàžàž°àžàž±àž§à¹àž£àžàž¡àž²àž£àž§àž¡àžàž±àž</i> à¹àžàž¢àžàžàžàžžà¹àž¡ acronyms 
+ <i></i>  àžàž¶à¹àžàžàž°à¹àžà¹àžàžàž²àž£à¹àž£àžµàž¢àžàž£àž²àž¢àžàž·à¹àž­àžàž­àž acronym. 
+à¹àž¥àž°àžàžµà¹à¹àž¡àž±àžà¹àžàžŽàž }
+
+_textPhraselong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>àžà¹àžàž«àž²àž§àž¥àžµàžàžµà¹àž¡àžµàž­àž¢àž¹à¹à¹àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹ </i> 
+à¹àžàž¢àžàžàžàžžà¹àž¡ <i>phrases</i> àž§àžŽàžàžµàžàžµà¹àžàž°à¹àžà¹ phind phrase browser}
+
+_textArtistlong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàžàžà¹à¹àžàž¢àž£àž°àžàž artist </i> à¹àžàž¢àžàžàžàžžà¹àž¡ artists 
+<i></i>. àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž·à¹àž­àžàžµà¹à¹àžàžµà¹àž¢àž§àžà¹àž­àžà¹àž¢àžàžàž£àž°à¹àž àžà¹àžàž¢àžàž·à¹àž­àžàž­àž artist }
+
+_textKeywordlong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàž keyword</i> 
+à¹àžàž¢àžàžàžàžžà¹àž¡ keyword   <i></i>   àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž²àž£àžàž­àž keyword}
+
+_textVolumelong_ [l=th] {<p>àžàžžàžàžªàž²àž¡àž²àž£àž <i>à¹àžà¹àž²à¹àžàž­à¹àž²àžàžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹à¹àžàž¢àž£àž°àžàžàžàž£àžŽàž¡àž²àž </i> 
+à¹àžàž¢àžàžàžàžžà¹àž¡ volume àž§àžŽàžàžµàžàžµà¹àžàž°àžàž£àž²àžàžàž£àž²àž¢àžàž²àž£àžàž­àžàžàž£àžŽàž¡àž²àž <i>volumes</i>  }
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=th] {<p>à¹àž¥àž·àž­àžàžàžžà¹àž¡ unknown à¹àžàž·à¹àž­àžà¹àžàž«àž²àžªàžŽà¹àžàžàžµàžàžŽàž¡àžà¹ (àž£àž²àž¢àžàž²àž£àžàž¹àžà¹àž¢àžàžàž£àž°à¹àž àžà¹àžàž¢àžªàž²àžàž²àžàžµà¹à¹àž¡à¹àž£àž¹à¹) <i></i> 
+}
+
+_texthelptopics_ [l=th] {<h2 align=left>àž«àž±àž§àžà¹àž­</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">àž§àžŽàžàžµàžà¹àžàž«àž²àžàž³àžàžµà¹à¹àžàžàž²àž°à¹àžàž²àž°àžàž</a>
+<ul>
+  <li><a href="\#query-terms">àžà¹àžàž«àž²àžàž³</a>
+  <li><a href="\#query-type">àžàžàžŽàžàžàž­àžàžà¹àž­àžàž±àžàžàž²àž¡</a>
+  <li><a href="\#scope-of-queries">àžàž­àžà¹àžàžàžàž­àžàžà¹àž­àžàž±àžàžàž²àž¡</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">àžàž²àž£àžªàž°àžªàž¡àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©</a>
+  <li><a href="\#lang-prefs">àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©àžàž²àžàžà¹àž²àžàž àž²àž©àž²</a>
+  <li><a href="\#pres-prefs">àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©àžàž²àžàžàž²àž£àžàž³à¹àžªàžàž­</a>
+  <li><a href="\#search-prefs">àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©àžàž²àž£àžà¹àžàž«àž²</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=th] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=th] {àž§àžŽàžàžµàž­à¹àž²àžà¹àž­àžàžªàž²àž£}
+
+# -- Missing translation: _texthelpreadingdocs_
+
+_texthelpsearching_ [l=th] {<h2>àž§àžŽàžàžµàžàž²àž£àžà¹àžàž«àž²àžàž³àžàžµà¹à¹àžàžàž²àž°à¹àžàž²àž°àžàž</h2>
+<p>
+  àžàž²àžàž«àžà¹àž²àžàž²àž£àžà¹àžàž«àž²àžàžžàžàžªàž²àž¡àž²àž£àžàžàž±à¹àžàžà¹àž­àžàž±àžàžàž²àž¡à¹àžà¹àžà¹àž§àž¢àž§àžŽàžàžµàžà¹àž²àž¢à¹àžàž²àž¡àžàž±à¹àžàžàž­àžàžàž±àžàžàžµà¹:<p>
+  
+  <ol><li>àž£àž°àžàžžàžàž³àžàžµà¹àžàžžàžàžà¹àž­àžàžàž²àž£àžà¹àžàž«àž²
+      <li>àž£àž°àžàžžàž§à¹àž²àžà¹àž­àžàžàž²àž£àžà¹àžàž«àž²àžàž±à¹àžàž«àž¡àžàž«àž£àž·àž­à¹àžà¹àžàž²àžàžàž³
+      <li>àžàžŽàž¡àžà¹àžàž³àžàžµà¹àžà¹àž­àžàžàž²àž£àžà¹àžàž«àž²àž¥àžà¹àž 
+      <li>àžàž¥àžŽàžàžàžžà¹àž¡ Begin Search  <i></i>
+  </ol>
+
+<p>à¹àž¡àž·à¹àž­àžàžžàžàžàž±à¹àžàžàž³àžàž²àž¡ àžàž·à¹àž­à¹àž£àž·à¹àž­àžàžàž­àžà¹àž­àžàžªàž²àž£àžàžµà¹à¹àžàžµà¹àž¢àž§àžà¹àž­àžàžàž£àžàžàž±àžàžàž°à¹àžªàžàžàžàž¶à¹àžàž¡àž² 20 àžàž·à¹àž­
+àžàž°àž¡àžµàžàžžà¹àž¡àž­àž¢àž¹à¹àžà¹àž²àžàžà¹àž²àž¢àžàžµà¹àžàž°àžàž³àžàžžàžà¹àžàžªàž¹à¹à¹àž­àžàžªàž²àž£ 20 àžàž·à¹àž­àžàž±àžà¹àž àžàž²àžàžàž±à¹àžàžàžžàžàžàž°à¹àž«à¹àžàžàžžà¹àž¡àžàžµà¹àžàž³àžàž³àžàžžàžà¹àžàžªàž¹à¹àž­àžµàž 20 àž£àž²àž¢àžàž·à¹àž­àžàž±àžà¹àžàž«àž£àž·àž­àžàž¥àž±àžà¹àžàžàžµà¹ 20 àž£àž²àž¢àžàž·à¹àž­à¹àž£àž à¹àž¥àž°àžà¹àž­à¹à¹àž
+
+ àžàž¥àžŽàžàžàž·à¹àž­à¹àž£àž·à¹àž­àžàžàž­àžà¹àž­àžàžªàž²àž£ àž«àž£àž·àž­àžàžžà¹àž¡à¹àž¥à¹àžà¹àžà¹àž²àžàžà¹àž²àžàžà¹à¹àžà¹ à¹àžàž·à¹àž­àžàžµà¹àžàž°à¹àž«à¹àžàž¡àž±àž
+
+
+<p>à¹àžàžàž³àžàž§àžà¹àž­àžàžªàž²àž£àžàžµà¹àžªà¹àžàžàž¥àž±àžàž¡àž²àž¡àž²àžàž°àžàž¹àžàžàž³àž«àžàžà¹àž§à¹àž§à¹àž²àžàž³àžàž§àž 100 àžàž·àž­àžàž³àžàž§àžàžàžµà¹àž¡àž²àžàžàžµà¹àžªàžžàž
+àžàžžàžàžªàž²àž¡àž²àž£àžà¹àžàž¥àžµà¹àž¢àžàžàž³àžàž§àžà¹àžàž¢àžàž¥àžŽàžàžàžžà¹àž¡ preference àžàžµà¹àžà¹àž²àžàžàžàžàž­àžàž«àžà¹àž² 
+  <i>preferences</i><p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>àžà¹àžàž«àž²àžàž³</h3>
+
+<p>à¹àž¡à¹àž§à¹àž²àžàž³àžàž²àž¡àžàž£àž°à¹àž àžà¹àžàžà¹àžàž²àž¡àžàžµà¹àžàžžàžàžàžŽàž¡àžà¹àž¥àžà¹àžà¹àžàžàž¥à¹àž­àžàžà¹àž­àžàž±àžàžàž²àž¡ àž¡àž±àžàžàž°àžàž¹àžà¹àžàž¥à¹àžà¹àžàž£àž²àž¢àžàž²àž£àžàž­àžàžàž³à¹àž£àžµàž¢àžàž§à¹àž²" Search terms" 
+ à¹àžà¹àž¥àž°àžàž³àžàž°à¹àž¡à¹àž£àž°àžàžžàž­àž°à¹àž£àžàž­àžàžàž²àžàžàž±àž§àž«àžàž±àžàžªàž·àž­à¹àž¥àž°àžàž±àž§à¹àž¥àž
+ àžàž³àžàž°àž¡àžµàžà¹àž­àžàž§à¹àž²àžàžªàžµàžàž²àž§àžàž±à¹àž àžà¹àž²àž«àž²àžàž¡àžµàžàž±àž§àž«àžàž±àžàžªàž·àž­àž­àž·à¹àžà¹ à¹àžà¹àž à¹àžàž£àž·à¹àž­àžàž«àž¡àž²àž¢àž§àž£àž£àžàžàž­àžàžàž£àž²àžàžàž­àž¢àž¹à¹ àž¡àž±àžàžàž°à¹àž¢àžàžàž³à¹àž«àž¡àž·àž­àžàžàž±àžàžàž²àž£àž¡àžµàžà¹àž­àžàž§à¹àž²àžàžàž±à¹àžàž£àž°àž«àž§à¹àž²àžàžàž³
+
+àž«àž¥àž±àžàžàž²àžàžàž±à¹àžàž¡àž±àžàžà¹àžàž°à¹àž¡à¹àž­à¹àž²àžàžàž³ àžàž±àžàžàž±à¹àžàžàžžàžà¹àž¡à¹àžªàž²àž¡àž²àž£àžàžàž°àžà¹àžàž«àž²àžàž³à¹àžàž¢à¹àžªà¹à¹àžàž£àž·à¹àž­àžàž«àž¡àž²àž¢àž§àž£àž£àžàžàž­àžàž¥àžà¹àžà¹àžà¹ 
+
+<p>àžàž±àž§àž­àž¢à¹àž²àžàžàž­àžàžà¹àž­àžàž±àžàžàž²àž¡<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      Agro-forestry in the Pacific Islands: Systems for Sustainability (1993) àžàž°àž¡àžµàžàž§àž²àž¡àž«àž¡àž²àž¢à¹àž«àž¡àž·àž­àžàžàž±àž Agro forestry in the Pacific Islands  Systems for Sustainability  1993  <p><p>
+      <ul><kbd> </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>àžàžàžŽàžàžàž­àžàžà¹àž­àžàž±àžàžàž²àž¡</h3>
+
+<p>àž¡àžµàžàžàžŽàžàžàž­àžàžàž³àžàž²àž¡àžàžµà¹àžà¹àž²àžàžàž±àž 2 àž­àž¢à¹àž²àž
+
+<ul>
+  <li>àžàž³àžàž²àž¡àžªàž³àž«àž£àž±àžàžàž³àžàž±à¹àžàž«àž¡àž  <b>l</b>   àž¡àž±àžàžàž°àž¡àž­àžàž«àž²à¹àžà¹àž­àžàžªàž²àž£ (àž«àž£àž·àž­àžàž àž«àž£àž·àž­ àžàž·à¹àž­à¹àž£àž·à¹àž­àž) àžàžµà¹àž¡àžµàžàž³àžàž±à¹àžàž«àž¡àžàžàžµà¹àžàžžàžàž£àž°àžàžž à¹àž­àžàžªàž²àž£àžàžµà¹àžàž£àžàžàž±àžàžàž³àžàž²àž¡àžà¹àžàž°à¹àžªàžàžà¹àžàž¢à¹àž£àžµàž¢àžàžàž²àž¡àž¥àž³àžàž±àžàžàž±àž§àž­àž±àžàž©àž£These look for documents 
+  <li>àžàž³àžàž²àž¡àžªàž³àž«àž£àž±àžàžàž³àžàž²àžàžàž³ <b></b>   à¹àžàžµàž¢àžà¹àžà¹àž£àž°àžàžžàžàž³àžàž²àžàžàž³àžàžµà¹àžàžžàžàžàžŽàžàž§à¹àž²àžà¹àž²àžàž°àžàž£àž²àžàžàž­àž¢àž¹à¹à¹àžà¹àž­àžàžªàž²àž£àžàžµà¹àžàžžàžàžàž³àž¥àž±àžàžà¹àžàž«àž²
+       à¹àž­àžàžªàž²àž£àžà¹àžàž°à¹àžªàžàžàžàž²àž£àž¥àž³àžàž±àžàžàž­àžàž¡àž±àžàžàžµà¹àžàž£àžàžàž±àžàžàž±àžàžà¹àž­àžàž±àžàžàž²àž¡àž¡àž²àžàžàžµà¹àžªàžžàž
+        à¹àž¡àž·à¹àž­àž¡àž±àžàžàž£àž§àžàžªàž­àžàžàž§àž²àž¡àžàž£àžàžàž±àžàž¡àž²àžàžàžµà¹àžªàžžàž
+
+    
+
+      <p><ul>
+        <li> àžàž²àž£àžà¹àžàž«àž²àžàž³à¹àžà¹àž­àžàžªàž²àž£àž¡àžµàž¡àž²àžà¹àžà¹àž²à¹àž«àž£à¹ àžàž³àžàžµà¹àžàž£àžàžàž±àžàžàž§àž²àž¡àžà¹àž­àžàžàž²àž£àžà¹àžàž°àž¡àžµàž¡àž²àžàžàž¶à¹àž;
+        <li> àžàž³àžàžµà¹àž«àž²àž¢àž²àžàž¡àžµàžàž§àž²àž¡àžªàž³àžàž±àžàž¡àž²àžàžàž§à¹àž²àžàž³àžàž±à¹àž§à¹à¹àž;
+        <li> à¹àž­àžàžªàž²àž£àžªàž±à¹àžà¹àžàž°àžàž£àžàžàž±àžàž¡àž²àžàžàž§à¹àž²à¹àž­àžàžªàž²àž£àžàžµà¹àž¡àžµàžàž§àž²àž¡àž¢àž²àž§.
+      </ul>
+</ul>
+
+<p>à¹àžà¹àžàž²àž£àžà¹àžàž«àž²àžàž³à¹àž«à¹àž¡àž²àžà¹àžà¹àžàž²àž¡àžàžµà¹àžàžžàžàžà¹àž­àžàžàž²àž£ à¹àž¡à¹àž§à¹àž²àžàž°à¹àžà¹àž àžàž£àž°à¹àž¢àž àž«àž£àž·àž­à¹àž¡à¹à¹àžà¹àžàž±à¹àžàž¢à¹àž­àž«àžà¹àž²  àžà¹àž²àžàžžàžàž£àž°àžàžžà¹àžàžµàž¢àžà¹àžà¹àžàž³à¹àžàžµàž¢àž§ à¹àž­àžàžªàž²àž£àžàž°àžàž¹àžà¹àž£àžµàž¢àžàž¥àž³àžàž±àžàžàž²àž¡àžàž§àž²àž¡àžàžµà¹àžàžµà¹à¹àžàžŽàžàžàž¶à¹àž
+.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=th] {àžà¹àžàž«àž²à¹àžàž¢à¹àžà¹àž§àž±àžàžàžµà¹}
+
+_texthelpdatesearch_ [l=th] {<h2>_textdatesearch_</h2>
+àžàž²àž£àžà¹àžàž«àž²àžà¹àž§àž¢àž§àž±àžàžàžµà¹àžàž°àžàž³à¹àž«à¹àžàžžàžàž«àž²à¹àž­àžàžªàž²àž£à¹àžà¹ à¹àž¥àž°àžàž£àžàžàž±àžàžàž³àžàžµà¹àžàž³àž¥àž±àžàžà¹àžàž«àž²à¹àžàžà¹àž§àžà¹àž§àž¥àž²àžàžµà¹à¹àžà¹àžàž­àž àžàžžàžàžªàž²àž¡àž²àž£àžàž«àž²à¹àž­àžàžªàž²àž£àžàž²àžàžàžµàžàžµà¹àž£àž°àžàžžà¹àž§à¹à¹àžà¹àžàž­àžàž«àž£àž·àž­àžàž²àžàž«àž¥àž²àž¢àžàžµàžàžµà¹àžà¹àž²àžàžàž±àž àžàžžàžà¹àž¡à¹àžàž³à¹àžà¹àžàžà¹àž­àžàžà¹àž­àžàž¡àžµàžàž³àžàžµà¹àžàž³àž¥àž±àžàžà¹àžàž«àž² àžàžžàžàžªàž²àž¡àž²àž£àžàžà¹àžàž«àž²à¹àžàž¢à¹àžà¹àž§àž±àžàžàžµà¹à¹àžàžµàž¢àžàž­àž¢à¹àž²àžà¹àžàžµàž¢àž§ à¹àž¥àž°àžà¹à¹àž¡à¹àžàž³à¹àžà¹àžàžà¹àž­àžà¹àžà¹àž§àž±àžàžàžµà¹à¹àžàžàž²àž£àžà¹àžàž«àž² àžà¹àž²àžàžžàžà¹àž¡à¹à¹àžà¹àžàžŽàž¡àžà¹àž§àž±àžàžàžµà¹à¹àžà¹à¹àž¥àž¢àžà¹àžàž°à¹àž«àž¡àž·àž­àžàž§à¹àž²àžàž²àž£àžà¹àžàž«àž²àžà¹àž§àž¢àž§àž±àžàžàžµà¹à¹àž¡à¹à¹àžà¹àž¡àžµàž­àž¢àž¹à¹
+<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>àž§àžŽàžàžµà¹àžà¹àžàžàžàž§àž²àž¡àžàžµ:</h3>
+<ul>
+   <li>àžàž²àž£àžà¹àžàž«àž²à¹àž­àžàžªàž²àž£à¹àžàžµàž¢àžàžàžµà¹àžàžµàž¢àž§:<p>
+   <ul>
+       <li>àžàžŽàž¡àžà¹àžàž³àžà¹àžàž«àž²àžàžµà¹àžàžžàžàž¡àž±àžàžàž°à¹àžà¹à¹àžªàž¡àž­àžà¹à¹àžà¹
+       <li>àžàžŽàž¡àžà¹àžàžµàžàžµà¹àžàžžàžàžà¹àž­àžàžàž²àž£àž¥àžà¹àžàžàž¥à¹àž­àž "start (or only) date"}
+
+_textchangeprefs_ [l=th] {àžàž²àž£à¹àžàž¥àžµà¹àž¢àžàžªàžŽàžàžàžŽàžàžŽà¹àžšàž©àžàž­àžàžàžžàž}
+
+_texthelppreferences_ [l=th] {<h2>_textchangeprefs_</h2>
+
+<p>à¹àž¡àž·à¹àž­àžàžžàžà¹àž¥àž·àž­àžàžàžžà¹àž¡ preference àžàž²àžàžà¹àž²àžàžàžàžàž­àžàž«àžà¹àž²àžàžžàžàžªàž²àž¡àž²àž£àžàžàžµà¹àžàž°à¹àžàž¥àžµà¹àž¢àžàž¥àž±àžàž©àžàž°àžàž­àžinterface àžàž²àž¡àžàž§àž²àž¡àžà¹àž­àžàžàž²àž£àžàž­àžàžàžžàž <i></i> 
+
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>àžàž²àž£àžªàž°àžªàž¡àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©</h3>
+
+àžàž²àž£àžªàž°àžªàž¡àžàž²àžàž­àž¢à¹àž²àžàžàž£àž°àžàž­àžàžà¹àž§àž¢àžàž²àž£àžªàž°àžªàž¡àž¢à¹àž­àž¢àž«àž¥àž²àž¢àž­àž¢à¹àž²àžàžàž¶à¹àžàžªàž²àž¡àž²àž£àžàžà¹àžàž«àž²à¹àžàž¢àž­àžŽàžªàž£àž°àž«àž£àž·àž­àž£à¹àž§àž¡àžàž±àžà¹àžªàž¡àž·àž­àžà¹àžà¹àžàžàžà¹àžàžµàž¢àž§àžàž±àž àžà¹àž²à¹àžà¹àžàžàž±àžàžàž±à¹àžàžàžžàžàžà¹àžªàž²àž¡àž²àž£àžà¹àž¥àž·àž­àžà¹àžà¹àž§à¹àž²àžàž²àž£àžªàž°àžªàž¡àž¢à¹àž­àž¢à¹àžàžàžµà¹àžàžžàžàžàž°àž£àž§àž¡à¹àž§à¹à¹àžàžàž²àž£àžà¹àžàž«àž²àžàž Preferences page
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©àžàž²àžàž àž²àž©àž²</h3>
+
+àžàž²àž£àžªàž°àžªàž¡à¹àžà¹àž¥àž°àž­àž¢à¹àž²àžàžàž°àž¡àžµàž àž²àž©àž²à¹àžªàžàžàžàž±àž§à¹àž¥àž·àž­àžàž­àž±àžà¹àžàž¡àž±àžàžŽàžàž²àžàžàž­àž¡àžàžŽàž§à¹àžàž­àž£à¹àžàž¶à¹àžàžàžžàžàžªàž²àž¡àž²àž£àžàžªàž¥àž±àžà¹àžà¹àžà¹àž àž²àž©àž²àžàžµà¹àžà¹àž²àžàžàž±àžà¹àžà¹àž«àž²àžàžàžžàžàžà¹àž­àžàžàž²àž£ àžàžžàžàžªàž²àž¡àž²àž£àžàžàžµà¹àžàž°à¹àžàž¥àžµà¹àž¢àžàžàž²àž£à¹àžªà¹àž£àž«àž±àžªàž£àž²àž¢àžàž²àž£à¹àžàž¢ Greenstone à¹àžàž·à¹àž­àž£àž±àžàžàž¥àžà¹àž­àž¡àž¹àž¥àžàž²àžàžàž­àž¡àžàžŽàž§à¹àžàž­àž£à¹àžàž²àžàžàž²àž£àžà¹àžàž«àž²
+-- àžàž­àžà¹àž§àž£à¹àžàž°à¹àž¥àž·àž­àžàžàž±àž§à¹àž¥àž·àž­àžàž­àž±à¹àžàž¡àž±àžàžŽàžàž²àžàžàž­àž¡àžàžŽàž§à¹àžàž­àž£à¹àžàžµà¹à¹àž§ à¹àžà¹browser àžàžµà¹à¹àž«à¹àžàžàž¥àž¥àž±àžàžà¹àžàžµà¹àžàž±àžà¹àžàžàžàž§à¹àž²àžà¹àžªàž²àž¡àž²àž£àžàžàž³àž¡àž²à¹àžà¹à¹àžàž¢àžªàž¥àž±àžà¹àžàžàžµà¹àž£àž²àž¢àžàž²àž£àžàž²àž£à¹àžªà¹àž£àž«àž±àžªàžàžµà¹à¹àžàžàžà¹àž²àž àžàž²àž£àžªàž°àžªàž¡àžàž±à¹àžàž«àž¡àžàžàžµà¹àžàž³à¹àž«à¹àžàžžàžàžªàž²àž¡àž²àž£àžàžªàž¥àž±àžàžàž²àž interface àžàžµà¹à¹àžà¹àžàž£àž¹àžà¹àžàžàž¡àž²àžàž£àžàž²àžà¹àžàžàžµà¹àžà¹àžàžàžàž±àžà¹àžàžŽàž¡  
+àž§àžŽàžàžµàžàžµà¹àžàž°à¹àžà¹àžàžàž£àž°à¹àž¢àžàžà¹àž­àž¢à¹àž²àžàž¢àžŽà¹àžàžàž±àžàžàž¹à¹à¹àžà¹àžàžµà¹àžàžàžàž£à¹àž­àžàžàžµà¹àžà¹àž­àžà¹àžà¹àžàž±àž§àž«àžàž±àžàžªàž·àž­àžàžàž²àžà¹àž«àžà¹àžªàž³àž«àž£àž±àžàžàž²àž£ output
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>àžàž²àž£àžàž³à¹àžªàžàž­àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©</h3>
+
+àž­àž²àžàž¡àžµàž«àž¥àž²àž¢àžàž±àž§à¹àž¥àž·àž­àžàžªàž³àž«àž£àž±àžàžàž±à¹àžàžàž²àž£àžàž§àžàžàžžàž¡àžàž²àž£àžàž³à¹àžªàžàž­àžàž¶à¹àžàž­àž¢àž¹à¹àžàž±àžàžàž²àž£àžªàž°àžªàž¡àžàž±à¹àžà¹
+
+
+<p>àžàž²àž£àžªàž°àžªàž¡àž«àžà¹àž²à¹àž§à¹àžà¹àžàžà¹àžàž°àžàž³à¹àž«à¹àžàžžàžàž«àž¢àžžàž navigation bar àžàž­àž Greenstone à¹àžà¹àžàžµà¹àžà¹àž²àžàžàžàžàž­àžàž«àžà¹àž²à¹àž­àžàžªàž²àž£ à¹àžàž·à¹àž­àž§à¹àž²à¹àž¡àž·à¹àž­àžàžžàžàžàž³àžàž²àž£àžà¹àžàž«àž²àžàžžàžàžà¹àžàž°à¹àžàž«àž¢àžžàžàžàžµà¹àž«àžà¹àž²à¹àž§à¹àžà¹àžàžà¹àžàžµà¹àžàž¹àžàžà¹àž­àžàžàž£àžàžàž±àžà¹àžàž¢à¹àž¡à¹àžà¹àž­àžàž¡àžµ header àžàž­àž Greenstone  àžà¹àž²àžà¹àž­àžàžàž²àž£àžà¹àžàž«àž²àž­àžµàžàžàžžàžàžàž°àžà¹àž­àžà¹àžà¹àžàžžà¹àž¡ browser "back" àžàž²àž£àžªàž°àžªàž¡àžàžµà¹àžàž°àžàž³à¹àž«à¹àžàžžàžàžªàž²àž¡àž²àž£àžàž«àž¢àžžàžàžà¹àž­àžàž§àž²àž¡à¹àžàž·àž­àžàžàž­àž Greenstone à¹àžà¹à¹àž¡àž·à¹àž­àžàžžàžàžàž¥àžŽàžàžàžµà¹ link àžàž¶à¹àžàžàž°àžàž³àžàžžàžàž­àž­àžàžàž²àž digital library  à¹àž¥àž°àžàž³à¹àžàžªàž¹à¹àž«àžà¹àž²à¹àž§à¹àžà¹àžàžà¹ à¹àž¥àž°à¹àžàžàž²àž Web collection àžàžžàžàžªàž²àž¡àž²àž£àžàžàž§àžàžàžžàž¡àž§à¹àž²àž«àžà¹àž²àžàž­àž link "Search Results" àžàž°àžàž³à¹àž«à¹àžàžžàžà¹àžà¹àžàž³àžàž­àžàžàžµà¹à¹àžà¹àžàž­àžàžàž­àž URL àž¡àž²àžàžàž§à¹àž² Digital Library 
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>àžàž²àž£àžà¹àžàž«àž²àžªàžŽàžàžàžŽàžàžŽà¹àžšàž©</h3>
+<p>àž¡àžµàžàžžà¹àž¡ 2 àžàžžà¹àž¡àžàž³àž«àžà¹àž²àžàžµà¹àžàž§àžàžàžžàž¡àžàžàžŽàžàžàž­àžà¹àžàžàž§àž²àž¡à¹àž«à¹àžàž£àžàžàž±àžàžàž²àž£àžà¹àžàž«àž²àžàžµà¹àžàžžàžàžªàž±à¹àž
+àžàžžà¹àž¡à¹àž£àž (àžàžŽàžàžà¹àž²àž¢àžàž·à¹àž­àž§à¹àž² "case differences") àžàž°àžàž§àžàžàžžàž¡à¹àžàžàž£àžàžµàžàžµà¹à¹àž¡à¹àž§à¹àž²àžàž°à¹àžà¹àžàžàž³àžàžµà¹àžªàž¹àžàžàž§à¹àž²à¹àž¥àž°àžà¹àž³àžàž§à¹àž²àžàž°àžà¹àž­àžàžàž£àžàžàž±àž   àžàžžà¹àž¡àžàžµà¹ 2 ( "word endings") àžàž°àžàž§àžàžàžžàž¡àž§à¹àž²àžàž° ignore word endings àž«àž£àž·àž­à¹àž¡à¹
+ àž¡àž±àžà¹àžà¹àžà¹àžà¹àžà¹àžàžµà¹àžàž°à¹àžà¹àžàž¥à¹àž­àžàžàž³àžàž²àž¡àžàžàž²àžà¹àž«àžà¹à¹àžàž·à¹àž­àžàžµà¹àžàžžàžàžàž°àžªàž²àž¡àž²àž£àžàžàž³àžàž²àž£àžà¹àžàž«àž²àžàžàž²àžàžàž±à¹àžàž¢à¹àž­àž«àžà¹àž²à¹àžà¹àž­àž¢à¹àž²àžàžà¹àž²àž¢àžàž²àž¢ àž¡àž±àžà¹àž£à¹àž§àž¡àž²àžàžàžàžà¹àž²àžàž£àž°àž«àž¥àž²àžà¹àžà¹àžàžàž²àž£àžà¹àžàž«àž²à¹àžàžàž§àž²àž¡àžàž³àžàž§àžàž¡àž²àž
+
+
+<p>àžàž±àž§àž­àž¢à¹àž²àžà¹àžà¹àž àžà¹àž²à¹àž¥àž·àž­àžàžàžžà¹àž¡ ignore case differences à¹àž¥àž°  ignore word endings  àžà¹àž­àžàž±àžàžàž²àž¡àžàž­àž  African building àžàž°à¹àž«àž¡àž·àž­àžàžàž±àž africa builds à¹àžàž£àž²àž°àžàž±àž§àž«àžàž±àžàžªàž·àž­àžà¹àž²àžàžàžàžàž·àž­ "African"  àžàž°àžàž¹àžà¹àžàž¥àžµà¹àž¢àžà¹àžà¹àž lowercase à¹àž¥àž°àžàž³àžà¹àž­àžà¹àž²àž¢ "n" à¹àž¥àž° "ing" àžà¹àžàž°àžàž¹àžàžàž±àžàž­àž­àžàžàž²àž "African" à¹àž¥àž° "building" àžàž²àž¡àž¥àž³àžàž±àž ( àžàž±àž§ s àžà¹àžàž°àžàž¹àžàžàž±àžàž­àž­àžàžàž²àž 'builds" àžà¹àž§àž¢à¹àžà¹àžàžàž±àž ) <i></i> 
+<i></i> <p>
+    <ul><kbd></kbd></ul>
+      <p><p>
+      <ul><kbd></kbd></ul><p>
+     
+<p>àžàžžàžàžªàž²àž¡àž²àž£àžàžªàž¥àž±àžà¹àžàžàžµà¹ àž£àž²àž¢àžàž²àž£àžàž³àžàž²àž¡ "advanced"  àžàž¶à¹àžàž¢àž­àž¡à¹àž«à¹àžàžžàžàžªàž²àž¡àž²àž£àžàž£àž§àž¡àžàž³à¹àžàž¢à¹àžà¹ AND(&) OR(I) à¹àž¥àž° NOT(!) àž§àžŽàžàžµàžàžµà¹àžàž°àžàž³à¹àž«à¹àžàžžàžàž£àž°àžàžžàžà¹àž­àžàž±àžàžàž²àž¡àžàžµà¹àžàž£àž°àžàž±àžàž¡àž²àžàžàž¶à¹àž
+àžàžžàžàžªàž²àž¡àž²àž£àžà¹àžàžŽàžàžàž¹àžàž²àž£àžà¹àžàž«àž²àžàž£àž°àž§àž±àžàžŽàžàž¶à¹àžàžàž°à¹àžªàžàžà¹àž«à¹à¹àž«à¹àžàžà¹àž­àžàž±àžàžàž²àž¡àž¥à¹àž²àžªàžžàžàžªàž­àžàžªàž²àž¡àžà¹àž­
+àž§àžŽàžàžµàžàžµà¹àžàž³à¹àž«à¹àžà¹àž²àž¢àžà¹àž­àžàž²àž£àžàž£àž±àžàžªàž¹à¹àžà¹àž­àžàž±àžàžàž²àž¡àžà¹àž­àžàž«àžà¹àž²àžàžµà¹
+àžªàžžàžàžà¹àž²àž¢àžàžžàžàžà¹àžªàž²àž¡àž²àž£àžàžàž§àžàžàžžàž¡àžàž±àž§à¹àž¥àžàžàž­àžàžàž²àž£àžàž¥àž±àžà¹àžàžàž¹à¹àž¥àž°àžàž±àž§à¹àž¥àžàžàžµà¹à¹àžªàžàžàž­àž¢àž¹à¹àžàžàž«àžà¹àž²àžàž­
+
+}
+
+_texttanumbrowseoptions_ [l=th] {àž¡àžµàž§àžŽàžàžµàžàžµà¹àžàž°àž«àž²àžà¹àž­àž¡àž¹àž¥à¹àžàžàž²àž£à¹àžà¹àžàžªàž°àžªàž¡àžàžµà¹}
+
+_textsimplehelpheading_ [l=th] {àžà¹àžàž«àž²àžà¹àž­àž¡àž¹àž¥à¹àžàžàž²àž£à¹àžà¹àžàžªàž°àžªàž¡àž­àž¢à¹àž²àžà¹àž£}
+
+_texthelpscope_ [l=th] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Scope of queries</h3>
+
+<p>
+à¹àžàžàž²àž£àžªàž°àžªàž¡àžªà¹àž§àžàž¡àž²àžàžàžžàžàžªàž²àž¡àž²àž£àžà¹àž¥àž·àž­àžàžàž±àžàžàžµàžàžµà¹àžà¹àž²àžàžàž±àžà¹àžàžàž²àž£àžà¹àžàž«àž²  àžàž±àž§àž­àž¢à¹àž²àžà¹àžà¹àž àž­àž²àžàžàž°àž¡àžµàžàž·à¹àž­àžàž¹à¹à¹àžàžµàž¢àžàž«àž£àž·àž­àžàž±àžàžàžµàžàž·à¹àž­à¹àž£àž·à¹àž­àž
+.àž«àž£àž·àž­àž­àž²àžàžàž°àž¡àžµàžàžàž«àž£àž·àž­àžàž±àžàžàžµàž¢à¹àž­àž«àžà¹àž²  à¹àžàž¢àžàž±à¹àž§à¹àžà¹àž­àžàžªàž²àž£àžàžµà¹àžàž£àžàžàž±àžàžàž±à¹àžàž«àž¡àžàžàž°àžàž¹àžàžªà¹àžàžàž¥àž±àžàž¡àž²à¹àžàž¢à¹àž¡à¹à¹àžà¹à¹àž«à¹àžàž§àž²àž¡àžªàž³àžàž±àžàžàž±àžàžàž±àžàžàžµàžàžµà¹à¹àžà¹àžà¹àžàž«àž²
+<p>àžà¹àž²à¹àž­àžàžªàž²àž£àžàž±à¹àžàžà¹àžàž«àžàž±àžàžªàž·àž­ àž¡àž±àžàžàž°àžàž¹àžà¹àžàžŽàžàž¡àž²à¹àžàž«àžà¹àž²àžàžµà¹à¹àž«àž¡àž²àž°àžªàž¡
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/thai2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/thai2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/thai2.dm	(revision 10506)
@@ -0,0 +1,740 @@
+# this file must be UTF-8 encoded
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+# -- Missing translation: _documents_
+# -- Missing translation: _lastupdate_
+# -- Missing translation: _ago_
+# -- Missing translation: _colnotbuilt_
+
+# -- Missing translation: _textpagetitle_
+# -- Missing translation: _textadmin_
+# -- Missing translation: _textabgs_
+# -- Missing translation: _textgsdocs_
+
+# -- Missing translation: _textimagegli_
+
+# -- Missing translation: _textimagecollector_
+
+# -- Missing translation: _textimagetranslator_
+
+# -- Missing translation: _textimageadmin_
+
+# -- Missing translation: _textimagegogreenstone_
+
+# -- Missing translation: _textimagegodocs_
+
+# -- Missing translation: _textpoem_
+
+# -- Missing translation: _textgreenstone_
+
+# -- Missing translation: _textaboutgreenstone_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: selcolgr
+# -- Missing translation: _httpiconselcolgr_
+# -- Missing translation: _widthselcolgr_
+# -- Missing translation: _heightselcolgr_
+# -- Missing translation: _altselcolgr_
+
+
+# -- Missing translation: cgli
+# -- Missing translation: _httpiconcgliof_
+# -- Missing translation: _httpiconcglion_
+# -- Missing translation: _widthcgli_
+
+# -- Missing translation: ccol
+# -- Missing translation: _httpiconccolof_
+# -- Missing translation: _httpiconccolon_
+# -- Missing translation: _widthccol_
+
+# -- Missing translation: ctrans
+# -- Missing translation: _httpiconctransof_
+# -- Missing translation: _httpiconctranson_
+# -- Missing translation: _widthctrans_
+
+# -- Missing translation: cadmin
+# -- Missing translation: _httpiconcadminof_
+# -- Missing translation: _httpiconcadminon_
+# -- Missing translation: _widthcadmin_
+
+# -- Missing translation: cabgs
+# -- Missing translation: _httpiconcabgsof_
+# -- Missing translation: _httpiconcabgson_
+# -- Missing translation: _widthcabgs_
+
+# -- Missing translation: cgsdoc
+# -- Missing translation: _httpiconcgsdocof_
+# -- Missing translation: _httpiconcgsdocon_
+# -- Missing translation: _widthcgsdoc_
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _text4buts_
+
+# -- Missing translation: _textnocollections_
+
+# -- Missing translation: _text1coll_
+
+# -- Missing translation: _textmorecolls_
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textextlink_
+# -- Missing translation: _textlinknotfound_
+
+# -- Missing translation: _textextlinkcontent_
+
+# -- Missing translation: _textlinknotfoundcontent_
+
+# should have arguments of collection, collectionname and link
+# -- Missing translation: _foundintcontent_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textGSDLtitle_
+
+# -- Missing translation: _textusername_
+# -- Missing translation: _textpassword_
+
+# -- Missing translation: _textmustbelongtogroup_
+
+# -- Missing translation: _textmessageinvalid_
+
+# -- Missing translation: _textmessagefailed_
+
+# -- Missing translation: _textmessagedisabled_
+
+# -- Missing translation: _textmessagepermissiondenied_
+
+# -- Missing translation: _textmessagestalekey_
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textnodocumentation_
+
+# -- Missing translation: _textuserguide_
+# -- Missing translation: _textinstallerguide_
+# -- Missing translation: _textdeveloperguide_
+# -- Missing translation: _textpaperguide_
+# -- Missing translation: _textorganizerguide_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: gsdocsgr
+# -- Missing translation: _httpicongsdocsgr_
+# -- Missing translation: _widthgsdocsgr_
+# -- Missing translation: _heightgsdocsgr_
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textdefaultstructure_
+# -- Missing translation: _textmore_
+# -- Missing translation: _textcollector_
+# -- Missing translation: _textinfo_
+# -- Missing translation: _textsrce_
+# -- Missing translation: _textconf_
+# -- Missing translation: _textbild_
+# -- Missing translation: _textview_
+# -- Missing translation: _textdel_
+# -- Missing translation: _textexpt_
+
+# -- Missing translation: _textdownloadingfiles_
+# -- Missing translation: _textimportingcollection_
+# -- Missing translation: _textbuildingcollection_
+# -- Missing translation: _textcreatingcollection_
+
+# -- Missing translation: _textcollectorblurb_
+
+# -- Missing translation: _textcb1_
+
+# -- Missing translation: _textcb2_
+# -- Missing translation: _textcnc_
+# -- Missing translation: _textwec_
+
+# -- Missing translation: _textcb3_
+
+# -- Missing translation: _textcb4_
+
+# -- Missing translation: _textfsc_
+
+# -- Missing translation: _textwtc_
+# -- Missing translation: _textamd_
+# -- Missing translation: _textetc_
+# -- Missing translation: _textdtc_
+# -- Missing translation: _textetcfcd_
+# -- Missing translation: _textcaec_
+# -- Missing translation: _textnwec_
+# -- Missing translation: _textcianc_
+# -- Missing translation: _texttsosn_
+# -- Missing translation: _textsin_
+# -- Missing translation: _textswts_
+# -- Missing translation: _textatco_
+# -- Missing translation: _textbtc_
+# -- Missing translation: _textpvyh_
+
+# -- Missing translation: _texttfsiw_
+
+# -- Missing translation: _textadab_
+
+# -- Missing translation: _textwyar_
+
+# -- Missing translation: _textcnmbs_
+# -- Missing translation: _texteambs_
+# -- Missing translation: _textpsea_
+# -- Missing translation: _textdocmbs_
+
+# -- Missing translation: _textwcanc_
+
+# -- Missing translation: _texttfc_
+
+# -- Missing translation: _texttctiasp_
+
+# -- Missing translation: _textcea_
+
+# -- Missing translation: _textteas_
+
+# -- Missing translation: _textatc_
+
+# -- Missing translation: _texttiasd_
+
+# -- Missing translation: _textypits_
+
+# -- Missing translation: _srcebadsources_
+
+# -- Missing translation: _textymbyco_
+
+# -- Missing translation: _textbtco_
+# -- Missing translation: _textand_
+# -- Missing translation: _textad_
+
+# -- Missing translation: _texttftysb_
+
+# -- Missing translation: _textis_
+
+# -- Missing translation: _textddd1_
+
+# -- Missing translation: _textddd2_
+
+# -- Missing translation: _textconf1_
+
+# -- Missing translation: _textreset_
+
+# -- Missing translation: _textbild1_
+
+# -- Missing translation: _textbild2_
+
+# -- Missing translation: _textstopbuild_
+
+# -- Missing translation: _textbild3_
+
+# -- Missing translation: _textbuildcancelled_
+
+# -- Missing translation: _textbildcancel1_
+
+# -- Missing translation: _textbsupdate1_
+# -- Missing translation: _textbsupdate2_
+# -- Missing translation: _textseconds_
+# -- Missing translation: _textbildsuc_
+
+# -- Missing translation: _textviewbildsummary_
+
+# -- Missing translation: _textfailmsg11_
+
+# -- Missing translation: _textfailmsg21_
+# -- Missing translation: _textblcont_
+
+# -- Missing translation: _texttryagain_
+
+# -- Missing translation: _textfailmsg31_
+# -- Missing translation: _textfailmsg41_
+# -- Missing translation: _textfailmsg71_
+# -- Missing translation: _textretcoll_
+
+# -- Missing translation: _textdelperm_
+
+# -- Missing translation: _textdelinv_
+
+# -- Missing translation: _textdelsuc_
+
+# -- Missing translation: _textclonefail_
+
+# -- Missing translation: _textcolerr_
+
+# -- Missing translation: _texttmpfail_
+
+# -- Missing translation: _textmkcolfail_
+
+# -- Missing translation: _textnocontent_
+
+# -- Missing translation: _textrestart_
+
+# -- Missing translation: _textreloaderror_
+
+# -- Missing translation: _textexptsuc_
+
+# -- Missing translation: _textexptfail_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_colect
+# -- Missing translation: _httpiconhcolect_
+
+# -- Missing translation: info
+# -- Missing translation: _httpicongcinfoof_
+# -- Missing translation: _httpicongcinfoon_
+# -- Missing translation: _httpiconycinfoof_
+# -- Missing translation: _httpiconycinfoon_
+# -- Missing translation: _httpiconncinfoof_
+
+# -- Missing translation: srce
+# -- Missing translation: _httpicongcsrceof_
+# -- Missing translation: _httpicongcsrceon_
+# -- Missing translation: _httpiconycsrceof_
+# -- Missing translation: _httpiconycsrceon_
+# -- Missing translation: _httpiconncsrceof_
+
+# -- Missing translation: conf
+# -- Missing translation: _httpicongcconfof_
+# -- Missing translation: _httpicongcconfon_
+# -- Missing translation: _httpiconycconfof_
+# -- Missing translation: _httpiconycconfon_
+# -- Missing translation: _httpiconncconfof_
+
+# -- Missing translation: bild
+# -- Missing translation: _httpicongcbildof_
+# -- Missing translation: _httpicongcbildon_
+# -- Missing translation: _httpiconycbildof_
+# -- Missing translation: _httpiconycbildon_
+# -- Missing translation: _httpiconncbildof_
+
+# -- Missing translation: view
+# -- Missing translation: _httpicongcviewof_
+# -- Missing translation: _httpicongcviewon_
+# -- Missing translation: _httpiconycviewof_
+# -- Missing translation: _httpiconycviewon_
+# -- Missing translation: _httpiconncviewof_
+
+# -- Missing translation: del
+# -- Missing translation: _httpicongcdelof_
+# -- Missing translation: _httpicongcdelon_
+
+# -- Missing translation: expt
+# -- Missing translation: _httpicongcexptof_
+# -- Missing translation: _httpicongcexpton_
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+# -- Missing translation: _textgreenstone1_
+
+# -- Missing translation: _textgreenstone2_
+
+# -- Missing translation: _textplatformtitle_
+# -- Missing translation: _textgreenstone3_
+
+# -- Missing translation: _textgreenstone4_
+
+# -- Missing translation: _textcustomisationtitle_
+# -- Missing translation: _textgreenstone5_
+
+# -- Missing translation: _textdocumentationtitle_
+# -- Missing translation: _textdocuments_
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+# -- Missing translation: _textmailinglisttitle_
+# -- Missing translation: _textmailinglist_
+
+# -- Missing translation: _textbugstitle_
+# -- Missing translation: _textreport_
+
+# -- Missing translation: _textgs3title_
+# -- Missing translation: _textgs3_
+
+# -- Missing translation: _textcreditstitle_
+
+# -- Missing translation: _textwhoswho_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+# -- Missing translation: abgsgr
+# -- Missing translation: _httpiconabgsgr_
+# -- Missing translation: _widthabgsgr_
+# -- Missing translation: _heightabgsgr_
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textlocu_
+# -- Missing translation: _textuser_
+# -- Missing translation: _textas_
+# -- Missing translation: _textgroups_
+# -- Missing translation: _textcomment_
+# -- Missing translation: _textadduser_
+# -- Missing translation: _textedituser_
+# -- Missing translation: _textdeleteuser_
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+# -- Missing translation: _textedituser_
+# -- Missing translation: _textadduser_
+
+# -- Missing translation: _textaboutusername_
+
+# -- Missing translation: _textaboutpassword_
+
+# -- Missing translation: _textoldpass_
+# -- Missing translation: _textenabled_
+# -- Missing translation: _textdisabled_
+
+# -- Missing translation: _textaboutgroups_
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textdeleteuser_
+# -- Missing translation: _textremwarn_
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textchangepw_
+# -- Missing translation: _textoldpw_
+# -- Missing translation: _textnewpw_
+# -- Missing translation: _textretype_
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textsuccess_
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textinvalidusername_
+# -- Missing translation: _textinvalidpassword_
+# -- Missing translation: _textemptypassword_
+# -- Missing translation: _textuserexists_
+
+# -- Missing translation: _textusernameempty_
+# -- Missing translation: _textpasswordempty_
+# -- Missing translation: _textnewpass1empty_
+# -- Missing translation: _textnewpassmismatch_
+# -- Missing translation: _textnewinvalidpassword_
+# -- Missing translation: _textfailed_
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+# -- Missing translation: _textversion_
+# -- Missing translation: _textframebrowser_
+# -- Missing translation: _textusermanage_
+# -- Missing translation: _textlistusers_
+# -- Missing translation: _textaddusers_
+# -- Missing translation: _textchangepasswd_
+# -- Missing translation: _textinfo_
+# -- Missing translation: _textgeneral_
+# -- Missing translation: _textarguments_
+# -- Missing translation: _textactions_
+# -- Missing translation: _textbrowsers_
+# -- Missing translation: _textprotocols_
+# -- Missing translation: _textconfigfiles_
+# -- Missing translation: _textlogs_
+# -- Missing translation: _textusagelog_
+# -- Missing translation: _textinitlog_
+# -- Missing translation: _texterrorlog_
+# -- Missing translation: _textadminhome_
+# -- Missing translation: _textreturnhome_
+# -- Missing translation: _titlewelcome_
+# -- Missing translation: _textmaas_
+# -- Missing translation: _textvol_
+# -- Missing translation: _textcmuc_
+# -- Missing translation: _textati_
+
+# -- Missing translation: _texttsaa_
+
+# -- Missing translation: _textcolstat_
+
+# -- Missing translation: _textcwoa_
+
+# -- Missing translation: _textcafi_
+# -- Missing translation: _textcctv_
+# -- Missing translation: _textsubc_
+# -- Missing translation: _texteom_
+# -- Missing translation: _textftum_
+# -- Missing translation: _textmus_
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textbsummary_
+# -- Missing translation: _textflog_
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=th] {àž§àžŽàžàžµàžàž²àž£à¹àžà¹àžàž£àžµàžàžªà¹àžàž}
+
+_textwhy_ [l=th] {<p>àžàž²àž£àžªà¹àžàž£àž²àž¢àžàž²àžàžàžµà¹à¹àžà¹àžàžàž²àžàžàžµà¹àžàžµà¹à¹àž«à¹à¹àž«à¹àžàž§à¹àž²àžàžžàžàžàžàž«àžà¹àž²à¹àž§àžà¹àžàžàžàžµà¹àžàžžàžà¹àžà¹àžàžŽàžàž²àž£àžàž²àžàž¶àžàžàž§àž²àž¡àž¢àž²àžàž«àž£àž·àž­àžàž§àž²àž¡à¹àž¡à¹àž­àžàžàž.}
+_textextraforform_ [l=th] {àžàžžàžà¹àž¡à¹àžà¹àž­àžàžàž£àž­àžà¹àžàžàžàž­àž£à¹àž¡ -- àžà¹àž­àž¡àž¹àž¥à¹àž à¹ àžà¹àžàž²àž¡àžàžµà¹àžàž°àžà¹àž§àž¢}
+_textprivacybasic_ [l=th] {<p>àžàž²àž£àž£àž²àž¢àžàž²àžàžàž°àžàž£àž°àžàž­àžàžàž¶à¹àžà¹àžàžàž²àž°àžà¹àž­àž¡àž¹àž¥àžàžµà¹à¹àžàžµà¹àž¢àž§àžàž±àžà¹àž§àžà¹àžàžàžàž£àžµàžàžªà¹àžàžàžàžžàžàžàžŽàžàž²àž£àžàž², à¹àž¥àž°à¹àžàžà¹àžà¹àž¥àž¢àžµàžàžµà¹àžàžžàžà¹àžà¹àž¡àž±àž (àžàž§àžàžàž±àžàžà¹àž­àž¡àž¹àž¥àžàž±àž§à¹àž¥àž·àž­àžàžàžµà¹àžàžžàžàžàž±àžàž«àž²à¹àž§à¹).}
+_textstillsend_ [l=th] {àžàžžàžàž¢àž±àžàžàžàžà¹àž­àžàžàž²àž£àžªà¹àžàž£àž²àž¢àžàž²àžàžàžµà¹àž«àž£àž·àž­?}
+
+_texterror_ [l=th] {àžàžŽàžàžàž¥àž²àž}
+_textyes_ [l=th] {à¹àžà¹}
+_textno_ [l=th] {à¹àž¡à¹}
+_textclosewindow_ [l=th] {àžàžŽàžàž«àžà¹àž²àžà¹àž²àž}
+_textabout_ [l=th] {à¹àžàžµà¹àž¢àž§àžàž±àž}
+_textprivacy_ [l=th] {àžàž§àž²àž¡àž¥àž±àž}
+_textsend_ [l=th] {àžªà¹àž}
+_textdontsend_ [l=th] {Don\\'t àžªà¹àž}
+_textoptionally_ [l=th] {àžàž±àž§à¹àž¥àž·àž­àž}
+
+_textunderdev_ [l=th] {àžàž²àž£àžàž¹àž£àž²àž¢àž¥àž°à¹àž­àžµàž¢àžàž¡àž²àžà¹àž­àžàžàž°àžªàž²àž¡àž²àž£àžà¹àžà¹àžàž£àž°à¹àž¢àžàžà¹à¹àžà¹à¹àžàžàžžàžàžªàžžàžàžà¹àž²àž¢}
+
+_textviewdetails_ [l=th] {àžàžŽàžàž²àž£àžàž²àž£àž²àž¢àž¥àž°à¹àž­àžµàž¢àžàžàž­àžàž£àž²àž¢àžàž²àž}
+_textmoredetails_ [l=th] {àž£àž²àž¢àž¥àž°à¹àž­àžµàž¢àžà¹àžàžŽà¹àž¡à¹àžàžŽàž¡}
+_texttrackreport_ [l=th] {àžàžŽàžàžàž²àž¡àž£àž²àž¢àžàž²àžàžàžµà¹}
+_textcharacterise_ [l=th] {àžàž±àžàž«àž²àž¡àž±àžàžàž·àž­àž­àž°à¹àž£}
+_textseverity_ [l=th] {àžàž±àžàž«àž²à¹àž¥àž§àž£à¹àž²àž¢àž­àž¢à¹àž²àžà¹àž£}
+ 
+_textbadrender_ [l=th] {àž«àžà¹àž²àžàž¹à¹àžàž¥àž}
+_textcontenterror_ [l=th] {à¹àžàž·à¹àž­àž«àž²àžàžŽàžàžàž¥àž²àž}
+_textstrangebehaviour_ [l=th] {àžàž€àžàžŽàžàž£àž£àž¡à¹àžàž¥àž}
+_textunexpected_ [l=th] {àžàž²àžàž­àž¢à¹àž²àžàžàžµà¹à¹àž¡à¹àžàž²àžàžàžŽàžà¹àžàžŽàžàžàž¶à¹àž}
+_textfunctionality_ [l=th] {àž¢àž²àžàžàžµà¹àžàž°à¹àžà¹}
+_textother_ [l=th] {àž­àž·à¹àžà¹}
+
+_textcritical_ [l=th] {à¹àžàžµà¹àž¢àž§àžàž±àžàžàž²àž£àž§àžŽàžàž²àž£àžà¹}
+_textmajor_ [l=th] {àžàž±àžàž§àž¥}
+_textmedium_ [l=th] {àžàž¥àž²àž}
+_textminor_ [l=th] {à¹àž¥à¹àžàžà¹àž­àž¢}
+_texttrivial_ [l=th] {àžàž£àž£àž¡àžàž²}
+
+_textwhatdoing_ [l=th] {àžàžžàžàžàž³àž¥àž±àžàžàž¢àž²àž¢àž²àž¡àžàž°àžàž³àž­àž°à¹àž£?}
+_textwhatexpected_ [l=th] {àž­àž°à¹àž£àžàžµà¹àžàžžàžà¹àžàž¢àžàž²àžàž«àž§àž±àžà¹àž«à¹à¹àžàžŽàžàžàž¶à¹àž}
+_textwhathappened_ [l=th] {à¹àžàžŽàžàž­àž°à¹àž£àžàž¶à¹àžàžàž²àž¡àžàž£àžŽàž?}
+
+_cannotfindcgierror_ [l=th] {<h2>àžàž­à¹àžàž©!</h2>Can\\'t àž«àž²à¹àžàž£à¹àžàž£àž¡à¹àžàžŽàžà¹àž§àž­àž£à¹àžªàž³àž«àž£àž±àž "I\\'d àžà¹àž­àžàžàž²àž£àžà¹àž" àžàžžà¹àž¡.}
+
+_textusabbanner_ [l=th] {àžàžàž£àž¹àžà¹àžàžà¹àžàž£àžžàžàž£àžµàžàžªà¹àžàž}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+# -- Missing translation: _textgli_
+# -- Missing translation: _textglihelp_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+# -- Missing translation: gligr
+# -- Missing translation: _httpicongligr_
+# -- Missing translation: _widthgligr_
+# -- Missing translation: _heightgligr_
Index: /tags/gsdl-2_61-distribution/gsdl/macros/tip.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/tip.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/tip.dm	(revision 10506)
@@ -0,0 +1,149 @@
+# this file must be UTF-8 encoded
+
+package tip
+
+#######################################################################
+# Tips
+# if you want a random tip to appear, use the macro name _tip:thistip_
+#######################################################################
+
+_tipstart_ {<center>}
+_tipquotestart_ {<b>}
+_tipquoteend_ {</b> }
+_tipattributionstart_ {<em>}
+_tipattributionend_ {</em>}
+_tipend_ {</center>}
+
+_tip1_ {
+       _tipstart_
+       _tipquotestart_
+       A word after a word after a word is power.
+       _tipquoteend_
+       _tipattributionstart_
+       Margaret Atwood
+       _tipattributionend_
+       _tipend_
+       _tipend_
+}
+
+_tip2_ {
+       _tipstart_
+       _tipquotestart_ Books are weapons in the war of ideas
+       _tipquoteend_
+       _tipattributionstart_ American Library Association, 1942
+       _tipattributionend_
+       _tipend_
+}
+
+_tip3_ {
+       _tipstart_
+       _tipquotestart_ Only the educated are free
+       _tipquoteend_
+       _tipattributionstart_ Epictetus
+       _tipattributionend_
+       _tipend_
+}
+
+_tip4_ {
+       _tipstart_
+       _tipquotestart_ We need our libraries open to all, so we can prepare our students for the 21st Century.
+       _tipquoteend_
+       _tipattributionstart_ Martin Luther King, quoted in the program at ALA midwinter, "Celebrating
+Equity and Empowerment," on Martin Luther King Day.
+       _tipattributionend_
+       _tipend_
+}
+
+_tip5_ {
+       _tipstart_
+       _tipquotestart_
+       Congress shall make no law abridging the freedom of sXXXch, or the right of the people peaceably to XXXemble, and to peXXXion the government for a redress of grievances.
+       _tipquoteend_
+       _tipattributionstart_
+The first amendment according to XStop (according to Marc Rotenberg, Electronic Privacy Information Center)
+       _tipattributionend_
+       _tipend_
+}
+_tip6_ {
+       _tipstart_
+       _tipquotestart_
+       My Alma mater was books, a good library . . . I could spend the rest of my life reading, just satisfying my curiosity.
+       _tipquoteend_
+       _tipattributionstart_
+       Malcolm X, Autobiograhy of Malcolm X
+       _tipattributionend_
+       _tipend_
+}
+_tip7_ {
+       _tipstart_
+       _tipquotestart_
+       To be literate is to possess the cow of plenty.
+       _tipquoteend_
+       _tipattributionstart_
+       Motto of the Madras Library Association
+       _tipattributionend_
+       _tipend_
+}
+
+_tip8_ {
+       _tipstart_
+       _tipquotestart_
+       It does not matter how many books you may have, but whether they are good or not.
+       _tipquoteend_
+       _tipattributionstart_
+       Seneca
+       _tipattributionend_
+       _tipend_
+}
+
+_tip9_ {
+       _tipstart_
+       _tipquotestart_
+       I have always imagined that Paradise will be a kind of library.
+       _tipquoteend_
+       _tipattributionstart_
+Jorge Luis Borges (1899-1986)
+       _tipattributionend_
+       _tipend_
+}
+
+_tip10_ {
+       _tipstart_
+       _tipquotestart_
+       When an old man dies, a library burns down.
+       _tipquoteend_
+       _tipattributionstart_
+       African Proverb
+       _tipattributionend_
+       _tipend_
+}
+
+_tip11_ {
+       _tipstart_
+       _tipquotestart_
+       My library / Was dukedom large enough. 
+       _tipquoteend_
+       _tipattributionstart_
+       William Shakespeare. The Tempest.
+       _tipattributionend_
+       _tipend_
+}
+
+_tip12_ {
+       _tipstart_
+       _tipquotestart_
+      Knowing I lov'd my books, he furnish'd me /
+      From mine own library with volumes that /
+      I prize above my dukedom. /
+       _tipquoteend_
+       _tipattributionstart_
+       William Shakespeare. The Tempest.
+       _tipattributionend_
+       _tipend_
+}
+
+
+_tip:tipmax_ {12}
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/macros/turkish.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/turkish.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/turkish.dm	(revision 10506)
@@ -0,0 +1,1269 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Turkish Language text and icon macros 
+# Translated by Ozcan Kabakcyoolu, October 2003
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=tr] {SÃŒreli YayÄ±nlar}
+_textsource_ [l=tr] {kaynak ref: }
+_textdate_ [l=tr] {yayÄ±n tarihi: }
+_textnumpages_ [l=tr] {sayfa sayÄ±sÄ±: }
+
+_textsignin_ [l=tr] {GiriÅ}
+
+_textdefaultcontent_ [l=tr] {Aranan sayfa bulunamadÄ±.
+LÃŒtfen tarayÄ±cÄ±nÄ±zÄ±n 'geri' yada ana sayfa dÃŒÄmesini kullanarak Sanal KÃŒtÃŒphaneye geri dÃ¶nÃŒnÃŒz.}
+
+_textdefaulttitle_ [l=tr] {GSDL Hata}
+
+# -- Missing translation: _textbadcollection_
+
+_textselectpage_ [l=tr] {Sayfa SeÃ§}
+
+_collectionextra_ [l=tr] {Bu koleksiyon _about:numdocs_ dokÃŒman iÃ§erir. 
+En son  _about:builddate_ gÃŒn Ã¶nce oluÅturuldu.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=tr] {<p>Bu koleksiyon _numdocs_ _If_("_numdocs_" eq "1",dokÃŒman,dokÃŒman), toplam _numbytes_ dÄ±r.
+<p><a href="_httppagex_(bsummary)">Koleksiyon Ã¶zeti</a>
+}
+
+_textimagecollection_ [l=tr] {}
+_textimageabout_ [l=tr] {HakkÄ±nda sayfasÄ±}
+_textimagehome_ [l=tr] {Ana sayfa}
+_textimagehelp_ [l=tr] {YardÄ±m}
+_textimagepref_ [l=tr] {Tercihler}
+_textimagegreenstone_ [l=tr] {Greenstone Sanal KÃŒtÃŒphane YazÄ±lÄ±mÄ±}
+_textimageusab_ [l=tr] {Size gÃ¶re kullanÄ±mÄ± zor olanlar neler?}
+
+_textimagesearch_ [l=tr] {Belirli sÃ¶zcÃŒkler iÃ§in arama}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=tr] {Alfabetik baÅlÄ±k listesine gÃ¶re gÃ¶zat}
+_textimageCreator_ [l=tr] {Alfabetik yazar listesine gÃ¶zat}
+_textimageSubject_ [l=tr] {Konu kategorisine gÃ¶re gÃ¶zat}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=tr] {Tarihe gÃ¶re gÃ¶zat}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=tr] {ÃzgÃŒn dosya adÄ±na gÃ¶re gÃ¶zat}
+_textimageLanguage_ [l=tr] {Dile gÃ¶re gÃ¶zat}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=tr] {Kuruma gÃ¶re gÃ¶zat}
+_textimageKeyword_ [l=tr] {Anahtar sÃ¶zcÃŒklere gÃ¶re gÃ¶zat}
+_textimageHowto_ [l=tr] {NasÄ±l kategorisine gÃ¶re gÃ¶zat}
+_textimageList_ [l=tr] {Belge listesine gÃ¶re gÃ¶zat}
+_textimageSeries_ [l=tr] {SayÄ±ya gÃ¶re gÃ¶zat}
+_textimageTo_ [l=tr] {Kime alanÄ±na gÃ¶re gÃ¶zat}
+_textimageFrom_ [l=tr] {Kimden alanÄ±na gÃ¶re gÃ¶zat}
+_textimageTopic_ [l=tr] {Ãzel konulara gÃ¶re gÃ¶zat}
+_textimageBrowse_ [l=tr] {GÃ¶zat}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=tr] {Alfabetik kiÅi listesine gÃ¶re gÃ¶zat}
+_textimageAcronym_ [l=tr] {KÄ±saltmalara gÃ¶zat}
+_textimagePhrase_ [l=tr] {Ä°fadelere gÃ¶re gÃ¶zat}
+_textimageArtist_ [l=tr] {SanatÃ§Ä±lara gÃ¶zat}
+_textimageVolume_ [l=tr] {Ciltlere gÃ¶re gÃ¶zat}
+# -- Missing translation: _textimageCountries_
+_textimageCaptions_ [l=tr] {Resim baÅlÄ±klarÄ±na gÃ¶re gÃ¶zat}
+
+
+_texticontabsearchgreen_ [l=tr] {Arama}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=tr] {BaÅlÄ±klar A-Z}
+_texticontabCreatorgreen_ [l=tr] {Yazarlar A-Z}
+_texticontabSubjectgreen_ [l=tr] {Konular}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=tr] {Tarihler}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=tr] {Dosya adlarÄ±}
+_texticontabLanguagegreen_ [l=tr] {Dil}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=tr] {Kurum}
+_texticontabKeywordgreen_ [l=tr] {Anahtar sÃ¶zcÃŒkler}
+_texticontabhowgreen_ [l=tr] {NasÄ±l}
+_texticontabseriesgreen_ [l=tr] {Seriler}
+_texticontablistgreen_ [l=tr] {Listele}
+_texticontabtogreen_ [l=tr] {Kime}
+_texticontabfromgreen_ [l=tr] {Kime}
+_texticontabtopicgreen_ [l=tr] {Konular}
+_texticontabbrwsegreen_ [l=tr] {GÃ¶zat}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=tr] {GÃ¶zat}
+_texticontabPeoplegreen_ [l=tr] {KiÅi A-Z}
+_texticontabAcronymgreen_ [l=tr] {KÄ±saltmalar}
+_texticontabPhrasegreen_ [l=tr] {Ä°fadeler}
+_texticontabArtistgreen_ [l=tr] {SanatÃ§Ä±lar}
+_texticontabVolumegreen_ [l=tr] {Ciltler}
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=tr] {Belgeyi gÃ¶rÃŒntÃŒle}
+_texticonclosedbook_ [l=tr] {bu belgeyi aÃ§ ve iÃ§eriÄini gÃ¶rÃŒntÃŒle}
+_texticonnext_ [l=tr] {sonraki bÃ¶lÃŒm}
+_texticonprev_ [l=tr] {Ã¶nceki bÃ¶lÃŒm}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=tr] {MIDI belgesini gÃ¶rÃŒntÃŒle}
+_texticonmsword_ [l=tr] {Word belgesini gÃ¶rÃŒntÃŒle}
+_texticonmp3_ [l=tr] {MP3 belgesini gÃ¶rÃŒntÃŒle}
+_texticonpdf_ [l=tr] {PDF belgesini gÃ¶rÃŒntÃŒle}
+_texticonps_ [l=tr] {PostScript belgesini gÃ¶rÃŒntÃŒle}
+_texticonppt_ [l=tr] {PowerPoint belgesini gÃ¶rÃŒntÃŒle}
+_texticonrtf_ [l=tr] {RTF belgesini gÃ¶rÃŒntÃŒle}
+_texticonxls_ [l=tr] {Microsoft Excel belgesini gÃ¶rÃŒntÃŒle}
+
+_page_ [l=tr] {sayfa }
+_pages_ [l=tr] {sayfa}
+# -- Missing translation: _of_
+_vol_ [l=tr] {Cilt}
+_num_ [l=tr] {No.}
+
+_textmonth00_ [l=tr] {}
+_textmonth01_ [l=tr] {Ocak}
+_textmonth02_ [l=tr] {Åubat}
+_textmonth03_ [l=tr] {Mart}
+_textmonth04_ [l=tr] {Nisan}
+_textmonth05_ [l=tr] {MayÄ±s}
+_textmonth06_ [l=tr] {Haziran}
+_textmonth07_ [l=tr] {Temmuz}
+_textmonth08_ [l=tr] {AÄustos}
+_textmonth09_ [l=tr] {EylÃŒl}
+_textmonth10_ [l=tr] {Ekim}
+_textmonth11_ [l=tr] {KasÄ±m}
+_textmonth12_ [l=tr] {AralÄ±k}
+
+_textdocument_ [l=tr] {Belge}
+_textsection_ [l=tr] {BÃ¶lÃŒm}
+_textparagraph_ [l=tr] {Paragraf}
+
+_magazines_ [l=tr] {Dergiler}
+
+_nzdlpagefooter_ [l=tr] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">Yeni Zelanda Sanal KÃŒtÃŒphane Projesi</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Bilgisayar BÃ¶lÃŒmÃŒ</a>, 
+<a href="http://www.waikato.ac.nz">Waikato Ãniversitesi</a>, 
+Yeni Zelanda}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ANA SAYFA" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=tr] {_httpimg_/tr/chomeof.gif}
+_httpiconchomeon_ [l=tr] {_httpimg_/tr/chomeon.gif}
+
+## "YARDIM" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=tr] {_httpimg_/tr/chelpof.gif}
+_httpiconchelpon_ [l=tr] {_httpimg_/tr/chelpon.gif}
+
+## "TERCÄ°HLER" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=tr] {_httpimg_/tr/cprefof.gif}
+_httpiconcprefon_ [l=tr] {_httpimg_/tr/cprefon.gif}
+
+## "GERÄ°BÄ°LDÄ°RÄ°M" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=tr] {_httpimg_/tr/cusabof.gif}
+_httpiconcusabon_ [l=tr] {_httpimg_/tr/cusabon.gif}
+
+
+## "arama" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=tr] {_httpimg_/tr/tsrchgr.gif}
+_httpicontsrchof_ [l=tr] {_httpimg_/tr/tsrchof.gif}
+_httpicontsrchon_ [l=tr] {_httpimg_/tr/tsrchon.gif}
+_widthtsrchx_ [l=tr] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "baÅlÄ±klar a-z" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=tr] {_httpimg_/tr/ttitlgr.gif}
+_httpiconttitleof_ [l=tr] {_httpimg_/tr/ttitlof.gif}
+_httpiconttitleon_ [l=tr] {_httpimg_/tr/ttitlon.gif}
+_widthttitlex_ [l=tr] {87}
+
+# Not true DC, kept for legacy reasons
+## "yazarlar a-z" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=tr] {_httpimg_/tr/tauthgr.gif}
+_httpicontcreatof_ [l=tr] {_httpimg_/tr/tauthof.gif}
+_httpicontcreaton_ [l=tr] {_httpimg_/tr/tauthon.gif}
+_widthtcreatx_ [l=tr] {110}
+
+## "konular" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=tr] {_httpimg_/tr/tsubjgr.gif}
+_httpicontsubjon_ [l=tr] {_httpimg_/tr/tsubjon.gif}
+_httpicontsubjof_ [l=tr] {_httpimg_/tr/tsubjof.gif}
+_widthtsubjx_ [l=tr] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "tarihler" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=tr] {_httpimg_/tr/tdategr.gif}
+_httpicontdateof_ [l=tr] {_httpimg_/tr/tdateof.gif}
+_httpicontdateon_ [l=tr] {_httpimg_/tr/tdateon.gif}
+_widthtdatex_ [l=tr] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "dosya adlarÄ±" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=tr] {_httpimg_/tr/tsrcgr.gif}
+_httpicontsrcof_ [l=tr] {_httpimg_/tr/tsrcof.gif}
+_httpicontsrcon_ [l=tr] {_httpimg_/tr/tsrcon.gif}
+_widthtsrcx_ [l=tr] {87}
+
+## "dil" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=tr] {_httpimg_/tr/tlanggr.gif}
+_httpicontlangon_ [l=tr] {_httpimg_/tr/tlangon.gif}
+_httpicontlangof_ [l=tr] {_httpimg_/tr/tlangof.gif}
+_widthtlangx_ [l=tr] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "seriler" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=tr] {_httpimg_/tr/tsergr.gif}
+_httpicontserof_ [l=tr] {_httpimg_/tr/tserof.gif}
+_httpicontseron_ [l=tr] {_httpimg_/tr/tseron.gif}
+_widthtserx_ [l=tr] {87}
+
+## "kime" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=tr] {_httpimg_/tr/ttogr.gif}
+_httpiconttoon_ [l=tr] {_httpimg_/tr/ttoon.gif}
+_httpiconttoof_ [l=tr] {_httpimg_/tr/ttoof.gif}
+_widthttox_ [l=tr] {87}
+
+## "kimden" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=tr] {_httpimg_/tr/tfromgr.gif}
+_httpicontfromon_ [l=tr] {_httpimg_/tr/tfromon.gif}
+_httpicontfromof_ [l=tr] {_httpimg_/tr/tfromof.gif}
+_widthtfromx_ [l=tr] {87}
+
+## "kurumlar" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=tr] {_httpimg_/tr/torggr.gif}
+_httpicontorgon_ [l=tr] {_httpimg_/tr/torgon.gif}
+_httpicontorgof_ [l=tr] {_httpimg_/tr/torgof.gif}
+_widthtorgx_ [l=tr] {114}
+
+## "nasÄ±l" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=tr] {_httpimg_/tr/thowgr.gif}
+_httpiconthowon_ [l=tr] {_httpimg_/tr/thowon.gif}
+_httpiconthowof_ [l=tr] {_httpimg_/tr/thowof.gif}
+_widththowx_ [l=tr] {87}
+
+## "konu" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=tr] {_httpimg_/tr/ttopicgr.gif}
+_httpiconttopicon_ [l=tr] {_httpimg_/tr/ttopicon.gif}
+_httpiconttopicof_ [l=tr] {_httpimg_/tr/ttopicof.gif}
+_widthttopicx_ [l=tr] {87}
+
+## "gÃ¶zat" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=tr] {_httpimg_/tr/tbrwsegr.gif}
+_httpicontbrwseon_ [l=tr] {_httpimg_/tr/tbrwseon.gif}
+_httpicontbrwseof_ [l=tr] {_httpimg_/tr/tbrwseof.gif}
+_widthtbrwsex_ [l=tr] {87}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "kiÅiler" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=tr] {_httpimg_/tr/tpeopgr.gif}
+_httpicontpeopof_ [l=tr] {_httpimg_/tr/tpeopof.gif}
+_httpicontpeopon_ [l=tr] {_httpimg_/tr/tpeopon.gif}
+_widthtpeopx_ [l=tr] {97}
+
+## "kÄ±saltmalar" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=tr] {_httpimg_/tr/tacrogr.gif}
+_httpicontacroof_ [l=tr] {_httpimg_/tr/tacroof.gif}
+_httpicontacroon_ [l=tr] {_httpimg_/tr/tacroon.gif}
+_widthtacrox_ [l=tr] {87}
+
+## "ifadeler" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=tr] {_httpimg_/tr/tphrsegr.gif}
+_httpicontphrseof_ [l=tr] {_httpimg_/tr/tphrseof.gif}
+_httpicontphrseon_ [l=tr] {_httpimg_/tr/tphrseon.gif}
+_widthtphrsex_ [l=tr] {87}
+
+## "sanatÃ§Ä±lar" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=tr] {_httpimg_/tr/tartstgr.gif}
+_httpicontartstof_ [l=tr] {_httpimg_/tr/tartstof.gif}
+_httpicontartston_ [l=tr] {_httpimg_/tr/tartston.gif}
+_widthtartstx_ [l=tr] {87}
+
+## "anahtar sÃ¶zcÃŒkler" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=tr] {_httpimg_/tr/tkwgr.gif}
+_httpicontkwof_ [l=tr] {_httpimg_/tr/tkwof.gif}
+_httpicontkwon_ [l=tr] {_httpimg_/tr/tkwon.gif}
+_widthtkwx_ [l=tr] {87}
+
+## "ciltler" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=tr] {_httpimg_/tr/tvolgr.gif}
+_httpicontvolof_ [l=tr] {_httpimg_/tr/tvolof.gif}
+_httpicontvolon_ [l=tr] {_httpimg_/tr/tvolon.gif}
+_widthtvolx_ [l=tr] {87}
+
+## "baÅlÄ±klar" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=tr] {_httpimg_/tr/tcaptgr.gif}
+_httpicontcaptof_ [l=tr] {_httpimg_/tr/tcaptof.gif}
+_httpicontcapton_ [l=tr] {_httpimg_/tr/tcapton.gif}
+_widthtcaptx_ [l=tr] {87}
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "yardÄ±m" ## green_title ## h_help ##
+_httpiconhhelp_ [l=tr] {_httpimg_/tr/h\_help.gif}
+_widthhhelp_ [l=tr] {200}
+_heighthhelp_ [l=tr] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=tr] {Bu Koleksiyon hakkÄ±nda}
+
+_textsubcols1_ [l=tr] {<p>Bu koleksiyon _1_ alt koleksiyondan
+oluÅmaktadÄ±r:
+<blockquote>}
+
+_textsubcols2_ [l=tr] {</blockquote>
+Tercihler sayfasÄ±nda Åu anda kullandÄ±ÄÄ±nÄ±z alt koleksiyonlarÄ± kontrol edebilir ve deÄiÅtirebilirsiniz.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "hakkÄ±nda" ## green_title ## h_about ##
+_httpiconhabout_ [l=tr] {_httpimg_/tr/h\_about.gif}
+_widthhabout_ [l=tr] {200}
+_heighthabout_ [l=tr] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=tr] {BaÅlÄ±klar A-Z}
+_texticonhcreat_ [l=tr] {Yazarlar A-Z}
+_texticonhsubj_ [l=tr] {Konular}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=tr] {Tarihler}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=tr] {Dosya adlarÄ±}
+_texticonhlang_ [l=tr] {Diller}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=tr] {Kime}
+_texticonhfrom_ [l=tr] {Kimden}
+_texticonhser_ [l=tr] {Seriler}
+_texticonhhow_ [l=tr] {NasÄ±l}
+_texticonhorg_ [l=tr] {Kurumlar}
+_texticonhbrwse_ [l=tr] {GÃ¶zat}
+_texticonhbrows_ [l=tr] {GÃ¶zat}
+_texticonhpeople_ [l=tr] {KiÅi A-Z}
+_texticonhacronym_ [l=tr] {KÄ±saltmalar}
+_texticonhphrases_ [l=tr] {Ä°fadeler}
+_texticonhartist_ [l=tr] {SanatÃ§Ä±lar}
+_texticonhkw_ [l=tr] {Anahtar sÃ¶zcÃŒkler}
+_texticonhvol_ [l=tr] {Ciltler}
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=tr] {kÃŒtÃŒphanenin bu bÃ¶lÃŒmÃŒnÃŒ kapat}
+_texticonclosedbookshelf_ [l=tr] {kÃŒtÃŒphanenin bu bÃ¶lÃŒmÃŒnÃŒ aÃ§ ve iÃ§indekileri gÃ¶rÃŒntÃŒle}
+_texticonopenbook_ [l=tr] {kitabÄ± kapat}
+_texticonclosedfolder_ [l=tr] {dizini aÃ§ ve iÃ§indekileri gÃ¶rÃŒntÃŒle}
+_texticonclosedfolder2_ [l=tr] {alt bÃ¶lÃŒmÃŒ aÃ§: }
+_texticonopenfolder_ [l=tr] {dizini kapat}
+_texticonopenfolder2_ [l=tr] {alt bÃ¶lÃŒmÃŒ kapat: }
+_texticonsmalltext_ [l=tr] {metnin bu bÃ¶lÃŒmÃŒnÃŒ gÃ¶rÃŒntÃŒle}
+_texticonsmalltext2_ [l=tr] {metni gÃ¶rÃŒntÃŒle: }
+_texticonpointer_ [l=tr] {mevcut bÃ¶lÃŒm}
+_texticondetach_ [l=tr] {sayfayÄ± yeni pencerede aÃ§}
+_texticonhighlight_ [l=tr] {Aranan sÃ¶zcÃŒkleri iÅaretle}
+_texticonnohighlight_ [l=tr] {Aranan sÃ¶zcÃŒkleri}
+_texticoncontracttoc_ [l=tr] {Ä°Ã§indekiler tablosunu daralt}
+_texticonexpandtoc_ [l=tr] {Ä°Ã§indekiler tablosunu geniÅlet}
+_texticonexpandtext_ [l=tr] {TÃŒm metni gÃ¶ster}
+_texticoncontracttext_ [l=tr] {Sadece seÃ§ilmiÅ bÃ¶lÃŒmÃŒn metnini gÃ¶rÃŒntÃŒle}
+_texticonwarning_ [l=tr] {<b>UyarÄ±: </b>}
+_texticoncont_ [l=tr] {devam?}
+
+_textltwarning_ [l=tr] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Burada metinin geniÅletilmesi 
+tarayÄ±cÄ±nÄ±zÄ±n gÃ¶rÃŒntÃŒleyebileceÄinden daha bÃŒyÃŒk veri oluÅturur_imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=tr] {sayfaya git}
+_textintro_ [l=tr] {<i>(giriÅ metni)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "baÅlÄ±klar a-z" ## green_title ## h_title ##
+_httpiconhtitle_ [l=tr] {_httpimg_/tr/h\_title.gif}
+_widthhtitle_ [l=tr] {200}
+_heighthtitle_ [l=tr] {57}
+
+# Not true DC, kept for legacy reasons
+## "yazarlar a-z" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=tr] {_httpimg_/tr/h\_auth.gif}
+_widthhcreat_ [l=tr] {200}
+_heighthcreat_ [l=tr] {57}
+
+## "konular" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=tr] {_httpimg_/tr/h\_subj.gif}
+_widthhsubj_ [l=tr] {200}
+_heighthsubj_ [l=tr] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "tarihler" ## green_title ## h_date ##
+_httpiconhdate_ [l=tr] {_httpimg_/tr/h\_date.gif}
+_widthhdate_ [l=tr] {200}
+_heighthdate_ [l=tr] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "dosya adlarÄ±" ## green_title ## h_src ##
+_httpiconhsrc_ [l=tr] {_httpimg_/tr/h\_src.gif}
+_widthhsrc_ [l=tr] {200}
+_heighthsrc_ [l=tr] {57}
+
+## "diller" ## green_title ## h_lang ##
+_httpiconhlang_ [l=tr] {_httpimg_/tr/h\_lang.gif}
+_widthhlang_ [l=tr] {200}
+_heighthlang_ [l=tr] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "kime" ## green_title ## h_to ##
+_httpiconhto_ [l=tr] {_httpimg_/tr/h\_to.gif}
+_widthhto_ [l=tr] {200}
+_heighthto_ [l=tr] {57}
+
+## "kimden" ## green_title ## h_from ##
+_httpiconhfrom_ [l=tr] {_httpimg_/tr/h\_from.gif}
+_widthhfrom_ [l=tr] {200}
+_heighthfrom_ [l=tr] {57}
+
+## "seriler" ## green_title ## h_ser ##
+_httpiconhser_ [l=tr] {_httpimg_/tr/h\_ser.gif}
+_widthhser_ [l=tr] {200}
+_heighthser_ [l=tr] {57}
+
+## "nasÄ±l" ## green_title ## h_how ##
+_httpiconhhow_ [l=tr] {_httpimg_/tr/h\_how.gif}
+_widthhhow_ [l=tr] {200}
+_heighthhow_ [l=tr] {57}
+
+## "konular" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=tr] {_httpimg_/tr/h\_topic.gif}
+_widthhtopic_ [l=tr] {200}
+_heighthtopic_ [l=tr] {57}
+
+## "kurum" ## green_title ## h_org ##
+_httpiconhorg_ [l=tr] {_httpimg_/tr/h\_org.gif}
+_widthhorg_ [l=tr] {250}
+_heighthorg_ [l=tr] {57}
+
+## "gÃ¶zat" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=tr] {_httpimg_/tr/h\_brwse.gif}
+_widthhbrwse_ [l=tr] {200}
+_heighthbrwse_ [l=tr] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "kiÅiler" ## green_title ## h_people ##
+_httpiconhpeople_ [l=tr] {_httpimg_/tr/h\_people.gif}
+_widthhpeople_ [l=tr] {200}
+_heighthpeople_ [l=tr] {57}
+
+## "kÄ±saltmalar" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=tr] {_httpimg_/tr/h\_acro.gif}
+_widthhacronym_ [l=tr] {200}
+_heighthacronym_ [l=tr] {57}
+
+## "ifadeler" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=tr] {_httpimg_/tr/h\_phrse.gif}
+_widthhphrse_ [l=tr] {200}
+_heighthphrse_ [l=tr] {57}
+
+## "santÃ§Ä±lar" ## green_title ## h_artist ##
+_httpiconhartist_ [l=tr] {_httpimg_/tr/h\_artist.gif}
+_widthhartist_ [l=tr] {200}
+_heighthartist_ [l=tr] {57}
+
+## "anahtar sÃ¶zcÃŒkler" ## green_title ## h_kw ##
+_httpiconhkw_ [l=tr] {_httpimg_/tr/h\_kw.gif}
+_widthhkw_ [l=tr] {200}
+_heighthkw_ [l=tr] {57}
+
+## "ciltler" ## green_title ## h_vol ##
+_httpiconhvol_ [l=tr] {_httpimg_/tr/h\_vol.gif}
+_widthhvol_ [l=tr] {200}
+_heighthvol_ [l=tr] {57}
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+## "captions" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=tr] {_httpimg_/tr/h\_capt.gif}
+_widthhcapt_ [l=tr] {200}
+_heighthcapt_ [l=tr] {57}
+
+
+## "DEVAM??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=tr] {_httpimg_/tr/contof.gif}
+_httpiconconton_ [l=tr] {_httpimg_/tr/conton.gif}
+
+## "METNÄ°\nGENÄ°ÅLET" ## document_button ## eallt ##
+_httpiconealltof_ [l=tr] {_httpimg_/tr/ealltof.gif}
+_httpiconeallton_ [l=tr] {_httpimg_/tr/eallton.gif}
+
+## "Ä°ÃÄ°NDEKÄ°LERÄ°\nDARALT" ## document_button ## econc ##
+_httpiconeconcof_ [l=tr] {_httpimg_/tr/econcof.gif}
+_httpiconeconcon_ [l=tr] {_httpimg_/tr/econcon.gif}
+
+## "AÃ" ## document_button ## edtch ##
+_httpiconedtchof_ [l=tr] {_httpimg_/tr/edtchof.gif}
+_httpiconedtchon_ [l=tr] {_httpimg_/tr/edtchon.gif}
+
+## "Ä°ÃÄ°NDEKÄ°LERÄ°\nAÃ" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=tr] {_httpimg_/tr/eexpcof.gif}
+_httpiconeexpcon_ [l=tr] {_httpimg_/tr/eexpcon.gif}
+
+## "METNÄ°\nDARALT" ## document_button ## etsec ##
+_httpiconetsecof_ [l=tr] {_httpimg_/tr/etsecof.gif}
+_httpiconetsecon_ [l=tr] {_httpimg_/tr/etsecon.gif}
+
+## "Ä°ÅARETLEME" ## document_button ## ehl ##
+_httpiconehlof_ [l=tr] {_httpimg_/tr/ehlof.gif}
+_httpiconehlon_ [l=tr] {_httpimg_/tr/ehlon.gif}
+
+## "Ä°ÅARETLEME\nYOK" ## document_button ## enhl ##
+_httpiconenhlof_ [l=tr] {_httpimg_/tr/enhlof.gif}
+_httpiconenhlon_ [l=tr] {_httpimg_/tr/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=tr] {_If_(_thislast_,results _thisfirst_ - _thislast_ for query: _cgiargq_,Arama sonucu bulunamadÄ±: _cgiargq_)}
+_textnoquerytitle_ [l=tr] {Arama sayfasÄ±}
+
+_texticonthispage_ [l=tr] {arama}
+_textsome_ [l=tr] {bazÄ±larÄ±nÄ± }
+_textall_ [l=tr] {tÃŒmÃŒ}
+_textboolean_ [l=tr] {boolean}
+_textranked_ [l=tr] {sÄ±ralÄ±}
+_textnatural_ [l=tr] {basit}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=tr] {}
+_texticonsearchhistorybar_ [l=tr] {Ã¶nceki arama}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=tr] {bu sorguyu kullan}
+_textfreqmsg1_ [l=tr] {SÃ¶zcÃŒk sayÄ±sÄ±: }
+_textpostprocess_ [l=tr] {_If_(_quotedquery_,<br><i>Åunu bulmak iÃ§in iÅlemden geÃ§ti:  _quotedquery_</i>
+)}
+_textinvalidquery_ [l=tr] {GeÃ§ersiz arama sÃ¶z dizimi}
+
+_textmorethan_ [l=tr] {Daha fazla }
+_textapprox_ [l=tr] {HakkÄ±nda }
+_textnodocs_ [l=tr] {Arama sonucu bulunamadÄ±.}
+_text1doc_ [l=tr] {1 belge bulundu.}
+_textlotsdocs_ [l=tr] {belge bulundu.}
+_textmatches_ [l=tr] {EÅleÅtirildi }
+_textbeginsearch_ [l=tr] {AramayÄ± BaÅlat}
+_textrunquery_ [l=tr] {Sorgula}
+_textclearform_ [l=tr] {Formu Temizle}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=tr] {SÃ¶zcÃŒk ya da ifade}
+_textinfield_ [l=tr] {... alanda}
+_textfoldstem_ [l=tr] {(gÃ¶vde, kÃ¶k)}
+
+_textadvquery_ [l=tr] {Ya da doÄrudan sorgula:}
+_textallfields_ [l=tr] {tÃŒm alanlar}
+_texttextonly_ [l=tr] {salt metin}
+_textand_ [l=tr] {ve}
+_textor_ [l=tr] {ya da}
+_textandnot_ [l=tr] {ve deÄil}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+# -- Missing translation: _textsimplesearch_
+
+# -- Missing translation: _textadvancedsearch_
+
+_textformsimplesearch_ [l=tr] {Arama yap _If_(_jselection_,_jselection_)_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )for _formquerytypeselection_ of}
+
+_textformadvancedsearch_ [l=tr] {Arama yap _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )ve sonuÃ§larÄ± ÅÃ¶yle gÃ¶rÃŒntÃŒle: _formquerytypeselection_ order}
+
+
+_textnojsformwarning_ [l=tr] {UyarÄ±: TarayÄ±cÄ±nÄ±zda Javascript uygulamalarÄ± pasifleÅtirilmiÅ. <br>Form aramasÄ± yapabilmek iÃ§in etkinleÅtirmeniz gerekiyor.}
+_textdatesearch_ [l=tr] {Bu koleksiyonda belgeler belirli tarihler arasÄ±nda ya da belirli bir tarihe gÃ¶re aranÄ±r; bu, aramanÄ±n seÃ§ime baÄlÄ± opsiyonel bir Ã¶zelliÄidir.}
+_textstartdate_ [l=tr] {BaÅlama (ya da tek) tarihi:}
+_textenddate_ [l=tr] {BitiÅ tarihi:}
+_textbc_ [l=tr] {M.Ã.}
+_textad_ [l=tr] {M.S.}
+_textexplaineras_ [l=tr] {M.Ã. Milattan Ã¶nceyi, M.S. Milattan sonrayÄ± belirtmektedir.}
+
+_textstemon_ [l=tr] {(sÃ¶zcÃŒk bitimini gÃ¶zardÄ± et)}
+
+_textsearchhistory_ [l=tr] {Ãnceki Aramalar}
+
+#text macros for search history
+_textnohistory_ [l=tr] {Ãnceki arama sonuÃ§larÄ± mevcut deÄil}
+_texthresult_ [l=tr] {sonuÃ§}
+_texthresults_ [l=tr] {sonuÃ§}
+_texthallwords_ [l=tr] {tÃŒm sÃ¶zcÃŒkler}
+_texthsomewords_ [l=tr] {herhangi birini}
+_texthboolean_ [l=tr] {boolean}
+_texthranked_ [l=tr] {sÄ±ralÄ±}
+_texthcaseon_ [l=tr] {kÃŒÃ§ÃŒk/bÃŒyÃŒk harf duyarlÄ±}
+_texthcaseoff_ [l=tr] {kÃŒÃ§ÃŒk/bÃŒyÃŒk harf duyarSIZ}
+_texthstemon_ [l=tr] {stemmed}
+_texthstemoff_ [l=tr] {unstemmed}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "arama" ## green_title ## h_search ##
+_httpiconhsearch_ [l=tr] {_httpimg_/tr/h\_search.gif}
+_widthhsearch_ [l=tr] {200}
+_heighthsearch_ [l=tr] {57}
+
+## "sonuÃ§lar" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=tr] {_httpimg_/tr/qryresb.gif}
+_widthqryresb_ [l=tr] {_pagewidth_}
+_heightqryresb_ [l=tr] {17}
+
+## "geÃ§miÅ aramalar" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=tr] {_httpimg_/tr/schhistb.gif}
+_widthsrchhistb_ [l=tr] {_pagewidth_}
+_heightsrchhistb_ [l=tr] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=tr] {Tercihleri aÅaÄÄ±daki menÃŒden deÄiÅtirebilirsiniz. TarayÄ±cÄ±nÄ±zÄ±n
+"geri" dÃŒÄmesini kullanmayÄ±nÄ±z! YukarÄ±daki eriÅim Ã§ubuÄunu kullanÄ±nÄ±z.
+}
+_textsetprefs_ [l=tr] {tercihleri kaydet}
+_textsearchprefs_ [l=tr] {Arama tercihleri}
+_textcollectionprefs_ [l=tr] {Koleksiyon tercihleri}
+_textpresentationprefs_ [l=tr] {GÃ¶rÃŒnÃŒm tercihleri}
+_textpreferences_ [l=tr] {Tercihler}
+_textcasediffs_ [l=tr] {BÃŒyÃŒk/kÃŒÃ§ÃŒk harf:}
+_textignorecase_ [l=tr] {bÃŒyÃŒk/kÃŒÃ§ÃŒk harf farklÄ±lÄ±klarÄ± dikkate alma}
+_textmatchcase_ [l=tr] {kÃŒÃ§ÃŒk/bÃŒyÃŒk harf farklÄ±lÄ±klarÄ± dikkate al}
+_textwordends_ [l=tr] {SÃ¶zcÃŒk sonu:}
+_textstem_ [l=tr] {sÃ¶zcÃŒk bitiÅlerini dikkate alma}
+_textnostem_ [l=tr] {tÃŒm sÃ¶zcÃŒk eÅleÅmeli}
+_textprefop_ [l=tr] {Taramada _maxdocoption_ adet bul, her sayfada _hitsperpageoption_ adet gÃ¶ster.}
+_textextlink_ [l=tr] {DÄ±Å web sayfalarÄ±na giriÅ:}
+_textintlink_ [l=tr] {Kaynak belgerinin Ã§aÄrÄ±ldÄ±ÄÄ± yer:}
+_textlanguage_ [l=tr] {ArayÃŒz dili:}
+_textencoding_ [l=tr] {Dil kodlamasÄ±:}
+_textformat_ [l=tr] {ArayÃŒz gÃ¶rÃŒnÃŒmÃŒ:}
+_textall_ [l=tr] {TÃŒmÃŒ}
+_textquerymode_ [l=tr] {Arama Åekli :}
+_textsimplemode_ [l=tr] {basit arama}
+_textadvancedmode_ [l=tr] {geliÅmiÅ arama ( !, &, |, ve parantezlerin kullanÄ±mÄ±yla "boolean" arama yapabilirsiniz)}
+_textlinkinterm_ [l=tr] {ara sayfa yoluyla}
+_textlinkdirect_ [l=tr] {doÄrudan git}
+_textdigitlib_ [l=tr] {sanal kÃŒtÃŒphane}
+_textweb_ [l=tr] {web}
+_textgraphical_ [l=tr] {Grafik}
+_texttextual_ [l=tr] {Metin}
+_textcollectionoption_ [l=tr] {<p>
+Alt koleksiyonlar:
+<br>}
+
+_textrelateddocdisplay_ [l=tr] {iliÅkili belgeleri gÃ¶ster}
+_textsearchhistory_ [l=tr] {Ãnceki arama:}
+_textnohistory_ [l=tr] {Ãnceki arama sonuÃ§larÄ± mevcut deÄil}
+_texthistorydisplay_ [l=tr] {Ã¶nceki arama sonuÃ§larÄ±ndan _historynumrecords_ adet gÃ¶ster.}
+_textnohistorydisplay_ [l=tr] {Ã¶nceki arama sonuÃ§larÄ±nÄ± gÃ¶sterme}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=tr] {form arama}
+_textplainsearch_ [l=tr] {DÃŒz arama:}
+_textqueryboxsize_ [l=tr] {arama kutusu bÃŒyÃŒklÃŒÄÃŒ :}
+_textregbox_ [l=tr] {normal arama kutusu}
+_textbigbox_ [l=tr] {geniÅ arama kutusu}
+_textformtype_ [l=tr] {Form tÃŒrÃŒ:}
+_textsimple_ [l=tr] {basit}
+_textadvanced_ [l=tr] {geliÅmiÅ}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=tr] {ile}
+_textfields_ [l=tr] {alanlar}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "tercihler" ## green_title ## h_pref ##
+_httpiconhpref_ [l=tr] {_httpimg_/tr/h\_pref.gif}
+_widthhpref_ [l=tr] {200}
+_heighthpref_ [l=tr] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=tr] {DokÃŒmanlarÄ± sÄ±rala}
+_textalsoshowing_ [l=tr] {gÃ¶stererek}
+_textwith_ [l=tr] {with at most}
+_textdocsperpage_ [l=tr] {sayfa baÅÄ±na belge sayÄ±sÄ±}
+
+_textfilterby_ [l=tr] {Åunu iÃ§eren belgeleri getir:}
+_textall_ [l=tr] {hepsi}
+_textany_ [l=tr] {herhangi biri}
+_textwords_ [l=tr] {kelimede}
+_textleaveblank_ [l=tr] {TÃŒm belgeleri gÃ¶rmek iÃ§in kutuyu boÅ bÄ±rak}
+
+_browsebuttontext_ [l=tr] {"Belgeleri SÄ±rala"}
+
+_nodata_ [l=tr] {<i>veri yok</i>}
+_docs_ [l=tr] {belgeler}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=tr] {YardÄ±m}
+_textSearchshort_ [l=tr] {belirli sÃ¶zcÃŒklerle arama}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=tr] {belge baÅlÄ±ÄÄ±na gÃ¶re yayÄ±nlara eriÅim}
+_textCreatorshort_ [l=tr] {yazar adÄ±ndan yayÄ±nlara eriÅim}
+_textSubjectshort_ [l=tr] {konuya gÃ¶re yayÄ±nlara eriÅim}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=tr] {tarihe gÃ¶re yayÄ±nlara eriÅim}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=tr] {dosya adÄ±na gÃ¶re yayÄ±nlara eriÅim}
+_textLanguageshort_ [l=tr] {yayÄ±n diline gÃ¶re yayÄ±nlara eriÅim}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=tr] {seri adÄ±na gÃ¶re yayÄ±nlara eriÅim}
+_textToshort_ [l=tr] {Kime alanÄ±na gÃ¶re yayÄ±nlara eriÅim}
+_textFromshort_ [l=tr] {Kimden alanÄ±na gÃ¶re yayÄ±nlara eriÅim}
+_textBrowseshort_ [l=tr] {yayÄ±nlara gÃ¶zat}
+_textOrganizationshort_ [l=tr] {kurum adÄ±na  gÃ¶re yayÄ±nlara eriÅim}
+_textHowtoshort_ [l=tr] {"nasÄ±l" listesi ile yayÄ±nlara eriÅim}
+_textTopicshort_ [l=tr] {konularÄ±na gÃ¶re yayÄ±nlara eriÅim}
+_textPeopleshort_ [l=tr] {kiÅi adÄ±na gÃ¶re yayÄ±nlara eriÅim}
+_textAcronymshort_ [l=tr] {kÄ±saltmalardan yayÄ±nlara eriÅim}
+_textPhraseshort_ [l=tr] {yayÄ±nlardaki ifadelere gÃ¶re }
+_textArtistshort_ [l=tr] {sanatÃ§Ä±lara gÃ¶re yayÄ±nlara eriÅim}
+_textKeywordshort_ [l=tr] {anahtar sÃ¶zcÃŒklerle yayÄ±nlara eriÅim }
+_textVolumeshort_ [l=tr] {ciltlerine gÃ¶re yayÄ±nlara eriÅim }
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=tr] {tanÄ±mlanamamÄ±Å sÄ±nÄ±flama}
+
+_textSearchlong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de <i>belirli kelimeleri </i> bulmak iÃ§in
+arama sayfasÄ± kullanÄ±lÄ±r. Programa giriÅte karÅÄ±nÄ±za gelen ilk sayfadÄ±r. DiÄer 
+sayfalardan <i>arama</i> butonu seÃ§ilerek ulaÅÄ±labilir. }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de <i>yayÄ±nlara eser adÄ±yla eriÅim</i> 
+<i>baÅlÄ±k a-z</i> butonu seÃ§ilerek saÄlanÄ±r. YayÄ±n listesi ekrana alfabetik 
+sÄ±ralanÄ±r.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de <i>yayÄ±nlara yazar adÄ±yla eriÅim</i> 
+<i>yazarlar a-z</i> butonu seÃ§ilerek saÄlanÄ±r. Yazar adlarÄ±na gÃ¶re sÄ±ralanmÄ±Å 
+yayÄ±n listesi gÃ¶rÃŒntÃŒlenir.  }
+
+_textSubjectlong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de <i>yayÄ±nlara konu baÅlÄ±ÄÄ±ndan eriÅim</i> 
+ <i>konu baÅlÄ±ÄÄ±</i> butonu seÃ§ilerek saÄlanÄ±r. 
+Bu bize konu baÅlÄ±ÄÄ± listesini oluÅturur.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de <i>yayÄ±nlara yayÄ±n tarihinden eriÅim</i> 
+<i>tarihler</i> butonu seÃ§ilerek saÄlanÄ±r. Bu bize kronolojik olarak listelenmiÅ
+sayÄ±larÄ±n gÃ¶sterilmesini saÄlar.  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=tr] {<p>Sanal kÃŒtÃŒphanede <i>yayÄ±nlara dosya adÄ±yla eriÅim</i> iÃ§in
+<i>dosya adÄ±</i> butonu seÃ§ilir. Bu bize Ã¶zgÃŒn dosya adÄ±na gÃ¶re oluÅturulan bir listeyi gÃ¶rÃŒntÃŒler.}
+
+_textLanguagelong_ [l=tr] {<p>Sanal kÃŒtÃŒphanede <i>yayÄ±nlara yayÄ±n dilinden eriÅim</i>
+<i>diller</i> butonu seÃ§ilerek saÄlanÄ±r.  }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de <i>yayÄ±ncÄ± kurumlara </i> eriÅim 
+ <i>kurumlar</i> butonu seÃ§ilerek saÄlanÄ±r. Kurumlar alfabetik olarak listelenir.  }
+
+_textHowtolong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de <i>"nasÄ±l" listesi</i>
+<i>nasÄ±l</i> butonu seÃ§ilerek oluÅturulur.  }
+
+_textTopiclong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de <i>yayÄ±nlara konu eriÅimi</i>
+<i>konu</i> butonu seÃ§ilerek saÄlanÄ±r. Konu listesi gÃ¶rÃŒntÃŒlenir.  }
+
+_textTolong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de e-posta koleksiyonlarÄ±nda <i>yayÄ±nlara Kime alanÄ±na gÃ¶re</i>eriÅim
+ <i>Kime</i> butonu seÃ§ilerek saÄlanÄ±r. Adres listesi ekrana alfabetik sÄ±ralanÄ±r.}
+
+_textFromlong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de <i>From</i>eriÅim 
+<i>from</i> butonu seÃ§ilerek saÄlanÄ±r.  }
+
+_textSerieslong_ [l=tr] {<p>Sanal kÃŒtÃŒphane'de <i>serilerle yayÄ±na eriÅim</i> 
+<i>seriler</i> butonu seÃ§ilerek saÄlanÄ±r. Bu bize koleksiyonda var olan 
+seriler listesini gÃ¶sterir. }
+
+_textBrowselong_ [l=tr] {<p>Sanal kÃŒtÃŒphanede <i>yayÄ±nlara gÃ¶zatmak iÃ§in</i> 
+<i>gÃ¶zat</i> butunu seÃ§ilir.  }
+
+_textPeoplelong_ [l=tr] {<p>Sanal kÃŒtÃŒphanede <i>yayÄ±nlara kiÅi adÄ±ndan eriÅim</i> 
+<i>kiÅiler a-z</i>butonu seÃ§ilerek saÄlanÄ±r. Bu soyadÄ±na gÃ¶re sÄ±ralanmÄ±Å 
+kiÅi listesi verir. }
+
+_textAcronymlong_ [l=tr] {<p>Sanal kÃŒtÃŒphanede <i>yayÄ±nlara kÄ±saltmalarla eriÅim</i>
+<i>kÄ±saltmalar</i> butonu seÃ§ilerek saÄlanÄ±r. Bu bize kÄ±saltmalar ve kÄ±saltmalarÄ±n
+geÃ§tiÄi yerleri veren liste oluÅturur.  }
+
+_textPhraselong_ [l=tr] {<p>Sanal kÃŒtÃŒphanede <i>yayÄ±nlarda geÃ§en ifadelere gÃ¶zatmak </i> iÃ§in
+<i>ifadeler</i> butonunu seÃ§eriz. }
+
+_textArtistlong_ [l=tr] {<p>Sanal kÃŒtÃŒphanede <i>yayÄ±nlara sanatÃ§Ä±larla eriÅim</i>
+<i>sanatÃ§Ä±lar</i>  butonu seÃ§ilerek saÄlanÄ±r.  }
+
+_textKeywordlong_ [l=tr] {<p>Sanal kÃŒtÃŒphanede <i>yayÄ±nlara anahtar sÃ¶zcÃŒklerle eriÅim</i>
+ <i>anahtar sÃ¶zcÃŒkler</i> butonu seÃ§ilerek saÄlanÄ±r.}
+
+# -- Missing translation: _textVolumelong_
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=tr] {<p><i>Bilinmeyen</i> botonu seÃ§ilerek yayÄ±nlara eriÅilir.  }
+
+_texthelptopics_ [l=tr] {<h2 align=left>Konular</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">Kelimeler nasÄ±l aranÄ±r</a>
+<ul>
+  <li><a href="\#query-terms">Arama terimleri</a>
+  <li><a href="\#query-type">Arama tipi</a>
+  <li><a href="\#scope-of-queries">Arama konusu</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Koleksiyon ayarlarÄ±</a>
+  <li><a href="\#lang-prefs">Dil ayarlarÄ±</a>
+  <li><a href="\#pres-prefs">GÃ¶rÃŒnÃŒm ayarlarÄ±</a>
+  <li><a href="\#search-prefs">Arama ayarlarÄ±</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=tr] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=tr] {Belgeler nasÄ±l okunur}
+
+_texthelpreadingdocs_ [l=tr] {<p>_iconblankbar_
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>Belgeye eriÅtiÄimizde sol ÃŒst kÃ¶Åede baÅlÄ±k ve yazar
+adÄ± gÃ¶rÃŒlÃŒr. Bunun yanÄ±nda sayfa numarasÄ±, yeni bir sayfa seÃ§memize
+yarayan bir kutucuk ve ileri-geri oklarÄ± bulunmaktadÄ±r.
+
+<p>Alt kÄ±sÄ±mda seÃ§ilen bÃ¶lÃŒmÃŒn metni, devam ettiÄimizde
+bir Ã¶nceki veya bir sonraki bÃ¶lÃŒme geÃ§memizi saÄlayan oklar bulunmaktadÄ±r. 
+
+<p>BaÅlÄ±k ve yazar adÄ± altÄ±nda ÃŒÃ§ dÃŒÄme vardÄ±r. <i>GeniÅletilmiÅ metni</i>
+seÃ§tiÄimizde belgenin tamamÄ±nÄ± gÃ¶rebiliriz. EÄer belge bÃŒyÃŒkse yÃŒklenmesi 
+zaman alacaktÄ±r. <i>Yeni pencere</i> seÃ§ildiÄinde belge yeni bir 
+pencerede aÃ§Ä±lÄ±r. SonuÃ§ olarak arama yaptÄ±ÄÄ±mÄ±z sÃ¶zcÃŒkler <i>iÅaretli</i> dir. 
+Bunu kaldÄ±rmak istiyorsanÄ±z <i>iÅaretlemeyi kaldÄ±r</i> butonu seÃ§ilmelidir.  
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Bir sonraki bÃ¶lÃŒme geÃ§mek iÃ§in tÄ±klayÄ±nÄ±z ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... veya bir Ã¶nceki bÃ¶lÃŒme dÃ¶nmek iÃ§in</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>TÃŒm metni gÃ¶ster ya da gÃ¶sterme</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Bu sayfayÄ± yeni bir pencerede aÃ§</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>Arama sÃ¶zcÃŒklerini iÅaretle ya da iÅaretleme</td></tr>
+</table>
+
+}
+
+_texthelpsearching_ [l=tr] {<h2>Belirli kelimeler nasÄ±l aranÄ±r</h2>
+<p>
+  Arama sayfasÄ±ndan sorgulama yapÄ±lÄ±r, bunun iÃ§in:<p>
+  
+  <ol><li>Aranmak istenen bilgi belirlenir
+      <li>Hepsinin mi, yoksa bazÄ± sÃ¶zcÃŒklerin mi aranmak istendiÄi belirlenir
+      <li>Aranan sÃ¶zcÃŒkler yazÄ±lÄ±r
+      <li>Son olarak <i>Arama</i> dÃŒÄmesi seÃ§ilir.
+  </ol>
+
+<p>Arama sonunda yirmi belge gÃ¶rÃŒntÃŒlenecektir. SayfanÄ±n altÄ±nda bir sonraki yirmi 
+belgeye gÃ¶tÃŒrecek dÃŒÄme bulunmaktadÄ±r. <i>Tercihlerden</i>  gÃ¶sterilecek belge deÄiÅtirilebilir.
+  
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>Arama SÃ¶zcÃŒkleri</h3>
+
+<p>SÃ¶zcÃŒkler yazÄ±lÄ±rken aralarÄ±na boÅluk bÄ±rakÄ±lÄ±r. Noktalama iÅaretleri yazmayÄ±nÄ±z, 
+taranamaz.
+
+
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Sorgulama</h3>
+
+<p>Ä°ki farklÄ± sorgulama tÃŒrÃŒ vardÄ±r.
+
+<ul>
+  <li>BÃŒtÃŒn sÃ¶zcÃŒklerin yazÄ±ldÄ±ÄÄ± sorgulama
+     <p>
+
+  <li>BazÄ± sÃ¶zcÃŒklerin yazÄ±ldÄ±ÄÄ± sorgulama
+
+      
+</ul>
+
+<p>Ä°stediÄiniz birÃ§ok arama sÃ¶zcÃŒÄÃŒnÃŒ kullanabilirsiniz. BÃŒtÃŒn cÃŒmle veya paragraf yazÄ±labilir.
+Sadece tek bir sÃ¶zcÃŒk tanÄ±mlarsanÄ±z geÃ§me sÄ±klÄ±ÄÄ±na gÃ¶re sÄ±ralanÄ±r.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=tr] {Tarihe gÃ¶re tarama}
+
+_texthelpdatesearch_ [l=tr] {<h2>_textdatesearch_</h2>
+Tarihe gÃ¶re aramalarda belirli bir zaman aralÄ±ÄÄ± iÃ§erisindeki dokÃŒmanlar 
+aranÄ±r. Belirli bir yÄ±lÄ± veya yÄ±llar arasÄ±nÄ± arayabilirsiniz. HiÃ§bir arama
+sÃ¶zcÃŒÄÃŒnÃŒz yoksa yalnÄ±zca tarihe gÃ¶re arama yapabilirsiniz. Ve taramanÄ±zda 
+tarih belirtme zorunluluÄu da yoktur.<p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>Bu Ã¶zelliÄi nasÄ±l kullanÄ±rÄ±z:</h3>
+<ul>
+   <li>Tek bir yÄ±l iÃ§in belge arama:<p>
+   <ul>
+       <li>Ä°stediÄiniz bir arama sÃ¶zcÃŒÄÃŒnÃŒ yazÄ±nÄ±z 
+       <li>BaÅlangÄ±Ã§ tarihi kutucuÄuna istediÄiniz tarihi yazÄ±nÄ±z
+       <li>EÄer aradÄ±ÄÄ±nÄ±z tarih milattan Ã¶nceyse kutunun yanÄ±ndaki menÃŒden M.Ã. seÃ§in.
+       <li>Aramaya baÅlayÄ±n.
+   </ul>
+<p><li>Belirli bir zaman veya zaman aralÄ±ÄÄ±nda arama:<p>
+   <ul>
+       <li>Ä°stediÄiniz bir arama sÃ¶zcÃŒÄÃŒnÃŒ yazÄ±nÄ±z 
+       <li>BaÅlangÄ±Ã§ tarihi yazan kutucuÄa ilk tarihi yazÄ±yoruz. 
+       <li>BitiÅ tarihi kutucuÄuna sonraki tarihi yazÄ±yoruz.
+       <li>M.Ã. seÃ§iyoruz.
+       <li>Taramaya baÅlÄ±yoruz.
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>Arama sonuÃ§larÄ±</h3>
+    Arama sonuÃ§larÄ± ayrÄ±ntÄ±lÄ± olarak ekrana gelir.<p>
+}
+
+_textchangeprefs_ [l=tr] {AyarlarÄ±nÄ±zÄ± DeÄiÅtirmek}
+
+_texthelppreferences_ [l=tr] {<h2>_textchangeprefs_</h2>
+
+<p>SayfanÄ±n ÃŒstÃŒndeki <i>tercihler</i> dÃŒÄmesini seÃ§tiÄinizde isteÄinize
+gÃ¶re sayfanÄ±n arayÃŒzÃŒndeki bazÄ± Ã¶zellikleri deÄiÅtirebilirsiniz.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Koleksiyon tercihleri</h3>
+
+BazÄ± koleksiyonlar baÄÄ±msÄ±z ya da birlikte taranabilecek Åekilde alt 
+koleksiyonlardan oluÅmuÅtur. Ayarlar sayfasÄ±ndan istediÄiniz alt 
+koleksiyonu seÃ§ebilirsiniz.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Dil tercihleri</h3>
+
+Her koleksiyonun kendine Ã¶zgÃŒ bir dili vardÄ±r. Ä°stediÄiniz farklÄ± bir dile
+Ã§evirebilirsiniz. Ä°stediÄiniz karakter setini ayarlamanÄ±z da mÃŒmkÃŒndÃŒr. TarayÄ±cÄ±nÄ±z
+tanÄ±mlÄ± olan karakter setini seÃ§ecektir. Kendiniz bu ayarlamayÄ± yaptÄ±ÄÄ±nÄ±zda 
+daha iyi sonuÃ§lar alabilirsiniz.
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>GÃ¶rÃŒnÃŒm tercihleri</h3>
+
+GÃ¶rÃŒnÃŒmÃŒ ayarlayabileceÄiniz birkaÃ§ seÃ§enek vardÄ±r. 
+
+<p>Bu seÃ§enekler kullanÄ±m kolaylÄ±ÄÄ± saÄlar.
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>Arama tercihleri</h3>
+<p> Ä°ki adet dÃŒÄme yaptÄ±ÄÄ±nÄ±z aramalardaki eÅleÅtirmeleri kontrol eder. 
+Birincisi bÃŒyÃŒk, kÃŒÃ§ÃŒk harf ayrÄ±mÄ±nÄ±, ikincisi ise kelime sonlandÄ±rmayÄ± 
+kontrol eder. Arama kutusu isteÄe gÃ¶re bÃŒyÃŒtÃŒlebilir.
+
+
+<p> AyrÄ±ntÄ±lÄ± taramada boolean operatÃ¶rleri kullanÄ±labilir. Bu da aramayÄ±
+Ã¶zelleÅtirmemizi saÄlar. Eski aramalar ekranda gÃ¶rÃŒntÃŒlenebilir. 
+}
+
+_texttanumbrowseoptions_ [l=tr] {Bu koleksiyondaki bilgilere eriÅim iÃ§in _numbrowseoptions_ yol vardÄ±r.}
+
+_textsimplehelpheading_ [l=tr] {_collectionname_ koleksiyonu}
+
+_texthelpscope_ [l=tr] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Arama alanÄ±</h3>
+
+<p>
+BirÃ§ok koleksiyonda arama yapmak iÃ§in farklÄ± indeksler seÃ§ebilirsiniz.
+ÃrneÄin bu bir yazar yada baÅlÄ±k indeksi  veya bÃ¶lÃŒm paragraf indeksi 
+olabilir. Hangi indeks seÃ§ilirse tarama sonucu o indeksten elde edilir. <p> 
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/turkish2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/turkish2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/turkish2.dm	(revision 10506)
@@ -0,0 +1,1116 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Turkish Language text and icon macros 
+# -- this file contains english text that is of less importance
+# -- to translate when creating a new interface language
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=tr] {DokÃŒmanlar }
+_lastupdate_ [l=tr] {En son GÃŒncelleme}
+_ago_ [l=tr] {gÃŒn Ã¶nce yapÄ±ldÄ±.}
+_colnotbuilt_ [l=tr] {Derleme yapÄ±landÄ±rÄ±lmadÄ±.}
+
+_textpagetitle_ [l=tr] {Greenstone Sanal KÃŒtÃŒphanesi}
+_textadmin_ [l=tr] {YÃ¶netici SayfasÄ±}
+_textabgs_ [l=tr] {Greenstone}
+_textgsdocs_ [l=tr] {Greenstone Belgelendirme}
+
+_textimagegli_ [l=tr] {Yeni koleksiyonlarÄ± oluÅturma, varolan koleksiyonlarÄ± deÄiÅtirme veya silme iÅlemlerine yardÄ±m eder.
+}
+
+# -- Missing translation: _textimagecollector_
+
+# -- Missing translation: _textimagetranslator_
+
+_textimageadmin_ [l=tr] {Yeni kullanÄ±cÄ±lar tanÄ±mlamanÄ±za izin verir, sistemdeki koleksiyonlarÄ± Ã¶zetler, 
+Greenstone'un kurulumu hakkÄ±nda teknik bilgiler verir.
+}
+
+_textimagegogreenstone_ [l=tr] {Greenstone yazÄ±lÄ±mÄ± ve yazÄ±lÄ±mÄ±n kaynaÄÄ± olanYeni Zelanda Sanal KÃŒtÃŒphanesi Projesi 
+hakkÄ±nda bilgiler verir.
+}
+
+_textimagegodocs_ [l=tr] {Greenstone elkitabÄ±}
+
+_textpoem_ [l=tr] {<p>BarÄ±Å ve huzur sarsÄ±n sizi.
+<br>Yaz sÄ±caklÄ±ÄÄ±nÄ±n pusu iÃ§inde kalÄ±n Ã¶ylece
+<br>ve okyanuslar boyunca sÃŒren yolculuklarÄ±nÄ±z pÃŒrÃŒzsÃŒz bir yeÅim taÅÄ±na dÃ¶nsÃŒn.
+}
+
+_textgreenstone_ [l=tr] {<p>
+
+Greenstone (yeÅim taÅÄ±) Yeni Zelanda'da bulunan yarÄ± kÄ±ymetli bir taÅtÄ±r. 
+Bu yazÄ±lÄ±m da aynÄ± Ã¶zellikleri gÃ¶stermektedir.Maori kabilesinin tÃ¶relerine
+gÃ¶re YeÅim taÅÄ± bÃŒtÃŒn diÄer madenlere gÃ¶re en fazla Ã¶vgÃŒye layÄ±k gÃ¶rÃŒlen bir taÅtÄ±r.
+YeÅim taÅÄ± yaÅama kuvvetinin kaynaÄÄ± ve ruhu olan <i>wairua</i>'yÄ± tutmakta ve iÃ§ermektedir
+ve bu nedenle bÃ¶ylesine bir sanal  kÃŒtÃŒphane projesinin esin kaynaÄÄ± olmuÅtur.
+
+}
+
+_textaboutgreenstone_ [l=tr] {<p>Greenstone sanal kÃŒtÃŒphane koleksiyonlarÄ± oluÅturmak ve daÄÄ±tÄ±mÄ±nÄ± 
+geÃ§ekleÅtirmek iÃ§in hazÄ±rlanmÄ±Å bir yazÄ±lÄ±mdÄ±r. Greenstone, bilginin dÃŒzenlenmesi ve
+Internet veya CD-ROM ÃŒzerinden yayÄ±mlanmasÄ± konusunda yenÃŒ usÃŒller sunmaktadÄ±r.
+Greenstone yazÄ±lÄ±mÄ± <b>University of Waikato</b> tarafÄ±ndan  <b>New Zealand Digital Library Project</b> 
+<i>(Yeni Zelanda Sanal KÃŒtÃŒphanesi  Projesi)</i> kapsamÄ±nda ÃŒretilmiÅ ve 
+<b>UNESCO</b>, <b>Human Info NGO</b> kuruluÅlarÄ± tarafÄ±ndan geliÅtirilmiÅ ve daÄÄ±tÄ±mÄ± saÄlanmÄ±ÅtÄ±r.
+Bu yazÄ±lÄ±mÄ±n aÃ§Ä±k kod kaynaÄÄ±nÄ± <a href="http://greenstone.org">http://greenstone.org</a> adresinden
+"GNU General Public Licence" ilkelerine uymak koÅulu ile temin edebilirsiniz.
+
+<p>Bu yazÄ±lÄ±mÄ±n amacÄ±, kullanÄ±cÄ±larÄ±n, Ã¶zellikle ÃŒniversitelerin, kÃŒtÃŒphanelerin,
+ve diÄer kamu hizmeti gÃ¶ren kurum ve kuruluÅlarÄ±n kendi sanal kÃŒtÃŒphanelerini
+kurmalarÄ±nÄ± saÄlamaktÄ±r. Sanal kÃŒtÃŒphaneler, Ã¶zellikle geliÅmekte olan ÃŒlkelerin
+eÄitim, bilim ve kÃŒltÃŒrel alanda; UNESCO'nun ortaklaÅa hareket ettiÄi kuruluÅlar ve kurumlarda 
+bilginin yayÄ±lmasÄ± ve edinilmesi konusunda kÃ¶kten bir deÄiÅiklik yapmÄ±ÅtÄ±r.
+Bu yazÄ±lÄ±mÄ± oluÅturanlarÄ±n dileÄi bu ve buna benzer yazÄ±lÄ±mlar ile sanal kÃŒtÃŒphanelerin
+etkin bir biÃ§imde yayÄ±lmasÄ± ve bilginin yaygÄ±nlaÅmasÄ±nÄ±n saÄlanmasÄ±dÄ±r.
+
+
+<p>Bu yazÄ±lÄ±m AÄustos 2000 tarihinde uluslararasÄ± iÅbirliÄi Ã§erÃ§evesinde aÅaÄÄ±da adÄ± geÃ§en 3 ayrÄ± kurumun 
+gayretleri ile yazÄ±lmÄ±Å ve daÄÄ±tÄ±mÄ± gerÃ§ekleÅtirilmiÅtir.
+
+<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="_httpimg_/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="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: selcolgr
+# -- Missing translation: _httpiconselcolgr_
+# -- Missing translation: _widthselcolgr_
+# -- Missing translation: _heightselcolgr_
+# -- Missing translation: _altselcolgr_
+
+
+# -- Missing translation: cgli
+# -- Missing translation: _httpiconcgliof_
+# -- Missing translation: _httpiconcglion_
+# -- Missing translation: _widthcgli_
+
+# -- Missing translation: ccol
+# -- Missing translation: _httpiconccolof_
+# -- Missing translation: _httpiconccolon_
+# -- Missing translation: _widthccol_
+
+# -- Missing translation: ctrans
+# -- Missing translation: _httpiconctransof_
+# -- Missing translation: _httpiconctranson_
+# -- Missing translation: _widthctrans_
+
+# -- Missing translation: cadmin
+# -- Missing translation: _httpiconcadminof_
+# -- Missing translation: _httpiconcadminon_
+# -- Missing translation: _widthcadmin_
+
+# -- Missing translation: cabgs
+# -- Missing translation: _httpiconcabgsof_
+# -- Missing translation: _httpiconcabgson_
+# -- Missing translation: _widthcabgs_
+
+# -- Missing translation: cgsdoc
+# -- Missing translation: _httpiconcgsdocof_
+# -- Missing translation: _httpiconcgsdocon_
+# -- Missing translation: _widthcgsdoc_
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=tr] {Ana Sayfada 4 buton daha bulunmaktadÄ±r.}
+
+_textnocollections_ [l=tr] {<p>Åu anda Greenstone'un kurulumunda herhangi bir koleksiyon bulunmamaktadÄ±r.
+Yeni koleksiyonlar eklemek iÃ§in 
+<ul><li>Use <a href="_httppagecollector_">The Collector</a> butonuna basarak yeni koleksiyonlar oluÅturabilirasiniz.
+    <li>EÄer Greenstone elinizde CD-ROM'u varsa koleksiyonlrÄ± CD-ROM'dan ekleyebilirsiniz.
+</ul>
+}
+
+_text1coll_ [l=tr] {Bu Greenstone kurulumu 1 adet koleksiyon iÃ§ermektedir.}
+
+_textmorecolls_ [l=tr] {Bu Greenstone kurulumu _1_ adet koleksiyon iÃ§ermektedir.}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=tr] {DÄ±Å link (kÃ¶prÃŒ)}
+_textlinknotfound_ [l=tr] {Ä°Ã§ link bulunamadÄ±}
+
+_textextlinkcontent_ [l=tr] {SeÃ§tiÄiniz link Åu anda seÃ§miÅ olduÄunuz koleksiyonlarÄ±n dÄ±ÅÄ±ndadÄ±r.
+    EÄer hala bu linki gÃ¶rÃŒntÃŒlemek ve web tarayÄ±cÄ±nÄ±zÄ±n ilgili web sayfasÄ±na gitmesini istiyorsanÄ±z
+    <a href="_nexturl_">buraya tÄ±klayÄ±n</a> ; linki gÃ¶rÃŒntÃŒlemek istemiyorsanÄ±z
+     tarayÄ±cÄ±nÄ±zdaki "back" (geri) sekmesine tÄ±klayÄ±n ve Ã¶nceki belgeye ulaÅÄ±n.
+
+_textlinknotfoundcontent_ [l=tr] {Bizim kontrolumuzda olmayan bir nedenden dolayÄ± seÃ§tiÄiniz link 
+            bulunmamaktadÄ±r.Bunun nedeni kaynak koleksiyondaki bir hata olabilir.
+            LÃŒtfen tarayÄ±cÄ±nÄ±zdaki "back" (geri) sekmesine tÄ±klayÄ±n ve Ã¶nceki belgeye ulaÅÄ±n.
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=tr] {
+
+<h3>Link to "_2_" collection</h3>
+
+<p> SeÃ§tiÄiniz link "_collectionname_" kolesksiyonunun dÄ±ÅÄ±ndadÄ±r.
+("_2_" koleksiyonuna link baÄlantÄ± kurmaktadÄ±r.)
+EÄer "_2_" koleksiyonundaki linki gÃ¶rÃŒntÃŒlemek istiyorsanÄ±z
+<a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">bu sayfaya ilerleyin</a>
+Linki gÃ¶rÃŒntÃŒlemek istemiyorsanÄ±z  tarayÄ±cÄ±nÄ±zdaki "back" (geri) 
+sekmesine tÄ±klayÄ±n ve Ã¶nceki belgeye ulaÅÄ±n.
+}
+
+# -- Missing translation: _textlinknotfoundcontent_
+
+# should have arguments of collection, collectionname and link
+# -- Missing translation: _foundintcontent_
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=tr] {Greenstone Digital Library}
+
+_textusername_ [l=tr] {KullanÄ±cÄ± adÄ±}
+_textpassword_ [l=tr] {Åifre}
+
+_textmustbelongtogroup_ [l=tr] {Bu sayfaya ulaÅabilmek iÃ§in "_cgiargug_" grubuna kayÄ±tlÄ± olmanÄ±z gerekmektedir.}
+
+_textmessageinvalid_ [l=tr] {UlaÅmak istediÄiniz sayfa iÃ§i kullanÄ±cÄ± adÄ± ile kayÄ±t yapmanÄ±z gerekir.<br>
+_If_(_cgiargug_,[_textmustbelongtogroup_]<br>)
+LÃŒtfen  Greenstone kullanÄ±cÄ± adÄ± ve Åifrenizi giriniz.}
+
+_textmessagefailed_ [l=tr] {KullanÄ±cÄ± adÄ± ve/veya Åifreniz hatalÄ±}
+
+_textmessagedisabled_ [l=tr] {ÃzgÃŒnÃŒz, KullanÄ±m hakkÄ±nÄ±z kaldÄ±rÄ±lmÄ±Å. LÃŒtfen bu sitenin yÃ¶neticisine danÄ±ÅÄ±n.}
+
+_textmessagepermissiondenied_ [l=tr] {ÃzgÃŒnÃŒz, bu sayfaya giriÅ hakkÄ±nÄ±z yok.}
+
+_textmessagestalekey_ [l=tr] {Ä°zlediÄiniz link kullanÄ±mdan Åu anda Åifreli alanda. 
+LÃŒtfen kullanÄ±cÄ± adÄ± ve Åifrenizi giriniz.}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=tr] {<p> Bu Greenstone kurulumu hiÃ§bir belge iÃ§ermemektedir. Bunun nedeni 
+Åunlar olabilir:
+<ol>
+ <li>Greenstone CD-ROM'dan endÃŒÅÃŒk dÃŒzeyde kurulumla yÃŒklenmiÅtir.
+ <li>Greenstone Internet aracÄ±lÄ±Äi ile indirilmiÅtir.
+</ol>
+Her iki durumda da aÅaÄÄ±daki Ã§Ã¶zÃŒm yollarÄ±na baÅvurabilirsiniz.
+-Greenstone CD-ROM'u iÃ§indeki <i>docs</i> dizininden belgeleri elde 
+edebilirsiniz veya
+
+- <a href="http://www.greenstone.org">http://www.greenstone.org</a>
+sitesini ziyaret edebilirsiniz.
+}
+
+_textuserguide_ [l=tr] {KullanÄ±cÄ± Rehberi}
+_textinstallerguide_ [l=tr] {Kurulumcu Rehberi}
+_textdeveloperguide_ [l=tr] {GeliÅtirici Rehberi}
+_textpaperguide_ [l=tr] {Koleksiyona HazÄ±rlama Rehberi}
+# -- Missing translation: _textorganizerguide_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "greenstone documentation" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=tr] {_httpimg_/tr/gsdocsgr.gif}
+_widthgsdocsgr_ [l=tr] {_pagewidth_}
+_heightgsdocsgr_ [l=tr] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textdefaultstructure_
+_textmore_ [l=tr] {Daha}
+_textcollector_ [l=tr] {Koleksiyon AyarlarÄ±}
+_textinfo_ [l=tr] {Koleksiyon Bilgisi}
+_textsrce_ [l=tr] {Kaynak Veri}
+_textconf_ [l=tr] {Koleksiyon KonfigÃŒrasyonu}
+_textbild_ [l=tr] {YapÄ±landÄ±r}
+_textview_ [l=tr] {GÃ¶rÃŒntÃŒle}
+_textdel_ [l=tr] {Koleksiyon sil}
+_textexpt_ [l=tr] {Koleksiyonu dÄ±Åa ver}
+
+# -- Missing translation: _textdownloadingfiles_
+# -- Missing translation: _textimportingcollection_
+# -- Missing translation: _textbuildingcollection_
+# -- Missing translation: _textcreatingcollection_
+
+_textcollectorblurb_ [l=tr] {<i>Kalem KÄ±lÄ±Ã§tan Keskindir.
+<br>Bilgi KoleksiyonlarÄ±nÄ± yapÄ±landÄ±rma ve daÄÄ±tÄ±mÄ±nÄ± yapmaya baÅlamadan Ã¶nce 
+deÄinmek istediÄimiz bazÄ± konular var.
+
+Telif HaklarÄ± Konusunda bazÄ± yasal zorunluluklar bulunmaktadÄ±r:Bir belgeye ulaÅabilme, 
+bu belgeyi baÅkalarÄ±na verebilme hakkÄ±nÄ± size vermemektedir.BazÄ± sosyal zorunluluklar 
+vardÄ±r: koleksiyonlar belgelerin oluÅtuÄu toplumun geleneklerine saygÄ±lÄ± olmalÄ±dÄ±r.
+AyrÄ±ca ahlaki zorunluluklar vardÄ±r: BazÄ± bilgiler kolayca eriÅilebilecek yerlerde olmamalÄ±dÄ±r.
+<br>Bilginin gÃŒcÃŒne karÅÄ± duyarlÄ± olun ve onu bilgece kullanÄ±n.
+</i>
+}
+
+_textcb1_ [l=tr] {Koleksiyon ayarlarÄ± size yeni koleksiyon oluÅturmakta, varolan koleksiyonlarÄ± deÄiÅtirmek,
+silmek veya ekleme yapmakta yardÄ±mcÄ± olur. Bu iÅlemler iÃ§in gerekli bilgilere ulaÅmak amacÄ± 
+ile  bir dizi web sayfasÄ±ndan rehberlik hizmeti alacaksÄ±nÄ±z
+}
+
+_textcb2_ [l=tr] {Ãncelikle ne yapacaÄÄ±nÄ±za karar vermeniz gerekiyor}
+_textcnc_ [l=tr] {Yeni bir koleksiyon oluÅturmak }
+_textwec_ [l=tr] {Varolan bir koleksiyon ÃŒstÃŒnde Ã§alÄ±Åmak, veri ekleme veya silmek }
+
+_textcb3_ [l=tr] {Sanal kÃŒtÃŒphane koleksiyonlarÄ±nÄ± yapÄ±landÄ±rmak veya ÃŒzerinde deÄiÅiklik yapmak iÃ§in
+sisteme giriÅ yapmanÄ±z gerekmektedir. Bu, istenmeyen kiÅilerin bilgisayar 
+kayÄ±tlarÄ±na girerek istenmeyen deÄiÅiklikleri yapmasÄ±na engel olmak iÃ§in istenmektedir.
+
+Not: GÃŒvenlik iÃ§in 30 dakika iÃ§inde herhangi bir iÅlem yapmazsanÄ±z sistem ile baÄlantÄ±nÄ±z 
+kesilir. 
+}
+
+_textcb4_ [l=tr] {LÃŒtfen kullanÄ±cÄ± adÄ± ve Åifrenizi yazÄ±n ve giriÅ iÃ§in tÄ±klayÄ±n.
+}
+
+_textfsc_ [l=tr] {Ãncelikle Ã§alÄ±Åmak istediÄiniz koleksiyonu seÃ§iniz. Bu evrede salt 
+okunur koleksiyonlar listede gÃ¶zÃŒkmeyecektir.
+}
+
+_textwtc_ [l=tr] {SeÃ§tiÄiniz koleksiyonda}
+_textamd_ [l=tr] {daha fazla veri ekleyebilirsiniz ve koleksiyonu yeniden yapÄ±landÄ±rabilirsiniz.}
+_textetc_ [l=tr] {Koleksiyon konfigÃŒrasyon dosyasÄ± ÃŒzerinde deÄiÅiklik yapabilir ve koleksiyonu yeniden yapÄ±landÄ±rabilirsiniz.}
+_textdtc_ [l=tr] {BÃŒtÃŒn koleksiyonu silebilirsiniz.}
+_textetcfcd_ [l=tr] {Koleksiyonu yazma amaÃ§lÄ± olarak kendinden kurulumlu Windows CD-ROM'unda kullanÄ±lÄ±r hale getirebilirsiniz.}
+_textcaec_ [l=tr] {Varolan bir koleksiyon ÃŒstÃŒnde Ã§alÄ±Åmak, veri ekleme veya silmek}
+_textnwec_ [l=tr] {Yeni bir koleksiyon oluÅturmak amacÄ± ile }
+_textcianc_ [l=tr] {Yeni koleksiyon oluÅturma}
+_texttsosn_ [l=tr] {Yeni bir sanal kÃŒtÃŒphane oluÅturmak iÃ§in izlenmesi gereken adÄ±mlar dizisi ÅÃ¶yledir:}
+_textsin_ [l=tr] {AdÄ±nÄ± (ve baÄlÄ± bilgileri) belirt }
+_textswts_ [l=tr] {Verinin yerini belirle}
+_textatco_ [l=tr] {KonfigÃŒrasyon tercihlerini ayarla (YalnÄ±zca deneyimli kullanÄ±cÄ±lar iÃ§in)}
+_textbtc_ [l=tr] {Koleksiyonu "yapÄ±landÄ±r" (aÅaÄÄ±da aÃ§Ä±klanmaktadÄ±r)}
+_textpvyh_ [l=tr] {HazÄ±rladÄ±ÄÄ±nÄ±z koleksiyonu gÃ¶rebilirsiniz.}
+
+_texttfsiw_ [l=tr] {DÃ¶rdÃŒncÃŒ adÄ±mdaki iÅlerin tamamÄ±nÄ± bilgisayar yapar. "YapÄ±landÄ±rma prosesisinde
+bilgisayar bÃŒtÃŒn indeksleri yapar ve gerekli diÄer bilgileri de bulunduÄu 
+yerlerden alÄ±p biraraya getirir. Ancak Ã¶ncelikle bilgiyi belirtmeniz gerekmektedir.
+}
+
+_textadab_ [l=tr] {Altta sizin nerede olduÄunuzu gÃ¶steren bir diyagram belirecektir.
+YeÅil dÃŒÄmeye basarak siz iÅlemler dizisine devam edebilirsiniz.
+Ä°Ålem dizisi boyunca dÃŒÄmeler sarÄ±ya dÃŒnÃŒÅecektir. Ãnceki sayfalardan birine 
+dÃ¶nmek iÃ§in diyagramda ilgili sarÄ± dÃŒÄmeye basmanÄ±z gerekmektedir.
+}
+
+_textwyar_ [l=tr] {EÄer hazÄ±rsanÄ±z, "koleksiyon bilgisi" yazÄ±lÄ± yeÅil dÃŒÄmeye basÄ±n ve 
+yeni sanal kÃŒtÃŒphane koleksiyonunu yaratmaya baÅlayÄ±n.
+}
+
+_textcnmbs_ [l=tr] {Koleksiyon adÄ± belirtilmeli.}
+_texteambs_ [l=tr] {E-posta adresi belirtilmeli.}
+_textpsea_ [l=tr] {LÃŒtfen e-posta adresini kullaniciadi@alan biÃ§iminde belirtin.}
+_textdocmbs_ [l=tr] {Koleksiyonun betimlemesi belirtilmeli}
+
+_textwcanc_ [l=tr] {Yeni bir koleksiyon oluÅtuturken kaynak veri hakkÄ±nda bazÄ± bilgileri 
+girmeniz gerekmektedir. Bu iÅlemler bir  web sayfasÄ± dizisi halinde 
+yapÄ±landÄ±rÄ±lmÄ±ÅtÄ±r.  SayfanÄ±n altÄ±ndaki Ã§ubuk sizin bitirmeniz gereken 
+iÅlemler dizisinde hangi sayfada olduÄunuzu gÃ¶sterir.
+}
+
+_texttfc_ [l=tr] {Koleksiyonun baÅlÄ±ÄÄ±:}
+
+_texttctiasp_ [l=tr] {Koleksiyon baÅlÄ±ÄÄ± kÄ±sa bir sÃ¶zcÃŒk Ã¶beÄinden ibarettir ve sanal kÃŒtÃŒphane 
+tarafÄ±ndan koleksiyonun iÃ§eriÄini belirtmek amacÄ± ile kullanÄ±lÄ±r. BazÄ± Ã¶rnek 
+koleksiyon baÅlÄ±klarÄ±nÄ± sunarsak: "Bilgisayar Bilimleri Teknik raporlarÄ±" ve
+"SayÄ±sal Analiz YÃ¶ntemleri"
+}
+
+_textcea_ [l=tr] {BaÄlantÄ± iÃ§in e-posta adresi:}
+
+_textteas_ [l=tr] {Bu e-posta adresi koleksiyon hakkÄ±nda ilk baÄlantÄ± kurulacak kiÅiyi belirtir.
+EÄer Greenstone yazÄ±lÄ±mÄ± bir problem ortaya Ã§Ä±karÄ±rsa, bulgulara ait bir rapor 
+bu adrese gÃ¶nderilir.
+}
+
+_textatc_ [l=tr] {Bu koleksiyon hakkÄ±nda:}
+
+_texttiasd_ [l=tr] {Bu bir  koleksiyon iÃ§inde olanlarÄ± yÃ¶neten ilkeleri tanÄ±mlayan ifadedir.
+Koleksiyon sunulduÄunda ilk sayfada bu ilkeler gÃ¶rÃŒntÃŒlenir.
+}
+
+_textypits_ [l=tr] {Sizin iÅlem dizisi iÃ§indeki durumunuz "koleksiyon bilgisi" aÅamasÄ±nda 
+bir ok ile belirtilmektedir. Ä°Ålemi sÃŒrdÃŒrmek Ã§in yeÅil "kaynak veri"
+dÃŒÄmesine basÄ±n.
+}
+
+_srcebadsources_ [l=tr] {<p>BelirttiÄiniz giriÅ kaynaklarÄ±nda biri veya diÄerine ulaÅÄ±lamÄ±yor 
+(altta _iconcross_ belirtilmiÅtir).
+
+<p>Bunun sebebi Åu olabilir:
+<ul>
+<li>Dosya, FTP sitesi veya URL yoktur.
+<li>Ãncelikle sizin Internet Srvis SaÄlayÄ±cÄ±nÄ±za baÄlanmanÄ±z gerekmektedir.
+<li>Bir gÃŒvenli duvarÄ± (firewall) arkasÄ±nda bulunan bir URL'ye baÄlanmaya
+Ã§alÄ±ÅÄ±yorsunuz. (bu aslÄ±ndan eÄerinternette bie kullanÄ±cÄ± adÄ± ve Åifre ile
+giriÅ yapÄ±yorsanÄ±z normal bir durumdur).
+</ul>
+
+<p>EÄer URL'yi TarayÄ±cÄ±nÄ±zda gÃ¶rebiliyorsanÄ±z, bu sayfa kaÅelenmiÅ bir 
+kopyadan gelmiÅ olabilir. Ne yazÄ±k ki yerel diskinizde kaÅelenmiÅ kopya sayfalar
+yazÄ±lÄ±mÄ±n aynalama prosesinde gÃ¶rÃŒnmemektedir.  Bu gibi durumlarda size
+ilgili sayfanÄ±n bir tarayÄ±cÄ± tarafÄ±ndan  indirilmesini Ã¶neriyoruz.
+}
+
+_textymbyco_ [l=tr] {<p>Koleksiyonunuzu aÅaÄÄ±daki seÃ§eneklere dayandÄ±rabilirsiniz:
+<ul>
+<li>VarsayÄ±lan yapÄ±
+<dl><dd>Yeni koleksiyonlar aÅaÄÄ±daki dosya tÃŒrlerini iÃ§erebilir:
+ html belgeler (.htm, .html), dÃŒz metin belgeler
+(.txt, .text), MS Word belgeleri (.doc), PDF belgeler (.pdf) veya
+"m-box" formatlÄ± e-posta belgeleri (.mbx).</dd></dl>
+<li>Varolan bir koleksiyon
+<dl><dd>Yeni koleksiyonunuzdaki dosyalar kesinlikle oluÅturmak iÃ§in kullanÄ±lan koleksiyondaki dosya tÃŒrleri
+ile aynÄ± tÃŒrde olmalÄ±dÄ±r.</dd></dl>
+</ul>
+}
+
+_textbtco_ [l=tr] {Koleksiyonu aÅaÄÄ±daki sisteme dayandÄ±rÄ±n:}
+_textand_ [l=tr] {Yeni veri ekleyin}
+_textad_ [l=tr] {Veri ekleme:}
+
+_texttftysb_ [l=tr] {AÅaÄÄ±da belirttiÄiniz seÃ§ilmiÅ dosyalar koleksiyona eklenecektir.
+Koleksiyonda halihazÄ±rda bulunan dosyalarÄ± yeniden belirtmediÄinize emin olun:
+Aksi takdirde iki kopya eklenmiÅ olacaktÄ±r. Dosyalar; tam dosya yollarÄ±,
+web adreslerini gÃ¶steren web sayfalarÄ± ile belirtilebilir.
+}
+
+_textis_ [l=tr] {GiriÅ KaynaklarÄ±:}
+
+_textddd1_ [l=tr] {<p>EÄer bir dosyayÄ± belirtmek iÃ§in  file:// veya ftp:// kullanÄ±yorsanÄ±z bu dosya indirilecektir.
+
+<p>EÄer http:// sistemini kullanÄ±yorsanÄ±z kullandÄ±ÄÄ±nÄ±z URL'ye gÃ¶re ya 
+tarayÄ±cÄ±nÄ±zda bir web sayfasÄ± gÃ¶zÃŒkecektir ya da dosyalarÄ±n listesi
+belirecektir. 
+
+<p> EÄer bir dizini veya klasÃ¶rÃŒ belirtmek iÃ§in file:// veya ftp:// yÃ¶ntemini
+kullanÄ±yorsanÄ±z veya http:// URL usulÃŒnÃŒ kullanÄ±yorsanÄ±z bu yÃ¶ntemler sizi bir
+dosyalar listesine yÃ¶neltecektir. Bu listedeki klasÃ¶r ve altondaki klasÃ¶rler
+koleksiyondaki herÅeyi iÃ§erecektir.
+
+<p>"Daha fazla giriÅ kutusu elde etmek iÃ§in "Daha Ã§ok Kaynak" dÃŒÄmesine basÄ±n.
+}
+
+_textddd2_ [l=tr] {<p> YeÅil dÃŒÄmelerden birine basÄ±n. Deneyimli bir kullanÄ±cÄ± iseniz koleksiyonun
+konfigÃŒrasyon ayarlarÄ±nÄ± deÄiÅtirebilirsiniz. Ya da doÄrudan yapÄ±landÄ±rma evresine 
+geÃ§ebilirsiniz. Bir daha hatÄ±rlatalÄ±m, daha Ã¶nceki bir evreyi sarÄ± dÃŒÄmelere basarak 
+ulaÅabilirsiniz.
+}
+
+_textconf1_ [l=tr] {<p>Koleksiyonununuzun yapÄ±sÄ± ve sunum biÃ§imi Ã¶zel bir "konfigÃŒrasyon dosyasÄ±" 
+iÃ§inde belirtilen spesifikasyonlarla kontrol edilmektedir. Deneyimli kullanÄ±cÄ±lar bu
+konfigÃŒrasyon ayarlarÄ±nÄ± deÄiÅtirebilirler.
+
+<center><p><b> EÄer deneyimli bir kullanÄ±cÄ± deÄilseniz  doÄrudan sayfa sonuna gidin.
+</b></center> 
+
+<p>
+KonfigÃŒrasyon ayarlarÄ±nÄ± deÄiÅtirmek iÃ§in, aÅaÄÄ±da beliren veri ÃŒzerinde deÄiÅiklik yapÄ±n.
+EÄer bir hata yaparsanÄ±z "SÄ±fÄ±rla" tuÅuna basarak Ã¶zgÃŒn konfigÃŒrasyon ayarlarÄ±na dÃ¶nebilirsiniz.
+}
+
+_textreset_ [l=tr] {SÄ±fÄ±rla}
+
+_textbild1_ [l=tr] {Koleksiyon Åu anda yapÄ±landÄ±rÄ±lÄ±yor: Bu iÅlem bir sÃŒre devam edecek.
+YapÄ±landÄ±rma durumu Ã§izgisi size iÅlemin durumu hakkÄ±nda bilgi verecektir.
+}
+
+_textbild2_ [l=tr] {YapÄ±landÄ±rma iÅlemini herhangi bir anda durdurmak iÃ§in buraya basÄ±n.
+<br>ÃalÄ±ÅtÄ±ÄÄ±nÄ±z koleksiyon bir bÃŒtÃŒn halinde duracaktÄ±r.
+}
+
+_textstopbuild_ [l=tr] {YapÄ±landÄ±rmayÄ± durdur.}
+
+_textbild3_ [l=tr] {EÄer bu sayfayÄ± "yapÄ±landÄ±rmayÄ± durdur" dÃŒÄmesine basÄ±p da iptal iÅlemini
+yapmadan  terkederseniz, koleksiyon yapÄ±lanmaya devam edecek ve baÅarÄ±lÄ± 
+bir biÃ§imde kurulum tamamlanana kadar iÅlem sÃŒrecektir.
+}
+
+_textbuildcancelled_ [l=tr] {YapÄ±lanma iptal edildi.}
+
+_textbildcancel1_ [l=tr] {Koleksiyon yapÄ±landÄ±rma iÅlemi iptal edildi. YApÄ±landÄ±rma iÅlemine yeniden 
+baÅlamak ya da iÅlemde deÄiÅiklikler yapmak iÃ§in aÅaÄÄ±daki sarÄ± dÃŒÄmeleri 
+kullananÄ±n.
+}
+
+_textbsupdate1_ [l=tr] {YapÄ±landÄ±rma durumu 1 saniyede gÃŒncellenir}
+_textbsupdate2_ [l=tr] {YapÄ±landÄ±rma durumu gÃŒncellemesi}
+_textseconds_ [l=tr] {saniyede}
+_textbildsuc_ [l=tr] {Koleksiyon baÅarÄ±lÄ± bir biÃ§imde yapÄ±landÄ±rÄ±ldÄ±}
+
+_textviewbildsummary_ [l=tr] {Koleksiyon hakkÄ±nda yapÄ±landÄ±rma Ã¶zeti bilgisini daha ayrÄ±ntÄ±lÄ± olarak elde edebilirsiniz. 
+<a href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>. </a> 
+}
+
+_textfailmsg11_ [l=tr] {Koleksiyon, hiÃ§ veri iÃ§ermediÄinden dolayÄ± yapÄ±landÄ±rÄ±lamadÄ±. En azÄ±ndan bir 
+dizin veya dosyanÄ±n belirttiÄiniz "<i>kaynak veri <\i> sayfasÄ±nÄ±n iÃ§inde varolduÄuna ve
+ilgili dosya tÃŒrlerinin Greenstone'un iÅleyebileceÄi tÃŒrden olduÄuna emin olun.
+}
+
+_textfailmsg21_ [l=tr] {Koleksiyon yapÄ±landÄ±rÄ±lamadÄ± (import.pl hatasÄ±).}
+_textblcont_ [l=tr] {YapÄ±landÄ±rma seyri aÅaÄÄ±daki bilgiyi iÃ§ermektedir:}
+
+_texttryagain_ [l=tr] {LÃŒtfen <a href="_httppagecollector_" target=_top> koleksiyon ayarlarÄ±nÄ± yeniden Ã§alÄ±ÅtÄ±rÄ±n</a>
+ve yeniden deneyin.
+}
+
+_textfailmsg31_ [l=tr] {Koleksiyon yapÄ±landÄ±rÄ±lamadÄ±(buildcol.pl failed).}
+_textfailmsg41_ [l=tr] {Koleksiyon baÅarÄ± ile yapÄ±landÄ±rÄ±ldÄ± ancak kurulum gerÃ§ekleÅtirilemedi.}
+_textfailmsg71_ [l=tr] {Koleksiyonunuzun yapÄ±landÄ±rÄ±lmasÄ± sÄ±rasÄ±nda beklenmeyen bir hata oluÅtu.}
+_textretcoll_ [l=tr] {Koleksiyon ayarlarÄ±na geri dÃ¶n}
+
+_textdelperm_ [l=tr] {_cgiargbc1dirname_ koleksiyonunun tamamÄ± veya bir kÄ±smÄ± silinemedi. 
+OlasÄ± sebepleri aÅaÄÄ±dadÄ±r:
+<ul>
+<li> Greenstone'un  _gsdlhome_/collect/_cgiargbc1dirname_ directory<br> dizinini silmeye izni yok.
+Bilgisayardan _cgiargbc1dirname_ koleksiyonunu kaldÄ±rmak iÃ§in bu dizini program dÄ±ÅÄ±ndan "manuel"
+silmeniz gerekiyor.
+</ul>
+}
+
+_textdelinv_ [l=tr] {_cgiargbc1dirname_ koleksiyonu korunmalÄ± ya da geÃ§ersiz. Silme iÅlemi iptal edildi.
+}
+
+_textdelsuc_ [l=tr] {_cgiargbc1dirname_ koleksiyonu baÅarÄ± ile silindi.}
+
+_textclonefail_ [l=tr] {_cgiargclonecol_ koleksiyonu klonlanamadÄ±. OlasÄ± sebepler ÅunlardÄ±r:
+<ul>
+<li>  _cgiargclonecol_ koleksiyonu yok.
+<li> _cgiargclonecol_ koleksiyonu collect.cfg konfigÃŒrasyon dosyasÄ±na sahip deÄil.
+}
+
+_textcolerr_ [l=tr] {Koleksiyon ayarlarÄ± hatasÄ±.}
+
+_texttmpfail_ [l=tr] {Koleksiyoncu bir geÃ§ici dosyadan veya dizinden okuma veya dosyaya /dizine  
+yazma iÅleminde hata verdi. OlasÄ± hatalar ÅunlardÄ±r:
+<ul>
+<li> Greenstone _gsdlhome_/tmp dizinine okuma / yazma eriÅim hakkÄ±na sahip deÄil.
+</ul>
+}
+
+_textmkcolfail_ [l=tr] {Koleksiyoncu yeni koleksiyonun gerektirdiÄi dizin yapÄ±sÄ±nÄ± oluÅtururken
+hata verdi (mkcol.pl failed). OlasÄ± nedenleri ÅunlardÄ±r:
+<ul>
+<li> Greenstone _gsdlhome_/tmp dizinine yazma hakkÄ±na sahip deÄildir.
+<li> mkcol.pl perl skript hatasÄ±.
+</ul>
+}
+
+_textnocontent_ [l=tr] {Koleksiyoncu hatasÄ±: YEni koleksiyon iÃ§in bir isim belirlenmedi. Koleksiyoncuyu 
+yeniden Ã§alÄ±ÅtÄ±rÄ±n.
+}
+
+_textrestart_ [l=tr] {Koleksiyoncuyu yeniden Ã§alÄ±ÅtÄ±r.}
+
+_textreloaderror_ [l=tr] {Yeni koleksiyonu oluÅtururken bir hata oluÅtu. Bunun nedeni Green Stone'un
+sizin tarayÄ±cÄ±nÄ±zda "Reload : Yeniden YÃŒkle" veya "back : Geri" tuÅlarÄ±na 
+basmanÄ±z olabilir. LÃŒtfen, koleksiyoncu tarafÄ±ndan bir koleksiyon oluÅturulurken 
+bu dÃŒÄmelere basmaktan kaÃ§Ä±nÄ±n. Koleksiyoncuyu yeniden baÅlatmanÄ±zÄ± Ã¶neririz.
+}
+
+_textexptsuc_ [l=tr] {_cgiargbc1dirname_ koleksiyonu baÅarÄ±lÄ± bir biÃ§imde 
+_gsdlhome_/tmp/exported\__cgiargbc1dirname_  dizinine  ihraÃ§ edildi.
+}
+
+_textexptfail_ [l=tr] {<p> _cgiargbc1dirname_ koleksiyonunu ihraÃ§ ederken hata oluÅtu.
+
+<p> Bunun nedeni Greenstone'un "koleksiyon ihracÄ±" iÅlevini destekleyen 
+bileÅenleri iÃ§ermeden kurulumu olabilir.
+<ul>
+
+ <li>
+EÄer Greenstone'u CD-ROM'dan kurduysanÄ±z, bu bileÅenler eÄer siz 
+"Custom" kurulumu evresinde seÃ§mediyseniz yÃŒklenmeyecektir.
+Ä°lgili bileÅenleri  kurulumunuza eklemelek iÃ§in kurulum prosedÃŒrÃŒnÃŒ 
+yeniden Ã§alÄ±ÅtÄ±rabilirsiniz.
+
+ <li>
+EÄer Greenstone'u bir eweb daÄÄ±tÄ±cÄ±sÄ±ndan kurduysanÄ±z, bu iÅlevi etkin kÄ±lacak
+bir ek paketi indirmeniz ve kutmanÄ±z gerekmektedir. LÃŒtfen;
+<a href="http://www.greenstone.org">http://www.greenstone.org</a>  adresini 
+ziyaret edin veya <a href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+adresine daha ayrÄ±ntÄ±lÄ± bilgi  almak iÃ§in e-posta ile baÄlantÄ± kurun.
+</ul>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# -- Missing translation: h_colect
+# -- Missing translation: _httpiconhcolect_
+
+# -- Missing translation: info
+# -- Missing translation: _httpicongcinfoof_
+# -- Missing translation: _httpicongcinfoon_
+# -- Missing translation: _httpiconycinfoof_
+# -- Missing translation: _httpiconycinfoon_
+# -- Missing translation: _httpiconncinfoof_
+
+# -- Missing translation: srce
+# -- Missing translation: _httpicongcsrceof_
+# -- Missing translation: _httpicongcsrceon_
+# -- Missing translation: _httpiconycsrceof_
+# -- Missing translation: _httpiconycsrceon_
+# -- Missing translation: _httpiconncsrceof_
+
+# -- Missing translation: conf
+# -- Missing translation: _httpicongcconfof_
+# -- Missing translation: _httpicongcconfon_
+# -- Missing translation: _httpiconycconfof_
+# -- Missing translation: _httpiconycconfon_
+# -- Missing translation: _httpiconncconfof_
+
+# -- Missing translation: bild
+# -- Missing translation: _httpicongcbildof_
+# -- Missing translation: _httpicongcbildon_
+# -- Missing translation: _httpiconycbildof_
+# -- Missing translation: _httpiconycbildon_
+# -- Missing translation: _httpiconncbildof_
+
+# -- Missing translation: view
+# -- Missing translation: _httpicongcviewof_
+# -- Missing translation: _httpicongcviewon_
+# -- Missing translation: _httpiconycviewof_
+# -- Missing translation: _httpiconycviewon_
+# -- Missing translation: _httpiconncviewof_
+
+# -- Missing translation: del
+# -- Missing translation: _httpicongcdelof_
+# -- Missing translation: _httpicongcdelon_
+
+# -- Missing translation: expt
+# -- Missing translation: _httpicongcexptof_
+# -- Missing translation: _httpicongcexpton_
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=tr] {Greenstone sanal kÃŒtÃŒphane koleksiyonlarÄ±nÄ± sunan ve yeni koleksiyonlarÄ± 
+yapÄ±landÄ±rabilen bir yazÄ±lÄ±m takÄ±mÄ±dÄ±r. Bu yazÄ±lÄ±m, Internet ÃŒzerinden veya
+CD-ROM aracÄ±lÄ±ÄÄ± ile bilginin dÃŒzenlenmesi ve yayÄ±nlanmasÄ± konusunda yeni bir
+yol aÃ§maktadÄ±r. Greenstone "Yeni Zelanda Sanal KÃŒtÃŒphane Projesi" kapsamÄ±nda
+Waikato Ãniversitesi'nde geliÅtirilmiÅ, UNESCO ve "Human Info" STK iÅbirliÄi ile 
+daÄÄ±tÄ±mÄ± gerÃ§ekleÅtirilmiÅtir. Greenstone aÃ§Ä±k kaynak kodlu bir yazÄ±lÄ±mdÄ±r,
+kod <i>http://greenstone.org</i> adresinden GNU "General Public License" 
+ilkelerine uygun bir biÃ§imde temin edilebilir.
+
+}
+
+_textgreenstone2_ [l=tr] {Yeni Zelanda Sanal KÃŒtÃŒphanesi web sitesi (<a href="http://nzdl.org">http://nzdl.org</a>) 
+Greenstone tarafÄ±ndan oluÅturulmuÅ ve sizin dikkatli incelemenize olanak 
+saÄlayan bir Ã§ok Ã¶rnek koleksiyon iÃ§ermektedir. Bu koleksiyonlar bir Ã§ok
+arama ve tarama seÃ§eneklerini ArapÃ§a, FransÄ±zca, Maori dilinde ve Ä°spanyolca olarak 
+Ã¶rneklerle gÃ¶stermektedir. AyrÄ±ca bazÄ± mÃŒzik koleksiyonlarÄ± da vardÄ±r.
+
+}
+
+# -- Missing translation: _textplatformtitle_
+_textgreenstone3_ [l=tr] {Greenstone Windows ve Unix ÃŒzerinde Ã§alÄ±Åabilir. Elinizdeki daÄÄ±tÄ±m, Windows ve Linux'un 
+bÃŒtÃŒn versiyonlarÄ± iÃ§in kullanÄ±ma hazÄ±r ikili kodlar iÃ§ermektedir. AyrÄ±ca bu daÄÄ±tÄ±m,
+sistemin Microsoft C++ veya gcc ile derlenebilen kaynak kod'un tamamÄ±nÄ± iÃ§ermektedir.
+Greenstone aynÄ± zamanda ÃŒcretsiz olarak edinilebilen Apache Webserver ve PERL ile 
+birlikte Ã§alÄ±Åabilmektedir. KullanÄ±cÄ± arayÃŒzÃŒ Netscape Navigator veya Internet 
+Explorer gibi web tarayÄ±cÄ±lar  kullanÄ±r.
+
+}
+
+_textgreenstone4_ [l=tr] {BirÃ§ok belge koleksiyonu CD-ROM'un ÃŒzerinde daÄÄ±tÄ±lmaktadÄ±r. ÃrneÄin
+<i>Humanity Development Library</i> koleksiyonu muhasebeden su saÄlÄ±ÄÄ± korumaya
+1230 yayÄ±nÄ± iÃ§ermektedir. Bu koleksiyon geliÅmekte olan ÃŒlkelerde rastlanabilen
+minimum konfigÃŒrasyonlu bilgisayarlarda rahatlÄ±kla Ã§alÄ±Åabilir. Koleksiyonun 
+iÃ§indeki bilgilere konuya gÃ¶re arama, tarama, baÅlÄ±klara gÃ¶re tarama,
+Ã¶rgÃŒtlenmeye gÃ¶re arama, nasÄ±l yapÄ±lÄ±rlar listesini tarama, ve rastgele 
+kitap kapaklarÄ±nÄ± gÃ¶zden geÃ§irme yÃ¶ntemleri ile ulaÅÄ±labilir.
+
+}
+
+# -- Missing translation: _textcustomisationtitle_
+_textgreenstone5_ [l=tr] {Greenstone esnek ve kiÅiye Ã¶zel dÃŒzenlenebilir biÃ§imde tasarlanmÄ±ÅtÄ±r.
+Yeni belge ve metadata formatlarÄ± yazÄ±lan "plugin"lerle (Perl dilinde) 
+barÄ±ndÄ±rÄ±labilir. AynÄ± Åekilde yeni metadata tarama yapÄ±larÄ± sÄ±nÄ±flandÄ±rÄ±cÄ±" 
+yazÄ±larak geliÅtirilebilir. KullanÄ±cÄ± arayÃŒzÃŒnÃŒnÃŒn genel gÃ¶rÃŒnÃŒmÃŒ ise basitÃ§e
+macro dilinde yazÄ±lan makrolarla deÄiÅtirilebilir. Corba protokolÃŒ Java tÃŒrÃŒ 
+aracÄ± programlar ile  belge koleksiyonuna yÃ¶nelik imkanlarÄ±n taamÄ±nÄ±n kullanÄ±lmasÄ±na
+imkan saÄlar.
+
+}
+
+# -- Missing translation: _textdocumentationtitle_
+# -- Missing translation: _textdocuments_
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+# -- Missing translation: _textmailinglisttitle_
+_textmailinglist_ [l=tr] {Greenstone Sanal KÃŒtÃŒphanesi YazÄ±lmÄ± hakkÄ±nda gÃ¶rÃŒÅme amaÃ§lÄ± bir  
+e-posta listesi kurulmuÅtur. Greenstone'un etkin kullanÄ±cÄ±larÄ±nÄ±n 
+bu listeye ÃŒye olmasÄ± ve gÃ¶rÃŒÅmelere katÄ±masÄ± tavsiye olunur.
+<a href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>.
+Listeye bir ileti gÃ¶ndermek iÃ§in <a
+href="mailto:greenstone-users@list.scms.waikato.ac.nz"
+>greenstone-users@list.scms.waikato.ac.nz</a> adresini kullanÄ±n.
+
+}
+
+# -- Missing translation: _textbugstitle_
+_textreport_ [l=tr] {Biz, bu yazÄ±lÄ±mÄ±n sizin iÃ§in dÃŒzgÃŒn Ã§alÄ±ÅtÄ±ÄÄ±na emin olmak istiyoruz.
+LÃŒtfen her tÃŒrlÃŒ yazÄ±lÄ±m hatasÄ±nÄ± <a href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a>
+adresinden bize bildirin.
+
+}
+
+# -- Missing translation: _textgs3title_
+# -- Missing translation: _textgs3_
+
+# -- Missing translation: _textcreditstitle_
+
+_textwhoswho_ [l=tr] {Greenstone yazÄ±lÄ±mÄ± bir Ã§ok insanÄ±n iÅbirliÄini gerektiren bir Ã§alÄ±Åma 
+ile ortaya Ã§Ä±kmÄ±ÅtÄ±r. Rodger McNab ve Stefan Boddie bu projenin Ã¶ncÃŒl 
+mimarlarÄ± ve uygulamacÄ±larÄ±dÄ±r. David Bainbridge, George Buchanan, Hong Chen, 
+Elke Duncker, Carl Gutwin, Geoff Holmes, John McPherson, Craig Nevill-Manning, 
+Gordon Paynter, Bernhard Pfahringer, Todd Reed, Bill Rogers, ve  Stuart Yeates
+katkÄ±larÄ±nÄ± unutmamak gerekir. Yeni Zelanda Sanal KÃŒtÃŒphane Projesinin  diÄer 
+ÃŒyeleri de tavsiyeleri ve ilhamlarÄ± ile sistem tasarÄ±mÄ±nÄ± gerÃ§ekleÅmesinde
+Ã¶nemli katkÄ±da bulunmuÅtur. Bu kiÅiler:Mark Apperley, Sally Jo Cunningham, 
+Steve Jones, Te Taka Keegan, Michel Loots, Malika Mahoui and Lloyd Smith.
+AyrÄ±ca GNU lisanslÄ± paketlerin daÄÄ±Ä±mÄ±nda yardÄ±mlarÄ±nÄ± esirgemeyen
+MG, GDBM, PDFTOHTML, WGET, WVWARE and XLHTML kuruluÅlarÄ±na da ÅÃŒkranlarÄ±mÄ±zÄ±
+sunarÄ±z.
+
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "about the greenstone software" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=tr] {_httpimg_/tr/abgsgr.gif}
+_widthabgsgr_ [l=tr] {_pagewidth_}
+_heightabgsgr_ [l=tr] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=tr] {Åu andaki kullanÄ±cÄ±larÄ±n listesi}
+_textuser_ [l=tr] {kullanÄ±cÄ±}
+_textas_ [l=tr] {hesap durumu}
+_textgroups_ [l=tr] {gruplar}
+_textcomment_ [l=tr] {comment}
+_textadduser_ [l=tr] {yeni bir kullanÄ±cÄ± ekle}
+_textedituser_ [l=tr] {deÄiÅtir}
+_textdeleteuser_ [l=tr] {sil}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=tr] {KullanÄ±cÄ± bilgisini deÄiÅtirin}
+_textadduser_ [l=tr] {Yeni bir kullanÄ±cÄ± ekleyin}
+
+_textaboutusername_ [l=tr] {KullanÄ±cÄ± adlarÄ± 2 ila 30 karakter arasÄ±nda uzunluÄa sahip olabilir.
+Bu adlar alfanÃŒmerik karakterler ile '.2 ve '_' karakterlerini iÃ§erebilir
+
+}
+
+_textaboutpassword_ [l=tr] {Åifreler 3 ila 8 karakter arasÄ±nda uzunluÄa sahip olabilir.
+Åifre iÃ§inde Ã§Ä±ktÄ±sÄ± alÄ±nabilir ASCII karakterleri kullanÄ±labilir.
+}
+
+_textoldpass_ [l=tr] {EÄer bu alan boÅ bÄ±rakÄ±lÄ±rsa eski Åifre tutulacaktÄ±r.}
+_textenabled_ [l=tr] {aktif}
+_textdisabled_ [l=tr] {kapalÄ±}
+
+_textaboutgroups_ [l=tr] {Gruplar virgÃŒlle ayrÄ±lmÄ±Å listedir, virgÃŒlden sonra boÅluk koymayÄ±n.
+
+}
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textdeleteuser_
+# -- Missing translation: _textremwarn_
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=tr] {Åifreyi deÄiÅtirin}
+_textoldpw_ [l=tr] {eski Åifre}
+_textnewpw_ [l=tr] {yeni Åifre}
+_textretype_ [l=tr] {yeni Åifreyi yeniden girin}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textsuccess_
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=tr] {KullanÄ±cÄ± adÄ± geÃ§ersiz.}
+_textinvalidpassword_ [l=tr] {Åifre geÃ§ersiz.}
+_textemptypassword_ [l=tr] {Bu kullanÄ±cÄ± iÃ§in bir baÅlangÄ±Ã§ Åifresi girin.}
+_textuserexists_ [l=tr] {Bu kullanÄ±cÄ± adÄ± halihazÄ±rda var, lÃŒtfen yeni bir kullanÄ±cÄ± adÄ± girin.}
+
+_textusernameempty_ [l=tr] {LÃŒtfen kullanÄ±cÄ± adÄ±nÄ±zÄ± girin.}
+_textpasswordempty_ [l=tr] {Eski Åifrenizi girmeniz gerekiyor.}
+_textnewpass1empty_ [l=tr] {Yeni Åifrenizi girin ve yeniden yazÄ±n.}
+_textnewpassmismatch_ [l=tr] {YazdÄ±ÄÄ±nÄ±z yeni Åifrelerin iki versiyonu birbirinden uyumsuz.}
+_textnewinvalidpassword_ [l=tr] {GeÃ§ersiz bir Åifre girdiniz.}
+_textfailed_ [l=tr] {KUllanÄ±cÄ± adÄ±nÄ±z veya Åifreniz geÃ§ersiz.}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=tr] {Greenstone SÃŒrÃŒm NumarasÄ±}
+_textframebrowser_ [l=tr] {Bu sistemi gÃ¶rÃŒntÃŒlemek iÃ§in "frame enabled" tarayÄ±cÄ±nÄ±z olmasÄ± gerekir.}
+_textusermanage_ [l=tr] {KullanÄ±cÄ± YÃ¶netimi}
+_textlistusers_ [l=tr] {kullanÄ±cÄ±larÄ± listele}
+_textaddusers_ [l=tr] {yeni bir kullanÄ±cÄ± ekle}
+_textchangepasswd_ [l=tr] {Åifre deÄiÅtir}
+_textinfo_ [l=tr] {Teknik Bilgi}
+_textgeneral_ [l=tr] {genel}
+_textarguments_ [l=tr] {argÃŒmanlar}
+_textactions_ [l=tr] {eylemler}
+_textbrowsers_ [l=tr] {tarayÄ±cÄ±lar}
+_textprotocols_ [l=tr] {protokoller}
+_textconfigfiles_ [l=tr] {KonfigÃŒrasyon dosyalarÄ±}
+_textlogs_ [l=tr] {Seyirler}
+_textusagelog_ [l=tr] {kullanÄ±m raporlarÄ±}
+# -- Missing translation: _textinitlog_
+_texterrorlog_ [l=tr] {hata raporlarÄ±}
+_textadminhome_ [l=tr] {Ana Sayfa}
+_textreturnhome_ [l=tr] {Greenstone Ana Sayfa}
+_titlewelcome_ [l=tr] {YÃ¶netim }
+_textmaas_ [l=tr] {BakÄ±m ve yÃ¶netim hizmetleri aÅaÄÄ±daki iÅlemler iÃ§in mevcuttur:}
+_textvol_ [l=tr] {seyirleri Ã§evrim iÃ§i izle}
+_textcmuc_ [l=tr] {koleksiyonlarÄ± oluÅtur, bakÄ±m yap ve gÃŒncelle}
+_textati_ [l=tr] {CGI ArgÃŒmanlarÄ± tÃŒrÃŒnde teknik bilgiye ulaÅ}
+
+_texttsaa_ [l=tr] {Bu hizmetlere sayfanÄ±n sol tarafÄ±ndaki yanal navigasyon Ã§ubuÄu ile ulaÅabilirsiniz.
+
+}
+
+_textcolstat_ [l=tr] {Koleksiyon Durumu}
+
+_textcwoa_ [l=tr] {Koleksiyonlar eÄer kendilerinin build.cfg dosyalarÄ± varsa, okunabiliyorsa  
+ve geÃ§erli bir builddate alanÄ± iÃ§eriyorsa ( >0 gibi) ve koleksiyonun ilgili index 
+dizininde  ise yalnÄ±zca "running" durumunda belirirler.
+(Bu dizin yapÄ±landÄ±rma dizini deÄildir)
+
+}
+
+# -- Missing translation: _textcafi_
+# -- Missing translation: _textcctv_
+# -- Missing translation: _textsubc_
+# -- Missing translation: _texteom_
+# -- Missing translation: _textftum_
+_textmus_ [l=tr] {main.cfg baÅarÄ±lÄ± bir biÃ§imde gÃŒncellendi}
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=tr] {_collectionname_ koleksiyonu iÃ§in Ã¶zet yapÄ±landÄ±r}
+_textflog_ [l=tr] {_collectionname_ koleksiyonu iÃ§in hata raporu}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+# -- Missing translation: _greenstoneusabilitytext_
+
+# -- Missing translation: _textwhy_
+# -- Missing translation: _textextraforform_
+# -- Missing translation: _textprivacybasic_
+# -- Missing translation: _textstillsend_
+
+# -- Missing translation: _texterror_
+# -- Missing translation: _textyes_
+# -- Missing translation: _textno_
+# -- Missing translation: _textclosewindow_
+# -- Missing translation: _textabout_
+# -- Missing translation: _textprivacy_
+# -- Missing translation: _textsend_
+# -- Missing translation: _textdontsend_
+# -- Missing translation: _textoptionally_
+
+# -- Missing translation: _textunderdev_
+
+# -- Missing translation: _textviewdetails_
+# -- Missing translation: _textmoredetails_
+# -- Missing translation: _texttrackreport_
+# -- Missing translation: _textcharacterise_
+# -- Missing translation: _textseverity_
+ 
+# -- Missing translation: _textbadrender_
+# -- Missing translation: _textcontenterror_
+# -- Missing translation: _textstrangebehaviour_
+# -- Missing translation: _textunexpected_
+# -- Missing translation: _textfunctionality_
+# -- Missing translation: _textother_
+
+# -- Missing translation: _textcritical_
+# -- Missing translation: _textmajor_
+# -- Missing translation: _textmedium_
+# -- Missing translation: _textminor_
+# -- Missing translation: _texttrivial_
+
+# -- Missing translation: _textwhatdoing_
+# -- Missing translation: _textwhatexpected_
+# -- Missing translation: _textwhathappened_
+
+# -- Missing translation: _cannotfindcgierror_
+
+# -- Missing translation: _textusabbanner_
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+# -- Missing translation: _textgli_
+# -- Missing translation: _textglihelp_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+# -- Missing translation: gligr
+# -- Missing translation: _httpicongligr_
+# -- Missing translation: _widthgligr_
+# -- Missing translation: _heightgligr_
Index: /tags/gsdl-2_61-distribution/gsdl/macros/ukrainian.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/ukrainian.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/ukrainian.dm	(revision 10506)
@@ -0,0 +1,1124 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Ukrainian Language text and icon macros 
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=uk] {ÐÐµÑÑÐŸÐŽÐžÑÐœÑ Ð²ÐžÐŽÐ°ÐœÐœÑ}
+_textsource_ [l=uk] {ÐŽÐ¶ÐµÑÐµÐ»ÐŸ: }
+_textdate_ [l=uk] {ÐŽÐ°ÑÐ° Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÑ:}
+_textnumpages_ [l=uk] {Ðº-ÑÑÑ ÑÑÐŸÑÑÐœÐŸÐº: }
+
+_textsignin_ [l=uk] {ÑÐ²ÑÐ¹ÑÐž}
+
+_textdefaultcontent_ [l=uk] {Ð¡ÑÐŸÑÑÐœÐºÐ° ÐœÐµ Ð±ÑÐ»Ð° Ð·ÐœÐ°Ð¹ÐŽÐµÐœÐ°. ÐÐ°ÑÐžÑÐœÑÑÑ
+"ÐœÐ°Ð·Ð°ÐŽ" Ñ Ð²Ð°ÑÐŸÐŒÑ Ð±ÑÐ°ÑÐ·ÐµÑÑ ÑÐŸÐ± Ð¿ÐŸÐ²ÐµÑÐœÑÑÐžÑÑ ÐœÐ° ÑÑÐŸÑÑÐœÐºÑ
+Greenstone Digital Library.}
+
+_textdefaulttitle_ [l=uk] {ÐÐŸÐŒÐžÐ»ÐºÐ° GSDL}
+
+# -- Missing translation: _textbadcollection_
+
+_textselectpage_ [l=uk] {-- ÐÐžÐ±ÑÑ Ð¡ÑÐŸÑÑÐœÐºÐž --}
+
+_collectionextra_ [l=uk] {ÐŠÑ ÐºÐŸÐ»ÐµÐºÑÑÑ ÐŒÑÑÑÐžÑÑ _about:numdocs_ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐ². 
+ÐÐŸÐœÐ° Ð±ÑÐ»Ð° Ð¿ÐŸÐ±ÑÐŽÐŸÐ²Ð°ÐœÐ° _about:builddate_ ÐŽÐœÑÐ² ÑÐŸÐŒÑ.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=uk] {<p>ÐŠÑ ÐºÐŸÐ»ÐµÐºÑÑÑ ÐŒÑÑÑÐžÑÑ _numdocs_ _If_("_numdocs_" eq "1",ÐŽÐŸÐºÑÐŒÐµÐœÑ,ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐ²), Ð·Ð°Ð³Ð°Ð»ÐŸÐŒ _numbytes_.
+<p><a href="_httppagex_(bsummary)">ÐÐ°ÑÐžÑÐœÑÑÑ ÑÑÐŽÐž</a> ÑÐŸÐ± Ð¿ÐµÑÐµÐ³Ð»ÑÐœÑÑÐž ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐž Ð¿ÐŸÐ±ÑÐŽÐŸÐ²Ðž ÐºÐŸÐ»ÐµÐºÑÑÑ.
+}
+
+_textimagecollection_ [l=uk] {}
+# -- Missing translation: _textimageabout_
+# -- Missing translation: _textimagehome_
+_textimagehelp_ [l=uk] {Ð¡ÑÐŸÑÑÐœÐºÐ° ÐŽÐŸÐ¿ÐŸÐŒÐŸÐ³Ðž}
+# -- Missing translation: _textimagepref_
+_textimagegreenstone_ [l=uk] {Greenstone Digital Library Software}
+_textimageusab_ [l=uk] {Ð©ÐŸ ÐŽÐ»Ñ Ð²Ð°Ñ Ð±ÑÐ»ÐŸ ÐœÐ°Ð¹ÑÐºÐ»Ð°ÐŽÐœÑÑÐžÐŒ?}
+
+_textimagesearch_ [l=uk] {ÐÐŸÑÑÐº ÑÐ¿ÐµÑÐžÑÑÑÐœÐžÑ
+ ÑÐµÑÐŒÑÐœÑÐ²}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð°Ð»ÑÐ°Ð²ÑÑÐœÐžÐ¹ ÑÐ¿ÐžÑÐŸÐº Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÑÐ²}
+_textimageCreator_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž ÑÐ¿ÐžÑÐŸÐº Ð°Ð²ÑÐŸÑÑÐ²}
+_textimageSubject_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° ÐºÐ°ÑÐµÐ³ÐŸÑÑÑÑ Ð¿ÑÐµÐŽÐŒÐµÑÐ°}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° ÐŽÐ°ÑÐŸÑ}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° ÑÐŒ'ÑÐŒ ÑÐ°Ð¹Ð»Ð°}
+_textimageLanguage_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° ÐŒÐŸÐ²ÐŸÑ}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° ÐŸÑÐ³Ð°ÐœÑÐ·Ð°ÑÑÑÑ}
+_textimageKeyword_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° ÐºÐ»ÑÑÐŸÐ²ÐžÐŒ ÑÐ»ÐŸÐ²ÐŸÐŒ}
+_textimageHowto_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž ÐŽÐŸÐ¿ÐŸÐŒÐŸÐ³Ñ}
+_textimageList_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž ÑÐµÐºÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°}
+_textimageSeries_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° Ð¿ÑÐžÐ·ÐœÐ°ÑÐµÐœÐœÑÐŒ}
+_textimageTo_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° Ð¿ÐŸÐ»ÐµÐŒ "ÐÑÐŽÐž"}
+_textimageFrom_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° Ð¿ÐŸÐ»ÐµÐŒ "ÐÐ²ÑÐŽÐºÐž"}
+_textimageTopic_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž ÑÐ¿ÐµÑÑÐ°Ð»ÑÐœÑ ÑÐµÐŒÐž}
+_textimageBrowse_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž}
+# -- Missing translation: _textimageCollage_
+_textimagePeople_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð°Ð»ÑÐ°Ð²ÑÑÐœÐžÐŒ ÑÐ¿ÐžÑÐºÐŸÐŒ Ð»ÑÐŽÐµÐ¹}
+_textimageAcronym_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð°ÐºÑÐŸÐœÑÐŒÐž}
+_textimagePhrase_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž ÑÑÐ°Ð·Ðž}
+_textimageArtist_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ñ
+ÑÐŽÐŸÐ¶ÐœÐžÐºÑÐ²}
+_textimageVolume_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° ÑÐŸÐŒÐŸÐŒ}
+# -- Missing translation: _textimageCountries_
+_textimageCaptions_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Ð·Ð° Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐ°ÐŒÐž ÑÐŸÑÐŸÐ³ÑÐ°ÑÑÐ¹}
+
+
+_texticontabsearchgreen_ [l=uk] {ÐÐŸÑÑÐº}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=uk] {ÐÐ°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž A-Z}
+_texticontabCreatorgreen_ [l=uk] {ÐÐ²ÑÐŸÑÐž A-Z}
+_texticontabSubjectgreen_ [l=uk] {ÐÑÐµÐŽÐŒÐµÑÐž}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=uk] {ÐÐ°ÑÐž}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=uk] {ÐÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÑÐ²}
+_texticontabLanguagegreen_ [l=uk] {ÐÐŸÐ²Ð°}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=uk] {ÐÑÐ³Ð°ÐœÑÐ·Ð°ÑÑÑ}
+_texticontabKeywordgreen_ [l=uk] {ÐÐ»ÑÑÐŸÐ²Ñ ÑÐ»ÐŸÐ²Ð°}
+_texticontabhowgreen_ [l=uk] {Ð¯Ðº}
+_texticontabseriesgreen_ [l=uk] {Ð¡ÐµÑÑÑ}
+_texticontablistgreen_ [l=uk] {Ð¡Ð¿ÐžÑÐŸÐº}
+_texticontabtogreen_ [l=uk] {ÐÐŸ}
+_texticontabfromgreen_ [l=uk] {ÐÑÐŽ}
+_texticontabtopicgreen_ [l=uk] {Ð¢ÐµÐŒÐž}
+_texticontabbrwsegreen_ [l=uk] {ÐÑÐŸÐŽÐžÐ²ÐžÑÐžÑÑ}
+# -- Missing translation: _texticontabCollagegreen_
+_texticontabbrowsgreen_ [l=uk] {ÐÑÐŸÐŽÐžÐ²ÐžÑÐžÑÑ}
+_texticontabPeoplegreen_ [l=uk] {ÐÑÐŽÐž A-Z}
+_texticontabAcronymgreen_ [l=uk] {ÐÐºÑÐŸÐœÑÐŒÐž}
+_texticontabPhrasegreen_ [l=uk] {Ð€ÑÐ°Ð·Ðž}
+_texticontabArtistgreen_ [l=uk] {Ð¥ÑÐŽÐŸÐ¶ÐœÐžÐºÐž}
+_texticontabVolumegreen_ [l=uk] {Ð¢ÐŸÐŒÐž}
+# -- Missing translation: _texticontabCaptionsgreen_
+# -- Missing translation: _texticontabCountriesgreen_
+
+_texticontext_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž ÐŽÐŸÐºÑÐŒÐµÐœÑ}
+_texticonclosedbook_ [l=uk] {Ð²ÑÐŽÐºÑÐžÑÐž ÑÐµÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ Ñ Ð¿ÐŸÐ±Ð°ÑÐžÑÐž Ð²ÐŒÑÑÑ}
+_texticonnext_ [l=uk] {ÐŽÐŸ ÐœÐ°ÑÑÑÐ¿ÐœÐŸÑ ÑÐ°ÑÑÐžÐœÐž}
+_texticonprev_ [l=uk] {ÐŽÐŸ Ð¿ÐŸÐ¿ÐµÑÐµÐŽÐœÑÐŸÑ ÑÐ°ÑÑÐžÐœÐž}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž MIDI ÐŽÐŸÐºÑÐŒÐµÐœÑ}
+_texticonmsword_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Microsoft Word ÐŽÐŸÐºÑÐŒÐµÐœÑ}
+_texticonmp3_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž MP3 ÐŽÐŸÐºÑÐŒÐµÐœÑ}
+_texticonpdf_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž PDF ÐŽÐŸÐºÑÐŒÐµÐœÑ}
+_texticonps_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž PostScript ÐŽÐŸÐºÑÐŒÐµÐœÑ}
+_texticonppt_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž PowerPoint ÐŽÐŸÐºÑÐŒÐµÐœÑ}
+_texticonrtf_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž RTF ÐŽÐŸÐºÑÐŒÐµÐœÑ}
+_texticonxls_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž Microsoft Excel ÐŽÐŸÐºÑÐŒÐµÐœÑ}
+
+_page_ [l=uk] {ÑÑÐŸÑÑÐœÐºÐ° }
+_pages_ [l=uk] {ÑÑÐŸÑÑÐœÐºÐž}
+_of_ [l=uk] {Ð· }
+_vol_ [l=uk] {Ð¢ÐŸÐŒ}
+_num_ [l=uk] {ÐÑ.	}
+
+_textmonth00_ [l=uk] {}
+_textmonth01_ [l=uk] {Ð¡ÑÑÐµÐœÑ}
+_textmonth02_ [l=uk] {ÐÑÑÐžÐ¹}
+_textmonth03_ [l=uk] {ÐÐµÑÐµÐ·ÐµÐœÑ}
+_textmonth04_ [l=uk] {ÐÐ²ÑÑÐµÐœÑ}
+_textmonth05_ [l=uk] {Ð¢ÑÐ°Ð²ÐµÐœÑ}
+_textmonth06_ [l=uk] {Ð§ÐµÑÐ²ÐµÐœÑ}
+_textmonth07_ [l=uk] {ÐÐžÐ¿ÐµÐœÑ}
+_textmonth08_ [l=uk] {Ð¡ÐµÑÐ¿ÐµÐœÑ}
+_textmonth09_ [l=uk] {ÐÐµÑÐµÑÐµÐœÑ}
+_textmonth10_ [l=uk] {ÐÐŸÐ²ÑÐµÐœÑ}
+_textmonth11_ [l=uk] {ÐÐžÑÑÐŸÐ¿Ð°ÐŽ}
+_textmonth12_ [l=uk] {ÐÑÑÐŽÐµÐœÑ}
+
+_textdocument_ [l=uk] {ÐÐŸÐºÑÐŒÐµÐœÑ}
+_textsection_ [l=uk] {Ð§Ð°ÑÑÐžÐœÐ°}
+_textparagraph_ [l=uk] {Ð ÐŸÐ·ÐŽÑÐ»}
+
+_magazines_ [l=uk] {ÐÑÑÐœÐ°Ð»Ðž	}
+
+_nzdlpagefooter_ [l=uk] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐÐÐÐÐšÐÐ¯ Ð¡Ð¢ÐÐ ÐÐÐÐ" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=uk] {_httpimg_/uk/chomeof.gif}
+_httpiconchomeon_ [l=uk] {_httpimg_/uk/chomeon.gif}
+
+## "ÐÐÐÐÐÐÐÐ" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=uk] {_httpimg_/uk/chelpof.gif}
+_httpiconchelpon_ [l=uk] {_httpimg_/uk/chelpon.gif}
+
+## "ÐÐÐÐÐšÐ¢Ð£ÐÐÐÐÐ¯" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=uk] {_httpimg_/uk/cprefof.gif}
+_httpiconcprefon_ [l=uk] {_httpimg_/uk/cprefon.gif}
+
+## "ÐÐÐšÐÐ¢Ð¬ ÐÐÐ" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=uk] {_httpimg_/uk/cusabof.gif}
+_httpiconcusabon_ [l=uk] {_httpimg_/uk/cusabon.gif}
+
+
+## "Ð¿ÐŸÑÑÐº" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=uk] {_httpimg_/uk/tsrchgr.gif}
+_httpicontsrchof_ [l=uk] {_httpimg_/uk/tsrchof.gif}
+_httpicontsrchon_ [l=uk] {_httpimg_/uk/tsrchon.gif}
+_widthtsrchx_ [l=uk] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "ÐœÐ°Ð·Ð²Ðž Ð°-Ñ" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=uk] {_httpimg_/uk/ttitlgr.gif}
+_httpiconttitleof_ [l=uk] {_httpimg_/uk/ttitlof.gif}
+_httpiconttitleon_ [l=uk] {_httpimg_/uk/ttitlon.gif}
+_widthttitlex_ [l=uk] {87}
+
+# Not true DC, kept for legacy reasons
+## "Ð°Ð²ÑÐŸÑÐž Ð°-Ñ" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=uk] {_httpimg_/uk/tauthgr.gif}
+_httpicontcreatof_ [l=uk] {_httpimg_/uk/tauthof.gif}
+_httpicontcreaton_ [l=uk] {_httpimg_/uk/tauthon.gif}
+_widthtcreatx_ [l=uk] {93}
+
+## "Ð¿ÑÐµÐŽÐŒÐµÑÐž" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=uk] {_httpimg_/uk/tsubjgr.gif}
+_httpicontsubjon_ [l=uk] {_httpimg_/uk/tsubjon.gif}
+_httpicontsubjof_ [l=uk] {_httpimg_/uk/tsubjof.gif}
+_widthtsubjx_ [l=uk] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "ÐŽÐ°ÑÐž" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=uk] {_httpimg_/uk/tdategr.gif}
+_httpicontdateof_ [l=uk] {_httpimg_/uk/tdateof.gif}
+_httpicontdateon_ [l=uk] {_httpimg_/uk/tdateon.gif}
+_widthtdatex_ [l=uk] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "ÑÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÑÐ²" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=uk] {_httpimg_/uk/tsrcgr.gif}
+_httpicontsrcof_ [l=uk] {_httpimg_/uk/tsrcof.gif}
+_httpicontsrcon_ [l=uk] {_httpimg_/uk/tsrcon.gif}
+_widthtsrcx_ [l=uk] {109}
+
+## "ÐŒÐŸÐ²Ð°" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=uk] {_httpimg_/uk/tlanggr.gif}
+_httpicontlangon_ [l=uk] {_httpimg_/uk/tlangon.gif}
+_httpicontlangof_ [l=uk] {_httpimg_/uk/tlangof.gif}
+_widthtlangx_ [l=uk] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "ÑÐµÑÑÑ" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=uk] {_httpimg_/uk/tsergr.gif}
+_httpicontserof_ [l=uk] {_httpimg_/uk/tserof.gif}
+_httpicontseron_ [l=uk] {_httpimg_/uk/tseron.gif}
+_widthtserx_ [l=uk] {87}
+
+## "ÐŽÐŸ" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=uk] {_httpimg_/uk/ttogr.gif}
+_httpiconttoon_ [l=uk] {_httpimg_/uk/ttoon.gif}
+_httpiconttoof_ [l=uk] {_httpimg_/uk/ttoof.gif}
+_widthttox_ [l=uk] {87}
+
+## "Ð²ÑÐŽ" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=uk] {_httpimg_/uk/tfromgr.gif}
+_httpicontfromon_ [l=uk] {_httpimg_/uk/tfromon.gif}
+_httpicontfromof_ [l=uk] {_httpimg_/uk/tfromof.gif}
+_widthtfromx_ [l=uk] {87}
+
+## "ÐŸÑÐ³Ð°ÐœÑÐ·Ð°ÑÑÑ" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=uk] {_httpimg_/uk/torggr.gif}
+_httpicontorgon_ [l=uk] {_httpimg_/uk/torgon.gif}
+_httpicontorgof_ [l=uk] {_httpimg_/uk/torgof.gif}
+_widthtorgx_ [l=uk] {92}
+
+## "ÑÐº" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=uk] {_httpimg_/uk/thowgr.gif}
+_httpiconthowon_ [l=uk] {_httpimg_/uk/thowon.gif}
+_httpiconthowof_ [l=uk] {_httpimg_/uk/thowof.gif}
+_widththowx_ [l=uk] {87}
+
+## "ÑÐµÐŒÐ°" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=uk] {_httpimg_/uk/ttopicgr.gif}
+_httpiconttopicon_ [l=uk] {_httpimg_/uk/ttopicon.gif}
+_httpiconttopicof_ [l=uk] {_httpimg_/uk/ttopicof.gif}
+_widthttopicx_ [l=uk] {87}
+
+## "Ð¿ÐµÑÐµÐ³Ð»ÑÐœÑÑÐž" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=uk] {_httpimg_/uk/tbrwsegr.gif}
+_httpicontbrwseon_ [l=uk] {_httpimg_/uk/tbrwseon.gif}
+_httpicontbrwseof_ [l=uk] {_httpimg_/uk/tbrwseof.gif}
+_widthtbrwsex_ [l=uk] {103}
+
+# -- Missing translation: tcoll
+# -- Missing translation: _httpicontcollgr_
+# -- Missing translation: _httpicontcollof_
+# -- Missing translation: _httpicontcollon_
+# -- Missing translation: _widthtcollx_
+
+## "Ð»ÑÐŽÐž" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=uk] {_httpimg_/uk/tpeopgr.gif}
+_httpicontpeopof_ [l=uk] {_httpimg_/uk/tpeopof.gif}
+_httpicontpeopon_ [l=uk] {_httpimg_/uk/tpeopon.gif}
+_widthtpeopx_ [l=uk] {87}
+
+## "Ð°ÐºÑÐŸÐœÑÐŒ" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=uk] {_httpimg_/uk/tacrogr.gif}
+_httpicontacroof_ [l=uk] {_httpimg_/uk/tacroof.gif}
+_httpicontacroon_ [l=uk] {_httpimg_/uk/tacroon.gif}
+_widthtacrox_ [l=uk] {87}
+
+## "ÑÑÐ°Ð·Ðž" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=uk] {_httpimg_/uk/tphrsegr.gif}
+_httpicontphrseof_ [l=uk] {_httpimg_/uk/tphrseof.gif}
+_httpicontphrseon_ [l=uk] {_httpimg_/uk/tphrseon.gif}
+_widthtphrsex_ [l=uk] {87}
+
+## "Ñ
+ÑÐŽÐŸÐ¶ÐœÐžÐºÐž" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=uk] {_httpimg_/uk/tartstgr.gif}
+_httpicontartstof_ [l=uk] {_httpimg_/uk/tartstof.gif}
+_httpicontartston_ [l=uk] {_httpimg_/uk/tartston.gif}
+_widthtartstx_ [l=uk] {97}
+
+## "ÐºÐ»ÑÑÐŸÐ²Ñ ÑÐ»ÐŸÐ²Ð°" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=uk] {_httpimg_/uk/tkwgr.gif}
+_httpicontkwof_ [l=uk] {_httpimg_/uk/tkwof.gif}
+_httpicontkwon_ [l=uk] {_httpimg_/uk/tkwon.gif}
+_widthtkwx_ [l=uk] {125}
+
+## "ÑÐŸÐŒÐž" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=uk] {_httpimg_/uk/tvolgr.gif}
+_httpicontvolof_ [l=uk] {_httpimg_/uk/tvolof.gif}
+_httpicontvolon_ [l=uk] {_httpimg_/uk/tvolon.gif}
+_widthtvolx_ [l=uk] {87}
+
+## "Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=uk] {_httpimg_/uk/tcaptgr.gif}
+_httpicontcaptof_ [l=uk] {_httpimg_/uk/tcaptof.gif}
+_httpicontcapton_ [l=uk] {_httpimg_/uk/tcapton.gif}
+_widthtcaptx_ [l=uk] {87}
+
+# -- Missing translation: tcount
+# -- Missing translation: _httpicontcountgr_
+# -- Missing translation: _httpicontcountof_
+# -- Missing translation: _httpicontcounton_
+# -- Missing translation: _widthtcountx_
+
+## "ÐŽÐŸÐ¿ÐŸÐŒÐŸÐ³Ð°" ## green_title ## h_help ##
+_httpiconhhelp_ [l=uk] {_httpimg_/uk/h\_help.gif}
+_widthhhelp_ [l=uk] {200}
+_heighthhelp_ [l=uk] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=uk] {ÐÑÐŸ ÑÑ ÐºÐŸÐ»ÐµÐºÑÑÑ}
+
+# -- Missing translation: _textsubcols1_
+
+_textsubcols2_ [l=uk] {</blockquote>
+ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ Ð¿ÐµÑÐµÐ³Ð»ÑÐœÑÑÐž (Ñ Ð·ÐŒÑÐœÐžÑÐž ÐºÐŸÐ»ÐµÐºÑÑÑ, ÑÐºÑ Ð¿ÑÐŽÐºÐŸÐ»ÐµÐºÑÑÑ Ð²Ðž Ð²ÐžÐºÐŸÑÐžÑÑÐŸÐ²ÑÑÑÐµ
+ÐœÐ° ÑÑÐŸÑÑÐœÑÑ ÐœÐ°Ð»Ð°ÑÑÑÐ²Ð°ÐœÑ.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Ð¿ÑÐŸ" ## green_title ## h_about ##
+_httpiconhabout_ [l=uk] {_httpimg_/uk/h\_about.gif}
+_widthhabout_ [l=uk] {200}
+_heighthabout_ [l=uk] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=uk] {ÐÐ°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž Ð-Ð¯}
+_texticonhcreat_ [l=uk] {ÐÐ²ÑÐŸÑÐž Ð-Ð¯}
+_texticonhsubj_ [l=uk] {ÐÑÐµÐŽÐŒÐµÑÐž}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=uk] {ÐÐ°ÑÐž}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=uk] {ÐÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÑÐ²}
+_texticonhlang_ [l=uk] {ÐÐŸÐ²Ðž}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+# -- Missing translation: _texticonhcoll_
+_texticonhto_ [l=uk] {ÐÐŸ}
+_texticonhfrom_ [l=uk] {ÐÑÐŽ}
+_texticonhser_ [l=uk] {Ð¡ÐµÑÑÑ}
+_texticonhhow_ [l=uk] {Ð¯Ðº}
+_texticonhorg_ [l=uk] {ÐÑÐ³Ð°ÐœÑÐ·Ð°ÑÑÑ}
+_texticonhbrwse_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž}
+_texticonhbrows_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž}
+_texticonhpeople_ [l=uk] {ÐÑÐŽÐž Ð-Ð¯}
+_texticonhacronym_ [l=uk] {ÐÐºÑÐŸÐœÑÐŒÐž}
+_texticonhphrases_ [l=uk] {Ð€ÑÐ°Ð·Ðž}
+_texticonhartist_ [l=uk] {Ð¥ÑÐŽÐŸÐ¶ÐœÐžÐºÐž}
+_texticonhkw_ [l=uk] {ÐÐ»ÑÑÐŸÐ²Ñ ÑÐ»ÐŸÐ²Ð°}
+_texticonhvol_ [l=uk] {Ð¢ÐŸÐŒÐž}
+# -- Missing translation: _texticonhcapt_
+# -- Missing translation: _texticonhcount_
+
+_texticonopenbookshelf_ [l=uk] {Ð·Ð°ÐºÑÐžÑÐž ÑÑ ÑÐ°ÑÑÐžÐœÑ Ð±ÑÐ±Ð»ÑÐŸÑÐµÐºÐž}
+_texticonclosedbookshelf_ [l=uk] {Ð²ÑÐŽÐºÑÐžÑÐž ÑÐµÐ¹ ÑÐŸÐ·ÐŽÑÐ» Ð±ÑÐ±Ð»ÑÐŸÑÐµÐºÐž Ñ Ð¿ÐŸÐ±Ð°ÑÐžÑÐž Ð²ÐŒÑÑÑ}
+_texticonopenbook_ [l=uk] {Ð·Ð°ÐºÑÐžÑÐž ÐºÐœÐžÐ³Ñ}
+_texticonclosedfolder_ [l=uk] {ÐÑÐŽÐºÑÐžÑÐž Ð¿Ð°Ð¿ÐºÑ Ñ Ð¿ÐŸÐ±Ð°ÑÐžÑÐž Ð²ÐŒÑÑÑ}
+_texticonclosedfolder2_ [l=uk] {Ð²ÑÐŽÐºÑÐžÑÐž Ð¿ÑÐŽÑÐŸÐ·ÐŽÑÐ»: }
+_texticonopenfolder_ [l=uk] {Ð·Ð°ÐºÑÐžÑÐž ÑÑ Ð¿Ð°Ð¿ÐºÑ}
+_texticonopenfolder2_ [l=uk] {Ð·Ð°ÐºÑÐžÑÐž Ð¿ÑÐŽÑÐµÐºÑÑÑ: }
+_texticonsmalltext_ [l=uk] {ÐÐµÑÐµÐ³Ð»ÑÐœÑÑÐž ÑÑ ÑÐ°ÑÑÐžÐœÑ ÑÐµÐºÑÑÑ}
+_texticonsmalltext2_ [l=uk] {Ð¿ÐµÑÐµÐ³Ð»ÑÐœÑÑÐž ÑÐµÐºÑÑ: }
+_texticonpointer_ [l=uk] {Ð°ÐºÑÐžÐ²ÐœÐ° ÑÐµÐºÑÑÑ}
+_texticondetach_ [l=uk] {ÐÑÐŽÐºÑÐžÑÐž ÑÑÐŸÑÑÐœÐºÑ Ð² ÐœÐŸÐ²ÐŸÐŒÑ Ð²ÑÐºÐœÑ}
+_texticonhighlight_ [l=uk] {ÐÐžÐŽÑÐ»ÐžÑÐž ÑÑÐºÐ°ÐœÑ ÑÐ»ÐŸÐ²Ð°}
+_texticonnohighlight_ [l=uk] {ÐÐµ Ð²ÐžÐŽÑÐ»ÑÑÐž ÑÑÐºÐ°ÐœÑ ÑÐ»ÐŸÐ²Ð°}
+_texticoncontracttoc_ [l=uk] {Ð ÐŸÐ·Ð³ÐŸÑÐœÑÑÐž ÑÐ°Ð±Ð»ÐžÑÑ Ð²ÐŒÑÑÑÑ}
+_texticonexpandtoc_ [l=uk] {ÐÐ³ÐŸÑÐœÑÑÐž ÑÐ°Ð±Ð»ÐžÑÑ Ð²ÐŒÑÑÑÑ}
+_texticonexpandtext_ [l=uk] {ÐÐŸÐºÐ°Ð·Ð°ÑÐž Ð²ÐµÑÑ ÑÐµÐºÑÑ}
+_texticoncontracttext_ [l=uk] {ÐÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÐž ÑÐµÐºÑÑ Ð»ÐžÑÐµ ÐŽÐ»Ñ Ð²ÐžÐ±ÑÐ°ÐœÐŸÑ ÑÐ°ÑÑÐžÐœÐž}
+_texticonwarning_ [l=uk] {<b>Ð£Ð²Ð°Ð³Ð°: </b>}
+_texticoncont_ [l=uk] {Ð¿ÑÐŸÐŽÐŸÐ²Ð¶ÐžÑÐž?}
+
+_textltwarning_ [l=uk] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Ð ÐŸÐ·Ð³ÐŸÑÑÐ°ÐœÐœÑ ÑÑÐŸÐ³ÐŸ ÑÐµÐºÑÑÑ Ð±ÑÐŽÐµ ÐŒÑÑÑÐžÑÐž Ð²ÐµÐ»ÐžÐºÑ ÐºÑÐ»ÑÐºÑÑÑÑ 
+ÑÐœÑÐŸÑÐŒÐ°ÑÑÑ ÐŽÐ»Ñ ÐÐ°ÑÐŸÐ³ÐŸ Ð±ÑÐ°ÑÐ·ÐµÑÐ°_imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=uk] {Ð¿ÐµÑÐµÐ¹ÑÐž ÐœÐ° ÑÑÐŸÑÑÐœÐºÑ}
+_textintro_ [l=uk] {<i>(Ð²ÑÑÑÐ¿ÐœÐžÐ¹ ÑÐµÐºÑÑ)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž Ð°-Ñ" ## green_title ## h_title ##
+_httpiconhtitle_ [l=uk] {_httpimg_/uk/h\_title.gif}
+_widthhtitle_ [l=uk] {200}
+_heighthtitle_ [l=uk] {57}
+
+# Not true DC, kept for legacy reasons
+## "Ð°Ð²ÑÐŸÑÐž Ð°-Ñ" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=uk] {_httpimg_/uk/h\_auth.gif}
+_widthhcreat_ [l=uk] {200}
+_heighthcreat_ [l=uk] {57}
+
+## "Ð¿ÑÐµÐŽÐŒÐµÑÐž" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=uk] {_httpimg_/uk/h\_subj.gif}
+_widthhsubj_ [l=uk] {200}
+_heighthsubj_ [l=uk] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "ÐŽÐ°ÑÐž" ## green_title ## h_date ##
+_httpiconhdate_ [l=uk] {_httpimg_/uk/h\_date.gif}
+_widthhdate_ [l=uk] {200}
+_heighthdate_ [l=uk] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "ÑÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÑÐ²" ## green_title ## h_src ##
+_httpiconhsrc_ [l=uk] {_httpimg_/uk/h\_src.gif}
+_widthhsrc_ [l=uk] {200}
+_heighthsrc_ [l=uk] {57}
+
+## "ÐŒÐŸÐ²Ðž" ## green_title ## h_lang ##
+_httpiconhlang_ [l=uk] {_httpimg_/uk/h\_lang.gif}
+_widthhlang_ [l=uk] {200}
+_heighthlang_ [l=uk] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "ÐŽÐŸ" ## green_title ## h_to ##
+_httpiconhto_ [l=uk] {_httpimg_/uk/h\_to.gif}
+_widthhto_ [l=uk] {200}
+_heighthto_ [l=uk] {57}
+
+## "Ð²ÑÐŽ" ## green_title ## h_from ##
+_httpiconhfrom_ [l=uk] {_httpimg_/uk/h\_from.gif}
+_widthhfrom_ [l=uk] {200}
+_heighthfrom_ [l=uk] {57}
+
+## "ÑÐµÑÑÑ" ## green_title ## h_ser ##
+_httpiconhser_ [l=uk] {_httpimg_/uk/h\_ser.gif}
+_widthhser_ [l=uk] {200}
+_heighthser_ [l=uk] {57}
+
+## "ÑÐº" ## green_title ## h_how ##
+_httpiconhhow_ [l=uk] {_httpimg_/uk/h\_how.gif}
+_widthhhow_ [l=uk] {200}
+_heighthhow_ [l=uk] {57}
+
+## "ÑÐµÐŒÐž Ð°-Ñ" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=uk] {_httpimg_/uk/h\_topic.gif}
+_widthhtopic_ [l=uk] {200}
+_heighthtopic_ [l=uk] {57}
+
+## "ÐŸÑÐ³Ð°ÐœÑÐ·Ð°ÑÑÑ" ## green_title ## h_org ##
+_httpiconhorg_ [l=uk] {_httpimg_/uk/h\_org.gif}
+_widthhorg_ [l=uk] {250}
+_heighthorg_ [l=uk] {57}
+
+## "Ð¿ÐµÑÐµÐ³Ð»ÑÐŽÐ°ÑÐž" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=uk] {_httpimg_/uk/h\_brwse.gif}
+_widthhbrwse_ [l=uk] {200}
+_heighthbrwse_ [l=uk] {57}
+
+# -- Missing translation: h_coll
+# -- Missing translation: _httpiconhcoll_
+# -- Missing translation: _widthhcoll_
+# -- Missing translation: _heighthcoll_
+
+## "Ð»ÑÐŽÐž" ## green_title ## h_people ##
+_httpiconhpeople_ [l=uk] {_httpimg_/uk/h\_people.gif}
+_widthhpeople_ [l=uk] {200}
+_heighthpeople_ [l=uk] {57}
+
+## "Ð°ÐºÑÐŸÐœÑÐŒÐž" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=uk] {_httpimg_/uk/h\_acro.gif}
+_widthhacronym_ [l=uk] {200}
+_heighthacronym_ [l=uk] {57}
+
+## "ÑÑÐ°Ð·Ðž" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=uk] {_httpimg_/uk/h\_phrse.gif}
+_widthhphrse_ [l=uk] {200}
+_heighthphrse_ [l=uk] {57}
+
+## "Ñ
+ÑÐŽÐŸÐ¶ÐœÐžÐºÐž" ## green_title ## h_artist ##
+_httpiconhartist_ [l=uk] {_httpimg_/uk/h\_artist.gif}
+_widthhartist_ [l=uk] {200}
+_heighthartist_ [l=uk] {57}
+
+## "ÐºÐ»ÑÑÐŸÐ²Ñ ÑÐŸÐ²Ð°" ## green_title ## h_kw ##
+_httpiconhkw_ [l=uk] {_httpimg_/uk/h\_kw.gif}
+_widthhkw_ [l=uk] {200}
+_heighthkw_ [l=uk] {57}
+
+## "ÑÐŸÐŒÐž" ## green_title ## h_vol ##
+_httpiconhvol_ [l=uk] {_httpimg_/uk/h\_vol.gif}
+_widthhvol_ [l=uk] {200}
+_heighthvol_ [l=uk] {57}
+
+# -- Missing translation: h_count
+# -- Missing translation: _httpiconhcount_
+# -- Missing translation: _widthhcount_
+# -- Missing translation: _heighthcount_
+
+## "Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=uk] {_httpimg_/uk/h\_capt.gif}
+_widthhcapt_ [l=uk] {200}
+_heighthcapt_ [l=uk] {57}
+
+
+## "ÐÐ ÐÐÐÐÐÐÐ¢Ð??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=uk] {_httpimg_/uk/contof.gif}
+_httpiconconton_ [l=uk] {_httpimg_/uk/conton.gif}
+
+## "Ð ÐÐÐÐÐ ÐÐ£Ð¢Ð\nÐ¢ÐÐÐ¡Ð¢" ## document_button ## eallt ##
+_httpiconealltof_ [l=uk] {_httpimg_/uk/ealltof.gif}
+_httpiconeallton_ [l=uk] {_httpimg_/uk/eallton.gif}
+
+# -- Missing translation: econc
+# -- Missing translation: _httpiconeconcof_
+# -- Missing translation: _httpiconeconcon_
+
+## "ÐÐÐ'ÐÐÐÐÐ¢Ð" ## document_button ## edtch ##
+_httpiconedtchof_ [l=uk] {_httpimg_/uk/edtchof.gif}
+_httpiconedtchon_ [l=uk] {_httpimg_/uk/edtchon.gif}
+
+# -- Missing translation: eexpc
+# -- Missing translation: _httpiconeexpcof_
+# -- Missing translation: _httpiconeexpcon_
+
+## "ÐÐÐ ÐÐÐÐ¯Ð¢Ð\nÐ¢ÐÐÐ¡Ð¢" ## document_button ## etsec ##
+_httpiconetsecof_ [l=uk] {_httpimg_/uk/etsecof.gif}
+_httpiconetsecon_ [l=uk] {_httpimg_/uk/etsecon.gif}
+
+## "ÐÐÐÐÐÐÐÐÐ¯" ## document_button ## ehl ##
+_httpiconehlof_ [l=uk] {_httpimg_/uk/ehlof.gif}
+_httpiconehlon_ [l=uk] {_httpimg_/uk/ehlon.gif}
+
+## "ÐÐÐ\nÐÐÐÐÐÐÐÐÐ¯" ## document_button ## enhl ##
+_httpiconenhlof_ [l=uk] {_httpimg_/uk/enhlof.gif}
+_httpiconenhlon_ [l=uk] {_httpimg_/uk/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=uk] {_If_(_thislast_,ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÑÐ² _thisfirst_ - _thislast_ ÐŽÐ»Ñ Ð·Ð°Ð¿ÐžÑÑ: _cgiargq_,ÐÐµÐŒÐ°Ñ ÑÐ¿ÑÐ²Ð¿Ð°ÐŽÐ°ÐœÑ ÐŽÐ»Ñ Ð·Ð°Ð¿ÐžÑÑ: _cgiargq_)}
+_textnoquerytitle_ [l=uk] {Ð¡ÑÐŸÑÑÐœÐºÐ° Ð¿ÐŸÑÑÐºÑ}
+
+_texticonthispage_ [l=uk] {Ð¿ÐŸÑÑÐº}
+_textsome_ [l=uk] {ÐŽÐµÑÐºÑ}
+_textall_ [l=uk] {Ð²ÑÐµ}
+_textboolean_ [l=uk] {Ð±ÑÐ»ÐµÐ²ÐžÐ¹}
+# -- Missing translation: _textranked_
+_textnatural_ [l=uk] {Ð¿ÑÐžÑÐŸÐŽÐœÑ}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=uk] {}
+_texticonsearchhistorybar_ [l=uk] {ÑÑÑÐŸÑÑÑ Ð¿ÐŸÑÑÐºÑ}
+
+# -- Missing translation: _textifeellucky_
+
+#alt text for query buttons
+_textusequery_ [l=uk] {Ð²ÐžÐºÐŸÑÐžÑÑÐŸÐ²ÑÐ²Ð°ÑÐž ÑÐµÐ¹ Ð·Ð°Ð¿ÐžÑ}
+# -- Missing translation: _textfreqmsg1_
+_textpostprocess_ [l=uk] {_If_(_quotedquery_,<br><i>Ð¿ÐµÑÐµÑÐ°Ñ
+ÐŸÐ²Ð°ÐœÐŸ ÑÐŸÐ± Ð·ÐœÐ°Ð¹ÑÐž _quotedquery_</i>
+)}
+_textinvalidquery_ [l=uk] {ÐÐµÐ¿ÑÐ°Ð²ÐžÐ»ÑÐœÑÐ¹ ÑÐŸÑÐŒÐ°Ñ Ð·Ð°Ð¿ÐžÑÑ}
+
+_textmorethan_ [l=uk] {ÐÑÐ»ÑÑ ÐœÑÐ¶ }
+_textapprox_ [l=uk] {ÐÑÐŸ }
+_textnodocs_ [l=uk] {ÐÐµÐŒÐ°Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐ², ÑÐŸ Ð²ÑÐŽÐ¿ÐŸÐ²ÑÐŽÐ°ÑÑÑ Ð·Ð°Ð¿ÐžÑÑ.}
+_text1doc_ [l=uk] {1 ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð²ÑÐŽÐ¿ÐŸÐ²ÑÐŽÐ°Ñ Ð·Ð°Ð¿ÐžÑÑ.}
+_textlotsdocs_ [l=uk] {ÐŽÐŸÐºÑÐŒÐµÐœÑÐž, ÑÐŸ Ð²ÑÐŽÐ¿ÐŸÐ²ÑÐŽÐ°ÑÑÑ Ð·Ð°Ð¿ÐžÑÑ.}
+_textmatches_ [l=uk] {Ð¡Ð¿ÑÐ²Ð¿Ð°ÐŽÐ°ÐœÐœÑ }
+_textbeginsearch_ [l=uk] {ÐÐŸÑÐ°ÑÐž ÐÐŸÑÑÐº}
+_textrunquery_ [l=uk] {ÐÐžÐºÐŸÐœÐ°ÑÐž ÐÐ°Ð¿ÐžÑ}
+_textclearform_ [l=uk] {ÐÑÐžÑÑÐžÑÐž ÑÐŸÑÐŒÑ}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=uk] {Ð¡Ð»ÐŸÐ²ÐŸ Ð°Ð±ÐŸ ÑÑÐ°Ð·Ð°}
+_textinfield_ [l=uk] {... Ð² Ð¿ÐŸÐ»Ñ}
+_textfoldstem_ [l=uk] {(fold, stem)}
+
+# -- Missing translation: _textadvquery_
+_textallfields_ [l=uk] {Ð²ÑÑ Ð¿ÐŸÐ»Ñ}
+_texttextonly_ [l=uk] {Ð»ÐžÑÐµ ÑÐµÐºÑÑ}
+_textand_ [l=uk] {Ñ}
+_textor_ [l=uk] {Ð°Ð±ÐŸ}
+_textandnot_ [l=uk] {Ñ ÐœÐµ}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=uk] {ÐšÑÐºÐ°ÑÐž _indexselection_ _If_(_jselection_, of _jselection_) _If_(_gselection_, ÐœÐ° _gselection_ ÑÑÐ²ÐœÑ) _If_(_nselection_, ÐœÐ° _nselection_ ÐŒÐŸÐ²Ñ) ÑÐŸ ÐŒÑÑÑÐžÑÑ _querytypeselection_ ÑÐ»ÑÐ²}
+
+# -- Missing translation: _textadvancedsearch_
+
+# -- Missing translation: _textformsimplesearch_
+
+# -- Missing translation: _textformadvancedsearch_
+
+
+_textnojsformwarning_ [l=uk] {Ð£Ð²Ð°Ð³Ð°: Javascript Ð·Ð°Ð±ÐŸÑÐŸÐœÐµÐœÐ° ÐœÑ ÐÐ°ÑÐŸÐŒÑ Ð±ÑÐ°ÑÐ·ÐµÑÑ. <br>Ð©ÐŸÐ± Ð²ÐžÐºÐŸÑÐžÑÑÐŸÐ²ÑÐ²Ð°ÑÐž Ð¿ÐŸÑÑÐº Ð· ÑÐŸÑÐŒÐŸÑ ÐŽÐŸÐ·Ð²ÐŸÐ»ÑÑÐµ Ð¹ÐŸÐ³ÐŸ Ð²ÐžÐºÐŸÑÐžÑÑÐ°ÐœÐœÑ.}
+# -- Missing translation: _textdatesearch_
+_textstartdate_ [l=uk] {ÐÐŸÑÐžÐœÐ°ÑÑÐž Ð· (Ð°Ð±ÐŸ Ð»ÐžÑÐµ) ÐŽÐ°ÑÐž:}
+_textenddate_ [l=uk] {ÐÑÐœÑÐµÐ²Ð° ÐŽÐ°ÑÐ°:}
+_textbc_ [l=uk] {B.C.E.}
+_textad_ [l=uk] {C.E.}
+# -- Missing translation: _textexplaineras_
+
+_textstemon_ [l=uk] {(ÑÐ³ÐœÐŸÑÑÐ²Ð°ÑÐž Ð·Ð°ÐºÑÐœÑÐµÐœÐœÑ ÑÐ»ÑÐ²)}
+
+_textsearchhistory_ [l=uk] {ÐšÑÐºÐ°ÑÐž Ð² ÑÑÑÐŸÑÑÑ}
+
+#text macros for search history
+_textnohistory_ [l=uk] {ÐÑÑÐŸÑÑÑ Ð¿ÐŸÑÑÐºÑ ÐœÐµÐŽÐŸÑÑÑÐ¿ÐœÐ°}
+_texthresult_ [l=uk] {ÑÐµÐ·ÑÐ»ÑÑÐ°Ñ}
+_texthresults_ [l=uk] {ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐž}
+# -- Missing translation: _texthallwords_
+_texthsomewords_ [l=uk] {ÐŽÐµÑÐºÑ ÑÐ»ÐŸÐ²Ð°}
+# -- Missing translation: _texthboolean_
+# -- Missing translation: _texthranked_
+_texthcaseon_ [l=uk] {Ð²ÐµÐ»ÐžÑÐžÐœÐ° Ð»ÑÑÐµÑ Ð¿ÐŸÐ²ÐžÐœÐœÐ° ÑÐ¿ÑÐ²Ð¿Ð°ÐŽÐ°ÑÐž}
+# -- Missing translation: _texthcaseoff_
+# -- Missing translation: _texthstemon_
+# -- Missing translation: _texthstemoff_
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Ð¿ÐŸÑÑÐº" ## green_title ## h_search ##
+_httpiconhsearch_ [l=uk] {_httpimg_/uk/h\_search.gif}
+_widthhsearch_ [l=uk] {200}
+_heighthsearch_ [l=uk] {57}
+
+## "ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐž" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=uk] {_httpimg_/uk/qryresb.gif}
+_widthqryresb_ [l=uk] {_pagewidth_}
+_heightqryresb_ [l=uk] {17}
+
+## "ÑÑÑÐŸÑÑÑ" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=uk] {_httpimg_/uk/schhistb.gif}
+_widthsrchhistb_ [l=uk] {_pagewidth_}
+_heightsrchhistb_ [l=uk] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# -- Missing translation: _textprefschanged_
+_textsetprefs_ [l=uk] {Ð²ÐžÑÑÐ°Ð²ÐžÑÐž ÐœÐ°Ð»Ð°ÑÑÑÐ²Ð°ÐœÐœÑ}
+_textsearchprefs_ [l=uk] {ÐÐ°Ð»Ð°ÑÑÑÐ²Ð°ÐœÐœÑ Ð¿ÐŸÑÑÐºÑ}
+_textcollectionprefs_ [l=uk] {ÐÐ°Ð»Ð°ÑÑÑÐ²Ð°ÐœÐœÑ ÐºÐŸÐ»ÐµÐºÑÑÑ}
+# -- Missing translation: _textpresentationprefs_
+_textpreferences_ [l=uk] {ÐÐ°Ð»Ð°ÑÑÑÐ²Ð°ÐœÐœÑ}
+_textcasediffs_ [l=uk] {Ð ÑÐ·ÐœÐžÑÑ Ð² Ð²ÐµÐ»ÐžÑÐžÐœÑ Ð±ÑÐºÐ²:}
+_textignorecase_ [l=uk] {ÑÐ³ÐœÐŸÑÑÐ²Ð°ÑÐž Ð²ÐµÐ»ÐžÑÐžÐœÑ Ð±ÑÐºÐ²}
+_textmatchcase_ [l=uk] {Ð²ÐµÐ»ÐžÐºÑ/ÐŒÐ°Ð»ÐµÐœÑÐºÑ Ð±ÑÐºÐ²Ðž Ð¿ÐŸÐ²ÐžÐœÐœÑ ÑÐ¿ÑÐ²Ð¿Ð°ÐŽÐ°ÑÐž}
+_textwordends_ [l=uk] {ÐÐ°ÐºÑÐœÑÐµÐœÐœÑ ÑÐ»ÑÐ²:}
+_textstem_ [l=uk] {ÑÐ³ÐœÐŸÑÑÐ²Ð°ÑÐž Ð·Ð°ÐºÑÐœÑÐµÐœÐœÑ ÑÐ»ÑÐ²}
+_textnostem_ [l=uk] {ÑÑÐ»Ðµ ÑÐ»ÐŸÐ²ÐŸ Ð¿ÐŸÐ²ÐžÐœÐœÐµ ÑÐ¿ÑÐ²Ð¿Ð°ÐŽÐ°ÑÐž}
+_textprefop_ [l=uk] {ÐÐŸÐ²ÐµÑÐœÑÑÐž ÐŽÐŸ _maxdocoption_ hits with _hitsperpageoption_ ÑÐ¿ÐŸÐ²Ð¿Ð°ÐŽÐ°ÐœÑ ÐœÐ° ÑÑÐŸÑÑÐœÐºÑ.}
+_textextlink_ [l=uk] {ÐÐŸÑÑÑÐ¿ ÐŽÐŸ Ð·ÐŸÐ²ÐœÑÑÐœÑÑ
+ Web-ÑÑÐŸÑÑÐœÐŸÐº:}
+_textintlink_ [l=uk] {ÐÐŸÐºÑÐŒÐµÐœÑÐž ÐŸÐŽÐµÑÐ¶Ð°ÐœÑ Ð·:}
+_textlanguage_ [l=uk] {ÐÐŸÐ²Ð° ÑÐœÑÐµÑÑÐµÐ¹ÑÑ:}
+_textencoding_ [l=uk] {ÐÐŸÐŽÑÐ²Ð°ÐœÐœÑ:}
+_textformat_ [l=uk] {ÑÐŸÑÐŒÐ°Ñ ÑÐœÑÐµÑÑÐµÐ¹ÑÑ:}
+_textall_ [l=uk] {Ð²ÑÐµ}
+# -- Missing translation: _textquerymode_
+_textsimplemode_ [l=uk] {ÑÐµÐ¶ÐžÐŒ Ð¿ÑÐŸÑÑÐŸÐ³ÐŸ Ð·Ð°Ð¿ÐžÑÑ}
+_textadvancedmode_ [l=uk] {ÑÐºÐ»Ð°ÐŽÐœÑÑÐžÐ¹ ÑÐµÐ¶ÐžÐŒ Ð·Ð°Ð¿ÐžÑÑ (ÐŽÐŸÐ·Ð²ÐŸÐ»ÑÑ Ð±ÑÐ»ÐµÐ²ÐžÐ¹ Ð¿ÐŸÑÑÐº, Ð²ÐžÐºÐŸÑÐžÑÑÐŸÐ²ÑÑÑÐž !, &, |, Ñ ÐŽÑÐ¶ÐºÐž)}
+_textlinkinterm_ [l=uk] {ÑÐµÑÐµÐ· intermediate ÑÑÐŸÑÑÐœÐºÑ}
+_textlinkdirect_ [l=uk] {Ð¿ÐµÑÐµÑ
+ÐŸÐŽÑÑÐµ Ð¿ÑÑÐŒÐŸ ÑÑÐŽÐž}
+_textdigitlib_ [l=uk] {ÐµÐ»ÐµÐºÑÑÐŸÐœÐœÐ° Ð±ÑÐ±Ð»ÑÐŸÑÐµÐºÐ°}
+# -- Missing translation: _textweb_
+_textgraphical_ [l=uk] {ÐÑÐ°ÑÑÑÐœÐžÐ¹}
+_texttextual_ [l=uk] {ÑÐµÐºÑÑÐŸÐ²ÐžÐ¹}
+_textcollectionoption_ [l=uk] {<p>
+ÐÐºÐ»ÑÑÐžÑÐž Ð¿ÑÐŽÐºÐŸÐ»ÐµÐºÑÑÑ:
+<br>}
+
+# -- Missing translation: _textrelateddocdisplay_
+_textsearchhistory_ [l=uk] {ÐÑÑÐŸÑÑÑ Ð¿ÐŸÑÑÐºÑ:}
+_textnohistory_ [l=uk] {ÐÐµÐŒÐ°Ñ ÑÑÑÐŸÑÑÑ Ð¿ÐŸÑÑÐºÑ}
+_texthistorydisplay_ [l=uk] {Ð¿ÐŸÐºÐ°Ð·Ð°ÑÐž _historynumrecords_ Ð·Ð°Ð¿ÐžÑÑÐ² ÑÑÑÐŸÑÑÑ Ð¿ÐŸÑÑÐºÑ}
+_textnohistorydisplay_ [l=uk] {ÐœÐµ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÐž ÑÑÑÐŸÑÑÑ Ð¿ÐŸÑÑÐºÑ}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=uk] {ÐÐŸÑÑÐº Ð·Ð° ÑÐŸÑÐŒÐŸÑ:}
+_textplainsearch_ [l=uk] {ÐÑÐŸÑÑÐžÐ¹ Ð¿ÐŸÑÑÐº:}
+# -- Missing translation: _textqueryboxsize_
+# -- Missing translation: _textregbox_
+_textbigbox_ [l=uk] {Ð²ÐµÐ»ÐžÐºÐµ Ð¿ÐŸÐ»Ðµ Ð·Ð°Ð¿ÐžÑÑ}
+_textformtype_ [l=uk] {Ð¢ÐžÐ¿ ÑÐŸÑÐŒÐž:}
+_textsimple_ [l=uk] {Ð¿ÑÐŸÑÑÐžÐ¹}
+_textadvanced_ [l=uk] {ÑÑÐºÐ»Ð°ÐŽÐœÐµÐœÐžÐ¹.}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=uk] {Ð·}
+_textfields_ [l=uk] {Ð¿ÐŸÐ»Ñ}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "ÐœÐ°Ð»Ð°ÑÑÑÐ²Ð°ÐœÐœÑ" ## green_title ## h_pref ##
+_httpiconhpref_ [l=uk] {_httpimg_/uk/h\_pref.gif}
+_widthhpref_ [l=uk] {200}
+_heighthpref_ [l=uk] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=uk] {Ð¡ÐŸÑÑÑÐ²Ð°ÑÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÐž Ð·Ð°}
+_textalsoshowing_ [l=uk] {ÑÐ°ÐºÐŸÐ¶ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÐŸ}
+_textwith_ [l=uk] {Ð· ÑÐŸÐœÐ°Ð¹Ð±ÑÐ»ÑÑÐµ}
+_textdocsperpage_ [l=uk] {ÐŽÐŸÐºÑÐŒÐµÐœÑÑÐ² ÐœÐ° ÑÑÐŸÑÑÐœÐºÑ}
+
+_textfilterby_ [l=uk] {ÐÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÐž, ÑÐŸ ÐŒÑÑÑÑÑÑ}
+_textall_ [l=uk] {Ð²ÑÐµ}
+_textany_ [l=uk] {Ð±ÑÐŽÑ-ÑÐºÐžÐ¹}
+_textwords_ [l=uk] {ÑÐ»ÑÐ²}
+_textleaveblank_ [l=uk] {Ð·Ð°Ð»ÐžÑÑÐµ ÑÐµ Ð¿ÐŸÐ»Ðµ Ð¿ÐŸÑÐŸÐ¶ÐœÑÐŒ, ÑÐŸÐ± ÐŸÐŽÐµÑÐ¶Ð°ÑÐž Ð²ÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐž}
+
+_browsebuttontext_ [l=uk] {"Ð¡ÐŸÑÑÑÐ²Ð°ÑÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÐž"}
+
+_nodata_ [l=uk] {<i>ÐœÐµÐŒÐ°Ñ ÐŽÐ°ÐœÐžÑ
+</i>}
+_docs_ [l=uk] {ÐŽÐŸÐºÑÐŒÐµÐœÑÐž}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=uk] {ÐÐŸÐ¿ÐŸÐŒÐŸÐ³Ð°}
+_textSearchshort_ [l=uk] {ÑÑÐºÐ°ÑÐž ÑÐ»ÐŸÐ²Ð°}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐŸÐŒ}
+_textCreatorshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð°Ð²ÑÐŸÑÐŸÐŒ}
+_textSubjectshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð¿ÑÐµÐŽÐŒÐµÑÐ°ÐŒÐž}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÐŽÐ°ÑÐŸÑ}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÑÐŒ'ÑÐ² ÑÐ°Ð¹Ð»Ð°}
+_textLanguageshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÐŒÐŸÐ²ÐŸÑ}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÑÐµÑÑÑÐŒÐž}
+_textToshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð¿ÐŸÐ»ÐµÐŒ ÐÐŸ}
+_textFromshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð¿ÐŸÐ»ÐµÐŒ ÐÐ²ÑÐŽÐºÐž}
+_textBrowseshort_ [l=uk] {Ð¿ÐµÑÐµÐ³Ð»ÑÐŽÐ°ÑÐž ÑÐµÐºÑÑÐž}
+_textOrganizationshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÐŸÑÐ³Ð°ÐœÑÐ·Ð°ÑÑÑÑ}
+_textHowtoshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÑÐ¿ÐžÑÐºÐŸÐŒ "ÑÐº"}
+_textTopicshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÑÐµÐŒÐŸÑ}
+_textPeopleshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð»ÑÐŽÑÐŒÐž}
+_textAcronymshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð¿ÐŸÑÐ»ÑÐŽÐŸÐ²ÐœÑÑÑÑ Ð°ÐºÑÐŸÐœÑÐŒÑÐ²}
+_textPhraseshort_ [l=uk] {ÑÑÐ°Ð·Ðž, ÑÐŸ Ð·ÑÑÑÑÑÑÐ°ÑÑÑÑÑ Ð² Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÑÑ
+}
+_textArtistshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ñ
+ÑÐŽÐŸÐ¶ÐœÐžÐºÐŸÐŒ}
+_textKeywordshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÐºÐ»ÑÑÐŸÐ²ÐžÐŒÐž ÑÐ»ÐŸÐ²Ð°ÐŒÐž}
+_textVolumeshort_ [l=uk] {ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÑÐŸÐŒÐŸÐŒ}
+# -- Missing translation: _textCountriesshort_
+_textdefaultshorttext_ [l=uk] {ÐœÐµÐ²ÑÐŽÐŸÐŒÐ° ÐºÐ»Ð°ÑÐžÑÑÐºÐ°ÑÑÑ}
+
+_textSearchlong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÑÑÐºÐ°ÑÐž ÑÐ»ÐŸÐ²Ð°</i>, 
+ÑÐŸ Ð²ÐžÐœÐžÐºÐ°ÑÑÑ ÐœÐ° ÑÑÐŸÑÑÐœÑÑ "Ð¿ÐŸÑÑÐº". ÐŠÐµ Ð¿ÐµÑÑÐ° ÑÑÐŸÑÑÐœÐºÐ°, ÑÐŸ Ð²ÐžÐœÐžÐºÐ°Ñ,
+ÐºÐŸÐ»Ðž ÐÐž Ð¿ÐŸÑÐžÐœÐ°ÑÑÐµ ÑÐŸÐ±ÐŸÑÑ, ÐŽÐŸ ÐœÐµÑ ÐŒÐŸÐ¶ÐœÐ° Ð¿ÐµÑÐµÐ¹ÑÐž Ð· ÑÐœÑÐžÑ
+ ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>Ð¿ÐŸÑÑÐº</i>. }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐŸÐŒ</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž Ð°-Ñ</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº ÐºÐœÐžÐ³ Ð² Ð°Ð»ÑÐ°Ð²ÑÑÐœÐŸÐŒÑ Ð¿ÐŸÑÑÐŽÐºÑ.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð°Ð²ÑÐŸÑÐŸÐŒ</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>Ð°Ð²ÑÐŸÑÐž Ð°-Ñ</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº, 
+Ð²ÑÐŽÑÐŸÑÑÐŸÐ²Ð°ÐœÐžÐ¹ Ð·Ð° ÑÐŒÐµÐœÐ°ÐŒÐž Ð°Ð²ÑÐŸÑÑÐ².  }
+
+_textSubjectlong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð¿ÑÐµÐŽÐŒÐµÑÐ°ÐŒÐž</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>Ð¿ÑÐµÐŽÐŒÐµÑÐž</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº Ð¿ÑÐµÐŽÐŒÐµÑÑÐ², 
+ÐœÐ° ÐºÐœÐžÐ¶ÐºÐŸÐ²ÑÐ¹ Ð¿ÐŸÐ»ÐžÑÑ.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÐŽÐ°ÑÐŸÑ</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÐŽÐ°ÑÐž</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº, 
+Ð²ÑÐŽÑÐŸÑÑÐŸÐ²Ð°ÐœÐžÐ¹ Ð·Ð° ÐŽÐ°ÑÐ°ÐŒÐž.  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÑÐŒ'ÑÐ² ÑÐ°Ð¹Ð»Ð°</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÑÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÑÐ²</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº, 
+Ð²ÑÐŽÑÐŸÑÑÐŸÐ²Ð°ÐœÐžÐ¹ Ð·Ð° ÑÐŒÐµÐœÐ°ÐŒÐž ÑÐ°Ð¹Ð»ÑÐ².  }
+
+_textLanguagelong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÐŒÐŸÐ²ÐŸÑ</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÐŒÐŸÐ²Ðž</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº, 
+Ð²ÑÐŽÑÐŸÑÑÐŸÐ²Ð°ÐœÐžÐ¹ Ð·Ð° ÐŒÐŸÐ²Ð°ÐŒÐž.  }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÐŸÑÐ³Ð°ÐœÑÐ·Ð°ÑÑÑÑ</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÐŸÑÐ³Ð°ÐœÑÐ·Ð°ÑÑÑ</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº, 
+Ð²ÑÐŽÑÐŸÑÑÐŸÐ²Ð°ÐœÐžÐ¹ Ð·Ð° ÐŸÑÐ³Ð°ÐœÑÐ·Ð°ÑÑÑÐŒÐž.  }
+
+_textHowtolong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÑÐ¿ÐžÑÐºÐŸÐŒ "ÑÐº"</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÑÐº</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº ÑÑÑÑÑÐŸÐº.  }
+
+_textTopiclong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÑÐµÐŒÐŸÑ</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÑÐµÐŒÐž</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº ÑÐµÐŒ.  }
+
+_textTolong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð¿ÐŸÐ»ÐµÐŒ ÐÐŸ<i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÐÐŸ</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº Ð°ÐŽÑÐµÑ.  }
+
+_textFromlong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð¿ÐŸÐ»ÐµÐŒ ÐÐ²ÑÐŽÐºÐž</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>Ð·Ð²ÑÐŽÐºÐž</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº, 
+Ð²ÑÐŽÑÐŸÑÑÐŸÐ²Ð°ÐœÐžÐ¹ Ð·Ð° ÑÐŒÐµÐœÐ°ÐŒÐž ÑÐžÑ
+, Ñ
+ÑÐŸ Ð¿ÑÐžÑÐ»Ð°Ð² ÑÐµÐºÑÑÐž.  }
+
+_textSerieslong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÑÐµÑÑÑÐŒÐž</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÑÐµÑÑÑ</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº ÑÐµÑÑÐ¹, 
+ÑÐŸ Ñ Ð² ÐºÐŸÐ»ÐµÐºÑÑÑ.  }
+
+_textBrowselong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>Ð¿ÐµÑÐµÐ³Ð»ÑÐŽÐ°ÑÐž ÑÐµÐºÑÑÐž</i>, ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž
+ÐºÐœÐŸÐ¿ÐºÐž <i>Ð¿ÐµÑÐµÐ³Ð»ÑÐŽ</i>.  }
+
+_textPeoplelong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð»ÑÐŽÑÐŒÐž</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>Ð»ÑÐŽÐž</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº, 
+Ð²ÑÐŽÑÐŸÑÑÐŸÐ²Ð°ÐœÐžÐ¹ Ð·Ð° Ð¿ÑÐžÐ·Ð²ÐžÑÐ°ÐŒÐž.  }
+
+_textAcronymlong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ð¿ÐŸÑÐ»ÑÐŽÐŸÐ²ÐœÑÑÑÑ Ð°ÐºÑÐŸÐœÑÐŒÑÐ²</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>Ð°ÐºÑÐŸÐœÑÐŒÐž</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº Ð°ÐºÑÐŸÐœÑÐŒÑÐ²
+Ñ ÐŒÑÑÑÑ ÐŽÐµ Ð²ÐŸÐœÐž Ð·ÑÑÑÑÑÑÐ°ÑÑÑÑÑ.  }
+
+_textPhraselong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÑÑÐ°Ð·Ðž, ÑÐŸ Ð·ÑÑÑÑÑÑÐ°ÑÑÑÑÑ Ð² Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÑÑ
+</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÑÑÐ°Ð·Ðž</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº ÑÑÐ°Ð·.  }
+
+_textArtistlong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° Ñ
+ÑÐŽÐŸÐ¶ÐœÐžÐºÐŸÐŒ</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>Ñ
+ÑÐŽÐŸÐ¶ÐœÐžÐºÐž</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº, 
+Ð²ÑÐŽÑÐŸÑÑÐŸÐ²Ð°ÐœÐžÐ¹ Ð·Ð° ÑÐŒÐµÐœÐ°ÐŒÐž Ñ
+ÑÐŽÐŸÐ¶ÐœÐžÐºÑÐ².  }
+
+_textKeywordlong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÐºÐ»ÑÑÐŸÐ²ÐžÐŒÐž ÑÐ»ÐŸÐ²Ð°ÐŒÐž</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÐºÐ»ÑÑÐŸÐ²Ñ ÑÐ»ÐŸÐ²Ð°</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº ÐºÐ»ÑÑÐŸÐ²ÐžÑ
+ ÑÐ»ÑÐ².  }
+
+_textVolumelong_ [l=uk] {<p>ÐÐž ÐŒÐŸÐ¶ÐµÑÐµ <i>ÐŸÐŽÐµÑÐ¶Ð°ÑÐž ÐŽÐŸÑÑÑÐ¿ ÐŽÐŸ Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÐ¹ Ð·Ð° ÑÐŸÐŒÐŸÐŒ</i> 
+ÐœÐ°ÑÐžÑÐœÑÐ²ÑÐž ÐºÐœÐŸÐ¿ÐºÑ <i>ÑÐŸÐŒÐž</i>.  ÐŠÐµ Ð²ÐžÐ²ÐµÐŽÐµ ÑÐ¿ÐžÑÐŸÐº ÑÐŸÐŒÑÐ².  }
+
+# -- Missing translation: _textCaptionslong_
+
+# -- Missing translation: _textCountrieslong_
+
+
+_textdefaultlongtext_ [l=uk] {<p>ÐÐ°ÑÐžÑÐœÑÑÑ ÐœÐ° ÐºÐœÐŸÐ¿ÐºÑ <i>ÐœÐµÐ²ÑÐŽÐŸÐŒÑ</i> ÑÐŸÐ± Ð¿ÐµÑÐµÐ³Ð»ÑÐœÑÑÐž
+Ð¿ÑÐ±Ð»ÑÐºÐ°ÑÑÑ (Ð²ÑÐŽÑÐŸÑÑÐŸÐ²Ð°ÐœÑ Ð·Ð° ÐœÐµÐ²ÑÐŽÐŸÐŒÐžÐŒ Ð¿ÐŸÐ»ÐµÐŒ).  }
+
+# -- Missing translation: _texthelptopics_
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=uk] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+# -- Missing translation: _textreadingdocs_
+
+# -- Missing translation: _texthelpreadingdocs_
+
+# -- Missing translation: _texthelpsearching_
+
+_textdatesearch_ [l=uk] {ÐšÑÐºÐ°ÑÐž Ð·Ð° ÐÐ°ÑÐ°ÐŒÐž}
+
+# -- Missing translation: _texthelpdatesearch_
+
+_textchangeprefs_ [l=uk] {ÐÐŒÑÐœÐžÑÐž ÐÐ°ÑÑ ÐœÐ°Ð»Ð°ÑÑÑÐ²Ð°ÐœÐœÑ}
+
+# -- Missing translation: _texthelppreferences_
+
+_texttanumbrowseoptions_ [l=uk] {ÐÑÐœÑÑ _numbrowseoptions_ ÑÐ¿ÐŸÑÐŸÐ±ÑÐ² Ð·ÐœÐ°Ð¹ÑÐž ÑÐœÑÐŸÑÐ²Ð°ÑÑÑ Ð² ÑÑÐ¹ ÐºÐŸÐ»ÐµÐºÑÑÑ:}
+
+_textsimplehelpheading_ [l=uk] {Ð¯Ðº ÑÑÐºÐ°ÑÐž ÑÐœÑÐŸÑÐŒÐ°ÑÑÑ Ð² ÐºÐŸÐ»ÐµÐºÑÑÑ _collectionname_}
+
+# -- Missing translation: _texthelpscope_
Index: /tags/gsdl-2_61-distribution/gsdl/macros/users.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/users.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/users.dm	(revision 10506)
@@ -0,0 +1,196 @@
+# this file must be UTF-8 encoded
+
+package userslistusers
+
+_header_ {
+<html>
+<head>
+<title>_textlocu_</title>
+</head>
+<body bgcolor="#ffffff" text="#000000" link="#006666"
+      alink="#cc9900" vlink="#666633">
+}
+
+_content_ {}
+
+_contentstart_ {
+<h2>_textlocu_</h2>
+
+
+<table border=0 cellspacing=1 cellpadding=3 width=100%>
+<tr>
+  <th bgcolor="\#d0d0d0">_textuser_</th>
+  <th bgcolor="\#d0d0d0">_textas_</th>
+  <th bgcolor="\#d0d0d0">_textgroups_</th>
+  <th bgcolor="\#d0d0d0">_textcomment_</th>
+  <th>&nbsp;</th>
+</tr>
+}
+
+_contentend_ {
+</table>
+}
+
+_footer_ {
+</body>
+</html>
+}
+
+
+
+package usersedituser
+
+_header_ {
+<html>
+<head>
+<title>_If_("_cgiarguma_" eq "edituser",_textedituser_,_textadduser_)</title>
+</head>
+<body bgcolor="#ffffff" text="#000000" link="#006666"
+      alink="#cc9900" vlink="#666633">
+}
+
+_content_ {
+<h2>_If_("_cgiarguma_" eq "edituser",_textedituser_,_textadduser_)</h2>
+
+
+_users:messagestatus_
+
+<form name="edituser" method="post" action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="a" value="um">
+<input type=hidden name="uma" value="_cgiarguma_">
+
+<table border=0>
+<tr><td>_authen:textusername_</td><td><input type="text" name="umun" value="_users:usersargun_" size=15></td>
+<td><font color=gray>_textaboutusername_</font></td>
+</tr>
+<tr><td>_authen:textpassword_</td><td><input type="text" name="umpw" value="_users:usersargpw_" size=9></td>
+<td><font color=gray>_textaboutpassword_
+_If_("_cgiarguma_" eq "edituser",_textoldpass_)
+</font></td></tr>
+<tr><td>_userslistusers:textas_</td><td>
+<select name="umus">
+<option value="enabled">_textenabled_
+<option value="disabled"_If_("_users:usersargus_" ne "enabled", selected)>_textdisabled_
+</select>
+</td></tr>
+<tr><td>_userslistusers:textgroups_</td><td><input type="text" name="umug" value="_users:usersargug_" size=15></td>
+<td><font color=gray>_textaboutgroups_</font></td></tr>
+<tr><td>_userslistusers:textcomment_</td><td colspan=2><input type="text" name="umc" value="_users:usersargc_" size=50></td></tr>
+<tr><td></td><td colspan=2><input type="submit" name=beu value="submit">
+<input type="submit" name=uma value="cancel"></td></tr>
+</table>
+</form>
+}
+
+_footer_ {
+</body>
+</html>
+}
+
+
+
+
+package usersdeleteuser
+
+_header_ {
+<html>
+<head>
+<title>_textdeleteuser_</title>
+</head>
+<body bgcolor="#ffffff" text="#000000" link="#006666"
+      alink="#cc9900" vlink="#666633">
+}
+
+_content_ {
+
+<p>
+<table border=0>
+<tr><td>
+<form name="deleteuser" method="post" action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="a" value="um">
+<input type=hidden name="uma" value="_cgiarguma_">
+<input type=hidden name="umun" value="_cgiargumun_">
+<font color=red>_textremwarn_</font>
+<input type="submit" name=cm value="no">
+<input type="submit" name=cm value="yes">
+</form>
+</td></tr>
+</table>
+}
+
+_footer_ {
+</body>
+</html>
+}
+
+
+
+package userschangepasswd
+
+_header_ {
+<html>
+<head>
+<title>_textchangepw_</title>
+</head>
+<body bgcolor="#ffffff" text="#000000" link="#006666"
+      alink="#cc9900" vlink="#666633">
+}
+
+_content_ {
+<h2>_textchangepw_</h2>
+<p><font color=gray>_usersedituser:textaboutpassword_</font>
+
+<p>_users:messagestatus_
+
+<p>
+<form name="changepasswd" method="post" action="_gwcgi_">
+<input type=hidden name="e" value="_decodedcompressedoptions_">
+<input type=hidden name="a" value="um">
+<input type=hidden name="uma" value="_cgiarguma_">
+<table border=0>
+<tr><td align=right>_textoldpw_</td><td><input type="password" name="umpw" size=9></td></tr>
+<tr><td align=right>_textnewpw_</td><td><input type="password" name="umnpw1" size=9></td></tr>
+<tr><td align=right>_textretype_</td><td><input type="password" name="umnpw2" size=9></td></tr>
+<tr><td></td><td><input type="submit" name=bcp value="submit"></td></tr>
+</table>
+</table>
+</form>
+
+}
+
+
+package userschangepasswdok
+
+_header_ {
+<html>
+<head>
+<title>_userschangepasswd:textchangepw_</title>
+</head>
+<body bgcolor="#ffffff" text="#000000" link="#006666"
+      alink="#cc9900" vlink="#666633">
+}
+
+_content_ {
+<h2>_userschangepasswd:textchangepw_</h2>
+
+<p>_textsuccess_
+}
+
+
+
+package users
+
+_messageinvalidusername_ {<font color=red>_textinvalidusername_</font>}
+_messageinvalidpassword_ {<font color=red>_textinvalidpassword_</font>}
+_messageemptypassword_ {<font color=red>_textemptypassword_</font>}
+_messageuserexists_ {<font color=red>_textuserexists_</font>}
+
+_messageusernameempty_ {<font color=red>_textusernameempty_</font>}
+_messagepasswordempty_ {<font color=red>_textpasswordempty_</font>}
+_messagenewpass1empty_ {<font color=red>_textnewpass1empty_</font>}
+_messagenewpass2empty_ {_messagenewpass1empty_}
+_messagenewpassmismatch_ {<font color=red>_textnewpassmismatch_</font>}
+_messagenewinvalidpassword_ {<font color=red>_textnewinvalidpassword_</font>}
+_messagefailed_ {<font color=red>_textfailed_</font>}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/vietnamese.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/vietnamese.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/vietnamese.dm	(revision 10506)
@@ -0,0 +1,1290 @@
+# this file must be UTF-8 encoded
+#####################################################################
+#
+# Vietnamese Language text and icon macros 
+# Many thanks to Integrated e-Solutions Ltd., Saigon (August 2004)
+#
+######################################################################
+
+
+######################################################################
+# Global (base) package
+package Global
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textperiodicals_ [l=vi] {Xuáº¥t báº£n Äá»nh kÃ¬}
+_textsource_ [l=vi] {nguá»n: }
+_textdate_ [l=vi] {ngÃ y xuáº¥t báº£n: }
+_textnumpages_ [l=vi] {sá» trang: }
+
+_textsignin_ [l=vi] {ÄÄng nháº­p}
+
+_textdefaultcontent_ [l=vi] {KhÃŽng tÃ¬m tháº¥y trang yÃªu cáº§u. Vui lÃ²ng sá»­ dá»¥ng nÃºt 'back' trÃªn trÃ¬nh duyá»t cá»§a báº¡n hoáº·c nÃºt Trang chá»§ phÃ­a trÃªn
+Äá» quay láº¡i Greenstone Digital Library.}
+
+_textdefaulttitle_ [l=vi] {Lá»i GSDL }
+
+_textbadcollection_ [l=vi] {Bá» sÆ°u táº­p nÃ y (cÃ³ tÃªn lÃ  "_cvariable_") khÃŽng ÄÆ°á»£c cÃ i Äáº·t trÃªn há» thá»ng thÆ° viá»n sá» Greenstone.}
+
+_textselectpage_ [l=vi] {-- Chá»n trang --}
+
+_collectionextra_ [l=vi] {Bá» sÆ°u táº­p nÃ y chá»©a _about:numdocs_ tÃ i liá»u. 
+NÃ³ ÄÆ°á»£c xÃ¢y dá»±ng láº§n cuá»i cÃ¡ch ÄÃ¢y _about:builddate_ ngÃ y.}
+
+# this is only used by the collector (where the above _collectionextra_
+# macro will always be set to another value)
+_collectorextra_ [l=vi] {<p>Bá» sÆ°u táº­p nÃ y chá»©a _numdocs_ _If_("_numdocs_" eq "1",tÃ i liá»u,tÃ i liá»u), tá»ng cá»ng _numbytes_.
+<p><a href="_httppagex_(bsummary)">Nháº¥n vÃ o ÄÃ¢y</a> Äá» xem tÃ³m táº¯t cÃ¡c thÃŽng tin trong quÃ¡ trÃ¬nh xÃ¢y dá»±ng bá» sÆ°u táº­p nÃ y.
+}
+
+_textimagecollection_ [l=vi] {}
+_textimageabout_ [l=vi] {Giá»i thiá»u}
+_textimagehome_ [l=vi] {Trang chá»§}
+_textimagehelp_ [l=vi] {GiÃºp Äá»¡}
+_textimagepref_ [l=vi] {Thuá»c tÃ­nh}
+_textimagegreenstone_ [l=vi] {Pháº§n má»m thÆ° viá»n sá» Greenstone}
+_textimageusab_ [l=vi] {Báº¡n cÃ³ khÃ³ khÄn trong quÃ¡ trÃ¬nh sá»­ dá»¥ng?}
+
+_textimagesearch_ [l=vi] {TÃ¬m kiáº¿m vá»i cÃ¡c Äiá»u kiá»n cá»¥ thá»}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textimageTitle_ [l=vi] {TrÃ¬nh duyá»t tÃªn cÃ¡c tÃ i liá»u theo thá»© tá»± chá»¯ cÃ¡i}
+_textimageCreator_ [l=vi] {TrÃ¬nh duyá»t danh sÃ¡ch tÃ¡c giáº£ theo thÆ° tá»± chá»¯ cÃ¡i}
+_textimageSubject_ [l=vi] {TrÃ¬nh duyá»t theo loáº¡i chá»§ Äá»}
+# -- Missing translation: _textimageDescription_
+# -- Missing translation: _textimagePublisher_
+# -- Missing translation: _textimageContributor_
+_textimageDate_ [l=vi] {TrÃ¬nh duyá»t theo ngÃ y phÃ¡t hÃ nh}
+# -- Missing translation: _textimageType_
+# -- Missing translation: _textimageFormat_
+# -- Missing translation: _textimageIdentifier_
+_textimageSource_ [l=vi] {TrÃ¬nh duyá»t theo tÃªn gá»c cá»§a táº­p tin}
+_textimageLanguage_ [l=vi] {TrÃ¬nh duyá»t theo ngÃŽn ngá»¯}
+# -- Missing translation: _textimageRelation_
+# -- Missing translation: _textimageCoverage_
+# -- Missing translation: _textimageRights_
+
+_textimageOrganization_ [l=vi] {TrÃ¬nh duyá»t theo tá» chá»©c xuáº¥t báº£n}
+_textimageKeyword_ [l=vi] {TrÃ¬nh duyá»t theo tá»« khÃ³a}
+_textimageHowto_ [l=vi] {TrÃ¬nh duyá»t dá»±a vÃ o phÃ¢n loáº¡i}
+_textimageList_ [l=vi] {TrÃ¬nh duyá»t danh sÃ¡ch tÃ i liá»u}
+_textimageSeries_ [l=vi] {TrÃ¬nh duyá»t theo ká»³ phÃ¡t hÃ nh}
+_textimageTo_ [l=vi] {TrÃ¬nh duyá»t theo trá»«Æ¡ng NÆ¡i chá»©a}
+_textimageFrom_ [l=vi] {TrÃ¬nh duyá»t theo trÆ°á»ng Nguá»n gá»c}
+_textimageTopic_ [l=vi] {TrÃ¬nh duyá»t dá»±a vÃ o chá»§ Äá» phÃ¡t hÃ nh cá»¥ thá»}
+_textimageBrowse_ [l=vi] {TrÃ¬nh duyá»t }
+_textimageCollage_ [l=vi] {TrÃ¬nh duyá»t theo nghá» thuáº­t táº¡o áº£nh}
+_textimagePeople_ [l=vi] {TrÃ¬nh duyá»t theo thá»© tá»± chá»¯ cÃ¡i tÃªn ngÆ°á»i}
+_textimageAcronym_ [l=vi] {TrÃ¬nh duyá»t theo tá»« viáº¿t táº¯t}
+_textimagePhrase_ [l=vi] {TrÃ¬nh duyá»t theo cá»¥m tá»«}
+_textimageArtist_ [l=vi] {TrÃ¬nh duyá»t theo tÃªn nghá» sá»}
+_textimageVolume_ [l=vi] {TrÃ¬nh duyá»t theo quyá»n}
+_textimageCountries_ [l=vi] {TrÃ¬nh duyá»t theo tÃªn quá»c gia}
+_textimageCaptions_ [l=vi] {TrÃ¬nh duyá»t theo chÃº thÃ­ch tranh áº£nh}
+
+
+_texticontabsearchgreen_ [l=vi] {TÃ¬m kiáº¿m}
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticontabTitlegreen_ [l=vi] {TiÃªu Äá»}
+_texticontabCreatorgreen_ [l=vi] {TÃ¡c giáº£}
+_texticontabSubjectgreen_ [l=vi] {Äá» má»¥c}
+# -- Missing translation: _texticontabDescriptiongreen_
+# -- Missing translation: _texticontabPublishergreen_
+# -- Missing translation: _texticontabContributorgreen_
+_texticontabDategreen_ [l=vi] {NgÃ y}
+# -- Missing translation: _texticontabTypesgreen_
+# -- Missing translation: _texticontabFormatgreen_
+# -- Missing translation: _texticontabIdentifiergreen_
+_texticontabSourcegreen_ [l=vi] {TÃªn táº­p tin}
+_texticontabLanguagegreen_ [l=vi] {NgÃŽn ngá»¯}
+# -- Missing translation: _texticontabRelationgreen_
+# -- Missing translation: _texticontabCoveragegreen_
+# -- Missing translation: _texticontabRightsgreen_
+
+_texticontaborggreen_ [l=vi] {Tá» chá»©c}
+_texticontabKeywordgreen_ [l=vi] {Tá»« khÃ³a}
+_texticontabhowgreen_ [l=vi] {Gá»£i Ãœ}
+_texticontabseriesgreen_ [l=vi] {NhÃ³m}
+_texticontablistgreen_ [l=vi] {Danh má»¥c}
+_texticontabtogreen_ [l=vi] {NÆ¡i chá»©a}
+_texticontabfromgreen_ [l=vi] {Nguá»n gá»c}
+_texticontabtopicgreen_ [l=vi] {Chá»§ Äá»}
+_texticontabbrwsegreen_ [l=vi] {TrÃ¬nh duyá»t}
+_texticontabCollagegreen_ [l=vi] {áº¢nh ghÃ©p}
+_texticontabbrowsgreen_ [l=vi] {TrÃ¬nh duyá»t }
+_texticontabPeoplegreen_ [l=vi] {TÃªn ngÆ°á»i}
+_texticontabAcronymgreen_ [l=vi] {Viáº¿t táº¯t}
+_texticontabPhrasegreen_ [l=vi] {Cá»¥m tá»«}
+_texticontabArtistgreen_ [l=vi] {Nghá» sÄ©}
+_texticontabVolumegreen_ [l=vi] {Quyá»n}
+_texticontabCaptionsgreen_ [l=vi] {Äáº§u Äá»}
+_texticontabCountriesgreen_ [l=vi] {Quá»c gia}
+
+_texticontext_ [l=vi] {Xem tÃ i liá»u}
+_texticonclosedbook_ [l=vi] {Má» tÃ i liá»u vÃ  xem ná»i dung}
+_texticonnext_ [l=vi] {Äáº¿n pháº§n káº¿ tiáº¿p}
+_texticonprev_ [l=vi] {quay láº¡i pháº§n trÆ°á»c}
+
+# -- Missing translation: _texticonworld_
+
+_texticonmidi_ [l=vi] {Xem tÃ i liá»u MIDI}
+_texticonmsword_ [l=vi] {Xem tÃ i liá»u Microsoft Word}
+# -- Missing translation: _texticonmp3_
+_texticonpdf_ [l=vi] {Xem tÃ i liá»u PDF}
+_texticonps_ [l=vi] {Xem tÃ i liá»u PostScript}
+_texticonppt_ [l=vi] {Xem tÃ i liá»u PowerPoint}
+_texticonrtf_ [l=vi] {Xem tÃ i liá»u RTF}
+_texticonxls_ [l=vi] {Xem tÃ i liá»u Microsoft Excel}
+
+_page_ [l=vi] {trang}
+_pages_ [l=vi] {trang}
+_of_ [l=vi] {cá»§a }
+_vol_ [l=vi] {Quyá»n.}
+_num_ [l=vi] {Sá».}
+
+_textmonth00_ [l=vi] {}
+_textmonth01_ [l=vi] {ThÃ¡ng má»t}
+_textmonth02_ [l=vi] {ThÃ¡ng hai}
+_textmonth03_ [l=vi] {ThÃ¡ng ba}
+_textmonth04_ [l=vi] {ThÃ¡ng tÆ°}
+_textmonth05_ [l=vi] {ThÃ¡ng nÄm}
+_textmonth06_ [l=vi] {ThÃ¡ng sÃ¡u}
+_textmonth07_ [l=vi] {ThÃ¡ng báº£y}
+_textmonth08_ [l=vi] {ThÃ¡ng tÃ¡m}
+_textmonth09_ [l=vi] {ThÃ¡ng chÃ­n}
+_textmonth10_ [l=vi] {ThÃ¡ng mÆ°á»i}
+_textmonth11_ [l=vi] {ThÃ¡ng mÆ°á»i má»t}
+_textmonth12_ [l=vi] {ThÃ¡ng mÆ°á»i hai}
+
+_textdocument_ [l=vi] {TÃ i liá»u}
+_textsection_ [l=vi] {Pháº§n}
+_textparagraph_ [l=vi] {Äoáº¡n vÄn báº£n}
+
+_magazines_ [l=vi] {Táº¡p trÃ­}
+
+_nzdlpagefooter_ [l=vi] {<p>_iconblankbar_
+<p><a href="http://www.nzdl.org">New Zealand Digital Library Project</a>
+<br><a href="http://www.cs.waikato.ac.nz/cs">Department of Computer Science</a>, 
+<a href="http://www.waikato.ac.nz">University of Waikato</a>, 
+New Zealand}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Trang chá»§" ## top_nav_button ## chome ##
+_httpiconchomeof_ [l=vi] {_httpimg_/vi/chomeof.gif}
+_httpiconchomeon_ [l=vi] {_httpimg_/vi/chomeon.gif}
+
+## "GiÃºp Äá»¡" ## top_nav_button ## chelp ##
+_httpiconchelpof_ [l=vi] {_httpimg_/vi/chelpof.gif}
+_httpiconchelpon_ [l=vi] {_httpimg_/vi/chelpon.gif}
+
+## "Thuá»c tÃ­nh" ## top_nav_button ## cpref ##
+_httpiconcprefof_ [l=vi] {_httpimg_/vi/cprefof.gif}
+_httpiconcprefon_ [l=vi] {_httpimg_/vi/cprefon.gif}
+
+## "Pháº£n há»i" ## top_nav_button ## cusab ##
+_httpiconcusabof_ [l=vi] {_httpimg_/vi/cusabof.gif}
+_httpiconcusabon_ [l=vi] {_httpimg_/vi/cusabon.gif}
+
+
+## "tÃ¬m kiáº¿m" ## nav_bar_button ## tsrch ##
+_httpicontsrchgr_ [l=vi] {_httpimg_/vi/tsrchgr.gif}
+_httpicontsrchof_ [l=vi] {_httpimg_/vi/tsrchof.gif}
+_httpicontsrchon_ [l=vi] {_httpimg_/vi/tsrchon.gif}
+_widthtsrchx_ [l=vi] {87}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tiÃªu Äá»" ## nav_bar_button ## ttitl ##
+_httpiconttitlegr_ [l=vi] {_httpimg_/vi/ttitlgr.gif}
+_httpiconttitleof_ [l=vi] {_httpimg_/vi/ttitlof.gif}
+_httpiconttitleon_ [l=vi] {_httpimg_/vi/ttitlon.gif}
+_widthttitlex_ [l=vi] {87}
+
+# Not true DC, kept for legacy reasons
+## "tÃ¡c giáº£" ## nav_bar_button ## tauth ##
+_httpicontcreatgr_ [l=vi] {_httpimg_/vi/tauthgr.gif}
+_httpicontcreatof_ [l=vi] {_httpimg_/vi/tauthof.gif}
+_httpicontcreaton_ [l=vi] {_httpimg_/vi/tauthon.gif}
+_widthtcreatx_ [l=vi] {110}
+
+## "Äá» má»¥c" ## nav_bar_button ## tsubj ##
+_httpicontsubjgr_ [l=vi] {_httpimg_/vi/tsubjgr.gif}
+_httpicontsubjon_ [l=vi] {_httpimg_/vi/tsubjon.gif}
+_httpicontsubjof_ [l=vi] {_httpimg_/vi/tsubjof.gif}
+_widthtsubjx_ [l=vi] {87}
+
+# -- Missing translation: tdesc
+# -- Missing translation: _httpicontdescgr_
+# -- Missing translation: _httpicontdescon_
+# -- Missing translation: _httpicontdescof_
+# -- Missing translation: _widthtdescx_
+
+# -- Missing translation: tpubl
+# -- Missing translation: _httpicontpublgr_
+# -- Missing translation: _httpicontpublon_
+# -- Missing translation: _httpicontpublof_
+# -- Missing translation: _widthtpublx_
+
+# -- Missing translation: tcontr
+# -- Missing translation: _httpicontcontrgr_
+# -- Missing translation: _httpicontcontron_
+# -- Missing translation: _httpicontcontrof_
+# -- Missing translation: _widthtcontrx_
+
+## "ngÃ y" ## nav_bar_button ## tdate ##
+_httpicontdategr_ [l=vi] {_httpimg_/vi/tdategr.gif}
+_httpicontdateof_ [l=vi] {_httpimg_/vi/tdateof.gif}
+_httpicontdateon_ [l=vi] {_httpimg_/vi/tdateon.gif}
+_widthtdatex_ [l=vi] {87}
+
+# -- Missing translation: ttype
+# -- Missing translation: _httpiconttypegr_
+# -- Missing translation: _httpiconttypeof_
+# -- Missing translation: _httpiconttypeon_
+# -- Missing translation: _widthttypex_
+
+# -- Missing translation: tform
+# -- Missing translation: _httpicontformgr_
+# -- Missing translation: _httpicontformof_
+# -- Missing translation: _httpicontformon_
+# -- Missing translation: _widthtformx_
+
+# -- Missing translation: tident
+# -- Missing translation: _httpicontidentgr_
+# -- Missing translation: _httpicontidentof_
+# -- Missing translation: _httpicontidenton_
+# -- Missing translation: _widthtidentx_
+
+# Not true DC, kept for legacy reasons
+## "tÃªn táº­p tin" ## nav_bar_button ## tsrc ##
+_httpicontsrcgr_ [l=vi] {_httpimg_/vi/tsrcgr.gif}
+_httpicontsrcof_ [l=vi] {_httpimg_/vi/tsrcof.gif}
+_httpicontsrcon_ [l=vi] {_httpimg_/vi/tsrcon.gif}
+_widthtsrcx_ [l=vi] {87}
+
+## "ngÃŽn ngá»¯" ## nav_bar_button ## tlang ##
+_httpicontlanggr_ [l=vi] {_httpimg_/vi/tlanggr.gif}
+_httpicontlangon_ [l=vi] {_httpimg_/vi/tlangon.gif}
+_httpicontlangof_ [l=vi] {_httpimg_/vi/tlangof.gif}
+_widthtlangx_ [l=vi] {87}
+
+# -- Missing translation: trel
+# -- Missing translation: _httpicontrelgr_
+# -- Missing translation: _httpicontrelon_
+# -- Missing translation: _httpicontrelof_
+# -- Missing translation: _widthtrelx_
+
+# -- Missing translation: tcover
+# -- Missing translation: _httpicontcovergr_
+# -- Missing translation: _httpicontcoveron_
+# -- Missing translation: _httpicontcoverof_
+# -- Missing translation: _widthtcoverx_
+
+# -- Missing translation: tright
+# -- Missing translation: _httpicontrightgr_
+# -- Missing translation: _httpicontrighton_
+# -- Missing translation: _httpicontrightof_
+# -- Missing translation: _widthtrightx_
+
+
+
+## "nhÃ³m" ## nav_bar_button ## tser ##
+_httpicontsergr_ [l=vi] {_httpimg_/vi/tsergr.gif}
+_httpicontserof_ [l=vi] {_httpimg_/vi/tserof.gif}
+_httpicontseron_ [l=vi] {_httpimg_/vi/tseron.gif}
+_widthtserx_ [l=vi] {87}
+
+## "nÆ¡i chá»©a" ## nav_bar_button ## tto ##
+_httpiconttogr_ [l=vi] {_httpimg_/vi/ttogr.gif}
+_httpiconttoon_ [l=vi] {_httpimg_/vi/ttoon.gif}
+_httpiconttoof_ [l=vi] {_httpimg_/vi/ttoof.gif}
+_widthttox_ [l=vi] {87}
+
+## "nguá»n gá»c" ## nav_bar_button ## tfrom ##
+_httpicontfromgr_ [l=vi] {_httpimg_/vi/tfromgr.gif}
+_httpicontfromon_ [l=vi] {_httpimg_/vi/tfromon.gif}
+_httpicontfromof_ [l=vi] {_httpimg_/vi/tfromof.gif}
+_widthtfromx_ [l=vi] {87}
+
+## "tá» chá»©c" ## nav_bar_button ## torg ##
+_httpicontorggr_ [l=vi] {_httpimg_/vi/torggr.gif}
+_httpicontorgon_ [l=vi] {_httpimg_/vi/torgon.gif}
+_httpicontorgof_ [l=vi] {_httpimg_/vi/torgof.gif}
+_widthtorgx_ [l=vi] {114}
+
+## "gá»£i Ãœ" ## nav_bar_button ## thow ##
+_httpiconthowgr_ [l=vi] {_httpimg_/vi/thowgr.gif}
+_httpiconthowon_ [l=vi] {_httpimg_/vi/thowon.gif}
+_httpiconthowof_ [l=vi] {_httpimg_/vi/thowof.gif}
+_widththowx_ [l=vi] {87}
+
+## "chá»§ Äá»" ## nav_bar_button ## ttopic ##
+_httpiconttopicgr_ [l=vi] {_httpimg_/vi/ttopicgr.gif}
+_httpiconttopicon_ [l=vi] {_httpimg_/vi/ttopicon.gif}
+_httpiconttopicof_ [l=vi] {_httpimg_/vi/ttopicof.gif}
+_widthttopicx_ [l=vi] {87}
+
+## "duyá»t" ## nav_bar_button ## tbrwse ##
+_httpicontbrwsegr_ [l=vi] {_httpimg_/vi/tbrwsegr.gif}
+_httpicontbrwseon_ [l=vi] {_httpimg_/vi/tbrwseon.gif}
+_httpicontbrwseof_ [l=vi] {_httpimg_/vi/tbrwseof.gif}
+_widthtbrwsex_ [l=vi] {87}
+
+## "áº£nh ghÃ©p" ## nav_bar_button ## tcoll ##
+_httpicontcollgr_ [l=vi] {_httpimg_/vi/tcollgr.gif}
+_httpicontcollof_ [l=vi] {_httpimg_/vi/tcollof.gif}
+_httpicontcollon_ [l=vi] {_httpimg_/vi/tcollon.gif}
+_widthtcollx_ [l=vi] {87}
+
+## "ngÆ°á»i" ## nav_bar_button ## tpeop ##
+_httpicontpeopgr_ [l=vi] {_httpimg_/vi/tpeopgr.gif}
+_httpicontpeopof_ [l=vi] {_httpimg_/vi/tpeopof.gif}
+_httpicontpeopon_ [l=vi] {_httpimg_/vi/tpeopon.gif}
+_widthtpeopx_ [l=vi] {97}
+
+## "chá»¯ viáº¿t táº¯t" ## nav_bar_button ## tacro ##
+_httpicontacrogr_ [l=vi] {_httpimg_/vi/tacrogr.gif}
+_httpicontacroof_ [l=vi] {_httpimg_/vi/tacroof.gif}
+_httpicontacroon_ [l=vi] {_httpimg_/vi/tacroon.gif}
+_widthtacrox_ [l=vi] {87}
+
+## "cá»¥m tá»«" ## nav_bar_button ## tphrse ##
+_httpicontphrsegr_ [l=vi] {_httpimg_/vi/tphrsegr.gif}
+_httpicontphrseof_ [l=vi] {_httpimg_/vi/tphrseof.gif}
+_httpicontphrseon_ [l=vi] {_httpimg_/vi/tphrseon.gif}
+_widthtphrsex_ [l=vi] {87}
+
+## "nghá» sÄ©" ## nav_bar_button ## tartst ##
+_httpicontartstgr_ [l=vi] {_httpimg_/vi/tartstgr.gif}
+_httpicontartstof_ [l=vi] {_httpimg_/vi/tartstof.gif}
+_httpicontartston_ [l=vi] {_httpimg_/vi/tartston.gif}
+_widthtartstx_ [l=vi] {87}
+
+## "tá»« khoÃ¡" ## nav_bar_button ## tkw ##
+_httpicontkwgr_ [l=vi] {_httpimg_/vi/tkwgr.gif}
+_httpicontkwof_ [l=vi] {_httpimg_/vi/tkwof.gif}
+_httpicontkwon_ [l=vi] {_httpimg_/vi/tkwon.gif}
+_widthtkwx_ [l=vi] {87}
+
+## "quyá»n" ## nav_bar_button ## tvol ##
+_httpicontvolgr_ [l=vi] {_httpimg_/vi/tvolgr.gif}
+_httpicontvolof_ [l=vi] {_httpimg_/vi/tvolof.gif}
+_httpicontvolon_ [l=vi] {_httpimg_/vi/tvolon.gif}
+_widthtvolx_ [l=vi] {87}
+
+## "Äáº§u Äá»" ## nav_bar_button ## tcapt ##
+_httpicontcaptgr_ [l=vi] {_httpimg_/vi/tcaptgr.gif}
+_httpicontcaptof_ [l=vi] {_httpimg_/vi/tcaptof.gif}
+_httpicontcapton_ [l=vi] {_httpimg_/vi/tcapton.gif}
+_widthtcaptx_ [l=vi] {87}
+
+## "quá»c gia" ## nav_bar_button ## tcount ##
+_httpicontcountgr_ [l=vi] {_httpimg_/vi/tcountgr.gif}
+_httpicontcountof_ [l=vi] {_httpimg_/vi/tcountof.gif}
+_httpicontcounton_ [l=vi] {_httpimg_/vi/tcounton.gif}
+_widthtcountx_ [l=vi] {87}
+
+## "giÃºp Äá»¡" ## green_title ## h_help ##
+_httpiconhhelp_ [l=vi] {_httpimg_/vi/h\_help.gif}
+_widthhhelp_ [l=vi] {200}
+_heighthhelp_ [l=vi] {57}
+
+
+
+
+######################################################################
+# 'about' page
+package about
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textabcol_ [l=vi] {Giá»i thiá»u vá» bá» sÆ°u táº­p}
+
+_textsubcols1_ [l=vi] {<p>Bá» sÆ°u táº­p hoÃ n chá»nh bao gá»m _1_ bá» sÆ°u táº­p con. 
+Nhá»¯ng bá» sÆ°u táº­p Äáºµ hoÃ n chá»nh lÃ : <blockquote>}
+
+_textsubcols2_ [l=vi] {</blockquote>
+Báº¡n cÃ³ thá» kiá»m tra (vÃ  thay tháº¿) nhá»¯ng bá» sÆ°u táº­p con mÃ  báº¡n sá»­ dá»¥ng trÃªn trang Thuá»c tÃ­nh.}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "giá»i thiá»u" ## green_title ## h_about ##
+_httpiconhabout_ [l=vi] {_httpimg_/vi/h\_about.gif}
+_widthhabout_ [l=vi] {200}
+_heighthabout_ [l=vi] {57}
+
+
+
+######################################################################
+# document package
+package document
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+_texticonhtitle_ [l=vi] {TiÃªu Äá»}
+_texticonhcreat_ [l=vi] {TÃ¡c giáº£}
+_texticonhsubj_ [l=vi] {Äá» má»¥c}
+# -- Missing translation: _texticonhdesc_
+# -- Missing translation: _texticonhpubl_
+# -- Missing translation: _texticonhcontr_
+_texticonhdate_ [l=vi] {NgÃ y}
+# -- Missing translation: _texticonhtype_
+# -- Missing translation: _texticonhform_
+# -- Missing translation: _texticonhident_
+_texticonhsrc_ [l=vi] {TÃªn táº­p tin}
+_texticonhlang_ [l=vi] {NgÃŽn ngá»¯}
+# -- Missing translation: _texticonhrel_
+# -- Missing translation: _texticonhcover_
+# -- Missing translation: _texticonhright_
+
+_texticonhcoll_ [l=vi] {áº¢nh ghÃ©p}
+_texticonhto_ [l=vi] {NÆ¡i chá»©a}
+_texticonhfrom_ [l=vi] {Nguá»n gá»c}
+_texticonhser_ [l=vi] {NhÃ³m}
+_texticonhhow_ [l=vi] {Gá»£i Ãœ}
+_texticonhorg_ [l=vi] {Tá» chá»©c}
+_texticonhbrwse_ [l=vi] {TrÃ¬nh duyá»t }
+_texticonhbrows_ [l=vi] {TrÃ¬nh duyá»t }
+_texticonhpeople_ [l=vi] {TÃªn ngÆ°á»i}
+_texticonhacronym_ [l=vi] {Tá»« viáº¿t táº¯t}
+_texticonhphrases_ [l=vi] {Cá»¥m tá»«}
+_texticonhartist_ [l=vi] {Nghá» sÄ©}
+_texticonhkw_ [l=vi] {Tá»« khÃ³a}
+_texticonhvol_ [l=vi] {Quyá»n}
+_texticonhcapt_ [l=vi] {Äáº§u Äá»}
+_texticonhcount_ [l=vi] {Quá»c gia}
+
+_texticonopenbookshelf_ [l=vi] {ÄÃ³ng pháº§n nÃ y cá»§a thÆ° viá»n}
+_texticonclosedbookshelf_ [l=vi] {má» pháº§n nÃ y cá»§a thÆ° viá»n vÃ  xem ná»i dung}
+_texticonopenbook_ [l=vi] {ÄÃ³ng cuá»n sÃ¡ch nÃ y}
+_texticonclosedfolder_ [l=vi] {Má» thÆ° má»¥c nÃ y vÃ  xem ná»i dung}
+_texticonclosedfolder2_ [l=vi] {má» thÆ° má»¥c con: }
+_texticonopenfolder_ [l=vi] {ÄÃ³ng thÆ° má»¥c nÃ y}
+_texticonopenfolder2_ [l=vi] {ÄÃ³ng thÆ° má»¥c con: }
+_texticonsmalltext_ [l=vi] {Xem pháº§n nÃ y cá»§a vÄn báº£n}
+_texticonsmalltext2_ [l=vi] {xem ná»i dung: }
+_texticonpointer_ [l=vi] {pháº§n hiá»n táº¡i}
+_texticondetach_ [l=vi] {Má» trang nÃ y trong má»t cá»­a sá» má»i}
+_texticonhighlight_ [l=vi] {TÃŽ mÃ u tá»« khÃ³a}
+_texticonnohighlight_ [l=vi] {KhÃŽng tÃŽ mÃ u tá»« khÃ³a }
+_texticoncontracttoc_ [l=vi] {Thu nhá» báº£ng má»¥c lá»¥c}
+_texticonexpandtoc_ [l=vi] {Má» rá»ng báº£ng má»¥c lá»¥c}
+_texticonexpandtext_ [l=vi] {Hiá»n thá» toÃ n bá» ná»i dung}
+_texticoncontracttext_ [l=vi] {Chá» hiá»n thá» ná»i dung cho pháº§n ÄÆ°á»£c chá»n}
+_texticonwarning_ [l=vi] {<b>Cáº£nh bÃ¡o: </b>}
+_texticoncont_ [l=vi] {tiáº¿p tá»¥c?}
+
+_textltwarning_ [l=vi] {<p><center>
+<table cellspacing=0 cellpadding=0 width=_pagewidth_>
+<tr valign=top><td>_iconwarning_Expanding vÄn báº£n á» ÄÃ¢y sáºœ phÃ¡t sinh má»t lÆ°á»£ng dá»¯ liá»u so vá»i kháº£ nÄng hiá»n thá» cá»§a trÃ¬nh duyá»t _imagecont_
+</td></tr></table></center>
+}
+
+_textgoto_ [l=vi] {Äi Äáº¿n trang}
+_textintro_ [l=vi] {<i>(vÄn báº£n giá»i thiá»u)</i>}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+# Not true DC, kept for legacy reasons
+## "tiÃªu Äá»" ## green_title ## h_title ##
+_httpiconhtitle_ [l=vi] {_httpimg_/vi/h\_title.gif}
+_widthhtitle_ [l=vi] {200}
+_heighthtitle_ [l=vi] {57}
+
+# Not true DC, kept for legacy reasons
+## "tÃ¡c giáº£" ## green_title ## h_auth ##
+_httpiconhcreat_ [l=vi] {_httpimg_/vi/h\_auth.gif}
+_widthhcreat_ [l=vi] {200}
+_heighthcreat_ [l=vi] {57}
+
+## "Äá» má»¥c" ## green_title ## h_subj ##
+_httpiconhsubj_ [l=vi] {_httpimg_/vi/h\_subj.gif}
+_widthhsubj_ [l=vi] {200}
+_heighthsubj_ [l=vi] {57}
+
+# -- Missing translation: h_desc
+# -- Missing translation: _httpiconhdesc_
+# -- Missing translation: _widthhdesc_
+# -- Missing translation: _heighthdesc_
+
+# -- Missing translation: h_publ
+# -- Missing translation: _httpiconhpubl_
+# -- Missing translation: _widthhpubl_
+# -- Missing translation: _heighthpubl_
+
+# -- Missing translation: h_contr
+# -- Missing translation: _httpiconhcontr_
+# -- Missing translation: _widthhcontr_
+# -- Missing translation: _heighthcontr_
+
+## "ngÃ y" ## green_title ## h_date ##
+_httpiconhdate_ [l=vi] {_httpimg_/vi/h\_date.gif}
+_widthhdate_ [l=vi] {200}
+_heighthdate_ [l=vi] {57}
+
+# -- Missing translation: h_type
+# -- Missing translation: _httpiconhtype_
+# -- Missing translation: _widthhtype_
+# -- Missing translation: _heighthtype_
+
+# -- Missing translation: h_form
+# -- Missing translation: _httpiconhform_
+# -- Missing translation: _widthhform_
+# -- Missing translation: _heighthform_
+
+# -- Missing translation: h_ident
+# -- Missing translation: _httpiconhident_
+# -- Missing translation: _widthhident_
+# -- Missing translation: _heighthident_
+
+# Not true DC, kept for legacy reasons
+## "tÃªn táº­p tin" ## green_title ## h_src ##
+_httpiconhsrc_ [l=vi] {_httpimg_/vi/h\_src.gif}
+_widthhsrc_ [l=vi] {200}
+_heighthsrc_ [l=vi] {57}
+
+## "ngÃŽn ngá»¯" ## green_title ## h_lang ##
+_httpiconhlang_ [l=vi] {_httpimg_/vi/h\_lang.gif}
+_widthhlang_ [l=vi] {200}
+_heighthlang_ [l=vi] {57}
+
+# -- Missing translation: h_rel
+# -- Missing translation: _httpiconhrel_
+# -- Missing translation: _widthhrel_
+# -- Missing translation: _heighthrel_
+
+# -- Missing translation: h_cover
+# -- Missing translation: _httpiconhcover_
+# -- Missing translation: _widthhcover_
+# -- Missing translation: _heighthcover_
+
+# -- Missing translation: h_right
+# -- Missing translation: _httpiconhright_
+# -- Missing translation: _widthhright_
+# -- Missing translation: _heighthright_
+
+
+
+## "nÆ¡i chá»©a" ## green_title ## h_to ##
+_httpiconhto_ [l=vi] {_httpimg_/vi/h\_to.gif}
+_widthhto_ [l=vi] {200}
+_heighthto_ [l=vi] {57}
+
+## "nguá»n gá»c" ## green_title ## h_from ##
+_httpiconhfrom_ [l=vi] {_httpimg_/vi/h\_from.gif}
+_widthhfrom_ [l=vi] {200}
+_heighthfrom_ [l=vi] {57}
+
+## "nhÃ³m" ## green_title ## h_ser ##
+_httpiconhser_ [l=vi] {_httpimg_/vi/h\_ser.gif}
+_widthhser_ [l=vi] {200}
+_heighthser_ [l=vi] {57}
+
+## "gá»£i Ãœ" ## green_title ## h_how ##
+_httpiconhhow_ [l=vi] {_httpimg_/vi/h\_how.gif}
+_widthhhow_ [l=vi] {200}
+_heighthhow_ [l=vi] {57}
+
+## "chá»§ Äá»" ## green_title ## h_topic ##
+_httpiconhtopic_ [l=vi] {_httpimg_/vi/h\_topic.gif}
+_widthhtopic_ [l=vi] {200}
+_heighthtopic_ [l=vi] {57}
+
+## "tá» chá»©c" ## green_title ## h_org ##
+_httpiconhorg_ [l=vi] {_httpimg_/vi/h\_org.gif}
+_widthhorg_ [l=vi] {250}
+_heighthorg_ [l=vi] {57}
+
+## "trÃ¬nh duyá»t" ## green_title ## h_brwse ##
+_httpiconhbrwse_ [l=vi] {_httpimg_/vi/h\_brwse.gif}
+_widthhbrwse_ [l=vi] {200}
+_heighthbrwse_ [l=vi] {57}
+
+# -- Missing translation: h_coll
+_httpiconhcoll_ [l=vi] {_httpimg_/vi/h\_coll.gif}
+_widthhcoll_ [l=vi] {200}
+_heighthcoll_ [l=vi] {57}
+
+## "tÃªn ngÆ°á»i" ## green_title ## h_people ##
+_httpiconhpeople_ [l=vi] {_httpimg_/vi/h\_people.gif}
+_widthhpeople_ [l=vi] {200}
+_heighthpeople_ [l=vi] {57}
+
+## "chá»¯ viáº¿t táº¯t" ## green_title ## h_acro ##
+_httpiconhacronym_ [l=vi] {_httpimg_/vi/h\_acro.gif}
+_widthhacronym_ [l=vi] {200}
+_heighthacronym_ [l=vi] {57}
+
+## "cá»¥m tá»«" ## green_title ## h_phrse ##
+_httpiconhphrse_ [l=vi] {_httpimg_/vi/h\_phrse.gif}
+_widthhphrse_ [l=vi] {200}
+_heighthphrse_ [l=vi] {57}
+
+## "nghá» sÄ©" ## green_title ## h_artist ##
+_httpiconhartist_ [l=vi] {_httpimg_/vi/h\_artist.gif}
+_widthhartist_ [l=vi] {200}
+_heighthartist_ [l=vi] {57}
+
+## "tá»« khoÃ¡" ## green_title ## h_kw ##
+_httpiconhkw_ [l=vi] {_httpimg_/vi/h\_kw.gif}
+_widthhkw_ [l=vi] {200}
+_heighthkw_ [l=vi] {57}
+
+## "quyá»n" ## green_title ## h_vol ##
+_httpiconhvol_ [l=vi] {_httpimg_/vi/h\_vol.gif}
+_widthhvol_ [l=vi] {200}
+_heighthvol_ [l=vi] {57}
+
+## "quá»c gia" ## green_title ## h_count ##
+_httpiconhcount_ [l=vi] {_httpimg_/vi/h\_count.gif}
+_widthhcount_ [l=vi] {200}
+_heighthcount_ [l=vi] {57}
+
+## "Äáº§u Äá»" ## green_title ## h_capt ##
+_httpiconhcapt_ [l=vi] {_httpimg_/vi/h\_capt.gif}
+_widthhcapt_ [l=vi] {200}
+_heighthcapt_ [l=vi] {57}
+
+
+## "Tiáº¿p tá»¥c??" ## top_nav_button ## cont ##
+_httpiconcontoff_ [l=vi] {_httpimg_/vi/contof.gif}
+_httpiconconton_ [l=vi] {_httpimg_/vi/conton.gif}
+
+## "Má»\nvÄn báº£n" ## document_button ## eallt ##
+_httpiconealltof_ [l=vi] {_httpimg_/vi/ealltof.gif}
+_httpiconeallton_ [l=vi] {_httpimg_/vi/eallton.gif}
+
+## "LiÃªn há»\nná»i dung" ## document_button ## econc ##
+_httpiconeconcof_ [l=vi] {_httpimg_/vi/econcof.gif}
+_httpiconeconcon_ [l=vi] {_httpimg_/vi/econcon.gif}
+
+## "Má» cá»­a\nsá» má»i" ## document_button ## edtch ##
+_httpiconedtchof_ [l=vi] {_httpimg_/vi/edtchof.gif}
+_httpiconedtchon_ [l=vi] {_httpimg_/vi/edtchon.gif}
+
+## "Má»\nná»i dung" ## document_button ## eexpc ##
+_httpiconeexpcof_ [l=vi] {_httpimg_/vi/eexpcof.gif}
+_httpiconeexpcon_ [l=vi] {_httpimg_/vi/eexpcon.gif}
+
+## "LiÃªn há»\ntÃ i liá»u" ## document_button ## etsec ##
+_httpiconetsecof_ [l=vi] {_httpimg_/vi/etsecof.gif}
+_httpiconetsecon_ [l=vi] {_httpimg_/vi/etsecon.gif}
+
+## "TÃŽ mÃ u" ## document_button ## ehl ##
+_httpiconehlof_ [l=vi] {_httpimg_/vi/ehlof.gif}
+_httpiconehlon_ [l=vi] {_httpimg_/vi/ehlon.gif}
+
+## "KhÃŽng\ntÃŽ mÃ u" ## document_button ## enhl ##
+_httpiconenhlof_ [l=vi] {_httpimg_/vi/enhlof.gif}
+_httpiconenhlon_ [l=vi] {_httpimg_/vi/enhlon.gif}
+
+
+######################################################################
+# 'search' page
+package query
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+# this if statement produces the text 'results n1 - nn for query: querystring' or 
+# 'No matches for query: querystring', depending on whether or not there were
+# any matches
+_textquerytitle_ [l=vi] {_If_(_thislast_,káº¿t quáº£ _thisfirst_ - _thislast_ cho cÃ¢u truy váº¥n: _cgiargq_,KhÃŽng cÃ³ káº¿t quáº£ khá»p vá»i cÃ¢u truy váº¥n: _cgiargq_)}
+_textnoquerytitle_ [l=vi] {Trang tÃ¬m kiáº¿m}
+
+_texticonthispage_ [l=vi] {tÃ¬m kiáº¿m}
+_textsome_ [l=vi] {má»t sá»}
+_textall_ [l=vi] {táº¥t cáº£ cÃ¡c}
+_textboolean_ [l=vi] {chÃ¢n trá»}
+_textranked_ [l=vi] {ÄÆ°á»£c xáº¿p háº¡ng thá»©}
+_textnatural_ [l=vi] {tá»± nhiÃªn}
+#_textsome_ {_If_(_cgiargb_,ranked,some)}
+#_textall_ {_If_(_cgiargb_,boolean,all)}
+#_textformsome_ {_If_(_cgiargb_,ranked,some)}
+#_textformall_ {_If_(_cgiargb_,natural,all)}
+_texticonqueryresultsbar_ [l=vi] {}
+_texticonsearchhistorybar_ [l=vi] {tÃ¬m kiáº¿m trÆ°á»c ÄÃ³}
+
+_textifeellucky_ [l=vi] {TÃŽi tháº­t may máº¯n}
+
+#alt text for query buttons
+_textusequery_ [l=vi] {sá»­ dá»¥ng cÃ¢u truy váº¥n nÃ y}
+_textfreqmsg1_ [l=vi] {Sá» tá»« xuáº¥t hiá»n: }
+_textpostprocess_ [l=vi] {_If_(_quotedquery_,<br><i>ÄÆ°á»£c xá»­ lÃ­ sau Äá» tÃ¬m _quotedquery_</i>
+)}
+_textinvalidquery_ [l=vi] {CÃ¢u truy váº¥n khÃŽng ÄÃºng cÃº phÃ¡p}
+
+_textmorethan_ [l=vi] {Nhiá»u hÆ¡n }
+_textapprox_ [l=vi] {Giá»i thiá»u }
+_textnodocs_ [l=vi] {KhÃŽng cÃ³ tÃ i liá»u nÃ o khá»p vá»i cÃ¢u truy váº¥n.}
+_text1doc_ [l=vi] {1 tÃ i liá»u khá»p vá»i cÃ¢u truy váº¥n.}
+_textlotsdocs_ [l=vi] {tÃ i liá»u khá»p vá»i cÃ¢u truy váº¥n.}
+_textmatches_ [l=vi] {Khá»p }
+_textbeginsearch_ [l=vi] {Báº¯t Äáº§u tÃ¬m kiáº¿m}
+_textrunquery_ [l=vi] {Cháº¡y cÃ¢u truy váº¥n}
+_textclearform_ [l=vi] {XoÃ¡ ÃŽ nháº­p}
+
+#these go together in form search:
+#"Word or phrase  (fold, stem)  ... in field"
+_textwordphrase_ [l=vi] {Tá»« hoáº·c cá»¥m tá»«}
+_textinfield_ [l=vi] {... trong trÆ°á»ng}
+_textfoldstem_ [l=vi] {(fold, stem)}
+
+_textadvquery_ [l=vi] {Hoáº·c nháº­p trá»±c tiáº¿p cÃ¢u truy váº¥n:}
+_textallfields_ [l=vi] {táº¥t cáº£ cÃ¡c trÆ°á»ng}
+_texttextonly_ [l=vi] {chá» gá»m ná»i dung vÄn báº£n}
+_textand_ [l=vi] {vÃ }
+_textor_ [l=vi] {hoáº·c}
+_textandnot_ [l=vi] {vÃ  khÃŽng}
+
+# _indexselection_, _jselection_, _nselection_ and _gselection_ are set from 
+# within the server - _indexselection_ is always set, but the others may be 
+# unset
+
+_textsimplesearch_ [l=vi] {TÃ¬m kiáº¿m _If_(_hselection_, _hselection_) _If_(_jselection_, _textjselect_) _If_(_gselection_, at _gselection_ level) _If_(_nselection_, in _nselection_ language)
+cÃ³ chá»©a _querytypeselection_ tá»«}
+
+_textadvancedsearch_ [l=vi] {TÃ¬m kiáº¿m _If_(_hselection_, _hselection_, _defaultindextext_) _If_(_jselection_,_textjselect_) _If_(_gselection_, at _gselection_ level)_If_(_nselection_, in _nselection_ language) 
+sá»­ dá»¥ng loáº¡i truy váº¥n _querytypeselection_}
+
+_textformsimplesearch_ [l=vi] {TÃ¬m kiáº¿m _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )sá»­ dá»¥ng máº«u truy váº¥n _formquerytypeselection_}
+
+_textformadvancedsearch_ [l=vi] {TÃ¬m kiáº¿m _If_(_jselection_,_jselection_ )_If_(_gformselection_,at _gformselection_ level )_If_(_nselection_,in _nselection_ language )vÃ  hiá»n thá» káº¿t quáº£ theo máº«u _formquerytypeselection_}
+
+
+_textnojsformwarning_ [l=vi] {Cáº£nh bÃ¡o: Javascript bá» táº¯t hoáº¡t Äá»ng trÃªn trÃ¬nh duyá»t cá»§a báº¡n. <br>Äá» sá»­ dá»¥ng máº«u tÃ¬m kiáº¿m, vui lÃ²ng báº­t láº¡i nÃ³.}
+_textdatesearch_ [l=vi] {Bá» sÆ°u táº­p nÃ y cÃ³ thá» tÃ¬m kiáº¿m cÃ¡c tÃ i liá»u theo má»t pháº¡m vi ngÃ y hoáº·c cÃ¡c tÃ i liá»u mÃ  chá»©a má»t ngÃ y cá»¥ thá». ÄÃ¢y lÃ  má»t tÃ¹y chá»n cá»§a tÃ¬m kiáº¿m.}
+_textstartdate_ [l=vi] {NgÃ y báº¯t Äáº§u:}
+_textenddate_ [l=vi] {NgÃ y káº¿t thÃºc:}
+_textbc_ [l=vi] {B.C.E.}
+_textad_ [l=vi] {C.E.}
+_textexplaineras_ [l=vi] {C.E. vÃ  B.C.E tÆ°Æ¡ng ÄÆ°Æ¡ng vá»i A.D. vÃ  B.C.  Nhá»¯ng tá»« nÃ y thay tháº¿ cho "CÃŽng nguyÃªn" vÃ  "TrÆ°á»c cÃŽng nguyÃªn"}
+
+_textstemon_ [l=vi] {(bá» qua pháº§n háº­u tá» cá»§a tá»«)}
+
+_textsearchhistory_ [l=vi] {TÃ¬m kiáº¿m trÆ°á»c ÄÃ³}
+
+#text macros for search history
+_textnohistory_ [l=vi] {TÃ¬m kiáº¿m trÆ°á»c ÄÃ³ khÃŽng tá»n táº¡i}
+_texthresult_ [l=vi] {káº¿t quáº£}
+_texthresults_ [l=vi] {cÃ¡c káº¿t quáº£}
+_texthallwords_ [l=vi] {táº¥t cáº£ cÃ¡c tá»«}
+_texthsomewords_ [l=vi] {má»t sá» tá»«}
+_texthboolean_ [l=vi] {chÃ¢n trá»}
+_texthranked_ [l=vi] {Äá»±Æ¡c xáº¿p thá»©}
+_texthcaseon_ [l=vi] {phÃ¢n biá»t chá»¯ hoa, chá»¯ thÆ°á»ng}
+_texthcaseoff_ [l=vi] {casefolded}
+_texthstemon_ [l=vi] {stemmed}
+_texthstemoff_ [l=vi] {unstemmed}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "tÃ¬m kiáº¿m" ## green_title ## h_search ##
+_httpiconhsearch_ [l=vi] {_httpimg_/vi/h\_search.gif}
+_widthhsearch_ [l=vi] {200}
+_heighthsearch_ [l=vi] {57}
+
+## "cÃ¡c káº¿t quáº£" ## green_bar_left_aligned ## qryresb ##
+_httpiconqryresb_ [l=vi] {_httpimg_/vi/qryresb.gif}
+_widthqryresb_ [l=vi] {_pagewidth_}
+_heightqryresb_ [l=vi] {17}
+
+## "lá»ch sá»­" ## green_bar_left_aligned ## schhistb ##
+_httpiconsrchhistb_ [l=vi] {_httpimg_/vi/schhistb.gif}
+_widthsrchhistb_ [l=vi] {_pagewidth_}
+_heightsrchhistb_ [l=vi] {17}
+
+
+######################################################################
+# 'preferences' page
+package preferences
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textprefschanged_ [l=vi] {CÃ¡c thuá»c tÃ­nh ÄÃ£ ÄÆ°á»£c thiáº¿t láº­p nhÆ° sau.
+KhÃŽng sá»­ dá»¥ng nÃºt "back" trÃªn trÃ¬nh duyá»t - NÃ³ sáºœ há»§y bá» cÃ¡c thiáº¿t láº­p ÄÃ£ lÃ m!
+Thay  vÃ o ÄÃ³, nháº¥n má»t trong cÃ¡c nÃºt trÃªn thanh truy xuáº¥t bÃªn trÃªn.
+}
+_textsetprefs_ [l=vi] {Thiáº¿t láº­p thuá»c tÃ­nh}
+_textsearchprefs_ [l=vi] {Thuá»c tÃ­nh tÃ¬m kiáº¿m}
+_textcollectionprefs_ [l=vi] {Thuá»c tÃ­nh bá» sÆ°u táº­p}
+_textpresentationprefs_ [l=vi] {Thuá»c tÃ­nh trÃ¬nh bÃ y}
+_textpreferences_ [l=vi] {Thuá»c tÃ­nh}
+_textcasediffs_ [l=vi] {PhÃ¢n biá»t chá»¯ hoa chá»¯ thÆ°á»ng:}
+_textignorecase_ [l=vi] {bá» qua sá»± khÃ¡c biá»t chá»¯ hoa chá»¯ thÆ°á»ng}
+_textmatchcase_ [l=vi] {chá»¯ hoa/thÆ°á»ng pháº£i khá»p tá»«ng cáº·p}
+_textwordends_ [l=vi] {Háº­u tá» cá»§a tá»«:}
+_textstem_ [l=vi] {bá» qua cÃ¡c háº­u tá» cá»§a tá»«}
+_textnostem_ [l=vi] {toÃ n bá» tá»« pháº£i khá»p}
+_textprefop_ [l=vi] {Káº¿t quáº£ tráº£ vá» tá»i Äa _maxdocoption_ dÃ²ng vá»i _hitsperpageoption_ dÃ²ng trÃªn má»t trang.}
+_textextlink_ [l=vi] {Truy xuáº¥t cÃ¡c trang Web bÃªn ngoÃ i:}
+_textintlink_ [l=vi] {TÃ i liá»u nguá»n ÄÃ£ nháº­n vá» tá»«:}
+_textlanguage_ [l=vi] {NgÃŽn ngá»¯ hiá»n thá»:}
+_textencoding_ [l=vi] {MÃ£ hÃ³a dáº¡ng:}
+_textformat_ [l=vi] {Äá»nh dáº¡ng giao diá»n:}
+_textall_ [l=vi] {táº¥t cáº£}
+_textquerymode_ [l=vi] {CÃ¡ch truy váº¥n:}
+_textsimplemode_ [l=vi] {cÃ¡ch truy váº¥n ÄÆ¡n giáº£n}
+_textadvancedmode_ [l=vi] {cÃ¡ch má» rá»ng (cho phÃ©p thá»±c hiá»n cÃ¢u truy váº¥n báº±ng cÃ¡c toÃ¡n tá»­ liÃªn káº¿t kiá»u logic &, |, !)}
+_textlinkinterm_ [l=vi] {thÃŽng qua trang trung gian}
+_textlinkdirect_ [l=vi] {Äi theo hÆ°á»ng ÄÃ³}
+_textdigitlib_ [l=vi] {thÆ° viá»n sá»}
+_textweb_ [l=vi] {trang web}
+_textgraphical_ [l=vi] {HÃ¬nh áº£nh}
+_texttextual_ [l=vi] {VÄn báº£n}
+_textcollectionoption_ [l=vi] {<p>
+Bá» sÆ°u táº­p con bao gá»m:
+<br>}
+
+_textrelateddocdisplay_ [l=vi] {hiá»n thá» cÃ¡c tÃ i liá»u liÃªn quan}
+_textsearchhistory_ [l=vi] {TÃ¬m kiáº¿m trÆ°á»c ÄÃ³:}
+_textnohistory_ [l=vi] {KhÃŽng dÃ¹ng chá»©c nÄng nÃ y}
+_texthistorydisplay_ [l=vi] {hiá»n thá» _historynumrecords_ tÃ¬m kiáº¿m trÆ°á»c ÄÃ³}
+_textnohistorydisplay_ [l=vi] {khÃŽng hiá»n thá» chá»©c nÄng tÃ¬m kiáº¿m trÆ°á»c ÄÃ³}
+
+#_texttypesearch_ {Type of search:}
+#_texttextsearch_ {text search}
+_textformsearch_ [l=vi] {TÃ¬m kiáº¿m báº±ng ÃŽ truy váº¥n:}
+_textplainsearch_ [l=vi] {TÃ¬m kiáº¿m ÄÆ¡n giáº£n:}
+_textqueryboxsize_ [l=vi] {KÃ­ch thÆ°á»c há»p truy váº¥n:}
+_textregbox_ [l=vi] {kÃ­ch thÆ°á»c chuáº©n}
+_textbigbox_ [l=vi] {kÃ­ch thÆ°á»c má» rá»ng}
+_textformtype_ [l=vi] {Loáº¡i há»p truy váº¥n:}
+_textsimple_ [l=vi] {ÄÆ¡n giáº£n}
+_textadvanced_ [l=vi] {má» rá»ng}
+
+# used in "with 4 fields" in the form search box
+_textwith_ [l=vi] {vá»i}
+_textfields_ [l=vi] {cÃ¡c trá»«Æ¡ng}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "thuá»c tÃ­nh" ## green_title ## h_pref ##
+_httpiconhpref_ [l=vi] {_httpimg_/vi/h\_pref.gif}
+_widthhpref_ [l=vi] {200}
+_heighthpref_ [l=vi] {57}
+
+#####################################################################
+# 'browse' package for the dynamic browsing interface
+package browse
+#####################################################################
+
+_textsortby_ [l=vi] {Sáº¯p xáº¿p cÃ¡c tÃ i liá»u theo}
+_textalsoshowing_ [l=vi] {cÅ©ng trÃ¬nh bÃ y}
+_textwith_ [l=vi] {vá»i tá»i Äa lÃ }
+_textdocsperpage_ [l=vi] {tÃ i liá»u trÃªn má»t trang}
+
+_textfilterby_ [l=vi] {Láº¥y cÃ¡c tÃ i liá»u cÃ³ chá»©a}
+_textall_ [l=vi] {táº¥t cáº£}
+_textany_ [l=vi] {má»t sá»}
+_textwords_ [l=vi] {trong cÃ¡c tá»«}
+_textleaveblank_ [l=vi] {bá» há»p thoáº¡i nháº­p liá»u tráº¯ng Äá» nháº­n vá» cÃ¡c tÃ i liá»u}
+
+_browsebuttontext_ [l=vi] {"Sáº¯p xáº¿p tÃ i liá»u"}
+
+_nodata_ [l=vi] {<i>khÃŽng cÃ³ dá»¯ liá»u</i>}
+_docs_ [l=vi] {cÃ¡c tÃ i liá»u}
+######################################################################
+# 'help' page -- this is lower priority for translating than the
+# rest of this file
+package help
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textHelp_ [l=vi] {GiÃºp Äá»¡}
+_textSearchshort_ [l=vi] {tÃ¬m kiáº¿m dá»±a vÃ o tá»« khoÃ¡.}
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+_textTitleshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo tÃªn tÃ i liá»u.}
+_textCreatorshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo tÃªn tÃ¡c giáº£.}
+_textSubjectshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo chá»§ Äá».}
+# -- Missing translation: _textDescriptionshort_
+# -- Missing translation: _textPublishershort_
+# -- Missing translation: _textContributorshort_
+_textDateshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo ngÃ y thÃ¡ng.}
+# -- Missing translation: _textTypeshort_
+# -- Missing translation: _textFormatshort_
+# -- Missing translation: _textIdentifiershort_
+_textSourceshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo tÃªn táº­p tin}
+_textLanguageshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo ngÃŽn ngá»¯}
+# -- Missing translation: _textRelationshort_
+# -- Missing translation: _textCoverageshort_
+# -- Missing translation: _textRightsshort_
+
+_textSeriesshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo nhÃ³m.}
+_textToshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo trÆ°á»ng NÆ¡i chá»©a}
+_textFromshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo trÆ°á»ng Nguá»n gá»c}
+_textBrowseshort_ [l=vi] {trÃ¬nh duyá»t tÃ i liá»u}
+_textOrganizationshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo tÃªn tá» chá»©c xuáº¥t báº£n.}
+_textHowtoshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo danh sÃ¡ch cÃ¡c "gá»£i Ãœ".}
+_textTopicshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo chá»§ Äá».}
+_textPeopleshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo tÃªn ngÆ°á»i}
+_textAcronymshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo tá»« viáº¿t táº¯t}
+_textPhraseshort_ [l=vi] {trÃ¬nh duyá»t cÃ¡c cá»¥m tá»« xuáº¥t hiá»n trong vÄn báº£n}
+_textArtistshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo tÃªn nghá» sÄ©}
+_textKeywordshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo tá»« khÃ³a}
+_textVolumeshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo quyá»n}
+_textCountriesshort_ [l=vi] {truy xuáº¥t tÃ i liá»u theo tÃªn quá»c gia}
+_textdefaultshorttext_ [l=vi] {chÆ°a ÄÆ°á»£c phÃ¢n loáº¡i}
+
+_textSearchlong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i>tÃ¬m kiáº¿m theo tá»« khoÃ¡</i> ÄÆ°á»£c cung cáº¥p trong ÃŽ nhÃ¢p liá»u trong trang tÃ¬m kiáº¿m. Trang nÃ y sáºœ  hiá»n lÃªn ngay khi báº¡n chá»n má»t bá» sÆ°u táº­p Äá» lÃ m viá»c vÃ  cÃ³ thá» ÄÆ°á»£c liÃªn káº¿t Äáº¿n tá»« cÃ¡c trang khÃ¡c báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>TÃ¬m kiáº¿m </i>. }
+
+
+# Dublin Core Metadata Element Set, Version 1.1
+
+_textTitlelong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i>truy xuáº¥t tÃ i liá»u theo tÃªn</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>tÃªn tÃ i liá»u</i>.  Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c quyá»n sÃ¡ch theo thá»© tá»± alphabetic.  }
+
+# Not true DC, kept for legacy reasons
+_textCreatorlong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i>truy xuáº¥t tÃ i liá»u theo tÃªn tÃ¡c giáº£</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>tÃ¡c giáº£ a-z</i>. Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c quyá»n sÃ¡ch ÄÆ°á»£c sáº¯p xáº¿p theo tÃªn tÃ¡c giáº£.  }
+
+_textSubjectlong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i>truy xuáº¥t tÃ i liá»u theo chá»§ Äá»</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>cÃ¡c chá»§ Äá»</i>. Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c chá»§ Äá», ÄÆ°á»£c sáº¯p xáº¿p thÃ nh tá»«ng ká» sÃ¡ch.  }
+
+# -- Missing translation: _textDescriptionlong_
+
+# -- Missing translation: _textPublisherlong_
+
+# -- Missing translation: _textContributorlong_
+
+_textDatelong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo ngÃ y thÃ¡ng</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>dates</i>.  Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c tÃ i liá»u ÄÆ°á»£c sáº¯p xáº¿p the ngÃ y thÃ¡ng.  }
+
+# -- Missing translation: _textTypelong_
+
+# -- Missing translation: _textFormatlong_
+
+# -- Missing translation: _textIdentifierlong_
+
+# Not true DC, kept for legacy reasons
+_textSourcelong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i>truy xuáº¥t tÃ i liá»u xuáº¥t báº£n theo tÃªn táº­p tin</i> báº±ng cÃ¡ch nháº¥n nÃºt <i>tÃªn tÃ¢p tin</i>.  Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t  danh sÃ¡ch cÃ¡c cÃ¡ch truy xuáº¥t ÄÆ°á»£c sáº¯p xáº¿p theo tÃªn tÃ¢p tin.  }
+
+_textLanguagelong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo ngÃŽn ngá»¯</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>ngÃŽn ngá»¯</i>.  Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c vÄn báº£n sáº¯p xáº¿p theo ngÃŽn ngá»¯.  }
+
+# -- Missing translation: _textRelationlong_
+
+# -- Missing translation: _textCoveragelong_
+
+# -- Missing translation: _textRightslong_
+
+
+
+_textOrganizationlong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i>truy xuáº¥t tÃ i liá»u  theo tá» chá»©c</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>Tá» chá»©c</i>.  Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c tá» chá»©c xuáº¥t báº£n.  }
+
+_textHowtolong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i>truy xuáº¥t tÃ i liá»u theo danh sÃ¡ch "gá»£i Ãœ"</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>gá»£i Ãœ</i>. Truy xuáº¥t tÃ i liá»u cÃ¡c chuá»i gá»£i Ãœ.  }
+
+_textTopiclong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo Äá» tÃ i</i> báº±ng cÃ¡ch nháº¥n vÃ o <i>Äá» tÃ i</i>.  Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c Äá» tÃ i Äá» trÃ¬nh duyá»t  }
+
+_textTolong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo trÆ°á»ng nÆ¡i chá»©a</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>nÆ¡i chá»©a</i>.  Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c Äá»a chá».  }
+
+_textFromlong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo trÆ°á»ng Nguá»n gá»c</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>nguá»n gá»c</i>.  Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch ngá»«Æ¡i gá»­i  }
+
+_textSerieslong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo nhÃ³m</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>nhÃ³m</i>.  Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch nhÃ³m cÃ³ trong bá» sÆ°u táº­p.  }
+
+_textBrowselong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i>trÃ¬nh duyá»t tÃ i liá»u</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt
+<i>trÃ¬nh duyá»t</i>.  }
+
+_textPeoplelong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo tÃªn ngÆ°á»i</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>tÃªn ngÆ°á»i a-z</i>. Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch tÃªn ngá»«Æ¡i ÄÆ°á»£c xáº¿p theo há»}
+
+_textAcronymlong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo chá»¯ viáº¿t táº¯t</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>tÃªn viáº¿t táº¯t</i>. Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c chá»¯ viáº¿t táº¯t vÃ  nÆ¡i chÃºng xuáº¥t hiá»n.  }
+
+_textPhraselong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i>trÃ¬nh duyá»t cá»¥m tá»« xuáº¥t hiá»n trong tÃ i liá»u </i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>cá»¥m tá»«</i>. }
+
+_textArtistlong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo tÃªn nghá» sÄ©<i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>tÃªn nghá» sÄ©</i>. Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c vÄn báº£n sáº¯p xáº¿p theo tÃªn nghá» sÄ©.  }
+
+_textKeywordlong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo tá»« khÃ³a</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>tá»« khÃ³a</i>. Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c tá»« khÃ³a. }
+
+_textVolumelong_ [l=vi] {<p>Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo tá»«ng quyá»
+n</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>quyá»n</i>. Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c quyá»n cá»§a táº¡p chÃ­ hay bá» sÃ¡ch }
+
+_textCaptionslong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo chÃº thÃ­ch</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>chÃº thÃ­ch</i>. Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c chÃº thÃ­ch }
+
+_textCountrieslong_ [l=vi] {<p> Báº¡n cÃ³ thá» <i> truy xuáº¥t tÃ i liá»u theo tÃªn quá»c gia</i> báº±ng cÃ¡ch nháº¥n vÃ o nÃºt <i>tÃªn quá»c gia</i>. Viá»c lÃ m nÃ y sáºœ tráº£ vá» má»t danh sÃ¡ch cÃ¡c quá»c gia. }
+
+
+_textdefaultlongtext_ [l=vi] {<p>Nháº¥n vÃ o nÃºt <i>khÃŽng hiá»u</i> Äá» duyá»t cÃ¡c tÃ i liá»u (danh sÃ¡ch ÄÆ°á»£c sáº¯p xáº¿p theo má»t trÆ°á»ng báº¥t kÃ¬ }
+
+_texthelptopics_ [l=vi] {<h2 align=left>Chá»§ Äá»</h2>
+<ul>
+  <li><a href="\#finding-information">_textsimplehelpheading_</a>
+  _topicreadingdocs_
+  <li><a href="\#searching">CÃ¡ch tÃ¬m kiáº¿m theo tá»« khoÃ¡</a>
+<ul>
+  <li><a href="\#query-terms">CÃ¡c Äiá»u kiá»n tÃ¬m kiáº¿m</a>
+  <li><a href="\#query-type">Loáº¡i truy váº¥n</a>
+  <li><a href="\#scope-of-queries">Pháº¡m vi cá»§a cÃ¢u truy váº¥n</a>
+</ul>
+  <li><a href="\#preferences">_textchangeprefs_</a>
+<ul>
+  <li><a href="\#col-prefs">Thuá»c tÃ­nh bá» sÆ°u táº­p</a>
+  <li><a href="\#lang-prefs">Thuá»c tÃ­nh ngÃŽn ngá»¯</a>
+  <li><a href="\#pres-prefs">Thuá»c tÃ­nh trÃ¬nh bÃ y</a>
+  <li><a href="\#search-prefs">Thuá»c tÃ­nh tÃ¬m kiáº¿m</a>
+</ul>
+</ul>
+}
+
+# there are 4 versions of this section of the help text.
+# which version is used is currently set within the server
+# (it should probably use the macro language e.g. [type=book])
+# 1 = html (like fao collections) -- section is empty
+# 2 = book (like hdl collection) -- macros beginning with book
+# 3 = bibliographic (like csbib) -- macros beginning with bib
+# 4 = standard (like gberg) -- the default
+
+_topicreadingdocs_ [l=vi] {<li><a href="\#reading-docs">_textreadingdocs_</a>}
+
+_textreadingdocs_ [l=vi] {CÃ¡ch Äá»c cÃ¡c tÃ i liá»u}
+
+_texthelpreadingdocs_ [l=vi] {<p>_iconblankbar_</p>
+<a name=reading-docs>
+<h2>_textreadingdocs_</h2>
+
+<p>- Báº¡n biáº¿t ÄÆ°á»£c báº¡n ÄÃ£ tÃ¬m tháº¥y quyá»n sÃ¡ch mÃ  báº¡n muá»n nhá» vÃ o tá»±a hoáº·c áº£nh bÃ¬a cá»§a nÃ³. Trong má»t sá» bá» sÆ°u táº­p nhá»¯ng minh
+há»a nÃ y ÄÆ°á»£c Äi kÃšm vá»i báº£ng má»¥c lá»¥c, má»t sá» khÃ¡c chá» chá»©a sá»
+cá»§a trang cÃ¹ng vá»i vá»i má»t há»p thoáº¡i mÃ  cho phÃ©p báº¡n chá»n má»t trang má»i vÃ 
+Äi tiáº¿p hoáº·c quay trá» láº¡i. Trong báº£ng má»¥c lá»¥c, pháº§n tiÃªu Äá» hiá»n táº¡i Äang Äá»©ng ÄÆ°á»£c in Äáº­m vÃ  báº£ng má»¥c lá»¥c cÃ³ thá» ÄÆ°á»£c má» rá»ng - nháº¥n chuá»t trÃªn thÆ° má»¥c Äá» má»
+hoáº·c ÄÃ³ng chÃºng; nháº¥n chuá»t vÃ o biá»u tÆ°á»£ng cuá»n sÃ¡ch má» á» bÃªn trÃªn Äá» ÄÃ³ng nÃ³.</p>
+
+<p>Pháº§n bÃªn dÆ°á»i lÃ  ná»i dung cá»§a pháº§n hiá»n hÃ nh. Khi báº¡n Äá»c qua nÃ³, cÃ³ nhiá»u
+mÅ©i tÃªn á» dÆ°á»i ÄÃ¡y trang cho báº¡n sang pháº§n káº¿ tiáº¿p hoáº·c quay trá» láº¡i pháº§n trÆ°á»c ÄÃ³.</p>
+
+<p>PhÃ­a dÆ°á»i tiÃªu Äá» hoáº·c bá»©c hÃ¬nh cÃ³ má»t sá» nÃºt. NÃºt <i>Má» vÄn báº£n</i> sáºœ má» rá»ng
+toÃ n bá» ná»i dung thÆ° má»¥c hiá»n hÃ nh hoáº·c toÃ n bá» ná»i dung cuá»n sÃ¡ch hiá»n hÃ nh.
+Náº¿u tÃ i liá»u quÃ¡ lá»n, nÃ³ cÃ³ thá» tá»n nhiá»u thá»i gian vÃ  bá» nhá». NÃºt <i>Má» ná»i dung</i> sáºœ
+má» rá»ng toÃ n bá» ná»i dung cá»§a báº£ng, giÃºp báº¡n tháº¥y tÃªn táº¥t cáº£ cÃ¡c chÆ°Æ¡ng, cÃ¡c
+thÆ° má»¥c con (subsections). NÃºt <i>Má» cá»­a sá» má»i</i> cÃ³ tÃ¡c dá»¥ng má» ra cá»­a sá» má»i. (Pháº§n nÃ y cÃ³
+cÃŽng dá»¥ng trong viá»c má» ra tÃ i liá»u cÃ¹ng má»t lÃºc Äá» Äá»c hoáº·c so sÃ¡nh). Cuá»i cÃ¹ng, khi
+báº¡n tÃ¬m kiáº¿m vá»i cÃ¡c tá»«, cÃ¡c tá»« ÄÃ³ sáºœ ÄÆ°á»£c tÃŽ sÃ¡ng. Nháº¥n chuá»t vÃ o nÃºt <i>KhÃŽng tÃŽ mÃ u</i> Äá»
+xoÃ¡ cÃ¡c pháº§n tÃŽ sÃ¡ng.</p>
+
+<p>
+<table cellspacing="0" cellpadding="2" border="0">
+<tr><td colspan=2><img src="_httpiconbshelf_" border="0"></td><td>Má» ká» sÃ¡ch nÃ y</td></tr>
+<tr><td><img src="_httpiconopenbook_" border="0"></td><td><img 
+src="_httpiconbook_" border="0"></td><td>Má»/ÄÃ³ng sÃ¡ch nÃ y</td></tr>
+<tr><td colspan=2><img src="_httpiconitext_" border="0"></td><td>Xem pháº§n nÃ y cá»§a vÄn báº£n</td></tr>
+<tr><td><img src="_document:httpiconealltof_" border="0"></td><td><img 
+src="_document:httpiconetsecof_" border="0"></td><td>Hiá»n thá» táº¥t cáº£ cÃ¡c vÄn báº£n hoáº·c khÃŽng</td></tr>
+<tr><td><img src="_document:httpiconeexpcof_" border="0"></td><td><img
+src="_document:httpiconeconcof_" border="0"></td><td>Má» báº£ng ná»i dung hoáº·c khÃŽng</td></tr>
+<tr><td colspan=2><img src="_document:httpiconedtchof_" border="0"></td><td>Má» trang nÃ y trong má»t cá»­a sá» má»i
+</td></tr>
+<tr><td><img src="_document:httpiconehlof_" border="0"></td><td><img
+src="_document:httpiconenhlof_" border="0"></td><td>TÃŽ mÃ u Äiá»u kiá»n tÃ¬m kiáº¿m hoáº·c khÃŽng</td></tr>
+<tr><td colspan=2><img src="_httpiconmore_" border="0"></td><td>Nháº¥n vÃ o mÅ©i tÃªn Äá» Äáº¿n pháº§n káº¿ tiáº¿p ...</td></tr>
+<tr><td colspan=2><img src="_httpiconless_" border="0"></td><td>... hoáº·c trá» láº¡i pháº§n trÆ°á»c</td></tr>
+</table>
+}
+
+_texthelpsearching_ [l=vi] {<h2>TÃ¬m kiáº¿m dÆ°a trÃªn tá»« khoÃ¡</h2>
+<p>
+  Tá»« trang tÃ¬m kiáº¿m, báº¡n cÃ³ thá» lÃ m cÃ¢u truy váº¥n theo cÃ¡c bÆ°á»c ÄÆ¡n giáº£n sau:<p>
+  
+  <ol><li>XÃ¡c Äá»nh cÃ¡c má»¥c báº¡n muá»n tÃ¬m.
+      <li>Báº¡n muá»n tÃ¬m táº¥t cáº£ cÃ¡c tá»« hay chá» má»t sá» tá»«.
+      <li>ÄÃ¡nh nhá»¯ng tá»« báº¡n muá»n tÃ¬m.
+      <li>Nháº¥n chuá»t vÃ o nÃºt <i>Báº¯t Äáº§u tÃ¬m kiáº¿m</i>.
+  </ol>
+
+<p>Khi báº¡n thá»±c hiá»n cÃ¢u truy váº¥n, tÃªn cá»§a 20 tÃ i liá»u phÃ¹ há»£p yÃªu cáº§u
+sáºœ ÄÆ°á»£c trÃ¬nh bÃ y. á» cuá»i má»i trang sáºœ cÃ³ nÃºt Äá» cho báº¡n chuyá»n
+sang trang káº¿ cÅ©ng chá»©a tá»i Äa 20 tÃ i liá»u. Tá»« vá» trÃ­ ÄÃ³ báº¡n sáºœ tÃ¬m tháº¥y
+cÃ¡c nÃºt Äá» báº¡n chuyá»n sang trang tiáº¿p theo hoáº·c trá» vá» trang Äáº§u, cá»©
+tiáº¿p tá»¥c nhÆ° tháº¿ Äá» xem káº¿t quáº£. Nháº¥n lÃªn tÃªn cá»§a báº¥t kÃ¬ má»t tÃ i liá»u nÃ o hoáº·c
+nÃºt nhá» bÃªn cáº¡nh nÃ³ Äá» xem ná»i dung.
+
+<p>Tá»i Äa 100 káº¿t quáº£ ÄÆ°á»£c trÃ¬nh bÃ y trong sá» káº¿t quáº£ tráº£ vá». Báº¡n cÃ³
+thá» thay Äá»i con sá» nÃ y báº±ng nháº¥n lÃªn nÃºt <i>cÃ¡c thuá»c tÃ­nh</i> phÃ­a trÃªn cÃ¹ng
+cá»§a trang. <p>
+
+<p>_iconblankbar_
+<a name=query-terms>
+<h3>CÃ¡c Äiá»u kiá»n tÃ¬m kiáº¿m</h3>
+
+<p>Báº¥t kÃœ khi nÃ o báº¡n ÄÃ¡nh vÃ o há»p truy váº¥n ÄÆ°á»£c xem nhÆ° lÃ  má»t danh sÃ¡ch
+cÃ¡c tá»« gá»i lÃ  âtá»« khÃ³aâ. Má»i Äiá»u kiá»n lÃ  má»t tá»« chá»©a cÃ¡c chá»¯ alphabet hay
+chá»¯ sá». CÃ¡c tá»« pháº£i ÄÆ°á»£c cÃ¡ch ra báº±ng khoáº£ng tráº¯ng. Báº¥t cá»© cÃ¡c dáº¥u cháº¥m cÃ¢u, cháº¥m pháº©y, gáº¡ch ngang, v.v.. cÅ©ng Äá»u ÄÆ°á»£c xem nhÆ° lÃ  khoáº£ng
+tráº¯ng. Báº¡n sáºœ khÃŽng thá» tÃ¬m nhá»¯ng tá»« khÃ³a cÃ³ chá»©a dáº¥u cháº¥m.
+
+<p>Ta cÃ³ cÃ¢u truy váº¥n sau<p>
+    <ul><kbd>Agro-forestry in the Pacific Islands: Systems for Sustainability (1993)</kbd></ul>
+      <p>sáºœ tÆ°Æ¡ng ÄÆ°Æ¡ng vá»i<p>
+      <ul><kbd>Agro forestry in the Pacific Islands  Systems for Sustainability  1993 </kbd></ul><p>
+
+<p>_iconblankbar_
+<a name=query-type>
+<h3>Loáº¡i cÃ¢u truy váº¥n</h3>
+
+<p>CÃ³ 2 loáº¡i truy váº¥n khÃ¡c nhau.
+
+<ul>
+  <li>Loáº¡i truy váº¥n thá»© nháº¥t lÃ  tÃ¬m <b>táº¥t cáº£</b> cÃ¡c tá»« trong há»p há»i thoáº¡i tÃ¬m kiáº¿m. TÃ i
+liá»u ÄÆ°á»£c tÃ¬m tháº¥y cÃ³ thá» lÃ  cÃ¡c ChÆ°Æ¡ng hoáº·c TÃªn sÃ¡ch chá»©a táº¥t cáº£ cÃ¡c tá»« tÃ¬m kiáº¿m.
+Nhá»¯ng tÃ i liá»u nÃ o thá»a Äiá»u kiá»n tÃ¬m kiáº¿m sáºœ ÄÆ°á»£c trÃ¬nh bÃ y.<p>
+
+  <li>Loáº¡i thá»© hai lÃ  chá» tÃ¬m <b>má»t sá»</b> tá»« trong má»t loáº¡t tá»« mÃ  báº¡n ÄÃ£ gÃµ vÃ o cÃ³ trong tÃ i
+liá»u báº¡n Äang tÃ¬m. Nhá»¯ng tÃ i liá»u nÃ o cÃ³ thá»a Äiá»u kiá»n tÃ¬m kiáº¿m hÆ¡n cáº£ sáºœ ÄÆ°á»£c hiá»n thá». CÃ¡c tÃ i liá»u ÄÆ°á»£c tÃ¬m tháº¥y sáºœ ÄÆ°á»£c sáº¯p xáº¿p theo Äá» phÃ¹ há»£p cá»§a chÃºng Äá»i vá»i yÃªu cáº§u. DÃŽ phÃ¹ há»£p nÃ y ÄÆ°á»£c xÃ¡c Äá»nh dá»±a trÃªn
+
+      <p><ul>
+         <li> TÃ i liá»u nÃ o chá»©a cÃ ng nhiá»u cÃ¡c tá»« tÃ¬m kiáº¿m trong há»p há»i thoáº¡i thÃ¬ káº¿t quáº£ cÃ ng chÃ­nh xÃ¡c.
+         <li> CÃ¡c tá»« Ã­t thÃŽng dá»¥ng quan trá»ng hÆ¡n cÃ¡c tá»« thÃŽng dá»¥ng
+         <li> TÃ i liá»u cÃ³ ná»i dung ngáº¯n dá»
+ thoáº£ Äiá»u kiá»n tÃ¬m kiáº¿m hÆ¡n.
+      </ul>
+</ul>
+  
+<p>NgÆ°á»i sá»­ dá»¥ng cÃ³ thá» chá»n nhá»¯ng cÃ¡ch tÃ¬m kiáº¿m mÃ  há» thÃ­ch - Chá»n cáº£ 
+má»t cÃ¢u hoáº·c ngay cáº£ má»t Äoáº¡n. Náº¿u báº¡n xÃ¡c Äá»nh chá» gÃµ vÃ o má»t tá»« thÃ¬ cÃ¡c 
+káº¿t quáº£ ÄÆ°á»£c sáº¯p thá»© tá»± theo sá» láº§n xuáº¥t hiá»n tá»« cáº§n tÃ¬m kiáº¿m trong má»i tÃ i liá»u.<p>
+_texthelpscope_
+}
+
+_textdatesearch_ [l=vi] {TÃ¬m kiáº¿m theo ngÃ y thÃ¡ng}
+
+_texthelpdatesearch_ [l=vi] {<h2>_textdatesearch_</h2>
+TÃ¬m kiáº¿m theo ngÃ y thÃ¡ng cho phÃ©p báº¡n tÃ¬m cÃ¡c tÃ i liá»u thá»a mÃ£n cÃ¡c tá»« khÃ³a vÃ  náº±m trong má»t khaá»ng thá»i gian nÃ o ÄÃ³. Báº¡n cÃ³ thá» tÃ¬m cÃ¡c tÃ i liá»u trong má»t nÄm hay trong má»t khoáº£ng thá»i gian nhiá»u nÄm. LÆ°u Ãœ ráº±ng báº¡n khÃŽng cáº§n pháº£i cÃ³ tá»« khÃ³a nÃ o cáº£ - báº¡n cÃ³ thá» chá» tÃ¬m kiáº¿m theo ngÃ y thÃ¡ng, hay ngÆ°á»£c láº¡i, báº¡n khÃŽng nháº¥t thiáº¿t pháº£i sá»­ dá»¥ng ngÃ y thÃ¡ng trong quÃ¡ trÃ¬nh tÃ¬m kiáº¿m, náº¿u báº¡n khÃŽng chá» rÃµ ngÃ y thÃ¡ng thi viá»c tÃ¬m kiáº¿m sáºœ giá»ng nhÆ° khi chá»©c nÄng tÃ¬m kiáº¿m báº±ng ngÃ y thÃ¡ng khÃŽng tá»n táº¡i. <p>
+
+<p>_iconblankbar_
+<a name=datesearch-howto>
+<h3>CÃ¡ch sá»­ dá»¥ng chá»©c nÄng nÃ y:</h3>
+<ul>
+   <li>Äá» tÃ¬m tÃ i liá»u trong má»t nÄm:<p>
+   <ul>
+       <li>ÄÃ¡nh vÃ o cÃ¡c tá»« khÃ³a Äá» tÃ¬m kiáº¿m nhÆ° bÃ¬nh thÆ°á»ng.
+       <li>ÄÃ¡nh nÄm cáº§n tÃ¬m vÃ o há»p "Start (or only) date".
+       <li>Náº¿u nÄm cáº§n tÃ¬m lÃ  trá»©Æ¡c cÃŽng nguyÃªn, hÃ£y chá»n chá»©c nÄng "B.C.E" tá»« há»p menu bÃªn cáº¡nh.
+       <li>Báº¯t Äáº§u tÃ¬m kiáº¿m nhÆ° bÃ¬nh thÆ°á»ng
+   </ul>
+<p><li> Äá» tÃ¬m tÃ i liá»u trong má»t khoáº£ng thá»i gian nhiá»u nÄm:<p>
+   <ul>
+       <li> ÄÃ¡nh vÃ o cÃ¡c tá»« khÃ³a Äá» tÃ¬m kiáº¿m nhÆ° bÃ¬nh thÆ°á»ng.
+       <li> ÄÃ¡nh nÄm báº¯t Äáº§u vÃ o há»p "Start (or only) date".
+       <li> ÄÃ¡nh nÄm káº¿t thÃºc vÃ o há»p "End date" box.
+       <li>Náº¿u nÄm cáº§n tÃ¬m lÃ  trá»©Æ¡c cÃŽng nguyÃªn, hÃ£y chá»n chá»©c nÄng "B.C.E" tá»« há»p menu bÃªn cáº¡nh.
+       <li> Báº¯t Äáº§u tÃ¬m kiáº¿m nhÆ° bÃ¬nh thÆ°á»ng
+   </ul>    
+</ul><p>
+
+<p>_iconblankbar_
+<a name=datesearch-results>
+<h3>CÃ¡ch quÃ¡ trÃ¬nh tÃ¬m kiáº¿m ÄÆ°á»£c thá»±c hiá»n</h3>
+
+NÃ³i chung, khi tÃ¬m kiáº¿m cÃ¡c vÄn báº£n vá» nam 1903, ta sáºœ khÃŽng cÃ³ cÃ¡c tÃ i liá»u viáº¿t vÃ o nÄm 1903, mÃ  chá» cÃ³ cÃ¡c tÃ i liá»u viáº¿t vá» nÄm 1903. Tuy nhiÃªn, káº¿t quáº£ sáºœ lÃ  cÃ¡c vÄn báº£n mÃ  ngÃ y thÃ¡ng cá»§a nÃ³ (vÃ­ dá»¥ 1899-1911) cÃ³ chá»©a 1903 vÃ  cáº£ nhá»¯ng vÄn báº£n mÃ  ná»i dung cÃ³ ghi tÃªn tháº¿ ká» mÃ  nÄm 1903 thuá»c vá» (vÃ­ dá»¥ tháº¿ ká» 20). CÃ³ nghÄ©a lÃ . Äá»i vá»i má»t sá» vÄn báº£n, ngÃ y thÃ¡ng báº¡n cáº§n tÃ¬m khÃŽng xuáº¥t hiá»n trá»±c tiáº¿p trÃªn vÄn báº£n. Äá»i vá»i tÃ¬m kiáº¿m trong má»t khoáº£ng thá»i gian, táº¥t cáº£ nhá»¯ng nguyÃªn táº¯c trÃªn ÄÆ°á»£c Ã¡p dá»¥ng cho tá»«ng ngÃ y trong khoáº£ng thá»i gian ÄÃ³.
+<p>
+}
+
+_textchangeprefs_ [l=vi] {Thay Äá»i nhá»¯ng thuá»c tÃ­nh}
+
+_texthelppreferences_ [l=vi] {<h2>_textchangeprefs_</h2>
+
+<p>Khi báº¡n nháº¥n chuá»t lÃªn nÃºt <i>Thuá»c tÃ­nh</i> á» phÃ­a trÃªn cá»§a trang, báº¡n sáºœ cÃ³ thá» thay Äá»i má»t vÃ i Äáº·c Äiá»m cá»§a giao diá»n cho phÃ¹ há»£p vá»i yÃªu cáº§u riÃªng cá»§a báº¡n.
+
+<p>_iconblankbar_
+<a name=col-prefs>
+<h3 align=left>Thuá»c tÃ­nh Bá» sÆ°u táº­p</h3>
+
+Má»t sá» bá» sÆ°u táº­p gá»p tá»« nhiá»u bá» sÆ°u táº­p nhá» hÆ¡n mÃ  ta cÃ³ thá» tÃ¬m kiáº¿m
+Äá»c láº­p hoáº·c káº¿t há»£p láº¡i lÃ m má»t. Khi ÄÃ³, báº¡n cÃ³ thá» chá»n nhá»¯ng bá» sÆ°u táº­p con báº¡n muá»n vÃ o trang tÃ¬m kiáº¿m cá»§a báº¡n dÃ¹ng trang Thuá»c tÃ­nh.
+
+<p>_iconblankbar_
+<a name=lang-prefs>
+<h3 align=left>Thuá»c tÃ­nh ngÃŽn ngá»¯</h3>
+
+Má»i bá» sÆ°u táº­p  Äá»u cÃ³ ngÃŽn ngá»¯ thá» hiá»n riÃªng, nhÆ°ng báº¡n váº«n cÃ³ thá» chuyá»n
+sang ngÃŽn ngá»¯ khÃ¡c náº¿u thÃ­ch. Báº¡n cÃ³ thá» thay Äá»i cÃ¡ch mÃ£ hoÃ¡ mÃ  pháº§n má»m. ThÃŽng thÆ°á»ng Greenstone sáºœ chá»n má»t cÃ¡ch thÃ­ch há»£p nhÆ°ng má»t sá» trÃ¬nh duyá»t sáºœ hoáº¡t Äá»ng tá»t hÆ¡n khi chuyá»n sang má»t loáº¡i mÃ£ hÃ³a khÃ¡c.
+Greenstone ÄÃ£ sá»­ dá»¥ng Äá» ÄÆ°a dá»¯ liá»u ra ngoÃ i dÃ¹ng cho viá»c tÃ¬m kiáº¿m. 
+Táº¥t cáº£ cÃ¡c bá» sÆ°u táº­p Äá»u cho phÃ©p báº¡n chuyá»n tá»« giao diá»n Äá» há»a dáº¡ng chuáº©n thÃ nh vÄn báº£n. Äiá»u nÃ y Äáº·c biá»t há»¯u Ã­ch cho gáº·p khÃ³ khÄn trong viá»c Äá»c dá»¯ liá»u, ngÆ°á»i dÃ¹ng cÃ³ thá» Äiá»u chá»nh phÃŽng chá»¯ lá»n hÆ¡n hoáº·c chuyá»n vÄn báº£n sang dáº¡ng Ã¢m thanh
+
+<p>_iconblankbar_
+<a name=pres-prefs>
+<h3 align=left>Thuá»c tÃ­nh trÃ¬nh bÃ y</h3>
+
+TÃ¹y thuá»c vÃ o tá»«ng bá» sÆ°u táº­p mÃ  báº¡n cÃ³ cÃ¡ch lá»±a chá»n khÃ¡c nhau
+
+<p>CÃ¡c bá» sÆ°u táº­p ÄÆ°á»£c trÃ¬nh trÃªn trang Web sáºœ cho phÃ©p báº¡n táº¯t
+thanh Äiá»u khiá»n cá»§a Greenstone trÃªn Äáº§u má»i trang tÃ i liá»u, Äá» khi báº¡n tÃ¬m Äáº¿n ÄÃºng trang web cáº§n tÃ¬m dÆ°á»i dáº¡ng khÃŽng cÃ³ thanh Äiá»u khiá»n Greenstone, báº¡n pháº£i báº¥m vÃ o nÃºt âbackâ Äá» quay trá» láº¡i tráº¡ng thÃ¡i tÃ¬m kiáº¿m ban Äáº§u.
+Bá» sÆ°u táº­p nÃ y cÅ©ng cho phÃ©p báº¡n táº¯t nhá»¯ng cáº£nh bÃ¡o khi nháº¥n vÃ o liÃªn káº¿t thoÃ¡t khá»i bá»
+tÃ i liá»u cá»§a ThÆ° viá»n vÃ  ngay vá»i chÃ­nh trÃªn trang web ÄÃ³. TrÃªn má»t sá» tÃ i liá»u trÃ¬nh bÃ y trÃªn web, báº¡n
+cÃ³ thá» chá»n sá»­ dá»¥ng liÃªn káº¿t trá»±c tiáº¿p tá»« URL hay sá»­ dá»¥ng báº£n sao cá»§a nÃ³ cÃ³ trong thÆ° viá»n sá». 
+
+<p>_iconblankbar_
+<a name=search-prefs>
+<h3 align=left>CÃ¡c thuá»c tÃ­nh tÃ¬m kiáº¿m</h3>
+<p>CÃ³ hai cáº·p nÃºt Äiá»u khiá»n vÄn báº£n trong tÃ¬m kiáº¿m mÃ  báº¡n cÃ³ thá» lÃ m. Cáº·p nÃºt Äáº§u
+tiÃªn cho phÃ©p tÃ¬m kiáº¿m cÃ³ phÃ¢n biá»t chá»¯ hoa vá»i chá»¯ thÆ°á»ng. Cáº·p nÃºt tiáº¿p theo cho phÃ©p
+tÃ¬m kiáº¿m cÃ³ bá» qua pháº§n háº­u tá» cá»§a tá»« hay khÃŽng. NÃ³ cÃ³ thá» cho phÃ©p kÃ­ch thÆ°á»c há»p truy váº¥n lá»n
+hÆ¡n bÃ¬nh thÆ°á»ng Äá» báº¡n cÃ³ thá» ÄÃ¡nh cáº£ Äoáº¡n vÄn vÃ o tÃ¬m kiáº¿m.
+
+<p>VÃ­ dá»¥ náº¿u báº¡n chá»n nÃºt <i>bá» qua phÃ¢n biá»t hoa thÆ°á»ng</i> vÃ  <i>bá» qua pháº§n cuá»i cá»§a tá»«</i> thÃ¬
+cÃ¢u truy váº¥n <p>
+      <ul><kbd>African building</kbd></ul>
+       <p>sáºœ ÄÆ°á»£c xem nhÆ° lÃ <p>
+       <ul><kbd>africa builds</kbd></ul><p>bá»i vÃ¬ tá»« kÃœ tá»±
+hoa trong âAfricanâ sáºœ ÄÆ°á»£c chuyá»n thÃ nh chá»¯ thÆ°á»ng, vÃ  háº­u tá» ânâ vÃ  âingâ sáºœ
+ÄÆ°á»£c bá» Äi khá»i âAfricanâ vÃ  âbuildingâ (tÆ°Æ¡ng tá»±, âsâ cÅ©ng ÄÆ°á»£c bá» khá»i âbuildsâ).
+
+<p>Báº¡n cÃ³ thá» chuyá»n Äáº¿n cháº¿ Äá» tÃ¬m kiáº¿m má» rá»ng Äá» káº¿t há»£p cÃ¡c Äiá»u kiá»n
+tÃ¬m kiáº¿m sá»­ dá»¥ng AND (&), OR(|), vÃ  NOT(!). Äiá»u nÃ y cho phÃ©p báº¡n tÄng Äá»
+chÃ­nh xÃ¡c cÃ¡c cÃ¢u truy váº¥n mÃ  báº¡n muá»n tÃ¬m. Báº¡n cÅ©ng cÃ³ thá» Äá»i sá»­ dá»¥ng tÃ­nh nÄng tÃ¬m kiáº¿m phÃ­a trÆ°á»c Äá» hiá»n thá» má»t vÃ i cÃ¢u truy váº¥n trÆ°á»c ÄÃ³, vÃ  do ÄÃ³ giÃºp báº¡n cÃ³ thá» chá»nh sá»­a cÃ¡c cÃ¢u truy
+váº¥n nÃ y Äá» cÃ³ cÃ¢u truy váº¥n má»i má»t cÃ¡ch dá»
+ dÃ ng. Cuá»i cÃ¹ng, báº¡n cÃ³ thá» Äiá»u khiá»n sá» káº¿t quáº£ tráº£ vá»
+vÃ  sá» dÃ²ng ÄÆ°á»£c hiá»n thá» má»i láº§n trÃªn mÃ n hÃ¬nh.
+}
+
+_texttanumbrowseoptions_ [l=vi] {CÃ³ _numbrowseoptions_ cÃ¡ch Äá» tÃ¬m kiáº¿m thÃŽng tin trong bá» sÆ°u táº­p nÃ y:}
+
+_textsimplehelpheading_ [l=vi] {TÃ¬m kiáº¿m thÃŽng tin trong bá» sÆ°u táº­p _collectionname_ nhÆ° tháº¿ nÃ o}
+
+_texthelpscope_ [l=vi] {<p>_iconblankbar_
+<a name=scope-of-queries>
+<h3 align=left>Pháº¡m vi cÃ¢u truy váº¥n</h3>
+
+<p>
+Trong háº§u háº¿t cÃ¡c bá» sÆ°u táº­p báº¡n cÃ³ thá» lá»±a chá»n cÃ¡c danh má»¥c tÃ¬m kiáº¿m khÃ¡c nhau.
+TÃ¬m kiáº¿m theo danh má»¥c tÃ¡c giáº£, tÃªn sÃ¡ch hoáº·c theo tá»«ng chÆ°Æ¡ng, tá»«ng Äoáº¡n. NÃ³i chung
+káº¿t quáº£ thá»a Äiá»u kiá»n nháº¥t sáºœ ÄÆ°á»£c tráº£ ra báº¥t ká» lÃ  báº¡n ÄÃ£ tÃ¬m kiáº¿m theo cÃ¡ch nÃ o.
+<p>Náº¿u tÃ i liá»u lÃ  sÃ¡ch thÃ¬ sáºœ ÄÆ°á»£c má» ra á» nÆ¡i thÃ­ch há»£p.
+}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/vietnamese2.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/vietnamese2.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/vietnamese2.dm	(revision 10506)
@@ -0,0 +1,958 @@
+# this file must be UTF-8 encoded
+######################################################################
+#
+# Vietnamese Language text and icon macros 
+# -- this file contains text that is of less importance
+# -- to translate when creating a new interface language
+######################################################################
+
+
+
+######################################################################
+# 'home' page
+package home
+######################################################################
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_documents_ [l=vi] {tÃ i liá»u. }
+_lastupdate_ [l=vi] {Cáº­p nháº­p láº§n cuá»i}
+_ago_ [l=vi] {cÃ¡ch ÄÃ¢y.}
+_colnotbuilt_ [l=vi] {Bá» sÆ°u táº­p khÃŽng ÄÆ°á»£c xÃ¢y dá»±ng.}
+
+_textpagetitle_ [l=vi] {Pháº§n má»m thÆ° viá»n sá» Greenstone}
+_textadmin_ [l=vi] {Trang quáº£n trá»}
+_textabgs_ [l=vi] {Giá»i thiá»u Greenstone}
+_textgsdocs_ [l=vi] {TÃ i liá»u Greenstone}
+
+_textimagegli_ [l=vi] {GiÃºp táº¡o bá» sÆ°u táº­p má»i, chá»nh sá»­a hoáº·c thÃªm má»i, hoáº·c xoÃ¡ bá» sÆ°u táº­p ÄÃ£ cÃ³}
+
+_textimagecollector_ [l=vi] {Chá»©c nÄng táº¡o má»i cÃ¡c bá» sÆ°u táº­p, thay Äá»i, thÃªm vÃ o hoáº·c xoÃ¡ cÃ¡c bá» sÆ°u táº­p ÄÃ£ tá»n táº¡i.
+}
+
+_textimagetranslator_ [l=vi] {Chá»©c nÄng lÆ°u giá»¯ cÃ¡c phiÃªn báº£n cá»§a Greenstone dÆ°á»i cÃ¡c dáº¡ng ngÃŽn ngá»¯ khÃ¡c nhau
+}
+
+_textimageadmin_ [l=vi] {Chá»©c nÄng táº¡o má»t tÃ i khoáº£n ngÆ°á»i dÃ¹ng má»i, tÃ³m táº¯t ná»i dung cÃ¡c bá» sÆ°u táº­p ÄÃ£ cÃ³ trong há» thá»ng, cung cáº¥p cÃ¡c thÃŽng tin ká»¹ thuáº­t vá» cÃ i Äáº·t pháº§n má»m Greenstone.
+}
+
+_textimagegogreenstone_ [l=vi] {Chá»©c nÄng cung cáº¥p cÃ¡c thÃŽng tin vá» pháº§n má»m Greenstone vÃ  dá»± Ã¡n New Zealand Digital Library nÆ¡i mÃ  pháº§n má»m ÄÆ°á»£c báº¯t nguá»n.
+}
+
+_textimagegodocs_ [l=vi] {TÃ i liá»u hÆ°á»ng dáº«n sá»­ dá»¥ng pháº§n má»m Greenstone}
+
+_textpoem_ [l=vi] {<br><h2>Kia papapounamu te moana</h2>
+
+<p>kia hora te marino,
+<br>kia tere te karohirohi,
+<br>kia papapounamu te moana
+
+<p>may peace and calmness surround you,
+<br>may you reside in the warmth of a summer's haze,
+<br>may the ocean of your travels be as smooth as the polished greenstone.
+}
+
+_textgreenstone_ [l=vi] {<p>Greenstone lÃ  má»t loáº¡i ÄÃ¡ quÃœ (giá»ng nhÆ° pháº§n má»m nÃ y) ÄÆ°á»£c tÃ¬m tháº¥y á» New Zealand. Trong vÄn hoÃ¡ truyá»n thá»ng Maori nÃ³ cÃ³ giÃ¡ trá» nháº¥t trong táº¥t cáº£ cÃ¡c váº­t cháº¥t ÄÆ°á»£c tÃ¬m tháº¥y. NÃ³ cÃ³ thá» háº¥p thá»¥ vÃ  chá»©a Äá»±ng <i> wairua</i>, má»t loáº¡i sá»©c máº¡nh tinh tháº§n ÄÆ°á»£c lÃ m giÃ u báº±ng nhá»¯ng giÃ¡ trá» truyá»n thá»ng, táº¥t cáº£ nhá»¯ng thá»© nÃ y táº¡o nÃªn má»t biá»u tÆ°á»£ng phÃ¹ há»£p cho dá»± Ã¡n thÆ° viá»n sá» nÃ y. Váº» Äáº¹p cá»§a nÃ³ toÃ¡t lÃªn sá»± nhÃ¢n Ã¡i, sá»± trong sÃ¡ng vÃ  tin cáº­y, sá»± kháº¯c nghiá»t, sá»± can Äáº£m vÃ  hÃ¬nh thÃ¹ cá»§a nÃ³ toÃ¡t lÃªn cáº£ sá»± cÃŽng báº±ng. Táº¥m kháº¯c ÄÆ°á»£c dÃ¹ng trÃªn logo cá»§a Greenstone ÄÆ°á»£c gá»i lÃ  <i>patu</i> - má»t vÅ© khÃ­ chiáº¿n Äáº¥u, ÄÃ¢y lÃ  má»t gia báº£o cá»§a má»t thÃ nh viÃªn trong dá»± Ã¡n. Trong chiáº¿n Äáº¥u, má»i thá»© pháº£i ÄÆ°á»£c phÃ¢n phá»i má»t cÃ¡ch nhanh chÃ³ng, chÃ­nh xÃ¡c vÃ  Äáº§y Äá»§. ChÃºng tÃŽi muá»n pháº§n má»m nÃ y cÅ©ng cÃ³ cÃ¡c tÃ­nh cháº¥t nÃ y. }
+
+_textaboutgreenstone_ [l=vi] {<p>Greenstone lÃ  má»t bá» pháº§n má»m dÃ¹ng  Äá» xÃ¢y dá»±ng vÃ  phÃ¢n phá»i cÃ¡c bá» sÆ°u táº­p thÆ° viá»n sá». NÃ³ cung cáº¥p má»t phÆ°Æ¡ng phÃ¡p má»i Äá» tá» chá»©c vÃ  xuáº¥t báº£n thÃŽng tin trÃªn Internet hoáº·c trÃªn CD-ROM. Greenstone lÃ  sáº£n pháº©m cá»§a dá»± Ã¡n <b>New Zealand Digital Library</b> cá»§a trÆ°á»ng Äáº¡i há»c <b>University of Waikato</b>, ÄÆ°á»£c phÃ¡t triá»n vÃ   phÃ¢n phá»i vá»i sá»± tham gia cá»§a <b>UNESCO</b> vÃ  <b>Human Info NGO</b>. ÄÃ¢y lÃ  pháº§n má»m mÃ£ nguá»n má» ÄÆ°á»£c cung cáº¥p trÃªn <a href="http://greenstone.org">http://greenstone.org</a> theo thoáº£ thuáº­n ÄÄng kÃ­ GNU General Public License.
+
+<p>Má»¥c tiÃªu cá»§a pháº§n má»m lÃ  cung cáº¥p cho ngÆ°á»i sá»­ dá»¥ng, Äáº·c biá»t lÃ  cÃ¡c trÆ°á»ng Äáº¡i há»c, cÃ¡c thÆ° viá»n hoáº·c trong cÃ¡c trá»¥ sá» cÃŽng cá»ng xÃ¢y dá»±ng cÃ¡c thÆ° viá»n sá» riÃªng cá»§a há». CÃ¡c thÆ° viá»n sá» lÃ m thay Äá»i nhanh chÃ³ng cÃ¡ch thá»©c thÃŽng tin ÄÆ°á»£c thu tháº­p vÃ  phá» biáº¿n trong cÃ¡c thÃ nh viÃªn cá»§a UNESCO vÃ  cÃ¡c trá»¥ sá» giÃ¡o dá»¥c, khoa há»c vÃ  vÄn hÃ³a trÃªn toÃ n tháº¿ giá»i, Äáº·c biá»t lÃ  á» cÃ¡c quá»c gia Äang phÃ¡t triá»n. ChÃºng tÃŽi hy vá»ng ráº±ng pháº§n má»m thÆ° viá»n sá» nÃ y sáºœ gia tÄng hiá»u quáº£ trong viá»c chia sáº» thÃŽng tin vÃ  cÃŽng bá» rá»ng rÃ£i chÃºng.
+
+
+<p>Pháº§n má»m nÃ y ÄÆ°á»£c phÃ¡t triá»n vÃ  phÃ¢n phá»i dÆ°á»i sá»± há»£p tÃ¡c hiá»u qá»§a giá»¯a ba bÃªn vÃ o thÃ¡ng 8 nÄm 2000.
+
+<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>
+Pháº§n má»m Greenstone ÄÆ°á»£c má» rá»ng tá»« dá»± Ã¡n nÃ y vÃ  Ãœ tÆ°á»ng ban Äáº§u cá»§a dá»± Ã¡n ÄÆ°á»£c phÃ¡t triá»n bá»i Communication Sub-Commission cá»§a New Zealand National Commission cho UNESCO nhÆ° lÃ  má»t pháº§n ÄÃ³ng ghÃ³p cá»§a New Zealand cho cÃ¡c chÆ°Æ¡ng trÃ¬nh cá»§a UNESCO.
+</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>
+Má»¥c tiÃªu chÃ­nh cá»§a UNESCO lÃ  quáº£ng bÃ¡ cÃ¡c thÃŽng tin vá» giÃ¡o dá»¥c, khoa há»c vÃ  vÄn hoÃ¡ trÃªn toÃ n tháº¿ giá»i, Äáº·c biá»t Äá»i cÃ¡c quá»c gia Äang phÃ¡t triá»n. Viá»c sá»­ dá»¥ng rá»ng rÃ£i cÃ¡c phÆ°Æ¡ng tiá»n thÃŽng tin liÃªn láº¡c ÄÆ°á»£c xem nhÆ° má»t cÃŽng cá»¥ quan trá»ng trong viá»c thá»±c thi má»¥c tiÃªu nÃ y
+</td>
+<td><a href="http://www.unesco.org"><img src="_httpimg_/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>
+ÄÃ¢y lÃ  dá»± Ã¡n há»£p tÃ¡c vá»i cÃ¡c cÆ¡ quan UN & NGOs. NÃ³ ÄÃ£ xÃ¢y dá»±ng ÄÆ°á»£c tiáº¿ng vang trÃªn kháº¯p tháº¿ giá»i trong viá»c sá» hoÃ¡ vÃ  phá» biáº¿n cÃ¡c tÃ i liá»u liÃªn quan Äáº¿n sá»± phÃ¡t triá»n cá»§a nhÃ¢n loáº¡i. 
+</td>
+<td><a href="http://humaninfo.org"><img src="_httpimg_/ghproj2.jpg" border="0"></a></td>
+</tr>
+</table>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "chá»n má»t bá» sÆ°u táº­p" ## green_bar_left_aligned ## selcolgr ##
+_httpiconselcolgr_ [l=vi] {_httpimg_/vi/selcolgr.gif}
+_widthselcolgr_ [l=vi] {537}
+_heightselcolgr_ [l=vi] {17}
+_altselcolgr_ [l=vi] {"Select a collection"}
+
+
+## "Giao diá»n thá»§ thÆ°" ## home_page_button ## cgli ##
+_httpiconcgliof_ [l=vi] {_httpimg_/vi/cgliof.gif}
+_httpiconcglion_ [l=vi] {_httpimg_/vi/cglion.gif}
+_widthcgli_ [l=vi] {100}
+
+## "Táº¡o bá» sÆ°u táº­p" ## home_page_button ## ccol ##
+_httpiconccolof_ [l=vi] {_httpimg_/vi/ccolof.gif}
+_httpiconccolon_ [l=vi] {_httpimg_/vi/ccolon.gif}
+_widthccol_ [l=vi] {100}
+
+## "Chuyá»n ngá»¯" ## home_page_button ## ctrans ##
+_httpiconctransof_ [l=vi] {_httpimg_/vi/ctransof.gif}
+_httpiconctranson_ [l=vi] {_httpimg_/vi/ctranson.gif}
+_widthctrans_ [l=vi] {100}
+
+## "Trang quáº£n trá»" ## home_page_button ## cadmin ##
+_httpiconcadminof_ [l=vi] {_httpimg_/vi/cadminof.gif}
+_httpiconcadminon_ [l=vi] {_httpimg_/vi/cadminon.gif}
+_widthcadmin_ [l=vi] {100}
+
+## "Giá»i thiá»u\nGreenstone" ## home_page_button ## cabgs ##
+_httpiconcabgsof_ [l=vi] {_httpimg_/vi/cabgsof.gif}
+_httpiconcabgson_ [l=vi] {_httpimg_/vi/cabgson.gif}
+_widthcabgs_ [l=vi] {100}
+
+## "TÃ i liá»u\nGreenstone" ## home_page_button ## cgsdoc ##
+_httpiconcgsdocof_ [l=vi] {_httpimg_/vi/cgsdocof.gif}
+_httpiconcgsdocon_ [l=vi] {_httpimg_/vi/cgsdocon.gif}
+_widthcgsdoc_ [l=vi] {100}
+
+
+######################################################################
+# home help page
+package homehelp
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_text4buts_ [l=vi] {CÃ³ bá»n nÃºt liÃªn káº¿t trÃªn trang chá»§}
+
+_textnocollections_ [l=vi] {<p>Hiá»n táº¡i khÃŽng cÃ³ bá» sÆ°u táº­p nÃ o dÃ¹ng ÄÆ°á»£c trÃªn báº£n cÃ i Äáº·t nÃ y. 
+Äá» thÃªm cÃ¡c bá» sÆ°u táº­p báº¡n pháº£i 
+<ul><li>Sá»­ dá»¥ng chá»©c nÄng <a href="_httppagecollector_">Táº¡o bá» sÆ°u táº­p</a> Äá» xÃ¢y dá»±ng má»i cÃ¡c bá» sÆ°u táº­p
+    <li>Náº¿u báº¡n cÃ³ má»t ÄÄ©a cd-rom Greenstone, ban cÃ³ thá» cÃ i Äáº·t cÃ¡c bá» sÆ°u táº­p tá»« cd-rom
+</ul>
+}
+
+_text1coll_ [l=vi] {Báº£n cÃ i Äáº·t nÃ y chá»©a 1 bá» sÆ°u táº­p}
+
+_textmorecolls_ [l=vi] {Báº£n cÃ i Äáº·t nÃ y chá»©a _1_  bá» sÆ°u táº­p}
+
+######################################################################
+# external link package
+package extlink
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textextlink_ [l=vi] {LiÃªn káº¿t bÃªn ngoÃ i}
+_textlinknotfound_ [l=vi] {LiÃªn káº¿t bÃªn trong khÃŽng tÃ¬m tháº¥y}
+
+_textextlinkcontent_ [l=vi] {LiÃªn káº¿t báº¡n chá»n lÃ  bÃªn ngoÃ i Äá»i vá»i bá» sÆ°u táº­p hiá»n táº¡i cá»§a báº¡n.
+    Náº¿u báº¡n váº«n muá»n xem liÃªn káº¿t nÃ y vÃ  trÃ¬nh duyá»t cá»§a báº¡n pháº£i truy xuáº¥t ÄÆ°á»£c Äáº¿n Web, báº¡n cÃ³
+    thá» <a href="_nexturl_">Äi tiáº¿p</a>Äáº¿n trang nÃ y; náº¿u khÃŽng báº¡n hÃ£y sá»­ dá»¥ng nÃºt "back" trÃªn trÃ¬nh duyá»t cá»§a báº¡n Äá» trá» vá» tÃ i liá»u trÆ°á»c. 
+    }
+
+_textlinknotfoundcontent_ [l=vi] {Má»t sá» nguyÃªn nhÃ¢n vÆ°á»£t khá»i táº§m kiá»m soÃ¡t cá»§a chÃºng ta, liÃªn káº¿t bÃªn trong 
+   báº¡n chá»n khÃŽng tá»n tÃ i. Äiá»u nÃ y cÃ³ thá» do má»t lá»i trong source bá» sÆ°u táº­p.
+   Sá»­ dá»¥ng nÃºt "back" trÃªn trÃ¬nh duyá»t cá»§a báº¡n Äá» chá» láº¡i tÃ i liá»u trÆ°á»c.
+}
+
+# should have arguments of collection, collectionname and link
+_foundintcontent_ [l=vi] {<h3>LiÃªn káº¿t Äáº¿n bá» sÆ°u táº­p "_2_"</h3>
+
+<p>LiÃªn káº¿t báº¡n chá»n náº±m bÃªn ngoÃ i bá» sÆ°u táº­p "_collectionname_".
+    Náº¿u báº¡n muá»n xem liÃªn káº¿t nÃ y trong bá» sÆ°u táº­p "_collectionname_" báº¡n cÃ³ thá» <a href="_httpdoc_&c=_1_&cl=_cgiargcl_&d=_3_">Äi tiáº¿p</a>
+    Äáº¿n trang nÃ y; máº·t khÃ¡c sá»­ dá»¥ng nÃºt "back" trÃªn trÃ¬nh duyá»t cá»§a báº¡n Äá» trá» vá» tÃ i liá»u trÆ°á»c.    
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+
+######################################################################
+# authentication page
+package authen
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textGSDLtitle_ [l=vi] {Pháº§n má»m thÆ° viá»n sá» Greenstone}
+
+_textusername_ [l=vi] {tÃªn ÄÄng nháº­p}
+_textpassword_ [l=vi] {máº­t kháº©u}
+
+_textmustbelongtogroup_ [l=vi] {ChÃº Ãœ ráº±ng báº¡n pháº£i thuá»c nhÃ³m quáº£n trá» má»i truy xuáº¥t ÄÆ°á»£c trang nÃ y.}
+
+_textmessageinvalid_ [l=vi] {Trang báº¡n yÃªu cáº§u ÄÃ²i há»i báº¡n pháº£i ÄÄng nháº­p.<br>
+_If_(_cgiargug_,[_textmustbelongtogroup_]<br>)
+Xin báº¡n vui lÃ²ng nháº­p tÃªn ÄÄng nháº­p vÃ  máº­t kháº©u.}
+
+_textmessagefailed_ [l=vi] {TÃªn ÄÄng nháº­p cá»§a báº¡n hoáº·c máº­t kháº©u bá» sai.}
+
+_textmessagedisabled_ [l=vi] {Xin lá»i, tÃ i khoáº£n cá»§a báº¡n ÄÃ£ bá» khoÃ¡. Vui lÃ²ng liÃªn há» vá»i ngÆ°á»i quáº£n trá».}
+
+_textmessagepermissiondenied_ [l=vi] {Xin lá»i, báº¡n khÃŽng cÃ³ quyá»n truy xuáº¥t trang nÃ y.}
+
+_textmessagestalekey_ [l=vi] {LiÃªn káº¿t nÃ y ÄÃ£ quÃ¡ cÅ©. Báº¡n vui lÃ²ng nháº­p máº­t kháº©u Äá» truy xuáº¥t trang nÃ y.}
+
+
+######################################################################
+# 'docs' page 
+package docs
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textnodocumentation_ [l=vi] {<p>Báº£n cÃ i Äáº·t nÃ y khÃŽng chá»©a báº¥t ká»³ má»t tÃ i liá»u hÆ°á»ng dáº«n nÃ o. Äiá»u nÃ y cÃ³ thá» do:
+<ol>
+ <li>Greenstone ÄÆ°á»£c cÃ i Äáº·t tá»« CD-ROM cÃ³ sá»­ dá»¥ng má»t thoáº£ thuáº­n cÃ i Äáº·t.
+ <li>Greenstone ÄÆ°á»£c cÃ i Äáº·t tá»« má»t Äiá»m phÃ¢n phá»i trÃªn máº¡ng Internet.
+</ol>
+Trong trÆ°á»ng há»£p nÃ y báº¡n cÃ³ thá» láº¥y tÃ i liá»u tá»« thÆ° má»¥c <i>docs</i> cá»§a ÄÄ©a CD-ROM Greenstone hoáº·c báº±ng cÃ¡ch truy cáº­p Äá»a <a
+href="http://www.greenstone.org">http://www.greenstone.org</a>.
+}
+
+_textuserguide_ [l=vi] {TÃ i liá»u hÆ°á»ng dáº«n sá»­ dá»¥ng}
+_textinstallerguide_ [l=vi] {TÃ i liá»u cÃ i Äáº·t pháº§n má»m}
+_textdeveloperguide_ [l=vi] {TÃ i liá»u cho ngÆ°á»i phÃ¡t triá»n bá» sÆ°u táº­p}
+_textpaperguide_ [l=vi] {Tá»« giáº¥y Äáº¿n bá» sÆ°u táº­p}
+_textorganizerguide_ [l=vi] {Sá»­ dá»¥ng chÆ°Æ¡ng trÃ¬nh Organizer}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "tÃ i liá»u greenstone" ## green_bar_left_aligned ## gsdocsgr ##
+_httpicongsdocsgr_ [l=vi] {_httpimg_/vi/gsdocsgr.gif}
+_widthgsdocsgr_ [l=vi] {_pagewidth_}
+_heightgsdocsgr_ [l=vi] {17}
+
+
+######################################################################
+# collectoraction
+package collector
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdefaultstructure_ [l=vi] {cáº¥u trÃºc máº·c Äá»nh}
+_textmore_ [l=vi] {nhiá»u hÆ¡n}
+_textcollector_ [l=vi] {Táº¡o bá» sÆ°u táº­p}
+_textinfo_ [l=vi] {ThÃŽng tin bá» sÆ°u táº­p}
+_textsrce_ [l=vi] {TÃ i liá»u nguá»n}
+_textconf_ [l=vi] {Cáº¥u hÃ¬nh bá» sÆ°u táº­p}
+_textbild_ [l=vi] {XÃ¢y dá»±ng}
+_textview_ [l=vi] {Xem}
+_textdel_ [l=vi] {xoÃ¡ bá» sÆ°u táº­p}
+_textexpt_ [l=vi] {xuáº¥t báº£n bá» sÆ°u táº­p}
+
+_textdownloadingfiles_ [l=vi] {Äang táº£i xuá»ng cÃ¡c táº­p tin ...}
+_textimportingcollection_ [l=vi] {Äang nháº­p bá» sÆ°u táº­p ...}
+_textbuildingcollection_ [l=vi] {Äang xÃ¢y dá»±ng bá» sÆ°u táº­p ...}
+_textcreatingcollection_ [l=vi] {Äang táº¡o bá» sÆ°u táº­p ...}
+
+_textcollectorblurb_ [l=vi] {<i>
+<br>Viá»c xÃ¢y dá»±ng vÃ  phÃ¢n phá»i bá» sÆ°u táº­p cÃ³ nhá»¯ng váº¥n Äá» mÃ  báº¡n cáº§n pháº£i náº¯m rÃµ trÆ°á»c khi tiáº¿n hÃ nh quÃ¡ trÃ¬nh tá»ng há»£p tÃ i liá»u. CÃ³ nhá»¯ng váº¥n Äá» phÃ¡p lÃ­: Báº¡n cÃ³ thá» truy cáº­p tÃ i liá»u nÃ y khÃŽng cÃ³ nghÄ©a lÃ  báº¡n cÃ³ thá» Äá» cho nhá»¯ng ngÆ°á»i khÃ¡c tá»± do xem tÃ i liá»u. CÃ³ nhá»¯ng váº¥n Äá» mang tÃ­nh xÃ£ há»i: CÃ¡c bá» sÆ°u táº­p pháº£i phÃ¹ há»£p vá»i thuáº§n phong má»¹ tá»¥c á» nÆ¡i phÃ¡t hÃ nh. CÃ³ nhá»¯ng váº¥n Äá» chá»§ng tá»c, nhá»¯ng thá»© ÄÆ¡n giáº£n lÃ  chÃºng ta khÃŽng thá» phÃ¡t hÃ nh rá»ng rÃ£i.
+<br>HÃ£y tháº­n trá»ng vá»i sá»©c máº¡nh cá»§a thÃŽng tin vÃ  sá»­ dá»¥ng chÃºng má»t cÃ¡ch ÄÃºng Äáº¯n
+</i>
+}
+
+_textcb1_ [l=vi] {Táº¡o bá» sÆ°u táº­p giÃºp báº¡n táº¡o má»i cÃ¡c bá» sÆ°u táº­p, thay Äá»i, thÃªm thÃŽng tin hoáº·c xÃ³a cÃ¡c bá» sÆ°u táº­p cÃ³ sáºµn. Äá» lÃ m ÄÆ°á»£c Äiá»u nÃ y báº¡n sáºœ ÄÆ°á»£c hÆ°á»ng dáº«n Äiá»n nhá»¯ng Äiá»n nhá»¯ng thÃŽng tin cáº§n thiáº¿t má»t cÃ¡ch tuáº§n tá»± vÃ o cÃ¡c trang Web yÃªu cáº§u.
+}
+
+_textcb2_ [l=vi] {Äáº§u tiÃªn báº¡n pháº£i chá»n má»t trong hai thao tÃ¡c sau}
+_textcnc_ [l=vi] {táº¡o má»i má»t bá» sÆ°u táº­p}
+_textwec_ [l=vi] {thÃªm dá»¯ liá»u vÃ o má»t bá» sÆ°u táº­p cÃ³ sáºµn hoáº·c xÃ³a bá» sÆ°u táº­p ÄÃ³.}
+
+_textcb3_ [l=vi] {Äá» xÃ¢y dá»±ng hoáº·c thay Äá»i cÃ¡c bá» sÆ°u táº­p thÆ° viá»n sá» báº¡n pháº£i ÄÄng nháº­p vÃ o há» thá»ng. Äiá»u nÃ y sáºœ báº£o vá» cÃ¡c thÃŽng tin cá»§a báº¡n khÃŽng bá» thay Äá»i bá»i nhá»¯ng ngÆ°á»i khÃ¡c sá»­ dá»¥ng mÃ¡y tÃ­nh cá»§a báº¡n. ChÃº Ãœ, vÃ¬ lÃœ do an ninh, báº¡n sáºœ bá» tá»± Äá»ng thoÃ¡t ra khá»i há» thá»ng 30 phÃºt sau khi ÄÃ£ ÄÄng nháº­p. Khi ÄÃ³, báº¡n Äá»«ng lo láº¯ng - báº¡n sáºœ ÄÆ°á»£c yÃªu cáº§u ÄÄng nháº­p láº¡i vÃ  tiáº¿p tá»¥c táº¡i vá» trÃ­ báº¡n ra khá»i há» thá»ng.
+}
+
+_textcb4_ [l=vi] {Vui lÃ²ng, nháº­p tÃªn ÄÄng nháº­p vÃ  máº­t kháº©u cá»§a báº¡n, sau ÄÃ³ nháº¥p chuá»t vÃ o nÃºt ÄÄng nháº­p.
+}
+
+_textfsc_ [l=vi] {Äáº§u tiÃªn báº¡n chá»n bá» sÆ°u táº­p mÃ  báº¡n muá»n lÃ m viá»c (cÃ¡c bá» sÆ°u táº­p khÃŽng ÄÆ°á»£c phÃ©p ghi sáºœ khÃŽng ÄÆ°á»£c liá»t kÃª á» ÄÃ¢y).
+}
+
+_textwtc_ [l=vi] {Vá»i bá» sÆ°u táº­p báº¡n ÄÃ£ chá»n, báº¡n cÃ³ thá»}
+_textamd_ [l=vi] {ThÃªm dá»¯ liá»u vÃ  xÃ¢y dá»±ng láº¡i bá» sÆ°u táº­p}
+_textetc_ [l=vi] {Chá»nh sá»­a táº­p tin cáº¥u hÃ¬nh cá»§a bá» sÆ°u táº­p vÃ  xÃ¢y dá»±ng láº¡i bá» sÆ°u táº­p}
+_textdtc_ [l=vi] {XoÃ¡ bá» sÆ°u táº­p}
+_textetcfcd_ [l=vi] {Xuáº¥t báº£n bá» sÆ°u táº­p ra CD-ROM}
+_textcaec_ [l=vi] {Chá»nh sá»­a bá» sÆ°u táº­p ÄÃ£ cÃ³}
+_textnwec_ [l=vi] {KhÃŽng tá»n táº¡i bá» sÆ°u táº­p cho phÃ©p chá»nh sá»­a}
+_textcianc_ [l=vi] {Táº¡o má»i má»t bá» sÆ°u táº­p}
+_texttsosn_ [l=vi] {Thá»© tá»± cÃ¡c bÆ°á»c cáº§n thiáº¿t Äá» táº¡o má»i bá» sÆ°u táº­p thÆ° viá»n sá» lÃ :}
+_textsin_ [l=vi] {XÃ¡c Äá»nh tÃªn cá»§a bá» sÆ°u táº­p (vÃ  thÃŽng tin liÃªn quan)}
+_textswts_ [l=vi] {XÃ¡c Äá»nh nÆ¡i láº¥y tÃ i liá»u nguá»n}
+_textatco_ [l=vi] {Chá»nh sá»­a cÃ¡c tÃ¹y chá»n cáº¥u hÃ¬nh (chá» dÃ nh cho ngÆ°á»i sá»­ dá»¥ng cáº¥p cao)}
+_textbtc_ [l=vi] {"XÃ¢y dá»±ng" bá» sÆ°u táº­p (xem pháº§n dÆ°á»i)}
+_textpvyh_ [l=vi] {Xem láº¡i cÃ¡c cÃŽng viá»c báº¡n ÄÃ£ lÃ m}
+
+_texttfsiw_ [l=vi] {BÆ°á»c thá»© tÆ° lÃ  bÆ°á»c mÃ  mÃ¡y tÃ­nh sáºœ lÃ m táº¥t cáº£ cÃ¡c cÃŽng viá»c. Trong quÃ¡ trÃ¬nh xÃ¢y dá»±ng mÃ¡y tÃ­nh táº¡o ra táº¥t cáº£ cÃ¡c chá» má»¥c vÃ  thu tháº­p cÃ¡c thÃŽng tin liÃªn quan. NhÆ°ng trÆ°á»c tiÃªn báº¡n pháº£i xÃ¡c Äá»nh thÃŽng tin.  
+}
+
+_textadab_ [l=vi] {Má»t sÆ¡ Äá» xuáº¥t hiá»n á» dÆ°á»i sáºœ giÃºp báº¡n nháº­n biáº¿t báº¡n Äang á» bÆ°á»c nÃ o. NÃºt mÃ u xanh lÃ¡ cÃ¢y lÃ  nÃºt mÃ  báº¡n nháº¥n vÃ o Äá» tiáº¿p tá»¥c. Khi báº¡n Äi theo tuáº§n tá»± cÃ¡c tráº¡ng thÃ¡i, cÃ¡c nÃºt sáºœ thay Äá»i sang mÃ u vÃ ng. Báº¡n cÃ³ thá» trá» vá» má»t trang trÆ°á»c ÄÃ³ báº±ng cÃ¡ch nháº¥n chuá»t vÃ o nÃºt mÃ u vÃ ng thÃ­ch há»£p trÃªn sÆ¡ Äá».
+}
+
+_textwyar_ [l=vi] {Khi báº¡n ÄÃ£ sáºµn sÃ ng, nháº¥n nÃºt mÃ u xanh lÃ¡ cÃ¢y âthÃŽng tin bá» sÆ°u táº­pâ Äá» báº¯t Äáº§u táº¡o bá» sÆ°u táº­p sá» má»i.
+}
+
+_textcnmbs_ [l=vi] {TÃªn bá» sÆ°u táº­p pháº£i ÄÆ°á»£c xÃ¡c Äá»nh}
+_texteambs_ [l=vi] {Äá»a chá» Email pháº£i ÄÆ°á»£c xÃ¡c Äá»nh}
+_textpsea_ [l=vi] {XÃ¡c Äá»nh Äá»a chá» emai theo máº«u: username@domain}
+_textdocmbs_ [l=vi] {MÃŽ táº£ vá» bá» sÆ°u táº­p pháº£i ÄÆ°á»£c xÃ¡c Äá»nh}
+
+_textwcanc_ [l=vi] {Khi táº¡o má»i má»t bá» sÆ°u táº­p báº¡n cáº§n nháº­p má»t sá» thÃŽng tin sÆ¡ bá» vá» tÃ i liá»u nguá»n. QuÃ¡ trÃ¬nh xÃ¢y dá»±ng ÄÆ°á»£c cáº¥u trÃºc nhÆ° lÃ  má»t loáº¡t cÃ¡c trang web ÄÆ°á»£c giÃ¡m sÃ¡t bá»i chá»©c nÄng XÃ¢y dá»±ng bá» sÆ°u táº­p.
+}
+
+_texttfc_ [l=vi] {TÃªn bá» sÆ°u táº­p:}
+
+_texttctiasp_ [l=vi] {TiÃªu Äá» cá»§a bá» sÆ°u táº­p lÃ  má»t nhÃ³m tá»« ngáº¯n ÄÆ°á»£c sá»­ dá»¥ng trong chÆ°Æ¡ng trÃ¬nh nháº±m xÃ¡c Äá»nh ná»i dung cá»§a bá» sÆ°u táº­p. VÃ­ dá»¥ cÃ¡c tiÃªu Äá» sau: âComputer Science Technical Reportsâ vÃ  "Humanity Development Library".
+}
+
+_textcea_ [l=vi] {Äá»a chá» email liÃªn há»:}
+
+_textteas_ [l=vi] {Äá»a chá» email nÃ y lÃ  Äiáº¡ chá» liÃªn há» cá»§a bá» sÆ°u táº­p. Khi bá» sÆ°u táº­p gáº·p trá»¥c tráº·c, má»t bÃ¡o cÃ¡o cháº©n ÄoÃ¡n sáºœ ÄÆ°á»£c gá»­i tá»i Äá»a chá» nÃ y. Nháº­p má»t Äá»a chá» email theo máº«u Äáº§y Äá»§: <tt>name@domain</tt>.
+}
+
+_textatc_ [l=vi] {Giá»i thiá»u vá» bá» sÆ°u táº­p:}
+
+_texttiasd_ [l=vi] {ÄÃ¢y lÃ  má»t cÃ¢u diá»
+n táº£ cÃ¡c nguyÃªn táº¯c bao trÃ¹m bá» sÆ°u táº­p. NÃ³ sáºœ xuáº¥t hiá»n trÃªn trang Äáº§u khi bá» sÆ°u táº­p ÄÆ°á»£c trÃ¬nh bÃ y.
+}
+
+_textypits_ [l=vi] {Vá» trÃ­ cá»§a báº¡n theo thá»© tá»± ÄÆ°á»£c chá» ra bá»i má»t mÅ©i tÃªn á» dÆ°á»i - trong trÆ°á»ng há»£p nÃ y lÃ  tráº¡ng thÃ¡i âThÃŽng tin bá» sÆ°u táº­pâ. Äá» tiáº¿p tá»¥c, nháº¥n chuá»t vÃ o nÃºt mÃ u xanh lÃ¡ cÃ¢y âTÃ i liá»u nguá»nâ. 
+}
+
+_srcebadsources_ [l=vi] {<p>CÃ³ má»t hoáº·c nhiá»u tÃ i liá»u nguá»n báº¡n xÃ¡c Äá»nh lÃ  khÃŽng há»£p lá» (ÄÃ¡nh dáº¥u
+_iconcross_ á» dÆ°á»i).
+
+<p>Äiá»u nÃ y cÃ³ thá» lÃ  do
+<ul>
+<li>Táº­p tin, vá» trÃ­ FTP hoáº·c URL khÃŽng tá»n táº¡i.
+<li>Báº¡n cáº§n pháº£i káº¿t ná»i vÃ o máº¡ng Internet trÆ°á»c
+<li>Báº¡n Äang cá» truy xuáº¥t tá»« bÃªn trong má»t firewall (Äiá»u nÃ y xáº£y ra khi báº¡n thÆ°á»ng pháº£i cung cáº¥p tÃªn ÄÄng nháº­p vÃ  máº­t kháº©u Äá» truy cáº­p Interner).
+</ul>
+
+<p>Náº¿u trang Äá»a chá» URL nÃ y cÃ³ thá» nhÃ¬n tháº¥y tá»« trÃ¬nh duyá»t cá»§a báº¡n, nÃ³ cÃ³ thá» lÃ  má»t báº£n sao ÄÆ°á»£c lÆ°u trong mÃ¡y cá»¥c bá». Tháº­t ÄÃ¡ng tiáº¿c, cÃ¡c báº£n sao nÃ y thÃ¬ láº¡i hoÃ n toÃ n há»£p lá» Äá»i vá»i cÃ¡c quÃ¡ trÃ¬nh xá»­ lÃœ cá»§a chÃºng tÃŽi. Trong trÆ°á»ng há»£p nÃ y chÃºng tÃŽi khuyÃªn báº¡n táº£i xuá»ng láº¡i cÃ¡c trang Äang sá»­ dá»¥ng bá»i trÃ¬nh duyá»t cá»§a báº¡n trÆ°á»c.
+}
+
+_textymbyco_ [l=vi] {<p>Báº¡n chá»n má»t trong hai cáº¥u trÃºc sau Äá» xÃ¢y dá»±ng bá» sÆ°u táº­p cá»§a mÃ¬nh.
+<ul>
+<li>Cáº¥u trÃºc máº·c Äá»nh
+<dl><dd>Bá» sÆ°u táº­p má»i pháº£i chá»©a tÃ i liá»u dáº¡ng hmtl (.htm, .html), tÃ i liá»u dáº¡ng vÄn báº£n (.txt, .text), tÃ i liá»u dáº¡ng Word (.doc), tÃ i liá»u dáº¡ng PDF (.pdf) hoáº·c tÃ i liá»u dáº¡ng email (.mbx).</dd></dl>
+<li>Má»t bá» sÆ°u táº­p ÄÃ£ cÃ³ sáºµn
+<dl><dd>CÃ¡c táº­p tin trong bá» sÆ°u táº­p má»i cá»§a báº¡n pháº£i cÃ³ kiá»u giá»ng vá»i nhá»¯ng táº­p tin ÄÆ°á»£c dÃ¹ng Äá» xÃ¢y dá»±ng bá» sÆ°u táº­p ÄÃ£ cÃ³.</dd></dl>
+</ul>
+}
+
+_textbtco_ [l=vi] {XÃ¢y dá»±ng bá» sÆ°u táº­p trÃªn}
+_textand_ [l=vi] {ThÃªm má»i dá»¯ liá»u}
+_textad_ [l=vi] {Äang thÃªm dá»¯ liá»u:}
+
+_texttftysb_ [l=vi] {CÃ¡c táº­p tin mÃ  báº¡n xÃ¡c Äá»nh á» dÆ°á»i sáºœ ÄÆ°á»£c thÃªm vÃ o bá» sÆ°u táº­p. HÃ£y kiá»m tra xem báº¡n cÃ³ Äang thÃªm vÃ o má»t táº­p tin sáºµn cÃ³ trong bá» sÆ°u táº­p khÃŽng, náº¿u trÆ°á»ng há»£p ÄÃ³ xáº£y ra, cáº£ 3 táº­p tin sáºœ Äá»u náº±m trong bá» sÆ°u táº­p. CÃ¡c táº­p tin ÄÆ°á»£c xÃ¡c Äá»nh thÃŽng qua ÄÆ°á»ng dáº«n Äáº§y Äá»§, cÃ¡c trang Web ÄÆ°á»£c xÃ¡c Äá»nh thÃŽng qua Äá»a chá» Web.
+}
+
+_textis_ [l=vi] {TÃ i liá»u nguá»n:}
+
+_textddd1_ [l=vi] {<p>Náº¿u báº¡n sá»­ dá»¥ng file:// hoáº·c ftp:// Äá» xÃ¡c Äá»nh má»t táº­p tin, thÃ¬ táº­p tin ÄÃ³ sáºœ ÄÆ°á»£c láº¥y vá».
+
+<p>Náº¿u báº¡n sá»­ dá»¥ng http:// thÃ¬ tÃ¹y theo URL báº¡n sáºœ nháº­n má»t trang hoáº·c nhiá»u trang web. Khi má»t trang ÄÆ°á»£c láº¥y vá» thÃ¬ táº¥t cáº£ cÃ¡c trang mÃ  liÃªn káº¿t trá»±c tiáº¿p hoáº·c giÃ¡n tiáº¿p vá»i nÃ³ cÅ©ng ÄÆ°á»£c láº¥y xuá»ng. 
+
+<p>Khi báº¡n sá»­ dá»¥ng file:// hoáº·c ftp:// Äá» xÃ¡c Äá»nh má»t thÆ° má»¥c, hoáº·c cung cáº¥p má»t http:// URL mÃ  chá» Äáº¿n má»t danh sÃ¡ch cÃ¡c táº­p tin, thÃ¬ má»i thá»© trong thÆ° má»¥c vÃ  táº¥t cáº£ cÃ¡c thÆ° má»¥c con cá»§a nÃ³ sáºœ ÄÆ°á»£c ÄÆ°a vÃ o bá» sÆ°u táº­p. 
+
+<p>Nháº¥n chuá»t vÃ o nÃºt âThÃªm tÃ i liá»uâ Äá» cÃ³ nhiá»u há»p nháº­p liá»u hÆ¡n.
+}
+
+_textddd2_ [l=vi] {<p>Nháº¥n chuá»t má»t láº§n vÃ o cÃ¡c nÃºt mÃ u xanh lÃ¡ cÃ¢y. Náº¿u báº¡n lÃ  ngÆ°á»i sá»­ dá»¥ng cáº¥p cao báº¡n cÃ³ thá» chá»nh sá»­a cáº¥u hÃ¬nh cá»§a bá» sÆ°u táº­p. NgÆ°á»£c láº¡i, báº¡n Äáº¿n bÆ°á»c xÃ¢y dá»±ng bá» sÆ°u táº­p. Báº¡n cÃ³ thá» quay láº¡i cÃ¡c bÆ°á»c trÆ°á»c ÄÃ³ báº±ng cÃ¡ch nháº¥n chuá»t vÃ o nÃºt mÃ u vÃ ng.
+}
+
+_textconf1_ [l=vi] {<p>Viá»c xÃ¢y dá»±ng vÃ  trÃ¬nh bÃ y bá» sÆ°u táº­p cá»§a báº¡n ÄÆ°á»£c Äiá»u khiá»n báº±ng cÃ¡c xÃ¡c láº­p trong má»t táº­p tin cáº¥u hÃ¬nh Äáº·c biá»t. NgÆ°á»i sá»­ dá»¥ng cáº¥p cao cÃ³ thá» thay Äá»i cÃ¡c xÃ¡c láº­p ÄÃ³.
+
+<center><p><b>Náº¿u khÃŽng, báº¡n cÃ³ thá» di chuyá»n xuá»ng cuá»i trang.</b></center> 
+
+<p>Äá» thay tháº¿ cÃ¡c xÃ¡c láº­p cáº¥u hÃ¬nh cÃ³ sáºµn, báº¡n hÃ£y thay tháº¿ dá»¯ liá»u xuáº¥t hiá»n á» dÆ°á»i. Khi bá» sai, báº¡n nháº¥n chuá»t vÃ o âLÃ m láº¡iâ Äá» láº¥y láº¡i cÃ¡c xÃ¡c láº­p ban Äáº§u.
+}
+
+_textreset_ [l=vi] {LÃ m láº¡i}
+
+_textbild1_ [l=vi] {Bá» sÆ°u táº­p bÃ¢y giá» Äang ÄÆ°á»£c xÃ¢y dá»±ng: tiáº¿n trÃ¬nh nÃ y cáº§n khoáº£ng thá»i gian Äá» hoÃ n táº¥t. DÃ²ng tráº¡ng thÃ¡i trong tiáº¿n trÃ¬nh á» dÆ°á»i pháº£n Ã¡nh quÃ¡ trÃ¬nh cÃŽng viá»c ÄÆ°á»£c thá»±c hiá»n.
+}
+
+_textbild2_ [l=vi] {Äá» dá»«ng tiáº¿n trÃ¬nh xÃ¢y dá»±ng vÃ o báº¥t ká»³ lÃºc nÃ o, nháº¥n chuá»t vÃ o ÄÃ¢y.<br>Bá» sÆ°u táº­p báº¡n Äang lÃ m viá»c sáºœ ÄÆ°á»£c giá»¯ nguyÃªn, khÃŽng thay Äá»i.
+}
+
+_textstopbuild_ [l=vi] {dá»«ng xÃ¢y dá»±ng}
+
+_textbild3_ [l=vi] {Náº¿u báº¡n rá»i khá»i trang nÃ y (vÃ  chÆ°a há»§y bá» tiáº¿n trÃ¬nh xÃ¢y dá»±ng vá»i nÃºt âDá»«ng xÃ¢y dá»±ngâ) bá» sÆ°u táº­p váº«n tiáº¿p tá»¥c xÃ¢y dá»±ng vÃ  sáºœ ÄÆ°á»£c tiáº¿n thÃ nh cho Äáº¿n khi hoÃ n táº¥t.
+}
+
+_textbuildcancelled_ [l=vi] {QuÃ¡ trÃ¬nh xÃ¢y dá»±ng ÄÃ£ há»§y bá»}
+
+_textbildcancel1_ [l=vi] {Bá» sÆ°u táº­p Äang trong quÃ¡ trÃ¬nh xÃ¢y dá»±ng bá» há»§y bá». Sá»­ dá»¥ng cÃ¡c nÃºt mÃ u vÃ ng Äá» lÃ m cÃ¡c thay Äá»i hoáº·c khá»i Äá»ng láº¡i quÃ¡ trÃ¬nh xÃ¢y dá»±ng.
+}
+
+_textbsupdate1_ [l=vi] {Tráº¡ng thÃ¡i Äang xÃ¢y dá»±ng cáº­p nháº­t trong 1 giÃ¢y}
+_textbsupdate2_ [l=vi] {Tráº¡ng thÃ¡i Äang xÃ¢y dá»±ng cáº­p nháº­t trong}
+_textseconds_ [l=vi] {giÃ¢y}
+_textbildsuc_ [l=vi] {Bá» sÆ°u táº­p ÄÃ£ xÃ¢y dá»±ng thÃ nh cÃŽng.}
+
+_textviewbildsummary_ [l=vi] {Báº¡n nÃªn <a href="_httppagex_(bsummary)&c=_cgiargbc1dirname_" target=_top>xem tÃ³m táº¯t quÃ¡ trÃ¬nh xÃ¢y dá»±ng</a> bá» sÆ°u táº­p nÃ y Äá» nháº­n nhiá»u thÃŽng tin chi tiáº¿t hÆ¡n.
+}
+
+_textfailmsg11_ [l=vi] {Bá» sÆ°u táº­p khÃŽng thá» ÄÆ°á»£c xÃ¢y dá»±ng khi nÃ³ khÃŽng chá»©a dá»¯ liá»u. Báº¡n cháº¯c cháº¯n tá»i thiá»u má»t thÆ° má»¥c hoáº·c táº­p tin báº¡n xÃ¡c Äá»nh trÃªn <i>tÃ i liá»u nguá»n</i> lÃ  tá»n táº¡i vÃ  ÄÃºng Äá»nh dáº¡ng hoáº·c chá»©a cÃ¡c táº­p tin ÄÃºng Äá»nh dáº¡ng (trong trÆ°á»ng há»£p lÃ  thÆ° má»¥c).
+}
+
+_textfailmsg21_ [l=vi] {Bá» sÆ°u táº­p khÃŽng thá» xÃ¢y dá»±ng (import.pl tháº¥t báº¡i).}
+_textblcont_ [l=vi] {Táº­p tin build log chá»©a nhá»¯ng thÃŽng tin sau:}
+
+_texttryagain_ [l=vi] {Vui lÃ²ng <a href="_httppagecollector_" target=_top>khá»i Äá»ng láº¡i chá»©c nÄng xÃ¢y dá»±ng bá» sÆ°u táº­p</a>
+ vÃ  thá»­ láº¡i.
+}
+
+_textfailmsg31_ [l=vi] {Bá» sÆ°u táº­p khÃŽng thá» xÃ¢y dá»±ng (buildcol.pl tháº¥t báº¡i).}
+_textfailmsg41_ [l=vi] {Bá» sÆ°u táº­p ÄÆ°á»£c xÃ¢y dá»±ng thÃ nh cÃŽng nhÆ°ng khÃŽng thá» cÃ i Äáº·t.}
+_textfailmsg71_ [l=vi] {Má»t lá»i xáº£y ra trong khi cÃ³ gáº¯ng xÃ¢y dá»±ng bá» sÆ°u táº­p cá»§a báº¡n}
+_textretcoll_ [l=vi] {Quay láº¡i Táº¡o bá» sÆ°u táº­p}
+
+_textdelperm_ [l=vi] {Má»t sá» hoáº·c táº¥t cáº£ _cgiargbc1dirname_ bá» sÆ°u táº­p khÃŽng thá» ÄÆ°á»£c xoÃ¡. NguyÃªn nhÃ¢n cÃ³ thá» lÃ :
+<ul>
+<li> Greenstone khÃŽng cÃ³ quyá»n xoÃ¡ thÆ° má»¥c _gsdlhome_/collect/_cgiargbc1dirname_ .
+<br>
+Báº¡n cáº§n tá»± tay xoÃ¡ bá» thÆ° má»¥c nÃ y Äá» hoÃ n táº¥t viá»c xoÃ¡ bá» sÆ°u táº­p _cgiargbc1dirname_
+.</li>
+<li>Greenstone khÃŽng thá» cháº¡y chÆ°Æ¡ng trÃ¬nh _gsdlhome_/bin/script/delcol.pl. Báº¡n pháº£i báº£o Äáº£m táº­p tin nÃ y cÃ³ thá» Äá»c vÃ  thá»±c thi.</li>
+</ul>
+}
+
+_textdelinv_ [l=vi] {Bá» sÆ°u táº­p _cgiargbc1dirname_ ÄÆ°á»£c báº£o vá» hoáº·c khÃŽng há»£p lá». QuÃ¡ trÃ¬nh xoÃ¡ ÄÆ°á»£c huá»· bá».
+}
+
+_textdelsuc_ [l=vi] {Bá» sÆ°u táº­p _cgiargbc1dirname_ ÄÆ°á»£c xoÃ¡ thÃ nh cÃŽng.}
+
+_textclonefail_ [l=vi] {Bá» sÆ°u táº­p _cgiargclonecol_ khÃŽng thá» sao chÃ©p. NguyÃªn nhÃ¢n cÃ³ thá» lÃ :
+<ul>
+<li> Bá» sÆ°u táº­p _cgiargclonecol_ khÃŽng tá»n tÃ i
+<li> Bá» sÆ°u táº­p _cgiargclonecol_ khÃŽng cÃ³ táº­p tin cáº¥u hÃ¬nh collect.cfg
+<li> Greenstone khÃŽng cÃ³ quyá»n Äá»c táº­p tin cáº¥u hÃ¬nh collect.cfg
+</ul>
+}
+
+_textcolerr_ [l=vi] {XÃ¢y dá»±ng bá» sÆ°u táº­p bá» lá»i.}
+
+_texttmpfail_ [l=vi] {XÃ¢y dá»±ng bá» sÆ°u táº­p khÃŽng thá» Äá»c hoáº·c ghi tá»« táº­p tin hoáº·c thÆ° má»¥c táº¡m thá»i. NguyÃªn nhÃ¢n cÃ³ thá» lÃ :
+<ul>
+<li> Greenstone khÃŽng thá» Äá»c hoáº·c ghi trÃªn thÆ° má»¥c _gsdlhome_/tmp.
+</ul>
+}
+
+_textmkcolfail_ [l=vi] {XÃ¢y dá»±ng bá» sÆ°u táº­p khÃŽng thá» táº¡o cáº¥u trÃºc thÆ° má»¥c theo yÃªu cáº§u cá»§a bá» sÆ°u táº­p má»i (mkcol.pl tháº¥t báº¡i). NguyÃªn nhÃ¢n cÃ³ thá» lÃ :
+<ul>
+<li> Greenstone khÃŽng cÃ³ quyá»n ghi trÃªn thÆ° má»¥c _gsdlhome_/tmp.
+<li> mkcol.pl perl script cÃ³ lá»i.
+</ul>
+}
+
+_textnocontent_ [l=vi] {Bá» sÆ°u táº­p bá» lá»i: báº¡n khÃŽng cung cáº¥p tÃªn cho bá» sÆ°u táº­p má»i. HÃ£y khá»i Äá»ng láº¡i quÃ¡ trÃ¬nh xÃ¢y dá»±ng bá» sÆ°u táº­p tá»« Äáº§u.
+}
+
+_textrestart_ [l=vi] {Báº¯t Äáº§u táº¡o bá» sÆ°u táº­p}
+
+_textreloaderror_ [l=vi] {Má»t lá»i xáº£y ra trong khi táº¡o má»t bá» sÆ°u táº­p má»i. Äiá»u nÃ y xáº£y ra Greenstone khÃŽng phÃ¢n biá»t ÄÆ°á»£c nÃºt "reload" hoáº·c nÃºt "back" trÃªn trÃ¬nh duyá»t cá»§a báº¡n (báº¡n nÃªn trÃ¡nh sá»­ dá»¥ng nhá»¯ng nÃºt nÃ y trong khi táº¡o bá» sÆ°u táº­p). Báº¡n nÃªn báº¯t Äáº§u láº¡i quÃ¡ trÃ¬nh xÃ¢y dá»±ng bá» sÆ°u táº­p.
+}
+
+_textexptsuc_ [l=vi] {Bá» sÆ°u táº­p _cgiargbc1dirname_ export thÃ nh cÃŽng Äáº¿n thÆ° má»¥c _gsdlhome_/tmp/exported\__cgiargbc1dirname_.
+}
+
+_textexptfail_ [l=vi] {<p>Export tháº¥t báº¡i bá» sÆ°u táº­p _cgiargbc1dirname_.
+
+<p>Äiá»u nÃ y hÃ¬nh nhÆ° lÃ  do Greenstone ÄÆ°á»£c cÃ i Äáº·t mÃ  khÃŽng cÃ³ cÃ¡c thÃ nh pháº§n cáº§n thiáº¿t Äá» há» trá»£ chá»©c nÄng  "Truy xuáº¥t Collection".
+<ul>
+
+ <li>Khi báº¡n cÃ i Äáº·t Greenstone tá»« CD-ROM cÃ¡c thÃ nh pháº§n nÃ y sáºœ khÃŽng ÄÆ°á»£c ÄÆ°á»£c cÃ i Äáº·t máº·c nhiÃªn báº¡n pháº£i chá»n chÃºng trong má»¥c "Custom". Báº¡n cÃ³ thá» thÃªm chÃºng trong báº£n cÃ i Äáº·t cá»§a báº¡n báº±ng cÃ¡ch cháº¡y láº¡i thá»§ tá»¥c cÃ i Äáº·t.
+
+ <li>Khi báº¡n cÃ i Äáº·t Greenstone tá»« má»t Äiá»m phÃ¢n phá»i trÃªn Internet báº¡n cáº§n táº£i xuá»ng vÃ  cÃ i Äáº·t thÃªm cÃ¡c gÃ³i cho phÃ©p sá»­ dá»¥ng chá»©c nÄng nÃ y. LiÃªn há» trang web nÃ y <a href="http://www.greenstone.org">http://www.greenstone.org</a> hoáº·c Äá»a chá» email <a
+ href="mailto:greenstone@cs.waikato.ac.nz">greenstone@cs.waikato.ac.nz</a> Äá» biáº¿t thÃªm chi tiáº¿t.
+
+</ul>
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+## "Táº¡o bá» sÆ°u táº­p" ## green_title ## h_colect ##
+_httpiconhcolect_ [l=vi] {_httpimg_/vi/h\_colect.gif}
+
+## "thÃŽng tin bá»\nsÆ°u táº­p" ## collector_bar_button ## info ##
+_httpicongcinfoof_ [l=vi] {_httpimg_/vi/gcinfoof.gif}
+_httpicongcinfoon_ [l=vi] {_httpimg_/vi/gcinfoon.gif}
+_httpiconycinfoof_ [l=vi] {_httpimg_/vi/ycinfoof.gif}
+_httpiconycinfoon_ [l=vi] {_httpimg_/vi/ycinfoon.gif}
+_httpiconncinfoof_ [l=vi] {_httpimg_/vi/ncinfoof.gif}
+
+## "tÃ i liá»u nguá»n" ## collector_bar_button ## srce ##
+_httpicongcsrceof_ [l=vi] {_httpimg_/vi/gcsrceof.gif}
+_httpicongcsrceon_ [l=vi] {_httpimg_/vi/gcsrceon.gif}
+_httpiconycsrceof_ [l=vi] {_httpimg_/vi/ycsrceof.gif}
+_httpiconycsrceon_ [l=vi] {_httpimg_/vi/ycsrceon.gif}
+_httpiconncsrceof_ [l=vi] {_httpimg_/vi/ncsrceof.gif}
+
+## "cáº¥u hÃ¬nh bá»\nsÆ°u táº­p" ## collector_bar_button ## conf ##
+_httpicongcconfof_ [l=vi] {_httpimg_/vi/gcconfof.gif}
+_httpicongcconfon_ [l=vi] {_httpimg_/vi/gcconfon.gif}
+_httpiconycconfof_ [l=vi] {_httpimg_/vi/ycconfof.gif}
+_httpiconycconfon_ [l=vi] {_httpimg_/vi/ycconfon.gif}
+_httpiconncconfof_ [l=vi] {_httpimg_/vi/ncconfof.gif}
+
+## "xÃ¢y dá»±ng bá»\nsÆ°u táº­p" ## collector_bar_button ## bild ##
+_httpicongcbildof_ [l=vi] {_httpimg_/vi/gcbildof.gif}
+_httpicongcbildon_ [l=vi] {_httpimg_/vi/gcbildon.gif}
+_httpiconycbildof_ [l=vi] {_httpimg_/vi/ycbildof.gif}
+_httpiconycbildon_ [l=vi] {_httpimg_/vi/ycbildon.gif}
+_httpiconncbildof_ [l=vi] {_httpimg_/vi/ncbildof.gif}
+
+## "xem bá»\nsÆ°u táº­p" ## collector_bar_button ## view ##
+_httpicongcviewof_ [l=vi] {_httpimg_/vi/gcviewof.gif}
+_httpicongcviewon_ [l=vi] {_httpimg_/vi/gcviewon.gif}
+_httpiconycviewof_ [l=vi] {_httpimg_/vi/ycviewof.gif}
+_httpiconycviewon_ [l=vi] {_httpimg_/vi/ycviewon.gif}
+_httpiconncviewof_ [l=vi] {_httpimg_/vi/ncviewof.gif}
+
+## "xoÃ¡ bá»\nsÆ°u táº­p" ## collector_bar_button ## del ##
+_httpicongcdelof_ [l=vi] {_httpimg_/vi/gcdelof.gif}
+_httpicongcdelon_ [l=vi] {_httpimg_/vi/gcdelon.gif}
+
+## "xuáº¥t báº£n bá»\nsÆ°u táº­p" ## collector_bar_button ## expt ##
+_httpicongcexptof_ [l=vi] {_httpimg_/vi/gcexptof.gif}
+_httpicongcexpton_ [l=vi] {_httpimg_/vi/gcexpton.gif}
+
+
+######################################################################
+# 'gsdl' page
+package gsdl
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textgreenstone1_ [l=vi] {Greenstone lÃ  má»t bá» pháº§n má»m dÃ¹ng  Äá» xÃ¢y dá»±ng vÃ  phÃ¢n phá»i cÃ¡c digital library collections. NÃ³ cung cáº¥p má»t phÆ°Æ¡ng phÃ¡p má»i Äá» tá» chá»©c vÃ  xuáº¥t báº£n thÃŽng tin trÃªn Internet hoáº·c trÃªn CD-ROM. Greenstone lÃ  sáº£n pháº©m cá»§a dá»± Ã¡n New Zealand Digital Library cá»§a trÆ°á»ng Äáº¡i há»c University of Waikato, ÄÆ°á»£c phÃ¡t triá»n vÃ   phÃ¢n phá»i vá»i sá»± tham gia cá»§a UNESCO vÃ  Human Info NGO. ÄÃ¢y lÃ  pháº§n má»m mÃ£ nguá»n má» ÄÆ°á»£c cung cáº¥p trÃªn <i>http://greenstone.org</i> theo thoáº£ thuáº­n cá»§a GNU General Public License.
+}
+
+_textgreenstone2_ [l=vi] {Äá»a chá» trang web cá»§a New Zealand Digital Library (<a
+href="http://nzdl.org">http://nzdl.org</a>) chá»©a nhiá»u bá» sÆ°u táº­p máº«u, táº¥t cáº£ chÃºng ÄÆ°á»£c táº¡o vá»i pháº§n má»m Greenstone, cÃ¡i mÃ  ÄÆ°á»£c cÃŽng bá» rá»ng rÃ£i cho báº¡n nghiÃªn cá»©u. Táº¥t cáº£ cÃ¡c bá» sÆ°u táº­p máº«u ÄÆ°á»£c minh hoáº¡ báº±ng nhiá»u vÃ­ dá»¥ khÃ¡c nhau vá» tÃ¬m kiáº¿m vÃ  hiá»n thá» cÃ¡c tÃ¹y chá»n vÃ  bao gá»m nhiá»u bá» sÆ°u táº­p báº±ng tiáº¿ng Arabic, Chinese, French, Maori vÃ  Spanish cÅ©ng nhÆ° tiáº¿ng English. CÅ©ng cÃ³ cáº£ cÃ¡c bá» sÆ°u táº­p vá» Ã¢m nháº¡c.
+}
+
+_textplatformtitle_ [l=vi] {cáº¥u hÃ¬nh ná»n}
+_textgreenstone3_ [l=vi] {Greenstone cháº¡y trÃªn Windows, Unix vÃ  Mac OS X. Viá»c phÃ¢n phá»i bao gá»m cÃ¡c báº£n cÃ i Äáº·t cho táº¥t cáº£ cÃ¡c phiÃªn báº£n cá»§a Windows, Linux vÃ  Mac OS X. NÃ³ cÅ©ng cung cáº¥p toÃ n bá» source code cá»§a há» thá»ng Äá» ngÆ°á»i sá»­ dá»¥ng cÃ³ thá» biÃªn dá»ch láº¡i báº±ng Microsoft C++ hoáº·c gcc. Pháº§n má»m Äi kÃšm vá»i Greenstone cÅ©ng Äá»u miá»
+n phÃ­, vÃ­ dá»¥ nhÆ° Apache Webserver vÃ  PERL. Giao diá»n ngÆ°á»i sá»­ dá»¥ng dÃ¹ng má»t Web browser Äiá»n hÃ¬nh lÃ  Netscape Navigator hoáº·c Internet Explorer.
+}
+
+_textgreenstone4_ [l=vi] {Nhiá»u bá» sÆ°u táº­p tÃ i liá»u ÄÆ°á»£c cung cáº¥p trÃªn CD-ROM cho viá»c sá»­ dá»¥ng pháº§n má»m Greenstone. VÃ­ dá»¥,  <i>Humanity Development</i> chá»©a 1.230 tÃ i liá»u tá»« káº¿ toÃ¡n tÃ i chÃ­nh cho Äáº¿n váº¥n Äá» an toÃ n nguá»n nÆ°á»c. NÃ³ cháº¡y trÃªn cÃ¡c mÃ¡y tÃ­nh cáº¥u hÃ¬nh tháº¥p chÄáº³ng háº¡n nhÆ° nhá»¯ng cÃ¡i thÆ°á»ng dÃ¹ng á» cÃ¡c nÆ°á»c Äang phÃ¡t triá»n. ThÃŽng tin cÃ³ thá» ÄÆ°á»£c truy xuáº¥t báº±ng cÃ¡ch tÃ¬m kiáº¿m, trÃ¬nh duyá»t dá»±a trÃªn chá»§ Äá», tÃªn tiÃªu Äá», tÃªn tá» chá»©c xuáº¥t báº£n, danh sÃ¡ch cÃ¡c gá»£i Ãœ hoáº·c xem bÃ¬a sÃ¡ch má»t cÃ¡ch tÃ¹y Ãœ.
+}
+
+_textcustomisationtitle_ [l=vi] {tÃ¹y chá»nh}
+_textgreenstone5_ [l=vi] {Greenstone ÄÆ°á»£c thiáº¿t káº¿ Äá» dá»
+ má» rá»ng vÃ  chá»nh sá»­a. CÃ¡c Äá»nh dáº¡ng má»i cá»§a má»t tÃ i liá»u vÃ  metadata ÄÆ°á»£c cung cáº¥p báº±ng cÃ¡ch viáº¿t âpluginsâ (trong Perl). TÆ°Æ¡ng tá»±, viá»c duyá»t cáº¥u trÃºc cá»§a metadata cÃ³ thá» thá»±c hiá»n báº±ng cÃ¡ch viáº¿t âclassifiersâ. Giao diá»n ngÆ°á»i sá»­ dá»¥ng cÃ³ thá» ÄÆ°á»£c thay tháº¿ báº±ng cÃ¡ch viáº¿t cÃ¡c âmacrosâ. Giao thá»©c Corba cho phÃ©p cÃ¡c chÆ°Æ¡ng trÃ¬nh thÃŽng minh (vÃ­ dá»¥ trong Java) sá»­ dá»¥ng táº¥t cáº£ cÃ¡c tiá»n Ã­ch Äi kÃšm vá»i bá» sÆ°u táº­p. Cuá»i cÃ¹ng, source code báº±ng C++ vÃ  Perl ÄÆ°á»£c cung cáº¥p miá»
+n phÃ­ vÃ  cho phÃ©p sá»­a Äá»i.
+}
+
+_textdocumentationtitle_ [l=vi] {tÃ i liá»u}
+_textdocuments_ [l=vi] {TÃ i liá»u viáº¿t thÃªm cho pháº§n má»m Greenstone lÃ  há»£p phÃ¡p.}
+
+#_textthreedocs_ {There are three documents that explain the Greenstone system:}
+#_textinstall_ {The Greenstone Digital Library Software Installer's Guide}
+#_textuser_ {The Greenstone Digital Library Software User's Guide}
+#_textdevelop_ {The Greenstone Digital Library Software Developer's Guide}
+
+_textmailinglisttitle_ [l=vi] {danh sÃ¡ch Äá»a chá» mail}
+_textmailinglist_ [l=vi] {CÃ³ má»t danh sÃ¡ch nhá»¯ng Äá»a chá» nháº­n thÃŽng tin thÆ°á»ng xuyÃªn mÃ  má»¥c ÄÃ­ch chÃ­nh lÃ  Äá» tháº£o luáº­n vá» pháº§n má»m thÆ° viá»n sá» Greenstone. Nhá»¯ng ngÆ°á»i sá»­ dá»¥ng cá»§a Greenstone nÃªn nÄng Äá»ng tham gia nháº­n thÃŽng tin thÆ°á»ng xuyÃªn vÃ  tÃ­ch cá»±c tham gia tháº£o luáº­n. Äá» ÄÄng kÃœ, truy cáº­p Äá»a chá»<a href="https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users">https://list.scms.waikato.ac.nz/mailman/listinfo/greenstone-users</a>. Äá» gá»­i thÃŽng tin Äáº¿n nhÃ³m gá»­i qua Äá»a chá» nÃ y <a
+href="mailto:greenstone-users@list.scms.waikato.ac.nz"
+>greenstone-users@list.scms.waikato.ac.nz</a>.
+}
+
+_textbugstitle_ [l=vi] {lá»i}
+_textreport_ [l=vi] {ChÃºng tÃŽi muá»n báº£o Äáº£m ráº±ng pháº§n má»m nÃ y lÃ m viá»c tá»t. Báº¡n vui lÃ²ng thÃŽng bÃ¡o cÃ¡c lá»i Äáº¿n <a href="mailto:greenstone-users@list.scms.waikato.ac.nz"
+>greenstone-users@list.scms.waikato.ac.nz</a>. 
+}
+
+_textgs3title_ [l=vi] {cÃŽng viá»c}
+_textgs3_ [l=vi] {Greenstone 3 lÃ  má»t thiáº¿t káº¿ vÃ  cÃ i Äáº·t láº¡i nÃ³ chá»©a táº¥t cáº£ cÃ¡c tÃ­nh nÄng tiÃªn tiáº¿n cá»§a Greenstone 2 (phiÃªn báº£n hiá»n táº¡i). NÃ³ káº¿t há»£p táº¥t cáº£ cÃ¡c Äáº·c Äiá»m cá»§a há» thá»ng ÄÃ£ tá»n táº¡i vÃ  tÆ°Æ¡ng thÃ­ch vá»i táº¥t cáº£ cÃ¡c há» thá»ng trÆ°á»c, ÄÃ³ lÃ  nÃ³ cÃ³ thá» xÃ¢y dá»±ng vÃ  cháº¡y trÃªn cÃ¡c bá» sÆ°u táº­p ÄÃ£ cÃ³ mÃ  khÃŽng pháº£i chá»nh sá»­a. NÃ³ ÄÆ°á»£c viáº¿t báº±ng Java vÃ  ÄÆ°á»£c xÃ¢y dá»±ng nhÆ° má»t thÃ nh pháº§n máº¡ng Äá»c láº­p sá»­ dá»¥ng XML Äá» truyá»n thÃŽng. Nhá»¯ng tÃ­nh nÄng nÃ y giÃºp Greenstone gia tÄng tÃ­nh kháº£ chuyá»n vÃ  má» rá»ng. PhiÃªn báº£n má»i ÄÆ°á»£c mong Äá»£i ÄÆ°a vÃ o sá»­ dá»¥ng thá»±c táº¿ vÃ o ngÃ y 23 thÃ¡ng 12 nÄm 2003. Ã tÆ°á»ng thiáº¿t káº¿ ban Äáº§u cá»§a há» thá»ng ÄÆ°á»£c phÃ¡c tháº£o trÃªn "The design of Greenstone 3: An agent based dynamic digital library" (<a href="http://www.greenstone.org/manuals/gs3design.pdf">PDF</a>). 
+}
+
+_textcreditstitle_ [l=vi] {ghi nháº­n}
+
+_textwhoswho_ [l=vi] {Pháº§n má»m Greenstone lÃ  má»t káº¿t há»£p hiá»u quáº£ giá»¯a nhiá»u ngÆ°á»i. Rodger McNab vÃ  Stefan Boddie lÃ  nhá»¯ng kiáº¿n trÃºc sÆ° vÃ  ngÆ°á»i thá»±c hiá»n chÃ­nh. Nhá»¯ng ngÆ°á»i cá»ng tÃ¡c thá»±c hiá»n bao gá»m: 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. Má»t sá» thÃ nh viÃªn khÃ¡c cá»§a dá»± Ã¡n New Zealand Digital Library ÄÃ£ cung cáº¥p lá»i khuyÃªn vÃ  Ãœ tÆ°á»ng trong thiáº¿t káº¿ cá»§a há» thá»ng: Mark Apperley, Sally Jo Cunningham, Matt Jones, Steve Jones, Te Taka Keegan, Michel Loots, Malika Mahoui, Gary Marsden, Dave Nichols and Lloyd Smith. ChÃºng tÃŽi cÅ©ng muá»n cáº£m Æ¡n táº¥t cáº£ nhá»¯ng ngÆ°á»i ÄÃ£ gÃ³p pháº§n ÄÆ°a cÃ¡c gÃ³i cÃ³ báº£n quyá»n cá»§a GNU vÃ o trong báº£n phÃ¢n phá»i nÃ y: MG, GDBM, PDFTOHTML, WGET, WVWARE and XLHTML. 
+}
+
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "giá»i thiá»u vá» pháº§n má»m greenstone" ## green_bar_left_aligned ## abgsgr ##
+_httpiconabgsgr_ [l=vi] {_httpimg_/vi/abgsgr.gif}
+_widthabgsgr_ [l=vi] {_pagewidth_}
+_heightabgsgr_ [l=vi] {17}
+
+
+######################################################################
+# 'users' page
+package userslistusers
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textlocu_ [l=vi] {Danh sÃ¡ch ngÆ°á»i sá»­ dá»¥ng hiá»n táº¡i}
+_textuser_ [l=vi] {ngÆ°á»i sá»­ dá»¥ng
+}
+_textas_ [l=vi] {tÃ¬nh tráº¡ng tÃ i khoáº£n}
+_textgroups_ [l=vi] {nhÃ³m}
+_textcomment_ [l=vi] {chÃº thÃ­ch}
+_textadduser_ [l=vi] {thÃªm ngÆ°á»i sá»­ dá»¥ng}
+_textedituser_ [l=vi] {chá»nh sá»­a}
+_textdeleteuser_ [l=vi] {xoÃ¡}
+
+
+######################################################################
+# 'users' page
+package usersedituser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textedituser_ [l=vi] {Chá»nh sá»­a thÃŽng tin ngÆ°á»i dÃ¹ng}
+_textadduser_ [l=vi] {ThÃªm ngÆ°á»i sá»­ dá»¥ng}
+
+_textaboutusername_ [l=vi] {TÃªn ÄÄng nháº­p pháº£i dÃ i tá»« 2 Äáº¿n 30 kÃœ tá»±. ChÃºng cÃ³ thá» chá»©a cÃ¡c kÃœ tá»±, chá»¯ sá», '.' vÃ  '_'.
+}
+
+_textaboutpassword_ [l=vi] {Máº­t kháº©u pháº£i dÃ i tá»« 3 Äáº¿n 8 kÃœ tá»±. ChÃºng chá» chá»©a cÃ¡c kÃœ tá»± ASCII in ÄÆ°á»£c thÃŽng thÆ°á»ng.
+}
+
+_textoldpass_ [l=vi] {Náº¿u trÆ°á»ng nÃ y trá»ng máº­t kháº©u cÅ© sáºœ ÄÆ°á»£c bá» qua.}
+_textenabled_ [l=vi] {cho phÃ©p}
+_textdisabled_ [l=vi] {khÃŽng cho phÃ©p}
+
+_textaboutgroups_ [l=vi] {CÃ¡c nhÃ³m phÃ¢n biá»t bá»i dáº¥u pháº©y, khÃŽng Äáº·t khoáº£ng tráº¯ng sau dáº¥u pháº©y.
+}
+
+
+######################################################################
+# 'users' page
+package usersdeleteuser
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textdeleteuser_ [l=vi] {XoÃ¡ ngÆ°á»i sá»­ dá»¥ng}
+_textremwarn_ [l=vi] {Báº¡n cÃ³ tháº­t sá»± muá»n xoÃ¡ ngÆ°á»i sá»­ dá»¥ng khÃŽng <b>_cgiargumun_</b>?}
+
+
+######################################################################
+# 'users' page
+package userschangepasswd
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textchangepw_ [l=vi] {Thay Äá»i máº­t kháº©u}
+_textoldpw_ [l=vi] {máº­t kháº©u cÅ©}
+_textnewpw_ [l=vi] {máº­t kháº©u má»i}
+_textretype_ [l=vi] {ÄÃ¡nh láº¡i máº­t kháº©u má»i}
+
+
+######################################################################
+# 'users' page
+package userschangepasswdok
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textsuccess_ [l=vi] {Máº­t kháº©u ÄÃ£ ÄÆ°á»£c thay Äá»i thÃ nh cÃŽng.}
+
+
+######################################################################
+# 'users' page
+package users
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textinvalidusername_ [l=vi] {TÃªn ÄÄng nháº­p khÃŽng tá»n táº¡i.}
+_textinvalidpassword_ [l=vi] {Máº­t kháº©u bá» sai.}
+_textemptypassword_ [l=vi] {Vui lÃ²ng nháº­p láº¡i máº­t kháº©u cho ngÆ°á»i dÃ¹ng nÃ y.}
+_textuserexists_ [l=vi] {NgÆ°á»i sá»­ dá»¥ng nÃ y ÄÃ£ tá»n táº¡i, báº¡n nháº­p tÃªn ÄÄng nháº­p khÃ¡c.}
+
+_textusernameempty_ [l=vi] {Vui lÃ²ng nháº­p tÃªn ÄÄng nháº­p.}
+_textpasswordempty_ [l=vi] {Báº¡n pháº£i nháº­p máº­t kháº©u cÅ©.}
+_textnewpass1empty_ [l=vi] {Báº¡n nháº­p máº­t kháº©u má»i sau ÄÃ³ ÄÃ¡nh láº¡i má»t láº§n ná»¯a.}
+_textnewpassmismatch_ [l=vi] {2 máº­t kháº©u báº¡n nháº­p vÃ o khÃŽng khá»p.}
+_textnewinvalidpassword_ [l=vi] {Báº¡n nháº­p má»t máº­t kháº©u khÃŽng cÃ³ giÃ¡ trá».}
+_textfailed_ [l=vi] {TÃªn ÄÄng nháº­p hoáº·c máº­t kháº©u cá»§a báº¡n bá» sai.}
+
+
+######################################################################
+# 'status' pages
+package status
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+
+_textversion_ [l=vi] {Sá» phiÃªn báº£n Greenstone }
+_textframebrowser_ [l=vi] {Báº¡n pháº£i cÃ³ trÃ¬nh duyá»t hiá»n thá» ÄÆ°á»£c frame.}
+_textusermanage_ [l=vi] {Quáº£n lÃœ ngÆ°á»i dÃ¹ng}
+_textlistusers_ [l=vi] {danh sÃ¡ch ngÆ°á»i dÃ¹ng}
+_textaddusers_ [l=vi] {thÃªm ngÆ°á»i dÃ¹ng má»i}
+_textchangepasswd_ [l=vi] {thay Äá»i máº­t kháº©u}
+_textinfo_ [l=vi] {ThÃŽng tin ká»¹ thuáº­t}
+_textgeneral_ [l=vi] {thÃŽng tin chung}
+_textarguments_ [l=vi] {Äá»i sá»}
+_textactions_ [l=vi] {hoáº¡t Äá»ng}
+_textbrowsers_ [l=vi] {cÃ¡ch hiá»n thá»}
+_textprotocols_ [l=vi] {cÃ¡c qui Æ°á»c}
+_textconfigfiles_ [l=vi] {CÃ¡c táº­p tin cáº¥u hÃ¬nh}
+_textlogs_ [l=vi] {Nháº­t kÃœ}
+_textusagelog_ [l=vi] {nháº­t kÃœ sá»­ dá»¥ng}
+_textinitlog_ [l=vi] {nháº­t kÃœ khá»i Äá»ng}
+_texterrorlog_ [l=vi] {nháº­t kÃœ lá»i}
+_textadminhome_ [l=vi] {Trang quáº£n trá»}
+_textreturnhome_ [l=vi] {Trang chá»§ Greenstone}
+_titlewelcome_ [l=vi] {Quáº£n trá» }
+_textmaas_ [l=vi] {CÃ¡c dá»ch vá»¥ duy trÃ¬ vÃ  quáº£n trá» ngÆ°á»i dÃ¹ng bao gá»m:}
+_textvol_ [l=vi] {Xem nháº­t kÃœ on-line}
+_textcmuc_ [l=vi] {táº¡o, duy trÃ¬ vÃ  cáº­p nháº­t cÃ¡c bá» sÆ°u táº­p}
+_textati_ [l=vi] {truy xuáº¥t cÃ¡c thÃŽng tin ká»¹ thuáº­t vÃ­ dá»¥ nhÆ° cÃ¡c Äá»i sá» CGI}
+
+_texttsaa_ [l=vi] {Nhá»¯ng dá»ch vá»¥ nÃ y ÄÆ°á»£c truy xuáº¥t sá»­ dá»¥ng cÃ¡c thanh Äiá»u khiá»n á» bÃªn trÃ¡i cá»§a trang.
+}
+
+_textcolstat_ [l=vi] {TÃ¬nh tráº¡ng bá» sÆ°u táº­p}
+
+_textcwoa_ [l=vi] {CÃ¡c bá» sÆ°u táº­p sáºœ chá» xuáº¥t hiá»n nhÆ° lÃ  âÄang cháº¡yâ náº¿u cÃ¡c táº­p tin build.cfg tá»n táº¡i, cÃ³ thá» Äá»c, chá»©a trÆ°á»ng ngÃ y xÃ¢y dá»±ng há»£p lá» vÃ  náº±m trong thÆ° má»¥c quáº£n lÃœ cá»§a bá» sÆ°u táº­p.
+}
+
+_textcafi_ [l=vi] {nháº¥n vÃ o <i>abbrev.</i> Äá» xem thÃŽng tin chi tiáº¿t cá»§a má»t bá» sÆ°u táº­p.}
+_textcctv_ [l=vi] {nháº¥n vÃ o  <i>collection</i> Äá» xem tá»ng quan vá» bá» sÆ°u táº­p.}
+_textsubc_ [l=vi] {Cáº­p nháº­t cÃ¡c thay Äá»i}
+_texteom_ [l=vi] {Má» táº­p tin main.cfg lá»i}
+_textftum_ [l=vi] {Cáº­p nháº­t táº­p tin main.cfg tháº¥t báº¡i}
+_textmus_ [l=vi] {main.cfg cáº­p nháº­p thÃ nh cÃŽng}
+
+
+######################################################################
+# 'bsummary' pages
+package bsummary
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+
+_textbsummary_ [l=vi] {TÃ³m táº¯t quÃ¡ trÃ¬nh xÃ¢y dá»±ng bá» sÆ°u táº­p _collectionname_ }
+_textflog_ [l=vi] {Ghi nháº­t kÃœ tháº¥t báº¡i cho bá» sÆ°u táº­p _collectionname_}
+
+
+############################################################################
+#
+# This stuff is only used by the usability (I'd like to Complain) stuff
+#
+############################################################################
+package Global
+
+_greenstoneusabilitytext_ [l=vi] {Tiá»n Ã­ch Greenstone}
+
+_textwhy_ [l=vi] {<p>Gá»­i bÃ¡o cÃ¡o nÃ y lÃ  cÃ¡ch chá» ra báº¡n Äang gáº·p khÃ³ khÄn hoáº·c tháº¥t báº¡i.}
+_textextraforform_ [l=vi] {Báº¡n khÃŽng pháº£i Äiá»n vÃ o máº«u -- báº¥t ká»³ thÃŽng tin giÃºp Äá»¡.}
+_textprivacybasic_ [l=vi] {<p>BÃ¡o cÃ¡o sáºœ chá» chá»©a cÃ¡c thÃŽng tin vá» trang web Greenstone báº¡n Äang xem vÃ  ká»¹ thuáº­t báº¡n Äang sá»­ dá»¥ng Äá» xem nÃ³ (vÃ  báº¥t cá»© thÃŽng tin báº¡n cung cáº¥p).}
+_textstillsend_ [l=vi] {Báº¡n váº«n muá»n gá»­i bÃ¡o cÃ¡o nÃ y?}
+
+_texterror_ [l=vi] {lá»i}
+_textyes_ [l=vi] {Muá»n}
+_textno_ [l=vi] {KhÃŽng}
+_textclosewindow_ [l=vi] {ÄÃ³ng cá»­a sá»}
+_textabout_ [l=vi] {Giá»i thiá»u}
+_textprivacy_ [l=vi] {RiÃªng tÆ°}
+_textsend_ [l=vi] {Gá»­i}
+_textdontsend_ [l=vi] {KhÃŽng gá»­i}
+_textoptionally_ [l=vi] {Tuá»³ chá»n}
+
+_textunderdev_ [l=vi] {Chi tiáº¿t ÄÆ°á»£c trÃ¬nh bÃ y trong phiÃªn báº£n cuá»i cÃ¹ng.}
+
+_textviewdetails_ [l=vi] {Xem bÃ¡o cÃ¡o chi tiáº¿t}
+_textmoredetails_ [l=vi] {Chi tiáº¿t hÆ¡n}
+_texttrackreport_ [l=vi] {Theo dÃµi bÃ¡o cÃ¡o nÃ y}
+_textcharacterise_ [l=vi] {Váº¥n Äá» gáº·p pháº£i lÃ  gÃ¬?}
+_textseverity_ [l=vi] {Má»©c Äá» nghiÃªm trá»ng nhÆ° tháº¿ nÃ o}
+ 
+_textbadrender_ [l=vi] {Trang nhÃ¬n cÃ³ váº» khÃŽng bÃ¬nh thÆ°á»ng}
+_textcontenterror_ [l=vi] {Lá»i ná»i dung }
+_textstrangebehaviour_ [l=vi] {Hoáº¡t Äá»ng má»t cÃ¡ch kÃ¬ láº¡}
+_textunexpected_ [l=vi] {Má»t viá»c khÃŽng mong Äá»£i ÄÃ£ xáº£y ra}
+_textfunctionality_ [l=vi] {KhÃ³ xá»­ dá»¥ng}
+_textother_ [l=vi] {Nhá»¯ng váº¥n Äá» khÃ¡c}
+
+_textcritical_ [l=vi] {Nháº­n xÃ©t}
+_textmajor_ [l=vi] {Quan trá»ng}
+_textmedium_ [l=vi] {BÃ¬nh thÆ°á»ng}
+_textminor_ [l=vi] {Thá»© yáº¿u}
+_texttrivial_ [l=vi] {Hiá»n nhiÃªn}
+
+_textwhatdoing_ [l=vi] {Báº¡n Äang Äá»nh lÃ m gÃ¬?}
+_textwhatexpected_ [l=vi] {Báº¡n mong Äá»£i cÃ¡i gÃ¬ sáºœ xáº£y ra?}
+_textwhathappened_ [l=vi] {Äiá»u gÃ¬ tháº­t sá»± xáº£y ra?}
+
+_cannotfindcgierror_ [l=vi] {<h2>Xin lá»i!</h2> KhÃŽng tÃ¬m ÄÆ°á»£c chÆ°Æ¡ng trÃ¬nh chá»§ cho nÃºt "TÃŽi muá»n khiáº¿u náº¡i".}
+
+_textusabbanner_ [l=vi] {the Greenstone koru-style banner}
+
+
+######################################################################
+# GTI text strings
+package gti
+######################################################################
+
+
+#------------------------------------------------------------
+# text macros
+#------------------------------------------------------------
+	
+# -- Missing translation: _textgti_
+
+# -- Missing translation: _textgtierror_
+
+# -- Missing translation: _textgtihome_
+
+# -- Missing translation: _textgtiselecttlc_
+
+# -- Missing translation: _textgtiselecttfk_
+
+# -- Missing translation: _textgticoredm_
+# -- Missing translation: _textgtiauxdm_
+# -- Missing translation: _textgtiglidict_
+# -- Missing translation: _textgtiperlmodules_
+# -- Missing translation: _textgtigreenorg_
+
+# -- Missing translation: _textgtienter_
+
+# -- Missing translation: _textgticorrectexistingtranslations_
+# -- Missing translation: _textgtidownloadtargetfile_
+# -- Missing translation: _textgtiviewtargetfileinaction_
+
+# -- Missing translation: _textgtinumchunksmatchingquery_
+
+# -- Missing translation: _textgtinumchunkstranslated_
+# -- Missing translation: _textgtinumchunksrequiringupdating_
+# -- Missing translation: _textgtinumchunksrequiringtranslation_
+
+# -- Missing translation: _textgtienterquery_
+# -- Missing translation: _textgtifind_
+
+# -- Missing translation: _textgtitranslatingchunk_
+# -- Missing translation: _textgtiupdatingchunk_
+# -- Missing translation: _textgtisubmit_
+
+# -- Missing translation: _textgtilastupdated_
+
+# -- Missing translation: _textgtitranslationfilecomplete_
+
+
+############
+# gli page
+############
+package gli
+
+_textgli_ [l=vi] {Giao diá»n thá»§ thÆ°}
+_textglihelp_ [l=vi] {Giao diá»n thá»§ thÆ° (GLI) cung cáº¥p cho báº¡n giao diá»n dá»
+ dÃ ng sá»­ dá»¥ng cÃ¡c chá»©c nÄng cá»§a Greenstone hÆ¡n. NÃ³ cho phÃ©p báº¡n táº­p há»£p tÃ i liá»u nguá»n, ÄÆ°a vÃ o hoáº·c chá» Äá»nh siÃªu dá»¯ liá»u vÃ  xÃ¢y dá»±ng bá» sÆ°u táº­p.
+ <p>
+ChÃº Ãœ ráº±ng GLI ÄÆ°á»£c cháº¡y káº¿t há»£p vá»i Greenstone vÃ  cháº¯c cháº¯n ráº±ng nÃ³ ÄÆ°á»£c cÃ i Äáº·t trong thÆ° má»¥c con cá»§a thÆ° má»¥c cÃ i Äáº·t Greenstone.  DÆ°á»i ÄÃ¢y sáºœ lÃ  má»t sá» hÆ°á»ng dáº«n náº¿u báº¡n cÃ i Äáº·t tá»« má»t trong nhá»¯ng báº£n phÃ¢n phá»i cá»§a Greenstone hoáº·c tá»« má»t CD-ROM Greenstone.
+ 
+ 
+<h4>Cháº¡y GLI trÃªn Windows</h4>
+ 
+Cháº¡y giao diá»n thá»§ thÆ° trÃªn Windows báº±ng cÃ¡ch chá»n <i>Start\Programs\Greenstone Digital Library\Librarian Interface</i>. 
+
+ 
+<h4>Cháº¡y GLI trÃªn Unix</h4>
+ 
+Äá» cháº¡y GLI trÃªn Unix chuyá»n thÆ° má»¥c Äáº¿n thÆ° má»¥c <i>gli</i> trong thÆ° má»¥c cÃ i Äáº·t Greenstone sau ÄÃ³ cháº¡y táº­p tin <i>gli.sh</i>. 
+ 
+<h4>Cháº¡y GLI trÃªn Mac OS X</h4>
+
+Trong cÃŽng cá»¥ tÃ¬m kiáº¿m duyá»t thÆ° má»¥c Äáº¿n <i>Applications</i> sau ÄÃ³ lÃ  <i>Greenstone</i>
+(náº¿u báº¡n cÃ i Äáº·t Greenstone vÃ o thÆ° má»¥c máº·c Äá»nh) vÃ  cháº¡y á»©ng dá»¥ng <i>GLI</i>.
+}
+
+#------------------------------------------------------------
+# icons
+#------------------------------------------------------------
+
+
+## "giao diá»n thá»§ thÆ°" ## green_bar_left_aligned ## gligr ##
+_httpicongligr_ [l=vi] {_httpimg_/vi/gligr.gif}
+_widthgligr_ [l=vi] {_pagewidth_}
+_heightgligr_ [l=vi] {17}
Index: /tags/gsdl-2_61-distribution/gsdl/macros/yourhome-es.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/yourhome-es.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/yourhome-es.dm	(revision 10506)
@@ -0,0 +1,40 @@
+# this file must be UTF-8 encoded
+
+package home
+_content_ {
+
+<h2>Su propia pÃ¡gina principal para Greenstone</h2>
+
+<ul>
+<table>
+<tr valign=top><td>PÃ¡gina de bÃºsqueda para la colecciÃ³n demo<br></td>
+    <td><a href="_httpquery_&c=demo">Presione aquÃ­</a></td></tr>
+
+<tr><td>PÃ¡gina Â«sobreÂ» para la colecciÃ³n demo</td>
+    <td><a href="_httppageabout_&c=demo">Presione aquÃ­</a></td></tr>
+
+<tr><td>PÃ¡gina de preferencias para la colecciÃ³n demo</td>
+    <td><a href="_httppagepref_&c=demo">Presione aquÃ­</a></td></tr>
+
+<tr><td>PÃ¡gina principal</td>
+    <td><a href="_httppagehome_">Presione aquÃ­</a></td></tr>
+
+<tr><td>PÃ¡gina de ayuda</td>
+    <td><a href="_httppagehelp_">Presione aquÃ­</a></td></tr>
+
+<tr><td>PÃ¡gina de administraciÃ³n</td>
+    <td><a href="_httppagestatus_">Presione aquÃ­</a></td></tr>
+
+<tr><td>El Collector</td>
+    <td><a href="_httppagecollector_">Presione aquÃ­</a></td></tr>
+
+</table>
+</ul>
+
+}
+
+# if you hate the squirly green bar down the left-hand side of the page,
+# uncomment these lines:
+
+# _header_ { 
+# }
Index: /tags/gsdl-2_61-distribution/gsdl/macros/yourhome-fr.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/yourhome-fr.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/yourhome-fr.dm	(revision 10506)
@@ -0,0 +1,40 @@
+# this file must be UTF-8 encoded
+
+package home
+_content_ {
+
+<h2>Votre propre page d'accueil pour Greenstone</h2>
+
+<ul>
+<table>
+<tr valign=top><td>Page de recherche pour la collection demo<br></td>
+    <td><a href="_httpquery_&c=demo">Cliquez ici</a></td></tr>
+
+<tr><td>Page Â«Ã  proposÂ» pour la collection demo</td>
+    <td><a href="_httppageabout_&c=demo">Cliquez ici</a></td></tr>
+
+<tr><td>Page de prÃ©fÃ©rences pour la collection demo</td>
+    <td><a href="_httppagepref_&c=demo">Cliquez ici</a></td></tr>
+
+<tr><td>Page d'accueil</td>
+    <td><a href="_httppagehome_">Cliquez ici</a></td></tr>
+
+<tr><td>Page d'aide</td>
+    <td><a href="_httppagehelp_">Cliquez ici</a></td></tr>
+
+<tr><td>Page d'administration</td>
+    <td><a href="_httppagestatus_">Cliquez ici</a></td></tr>
+
+<tr><td>Le Collector</td>
+    <td><a href="_httppagecollector_">Cliquez ici</a></td></tr>
+
+</table>
+</ul>
+
+}
+
+# if you hate the squirly green bar down the left-hand side of the page,
+# uncomment these lines:
+
+# _header_ { 
+# }
Index: /tags/gsdl-2_61-distribution/gsdl/macros/yourhome.dm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/macros/yourhome.dm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/macros/yourhome.dm	(revision 10506)
@@ -0,0 +1,40 @@
+# this file must be UTF-8 encoded
+
+package home
+_content_ {
+
+<h2>Your own Greenstone home page</h2>
+
+<ul>
+<table>
+<tr valign=top><td>Search page for the demo collection<br></td>
+    <td><a href="_httpquery_&c=demo">Click here</a></td></tr>
+
+<tr><td>"About" page for the demo collection</td>
+    <td><a href="_httppageabout_&c=demo">Click here</a></td></tr>
+
+<tr><td>Preferences page for the demo collection</td>
+    <td><a href="_httppagepref_&c=demo">Click here</a></td></tr>
+
+<tr><td>Home page</td>
+    <td><a href="_httppagehome_">Click here</a></td></tr>
+
+<tr><td>Help page</td>
+    <td><a href="_httppagehelp_">Click here</a></td></tr>
+
+<tr><td>Administration page</td>
+    <td><a href="_httppagestatus_">Click here</a></td></tr>
+
+<tr><td>The Collector</td>
+    <td><a href="_httppagecollector_">Click here</a></td></tr>
+
+</table>
+</ul>
+
+}
+
+# if you hate the squirly green bar down the left-hand side of the page,
+# uncomment these lines:
+
+# _header_ { 
+#          }
Index: /tags/gsdl-2_61-distribution/gsdl/mappings/README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/mappings/README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/mappings/README	(revision 10506)
@@ -0,0 +1,22 @@
+This directory and its subdirectories contain .ump mapping files for
+converting various character encodings to and from unicode.
+
+To generate .ump files use a command like "makemapfile.pl -encoding
+encodingname -mapfile textmapfile" where encodingname becomes the filename
+of the two new .ump files and textmapfile is a plain text file containing a
+tab separated list of the form:
+0x8167	      0x201C
+where the first column is the hexadecimal value of the encoded character
+and the second is the hexadecimal value of it's unicode equivalent.
+
+
+
+The following .ump files were generated from their corresponding Microsoft
+codepages. These codepages do, in some cases, differ very slightly from the
+standards they were based on but we've used them anyway as they're so
+extensively used on the web.
+
+* gbk.ump: Simplified Chinese - generated from Microsoft's codepage 936
+* shiftjis.ump: Japanese - generated from Microsoft's codepage 932
+* uhc.ump: UHC Korean - generated from Microsoft's codepage 949
+* big5.ump: Traditional Chinese - generated from Microsoft's codepage 950
Index: /tags/gsdl-2_61-distribution/gsdl/micotest.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/micotest.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/micotest.cpp	(revision 10506)
@@ -0,0 +1,11 @@
+#include <iostream.h>
+#include <stdlib.h>
+#include <mico/version.h>
+
+char version[] = MICO_VERSION;
+
+int main()
+{
+  cout << version;
+  exit(0);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/Makefile.in	(revision 10506)
@@ -0,0 +1,96 @@
+###########################################################################
+#
+# Makefile -- Makefile for packages 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.
+#
+###########################################################################
+
+
+# PACKAGEDIRS contains the packages that we want to make and install.  It
+# is assumed that each package will have at least four rules: all, install,
+# clean, and distclean.
+USE_Z3950=@USE_Z3950@
+ifeq ($(USE_Z3950), 1)
+# we only compile the src and client dirs for now. also need d2m
+YAZ=yaz/yaz-2.1.4/src yaz/yaz-2.1.4/client d2m
+else
+YAZ=
+endif
+
+USE_CORBA=@USE_CORBA@
+MICO_DIR=@MICO_DIR@
+ifeq ($(USE_CORBA), 1)
+ifeq ($(MICO_DIR), default)
+CORBA="mico/mico"
+else
+CORBA=
+endif
+else
+CORBA=
+endif
+
+PACKAGEDIRS =	wv/wv-gs rtftohtml/rtftohtml_src pdftohtml/pdftohtml_gs \
+		wget/wget-1.9 expat/ cpan/XML-Parser-2.34 \
+		$(YAZ) $(CORBA) \
+		xlhtml/xlhtml-0.4.9.0 isis-gdl
+
+all:
+	for odir in $(PACKAGEDIRS); do \
+          echo making $@ in $$odir; \
+          (cd $$odir && $(MAKE) $(MDEFINES) $@) || exit 1; \
+        done
+ifeq ($(CORBA), "mico/mico")
+	cd mico/mico; $(MAKE)  $(MDEFINES) install
+	mkdir -p ../bin/linux
+	mkdir -p ../lib
+	mkdir -p ../include
+	mkdir -p ../man
+	cp -f mico/bin/* ../bin/linux
+	cp -f mico/lib/* ../lib/
+	cp -fr mico/include/* ../include
+	cp -fr mico/man ../man
+endif
+ifeq ($(USE_Z3950), 1)
+# need to do make install in include and src dirs to get the header files and
+# lib file into the right place
+	cd yaz/yaz-2.1.4/include; $(MAKE)  $(MDEFINES) install
+	cd yaz/yaz-2.1.4/src; $(MAKE)  $(MDEFINES) install
+endif
+
+
+install:
+	for idir in $(PACKAGEDIRS); do \
+          echo installing $$idir; \
+          (cd $$idir && $(MAKE) install) || exit 1; \
+        done
+
+clean:
+	for subdir in $(PACKAGEDIRS); do \
+          echo cleaning $@ in $$subdir; \
+          (cd $$subdir && $(MAKE) clean || exit 0) ; \
+        done
+
+distclean:
+	for subdir in $(PACKAGEDIRS); do \
+          echo cleaning $@ in $$subdir; \
+          (cd $$subdir && $(MAKE) distclean || exit 0) ; \
+        done
Index: /tags/gsdl-2_61-distribution/gsdl/packages/configure
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/configure	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/configure	(revision 10506)
@@ -0,0 +1,230 @@
+#! /bin/sh
+
+PACKAGES=`pwd`
+cd ..
+GSDLHOME=`pwd`
+cd $PACKAGES
+
+GSDLOS=`uname -s |tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+# check for running bash under cygwin
+if test "`echo $GSDLOS | sed 's/cygwin//'`" != "$GSDLOS" ;
+then
+ GSDLOS=windows
+fi
+
+prefix=""
+bindir=""
+HOSTTARGETFLAGS=""
+
+USE_CORBA=false
+MICO_DIR=default
+
+# parse any arguments given from toplevel configure
+while test $# -ne 0; do
+    case "$1" in
+	--cache-file=*)
+	    cache_filename=`echo $1 | sed s/--cache-file=//`
+	    # turn relative path into an absolute path
+	    cache_dir=`echo $cache_filename | sed 's@/[^/]*$@@'`
+	    cache_dir=`cd $cache_dir 2>/dev/null && pwd`
+
+	    cache_basefile=`echo $cache_filename | sed 's@.*/@@'`
+	    cache_file="$cache_dir/$cache_basefile"
+	    if test ! -f "$cache_file"; then
+		CACHE_FILE=""
+	    else
+		CACHE_FILE="--cache-file=$cache_file"
+	    fi
+	    ;;
+	--enable-z3950)
+	    USE_Z3950=true
+	    ;;
+	--enable-corba)
+	    USE_CORBA=true
+	    ;;
+	--with-micodir=*)
+	    if test $1 = ""; then
+	      $1 = "default"
+            fi
+	    MICO_DIR=$1
+	    ;;       
+	--prefix=*)
+	    prefix=`echo $1 | sed s/--prefix=//`
+	    ;;
+	--bindir=*)
+	    # where to install binaries to
+	    bindir=`echo $1 | sed s/--bindir=//`
+	    # turn relative path into an absolute path
+	    if test -d "$bindir" ; then
+	      bindir=`cd "$bindir" ; pwd `
+	      cd "$PACKAGES"
+	    elif test -z `echo $bindir | sed '/^\// p;D'` ; then
+	      rel_bindir="`echo $bindir | sed s@/.*@@`"
+	      cd "$rel_bindir"
+	      bindir="`pwd`/`echo $bindir | sed s@^[^/]*/@@`"
+	      cd "$PACKAGES"
+	    else
+	      # bindir doesn't exist, and isn't relative
+	      true
+	    fi
+	    ;;
+	--host=* | --target=*)
+	    HOSTTARGETFLAGS="$HOSTTARGETFLAGS $1"
+	    ;;
+	*)
+	    # ignore all other options for now
+	    ;;
+    esac
+    shift
+done
+
+# note! Our GSDL package currently always installs into it's source
+# directory, ignoring any --prefix given to configure.
+# When this is fixed, uncomment the relevant lines below...
+
+##if test -z "$prefix" ; then
+prefix="${GSDLHOME}"
+##fi
+
+##if test -z "$bindir" ; then
+bindir="${prefix}/bin/$GSDLOS"
+##fi
+
+# This loads the top configure's cache file, with variables already set.
+if test -f "$cache_file" ; then
+  . $cache_file
+fi
+
+# we assume that gzip and tar are on the search path.
+# non-GNU versions of tar don't take the -z option.
+
+if test $USE_CORBA = true ; then
+  if test $MICO_DIR = default; then
+    # configure the MICO CORBA ORB
+    echo ""
+    echo "Configuring MICO CORBA"
+    echo ""
+
+    cd "$PACKAGES/mico"
+    gzip -dc mico-2.3.5.tar.gz | tar -xf -
+    cd mico && \
+    ./configure $CACHE_FILE    --prefix=$PACKAGES/mico/  --disable-coss --disable-naming --disable-relship --disable-events --disable-streams --disable-property --disable-trader --disable-time --disable-debug --enable-optimize --enable-final --enable-speed-tune
+    sed 's/tools//'  $PACKAGES/mico/mico/Makefile | sed 's/ldconfig//' >$PACKAGES/mico/mico/Makefile.out
+    mv $PACKAGES/mico/mico/Makefile.out $PACKAGES/mico/mico/Makefile
+  else
+    #MICO is on the system path
+    echo ""
+    echo "Taking MICO from system paths"
+    echo ""
+  fi
+else
+  echo "corba support disabled - mico compiler not required."
+  echo "  add '--enable-corba' to the configure command to include corba support."
+  echo ""
+fi
+
+
+
+
+
+# configure the wvWare Word document converter
+echo ""
+echo "Configuring wvWare"
+echo ""
+
+cd "$PACKAGES/wv"
+gzip -dc wv-0.7.1-gs.tar.gz | tar -xf -
+# datadir is for default location of wvHtml.xml config file
+cd wv-gs && \
+./configure $CACHE_FILE --prefix=$PACKAGES/wv --bindir="$bindir" --datadir="$prefix/etc/packages" $HOSTTARGETFLAGS
+
+# configure the pdftohtml converter
+echo ""
+echo "Configuring pdftohtml"
+echo ""
+
+cd "$PACKAGES/pdftohtml"
+gzip -dc pdftohtml_0_36_gs.tar.gz | tar -xf -
+cd pdftohtml_gs && \
+./configure $CACHE_FILE --prefix="$prefix" --bindir="$bindir" $HOSTTARGETFLAGS
+
+# rtftohtml converter
+echo ""
+echo "Configuring rtftohtml"
+echo ""
+
+cd "$PACKAGES/rtftohtml"
+gzip -dc rtftohtml-gs.tar.gz | tar -xf -
+cd rtftohtml_src && \
+./configure $CACHE_FILE --prefix="$prefix" --bindir="$bindir" $HOSTTARGETFLAGS
+
+
+# YAZ Z39.50 toolkit
+echo ""
+echo "Configuring YAZ"
+if test x$USE_Z3950 = xtrue ; 
+then
+  echo ""
+  cd "$PACKAGES/yaz" 
+  gzip -dc yaz-2.1.4.tar.gz | tar -xf -
+  cd yaz-2.1.4 && \
+    ./configure $CACHE_FILE --prefix="$PACKAGES/yaz" --with-xml2=no --with-iconv=no $HOSTTARGETFLAGS
+  cd "$PACKAGES/d2m"
+  ./configure $CACHE_FILE --prefix="$PACKAGES/d2m" $HOSTTARGETFLAGS
+else
+  echo "Z39.50 support disabled - YAZ library not required."
+  echo "  add '--enable-z3950' to the configure command to include z39.50 support."
+  echo ""
+fi
+
+# configure wget
+echo ""
+echo "Configuring wget"
+echo ""
+cd "$PACKAGES/wget"
+gzip -dc wget.tar.gz | tar -xf -
+cd "$PACKAGES/wget/wget-1.9" && \
+./configure $CACHE_FILE --prefix=$PACKAGES/wget --bindir="$bindir" $HOSTTARGETFLAGS
+
+# configure expat (needs to be done before XML::Parser
+echo ""
+echo "Configuring expat"
+echo ""
+cd "$PACKAGES/expat"
+gzip -dc expat-1.95.8.tar.gz | tar -xf -
+cd "$PACKAGES/expat/expat-1.95.8" && \
+./configure $CACHE_FILE --prefix=$PACKAGES/expat --bindir="$bindir" $HOSTTARGETFLAGS
+
+# configure XML::Parser perl module
+echo ""
+echo "Configuring XML::Parser"
+echo ""
+cd "$PACKAGES/cpan"
+perl_dir=`echo 'my $vn = $]; $vn =~ s/5\.00(\d).*$/perl-5.$1/; print "$vn" ' | perl`
+gzip -dc XML-Parser-2.34.tar.gz | tar -xf -
+cd "$PACKAGES/cpan/XML-Parser-2.34" && \
+perl Makefile.PL \
+  INSTALLSITELIB="$GSDLHOME/perllib/cpan/$perl_dir" \
+  PREFIX="$GSDLHOME/perllib/cpan/XML" \
+  INSTALLMAN1DIR="$GSDLHOME/perllib/cpan/$perl_dir" \
+  INSTALLMAN3DIR="$GSDLHOME/perllib/cpan/$perl_dir" \
+  SITEPREFIX="$GSDLHOME/perllib/cpan" \
+  EXPATINCPATH="$GSDLHOME/packages/expat/include" \
+  EXPATLIBPATH="$GSDLHOME/packages/expat/lib" 
+
+# configure powerpoint converter
+echo ""
+echo "Configuring xlhtml (powerpoint & excel converter)"
+echo ""
+cd "$PACKAGES/xlhtml"
+gzip -dc xlhtml-0.4.9.0-gs.tar.gz | tar -xf -
+cd xlhtml-0.4.9.0 && \
+./configure $CACHE_FILE --prefix="$prefix" --bindir="$bindir" $HOSTTARGETFLAGS
+
+
+# configure IsisGdl program
+echo ""
+echo "Configuring IsisGdl (CDS/ISIS database reader)"
+echo ""
+cd "$PACKAGES/isis-gdl" && \
+./configure $CACHE_FILE --prefix="$prefix" --bindir="$bindir" $HOSTTARGETFLAGS
Index: /tags/gsdl-2_61-distribution/gsdl/packages/cpan/README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/cpan/README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/cpan/README	(revision 10506)
@@ -0,0 +1,42 @@
+This directory contains perl modules from cpan for use with the Greenstone
+collection building code. After a "make install" these modules will be
+installed to the gsdl/perllib/cpan directory.
+
+Note that pure perl modules (i.e. those not containing any C code to
+compile) don't need building so they don't live in the packages directory
+tree (they live in perllib/cpan).
+
+
+The following modules are currently included:
+
+XML::Parser: Copyright (c) 1998-2000 Larry Wall and Clark Cooper
+ 
+ - Version 2.34
+
+  Originally, we used Version 2.27 cut down a bit for size, plus
+  a few modifications to Makefile.PL.  See below.
+
+
+HISTORY
+-------
+
+Mar 2005
+
+XML::Parser
+
+ - Version 2.34 and version 2.27
+added MAKEFILE_OLD => 'Makefile' to the Makefile.PL WriteMakeFile directive.
+previously, doing a make clean renamed the Makefile to Makefile.old, so then
+a make wouldn't work. Now Makefile gets renamed to Makefile. Hopefully this
+won't stuff anything else up.
+ 
+< Aug 2004
+
+XML::Parser: Copyright (c) 1998-2000 Larry Wall and Clark Cooper
+
+- Version 2.27 - as downloaded from cpan.org but with a few files removed
+  (to minimize the size of the tarball we distribute) and minor Greenstone
+  specific modifications to Makefile.PL. Originally used version 2.29 but
+  it appeared to be incompatible with perl 5.6.1.
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/D2Mcgi.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/D2Mcgi.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/D2Mcgi.c	(revision 10506)
@@ -0,0 +1,326 @@
+/* ------------------------------------------------------------------- */
+/* D2Mcgi.c  : CGI program for DC -> MARC conversion                   */
+/* Author    : Ole Husby                                               */
+/* Updated   : 1998-09-30                                              */
+/* ------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------
+D2MCgi() will take metadata input from a parameter, or fetch an
+HTML file using HTTP.
+
+DC metadata will be converted into MARC, and presented in one of
+several formats.
+
+The program will look for the following QUERY_STRING:
+
+url=xxx&fmt=xxx&prs=xxx&txt=xxx&par=xxx 
+
+where: 
+
+  url
+      xxx = the URL for the file containing the metadata
+  fmt
+      The MARC format. xxx =
+      DANMARC | FINMARC | ISMARC | NORMARC (default) | SWEMARC | USMARC.
+  prs
+      The presentation format. xxx =
+      plain (default) | html | 2709 | binary.
+
+  txt
+      If present, this field will be parsed for metadata, and the only 
+      use of the URL (if entered) will be used to produce the 856 field 
+      of the MARC record. 
+
+  par
+      If xxx = on, the program will additionally display the tags as
+      they are recognized. Will only work together with the html format.
+   ------------------------------------------------------------------- */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "d2m.h"
+
+
+
+
+/* ------------------------------------------------------------------- */
+/* main() program                                                      */
+/* ------------------------------------------------------------------- */
+
+int main ()
+{
+  int rc, i, source, textarea, f2709, tracing, mformat, marcfile;
+  int linel, llen, slen;
+  int *meta;
+
+  FILE *df, *of;
+  char contype[64], dfilename[64], tfilename[64], line[50000];
+  char *pq, *p, *q, pre[16], *l, *u;
+  char marcformat[256], url[1000], method[32];
+  char *buffer[50000];
+  char syntax[64];
+
+  char recstatus = 'n';
+  char rectype   = 'm';
+  char biblevel  = ' ';
+
+/* Initializing  */
+
+  of = stdout;
+  *url = 0;
+  marcfile = 0;
+
+  strcpy(marcformat, D2M_DEFAULT_FORMAT);
+  strcpy(syntax, D2M_DEFAULT_SYNTAX);
+  sprintf(dfilename, "%s.%d", D2M_TEMPFILE, getpid());
+
+  textarea = tracing = f2709 = 0;
+  *line = 0;
+
+
+/* Decide parameters for line format formating   */
+
+  linel = D2M_LINELEN;
+  if (!linel)
+    linel = 80;
+
+  if (linel > 200)
+    linel = 200;
+
+  llen = linel - 9;
+  slen = linel - 30;
+  if (slen < 10)
+    slen = 10;
+
+
+/* Check request method (POST or GET)  */
+
+  strcpy(method, getenv("REQUEST_METHOD"));
+
+  if (strcmp(method, "GET") == 0)
+  {
+    strcpy(line, getenv("QUERY_STRING"));
+    pq = (char *) strdup(line);
+  }
+  
+  else if (strcmp(method, "POST") == 0)
+    pq = poq();
+
+  else
+    pq = (char *) NULL;           /* Error exit is missing here ! */
+
+
+/* Parse parameters  */
+  
+  if (pq)
+  {
+    strcpy(line, pq);
+    free(pq);
+
+    l = (char *) line;
+
+    u = strtok(l, "&");
+    while (u)
+    {
+      unescape(u);
+      if (strncasecmp(u, "url=", 4) == 0)
+        strcpy(url, u + 4); 
+      else if (strncasecmp(u, "fmt=", 4) == 0)
+        strcpy(marcformat, u + 4); 
+      else if (strncasecmp(u, "prs=", 4) == 0)
+        strcpy(syntax, u + 4); 
+      else if (strncasecmp(u, "par=", 4) == 0)
+      {
+        if (strcmp(u + 4, "on") == 0) 
+          tracing = 1;
+      }
+      else if (strncasecmp(u, "txt=", 4) == 0)
+      {
+        if (strlen(u + 4))
+        {
+          if ( df = fopen(dfilename, "w"))
+          {
+            fprintf(df, "%s", u + 4);
+            textarea = 1;
+            fclose(df);
+          }
+        }
+      }
+      u = strtok(NULL, "&");
+    }
+  }
+
+
+
+/* Check the syntax */
+
+  if (strcmp(syntax, "2709") == 0)
+  {
+    strcpy(contype, "text/plain");
+    tracing = 0;
+    f2709 = 1;
+  }
+
+  else if (strcmp(syntax, "binary") == 0)
+  {
+    strcpy(contype, "application/marc");
+    tracing = 0;
+    f2709 = 1;
+  }
+
+  else if (strcmp(syntax, "html") == 0)
+  {
+    strcpy(contype, "text/html");
+  }
+
+  else if (strcmp(syntax, "plain") == 0)
+  {
+    strcpy(contype, "text/plain");
+    tracing = 0;
+  }
+
+
+/* Write HTTP header and HTML <HEAD>: */
+
+  printf("Content-type: %s\n\n", contype);
+  if (strcmp(syntax, "html") == 0)
+  {
+    printf("<html><head><title>\n");
+    printf("%s\n", HTML_TITLE);
+    printf("</title></head>\n\n<body bgcolor=\"#ffffbb\">\n");
+  }
+
+
+
+/* Check if metadata in input (source = TEXTAREA) or in URL   */
+
+  if (!textarea && !*url)
+  {
+    printf("1: ");
+    printf("Error: Insufficient input\n");
+    exit(0);
+  }
+
+  else if (textarea)
+    source = TEXTAREA;
+
+  else
+    source = URL;
+
+  if (!textarea && !*url)
+  {
+    printf("2: ");
+    printf("Error: Insufficient input\n");
+    exit(0);
+  }
+
+
+/* Check the marcformat   */
+
+  if (strncasecmp(marcformat, "DAN", 3) == 0)
+    mformat = DANMARC;
+  else if (strncasecmp(marcformat, "FIN", 3) == 0)
+    mformat = FINMARC;
+  else if (strncasecmp(marcformat, "IS", 2) == 0)
+    mformat = ISMARC;
+  else if (strncasecmp(marcformat, "US", 2) == 0)
+    mformat = USMARC;
+  else if (strncasecmp(marcformat, "NOR", 3) == 0)
+    mformat = NORMARC;
+  else if (strncasecmp(marcformat, "SWE", 3) == 0)
+    mformat = SWEMARC;
+  else
+  {
+    printf("Error: This MARC format is not supported!\n");
+    exit(0);
+  }
+
+
+/* Fetch URL if necessary    */
+
+  if (source == URL)
+  {
+    if (strcmp(url, "test") == 0)
+      strcpy(url, D2M_DEFAULT_URL);
+    rc = wfetch(&url, &dfilename);
+    if (!rc)
+    {
+      printf("Error %d: Unable to fetch file %s\n", rc, url);
+      exit(0);
+    }
+    if (rc == 2)
+      marcfile = 1;
+  }
+
+  if (*url && !textarea && ( strcmp(syntax, "html") == 0 ) )
+  {
+    printf("<h2><a href=\"%s\">%s</a></h2>\n", url, url);
+    printf("<h3>%s record:</h3><hr>\n", marcformat);
+  }
+
+   if (strcmp(syntax, "html") == 0)
+     printf("<pre>\n");
+
+   if (tracing)
+     strcpy(tfilename, D2M_TRACEFILE);
+   else
+     *tfilename = 0;
+
+/* Convert to MARC                                                    */
+/* NOTE: M2Mconv() will even convert from MARC 2709 to line format    */
+
+   if (marcfile)
+     rc = M2Mconv((char *) dfilename, (char *) buffer,
+                 (char *) tfilename, mformat);
+   else            
+     rc = D2Mconv((char *) dfilename, (char *) buffer,
+                 (char *) tfilename, (char *) url, mformat);
+
+   remove(dfilename);
+
+
+/* Produce output                                                      */
+
+   if (!rc)
+     printf("Error: Unable to parse data\n");
+
+   else
+   {
+     if (f2709)
+       printf("%s", 
+         (char *) MARC2709(buffer, 0, 6, recstatus, rectype, biblevel));
+     else
+  
+     {
+       l = strtok((char *) buffer, "\n");
+  
+       while (l)
+       {
+         write_field(l, of, linel, llen, slen);
+         l = strtok(NULL, "\n");
+       }
+     }
+   }
+
+   if (*url && !textarea && ( strcmp(syntax, "html") == 0 ) )
+     printf("<hr>\n");
+
+   if (tracing)
+   {
+     printf("</pre>\n");
+     printf("<h3>Parsed DC metadata:</h3>\n");
+     printf("<pre>\n");
+     write_trace(tfilename, of);
+   }
+
+   if (strcmp(syntax, "html") == 0)
+   {
+     printf("</pre>\n");
+     printf("</body></html>\n");
+   }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/D2Mconv.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/D2Mconv.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/D2Mconv.c	(revision 10506)
@@ -0,0 +1,265 @@
+/* ------------------------------------------------------------------- */
+/* D2Mconv   : Converts metadata present in a file to MARC             */
+/*             Writes MARC record in "line format"                     */
+/*                                                                     */
+/* Syntax    : Arguments:                                              */
+/*                                                                     */
+/*       char *dfile : input file                                      */
+/*                     DC metadata must be present in HTML 2.0         */
+/*                     or HTML 4.0 syntax                              */
+/*       char *buffer: output record in line format                    */
+/*                     Must be allocated in calling program!           */
+/*       char *tfile : tracefile                                       */
+/*                     No trace if NULL                                */
+/*       char *url   : URL for use in case no URL in DC.Identifier     */
+/*                                                                     */
+/*       char *format: MARC format (see d2m.h)                         */
+/*                                                                     */
+/* Author    : Ole Husby, BIBSYS                                       */
+/* Updated   : 1998-09-30                                              */
+/* ------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include "d2m.h"
+
+
+
+
+/* ------------------------------------------------------------------- */
+/* Checks a new line                                                   */
+/* ------------------------------------------------------------------- */
+/*
+   This is where starting and ending of a meta tag is parsed.
+   The whole metatag (resulting from one ore more lines) is put
+   into the buffer.
+
+   Note: This function is called recursively!
+*/
+
+int mline(char *l, char *buf, int *meta, 
+          struct marcrec *mrec, FILE *tf, int format)
+{
+  char *p, *q, rc;
+  int diff;
+
+  struct metatag *mtag;
+ 
+  if (!l || !*l) return 1;
+
+  q = l;
+
+
+/* Looks for the end of an already started metatag buffer              */
+/* The end is normally '">'                                            */
+
+  if (*meta)
+  {
+     p = strstr(l, "\">");
+
+     if (p) 
+     {
+        if ( (char *) p != (char *) l)
+        {
+           diff = (int)(p - l);
+           if (*buf)
+             strcat(buf, " ");
+           strncat(buf, l, diff);
+        }
+
+/* Parsing the buffer for metadata                                  */
+
+        mtag = dc_parse(buf);
+
+        if (mtag)
+        {
+          if (tf)
+          {
+            fprintf(tf, "Name  : %s\n", mtag->name   );
+            fprintf(tf, "Type  : %s\n", mtag->type   );
+            fprintf(tf, "Scheme: %s\n", mtag->scheme );
+            fprintf(tf, "Value : %s\n", mtag->value  );
+            fprintf(tf, "\n");
+          }
+
+/*        Convert to MARC                                           */
+
+          MARCmake(mtag, mrec, format);
+        }
+        free(mtag);
+
+        *buf = 0;
+        *meta = FALSE;
+        q = p + 2;
+     }
+     else
+     {
+        strcat(buf, l);
+        q = NULL;
+     }
+  }
+
+
+  if (!q) return 1;
+
+  p = (char *) cstr(q, "<meta ");
+
+  if (p)
+  {
+    *meta = TRUE;
+    mline(p + 6, buf, meta, mrec, tf, format);
+  }
+
+  return 1;
+}
+
+
+
+int D2Mconv(char *dfile, char *buffer, char *tfile, char *url, int format)
+{
+  struct marcrec *mrec;
+  struct metatag *mtag;
+  char line[50000], today[32];
+  char *l, *p;
+  time_t d;
+  struct tm *time_struct;
+
+  FILE *df, *tf;
+  int *meta;
+
+  putenv("TZ=NFT-1DFT");
+  d = time(NULL);
+  time_struct = localtime(&d);
+  strftime(today, 16, "%y%m%d", time_struct);
+
+  mrec = malloc(sizeof(*mrec));
+
+  mrec->marcline = malloc(100000);
+  mrec->partitle = malloc(10000);
+  mrec->subtitle = malloc(10000);
+  mrec->year     = malloc(1000);
+  mrec->url      = malloc(1000);
+  mrec->fmat     = malloc(1000);
+  mrec->s008     = malloc(41);
+
+  mrec->ncreators = 0;
+  mrec->ntitles   = 0;
+  *mrec->marcline = 0;
+  *mrec->subtitle = 0;
+  *mrec->partitle = 0;
+  *mrec->year     = 0;
+  *mrec->url      = 0;
+  *mrec->fmat     = 0;
+  strcpy(mrec->s008, "                                        ");
+
+  meta = malloc(sizeof(int));
+
+  tf = (FILE *) NULL;
+
+
+/* Open inputfile */
+
+  df = fopen(dfile, "r");
+  if (!df)
+    return 0;                            /* Error: Unable to read data */
+
+
+
+/* Open tracefile */
+
+   if (*tfile)
+   {
+     tf = fopen(tfile, "w");
+     if (!tf)
+     {
+       fclose(df);
+       return 0;                         /* Error: Unable to create trace */
+     }
+   }
+
+   *meta = FALSE;
+
+
+/* Reads the file */ 
+
+
+   while (l = fgets(line, 9999, df))
+   {
+
+/*   Remove trailing LF and / or CR     */
+
+     while ( (l[strlen(l) - 1] == '\n') || (l[strlen(l) - 1] == '\r') )
+       l[strlen(l) -1] = '\0';
+
+
+/*   printf("... main  %s\n",l);                             */ 
+
+/*   Stops reading file if "</head" or "<body" is encountered  */
+
+     p = cstr(l, (char *) "</head");
+     if (p) break;
+
+     p = cstr(l, (char *) "<body");
+     if (p) break;
+
+     mline(l, (char *) buffer, (int *) meta, mrec, tf, format);
+   }
+
+
+
+/* Check if remaining data in buffer */
+  
+   mtag = dc_parse((char *) buffer);
+
+   if (mtag) 
+   {
+     if (tf)
+     {
+       fprintf(tf, "Name  : %s\n", mtag->name   );
+       fprintf(tf, "Type  : %s\n", mtag->type   );
+       fprintf(tf, "Scheme: %s\n", mtag->scheme );
+       fprintf(tf, "Value : %s\n", mtag->value  );
+       fprintf(tf, "\n");
+     }
+     MARCmake(mtag, mrec, format);
+   }
+   free(mtag);
+
+
+/* Close files */ 
+
+   fclose(df);
+
+   if (tf)
+     fclose(tf);
+
+/* Put URL into mrec (if not present)  */
+
+   if (!*mrec->url)
+     strcpy(mrec->url, url);
+
+/* Put date into 008 */
+
+   put008(mrec->s008, today, F008_DATE_ENTERED);
+   put008(mrec->s008, "s", F008_TYPE_OF_DATE);
+
+   switch (format)
+   {
+     case ISMARC  :
+     {
+       put008(mrec->s008, "k", F008_FORM_OF_PUBLICATION);
+       break;
+     }
+   }
+
+/* Tidy up the MARC buffer                                               */
+
+   MARCtidy(mrec, buffer, format);
+
+   return 1;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/D2Mmain.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/D2Mmain.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/D2Mmain.c	(revision 10506)
@@ -0,0 +1,246 @@
+/* ------------------------------------------------------------------- */
+/* D2Mmain   : standalone program for DC -> MARC conversion            */
+/*                                                                     */
+/* Syntax    : d2main [File] [Options]                                 */
+/*                                                                     */
+/* File      : This may be a local filename, or a URL (which is        */
+/*             recognized by the "http://" prefix). When a URL,        */
+/*             the remote file will be fetched using the builtin       */
+/*             HTTP "client".                                          */
+/*                                                                     */
+/* Options   : -l                       : Format = line format         */
+/*                                        (Default is ISO 2709)        */
+/* Options   : -f [filename]            : Outputfile                   */
+/*                                        (Default is stdout)          */
+/* Options   : -m [marcformat]          : Marcformat (upper case)      */
+/*                                        (Default is NORMARC)         */
+/* Options   : -t [filename]            : Tracefile                    */
+/*                                        (Default is no trace)        */
+/*                                                                     */
+/* Return    : 0 : OK                                                  */
+/*             1 : Syntax error (no parms != 2)                        */
+/*             2 : Illegal MARC format                                 */
+/*             3 : Cannot open output file                             */
+/*             8 : Error in MARC conversion                            */
+/*             9 : URL not found                                       */
+/*                                                                     */
+/* Author    : Ole Husby                                               */
+/* Updated   : 1998-09-30                                              */
+/* ------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "d2m.h"
+
+
+
+
+
+/* ------------------------------------------------------------------- */
+/* main() program                                                      */
+/* ------------------------------------------------------------------- */
+
+int main (int argc, char **argv)
+{
+  int rc, i, f2709, tracing, argtype, mformat, marcfile;
+  int linel, llen, slen;
+
+  FILE *df, *of;
+  char dfilename[64], tfilename[64], ofilename[64], line[50000];
+  char *pq, *p, *q, pre[16], *l, *u;
+  char marcformat[64], url[1000];
+  char buffer[50000];
+
+  char recstatus = 'n';
+  char rectype   = 'm';
+  char biblevel  = ' ';
+
+  enum options {OPT_NONE, OPT_FILE, OPT_TRAC, OPT_MARC};
+
+
+/* Initialize */
+
+  of = stdout;
+  *url = *ofilename = 0;
+  strcpy(marcformat, "NORMARC");
+
+  tracing = FALSE;
+  *tfilename = 0;
+  f2709 = TRUE;
+  marcfile = 0;
+
+  *line = 0;
+
+  linel = D2M_LINELEN;
+  if (!linel)
+    linel = 80;
+
+  if (linel > 200)
+    linel = 200;
+
+  llen = linel - 9;
+  slen = linel - 30;
+  if (slen < 10)
+    slen = 10;
+
+
+/* Read command line arguments */
+
+  if (argc < 2)
+  { 
+    printf(" Syntax    : d2main [File] [Options]\n\n");
+    printf(" File      : This may be a local filename, or a URL (which is\n");
+    printf("             recognized by the \"http://\" prefix). When a URL,\n");
+    printf("             the remote file will be fetched using the builtin\n");
+    printf("             HTTP \"client\".\n\n");
+    printf(" Options   : -l                       : Format = line format\n");
+    printf("                                        (Default is ISO 2709)\n");
+    printf(" Options   : -f [filename]            : Outputfile\n");
+    printf("                                        (Default is stdout)\n");
+    printf(" Options   : -m [marcformat]          : Marcformat (upper case)\n");
+    printf("                                        (Default is NORMARC)\n");
+    printf(" Options   : -t [filename]            : Tracefile\n");
+    printf("                                        (Default is no trace)\n\n");
+    printf(" Return    : 0 : OK\n");
+    printf("             1 : Syntax error\n");
+    printf("             2 : Illegal MARC format\n");
+    printf("             3 : Cannot open output file\n");
+    printf("             8 : Error in MARC conversion\n");
+    printf("             9 : URL not found\n");
+    exit(1);
+  }
+
+  strcpy(dfilename, argv[1]);
+
+
+/* Get options                                                         */
+
+  if (argc > 2)
+  {
+    argtype = OPT_NONE;
+
+    for (i = 1; i < argc; i++)
+    {
+      if (argtype == OPT_FILE)
+      {
+        strcpy(ofilename, argv[i]);
+        argtype = OPT_NONE;
+      }
+      else if (argtype == OPT_TRAC)
+      {
+        strcpy(tfilename, argv[i]);
+        tracing = TRUE;
+        argtype = OPT_NONE;
+      }
+      else if (argtype == OPT_MARC)
+      {
+        strcpy(marcformat, argv[i]);
+        argtype = OPT_NONE;
+      }
+      else if (strcmp(argv[i], "-l") == 0)
+      {
+        f2709 = FALSE;
+        argtype = OPT_NONE;
+      }
+      else if (strcmp(argv[i], "-m") == 0)
+         argtype = OPT_MARC;
+      else if (strcmp(argv[i], "-f") == 0)
+         argtype = OPT_FILE;
+      else if (strcmp(argv[i], "-t") == 0)
+         argtype = OPT_TRAC;
+      else
+        argtype = OPT_NONE;
+    }
+  }
+
+/* Verify MARC format */
+
+  if (strncasecmp(marcformat, "US", 2) == 0)
+    mformat = USMARC;
+  else if (strncasecmp(marcformat, "DAN", 3) == 0)
+    mformat = DANMARC;
+  else if (strncasecmp(marcformat, "FIN", 3) == 0)
+    mformat = FINMARC;
+  else if (strncasecmp(marcformat, "IS", 2) == 0)
+    mformat = ISMARC;
+  else if (strncasecmp(marcformat, "NOR", 3) == 0)
+    mformat = NORMARC;
+  else if (strncasecmp(marcformat, "SWE", 3) == 0)
+    mformat = SWEMARC;
+  else 
+    exit(2);
+
+
+/* Fetch URL if remote file  */
+
+  if (strncmp(dfilename, "http://", 7) == 0)
+  {
+    strcpy(url, dfilename);
+    sprintf(dfilename, "%s.%d", D2M_TEMPFILE, getpid());
+    rc = wfetch(&url, &dfilename);
+    if (!rc)
+    {
+      remove(dfilename);
+      exit(9);
+    }
+    if (rc == 2)
+      marcfile = 1;
+  }
+
+
+
+
+/* Convert into buffer (line format)  */
+
+  if (marcfile)
+    rc = M2Mconv((char *) dfilename, (char *) buffer,
+                (char *) tfilename, mformat);
+  else
+    rc = D2Mconv((char *) dfilename, (char *) buffer,
+                (char *) tfilename, (char *) url, mformat);
+
+  if (!rc)
+  {
+    fclose(df);
+    exit(8);
+  }
+
+  if (*url)
+    remove(dfilename);
+
+
+/* Prepare for output      */
+
+   if (*ofilename)
+   {
+     of = fopen(ofilename, "w");
+     if (!of)
+       exit(3);
+   }
+   else
+     of = stdout;
+
+
+/* Write output, if necessary converted to ISO 27809   */
+
+   if (f2709)
+     fprintf(of, "%s", 
+       (char *) MARC2709(buffer, 0, 6, recstatus, rectype, biblevel));
+
+   else
+   {
+     l = strtok((char *) buffer, "\n");
+
+     while (l)
+     {
+       write_field(l, of, linel, llen, slen);
+       l = strtok(NULL, "\n");
+     }
+   }
+
+   if (*ofilename)
+     fclose(of);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/M2Mconv.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/M2Mconv.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/M2Mconv.c	(revision 10506)
@@ -0,0 +1,84 @@
+/* ------------------------------------------------------------------- */
+/* M2Mconv   : Convert an ISO 2709 record into MARC format             */
+/* Author    : Ole Husby, BIBSYS                                       */
+/* Updated   : 1998-09-30                                              */
+/* ------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+
+
+
+
+int M2Mconv(char *dfile, char *buffer, char *tfile, int format)
+{
+  char mtype[16], line[50000];
+  char *l, *p, *bf;
+  int lines;
+  FILE *df, *tf;
+
+  tf = (FILE *) NULL;
+  strcpy(mtype, "bibsys");
+
+
+/* Open inputfile */
+
+  df = fopen(dfile, "r");
+  if (!df)
+    return 0;                            /* Error: Unable to read data */
+
+
+
+/* Open tracefile */
+
+   if (*tfile)
+   {
+     tf = fopen(tfile, "w");
+     if (!tf)
+     {
+       fclose(df);
+       return 0;                         /* Error: Unable to create trace */
+     }
+   }
+
+
+/* Reads the file */ 
+
+   lines = 0;
+
+   while (l = fgets(line, 49999, df))
+   {
+/*   Remove trailing lf or cr     */
+
+     while ( (l[strlen(l) - 1] == '\n') || (l[strlen(l) - 1] == '\r') )
+       l[strlen(l) -1] = '\0';
+
+     lines++;
+     if (lines > 1)
+       break;                            /* Error: Not a 2709 file       */
+     p = l;
+   }
+
+
+/* Close files */ 
+
+  fclose(df);
+
+  if (tf)
+    fclose(tf);
+
+  if ( lines > 1 )
+    return 0;
+
+
+/* Convert to line format */
+
+  bf = (char *) marc2line(p, mtype);
+
+  strcpy(buffer, bf);
+
+  return 1;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/MARC2709.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/MARC2709.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/MARC2709.c	(revision 10506)
@@ -0,0 +1,495 @@
+/* ------------------------------------------------------------------- */
+/* MARC2709  : Converts a "line format MARC record" into ISO 2709      */
+/*                                                                     */
+/*             Input string requirements:                              */
+/*             1. New MARC tag is indicated by MARC tag in pos 1-3     */
+/*                (may be preceded by *). Indicator follows in next 2  */
+/*                bytes.                                               */
+/*             2. Continuation line is indicated by blank in col 1     */
+/*             3. End-of-record (^) may or may not be present          */
+/*                                                                     */
+/* author    : Ole Husby                                               */
+/* updated   : 1998-09-30                                              */
+/* ------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#define NORMARC                                12
+
+#define SUBFIELD_CODE                          "\x1f"
+#define FIELD_TERMINATOR                       "\x1e"
+#define RECORD_TERMINATOR                      "\x1d"
+
+#define INDICATOR_COUNT                        '2'
+#define SUBFIELD_CODE_COUNT                    '2'
+#define LENGTH_OF_LENGTH_OF_FIELD              '4'
+#define LENGTH_OF_STARTING_CHARACTER_POSITION  '5'
+#define UNUSED                                 "   "
+#define TAG001                                 "001"
+#define TAG008                                 "008"
+#define SKIP                                     41
+
+static char out_record[10240],
+	      leader[24+1],
+	      directory[10240],
+	      field_001[32], 
+	      field_008[40+2],
+	      data_field[10240];
+
+
+static char logline[128];
+static char rstr[6], dollar, dollarstring[2];
+static int skip;
+
+static char direlem[300][12+1];
+static int dircntr;
+
+union LDR   {
+   char ldr_string[24+1];
+   struct {
+      char record_length[5],
+      record_status,
+      record_type,
+      bibliographic_level,
+      unused1[2],
+      indicator_count,
+      subfield_code_count,
+      base_adress[5],
+      unused2[3],
+      entry1,
+      entry2,
+      entry3,
+      entry4;
+   } ltab;
+ } ldr;
+
+static int startet = 0;
+
+
+
+/* ------------------------------------------------------------------- */
+/* Compare function for qsort                                          */
+/* ------------------------------------------------------------------- */
+
+int cmp(const void *a, const void *b)
+{
+   return strcmp((char*)a, (char*)b);
+}
+
+
+
+
+/* ------------------------------------------------------------------- */
+/* Convert integer to string of fixed length. Right justified padded   */
+/* with zeros. Returns NULL if error                                   */
+/* ------------------------------------------------------------------- */
+
+char *itoal(int n, int len)
+{
+   char *r;
+   r = (char *) rstr;
+
+   switch (len)
+   {
+      case  4 : sprintf(r, "%04d", n); break;
+      case  5 : sprintf(r, "%05d", n); break;
+      default : return NULL;                       
+   }
+
+   r[len] = '\0';
+
+   return r;
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* One 001 subfield is put into field_001                              */
+/* ------------------------------------------------------------------- */
+
+static int make_001(char *data, char subfield)
+{
+   int len;
+
+   startet = 0;
+   switch (subfield)
+   {
+      case ' ' : break;
+      case 'a' : break;
+      default  : return 1;
+   }
+
+   while (data[0] == ' ') data++;
+   strcpy(field_001, data);
+
+   len = strlen(data) + 1;
+   skip = SKIP + len;
+
+   sprintf(directory, "00100%2d000000080041000%2d", len, len);
+   return 1;
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* One subfield string is appended to data_field                       */
+/* ------------------------------------------------------------------- */
+
+static int out_subfield(char *data, char *ftag, char subfield, char nextsubfield)
+{
+   int len, subint;
+   char subreplace, *p, *up;
+
+   while (data[strlen(data) -1] == ' ') 
+          data[strlen(data) -1] = '\0';            /* strip trailing blanks */
+
+   if (subfield == '3')                            /* always discard $3     */
+      return 1;
+
+   if (strcmp(ftag, TAG001) == 0)                  /* 001 data treatment     */
+   {
+      make_001(data, subfield);
+      return 1;
+   }
+   
+   if (strcmp(ftag, TAG008) == 0)                  /* 008 data treatment     */
+   {
+      strncpy(field_008, data, strlen(data)); 
+      return 1;
+   }
+   
+   if (subfield != ' ')                             /* handle subfield code  */
+   {
+      strcat(data_field, SUBFIELD_CODE);
+      len = strlen(data_field);
+      data_field[len] = subfield;
+      data_field[len + 1] = '\0';
+   }
+
+   while(data[0] == ' ') data++;                   /* strip leading blanks   */
+   if (!data) return 0;
+
+   strcat(data_field, data);                       /* append data            */
+   
+   return 1;
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* One MARC field is split into subfields and given to output          */
+/* ------------------------------------------------------------------- */
+
+static int out_field(char *data, char *ftag, char *find)
+{
+   char lnumber[5], snumber[6];
+   int fStart, fLen, moresubs;
+   char subfield[5120], *sub, subcode, *nextsub, nextsubcode;
+   char *v, subfield_v[32];
+
+   if (!startet) return 1;
+
+   if ((strncmp(ftag, "00", 2) == 0) &&
+       (strcmp(ftag, TAG001) != 0) &&
+       (strcmp(ftag, TAG008) != 0))
+      return 1;
+
+   fStart = strlen(data_field);
+   
+   if (strncmp(data, "  $", 3) == 0) data +=2;   /* possible if 008         */
+
+   if (data[0] != dollar)                        /* Dollar sign missing     */
+   {
+      if (strncmp(ftag,"00",2) != 0) return 0;   /* only allowed if tag=00x */
+	 
+      if (strcmp(ftag, TAG001) == 0)             /* 001: skip leading blanks */
+         while (data[0] == ' ') 
+            data++;  
+
+      subcode = ' ';
+      nextsubcode = ' ';
+
+      if (!out_subfield(data, ftag, subcode, nextsubcode)) 
+	 return 0;
+      return 1;
+   }
+
+   else
+   {
+      data++;
+
+      if (!data) return 0;
+
+      if (strncmp(ftag,"00",2) != 0)             /* append indicators       */
+         strcat(data_field, find);
+      
+      sub = strtok(data, dollarstring);          /* first subfield          */
+      if (!sub)
+         return 0;
+
+/*    printf("--- %s\n", sub); */
+
+      subcode = sub[0];
+      sub++;
+
+      moresubs = 1;
+
+      while (moresubs)                           /* loop while more subflds */
+      {  
+         nextsub = strtok(NULL, dollarstring);   /* next subfld             */
+         if (nextsub) 
+         {
+/*          printf("--- %s\n", nextsub); */
+	    nextsubcode = nextsub[0];
+	    nextsub++;
+         }
+         else
+            nextsubcode = ' ';
+
+         if (sub)
+         {
+	    if (!out_subfield(sub, ftag, subcode, nextsubcode)) 
+	       return 0;
+/*          printf("Denne |%c| Neste |%c|\n", subcode, nextsubcode);  */
+         }
+
+         if (nextsub)
+         {
+            subcode = nextsubcode;
+            sub = nextsub;
+         }
+         else
+            moresubs = 0;
+      }
+   }
+
+   if (strcmp(ftag,TAG001) == 0 || strcmp(ftag,TAG008) == 0)              
+      return 1;                                  /* directory ready         */
+
+   strcat(data_field, FIELD_TERMINATOR);         /* terminate data field   */
+   fLen = strlen(data_field) - fStart;           /* length of field        */
+
+   strcpy(lnumber,itoal(fLen,4));                /* convert to 4digit str  */
+   if (!lnumber) return 0;
+   strcpy(snumber,itoal(fStart + skip,5));       /* convert start          */
+   if (!snumber) return 0;
+
+   strcpy(direlem[dircntr], ftag);               /* start direlem with tag */
+   strcat(direlem[dircntr], lnumber);            /* append length to dir   */
+   strcat(direlem[dircntr], snumber);            /* append start to dir    */
+   dircntr++;
+
+   return 1;
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* Main program                                                        */
+/* ------------------------------------------------------------------- */
+
+char *MARC2709(char *record, int last, int first, char recstatus, 
+  char rectype, char biblevel)          
+{
+   static char buffer[10240], field_data[5120], tag[4], ind[3];
+   char        alen[3], *cp, *buf = buffer, *cq, logline[128];
+   int                  prelen, ii; 
+   int                  lastchar, Last, First, x, more;
+   int			SOF, digits, newField;
+
+   char test[6];
+
+   strcpy(buf, record);
+
+   Last = First = 0;                        /* initialize             */
+   if (last > 0)                            /* Last : linelength if   */
+   {                                        /*        fixed           */
+      Last = last;                          /* First: starting col    */
+      First = first;                        /*        for cont. line  */
+   }
+  
+   prelen = 5;
+   dollar = '$';
+   strcpy(dollarstring, "$");
+
+   data_field[0] = '\0';
+   directory[0]  = '\0';
+   strcpy(field_001, "         ");
+   strcpy(field_008, "                                        ");
+   out_record[0] = '\0';
+   dircntr       = 0;
+   startet       = 0;
+
+   /* initialize directory  with 9 bytes for 001 */
+
+   sprintf(directory, "001001000000008004100010", alen, alen);
+   skip = SKIP + 10;
+
+   more = 1; 
+   while (more)                                       /* loop until EOR  */ 
+   {
+      x = 0;                                          /* x counts bytes  */
+
+      for (cp = buf; *cp && *cp != '\n'; cp++) x++;   /* read until LF   */
+
+      if (!*cp)                                       /* EOR             */
+        more = 0; 
+      else
+        cp++;
+
+      SOF = 0;
+
+      if (buf[0] == '^') break;                       /* "EOR-line"      */
+      if (buf[0] == '*')                              /* skip leading *  */
+      {
+	 buf++;
+	 x--;
+         SOF = 1;
+      }
+
+      if (x == 0) continue;                           /* empty line     */
+
+      digits = 1;                                     /* test if first 3     */ 
+      for (ii = 0; ii < 3; ii++)                      /* bytes are digits    */
+         if (!isdigit(buf[ii]))
+         {
+            digits = 0;
+            break;
+         }
+         
+      newField = 0;     
+
+      if (SOF)
+      {
+	if (!digits) continue;                      /* illegal line        */
+        else newField = 1;
+      } 
+      else
+	 if (digits) newField = 1;
+
+
+      if (newField)                                  /* start of new field   */
+      {
+	 if (!out_field(field_data, tag, ind))       /* output prev. field   */
+	    return NULL;
+
+	 startet = 1;
+	 field_data[0] = '\0';                       /* reset field buffer   */
+	 strncpy(tag, buf, 3);                       /* keep MARC tag        */
+	 buf += 3;
+	 x -=3;
+     
+         if (strncmp(tag, "00", 2) != 0) 
+         {
+            strncpy(ind, buf, 2);                 /* keep indicator       */
+            buf += 2;                             /* if not control field */
+            x -= 2;
+         }
+
+	 strncat(field_data, buf, x);             /* keep data               */
+        
+	   					/* strip trailing blanks   */
+	 while (field_data[strlen(field_data) -1] == ' ')
+	 {
+	    field_data[strlen(field_data) -1] = '\0';
+	    x--;
+	 }
+
+	 if (Last && x == (Last - prelen))           /* full line            */
+            lastchar = 1;
+         else 
+            lastchar = 0;
+      }
+
+      else                                     /* continuation line     */
+      {
+	if (Last)
+	{
+	   cq  = buf + First - 1;              /* skip fixed nmbr chars */
+	   x -= (First - 1); 
+	   if (!lastchar && cq[0] != ' '       /* and insert one blank  */
+	       && cq[0] != dollar)
+	      strcat(field_data, " ");         /* if needed             */
+	}
+	else
+	{
+	   for (cq = buf; *cq == ' '; cq++) x--;  /* skip leading blanks   */
+	   strcat(field_data, " ");               /* insert one blank      */
+	}
+
+	strncat(field_data, cq, x);            /* append data           */
+                                               /* strip trail. blanks   */
+        while (field_data[strlen(field_data) -1] == ' ')
+        {
+	   field_data[strlen(field_data) -1] = '\0';
+	   x--;
+	}
+
+	if (Last && x == (Last - 5))           /* full line            */
+	   lastchar = 1;
+        else lastchar = 0;
+        
+      }
+
+      while (field_data[strlen(field_data) -1] == ' ')
+         field_data[strlen(field_data) - 1] = '\0'; /* rm trailing blanks */
+      buf = cp;
+   }
+
+   if (!out_field(field_data, tag, ind))       /* output last field     */
+      return NULL;
+
+                                               /* terminate field_001   */
+   strcat(field_001, FIELD_TERMINATOR); 
+
+   field_008[40] = '\0';                       /* terminate field_008   */
+   strcat(field_008, FIELD_TERMINATOR); 
+
+					       /* sort directory elem.  */
+   qsort ((void *) direlem, dircntr, sizeof(direlem[0]), cmp); 
+   for (ii = 0; ii < dircntr; ii++)
+      strcat(directory, direlem[ii]);          /* append to directory   */
+
+   strcat(directory, FIELD_TERMINATOR);        /* terminate dictionary  */ 
+   
+   strcat(data_field, RECORD_TERMINATOR);      /* terminate data        */
+
+   x = 24 + strlen(directory);                 /* construct leader      */
+   
+   strcpy(test, itoal(x,5));
+
+   strncpy(ldr.ltab.base_adress, test, 5);
+
+   x += (strlen(data_field)
+       + strlen(field_001)
+       + strlen(field_008));
+
+   strcpy(test, itoal(x,5));
+   
+   strncpy(ldr.ltab.record_length, test, 5);
+   
+   ldr.ltab.record_status = recstatus;
+   ldr.ltab.record_type = rectype;
+   ldr.ltab.bibliographic_level = biblevel;
+   ldr.ltab.indicator_count = INDICATOR_COUNT;
+   ldr.ltab.subfield_code_count = SUBFIELD_CODE_COUNT;
+   strncpy(ldr.ltab.unused1,UNUSED,2);
+   strncpy(ldr.ltab.unused2,UNUSED,3);
+   ldr.ltab.entry1 = LENGTH_OF_LENGTH_OF_FIELD;
+   ldr.ltab.entry2 = LENGTH_OF_STARTING_CHARACTER_POSITION;
+   ldr.ltab.entry3 = '0';     
+   ldr.ltab.entry4 = '0';     
+
+   ldr.ldr_string[24] = '\0';
+
+   strcpy(out_record, ldr.ldr_string);          /* put together record  */
+   strcat(out_record, directory);
+   strcat(out_record, field_001);
+   strcat(out_record, field_008);
+   strcat(out_record, data_field);
+ 
+   return out_record; 
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/MARCmake.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/MARCmake.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/MARCmake.c	(revision 10506)
@@ -0,0 +1,33 @@
+/* ------------------------------------------------------------------- */
+/* MARCmake  : Convert a metatag struct to MARC and add it to the      */
+/*             marcrecord struct.                                      */
+/*                                                                     */
+/*             This is where the format-dependent conversion           */
+/*             program is selected.                                    */
+/*                                                                     */
+/* Author    : Ole Husby                                               */
+/* Updated   : 1998-09-30                                              */
+/* ------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include "d2m.h" 
+
+
+
+int MARCmake(struct metatag *mt, struct marcrec *mr, int format)
+{
+  char pre[64], creator_tag[4];
+
+  if (format == DANMARC)
+    return danMARC(mt, mr);
+  else if (format == FINMARC)
+    return finMARC(mt, mr);
+  else if (format == ISMARC)
+    return isMARC(mt, mr);
+  else if (format == USMARC)
+    return usMARC(mt, mr);
+  else if (format == SWEMARC)
+    return sweMARC(mt, mr);
+  else
+    return norMARC(mt, mr);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/MARCtidy.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/MARCtidy.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/MARCtidy.c	(revision 10506)
@@ -0,0 +1,147 @@
+/* ------------------------------------------------------------------- */
+/* MARCtidy  : Tidying up of MARC record, building the line format     */
+/*             record.                                                 */
+/*                                                                     */
+/* Syntax    : MARCtidy(marcrec *mrec, char *buf, int format)          */
+/*                                                                     */
+/*             The preliminary MARC data are converted from the        */
+/*             mrec struct to the buf line format buffer.              */
+/*                                                                     */
+/*             The main data is in mrec->marcline, while some          */
+/*             additional data (year, URL ...) are kept in separat     */
+/*             variables to be added in.                               */
+/*                                                                     */
+/* NOTE      : The behaviour of this program i sto some extent         */
+/*             depending on the format argument!                       */
+/*                                                                     */
+/* Author    : Ole Husby, BIBSYS                                       */
+/* Updated   : 1998-09-30                                              */
+/* ------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "d2m.h"
+
+
+
+void  nline(char *p, char *l, char *buf)
+{
+   strcat(buf, p);
+   if (strncmp(p, "00", 2) != 0)
+     strcat(buf, " ");
+   strcat(buf, l);
+   strcat(buf, "\n");
+}
+
+
+
+void MARCtidy(struct marcrec *mrec, char *buf, int format)
+{
+
+   char *p, *u, *l;
+   char pre[64], line[10000];
+
+   p = (char *) &pre;
+   l = (char *) &line;
+
+   *buf = 0;
+
+   strcpy(p, "008");
+   strcpy(l, mrec->s008);
+   nline(p, l, buf);
+
+   u = strtok(mrec->marcline, "\n");
+   while (u && *u)
+   {
+      if (strlen(u) > 7)
+      {
+        *p = 0;
+        strncat(p, u, 7);
+        strcpy(l, u + 8);
+        nline(p, l, buf);
+
+
+/*      Add 245 subfields after $a */
+
+        if ( (strncmp(p, "245", 3) == 0) && (strncmp(p + 5, "$a", 2) == 0) )
+        {
+          if ( ( format == NORMARC ) && ( *mrec->subtitle) )
+          {
+            strcpy(p, "     $b");
+            strcpy(l, mrec->subtitle);
+            nline(p, l, buf);
+          }
+          if ( *mrec->partitle )
+          {
+            if ( format == FINMARC || format == DANMARC ) 
+            {
+              strcpy(p, "    ");
+              strcpy(l, mrec->partitle);
+              nline(p, l, buf);
+            }
+            if ( format == ISMARC ) 
+            {
+              strcpy(l, mrec->partitle);
+              nline(p, l, buf);
+            }
+          }
+        } 
+
+/*      Add year as 260 $c after $b                                    */
+
+        if ( (strncmp(p, "260", 3) == 0) && (strncmp(p + 5, "$b", 2) == 0) )
+        {
+          if (*mrec->year)
+          {
+            strcpy(p, "     $c");
+            strcpy(l, mrec->year);
+            nline(p, l, buf);
+            *mrec->year = 0;
+          }
+        } 
+      }
+      u = strtok(NULL, "\n");
+   }
+
+/* Add year as 260 $c if not aleady done                               */
+
+   if (*mrec->year)
+   {
+     strcpy(p, "260  $c");
+     strcpy(l, mrec->year);
+     nline(p, l, buf);
+   }
+
+/* Add parallel title in spearate field  */
+
+   if ( *mrec->partitle && ( format == ISMARC ) ) 
+   {
+     strcpy(p, "24630$c");
+     strcpy(l, mrec->partitle);
+     nline(p, l, buf);
+   }
+
+
+/* Add URL as 856 $u                                                 */
+
+   if (*mrec->url)
+   {
+     strcpy(p, "856  $u");
+     strcpy(l, mrec->url);
+     nline(p, l, buf);
+
+/* Add format as $q                                                    */
+
+     if (*mrec->fmat)
+     {
+       strcpy(p, "     $q");
+       strcpy(l, mrec->fmat);
+       nline(p, l, buf);
+     }
+   }
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/Makefile.in	(revision 10506)
@@ -0,0 +1,45 @@
+# ///////////////// d2m : Dublin Core to MARC converter /////////////////////
+#
+#
+# Modified for Greenstone kjdon May 2005.
+# Used by z3950server
+
+CC = @CC@
+AR = ar
+RANLIB = @RANLIB@
+
+o = .@U@o
+
+# This may have to uncomment this on solaris ???
+# LIBS = -lsocket -lnsl
+
+LIB_OBJS = MARC2709.o MARCtidy.o usMARC.o util.o
+
+all: libd2m.a
+
+libd2m.a: $(LIB_OBJS)
+	rm -f libd2m.a
+	$(AR) cru libd2m.a $(LIB_OBJS)
+	$(RANLIB) libd2m.a
+
+
+MARCtidy.o: MARCtidy.c d2m.h
+	$(CC) -c MARCtidy.c
+
+MARC2709.o: MARC2709.c d2m.h
+	$(CC) -c MARC2709.c
+
+util.o: util.c d2m.h
+	$(CC) -c util.c 
+
+usMARC.o: usMARC.c d2m.h
+	$(CC) -c usMARC.c
+
+install:
+
+clean:
+	rm -f *.o libd2m.a
+
+distclean: clean
+	rm -f Makefile config.h
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/Makefile.orig
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/Makefile.orig	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/Makefile.orig	(revision 10506)
@@ -0,0 +1,111 @@
+# ///////////////// d2m : Dublin Core to MARC converter /////////////////////
+#
+# The basic conversion (reading a file and producing a MARC record)
+# is performed by D2Mconv.c
+#
+# On top of D2Mconv.c is built 2 applications:
+#
+# d2m   : A CGI version
+#         (See documentation in main program D2Mcgi.c)
+# d2main: A command line (standalone version)
+#         (See documentation in main program D2Mmain.c)
+#
+# Both applications are capable of reading from a local file or a
+# remote file using builtin HTTP client services. 
+#
+# (You can compile a version of d2main without HTTP ability by
+#   make d2main-nosock 
+# )
+#
+# Both applications has the added ability to read a 2709 MARC record
+# instead of DC metadata, using M2Mconv.c to perform the conversion.
+# (This is not a MARC converter with the ability to convert between
+# MARC formats, just between "presentation syntaxes".
+#
+# 1998-10-15 Ole Husby
+#
+
+CC = cc 
+
+# This may have to uncomment this on solaris:
+# LIBS = -lsocket -lnsl
+
+OBJ = D2Mconv.o M2Mconv.o marc2line.o util.o MARC2709.o MARCmake.o MARCtidy.o dc_parse.o
+OBJ_MARC = danMARC.o finMARC.o isMARC.o norMARC.o sweMARC.o usMARC.o
+OBJ_SOCK = wfetch.o htget.o
+OBJ_NOSOCK = wfetch-l.o
+
+all: d2m d2main
+
+d2m: D2Mcgi.o $(OBJ) $(OBJ_MARC) $(OBJ_SOCK) 
+	@echo "------------------- Compiling d2m -------------------------------" 
+	$(CC) D2Mcgi.o $(OBJ) $(OBJ_MARC) $(OBJ_SOCK) -o d2m $(LIBS) 
+
+d2main: D2Mmain.o $(OBJ) $(OBJ_MARC) $(OBJ_SOCK) 
+	@echo "------------------- Compiling d2main ----------------------------" 
+	$(CC) D2Mmain.o $(OBJ) $(OBJ_MARC) $(OBJ_SOCK) -o d2main $(LIBS) 
+
+d2main-nosock: D2Mmain.o $(OBJ) $(OBJ_MARC) $(OBJ_NOSOCK) 
+	@echo "------------------- Compiling d2main (no sockets) ---------------" 
+	$(CC) D2Mmain.o $(OBJ) $(OBJ_MARC) $(OBJ_NOSOCK) -o d2main $(LIBS) 
+
+
+D2Mcgi.o: D2Mcgi.c d2m.h
+	$(CC) -c D2Mcgi.c
+
+D2Mmain.o: D2Mmain.c d2m.h
+	$(CC) -c D2Mmain.c
+
+D2Mconv.o: D2Mconv.c d2m.h
+	$(CC) -c D2Mconv.c
+
+M2Mconv.o: M2Mconv.c
+	$(CC) -c M2Mconv.c
+
+marc2line.o: marc2line.c 
+	$(CC) -c marc2line.c
+
+MARCmake.o: MARCmake.c d2m.h
+	$(CC) -c MARCmake.c
+
+MARCtidy.o: MARCtidy.c d2m.h
+	$(CC) -c MARCtidy.c
+
+MARC2709.o: MARC2709.c d2m.h
+	$(CC) -c MARC2709.c
+
+dc_parse.o: dc_parse.c d2m.h
+	$(CC) -c dc_parse.c
+
+util.o: util.c d2m.h
+	$(CC) -c util.c 
+
+danMARC.o: danMARC.c d2m.h
+	$(CC) -c danMARC.c
+
+finMARC.o: finMARC.c d2m.h
+	$(CC) -c finMARC.c
+
+isMARC.o: isMARC.c d2m.h
+	$(CC) -c isMARC.c
+
+norMARC.o: norMARC.c d2m.h
+	$(CC) -c norMARC.c
+
+sweMARC.o: sweMARC.c d2m.h
+	$(CC) -c sweMARC.c
+
+usMARC.o: usMARC.c d2m.h
+	$(CC) -c usMARC.c
+
+wfetch.o: wfetch.c
+	$(CC) -c wfetch.c
+
+wfetch-l.o: wfetch-l.c
+	$(CC) -c wfetch-l.c
+
+htget.o: htget.c 
+	$(CC) -c htget.c 
+
+clean:
+	rm -f *.o d2m d2main
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/README.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/README.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/README.html	(revision 10506)
@@ -0,0 +1,159 @@
+<html><head><title>
+d2m v0.2
+</title>
+</head>
+
+<body bgcolor="#ffffcc">
+
+<font face="Comic Sans MS">
+<h1 align=center>d2m : A Dublin Core to MARC converter</h1>
+
+<div align=center>
+
+version 0.2<br>
+1998-10-14<br>
+Ole Husby<br>
+BIBSYS<br>
+ole.husby@bibsys.no
+</div>
+</font>
+
+
+<h2>1. Introduction</h2>
+
+This software is part of the results from the Nordic Metadata project.
+(See <a href="http://linnea.helsinki.fi/meta/">
+http://linnea.helsinki.fi/meta/</a>).
+
+<p>
+ 
+This version is a "pre-release". It is not really ready for distribution.
+All the customary disclaimers apply!
+The programs have been compiled on Solaris, AIX and Linux.
+
+
+
+<h2>2. Contents</h2>
+
+The distribution includes the following files:
+
+<table>
+<tr><td><b>README.html </b></td><td>This file</td></tr>
+<tr><td><b>Makefile    </b></td><td>Also includes some documentation</td></tr>
+<tr><td><b>d2m.h       </b></td><td>Common include file</td></tr>
+<tr><td><b>D2Mcgi.c    </b></td><td>Main program for the CGI version</td></tr>
+<tr><td><b>D2Mmain.c   </b></td><td>Main program for the standalone version</td></tr>
+<tr><td><b>D2Mconv.c   </b></td><td>Inputs file with DC metadata, outputs line MARC record</td></tr>
+<tr><td><b>M2Mconv.c   </b></td><td>Inputs file with ISO 2709 MARC record, outputs line MARC record</td></tr>
+<tr><td><b>MARC2709.c  </b></td><td>Converts from line MARC format to ISO 2709 MARC format</td></tr>
+<tr><td><b>MARCmake.c  </b></td><td>Builds a MARC struct from a DC struct. Selects one of the following :</td></tr>
+<tr><td><b>danMARC.c   </b></td><td>&nbsp;</td></tr>
+<tr><td><b>finMARC.c   </b></td><td>&nbsp;</td></tr>
+<tr><td><b>isMARC.c    </b></td><td>&nbsp;</td></tr>
+<tr><td><b>norMARC.c   </b></td><td>&nbsp;</td></tr>
+<tr><td><b>sweMARC.c   </b></td><td>&nbsp;</td></tr>
+<tr><td><b>usMARC.c    </b></td><td>&nbsp;</td></tr>
+<tr><td><b>MARCtidy.c  </b></td><td>Finishes the line MARC record from the MARC struct</td></tr>
+<tr><td><b>marc2line.c </b></td><td>Converts from ISO 2709 MARC format to line MARC format</td></tr>
+<tr><td><b>htget.c     </b></td><td>Fetches a remote file using HTTP</td></tr>
+<tr><td><b>dc_parse.c  </b></td><td>Parses an HTML <META> tag</td></tr>
+<tr><td><b>util.c      </b></td><td>Some utilities</td></tr>
+<tr><td><b>wfetch.c    </b></td><td>Small program on top of htget()</td></tr>
+<tr><td><b>wfetch-l.c  </b></td><td>Dummy version of wfetch.c, does nothing except return 0</td></tr>
+<tr><td><b>test.data   </b></td><td>A simple test file with a <meta> tag.</td></tr>
+</table>
+
+<h2>3. Compilation</h2>
+
+Unpack the d2m-v02.tar file. It will produce a directory <b>d2m-v02/</b>
+with the contents listed above.
+
+<p>
+
+Check the Makefile.
+
+<p>
+
+Type
+
+<pre>
+
+  <b>make all</b>
+
+</pre>
+
+This should produce the programs <b>d2m</b> and <b>d2main</b> . 
+
+<p>
+
+If you do not need access to remote files, or have problems compiling
+socket libraries, try to compile
+  
+<pre>
+
+  <b>make d2main-nosock</b>
+
+</pre>
+
+
+<h2>4. Use of d2main</h2>
+
+<b>d2main</b> should be ready to execute from the command line. No configuration
+or environment variables are needed.
+
+<p>
+
+If you do not enter any arguments, a short instruction will be printed.
+
+<p>
+
+The first test could be 
+
+<pre>
+
+  <b>d2main test.data -l</b>
+
+</pre>
+
+The next test could be (if d2main is not compiled using Makefile-l)
+
+<pre>
+
+  <b>d2main http://linnea.helsinki.fi/meta/ -l -m FINMARC</b>
+
+</pre>
+
+<h2>5. Use of d2m</h2>
+
+<b>d2m</b> should be used as a CGI program.
+
+<p>
+  
+A simple users guide is in D2Mcgi.c
+
+<p>
+
+See an example of use in <a href="http://www.bibsys.no/meta/d2m">
+http://www.bibsys.no/meta/d2m</a>
+
+
+
+<h2>6. Tailoring</h2>
+
+This version is not table-driven. The different MARC formats are
+treated by customized functions (norMARC.c, isMARC.c etc.). The
+selection of conversion program is performed by MARKmake.c .
+
+<p>
+
+The program MARCtidy.c is also to some degree depending of the
+MARC format. In addition there is a small sequence in D2Mconv.c
+with a special treatment for ISMARC. (It should really not be
+done there ...). Apart from this, all programs are independent on
+MARC format.
+
+<p>
+
+The supported formats are introduced in d2m.h .
+
+</body></html>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/README_GS
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/README_GS	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/README_GS	(revision 10506)
@@ -0,0 +1,14 @@
+d2m : Dublin Core to MARC converter
+Software distribution: Prerelease version
+version 0.2
+1998-10-14
+Ole Husby
+BIBSYS
+ole.husby@bibsys.no
+
+http://www.bibsys.no/meta/d2m/distr/
+
+The original Makefile that comes with d2m has been saved as Makefile.orig, and a new Makefile.in and some configure scripts have been generated for use with Greenstone.
+
+We no longer compile up the two executables, instead just compile the source into a library: libd2m.a.
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/config.h.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/config.h.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/config.h.in	(revision 10506)
@@ -0,0 +1,107 @@
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+   to 0 otherwise. */
+#undef HAVE_MALLOC
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the `putenv' function. */
+#undef HAVE_PUTENV
+
+/* Define to 1 if you have the `socket' function. */
+#undef HAVE_SOCKET
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strftime' function. */
+#undef HAVE_STRFTIME
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the `strstr' function. */
+#undef HAVE_STRSTR
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to rpl_malloc if the replacement function should be used. */
+#undef malloc
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/configure
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/configure	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/configure	(revision 10506)
@@ -0,0 +1,4903 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59 for FULL-PACKAGE-NAME VERSION.
+#
+# Report bugs to <BUG-REPORT-ADDRESS>.
+#
+# 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='FULL-PACKAGE-NAME'
+PACKAGE_TARNAME='full-package-name'
+PACKAGE_VERSION='VERSION'
+PACKAGE_STRING='FULL-PACKAGE-NAME VERSION'
+PACKAGE_BUGREPORT='BUG-REPORT-ADDRESS'
+
+ac_unique_file="danMARC.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 RANLIB ac_ct_RANLIB CPP EGREP 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 FULL-PACKAGE-NAME VERSION 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
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of FULL-PACKAGE-NAME VERSION:";;
+   esac
+  cat <<\_ACEOF
+
+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.
+
+Report bugs to <BUG-REPORT-ADDRESS>.
+_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
+FULL-PACKAGE-NAME configure VERSION
+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.
+_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 FULL-PACKAGE-NAME $as_me VERSION, 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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+          ac_config_headers="$ac_config_headers config.h"
+
+
+# Checks for programs.
+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
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; 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_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # 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_RANLIB="${ac_tool_prefix}ranlib"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; 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_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # 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_RANLIB="ranlib"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  RANLIB=$ac_ct_RANLIB
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+
+# Checks for libraries.
+
+# Checks for header files.
+
+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
+
+
+
+
+
+
+
+
+
+
+for ac_header in fcntl.h malloc.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  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
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+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
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_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
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to BUG-REPORT-ADDRESS ##
+## --------------------------------- ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+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
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+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
+
+
+# Checks for typedefs, structures, and compiler characteristics.
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+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 ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this.  */
+  typedef int charset[2];
+  const charset x;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *ccp;
+  char **p;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  ccp = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++ccp;
+  p = (char**) ccp;
+  ccp = (char const *const *) p;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; };
+    struct s *b; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+  }
+#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_cv_c_const=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_c_const=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+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 ((size_t *) 0)
+  return 0;
+if (sizeof (size_t))
+  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_size_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_size_t=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned
+_ACEOF
+
+fi
+
+echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5
+echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6
+if test "${ac_cv_struct_tm+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 <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm *tp; tp->tm_sec;
+  ;
+  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_struct_tm=time.h
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5
+echo "${ECHO_T}$ac_cv_struct_tm" >&6
+if test $ac_cv_struct_tm = sys/time.h; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TM_IN_SYS_TIME 1
+_ACEOF
+
+fi
+
+
+# Checks for library functions.
+
+for ac_header in stdlib.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  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
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+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
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_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
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## --------------------------------- ##
+## Report this to BUG-REPORT-ADDRESS ##
+## --------------------------------- ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+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
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+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 GNU libc compatible malloc" >&5
+echo $ECHO_N "checking for GNU libc compatible malloc... $ECHO_C" >&6
+if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_func_malloc_0_nonnull=no
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#if STDC_HEADERS || HAVE_STDLIB_H
+# include <stdlib.h>
+#else
+char *malloc ();
+#endif
+
+int
+main ()
+{
+exit (malloc (0) ? 0 : 1);
+  ;
+  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_func_malloc_0_nonnull=yes
+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_func_malloc_0_nonnull=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_malloc_0_nonnull" >&5
+echo "${ECHO_T}$ac_cv_func_malloc_0_nonnull" >&6
+if test $ac_cv_func_malloc_0_nonnull = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MALLOC 1
+_ACEOF
+
+else
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_MALLOC 0
+_ACEOF
+
+   case $LIBOBJS in
+    "malloc.$ac_objext"   | \
+  *" malloc.$ac_objext"   | \
+    "malloc.$ac_objext "* | \
+  *" malloc.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;;
+esac
+
+
+cat >>confdefs.h <<\_ACEOF
+#define malloc rpl_malloc
+_ACEOF
+
+fi
+
+
+
+echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
+if test "${ac_cv_type_signal+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 <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int
+main ()
+{
+int i;
+  ;
+  return 0;
+}
+_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_signal=void
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_type_signal=int
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+echo "${ECHO_T}$ac_cv_type_signal" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+for ac_func in strftime
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+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.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  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
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  # strftime is in -lintl on SCO UNIX.
+echo "$as_me:$LINENO: checking for strftime in -lintl" >&5
+echo $ECHO_N "checking for strftime in -lintl... $ECHO_C" >&6
+if test "${ac_cv_lib_intl_strftime+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lintl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char strftime ();
+int
+main ()
+{
+strftime ();
+  ;
+  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
+  ac_cv_lib_intl_strftime=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_intl_strftime=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_intl_strftime" >&5
+echo "${ECHO_T}$ac_cv_lib_intl_strftime" >&6
+if test $ac_cv_lib_intl_strftime = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRFTIME 1
+_ACEOF
+
+LIBS="-lintl $LIBS"
+fi
+
+fi
+done
+
+
+
+
+
+
+
+
+
+for ac_func in alarm gethostbyname putenv socket strcasecmp strdup strncasecmp strstr
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+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.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  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
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+          ac_config_files="$ac_config_files 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
+
+DEFS=-DHAVE_CONFIG_H
+
+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 FULL-PACKAGE-NAME $as_me VERSION, 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
+  --header=FILE[:TEMPLATE]
+		   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+FULL-PACKAGE-NAME config.status VERSION
+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
+_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" ;;
+  "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+  *) { { 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
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+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,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@CPP@,$CPP,;t t
+s,@EGREP@,$EGREP,;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
+
+
+
+  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
+" $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
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([	 ]*\)#\([	 ]*define[	 ][	 ]*\)'
+ac_dB='[	 ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([	 ]*\)#\([	 ]*\)undef\([	 ][	 ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; 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
+
+  test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+  # 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; }; }
+	 # Do quote $f, to prevent DOS paths from being IFS'd.
+	 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; }
+  # Remove the trailing spaces.
+  sed 's/[	 ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h.  The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status.  Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*\)\(([^)]*)\)[	 ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless.  Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[	 ]*#[	 ]*undef[	 ][	 ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo '  if grep "^[	 ]*#[	 ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo '  # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo '  :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+  # Write a limited-size here document to $tmp/defines.sed.
+  echo '  cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#define' lines.
+  echo '/^[	 ]*#[	 ]*define/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/defines.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo '  fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+  # Write a limited-size here document to $tmp/undefs.sed.
+  echo '  cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#undef'
+  echo '/^[	 ]*#[	 ]*undef/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+  rm -f conftest.undefs
+  mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+  # 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
+    echo "/* Generated by configure.  */" >$tmp/config.h
+  else
+    echo "/* $ac_file.  Generated by configure.  */" >$tmp/config.h
+  fi
+  cat $tmp/in >>$tmp/config.h
+  rm -f $tmp/in
+  if test x"$ac_file" != x-; then
+    if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      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; }; }; }
+
+      rm -f $ac_file
+      mv $tmp/config.h $ac_file
+    fi
+  else
+    cat $tmp/config.h
+    rm -f $tmp/config.h
+  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: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/configure.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/configure.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/configure.in	(revision 10506)
@@ -0,0 +1,30 @@
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
+AC_CONFIG_SRCDIR([danMARC.c])
+AC_CONFIG_HEADER([config.h])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_RANLIB
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([fcntl.h malloc.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+AC_STRUCT_TM
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_TYPE_SIGNAL
+AC_FUNC_STRFTIME
+AC_CHECK_FUNCS([alarm gethostbyname putenv socket strcasecmp strdup strncasecmp strstr])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/d2m.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/d2m.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/d2m.h	(revision 10506)
@@ -0,0 +1,76 @@
+#ifndef D2MH
+#define D2MH
+
+#include <stdio.h>
+
+#define  TRUE    1
+#define  FALSE   0
+
+#define  HTML_TITLE           "d2m: Dublin Core to MARC conversion"
+
+#define  D2M_LINELEN          80
+#define  D2M_TEMPFILE         "/tmp/d2m.data"
+#define  D2M_TRACEFILE        "/tmp/d2m.trace"
+#define  D2M_DEFAULT_SYNTAX   "plain"
+#define  D2M_DEFAULT_FORMAT   "NORMARC"        
+#define  D2M_DEFAULT_URL      "http://www.bibsys.no/meta/test.html"
+
+struct metatag {
+   char    *name;
+   char    *type;
+   char    *scheme;
+   char    *value;
+               };
+
+struct marcrec {
+   int     ntitles;
+   int     ncreators;
+   char    *marcline;
+   char    *partitle;
+   char    *subtitle;
+   char    *year;
+   char    *url;
+   char    *fmat;
+   char    *s008;
+               };
+
+enum mformats {
+   USMARC,
+   DANMARC,
+   FINMARC,
+   ISMARC,
+   NORMARC,
+   SWEMARC    };
+
+enum SOURCES { TEXTAREA, URL };
+
+enum fields_in_008 {
+   F008_DATE_ENTERED,
+   F008_TYPE_OF_DATE,
+   F008_DATE1,
+   F008_LANGUAGE,
+   F008_FORM_OF_PUBLICATION };
+              
+enum levels {
+  LNAME,
+  LTYPE,
+  LSCHEME,
+  LOCC,
+  LTAG,
+  LIND,
+  LSUBF,
+  LRULE
+            };
+
+extern void write_field(char *i, FILE *of, int l, int n, int s);
+extern int write_trace(char *n, FILE *of);
+extern struct metatag *dc_parse(char *b); 
+extern char *cstr(char *h, char *n);
+extern void unescape(char *n);
+extern char *poq();
+extern int  put008(char *n, char *s, int p);
+extern int  find_year(char *n);
+extern int  split_name(char *n);
+extern int  split_subj(char *n);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/d2m4gs.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/d2m4gs.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/d2m4gs.h	(revision 10506)
@@ -0,0 +1,22 @@
+#ifndef D2M4GSH
+#define D2M4GSH
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "d2m.h"
+
+void MARCtidy(struct marcrec *mrec, char *buf, int format);
+void usMARC(struct metatag *mt, struct marcrec *mr);
+char *MARC2709(char *record, int last, int first, char recstatus, 
+	       char rectype, char biblevel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/danMARC.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/danMARC.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/danMARC.c	(revision 10506)
@@ -0,0 +1,239 @@
+/* ------------------------------------------------------------------- */
+/* danMARC    : Convert a metatag struct to DANMARC2                   */
+/*                                                                     */
+/* Specs      : http://www.bibsys.no/meta/d2m/dancross.html            */
+/*                                                                     */
+/* Author     : Ole Husby                                              */
+/* Last update: 1998-09-30                                             */
+/* ------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include "d2m.h" 
+
+
+
+/* Splits subject heading on ":". First occurence go into $a, second into $v */ 
+
+int split_dk5(char *str)
+{
+  char *p, *q, subtag[5];
+
+  if (!strstr(str, ":"))
+    return 1;
+
+  p = (char *) malloc(strlen(str) + 50);
+  *p = 0;
+  *subtag = 0;
+
+  q = strtok(str, ":");
+  if (q)
+  {
+    while ( ( q[0] == ' ' ) && ( strlen(q) ) )
+      q++;
+
+    while( ( q[strlen(q) - 1] == ' ' ) && ( strlen(q) ) )
+      q[strlen(q) - 1] = '\0';
+
+    if (*q)
+    {
+      strcat(p, subtag);
+      strcat(p, q);
+      strcpy(subtag, " $v ");
+    }
+  }
+
+  strcpy(str, p);
+  free(p);
+
+  return 1;
+}
+
+
+
+
+int danMARC(struct metatag *mt, struct marcrec *mr)
+{
+  char pre[64], type_tag[4];
+  int i;
+
+  *pre = 0;
+
+  if (strcasecmp(mt->name, "title") == 0)
+  {
+    if ( (!*mt->type)
+         | (strcasecmp(mt->type, "main") == 0)
+         | (strcasecmp(mt->type, "long") == 0) )
+    {
+      if (mr->ntitles)
+      {
+        strcat(mr->partitle, "$a ");
+        strcat(mr->partitle, mt->value);
+
+      }
+      else
+      {
+        mr->ntitles++;
+        strcpy(pre, "245  $a");
+      }
+    }
+  }
+
+  else if (strcasecmp(mt->name, "creator") == 0)
+  {
+    if ( strcasecmp(mt->type, "personal") == 0) 
+    {
+      strcpy(pre, "700  $a");
+      split_name(mt->value);
+    }
+    else if (strcasecmp(mt->type, "corporate") == 0)
+      strcpy(pre, "710  $a");
+  }
+
+
+  else if (strcasecmp(mt->name, "publisher") == 0)
+    strcpy(pre, "260  $b");
+
+  else if (strcasecmp(mt->name, "description") == 0)
+    strcpy(pre, "504  $a");
+
+  else if (strncasecmp(mt->name, "contributor", 11) == 0)   
+  {
+    if ( strcasecmp(mt->type, "personal") == 0 )
+    {
+      strcpy(pre, "700  $a");
+      split_name(mt->value);
+    }
+    else if (strcasecmp(mt->type, "corporate") == 0)
+      strcpy(pre, "710  $a");
+  }
+
+  else if (strcasecmp(mt->name, "coverage") == 0)
+  {
+    if (!*mt->type)
+      strcpy(pre, "559  $a");
+    else if (strcasecmp(mt->type , "spatial") == 0)
+    {
+      strcpy(pre, "633  $a");
+      split_subj(mt->value);
+    }
+    else if (strcasecmp(mt->type,  "temporal") == 0)
+    {
+      strcpy(pre, "334  $b");
+      for (i = 0; i < strlen(mt->value); i++)
+      {
+        if (!isdigit(mt->value[i]))
+        {
+          strcpy(pre, "334  $a");
+        }
+      } 
+    }
+  }
+
+  else if (strcasecmp(mt->name, "source") == 0)
+    strcpy(pre, "523  $a");
+
+  else if (strcasecmp(mt->name, "rights") == 0)
+  {
+    if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(pre, "856  $3 rights $u");
+    else
+      strcpy(pre, "518  $a");
+  }
+
+  else if (strcasecmp(mt->name, "identifier") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "urn") == 0)
+      strcpy(pre, "856  $g urn:");
+    else if (strcasecmp(mt->scheme, "isbn") == 0)
+      strcpy(pre, "021  $a");
+    else if (strcasecmp(mt->scheme, "issn") == 0)
+      strcpy(pre, "022  $a");
+    else if (strcasecmp(mt->scheme, "isrc") == 0)
+      strcpy(pre, "024  $a");
+    else if (strcasecmp(mt->scheme, "ismn") == 0)
+      strcpy(pre, "028  $a");
+    else if (strcasecmp(mt->scheme, "isrn") == 0)
+      strcpy(pre, "027  $a");
+  }
+
+  else if (strcasecmp(mt->name, "type") == 0)
+    strcpy(pre, "505  $a");
+
+  else if (strcasecmp(mt->name, "relation") == 0)
+    strcpy(pre, "559  $a");
+
+  else if (strcasecmp(mt->name, "language") == 0)  /* Only if repeated ! */
+  {
+    if (strcasecmp(mt->scheme, "z39.53") == 0)
+    {
+      strcpy(pre, "041  $a");
+      put008(mr->s008, mt->value, F008_LANGUAGE);
+    }
+  }
+
+  else if (strcasecmp(mt->name, "format") == 0)
+  {
+    if ( (!*mt->scheme)
+      || (strcasecmp(mt->scheme, "imt") == 0)
+      || (strcasecmp(mt->scheme, "mime") == 0) )
+      strcpy(mr->fmat, mt->value); 
+  }
+
+  else if (strcasecmp(mt->name, "subject") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "631  $a");
+    else if (strcasecmp(mt->scheme, "udc") == 0)
+      strcpy(pre, "080  $a");
+    else if (strcasecmp(mt->scheme, "lccs") == 0)
+      strcpy(pre, "050  $a");
+    else if (strcasecmp(mt->scheme, "lcsh") == 0)
+      strcpy(pre, "650  $a");
+    else if (strcasecmp(mt->scheme, "ddc") == 0)
+      strcpy(pre, "082  $a");
+    else if (strcasecmp(mt->scheme, "nlm") == 0)
+      strcpy(pre, "060  $a");
+    else if (strcasecmp(mt->scheme, "agr") == 0)
+      strcpy(pre, "662  $a");
+    else if (strcasecmp(mt->scheme, "eudised") == 0)
+      strcpy(pre, "661  $b");
+    else if (strcasecmp(mt->scheme, "dbc") == 0)
+      strcpy(pre, "666  $f");
+    else if (strcasecmp(mt->scheme, "mesh") == 0)
+      strcpy(pre, "690  $a");
+    else if (strcasecmp(mt->scheme, "dk5") == 0)
+    {
+      strcpy(pre, "652  $m");
+      split_dk5(mt->value);
+    }
+  }
+
+  else if (strcasecmp(mt->name, "date") == 0)
+  {
+    if ( (!*mt->type) || ( strcasecmp(mt->type, "current") == 0) )
+    {
+      if ( (strncasecmp(mt->scheme, "ans", 3) == 0) 
+         || (strncasecmp(mt->scheme, "iso", 3) == 0) )
+      {
+        if (find_year(mt->value))
+        {
+          strcpy(mr->year, mt->value);
+          put008(mr->s008, mt->value, F008_DATE1);
+        }
+      }
+    }
+  }
+
+  if (*pre)
+  {
+    strcat(mr->marcline, pre);
+    strcat(mr->marcline, " ");
+    strcat(mr->marcline, mt->value);
+    strcat(mr->marcline, "\n");
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/dc_parse.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/dc_parse.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/dc_parse.c	(revision 10506)
@@ -0,0 +1,216 @@
+/* ------------------------------------------------------------------- */
+/* dc_parse   : parse the meta tag, build a metatag struct             */
+/* Author     : Ole Husby                                              */
+/* Updated    : 1998-09-30                                             */
+/*                                                                     */
+/* Syntax     : #include "d2m.h"                                       */
+/*              dc_parse(char * string)                                */
+/*                                                                     */
+/*              Returns pointer to struct metatag                      */
+/*                                                                     */
+/*              Memory for the struct is allocated in the program!     */
+/*                                                                     */
+/*              String includes a meta tag, after the initial          */
+/*              "<meta " and the ending ">" are stripped away.         */
+/*                                                                     */
+/*              The program accepts the tag if name starts with "dc."  */
+/*              (case insensitive), else NULL is returned.             */
+/*                                                                     */
+/*              The parsing looks for the HTML attributes "name",      */
+/*              "scheme", and "content" only. Other attributes are     */
+/*              ignored.                                               */
+/*                                                                     */
+/*              The DC "type" will be recognized if suffixed           */
+/*              "name" by "dot notation", or contained within          */
+/*              parentheses within "content" (old notation).           */
+/*              (type = subelement)                                    */
+/*                                                                     */
+/*              The DC "scheme" will be recognized if                  */
+/*              present in "scheme" attribute (HTML 4.0), or if        */
+/*              contained within aprentheses in "content" (HTML 2.0)   */
+/*                                                                     */
+/*              Examples:                                              */
+/*                                                                     */
+/*              meta name="DC.Creator.Personalname"                    */
+/*                content="Smith, John"                                */
+/*                                                                     */
+/*              meta name="dc.Creator"                                 */
+/*                content="(type=Personalname) Smith, John">           */
+/*                                                                     */
+/*              meta name="DC.Subject" scheme="LCSH"                   */
+/*                content="Cataloguing"                                */
+/*                                                                     */
+/*              meta name="DC.Subject"                                 */
+/*                content="(scheme=LCSH) Cataloguing"                  */
+/*                                                                     */
+/*              The values of the DC attributes are NOT validated!     */
+/*                                                                     */
+/* ------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include "d2m.h"
+
+
+
+
+struct metatag *dc_parse(char *buf)
+{
+  int more;
+  char *p, *q;
+  struct metatag *mtag;
+  int strict = TRUE;       /* Indicates that DC. prefix is mandatory */
+  char attrname[16];
+
+/* Allocates and initializes metatag struct */
+
+  mtag = malloc(sizeof(*mtag));
+
+  mtag->name   = malloc(256);
+  mtag->type   = malloc(256);
+  mtag->scheme = malloc(256);
+  mtag->value  = malloc(10000);
+
+  *mtag->name   = 0;
+  *mtag->type   = 0;
+  *mtag->scheme = 0;
+  *mtag->value  = 0;
+
+
+
+
+/* Parse attribute name/value pairs: */ 
+ 
+  if (!buf || !*buf) return NULL;
+
+  p = strtok(buf, "\"");
+
+
+
+  while (p)
+  {
+/*  Look for attribute name  */
+
+    *attrname = 0;
+
+    while (*p && ( p[strlen(p) - 1] == ' ' || p[strlen(p) - 1] == '=')) 
+      p[strlen(p) - 1] = '\0'; 
+
+    if (*p && strlen(p) < 10)
+      strcpy(attrname, p);
+
+/*  Look for attribute value */
+
+    p = strtok(NULL, "\"");
+
+    while(*p && p[0] == ' ')
+      p++;
+
+    if (!p || !*p)
+      break;
+
+    if (strncasecmp(attrname, "name", 4) == 0)
+      strcpy(mtag->name, p);
+    else if (strncasecmp(attrname, "scheme", 6) == 0)
+      strcpy(mtag->scheme, p);
+    else if (strncasecmp(attrname, "content", 7) == 0)
+      strcpy(mtag->value, p);
+    p = strtok(NULL, "\"");
+
+    if (p)
+    {
+      while (*p && p[0] == ' ')
+        p++;
+      if (!*p) p = NULL;      
+    }
+  }
+
+
+
+/* Check the name attribute value */
+
+  p = mtag->name;
+  
+  if (!p || !*p)
+    return NULL;
+
+/* Check for leading "dc." and suffixed type */
+
+  if (strncasecmp(p, "dc.", 3) == 0)
+  {
+    p += 3;
+    q = strstr(p, ".");
+    if (q)
+    {
+      strcpy(mtag->type, q + 1);
+      *q = 0;
+    }
+    mtag->name = p;
+  }
+  else
+  {
+    if (strict)
+      return NULL;
+  }
+
+
+/* Check the content attribute value */
+/* Extracting type and scheme        */
+ 
+
+  p = mtag->value;
+ 
+  more = 1;
+     
+  while (more)
+  {
+    if (strncasecmp(p, "(type=", 6) == 0)
+    {
+       p += 6;
+       q = strtok(p, ")");
+       if (!q)
+         return NULL;
+       else
+       {
+          if (!*mtag->type)
+            strcpy(mtag->type, q);
+          q = strtok(NULL, "\0");
+          p = q;
+          while (p && *p && p[0] == ' ') p++;
+
+       }
+    }
+
+    else if (strncasecmp(p, "(scheme=", 8) == 0)
+    {
+       p += 8;
+       q = strtok(p, ")");
+       if (!q)
+         return NULL;
+       else
+       {
+          if (!*mtag->scheme)
+            strcpy(mtag->scheme, q);
+          q = strtok(NULL, "\0");
+          p = q;
+          while (p && *p && p[0] == ' ') p++;
+       }
+    }
+
+    else
+    {
+      mtag->value = p;
+      more = 0; 
+    }
+
+  }
+
+/* Finished */
+
+  if (!*mtag->value)
+    mtag = (struct metatag *) NULL;
+
+  return mtag;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/finMARC.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/finMARC.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/finMARC.c	(revision 10506)
@@ -0,0 +1,275 @@
+/* ------------------------------------------------------------------- */
+/* finMARC    : Convert a metatag struct to FINMARC                    */
+/*                                                                     */
+/* Author     : Ole Husby                                              */
+/* Last update: 1998-09-30                                             */
+/* ------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include "d2m.h" 
+
+
+/* Decides tag for format                                                    */
+
+int parse_format(char *str, char *format)
+{
+   if (strcasecmp(str, "text/html") == 0)
+     strcpy(format, "HTML"); 
+
+   return 1;
+}
+
+
+/* Decides tag for type                                                      */
+
+int parse_type(char *str, char *tag)
+{
+   strcpy(tag, "500");
+
+   if ( (strcasecmp(str, "diss."             ) == 0) 
+     || (strcasecmp(str, "dissertation"      ) == 0) 
+     || (strcasecmp(str, "phd thesis"        ) == 0) 
+     || (strcasecmp(str, "väitöskirja"       ) == 0) 
+     || (strcasecmp(str, "väitösk."          ) == 0) 
+     || (strcasecmp(str, "avhandling"        ) == 0) ) 
+     strcpy(tag, "502");
+
+   else
+   if ( (strcasecmp(str, "masters thesis"    ) == 0) 
+     || (strcasecmp(str, "honours thesis"    ) == 0) 
+     || (strcasecmp(str, "opinnäyte"         ) == 0) 
+     || (strcasecmp(str, "opinn."            ) == 0) ) 
+     strcpy(tag, "509");
+
+   return 1;
+}
+
+
+int finMARC(struct metatag *mt, struct marcrec *mr)
+{
+  char pre[64], type_tag[4];
+
+  *pre = 0;
+
+  if (strcasecmp(mt->name, "title") == 0)
+  {
+    if ( (!*mt->type)
+         | (strcasecmp(mt->type, "main") == 0)
+         | (strcasecmp(mt->type, "long") == 0) )
+    {
+      if (mr->ntitles)
+      {
+        strcat(mr->partitle, "$r ");
+        strcat(mr->partitle, mt->value);
+
+      }
+      else
+      {
+        mr->ntitles++;
+        strcpy(pre, "245  $a");
+      }
+    }
+  }
+
+  else if (strcasecmp(mt->name, "creator") == 0)
+  {
+    if (!*mt->type)
+    {
+      strcpy(pre, "720  $a");
+      split_name(mt->value);
+    }
+    else if ( (strcasecmp(mt->type, "name") == 0) 
+            || (strcasecmp(mt->type, "personal") == 0) )
+    {
+      strcpy(pre, "100  $a");
+      split_name(mt->value);
+    }
+    else if (strcasecmp(mt->type, "corporate") == 0)
+      strcpy(pre, "110  $a");
+  }
+
+  else if (strcasecmp(mt->name, "publisher") == 0)
+  {
+    if (!*mt->type)
+      strcpy(pre, "260  $b");
+    else if (strcasecmp(mt->type, "name") == 0)
+      strcpy(pre, "260  $b");
+  }
+
+  else if (strcasecmp(mt->name, "description") == 0)
+    strcpy(pre, "519  $a");
+
+  else if (strncasecmp(mt->name, "contributor", 11) == 0)     /* Note both pl and sgl allowed */
+  {
+    if (!*mt->type)
+    {
+      strcpy(pre, "720  $a");
+      split_name(mt->value);
+    }
+    else if ( (strcasecmp(mt->type, "name") == 0) 
+            || (strcasecmp(mt->type, "personal") == 0) )
+    {
+      strcpy(pre, "700  $a");
+      split_name(mt->value);
+    }
+    else if (strcasecmp(mt->type, "corporate") == 0)
+      strcpy(pre, "710  $a");
+  }
+
+  else if (strcasecmp(mt->name, "coverage") == 0)
+  {
+    if (!*mt->type)
+      strcpy(pre, "500  $a");
+    else if (strcasecmp(mt->type , "spatial") == 0)
+    {
+      strcpy(pre, "655  $a");
+      split_subj(mt->value);
+    }
+    else if (strcasecmp(mt->type,  "temporal") == 0)
+    {
+      strcpy(pre, "652  $a");
+      split_subj(mt->value);
+    }
+  }
+
+  else if (strcasecmp(mt->name, "source") == 0)
+    strcpy(pre, "501  $a");
+
+  else if (strcasecmp(mt->name, "rights") == 0)
+  {
+    if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(pre, "856  $u");
+  }
+
+  else if (strcasecmp(mt->name, "identifier") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "urn") == 0)
+      strcpy(pre, "856  $g");
+    else if (strcasecmp(mt->scheme, "isbn") == 0)
+      strcpy(pre, "021  $a");
+    else if (strcasecmp(mt->scheme, "issn") == 0)
+      strcpy(pre, "022  $a");
+    else if (strcasecmp(mt->scheme, "nbn") == 0)
+      strcpy(pre, "015  $a");
+    else if (strcasecmp(mt->scheme, "isrc") == 0)
+      strcpy(pre, "015  $a");
+    else if (strcasecmp(mt->scheme, "ismn") == 0)
+      strcpy(pre, "024  $a");
+    else if (strcasecmp(mt->scheme, "isrn") == 0)
+      strcpy(pre, "027  $a");
+  }
+
+  else if (strcasecmp(mt->name, "type") == 0)
+  {
+    parse_type(mt->value, (char *) type_tag);
+    sprintf(pre, "%s  $a", type_tag);
+  }
+
+  else if (strcasecmp(mt->name, "language") == 0)
+  {
+    if (strcasecmp(mt->scheme, "z39.53") == 0)
+    {
+      strcpy(pre, "041  $a");
+      if (strlen(mt->value) == 3)
+        put008(mr->s008, mt->value, F008_LANGUAGE);
+    }
+  }
+
+  else if (strcasecmp(mt->name, "format") == 0)
+  {
+    if ( (!*mt->scheme)
+      || (strcasecmp(mt->scheme, "imt") == 0)
+      || (strcasecmp(mt->scheme, "mime") == 0) )
+      parse_format(mt->value, (char *) mr->fmat);
+  }
+
+  else if (strcasecmp(mt->name, "subject") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "692  $a");
+    else if (strcasecmp(mt->scheme, "udc") == 0)
+      strcpy(pre, "080  $a");
+    else if (strcasecmp(mt->scheme, "lcsh") == 0)
+      strcpy(pre, "650  $a");
+    else if (strcasecmp(mt->scheme, "ddc") == 0)
+      strcpy(pre, "082  $a");
+    else if (strcasecmp(mt->scheme, "mesh") == 0)
+      strcpy(pre, "690  $a");
+    else if (strcasecmp(mt->scheme, "ykl") == 0)
+      strcpy(pre, "098  $a");
+    else if (strcasecmp(mt->scheme, "ysa") == 0)
+    {
+      strcpy(pre, "652  $a");
+      split_subj(mt->value);
+    }
+    else if (strcasecmp(mt->scheme, "fimu") == 0)
+    {
+      strcpy(pre, "653  $a");
+      split_subj(mt->value);
+    }
+    else if (strcasecmp(mt->scheme, "fige") == 0)
+    {
+      strcpy(pre, "655  $a");
+      split_subj(mt->value);
+    }
+    else if (strcasecmp(mt->scheme, "file") == 0)
+    {
+      strcpy(pre, "665  $a");
+      split_subj(mt->value);
+    }
+    else if (strcasecmp(mt->scheme, "fiso") == 0)
+    {
+      strcpy(pre, "670  $a");
+      split_subj(mt->value);
+    }
+    else if (strcasecmp(mt->scheme, "fire") == 0)
+    {
+      strcpy(pre, "680  $a");
+      split_subj(mt->value);
+    }
+    else if (strcasecmp(mt->scheme, "fifo") == 0)
+    {
+      strcpy(pre, "685  $a");
+      split_subj(mt->value);
+    }
+    else if (strcasecmp(mt->scheme, "fiag") == 0)
+    {
+      strcpy(pre, "686  $a");
+      split_subj(mt->value);
+    }
+    else if (strcasecmp(mt->scheme, "fiep") == 0)
+    {
+      strcpy(pre, "660  $a");
+      split_subj(mt->value);
+    }
+  }
+
+  else if (strcasecmp(mt->name, "date") == 0)
+  {
+    if ( (!*mt->type) || ( strcasecmp(mt->type, "current") == 0) )
+    {
+      if ( (strncasecmp(mt->scheme, "ans", 3) == 0) 
+         || (strncasecmp(mt->scheme, "iso", 3) == 0) )
+      {
+        if (find_year(mt->value))
+        {
+          strcpy(mr->year, mt->value);
+          put008(mr->s008, mt->value, F008_DATE1);
+        }
+      }
+    }
+  }
+
+  if (*pre)
+  {
+    strcat(mr->marcline, pre);
+    strcat(mr->marcline, " ");
+    strcat(mr->marcline, mt->value);
+    strcat(mr->marcline, "\n");
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/htget.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/htget.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/htget.c	(revision 10506)
@@ -0,0 +1,545 @@
+/* ------------------------------------------------------------------- */
+/* htget     : Fetch a file using HTTP protocol                        */
+/*                                                                     */
+/* Author    : Ole Husby, BIBSYS                                       */
+/* Updated   : 1998-09-30                                              */
+/*                                                                     */
+/* ------------------------------------------------------------------- */
+/*                                                                     */
+/* htget(url, type, timeout_seconds, outfile, content_type, location)  */
+/*                                                                     */
+/*   Returns: HTTP statuscode, with additional private:                */
+/*                 0 : OK ( = 200)                                     */
+/*               900 : Error, possible timeout                         */
+/*               901 : Syntax error in url                             */
+/*               902 : Unknown host                                    */
+/*               903 : No response from server (no connection)         */
+/*               904 : File is not text/html                           */
+/*               905 : Statusline > 255 bytes                          */
+/*               906 : Statusline < 4 bytes                            */
+/*               907 : Statusline not starting with "HTTP"             */
+/*               908 : Statuscode not numeric                          */
+/*               909 : Size of header > BUFSIZE                        */
+/*               910 : Unable to open output file                      */
+/*               999 : Unspecified TCP/IP error                        */
+/*                                                                     */
+/*   Writes to outfile, depending on type, if statuscode = 0 | 200 :   */
+/*                                                                     */
+/*   type = 0  : Nothing                                               */
+/*   type = 1  : HTTP header                                           */
+/*   type = 2  : HTTP header + entitybody                              */
+/*   type = 3  : HTTP entitybody                                       */
+/*   type = 4  : HTTP entitybody if text/html                          */
+/*   type = 5  : HTTP <HEAD> part of entitybody if text/html           */
+/*   type = 6  : HTTP <HEAD> part of entitybody if text/html           */
+/*               HTTP entitybody if application/marc                   */
+/*                                                                     */
+/* ------------------------------------------------------------------- */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <signal.h>
+
+#define FALSE               0
+#define TRUE                1
+#define BUFSIZE             10000
+#define TYPE_NONE           0     
+#define TYPE_HTTPHEAD       1     
+#define TYPE_HTTPALL        2     
+#define TYPE_HTTPBODY       3     
+#define TYPE_HTMLALL        4     
+#define TYPE_HTMLHEAD       5     
+#define TYPE_MARC           6     
+
+#define TRACE               0
+
+#define AGENT               "BIBSYS_htget v1.1"
+
+char conType[128];
+int htmlonly, marcrecord;
+
+
+
+void thandler(int i)
+{
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* geteoHEAD: Look for </HEAD> or <BODY                                */
+/*                                                                     */
+/* returns: 0 if not found                                             */
+/*          1 if found. Terminates buf immediately after </HEAD> or    */
+/*            immediately before <BODY                                 */
+/* ------------------------------------------------------------------- */
+
+int geteoHEAD(char *buf)
+{
+  char *p;
+  int i;
+
+  p = (char *) cstr(buf, "<BODY");
+  if (p)
+  {
+    i = p - buf;
+
+    buf[i] = '\n';
+    buf[i+1] = '\0';
+    return 1;
+  }
+
+  p = (char *) cstr(buf, "</HEAD>");
+  if (p)
+  {
+    i = p - buf + 7;
+
+    buf[i] = '\n';
+    buf[i+1] = '\0';
+    return 1;
+  }
+
+  return 0;
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* writeRequest: send request to server                                */
+/*                                                                     */
+/* returns: Number of bytes written                                    */
+/* ------------------------------------------------------------------- */
+
+int writeRequest(char *req, int server)
+{
+   if (TRACE)
+      printf("*** send(): %s\n", req);
+
+   return write(server, req, strlen(req));
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* getBody : Read the Entity-body into the file filename               */
+/*                                                                     */
+/* Open the given file for writing, read data from the                 */
+/* socket until a terminating '\0' is found, write to                  */
+/* the file. Returns 0 if ok, positive if an error results             */
+/* in errno being set, or -1 if other error.                           */
+
+/* Single read()'s blocking for more than TIMEOUT_SECONDS will         */
+/* be interrupted. The read() then returns a negative value, and       */
+/* errno will be set appropriately (EINTR).                            */
+/*                                                                     */
+/* Returns   0 if ok                                                   */
+/*         900 if read error                                           */
+/*                                                                     */
+/* ------------------------------------------------------------------- */
+
+int getBody(int server, int timeout, int fd, char *filename)
+{
+   int i, ef;
+   unsigned char *bf, buf[BUFSIZE + 1];
+   int  bytecount;
+   int  found_end;
+   
+   if (TRACE)
+     printf("*** Read entitybody\n");
+
+/* Loop until the endmark is found                                     */
+
+   found_end = FALSE;
+
+
+   while (!found_end) 
+   {
+      alarm (timeout);
+      bytecount = read (server, buf, BUFSIZE);
+      alarm (0);
+
+      if (bytecount < 0) 
+        return 900;                                 /* error in read() */
+
+      else if (bytecount == 0)
+        break;                                 /* server closed socket */
+
+
+      else
+      {
+       if (buf[bytecount-1] == '\0') 
+         {
+            bytecount--;              /* do not write the '\0' to file */
+            found_end = TRUE;                    /* terminate the loop */
+	 }
+
+/*       Write to file                                                 */
+
+         if (bytecount > 0) 
+         {
+            bf = (unsigned char *) buf;
+            bf[bytecount] = '\0';
+            if ( htmlonly )
+            {
+              ef = geteoHEAD(bf);
+              bytecount = strlen(bf);
+            }
+            else
+              ef = 0;
+            write (fd, bf, bytecount);
+            if (ef)
+              break;
+         }
+      }
+   }
+
+   return 0; 
+}
+      
+
+
+/* ------------------------------------------------------------------- */
+/* getHeader : Access file and read HTTP header                        */
+/*                                                                     */
+/* Returns   0 if ok                                                   */
+/*         904 if Content-type not "text/html"                         */
+/*         905 if Statusline > 255 bytes                               */
+/*         906 if Statusline < 4 bytes                                 */
+/*         907 if Statusline not starting with "HTTP"                  */
+/*         908 if Statuscode not numeric                               */
+/*         909 if size of header > BUFSIZE                             */
+/*         HTTP statuscode if <> 200                                   */
+/*                                                                     */
+/* ------------------------------------------------------------------- */
+
+int getHeader(int server, int timeout, int type, int fd, char *reason, char *loc)
+{
+   char buf[BUFSIZE+1], dummy[8];
+   unsigned char *p,  *cp = buf, *d = dummy;
+   int i, rc, statuscode, plf, rlen = 0;
+
+   reason = (char *) NULL;
+   *conType = 0;
+
+   if (TRACE)
+     printf("*** Read statusline\n");
+
+
+/* Read HTTP statusline (until LF or 0, max 256 byte)                 */
+
+   for ( cp = buf, *buf = 0; 1; cp++ )
+   {
+      alarm (timeout);
+      rc = read ( server, cp, 1 );
+      alarm (0);
+
+      if ( rc < 0 )
+	 return 900;
+
+      if ( *cp == '\r')
+      {
+        cp--;
+        continue;
+      }
+
+      rlen++;
+
+      if (TRACE)
+        printf("%c", *cp);
+
+      if ( *cp == 0 || rlen > 255)
+	 return 905;
+      if ( *cp == '\n')
+      {
+         *cp = 0;
+	 break;
+      }
+   }
+
+/*  Write statusline                                                 */
+
+   if ( ( type == TYPE_HTTPHEAD ) || ( type == TYPE_HTTPALL ) )
+   {
+     write(fd, buf, strlen(buf));
+     write(fd, "\n\n", 2);
+   }
+
+   if (TRACE)
+      printf("*** read() : (%d) %s\n", rlen, buf);
+
+
+/* Parse statusline                                                   */
+
+   if (rlen < 4)
+     return 906;
+
+   if (strncmp(buf, "HTTP", 4) != 0)
+     return 907;
+
+   p = strtok(buf, " ");
+   p = strtok(NULL, " ");
+
+   if (!*p)
+     statuscode = 200;
+   else
+   {
+     for (i = 0; i < strlen(p); i++)
+       if (!isdigit(p[i]))
+         return 908;
+   }
+   statuscode = atoi(p);
+
+   p = strtok(NULL, "\0");
+   if (p)
+     reason = p;
+
+   if (statuscode == 200)
+     statuscode = 0;
+
+   if (!type)
+     return statuscode;
+
+
+/* Read HTTP response header (until 0 or empty line, max BUFSIZE bytes  */
+
+   rlen = 0;
+   plf = FALSE;
+
+   if (TRACE)
+     printf("*** Read responseheader\n");
+
+   for ( cp = buf, *buf = 0; 1; cp++ )
+   {
+      alarm (timeout);
+      rc = read ( server, cp, 1 ); 
+      alarm (0);
+
+      if ( rc < 0 )
+	 return 900;
+
+      if ( *cp == '\r')
+      {
+        cp--;
+        continue;
+      }
+
+      rlen++;
+
+      if ( *cp == 0 || rlen > BUFSIZE)
+	 return 909;
+      else if ( *cp == '\n')
+      {
+         if (plf)
+         {
+           *cp = 0;
+	   break;
+         }
+         else
+           plf = TRUE;
+      }
+      else
+        plf = FALSE;
+   }
+
+/*  Write rest of HTTP header                                         */
+
+   if ( ( type == TYPE_HTTPHEAD ) || ( type == TYPE_HTTPALL ) )
+   {
+     write(fd, buf, strlen(buf));
+     write(fd, "\n", 1);
+   }
+
+   if (TRACE)
+      printf("*** read() : (%d) %s\n", rlen, buf);
+
+
+/* Parse header for Content-Type and Loaction                         */
+
+   rc = 904;
+
+   p = strtok(buf, "\n");
+   while (p)
+   {
+     if (strncasecmp(p, "Content-Type:", 13) == 0)
+     {
+       p += 13;
+       while (p[0] == ' ')
+         p++;
+       strcpy(conType, p);
+
+       if (strncasecmp(p, "text/html", 7) == 0)
+       {
+         if ( ( type == TYPE_HTMLHEAD) || (type == TYPE_MARC ) )
+           htmlonly = 1;
+         rc = 0;
+       }
+
+       else if (strncasecmp(p, "application/marc", 16) == 0)
+       {
+         if ( type == TYPE_MARC )
+         {
+           marcrecord = 1; 
+           rc = 0;
+         }
+       }
+     }
+
+     else if (strncasecmp(p, "Location:", 9) == 0)
+     {
+       p += 9;
+       while (p[0] == ' ')
+         p++;
+       strcpy(loc, p);
+     }
+     p = strtok(NULL, "\n");
+   }
+
+
+/* All OK. Socket is positioned at start of HTTP Entity-Body          */
+
+   if (rc)
+     return rc;
+   else
+     return statuscode;
+}
+
+
+
+
+
+/* ------------------------------------------------------------------- */
+/* htget  : Fetch a URL                                                */
+/* ------------------------------------------------------------------- */
+
+int htget(char *iurl, int type, int timeout, char *outfile, char *h_contype, char *h_location)
+{
+   int i, rc, fd, soc, port;
+   struct sockaddr_in addr; 
+   struct hostent *hp, *gethostbyname();
+   char	uurl[1024], *url = uurl, hostname[256], cport[64], req[1024];
+   char *h, *p, *q, *r;
+   char tfile[256], blank[2];
+
+   *blank = *h_contype = *h_location = 0; 
+   htmlonly = marcrecord = 0;
+
+   strcpy(tfile, "/tmp/geturl.tmp");
+   if (!*outfile)
+     outfile = (char *) tfile;
+
+   if (!*iurl || ( strlen(iurl) > 1023 ) )
+     return 901;
+
+   strcpy(url, iurl);
+
+/* Parse and validate URL                                             */
+
+   if (strncmp(url, "http://", 7) != 0)
+     return 901;
+
+   url += 7;
+
+   q = strtok(url, "/");
+   if (!q)
+     return 901;
+
+   r = strtok(NULL, "\0");
+   if (!r)
+     r = (char *) blank;
+
+   h = strtok(q, ":");
+   if (!*h)
+     return 901;
+
+   strcpy(hostname, h);
+
+   p = strtok(NULL, "\0");
+
+   if (!p || !*p)
+     port = 80;
+   else
+   {
+     for (i = 0; i < strlen(p); i++)
+       if (!isdigit(p[i]))
+         return 901;
+     port = atoi(p);
+   }
+   sprintf(req, "GET /%s HTTP/1.0\r\nUser_Agent: %s\n\n", r, AGENT);
+  
+
+/* Establish handler for the alarm-signal                              */
+
+   signal (SIGALRM, thandler);
+
+
+/* Get IP address                                                      */
+ 
+   hp = gethostbyname(hostname);
+   if (!hp)
+     return 902;
+
+/* Get socket and connect                                              */
+ 
+   soc = socket(AF_INET, SOCK_STREAM, 0);
+ 
+   addr.sin_family = AF_INET;
+   
+   memcpy( &addr.sin_addr.s_addr, hp->h_addr, (size_t) hp->h_length );
+
+   addr.sin_port = htons(port);
+   if (connect(soc, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) < 0)
+      return 903;
+
+
+/* Open the destination file                                           */
+ 
+   if (type)
+   {
+     fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC , 0666);
+     if (fd < 0)  
+     {
+        close(soc);
+        return 910;
+     }
+   }
+
+
+
+
+/* Write HTTP-request                                               */
+ 
+   if (!writeRequest(req, soc))
+   {
+     close(soc);
+     if (type)
+       close(fd);
+     return 999;
+   }
+
+
+/* Read header part of response                                     */
+
+   rc = getHeader(soc, timeout, type, fd, r, h_location);
+   
+   if ( ( rc == 904 ) && (type < 4 ) )
+     rc = 0;
+
+   if ( ( rc == 0 ) && ( type > 1 ) )
+     rc = getBody(soc, timeout, fd, outfile);
+ 
+   close(soc);
+   if (type)
+     close(fd);
+   strcpy(h_contype, conType);
+
+   return rc;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/isMARC.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/isMARC.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/isMARC.c	(revision 10506)
@@ -0,0 +1,333 @@
+/* ------------------------------------------------------------------- */
+/* isMARC     : Convert a metatag struct to ISMARC                     */
+/*              (i.e. UKMARC as used in the National and University    */
+/*              Library of Island).                                    */
+/*                                                                     */
+/* Specs      : http://www.bibsys.no/meta/d2m/iscross.txt              */
+/*                                                                     */
+/* Author     : Ole Husby                                              */
+/* Last update: 1998-09-30                                             */
+/* ------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include "d2m.h" 
+
+
+
+
+/* ------------------------------------------------------------------- */
+/* Splits Icelandig name without a comma                               */
+/* ------------------------------------------------------------------- */
+
+int split_ice2(char *str)
+{
+  char *q, *temp, *suba, *subi, *subb;
+
+  if (!strstr(str, " "))
+    return 1;
+
+  suba = (char *) malloc(strlen(str) + 50);
+  subi = (char *) malloc(strlen(str) + 50);
+  subb = (char *) malloc(strlen(str) + 50);
+  temp = (char *) malloc(strlen(str) + 50);
+
+  *suba = *subi = *subb = *temp = 0;
+
+  q = strtok(str, " ");
+  while (q)
+  {
+    while ( ( q[0] == ' ' ) && ( strlen(q) ) )
+      q++;
+
+    while( ( q[strlen(q) - 1] == ' ' ) && ( strlen(q) ) )
+      q[strlen(q) - 1] = '\0';
+
+    if (*q)
+    {
+      if (!*suba)
+        strcpy(suba, q);
+      else
+      {
+        if (*temp)
+        {
+          if (*subi)
+            strcat(subi, " ");
+          strcat(subi, temp);
+        }
+        strcpy(temp, q);
+      }
+    }
+    q = strtok(NULL, " ");
+  }
+
+  *str = 0;
+
+  if (*temp)
+  {
+    if (*subi)
+      strcpy(subb, temp);
+    else
+      strcpy(subi, temp);
+  }
+
+  if (*suba)
+  {
+    strcpy(str, suba);
+    if (*subi)
+    {
+      strcat(str, " $i ");
+      strcat(str, subi); 
+    }
+    if (*subb)
+    {
+      strcat(str, " $b ");
+      strcat(str, subb); 
+    }
+  }
+
+  free(suba);
+  free(subi);
+  free(subb);
+  free(temp);
+
+  return 40;
+}
+
+
+
+
+
+/* ------------------------------------------------------------------- */
+/* Splits Icelandig name                                               */
+/* ------------------------------------------------------------------- */
+
+int split_icename(char *str, int i2)
+{
+  char *p, *q, subtag[5];
+
+  if (!strstr(str, ","))
+  {
+    if (i2)
+      return split_ice2(str);
+    else
+      return 1;
+  }
+
+  p = (char *) malloc(strlen(str) + 50);
+  *p = 0;
+  *subtag = 0;
+
+  q = strtok(str, ",");
+  if (q)
+  {
+    strcpy(p, q);
+    q = strtok(NULL, "\0");
+    if (q)
+    {
+      while ( ( q[0] == ' ' ) && ( strlen(q) ) )
+        q++;
+      strcat(p, " $h ");
+      strcat(p, q);
+    }
+    strcpy(str, p);
+  }
+
+  free(p);
+
+  return 10;
+}
+
+
+int isMARC(struct metatag *mt, struct marcrec *mr)
+{
+  char pre[64], type_tag[4], creator_tag[4], title_tag[6];
+  int i, ind, ice2;
+
+  *pre = 0;
+
+  if (strcasecmp(mt->name, "title") == 0)
+  {
+    if ( (!*mt->type)
+         | (strcasecmp(mt->type, "main") == 0)
+         | (strcasecmp(mt->type, "long") == 0) )
+    {
+      if (mr->ntitles)
+        strcpy(title_tag, "24630");
+      else
+        strcpy(title_tag, "24510");
+
+      mr->ntitles++;
+
+      sprintf(pre, "%s$a", title_tag);
+    }
+  }
+
+  else if (strcasecmp(mt->name, "creator") == 0)
+  {
+    if ( strcasecmp(mt->type, "personal") == 0) 
+    {
+      if (!mr->ncreators)
+        strcpy(creator_tag, "100");
+      else 
+        strcpy(creator_tag, "700");
+
+      ice2 = 1; 
+      ind = split_icename(mt->value, ice2);
+      sprintf(pre, "%s%2d$a", creator_tag, ind);
+    }
+    else if (strcasecmp(mt->type, "corporate") == 0)
+    {
+      if (!mr->ncreators)
+        strcpy(creator_tag, "110");
+      else 
+        strcpy(creator_tag, "710");
+      sprintf(pre, "%s20$a", creator_tag);
+    }
+    else
+    {
+      ice2 = 0;
+      strcpy(pre, "720  $a");
+      ind = split_icename(mt->value, ice2);
+    }
+    mr->ncreators++;
+  }
+
+  else if (strncasecmp(mt->name, "contributor", 11) == 0)
+  {
+    if ( strcasecmp(mt->type, "personal") == 0) 
+    {
+      ice2 = 1; 
+      ind = split_icename(mt->value, ice2);
+      sprintf(pre, "700%2d$a", ind);
+    }
+    else if (strcasecmp(mt->type, "corporate") == 0)
+    {
+      strcpy(pre, "71020$a");
+    }
+    else
+    {
+      ice2 = 0;
+      strcpy(pre, "720  $a");
+      ind = split_icename(mt->value, ice2);
+    }
+    mr->ncreators++;
+  }
+
+
+  else if (strcasecmp(mt->name, "publisher") == 0)
+    strcpy(pre, "260  $b");
+
+  else if (strcasecmp(mt->name, "description") == 0)
+    strcpy(pre, "513  $a");
+
+  else if (strcasecmp(mt->name, "coverage") == 0)
+  {
+    if (strcasecmp(mt->type , "spatial") == 0)
+    {
+      strcpy(pre, "651  $a");
+      split_subj(mt->value);
+    }
+    else
+      strcpy(pre, "500  $a");
+  }
+
+  else if (strcasecmp(mt->name, "source") == 0)
+    strcpy(pre, "787  $a");
+
+  else if (strcasecmp(mt->name, "rights") == 0)
+  {
+    if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(pre, "856  $3 rights $u");
+    else
+      strcpy(pre, "500  $a");
+  }
+
+  else if (strcasecmp(mt->name, "identifier") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "urn") == 0)
+      strcpy(pre, "8567 $u urn:");
+    else if (strcasecmp(mt->scheme, "nbn") == 0)
+      strcpy(pre, "015  $a");
+    else if (strcasecmp(mt->scheme, "isbn") == 0)
+      strcpy(pre, "021  $a");
+    else if (strcasecmp(mt->scheme, "issn") == 0)
+      strcpy(pre, "022  $a");
+    else if (strcasecmp(mt->scheme, "isrc") == 0)
+      strcpy(pre, "024  $a");
+    else if (strcasecmp(mt->scheme, "ismn") == 0)
+      strcpy(pre, "025  $a");
+    else if (strcasecmp(mt->scheme, "isrn") == 0)
+      strcpy(pre, "027  $a");
+  }
+
+  else if (strcasecmp(mt->name, "type") == 0)
+    strcpy(pre, "655  $a");
+
+  else if (strcasecmp(mt->name, "relation") == 0)
+    strcpy(pre, "787  $a");
+
+  else if (strcasecmp(mt->name, "language") == 0)
+  {
+    if (strcasecmp(mt->scheme, "z39.53") == 0)
+    {
+      strcpy(pre, "04109$a");
+      if (strlen(mt->value) == 3) 
+        put008(mr->s008, mt->value, F008_LANGUAGE);
+    }
+    else if (strcasecmp(mt->scheme, "usmarc") == 0)
+      strcpy(pre, "04109$a");
+    else
+      strcpy(pre, "546  $a");
+  }
+
+  else if (strcasecmp(mt->name, "format") == 0)
+    strcpy(mr->fmat, mt->value); 
+
+  else if (strcasecmp(mt->name, "subject") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "680  $a");
+    else if (strcasecmp(mt->scheme, "udc") == 0)
+      strcpy(pre, "080  $a");
+    else if (strcasecmp(mt->scheme, "lcc") == 0)
+      strcpy(pre, "050  $a");
+    else if (strcasecmp(mt->scheme, "lcsh") == 0)
+      strcpy(pre, "650  $a");
+    else if (strcasecmp(mt->scheme, "ddc") == 0)
+      strcpy(pre, "082  $a");
+    else if (strcasecmp(mt->scheme, "nlm") == 0)
+      strcpy(pre, "060  $a");
+    else if (strcasecmp(mt->scheme, "landslyk") == 0)
+      strcpy(pre, "659  $a");
+    else if (strcasecmp(mt->scheme, "kerfefn") == 0)
+      strcpy(pre, "659  $a");
+    else if (strcasecmp(mt->scheme, "dbc") == 0)
+      strcpy(pre, "65002$a");
+    else if (strcasecmp(mt->scheme, "mesh") == 0)
+      strcpy(pre, "690  $a");
+    else
+      strcpy(pre, "65004$a");
+  }
+
+  else if (strcasecmp(mt->name, "date") == 0)
+  {
+    if (find_year(mt->value))
+    {
+      strcpy(mr->year, mt->value);
+      put008(mr->s008, mt->value, F008_DATE1);
+    }
+  }
+
+  if (*pre)
+  {
+    strcat(mr->marcline, pre);
+    strcat(mr->marcline, " ");
+    strcat(mr->marcline, mt->value);
+    strcat(mr->marcline, "\n");
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/marc2line.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/marc2line.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/marc2line.c	(revision 10506)
@@ -0,0 +1,243 @@
+/* ------------------------------------------------------------------- */
+/* marc2line : Reads an ISO 2709 MARC record, converts to MARC         */
+/*             "Line format"                                           */
+/*                                                                     */
+/* author    : Ole Husby, BIBSYS                                       */
+/* updated   : 1998-09-30                                              */
+/* ------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#define DIRL                                   3600
+
+#define LINEL                                  72 
+#define SUBFIELD_CODE                          '\x1f'
+#define SUBFIELD_STR                           "\x1f" 
+#define FIELD_TERMINATOR                       '\x1e'
+#define RECORD_TERMINATOR                      '\x1d'
+
+#define BIBSYS_TYPE                            0
+#define NORMARC_TYPE                           1
+
+union LDR   {
+   char ldr_string[24+1];
+   struct {
+      char record_length[5],
+      record_status,
+      record_type,
+      bibliographic_level,
+      unused1[2],
+      indicator_count,
+      subfield_code_count,
+      base_adress[5],
+      unused2[3],
+      entry1,
+      entry2,
+      entry3,
+      entry4;
+   } ltab;
+} ldr; 
+
+static char out_record[10240];
+static int out_type;
+
+
+
+/* ------------------------------------------------------------------- */
+/* One subfield string is split into output lines                      */
+/* ------------------------------------------------------------------- */
+
+static void out_subfield(data, prefix, slen)
+char *data, *prefix;
+int slen;
+
+{
+   char lineprefix[7], subprefix[4], *spre;
+   int i, more, len, max;
+
+   if (out_type == BIBSYS_TYPE)
+      strcpy(lineprefix, prefix);
+   else
+   {
+      if (prefix[0] == ' ') strcpy(lineprefix, " ");
+      else                  strcpy(lineprefix, "*");
+      strcat(lineprefix, prefix);
+   }
+
+   max = LINEL;
+
+   if (slen)
+   {
+      spre = (char *) subprefix;
+      strcpy(spre, "$");                       /* Construct subfield    */
+      strncat(spre, data, 1);                  /* prefix                */
+      if (out_type == BIBSYS_TYPE) 
+	 strcat(spre, " ");
+      data++;
+      max = LINEL - 2; 
+      if (out_type == BIBSYS_TYPE) 
+	 max--;
+   }
+   else spre = NULL;  
+
+   more = 1;
+
+   while (more)
+   {
+      if (slen)
+         while (data[0] == ' ') data++;    /* skip leading blanks    */
+
+      strcat(out_record, lineprefix);      /* Start with prefix      */
+      strcpy(lineprefix, "     ");
+      if (out_type == NORMARC_TYPE) 
+	 strcat(lineprefix, " ");
+
+      len = strlen(data);
+      if (len > max)                       /* Must fit into one line */
+      {
+	 len = max;
+	 for (i = max; i > max - 15; i--)
+	 {
+	    if (data[i] == ' ')
+	    {
+	       len = i;
+	       break;
+	    }
+	 }
+      }
+      else more = 0;
+
+      if (spre)
+      {
+	 strcat(out_record, spre);         /* subfield pref needed  */
+	 spre = NULL;                      /* only first line       */
+	 max = LINEL;
+      }
+
+      strncat(out_record, data, len);      /* append data           */
+      if (more) data += len;
+      strcat(out_record, "\n");
+   }
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* One MARC field is split into subfields and given to output          */
+/* ------------------------------------------------------------------- */
+
+static int out_field(data, ftag, find)
+char *data, *ftag, *find;
+
+{
+   char prefix[5];
+   char subfield[5120], *sub = subfield;
+   int subcode = 0;
+
+   strcpy(prefix, ftag);
+
+   if (!find)                                 /* output entire field   */ 
+   {
+      out_subfield(data, prefix, subcode);
+      return 1;
+   }
+
+   strcat(prefix, find);
+
+   if (data[0] != SUBFIELD_CODE) return 0;    /* requires subf code in */
+   data++;                                    /*   first byte          */
+
+   sub = strtok(data, SUBFIELD_STR);          /* find first subfield   */
+   if (!sub) return 0;
+
+   subcode = 1;
+   out_subfield(sub, prefix, subcode);        /* output subfield       */
+   strcpy(prefix, "     ");                   /* reset prefix          */
+
+   while (sub = strtok(NULL, SUBFIELD_STR))   /* find and output rest  */
+      out_subfield(sub, prefix, subcode);     /* of the subfields      */
+
+   return 1;
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* Main program                                                        */
+/* ------------------------------------------------------------------- */
+
+char *marc2line(record, type)          
+char *record, *type;
+{
+   char buffer[10240], tag[4], indicators[3];
+   char *cp, *fld, *buf = buffer, *cq;
+   char directory[DIRL+1], *dir = directory, *ind;
+   char sBase[6], fLen[5], fStart[6];
+   int           dlen, base, x = 0, more = 1, len, start;
+
+   if (!record || !*record)
+     return (char *) NULL;
+
+   strcpy(buf, record);
+   *out_record = 0;                                 /* reset out area     */
+
+   if (strcmp(type, "bibsys") == 0) out_type = BIBSYS_TYPE;
+   else out_type = NORMARC_TYPE;
+
+   strncpy(ldr.ldr_string, buf, 24);                 /* get leader         */
+   ldr.ldr_string[24] = '\0';
+   buf += 24;
+  
+   strncpy(sBase, ldr.ltab.base_adress, 5);
+   sBase[5] = '\0';
+   base = atoi(sBase);
+
+   dlen = base - 24;                                 /* get directory      */
+   strncpy(dir, buf, dlen);
+   dir[dlen] = '\0';
+   buf += dlen;
+
+   cp = dir;
+
+   while (more)                                      /* loop until EOdir   */ 
+   {
+      if (*cp == FIELD_TERMINATOR)  break;
+      if (strlen(cp) < 13) return (char *) NULL;
+
+      strncpy(tag, cp, 3);                           /* get tag            */
+      tag[3] = '\0';
+      cp +=3;
+
+      strncpy(fLen, cp, 4);                         /* get length          */
+      fLen[4] = '\0';
+      len = atoi(fLen) -1;                          /* discard field term. */
+      cp += 4;
+
+      strncpy(fStart, cp, 5);                       /* get start of field  */
+      fStart[5] = '\0';
+      start = atoi(fStart);
+      cp += 5;
+
+      fld = buf + start;                            /* get field           */ 
+      fld[len] = '\0';
+      
+      if (strncmp(tag, "00", 2) != 0)               /* get indicators      */
+      {
+	 indicators[0] = '\0';
+	 strncat(indicators, fld, 2);
+	 ind = (char *) indicators;
+	 fld += 2;
+      }
+      else ind = NULL;
+
+      if (!out_field(fld, tag, ind))                /* output field         */
+	 return (char *) NULL;
+
+   }
+
+   return (char *) out_record;
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/norMARC.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/norMARC.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/norMARC.c	(revision 10506)
@@ -0,0 +1,194 @@
+/* ------------------------------------------------------------------- */
+/* norMARC   : Convert a metatag struct to NORMARC                     */
+/*                                                                     */
+/* 1998-09-30: Ole Husby                                               */
+/* ------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include "d2m.h" 
+
+
+
+int norMARC(struct metatag *mt, struct marcrec *mr)
+{
+  char pre[64], creator_tag[4], title_tag[4];
+
+  *pre = 0;
+
+  if (strcasecmp(mt->name, "title") == 0)
+  {
+    if ( (!*mt->type)
+         | (strcasecmp(mt->type, "main") == 0)
+         | (strcasecmp(mt->type, "long") == 0) )
+    {
+      if (mr->ntitles)
+        strcpy(title_tag, "246");
+      else
+        strcpy(title_tag, "245");
+
+      mr->ntitles++;
+
+      sprintf(pre, "%s  $a", title_tag);
+    }
+    else if (strcasecmp(mt->type, "subtitle") == 0)
+    {
+      if (mr->ntitles < 2)
+        strcpy(mr->subtitle, mt->value);
+    }
+  }
+
+  else if (strcasecmp(mt->name, "creator") == 0)
+  {
+    if ( (!*mt->type) || (strcasecmp(mt->type, "name") == 0) 
+      || (strcasecmp(mt->type, "personalname") == 0) )
+    {
+      if (mr->ncreators)
+        strcpy(creator_tag, "700");
+      else
+        strcpy(creator_tag, "100");
+
+      mr->ncreators++;
+
+      sprintf(pre, "%s  $a", creator_tag);
+    }
+
+    else if (strcasecmp(mt->type, "corporatename") == 0) 
+    {
+      if (mr->ncreators)
+        strcpy(creator_tag, "710");
+      else
+        strcpy(creator_tag, "110");
+
+      mr->ncreators++;
+
+      sprintf(pre, "%s  $a", creator_tag);
+    }
+  }
+
+  else if (strcasecmp(mt->name, "publisher") == 0)
+  {
+    if (!*mt->type)
+      strcpy(pre, "260  $b");
+    else if (strcasecmp(mt->type, "name") == 0)
+      strcpy(pre, "260  $b");
+  }
+
+  else if (strcasecmp(mt->name, "contributor") == 0)
+  {
+    if ( (!*mt->type)|| (strcasecmp(mt->type, "name") == 0)
+      || (strcasecmp(mt->type, "personalname") == 0) )
+      strcpy(pre, "700  $a");
+    else if (strcasecmp(mt->type, "corporatename") == 0)
+      strcpy(pre, "710  $a");
+  }
+
+  else if (strcasecmp(mt->name, "coverage") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "500  $a");
+    else if (strcasecmp(mt->scheme, "freetext") == 0)
+      strcpy(pre, "500  $a");
+  }
+
+  else if (strcasecmp(mt->name, "source") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "500  $a Kilde:");
+    else if (strcasecmp(mt->scheme, "freetext") == 0)
+      strcpy(pre, "500  $a Kilde:");
+    else if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(pre, "500  $a Kilde: URL:");
+    else if (strcasecmp(mt->scheme, "urn") == 0)
+      strcpy(pre, "500  $a Kilde: URN:");
+    else if (strcasecmp(mt->scheme, "isbn") == 0)
+      strcpy(pre, "500  $a Kilde: ISBN:");
+    else if (strcasecmp(mt->scheme, "issn") == 0)
+      strcpy(pre, "500  $a Kilde: ISSN:");
+  }
+
+  else if (strcasecmp(mt->name, "rights") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "500  $a Copyright:");
+    else if (strcasecmp(mt->scheme, "freetext") == 0)
+      strcpy(pre, "500  $a Copyright:");
+  }
+
+  else if (strcasecmp(mt->name, "identifier") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "urn") == 0)
+      strcpy(pre, "856  $u urn:");
+    else if (strcasecmp(mt->scheme, "isbn") == 0)
+      strcpy(pre, "020  $a");
+    else if (strcasecmp(mt->scheme, "issn") == 0)
+      strcpy(pre, "022  $a");
+  }
+
+  else if (strcasecmp(mt->name, "language") == 0)
+  {
+    if (strcasecmp(mt->scheme, "z39.53") == 0)
+    {
+      if (strlen(mt->value) == 3)
+        put008(mr->s008, mt->value, F008_LANGUAGE);
+    }
+  }
+
+  else if (strcasecmp(mt->name, "format") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(mr->fmat, mt->value);
+    else if (strcasecmp(mt->scheme, "imt") == 0)
+      strcpy(mr->fmat, mt->value);
+    else if (strcasecmp(mt->scheme, "mime") == 0)
+      strcpy(mr->fmat, mt->value);
+  }
+
+  else if (strcasecmp(mt->name, "subject") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "691  $a");
+    else if (strcasecmp(mt->scheme, "internal") == 0)
+      strcpy(pre, "691  $a");
+    else if (strcasecmp(mt->scheme, "udc") == 0)
+      strcpy(pre, "080  $a");
+    else if (strcasecmp(mt->scheme, "lcsh") == 0)
+      strcpy(pre, "650  $a");
+    else if (strcasecmp(mt->scheme, "ddc") == 0)
+      strcpy(pre, "082  $a");
+    else if (strcasecmp(mt->scheme, "mesh") == 0)
+      strcpy(pre, "660  $a");
+    else if (strcasecmp(mt->scheme, "humord") == 0)
+      strcpy(pre, "698  $a");
+    else if (strcasecmp(mt->scheme, "ntub") == 0)
+      strcpy(pre, "699  $a");
+  }
+
+  else if (strcasecmp(mt->name, "date") == 0)
+  {
+    if ( (strncasecmp(mt->scheme, "ans", 3) == 0) ||
+         (strncasecmp(mt->scheme, "iso", 3) == 0) )
+    {
+      if ( (!*mt->type) || ( strcasecmp(mt->type, "current") == 0) )
+      {
+        if (find_year(mt->value))
+        {
+          strcpy(mr->year, mt->value);
+          put008(mr->s008, mt->value, F008_DATE1);
+        }
+      }
+    }
+  }
+
+  if (*pre)
+  {
+    strcat(mr->marcline, pre);
+    strcat(mr->marcline, " ");
+    strcat(mr->marcline, mt->value);
+    strcat(mr->marcline, "\n");
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/strcasecmp.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/strcasecmp.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/strcasecmp.c	(revision 10506)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific written prior permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcasecmp.c	5.5 (Berkeley) 11/24/87";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char charmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+int
+strcasecmp(s1, s2)
+    char *s1, *s2;
+{
+    register unsigned char u1, u2;
+
+    for (;;) {
+	u1 = (unsigned char) *s1++;
+	u2 = (unsigned char) *s2++;
+	if (charmap[u1] != charmap[u2]) {
+	    return charmap[u1] - charmap[u2];
+	}
+	if (u1 == '\0') {
+	    return 0;
+	}
+    }
+}
+int
+strncasecmp(s1, s2, n)
+    char *s1, *s2;
+    int n;
+{
+    register unsigned char u1, u2;
+    int i;
+    for (i=0;i<n;i++) {
+	u1 = (unsigned char) *s1++;
+	u2 = (unsigned char) *s2++;
+	if (charmap[u1] != charmap[u2]) {
+	    return charmap[u1] - charmap[u2];
+	}
+	if (u1 == '\0') {
+	    return 0;
+	}
+    }
+    return 0;
+}
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/sweMARC.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/sweMARC.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/sweMARC.c	(revision 10506)
@@ -0,0 +1,259 @@
+/* ------------------------------------------------------------------- */
+/* sweMARC    : Convert a metatag struct to LIBRISMARC                 */
+/*                                                                     */
+/* Author     : Ole Husby                                              */
+/* Last update: 1998-09-30                                             */
+/* ------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "d2m.h" 
+
+
+
+
+/* ---------------------------------------------------------------------- */
+/* Decides on first indicator for personal name                           */
+/*                                                                        */
+/* f : no comma                                                           */
+/* e : comma, with only one word preceeding                               */
+/* s : comma, with more than one word preceeding (delimiter blank or "-") */
+/* ---------------------------------------------------------------------- */
+
+int personal_indicator(char *pname)
+{
+  char *comma, *blank, *hyphen;
+
+  comma = strstr(pname, ",");
+  if (!comma)
+    return (int) 'f';
+
+  blank = strstr(pname, " ");
+  hyphen = strstr(pname, "-");
+
+  if ( (blank && blank < comma) || (hyphen && hyphen < comma) )
+    return (int) 's';
+  else
+    return (int) 'e';
+}
+
+
+
+/* ---------------------------------------------------------------------- */
+/* Decides tag for type                                                   */
+/* ---------------------------------------------------------------------- */
+
+int parse_swetype(char *str, char *tag)
+{
+   if ( (strcasecmp(str, "diss."             ) == 0) 
+     || (strcasecmp(str, "dissertation"      ) == 0) 
+     || (strcasecmp(str, "thesis"            ) == 0) 
+     || (strcasecmp(str, "domkap.avh."       ) == 0) 
+     || (strcasecmp(str, "hab.-schr"         ) == 0) 
+     || (strcasecmp(str, "prästmösteavh."    ) == 0)
+     || (strcasecmp(str, "avhandling"        ) == 0) ) 
+     strcpy(tag, "502");
+   else
+     strcpy(tag, "500");
+
+   return 1;
+}
+
+
+/* ---------------------------------------------------------------------- */
+/* sweMARC()                                                              */
+/* ---------------------------------------------------------------------- */
+
+int sweMARC(struct metatag *mt, struct marcrec *mr)
+{
+  char pre[64], creator_tag[4], type_tag[4];
+  int ind1;
+
+  *pre = 0;
+
+  if (strcasecmp(mt->name, "title") == 0)
+  {
+    if ( (!*mt->type)
+         | (strcasecmp(mt->type, "main") == 0)
+         | (strcasecmp(mt->type, "long") == 0) )
+    {
+      if (mr->ntitles)
+        strcpy(pre, "740  $a");
+      else
+      {
+        mr->ntitles++;
+        strcpy(pre, "245  $a");
+      }
+    }
+  }
+
+
+  else if (strcasecmp(mt->name, "creator") == 0)
+  {
+    if (!*mt->type)
+      strcpy(pre, "720  $a");
+    else if (strcasecmp(mt->type, "personal") == 0) 
+    {
+      ind1 = personal_indicator(mt->value);
+      if (mr->ncreators)
+        strcpy(creator_tag, "700");
+      else
+      {
+        strcpy(creator_tag, "100");
+        mr-> ncreators++;
+      }
+      sprintf(pre, "%s%c $a", creator_tag, ind1);
+    }
+    else if (strcasecmp(mt->type, "corporate") == 0)
+    {
+      if (mr->ncreators)
+        strcpy(creator_tag, "710");
+      else
+      {
+        strcpy(creator_tag, "110");
+        mr-> ncreators++;
+      }
+      sprintf(pre, "%sc $a", creator_tag);
+    }
+  }
+
+
+  else if (strncasecmp(mt->name, "contributor", 11) == 0)     /* Note both pl and sgl allowed */
+  {
+    if (!*mt->type)
+      strcpy(pre, "720  $a");
+    else if (strcasecmp(mt->type, "personal") == 0) 
+    {
+      ind1 = personal_indicator(mt->value);
+      sprintf(pre, "700%cm$a", ind1);
+    }
+    else if (strcasecmp(mt->type, "corporate") == 0)
+      strcpy(pre, "710  $a");
+  }
+
+
+  else if (strcasecmp(mt->name, "publisher") == 0)          /* Note both should go to same tag! */
+  {
+    if (!*mt->type)
+      strcpy(pre, "260  $b");
+    else if (strcasecmp(mt->type, "email") == 0)
+      strcpy(pre, "260  $d");
+  }
+
+
+
+  else if (strcasecmp(mt->name, "description") == 0)
+    strcpy(pre, "520  $a");
+
+
+
+  else if (strcasecmp(mt->name, "coverage") == 0)
+  {
+    if (!*mt->type)
+      strcpy(pre, "500  $a");
+    else if (strcasecmp(mt->type , "spatial") == 0)
+      strcpy(pre, "651  $a");
+    else if (strcasecmp(mt->type,  "temporal") == 0)
+      strcpy(pre, "650  $a");
+  }
+
+  else if (strcasecmp(mt->name, "source") == 0)
+    strcpy(pre, "786  $a");
+
+
+  else if (strcasecmp(mt->name, "relation") == 0)
+    strcpy(pre, "787  $a");
+
+
+  else if (strcasecmp(mt->name, "rights") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "500  $a");
+    if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(pre, "856  $u");
+    if (strcasecmp(mt->scheme, "urn") == 0)
+      strcpy(pre, "856  $g");
+  }
+
+  else if (strcasecmp(mt->name, "identifier") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "urn") == 0)
+      strcpy(pre, "856  $g");
+    else if (strcasecmp(mt->scheme, "ismn") == 0)
+      strcpy(pre, "538  $a ISMN $b");
+    else if (strcasecmp(mt->scheme, "sici") == 0)
+      strcpy(pre, "538  $a SICI $b");
+    else 
+      sprintf(pre, "538  $a %s $b", mt->scheme);
+  }
+
+  else if (strcasecmp(mt->name, "type") == 0)
+  {
+    parse_swetype(mt->value, (char *) type_tag);
+    sprintf(pre, "%s  $a", type_tag);
+  }
+
+  else if (strcasecmp(mt->name, "language") == 0)
+  {
+    strcpy(pre, "506  $a");
+    if (strcasecmp(mt->scheme, "z39.53") == 0)
+      put008(mr->s008, mt->value, F008_LANGUAGE);
+  }
+
+  else if (strcasecmp(mt->name, "format") == 0)
+  {
+    if ( (!*mt->scheme)
+      || (strcasecmp(mt->scheme, "imt") == 0)
+      || (strcasecmp(mt->scheme, "mime") == 0) )
+      strcpy(pre, "856  $q");
+  }
+
+  else if (strcasecmp(mt->name, "subject") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "697  $a");
+    else if (strcasecmp(mt->scheme, "udc") == 0)
+      strcpy(pre, "080  $a");
+    else if (strcasecmp(mt->scheme, "lcsh") == 0)
+      strcpy(pre, "650  $a");
+    else if (strcasecmp(mt->scheme, "ddc") == 0)
+      strcpy(pre, "082  $a");
+    else if (strcasecmp(mt->scheme, "lcc") == 0)
+      strcpy(pre, "087  $a");
+    else if (strcasecmp(mt->scheme, "sab") == 0)
+      strcpy(pre, "081  $a");
+    else if (strcasecmp(mt->scheme, "mesh") == 0)
+      strcpy(pre, "660  $a");
+    else
+      strcpy(pre, "650  $a");
+  }
+
+  else if (strcasecmp(mt->name, "date") == 0)
+  {
+    if ( (!*mt->type) || ( strcasecmp(mt->type, "current") == 0) )
+    {
+      if ( (strncasecmp(mt->scheme, "ans", 3) == 0) 
+         || (strncasecmp(mt->scheme, "iso", 3) == 0) )
+      {
+        if (find_year(mt->value))
+        {
+          strcpy(mr->year, mt->value);
+          put008(mr->s008, mt->value, F008_DATE1);
+        }
+      }
+    }
+  }
+
+  if (*pre)
+  {
+    strcat(mr->marcline, pre);
+    strcat(mr->marcline, " ");
+    strcat(mr->marcline, mt->value);
+    strcat(mr->marcline, "\n");
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/test.data
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/test.data	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/test.data	(revision 10506)
@@ -0,0 +1,1 @@
+<meta name="DC.title" content="Test file for d2m">
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/usMARC.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/usMARC.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/usMARC.c	(revision 10506)
@@ -0,0 +1,165 @@
+/* ------------------------------------------------------------------- */
+/* usMARC   : Convert a metatag struct to USMARC                       */
+/*                                                                     */
+/* 1998-09-30: Ole Husby                                               */
+/* ------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include "d2m.h" 
+
+
+
+void usMARC(struct metatag *mt, struct marcrec *mr)
+{
+  char pre[64], title_tag[4];
+
+  *pre = 0;
+
+  if (strcasecmp(mt->name, "title") == 0)
+  {
+    if ( (!*mt->type)
+         | (strcasecmp(mt->type, "main") == 0)
+         | (strcasecmp(mt->type, "long") == 0) )
+    {
+      if (mr->ntitles)
+        strcpy(title_tag, "2460");
+      else
+        strcpy(title_tag, "245 ");
+
+      mr->ntitles++;
+
+      sprintf(pre, "%s $a", title_tag);
+    }
+  }
+
+  else if (strcasecmp(mt->name, "creator") == 0) 
+  {
+    if (!*mt->type)
+      strcpy(pre, "720  $a");
+    else if ( (strcasecmp(mt->type, "name") == 0)
+            || (strcasecmp(mt->type, "personal") == 0) )
+      strcpy(pre, "700  $a");
+    else if (strcasecmp(mt->type, "corporate") == 0)
+      strcpy(pre, "710  $a");
+  }
+
+
+  else if (strcasecmp(mt->name, "publisher") == 0)
+  {
+    if (!*mt->type)
+      strcpy(pre, "260  $b");
+    else if (strcasecmp(mt->type, "name") == 0)
+      strcpy(pre, "260  $b");
+  }
+
+  else if (strncasecmp(mt->name, "contributor", 11) == 0)     /* Note both pl and sgl allowed */
+  {
+    if (!*mt->type)
+      strcpy(pre, "720  $a");
+    else if ( (strcasecmp(mt->type, "name") == 0)
+            || (strcasecmp(mt->type, "personal") == 0) )
+      strcpy(pre, "700  $a");
+    else if (strcasecmp(mt->type, "corporate") == 0)
+      strcpy(pre, "710  $a");
+  }
+
+
+  else if (strcasecmp(mt->name, "coverage") == 0)
+  {
+    if (!*mt->type)
+      strcpy(pre, "500  $a");
+    else if (strcasecmp(mt->type , "spatial") == 0)
+      strcpy(pre, "255  $c");
+    else if (strcasecmp(mt->type,  "temporal") == 0)
+      strcpy(pre, "513  $b");
+  }
+
+
+  else if (strcasecmp(mt->name, "source") == 0)
+    strcpy(pre, "7860 $n");
+
+  else if (strcasecmp(mt->name, "rights") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "540  $a");
+    else if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(pre, "856  $3 rights $a");
+  }
+
+  else if (strcasecmp(mt->name, "identifier") == 0)
+
+/* Not supported: Indicator for urn! (See crosswalk)            */
+
+  {
+    if (!*mt->scheme)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "url") == 0)
+      strcpy(mr->url, mt->value);
+    else if (strcasecmp(mt->scheme, "urn") == 0)
+      strcpy(pre, "856  $u urn:");
+    else if (strcasecmp(mt->scheme, "isbn") == 0)
+      strcpy(pre, "020  $a");
+    else if (strcasecmp(mt->scheme, "issn") == 0)
+      strcpy(pre, "022  $a");
+    else
+      strcpy(pre, "0248 $a");
+  }
+
+  else if (strcasecmp(mt->name, "format") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(mr->fmat, mt->value);
+    else if (strcasecmp(mt->scheme, "imt") == 0)
+      strcpy(mr->fmat, mt->value);
+    else if (strcasecmp(mt->scheme, "mime") == 0)
+      strcpy(mr->fmat, mt->value);
+  }
+
+  else if (strcasecmp(mt->name, "subject") == 0)
+  {
+    if (!*mt->scheme)
+      strcpy(pre, "653  $a");
+    else if (strcasecmp(mt->scheme, "lcc") == 0)
+      strcpy(pre, "050  $a");
+    else if (strcasecmp(mt->scheme, "lcsh") == 0)
+      strcpy(pre, "650  $a");
+    else if (strcasecmp(mt->scheme, "ddc") == 0)
+      strcpy(pre, "082  $a");
+  }
+
+
+  else if (strcasecmp(mt->name, "language") == 0)
+  {
+    if (strcasecmp(mt->scheme, "z39.53") == 0)
+    {
+      if (strlen(mt->value) == 3)
+        put008(mr->s008, mt->value, F008_LANGUAGE);
+    }
+  }
+
+
+  else if (strcasecmp(mt->name, "date") == 0)
+  {
+    if ( (strncasecmp(mt->scheme, "ans", 3) == 0) ||
+         (strncasecmp(mt->scheme, "iso", 3) == 0) )
+    {
+      if ( (!*mt->type) || ( strcasecmp(mt->type, "current") == 0) )
+      {
+        if (find_year(mt->value))
+        {
+          strcpy(mr->year, mt->value);
+          put008(mr->s008, mt->value, F008_DATE1);
+        }
+      }
+    }
+  }
+
+  if (*pre)
+  {
+    strcat(mr->marcline, pre);
+    strcat(mr->marcline, " ");
+    strcat(mr->marcline, mt->value);
+    strcat(mr->marcline, "\n");
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/util.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/util.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/util.c	(revision 10506)
@@ -0,0 +1,472 @@
+/* ------------------------------------------------------------------- */
+/* util      : Several utilities for the d2m converter                 */
+/*                                                                     */
+/* Author    : Ole Husby                                               */
+/* Updated   : 1998-09-30                                              */
+/* ------------------------------------------------------------------- */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "d2m.h"
+
+
+
+
+/* ------------------------------------------------------------------- */
+/* Produce MARC line-format output                                     */
+/* ------------------------------------------------------------------- */
+
+void write_field(char *l, FILE *of, int linel, int llen, int slen)
+{
+  char pre[64], line[256], *p, *q, *n;
+  int more, i, spos, compact, ctr;
+
+  ctr = 0;
+  *pre = *line = 0;
+  p = strdup(l);
+  q = p;
+
+  more = TRUE;
+  compact = FALSE;  
+
+  while (more)
+  {
+
+    ctr++;
+    if (ctr > 20) more = FALSE;
+
+    if (strlen(q) <= linel - 8)           /* String fits into 1 line  */
+    {
+      if (compact)
+      {
+        fprintf(of, "%s%s\n", pre, q);
+        more = FALSE;
+      }
+      else
+      {
+        n = strstr(q + 6, "$");
+
+        if ( (n - q ) > 5)
+        {
+          spos = (n - q);
+          strncat(line, q, spos);
+          q = n;
+          fprintf(of, "%s%s\n", pre, line);
+          strcpy(pre, "     ");
+          *line = 0;
+        }
+        else
+        {
+          fprintf(of, "%s%s\n", pre, q);
+          more = FALSE;
+        }
+      }
+    }
+
+    else                                  /* Look for splitting point */
+    {
+      spos = 0;
+
+      if (!compact)
+      {
+        for (i = 6; i < linel - 8; i++)
+        {
+          if (q[i] == '$')
+          {
+            spos = i + 1;
+            break;
+          }
+        } 
+      }
+
+ 
+      if (!spos)
+      {
+        for (i = linel - 9; i > slen; i--)
+        {
+          if ( !compact && (q[i] == '$'))
+          {
+            spos = i + 1;
+            break;
+          }
+          else if (q[i] == ' ')
+          {
+            spos = i;
+            break;
+          }
+        }
+      }
+
+      if (spos)
+      {
+         strncat(line, q, spos);
+         q +=  spos + 1;
+      }
+      else
+      {
+         strncat(line, q, llen);
+         strcat(line, "-");
+         q += llen;
+      }
+
+      fprintf(of, "%s%s\n", pre, line);
+      strcpy(pre, "     ");
+      *line = 0;
+    }
+  }
+  free(p);
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* Fetching HTTP POST data                                             */
+/* ------------------------------------------------------------------- */
+
+char *poq() 
+{
+    int m=0, c, cl;
+    char *rec;
+
+    if(strcmp(getenv("REQUEST_METHOD"),"POST"))
+      return NULL;
+
+    cl = atoi(getenv("CONTENT_LENGTH"));
+
+    if (cl)
+      rec = (char*) malloc(cl + 1);
+    else
+      return NULL;
+    
+    while (c = fgetc(stdin))
+    {
+      rec[m] = c;
+      m++;
+      if (m >= cl) break;
+    }
+
+    rec[m] = 0;
+
+    return rec;
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* ------------------------------------------------------------------- */
+
+int unesc (char h, char l)
+{
+   char buf[3];
+   int i;
+
+   buf[0]=h;
+   buf[1]=l;
+   buf[2]='\0';
+   sscanf(buf,"%x",&i);
+   return (i);
+}
+
+
+/* ------------------------------------------------------------------- */
+/* Replace '+' with space and unescape hex coded characters.           */
+/* ------------------------------------------------------------------- */
+
+void unescape (char *s)
+{
+   char *rp, *wp;  /* read position and write position in string */
+   rp=wp=s;
+   while (*rp != '\0') {
+      if (*rp=='+') {
+         *(wp++)=' ';
+         rp++;
+      }
+      else if (*rp=='%') {
+         int a,b;
+         rp++;   /* skip the '%' */
+         a = (unsigned char) *(rp++);
+         b = (unsigned char) *(rp++);
+         *(wp++)=unesc (a,b);
+      } else
+         *(wp++)=*(rp++);
+    }
+    *wp = '\0';
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* Case independent string search.                                     */
+/*                                                                     */
+/* Call syntax like strstr()                                           */
+/* ------------------------------------------------------------------- */
+
+char *cstr(char *h, char *n)
+{
+  char *nn;
+  char *hh;
+  char *p, *s;
+  long i;
+
+
+/* Returns NULL if either of strings are NULL                     */
+
+  if (!*h || !*n)
+    return (char *) NULL;
+
+
+/* Make a copy hh of h and nn of n                                */
+
+  hh = (char *) strdup(h);
+  nn = (char *) strdup(n);
+
+/* Converts hh and nn to lower                                    */
+
+  for (i = 0; i < strlen(nn); i++)
+    nn[i] = tolower(n[i]);
+
+  for (i = 0; i < strlen(hh); i++)
+    hh[i] = tolower(h[i]);
+
+/* Searches for nn in hh using strstr                             */
+
+  p = (char *) strstr(hh, nn);
+
+/* If found, calculates corresponding pointer into h              */
+
+  if (!p)
+    s = (char *) NULL;
+  else
+  {
+    i = strlen(hh) - strlen(p);
+    s = h + i;
+  }
+
+/* Frees string copies and returns                                */
+
+  free(hh);
+  free(nn);
+
+  return s; 
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* Write and remove tracefile                                          */
+/* ------------------------------------------------------------------- */
+
+int write_trace(char *tracefile, FILE *of)
+{
+  char line[10000], *l;
+  FILE *tf;
+
+  tf = fopen(tracefile, "r");
+  if (!tf)
+    return 0;
+
+  while (l = fgets(line, 9999, tf))
+    fprintf(of, "%s", l);
+
+  fclose(tf);
+  remove(tracefile);  
+  return 1;
+}
+
+
+/* ------------------------------------------------------------------- */
+/* Insert field into 008                                               */
+/* ------------------------------------------------------------------- */
+
+int put008(char *s8, char *str, int f8)
+{
+   int i, len, pos, nlen, npos, append=0;
+
+   if (strlen(s8) != 40)
+     return 0;
+
+   switch (f8)
+   {
+     case (F008_DATE_ENTERED) :
+     {
+       pos = 0;
+       len = 6;
+       break;
+     }
+     case (F008_TYPE_OF_DATE) :
+     {
+       pos = 6;
+       len = 1;
+       break;
+     }
+     case (F008_DATE1) :
+     {
+       pos = 7;
+       len = 4;
+       break;
+     }
+     case (F008_FORM_OF_PUBLICATION) :
+     {
+       pos = 24;
+       len = 4;
+       append = 1;
+       break;
+     }
+     case (F008_LANGUAGE) :
+     {
+       pos = 35;
+       len = 3;
+       break;
+     }
+     default :
+       return 0;
+   }
+
+
+   npos = pos;
+   nlen = strlen(str);
+   if (nlen > len)
+     return 0;
+
+   if (nlen < len)
+   {
+     if (append)
+     {
+       npos = 0;
+       for (i = pos; i < pos + len; i++)
+       {
+         if ( s8[i] == ' ' )
+         {
+           npos = i;
+           break; 
+         }
+       }
+       if (npos == 0)
+         return 0;
+       if (npos >= pos + len)
+         return 0;
+       if (npos + nlen > pos + len)
+         return 0;
+     }
+     else
+       return 0;
+   }
+/* printf
+     ("pos %d len %d npos %d nlen %d str %s\n", 
+     pos, len, npos, nlen, str);
+*/
+
+   for (i = 0; i < nlen; i++)
+     s8[npos+i] = str[i];
+
+   return 1;
+}
+
+
+/* ------------------------------------------------------------------- */
+/* Converts date to YYYY                                               */
+/* ------------------------------------------------------------------- */
+
+int find_year(char *str)
+{
+  int i;
+
+  if (strlen(str) < 4)
+    return 0;
+
+  str[4] = 0;
+
+  for (i = 0; i < 4; i++)
+  {
+    if (!isdigit(str[i]))
+      return 0;
+  }
+ 
+  return 1;
+}
+
+
+
+
+/* ------------------------------------------------------------------- */
+/* Splits personal name at first "," into $a and $h                    */
+/* ------------------------------------------------------------------- */
+
+int split_name(char *str)
+{
+  char *p, *q, subtag[5];
+
+  if (!strstr(str, ","))
+    return 1;
+
+  p = (char *) malloc(strlen(str) + 50);
+  *p = 0;
+  *subtag = 0;
+
+  q = strtok(str, ",");
+  if (q)
+  {
+    strcpy(p, q);
+    q = strtok(NULL, "\0");
+    if (q)
+    {
+      while ( ( q[0] == ' ' ) && ( strlen(q) ) )
+        q++;
+      strcat(p, " $h ");
+      strcat(p, q);
+    }
+    strcpy(str, p);
+  }
+
+  free(p);
+
+  return 1;
+}
+
+
+
+/* ------------------------------------------------------------------- */
+/* Splits subject heading on "-". First occurence go into $a, second   */ 
+/* into $b, all the rest into $x                                       */
+/* ------------------------------------------------------------------- */
+
+int split_subj(char *str)
+{
+  char *p, *q, subtag[5];
+
+  if (!strstr(str, "-"))
+    return 1;
+
+  p = (char *) malloc(strlen(str) + 50);
+  *p = 0;
+  *subtag = 0;
+
+  q = strtok(str, "-");
+  while (q)
+  {
+    while ( ( q[0] == ' ' ) && ( strlen(q) ) )
+      q++;
+
+    while( ( q[strlen(q) - 1] == ' ' ) && ( strlen(q) ) )
+      q[strlen(q) - 1] = '\0';
+
+    if (*q)
+    {
+      strcat(p, subtag);
+      strcat(p, q);
+      if (!*subtag)
+        strcpy(subtag, " $b ");
+      else
+        strcpy(subtag, " $x ");
+    }
+    q = strtok(NULL, "-");
+  }
+
+  strcpy(str, p);
+  free(p);
+
+  return 1;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/wfetch-l.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/wfetch-l.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/wfetch-l.c	(revision 10506)
@@ -0,0 +1,19 @@
+/* ------------------------------------------------------------------- */
+/* wfetch    : Fetch a remote file using the htget() "HTTP client"     */
+/*                                                                     */
+/* syntax    : wfatch(char *url, char *filename)                       */
+/*                                                                     */
+/* Returns   : 0 ALWAYS!                                               */
+/*                                                                     */
+/* Author    : Ole Husby, BIBSYS                                       */
+/* Updated   : 1998-10-04                                              */
+/* ------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+int wfetch(char *url, char *filename)
+{
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/wfetch.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/wfetch.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/wfetch.c	(revision 10506)
@@ -0,0 +1,53 @@
+/* ------------------------------------------------------------------- */
+/* wfetch    : Fetch a remote file using the htget() "HTTP client"     */
+/*                                                                     */
+/* syntax    : wfatch(char *url, char *filename)                       */
+/*                                                                     */
+/*             The file will be written to "filename"                  */
+/*                                                                     */
+/* Returns   : 0 if fail                                               */
+/*           : 1 if HTML file (text/html)                              */
+/*           : 2 if MARC file (application/marc)                       */
+/*                                                                     */
+/* NOTE      : Timeout period (HTTP) is set here.                      */
+/*                                                                     */
+/* Author    : Ole Husby, BIBSYS                                       */
+/* Updated   : 1998-08-11                                              */
+/* ------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define  TIMEOUT_SECONDS       10
+
+int wfetch(char *url, char *filename)
+{
+  int i, type, argtype, timeout, rc, retc;
+  char iurl[1024], content_type[128], location[128];
+
+  retc = 1;
+
+  strcpy(iurl, url);
+  timeout = TIMEOUT_SECONDS;
+
+  type = 6;                           /* Fetch HTML HEAD or MARC      */
+
+  rc = htget(iurl, type, timeout, filename, content_type, location);
+
+
+/* Try again if redirect                                              */
+
+  if ( ( ( rc == 301 ) || ( rc == 302 ) ) && *location )
+  {
+    strcpy(iurl, location);
+    rc = htget(iurl, type, timeout, filename, content_type, location);
+  }
+
+  if (rc)
+    retc = 0;
+  else if (strcmp(content_type, "application/marc") == 0)
+    retc = 2;
+
+  return retc;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/d2m/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/d2m/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/d2m/win32.mak	(revision 10506)
@@ -0,0 +1,45 @@
+# ///////////////// d2m : Dublin Core to MARC converter /////////////////////
+#
+#
+# Generated for Greenstone kjdon May 2005.
+# Used by z3950server
+
+GSDLHOME = ..\..
+CC = cl
+AR = lib
+
+DLL = 0
+DLLDEBUG = 0
+
+CPPFLAGS = -GX
+!IF $(DLL)
+CPPFLAGS = $(CPPFLAGS) -MD 
+!ELSE
+!IF ($(DLLDEBUG))
+CPPFLAGS = $(CPPFLAGS) -MDd
+!ENDIF
+!ENDIF
+
+o = .obj
+
+DEFS=-DHAVE_CONFIG_H -D__WIN32__
+INCLUDES= -I"$(GSDLHOME)"
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+
+LIB_OBJS = MARC2709$o MARCtidy$o usMARC$o util$o strcasecmp$o
+
+all: libd2m.lib
+
+libd2m.lib: $(LIB_OBJS)
+	if EXIST libd2m.lib del libd2m.lib
+	$(AR) /out:libd2m.lib $(LIB_OBJS)
+
+install:
+
+clean:
+	del *$o 
+	del libd2m.lib
+
+distclean: clean
+	rm -f Makefile config.h
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/expat/Makefile
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/expat/Makefile	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/expat/Makefile	(revision 10506)
@@ -0,0 +1,12 @@
+
+all:
+	(cd expat-1.95.8 ; make all installlib)
+
+clean:
+	(cd expat-1.95.8 ; make clean)
+
+distclean:
+	(cd expat-1.95.8 ; make distclean)
+
+install:
+	@echo Expat installed
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/AbstractIsisDb.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/AbstractIsisDb.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/AbstractIsisDb.h	(revision 10506)
@@ -0,0 +1,171 @@
+/**********************************************************************
+ *
+ * AbstractIsisDb.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+///////////////////////////////////////////////////////////////////////////////////
+// AbstractIsisDb.h -- Abstract Base Class Definitions for an ISIS db
+//
+//
+// The objective is to provide an interface for creating families of Isis
+// db without specifying their concrete classes. 
+// ABSTRACT FACTORY PATTERN is used.
+//
+// Author: J-C Dauphin, UNESCO, August 2000
+///////////////////////////////////////////////////////////////////////////////////
+ 
+#ifndef __ABSTRACT_ISISDB_H__
+#define __ABSTRACT_ISISDB_H__
+
+#include <vector>
+#include "IsisDef.h"
+#include "mytchar.h"
+
+
+/////////////////////////////////////////////////////////////////////////////////// 
+//   Abstract Base Class, set the DB interface. All db concrete classes must be
+//   derived from this class.
+//
+// Note that this abstract base class can be extended by specifying abstract base
+// classes for class class MfFile, class XrfFile, class CFdtCWorksheet, 
+// class CDisplayFormat, class CFieldSelectTable, class CSortTable, 
+// class MfRecord and struct SMfHeader. Pure virtual methods would then be added
+// in the class AbstractIsisDbFactory:
+//
+// 	virtual AbstractMfFile* makeMfFile() = 0;
+//	virtual AbstractXrfFile* makeXrfFile() = 0;
+//  ................
+ 
+
+class MfFile;
+class XrfFile;
+class CFdt; // Forward 
+
+class CWorksheet;
+class CDisplayFormat;
+class CFieldSelectTable;
+class CSortTable;
+class MfRecord;
+struct SMfHeader;
+ 
+class AbstractIsisDb 
+{
+protected:
+	ustring    	name;
+
+    MfFile*   mf_;   // Has-a master file
+    XrfFile*  xf_;   // Has-a cross ref file
+    CFdt*     fdt_;  // Has-a FDT
+
+    std::vector<CWorksheet*>            apWS_;   // Worksheets
+    std::vector<CDisplayFormat*>        apDFMT_; // Display formats
+    std::vector<CFieldSelectTable*>     apFST_;  // Field Select Tables
+    std::vector<CSortTable*>            apST_;   // Sort Tables   
+    
+public:
+	AbstractIsisDb() { };                    // Trivial default C++ constructor
+	virtual ~AbstractIsisDb() { };           // Trivial C++ destructor
+
+// Opening the database
+   virtual int OpenDb(const TCHAR *fname, FileSystem::AccessMode mode =
+	                                          FileSystem::FILE_READWRITE) = 0; 
+// Creating the database
+   virtual int CreateDb(const TCHAR* fname) = 0;
+
+// Closing the database
+   virtual void CloseDb()   = 0;    // Close the db
+   virtual void ClearDb()   = 0;    // Clear the db
+   virtual void DestroyDb() = 0;    // Delete the db
+
+// Recovery
+   virtual bool IsDamaged() = 0;   // Test if the database is damaged
+   virtual bool Recover()   = 0;   // Recover the db
+
+// Transactions
+   virtual void BeginTransaction()     = 0;   // Begin a transaction
+   virtual void CommitTRansaction()    = 0;   // Commit a transaction
+   virtual void RollbackTransaction()  = 0;   // Rollback a transaction
+   virtual bool InTransaction()        = 0;   // Test if transaction is pending
+
+// (FDT)
+   virtual void SetFdt(CFdt *pFdt) { fdt_ = pFdt; }
+   virtual CFdt* GetFdt() { return fdt_; }
+
+//  worksheets (WORKSHEETS). 
+// (used to create/update the master records of the db)
+   virtual void SetWorksheetAt(int i, CWorksheet* pWS) { apWS_.insert(apWS_.begin()+i, pWS); }
+   virtual CWorksheet* GetWorksheetAt(int i)           { return apWS_[i]; }
+   virtual void RemoveWorksheetAt(int i)               { apWS_.erase(apWS_.begin()+i); }
+
+// display formats (DISPLAY FORMATS).
+// (used for specifying the formatting requirements for either on-line
+// display of records during searching or for the generation of printed
+// output documents.
+   virtual void SetDisplayFormatAt(int i, CDisplayFormat* pDFMT) { apDFMT_.insert(apDFMT_.begin()+i, pDFMT); }
+   virtual CDisplayFormat* GetDisplayFormatAt(int i)             { return apDFMT_[i]; }
+   virtual void RemoveDisplayFormatAt(int i)                     { apDFMT_.erase(apDFMT_.begin()+i); }
+
+// Field Select Table (FST).
+// One FST defines the fields of the database to be made searchable
+// through the inverted dile.
+   virtual void SetFieldSelectTableAt(int i, CFieldSelectTable* pFST) { apFST_.insert(apFST_.begin()+i, pFST); }
+   virtual CFieldSelectTable* GetFieldSelectTableAt(int i)            { return apFST_[i]; }
+   virtual void RemoveFieldSelectTableAt(int i)                       { apFST_.erase(apFST_.begin()+i); }
+
+   virtual void CreateIndex(int i) = 0;
+   virtual void DropIndex(int i)   = 0;
+
+// Sort Select Table (SST).
+// One FST defines the fields of the database to be made searchable
+// through the inverted dile.
+
+   virtual void SetSortTableAt(int i, CSortTable* pST) { apST_.insert(apST_.begin()+i, pST); }
+   virtual CSortTable* GetSortTableAt(int i)           { return apST_[i]; }
+   virtual void RemoveSortTableAt(int i)               { apST_.erase(apST_.begin()+i); }
+
+   virtual void  CreateDbRecord(MfRecord &m) = 0;
+   virtual void  UpdateDbRecord(MfRecord &m) = 0;
+   
+   virtual int   ReadDbRecord(long mfn, MfRecord &m) = 0;
+   virtual int   ReadNextDbRecord(MfRecord &m)       = 0;
+   
+   virtual bool  DeleteRecord(long mfn)              = 0;
+
+   virtual void  PrintDbRecord(MfRecord &m)          = 0;
+   virtual void  PrintDbHdr()                        = 0;
+
+   virtual long GetNextMfn() = 0;
+   virtual long GetNextActiveMfn(long mfn=-1) = 0;
+
+   virtual SMfHeader& GetSMfHeader() = 0;
+   virtual _TCHAR *GetIdxFileName()  = 0;
+ 
+
+};
+ 
+class AbstractIsisDbFactory
+{
+public:
+	virtual AbstractIsisDb* MakeIsisDb() = 0;
+};
+#endif   // __ABSTRACT_ISISDB_H__
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/BlkFile.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/BlkFile.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/BlkFile.h	(revision 10506)
@@ -0,0 +1,155 @@
+/**********************************************************************
+ *
+ * BlkFile.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+//////////////////////////////////////////////////////////////////////
+//  BLKFILE.H
+//
+//  Class for accessing a file per blocks of blksize bytes, blocks
+//  are sequential from 1 to nblock.
+//                                                                       
+//////////////////////////////////////////////////////////////////////
+ 
+#ifndef _BLKFILE_H_
+#define _BLKFILE_H_
+#include "CacheMan.h"
+#include "File.h"
+ 
+//////////////////////////
+// Block I/O file class
+//
+ 
+ 
+ 
+class BlkFile : public CFileBase
+{
+public:
+   enum { blk_size = 512 };
+protected:
+   unsigned     blkSize_;      // Block Size
+   CacheManager cache_;
+public:
+   BlkFile(int bs=BlkFile::blk_size);
+   BlkFile(const _TCHAR *fname, int bs=BlkFile::blk_size);
+   virtual FileError Close();
+   virtual ~BlkFile();
+   virtual void ReadBlk(void* d, long b);
+   virtual void WriteBlk(void* d, long b);
+   virtual void ReadBlk(void* d);
+   virtual void WriteBlk(void* d);
+
+   void SetBlockSize(int blockSize) { blkSize_ = blockSize; }
+   int  GetBlockSize() { return blkSize_; }
+};
+ 
+////////////////////////////////////////
+ 
+inline BlkFile::BlkFile(int bs) :
+// Makes a Blocked File object that isn't connected to a file
+// Block size is bs
+CFileBase(), blkSize_(bs)
+{
+	cache_.Create(bs, 40);
+	cache_.Connect(this);
+   // Nothing more to do
+}
+ 
+ 
+////////////////////////////////////////
+ 
+inline BlkFile::BlkFile(const _TCHAR *fname, int bs) :
+// Makes a Blocked File object connected to a file
+// Block size is bs
+CFileBase(), blkSize_(bs), cache_(bs, 20)
+{
+	CFileBase::Open(fname, FileSystem::FILE_READWRITE);
+	cache_.Create(bs, 40);
+	cache_.Connect(this);
+   // Nothing more to do
+}
+ 
+////////////////////////////////////////
+ 
+inline BlkFile::~BlkFile()
+// Destructor  for BlkFile object
+{
+	cache_.Disconnect();
+   // Nothing more to do
+}
+ 
+////////////////////////////////////////////
+
+
+inline FileError BlkFile::Close()
+{
+	if (IsOpen())
+	    cache_.Invalidate();
+	return CFileBase::Close();
+}
+////////////////////////////////////////
+ 
+inline void BlkFile::ReadBlk(void* d, long b)
+// Reads block number b into d, b is in range [1:NBLOCK]
+{
+	ASSERT(d!=NULL && b>0);
+	//TRACE("\nBlkFile::ReadBlk -- %s Read Block %ld", file_name, b);
+    //CFileBase::Fetch(d, blkSize_, (b-1)*blkSize_);
+	cache_.Read((b-1)*blkSize_, d);
+}
+ 
+////////////////////////////////////////
+ 
+inline void BlkFile::WriteBlk(void* d, long b)
+// Writes blksize bytes from d at block number b
+{
+	ASSERT(d!=NULL && b>0);
+	//TRACE("\nBlkFile::WriteBlk -- %s Write Block %ld", file_name, b);
+    //CFileBase::Store(d, blkSize_, (b-1)*blkSize_);
+	cache_.Write((b-1)*blkSize_, d);
+}
+ 
+ 
+////////////////////////////////////////
+ 
+inline void BlkFile::ReadBlk(void* d)
+// Reads block at current address into d
+{
+	ASSERT(d!=NULL);
+    //CFileBase::Fetch(d, blkSize_);
+	long addr = CFileBase::FilePosition();
+	cache_.Read(addr, d);
+}
+ 
+////////////////////////////////////////
+ 
+inline void BlkFile::WriteBlk(void* d)
+// Writes blkSize_ bytes from d at current address
+{
+	ASSERT(d!=NULL);
+    //CFileBase::Store(d, blkSize_);
+	long addr = CFileBase::FilePosition();
+	cache_.Write(addr, d);
+}
+ 
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CRC32.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CRC32.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CRC32.cpp	(revision 10506)
@@ -0,0 +1,170 @@
+/**********************************************************************
+ *
+ * CRC32.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////////////////////////////
+// CRC32.cpp --
+//  
+// The CRC32 functions (Cyclic Redundancy Check) are used to
+// calculate a sophisticated checksum based on the algebra of
+// polynomials. The Cyclic Redundancy Check, is a way to detect
+// bit errors that occur during data storage or transmission.
+// The CRC-32 algorithm operates on a block of data as a single
+// large numerical value. The algorithm divides this large value
+// by the CRC-32 polynomial or generator polynomial, leaving the
+// remainder 32-bit, which is the checksum. 
+//
+// #include "stdafx.h" 
+#include <iomanip>
+#include "CRC32.h"
+#include "CRCTab.h"
+
+unsigned long CalcCRC32(const char *buf, unsigned len)
+// Calculate a 32-bit CRC for a raw pattern of bytes.
+// Returns a 32-bit checksum.
+{
+ unsigned long CRC=0xffffffffL;
+ unsigned int n = len;
+
+ while(n--) 
+   CRC=crc32tab[(CRC ^ (*buf++)) & 0xFF] ^ ((CRC>>8) & 0x00ffffffL);
+
+ return CRC ^ 0xffffffffL;
+}
+
+unsigned long CalcCRC32(char *buf, unsigned len)
+// Calculate a 32-bit CRC for a raw pattern of bytes.
+// Returns a 32-bit checksum.
+{
+ unsigned long CRC=0xffffffffL;
+ unsigned int n = len;
+ char *p = (char *)buf;
+ while(n--) 
+   CRC=crc32tab[(CRC ^ (*p++)) & 0xFF] ^ ((CRC>>8) & 0x00ffffffL);
+
+ return CRC ^ 0xffffffffL;
+}
+
+unsigned long CalcCRC32(unsigned char c, unsigned long CRC)
+// Calculate a 32-bit CRC table value for a single byte.
+// NOTE: The initial CRC value must be set to 0xffffffffL
+// and the final 32-bit value that must be XOR'ed with
+// 0xffffffffL to obtain the checksum.
+{
+  unsigned int i;
+  i = (unsigned int)c;
+  i &= 0xFF; // Reset all the bits
+  CRC=crc32tab[(CRC ^ i) & 0xFF] ^ ((CRC>>8) & 0x00ffffffL);
+  return CRC;
+}
+
+unsigned long CalcCRC32(std::fstream &infile)
+// Calculate a 32-bit CRC for a file. Assumes the stream
+// is already open. Returns a 32-bit checksum.
+{
+ unsigned long CRC=0xffffffffL;
+#ifdef _WIN32
+ char c;
+#else
+ unsigned char c;
+#endif
+ unsigned int i;
+
+ // Rewind to the start of the stream
+ infile.clear(); 
+ infile.seekg(0, std::ios::beg);
+ infile.seekp(0, std::ios::beg);
+
+ while(!infile.eof()) {
+   c=infile.get();
+   i = (unsigned int)c;
+   i &= 0xFF; // Reset all the bits
+   if(infile.eof()) break;
+   CRC=crc32tab[(CRC ^ i) & 0xFF] ^ ((CRC>>8) & 0x00ffffffL);
+ }
+ return CRC ^ 0xffffffffL;
+}
+
+#ifdef __USE_CRC32_TABLE_FUNCTIONS__
+int MakeCRC32(ostream &stream)
+// Write a CRC 32 table for a byte-wise 32-bit CRC calculation
+// based on the Autodin/Ethernet/ADCCP polynomial of 0x4C11DB7:
+// 0000 0100 1100 0001 0001 1101 1011 0111 (binary) or a poly of
+// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7 +x^5+x^4+x^2+x^1+x^0
+// In this representation the coefficient of x^0 is stored in the 
+// MSB of the 32-bit word and the coefficient of x^31 is stored in 
+// the LSB. Thus 0x4C11DB7 becomes 0xEDB88320:
+// 1110 1101 1011 1000 1000 0011 0010 0000 (binary)
+
+// Adding the polynomials is performed using an exclusive-or, and
+// multiplying a polynomial by x is a right shift by one. If the 
+// polynomial is called "p", and each byte is represented as polynomial
+// "q", with the lowest power in the most significant bit (so the byte
+// 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) 
+// mod "p", where "a" mod "b" means the remainder after dividing "a" by
+// "b". This calculation is done using the shift-register method of
+// multiplying and taking the remainder. The register is initialized
+// to zero, and for each incoming bit, x^32 is added mod "p" to the
+// register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1),
+// and the register is multiplied mod "p" by "x" (which is shifting right
+// by one and adding x^32 mod "p" if the bit shifted out is a one.) This
+// algorithm starts with the highest power (least significant bit) of "q"
+// and repeats for all eight bits of "q".
+{
+  unsigned long c; // CRC shift register 
+  unsigned long e; // Polynomial exclusive-or pattern 
+  int i;           // Counter for all possible eight bit values 
+  int k;           // Byte being shifted into crc apparatus 
+
+  // Terms of polynomial defining this crc (except x^32): 
+  static const int p[14] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  // Make exclusive-or pattern from polynomial 
+  e = 0;
+  for (i = 0; i < sizeof(p)/sizeof(int); i++)
+    e |= 1L << (31 - p[i]);
+
+  // Compute and print table of CRC's, five per line 
+  stream << endl;
+  stream << "  0x00000000U";
+  for (i = 1; i < 256; i++)
+  {
+    c = 0;
+    for (k = i | 256; k != 1; k >>= 1)
+    {
+      c = c & 1 ? (c >> 1) ^ e : c >> 1;
+      if (k & 1)
+        c ^= e;
+    }
+
+    if(i % 5)
+      stream << ", 0x" << setfill('0') << setw(8) << hex << c << "U";
+    else
+      stream << "," << endl << "  0x" << setfill('0') << setw(8) << hex
+	     << c << "U";
+  }
+  stream << endl;
+  return 1;
+}
+#endif // __USE_CRC32_TABLE_FUNCTIONS__
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CRC32.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CRC32.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CRC32.h	(revision 10506)
@@ -0,0 +1,52 @@
+/**********************************************************************
+ *
+ * CRC32.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////////////////////////////
+// CRC32.H
+//
+// The CRC32 functions (Cyclic Redundancy Check) are used to
+// calculate a sophisticated checksum based on the algebra of
+// polynomials. The Cyclic Redundancy Check, is a way to detect
+// bit errors that occur during data storage or transmission.
+// The CRC-32 algorithm operates on a block of data as a single
+// large numerical value. The algorithm divides this large value
+// by the CRC-32 polynomial or generator polynomial, leaving the
+// remainder 32-bit, which is the checksum. 
+#ifndef __CRC32_H__
+#define __CRC32_H__
+
+#include <fstream>
+
+unsigned long CalcCRC32(char *buf, unsigned len);
+unsigned long CalcCRC32(const char *buf, unsigned len);
+unsigned long CalcCRC32(unsigned char c, unsigned long CRC);
+unsigned long CalcCRC32(std::fstream &infile);
+
+#ifdef __USE_CRC32_TABLE_FUNCTIONS__
+#include <iostream>
+int makeCRC32(std::ostream &stream);
+#endif
+
+#endif  // __CRC32_H__
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CRCTab.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CRCTab.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CRCTab.h	(revision 10506)
@@ -0,0 +1,100 @@
+/**********************************************************************
+ *
+ * CRCTab.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////////////////////////////
+// CRCTAB.H --
+
+// CRC 32 table of all possible single-byte values. The table is
+// the CRC of all possible eight bit values. This is all the info
+// needed to generate 32-bit CRC's on data one a byte at a time 
+// for all combinations of CRC register values and incoming bytes.   
+// This table was generated with the makeCRC32() function. It is
+// based on the Autodin/Ethernet/ADCCP polynomial of 0x4C11DB7:
+// 0000 0100 1100 0001 0001 1101 1011 0111 (binary) or a poly of
+// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7 +x^5+x^4+x^2+x^1+x^0
+// In this representation the coefficient of x^0 is stored in the 
+// MSB of the 32-bit word and the coefficient of x^31 is stored in 
+// the LSB. Thus 0x4C11DB7 becomes 0xEDB88320:
+// 1110 1101 1011 1000 1000 0011 0010 0000 (binary)
+
+#ifndef __CRC32_TABLE_HPP__
+#define __CRC32_TABLE_HPP__
+
+const unsigned long crc32tab[256] = {
+  0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
+  0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
+  0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
+  0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
+  0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
+  0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
+  0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
+  0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
+  0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
+  0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
+  0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
+  0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
+  0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
+  0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
+  0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
+  0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
+  0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
+  0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
+  0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
+  0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
+  0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
+  0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
+  0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
+  0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
+  0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
+  0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
+  0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
+  0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
+  0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
+  0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
+  0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
+  0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
+  0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
+  0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
+  0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
+  0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
+  0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
+  0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
+  0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
+  0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
+  0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
+  0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
+  0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
+  0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
+  0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
+  0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
+  0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
+  0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
+  0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
+  0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
+  0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
+  0x2d02ef8dU
+};
+
+#endif // __CRC32_TABLE_HPP__
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CacheMan.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CacheMan.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CacheMan.cpp	(revision 10506)
@@ -0,0 +1,213 @@
+/**********************************************************************
+ *
+ * CacheMan.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#include "stdafx.h"
+#include "File.h"
+
+#include "CacheMan.h"
+
+
+CacheManager::CacheManager()
+{
+	maxblocks_ = 0;
+}
+CacheManager::CacheManager(unsigned blocksz, unsigned mxblks)
+{
+	PRECONDITION(maxblocks_ == 0);
+	maxblocks_ = mxblks;
+	nused_     = 0;
+	blocksize_ = blocksz;
+	buff_      = new char[blocksize_*maxblocks_];
+	diskAddrs_ = new FileSystem::FAU_t[maxblocks_];
+	useCounts_ = new unsigned[maxblocks_];
+	theFile_   = NULL;
+}
+/*
+ * Construct a cache manager for blocks of size blocksz and mxblks buffers
+ */
+void CacheManager::Create(unsigned blocksz, unsigned mxblks)
+{
+	PRECONDITION(maxblocks_ == 0);
+	maxblocks_ = mxblks;
+	nused_     = 0;
+	blocksize_ = blocksz;
+	buff_      = new char[blocksize_*maxblocks_];
+	diskAddrs_ = new FileSystem::FAU_t[maxblocks_];
+	useCounts_ = new unsigned[maxblocks_];
+	theFile_   = NULL;
+}
+
+//
+// Connect to a CFileBase
+//
+void CacheManager::Connect(CFileBase* file)
+{
+	PRECONDITION(nused_ == 0);
+	theFile_   = file;
+}
+//
+// Disconnect the cache from the CFileBase
+//
+void CacheManager::Disconnect()
+{
+	if (theFile_)
+	{
+		if (theFile_->IsOpen())
+		    Flush();
+	}
+	theFile_   = NULL;
+}
+
+void CacheManager::Erase()
+{
+	Disconnect();
+	delete[] useCounts_;
+	delete[] diskAddrs_;
+	delete[] buff_;
+	maxblocks_ = 0;
+}
+
+
+CacheManager::~CacheManager()
+{
+	Disconnect();
+	delete[] useCounts_;
+	delete[] diskAddrs_;
+	delete[] buff_;
+}
+
+bool CacheManager::Flush()
+{
+	PRECONDITION(theFile_ != NULL && theFile_->IsOpen());
+	// Because we use "write through", this is all that's necessary:
+	if (theFile_->Flush() == FILE_NO_ERROR)
+		return true;
+	return false;
+}
+
+void CacheManager::Invalidate()
+{
+	nused_ = 0;
+}
+
+bool CacheManager::Read(FileSystem::FAU_t locn, void* dat)
+{
+	PRECONDITION(dat != NULL);
+	size_t islot = AgeAndFindSlot(locn);
+	
+	if (islot == INVALID_NPOS)
+	{
+        // Not in buffer;  we'll have to read it in from disk.
+	    // Get a free slot.
+		if ((islot = GetFreeSlot()) == INVALID_NPOS)
+			return false;
+		diskAddrs_[islot] = locn;
+		if (!(theFile_->SeekTo(locn) == locn) || 
+			!(theFile_->Fetch(buff_ + islot*blocksize_, blocksize_) == FILE_NO_ERROR))
+			return false;
+	}
+	useCounts_[islot] = 0;
+	memcpy(dat, buff_ + islot*blocksize_, blocksize_);
+	return true;
+}
+
+bool CacheManager::Write(FileSystem::FAU_t locn, void* dat)
+{
+	PRECONDITION(dat != NULL);
+	PRECONDITION(theFile_->ReadyForWriting());
+	size_t islot = AgeAndFindSlot(locn);
+	
+	if (islot == INVALID_NPOS)
+	{
+        // Not in buffer; find a free slot.
+		if ((islot = GetFreeSlot()) == INVALID_NPOS)
+			return false;
+		diskAddrs_[islot] = locn;
+	}
+	
+	useCounts_[islot] = 0;
+	memcpy(buff_ + islot*blocksize_, dat, blocksize_);
+	if ((theFile_->SeekTo(locn) == locn) &&
+		(theFile_->Store(buff_ + islot*blocksize_, blocksize_) == FILE_NO_ERROR))
+		return true;
+	return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Private helper functions	
+
+size_t CacheManager::AgeAndFindSlot(FileSystem::FAU_t locn)
+{
+	size_t islot = INVALID_NPOS;
+	for (register unsigned i = 0; i < nused_; i++)
+	{
+		if (diskAddrs_[i] == locn)
+			islot = i;
+		useCounts_[i]++;		// Age the blocks
+	}
+	return islot;
+}
+
+bool CacheManager::Flush(unsigned)
+{
+	if (theFile_->Flush() == FILE_NO_ERROR)
+		return true;
+	return false;
+}
+
+size_t CacheManager::GetFreeSlot()
+{
+	size_t islot;
+	
+	if (nused_ < maxblocks_)
+	{
+		islot = nused_++;		// Found an unused slot.
+	}
+	else 
+	{
+		// No free slots; get the Least Recently Used block
+		islot = LRU();
+
+		if (theFile_->ReadyForWriting())
+			if (!Flush(islot))
+			    islot = INVALID_NPOS;
+	}
+	return islot;
+}
+
+size_t CacheManager::LRU() const
+{
+	size_t islot = 0;
+	unsigned maxCount = useCounts_[0];
+	for (register unsigned i = 1; i < nused_; i++)
+	{
+		if (useCounts_[i] > maxCount)
+		{
+			maxCount = useCounts_[islot = i]; 
+		}
+	}
+	return islot;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CacheMan.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CacheMan.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/CacheMan.h	(revision 10506)
@@ -0,0 +1,71 @@
+/**********************************************************************
+ *
+ * CacheMan.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef __CACHEMAN_H__
+#define __CACHEMAN_H__
+
+
+#include "File.h"
+
+class CacheManager
+{
+private:
+	
+	CFileBase*	       theFile_;
+	unsigned		   maxblocks_;  // Max # blocks in buff_er
+	unsigned		   nused_;	    // Number being used.
+	unsigned		   blocksize_;  // Size of a block
+	FileSystem::FAU_t* diskAddrs_;  // Its disk address
+	unsigned*		   useCounts_;  // Use count for the block
+	char*			   buff_;	    // The set of blocks.
+	
+public:
+	
+	CacheManager();
+    CacheManager::CacheManager(unsigned blocksz, unsigned mxblks);
+
+	~CacheManager();
+	
+	void        Create(unsigned blocksz, unsigned mxblks = 10);
+	void        Erase();
+	
+	void        Connect(CFileBase* file);
+	void        Disconnect();
+	bool  		Flush();	        // Perform any pending writes.
+	void		Invalidate();	    // Invalidate the entire cache
+	bool  		Read (FileSystem::FAU_t locn, void* dat);
+	bool  		Write(FileSystem::FAU_t locn, void* dat);
+	
+private:
+	
+	CacheManager(const CacheManager&);          // Private to insure no copies
+	void		operator=(const CacheManager&); // Ditto
+	size_t		AgeAndFindSlot(FileSystem::FAU_t);
+	bool  		Flush(unsigned);
+	size_t		GetFreeSlot();
+	size_t		LRU() const; // Find least recently used block
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Checking.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Checking.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Checking.cpp	(revision 10506)
@@ -0,0 +1,65 @@
+/**********************************************************************
+ *
+ * Checking.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+// Checking -- 
+//               
+
+
+#include "stdafx.h"
+#include "File.h"
+#include "Master.h"
+#include "MFFile.h"
+#include "Checking.h"
+
+using namespace Checking;
+//---------------------------------------------------------------------
+// Checking::CheckMfHeader(const char *mfname, SMfHeader *mfh)
+//
+// Invariant to be respected by the mf header
+//---------------------------------------------------------------------
+void Checking::CheckMfHeader(const _TCHAR *mfname, SMfHeader &mfh)
+{
+	long size = FileSystem::FileSize(mfname);
+	TRACE(_T("\nsize=%ld "), size);
+	long mfSize = mfh.nxtmfb_ * MFBLKSIZE;
+	//ASSERT(size == mfSize);
+	ASSERT(mfh.nxtmfp_>0 && mfh.nxtmfp_<=MFBLKSIZE);
+	ASSERT(mfh.mftype_ == USERMST);
+	ASSERT(mfh.nxtmfn_>0);
+	ASSERT(mfh.ctlmfn_ == 0);
+	//assert(mfh.reccnt == 0);
+	//assert(mfh.mfcxx1 == 0);
+	//assert(mfh.mfcxx2 == 0);
+	//assert(mfh.mfcxx3 == 0);
+}
+
+void Checking::CheckMfRecordHeader(long addr)
+{
+
+}
+
+using namespace std;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Checking.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Checking.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Checking.h	(revision 10506)
@@ -0,0 +1,34 @@
+/**********************************************************************
+ *
+ * Checking.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+/////////////////////////////////////////////////////////////////////////////////
+// Checking.h --
+
+
+namespace Checking {
+   void CheckMfHeader(const _TCHAR *mfname, SMfHeader &mfh);
+   void CheckMfRecordHeader(long addr);
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Compat.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Compat.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Compat.h	(revision 10506)
@@ -0,0 +1,105 @@
+/**********************************************************************
+ *
+ * Compat.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef _WIN32
+
+#include <string>
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#define TCHAR  char
+#define BOOL   bool
+#define WORD   unsigned short
+#define DWORD  unsigned long
+#define INT32  int
+#define UINT32 unsigned int
+#define LONG   long int
+#define TRUE   true
+#define FALSE  false
+
+#define _MAX_PATH 512
+// #define SHRT_MAX  32732
+
+/* Formatted i/o */
+
+#define _tprintf    printf
+#define _ftprintf   fprintf
+#define _stprintf   sprintf
+#define _sntprintf  _snprintf
+#define _vtprintf   vprintf
+#define _vftprintf  vfprintf
+#define _vstprintf  vsprintf
+#define _vsntprintf _vsnprintf
+#define _tscanf     scanf
+#define _ftscanf    fscanf
+#define _stscanf    sscanf
+/* String conversion functions */
+
+#define _tcstod     strtod
+#define _tcstol     strtol
+#define _tcstoul    strtoul
+
+#define _itot       _itoa
+#define _ltot       _ltoa
+#define _ultot      _ultoa
+#define _ttoi       atoi
+#define _ttol       atol
+
+#define _ttoi64     _atoi64
+#define _i64tot     _i64toa
+#define _ui64tot    _ui64toa
+/* String functions */
+
+/* Note that _mbscat, _mbscpy and _mbsdup are functionally equivalent to 
+   strcat, strcpy and strdup, respectively. */
+
+#define _tcscat     strcat
+#define _tcscpy     strcpy
+#define _tcsdup     _strdup
+
+#define _tcslen     strlen
+#define _tcsxfrm    strxfrm
+
+
+// #define assert
+#define ASSERT
+#define AssertFailed
+
+// #define _T(par) par
+#define LPCTSTR const char *
+#define LPTSTR char *
+#define FAR
+#define TRACE
+#define PRECONDITION
+#define SIZE_T size_t
+
+
+
+#endif
+#define MoveMemory memmove
+#define ZeroMemory(p,size) memset(p,0,size)
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/DLLCode.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/DLLCode.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/DLLCode.h	(revision 10506)
@@ -0,0 +1,74 @@
+/**********************************************************************
+ *
+ * DLLCode.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+/////////////////////////////////////////////////////////////////////////////
+// DLLCODE.H - include file used by all platforms to define macros required 
+//             to build static and dynamic libraries.
+//             The DLLCODE.H file is included in every include file extending
+//             the visibility of the macros defined here to the every source
+//             code file. 
+
+
+#ifndef __DLL_CODE_H__
+#define __DLL_CODE_H__
+
+#if defined (__MSVC_DLL__) // Defines the entry point for the DLL application
+//--------------------------------------------------------------------------
+// The following ifdef block is the standard way of creating macros which 
+// make exporting from a DLL simpler. All files within this DLL are compiled 
+// with the DLL_CODE_EXPORTS  symbol defined on the command line. This 
+// symbol should not be defined on any project that uses this DLL. This way 
+// any other project whose source files include this file see DLL_CODE_API 
+// functions as being imported from a DLL, whereas this DLL sees symbols
+// defined with this macro as being exported.
+//---------------------------------------------------------------------------
+#ifdef DLL_CODE_EXPORTS
+#define DLL_CODE_API __declspec(dllexport)
+#else
+#define DLL_CODE_API __declspec(dllimport)
+#endif
+#else // Macro used for non DLL code
+#define DLL_CODE_API
+#endif // __MSVC_DLL__
+
+// Force ANSI compatibility for Visual C++ .NET
+#if defined (__MSDEVNET__) && !defined (__USE_ANSI_CPP__)
+#define __USE_ANSI_CPP__
+#endif // __MSDEVNET__
+
+// Force ANSI compatibility for BCC32
+#if defined (__BCC32__) && !defined (__USE_ANSI_CPP__)
+#define __USE_ANSI_CPP__
+#endif // __BCC32__
+
+#if defined (__USE_ANSI_CPP__)
+// Macro used to define the std name space used by the ANSI 
+// Standard C++ library.
+#define GXSTD std
+#else // Use the old Standard C++ library by default  
+#define GXSTD
+#endif // __USE_ANSI_CPP__
+
+#endif // __DLL_CODE_H__
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Debug.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Debug.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Debug.cpp	(revision 10506)
@@ -0,0 +1,213 @@
+#include "stdafx.h"
+#include "Debug.h"
+
+//---------------------------------------------------------------
+//
+// AssertFailed
+//
+//---------------------------------------------------------------
+#if DEBUG || ASSERTS_THROW
+void AssertFailed(const char* expr, const char* file, int line)
+{
+	/*
+	_TCHAR mesg[512];							
+
+	const char* fileName = file + strlen(file);		// strip off path
+	while (fileName > file && fileName[-1] != '\\')
+		--fileName;
+
+	_stprintf(mesg, _T("ASSERT(%s) in '%s' at line %d failed."), expr, fileName, line);
+	
+	MSG msg;							// remove pending quit messages so the message box displays
+	bool quitting = (bool) ::PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
+
+	UINT32 flags = MB_OK +				// just an OK button
+				   MB_ICONERROR +		// display the icon for errors
+				   MB_DEFBUTTON1 +		// select the OK button
+				   MB_TASKMODAL +		// don't let the user do anything else in the app
+				   MB_SETFOREGROUND;	// bring the app to the front
+
+	(void) MessageBox(NULL, mesg, NULL, flags);
+//#if DEBUG
+//	if (gBreakOnAssert)
+//		BreakStrToDebugger(mesg);
+//#endif
+
+//#if ASSERTS_THROW
+	CString text = L"Internal (Assert) Error: ";
+	AfxThrowUserException( ); 
+//#endif
+*/
+}
+#endif	// DEBUG || ASSERTS_THROW
+
+
+//---------------------------------------------------------------
+//
+// RequireFailed
+//
+//---------------------------------------------------------------
+#if !DEBUG
+void RequireFailed(const char* expr, const char* file, int line)
+{
+	/*
+	char mesg[512];							
+
+	const char* fileName = file + strlen(file);		// strip off path
+	while (fileName > file && fileName[-1] != '\\')
+		--fileName;
+
+	sprintf(mesg, "There has been a fatal error in '%s' at line %d.", fileName, line);
+
+	MSG msg;							// remove pending quit messages so the message box displays
+	bool quitting = (bool) ::PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
+
+	UINT32 flags = MB_OK +				// just an OK button
+				   MB_ICONERROR +		// display the icon for errors
+				   MB_DEFBUTTON1 +		// select the OK button
+				   MB_TASKMODAL +		// don't let the user do anything else in the app
+				   MB_SETFOREGROUND;	// bring the app to the front
+
+	(void) MessageBox(NULL, mesg, NULL, flags);
+
+	abort();
+	*/
+}
+#endif // !DEBUG
+
+//---------------------------------------------------------------
+//
+// ToStr (bool)
+//
+//---------------------------------------------------------------
+std::wstring ToStr(bool value)
+{
+	return value ? L"true" : L"false";
+}
+
+
+//---------------------------------------------------------------
+//
+// ToStr (char)
+//
+//---------------------------------------------------------------
+std::wstring ToStr(char value)
+{
+	wchar_t str[32];							
+	::swprintf(str, L"%c", value);
+	
+	return str;
+}
+
+
+//---------------------------------------------------------------
+//
+// ToStr (int16, int32)
+//
+//---------------------------------------------------------------
+std::wstring ToStr(int16_t value, int32_t fieldWidth)
+{
+	wchar_t str[32];							
+	::swprintf(str, L"%*d", fieldWidth, value);
+	
+	return str;
+}
+
+
+//---------------------------------------------------------------
+//
+// ToStr (uint16, int32)
+//
+//---------------------------------------------------------------
+std::wstring ToStr(uint16_t value, int32_t fieldWidth)
+{
+	wchar_t str[32];							
+	::swprintf(str, L"%*d", fieldWidth, value);
+	
+	return str;
+}
+
+
+//---------------------------------------------------------------
+//
+// ToStr (int32, int32)
+//
+//---------------------------------------------------------------
+std::wstring ToStr(int32_t value, int32_t fieldWidth)
+{
+	wchar_t str[32];							
+	::swprintf(str, L"%*ld", fieldWidth, value);
+	
+	return str;
+}
+
+
+//---------------------------------------------------------------
+//
+// ToStr (uint32, int32)
+//
+//---------------------------------------------------------------
+std::wstring ToStr(uint32_t value, int32_t fieldWidth)
+{
+	wchar_t str[32];							
+	::swprintf(str, L"%*lu", fieldWidth, value);
+	
+	return str;
+}
+
+
+//---------------------------------------------------------------
+//
+// ToStr (float, int32)
+//
+//---------------------------------------------------------------
+std::wstring ToStr(float value, int32_t precision)
+{
+	wchar_t str[32];							
+	::swprintf(str, L"%.*f", precision, value);
+	
+	return str;
+}
+
+
+//---------------------------------------------------------------
+//
+// ToStr (double, int32)
+//
+//---------------------------------------------------------------
+std::wstring ToStr(double_t value, int32_t precision)
+{
+	wchar_t str[32];							
+	::swprintf(str, L"%.*f", precision, value);
+	
+	return str;
+}
+
+
+//---------------------------------------------------------------
+//
+// ToStr (const char*)
+//
+//---------------------------------------------------------------
+std::wstring ToStr(const char* value)
+{
+	wchar_t str[2048];							
+	::swprintf(str, L"%s", value);
+	
+	return str;
+}
+
+
+//---------------------------------------------------------------
+//
+// ToStr (std::string)
+//
+//---------------------------------------------------------------
+std::wstring ToStr(const std::string& value)
+{
+	wchar_t str[2048];							
+	::swprintf(str, L"%s", value.c_str());
+	
+	return str;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Debug.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Debug.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Debug.h	(revision 10506)
@@ -0,0 +1,161 @@
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+//	Abstract:	This file provides the following macros:
+//
+//				ASSERT(p) - If p is false and DEBUG is true drops into the 
+//				debugger, if ASSERTS_THROW is true throws a XAssertException exception.
+//
+//				VERIFY(p) - Like ASSERT except that p is evaluated in release builds.
+//
+//				REQUIRE(p) - Like VERIFY except that it exits the app if the test fails
+//				(this is needed because the boot strap code can't safely throw).
+//
+//				COMPILE_CHECK(p) - An ASSERT that fires at compile time. This is useful
+//				for doing things like verifying the layout of items within a struct.
+//				Note that this check is also done in release builds.
+//
+//				DEBUGSTR(formatStr, n1, n2, ...) - Drops into the debugger and
+//				displays a string.
+//
+//				TRACE(formatStr, n1, n2, ...) - Writes a string to a debug window
+//				without suspending the program.
+//
+//				TRACEFLOW(category, formatStr, n1, n2, ...) - Like TRACE, but with 
+//				the addition of a category string. The category string allows users 
+//				to turn off entire categories of messages. Note that DEBUGSTR, TRACE, 
+//				and TRACEFLOW may be used with boolean expressions by tacking an _IF 
+//				on the end (eg DEBUGSTR_IF(x < 0, "Sqrt was passed a negative argument.")).
+//
+//				PRECONDITION(p)  - Used in conjunction with POSTCONDITION to verify 
+//				the integrity of an object: each public method should include one call to 
+//				PRECONDITION and another to POSTCONDITION. The idea here is to check to 
+//				see if the object stays in a valid state given valid arguments. Note that 
+//				these macros call a method named Invariant. This method should use ASSERT's 
+//				to check to see if the object is in a sane state. See ZInvariant.h for
+//				more details.
+//
+//				CHECK_INVARIANT() - Calls the Invariant. This is useful in ctors because
+//				PRECONDITION doesn't call the dtor (PRECONDITION constructs an object on
+//				the stack which calls the Invariant when the function exits).
+
+#pragma once      // Open only once per build
+
+#define RUNTIME_EXPORT 
+
+RUNTIME_EXPORT std::wstring ToStr(bool value);				// I originally used iostreams, but that caused a ridiculous amount of bloat in object files (but much less so in the exe)
+RUNTIME_EXPORT std::wstring ToStr(char value);
+inline 		   std::wstring ToStr(wchar_t value)						{return std::wstring(1, value);}
+RUNTIME_EXPORT std::wstring ToStr(int16_t value, int32_t fieldWidth = 1);
+RUNTIME_EXPORT std::wstring ToStr(uint16_t value, int32_t fieldWidth = 1);
+RUNTIME_EXPORT std::wstring ToStr(int32_t value, int32_t fieldWidth = 1);
+RUNTIME_EXPORT std::wstring ToStr(uint32_t value, int32_t fieldWidth = 1);
+RUNTIME_EXPORT std::wstring ToStr(float value, int32_t precision = 6);
+RUNTIME_EXPORT std::wstring ToStr(double_t value, int32_t precision = 6);
+RUNTIME_EXPORT std::wstring ToStr(const char* value);
+inline 		   std::wstring ToStr(const wchar_t* value)					{return value;}
+RUNTIME_EXPORT std::wstring ToStr(const std::string& value);
+inline 		   std::wstring ToStr(const std::wstring& value)			{return value;}
+
+
+#ifdef _DEBUG
+	#define	DEBUG					1
+#else		
+	#define	DEBUG					0
+	
+	#if	!defined(NDEBUG)
+		#define	NDEBUG							// used by <assert.h>
+	#endif
+#endif
+
+#ifndef ASSERTS_THROW
+#define ASSERTS_THROW				0			
+#endif
+// #define ASSERTS_THROW               1
+// Synch with ANSI definitions.
+#if DEBUG && defined(NDEBUG)
+	#error DEBUG and NDEBUG are out of sync!
+#endif
+
+#if !DEBUG && !defined(NDEBUG)
+	#error DEBUG and NDEBUG are out of sync!
+#endif
+
+// Synch with MSVC.
+#if _MSC_VER && DEBUG != defined(_DEBUG)
+	#error DEBUG and _DEBUG are out of sync!
+#endif
+
+#ifndef _lint
+	#define COMPILE_CHECK(p)	{struct _CC {char a[(p) ? 1 : -1];};} (void) 0
+#else
+	#define COMPILE_CHECK(p)					
+#endif
+
+#if DEBUG
+	
+	void AssertFailed(const char* expr, const char* file, int line);
+	
+	#undef assert
+
+	#define ASSERT(p)					do {if (!(p)) AssertFailed(#p, __FILE__, __LINE__);} while (false)
+
+	#define ASSERT_IF(p, x)				do {if ((p) && !(x)) AssertFailed(#x, __FILE__, __LINE__);} while (false)
+	#define assert(p) 					ASSERT(p)
+	#define VERIFY(p)					ASSERT(p)
+	#define REQUIRE(p)					ASSERT(p)
+
+	#define	PRECONDITION(p)				ASSERT(p)
+	#define	POSTCONDITION(p)			ASSERT(p)
+
+    #ifdef NO_NESTED_QUOTES
+          #define PRECONDITION2(a,b)	ASSERT(a)
+          #define POSTCONDITION2(a,b)	ASSERT(a)
+    #else
+          #define PRECONDITION2(a,b)	ASSERT((b, (a) !=0))
+          #define POSTCONDITION2(a,b)	ASSERT((b, (a) !=0))
+    #endif
+
+#else	// #if DEBUG
+
+
+	#if ASSERTS_THROW
+		void AssertFailed(const char*, const char*, int);
+
+		#define ASSERT(p)				do {if (!(p)) AssertFailed(#p, __FILE__, __LINE__);} while (false)
+
+		#define ASSERT_IF(p, x)			do {if ((p) && !(x)) AssertFailed(#x, __FILE__, __LINE__);} while (false)
+		#define VERIFY(p)				ASSERT(p)
+
+		#define	PRECONDITION(p)			ASSERT(p)
+		#define	POSTCONDITION(p)		ASSERT(p)
+
+        #define PRECONDITION2(a,b)	    ASSERT(a)
+        #define POSTCONDITION2(a,b)	    ASSERT(a)
+	#else
+		#define	ASSERT(p)				((void) 0)
+
+		#define	ASSERT_IF(p, x)			((void) 0)
+		#define VERIFY(p)				do {if (p) 0;} while (false)
+
+		#define	PRECONDITION(p)			((void) 0)
+		#define	POSTCONDITION(p)		((void) 0)
+
+        #define PRECONDITION2(a,b)
+        #define POSTCONDITION2(a,b)
+	#endif
+
+	void RequireFailed(const char*, const char*, int);
+	
+	#define REQUIRE(p)					do {if (!(p)) RequireFailed(#p, __FILE__, __LINE__);} while (false)
+
+
+#endif	// DEBUG
+
+#ifdef _CONSOLE
+#define TRACE
+#endif
+	
+
+
+#endif /* __DEBUG_H__ */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Fdt.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Fdt.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Fdt.cpp	(revision 10506)
@@ -0,0 +1,536 @@
+/**********************************************************************
+ *
+ * Fdt.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+///////////////////////////////////////////////////////////////////////////
+//  fdt.cpp
+
+#include "stdafx.h"
+#include "Fdt.h"
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <sstream>
+#include <stdio.h>
+
+//////////////////////////////
+ 
+CFdt::CFdt()   
+// Constructor
+{
+   InitData();
+   InitFields();
+}
+
+//////////////////////////////
+
+CFdt::~CFdt()
+{
+	for (int i = 0; i < m_nFieldCount; i++)
+	{
+#ifndef _WIN32
+		CFieldDef* p = (CFieldDef*) m_fieldArray[i];
+#else
+		CFieldDef* p = (CFieldDef*) m_fieldArray.at(i);
+#endif
+    	delete p;
+	}
+	m_fieldArray.clear();
+
+	Close();
+}
+
+////////////////////////////
+
+bool CFdt::Open(const _TCHAR *szFileName, bool readOnly)
+{
+	if (!m_bIsEmpty)
+		Close();
+	m_sFileName = szFileName;
+	if (!Load(szFileName))
+	{
+		Close();
+		return false;
+	}
+
+	m_bReadOnly = readOnly;
+	return Seek(0);   // 
+}
+
+
+
+
+//////////////////////////////
+
+void CFdt::InitData()
+{
+   m_iCurrentRecord = -1;
+   m_sFileName.erase();
+   
+   m_bReadOnly = false;
+   m_bIsEmpty  = true;
+   m_fdtEntry.Clear();
+   m_bDirty    = false;
+   m_aFdt.clear();
+   m_asPrelude.clear();
+   // Suppose the fdt is empty and we are 
+   // going to append 
+   m_bAppend = true;
+}
+
+//////////////////////////////
+
+void CFdt::Close()
+{
+	if (!m_bIsEmpty)
+		DeleteContents();
+
+    InitData();        // Reset data members   
+	m_bIsEmpty = true;
+}
+
+////////////////////////////////////
+ 
+void CFdt::DeleteContents()
+// Delete the fdt data structures
+{
+    m_aFdt.clear();
+  
+}
+
+
+
+bool CFdt::Load(const _TCHAR *dbaseName)
+{
+	std::ifstream in((const char*)dbaseName);
+	if (!in)
+    {
+//#ifdef _WIN32
+//	   CString strMsg;
+//		strMsg.Format(_T("Error opening %s for reading. "), dbaseName);
+//		AfxMessageBox(strMsg, MB_OK | MB_ICONEXCLAMATION);
+//#else
+		std::cout << _T("Error opening") << dbaseName << _T("for reading") << std::endl;
+//#endif
+		return false;
+    }
+
+
+	std::string s;
+
+    while (std::getline(in,s) && s.substr(0,3) != "***")
+    {
+		m_asPrelude.push_back(s);
+    }
+
+    while (std::getline(in,s))
+    {
+        CFdtEntry e;
+        strncpy(e.name, s.c_str(), FDT_NAME_LENG);
+	    e.name[FDT_NAME_LENG] = _T('\0');
+	    for (int i=FDT_NAME_LENG-1; e.name[i]==_T(' '); e.name[i--]=_T('\0'))
+		   ;
+        if (s[FDT_NAME_LENG] == _T(' '))        //no subfield delimiters spec.
+		 	e.subfields[0] = _T('\0');
+	    else
+		{
+		 	strncpy(e.subfields, s.c_str()+FDT_NAME_LENG, FDT_SFLD_LENG);
+			e.subfields[FDT_SFLD_LENG] = _T('\0');
+			for (int i= FDT_SFLD_LENG-1; e.subfields[i]==_T(' '); e.subfields[i--]='\0')
+				 ;
+		}
+	    sscanf(s.c_str() + FDT_NAME_LENG + FDT_SFLD_LENG, "%d %d %d %d",
+										  &e.tag, &e.len, &e.type, &e.rep);
+	    m_aFdt.push_back(e);
+    }
+    in.close();
+    return true;
+}
+
+		
+		
+		
+
+
+// Define the fields used for the dictionary
+
+static CFieldDef fdtFields[7] =  { 
+   {"Name",       'C', 30, 30, 0, 0, 30},
+   {"Subfields",  'C', 20, 20, 0, 30, 20},
+   {"Tag",        'N', 4, 4, 0,50, 4},
+   {"Len",        'N', 4, 4, 0,54, 4},
+   {"Type",       'N', 1, 1, 0,58, 4},
+   {"Rep",        'C', 1, 1, 0,62, 4},
+   {0,             0, 0, 0, 0, 0, 0}
+}; 
+
+
+
+
+
+
+//+----------------------------------------------------------------
+//
+// Member:     Store(const char* fileName)
+//
+// Synopsis:   Store dictionary tables on a file
+//
+// Parameters: 
+//
+//     fileName -- Full path of dictionary file
+// 
+//-----------------------------------------------------------------   
+
+void FormatFdtEntry(CFdtEntry &e, ustring &s)
+{
+#ifdef _WIN32
+	ustringstream ost;
+
+	ost.setf(std::ios_base::left, std::ios_base::adjustfield);
+	ost << std::setw(30) << e.name << std::setw(20) << e.subfields;
+	ost.setf(std::ios_base::internal,std::ios_base::adjustfield);
+	ost << " " << e.tag << " " << e.len << " " << e.type << " " << e.rep;
+	s = ost.str();
+#endif
+}
+
+void CFdt::Store(const char* fileName)
+{
+	if (m_bDirty)
+	{
+		Flush();
+		m_bDirty = false;
+	}
+
+	std::ofstream out((const char *) fileName);
+	TRACE(_T("\n<CFdt::Store> fileName=%s"),fileName);
+	for (int i=0; i<m_asPrelude.size(); i++)
+		out << m_asPrelude[i] << std::endl;
+	
+	out << "***" << std::endl;
+
+	ustring s;
+#ifdef _WIN32
+	for (i=0; i< m_aFdt.size(); i++)
+#else
+	for (int i=0; i< m_aFdt.size(); i++)
+#endif
+	{
+		FormatFdtEntry(m_aFdt[i], s);
+		out << s << std::endl;
+	}
+    out.close();
+
+}
+
+//////////////////////////////
+
+int CFdt::InitFields ()
+{
+	m_nFieldCount = 0;
+
+	for (int i = 0; fdtFields[i].width != 0; i++)
+	{
+		CFieldDef* fld = (CFieldDef*) new CFieldDef();
+		//TRACE("\n<CFdt::InitFields>i=%d after new",i);
+		//TRACE("<CFdt::InitFields>After SetAtGrow");
+		strcpy(fld->name, fdtFields[i].name);
+		fld->type          = fdtFields[i].type;
+		fld->len           = fdtFields[i].len;
+		fld->width         = fdtFields[i].width;
+		fld->decimals      = fdtFields[i].decimals;
+		fld->offset        = fdtFields[i].offset;
+		fld->display_width = fdtFields[i].display_width;
+
+		int l = strlen(fld->name);
+		if (fld->width < l)
+			fld->width = static_cast<short>(l);
+
+		m_fieldArray.push_back(fld);
+		m_nFieldCount++;
+	}
+	//TRACE("\n<CFdt::InitFields>InitField After loop");
+	return 1;
+}
+
+////////////////////////////////////////////////////////////////////
+
+CFieldDef* CFdt::GetField(int n) const
+// Returns field info
+{
+	ASSERT(n >= 0 && n <= m_nFieldCount);
+#ifndef _WIN32
+	return (CFieldDef*) m_fieldArray[n];
+#else
+	return (CFieldDef*) m_fieldArray.at(n);
+#endif
+}
+
+/////////////////////////////////////////////////////////////////////
+// Methods for accessing and maintaining the list of CDictTRecords 
+// pointers
+
+////////////////////////////
+// First the List Accessors
+////////////////////////////
+
+CFdtEntry CFdt::GetAt(int i)
+{
+#ifndef _WIN32
+	return m_aFdt[i];
+#else
+	return m_aFdt.at(i);
+#endif
+
+}
+
+
+//////////////////////////
+
+const CFdtEntry CFdt::GetAt(int i) const
+{
+#ifndef _WIN32
+	return m_aFdt[i];
+#else
+	return m_aFdt.at(i);
+#endif
+}
+
+//////////////////////////
+// And now the modifiers
+//////////////////////////
+
+int CFdt::Append(CFdtEntry& e)
+{
+	int n = m_aFdt.size();
+	m_aFdt.push_back(e);
+    m_iCurrentRecord = -1;
+    m_bIsEmpty = false;
+
+    return m_aFdt.size();
+}
+
+
+/**-------------------------------------------------------------------
+ * RemoveAt(int i)
+ *
+ *--------------------------------------------------------------------
+ */
+void CFdt::RemoveAt(int i)
+{
+
+	m_aFdt.erase(m_aFdt.begin()+i);
+    m_iCurrentRecord = -1;
+}
+
+/**-------------------------------------------------------------------
+ * SetAt(int i, CFdtEntry& e)
+ *
+ *--------------------------------------------------------------------
+ */
+void CFdt::SetAt(int i, CFdtEntry& e)
+{
+
+	m_aFdt[i] = e;
+	// Force reloading
+    m_iCurrentRecord = -1;
+}
+
+/////////////////////////////////////////////////////////////////
+// 
+// We use a buffer "m_fdtEntry" to hold the content of the current
+// fdt entry. This buffer is filled by the "Seek" member function
+// as follow:
+//
+
+//////////////////////////////
+
+bool CFdt::Seek(long iRecord)
+{
+
+	// move to new record and flush changes of previous record
+	if (iRecord < 0 || iRecord > GetRecordCount())
+		return false;
+	else if (iRecord == m_iCurrentRecord)
+		return true;
+
+	if (m_iCurrentRecord != -1 &&  m_bDirty)
+		Flush();
+	if (m_bDirty)
+	   /*AfxMessageBox(_T("Seek Alert Modification not saved"))*/;
+	m_iCurrentRecord = iRecord;
+	
+	if (iRecord == GetRecordCount())
+	{
+		m_fdtEntry.Clear();
+        m_bAppend = true;
+	}
+	else
+	{
+		TRACE(_T("\n<CFdt::Seek> Load iRecord=%d GetRecordCount()=%d"), iRecord, GetRecordCount());
+		m_fdtEntry = GetAt(iRecord);
+		m_bAppend = false;
+	}
+    m_bDirty = false;
+	return true;
+}
+
+
+
+//+------------------------------------------------------------------
+//
+// Member:   Flush()
+//
+// Synopsis: Moves the changes made to the current record from
+//           the buffer to the dictionary data structure so that
+//           they are effective.
+//-------------------------------------------------------------------    
+
+void CFdt::Flush()
+{
+	if (m_iCurrentRecord == GetRecordCount())
+	{
+		Append(m_fdtEntry); 
+	}
+	else
+	{
+		SetAt(m_iCurrentRecord, m_fdtEntry);
+	}
+	m_bDirty = false;
+}
+
+//////////////////////////////////////////////////////////////
+// Get the value of field n for the current record
+//
+
+bool CFdt::GetValue(int n, std::string& result) 
+// Read value from buffer
+{
+	ASSERT(n >= 0 && n <= m_nFieldCount);
+    ASSERT(m_iCurrentRecord >= 0 && m_iCurrentRecord <= GetRecordCount());
+	
+	if (!(n >= 0 && n <= m_nFieldCount))
+		return false;
+
+	result.erase();
+
+	std::ostringstream os;
+    switch (n)
+	{
+	    case 0:       // Field Name
+			os << m_fdtEntry.name;
+			result = os.str();
+		    break;
+	    case 1:       // Subfields
+			os << m_fdtEntry.subfields;
+			result = os.str();
+		    break;
+	    case 2:       // Tag
+		  	if (m_fdtEntry.tag == 0)
+				result = "";
+			else
+			{
+			    os << m_fdtEntry.tag;
+			    result = os.str();
+			}
+		    break;
+	    case 3:       // length
+		  	if (m_fdtEntry.len == 0)
+				result = "";
+			else
+			{
+			    os << m_fdtEntry.len;
+			    result = os.str();
+			}
+		    break;
+	    case 4:       // type
+		  	if (m_fdtEntry.type == 0)
+				result = "";
+			else
+			{
+			    os << m_fdtEntry.type;
+			    result = os.str();
+			}
+		    break;
+	    case 5:       // Rep
+		  	if (m_fdtEntry.rep == 0)
+				result = "";
+			else
+			{
+			    os << m_fdtEntry.rep;
+			    result = os.str();
+			}
+		    break;
+	}
+	return true;
+}
+
+
+//////////////////////////////
+
+bool CFdt::SetValue(int n, const char* pszValue)
+// Write value to buffer
+{
+	ASSERT(n >= 0 && n <= m_nFieldCount);
+    ASSERT(m_iCurrentRecord >= 0 && m_iCurrentRecord <= GetRecordCount());
+
+	if (m_bReadOnly)
+		return false;
+
+	if (!(n >= 0 && n <= m_nFieldCount))
+		return false;
+
+    bool bEmpty = true;
+
+
+	switch (n) 
+	{
+	case 0:       // Name
+		strcpy(m_fdtEntry.name,(const char*)pszValue);
+	//	TRACE("\nvalue=%s num=%d",pszValue,m_tRecord.num);
+		break;
+	case 1:       // Subfields
+		strcpy(m_fdtEntry.subfields,(const char*)pszValue);
+	//	TRACE("\nvalue=%s name=%d",pszValue,m_tRecord.name);
+		break;
+	case 2:       // Tag
+		m_fdtEntry.tag = _ttoi(pszValue);
+	//	TRACE("\nvalue=%s loc=%d",pszValue,m_tRecord.loc);
+		break;
+	case 3:       // Len
+		m_fdtEntry.len = _ttoi(pszValue);
+	//	TRACE("\nvalue=%s wid=%d",pszValue,m_tRecord.wid);
+		break;
+	case 4:       // Type
+		m_fdtEntry.type = _ttoi(pszValue);
+		break;
+	case 5:       // Rep
+		m_fdtEntry.type = _ttoi(pszValue);
+		break;
+	}
+	m_bDirty = true;
+	
+	return true;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Fdt.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Fdt.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Fdt.h	(revision 10506)
@@ -0,0 +1,172 @@
+/**********************************************************************
+ *
+ * Fdt.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////////////////////////////
+// Fdt.h
+
+#ifndef __FDT_H__
+#define __FDT_H__
+
+#include <vector>
+#include "mytchar.h"
+
+#define FDT_NAME_LENG    30     // maximum name length in FDT_FILE
+#define FDT_SFLD_LENG    20    // maximum subfield length in FDT_FILE
+
+#ifndef __CFIELDDEF__
+#define __CFIELDDEF__
+
+class CFieldDef
+{
+public:
+	enum FieldType {
+		charField       = 'C',
+		dateField       = 'D',
+		numericField    = 'N',
+		logicalField    = 'L',
+		memoField       = 'M'
+	};
+
+	char  name[31];   // dbf field names are 10 chars long max.
+		// If this application is compiled with _UNICODE switch,
+		// the field name will be converted to wide chars
+		// when the column header is displayed in the grid.
+	char  type;
+	short len;
+	short width;
+	short decimals;
+	int   offset;
+	short display_width;
+};
+#endif // __CFIELDDEF__
+
+
+
+class CFdtEntry
+{
+public:
+	CFdtEntry() :  tag(0), len(0), type(0), rep(0) 
+	{ name[0] = '\0'; subfields[0] = '\0'; }
+    void Clear()
+	{
+		tag = len = type = rep = 0;
+        name[0] = '\0'; subfields[0] = '\0';
+	}
+    char    name[FDT_NAME_LENG+1];
+    char    subfields[FDT_SFLD_LENG+1];
+    int      tag;
+    int      len;
+    int      type;     //X=0
+    int      rep;      //repeatable 1, non rep. 0
+   CFdtEntry& operator=(const CFdtEntry& rhs)
+   {
+	   if (&name[0] != &rhs.name[0])
+	   {
+		   Copy(rhs);
+	   }
+	   return *this;
+   }
+
+   void Copy(const CFdtEntry &rhs)
+   {
+	   strcpy(name, rhs.name);
+	   strcpy(subfields, rhs.subfields);
+	   tag  = rhs.tag;
+	   len  = rhs.len;
+	   type = rhs.type;
+	   rep  = rhs.rep;
+   }
+};
+
+
+void FormatFdtEntry(CFdtEntry &e, ustring &s);
+
+
+
+class CFdt
+{
+protected:
+	std::vector<CFdtEntry>  m_aFdt;
+    int                     m_nFieldCount;       // Num. of fields
+	std::vector<CFieldDef*> m_fieldArray;        // Array with fields
+
+	long        m_iCurrentRecord;    // Current read record stored in
+	CFdtEntry   m_fdtEntry;
+	bool        m_bReadOnly;
+	bool        m_bIsEmpty;
+	bool        m_bDirty;            // True if m_fdtEntry modified 
+	bool        m_bAppend;
+public:
+	ustring  m_sFileName;              // Fdt full pathname
+	std::vector<std::string> m_asPrelude;  // What is bef ***
+public:
+	CFdt();          
+	virtual ~CFdt();
+
+	bool      Load(const _TCHAR *fname);
+	int       GetEntryCount() { return m_aFdt.size(); }
+
+	CFdtEntry GetEntryAt(int i) 
+	{ 
+      #ifdef _WIN32
+	     return m_aFdt.at(i); 
+      #else
+	     return m_aFdt[i];
+      #endif
+	}
+
+	int       GetFieldCount() { return  m_nFieldCount; }
+
+    bool      Open(const char* szFileName, bool readOnly=true);
+
+    void InitData();
+
+    void Close();
+ 
+    void DeleteContents();
+
+    void Store(const char* fileName);
+    int InitFields ();
+
+    CFieldDef* GetField(int n) const;
+
+    CFdtEntry GetAt(int i);
+
+    const CFdtEntry GetAt(int i) const;
+
+    int Append(CFdtEntry& e);
+
+    void RemoveAt(int i);
+    void SetAt(int i, CFdtEntry& e);
+
+    bool Seek(long iRecord);
+    void Flush();
+    bool GetValue(int n, std::string& result);
+    bool SetValue(int n, const char* pszValue);
+
+	int GetRecordCount() { return m_aFdt.size(); }
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/File.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/File.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/File.cpp	(revision 10506)
@@ -0,0 +1,618 @@
+/**********************************************************************
+ *
+ * File.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////
+// File.cpp   File object methods
+////////////////////////////////////////////////////////////
+#include "stdafx.h"
+
+ 
+#include <assert.h>
+#include "CRC32.h"
+#include "File.h"
+
+
+
+
+static TCHAR closed_file_name[] = _T("closed-file");
+
+static const int MaxExceptionMessages = 34;
+static const TCHAR *fileExceptionMsg[MaxExceptionMessages] =
+{
+  _T("File exception: No exception reported"),               // FILE_NO_ERROR
+  _T("File exception: Checksum error"),                      // FILE_CHECKSUM_ERROR
+  _T("File exception: Error closing file"),                  // FILE_CLOSE_ERROR
+  _T("File exception: File is corrupted"),
+  _T("File exception: Error creating file"),                 // FILE_CREATION_ERROR
+  _T("File exception: File already exists"),                 // FILE_EXISTS
+  _T("File exception: Trying to use a closed file"),         // FILE_NOT_OPEN_ERROR
+  _T("File exception: File not ready for reading/writing"),  // FILE_NOT_READY
+  _T("File exception: Could not write to file"),             // FILE_NOT_WRITEABLE
+  _T("File exception: Error opening file"),                  // FILE_OPEN_ERROR
+  _T("File exception: Cannot obtain a file position"),       // FILE_POSITION_ERROR
+  _T("File exception: Error reading from file"),             // FILE_READ_ERROR
+  _T("File exception: Error seeking in file"),               // FILE_SEEK_ERROR
+  _T("File exception: Error writing to file"),               // FILE_WRITE_ERROR
+
+  _T("Fmgr exception: No database open"),                    // FMGR_NO_DATABASE_OPEN
+  _T("Fmgr exception: No such file exists"),                 // FMGR_NO_FILE_EXISTS
+  _T("Fmgr exception: No objects exist"),                    // FMGR_NO_OBJECTS_EXIST
+  _T("Fmgr exception: Accessing a null pointer"),            // FMGR_NULL_PTR
+  _T("Fmgr exception: Object already exists"),               // FMGR_OBJECT_EXISTS
+  _T("Fmgr exception: Another object is referencing this file"), // FMGR_OBJECT_EXISTS
+  _T("Fmgr exception: Math overflow error"),                 // FMGR_OVERFLOW
+  _T("Fmgr exception: Parse error"),                         // FMGR_PARSE_ERROR
+  _T("Fmgr exception: Invalid path"),                        // FMGR_PATH_ERROR
+  _T("Fmgr exception: Trying to write to a read-only file"), // FMGR_READ_ONLY_FILE
+  _T("Fmgr exception: Stack empty"),                         // FMGR_STACK_EMPTY
+  _T("Fmgr exception: Stack full"),                          // FMGR_STACK_FULL
+  _T("Fmgr exception: Synchronization Error"),               // FMGR_SYNC_ERROR    
+  _T("Fmgr exception: Math under-flow error"),               // FMGR_UNDERFLOW
+  _T("Fmgr exception: Wrong file type"),                     // FMGR_WRONG_FILE_TYPE
+  
+  // Persistent lock error messages
+  _T("Fmgr exception: Invalid lock type specified"),          // FMGR_INVALID_LOCK_TYPE
+  _T("Fmgr exception: Cannot access the file lock header"),   // FMGR_FILELOCK_ACCESS_ERROR
+  _T("Fmgr exception: Cannot lock the file"),                 // FMGR_FILELOCK_ERROR
+  _T("Fmgr exception: Cannot access the record lock header"), // FMGR_RECORDLOCK_ACCESS_ERROR
+  _T("Fmgr exception: Cannot lock the specified record")      // FMGR_RECORDLOCK_ERROR
+};
+ 
+//---------------------------------------------------------------------------
+// CFileBase::CFileBase()
+//
+// Default constructor, makes a File object that isn't attached to a file
+//--------------------------------------------------------------------------- 
+CFileBase::CFileBase()
+{
+    _tcscpy(file_name, closed_file_name); // Set the initial file name
+    fp = 0;
+
+    // Reset the last reported error and the file status members
+    file_error        = FILE_NO_ERROR;
+    is_open           = 0;
+    is_ok             = 0;
+    ready_for_reading = 0;
+    ready_for_writing = 0;
+}
+  
+//---------------------------------------------------------------------------
+// CFileBase::~CFileBase()
+//
+// Destructor for CFileBase file object
+//--------------------------------------------------------------------------- 
+CFileBase::~CFileBase()
+{
+	Close();
+}
+
+//---------------------------------------------------------------------------
+// const char* CFileBase::FileExceptionMessage()
+//
+// Returns a null terminated string that can / be used to log or print a
+// file exception.
+//---------------------------------------------------------------------------
+const TCHAR *CFileBase::FileExceptionMessage()
+{
+	assert(file_error<MaxExceptionMessages);
+    return fileExceptionMsg[file_error];
+}
+ 
+//--------------------------------------------------------------------------------
+// int Create(const char* fname)
+//
+// Creates a new file, truncate the file if it already exists. The file open for
+// Read/Write access. 
+// Returns a non-zero value to indicate an error condition or zero if successful.
+//--------------------------------------------------------------------------------
+FileError CFileBase::Create(const TCHAR *fname)
+{
+    // Close any open files 
+    if (Close() != FILE_NO_ERROR) 
+		return file_error;
+	
+    // Create and truncate existing files
+    fp = FileSystem::Create(fname);
+	
+    if (fp == 0)
+	{
+		is_ok             = 0;
+		is_open           = 0;
+		ready_for_writing = 0;
+		ready_for_reading = 0;
+		file_error        = FILE_CREATION_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+		throw CFileBaseException(file_error);
+#else
+		return file_error;
+#endif
+	}
+	else
+	{
+		is_open           = 1;
+		is_ok             = 1;
+		ready_for_writing = 1;
+		ready_for_reading = 1;
+		last_operation    = IO_READ;
+		_tcscpy(file_name, fname);
+	}
+	
+	// Returns 0 if the file was successfully created and opened.
+	return file_error = FILE_NO_ERROR; 
+}
+ 
+//----------------------------------------------------------------------------------------
+// FileError CFileBase::Open(const TCHAR *fname, FileSystem::AccessMode mode
+//                                               /* = FileSystem::FILE_READWRITE */ )
+//
+// Open an existing file. The "mode" variable determines if the file is opened for
+// read only or read/write access.  Returns a non-zero value to indicate an error
+// condition or zero if successful.
+// NOTE: This version of the open functions will only accept:
+// FILE_READONLY and FILE_READWRITE access modes.
+//---------------------------------------------------------------------------------------
+FileError CFileBase::Open(const TCHAR *fname, FileSystem::AccessMode mode /* = FileSystem::FILE_READWRITE */)
+{
+	// Close any open files
+	if (Close() != FILE_NO_ERROR) 
+		return file_error;
+	
+	if (mode == FileSystem::FILE_READONLY)
+	{   // Open with read only access
+		ready_for_reading = 1;
+		ready_for_writing = 0;
+		fp = FileSystem::Open(fname, FileSystem::FILE_READONLY);
+	}
+	else
+	{   // Open with read/write access
+		ready_for_reading = 1;
+		ready_for_writing = 1;
+		fp = FileSystem::Open(fname, FileSystem::FILE_READWRITE);
+	}
+    
+	if (fp == 0)
+	{
+		ready_for_reading = 0;
+		ready_for_writing = 0;
+		file_error        = FILE_OPEN_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+		throw CFileBaseException(file_error);
+#else
+		return file_error;
+#endif
+	}
+	else
+	{
+		is_open         = 1;
+		is_ok           = 1;
+		last_operation  = IO_WRITE;
+		_tcscpy(file_name, fname);
+	}
+	return file_error = FILE_NO_ERROR;
+}
+ 
+//--------------------------------------------------------------------------------
+// void CFileBase::Close()
+//
+// Close the open database file. Returns a non-zero value
+// to indicate an error condition or zero if successful.
+//--------------------------------------------------------------------------------
+FileError CFileBase::Close()
+{
+   if (IsOpen()) 
+   {
+       if (FileSystem::Close(fp) != 0) 
+	   {
+		   file_error = FILE_CLOSE_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+		   throw CFileBaseException(file_error);
+#else
+		   return file_error;
+#endif
+	   }
+       _tcscpy(file_name, closed_file_name); // Set the initial file name
+   }
+
+   is_open           = 0;
+   is_ok             = 0;
+   ready_for_reading = 0;
+   ready_for_writing = 0;
+   fp                = 0; // Reset the file pointer to zero after the file is closed
+
+   return file_error = FILE_NO_ERROR; 
+}
+
+//----------------------------------------------------------------------------------
+// FileError CFileBase::Seek(FAU offset, FileSystem::SeekMode mode)
+//
+// Seek to the specified offset starting at the beginning (SEEK_SET), end (SEEK_END)
+// or current offset (SEEK_CUR). Returns a non-zero value to indicate an error
+// condition or zero if successful.
+//----------------------------------------------------------------------------------
+FileError CFileBase::Seek(FileSystem::FAU_t offset, FileSystem::SeekMode mode)
+{
+	if (IsOK()) 
+	{
+		if (FileSystem::Seek(fp, offset, mode) == (isis::int32_t) - 1)
+		{
+			file_error = FILE_SEEK_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+			throw CFileBaseException(file_error);
+#else
+			return file_error;
+#endif
+		}
+		last_operation = IO_SEEK;
+	}
+	else 
+	{
+		file_error = FILE_NOT_READY;
+#ifdef __CPP_EXCEPTIONS__
+		throw CFileBaseException(file_error);
+#else
+		return file_error;
+#endif
+	}
+	return file_error = FILE_NO_ERROR;
+}
+
+//----------------------------------------------------------------------------------
+// FAU CFileBase::SeekTo(FileSystem::FAU_t file_address)
+//
+// Seek to the specified address, optimizing the seek operation by moving the 
+// file position indicator based on the current stream position. Returns the
+// current file position after performing the seek operation.
+//----------------------------------------------------------------------------------
+FileSystem::FAU_t CFileBase::SeekTo(FileSystem::FAU_t file_address)
+{
+	// Get the current stream position
+	FileSystem::StreamPos pos = FilePosition();
+	
+	if (file_address == CURRADDR) 
+	{   // Do not perform a seek operation
+		return pos;
+	}
+	else if (file_address > pos)
+	{   // Seek forward to the specified address
+		FileSystem::StreamPos offset = file_address - pos;
+		Seek(offset, FileSystem::FILE_SEEK_CUR);
+	}
+	else if (file_address < pos) 
+	{   // Seek backward to the specified address
+		Seek(file_address, FileSystem::FILE_SEEK_BEG);
+	}
+	else 
+	{  // Current file position equals the specified address
+		// Find current the position
+		Seek((FileSystem::FAU_t)0, FileSystem::FILE_SEEK_CUR);
+	}
+	
+	return FilePosition(); // Return current file position after seeking
+}
+
+//-------------------------------------------------------------------------------
+// FileError Store(const void* buf, isis::uint32_t nBytes,
+//                             FAU file_addres = CFileBase::CURRADDR,
+//			                   int flush = 1, int bit_test = 1);
+//
+// Write a specific number of bytes from a memory buffer to a specified file
+// offset. If the "flush" variable is true, the file buffers will be flushed to
+// disk with each write operation. If the bit_test variable if true, the CRC of 
+// the buffer will be compared to the CRC of the actual bytes written to disk.
+// Returns a non-zero value to indicate an error condition or zero if successful.
+//
+// void* buf         - Pointer to the user-supplied buffer that is to receive
+//                     the data read from the file.
+// isis::uint32_t nBytes - The maximum number of bytes to be read from the 
+//                     file.  Note that an CFileBase is always a binary file,
+//                     so a CR/LF pair will always be read or written as two bytes.
+// FAU file_address  - The file byte address. The address is always interpreted to 
+//                     be from the beginning of the file, unless dwAddr is equal 
+//                     to CURRADDR, which means from the current position.
+//------------------------------------------------------------------------------- 
+FileError CFileBase::Store(const void* buf, isis::uint32_t nBytes,
+						   FileSystem::FAU_t file_address /*= CURRADDR */, 
+						   int flush_flag /* = 1 */,
+						   int bit_test /* = 1 */)
+{
+    FileSystem::FAU_t buf_address;
+	
+    if (ReadyForWriting())
+	{
+        if (file_address == CURRADDR)
+		{
+			if (last_operation == IO_READ)
+			{
+				if (Seek(0, FileSystem::FILE_SEEK_CUR) != FILE_NO_ERROR)
+					return file_error;
+			}
+		}
+        else
+		{
+			if (Seek(file_address, FileSystem::FILE_SEEK_BEG) != FILE_NO_ERROR)
+				return file_error;
+		}
+		
+        buf_address = FilePosition(); 
+		
+        if (file_error != FILE_NO_ERROR)
+			return file_error;
+		
+        if (FileSystem::Write(fp, buf, nBytes) != nBytes)
+		{
+			file_error = FILE_WRITE_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+			throw CFileBaseException(file_error);
+#else
+			return file_error;
+#endif
+		}
+        last_operation = IO_WRITE;
+	}
+    else
+	{
+        file_error = FILE_NOT_WRITEABLE;
+#ifdef __CPP_EXCEPTIONS__
+        throw CFileBaseException(file_error);
+#else
+        return file_error;
+#endif
+	} 
+	
+    // Allow application to flush disk buffers after each write
+    // operation to ensure the file data stays in sync during multiple
+    // file access.
+    if (flush_flag)
+	{  
+		if (FileSystem::Flush(fp) != FILE_NO_ERROR)
+		{
+			file_error = FILE_WRITE_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+			throw CFileBaseException(file_error);
+#else
+			return file_error;
+#endif
+		}
+        if (Seek(0, FileSystem::FILE_SEEK_CUR) != FILE_NO_ERROR)
+			return file_error;
+	}
+	
+    if (bit_test) 
+	{
+        isis::uint32_t w_csum = CalcCRC32((char* ) buf, nBytes);
+        isis::uint32_t r_csum = CalcChecksum(nBytes, buf_address);
+		
+		// Check for file errors
+		
+		if (file_error != FILE_NO_ERROR)
+			return file_error;
+		
+		if (w_csum ^ r_csum)
+		{
+			file_error = FILE_CHECKSUM_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+			throw CFileBaseException(file_error);
+#else
+			return file_error;
+#endif
+		}
+	}
+	return file_error = FILE_NO_ERROR;	
+}
+ 
+//-------------------------------------------------------------------------------
+// FileError CFileBase::Fetch(void* buf, isis::uint32_t nBytes, FAU file_addres
+//                                                  /* = CFileBase::CURRADDR */)
+//
+// Read a specified number of bytes from the specified file offset into a memory
+// buffer. Returns a non-zero value to indicate an error condition or zero if
+// successful.
+// void* buf         - Pointer to the user-supplied buffer that is to receive
+//                     the data read from the file.
+// isis::uint32_t nBytes - The maximum number of bytes to be read from the file. 
+//                     Note that an CFileBase is always a binary file, so a 
+//                     CR/LF pair will always be read or written as two bytes.
+// FAU file_addres   - The file byte address. The address is always interpreted 
+//                     to be from the beginning of the file, unless dwAddr is 
+//                     equal to CURRADDR, which means from the current position.
+//------------------------------------------------------------------------------- 
+FileError CFileBase::Fetch(void* buf, isis::uint32_t nBytes, 
+						   FileSystem::FAU_t file_address /* = CFileBase::CURRADDR */)
+{
+    if (IsOK())
+	{
+        if (file_address == CURRADDR)
+		{
+            if (last_operation == IO_WRITE)
+			{
+	           if (Seek(0, FileSystem::FILE_SEEK_CUR) != FILE_NO_ERROR) 
+				   return file_error;
+			}
+		}
+        else
+		{
+            if (Seek(file_address, FileSystem::FILE_SEEK_BEG) != FILE_NO_ERROR)
+              	return file_error;
+		}
+
+		//TRACE("\nFetchfile_address=%ld nBytes=%u",file_address, nBytes);
+        if (FileSystem::Read(fp, buf, nBytes) != nBytes)
+		{
+            file_error = FILE_READ_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+            throw CFileBaseException(file_error);
+#else
+            return file_error;
+#endif
+		}
+        last_operation = IO_READ;
+	}
+    else 
+	{
+        file_error = FILE_NOT_READY;
+#ifdef __CPP_EXCEPTIONS__
+        throw CFileBaseException(file_error);
+#else
+        return file_error;
+#endif
+	}
+
+    return file_error = FILE_NO_ERROR;
+}
+//------------------------------------------------------------------------------- 
+// FileError Flush()
+//
+// Flush any open disk buffers. Returns a non-zero value to indicate an error
+// condition or zero if successful.
+//------------------------------------------------------------------------------- 
+FileError CFileBase::Flush()
+{
+	PRECONDITION(ReadyForWriting());
+	if (FileSystem::Flush(fp) != FILE_NO_ERROR)
+	{
+		file_error = FILE_WRITE_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+		throw CFileBaseException(file_error);
+#else
+		return file_error;
+#endif
+	}
+	Seek((FileSystem::FAU_t)0, FileSystem::FILE_SEEK_CUR);
+	return file_error = FILE_NO_ERROR;
+}
+
+
+//------------------------------------------------------------------------------- 
+// StreamPos CFileBase::FilePosition()
+//
+// Returns the current file position or -1 to indicate an error condition.
+//------------------------------------------------------------------------------- 
+FileSystem::StreamPos CFileBase::FilePosition()
+{
+   if (!IsOK())
+   {
+      file_error = FILE_NOT_READY;
+#ifdef __CPP_EXCEPTIONS__
+      throw CFileBase();
+#else
+      return (StreamPos) - 1;
+#endif
+   }
+
+   FileSystem::StreamPos pos = FileSystem::Tell(fp);
+   if (pos < 0)
+   {
+      file_error = FILE_POSITION_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+      throw CFileBaseException(file_error);
+#else
+      return (StreamPos) - 1;
+#endif
+   }
+   return pos;
+}
+
+//------------------------------------------------------------------------------- 
+// isis::uint32_t CFileBase::CalcChecksum(isis::uint32_t bytes, FAU file_address, 
+//                                                         int mem_alloc)
+//
+// Calculate a 32-bit CRC checksum for a given number of bytes starting at the
+// specified address. Returns a 32-bit CRC value. If the mem_alloc variable is
+// true, a buffer equal to the specified number of bytes will be created in
+// memory. If the mem_alloc variable is false or memory allocation fails, the CRC
+// will be calculated byte by byte starting at the specified address. 
+// NOTE: the calling function must check for disk file errors.
+// Returns the CRC value.
+//------------------------------------------------------------------------------- 
+
+isis::uint32_t CFileBase::CalcChecksum(isis::uint32_t bytes, FileSystem::FAU_t file_address, int mem_alloc)
+{
+   isis::uint32_t CRC;
+   isis::uint32_t len = bytes;
+   unsigned char data;
+   char *buf = 0;  
+
+   // Create a buffer equal to the object length
+   if (mem_alloc) 
+	   buf = new char[bytes]; 
+
+   if (buf)
+   {
+      if (IsOK())
+	  {
+         if (Fetch(buf, bytes, file_address) != FILE_NO_ERROR) return 0;
+         CRC = CalcCRC32(buf, bytes);
+         delete[] buf;
+	  }
+   }
+   else
+   {
+      if (IsOK())
+	  {
+          // Seek to the specified file address
+          SeekTo(file_address);
+          if (file_error != FILE_NO_ERROR) return 0; 
+          CRC = 0xffffffffL;
+          while (len--)
+		  {
+	         if (Fetch(&data, sizeof(data)) != FILE_NO_ERROR) return 0;
+	         CRC = CalcCRC32(data, CRC);
+		  }
+          CRC ^= 0xffffffffL;
+	  }
+   }
+
+   return CRC; 
+}
+///////////////////////////////////////////////////////////////////////////
+// General purpose file utilites 
+//
+int CFileBase::Exists(const TCHAR *fname)
+// Returns true if the file exists
+{
+	return FileSystem::Exists(fname);
+}
+
+FileSystem::FAU_t CFileBase::FileSize(const TCHAR *fname)
+// Returns the file size. Use after file has been closed
+// and re-opened to ensure that all the buffers are flushed
+// to disk. Returns -1 to indicate an error condition.
+{
+	return (FileSystem::FAU_t) FileSystem::FileSize(fname);
+}
+
+int CFileBase::CanOpenForWriting(const TCHAR *fname)
+// Returns true if the file is opened
+{
+	return 1;
+	//return FileSystem::CanOpenForWriting(fname);
+}
+
+int CFileBase::CanOpenReadOnly(const TCHAR *fname)
+// Returns true if the file is opened
+{
+	return 1;
+	//return FileSystem::CanOpenReadOnly(fname);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/File.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/File.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/File.h	(revision 10506)
@@ -0,0 +1,188 @@
+/**********************************************************************
+ *
+ * File.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+//////////////////////////////////////////////////////////////////////////
+// File.h -- File Base class
+// 
+//////////////////////////////////////////////////////////////////////////
+ 
+
+ 
+#ifndef __FILE_BASE__
+#define __FILE_BASE__
+
+#include "FileSystem.h"
+# define __CPP_EXCEPTIONS__ 1
+
+// CRC-32 checksum used to detect bit errors
+typedef unsigned long Checksum;
+
+
+// Constants for file operations and stream position 
+const int MaxNameLength             = 512;        // Max length of names buffers
+const FileSystem::FAU_t StartOfFile = (FileSystem::FAU_t)0; // First byte in the file
+const FileSystem::FAU_t CURRADDR    = (FileSystem::FAU_t)-1;// Indicates current location
+const isis::uint32_t CheckWord      = 0xfefefefe;           // Default synchronization word
+const isis::int32_t  FSListCorrupt  = (FileSystem::FAU_t)-1;// Free space list is corrupt
+
+
+//------------------
+// File  error codes
+//------------------
+enum FileError { 
+  FILE_NO_ERROR = 0,   // No errors reported
+  FILE_CHECKSUM_ERROR, // Checksum Error
+  FILE_CLOSE_ERROR,    // Error closing file
+  FILE_CORRUPT,        // File corrupted
+  FILE_CREATION_ERROR, // Error creating file
+  FILE_EXISTS,         // File already exists
+  FILE_NOT_OPEN_ERROR, // Trying to use a closed file
+  FILE_NOT_READY,      // File not ready (failed or closed file)
+  FILE_NOT_WRITEABLE,  // Could not write to file 
+  FILE_OPEN_ERROR,     // Error opening file
+  FILE_POSITION_ERROR, // Cannot obtain the current file position
+  FILE_READ_ERROR,     // Error reading file  
+  FILE_SEEK_ERROR,     // Error seeking in file
+  FILE_WRITE_ERROR,    // Error writing to file
+
+  FMGR_NO_DATABASE_OPEN,    // No database open
+  FMGR_NO_FILE_EXISTS,      // No such file exists
+  FMGR_NO_OBJECTS_EXIST,    // No objects exist
+  FMGR_NULL_PTR,            // Accessing a null pointer 
+  FMGR_OBJECT_EXISTS,       // Object already exists
+  FMGR_OPEN_FILE_REFERENCE, // Another object is referencing this file
+  FMGR_OVERFLOW,            // Math overflow
+  FMGR_PARSE_ERROR,         // Parse error
+  FMGR_PATH_ERROR,          // Invalid path
+  FMGR_READ_ONLY_FILE,      // Trying to write to read-only file
+  FMGR_STACK_EMPTY,         // Stack empty
+  FMGR_STACK_FULL,          // Stack full
+  FMGR_SYNC_ERROR,          // Synchronization Error
+  FMGR_UNDERFLOW,           // Math under-flow
+  FMGR_WRONG_FILE_TYPE,     // Wrong file type
+
+  // Persistent lock error codes
+  FMGR_INVALID_LOCK_TYPE,        // Invalid lock type specified
+  FMGR_FILELOCK_ACCESS_ERROR,    // The file lock cannot be accessed
+  FMGR_FILELOCK_ERROR,           // Error locking the file
+  FMGR_RECORDLOCK_ACCESS_ERROR,  // The record lock cannot be accessed
+  FMGR_RECORDLOCK_ERROR          // Error locking a record};
+
+
+};
+
+
+
+
+class DLL_CODE_API CFileBase 
+{
+protected:
+    // File I/O operation codes
+  enum IO_Op { 
+     IO_READ,         // A read was performed
+     IO_WRITE,        // A write operation was performed
+     IO_REWIND,       // A rewind operation was performed
+     IO_NO_OPERATION, // No operation was performed
+     IO_SEEK          // A seek operation was preformed 
+  };
+
+  _TCHAR            file_name[MaxNameLength];  // Open file name
+  FileSystem::FPTR* fp;                        // Stream file handle
+  IO_Op             last_operation;            // Last I/O operation preformed
+  FileError         file_error;                // Last reported file error
+
+  // File status members
+  int is_ok;             // Used to signal a fatal error condition
+  int is_open;           // True if the file is open
+  int ready_for_reading; // True if the file is ready for reading
+  int ready_for_writing; // True if the file is ready for writing
+
+
+public:
+   CFileBase();
+   virtual ~CFileBase();
+
+public: // File functions
+   virtual FileError Create(const TCHAR *fname);
+   virtual FileError Open(const TCHAR *fname, FileSystem::AccessMode mode = FileSystem::FILE_READWRITE); 
+   virtual FileError Close();
+   
+   FileError         Seek(FileSystem::FAU_t offset, FileSystem::SeekMode mode = FileSystem::FILE_SEEK_BEG);
+ 
+   FileError         Fetch(void* buf, isis::uint32_t nBytes, FileSystem::FAU_t file_addres = CURRADDR);
+   FileError         Store(const void* buf, isis::uint32_t nBytes, FileSystem::FAU_t file_address = CURRADDR,
+			                int flush_flag = 1, int bit_test = 1);
+
+   FileSystem::FAU_t     SeekTo(FileSystem::FAU_t file_address);
+   FileSystem::StreamPos FilePosition();
+
+   FileError Flush();
+
+   _TCHAR *FileName() { return file_name; }
+
+public: // 32-bit CRC checksum routines 
+  isis::uint32_t CalcChecksum(isis::uint32_t bytes, FileSystem::FAU_t file_address, int mem_alloc = 1);
+
+public:  // File Status functions
+  int IsOK()                  { return ((is_ok == 1) && (is_open == 1)); }
+  int IsOK()            const { return ((is_ok == 1) && (is_open == 1)); }
+  int IsOpen()                { return ((is_ok == 1) && (is_open == 1)); }
+  int IsOpen()          const { return ((is_ok == 1) && (is_open == 1)); }
+  int ReadyForReading()       { return ready_for_reading == 1; }
+  int ReadyForReading() const { return ready_for_reading == 1; }
+  int ReadyForWriting()       { return ready_for_writing == 1; }
+  int ReadyForWriting() const { return ready_for_writing == 1; }
+
+public:  // Exception handling functions
+  FileError   GetFileError()              { return file_error; }
+  FileError   GetFileError() const        { return file_error; }
+  void        SetFileError(FileError err) { file_error = err; }
+  void        ResetFileError()            { file_error = FILE_NO_ERROR; }
+  const TCHAR *FileExceptionMessage();
+
+public: // General purpose file utilities
+  static int Exists(const TCHAR *fname);
+  static FileSystem::FAU_t FileSize(const TCHAR *fname);
+  static int CanOpenForWriting(const TCHAR *fname);
+  static int CanOpenReadOnly(const TCHAR *fname);
+  
+};
+
+
+#ifdef __CPP_EXCEPTIONS__
+// Class declarations for exceptions representing program errors. 
+// This implementation is provided for use C++'s built-in exception
+// handling routines.
+
+class CFileBaseException 
+{
+	int error_;
+public:
+	CFileBaseException(int error) { error_ = error; }
+};  
+
+#endif // __CPP_EXCEPTIONS__
+ 
+#endif   // __FILE_BASE__
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/FileSystem.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/FileSystem.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/FileSystem.cpp	(revision 10506)
@@ -0,0 +1,482 @@
+/**********************************************************************
+ *
+ * FileSystem.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////////////////////////////
+//
+// FileSystem -- The generic file pointer routines are a collection of member
+//               functions used to wrap  the underlying file system.
+
+
+#include "errno.h"
+#include "stdafx.h"
+#include "FileSystem.h"
+
+
+using namespace FileSystem;
+//---------------------------------------------------------------------
+// FileSystem::FPTR *Create(const _TCHAR *fname)
+//
+// Create a new file and truncate existing files.
+// Returns a null value if the file cannot be
+// created.
+//---------------------------------------------------------------------
+DLL_CODE_API FileSystem::FPTR *FileSystem::Create(const char *fname)
+{
+#if defined(__64_BIT_FILE_SYSTEM__)
+	return FS64Create(fname);
+	
+#elif defined(__WIN32__) && defined(__NTFS__)
+	FPTR *stream = new FPTR;
+	if (!stream)
+		return 0;
+	stream->fptr = CreateFile(fname, 
+		GENERIC_READ | GENERIC_WRITE, 
+		FILE_SHARE_READ | FILE_SHARE_WRITE, 
+		NULL, // No security
+		CREATE_ALWAYS, 
+		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+		NULL // No attr. template 
+		);
+	
+	if (stream->fptr == INVALID_HANDLE_VALUE)
+	{
+		delete stream;
+		return 0;
+	}
+	return stream;
+	
+#else // Use the 32-bit stdio version by default
+	FPTR *stream = new FPTR;
+	if (!stream)
+		return 0;
+	stream->fptr = fopen(fname, "w+b");
+	if (stream->fptr == 0)
+	{
+		delete stream; // 01/30/2002: Prevent memory leak
+		return 0;
+	}
+	return stream;
+#endif
+}
+
+//---------------------------------------------------------------------
+// FileSystem::FPTR *Open(const _TCHAR *fname, FileSystemAccessMode mode)
+//
+// Open an existing file. The "mode" variable determines if the file
+// is opened for read only or read/write access. Returns a null value
+// if the specified file cannot be opened. NOTE: This version of the
+// open functions will only accept: FILE_READONLY and FILE_READWRITE
+// access modes.
+//---------------------------------------------------------------------
+DLL_CODE_API FileSystem::FPTR *FileSystem::Open(const char *fname, FileSystem::AccessMode mode)
+{
+#if defined(__64_BIT_FILE_SYSTEM__)
+	return FSOpen(fname, mode);
+	
+#elif defined(__WIN32__) && defined(__NTFS__)
+	FPTR *stream = new FPTR;
+	if (!stream)
+		return 0;
+	if (mode == FILE_READONLY)
+	{
+		// Open for read only access
+		stream->fptr = CreateFile(fname, 
+			GENERIC_READ,
+			FILE_SHARE_READ | FILE_SHARE_WRITE, 
+			NULL, // No security
+			OPEN_EXISTING, 
+			FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 
+			NULL // No attr. template 
+			);
+		if (stream->fptr == INVALID_HANDLE_VALUE)
+		{
+			delete stream;
+			return 0;
+		}
+	}
+	else 
+	{ // Open for read/write access
+		stream->fptr = CreateFile(fname, 
+			GENERIC_READ | GENERIC_WRITE, 
+			FILE_SHARE_READ | FILE_SHARE_WRITE, 
+			NULL, // No security 
+			OPEN_EXISTING, 
+			FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 
+			NULL // No attr. template 
+			);
+		
+		if (stream->fptr == INVALID_HANDLE_VALUE)
+		{
+			delete stream;
+			return 0;
+		}
+	}
+	return stream;
+	
+#else // Use the 32-bit stdio version by default
+	FPTR *stream = new FPTR;
+	if (!stream)
+		return 0;
+	
+	if (mode == FILE_READONLY)
+	{
+		// Open for read only access
+		stream->fptr = fopen(fname, "rb");
+		if (stream->fptr == 0)
+		{
+			delete stream; // 01/30/2002: Prevent memory leak
+			return 0;
+		}
+	}
+	else 
+	{ // Open for read/write access
+		stream->fptr = fopen(fname, "r+b");
+		if (stream->fptr == 0)
+		{
+			delete stream; // 01/30/2002: Prevent memory leak
+			return 0;
+		}
+	}
+	return stream;
+#endif
+}
+
+//---------------------------------------------------------------------
+// int Close(FileSystem::FPTR *stream)
+//
+// Close an open file. Returns a non-zero value to  indicate an error 
+// condition or zero if successful.
+//---------------------------------------------------------------------
+DLL_CODE_API int FileSystem::Close(FPTR *stream)
+{
+	if (!stream)
+		return 0; // The file stream is not open
+	
+#if defined(__64_BIT_FILE_SYSTEM__)
+	return FS64Close(stream);
+	
+#elif defined(__WIN32__) && defined(__NTFS__)
+	if (!CloseHandle(stream->fptr))
+		return 1;
+	delete stream;
+	stream = 0;
+	return 0;
+	
+#else // Use the 32-bit stdio version by default
+	if (fclose(stream->fptr) != 0)
+		return 1;
+	delete stream;
+	stream = 0; // 02/02/2002: Set pointer to zero after releasing it
+	return 0;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// int Flush(FileSystem::FPTR *stream)
+//
+// Flush the any open disk buffers. Returns a non-zero value to indicate
+// an error // condition or zero if successful. 
+//
+// ATTENTION: ****MS VC++*** YOU SHOULD LINK YOUR APPLICATION WITH COMMODE.OBJ 
+// file. COMMODE.OBJ changes the global commit flag such that 
+// calling fflush() or _flushall() commits the file buffer to disk.
+// The Windows NT operating system provides the WIN32 API FlushFileBuffers().
+// The _commit() function included with the Visual C++ 32-bit Edition 
+// CRT calls FlushFileBuffers to write buffered data to disk. 
+//-----------------------------------------------------------------------------
+DLL_CODE_API int FileSystem::Flush(FPTR *stream)
+{
+	if (!stream)
+		return 0; // The file stream is not open
+	
+#if defined(__64_BIT_FILE_SYSTEM__)
+	return FS64Flush(stream);
+	
+#elif defined(__WIN32__) && defined(__NTFS__)
+	if (!FlushFileBuffers(stream->fptr))
+		return 1;
+	return 0;
+	
+#else // Use the 32-bit stdio version by default
+	int ret = fflush(stream->fptr);
+	if (ret != 0)
+	{
+		TRACE("\nerrno=%d\n\n\n", errno);
+		return 1;       // Error
+	}
+	else
+		return 0;
+#endif
+}
+
+//---------------------------------------------------------------------
+// int Read(FileSystem::FPTR *stream, void *buf, isis::uint32_t bytes)
+//
+// Read a specified number of bytes from the current file position
+// into a memory buffer. Returns the total number if bytes read from the
+// file.
+//---------------------------------------------------------------------
+DLL_CODE_API isis::ulong32_t FileSystem::Read(FPTR *stream, void *buf, 
+											  isis::ulong32_t bytes)
+{
+	if (!stream)
+		return (isis::ulong32_t)0; // The file stream is not open
+	
+#if defined(__64_BIT_FILE_SYSTEM__)
+	return FS64Read(stream, buf, bytes);
+	
+#elif defined(__WIN32__) && defined(__NTFS__)
+	DWORD bytes_read; 
+	if (!ReadFile(stream->fptr, (LPVOID)buf, (DWORD)bytes, &bytes_read, NULL))
+	{
+		return (isis::ulong32_t)0;
+	}
+	return (isis::ulong32_t)bytes_read;
+	
+#else // Use the 32-bit stdio version by default
+	return (isis::ulong32_t)fread((unsigned char *)buf, 1, bytes, stream->fptr);
+#endif
+}
+//---------------------------------------------------------------------
+// int Write(FileSystem::FPTR *stream, const void *buf, isis::uint32_t bytes) 
+//
+// Write a specific number of bytes from a memory buffer to the
+// current file position. Returns the total number if bytes written
+// to the file.
+//---------------------------------------------------------------------
+DLL_CODE_API isis::ulong32_t FileSystem::Write(FPTR *stream, const void *buf, 
+				                   isis::ulong32_t bytes) 
+{
+	if (!stream)
+		return (isis::ulong32_t)0; // The file stream is not open
+	
+#if defined(__64_BIT_FILE_SYSTEM__)
+	return FS64Write(stream, buf, bytes);
+	
+#elif defined(__WIN32__) && defined(__NTFS__)
+	DWORD bytes_moved; 
+	if (!WriteFile(stream->fptr, (LPVOID)buf, (DWORD)bytes, &bytes_moved, NULL))
+	{
+		return (isis::ulong32_t)0;
+	}
+	return (isis::ulong32_t)bytes_moved;
+	
+#else // Use the 32-bit stdio version by default
+	return (isis::ulong32_t)fwrite((const unsigned char *)buf, 1, bytes, stream->fptr);
+#endif
+}
+//---------------------------------------------------------------------------
+// isis::int32_t Seek(FileSystem::FPTR *stream, isis::int32_t offset,  FileSystemSeekMode mode)
+//
+// Seek to the specified offset starting at the beginning (SEEK_SET),
+// end (SEEK_END) or current offset (SEEK_CUR). Returns a negative 1
+// to indicate an error condition or the current stream position if
+// successful.
+//----------------------------------------------------------------------------
+DLL_CODE_API FAU_t FileSystem::Seek(FPTR *stream, FAU_t offset, FileSystem::SeekMode mode)
+{
+	if (!stream)
+		return (FAU_t) - 1; // The file stream is not open
+	
+#if defined(__64_BIT_FILE_SYSTEM__)
+	return FS64Seek(stream, offset, mode);
+	
+#elif defined(__WIN32__) && defined(__NTFS__)
+	if (mode == FILE_SEEK_BEG)
+	{
+		return (FAU_t)SetFilePointer(stream->fptr, offset, NULL, FILE_BEGIN);
+	}
+	else if (mode == FILE_SEEK_CUR)
+	{
+		return (FAU_t)SetFilePointer(stream->fptr, offset, NULL, FILE_CURRENT);
+	}
+	else if (mode == FILE_SEEK_END)
+	{
+		return (FAU_t)SetFilePointer(stream->fptr, offset, NULL, FILE_END);
+	}
+	else 
+	{ // An invalid seek mode was specified
+		return (FAU_t) - 1;
+	}
+	
+#else // Use the 32-bit stdio version by default
+	if (mode == FILE_SEEK_BEG)
+	{
+		return fseek(stream->fptr, offset, SEEK_SET);
+	}
+	else if (mode == FILE_SEEK_CUR)
+	{
+		return fseek(stream->fptr, offset, SEEK_CUR);
+	}
+	else if (mode == FILE_SEEK_END)
+	{
+		return fseek(stream->fptr, offset, SEEK_CUR);
+	}
+	else 
+	{ // An invalid seek mode was specified
+		return (FAU_t) - 1;
+	}
+#endif
+}
+//----------------------------------------------------------------------------
+// isis::int32_t Tell(FileSystem::FPTR *stream)
+//
+//----------------------------------------------------------------------------
+DLL_CODE_API FAU_t FileSystem::Tell(FPTR *stream)
+{
+	if (!stream)
+		return (FAU_t) - 1; // The file stream is not open
+	
+#if defined(__64_BIT_FILE_SYSTEM__)
+	return FS64Tell(stream);
+	
+#elif defined(__WIN32__) && defined(__NTFS__)
+	return (__LWORD__)SetFilePointer(stream->fptr, 0, NULL, FILE_CURRENT);
+	
+#else // Use the 32-bit stdio version by default
+	return ftell(stream->fptr);
+#endif
+}
+
+//----------------------------------------------------------------------------
+// int Exists(const char *fname)
+//
+// Returns true if the specified file exists.
+//----------------------------------------------------------------------------
+DLL_CODE_API int FileSystem::Exists(const char *fname)
+// Returns true if the specified file exists.
+{
+#if defined(__64_BIT_FILE_SYSTEM__)
+	return FS64Exists(fname);
+	
+#elif defined(__WIN32__) && defined(__NTFS__)
+	HANDLE hFile = CreateFile(fname, 
+		GENERIC_READ,
+		FILE_SHARE_READ | FILE_SHARE_WRITE, 
+		NULL, // No security
+		OPEN_EXISTING, 
+		FILE_ATTRIBUTE_NORMAL, 
+		NULL // No attr. template
+		);
+	
+	if (hFile == INVALID_HANDLE_VALUE)
+	{
+		return 0;
+	}
+	
+	CloseHandle(hFile);
+	return 1;
+	
+#else // Use the 32-bit stdio version by default
+	struct stat buf;
+	return stat(fname, &buf) ==(FAU_t)0;
+#endif
+}
+
+
+
+//----------------------------------------------------------------------------
+// FAU_t FileSize(const _TCHAR *fname)
+//
+// Returns the length of the specified file or negative 1 to indicate an
+// error condition.
+//----------------------------------------------------------------------------
+DLL_CODE_API FAU_t FileSystem::FileSize(const char *fname)
+{
+#if defined(__64_BIT_FILE_SYSTEM__)
+	return FS64FileSize(fname);
+	
+#elif defined(__WIN32__) && defined(__NTFS__)
+	HANDLE hFile = CreateFile(fname, 
+		GENERIC_READ,
+		FILE_SHARE_READ | FILE_SHARE_WRITE, 
+		NULL, // No security
+		OPEN_EXISTING, 
+		FILE_ATTRIBUTE_NORMAL, 
+		NULL // No attr. template 
+		);
+	
+	// Could not open the specified file
+	if (hFile == INVALID_HANDLE_VALUE)
+	{
+		return (FAU_t) - 1;
+	}
+	
+	BY_HANDLE_FILE_INFORMATION info;
+	
+	if (GetFileInformationByHandle(hFile, &info) == 0)
+	{
+		return (FAU_t) - 1;
+	}
+	CloseHandle(hFile);
+	return (FAU_t)info.nFileSizeLow;;
+	
+#else // Use the 32-bit stdio version by default
+	struct stat buf;
+	int result = stat(fname, &buf);
+	if (result != 0)
+		return -1;
+	return buf.st_size;
+#endif
+}
+
+//  #include <io.h>
+//  #include <share.h>
+
+
+//  int FileSystem::CanOpenForWriting(const _TCHAR *fname)
+//  {
+//  	// Try to open for writing
+//  	int fd = _tsopen(fname, _O_WRONLY | O_BINARY, _SH_DENYWR);
+//  	if (fd == -1)
+//  		return 0;
+//  	_close(fd);
+//  	return 1;
+//  }
+
+//  int FileSystem::CanOpenReadOnly(const _TCHAR *fname)
+//  {
+//  	// Try to open for read only
+//  	int fd = _tsopen(fname, _O_RDONLY | O_BINARY, _SH_DENYNO);
+//  	if (fd == -1)
+//  		return 0;
+//  	_close(fd);
+//  	return 1;
+//  }
+
+//----------------------------------------------------------------------------
+// int IsReadOnly(const _TCHAR* fname)
+//
+// Returns true if the specified file is read only.
+//----------------------------------------------------------------------------
+//  int FileSystem::IsReadOnly(const _TCHAR *fname)
+//  {
+//  	struct _stat buf;
+//  	_tstat(fname, &buf);
+//  	if (buf.st_mode & S_IWRITE)
+//  		return 0;
+//  	return 1;
+//  }
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/FileSystem.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/FileSystem.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/FileSystem.h	(revision 10506)
@@ -0,0 +1,121 @@
+/**********************************************************************
+ *
+ * FileSystem.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////////////////////////
+// FileSystem.h -- The generic file pointer routines are a collection of member
+//                 functions used to wrap  the underlying file system.
+
+//
+
+  
+#ifndef __FILE_SYSTEM__
+#define __FILE_SYSTEM__
+
+// Non-platform specific include files
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include "DLLCode.h"
+#include "IsisTypes.h"
+
+namespace FileSystem {
+	
+// ----------------
+// Type definitions 
+// ----------------
+// typedefs for 64-bit and 32-bit file operations and stream position
+#if defined (__64_BIT_FILE_SYSTEM__)
+    typedef isis::int64_t FAU;       // 64-bit File Address Unit, physical file address type
+    typedef isis::int64_t FAU_t;     // Native 64-bit FAU type
+    typedef isis::int64_t StreamPos; // 64-bit stream position
+#else // Use the 32-bit version by default
+	typedef isis::int32_t FAU;       // 32-bit File Address Unit, physical file address type
+	typedef isis::int32_t FAU_t;     // Native 32-bit FAU type
+	typedef isis::int32_t StreamPos; // 32-bit stream position
+#endif
+
+
+// Select the underlying file system 
+#if defined (__64_BIT_FILE_SYSTEM__)
+	#include "FS64.H"              // WIN32 will always use NTFS for large files
+	typedef  FPTR64 FPTR;
+
+
+#elif defined (__WIN32__) && defined (__NTFS__)
+	// WIN32 file I/O API
+	#include <windows.h>
+	#include <io.h>
+	#include <string.h>
+	#include <stdlib.h>
+	#include <fcntl.h>
+	#include <sys/types.h>
+	#include <sys/stat.h>
+	#include <stdio.h>
+	#include "gxdtypes.h"
+	#include "gxheader.h"
+
+	struct DLL_CODE_API FPTR { // Platform specific file pointer type
+		HANDLE fptr;
+	};
+
+#else // Use the stdio version by default. Common to all platforms.
+	// Non-platform specific stdio include files
+	#include <string.h>
+	#include <stdlib.h>
+	#include <fcntl.h>
+	#include <sys/types.h>
+	#include <sys/stat.h>
+	#include <stdio.h>
+	#include "IsisTypes.h"
+	//#include "gxheader.h"
+
+	struct DLL_CODE_API FPTR { // File pointer type
+		 FILE *fptr;
+	};
+#endif // File system type
+
+
+
+    // NOTE: Any underlying file system used must provide the basic
+    // functionallity defined here.
+    DLL_CODE_API FPTR            *Create(const char  *fname);
+    DLL_CODE_API FPTR            *Open(const char *fname, AccessMode mode);
+    DLL_CODE_API int             Close(FPTR *stream);
+    DLL_CODE_API int             Flush(FPTR *stream);
+    DLL_CODE_API isis::ulong32_t Read(FPTR *stream, void *buf, isis::ulong32_t bytes);
+    DLL_CODE_API isis::ulong32_t Write(FPTR *stream, const void *buf, isis::ulong32_t bytes);
+    DLL_CODE_API FAU_t           Seek(FPTR *stream, FAU_t, SeekMode mode);
+    DLL_CODE_API FAU_t           Tell(FPTR *stream);
+    DLL_CODE_API int             Exists(const _TCHAR *fname);
+    DLL_CODE_API FAU_t           FileSize(const _TCHAR *fname);
+    // DLL_CODE_API int             CanOpenForWriting(const _TCHAR *fname);
+    // DLL_CODE_API int             CanOpenReadOnly(const _TCHAR *fname);
+    // DLL_CODE_API int             IsReadOnly(const _TCHAR *fname);
+}
+
+#endif // __FILE_SYSTEM__
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IErrors.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IErrors.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IErrors.cpp	(revision 10506)
@@ -0,0 +1,113 @@
+/**********************************************************************
+ *
+ * IErrors.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////////////////////////////
+// Error.cpp
+
+// #include "stdafx.h"
+// The Error functions and classes are used to catch and/or
+// record database exceptions that occur during run-time. This
+// implementation can be used with or without C++ built-in exception
+// handling. If C++ exception handling is not enabled with the
+// __CPP_EXCEPTIONS__ macro, then the vbDatabaseError enumerated
+// constants can be used to record database errors.
+#include "IErrors.h"
+
+// NOTE: This array must contain the same number of exceptions as the
+// IsisError enumeration. 
+const int MaxExceptionMessages = 57;
+const char* isisExceptionMessages[MaxExceptionMessages] = {
+  "Database exception: No exception reported",               // None
+  "Database exception: Invalid error code reported",         // Invalid
+  "Database exception: Memory exhausted",
+  "Database exception: Error opening xrf file",
+  "Database exception: Error creating xrf file",
+  "Database exception: Error reading xrf file",
+  "Database exception: Error writing xrf file",
+  "Database exception: xrf file is corrupted",
+  "Database exception: xrf file, invalid block",
+  "Database exception: xrf file, invalid status",
+  "Database exception: Error creating an existing mf file",
+  "Database exception: Error opening mf file",
+  "Database exception: Error opening mf file",
+  "Database exception: Error creating mf file",
+  "Database exception: Error reading mf file",
+  "Database exception: Error writing mf file",
+  "Database exception: Access Violation",                    // AccessViolation
+  "Database exception: Assertion failed",                    // AssertError
+  "Database exception: Wrong object type",                   // BadClassID
+  "Database exception: Bad object address",                  // BadObjectAddress
+  "Database exception: Bad reference",                       // BadReference
+  "Database exception: Cache full",                          // CacheFull
+  "Database exception: Checksum error",                      // ChecksumError
+  "Database exception: Divide by zero error",                // DivideByZero
+  "Database exception: Unexpected end of file was reached",  // EOFError
+  "Database exception: Error closing file",                  // FileCloseError
+  "Database exception: File is corrupt",                     // FileCorrupt
+  "Database exception: Error creating file",                 // CreationError
+  "Database exception: File already exists",                 // FileExists
+  "Database exception: Trying to use a closed file",         // FileNotOpenError
+  "Database exception: File not ready for reading/writing",  // FileNotReady
+  "Database exception: Could not write to file",             // NotWriteable
+  "Database exception: Error opening file",                  // FileOpenError
+  "Database exception: Cannot obtain a file position",       // FilePostionError
+  "Database exception: Error reading from file",             // FileReadError
+  "Database exception: Error seeking in file",               // FileSeekError
+  "Database exception: Error writing to file",               // FileWriteError
+  "Database exception: No database open",                    // NoDatabaseOpen
+  "Database exception: No such file exists",                 // NoFileExists
+  "Database exception: No objects exist",                    // NoObjectsExist
+  "Database exception: Accessing a null pointer",            // NullPtr
+  "Database exception: Object already exists",               // ObjectExists
+  "Database exception: Another object is referencing this file", // Referenced
+  "Database exception: Math overflow error",                 // OverFlow
+  "Database exception: Parse error",                         // ParseError
+  "Database exception: Invalid path",                        // PathError
+  "Database exception: Trying to write to a read-only file", // ReadOnlyFile
+  "Database exception: Stack empty",                         // StackEmpty
+  "Database exception: Stack full",                          // StackFull
+  "Database exception: Synchronization Error",               // SyncError    
+  "Database exception: Math under-flow error",               // UnderFlow
+  "Database exception: Wrong file type",                     // WrongFileType
+
+  // Persistent lock error messages
+  "Database exception: Invalid lock type specified",          // LOCK_TYPE
+  "Database exception: Cannot access the file lock header",   // FLK_ACCESS
+  "Database exception: Cannot lock the file",                 // FLK_ERROR
+  "Database exception: Cannot access the record lock header", // RLK_ACCESS
+  "Database exception: Cannot lock the specified record"      // RLK_ERROR
+};
+
+const char *isisExceptionMessage(IsisError err)
+// Standalone function that returns a null terminated string that can
+// be use to log or print a database exception message.
+{
+  int error = (int)err;
+  if(error > MaxExceptionMessages) error = ISIS_INVALID_CODE;
+
+  // Find the corresponding message in the exception array
+  return isisExceptionMessages[error];
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IErrors.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IErrors.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IErrors.h	(revision 10506)
@@ -0,0 +1,104 @@
+/**********************************************************************
+ *
+ * IErrors.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef __ISIS_ERROR_H__
+#define __ISIS_ERROR_H__
+
+enum IsisError { // Database error codes
+  ISIS_NO_ERROR = 0,        // No errors reported
+  ISIS_INVALID_CODE,
+  ISIS_BAD_ALLOC,
+  ISIS_XRF_OPEN_ERROR,      // Xrf open error
+  ISIS_XRF_CREATE_ERROR,    // Xrf creation error
+  ISIS_XRF_READ_ERROR,      // Xrf read error
+  ISIS_XRF_WRITE_ERROR,     // Xrf write error
+  ISIS_XRF_CORRUPT,         // Xrf corrupted
+  ISIS_XRF_INVALID_BLOCK,   // Xrf invalid block
+  ISIS_XRF_INVALID_STATUS,  // Xrf invalid status
+  ISIS_MF_ALREADY_EXIST_ERROR, // Attempt to create an existing mf
+  ISIS_MF_OPEN_ERROR,       // Mf open error
+  ISIS_MF_CREATE_ERROR,     // Mf creation error
+  ISIS_MF_READ_ERROR,       // Mf read error
+  ISIS_MF_WRITE_ERROR,      // Mf write error 
+  ISIS_ASSERT_ERROR,        // Assertion failed
+  ISIS_BAD_CLASS_ID,        // Wrong object type
+  ISIS_BAD_OBJECT_ADDRESS,  // Bad object address  ISIS_BAD_REFERENCE,       // Bad Reference
+  ISIS_CACHE_FULL,          // Cache full
+  ISIS_CHECKSUM_ERROR,      // Checksum Error
+  ISIS_DIVIDEBY_ZERO,       // Divide By Zero Error
+  ISIS_EOF_ERROR,           // Unexpected end of file
+  ISIS_FILE_CLOSE_ERROR,    // Error closing file
+  ISIS_FILE_CORRUPT,        // File corrupted
+  ISIS_FILE_CREATION_ERROR, // Error creating file
+  ISIS_FILE_EXISTS,         // File already exists
+  ISIS_FILE_NOT_OPEN_ERROR, // Trying to use a closed file
+  ISIS_FILE_NOT_READY,      // File not ready (failed or closed file)
+  ISIS_FILE_NOT_WRITEABLE,  // Could not write to file 
+  ISIS_FILE_OPEN_ERROR,     // Error opening file
+  ISIS_FILE_POSITION_ERROR, // Cannot obtain the current file position
+  ISIS_FILE_READ_ERROR,     // Error reading file  
+  ISIS_FILE_SEEK_ERROR,     // Error seeking in file
+  ISIS_FILE_WRITE_ERROR,    // Error writing to file
+  ISIS_NO_DATABASE_OPEN,    // No database open
+  ISIS_NO_FILE_EXISTS,      // No such file exists
+  ISIS_NO_OBJECTS_EXIST,    // No objects exist
+  ISIS_NULL_PTR,            // Accessing a null pointer 
+  ISIS_OBJECT_EXISTS,       // Object already exists
+  ISIS_OPEN_FILE_REFERENCE, // Another object is referencing this file
+  ISIS_OVERFLOW,            // Math overflow
+  ISIS_PARSE_ERROR,         // Parse error
+  ISIS_PATH_ERROR,          // Invalid path
+  ISIS_READ_ONLY_FILE,      // Trying to write to read-only file
+  ISIS_STACK_EMPTY,         // Stack empty
+  ISIS_STACK_FULL,          // Stack full
+  ISIS_SYNC_ERROR,          // Synchronization Error
+  ISIS_UNDERFLOW,           // Math under-flow
+  ISIS_WRONG_FILE_TYPE,     // Wrong file type
+
+  // Persistent lock error codes
+  ISIS_INVALID_LOCK_TYPE,        // Invalid lock type specified
+  ISIS_MFLOCK_ACCESS_ERROR,    // The file lock cannot be accessed
+  ISIS_MFLOCK_ERROR,           // Error locking the file
+  ISIS_RECORDLOCK_ACCESS_ERROR,  // The record lock cannot be accessed
+  ISIS_RECORDLOCK_ERROR          // Error locking a record
+};
+
+// Standalone functions use to report database errors
+const char *isisExceptionMessage(IsisError err);
+
+#ifdef __CPP_EXCEPTIONS__
+// Class declarations for exceptions representing program errors. 
+// This implementation is provided for use C++'s built-in exception
+// handling routines.
+
+// A fatal file error condition has been reached. All database engine
+// calls must catch this exception and evaluate it by testing the
+// vbDatabase or vbDatabase64 internal error variable.
+class CIsisException { };  
+
+#endif // __CPP_EXCEPTIONS__
+
+#endif // __ISIS_ERROR_H__
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisDb.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisDb.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisDb.cpp	(revision 10506)
@@ -0,0 +1,252 @@
+/**********************************************************************
+ *
+ * IsisDb.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////
+// ISISDB: Isis Master file methods
+////////////////////////////////////////////////////////////
+#include "stdafx.h"
+#include "IsisDb.h"
+#include "XRFFile.h"
+
+
+
+//-------------------------------------------------------------------------------- 
+// IsisDb::IsisDb()
+//
+// Constructor, Makes an ISIS Data Base object that isn't connected to a Master 
+// file, Cross Reference file and Fdt.
+//-------------------------------------------------------------------------------
+IsisDb::IsisDb()
+{
+	bReadOnly_ = false;
+	try
+	{
+        mf_  = new MfFile;
+	    xf_  = new XrfFile; 
+	    fdt_ = new CFdt;
+	}
+	catch(std::bad_alloc)
+	{
+		throw CIsisDbException(ISIS_BAD_ALLOC, __FILE__, __LINE__);
+	}
+}
+ 
+//////////////////////////////
+ 
+IsisDb::~IsisDb( )
+{
+   delete mf_; delete xf_; delete fdt_;
+}
+ 
+ 
+//////////////////////////////
+ 
+int IsisDb::CreateDb(const TCHAR *fname)
+{
+   name = fname;
+   MkNames();
+   int rc = ISIS_NO_ERROR;
+
+   // We should not try to create a mf_ which already exist!
+   if (CFileBase::Exists(mfname_))
+   {
+	   throw CIsisDbException(ISIS_MF_ALREADY_EXIST_ERROR, __FILE__, __LINE__);
+   }
+   else
+   {
+       try
+	   {
+           rc = mf_->CreateMf(mfname_, USERMST);   
+           rc = xf_->CreateXrf(xrfname_);
+           rc = fdt_->Load(fdtname_);
+	   }
+       catch(CIsisDbException)
+	   {
+    	   throw CIsisDbException(ISIS_MF_OPEN_ERROR, __FILE__, __LINE__);
+	   }
+   }
+   
+   return rc;
+}
+ 
+ 
+//////////////////////////////
+ 
+void IsisDb::CloseDb()
+{
+   mf_->CloseMf();
+   xf_->Close();
+}
+ 
+//////////////////////////////
+ 
+void IsisDb::MkNames()
+// Make file names
+{
+    const _TCHAR *s = name.c_str();
+	_TCHAR *ps = new _TCHAR[_tcslen(s)+1];
+	_tcscpy(ps, s);
+	_TCHAR * tmp = _tcsrchr(ps, _T('.'));
+	assert(tmp != NULL);
+    // Terminate the string at the last dot 
+    *tmp = _T('\0');
+
+   _tcscpy(mfname_,ps);
+   _tcscat(mfname_,_T(".mst"));
+   _tcscpy(xrfname_,ps);
+   _tcscat(xrfname_,_T(".xrf"));
+   _tcscpy(fdtname_,ps);
+   _tcscat(fdtname_,_T(".fdt"));
+   _tcscpy(idxname_,ps);
+   _tcscat(idxname_,_T(".idx"));
+   delete[] ps;
+}
+ 
+//////////////////////////////
+ 
+int IsisDb::OpenDb(const TCHAR *fname,  FileSystem::AccessMode mode
+				                              /* = FileSystem::FILE_READWRITE */)
+{
+   name = fname;
+   MkNames();
+   int rc;
+   try
+   {
+     // if (FileSystem::IsReadOnly(mfname_))
+     //	   mode = FileSystem::FILE_READONLY;
+       rc = mf_->OpenMf(mfname_, mode);
+       rc = xf_->OpenXrf(xrfname_, mode);
+       rc = fdt_->Load(fdtname_);
+   }
+   catch(CIsisDbException)
+   {
+	   throw CIsisDbException(ISIS_MF_OPEN_ERROR, __FILE__, __LINE__);
+   }
+
+   return rc;
+}
+ 
+//----------------------------------------------------------------------------------
+// int  IsisDb::ReadDbRecord(long mfn, MfRecord &m)
+//
+// This function reads Master File record with MFN "mfn" into m
+//
+// Returns the status of the record: 
+// Active=0, LogicalyDeleted=1, PhysicalyDeleted=2, EndOfFile=-1, NewRecord = 3
+//----------------------------------------------------------------------------------
+int  IsisDb::ReadDbRecord(long mfn, MfRecord &m)
+{
+   long mfb;
+   int mfp;
+   int status;
+   bool rc;
+
+   try
+   {
+       status = xf_->GetMfp(mfn, mfb, mfp);
+       if (status == Active || status == LogicalyDeleted)
+	       if (!mf_->ReadMfRecord(mfb, mfp, m))
+			   status = -1;    // Error in reading the record!
+   }
+   catch(CIsisDbException)
+   {
+	   throw CIsisDbException(ISIS_MF_OPEN_ERROR, __FILE__, __LINE__);
+   }
+   return status;
+}
+ 
+//--------------------------------------------------------------------------------
+// void CreateDbRecord(MfRecord &m)
+//
+// Create a new record at the end of the master file. The Master file address is
+// set into the pair mfb/mfp and the XRF file is updated.
+//---------------------------------------------------------------------------------
+ void IsisDb::CreateDbRecord(MfRecord &m)
+{
+ 
+}
+
+//--------------------------------------------------------------------------------
+// void CreateDbRecordWithMfn(MfRecord &m)
+//
+// Create a new record at the end of the master file. The Master file address is
+// set into the pair mfb/mfp and the XRF file is updated.
+//---------------------------------------------------------------------------------
+ void IsisDb::CreateDbRecordWithMfn(MfRecord &m)
+{
+ 
+}
+
+ 
+//----------------------------------------------------------------------------------
+// void  UpdateDbRecord(MfRecord &m)
+//
+// Update of existing records. Whenever a record is updated, the system writes
+// the record back to the master file. Where it is written depends on the status
+// of the record when it was initially read.
+//
+//----------------------------------------------------------------------------------
+ void  IsisDb::UpdateDbRecord(MfRecord &m)
+{
+}
+//----------------------------------------------------------------------------------
+// int  IsisDb::DeleteRecord(long mfn)
+//
+// This function logically deletes a Master File record with MFN "mfn".
+// On XRF, xrfmfb is negative and on MST, status is set to 1
+//
+// Returns true if successful 
+//----------------------------------------------------------------------------------
+bool  IsisDb::DeleteRecord(long mfn)
+{
+
+   return false;
+}
+
+long  IsisDb::GetNextActiveMfn(long mfn /* = -1 */)
+{
+	if (mfn == -1)
+		mfn = 1;
+	else
+		mfn++;
+	long  mfb;
+	int  mfp;
+	int iRet = xf_->GetMfp(mfn, mfb, mfp);
+	while (iRet != Active && iRet != EndOfFile)
+	{
+		mfn++;
+        iRet = xf_->GetMfp(mfn, mfb, mfp);
+	}
+	if (iRet == EndOfFile)
+		return 0;
+	else
+		return mfn;
+}
+	
+_TCHAR *IsisDb::GetIdxFileName()
+{
+	return idxname_;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisDb.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisDb.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisDb.h	(revision 10506)
@@ -0,0 +1,130 @@
+/**********************************************************************
+ *
+ * IsisDb.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////
+// Isisdb.h : Class Definition for an ISIS db
+////////////////////////////////////////////////////////////
+ 
+#ifndef __ISISDB_H__
+#define __ISISDB_H__
+
+#include "AbstractIsisDb.h"
+#include "IsisDef.h"
+#ifndef _MFFILE_H_
+#include "MFFile.h"
+#endif
+
+ 
+class IsisDb : public AbstractIsisDb
+{
+	friend class CDBaseFile;
+
+	bool  bReadOnly_;
+    TCHAR xrfname_[_MAX_PATH];
+    TCHAR mfname_[_MAX_PATH];
+    TCHAR fdtname_[_MAX_PATH];
+    TCHAR idxname_[_MAX_PATH];
+protected:
+   void MkNames();
+public:
+   IsisDb();
+   virtual ~IsisDb( );
+   int OpenDb(const TCHAR *fname, FileSystem::AccessMode mode =
+	                                          FileSystem::FILE_READWRITE);
+   int CreateDb(const TCHAR *fname);
+
+
+// Closing the database
+   virtual void CloseDb();       // Close the db
+
+   virtual void ClearDb()   { }    // Clear the db
+   virtual void DestroyDb() { }  // Delete the db
+
+// Recovery
+   virtual bool IsDamaged() { return false;}   // Test if the database is damaged
+   virtual bool Recover()   { return true; }   // Recover the db
+
+// Transactions
+   virtual void BeginTransaction()    { }  // Begin a transaction
+   virtual void CommitTRansaction()   { }  // Commit a transaction
+   virtual void RollbackTransaction() { }  // Rollback a transaction
+   virtual bool InTransaction()       { return false; }  // Test if transaction is pending
+
+   virtual void CreateIndex(int i) { }
+   virtual void DropIndex(int i)   { }
+
+   void  CreateDbRecord(MfRecord &m);
+   void  CreateDbRecordWithMfn(MfRecord &m);
+   void  UpdateDbRecord(MfRecord &m);
+   bool  DeleteRecord(long mfn);
+   int   ReadDbRecord(long mfn, MfRecord &m);
+   int   ReadNextDbRecord(MfRecord &m);
+   void  PrintDbRecord(MfRecord &m);
+   void  PrintDbHdr();
+
+   void SetNextMfn(long mfn) { mf_->setNextMfn(mfn); }
+   long GetNextMfn()        { return mf_->GetNextMfn(); }
+   long GetNextActiveMfn(long mfn=-1);
+
+   SMfHeader& GetSMfHeader() { return mf_->GetSMfHeader(); }
+   _TCHAR *GetIdxFileName();
+
+   bool IsReadOnly() { return bReadOnly_; }
+};
+ 
+//////////////////////////////
+ 
+inline int IsisDb::ReadNextDbRecord(MfRecord &m)
+{
+   return 1;
+}
+ 
+//////////////////////////////
+ 
+inline void  IsisDb::PrintDbRecord(MfRecord &m)
+{
+   mf_->PrintMfRecord(m);
+}
+ 
+//////////////////////////////
+ 
+inline void  IsisDb::PrintDbHdr()
+{
+   mf_->PrintMfHdr();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class IsisDbFactory : public AbstractIsisDbFactory
+{
+public:
+	virtual AbstractIsisDb* MakeIsisDb() { return new IsisDb(); }
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisDef.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisDef.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisDef.h	(revision 10506)
@@ -0,0 +1,138 @@
+/**********************************************************************
+ *
+ * IsisDef.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef __ISIS_DEFINITION_H__
+#define __ISIS_DEFINITION_H__
+
+// disable warning C4786: symbol greater than 255 character,
+// okay to ignore
+#pragma warning(disable: 4786)
+
+#ifndef __ISIS_TYPE_H__
+#include "IsisTypes.h"
+#endif
+
+#include <sstream>
+
+typedef std::string ustring;
+typedef std::string cstring;
+// typedef std::wstring awstring;
+typedef std::stringstream ustringstream;
+typedef std::stringstream cstringstream;
+typedef wchar_t WCHAR;
+
+
+const size_t INVALID_NPOS = ~(size_t)0;
+
+namespace FileSystem {
+    // Generic File access/open mode enumeration
+    enum AccessMode { 
+       FILE_READONLY,   // Open file with read access only
+       FILE_WRITEONLY,  // Open file with write access only
+       FILE_READWRITE,  // Open file with read and write access
+       FILE_CREATE,     // Create the file if it does not exist
+       FILE_NO_CREATE,  // Do not create the file if it does not exist
+       FILE_TRUNCATE,   // Truncate the file  
+       FILE_APPEND,     // Append to the file
+       FILE_SHARE,      // Enable file sharing  (Platform specific)
+       FILE_EXCLUSIVE   // Disable file sharing (Platform specific)
+	};
+
+
+    // Generic File seek mode enumeration
+    enum SeekMode { 
+      FILE_SEEK_BEG, // Seek starting from the beginning of the file
+      FILE_SEEK_CUR, // Seek starting from the current location
+      FILE_SEEK_END  // Seek starting from the end of the file
+    };
+};
+
+#ifndef __FILE_SYSTEM__
+#include "FileSystem.h"
+#endif
+
+#ifndef __FILE_BASE__
+#include "File.h"
+#endif
+
+#ifndef __ISIS_ERROR_H__
+#include "IErrors.h"
+#endif
+
+#ifdef _WIN32
+#ifndef __DEBUG_H__
+#define _DEBUG
+#define _CONSOLE
+#include "debug.h"
+#endif
+#endif
+
+#ifndef __ABSTRACT_ISISDB_H__
+#include "AbstractIsisDb.h"
+#endif
+
+#ifndef __ISISDB_H__
+#include "IsisDb.h"
+#endif
+
+
+#ifndef __MASTER_RECORD_H__
+#include "Master.h"
+#endif
+
+#ifndef __FDT_H__
+#include "Fdt.h"
+#endif
+
+
+enum { RecordDeleted=0, RecordUpdated=1, RecordCreated=2};
+enum { Active=0, LogicalyDeleted=1, PhysicalyDeleted=2,
+       EndOfFile=-1, NewRecord = 3 };
+
+
+
+
+// Class declarations for exceptions representing program errors. 
+// This implementation is provided for use C++'s built-in exception
+// handling routines.
+
+class CIsisDbException { 
+public:
+	int m_iError;
+	CIsisDbException(const int iError, const char* file_name, const long line_number) 
+	{
+		m_iError = iError;
+#ifdef _WIN32
+		AssertFailed(isisExceptionMessage((IsisError) m_iError), file_name, line_number);
+#else
+		std::cout << isisExceptionMessage((IsisError) m_iError) << file_name
+			      << " Line=" << line_number;
+#endif
+	}
+};  
+
+
+#endif // __ISIS_DEFINITION_H__
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisGdl.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisGdl.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisGdl.cpp	(revision 10506)
@@ -0,0 +1,135 @@
+/**********************************************************************
+ *
+ * IsisGdl.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+// IsisGdl.cpp : Defines the entry point for the console application.
+//
+
+#include "stdafx.h"
+#include "IsisDb.h"
+#include <iostream>
+
+void PausePrg()
+{
+	std::cout << "\n";
+	std::cout << "Press enter to continue..." << "\n";
+	std::cin.get();
+}
+
+void ClearInputStream(std::istream &s)
+// Used to clear istream
+{
+	char c;
+	s.clear();
+	while(s.get(c) && c != '\n') { ; }
+}
+
+// Should be called with the master file name as parameter
+// IsisGdl "full_path\master_file_name" 
+// IsisGdl C:\IsisGdl\cds.mst for ex
+
+
+int main(int argc, _TCHAR* argv[])
+{
+
+	if (argc < 2)
+	{
+		std::cout << "usage: IsisGdl master_file_full_name" << std::endl;
+		return 1;
+	}
+	// Instantiation of the IsisDb Object
+	IsisDb db;
+	try
+	{
+		// The file name should be prefixed with the full path
+		// and should be the master file name with extension ".mst"
+		// "C:\IsisGdl\cds.mst" for ex
+		db.OpenDb(argv[1]);
+	}
+	catch(CIsisDbException e)
+	{
+		std::string msg = "Cannot open isis db: ";
+		msg += argv[1];
+		msg += isisExceptionMessage((IsisError) e.m_iError);
+		std::cerr<< msg << std::endl;
+		return false;
+	}
+
+	// Create a Master File object without the Field Definition
+	// Information
+	MfRecord mfr(0); 
+
+	// Extract the number of the next master file number to
+	// assign
+	const long nextMfn = db.GetNextMfn();
+
+
+
+	// Browse the master file in increasing order of Master
+	// file numbers (MFN is the record ID)
+	for (long i=1; i<nextMfn; i++)
+	{
+
+		int status = db.ReadDbRecord(i, mfr);
+
+		if (status == Active || status == LogicalyDeleted)
+		{
+			// If the record is physically on the master file
+			// then get the vector of field tags.
+			
+			// 1) Repetitive fields have the same tag and are stored in
+			//    a single field but are separated by the "%" char
+			// 2) Subfields are separated by "^"letter (^a ^b ^c ...)
+			//
+			// 3) Terms or Phrases between "<>" are terms/Phrases to 
+			//    index
+			std::vector<int> vf = mfr.GetFieldTags();
+			std::cout << "----------" << std::endl;
+			  //				      << "mfn=" << i  
+				// 	  << " nvf=" << vf.size() << std::endl;
+
+			for (int j=0; j<vf.size(); j++)
+			{
+				std::string stemp;
+				// Special case when tag is <=0
+				if (vf[j]<=0 || vf[j]>SHRT_MAX)
+					continue;
+				// Extract the field with tag contained into vf[j]
+				bool rc = mfr.GetField(vf[j], stemp);
+				if (rc)
+				{
+					std::cout << "tag=" << vf[j]
+					          << " data=" << stemp << std::endl;
+				}
+			}
+
+		}
+		else
+			continue;
+		// PausePrg();
+
+	}
+	return 0;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisTypes.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisTypes.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisTypes.h	(revision 10506)
@@ -0,0 +1,98 @@
+/**********************************************************************
+ *
+ * IsisTypes.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+///////////////////////////////////////////////////////////////////////////////
+//  isisType.h 
+
+
+#ifndef __ISIS_TYPE_H__
+#define __ISIS_TYPE_H__
+
+#include "DLLCode.h"
+
+#ifdef __USE_ISOC99 // get double_t type from math.h
+#include <math.h>
+#endif
+namespace isis
+{
+
+
+// ----------------------------------------
+// Type definitions common to all platforms
+// ----------------------------------------
+typedef char            int8_t;    // 8-bit signed value
+typedef unsigned char   uint8_t;   // 8-bit unsigned value
+typedef int             int32_t;   // Word size (4 bytes)
+typedef unsigned int    uint32_t;  // Unsigned word size (4 bytes)
+typedef long            long32_t;  // Long word (4 bytes)
+typedef unsigned long   ulong32_t; // Unsigned long word (4 bytes)
+typedef short           int16_t;   // short word (2 bytes)
+typedef unsigned short  uint16_t;  // Unsigned short word (2 bytes)
+#ifndef __USE_ISOC99 // gnu lic math.h has a double_t
+typedef double          double_t;  // Double precision floating point (8 bytes)
+#endif
+
+
+// --------------------------------------------------------------
+// Platform/compiler specific INT64 types
+// --------------------------------------------------------------
+#if defined (__64_BIT_FILE_SYSTEM__)
+#include "TYPES64.H" 
+#endif
+} // namespace isis
+
+namespace isis
+{
+    typedef  isis::int16_t  db_t;
+    typedef  isis::int16_t  server_t;
+    typedef  isis::int16_t  IsisClientId;
+    typedef  isis::uint32_t mfn_t;
+}
+// typedef char            int8_t;    // 8-bit signed value
+typedef unsigned char   uint8_t;   // 8-bit unsigned value
+typedef int             int32_t;   // Word size (4 bytes)
+typedef unsigned int    uint32_t;  // Unsigned word size (4 bytes)
+typedef long            long32_t;  // Long word (4 bytes)
+typedef unsigned long   ulong32_t; // Unsigned long word (4 bytes)
+typedef short           int16_t;   // short word (2 bytes)
+typedef unsigned short  uint16_t;  // Unsigned short word (2 bytes)
+#ifndef __USE_ISOC99 // gnu lic math.h has a double_t
+typedef double     double_t;  // Double precision floating point (8 bytes) // ****
+#endif
+
+typedef uint32_t        xrf_page_no_t;
+
+typedef uint32_t        mst_page_no_t;
+typedef uint16_t        mst_offset_t;
+typedef uint32_t        mfn_t;
+typedef uint32_t        mfrl_t;
+
+typedef isis::uint32_t file_size_t;
+
+
+#endif // __ISIS_TYPE_H__
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisUtil.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisUtil.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisUtil.cpp	(revision 10506)
@@ -0,0 +1,183 @@
+/**********************************************************************
+ *
+ * IsisUtil.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "stdafx.h"
+#include "IsisUtil.h" 
+#include <algorithm>
+
+
+//---------------------------------------------------------------------------------
+// bool RepFieldSep(TCHAR c)
+//
+// This function is a predicate that takes a TCHAR and returns a value that indicates
+// if that TCHAR is a repeteable field separator.
+//----------------------------------------------------------------------------------
+bool RepFieldSep(char c)
+{
+	return (c == SYSRSEP);
+}
+
+//--------------------------------------------------------------------------------
+// vector<string> SplitOccurences(const cstring& s)
+//
+// This function takes as input a string which contains a field and return a 
+// vector<string> which will contain an entry for each field occurence.
+//--------------------------------------------------------------------------------
+std::vector<cstring> SplitOccurences(const cstring& s)
+{
+	typedef cstring::const_iterator iter;
+	std::vector<cstring> ret;
+
+	iter i = s.begin();
+	//TRACE("\ni=%s",i);
+	while (i != s.end())
+	{
+		// find end of occurence
+		iter j = std::find_if(i,s.end(),RepFieldSep);
+
+		// copy the characters in [i, j]
+		ret.push_back(cstring(i, j));
+		//TRACE("\ni=%s j=%s string(i,j)=%s", i, j, string(i,j).c_str());
+
+		i = j;
+		if (j != s.end())
+		    i++;
+	}
+	return ret;
+}
+
+
+bool WSubFieldSep(WCHAR c)
+{
+	return (c == SUBFIELD_SEP);
+}
+
+//--------------------------------------------------------------------------------
+// vector<cstring> SplitSubfields(const cstring& s, TCHAR sc)
+//
+// This function takes as input a string which contains a field and return a 
+// vector<string> which will contain an entry for each subfield occurrence.
+//--------------------------------------------------------------------------------
+std::vector<cstring> SplitSubfields(const cstring& s, TCHAR sc/*=0*/)
+{
+	typedef cstring::const_iterator iter;
+	std::vector<cstring> ret;
+
+	iter i= s.begin();
+	iter j;
+	while (i < s.end())
+	{
+		// Look for subfield separator (^)
+		iter k =  std::find_if(i ,s.end(),WSubFieldSep);
+		if (k == s.end())
+		{
+			j = s.end(); // separator not found
+		}
+		else
+		{
+			// Special case when field is terminated by "^x" or "^"
+			if (k==s.end()-1 || k==s.end()-2)
+				break;
+			i = k + 2;  // separator found, skip next char
+			assert(i<s.end());
+			j = std::find_if(i ,s.end() ,WSubFieldSep);
+		}
+		ret.push_back(cstring(i, j));
+		i = j;
+	}
+	return ret;
+}
+
+
+//--------------------------------------------------------------------------------
+// vector<string> SplitOccurences(const awstring& s)
+//
+// This function takes as input a string which contains a field and return a 
+// vector<string> which will contain an entry for each field occurence.
+//--------------------------------------------------------------------------------
+//  std::vector<awstring> SplitOccurences(const awstring& s)
+//  {
+//  	typedef awstring::const_iterator iter;
+//  	std::vector<awstring> ret;
+
+//  	iter i = s.begin();
+//  	//TRACE("\ni=%s",i);
+//  	while (i != s.end())
+//  	{
+//  		// find end of occurence
+//  		iter j = std::find_if(i,s.end(),RepFieldSep);
+
+//  		// copy the characters in [i, j]
+//  		ret.push_back(awstring(i, j));
+//  		//TRACE("\ni=%s j=%s string(i,j)=%s", i, j, string(i,j).c_str());
+
+//  		i = j;
+//  		if (j != s.end())
+//  		    i++;
+//  	}
+//  	return ret;
+//  }
+
+
+bool SubFieldSep(TCHAR c)
+{
+	return (c == SUBFIELD_SEP);
+}
+
+//--------------------------------------------------------------------------------
+// vector<awstring> SplitSubfields(const awstring& s, TCHAR sc)
+//
+// This function takes as input a string which contains a field and return a 
+// vector<string> which will contain an entry for each subfield occurrence.
+//--------------------------------------------------------------------------------
+//  std::vector<awstring> SplitSubfields(const awstring& s, TCHAR sc/*=0*/)
+//  {
+//  	typedef awstring::const_iterator iter;
+//  	std::vector<awstring> ret;
+
+//  	iter i = s.begin();
+//  	//TRACE("\ni=%s",i);
+//  	bool found=false;
+//  	while (i != s.end())
+//  	{
+//  		// find index of subfield separator (^)
+//  		iter j = std::find_if(i,s.end(),SubFieldSep);
+//  		if (found && j<s.end()-1)
+//  		{
+//  		    // copy the characters in [i, j]
+//  			ret.push_back(awstring(i+1, j));
+//  		}
+//  		if (sc==0 || s.at(j-s.begin()+1)==sc)
+//  		    found = true;
+//  		else
+//  		    found = false;
+
+
+//  		i = j+1;
+//  		if (j != s.end())
+//  		    i++;
+//  	}
+//  	return ret;
+//  }
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisUtil.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisUtil.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/IsisUtil.h	(revision 10506)
@@ -0,0 +1,35 @@
+/**********************************************************************
+ *
+ * IsisUtil.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef __ISIS_UTIL__
+#define __ISIS_UTIL__
+#include <vector>
+#include <string>
+std::vector<cstring> SplitOccurences(const cstring &s);
+// std::vector<awstring> SplitOccurences(const awstring &s);
+
+std::vector<cstring> SplitSubfields(const cstring &s, TCHAR sc=0);
+// std::vector<awstring> SplitSubfields(const awstring &s, TCHAR sc=0);
+#endif // __ISIS_UTIL_
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/MFFile.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/MFFile.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/MFFile.cpp	(revision 10506)
@@ -0,0 +1,470 @@
+/**********************************************************************
+ *
+ * MFFile.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////
+// MfFile.cpp : Master file object methods using blocked I/O
+//
+////////////////////////////////////////////////////////////
+#include "stdafx.h"
+#include "IsisDb.h"
+#include "Checking.h"
+
+
+
+//---------------------------------------------------------------------------------- 
+// MfFile::MfFile() :
+//
+// Constructor, makes a Masterfile object that isn't connected to a file
+//---------------------------------------------------------------------------------- 
+MfFile::MfFile() : BlkFile(), hdr_created_(false), nextaddr_(MFCTLLEN)
+{
+    lastWrittenBlock_ = -1;
+}
+ 
+//----------------------------------------------------------------------------------
+// int MfFile::OpenMf(const TCHAR *fname, 
+//                    FileSystem::AccessMode mode /* = FileSystem::FILE_READWRITE */)
+//
+// Opens a Masterfile object
+//---------------------------------------------------------------------------------- 
+int MfFile::OpenMf(const TCHAR *fname, FileSystem::AccessMode mode
+				                              /* = FileSystem::FILE_READWRITE */)
+{
+	int rc;
+	try
+	{
+	    rc = CFileBase::Open(fname, mode);
+		hdr_created_ = true;
+	    ReadMfHdr();
+		PrintMfHdr();
+		Checking::CheckMfHeader(fname, mfh_);
+	}
+	catch (CFileBaseException e)
+	{
+        throw CIsisDbException(ISIS_MF_OPEN_ERROR, __FILE__, __LINE__);
+	}
+    return rc;
+}
+ 
+//----------------------------------------------------------------------------------
+// int MfFile::createMf(const TCHAR *fname, int  type)
+//
+// Creates a Masterfile object
+//---------------------------------------------------------------------------------- 
+int MfFile::CreateMf(const TCHAR *fname, int  type)
+{
+    return 0;
+}
+ 
+//////////////////////////////
+MfFile::~MfFile()
+{
+}
+ 
+//----------------------------------------------------------------------------------
+// void  MfFile::ReadMfRecord(long mfb, int mfp, MfRecord &m)
+//
+// Reads the master file record beginning at address (mfb,mfp) into m
+//----------------------------------------------------------------------------------
+bool  MfFile::ReadMfRecord(long mfb, int mfp, MfRecord &m)
+{
+	return m.Read(*this, mfb, mfp);
+}
+
+//-------------------------------------------------------------------------------
+//  void WriteMfRecord(long mfb, int mfp, MfRecord &m)
+//
+//  Helper protected method, which writes the Master file record m at address 
+//  (mfb, mfp)   mfb (1:MAXMFB),   mfp (0: MFBLKSIZE)
+//-------------------------------------------------------------------------------
+void  MfFile::WriteMfRecord(long mfb, int mfp, MfRecord &m)
+{
+	m.Write(*this, mfb, mfp);
+} 
+
+
+//--------------------------------------------------------------------------------
+// void CreateMfRecord(MfRecord &m, long &mfb, int &mfp)
+//
+//  Create a new record. The MFN to be assigned is obtained from the field nxtmfn_
+//  in the Master file header. Then addMfRecord is called for adding the record
+//  at the end of the master file, at the position indicated by the fields
+//  nxtmfb_/nxtmfb_. The next MFN to be assigned is updated.
+//
+//--------------------------------------------------------------------------------
+void  MfFile::CreateMfRecord(MfRecord &m, long &mfb, int &mfp)
+{
+}
+
+void  MfFile::AppendNewBlock()
+{
+}
+
+//--------------------------------------------------------------------------------
+// void AddMfRecord(MfRecord &m, long &mfb, int &mfp)
+//
+// Add the record at the end of the master file, at the position indicated by
+// the fields nxtmfb_/nxtmfp_. (nxtmfp_ is in range [1:MFBLKSIZE])
+// Return the address where the record was stored into mfb & mfp
+//--------------------------------------------------------------------------------
+void  MfFile::AddMfRecord(MfRecord &m, long &mfb, int &mfp)
+{
+}
+ 
+ 
+//--------------------------------------------------------------------------------
+// void UpdateMfRecord(MfRecord &m, long &mfb, int &mfp)
+//
+// Update a Master file record.If possible, i.e. if the record length was not
+// increased, the record is written back at its original location otherwise it is
+// written at the end of the file. In both cases, MFBWB/MFBWP are not changed.
+// 
+//--------------------------------------------------------------------------------
+void  MfFile::UpdateMfRecord(MfRecord &m, long &mfb, int &mfp)
+{
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// methods for dumping file and record headers
+
+ 
+void MfFile::PrintMfHdr(SMfHeader &h)
+// Prints header record
+{
+}
+ 
+//////////////////////////////
+ 
+void MfFile::PrintMfRecord(MfRecord &m)
+// Print a master file record structure
+{
+	m.Dump();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Methods for accessing records directly
+ 
+//----------------------------------------------------------------------------------
+// void MfFile::ReadMfRecord(long daddr, MfRecord &m)
+//
+// Reads a master file record into the master record object m.
+// Non blocked version
+//----------------------------------------------------------------------------------
+void MfFile::ReadMfRecord(long daddr, MfRecord &m)
+{
+	m.Clear();
+    ReadLeader(daddr, m);       // Read record leader (Leader is added to record)
+	m.ExtractSubLeader();
+    
+	//TRACE("\nReadMfRecord -- mfn=%ld mfrl=%d", m.GetMfn(), m.GetMfrl());
+	//assert(m.CheckIntegrity());
+	int mfrl = m.GetMfrl();
+	if (mfrl < 0) mfrl = -mfrl; 	// mfrl can be negative!!!!
+	char* p = new char[mfrl];
+    CFileBase::Fetch(p, mfrl, daddr);
+	m.AddToRecord(p+GetLeaderSize(), mfrl-GetLeaderSize());
+	delete[] p;
+    nextaddr_ += mfrl;
+ 	int mfb = nextaddr_ / MFBLKSIZE + 1;
+    int mfp = nextaddr_ % MFBLKSIZE;
+    if (mfp > MFBLKSIZE - GetMinLeaderSize())
+	{
+		mfb++;
+	    mfp = 0;
+	}
+	nextaddr_ = (mfb-1)*MFBLKSIZE + mfp;
+	m.DecomposeRecord();
+}
+
+//---------------------------------------------------------------------------------
+// void  MfFile::WriteMfRecord(long daddr, MfRecord &m)
+//
+// Stores Master record object m to disk address daddr
+// Non blocked version
+//---------------------------------------------------------------------------------
+void  MfFile::WriteMfRecord(long daddr, MfRecord &m)
+{
+}
+/////////////////////////////////////////////////////////////////////////////////////
+// Master file locking methods
+
+
+ 
+//-----------------------------------------------------------------------------------
+// void MfFile::InitFileLockHdr(SMfLockHeader &hdr)
+//
+// Initialize a the lock header for a newly constructed file lock header.
+//-----------------------------------------------------------------------------------
+void MfFile::InitFileLockHdr(SMfLockHeader &hdr)
+{
+	hdr.lockProtect_ = (uint32_t)0;
+	hdr.readLock_    = (uint32_t)0;
+	hdr.writeLock_   = (uint32_t)0;
+}
+
+//-----------------------------------------------------------------------------------
+// FileError MfFile::WriteFileLockHdr(const SMfLockHeader &hdr)
+//
+// Write the lock header to the file. 
+// Returns a non-zero value to indicate an error condition or zero if successful.
+//-----------------------------------------------------------------------------------
+FileError MfFile::WriteFileLockHdr(const SMfLockHeader &hdr)
+{
+	
+	return CFileBase::Store(&hdr, sizeof(SMfLockHeader), sizeof(SMfHeader));
+}
+
+//-----------------------------------------------------------------------------------
+// FileError MfFile::ReadFileLockHdr(SMfLockHeader &hdr)
+//
+// Read the lock header from the file.
+// Returns a non-zero value to indicate an error condition or zero if successful.
+//-----------------------------------------------------------------------------------
+FileError MfFile::ReadFileLockHdr(SMfLockHeader &hdr)
+{
+	
+	return CFileBase::Fetch(&hdr, sizeof(SMfLockHeader), sizeof(SMfHeader));
+}
+
+//-----------------------------------------------------------------------------------
+// int MfFile::LockFile(CFileMgrLockType l_type) 
+//
+// Lock the file and set the lock access mode to shared or exclusive.
+// Returns a non-zero value if the file cannot be locked or the lock variable cannot
+// be changed because it is exclusive or another thread is currently updating it. 
+//-----------------------------------------------------------------------------------
+int MfFile::LockFile(MfLockType l_type) 
+{
+	// Read the file lock to ensure that this file has a lock header
+	// and to keep the header in sync during multiple file access.
+	SMfLockHeader lock_header;
+	if (ReadFileLockHdr(lock_header) != FILE_NO_ERROR)
+		return fileError_;
+	
+	// Cannot modifiy this lock until the thread holding it releases the
+	// lock header.
+	if (lock_header.lockProtect_ != 0)
+	{
+		fileError_ = ISIS_MFLOCK_ACCESS_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+		throw CFileBaseException(fileError_);
+#else
+		return fileError_;
+#endif
+	}
+	
+	switch (l_type)
+	{
+		case MF_WRITE_LOCK :
+			// Cannot obtain an exclusive lock until all the threads in the
+			// read lock queue have finished
+			if ((lock_header.readLock_ != 0) || 
+				(lock_header.writeLock_ != 0))
+			{
+				fileError_ = ISIS_MFLOCK_ERROR;
+	#ifdef __CPP_EXCEPTIONS__
+				throw CFileBaseException(fileError_);
+	#else
+				return fileError_;
+	#endif
+			}
+			else 
+			{
+				lock_header.writeLock_ = 1;
+			}
+			
+			lock_header.lockProtect_ = 1;
+			if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t),
+				sizeof(SMfHeader)) != FILE_NO_ERROR)
+				return fileError_;
+			
+			// Skip over the read lock member
+			SeekTo(sizeof(SMfHeader) + (sizeof(uint32_t) * 2));
+			if (CFileBase::Store(&lock_header.writeLock_, sizeof(uint32_t)) !=
+				FILE_NO_ERROR)
+				return fileError_;
+			
+			lock_header.lockProtect_ = (uint32_t)0;
+			if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t),
+				sizeof(SMfHeader)) != FILE_NO_ERROR)
+				return fileError_;
+			break;
+			
+		case MF_READ_LOCK :
+			// This lock is exclusively owned and cannot be read locked
+			// until the thread holding this lock release the exclusive lock.
+			if (lock_header.writeLock_ == 1)
+			{
+				fileError_ = ISIS_MFLOCK_ERROR;
+	#ifdef __CPP_EXCEPTIONS__
+				throw CFileBaseException(fileError_);
+	#else
+				return fileError_;
+	#endif
+			}
+			
+			if (lock_header.readLock_ < 0xFFFFFFFF)
+			{
+				lock_header.readLock_++;
+			}
+			else 
+			{
+				fileError_ = ISIS_MFLOCK_ERROR;
+	#ifdef __CPP_EXCEPTIONS__
+				throw CFileBaseException(fileError_);
+	#else
+				return fileError_;
+	#endif
+			}
+			
+			lock_header.lockProtect_ = 1;
+			if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t),
+				sizeof(SMfHeader)) != FILE_NO_ERROR)
+				return fileError_;
+			
+			if (CFileBase::Store(&lock_header.readLock_, sizeof(uint32_t)) !=
+				FILE_NO_ERROR)
+				return fileError_; 
+			
+			lock_header.lockProtect_ = (uint32_t)0;
+			if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t),
+				sizeof(SMfHeader)) != FILE_NO_ERROR)
+				return fileError_;
+			break;
+			
+		default: // Invalid lock type specified
+			fileError_ =  ISIS_INVALID_LOCK_TYPE;
+	#ifdef __CPP_EXCEPTIONS__
+			throw CFileBaseException(fileError_);
+	#else
+			return fileError_;
+	#endif
+	}
+	
+	return fileError_ = fileError_ = FILE_NO_ERROR;
+}
+
+//-----------------------------------------------------------------------------------
+// int MfFile::UnlockFile(CFileMgrLockType l_type)
+//
+// Unlock the file. Returns a non-zero value if the file cannot be unlocked or the
+// lock variable cannot be changed because it is exclusive or another thread is
+// currently updating it. 
+//-----------------------------------------------------------------------------------
+int MfFile::UnlockFile(MfLockType l_type)
+{
+	
+	// Read the file lock to ensure that this file has a lock header
+	// and to keep the header in sync during multiple file access.
+	SMfLockHeader lock_header;
+	if (ReadFileLockHdr(lock_header) != FILE_NO_ERROR)
+		return fileError_;
+	
+	// Cannot modifiy this lock until the thread holding it releases the
+	// lock header.
+	if (lock_header.lockProtect_ != 0)
+	{
+		fileError_ = ISIS_MFLOCK_ACCESS_ERROR;
+#ifdef __CPP_EXCEPTIONS__
+		throw CFileBaseException(fileError_);
+#else
+		return fileError_;
+#endif
+	}
+	
+	switch (l_type)
+	{
+		case MF_WRITE_LOCK :
+			if (lock_header.writeLock_ == 0)
+				return FILE_NO_ERROR;
+			else
+				lock_header.writeLock_ = 0;
+			
+			lock_header.lockProtect_ = 1;
+			if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t),
+				sizeof(SMfHeader)) != FILE_NO_ERROR)
+				return fileError_;
+			
+			// Skip over the read lock member
+			SeekTo(sizeof(SMfHeader) + (sizeof(uint32_t) * 2));
+			if (CFileBase::Store(&lock_header.writeLock_, sizeof(uint32_t)) !=
+				FILE_NO_ERROR)
+				return fileError_;
+			
+			lock_header.lockProtect_ = (uint32_t)0;
+			if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t),
+				sizeof(SMfHeader)) != FILE_NO_ERROR)
+				return fileError_;
+			break;
+			
+		case MF_READ_LOCK :
+			if (lock_header.readLock_ == 0)      // This record is not locked
+				return fileError_ = FILE_NO_ERROR;
+			else if (lock_header.readLock_  > 0) // Prevent read lock rollover
+				lock_header.readLock_--;
+			else
+				lock_header.readLock_ = 0;
+			
+			lock_header.lockProtect_ = 1;
+			if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t),
+				sizeof(SMfHeader)) != FILE_NO_ERROR)
+				return fileError_;
+			
+			if (CFileBase::Store(&lock_header.readLock_, sizeof(uint32_t)) !=
+				FILE_NO_ERROR)
+				return fileError_; 
+			
+			lock_header.lockProtect_ = (uint32_t)0;
+			if (CFileBase::Store(&lock_header.lockProtect_, sizeof(uint32_t),
+				sizeof(SMfHeader)) != FILE_NO_ERROR)
+				return fileError_;
+			break;
+			
+		default: // Invalid lock type specified
+			fileError_ =  FMGR_INVALID_LOCK_TYPE;
+	#ifdef __CPP_EXCEPTIONS__
+			throw CFileBaseException(fileError_);
+	#else
+			return fileError_;
+	#endif
+	}
+	
+	return fileError_ = fileError_ = FILE_NO_ERROR;
+}
+
+//-----------------------------------------------------------------------------------
+// FileError MfFile::ResetFileLock()
+//
+// Reset the file's lock header. This function will clear all the file lock fields
+// without testing the lock or the lock protect. Returns a non-zero value to indicate
+// an error condition or zero if successful.
+//-----------------------------------------------------------------------------------
+FileError MfFile::ResetFileLock()
+{
+	SMfLockHeader lock_header;
+	InitFileLockHdr(lock_header);
+	return WriteFileLockHdr(lock_header);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/MFFile.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/MFFile.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/MFFile.h	(revision 10506)
@@ -0,0 +1,318 @@
+/**********************************************************************
+ *
+ * MFFile.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////
+// MFFILE.H: Class definition for blocked I/O on the master
+//           file
+////////////////////////////////////////////////////////////
+ 
+#ifndef _MFFILE_H_
+#define _MFFILE_H_
+#ifndef _MASTER_H_
+#include "Master.h"
+#endif
+#ifndef _BLKFILE_H_
+#include "BlkFile.h"
+#endif
+#include <string>
+
+enum MfLockType
+{
+	MF_READ_LOCK,
+	MF_WRITE_LOCK
+};
+
+struct SMfLockHeader
+{
+	long lockProtect_; // Serialize access to the file lock members
+	long readLock_;    // Shared (or read_only) file lock
+	long writeLock_;   // Exclusive (or write-only) file lock
+
+	SMfLockHeader() : lockProtect_(0), readLock_(0), writeLock_(0)
+	{}
+};
+
+enum  { USERMST=0, MSGMST=1 };
+//  binary  hex
+//  ------  ---
+//  0000    0
+//  0001    1
+//  0010    2
+//  0011    3
+
+class MfAddress
+{
+private:
+	long  m_mfb;
+	short m_mfp;
+	char  m_status;
+public:
+	MfAddress() { m_status = 0x00; }
+	MfAddress(long mfb, short mfp)
+	{ ASSERT(mfb>0); ASSERT(mfp>=0); m_mfb = mfb; m_mfp = mfp; m_status = 0x03; }
+
+	long getMfb()          { ASSERT(m_status & 0x01); return m_mfb; }
+	short getMfp()         { ASSERT(m_status & 0x02); return m_mfp; } 
+
+	void setMfb(long mfb)  { ASSERT(mfb>0);  m_mfb = mfb; m_status |= 0x01; }
+	void setMfp(short mfp) { ASSERT(mfp>=0); m_mfp = mfp; m_status |= 0x02; }
+	bool isValid()         { return (m_status == 0x03); }
+};
+ 
+/////////////////////////////////////////////////////////////////////////
+// Master File header record aggregate structure
+//
+struct  SMfHeader 
+{
+   ISIS_LONG   ctlmfn_;    // Always 0
+   ISIS_LONG   nxtmfn_;    // MFN to be assigned to next record created
+   ISIS_LONG   nxtmfb_;    // Last block number allocated (1st is 1)
+   ISIS_INT    nxtmfp_;    // Offset to next available position in last block (1:MFBLKSIZE)
+   ISIS_INT    mftype_;    // Type of master file (USERMST or MSGMST)
+   ISIS_LONG   reccnt_;
+   ISIS_LONG   mfcxx1_;
+   ISIS_LONG   mfcxx2_;
+   ISIS_LONG   mfcxx3_;
+public:
+   SMfHeader(const char *dbname="");
+   ~SMfHeader()                 { }
+};
+ 
+//--------------------------------------------------------------------------
+// SMfHeader::SMfHeader(const char *dbname /* ="" */)
+//
+// Default constructor, initializes the Master file header to default values
+//--------------------------------------------------------------------------
+inline SMfHeader::SMfHeader(const char *dbname /* ="" */)
+{
+   ctlmfn_ = 0;
+   nxtmfn_ = 1L;
+   nxtmfb_ = 1L;
+   nxtmfp_ = MFCTLLEN+1;
+   mftype_ = USERMST;
+   reccnt_ = mfcxx1_=mfcxx2_=mfcxx3_=0;
+}
+ 
+//////////////////////
+// Master file class
+//
+class MfFile : public BlkFile  
+{
+   friend class IsisDb;
+   friend class MfRecord;
+
+protected:
+   SMfHeader mfh_;            // Header structure
+   long nextaddr_;            // Address of next record
+   char buf_[MFBLKSIZE];      // Buffer to hold 1 Master File block
+   bool hdr_created_;         // True if 1st block exists
+   int  fileError_;
+   long lastWrittenBlock_;
+
+protected:  
+   void WriteMfRecord(long mfb, int mfp, MfRecord &r);
+   void AppendNewBlock();
+
+public:
+   void setNextMfn(long mfn)       // Set MFN to be assigned to next record created
+   { mfh_.nxtmfn_ = mfn; }
+
+protected:
+   void setNextMfb(long nxtmfb_)  // Set last block number allocated (1st is 1)
+   { mfh_.nxtmfb_ = nxtmfb_; }
+   void setNextMfp(int nxtmfp_)   // Set offset to next available position in last block
+   { mfh_.nxtmfp_ = nxtmfp_; }
+   int setm_mftype(int mftype_)     // Set type of master file (USERMST or MSGMST)
+   { mfh_.mftype_ = mftype_; }     
+   virtual void ReadBlk(void* d, long b)  { BlkFile::ReadBlk(d, b);  }
+   virtual void WriteBlk(void* d, long b) { BlkFile::WriteBlk(d, b); }
+   void ReadMfHdr(SMfHeader &h);
+   void ReadMfHdr();
+   void WriteMfHdr(SMfHeader &h);
+   void WriteMfHdr();
+   void SetLastWrittenBlock(long b) { lastWrittenBlock_ = b; }
+public:
+   MfFile();
+   virtual ~MfFile();
+
+   int  OpenMf(const TCHAR* name, FileSystem::AccessMode mode = FileSystem::FILE_READWRITE);
+   int  CreateMf(const TCHAR* name, int MSTtype = USERMST);
+   void CloseMf() { if (ReadyForWriting()) WriteMfHdr(); Close(); }
+
+   // Accessors for the Master File Header
+   long GetNextMfn()        // Get MFN to be assigned to next record created
+   { return mfh_.nxtmfn_; }
+   long GetNextMfb()        // Get last block number allocated (1st is 1)
+   { return mfh_.nxtmfb_; }
+   int GetNextMfp()         // Get offset to next available position in last block
+   { return mfh_.nxtmfp_; }
+   int GetMftype()          // Get type of master file (USERMST or MSGMST)
+   { return mfh_.mftype_; }   
+   SMfHeader& GetSMfHeader() { return mfh_; }
+
+
+   void CreateMfRecord(MfRecord &m, long &mfb, int &mfp);
+   void AddMfRecord(MfRecord &m, long &mfb, int &mfp);
+   void UpdateMfRecord(MfRecord &m, long &mfb, int &mfp);
+   bool ReadMfRecord(long mfb, int mfp, MfRecord &r);
+
+   void ReadMfRecord(long addr, MfRecord &r);
+   void WriteMfRecord(long addr, MfRecord &r);
+   void RewindMf();
+   bool ReadMfNext(MfRecord &r);
+   void WriteMfNext(MfRecord &r);
+   void ReadLeader(long daddr, MfRecord& m)
+   {
+	   m.ReadLeader(*this, daddr);
+   }
+
+
+   void LockMfHdr();
+   void UnlockMfHdr();
+   void LockMfr(long mfn);
+   void UnlockMfr(long mfn);
+
+public: // File lock functions
+	void InitFileLockHdr(SMfLockHeader &hdr);
+	FileError ResetFileLock();
+	FileError WriteFileLockHdr(const SMfLockHeader &hdr);
+	FileError ReadFileLockHdr(SMfLockHeader &hdr);
+	int LockFile(MfLockType l_type = MF_WRITE_LOCK);
+	int UnlockFile(MfLockType l_type = MF_WRITE_LOCK);
+
+
+   void PrintMfRecord(MfRecord &r);
+   void PrintMfHdr(SMfHeader &h);
+   void PrintMfHdr();
+};
+ 
+
+class CMfIterator
+{
+	const MfFile& m_mf;
+	long cur;
+public:
+	CMfIterator(const MfFile& mf) : m_mf(mf) { }
+
+	bool More() const;
+	void Advance();
+
+	MfRecord Current() 
+	{ 
+		MfRecord mfr(NULL);
+		
+		return mfr;
+	}
+};
+
+ 
+//////////////////////////////
+ 
+inline void  MfFile::LockMfHdr()
+//  Locks the master file header record
+{
+	double_t dwPos   = 0;
+	double_t dwCount = sizeof(SMfHeader);
+	//CFile::LockRange(dwPos, dwCount);
+}
+ 
+//////////////////////////////
+ 
+inline void MfFile::UnlockMfHdr()
+//  Unlocks the master file header record
+{
+	double_t dwPos   = 0;
+	double_t dwCount = sizeof(SMfHeader);
+	//CFile::UnlockRange(dwPos, dwCount);
+}
+ 
+//////////////////////////////
+ 
+inline void MfFile::ReadMfHdr()
+//  Reads the master file header record
+{
+   ReadBlk(buf_, 1L);
+   TRACE(_T("\nsizeof(SMfHeader)=%d"), sizeof(SMfHeader));
+   ::MoveMemory(&mfh_, buf_, sizeof(SMfHeader));
+}
+ 
+//////////////////////////////
+ 
+inline void MfFile::WriteMfHdr()
+//  Updates the master file header record
+{
+    if (hdr_created_) 
+	   ReadBlk(buf_, 1L);
+    TRACE(_T("\nsizeof(SMfHeader)=%d"), sizeof(SMfHeader));
+    ::MoveMemory(buf_, &mfh_, sizeof(SMfHeader));
+    WriteBlk(buf_, 1L);
+}
+ 
+ 
+//////////////////////////////
+ 
+inline void MfFile::ReadMfHdr(SMfHeader &h)
+//  Reads the master file header record
+{
+   ReadBlk(buf_, 1L);
+   ::MoveMemory(&h, buf_, sizeof(SMfHeader));
+}
+ 
+//////////////////////////////
+ 
+inline void MfFile::WriteMfHdr(SMfHeader &h)
+//  Updates the master file header record
+{
+   if (hdr_created_)
+	   ReadBlk(buf_, 1L);
+   ::MoveMemory(buf_, &h, sizeof(SMfHeader));
+   WriteBlk(buf_, 1L);
+}
+ 
+ 
+inline void MfFile::PrintMfHdr()
+{
+   PrintMfHdr(mfh_);
+}
+ 
+//////////////////////////////
+ 
+inline bool MfFile::ReadMfNext(MfRecord &r)
+// Reads the next physically record
+{
+	if (nextaddr_ >= CFileBase::FileSize(file_name))
+	    return false;
+   ReadMfRecord(nextaddr_, r);
+   return true;
+}
+ 
+//////////////////////////////
+ 
+inline void MfFile::WriteMfNext(MfRecord &r)
+// Writes physically at next position
+{
+   WriteMfRecord(nextaddr_, r);
+}
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Makefile.in	(revision 10506)
@@ -0,0 +1,33 @@
+prefix	    = @prefix@
+exec_prefix = @exec_prefix@
+bindir	    = @bindir@
+
+CXX	    = @CXX@
+CXXFLAGS    = @CXXFLAGS@
+EXEEXT	    = @EXEEXT@
+
+INSTALL     = @INSTALL@
+
+LDFLAGS     = @LDFLAGS@
+
+ISIS_OBJS   = IsisGdl.o CacheMan.o Checking.o CRC32.o Fdt.o File.o \
+              FileSystem.o IErrors.o IsisDb.o IsisUtil.o Master.o MFFile.o \
+              stdafx.o Unimarc.o XRFFile.o
+
+
+all: IsisGdl$(EXEEXT)
+
+IsisGdl$(EXEEXT): $(ISIS_OBJS)
+	$(CXX) -o IsisGdl$(EXEEXT) $(ISIS_OBJS) $(LDFLAGS)
+
+$(ISIS_OBJS) :%.o :%.cpp
+	$(CXX) -c $(CXXFLAGS) -o $@ $<
+
+install: all
+	$(INSTALL) IsisGdl$(EXEEXT) $(bindir)
+
+clean:
+	rm -f IsisGdl$(EXEEXT) $(ISIS_OBJS)
+
+distclean: clean
+	rm -f Makefile config.status config.cache config.log
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Master.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Master.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Master.cpp	(revision 10506)
@@ -0,0 +1,1071 @@
+/**********************************************************************
+ *
+ * Master.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////
+//  MASTER.CPP: Master file record object methods
+//                                                                        
+////////////////////////////////////////////////////////////
+#include "stdafx.h"
+#include <iomanip>
+#include "XRFFile.h"
+#include "IsisUtil.h" 
+#include "Master.h"
+#include "MFFile.h"
+#include "IsisDb.h"
+#include "Unimarc.h"
+#include <algorithm>
+
+
+using namespace std;
+
+   
+
+char MfRecord::m_buf[MFBLKSIZE];      // Buffer to hold 1 File block
+
+
+
+/////////////////////////////////////////////////////////////////////
+// LeaderAndDirectory methods
+
+int LeaderAndDirectory::GetFieldSize()
+{
+	int field_len = 0;
+	for (int i=0; i!=nvf_; ++i)
+		field_len  += dir_[i].len_;
+	return field_len;
+}
+
+bool LeaderAndDirectory::operator==(const LeaderAndDirectory& rhs) const
+{
+    if (mfn_ != rhs.mfn_)         // Master file number
+		return false;
+    if (mfrl_ != rhs.mfrl_)       // Record length
+		return false;
+	if (mfbwb_ != rhs.mfbwb_)     // Backward pointer block number
+		return false;
+    if (mfbwp_ != rhs.mfbwp_)     // Backward pointer offset
+		return false;
+    if (base_ != rhs.base_)       // Offset to begining of variable fields
+		return false;
+    if (nvf_ != rhs.nvf_)         // Number of directory entries
+		return false;
+    if (status_ != rhs.status_)   // 1 = DELETED
+		return false;
+	for(std::vector<DirEntry>::size_type i=0; i!=nvf_; i++) // Directory
+	{
+		if (dir_[i]!=rhs.dir_[i])
+		    return false;
+	}
+    return true;
+}
+
+bool LeaderAndDirectory::operator!=(const LeaderAndDirectory& rhs) const
+{
+    if (mfn_ != rhs.mfn_)         // Master file number
+		return true;
+    if (mfrl_ != rhs.mfrl_)       // Record length
+		return true;
+	if (mfbwb_ != rhs.mfbwb_)     // Backward pointer block number
+		return true;
+    if (mfbwp_ != rhs.mfbwp_)     // Backward pointer offset
+		return true;
+    if (base_ != rhs.base_)       // Offset to begining of variable fields
+		return true;
+    if (nvf_ != rhs.nvf_)         // Number of directory entries
+		return true;
+    if (status_ != rhs.status_)   // 1 = DELETED
+		return true;
+	for(std::vector<DirEntry>::size_type i=0; i!=nvf_; i++) // Directory
+	{
+		if (dir_[i]!=rhs.dir_[i])
+		    return true;
+	}
+    return false;
+}
+//-------------------------------------------------------------------------------
+// ostream& operator<<(ostream& s, const LeaderAndDirectory& leader_directory)
+//
+// Overloaded instance of the output operator for LeaderAndDirectory objects
+//---------------------------------------------------------------------------------
+cstringstream& operator<<(cstringstream& s, const LeaderAndDirectory& leader_directory)
+{
+	s.write((char *) &leader_directory.mfn_,    sizeof(ISIS_LONG));
+	s.write((char *) &leader_directory.mfrl_,   sizeof(ISIS_INT));
+	s.write((char *) &leader_directory.mfbwb_,  sizeof(ISIS_LONG));
+	s.write((char *) &leader_directory.mfbwp_,  sizeof(ISIS_INT));
+#ifdef UNIX_BIREME
+	ISIS_INT dummy = 0;
+	s.write((char *) &dummy,   sizeof(ISIS_INT));
+#endif
+
+	s.write((char *) &leader_directory.base_,   sizeof(ISIS_INT));
+	s.write((char *) &leader_directory.nvf_,    sizeof(ISIS_INT));
+	s.write((char *) &leader_directory.status_, sizeof(ISIS_INT));
+
+	int n = leader_directory.dir_.size();
+    assert(n==leader_directory.nvf_);	
+	for(vector<DirEntry>::size_type i=0; i!=leader_directory.dir_.size(); i++)
+	{
+	     assert(leader_directory.dir_[i].tag_>0 && leader_directory.dir_[i].tag_<SHRT_MAX);
+		 DirEntry de = leader_directory.dir_[i];
+         s.write((char *) &de, GetDirEntrySize());
+	}
+	
+	return s;
+}
+
+//----------------------------------------------------------------------------------
+// istream& operator>>(istream& s, LeaderAndDirectory& leader_directory)
+//
+// Overloaded instance of the input operator for LeaderAndDirectory objects
+//----------------------------------------------------------------------------------
+cstringstream& operator>>(cstringstream& s, LeaderAndDirectory& leader_directory)
+{
+	if (!s.good()) return s;
+
+	ios::iostate err = ios::goodbit;
+	try
+	{
+		s.read((char *) &leader_directory.mfn_,    sizeof(ISIS_LONG));
+	    s.read((char *) &leader_directory.mfrl_,   sizeof(ISIS_INT));
+	    s.read((char *) &leader_directory.mfbwb_,  sizeof(ISIS_LONG));
+	    s.read((char *) &leader_directory.mfbwp_,  sizeof(ISIS_INT));
+#ifdef UNIX_BIREME
+	    ISIS_INT dummy;
+	    s.read((char *) &dummy,   sizeof(ISIS_INT));
+#endif
+	    s.read((char *) &leader_directory.base_,   sizeof(ISIS_INT));
+	    s.read((char *) &leader_directory.nvf_,    sizeof(ISIS_INT));
+	    s.read((char *) &leader_directory.status_, sizeof(ISIS_INT));
+
+		if (!leader_directory.dir_.empty())
+			leader_directory.dir_.clear();
+
+		// Try to recover if nvf_ = 0
+		if (leader_directory.nvf_==0)
+			leader_directory.nvf_ = (leader_directory.base_ - GetLeaderSize()) / GetDirEntrySize();
+
+		if (leader_directory.nvf_>0)
+		{
+			for(vector<DirEntry>::size_type i=0; i!=leader_directory.nvf_; i++)
+			{
+				DirEntry de;
+		        s.read((char *) &de, GetDirEntrySize());
+			    // Don't check integrity of directory entries here
+			    leader_directory.dir_.push_back(de);
+			}
+
+		}
+	}
+	catch(bad_alloc&)
+	{
+		err |= ios::badbit;
+		ios::iostate exception_mask = s.exceptions();
+		if (  (exception_mask & ios::failbit) &&
+			!(exception_mask & ios::badbit))
+		{
+			s.setstate(err);
+		}
+		else if (exception_mask & ios::badbit)
+		{
+		  s.setstate(err);
+		  // try { s.setstate(err); }
+		  // catch( ios::failure& ) { }
+			throw;
+		
+		}
+	}
+    catch(...)
+	{
+		err |= ios::failbit;
+		ios::iostate exception_mask = s.exceptions();
+		if ( (exception_mask & ios::badbit) &&
+			(err & ios::badbit))
+		{
+			s.setstate(err);
+		}
+		else if (exception_mask & ios::failbit)
+		{
+		  s.setstate(err);
+		  // try { s.setstate(err); }
+		  // catch( ios::failure& ) { }
+			throw;
+
+		}
+	}
+
+	if (err) s.setstate(err);
+	return s;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//
+
+//  void MfRecord::Copy(UMfRecord& rhs)           
+//  {
+//  	Clear();
+//  	pFdt_      = rhs.pFdt_;
+//      state_     = Record_Created;
+	
+//  	// 1 - Prepare the LeaderAndDirectory, directory, end data part
+//  	int n   = 0;
+//  	int pos = 0;
+
+//  	cstring all_fields_mb;
+//      leader_directory_.dir_.clear();	
+//  	all_fields_mb.erase();
+//  	for (vector<int>::size_type i=0; i!=rhs.tags_.size(); ++i)
+//  	{
+//  		bool bRep = false;
+//  		if (rhs.pFdt_)
+//  		{
+//  			if (rhs.pFdt_->GetEntryAt(i).rep)
+//  			   bRep = true;
+//  		}
+//  		// Get the field, all occurences combined
+//  		int tag = rhs.tags_[i];
+//  	    awstring ws;
+//  		bool rc = rhs.GetField(tag, ws);
+//  		vector<awstring> occ;
+//  		if (bRep)
+//  			vector<awstring> occ = SplitOccurences(ws);
+//  		else
+//  			occ.push_back(ws);
+//          // one entry per occurence
+//  		int nocc = occ.size();
+//  		for (vector<awstring>::size_type j=0; j!= nocc; ++j)
+//  		{
+//  			DirEntry de;
+//  			de.tag_ = tag;
+//  			de.pos_ = pos;
+//  			cstring cs; // For storing the unicode string
+//  			de.len_ = UnicodeToCodePage(occ[j], cs);
+//              leader_directory_.dir_.push_back(de);
+//  			all_fields_mb += cs;
+//  			n++;
+//  			pos += occ[j].length();
+			
+//  		}
+//  	}
+
+//  	leader_directory_.nvf_  = n;
+//  	leader_directory_.base_ = GetLeaderSize() + leader_directory_.nvf_*GetDirEntrySize();
+//  	leader_directory_.mfrl_ = ComputeMfrl();
+
+//  	// 2   - Make record
+
+//  	record_.erase(); // Empty the record
+
+//  	// Prepare the binary part, note that this part must be  independent
+//  	// of the character set.
+
+//  	cstringstream ost(std::ios::out | std::ios::binary);   
+//  	ost << leader_directory_;   // Output the LeaderAndDirectory to a string
+
+	
+//  	AddToRecord(ost.str().c_str(), ost.str().length());
+
+//  	// Here comes the part which is dependent from the character set,
+//  	// the data itself.
+//  	AddToRecord((char*)all_fields_mb.c_str(), all_fields_mb.length());
+
+//  	DecomposeRecord();
+//  }
+
+//  MfRecord::MfRecord(const UMfRecord& rhs)     // Copy constructor
+//  { 
+//     Copy(rhs);
+//  }
+
+//  MfRecord& MfRecord::operator=(const UMfRecord& rhs) // Assignment
+//  {
+//     if (&leader_directory_ != &rhs.leader_directory_)
+//     {
+//     	   Copy(rhs);
+//     }
+//     return *this;
+//  }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Accessors
+ 
+ 
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Methods working on the in memory image of the record
+ 
+//-------------------------------------------------------------------------------
+// bool  MfRecord::GetField(int tag, string& s)
+//
+// This function takes as input a tag and will place the field into the string
+// s. It will return true if the field exists and false otherwise.
+//-------------------------------------------------------------------------------
+bool  MfRecord::GetField(int tag, ustring& s)
+{
+	PRECONDITION(tag>=0 && tag < SHRT_MAX);
+
+	map<int, ustring>::iterator it = fields_.find(tag);
+
+	bool ret = false;
+	if (it != fields_.end())
+	{
+		s   = it->second;
+		ret = true;
+	}
+	return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// Modifiers, They synchronize the record structure with the internal structures
+
+
+//---------------------------------------------------------------------------------
+// AddField --- Add a field to the master record structure.
+//            
+//--------------------------------------------------------------------------------- 
+bool MfRecord::AddField(int tag, ustring& s)
+{
+	PRECONDITION(tag>=0 && tag < SHRT_MAX);
+
+	map<int, ustring>::iterator it = fields_.find(tag);
+
+	bool ret = false;
+	if (it == fields_.end())
+	{
+		fields_.insert(make_pair(tag, s));
+		tags_.push_back(tag);
+		sort(tags_.begin(), tags_.end());
+		ret = true;
+		ComposeRecord();
+	}
+	return ret;
+}
+//---------------------------------------------------------------------------------
+// AddOccurence --- Add an occurence to an existing field.
+//--------------------------------------------------------------------------------- 
+bool MfRecord::AddOccurence(int tag, ustring& o)
+{
+	PRECONDITION(tag>=0 && tag < SHRT_MAX);
+
+	map<int, ustring>::iterator it = fields_.find(tag);
+
+	bool ret = false;
+	if (it != fields_.end())
+	{
+	    it->second += SYSRSEP;
+		it->second += o;
+		ret = true;
+		ComposeRecord();
+	}
+	return ret;
+}
+
+//-----------------------------------------------------------------------------
+// bool  MfRecord::DeleteField(int tag)
+//
+//-----------------------------------------------------------------------------
+bool  MfRecord::DeleteField(int tag)
+{
+	PRECONDITION(tag>=0 && tag < SHRT_MAX);
+
+	map<int, ustring>::iterator it = fields_.find(tag);
+
+	bool ret = false;
+	if (it != fields_.end())
+	{
+		fields_.erase(it);
+		ret = true;
+		vector<int>::iterator j = find(tags_.begin(), tags_.end(), tag);
+		if (j != tags_.end())
+			tags_.erase(j);
+		ComposeRecord();
+	}
+	return ret;
+}
+
+//-------------------------------------------------------------------------------
+// bool ReplaceField(int tag, string& s)
+//
+//-------------------------------------------------------------------------------
+bool MfRecord::ReplaceField(int tag, ustring& s)
+{
+    
+	PRECONDITION(tag>=0 && tag < SHRT_MAX);
+
+	map<int, ustring>::iterator it = fields_.find(tag);
+
+	bool ret = false;
+	if (it != fields_.end())
+	{
+		it->second  = s;
+		ret         = true;
+	}
+	else
+		AddField(tag, s);
+	ComposeRecord();
+
+	return ret;
+}
+
+ustring MfRecord::GetAllFields()
+{
+	cstring all_fields; // As a string of ANSI characters
+	all_fields.erase();
+	all_fields = record_.substr(GetBase(), GetFieldSize());
+	return ustring(all_fields);
+}
+
+void MfRecord::ConvertToAnsi()
+{
+	/*
+	int mfrl = GetMfrl();
+	int size1 = record_.length();
+	if (GetFieldSize()==0)
+		return;
+	cstring s = record_.substr(GetBase(), GetFieldSize());
+	CString cs(s.c_str());
+	cs.OemToAnsi();
+	TRACE("\nbase=%d GetFieldSize=%d",GetBase(),GetFieldSize());
+	record_.replace(GetBase(),GetBase()+GetFieldSize(),
+		                                 cs.GetBuffer(GetFieldSize()));
+	int size2 = record_.length();
+	cs.ReleaseBuffer();
+	int padding = size1-size2;
+	for (int i=0; i<padding; i++)
+		record_ += " ";
+*/
+}
+
+long MfRecord::GetDirectorySize()
+{
+	return (GetNvf()*GetDirEntrySize());
+}
+
+long MfRecord::ComputeMfrl()
+{
+	return (GetLeaderSize() + GetDirectorySize() + GetFieldSize());
+}
+
+//--------------------------------------------------------------------------------------
+// void MfRecord::ComposeRecord()
+//
+// Build the record into continuous bytes for output
+//--------------------------------------------------------------------------------------
+void MfRecord::ComposeRecord()
+{
+	PRECONDITION(tags_.size() == fields_.size());
+	
+	// 1 - Prepare the LeaderAndDirectory, directory, end data part
+	int n   = 0;
+	int pos = 0;
+
+	ustring all_fields;
+    leader_directory_.dir_.clear();	
+	all_fields.erase();
+	for (vector<int>::size_type i=0; i!=tags_.size(); ++i)
+	{
+		int tag = tags_[i];
+		bool bRep = false;
+		if (pFdt_)
+		{
+			if (pFdt_->GetEntryAt(i).rep)
+			   bRep = true;
+		}
+		vector<ustring> occ;
+		if (bRep)
+			vector<ustring> occ = SplitOccurences(fields_[tags_[i]]);
+		else
+			occ.push_back(fields_[tags_[i]]);
+        // one entry per occurence
+		int nocc = occ.size();
+		for (vector<ustring>::size_type j=0; j!= nocc; ++j)
+		{
+			DirEntry de;
+			de.tag_ = tag;
+			de.pos_ = pos;
+			de.len_ = occ[j].length();
+            leader_directory_.dir_.push_back(de);
+			all_fields += occ[j];
+			n++;
+			pos += occ[j].length();
+			
+		}
+	}
+
+	leader_directory_.nvf_  = n;
+	leader_directory_.base_ = GetLeaderSize() + leader_directory_.nvf_*GetDirEntrySize();
+	leader_directory_.mfrl_ = ComputeMfrl();
+
+	// 2   - Make record
+
+	record_.erase(); // Empty the record
+
+	// Prepare the binary part, note that this part must be  independent
+	// of the character set.
+
+	cstringstream ost(std::ios::out | std::ios::binary);   
+	ost << leader_directory_;   // Output the LeaderAndDirectory to a string
+
+	
+	AddToRecord(ost.str().c_str(), ost.str().length());
+
+	// Here comes the part which is dependent from the character set,
+	// the data itself.
+	cstring all_fields_ansi(all_fields); 
+	AddToRecord(all_fields_ansi.c_str(), all_fields_ansi.length());
+	
+}
+
+//-------------------------------
+// Helper functions for decompose
+//-------------------------------
+
+bool MfRecord::CheckLeaderAndDirectory()
+{
+	if (GetMfrl() < 0)                  // Negative mfrl
+	{
+		//VLOG("DecomposeRecord -  Warning! Negative mfrl - mfn=%d", GetMfn());
+		SetMfrl(-GetMfrl());
+	}
+
+	if (GetMfrl()<=GetBase())
+	{
+		//VLOG("DecomposeRecord - Error! mfn=%d GetMfrl()=%d > GetBase()=%d", 
+		//	  GetMfn(),  GetMfrl(), GetBase());
+		return false;
+	}
+
+	
+
+	if (GetLeaderSize()>GetBase())
+	{
+		//VLOG("DecomposeRecord - Error! mfn=%d GetLeaderSize()=%d > GetBase()=%d", 
+		//	  GetMfn(),  GetLeaderSize(), GetBase());
+		return false;
+	}
+	if (GetNvf()==0) 
+	{
+	    // Null nvf      
+		//VLOG("DecomposeRecord -  Warning! mfn=%d nvf=0", GetMfn());
+		//SetNvf((GetBase() - GetLeaderSize()) / GetDirEntrySize());
+		return false;
+	}
+
+	if (GetMfn()<=0 || GetMfrl()<=0 || GetBase()<0 || GetNvf()<0 || GetStatus()< 0) 
+	{
+		//VLOG("DecomposeRecord - Error! mfn=%d GetMfrl()=%d GetLeaderSize()=%d GetBase()=%d GetNvf()=%d GetStatus()=%d", 
+		//      GetMfn(), GetMfrl(), GetLeaderSize(), GetBase(), GetNvf(), GetStatus());
+		return false;
+	}
+
+
+	int base = GetLeaderSize() + leader_directory_.nvf_*GetDirEntrySize();
+
+	if (record_.length() <= base)
+	{
+        //VLOG("DecomposeRecord - Error! mfn=%d record_.length()=%d < base=%d",
+		//	 GetMfn(), record_.length(), base);
+		return false;
+	}
+
+	int field_len = 0;
+	for (int i=0; i!=GetNvf(); ++i)
+	{
+		if (GetFieldTag(i)<0 || GetFieldTag(i)>SHRT_MAX ||
+			GetFieldPos(i)<0 || GetFieldPos(i)>SHRT_MAX ||
+			GetFieldLen(i)<0 || GetFieldLen(i)>SHRT_MAX)
+		{
+            //VLOG("DecomposeRecord - Error! mfn=%d Bad dir entry i=%d tag=%d pos=%d len=%d",
+			//    	GetMfn(), GetFieldTag(i), GetFieldPos(i), GetFieldLen(i));
+			return false;
+		}
+		field_len  += GetFieldLen(i);
+	}
+	
+    for (int j=0; j!=GetNvf(); ++j)
+	{
+		if (GetFieldPos(j)>=field_len || GetFieldPos(j)+GetFieldLen(j)>field_len)
+		{
+            //VLOG("DecomposeRecord - Error! mfn=%d Bad dir entry j=%d tag=%d pos=%d len=%d",
+			//    	GetMfn(), GetFieldTag(j), GetFieldPos(j), GetFieldLen(j));
+			return false;
+		}
+	}
+	// Check for bad values
+    if (GetBase() != base)	
+		SetBase(base);
+	
+	if (record_.length() < base + field_len)
+	{
+        //VLOG("DecomposeRecord - Error! mfn=%d record_.length()=%d < base=%d + field_len=%d",
+        //GetMfn(), record_.length(), base, field_len);  
+		return false;
+	}
+	return true;
+}
+
+void MfRecord::MakeTagToFieldMap()
+{
+	cstring all_fields_ansi;
+	all_fields_ansi.erase();
+	all_fields_ansi = record_.substr(leader_directory_.base_, GetFieldSize());
+	PRECONDITION(fields_.empty() && tags_.empty());
+
+
+	// Build the map from tags to fields
+	for (int i=0; i!=GetNvf(); ++i)
+	{
+		//int    all_len = all_fields.length();
+		//if (pos>all_len || pos+len>all_len)
+		//	return false;
+		cstring field_ansi = 
+			   all_fields_ansi.substr(GetFieldPos(i), GetFieldLen(i));
+		ustring field(field_ansi);
+	    map<int, ustring>::iterator it = fields_.find(GetFieldTag(i));
+	    if (it != fields_.end())
+		{
+			// Repeatable field, several occ
+		    it->second += SYSRSEP;
+			it->second += field;
+		}
+		else
+		{
+		    fields_.insert(make_pair(GetFieldTag(i), field));
+			
+		}
+		
+	}
+}
+void MfRecord::MakeTagVector()
+{
+	// Build a vector of tags
+	map<int, ustring>::const_iterator it;
+    for ( it = fields_.begin(); it != fields_.end(); ++it )
+		tags_.push_back(it->first);
+
+	// Sort in ascending order
+	sort(tags_.begin(), tags_.end());
+}
+
+
+//--------------------------------------------------------------------------------------
+// bool MfRecord::DecomposeRecord()
+//
+// Make a memory version of the record to facilitate manipulations.
+//--------------------------------------------------------------------------------------
+bool MfRecord::DecomposeRecord()
+{
+	PRECONDITION(!record_.empty());
+
+	if (record_.length() <= GetLeaderSize())
+	{
+		//VLOG("DecomposeRecord - Error! record_.length()=%d < GetLeaderSize()=%d",record_.length(), GetLeaderSize());
+		return false;
+	}
+
+	// Input the LeaderAndDirectory from a string
+    cstringstream ist(record_,cstringstream::in|cstringstream::binary);
+	if (!(ist >> leader_directory_))
+		return false;
+
+	if (!CheckLeaderAndDirectory())
+	{
+		//VLOG("Record rejected mfn=%ld", GetMfn());
+		return false;
+	}
+
+	//VLOG("Record accepted mfn=%ld", GetMfn());
+
+    MakeTagToFieldMap();
+    MakeTagVector();
+
+	return true;
+}
+
+
+
+void MfRecord::ExtractSubLeader()
+{
+	//PRECONDITION(!record_.empty() && record_.length()>=sizeof(leader_directory_.mfn_)+sizeof(leader_directory_.mfrl_));
+
+	leader_directory_.mfn_  = *(reinterpret_cast<ISIS_LONG*>((char *) record_.c_str()));
+	leader_directory_.mfrl_ = *(reinterpret_cast<ISIS_INT*> ((char *)(record_.c_str()+sizeof(ISIS_LONG))));
+	if (leader_directory_.mfrl_ < 0) leader_directory_.mfrl_ = -leader_directory_.mfrl_; 	// mfrl can be negative!!!!
+
+	//POSTCONDITION(leader_directory_.mfn_>0 && leader_directory_.mfrl_>=0);
+}
+
+bool MfRecord::CheckLeader()
+{
+	int leader_size = GetLeaderSize();
+	if (leader_directory_.mfn_<=0)
+		return false;
+	if (abs(leader_directory_.mfrl_)<leader_size)
+		return false;
+	return true;
+}
+
+
+bool MfRecord::CheckIntegrity()
+{
+	int leader_size = GetLeaderSize();
+	if (leader_directory_.mfn_<=0)
+		return false;
+	if (abs(leader_directory_.mfrl_)<leader_size)
+		return false;
+	if (leader_directory_.nvf_<0)
+		return false;
+	//if (leader_directory_.base_ != leader_directory_size + leader_directory_.nvf_*sizeof(MAXDIRL))
+	//	return false;
+	if (leader_directory_.status_ == 1)
+		return true;
+	else if (leader_directory_.status_ == 0)
+		return true;
+	else
+		return false;
+
+	return true;
+}
+ 
+
+void  MfRecord::Dump()
+{
+
+	ustringstream os;
+    os.str("");
+
+
+    os <<  "\n================= entry in MfRecord::Dump==============";
+    os <<  "\n   MFN      " << GetMfn();
+    os <<  "\n   MFRL     " << GetMfrl();
+    os <<  "\n   MFBWB    " << GetMfbwb();
+    os <<  "\n   MFBWP    " << GetMfbwp();
+    os <<  "\n   BASE     " << GetBase();
+    os <<  "\n   NVF      " << GetNvf();
+    os <<  "\n   STATUS   " << GetStatus();
+ 	//TRACE(os.str().c_str());
+
+
+	for (int i=0; i<GetNvf(); i++)
+	{
+		  ustring stemp;
+		  bool rc = GetField(GetDirEntry(i).tag_, stemp);
+		  int len;
+		  if (rc)
+		  {
+		       len = 50;
+		       if (stemp.length()<len)
+			      len = stemp.length();
+		  }
+		  ustring fld = (rc==false) ? _T("Empty") : stemp.substr(0,len);
+	      os.str("");
+		  os << _T(" tag=") << ISIS_INT(GetDirEntry(i).tag_)
+             << _T(" pos=") << ISIS_INT(GetDirEntry(i).pos_)
+			 << _T(" len=") << ISIS_INT(GetDirEntry(i).len_)
+			 << _T(" ")     << fld.c_str() << std::endl; 
+          TRACE(_T("\n%s"),os.str().c_str());   
+	  }
+
+      TRACE("\n---------------- exit in MfRecord::Dump-------------");
+}
+
+
+
+
+bool MfRecord::CheckRecord()
+{
+	PRECONDITION(!record_.empty());
+
+	if (record_.length() < GetLeaderSize())
+	{
+		TRACE(_T("\nWrong LeaderAndDirectory in record!"));
+		return false;
+	}
+
+    cstringstream ist(record_,cstringstream::in|cstringstream::binary);
+
+	LeaderAndDirectory leader_directory;
+	ist >> leader_directory;
+
+	if (leader_directory.mfrl_ < 0)                  // Negative mfrl
+	{
+		//VLOG("CheckRecord -  Warning! Negative mfrl - mfn=%d", GetMfn());
+	}
+	
+	if (leader_directory.nvf_<=0) 
+	{
+		//VLOG("CheckRecord -  Warning! mfn=%d nvf=0", leader_directory.mfn_);
+	}
+
+	if (leader_directory.mfn_<=0 || leader_directory.mfrl_<=0 ||
+		leader_directory.base_<0 || leader_directory.nvf_ < 0 ||
+		leader_directory.status_ < 0) 
+	{
+		//VLOG("CheckRecord - Corrupted record! leader_directory.mfn_=%d leader_directory.mfrl_=%d leader_directory.base_=%d leader_directory.nvf_=%d leader_directory.status_=%d",
+        //      leader_directory.mfn_, leader_directory.mfrl_,
+		//	  leader_directory.base_, leader_directory.nvf_,
+		//	  leader_directory.status_);
+		return false;
+	}
+
+
+	int base = GetLeaderSize() + GetDirectorySize();
+
+	if (record_.length() < base)
+	{
+		//VLOG("CheckRecord - Corrupted record! mfn=%d record_.length()=%d base=%d",
+		//	  leader_directory.mfn_, record_.length(), base);
+		return false;
+	}
+
+	int field_len = 0;
+	for (int i=0; i!=leader_directory.nvf_; ++i)
+	{
+		DirEntry de = leader_directory.dir_[i];
+//  		if (de.tag_<0 || de.tag_>SHRT_MAX || de.pos_<0 || de.pos_>SHRT_MAX || de.len_<0 || de.len_>SHRT_MAX)
+//  		{
+//  		    //VLOG("CheckRecord - Corrupted record! mfn=%d tag=%d pos=%d len=%d",
+//  			//	  leader_directory.mfn_, de.tag_, de.pos_, de.len_);
+//  			return false;
+//  		}
+		if (i>0)
+		{
+			if(de.pos_ != leader_directory.dir_[i-1].pos_+leader_directory.dir_[i-1].len_)
+			{
+		    //VLOG("CheckRecord - Position not consistent - mfn=%d",
+			//	  leader_directory.mfn_);
+			return false;
+			}
+		}
+		field_len  += de.len_;
+	}
+	
+
+	// Check for bad values
+    if (leader_directory.base_ != base)	
+		leader_directory.base_ = base;
+	
+	if (record_.length() < base + field_len)
+	{
+		    //VLOG("CheckRecord - Corrupted record, record length < base+field_len  - mfn=%ld",
+			//	  leader_directory.mfn_);
+		return false;
+	}
+
+	return true;
+}
+
+void MfRecord::ReadLeader(MfFile& f, long daddr)
+{
+    int leader_size = GetLeaderSize();
+    char* buffer = new char[leader_size];
+    f.Fetch(buffer, leader_size, daddr);  // Read record leader
+    Clear();
+    AddToRecord(buffer, leader_size);
+    delete[] buffer;
+}
+
+bool  MfRecord::Read(MfFile& f, long mfb, int mfp)
+{
+    //TRACE("\nMfFile::ReadMfRecord -- mfb=%ld mfp=%d", mfb, mfp);
+	PRECONDITION(mfb>0 && mfb<=MAXMFB);
+    long  blk;
+    int   mfrr, offs, l;
+
+	try
+	{
+		Clear();
+	    // Save original mfb, mfp pair into m
+	    SetMfbRead(mfb);
+	    SetMfpRead(mfp);
+	    SetState(MfRecord::Record_Read);
+
+	    // Be sure that mfp is in range [0:MFBLKSIZE-1]
+	    mfp = mfp%MFBLKSIZE;
+		assert(mfp>=0 && mfp<MFBLKSIZE);
+        //TRACE("\nMfFile::ReadMfRecord - mfb=%ld mfp=%d", mfb, mfp);
+
+		// 1 - Read block where record starts 
+        f.ReadBlk(m_buf,mfb);                    
+
+        blk = mfb;
+		// 2 - Extract the record leader (Mfn+Mfrl) from the block buffer, the 
+		//     record leader cannot be split on two  consecutive blocks.
+        int len = GetSubLeaderSize(); // Mfn + Mfrl
+		ASSERT(mfp+len<MFBLKSIZE);
+
+        AddToRecord(m_buf+mfp, len); // Move 1st 6 bytes  (Mfn+Mfrl)
+		ExtractSubLeader();
+
+		// 3 - Continue to transfer data for building the MfRecord object
+        int mflen = GetMfrl();                // Get record length
+	    SetMflenRead(mflen);                  // Save it 
+        //TRACE("\nMfFile::readMfRecord - After reading leader mfn=%ld mflen=%d",GetMfn(), mflen);
+        mfrr = mflen - len;                     // Not yet moved
+        l = (mfrr > (f.GetBlockSize()-(mfp+len)))      // What remains to move
+            ? (f.GetBlockSize()-(mfp+len)) : mfrr;         // in this block
+        offs = len;
+        AddToRecord(m_buf+mfp+len, l); // Move-it
+        mfrr -= l;
+        while (mfrr>0)                        // Record continues on next block ?
+		{                
+            f.ReadBlk(m_buf,++blk);             // Yes read next block
+            offs += l;
+            l = (mfrr > f.GetBlockSize()) ? f.GetBlockSize() : mfrr;
+            AddToRecord(m_buf, l); // Move data
+            mfrr -= l;
+		}
+	    //TRACE("\nMfFile::ReadMfRecord -- mfb=%ld mfp=%d nvf=%d", mfb, mfp, GetNvf());
+	}
+	catch (CFileBaseException e)
+	{
+        throw CIsisDbException(ISIS_MF_READ_ERROR, __FILE__, __LINE__);
+	}
+
+	return DecomposeRecord();
+}
+
+
+void  MfRecord::Write(MfFile& f, long mfb, int mfp)
+{
+	TRACE(_T("\nMfFile::writeMfRecord - mfb=%ld mfp=%d"), mfb, mfp);
+	PRECONDITION(mfb>0 && mfb <= MAXMFB);
+	// Be sure that mfp is in range [0:MFBLKSIZE-1]
+	mfp = mfp%MFBLKSIZE;
+	
+    long hiblk = f.GetNextMfb(); // Highest block number in master file
+	
+    int s  = 0;              // Index in master file record [0:mfrl-1]
+    int d  = mfp;            // Index in block buffer [0:bsize-1]
+    long b = mfb;            // Starting block number
+	
+    // Adjust record length
+	int padding = GetMfrl() % MFALIGN;
+	if (padding>0)
+	{
+		SetMfrl(GetMfrl() + padding);
+		for (int i=0; i<padding;i++)
+			AddToRecord(" ", 1);
+	}
+	
+    int mfrl = GetMfrl();
+    TRACE(_T("\nMfFile::writeMfRecord - b=%ld d=%d mfrl=%ld hiblk=%ld"), b, d, mfrl, hiblk);
+    TRACE(_T("\nBefore writing->"));
+	do 
+    {
+		if (b <= hiblk)        
+			f.ReadBlk(m_buf, b);
+		else
+			::memset(m_buf, ' ', MFBLKSIZE);
+		
+		while (d < MFBLKSIZE && s < mfrl)
+			m_buf[d++] = record_.at(s++);
+		if (d >= MFBLKSIZE) 
+		{
+			TRACE(_T("MfFile::WriteMfRecord - Before WriteBlk b=%ld"), b);
+			f.SetLastWrittenBlock(b);
+			f.WriteBlk(m_buf, b++);
+			// Reset m_buf pos
+			d = 0;
+		}
+	} while (s < mfrl);
+	
+    // Write last block
+	if (d == 0)
+		::memset(m_buf, ' ', MFBLKSIZE); // Should be an empty block
+	
+	f.WriteBlk(m_buf, b);       
+	f.SetLastWrittenBlock(b);
+} 
+
+void IntToChar(int value, int width, std::string& s)
+{
+	std::ostringstream ost;
+
+#ifdef _WIN32
+	ost.setf(std::ios_base::right, std::ios_base::adjustfield);
+#endif
+	ost << std::setw(width) 
+		<< std::setfill('0') 
+		<< value;
+	s = ost.str();
+}
+//--------------------------------------------------------------------------------------
+// void MfRecord::MakeISORecord(std::string& s)
+//
+// Build the record into continuous bytes for output
+//--------------------------------------------------------------------------------------
+void MfRecord::MakeISORecord(std::string& s)
+{
+	std::string    tmp;
+
+	MarcLeader l;
+
+	// 1 - Complete the leader (base and record length), output the directory 
+	//     to a string and prepare a string with the data fields
+	int base = MARC_LEADER_LEN + GetNvf()*MARC_DIRENT_LEN + 1;
+	IntToChar(base, 5, tmp);
+	strncpy(l.base_ ,tmp.c_str(),5);
+
+	DirectoryEntry mde;
+	ustring    all_fields;
+	all_fields.erase();
+	ostringstream  osd;     // Output the directory to a string
+	int pos = 0; 
+	for (int i=0; i!=GetNvf(); ++i)
+	{
+		IntToChar(GetFieldTag(i), 3, tmp); 
+		strncpy(mde.tag_,tmp.c_str(),3);
+		int len = GetFieldLen(i)+1;  // Include space for separator
+		IntToChar(len, 4, tmp);
+		strncpy(mde.len_, tmp.c_str(), 4);
+		IntToChar(pos, 5, tmp);
+		strncpy(mde.scp_, tmp.c_str(), 5);
+		osd << mde; 
+		pos += len;
+
+		cstring field = record_.substr(GetBase()+GetFieldPos(i), GetFieldLen(i));
+		all_fields += ustring(field);
+		all_fields += FIELDTERM;
+	}
+	// (+2) ->Field sep at end of directory and record sep
+    int reclen =  MARC_LEADER_LEN + GetNvf()*MARC_DIRENT_LEN + pos +2;
+	IntToChar(reclen, 5, tmp);
+	strncpy(l.lreclen_,tmp.c_str(),5);
+
+
+	ostringstream osl;     // Output the Leader to a string
+	osl << l;
+
+	// 2   - Make record
+	s.erase();       // Empty the record
+    s += osl.str();  // Add the leader
+	s += osd.str();  // Add the directory
+	s += FIELDTERM;  // Separator
+	s += cstring(all_fields); // Data part
+	s += RECTERM;
+		
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Master.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Master.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Master.h	(revision 10506)
@@ -0,0 +1,609 @@
+/**********************************************************************
+ *
+ * Master.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+///////////////////////////////////////                                   */
+//  Master.h: Master File Record object
+///////////////////////////////////////                                   */
+ 
+#ifndef __MASTER_RECORD_H__
+#define __MASTER_RECORD_H__
+
+#include "BlkFile.h"
+#include <vector>
+#include <map>
+#include <sstream>
+
+
+ 
+// Length in bytes of master file header 
+#define MFCTLLEN sizeof(SMfHeader)+sizeof(SMfHeader) // Length in bytes of master file header
+
+const int MFALIGN   =    2;   // Master file record alignment
+const int MFBLKSIZE =  512;   // Master file block size
+ 
+typedef short int ISIS_INT;
+typedef long  int ISIS_LONG;
+
+#ifdef UNIX_BIREME
+    //Length of Leader in master record
+	inline 	int GetLeaderSize()
+	{
+		return (2*sizeof(ISIS_LONG)+6*sizeof(ISIS_INT));
+	}
+    // Mini Leader length guaranteed to be in same block
+	inline 	int GetMinLeaderSize()
+	{ 
+		return (2*sizeof(ISIS_LONG)+4*sizeof(ISIS_INT));
+	}
+#else
+    //Length of Leader in master record
+	inline 	int GetLeaderSize() 
+	{
+		return (2*sizeof(ISIS_LONG)+5*sizeof(ISIS_INT)); 
+	}
+    // Mini Leader length guaranteed to be in same block
+	inline 	int GetMinLeaderSize()
+	{ 
+		return (2*sizeof(ISIS_LONG)+3*sizeof(ISIS_INT));
+	}
+#endif
+
+// Size of Mfn and Mfrl in the leader part
+inline int GetSubLeaderSize() { return sizeof(ISIS_LONG)+sizeof(ISIS_INT); }
+ 
+inline int GetDirEntrySize() { return (3*sizeof(ISIS_INT)); }
+ 
+ 
+const TCHAR SYSRSEP      =  TCHAR('%'); // Repeatable field separator
+const TCHAR SUBFIELD_SEP =  TCHAR('^'); // Subfield separator
+
+////////////////////////////////////////
+// Directory entry aggregate structure
+//
+struct DirEntry  
+{
+   ISIS_INT  tag_;
+   ISIS_INT  pos_;
+   ISIS_INT  len_;
+   DirEntry() 
+	   : tag_(0), pos_(0), len_ (0) {  }
+
+   DirEntry(ISIS_INT tag, ISIS_INT pos, ISIS_INT len)
+	   : tag_(tag), pos_(pos), len_ (len) {  }
+   bool operator==(const DirEntry& rhs) const
+   {
+	   if (tag_!=rhs.tag_ || pos_!=rhs.pos_ || len_!=rhs.len_)
+		   return false;
+	   return true;
+   }
+   bool operator!=(const DirEntry& rhs) const
+   {
+	   if (tag_!=rhs.tag_ || pos_!=rhs.pos_ || len_!=rhs.len_)
+		   return true;
+	   return false;
+   }
+
+};
+ 
+
+//////////////////////////////////////////////////////////////////////////
+// Data Master record aggregate structure
+//
+struct LeaderAndDirectory 
+{
+   ISIS_LONG        mfn_;            // Master file number
+   ISIS_INT         mfrl_;           // Record length
+   ISIS_LONG        mfbwb_;          // Backward pointer block number
+   ISIS_INT         mfbwp_;          // Backward pointer offset
+   ISIS_INT         base_;           // Offset to begining of variable fields
+   ISIS_INT         nvf_;            // Number of directory entries
+   ISIS_INT         status_;         // 1 = DELETED
+   std::vector<DirEntry> dir_;            // Directory
+
+   LeaderAndDirectory()
+   {
+	   Clear();
+   }
+   LeaderAndDirectory(const LeaderAndDirectory& src)
+   {
+	   Copy(src);
+   }
+
+   LeaderAndDirectory& operator=(const LeaderAndDirectory& rhs)
+   {
+	   if (&mfn_ != &rhs.mfn_)
+	   {
+		   Copy(rhs);
+	   }
+	   return *this;
+   }
+
+   void Copy(const LeaderAndDirectory& rhs)
+   {
+	   mfn_    = rhs.mfn_;
+	   mfrl_   = rhs.mfrl_;
+	   mfbwb_  = rhs.mfbwb_;
+	   mfbwp_  = rhs.mfbwp_;
+       base_   = rhs.base_;
+       nvf_    = rhs.nvf_;
+	   status_ = rhs.status_;
+	   dir_    = rhs.dir_;
+   }
+   void Clear()
+   {
+	   mfn_ = mfrl_ = mfbwb_ = mfbwp_ = base_ = nvf_ = status_ = 0;
+	   dir_.clear();
+   }
+
+   bool operator==(const LeaderAndDirectory& rhs) const;
+   bool operator!=(const LeaderAndDirectory& rhs) const;
+   int GetFieldSize();
+};
+
+cstringstream& operator<<(cstringstream& s, const LeaderAndDirectory& leader);
+cstringstream& operator>>(cstringstream& s, LeaderAndDirectory& leader);
+
+////////////////////////////////////////////////////////////
+//
+ 
+/////////////////////////////////
+// Data master file record class
+//
+
+typedef std::map<int, ustring> TAG2FIELD;
+class MfFile;
+class MstFile;
+class IsisDb;
+class ACE_InputCDR;
+class ACE_OutputCDR;
+class UMfRecord;
+
+
+class  MfRecord
+{
+	friend class MfFile;
+	friend class MstFile;
+	friend class IsisDb;
+	friend class UMfRecord;
+    friend int operator>>(ACE_InputCDR& cdr, MfRecord& mfr);
+    friend int operator<<(ACE_OutputCDR& cdr, MfRecord& mfr);
+protected:
+
+	CFdt*                pFdt_;        // Use a copy of the FDT
+	cstring              record_;      // Record in continuous storage
+	                                   // always as ANSI!
+	
+	LeaderAndDirectory           leader_directory_;
+	
+	TAG2FIELD        fields_;
+	std::vector<int> tags_;
+    static char      m_buf[MFBLKSIZE];      // Buffer to hold 1 File block
+
+protected: // Additional data
+	short int state_;         // Record state in memory
+	long      mfb_read_;      // Record was read at Block number [1...]
+	int       mfp_read_;      // Record was read at position in block
+	int       mflen_read_;    // Record length was when record read 
+
+protected:
+   void         Copy(const MfRecord& rhs); 
+   
+   void         AddToRecord(const char* p, int len);
+   int          AddDirEntry(const DirEntry& d);
+   int          AddDirEntry(int tag, int pos, int len);
+   int          DelDirEntry(int i);
+   void         SetMfrl(int mfrl);
+   void         SetMfbwb(long mfbwb);
+   void         SetMfbwp(int mfbwp);
+   void         SetBase(int base);
+   void         SetNvf(int nvf);
+   void         SetStatus(int s);
+   int          SetDirEntry(int i, int tag, int pos, int len);
+   int          SetDirEntry(int i, const DirEntry& d);
+   void         SetMfbRead(long b);
+   void         SetMfpRead(int pos);
+   void         SetMflenRead(int len);
+
+ 
+   void         SetSubLeaderAndDirectory(const char* p, int len);
+
+
+   void         MakeTagToFieldMap();
+   void         MakeTagVector();
+
+   long         ComputeMfrl();
+
+   void         Copy(UMfRecord& rhs);           
+public:
+	enum { Record_Empty, Record_Read, Record_Changed, Record_Created };
+
+public:
+   //-----------------
+   // Public Interface
+   //-----------------
+   MfRecord(CFdt* pFdt=NULL);                // Default constructor   
+   virtual ~MfRecord();                      // Destructor
+
+   MfRecord(const MfRecord& rhs);            // Copy constructor
+   MfRecord& operator=(const MfRecord& rhs); // Assignment
+ 
+   MfRecord(const UMfRecord& umfr);
+   MfRecord& operator=(const UMfRecord& rhs);
+
+   void Clear();
+   void ClearData();
+
+
+   void ReadLeader(MfFile& f, long daddr);
+   bool Read (MfFile& f, long mfb, int mfp);
+   void Write(MfFile& f, long mfb, int mfp);
+
+   void MakeISORecord(std::string& s);
+ 
+   long         GetMfn()           const; // Get MFN
+   int          GetMfrl()          const; // Get Master File Record Length
+   long         GetMfbwb()         const; // Get Master File Backward Block number
+   int          GetMfbwp()         const; // Get Master File Backward block position
+   int          GetBase()          const; // Get Variable fields starting byte
+   int          GetNvf()           const; // Get Number of entries in the directory
+   int          GetStatus()        const; // Get Record Status
+   DirEntry     GetDirEntry(int i) const; // Get a reference to the ieme directory entry
+   int          GetState()         const; // Get record state in memory
+   long         GetMfbRead()       const;
+   int          GetMfpRead()       const;
+   int          GetMflenRead()     const;
+
+   ustring     GetAllFields(); // ANSI or UNICODE
+   cstring     GetRecordAsString() { return record_; }
+   const char* GetRecord()         { return record_.c_str(); }
+   int         GetRecordLength()   { return record_.length(); }
+
+   void        ConvertToAnsi();
+
+
+   bool         GetField(int tag, std::string& s);  // Get field content for field with tag "tag" 
+   bool         AddField(int tag, std::string& s);
+   bool         DeleteField(int tag);
+   bool         ReplaceField(int tag, std::string& s);
+   bool         AddOccurence(int tag, std::string& o);
+
+   int          GetFieldTag(int i);
+   int          GetFieldPos(int i);
+   int          GetFieldLen(int i);
+ 
+   void         SetMfn(long mfn);
+   void         SetState(int s);
+
+   long         GetDirectorySize();
+   int          GetFieldSize()     { return leader_directory_.GetFieldSize(); }
+
+   std::vector<int>  GetFieldTags(); // Get tags of fields in increasing order,
+                                     // Occurences made only 1 field
+   void         ExtractSubLeader();
+   void         ExtractLeader();
+   bool         CheckIntegrity();
+   bool         CheckLeader();
+   bool         CheckLeaderAndDirectory(); 
+
+   bool operator==(const MfRecord& rhs) const
+   {
+	   return (record_ == rhs.record_); 
+   }
+   bool operator!=(const MfRecord& rhs) const
+   {
+	   return (record_ != rhs.record_); 
+   }
+
+   void         SetRecord(const char *s) { record_ = s;  DecomposeRecord();}
+   void         SetRecord(const cstring &s) 
+				{ record_ = s;  DecomposeRecord();}
+   void         ComposeRecord();
+   bool         DecomposeRecord();
+
+   bool         CheckRecord();
+   void         Dump();
+} ;
+ 
+//////////////////////////////
+ 
+
+
+
+inline void MfRecord::AddToRecord(const char* p, int len)
+{
+	record_ += cstring(p,len);
+} 
+
+/////////////////////////////
+
+inline MfRecord::MfRecord(CFdt* pFdt) 
+// Makes a Master file Record object
+{
+	Clear();
+	pFdt_ = pFdt;
+   // Nothing more to do
+}
+ 
+inline void MfRecord::Copy(const MfRecord& rhs)           
+{
+   record_     = rhs.record_;
+   leader_directory_     = rhs.leader_directory_;
+   fields_     = rhs.fields_;
+   state_      = rhs.state_;
+   mfb_read_   = rhs.mfb_read_;
+   mfp_read_   = rhs.mfp_read_;
+   mflen_read_ = rhs.mflen_read_;
+   tags_       = rhs.tags_;         
+	pFdt_      = rhs.pFdt_;
+}
+
+inline MfRecord::MfRecord(const MfRecord& rhs)     // Copy constructor
+{ 
+   Copy(rhs);
+}
+
+inline MfRecord& MfRecord::operator=(const MfRecord& rhs) // Assignment
+{
+   if (&leader_directory_ != &rhs.leader_directory_)
+   {
+   	   Copy(rhs);
+   }
+   return *this;
+}
+ 
+inline void MfRecord::Clear()
+{
+   tags_.clear();
+   record_.erase();
+   leader_directory_.Clear();
+   fields_.clear();
+   SetBase(GetLeaderSize());
+   SetMfrl(GetLeaderSize());
+   state_ = Record_Empty;
+   mfb_read_ = mfp_read_ = mflen_read_ = 0;
+   pFdt_ = NULL;
+}
+
+// Clear the data part but keep other info intact so that
+// it appears as an empty record
+inline void MfRecord::ClearData()
+{
+   tags_.clear();
+   record_.erase();
+   leader_directory_.Clear();
+   fields_.clear();
+   SetBase(GetLeaderSize());
+   SetMfrl(GetLeaderSize());
+}
+
+
+//////////////////////////////
+ 
+inline MfRecord::~MfRecord()
+{
+}
+ 
+//////////////////////////////
+ 
+inline long MfRecord::GetMfn() const
+// Returns Master file number
+{
+   return leader_directory_.mfn_;
+}
+ 
+//////////////////////////////
+ 
+inline int MfRecord::GetMfrl() const
+// Returns Master file record length
+{
+   return leader_directory_.mfrl_;
+}
+ 
+//////////////////////////////
+ 
+inline long MfRecord::GetMfbwb() const
+// Returns backward pointer block number
+{
+   return leader_directory_.mfbwb_;
+}
+ 
+//////////////////////////////
+ 
+inline int MfRecord::GetMfbwp() const
+// Returns backward pointer offset
+{
+   return leader_directory_.mfbwp_;
+}
+ 
+//////////////////////////////
+ 
+inline int MfRecord::GetBase() const
+// Returns base value to field data
+{
+    return leader_directory_.base_;
+}
+ 
+//////////////////////////////
+ 
+inline int MfRecord::GetNvf() const
+// Returns the number of directory entries
+// in the master file record
+{
+   return leader_directory_.nvf_;
+}
+
+//////////////////////////////
+ 
+inline int MfRecord::GetStatus() const
+// Returns the status of the record
+{
+   return leader_directory_.status_;
+}
+
+//////////////////////////////
+ 
+ 
+//////////////////////////////
+ 
+inline DirEntry MfRecord::GetDirEntry(int i) const
+// Returns the ith dir entry
+{
+   return leader_directory_.dir_[i];
+} 
+
+//////////////////////////////
+ 
+inline int MfRecord::GetState() const
+{
+   return state_;
+} 
+
+//////////////////////////////
+ 
+inline long MfRecord::GetMfbRead() const
+{
+   return mfb_read_;
+} 
+//////////////////////////////
+ 
+inline int MfRecord::GetMfpRead() const
+{
+   return mfp_read_;
+} 
+    
+//////////////////////////////
+ 
+// Get tags of fields in increasing order,
+inline std::vector<int> MfRecord::GetFieldTags()
+{
+	PRECONDITION(tags_.size() == fields_.size());
+	return tags_;
+}
+//////////////////////////////
+ 
+inline int MfRecord::GetMflenRead() const
+{
+   return mflen_read_;
+} 
+    
+///////////////////////////////////////////////////////////////////////////////
+ 
+inline void MfRecord::SetMfn(long mfn)
+// Set Master file number
+{
+	assert(mfn>0);
+    leader_directory_.mfn_ = mfn;
+}
+//////////////////////////////
+ 
+inline void MfRecord::SetMfrl(int mfrl)
+// Set Master file record length
+{
+	assert(mfrl>0);
+    leader_directory_.mfrl_ = mfrl;
+}
+//////////////////////////////
+ 
+inline void MfRecord::SetMfbwb(long mfbwb)
+// Sets backward pointer block number to mfbwb
+{
+	assert(mfbwb>=0);
+    leader_directory_.mfbwb_ = mfbwb;
+}
+
+//////////////////////////////
+ 
+inline void MfRecord::SetMfbwp(int mfbwp)
+// Sets backward pointer block offset to mfbwp
+{
+	assert(mfbwp>=0);
+    leader_directory_.mfbwp_ = mfbwp;
+}
+//////////////////////////////
+ 
+inline void  MfRecord::SetBase(int base)
+// Sets the base value in the record aggregate
+{
+	assert(base>=0);
+    leader_directory_.base_ = base;
+}
+
+//////////////////////////////
+ 
+inline void MfRecord::SetNvf(int nvf)
+// Sets the number of entries in the directory part
+{
+	assert(nvf>=0);
+    leader_directory_.nvf_ = nvf;
+}
+ 
+//////////////////////////////
+ 
+inline void MfRecord::SetStatus(int s)
+// Sets the status of the record
+{
+   leader_directory_.status_ = s;
+}
+ 
+//////////////////////////////
+ 
+inline void MfRecord::SetState(int s)
+// Sets the status of the record
+{
+	assert(s==MfRecord::Record_Empty || s==MfRecord::Record_Read 
+		|| s==MfRecord::Record_Changed || s==MfRecord::Record_Created);
+   state_ = s;
+}
+
+inline void MfRecord::SetMfbRead(long b)
+{
+	mfb_read_ = b;
+}
+
+inline void MfRecord::SetMfpRead(int pos)
+{
+	mfp_read_ = pos;
+}
+
+inline void MfRecord::SetMflenRead(int len)
+{
+	mflen_read_ = len;
+}
+
+inline int MfRecord::GetFieldTag(int i)
+{
+	return leader_directory_.dir_[i].tag_;
+}
+inline int MfRecord::GetFieldPos(int i)
+{
+	return leader_directory_.dir_[i].pos_;
+}
+
+inline int MfRecord::GetFieldLen(int i)
+{
+	return leader_directory_.dir_[i].len_;
+}
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Unimarc.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Unimarc.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Unimarc.cpp	(revision 10506)
@@ -0,0 +1,620 @@
+/**********************************************************************
+ *
+ * Unimarc.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "stdafx.h"
+
+///////////////////////////////////////////////////////////////////////////////////
+// MarcRecord - This class can instantiate objects that represent a MARC
+//              bibilographic record and includes methods for manipulating the 
+//              record.
+//
+//             example:
+//
+//	#include "Unimarc.h"
+//
+//     // Create a MarcRecord object with a raw MARC record
+//     MarcRecord mr(buf,1)
+//     mr.PrettyFormat("The title is %245, which is the field with tag 245");
+#include <vector>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "Unimarc.h"
+
+//-------------------------------------------------------------------------------
+// ostream& operator<<(ostream& s, const MarcLeader& leader)
+//
+// Overloaded instance of the output operator for MarcLeader objects
+//---------------------------------------------------------------------------------
+std::ostream& operator<<(std::ostream& s, const MarcLeader& leader)
+{
+	s.write(leader.lreclen_, 5);	// Logical record length
+	s.write(&leader.status_, 1);	// Record status  
+	s.write(&leader.type_, 1);		// Type of record
+	s.write(&leader.bibLevel_, 1);	// Bibliographic level
+	s.write(&leader.ctrlType_, 1);	// Type of control
+	s.write(&leader.undPos_, 1);	// Undefined character position
+	s.write(&leader.indCount_, 1);	// Indicator count
+	s.write(&leader.scd_, 1);		// Subfield code count
+	s.write(leader.base_, 5);   	// Base address of data
+	s.write(&leader.encLevel_, 1);	// Encoding level
+	s.write(&leader.dcf_, 1);		// Descriptive cataloging form
+	s.write(&leader.lrr_, 1);		// Linked record requirement
+	  // Directory  entry map
+	s.write(&leader.llof_, 1);		// Length of the length-of-field portion
+	s.write(&leader.lscp_, 1);		// Length of starting-character-position portion
+	s.write(&leader.lidp_, 1);		// Length of implementation-defined portion
+	s.write(&leader.uep_, 1);		// Undefined entry map character position
+	return s;
+}
+
+//----------------------------------------------------------------------------------
+// istream& operator>>(istream& s, const MarcLeader& leader)
+//
+// Overloaded instance of the input operator for MarcLeader objects
+//----------------------------------------------------------------------------------
+std::istream& operator>>(std::istream& s, MarcLeader& leader)
+{
+	s.read(leader.lreclen_, 5);	    // Logical record length
+	s.read(&leader.status_, 1);	    // Record status  
+	s.read(&leader.type_, 1);		// Type of record
+	s.read(&leader.bibLevel_, 1);	// Bibliographic level
+	s.read(&leader.ctrlType_, 1);	// Type of control
+	s.read(&leader.undPos_, 1);	    // Undefined character position
+	s.read(&leader.indCount_, 1);	// Indicator count
+	s.read(&leader.scd_, 1);		// Subfield code count
+	s.read(leader.base_, 5);   	    // Base address of data
+	s.read(&leader.encLevel_, 1);	// Encoding level
+	s.read(&leader.dcf_, 1);		// Descriptive cataloging form
+	s.read(&leader.lrr_, 1);		// Linked record requirement
+	  // Directory  entry map
+	s.read(&leader.llof_, 1);		// Length of the length-of-field portion
+	s.read(&leader.lscp_, 1);		// Length of starting-character-position portion
+	s.read(&leader.lidp_, 1);		// Length of implementation-defined portion
+	s.read(&leader.uep_, 1);		// Undefined entry map character position
+	return s;
+}
+
+/************************************************************************
+Local prototypes
+ ***********************************************************************/
+static void Printx(FILE *fp, char *s, int x);
+
+//----------------------------------------------------------------------
+// MarcRecord::MarcRecord(char *data, int length, int copyData)
+// 
+// Constructor that creates a new MarcRecord object. 
+// data is raw marc record data for a single record.  If copyData is 1, 
+// data is encapsulated within this object.  If 0, does not copy data and 
+// responsibility falls to caller to maintain data pointer.
+//----------------------------------------------------------------------
+MarcRecord::MarcRecord(char* data, int length, int copyData)
+{
+	encapsulated_ = copyData;
+	
+	/* encapsulate or set pointer to data */
+	if (encapsulated_)
+	{
+		data_ = new char[length + 1]; 
+		memcpy(data_, data, length);
+		data_[length] = '\0';
+	}
+	else
+		data = data;
+	
+	// Lay leader overlay onto data
+	leader_ = *(MarcLeader *) (data_);
+	
+	// Parse the record.  sets dirCount_, directory_ 
+	if (!ParseMarcRecord()) 
+	{
+		// marcRecord_destroy(m);
+		// return NULL;
+	}
+}
+
+//----------------------------------------------------------------------
+// void MarcRecord::~MarcRecord()
+//
+// Destructor, destroys a MarcRecord object and all used resources.
+//----------------------------------------------------------------------
+MarcRecord::~MarcRecord()
+{
+	if ((encapsulated_) && (data_))
+		delete[] data_;
+
+	for (std::vector<MarcDirectoryEntry>::size_type i=0; i!=directory_.size(); ++i)
+		directory_[i].field_.erase(directory_[i].field_.begin(),directory_[i].field_.end());
+	directory_.erase(directory_.begin(),directory_.end());
+}
+
+#define MARC_STATE_IDLE 0
+#define MARC_STATE_TAG 1
+#define MARC_STATE_WIDTH 2
+//----------------------------------------------------------------------
+// int MarcRecord::PrettyFormat(char* format, char* buf, int maxlen)
+//
+//  Formats the contents of the marc record according to a format string.
+//  Useful for generating a buffer to pretty-print the record.
+//  format contains a format-specifier string.  The format-specifier string
+//  is kindof like printf's, except the only control character is '%'.
+//  Following the '%' should be the integer MARC field code as defined in 
+//  the (huge) list of available MARC fields from the library of congress
+//  (http://lcweb.loc.gov/marc/).  buf is a previously allocated 
+// buffer into which the pretty version will be copied.  maxlen is the max 
+// length to write into buf.  After call, buf contains pretty formatted text.
+//----------------------------------------------------------------------
+int MarcRecord::PrettyFormat(char* format, char* buf, int maxlen)
+{
+	char b[1024];
+	int bufpos = 0, fmtpos = 0;
+	
+	b[0] = '\0';
+	buf[0] = '\0';
+	
+	for (; format[fmtpos] != '\0'; )
+	{
+		switch (format[fmtpos])
+		{
+			case '%': 
+				{
+					char tag[4];
+					strncpy(tag, (char *)(format + fmtpos + 1), 3);
+					tag[3] = '\0';
+					GetSubField(tag, format[fmtpos + 4], b,	sizeof(b) - 1);
+					if (*b)
+					{
+						int l = strlen(b);
+						strncat(buf, b, maxlen - bufpos - 1);
+						bufpos += l;
+						if (bufpos >= maxlen)
+						{
+							buf[maxlen - 1] = '\0';
+							return maxlen;
+						}
+					}
+					fmtpos += 5;
+					break;
+				}
+			default:
+				buf[bufpos] = format[fmtpos];
+				bufpos++;
+				fmtpos++;
+				buf[bufpos] = '\0';
+				break;
+		}
+	}
+	return bufpos;
+}
+
+//----------------------------------------------------------------------
+// int MarcRecord::GetField(char* tag, char* buf, int maxlen)
+//
+// append all subfields in a field together. 
+//----------------------------------------------------------------------
+int MarcRecord::GetField(char* tag, char* buf, int maxlen)
+{
+	int remain = maxlen - 1;
+	
+	buf[0] = '\0';
+	
+	if ((tag == NULL) || (*tag == '\0'))
+		return 0;
+	
+	for (std::vector<MarcDirectoryEntry>::size_type i=0; i!=directory_.size(); ++i)
+	{
+		if (!strncmp(tag, directory_[i].tag_, strlen(tag)))
+		{
+			for (std::vector<MarcField>::size_type j=0; j!=directory_[i].field_.size(); ++j)
+			{
+				int flen = directory_[i].field_[j].len_;
+				if (flen > remain)
+				{
+					strncat(buf, directory_[i].field_[j].data_ + 1, remain);
+					buf[maxlen] = '\0';
+					return 1;
+				}
+				else 
+				{
+					strncat(buf, directory_[i].field_[j].data_ + 1, flen);
+					remain -= flen;
+				}
+			}
+			return 1;
+		}
+	}
+	return 0;
+}
+
+//----------------------------------------------------------------------
+// int MarcRecord::GetSubFields(char* tag, char subtag, char* buf, int maxlen)
+//
+// append all fields with a certain subfield together.
+//----------------------------------------------------------------------
+int MarcRecord::GetSubFields(char* tag, char subtag, char* buf, int maxlen)
+{
+	int remain = maxlen - 1;
+	
+	buf[0] = '\0';
+	
+	if ((tag == NULL) || (*tag == '\0'))
+		return 0;
+	
+	for (std::vector<MarcDirectoryEntry>::size_type i=0; i!=directory_.size(); ++i)
+	{
+		if (!strncmp(tag, directory_[i].tag_, strlen(tag)))
+		{
+			for (std::vector<MarcField>::size_type j=0; j!=directory_[i].field_.size(); ++j)
+			{
+				if (*(directory_[i].field_[j].data_) == subtag)
+				{
+					int flen = directory_[i].field_[j].len_;
+					if (flen > remain)
+					{
+						strncpy(buf, directory_[i].field_[j].data_ + 1, remain);
+						buf[maxlen] = '\0';
+						return 1;
+					}
+					else 
+					{
+						strcpy(buf, directory_[i].field_[j].data_ + 1);
+						remain -= flen;
+					}
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+int MarcRecord::HasField(char* tag)
+{
+	
+	for (std::vector<MarcDirectoryEntry>::size_type i=0; i!=directory_.size(); ++i)
+		if (!strncmp(tag, directory_[i].tag_, strlen(tag)))
+			return 1;
+		
+		return 0;
+}
+
+int MarcRecord::HasSubField(char* tag, char subtag)
+{
+	
+	for (std::vector<MarcDirectoryEntry>::size_type i=0; i!=directory_.size(); ++i)
+		if (!strncmp(tag, directory_[i].tag_, strlen(tag)))
+			for (std::vector<MarcField>::size_type j=0; j!=directory_[i].field_.size(); ++j)
+				if (*directory_[i].field_[j].data_ == subtag)
+					return 1;
+				return 0;
+}
+
+int MarcRecord::GetSubField(char *tag, char subtag, char *buf, 	int maxlen)
+{
+	
+	buf[0] = '\0';
+	
+	if ((tag == NULL) || (*tag == '\0'))
+		return 0;
+	
+	for (std::vector<MarcDirectoryEntry>::size_type i=0; i!=directory_.size(); ++i)
+	{
+		if (!strncmp(tag, directory_[i].tag_, strlen(tag)))
+		{
+			for (std::vector<MarcField>::size_type j=0; j!=directory_[i].field_.size(); ++j)
+			{
+				if (*(directory_[i].field_[j].data_) == subtag)
+				{
+					int l = directory_[i].field_[j].len_ - 1 > maxlen ? maxlen : directory_[i].field_[j].len_ - 1;
+					strncpy(buf, directory_[i].field_[j].data_ + 1, l);
+					buf[l] = '\0';
+					return 1;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+
+int GetNum(char *s, int n)
+{
+	char nbuf[10]; /* no more than 9 digits */
+	
+	strncpy(&nbuf[0], s, n);
+	nbuf[n] = '\0';
+	return (atoi(nbuf));
+}
+
+void MarcRecord::Dump()
+{
+	int dc = 0, fc = 0;
+	
+	printf("tags: ");
+	for (std::vector<MarcDirectoryEntry>::size_type i=0; i!=directory_.size(); ++i)
+	{
+		Printx(stdout, directory_[i].tag_, 3);
+		dc++;
+		for (std::vector<MarcField>::size_type j=0; j!=directory_[i].field_.size(); ++j)
+		{
+			if (directory_[i].field_[j].data_)
+			{
+				putchar((int)directory_[i].field_[j].data_);
+			}
+			fc++;
+			/*
+			printx(stdout, (char*)f->data + 1, f->len);
+			printf("\n"); */
+		}
+		printf(",");
+	}
+	putchar('\n');
+}
+
+
+
+
+
+void MarcRecord::PrintDetailed(FILE *fp)
+{
+	int count, i;
+	
+	fprintf(fp, "RecordLength:\t\t%i\n", GetNum(leader_.lreclen_, 5));
+	fprintf(fp, "RecordStatus:\t\t%c\n", leader_.status_);
+	fprintf(fp, "RecordType:\t\t%c\n", leader_.type_);
+	fprintf(fp, "BibLevel:\t\t%c\n", leader_.bibLevel_);
+	fprintf(fp, "ControlType:\t\t%c\n", leader_.ctrlType_);
+	fprintf(fp, "UndefCharPos:\t\t%c\n", leader_.undPos_);
+	fprintf(fp, "IndCount:\t\t%i\n", GetNum(&leader_.indCount_, 1));
+	fprintf(fp, "SubCodeCount:\t\t%i\n", GetNum(&leader_.scd_, 1));
+	fprintf(fp, "DataBaseAddr:\t\t%i\n", GetNum(leader_.base_, 5));
+	fprintf(fp, "EncodingLevel:\t\t%c\n", leader_.encLevel_);
+	fprintf(fp, "DescCatForm:\t\t%c\n", leader_.dcf_);
+	fprintf(fp, "LinkedRecReq:\t\t%c\n", leader_.lrr_);
+	fprintf(fp, "LengthOf LengthOfField:\t%i\n", GetNum(&leader_.llof_, 1));
+	fprintf(fp, "LengthOf StartCharPos:\t%i\n", GetNum(&leader_.lscp_, 1));
+	fprintf(fp, "LengthOf ImpDefined:\t%i\n", GetNum(&leader_.lidp_, 1));
+	fprintf(fp, "UndefinedEntry:\t\t%i\n", GetNum(&leader_.uep_, 1));
+	
+	count = (GetNum(leader_.base_, 5) - MARC_LEADER_LEN) / MARC_DIRENT_LEN;
+	for (i = 0; i < count; i++)
+	{
+		DirectoryEntry dir = *(DirectoryEntry*)(data_+MARC_LEADER_LEN+(i*MARC_DIRENT_LEN));
+		fprintf(fp, "\n");
+		fprintf(fp, "Tag:\t\t");
+		Printx(fp, dir.tag_, 3);
+		fprintf(fp, "\nLength:\t\t%i\n", GetNum(dir.len_, 4));
+		fprintf(fp, "StartPos:\t%i\n", GetNum(dir.scp_, 5));
+		fprintf(fp, "Data:\t\t");
+		Printx(fp, (char *)(data_ + GetNum(leader_.base_, 5) + GetNum(dir.scp_, 5)), GetNum(dir.len_, 4));
+		fprintf(fp, "\n");
+	}
+}
+
+/*
+desc:		parses the marc record and builds appropriate data structures in m
+
+params:
+
+	m		newly created marcRecord
+	
+returns:
+
+	1 on success
+	0 on parse or memory failure
+*/
+int MarcRecord::ParseMarcRecord()
+{
+	dirCount_ = (GetNum(leader_.base_, 5) - MARC_LEADER_LEN) / MARC_DIRENT_LEN;
+	
+	// For each MarcDirectory entry, create list of subfields
+	MarcDirectoryEntry dir_entry;
+	for (int i = 0; i < dirCount_; i++)
+	{
+		char*  data;
+		// Extract the directory component
+		DirectoryEntry dir_entry = *(DirectoryEntry*)(data_+MARC_LEADER_LEN+(i*MARC_DIRENT_LEN));
+
+		MarcDirectoryEntry marc_dir_entry;
+		
+		// Get a pointer to the data for this MarcDirectory
+		data = (char *)(data_ + GetNum(leader_.base_, 5) + GetNum(dir_entry.scp_, 5));
+		
+		// set the tag for this MarcDirectory 
+		marc_dir_entry.tag_ = dir_entry.tag_;
+		
+		/* add the list of subfields for this MarcDirectory */
+		if (!AddSubFields(marc_dir_entry, data))
+			return 0;
+		directory_.push_back(marc_dir_entry);
+		
+	}
+	
+	return 1;
+}
+
+void Printx(FILE* fp, char* s, int x)
+{
+	int i;
+	for (i = 0; i < x; i++)
+		fprintf(fp, "%c", s[i]);
+}
+
+//----------------------------------------------------------------------
+// int MarcRecord::AddSubFields(MarcDirectory& d, char* b)
+//
+// Parses and adds subfields to MarcDirectory
+//
+// params:
+//
+//	d		MarcDirectory to which subfields are added
+//	b		buffer of data for d
+//
+// returns:
+//
+//	1 on success
+//	0 on parse or memory error
+//----------------------------------------------------------------------
+int MarcRecord::AddSubFields(MarcDirectoryEntry& d, char* b)
+{
+	char *p, *start;
+	int cont = 1, length = 0;
+	
+	/* create new field */
+	MarcField field;
+	
+	
+	start = b;
+	for (p = b; ((*p != '\0') && (cont == 1)); p = (char *)p + 1)
+	{
+		switch (*p)
+		{
+			case SUBFDELIM:
+				/* end of current subfield, but more exist */
+				
+				/* set length and pointer to data for this field */
+				field.len_  = length;
+				field.data_ = start;
+				d.field_.push_back(field);
+				/* by definition, there should be more subfields, but we'll
+				check for NULL just in case
+				*/
+				if (*p + 1)
+				{
+				}
+				else 
+				{
+					/* uh oh */
+					return 0;
+				}
+				length = 0;
+				start = (char *)p + 1;
+				break;
+			case FIELDTERM:
+				/* end of subfield list */
+				
+				/* set length and pointer to data for this field */
+				field.len_  = length;
+				field.data_ = start;
+				d.field_.push_back(field);
+				
+				/* break out of loop */
+				cont = 0;
+				break;
+			case RECTERM:
+				/* end of record */
+				cont = 0;
+				break;
+			default:
+				/* regular character */			
+				length++;
+				break;
+		}
+	}
+	return 1;
+}
+
+void MarcRecord::Format(char *buf, int maxlen, int format)
+{
+	char b[1024];
+	char date[24];
+	char title[128];
+	
+	b[0] = '\0';
+	buf[0] = '\0';
+	
+	/* FIXME: get rid of this debugging crap sometime */
+	Dump();
+	
+	switch (format)
+	{
+		case MARC_FMT_BRIEF: 
+			{
+				GetSubField("245", 'a', title, 	sizeof(title) - 1);
+				GetSubField("260", 'c', date, sizeof(date) - 1);
+				if ((strlen(date) + strlen(title) + 2) <=(size_t)maxlen)
+				{
+					sprintf(buf, "%s %s", date, title);
+				}
+				else 
+				{
+					/* FIXME: we're overflowing the buffer! */
+				}
+				break;
+			}
+		case MARC_FMT_FULL: 
+			{
+				int dc = 0, fc = 0;
+				int remain = maxlen;
+				
+	            for (std::vector<MarcDirectoryEntry>::size_type i=0; i!=directory_.size(); ++i)
+				{
+					dc++;
+		            for (std::vector<MarcField>::size_type j=0; j!=directory_[i].field_.size(); ++j)
+					{
+						fc++;
+						if ((directory_[i].field_[j].len_ + 2) > remain)
+						{
+							strncat(buf, (char *)directory_[i].field_[j].data_ + 1, remain - 2);
+							* (buf + remain - 2) = '\n';
+							* (buf + remain - 1) = '\0';
+							/* we're out of room in the buffer. */
+							return;
+						}
+						if (directory_[i].field_[j].len_ > 0)
+						{
+							strncat(buf, (char*)directory_[i].field_[j].data_ + 1, directory_[i].field_[j].len_);
+							strncat(buf, "\n\0", 2);
+							remain -=(directory_[i].field_[j].len_ + 2);
+						}
+					} 
+				}
+				/*
+				marcRecord_getSubField(m, "245", 'a', title, 
+				sizeof(title) - 1);
+				marcRecord_getSubField(m, "245", 'a', title, 
+				sizeof(title) - 1);
+				marcRecord_getSubField(m, "260", 'c', date, 
+				sizeof(date) - 1);
+				sprintf(buf, "%s %s", date, title);
+				*/
+				break;
+			}
+		default:
+			break;
+	}
+}
+
+int MarcRecord::RecordLength()
+{
+	register int l = 0;
+	
+	
+	for (std::vector<MarcDirectoryEntry>::size_type i=0; i!=directory_.size(); ++i)
+		for (std::vector<MarcField>::size_type j=0; j!=directory_[i].field_.size(); ++j)
+			l += directory_[i].field_[i].len_;
+		
+        return l;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Unimarc.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Unimarc.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/Unimarc.h	(revision 10506)
@@ -0,0 +1,175 @@
+/**********************************************************************
+ *
+ * Unimarc.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef MARC_RECORD
+#define MARC_RECORD
+
+#define SUBFDELIM '\037'   // %
+#define FIELDTERM '\036'   // $
+#define RECTERM   '\035'   // # sharp
+
+#define MARC_LEADER_LEN 24
+#define MARC_DIRENT_LEN 12
+
+#define MARC_FMT_BRIEF 0
+#define MARC_FMT_FULL 1
+
+//---------------------
+// UNIMARC Record Label
+//---------------------
+struct  MarcLeader
+{
+	char	lreclen_[5];	/* logical record length */
+	char	status_;		/* record status_ */
+	char	type_;			/* type_ of record */
+	char	bibLevel_;	    /* bibliographic level */
+	char	ctrlType_;	    /* type_ of control */
+	char	undPos_;		/* undefined character position */
+	char	indCount_;	    /* indicator count */
+	char	scd_;			/* subfield code count */
+	char	base_[5];		/* base_ address of data */
+	char	encLevel_;	    /* encoding level */
+	char	dcf_;			/* descriptive cataloging form */
+	char	lrr_;			/* linked record requirement */
+	char	llof_;			/* length of the length-of-field portion */
+	char	lscp_;			/* length of starting-character-position portion */
+	char	lidp_;			/* length of implementation-defined portion */
+	char	uep_;			/* undefined entry map character position */
+
+	MarcLeader()
+	{
+		lreclen_[0]=' ';
+		lreclen_[1]=' ';
+		lreclen_[2]=' ';
+		lreclen_[3]=' ';
+		lreclen_[4]=' ';
+		status_   = '0';     // New record
+        type_     = '0';     // Language materials, printed
+	    bibLevel_ = '0';	     // Monographic
+	    ctrlType_ = '0';     // Hierarchical relationship undefined
+	    undPos_   = '0';     // Undefined, contains a blank
+	    indCount_ = '0';     // Invariably 2 in UNIMARC
+	    scd_      = '0';     // Invariably 2 in UNIMARC
+	    base_[0]  = ' ';     // Base_ address of data
+		base_[1]  = ' ';
+		base_[2]  = ' ';
+		base_[3]  = ' ';
+		base_[4]  = ' ';
+	    encLevel_ = '0';     // (Blank) full level
+	    dcf_      = '0';     // (Blank) record is in full ISBD form
+	    lrr_      = '0';     // Undefined, contains a blank
+	    llof_     = '4';     // Length of the length-of-field portion
+	    lscp_     = '5';     // Length of starting-character-position portion 
+	    lidp_     = '0';     // Length of implementation-defined portion
+	    uep_      = '0';     // Undefined, contains a blank
+	}
+
+   friend std::ostream& operator<<(std::ostream& s, const MarcLeader& leader);
+   friend std::istream& operator>>(std::istream& s, MarcLeader& leader);
+};
+
+//----------------
+// Directory entry
+//----------------
+struct DirectoryEntry
+{
+	char	tag_[3];		/* tag */
+	char	len_[4];		/* field length */
+	char	scp_[5];		/* starting character position */
+   friend std::ostream& operator<<(std::ostream& s, const DirectoryEntry& de);
+   friend std::istream& operator>>(std::istream& s, DirectoryEntry& leader);
+};
+inline std::istream& operator>>(std::istream& s, DirectoryEntry& de)
+{
+	s.read(de.tag_, 3);
+	s.read(de.len_, 4);
+	s.read(de.scp_, 5);
+	return s;
+}
+inline std::ostream& operator<<(std::ostream& s, const DirectoryEntry& de)
+{
+	s.write(de.tag_, 3);
+	s.write(de.len_, 4);
+	s.write(de.scp_, 5);
+	return s;
+}
+
+
+
+//------------------
+// Subfield item 
+//------------------
+struct MarcField
+{
+	int			len_;
+	char*       data_;
+};
+
+//-------------------
+// Directory entry
+//-------------------
+struct MarcDirectoryEntry
+{
+	char*                  tag_;
+	std::vector<MarcField> field_;
+};
+
+
+//---------------------------
+// UNIMARC record structure 
+//---------------------------
+
+class MarcRecord
+{
+protected:
+	MarcLeader      leader_;
+	char*           data_;
+	int			    length_;
+	int				dirCount_;
+	int				encapsulated_;
+	std::vector<MarcDirectoryEntry>   directory_;
+	
+    int ParseMarcRecord();
+    int AddSubFields(MarcDirectoryEntry& d, char* b);
+public:
+    MarcRecord(char* data, int length, int copyData);
+    ~MarcRecord();
+    void PrintDetailed(FILE* fp);
+    void Get(char* buf,int maxlen,int format);
+    int  GetSubField(char* tag, char subtag, char* buf, int maxlen);
+    int  GetField(char* tag, char* buf, int maxlen);
+    int  GetSubFields(char* tag, char subtag, char* buf, int maxlen);
+
+    int  HasField(char* tag);
+    int  HasSubField(char* tag, char subtag);
+
+    void Format(char* buf, int maxlen, int format);
+    int  RecordLength();
+    int  PrettyFormat(char* format, char* buf, int maxlen);
+
+    void Dump ();
+};
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/XRFFile.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/XRFFile.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/XRFFile.cpp	(revision 10506)
@@ -0,0 +1,293 @@
+/**********************************************************************
+ *
+ * XRFFile.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////
+// XrfFile.cpp: XrfFile object methods
+//
+////////////////////////////////////////////////////////////
+#include "stdafx.h"
+#include "XRFFile.h"
+
+
+
+//-----------------------------------------------------------------------------------
+// IsisError  XrfFile::OpenXrf(const _TCHAR *fname, FileSystem::AccessMode mode
+//				                              /* = FileSystem::FILE_READWRITE */)
+//
+// Open xrf_ file with file name fname 
+//-----------------------------------------------------------------------------------
+IsisError  XrfFile::OpenXrf(const _TCHAR *fname, FileSystem::AccessMode mode
+				                              /* = FileSystem::FILE_READWRITE */)
+{
+    IsisError isis_error;
+    xrfa_->xrfpos_ = -1;   // No block into buffer
+	try {
+        FileError rc = CFileBase::Open(fname, mode);
+	}
+	catch(CFileBaseException)
+	{
+		isis_error = ISIS_XRF_OPEN_ERROR;
+        throw CIsisDbException(isis_error, __FILE__, __LINE__); 
+	}
+  	long file_size   = CFileBase::FileSize(file_name);
+	
+	last_block_  = file_size/XRFBLKSIZE;
+
+	if (last_block_<1 || last_block_*XRFBLKSIZE != file_size)
+	{
+		isis_error =  ISIS_XRF_CORRUPT;
+        throw CIsisDbException(isis_error, __FILE__, __LINE__); 
+	}
+
+	return ISIS_NO_ERROR;
+}
+ 
+//////////////////////////////
+ 
+ 
+IsisError  XrfFile::CreateXrf(const _TCHAR *fname)
+// Creates an xrf_ file
+{
+    IsisError isis_error;
+	try 
+	{
+        FileError rc = CFileBase::Create(fname);
+    	// Initialize an empty block and write-it
+		xrfa_->Init();
+        xrfa_->xrfpos_ = 1; // Block number
+		xrfa_->xrfeof_ = 1; // Last xrf_ block
+        last_block_    = 1;		
+        WriteXrf(1L);
+	}
+	catch(CFileBaseException)
+	{
+		isis_error = ISIS_XRF_CREATE_ERROR;
+        throw CIsisDbException(isis_error, __FILE__, __LINE__);
+	}
+	
+    return ISIS_NO_ERROR;
+}
+//-----------------------------------------------------------------------------------
+// IsisError  XrfFile::CreateXrf(const _TCHAR *fname, long nextMfn)
+//
+// Special xrf_ file creation for building xrf_ blocks of an existing mst
+//-----------------------------------------------------------------------------------
+IsisError  XrfFile::CreateXrf(const _TCHAR *fname, long nextMfn)
+// Creates an xrf_ file
+{
+    IsisError isis_error;
+    long nBlocks = (nextMfn-1)/MAXTIV + 1;       // Number of blocks to allocate
+	try 
+	{
+        FileError rc = CFileBase::Create(fname);
+		xrfa_->Init();
+    	// Initialize an empty block and write-it
+		for (int iBlock=1; iBlock<= nBlocks; iBlock++)
+		{
+			TRACE("\niBlock=%d", iBlock);
+			xrfa_->xrfpos_ = iBlock;
+			xrfa_->xrfeof_ = 0;
+			if (iBlock == nBlocks)
+			    xrfa_->xrfeof_ = 1;
+
+			WriteXrf(iBlock);
+		}
+	}
+	catch(CFileBaseException)
+	{
+		isis_error = ISIS_XRF_CREATE_ERROR;
+        throw CIsisDbException(isis_error, __FILE__, __LINE__);
+	}
+
+    last_block_ = nBlocks;	
+    return ISIS_NO_ERROR;
+}
+
+//------------------------------------------------------------------------------
+// void XrfFile::UnPack(void)
+//
+// Unpack addresses of master file records. The current packed XRF block 
+// contained in xrf_ structure will be unpacked in xrfa_ structure.
+//
+//  A master file address is packed as follow: addr = mfb*2048 + mfp
+//
+//  2048 = 2**11 e.g. mfp->[0:2047] and block number -> [1: 2**20]
+//  2**20 = 1 048 576
+//
+// As we can put 127 addresses per block, then the limit on number of records
+// is 127 * 1 048 576
+//------------------------------------------------------------------------------
+void XrfFile::UnPack(void)
+{
+   xrfa_->xrfpos_ = xrf_->xrfpos_;
+   if (xrfa_->xrfpos_ < 0)
+   {
+      xrfa_->xrfpos_ = - xrf_->xrfpos_;
+      xrfa_->xrfeof_ = 1;
+   }
+   else
+      xrfa_->xrfeof_ = 0;
+ 
+   for (int i=0; i<MAXTIV; i++)
+   {
+      long j = xrf_->xrftiv_[i];             // Packed value
+      bool b = (j < 0);
+      if (b)
+         j = - j;
+      xrfa_->xrftiv_[i].xrfmfb_ = int(j / 2048L);   // Unpack block number
+      if (b)
+         xrfa_->xrftiv_[i].xrfmfb_ = -xrfa_->xrftiv_[i].xrfmfb_;
+      xrfa_->xrftiv_[i].xrfmfp_ = int(j % 2048L);   // Unpack offset
+   }
+}
+ 
+//------------------------------------------------------------------------------
+// void XrfFile::Pack(void)
+//
+// Pack addresses of master file records. The current unpacked XRF block 
+// contained in xrfa_ will be packed in xrf_ structure.
+//------------------------------------------------------------------------------
+void XrfFile::Pack(void)
+{
+   long j = xrfa_->xrfpos_;
+   if (xrfa_->xrfeof_ != 0)
+      j = -j;
+   xrf_->xrfpos_ = j;
+
+ 
+   for (int i=0; i<MAXTIV; i++)
+   {
+      j = xrfa_->xrftiv_[i].xrfmfb_;    // Unpacked block number
+      int b = (j < 0);
+      if (b)
+         j = - j;
+      //-------------------------------------------
+      // pack block number and offset in a long int
+      //-------------------------------------------
+      j = j * 2048 + xrfa_->xrftiv_[i].xrfmfp_;
+      if (b) j = -j;
+      xrf_->xrftiv_[i] = j;     // Put value in xrf_
+   }
+}
+ 
+//------------------------------------------------------------------------------
+// int XrfFile::GetMfp(long mfn, long& mfb, int& mfp)
+//
+// Gets the address of master file data record with MFN "mfn" by accessing the 
+// xrf_ file). mfb is the master file block number [1:NBLK] and mfp is the offset
+// in the master file block where the record starts [0:BLKSIZE-1]
+//
+//  Returns   Active              = Record active
+//            LogicalyDeleted     = Record logically deleted
+//            PhysicalyDeleted    = Record physically deleted
+//            EndOfFile
+//  Note: mfp can be >=      than BLKSIZE if the inverted file
+//  wasn't updated, then true mfp is mfp%BLKSIZE
+//------------------------------------------------------------------------------
+int XrfFile::GetMfp(long mfn, long& mfb, int& mfp)
+{
+	PRECONDITION(mfn>0);
+	PRECONDITION(last_block_>0);
+    int  comp;
+    long comb;
+    int  rc;
+	
+    long psxrf=(mfn-1)/MAXTIV+1;       // Block number
+	if (psxrf > last_block_)
+	{
+        rc = EndOfFile;                // Inexistent record (eof)
+		return rc;
+		throw CIsisDbException(ISIS_XRF_INVALID_BLOCK, __FILE__, __LINE__);
+	}
+    if (psxrf != xrfa_->xrfpos_) 
+	{                                  // If current block in xrf_ different
+		try
+		{
+            ReadXrf(psxrf);            // then read the block
+		}
+		catch (CFileBaseException e)
+		{
+            throw CIsisDbException(ISIS_XRF_READ_ERROR, __FILE__, __LINE__);
+		}
+
+    }
+    int i = int((mfn-1) % MAXTIV);     // Index
+    comb = xrfa_->xrftiv_[i].xrfmfb_;     // Master file block #
+    comp = xrfa_->xrftiv_[i].xrfmfp_;     // Offset in block
+
+	if (comb > 0)
+        rc = Active;                   // Record active 
+    else if (comb < 0 && comp > 0)
+        rc = LogicalyDeleted;          // Record logicaly deleted 
+	else if (comb == -1 && comp == 0)
+        rc = PhysicalyDeleted;         // Record physically deleted 
+    else if (comb == 0 && comp == 0)
+        rc = EndOfFile;                // Inexistent record (eof)
+	else
+	{
+        throw CIsisDbException(ISIS_XRF_INVALID_STATUS, __FILE__, __LINE__); 
+	}
+    mfb = labs(comb);
+    mfp = comp;
+	if (rc == Active)
+	{
+	    ASSERT(mfb>0 && mfb <= MAXMFB);
+		ASSERT(mfp>=0 && mfp < 2048);
+	    int mfpTemp = mfp%XRFBLKSIZE;
+	    ASSERT(mfpTemp>=0 && mfpTemp<XRFBLKSIZE);
+	}
+    return(rc);
+}
+ 
+void XrfFile::Grow(long from_lastb, long to_lastb)
+{
+	for (long i=from_lastb+1; i<=to_lastb; i++)
+	{
+        //--------------------
+        // append empty blocks
+        //--------------------
+ 		xrfa_->Init();
+		xrfa_->xrfpos_ = i;
+		xrfa_->xrfeof_ = (i==to_lastb) ? 1 : 0; // Eof flag
+	    try
+		{
+           WriteXrf(i);           // Write xrf_ at block address xrfb
+		}
+		catch (CFileBaseException)
+		{
+			throw(ISIS_XRF_WRITE_ERROR);
+		}
+	}
+}
+ 
+//------------------------------------------------------------------------------
+// void XrfFile::PutMfp(long mfn, long mfb, int mfp, int status)
+//
+// Puts the address of a master file record (mfb,mfp) as the address for MFN 
+// "mfn" in xrf_ file
+//------------------------------------------------------------------------------
+void XrfFile::PutMfp(long mfn, long mfb, int mfp, int status)
+{
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/XRFFile.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/XRFFile.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/XRFFile.h	(revision 10506)
@@ -0,0 +1,151 @@
+/**********************************************************************
+ *
+ * XRFFile.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+////////////////////////////////////////////////////////////
+// XRFFILE.H : Cross Ref File object
+//
+////////////////////////////////////////////////////////////
+ 
+#ifndef _XRFFILE_H_
+#define _XRFFILE_H_
+#ifndef _BLKFILE_H_
+#include "blkfile.h"
+#endif
+#include <assert.h>
+#include "IErrors.h"
+ 
+const int MAXTIV     =     127; //  # of XRF entries per block
+const int XRFBLKSIZE =     512; //
+const int MAXMFB     = 1048576; 
+
+ 
+ 
+/////////////////////////////////////////
+// Cross reference file data structures
+//
+ 
+ 
+struct MSTA_ENTRY                 // Unpacked MST address
+{             
+   long       xrfmfb_;             // Master file block
+   short int  xrfmfp_;             // Offset
+} ;
+ 
+struct XRFA                       // To strore unpacked addresses
+{                
+   long          xrfpos_;          // Block number on xrf_ file or -1 if empty
+   short int     xrfeof_;          // 1 if last block of xrf_ file
+   MSTA_ENTRY xrftiv_[MAXTIV];     // MAXTIV unpacked MST addresses
+
+   XRFA() { Init(); }
+
+   void Init()
+   {
+	   xrfeof_ = 0;              // Not eof
+	   xrfpos_ = -1;             // empty   
+	   for (int i=0; i<MAXTIV; i++)
+	   {
+		   xrftiv_[i].xrfmfb_  = -1;
+	       xrftiv_[i].xrfmfp_  = 0;
+	   }
+   }
+
+
+} ;
+ 
+struct XRF                       // To store packed addresses
+{                                // for reading and wrting
+   long xrfpos_;                  // block number on xrf_ file
+   long xrftiv_[MAXTIV];          // MAXTIV packed MST addresses 
+} ;
+ 
+///////////////////
+// XrfFile class
+//
+
+ 
+class XrfFile : public BlkFile 
+{
+private:
+   XRF*  xrf_;             // Buffer to store packed addresses
+   XRFA* xrfa_;            // Buffer to store unpacked addresses
+   long  last_block_;      // Should always contain the last allocated block
+   
+   void ReadXrf(long b);
+   void WriteXrf(long b);
+   void UnPack();
+   void Pack();
+   void Grow(long from_lastb, long to_lastb);
+public:
+   XrfFile();
+   IsisError OpenXrf(const _TCHAR *fname,
+	                 FileSystem::AccessMode mode = FileSystem::FILE_READWRITE);
+   IsisError CreateXrf(const _TCHAR *fname);
+   IsisError CreateXrf(const _TCHAR *fname, long nextMfn);
+  ~XrfFile();
+   int  GetMfp(long mfn, long& mfb, int& mfp);
+   void PutMfp(long mfn, long mfb, int mfp, int status);
+};
+ 
+//////////////////////////////
+ 
+inline XrfFile::XrfFile()  :
+// Makes a XrfFile object that isn't connected to a file
+   xrf_(new XRF),
+   xrfa_(new XRFA)
+{
+   last_block_ = -1;   // Not yet initialize
+   // Nothing more to do
+}
+ 
+//////////////////////////////
+ 
+ 
+inline XrfFile::~XrfFile()
+{
+   if (xrf_)  delete xrf_;
+   if (xrfa_) delete xrfa_;
+}
+ 
+//////////////////////////////
+ 
+inline void XrfFile::ReadXrf(long b)
+// Reads block # b into xrf_ buffer
+{
+	assert(b>0);
+    ReadBlk(xrf_, b);
+    UnPack();
+}
+ 
+//////////////////////////////
+ 
+inline void XrfFile::WriteXrf(long b)
+// Writes the content of xrf_ buffer as block number b
+{
+	assert(b>0);
+    Pack();
+    WriteBlk(xrf_, b);
+}
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/configure
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/configure	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/configure	(revision 10506)
@@ -0,0 +1,2029 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by Autoconf 2.50.
+#
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+
+# Name of the executable.
+as_me=`echo "$0" |sed 's,.*[\\/],,'`
+
+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
+
+as_executable_p="test -f"
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+# NLS nuisances.
+$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; }
+$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; }
+$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; }
+$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; }
+$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; }
+$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; }
+$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; }
+$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; }
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" 	$as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export 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
+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}
+
+# Avoid depending upon Character Ranges.
+ac_cr_az='abcdefghijklmnopqrstuvwxyz'
+ac_cr_AZ='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ac_cr_09='0123456789'
+ac_cr_alnum=$ac_cr_az$ac_cr_AZ$ac_cr_09
+
+# Sed expression to map a string onto a valid sh and CPP variable names.
+ac_tr_sh="sed y%*+%pp%;s%[^_$ac_cr_alnum]%_%g"
+ac_tr_cpp="sed y%*$ac_cr_az%P$ac_cr_AZ%;s%[^_$ac_cr_alnum]%_%g"
+
+ac_default_prefix=../..
+
+# 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'
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+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" : ".*[^-_$ac_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" : ".*[^-_$ac_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)
+    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" : ".*[^-_$ac_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" : ".*[^-_$ac_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" : ".*[^_$ac_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" : ".*[^-._$ac_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 bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+              localstatedir libdir includedir oldincludedir infodir mandir \
+              exec_prefix prefix
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* ) ;;
+    NONE ) ;;
+    *)  { echo "$as_me: error: expected an absolute path 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.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: should be removed in autoconf 3.0.
+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_prog=$0
+  ac_confdir=`echo "$ac_prog" | sed 's%[\\/][^\\/][^\\/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "$as_me: error: cannot find sources in $ac_confdir or .." >&2
+   { (exit 1); exit 1; }; }
+  else
+    { echo "$as_me: error: cannot find sources in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+  fi
+fi
+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_CXX_set=${CXX+set}
+ac_env_CXX_value=$CXX
+ac_cv_env_CXX_set=${CXX+set}
+ac_cv_env_CXX_value=$CXX
+ac_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_env_CXXFLAGS_value=$CXXFLAGS
+ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set}
+ac_cv_env_CXXFLAGS_value=$CXXFLAGS
+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
+
+#
+# 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 <<EOF
+\`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 \`..']
+
+EOF
+
+  cat <<EOF
+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]
+EOF
+
+  cat <<\EOF
+EOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\EOF
+
+Some influential environment variables:
+  CXX         C++ compiler command
+  CXXFLAGS    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>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+EOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  ac_popdir=`pwd`
+  for ac_subdir in : $ac_subdirs_all; do test "x$ac_subdir" = x: && continue
+    cd $ac_subdir
+    # A "../" for each directory in /$ac_subdir.
+    ac_dots=`echo $ac_subdir |
+             sed 's,^\./,,;s,[^/]$,&/,;s,[^/]*/,../,g'`
+
+    case $srcdir in
+    .) # No --srcdir option.  We are building in place.
+      ac_sub_srcdir=$srcdir ;;
+    [\\/]* | ?:[\\/]* ) # Absolute path.
+      ac_sub_srcdir=$srcdir/$ac_subdir ;;
+    *) # Relative path.
+      ac_sub_srcdir=$ac_dots$srcdir/$ac_subdir ;;
+    esac
+
+    # Check for guested configure; otherwise get Cygnus style configure.
+    if test -f $ac_sub_srcdir/configure.gnu; then
+      echo
+      $SHELL $ac_sub_srcdir/configure.gnu  --help=recursive
+    elif test -f $ac_sub_srcdir/configure; then
+      echo
+      $SHELL $ac_sub_srcdir/configure  --help=recursive
+    elif test -f $ac_sub_srcdir/configure.ac ||
+           test -f $ac_sub_srcdir/configure.in; then
+      echo
+      $ac_configure --help
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_subdir" >&2
+    fi
+    cd $ac_popdir
+  done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+  cat <<\EOF
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+EOF
+  exit 0
+fi
+exec 5>config.log
+cat >&5 <<EOF
+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.50.  Invocation command line was
+
+  $ $0 $@
+
+EOF
+{
+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`
+
+PATH = $PATH
+
+_ASUNAME
+} >&5
+
+cat >&5 <<EOF
+## ------------ ##
+## Core tests.  ##
+## ------------ ##
+
+EOF
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell meta-characters.
+ac_configure_args=
+ac_sep=
+for ac_arg
+do
+  case $ac_arg in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+    ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"`
+    ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+    ac_sep=" " ;;
+  *) ac_configure_args="$ac_configure_args$ac_sep$ac_arg"
+     ac_sep=" " ;;
+  esac
+  # Get rid of the leading space.
+done
+
+# 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.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  echo >&5
+  echo "## ----------------- ##" >&5
+  echo "## Cache variables.  ##" >&5
+  echo "## ----------------- ##" >&5
+  echo >&5
+  # 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/^\\([_$ac_cr_alnum]*_cv_[_$ac_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+      ;;
+    *)
+      sed -n \
+        "s/^\\([_$ac_cr_alnum]*_cv_[_$ac_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+} >&5
+  sed "/^$/d" confdefs.h >conftest.log
+  if test -s conftest.log; then
+    echo >&5
+    echo "## ------------ ##" >&5
+    echo "## confdefs.h.  ##" >&5
+    echo "## ------------ ##" >&5
+    echo >&5
+    cat conftest.log >&5
+  fi
+  (echo; echo) >&5
+  test "$ac_signal" != 0 &&
+    echo "$as_me: caught signal $ac_signal" >&5
+  echo "$as_me: exit $exit_status" >&5
+  rm -rf conftest* confdefs* core core.* *.core conf$$* $ac_clean_files &&
+    exit $exit_status
+     ' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_status=$?; ac_signal='$ac_signal'; { (exit $ac_status); exit $ac_status; }' $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
+
+# 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:802: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    cat "$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:813: 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:821: 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_suggest_removing_cache=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:837: WARNING: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: WARNING: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_suggest_removing_cache=: ;;
+    ,set)
+      { echo "$as_me:841: WARNING: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: WARNING: \`$ac_var' was not set in the previous run" >&2;}
+      ac_suggest_removing_cache=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+        { echo "$as_me:847: WARNING: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: WARNING: \`$ac_var' has changed since the previous run:" >&2;}
+        { echo "$as_me:849: WARNING:   former value:  $ac_old_val" >&5
+echo "$as_me: WARNING:   former value:  $ac_old_val" >&2;}
+        { echo "$as_me:851: WARNING:   current value: $ac_new_val" >&5
+echo "$as_me: WARNING:   current value: $ac_new_val" >&2;}
+        ac_suggest_removing_cache=:
+      fi;;
+  esac
+done
+if $ac_suggest_removing_cache; then
+  { echo "$as_me:858: WARNING: changes in the environment can compromise the build" >&5
+echo "$as_me: WARNING: changes in the environment can compromise the build" >&2;}
+  { echo "$as_me:860: WARNING: consider removing $cache_file and starting over" >&5
+echo "$as_me: WARNING: consider removing $cache_file and starting over" >&2;}
+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
+
+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
+echo "#! $SHELL" >conftest.sh
+echo  "exit 0"   >>conftest.sh
+chmod +x conftest.sh
+if { (echo "$as_me:879: PATH=\".;.\"; conftest.sh") >&5
+  (PATH=".;."; conftest.sh) 2>&5
+  ac_status=$?
+  echo "$as_me:882: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  ac_path_separator=';'
+else
+  ac_path_separator=:
+fi
+PATH_SEPARATOR="$ac_path_separator"
+rm -f conftest.sh
+
+ac_aux_dir=
+for ac_dir in ../.. $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:908: error: cannot find install-sh or install.sh in ../.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in ../.. $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.
+
+ac_ext=cc
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl KCC RCC xlC_r xlC
+  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:926: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CXX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+  ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+  IFS=$ac_save_IFS
+  test -z "$ac_dir" && ac_dir=.
+  $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+echo "$as_me:941: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  echo "$as_me:949: result: $CXX" >&5
+echo "${ECHO_T}$CXX" >&6
+else
+  echo "$as_me:952: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl KCC RCC xlC_r xlC
+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:965: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+  ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+  IFS=$ac_save_IFS
+  test -z "$ac_dir" && ac_dir=.
+  $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_CXX="$ac_prog"
+echo "$as_me:980: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  echo "$as_me:988: result: $ac_ct_CXX" >&5
+echo "${ECHO_T}$ac_ct_CXX" >&6
+else
+  echo "$as_me:991: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$ac_ct_CXX" && break
+done
+test -n "$ac_ct_CXX" || ac_ct_CXX="g++"
+
+  CXX=$ac_ct_CXX
+fi
+
+cat >conftest.$ac_ext <<_ACEOF
+#line 1003 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compiler, and finding out an intuition
+# of exeext.
+echo "$as_me:1019: checking for C++ compiler default output" >&5
+echo $ECHO_N "checking for C++ compiler default output... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:1022: \"$ac_link_default\"") >&5
+  (eval $ac_link_default) 2>&5
+  ac_status=$?
+  echo "$as_me:1025: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in `ls a.exe conftest.exe a.* conftest conftest.* 2>/dev/null`; do
+  case $ac_file in
+    *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;;
+    a.out ) # We found the default executable, but exeext='' is most
+            # certainly right.
+            break;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+          export ac_cv_exeext
+          break;;
+    * ) break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:1042: error: C++ compiler cannot create executables" >&5
+echo "$as_me: error: C++ compiler cannot create executables" >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:1048: 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:1053: 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:1059: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:1062: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { echo "$as_me:1069: error: cannot run C++ compiled programs.
+If you meant to cross compile, use \`--host'." >&5
+echo "$as_me: error: cannot run C++ compiled programs.
+If you meant to cross compile, use \`--host'." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+echo "$as_me:1077: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext
+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:1084: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:1086: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:1089: checking for executable suffix" >&5
+echo $ECHO_N "checking for executable suffix... $ECHO_C" >&6
+if { (eval echo "$as_me:1091: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:1094: \$? = $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 `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do
+  case $ac_file in
+    *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+          export ac_cv_exeext
+          break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:1110: error: cannot compute EXEEXT: cannot compile and link" >&5
+echo "$as_me: error: cannot compute EXEEXT: cannot compile and link" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:1116: 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:1122: checking for object suffix" >&5
+echo $ECHO_N "checking for object suffix... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+#line 1128 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:1140: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:1143: \$? = $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 ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:1155: error: cannot compute OBJEXT: cannot compile" >&5
+echo "$as_me: error: cannot compute OBJEXT: cannot compile" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:1162: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:1166: 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_cxx_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+#line 1172 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1187: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:1190: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:1193: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:1196: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_compiler_gnu=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:1208: result: $ac_cv_cxx_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6
+GXX=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="-g"
+echo "$as_me:1214: checking whether $CXX accepts -g" >&5
+echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cxx_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+#line 1220 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1232: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:1235: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:1238: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:1241: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cxx_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_prog_cxx_g=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:1251: result: $ac_cv_prog_cxx_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+for ac_declaration in \
+   ''\
+   '#include <stdlib.h>' \
+   '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
+#line 1278 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+$ac_declaration
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1291: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:1294: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:1297: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:1300: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+continue
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+  cat >conftest.$ac_ext <<_ACEOF
+#line 1310 "configure"
+#include "confdefs.h"
+$ac_declaration
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1322: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:1325: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:1328: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:1331: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  break
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+echo '#ifdef __cplusplus' >>confdefs.h
+echo $ac_declaration      >>confdefs.h
+echo '#endif'             >>confdefs.h
+
+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
+
+# 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"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:1362: 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
+    ac_save_IFS=$IFS; IFS=$ac_path_separator
+  for ac_dir in $PATH; do
+    IFS=$ac_save_IFS
+    # Account for people who put trailing slashes in PATH elements.
+    case $ac_dir/ in
+    / | ./ | .// | /cC/* \
+    | /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* \
+    | /usr/ucb/* ) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if $as_executable_p "$ac_dir/$ac_prog"; then
+	  if test $ac_prog = install &&
+            grep dspmsg "$ac_dir/$ac_prog" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$ac_dir/$ac_prog" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      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:1411: 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'
+
+ac_config_files="$ac_config_files 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 overriden 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/^\\([_$ac_cr_alnum]*_cv_[_$ac_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;;
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n \
+        "s/^\\([_$ac_cr_alnum]*_cv_[_$ac_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 cmp -s $cache_file confcache; 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 <<\EOF
+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
+EOF
+# 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
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:1532: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated automatically by configure.
+# 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
+SHELL=\${CONFIG_SHELL-$SHELL}
+ac_cs_invocation="\$0 \$@"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+
+# Name of the executable.
+as_me=`echo "$0" |sed 's,.*[\\/],,'`
+
+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
+
+as_executable_p="test -f"
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+# NLS nuisances.
+$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; }
+$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; }
+$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; }
+$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; }
+$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; }
+$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; }
+$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; }
+$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; }
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" 	$as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; }
+
+exec 6>&1
+
+_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 <<\EOF
+
+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
+  -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>."
+EOF
+
+cat >>$CONFIG_STATUS <<EOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.50,
+  with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+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"
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+# 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[^=]*=\(.*\)'`
+    shift
+    set dummy "$ac_option" "$ac_optarg" ${1+"$@"}
+    shift
+    ;;
+  -*);;
+  *) # This is not an option, so the user has probably given explicit
+     # arguments.
+     ac_need_defaults=false;;
+  esac
+
+  case $1 in
+  # Handling of the options.
+EOF
+cat >>$CONFIG_STATUS <<EOF
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion"
+    exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;;
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+  --version | --vers* | -V )
+    echo "$ac_cs_version"; exit 0 ;;
+  --he | --h)
+    # Conflict between --help and --header
+    { { echo "$as_me:1700: 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 )
+    shift
+    CONFIG_FILES="$CONFIG_FILES $1"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $1"
+    ac_need_defaults=false;;
+
+  # Handling of arguments.
+  'Makefile' ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+  # This is an error.
+  -*) { { echo "$as_me:1722: 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; }; } ;;
+  *) { { echo "$as_me:1727: error: invalid argument: $1" >&5
+echo "$as_me: error: invalid argument: $1" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+  shift
+done
+
+exec 5>>config.log
+cat >&5 << _ACEOF
+
+## ----------------------- ##
+## Running config.status.  ##
+## ----------------------- ##
+
+This file was extended by $as_me 2.50, executed with
+  > $ac_cs_invocation
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+
+_ACEOF
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+# 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
+
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+  trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+  trap '{ (exit $?); exit $?; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+: ${TMPDIR=/tmp}
+{
+  tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=$TMPDIR/cs$$-$RANDOM
+  (umask 077 && mkdir $tmp)
+} ||
+{
+   echo "$me: cannot create a temporary directory in $TMPDIR" >&2
+   { (exit 1); exit 1; }
+}
+
+EOF
+
+cat >>$CONFIG_STATUS <<EOF
+
+#
+# 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,@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,@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,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@DEFS@,$DEFS,;t t
+s,@LIBS@,$LIBS,;t t
+s,@CXX@,$CXX,;t t
+s,@CXXFLAGS@,$CXXFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CXX@,$ac_ct_CXX,;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
+CEOF
+
+EOF
+
+  cat >>$CONFIG_STATUS <<\EOF
+  # Split the substitutions into bite-sized pieces for seds with
+  # small command number limits, like on Digital OSF/1 and HP-UX.
+  ac_max_sed_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"
+
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+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=`$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 test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    { case "$ac_dir" in
+  [\\/]* | ?:[\\/]* ) as_incr_dir=;;
+  *)                      as_incr_dir=.;;
+esac
+as_dummy="$ac_dir"
+for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
+  case $as_mkdir_dir in
+    # Skip DOS drivespec
+    ?:) as_incr_dir=$as_mkdir_dir ;;
+    *)
+      as_incr_dir=$as_incr_dir/$as_mkdir_dir
+      test -d "$as_incr_dir" || mkdir "$as_incr_dir"
+    ;;
+  esac
+done; }
+
+    ac_dir_suffix="/`echo $ac_dir|sed 's,^\./,,'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo "$ac_dir_suffix" | sed 's,/[^/]*,../,g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case $srcdir in
+  .)  ac_srcdir=.
+      if test -z "$ac_dots"; then
+         ac_top_srcdir=.
+      else
+         ac_top_srcdir=`echo $ac_dots | sed 's,/$,,'`
+      fi ;;
+  [\\/]* | ?:[\\/]* )
+      ac_srcdir=$srcdir$ac_dir_suffix;
+      ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_dots$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_dots$srcdir ;;
+  esac
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_dots$INSTALL ;;
+  esac
+
+  if test x"$ac_file" != x-; then
+    { echo "$as_me:1944: 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 automatically by config.status.  */
+  configure_input="Generated automatically 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:1962: 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:1975: 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; }
+EOF
+cat >>$CONFIG_STATUS <<EOF
+  sed "$ac_vpsub
+$extrasub
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;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
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+
+{ (exit 0); exit 0; }
+EOF
+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=:
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS || 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: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/configure.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/configure.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/configure.in	(revision 10506)
@@ -0,0 +1,19 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT()
+
+dnl  default installation
+dnl will be overridden by command-line args from packages/configure
+AC_PREFIX_DEFAULT(../..)
+
+dnl this uses the config.guess, config.sub and install-sh from gsdl.
+AC_CONFIG_AUX_DIR(../..)
+
+dnl compiler - need c++
+AC_PROG_CXX
+
+dnl Windows extension
+AC_EXEEXT
+
+AC_PROG_INSTALL
+
+AC_OUTPUT(Makefile)
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/mytchar.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/mytchar.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/mytchar.h	(revision 10506)
@@ -0,0 +1,35 @@
+/**********************************************************************
+ *
+ * mytchar.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef __MY_TCHAR__
+#define __MY_TCHAR__
+
+#include "tchar.h"
+
+#ifndef _WIN32
+typedef wchar_t TCHAR;
+#endif
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/stdafx.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/stdafx.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/stdafx.cpp	(revision 10506)
@@ -0,0 +1,33 @@
+/**********************************************************************
+ *
+ * stdafx.cpp
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+// stdafx.cpp : source file that includes just the standard includes
+// IsisGdl.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/stdafx.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/stdafx.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/stdafx.h	(revision 10506)
@@ -0,0 +1,40 @@
+/**********************************************************************
+ *
+ * stdafx.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+// #pragma once
+
+
+#include <iostream>
+#include <assert.h>
+#include "mytchar.h"
+#include "Compat.h"
+// TODO: reference additional headers your program requires here
+#include "IsisDef.h"
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/tchar.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/tchar.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/isis-gdl/tchar.h	(revision 10506)
@@ -0,0 +1,1046 @@
+/**********************************************************************
+ *
+ * tchar.h
+ * Copyright (C) 2003  UNESCO
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+/***
+*tchar.h - definitions for generic international text functions
+*
+*       Copyright (c) 1991-1997, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       Definitions for generic international functions, mostly defines
+*       which map string/formatted-io/ctype functions to char, wchar_t, or
+*       MBCS versions.  To be used for compatibility between single-byte,
+*       multi-byte and Unicode text models.
+*
+*       [Public]
+*
+****/
+
+#if     _MSC_VER > 1000 /*IFSTRIP=IGN*/
+#pragma once
+#endif
+
+#ifndef _INC_TCHAR
+#define _INC_TCHAR
+
+#ifdef  _MSC_VER
+#pragma warning(disable:4514)       /* disable unwanted C++ /W4 warning */
+/* #pragma warning(default:4514) */ /* use this to reenable, if necessary */
+#endif  /* _MSC_VER */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+/* Define __cdecl for non-Microsoft compilers */
+
+#if     ( !defined(_MSC_VER) && !defined(__cdecl) )
+#define __cdecl
+#endif
+
+
+/* Define _CRTIMP */
+
+#ifndef _CRTIMP
+#ifdef  CRTDLL
+#define _CRTIMP __declspec(dllexport)
+#else   /* ndef CRTDLL */
+#ifdef  _DLL
+#define _CRTIMP __declspec(dllimport)
+#else   /* ndef _DLL */
+#define _CRTIMP
+#endif  /* _DLL */
+#endif  /* CRTDLL */
+#endif  /* _CRTIMP */
+
+
+#define _ftcscat    _tcscat
+#define _ftcschr    _tcschr
+#define _ftcscpy    _tcscpy
+#define _ftcscspn   _tcscspn
+#define _ftcslen    _tcslen
+#define _ftcsncat   _tcsncat
+#define _ftcsncpy   _tcsncpy
+#define _ftcspbrk   _tcspbrk
+#define _ftcsrchr   _tcsrchr
+#define _ftcsspn    _tcsspn
+#define _ftcsstr    _tcsstr
+#define _ftcstok    _tcstok
+
+#define _ftcsdup    _tcsdup
+#define _ftcsnset   _tcsnset
+#define _ftcsrev    _tcsrev
+#define _ftcsset    _tcsset
+
+#define _ftcscmp      _tcscmp
+#define _ftcsicmp     _tcsicmp
+#define _ftcsnccmp    _tcsnccmp
+#define _ftcsncmp     _tcsncmp
+#define _ftcsncicmp   _tcsncicmp
+#define _ftcsnicmp    _tcsnicmp
+
+#define _ftcscoll     _tcscoll
+#define _ftcsicoll    _tcsicoll
+#define _ftcsnccoll   _tcsnccoll
+#define _ftcsncoll    _tcsncoll
+#define _ftcsncicoll  _tcsncicoll
+#define _ftcsnicoll   _tcsnicoll
+
+/* Redundant "logical-character" mappings */
+
+#define _ftcsclen   _tcsclen
+#define _ftcsnccat  _tcsnccat
+#define _ftcsnccpy  _tcsnccpy
+#define _ftcsncset  _tcsncset
+
+#define _ftcsdec    _tcsdec
+#define _ftcsinc    _tcsinc
+#define _ftcsnbcnt  _tcsnbcnt
+#define _ftcsnccnt  _tcsnccnt
+#define _ftcsnextc  _tcsnextc
+#define _ftcsninc   _tcsninc
+#define _ftcsspnp   _tcsspnp
+
+#define _ftcslwr    _tcslwr
+#define _ftcsupr    _tcsupr
+
+#define _ftclen     _tclen
+#define _ftccpy     _tccpy
+#define _ftccmp     _tccmp
+
+
+#ifdef  _UNICODE
+
+#ifdef  __cplusplus
+}   /* ... extern "C" */
+#endif
+
+/* ++++++++++++++++++++ UNICODE ++++++++++++++++++++ */
+
+#include <wchar.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifndef _WCTYPE_T_DEFINED
+typedef wchar_t wint_t;
+typedef wchar_t wctype_t;
+#define _WCTYPE_T_DEFINED
+#endif
+
+#ifndef __TCHAR_DEFINED
+typedef wchar_t     _TCHAR;
+typedef wchar_t     _TSCHAR;
+typedef wchar_t     _TUCHAR;
+typedef wchar_t     _TXCHAR;
+typedef wint_t      _TINT;
+#define __TCHAR_DEFINED
+#endif
+
+#ifndef _TCHAR_DEFINED
+#if     !__STDC__
+typedef wchar_t     TCHAR;
+#endif
+#define _TCHAR_DEFINED
+#endif
+
+#define _TEOF       WEOF
+
+#define __T(x)      L ## x
+
+
+/* Program */
+
+#define _tmain      wmain
+#define _tWinMain   wWinMain
+#define _tenviron   _wenviron
+#define __targv     __wargv
+
+/* Formatted i/o */
+
+#define _tprintf    wprintf
+#define _ftprintf   fwprintf
+#define _stprintf   swprintf
+#define _sntprintf  _snwprintf
+#define _vtprintf   vwprintf
+#define _vftprintf  vfwprintf
+#define _vstprintf  vswprintf
+#define _vsntprintf _vsnwprintf
+#define _tscanf     wscanf
+#define _ftscanf    fwscanf
+#define _stscanf    swscanf
+
+
+/* Unformatted i/o */
+
+#define _fgettc     fgetwc
+#define _fgettchar  _fgetwchar
+#define _fgetts     fgetws
+#define _fputtc     fputwc
+#define _fputtchar  _fputwchar
+#define _fputts     fputws
+#define _gettc      getwc
+#define _gettchar   getwchar
+#define _getts      _getws
+#define _puttc      putwc
+#define _puttchar   putwchar
+#define _putts      _putws
+#define _ungettc    ungetwc
+
+
+/* String conversion functions */
+
+#define _tcstod     wcstod
+#define _tcstol     wcstol
+#define _tcstoul    wcstoul
+
+#define _itot       _itow
+#define _ltot       _ltow
+#define _ultot      _ultow
+#define _ttoi       _wtoi
+#define _ttol       _wtol
+
+#define _ttoi64     _wtoi64
+#define _i64tot     _i64tow
+#define _ui64tot    _ui64tow
+
+/* String functions */
+
+#define _tcscat     wcscat
+#define _tcschr     wcschr
+#define _tcscpy     wcscpy
+#define _tcscspn    wcscspn
+#define _tcslen     wcslen
+#define _tcsncat    wcsncat
+#define _tcsncpy    wcsncpy
+#define _tcspbrk    wcspbrk
+#define _tcsrchr    wcsrchr
+#define _tcsspn     wcsspn
+#define _tcsstr     wcsstr
+#define _tcstok     wcstok
+
+#define _tcsdup     _wcsdup
+#define _tcsnset    _wcsnset
+#define _tcsrev     _wcsrev
+#define _tcsset     _wcsset
+
+#define _tcscmp     wcscmp
+#define _tcsicmp    _wcsicmp
+#define _tcsnccmp   wcsncmp
+#define _tcsncmp    wcsncmp
+#define _tcsncicmp  _wcsnicmp
+#define _tcsnicmp   _wcsnicmp
+
+#define _tcscoll    wcscoll
+#define _tcsicoll   _wcsicoll
+#define _tcsnccoll  _wcsncoll
+#define _tcsncoll   _wcsncoll
+#define _tcsncicoll _wcsnicoll
+#define _tcsnicoll  _wcsnicoll
+
+
+/* Execute functions */
+
+#define _texecl     _wexecl
+#define _texecle    _wexecle
+#define _texeclp    _wexeclp
+#define _texeclpe   _wexeclpe
+#define _texecv     _wexecv
+#define _texecve    _wexecve
+#define _texecvp    _wexecvp
+#define _texecvpe   _wexecvpe
+
+#define _tspawnl    _wspawnl
+#define _tspawnle   _wspawnle
+#define _tspawnlp   _wspawnlp
+#define _tspawnlpe  _wspawnlpe
+#define _tspawnv    _wspawnv
+#define _tspawnve   _wspawnve
+#define _tspawnvp   _wspawnvp
+#define _tspawnvp   _wspawnvp
+#define _tspawnvpe  _wspawnvpe
+
+#define _tsystem    _wsystem
+
+
+/* Time functions */
+
+#define _tasctime   _wasctime
+#define _tctime     _wctime
+#define _tstrdate   _wstrdate
+#define _tstrtime   _wstrtime
+#define _tutime     _wutime
+#define _tcsftime   wcsftime
+
+
+/* Directory functions */
+
+#define _tchdir     _wchdir
+#define _tgetcwd    _wgetcwd
+#define _tgetdcwd   _wgetdcwd
+#define _tmkdir     _wmkdir
+#define _trmdir     _wrmdir
+
+
+/* Environment/Path functions */
+
+#define _tfullpath  _wfullpath
+#define _tgetenv    _wgetenv
+#define _tmakepath  _wmakepath
+#define _tputenv    _wputenv
+#define _tsearchenv _wsearchenv
+#define _tsplitpath _wsplitpath
+
+
+/* Stdio functions */
+
+#define _tfdopen    _wfdopen
+#define _tfsopen    _wfsopen
+#define _tfopen     _wfopen
+#define _tfreopen   _wfreopen
+#define _tperror    _wperror
+#define _tpopen     _wpopen
+#define _ttempnam   _wtempnam
+#define _ttmpnam    _wtmpnam
+
+
+/* Io functions */
+
+#define _taccess    _waccess
+#define _tchmod     _wchmod
+#define _tcreat     _wcreat
+#define _tfindfirst _wfindfirst
+#define _tfindfirsti64  _wfindfirsti64
+#define _tfindnext  _wfindnext
+#define _tfindnexti64   _wfindnexti64
+#define _tmktemp    _wmktemp
+#define _topen      _wopen
+#define _tremove    _wremove
+#define _trename    _wrename
+#define _tsopen     _wsopen
+#define _tunlink    _wunlink
+
+#define _tfinddata_t    _wfinddata_t
+#define _tfinddatai64_t _wfinddatai64_t
+
+
+/* Stat functions */
+
+#define _tstat      _wstat
+#define _tstati64   _wstati64
+
+
+/* Setlocale functions */
+
+#define _tsetlocale _wsetlocale
+
+
+/* Redundant "logical-character" mappings */
+
+#define _tcsclen    wcslen
+#define _tcsnccat   wcsncat
+#define _tcsnccpy   wcsncpy
+#define _tcsncset   _wcsnset
+
+#define _tcsdec     _wcsdec
+#define _tcsinc     _wcsinc
+#define _tcsnbcnt   _wcsncnt
+#define _tcsnccnt   _wcsncnt
+#define _tcsnextc   _wcsnextc
+#define _tcsninc    _wcsninc
+#define _tcsspnp    _wcsspnp
+
+#define _tcslwr     _wcslwr
+#define _tcsupr     _wcsupr
+#define _tcsxfrm    wcsxfrm
+
+
+#if     (__STDC__ || defined(_NO_INLINING)) && !defined(_M_M68K)
+#define _tclen(_pc) (1)
+#define _tccpy(_pc1,_cpc2) ((*(_pc1) = *(_cpc2)))
+#define _tccmp(_cpc1,_cpc2) ((*(_cpc1))-(*(_cpc2)))
+#else   /* __STDC__ */
+__inline size_t __cdecl _tclen(const wchar_t *_cpc) { return (_cpc,1); }
+__inline void __cdecl _tccpy(wchar_t *_pc1, const wchar_t *_cpc2) { *_pc1 = (wchar_t)*_cpc2; }
+__inline int __cdecl _tccmp(const wchar_t *_cpc1, const wchar_t *_cpc2) { return (int) ((*_cpc1)-(*_cpc2)); }
+#endif  /* __STDC__ */
+
+
+/* ctype functions */
+
+#define _istalnum   iswalnum
+#define _istalpha   iswalpha
+#define _istascii   iswascii
+#define _istcntrl   iswcntrl
+#define _istdigit   iswdigit
+#define _istgraph   iswgraph
+#define _istlower   iswlower
+#define _istprint   iswprint
+#define _istpunct   iswpunct
+#define _istspace   iswspace
+#define _istupper   iswupper
+#define _istxdigit  iswxdigit
+
+#define _totupper   towupper
+#define _totlower   towlower
+
+#define _istlegal(_c)   (1)
+#define _istlead(_c)    (0)
+#define _istleadbyte(_c)    (0)
+
+
+#if     (__STDC__ || defined(_NO_INLINING)) && !defined(_M_M68K)
+#define _wcsdec(_cpc1, _cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1)
+#define _wcsinc(_pc)    ((_pc)+1)
+#define _wcsnextc(_cpc) ((unsigned int) *(_cpc))
+#define _wcsninc(_pc, _sz) (((_pc)+(_sz)))
+#define _wcsncnt(_cpc, _sz) ((wcslen(_cpc)>_sz) ? _sz : wcslen(_cpc))
+#define _wcsspnp(_cpc1, _cpc2) ((*((_cpc1)+wcsspn(_cpc1,_cpc2))) ? ((_cpc1)+wcsspn(_cpc1,_cpc2)) : NULL)
+#else   /* __STDC__ */
+__inline wchar_t * __cdecl _wcsdec(const wchar_t * _cpc1, const wchar_t * _cpc2) { return (wchar_t *)((_cpc1)>=(_cpc2) ? NULL : ((_cpc2)-1)); }
+__inline wchar_t * __cdecl _wcsinc(const wchar_t * _pc) { return (wchar_t *)(_pc+1); }
+__inline unsigned int __cdecl _wcsnextc(const wchar_t * _cpc) { return (unsigned int)*_cpc; }
+__inline wchar_t * __cdecl _wcsninc(const wchar_t * _pc, size_t _sz) { return (wchar_t *)(_pc+_sz); }
+__inline size_t __cdecl _wcsncnt( const wchar_t * _cpc, size_t _sz) { size_t len; len = wcslen(_cpc); return (len>_sz) ? _sz : len; }
+__inline wchar_t * __cdecl _wcsspnp( const wchar_t * _cpc1, const wchar_t * _cpc2) { return (*(_cpc1 += wcsspn(_cpc1,_cpc2))!='\0') ? (wchar_t*)_cpc1 : NULL; }
+#endif  /* __STDC__ */
+
+
+#else   /* ndef _UNICODE */
+
+/* ++++++++++++++++++++ SBCS and MBCS ++++++++++++++++++++ */
+
+#ifdef  __cplusplus
+}   /* ... extern "C" */
+#endif
+
+#include <string.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+#define _TEOF       EOF
+
+#define __T(x)      x
+
+
+/* Program */
+
+#define _tmain      main
+#define _tWinMain   WinMain
+#ifdef  _POSIX_
+#define _tenviron   environ
+#else
+#define _tenviron  _environ
+#endif
+#define __targv     __argv
+
+
+/* Formatted i/o */
+
+#define _tprintf    printf
+#define _ftprintf   fprintf
+#define _stprintf   sprintf
+#define _sntprintf  _snprintf
+#define _vtprintf   vprintf
+#define _vftprintf  vfprintf
+#define _vstprintf  vsprintf
+#define _vsntprintf _vsnprintf
+#define _tscanf     scanf
+#define _ftscanf    fscanf
+#define _stscanf    sscanf
+
+
+/* Unformatted i/o */
+
+#define _fgettc     fgetc
+#define _fgettchar  _fgetchar
+#define _fgetts     fgets
+#define _fputtc     fputc
+#define _fputtchar  _fputchar
+#define _fputts     fputs
+#define _gettc      getc
+#define _gettchar   getchar
+#define _getts      gets
+#define _puttc      putc
+#define _puttchar   putchar
+#define _putts      puts
+#define _ungettc    ungetc
+
+
+/* String conversion functions */
+
+#define _tcstod     strtod
+#define _tcstol     strtol
+#define _tcstoul    strtoul
+
+#define _itot       _itoa
+#define _ltot       _ltoa
+#define _ultot      _ultoa
+#define _ttoi       atoi
+#define _ttol       atol
+
+#define _ttoi64     _atoi64
+#define _i64tot     _i64toa
+#define _ui64tot    _ui64toa
+
+/* String functions */
+
+/* Note that _mbscat, _mbscpy and _mbsdup are functionally equivalent to 
+   strcat, strcpy and strdup, respectively. */
+
+#define _tcscat     strcat
+#define _tcscpy     strcpy
+#define _tcsdup     _strdup
+
+#define _tcslen     strlen
+#define _tcsxfrm    strxfrm
+
+
+/* Execute functions */
+
+#define _texecl     _execl
+#define _texecle    _execle
+#define _texeclp    _execlp
+#define _texeclpe   _execlpe
+#define _texecv     _execv
+#define _texecve    _execve
+#define _texecvp    _execvp
+#define _texecvpe   _execvpe
+
+#define _tspawnl    _spawnl
+#define _tspawnle   _spawnle
+#define _tspawnlp   _spawnlp
+#define _tspawnlpe  _spawnlpe
+#define _tspawnv    _spawnv
+#define _tspawnve   _spawnve
+#define _tspawnvp   _spawnvp
+#define _tspawnvpe  _spawnvpe
+
+#define _tsystem    system
+
+
+/* Time functions */
+
+#define _tasctime   asctime
+#define _tctime     ctime
+#define _tstrdate   _strdate
+#define _tstrtime   _strtime
+#define _tutime     _utime
+#define _tcsftime   strftime
+
+
+/* Directory functions */
+
+#define _tchdir     _chdir
+#define _tgetcwd    _getcwd
+#define _tgetdcwd   _getdcwd
+#define _tmkdir     _mkdir
+#define _trmdir     _rmdir
+
+
+/* Environment/Path functions */
+
+#define _tfullpath  _fullpath
+#define _tgetenv    getenv
+#define _tmakepath  _makepath
+#define _tputenv    _putenv
+#define _tsearchenv _searchenv
+#define _tsplitpath _splitpath
+
+
+/* Stdio functions */
+
+#ifdef  _POSIX_
+#define _tfdopen    fdopen
+#else
+#define _tfdopen    _fdopen
+#endif
+#define _tfsopen    _fsopen
+#define _tfopen     fopen
+#define _tfreopen   freopen
+#define _tperror    perror
+#define _tpopen     _popen
+#define _ttempnam   _tempnam
+#define _ttmpnam    tmpnam
+
+
+/* Io functions */
+
+#define _tchmod     _chmod
+#define _tcreat     _creat
+#define _tfindfirst _findfirst
+#define _tfindfirsti64  _findfirsti64
+#define _tfindnext  _findnext
+#define _tfindnexti64   _findnexti64
+#define _tmktemp    _mktemp
+
+#ifdef  _POSIX_
+#define _topen      open
+#define _taccess    access
+#else
+#define _topen      _open
+#define _taccess    _access
+#endif
+
+#define _tremove    remove
+#define _trename    rename
+#define _tsopen     _sopen
+#define _tunlink    _unlink
+
+#define _tfinddata_t    _finddata_t
+#define _tfinddatai64_t _finddatai64_t
+
+
+/* ctype functions */
+
+#define _istascii   isascii
+#define _istcntrl   iscntrl
+#define _istxdigit  isxdigit
+
+
+/* Stat functions */
+
+#define _tstat      _stat
+#define _tstati64   _stati64
+
+
+/* Setlocale functions */
+
+#define _tsetlocale setlocale
+
+
+#ifdef  _MBCS
+
+/* ++++++++++++++++++++ MBCS ++++++++++++++++++++ */
+
+#ifdef  __cplusplus
+}   /* ... extern "C" */
+#endif
+
+#include <mbstring.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef __TCHAR_DEFINED
+typedef char            _TCHAR;
+typedef signed char     _TSCHAR;
+typedef unsigned char   _TUCHAR;
+typedef unsigned char   _TXCHAR;
+typedef unsigned int    _TINT;
+#define __TCHAR_DEFINED
+#endif
+
+#ifndef _TCHAR_DEFINED
+#if     !__STDC__
+typedef char            TCHAR;
+#endif
+#define _TCHAR_DEFINED
+#endif
+
+
+#ifdef  _MB_MAP_DIRECT
+
+/* use mb functions directly - types must match */
+
+/* String functions */
+
+#define _tcschr     _mbschr
+#define _tcscspn    _mbscspn
+#define _tcsncat    _mbsnbcat
+#define _tcsncpy    _mbsnbcpy
+#define _tcspbrk    _mbspbrk
+#define _tcsrchr    _mbsrchr
+#define _tcsspn     _mbsspn
+#define _tcsstr     _mbsstr
+#define _tcstok     _mbstok
+
+#define _tcsnset    _mbsnbset
+#define _tcsrev     _mbsrev
+#define _tcsset     _mbsset
+
+#define _tcscmp     _mbscmp
+#define _tcsicmp    _mbsicmp
+#define _tcsnccmp   _mbsncmp
+#define _tcsncmp    _mbsnbcmp
+#define _tcsncicmp  _mbsnicmp
+#define _tcsnicmp   _mbsnbicmp
+
+#define _tcscoll    _mbscoll
+#define _tcsicoll   _mbsicoll
+#define _tcsnccoll  _mbsncoll
+#define _tcsncoll   _mbsnbcoll
+#define _tcsncicoll _mbsnicoll
+#define _tcsnicoll  _mbsnbicoll
+
+
+/* "logical-character" mappings */
+
+#define _tcsclen    _mbslen
+#define _tcsnccat   _mbsncat
+#define _tcsnccpy   _mbsncpy
+#define _tcsncset   _mbsnset
+
+
+/* MBCS-specific mappings */
+
+#define _tcsdec     _mbsdec
+#define _tcsinc     _mbsinc
+#define _tcsnbcnt   _mbsnbcnt
+#define _tcsnccnt   _mbsnccnt
+#define _tcsnextc   _mbsnextc
+#define _tcsninc    _mbsninc
+#define _tcsspnp    _mbsspnp
+
+#define _tcslwr     _mbslwr
+#define _tcsupr     _mbsupr
+
+#define _tclen      _mbclen
+#define _tccpy      _mbccpy
+
+#define _tccmp(_cpuc1,_cpuc2)   _tcsnccmp(_cpuc1,_cpuc2,1)
+
+
+#else /* _MB_MAP_DIRECT */
+
+#if     (__STDC__ || defined(_NO_INLINING)) && !defined(_M_M68K)
+
+/* use type-safe linked-in function thunks */
+
+/* String functions */
+
+_CRTIMP char * __cdecl _tcschr(const char *, unsigned int);
+_CRTIMP size_t __cdecl _tcscspn(const char *, const char *);
+_CRTIMP char * __cdecl _tcsncat(char *, const char *, size_t);
+_CRTIMP char * __cdecl _tcsncpy(char *, const char *, size_t);
+_CRTIMP char * __cdecl _tcspbrk(const char *, const char *);
+_CRTIMP char * __cdecl _tcsrchr(const char *, int);
+_CRTIMP size_t __cdecl _tcsspn(const char *, const char *);
+_CRTIMP char * __cdecl _tcsstr(const char *, const char *);
+_CRTIMP char * __cdecl _tcstok(char *, const char *);
+
+_CRTIMP char * __cdecl _tcsnset(char *, unsigned int, size_t);
+_CRTIMP char * __cdecl _tcsrev(char *);
+_CRTIMP char * __cdecl _tcsset(char *, unsigned int);
+
+_CRTIMP int __cdecl _tcscmp(const char *, const char *);
+_CRTIMP int __cdecl _tcsicmp(const char *, const char *);
+_CRTIMP int __cdecl _tcsnccmp(const char *, const char *, size_t);
+_CRTIMP int __cdecl _tcsncmp(const char *, const char *, size_t);
+_CRTIMP int __cdecl _tcsncicmp(const char *, const char *, size_t);
+_CRTIMP int __cdecl _tcsnicmp(const char *, const char *, size_t);
+
+_CRTIMP int __cdecl _tcscoll(const char *, const char *);
+_CRTIMP int __cdecl _tcsicoll(const char *, const char *);
+_CRTIMP int __cdecl _tcsnccoll(const char *, const char *, size_t);
+_CRTIMP int __cdecl _tcsncoll(const char *, const char *, size_t);
+_CRTIMP int __cdecl _tcsncicoll(const char *, const char *, size_t);
+_CRTIMP int __cdecl _tcsnicoll(const char *, const char *, size_t);
+
+
+/* "logical-character" mappings */
+
+_CRTIMP size_t __cdecl _tcsclen(const char *);
+_CRTIMP char * __cdecl _tcsnccat(char *, const char *, size_t);
+_CRTIMP char * __cdecl _tcsnccpy(char *, const char *, size_t);
+_CRTIMP char * __cdecl _tcsncset(char *, unsigned int, size_t);
+
+
+/* MBCS-specific mappings */
+
+_CRTIMP char * __cdecl _tcsdec(const char *, const char *);
+_CRTIMP char * __cdecl _tcsinc(const char *);
+_CRTIMP size_t __cdecl _tcsnbcnt(const char *, size_t);
+_CRTIMP size_t __cdecl _tcsnccnt(const char *, size_t);
+_CRTIMP unsigned int __cdecl _tcsnextc (const char *);
+_CRTIMP char * __cdecl _tcsninc(const char *, size_t);
+_CRTIMP char * __cdecl _tcsspnp(const char *, const char *);
+
+_CRTIMP char * __cdecl _tcslwr(char *);
+_CRTIMP char * __cdecl _tcsupr(char *);
+
+_CRTIMP size_t __cdecl _tclen(const char *);
+_CRTIMP void __cdecl _tccpy(char *, const char *);
+
+
+#else   /* __STDC__ */
+
+/* the default: use type-safe inline function thunks */
+
+#define _PUC    unsigned char *
+#define _CPUC   const unsigned char *
+#define _PC     char *
+#define _CPC    const char *
+#define _UI     unsigned int
+
+
+/* String functions */
+
+__inline _PC _tcschr(_CPC _s1,_UI _c) {return (_PC)_mbschr((_CPUC)_s1,_c);}
+__inline size_t _tcscspn(_CPC _s1,_CPC _s2) {return _mbscspn((_CPUC)_s1,(_CPUC)_s2);}
+__inline _PC _tcsncat(_PC _s1,_CPC _s2,size_t _n) {return (_PC)_mbsnbcat((_PUC)_s1,(_CPUC)_s2,_n);}
+__inline _PC _tcsncpy(_PC _s1,_CPC _s2,size_t _n) {return (_PC)_mbsnbcpy((_PUC)_s1,(_CPUC)_s2,_n);}
+__inline _PC _tcspbrk(_CPC _s1,_CPC _s2) {return (_PC)_mbspbrk((_CPUC)_s1,(_CPUC)_s2);}
+__inline _PC _tcsrchr(_CPC _s1,_UI _c) {return (_PC)_mbsrchr((_CPUC)_s1,_c);}
+__inline size_t _tcsspn(_CPC _s1,_CPC _s2) {return _mbsspn((_CPUC)_s1,(_CPUC)_s2);}
+__inline _PC _tcsstr(_CPC _s1,_CPC _s2) {return (_PC)_mbsstr((_CPUC)_s1,(_CPUC)_s2);}
+__inline _PC _tcstok(_PC _s1,_CPC _s2) {return (_PC)_mbstok((_PUC)_s1,(_CPUC)_s2);}
+
+__inline _PC _tcsnset(_PC _s1,_UI _c,size_t _n) {return (_PC)_mbsnbset((_PUC)_s1,_c,_n);}
+__inline _PC _tcsrev(_PC _s1) {return (_PC)_mbsrev((_PUC)_s1);}
+__inline _PC _tcsset(_PC _s1,_UI _c) {return (_PC)_mbsset((_PUC)_s1,_c);}
+
+__inline int _tcscmp(_CPC _s1,_CPC _s2) {return _mbscmp((_CPUC)_s1,(_CPUC)_s2);}
+__inline int _tcsicmp(_CPC _s1,_CPC _s2) {return _mbsicmp((_CPUC)_s1,(_CPUC)_s2);}
+__inline int _tcsnccmp(_CPC _s1,_CPC _s2,size_t _n) {return _mbsncmp((_CPUC)_s1,(_CPUC)_s2,_n);}
+__inline int _tcsncmp(_CPC _s1,_CPC _s2,size_t _n) {return _mbsnbcmp((_CPUC)_s1,(_CPUC)_s2,_n);}
+__inline int _tcsncicmp(_CPC _s1,_CPC _s2,size_t _n) {return _mbsnicmp((_CPUC)_s1,(_CPUC)_s2,_n);}
+__inline int _tcsnicmp(_CPC _s1,_CPC _s2,size_t _n) {return _mbsnbicmp((_CPUC)_s1,(_CPUC)_s2,_n);}
+
+__inline int _tcscoll(_CPC _s1,_CPC _s2) {return _mbscoll((_CPUC)_s1,(_CPUC)_s2);}
+__inline int _tcsicoll(_CPC _s1,_CPC _s2) {return _mbsicoll((_CPUC)_s1,(_CPUC)_s2);}
+__inline int _tcsnccoll(_CPC _s1,_CPC _s2,size_t _n) {return _mbsncoll((_CPUC)_s1,(_CPUC)_s2,_n);}
+__inline int _tcsncoll(_CPC _s1,_CPC _s2,size_t _n) {return _mbsnbcoll((_CPUC)_s1,(_CPUC)_s2,_n);}
+__inline int _tcsncicoll(_CPC _s1,_CPC _s2,size_t _n) {return _mbsnicoll((_CPUC)_s1,(_CPUC)_s2,_n);}
+__inline int _tcsnicoll(_CPC _s1,_CPC _s2,size_t _n) {return _mbsnbicoll((_CPUC)_s1,(_CPUC)_s2,_n);}
+
+
+/* "logical-character" mappings */
+
+__inline size_t _tcsclen(_CPC _s1) {return _mbslen((_CPUC)_s1);}
+__inline _PC _tcsnccat(_PC _s1,_CPC _s2,size_t _n) {return (_PC)_mbsncat((_PUC)_s1,(_CPUC)_s2,_n);}
+__inline _PC _tcsnccpy(_PC _s1,_CPC _s2,size_t _n) {return (_PC)_mbsncpy((_PUC)_s1,(_CPUC)_s2,_n);}
+__inline _PC _tcsncset(_PC _s1,_UI _c,size_t _n) {return (_PC)_mbsnset((_PUC)_s1,_c,_n);}
+
+
+/* MBCS-specific mappings */
+
+__inline _PC _tcsdec(_CPC _s1,_CPC _s2) {return (_PC)_mbsdec((_CPUC)_s1,(_CPUC)_s2);}
+__inline _PC _tcsinc(_CPC _s1) {return (_PC)_mbsinc((_CPUC)_s1);}
+__inline size_t _tcsnbcnt(_CPC _s1,size_t _n) {return _mbsnbcnt((_CPUC)_s1,_n);}
+__inline size_t _tcsnccnt(_CPC _s1,size_t _n) {return _mbsnccnt((_CPUC)_s1,_n);}
+__inline _PC _tcsninc(_CPC _s1,size_t _n) {return (_PC)_mbsninc((_CPUC)_s1,_n);}
+__inline _PC _tcsspnp(_CPC _s1,_CPC _s2) {return (_PC)_mbsspnp((_CPUC)_s1,(_CPUC)_s2);}
+__inline _PC _tcslwr(_PC _s1) {return (_PC)_mbslwr((_PUC)_s1);}
+__inline _PC _tcsupr(_PC _s1) {return (_PC)_mbsupr((_PUC)_s1);}
+
+__inline size_t _tclen(_CPC _s1) {return _mbclen((_CPUC)_s1);}
+__inline void _tccpy(_PC _s1,_CPC _s2) {_mbccpy((_PUC)_s1,(_CPUC)_s2); return;}
+
+
+/* inline helper */
+__inline _UI _tcsnextc(_CPC _s1) {_UI _n=0; if (_ismbblead((_UI)*(_PUC)_s1)) _n=((_UI)*_s1++)<<8; _n+=(_UI)*_s1; return(_n);}
+
+
+#endif  /* __STDC__ */
+
+#endif  /* _MB_MAP_DIRECT */
+
+
+/* MBCS-specific mappings */
+
+#define _tccmp(_cp1,_cp2)   _tcsnccmp(_cp1,_cp2,1)
+
+
+/* ctype functions */
+
+#define _istalnum   _ismbcalnum
+#define _istalpha   _ismbcalpha
+#define _istdigit   _ismbcdigit
+#define _istgraph   _ismbcgraph
+#define _istlegal   _ismbclegal
+#define _istlower   _ismbclower
+#define _istprint   _ismbcprint
+#define _istpunct   _ismbcpunct
+#define _istspace   _ismbcspace
+#define _istupper   _ismbcupper
+
+#define _totupper   _mbctoupper
+#define _totlower   _mbctolower
+
+#define _istlead    _ismbblead
+#define _istleadbyte    isleadbyte
+
+#else   /* !_MBCS */
+
+/* ++++++++++++++++++++ SBCS ++++++++++++++++++++ */
+
+
+#ifndef __TCHAR_DEFINED
+typedef char            _TCHAR;
+typedef signed char     _TSCHAR;
+typedef unsigned char   _TUCHAR;
+typedef char            _TXCHAR;
+typedef int             _TINT;
+#define __TCHAR_DEFINED
+#endif
+
+#ifndef _TCHAR_DEFINED
+#if     !__STDC__
+typedef char            TCHAR;
+#endif
+#define _TCHAR_DEFINED
+#endif
+
+
+/* String functions */
+
+#define _tcschr     strchr
+#define _tcscspn    strcspn
+#define _tcsncat    strncat
+#define _tcsncpy    strncpy
+#define _tcspbrk    strpbrk
+#define _tcsrchr    strrchr
+#define _tcsspn     strspn
+#define _tcsstr     strstr
+#define _tcstok     strtok
+
+#define _tcsnset    _strnset
+#define _tcsrev     _strrev
+#define _tcsset     _strset
+
+#define _tcscmp     strcmp
+#define _tcsicmp    _stricmp
+#define _tcsnccmp   strncmp
+#define _tcsncmp    strncmp
+#define _tcsncicmp  _strnicmp
+#define _tcsnicmp   _strnicmp
+
+#define _tcscoll    strcoll
+#define _tcsicoll   _stricoll
+#define _tcsnccoll  _strncoll
+#define _tcsncoll   _strncoll
+#define _tcsncicoll _strnicoll
+#define _tcsnicoll  _strnicoll
+
+
+/* "logical-character" mappings */
+
+#define _tcsclen    strlen
+#define _tcsnccat   strncat
+#define _tcsnccpy   strncpy
+#define _tcsncset   _strnset
+
+
+/* MBCS-specific functions */
+
+#define _tcsdec     _strdec
+#define _tcsinc     _strinc
+#define _tcsnbcnt   _strncnt
+#define _tcsnccnt   _strncnt
+#define _tcsnextc   _strnextc
+#define _tcsninc    _strninc
+#define _tcsspnp    _strspnp
+
+#define _tcslwr     _strlwr
+#define _tcsupr     _strupr
+#define _tcsxfrm    strxfrm
+
+#define _istlead(_c)    (0)
+#define _istleadbyte(_c)    (0)
+
+#if     (__STDC__ || defined(_NO_INLINING)) && !defined(_M_M68K)
+#define _tclen(_pc) (1)
+#define _tccpy(_pc1,_cpc2) (*(_pc1) = *(_cpc2))
+#define _tccmp(_cpc1,_cpc2) (((unsigned char)*(_cpc1))-((unsigned char)*(_cpc2)))
+#else   /* __STDC__ */
+__inline size_t __cdecl _tclen(const char *_cpc) { return (_cpc,1); }
+__inline void __cdecl _tccpy(char *_pc1, const char *_cpc2) { *_pc1 = *_cpc2; }
+__inline int __cdecl _tccmp(const char *_cpc1, const char *_cpc2) { return (int) (((unsigned char)*_cpc1)-((unsigned char)*_cpc2)); }
+#endif  /* __STDC__ */
+
+
+/* ctype-functions */
+
+#define _istalnum   isalnum
+#define _istalpha   isalpha
+#define _istdigit   isdigit
+#define _istgraph   isgraph
+#define _istlower   islower
+#define _istprint   isprint
+#define _istpunct   ispunct
+#define _istspace   isspace
+#define _istupper   isupper
+
+#define _totupper   toupper
+#define _totlower   tolower
+
+#define _istlegal(_c)   (1)
+
+
+/* the following is optional if functional versions are available */
+
+/* define NULL pointer value */
+
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL    0
+#else
+#define NULL    ((void *)0)
+#endif
+#endif
+
+
+#if     (__STDC__ || defined(_NO_INLINING)) && !defined(_M_M68K)
+#define _strdec(_cpc1, _cpc2) ((_cpc1)>=(_cpc2) ? NULL : (_cpc2)-1)
+#define _strinc(_pc)    ((_pc)+1)
+#define _strnextc(_cpc) ((unsigned int) *(_cpc))
+#define _strninc(_pc, _sz) (((_pc)+(_sz)))
+#define _strncnt(_cpc, _sz) ((strlen(_cpc)>_sz) ? _sz : strlen(_cpc))
+#define _strspnp(_cpc1, _cpc2) ((*((_cpc1)+strspn(_cpc1,_cpc2))) ? ((_cpc1)+strspn(_cpc1,_cpc2)) : NULL)
+#else   /* __STDC__ */
+__inline char * __cdecl _strdec(const char * _cpc1, const char * _cpc2) { return (char *)((_cpc1)>=(_cpc2) ? NULL : (_cpc2-1)); }
+__inline char * __cdecl _strinc(const char * _pc) { return (char *)(_pc+1); }
+__inline unsigned int __cdecl _strnextc(const char * _cpc) { return (unsigned int)*_cpc; }
+__inline char * __cdecl _strninc(const char * _pc, size_t _sz) { return (char *)(_pc+_sz); }
+__inline size_t __cdecl _strncnt( const char * _cpc, size_t _sz) { size_t len; len = strlen(_cpc); return (len>_sz) ? _sz : len; }
+__inline char * __cdecl _strspnp( const char * _cpc1, const char * _cpc2) { return (*(_cpc1 += strspn(_cpc1,_cpc2))!='\0') ? (char*)_cpc1 : NULL; }
+#endif  /* __STDC__ */
+
+
+#endif  /* _MBCS */
+
+#endif  /* _UNICODE */
+
+
+/* Generic text macros to be used with string literals and character constants.
+   Will also allow symbolic constants that resolve to same. */
+
+#define _T(x)       __T(x)
+#define _TEXT(x)    __T(x)
+
+
+#ifdef  __cplusplus
+}   /* ... extern "C" */
+#endif
+
+#endif  /* _INC_TCHAR */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/ACKNOWLEDGMENTS
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/ACKNOWLEDGMENTS	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/ACKNOWLEDGMENTS	(revision 10506)
@@ -0,0 +1,2 @@
+This product includes software developed by the
+Apache Software Foundation (http://www.apache.org/).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/COPYING
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/COPYING	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/COPYING	(revision 10506)
@@ -0,0 +1,345 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 		59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    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
+
+
+	Appendix: 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: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/Counter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/Counter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/Counter.java	(revision 10506)
@@ -0,0 +1,73 @@
+/*
+ *    Counter.java
+ *    Copyright (C) 2000 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import java.io.*;
+
+/**
+ * Class that implements a simple counter.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public class Counter implements Serializable {
+  
+  /** Integer value stored */
+    private int m_val = 1;
+  
+  /**
+   * Initializes the counter to 1
+   */
+  public Counter() {
+    
+    m_val = 1;
+  }
+  
+  /**
+   * Initializes the counter to the given value
+   */
+  public Counter(int val) {
+    
+    m_val = val;
+  }
+  
+  /**
+   * Increments the counter.
+   */
+  public void increment() {
+    
+    m_val++;
+  }
+  
+  /**
+   * Gets the value.
+   * @return the value
+   */
+  public int value() {
+    
+    return m_val;
+  }
+  
+  /**
+   * Returns string containing value.
+   */
+  public String toString() {
+    
+    return String.valueOf(m_val);
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/GermanStemmer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/GermanStemmer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/GermanStemmer.java	(revision 10506)
@@ -0,0 +1,309 @@
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ *    "Apache Lucene" must not be used to endorse or promote products
+ *    derived from this software without prior written permission. For
+ *    written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    "Apache Lucene", nor may "Apache" appear in their name, without
+ *    prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+/**
+ * A stemmer for German words. The algorithm is based on the report
+ * "A Fast and Simple Stemming Algorithm for German Words" by Jörg
+ * Caumanns (joerg.caumanns@isst.fhg.de).
+ *
+ * Changed stem() from protected to public.
+ * Changed coding for umlaute to unicode.
+ *
+ * @author    Gerhard Schwarz
+ * @version   $Id$
+ */
+public class GermanStemmer extends Stemmer
+{
+    /**
+     * Buffer for the terms while stemming them.
+     */
+    private StringBuffer sb = new StringBuffer();
+
+    /**
+     * Indicates if a term is handled as a noun.
+     */
+    private boolean uppercase = false;
+
+    /**
+     * Amount of characters that are removed with <tt>substitute()</tt> while stemming.
+     */
+    private int substCount = 0;
+
+    /**
+     * Stemms the given term to an unique <tt>discriminator</tt>.
+     *
+     * @param term  The term that should be stemmed.
+     * @return      Discriminator for <tt>term</tt>
+     */
+    public String stem( String term )
+    {
+	// Mark a possible noun.
+	uppercase = Character.isUpperCase( term.charAt( 0 ) );
+	// Use lowercase for medium stemming.
+	term = term.toLowerCase();
+	if ( !isStemmable( term ) )
+	    return term;
+	// Reset the StringBuffer.
+	sb.delete( 0, sb.length() );
+	sb.insert( 0, term );
+	// Stemming starts here...
+	substitute( sb );
+	strip( sb );
+	optimize( sb );
+	resubstitute( sb );
+	removeParticleDenotion( sb );
+	return sb.toString();
+    }
+
+    /**
+     * Checks if a term could be stemmed.
+     *
+     * @return  true if, and only if, the given term consists in letters.
+     */
+    private boolean isStemmable( String term )
+    {
+	for ( int c = 0; c < term.length(); c++ ) {
+	    if ( !Character.isLetter( term.charAt( c ) ) ) return false;
+	}
+	return true;
+    }
+
+    /**
+     * suffix stripping (stemming) on the current term. The stripping is reduced
+     * to the seven "base" suffixes "e", "s", "n", "t", "em", "er" and * "nd",
+     * from which all regular suffixes are build of. The simplification causes
+     * some overstemming, and way more irregular stems, but still provides unique.
+     * discriminators in the most of those cases.
+     * The algorithm is context free, except of the length restrictions.
+     */
+    private void strip( StringBuffer buffer )
+    {
+	boolean doMore = true;
+	while ( doMore && buffer.length() > 3 ) {
+	    if ( ( buffer.length() + substCount > 5 ) &&
+		buffer.substring( buffer.length() - 2, buffer.length() ).equals( "nd" ) )
+	    {
+		buffer.delete( buffer.length() - 2, buffer.length() );
+	    }
+	    else if ( ( buffer.length() + substCount > 4 ) &&
+		buffer.substring( buffer.length() - 2, buffer.length() ).equals( "em" ) ) {
+		buffer.delete( buffer.length() - 2, buffer.length() );
+	    }
+	    else if ( ( buffer.length() + substCount > 4 ) &&
+		buffer.substring( buffer.length() - 2, buffer.length() ).equals( "er" ) ) {
+		buffer.delete( buffer.length() - 2, buffer.length() );
+	    }
+	    else if ( buffer.charAt( buffer.length() - 1 ) == 'e' ) {
+		buffer.deleteCharAt( buffer.length() - 1 );
+	    }
+	    else if ( buffer.charAt( buffer.length() - 1 ) == 's' ) {
+		buffer.deleteCharAt( buffer.length() - 1 );
+	    }
+	    else if ( buffer.charAt( buffer.length() - 1 ) == 'n' ) {
+		buffer.deleteCharAt( buffer.length() - 1 );
+	    }
+	    // "t" occurs only as suffix of verbs.
+	    else if ( buffer.charAt( buffer.length() - 1 ) == 't' && !uppercase ) {
+		buffer.deleteCharAt( buffer.length() - 1 );
+	    }
+	    else {
+		doMore = false;
+	    }
+	}
+    }
+
+    /**
+     * Does some optimizations on the term. This optimisations are
+     * contextual.
+     */
+    private void optimize( StringBuffer buffer )
+    {
+	// Additional step for female plurals of professions and inhabitants.
+	if ( buffer.length() > 5 && buffer.substring( buffer.length() - 5, buffer.length() ).equals( "erin*" ) ) {
+	    buffer.deleteCharAt( buffer.length() -1 );
+	    strip( buffer );
+	}
+	// Additional step for irregular plural nouns like "Matrizen -> Matrix".
+	if ( buffer.charAt( buffer.length() - 1 ) == ( 'z' ) ) {
+	    buffer.setCharAt( buffer.length() - 1, 'x' );
+	}
+    }
+
+    /**
+     * Removes a particle denotion ("ge") from a term.
+     */
+    private void removeParticleDenotion( StringBuffer buffer )
+    {
+	if ( buffer.length() > 4 ) {
+	    for ( int c = 0; c < buffer.length() - 3; c++ ) {
+		if ( buffer.substring( c, c + 4 ).equals( "gege" ) ) {
+		    buffer.delete( c, c + 2 );
+		    return;
+		}
+	    }
+	}
+    }
+
+    /**
+     * Do some substitutions for the term to reduce overstemming:
+     *
+     * - Substitute Umlauts with their corresponding vowel: äöü -> aou,
+     *   "ß" is substituted by "ss"
+     * - Substitute a second char of a pair of equal characters with
+     *   an asterisk: ?? -> ?*
+     * - Substitute some common character combinations with a token:
+     *   sch/ch/ei/ie/ig/st -> $/§/%/&/#/!
+     */
+    private void substitute( StringBuffer buffer )
+    {
+	substCount = 0;
+	for ( int c = 0; c < buffer.length(); c++ ) {
+	    // Replace the second char of a pair of the equal characters with an asterisk
+	    if ( c > 0 && buffer.charAt( c ) == buffer.charAt ( c - 1 )  ) {
+		buffer.setCharAt( c, '*' );
+	    }
+	    // Substitute Umlauts.
+	    else if ( buffer.charAt( c ) == '\u00E4' ) {
+		buffer.setCharAt( c, 'a' );
+	    }
+	    else if ( buffer.charAt( c ) == '\u00F6' ) {
+		buffer.setCharAt( c, 'o' );
+	    }
+	    else if ( buffer.charAt( c ) == '\u00FC' ) {
+		buffer.setCharAt( c, 'u' );
+	    }
+	    // Take care that at least one character is left left side from the current one
+	    if ( c < buffer.length() - 1 ) {
+		if ( buffer.charAt( c ) == '\u00DF' ) {
+		    buffer.setCharAt( c, 's' );
+		    buffer.insert( c + 1, 's' );
+		    substCount++;
+		}
+		// Masking several common character combinations with an token
+		else if ( ( c < buffer.length() - 2 ) && buffer.charAt( c ) == 's' &&
+		    buffer.charAt( c + 1 ) == 'c' && buffer.charAt( c + 2 ) == 'h' )
+		{
+		    buffer.setCharAt( c, '$' );
+		    buffer.delete( c + 1, c + 3 );
+		    substCount =+ 2;
+		}
+		else if ( buffer.charAt( c ) == 'c' && buffer.charAt( c + 1 ) == 'h' ) {
+		    buffer.setCharAt( c, '§' );
+		    buffer.deleteCharAt( c + 1 );
+		    substCount++;
+		}
+		else if ( buffer.charAt( c ) == 'e' && buffer.charAt( c + 1 ) == 'i' ) {
+		    buffer.setCharAt( c, '%' );
+		    buffer.deleteCharAt( c + 1 );
+		    substCount++;
+		}
+		else if ( buffer.charAt( c ) == 'i' && buffer.charAt( c + 1 ) == 'e' ) {
+		    buffer.setCharAt( c, '&' );
+		    buffer.deleteCharAt( c + 1 );
+		    substCount++;
+		}
+		else if ( buffer.charAt( c ) == 'i' && buffer.charAt( c + 1 ) == 'g' ) {
+		    buffer.setCharAt( c, '#' );
+		    buffer.deleteCharAt( c + 1 );
+		    substCount++;
+		}
+		else if ( buffer.charAt( c ) == 's' && buffer.charAt( c + 1 ) == 't' ) {
+		    buffer.setCharAt( c, '!' );
+		    buffer.deleteCharAt( c + 1 );
+		    substCount++;
+		}
+	    }
+	}
+    }
+
+    /**
+     * Undoes the changes made by substitute(). That are character pairs and
+     * character combinations. Umlauts will remain as their corresponding vowel,
+     * as "ß" remains as "ss".
+     */
+    private void resubstitute( StringBuffer buffer )
+    {
+	for ( int c = 0; c < buffer.length(); c++ ) {
+	    if ( buffer.charAt( c ) == '*' ) {
+		char x = buffer.charAt( c - 1 );
+		buffer.setCharAt( c, x );
+	    }
+	    else if ( buffer.charAt( c ) == '$' ) {
+		buffer.setCharAt( c, 's' );
+		buffer.insert( c + 1, new char[]{'c', 'h'}, 0, 2 );
+	    }
+	    else if ( buffer.charAt( c ) == '§' ) {
+		buffer.setCharAt( c, 'c' );
+		buffer.insert( c + 1, 'h' );
+	    }
+	    else if ( buffer.charAt( c ) == '%' ) {
+		buffer.setCharAt( c, 'e' );
+		buffer.insert( c + 1, 'i' );
+	    }
+	    else if ( buffer.charAt( c ) == '&' ) {
+		buffer.setCharAt( c, 'i' );
+		buffer.insert( c + 1, 'e' );
+	    }
+	    else if ( buffer.charAt( c ) == '#' ) {
+		buffer.setCharAt( c, 'i' );
+		buffer.insert( c + 1, 'g' );
+	    }
+	    else if ( buffer.charAt( c ) == '!' ) {
+		buffer.setCharAt( c, 's' );
+		buffer.insert( c + 1, 't' );
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/IteratedLovinsStemmer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/IteratedLovinsStemmer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/IteratedLovinsStemmer.java	(revision 10506)
@@ -0,0 +1,76 @@
+/*
+ *    IteratedLovinsStemmer.java
+ *    Copyright (C) 2001 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import java.util.*;
+
+/**
+ * Implements the iterated version of the Lovins stemmer.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public class IteratedLovinsStemmer extends LovinsStemmer {
+
+  /**
+   * Iterated stemming of the given word.
+   */
+  public String stem(String str) {
+
+    if (str.length() <= 2) {
+      return str;
+    }
+    String stemmed = super.stem(str);
+    while (!stemmed.equals(str)) {
+      str = stemmed;
+      stemmed = super.stem(stemmed);
+    }
+    return stemmed;
+  }
+
+  /**
+   * Stems text coming into stdin and writes it to stdout.
+   */
+  public static void main(String[] ops) {
+
+    IteratedLovinsStemmer ls = new IteratedLovinsStemmer();
+
+    try {
+      int num;
+      StringBuffer wordBuffer = new StringBuffer();
+      while ((num = System.in.read()) != -1) {
+	char c = (char)num;
+	if (((num >= (int)'A') && (num <= (int)'Z')) ||
+	    ((num >= (int)'a') && (num <= (int)'z'))) {
+	  wordBuffer.append(c);
+	} else {
+	  if (wordBuffer.length() > 0) {
+	    System.out.print(ls.stem(wordBuffer.toString().
+				     toLowerCase()));
+	    wordBuffer = new StringBuffer();
+	  }
+	  System.out.print(c);
+	}
+      }
+    } catch (Exception e) {
+      System.err.println(e.getMessage());
+    }
+  }
+}
+    
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAFilter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAFilter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAFilter.java	(revision 10506)
@@ -0,0 +1,1496 @@
+/*
+ *    KEAFilter.java
+ *    Copyright (C) 2000, 2001 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import java.util.*;
+import java.io.*;
+
+import weka.core.*;
+import weka.filters.*;
+import weka.classifiers.*;
+
+/**
+ * This filter converts the incoming data into data appropriate for
+ * keyphrase classification. It assumes that the dataset contains two
+ * string attributes. The first attribute should contain the text of a
+ * document. The second attribute should contain the keyphrases
+ * associated with that document (if present). 
+ *
+ * The filter converts every instance (i.e. document) into a set of
+ * instances, one for each word-based n-gram in the document. The
+ * string attribute representing the document is replaced by some
+ * numeric features, the estimated probability of each n-gram being a
+ * keyphrase, and the rank of this phrase in the document according to
+ * the probability.  Each new instances also has a class value
+ * associated with it. The class is "true" if the n-gram is a true
+ * keyphrase, and "false" otherwise. Of course, if the input document
+ * doesn't come with author-assigned keyphrases, the class values for
+ * that document will be missing.  
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+  */
+public class KEAFilter extends Filter implements OptionHandler {
+
+  /** Index of attribute containing the documents */
+  private int m_DocumentAtt = 0;
+
+  /** Index of attribute containing the keyphrases */
+  private int m_KeyphrasesAtt = 1;
+
+  /** The maximum length of phrases */
+  private int m_MaxPhraseLength = 3;
+
+  /** The minimum length of phrases */
+  private int m_MinPhraseLength = 1;
+
+  /** Is keyphrase frequency attribute being used? */
+  private boolean m_KFused = false;
+
+  /** Flag for debugging mode */
+  private boolean m_Debug = false;
+
+  /** Determines whether internal periods are allowed */
+  private boolean m_DisallowInternalPeriods = false;
+
+  /** The minimum number of occurences of a phrase */
+  private int m_MinNumOccur = 2;
+
+  /** The number of features describing a phrase */
+  private int m_NumFeatures = 2;
+
+  /* Indices of attributes in m_ClassifierData */
+  private int m_TfidfIndex = 0;
+  private int m_FirstOccurIndex = 1;
+  private int m_KeyFreqIndex = 2;
+
+  /** The punctuation filter used by this filter */
+  private KEAPhraseFilter m_PunctFilter = null;
+
+  /** The numbers filter used by this filter */
+  private NumbersFilter m_NumbersFilter = null;
+ 
+  /** The actual classifier used to compute probabilities */
+  private DistributionClassifier m_Classifier = null;
+
+  /** The dictionary containing the document frequencies */
+  private HashMap m_Dictionary = null;
+
+  /** The dictionary containing the keyphrases */
+  private HashMap m_KeyphraseDictionary = null;
+
+  /** The number of documents in the global frequencies corpus */
+  private int m_NumDocs = 0;
+
+  /** Template for the classifier data */
+  private Instances m_ClassifierData = null;
+
+  /** The stemmer to be used */
+  private Stemmer m_Stemmer = new IteratedLovinsStemmer();
+
+  /** The list of stop words to be used */
+  private Stopwords m_Stopwords = new StopwordsEnglish();
+
+  /** Determines whether check for proper nouns is performed */
+  private boolean m_CheckForProperNouns = true;
+
+  /**
+   * Get the M_CheckProperNouns value.
+   * @return the M_CheckProperNouns value.
+   */
+  public boolean getCheckForProperNouns() {
+    return m_CheckForProperNouns;
+  }
+
+  /**
+   * Set the M_CheckProperNouns value.
+   * @param newM_CheckProperNouns The new M_CheckProperNouns value.
+   */
+  public void setCheckForProperNouns(boolean newM_CheckProperNouns) {
+    this.m_CheckForProperNouns = newM_CheckProperNouns;
+  }
+  
+  /**
+   * Get the M_Stopwords value.
+   * @return the M_Stopwords value.
+   */
+  public Stopwords getStopwords() {
+    return m_Stopwords;
+  }
+
+  /**
+   * Set the M_Stopwords value.
+   * @param newM_Stopwords The new M_Stopwords value.
+   */
+  public void setStopwords(Stopwords newM_Stopwords) {
+    this.m_Stopwords = newM_Stopwords;
+  }
+
+  
+  /**
+   * Get the Stemmer value.
+   * @return the Stemmer value.
+   */
+  public Stemmer getStemmer() {
+
+    return m_Stemmer;
+  }
+
+  /**
+   * Set the Stemmer value.
+   * @param newStemmer The new Stemmer value.
+   */
+  public void setStemmer(Stemmer newStemmer) {
+
+    this.m_Stemmer = newStemmer;
+  }
+
+  /**
+   * Get the value of MinNumOccur.
+   *
+   * @return Value of MinNumOccur.
+   */
+  public int getMinNumOccur() {
+    
+    return m_MinNumOccur;
+  }
+  
+  /**
+   * Set the value of MinNumOccur.
+   *
+   * @param newMinNumOccur Value to assign to MinNumOccur.
+   */
+  public void setMinNumOccur(int newMinNumOccur) {
+    
+    m_MinNumOccur = newMinNumOccur;
+  }
+  
+  /**
+   * Get the value of MaxPhraseLength.
+   *
+   * @return Value of MaxPhraseLength.
+   */
+  public int getMaxPhraseLength() {
+    
+    return m_MaxPhraseLength;
+  }
+  
+  /**
+   * Set the value of MaxPhraseLength.
+   *
+   * @param newMaxPhraseLength Value to assign to MaxPhraseLength.
+   */
+  public void setMaxPhraseLength(int newMaxPhraseLength) {
+    
+    m_MaxPhraseLength = newMaxPhraseLength;
+  }
+  
+  /**
+   * Get the value of MinPhraseLength.
+   *
+   * @return Value of MinPhraseLength.
+   */
+  public int getMinPhraseLength() {
+    
+    return m_MinPhraseLength;
+  }
+  
+  /**
+   * Set the value of MinPhraseLength.
+   *
+   * @param newMinPhraseLength Value to assign to MinPhraseLength.
+   */
+  public void setMinPhraseLength(int newMinPhraseLength) {
+    
+    m_MinPhraseLength = newMinPhraseLength;
+  }
+
+  /**
+   * Returns the index of the stemmed phrases in the output ARFF file.
+   */
+  public int getStemmedPhraseIndex() {
+
+    return m_DocumentAtt;
+  }
+
+  /**
+   * Returns the index of the unstemmed phrases in the output ARFF file.
+   */
+  public int getUnstemmedPhraseIndex() {
+
+    return m_DocumentAtt + 1;
+  }
+
+  /**
+   * Returns the index of the phrases' probabilities in the output ARFF file.
+   */
+  public int getProbabilityIndex() {
+
+    int index = m_DocumentAtt + 4;
+
+    if (m_Debug) {
+      if (m_KFused) {
+	index++;
+      }
+    }
+    return index;
+  }
+
+  /**
+   * Returns the index of the phrases' ranks in the output ARFF file.
+   */
+  public int getRankIndex() {
+
+    return getProbabilityIndex() + 1;
+  }
+
+  /**
+   * Get the value of DocumentAtt.
+   *
+   * @return Value of DocumentAtt.
+   */
+  public int getDocumentAtt() {
+    
+    return m_DocumentAtt;
+  }
+  
+  /**
+   * Set the value of DocumentAtt.
+   *
+   * @param newDocumentAtt Value to assign to DocumentAtt.
+   */
+  public void setDocumentAtt(int newDocumentAtt) {
+    
+    m_DocumentAtt = newDocumentAtt;
+  }
+  
+  /**
+   * Get the value of KeyphraseAtt.
+   *
+   * @return Value of KeyphraseAtt.
+   */
+  public int getKeyphrasesAtt() {
+    
+    return m_KeyphrasesAtt;
+  }
+  
+  /**
+   * Set the value of KeyphrasesAtt.
+   *
+   * @param newKeyphrasesAtt Value to assign to KeyphrasesAtt.
+   */
+  public void setKeyphrasesAtt(int newKeyphrasesAtt) {
+    
+    m_KeyphrasesAtt = newKeyphrasesAtt;
+  }
+  
+  
+  /**
+   * Get the value of Debug.
+   *
+   * @return Value of Debug.
+   */
+  public boolean getDebug() {
+    
+    return m_Debug;
+  }
+  
+  /**
+   * Set the value of Debug.
+   *
+   * @param newDebug Value to assign to Debug.
+   */
+  public void setDebug(boolean newDebug) {
+    
+    m_Debug = newDebug;
+  }
+
+  /**
+   * Sets whether keyphrase frequency attribute is used.
+   */
+  public void setKFused(boolean flag) {
+
+    m_KFused = flag;
+    if (flag) {
+      m_NumFeatures = 3;
+    } else {
+      m_NumFeatures = 2;
+    }
+  }
+
+  /**
+   * Gets whether keyphrase frequency attribute is used.
+   */
+  public boolean getKFused() {
+
+    return m_KFused;
+  }
+
+  /**
+   * Get whether the supplied columns are to be processed
+   *
+   * @return true if the supplied columns won't be processed
+   */
+  public boolean getDisallowInternalPeriods() {
+
+    return m_DisallowInternalPeriods;
+  }
+
+  /**
+   * Set whether selected columns should be processed. If true the 
+   * selected columns won't be processed.
+   *
+   * @param invert the new invert setting
+   */
+  public void setDisallowInternalPeriods(boolean disallow) {
+
+    m_DisallowInternalPeriods = disallow;
+  }
+
+  /**
+   * Parses a given list of options controlling the behaviour of this object.
+   * Valid options are:<p>
+   *
+   * -K<br>
+   * Specifies whether keyphrase frequency statistic is used.<p>
+   *
+   * -M length<br>
+   * Sets the maximum phrase length (default: 3).<p>
+   *
+   * -L length<br>
+   * Sets the minimum phrase length (default: 1).<p>
+   *
+   * -D<br>
+   * Turns debugging mode on.<p>
+   *
+   * -I index<br>
+   * Sets the index of the attribute containing the documents (default: 0).<p>
+   *
+   * -J index<br>
+   * Sets the index of the attribute containing the keyphrases (default: 1).<p>
+   *
+   * -P<br>
+   * Disallow internal periods <p>
+   *
+   * -O number<br>
+   * The minimum number of times a phrase needs to occur (default: 2). <p>
+   *
+   * @param options the list of options as an array of strings
+   * @exception Exception if an option is not supported
+   */
+  public void setOptions(String[] options) throws Exception {
+
+    setKFused(Utils.getFlag('K', options));
+    setDebug(Utils.getFlag('D', options));
+    String docAttIndexString = Utils.getOption('I', options);
+    if (docAttIndexString.length() > 0) {
+      setDocumentAtt(Integer.parseInt(docAttIndexString) - 1);
+    } else {
+      setDocumentAtt(0);
+    }
+    String keyphraseAttIndexString = Utils.getOption('J', options);
+    if (keyphraseAttIndexString.length() > 0) {
+      setKeyphrasesAtt(Integer.parseInt(keyphraseAttIndexString) - 1);
+    } else {
+      setKeyphrasesAtt(1);
+    }
+    String maxPhraseLengthString = Utils.getOption('M', options);
+    if (maxPhraseLengthString.length() > 0) {
+      setMaxPhraseLength(Integer.parseInt(maxPhraseLengthString));
+    } else {
+      setMaxPhraseLength(3);
+    }
+    String minPhraseLengthString = Utils.getOption('M', options);
+    if (minPhraseLengthString.length() > 0) {
+      setMinPhraseLength(Integer.parseInt(minPhraseLengthString));
+    } else {
+      setMinPhraseLength(1);
+    }
+    String minNumOccurString = Utils.getOption('O', options);
+    if (minNumOccurString.length() > 0) {
+      setMinNumOccur(Integer.parseInt(minNumOccurString));
+    } else {
+      setMinNumOccur(2);
+    }
+    setDisallowInternalPeriods(Utils.getFlag('P', options));
+   }
+
+  /**
+   * Gets the current settings of the filter.
+   *
+   * @return an array of strings suitable for passing to setOptions
+   */
+  public String [] getOptions() {
+
+    String [] options = new String [13];
+    int current = 0;
+
+    if (getKFused()) {
+      options[current++] = "-K";
+    }
+    if (getDebug()) {
+      options[current++] = "-D";
+    }
+    options[current++] = "-I"; 
+    options[current++] = "" + (getDocumentAtt() + 1);
+    options[current++] = "-J"; 
+    options[current++] = "" + (getKeyphrasesAtt() + 1);
+    options[current++] = "-M"; 
+    options[current++] = "" + (getMaxPhraseLength());
+    options[current++] = "-L"; 
+    options[current++] = "" + (getMinPhraseLength());
+    options[current++] = "-O"; 
+    options[current++] = "" + (getMinNumOccur());
+
+    if (getDisallowInternalPeriods()) {
+      options[current++] = "-P";
+    }
+
+    while (current < options.length) {
+      options[current++] = "";
+    }
+    return options;
+  }
+
+  /**
+   * Returns an enumeration describing the available options
+   *
+   * @return an enumeration of all the available options
+   */
+  public Enumeration listOptions() {
+
+    Vector newVector = new Vector(7);
+
+    newVector.addElement(new Option(
+	      "\tSpecifies whether keyphrase frequency statistic is used.",
+              "K", 0, "-K"));
+    newVector.addElement(new Option(
+	      "\tSets the maximum phrase length (default: 3).",
+              "M", 1, "-M <length>"));
+    newVector.addElement(new Option(
+	      "\tSets the minimum phrase length (default: 1).",
+              "L", 1, "-L <length>"));
+    newVector.addElement(new Option(
+	      "\tTurns debugging mode on.",
+              "D", 0, "-D"));
+    newVector.addElement(new Option(
+	      "\tSets the index of the document attribute (default: 0).",
+              "I", 1, "-I"));
+    newVector.addElement(new Option(
+	      "\tSets the index of the keyphrase attribute (default: 1).",
+              "J", 1, "-J"));
+    newVector.addElement(new Option(
+	      "\tDisallow internal periods.",
+              "P", 0, "-P"));
+    newVector.addElement(new Option(
+	      "\tSet the minimum number of occurences (default: 2).",
+              "O", 1, "-O"));
+
+    return newVector.elements();
+  }
+
+  /**
+   * Returns a string describing this filter
+   *
+   * @return a description of the filter suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String globalInfo() {
+    return "Converts incoming data into data appropriate for " +
+      "keyphrase classification.";
+  }
+
+  /**
+   * Sets the format of the input instances.
+   *
+   * @param instanceInfo an Instances object containing the input
+   * instance structure (any instances contained in the object are
+   * ignored - only the structure is required).
+   * @return true if the outputFormat may be collected immediately 
+   */
+  public boolean setInputFormat(Instances instanceInfo) throws Exception {
+
+    if (instanceInfo.classIndex() >= 0) {
+      throw new Exception("Don't know what do to if class index set!");
+    }
+    if (!instanceInfo.attribute(m_KeyphrasesAtt).isString() ||
+	!instanceInfo.attribute(m_DocumentAtt).isString()) {
+      throw new Exception("Keyphrase attribute and document attribute " +
+			  "need to be string attributes.");
+    }
+    m_PunctFilter = new KEAPhraseFilter();
+    int[] arr = new int[1];
+    arr[0] = m_DocumentAtt;
+    m_PunctFilter.setAttributeIndicesArray(arr);
+    m_PunctFilter.setInputFormat(instanceInfo);
+    m_PunctFilter.setDisallowInternalPeriods(getDisallowInternalPeriods());
+    m_NumbersFilter = new NumbersFilter();
+    m_NumbersFilter.setInputFormat(m_PunctFilter.getOutputFormat());
+    super.setInputFormat(m_NumbersFilter.getOutputFormat());
+    return false;
+  }
+
+  /**
+   * Input an instance for filtering. Ordinarily the instance is processed
+   * and made available for output immediately. Some filters require all
+   * instances be read before producing output.
+   *
+   * @param instance the input instance
+   * @return true if the filtered instance may now be
+   * collected with output().
+   * @exception Exception if the input instance was not of the correct 
+   * format or if there was a problem with the filtering.
+   */
+  public boolean input(Instance instance) throws Exception {
+
+    if (getInputFormat() == null) {
+      throw new Exception("No input instance format defined");
+    }
+    if (m_NewBatch) {
+      resetQueue();
+      m_NewBatch = false;
+    }
+
+    if (m_Debug) {
+      System.err.println("-- Reading instance");
+    }
+
+    m_PunctFilter.input(instance);
+    m_PunctFilter.batchFinished();
+    instance = m_PunctFilter.output();
+
+    m_NumbersFilter.input(instance);
+    m_NumbersFilter.batchFinished();
+    instance = m_NumbersFilter.output();
+    
+    if (m_Dictionary == null) {
+      bufferInput(instance);
+      return false;
+    } else {
+      FastVector vector = convertInstance(instance, false);
+      Enumeration enum = vector.elements();
+      while (enum.hasMoreElements()) {
+	Instance inst = (Instance)enum.nextElement();
+	push(inst);
+      }
+      return true;
+    }
+  }
+
+  /**
+   * Signify that this batch of input to the filter is finished. 
+   * If the filter requires all instances prior to filtering,
+   * output() may now be called to retrieve the filtered instances.
+   *
+   * @return true if there are instances pending output
+   * @exception Exception if no input structure has been defined
+   */
+  public boolean batchFinished() throws Exception {
+
+    if (getInputFormat() == null) {
+      throw new Exception("No input instance format defined");
+    }
+    if (m_Dictionary == null) {
+      buildGlobalDictionaries();
+      buildClassifier();
+      convertPendingInstances();
+    } 
+    flushInput();
+    m_NewBatch = true;
+    return (numPendingOutput() != 0);
+  }
+
+  /**
+   * Builds the global dictionaries.
+   */
+  private void buildGlobalDictionaries() throws Exception {
+
+    if (m_Debug) {
+      System.err.println("--- Building global dictionaries");
+    }
+    
+    // Build dictionary of n-grams with associated
+    // document frequencies
+    m_Dictionary = new HashMap();
+    for (int i = 0; i < getInputFormat().numInstances(); i++) {
+      String str = getInputFormat().instance(i).stringValue(m_DocumentAtt);
+      HashMap hash = getPhrasesForDictionary(str);
+      Iterator it = hash.keySet().iterator();
+      while (it.hasNext()) {
+	String phrase = (String)it.next();
+	Counter counter = (Counter)m_Dictionary.get(phrase);
+	if (counter == null) {
+	  m_Dictionary.put(phrase, new Counter());
+	} else {
+	  counter.increment();
+	}
+      }
+    }
+    
+    if (m_KFused) {
+      
+      // Build dictionary of n-grams that occur as keyphrases
+      // with associated keyphrase frequencies
+      m_KeyphraseDictionary = new HashMap();
+      for (int i = 0; i < getInputFormat().numInstances(); i++) {
+	String str = getInputFormat().instance(i).stringValue(m_KeyphrasesAtt);
+	HashMap hash = getGivenKeyphrases(str, false);
+	if (hash != null) {
+	  Iterator it = hash.keySet().iterator();
+	  while (it.hasNext()) {
+	    String phrase = (String)it.next();
+	    Counter counter = (Counter)m_KeyphraseDictionary.get(phrase);
+	    if (counter == null) {
+	      m_KeyphraseDictionary.put(phrase, new Counter());
+	    } else {
+	      counter.increment();
+	    }
+	  }
+	}
+      }
+    } else {
+      m_KeyphraseDictionary = null;
+    }
+    
+    // Set the number of documents in the global corpus
+    m_NumDocs = getInputFormat().numInstances();
+  }
+ 
+  /**
+   * Builds the classifier.
+   */
+  private void buildClassifier() throws Exception {
+    
+    // Generate input format for classifier
+    FastVector atts = new FastVector();
+    for (int i = 0; i < getInputFormat().numAttributes(); i++) {
+      if (i == m_DocumentAtt) {
+	atts.addElement(new Attribute("TFxIDF"));
+	atts.addElement(new Attribute("First_occurrence"));
+	if (m_KFused) {
+	  atts.addElement(new Attribute("Keyphrase_frequency"));
+	}
+      } else if (i == m_KeyphrasesAtt) {
+	FastVector vals = new FastVector(2);
+	vals.addElement("False");
+	vals.addElement("True");
+	atts.addElement(new Attribute("Keyphrase?", vals));
+      } 
+    }
+    m_ClassifierData = new Instances("ClassifierData", atts, 0);
+    m_ClassifierData.setClassIndex(m_NumFeatures);
+    
+    if (m_Debug) {
+      System.err.println("--- Converting instances for classifier");
+    }
+    
+    // Convert pending input instances into data for classifier
+    for(int i = 0; i < getInputFormat().numInstances(); i++) {
+      Instance current = getInputFormat().instance(i);
+
+      // Get the key phrases for the document
+      String keyphrases = current.stringValue(m_KeyphrasesAtt);
+      HashMap hashKeyphrases = getGivenKeyphrases(keyphrases, false);
+      HashMap hashKeysEval = getGivenKeyphrases(keyphrases, true);
+
+      // Get the phrases for the document
+      HashMap hash = new HashMap();
+      int length = getPhrases(hash, current.stringValue(m_DocumentAtt));
+
+      // Compute the feature values for each phrase and
+      // add the instance to the data for the classifier
+      Iterator it = hash.keySet().iterator();
+      while (it.hasNext()) {
+	String phrase = (String)it.next();
+	FastVector phraseInfo = (FastVector)hash.get(phrase);
+	double[] vals =  featVals(phrase, phraseInfo, true,
+				  hashKeysEval, hashKeyphrases, length);
+	Instance inst = new Instance(current.weight(), vals);
+	m_ClassifierData.add(inst);
+      }
+    }
+    
+    if (m_Debug) {
+      System.err.println("--- Building classifier");
+    }
+    
+    // Build classifier
+    FilteredClassifier fclass = new FilteredClassifier();
+    fclass.setClassifier(new weka.classifiers.NaiveBayesSimple());
+    fclass.setFilter(new DiscretizeFilter());
+    m_Classifier = fclass;
+    m_Classifier.buildClassifier(m_ClassifierData);
+
+    if (m_Debug) {
+      System.err.println(m_Classifier);
+    }
+
+    // Save space
+    m_ClassifierData = new Instances(m_ClassifierData, 0);
+  }
+
+  /** 
+   * Conmputes the feature values for a given phrase.
+   */
+  private double[] featVals(String phrase, FastVector phraseInfo, 
+			    boolean training, HashMap hashKeysEval,
+			    HashMap hashKeyphrases, int length) {
+
+    // Compute feature values
+    Counter counterLocal = (Counter)phraseInfo.elementAt(1);
+    double[] newInst = new double[m_NumFeatures + 1];
+	  
+    // Compute TFxIDF
+    Counter counterGlobal = (Counter)m_Dictionary.get(phrase);
+    double localVal = counterLocal.value(), globalVal = 0;
+    if (counterGlobal != null) {
+      globalVal = counterGlobal.value();
+      if (training) {
+	globalVal = globalVal - 1;
+      }
+    }
+    
+    // Just devide by length to get approximation of probability
+    // that phrase in document is our phrase
+    newInst[m_TfidfIndex] = (localVal / ((double)length)) *
+      (-Math.log((globalVal + 1)/ ((double)m_NumDocs + 1)));
+	  
+    // Compute first occurrence
+    Counter counterFirst = (Counter)phraseInfo.elementAt(0);
+    newInst[m_FirstOccurIndex] = (double)counterFirst.value() /
+      (double)length;
+    
+    // Is keyphrase frequency attribute being used?
+    if (m_KFused) {
+      Counter keyphraseC = (Counter)m_KeyphraseDictionary.get(phrase);
+      if ((training) && (hashKeyphrases != null) &&
+	  (hashKeyphrases.containsKey(phrase))) {
+	newInst[m_KeyFreqIndex] = keyphraseC.value() - 1;
+      } else {
+	if (keyphraseC != null) {
+	  newInst[m_KeyFreqIndex] = keyphraseC.value();
+	} else {
+	  newInst[m_KeyFreqIndex] = 0;
+	}
+      }
+    }
+
+    // Compute class value
+    String phraseInEvalFormat = evalFormat((String)phraseInfo.elementAt(2));
+    if (hashKeysEval == null) { // no author-assigned keyphrases
+      newInst[m_NumFeatures] = Instance.missingValue();
+    } else if (!hashKeysEval.containsKey(phraseInEvalFormat)) {
+      newInst[m_NumFeatures] = 0; // No keyphrase
+    } else {
+      hashKeysEval.remove(phraseInEvalFormat);
+      newInst[m_NumFeatures] = 1; // Keyphrase
+    }
+    return newInst;
+  }
+
+  /**
+   * Sets output format and converts pending input instances.
+   */
+  private void convertPendingInstances() throws Exception {
+
+    if (m_Debug) {
+      System.err.println("--- Converting pending instances");
+    }
+    
+    // Create output format for filter
+    FastVector atts = new FastVector();
+    for (int i = 0; i < getInputFormat().numAttributes(); i++) {
+      if (i == m_DocumentAtt) {
+	atts.addElement(new Attribute("N-gram", null));
+	atts.addElement(new Attribute("N-gram-original", null));
+	atts.addElement(new Attribute("TFxIDF"));
+	atts.addElement(new Attribute("First_occurrence"));
+	if (m_Debug) {
+	  if (m_KFused) {
+	    atts.addElement(new Attribute("Keyphrase_frequency"));
+	  }
+	}
+	atts.addElement(new Attribute("Probability"));
+	atts.addElement(new Attribute("Rank"));
+      } else if (i == m_KeyphrasesAtt) {
+	FastVector vals = new FastVector(2);
+	vals.addElement("False");
+	vals.addElement("True");
+	atts.addElement(new Attribute("Keyphrase?", vals));
+      } else {
+	atts.addElement(getInputFormat().attribute(i));
+      }
+    }
+    Instances outFormat = new Instances("KEAdata", atts, 0);
+    setOutputFormat(outFormat);
+    
+    // Convert pending input instances into output data
+    for(int i = 0; i < getInputFormat().numInstances(); i++) {
+      Instance current = getInputFormat().instance(i);
+      FastVector vector = convertInstance(current, true);
+      Enumeration enum = vector.elements();
+      while (enum.hasMoreElements()) {
+	Instance inst = (Instance)enum.nextElement();
+	push(inst);
+      }
+    }
+  } 
+
+  /**
+   * Converts an instance.
+   */
+  private FastVector convertInstance(Instance instance, boolean training) 
+    throws Exception {
+
+    FastVector vector = new FastVector();
+
+    if (m_Debug) {
+      System.err.println("-- Converting instance");
+    }
+
+    // Get the key phrases for the document
+    HashMap hashKeyphrases = null;
+    HashMap hashKeysEval = null;
+    if (!instance.isMissing(m_KeyphrasesAtt)) {
+      String keyphrases = instance.stringValue(m_KeyphrasesAtt);
+      hashKeyphrases = getGivenKeyphrases(keyphrases, false);
+      hashKeysEval = getGivenKeyphrases(keyphrases, true);
+    }
+
+    // Get the phrases for the document
+    HashMap hash = new HashMap();
+    int length = getPhrases(hash, instance.stringValue(m_DocumentAtt));
+
+    // Compute number of extra attributes
+    int numFeatures = 5;
+    if (m_Debug) {
+      if (m_KFused) {
+	numFeatures = numFeatures + 1;
+      }
+    } 
+
+    // Set indices of key attributes
+    int phraseAttIndex = m_DocumentAtt;
+    int tfidfAttIndex = m_DocumentAtt + 2;
+    int distAttIndex = m_DocumentAtt + 3;
+    int probsAttIndex = m_DocumentAtt + numFeatures - 1;
+
+    // Go through the phrases and convert them into instances
+    Iterator it = hash.keySet().iterator();
+    while (it.hasNext()) {
+      String phrase = (String)it.next();
+      FastVector phraseInfo = (FastVector)hash.get(phrase);
+      double[] vals =  featVals(phrase, phraseInfo, training,
+				hashKeysEval, hashKeyphrases, length);
+      Instance inst = new Instance(instance.weight(), vals);
+      inst.setDataset(m_ClassifierData);
+
+      // Get probability of phrase being key phrase
+      double[] probs = m_Classifier.distributionForInstance(inst);
+      double prob = probs[1];
+
+      // Compute attribute values for final instance
+      double[] newInst = 
+	new double[instance.numAttributes() + numFeatures];
+      int pos = 0;
+      for (int i = 0; i < instance.numAttributes(); i++) {
+	if (i == m_DocumentAtt) {
+	    
+	  // Add phrase
+	  int index = outputFormatPeek().attribute(pos).
+	    addStringValue(phrase);
+	  newInst[pos++] = index;
+	  
+	  // Add original version
+	  index = outputFormatPeek().attribute(pos).
+	    addStringValue((String)phraseInfo.elementAt(2));
+	  newInst[pos++] = index;
+
+	  // Add TFxIDF
+	  newInst[pos++] = inst.value(m_TfidfIndex);
+	    
+	  // Add distance
+	  newInst[pos++] = inst.value(m_FirstOccurIndex);
+
+	    // Add other features
+	  if (m_Debug) {
+	    if (m_KFused) {
+	      newInst[pos++] = inst.value(m_KeyFreqIndex);
+	    }
+	  }
+
+	  // Add probability 
+	  probsAttIndex = pos;
+	  newInst[pos++] = prob;
+
+	  // Set rank to missing (computed below)
+	  newInst[pos++] = Instance.missingValue();
+	} else if (i == m_KeyphrasesAtt) {
+	  newInst[pos++] = inst.classValue();
+	} else {
+	  newInst[pos++] = instance.value(i);
+	}
+      }
+      Instance ins = new Instance(instance.weight(), newInst);
+      ins.setDataset(outputFormatPeek());
+      vector.addElement(ins);
+    }
+
+    // Add dummy instances for keyphrases that don't occur
+    // in the document
+    if (hashKeysEval != null) {
+      Iterator phrases = hashKeysEval.keySet().iterator();
+      while (phrases.hasNext()) {
+	String phrase = (String)phrases.next();
+	double[] newInst = 
+	  new double[instance.numAttributes() + numFeatures];
+	int pos = 0;
+	for (int i = 0; i < instance.numAttributes(); i++) {
+	  if (i == m_DocumentAtt) {
+	    
+	    // Add phrase
+	    int index = outputFormatPeek().attribute(pos).
+	      addStringValue(phrase);
+	    newInst[pos++] = (double)index;
+	    
+	    // Add original version
+	    index = outputFormatPeek().attribute(pos).
+	      addStringValue((String)hashKeysEval.get(phrase));
+	    newInst[pos++] = (double)index;
+	    
+	    // Add TFxIDF
+	    newInst[pos++] = Instance.missingValue();
+	    
+	    // Add distance
+	    newInst[pos++] = Instance.missingValue();
+	      
+	    // Add other features
+	    if (m_Debug) {
+	      if (m_KFused) {
+		newInst[pos++] = Instance.missingValue();
+	      }
+	    }
+
+	    // Add probability and rank
+	    newInst[pos++] = -Double.MAX_VALUE;
+	    newInst[pos++] = Instance.missingValue();
+	  } else if (i == m_KeyphrasesAtt) {
+	    newInst[pos++] = 1; // Keyphrase
+	  } else {
+	    newInst[pos++] = instance.value(i);
+	  } 
+	}
+	Instance inst = new Instance(instance.weight(), newInst);
+	inst.setDataset(outputFormatPeek());
+	vector.addElement(inst);
+      }
+    }
+
+    // Sort phrases according to their distance (stable sort)
+    double[] vals = new double[vector.size()];
+    for (int i = 0; i < vals.length; i++) {
+      vals[i] = ((Instance)vector.elementAt(i)).value(distAttIndex);
+    }
+    FastVector newVector = new FastVector(vector.size());
+    int[] sortedIndices = Utils.stableSort(vals);
+    for (int i = 0; i < vals.length; i++) {
+      newVector.addElement(vector.elementAt(sortedIndices[i]));
+    }
+    vector = newVector;
+
+    // Sort phrases according to their tfxidf value (stable sort)
+    for (int i = 0; i < vals.length; i++) {
+      vals[i] = -((Instance)vector.elementAt(i)).value(tfidfAttIndex);
+    }
+    newVector = new FastVector(vector.size());
+    sortedIndices = Utils.stableSort(vals);
+    for (int i = 0; i < vals.length; i++) {
+      newVector.addElement(vector.elementAt(sortedIndices[i]));
+    }
+    vector = newVector;
+
+    // Sort phrases according to their probability (stable sort)
+    for (int i = 0; i < vals.length; i++) {
+      vals[i] = 1 - ((Instance)vector.elementAt(i)).value(probsAttIndex);
+    }
+    newVector = new FastVector(vector.size());
+    sortedIndices = Utils.stableSort(vals);
+    for (int i = 0; i < vals.length; i++) {
+      newVector.addElement(vector.elementAt(sortedIndices[i]));
+    }
+    vector = newVector;
+
+    // Compute rank of phrases. Check for subphrases that are ranked
+    // lower than superphrases and assign probability -1 and set the
+    // rank to Integer.MAX_VALUE
+    int rank = 1;
+    for (int i = 0; i < vals.length; i++) {
+      Instance currentInstance = (Instance)vector.elementAt(i);
+
+      // Short cut: if phrase very unlikely make rank very low and continue
+      if (Utils.grOrEq(vals[i], 1.0)) {
+	currentInstance.setValue(probsAttIndex + 1, Integer.MAX_VALUE);
+	continue;
+      }
+
+      // Otherwise look for super phrase starting with first phrase
+      // in list that has same probability, TFxIDF value, and distance as
+      // current phrase. We do this to catch all superphrases
+      // that have same probability, TFxIDF value and distance as current phrase.
+      int startInd = i;
+      while (startInd < vals.length) {
+	Instance inst = (Instance)vector.elementAt(startInd);
+	if ((inst.value(tfidfAttIndex) != 
+	     currentInstance.value(tfidfAttIndex)) ||
+	    (inst.value(probsAttIndex) != 
+	     currentInstance.value(probsAttIndex)) ||
+	    (inst.value(distAttIndex) !=
+	     currentInstance.value(distAttIndex))) {
+	  break;
+	}
+	startInd++;
+      }
+      String val = currentInstance.stringValue(phraseAttIndex);
+      boolean foundSuperphrase = false;
+      for (int j = startInd - 1; j >= 0; j--) {
+	if (j != i) {
+	  Instance candidate = (Instance)vector.elementAt(j);
+	  String potSuperphrase = candidate.stringValue(phraseAttIndex);
+	  if (val.length() <= potSuperphrase.length()) {
+	    if (KEAFilter.contains(val, potSuperphrase)) {
+	      foundSuperphrase = true;
+	      break;
+	    }
+	  }
+	}
+      }
+      if (foundSuperphrase) {
+	currentInstance.setValue(probsAttIndex + 1, Integer.MAX_VALUE);
+      } else {
+	currentInstance.setValue(probsAttIndex + 1, rank++);
+      }
+    }
+    return vector;
+  }
+    
+  /** 
+   * Checks whether one phrase is a subphrase of another phrase.
+   */
+  private static boolean contains(String sub, String sup) {
+
+    int i = 0;
+    while (i + sub.length() - 1 < sup.length()) {
+      int j;
+      for (j = 0; j < sub.length(); j++) {
+	if (sub.charAt(j) != sup.charAt(i + j)) {
+	  break;
+	}
+      }
+      if (j == sub.length()) {
+	if ((i + j) < sup.length()) {
+	  if (sup.charAt(i + j) == ' ') {
+	    return true;
+	  } else {
+	    return false;
+	  }
+	} else {
+	  return true;
+	}
+      }
+
+      // Skip forward to next space
+      do {
+	i++;
+      } while ((i < sup.length()) && (sup.charAt(i) != ' '));
+      i++;
+    }
+    return false;
+  }
+
+  /**
+   * Returns a hashtable. Fills the hashtable
+   * with the stemmed n-grams occuring in the given string
+   * (as keys) and the number of times it occurs.
+   */
+  private HashMap getPhrasesForDictionary(String str) {
+
+    String[] buffer = new String[m_MaxPhraseLength];
+    HashMap hash = new HashMap();
+
+    StringTokenizer tok = new StringTokenizer(str, "\n");
+    while (tok.hasMoreTokens()) {
+      String phrase = tok.nextToken();
+      int numSeen = 0;
+      StringTokenizer wordTok = new StringTokenizer(phrase, " ");
+      while (wordTok.hasMoreTokens()) {
+	String word = wordTok.nextToken();
+	
+	// Store word in buffer
+	for (int i = 0; i < m_MaxPhraseLength - 1; i++) {
+	  buffer[i] = buffer[i + 1];
+	}
+	buffer[m_MaxPhraseLength - 1] = word;
+	
+	// How many are buffered?
+	numSeen++;
+	if (numSeen > m_MaxPhraseLength) {
+	  numSeen = m_MaxPhraseLength;
+	}
+	
+	// Don't consider phrases that end with a stop word
+	if (m_Stopwords.isStopword(buffer[m_MaxPhraseLength - 1])) {
+	  continue;
+	}
+	
+	// Loop through buffer and add phrases to hashtable
+	StringBuffer phraseBuffer = new StringBuffer();
+	for (int i = 1; i <= numSeen; i++) {
+	  if (i > 1) {
+	    phraseBuffer.insert(0, ' ');
+	  }
+	  phraseBuffer.insert(0, buffer[m_MaxPhraseLength - i]);
+	  
+	  // Don't consider phrases that begin with a stop word
+	  if ((i > 1) && 
+	      (m_Stopwords.isStopword(buffer[m_MaxPhraseLength - i]))) {
+	    continue;
+	  }
+	  
+	  // Only consider phrases with minimum length
+	  if (i >= m_MinPhraseLength) {
+	    
+	    // Stem string
+	    String orig = phraseBuffer.toString();
+	    String internal = internalFormat(orig);
+	    Counter count = (Counter)hash.get(internal);
+	    if (count == null) {
+	      hash.put(internal, new Counter());
+	    } else {
+	      count.increment();
+	    }
+	    
+	    // Add components if phrase is single word before
+	    // conversion into internal format (i.e. error-correcting)
+	    /*if ((orig.indexOf(' ') == -1) &&
+	      (internal.indexOf(' ') != -1)) {
+	      StringTokenizer tokW = new StringTokenizer(internal, " ");
+	      while (tokW.hasMoreTokens()) {
+	      String comp = (String)tokW.nextToken();
+	      Counter countW = (Counter)hash.get(comp);
+	      if (countW == null) {
+	      hash.put(comp, new Counter());
+	      } else {
+	      countW.increment();
+	      }
+	      }
+	      }*/
+	  }
+	}
+      }
+    }
+    return hash;
+  }
+
+  /**
+   * Expects an empty hashtable. Fills the hashtable
+   * with the stemmed n-grams occuring in the given string
+   * (as keys). Stores the position, the number of occurences,
+   * and the most commonly occurring orgininal version of
+   * each n-gram.
+   *
+   * N-grams that occur less than m_MinNumOccur are not used.
+   *
+   * Returns the total number of words (!) in the string.
+   */
+  private int getPhrases(HashMap hash, String str) {
+
+    String[] buffer = new String[m_MaxPhraseLength];
+    
+    StringTokenizer tok = new StringTokenizer(str, "\n");
+    int pos = 1; 
+    while (tok.hasMoreTokens()) {
+      String phrase = tok.nextToken();
+      int numSeen = 0;
+      StringTokenizer wordTok = new StringTokenizer(phrase, " ");
+      while (wordTok.hasMoreTokens()) {
+	String word = wordTok.nextToken();
+	
+	// Store word in buffer
+	for (int i = 0; i < m_MaxPhraseLength - 1; i++) {
+	  buffer[i] = buffer[i + 1];
+	}
+	buffer[m_MaxPhraseLength - 1] = word;
+	
+	// How many are buffered?
+	numSeen++;
+	if (numSeen > m_MaxPhraseLength) {
+	  numSeen = m_MaxPhraseLength;
+	}
+	
+	// Don't consider phrases that end with a stop word
+	if (m_Stopwords.isStopword(buffer[m_MaxPhraseLength - 1])) {
+	  pos++;
+	  continue;
+	}
+	
+	// Loop through buffer and add phrases to hashtable
+	StringBuffer phraseBuffer = new StringBuffer();
+	for (int i = 1; i <= numSeen; i++) {
+	  if (i > 1) {
+	    phraseBuffer.insert(0, ' ');
+	  }
+	  phraseBuffer.insert(0, buffer[m_MaxPhraseLength - i]);
+	  
+	  // Don't consider phrases that begin with a stop word
+	  if ((i > 1) && 
+	      (m_Stopwords.isStopword(buffer[m_MaxPhraseLength - i]))) {
+	    continue;
+	  }
+	  
+	  // Only consider phrases with minimum length
+	  if (i >= m_MinPhraseLength) {
+	    
+	    // Stem string
+	    String phrStr = phraseBuffer.toString();
+	    String internal = internalFormat(phrStr);
+	    FastVector vec = (FastVector)hash.get(internal);
+	    if (vec == null) {
+	      vec = new FastVector(3);
+	      
+	      // HashMap for storing all versions
+	      HashMap secHash = new HashMap();
+	      secHash.put(phrStr, new Counter());
+	      
+	      // Update hashtable with all the info
+	      vec.addElement(new Counter(pos + 1 - i));
+	      vec.addElement(new Counter());
+	      vec.addElement(secHash);
+	      hash.put(internal, vec);
+	    } else {
+	      
+	      // Update number of occurrences
+	      ((Counter)((FastVector)vec).elementAt(1)).increment();
+	      
+	      // Update hashtable storing different versions
+	      HashMap secHash = (HashMap)vec.elementAt(2);
+	      Counter count = (Counter)secHash.get(phrStr);
+	      if (count == null) {
+		secHash.put(phrStr, new Counter());
+	      } else {
+		count.increment();
+	      }
+	    }
+	  }
+	}
+	pos++;
+      }
+    }
+    
+    // Replace secondary hashtables with most commonly occurring
+    // version of each phrase (canonical) form. Delete all words
+    // that are proper nouns.
+    Iterator phrases = hash.keySet().iterator();
+    while (phrases.hasNext()) {
+      String phrase = (String)phrases.next();
+      FastVector info = (FastVector)hash.get(phrase);
+
+      // Occurring less than m_MinNumOccur?
+      if (((Counter)((FastVector)info).elementAt(1)).value() < m_MinNumOccur) {
+	phrases.remove();
+	continue;
+      }
+
+      // Get canonical form
+      String canForm = canonicalForm((HashMap)info.elementAt(2));
+      if (canForm == null) {
+	phrases.remove();
+      } else {
+	info.setElementAt(canForm, 2);
+      }
+    }
+    return pos;
+  }
+
+  /**
+   * Create canonical form of phrase.
+   */
+  private String canonicalForm(HashMap secHash) {
+
+    int max = 0; String bestVersion = null;
+    boolean allFullyHyphenated = true;
+    int num = 0;
+    Iterator versions = secHash.keySet().iterator();
+    while (versions.hasNext()) {
+      num++;
+      String version = (String)versions.next();
+
+      // Are all the words joined up?
+      if (!isFullyHyphenated(version)) {
+	allFullyHyphenated = false;
+      }
+
+      // Check for how often this version occurs
+      Counter count = (Counter)secHash.get(version);
+      if (count.value() > max) {
+	max = count.value();
+	bestVersion = version;
+      }
+    }
+    if ((getCheckForProperNouns()) && (num == 1) && properNoun(bestVersion)) {
+    //if (allProperNouns) {
+      return null;
+    } else {
+      if (isFullyHyphenated(bestVersion) &&
+	  !allFullyHyphenated) {
+	bestVersion = bestVersion.replace('-', ' ');
+      }
+      return bestVersion;
+    }
+  }
+
+  /**
+   * Checks whether the given phrase is
+   * fully hyphenated.
+   */
+  private boolean isFullyHyphenated(String str) {
+    
+    return (str.indexOf(' ') == -1);
+  }
+
+  /**
+   * Checks whether the given string is a 
+   * proper noun.
+   *
+   * @return true if it is a potential proper noun
+   */
+  private static boolean properNoun(String str) {
+
+    // Is it more than one word?
+    if (str.indexOf(' ') != -1) {
+      return false;
+    }
+
+    // Does it start with an upper-case character?
+    if (Character.isLowerCase(str.charAt(0))) {
+      return false;
+    } 
+
+    // Is there at least one character that's
+    // not upper-case?
+    for (int i = 1; i < str.length(); i++) {
+      /*if (Character.isUpperCase(str.charAt(i))) {
+	return false;
+	}*/
+      if (!Character.isUpperCase(str.charAt(i))) {
+	return true;
+      }
+    }
+    //return true;
+    return false;
+  }
+
+  /**
+   * Generates the evaluation format of a phrase.
+   */
+  private String evalFormat(String str) {
+    
+    return m_Stemmer.stemString(str);
+  }
+
+  /** 
+   * Generates the internal format of a phrase.
+   */
+  private String internalFormat(String str) {
+
+    // Remove some non-alphanumeric characters
+    str = str.replace('-', ' ');
+    str = str.replace('/', ' ');
+    str = str.replace('&', ' ');
+
+    // Stem string
+    return m_Stemmer.stemString(str);
+  }
+
+  /**
+   * Gets all the phrases in the given string and puts them into the
+   * hashtable.  Also stores the original version of the stemmed
+   * phrase in the hash table.  
+   */
+  private HashMap getGivenKeyphrases(String str,
+				       boolean forEval) {
+
+    FastVector vector = new FastVector();
+    HashMap hash = new HashMap();
+    
+    StringTokenizer tok = new StringTokenizer(str, "\n");
+    while (tok.hasMoreTokens()) {
+      String orig = tok.nextToken();
+      orig = orig.trim();
+      if (orig.length() > 0) {
+	String modified;
+	if (!forEval) {
+	  modified = internalFormat(orig);
+	} else {
+	  modified = evalFormat(orig);
+	}
+	if (!hash.containsKey(modified)) {
+	  hash.put(modified, orig);
+	} else {
+	  if (forEval) {
+	    System.err.println("WARNING: stem of author-assigned keyphrase " +
+			       orig + " matches existing stem (skipping it)!");
+	  }
+	}
+      }
+    }
+    if (hash.size() == 0) {
+      return null;
+    } else {
+      return hash;
+    }
+  }
+
+  /**
+   * Main method for testing this class.
+   *
+   * @param argv should contain arguments to the filter: use -h for help
+   */
+  public static void main(String [] argv) {
+    
+    try {
+      if (Utils.getFlag('b', argv)) {
+	Filter.batchFilterFile(new KEAFilter(), argv);
+      } else {
+	Filter.filterFile(new KEAFilter(), argv);
+      }
+    } catch (Exception ex) {
+      System.out.println(ex.getMessage());
+    }
+  }
+}
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAKeyphraseExtractor.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAKeyphraseExtractor.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAKeyphraseExtractor.java	(revision 10506)
@@ -0,0 +1,532 @@
+/*
+ *    KEAKeyphraseExtractor.java
+ *    Copyright (C) 2001 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+import java.io.*;
+import java.util.*;
+import weka.core.*;
+import weka.filters.*;
+
+/**
+ * Extracts keyphrases from the documents in a given directory.
+ * Assumes that the file names for the documents end with ".txt".
+ * Puts extracted keyphrases into corresponding files ending with
+ * ".key" (if those are not already present). Optionally an encoding
+ * for the documents/keyphrases can be defined (e.g. for Chinese
+ * text). Documents for which ".key" exists, are used for evaluation.
+ *
+ * Valid options are:<p>
+ *
+ * -l "directory name"<br>
+ * Specifies name of directory.<p>
+ *
+ * -m "model name"<br>
+ * Specifies name of model.<p>
+ *
+ * -e "encoding"<br>
+ * Specifies encoding.<p>
+ *
+ * -n <br>
+ * Specifies number of phrases to be output (default: 5).<p>
+ *
+ * -d<br>
+ * Turns debugging mode on.<p>
+ *
+ * -a<br>
+ * Also write stemmed phrase and score into ".key" file.<p>
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public class KEAKeyphraseExtractor implements OptionHandler {
+  
+  /** Name of directory */
+  String m_dirName = null;
+  
+  /** Name of model */
+  String m_modelName = null;
+
+  /** Encoding */
+  String m_encoding = "default";
+
+  /** Debugging mode? */
+  boolean m_debug = false;
+
+  /** The KEA filter object */
+  KEAFilter m_KEAFilter = null;
+  
+  /** The number of phrases to extract. */
+  int m_numPhrases = 5;
+
+  /** Also write stemmed phrase and score into .key file. */
+  boolean m_AdditionalInfo = false;
+  
+  /**
+   * Get the value of AdditionalInfo.
+   *
+   * @return Value of AdditionalInfo.
+   */
+  public boolean getAdditionalInfo() {
+    
+    return m_AdditionalInfo;
+  }
+  
+  /**
+   * Set the value of AdditionalInfo.
+   *
+   * @param newAdditionalInfo Value to assign to AdditionalInfo.
+   */
+  public void setAdditionalInfo(boolean newAdditionalInfo) {
+    
+    m_AdditionalInfo = newAdditionalInfo;
+  }
+  
+  /**
+   * Get the value of numPhrases.
+   *
+   * @return Value of numPhrases.
+   */
+  public int getNumPhrases() {
+    
+    return m_numPhrases;
+  }
+  
+  /**
+   * Set the value of numPhrases.
+   *
+   * @param newnumPhrases Value to assign to numPhrases.
+   */
+  public void setNumPhrases(int newnumPhrases) {
+    
+    m_numPhrases = newnumPhrases;
+  }
+  
+  /**
+   * Get the value of debug.
+   *
+   * @return Value of debug.
+   */
+  public boolean getDebug() {
+    
+    return m_debug;
+  }
+  
+  /**
+   * Set the value of debug.
+   *
+   * @param newdebug Value to assign to debug.
+   */
+  public void setDebug(boolean newdebug) {
+    
+    m_debug = newdebug;
+  }
+  
+  /**
+   * Get the value of encoding.
+   *
+   * @return Value of encoding.
+   */
+  public String getEncoding() {
+    
+    return m_encoding;
+  }
+  
+  /**
+   * Set the value of encoding.
+   *
+   * @param newencoding Value to assign to encoding.
+   */
+  public void setEncoding(String newencoding) {
+    
+    m_encoding = newencoding;
+  }
+  
+  /**
+   * Get the value of modelName.
+   *
+   * @return Value of modelName.
+   */
+  public String getModelName() {
+    
+    return m_modelName;
+  }
+  
+  /**
+   * Set the value of modelName.
+   *
+   * @param newmodelName Value to assign to modelName.
+   */
+  public void setModelName(String newmodelName) {
+    
+    m_modelName = newmodelName;
+  }
+  
+  /**
+   * Get the value of dirName.
+   *
+   * @return Value of dirName.
+   */
+  public String getDirName() {
+    
+    return m_dirName;
+  }
+  
+  /**
+   * Set the value of dirName.
+   *
+   * @param newdirName Value to assign to dirName.
+   */
+  public void setDirName(String newdirName) {
+    
+    m_dirName = newdirName;
+  }
+  
+  /**
+   * Parses a given list of options controlling the behaviour of this object.
+   * Valid options are:<p>
+   *
+   * -l "directory name"<br>
+   * Specifies name of directory.<p>
+   *
+   * -m "model name"<br>
+   * Specifies name of model.<p>
+   *
+   * -e "encoding"<br>
+   * Specifies encoding.<p>
+   *
+   * -n<br>
+   * Specifies number of phrases to be output (default: 5).<p>
+   *
+   * -d<br>
+   * Turns debugging mode on.<p>
+   *
+   * -a<br>
+   * Also write stemmed phrase and score into ".key" file.<p>
+   *
+   * @param options the list of options as an array of strings
+   * @exception Exception if an option is not supported
+   */
+  public void setOptions(String[] options) throws Exception {
+
+    String dirName = Utils.getOption('l', options);
+    if (dirName.length() > 0) {
+      setDirName(dirName);
+    } else {
+      setDirName(null);
+      throw new Exception("Name of directory required argument.");
+    }
+    String modelName = Utils.getOption('m', options);
+    if (modelName.length() > 0) {
+      setModelName(modelName);
+    } else {
+      setModelName(null);
+      throw new Exception("Name of model required argument.");
+    }
+    String encoding = Utils.getOption('e', options);
+    if (encoding.length() > 0) {
+      setEncoding(encoding);
+    } else {
+      setEncoding("default");
+    }
+    String numPhrases = Utils.getOption('n', options);
+    if (numPhrases.length() > 0) {
+      setNumPhrases(Integer.parseInt(numPhrases));
+    } else {
+      setNumPhrases(5);
+    }
+    setDebug(Utils.getFlag('d', options));
+    setAdditionalInfo(Utils.getFlag('a', options));
+    Utils.checkForRemainingOptions(options);
+   }
+
+  /**
+   * Gets the current option settings.
+   *
+   * @return an array of strings suitable for passing to setOptions
+   */
+  public String [] getOptions() {
+
+    String [] options = new String [10];
+    int current = 0;
+
+    options[current++] = "-l"; 
+    options[current++] = "" + (getDirName());
+    options[current++] = "-m"; 
+    options[current++] = "" + (getModelName());
+    options[current++] = "-e"; 
+    options[current++] = "" + (getEncoding());
+    options[current++] = "-n"; 
+    options[current++] = "" + (getNumPhrases());
+    if (getDebug()) {
+      options[current++] = "-d";
+    }
+    if (getAdditionalInfo()) {
+      options[current++] = "-a";
+    }
+
+    while (current < options.length) {
+      options[current++] = "";
+    }
+    return options;
+  }
+
+  /**
+   * Returns an enumeration describing the available options.
+   *
+   * @return an enumeration of all the available options
+   */
+  public Enumeration listOptions() {
+
+    Vector newVector = new Vector(6);
+
+    newVector.addElement(new Option(
+	      "\tSpecifies name of directory.",
+              "l", 1, "-l <directory name>"));
+    newVector.addElement(new Option(
+	      "\tSpecifies name of model.",
+              "m", 1, "-m <model name>"));
+    newVector.addElement(new Option(
+	      "\tSpecifies encoding.",
+              "e", 1, "-e <encoding>"));
+    newVector.addElement(new Option(
+	      "\tSpecifies number of phrases to be output (default: 5).",
+              "n", 1, "-n"));
+    newVector.addElement(new Option(
+	      "\tTurns debugging mode on.",
+              "d", 0, "-d"));
+    newVector.addElement(new Option(
+	      "\tAlso write stemmed phrase and score into \".key\" file.",
+              "a", 0, "-a"));
+
+    return newVector.elements();
+  }
+
+  /**
+   * Collects the stems of the file names.
+   */
+  public Hashtable collectStems() throws Exception {
+
+    Hashtable stems = new Hashtable();
+
+    try {
+      File dir = new File(m_dirName);
+      String[] files = dir.list();
+      for (int i = 0; i < files.length; i++) {
+	if (files[i].endsWith(".txt")) {
+	  String stem = files[i].substring(0, files[i].length() - 4);
+	  if (!stems.containsKey(stem)) {
+	    stems.put(stem, new Double(0));
+	  }
+	}
+      }
+    } catch (Exception e) {
+      throw new Exception("Problem opening directory " + m_dirName);
+    }
+    return stems;
+  }
+
+  /**
+   * Builds the model from the files
+   */
+  public void extractKeyphrases(Hashtable stems) throws Exception {
+    
+    Vector stats = new Vector();
+
+    // Check whether there is actually any data
+    if (stems.size() == 0) {
+      throw new Exception("Couldn't find any data!");
+    }
+
+    FastVector atts = new FastVector(2);
+    atts.addElement(new Attribute("doc", null));
+    atts.addElement(new Attribute("keyphrases", null));
+    Instances data = new Instances("keyphrase_training_data", atts, 0);
+
+    // Extract keyphrases
+    Enumeration elem = stems.keys();
+    while (elem.hasMoreElements()) {
+      String str = (String)elem.nextElement();
+      double[] newInst = new double[2];
+      try {
+	File txt = new File(m_dirName + "/" + str + ".txt");
+	InputStreamReader is;
+	if (!m_encoding.equals("default")) {
+	  is = new InputStreamReader(new FileInputStream(txt), m_encoding);
+	} else {
+	  is = new InputStreamReader(new FileInputStream(txt));
+	}
+	StringBuffer txtStr = new StringBuffer();
+	int c;
+	while ((c = is.read()) != -1) {
+	  txtStr.append((char)c);
+	}
+	newInst[0] = (double)data.attribute(0).addStringValue(txtStr.toString());
+      } catch (Exception e) {
+	if (m_debug) {
+	  System.err.println("Can't read document " + str + ".txt");
+	}
+	newInst[0] = Instance.missingValue();
+      }
+      try {
+	File key = new File(m_dirName + "/" + str + ".key");
+	InputStreamReader is; 
+	if (!m_encoding.equals("default")) {
+	  is = new InputStreamReader(new FileInputStream(key), m_encoding);
+	} else {
+	  is = new InputStreamReader(new FileInputStream(key));
+	}
+	StringBuffer keyStr = new StringBuffer();
+	int c;
+	while ((c = is.read()) != -1) {
+	  keyStr.append((char)c);
+	}      
+	newInst[1] = (double)data.attribute(1).addStringValue(keyStr.toString());
+      } catch (Exception e) {
+	if (m_debug) {
+	  System.err.println("No keyphrases for stem " + str + ".");
+	}
+	newInst[1] = Instance.missingValue();
+      }
+      data.add(new Instance(1.0, newInst));
+      m_KEAFilter.input(data.instance(0));
+      data = data.stringFreeStructure();
+      if (m_debug) {
+	System.err.println("-- Document: " + str);
+      }
+      Instance[] topRankedInstances = new Instance[m_numPhrases];
+      Instance inst;
+      while ((inst = m_KEAFilter.output()) != null) {
+	int index = (int)inst.value(m_KEAFilter.getRankIndex()) - 1;
+	if (index < m_numPhrases) {
+	  topRankedInstances[index] = inst;
+	}
+      }
+      if (m_debug) {
+	System.err.println("-- Keyphrases and feature values:");
+      }
+      FileOutputStream out = null;
+      PrintWriter printer = null; 
+      File key = new File(m_dirName + "/" + str + ".key");
+      if (!key.exists()) {
+	out = new FileOutputStream(m_dirName + "/" + str + ".key");
+	if (!m_encoding.equals("default")) {
+	  printer = new PrintWriter(new OutputStreamWriter(out, m_encoding));
+	} else {
+	  printer = new PrintWriter(out);
+	}
+      }
+      double numExtracted = 0, numCorrect = 0;
+      for (int i = 0; i < m_numPhrases; i++) {
+	if (topRankedInstances[i] != null) {
+	  if (!topRankedInstances[i].
+	      isMissing(topRankedInstances[i].numAttributes() - 1)) {
+	    numExtracted += 1.0;
+	  }
+	  if ((int)topRankedInstances[i].
+	      value(topRankedInstances[i].numAttributes() - 1) == 
+	      topRankedInstances[i].
+	      attribute(topRankedInstances[i].numAttributes() - 1).
+	      indexOfValue("True")) {
+	    numCorrect += 1.0;
+	  }
+	  if (printer != null) {
+	    printer.print(topRankedInstances[i].
+			  stringValue(m_KEAFilter.getUnstemmedPhraseIndex()));
+	    if (m_AdditionalInfo) {
+	      printer.print("\t");
+	      printer.print(topRankedInstances[i].
+			  stringValue(m_KEAFilter.getStemmedPhraseIndex()));
+	      printer.print("\t");
+	      printer.print(Utils.
+			    doubleToString(topRankedInstances[i].
+					   value(m_KEAFilter.
+						 getProbabilityIndex()), 4));
+	    }
+	    printer.println();
+	  }
+	  if (m_debug) {
+	    System.err.println(topRankedInstances[i]);
+	  }
+	}
+      }
+      if (numExtracted > 0) {
+	if (m_debug) {
+	  System.err.println("-- " + numCorrect + " correct");
+	}
+	stats.addElement(new Double(numCorrect));
+      }
+      if (printer != null) {
+	printer.flush();
+	printer.close();
+	out.close();
+      }
+    }
+    double[] st = new double[stats.size()];
+    for (int i = 0; i < stats.size(); i++) {
+      st[i] = ((Double)stats.elementAt(i)).doubleValue();
+    }
+    double avg = Utils.mean(st);
+    double stdDev = Math.sqrt(Utils.variance(st));
+    System.err.println("Avg. number of correct keyphrases: " +
+		       Utils.doubleToString(avg, 2) + " +/- " + 
+		       Utils.doubleToString(stdDev, 2));
+    System.err.println("Based on " + stats.size() + " documents");
+    m_KEAFilter.batchFinished();
+  }
+  
+  /** 
+   * Loads the extraction model from the file.
+   */
+  public void loadModel() throws Exception {
+    
+    BufferedInputStream inStream =
+      new BufferedInputStream(new FileInputStream(m_modelName));
+    ObjectInputStream in = new ObjectInputStream(inStream);
+    m_KEAFilter = (KEAFilter)in.readObject();
+    in.close();
+  }
+  
+  /**
+   * The main method.  
+   */
+  public static void main(String[] ops) {
+    
+    KEAKeyphraseExtractor kmb = new KEAKeyphraseExtractor();
+    try {
+      kmb.setOptions(ops);
+      System.err.print("Extracting keyphrases with options: ");
+      String[] optionSettings = kmb.getOptions();
+      for (int i = 0; i < optionSettings.length; i++) {
+	System.err.print(optionSettings[i] + " ");
+      }
+      System.err.println();
+      kmb.loadModel();
+      kmb.extractKeyphrases(kmb.collectStems());
+    } catch (Exception e) {
+      e.printStackTrace();
+      System.err.println(e.getMessage());
+      System.err.println("\nOptions:\n");
+      Enumeration enum = kmb.listOptions();
+      while (enum.hasMoreElements()) {
+	Option option = (Option) enum.nextElement();
+	System.err.println(option.synopsis());
+	System.err.println(option.description());
+      }
+    }
+  }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAModelBuilder.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAModelBuilder.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAModelBuilder.java	(revision 10506)
@@ -0,0 +1,689 @@
+/*
+ *    KEAModelBuilder.java
+ *    Copyright (C) 2001 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import java.io.*;
+import java.util.*;
+import weka.core.*;
+import weka.filters.*;
+
+/**
+ * Builds a keyphrase extraction model from the documents in a given
+ * directory.  Assumes that the file names for the documents end with
+ * ".txt".  Assumes that files containing corresponding
+ * author-assigned keyphrases end with ".key". Optionally an encoding
+ * for the documents/keyphrases can be defined (e.g. for Chinese
+ * text).
+ *
+ * Valid options are:<p>
+ *
+ * -l "directory name"<br>
+ * Specifies name of directory.<p>
+ *
+ * -m "model name"<br>
+ * Specifies name of model.<p>
+ *
+ * -e "encoding"<br>
+ * Specifies encoding.<p>
+ *
+ * -d<br>
+ * Turns debugging mode on.<p>
+ *
+ * -k<br>
+ * Use keyphrase frequency statistic.<p>
+ *
+ * -p<br>
+ * Disallow internal periods.<p>
+ *
+ * -x "length"<br>
+ * Sets maximum phrase length (default: 3).<p>
+ *
+ * -y "length"<br>
+ * Sets minimum phrase length (default: 1).<p>
+ *
+ * -o "number"<br>
+ * The minimum number of times a phrase needs to occur (default: 2). <p>
+ *
+ * -s "name of class implementing list of stop words"<br>
+ * Sets list of stop words to used (default: StopwordsEnglish).<p>
+ *
+ * -t "name of class implementing stemmer"<br>
+ * Sets stemmer to use (default: IteratedLovinsStemmer). <p>
+ *
+ * -n<br>
+ * Do not check for proper nouns. <p>
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public class KEAModelBuilder implements OptionHandler {
+  
+  /** Name of directory */
+  String m_dirName = null;
+  
+  /** Name of model */
+  String m_modelName = null;
+
+  /** Encoding */
+  String m_encoding = "default";
+
+  /** Debugging mode? */
+  boolean m_debug = false;
+
+  /** Use keyphrase frequency attribute? */
+  boolean m_useKFrequency = false;
+
+  /** Disallow internal periods? */
+  boolean m_disallowIPeriods = false;
+
+  /** The maximum length of phrases */
+  private int m_MaxPhraseLength = 3;
+
+  /** The minimum length of phrases */
+  private int m_MinPhraseLength = 1;
+
+  /** The minimum number of occurences of a phrase */
+  private int m_MinNumOccur = 2;
+
+  /** The KEA filter object */
+  KEAFilter m_KEAFilter = null;
+
+  /** The stemmer to be used */
+  private Stemmer m_Stemmer = new IteratedLovinsStemmer();
+
+  /** The list of stop words to be used */
+  private Stopwords m_Stopwords = new StopwordsEnglish();
+
+  /** Determines whether check for proper nouns is performed */
+  private boolean m_CheckForProperNouns = true;
+
+  /**
+   * Get the M_CheckProperNouns value.
+   * @return the M_CheckProperNouns value.
+   */
+  public boolean getCheckForProperNouns() {
+    return m_CheckForProperNouns;
+  }
+
+  /**
+   * Set the M_CheckProperNouns value.
+   * @param newM_CheckProperNouns The new M_CheckProperNouns value.
+   */
+  public void setCheckForProperNouns(boolean newM_CheckProperNouns) {
+    this.m_CheckForProperNouns = newM_CheckProperNouns;
+  }
+
+  /**
+   * Get the M_Stopwords value.
+   * @return the M_Stopwords value.
+   */
+  public Stopwords getStopwords() {
+
+    return m_Stopwords;
+  }
+
+  /**
+   * Set the M_Stopwords value.
+   * @param newM_Stopwords The new M_Stopwords value.
+   */
+  public void setStopwords(Stopwords newM_Stopwords) {
+
+    this.m_Stopwords = newM_Stopwords;
+  }
+
+  
+  /**
+   * Get the Stemmer value.
+   * @return the Stemmer value.
+   */
+  public Stemmer getStemmer() {
+
+    return m_Stemmer;
+  }
+
+  /**
+   * Set the Stemmer value.
+   * @param newStemmer The new Stemmer value.
+   */
+  public void setStemmer(Stemmer newStemmer) {
+
+    this.m_Stemmer = newStemmer;
+  }
+  
+  /**
+   * Get the value of MinNumOccur.
+   *
+   * @return Value of MinNumOccur.
+   */
+  public int getMinNumOccur() {
+    
+    return m_MinNumOccur;
+  }
+  
+  /**
+   * Set the value of MinNumOccur.
+   *
+   * @param newMinNumOccur Value to assign to MinNumOccur.
+   */
+  public void setMinNumOccur(int newMinNumOccur) {
+    
+    m_MinNumOccur = newMinNumOccur;
+  }
+  
+  /**
+   * Get the value of MaxPhraseLength.
+   *
+   * @return Value of MaxPhraseLength.
+   */
+  public int getMaxPhraseLength() {
+    
+    return m_MaxPhraseLength;
+  }
+  
+  /**
+   * Set the value of MaxPhraseLength.
+   *
+   * @param newMaxPhraseLength Value to assign to MaxPhraseLength.
+   */
+  public void setMaxPhraseLength(int newMaxPhraseLength) {
+    
+    m_MaxPhraseLength = newMaxPhraseLength;
+  }
+  
+  /**
+   * Get the value of MinPhraseLength.
+   *
+   * @return Value of MinPhraseLength.
+   */
+  public int getMinPhraseLength() {
+    
+    return m_MinPhraseLength;
+  }
+  
+  /**
+   * Set the value of MinPhraseLength.
+   *
+   * @param newMinPhraseLength Value to assign to MinPhraseLength.
+   */
+  public void setMinPhraseLength(int newMinPhraseLength) {
+    
+    m_MinPhraseLength = newMinPhraseLength;
+  }
+  
+  /**
+   * Get the value of disallowIPeriods.
+   *
+   * @return Value of disallowIPeriods.
+   */
+  public boolean getDisallowIPeriods() {
+    
+    return m_disallowIPeriods;
+  }
+  
+  /**
+   * Set the value of disallowIPeriods.
+   *
+   * @param newdisallowIPeriods Value to assign to disallowIPeriods.
+   */
+  public void setDisallowIPeriods(boolean newdisallowIPeriods) {
+    
+    m_disallowIPeriods = newdisallowIPeriods;
+  }
+  
+  /**
+   * Get the value of useKFrequency.
+   *
+   * @return Value of useKFrequency.
+   */
+  public boolean getUseKFrequency() {
+    
+    return m_useKFrequency;
+  }
+  
+  /**
+   * Set the value of useKFrequency.
+   *
+   * @param newuseKFrequency Value to assign to useKFrequency.
+   */
+  public void setUseKFrequency(boolean newuseKFrequency) {
+    
+    m_useKFrequency = newuseKFrequency;
+  }
+  
+  /**
+   * Get the value of debug.
+   *
+   * @return Value of debug.
+   */
+  public boolean getDebug() {
+    
+    return m_debug;
+  }
+  
+  /**
+   * Set the value of debug.
+   *
+   * @param newdebug Value to assign to debug.
+   */
+  public void setDebug(boolean newdebug) {
+    
+    m_debug = newdebug;
+  }
+  
+  /**
+   * Get the value of encoding.
+   *
+   * @return Value of encoding.
+   */
+  public String getEncoding() {
+    
+    return m_encoding;
+  }
+  
+  /**
+   * Set the value of encoding.
+   *
+   * @param newencoding Value to assign to encoding.
+   */
+  public void setEncoding(String newencoding) {
+    
+    m_encoding = newencoding;
+  }
+  
+  /**
+   * Get the value of modelName.
+   *
+   * @return Value of modelName.
+   */
+  public String getModelName() {
+    
+    return m_modelName;
+  }
+  
+  /**
+   * Set the value of modelName.
+   *
+   * @param newmodelName Value to assign to modelName.
+   */
+  public void setModelName(String newmodelName) {
+    
+    m_modelName = newmodelName;
+  }
+  
+  /**
+   * Get the value of dirName.
+   *
+   * @return Value of dirName.
+   */
+  public String getDirName() {
+    
+    return m_dirName;
+  }
+  
+  /**
+   * Set the value of dirName.
+   *
+   * @param newdirName Value to assign to dirName.
+   */
+  public void setDirName(String newdirName) {
+    
+    m_dirName = newdirName;
+  }
+  
+  /**
+   * Parses a given list of options controlling the behaviour of this object.
+   * Valid options are:<p>
+   *
+   * -l "directory name" <br>
+   * Specifies name of directory.<p>
+   *
+   * -m "model name" <br>
+   * Specifies name of model.<p>
+   *
+   * -e "encoding" <br>
+   * Specifies encoding.<p>
+   *
+   * -d<br>
+   * Turns debugging mode on.<p>
+   *
+   * -k<br>
+   * Use keyphrase frequency statistic.<p>
+   *
+   * -p<br>
+   * Disallow internal periods. <p>
+   *
+   * -x "length"<br>
+   * Sets maximum phrase length (default: 3).<p>
+   *
+   * -y "length"<br>
+   * Sets minimum phrase length (default: 3).<p>
+   *
+   * -o "number"<br>
+   * The minimum number of times a phrase needs to occur (default: 2). <p>
+   *
+   * -s "name of class implementing list of stop words"<br>
+   * Sets list of stop words to used (default: StopwordsEnglish).<p>
+   *
+   * -t "name of class implementing stemmer"<br>
+   * Sets stemmer to use (default: IteratedLovinsStemmer). <p>
+   *
+   * -n<br>
+   * Do not check for proper nouns. <p>
+   *
+   * @param options the list of options as an array of strings
+   * @exception Exception if an option is not supported
+   */
+  public void setOptions(String[] options) throws Exception {
+
+    String dirName = Utils.getOption('l', options);
+    if (dirName.length() > 0) {
+      setDirName(dirName);
+    } else {
+      setDirName(null);
+      throw new Exception("Name of directory required argument.");
+    }
+    String modelName = Utils.getOption('m', options);
+    if (modelName.length() > 0) {
+      setModelName(modelName);
+    } else {
+      setModelName(null);
+      throw new Exception("Name of model required argument.");
+    }
+    String encoding = Utils.getOption('e', options);
+    if (encoding.length() > 0) {
+      setEncoding(encoding);
+    } else {
+      setEncoding("default");
+    }
+    String maxPhraseLengthString = Utils.getOption('x', options);
+    if (maxPhraseLengthString.length() > 0) {
+      setMaxPhraseLength(Integer.parseInt(maxPhraseLengthString));
+    } else {
+      setMaxPhraseLength(3);
+    }
+    String minPhraseLengthString = Utils.getOption('y', options);
+    if (minPhraseLengthString.length() > 0) {
+      setMinPhraseLength(Integer.parseInt(minPhraseLengthString));
+    } else {
+      setMinPhraseLength(1);
+    }
+    String minNumOccurString = Utils.getOption('o', options);
+    if (minNumOccurString.length() > 0) {
+      setMinNumOccur(Integer.parseInt(minNumOccurString));
+    } else {
+      setMinNumOccur(2);
+    }
+    String stopwordsString = Utils.getOption('s', options);
+    if (stopwordsString.length() > 0) {
+      setStopwords((Stopwords)Class.forName(stopwordsString).newInstance());
+    }
+    String stemmerString = Utils.getOption('t', options);
+    if (stemmerString.length() > 0) {
+      setStemmer((Stemmer)Class.forName(stemmerString).newInstance());
+    }
+    setDebug(Utils.getFlag('d', options));
+    setUseKFrequency(Utils.getFlag('k', options));
+    setDisallowIPeriods(Utils.getFlag('p', options));
+    setCheckForProperNouns(!Utils.getFlag('n', options));
+    Utils.checkForRemainingOptions(options);
+   }
+
+  /**
+   * Gets the current option settings.
+   *
+   * @return an array of strings suitable for passing to setOptions
+   */
+  public String [] getOptions() {
+
+    String [] options = new String [20];
+    int current = 0;
+
+    options[current++] = "-l"; 
+    options[current++] = "" + (getDirName());
+    options[current++] = "-m"; 
+    options[current++] = "" + (getModelName());
+    options[current++] = "-e"; 
+    options[current++] = "" + (getEncoding());
+    if (getUseKFrequency()) {
+      options[current++] = "-k";
+    }
+    if (getDebug()) {
+      options[current++] = "-d";
+    }
+    if (getDisallowIPeriods()) {
+      options[current++] = "-p";
+    }
+    options[current++] = "-x"; 
+    options[current++] = "" + (getMaxPhraseLength());
+    options[current++] = "-y"; 
+    options[current++] = "" + (getMinPhraseLength());
+    options[current++] = "-o"; 
+    options[current++] = "" + (getMinNumOccur());
+    options[current++] = "-s"; 
+    options[current++] = "" + (getStopwords().getClass().getName());
+    options[current++] = "-t"; 
+    options[current++] = "" + (getStemmer().getClass().getName());
+    if (getCheckForProperNouns()) {
+      options[current++] = "-n";
+    }
+
+    while (current < options.length) {
+      options[current++] = "";
+    }
+    return options;
+  }
+
+  /**
+   * Returns an enumeration describing the available options.
+   *
+   * @return an enumeration of all the available options
+   */
+  public Enumeration listOptions() {
+
+    Vector newVector = new Vector(12);
+
+    newVector.addElement(new Option(
+	      "\tSpecifies name of directory.",
+              "l", 1, "-l <directory name>"));
+    newVector.addElement(new Option(
+	      "\tSpecifies name of model.",
+              "m", 1, "-m <model name>"));
+    newVector.addElement(new Option(
+	      "\tSpecifies encoding.",
+              "e", 1, "-e <encoding>"));
+    newVector.addElement(new Option(
+	      "\tTurns debugging mode on.",
+              "d", 0, "-d"));
+    newVector.addElement(new Option(
+	      "\tUse keyphrase frequency statistic.",
+              "k", 0, "-k"));
+    newVector.addElement(new Option(
+	      "\tDisallow internal periods.",
+              "p", 0, "-p"));
+    newVector.addElement(new Option(
+	      "\tSets the maximum phrase length (default: 3).",
+              "x", 1, "-x <length>"));
+    newVector.addElement(new Option(
+	      "\tSets the minimum phrase length (default: 1).",
+              "y", 1, "-y <length>"));
+    newVector.addElement(new Option(
+	      "\tSet the minimum number of occurences (default: 2).",
+              "o", 1, "-o"));
+    newVector.addElement(new Option(
+	      "\tSets the list of stopwords to use (default: StopwordsEnglish).",
+              "s", 1, "-s <name of stopwords class>"));
+    newVector.addElement(new Option(
+	      "\tSet the stemmer to use (default: IteratedLovinsStemmer).",
+              "t", 1, "-t <name of stemmer class>"));
+    newVector.addElement(new Option(
+	      "\tDo not check for proper nouns.",
+              "n", 0, "-n"));
+ 
+    return newVector.elements();
+  }
+
+  /**
+   * Collects the stems of the file names.
+   */
+  public Hashtable collectStems() throws Exception {
+
+    Hashtable stems = new Hashtable();
+
+    try {
+      File dir = new File(m_dirName);
+      String[] files = dir.list();
+      for (int i = 0; i < files.length; i++) {
+	if (files[i].endsWith(".key") ||
+	    files[i].endsWith(".txt")) {
+	  String stem = files[i].substring(0, files[i].length() - 4);
+	  if (!stems.containsKey(stem)) {
+	    stems.put(stem, new Double(0));
+	  }
+	}
+      }
+    } catch (Exception e) {
+      throw new Exception("Problem opening directory " + m_dirName);
+    }
+    return stems;
+  }
+
+  /**
+   * Builds the model from the files
+   */
+  public void buildModel(Hashtable stems) throws Exception {
+    
+    // Check whether there is actually any data
+    if (stems.size() == 0) {
+      throw new Exception("Couldn't find any data!");
+    }
+
+    FastVector atts = new FastVector(2);
+    atts.addElement(new Attribute("doc", null));
+    atts.addElement(new Attribute("keyphrases", null));
+    Instances data = new Instances("keyphrase_training_data", atts, 0);
+
+    // Build model
+    m_KEAFilter = new KEAFilter();
+    m_KEAFilter.setDebug(m_debug);
+    m_KEAFilter.setDisallowInternalPeriods(getDisallowIPeriods());
+    m_KEAFilter.setKFused(getUseKFrequency());
+    m_KEAFilter.setMaxPhraseLength(getMaxPhraseLength());
+    m_KEAFilter.setMinPhraseLength(getMinPhraseLength());
+    m_KEAFilter.setMinNumOccur(getMinNumOccur());
+    m_KEAFilter.setInputFormat(data);
+    m_KEAFilter.setStemmer(getStemmer());
+    m_KEAFilter.setStopwords(getStopwords());
+    m_KEAFilter.setCheckForProperNouns(getCheckForProperNouns());
+    Enumeration elem = stems.keys();
+    while (elem.hasMoreElements()) {
+      String str = (String)elem.nextElement();
+      double[] newInst = new double[2];
+      try {
+	File txt = new File(m_dirName + "/" + str + ".txt");
+	InputStreamReader is;
+	if (!m_encoding.equals("default")) {
+	  is = new InputStreamReader(new FileInputStream(txt), m_encoding);
+	} else {
+	  is = new InputStreamReader(new FileInputStream(txt));
+	}
+	StringBuffer txtStr = new StringBuffer();
+	int c;
+	while ((c = is.read()) != -1) {
+	  txtStr.append((char)c);
+	}
+	newInst[0] = (double)data.attribute(0).addStringValue(txtStr.toString());
+      } catch (Exception e) {
+	if (m_debug) {
+	  System.err.println("Can't find document for stem " + str + ".");
+	}
+	newInst[0] = Instance.missingValue();
+      }
+      try {
+	File key = new File(m_dirName + "/" + str + ".key");
+	InputStreamReader is; 
+	if (!m_encoding.equals("default")) {
+	  is = new InputStreamReader(new FileInputStream(key), m_encoding);
+	} else {
+	  is = new InputStreamReader(new FileInputStream(key));
+	}
+	StringBuffer keyStr = new StringBuffer();
+	int c;
+	while ((c = is.read()) != -1) {
+	  keyStr.append((char)c);
+	}      
+	newInst[1] = (double)data.attribute(1).addStringValue(keyStr.toString());
+      } catch (Exception e) {
+	if (m_debug) {
+	  System.err.println("Can't find keyphrases for stem " + str + ".");
+	}
+	newInst[1] = Instance.missingValue();
+      }
+      data.add(new Instance(1.0, newInst));
+      m_KEAFilter.input(data.instance(0));
+      data = data.stringFreeStructure();
+    }
+    m_KEAFilter.batchFinished();
+    
+    // Get rid of instances in filter
+    Instance dummy;
+    while ((dummy = m_KEAFilter.output()) != null) {};
+  }
+  
+  /** 
+   * Saves the extraction model to the file.
+   */
+  public void saveModel() throws Exception {
+    
+    BufferedOutputStream bufferedOut = 
+      new BufferedOutputStream(new FileOutputStream(m_modelName));
+    ObjectOutputStream out = new ObjectOutputStream(bufferedOut);
+    out.writeObject(m_KEAFilter);
+    out.flush();
+    out.close();
+  }
+  
+  /**
+   * The main method.  
+   */
+  public static void main(String[] ops) {
+    
+    KEAModelBuilder kmb = new KEAModelBuilder();
+    try {
+      kmb.setOptions(ops);
+      System.err.print("Building model with options: ");
+      String[] optionSettings = kmb.getOptions();
+      for (int i = 0; i < optionSettings.length; i++) {
+	System.err.print(optionSettings[i] + " ");
+      }
+      System.err.println();
+      kmb.buildModel(kmb.collectStems());
+      kmb.saveModel();
+    } catch (Exception e) {
+      e.printStackTrace();
+      System.err.println(e.getMessage());
+      System.err.println("\nOptions:\n");
+      Enumeration enum = kmb.listOptions();
+      while (enum.hasMoreElements()) {
+	Option option = (Option) enum.nextElement();
+	System.err.println(option.synopsis());
+	System.err.println(option.description());
+      }
+    }
+  }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAPhraseFilter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAPhraseFilter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/KEAPhraseFilter.java	(revision 10506)
@@ -0,0 +1,487 @@
+/*
+ *    KEAPhraseFilter.java
+ *    Copyright (C) 2001 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import java.util.*;
+
+import weka.core.*;
+import weka.filters.*;
+
+/**
+ * This filter splits the text in selected string
+ * attributes into phrases. The resulting
+ * string attributes contain these phrases
+ * separated by '\n' characters.
+ *
+ * Phrases are identified according to the
+ * following definitions:
+ * 
+ * A phrase is a sequence of words interrupted
+ * only by sequences of whitespace characters,
+ * where each sequence of whitespace characters
+ * contains at most one '\n'.
+ *
+ * A word is a sequence of letters or digits
+ * that contains at least one letter, with
+ * the following exceptions:
+ *
+ * a) '.', '@', '_', '&', '/', '-' are allowed
+ * if surrounded by letters or digits,
+ *
+ * b) '\'' is allowed if preceeded by a letter
+ * or digit,
+ * 
+ * c) '-', '/' are also allowed if succeeded by
+ * whitespace characters followed by another
+ * word. In that case the whitespace characters
+ * will be deleted.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public class KEAPhraseFilter extends Filter implements OptionHandler {
+
+  /** Stores which columns to select as a funky range */
+  protected Range m_SelectCols = new Range();
+
+  /** Determines whether internal periods are allowed */
+  protected boolean m_DisallowInternalPeriods = false;
+
+  /**
+   * Returns a string describing this filter
+   *
+   * @return a description of the filter suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String globalInfo() {
+    return "This filter splits the text contained " +
+      "by the selected string attributes into phrases.";
+  }
+
+  /**
+   * Returns an enumeration describing the available options
+   *
+   * @return an enumeration of all the available options
+   */
+  public Enumeration listOptions() {
+
+    Vector newVector = new Vector(3);
+
+    newVector.addElement(new Option(
+              "\tSpecify list of attributes to process. First and last are valid\n"
+	      +"\tindexes. (default none)",
+              "R", 1, "-R <index1,index2-index4,...>"));
+    newVector.addElement(new Option(
+	      "\tInvert matching sense",
+              "V", 0, "-V"));
+    newVector.addElement(new Option(
+	      "\tDisallow internal periods",
+              "P", 0, "-P"));
+
+    return newVector.elements();
+  }
+
+  /**
+   * Parses a given list of options controlling the behaviour of this object.
+   * Valid options are:<p>
+   *
+   * -R index1,index2-index4,...<br>
+   * Specify list of attributes to process. First and last are valid indexes.
+   * (default none)<p>
+   *
+   * -V<br>
+   * Invert matching sense <p>
+   *
+   * -P<br>
+   * Disallow internal periods <p>
+   *
+   * @param options the list of options as an array of strings
+   * @exception Exception if an option is not supported
+   */
+  public void setOptions(String[] options) throws Exception {
+
+    String list = Utils.getOption('R', options);
+    if (list.length() != 0) {
+      setAttributeIndices(list);
+    }
+    setInvertSelection(Utils.getFlag('V', options));
+
+    setDisallowInternalPeriods(Utils.getFlag('P', options));
+    
+    if (getInputFormat() != null) {
+      setInputFormat(getInputFormat());
+    }
+  }
+
+  /**
+   * Gets the current settings of the filter.
+   *
+   * @return an array of strings suitable for passing to setOptions
+   */
+  public String [] getOptions() {
+
+    String [] options = new String [4];
+    int current = 0;
+
+    if (getInvertSelection()) {
+      options[current++] = "-V";
+    }
+    if (getDisallowInternalPeriods()) {
+      options[current++] = "-P";
+    }
+    if (!getAttributeIndices().equals("")) {
+      options[current++] = "-R"; options[current++] = getAttributeIndices();
+    }
+
+    while (current < options.length) {
+      options[current++] = "";
+    }
+    return options;
+  }
+
+  /**
+   * Sets the format of the input instances.
+   *
+   * @param instanceInfo an Instances object containing the input
+   * instance structure (any instances contained in the object are
+   * ignored - only the structure is required).
+   * @return true if the outputFormat may be collected immediately 
+   */
+  public boolean setInputFormat(Instances instanceInfo) throws Exception {
+
+    super.setInputFormat(instanceInfo);
+    setOutputFormat(instanceInfo);
+    m_SelectCols.setUpper(instanceInfo.numAttributes() - 1);
+
+    return true;
+  }
+
+  /**
+   * Input an instance for filtering. Ordinarily the instance is processed
+   * and made available for output immediately. Some filters require all
+   * instances be read before producing output.
+   *
+   * @param instance the input instance
+   * @return true if the filtered instance may now be
+   * collected with output().
+   * @exception Exception if the input instance was not of the correct 
+   * format or if there was a problem with the filtering.
+   */
+  public boolean input(Instance instance) throws Exception {
+
+    if (getInputFormat() == null) {
+      throw new Exception("No input instance format defined");
+    }
+    if (m_NewBatch) {
+      resetQueue();
+      m_NewBatch = false;
+    }
+    convertInstance(instance);
+    return true;
+  }
+
+  /**
+   * Signify that this batch of input to the filter is finished. If
+   * the filter requires all instances prior to filtering, output()
+   * may now be called to retrieve the filtered instances. Any
+   * subsequent instances filtered should be filtered based on setting
+   * obtained from the first batch (unless the inputFormat has been
+   * re-assigned or new options have been set). This default
+   * implementation assumes all instance processing occurs during
+   * inputFormat() and input().
+   *
+   * @return true if there are instances pending output
+   * @exception NullPointerException if no input structure has been defined,
+   * @exception Exception if there was a problem finishing the batch.
+   */
+  public boolean batchFinished() throws Exception {
+
+    if (getInputFormat() == null) {
+      throw new NullPointerException("No input instance format defined");
+    }
+    m_NewBatch = true;
+    return (numPendingOutput() != 0);
+  }
+
+  /**
+   * Main method for testing this class.
+   *
+   * @param argv should contain arguments to the filter: use -h for help
+   */
+  public static void main(String [] argv) {
+    
+    try {
+      if (Utils.getFlag('b', argv)) {
+	Filter.batchFilterFile(new KEAPhraseFilter(), argv);
+      } else {
+	Filter.filterFile(new KEAPhraseFilter(), argv);
+      }
+    } catch (Exception ex) {
+      System.out.println(ex.getMessage());
+    }
+  }
+ 
+  /** 
+   * Converts an instance by removing all non-alphanumeric characters
+   * from its string attribute values.
+   */
+  private void convertInstance(Instance instance) throws Exception {
+  
+    double[] instVals = new double[instance.numAttributes()];
+
+    for (int i = 0; i < instance.numAttributes(); i++) {
+      if (!instance.attribute(i).isString() || 
+	  instance.isMissing(i)) {
+	instVals[i] = instance.value(i);
+      } else {
+	if (!m_SelectCols.isInRange(i)) {
+	  int index = getOutputFormat().attribute(i).
+	    addStringValue(instance.stringValue(i));
+	  instVals[i] = (double)index;
+	  continue;
+	}
+	String str = instance.stringValue(i);
+	StringBuffer resultStr = new StringBuffer();
+	int j = 0;
+	boolean phraseStart = true;
+	boolean seenNewLine = false;
+	boolean haveSeenHyphen = false;
+	boolean haveSeenSlash = false;
+	while (j < str.length()) {
+	  boolean isWord = false;
+	  boolean potNumber = false;
+	  int startj = j;
+	  while (j < str.length()) {
+	    char ch = str.charAt(j);
+	    if (Character.isLetterOrDigit(ch)) {
+	      potNumber = true;
+	      if (Character.isLetter(ch)) {
+		isWord = true;
+	      }
+	      j++;
+	    } else if ((!m_DisallowInternalPeriods && (ch == '.')) ||
+		       (ch == '@') ||
+		       (ch == '_') ||
+		       (ch == '&') ||
+		       (ch == '/') ||
+		       (ch == '-')) {
+	      if ((j > 0) && (j  + 1 < str.length()) &&
+		  Character.isLetterOrDigit(str.charAt(j - 1)) &&
+		  Character.isLetterOrDigit(str.charAt(j + 1))) {
+		j++;
+	      } else {
+		break;
+	      }
+	    } else if (ch == '\'') {
+	      if ((j > 0) &&
+		  Character.isLetterOrDigit(str.charAt(j - 1))) {
+		j++;
+	      } else {
+		break;
+	      }
+	    } else {
+	      break;
+	    }
+	  }
+	  if (isWord == true) {
+	    if (!phraseStart) {
+	      if (haveSeenHyphen) {
+		resultStr.append('-');
+	      } else if (haveSeenSlash) {
+		resultStr.append('/');
+	      } else {
+		resultStr.append(' ');
+	      }
+	    }
+	    resultStr.append(str.substring(startj, j));
+	    if (j == str.length()) {
+	      break;
+	    }
+	    phraseStart = false;
+	    seenNewLine = false;
+	    haveSeenHyphen = false;
+	    haveSeenSlash = false;
+	    if (Character.isWhitespace(str.charAt(j))) {
+	      if (str.charAt(j) == '\n') {
+		seenNewLine = true;
+	      } 
+	    } else if (str.charAt(j) == '-') {
+	      haveSeenHyphen = true;
+	    } else if (str.charAt(j) == '/') {
+	      haveSeenSlash = true;
+	    } else {
+	      phraseStart = true;
+	      resultStr.append('\n');
+	    }
+	    j++;
+	  } else if (j == str.length()) {
+	    break;
+	  } else if (str.charAt(j) == '\n') {
+	    if (seenNewLine) {
+	      if (phraseStart == false) {
+		resultStr.append('\n');
+		phraseStart = true;
+	      }
+	    } else if (potNumber) {
+	      if (phraseStart == false) {
+		phraseStart = true;
+		resultStr.append('\n');
+	      }
+	    }
+	    seenNewLine = true;
+	    j++;
+	  } else if (Character.isWhitespace(str.charAt(j))) {
+	    if (potNumber) {
+	      if (phraseStart == false) {
+		phraseStart = true;
+		resultStr.append('\n');
+	      }
+	    }
+	    j++;
+	  } else {
+	    if (phraseStart == false) {
+	      resultStr.append('\n');
+	      phraseStart = true;
+	    }
+	    j++;
+	  }
+	}
+	int index = getOutputFormat().attribute(i).
+	  addStringValue(resultStr.toString());
+	instVals[i] = (double)index;
+      }
+    }
+    Instance inst = new Instance(instance.weight(), instVals);
+    inst.setDataset(getOutputFormat());
+    push(inst);
+  }
+
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String invertSelectionTipText() {
+
+    return "If set to false, the specified attributes will be processed;"
+      + " If set to true, specified attributes won't be processed.";
+  }
+
+  /**
+   * Get whether the supplied columns are to be processed
+   *
+   * @return true if the supplied columns won't be processed
+   */
+  public boolean getInvertSelection() {
+
+    return m_SelectCols.getInvert();
+  }
+
+  /**
+   * Set whether selected columns should be processed. If true the 
+   * selected columns won't be processed.
+   *
+   * @param invert the new invert setting
+   */
+  public void setInvertSelection(boolean invert) {
+
+    m_SelectCols.setInvert(invert);
+  }
+
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String disallowInternalPeriodsTipText() {
+
+    return "If set to false, internal periods are allowed.";
+  }
+
+  /**
+   * Get whether the supplied columns are to be processed
+   *
+   * @return true if the supplied columns won't be processed
+   */
+  public boolean getDisallowInternalPeriods() {
+
+    return m_DisallowInternalPeriods;
+  }
+
+  /**
+   * Set whether selected columns should be processed. If true the 
+   * selected columns won't be processed.
+   *
+   * @param invert the new invert setting
+   */
+  public void setDisallowInternalPeriods(boolean disallow) {
+
+    m_DisallowInternalPeriods = disallow;
+  }
+
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String attributeIndicesTipText() {
+
+    return "Specify range of attributes to act on."
+      + " This is a comma separated list of attribute indices, with"
+      + " \"first\" and \"last\" valid values. Specify an inclusive"
+      + " range with \"-\". E.g: \"first-3,5,6-10,last\".";
+  }
+
+  /**
+   * Get the current range selection.
+   *
+   * @return a string containing a comma separated list of ranges
+   */
+  public String getAttributeIndices() {
+
+    return m_SelectCols.getRanges();
+  }
+
+  /**
+   * Set which attributes are to be processed
+   *
+   * @param rangeList a string representing the list of attributes.  Since
+   * the string will typically come from a user, attributes are indexed from
+   * 1. <br>
+   * eg: first-3,5,6-last
+   */
+  public void setAttributeIndices(String rangeList) {
+
+    m_SelectCols.setRanges(rangeList);
+  }
+
+  /**
+   * Set which attributes are to be processed
+   *
+   * @param attributes an array containing indexes of attributes to select.
+   * Since the array will typically come from a program, attributes are indexed
+   * from 0.
+   */
+  public void setAttributeIndicesArray(int [] attributes) {
+    
+    setAttributeIndices(Range.indicesToRangeList(attributes));
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/LovinsStemmer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/LovinsStemmer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/LovinsStemmer.java	(revision 10506)
@@ -0,0 +1,890 @@
+/*
+ *    LovinsStemmer.java
+ *    Copyright (C) 2001 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import java.util.*;
+import java.io.*;
+
+/** 
+ * Implements the Lovins stemmer.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public class LovinsStemmer extends Stemmer implements Serializable {
+
+  /** C version compatibility mode (emulates bugs
+      in original C implementation) */
+  private static boolean m_CompMode = true;
+
+  /** The hash tables containing the list of endings. */
+  private static HashMap m_l11 = null;
+  private static HashMap m_l10 = null;
+  private static HashMap m_l9 = null;
+  private static HashMap m_l8 = null;
+  private static HashMap m_l7 = null;
+  private static HashMap m_l6 = null;
+  private static HashMap m_l5 = null;
+  private static HashMap m_l4 = null;
+  private static HashMap m_l3 = null;
+  private static HashMap m_l2 = null;
+  private static HashMap m_l1 = null;
+
+  static {
+
+    m_l11 = new HashMap();
+    m_l11.put("alistically", "B");
+    m_l11.put("arizability", "A");
+    m_l11.put("izationally", "B");
+    m_l10 = new HashMap();
+    m_l10.put("antialness", "A");
+    m_l10.put("arisations", "A");
+    m_l10.put("arizations", "A");
+    m_l10.put("entialness", "A");
+    m_l9 = new HashMap();
+    m_l9.put("allically", "C");
+    m_l9.put("antaneous", "A");
+    m_l9.put("antiality", "A");
+    m_l9.put("arisation", "A");
+    m_l9.put("arization", "A");
+    m_l9.put("ationally", "B");
+    m_l9.put("ativeness", "A");
+    m_l9.put("eableness", "E");
+    m_l9.put("entations", "A");
+    m_l9.put("entiality", "A");
+    m_l9.put("entialize", "A");
+    m_l9.put("entiation", "A");
+    m_l9.put("ionalness", "A");
+    m_l9.put("istically", "A");
+    m_l9.put("itousness", "A");
+    m_l9.put("izability", "A");
+    m_l9.put("izational", "A");
+    m_l8 = new HashMap();
+    m_l8.put("ableness", "A");
+    m_l8.put("arizable", "A");
+    m_l8.put("entation", "A");
+    m_l8.put("entially", "A");
+    m_l8.put("eousness", "A");
+    m_l8.put("ibleness", "A");
+    m_l8.put("icalness", "A");
+    m_l8.put("ionalism", "A");
+    m_l8.put("ionality", "A");
+    m_l8.put("ionalize", "A");
+    m_l8.put("iousness", "A");
+    m_l8.put("izations", "A");
+    m_l8.put("lessness", "A");
+    m_l7 = new HashMap();
+    m_l7.put("ability", "A");
+    m_l7.put("aically", "A");
+    m_l7.put("alistic", "B");
+    m_l7.put("alities", "A");
+    m_l7.put("ariness", "E");
+    m_l7.put("aristic", "A");
+    m_l7.put("arizing", "A");
+    m_l7.put("ateness", "A");
+    m_l7.put("atingly", "A");
+    m_l7.put("ational", "B");
+    m_l7.put("atively", "A");
+    m_l7.put("ativism", "A");
+    m_l7.put("elihood", "E");
+    m_l7.put("encible", "A");
+    m_l7.put("entally", "A");
+    m_l7.put("entials", "A");
+    m_l7.put("entiate", "A");
+    m_l7.put("entness", "A");
+    m_l7.put("fulness", "A");
+    m_l7.put("ibility", "A");
+    m_l7.put("icalism", "A");
+    m_l7.put("icalist", "A");
+    m_l7.put("icality", "A");
+    m_l7.put("icalize", "A");
+    m_l7.put("ication", "G");
+    m_l7.put("icianry", "A");
+    m_l7.put("ination", "A");
+    m_l7.put("ingness", "A");
+    m_l7.put("ionally", "A");
+    m_l7.put("isation", "A");
+    m_l7.put("ishness", "A");
+    m_l7.put("istical", "A");
+    m_l7.put("iteness", "A");
+    m_l7.put("iveness", "A");
+    m_l7.put("ivistic", "A");
+    m_l7.put("ivities", "A");
+    m_l7.put("ization", "F");
+    m_l7.put("izement", "A");
+    m_l7.put("oidally", "A");
+    m_l7.put("ousness", "A");
+    m_l6 = new HashMap();
+    m_l6.put("aceous", "A");
+    m_l6.put("acious", "B");
+    m_l6.put("action", "G");
+    m_l6.put("alness", "A");
+    m_l6.put("ancial", "A");
+    m_l6.put("ancies", "A");
+    m_l6.put("ancing", "B");
+    m_l6.put("ariser", "A");
+    m_l6.put("arized", "A");
+    m_l6.put("arizer", "A");
+    m_l6.put("atable", "A");
+    m_l6.put("ations", "B");
+    m_l6.put("atives", "A");
+    m_l6.put("eature", "Z");
+    m_l6.put("efully", "A");
+    m_l6.put("encies", "A");
+    m_l6.put("encing", "A");
+    m_l6.put("ential", "A");
+    m_l6.put("enting", "C");
+    m_l6.put("entist", "A");
+    m_l6.put("eously", "A");
+    m_l6.put("ialist", "A");
+    m_l6.put("iality", "A");
+    m_l6.put("ialize", "A");
+    m_l6.put("ically", "A");
+    m_l6.put("icance", "A");
+    m_l6.put("icians", "A");
+    m_l6.put("icists", "A");
+    m_l6.put("ifully", "A");
+    m_l6.put("ionals", "A");
+    m_l6.put("ionate", "D");
+    m_l6.put("ioning", "A");
+    m_l6.put("ionist", "A");
+    m_l6.put("iously", "A");
+    m_l6.put("istics", "A");
+    m_l6.put("izable", "E");
+    m_l6.put("lessly", "A");
+    m_l6.put("nesses", "A");
+    m_l6.put("oidism", "A");
+    m_l5 = new HashMap();
+    m_l5.put("acies", "A");
+    m_l5.put("acity", "A");
+    m_l5.put("aging", "B");
+    m_l5.put("aical", "A");
+    if (!m_CompMode) {
+      m_l5.put("alist", "A");
+    }
+    m_l5.put("alism", "B");
+    m_l5.put("ality", "A");
+    m_l5.put("alize", "A");
+    m_l5.put("allic", "b");
+    m_l5.put("anced", "B");
+    m_l5.put("ances", "B");
+    m_l5.put("antic", "C");
+    m_l5.put("arial", "A");
+    m_l5.put("aries", "A");
+    m_l5.put("arily", "A");
+    m_l5.put("arity", "B");
+    m_l5.put("arize", "A");
+    m_l5.put("aroid", "A");
+    m_l5.put("ately", "A");
+    m_l5.put("ating", "I");
+    m_l5.put("ation", "B");
+    m_l5.put("ative", "A");
+    m_l5.put("ators", "A");
+    m_l5.put("atory", "A");
+    m_l5.put("ature", "E");
+    m_l5.put("early", "Y");
+    m_l5.put("ehood", "A");
+    m_l5.put("eless", "A");
+    if (!m_CompMode) {
+      m_l5.put("elily", "A");
+    } else {
+      m_l5.put("elity", "A");
+    }
+    m_l5.put("ement", "A");
+    m_l5.put("enced", "A");
+    m_l5.put("ences", "A");
+    m_l5.put("eness", "E");
+    m_l5.put("ening", "E");
+    m_l5.put("ental", "A");
+    m_l5.put("ented", "C");
+    m_l5.put("ently", "A");
+    m_l5.put("fully", "A");
+    m_l5.put("ially", "A");
+    m_l5.put("icant", "A");
+    m_l5.put("ician", "A");
+    m_l5.put("icide", "A");
+    m_l5.put("icism", "A");
+    m_l5.put("icist", "A");
+    m_l5.put("icity", "A");
+    m_l5.put("idine", "I");
+    m_l5.put("iedly", "A");
+    m_l5.put("ihood", "A");
+    m_l5.put("inate", "A");
+    m_l5.put("iness", "A");
+    m_l5.put("ingly", "B");
+    m_l5.put("inism", "J");
+    m_l5.put("inity", "c");
+    m_l5.put("ional", "A");
+    m_l5.put("ioned", "A");
+    m_l5.put("ished", "A");
+    m_l5.put("istic", "A");
+    m_l5.put("ities", "A");
+    m_l5.put("itous", "A");
+    m_l5.put("ively", "A");
+    m_l5.put("ivity", "A");
+    m_l5.put("izers", "F");
+    m_l5.put("izing", "F");
+    m_l5.put("oidal", "A");
+    m_l5.put("oides", "A");
+    m_l5.put("otide", "A");
+    m_l5.put("ously", "A");
+    m_l4 = new HashMap();
+    m_l4.put("able", "A");
+    m_l4.put("ably", "A");
+    m_l4.put("ages", "B");
+    m_l4.put("ally", "B");
+    m_l4.put("ance", "B");
+    m_l4.put("ancy", "B");
+    m_l4.put("ants", "B");
+    m_l4.put("aric", "A");
+    m_l4.put("arly", "K");
+    m_l4.put("ated", "I");
+    m_l4.put("ates", "A");
+    m_l4.put("atic", "B");
+    m_l4.put("ator", "A");
+    m_l4.put("ealy", "Y");
+    m_l4.put("edly", "E");
+    m_l4.put("eful", "A");
+    m_l4.put("eity", "A");
+    m_l4.put("ence", "A");
+    m_l4.put("ency", "A");
+    m_l4.put("ened", "E");
+    m_l4.put("enly", "E");
+    m_l4.put("eous", "A");
+    m_l4.put("hood", "A");
+    m_l4.put("ials", "A");
+    m_l4.put("ians", "A");
+    m_l4.put("ible", "A");
+    m_l4.put("ibly", "A");
+    m_l4.put("ical", "A");
+    m_l4.put("ides", "L");
+    m_l4.put("iers", "A");
+    m_l4.put("iful", "A");
+    m_l4.put("ines", "M");
+    m_l4.put("ings", "N");
+    m_l4.put("ions", "B");
+    m_l4.put("ious", "A");
+    m_l4.put("isms", "B");
+    m_l4.put("ists", "A");
+    m_l4.put("itic", "H");
+    m_l4.put("ized", "F");
+    m_l4.put("izer", "F");
+    m_l4.put("less", "A");
+    m_l4.put("lily", "A");
+    m_l4.put("ness", "A");
+    m_l4.put("ogen", "A");
+    m_l4.put("ward", "A");
+    m_l4.put("wise", "A");
+    m_l4.put("ying", "B");
+    m_l4.put("yish", "A");
+    m_l3 = new HashMap();
+    m_l3.put("acy", "A");
+    m_l3.put("age", "B");
+    m_l3.put("aic", "A");
+    m_l3.put("als", "b");
+    m_l3.put("ant", "B");
+    m_l3.put("ars", "O");
+    m_l3.put("ary", "F");
+    m_l3.put("ata", "A");
+    m_l3.put("ate", "A");
+    m_l3.put("eal", "Y");
+    m_l3.put("ear", "Y");
+    m_l3.put("ely", "E");
+    m_l3.put("ene", "E");
+    m_l3.put("ent", "C");
+    m_l3.put("ery", "E");
+    m_l3.put("ese", "A");
+    m_l3.put("ful", "A");
+    m_l3.put("ial", "A");
+    m_l3.put("ian", "A");
+    m_l3.put("ics", "A");
+    m_l3.put("ide", "L");
+    m_l3.put("ied", "A");
+    m_l3.put("ier", "A");
+    m_l3.put("ies", "P");
+    m_l3.put("ily", "A");
+    m_l3.put("ine", "M");
+    m_l3.put("ing", "N");
+    m_l3.put("ion", "Q");
+    m_l3.put("ish", "C");
+    m_l3.put("ism", "B");
+    m_l3.put("ist", "A");
+    m_l3.put("ite", "a");
+    m_l3.put("ity", "A");
+    m_l3.put("ium", "A");
+    m_l3.put("ive", "A");
+    m_l3.put("ize", "F");
+    m_l3.put("oid", "A");
+    m_l3.put("one", "R");
+    m_l3.put("ous", "A");
+    m_l2 = new HashMap();
+    m_l2.put("ae", "A"); 
+    m_l2.put("al", "b");
+    m_l2.put("ar", "X");
+    m_l2.put("as", "B");
+    m_l2.put("ed", "E");
+    m_l2.put("en", "F");
+    m_l2.put("es", "E");
+    m_l2.put("ia", "A");
+    m_l2.put("ic", "A");
+    m_l2.put("is", "A");
+    m_l2.put("ly", "B");
+    m_l2.put("on", "S");
+    m_l2.put("or", "T");
+    m_l2.put("um", "U");
+    m_l2.put("us", "V");
+    m_l2.put("yl", "R");
+    m_l2.put("s\'", "A");
+    m_l2.put("\'s", "A");
+    m_l1 = new HashMap();
+    m_l1.put("a", "A");
+    m_l1.put("e", "A");
+    m_l1.put("i", "A");
+    m_l1.put("o", "A");
+    m_l1.put("s", "W");
+    m_l1.put("y", "B");	
+  }
+
+  /**
+   * Finds and removes ending from given word.
+   */
+  private String removeEnding(String word) {
+
+    int length = word.length();
+    int el = 11;
+
+    while (el > 0) {
+      if (length - el > 1) {
+	String ending = word.substring(length - el);
+	String conditionCode = null;
+	switch (el) {
+	case 11: conditionCode = (String)m_l11.get(ending);
+	  break;
+	case 10: conditionCode = (String)m_l10.get(ending);
+	  break; 
+	case 9: conditionCode = (String)m_l9.get(ending);
+	  break;
+	case 8: conditionCode = (String)m_l8.get(ending);
+	  break;   
+	case 7: conditionCode = (String)m_l7.get(ending);
+	  break;   
+	case 6: conditionCode = (String)m_l6.get(ending);
+	  break;   
+	case 5: conditionCode = (String)m_l5.get(ending);
+	  break;   
+	case 4: conditionCode = (String)m_l4.get(ending);
+	  break;   
+	case 3: conditionCode = (String)m_l3.get(ending);
+	  break;   
+	case 2: conditionCode = (String)m_l2.get(ending);
+	  break;   
+	case 1: conditionCode = (String)m_l1.get(ending);
+	  break;   
+	default:
+	}
+	if (conditionCode != null) {
+	  switch (conditionCode.charAt(0)) {
+	  case 'A':
+	    return word.substring(0, length - el);
+	  case 'B':
+	    if (length - el > 2) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'C':
+	    if (length - el > 3) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'D':
+	    if (length - el > 4) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'E':
+	    if (word.charAt(length - el - 1) != 'e') {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'F':
+	    if ((length - el > 2) &&
+		(word.charAt(length - el - 1) != 'e')) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'G':
+	    if ((length - el > 2) &&
+		(word.charAt(length - el - 1) == 'f')) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'H':
+	    if ((word.charAt(length - el - 1) == 't') ||
+		((word.charAt(length - el - 1) == 'l') &&
+		 (word.charAt(length - el - 2) == 'l'))) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'I':
+	    if ((word.charAt(length - el - 1) != 'o') &&
+		(word.charAt(length - el - 1) != 'e')) { 
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'J':
+	    if ((word.charAt(length - el - 1) != 'a') &&
+		(word.charAt(length - el - 1) != 'e')) { 
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'K':
+	    if ((length - el > 2) &&
+		((word.charAt(length - el - 1) == 'l') ||
+		 (word.charAt(length - el - 1) == 'i') ||
+		 ((word.charAt(length - el - 1) == 'e') &&
+		  (word.charAt(length - el - 3) == 'u')))) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'L':
+	    if ((word.charAt(length - el - 1) != 'u') &&
+		(word.charAt(length - el - 1) != 'x') &&
+		((word.charAt(length - el - 1) != 's') ||
+		 (word.charAt(length - el - 2) == 'o'))) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'M':
+	    if ((word.charAt(length - el - 1) != 'a') &&
+		(word.charAt(length - el - 1) != 'c') &&
+		(word.charAt(length - el - 1) != 'e') &&
+		(word.charAt(length - el - 1) != 'm')) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'N':
+	    if ((length - el > 3) || 
+		((length - el == 3) &&
+		 ((word.charAt(length - el - 3) != 's')))) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'O':
+	    if ((word.charAt(length - el - 1) == 'l') ||
+		(word.charAt(length - el - 1) == 'i')) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'P':
+	    if (word.charAt(length - el - 1) != 'c') {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'Q':
+	    if ((length - el > 2) &&
+		(word.charAt(length - el - 1) != 'l') &&
+		(word.charAt(length - el - 1) != 'n')) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'R':
+	    if ((word.charAt(length - el - 1) == 'n') ||
+		(word.charAt(length - el - 1) == 'r')) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'S':
+	    if (((word.charAt(length - el - 1) == 'r') &&
+		 (word.charAt(length - el - 2) == 'd')) ||
+		((word.charAt(length - el - 1) == 't') &&
+		 (word.charAt(length - el - 2) != 't'))) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'T':
+	    if ((word.charAt(length - el - 1) == 's') ||
+		((word.charAt(length - el - 1) == 't') &&
+		 (word.charAt(length - el - 2) != 'o'))) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'U':
+	    if ((word.charAt(length - el - 1) == 'l') ||
+		(word.charAt(length - el - 1) == 'm') ||
+		(word.charAt(length - el - 1) == 'n') ||
+		(word.charAt(length - el - 1) == 'r')) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'V':
+	    if (word.charAt(length - el - 1) == 'c') {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'W':
+	    if ((word.charAt(length - el - 1) != 's') &&
+		(word.charAt(length - el - 1) != 'u')) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'X':
+	    if ((word.charAt(length - el - 1) == 'l') ||
+		(word.charAt(length - el - 1) == 'i') ||
+		((length - el > 2) &&
+		 (word.charAt(length - el - 1) == 'e') &&
+		 (word.charAt(length - el - 3) == 'u'))) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'Y':
+	    if ((word.charAt(length - el - 1) == 'n') &&
+		(word.charAt(length - el - 2) == 'i')) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'Z':
+	    if (word.charAt(length - el - 1) != 'f') {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'a':
+	    if ((word.charAt(length - el - 1) == 'd') ||
+		(word.charAt(length - el - 1) == 'f') ||
+		(((word.charAt(length - el - 1) == 'h') &&
+		  (word.charAt(length - el - 2) == 'p'))) ||
+		(((word.charAt(length - el - 1) == 'h') &&
+		  (word.charAt(length - el - 2) == 't'))) ||
+		(word.charAt(length - el - 1) == 'l') ||
+		(((word.charAt(length - el - 1) == 'r') &&
+		  (word.charAt(length - el - 2) == 'e'))) ||
+		(((word.charAt(length - el - 1) == 'r') &&
+		  (word.charAt(length - el - 2) == 'o'))) ||
+		(((word.charAt(length - el - 1) == 's') &&
+		  (word.charAt(length - el - 2) == 'e'))) ||
+		(word.charAt(length - el - 1) == 't')) {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  case 'b':
+	    if (m_CompMode) {
+	      if (((length - el == 3 ) &&
+		   (!((word.charAt(length - el - 1) == 't') &&
+		      (word.charAt(length - el - 2) == 'e') &&
+		      (word.charAt(length - el - 3) == 'm')))) ||
+		  ((length - el > 3) &&
+		   (!((word.charAt(length - el - 1) == 't') &&
+		      (word.charAt(length - el - 2) == 's') &&
+		      (word.charAt(length - el - 3) == 'y') &&
+		      (word.charAt(length - el - 4) == 'r'))))) {
+		return word.substring(0, length - el);
+	      }
+	    } else {
+	      if ((length - el > 2) &&
+		  (!((word.charAt(length - el - 1) == 't') &&
+		     (word.charAt(length - el - 2) == 'e') &&
+		     (word.charAt(length - el - 3) == 'm'))) &&
+		  ((length - el < 4) ||
+		   (!((word.charAt(length - el - 1) == 't') &&
+		      (word.charAt(length - el - 2) == 's') &&
+		      (word.charAt(length - el - 3) == 'y') &&
+		      (word.charAt(length - el - 4) == 'r'))))) {
+		return word.substring(0, length - el);
+	      }
+	    } 
+	    break;
+	  case 'c':
+	    if (word.charAt(length - el - 1) == 'l') {
+	      return word.substring(0, length - el);
+	    }
+	    break;
+	  default:
+	    throw new IllegalArgumentException("Fatal error.");
+	  }
+	}
+      }
+      el--;
+    }
+    return word;
+  }
+
+  /**
+   * Recodes ending of given word.
+   */
+  private String recodeEnding(String word) {
+
+    int lastPos = word.length() - 1;
+
+    // Rule 1
+    if (word.endsWith("bb") ||
+	word.endsWith("dd") ||
+	word.endsWith("gg") ||
+	word.endsWith("ll") ||
+	word.endsWith("mm") ||
+	word.endsWith("nn") ||
+	word.endsWith("pp") ||
+	word.endsWith("rr") ||
+	word.endsWith("ss") ||
+	word.endsWith("tt")) {
+      word = word.substring(0, lastPos);
+      lastPos--;
+    }
+
+    // Rule 2
+    if (word.endsWith("iev")) {
+      word = word.substring(0, lastPos - 2).concat("ief");
+    }
+
+    // Rule 3
+    if (word.endsWith("uct")) {
+      word = word.substring(0, lastPos - 2).concat("uc");
+      lastPos--;
+    }
+
+    // Rule 4
+    if (word.endsWith("umpt")) {
+      word = word.substring(0, lastPos - 3).concat("um");
+      lastPos -= 2;
+    }
+
+    // Rule 5
+    if (word.endsWith("rpt")) {
+      word = word.substring(0, lastPos - 2).concat("rb");
+      lastPos--;
+    }
+
+    // Rule 6
+    if (word.endsWith("urs")) {
+      word = word.substring(0, lastPos - 2).concat("ur");
+      lastPos--;
+    }
+
+    // Rule 7
+    if (word.endsWith("istr")) {
+      word = word.substring(0, lastPos - 3).concat("ister");
+      lastPos++;
+    }
+ 
+    // Rule 7a
+    if (word.endsWith("metr")) {
+      word = word.substring(0, lastPos - 3).concat("meter");
+      lastPos++;
+    }
+
+    // Rule 8
+    if (word.endsWith("olv")) {
+      word = word.substring(0, lastPos - 2).concat("olut");
+      lastPos++;
+    }
+ 
+    // Rule 9
+    if (word.endsWith("ul")) {
+      if ((lastPos - 2 < 0) ||
+	  ((word.charAt(lastPos - 2) != 'a') &&
+	   (word.charAt(lastPos - 2) != 'i') &&
+	   (word.charAt(lastPos - 2) != 'o'))) {
+	word = word.substring(0, lastPos - 1).concat("l");
+	lastPos--;
+      }
+    }
+
+    // Rule 10
+    if (word.endsWith("bex")) {
+      word = word.substring(0, lastPos - 2).concat("bic");
+    }
+
+    // Rule 11
+    if (word.endsWith("dex")) {
+      word = word.substring(0, lastPos - 2).concat("dic");
+    }
+
+    // Rule 12
+    if (word.endsWith("pex")) {
+      word = word.substring(0, lastPos - 2).concat("pic");
+    }
+
+    // Rule 13
+    if (word.endsWith("tex")) {
+      word = word.substring(0, lastPos - 2).concat("tic");
+    }
+
+    // Rule 14
+    if (word.endsWith("ax")) {
+      word = word.substring(0, lastPos - 1).concat("ac");
+    }
+
+    // Rule 15
+    if (word.endsWith("ex")) {
+      word = word.substring(0, lastPos - 1).concat("ec");
+    }
+
+    // Rule 16
+    if (word.endsWith("ix")) {
+      word = word.substring(0, lastPos - 1).concat("ic");
+    }
+
+    // Rule 17
+    if (word.endsWith("lux")) {
+      word = word.substring(0, lastPos - 2).concat("luc");
+    }
+
+    // Rule 18
+    if (word.endsWith("uad")) {
+      word = word.substring(0, lastPos - 2).concat("uas");
+    }
+
+    // Rule 19
+    if (word.endsWith("vad")) {
+      word = word.substring(0, lastPos - 2).concat("vas");
+    }
+
+    // Rule 20
+    if (word.endsWith("cid")) {
+      word = word.substring(0, lastPos - 2).concat("cis");
+    }
+
+    // Rule 21
+    if (word.endsWith("lid")) {
+      word = word.substring(0, lastPos - 2).concat("lis");
+    }
+
+    // Rule 22
+    if (word.endsWith("erid")) {
+      word = word.substring(0, lastPos - 3).concat("eris");
+    }
+
+    // Rule 23
+    if (word.endsWith("pand")) {
+      word = word.substring(0, lastPos - 3).concat("pans");
+    }
+ 
+    // Rule 24
+    if (word.endsWith("end")) {
+      if ((lastPos - 3 < 0) ||
+	   (word.charAt(lastPos - 3) != 's')) {
+	word = word.substring(0, lastPos - 2).concat("ens");
+      }
+    }
+
+    // Rule 25
+    if (word.endsWith("ond")) {
+      word = word.substring(0, lastPos - 2).concat("ons");
+    }
+
+    // Rule 26
+    if (word.endsWith("lud")) {
+      word = word.substring(0, lastPos - 2).concat("lus");
+    }
+
+    // Rule 27
+    if (word.endsWith("rud")) {
+      word = word.substring(0, lastPos - 2).concat("rus");
+    }
+
+    // Rule 28
+    if (word.endsWith("her")) {
+      if ((lastPos - 3 < 0) ||
+	  ((word.charAt(lastPos - 3) != 'p') &&
+	   (word.charAt(lastPos - 3) != 't'))) {
+	word = word.substring(0, lastPos - 2).concat("hes");
+      }
+    }
+
+    // Rule 29
+    if (word.endsWith("mit")) {
+      word = word.substring(0, lastPos - 2).concat("mis");
+    }
+
+    // Rule 30
+    if (word.endsWith("end")) {
+      if ((lastPos - 3 < 0) ||
+	  (word.charAt(lastPos - 3) != 'm')) {
+	word = word.substring(0, lastPos - 2).concat("ens");
+      }
+    }
+
+    // Rule 31
+    if (word.endsWith("ert")) {
+      word = word.substring(0, lastPos - 2).concat("ers");
+    }
+
+    // Rule 32
+    if (word.endsWith("et")) {
+      if ((lastPos - 2 < 0) ||
+	  (word.charAt(lastPos - 2) != 'n')) {
+	word = word.substring(0, lastPos - 1).concat("es");
+      }
+    }
+
+    // Rule 33
+    if (word.endsWith("yt")) {
+      word = word.substring(0, lastPos - 1).concat("ys");
+    }
+
+    // Rule 34
+    if (word.endsWith("yz")) {
+      word = word.substring(0, lastPos - 1).concat("ys");
+    }
+
+    return word;
+  }
+
+  /**
+   * Returns the stemmed version of the given word.
+   * 
+   * @param word a string consisting of a single word
+   */
+  public String stem(String word) {
+
+    if (word.length() > 2) {
+      return recodeEnding(removeEnding(word.toLowerCase()));
+    } else {
+      return word.toLowerCase();
+    }
+  }
+
+  /**
+   * Stems text coming into stdin and writes it to stdout.
+   */
+  public static void main(String[] ops) {
+
+    LovinsStemmer ls = new LovinsStemmer();
+
+    try {
+      int num;
+      StringBuffer wordBuffer = new StringBuffer();
+      while ((num = System.in.read()) != -1) {
+	char c = (char)num;
+	if (((num >= (int)'A') && (num <= (int)'Z')) ||
+	    ((num >= (int)'a') && (num <= (int)'z'))) {
+	  wordBuffer.append(c);
+	} else {
+	  if (wordBuffer.length() > 0) {
+	    System.out.print(ls.stem(wordBuffer.toString().
+				     toLowerCase()));
+	    wordBuffer = new StringBuffer();
+	  }
+	  System.out.print(c);
+	}
+      }
+    } catch (Exception e) {
+      System.err.println(e.getMessage());
+    }
+  }
+}
+    
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/NumbersFilter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/NumbersFilter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/NumbersFilter.java	(revision 10506)
@@ -0,0 +1,182 @@
+/*
+ *    NumbersFilter.java
+ *    Copyright (C) 2000 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import weka.core.*;
+import weka.filters.*;
+
+import java.util.*;
+
+/**
+ * Removes all numbers from all the string attributes in the given
+ * dataset. Assumes that words are separated by whitespace.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public class NumbersFilter extends Filter {
+
+  /**
+   * Returns a string describing this filter
+   *
+   * @return a description of the filter suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String globalInfo() {
+      return "Removes all numbers from all the string attributes in " +
+      "the given dataset. Assumes that words are separated by whitespace.";
+  }
+
+  /**
+   * Signify that this batch of input to the filter is finished. If
+   * the filter requires all instances prior to filtering, output()
+   * may now be called to retrieve the filtered instances. Any
+   * subsequent instances filtered should be filtered based on setting
+   * obtained from the first batch (unless the inputFormat has been
+   * re-assigned or new options have been set). This default
+   * implementation assumes all instance processing occurs during
+   * inputFormat() and input().
+   *
+   * @return true if there are instances pending output
+   * @exception NullPointerException if no input structure has been defined,
+   * @exception Exception if there was a problem finishing the batch.
+   */
+  public boolean batchFinished() throws Exception {
+
+    if (getInputFormat() == null) {
+      throw new NullPointerException("No input instance format defined");
+    }
+    m_NewBatch = true;
+    return (numPendingOutput() != 0);
+  }
+
+  /**
+   * Sets the format of the input instances.
+   *
+   * @param instanceInfo an Instances object containing the input
+   * instance structure (any instances contained in the object are
+   * ignored - only the structure is required).
+   * @return true if the outputFormat may be collected immediately 
+   */
+  public boolean setInputFormat(Instances instanceInfo) throws Exception {
+
+    super.setInputFormat(instanceInfo);
+    setOutputFormat(instanceInfo);
+    return true;
+  }
+
+  /**
+   * Input an instance for filtering. Ordinarily the instance is processed
+   * and made available for output immediately. Some filters require all
+   * instances be read before producing output.
+   *
+   * @param instance the input instance
+   * @return true if the filtered instance may now be
+   * collected with output().
+   * @exception Exception if the input instance was not of the correct 
+   * format or if there was a problem with the filtering.
+   */
+  public boolean input(Instance instance) throws Exception {
+
+    if (getInputFormat() == null) {
+      throw new Exception("No input instance format defined");
+    }
+    if (m_NewBatch) {
+      resetQueue();
+      m_NewBatch = false;
+    }
+    convertInstance(instance);
+    return true;
+  }
+
+  /**
+   * Main method for testing this class.
+   *
+   * @param argv should contain arguments to the filter: use -h for help
+   */
+  public static void main(String [] argv) {
+    
+    try {
+      if (Utils.getFlag('b', argv)) {
+	Filter.batchFilterFile(new NumbersFilter(), argv);
+      } else {
+	Filter.filterFile(new NumbersFilter(), argv);
+      }
+    } catch (Exception ex) {
+      System.out.println(ex.getMessage());
+    }
+  }
+ 
+  /** 
+   * Converts an instance. A phrase boundary is inserted where
+   * a number is found.
+   */
+  private void convertInstance(Instance instance) throws Exception {
+  
+    double[] instVals = new double[instance.numAttributes()];
+
+    for (int i = 0; i < instance.numAttributes(); i++) {
+      if ((!instance.attribute(i).isString()) || instance.isMissing(i)) {
+	instVals[i] = instance.value(i);
+      } else {
+	String str = instance.stringValue(i);
+	StringBuffer resultStr = new StringBuffer();
+	StringTokenizer tok = new StringTokenizer(str, " \t\n", true);
+	while (tok.hasMoreTokens()) {
+	  String token = tok.nextToken();
+
+	  // Everything that doesn't contain at least
+	  // one letter is considered to be a number
+	  boolean isNumber = true;
+	  for (int j = 0; j < token.length(); j++) {
+	    if (Character.isLetter(token.charAt(j))) {
+	      isNumber = false;
+	      break;
+	    }
+	  }
+	  if (!isNumber) {
+	    resultStr.append(token);
+	  } else {
+	    if (token.equals(" ") || token.equals("\t") ||
+		token.equals("\n")) {
+	      resultStr.append(token);
+	    } else {
+	      resultStr.append(" \n ");
+	    }
+	  }
+	}
+	int index = getOutputFormat().attribute(i).addStringValue(resultStr.toString());
+	instVals[i] = (double)index;
+      }
+    }
+    Instance inst = new Instance(instance.weight(), instVals);
+    inst.setDataset(getOutputFormat());
+    push(inst);
+  }
+}
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/README	(revision 10506)
@@ -0,0 +1,284 @@
+=====================================================================
+                                                                       
+                              ======                                   
+                              README                                   
+                              ======                                   
+                                                                       
+                             KEA 3.0
+                          18 March 2004
+                                                                       
+           Java Programs for Automatic Keyphrase Extraction
+                                                                       
+               Copyright (C) 2000, 2001, 2004  Eibe Frank
+
+                   email: eibe@cs.waikato.ac.nz            
+                                                                       
+=====================================================================
+
+Contents:
+---------
+
+1. Installation
+
+2. Getting started
+
+   - Building a keyphrase extraction model
+   - Extracting keyphrases
+   - Important comment
+
+3. Examples
+
+4. Other documentation
+
+5. Copyright
+
+----------------------------------------------------------------------
+
+NOTE:
+-----
+
+This distribution includes a cut-down version of WEKA, the GPL'ed
+machine learning workbench available from 
+
+  http://www.cs.waikato.ac.nz/ml/weka.
+
+----------------------------------------------------------------------
+
+1. Installation:
+----------------
+
+KEA is implemented as a set of Java classes (located in the same
+directory as this README file). To run KEA you need to tell the Java
+Virtual Machine where to look for KEA classes.  One possible way of
+doing this is to add the directory that contains this README file to
+the CLASSPATH environment variable that is used by the Java Virtual
+Machine.
+
+Under Linux you would do the following:
+
+a) Set KEAHOME to be the directory which contains this README.
+
+b) Add $KEAHOME to your CLASSPATH environment variable.
+
+The on-line documentation (generated from the source code) is located
+in the doc directory. You might want to do the following to have the
+documentation handy in you web browser:
+
+c) Bookmark $KEAHOME/doc/packages.html in your web browser.
+
+----------------------------------------------------------------------
+
+2. Getting started:
+-------------------
+
+Building a keyphrase extraction model
+=====================================
+
+To extract keyphrases for new documents, you first need to build a KEA
+keyphrase extraction model from a set of documents (preferably from
+the same domain) for which you have author- assigned keyphrases. To
+this end you have to go through the following steps:
+
+a) Create a directory, called, for example, "training_documents",
+   containing the documents that you want to use for training the
+   keyphrase extractor.
+
+b) Rename the document files in that directory so that they end with
+   the suffix ".txt".
+
+c) Delete the author-assigned keyphrases from those documents
+   and put them into separate ".key" files. For example, if
+   your document file is called doc1.txt, move the keyphrases
+   into a new file called "doc1.key". It is important that
+   you put each keyphrase on a separate line in the .key file!
+
+d) Build the keyphrase extraction model by running the
+   KEAModelBuilder:
+
+   java KEAModelBuilder -l <name_of_directory> -m <name_of_model>
+
+   This will use the documents in <name_of_directory> to build a
+   keyphrase extraction model and save it in <name_of_model>.
+
+KEAModelBuilder has a few other options that you can view if you run
+KEAModelBuilder without any arguments. Here is a list of all the
+options:
+
+-l <directory name>
+	Specifies name of directory.
+-m <model name>
+	Specifies name of model.
+-e <encoding>
+	Specifies encoding.
+-d
+	Turns debugging mode on.
+-k
+	Use keyphrase frequency statistic.
+-p
+	Disallow internal periods.
+-x <length>
+	Sets the maximum phrase length (default: 3).
+-y <length>
+	Sets the minimum phrase length (default: 1).
+-o <number>
+	The minimum number of times a phrase needs to occur 
+	(default: 2).
+-s <name of stopwords class>
+        Sets the list of stopwords to use (default: StopwordsEnglish).
+-t <name of stemmer class>
+        Set the stemmer to use (default: IteratedLovinsStemmer).
+-n
+        Do not check for proper nouns.
+   
+The -e option allows you to specify a different character encoding
+supported by Java. For example, to extract keyphrases from Chinese
+documents encoded using GBK, you would use specify "-e GBK" as an
+argument.
+
+The -d option generates some output that shows the progress of the
+model builder.
+
+If -k is set, the keyphrase frequency attribute is used in the
+model. For more info on this, have a look at the paper on
+"Domain-specific keyphrase extraction" listed below. Using this option
+improves accuracy if the domain of the documents for which you want to
+extract keyphrases is the same as the domain of the training
+documents. In other words, if you want to extract keyphrases from
+papers on radiology, and your training documents are about radiology,
+you should use this option.
+
+If -p is set, KEA does not consider phrases with internal periods as
+candidate keyphrases. It is important to use this if a full stop is
+not always followed by white space in the documents.
+
+Using -s and -t you can set different classes for stopword detection
+and stemming respectively (for languages other than English).
+
+Using -d you turn KEA's heuristic for detecting proper nouns off. This
+is important for languages like German, where all nouns start with an
+uppercase letter, not just proper nouns.
+
+Extracting keyphrases
+=====================
+
+To extract keyphrases for some documents, put them into an empty
+directory. Then rename them so that they end with the suffix ".txt".
+
+If you've previously built a keyphrase extraction model you can now
+apply keyphrases for these documents using:
+
+java KEAKeyphraseExtractor -l <name_of_directory> -m <name_of_model>
+
+This will create a ".key" file for each document in the
+directory. Each file will contain five extracted keyphrases for the
+corresponding document.
+
+If a ".key" file is already present it won't be overwritten.  Instead,
+the keyphrases present in that file will be used to evaluate the
+extraction model. The stemmed extracted phrases are compared to the
+stemmed versions of the phrases in the ".key"
+file. KEAKeyphraseExtractor reports the number of hits among the total
+number of extracted phrases for those documents that have associated
+".key" files in the directory.
+
+KEAKeyphraseExtractor has a few options. Here they are:
+
+-l <directory name>
+	Specifies name of directory.
+-m <model name>
+	Specifies name of model.
+-e <encoding>
+	Specifies encoding.
+-n
+	Specifies number of phrases to be output (default: 5).
+-d
+	Turns debugging mode on.
+-a
+	Also write stemmed phrase and score into ".key" file.
+
+Important comment
+-----------------
+
+To get good results, it is important that the input text for KEA is as
+"clean" as possible. That means html tags etc. in the input documents
+need to be deleted before the model is built and before keyphrases are
+extracted from new documents.
+
+----------------------------------------------------------------------
+
+3. Examples:
+------------
+
+The directory contains two example collections, each split up into a
+train and test directory. Note that these collections are only
+included to show how the system can be applied to actual documents.
+Due to the lack of data, the accuracy isn't very good on either
+example collection.
+
+Collection A
+------------
+
+A collection of abstracts taken from computer science technical
+reports:
+
+   CSTR_abstracts_train
+   CSTR_abstracts_test
+
+To build a model from the training data, try:
+
+   java KEAModelBuilder -l CSTR_abstracts_train -m CSTR_abstracts_model
+
+To evaluate that model on the test data, try:
+
+   java KEAKeyphraseExtractor -l CSTR_abstracts_test -m CSTR_abstracts_model
+
+Collection B
+------------
+
+A small collection of Chinese documents (in GBK encoding):
+
+   Journals_train
+   Journals_test
+
+To build a model from the training data, try:
+
+   java KEAModelBuilder -l Chinese_train -m Chinese_model -e GBK
+
+To evaluate that model on the test data, try:
+
+   java KEAKeyphraseExtractor -l Chinese_test -m Chinese_model -e GBK 
+
+----------------------------------------------------------------------
+
+4. Other documentation:
+-----------------------
+
+There are several papers on the KEA algorithm, listed below. Note that
+this implementation differs slightly from the version described in the
+papers, mainly in the pre-processing step (i.e. in the way candidate
+keyphrases are generated). For more info on the new method please
+consult the online documentation.
+
+Witten I.H., Paynter G.W., Frank E., Gutwin C. and Nevill-Manning
+C.G. (2000) "KEA: Practical automatic keyphrase extraction." Working
+Paper 00/5, Department of Computer Science, The University of Waikato.
+
+Witten I.H., Paynter G.W., Frank E., Gutwin C. and Nevill-Manning
+C.G. (1999) "KEA: Practical automatic keyphrase extraction." Proc. DL
+'99, pp. 254-256. (Poster presentation.)
+
+Frank E., Paynter G.W., Witten I.H., Gutwin C. and Nevill-Manning
+C.G. (1999) "Domain-specific keyphrase extraction" Proc. Sixteenth
+International Joint Conference on Artificial Intelligence, Morgan
+Kaufmann Publishers, San Francisco, CA, pp. 668-673.
+
+-----------------------------------------------------------------------
+
+5. Copyright:
+-------------
+
+KEA is distributed under the GNU public license. Please read the file
+COPYING.
+
+-----------------------------------------------------------------------
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/Stemmer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/Stemmer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/Stemmer.java	(revision 10506)
@@ -0,0 +1,68 @@
+/*
+ *    Stemmer.java
+ *    Copyright (C) 2001 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Abstract class for stemmers.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public abstract class Stemmer implements Serializable {
+
+  /**
+   * Iterated stemming of the given word.
+   */
+  public abstract String stem(String str);
+
+  /**
+   * Stems everything in the given string.
+   */
+  public String stemString(String str) {
+
+    StringBuffer result = new StringBuffer();
+    int start = -1;
+    for (int j = 0; j < str.length(); j++) {
+      char c = str.charAt(j);
+      if (Character.isLetterOrDigit(c)) {
+	if (start == -1) {
+	  start = j;
+	}
+      } else if (c == '\'') {
+	if (start == -1) {
+	  result.append(c);
+	}
+      } else {
+	if (start != -1) {
+	  result.append(stem(str.substring(start, j)));
+	  start = -1;
+	}
+	result.append(c);
+      }
+    }
+    if (start != -1) {
+      result.append(stem(str.substring(start, str.length())));
+    }
+    return result.toString();  
+  }
+}
+    
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/Stopwords.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/Stopwords.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/Stopwords.java	(revision 10506)
@@ -0,0 +1,38 @@
+/*
+ *    Stopwords.java
+ *    Copyright (C) 2001 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Class that can test whether a given string is a stop word.
+ * Lowercases all words before the test.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public abstract class Stopwords implements Serializable {
+  
+  /** 
+   * Returns true if the given string is a stop word.
+   */
+  public abstract boolean isStopword(String str);
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/StopwordsEnglish.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/StopwordsEnglish.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/StopwordsEnglish.java	(revision 10506)
@@ -0,0 +1,504 @@
+/*
+ *    StopwordsEnglish.java
+ *    Copyright (C) 2001 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import java.util.*;
+
+/**
+ * Class that can test whether a given string is a stop word.
+ * Lowercases all words before the test.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public class StopwordsEnglish extends Stopwords {
+  
+  /** The hashtable containing the list of stopwords */
+  private static Hashtable m_Stopwords = null;
+
+  static {
+   
+    if (m_Stopwords == null) {
+      m_Stopwords = new Hashtable();
+      Double dummy = new Double(0);
+      
+      m_Stopwords.put("a", dummy);
+      m_Stopwords.put("abaft", dummy);
+      m_Stopwords.put("aboard", dummy);
+      m_Stopwords.put("about", dummy);
+      m_Stopwords.put("above", dummy);
+      m_Stopwords.put("across", dummy);
+      m_Stopwords.put("afore", dummy);
+      m_Stopwords.put("aforesaid", dummy);
+      m_Stopwords.put("after", dummy);
+      m_Stopwords.put("again", dummy);
+      m_Stopwords.put("against", dummy);
+      m_Stopwords.put("agin", dummy);
+      m_Stopwords.put("ago", dummy);
+      m_Stopwords.put("aint", dummy);
+      m_Stopwords.put("albeit", dummy);
+      m_Stopwords.put("all", dummy);
+      m_Stopwords.put("almost", dummy);
+      m_Stopwords.put("alone", dummy);
+      m_Stopwords.put("along", dummy);
+      m_Stopwords.put("alongside", dummy);
+      m_Stopwords.put("already", dummy);
+      m_Stopwords.put("also", dummy);
+      m_Stopwords.put("although", dummy);
+      m_Stopwords.put("always", dummy);
+      m_Stopwords.put("am", dummy);
+      m_Stopwords.put("american", dummy);
+      m_Stopwords.put("amid", dummy);
+      m_Stopwords.put("amidst", dummy);
+      m_Stopwords.put("among", dummy);
+      m_Stopwords.put("amongst", dummy);
+      m_Stopwords.put("an", dummy);
+      m_Stopwords.put("and", dummy);
+      m_Stopwords.put("anent", dummy);
+      m_Stopwords.put("another", dummy);
+      m_Stopwords.put("any", dummy);
+      m_Stopwords.put("anybody", dummy);
+      m_Stopwords.put("anyone", dummy);
+      m_Stopwords.put("anything", dummy);
+      m_Stopwords.put("are", dummy);
+      m_Stopwords.put("aren't", dummy);
+      m_Stopwords.put("around", dummy);
+      m_Stopwords.put("as", dummy);
+      m_Stopwords.put("aslant", dummy);
+      m_Stopwords.put("astride", dummy);
+      m_Stopwords.put("at", dummy);
+      m_Stopwords.put("athwart", dummy);
+      m_Stopwords.put("away", dummy);
+      m_Stopwords.put("b", dummy);
+      m_Stopwords.put("back", dummy);
+      m_Stopwords.put("bar", dummy);
+      m_Stopwords.put("barring", dummy);
+      m_Stopwords.put("be", dummy);
+      m_Stopwords.put("because", dummy);
+      m_Stopwords.put("been", dummy);
+      m_Stopwords.put("before", dummy);
+      m_Stopwords.put("behind", dummy);
+      m_Stopwords.put("being", dummy);
+      m_Stopwords.put("below", dummy);
+      m_Stopwords.put("beneath", dummy);
+      m_Stopwords.put("beside", dummy);
+      m_Stopwords.put("besides", dummy);
+      m_Stopwords.put("best", dummy);
+      m_Stopwords.put("better", dummy);
+      m_Stopwords.put("between", dummy);
+      m_Stopwords.put("betwixt", dummy);
+      m_Stopwords.put("beyond", dummy);
+      m_Stopwords.put("both", dummy);
+      m_Stopwords.put("but", dummy);
+      m_Stopwords.put("by", dummy);
+      m_Stopwords.put("c", dummy);
+      m_Stopwords.put("can", dummy);
+      m_Stopwords.put("cannot", dummy);
+      m_Stopwords.put("can't", dummy);
+      m_Stopwords.put("certain", dummy);
+      m_Stopwords.put("circa", dummy);
+      m_Stopwords.put("close", dummy);
+      m_Stopwords.put("concerning", dummy);
+      m_Stopwords.put("considering", dummy);
+      m_Stopwords.put("cos", dummy);
+      m_Stopwords.put("could", dummy);
+      m_Stopwords.put("couldn't", dummy);
+      m_Stopwords.put("couldst", dummy);
+      m_Stopwords.put("d", dummy);
+      m_Stopwords.put("dare", dummy);
+      m_Stopwords.put("dared", dummy);
+      m_Stopwords.put("daren't", dummy);
+      m_Stopwords.put("dares", dummy);
+      m_Stopwords.put("daring", dummy);
+      m_Stopwords.put("despite", dummy);
+      m_Stopwords.put("did", dummy);
+      m_Stopwords.put("didn't", dummy);
+      m_Stopwords.put("different", dummy);
+      m_Stopwords.put("directly", dummy);
+      m_Stopwords.put("do", dummy);
+      m_Stopwords.put("does", dummy);
+      m_Stopwords.put("doesn't", dummy);
+      m_Stopwords.put("doing", dummy);
+      m_Stopwords.put("done", dummy);
+      m_Stopwords.put("don't", dummy);
+      m_Stopwords.put("dost", dummy);
+      m_Stopwords.put("doth", dummy);
+      m_Stopwords.put("down", dummy);
+      m_Stopwords.put("during", dummy);
+      m_Stopwords.put("durst", dummy);
+      m_Stopwords.put("e", dummy);
+      m_Stopwords.put("each", dummy);
+      m_Stopwords.put("early", dummy);
+      m_Stopwords.put("either", dummy);
+      m_Stopwords.put("em", dummy);
+      m_Stopwords.put("english", dummy);
+      m_Stopwords.put("enough", dummy);
+      m_Stopwords.put("ere", dummy);
+      m_Stopwords.put("even", dummy);
+      m_Stopwords.put("ever", dummy);
+      m_Stopwords.put("every", dummy);
+      m_Stopwords.put("everybody", dummy);
+      m_Stopwords.put("everyone", dummy);
+      m_Stopwords.put("everything", dummy);
+      m_Stopwords.put("except", dummy);
+      m_Stopwords.put("excepting", dummy);
+      m_Stopwords.put("f", dummy);
+      m_Stopwords.put("failing", dummy);
+      m_Stopwords.put("far", dummy);
+      m_Stopwords.put("few", dummy);
+      m_Stopwords.put("first", dummy);
+      m_Stopwords.put("five", dummy);
+      m_Stopwords.put("following", dummy);
+      m_Stopwords.put("for", dummy);
+      m_Stopwords.put("four", dummy);
+      m_Stopwords.put("from", dummy);
+      m_Stopwords.put("g", dummy);
+      m_Stopwords.put("gonna", dummy);
+      m_Stopwords.put("gotta", dummy);
+      m_Stopwords.put("h", dummy);
+      m_Stopwords.put("had", dummy);
+      m_Stopwords.put("hadn't", dummy);
+      m_Stopwords.put("hard", dummy);
+      m_Stopwords.put("has", dummy);
+      m_Stopwords.put("hasn't", dummy);
+      m_Stopwords.put("hast", dummy);
+      m_Stopwords.put("hath", dummy);
+      m_Stopwords.put("have", dummy);
+      m_Stopwords.put("haven't", dummy);
+      m_Stopwords.put("having", dummy);
+      m_Stopwords.put("he", dummy);
+      m_Stopwords.put("he'd", dummy);
+      m_Stopwords.put("he'll", dummy);
+      m_Stopwords.put("her", dummy);
+      m_Stopwords.put("here", dummy);
+      m_Stopwords.put("here's", dummy);
+      m_Stopwords.put("hers", dummy);
+      m_Stopwords.put("herself", dummy);
+      m_Stopwords.put("he's", dummy);
+      m_Stopwords.put("high", dummy);
+      m_Stopwords.put("him", dummy);
+      m_Stopwords.put("himself", dummy);
+      m_Stopwords.put("his", dummy);
+      m_Stopwords.put("home", dummy);
+      m_Stopwords.put("how", dummy);
+      m_Stopwords.put("howbeit", dummy);
+      m_Stopwords.put("however", dummy);
+      m_Stopwords.put("how's", dummy);
+      m_Stopwords.put("i", dummy);
+      m_Stopwords.put("id", dummy);
+      m_Stopwords.put("if", dummy);
+      m_Stopwords.put("ill", dummy);
+      m_Stopwords.put("i'm", dummy);
+      m_Stopwords.put("immediately", dummy);
+      m_Stopwords.put("important", dummy);
+      m_Stopwords.put("in", dummy);
+      m_Stopwords.put("inside", dummy);
+      m_Stopwords.put("instantly", dummy);
+      m_Stopwords.put("into", dummy);
+      m_Stopwords.put("is", dummy);
+      m_Stopwords.put("isn't", dummy);
+      m_Stopwords.put("it", dummy);
+      m_Stopwords.put("it'll", dummy);
+      m_Stopwords.put("it's", dummy);
+      m_Stopwords.put("its", dummy);
+      m_Stopwords.put("itself", dummy);
+      m_Stopwords.put("i've", dummy);
+      m_Stopwords.put("j", dummy);
+      m_Stopwords.put("just", dummy);
+      m_Stopwords.put("k", dummy);
+      m_Stopwords.put("l", dummy);
+      m_Stopwords.put("large", dummy);
+      m_Stopwords.put("last", dummy);
+      m_Stopwords.put("later", dummy);
+      m_Stopwords.put("least", dummy);
+      m_Stopwords.put("left", dummy);
+      m_Stopwords.put("less", dummy);
+      m_Stopwords.put("lest", dummy);
+      m_Stopwords.put("let's", dummy);
+      m_Stopwords.put("like", dummy);
+      m_Stopwords.put("likewise", dummy);
+      m_Stopwords.put("little", dummy);
+      m_Stopwords.put("living", dummy);
+      m_Stopwords.put("long", dummy);
+      m_Stopwords.put("m", dummy);
+      m_Stopwords.put("many", dummy);
+      m_Stopwords.put("may", dummy);
+      m_Stopwords.put("mayn't", dummy);
+      m_Stopwords.put("me", dummy);
+      m_Stopwords.put("mid", dummy);
+      m_Stopwords.put("midst", dummy);
+      m_Stopwords.put("might", dummy);
+      m_Stopwords.put("mightn't", dummy);
+      m_Stopwords.put("mine", dummy);
+      m_Stopwords.put("minus", dummy);
+      m_Stopwords.put("more", dummy);
+      m_Stopwords.put("most", dummy);
+      m_Stopwords.put("much", dummy);
+      m_Stopwords.put("must", dummy);
+      m_Stopwords.put("mustn't", dummy);
+      m_Stopwords.put("my", dummy);
+      m_Stopwords.put("myself", dummy);
+      m_Stopwords.put("n", dummy);
+      m_Stopwords.put("near", dummy);
+      m_Stopwords.put("'neath", dummy);
+      m_Stopwords.put("need", dummy);
+      m_Stopwords.put("needed", dummy);
+      m_Stopwords.put("needing", dummy);
+      m_Stopwords.put("needn't", dummy);
+      m_Stopwords.put("needs", dummy);
+      m_Stopwords.put("neither", dummy);
+      m_Stopwords.put("never", dummy);
+      m_Stopwords.put("nevertheless", dummy);
+      m_Stopwords.put("new", dummy);
+      m_Stopwords.put("next", dummy);
+      m_Stopwords.put("nigh", dummy);
+      m_Stopwords.put("nigher", dummy);
+      m_Stopwords.put("nighest", dummy);
+      m_Stopwords.put("nisi", dummy);
+      m_Stopwords.put("no", dummy);
+      m_Stopwords.put("no-one", dummy);
+      m_Stopwords.put("nobody", dummy);
+      m_Stopwords.put("none", dummy);
+      m_Stopwords.put("nor", dummy);
+      m_Stopwords.put("not", dummy);
+      m_Stopwords.put("nothing", dummy);
+      m_Stopwords.put("notwithstanding", dummy);
+      m_Stopwords.put("now", dummy);
+      m_Stopwords.put("o", dummy);
+      m_Stopwords.put("o'er", dummy);
+      m_Stopwords.put("of", dummy);
+      m_Stopwords.put("off", dummy);
+      m_Stopwords.put("often", dummy);
+      m_Stopwords.put("on", dummy);
+      m_Stopwords.put("once", dummy);
+      m_Stopwords.put("one", dummy);
+      m_Stopwords.put("oneself", dummy);
+      m_Stopwords.put("only", dummy);
+      m_Stopwords.put("onto", dummy);
+      m_Stopwords.put("open", dummy);
+      m_Stopwords.put("or", dummy);
+      m_Stopwords.put("other", dummy);
+      m_Stopwords.put("otherwise", dummy);
+      m_Stopwords.put("ought", dummy);
+      m_Stopwords.put("oughtn't", dummy);
+      m_Stopwords.put("our", dummy);
+      m_Stopwords.put("ours", dummy);
+      m_Stopwords.put("ourselves", dummy);
+      m_Stopwords.put("out", dummy);
+      m_Stopwords.put("outside", dummy);
+      m_Stopwords.put("over", dummy);
+      m_Stopwords.put("own", dummy);
+      m_Stopwords.put("p", dummy);
+      m_Stopwords.put("past", dummy);
+      m_Stopwords.put("pending", dummy);
+      m_Stopwords.put("per", dummy);
+      m_Stopwords.put("perhaps", dummy);
+      m_Stopwords.put("plus", dummy);
+      m_Stopwords.put("possible", dummy);
+      m_Stopwords.put("present", dummy);
+      m_Stopwords.put("probably", dummy);
+      m_Stopwords.put("provided", dummy);
+      m_Stopwords.put("providing", dummy);
+      m_Stopwords.put("public", dummy);
+      m_Stopwords.put("q", dummy);
+      m_Stopwords.put("qua", dummy);
+      m_Stopwords.put("quite", dummy);
+      m_Stopwords.put("r", dummy);
+      m_Stopwords.put("rather", dummy);
+      m_Stopwords.put("re", dummy);
+      m_Stopwords.put("real", dummy);
+      m_Stopwords.put("really", dummy);
+      m_Stopwords.put("respecting", dummy);
+      m_Stopwords.put("right", dummy);
+      m_Stopwords.put("round", dummy);
+      m_Stopwords.put("s", dummy);
+      m_Stopwords.put("same", dummy);
+      m_Stopwords.put("sans", dummy);
+      m_Stopwords.put("save", dummy);
+      m_Stopwords.put("saving", dummy);
+      m_Stopwords.put("second", dummy);
+      m_Stopwords.put("several", dummy);
+      m_Stopwords.put("shall", dummy);
+      m_Stopwords.put("shalt", dummy);
+      m_Stopwords.put("shan't", dummy);
+      m_Stopwords.put("she", dummy);
+      m_Stopwords.put("shed", dummy);
+      m_Stopwords.put("shell", dummy);
+      m_Stopwords.put("she's", dummy);
+      m_Stopwords.put("short", dummy);
+      m_Stopwords.put("should", dummy);
+      m_Stopwords.put("shouldn't", dummy);
+      m_Stopwords.put("since", dummy);
+      m_Stopwords.put("six", dummy);
+      m_Stopwords.put("small", dummy);
+      m_Stopwords.put("so", dummy);
+      m_Stopwords.put("some", dummy);
+      m_Stopwords.put("somebody", dummy);
+      m_Stopwords.put("someone", dummy);
+      m_Stopwords.put("something", dummy);
+      m_Stopwords.put("sometimes", dummy);
+      m_Stopwords.put("soon", dummy);
+      m_Stopwords.put("special", dummy);
+      m_Stopwords.put("still", dummy);
+      m_Stopwords.put("such", dummy);
+      m_Stopwords.put("summat", dummy);
+      m_Stopwords.put("supposing", dummy);
+      m_Stopwords.put("sure", dummy);
+      m_Stopwords.put("t", dummy);
+      m_Stopwords.put("than", dummy);
+      m_Stopwords.put("that", dummy);
+      m_Stopwords.put("that'd", dummy);
+      m_Stopwords.put("that'll", dummy);
+      m_Stopwords.put("that's", dummy);
+      m_Stopwords.put("the", dummy);
+      m_Stopwords.put("thee", dummy);
+      m_Stopwords.put("their", dummy);
+      m_Stopwords.put("theirs", dummy);
+      m_Stopwords.put("their's", dummy);
+      m_Stopwords.put("them", dummy);
+      m_Stopwords.put("themselves", dummy);
+      m_Stopwords.put("then", dummy);
+      m_Stopwords.put("there", dummy);
+      m_Stopwords.put("there's", dummy);
+      m_Stopwords.put("these", dummy);
+      m_Stopwords.put("they", dummy);
+      m_Stopwords.put("they'd", dummy);
+      m_Stopwords.put("they'll", dummy);
+      m_Stopwords.put("they're", dummy);
+      m_Stopwords.put("they've", dummy);
+      m_Stopwords.put("thine", dummy);
+      m_Stopwords.put("this", dummy);
+      m_Stopwords.put("tho", dummy);
+      m_Stopwords.put("those", dummy);
+      m_Stopwords.put("thou", dummy);
+      m_Stopwords.put("though", dummy);
+      m_Stopwords.put("three", dummy);
+      m_Stopwords.put("thro'", dummy);
+      m_Stopwords.put("through", dummy);
+      m_Stopwords.put("throughout", dummy);
+      m_Stopwords.put("thru", dummy);
+      m_Stopwords.put("thyself", dummy);
+      m_Stopwords.put("till", dummy);
+      m_Stopwords.put("to", dummy);
+      m_Stopwords.put("today", dummy);
+      m_Stopwords.put("together", dummy);
+      m_Stopwords.put("too", dummy);
+      m_Stopwords.put("touching", dummy);
+      m_Stopwords.put("toward", dummy);
+      m_Stopwords.put("towards", dummy);
+      m_Stopwords.put("true", dummy);
+      m_Stopwords.put("'twas", dummy);
+      m_Stopwords.put("'tween", dummy);
+      m_Stopwords.put("'twere", dummy);
+      m_Stopwords.put("'twill", dummy);
+      m_Stopwords.put("'twixt", dummy);
+      m_Stopwords.put("two", dummy);
+      m_Stopwords.put("'twould", dummy);
+      m_Stopwords.put("u", dummy);
+      m_Stopwords.put("under", dummy);
+      m_Stopwords.put("underneath", dummy);
+      m_Stopwords.put("unless", dummy);
+      m_Stopwords.put("unlike", dummy);
+      m_Stopwords.put("until", dummy);
+      m_Stopwords.put("unto", dummy);
+      m_Stopwords.put("up", dummy);
+      m_Stopwords.put("upon", dummy);
+      m_Stopwords.put("us", dummy);
+      m_Stopwords.put("used", dummy);
+      m_Stopwords.put("usually", dummy);
+      m_Stopwords.put("v", dummy);
+      m_Stopwords.put("versus", dummy);
+      m_Stopwords.put("very", dummy);
+      m_Stopwords.put("via", dummy);
+      m_Stopwords.put("vice", dummy);
+      m_Stopwords.put("vis-a-vis", dummy);
+      m_Stopwords.put("w", dummy);
+      m_Stopwords.put("wanna", dummy);
+      m_Stopwords.put("wanting", dummy);
+      m_Stopwords.put("was", dummy);
+      m_Stopwords.put("wasn't", dummy);
+      m_Stopwords.put("way", dummy);
+      m_Stopwords.put("we", dummy);
+      m_Stopwords.put("we'd", dummy);
+      m_Stopwords.put("well", dummy);
+      m_Stopwords.put("were", dummy);
+      m_Stopwords.put("weren't", dummy);
+      m_Stopwords.put("wert", dummy);
+      m_Stopwords.put("we've", dummy);
+      m_Stopwords.put("what", dummy);
+      m_Stopwords.put("whatever", dummy);
+      m_Stopwords.put("what'll", dummy);
+      m_Stopwords.put("what's", dummy);
+      m_Stopwords.put("when", dummy);
+      m_Stopwords.put("whencesoever", dummy);
+      m_Stopwords.put("whenever", dummy);
+      m_Stopwords.put("when's", dummy);
+      m_Stopwords.put("whereas", dummy);
+      m_Stopwords.put("where's", dummy);
+      m_Stopwords.put("whether", dummy);
+      m_Stopwords.put("which", dummy);
+      m_Stopwords.put("whichever", dummy);
+      m_Stopwords.put("whichsoever", dummy);
+      m_Stopwords.put("while", dummy);
+      m_Stopwords.put("whilst", dummy);
+      m_Stopwords.put("who", dummy);
+      m_Stopwords.put("who'd", dummy);
+      m_Stopwords.put("whoever", dummy);
+      m_Stopwords.put("whole", dummy);
+      m_Stopwords.put("who'll", dummy);
+      m_Stopwords.put("whom", dummy);
+      m_Stopwords.put("whore", dummy);
+      m_Stopwords.put("who's", dummy);
+      m_Stopwords.put("whose", dummy);
+      m_Stopwords.put("whoso", dummy);
+      m_Stopwords.put("whosoever", dummy);
+      m_Stopwords.put("will", dummy);
+      m_Stopwords.put("with", dummy);
+      m_Stopwords.put("within", dummy);
+      m_Stopwords.put("without", dummy);
+      m_Stopwords.put("wont", dummy);
+      m_Stopwords.put("would", dummy);
+      m_Stopwords.put("wouldn't", dummy);
+      m_Stopwords.put("wouldst", dummy);
+      m_Stopwords.put("x", dummy);
+      m_Stopwords.put("y", dummy);
+      m_Stopwords.put("ye", dummy);
+      m_Stopwords.put("yet", dummy);
+      m_Stopwords.put("you", dummy);
+      m_Stopwords.put("you'd", dummy);
+      m_Stopwords.put("you'll", dummy);
+      m_Stopwords.put("your", dummy);
+      m_Stopwords.put("you're", dummy);
+      m_Stopwords.put("yours", dummy);
+      m_Stopwords.put("yourself", dummy);
+      m_Stopwords.put("yourselves", dummy);
+      m_Stopwords.put("you've", dummy);
+      m_Stopwords.put("z", dummy);
+    }
+  }
+  
+  /** 
+   * Returns true if the given string is a stop word.
+   */
+  public boolean isStopword(String str) {
+
+    return m_Stopwords.containsKey(str.toLowerCase());
+  }
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/StopwordsGerman.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/StopwordsGerman.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/StopwordsGerman.java	(revision 10506)
@@ -0,0 +1,330 @@
+/*
+ *    StopwordsGerman.java
+ *    Copyright (C) 2001 Eibe Frank
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+import java.util.*;
+
+/**
+ * Class that can test whether a given string is a stop word.
+ * Lowercases all words before the test.
+ *
+ * This list of German stop words has been obtained from
+ * http://snowball.tartarus.org/german/stop.txt
+ *
+ * But I have deleted/changed some words that I haven't seen before.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version 1.0
+ */
+public class StopwordsGerman extends Stopwords {
+  
+  /** The hashtable containing the list of stopwords */
+  private static Hashtable m_Stopwords = null;
+
+  static {
+   
+    if (m_Stopwords == null) {
+      m_Stopwords = new Hashtable();
+      Double dummy = new Double(0);
+
+      m_Stopwords.put("aber", dummy);
+
+      m_Stopwords.put("alle", dummy);
+      m_Stopwords.put("allem", dummy);
+      m_Stopwords.put("allen", dummy);
+      m_Stopwords.put("aller", dummy);
+      m_Stopwords.put("alles", dummy);
+
+      m_Stopwords.put("als", dummy);
+      m_Stopwords.put("also", dummy);
+      m_Stopwords.put("am", dummy);
+      m_Stopwords.put("an", dummy);
+
+      m_Stopwords.put("ander", dummy);
+      m_Stopwords.put("andere", dummy);
+      m_Stopwords.put("anderem", dummy);
+      m_Stopwords.put("anderen", dummy);
+      m_Stopwords.put("anderer", dummy);
+      m_Stopwords.put("anderes", dummy);
+      m_Stopwords.put("anderm", dummy);
+      m_Stopwords.put("andern", dummy);
+      m_Stopwords.put("anders", dummy);
+
+      m_Stopwords.put("auch", dummy);
+      m_Stopwords.put("auf", dummy);
+      m_Stopwords.put("aus", dummy);
+      m_Stopwords.put("bei", dummy);
+      m_Stopwords.put("bin", dummy);
+      m_Stopwords.put("bis", dummy);
+      m_Stopwords.put("bist", dummy);
+      m_Stopwords.put("da", dummy);
+      m_Stopwords.put("damit", dummy);
+      m_Stopwords.put("dann", dummy);
+      
+      m_Stopwords.put("der", dummy);
+      m_Stopwords.put("den", dummy);
+      m_Stopwords.put("des", dummy);
+      m_Stopwords.put("dem", dummy);
+      m_Stopwords.put("die", dummy);
+      m_Stopwords.put("das", dummy);
+
+      m_Stopwords.put("da\u00df", dummy);
+
+      m_Stopwords.put("derselbe", dummy);
+      m_Stopwords.put("derselben", dummy);
+      m_Stopwords.put("denselben", dummy);
+      m_Stopwords.put("desselben", dummy);
+      m_Stopwords.put("demselben", dummy);
+      m_Stopwords.put("dieselbe", dummy);
+      m_Stopwords.put("dieselben", dummy);
+      m_Stopwords.put("dasselbe", dummy);
+
+      m_Stopwords.put("dazu", dummy);
+
+      m_Stopwords.put("dein", dummy);
+      m_Stopwords.put("deine", dummy);
+      m_Stopwords.put("deinem", dummy);
+      m_Stopwords.put("deinen", dummy);
+      m_Stopwords.put("deiner", dummy);
+      m_Stopwords.put("deines", dummy);
+
+      m_Stopwords.put("denn", dummy);
+      
+      m_Stopwords.put("derer", dummy);
+      m_Stopwords.put("dessen", dummy);
+      
+      m_Stopwords.put("dich", dummy);
+      m_Stopwords.put("dir", dummy);
+      m_Stopwords.put("du", dummy);
+
+      m_Stopwords.put("dies", dummy);
+      m_Stopwords.put("diese", dummy);
+      m_Stopwords.put("diesem", dummy);
+      m_Stopwords.put("diesen", dummy);
+      m_Stopwords.put("dieser", dummy);
+      m_Stopwords.put("dieses", dummy);
+
+      m_Stopwords.put("doch", dummy);
+      m_Stopwords.put("dort", dummy);
+
+      m_Stopwords.put("durch", dummy);
+
+      m_Stopwords.put("ein", dummy);
+      m_Stopwords.put("eine", dummy);
+      m_Stopwords.put("einem", dummy);
+      m_Stopwords.put("einen", dummy);
+      m_Stopwords.put("einer", dummy);
+      m_Stopwords.put("eines", dummy);
+
+      m_Stopwords.put("einig", dummy);
+      m_Stopwords.put("einige", dummy);
+      m_Stopwords.put("einigem", dummy);
+      m_Stopwords.put("einigen", dummy);
+      m_Stopwords.put("einiger", dummy);
+      m_Stopwords.put("einiges", dummy);
+
+      m_Stopwords.put("einmal", dummy);
+
+      m_Stopwords.put("er", dummy);
+      m_Stopwords.put("ihn", dummy);
+      m_Stopwords.put("ihm", dummy);
+
+      m_Stopwords.put("es", dummy);
+      m_Stopwords.put("etwas", dummy);
+
+      m_Stopwords.put("euer", dummy);
+      m_Stopwords.put("eure", dummy);
+      m_Stopwords.put("eurem", dummy);
+      m_Stopwords.put("euren", dummy);
+      m_Stopwords.put("eurer", dummy);
+      m_Stopwords.put("eures", dummy);
+
+      m_Stopwords.put("f\u00fcr", dummy);
+      m_Stopwords.put("gegen", dummy);
+      m_Stopwords.put("gewesen", dummy);
+      m_Stopwords.put("hab", dummy);
+      m_Stopwords.put("habe", dummy);
+      m_Stopwords.put("haben", dummy);
+      m_Stopwords.put("hat", dummy);
+      m_Stopwords.put("hatte", dummy);
+      m_Stopwords.put("hatten", dummy);
+      m_Stopwords.put("hier", dummy);
+      m_Stopwords.put("hin", dummy);
+      m_Stopwords.put("hinter", dummy);
+      
+      m_Stopwords.put("ich", dummy);
+      m_Stopwords.put("mich", dummy);
+      m_Stopwords.put("mir", dummy);
+
+      m_Stopwords.put("ihr", dummy);
+      m_Stopwords.put("ihre", dummy);
+      m_Stopwords.put("ihrem", dummy);
+      m_Stopwords.put("ihren", dummy);
+      m_Stopwords.put("ihrer", dummy);
+      m_Stopwords.put("ihres", dummy);
+      m_Stopwords.put("euch", dummy);
+
+      m_Stopwords.put("im", dummy);
+      m_Stopwords.put("in", dummy);
+      m_Stopwords.put("indem", dummy);
+      m_Stopwords.put("ins", dummy);
+      m_Stopwords.put("ist", dummy);
+
+      m_Stopwords.put("jede", dummy);
+      m_Stopwords.put("jedem", dummy);
+      m_Stopwords.put("jeden", dummy);
+      m_Stopwords.put("jeder", dummy);
+      m_Stopwords.put("jedes", dummy);
+
+      m_Stopwords.put("jene", dummy);
+      m_Stopwords.put("jenem", dummy);
+      m_Stopwords.put("jenen", dummy);
+      m_Stopwords.put("jener", dummy);
+      m_Stopwords.put("jenes", dummy);
+
+      m_Stopwords.put("jetzt", dummy);
+      m_Stopwords.put("kann", dummy);
+
+      m_Stopwords.put("kein", dummy);
+      m_Stopwords.put("keine", dummy);
+      m_Stopwords.put("keinem", dummy);
+      m_Stopwords.put("keinen", dummy);
+      m_Stopwords.put("keiner", dummy);
+      m_Stopwords.put("keines", dummy);
+
+      m_Stopwords.put("k\u00f6nnen", dummy);
+      m_Stopwords.put("k\u00f6nnte", dummy);
+      m_Stopwords.put("machen", dummy);
+      m_Stopwords.put("man", dummy);
+
+      m_Stopwords.put("manche", dummy);
+      m_Stopwords.put("manchem", dummy);
+      m_Stopwords.put("manchen", dummy);
+      m_Stopwords.put("mancher", dummy);
+      m_Stopwords.put("manches", dummy);
+
+      m_Stopwords.put("mein", dummy);
+      m_Stopwords.put("meine", dummy);
+      m_Stopwords.put("meinem", dummy);
+      m_Stopwords.put("meinen", dummy);
+      m_Stopwords.put("meiner", dummy);
+      m_Stopwords.put("meines", dummy);
+
+      m_Stopwords.put("mit", dummy);
+      m_Stopwords.put("muss", dummy);
+      m_Stopwords.put("musste", dummy);
+      m_Stopwords.put("nach", dummy);
+      m_Stopwords.put("nicht", dummy);
+      m_Stopwords.put("nichts", dummy);
+      m_Stopwords.put("noch", dummy);
+      m_Stopwords.put("nun", dummy);
+      m_Stopwords.put("nur", dummy);
+      m_Stopwords.put("ob", dummy);
+      m_Stopwords.put("oder", dummy);
+      m_Stopwords.put("ohne", dummy);
+      m_Stopwords.put("sehr", dummy);
+
+      m_Stopwords.put("sein", dummy);
+      m_Stopwords.put("seine", dummy);
+      m_Stopwords.put("seinem", dummy);
+      m_Stopwords.put("seinen", dummy);
+      m_Stopwords.put("seiner", dummy);
+      m_Stopwords.put("seines", dummy);
+
+      m_Stopwords.put("selbst", dummy);
+      m_Stopwords.put("sich", dummy);
+      
+      m_Stopwords.put("sie", dummy);
+      m_Stopwords.put("ihnen", dummy);
+
+      m_Stopwords.put("sind", dummy);
+      m_Stopwords.put("so", dummy);
+
+      m_Stopwords.put("solche", dummy);
+      m_Stopwords.put("solchem", dummy);
+      m_Stopwords.put("solchen", dummy);
+      m_Stopwords.put("solcher", dummy);
+      m_Stopwords.put("solches", dummy);
+
+      m_Stopwords.put("soll", dummy);
+      m_Stopwords.put("sollte", dummy);
+      m_Stopwords.put("sondern", dummy);
+      m_Stopwords.put("sonst", dummy);
+      m_Stopwords.put("\00fcber", dummy);
+      m_Stopwords.put("um", dummy);
+      m_Stopwords.put("und", dummy);
+
+      m_Stopwords.put("uns", dummy);
+      m_Stopwords.put("unser", dummy);
+      m_Stopwords.put("unserem", dummy);
+      m_Stopwords.put("unseren", dummy);
+      m_Stopwords.put("unsere", dummy);
+      m_Stopwords.put("unseres", dummy);
+
+      m_Stopwords.put("unter", dummy);
+      m_Stopwords.put("viel", dummy);
+      m_Stopwords.put("vom", dummy);
+      m_Stopwords.put("von", dummy);
+      m_Stopwords.put("vor", dummy);
+      m_Stopwords.put("w\u00e4hrend", dummy);
+      m_Stopwords.put("war", dummy);
+      m_Stopwords.put("waren", dummy);
+      m_Stopwords.put("warst", dummy);
+      m_Stopwords.put("was", dummy);
+      m_Stopwords.put("weg", dummy);
+      m_Stopwords.put("weil", dummy);
+      m_Stopwords.put("weiter", dummy);
+
+      m_Stopwords.put("welche", dummy);
+      m_Stopwords.put("welchem", dummy);
+      m_Stopwords.put("welchen", dummy);
+      m_Stopwords.put("welcher", dummy);
+      m_Stopwords.put("welches", dummy);
+
+      m_Stopwords.put("wenn", dummy);
+      m_Stopwords.put("werde", dummy);
+      m_Stopwords.put("werden", dummy);
+      m_Stopwords.put("wie", dummy);
+      m_Stopwords.put("wieder", dummy);
+      m_Stopwords.put("will", dummy);
+      m_Stopwords.put("wir", dummy);
+      m_Stopwords.put("wird", dummy);
+      m_Stopwords.put("wirst", dummy);
+      m_Stopwords.put("wo", dummy);
+      m_Stopwords.put("wollen", dummy);
+      m_Stopwords.put("wollte", dummy);
+      m_Stopwords.put("w\u00fcrde", dummy);
+      m_Stopwords.put("w\u00fcrden", dummy);
+      m_Stopwords.put("zu", dummy);
+      m_Stopwords.put("zum", dummy);
+      m_Stopwords.put("zur", dummy);
+      m_Stopwords.put("zwar", dummy);
+      m_Stopwords.put("zwischen", dummy);
+    }
+  }
+  
+  /** 
+   * Returns true if the given string is a stop word.
+   */
+  public boolean isStopword(String str) {
+
+    return m_Stopwords.containsKey(str.toLowerCase());
+  }
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/Counter.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/Counter.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/Counter.html	(revision 10506)
@@ -0,0 +1,318 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:48 NZDT 2004 -->
+<TITLE>
+Counter
+</TITLE>
+<META NAME="keywords" CONTENT="Counter,Counter class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="Counter";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV CLASS&nbsp;
+&nbsp;<A HREF="GermanStemmer.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="Counter.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class Counter</H2>
+<PRE>
+java.lang.Object
+  |
+  +--<B>Counter</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>java.io.Serializable</DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>Counter</B><DT>extends java.lang.Object<DT>implements java.io.Serializable</DL>
+
+<P>
+Class that implements a simple counter.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="Counter">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="Counter.html#Counter()">Counter</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Initializes the counter to 1</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="Counter.html#Counter(int)">Counter</A></B>(int&nbsp;val)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Initializes the counter to the given value</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="Counter.html#increment()">increment</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Increments the counter.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="Counter.html#toString()">toString</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns string containing value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="Counter.html#value()">value</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gets the value.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="Counter()"><!-- --></A><H3>
+Counter</H3>
+<PRE>
+public <B>Counter</B>()</PRE>
+<DL>
+<DD>Initializes the counter to 1
+<P>
+</DL>
+<HR>
+
+<A NAME="Counter(int)"><!-- --></A><H3>
+Counter</H3>
+<PRE>
+public <B>Counter</B>(int&nbsp;val)</PRE>
+<DL>
+<DD>Initializes the counter to the given value
+<P>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="increment()"><!-- --></A><H3>
+increment</H3>
+<PRE>
+public void <B>increment</B>()</PRE>
+<DL>
+<DD>Increments the counter.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="value()"><!-- --></A><H3>
+value</H3>
+<PRE>
+public int <B>value</B>()</PRE>
+<DL>
+<DD>Gets the value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>the value</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="toString()"><!-- --></A><H3>
+toString</H3>
+<PRE>
+public java.lang.String <B>toString</B>()</PRE>
+<DL>
+<DD>Returns string containing value.
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>toString</CODE> in class <CODE>java.lang.Object</CODE></DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV CLASS&nbsp;
+&nbsp;<A HREF="GermanStemmer.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="Counter.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/GermanStemmer.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/GermanStemmer.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/GermanStemmer.html	(revision 10506)
@@ -0,0 +1,268 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:49 NZDT 2004 -->
+<TITLE>
+GermanStemmer
+</TITLE>
+<META NAME="keywords" CONTENT="GermanStemmer,GermanStemmer class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="GermanStemmer";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="Counter.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="IteratedLovinsStemmer.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="GermanStemmer.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class GermanStemmer</H2>
+<PRE>
+java.lang.Object
+  |
+  +--<A HREF="Stemmer.html">Stemmer</A>
+        |
+        +--<B>GermanStemmer</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>java.io.Serializable</DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>GermanStemmer</B><DT>extends <A HREF="Stemmer.html">Stemmer</A></DL>
+
+<P>
+A stemmer for German words. The algorithm is based on the report
+ "A Fast and Simple Stemming Algorithm for German Words" by Jörg
+ Caumanns (joerg.caumanns@isst.fhg.de).
+
+ Changed stem() from protected to public.
+ Changed coding for umlaute to unicode.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="GermanStemmer">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="GermanStemmer.html#GermanStemmer()">GermanStemmer</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="GermanStemmer.html#stem(java.lang.String)">stem</A></B>(java.lang.String&nbsp;term)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stemms the given term to an unique <tt>discriminator</tt>.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_Stemmer"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class <A HREF="Stemmer.html">Stemmer</A></B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><A HREF="Stemmer.html#stemString(java.lang.String)">stemString</A></CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="GermanStemmer()"><!-- --></A><H3>
+GermanStemmer</H3>
+<PRE>
+public <B>GermanStemmer</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="stem(java.lang.String)"><!-- --></A><H3>
+stem</H3>
+<PRE>
+public java.lang.String <B>stem</B>(java.lang.String&nbsp;term)</PRE>
+<DL>
+<DD>Stemms the given term to an unique <tt>discriminator</tt>.
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE><A HREF="Stemmer.html#stem(java.lang.String)">stem</A></CODE> in class <CODE><A HREF="Stemmer.html">Stemmer</A></CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>term</CODE> - The term that should be stemmed.
+<DT><B>Returns:</B><DD>Discriminator for <tt>term</tt></DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="Counter.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="IteratedLovinsStemmer.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="GermanStemmer.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/IteratedLovinsStemmer.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/IteratedLovinsStemmer.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/IteratedLovinsStemmer.html	(revision 10506)
@@ -0,0 +1,285 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:49 NZDT 2004 -->
+<TITLE>
+IteratedLovinsStemmer
+</TITLE>
+<META NAME="keywords" CONTENT="IteratedLovinsStemmer,IteratedLovinsStemmer class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="IteratedLovinsStemmer";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="GermanStemmer.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="KEAFilter.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="IteratedLovinsStemmer.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class IteratedLovinsStemmer</H2>
+<PRE>
+java.lang.Object
+  |
+  +--<A HREF="Stemmer.html">Stemmer</A>
+        |
+        +--<A HREF="LovinsStemmer.html">LovinsStemmer</A>
+              |
+              +--<B>IteratedLovinsStemmer</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>java.io.Serializable</DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>IteratedLovinsStemmer</B><DT>extends <A HREF="LovinsStemmer.html">LovinsStemmer</A></DL>
+
+<P>
+Implements the iterated version of the Lovins stemmer.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="IteratedLovinsStemmer">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="IteratedLovinsStemmer.html#IteratedLovinsStemmer()">IteratedLovinsStemmer</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="IteratedLovinsStemmer.html#main(java.lang.String[])">main</A></B>(java.lang.String[]&nbsp;ops)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stems text coming into stdin and writes it to stdout.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="IteratedLovinsStemmer.html#stem(java.lang.String)">stem</A></B>(java.lang.String&nbsp;str)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Iterated stemming of the given word.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_Stemmer"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class <A HREF="Stemmer.html">Stemmer</A></B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><A HREF="Stemmer.html#stemString(java.lang.String)">stemString</A></CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="IteratedLovinsStemmer()"><!-- --></A><H3>
+IteratedLovinsStemmer</H3>
+<PRE>
+public <B>IteratedLovinsStemmer</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="stem(java.lang.String)"><!-- --></A><H3>
+stem</H3>
+<PRE>
+public java.lang.String <B>stem</B>(java.lang.String&nbsp;str)</PRE>
+<DL>
+<DD>Iterated stemming of the given word.
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE><A HREF="LovinsStemmer.html#stem(java.lang.String)">stem</A></CODE> in class <CODE><A HREF="LovinsStemmer.html">LovinsStemmer</A></CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>str</CODE> - a string consisting of a single word</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="main(java.lang.String[])"><!-- --></A><H3>
+main</H3>
+<PRE>
+public static void <B>main</B>(java.lang.String[]&nbsp;ops)</PRE>
+<DL>
+<DD>Stems text coming into stdin and writes it to stdout.
+<P>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="GermanStemmer.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="KEAFilter.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="IteratedLovinsStemmer.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAFilter.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAFilter.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAFilter.html	(revision 10506)
@@ -0,0 +1,1147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:49 NZDT 2004 -->
+<TITLE>
+KEAFilter
+</TITLE>
+<META NAME="keywords" CONTENT="KEAFilter,KEAFilter class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="KEAFilter";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="IteratedLovinsStemmer.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="KEAKeyphraseExtractor.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="KEAFilter.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#fields_inherited_from_class_weka.filters.Filter">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class KEAFilter</H2>
+<PRE>
+java.lang.Object
+  |
+  +--weka.filters.Filter
+        |
+        +--<B>KEAFilter</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>weka.core.OptionHandler, java.io.Serializable</DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>KEAFilter</B><DT>extends weka.filters.Filter<DT>implements weka.core.OptionHandler</DL>
+
+<P>
+This filter converts the incoming data into data appropriate for
+ keyphrase classification. It assumes that the dataset contains two
+ string attributes. The first attribute should contain the text of a
+ document. The second attribute should contain the keyphrases
+ associated with that document (if present). 
+
+ The filter converts every instance (i.e. document) into a set of
+ instances, one for each word-based n-gram in the document. The
+ string attribute representing the document is replaced by some
+ numeric features, the estimated probability of each n-gram being a
+ keyphrase, and the rank of this phrase in the document according to
+ the probability.  Each new instances also has a class value
+ associated with it. The class is "true" if the n-gram is a true
+ keyphrase, and "false" otherwise. Of course, if the input document
+ doesn't come with author-assigned keyphrases, the class values for
+ that document will be missing.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="KEAFilter">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Field Summary</B></FONT></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="fields_inherited_from_class_weka.filters.Filter"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Fields inherited from class weka.filters.Filter</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>m_NewBatch</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="KEAFilter.html#KEAFilter()">KEAFilter</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#batchFinished()">batchFinished</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Signify that this batch of input to the filter is finished.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getCheckForProperNouns()">getCheckForProperNouns</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the M_CheckProperNouns value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getDebug()">getDebug</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of Debug.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getDisallowInternalPeriods()">getDisallowInternalPeriods</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get whether the supplied columns are to be processed</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getDocumentAtt()">getDocumentAtt</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of DocumentAtt.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getKeyphrasesAtt()">getKeyphrasesAtt</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of KeyphraseAtt.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getKFused()">getKFused</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gets whether keyphrase frequency attribute is used.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getMaxPhraseLength()">getMaxPhraseLength</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of MaxPhraseLength.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getMinNumOccur()">getMinNumOccur</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of MinNumOccur.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getMinPhraseLength()">getMinPhraseLength</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of MinPhraseLength.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String[]</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getOptions()">getOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gets the current settings of the filter.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getProbabilityIndex()">getProbabilityIndex</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns the index of the phrases' probabilities in the output ARFF file.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getRankIndex()">getRankIndex</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns the index of the phrases' ranks in the output ARFF file.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getStemmedPhraseIndex()">getStemmedPhraseIndex</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns the index of the stemmed phrases in the output ARFF file.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;Stemmer</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getStemmer()">getStemmer</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the Stemmer value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;Stopwords</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getStopwords()">getStopwords</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the M_Stopwords value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#getUnstemmedPhraseIndex()">getUnstemmedPhraseIndex</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns the index of the unstemmed phrases in the output ARFF file.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#globalInfo()">globalInfo</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns a string describing this filter</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#input(weka.core.Instance)">input</A></B>(weka.core.Instance&nbsp;instance)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input an instance for filtering.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Enumeration</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#listOptions()">listOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns an enumeration describing the available options</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#main(java.lang.String[])">main</A></B>(java.lang.String[]&nbsp;argv)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Main method for testing this class.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setCheckForProperNouns(boolean)">setCheckForProperNouns</A></B>(boolean&nbsp;newM_CheckProperNouns)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the M_CheckProperNouns value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setDebug(boolean)">setDebug</A></B>(boolean&nbsp;newDebug)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of Debug.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setDisallowInternalPeriods(boolean)">setDisallowInternalPeriods</A></B>(boolean&nbsp;disallow)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set whether selected columns should be processed.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setDocumentAtt(int)">setDocumentAtt</A></B>(int&nbsp;newDocumentAtt)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of DocumentAtt.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setInputFormat(weka.core.Instances)">setInputFormat</A></B>(weka.core.Instances&nbsp;instanceInfo)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the format of the input instances.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setKeyphrasesAtt(int)">setKeyphrasesAtt</A></B>(int&nbsp;newKeyphrasesAtt)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of KeyphrasesAtt.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setKFused(boolean)">setKFused</A></B>(boolean&nbsp;flag)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets whether keyphrase frequency attribute is used.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setMaxPhraseLength(int)">setMaxPhraseLength</A></B>(int&nbsp;newMaxPhraseLength)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of MaxPhraseLength.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setMinNumOccur(int)">setMinNumOccur</A></B>(int&nbsp;newMinNumOccur)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of MinNumOccur.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setMinPhraseLength(int)">setMinPhraseLength</A></B>(int&nbsp;newMinPhraseLength)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of MinPhraseLength.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setOptions(java.lang.String[])">setOptions</A></B>(java.lang.String[]&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parses a given list of options controlling the behaviour of this object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setStemmer(Stemmer)">setStemmer</A></B>(Stemmer&nbsp;newStemmer)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the Stemmer value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAFilter.html#setStopwords(Stopwords)">setStopwords</A></B>(Stopwords&nbsp;newM_Stopwords)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the M_Stopwords value.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_weka.filters.Filter"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class weka.filters.Filter</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>batchFilterFile, bufferInput, copyStringValues, copyStringValues, filterFile, flushInput, getInputFormat, getInputStringIndex, getOutputFormat, getOutputStringIndex, getStringIndices, inputFormat, isOutputFormatDefined, numPendingOutput, output, outputFormat, outputFormatPeek, outputPeek, push, resetQueue, setOutputFormat, useFilter</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="KEAFilter()"><!-- --></A><H3>
+KEAFilter</H3>
+<PRE>
+public <B>KEAFilter</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="getCheckForProperNouns()"><!-- --></A><H3>
+getCheckForProperNouns</H3>
+<PRE>
+public boolean <B>getCheckForProperNouns</B>()</PRE>
+<DL>
+<DD>Get the M_CheckProperNouns value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>the M_CheckProperNouns value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setCheckForProperNouns(boolean)"><!-- --></A><H3>
+setCheckForProperNouns</H3>
+<PRE>
+public void <B>setCheckForProperNouns</B>(boolean&nbsp;newM_CheckProperNouns)</PRE>
+<DL>
+<DD>Set the M_CheckProperNouns value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newM_CheckProperNouns</CODE> - The new M_CheckProperNouns value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getStopwords()"><!-- --></A><H3>
+getStopwords</H3>
+<PRE>
+public Stopwords <B>getStopwords</B>()</PRE>
+<DL>
+<DD>Get the M_Stopwords value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>the M_Stopwords value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setStopwords(Stopwords)"><!-- --></A><H3>
+setStopwords</H3>
+<PRE>
+public void <B>setStopwords</B>(Stopwords&nbsp;newM_Stopwords)</PRE>
+<DL>
+<DD>Set the M_Stopwords value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newM_Stopwords</CODE> - The new M_Stopwords value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getStemmer()"><!-- --></A><H3>
+getStemmer</H3>
+<PRE>
+public Stemmer <B>getStemmer</B>()</PRE>
+<DL>
+<DD>Get the Stemmer value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>the Stemmer value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setStemmer(Stemmer)"><!-- --></A><H3>
+setStemmer</H3>
+<PRE>
+public void <B>setStemmer</B>(Stemmer&nbsp;newStemmer)</PRE>
+<DL>
+<DD>Set the Stemmer value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newStemmer</CODE> - The new Stemmer value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMinNumOccur()"><!-- --></A><H3>
+getMinNumOccur</H3>
+<PRE>
+public int <B>getMinNumOccur</B>()</PRE>
+<DL>
+<DD>Get the value of MinNumOccur.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of MinNumOccur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setMinNumOccur(int)"><!-- --></A><H3>
+setMinNumOccur</H3>
+<PRE>
+public void <B>setMinNumOccur</B>(int&nbsp;newMinNumOccur)</PRE>
+<DL>
+<DD>Set the value of MinNumOccur.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newMinNumOccur</CODE> - Value to assign to MinNumOccur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMaxPhraseLength()"><!-- --></A><H3>
+getMaxPhraseLength</H3>
+<PRE>
+public int <B>getMaxPhraseLength</B>()</PRE>
+<DL>
+<DD>Get the value of MaxPhraseLength.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of MaxPhraseLength.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setMaxPhraseLength(int)"><!-- --></A><H3>
+setMaxPhraseLength</H3>
+<PRE>
+public void <B>setMaxPhraseLength</B>(int&nbsp;newMaxPhraseLength)</PRE>
+<DL>
+<DD>Set the value of MaxPhraseLength.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newMaxPhraseLength</CODE> - Value to assign to MaxPhraseLength.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMinPhraseLength()"><!-- --></A><H3>
+getMinPhraseLength</H3>
+<PRE>
+public int <B>getMinPhraseLength</B>()</PRE>
+<DL>
+<DD>Get the value of MinPhraseLength.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of MinPhraseLength.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setMinPhraseLength(int)"><!-- --></A><H3>
+setMinPhraseLength</H3>
+<PRE>
+public void <B>setMinPhraseLength</B>(int&nbsp;newMinPhraseLength)</PRE>
+<DL>
+<DD>Set the value of MinPhraseLength.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newMinPhraseLength</CODE> - Value to assign to MinPhraseLength.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getStemmedPhraseIndex()"><!-- --></A><H3>
+getStemmedPhraseIndex</H3>
+<PRE>
+public int <B>getStemmedPhraseIndex</B>()</PRE>
+<DL>
+<DD>Returns the index of the stemmed phrases in the output ARFF file.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getUnstemmedPhraseIndex()"><!-- --></A><H3>
+getUnstemmedPhraseIndex</H3>
+<PRE>
+public int <B>getUnstemmedPhraseIndex</B>()</PRE>
+<DL>
+<DD>Returns the index of the unstemmed phrases in the output ARFF file.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getProbabilityIndex()"><!-- --></A><H3>
+getProbabilityIndex</H3>
+<PRE>
+public int <B>getProbabilityIndex</B>()</PRE>
+<DL>
+<DD>Returns the index of the phrases' probabilities in the output ARFF file.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getRankIndex()"><!-- --></A><H3>
+getRankIndex</H3>
+<PRE>
+public int <B>getRankIndex</B>()</PRE>
+<DL>
+<DD>Returns the index of the phrases' ranks in the output ARFF file.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getDocumentAtt()"><!-- --></A><H3>
+getDocumentAtt</H3>
+<PRE>
+public int <B>getDocumentAtt</B>()</PRE>
+<DL>
+<DD>Get the value of DocumentAtt.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of DocumentAtt.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setDocumentAtt(int)"><!-- --></A><H3>
+setDocumentAtt</H3>
+<PRE>
+public void <B>setDocumentAtt</B>(int&nbsp;newDocumentAtt)</PRE>
+<DL>
+<DD>Set the value of DocumentAtt.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newDocumentAtt</CODE> - Value to assign to DocumentAtt.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getKeyphrasesAtt()"><!-- --></A><H3>
+getKeyphrasesAtt</H3>
+<PRE>
+public int <B>getKeyphrasesAtt</B>()</PRE>
+<DL>
+<DD>Get the value of KeyphraseAtt.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of KeyphraseAtt.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setKeyphrasesAtt(int)"><!-- --></A><H3>
+setKeyphrasesAtt</H3>
+<PRE>
+public void <B>setKeyphrasesAtt</B>(int&nbsp;newKeyphrasesAtt)</PRE>
+<DL>
+<DD>Set the value of KeyphrasesAtt.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newKeyphrasesAtt</CODE> - Value to assign to KeyphrasesAtt.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getDebug()"><!-- --></A><H3>
+getDebug</H3>
+<PRE>
+public boolean <B>getDebug</B>()</PRE>
+<DL>
+<DD>Get the value of Debug.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of Debug.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setDebug(boolean)"><!-- --></A><H3>
+setDebug</H3>
+<PRE>
+public void <B>setDebug</B>(boolean&nbsp;newDebug)</PRE>
+<DL>
+<DD>Set the value of Debug.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newDebug</CODE> - Value to assign to Debug.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setKFused(boolean)"><!-- --></A><H3>
+setKFused</H3>
+<PRE>
+public void <B>setKFused</B>(boolean&nbsp;flag)</PRE>
+<DL>
+<DD>Sets whether keyphrase frequency attribute is used.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getKFused()"><!-- --></A><H3>
+getKFused</H3>
+<PRE>
+public boolean <B>getKFused</B>()</PRE>
+<DL>
+<DD>Gets whether keyphrase frequency attribute is used.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getDisallowInternalPeriods()"><!-- --></A><H3>
+getDisallowInternalPeriods</H3>
+<PRE>
+public boolean <B>getDisallowInternalPeriods</B>()</PRE>
+<DL>
+<DD>Get whether the supplied columns are to be processed
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>true if the supplied columns won't be processed</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setDisallowInternalPeriods(boolean)"><!-- --></A><H3>
+setDisallowInternalPeriods</H3>
+<PRE>
+public void <B>setDisallowInternalPeriods</B>(boolean&nbsp;disallow)</PRE>
+<DL>
+<DD>Set whether selected columns should be processed. If true the 
+ selected columns won't be processed.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setOptions(java.lang.String[])"><!-- --></A><H3>
+setOptions</H3>
+<PRE>
+public void <B>setOptions</B>(java.lang.String[]&nbsp;options)
+                throws java.lang.Exception</PRE>
+<DL>
+<DD>Parses a given list of options controlling the behaviour of this object.
+ Valid options are:<p>
+
+ -K<br>
+ Specifies whether keyphrase frequency statistic is used.<p>
+
+ -M length<br>
+ Sets the maximum phrase length (default: 3).<p>
+
+ -L length<br>
+ Sets the minimum phrase length (default: 1).<p>
+
+ -D<br>
+ Turns debugging mode on.<p>
+
+ -I index<br>
+ Sets the index of the attribute containing the documents (default: 0).<p>
+
+ -J index<br>
+ Sets the index of the attribute containing the keyphrases (default: 1).<p>
+
+ -P<br>
+ Disallow internal periods <p>
+
+ -O number<br>
+ The minimum number of times a phrase needs to occur (default: 2). <p>
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>setOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - the list of options as an array of strings
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.Exception</CODE> - if an option is not supported</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getOptions()"><!-- --></A><H3>
+getOptions</H3>
+<PRE>
+public java.lang.String[] <B>getOptions</B>()</PRE>
+<DL>
+<DD>Gets the current settings of the filter.
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>getOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>an array of strings suitable for passing to setOptions</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="listOptions()"><!-- --></A><H3>
+listOptions</H3>
+<PRE>
+public java.util.Enumeration <B>listOptions</B>()</PRE>
+<DL>
+<DD>Returns an enumeration describing the available options
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>listOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>an enumeration of all the available options</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="globalInfo()"><!-- --></A><H3>
+globalInfo</H3>
+<PRE>
+public java.lang.String <B>globalInfo</B>()</PRE>
+<DL>
+<DD>Returns a string describing this filter
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>a description of the filter suitable for
+ displaying in the explorer/experimenter gui</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setInputFormat(weka.core.Instances)"><!-- --></A><H3>
+setInputFormat</H3>
+<PRE>
+public boolean <B>setInputFormat</B>(weka.core.Instances&nbsp;instanceInfo)
+                       throws java.lang.Exception</PRE>
+<DL>
+<DD>Sets the format of the input instances.
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>setInputFormat</CODE> in class <CODE>weka.filters.Filter</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>instanceInfo</CODE> - an Instances object containing the input
+ instance structure (any instances contained in the object are
+ ignored - only the structure is required).
+<DT><B>Returns:</B><DD>true if the outputFormat may be collected immediately
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="input(weka.core.Instance)"><!-- --></A><H3>
+input</H3>
+<PRE>
+public boolean <B>input</B>(weka.core.Instance&nbsp;instance)
+              throws java.lang.Exception</PRE>
+<DL>
+<DD>Input an instance for filtering. Ordinarily the instance is processed
+ and made available for output immediately. Some filters require all
+ instances be read before producing output.
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>input</CODE> in class <CODE>weka.filters.Filter</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>instance</CODE> - the input instance
+<DT><B>Returns:</B><DD>true if the filtered instance may now be
+ collected with output().
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.Exception</CODE> - if the input instance was not of the correct 
+ format or if there was a problem with the filtering.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="batchFinished()"><!-- --></A><H3>
+batchFinished</H3>
+<PRE>
+public boolean <B>batchFinished</B>()
+                      throws java.lang.Exception</PRE>
+<DL>
+<DD>Signify that this batch of input to the filter is finished. 
+ If the filter requires all instances prior to filtering,
+ output() may now be called to retrieve the filtered instances.
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>batchFinished</CODE> in class <CODE>weka.filters.Filter</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>true if there are instances pending output
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.Exception</CODE> - if no input structure has been defined</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="main(java.lang.String[])"><!-- --></A><H3>
+main</H3>
+<PRE>
+public static void <B>main</B>(java.lang.String[]&nbsp;argv)</PRE>
+<DL>
+<DD>Main method for testing this class.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>argv</CODE> - should contain arguments to the filter: use -h for help</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="IteratedLovinsStemmer.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="KEAKeyphraseExtractor.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="KEAFilter.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#fields_inherited_from_class_weka.filters.Filter">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAKeyphraseExtractor.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAKeyphraseExtractor.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAKeyphraseExtractor.html	(revision 10506)
@@ -0,0 +1,742 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:49 NZDT 2004 -->
+<TITLE>
+KEAKeyphraseExtractor
+</TITLE>
+<META NAME="keywords" CONTENT="KEAKeyphraseExtractor,KEAKeyphraseExtractor class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="KEAKeyphraseExtractor";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="KEAFilter.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="KEAModelBuilder.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="KEAKeyphraseExtractor.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class KEAKeyphraseExtractor</H2>
+<PRE>
+java.lang.Object
+  |
+  +--<B>KEAKeyphraseExtractor</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>weka.core.OptionHandler</DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>KEAKeyphraseExtractor</B><DT>extends java.lang.Object<DT>implements weka.core.OptionHandler</DL>
+
+<P>
+Extracts keyphrases from the documents in a given directory.
+ Assumes that the file names for the documents end with ".txt".
+ Puts extracted keyphrases into corresponding files ending with
+ ".key" (if those are not already present). Optionally an encoding
+ for the documents/keyphrases can be defined (e.g. for Chinese
+ text). Documents for which ".key" exists, are used for evaluation.
+
+ Valid options are:<p>
+
+ -l "directory name"<br>
+ Specifies name of directory.<p>
+
+ -m "model name"<br>
+ Specifies name of model.<p>
+
+ -e "encoding"<br>
+ Specifies encoding.<p>
+
+ -n <br>
+ Specifies number of phrases to be output (default: 5).<p>
+
+ -d<br>
+ Turns debugging mode on.<p>
+
+ -a<br>
+ Also write stemmed phrase and score into ".key" file.<p>
+<P>
+
+<P>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#KEAKeyphraseExtractor()">KEAKeyphraseExtractor</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Hashtable</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#collectStems()">collectStems</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collects the stems of the file names.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#extractKeyphrases(java.util.Hashtable)">extractKeyphrases</A></B>(java.util.Hashtable&nbsp;stems)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Builds the model from the files</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#getAdditionalInfo()">getAdditionalInfo</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of AdditionalInfo.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#getDebug()">getDebug</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of debug.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#getDirName()">getDirName</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of dirName.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#getEncoding()">getEncoding</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of encoding.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#getModelName()">getModelName</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of modelName.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#getNumPhrases()">getNumPhrases</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of numPhrases.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String[]</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#getOptions()">getOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gets the current option settings.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Enumeration</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#listOptions()">listOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns an enumeration describing the available options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#loadModel()">loadModel</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Loads the extraction model from the file.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#main(java.lang.String[])">main</A></B>(java.lang.String[]&nbsp;ops)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The main method.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#setAdditionalInfo(boolean)">setAdditionalInfo</A></B>(boolean&nbsp;newAdditionalInfo)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of AdditionalInfo.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#setDebug(boolean)">setDebug</A></B>(boolean&nbsp;newdebug)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of debug.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#setDirName(java.lang.String)">setDirName</A></B>(java.lang.String&nbsp;newdirName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of dirName.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#setEncoding(java.lang.String)">setEncoding</A></B>(java.lang.String&nbsp;newencoding)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of encoding.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#setModelName(java.lang.String)">setModelName</A></B>(java.lang.String&nbsp;newmodelName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of modelName.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#setNumPhrases(int)">setNumPhrases</A></B>(int&nbsp;newnumPhrases)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of numPhrases.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAKeyphraseExtractor.html#setOptions(java.lang.String[])">setOptions</A></B>(java.lang.String[]&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parses a given list of options controlling the behaviour of this object.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="KEAKeyphraseExtractor()"><!-- --></A><H3>
+KEAKeyphraseExtractor</H3>
+<PRE>
+public <B>KEAKeyphraseExtractor</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="getAdditionalInfo()"><!-- --></A><H3>
+getAdditionalInfo</H3>
+<PRE>
+public boolean <B>getAdditionalInfo</B>()</PRE>
+<DL>
+<DD>Get the value of AdditionalInfo.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of AdditionalInfo.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setAdditionalInfo(boolean)"><!-- --></A><H3>
+setAdditionalInfo</H3>
+<PRE>
+public void <B>setAdditionalInfo</B>(boolean&nbsp;newAdditionalInfo)</PRE>
+<DL>
+<DD>Set the value of AdditionalInfo.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newAdditionalInfo</CODE> - Value to assign to AdditionalInfo.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getNumPhrases()"><!-- --></A><H3>
+getNumPhrases</H3>
+<PRE>
+public int <B>getNumPhrases</B>()</PRE>
+<DL>
+<DD>Get the value of numPhrases.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of numPhrases.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setNumPhrases(int)"><!-- --></A><H3>
+setNumPhrases</H3>
+<PRE>
+public void <B>setNumPhrases</B>(int&nbsp;newnumPhrases)</PRE>
+<DL>
+<DD>Set the value of numPhrases.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newnumPhrases</CODE> - Value to assign to numPhrases.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getDebug()"><!-- --></A><H3>
+getDebug</H3>
+<PRE>
+public boolean <B>getDebug</B>()</PRE>
+<DL>
+<DD>Get the value of debug.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of debug.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setDebug(boolean)"><!-- --></A><H3>
+setDebug</H3>
+<PRE>
+public void <B>setDebug</B>(boolean&nbsp;newdebug)</PRE>
+<DL>
+<DD>Set the value of debug.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newdebug</CODE> - Value to assign to debug.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getEncoding()"><!-- --></A><H3>
+getEncoding</H3>
+<PRE>
+public java.lang.String <B>getEncoding</B>()</PRE>
+<DL>
+<DD>Get the value of encoding.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of encoding.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setEncoding(java.lang.String)"><!-- --></A><H3>
+setEncoding</H3>
+<PRE>
+public void <B>setEncoding</B>(java.lang.String&nbsp;newencoding)</PRE>
+<DL>
+<DD>Set the value of encoding.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newencoding</CODE> - Value to assign to encoding.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getModelName()"><!-- --></A><H3>
+getModelName</H3>
+<PRE>
+public java.lang.String <B>getModelName</B>()</PRE>
+<DL>
+<DD>Get the value of modelName.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of modelName.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setModelName(java.lang.String)"><!-- --></A><H3>
+setModelName</H3>
+<PRE>
+public void <B>setModelName</B>(java.lang.String&nbsp;newmodelName)</PRE>
+<DL>
+<DD>Set the value of modelName.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newmodelName</CODE> - Value to assign to modelName.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getDirName()"><!-- --></A><H3>
+getDirName</H3>
+<PRE>
+public java.lang.String <B>getDirName</B>()</PRE>
+<DL>
+<DD>Get the value of dirName.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of dirName.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setDirName(java.lang.String)"><!-- --></A><H3>
+setDirName</H3>
+<PRE>
+public void <B>setDirName</B>(java.lang.String&nbsp;newdirName)</PRE>
+<DL>
+<DD>Set the value of dirName.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newdirName</CODE> - Value to assign to dirName.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setOptions(java.lang.String[])"><!-- --></A><H3>
+setOptions</H3>
+<PRE>
+public void <B>setOptions</B>(java.lang.String[]&nbsp;options)
+                throws java.lang.Exception</PRE>
+<DL>
+<DD>Parses a given list of options controlling the behaviour of this object.
+ Valid options are:<p>
+
+ -l "directory name"<br>
+ Specifies name of directory.<p>
+
+ -m "model name"<br>
+ Specifies name of model.<p>
+
+ -e "encoding"<br>
+ Specifies encoding.<p>
+
+ -n<br>
+ Specifies number of phrases to be output (default: 5).<p>
+
+ -d<br>
+ Turns debugging mode on.<p>
+
+ -a<br>
+ Also write stemmed phrase and score into ".key" file.<p>
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>setOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - the list of options as an array of strings
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.Exception</CODE> - if an option is not supported</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getOptions()"><!-- --></A><H3>
+getOptions</H3>
+<PRE>
+public java.lang.String[] <B>getOptions</B>()</PRE>
+<DL>
+<DD>Gets the current option settings.
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>getOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>an array of strings suitable for passing to setOptions</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="listOptions()"><!-- --></A><H3>
+listOptions</H3>
+<PRE>
+public java.util.Enumeration <B>listOptions</B>()</PRE>
+<DL>
+<DD>Returns an enumeration describing the available options.
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>listOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>an enumeration of all the available options</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="collectStems()"><!-- --></A><H3>
+collectStems</H3>
+<PRE>
+public java.util.Hashtable <B>collectStems</B>()
+                                 throws java.lang.Exception</PRE>
+<DL>
+<DD>Collects the stems of the file names.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="extractKeyphrases(java.util.Hashtable)"><!-- --></A><H3>
+extractKeyphrases</H3>
+<PRE>
+public void <B>extractKeyphrases</B>(java.util.Hashtable&nbsp;stems)
+                       throws java.lang.Exception</PRE>
+<DL>
+<DD>Builds the model from the files
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="loadModel()"><!-- --></A><H3>
+loadModel</H3>
+<PRE>
+public void <B>loadModel</B>()
+               throws java.lang.Exception</PRE>
+<DL>
+<DD>Loads the extraction model from the file.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="main(java.lang.String[])"><!-- --></A><H3>
+main</H3>
+<PRE>
+public static void <B>main</B>(java.lang.String[]&nbsp;ops)</PRE>
+<DL>
+<DD>The main method.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="KEAFilter.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="KEAModelBuilder.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="KEAKeyphraseExtractor.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAModelBuilder.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAModelBuilder.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAModelBuilder.html	(revision 10506)
@@ -0,0 +1,1072 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:49 NZDT 2004 -->
+<TITLE>
+KEAModelBuilder
+</TITLE>
+<META NAME="keywords" CONTENT="KEAModelBuilder,KEAModelBuilder class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="KEAModelBuilder";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="KEAKeyphraseExtractor.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="KEAPhraseFilter.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="KEAModelBuilder.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class KEAModelBuilder</H2>
+<PRE>
+java.lang.Object
+  |
+  +--<B>KEAModelBuilder</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>weka.core.OptionHandler</DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>KEAModelBuilder</B><DT>extends java.lang.Object<DT>implements weka.core.OptionHandler</DL>
+
+<P>
+Builds a keyphrase extraction model from the documents in a given
+ directory.  Assumes that the file names for the documents end with
+ ".txt".  Assumes that files containing corresponding
+ author-assigned keyphrases end with ".key". Optionally an encoding
+ for the documents/keyphrases can be defined (e.g. for Chinese
+ text).
+
+ Valid options are:<p>
+
+ -l "directory name"<br>
+ Specifies name of directory.<p>
+
+ -m "model name"<br>
+ Specifies name of model.<p>
+
+ -e "encoding"<br>
+ Specifies encoding.<p>
+
+ -d<br>
+ Turns debugging mode on.<p>
+
+ -k<br>
+ Use keyphrase frequency statistic.<p>
+
+ -p<br>
+ Disallow internal periods.<p>
+
+ -x "length"<br>
+ Sets maximum phrase length (default: 3).<p>
+
+ -y "length"<br>
+ Sets minimum phrase length (default: 1).<p>
+
+ -o "number"<br>
+ The minimum number of times a phrase needs to occur (default: 2). <p>
+
+ -s "name of class implementing list of stop words"<br>
+ Sets list of stop words to used (default: StopwordsEnglish).<p>
+
+ -t "name of class implementing stemmer"<br>
+ Sets stemmer to use (default: IteratedLovinsStemmer). <p>
+
+ -n<br>
+ Do not check for proper nouns. <p>
+<P>
+
+<P>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="KEAModelBuilder.html#KEAModelBuilder()">KEAModelBuilder</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#buildModel(java.util.Hashtable)">buildModel</A></B>(java.util.Hashtable&nbsp;stems)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Builds the model from the files</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Hashtable</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#collectStems()">collectStems</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collects the stems of the file names.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getCheckForProperNouns()">getCheckForProperNouns</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the M_CheckProperNouns value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getDebug()">getDebug</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of debug.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getDirName()">getDirName</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of dirName.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getDisallowIPeriods()">getDisallowIPeriods</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of disallowIPeriods.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getEncoding()">getEncoding</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of encoding.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getMaxPhraseLength()">getMaxPhraseLength</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of MaxPhraseLength.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getMinNumOccur()">getMinNumOccur</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of MinNumOccur.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;int</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getMinPhraseLength()">getMinPhraseLength</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of MinPhraseLength.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getModelName()">getModelName</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of modelName.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String[]</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getOptions()">getOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gets the current option settings.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;Stemmer</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getStemmer()">getStemmer</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the Stemmer value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;Stopwords</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getStopwords()">getStopwords</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the M_Stopwords value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#getUseKFrequency()">getUseKFrequency</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the value of useKFrequency.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Enumeration</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#listOptions()">listOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns an enumeration describing the available options.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#main(java.lang.String[])">main</A></B>(java.lang.String[]&nbsp;ops)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The main method.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#saveModel()">saveModel</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Saves the extraction model to the file.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setCheckForProperNouns(boolean)">setCheckForProperNouns</A></B>(boolean&nbsp;newM_CheckProperNouns)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the M_CheckProperNouns value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setDebug(boolean)">setDebug</A></B>(boolean&nbsp;newdebug)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of debug.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setDirName(java.lang.String)">setDirName</A></B>(java.lang.String&nbsp;newdirName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of dirName.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setDisallowIPeriods(boolean)">setDisallowIPeriods</A></B>(boolean&nbsp;newdisallowIPeriods)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of disallowIPeriods.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setEncoding(java.lang.String)">setEncoding</A></B>(java.lang.String&nbsp;newencoding)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of encoding.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setMaxPhraseLength(int)">setMaxPhraseLength</A></B>(int&nbsp;newMaxPhraseLength)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of MaxPhraseLength.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setMinNumOccur(int)">setMinNumOccur</A></B>(int&nbsp;newMinNumOccur)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of MinNumOccur.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setMinPhraseLength(int)">setMinPhraseLength</A></B>(int&nbsp;newMinPhraseLength)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of MinPhraseLength.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setModelName(java.lang.String)">setModelName</A></B>(java.lang.String&nbsp;newmodelName)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of modelName.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setOptions(java.lang.String[])">setOptions</A></B>(java.lang.String[]&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parses a given list of options controlling the behaviour of this object.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setStemmer(Stemmer)">setStemmer</A></B>(Stemmer&nbsp;newStemmer)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the Stemmer value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setStopwords(Stopwords)">setStopwords</A></B>(Stopwords&nbsp;newM_Stopwords)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the M_Stopwords value.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAModelBuilder.html#setUseKFrequency(boolean)">setUseKFrequency</A></B>(boolean&nbsp;newuseKFrequency)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set the value of useKFrequency.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="KEAModelBuilder()"><!-- --></A><H3>
+KEAModelBuilder</H3>
+<PRE>
+public <B>KEAModelBuilder</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="getCheckForProperNouns()"><!-- --></A><H3>
+getCheckForProperNouns</H3>
+<PRE>
+public boolean <B>getCheckForProperNouns</B>()</PRE>
+<DL>
+<DD>Get the M_CheckProperNouns value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>the M_CheckProperNouns value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setCheckForProperNouns(boolean)"><!-- --></A><H3>
+setCheckForProperNouns</H3>
+<PRE>
+public void <B>setCheckForProperNouns</B>(boolean&nbsp;newM_CheckProperNouns)</PRE>
+<DL>
+<DD>Set the M_CheckProperNouns value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newM_CheckProperNouns</CODE> - The new M_CheckProperNouns value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getStopwords()"><!-- --></A><H3>
+getStopwords</H3>
+<PRE>
+public Stopwords <B>getStopwords</B>()</PRE>
+<DL>
+<DD>Get the M_Stopwords value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>the M_Stopwords value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setStopwords(Stopwords)"><!-- --></A><H3>
+setStopwords</H3>
+<PRE>
+public void <B>setStopwords</B>(Stopwords&nbsp;newM_Stopwords)</PRE>
+<DL>
+<DD>Set the M_Stopwords value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newM_Stopwords</CODE> - The new M_Stopwords value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getStemmer()"><!-- --></A><H3>
+getStemmer</H3>
+<PRE>
+public Stemmer <B>getStemmer</B>()</PRE>
+<DL>
+<DD>Get the Stemmer value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>the Stemmer value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setStemmer(Stemmer)"><!-- --></A><H3>
+setStemmer</H3>
+<PRE>
+public void <B>setStemmer</B>(Stemmer&nbsp;newStemmer)</PRE>
+<DL>
+<DD>Set the Stemmer value.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newStemmer</CODE> - The new Stemmer value.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMinNumOccur()"><!-- --></A><H3>
+getMinNumOccur</H3>
+<PRE>
+public int <B>getMinNumOccur</B>()</PRE>
+<DL>
+<DD>Get the value of MinNumOccur.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of MinNumOccur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setMinNumOccur(int)"><!-- --></A><H3>
+setMinNumOccur</H3>
+<PRE>
+public void <B>setMinNumOccur</B>(int&nbsp;newMinNumOccur)</PRE>
+<DL>
+<DD>Set the value of MinNumOccur.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newMinNumOccur</CODE> - Value to assign to MinNumOccur.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMaxPhraseLength()"><!-- --></A><H3>
+getMaxPhraseLength</H3>
+<PRE>
+public int <B>getMaxPhraseLength</B>()</PRE>
+<DL>
+<DD>Get the value of MaxPhraseLength.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of MaxPhraseLength.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setMaxPhraseLength(int)"><!-- --></A><H3>
+setMaxPhraseLength</H3>
+<PRE>
+public void <B>setMaxPhraseLength</B>(int&nbsp;newMaxPhraseLength)</PRE>
+<DL>
+<DD>Set the value of MaxPhraseLength.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newMaxPhraseLength</CODE> - Value to assign to MaxPhraseLength.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getMinPhraseLength()"><!-- --></A><H3>
+getMinPhraseLength</H3>
+<PRE>
+public int <B>getMinPhraseLength</B>()</PRE>
+<DL>
+<DD>Get the value of MinPhraseLength.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of MinPhraseLength.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setMinPhraseLength(int)"><!-- --></A><H3>
+setMinPhraseLength</H3>
+<PRE>
+public void <B>setMinPhraseLength</B>(int&nbsp;newMinPhraseLength)</PRE>
+<DL>
+<DD>Set the value of MinPhraseLength.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newMinPhraseLength</CODE> - Value to assign to MinPhraseLength.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getDisallowIPeriods()"><!-- --></A><H3>
+getDisallowIPeriods</H3>
+<PRE>
+public boolean <B>getDisallowIPeriods</B>()</PRE>
+<DL>
+<DD>Get the value of disallowIPeriods.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of disallowIPeriods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setDisallowIPeriods(boolean)"><!-- --></A><H3>
+setDisallowIPeriods</H3>
+<PRE>
+public void <B>setDisallowIPeriods</B>(boolean&nbsp;newdisallowIPeriods)</PRE>
+<DL>
+<DD>Set the value of disallowIPeriods.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newdisallowIPeriods</CODE> - Value to assign to disallowIPeriods.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getUseKFrequency()"><!-- --></A><H3>
+getUseKFrequency</H3>
+<PRE>
+public boolean <B>getUseKFrequency</B>()</PRE>
+<DL>
+<DD>Get the value of useKFrequency.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of useKFrequency.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setUseKFrequency(boolean)"><!-- --></A><H3>
+setUseKFrequency</H3>
+<PRE>
+public void <B>setUseKFrequency</B>(boolean&nbsp;newuseKFrequency)</PRE>
+<DL>
+<DD>Set the value of useKFrequency.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newuseKFrequency</CODE> - Value to assign to useKFrequency.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getDebug()"><!-- --></A><H3>
+getDebug</H3>
+<PRE>
+public boolean <B>getDebug</B>()</PRE>
+<DL>
+<DD>Get the value of debug.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of debug.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setDebug(boolean)"><!-- --></A><H3>
+setDebug</H3>
+<PRE>
+public void <B>setDebug</B>(boolean&nbsp;newdebug)</PRE>
+<DL>
+<DD>Set the value of debug.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newdebug</CODE> - Value to assign to debug.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getEncoding()"><!-- --></A><H3>
+getEncoding</H3>
+<PRE>
+public java.lang.String <B>getEncoding</B>()</PRE>
+<DL>
+<DD>Get the value of encoding.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of encoding.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setEncoding(java.lang.String)"><!-- --></A><H3>
+setEncoding</H3>
+<PRE>
+public void <B>setEncoding</B>(java.lang.String&nbsp;newencoding)</PRE>
+<DL>
+<DD>Set the value of encoding.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newencoding</CODE> - Value to assign to encoding.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getModelName()"><!-- --></A><H3>
+getModelName</H3>
+<PRE>
+public java.lang.String <B>getModelName</B>()</PRE>
+<DL>
+<DD>Get the value of modelName.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of modelName.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setModelName(java.lang.String)"><!-- --></A><H3>
+setModelName</H3>
+<PRE>
+public void <B>setModelName</B>(java.lang.String&nbsp;newmodelName)</PRE>
+<DL>
+<DD>Set the value of modelName.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newmodelName</CODE> - Value to assign to modelName.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getDirName()"><!-- --></A><H3>
+getDirName</H3>
+<PRE>
+public java.lang.String <B>getDirName</B>()</PRE>
+<DL>
+<DD>Get the value of dirName.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>Value of dirName.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setDirName(java.lang.String)"><!-- --></A><H3>
+setDirName</H3>
+<PRE>
+public void <B>setDirName</B>(java.lang.String&nbsp;newdirName)</PRE>
+<DL>
+<DD>Set the value of dirName.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>newdirName</CODE> - Value to assign to dirName.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setOptions(java.lang.String[])"><!-- --></A><H3>
+setOptions</H3>
+<PRE>
+public void <B>setOptions</B>(java.lang.String[]&nbsp;options)
+                throws java.lang.Exception</PRE>
+<DL>
+<DD>Parses a given list of options controlling the behaviour of this object.
+ Valid options are:<p>
+
+ -l "directory name" <br>
+ Specifies name of directory.<p>
+
+ -m "model name" <br>
+ Specifies name of model.<p>
+
+ -e "encoding" <br>
+ Specifies encoding.<p>
+
+ -d<br>
+ Turns debugging mode on.<p>
+
+ -k<br>
+ Use keyphrase frequency statistic.<p>
+
+ -p<br>
+ Disallow internal periods. <p>
+
+ -x "length"<br>
+ Sets maximum phrase length (default: 3).<p>
+
+ -y "length"<br>
+ Sets minimum phrase length (default: 3).<p>
+
+ -o "number"<br>
+ The minimum number of times a phrase needs to occur (default: 2). <p>
+
+ -s "name of class implementing list of stop words"<br>
+ Sets list of stop words to used (default: StopwordsEnglish).<p>
+
+ -t "name of class implementing stemmer"<br>
+ Sets stemmer to use (default: IteratedLovinsStemmer). <p>
+
+ -n<br>
+ Do not check for proper nouns. <p>
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>setOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - the list of options as an array of strings
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.Exception</CODE> - if an option is not supported</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getOptions()"><!-- --></A><H3>
+getOptions</H3>
+<PRE>
+public java.lang.String[] <B>getOptions</B>()</PRE>
+<DL>
+<DD>Gets the current option settings.
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>getOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>an array of strings suitable for passing to setOptions</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="listOptions()"><!-- --></A><H3>
+listOptions</H3>
+<PRE>
+public java.util.Enumeration <B>listOptions</B>()</PRE>
+<DL>
+<DD>Returns an enumeration describing the available options.
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>listOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>an enumeration of all the available options</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="collectStems()"><!-- --></A><H3>
+collectStems</H3>
+<PRE>
+public java.util.Hashtable <B>collectStems</B>()
+                                 throws java.lang.Exception</PRE>
+<DL>
+<DD>Collects the stems of the file names.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="buildModel(java.util.Hashtable)"><!-- --></A><H3>
+buildModel</H3>
+<PRE>
+public void <B>buildModel</B>(java.util.Hashtable&nbsp;stems)
+                throws java.lang.Exception</PRE>
+<DL>
+<DD>Builds the model from the files
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="saveModel()"><!-- --></A><H3>
+saveModel</H3>
+<PRE>
+public void <B>saveModel</B>()
+               throws java.lang.Exception</PRE>
+<DL>
+<DD>Saves the extraction model to the file.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="main(java.lang.String[])"><!-- --></A><H3>
+main</H3>
+<PRE>
+public static void <B>main</B>(java.lang.String[]&nbsp;ops)</PRE>
+<DL>
+<DD>The main method.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="KEAKeyphraseExtractor.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="KEAPhraseFilter.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="KEAModelBuilder.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAPhraseFilter.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAPhraseFilter.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/KEAPhraseFilter.html	(revision 10506)
@@ -0,0 +1,817 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:49 NZDT 2004 -->
+<TITLE>
+KEAPhraseFilter
+</TITLE>
+<META NAME="keywords" CONTENT="KEAPhraseFilter,KEAPhraseFilter class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="KEAPhraseFilter";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="KEAModelBuilder.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="LovinsStemmer.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="KEAPhraseFilter.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class KEAPhraseFilter</H2>
+<PRE>
+java.lang.Object
+  |
+  +--weka.filters.Filter
+        |
+        +--<B>KEAPhraseFilter</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>weka.core.OptionHandler, java.io.Serializable</DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>KEAPhraseFilter</B><DT>extends weka.filters.Filter<DT>implements weka.core.OptionHandler</DL>
+
+<P>
+This filter splits the text in selected string
+ attributes into phrases. The resulting
+ string attributes contain these phrases
+ separated by '\n' characters.
+
+ Phrases are identified according to the
+ following definitions:
+ 
+ A phrase is a sequence of words interrupted
+ only by sequences of whitespace characters,
+ where each sequence of whitespace characters
+ contains at most one '\n'.
+
+ A word is a sequence of letters or digits
+ that contains at least one letter, with
+ the following exceptions:
+
+ a) '.', '@', '_', '&', '/', '-' are allowed
+ if surrounded by letters or digits,
+
+ b) '\'' is allowed if preceeded by a letter
+ or digit,
+ 
+ c) '-', '/' are also allowed if succeeded by
+ whitespace characters followed by another
+ word. In that case the whitespace characters
+ will be deleted.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="KEAPhraseFilter">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Field Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>protected &nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#m_DisallowInternalPeriods">m_DisallowInternalPeriods</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Determines whether internal periods are allowed</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>protected &nbsp;weka.core.Range</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#m_SelectCols">m_SelectCols</A></B></CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stores which columns to select as a funky range</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="fields_inherited_from_class_weka.filters.Filter"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Fields inherited from class weka.filters.Filter</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>m_NewBatch</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#KEAPhraseFilter()">KEAPhraseFilter</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#attributeIndicesTipText()">attributeIndicesTipText</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns the tip text for this property</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#batchFinished()">batchFinished</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Signify that this batch of input to the filter is finished.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#disallowInternalPeriodsTipText()">disallowInternalPeriodsTipText</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns the tip text for this property</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#getAttributeIndices()">getAttributeIndices</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get the current range selection.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#getDisallowInternalPeriods()">getDisallowInternalPeriods</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get whether the supplied columns are to be processed</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#getInvertSelection()">getInvertSelection</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get whether the supplied columns are to be processed</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String[]</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#getOptions()">getOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Gets the current settings of the filter.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#globalInfo()">globalInfo</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns a string describing this filter</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#input(weka.core.Instance)">input</A></B>(weka.core.Instance&nbsp;instance)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input an instance for filtering.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#invertSelectionTipText()">invertSelectionTipText</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns the tip text for this property</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.util.Enumeration</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#listOptions()">listOptions</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns an enumeration describing the available options</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#main(java.lang.String[])">main</A></B>(java.lang.String[]&nbsp;argv)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Main method for testing this class.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#setAttributeIndices(java.lang.String)">setAttributeIndices</A></B>(java.lang.String&nbsp;rangeList)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set which attributes are to be processed</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#setAttributeIndicesArray(int[])">setAttributeIndicesArray</A></B>(int[]&nbsp;attributes)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set which attributes are to be processed</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#setDisallowInternalPeriods(boolean)">setDisallowInternalPeriods</A></B>(boolean&nbsp;disallow)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set whether selected columns should be processed.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#setInputFormat(weka.core.Instances)">setInputFormat</A></B>(weka.core.Instances&nbsp;instanceInfo)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the format of the input instances.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#setInvertSelection(boolean)">setInvertSelection</A></B>(boolean&nbsp;invert)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Set whether selected columns should be processed.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="KEAPhraseFilter.html#setOptions(java.lang.String[])">setOptions</A></B>(java.lang.String[]&nbsp;options)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Parses a given list of options controlling the behaviour of this object.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_weka.filters.Filter"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class weka.filters.Filter</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>batchFilterFile, bufferInput, copyStringValues, copyStringValues, filterFile, flushInput, getInputFormat, getInputStringIndex, getOutputFormat, getOutputStringIndex, getStringIndices, inputFormat, isOutputFormatDefined, numPendingOutput, output, outputFormat, outputFormatPeek, outputPeek, push, resetQueue, setOutputFormat, useFilter</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+<A NAME="field_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Field Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="m_SelectCols"><!-- --></A><H3>
+m_SelectCols</H3>
+<PRE>
+protected weka.core.Range <B>m_SelectCols</B></PRE>
+<DL>
+<DD>Stores which columns to select as a funky range
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<A NAME="m_DisallowInternalPeriods"><!-- --></A><H3>
+m_DisallowInternalPeriods</H3>
+<PRE>
+protected boolean <B>m_DisallowInternalPeriods</B></PRE>
+<DL>
+<DD>Determines whether internal periods are allowed
+<P>
+<DL>
+</DL>
+</DL>
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="KEAPhraseFilter()"><!-- --></A><H3>
+KEAPhraseFilter</H3>
+<PRE>
+public <B>KEAPhraseFilter</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="globalInfo()"><!-- --></A><H3>
+globalInfo</H3>
+<PRE>
+public java.lang.String <B>globalInfo</B>()</PRE>
+<DL>
+<DD>Returns a string describing this filter
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>a description of the filter suitable for
+ displaying in the explorer/experimenter gui</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="listOptions()"><!-- --></A><H3>
+listOptions</H3>
+<PRE>
+public java.util.Enumeration <B>listOptions</B>()</PRE>
+<DL>
+<DD>Returns an enumeration describing the available options
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>listOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>an enumeration of all the available options</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setOptions(java.lang.String[])"><!-- --></A><H3>
+setOptions</H3>
+<PRE>
+public void <B>setOptions</B>(java.lang.String[]&nbsp;options)
+                throws java.lang.Exception</PRE>
+<DL>
+<DD>Parses a given list of options controlling the behaviour of this object.
+ Valid options are:<p>
+
+ -R index1,index2-index4,...<br>
+ Specify list of attributes to process. First and last are valid indexes.
+ (default none)<p>
+
+ -V<br>
+ Invert matching sense <p>
+
+ -P<br>
+ Disallow internal periods <p>
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>setOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>options</CODE> - the list of options as an array of strings
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.Exception</CODE> - if an option is not supported</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getOptions()"><!-- --></A><H3>
+getOptions</H3>
+<PRE>
+public java.lang.String[] <B>getOptions</B>()</PRE>
+<DL>
+<DD>Gets the current settings of the filter.
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE>getOptions</CODE> in interface <CODE>weka.core.OptionHandler</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>an array of strings suitable for passing to setOptions</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setInputFormat(weka.core.Instances)"><!-- --></A><H3>
+setInputFormat</H3>
+<PRE>
+public boolean <B>setInputFormat</B>(weka.core.Instances&nbsp;instanceInfo)
+                       throws java.lang.Exception</PRE>
+<DL>
+<DD>Sets the format of the input instances.
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>setInputFormat</CODE> in class <CODE>weka.filters.Filter</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>instanceInfo</CODE> - an Instances object containing the input
+ instance structure (any instances contained in the object are
+ ignored - only the structure is required).
+<DT><B>Returns:</B><DD>true if the outputFormat may be collected immediately
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="input(weka.core.Instance)"><!-- --></A><H3>
+input</H3>
+<PRE>
+public boolean <B>input</B>(weka.core.Instance&nbsp;instance)
+              throws java.lang.Exception</PRE>
+<DL>
+<DD>Input an instance for filtering. Ordinarily the instance is processed
+ and made available for output immediately. Some filters require all
+ instances be read before producing output.
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>input</CODE> in class <CODE>weka.filters.Filter</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>instance</CODE> - the input instance
+<DT><B>Returns:</B><DD>true if the filtered instance may now be
+ collected with output().
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.Exception</CODE> - if the input instance was not of the correct 
+ format or if there was a problem with the filtering.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="batchFinished()"><!-- --></A><H3>
+batchFinished</H3>
+<PRE>
+public boolean <B>batchFinished</B>()
+                      throws java.lang.Exception</PRE>
+<DL>
+<DD>Signify that this batch of input to the filter is finished. If
+ the filter requires all instances prior to filtering, output()
+ may now be called to retrieve the filtered instances. Any
+ subsequent instances filtered should be filtered based on setting
+ obtained from the first batch (unless the inputFormat has been
+ re-assigned or new options have been set). This default
+ implementation assumes all instance processing occurs during
+ inputFormat() and input().
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>batchFinished</CODE> in class <CODE>weka.filters.Filter</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>true if there are instances pending output
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.NullPointerException</CODE> - if no input structure has been defined,
+<DD><CODE>java.lang.Exception</CODE> - if there was a problem finishing the batch.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="main(java.lang.String[])"><!-- --></A><H3>
+main</H3>
+<PRE>
+public static void <B>main</B>(java.lang.String[]&nbsp;argv)</PRE>
+<DL>
+<DD>Main method for testing this class.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>argv</CODE> - should contain arguments to the filter: use -h for help</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="invertSelectionTipText()"><!-- --></A><H3>
+invertSelectionTipText</H3>
+<PRE>
+public java.lang.String <B>invertSelectionTipText</B>()</PRE>
+<DL>
+<DD>Returns the tip text for this property
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>tip text for this property suitable for
+ displaying in the explorer/experimenter gui</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getInvertSelection()"><!-- --></A><H3>
+getInvertSelection</H3>
+<PRE>
+public boolean <B>getInvertSelection</B>()</PRE>
+<DL>
+<DD>Get whether the supplied columns are to be processed
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>true if the supplied columns won't be processed</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setInvertSelection(boolean)"><!-- --></A><H3>
+setInvertSelection</H3>
+<PRE>
+public void <B>setInvertSelection</B>(boolean&nbsp;invert)</PRE>
+<DL>
+<DD>Set whether selected columns should be processed. If true the 
+ selected columns won't be processed.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>invert</CODE> - the new invert setting</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="disallowInternalPeriodsTipText()"><!-- --></A><H3>
+disallowInternalPeriodsTipText</H3>
+<PRE>
+public java.lang.String <B>disallowInternalPeriodsTipText</B>()</PRE>
+<DL>
+<DD>Returns the tip text for this property
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>tip text for this property suitable for
+ displaying in the explorer/experimenter gui</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getDisallowInternalPeriods()"><!-- --></A><H3>
+getDisallowInternalPeriods</H3>
+<PRE>
+public boolean <B>getDisallowInternalPeriods</B>()</PRE>
+<DL>
+<DD>Get whether the supplied columns are to be processed
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>true if the supplied columns won't be processed</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setDisallowInternalPeriods(boolean)"><!-- --></A><H3>
+setDisallowInternalPeriods</H3>
+<PRE>
+public void <B>setDisallowInternalPeriods</B>(boolean&nbsp;disallow)</PRE>
+<DL>
+<DD>Set whether selected columns should be processed. If true the 
+ selected columns won't be processed.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="attributeIndicesTipText()"><!-- --></A><H3>
+attributeIndicesTipText</H3>
+<PRE>
+public java.lang.String <B>attributeIndicesTipText</B>()</PRE>
+<DL>
+<DD>Returns the tip text for this property
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>tip text for this property suitable for
+ displaying in the explorer/experimenter gui</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="getAttributeIndices()"><!-- --></A><H3>
+getAttributeIndices</H3>
+<PRE>
+public java.lang.String <B>getAttributeIndices</B>()</PRE>
+<DL>
+<DD>Get the current range selection.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>a string containing a comma separated list of ranges</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setAttributeIndices(java.lang.String)"><!-- --></A><H3>
+setAttributeIndices</H3>
+<PRE>
+public void <B>setAttributeIndices</B>(java.lang.String&nbsp;rangeList)</PRE>
+<DL>
+<DD>Set which attributes are to be processed
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>rangeList</CODE> - a string representing the list of attributes.  Since
+ the string will typically come from a user, attributes are indexed from
+ 1. <br>
+ eg: first-3,5,6-last</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setAttributeIndicesArray(int[])"><!-- --></A><H3>
+setAttributeIndicesArray</H3>
+<PRE>
+public void <B>setAttributeIndicesArray</B>(int[]&nbsp;attributes)</PRE>
+<DL>
+<DD>Set which attributes are to be processed
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>attributes</CODE> - an array containing indexes of attributes to select.
+ Since the array will typically come from a program, attributes are indexed
+ from 0.</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="KEAModelBuilder.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="LovinsStemmer.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="KEAPhraseFilter.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#field_summary">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;<A HREF="#field_detail">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/LovinsStemmer.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/LovinsStemmer.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/LovinsStemmer.html	(revision 10506)
@@ -0,0 +1,289 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:50 NZDT 2004 -->
+<TITLE>
+LovinsStemmer
+</TITLE>
+<META NAME="keywords" CONTENT="LovinsStemmer,LovinsStemmer class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="LovinsStemmer";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="KEAPhraseFilter.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="NumbersFilter.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="LovinsStemmer.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class LovinsStemmer</H2>
+<PRE>
+java.lang.Object
+  |
+  +--<A HREF="Stemmer.html">Stemmer</A>
+        |
+        +--<B>LovinsStemmer</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>java.io.Serializable</DD>
+</DL>
+<DL>
+<DT><B>Direct Known Subclasses:</B> <DD><A HREF="IteratedLovinsStemmer.html">IteratedLovinsStemmer</A></DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>LovinsStemmer</B><DT>extends <A HREF="Stemmer.html">Stemmer</A><DT>implements java.io.Serializable</DL>
+
+<P>
+Implements the Lovins stemmer.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="LovinsStemmer">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="LovinsStemmer.html#LovinsStemmer()">LovinsStemmer</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="LovinsStemmer.html#main(java.lang.String[])">main</A></B>(java.lang.String[]&nbsp;ops)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stems text coming into stdin and writes it to stdout.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="LovinsStemmer.html#stem(java.lang.String)">stem</A></B>(java.lang.String&nbsp;word)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns the stemmed version of the given word.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_Stemmer"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class <A HREF="Stemmer.html">Stemmer</A></B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><A HREF="Stemmer.html#stemString(java.lang.String)">stemString</A></CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="LovinsStemmer()"><!-- --></A><H3>
+LovinsStemmer</H3>
+<PRE>
+public <B>LovinsStemmer</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="stem(java.lang.String)"><!-- --></A><H3>
+stem</H3>
+<PRE>
+public java.lang.String <B>stem</B>(java.lang.String&nbsp;word)</PRE>
+<DL>
+<DD>Returns the stemmed version of the given word.
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE><A HREF="Stemmer.html#stem(java.lang.String)">stem</A></CODE> in class <CODE><A HREF="Stemmer.html">Stemmer</A></CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>word</CODE> - a string consisting of a single word</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="main(java.lang.String[])"><!-- --></A><H3>
+main</H3>
+<PRE>
+public static void <B>main</B>(java.lang.String[]&nbsp;ops)</PRE>
+<DL>
+<DD>Stems text coming into stdin and writes it to stdout.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="KEAPhraseFilter.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="NumbersFilter.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="LovinsStemmer.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/NumbersFilter.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/NumbersFilter.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/NumbersFilter.html	(revision 10506)
@@ -0,0 +1,396 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:50 NZDT 2004 -->
+<TITLE>
+NumbersFilter
+</TITLE>
+<META NAME="keywords" CONTENT="NumbersFilter,NumbersFilter class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="NumbersFilter";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="LovinsStemmer.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="Stemmer.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="NumbersFilter.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#fields_inherited_from_class_weka.filters.Filter">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class NumbersFilter</H2>
+<PRE>
+java.lang.Object
+  |
+  +--weka.filters.Filter
+        |
+        +--<B>NumbersFilter</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>java.io.Serializable</DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>NumbersFilter</B><DT>extends weka.filters.Filter</DL>
+
+<P>
+Removes all numbers from all the string attributes in the given
+ dataset. Assumes that words are separated by whitespace.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="NumbersFilter">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+<A NAME="field_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Field Summary</B></FONT></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="fields_inherited_from_class_weka.filters.Filter"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Fields inherited from class weka.filters.Filter</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>m_NewBatch</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="NumbersFilter.html#NumbersFilter()">NumbersFilter</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="NumbersFilter.html#batchFinished()">batchFinished</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Signify that this batch of input to the filter is finished.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="NumbersFilter.html#globalInfo()">globalInfo</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns a string describing this filter</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="NumbersFilter.html#input(weka.core.Instance)">input</A></B>(weka.core.Instance&nbsp;instance)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Input an instance for filtering.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>static&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="NumbersFilter.html#main(java.lang.String[])">main</A></B>(java.lang.String[]&nbsp;argv)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Main method for testing this class.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="NumbersFilter.html#setInputFormat(weka.core.Instances)">setInputFormat</A></B>(weka.core.Instances&nbsp;instanceInfo)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sets the format of the input instances.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_weka.filters.Filter"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class weka.filters.Filter</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>batchFilterFile, bufferInput, copyStringValues, copyStringValues, filterFile, flushInput, getInputFormat, getInputStringIndex, getOutputFormat, getOutputStringIndex, getStringIndices, inputFormat, isOutputFormatDefined, numPendingOutput, output, outputFormat, outputFormatPeek, outputPeek, push, resetQueue, setOutputFormat, useFilter</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="NumbersFilter()"><!-- --></A><H3>
+NumbersFilter</H3>
+<PRE>
+public <B>NumbersFilter</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="globalInfo()"><!-- --></A><H3>
+globalInfo</H3>
+<PRE>
+public java.lang.String <B>globalInfo</B>()</PRE>
+<DL>
+<DD>Returns a string describing this filter
+<P>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>a description of the filter suitable for
+ displaying in the explorer/experimenter gui</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="batchFinished()"><!-- --></A><H3>
+batchFinished</H3>
+<PRE>
+public boolean <B>batchFinished</B>()
+                      throws java.lang.Exception</PRE>
+<DL>
+<DD>Signify that this batch of input to the filter is finished. If
+ the filter requires all instances prior to filtering, output()
+ may now be called to retrieve the filtered instances. Any
+ subsequent instances filtered should be filtered based on setting
+ obtained from the first batch (unless the inputFormat has been
+ re-assigned or new options have been set). This default
+ implementation assumes all instance processing occurs during
+ inputFormat() and input().
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>batchFinished</CODE> in class <CODE>weka.filters.Filter</CODE></DL>
+</DD>
+<DD><DL>
+
+<DT><B>Returns:</B><DD>true if there are instances pending output
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.NullPointerException</CODE> - if no input structure has been defined,
+<DD><CODE>java.lang.Exception</CODE> - if there was a problem finishing the batch.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="setInputFormat(weka.core.Instances)"><!-- --></A><H3>
+setInputFormat</H3>
+<PRE>
+public boolean <B>setInputFormat</B>(weka.core.Instances&nbsp;instanceInfo)
+                       throws java.lang.Exception</PRE>
+<DL>
+<DD>Sets the format of the input instances.
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>setInputFormat</CODE> in class <CODE>weka.filters.Filter</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>instanceInfo</CODE> - an Instances object containing the input
+ instance structure (any instances contained in the object are
+ ignored - only the structure is required).
+<DT><B>Returns:</B><DD>true if the outputFormat may be collected immediately
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="input(weka.core.Instance)"><!-- --></A><H3>
+input</H3>
+<PRE>
+public boolean <B>input</B>(weka.core.Instance&nbsp;instance)
+              throws java.lang.Exception</PRE>
+<DL>
+<DD>Input an instance for filtering. Ordinarily the instance is processed
+ and made available for output immediately. Some filters require all
+ instances be read before producing output.
+<P>
+<DD><DL>
+<DT><B>Overrides:</B><DD><CODE>input</CODE> in class <CODE>weka.filters.Filter</CODE></DL>
+</DD>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>instance</CODE> - the input instance
+<DT><B>Returns:</B><DD>true if the filtered instance may now be
+ collected with output().
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.Exception</CODE> - if the input instance was not of the correct 
+ format or if there was a problem with the filtering.</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="main(java.lang.String[])"><!-- --></A><H3>
+main</H3>
+<PRE>
+public static void <B>main</B>(java.lang.String[]&nbsp;argv)</PRE>
+<DL>
+<DD>Main method for testing this class.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>argv</CODE> - should contain arguments to the filter: use -h for help</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="LovinsStemmer.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="Stemmer.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="NumbersFilter.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;<A HREF="#fields_inherited_from_class_weka.filters.Filter">FIELD</A>&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/Stemmer.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/Stemmer.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/Stemmer.html	(revision 10506)
@@ -0,0 +1,278 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:50 NZDT 2004 -->
+<TITLE>
+Stemmer
+</TITLE>
+<META NAME="keywords" CONTENT="Stemmer,Stemmer class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="Stemmer";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="NumbersFilter.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="Stopwords.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="Stemmer.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class Stemmer</H2>
+<PRE>
+java.lang.Object
+  |
+  +--<B>Stemmer</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>java.io.Serializable</DD>
+</DL>
+<DL>
+<DT><B>Direct Known Subclasses:</B> <DD><A HREF="GermanStemmer.html">GermanStemmer</A>, <A HREF="LovinsStemmer.html">LovinsStemmer</A></DD>
+</DL>
+<HR>
+<DL>
+<DT>public abstract class <B>Stemmer</B><DT>extends java.lang.Object<DT>implements java.io.Serializable</DL>
+
+<P>
+Abstract class for stemmers.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="Stemmer">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="Stemmer.html#Stemmer()">Stemmer</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>abstract &nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="Stemmer.html#stem(java.lang.String)">stem</A></B>(java.lang.String&nbsp;str)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Iterated stemming of the given word.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;java.lang.String</CODE></FONT></TD>
+<TD><CODE><B><A HREF="Stemmer.html#stemString(java.lang.String)">stemString</A></B>(java.lang.String&nbsp;str)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Stems everything in the given string.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="Stemmer()"><!-- --></A><H3>
+Stemmer</H3>
+<PRE>
+public <B>Stemmer</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="stem(java.lang.String)"><!-- --></A><H3>
+stem</H3>
+<PRE>
+public abstract java.lang.String <B>stem</B>(java.lang.String&nbsp;str)</PRE>
+<DL>
+<DD>Iterated stemming of the given word.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<HR>
+
+<A NAME="stemString(java.lang.String)"><!-- --></A><H3>
+stemString</H3>
+<PRE>
+public java.lang.String <B>stemString</B>(java.lang.String&nbsp;str)</PRE>
+<DL>
+<DD>Stems everything in the given string.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="NumbersFilter.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="Stopwords.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="Stemmer.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/Stopwords.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/Stopwords.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/Stopwords.html	(revision 10506)
@@ -0,0 +1,255 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:50 NZDT 2004 -->
+<TITLE>
+Stopwords
+</TITLE>
+<META NAME="keywords" CONTENT="Stopwords,Stopwords class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="Stopwords";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="Stemmer.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="StopwordsEnglish.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="Stopwords.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class Stopwords</H2>
+<PRE>
+java.lang.Object
+  |
+  +--<B>Stopwords</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>java.io.Serializable</DD>
+</DL>
+<DL>
+<DT><B>Direct Known Subclasses:</B> <DD><A HREF="StopwordsEnglish.html">StopwordsEnglish</A>, <A HREF="StopwordsGerman.html">StopwordsGerman</A></DD>
+</DL>
+<HR>
+<DL>
+<DT>public abstract class <B>Stopwords</B><DT>extends java.lang.Object<DT>implements java.io.Serializable</DL>
+
+<P>
+Class that can test whether a given string is a stop word.
+ Lowercases all words before the test.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="Stopwords">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="Stopwords.html#Stopwords()">Stopwords</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>abstract &nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="Stopwords.html#isStopword(java.lang.String)">isStopword</A></B>(java.lang.String&nbsp;str)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns true if the given string is a stop word.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="Stopwords()"><!-- --></A><H3>
+Stopwords</H3>
+<PRE>
+public <B>Stopwords</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="isStopword(java.lang.String)"><!-- --></A><H3>
+isStopword</H3>
+<PRE>
+public abstract boolean <B>isStopword</B>(java.lang.String&nbsp;str)</PRE>
+<DL>
+<DD>Returns true if the given string is a stop word.
+<P>
+<DD><DL>
+</DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="Stemmer.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="StopwordsEnglish.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="Stopwords.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/StopwordsEnglish.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/StopwordsEnglish.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/StopwordsEnglish.html	(revision 10506)
@@ -0,0 +1,254 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:50 NZDT 2004 -->
+<TITLE>
+StopwordsEnglish
+</TITLE>
+<META NAME="keywords" CONTENT="StopwordsEnglish,StopwordsEnglish class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="StopwordsEnglish";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="Stopwords.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="StopwordsGerman.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="StopwordsEnglish.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class StopwordsEnglish</H2>
+<PRE>
+java.lang.Object
+  |
+  +--<A HREF="Stopwords.html">Stopwords</A>
+        |
+        +--<B>StopwordsEnglish</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>java.io.Serializable</DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>StopwordsEnglish</B><DT>extends <A HREF="Stopwords.html">Stopwords</A></DL>
+
+<P>
+Class that can test whether a given string is a stop word.
+ Lowercases all words before the test.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="StopwordsEnglish">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="StopwordsEnglish.html#StopwordsEnglish()">StopwordsEnglish</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="StopwordsEnglish.html#isStopword(java.lang.String)">isStopword</A></B>(java.lang.String&nbsp;str)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns true if the given string is a stop word.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="StopwordsEnglish()"><!-- --></A><H3>
+StopwordsEnglish</H3>
+<PRE>
+public <B>StopwordsEnglish</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="isStopword(java.lang.String)"><!-- --></A><H3>
+isStopword</H3>
+<PRE>
+public boolean <B>isStopword</B>(java.lang.String&nbsp;str)</PRE>
+<DL>
+<DD>Returns true if the given string is a stop word.
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE><A HREF="Stopwords.html#isStopword(java.lang.String)">isStopword</A></CODE> in class <CODE><A HREF="Stopwords.html">Stopwords</A></CODE></DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="Stopwords.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;<A HREF="StopwordsGerman.html"><B>NEXT CLASS</B></A></FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="StopwordsEnglish.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/StopwordsGerman.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/StopwordsGerman.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/StopwordsGerman.html	(revision 10506)
@@ -0,0 +1,259 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:50 NZDT 2004 -->
+<TITLE>
+StopwordsGerman
+</TITLE>
+<META NAME="keywords" CONTENT="StopwordsGerman,StopwordsGerman class">
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="StopwordsGerman";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="StopwordsEnglish.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;NEXT CLASS</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="StopwordsGerman.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<!-- ======== START OF CLASS DATA ======== -->
+<H2>
+Class StopwordsGerman</H2>
+<PRE>
+java.lang.Object
+  |
+  +--<A HREF="Stopwords.html">Stopwords</A>
+        |
+        +--<B>StopwordsGerman</B>
+</PRE>
+<DL>
+<DT><B>All Implemented Interfaces:</B> <DD>java.io.Serializable</DD>
+</DL>
+<HR>
+<DL>
+<DT>public class <B>StopwordsGerman</B><DT>extends <A HREF="Stopwords.html">Stopwords</A></DL>
+
+<P>
+Class that can test whether a given string is a stop word.
+ Lowercases all words before the test.
+
+ This list of German stop words has been obtained from
+ http://snowball.tartarus.org/german/stop.txt
+
+ But I have deleted/changed some words that I haven't seen before.
+<P>
+
+<P>
+<DL>
+<DT><B>See Also:</B><DD><A HREF="serialized-form.html" TARGET="StopwordsGerman">Serialized Form</A></DL>
+<HR>
+
+<P>
+<!-- ======== NESTED CLASS SUMMARY ======== -->
+
+
+<!-- =========== FIELD SUMMARY =========== -->
+
+
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+
+<A NAME="constructor_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Constructor Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="StopwordsGerman.html#StopwordsGerman()">StopwordsGerman</A></B>()</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD>
+</TR>
+</TABLE>
+&nbsp;
+<!-- ========== METHOD SUMMARY =========== -->
+
+<A NAME="method_summary"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Method Summary</B></FONT></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;boolean</CODE></FONT></TD>
+<TD><CODE><B><A HREF="StopwordsGerman.html#isStopword(java.lang.String)">isStopword</A></B>(java.lang.String&nbsp;str)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Returns true if the given string is a stop word.</TD>
+</TR>
+</TABLE>
+&nbsp;<A NAME="methods_inherited_from_class_java.lang.Object"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#EEEEFF" CLASS="TableSubHeadingColor">
+<TD><B>Methods inherited from class java.lang.Object</B></TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE>clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait</CODE></TD>
+</TR>
+</TABLE>
+&nbsp;
+<P>
+
+<!-- ============ FIELD DETAIL =========== -->
+
+
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+
+<A NAME="constructor_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Constructor Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="StopwordsGerman()"><!-- --></A><H3>
+StopwordsGerman</H3>
+<PRE>
+public <B>StopwordsGerman</B>()</PRE>
+<DL>
+</DL>
+
+<!-- ============ METHOD DETAIL ========== -->
+
+<A NAME="method_detail"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Method Detail</B></FONT></TD>
+</TR>
+</TABLE>
+
+<A NAME="isStopword(java.lang.String)"><!-- --></A><H3>
+isStopword</H3>
+<PRE>
+public boolean <B>isStopword</B>(java.lang.String&nbsp;str)</PRE>
+<DL>
+<DD>Returns true if the given string is a stop word.
+<P>
+<DD><DL>
+<DT><B>Specified by:</B><DD><CODE><A HREF="Stopwords.html#isStopword(java.lang.String)">isStopword</A></CODE> in class <CODE><A HREF="Stopwords.html">Stopwords</A></CODE></DL>
+</DD>
+<DD><DL>
+</DL>
+</DD>
+</DL>
+<!-- ========= END OF CLASS DATA ========= -->
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">      <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Class</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;<A HREF="StopwordsEnglish.html"><B>PREV CLASS</B></A>&nbsp;
+&nbsp;NEXT CLASS</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="StopwordsGerman.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+<TR>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+  SUMMARY:&nbsp;NESTED&nbsp;|&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_summary">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_summary">METHOD</A></FONT></TD>
+<TD VALIGN="top" CLASS="NavBarCell3"><FONT SIZE="-2">
+DETAIL:&nbsp;FIELD&nbsp;|&nbsp;<A HREF="#constructor_detail">CONSTR</A>&nbsp;|&nbsp;<A HREF="#method_detail">METHOD</A></FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/allclasses-frame.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/allclasses-frame.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/allclasses-frame.html	(revision 10506)
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:48 NZDT 2004 -->
+<TITLE>
+All Classes
+</TITLE>
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="All Classes";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+<FONT size="+1" CLASS="FrameHeadingFont">
+<B>All Classes</B></FONT>
+<BR>
+
+<TABLE BORDER="0" WIDTH="100%">
+<TR>
+<TD NOWRAP><FONT CLASS="FrameItemFont"><A HREF="Counter.html" TARGET="classFrame">Counter</A>
+<BR>
+<A HREF="GermanStemmer.html" TARGET="classFrame">GermanStemmer</A>
+<BR>
+<A HREF="IteratedLovinsStemmer.html" TARGET="classFrame">IteratedLovinsStemmer</A>
+<BR>
+<A HREF="KEAFilter.html" TARGET="classFrame">KEAFilter</A>
+<BR>
+<A HREF="KEAKeyphraseExtractor.html" TARGET="classFrame">KEAKeyphraseExtractor</A>
+<BR>
+<A HREF="KEAModelBuilder.html" TARGET="classFrame">KEAModelBuilder</A>
+<BR>
+<A HREF="KEAPhraseFilter.html" TARGET="classFrame">KEAPhraseFilter</A>
+<BR>
+<A HREF="LovinsStemmer.html" TARGET="classFrame">LovinsStemmer</A>
+<BR>
+<A HREF="NumbersFilter.html" TARGET="classFrame">NumbersFilter</A>
+<BR>
+<A HREF="Stemmer.html" TARGET="classFrame">Stemmer</A>
+<BR>
+<A HREF="Stopwords.html" TARGET="classFrame">Stopwords</A>
+<BR>
+<A HREF="StopwordsEnglish.html" TARGET="classFrame">StopwordsEnglish</A>
+<BR>
+<A HREF="StopwordsGerman.html" TARGET="classFrame">StopwordsGerman</A>
+<BR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/allclasses-noframe.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/allclasses-noframe.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/allclasses-noframe.html	(revision 10506)
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:48 NZDT 2004 -->
+<TITLE>
+All Classes
+</TITLE>
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="All Classes";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+<FONT size="+1" CLASS="FrameHeadingFont">
+<B>All Classes</B></FONT>
+<BR>
+
+<TABLE BORDER="0" WIDTH="100%">
+<TR>
+<TD NOWRAP><FONT CLASS="FrameItemFont"><A HREF="Counter.html" TARGET="">Counter</A>
+<BR>
+<A HREF="GermanStemmer.html" TARGET="">GermanStemmer</A>
+<BR>
+<A HREF="IteratedLovinsStemmer.html" TARGET="">IteratedLovinsStemmer</A>
+<BR>
+<A HREF="KEAFilter.html" TARGET="">KEAFilter</A>
+<BR>
+<A HREF="KEAKeyphraseExtractor.html" TARGET="">KEAKeyphraseExtractor</A>
+<BR>
+<A HREF="KEAModelBuilder.html" TARGET="">KEAModelBuilder</A>
+<BR>
+<A HREF="KEAPhraseFilter.html" TARGET="">KEAPhraseFilter</A>
+<BR>
+<A HREF="LovinsStemmer.html" TARGET="">LovinsStemmer</A>
+<BR>
+<A HREF="NumbersFilter.html" TARGET="">NumbersFilter</A>
+<BR>
+<A HREF="Stemmer.html" TARGET="">Stemmer</A>
+<BR>
+<A HREF="Stopwords.html" TARGET="">Stopwords</A>
+<BR>
+<A HREF="StopwordsEnglish.html" TARGET="">StopwordsEnglish</A>
+<BR>
+<A HREF="StopwordsGerman.html" TARGET="">StopwordsGerman</A>
+<BR>
+</FONT></TD>
+</TR>
+</TABLE>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/constant-values.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/constant-values.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/constant-values.html	(revision 10506)
@@ -0,0 +1,123 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:47 NZDT 2004 -->
+<TITLE>
+Constant Field Values
+</TITLE>
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="Constant Field Values";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="constant-values.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<CENTER>
+<H1>
+Constant Field Values</H1>
+</CENTER>
+<HR SIZE="4" NOSHADE>
+<B>Contents</B><UL>
+</UL>
+
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="constant-values.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/deprecated-list.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/deprecated-list.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/deprecated-list.html	(revision 10506)
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:48 NZDT 2004 -->
+<TITLE>
+Deprecated List
+</TITLE>
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="Deprecated List";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Deprecated</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="deprecated-list.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<CENTER>
+<H2>
+<B>Deprecated API</B></H2>
+</CENTER>
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Deprecated</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="deprecated-list.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/help-doc.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/help-doc.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/help-doc.html	(revision 10506)
@@ -0,0 +1,168 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:50 NZDT 2004 -->
+<TITLE>
+API Help
+</TITLE>
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="API Help";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Help</B></FONT>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="help-doc.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<CENTER>
+<H1>
+How This API Document Is Organized</H1>
+</CENTER>
+This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.<H3>
+Package</H3>
+<BLOCKQUOTE>
+
+<P>
+Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain four categories:<UL>
+<LI>Interfaces (italic)<LI>Classes<LI>Exceptions<LI>Errors</UL>
+</BLOCKQUOTE>
+<H3>
+Class/Interface</H3>
+<BLOCKQUOTE>
+
+<P>
+Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:<UL>
+<LI>Class inheritance diagram<LI>Direct Subclasses<LI>All Known Subinterfaces<LI>All Known Implementing Classes<LI>Class/interface declaration<LI>Class/interface description
+<P>
+<LI>Nested Class Summary<LI>Field Summary<LI>Constructor Summary<LI>Method Summary
+<P>
+<LI>Field Detail<LI>Constructor Detail<LI>Method Detail</UL>
+Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.</BLOCKQUOTE>
+<H3>
+Tree (Class Hierarchy)</H3>
+<BLOCKQUOTE>
+There is a <A HREF="overview-tree.html">Class Hierarchy</A> page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with <code>java.lang.Object</code>. The interfaces do not inherit from <code>java.lang.Object</code>.<UL>
+<LI>When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.<LI>When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.</UL>
+</BLOCKQUOTE>
+<H3>
+Deprecated API</H3>
+<BLOCKQUOTE>
+The <A HREF="deprecated-list.html">Deprecated API</A> page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.</BLOCKQUOTE>
+<H3>
+Index</H3>
+<BLOCKQUOTE>
+The <A HREF="index-all.html">Index</A> contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.</BLOCKQUOTE>
+<H3>
+Prev/Next</H3>
+These links take you to the next or previous class, interface, package, or related page.<H3>
+Frames/No Frames</H3>
+These links show and hide the HTML frames.  All pages are available with or without frames.
+<P>
+<H3>
+Serialized Form</H3>
+Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.
+<P>
+<FONT SIZE="-1">
+<EM>
+This help file applies to API documentation generated using the standard doclet.</EM>
+</FONT>
+<BR>
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Help</B></FONT>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="help-doc.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/index-all.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/index-all.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/index-all.html	(revision 10506)
@@ -0,0 +1,596 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:48 NZDT 2004 -->
+<TITLE>
+Index
+</TITLE>
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="Index";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="index-all.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<A HREF="#_A_">A</A> <A HREF="#_B_">B</A> <A HREF="#_C_">C</A> <A HREF="#_D_">D</A> <A HREF="#_E_">E</A> <A HREF="#_G_">G</A> <A HREF="#_I_">I</A> <A HREF="#_K_">K</A> <A HREF="#_L_">L</A> <A HREF="#_M_">M</A> <A HREF="#_N_">N</A> <A HREF="#_S_">S</A> <A HREF="#_T_">T</A> <A HREF="#_V_">V</A> <HR>
+<A NAME="_A_"><!-- --></A><H2>
+<B>A</B></H2>
+<DL>
+<DT><A HREF="KEAPhraseFilter.html#attributeIndicesTipText()"><B>attributeIndicesTipText()</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Returns the tip text for this property
+</DL>
+<HR>
+<A NAME="_B_"><!-- --></A><H2>
+<B>B</B></H2>
+<DL>
+<DT><A HREF="KEAFilter.html#batchFinished()"><B>batchFinished()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Signify that this batch of input to the filter is finished.
+<DT><A HREF="KEAPhraseFilter.html#batchFinished()"><B>batchFinished()</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Signify that this batch of input to the filter is finished.
+<DT><A HREF="NumbersFilter.html#batchFinished()"><B>batchFinished()</B></A> - 
+Method in class <A HREF="NumbersFilter.html">NumbersFilter</A>
+<DD>Signify that this batch of input to the filter is finished.
+<DT><A HREF="KEAModelBuilder.html#buildModel(java.util.Hashtable)"><B>buildModel(Hashtable)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Builds the model from the files
+</DL>
+<HR>
+<A NAME="_C_"><!-- --></A><H2>
+<B>C</B></H2>
+<DL>
+<DT><A HREF="KEAKeyphraseExtractor.html#collectStems()"><B>collectStems()</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Collects the stems of the file names.
+<DT><A HREF="KEAModelBuilder.html#collectStems()"><B>collectStems()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Collects the stems of the file names.
+<DT><A HREF="Counter.html"><B>Counter</B></A> - class <A HREF="Counter.html">Counter</A>.<DD>Class that implements a simple counter.<DT><A HREF="Counter.html#Counter()"><B>Counter()</B></A> - 
+Constructor for class <A HREF="Counter.html">Counter</A>
+<DD>Initializes the counter to 1
+<DT><A HREF="Counter.html#Counter(int)"><B>Counter(int)</B></A> - 
+Constructor for class <A HREF="Counter.html">Counter</A>
+<DD>Initializes the counter to the given value
+</DL>
+<HR>
+<A NAME="_D_"><!-- --></A><H2>
+<B>D</B></H2>
+<DL>
+<DT><A HREF="KEAPhraseFilter.html#disallowInternalPeriodsTipText()"><B>disallowInternalPeriodsTipText()</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Returns the tip text for this property
+</DL>
+<HR>
+<A NAME="_E_"><!-- --></A><H2>
+<B>E</B></H2>
+<DL>
+<DT><A HREF="KEAKeyphraseExtractor.html#extractKeyphrases(java.util.Hashtable)"><B>extractKeyphrases(Hashtable)</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Builds the model from the files
+</DL>
+<HR>
+<A NAME="_G_"><!-- --></A><H2>
+<B>G</B></H2>
+<DL>
+<DT><A HREF="GermanStemmer.html"><B>GermanStemmer</B></A> - class <A HREF="GermanStemmer.html">GermanStemmer</A>.<DD>A stemmer for German words.<DT><A HREF="GermanStemmer.html#GermanStemmer()"><B>GermanStemmer()</B></A> - 
+Constructor for class <A HREF="GermanStemmer.html">GermanStemmer</A>
+<DD>&nbsp;
+<DT><A HREF="KEAKeyphraseExtractor.html#getAdditionalInfo()"><B>getAdditionalInfo()</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Get the value of AdditionalInfo.
+<DT><A HREF="KEAPhraseFilter.html#getAttributeIndices()"><B>getAttributeIndices()</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Get the current range selection.
+<DT><A HREF="KEAFilter.html#getCheckForProperNouns()"><B>getCheckForProperNouns()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Get the M_CheckProperNouns value.
+<DT><A HREF="KEAModelBuilder.html#getCheckForProperNouns()"><B>getCheckForProperNouns()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the M_CheckProperNouns value.
+<DT><A HREF="KEAFilter.html#getDebug()"><B>getDebug()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Get the value of Debug.
+<DT><A HREF="KEAKeyphraseExtractor.html#getDebug()"><B>getDebug()</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Get the value of debug.
+<DT><A HREF="KEAModelBuilder.html#getDebug()"><B>getDebug()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the value of debug.
+<DT><A HREF="KEAKeyphraseExtractor.html#getDirName()"><B>getDirName()</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Get the value of dirName.
+<DT><A HREF="KEAModelBuilder.html#getDirName()"><B>getDirName()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the value of dirName.
+<DT><A HREF="KEAFilter.html#getDisallowInternalPeriods()"><B>getDisallowInternalPeriods()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Get whether the supplied columns are to be processed
+<DT><A HREF="KEAPhraseFilter.html#getDisallowInternalPeriods()"><B>getDisallowInternalPeriods()</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Get whether the supplied columns are to be processed
+<DT><A HREF="KEAModelBuilder.html#getDisallowIPeriods()"><B>getDisallowIPeriods()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the value of disallowIPeriods.
+<DT><A HREF="KEAFilter.html#getDocumentAtt()"><B>getDocumentAtt()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Get the value of DocumentAtt.
+<DT><A HREF="KEAKeyphraseExtractor.html#getEncoding()"><B>getEncoding()</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Get the value of encoding.
+<DT><A HREF="KEAModelBuilder.html#getEncoding()"><B>getEncoding()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the value of encoding.
+<DT><A HREF="KEAPhraseFilter.html#getInvertSelection()"><B>getInvertSelection()</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Get whether the supplied columns are to be processed
+<DT><A HREF="KEAFilter.html#getKeyphrasesAtt()"><B>getKeyphrasesAtt()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Get the value of KeyphraseAtt.
+<DT><A HREF="KEAFilter.html#getKFused()"><B>getKFused()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Gets whether keyphrase frequency attribute is used.
+<DT><A HREF="KEAFilter.html#getMaxPhraseLength()"><B>getMaxPhraseLength()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Get the value of MaxPhraseLength.
+<DT><A HREF="KEAModelBuilder.html#getMaxPhraseLength()"><B>getMaxPhraseLength()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the value of MaxPhraseLength.
+<DT><A HREF="KEAFilter.html#getMinNumOccur()"><B>getMinNumOccur()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Get the value of MinNumOccur.
+<DT><A HREF="KEAModelBuilder.html#getMinNumOccur()"><B>getMinNumOccur()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the value of MinNumOccur.
+<DT><A HREF="KEAFilter.html#getMinPhraseLength()"><B>getMinPhraseLength()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Get the value of MinPhraseLength.
+<DT><A HREF="KEAModelBuilder.html#getMinPhraseLength()"><B>getMinPhraseLength()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the value of MinPhraseLength.
+<DT><A HREF="KEAKeyphraseExtractor.html#getModelName()"><B>getModelName()</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Get the value of modelName.
+<DT><A HREF="KEAModelBuilder.html#getModelName()"><B>getModelName()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the value of modelName.
+<DT><A HREF="KEAKeyphraseExtractor.html#getNumPhrases()"><B>getNumPhrases()</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Get the value of numPhrases.
+<DT><A HREF="KEAFilter.html#getOptions()"><B>getOptions()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Gets the current settings of the filter.
+<DT><A HREF="KEAKeyphraseExtractor.html#getOptions()"><B>getOptions()</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Gets the current option settings.
+<DT><A HREF="KEAModelBuilder.html#getOptions()"><B>getOptions()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Gets the current option settings.
+<DT><A HREF="KEAPhraseFilter.html#getOptions()"><B>getOptions()</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Gets the current settings of the filter.
+<DT><A HREF="KEAFilter.html#getProbabilityIndex()"><B>getProbabilityIndex()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Returns the index of the phrases' probabilities in the output ARFF file.
+<DT><A HREF="KEAFilter.html#getRankIndex()"><B>getRankIndex()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Returns the index of the phrases' ranks in the output ARFF file.
+<DT><A HREF="KEAFilter.html#getStemmedPhraseIndex()"><B>getStemmedPhraseIndex()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Returns the index of the stemmed phrases in the output ARFF file.
+<DT><A HREF="KEAFilter.html#getStemmer()"><B>getStemmer()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Get the Stemmer value.
+<DT><A HREF="KEAModelBuilder.html#getStemmer()"><B>getStemmer()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the Stemmer value.
+<DT><A HREF="KEAFilter.html#getStopwords()"><B>getStopwords()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Get the M_Stopwords value.
+<DT><A HREF="KEAModelBuilder.html#getStopwords()"><B>getStopwords()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the M_Stopwords value.
+<DT><A HREF="KEAFilter.html#getUnstemmedPhraseIndex()"><B>getUnstemmedPhraseIndex()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Returns the index of the unstemmed phrases in the output ARFF file.
+<DT><A HREF="KEAModelBuilder.html#getUseKFrequency()"><B>getUseKFrequency()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Get the value of useKFrequency.
+<DT><A HREF="KEAFilter.html#globalInfo()"><B>globalInfo()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Returns a string describing this filter
+<DT><A HREF="KEAPhraseFilter.html#globalInfo()"><B>globalInfo()</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Returns a string describing this filter
+<DT><A HREF="NumbersFilter.html#globalInfo()"><B>globalInfo()</B></A> - 
+Method in class <A HREF="NumbersFilter.html">NumbersFilter</A>
+<DD>Returns a string describing this filter
+</DL>
+<HR>
+<A NAME="_I_"><!-- --></A><H2>
+<B>I</B></H2>
+<DL>
+<DT><A HREF="Counter.html#increment()"><B>increment()</B></A> - 
+Method in class <A HREF="Counter.html">Counter</A>
+<DD>Increments the counter.
+<DT><A HREF="KEAFilter.html#input(weka.core.Instance)"><B>input(Instance)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Input an instance for filtering.
+<DT><A HREF="KEAPhraseFilter.html#input(weka.core.Instance)"><B>input(Instance)</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Input an instance for filtering.
+<DT><A HREF="NumbersFilter.html#input(weka.core.Instance)"><B>input(Instance)</B></A> - 
+Method in class <A HREF="NumbersFilter.html">NumbersFilter</A>
+<DD>Input an instance for filtering.
+<DT><A HREF="KEAPhraseFilter.html#invertSelectionTipText()"><B>invertSelectionTipText()</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Returns the tip text for this property
+<DT><A HREF="Stopwords.html#isStopword(java.lang.String)"><B>isStopword(String)</B></A> - 
+Method in class <A HREF="Stopwords.html">Stopwords</A>
+<DD>Returns true if the given string is a stop word.
+<DT><A HREF="StopwordsEnglish.html#isStopword(java.lang.String)"><B>isStopword(String)</B></A> - 
+Method in class <A HREF="StopwordsEnglish.html">StopwordsEnglish</A>
+<DD>Returns true if the given string is a stop word.
+<DT><A HREF="StopwordsGerman.html#isStopword(java.lang.String)"><B>isStopword(String)</B></A> - 
+Method in class <A HREF="StopwordsGerman.html">StopwordsGerman</A>
+<DD>Returns true if the given string is a stop word.
+<DT><A HREF="IteratedLovinsStemmer.html"><B>IteratedLovinsStemmer</B></A> - class <A HREF="IteratedLovinsStemmer.html">IteratedLovinsStemmer</A>.<DD>Implements the iterated version of the Lovins stemmer.<DT><A HREF="IteratedLovinsStemmer.html#IteratedLovinsStemmer()"><B>IteratedLovinsStemmer()</B></A> - 
+Constructor for class <A HREF="IteratedLovinsStemmer.html">IteratedLovinsStemmer</A>
+<DD>&nbsp;
+</DL>
+<HR>
+<A NAME="_K_"><!-- --></A><H2>
+<B>K</B></H2>
+<DL>
+<DT><A HREF="KEAFilter.html"><B>KEAFilter</B></A> - class <A HREF="KEAFilter.html">KEAFilter</A>.<DD>This filter converts the incoming data into data appropriate for
+ keyphrase classification.<DT><A HREF="KEAFilter.html#KEAFilter()"><B>KEAFilter()</B></A> - 
+Constructor for class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>&nbsp;
+<DT><A HREF="KEAKeyphraseExtractor.html"><B>KEAKeyphraseExtractor</B></A> - class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>.<DD>Extracts keyphrases from the documents in a given directory.<DT><A HREF="KEAKeyphraseExtractor.html#KEAKeyphraseExtractor()"><B>KEAKeyphraseExtractor()</B></A> - 
+Constructor for class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>&nbsp;
+<DT><A HREF="KEAModelBuilder.html"><B>KEAModelBuilder</B></A> - class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>.<DD>Builds a keyphrase extraction model from the documents in a given
+ directory.<DT><A HREF="KEAModelBuilder.html#KEAModelBuilder()"><B>KEAModelBuilder()</B></A> - 
+Constructor for class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>&nbsp;
+<DT><A HREF="KEAPhraseFilter.html"><B>KEAPhraseFilter</B></A> - class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>.<DD>This filter splits the text in selected string
+ attributes into phrases.<DT><A HREF="KEAPhraseFilter.html#KEAPhraseFilter()"><B>KEAPhraseFilter()</B></A> - 
+Constructor for class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>&nbsp;
+</DL>
+<HR>
+<A NAME="_L_"><!-- --></A><H2>
+<B>L</B></H2>
+<DL>
+<DT><A HREF="KEAFilter.html#listOptions()"><B>listOptions()</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Returns an enumeration describing the available options
+<DT><A HREF="KEAKeyphraseExtractor.html#listOptions()"><B>listOptions()</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Returns an enumeration describing the available options.
+<DT><A HREF="KEAModelBuilder.html#listOptions()"><B>listOptions()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Returns an enumeration describing the available options.
+<DT><A HREF="KEAPhraseFilter.html#listOptions()"><B>listOptions()</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Returns an enumeration describing the available options
+<DT><A HREF="KEAKeyphraseExtractor.html#loadModel()"><B>loadModel()</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Loads the extraction model from the file.
+<DT><A HREF="LovinsStemmer.html"><B>LovinsStemmer</B></A> - class <A HREF="LovinsStemmer.html">LovinsStemmer</A>.<DD>Implements the Lovins stemmer.<DT><A HREF="LovinsStemmer.html#LovinsStemmer()"><B>LovinsStemmer()</B></A> - 
+Constructor for class <A HREF="LovinsStemmer.html">LovinsStemmer</A>
+<DD>&nbsp;
+</DL>
+<HR>
+<A NAME="_M_"><!-- --></A><H2>
+<B>M</B></H2>
+<DL>
+<DT><A HREF="KEAPhraseFilter.html#m_DisallowInternalPeriods"><B>m_DisallowInternalPeriods</B></A> - 
+Variable in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Determines whether internal periods are allowed
+<DT><A HREF="KEAPhraseFilter.html#m_SelectCols"><B>m_SelectCols</B></A> - 
+Variable in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Stores which columns to select as a funky range
+<DT><A HREF="IteratedLovinsStemmer.html#main(java.lang.String[])"><B>main(String[])</B></A> - 
+Static method in class <A HREF="IteratedLovinsStemmer.html">IteratedLovinsStemmer</A>
+<DD>Stems text coming into stdin and writes it to stdout.
+<DT><A HREF="KEAFilter.html#main(java.lang.String[])"><B>main(String[])</B></A> - 
+Static method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Main method for testing this class.
+<DT><A HREF="KEAKeyphraseExtractor.html#main(java.lang.String[])"><B>main(String[])</B></A> - 
+Static method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>The main method.
+<DT><A HREF="KEAModelBuilder.html#main(java.lang.String[])"><B>main(String[])</B></A> - 
+Static method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>The main method.
+<DT><A HREF="KEAPhraseFilter.html#main(java.lang.String[])"><B>main(String[])</B></A> - 
+Static method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Main method for testing this class.
+<DT><A HREF="LovinsStemmer.html#main(java.lang.String[])"><B>main(String[])</B></A> - 
+Static method in class <A HREF="LovinsStemmer.html">LovinsStemmer</A>
+<DD>Stems text coming into stdin and writes it to stdout.
+<DT><A HREF="NumbersFilter.html#main(java.lang.String[])"><B>main(String[])</B></A> - 
+Static method in class <A HREF="NumbersFilter.html">NumbersFilter</A>
+<DD>Main method for testing this class.
+</DL>
+<HR>
+<A NAME="_N_"><!-- --></A><H2>
+<B>N</B></H2>
+<DL>
+<DT><A HREF="NumbersFilter.html"><B>NumbersFilter</B></A> - class <A HREF="NumbersFilter.html">NumbersFilter</A>.<DD>Removes all numbers from all the string attributes in the given
+ dataset.<DT><A HREF="NumbersFilter.html#NumbersFilter()"><B>NumbersFilter()</B></A> - 
+Constructor for class <A HREF="NumbersFilter.html">NumbersFilter</A>
+<DD>&nbsp;
+</DL>
+<HR>
+<A NAME="_S_"><!-- --></A><H2>
+<B>S</B></H2>
+<DL>
+<DT><A HREF="KEAModelBuilder.html#saveModel()"><B>saveModel()</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Saves the extraction model to the file.
+<DT><A HREF="KEAKeyphraseExtractor.html#setAdditionalInfo(boolean)"><B>setAdditionalInfo(boolean)</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Set the value of AdditionalInfo.
+<DT><A HREF="KEAPhraseFilter.html#setAttributeIndices(java.lang.String)"><B>setAttributeIndices(String)</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Set which attributes are to be processed
+<DT><A HREF="KEAPhraseFilter.html#setAttributeIndicesArray(int[])"><B>setAttributeIndicesArray(int[])</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Set which attributes are to be processed
+<DT><A HREF="KEAFilter.html#setCheckForProperNouns(boolean)"><B>setCheckForProperNouns(boolean)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Set the M_CheckProperNouns value.
+<DT><A HREF="KEAModelBuilder.html#setCheckForProperNouns(boolean)"><B>setCheckForProperNouns(boolean)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the M_CheckProperNouns value.
+<DT><A HREF="KEAFilter.html#setDebug(boolean)"><B>setDebug(boolean)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Set the value of Debug.
+<DT><A HREF="KEAKeyphraseExtractor.html#setDebug(boolean)"><B>setDebug(boolean)</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Set the value of debug.
+<DT><A HREF="KEAModelBuilder.html#setDebug(boolean)"><B>setDebug(boolean)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the value of debug.
+<DT><A HREF="KEAKeyphraseExtractor.html#setDirName(java.lang.String)"><B>setDirName(String)</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Set the value of dirName.
+<DT><A HREF="KEAModelBuilder.html#setDirName(java.lang.String)"><B>setDirName(String)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the value of dirName.
+<DT><A HREF="KEAFilter.html#setDisallowInternalPeriods(boolean)"><B>setDisallowInternalPeriods(boolean)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Set whether selected columns should be processed.
+<DT><A HREF="KEAPhraseFilter.html#setDisallowInternalPeriods(boolean)"><B>setDisallowInternalPeriods(boolean)</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Set whether selected columns should be processed.
+<DT><A HREF="KEAModelBuilder.html#setDisallowIPeriods(boolean)"><B>setDisallowIPeriods(boolean)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the value of disallowIPeriods.
+<DT><A HREF="KEAFilter.html#setDocumentAtt(int)"><B>setDocumentAtt(int)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Set the value of DocumentAtt.
+<DT><A HREF="KEAKeyphraseExtractor.html#setEncoding(java.lang.String)"><B>setEncoding(String)</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Set the value of encoding.
+<DT><A HREF="KEAModelBuilder.html#setEncoding(java.lang.String)"><B>setEncoding(String)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the value of encoding.
+<DT><A HREF="KEAFilter.html#setInputFormat(weka.core.Instances)"><B>setInputFormat(Instances)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Sets the format of the input instances.
+<DT><A HREF="KEAPhraseFilter.html#setInputFormat(weka.core.Instances)"><B>setInputFormat(Instances)</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Sets the format of the input instances.
+<DT><A HREF="NumbersFilter.html#setInputFormat(weka.core.Instances)"><B>setInputFormat(Instances)</B></A> - 
+Method in class <A HREF="NumbersFilter.html">NumbersFilter</A>
+<DD>Sets the format of the input instances.
+<DT><A HREF="KEAPhraseFilter.html#setInvertSelection(boolean)"><B>setInvertSelection(boolean)</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Set whether selected columns should be processed.
+<DT><A HREF="KEAFilter.html#setKeyphrasesAtt(int)"><B>setKeyphrasesAtt(int)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Set the value of KeyphrasesAtt.
+<DT><A HREF="KEAFilter.html#setKFused(boolean)"><B>setKFused(boolean)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Sets whether keyphrase frequency attribute is used.
+<DT><A HREF="KEAFilter.html#setMaxPhraseLength(int)"><B>setMaxPhraseLength(int)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Set the value of MaxPhraseLength.
+<DT><A HREF="KEAModelBuilder.html#setMaxPhraseLength(int)"><B>setMaxPhraseLength(int)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the value of MaxPhraseLength.
+<DT><A HREF="KEAFilter.html#setMinNumOccur(int)"><B>setMinNumOccur(int)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Set the value of MinNumOccur.
+<DT><A HREF="KEAModelBuilder.html#setMinNumOccur(int)"><B>setMinNumOccur(int)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the value of MinNumOccur.
+<DT><A HREF="KEAFilter.html#setMinPhraseLength(int)"><B>setMinPhraseLength(int)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Set the value of MinPhraseLength.
+<DT><A HREF="KEAModelBuilder.html#setMinPhraseLength(int)"><B>setMinPhraseLength(int)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the value of MinPhraseLength.
+<DT><A HREF="KEAKeyphraseExtractor.html#setModelName(java.lang.String)"><B>setModelName(String)</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Set the value of modelName.
+<DT><A HREF="KEAModelBuilder.html#setModelName(java.lang.String)"><B>setModelName(String)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the value of modelName.
+<DT><A HREF="KEAKeyphraseExtractor.html#setNumPhrases(int)"><B>setNumPhrases(int)</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Set the value of numPhrases.
+<DT><A HREF="KEAFilter.html#setOptions(java.lang.String[])"><B>setOptions(String[])</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Parses a given list of options controlling the behaviour of this object.
+<DT><A HREF="KEAKeyphraseExtractor.html#setOptions(java.lang.String[])"><B>setOptions(String[])</B></A> - 
+Method in class <A HREF="KEAKeyphraseExtractor.html">KEAKeyphraseExtractor</A>
+<DD>Parses a given list of options controlling the behaviour of this object.
+<DT><A HREF="KEAModelBuilder.html#setOptions(java.lang.String[])"><B>setOptions(String[])</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Parses a given list of options controlling the behaviour of this object.
+<DT><A HREF="KEAPhraseFilter.html#setOptions(java.lang.String[])"><B>setOptions(String[])</B></A> - 
+Method in class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A>
+<DD>Parses a given list of options controlling the behaviour of this object.
+<DT><A HREF="KEAFilter.html#setStemmer(Stemmer)"><B>setStemmer(Stemmer)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Set the Stemmer value.
+<DT><A HREF="KEAModelBuilder.html#setStemmer(Stemmer)"><B>setStemmer(Stemmer)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the Stemmer value.
+<DT><A HREF="KEAFilter.html#setStopwords(Stopwords)"><B>setStopwords(Stopwords)</B></A> - 
+Method in class <A HREF="KEAFilter.html">KEAFilter</A>
+<DD>Set the M_Stopwords value.
+<DT><A HREF="KEAModelBuilder.html#setStopwords(Stopwords)"><B>setStopwords(Stopwords)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the M_Stopwords value.
+<DT><A HREF="KEAModelBuilder.html#setUseKFrequency(boolean)"><B>setUseKFrequency(boolean)</B></A> - 
+Method in class <A HREF="KEAModelBuilder.html">KEAModelBuilder</A>
+<DD>Set the value of useKFrequency.
+<DT><A HREF="GermanStemmer.html#stem(java.lang.String)"><B>stem(String)</B></A> - 
+Method in class <A HREF="GermanStemmer.html">GermanStemmer</A>
+<DD>Stemms the given term to an unique <tt>discriminator</tt>.
+<DT><A HREF="IteratedLovinsStemmer.html#stem(java.lang.String)"><B>stem(String)</B></A> - 
+Method in class <A HREF="IteratedLovinsStemmer.html">IteratedLovinsStemmer</A>
+<DD>Iterated stemming of the given word.
+<DT><A HREF="LovinsStemmer.html#stem(java.lang.String)"><B>stem(String)</B></A> - 
+Method in class <A HREF="LovinsStemmer.html">LovinsStemmer</A>
+<DD>Returns the stemmed version of the given word.
+<DT><A HREF="Stemmer.html#stem(java.lang.String)"><B>stem(String)</B></A> - 
+Method in class <A HREF="Stemmer.html">Stemmer</A>
+<DD>Iterated stemming of the given word.
+<DT><A HREF="Stemmer.html"><B>Stemmer</B></A> - class <A HREF="Stemmer.html">Stemmer</A>.<DD>Abstract class for stemmers.<DT><A HREF="Stemmer.html#Stemmer()"><B>Stemmer()</B></A> - 
+Constructor for class <A HREF="Stemmer.html">Stemmer</A>
+<DD>&nbsp;
+<DT><A HREF="Stemmer.html#stemString(java.lang.String)"><B>stemString(String)</B></A> - 
+Method in class <A HREF="Stemmer.html">Stemmer</A>
+<DD>Stems everything in the given string.
+<DT><A HREF="Stopwords.html"><B>Stopwords</B></A> - class <A HREF="Stopwords.html">Stopwords</A>.<DD>Class that can test whether a given string is a stop word.<DT><A HREF="Stopwords.html#Stopwords()"><B>Stopwords()</B></A> - 
+Constructor for class <A HREF="Stopwords.html">Stopwords</A>
+<DD>&nbsp;
+<DT><A HREF="StopwordsEnglish.html"><B>StopwordsEnglish</B></A> - class <A HREF="StopwordsEnglish.html">StopwordsEnglish</A>.<DD>Class that can test whether a given string is a stop word.<DT><A HREF="StopwordsEnglish.html#StopwordsEnglish()"><B>StopwordsEnglish()</B></A> - 
+Constructor for class <A HREF="StopwordsEnglish.html">StopwordsEnglish</A>
+<DD>&nbsp;
+<DT><A HREF="StopwordsGerman.html"><B>StopwordsGerman</B></A> - class <A HREF="StopwordsGerman.html">StopwordsGerman</A>.<DD>Class that can test whether a given string is a stop word.<DT><A HREF="StopwordsGerman.html#StopwordsGerman()"><B>StopwordsGerman()</B></A> - 
+Constructor for class <A HREF="StopwordsGerman.html">StopwordsGerman</A>
+<DD>&nbsp;
+</DL>
+<HR>
+<A NAME="_T_"><!-- --></A><H2>
+<B>T</B></H2>
+<DL>
+<DT><A HREF="Counter.html#toString()"><B>toString()</B></A> - 
+Method in class <A HREF="Counter.html">Counter</A>
+<DD>Returns string containing value.
+</DL>
+<HR>
+<A NAME="_V_"><!-- --></A><H2>
+<B>V</B></H2>
+<DL>
+<DT><A HREF="Counter.html#value()"><B>value()</B></A> - 
+Method in class <A HREF="Counter.html">Counter</A>
+<DD>Gets the value.
+</DL>
+<HR>
+<A HREF="#_A_">A</A> <A HREF="#_B_">B</A> <A HREF="#_C_">C</A> <A HREF="#_D_">D</A> <A HREF="#_E_">E</A> <A HREF="#_G_">G</A> <A HREF="#_I_">I</A> <A HREF="#_K_">K</A> <A HREF="#_L_">L</A> <A HREF="#_M_">M</A> <A HREF="#_N_">N</A> <A HREF="#_S_">S</A> <A HREF="#_T_">T</A> <A HREF="#_V_">V</A> 
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Index</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="index-all.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/index.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/index.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/index.html	(revision 10506)
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:48 NZDT 2004-->
+<TITLE>
+Generated Documentation (Untitled)
+</TITLE>
+</HEAD>
+<FRAMESET cols="20%,80%">
+<FRAME src="allclasses-frame.html" name="packageFrame">
+<FRAME src="Counter.html" name="classFrame">
+</FRAMESET>
+<NOFRAMES>
+<H2>
+Frame Alert</H2>
+
+<P>
+This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+<BR>
+Link to<A HREF="Counter.html">Non-frame version.</A></NOFRAMES>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/overview-tree.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/overview-tree.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/overview-tree.html	(revision 10506)
@@ -0,0 +1,143 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:48 NZDT 2004 -->
+<TITLE>
+Class Hierarchy
+</TITLE>
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="Class Hierarchy";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="overview-tree.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<CENTER>
+<H2>
+Hierarchy For All Packages</H2>
+</CENTER>
+<H2>
+Class Hierarchy
+</H2>
+<UL>
+<LI TYPE="circle">class java.lang.Object<UL>
+<LI TYPE="circle">class <A HREF="Counter.html"><B>Counter</B></A> (implements java.io.Serializable)
+<LI TYPE="circle">class weka.filters.Filter (implements java.io.Serializable)
+<UL>
+<LI TYPE="circle">class <A HREF="KEAFilter.html"><B>KEAFilter</B></A> (implements weka.core.OptionHandler)
+<LI TYPE="circle">class <A HREF="KEAPhraseFilter.html"><B>KEAPhraseFilter</B></A> (implements weka.core.OptionHandler)
+<LI TYPE="circle">class <A HREF="NumbersFilter.html"><B>NumbersFilter</B></A></UL>
+<LI TYPE="circle">class <A HREF="KEAKeyphraseExtractor.html"><B>KEAKeyphraseExtractor</B></A> (implements weka.core.OptionHandler)
+<LI TYPE="circle">class <A HREF="KEAModelBuilder.html"><B>KEAModelBuilder</B></A> (implements weka.core.OptionHandler)
+<LI TYPE="circle">class <A HREF="Stemmer.html"><B>Stemmer</B></A> (implements java.io.Serializable)
+<UL>
+<LI TYPE="circle">class <A HREF="GermanStemmer.html"><B>GermanStemmer</B></A><LI TYPE="circle">class <A HREF="LovinsStemmer.html"><B>LovinsStemmer</B></A> (implements java.io.Serializable)
+<UL>
+<LI TYPE="circle">class <A HREF="IteratedLovinsStemmer.html"><B>IteratedLovinsStemmer</B></A></UL>
+</UL>
+<LI TYPE="circle">class <A HREF="Stopwords.html"><B>Stopwords</B></A> (implements java.io.Serializable)
+<UL>
+<LI TYPE="circle">class <A HREF="StopwordsEnglish.html"><B>StopwordsEnglish</B></A><LI TYPE="circle">class <A HREF="StopwordsGerman.html"><B>StopwordsGerman</B></A></UL>
+</UL>
+</UL>
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#FFFFFF" CLASS="NavBarCell1Rev"> &nbsp;<FONT CLASS="NavBarFont1Rev"><B>Tree</B></FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="overview-tree.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/package-list
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/package-list	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/package-list	(revision 10506)
@@ -0,0 +1,1 @@
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/packages.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/packages.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/packages.html	(revision 10506)
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:48 NZDT 2004 -->
+<TITLE>
+
+</TITLE>
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<BODY BGCOLOR="white">
+
+<BR>
+
+<BR>
+
+<BR>
+<CENTER>
+The front page has been relocated.Please see:
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="index.html">Frame version</A>
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<A HREF="Counter.html">Non-frame version.</A></CENTER>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/serialized-form.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/serialized-form.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/serialized-form.html	(revision 10506)
@@ -0,0 +1,604 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
+<!--NewPage-->
+<HTML>
+<HEAD>
+<!-- Generated by javadoc on Fri Mar 19 17:50:50 NZDT 2004 -->
+<TITLE>
+Serialized Form
+</TITLE>
+<LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
+</HEAD>
+<SCRIPT>
+function asd()
+{
+parent.document.title="Serialized Form";
+}
+</SCRIPT>
+<BODY BGCOLOR="white" onload="asd();">
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_top"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_top_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="serialized-form.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+<CENTER>
+<H1>
+Serialized Form</H1>
+</CENTER>
+<A NAME="Counter"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="Counter.html">Counter</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+<A NAME="serializedForm"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Serialized Fields</B></FONT></TD>
+</TR>
+</TABLE>
+
+<H3>
+m_val</H3>
+<PRE>
+int <B>m_val</B></PRE>
+<DL>
+<DD>Integer value stored
+<P>
+<DL>
+</DL>
+</DL>
+
+<P>
+<HR SIZE="4" NOSHADE>
+<A NAME="GermanStemmer"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="GermanStemmer.html">GermanStemmer</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+<A NAME="serializedForm"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Serialized Fields</B></FONT></TD>
+</TR>
+</TABLE>
+
+<H3>
+sb</H3>
+<PRE>
+java.lang.StringBuffer <B>sb</B></PRE>
+<DL>
+<DD>Buffer for the terms while stemming them.
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+uppercase</H3>
+<PRE>
+boolean <B>uppercase</B></PRE>
+<DL>
+<DD>Indicates if a term is handled as a noun.
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+substCount</H3>
+<PRE>
+int <B>substCount</B></PRE>
+<DL>
+<DD>Amount of characters that are removed with <tt>substitute()</tt> while stemming.
+<P>
+<DL>
+</DL>
+</DL>
+
+<P>
+<HR SIZE="4" NOSHADE>
+<A NAME="IteratedLovinsStemmer"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="IteratedLovinsStemmer.html">IteratedLovinsStemmer</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+<HR SIZE="4" NOSHADE>
+<A NAME="KEAFilter"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="KEAFilter.html">KEAFilter</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+<A NAME="serializedForm"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Serialized Fields</B></FONT></TD>
+</TR>
+</TABLE>
+
+<H3>
+m_DocumentAtt</H3>
+<PRE>
+int <B>m_DocumentAtt</B></PRE>
+<DL>
+<DD>Index of attribute containing the documents
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_KeyphrasesAtt</H3>
+<PRE>
+int <B>m_KeyphrasesAtt</B></PRE>
+<DL>
+<DD>Index of attribute containing the keyphrases
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_MaxPhraseLength</H3>
+<PRE>
+int <B>m_MaxPhraseLength</B></PRE>
+<DL>
+<DD>The maximum length of phrases
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_MinPhraseLength</H3>
+<PRE>
+int <B>m_MinPhraseLength</B></PRE>
+<DL>
+<DD>The minimum length of phrases
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_KFused</H3>
+<PRE>
+boolean <B>m_KFused</B></PRE>
+<DL>
+<DD>Is keyphrase frequency attribute being used?
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_Debug</H3>
+<PRE>
+boolean <B>m_Debug</B></PRE>
+<DL>
+<DD>Flag for debugging mode
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_DisallowInternalPeriods</H3>
+<PRE>
+boolean <B>m_DisallowInternalPeriods</B></PRE>
+<DL>
+<DD>Determines whether internal periods are allowed
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_MinNumOccur</H3>
+<PRE>
+int <B>m_MinNumOccur</B></PRE>
+<DL>
+<DD>The minimum number of occurences of a phrase
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_NumFeatures</H3>
+<PRE>
+int <B>m_NumFeatures</B></PRE>
+<DL>
+<DD>The number of features describing a phrase
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_TfidfIndex</H3>
+<PRE>
+int <B>m_TfidfIndex</B></PRE>
+<DL>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_FirstOccurIndex</H3>
+<PRE>
+int <B>m_FirstOccurIndex</B></PRE>
+<DL>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_KeyFreqIndex</H3>
+<PRE>
+int <B>m_KeyFreqIndex</B></PRE>
+<DL>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_PunctFilter</H3>
+<PRE>
+KEAPhraseFilter <B>m_PunctFilter</B></PRE>
+<DL>
+<DD>The punctuation filter used by this filter
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_NumbersFilter</H3>
+<PRE>
+NumbersFilter <B>m_NumbersFilter</B></PRE>
+<DL>
+<DD>The numbers filter used by this filter
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_Classifier</H3>
+<PRE>
+weka.classifiers.DistributionClassifier <B>m_Classifier</B></PRE>
+<DL>
+<DD>The actual classifier used to compute probabilities
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_Dictionary</H3>
+<PRE>
+java.util.HashMap <B>m_Dictionary</B></PRE>
+<DL>
+<DD>The dictionary containing the document frequencies
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_KeyphraseDictionary</H3>
+<PRE>
+java.util.HashMap <B>m_KeyphraseDictionary</B></PRE>
+<DL>
+<DD>The dictionary containing the keyphrases
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_NumDocs</H3>
+<PRE>
+int <B>m_NumDocs</B></PRE>
+<DL>
+<DD>The number of documents in the global frequencies corpus
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_ClassifierData</H3>
+<PRE>
+weka.core.Instances <B>m_ClassifierData</B></PRE>
+<DL>
+<DD>Template for the classifier data
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_Stemmer</H3>
+<PRE>
+Stemmer <B>m_Stemmer</B></PRE>
+<DL>
+<DD>The stemmer to be used
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_Stopwords</H3>
+<PRE>
+Stopwords <B>m_Stopwords</B></PRE>
+<DL>
+<DD>The list of stop words to be used
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_CheckForProperNouns</H3>
+<PRE>
+boolean <B>m_CheckForProperNouns</B></PRE>
+<DL>
+<DD>Determines whether check for proper nouns is performed
+<P>
+<DL>
+</DL>
+</DL>
+
+<P>
+<HR SIZE="4" NOSHADE>
+<A NAME="KEAPhraseFilter"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="KEAPhraseFilter.html">KEAPhraseFilter</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+<A NAME="serializedForm"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+<TD COLSPAN=1><FONT SIZE="+2">
+<B>Serialized Fields</B></FONT></TD>
+</TR>
+</TABLE>
+
+<H3>
+m_SelectCols</H3>
+<PRE>
+weka.core.Range <B>m_SelectCols</B></PRE>
+<DL>
+<DD>Stores which columns to select as a funky range
+<P>
+<DL>
+</DL>
+</DL>
+<HR>
+
+<H3>
+m_DisallowInternalPeriods</H3>
+<PRE>
+boolean <B>m_DisallowInternalPeriods</B></PRE>
+<DL>
+<DD>Determines whether internal periods are allowed
+<P>
+<DL>
+</DL>
+</DL>
+
+<P>
+<HR SIZE="4" NOSHADE>
+<A NAME="LovinsStemmer"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="LovinsStemmer.html">LovinsStemmer</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+<HR SIZE="4" NOSHADE>
+<A NAME="NumbersFilter"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="NumbersFilter.html">NumbersFilter</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+<HR SIZE="4" NOSHADE>
+<A NAME="Stemmer"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="Stemmer.html">Stemmer</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+<HR SIZE="4" NOSHADE>
+<A NAME="Stopwords"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="Stopwords.html">Stopwords</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+<HR SIZE="4" NOSHADE>
+<A NAME="StopwordsEnglish"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="StopwordsEnglish.html">StopwordsEnglish</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+<HR SIZE="4" NOSHADE>
+<A NAME="StopwordsGerman"><!-- --></A>
+<TABLE BORDER="1" CELLPADDING="3" CELLSPACING="0" WIDTH="100%">
+<TR BGCOLOR="#CCCCFF" CLASS="TableSubHeadingColor">
+<TD COLSPAN=2><FONT SIZE="+2">
+<B>Class <A HREF="StopwordsGerman.html">StopwordsGerman</A> implements Serializable</B></FONT></TD>
+</TR>
+</TABLE>
+
+<P>
+
+<P>
+<HR>
+
+<!-- ========== START OF NAVBAR ========== -->
+<A NAME="navbar_bottom"><!-- --></A>
+<TABLE BORDER="0" WIDTH="100%" CELLPADDING="1" CELLSPACING="0">
+<TR>
+<TD COLSPAN=3 BGCOLOR="#EEEEFF" CLASS="NavBarCell1">
+<A NAME="navbar_bottom_firstrow"><!-- --></A>
+<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="3">
+  <TR ALIGN="center" VALIGN="top">
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Package</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <FONT CLASS="NavBarFont1">Class</FONT>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="overview-tree.html"><FONT CLASS="NavBarFont1"><B>Tree</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="deprecated-list.html"><FONT CLASS="NavBarFont1"><B>Deprecated</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="index-all.html"><FONT CLASS="NavBarFont1"><B>Index</B></FONT></A>&nbsp;</TD>
+  <TD BGCOLOR="#EEEEFF" CLASS="NavBarCell1">    <A HREF="help-doc.html"><FONT CLASS="NavBarFont1"><B>Help</B></FONT></A>&nbsp;</TD>
+  </TR>
+</TABLE>
+</TD>
+<TD ALIGN="right" VALIGN="top" ROWSPAN=3><EM>
+</EM>
+</TD>
+</TR>
+
+<TR>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+&nbsp;PREV&nbsp;
+&nbsp;NEXT</FONT></TD>
+<TD BGCOLOR="white" CLASS="NavBarCell2"><FONT SIZE="-2">
+  <A HREF="index.html" TARGET="_top"><B>FRAMES</B></A>  &nbsp;
+&nbsp;<A HREF="serialized-form.html" TARGET="_top"><B>NO FRAMES</B></A>  &nbsp;
+&nbsp;
+<SCRIPT>
+  <!--
+  if(window==top) {
+    document.writeln('<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>');
+  }
+  //-->
+</SCRIPT>
+<NOSCRIPT>
+<A HREF="allclasses-noframe.html" TARGET=""><B>All Classes</B></A>
+</NOSCRIPT>
+</FONT></TD>
+</TR>
+</TABLE>
+<!-- =========== END OF NAVBAR =========== -->
+
+<HR>
+
+</BODY>
+</HTML>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/stylesheet.css
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/stylesheet.css	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/doc/stylesheet.css	(revision 10506)
@@ -0,0 +1,29 @@
+/* Javadoc style sheet */
+
+/* Define colors, fonts and other style attributes here to override the defaults */
+
+/* Page background color */
+body { background-color: #FFFFFF }
+
+/* Table colors */
+.TableHeadingColor     { background: #CCCCFF } /* Dark mauve */
+.TableSubHeadingColor  { background: #EEEEFF } /* Light mauve */
+.TableRowColor         { background: #FFFFFF } /* White */
+
+/* Font used in left-hand frame lists */
+.FrameTitleFont   { font-size: 10pts; font-family: Helvetica, Arial, san-serif }
+.FrameHeadingFont { font-size: 10pts; font-family: Helvetica, Arial, san-serif }
+.FrameItemFont    { font-size: 10pts; font-family: Helvetica, Arial, san-serif }
+
+/* Example of smaller, sans-serif font in frames */
+/* .FrameItemFont  { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */
+
+/* Navigation bar fonts and colors */
+.NavBarCell1    { background-color:#EEEEFF;}/* Light mauve */
+.NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */
+.NavBarFont1    { font-family: Arial, Helvetica, sans-serif; color:#000000;}
+.NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}
+
+.NavBarCell2    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
+.NavBarCell3    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/Classifier.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/Classifier.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/Classifier.java	(revision 10506)
@@ -0,0 +1,115 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Classifier.java
+ *    Copyright (C) 1999 Eibe Frank, Len Trigg
+ *
+ */
+
+package weka.classifiers;
+
+import java.io.Serializable;
+import weka.core.Instance;
+import weka.core.Instances;
+import weka.core.SerializedObject;
+import weka.core.Utils;
+
+
+/** 
+ * Abstract classifier. All schemes for numeric or nominal prediction in
+ * Weka extend this class.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @author Len Trigg (trigg@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public abstract class Classifier implements Cloneable, Serializable {
+ 
+  /**
+   * Generates a classifier. Must initialize all fields of the classifier
+   * that are not being set via options (ie. multiple calls of buildClassifier
+   * must always lead to the same result). Must not change the dataset
+   * in any way.
+   *
+   * @param data set of instances serving as training data 
+   * @exception Exception if the classifier has not been 
+   * generated successfully
+   */
+  public abstract void buildClassifier(Instances data) throws Exception;
+
+  /**
+   * Classifies a given instance.
+   *
+   * @param instance the instance to be classified
+   * @return index of the predicted class as a double
+   * if the class is nominal, otherwise the predicted value
+   * @exception Exception if instance could not be classified
+   * successfully
+   */
+  public abstract double classifyInstance(Instance instance) throws Exception; 
+
+
+  
+  /**
+   * Creates a new instance of a classifier given it's class name and
+   * (optional) arguments to pass to it's setOptions method. If the
+   * classifier implements OptionHandler and the options parameter is
+   * non-null, the classifier will have it's options set.
+   *
+   * @param classifierName the fully qualified class name of the classifier
+   * @param options an array of options suitable for passing to setOptions. May
+   * be null.
+   * @return the newly created classifier, ready for use.
+   * @exception Exception if the classifier name is invalid, or the options
+   * supplied are not acceptable to the classifier
+   */
+  public static Classifier forName(String classifierName,
+				   String [] options) throws Exception {
+
+    return (Classifier)Utils.forName(Classifier.class,
+				     classifierName,
+				     options);
+  }
+
+  /**
+   * Creates copies of the current classifier, which can then
+   * be used for boosting etc. Note that this method now uses
+   * Serialization to perform a deep copy, so the Classifier
+   * object must be fully Serializable. Any currently built model
+   * will now be copied as well.
+   *
+   * @param model an example classifier to copy
+   * @param num the number of classifiers copies to create.
+   * @return an array of classifiers.
+   * @exception Exception if an error occurs
+   */
+  public static Classifier [] makeCopies(Classifier model,
+					 int num) throws Exception {
+
+    if (model == null) {
+      throw new Exception("No model classifier set");
+    }
+    Classifier [] classifiers = new Classifier [num];
+    SerializedObject so = new SerializedObject(model);
+    for(int i = 0; i < classifiers.length; i++) {
+      classifiers[i] = (Classifier) so.getObject();
+    }
+    return classifiers;
+  }
+
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/DistributionClassifier.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/DistributionClassifier.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/DistributionClassifier.java	(revision 10506)
@@ -0,0 +1,92 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    DistributionClassifier.java
+ *    Copyright (C) 1999 Eibe Frank, Len Trigg
+ *
+ */
+
+package weka.classifiers;
+
+import weka.core.*;
+
+/** 
+ * Abstract classification model that produces (for each test instance)
+ * an estimate of the membership in each class 
+ * (ie. a probability distribution).
+ *
+ * @author   Eibe Frank (trigg@cs.waikato.ac.nz)
+ * @author   Len Trigg (trigg@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public abstract class DistributionClassifier extends Classifier {
+
+  /**
+   * Predicts the class memberships for a given instance. If
+   * an instance is unclassified, the returned array elements
+   * must be all zero. If the class is numeric, the array
+   * must consist of only one element, which contains the
+   * predicted value.
+   *
+   * @param instance the instance to be classified
+   * @return an array containing the estimated membership 
+   * probabilities of the test instance in each class (this 
+   * should sum to at most 1)
+   * @exception Exception if distribution could not be 
+   * computed successfully
+   */
+  public abstract double[] distributionForInstance(Instance instance) 
+       throws Exception;
+
+  /**
+   * Classifies the given test instance. The instance has to belong to a
+   * dataset when it's being classified.
+   *
+   * @param instance the instance to be classified
+   * @return the predicted most likely class for the instance or 
+   * Instance.missingValue() if no prediction is made
+   * @exception Exception if an error occurred during the prediction
+   */
+  public double classifyInstance(Instance instance) throws Exception {
+
+    double [] dist = distributionForInstance(instance);
+    if (dist == null) {
+      throw new Exception("Null distribution predicted");
+    }
+    switch (instance.classAttribute().type()) {
+    case Attribute.NOMINAL:
+      double max = 0;
+      int maxIndex = 0;
+      
+      for (int i = 0; i < dist.length; i++) {
+	if (dist[i] > max) {
+	  maxIndex = i;
+	  max = dist[i];
+	}
+      }
+      if (max > 0) {
+	return maxIndex;
+      } else {
+	return Instance.missingValue();
+      }
+    case Attribute.NUMERIC:
+      return dist[0];
+    default:
+      return Instance.missingValue();
+    }
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/FilteredClassifier.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/FilteredClassifier.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/FilteredClassifier.java	(revision 10506)
@@ -0,0 +1,374 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    FilteredClassifier.java
+ *    Copyright (C) 1999 Len Trigg
+ *
+ */
+
+package weka.classifiers;
+
+import java.util.Enumeration;
+import java.util.Vector;
+import weka.core.Instance;
+import weka.core.Instances;
+import weka.core.Option;
+import weka.core.OptionHandler;
+import weka.core.Utils;
+import weka.filters.Filter;
+import weka.core.Attribute;
+
+
+/**
+ * Class for running an arbitrary classifier on data that has been passed
+ * through an arbitrary filter.<p>
+ *
+ * Valid options from the command line are:<p>
+ *
+ * -B classifierstring <br>
+ * Classifierstring should contain the full class name of a classifier
+ * followed by options to the classifier.
+ * (required).<p>
+ *
+ * -F filterstring <br>
+ * Filterstring should contain the full class name of a filter
+ * followed by options to the filter.
+ * (required).<p>
+ *
+ * @author Len Trigg (trigg@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public class FilteredClassifier extends DistributionClassifier
+  implements OptionHandler {
+
+  /** The classifier */
+  protected Classifier m_Classifier = new weka.classifiers.NaiveBayesSimple();
+
+  /** The filter */
+  protected Filter m_Filter = new weka.filters.DiscretizeFilter();
+
+  /** The instance structure of the filtered instances */
+  protected Instances m_FilteredInstances;
+  
+  /**
+   * Default constructor specifying NaiveBayesSimple as the classifier and
+   * DiscretizeFilter as the filter. Both of these are just placeholders
+   * for more useful selections.
+   */
+  public FilteredClassifier() {
+
+    this(new weka.classifiers.NaiveBayesSimple(), 
+	 new weka.filters.DiscretizeFilter());
+  }
+
+  /**
+   * Constructor that specifies the subclassifier and filter to use.
+   *
+   * @param classifier the Classifier to receive filtered instances.
+   * @param filter the Filter that will process instances before
+   * passing to the Classifier.
+   */
+  public FilteredClassifier(Classifier classifier, Filter filter) {
+
+    m_Classifier = classifier;
+    m_Filter = filter;
+  }
+
+  /**
+   * Returns an enumeration describing the available options
+   *
+   * @return an enumeration of all the available options
+   */
+  public Enumeration listOptions() {
+
+    Vector newVector = new Vector(2);
+
+    newVector.addElement(new Option(
+	      "\tFull class name of classifier to use, followed\n"
+	      + "\tby scheme options. (required)\n"
+	      + "\teg: \"weka.classifiers.NaiveBayes -D\"",
+	      "B", 1, "-B <classifier specification>"));
+    newVector.addElement(new Option(
+	      "\tFull class name of filter to use, followed\n"
+	      + "\tby filter options. (required)\n"
+	      + "\teg: \"weka.filters.AttributeFilter -V -R 1,2\"",
+	      "F", 1, "-F <filter specification>"));
+    return newVector.elements();
+  }
+
+  /**
+   * Parses a given list of options. Valid options are:<p>
+   *
+   * -B classifierstring <br>
+   * Classifierstring should contain the full class name of a classifier
+   * followed by options to the classifier.
+   * (required).<p>
+   *
+   * -F filterstring <br>
+   * Filterstring should contain the full class name of a filter
+   * followed by options to the filter.
+   * (required).<p>
+   *
+   * @param options the list of options as an array of strings
+   * @exception Exception if an option is not supported
+   */
+  public void setOptions(String[] options) throws Exception {
+
+    String classifierString = Utils.getOption('B', options);
+    if (classifierString.length() == 0) {
+      throw new Exception("A classifier must be specified"
+			  + " with the -B option.");
+    }
+    String [] classifierSpec = Utils.splitOptions(classifierString);
+    if (classifierSpec.length == 0) {
+      throw new Exception("Invalid classifier specification string");
+    }
+    String classifierName = classifierSpec[0];
+    classifierSpec[0] = "";
+    setClassifier(Classifier.forName(classifierName, classifierSpec));
+    
+    // Same for filter
+    String filterString = Utils.getOption('F', options);
+    if (filterString.length() == 0) {
+      throw new Exception("A filter must be specified"
+			  + " with the -F option.");
+    }
+    String [] filterSpec = Utils.splitOptions(filterString);
+    if (filterSpec.length == 0) {
+      throw new Exception("Invalid filter specification string");
+    }
+    String filterName = filterSpec[0];
+    filterSpec[0] = "";
+    setFilter((Filter) Utils.forName(Filter.class, filterName, filterSpec));
+  }
+
+  /**
+   * Gets the current settings of the Classifier.
+   *
+   * @return an array of strings suitable for passing to setOptions
+   */
+  public String [] getOptions() {
+
+    String [] options = new String [4];
+    int current = 0;
+
+    options[current++] = "-B";
+    options[current++] = "" + getClassifierSpec();
+
+    // Same for filter
+    options[current++] = "-F";
+    options[current++] = "" + getFilterSpec();
+    
+    while (current < options.length) {
+      options[current++] = "";
+    }
+    return options;
+  }
+
+  /**
+   * Sets the classifier
+   *
+   * @param classifier the classifier with all options set.
+   */
+  public void setClassifier(Classifier classifier) {
+
+    m_Classifier = classifier;
+  }
+
+  /**
+   * Gets the classifier used.
+   *
+   * @return the classifier
+   */
+  public Classifier getClassifier() {
+
+    return m_Classifier;
+  }
+  
+  /**
+   * Gets the classifier specification string, which contains the class name of
+   * the classifier and any options to the classifier
+   *
+   * @return the classifier string.
+   */
+  protected String getClassifierSpec() {
+    
+    Classifier c = getClassifier();
+    if (c instanceof OptionHandler) {
+      return c.getClass().getName() + " "
+	+ Utils.joinOptions(((OptionHandler)c).getOptions());
+    }
+    return c.getClass().getName();
+  }
+
+  /**
+   * Sets the filter
+   *
+   * @param filter the filter with all options set.
+   */
+  public void setFilter(Filter filter) {
+
+    m_Filter = filter;
+  }
+
+  /**
+   * Gets the filter used.
+   *
+   * @return the filter
+   */
+  public Filter getFilter() {
+
+    return m_Filter;
+  }
+  
+  /**
+   * Gets the filter specification string, which contains the class name of
+   * the filter and any options to the filter
+   *
+   * @return the filter string.
+   */
+  protected String getFilterSpec() {
+    
+    Filter c = getFilter();
+    if (c instanceof OptionHandler) {
+      return c.getClass().getName() + " "
+	+ Utils.joinOptions(((OptionHandler)c).getOptions());
+    }
+    return c.getClass().getName();
+  }
+
+  /**
+   * Build the classifier on the filtered data.
+   *
+   * @param data the training data
+   * @exception Exception if the classifier could not be built successfully
+   */
+  public void buildClassifier(Instances data) throws Exception {
+
+    if (m_Classifier == null) {
+      throw new Exception("No base classifiers have been set!");
+    }
+    /*
+    String fname = m_Filter.getClass().getName();
+    fname = fname.substring(fname.lastIndexOf('.') + 1);
+    util.Timer t = util.Timer.getTimer("FilteredClassifier::" + fname);
+    t.start();
+    */
+    m_Filter.setInputFormat(data);
+    data = Filter.useFilter(data, m_Filter);
+    //t.stop();
+    m_FilteredInstances = data.stringFreeStructure();
+    m_Classifier.buildClassifier(data);
+  }
+
+  /**
+   * Classifies a given instance after filtering.
+   *
+   * @param instance the instance to be classified
+   * @exception Exception if instance could not be classified
+   * successfully
+   */
+  public double [] distributionForInstance(Instance instance)
+    throws Exception {
+
+    /*
+      System.err.println("FilteredClassifier:: " 
+                         + m_Filter.getClass().getName()
+                         + " in: " + instance);
+    */
+    if (m_Filter.numPendingOutput() > 0) {
+      throw new Exception("Filter output queue not empty!");
+    }
+    /*
+    String fname = m_Filter.getClass().getName();
+    fname = fname.substring(fname.lastIndexOf('.') + 1);
+    util.Timer t = util.Timer.getTimer("FilteredClassifier::" + fname);
+    t.start();
+    */
+    if (!m_Filter.input(instance)) {
+      throw new Exception("Filter didn't make the test instance"
+			  + " immediately available!");
+    }
+    m_Filter.batchFinished();
+    Instance newInstance = m_Filter.output();
+    //t.stop();
+    /*
+    System.err.println("FilteredClassifier:: " 
+                       + m_Filter.getClass().getName()
+                       + " out: " + newInstance);
+    */
+    if (m_Classifier instanceof DistributionClassifier) {
+      return ((DistributionClassifier)m_Classifier)
+	.distributionForInstance(newInstance);
+    }
+    double pred = m_Classifier.classifyInstance(newInstance);
+    double [] result = new double [m_FilteredInstances.numClasses()];
+    if (Instance.isMissingValue(pred)) {
+      return result;
+    }
+    switch (instance.classAttribute().type()) {
+    case Attribute.NOMINAL:
+      result[(int) pred] = 1.0;
+      break;
+    case Attribute.NUMERIC:
+      result[0] = pred;
+      break;
+    default:
+      throw new Exception("Unknown class type");
+    }
+    return result;
+  }
+
+  /**
+   * Output a representation of this classifier
+   */
+  public String toString() {
+
+    if (m_FilteredInstances == null) {
+      return "FilteredClassifier: No model built yet.";
+    }
+
+    String result = "FilteredClassifier using "
+      + getClassifierSpec()
+      + " on data filtered through "
+      + getFilterSpec()
+      + "\n\nFiltered Header\n"
+      + m_FilteredInstances.toString()
+      + "\n\nClassifier Model\n"
+      + m_Classifier.toString();
+    return result;
+  }
+
+
+  /**
+   * Main method for testing this class.
+   *
+   * @param argv should contain the following arguments:
+   * -t training file [-T test file] [-c class index]
+   */
+  public static void main(String [] argv) {
+
+    try {
+      System.out.println("Evaluation disabled!");
+      //System.out.println(Evaluation.evaluateModel(new FilteredClassifier(),
+      //					  argv));
+    } catch (Exception e) {
+      System.err.println(e.getMessage());
+    }
+  }
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/NaiveBayesSimple.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/NaiveBayesSimple.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/classifiers/NaiveBayesSimple.java	(revision 10506)
@@ -0,0 +1,331 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    NaiveBayesSimple.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.classifiers;
+
+import java.io.*;
+import java.util.*;
+import weka.core.*;
+
+/**
+ * Class for building and using a simple Naive Bayes classifier.
+ * Numeric attributes are modelled by a normal distribution. For more
+ * information, see<p>
+ *
+ * Richard Duda and Peter Hart (1973).<i>Pattern
+ * Classification and Scene Analysis</i>. Wiley, New York.
+
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$ 
+*/
+public class NaiveBayesSimple extends DistributionClassifier {
+
+  /** All the counts for nominal attributes. */
+  private double [][][] m_Counts;
+  
+  /** The means for numeric attributes. */
+  private double [][] m_Means;
+
+  /** The standard deviations for numeric attributes. */
+  private double [][] m_Devs;
+
+  /** The prior probabilities of the classes. */
+  private double [] m_Priors;
+
+  /** The instances used for training. */
+  private Instances m_Instances;
+
+  /** Constant for normal distribution. */
+  private static double NORM_CONST = Math.sqrt(2 * Math.PI);
+
+  /**
+   * Generates the classifier.
+   *
+   * @param instances set of instances serving as training data 
+   * @exception Exception if the classifier has not been generated successfully
+   */
+  public void buildClassifier(Instances instances) throws Exception {
+
+    int attIndex = 0;
+    double sum;
+    
+    if (instances.checkForStringAttributes()) {
+      throw new Exception("Can't handle string attributes!");
+    }
+    if (instances.classAttribute().isNumeric()) {
+      throw new Exception("Naive Bayes: Class is numeric!");
+    }
+    
+    m_Instances = new Instances(instances, 0);
+    
+    // Reserve space
+    m_Counts = new double[instances.numClasses()]
+      [instances.numAttributes() - 1][0];
+    m_Means = new double[instances.numClasses()]
+      [instances.numAttributes() - 1];
+    m_Devs = new double[instances.numClasses()]
+      [instances.numAttributes() - 1];
+    m_Priors = new double[instances.numClasses()];
+    Enumeration enum = instances.enumerateAttributes();
+    while (enum.hasMoreElements()) {
+      Attribute attribute = (Attribute) enum.nextElement();
+      if (attribute.isNominal()) {
+	for (int j = 0; j < instances.numClasses(); j++) {
+	  m_Counts[j][attIndex] = new double[attribute.numValues()];
+	}
+      } else {
+	for (int j = 0; j < instances.numClasses(); j++) {
+	  m_Counts[j][attIndex] = new double[1];
+	}
+      }
+      attIndex++;
+    }
+    
+    // Compute counts and sums
+    Enumeration enumInsts = instances.enumerateInstances();
+    while (enumInsts.hasMoreElements()) {
+      Instance instance = (Instance) enumInsts.nextElement();
+      if (!instance.classIsMissing()) {
+	Enumeration enumAtts = instances.enumerateAttributes();
+	attIndex = 0;
+	while (enumAtts.hasMoreElements()) {
+	  Attribute attribute = (Attribute) enumAtts.nextElement();
+	  if (!instance.isMissing(attribute)) {
+	    if (attribute.isNominal()) {
+	      m_Counts[(int)instance.classValue()][attIndex]
+		[(int)instance.value(attribute)]++;
+	    } else {
+	      m_Means[(int)instance.classValue()][attIndex] +=
+		instance.value(attribute);
+	      m_Counts[(int)instance.classValue()][attIndex][0]++;
+	    }
+	  }
+	  attIndex++;
+	}
+	m_Priors[(int)instance.classValue()]++;
+      }
+    }
+    
+    // Compute means
+    Enumeration enumAtts = instances.enumerateAttributes();
+    attIndex = 0;
+    while (enumAtts.hasMoreElements()) {
+      Attribute attribute = (Attribute) enumAtts.nextElement();
+      if (attribute.isNumeric()) {
+	for (int j = 0; j < instances.numClasses(); j++) {
+	  if (m_Counts[j][attIndex][0] < 2) {
+	    throw new Exception("attribute " + attribute.name() +
+				": less than two values for class " +
+				instances.classAttribute().value(j));
+	  }
+	  m_Means[j][attIndex] /= m_Counts[j][attIndex][0];
+	}
+      }
+      attIndex++;
+    }    
+    
+    // Compute standard deviations
+    enumInsts = instances.enumerateInstances();
+    while (enumInsts.hasMoreElements()) {
+      Instance instance = 
+	(Instance) enumInsts.nextElement();
+      if (!instance.classIsMissing()) {
+	enumAtts = instances.enumerateAttributes();
+	attIndex = 0;
+	while (enumAtts.hasMoreElements()) {
+	  Attribute attribute = (Attribute) enumAtts.nextElement();
+	  if (!instance.isMissing(attribute)) {
+	    if (attribute.isNumeric()) {
+	      m_Devs[(int)instance.classValue()][attIndex] +=
+		(m_Means[(int)instance.classValue()][attIndex]-
+		 instance.value(attribute))*
+		(m_Means[(int)instance.classValue()][attIndex]-
+		 instance.value(attribute));
+	    }
+	  }
+	  attIndex++;
+	}
+      }
+    }
+    enumAtts = instances.enumerateAttributes();
+    attIndex = 0;
+    while (enumAtts.hasMoreElements()) {
+      Attribute attribute = (Attribute) enumAtts.nextElement();
+      if (attribute.isNumeric()) {
+	for (int j = 0; j < instances.numClasses(); j++) {
+	  if (m_Devs[j][attIndex] <= 0) {
+	    throw new Exception("attribute " + attribute.name() +
+				": standard deviation is 0 for class " +
+				instances.classAttribute().value(j));
+	  }
+	  else {
+	    m_Devs[j][attIndex] /= m_Counts[j][attIndex][0] - 1;
+	    m_Devs[j][attIndex] = Math.sqrt(m_Devs[j][attIndex]);
+	  }
+	}
+      }
+      attIndex++;
+    } 
+    
+    // Normalize counts
+    enumAtts = instances.enumerateAttributes();
+    attIndex = 0;
+    while (enumAtts.hasMoreElements()) {
+      Attribute attribute = (Attribute) enumAtts.nextElement();
+      if (attribute.isNominal()) {
+	for (int j = 0; j < instances.numClasses(); j++) {
+	  sum = Utils.sum(m_Counts[j][attIndex]);
+	  for (int i = 0; i < attribute.numValues(); i++) {
+	    m_Counts[j][attIndex][i] =
+	      (m_Counts[j][attIndex][i] + 1) 
+	      / (sum + (double)attribute.numValues());
+	  }
+	}
+      }
+      attIndex++;
+    }
+    
+    // Normalize priors
+    sum = Utils.sum(m_Priors);
+    for (int j = 0; j < instances.numClasses(); j++)
+      m_Priors[j] = (m_Priors[j] + 1) 
+	/ (sum + (double)instances.numClasses());
+  }
+
+  /**
+   * Calculates the class membership probabilities for the given test instance.
+   *
+   * @param instance the instance to be classified
+   * @return predicted class probability distribution
+   * @exception Exception if distribution can't be computed
+   */
+  public double[] distributionForInstance(Instance instance) throws Exception {
+    
+    double [] probs = new double[instance.numClasses()];
+    int attIndex;
+    
+    for (int j = 0; j < instance.numClasses(); j++) {
+      probs[j] = 1;
+      Enumeration enumAtts = instance.enumerateAttributes();
+      attIndex = 0;
+      while (enumAtts.hasMoreElements()) {
+	Attribute attribute = (Attribute) enumAtts.nextElement();
+	if (!instance.isMissing(attribute)) {
+	  if (attribute.isNominal()) {
+	    probs[j] *= m_Counts[j][attIndex][(int)instance.value(attribute)];
+	  } else {
+	    probs[j] *= normalDens(instance.value(attribute),
+				   m_Means[j][attIndex],
+				   m_Devs[j][attIndex]);}
+	}
+	attIndex++;
+      }
+      probs[j] *= m_Priors[j];
+    }
+    
+    // Normalize probabilities
+    Utils.normalize(probs);
+
+    return probs;
+  }
+
+  /**
+   * Returns a description of the classifier.
+   *
+   * @return a description of the classifier as a string.
+   */
+  public String toString() {
+
+    if (m_Instances == null) {
+      return "Naive Bayes (simple): No model built yet.";
+    }
+    try {
+      StringBuffer text = new StringBuffer("Naive Bayes (simple)");
+      int attIndex;
+      
+      for (int i = 0; i < m_Instances.numClasses(); i++) {
+	text.append("\n\nClass " + m_Instances.classAttribute().value(i) 
+		    + ": P(C) = " 
+		    + Utils.doubleToString(m_Priors[i], 10, 8)
+		    + "\n\n");
+	Enumeration enumAtts = m_Instances.enumerateAttributes();
+	attIndex = 0;
+	while (enumAtts.hasMoreElements()) {
+	  Attribute attribute = (Attribute) enumAtts.nextElement();
+	  text.append("Attribute " + attribute.name() + "\n");
+	  if (attribute.isNominal()) {
+	    for (int j = 0; j < attribute.numValues(); j++) {
+	      text.append(attribute.value(j) + "\t");
+	    }
+	    text.append("\n");
+	    for (int j = 0; j < attribute.numValues(); j++)
+	      text.append(Utils.
+			  doubleToString(m_Counts[i][attIndex][j], 10, 8)
+			  + "\t");
+	  } else {
+	    text.append("Mean: " + Utils.
+			doubleToString(m_Means[i][attIndex], 10, 8) + "\t");
+	    text.append("Standard Deviation: " 
+			+ Utils.doubleToString(m_Devs[i][attIndex], 10, 8));
+	  }
+	  text.append("\n\n");
+	  attIndex++;
+	}
+      }
+      
+      return text.toString();
+    } catch (Exception e) {
+      return "Can't print Naive Bayes classifier!";
+    }
+  }
+
+  /**
+   * Density function of normal distribution.
+   */
+  private double normalDens(double x, double mean, double stdDev) {
+    
+    double diff = x - mean;
+    
+    return (1 / (NORM_CONST * stdDev)) 
+      * Math.exp(-(diff * diff / (2 * stdDev * stdDev)));
+  }
+
+  /**
+   * Main method for testing this class.
+   *
+   * @param argv the options
+   */
+  public static void main(String [] argv) {
+
+    Classifier scheme;
+
+    try {
+      scheme = new NaiveBayesSimple();
+      System.out.println("Evaluation disabled!");
+      //System.out.println(Evaluation.evaluateModel(scheme, argv));
+    } catch (Exception e) {
+      System.err.println(e.getMessage());
+    }
+  }
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Attribute.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Attribute.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Attribute.java	(revision 10506)
@@ -0,0 +1,682 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Attribute.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+import java.io.*;
+import java.util.*;
+
+/** 
+ * Class for handling an attribute. Once an attribute has been created,
+ * it can't be changed. <p>
+ *
+ * Three attribute types are supported:
+ * <ul>
+ *    <li> numeric: <ul>
+ *         This type of attribute represents a floating-point number.
+ *    </ul>
+ *    <li> nominal: <ul>
+ *         This type of attribute represents a fixed set of nominal values.
+ *    </ul>
+ *    <li> string: <ul>
+ *         This type of attribute represents a dynamically expanding set of
+ *         nominal values. String attributes are not used by the learning
+ *         schemes in Weka. They can be used, for example,  to store an 
+ *         identifier with each instance in a dataset.
+ *    </ul>
+ * </ul>
+ * Typical usage (code from the main() method of this class): <p>
+ *
+ * <code>
+ * ... <br>
+ *
+ * // Create numeric attributes "length" and "weight" <br>
+ * Attribute length = new Attribute("length"); <br>
+ * Attribute weight = new Attribute("weight"); <br><br>
+ * 
+ * // Create vector to hold nominal values "first", "second", "third" <br>
+ * FastVector my_nominal_values = new FastVector(3); <br>
+ * my_nominal_values.addElement("first"); <br>
+ * my_nominal_values.addElement("second"); <br>
+ * my_nominal_values.addElement("third"); <br><br>
+ *
+ * // Create nominal attribute "position" <br>
+ * Attribute position = new Attribute("position", my_nominal_values);<br>
+ *
+ * ... <br>
+ * </code><p>
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public class Attribute implements Copyable, Serializable {
+
+  /** Constant set for numeric attributes. */
+  public final static int NUMERIC = 0;
+
+  /** Constant set for nominal attributes. */
+  public final static int NOMINAL = 1;
+
+  /** Constant set for attributes with string values. */
+  public final static int STRING = 2;
+
+  /** Strings longer than this will be stored compressed. */
+  private final static int STRING_COMPRESS_THRESHOLD = 200;
+  //private final static int STRING_COMPRESS_THRESHOLD = Integer.MAX_VALUE;
+
+  /** The attribute's name. */
+  private String m_Name;
+
+  /** The attribute's type. */
+  private int m_Type;
+
+  /** The attribute's values (if nominal or string). */
+  private FastVector m_Values;
+
+  /** Mapping of values to indices (if nominal or string). */
+  private Hashtable m_Hashtable;
+
+  /** The attribute's index. */
+  private int m_Index;
+
+  /**
+   * Constructor for a numeric attribute.
+   *
+   * @param attributeName the name for the attribute
+   */
+  public Attribute(String attributeName) {
+
+    m_Name = attributeName;
+    m_Index = -1;
+    m_Values = null;
+    m_Hashtable = null;
+    m_Type = NUMERIC;
+  }
+
+  /**
+   * Constructor for nominal attributes and string attributes.
+   * If a null vector of attribute values is passed to the method,
+   * the attribute is assumed to be a string.
+   *
+   * @param attributeName the name for the attribute
+   * @param attributeValues a vector of strings denoting the 
+   * attribute values. Null if the attribute is a string attribute.
+   */
+  public Attribute(String attributeName, 
+		   FastVector attributeValues) {
+
+    m_Name = attributeName;
+    m_Index = -1;
+    if (attributeValues == null) {
+      m_Values = new FastVector();
+      m_Hashtable = new Hashtable();
+      m_Type = STRING;
+    } else {
+      m_Values = (FastVector) attributeValues.copy();
+      m_Hashtable = new Hashtable(m_Values.size());
+      for (int i = 0; i < m_Values.size(); i++) {
+	m_Hashtable.put(m_Values.elementAt(i), new Integer(i));
+      }
+      m_Type = NOMINAL;
+    }
+  }
+
+  /**
+   * Produces a shallow copy of this attribute.
+   *
+   * @return a copy of this attribute with the same index
+   */
+  public Object copy() {
+
+    Attribute copy = new Attribute(m_Name);
+
+    copy.m_Index = m_Index;
+    if (!isNominal() && !isString())
+      return copy;
+    copy.m_Type = m_Type;
+    copy.m_Values = m_Values;
+    copy.m_Hashtable = m_Hashtable;
+ 
+    return copy;
+  }
+
+  /**
+   * Returns an enumeration of all the attribute's values if
+   * the attribute is nominal or a string, null otherwise. 
+   *
+   * @return enumeration of all the attribute's values
+   */
+  public final Enumeration enumerateValues() {
+
+    if (isNominal() || isString()) {
+      final Enumeration ee = m_Values.elements();
+      return new Enumeration () {
+          public boolean hasMoreElements() {
+            return ee.hasMoreElements();
+          }
+          public Object nextElement() {
+            Object oo = ee.nextElement();
+            if (oo instanceof SerializedObject) {
+              return ((SerializedObject)oo).getObject();
+            } else {
+              return oo;
+            }
+          }
+        };
+    }
+    return null;
+  }
+
+  /**
+   * Tests if given attribute is equal to this attribute.
+   *
+   * @param other the Object to be compared to this attribute
+   * @return true if the given attribute is equal to this attribute
+   */
+  public final boolean equals(Object other) {
+
+    if ((other == null) || !(other.getClass().equals(this.getClass()))) {
+      return false;
+    }
+    Attribute att = (Attribute) other;
+    if (!m_Name.equals(att.m_Name)) {
+      return false;
+    }
+    if (isNumeric() && att.isNumeric()) {
+      return true;
+    }
+    if (isNumeric() || att.isNumeric()) {
+      return false;
+    }
+    if (m_Values.size() != att.m_Values.size()) {
+      return false;
+    }
+    for (int i = 0; i < m_Values.size(); i++) {
+      if (!m_Values.elementAt(i).equals(att.m_Values.elementAt(i))) {
+	return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Returns the index of this attribute.
+   *
+   * @return the index of this attribute
+   */
+  public final int index() {
+
+    return m_Index;
+  }
+
+  /**
+   * Returns the index of a given attribute value. (The index of
+   * the first occurence of this value.)
+   *
+   * @param value the value for which the index is to be returned
+   * @return the index of the given attribute value if attribute
+   * is nominal or a string, -1 if it is numeric or the value 
+   * can't be found
+   */
+  public final int indexOfValue(String value) {
+
+    if (!isNominal() && !isString())
+      return -1;
+    Object store = value;
+    if (value.length() > STRING_COMPRESS_THRESHOLD) {
+      try {
+        store = new SerializedObject(value, true);
+      } catch (Exception ex) {
+        System.err.println("Couldn't compress string attribute value -"
+                           + " searching uncompressed.");
+      }
+    }
+    Integer val = (Integer)m_Hashtable.get(store);
+    if (val == null) {
+      throw new IllegalArgumentException("Value \"" + value + 
+					 "\" not found in attribute " +
+					 "declaration!");
+    } else {
+      return val.intValue();
+    }
+  }
+
+  /**
+   * Test if the attribute is nominal.
+   *
+   * @return true if the attribute is nominal
+   */
+  public final boolean isNominal() {
+
+    return (m_Type == NOMINAL);
+  }
+
+  /**
+   * Tests if the attribute is numeric.
+   *
+   * @return true if the attribute is numeric
+   */
+  public final boolean isNumeric() {
+
+    return (m_Type == NUMERIC);
+  }
+
+  /**
+   * Tests if the attribute is a string.
+   *
+   * @return true if the attribute is a string
+   */
+  public final boolean isString() {
+
+    return (m_Type == STRING);
+  }
+
+  /**
+   * Returns the attribute's name.
+   *
+   * @return the attribute's name as a string
+   */
+  public final String name() {
+
+    return m_Name;
+  }
+  
+  /**
+   * Returns the number of attribute values. Returns 0 for numeric attributes.
+   *
+   * @return the number of attribute values
+   */
+  public final int numValues() {
+
+    if (!isNominal() && !isString()) {
+      return 0;
+    } else {
+      return m_Values.size();
+    }
+  }
+
+  /**
+   * Returns a description of this attribute in ARFF format. Quotes
+   * strings if they contain whitespace characters, or if they
+   * are a question mark.
+   *
+   * @return a description of this attribute as a string
+   */
+  public final String toString() {
+    
+    StringBuffer text = new StringBuffer();
+    
+    text.append("@attribute " + Utils.quote(m_Name) + " ");
+    if (isNominal()) {
+      text.append('{');
+      Enumeration enum = enumerateValues();
+      while (enum.hasMoreElements()) {
+	text.append(Utils.quote((String) enum.nextElement()));
+	if (enum.hasMoreElements())
+	  text.append(',');
+      }
+      text.append('}');
+    } else {
+      if (isNumeric()) {
+	text.append("numeric");
+      } else {
+	text.append("string");
+      }
+    }
+    return text.toString();
+  }
+
+  /**
+   * Returns the attribute's type as an integer.
+   *
+   * @returns the attribute's type.
+   */
+  public final int type() {
+
+    return m_Type;
+  }
+
+  /**
+   * Returns a value of a nominal or string attribute. 
+   * Returns an empty string if the attribute is neither
+   * nominal nor a string attribute.
+   *
+   * @param valIndex the value's index
+   * @return the attribute's value as a string
+   */
+  public final String value(int valIndex) {
+    
+    if (!isNominal() && !isString()) {
+      return "";
+    } else {
+      Object val = m_Values.elementAt(valIndex);
+      
+      // If we're storing strings compressed, uncompress it.
+      if (val instanceof SerializedObject) {
+        val = ((SerializedObject)val).getObject();
+      }
+      return (String) val;
+    }
+  }
+
+  /**
+   * Constructor for a numeric attribute with a particular index.
+   *
+   * @param attributeName the name for the attribute
+   * @param index the attribute's index
+   */
+  Attribute(String attributeName, int index) {
+
+    this(attributeName);
+
+    m_Index = index;
+  }
+
+  /**
+   * Constructor for nominal attributes and string attributes with
+   * a particular index.
+   * If a null vector of attribute values is passed to the method,
+   * the attribute is assumed to be a string.
+   *
+   * @param attributeName the name for the attribute
+   * @param attributeValues a vector of strings denoting the attribute values.
+   * Null if the attribute is a string attribute.
+   * @param index the attribute's index
+   */
+  Attribute(String attributeName, FastVector attributeValues, 
+	    int index) {
+
+    this(attributeName, attributeValues);
+
+    m_Index = index;
+  }
+
+  /**
+   * Adds a string value to the list of valid strings for attributes
+   * of type STRING and returns the index of the string.
+   *
+   * @param value The string value to add
+   * @return the index assigned to the string, or -1 if the attribute is not
+   * of type Attribute.STRING 
+   */
+  public int addStringValue(String value) {
+
+    if (!isString()) {
+      return -1;
+    }
+    Object store = value;
+
+    if (value.length() > STRING_COMPRESS_THRESHOLD) {
+      try {
+        store = new SerializedObject(value, true);
+      } catch (Exception ex) {
+        System.err.println("Couldn't compress string attribute value -"
+                           + " storing uncompressed.");
+      }
+    }
+    Integer index = (Integer)m_Hashtable.get(store);
+    if (index != null) {
+      return index.intValue();
+    } else {
+      int intIndex = m_Values.size();
+      m_Values.addElement(store);
+      m_Hashtable.put(store, new Integer(intIndex));
+      return intIndex;
+    }
+  }
+
+  /**
+   * Adds a string value to the list of valid strings for attributes
+   * of type STRING and returns the index of the string. This method is
+   * more efficient than addStringValue(String) for long strings.
+   *
+   * @param src The Attribute containing the string value to add.
+   * @param int index the index of the string value in the source attribute.
+   * @return the index assigned to the string, or -1 if the attribute is not
+   * of type Attribute.STRING 
+   */
+  public int addStringValue(Attribute src, int index) {
+
+    if (!isString()) {
+      return -1;
+    }
+    Object store = src.m_Values.elementAt(index);
+    Integer oldIndex = (Integer)m_Hashtable.get(store);
+    if (oldIndex != null) {
+      return oldIndex.intValue();
+    } else {
+      int intIndex = m_Values.size();
+      m_Values.addElement(store);
+      m_Hashtable.put(store, new Integer(intIndex));
+      return intIndex;
+    }
+  }
+
+  /**
+   * Adds an attribute value. Creates a fresh list of attribute
+   * values before adding it.
+   *
+   * @param value the attribute value
+   */
+  final void addValue(String value) {
+
+    m_Values = (FastVector)m_Values.copy();
+    m_Hashtable = (Hashtable)m_Hashtable.clone();
+    forceAddValue(value);
+  }
+
+  /**
+   * Produces a shallow copy of this attribute with a new name.
+   *
+   * @param newName the name of the new attribute
+   * @return a copy of this attribute with the same index
+   */
+  final Attribute copy(String newName) {
+
+    Attribute copy = new Attribute(newName);
+
+    copy.m_Index = m_Index;
+    if (!isNominal() && !isString())
+      return copy;
+    copy.m_Type = m_Type;
+    copy.m_Values = m_Values;
+    copy.m_Hashtable = m_Hashtable;
+ 
+    return copy;
+  }
+
+  /**
+   * Removes a value of a nominal or string attribute. Creates a 
+   * fresh list of attribute values before removing it.
+   *
+   * @param index the value's index
+   * @exception IllegalArgumentException if the attribute is not nominal
+   */
+  final void delete(int index) {
+    
+    if (!isNominal() && !isString()) 
+      throw new IllegalArgumentException("Can only remove value of" +
+                                         "nominal or string attribute!");
+    else {
+      m_Values = (FastVector)m_Values.copy();
+      m_Values.removeElementAt(index);
+      Hashtable hash = new Hashtable(m_Hashtable.size());
+      Enumeration enum = hash.keys();
+      while (enum.hasMoreElements()) {
+	String string = (String)enum.nextElement();
+	Integer valIndexObject = (Integer)m_Hashtable.get(string);
+	int valIndex = valIndexObject.intValue();
+	if (valIndex > index) {
+	  hash.put(string, new Integer(valIndex - 1));
+	} else if (valIndex < index) {
+	  hash.put(string, valIndexObject);
+	}
+      }
+      m_Hashtable = hash;
+    }
+  }
+
+  /**
+   * Adds an attribute value.
+   *
+   * @param value the attribute value
+   */
+  final void forceAddValue(String value) {
+
+    Object store = value;
+    if (value.length() > STRING_COMPRESS_THRESHOLD) {
+      try {
+        store = new SerializedObject(value, true);
+      } catch (Exception ex) {
+        System.err.println("Couldn't compress string attribute value -"
+                           + " storing uncompressed.");
+      }
+    }
+    m_Values.addElement(store);
+    m_Hashtable.put(store, new Integer(m_Values.size() - 1));
+  }
+
+  /**
+   * Sets the index of this attribute.
+   *
+   * @param the index of this attribute
+   */
+  final void setIndex(int index) {
+
+    m_Index = index;
+  }
+
+  /**
+   * Sets a value of a nominal attribute or string attribute.
+   * Creates a fresh list of attribute values before it is set.
+   *
+   * @param index the value's index
+   * @param string the value
+   * @exception IllegalArgumentException if the attribute is not nominal or 
+   * string.
+   */
+  final void setValue(int index, String string) {
+
+    if (!isNominal() && !isString()) {
+      throw new IllegalArgumentException("Can only set value of nominal"+
+                                         "or string attribute!");
+    } else {
+      m_Values = (FastVector)m_Values.copy();
+      m_Hashtable = (Hashtable)m_Hashtable.clone();
+      Object store = string;
+      if (string.length() > STRING_COMPRESS_THRESHOLD) {
+        try {
+          store = new SerializedObject(string, true);
+        } catch (Exception ex) {
+          System.err.println("Couldn't compress string attribute value -"
+                             + " storing uncompressed.");
+        }
+      }
+      m_Hashtable.remove(m_Values.elementAt(index));
+      m_Values.setElementAt(store, index);
+      m_Hashtable.put(store, new Integer(index));
+    }
+  }
+
+  /**
+   * Simple main method for testing this class.
+   */
+  public static void main(String[] ops) {
+
+    try {
+      
+      // Create numeric attributes "length" and "weight"
+      Attribute length = new Attribute("length");
+      Attribute weight = new Attribute("weight");
+      
+      // Create vector to hold nominal values "first", "second", "third" 
+      FastVector my_nominal_values = new FastVector(3); 
+      my_nominal_values.addElement("first"); 
+      my_nominal_values.addElement("second"); 
+      my_nominal_values.addElement("third"); 
+      
+      // Create nominal attribute "position" 
+      Attribute position = new Attribute("position", my_nominal_values);
+
+      // Print the name of "position"
+      System.out.println("Name of \"position\": " + position.name());
+
+      // Print the values of "position"
+      Enumeration attValues = position.enumerateValues();
+      while (attValues.hasMoreElements()) {
+	String string = (String)attValues.nextElement();
+	System.out.println("Value of \"position\": " + string);
+      }
+
+      // Shallow copy attribute "position"
+      Attribute copy = (Attribute) position.copy();
+
+      // Test if attributes are the same
+      System.out.println("Copy is the same as original: " + copy.equals(position));
+
+      // Print index of attribute "weight" (should be unset: -1)
+      System.out.println("Index of attribute \"weight\" (should be -1): " + 
+			 weight.index());
+
+      // Print index of value "first" of attribute "position"
+      System.out.println("Index of value \"first\" of \"position\" (should be 0): " +
+			 position.indexOfValue("first"));
+
+      // Tests type of attribute "position"
+      System.out.println("\"position\" is numeric: " + position.isNumeric());
+      System.out.println("\"position\" is nominal: " + position.isNominal());
+      System.out.println("\"position\" is string: " + position.isString());
+
+      // Prints name of attribute "position"
+      System.out.println("Name of \"position\": " + position.name());
+    
+      // Prints number of values of attribute "position"
+      System.out.println("Number of values for \"position\": " + position.numValues());
+
+      // Prints the values (againg)
+      for (int i = 0; i < position.numValues(); i++) {
+	System.out.println("Value " + i + ": " + position.value(i));
+      }
+
+      // Prints the attribute "position" in ARFF format
+      System.out.println(position);
+
+      // Checks type of attribute "position" using constants
+      switch (position.type()) {
+      case Attribute.NUMERIC:
+	System.out.println("\"position\" is numeric");
+	break;
+      case Attribute.NOMINAL:
+	System.out.println("\"position\" is nominal");
+	break;
+      case Attribute.STRING:
+	System.out.println("\"position\" is string");
+	break;
+      default:
+	System.out.println("\"position\" has unknown type");
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
+  
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/AttributeStats.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/AttributeStats.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/AttributeStats.java	(revision 10506)
@@ -0,0 +1,136 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    AttributeStats.java
+ *    Copyright (C) 1999 Len Trigg
+ *
+ */
+
+package weka.core;
+
+/**
+ * A Utility class that contains summary information on an
+ * the values that appear in a dataset for a particular attribute.
+ *
+ * @author <a href="mailto:len@webmind.com">Len Trigg</a>
+ * @version $Revision$
+ */
+public class AttributeStats {    
+  
+  /** The number of int-like values */
+  public int intCount = 0;
+  
+  /** The number of real-like values (i.e. have a fractional part) */
+  public int realCount = 0;
+  
+  /** The number of missing values */
+  public int missingCount = 0;
+  
+  /** The number of distinct values */
+  public int distinctCount = 0;
+  
+  /** The number of values that only appear once */
+  public int uniqueCount = 0;
+  
+  /** The total number of values (i.e. number of instances) */
+  public int totalCount = 0;
+  
+  /** Stats on numeric value distributions */
+  // perhaps Stats should be moved from weka.experiment to weka.core
+  public weka.experiment.Stats numericStats;
+  
+  /** Counts of each nominal value */
+  public int [] nominalCounts;
+    
+  /**
+   * Updates the counters for one more observed distinct value.
+   *
+   * @param value the value that has just been seen
+   * @param count the number of times the value appeared
+   */
+  protected void addDistinct(double value, int count) {
+    
+    if (count > 0) {
+      if (count == 1) {
+	uniqueCount++;
+	}
+      if (Utils.eq(value, (double)((int)value))) {
+	intCount += count;
+      } else {
+	realCount += count;
+      }
+      if (nominalCounts != null) {
+	nominalCounts[(int)value] = count;
+      }
+      if (numericStats != null) {
+	  numericStats.add(value, count);
+	  numericStats.calculateDerived();
+      }
+    }
+    distinctCount++;
+  }
+
+  /**
+   * Returns a human readable representation of this AttributeStats instance.
+   *
+   * @return a String represtinging these AttributeStats.
+   */
+  public String toString() {
+
+    StringBuffer sb = new StringBuffer();
+    sb.append(Utils.padLeft("Type", 4)).append(Utils.padLeft("Nom", 5));
+    sb.append(Utils.padLeft("Int", 5)).append(Utils.padLeft("Real", 5));
+    sb.append(Utils.padLeft("Missing", 12));
+    sb.append(Utils.padLeft("Unique", 12));
+    sb.append(Utils.padLeft("Dist", 6));
+    if (nominalCounts != null) {
+      sb.append(' ');
+      for (int i = 0; i < nominalCounts.length; i++) {
+        sb.append(Utils.padLeft("C[" + i + "]", 5));
+      }
+    }
+    sb.append('\n');
+
+    long percent;
+    percent = Math.round(100.0 * intCount / totalCount);
+    if (nominalCounts != null) {
+      sb.append(Utils.padLeft("Nom", 4)).append(' ');
+      sb.append(Utils.padLeft("" + percent, 3)).append("% ");
+      sb.append(Utils.padLeft("" + 0, 3)).append("% ");
+    } else {
+      sb.append(Utils.padLeft("Num", 4)).append(' ');
+      sb.append(Utils.padLeft("" + 0, 3)).append("% ");
+      sb.append(Utils.padLeft("" + percent, 3)).append("% ");
+    }
+    percent = Math.round(100.0 * realCount / totalCount);
+    sb.append(Utils.padLeft("" + percent, 3)).append("% ");
+    sb.append(Utils.padLeft("" + missingCount, 5)).append(" /");
+    percent = Math.round(100.0 * missingCount / totalCount);
+    sb.append(Utils.padLeft("" + percent, 3)).append("% ");
+    sb.append(Utils.padLeft("" + uniqueCount, 5)).append(" /");
+    percent = Math.round(100.0 * uniqueCount / totalCount);
+    sb.append(Utils.padLeft("" + percent, 3)).append("% ");
+    sb.append(Utils.padLeft("" + distinctCount, 5)).append(' ');
+    if (nominalCounts != null) {
+      for (int i = 0; i < nominalCounts.length; i++) {
+        sb.append(Utils.padLeft("" + nominalCounts[i], 5));
+      }
+    }
+    sb.append('\n');
+    return sb.toString();
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/ContingencyTables.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/ContingencyTables.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/ContingencyTables.java	(revision 10506)
@@ -0,0 +1,635 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    ContingencyTables.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+/**
+ * Class implementing some statistical routines for contingency tables.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public class ContingencyTables {
+
+  /** The natural logarithm of 2 */
+  private static double log2 = Math.log(2);
+
+  /**
+   * Returns chi-squared probability for a given matrix.
+   *
+   * @param matrix the contigency table
+   * @param yates is Yates' correction to be used?
+   * @return the chi-squared probability
+   */
+
+  public static double chiSquared(double [][] matrix, boolean yates) {
+
+    int df = (matrix.length - 1) * (matrix[0].length - 1);
+
+    return Statistics.chiSquaredProbability(chiVal(matrix, yates), df);
+  }
+
+  /**
+   * Computes chi-squared statistic for a contingency table.
+   *
+   * @param matrix the contigency table
+   * @param yates is Yates' correction to be used?
+   * @return the value of the chi-squared statistic
+   */
+  public static double chiVal(double [][] matrix, boolean useYates) {
+    
+    int df, nrows, ncols, row, col;
+    double[] rtotal, ctotal;
+    double expect = 0, chival = 0, n = 0;
+    boolean yates = true;
+    
+    nrows = matrix.length;
+    ncols = matrix[0].length;
+    rtotal = new double [nrows];
+    ctotal = new double [ncols];
+    for (row = 0; row < nrows; row++) {
+      for (col = 0; col < ncols; col++) {
+	rtotal[row] += matrix[row][col];
+	ctotal[col] += matrix[row][col];
+	n += matrix[row][col];
+      }
+    }
+    df = (nrows - 1)*(ncols - 1);
+    if ((df > 1) || (!useYates)) {
+      yates = false;
+    } else if (df <= 0) {
+      return 0;
+    }
+    chival = 0.0;
+    for (row = 0; row < nrows; row++) {
+      if (Utils.gr(rtotal[row], 0)) {
+	for (col = 0; col < ncols; col++) {
+	  if (Utils.gr(ctotal[col], 0)) {
+	    expect = (ctotal[col] * rtotal[row]) / n;
+	    chival += chiCell (matrix[row][col], expect, yates);
+	  }
+	}
+      }
+    }
+    return chival;
+  }
+
+  /**
+   * Tests if Cochran's criterion is fullfilled for the given
+   * contingency table. Rows and columns with all zeros are not considered
+   * relevant.
+   *
+   * @param matrix the contigency table to be tested
+   * @return true if contingency table is ok, false if not
+   */
+  public static boolean cochransCriterion(double[][] matrix) {
+
+    double[] rtotal, ctotal;
+    double n = 0, expect, smallfreq = 5;
+    int smallcount = 0, nonZeroRows = 0, nonZeroColumns = 0, nrows, ncols, 
+      row, col;
+
+    nrows = matrix.length;
+    ncols = matrix[0].length;
+
+    rtotal = new double [nrows];
+    ctotal = new double [ncols];
+    for (row = 0; row < nrows; row++) {
+      for (col = 0; col < ncols; col++) {
+	rtotal[row] += matrix[row][col];
+	ctotal[col] += matrix[row][col];
+	n += matrix[row][col];
+      }
+    }
+    for (row = 0; row < nrows; row++) {
+      if (Utils.gr(rtotal[row], 0)) {
+	nonZeroRows++;
+      }
+    }
+    for (col = 0; col < ncols; col++) {
+      if (Utils.gr(ctotal[col], 0)) {
+	nonZeroColumns++;
+      }
+    }
+    for (row = 0; row < nrows; row++) {
+      if (Utils.gr(rtotal[row], 0)) {
+	for (col = 0; col < ncols; col++) {
+	  if (Utils.gr(ctotal[col], 0)) {
+	    expect = (ctotal[col] * rtotal[row]) / n;
+	    if (Utils.sm(expect, smallfreq)) {
+	      if (Utils.sm(expect, 1)) {
+		return false;
+	      } else {
+		smallcount++;
+		if (smallcount > (nonZeroRows * nonZeroColumns) / smallfreq) {
+		  return false;
+		}
+	      }
+	    }
+	  }
+	}
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Computes Cramer's V for a contingency table.
+   *
+   * @param matrix the contingency table
+   * @return Cramer's V
+   */
+  public static double CramersV(double [][] matrix) {
+
+    int row, col, nrows,ncols, min;
+    double n = 0;
+    
+    nrows = matrix.length;
+    ncols = matrix[0].length;
+    for (row = 0; row < nrows; row++) {
+      for (col = 0; col < ncols; col++) {
+	n += matrix[row][col];
+      }
+    }
+    min = nrows < ncols ? nrows-1 : ncols-1;
+    if ((min == 0) || Utils.eq(n, 0))
+      return 0;
+    return Math.sqrt(chiVal(matrix, false) / (n * (double)min)); 
+  } 
+
+  /**
+   * Computes the entropy of the given array.
+   *
+   * @param array the array
+   * @return the entropy
+   */
+  public static double entropy(double[] array) {
+
+    double returnValue = 0, sum = 0;
+
+    for (int i = 0; i < array.length; i++) {
+      returnValue -= lnFunc(array[i]);
+      sum += array[i];
+    }
+    if (Utils.eq(sum, 0)) {
+      return 0;
+    } else {
+      return (returnValue + lnFunc(sum)) / (sum * log2);
+    }
+  }
+
+  /**
+   * Computes conditional entropy of the rows given
+   * the columns.
+   *
+   * @param matrix the contingency table
+   * @return the conditional entropy of the rows given the columns
+   */
+  public static double entropyConditionedOnColumns(double[][] matrix) {
+    
+    double returnValue = 0, sumForColumn, total = 0;
+
+    for (int j = 0; j < matrix[0].length; j++) {
+      sumForColumn = 0;
+      for (int i = 0; i < matrix.length; i++) {
+	returnValue = returnValue + lnFunc(matrix[i][j]);
+	sumForColumn += matrix[i][j];
+      }
+      returnValue = returnValue - lnFunc(sumForColumn);
+      total += sumForColumn;
+    }
+    if (Utils.eq(total, 0)) {
+      return 0;
+    }
+    return -returnValue / (total * log2);
+  }
+
+  /**
+   * Computes conditional entropy of the columns given
+   * the rows.
+   *
+   * @param matrix the contingency table
+   * @return the conditional entropy of the columns given the rows
+   */
+  public static double entropyConditionedOnRows(double[][] matrix) {
+    
+    double returnValue = 0, sumForRow, total = 0;
+
+    for (int i = 0; i < matrix.length; i++) {
+      sumForRow = 0;
+      for (int j = 0; j < matrix[0].length; j++) {
+	returnValue = returnValue + lnFunc(matrix[i][j]);
+	sumForRow += matrix[i][j];
+      }
+      returnValue = returnValue - lnFunc(sumForRow);
+      total += sumForRow;
+    }
+    if (Utils.eq(total, 0)) {
+      return 0;
+    }
+    return -returnValue / (total * log2);
+  }
+
+  /**
+   * Computes conditional entropy of the columns given the rows
+   * of the test matrix with respect to the train matrix. Uses a
+   * Laplace prior. Does NOT normalize the entropy.
+   *
+   * @param train the train matrix 
+   * @param test the test matrix
+   * @param the number of symbols for Laplace
+   * @return the entropy
+   */
+  public static double entropyConditionedOnRows(double[][] train, 
+						double[][] test,
+						double numClasses) {
+    
+    double returnValue = 0, trainSumForRow, testSumForRow, testSum = 0;
+
+    for (int i = 0; i < test.length; i++) {
+      trainSumForRow = 0;
+      testSumForRow = 0;
+      for (int j = 0; j < test[0].length; j++) {
+	returnValue -= test[i][j] * Math.log(train[i][j] + 1);
+	trainSumForRow += train[i][j];
+	testSumForRow += test[i][j];
+      }
+      testSum = testSumForRow;
+      returnValue += testSumForRow * Math.log(trainSumForRow + 
+					     numClasses);
+    }
+    return returnValue / (testSum * log2);
+  }
+
+  /**
+   * Computes the rows' entropy for the given contingency table.
+   *
+   * @param matrix the contingency table
+   * @return the rows' entropy
+   */
+  public static double entropyOverRows(double[][] matrix) {
+    
+    double returnValue = 0, sumForRow, total = 0;
+
+    for (int i = 0; i < matrix.length; i++) {
+      sumForRow = 0;
+      for (int j = 0; j < matrix[0].length; j++) {
+	sumForRow += matrix[i][j];
+      }
+      returnValue = returnValue - lnFunc(sumForRow);
+      total += sumForRow;
+    }
+    if (Utils.eq(total, 0)) {
+      return 0;
+    }
+    return (returnValue + lnFunc(total)) / (total * log2);
+  }
+
+  /**
+   * Computes the columns' entropy for the given contingency table.
+   *
+   * @param matrix the contingency table
+   * @return the columns' entropy
+   */
+  public static double entropyOverColumns(double[][] matrix){
+    
+    double returnValue = 0, sumForColumn, total = 0;
+
+    for (int j = 0; j < matrix[0].length; j++){
+      sumForColumn = 0;
+      for (int i = 0; i < matrix.length; i++) {
+	sumForColumn += matrix[i][j];
+      }
+      returnValue = returnValue - lnFunc(sumForColumn);
+      total += sumForColumn;
+    }
+    if (Utils.eq(total, 0)) {
+      return 0;
+    }
+    return (returnValue + lnFunc(total)) / (total * log2);
+  }
+
+  /**
+   * Computes gain ratio for contingency table (split on rows).
+   * Returns Double.MAX_VALUE if the split entropy is 0.
+   *
+   * @param matrix the contingency table
+   * @return the gain ratio
+   */
+  public static double gainRatio(double[][] matrix){
+    
+    double preSplit = 0, postSplit = 0, splitEnt = 0,
+      sumForRow, sumForColumn, total = 0, infoGain;
+
+    // Compute entropy before split
+    for (int i = 0; i < matrix[0].length; i++) {
+      sumForColumn = 0;
+      for (int j = 0; j < matrix.length; j++) 
+	sumForColumn += matrix[j][i];
+      preSplit += lnFunc(sumForColumn);
+      total += sumForColumn;
+    }
+    preSplit -= lnFunc(total);
+
+    // Compute entropy after split and split entropy
+    for (int i = 0; i < matrix.length; i++) {
+      sumForRow = 0;
+      for (int j = 0; j < matrix[0].length; j++) {
+	postSplit += lnFunc(matrix[i][j]);
+	sumForRow += matrix[i][j];
+      }
+      splitEnt += lnFunc(sumForRow);
+    }
+    postSplit -= splitEnt;
+    splitEnt -= lnFunc(total);
+
+    infoGain = preSplit - postSplit;
+    if (Utils.eq(splitEnt, 0))
+      return 0;
+    return infoGain / splitEnt;
+  }
+
+  /**
+   * Returns negative base 2 logarithm of multiple hypergeometric
+   * probability for a contingency table.
+   *
+   * @param matrix the contingency table
+   * @return the log of the hypergeometric probability of the contingency table 
+   */
+  public static double log2MultipleHypergeometric(double[][] matrix) {
+
+    double sum = 0, sumForRow, sumForColumn, total = 0;
+
+    for (int i = 0; i < matrix.length; i++) {
+      sumForRow = 0;
+      for (int j = 0; j < matrix[i].length; j++) {
+	sumForRow += matrix[i][j];
+      }
+      sum += SpecialFunctions.lnFactorial(sumForRow);
+      total += sumForRow;
+    }
+    for (int j = 0; j < matrix[0].length; j++) {
+      sumForColumn = 0;
+      for (int i = 0; i < matrix.length; i++) {
+	sumForColumn += matrix [i][j];
+      }
+      sum += SpecialFunctions.lnFactorial(sumForColumn);
+    }
+    for (int i = 0; i < matrix.length; i++) {
+      for (int j = 0; j < matrix[i].length; j++) {
+	sum -= SpecialFunctions.lnFactorial(matrix[i][j]);
+      }
+    }
+    sum -= SpecialFunctions.lnFactorial(total);
+    return -sum / log2;
+  }
+
+  /**
+   * Reduces a matrix by deleting all zero rows and columns.
+   *
+   * @param matrix the matrix to be reduced
+   * @param the matrix with all zero rows and columns deleted
+   */
+  public static double[][] reduceMatrix(double[][] matrix) {
+
+    int row, col, currCol, currRow, nrows, ncols, 
+      nonZeroRows = 0, nonZeroColumns = 0;
+    double[] rtotal, ctotal;
+    double[][] newMatrix;
+
+    nrows = matrix.length;
+    ncols = matrix[0].length;
+    rtotal = new double [nrows];
+    ctotal = new double [ncols];
+    for (row = 0; row < nrows; row++) {
+      for (col = 0; col < ncols; col++) {
+	rtotal[row] += matrix[row][col];
+	ctotal[col] += matrix[row][col];
+      }
+    }
+    for (row = 0; row < nrows; row++) {
+      if (Utils.gr(rtotal[row],0)) {
+	nonZeroRows++;
+      }
+    }
+    for (col = 0; col < ncols; col++) {
+      if (Utils.gr(ctotal[col],0)) {
+	nonZeroColumns++;
+      }
+    }
+    newMatrix = new double[nonZeroRows][nonZeroColumns];
+    currRow = 0;
+    for (row = 0; row < nrows; row++) {
+      if (Utils.gr(rtotal[row],0)) {
+	currCol = 0;
+	for (col = 0; col < ncols; col++) {
+	  if (Utils.gr(ctotal[col],0)) {
+	    newMatrix[currRow][currCol] = matrix[row][col];
+	    currCol++;
+	  }
+	}
+	currRow++;
+      }
+    }
+    return newMatrix;
+  }
+    
+   /**
+    * Calculates the symmetrical uncertainty for base 2.
+    *
+    * @param matrix the contingency table
+    * @return the calculated symmetrical uncertainty
+    *
+    */
+  public static double symmetricalUncertainty(double matrix[][]) {
+
+    double sumForColumn, sumForRow, total = 0, columnEntropy = 0, 
+      rowEntropy = 0, entropyConditionedOnRows = 0, infoGain = 0;
+
+    // Compute entropy for columns
+    for (int i = 0; i < matrix[0].length; i++) {
+      sumForColumn = 0;
+      for (int j = 0; j < matrix.length; j++) {
+	sumForColumn += matrix[j][i];
+      }
+      columnEntropy += lnFunc(sumForColumn);
+      total += sumForColumn;
+    }
+    columnEntropy -= lnFunc(total);
+
+    // Compute entropy for rows and conditional entropy
+    for (int i = 0; i < matrix.length; i++) {
+      sumForRow = 0;
+      for (int j = 0; j < matrix[0].length; j++) { 
+	sumForRow += matrix[i][j];
+	entropyConditionedOnRows += lnFunc(matrix[i][j]);
+      }
+      rowEntropy += lnFunc(sumForRow);
+    }
+    entropyConditionedOnRows -= rowEntropy;
+    rowEntropy -= lnFunc(total);
+    infoGain = columnEntropy - entropyConditionedOnRows;
+    if (Utils.eq(columnEntropy, 0) || Utils.eq(rowEntropy, 0))
+      return 0;
+    return 2.0 * (infoGain / (columnEntropy + rowEntropy));
+  }
+
+  /**
+   * Computes Goodman and Kruskal's tau-value for a contingency table.
+   *
+   * @param matrix the contingency table
+   * @param Goodman and Kruskal's tau-value
+   */
+  public static double tauVal(double[][] matrix) {
+    
+    int nrows, ncols, row, col;
+    double [] ctotal;
+    double maxcol = 0, max, maxtotal = 0, n = 0;
+    
+    nrows = matrix.length;
+    ncols = matrix[0].length;
+    ctotal = new double [ncols];
+    for (row = 0; row < nrows; row++) {
+      max = 0;
+      for (col = 0; col < ncols; col++) {
+	if (Utils.gr(matrix[row][col], max)) 
+	  max = matrix[row][col];
+	ctotal[col] += matrix[row][col];
+	n += matrix[row][col];
+      }
+      maxtotal += max;
+    }
+    if (Utils.eq(n, 0)) {
+      return 0;
+    }
+    maxcol = ctotal[Utils.maxIndex(ctotal)];
+    return (maxtotal - maxcol)/(n - maxcol);
+  }
+
+  /**
+   * Help method for computing entropy.
+   */
+  private static double lnFunc(double num){
+    
+    // Constant hard coded for efficiency reasons
+    if (num < 1e-6) {
+      return 0;
+    } else {
+      return num * Math.log(num);
+    }
+  }
+  
+  /**
+   * Computes chi-value for one cell in matrix.
+   * From Gary Perlman's unixstat.
+   */
+  private static double chiCell(double freq, double expect, boolean yates){
+
+    double  diff = freq - expect;
+       
+    if (yates) {
+      diff = Math.abs (diff) - 0.5;
+      if (diff < 0.0) { // over-correction
+	diff = 0.0;
+      }
+    }
+    if (Math.abs(expect) < 10e-10) {
+      return (0.0);
+    } else {
+      return (diff * diff / expect);
+    }
+  }
+
+  /**
+   * Main method for testing this class.
+   */
+  public static void main(String[] ops) {
+
+    double[] firstRow = {10, 5, 20};
+    double[] secondRow = {2, 10, 6};
+    double[] thirdRow = {5, 10, 10};
+    double[][] matrix = new double[3][0];
+
+    matrix[0] = firstRow; matrix[1] = secondRow; matrix[2] = thirdRow;
+    for (int i = 0; i < matrix.length; i++) {
+      for (int j = 0; j < matrix[i].length; j++) {
+	System.out.print(matrix[i][j] + " ");
+      }
+      System.out.println();
+    }
+    System.out.println("Chi-squared probability: " +
+		       ContingencyTables.chiSquared(matrix, false));
+    System.out.println("Chi-squared value: " +
+		       ContingencyTables.chiVal(matrix, false));
+    System.out.println("Cochran's criterion fullfilled: " +
+		       ContingencyTables.cochransCriterion(matrix));
+    System.out.println("Cramer's V: " +
+		       ContingencyTables.CramersV(matrix));
+    System.out.println("Entropy of first row: " +
+		       ContingencyTables.entropy(firstRow));
+    System.out.println("Entropy conditioned on columns: " +
+		       ContingencyTables.entropyConditionedOnColumns(matrix));
+    System.out.println("Entropy conditioned on rows: " +
+		       ContingencyTables.entropyConditionedOnRows(matrix));
+    System.out.println("Entropy conditioned on rows (with Laplace): " +
+		       ContingencyTables.entropyConditionedOnRows(matrix, matrix, 3));
+    System.out.println("Entropy of rows: " +
+		       ContingencyTables.entropyOverRows(matrix));
+    System.out.println("Entropy of columns: " +
+		       ContingencyTables.entropyOverColumns(matrix));
+    System.out.println("Gain ratio: " +
+		       ContingencyTables.gainRatio(matrix));
+    System.out.println("Negative log2 of multiple hypergeometric probability: " +
+		       ContingencyTables.log2MultipleHypergeometric(matrix));
+    System.out.println("Symmetrical uncertainty: " +
+		       ContingencyTables.symmetricalUncertainty(matrix));
+    System.out.println("Tau value: " +
+		       ContingencyTables.tauVal(matrix));
+    double[][] newMatrix = new double[3][3];
+    newMatrix[0][0] = 1; newMatrix[0][1] = 0; newMatrix[0][2] = 1;
+    newMatrix[1][0] = 0; newMatrix[1][1] = 0; newMatrix[1][2] = 0;
+    newMatrix[2][0] = 1; newMatrix[2][1] = 0; newMatrix[2][2] = 1;
+    System.out.println("Matrix with empty row and column: ");
+    for (int i = 0; i < newMatrix.length; i++) {
+      for (int j = 0; j < newMatrix[i].length; j++) {
+	System.out.print(newMatrix[i][j] + " ");
+      }
+      System.out.println();
+    }
+    System.out.println("Reduced matrix: ");
+    newMatrix = ContingencyTables.reduceMatrix(newMatrix);
+    for (int i = 0; i < newMatrix.length; i++) {
+      for (int j = 0; j < newMatrix[i].length; j++) {
+	System.out.print(newMatrix[i][j] + " ");
+      }
+      System.out.println();
+    }
+  }
+}
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Copyable.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Copyable.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Copyable.java	(revision 10506)
@@ -0,0 +1,41 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Copyable.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+/**
+ * Interface implemented by classes that can produce "shallow" copies
+ * of their objects. (As opposed to clone(), which is supposed to
+ * produce a "deep" copy.)
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public interface Copyable {
+
+  /**
+   * This method produces a shallow copy of an object.
+   * It does the same as the clone() method in Object, which also produces
+   * a shallow copy.
+   */
+  public Object copy();
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/FastVector.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/FastVector.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/FastVector.java	(revision 10506)
@@ -0,0 +1,432 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    FastVector.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Implements a fast vector class without synchronized
+ * methods. Replaces java.util.Vector. (Synchronized methods tend to
+ * be slow.)
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$ */
+public class FastVector implements Copyable, Serializable {
+
+  /**
+   * Class for enumerating the vector's elements.
+   */
+  public class FastVectorEnumeration implements Enumeration {
+
+    /** The counter. */
+    private int m_Counter;
+
+    /** The vector. */
+    private FastVector m_Vector;
+
+    /** Special element. Skipped during enumeration. */
+    private int m_SpecialElement;
+
+    /**
+     * Constructs an enumeration.
+     *
+     * @param vector the vector which is to be enumerated
+     */
+    public FastVectorEnumeration(FastVector vector) {
+
+      m_Counter = 0;
+      m_Vector = vector;
+      m_SpecialElement = -1;
+    }
+
+    /**
+     * Constructs an enumeration with a special element.
+     * The special element is skipped during the enumeration.
+     *
+     * @param vector the vector which is to be enumerated
+     * @param special the index of the special element
+     */
+    public FastVectorEnumeration(FastVector vector, int special) {
+
+      m_Vector = vector;
+      m_SpecialElement = special;
+      if (special == 0) {
+	m_Counter = 1;
+      } else {
+	m_Counter = 0;
+      }
+    }
+
+
+    /**
+     * Tests if there are any more elements to enumerate.
+     *
+     * @return true if there are some elements left
+     */
+    public final boolean hasMoreElements() {
+
+      if (m_Counter < m_Vector.size()) {
+	return true;
+      }
+      return false;
+    }
+
+    /**
+     * Returns the next element.
+     *
+     * @return the next element to be enumerated
+     */
+    public final Object nextElement() {
+  
+      Object result = m_Vector.elementAt(m_Counter);
+
+      m_Counter++;
+      if (m_Counter == m_SpecialElement) {
+	m_Counter++;
+      }
+      return result;
+    }
+  }
+
+  /** The array of objects. */
+  private Object[] m_Objects;
+
+  /** The current size; */
+  private int m_Size;
+
+  /** The capacity increment */
+  private int m_CapacityIncrement;
+  
+  /** The capacity multiplier. */
+  private double m_CapacityMultiplier;
+
+  /**
+   * Constructs an empty vector with initial
+   * capacity zero.
+   */
+  public FastVector() {
+  
+    m_Objects = new Object[0];
+    m_Size = 0;
+    m_CapacityIncrement = 1;
+    m_CapacityMultiplier = 2;
+  }
+
+  /**
+   * Constructs a vector with the given capacity.
+   *
+   * @param capacity the vector's initial capacity
+   */
+  public FastVector(int capacity) {
+
+    m_Objects = new Object[capacity];
+    m_Size = 0;
+    m_CapacityIncrement = 1;
+    m_CapacityMultiplier = 2;
+  }
+
+  /**
+   * Constructs a vector with the given capacity, capacity 
+   * increment and capacity mulitplier.
+   *
+   * @param capacity the vector's initial capacity
+   */
+  public FastVector(int capacity, int capIncrement, 
+		    double capMultiplier) {
+
+    m_Objects = new Object[capacity];
+    m_Size = 0;
+    m_CapacityIncrement = capIncrement;
+    m_CapacityMultiplier = capMultiplier;
+  }
+
+  /**
+   * Adds an element to this vector. Increases its
+   * capacity if its not large enough.
+   *
+   * @param element the element to add
+   */
+  public final void addElement(Object element) {
+
+    Object[] newObjects;
+
+    if (m_Size == m_Objects.length) {
+      newObjects = new Object[(int)m_CapacityMultiplier *
+			     (m_Objects.length +
+			      m_CapacityIncrement)];
+      System.arraycopy(m_Objects, 0, newObjects, 0, m_Size);
+      m_Objects = newObjects;
+    }
+    m_Objects[m_Size] = element;
+    m_Size++;
+  }
+
+  /**
+   * Returns the capacity of the vector.
+   *
+   * @return the capacity of the vector
+   */
+  public final int capacity() {
+  
+    return m_Objects.length;
+  }
+
+  /**
+   * Produces a shallow copy of this vector.
+   *
+   * @return the new vector
+   */
+  public final Object copy() {
+
+    FastVector copy = new FastVector(m_Objects.length, 
+				     m_CapacityIncrement,
+				     m_CapacityMultiplier);
+    copy.m_Size = m_Size;
+    System.arraycopy(m_Objects, 0, copy.m_Objects, 0, m_Size);
+    return copy;
+  }
+
+  /**
+   * Clones the vector and shallow copies all its elements.
+   * The elements have to implement the Copyable interface.
+   * 
+   * @return the new vector
+   */
+  public final Object copyElements() {
+
+    FastVector copy = new FastVector(m_Objects.length, 
+				     m_CapacityIncrement,
+				     m_CapacityMultiplier);
+    copy.m_Size = m_Size;
+    for (int i = 0; i < m_Size; i++) {
+      copy.m_Objects[i] = ((Copyable)m_Objects[i]).copy();
+    }
+    return copy;
+  }
+
+  /**
+   * Returns the element at the given position.
+   *
+   * @param index the element's index
+   * @return the element with the given index
+   */
+  public final Object elementAt(int index) {
+
+    return m_Objects[index];
+  }
+
+  /**
+   * Returns an enumeration of this vector.
+   *
+   * @return an enumeration of this vector
+   */
+  public final Enumeration elements() {
+  
+    return new FastVectorEnumeration(this);
+  }
+
+  /**
+   * Returns an enumeration of this vector, skipping the
+   * element with the given index.
+   *
+   * @param index the element to skip
+   * @return an enumeration of this vector
+   */
+  public final Enumeration elements(int index) {
+  
+    return new FastVectorEnumeration(this, index);
+  }
+
+  /**
+   * Returns the first element of the vector.
+   *
+   * @return the first element of the vector
+   */
+  public final Object firstElement() {
+
+    return m_Objects[0];
+  }
+
+  /**
+   * Searches for the first occurence of the given argument, 
+   * testing for equality using the equals method. 
+   *
+   * @param element the element to be found
+   * @return the index of the first occurrence of the argument 
+   * in this vector; returns -1 if the object is not found
+   */
+  public final int indexOf(Object element) {
+
+    for (int i = 0; i < m_Size; i++) {
+      if (element.equals(m_Objects[i])) {
+	return i;
+      }
+    }
+    return -1;
+  }
+
+  /**
+   * Inserts an element at the given position.
+   *
+   * @param element the element to be inserted
+   * @param index the element's index
+   */
+  public final void insertElementAt(Object element, int index) {
+
+    Object[] newObjects;
+
+    if (m_Size < m_Objects.length) {
+      System.arraycopy(m_Objects, index, m_Objects, index + 1, 
+                       m_Size - index);
+      m_Objects[index] = element;
+    } else {
+      newObjects = new Object[(int)m_CapacityMultiplier *
+			     (m_Objects.length +
+			      m_CapacityIncrement)];
+      System.arraycopy(m_Objects, 0, newObjects, 0, index);
+      newObjects[index] = element;
+      System.arraycopy(m_Objects, index, newObjects, index + 1,
+		       m_Size - index);
+      m_Objects = newObjects;
+    }
+    m_Size++;
+  }
+
+  /**
+   * Returns the last element of the vector.
+   *
+   * @return the last element of the vector
+   */
+  public final Object lastElement() {
+
+    return m_Objects[m_Size - 1];
+  }
+
+  /**
+   * Deletes an element from this vector.
+   *
+   * @param index the index of the element to be deleted
+   */
+  public final void removeElementAt(int index) {
+
+    System.arraycopy(m_Objects, index + 1, m_Objects, index, 
+                     m_Size - index - 1);
+    m_Size--;
+  }
+
+  /**
+   * Removes all components from this vector and sets its 
+   * size to zero. 
+   */
+  public final void removeAllElements() {
+
+    m_Objects = new Object[m_Objects.length];
+    m_Size = 0;
+  }
+
+  /**
+   * Appends all elements of the supplied vector to this vector.
+   *
+   * @param toAppend the FastVector containing elements to append.
+   */
+  public final void appendElements(FastVector toAppend) {
+
+    setCapacity(size() + toAppend.size());
+    System.arraycopy(toAppend.m_Objects, 0, m_Objects, size(), toAppend.size());
+    m_Size = m_Objects.length;
+  }
+
+  /** 
+   * Returns all the elements of this vector as an array
+   *
+   * @param an array containing all the elements of this vector
+   */
+  public final Object [] toArray() {
+
+    Object [] newObjects = new Object[size()];
+    System.arraycopy(m_Objects, 0, newObjects, 0, size());
+    return newObjects;
+  }
+
+  /**
+   * Sets the vector's capacity to the given value.
+   *
+   * @param capacity the new capacity
+   */
+  public final void setCapacity(int capacity) {
+
+    Object[] newObjects = new Object[capacity];
+   
+    System.arraycopy(m_Objects, 0, newObjects, 0, Math.min(capacity, m_Size));
+    m_Objects = newObjects;
+    if (m_Objects.length < m_Size)
+      m_Size = m_Objects.length;
+  }
+
+  /**
+   * Sets the element at the given index.
+   *
+   * @param element the element to be put into the vector
+   * @param index the index at which the element is to be placed
+   */
+  public final void setElementAt(Object element, int index) {
+
+    m_Objects[index] = element;
+  }
+
+  /**
+   * Returns the vector's current size.
+   *
+   * @return the vector's current size
+   */
+  public final int size() {
+
+    return m_Size;
+  }
+
+  /**
+   * Swaps two elements in the vector.
+   *
+   * @param first index of the first element
+   * @param second index of the second element
+   */
+  public final void swap(int first, int second) {
+
+    Object help = m_Objects[first];
+
+    m_Objects[first] = m_Objects[second];
+    m_Objects[second] = help;
+  }
+
+  /**
+   * Sets the vector's capacity to its size.
+   */
+  public final void trimToSize() {
+
+    Object[] newObjects = new Object[m_Size];
+    
+    System.arraycopy(m_Objects, 0, newObjects, 0, m_Size);
+    m_Objects = newObjects;
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Instance.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Instance.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Instance.java	(revision 10506)
@@ -0,0 +1,1064 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Instance.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Class for handling an instance. All values (numeric, nominal, or
+ * string) are internally stored as floating-point numbers. If an
+ * attribute is nominal (or a string), the stored value is the index
+ * of the corresponding nominal (or string) value in the attribute's
+ * definition. We have chosen this approach in favor of a more elegant
+ * object-oriented approach because it is much faster. <p>
+ *
+ * Typical usage (code from the main() method of this class): <p>
+ *
+ * <code>
+ * ... <br>
+ *      
+ * // Create empty instance with three attribute values <br>
+ * Instance inst = new Instance(3); <br><br>
+ *     
+ * // Set instance's values for the attributes "length", "weight", and "position"<br>
+ * inst.setValue(length, 5.3); <br>
+ * inst.setValue(weight, 300); <br>
+ * inst.setValue(position, "first"); <br><br>
+ *   
+ * // Set instance's dataset to be the dataset "race" <br>
+ * inst.setDataset(race); <br><br>
+ *   
+ * // Print the instance <br>
+ * System.out.println("The instance: " + inst); <br>
+ *
+ * ... <br>
+ * </code><p>
+ *
+ * All methods that change an instance are safe, ie. a change of an
+ * instance does not affect any other instances. All methods that
+ * change an instance's attribute values clone the attribute value
+ * vector before it is changed. If your application heavily modifies
+ * instance values, it may be faster to create a new instance from scratch.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$ 
+ */
+public class Instance implements Copyable, Serializable {
+  
+  /** Constant representing a missing value. */
+  protected final static double MISSING_VALUE = Double.NaN;
+
+  /** 
+   * The dataset the instance has access to.  Null if the instance
+   * doesn't have access to any dataset.  Only if an instance has
+   * access to a dataset, it knows about the actual attribute types.  
+   */
+  protected Instances m_Dataset;
+
+  /** The instance's attribute values. */
+  protected double[] m_AttValues;
+
+  /** The instance's weight. */
+  protected double m_Weight;
+
+  /**
+   * Constructor that copies the attribute values and the weight from
+   * the given instance. Reference to the dataset is set to null.
+   * (ie. the instance doesn't have access to information about the
+   * attribute types)
+   *
+   * @param instance the instance from which the attribute
+   * values and the weight are to be copied 
+   */
+  public Instance(Instance instance) {
+    
+    m_AttValues = instance.m_AttValues;
+    m_Weight = instance.m_Weight;
+    m_Dataset = null;
+  }
+
+  /**
+   * Constructor that inititalizes instance variable with given
+   * values. Reference to the dataset is set to null. (ie. the instance
+   * doesn't have access to information about the attribute types)
+   *
+   * @param weight the instance's weight
+   * @param attValues a vector of attribute values 
+   */
+  public Instance(double weight, double[] attValues){
+    
+    m_AttValues = attValues;
+    m_Weight = weight;
+    m_Dataset = null;
+  }
+
+  /**
+   * Constructor of an instance that sets weight to one, all values to
+   * be missing, and the reference to the dataset to null. (ie. the instance
+   * doesn't have access to information about the attribute types)
+   *
+   * @param numAttributes the size of the instance 
+   */
+  public Instance(int numAttributes) {
+    
+    m_AttValues = new double[numAttributes];
+    for (int i = 0; i < m_AttValues.length; i++) {
+      m_AttValues[i] = MISSING_VALUE;
+    }
+    m_Weight = 1;
+    m_Dataset = null;
+  }
+
+  /**
+   * Returns the attribute with the given index.
+   *
+   * @param index the attribute's index
+   * @return the attribute at the given position
+   * @exception UnassignedDatasetException if instance doesn't have access to a
+   * dataset
+   */ 
+  public Attribute attribute(int index) {
+   
+    if (m_Dataset == null) {
+      throw new UnassignedDatasetException("Instance doesn't have access to a dataset!");
+    }
+    return m_Dataset.attribute(index);
+  }
+
+  /**
+   * Returns the attribute with the given index. Does the same
+   * thing as attribute().
+   *
+   * @param indexOfIndex the index of the attribute's index 
+   * @return the attribute at the given position
+   * @exception UnassignedDatasetException if instance doesn't have access to a
+   * dataset
+   */ 
+  public Attribute attributeSparse(int indexOfIndex) {
+   
+    if (m_Dataset == null) {
+      throw new UnassignedDatasetException("Instance doesn't have access to a dataset!");
+    }
+    return m_Dataset.attribute(indexOfIndex);
+  }
+
+  /**
+   * Returns class attribute.
+   *
+   * @return the class attribute
+   * @exception UnassignedDatasetException if the class is not set or the
+   * instance doesn't have access to a dataset
+   */
+  public Attribute classAttribute() {
+
+    if (m_Dataset == null) {
+      throw new UnassignedDatasetException("Instance doesn't have access to a dataset!");
+    }
+    return m_Dataset.classAttribute();
+  }
+
+  /**
+   * Returns the class attribute's index.
+   *
+   * @return the class index as an integer 
+   * @exception UnassignedDatasetException if instance doesn't have access to a dataset 
+   */
+  public int classIndex() {
+    
+    if (m_Dataset == null) {
+      throw new UnassignedDatasetException("Instance doesn't have access to a dataset!");
+    }
+    return m_Dataset.classIndex();
+  }
+
+  /**
+   * Tests if an instance's class is missing.
+   *
+   * @return true if the instance's class is missing
+   * @exception UnassignedClassException if the class is not set or the instance doesn't
+   * have access to a dataset
+   */
+  public boolean classIsMissing() {
+
+    if (classIndex() < 0) {
+      throw new UnassignedClassException("Class is not set!");
+    }
+    return isMissing(classIndex());
+  }
+
+  /**
+   * Returns an instance's class value in internal format. (ie. as a
+   * floating-point number)
+   *
+   * @return the corresponding value as a double (If the 
+   * corresponding attribute is nominal (or a string) then it returns the 
+   * value's index as a double).
+   * @exception UnassignedClassException if the class is not set or the instance doesn't
+   * have access to a dataset 
+   */
+  public double classValue() {
+    
+    if (classIndex() < 0) {
+      throw new UnassignedClassException("Class is not set!");
+    }
+    return value(classIndex());
+  }
+
+  /**
+   * Produces a shallow copy of this instance. The copy has
+   * access to the same dataset. (if you want to make a copy
+   * that doesn't have access to the dataset, use 
+   * <code>new Instance(instance)</code>
+   *
+   * @return the shallow copy
+   */
+  public Object copy() {
+
+    Instance result = new Instance(this);
+    result.m_Dataset = m_Dataset;
+    return result;
+  }
+
+  /**
+   * Returns the dataset this instance has access to. (ie. obtains
+   * information about attribute types from) Null if the instance
+   * doesn't have access to a dataset.
+   *
+   * @return the dataset the instance has accesss to
+   */
+  public Instances dataset() {
+
+    return m_Dataset;
+  }
+
+  /**
+   * Deletes an attribute at the given position (0 to 
+   * numAttributes() - 1). Only succeeds if the instance does not
+   * have access to any dataset because otherwise inconsistencies
+   * could be introduced.
+   *
+   * @param pos the attribute's position
+   * @exception RuntimeException if the instance has access to a
+   * dataset 
+   */
+  public void deleteAttributeAt(int position) {
+
+    if (m_Dataset != null) {
+      throw new RuntimeException("Instance has access to a dataset!");
+    }
+    forceDeleteAttributeAt(position);
+  }
+
+  /**
+   * Returns an enumeration of all the attributes.
+   *
+   * @return enumeration of all the attributes
+   * @exception UnassignedDatasetException if the instance doesn't
+   * have access to a dataset 
+   */
+  public Enumeration enumerateAttributes() {
+
+    if (m_Dataset == null) {
+      throw new UnassignedDatasetException("Instance doesn't have access to a dataset!");
+    }
+    return m_Dataset.enumerateAttributes();
+  }
+
+  /**
+   * Tests if the headers of two instances are equivalent.
+   *
+   * @param instance another instance
+   * @return true if the header of the given instance is 
+   * equivalent to this instance's header
+   * @exception UnassignedDatasetException if instance doesn't have access to any
+   * dataset
+   */
+  public boolean equalHeaders(Instance inst) {
+
+    if (m_Dataset == null) {
+      throw new UnassignedDatasetException("Instance doesn't have access to a dataset!");
+    }
+    return m_Dataset.equalHeaders(inst.m_Dataset);
+  }
+
+  /**
+   * Returns the index of the attribute stored at the given position.
+   * Just returns the given value.
+   *
+   * @param position the position 
+   * @return the index of the attribute stored at the given position
+   */
+  public int index(int position) {
+
+    return position;
+  }
+
+  /**
+   * Inserts an attribute at the given position (0 to 
+   * numAttributes()). Only succeeds if the instance does not
+   * have access to any dataset because otherwise inconsistencies
+   * could be introduced.
+   *
+   * @param pos the attribute's position
+   * @exception RuntimeException if the instance has accesss to a
+   * dataset
+   * @exception IllegalArgumentException if the position is out of range
+   */
+  public void insertAttributeAt(int position) {
+
+    if (m_Dataset != null) {
+      throw new RuntimeException("Instance has accesss to a dataset!");
+    }
+    if ((position < 0) ||
+	(position > numAttributes())) {
+      throw new IllegalArgumentException("Can't insert attribute: index out "+
+                                         "of range");
+    }
+    forceInsertAttributeAt(position);
+  }
+
+  /**
+   * Tests if a specific value is "missing".
+   *
+   * @param attIndex the attribute's index
+   */
+  public boolean isMissing(int attIndex) {
+
+    if (Double.isNaN(m_AttValues[attIndex])) {
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Tests if a specific value is "missing". Does
+   * the same thing as isMissing() if applied to an Instance.
+   *
+   * @param indexOfIndex the index of the attribute's index 
+   */
+  public boolean isMissingSparse(int indexOfIndex) {
+
+    if (Double.isNaN(m_AttValues[indexOfIndex])) {
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Tests if a specific value is "missing".
+   * The given attribute has to belong to a dataset.
+   *
+   * @param att the attribute
+   */
+  public boolean isMissing(Attribute att) {
+
+    return isMissing(att.index());
+  }
+
+  /**
+   * Tests if the given value codes "missing".
+   *
+   * @param val the value to be tested
+   * @return true if val codes "missing"
+   */
+  public static boolean isMissingValue(double val) {
+
+    return Double.isNaN(val);
+  }
+
+  /**
+   * Merges this instance with the given instance and returns
+   * the result. Dataset is set to null.
+   *
+   * @param inst the instance to be merged with this one
+   * @return the merged instances
+   */
+  public Instance mergeInstance(Instance inst) {
+
+    int m = 0;
+    double [] newVals = new double[numAttributes() + inst.numAttributes()];
+    for (int j = 0; j < numAttributes(); j++, m++) {
+      newVals[m] = value(j);
+    }
+    for (int j = 0; j < inst.numAttributes(); j++, m++) {
+      newVals[m] = inst.value(j);
+    }
+    return new Instance(1.0, newVals);
+  }
+
+  /**
+   * Returns the double that codes "missing".
+   *
+   * @return the double that codes "missing"
+   */
+  public static double missingValue() {
+
+    return MISSING_VALUE;
+  }
+
+  /**
+   * Returns the number of attributes.
+   *
+   * @return the number of attributes as an integer
+   */
+  public int numAttributes() {
+
+    return m_AttValues.length;
+  }
+
+  /**
+   * Returns the number of class labels.
+   *
+   * @return the number of class labels as an integer if the 
+   * class attribute is nominal, 1 otherwise.
+   * @exception UnassignedDatasetException if instance doesn't have access to any
+   * dataset
+   */
+  public int numClasses() {
+    
+    if (m_Dataset == null) {
+      throw new UnassignedDatasetException("Instance doesn't have access to a dataset!");
+    }
+    return m_Dataset.numClasses();
+  }
+
+  /**
+   * Returns the number of values present. Always the same as numAttributes().
+   *
+   * @return the number of values
+   */
+  public int numValues() {
+
+    return m_AttValues.length;
+  }
+
+  /** 
+   * Replaces all missing values in the instance with the
+   * values contained in the given array. A deep copy of
+   * the vector of attribute values is performed before the
+   * values are replaced.
+   *
+   * @param array containing the means and modes
+   * @exception IllegalArgumentException if numbers of attributes are unequal
+   */
+  public void replaceMissingValues(double[] array) {
+	 
+    if ((array == null) || 
+	(array.length != m_AttValues.length)) {
+      throw new IllegalArgumentException("Unequal number of attributes!");
+    }
+    freshAttributeVector();
+    for (int i = 0; i < m_AttValues.length; i++) {
+      if (isMissing(i)) {
+	m_AttValues[i] = array[i];
+      }
+    }
+  }
+
+  /**
+   * Sets the class value of an instance to be "missing". A deep copy of
+   * the vector of attribute values is performed before the
+   * value is set to be missing.
+   *
+   * @exception UnassignedClassException if the class is not set
+   * @exception UnassignedDatasetException if the instance doesn't
+   * have access to a dataset
+   */
+  public void setClassMissing() {
+
+    if (classIndex() < 0) {
+      throw new UnassignedClassException("Class is not set!");
+    }
+    setMissing(classIndex());
+  }
+
+  /**
+   * Sets the class value of an instance to the given value (internal
+   * floating-point format).  A deep copy of the vector of attribute
+   * values is performed before the value is set.
+   *
+   * @param value the new attribute value (If the corresponding
+   * attribute is nominal (or a string) then this is the new value's
+   * index as a double).  
+   * @exception UnassignedClassException if the class is not set
+   * @exception UnaddignedDatasetException if the instance doesn't
+   * have access to a dataset 
+   */
+  public void setClassValue(double value) {
+
+    if (classIndex() < 0) {
+      throw new UnassignedClassException("Class is not set!");
+    }
+    setValue(classIndex(), value);
+  }
+
+  /**
+   * Sets the class value of an instance to the given value. A deep
+   * copy of the vector of attribute values is performed before the
+   * value is set.
+   *
+   * @param value the new class value (If the class
+   * is a string attribute and the value can't be found,
+   * the value is added to the attribute).
+   * @exception UnassignedClassException if the class is not set
+   * @exception UnassignedDatasetException if the dataset is not set
+   * @exception IllegalArgumentException if the attribute is not
+   * nominal or a string, or the value couldn't be found for a nominal
+   * attribute 
+   */
+  public final void setClassValue(String value) {
+
+    if (classIndex() < 0) {
+      throw new UnassignedClassException("Class is not set!");
+    }
+    setValue(classIndex(), value);
+  }
+
+  /**
+   * Sets the reference to the dataset. Does not check if the instance
+   * is compatible with the dataset. Note: the dataset does not know
+   * about this instance. If the structure of the dataset's header
+   * gets changed, this instance will not be adjusted automatically.
+   *
+   * @param instances the reference to the dataset 
+   */
+  public final void setDataset(Instances instances) {
+    
+    m_Dataset = instances;
+  }
+
+  /**
+   * Sets a specific value to be "missing". Performs a deep copy
+   * of the vector of attribute values before the value is set to
+   * be missing.
+   *
+   * @param attIndex the attribute's index
+   */
+  public final void setMissing(int attIndex) {
+
+    setValue(attIndex, MISSING_VALUE);
+  }
+
+  /**
+   * Sets a specific value to be "missing". Performs a deep copy
+   * of the vector of attribute values before the value is set to
+   * be missing. The given attribute has to belong to a dataset.
+   *
+   * @param att the attribute
+   */
+  public final void setMissing(Attribute att) {
+
+    setMissing(att.index());
+  }
+
+  /**
+   * Sets a specific value in the instance to the given value 
+   * (internal floating-point format). Performs a deep copy
+   * of the vector of attribute values before the value is set.
+   *
+   * @param attIndex the attribute's index 
+   * @param value the new attribute value (If the corresponding
+   * attribute is nominal (or a string) then this is the new value's
+   * index as a double).  
+   */
+  public void setValue(int attIndex, double value) {
+    
+    freshAttributeVector();
+    m_AttValues[attIndex] = value;
+  }
+
+  /**
+   * Sets a specific value in the instance to the given value 
+   * (internal floating-point format). Performs a deep copy
+   * of the vector of attribute values before the value is set.
+   * Does exactly the same thing as setValue().
+   *
+   * @param indexOfIndex the index of the attribute's index 
+   * @param value the new attribute value (If the corresponding
+   * attribute is nominal (or a string) then this is the new value's
+   * index as a double).  
+   */
+  public void setValueSparse(int indexOfIndex, double value) {
+    
+    freshAttributeVector();
+    m_AttValues[indexOfIndex] = value;
+  }
+
+  /**
+   * Sets a value of a nominal or string attribute to the given
+   * value. Performs a deep copy of the vector of attribute values
+   * before the value is set.
+   *
+   * @param attIndex the attribute's index
+   * @param value the new attribute value (If the attribute
+   * is a string attribute and the value can't be found,
+   * the value is added to the attribute).
+   * @exception UnassignedDatasetException if the dataset is not set
+   * @exception IllegalArgumentException if the selected
+   * attribute is not nominal or a string, or the supplied value couldn't 
+   * be found for a nominal attribute 
+   */
+  public final void setValue(int attIndex, String value) {
+    
+    int valIndex;
+
+    if (m_Dataset == null) {
+      throw new UnassignedDatasetException("Instance doesn't have access to a dataset!");
+    }
+    if (!attribute(attIndex).isNominal() &&
+	!attribute(attIndex).isString()) {
+      throw new IllegalArgumentException("Attribute neither nominal nor string!");
+    }
+    valIndex = attribute(attIndex).indexOfValue(value);
+    if (valIndex == -1) {
+      if (attribute(attIndex).isNominal()) {
+	throw new IllegalArgumentException("Value not defined for given nominal attribute!");
+      } else {
+	attribute(attIndex).forceAddValue(value);
+	valIndex = attribute(attIndex).indexOfValue(value);
+      }
+    }
+    setValue(attIndex, (double)valIndex); 
+  }
+
+  /**
+   * Sets a specific value in the instance to the given value
+   * (internal floating-point format). Performs a deep copy of the
+   * vector of attribute values before the value is set, so if you are
+   * planning on calling setValue many times it may be faster to
+   * create a new instance using toDoubleArray.  The given attribute
+   * has to belong to a dataset.
+   *
+   * @param att the attribute 
+   * @param value the new attribute value (If the corresponding
+   * attribute is nominal (or a string) then this is the new value's
+   * index as a double).  
+   */
+  public final void setValue(Attribute att, double value) {
+
+    setValue(att.index(), value);
+  }
+
+  /**
+   * Sets a value of an nominal or string attribute to the given
+   * value. Performs a deep copy of the vector of attribute values
+   * before the value is set, so if you are planning on calling setValue many
+   * times it may be faster to create a new instance using toDoubleArray.
+   * The given attribute has to belong to a dataset.
+   *
+   * @param att the attribute
+   * @param value the new attribute value (If the attribute
+   * is a string attribute and the value can't be found,
+   * the value is added to the attribute).
+   * @exception IllegalArgumentException if the the attribute is not
+   * nominal or a string, or the value couldn't be found for a nominal
+   * attribute 
+   */
+  public final void setValue(Attribute att, String value) {
+
+    if (!att.isNominal() &&
+	!att.isString()) {
+      throw new IllegalArgumentException("Attribute neither nominal nor string!");
+    }
+    int valIndex = att.indexOfValue(value);
+    if (valIndex == -1) {
+      if (att.isNominal()) {
+	throw new IllegalArgumentException("Value not defined for given nominal attribute!");
+      } else {
+	att.forceAddValue(value);
+	valIndex = att.indexOfValue(value);
+      }
+    }
+    setValue(att.index(), (double)valIndex);
+  }
+
+  /**
+   * Sets the weight of an instance.
+   *
+   * @param weight the weight
+   */
+  public final void setWeight(double weight) {
+
+    m_Weight = weight;
+  }
+
+  /** 
+   * Returns the value of a nominal (or string) attribute
+   * for the instance.
+   *
+   * @param attIndex the attribute's index
+   * @return the value as a string
+   * @exception IllegalArgumentException if the attribute is not a nominal
+   * (or string) attribute.
+   * @exception UnassignedDatasetException if the instance doesn't belong
+   * to a dataset.
+   */
+  public final String stringValue(int attIndex) {
+
+    if (m_Dataset == null) {
+      throw new UnassignedDatasetException("Instance doesn't have access to a dataset!");
+    } 
+    if (!m_Dataset.attribute(attIndex).isNominal() &&
+	!m_Dataset.attribute(attIndex).isString()) {
+      throw new IllegalArgumentException("Attribute neither nominal nor string!");
+    }
+    return m_Dataset.attribute(attIndex).
+      value((int) value(attIndex));
+  }
+
+  /** 
+   * Returns the value of a nominal (or string) attribute
+   * for the instance.
+   *
+   * @param att the attribute
+   * @return the value as a string
+   * @exception IllegalArgumentException if the attribute is not a nominal
+   * (or string) attribute.
+   * @exception UnassignedDatasetException if the instance doesn't belong
+   * to a dataset.
+   */
+  public final String stringValue(Attribute att) {
+
+    return stringValue(att.index());
+  }
+
+  /**
+   * Returns the values of each attribute as an array of doubles.
+   *
+   * @return an array containing all the instance attribute values
+   */
+  public double[] toDoubleArray() {
+
+    double[] newValues = new double[m_AttValues.length];
+    System.arraycopy(m_AttValues, 0, newValues, 0, 
+		     m_AttValues.length);
+    return newValues;
+  }
+
+  /**
+   * Returns the description of one instance. If the instance
+   * doesn't have access to a dataset, it returns the internal
+   * floating-point values. Quotes string
+   * values that contain whitespace characters.
+   *
+   * @return the instance's description as a string
+   */
+  public String toString() {
+
+    StringBuffer text = new StringBuffer();
+    
+    for (int i = 0; i < m_AttValues.length; i++) {
+      if (i > 0) text.append(",");
+      text.append(toString(i));
+    }
+
+    return text.toString();
+  }
+
+  /**
+   * Returns the description of one value of the instance as a 
+   * string. If the instance doesn't have access to a dataset, it 
+   * returns the internal floating-point value. Quotes string
+   * values that contain whitespace characters, or if they
+   * are a question mark.
+   *
+   * @param attIndex the attribute's index
+   * @return the value's description as a string
+   */
+  public final String toString(int attIndex) {
+
+   StringBuffer text = new StringBuffer();
+   
+   if (isMissing(attIndex)) {
+     text.append("?");
+   } else {
+     if (m_Dataset == null) {
+       text.append(Utils.doubleToString(m_AttValues[attIndex],6));
+     } else {
+       if (m_Dataset.attribute(attIndex).isNominal() || 
+	   m_Dataset.attribute(attIndex).isString()) {
+         text.append(Utils.quote(stringValue(attIndex)));
+       } else {
+	 text.append(Utils.doubleToString(value(attIndex),6));
+       }
+     }
+   }
+   return text.toString();
+  }
+
+  /**
+   * Returns the description of one value of the instance as a 
+   * string. If the instance doesn't have access to a dataset it 
+   * returns the internal floating-point value. Quotes string
+   * values that contain whitespace characters, or if they
+   * are a question mark.
+   * The given attribute has to belong to a dataset.
+   *
+   * @param att the attribute
+   * @return the value's description as a string
+   */
+  public final String toString(Attribute att) {
+   
+   return toString(att.index());
+  }
+
+  /**
+   * Returns an instance's attribute value in internal format.
+   *
+   * @param attIndex the attribute's index
+   * @return the specified value as a double (If the corresponding
+   * attribute is nominal (or a string) then it returns the value's index as a 
+   * double).
+   */
+  public double value(int attIndex) {
+
+    return m_AttValues[attIndex];
+  }
+
+  /**
+   * Returns an instance's attribute value in internal format.
+   * Does exactly the same thing as value() if applied to an Instance.
+   *
+   * @param indexOfIndex the index of the attribute's index
+   * @return the specified value as a double (If the corresponding
+   * attribute is nominal (or a string) then it returns the value's index as a 
+   * double).
+   */
+  public double valueSparse(int indexOfIndex) {
+
+    return m_AttValues[indexOfIndex];
+  }  
+
+  /**
+   * Returns an instance's attribute value in internal format.
+   * The given attribute has to belong to a dataset.
+   *
+   * @param att the attribute
+   * @return the specified value as a double (If the corresponding
+   * attribute is nominal (or a string) then it returns the value's index as a
+   * double).
+   */
+  public double value(Attribute att) {
+
+    return value(att.index());
+  }
+
+  /**
+   * Returns the instance's weight.
+   *
+   * @return the instance's weight as a double
+   */
+  public final double weight() {
+
+    return m_Weight;
+  }
+
+  /**
+   * Deletes an attribute at the given position (0 to 
+   * numAttributes() - 1).
+   *
+   * @param pos the attribute's position
+   */
+
+  void forceDeleteAttributeAt(int position) {
+
+    double[] newValues = new double[m_AttValues.length - 1];
+
+    System.arraycopy(m_AttValues, 0, newValues, 0, position);
+    if (position < m_AttValues.length - 1) {
+      System.arraycopy(m_AttValues, position + 1, 
+		       newValues, position, 
+		       m_AttValues.length - (position + 1));
+    }
+    m_AttValues = newValues;
+  }
+
+  /**
+   * Inserts an attribute at the given position
+   * (0 to numAttributes()) and sets its value to be missing. 
+   *
+   * @param pos the attribute's position
+   */
+  void forceInsertAttributeAt(int position)  {
+
+    double[] newValues = new double[m_AttValues.length + 1];
+
+    System.arraycopy(m_AttValues, 0, newValues, 0, position);
+    newValues[position] = MISSING_VALUE;
+    System.arraycopy(m_AttValues, position, newValues, 
+		     position + 1, m_AttValues.length - position);
+    m_AttValues = newValues;
+  }
+
+  /**
+   * Private constructor for subclasses. Does nothing.
+   */
+  protected Instance() {
+  }
+
+  /**
+   * Clones the attribute vector of the instance and
+   * overwrites it with the clone.
+   */
+  private void freshAttributeVector() {
+
+    m_AttValues = toDoubleArray();
+  }
+
+  /**
+   * Main method for testing this class.
+   */
+  public static void main(String[] options) {
+
+    try {
+
+      // Create numeric attributes "length" and "weight"
+      Attribute length = new Attribute("length");
+      Attribute weight = new Attribute("weight");
+      
+      // Create vector to hold nominal values "first", "second", "third" 
+      FastVector my_nominal_values = new FastVector(3); 
+      my_nominal_values.addElement("first"); 
+      my_nominal_values.addElement("second"); 
+      my_nominal_values.addElement("third"); 
+      
+      // Create nominal attribute "position" 
+      Attribute position = new Attribute("position", my_nominal_values);
+      
+      // Create vector of the above attributes 
+      FastVector attributes = new FastVector(3);
+      attributes.addElement(length);
+      attributes.addElement(weight);
+      attributes.addElement(position);
+      
+      // Create the empty dataset "race" with above attributes
+      Instances race = new Instances("race", attributes, 0);
+      
+      // Make position the class attribute
+      race.setClassIndex(position.index());
+      
+      // Create empty instance with three attribute values
+      Instance inst = new Instance(3);
+      
+      // Set instance's values for the attributes "length", "weight", and "position"
+      inst.setValue(length, 5.3);
+      inst.setValue(weight, 300);
+      inst.setValue(position, "first");
+      
+      // Set instance's dataset to be the dataset "race"
+      inst.setDataset(race);
+      
+      // Print the instance
+      System.out.println("The instance: " + inst);
+      
+      // Print the first attribute
+      System.out.println("First attribute: " + inst.attribute(0));
+      
+      // Print the class attribute
+      System.out.println("Class attribute: " + inst.classAttribute());
+      
+      // Print the class index
+      System.out.println("Class index: " + inst.classIndex());
+      
+      // Say if class is missing
+      System.out.println("Class is missing: " + inst.classIsMissing());
+      
+      // Print the instance's class value in internal format
+      System.out.println("Class value (internal format): " + inst.classValue());
+      
+      // Print a shallow copy of this instance
+      Instance copy = (Instance) inst.copy();
+      System.out.println("Shallow copy: " + copy);
+      
+      // Set dataset for shallow copy
+      copy.setDataset(inst.dataset());
+      System.out.println("Shallow copy with dataset set: " + copy);
+      
+      // Unset dataset for copy, delete first attribute, and insert it again
+      copy.setDataset(null);
+      copy.deleteAttributeAt(0);
+      copy.insertAttributeAt(0);
+      copy.setDataset(inst.dataset());
+      System.out.println("Copy with first attribute deleted and inserted: " + copy); 
+      
+      // Enumerate attributes (leaving out the class attribute)
+      System.out.println("Enumerating attributes (leaving out class):");
+      Enumeration enum = inst.enumerateAttributes();
+      while (enum.hasMoreElements()) {
+	Attribute att = (Attribute) enum.nextElement();
+	System.out.println(att);
+      }
+      
+      // Headers are equivalent?
+      System.out.println("Header of original and copy equivalent: " +
+			 inst.equalHeaders(copy));
+
+      // Test for missing values
+      System.out.println("Length of copy missing: " + copy.isMissing(length));
+      System.out.println("Weight of copy missing: " + copy.isMissing(weight.index()));
+      System.out.println("Length of copy missing: " + 
+			 Instance.isMissingValue(copy.value(length)));
+      System.out.println("Missing value coded as: " + Instance.missingValue());
+
+      // Prints number of attributes and classes
+      System.out.println("Number of attributes: " + copy.numAttributes());
+      System.out.println("Number of classes: " + copy.numClasses());
+
+      // Replace missing values
+      double[] meansAndModes = {2, 3, 0};
+      copy.replaceMissingValues(meansAndModes);
+      System.out.println("Copy with missing value replaced: " + copy);
+
+      // Setting and getting values and weights
+      copy.setClassMissing();
+      System.out.println("Copy with missing class: " + copy);
+      copy.setClassValue(0);
+      System.out.println("Copy with class value set to first value: " + copy);
+      copy.setClassValue("third");
+      System.out.println("Copy with class value set to \"third\": " + copy);
+      copy.setMissing(1);
+      System.out.println("Copy with second attribute set to be missing: " + copy);
+      copy.setMissing(length);
+      System.out.println("Copy with length set to be missing: " + copy);
+      copy.setValue(0, 0);
+      System.out.println("Copy with first attribute set to 0: " + copy);
+      copy.setValue(weight, 1);
+      System.out.println("Copy with weight attribute set to 1: " + copy);
+      copy.setValue(position, "second");
+      System.out.println("Copy with position set to \"second\": " + copy);
+      copy.setValue(2, "first");
+      System.out.println("Copy with last attribute set to \"first\": " + copy);
+      System.out.println("Current weight of instance copy: " + copy.weight());
+      copy.setWeight(2);
+      System.out.println("Current weight of instance copy (set to 2): " + copy.weight());
+      System.out.println("Last value of copy: " + copy.toString(2));
+      System.out.println("Value of position for copy: " + copy.toString(position));
+      System.out.println("Last value of copy (internal format): " + copy.value(2));
+      System.out.println("Value of position for copy (internal format): " + 
+			 copy.value(position));
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Instances.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Instances.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Instances.java	(revision 10506)
@@ -0,0 +1,2150 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Instances.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Class for handling an ordered set of weighted instances. <p>
+ *
+ * Typical usage (code from the main() method of this class): <p>
+ *
+ * <code>
+ * ... <br>
+ * 
+ * // Read all the instances in the file <br>
+ * reader = new FileReader(filename); <br>
+ * instances = new Instances(reader); <br><br>
+ *
+ * // Make the last attribute be the class <br>
+ * instances.setClassIndex(instances.numAttributes() - 1); <br><br>
+ * 
+ * // Print header and instances. <br>
+ * System.out.println("\nDataset:\n"); <br> 
+ * System.out.println(instances); <br><br>
+ *
+ * ... <br>
+ * </code><p>
+ *
+ * All methods that change a set of instances are safe, ie. a change
+ * of a set of instances does not affect any other sets of
+ * instances. All methods that change a datasets's attribute
+ * information clone the dataset before it is changed.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @author Len Trigg (trigg@cs.waikato.ac.nz)
+ * @version $Revision$ 
+ */
+public class Instances implements Serializable {
+ 
+  /** The filename extension that should be used for arff files */
+  public static String FILE_EXTENSION = ".arff";
+
+  /** The dataset's name. */
+  protected String m_RelationName;         
+
+  /** The attribute information. */
+  protected FastVector m_Attributes;
+
+  /** The instances. */
+  protected FastVector m_Instances;
+
+  /** The class attribute's index */
+  protected int m_ClassIndex;
+
+  /** Buffer of values for sparse instance */
+  protected double[] m_ValueBuffer;
+
+  /** Buffer of indices for sparse instance */
+  protected int[] m_IndicesBuffer;
+
+  /**
+   * Reads an ARFF file from a reader, and assigns a weight of
+   * one to each instance. Lets the index of the class 
+   * attribute be undefined (negative).
+   *
+   * @param reader the reader
+   * @exception IOException if the ARFF file is not read 
+   * successfully
+   */
+  public Instances(Reader reader) throws IOException {
+
+    StreamTokenizer tokenizer;
+
+    tokenizer = new StreamTokenizer(reader);
+    initTokenizer(tokenizer);
+    readHeader(tokenizer);
+    m_ClassIndex = -1;
+    m_Instances = new FastVector(1000);
+    while (getInstance(tokenizer, true)) {};
+    compactify();
+  }
+ 
+  /**
+   * Reads the header of an ARFF file from a reader and 
+   * reserves space for the given number of instances. Lets
+   * the class index be undefined (negative).
+   *
+   * @param reader the reader
+   * @param capacity the capacity
+   * @exception IllegalArgumentException if the header is not read successfully
+   * or the capacity is negative.
+   * @exception IOException if there is a problem with the reader.
+   */
+   public Instances(Reader reader, int capacity) throws IOException {
+
+    StreamTokenizer tokenizer;
+
+    if (capacity < 0) {
+      throw new IllegalArgumentException("Capacity has to be positive!");
+    }
+    tokenizer = new StreamTokenizer(reader); 
+    initTokenizer(tokenizer);
+    readHeader(tokenizer);
+    m_ClassIndex = -1;
+    m_Instances = new FastVector(capacity);
+  }
+
+  /**
+   * Constructor copying all instances and references to
+   * the header information from the given set of instances.
+   *
+   * @param instances the set to be copied
+   */
+  public Instances(Instances dataset) {
+
+    this(dataset, dataset.numInstances());
+
+    dataset.copyInstances(0, this, dataset.numInstances());
+  }
+
+  /**
+   * Constructor creating an empty set of instances. Copies references
+   * to the header information from the given set of instances. Sets
+   * the capacity of the set of instances to 0 if its negative.
+   *
+   * @param instances the instances from which the header 
+   * information is to be taken
+   * @param capacity the capacity of the new dataset 
+   */
+  public Instances(Instances dataset, int capacity) {
+    
+    if (capacity < 0) {
+      capacity = 0;
+    }
+    
+    // Strings only have to be "shallow" copied because
+    // they can't be modified.
+    m_ClassIndex = dataset.m_ClassIndex;
+    m_RelationName = dataset.m_RelationName;
+    m_Attributes = dataset.m_Attributes;
+    m_Instances = new FastVector(capacity);
+  }
+
+  /**
+   * Creates a new set of instances by copying a 
+   * subset of another set.
+   *
+   * @param source the set of instances from which a subset 
+   * is to be created
+   * @param first the index of the first instance to be copied
+   * @param toCopy the number of instances to be copied
+   * @exception IllegalArgumentException if first and toCopy are out of range
+   */
+  public Instances(Instances source, int first, int toCopy) {
+    
+    this(source, toCopy);
+
+    if ((first < 0) || ((first + toCopy) > source.numInstances())) {
+      throw new IllegalArgumentException("Parameters first and/or toCopy out "+
+                                         "of range");
+    }
+    source.copyInstances(first, this, toCopy);
+  }
+
+  /**
+   * Creates an empty set of instances. Uses the given
+   * attribute information. Sets the capacity of the set of 
+   * instances to 0 if its negative. Given attribute information
+   * must not be changed after this constructor has been used.
+   *
+   * @param name the name of the relation
+   * @param attInfo the attribute information
+   * @param capacity the capacity of the set
+   */
+  public Instances(String name, FastVector attInfo, int capacity) {
+
+    m_RelationName = name;
+    m_ClassIndex = -1;
+    m_Attributes = attInfo;
+    for (int i = 0; i < numAttributes(); i++) {
+      attribute(i).setIndex(i);
+    }
+    m_Instances = new FastVector(capacity);
+  }
+ 
+  /**
+   * Create a copy of the structure, but "cleanse" string types (i.e.
+   * doesn't contain references to the strings seen in the past).
+   *
+   * @return a copy of the instance structure.
+   */
+  public Instances stringFreeStructure() {
+
+    FastVector atts = (FastVector)m_Attributes.copy();
+    for (int i = 0 ; i < atts.size(); i++) {
+      Attribute att = (Attribute)atts.elementAt(i);
+      if (att.type() == Attribute.STRING) {
+        atts.setElementAt(new Attribute(att.name(), null), i);
+      }
+    }
+    Instances result = new Instances(relationName(), atts, 0);
+    result.m_ClassIndex = m_ClassIndex;
+    return result;
+  }
+
+  /**
+   * Adds one instance to the end of the set. 
+   * Shallow copies instance before it is added. Increases the
+   * size of the dataset if it is not large enough. Does not
+   * check if the instance is compatible with the dataset.
+   *
+   * @param instance the instance to be added
+   */
+  public final void add(Instance instance) {
+
+    Instance newInstance = (Instance)instance.copy();
+
+    newInstance.setDataset(this);
+    m_Instances.addElement(newInstance);
+  }
+
+  /**
+   * Returns an attribute.
+   *
+   * @param index the attribute's index
+   * @return the attribute at the given position
+   */ 
+  public final Attribute attribute(int index) {
+    
+    return (Attribute) m_Attributes.elementAt(index);
+  }
+
+  /**
+   * Returns an attribute given its name. If there is more than
+   * one attribute with the same name, it returns the first one.
+   * Returns null if the attribute can't be found.
+   *
+   * @param name the attribute's name
+   * @return the attribute with the given name, null if the
+   * attribute can't be found
+   */ 
+  public final Attribute attribute(String name) {
+    
+    for (int i = 0; i < numAttributes(); i++) {
+      if (attribute(i).name().equals(name)) {
+	return attribute(i);
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Checks for string attributes in the dataset
+   *
+   * @return true if string attributes are present, false otherwise
+   */
+  public boolean checkForStringAttributes() {
+
+    int i = 0;
+   
+    while (i < m_Attributes.size()) {
+      if (attribute(i++).isString()) {
+	return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Checks if the given instance is compatible
+   * with this dataset. Only looks at the size of
+   * the instance and the ranges of the values for 
+   * nominal and string attributes.
+   *
+   * @return true if the instance is compatible with the dataset 
+   */
+  public final boolean checkInstance(Instance instance) {
+
+    if (instance.numAttributes() != numAttributes()) {
+      return false;
+    }
+    for (int i = 0; i < numAttributes(); i++) {
+      if (instance.isMissing(i)) {
+	continue;
+      } else if (attribute(i).isNominal() ||
+		 attribute(i).isString()) {
+	if (!(Utils.eq(instance.value(i),
+		       (double)(int)instance.value(i)))) {
+	  return false;
+	} else if (Utils.sm(instance.value(i), 0) ||
+		   Utils.gr(instance.value(i),
+			    attribute(i).numValues())) {
+	  return false;
+	}
+      }
+    }
+    return true;
+  }
+	
+  /**
+   * Returns the class attribute.
+   *
+   * @return the class attribute
+   * @exception UnassignedClassException if the class is not set
+   */
+  public final Attribute classAttribute() {
+
+    if (m_ClassIndex < 0) {
+      throw new UnassignedClassException("Class index is negative (not set)!");
+    }
+    return attribute(m_ClassIndex);
+  }
+
+  /**
+   * Returns the class attribute's index. Returns negative number
+   * if it's undefined.
+   *
+   * @return the class index as an integer
+   */
+  public final int classIndex() {
+    
+    return m_ClassIndex;
+  }
+ 
+  /**
+   * Compactifies the set of instances. Decreases the capacity of
+   * the set so that it matches the number of instances in the set.
+   */
+  public final void compactify() {
+
+    m_Instances.trimToSize();
+  }
+
+  /**
+   * Removes all instances from the set.
+   */
+  public final void delete() {
+    
+    m_Instances = new FastVector();
+  }
+
+  /**
+   * Removes an instance at the given position from the set.
+   *
+   * @param index the instance's position
+   */
+  public final void delete(int index) {
+    
+    m_Instances.removeElementAt(index);
+  }
+
+  /**
+   * Deletes an attribute at the given position 
+   * (0 to numAttributes() - 1). A deep copy of the attribute
+   * information is performed before the attribute is deleted.
+   *
+   * @param pos the attribute's position
+   * @exception IllegalArgumentException if the given index is out of range or the
+   * class attribute is being deleted
+   */
+  public void deleteAttributeAt(int position) {
+	 
+    if ((position < 0) || (position >= m_Attributes.size())) {
+      throw new IllegalArgumentException("Index out of range");
+    }
+    if (position == m_ClassIndex) {
+      throw new IllegalArgumentException("Can't delete class attribute");
+    }
+    freshAttributeInfo();
+    if (m_ClassIndex > position) {
+      m_ClassIndex--;
+    }
+    m_Attributes.removeElementAt(position);
+    for (int i = position; i < m_Attributes.size(); i++) {
+      Attribute current = (Attribute)m_Attributes.elementAt(i);
+      current.setIndex(current.index() - 1);
+    }
+    for (int i = 0; i < numInstances(); i++) {
+      instance(i).forceDeleteAttributeAt(position); 
+    }
+  }
+
+  /**
+   * Deletes all string attributes in the dataset. A deep copy of the attribute
+   * information is performed before an attribute is deleted.
+   *
+   * @exception IllegalArgumentException if string attribute couldn't be 
+   * successfully deleted (probably because it is the class attribute).
+   */
+  public void deleteStringAttributes() {
+
+    int i = 0;
+    while (i < m_Attributes.size()) {
+      if (attribute(i).isString()) {
+	deleteAttributeAt(i);
+      } else {
+	i++;
+      }
+    }
+  }
+
+  /**
+   * Removes all instances with missing values for a particular
+   * attribute from the dataset.
+   *
+   * @param attIndex the attribute's index
+   */
+  public final void deleteWithMissing(int attIndex) {
+
+    FastVector newInstances = new FastVector(numInstances());
+
+    for (int i = 0; i < numInstances(); i++) {
+      if (!instance(i).isMissing(attIndex)) {
+	newInstances.addElement(instance(i));
+      }
+    }
+    m_Instances = newInstances;
+  }
+
+  /**
+   * Removes all instances with missing values for a particular
+   * attribute from the dataset.
+   *
+   * @param att the attribute
+   */
+  public final void deleteWithMissing(Attribute att) {
+
+    deleteWithMissing(att.index());
+  }
+
+  /**
+   * Removes all instances with a missing class value
+   * from the dataset.
+   *
+   * @exception UnassignedClassException if class is not set
+   */
+  public final void deleteWithMissingClass() {
+
+    if (m_ClassIndex < 0) {
+      throw new UnassignedClassException("Class index is negative (not set)!");
+    }
+    deleteWithMissing(m_ClassIndex);
+  }
+
+  /**
+   * Returns an enumeration of all the attributes.
+   *
+   * @return enumeration of all the attributes.
+   */
+  public Enumeration enumerateAttributes() {
+
+    return m_Attributes.elements(m_ClassIndex);
+  }
+
+  /**
+   * Returns an enumeration of all instances in the dataset.
+   *
+   * @return enumeration of all instances in the dataset
+   */
+  public final Enumeration enumerateInstances() {
+
+    return m_Instances.elements();
+  }
+
+  /**
+   * Checks if two headers are equivalent.
+   *
+   * @param dataset another dataset
+   * @return true if the header of the given dataset is equivalent 
+   * to this header
+   */
+  public final boolean equalHeaders(Instances dataset){
+
+    // Check class and all attributes
+    if (m_ClassIndex != dataset.m_ClassIndex) {
+      return false;
+    }
+    if (m_Attributes.size() != dataset.m_Attributes.size()) {
+      return false;
+    }
+    for (int i = 0; i < m_Attributes.size(); i++) {
+      if (!(attribute(i).equals(dataset.attribute(i)))) {
+	return false;
+      }
+    }
+    return true;
+  }
+ 
+  /**
+   * Returns the first instance in the set.
+   *
+   * @return the first instance in the set
+   */
+  public final Instance firstInstance() {
+    
+    return (Instance)m_Instances.firstElement();
+  }
+ 
+  /**
+   * Inserts an attribute at the given position (0 to 
+   * numAttributes()) and sets all values to be missing.
+   * Shallow copies the attribute before it is inserted, and performs
+   * a deep copy of the existing attribute information.
+   *
+   * @param att the attribute to be inserted
+   * @param pos the attribute's position
+   * @exception IllegalArgumentException if the given index is out of range
+   */
+  public void insertAttributeAt(Attribute att, int position) {
+	 
+    if ((position < 0) ||
+	(position > m_Attributes.size())) {
+      throw new IllegalArgumentException("Index out of range");
+    }
+    att = (Attribute)att.copy();
+    freshAttributeInfo();
+    att.setIndex(position);
+    m_Attributes.insertElementAt(att, position);
+    for (int i = position + 1; i < m_Attributes.size(); i++) {
+      Attribute current = (Attribute)m_Attributes.elementAt(i);
+      current.setIndex(current.index() + 1);
+    }
+    for (int i = 0; i < numInstances(); i++) {
+      instance(i).forceInsertAttributeAt(position);
+    }
+    if (m_ClassIndex >= position) {
+      m_ClassIndex++;
+    }
+  }
+
+  /**
+   * Returns the instance at the given position.
+   *
+   * @param index the instance's index
+   * @return the instance at the given position
+   */
+  public final Instance instance(int index) {
+
+    return (Instance)m_Instances.elementAt(index);
+  }
+
+  /**
+   * Returns the last instance in the set.
+   *
+   * @return the last instance in the set
+   */
+  public final Instance lastInstance() {
+    
+    return (Instance)m_Instances.lastElement();
+  }
+
+  /**
+   * Returns the mean (mode) for a numeric (nominal) attribute as
+   * a floating-point value. Returns 0 if the attribute is neither nominal nor 
+   * numeric. If all values are missing it returns zero.
+   *
+   * @param attIndex the attribute's index
+   * @return the mean or the mode
+   */
+  public final double meanOrMode(int attIndex) {
+
+    double result, found;
+    int [] counts;
+
+    if (attribute(attIndex).isNumeric()) {
+      result = found = 0;
+      for (int j = 0; j < numInstances(); j++) {
+	if (!instance(j).isMissing(attIndex)) {
+	  found += instance(j).weight();
+	  result += instance(j).weight()*instance(j).value(attIndex);
+	}
+      }
+      if (Utils.eq(found, 0)) {
+	return 0;
+      } else {
+	return result / found;
+      }
+    } else if (attribute(attIndex).isNominal()) {
+      counts = new int[attribute(attIndex).numValues()];
+      for (int j = 0; j < numInstances(); j++) {
+	if (!instance(j).isMissing(attIndex)) {
+	  counts[(int) instance(j).value(attIndex)] += instance(j).weight();
+	}
+      }
+      return (double)Utils.maxIndex(counts);
+    } else {
+      return 0;
+    }
+  }
+
+  /**
+   * Returns the mean (mode) for a numeric (nominal) attribute as a
+   * floating-point value.  Returns 0 if the attribute is neither
+   * nominal nor numeric.  If all values are missing it returns zero.
+   *
+   * @param att the attribute
+   * @return the mean or the mode 
+   */
+  public final double meanOrMode(Attribute att) {
+
+    return meanOrMode(att.index());
+  }
+
+  /**
+   * Returns the number of attributes.
+   *
+   * @return the number of attributes as an integer
+   */
+  public final int numAttributes() {
+
+    return m_Attributes.size();
+  }
+
+  /**
+   * Returns the number of class labels.
+   *
+   * @return the number of class labels as an integer if the class 
+   * attribute is nominal, 1 otherwise.
+   * @exception UnassignedClassException if the class is not set
+   */
+  public final int numClasses() {
+    
+    if (m_ClassIndex < 0) {
+      throw new UnassignedClassException("Class index is negative (not set)!");
+    }
+    if (!classAttribute().isNominal()) {
+      return 1;
+    } else {
+      return classAttribute().numValues();
+    }
+  }
+
+  /**
+   * Returns the number of distinct values of a given attribute.
+   * Returns the number of instances if the attribute is a
+   * string attribute. The value 'missing' is not counted.
+   *
+   * @param attIndex the attribute
+   * @return the number of distinct values of a given attribute
+   */
+  public final int numDistinctValues(int attIndex) {
+
+    if (attribute(attIndex).isNumeric()) {
+      double [] attVals = attributeToDoubleArray(attIndex);
+      int [] sorted = Utils.sort(attVals);
+      double prev = 0;
+      int counter = 0;
+      for (int i = 0; i < sorted.length; i++) {
+	Instance current = instance(sorted[i]);
+	if (current.isMissing(attIndex)) {
+	  break;
+	}
+	if ((i == 0) || 
+	    Utils.gr(current.value(attIndex), prev)) {
+	  prev = current.value(attIndex);
+	  counter++;
+	}
+      }
+      return counter;
+    } else {
+      return attribute(attIndex).numValues();
+    }
+  }
+
+  /**
+   * Returns the number of distinct values of a given attribute.
+   * Returns the number of instances if the attribute is a
+   * string attribute. The value 'missing' is not counted.
+   *
+   * @param att the attribute
+   * @return the number of distinct values of a given attribute
+   */
+  public final int numDistinctValues(Attribute att) {
+
+    return numDistinctValues(att.index());
+  }
+  
+  /**
+   * Returns the number of instances in the dataset.
+   *
+   * @return the number of instances in the dataset as an integer
+   */
+  public final int numInstances() {
+
+    return m_Instances.size();
+  }
+
+  /**
+   * Shuffles the instances in the set so that they are ordered 
+   * randomly.
+   *
+   * @param random a random number generator
+   */
+  public final void randomize(Random random) {
+
+    for (int j = numInstances() - 1; j > 0; j--)
+      swap(j,(int)(random.nextDouble()*(double)j));
+  }
+
+  /**
+   * Reads a single instance from the reader and appends it
+   * to the dataset.  Automatically expands the dataset if it
+   * is not large enough to hold the instance. This method does
+   * not check for carriage return at the end of the line.
+   *
+   * @param reader the reader 
+   * @return false if end of file has been reached
+   * @exception IOException if the information is not read 
+   * successfully
+   */ 
+  public final boolean readInstance(Reader reader) 
+       throws IOException {
+
+    StreamTokenizer tokenizer = new StreamTokenizer(reader);
+    
+    initTokenizer(tokenizer);
+    return getInstance(tokenizer, false);
+  }    
+
+  /**
+   * Returns the relation's name.
+   *
+   * @return the relation's name as a string
+   */
+  public final String relationName() {
+
+    return m_RelationName;
+  }
+
+  /**
+   * Renames an attribute. This change only affects this
+   * dataset.
+   *
+   * @param att the attribute's index
+   * @param name the new name
+   */
+  public final void renameAttribute(int att, String name) {
+
+    Attribute newAtt = attribute(att).copy(name);
+    FastVector newVec = new FastVector(numAttributes());
+
+    for (int i = 0; i < numAttributes(); i++) {
+      if (i == att) {
+	newVec.addElement(newAtt);
+      } else {
+	newVec.addElement(attribute(i));
+      }
+    }
+    m_Attributes = newVec;
+  }
+
+  /**
+   * Renames an attribute. This change only affects this
+   * dataset.
+   *
+   * @param att the attribute
+   * @param name the new name
+   */
+  public final void renameAttribute(Attribute att, String name) {
+
+    renameAttribute(att.index(), name);
+  }
+
+  /**
+   * Renames the value of a nominal (or string) attribute value. This
+   * change only affects this dataset.
+   *
+   * @param att the attribute's index
+   * @param val the value's index
+   * @param name the new name 
+   */
+  public final void renameAttributeValue(int att, int val, String name) {
+
+    Attribute newAtt = (Attribute)attribute(att).copy();
+    FastVector newVec = new FastVector(numAttributes());
+
+    newAtt.setValue(val, name);
+    for (int i = 0; i < numAttributes(); i++) {
+      if (i == att) {
+	newVec.addElement(newAtt);
+      } else {
+	newVec.addElement(attribute(i));
+      }
+    }
+    m_Attributes = newVec;
+  }
+
+  /**
+   * Renames the value of a nominal (or string) attribute value. This
+   * change only affects this dataset.
+   *
+   * @param att the attribute
+   * @param val the value
+   * @param name the new name
+   */
+  public final void renameAttributeValue(Attribute att, String val, 
+                                         String name) {
+
+    renameAttributeValue(att.index(), att.indexOfValue(val), name);
+  }
+
+  /**
+   * Creates a new dataset of the same size using random sampling
+   * with replacement.
+   *
+   * @param random a random number generator
+   * @return the new dataset
+   */
+  public final Instances resample(Random random) {
+
+    Instances newData = new Instances(this, numInstances());
+    while (newData.numInstances() < numInstances()) {
+      int i = (int) (random.nextDouble() * (double) numInstances());
+      newData.add(instance(i));
+    }
+    return newData;
+  }
+
+  /**
+   * Creates a new dataset of the same size using random sampling
+   * with replacement according to the current instance weights. The
+   * weights of the instances in the new dataset are set to one.
+   *
+   * @param random a random number generator
+   * @return the new dataset
+   */
+  public final Instances resampleWithWeights(Random random) {
+
+    double [] weights = new double[numInstances()];
+    boolean foundOne = false;
+    for (int i = 0; i < weights.length; i++) {
+      weights[i] = instance(i).weight();
+      if (!Utils.eq(weights[i], weights[0])) {
+        foundOne = true;
+      }
+    }
+    if (foundOne) {
+      return resampleWithWeights(random, weights);
+    } else {
+      return new Instances(this);
+    }
+  }
+
+
+  /**
+   * Creates a new dataset of the same size using random sampling
+   * with replacement according to the given weight vector. The
+   * weights of the instances in the new dataset are set to one.
+   * The length of the weight vector has to be the same as the
+   * number of instances in the dataset, and all weights have to
+   * be positive.
+   *
+   * @param random a random number generator
+   * @param weights the weight vector
+   * @return the new dataset
+   * @exception IllegalArgumentException if the weights array is of the wrong
+   * length or contains negative weights.
+   */
+  public final Instances resampleWithWeights(Random random, 
+					     double[] weights) {
+
+    if (weights.length != numInstances()) {
+      throw new IllegalArgumentException("weights.length != numInstances.");
+    }
+    Instances newData = new Instances(this, numInstances());
+    double[] probabilities = new double[numInstances()];
+    double sumProbs = 0, sumOfWeights = Utils.sum(weights);
+    for (int i = 0; i < numInstances(); i++) {
+      sumProbs += random.nextDouble();
+      probabilities[i] = sumProbs;
+    }
+    Utils.normalize(probabilities, sumProbs / sumOfWeights);
+
+    // Make sure that rounding errors don't mess things up
+    probabilities[numInstances() - 1] = sumOfWeights;
+    int k = 0; int l = 0;
+    sumProbs = 0;
+    while ((k < numInstances() && (l < numInstances()))) {
+      if (weights[l] < 0) {
+	throw new IllegalArgumentException("Weights have to be positive.");
+      }
+      sumProbs += weights[l];
+      while ((k < numInstances()) &&
+	     (probabilities[k] <= sumProbs)) { 
+	newData.add(instance(l));
+	newData.instance(k).setWeight(1);
+	k++;
+      }
+      l++;
+    }
+    return newData;
+  }
+
+  /** 
+   * Sets the class attribute.
+   *
+   * @param att attribute to be the class
+   */
+  public final void setClass(Attribute att) {
+
+    m_ClassIndex = att.index();
+  }
+
+  /** 
+   * Sets the class index of the set.
+   * If the class index is negative there is assumed to be no class.
+   * (ie. it is undefined)
+   *
+   * @param classIndex the new class index
+   * @exception IllegalArgumentException if the class index is too big or < 0
+   */
+  public final void setClassIndex(int classIndex) {
+
+    if (classIndex >= numAttributes()) {
+      throw new IllegalArgumentException("Invalid class index: " + classIndex);
+    }
+    m_ClassIndex = classIndex;
+  }
+
+  /**
+   * Sets the relation's name.
+   *
+   * @param newName the new relation name.
+   */
+  public final void setRelationName(String newName) {
+    
+    m_RelationName = newName;
+  }
+
+  /**
+   * Sorts the instances based on an attribute. For numeric attributes, 
+   * instances are sorted in ascending order. For nominal attributes, 
+   * instances are sorted based on the attribute label ordering 
+   * specified in the header. Instances with missing values for the 
+   * attribute are placed at the end of the dataset.
+   *
+   * @param attIndex the attribute's index
+   */
+  public final void sort(int attIndex) {
+
+    int i,j;
+
+    // move all instances with missing values to end
+    j = numInstances() - 1;
+    i = 0;
+    while (i <= j) {
+      if (instance(j).isMissing(attIndex)) {
+	j--;
+      } else {
+	if (instance(i).isMissing(attIndex)) {
+	  swap(i,j);
+	  j--;
+	}
+	i++;
+      }
+    }
+    quickSort(attIndex, 0, j);
+  }
+
+  /**
+   * Sorts the instances based on an attribute. For numeric attributes, 
+   * instances are sorted into ascending order. For nominal attributes, 
+   * instances are sorted based on the attribute label ordering 
+   * specified in the header. Instances with missing values for the 
+   * attribute are placed at the end of the dataset.
+   *
+   * @param att the attribute
+   */
+  public final void sort(Attribute att) {
+
+    sort(att.index());
+  }
+
+  /**
+   * Stratifies a set of instances according to its class values 
+   * if the class attribute is nominal (so that afterwards a 
+   * stratified cross-validation can be performed).
+   *
+   * @param numFolds the number of folds in the cross-validation
+   * @exception UnassignedClassException if the class is not set
+   */
+  public final void stratify(int numFolds) {
+    
+    if (numFolds <= 0) {
+      throw new IllegalArgumentException("Number of folds must be greater than 1");
+    }
+    if (m_ClassIndex < 0) {
+      throw new UnassignedClassException("Class index is negative (not set)!");
+    }
+    if (classAttribute().isNominal()) {
+
+      // sort by class
+      int index = 1;
+      while (index < numInstances()) {
+	Instance instance1 = instance(index - 1);
+	for (int j = index; j < numInstances(); j++) {
+	  Instance instance2 = instance(j);
+	  if ((instance1.classValue() == instance2.classValue()) ||
+	      (instance1.classIsMissing() && 
+	       instance2.classIsMissing())) {
+	    swap(index,j);
+	    index++;
+	  }
+	}
+	index++;
+      }
+      stratStep(numFolds);
+    }
+  }
+ 
+  /**
+   * Computes the sum of all the instances' weights.
+   *
+   * @return the sum of all the instances' weights as a double
+   */
+  public final double sumOfWeights() {
+    
+    double sum = 0;
+
+    for (int i = 0; i < numInstances(); i++) {
+      sum += instance(i).weight();
+    }
+    return sum;
+  }
+
+  /**
+   * Creates the test set for one fold of a cross-validation on 
+   * the dataset.
+   *
+   * @param numFolds the number of folds in the cross-validation. Must
+   * be greater than 1.
+   * @param numFold 0 for the first fold, 1 for the second, ...
+   * @return the test set as a set of weighted instances
+   * @exception IllegalArgumentException if the number of folds is less than 2
+   * or greater than the number of instances.
+   */
+  public Instances testCV(int numFolds, int numFold) {
+
+    int numInstForFold, first, offset;
+    Instances test;
+    
+    if (numFolds < 2) {
+      throw new IllegalArgumentException("Number of folds must be at least 2!");
+    }
+    if (numFolds > numInstances()) {
+      throw new IllegalArgumentException("Can't have more folds than instances!");
+    }
+    numInstForFold = numInstances() / numFolds;
+    if (numFold < numInstances() % numFolds){
+      numInstForFold++;
+      offset = numFold;
+    }else
+      offset = numInstances() % numFolds;
+    test = new Instances(this, numInstForFold);
+    first = numFold * (numInstances() / numFolds) + offset;
+    copyInstances(first, test, numInstForFold);
+    return test;
+  }
+ 
+  /**
+   * Returns the dataset as a string in ARFF format. Strings
+   * are quoted if they contain whitespace characters, or if they
+   * are a question mark.
+   *
+   * @return the dataset in ARFF format as a string
+   */
+  public final String toString() {
+    
+    StringBuffer text = new StringBuffer();
+    
+    text.append("@relation " + Utils.quote(m_RelationName) + "\n\n");
+    for (int i = 0; i < numAttributes(); i++) {
+      text.append(attribute(i) + "\n");
+    }
+    text.append("\n@data\n");
+    for (int i = 0; i < numInstances(); i++) {
+      text.append(instance(i));
+      if (i < numInstances() - 1) {
+	text.append('\n');
+      }
+    }
+    return text.toString();
+  }
+
+  /**
+   * Creates the training set for one fold of a cross-validation 
+   * on the dataset.
+   *
+   * @param numFolds the number of folds in the cross-validation. Must
+   * be greater than 1.
+   * @param numFold 0 for the first fold, 1 for the second, ...
+   * @return the training set as a set of weighted 
+   * instances
+   * @exception IllegalArgumentException if the number of folds is less than 2
+   * or greater than the number of instances.
+   */
+  public Instances trainCV(int numFolds, int numFold) {
+
+    int numInstForFold, first, offset;
+    Instances train;
+ 
+    if (numFolds < 2) {
+      throw new IllegalArgumentException("Number of folds must be at least 2!");
+    }
+    if (numFolds > numInstances()) {
+      throw new IllegalArgumentException("Can't have more folds than instances!");
+    }
+    numInstForFold = numInstances() / numFolds;
+    if (numFold < numInstances() % numFolds) {
+      numInstForFold++;
+      offset = numFold;
+    }else
+      offset = numInstances() % numFolds;
+    train = new Instances(this, numInstances() - numInstForFold);
+    first = numFold * (numInstances() / numFolds) + offset;
+    copyInstances(0, train, first);
+    copyInstances(first + numInstForFold, train,
+		  numInstances() - first - numInstForFold);
+
+    return train;
+  }
+
+  /**
+   * Computes the variance for a numeric attribute.
+   *
+   * @param attIndex the numeric attribute
+   * @return the variance if the attribute is numeric
+   * @exception IllegalArgumentException if the attribute is not numeric
+   */
+  public final double variance(int attIndex) {
+  
+    double sum = 0, sumSquared = 0, sumOfWeights = 0;
+
+    if (!attribute(attIndex).isNumeric()) {
+      throw new IllegalArgumentException("Can't compute variance because attribute is " +
+			  "not numeric!");
+    }
+    for (int i = 0; i < numInstances(); i++) {
+      if (!instance(i).isMissing(attIndex)) {
+	sum += instance(i).weight() * 
+	  instance(i).value(attIndex);
+	sumSquared += instance(i).weight() * 
+	  instance(i).value(attIndex) *
+	  instance(i).value(attIndex);
+	sumOfWeights += instance(i).weight();
+      }
+    }
+    if (Utils.smOrEq(sumOfWeights, 1)) {
+      return 0;
+    }
+    return (sumSquared - (sum * sum / sumOfWeights)) / 
+      (sumOfWeights - 1);
+  }
+
+  /**
+   * Computes the variance for a numeric attribute.
+   *
+   * @param att the numeric attribute
+   * @return the variance if the attribute is numeric
+   * @exception IllegalArgumentException if the attribute is not numeric
+   */
+  public final double variance(Attribute att) {
+    
+    return variance(att.index());
+  }
+  
+  /**
+   * Calculates summary statistics on the values that appear in this
+   * set of instances for a specified attribute.
+   *
+   * @param index the index of the attribute to summarize.
+   * @return an AttributeStats object with it's fields calculated.
+   */
+  public AttributeStats attributeStats(int index) {
+
+    AttributeStats result = new AttributeStats();
+    if (attribute(index).isNominal()) {
+      result.nominalCounts = new int [attribute(index).numValues()];
+    }
+    if (attribute(index).isNumeric()) {
+      result.numericStats = new weka.experiment.Stats();
+    }
+    result.totalCount = numInstances();
+
+    double [] attVals = attributeToDoubleArray(index);
+    int [] sorted = Utils.sort(attVals);
+    int currentCount = 0;
+    double prev = Instance.missingValue();
+    for (int j = 0; j < numInstances(); j++) {
+      Instance current = instance(sorted[j]);
+      if (current.isMissing(index)) {
+	result.missingCount = numInstances() - j;
+	break;
+      }
+      if (Utils.eq(current.value(index), prev)) {
+	currentCount++;
+      } else {
+	result.addDistinct(prev, currentCount);
+	currentCount = 1;
+	prev = current.value(index);
+      }
+    }
+    result.addDistinct(prev, currentCount);
+    result.distinctCount--; // So we don't count "missing" as a value 
+    return result;
+  }
+  
+  /**
+   * Gets the value of all instances in this dataset for a particular
+   * attribute. Useful in conjunction with Utils.sort to allow iterating
+   * through the dataset in sorted order for some attribute.
+   *
+   * @param index the index of the attribute.
+   * @return an array containing the value of the desired attribute for
+   * each instance in the dataset. 
+   */
+  public double [] attributeToDoubleArray(int index) {
+
+    double [] result = new double[numInstances()];
+    for (int i = 0; i < result.length; i++) {
+      result[i] = instance(i).value(index);
+    }
+    return result;
+  }
+
+  /**
+   * Generates a string summarizing the set of instances. Gives a breakdown
+   * for each attribute indicating the number of missing/discrete/unique
+   * values and other information.
+   *
+   * @return a string summarizing the dataset
+   */
+  public String toSummaryString() {
+
+    StringBuffer result = new StringBuffer();
+    result.append("Relation Name:  ").append(relationName()).append('\n');
+    result.append("Num Instances:  ").append(numInstances()).append('\n');
+    result.append("Num Attributes: ").append(numAttributes()).append('\n');
+    result.append('\n');
+
+    result.append(Utils.padLeft("", 5)).append(Utils.padRight("Name", 25));
+    result.append(Utils.padLeft("Type", 5)).append(Utils.padLeft("Nom", 5));
+    result.append(Utils.padLeft("Int", 5)).append(Utils.padLeft("Real", 5));
+    result.append(Utils.padLeft("Missing", 12));
+    result.append(Utils.padLeft("Unique", 12));
+    result.append(Utils.padLeft("Dist", 6)).append('\n');
+    for (int i = 0; i < numAttributes(); i++) {
+      Attribute a = attribute(i);
+      AttributeStats as = attributeStats(i);
+      result.append(Utils.padLeft("" + (i + 1), 4)).append(' ');
+      result.append(Utils.padRight(a.name(), 25)).append(' ');
+      long percent;
+      switch (a.type()) {
+      case Attribute.NOMINAL:
+	result.append(Utils.padLeft("Nom", 4)).append(' ');
+	percent = Math.round(100.0 * as.intCount / as.totalCount);
+	result.append(Utils.padLeft("" + percent, 3)).append("% ");
+	result.append(Utils.padLeft("" + 0, 3)).append("% ");
+	percent = Math.round(100.0 * as.realCount / as.totalCount);
+	result.append(Utils.padLeft("" + percent, 3)).append("% ");
+	break;
+      case Attribute.NUMERIC:
+	result.append(Utils.padLeft("Num", 4)).append(' ');
+	result.append(Utils.padLeft("" + 0, 3)).append("% ");
+	percent = Math.round(100.0 * as.intCount / as.totalCount);
+	result.append(Utils.padLeft("" + percent, 3)).append("% ");
+	percent = Math.round(100.0 * as.realCount / as.totalCount);
+	result.append(Utils.padLeft("" + percent, 3)).append("% ");
+	break;
+      case Attribute.STRING:
+	result.append(Utils.padLeft("Str", 4)).append(' ');
+	percent = Math.round(100.0 * as.intCount / as.totalCount);
+	result.append(Utils.padLeft("" + percent, 3)).append("% ");
+	result.append(Utils.padLeft("" + 0, 3)).append("% ");
+	percent = Math.round(100.0 * as.realCount / as.totalCount);
+	result.append(Utils.padLeft("" + percent, 3)).append("% ");
+	break;
+      default:
+	result.append(Utils.padLeft("???", 4)).append(' ');
+	result.append(Utils.padLeft("" + 0, 3)).append("% ");
+	percent = Math.round(100.0 * as.intCount / as.totalCount);
+	result.append(Utils.padLeft("" + percent, 3)).append("% ");
+	percent = Math.round(100.0 * as.realCount / as.totalCount);
+	result.append(Utils.padLeft("" + percent, 3)).append("% ");
+	break;
+      }
+      result.append(Utils.padLeft("" + as.missingCount, 5)).append(" /");
+      percent = Math.round(100.0 * as.missingCount / as.totalCount);
+      result.append(Utils.padLeft("" + percent, 3)).append("% ");
+      result.append(Utils.padLeft("" + as.uniqueCount, 5)).append(" /");
+      percent = Math.round(100.0 * as.uniqueCount / as.totalCount);
+      result.append(Utils.padLeft("" + percent, 3)).append("% ");
+      result.append(Utils.padLeft("" + as.distinctCount, 5)).append(' ');
+      result.append('\n');
+    }
+    return result.toString();
+  }
+  
+  /**
+   * Reads a single instance using the tokenizer and appends it
+   * to the dataset. Automatically expands the dataset if it
+   * is not large enough to hold the instance.
+   *
+   * @param tokenizer the tokenizer to be used
+   * @param flag if method should test for carriage return after 
+   * each instance
+   * @return false if end of file has been reached
+   * @exception IOException if the information is not read 
+   * successfully
+   */ 
+  protected boolean getInstance(StreamTokenizer tokenizer, 
+				boolean flag) 
+       throws IOException {
+    
+    // Check if any attributes have been declared.
+    if (m_Attributes.size() == 0) {
+      errms(tokenizer,"no header information available");
+    }
+
+    // Check if end of file reached.
+    getFirstToken(tokenizer);
+    if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
+      return false;
+    }
+    
+    // Parse instance
+    if (tokenizer.ttype == '{') {
+      return getInstanceSparse(tokenizer, flag);
+    } else {
+      return getInstanceFull(tokenizer, flag);
+    }
+  }
+
+  /**
+   * Reads a single instance using the tokenizer and appends it
+   * to the dataset. Automatically expands the dataset if it
+   * is not large enough to hold the instance.
+   *
+   * @param tokenizer the tokenizer to be used
+   * @param flag if method should test for carriage return after 
+   * each instance
+   * @return false if end of file has been reached
+   * @exception IOException if the information is not read 
+   * successfully
+   */ 
+  protected boolean getInstanceSparse(StreamTokenizer tokenizer, 
+				      boolean flag) 
+       throws IOException {
+
+    int valIndex, numValues = 0, maxIndex = -1;
+    
+    // Get values
+    do {
+      
+      // Get index
+      getIndex(tokenizer);
+      if (tokenizer.ttype == '}') {
+	break;
+      }
+       
+      // Is index valid?
+      try{
+	m_IndicesBuffer[numValues] = Integer.valueOf(tokenizer.sval).intValue();
+      } catch (NumberFormatException e) {
+	errms(tokenizer,"index number expected");
+      }
+      if (m_IndicesBuffer[numValues] <= maxIndex) {
+	errms(tokenizer,"indices have to be ordered");
+      }
+      if ((m_IndicesBuffer[numValues] < 0) || 
+	  (m_IndicesBuffer[numValues] >= numAttributes())) {
+	errms(tokenizer,"index out of bounds");
+      }
+      maxIndex = m_IndicesBuffer[numValues];
+
+      // Get value;
+      getNextToken(tokenizer);
+
+      // Check if value is missing.
+      if  (tokenizer.ttype == '?') {
+	m_ValueBuffer[numValues] = Instance.missingValue();
+      } else {
+
+	// Check if token is valid.
+	if (tokenizer.ttype != StreamTokenizer.TT_WORD) {
+	  errms(tokenizer,"not a valid value");
+	}
+	if (attribute(m_IndicesBuffer[numValues]).isNominal()) {
+	  
+	  // Check if value appears in header.
+	  valIndex = 
+	    attribute(m_IndicesBuffer[numValues]).indexOfValue(tokenizer.sval);
+	  if (valIndex == -1) {
+	    errms(tokenizer,"nominal value not declared in header");
+	  }
+	  m_ValueBuffer[numValues] = (double)valIndex;
+	} else if (attribute(m_IndicesBuffer[numValues]).isNumeric()) {
+	  
+	  // Check if value is really a number.
+	  try{
+	    m_ValueBuffer[numValues] = Double.valueOf(tokenizer.sval).
+	      doubleValue();
+	  } catch (NumberFormatException e) {
+	    errms(tokenizer,"number expected");
+	  }
+	} else { 
+	  m_ValueBuffer[numValues] = 
+	    attribute(m_IndicesBuffer[numValues]).addStringValue(tokenizer.sval);
+	}
+      }
+      numValues++;
+    } while (true);
+    if (flag) {
+      getLastToken(tokenizer,true);
+    }
+      
+    // Add instance to dataset
+    double[] tempValues = new double[numValues];
+    int[] tempIndices = new int[numValues];
+    System.arraycopy(m_ValueBuffer, 0, tempValues, 0, numValues);
+    System.arraycopy(m_IndicesBuffer, 0, tempIndices, 0, numValues);
+    add(new SparseInstance(1, tempValues, tempIndices, numAttributes()));
+    return true;
+  }
+
+  /**
+   * Reads a single instance using the tokenizer and appends it
+   * to the dataset. Automatically expands the dataset if it
+   * is not large enough to hold the instance.
+   *
+   * @param tokenizer the tokenizer to be used
+   * @param flag if method should test for carriage return after 
+   * each instance
+   * @return false if end of file has been reached
+   * @exception IOException if the information is not read 
+   * successfully
+   */ 
+  protected boolean getInstanceFull(StreamTokenizer tokenizer, 
+				    boolean flag) 
+       throws IOException {
+
+    double[] instance = new double[numAttributes()];
+    int index;
+    
+    // Get values for all attributes.
+    for (int i = 0; i < numAttributes(); i++){
+      
+      // Get next token
+      if (i > 0) {
+	getNextToken(tokenizer);
+      }
+            
+      // Check if value is missing.
+      if  (tokenizer.ttype == '?') {
+	instance[i] = Instance.missingValue();
+      } else {
+
+	// Check if token is valid.
+	if (tokenizer.ttype != StreamTokenizer.TT_WORD) {
+	  errms(tokenizer,"not a valid value");
+	}
+	if (attribute(i).isNominal()) {
+	  
+	  // Check if value appears in header.
+	  index = attribute(i).indexOfValue(tokenizer.sval);
+	  if (index == -1) {
+	    errms(tokenizer,"nominal value not declared in header");
+	  }
+	  instance[i] = (double)index;
+	} else if (attribute(i).isNumeric()) {
+	  
+	  // Check if value is really a number.
+	  try{
+	    instance[i] = Double.valueOf(tokenizer.sval).
+	      doubleValue();
+	  } catch (NumberFormatException e) {
+	    errms(tokenizer,"number expected");
+	  }
+	} else { 
+	  instance[i] = attribute(i).addStringValue(tokenizer.sval);
+	}
+      }
+    }
+    if (flag) {
+      getLastToken(tokenizer,true);
+    }
+      
+    // Add instance to dataset
+    add(new Instance(1, instance));
+    return true;
+  }
+
+  /**
+   * Reads and stores header of an ARFF file.
+   *
+   * @param tokenizer the stream tokenizer
+   * @exception IOException if the information is not read 
+   * successfully
+   */ 
+  protected void readHeader(StreamTokenizer tokenizer) 
+     throws IOException{
+    
+    String attributeName;
+    FastVector attributeValues;
+    int i;
+
+    // Get name of relation.
+    getFirstToken(tokenizer);
+    if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
+      errms(tokenizer,"premature end of file");
+    }
+    if (tokenizer.sval.equalsIgnoreCase("@relation")){
+      getNextToken(tokenizer);
+      m_RelationName = tokenizer.sval;
+      getLastToken(tokenizer,false);
+    } else {
+      errms(tokenizer,"keyword @relation expected");
+    }
+
+    // Create vectors to hold information temporarily.
+    m_Attributes = new FastVector();
+ 
+    // Get attribute declarations.
+    getFirstToken(tokenizer);
+    if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
+      errms(tokenizer,"premature end of file");
+    }
+    while (tokenizer.sval.equalsIgnoreCase("@attribute")) {
+
+      // Get attribute name.
+      getNextToken(tokenizer);
+      attributeName = tokenizer.sval;
+      getNextToken(tokenizer);
+
+      // Check if attribute is nominal.
+      if (tokenizer.ttype == StreamTokenizer.TT_WORD) {
+
+	// Attribute is real, integer, or string.
+	if (tokenizer.sval.equalsIgnoreCase("real") ||
+	    tokenizer.sval.equalsIgnoreCase("integer") ||
+	    tokenizer.sval.equalsIgnoreCase("numeric")) {
+	  m_Attributes.addElement(new Attribute(attributeName,
+						 numAttributes()));
+	  readTillEOL(tokenizer);
+	} else if (tokenizer.sval.equalsIgnoreCase("string")) {
+	  m_Attributes.
+	    addElement(new Attribute(attributeName, null,
+				     numAttributes()));
+	  readTillEOL(tokenizer);
+	} else {
+	  errms(tokenizer,"no valid attribute type or invalid "+
+		"enumeration");
+	}
+      } else {
+
+	// Attribute is nominal.
+	attributeValues = new FastVector();
+	tokenizer.pushBack();
+	
+	// Get values for nominal attribute.
+	if (tokenizer.nextToken() != '{') {
+	  errms(tokenizer,"{ expected at beginning of enumeration");
+	}
+	while (tokenizer.nextToken() != '}') {
+	  if (tokenizer.ttype == StreamTokenizer.TT_EOL) {
+	    errms(tokenizer,"} expected at end of enumeration");
+	  } else {
+	    attributeValues.addElement(tokenizer.sval);
+	  }
+	}
+	if (attributeValues.size() == 0) {
+	  errms(tokenizer,"no nominal values found");
+	}
+	m_Attributes.
+	  addElement(new Attribute(attributeName, attributeValues,
+				   numAttributes()));
+      }
+      getLastToken(tokenizer,false);
+      getFirstToken(tokenizer);
+      if (tokenizer.ttype == StreamTokenizer.TT_EOF)
+	errms(tokenizer,"premature end of file");
+    }
+
+    // Check if data part follows. We can't easily check for EOL.
+    if (!tokenizer.sval.equalsIgnoreCase("@data")) {
+      errms(tokenizer,"keyword @data expected");
+    }
+    
+    // Check if any attributes have been declared.
+    if (m_Attributes.size() == 0) {
+      errms(tokenizer,"no attributes declared");
+    }
+
+    // Allocate buffers in case sparse instances have to be read
+    m_ValueBuffer = new double[numAttributes()];
+    m_IndicesBuffer = new int[numAttributes()];
+  }
+
+  /**
+   * Copies instances from one set to the end of another 
+   * one.
+   *
+   * @param source the source of the instances
+   * @param from the position of the first instance to be copied
+   * @param dest the destination for the instances
+   * @param num the number of instances to be copied
+   */
+  private void copyInstances(int from, Instances dest, int num) {
+    
+    for (int i = 0; i < num; i++) {
+      dest.add(instance(from + i));
+    }
+  }
+  
+  /**
+   * Throws error message with line number and last token read.
+   *
+   * @param theMsg the error message to be thrown
+   * @param tokenizer the stream tokenizer
+   * @throws IOExcpetion containing the error message
+   */
+  private void errms(StreamTokenizer tokenizer, String theMsg) 
+       throws IOException {
+    
+    throw new IOException(theMsg + ", read " + tokenizer.toString());
+  }
+  
+  /**
+   * Replaces the attribute information by a clone of
+   * itself.
+   */
+  private void freshAttributeInfo() {
+
+    m_Attributes = (FastVector) m_Attributes.copyElements();
+  }
+
+  /**
+   * Gets next token, skipping empty lines.
+   *
+   * @param tokenizer the stream tokenizer
+   * @exception IOException if reading the next token fails
+   */
+  private void getFirstToken(StreamTokenizer tokenizer) 
+    throws IOException{
+    
+    while (tokenizer.nextToken() == StreamTokenizer.TT_EOL){};
+    if ((tokenizer.ttype == '\'') ||
+	(tokenizer.ttype == '"')) {
+      tokenizer.ttype = StreamTokenizer.TT_WORD;
+    } else if ((tokenizer.ttype == StreamTokenizer.TT_WORD) &&
+	       (tokenizer.sval.equals("?"))){
+      tokenizer.ttype = '?';
+    }
+  }
+
+  /**
+   * Gets index, checking for a premature and of line.
+   *
+   * @param tokenizer the stream tokenizer
+   * @exception IOException if it finds a premature end of line
+   */
+  private void getIndex(StreamTokenizer tokenizer) throws IOException{
+    
+    if (tokenizer.nextToken() == StreamTokenizer.TT_EOL) {
+      errms(tokenizer,"premature end of line");
+    }
+    if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
+      errms(tokenizer,"premature end of file");
+    }
+  }
+  
+  /**
+   * Gets token and checks if its end of line.
+   *
+   * @param tokenizer the stream tokenizer
+   * @exception IOException if it doesn't find an end of line
+   */
+  private void getLastToken(StreamTokenizer tokenizer, boolean endOfFileOk) 
+       throws IOException{
+
+    if ((tokenizer.nextToken() != StreamTokenizer.TT_EOL) &&
+	((tokenizer.nextToken() != StreamTokenizer.TT_EOF) || !endOfFileOk)) {
+      errms(tokenizer,"end of line expected");
+    }
+  }
+
+  /**
+   * Gets next token, checking for a premature and of line.
+   *
+   * @param tokenizer the stream tokenizer
+   * @exception IOException if it finds a premature end of line
+   */
+  private void getNextToken(StreamTokenizer tokenizer) 
+       throws IOException{
+    
+    if (tokenizer.nextToken() == StreamTokenizer.TT_EOL) {
+      errms(tokenizer,"premature end of line");
+    }
+    if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
+      errms(tokenizer,"premature end of file");
+    } else if ((tokenizer.ttype == '\'') ||
+	       (tokenizer.ttype == '"')) {
+      tokenizer.ttype = StreamTokenizer.TT_WORD;
+    } else if ((tokenizer.ttype == StreamTokenizer.TT_WORD) &&
+	       (tokenizer.sval.equals("?"))){
+      tokenizer.ttype = '?';
+    }
+  }
+	
+  /**
+   * Initializes the StreamTokenizer used for reading the ARFF file.
+   *
+   * @param tokenizer the stream tokenizer
+   */
+  private void initTokenizer(StreamTokenizer tokenizer){
+
+    tokenizer.resetSyntax();         
+    tokenizer.whitespaceChars(0, ' ');    
+    tokenizer.wordChars(' '+1,'\u00FF');
+    tokenizer.whitespaceChars(',',',');
+    tokenizer.commentChar('%');
+    tokenizer.quoteChar('"');
+    tokenizer.quoteChar('\'');
+    tokenizer.ordinaryChar('{');
+    tokenizer.ordinaryChar('}');
+    tokenizer.eolIsSignificant(true);
+  }
+ 
+  /**
+   * Returns string including all instances, their weights and
+   * their indices in the original dataset.
+   *
+   * @return description of instance and its weight as a string
+   */
+  private String instancesAndWeights(){
+
+    StringBuffer text = new StringBuffer();
+
+    for (int i = 0; i < numInstances(); i++) {
+      text.append(instance(i) + " " + instance(i).weight());
+      if (i < numInstances() - 1) {
+	text.append("\n");
+      }
+    }
+    return text.toString();
+  }
+  
+  /**
+   * Implements quicksort.
+   *
+   * @param attIndex the attribute's index
+   * @param lo0 the first index of the subset to be sorted
+   * @param hi0 the last index of the subset to be sorted
+   */
+  private void quickSort(int attIndex, int lo0, int hi0) {
+    
+    int lo = lo0, hi = hi0;
+    double mid, midPlus, midMinus;
+    
+    if (hi0 > lo0) {
+      
+      // Arbitrarily establishing partition element as the 
+      // midpoint of the array.
+      mid = instance((lo0 + hi0) / 2).value(attIndex);
+      midPlus = mid + 1e-6;
+      midMinus = mid - 1e-6;
+
+      // loop through the array until indices cross
+      while(lo <= hi) {
+	
+	// find the first element that is greater than or equal to 
+	// the partition element starting from the left Index.
+	while ((instance(lo).value(attIndex) < 
+		midMinus) && (lo < hi0)) {
+	  ++lo;
+	}
+	
+	// find an element that is smaller than or equal to
+	// the partition element starting from the right Index.
+	while ((instance(hi).value(attIndex)  > 
+		midPlus) && (hi > lo0)) {
+	  --hi;
+	}
+	
+	// if the indexes have not crossed, swap
+	if(lo <= hi) {
+	  swap(lo,hi);
+	  ++lo;
+	  --hi;
+	}
+      }
+      
+      // If the right index has not reached the left side of array
+      // must now sort the left partition.
+      if(lo0 < hi) {
+	quickSort(attIndex,lo0,hi);
+      }
+      
+      // If the left index has not reached the right side of array
+      // must now sort the right partition.
+      if(lo < hi0) {
+	quickSort(attIndex,lo,hi0);
+      }
+    }
+  }
+
+  /**
+   * Reads and skips all tokens before next end of line token.
+   *
+   * @param tokenizer the stream tokenizer
+   */
+  private void readTillEOL(StreamTokenizer tokenizer) 
+       throws IOException{
+    
+    while (tokenizer.nextToken() != StreamTokenizer.TT_EOL) {};
+    tokenizer.pushBack();
+  }
+
+  /**
+   * Help function needed for stratification of set.
+   *
+   * @param numFolds the number of folds for the stratification
+   */
+  private void stratStep (int numFolds){
+    
+    FastVector newVec = new FastVector(m_Instances.capacity());
+    int start = 0, j;
+
+    // create stratified batch
+    while (newVec.size() < numInstances()) {
+      j = start;
+      while (j < numInstances()) {
+	newVec.addElement(instance(j));
+	j = j + numFolds;
+      }
+      start++;
+    }
+    m_Instances = newVec;
+  }
+  
+  /**
+   * Swaps two instances in the set.
+   *
+   * @param i the first instance's index
+   * @param j the second instance's index
+   */
+  private void swap(int i, int j){
+    
+    m_Instances.swap(i, j);
+  }
+
+  /**
+   * Merges two sets of Instances together. The resulting set will have
+   * all the attributes of the first set plus all the attributes of the 
+   * second set. The number of instances in both sets must be the same.
+   *
+   * @param first the first set of Instances
+   * @param second the second set of Instances
+   * @return the merged set of Instances
+   * @exception IllegalArgumentException if the datasets are not the same size
+   */
+  public static Instances mergeInstances(Instances first, Instances second) {
+
+    if (first.numInstances() != second.numInstances()) {
+      throw new IllegalArgumentException("Instance sets must be of the same size");
+    }
+
+    // Create the vector of merged attributes
+    FastVector newAttributes = new FastVector();
+    for (int i = 0; i < first.numAttributes(); i++) {
+      newAttributes.addElement(first.attribute(i));
+    }
+    for (int i = 0; i < second.numAttributes(); i++) {
+      newAttributes.addElement(second.attribute(i));
+    }
+    
+    // Create the set of Instances
+    Instances merged = new Instances(first.relationName() + '_'
+				     + second.relationName(), 
+				     newAttributes, 
+				     first.numInstances());
+    // Merge each instance
+    for (int i = 0; i < first.numInstances(); i++) {
+      merged.add(first.instance(i).mergeInstance(second.instance(i)));
+    }
+    return merged;
+  }
+
+  /**
+   * Method for testing this class.
+   *
+   * @param argv should contain one element: the name of an ARFF file
+   */
+  public static void test(String [] argv) {
+
+    Instances instances, secondInstances, train, test, transformed, empty;
+    Instance instance;
+    Random random = new Random(2);
+    Reader reader;
+    int start, num;
+    double newWeight;
+    FastVector testAtts, testVals;
+    int i,j;
+    
+    try{
+      if (argv.length > 1) {
+	throw (new Exception("Usage: Instances [<filename>]"));
+      }
+      
+      // Creating set of instances from scratch
+      testVals = new FastVector(2);
+      testVals.addElement("first_value");
+      testVals.addElement("second_value");
+      testAtts = new FastVector(2);
+      testAtts.addElement(new Attribute("nominal_attribute", testVals));
+      testAtts.addElement(new Attribute("numeric_attribute"));
+      instances = new Instances("test_set", testAtts, 10);
+      instances.add(new Instance(instances.numAttributes()));
+      instances.add(new Instance(instances.numAttributes()));
+      instances.add(new Instance(instances.numAttributes()));
+      instances.setClassIndex(0);
+      System.out.println("\nSet of instances created from scratch:\n");
+      System.out.println(instances);
+      
+      if (argv.length == 1) {
+	String filename = argv[0];
+	reader = new FileReader(filename);
+	
+	// Read first five instances and print them
+	System.out.println("\nFirst five instances from file:\n");
+	instances = new Instances(reader, 1);
+	instances.setClassIndex(instances.numAttributes() - 1);
+	i = 0;
+	while ((i < 5) && (instances.readInstance(reader))) {
+	  i++;
+	}
+	System.out.println(instances);
+
+	// Read all the instances in the file
+	reader = new FileReader(filename);
+	instances = new Instances(reader);
+
+	// Make the last attribute be the class 
+	instances.setClassIndex(instances.numAttributes() - 1);
+	
+	// Print header and instances.
+	System.out.println("\nDataset:\n");
+	System.out.println(instances);
+	System.out.println("\nClass index: "+instances.classIndex());
+      }
+      
+      // Test basic methods based on class index.
+      System.out.println("\nClass name: "+instances.classAttribute().name());
+      System.out.println("\nClass index: "+instances.classIndex());
+      System.out.println("\nClass is nominal: " +
+			 instances.classAttribute().isNominal());
+      System.out.println("\nClass is numeric: " +
+			 instances.classAttribute().isNumeric());
+      System.out.println("\nClasses:\n");
+      for (i = 0; i < instances.numClasses(); i++) {
+	System.out.println(instances.classAttribute().value(i));
+      }
+      System.out.println("\nClass values and labels of instances:\n");
+      for (i = 0; i < instances.numInstances(); i++) {
+	Instance inst = instances.instance(i);
+	System.out.print(inst.classValue() + "\t");
+	System.out.print(inst.toString(inst.classIndex()));
+	if (instances.instance(i).classIsMissing()) {
+	  System.out.println("\tis missing");
+	} else {
+	  System.out.println();
+	}
+      }
+      
+      // Create random weights.
+      System.out.println("\nCreating random weights for instances.");
+      for (i = 0; i < instances.numInstances(); i++) {
+	instances.instance(i).setWeight(random.nextDouble()); 
+      }
+      
+      // Print all instances and their weights (and the sum of weights).
+      System.out.println("\nInstances and their weights:\n");
+      System.out.println(instances.instancesAndWeights());
+      System.out.print("\nSum of weights: ");
+      System.out.println(instances.sumOfWeights());
+      
+      // Insert an attribute
+      secondInstances = new Instances(instances);
+      Attribute testAtt = new Attribute("Inserted");
+      secondInstances.insertAttributeAt(testAtt, 0);
+      System.out.println("\nSet with inserted attribute:\n");
+      System.out.println(secondInstances);
+      System.out.println("\nClass name: "
+			 + secondInstances.classAttribute().name());
+      
+      // Delete the attribute
+      secondInstances.deleteAttributeAt(0);
+      System.out.println("\nSet with attribute deleted:\n");
+      System.out.println(secondInstances);
+      System.out.println("\nClass name: "
+			 + secondInstances.classAttribute().name());
+      
+      // Test if headers are equal
+      System.out.println("\nHeaders equal: "+
+			 instances.equalHeaders(secondInstances) + "\n");
+      
+      // Print data in internal format.
+      System.out.println("\nData (internal values):\n");
+      for (i = 0; i < instances.numInstances(); i++) {
+	for (j = 0; j < instances.numAttributes(); j++) {
+	  if (instances.instance(i).isMissing(j)) {
+	    System.out.print("? ");
+	  } else {
+	    System.out.print(instances.instance(i).value(j) + " ");
+	  }
+	}
+	System.out.println();
+      }
+      
+      // Just print header
+      System.out.println("\nEmpty dataset:\n");
+      empty = new Instances(instances, 0);
+      System.out.println(empty);
+      System.out.println("\nClass name: "+empty.classAttribute().name());
+
+      // Create copy and rename an attribute and a value (if possible)
+      if (empty.classAttribute().isNominal()) {
+	Instances copy = new Instances(empty, 0);
+	copy.renameAttribute(copy.classAttribute(), "new_name");
+	copy.renameAttributeValue(copy.classAttribute(), 
+				  copy.classAttribute().value(0), 
+				  "new_val_name");
+	System.out.println("\nDataset with names changed:\n" + copy);
+	System.out.println("\nOriginal dataset:\n" + empty);
+      }
+
+      // Create and prints subset of instances.
+      start = instances.numInstances() / 4;
+      num = instances.numInstances() / 2;
+      System.out.print("\nSubset of dataset: ");
+      System.out.println(num + " instances from " + (start + 1) 
+			 + ". instance");
+      secondInstances = new Instances(instances, start, num);
+      System.out.println("\nClass name: "
+			 + secondInstances.classAttribute().name());
+
+      // Print all instances and their weights (and the sum of weights).
+      System.out.println("\nInstances and their weights:\n");
+      System.out.println(secondInstances.instancesAndWeights());
+      System.out.print("\nSum of weights: ");
+      System.out.println(secondInstances.sumOfWeights());
+      
+      // Create and print training and test sets for 3-fold
+      // cross-validation.
+      System.out.println("\nTrain and test folds for 3-fold CV:");
+      if (instances.classAttribute().isNominal()) {
+	instances.stratify(3);
+      }
+      for (j = 0; j < 3; j++) {
+        train = instances.trainCV(3,j);
+	test = instances.testCV(3,j);
+                      
+	// Print all instances and their weights (and the sum of weights).
+	System.out.println("\nTrain: ");
+	System.out.println("\nInstances and their weights:\n");
+	System.out.println(train.instancesAndWeights());
+	System.out.print("\nSum of weights: ");
+	System.out.println(train.sumOfWeights());
+	System.out.println("\nClass name: "+train.classAttribute().name());
+	System.out.println("\nTest: ");
+	System.out.println("\nInstances and their weights:\n");
+	System.out.println(test.instancesAndWeights());
+	System.out.print("\nSum of weights: ");
+	System.out.println(test.sumOfWeights());
+	System.out.println("\nClass name: "+test.classAttribute().name());
+      }
+
+      // Randomize instances and print them.
+      System.out.println("\nRandomized dataset:");
+      instances.randomize(random);
+      
+      // Print all instances and their weights (and the sum of weights).
+      System.out.println("\nInstances and their weights:\n");
+      System.out.println(instances.instancesAndWeights());
+      System.out.print("\nSum of weights: ");
+      System.out.println(instances.sumOfWeights());
+
+      // Sort instances according to first attribute and
+      // print them.
+      System.out.print("\nInstances sorted according to first attribute:\n ");
+      instances.sort(0);
+        
+      // Print all instances and their weights (and the sum of weights).
+      System.out.println("\nInstances and their weights:\n");
+      System.out.println(instances.instancesAndWeights());
+      System.out.print("\nSum of weights: ");
+      System.out.println(instances.sumOfWeights());
+    } catch (Exception e) {
+      e.printStackTrace(); 
+    }
+  }
+
+  /**
+   * Main method for this class -- just prints a summary of a set
+   * of instances.
+   *
+   * @param argv should contain one element: the name of an ARFF file
+   */
+  public static void main(String [] args) {
+
+    try {
+      Reader r = null;
+      if (args.length > 1) {
+	throw (new Exception("Usage: Instances <filename>"));
+      } else if (args.length == 0) {
+        r = new BufferedReader(new InputStreamReader(System.in));
+      } else {
+        r = new BufferedReader(new FileReader(args[0]));
+      }
+      Instances i = new Instances(r);
+      System.out.println(i.toSummaryString());
+    } catch (Exception ex) {
+      System.err.println(ex.getMessage());
+    }
+  }
+}
+
+     
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Option.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Option.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Option.java	(revision 10506)
@@ -0,0 +1,105 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Option.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+/** 
+ * Class to store information about an option. <p>
+ *
+ * Typical usage: <p>
+ *
+ * <code>Option myOption = new Option("Uses extended mode.", "E", 0, "-E")); </code><p>
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public class Option {
+
+  /** What does this option do? */
+  private String m_Description;
+
+  /** The synopsis. */
+  private String m_Synopsis;
+
+  /** What's the option's name? */
+  private String m_Name;
+
+  /** How many arguments does it take? */
+  private int m_NumArguments;
+
+  /**
+   * Creates new option with the given parameters.
+   *
+   * @String description the option's description
+   * @String name the option's name
+   * @String numArguments the number of arguments
+   */
+  public Option(String description, String name, 
+		int numArguments, String synopsis) {
+  
+    m_Description = description;
+    m_Name = name;
+    m_NumArguments = numArguments;
+    m_Synopsis = synopsis;
+  }
+
+  /**
+   * Returns the option's description.
+   *
+   * @return the option's description
+   */
+  public String description() {
+  
+    return m_Description;
+  }
+
+  /**
+   * Returns the option's name.
+   *
+   * @return the option's name
+   */
+  public String name() {
+
+    return m_Name;
+  }
+
+  /**
+   * Returns the option's number of arguments.
+   *
+   * @return the option's number of arguments
+   */
+  public int numArguments() {
+  
+    return m_NumArguments;
+  }
+
+  /**
+   * Returns the option's synopsis.
+   *
+   * @return the option's synopsis
+   */
+  public String synopsis() {
+  
+    return m_Synopsis;
+  }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/OptionHandler.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/OptionHandler.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/OptionHandler.java	(revision 10506)
@@ -0,0 +1,67 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    OptionHandler.java
+ *    Copyright (C) 1999 Eibe Frank,Len Trigg
+ *
+ */
+
+package weka.core;
+
+import java.util.*;
+
+/** 
+ * Interface to something that understands options.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @author Len Trigg (trigg@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public interface OptionHandler {
+
+  /**
+   * Returns an enumeration of all the available options.
+   *
+   * @return an enumeration of all available options
+   */
+  public Enumeration listOptions();
+
+  /**
+   * Sets the OptionHandler's options using the given list. All options
+   * will be set (or reset) during this call (i.e. incremental setting
+   * of options is not possible).
+   *
+   * @param options the list of options as an array of strings
+   * @exception Exception if an option is not supported
+   */
+  public void setOptions(String[] options) throws Exception;
+
+  /**
+   * Gets the current option settings for the OptionHandler.
+   *
+   * @return the list of current option settings as an array of strings
+   */
+  public String[] getOptions();
+}
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Queue.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Queue.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Queue.java	(revision 10506)
@@ -0,0 +1,229 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Queue.java
+ *    Copyright (C) 1999 Len Trigg
+ *
+ */
+
+package weka.core;
+
+import java.io.*;
+
+/** 
+ * Class representing a FIFO queue.
+ *
+ * @author Len Trigg (trigg@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public class Queue extends Object implements Serializable {
+
+  /**
+   * Represents one node in the queue.
+   */
+  protected class QueueNode implements Serializable {
+
+    /** The next node in the queue */
+    protected QueueNode m_Next;
+
+    /** The nodes contents */
+    protected Object m_Contents;
+
+    /** 
+     * Creates a queue node with the given contents 
+     */
+    public QueueNode(Object contents) {
+
+      m_Contents = contents;
+      next(null);
+    }
+
+    /**
+     * Sets the next node in the queue, and returns it.
+     */
+    public QueueNode next(QueueNode next) {
+
+      return m_Next = next;
+    }
+
+    /**
+     * Gets the next node in the queue. 
+     */
+    public QueueNode next() {
+
+      return m_Next;
+    }
+
+    /**
+     * Sets the contents of the node.
+     */
+    public Object contents(Object contents) {
+
+      return m_Contents = contents;
+    }
+
+    /**
+     * Returns the contents in the node.
+     */
+    public Object contents() {
+
+      return m_Contents;
+    }
+  }
+
+  /** Store a reference to the head of the queue */
+  protected QueueNode m_Head = null;
+
+  /** Store a reference to the tail of the queue */
+  protected QueueNode m_Tail = null;
+
+  /** Store the current number of elements in the queue */
+  protected int m_Size = 0;
+
+  /**
+   * Removes all objects from the queue.
+   */
+  public final synchronized void removeAllElements() {
+
+    m_Size = 0;
+    m_Head = null;
+    m_Tail = null;
+  }
+
+  /**
+   * Appends an object to the back of the queue.
+   *
+   * @param item the object to be appended
+   * @return the object appended
+   */
+  public synchronized Object push(Object item) {
+
+    QueueNode newNode = new QueueNode(item);
+    if (m_Head == null) {
+      m_Head = m_Tail = newNode;
+    } else {
+      m_Tail = m_Tail.next(newNode);
+    }
+    m_Size++;
+    return item;
+  }
+
+  /**
+   * Pops an object from the front of the queue.
+   *
+   * @return the object at the front of the queue
+   * @exception RuntimeException if the queue is empty
+   */
+  public synchronized Object pop() {
+
+    if (m_Head == null) {
+      throw new RuntimeException("Queue is empty");
+    }
+    Object retval = m_Head.contents();
+    m_Size--;
+    m_Head = m_Head.next();
+    if (m_Head == null) {
+      m_Tail = null;
+    }
+    return retval;
+  }
+
+  /**
+   * Gets object from the front of the queue.
+   *
+   * @return the object at the front of the queue
+   * @exception RuntimeException if the queue is empty
+   */
+  public synchronized Object peek() {
+    
+    if (m_Head == null) {
+      throw new RuntimeException("Queue is empty");
+    }
+    return m_Head.contents();
+  }
+
+  /**
+   * Checks if queue is empty.
+   * 
+   * @return true if queue is empty
+   */
+  public boolean empty() {
+
+    return (m_Head == null);
+  }
+
+  /** 
+   * Gets queue's size.
+   *
+   * @return size of queue
+   */
+  public int size() {
+
+    return m_Size;
+  }
+
+  /**
+   * Produces textual description of queue.
+   *
+   * @return textual description of queue
+   */
+  public String toString() {
+
+    String retval = "Queue Contents "+m_Size+" elements\n";
+    QueueNode current = m_Head;
+    if (current == null) {
+      return retval + "Empty\n";
+    } else {
+      while (current != null) {
+	retval += current.contents().toString()+"\n";
+	current = current.next();
+      }
+    }
+    return retval;
+  }
+
+  /**
+   * Main method for testing this class.
+   *
+   * @param argv a set of strings that are pushed on a test queue
+   */
+  public static void main(String [] argv) {
+
+    try {
+      Queue queue = new Queue();
+      for(int i = 0; i < argv.length; i++) {
+	queue.push(argv[i]);
+      }
+      System.out.println("After Pushing");
+      System.out.println(queue.toString());
+      System.out.println("Popping...");
+      while (!queue.empty()) {
+	System.out.println(queue.pop().toString());
+      }
+    } catch (Exception ex) {
+      System.out.println(ex.getMessage());
+    }
+  }
+}
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Range.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Range.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Range.java	(revision 10506)
@@ -0,0 +1,439 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Range.java
+ *    Copyright (C) 1999 Len Trigg
+ *
+ */
+
+package weka.core;
+
+import java.io.*;
+import java.util.*;
+
+/** 
+ * Class representing a range of cardinal numbers. The range is set by a 
+ * string representation such as: <P>
+ *
+ * <code>
+ *   all
+ *   first-last
+ *   1,2,3,4
+ * </code> <P>
+ * or combinations thereof. The range is internally converted from
+ * 1-based to 0-based (so methods that set or get numbers not in string
+ * format should use 0-based numbers).
+ *
+ * @author Len Trigg (trigg@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public class Range implements Serializable {
+
+  /** Record the string representations of the columns to delete */
+  Vector m_RangeStrings = new Vector();
+
+  /** Whether matching should be inverted */
+  boolean m_Invert;
+
+  /** The array of flags for whether an column is selected */
+  boolean [] m_SelectFlags;
+
+  /** Store the maximum value permitted in the range. -1 indicates that
+      no upper value has been set */
+  int m_Upper = -1;
+
+  /** Default constructor. */
+  public Range() {
+  }
+
+  /**
+   * Constructor to set initial range.
+   *
+   * @param rangeList the initial range
+   * @exception IllegalArgumentException if the range list is invalid
+   */
+  public Range(String rangeList) {
+
+    setRanges(rangeList);
+  }
+
+  /**
+   * Sets the value of "last".
+   *
+   * @param newUpper the value of "last"
+   */
+  public void setUpper(int newUpper) {
+
+    if (newUpper >= 0) {
+      m_Upper = newUpper;
+      setFlags();
+    }
+  }
+  
+  /**
+   * Gets whether the range sense is inverted, i.e. all <i>except</i>
+   * the values included by the range string are selected.
+   * 
+   * @return whether the matching sense is inverted
+   */
+  public boolean getInvert() {
+
+    return m_Invert;
+  }
+
+  /**
+   * Sets whether the range sense is inverted, i.e. all <i>except</i>
+   * the values included by the range string are selected.
+   * 
+   * @param newSetting true if the matching sense is inverted
+   */
+  public void setInvert(boolean newSetting) {
+
+    m_Invert = newSetting;
+  }
+
+  /**
+   * Gets the string representing the selected range of values
+   *
+   * @return the range selection string
+   */
+  public String getRanges() {
+
+    String result = null;
+    Enumeration enum = m_RangeStrings.elements();
+    while (enum.hasMoreElements()) {
+      if (result == null) {
+	result = (String)enum.nextElement();
+      } else {
+	result += ',' + (String)enum.nextElement();
+      }
+    }
+    return (result == null) ? "" : result;
+  }
+
+  /**
+   * Sets the ranges from a string representation.
+   *
+   * @param rangeList the comma separated list of ranges. The empty
+   * string sets the range to empty.
+   * @exception IllegalArgumentException if the rangeList was not well formed
+   */
+  public void setRanges(String rangeList) {
+
+    Vector ranges = new Vector (10);
+
+    // Split the rangeList up into the vector
+    while (!rangeList.equals("")) {
+      String range = rangeList.trim();
+      int commaLoc = rangeList.indexOf(',');
+      if (commaLoc != -1) {
+	range = rangeList.substring(0, commaLoc).trim();
+	rangeList = rangeList.substring(commaLoc + 1).trim();
+      } else {
+	rangeList = "";
+      }
+      if (!range.equals("")) {
+	if (isValidRange(range)) {
+	  ranges.addElement(range);
+	} else {
+	  throw new IllegalArgumentException("Invalid range list at " + range
+                                             + rangeList);
+	}
+      }
+    }
+    m_RangeStrings = ranges;
+    
+    if (m_Upper >= 0) {
+      setFlags();
+    }
+  }
+
+  /**
+   * Gets whether the supplied cardinal number is included in the current
+   * range.
+   *
+   * @param index the number of interest
+   * @return true if index is in the current range
+   * @exception RuntimeException if the upper limit of the range hasn't been defined
+   */
+  public boolean isInRange(int index) {
+
+    if (m_Upper == -1) {
+      throw new RuntimeException("No upper limit has been specified for range");
+    }
+    if (m_Invert) {
+      return !m_SelectFlags[index];
+    } else {
+      return m_SelectFlags[index];
+    }
+  }
+
+  /**
+   * Constructs a representation of the current range. Being a string
+   * representation, the numbers are based from 1.
+   * 
+   * @return the string representation of the current range
+   */
+  public String toString() {
+
+    if (m_RangeStrings.size() == 0) {
+      return "Empty";
+    }
+    String result ="Strings: ";
+    Enumeration enum = m_RangeStrings.elements();
+    while (enum.hasMoreElements()) {
+      result += (String)enum.nextElement() + " ";
+    }
+    result += "\n";
+
+    result += "Invert: " + m_Invert + "\n";
+
+    try {
+      if (m_Upper == -1) {
+	throw new RuntimeException("Upper limit has not been specified");
+      }
+      String cols = null;
+      for (int i = 0; i < m_SelectFlags.length; i++) {
+	if (isInRange(i)) {
+	  if (cols == null) {
+	    cols = "Cols: " + (i + 1);
+	  } else {
+	    cols += "," + (i + 1);
+	  }
+	}
+      }
+      if (cols != null) {
+	result += cols + "\n";
+      }
+    } catch (Exception ex) {
+      result += ex.getMessage();
+    }
+    return result;
+  }
+
+  /**
+   * Gets an array containing all the selected values, in the order
+   * that they were selected (or ascending order if range inversion is on)
+   *
+   * @return the array of selected values
+   * @exception RuntimeException if the upper limit of the range hasn't been defined
+   */
+  public int [] getSelection() {
+
+    if (m_Upper == -1) {
+      throw new RuntimeException("No upper limit has been specified for range");
+    }
+    int [] selectIndices = new int [m_Upper + 1];
+    int numSelected = 0;
+    if (m_Invert)
+    {
+      for (int i = 0; i <= m_Upper; i++) {
+	if (!m_SelectFlags[i]) {
+	  selectIndices[numSelected++] = i;
+	}
+      }
+    }
+    else
+    {
+      Enumeration enum = m_RangeStrings.elements();
+      while (enum.hasMoreElements()) {
+	String currentRange = (String)enum.nextElement();
+	int start = rangeLower(currentRange);
+	int end = rangeUpper(currentRange);
+	for (int i = start; (i <= m_Upper) && (i <= end); i++) {
+	  if (m_SelectFlags[i]) {
+	    selectIndices[numSelected++] = i;
+	  }
+	}
+      }
+    }
+    int [] result = new int [numSelected];
+    System.arraycopy(selectIndices, 0, result, 0, numSelected);
+    return result;
+  }
+
+  /**
+   * Creates a string representation of the indices in the supplied array.
+   *
+   * @param indices an array containing indices to select.
+   * Since the array will typically come from a program, indices are assumed
+   * from 0, and thus will have 1 added in the String representation.
+   */
+  public static String indicesToRangeList(int []indices) {
+
+    StringBuffer rl = new StringBuffer();
+    int last = -2;
+    boolean range = false;
+    for(int i = 0; i < indices.length; i++) {
+      if (i == 0) {
+	rl.append(indices[i] + 1);
+      } else if (indices[i] == last) {
+        range = true;
+      } else {
+        if (range) {
+          rl.append('-').append(last);
+          range = false;
+        }
+	rl.append(',').append(indices[i] + 1);
+      }
+      last = indices[i] + 1;
+    }
+    if (range) {
+      rl.append('-').append(last);
+    }
+    return rl.toString();
+  }
+
+  /** Sets the flags array. */
+  protected void setFlags() {
+
+    m_SelectFlags = new boolean [m_Upper + 1];
+    Enumeration enum = m_RangeStrings.elements();
+    while (enum.hasMoreElements()) {
+      String currentRange = (String)enum.nextElement();
+      int start = rangeLower(currentRange);
+      int end = rangeUpper(currentRange);
+      for (int i = start; (i <= m_Upper) && (i <= end); i++) {
+	m_SelectFlags[i] = true;
+      }
+    }
+  }
+
+
+  /**
+   * Translates a single string selection into it's internal 0-based equivalent
+   *
+   * @param single the string representing the selection (eg: 1 first last)
+   * @return the number corresponding to the selected value
+   */
+  protected int rangeSingle(String single) {
+
+    if (single.toLowerCase().equals("first")) {
+      return 0;
+    }
+    if (single.toLowerCase().equals("last")) {
+      return m_Upper;
+    }
+    int index = Integer.parseInt(single) - 1;
+    if (index < 0) {
+      index = 0;
+    }
+    if (index > m_Upper) {
+      index = m_Upper;
+    }
+    return index;
+  }
+
+  /**
+   * Translates a range into it's lower index.
+   *
+   * @param range the string representation of the range
+   * @return the lower index of the range
+   */
+  protected int rangeLower(String range) {
+
+    int hyphenIndex;
+    if ((hyphenIndex = range.indexOf('-')) >= 0) {
+      return Math.min(rangeLower(range.substring(0, hyphenIndex)),
+		       rangeLower(range.substring(hyphenIndex + 1)));
+    }
+    return rangeSingle(range);
+  }
+
+  /**
+   * Translates a range into it's upper index. Must only be called once
+   * setUpper has been called.
+   *
+   * @param range the string representation of the range
+   * @return the upper index of the range
+   */
+  protected int rangeUpper(String range) {
+
+    int hyphenIndex;
+    if ((hyphenIndex = range.indexOf('-')) >= 0) {
+      return Math.max(rangeUpper(range.substring(0, hyphenIndex)),
+		       rangeUpper(range.substring(hyphenIndex + 1)));
+    }
+    return rangeSingle(range);
+  }
+
+  /**
+   * Determines if a string represents a valid index or simple range.
+   * Examples: <code>first  last   2   first-last  first-4  4-last</code>
+   * Doesn't check that a < b for a-b
+   *
+   * @param range
+   * @return true if the range is valid
+   */
+  protected boolean isValidRange(String range) {
+
+    if (range == null) {
+      return false;
+    }
+    int hyphenIndex;
+    if ((hyphenIndex = range.indexOf('-')) >= 0) {
+      if (isValidRange(range.substring(0, hyphenIndex)) &&
+	  isValidRange(range.substring(hyphenIndex + 1))) {
+	return true;
+      }
+      return false;
+    }
+    if (range.toLowerCase().equals("first")) {
+      return true;
+    }
+    if (range.toLowerCase().equals("last")) {
+      return true;
+    }
+    try {
+      int index = Integer.parseInt(range);
+      if (index > 0) {
+	return true;
+      }
+      return false;
+    } catch (NumberFormatException ex) {
+      return false;
+    }
+  }
+
+  /**
+   * Main method for testing this class.
+   *
+   * @param argv one parameter: a test range specification
+   */
+  public static void main(String [] argv) {
+
+    try {
+      if (argv.length == 0) {
+	throw new Exception("Usage: Range <rangespec>");
+      }
+      Range range = new Range();
+      range.setRanges(argv[0]);
+      range.setUpper(9);
+      range.setInvert(false);
+      System.out.println("Input: " + argv[0] + "\n"
+			 + range.toString());
+      int [] rangeIndices = range.getSelection();
+      for (int i = 0; i < rangeIndices.length; i++)
+	System.out.print(" " + (rangeIndices[i] + 1));
+      System.out.println("");
+    } catch (Exception ex) {
+      System.out.println(ex.getMessage());
+    }
+  }
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/SerializedObject.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/SerializedObject.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/SerializedObject.java	(revision 10506)
@@ -0,0 +1,249 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    SerializedObject.java
+ *    Copyright (C) 2000 Webmind Inc.
+ *
+ */
+
+package weka.core;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * This class stores an object serialized in memory. It allows compression,
+ * to be used to conserve memory (for example, when storing large strings
+ * in memory), or can be used as a mechanism for deep copying objects.
+ *
+ * @author Len Trigg (len@intelligenesis.net)
+ * @version $Revision$
+ */
+public class SerializedObject implements Serializable {
+
+  /** Stores the serialized object */
+  private byte [] m_Serialized;
+
+  /** True if the object has been compressed during storage */
+  private boolean m_Compressed;
+
+  /**
+   * Serializes the supplied object into a byte array without compression.
+   *
+   * @param obj the Object to serialize.
+   * @exception Exception if the object is not Serializable.
+   */
+  public SerializedObject(Object obj) throws Exception {
+
+    this(obj, false);
+  }
+
+  /**
+   * Serializes the supplied object into a byte array.
+   *
+   * @param obj the Object to serialize.
+   * @param compress true if the object should be stored compressed.
+   * @exception Exception if the object is not Serializable.
+   */
+  public SerializedObject(Object obj, boolean compress) throws Exception {
+
+    //System.err.print("."); System.err.flush();
+    m_Compressed = compress;
+    m_Serialized = toByteArray(obj, m_Compressed);
+  }
+
+  /**
+   * Serializes the supplied object to a byte array.
+   *
+   * @param obj the Object to serialize
+   * @param compress true if the object should be compressed.
+   * @return the byte array containing the serialized object.
+   * @exception Exception if the object is not Serializable.
+   */
+  protected static byte [] toByteArray(Object obj, boolean compress) 
+    throws Exception {
+
+    ByteArrayOutputStream bo = new ByteArrayOutputStream();
+    OutputStream os = bo;
+    if (compress) {
+      os = new GZIPOutputStream(os);
+    }
+    os = new BufferedOutputStream(os);
+    ObjectOutputStream oo = new ObjectOutputStream(os);
+    oo.writeObject(obj);
+    oo.close();
+    return bo.toByteArray();
+  }
+
+  /**
+   * Gets the object stored in this SerializedObject. The object returned
+   * will be a deep copy of the original stored object.
+   *
+   * @return the deserialized Object.
+   */
+  public Object getObject() {
+    try {
+      InputStream is = new ByteArrayInputStream(m_Serialized);
+      if (m_Compressed) {
+        is = new GZIPInputStream(is);
+      }
+      is = new BufferedInputStream(is);
+      ObjectInputStream oi = new ObjectInputStream(is);
+      Object result = oi.readObject();
+      oi.close();
+      return result;
+    } catch (Exception ex) {
+      ex.printStackTrace();
+    }
+    return null;
+  }
+
+  /**
+   * Compares this object with another for equality.
+   *
+   * @param other the other Object.
+   * @return true if the objects are equal.
+   */
+  public final boolean equals(Object other) {
+
+    // Check class type
+    if ((other == null) || !(other.getClass().equals(this.getClass()))) {
+      return false;
+    }
+    // Check serialized length
+    byte [] os = ((SerializedObject)other).m_Serialized;
+    if (os.length != m_Serialized.length) {
+      return false;
+    }
+    // Check serialized contents
+    for (int i = 0; i < m_Serialized.length; i++) {
+      if (m_Serialized[i] != os[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Returns a hashcode for this object.
+   *
+   * @return the hashcode for this object.
+   */
+  public final int hashCode() {
+    
+    return m_Serialized.length;
+  }
+
+  /**
+   * Returns a text representation of the state of this object.
+   *
+   * @return a String representing this object.
+   */
+  public String toString() {
+    
+    return (m_Compressed ? "Compressed object: " : "Uncompressed object: ")
+      + m_Serialized.length + " bytes";
+  }
+
+  /**
+   * Test routine, reads text from stdin and measures memory usage
+   */
+  public static void main2(String []args) {
+
+    try {
+      Runtime r = Runtime.getRuntime();
+      r.gc();
+      java.io.LineNumberReader lnr = new java.io.LineNumberReader(new java.io.InputStreamReader(System.in));
+      StringBuffer sb = new StringBuffer();
+      String line;
+      while ((line = lnr.readLine()) != null) {
+        sb.append(line).append('\n');
+      }
+      String text = sb.toString();
+      //System.err.println("TEXT:");
+      //System.err.println(text);
+      r.gc();
+
+      System.err.print("TOTAL: " + r.totalMemory());
+      System.err.println("\tFREE: " + r.freeMemory());
+      long used = r.totalMemory() - r.freeMemory();
+      
+      // convert to a compressedobject
+      SerializedObject co = new SerializedObject(text, true);
+
+      System.err.print("TOTAL: " + r.totalMemory());
+      System.err.println("\tFREE: " + r.freeMemory());
+      r.gc();
+      long used1 = r.totalMemory() - r.freeMemory();
+      long csize = used1 - used;
+      System.err.println("CompressedSize = " + csize);
+
+      String newstr = (String)co.getObject();
+      r.gc();
+      System.err.print("TOTAL: " + r.totalMemory());
+      System.err.println("\tFREE: " + r.freeMemory());
+      long used2 = r.totalMemory() - r.freeMemory();
+      long usize = used2 - used1;
+      System.err.println("UncompressedSize = " + usize);
+
+      // A couple of references to the original objects
+      // so they don't get freed prematurely and muck up the
+      // measurements.
+      newstr = newstr.toLowerCase();
+      text = text.toLowerCase();
+      System.err.println("Byte array: " + co.toString());
+      System.err.println("Length of text: " + text.length());
+    } catch (Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+
+
+  /**
+   * Test routine, reads an arff file from stdin and measures memory usage
+   * (the arff file should have long string attribute values)
+   */
+  public static void main(String []args) {
+
+    try {
+      Runtime r = Runtime.getRuntime();
+      r.gc();
+      System.err.print("TOTAL: " + r.totalMemory());
+      System.err.println("\tFREE: " + r.freeMemory());
+      long used = r.totalMemory() - r.freeMemory();
+      Instances inst = new Instances(new java.io.BufferedReader(new java.io.InputStreamReader(System.in)));
+      r.gc();
+      long used1 = r.totalMemory() - r.freeMemory();
+      long csize = used1 - used;
+      System.err.print("\nTOTAL: " + r.totalMemory());
+      System.err.println("\tFREE: " + r.freeMemory());
+      System.err.println("size = " + csize);
+      int blah = inst.numAttributes();
+    } catch (Exception ex) {
+      ex.printStackTrace();
+    }
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/SparseInstance.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/SparseInstance.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/SparseInstance.java	(revision 10506)
@@ -0,0 +1,773 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    SparseInstance.java
+ *    Copyright (C) 2000 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * Class for storing an instance as a sparse vector. A sparse instance
+ * only requires storage for those attribute values that are non-zero.
+ * Since the objective is to reduce storage requirements for datasets
+ * with large numbers of default values, this also includes nominal
+ * attributes -- the first nominal value (i.e. that which has index 0)
+ * will not require explicit storage, so rearrange your nominal attribute
+ * value orderings if necessary. Missing values will be stored
+ * explicitly.
+ */
+public class SparseInstance extends Instance {
+
+  /** The index of the attribute associated with each stored value. */
+  protected int[] m_Indices;
+
+  /** The maximum number of values that can be stored. */
+  protected int m_NumAttributes;
+
+  protected SparseInstance() {
+
+  }
+
+  /**
+   * Constructor that generates a sparse instance from the given
+   * instance. Reference to the dataset is set to null.
+   * (ie. the instance doesn't have access to information about the
+   * attribute types)
+   *
+   * @param instance the instance from which the attribute values
+   * and the weight are to be copied
+   */
+  public SparseInstance(Instance instance) {
+    
+    m_Weight = instance.m_Weight;
+    m_Dataset = null;
+    m_NumAttributes = instance.numAttributes();
+    if (instance instanceof SparseInstance) {
+      m_AttValues = ((SparseInstance)instance).m_AttValues;
+      m_Indices = ((SparseInstance)instance).m_Indices;
+    } else {
+      double[] tempValues = new double[instance.numAttributes()];
+      int[] tempIndices = new int[instance.numAttributes()];
+      int vals = 0;
+      for (int i = 0; i < instance.numAttributes(); i++) {
+	if (instance.value(i) != 0) {
+	  tempValues[vals] = instance.value(i);
+	  tempIndices[vals] = i;
+	  vals++;
+	}
+      }
+      m_AttValues = new double[vals];
+      m_Indices = new int[vals];
+      System.arraycopy(tempValues, 0, m_AttValues, 0, vals);
+      System.arraycopy(tempIndices, 0, m_Indices, 0, vals);
+    }
+  }
+
+  /**
+   * Constructor that copies the info from the given instance. 
+   * Reference to the dataset is set to null.
+   * (ie. the instance doesn't have access to information about the
+   * attribute types)
+   *
+   * @param instance the instance from which the attribute
+   * info is to be copied 
+   */
+  public SparseInstance(SparseInstance instance) {
+    
+    m_AttValues = instance.m_AttValues;
+    m_Indices = instance.m_Indices;
+    m_Weight = instance.m_Weight;
+    m_NumAttributes = instance.m_NumAttributes;
+    m_Dataset = null;
+  }
+
+  /**
+   * Constructor that generates a sparse instance from the given
+   * parameters. Reference to the dataset is set to null.
+   * (ie. the instance doesn't have access to information about the
+   * attribute types)
+   *
+   * @param weight the instance's weight
+   * @param attValues a vector of attribute values 
+   */
+  public SparseInstance(double weight, double[] attValues) {
+    
+    m_Weight = weight;
+    m_Dataset = null;
+    m_NumAttributes = attValues.length;
+    double[] tempValues = new double[m_NumAttributes];
+    int[] tempIndices = new int[m_NumAttributes];
+    int vals = 0;
+    for (int i = 0; i < m_NumAttributes; i++) {
+      if (attValues[i] != 0) {
+	tempValues[vals] = attValues[i];
+	tempIndices[vals] = i;
+	vals++;
+      }
+    }
+    m_AttValues = new double[vals];
+    m_Indices = new int[vals];
+    System.arraycopy(tempValues, 0, m_AttValues, 0, vals);
+    System.arraycopy(tempIndices, 0, m_Indices, 0, vals);
+  }
+  
+  /**
+   * Constructor that inititalizes instance variable with given
+   * values. Reference to the dataset is set to null. (ie. the instance
+   * doesn't have access to information about the attribute types)
+   *
+   * @param weight the instance's weight
+   * @param attValues a vector of attribute values (just the ones to be stored)
+   * @param indices the indices of the given values in the full vector
+   * @param maxNumValues the maximium number of values that can be stored
+   */
+  public SparseInstance(double weight, double[] attValues,
+			int[] indices, int maxNumValues){
+    
+    int vals = 0; 
+    m_AttValues = new double [attValues.length];
+    m_Indices = new int [indices.length];
+    for (int i = 0; i < attValues.length; i++) {
+      if (attValues[i] != 0) {
+        m_AttValues[vals] = attValues[i];
+        m_Indices[vals] = indices[i];
+        vals++;
+      }
+    }
+    if (vals != attValues.length) {
+      // Need to truncate.
+      double [] newVals = new double[vals];
+      System.arraycopy(m_AttValues, 0, newVals, 0, vals);
+      m_AttValues = newVals;
+      int [] newIndices = new int[vals];
+      System.arraycopy(m_Indices, 0, newIndices, 0, vals);
+      m_Indices = newIndices;
+    }
+    m_Weight = weight;
+    m_NumAttributes = maxNumValues;
+    m_Dataset = null;
+  }
+
+  /**
+   * Constructor of an instance that sets weight to one, all values to
+   * be missing, and the reference to the dataset to null. (ie. the instance
+   * doesn't have access to information about the attribute types)
+   *
+   * @param numAttributes the size of the instance 
+   */
+  public SparseInstance(int numAttributes) {
+    
+    m_AttValues = new double[numAttributes];
+    m_NumAttributes = numAttributes;
+    m_Indices = new int[numAttributes];
+    for (int i = 0; i < m_AttValues.length; i++) {
+      m_AttValues[i] = MISSING_VALUE;
+      m_Indices[i] = i;
+    }
+    m_Weight = 1;
+    m_Dataset = null;
+  }
+
+  /**
+   * Returns the attribute associated with the internal index. 
+   *
+   * @param indexOfIndex the index of the attribute's index 
+   * @return the attribute at the given position
+   * @exception UnassignedDatasetException if instance doesn't have access to a
+   * dataset
+   */ 
+  public Attribute attributeSparse(int indexOfIndex) {
+   
+    if (m_Dataset == null) {
+      throw new UnassignedDatasetException("Instance doesn't have access to a dataset!");
+    }
+    return m_Dataset.attribute(m_Indices[indexOfIndex]);
+  }
+
+  /**
+   * Produces a shallow copy of this instance. The copy has
+   * access to the same dataset. (if you want to make a copy
+   * that doesn't have access to the dataset, use 
+   * <code>new SparseInstance(instance)</code>
+   *
+   * @return the shallow copy
+   */
+  public Object copy() {
+
+    Instance result = new SparseInstance(this);
+    result.m_Dataset = m_Dataset;
+    return result;
+  }
+
+  /**
+   * Returns the index of the attribute stored at the given position.
+   *
+   * @param position the position 
+   * @return the index of the attribute stored at the given position
+   */
+  public int index(int position) {
+
+    return m_Indices[position];
+  }
+
+  /**
+   * Tests if a specific value is "missing".
+   *
+   * @param attIndex the attribute's index
+   */
+  public boolean isMissing(int attIndex) {
+
+    if (Double.isNaN(value(attIndex))) {
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Locates the greatest index that is not greater than the
+   * given index.
+   *
+   * @return the internal index of the attribute index. Returns
+   * -1 if no index with this property couldn't be found
+   */
+  public int locateIndex(int index) {
+
+    int min = 0, max = m_Indices.length - 1;
+
+    // Binary search
+    while (max >= min) {
+      int current = (max + min) / 2;
+      if (m_Indices[current] > index) {
+	max = current - 1;
+      } else if (m_Indices[current] < index) {
+	min = current + 1;
+      } else {
+	return current;
+      }
+    }
+    return max;
+  }
+
+  /**
+   * Merges this instance with the given instance and returns
+   * the result. Dataset is set to null.
+   *
+   * @param inst the instance to be merged with this one
+   * @return the merged instances
+   */
+  public Instance mergeInstance(Instance inst) {
+
+    double[] values = new double[numValues() + inst.numValues()];
+    int[] indices = new int[numValues() + inst.numValues()];
+
+    int m = 0;
+    for (int j = 0; j < numValues(); j++, m++) {
+      values[m] = valueSparse(j);
+      indices[m] = index(j);
+    }
+    for (int j = 0; j < inst.numValues(); j++, m++) {
+      values[m] = inst.valueSparse(j);
+      indices[m] = inst.index(j) + inst.numAttributes();
+    }
+    
+    return new SparseInstance(1.0, values, indices, numAttributes() +
+			      inst.numAttributes());
+  }
+
+  /**
+   * Returns the number of attributes.
+   *
+   * @return the number of attributes as an integer
+   */
+  public int numAttributes() {
+
+    return m_NumAttributes;
+  }
+
+  /**
+   * Returns the number of values in the sparse vector.
+   *
+   * @return the number of values
+   */
+  public int numValues() {
+
+    return m_Indices.length;
+  }
+
+  /** 
+   * Replaces all missing values in the instance with the 
+   * values contained in the given array. A deep copy of
+   * the vector of attribute values is performed before the
+   * values are replaced.
+   *
+   * @param array containing the means and modes
+   * @exception IllegalArgumentException if numbers of attributes are unequal
+   */
+  public void replaceMissingValues(double[] array) {
+	 
+    if ((array == null) || (array.length != m_NumAttributes)) {
+      throw new IllegalArgumentException("Unequal number of attributes!");
+    }
+    double[] tempValues = new double[m_AttValues.length];
+    int[] tempIndices = new int[m_AttValues.length];
+    int vals = 0;
+    for (int i = 0; i < m_AttValues.length; i++) {
+      if (isMissingValue(m_AttValues[i])) {
+	if (array[m_Indices[i]] != 0) {
+	  tempValues[vals] = array[m_Indices[i]];
+	  tempIndices[vals] = m_Indices[i];
+	  vals++;
+	} 
+      } else {
+	tempValues[vals] = m_AttValues[i];
+	tempIndices[vals] = m_Indices[i];
+	vals++;
+      }
+    }
+    m_AttValues = new double[vals];
+    m_Indices = new int[vals];
+    System.arraycopy(tempValues, 0, m_AttValues, 0, vals);
+    System.arraycopy(tempIndices, 0, m_Indices, 0, vals);
+  }
+
+  /**
+   * Sets a specific value in the instance to the given value 
+   * (internal floating-point format). Performs a deep copy
+   * of the vector of attribute values before the value is set.
+   *
+   * @param attIndex the attribute's index 
+   * @param value the new attribute value (If the corresponding
+   * attribute is nominal (or a string) then this is the new value's
+   * index as a double).  
+   */
+  public void setValue(int attIndex, double value) {
+
+    int index = locateIndex(attIndex);
+    
+    if ((index >= 0) && (m_Indices[index] == attIndex)) {
+      if (value != 0) {
+	double[] tempValues = new double[m_AttValues.length];
+	System.arraycopy(m_AttValues, 0, tempValues, 0, m_AttValues.length);
+	tempValues[index] = value;
+	m_AttValues = tempValues;
+      } else {
+	double[] tempValues = new double[m_AttValues.length - 1];
+	int[] tempIndices = new int[m_Indices.length - 1];
+	System.arraycopy(m_AttValues, 0, tempValues, 0, index);
+	System.arraycopy(m_Indices, 0, tempIndices, 0, index);
+	System.arraycopy(m_AttValues, index + 1, tempValues, index, 
+			 m_AttValues.length - index - 1);
+	System.arraycopy(m_Indices, index + 1, tempIndices, index, 
+			 m_Indices.length - index - 1);
+	m_AttValues = tempValues;
+	m_Indices = tempIndices;
+      }
+    } else {
+      if (value != 0) {
+	double[] tempValues = new double[m_AttValues.length + 1];
+	int[] tempIndices = new int[m_Indices.length + 1];
+	System.arraycopy(m_AttValues, 0, tempValues, 0, index + 1);
+	System.arraycopy(m_Indices, 0, tempIndices, 0, index + 1);
+	tempIndices[index + 1] = attIndex;
+	tempValues[index + 1] = value;
+	System.arraycopy(m_AttValues, index + 1, tempValues, index + 2, 
+			 m_AttValues.length - index - 1);
+	System.arraycopy(m_Indices, index + 1, tempIndices, index + 2, 
+			 m_Indices.length - index - 1);
+	m_AttValues = tempValues;
+	m_Indices = tempIndices;
+      }
+    }
+  }
+
+  /**
+   * Sets a specific value in the instance to the given value 
+   * (internal floating-point format). Performs a deep copy
+   * of the vector of attribute values before the value is set.
+   *
+   * @param indexOfIndex the index of the attribute's index 
+   * @param value the new attribute value (If the corresponding
+   * attribute is nominal (or a string) then this is the new value's
+   * index as a double).  
+   */
+  public void setValueSparse(int indexOfIndex, double value) {
+
+    if (value != 0) {
+      double[] tempValues = new double[m_AttValues.length];
+      System.arraycopy(m_AttValues, 0, tempValues, 0, m_AttValues.length);
+      m_AttValues = tempValues;
+      m_AttValues[indexOfIndex] = value;
+    } else {
+      double[] tempValues = new double[m_AttValues.length - 1];
+      int[] tempIndices = new int[m_Indices.length - 1];
+      System.arraycopy(m_AttValues, 0, tempValues, 0, indexOfIndex);
+      System.arraycopy(m_Indices, 0, tempIndices, 0, indexOfIndex);
+      System.arraycopy(m_AttValues, indexOfIndex + 1, tempValues, indexOfIndex, 
+		       m_AttValues.length - indexOfIndex - 1);
+      System.arraycopy(m_Indices, indexOfIndex + 1, tempIndices, indexOfIndex, 
+		       m_Indices.length - indexOfIndex - 1);
+      m_AttValues = tempValues;
+      m_Indices = tempIndices;
+    }
+  }
+
+  /**
+   * Returns the values of each attribute as an array of doubles.
+   *
+   * @return an array containing all the instance attribute values
+   */
+  public double[] toDoubleArray() {
+
+    double[] newValues = new double[m_NumAttributes];
+    for (int i = 0; i < m_AttValues.length; i++) {
+      newValues[m_Indices[i]] = m_AttValues[i];
+    }
+    return newValues;
+  }
+
+  /**
+   * Returns the description of one instance in sparse format. 
+   * If the instance doesn't have access to a dataset, it returns the 
+   * internal floating-point values. Quotes string values that contain 
+   * whitespace characters.
+   *
+   * @return the instance's description as a string
+   */
+  public String toString() {
+
+    StringBuffer text = new StringBuffer();
+    
+    text.append('{');
+    for (int i = 0; i < m_Indices.length; i++) {
+      if (i > 0) text.append(",");
+      if (isMissingValue(m_AttValues[i])) {
+	text.append(m_Indices[i] + " ?");
+      } else {
+	if (m_Dataset == null) {
+	  text.append(m_Indices[i] + " " + 
+		      Utils.doubleToString(m_AttValues[i],6));
+	} else {
+	  if (m_Dataset.attribute(m_Indices[i]).isNominal() || 
+	      m_Dataset.attribute(m_Indices[i]).isString()) {
+	    try {
+	      text.append(m_Indices[i] + " " +
+			  Utils.quote(m_Dataset.attribute(m_Indices[i]).
+				      value((int)valueSparse(i))));
+	    } catch (Exception e) {
+              e.printStackTrace();
+              System.err.println(new Instances(m_Dataset, 0));
+              System.err.println("Att:" + m_Indices[i] + " Val:" + valueSparse(i));
+	      throw new Error("This should never happen!");
+	    }
+	  } else {
+	    text.append(m_Indices[i] + " " +
+			Utils.doubleToString(m_AttValues[i],6));
+	  }
+	}
+      }
+    }
+    text.append('}');
+    return text.toString();
+  }
+
+  /**
+   * Returns an instance's attribute value in internal format.
+   *
+   * @param attIndex the attribute's index
+   * @return the specified value as a double (If the corresponding
+   * attribute is nominal (or a string) then it returns the value's index as a 
+   * double).
+   */
+  public double value(int attIndex) {
+
+    int index = locateIndex(attIndex);
+    if ((index >= 0) && (m_Indices[index] == attIndex)) {
+      return m_AttValues[index];
+    } else {
+      return 0.0;
+    }
+  }  
+
+  /**
+   * Deletes an attribute at the given position (0 to 
+   * numAttributes() - 1).
+   *
+   * @param pos the attribute's position
+   */
+  void forceDeleteAttributeAt(int position) {
+
+    int index = locateIndex(position);
+
+    m_NumAttributes--;
+    if ((index >= 0) && (m_Indices[index] == position)) {
+      int[] tempIndices = new int[m_Indices.length - 1];
+      double[] tempValues = new double[m_AttValues.length - 1];
+      System.arraycopy(m_Indices, 0, tempIndices, 0, index);
+      System.arraycopy(m_AttValues, 0, tempValues, 0, index);
+      for (int i = index; i < m_Indices.length - 1; i++) {
+	tempIndices[i] = m_Indices[i + 1] - 1;
+	tempValues[i] = m_AttValues[i + 1];
+      }
+      m_Indices = tempIndices;
+      m_AttValues = tempValues;
+    } else {
+      int[] tempIndices = new int[m_Indices.length];
+      double[] tempValues = new double[m_AttValues.length];
+      System.arraycopy(m_Indices, 0, tempIndices, 0, index + 1);
+      System.arraycopy(m_AttValues, 0, tempValues, 0, index + 1);
+      for (int i = index + 1; i < m_Indices.length - 1; i++) {
+	tempIndices[i] = m_Indices[i] - 1;
+	tempValues[i] = m_AttValues[i];
+      }
+      m_Indices = tempIndices;
+      m_AttValues = tempValues;
+    }
+  }
+
+  /**
+   * Inserts an attribute at the given position
+   * (0 to numAttributes()) and sets its value to be missing. 
+   *
+   * @param pos the attribute's position
+   */
+  void forceInsertAttributeAt(int position)  {
+
+    int index = locateIndex(position);
+
+    m_NumAttributes++;
+    if ((index >= 0) && (m_Indices[index] == position)) {
+      int[] tempIndices = new int[m_Indices.length + 1];
+      double[] tempValues = new double[m_AttValues.length + 1];
+      System.arraycopy(m_Indices, 0, tempIndices, 0, index);
+      System.arraycopy(m_AttValues, 0, tempValues, 0, index);
+      tempIndices[index] = position;
+      tempValues[index] = MISSING_VALUE;
+      for (int i = index; i < m_Indices.length; i++) {
+	tempIndices[i + 1] = m_Indices[i] + 1;
+	tempValues[i + 1] = m_AttValues[i];
+      }
+      m_Indices = tempIndices;
+      m_AttValues = tempValues;
+    } else {
+      int[] tempIndices = new int[m_Indices.length + 1];
+      double[] tempValues = new double[m_AttValues.length + 1];
+      System.arraycopy(m_Indices, 0, tempIndices, 0, index + 1);
+      System.arraycopy(m_AttValues, 0, tempValues, 0, index + 1);
+      tempIndices[index + 1] = position;
+      tempValues[index + 1] = MISSING_VALUE;
+      for (int i = index + 1; i < m_Indices.length; i++) {
+	tempIndices[i + 1] = m_Indices[i] + 1;
+	tempValues[i + 1] = m_AttValues[i];
+      }
+      m_Indices = tempIndices;
+      m_AttValues = tempValues;
+    }
+  }
+
+  /**
+   * Main method for testing this class.
+   */
+  public static void main(String[] options) {
+
+    try {
+
+      // Create numeric attributes "length" and "weight"
+      Attribute length = new Attribute("length");
+      Attribute weight = new Attribute("weight");
+      
+      // Create vector to hold nominal values "first", "second", "third" 
+      FastVector my_nominal_values = new FastVector(3); 
+      my_nominal_values.addElement("first"); 
+      my_nominal_values.addElement("second"); 
+      my_nominal_values.addElement("third"); 
+      
+      // Create nominal attribute "position" 
+      Attribute position = new Attribute("position", my_nominal_values);
+      
+      // Create vector of the above attributes 
+      FastVector attributes = new FastVector(3);
+      attributes.addElement(length);
+      attributes.addElement(weight);
+      attributes.addElement(position);
+      
+      // Create the empty dataset "race" with above attributes
+      Instances race = new Instances("race", attributes, 0);
+      
+      // Make position the class attribute
+      race.setClassIndex(position.index());
+      
+      // Create empty instance with three attribute values
+      SparseInstance inst = new SparseInstance(3);
+      
+      // Set instance's values for the attributes "length", "weight", and "position"
+      inst.setValue(length, 5.3);
+      inst.setValue(weight, 300);
+      inst.setValue(position, "first");
+      
+      // Set instance's dataset to be the dataset "race"
+      inst.setDataset(race);
+      
+      // Print the instance
+      System.out.println("The instance: " + inst);
+      
+      // Print the first attribute
+      System.out.println("First attribute: " + inst.attribute(0));
+      
+      // Print the class attribute
+      System.out.println("Class attribute: " + inst.classAttribute());
+      
+      // Print the class index
+      System.out.println("Class index: " + inst.classIndex());
+      
+      // Say if class is missing
+      System.out.println("Class is missing: " + inst.classIsMissing());
+      
+      // Print the instance's class value in internal format
+      System.out.println("Class value (internal format): " + inst.classValue());
+      
+      // Print a shallow copy of this instance
+      SparseInstance copy = (SparseInstance) inst.copy();
+      System.out.println("Shallow copy: " + copy);
+      
+      // Set dataset for shallow copy
+      copy.setDataset(inst.dataset());
+      System.out.println("Shallow copy with dataset set: " + copy);
+
+      // Print out all values in internal format
+      System.out.print("All stored values in internal format: ");
+      for (int i = 0; i < inst.numValues(); i++) {
+	if (i > 0) {
+	  System.out.print(",");
+	}
+	System.out.print(inst.valueSparse(i));
+      }
+      System.out.println();
+
+      // Set all values to zero
+      System.out.print("All values set to zero: ");
+      while (inst.numValues() > 0) {
+	inst.setValueSparse(0, 0);
+      }
+      for (int i = 0; i < inst.numValues(); i++) {
+	if (i > 0) {
+	  System.out.print(",");
+	}
+	System.out.print(inst.valueSparse(i));
+      }
+      System.out.println();
+
+      // Set all values to one
+      System.out.print("All values set to one: ");
+      for (int i = 0; i < inst.numAttributes(); i++) {
+	inst.setValue(i, 1);
+      }
+      for (int i = 0; i < inst.numValues(); i++) {
+	if (i > 0) {
+	  System.out.print(",");
+	}
+	System.out.print(inst.valueSparse(i));
+      }
+      System.out.println();
+
+      // Unset dataset for copy, delete first attribute, and insert it again
+      copy.setDataset(null);
+      copy.deleteAttributeAt(0);
+      copy.insertAttributeAt(0);
+      copy.setDataset(inst.dataset());
+      System.out.println("Copy with first attribute deleted and inserted: " + copy); 
+
+      // Same for second attribute
+      copy.setDataset(null);
+      copy.deleteAttributeAt(1);
+      copy.insertAttributeAt(1);
+      copy.setDataset(inst.dataset());
+      System.out.println("Copy with second attribute deleted and inserted: " + copy); 
+
+      // Same for last attribute
+      copy.setDataset(null);
+      copy.deleteAttributeAt(2);
+      copy.insertAttributeAt(2);
+      copy.setDataset(inst.dataset());
+      System.out.println("Copy with third attribute deleted and inserted: " + copy); 
+      
+      // Enumerate attributes (leaving out the class attribute)
+      System.out.println("Enumerating attributes (leaving out class):");
+      Enumeration enum = inst.enumerateAttributes();
+      while (enum.hasMoreElements()) {
+	Attribute att = (Attribute) enum.nextElement();
+	System.out.println(att);
+      }
+      
+      // Headers are equivalent?
+      System.out.println("Header of original and copy equivalent: " +
+			 inst.equalHeaders(copy));
+
+      // Test for missing values
+      System.out.println("Length of copy missing: " + copy.isMissing(length));
+      System.out.println("Weight of copy missing: " + copy.isMissing(weight.index()));
+      System.out.println("Length of copy missing: " + 
+			 Instance.isMissingValue(copy.value(length)));
+      System.out.println("Missing value coded as: " + Instance.missingValue());
+
+      // Prints number of attributes and classes
+      System.out.println("Number of attributes: " + copy.numAttributes());
+      System.out.println("Number of classes: " + copy.numClasses());
+
+      // Replace missing values
+      double[] meansAndModes = {2, 3, 0};
+      copy.replaceMissingValues(meansAndModes);
+      System.out.println("Copy with missing value replaced: " + copy);
+
+      // Setting and getting values and weights
+      copy.setClassMissing();
+      System.out.println("Copy with missing class: " + copy);
+      copy.setClassValue(0);
+      System.out.println("Copy with class value set to first value: " + copy);
+      copy.setClassValue("third");
+      System.out.println("Copy with class value set to \"third\": " + copy);
+      copy.setMissing(1);
+      System.out.println("Copy with second attribute set to be missing: " + copy);
+      copy.setMissing(length);
+      System.out.println("Copy with length set to be missing: " + copy);
+      copy.setValue(0, 0);
+      System.out.println("Copy with first attribute set to 0: " + copy);
+      copy.setValue(weight, 1);
+      System.out.println("Copy with weight attribute set to 1: " + copy);
+      copy.setValue(position, "second");
+      System.out.println("Copy with position set to \"second\": " + copy);
+      copy.setValue(2, "first");
+      System.out.println("Copy with last attribute set to \"first\": " + copy);
+      System.out.println("Current weight of instance copy: " + copy.weight());
+      copy.setWeight(2);
+      System.out.println("Current weight of instance copy (set to 2): " + copy.weight());
+      System.out.println("Last value of copy: " + copy.toString(2));
+      System.out.println("Value of position for copy: " + copy.toString(position));
+      System.out.println("Last value of copy (internal format): " + copy.value(2));
+      System.out.println("Value of position for copy (internal format): " + 
+			 copy.value(position));
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/SpecialFunctions.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/SpecialFunctions.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/SpecialFunctions.java	(revision 10506)
@@ -0,0 +1,127 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    SpecialFunctions.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+import java.lang.Math;
+
+/**
+ * Class implementing some mathematical functions.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public final class SpecialFunctions {
+
+  /** Some constants */
+  private static double log2 = Math.log(2);
+  private static double[] cofLogGamma = {76.18009172947146,-86.50532032941677,
+					 24.01409824083091,-1.231739572450155,
+					 0.1208650973866179e-2,-0.5395239384953e-5};
+
+  /**
+   * Returns natural logarithm of factorial using gamma function.
+   *
+   * @param x the value
+   * @return natural logarithm of factorial
+   */
+  public static double lnFactorial(double x){
+
+    return lnGamma(x+1);
+  }
+
+  /**
+   * Returns natural logarithm of gamma function. Converted to java
+   * from Numerical Recipes in C.
+   *
+   * @param x the value
+   * @return natural logarithm of gamma function
+   */
+  public static double lnGamma(double x){
+    
+    double y,tmp,ser;
+    int j;
+    
+    y=x;
+    tmp=x+5.5;
+    tmp -= (x+0.5)*Math.log(tmp);
+    ser=1.000000000190015;
+    for (j=0;j<=5;j++) {
+      ser += cofLogGamma[j]/++y;
+    }
+    return -tmp+Math.log(2.5066282746310005*ser/x);
+  }
+
+  /**
+   * Returns base 2 logarithm of binomial coefficient using gamma function.
+   *
+   * @param a upper part of binomial coefficient
+   * @param b lower part
+   * @return the base 2 logarithm of the binominal coefficient a over b
+   */
+  public static double log2Binomial(double a, double b) throws ArithmeticException{
+    
+    if (Utils.gr(b,a)) {
+      throw new ArithmeticException("Can't compute binomial coefficient.");
+    }
+    return (lnFactorial(a)-lnFactorial(b)-lnFactorial(a-b))/log2;
+  }
+
+  /**
+   * Returns base 2 logarithm of multinomial using gamma function.
+   *
+   * @param a upper part of multinomial coefficient
+   * @param bs lower part
+   * @return multinomial coefficient of a over the bs
+   */
+  public static double log2Multinomial(double a, double[] bs)
+       throws ArithmeticException{
+    
+    double sum = 0;
+    int i;
+    
+    for (i=0;i<bs.length;i++) {
+      if (Utils.gr(bs[i],a)) {
+	throw 
+	  new ArithmeticException("Can't compute multinomial coefficient.");
+      } else {
+	sum = sum+lnFactorial(bs[i]);
+      }
+    }
+    return (lnFactorial(a)-sum)/log2;
+  }
+
+  /**
+   * Main method for testing this class.
+   */
+  public static void main(String[] ops) {
+
+    double[] doubles = {1, 2, 3};
+
+    System.out.println("6!: " + Math.exp(SpecialFunctions.lnFactorial(6)));
+    System.out.println("lnGamma(6): "+ SpecialFunctions.lnGamma(6));
+    System.out.println("Binomial 6 over 2: " +
+		       Math.pow(2, SpecialFunctions.log2Binomial(6, 2)));
+    System.out.println("Multinomial 6 over 1, 2, 3: " +
+		       Math.pow(2, SpecialFunctions.log2Multinomial(6, doubles)));
+  }    
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Statistics.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Statistics.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Statistics.java	(revision 10506)
@@ -0,0 +1,280 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Statistics.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+/**
+ * Class implementing some distributions, tests, etc. Most of the
+ * code is adapted from Gary Perlman's unixstat.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public class Statistics {
+
+  /** Some constants */
+  private static double logSqrtPi = Math.log(Math.sqrt(Math.PI));
+  private static double rezSqrtPi = 1/Math.sqrt(Math.PI);
+  private static double bigx = 20.0;
+
+  /**
+   * Computes standard error for observed values of a binomial
+   * random variable.
+   *
+   * @param p the probability of success
+   * @param n the size of the sample
+   * @return the standard error
+   */
+  public static double binomialStandardError(double p, int n) {
+
+    if (n == 0) {
+      return 0; 
+    }
+    return Math.sqrt((p*(1-p))/(double) n);
+  }
+
+  /**
+   * Returns chi-squared probability for given value and degrees
+   * of freedom. (The probability that the chi-squared variate
+   * will be greater than x for the given degrees of freedom.)
+   * Adapted from unixstat by Gary Perlman.
+   *
+   * @param x the value
+   * @param df the number of degrees of freedom
+   */
+  public static double chiSquaredProbability(double x, int df) {
+
+    double a, y = 0, s, e, c, z, val;
+    boolean even;
+   
+    if (x <= 0 || df < 1)
+      return (1);
+    a = 0.5 * x;
+    even = (((int)(2*(df/2))) == df);
+    if (df > 1)
+      y = Math.exp(-a); //((-a < -bigx) ? 0.0 : Math.exp (-a));
+    s = (even ? y : (2.0 * normalProbability(-Math.sqrt (x))));
+    if (df > 2){
+      x = 0.5 * (df - 1.0);
+      z = (even ? 1.0 : 0.5);
+      if (a > bigx){
+	e = (even ? 0.0 : logSqrtPi);
+	c = Math.log (a);
+	while (z <= x){
+	  e = Math.log (z) + e;
+	  val = c*z-a-e;
+	  s += Math.exp (val); //((val < -bigx) ? 0.0 : Math.exp (val));
+	  z += 1.0;
+	}
+	return (s);
+      }else{
+	e = (even ? 1.0 : (rezSqrtPi / Math.sqrt (a)));
+	c = 0.0;
+	while (z <= x){
+	  e = e * (a / z);
+	  c = c + e;
+	  z += 1.0;
+	}
+	return (c * y + s);
+      }
+    }else{
+      return (s);
+    }
+  }
+
+  /**
+   * Critical value for given probability of F-distribution.
+   * Adapted from unixstat by Gary Perlman.
+   *
+   * @param p the probability
+   * @param df1 the first number of degrees of freedom
+   * @param df2 the second number of degrees of freedom
+   * @return the critical value for the given probability
+   */
+  public static double FCriticalValue(double p, int df1, int df2) {
+
+    double  fval;
+    double  maxf = 99999.0;     /* maximum possible F ratio */
+    double  minf = .000001;     /* minimum possible F ratio */
+    
+    if (p <= 0.0 || p >= 1.0)
+      return (0.0);
+    
+    fval = 1.0 / p; /* the smaller the p, the larger the F */
+    
+    while (Math.abs (maxf - minf) > .000001) {
+      if (FProbability(fval, df1, df2) < p) /* F too large */
+	maxf = fval;
+      else /* F too small */
+	minf = fval;
+      fval = (maxf + minf) * 0.5;
+    }
+    
+    return (fval);
+  }
+
+  /**
+   * Computes probability of F-ratio.
+   * Adapted from unixstat by Gary Perlman.
+   * Collected Algorithms of the CACM 
+   * Algorithm 322
+   * Egon Dorrer
+   *
+   * @param F the F-ratio
+   * @param df1 the first number of degrees of freedom
+   * @param df2 the second number of degrees of freedom
+   * @return the probability of the F-ratio.
+   */
+  public static double FProbability(double F, int df1, int df2) {
+
+    int     i, j;
+    int     a, b;
+    double  w, y, z, d, p;
+
+    if ((Math.abs(F) < 10e-10) || df1 <= 0 || df2 <= 0)
+      return (1.0);
+    a = (df1%2 == 1) ? 1 : 2;
+    b = (df2%2 == 1) ? 1 : 2;
+    w = (F * df1) / df2;
+    z = 1.0 / (1.0 + w);
+    if (a == 1)
+      if (b == 1) {
+	p = Math.sqrt (w);
+	y = 1/Math.PI; /* 1 / 3.14159 */
+	d = y * z / p;
+	p = 2.0 * y * Math.atan (p);
+      } else {
+	p = Math.sqrt (w * z);
+	d = 0.5 * p * z / w;
+      } else if (b == 1) {
+	p = Math.sqrt (z);
+	d = 0.5 * z * p;
+	p = 1.0 - p;
+      } else {
+	d = z * z;
+	p = w * z;
+      }
+    y = 2.0 * w / z;
+    for (j = b + 2; j <= df2; j += 2) {
+      d *= (1.0 + a / (j - 2.0)) * z;
+      p = (a == 1 ? p + d * y / (j - 1.0) : (p + w) * z);
+    }
+    y = w * z;
+    z = 2.0 / z;
+    b = df2 - 2;
+    for (i = a + 2; i <= df1; i += 2) {
+      j = i + b;
+      d *= y * j / (i - 2.0);
+      p -= z * d / j;
+    }
+    
+    // correction for approximation errors suggested in certification
+    if (p < 0.0)
+      p = 0.0;
+    else if (p > 1.0)
+      p = 1.0;
+    return (1.0-p);
+  }
+  
+  /**
+   * Returns probability that the standardized normal variate Z (mean = 0, standard
+   * deviation = 1) is less than z.
+   * Adapted from unixstat by Gary Perlman.
+   *
+   * @param the z-value
+   * @return the probability of the z value according to the normal pdf
+   */
+  public static double normalProbability(double z) {
+
+    double  y, x, w;
+    
+    if (z == 0.0)
+      x = 0.0;
+    else{
+      y = 0.5 * Math.abs (z);
+      if (y >= 3.0)
+	x = 1.0;
+      else if (y < 1.0){
+	w = y*y;
+	x = ((((((((0.000124818987 * w
+                   -0.001075204047) * w +0.005198775019) * w
+                   -0.019198292004) * w +0.059054035642) * w
+                   -0.151968751364) * w +0.319152932694) * w
+                   -0.531923007300) * w +0.797884560593) * y * 2.0;
+      }else{
+	y -= 2.0;
+	x = (((((((((((((-0.000045255659 * y
+                         +0.000152529290) * y -0.000019538132) * y
+                         -0.000676904986) * y +0.001390604284) * y
+                         -0.000794620820) * y -0.002034254874) * y
+                         +0.006549791214) * y -0.010557625006) * y
+                         +0.011630447319) * y -0.009279453341) * y
+                         +0.005353579108) * y -0.002141268741) * y
+                         +0.000535310849) * y +0.999936657524;
+      }
+    }
+  
+    return (z > 0.0 ? ((x + 1.0) / 2.0) : ((1.0 - x) / 2.0));
+  }
+
+  /**
+   * Computes absolute size of half of a student-t confidence interval 
+   * for given degrees of freedom, probability, and observed value.
+   *
+   * @param df the number of degrees of freedom
+   * @param p the probability
+   * @param se the observed value
+   * @return absolute size of half of a student-t confidence interval
+   */
+  public static double studentTConfidenceInterval(int df, double p,
+						  double se) {
+
+    return Math.sqrt(FCriticalValue(p, 1, df))*se;
+  }
+
+  /**
+   * Main method for testing this class.
+   */
+  public static void main(String[] ops) {
+
+    System.out.println("Binomial standard error (0.5, 100): " + 
+		       Statistics.binomialStandardError(0.5, 100));
+    System.out.println("Chi-squared probability (2.558, 10): " +
+		       Statistics.chiSquaredProbability(2.558, 10));
+    System.out.println("Normal probability (0.2): " +
+		       Statistics.normalProbability(0.2));
+    System.out.println("F critical value (0.05, 4, 5): " +
+		       Statistics.FCriticalValue(0.05, 4, 5));
+    System.out.println("F probability (5.1922, 4, 5): " +
+		       Statistics.FProbability(5.1922, 4, 5));
+    System.out.println("Student-t confidence interval (9, 0.01, 2): " +
+		       Statistics.studentTConfidenceInterval(9, 0.01, 2));
+  }
+}
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/UnassignedClassException.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/UnassignedClassException.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/UnassignedClassException.java	(revision 10506)
@@ -0,0 +1,52 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    UnassignedClassException.java
+ *    Copyright (C) 2001 Webmind Corp.
+ */
+
+package weka.core;
+
+/**
+ * <code>UnassignedClassException</code> is used when
+ * a method requires access to the Attribute designated as 
+ * the class attribute in a set of Instances, but the Instances does not
+ * have any class attribute assigned (such as by setClassIndex()).
+ *
+ * @author <a href="mailto:len@webmind.com">Len Trigg</a>
+ * @version $Revision$
+ */
+public class UnassignedClassException extends RuntimeException {
+
+  /**
+   * Creates a new <code>UnassignedClassException</code> instance
+   * with no detail message.
+   */
+  public UnassignedClassException() { 
+    super(); 
+  }
+
+  /**
+   * Creates a new <code>UnassignedClassException</code> instance
+   * with a specified message.
+   *
+   * @param messagae a <code>String</code> containing the message.
+   */
+  public UnassignedClassException(String message) { 
+    super(message); 
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/UnassignedDatasetException.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/UnassignedDatasetException.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/UnassignedDatasetException.java	(revision 10506)
@@ -0,0 +1,53 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    UnassignedDatasetException.java
+ *    Copyright (C) 2001 Webmind Corp.
+ */
+
+package weka.core;
+
+/**
+ * <code>UnassignedDatasetException</code> is used when
+ * a method of an Instance is called that requires access to
+ * the Instance structure, but that the Instance does not contain
+ * a reference to any Instances (as set by Instance.setDataset(), or when
+ * an Instance is added to a set of Instances)).
+ *
+ * @author <a href="mailto:len@webmind.com">Len Trigg</a>
+ * @version $Revision$
+ */
+public class UnassignedDatasetException extends RuntimeException {
+
+  /**
+   * Creates a new <code>UnassignedDatasetException</code> instance
+   * with no detail message.
+   */
+  public UnassignedDatasetException() { 
+    super(); 
+  }
+
+  /**
+   * Creates a new <code>UnassignedDatasetException</code> instance
+   * with a specified message.
+   *
+   * @param messagae a <code>String</code> containing the message.
+   */
+  public UnassignedDatasetException(String message) { 
+    super(message); 
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/UnsupportedClassTypeException.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/UnsupportedClassTypeException.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/UnsupportedClassTypeException.java	(revision 10506)
@@ -0,0 +1,51 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    UnsupportedClassTypeException.java
+ *    Copyright (C) 2001 Webmind Corp.
+ */
+
+package weka.core;
+
+/**
+ * <code>UnsupportedClassTypeException</code> is used in situations
+ * where the throwing object is not able to accept Instances with the
+ * supplied structure, because the class Attribute is of the wrong type.
+ *
+ * @author <a href="mailto:len@webmind.com">Len Trigg</a>
+ * @version $Revision$
+ */
+public class UnsupportedClassTypeException extends WekaException {
+
+  /**
+   * Creates a new <code>UnsupportedClassTypeException</code> instance
+   * with no detail message.
+   */
+  public UnsupportedClassTypeException() { 
+    super(); 
+  }
+
+  /**
+   * Creates a new <code>UnsupportedClassTypeException</code> instance
+   * with a specified message.
+   *
+   * @param messagae a <code>String</code> containing the message.
+   */
+  public UnsupportedClassTypeException(String message) { 
+    super(message); 
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Utils.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Utils.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/Utils.java	(revision 10506)
@@ -0,0 +1,1384 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Utils.java
+ *    Copyright (C) 1999 Eibe Frank,Len Trigg,Yong Wang
+ *
+ */
+
+package weka.core;
+
+import java.lang.Math;
+import java.util.StringTokenizer;
+import java.util.Properties;
+import java.io.File;
+import java.io.FileInputStream;
+
+/**
+ * Class implementing some simple utility methods.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @author Yong Wang (yongwang@cs.waikato.ac.nz)
+ * @author Len Trigg (trigg@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public final class Utils {
+
+  /** The natural logarithm of 2. */
+  public static double log2 = Math.log(2);
+
+  /** The small deviation allowed in double comparisons */
+  public static double SMALL = 1e-6;
+
+  
+  /**
+   * Reads properties that inherit from three locations. Properties
+   * are first defined in the system resource location (i.e. in the
+   * CLASSPATH).  These default properties must exist. Properties
+   * defined in the users home directory (optional) override default
+   * settings. Properties defined in the current directory (optional)
+   * override all these settings.
+   *
+   * @param resourceName the location of the resource that should be
+   * loaded.  e.g.: "weka/core/Utils.props". (The use of hardcoded
+   * forward slashes here is OK - see
+   * jdk1.1/docs/guide/misc/resources.html) This routine will also
+   * look for the file (in this case) "Utils.props" in the users home
+   * directory and the current directory.
+   * @return the Properties
+   * @exception Exception if no default properties are defined, or if
+   * an error occurs reading the properties files.  
+   */
+  public static Properties readProperties(String resourceName)
+    throws Exception{
+
+    Properties defaultProps = new Properties();
+    try {
+      // Apparently hardcoded slashes are OK here
+      // jdk1.1/docs/guide/misc/resources.html
+      defaultProps.load(ClassLoader.getSystemResourceAsStream(resourceName));
+    } catch (Exception ex) {
+/*      throw new Exception("Problem reading default properties: "
+	+ ex.getMessage()); */
+      System.err.println("Warning, unable to load properties file from "
+			 +"system resource (Utils.java)");
+    }
+
+    // Hardcoded slash is OK here
+    // eg: see jdk1.1/docs/guide/misc/resources.html
+    int slInd = resourceName.lastIndexOf('/');
+    if (slInd != -1) {
+      resourceName = resourceName.substring(slInd + 1);
+    }
+
+    // Allow a properties file in the home directory to override
+    Properties userProps = new Properties(defaultProps);    
+    File propFile = new File(System.getProperties().getProperty("user.home")
+                             + File.separatorChar
+                             + resourceName);
+    if (propFile.exists()) {
+      try {
+        userProps.load(new FileInputStream(propFile));
+      } catch (Exception ex) {
+        throw new Exception("Problem reading user properties: " + propFile);
+      }
+    }
+
+    // Allow a properties file in the current directory to override
+    Properties localProps = new Properties(userProps);
+    propFile = new File(resourceName);
+    if (propFile.exists()) {
+      try {
+        localProps.load(new FileInputStream(propFile));
+      } catch (Exception ex) {
+        throw new Exception("Problem reading local properties: " + propFile);
+      }
+    }
+    
+    return localProps;
+  }
+
+  /**
+   * Returns the correlation coefficient of two double vectors.
+   *
+   * @param y1 double vector 1
+   * @param y2 double vector 2
+   * @param n the length of two double vectors
+   * @return the correlation coefficient
+   */
+  public final static double correlation(double y1[],double y2[],int n) {
+
+    int i;
+    double av1 = 0.0, av2 = 0.0, y11 = 0.0, y22 = 0.0, y12 = 0.0, c;
+    
+    if (n <= 1) {
+      return 1.0;
+    }
+    for (i = 0; i < n; i++) {
+      av1 += y1[i];
+      av2 += y2[i];
+    }
+    av1 /= (double) n;
+    av2 /= (double) n;
+    for (i = 0; i < n; i++) {
+      y11 += (y1[i] - av1) * (y1[i] - av1);
+      y22 += (y2[i] - av2) * (y2[i] - av2);
+      y12 += (y1[i] - av1) * (y2[i] - av2);
+    }
+    if (y11 * y22 == 0.0) {
+      c=1.0;
+    } else {
+      c = y12 / Math.sqrt(Math.abs(y11 * y22));
+    }
+    
+    return c;
+  }
+
+  /**
+   * Removes all occurrences of a string from another string.
+   *
+   * @param inString the string to remove substrings from.
+   * @param substring the substring to remove.
+   * @return the input string with occurrences of substring removed.
+   */
+  public static String removeSubstring(String inString, String substring) {
+
+    StringBuffer result = new StringBuffer();
+    int oldLoc = 0, loc = 0;
+    while ((loc = inString.indexOf(substring, oldLoc))!= -1) {
+      result.append(inString.substring(oldLoc, loc));
+      oldLoc = loc + substring.length();
+    }
+    result.append(inString.substring(oldLoc));
+    return result.toString();
+  }
+
+  /**
+   * Replaces with a new string, all occurrences of a string from 
+   * another string.
+   *
+   * @param inString the string to replace substrings in.
+   * @param substring the substring to replace.
+   * @param replaceString the replacement substring
+   * @return the input string with occurrences of substring replaced.
+   */
+  public static String replaceSubstring(String inString, String subString,
+					String replaceString) {
+
+    StringBuffer result = new StringBuffer();
+    int oldLoc = 0, loc = 0;
+    while ((loc = inString.indexOf(subString, oldLoc))!= -1) {
+      result.append(inString.substring(oldLoc, loc));
+      result.append(replaceString);
+      oldLoc = loc + subString.length();
+    }
+    result.append(inString.substring(oldLoc));
+    return result.toString();
+  }
+
+
+  /**
+   * Pads a string to a specified length, inserting spaces on the left
+   * as required. If the string is too long, characters are removed (from
+   * the right).
+   *
+   * @param inString the input string
+   * @param length the desired length of the output string
+   * @return the output string
+   */
+  public static String padLeft(String inString, int length) {
+
+    return fixStringLength(inString, length, false);
+  }
+  
+  /**
+   * Pads a string to a specified length, inserting spaces on the right
+   * as required. If the string is too long, characters are removed (from
+   * the right).
+   *
+   * @param inString the input string
+   * @param length the desired length of the output string
+   * @return the output string
+   */
+  public static String padRight(String inString, int length) {
+
+    return fixStringLength(inString, length, true);
+  }
+  
+  /**
+   * Pads a string to a specified length, inserting spaces as
+   * required. If the string is too long, characters are removed (from
+   * the right).
+   *
+   * @param inString the input string
+   * @param length the desired length of the output string
+   * @param right true if inserted spaces should be added to the right
+   * @return the output string
+   */
+  private static String fixStringLength(String inString, int length,
+					boolean right) {
+
+    if (inString.length() < length) {
+      while (inString.length() < length) {
+	inString = (right ? inString.concat(" ") : " ".concat(inString));
+      }
+    } else if (inString.length() > length) {
+      inString = inString.substring(0, length);
+    }
+    return inString;
+  }
+ 
+  /**
+   * Rounds a double and converts it into String.
+   *
+   * @param value the double value
+   * @param afterDecimalPoint the (maximum) number of digits permitted
+   * after the decimal point
+   * @return the double as a formatted string
+   */
+  public static String doubleToString(double value, int afterDecimalPoint) {
+    
+    StringBuffer stringBuffer;
+    double temp;
+    int i,dotPosition;
+    long precisionValue;
+    
+    temp = value * Math.pow(10.0, afterDecimalPoint);
+    if (Math.abs(temp) < Long.MAX_VALUE) {
+      precisionValue = 	(temp > 0) ? (long)(temp + 0.5) 
+                                   : -(long)(Math.abs(temp) + 0.5);
+      if (precisionValue == 0) {
+	stringBuffer = new StringBuffer(String.valueOf(0));
+      } else {
+	stringBuffer = new StringBuffer(String.valueOf(precisionValue));
+      }
+      if (afterDecimalPoint == 0) {
+	return stringBuffer.toString();
+      }
+      dotPosition = stringBuffer.length() - afterDecimalPoint;
+      while (((precisionValue < 0) && (dotPosition < 1)) ||
+	     (dotPosition < 0)) {
+	if (precisionValue < 0) {
+	  stringBuffer.insert(1, 0);
+	} else {
+	  stringBuffer.insert(0, 0);
+	}
+	dotPosition++;
+      }
+      stringBuffer.insert(dotPosition, '.');
+      if ((precisionValue < 0) && (stringBuffer.charAt(1) == '.')) {
+	stringBuffer.insert(1, 0);
+      } else if (stringBuffer.charAt(0) == '.') {
+	stringBuffer.insert(0, 0);
+      }
+      int currentPos = stringBuffer.length() - 1;
+      while ((currentPos > dotPosition) &&
+	     (stringBuffer.charAt(currentPos) == '0')) {
+	stringBuffer.setCharAt(currentPos--, ' ');
+      }
+      if (stringBuffer.charAt(currentPos) == '.') {
+	stringBuffer.setCharAt(currentPos, ' ');
+      }
+      
+      return stringBuffer.toString().trim();
+    }
+    return new String("" + value);
+  }
+
+  /**
+   * Rounds a double and converts it into a formatted decimal-justified String.
+   * Trailing 0's are replaced with spaces.
+   *
+   * @param value the double value
+   * @param width the width of the string
+   * @param afterDecimalPoint the number of digits after the decimal point
+   * @return the double as a formatted string
+   */
+  public static String doubleToString(double value, int width,
+				      int afterDecimalPoint) {
+    
+    String tempString = doubleToString(value, afterDecimalPoint);
+    char[] result;
+    int dotPosition;
+
+    if ((afterDecimalPoint >= width) 
+        || (tempString.indexOf('E') != -1)) { // Protects sci notation
+      return tempString;
+    }
+
+    // Initialize result
+    result = new char[width];
+    for (int i = 0; i < result.length; i++) {
+      result[i] = ' ';
+    }
+
+    if (afterDecimalPoint > 0) {
+      // Get position of decimal point and insert decimal point
+      dotPosition = tempString.indexOf('.');
+      if (dotPosition == -1) {
+	dotPosition = tempString.length();
+      } else {
+	result[width - afterDecimalPoint - 1] = '.';
+      }
+    } else {
+      dotPosition = tempString.length();
+    }
+    
+
+    int offset = width - afterDecimalPoint - dotPosition;
+    if (afterDecimalPoint > 0) {
+      offset--;
+    }
+
+    // Not enough room to decimal align within the supplied width
+    if (offset < 0) {
+      return tempString;
+    }
+
+    // Copy characters before decimal point
+    for (int i = 0; i < dotPosition; i++) {
+      result[offset + i] = tempString.charAt(i);
+    }
+
+    // Copy characters after decimal point
+    for (int i = dotPosition + 1; i < tempString.length(); i++) {
+      result[offset + i] = tempString.charAt(i);
+    }
+
+    return new String(result);
+  }
+
+  /**
+   * Tests if a is equal to b.
+   *
+   * @param a a double
+   * @param b a double
+   */
+  public static boolean eq(double a, double b){
+    
+    return (a - b < SMALL) && (b - a < SMALL); 
+  }
+
+  /**
+   * Checks if the given array contains any non-empty options.
+   *
+   * @param strings an array of strings
+   * @exception Exception if there are any non-empty options
+   */
+  public static void checkForRemainingOptions(String [] options) 
+    throws Exception {
+    
+    int illegalOptionsFound = 0;
+    StringBuffer text = new StringBuffer();
+
+    if (options == null) {
+      return;
+    }
+    for (int i = 0; i < options.length; i++) {
+      if (options[i].length() > 0) {
+	illegalOptionsFound++;
+	text.append(options[i] + ' ');
+      }
+    }
+    if (illegalOptionsFound > 0) {
+      throw new Exception("Illegal options: " + text);
+    }
+  }
+  
+  /**
+   * Checks if the given array contains the flag "-Char". Stops
+   * searching at the first marker "--". If the flag is found,
+   * it is replaced with the empty string.
+   *
+   * @param flag the character indicating the flag.
+   * @param strings the array of strings containing all the options.
+   * @return true if the flag was found
+   * @exception Exception if an illegal option was found
+   */
+
+  public static boolean getFlag(char flag, String [] options) 
+    throws Exception {
+
+    if (options == null) {
+      return false;
+    }
+    for (int i = 0; i < options.length; i++) {
+      if ((options[i].length() > 1) && (options[i].charAt(0) == '-')) {
+	try {
+	  Double dummy = Double.valueOf(options[i]);
+	} catch (NumberFormatException e) {
+	  if (options[i].length() > 2) {
+	    throw new Exception("Illegal option: " + options[i]);
+	  }
+	  if (options[i].charAt(1) == flag) {
+	    options[i] = "";
+	    return true;
+	  }
+	  if (options[i].charAt(1) == '-') {
+	    return false;
+	  }
+	}
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Gets an option indicated by a flag "-Char" from the given array
+   * of strings. Stops searching at the first marker "--". Replaces 
+   * flag and option with empty strings.
+   *
+   * @param flag the character indicating the option.
+   * @param options the array of strings containing all the options.
+   * @return the indicated option or an empty string
+   * @exception Exception if the option indicated by the flag can't be found
+   */
+  public static String getOption(char flag, String [] options) 
+    throws Exception {
+
+    String newString;
+
+    if (options == null)
+      return "";
+    for (int i = 0; i < options.length; i++) {
+      if ((options[i].length() > 0) && (options[i].charAt(0) == '-')) {
+	
+	// Check if it is a negative number
+	try {
+	  Double dummy = Double.valueOf(options[i]);
+	} catch (NumberFormatException e) {
+	  if (options[i].length() > 2) {
+	    throw new Exception("Illegal option: " + options[i]);
+	  }
+	  if (options[i].charAt(1) == flag) {
+	    if (i + 1 == options.length) {
+	      throw new Exception("No value given for -" + flag + " option.");
+	    }
+	    options[i] = "";
+	    newString = new String(options[i + 1]);
+	    options[i + 1] = "";
+	    return newString;
+	  }
+	  if (options[i].charAt(1) == '-') {
+	    return "";
+	  }
+	}
+      }
+    }
+    return "";
+  }
+
+  /**
+   * Quotes a string if it contains special characters.
+   * 
+   * The following rules are applied:
+   *
+   * A character is backquoted version of it is one 
+   * of <tt>" ' % \ \n \r \t</tt>.
+   *
+   * A string is enclosed within single quotes if a character has been
+   * backquoted using the previous rule above or contains 
+   * <tt>{ }</tt> or is exactly equal to the strings 
+   * <tt>, ? space or ""</tt> (empty string).
+   *
+   * A quoted question mark distinguishes it from the missing value which
+   * is represented as an unquoted question mark in arff files.
+   *
+   * @param string the string to be quoted
+   * @return the string (possibly quoted)
+   */
+  public static String quote(String string) {
+      boolean quote = false;
+
+      // backquote the following characters 
+      if ((string.indexOf('\n') != -1) || (string.indexOf('\r') != -1) || 
+	  (string.indexOf('\'') != -1) || (string.indexOf('"') != -1) || 
+	  (string.indexOf('\\') != -1) || 
+	  (string.indexOf('\t') != -1) || (string.indexOf('%') != -1)) {
+	  string = backQuoteChars(string);
+	  quote = true;
+      }
+
+      // Enclose the string in 's if the string contains a recently added
+      // backquote or contains one of the following characters.
+      if((quote == true) || 
+	 (string.indexOf('{') != -1) || (string.indexOf('}') != -1) ||
+	 (string.indexOf(',') != -1) || (string.equals("?")) ||
+	 (string.indexOf(' ') != -1) || (string.equals(""))) {
+	  string = ("'".concat(string)).concat("'");
+      }
+
+      return string;
+  }
+
+  /**
+   * Converts carriage returns and new lines in a string into \r and \n.
+   * Backquotes the following characters: ` " \ \t and %
+   * @param string the string
+   * @return the converted string
+   */
+  public static String backQuoteChars(String string) {
+
+    int index;
+    StringBuffer newStringBuffer;
+
+    // replace each of the following characters with the backquoted version
+    char   charsFind[] =    {'\\',   '\'',  '\t',  '"',    '%'};
+    String charsReplace[] = {"\\\\", "\\'", "\\t", "\\\"", "\\%"};
+    for(int i = 0; i < charsFind.length; i++) {
+	if (string.indexOf(charsFind[i]) != -1 ) {
+	    newStringBuffer = new StringBuffer();
+	    while ((index = string.indexOf(charsFind[i])) != -1) {
+		if (index > 0) {
+		    newStringBuffer.append(string.substring(0, index));
+		}
+		newStringBuffer.append(charsReplace[i]);
+		if ((index + 1) < string.length()) {
+		    string = string.substring(index + 1);
+		} else {
+		    string = "";
+		}
+	    }
+	    newStringBuffer.append(string);
+	    string = newStringBuffer.toString();
+	}
+    }
+
+    return Utils.convertNewLines(string);
+  }
+
+  /**
+   * Converts carriage returns and new lines in a string into \r and \n.
+   * @param string the string
+   * @return the converted string
+   */
+  public static String convertNewLines(String string) {
+    
+    int index;
+
+    // Replace with \n
+    StringBuffer newStringBuffer = new StringBuffer();
+    while ((index = string.indexOf('\n')) != -1) {
+      if (index > 0) {
+	newStringBuffer.append(string.substring(0, index));
+      }
+      newStringBuffer.append('\\');
+      newStringBuffer.append('n');
+      if ((index + 1) < string.length()) {
+	string = string.substring(index + 1);
+      } else {
+	string = "";
+      }
+    }
+    newStringBuffer.append(string);
+    string = newStringBuffer.toString();
+
+    // Replace with \r
+    newStringBuffer = new StringBuffer();
+    while ((index = string.indexOf('\r')) != -1) {
+      if (index > 0) {
+	newStringBuffer.append(string.substring(0, index));
+      }
+      newStringBuffer.append('\\');
+      newStringBuffer.append('r');
+      if ((index + 1) < string.length()){
+	string = string.substring(index + 1);
+      } else {
+	string = "";
+      }
+    }
+    newStringBuffer.append(string);
+    return newStringBuffer.toString();
+  }
+    
+
+  /**
+   * Returns the secondary set of options (if any) contained in
+   * the supplied options array. The secondary set is defined to
+   * be any options after the first "--". These options are removed from
+   * the original options array.
+   *
+   * @param options the input array of options
+   * @return the array of secondary options
+   */
+  public static String [] partitionOptions(String [] options) {
+
+    for (int i = 0; i < options.length; i++) {
+      if (options[i].equals("--")) {
+	options[i++] = "";
+	String [] result = new String [options.length - i];
+	for (int j = i; j < options.length; j++) {
+	  result[j - i] = options[j];
+	  options[j] = "";
+	}
+	return result;
+      }
+    }
+    return new String [0];
+  }
+
+  /**
+   * Split up a string containing options into an array of strings,
+   * one for each option.
+   *
+   * @param optionString the string containing the options
+   * @return the array of options
+   */
+  public static String [] splitOptions(String optionString) {
+
+    FastVector optionsVec = new FastVector();
+    StringTokenizer st = new StringTokenizer(optionString);
+    while (st.hasMoreTokens())
+      optionsVec.addElement(st.nextToken());
+
+    String [] options = new String[optionsVec.size()];
+    for (int i = 0; i < optionsVec.size(); i++) {
+      options[i] = (String)optionsVec.elementAt(i);
+    }
+    return options;
+  }
+
+  /**
+   * Joins all the options in an option array into a single string,
+   * as might be used on the command line.
+   *
+   * @param optionArray the array of options
+   * @return the string containing all options.
+   */
+  public static String joinOptions(String [] optionArray) {
+
+    String optionString = "";
+    for (int i = 0; i < optionArray.length; i++) {
+      if (optionArray[i].equals("")) {
+	continue;
+      }
+      if (optionArray[i].indexOf(' ') != -1) {
+	optionString += '"' + optionArray[i] + '"';
+      } else {
+	optionString += optionArray[i];
+      }
+      optionString += " ";
+    }
+    return optionString.trim();
+  }
+  
+  /**
+   * Creates a new instance of an object given it's class name and
+   * (optional) arguments to pass to it's setOptions method. If the
+   * object implements OptionHandler and the options parameter is
+   * non-null, the object will have it's options set. Example use:<p>
+   *
+   * <code> <pre>
+   * String classifierName = Utils.getOption('W', options);
+   * Classifier c = (Classifier)Utils.forName(Classifier.class,
+   *                                          classifierName,
+   *                                          options);
+   * setClassifier(c);
+   * </pre></code>
+   *
+   * @param classType the class that the instantiated object should
+   * be assignable to -- an exception is thrown if this is not the case
+   * @param className the fully qualified class name of the object
+   * @param options an array of options suitable for passing to setOptions. May
+   * be null. Any options accepted by the object will be removed from the
+   * array.
+   * @return the newly created object, ready for use.
+   * @exception Exception if the class name is invalid, or if the
+   * class is not assignable to the desired class type, or the options
+   * supplied are not acceptable to the object
+   */
+  public static Object forName(Class classType,
+			       String className,
+			       String [] options) throws Exception {
+
+    Class c = null;
+    try {
+      c = Class.forName(className);
+    } catch (Exception ex) {
+      throw new Exception("Can't find class called: " + className);
+    }
+    if (!classType.isAssignableFrom(c)) {
+      throw new Exception(classType.getName() + " is not assignable from "
+			  + className);
+    }
+    Object o = c.newInstance();
+    if ((o instanceof OptionHandler)
+	&& (options != null)) {
+      ((OptionHandler)o).setOptions(options);
+      Utils.checkForRemainingOptions(options);
+    }
+    return o;
+  }
+
+  /**
+   * Computes entropy for an array of integers.
+   *
+   * @param counts array of counts
+   * @returns - a log2 a - b log2 b - c log2 c + (a+b+c) log2 (a+b+c)
+   * when given array [a b c]
+   */
+  public static double info(int counts[]) {
+    
+    int total = 0; int c;
+    double x = 0;
+    for (int j = 0; j < counts.length; j++) {
+      x -= xlogx(counts[j]);
+      total += counts[j];
+    }
+    return x + xlogx(total);
+  }
+
+  /**
+   * Tests if a is smaller or equal to b.
+   *
+   * @param a a double
+   * @param b a double
+   */
+  public static boolean smOrEq(double a,double b) {
+    
+    return (a-b < SMALL);
+  }
+
+  /**
+   * Tests if a is greater or equal to b.
+   *
+   * @param a a double
+   * @param b a double
+   */
+  public static boolean grOrEq(double a,double b) {
+    
+    return (b-a < SMALL);
+  }
+  
+  /**
+   * Tests if a is smaller than b.
+   *
+   * @param a a double
+   * @param b a double
+   */
+  public static boolean sm(double a,double b) {
+    
+    return (b-a > SMALL);
+  }
+
+  /**
+   * Tests if a is smaller than b.
+   *
+   * @param a a double
+   * @param b a double 
+   */
+  public static boolean gr(double a,double b) {
+    
+    return (a-b > SMALL);
+  }
+
+  /**
+   * Returns the logarithm of a for base 2.
+   *
+   * @param a a double
+   */
+  public static double log2(double a) {
+    
+    return Math.log(a) / log2;
+  }
+
+  /**
+   * Returns index of maximum element in a given
+   * array of doubles. First maximum is returned.
+   *
+   * @param doubles the array of doubles
+   * @return the index of the maximum element
+   */
+  public static int maxIndex(double [] doubles) {
+
+    double maximum = 0;
+    int maxIndex = 0;
+
+    for (int i = 0; i < doubles.length; i++) {
+      if ((i == 0) || (doubles[i] > maximum)) {
+	maxIndex = i;
+	maximum = doubles[i];
+      }
+    }
+
+    return maxIndex;
+  }
+
+  /**
+   * Returns index of maximum element in a given
+   * array of integers. First maximum is returned.
+   *
+   * @param ints the array of integers
+   * @return the index of the maximum element
+   */
+  public static int maxIndex(int [] ints) {
+
+    int maximum = 0;
+    int maxIndex = 0;
+
+    for (int i = 0; i < ints.length; i++) {
+      if ((i == 0) || (ints[i] > maximum)) {
+	maxIndex = i;
+	maximum = ints[i];
+      }
+    }
+
+    return maxIndex;
+  }
+
+  /**
+   * Computes the mean for an array of doubles.
+   *
+   * @param vector the array
+   * @return the mean
+   */
+  public static double mean(double[] vector) {
+  
+    double sum = 0;
+
+    if (vector.length == 0) {
+      return 0;
+    }
+    for (int i = 0; i < vector.length; i++) {
+      sum += vector[i];
+    }
+    return sum / (double) vector.length;
+  }
+
+  /**
+   * Returns index of minimum element in a given
+   * array of integers. First minimum is returned.
+   *
+   * @param ints the array of integers
+   * @return the index of the minimum element
+   */
+  public static int minIndex(int [] ints) {
+
+    int minimum = 0;
+    int minIndex = 0;
+
+    for (int i = 0; i < ints.length; i++) {
+      if ((i == 0) || (ints[i] < minimum)) {
+	minIndex = i;
+	minimum = ints[i];
+      }
+    }
+
+    return minIndex;
+  }
+
+  /**
+   * Returns index of minimum element in a given
+   * array of doubles. First minimum is returned.
+   *
+   * @param doubles the array of doubles
+   * @return the index of the minimum element
+   */
+  public static int minIndex(double [] doubles) {
+
+    double minimum = 0;
+    int minIndex = 0;
+
+    for (int i = 0; i < doubles.length; i++) {
+      if ((i == 0) || (doubles[i] < minimum)) {
+	minIndex = i;
+	minimum = doubles[i];
+      }
+    }
+
+    return minIndex;
+  }
+
+  /**
+   * Normalizes the doubles in the array by their sum.
+   *
+   * @param doubles the array of double
+   * @exception IllegalArgumentException if sum is Zero or NaN
+   */
+  public static void normalize(double[] doubles) {
+
+    double sum = 0;
+    for (int i = 0; i < doubles.length; i++) {
+      sum += doubles[i];
+    }
+    normalize(doubles, sum);
+  }
+
+  /**
+   * Normalizes the doubles in the array using the given value.
+   *
+   * @param doubles the array of double
+   * @param sum the value by which the doubles are to be normalized
+   * @exception IllegalArgumentException if sum is zero or NaN
+   */
+  public static void normalize(double[] doubles, double sum) {
+
+    if (Double.isNaN(sum)) {
+      throw new IllegalArgumentException("Can't normalize array. Sum is NaN.");
+    }
+    if (sum == 0) {
+      // Maybe this should just be a return.
+      throw new IllegalArgumentException("Can't normalize array. Sum is zero.");
+    }
+    for (int i = 0; i < doubles.length; i++) {
+      doubles[i] /= sum;
+    }
+  }
+
+  /**
+   * Rounds a double to the next nearest integer value. The JDK version
+   * of it doesn't work properly.
+   *
+   * @param value the double value
+   * @return the resulting integer value
+   */
+  public static int round(double value) {
+
+    int roundedValue = value > 0
+      ? (int)(value + 0.5)
+      : -(int)(Math.abs(value) + 0.5);
+    
+    return roundedValue;
+  }
+
+  /**
+   * Rounds a double to the given number of decimal places.
+   *
+   * @param value the double value
+   * @param afterDecimalPoint the number of digits after the decimal point
+   * @return the double rounded to the given precision
+   */
+  public static double roundDouble(double value,int afterDecimalPoint) {
+
+    double mask = Math.pow(10.0, (double)afterDecimalPoint);
+
+    return (double)(Math.round(value * mask)) / mask;
+  }
+
+  /**
+   * Sorts a given array of integers in ascending order and returns an 
+   * array of integers with the positions of the elements of the original 
+   * array in the sorted array. The sort is stable. (Equal elements remain
+   * in their original order.)
+   *
+   * @param array this array is not changed by the method!
+   * @return an array of integers with the positions in the sorted
+   * array.
+   */
+  public static int[] sort(int [] array) {
+
+    int [] index = new int[array.length];
+    int [] newIndex = new int[array.length];
+    int [] helpIndex;
+    int numEqual;
+    
+    for (int i = 0; i < index.length; i++) {
+      index[i] = i;
+    }
+    quickSort(array, index, 0, array.length - 1);
+
+    // Make sort stable
+    int i = 0;
+    while (i < index.length) {
+      numEqual = 1;
+      for (int j = i + 1; ((j < index.length)
+			   && (array[index[i]] == array[index[j]]));
+	   j++) {
+	numEqual++;
+      }
+      if (numEqual > 1) {
+	helpIndex = new int[numEqual];
+	for (int j = 0; j < numEqual; j++) {
+	  helpIndex[j] = i + j;
+	}
+	quickSort(index, helpIndex, 0, numEqual - 1);
+	for (int j = 0; j < numEqual; j++) {
+	  newIndex[i + j] = index[helpIndex[j]];
+	}
+	i += numEqual;
+      } else {
+	newIndex[i] = index[i];
+	i++;
+      }
+    }
+    return newIndex;
+  }
+
+  /**
+   * Sorts a given array of doubles in ascending order and returns an
+   * array of integers with the positions of the elements of the
+   * original array in the sorted array. NOTE THESE CHANGES: the sort
+   * is no longer stable and it doesn't use safe floating-point
+   * comparisons anymore. Occurrences of Double.NaN are treated as 
+   * Double.MAX_VALUE
+   *
+   * @param array this array is not changed by the method!
+   * @return an array of integers with the positions in the sorted
+   * array.  
+   */
+  public static int[] sort(double [] array) {
+
+    int [] index = new int[array.length];
+    array = (double [])array.clone();
+    for (int i = 0; i < index.length; i++) {
+      index[i] = i;
+      if (Double.isNaN(array[i])) {
+        array[i] = Double.MAX_VALUE;
+      }
+    }
+    quickSort(array, index, 0, array.length - 1);
+    return index;
+  }
+
+  /**
+   * Sorts a given array of doubles in ascending order and returns an 
+   * array of integers with the positions of the elements of the original 
+   * array in the sorted array. The sort is stable (Equal elements remain
+   * in their original order.) Occurrences of Double.NaN are treated as 
+   * Double.MAX_VALUE
+   *
+   * @param array this array is not changed by the method!
+   * @return an array of integers with the positions in the sorted
+   * array.
+   */
+  public static int[] stableSort(double [] array){
+
+    int [] index = new int[array.length];
+    int [] newIndex = new int[array.length];
+    int [] helpIndex;
+    int numEqual;
+    
+    array = (double [])array.clone();
+    for (int i = 0; i < index.length; i++) {
+      index[i] = i;
+      if (Double.isNaN(array[i])) {
+        array[i] = Double.MAX_VALUE;
+      }
+    }
+    quickSort(array,index,0,array.length-1);
+
+    // Make sort stable
+
+    int i = 0;
+    while (i < index.length) {
+      numEqual = 1;
+      for (int j = i+1; ((j < index.length) && Utils.eq(array[index[i]],
+							array[index[j]])); j++)
+	numEqual++;
+      if (numEqual > 1) {
+	helpIndex = new int[numEqual];
+	for (int j = 0; j < numEqual; j++)
+	  helpIndex[j] = i+j;
+	quickSort(index, helpIndex, 0, numEqual-1);
+	for (int j = 0; j < numEqual; j++) 
+	  newIndex[i+j] = index[helpIndex[j]];
+	i += numEqual;
+      } else {
+	newIndex[i] = index[i];
+	i++;
+      }
+    }
+
+    return newIndex;
+  }
+
+  /**
+   * Computes the variance for an array of doubles.
+   *
+   * @param vector the array
+   * @return the variance
+   */
+  public static double variance(double[] vector) {
+  
+    double sum = 0, sumSquared = 0;
+
+    if (vector.length <= 1) {
+      return 0;
+    }
+    for (int i = 0; i < vector.length; i++) {
+      sum += vector[i];
+      sumSquared += (vector[i] * vector[i]);
+    }
+    return (sumSquared - (sum * sum / (double) vector.length)) / 
+      (double) (vector.length - 1);
+  }
+
+  /**
+   * Computes the sum of the elements of an array of doubles.
+   *
+   * @param doubles the array of double
+   * @returns the sum of the elements
+   */
+  public static double sum(double[] doubles) {
+
+    double sum = 0;
+
+    for (int i = 0; i < doubles.length; i++) {
+      sum += doubles[i];
+    }
+    return sum;
+  }
+
+  /**
+   * Computes the sum of the elements of an array of integers.
+   *
+   * @param ints the array of integers
+   * @returns the sum of the elements
+   */
+  public static int sum(int[] ints) {
+
+    int sum = 0;
+
+    for (int i = 0; i < ints.length; i++) {
+      sum += ints[i];
+    }
+    return sum;
+  }
+
+  /**
+   * Returns c*log2(c) for a given integer value c.
+   *
+   * @param c an integer value
+   * @returns c*log2(c) (but is careful to return 0 if c is 0)
+   */
+  public static double xlogx(int c) {
+    
+    if (c == 0) {
+      return 0.0;
+    }
+    return c * Utils.log2((double) c);
+  }
+
+  /**
+   * Implements quicksort for an array of indices.
+   *
+   * @param array the array of integers to be sorted
+   * @param index the index which should contain the positions in the
+   * sorted array
+   * @param lo0 the first index of the subset to be sorted
+   * @param hi0 the last index of the subset to be sorted
+   */
+  private static void quickSort(int [] array, int [] index,
+				int lo0, int hi0) {
+
+    int lo = lo0;
+    int hi = hi0;
+    int mid;
+    int help;
+    
+    if (hi0 > lo0) {
+      
+      // Arbitrarily establishing partition element as the midpoint of
+      // the array.
+      mid = array[index[(lo0 + hi0) / 2]];
+
+      // loop through the array until indices cross
+      while (lo <= hi) {
+	
+	// find the first element that is greater than or equal to  
+	// the partition element starting from the left Index.
+	while ((array[index[lo]] < mid) && (lo < hi0)) {
+	  ++lo;
+	}
+	
+	// find an element that is smaller than or equal to 
+	// the partition element starting from the right Index.
+	while ((array[index[hi]] > mid) && (hi > lo0)) {
+	  --hi;
+	}
+	
+	// if the indexes have not crossed, swap
+	if (lo <= hi) {
+	  help = index[lo];
+	  index[lo] = index[hi];
+	  index[hi] = help;
+	  ++lo;
+	  --hi;
+	}
+      }
+      
+      // If the right index has not reached the left side of array
+      // must now sort the left partition.
+      if (lo0 < hi) {
+	quickSort(array, index, lo0, hi);
+      }
+      
+      // If the left index has not reached the right side of array
+      // must now sort the right partition.
+      if (lo < hi0) {
+	quickSort(array, index, lo, hi0);
+      }
+    }
+  }
+
+  /**
+   * Implements unsafe quicksort for an array of indices.
+   *
+   * @param array the array of doubles to be sorted
+   * @param index the index which should contain the positions in the
+   * sorted array
+   * @param lo0 the first index of the subset to be sorted
+   * @param hi0 the last index of the subset to be sorted
+   */
+  private static void quickSort(double [] array, int [] index, int lo0, int hi0) {
+
+    int lo = lo0;
+    int hi = hi0;
+    double mid;
+    int help;
+    
+    if (hi0 > lo0) {
+      
+      // Arbitrarily establishing partition element as the midpoint of
+      // the array.
+      mid = array[index[(lo0 + hi0) / 2]];
+
+      // loop through the array until indices cross
+      while (lo <= hi) {
+	
+	// find the first element that is greater than or equal to  
+	// the partition element starting from the left Index.
+	while ((array[index[lo]] < mid) && (lo < hi0)) {
+	  ++lo;
+	}
+	
+	// find an element that is smaller than or equal to 
+	// the partition element starting from the right Index.
+	while ((array[index[hi]] > mid) && (hi > lo0)) {
+	  --hi;
+	}
+	
+	// if the indexes have not crossed, swap
+	if (lo <= hi) {
+	  help = index[lo];
+	  index[lo] = index[hi];
+	  index[hi] = help;
+	  ++lo;
+	  --hi;
+	}
+      }
+      
+      // If the right index has not reached the left side of array
+      // must now sort the left partition.
+      if (lo0 < hi) {
+	quickSort(array, index, lo0, hi);
+      }
+      
+      // If the left index has not reached the right side of array
+      // must now sort the right partition.
+      if (lo < hi0) {
+	quickSort(array, index, lo, hi0);
+      }
+    }
+  }
+
+  /**
+   * Main method for testing this class.
+   *
+   * @param ops some dummy options
+   */
+  public static void main(String[] ops) {
+
+    double[] doubles = {4.5, 6.7, Double.NaN, 3.4, 4.8, 1.2, 3.4};
+    int[] ints = {12, 6, 2, 18, 16, 6, 7, 5};
+
+    try {
+
+      // Option handling
+      System.out.println("First option split up:");
+      if (ops.length > 0) {
+	String[] firstOptionSplitUp = Utils.splitOptions(ops[0]);
+	for (int i = 0; i < firstOptionSplitUp.length; i ++) {
+	  System.out.println(firstOptionSplitUp[i]);
+	}
+      }					       
+      System.out.println("Partitioned options: ");
+      String[] partitionedOptions = Utils.partitionOptions(ops);
+      for (int i  = 0; i < partitionedOptions.length; i++) {
+	System.out.println(partitionedOptions[i]);
+      }
+      System.out.println("Get flag -f: " + Utils.getFlag('f', ops));
+      System.out.println("Get option -o: " + Utils.getOption('o', ops));
+      System.out.println("Checking for remaining options... ");
+      Utils.checkForRemainingOptions(ops);
+      
+      // Statistics
+      System.out.println("Original array (doubles): ");
+      for (int i = 0; i < doubles.length; i++) {
+	System.out.print(doubles[i] + " ");
+      }
+      System.out.println();
+      System.out.println("Original array (ints): ");
+      for (int i = 0; i < ints.length; i++) {
+	System.out.print(ints[i] + " ");
+      }
+      System.out.println();
+      System.out.println("Correlation: " + Utils.correlation(doubles, doubles, 
+							     doubles.length));
+      System.out.println("Mean: " + Utils.mean(doubles));
+      System.out.println("Variance: " + Utils.variance(doubles));
+      System.out.println("Sum (doubles): " + Utils.sum(doubles));
+      System.out.println("Sum (ints): " + Utils.sum(ints));
+      System.out.println("Max index (doubles): " + Utils.maxIndex(doubles));
+      System.out.println("Max index (ints): " + Utils.maxIndex(ints));
+      System.out.println("Min index (doubles): " + Utils.minIndex(doubles));
+      System.out.println("Min index (ints): " + Utils.minIndex(ints));
+      
+      // Sorting and normalizing
+      System.out.println("Sorted array (doubles): ");
+      int[] sorted = Utils.sort(doubles);
+      for (int i = 0; i < doubles.length; i++) {
+	System.out.print(doubles[sorted[i]] + " ");
+      }
+      System.out.println();
+      System.out.println("Normalized array (doubles): ");
+      Utils.normalize(doubles);
+      for (int i = 0; i < doubles.length; i++) {
+	System.out.print(doubles[i] + " ");
+      }
+      System.out.println();
+      System.out.println("Normalized again (doubles): ");
+      Utils.normalize(doubles, Utils.sum(doubles));
+      for (int i = 0; i < doubles.length; i++) {
+	System.out.print(doubles[i] + " ");
+      }
+      System.out.println();
+      
+      // Pretty-printing
+      System.out.println("-4.58: " + Utils.doubleToString(-4.57826535, 2));
+      System.out.println("-6.78: " + Utils.doubleToString(-6.78214234, 6,2));
+      
+      // Comparisons
+      System.out.println("5.70001 == 5.7 ? " + Utils.eq(5.70001, 5.7));
+      System.out.println("5.70001 > 5.7 ? " + Utils.gr(5.70001, 5.7));
+      System.out.println("5.70001 >= 5.7 ? " + Utils.grOrEq(5.70001, 5.7));
+      System.out.println("5.7 < 5.70001 ? " + Utils.sm(5.7, 5.70001));
+      System.out.println("5.7 <= 5.70001 ? " + Utils.smOrEq(5.7, 5.70001));
+      
+      // Math
+      System.out.println("Info (ints): " + Utils.info(ints));
+      System.out.println("log2(4.6): " + Utils.log2(4.6));
+      System.out.println("5 * log(5): " + Utils.xlogx(5));
+      System.out.println("5.5 rounded: " + Utils.round(5.5));
+      System.out.println("5.55555 rounded to 2 decimal places: " + 
+			 Utils.roundDouble(5.55555, 2));
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
+  
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/WeightedInstancesHandler.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/WeightedInstancesHandler.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/WeightedInstancesHandler.java	(revision 10506)
@@ -0,0 +1,43 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    WeightedInstancesHandler.java
+ *    Copyright (C) 1999 Eibe Frank
+ *
+ */
+
+package weka.core;
+
+/** 
+ * Interface to something that makes use of the information provided
+ * by instance weights.
+ *
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$ 
+*/
+public interface WeightedInstancesHandler {
+
+  // Nothing in here, because the class is just used as an indicator
+}
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/WekaException.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/WekaException.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/core/WekaException.java	(revision 10506)
@@ -0,0 +1,50 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    WekaException.java
+ *    Copyright (C) 2001 Webmind Corp.
+ */
+
+package weka.core;
+
+/**
+ * <code>WekaException</code> is used when some Weka-specific
+ * checked exception must be raised.
+ *
+ * @author <a href="mailto:len@webmind.com">Len Trigg</a>
+ * @version $Revision$
+ */
+public class WekaException extends Exception {
+
+  /**
+   * Creates a new <code>WekaException</code> instance
+   * with no detail message.
+   */
+  public WekaException() { 
+    super(); 
+  }
+
+  /**
+   * Creates a new <code>WekaException</code> instance
+   * with a specified message.
+   *
+   * @param messagae a <code>String</code> containing the message.
+   */
+  public WekaException(String message) { 
+    super(message); 
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/experiment/Stats.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/experiment/Stats.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/experiment/Stats.java	(revision 10506)
@@ -0,0 +1,188 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    Stats.java
+ *    Copyright (C) 1999 Len Trigg
+ *
+ */
+
+
+package weka.experiment;
+import weka.core.Utils;
+
+/**
+ * A class to store simple statistics
+ *
+ * @author Len Trigg (trigg@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public class Stats {
+  
+  /** The number of values seen */
+  public double count = 0;
+
+  /** The sum of values seen */
+  public double sum = 0;
+
+  /** The sum of values squared seen */
+  public double sumSq = 0;
+
+  /** The std deviation of values at the last calculateDerived() call */    
+  public double stdDev = Double.NaN;
+
+  /** The mean of values at the last calculateDerived() call */    
+  public double mean = Double.NaN;
+
+  /** The minimum value seen, or Double.NaN if no values seen */
+  public double min = Double.NaN;
+
+  /** The maximum value seen, or Double.NaN if no values seen */
+  public double max = Double.NaN;
+    
+  /**
+   * Adds a value to the observed values
+   *
+   * @param value the observed value
+   */
+  public void add(double value) {
+
+    add(value, 1);
+  }
+
+  /**
+   * Adds a value that has been seen n times to the observed values
+   *
+   * @param value the observed value
+   * @param n the number of times to add value
+   */
+  public void add(double value, double n) {
+
+    sum += value * n;
+    sumSq += value * value * n;
+    count += n;
+    if (Double.isNaN(min)) {
+      min = max = value;
+    } else if (value < min) {
+      min = value;
+    } else if (value > max) {
+      max = value;
+    }
+  }
+
+  /**
+   * Removes a value to the observed values (no checking is done
+   * that the value being removed was actually added). 
+   *
+   * @param value the observed value
+   */
+  public void subtract(double value) {
+
+    sum -= value;
+    sumSq -= value * value;
+    count --;
+  }
+
+  /**
+   * Tells the object to calculate any statistics that don't have their
+   * values automatically updated during add. Currently updates the mean
+   * and standard deviation.
+   */
+  public void calculateDerived() {
+
+    mean = Double.NaN;
+    stdDev = Double.NaN;
+    if (count > 0) {
+      mean = sum / count;
+      stdDev = Double.POSITIVE_INFINITY;
+      if (count > 1) {
+	stdDev = sumSq - (sum * sum) / count;
+	stdDev /= (count - 1);
+        if (stdDev < 0) {
+          System.err.println("Warning: stdDev value = " + stdDev 
+                             + " -- rounded to zero.");
+          stdDev = 0;
+        }
+	stdDev = Math.sqrt(stdDev);
+      }
+    }
+  }
+    
+  /**
+   * Returns a string summarising the stats so far.
+   *
+   * @return the summary string
+   */
+  public String toString() {
+
+    calculateDerived();
+    return
+      "Count   " + Utils.doubleToString(count, 8) + '\n'
+      + "Min     " + Utils.doubleToString(min, 8) + '\n'
+      + "Max     " + Utils.doubleToString(max, 8) + '\n'
+      + "Sum     " + Utils.doubleToString(sum, 8) + '\n'
+      + "SumSq   " + Utils.doubleToString(sumSq, 8) + '\n'
+      + "Mean    " + Utils.doubleToString(mean, 8) + '\n'
+      + "StdDev  " + Utils.doubleToString(stdDev, 8) + '\n';
+  }
+
+  /**
+   * Tests the paired stats object from the command line.
+   * reads line from stdin, expecting two values per line.
+   *
+   * @param args ignored.
+   */
+  public static void main(String [] args) {
+
+    try {
+      Stats ps = new Stats();
+      java.io.LineNumberReader r = new java.io.LineNumberReader(
+				   new java.io.InputStreamReader(System.in));
+      String line;
+      while ((line = r.readLine()) != null) {
+        line = line.trim();
+        if (line.equals("") || line.startsWith("@") || line.startsWith("%")) {
+          continue;
+        }
+	java.util.StringTokenizer s 
+          = new java.util.StringTokenizer(line, " ,\t\n\r\f");
+	int count = 0;
+	double v1 = 0;
+	while (s.hasMoreTokens()) {
+	  double val = (new Double(s.nextToken())).doubleValue();
+	  if (count == 0) {
+	    v1 = val;
+	  } else {
+            System.err.println("MSG: Too many values in line \"" 
+                               + line + "\", skipped.");
+	    break;
+	  }
+	  count++;
+	}
+        if (count == 1) {
+          ps.add(v1);
+        }
+      }
+      ps.calculateDerived();
+      System.err.println(ps);
+    } catch (Exception ex) {
+      ex.printStackTrace();
+      System.err.println(ex.getMessage());
+    }
+  }
+
+} // Stats
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/filters/DiscretizeFilter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/filters/DiscretizeFilter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/filters/DiscretizeFilter.java	(revision 10506)
@@ -0,0 +1,1292 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *    DiscretizeFilter.java
+ *    Copyright (C) 1999 Eibe Frank,Len Trigg
+ *
+ */
+
+
+package weka.filters;
+
+import java.io.*;
+import java.util.*;
+import weka.core.*;
+
+/** 
+ * An instance filter that discretizes a range of numeric attributes in 
+ * the dataset into nominal attributes. Discretization can be either by 
+ * simple binning, or by Fayyad & Irani's MDL method (the default).<p>
+ *
+ * Valid filter-specific options are: <p>
+ *
+ * -B num <br>
+ * Specifies the (maximum) number of bins to divide numeric attributes into.
+ * (default: class-based discretisation).<p>
+ *
+ * -F <br>
+ * Use equal-frequency instead of equal-width discretization if 
+ * class-based discretisation is turned off.<p>
+ *
+ * -O <br>
+ * Optimize the number of bins using a leave-one-out estimate of the 
+ * entropy (for equal-width binning).<p>
+ *
+ * -R col1,col2-col4,... <br>
+ * Specifies list of columns to Discretize. First
+ * and last are valid indexes. (default: none) <p>
+ *
+ * -V <br>
+ * Invert matching sense.<p>
+ *
+ * -D <br>
+ * Make binary nominal attributes. <p>
+ *
+ * -E <br>
+ * Use better encoding of split point for MDL. <p>
+ *   
+ * -K <br>
+ * Use Kononeko's MDL criterion. <p>
+ * 
+ * @author Len Trigg (trigg@cs.waikato.ac.nz)
+ * @author Eibe Frank (eibe@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public class DiscretizeFilter extends Filter 
+  implements OptionHandler, WeightedInstancesHandler {
+
+  /** Stores which columns to Discretize */
+  protected Range m_DiscretizeCols = new Range();
+
+  /** The number of bins to divide the attribute into */
+  protected int m_NumBins = 10;
+
+  /** Store the current cutpoints */
+  protected double [][] m_CutPoints = null;
+
+  /** True if discretisation will be done by MDL rather than binning */
+  protected boolean m_UseMDL = true;
+
+  /** Output binary attributes for discretized attributes. */
+  protected boolean m_MakeBinary = false;
+
+  /** Use better encoding of split point for MDL. */
+  protected boolean m_UseBetterEncoding = false;
+
+  /** Use Kononenko's MDL criterion instead of Fayyad et al.'s */
+  protected boolean m_UseKononenko = false;
+
+  /** Find the number of bins using cross-validated entropy. */
+  protected boolean m_FindNumBins = false;
+
+  /** Use equal-frequency binning if unsupervised discretization turned on */
+  protected boolean m_UseEqualFrequency = false;
+
+  /** Constructor - initialises the filter */
+  public DiscretizeFilter() {
+
+    setAttributeIndices("first-last");
+  }
+
+
+  /**
+   * Gets an enumeration describing the available options
+   *
+   * @return an enumeration of all the available options
+   */
+  public Enumeration listOptions() {
+
+    Vector newVector = new Vector(7);
+
+    newVector.addElement(new Option(
+              "\tSpecifies the (maximum) number of bins to divide numeric"
+	      + " attributes into.\n"
+	      + "\t(default class-based discretization)",
+              "B", 1, "-B <num>"));
+
+    newVector.addElement(new Option(
+              "\tUse equal-frequency instead of equal-width with\n"+
+	      "\tunsupervised discretization.",
+              "F", 0, "-F"));
+
+    newVector.addElement(new Option(
+              "\tOptimize number of bins using leave-one-out estimate\n"+
+	      "\tof estimated entropy (for equal-width discretization).",
+              "O", 0, "-O"));
+
+    /* If we decide to implement loading and saving cutfiles like 
+     * the C Discretizer (which is probably not necessary)
+    newVector.addElement(new Option(
+              "\tSpecify that the cutpoints should be loaded from a file.",
+              "L", 1, "-L <file>"));
+    newVector.addElement(new Option(
+              "\tSpecify that the chosen cutpoints should be saved to a file.",
+              "S", 1, "-S <file>"));
+    */
+
+    newVector.addElement(new Option(
+              "\tSpecifies list of columns to Discretize. First"
+	      + " and last are valid indexes.\n"
+	      + "\t(default none)",
+              "R", 1, "-R <col1,col2-col4,...>"));
+
+    newVector.addElement(new Option(
+              "\tInvert matching sense of column indexes.",
+              "V", 0, "-V"));
+
+    newVector.addElement(new Option(
+              "\tOutput binary attributes for discretized attributes.",
+              "D", 0, "-D"));
+
+    newVector.addElement(new Option(
+              "\tUse better encoding of split point for MDL.",
+              "E", 0, "-E"));
+
+    newVector.addElement(new Option(
+              "\tUse Kononenko's MDL criterion.",
+              "K", 0, "-K"));
+
+    return newVector.elements();
+  }
+
+
+  /**
+   * Parses the options for this object. Valid options are: <p>
+   *
+   * -B num <br>
+   * Specifies the (maximum) number of bins to divide numeric attributes into.
+   * (default class-based discretisation).<p>
+   *
+   * -F <br>
+   * Use equal-frequency instead of equal-width discretization if 
+   * class-based discretisation is turned off.<p>
+   *
+   * -O <br>
+   * Optimize the number of bins using a leave-one-out estimate of the 
+   * entropy (for equal-width binning).<p>
+   *
+   * -R col1,col2-col4,... <br>
+   * Specifies list of columns to Discretize. First
+   * and last are valid indexes. (default none) <p>
+   *
+   * -V <br>
+   * Invert matching sense.<p>
+   *
+   * -D <br>
+   * Make binary nominal attributes. <p>
+   *
+   * -E <br>
+   * Use better encoding of split point for MDL. <p>
+   *   
+   * -K <br>
+   * Use Kononeko's MDL criterion. <p>
+   * 
+   * @param options the list of options as an array of strings
+   * @exception Exception if an option is not supported
+   */
+  public void setOptions(String[] options) throws Exception {
+
+    setMakeBinary(Utils.getFlag('D', options));
+    setUseEqualFrequency(Utils.getFlag('F', options));
+    setUseBetterEncoding(Utils.getFlag('E', options));
+    setUseKononenko(Utils.getFlag('K', options));
+    setFindNumBins(Utils.getFlag('O', options));
+    setInvertSelection(Utils.getFlag('V', options));
+    setUseMDL(true);
+
+    String numBins = Utils.getOption('B', options);
+    if (numBins.length() != 0) {
+      setBins(Integer.parseInt(numBins));
+      setUseMDL(false);
+    } else {
+      setBins(10);
+    }
+    
+    String convertList = Utils.getOption('R', options);
+    if (convertList.length() != 0) {
+      setAttributeIndices(convertList);
+    } else {
+      setAttributeIndices("first-last");
+    }
+
+    if (getInputFormat() != null) {
+      setInputFormat(getInputFormat());
+    }
+  }
+  /**
+   * Gets the current settings of the filter.
+   *
+   * @return an array of strings suitable for passing to setOptions
+   */
+  public String [] getOptions() {
+
+    String [] options = new String [12];
+    int current = 0;
+
+    if (getMakeBinary()) {
+      options[current++] = "-D";
+    }
+    if (getUseEqualFrequency()) {
+      options[current++] = "-F";
+    }
+    if (getUseBetterEncoding()) {
+      options[current++] = "-E";
+    }
+    if (getUseKononenko()) {
+      options[current++] = "-K";
+    }
+    if (getFindNumBins()) {
+      options[current++] = "-O";
+    }
+    if (getInvertSelection()) {
+      options[current++] = "-V";
+    }
+    if (!getUseMDL()) {
+      options[current++] = "-B"; options[current++] = "" + getBins();
+    }
+    if (!getAttributeIndices().equals("")) {
+      options[current++] = "-R"; options[current++] = getAttributeIndices();
+    }
+    while (current < options.length) {
+      options[current++] = "";
+    }
+    return options;
+  }
+
+
+  /**
+   * Sets the format of the input instances.
+   *
+   * @param instanceInfo an Instances object containing the input instance
+   * structure (any instances contained in the object are ignored - only the
+   * structure is required).
+   * @return true if the outputFormat may be collected immediately
+   * @exception Exception if the input format can't be set successfully
+   */
+  public boolean setInputFormat(Instances instanceInfo) throws Exception {
+
+    super.setInputFormat(instanceInfo);
+
+    m_DiscretizeCols.setUpper(instanceInfo.numAttributes() - 1);
+    m_CutPoints = null;
+    if (m_UseMDL) {
+      if (instanceInfo.classIndex() < 0) {
+	throw new UnassignedClassException("Cannot use class-based discretization: "
+                                           + "no class assigned to the dataset");
+      }
+      if (!instanceInfo.classAttribute().isNominal()) {
+	throw new UnsupportedClassTypeException("Supervised discretization not possible:"
+                                                + " class is not nominal!");
+      }
+    } else {
+      if (getFindNumBins() && getUseEqualFrequency()) {
+	throw new IllegalArgumentException("Bin number optimization in conjunction "+
+					   "with equal-frequency binning not implemented.");
+      }
+    }
+
+    // If we implement loading cutfiles, then load 
+    //them here and set the output format
+    return false;
+  }
+
+  
+
+  /**
+   * Input an instance for filtering. Ordinarily the instance is processed
+   * and made available for output immediately. Some filters require all
+   * instances be read before producing output.
+   *
+   * @param instance the input instance
+   * @return true if the filtered instance may now be
+   * collected with output().
+   * @exception IllegalStateException if no input format has been defined.
+   */
+  public boolean input(Instance instance) {
+
+    if (getInputFormat() == null) {
+      throw new IllegalStateException("No input instance format defined");
+    }
+    if (m_NewBatch) {
+      resetQueue();
+      m_NewBatch = false;
+    }
+    
+    if (m_CutPoints != null) {
+      convertInstance(instance);
+      return true;
+    }
+
+    bufferInput(instance);
+    return false;
+  }
+
+
+  /**
+   * Signifies that this batch of input to the filter is finished. If the 
+   * filter requires all instances prior to filtering, output() may now 
+   * be called to retrieve the filtered instances.
+   *
+   * @return true if there are instances pending output
+   * @exception IllegalStateException if no input structure has been defined
+   */
+  public boolean batchFinished() {
+
+    if (getInputFormat() == null) {
+      throw new IllegalStateException("No input instance format defined");
+    }
+    if (m_CutPoints == null) {
+      calculateCutPoints();
+
+      setOutputFormat();
+
+      // If we implement saving cutfiles, save the cuts here
+
+      // Convert pending input instances
+      for(int i = 0; i < getInputFormat().numInstances(); i++) {
+	convertInstance(getInputFormat().instance(i));
+      }
+    } 
+    flushInput();
+
+    m_NewBatch = true;
+    return (numPendingOutput() != 0);
+  }
+
+  /**
+   * Returns a string describing this filter
+   *
+   * @return a description of the filter suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String globalInfo() {
+
+    return "An instance filter that discretizes a range of numeric"
+      + " attributes in the dataset into nominal attributes."
+      + " Discretization can be either by simple binning, or by"
+      + " Fayyad & Irani's MDL method (the default).";
+  }
+  
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String findNumBinsTipText() {
+
+    return "Optimize number of equal-width bins using leave-one-out.";
+  }
+
+  /**
+   * Get the value of FindNumBins.
+   *
+   * @return Value of FindNumBins.
+   */
+  public boolean getFindNumBins() {
+    
+    return m_FindNumBins;
+  }
+  
+  /**
+   * Set the value of FindNumBins.
+   *
+   * @param newFindNumBins Value to assign to FindNumBins.
+   */
+  public void setFindNumBins(boolean newFindNumBins) {
+    
+    m_FindNumBins = newFindNumBins;
+  }
+  
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String makeBinaryTipText() {
+
+    return "Make resulting attributes binary.";
+  }
+
+  /**
+   * Gets whether binary attributes should be made for discretized ones.
+   *
+   * @return true if attributes will be binarized
+   */
+  public boolean getMakeBinary() {
+
+    return m_MakeBinary;
+  }
+
+  /** 
+   * Sets whether binary attributes should be made for discretized ones.
+   *
+   * @param makeBinary if binary attributes are to be made
+   */
+  public void setMakeBinary(boolean makeBinary) {
+
+    m_MakeBinary = makeBinary;
+  }
+
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String useMDLTipText() {
+
+    return "Use class-based discretization. If set to false, does"
+      + " not require a class attribute, and uses a fixed number"
+      + " of bins (according to bins setting).";
+  }
+
+  /**
+   * Gets whether MDL will be used as the discretisation method.
+   *
+   * @return true if so, false if fixed bins should be used.
+   */
+  public boolean getUseMDL() {
+
+    return m_UseMDL;
+  }
+
+  /** 
+   * Sets whether MDL will be used as the discretisation method.
+   *
+   * @param useMDL true if MDL should be used, false if fixed bins should
+   * be used.
+   */
+  public void setUseMDL(boolean useMDL) {
+
+    m_UseMDL = useMDL;
+  }
+
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String useKononenkoTipText() {
+
+    return "Use Kononenko's MDL criterion. If set to false"
+      + " uses the Fayyad & Irani criterion.";
+  }
+  
+  /**
+   * Get the value of UseEqualFrequency.
+   *
+   * @return Value of UseEqualFrequency.
+   */
+  public boolean getUseEqualFrequency() {
+    
+    return m_UseEqualFrequency;
+  }
+  
+  /**
+   * Set the value of UseEqualFrequency.
+   *
+   * @param newUseEqualFrequency Value to assign to UseEqualFrequency.
+   */
+  public void setUseEqualFrequency(boolean newUseEqualFrequency) {
+    
+    m_UseEqualFrequency = newUseEqualFrequency;
+  }
+  
+  /**
+   * Gets whether Kononenko's MDL criterion is to be used.
+   *
+   * @return true if Kononenko's criterion will be used.
+   */
+  public boolean getUseKononenko() {
+
+    return m_UseKononenko;
+  }
+
+  /** 
+   * Sets whether Kononenko's MDL criterion is to be used.
+   *
+   * @param useKon true if Kononenko's one is to be used
+   */
+  public void setUseKononenko(boolean useKon) {
+
+    m_UseKononenko = useKon;
+  }
+
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String useBetterEncodingTipText() {
+
+    return "Uses a more efficient split point encoding.";
+  }
+
+  /**
+   * Gets whether better encoding is to be used for MDL.
+   *
+   * @return true if the better MDL encoding will be used
+   */
+  public boolean getUseBetterEncoding() {
+
+    return m_UseBetterEncoding;
+  }
+
+  /** 
+   * Sets whether better encoding is to be used for MDL.
+   *
+   * @param useBetterEncoding true if better encoding to be used.
+   */
+  public void setUseBetterEncoding(boolean useBetterEncoding) {
+
+    m_UseBetterEncoding = useBetterEncoding;
+  }
+
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String binsTipText() {
+
+    return "Number of bins for class-blind discretisation. This"
+      + " setting is ignored if MDL-based discretisation is used.";
+  }
+
+  /**
+   * Gets the number of bins numeric attributes will be divided into
+   *
+   * @return the number of bins.
+   */
+  public int getBins() {
+
+    return m_NumBins;
+  }
+
+  /**
+   * Sets the number of bins to divide each selected numeric attribute into
+   *
+   * @param numBins the number of bins
+   */
+  public void setBins(int numBins) {
+
+    m_NumBins = numBins;
+  }
+
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String invertSelectionTipText() {
+
+    return "Set attribute selection mode. If false, only selected"
+      + " (numeric) attributes in the range will be discretized; if"
+      + " true, only non-selected attributes will be discretized.";
+  }
+
+  /**
+   * Gets whether the supplied columns are to be removed or kept
+   *
+   * @return true if the supplied columns will be kept
+   */
+  public boolean getInvertSelection() {
+
+    return m_DiscretizeCols.getInvert();
+  }
+
+  /**
+   * Sets whether selected columns should be removed or kept. If true the 
+   * selected columns are kept and unselected columns are deleted. If false
+   * selected columns are deleted and unselected columns are kept.
+   *
+   * @param invert the new invert setting
+   */
+  public void setInvertSelection(boolean invert) {
+
+    m_DiscretizeCols.setInvert(invert);
+  }
+
+  /**
+   * Returns the tip text for this property
+   *
+   * @return tip text for this property suitable for
+   * displaying in the explorer/experimenter gui
+   */
+  public String attributeIndicesTipText() {
+    return "Specify range of attributes to act on."
+      + " This is a comma separated list of attribute indices, with"
+      + " \"first\" and \"last\" valid values. Specify an inclusive"
+      + " range with \"-\". E.g: \"first-3,5,6-10,last\".";
+  }
+
+  /**
+   * Gets the current range selection
+   *
+   * @return a string containing a comma separated list of ranges
+   */
+  public String getAttributeIndices() {
+
+    return m_DiscretizeCols.getRanges();
+  }
+
+  /**
+   * Sets which attributes are to be Discretized (only numeric
+   * attributes among the selection will be Discretized).
+   *
+   * @param rangeList a string representing the list of attributes. Since
+   * the string will typically come from a user, attributes are indexed from
+   * 1. <br>
+   * eg: first-3,5,6-last
+   * @exception IllegalArgumentException if an invalid range list is supplied 
+   */
+  public void setAttributeIndices(String rangeList) {
+
+    m_DiscretizeCols.setRanges(rangeList);
+  }
+
+  /**
+   * Sets which attributes are to be Discretized (only numeric
+   * attributes among the selection will be Discretized).
+   *
+   * @param attributes an array containing indexes of attributes to Discretize.
+   * Since the array will typically come from a program, attributes are indexed
+   * from 0.
+   * @exception IllegalArgumentException if an invalid set of ranges
+   * is supplied 
+   */
+  public void setAttributeIndicesArray(int [] attributes) {
+
+    setAttributeIndices(Range.indicesToRangeList(attributes));
+  }
+
+  /**
+   * Gets the cut points for an attribute
+   *
+   * @param the index (from 0) of the attribute to get the cut points of
+   * @return an array containing the cutpoints (or null if the
+   * attribute requested isn't being Discretized
+   */
+  public double [] getCutPoints(int attributeIndex) {
+
+    if (m_CutPoints == null) {
+      return null;
+    }
+    return m_CutPoints[attributeIndex];
+  }
+
+  /** Generate the cutpoints for each attribute */
+  protected void calculateCutPoints() {
+
+    Instances copy = null;
+
+    m_CutPoints = new double [getInputFormat().numAttributes()] [];
+    for(int i = getInputFormat().numAttributes() - 1; i >= 0; i--) {
+      if ((m_DiscretizeCols.isInRange(i)) && 
+	  (getInputFormat().attribute(i).isNumeric())) {
+	if (m_UseMDL) {
+
+	  // Use copy to preserve order
+	  if (copy == null) {
+	    copy = new Instances(getInputFormat());
+	  }
+	  calculateCutPointsByMDL(i, copy);
+	} else {
+	  if (m_FindNumBins) {
+	    findNumBins(i);
+	  } else if (!m_UseEqualFrequency) {
+	    calculateCutPointsByEqualWidthBinning(i);
+	  } else {
+	    calculateCutPointsByEqualFrequencyBinning(i);
+	  }
+	}
+      }
+    }
+  }
+
+  /**
+   * Set cutpoints for a single attribute using MDL.
+   *
+   * @param index the index of the attribute to set cutpoints for
+   */
+  protected void calculateCutPointsByMDL(int index,
+					 Instances data) {
+
+    // Sort instances
+    data.sort(data.attribute(index));
+
+    // Find first instances that's missing
+    int firstMissing = data.numInstances();
+    for (int i = 0; i < data.numInstances(); i++) {
+      if (data.instance(i).isMissing(index)) {
+        firstMissing = i;
+        break;
+      }
+    }
+    m_CutPoints[index] = cutPointsForSubset(data, index, 0, firstMissing);
+  }
+
+  /** Test using Kononenko's MDL criterion. */
+  private boolean KononenkosMDL(double[] priorCounts,
+				double[][] bestCounts,
+				double numInstances,
+				int numCutPoints) {
+
+    double distPrior, instPrior, distAfter = 0, sum, instAfter = 0;
+    double before, after;
+    int numClassesTotal;
+
+    // Number of classes occuring in the set
+    numClassesTotal = 0;
+    for (int i = 0; i < priorCounts.length; i++) {
+      if (priorCounts[i] > 0) {
+	numClassesTotal++;
+      }
+    }
+
+    // Encode distribution prior to split
+    distPrior = SpecialFunctions.log2Binomial(numInstances 
+					      + numClassesTotal - 1,
+					      numClassesTotal - 1);
+
+    // Encode instances prior to split.
+    instPrior = SpecialFunctions.log2Multinomial(numInstances,
+						 priorCounts);
+
+    before = instPrior + distPrior;
+
+    // Encode distributions and instances after split.
+    for (int i = 0; i < bestCounts.length; i++) {
+      sum = Utils.sum(bestCounts[i]);
+      distAfter += SpecialFunctions.log2Binomial(sum + numClassesTotal - 1,
+						 numClassesTotal - 1);
+      instAfter += SpecialFunctions.log2Multinomial(sum,
+						    bestCounts[i]);
+    }
+
+    // Coding cost after split
+    after = Utils.log2(numCutPoints) + distAfter + instAfter;
+
+    // Check if split is to be accepted
+    return (Utils.gr(before, after));
+  }
+
+
+  /** Test using Fayyad and Irani's MDL criterion. */
+  private boolean FayyadAndIranisMDL(double[] priorCounts,
+				     double[][] bestCounts,
+				     double numInstances,
+				     int numCutPoints) {
+
+    double priorEntropy, entropy, gain; 
+    double entropyLeft, entropyRight, delta;
+    int numClassesTotal, numClassesRight, numClassesLeft;
+
+    // Compute entropy before split.
+    priorEntropy = ContingencyTables.entropy(priorCounts);
+
+    // Compute entropy after split.
+    entropy = ContingencyTables.entropyConditionedOnRows(bestCounts);
+
+    // Compute information gain.
+    gain = priorEntropy - entropy;
+
+    // Number of classes occuring in the set
+    numClassesTotal = 0;
+    for (int i = 0; i < priorCounts.length; i++) {
+      if (priorCounts[i] > 0) {
+	numClassesTotal++;
+      }
+    }
+
+    // Number of classes occuring in the left subset
+    numClassesLeft = 0;
+    for (int i = 0; i < bestCounts[0].length; i++) {
+      if (bestCounts[0][i] > 0) {
+	numClassesLeft++;
+      }
+    }
+
+    // Number of classes occuring in the right subset
+    numClassesRight = 0;
+    for (int i = 0; i < bestCounts[1].length; i++) {
+      if (bestCounts[1][i] > 0) {
+	numClassesRight++;
+      }
+    }
+
+    // Entropy of the left and the right subsets
+    entropyLeft = ContingencyTables.entropy(bestCounts[0]);
+    entropyRight = ContingencyTables.entropy(bestCounts[1]);
+
+    // Compute terms for MDL formula
+    delta = Utils.log2(Math.pow(3, numClassesTotal) - 2) - 
+      (((double) numClassesTotal * priorEntropy) - 
+       (numClassesRight * entropyRight) - 
+       (numClassesLeft * entropyLeft));
+
+    // Check if split is to be accepted
+    return (Utils.gr(gain, (Utils.log2(numCutPoints) + delta) /
+		     (double)numInstances));
+  }
+    
+
+  /** Selects cutpoints for sorted subset. */
+  private double[] cutPointsForSubset(Instances instances, int attIndex, 
+				      int first, int lastPlusOne) { 
+
+    double[][] counts, bestCounts;
+    double[] priorCounts, left, right, cutPoints;
+    double currentCutPoint = -Double.MAX_VALUE, bestCutPoint = -1, 
+      currentEntropy, bestEntropy, priorEntropy, gain;
+    int bestIndex = -1, numInstances = 0, numCutPoints = 0;
+
+    // Compute number of instances in set
+    if ((lastPlusOne - first) < 2) {
+      return null;
+    }
+
+    // Compute class counts.
+    counts = new double[2][instances.numClasses()];
+    for (int i = first; i < lastPlusOne; i++) {
+      numInstances += instances.instance(i).weight();
+      counts[1][(int)instances.instance(i).classValue()] +=
+	instances.instance(i).weight();
+    }
+
+    // Save prior counts
+    priorCounts = new double[instances.numClasses()];
+    System.arraycopy(counts[1], 0, priorCounts, 0, 
+		     instances.numClasses());
+
+    // Entropy of the full set
+    priorEntropy = ContingencyTables.entropy(priorCounts);
+    bestEntropy = priorEntropy;
+    
+    // Find best entropy.
+    bestCounts = new double[2][instances.numClasses()];
+    for (int i = first; i < (lastPlusOne - 1); i++) {
+      counts[0][(int)instances.instance(i).classValue()] +=
+	instances.instance(i).weight();
+      counts[1][(int)instances.instance(i).classValue()] -=
+	instances.instance(i).weight();
+      if (Utils.sm(instances.instance(i).value(attIndex), 
+		   instances.instance(i + 1).value(attIndex))) {
+	currentCutPoint = instances.instance(i).value(attIndex); //+ 
+	//instances.instance(i + 1).value(attIndex)) / 2.0;
+	currentEntropy = ContingencyTables.entropyConditionedOnRows(counts);
+	if (Utils.sm(currentEntropy, bestEntropy)) {
+	  bestCutPoint = currentCutPoint;
+	  bestEntropy = currentEntropy;
+	  bestIndex = i;
+	  System.arraycopy(counts[0], 0, 
+			   bestCounts[0], 0, instances.numClasses());
+	  System.arraycopy(counts[1], 0, 
+			   bestCounts[1], 0, instances.numClasses()); 
+	}
+	numCutPoints++;
+      }
+    }
+
+    // Use worse encoding?
+    if (!m_UseBetterEncoding) {
+      numCutPoints = (lastPlusOne - first) - 1;
+    }
+
+    // Checks if gain is zero
+    gain = priorEntropy - bestEntropy;
+    if (Utils.eq(gain, 0)) {
+      return null;
+    }
+
+    // Check if split is to be accepted
+    if ((m_UseKononenko && KononenkosMDL(priorCounts, bestCounts,
+					 numInstances, numCutPoints)) ||
+	(!m_UseKononenko && FayyadAndIranisMDL(priorCounts, bestCounts,
+					       numInstances, numCutPoints))) {
+      
+      // Select split points for the left and right subsets
+      left = cutPointsForSubset(instances, attIndex, first, bestIndex + 1);
+      right = cutPointsForSubset(instances, attIndex, 
+				 bestIndex + 1, lastPlusOne);
+      
+      // Merge cutpoints and return them
+      if ((left == null) && (right) == null) {
+	cutPoints = new double[1];
+	cutPoints[0] = bestCutPoint;
+      } else if (right == null) {
+	cutPoints = new double[left.length + 1];
+	System.arraycopy(left, 0, cutPoints, 0, left.length);
+	cutPoints[left.length] = bestCutPoint;
+      } else if (left == null) {
+	cutPoints = new double[1 + right.length];
+	cutPoints[0] = bestCutPoint;
+	System.arraycopy(right, 0, cutPoints, 1, right.length);
+      } else {
+	cutPoints =  new double[left.length + right.length + 1];
+	cutPoints = new double[left.length + right.length + 1];
+	System.arraycopy(left, 0, cutPoints, 0, left.length);
+	cutPoints[left.length] = bestCutPoint;
+	System.arraycopy(right, 0, cutPoints, left.length + 1, right.length);
+      }
+      
+      return cutPoints;
+    } else
+      return null;
+  }
+ 
+  /**
+   * Set cutpoints for a single attribute.
+   *
+   * @param index the index of the attribute to set cutpoints for
+   */
+  protected void calculateCutPointsByEqualWidthBinning(int index) {
+
+    // Scan for max and min values
+    double max = 0, min = 1, currentVal;
+    Instance currentInstance;
+    for(int i = 0; i < getInputFormat().numInstances(); i++) {
+      currentInstance = getInputFormat().instance(i);
+      if (!currentInstance.isMissing(index)) {
+	currentVal = currentInstance.value(index);
+	if (max < min) {
+	  max = min = currentVal;
+	}
+	if (currentVal > max) {
+	  max = currentVal;
+	}
+	if (currentVal < min) {
+	  min = currentVal;
+	}
+      }
+    }
+    double binWidth = (max - min) / m_NumBins;
+    double [] cutPoints = null;
+    if ((m_NumBins > 1) && (binWidth > 0)) {
+      cutPoints = new double [m_NumBins - 1];
+      for(int i = 1; i < m_NumBins; i++) {
+	cutPoints[i - 1] = min + binWidth * i;
+      }
+    }
+    m_CutPoints[index] = cutPoints;
+  }
+ 
+  /**
+   * Set cutpoints for a single attribute.
+   *
+   * @param index the index of the attribute to set cutpoints for
+   */
+  protected void calculateCutPointsByEqualFrequencyBinning(int index) {
+
+    // Copy data so that it can be sorted
+    Instances data = new Instances(getInputFormat());
+
+    // Sort input data
+    data.sort(index);
+
+    // Compute weight of instances without missing values
+    double sumOfWeights = 0;
+    for (int i = 0; i < data.numInstances(); i++) {
+      if (data.instance(i).isMissing(index)) {
+	break;
+      } else {
+	sumOfWeights += data.instance(i).weight();
+      }
+    }
+    double freq = sumOfWeights / m_NumBins;
+
+    // Compute break points
+    double[] cutPoints = new double[m_NumBins - 1];
+    double counter = 0;
+    int cpindex = 0;
+    for (int i = 0; i < data.numInstances() - 1; i++) {
+
+      // Stop if value missing
+      if (data.instance(i).isMissing(index)) {
+	break;
+      }
+      counter += data.instance(i).weight();
+
+      // Do we have a potential breakpoint?
+      if (data.instance(i).value(index) < 
+	  data.instance(i + 1).value(index)) {
+	if (counter >= freq) {
+	  cutPoints[cpindex] = (data.instance(i).value(index) +
+				data.instance(i + 1).value(index)) / 2;
+	  cpindex++;
+	  counter = counter - freq;
+	}
+      }
+    }
+
+    // Did we find any cutpoints?
+    if (cpindex == 0) {
+      m_CutPoints[index] = null;
+    } else {
+      double[] cp = new double[cpindex];
+      for (int i = 0; i < cpindex; i++) {
+	cp[i] = cutPoints[i];
+      }
+      m_CutPoints[index] = cp;
+    }
+  }
+
+  /**
+   * Optimizes the number of bins using leave-one-out cross-validation.
+   *
+   * @param index the attribute index
+   */
+  protected void findNumBins(int index) {
+
+    double min = Double.MAX_VALUE, max = -Double.MIN_VALUE, binWidth = 0, 
+      entropy, bestEntropy = Double.MAX_VALUE, currentVal;
+    double[] distribution;
+    int bestNumBins  = 1;
+    Instance currentInstance;
+
+    // Find minimum and maximum
+    for (int i = 0; i < getInputFormat().numInstances(); i++) {
+      currentInstance = getInputFormat().instance(i);
+      if (!currentInstance.isMissing(index)) {
+	currentVal = currentInstance.value(index);
+	if (currentVal > max) {
+	  max = currentVal;
+	}
+	if (currentVal < min) {
+	  min = currentVal;
+	}
+      }
+    }
+
+    // Find best number of bins
+    for (int i = 0; i < m_NumBins; i++) {
+      distribution = new double[i + 1];
+      binWidth = (max - min) / (i + 1);
+
+      // Compute distribution
+      for (int j = 0; j < getInputFormat().numInstances(); j++) {
+	currentInstance = getInputFormat().instance(j);
+	if (!currentInstance.isMissing(index)) {
+	  for (int k = 0; k < i + 1; k++) {
+	    if (currentInstance.value(index) <= 
+		(min + (((double)k + 1) * binWidth))) {
+	      distribution[k] += currentInstance.weight();
+	      break;
+	    }
+	  }
+	}
+      }
+
+      // Compute cross-validated entropy
+      entropy = 0;
+      for (int k = 0; k < i + 1; k++) {
+	if (distribution[k] < 2) {
+	  entropy = Double.MAX_VALUE;
+	  break;
+	}
+	entropy -= distribution[k] * Math.log((distribution[k] - 1) / 
+					      binWidth);
+      }
+
+      // Best entropy so far?
+      if (entropy < bestEntropy) {
+	bestEntropy = entropy;
+	bestNumBins = i + 1;
+      }
+    }
+
+    // Compute cut points
+    double [] cutPoints = null;
+    if ((bestNumBins > 1) && (binWidth > 0)) {
+      cutPoints = new double [bestNumBins - 1];
+      for(int i = 1; i < bestNumBins; i++) {
+	cutPoints[i - 1] = min + binWidth * i;
+      }
+    }
+    m_CutPoints[index] = cutPoints;
+   }
+
+  /**
+   * Set the output format. Takes the currently defined cutpoints and 
+   * m_InputFormat and calls setOutputFormat(Instances) appropriately.
+   */
+  protected void setOutputFormat() {
+
+    if (m_CutPoints == null) {
+      setOutputFormat(null);
+      return;
+    }
+    FastVector attributes = new FastVector(getInputFormat().numAttributes());
+    int classIndex = getInputFormat().classIndex();
+    for(int i = 0; i < getInputFormat().numAttributes(); i++) {
+      if ((m_DiscretizeCols.isInRange(i)) 
+	  && (getInputFormat().attribute(i).isNumeric())) {
+	if (!m_MakeBinary) {
+	  FastVector attribValues = new FastVector(1);
+	  if (m_CutPoints[i] == null) {
+	    attribValues.addElement("'All'");
+	  } else {
+	    for(int j = 0; j <= m_CutPoints[i].length; j++) {
+	      if (j == 0) {
+		attribValues.addElement("'(-inf-"
+			+ Utils.doubleToString(m_CutPoints[i][j], 6) + "]'");
+	      } else if (j == m_CutPoints[i].length) {
+		attribValues.addElement("'("
+			+ Utils.doubleToString(m_CutPoints[i][j - 1], 6) 
+					+ "-inf)'");
+	      } else {
+		attribValues.addElement("'("
+			+ Utils.doubleToString(m_CutPoints[i][j - 1], 6) + "-"
+			+ Utils.doubleToString(m_CutPoints[i][j], 6) + "]'");
+	      }
+	    }
+	  }
+	  attributes.addElement(new Attribute(getInputFormat().
+					      attribute(i).name(),
+					      attribValues));
+	} else {
+	  if (m_CutPoints[i] == null) {
+	    FastVector attribValues = new FastVector(1);
+	    attribValues.addElement("'All'");
+	    attributes.addElement(new Attribute(getInputFormat().
+						attribute(i).name(),
+						attribValues));
+	  } else {
+	    if (i < getInputFormat().classIndex()) {
+	      classIndex += m_CutPoints[i].length - 1;
+	    }
+	    for(int j = 0; j < m_CutPoints[i].length; j++) {
+	      FastVector attribValues = new FastVector(2);
+	      attribValues.addElement("'(-inf-"
+		      + Utils.doubleToString(m_CutPoints[i][j], 6) + "]'");
+	      attribValues.addElement("'("
+		      + Utils.doubleToString(m_CutPoints[i][j], 6) + "-inf)'");
+	      attributes.addElement(new Attribute(getInputFormat().
+						  attribute(i).name(),
+						  attribValues));
+	    }
+	  }
+	}
+      } else {
+	attributes.addElement(getInputFormat().attribute(i).copy());
+      }
+    }
+    Instances outputFormat = 
+      new Instances(getInputFormat().relationName(), attributes, 0);
+    outputFormat.setClassIndex(classIndex);
+    setOutputFormat(outputFormat);
+  }
+
+  /**
+   * Convert a single instance over. The converted instance is added to 
+   * the end of the output queue.
+   *
+   * @param instance the instance to convert
+   */
+  protected void convertInstance(Instance instance) {
+
+    int index = 0;
+    double [] vals = new double [outputFormatPeek().numAttributes()];
+    // Copy and convert the values
+    for(int i = 0; i < getInputFormat().numAttributes(); i++) {
+      if (m_DiscretizeCols.isInRange(i) && 
+	  getInputFormat().attribute(i).isNumeric()) {
+	int j;
+	double currentVal = instance.value(i);
+	if (m_CutPoints[i] == null) {
+	  if (instance.isMissing(i)) {
+	    vals[index] = Instance.missingValue();
+	  } else {
+	    vals[index] = 0;
+	  }
+	  index++;
+	} else {
+	  if (!m_MakeBinary) {
+	    if (instance.isMissing(i)) {
+	      vals[index] = Instance.missingValue();
+	    } else {
+	      for (j = 0; j < m_CutPoints[i].length; j++) {
+		if (currentVal <= m_CutPoints[i][j]) {
+		  break;
+		}
+	      }
+              vals[index] = j;
+	    }
+	    index++;
+	  } else {
+	    for (j = 0; j < m_CutPoints[i].length; j++) {
+	      if (instance.isMissing(i)) {
+                vals[index] = Instance.missingValue();
+	      } else if (currentVal <= m_CutPoints[i][j]) {
+                vals[index] = 0;
+	      } else {
+                vals[index] = 1;
+	      }
+	      index++;
+	    }
+	  }   
+	}
+      } else {
+        vals[index] = instance.value(i);
+	index++;
+      }
+    }
+    
+    Instance inst = null;
+    if (instance instanceof SparseInstance) {
+      inst = new SparseInstance(instance.weight(), vals);
+    } else {
+      inst = new Instance(instance.weight(), vals);
+    }
+    copyStringValues(inst, false, instance.dataset(), getInputStringIndex(),
+                     getOutputFormat(), getOutputStringIndex());
+    inst.setDataset(getOutputFormat());
+    push(inst);
+  }
+
+  /**
+   * Main method for testing this class.
+   *
+   * @param argv should contain arguments to the filter: use -h for help
+   */
+  public static void main(String [] argv) {
+
+    try {
+      if (Utils.getFlag('b', argv)) {
+ 	Filter.batchFilterFile(new DiscretizeFilter(), argv);
+      } else {
+	Filter.filterFile(new DiscretizeFilter(), argv);
+      }
+    } catch (Exception ex) {
+      System.out.println(ex.getMessage());
+    }
+  }
+}
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/filters/Filter.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/filters/Filter.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/kea/kea-3.0/weka/filters/Filter.java	(revision 10506)
@@ -0,0 +1,934 @@
+/*
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ *    Filter.java
+ *    Copyright (C) 1999 Len Trigg
+ *
+ */
+
+
+package weka.filters;
+
+import java.io.BufferedReader;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Serializable;
+import java.util.Enumeration;
+import weka.core.Attribute;
+import weka.core.Instance;
+import weka.core.Instances;
+import weka.core.Option;
+import weka.core.OptionHandler;
+import weka.core.Queue;
+import weka.core.Utils;
+
+/** 
+ * An abstract class for instance filters: objects that take instances
+ * as input, carry out some transformation on the instance and then
+ * output the instance. The method implementations in this class
+ * assume that most of the work will be done in the methods overridden
+ * by subclasses.<p>
+ *
+ * A simple example of filter use. This example doesn't remove
+ * instances from the output queue until all instances have been
+ * input, so has higher memory consumption than an approach that
+ * uses output instances as they are made available:<p>
+ *
+ * <code> <pre>
+ *  Filter filter = ..some type of filter..
+ *  Instances instances = ..some instances..
+ *  for (int i = 0; i < data.numInstances(); i++) {
+ *    filter.input(data.instance(i));
+ *  }
+ *  filter.batchFinished();
+ *  Instances newData = filter.outputFormat();
+ *  Instance processed;
+ *  while ((processed = filter.output()) != null) {
+ *    newData.add(processed);
+ *  }
+ *  ..do something with newData..
+ * </pre> </code>
+ *
+ * @author Len Trigg (trigg@cs.waikato.ac.nz)
+ * @version $Revision$
+ */
+public abstract class Filter implements Serializable {
+
+  /*
+   * Filter refactoring TODO:
+   *
+   * - Update all filters to use getOutputFormat and setInputFormat
+   * instead of outputFormat, outputFormatPeek and inputFormat.
+   * - Update users of filters to use getOutputFormat and setInputFormat
+   * - remove outputFormat, outputFormatPeek and inputFormat
+   *
+   */
+
+  /** Debugging mode */
+  private boolean m_Debug = false;
+
+  /** The output format for instances */
+  private Instances m_OutputFormat = null;
+
+  /** The output instance queue */
+  private Queue m_OutputQueue = null;
+
+  /** Indices of string attributes in the output format */
+  private int [] m_OutputStringAtts = null;
+
+  /** Indices of string attributes in the input format */
+  private int [] m_InputStringAtts = null;
+
+  /** The input format for instances */
+  private Instances m_InputFormat = null;
+
+  /** Record whether the filter is at the start of a batch */
+  protected boolean m_NewBatch = true;
+
+  /**
+   * Sets the format of output instances. The derived class should use this
+   * method once it has determined the outputformat. The 
+   * output queue is cleared.
+   *
+   * @param outputFormat the new output format
+   */
+  protected void setOutputFormat(Instances outputFormat) {
+
+    if (outputFormat != null) {
+      m_OutputFormat = outputFormat.stringFreeStructure();
+      m_OutputStringAtts = getStringIndices(m_OutputFormat);
+
+      // Rename the attribute
+      String relationName = outputFormat.relationName() 
+        + "-" + this.getClass().getName();
+      if (this instanceof OptionHandler) {
+        String [] options = ((OptionHandler)this).getOptions();
+        for (int i = 0; i < options.length; i++) {
+          relationName += options[i].trim();
+        }
+      }
+      m_OutputFormat.setRelationName(relationName);
+    } else {
+      m_OutputFormat = null;
+    }
+    m_OutputQueue = new Queue();
+  }
+
+  /**
+   * Gets the currently set inputformat instances. This dataset may contain
+   * buffered instances.
+   *
+   * @return the input Instances.
+   */
+  protected Instances getInputFormat() {
+
+    return m_InputFormat;
+  }
+
+  /**
+   * Returns a reference to the current output format without
+   * copying it.
+   *
+   * @return a reference to the current output format
+   */
+  protected Instances outputFormatPeek() {
+
+    return m_OutputFormat;
+  }
+
+  /**
+   * Adds an output instance to the queue. The derived class should use this
+   * method for each output instance it makes available. 
+   *
+   * @param instance the instance to be added to the queue
+   */
+  protected void push(Instance instance) {
+
+    if (instance != null) {
+      copyStringValues(instance, m_OutputFormat, m_OutputStringAtts);
+      instance.setDataset(m_OutputFormat);
+      m_OutputQueue.push(instance);
+    }
+  }
+
+  /**
+   * Clears the output queue.
+   */
+  protected void resetQueue() {
+
+    m_OutputQueue = new Queue();
+  }
+
+  /**
+   * Adds the supplied input instance to the inputformat dataset for
+   * later processing.  Use this method rather than
+   * getInputFormat().add(instance). Or else.
+   *
+   * @param instance the <code>Instance</code> to buffer.  
+   */
+  protected void bufferInput(Instance instance) {
+
+    if (instance != null) {
+      copyStringValues(instance, m_InputFormat, m_InputStringAtts);
+      instance.setDataset(m_InputFormat);
+      m_InputFormat.add(instance);
+    }
+  }
+
+  /**
+   * Returns an array containing the indices of all string attributes in the
+   * input format. This index is created during setInputFormat()
+   *
+   * @return an array containing the indices of string attributes in the 
+   * input dataset.
+   */
+  protected int [] getInputStringIndex() {
+
+    return m_InputStringAtts;
+  }
+
+  /**
+   * Returns an array containing the indices of all string attributes in the
+   * output format. This index is created during setOutputFormat()
+   *
+   * @return an array containing the indices of string attributes in the 
+   * output dataset.
+   */
+  protected int [] getOutputStringIndex() {
+
+    return m_OutputStringAtts;
+  }
+
+  /**
+   * Copies string values contained in the instance copied to a new
+   * dataset. The Instance must already be assigned to a dataset. This
+   * dataset and the destination dataset must have the same structure.
+   *
+   * @param instance the Instance containing the string values to copy.
+   * @param destDataset the destination set of Instances
+   * @param strAtts an array containing the indices of any string attributes
+   * in the dataset.  
+   */
+  private void copyStringValues(Instance inst, Instances destDataset, 
+                                int []strAtts) {
+
+    if (strAtts.length == 0) {
+      return;
+    }
+    if (inst.dataset() == null) {
+      throw new IllegalArgumentException("Instance has no dataset assigned!!");
+    } else if (inst.dataset().numAttributes() != destDataset.numAttributes()) {
+      throw new IllegalArgumentException("Src and Dest differ in # of attributes!!");
+    } 
+    copyStringValues(inst, true, inst.dataset(), strAtts,
+                     destDataset, strAtts);
+  }
+
+  /**
+   * Takes string values referenced by an Instance and copies them from a
+   * source dataset to a destination dataset. The instance references are
+   * updated to be valid for the destination dataset. The instance may have the 
+   * structure (i.e. number and attribute position) of either dataset (this
+   * affects where references are obtained from). The source dataset must
+   * have the same structure as the filter input format and the destination
+   * must have the same structure as the filter output format.
+   *
+   * @param instance the instance containing references to strings in the source
+   * dataset that will have references updated to be valid for the destination
+   * dataset.
+   * @param instSrcCompat true if the instance structure is the same as the
+   * source, or false if it is the same as the destination
+   * @param srcDataset the dataset for which the current instance string
+   * references are valid (after any position mapping if needed)
+   * @param destDataset the dataset for which the current instance string
+   * references need to be inserted (after any position mapping if needed)
+   */
+  protected void copyStringValues(Instance instance, boolean instSrcCompat,
+                                  Instances srcDataset, Instances destDataset) {
+
+    copyStringValues(instance, instSrcCompat, srcDataset, m_InputStringAtts,
+                     destDataset, m_OutputStringAtts);
+  }
+
+  /**
+   * Takes string values referenced by an Instance and copies them from a
+   * source dataset to a destination dataset. The instance references are
+   * updated to be valid for the destination dataset. The instance may have the 
+   * structure (i.e. number and attribute position) of either dataset (this
+   * affects where references are obtained from). Only works if the number
+   * of string attributes is the same in both indices (implicitly these string
+   * attributes should be semantically same but just with shifted positions).
+   *
+   * @param instance the instance containing references to strings in the source
+   * dataset that will have references updated to be valid for the destination
+   * dataset.
+   * @param instSrcCompat true if the instance structure is the same as the
+   * source, or false if it is the same as the destination (i.e. which of the
+   * string attribute indices contains the correct locations for this instance).
+   * @param srcDataset the dataset for which the current instance string
+   * references are valid (after any position mapping if needed)
+   * @param srcStrAtts an array containing the indices of string attributes
+   * in the source datset.
+   * @param destDataset the dataset for which the current instance string
+   * references need to be inserted (after any position mapping if needed)
+   * @param destStrAtts an array containing the indices of string attributes
+   * in the destination datset.
+   */
+  protected void copyStringValues(Instance instance, boolean instSrcCompat,
+                                  Instances srcDataset, int []srcStrAtts,
+                                  Instances destDataset, int []destStrAtts) {
+    if (srcDataset == destDataset) {
+      return;
+    }
+    if (srcStrAtts.length != destStrAtts.length) {
+      throw new IllegalArgumentException("Src and Dest string indices differ in length!!");
+    }
+    for (int i = 0; i < srcStrAtts.length; i++) {
+      int instIndex = instSrcCompat ? srcStrAtts[i] : destStrAtts[i];
+      Attribute src = srcDataset.attribute(srcStrAtts[i]);
+      Attribute dest = destDataset.attribute(destStrAtts[i]);
+      if (!instance.isMissing(instIndex)) {
+        //System.err.println(instance.value(srcIndex) 
+        //                   + " " + src.numValues()
+        //                   + " " + dest.numValues());
+        int valIndex = dest.addStringValue(src, (int)instance.value(instIndex));
+        // setValue here shouldn't be too slow here unless your dataset has
+        // squillions of string attributes
+        instance.setValue(instIndex, (double)valIndex);
+      }
+    }
+  }
+
+  /**
+   * This will remove all buffered instances from the inputformat dataset.
+   * Use this method rather than getInputFormat().delete();
+   */
+  protected void flushInput() {
+
+    if (m_InputStringAtts.length > 0) {
+      m_InputFormat = m_InputFormat.stringFreeStructure();
+    } else {
+      // This more efficient than new Instances(m_InputFormat, 0);
+      m_InputFormat.delete();
+    }
+  }
+
+  /**
+   * @deprecated use <code>setInputFormat(Instances)</code> instead.
+   */
+  public boolean inputFormat(Instances instanceInfo) throws Exception {
+
+    return setInputFormat(instanceInfo);
+  }
+
+  /**
+   * Sets the format of the input instances. If the filter is able to
+   * determine the output format before seeing any input instances, it
+   * does so here. This default implementation clears the output format
+   * and output queue, and the new batch flag is set. Overriders should
+   * call <code>super.setInputFormat(Instances)</code>
+   *
+   * @param instanceInfo an Instances object containing the input instance
+   * structure (any instances contained in the object are ignored - only the
+   * structure is required).
+   * @return true if the outputFormat may be collected immediately
+   * @exception Exception if the inputFormat can't be set successfully 
+   */
+  public boolean setInputFormat(Instances instanceInfo) throws Exception {
+
+    m_InputFormat = instanceInfo.stringFreeStructure();
+    m_InputStringAtts = getStringIndices(instanceInfo);
+    m_OutputFormat = null;
+    m_OutputQueue = new Queue();
+    m_NewBatch = true;
+    return false;
+  }
+
+  /**
+   * @deprecated use <code>getOutputFormat()</code> instead.
+   */
+  public final Instances outputFormat() {
+
+    return getOutputFormat();
+  }
+
+  /**
+   * Gets the format of the output instances. This should only be called
+   * after input() or batchFinished() has returned true. The relation
+   * name of the output instances should be changed to reflect the
+   * action of the filter (eg: add the filter name and options).
+   *
+   * @return an Instances object containing the output instance
+   * structure only.
+   * @exception NullPointerException if no input structure has been
+   * defined (or the output format hasn't been determined yet) 
+   */
+  public final Instances getOutputFormat() {
+
+    if (m_OutputFormat == null) {
+      throw new NullPointerException("No output format defined.");
+    }
+    return new Instances(m_OutputFormat, 0);
+  }
+
+  /**
+   * Input an instance for filtering. Ordinarily the instance is
+   * processed and made available for output immediately. Some filters
+   * require all instances be read before producing output, in which
+   * case output instances should be collected after calling
+   * batchFinished(). If the input marks the start of a new batch, the
+   * output queue is cleared. This default implementation assumes all
+   * instance conversion will occur when batchFinished() is called.
+   *
+   * @param instance the input instance
+   * @return true if the filtered instance may now be
+   * collected with output().
+   * @exception NullPointerException if the input format has not been
+   * defined.
+   * @exception Exception if the input instance was not of the correct 
+   * format or if there was a problem with the filtering.  
+   */
+  public boolean input(Instance instance) throws Exception {
+
+    if (m_InputFormat == null) {
+      throw new NullPointerException("No input instance format defined");
+    }
+    if (m_NewBatch) {
+      m_OutputQueue = new Queue();
+      m_NewBatch = false;
+    }
+    bufferInput(instance);
+    return false;
+  }
+
+  /**
+   * Signify that this batch of input to the filter is finished. If
+   * the filter requires all instances prior to filtering, output()
+   * may now be called to retrieve the filtered instances. Any
+   * subsequent instances filtered should be filtered based on setting
+   * obtained from the first batch (unless the inputFormat has been
+   * re-assigned or new options have been set). This default
+   * implementation assumes all instance processing occurs during
+   * inputFormat() and input().
+   *
+   * @return true if there are instances pending output
+   * @exception NullPointerException if no input structure has been defined,
+   * @exception Exception if there was a problem finishing the batch.
+   */
+  public boolean batchFinished() throws Exception {
+
+    if (m_InputFormat == null) {
+      throw new NullPointerException("No input instance format defined");
+    }
+    flushInput();
+    m_NewBatch = true;
+    return (numPendingOutput() != 0);
+  }
+
+
+  /**
+   * Output an instance after filtering and remove from the output queue.
+   *
+   * @return the instance that has most recently been filtered (or null if
+   * the queue is empty).
+   * @exception NullPointerException if no output structure has been defined
+   */
+  public Instance output() {
+
+    if (m_OutputFormat == null) {
+      throw new NullPointerException("No output instance format defined");
+    }
+    if (m_OutputQueue.empty()) {
+      return null;
+    }
+    Instance result = (Instance)m_OutputQueue.pop();
+    // Clear out references to old strings occasionally
+    if (m_OutputQueue.empty() && m_NewBatch) {
+      if (m_OutputStringAtts.length > 0) {
+        m_OutputFormat = m_OutputFormat.stringFreeStructure();
+      }
+    }
+    return result;
+  }
+  
+  /**
+   * Output an instance after filtering but do not remove from the
+   * output queue.
+   *
+   * @return the instance that has most recently been filtered (or null if
+   * the queue is empty).
+   * @exception NullPointerException if no input structure has been defined 
+   */
+  public Instance outputPeek() {
+
+    if (m_OutputFormat == null) {
+      throw new NullPointerException("No output instance format defined");
+    }
+    if (m_OutputQueue.empty()) {
+      return null;
+    }
+    Instance result = (Instance)m_OutputQueue.peek();
+    return result;
+  }
+
+  /**
+   * Returns the number of instances pending output
+   *
+   * @return the number of instances  pending output
+   * @exception NullPointerException if no input structure has been defined
+   */
+  public int numPendingOutput() {
+
+    if (m_OutputFormat == null) {
+      throw new NullPointerException("No output instance format defined");
+    }
+    return m_OutputQueue.size();
+  }
+
+  /**
+   * Returns whether the output format is ready to be collected
+   *
+   * @return true if the output format is set
+   */
+  public boolean isOutputFormatDefined() {
+
+    return (m_OutputFormat != null);
+  }
+
+  /**
+   * Gets an array containing the indices of all string attributes.
+   *
+   * @param insts the Instances to scan for string attributes. 
+   * @return an array containing the indices of string attributes in
+   * the input structure. Will be zero-length if there are no
+   * string attributes
+   */
+  protected int [] getStringIndices(Instances insts) {
+    
+    // Scan through getting the indices of String attributes
+    int [] index = new int [insts.numAttributes()];
+    int indexSize = 0;
+    for (int i = 0; i < insts.numAttributes(); i++) {
+      if (insts.attribute(i).type() == Attribute.STRING) {
+        index[indexSize++] = i;
+      }
+    }
+    int [] result = new int [indexSize];
+    System.arraycopy(index, 0, result, 0, indexSize);
+    return result;
+  }
+  
+  /**
+   * Filters an entire set of instances through a filter and returns
+   * the new set. 
+   *
+   * @param data the data to be filtered
+   * @param filter the filter to be used
+   * @return the filtered set of data
+   * @exception Exception if the filter can't be used successfully
+   */
+  public static Instances useFilter(Instances data,
+				    Filter filter) throws Exception {
+    /*
+    System.err.println(filter.getClass().getName() 
+                       + " in:" + data.numInstances());
+    */
+    for (int i = 0; i < data.numInstances(); i++) {
+      filter.input(data.instance(i));
+    }
+    filter.batchFinished();
+    Instances newData = filter.getOutputFormat();
+    Instance processed;
+    while ((processed = filter.output()) != null) {
+      newData.add(processed);
+    }
+
+    /*
+    System.err.println(filter.getClass().getName() 
+                       + " out:" + newData.numInstances());
+    */
+    return newData;
+  }
+
+  /**
+   * Method for testing filters.
+   *
+   * @param argv should contain the following arguments: <br>
+   * -i input_file <br>
+   * -o output_file <br>
+   * -c class_index <br>
+   * or -h for help on options
+   * @exception Exception if something goes wrong or the user requests help on
+   * command options
+   */
+  public static void filterFile(Filter filter, String [] options) 
+    throws Exception {
+
+    boolean debug = false;
+    Instances data = null;
+    Reader input = null;
+    PrintWriter output = null;
+    boolean helpRequest;
+
+    try {
+       helpRequest = Utils.getFlag('h', options);
+
+      if (Utils.getFlag('d', options)) {
+	debug = true;
+      }
+      String infileName = Utils.getOption('i', options);
+      String outfileName = Utils.getOption('o', options); 
+      String classIndex = Utils.getOption('c', options);
+      
+      if (filter instanceof OptionHandler) {
+	((OptionHandler)filter).setOptions(options);
+      }
+
+      Utils.checkForRemainingOptions(options);
+      if (helpRequest) {
+	throw new Exception("Help requested.\n");
+      }
+      if (infileName.length() != 0) {
+	input = new BufferedReader(new FileReader(infileName));
+      } else {
+	input = new BufferedReader(new InputStreamReader(System.in));
+      }
+      if (outfileName.length() != 0) {
+	output = new PrintWriter(new FileOutputStream(outfileName));
+      } else { 
+	output = new PrintWriter(System.out);
+      }
+
+      data = new Instances(input, 1);
+      if (classIndex.length() != 0) {
+	if (classIndex.equals("first")) {
+	  data.setClassIndex(0);
+	} else if (classIndex.equals("last")) {
+	  data.setClassIndex(data.numAttributes() - 1);
+	} else {
+	  data.setClassIndex(Integer.parseInt(classIndex) - 1);
+	}
+      }
+    } catch (Exception ex) {
+      String filterOptions = "";
+      // Output the error and also the valid options
+      if (filter instanceof OptionHandler) {
+	filterOptions += "\nFilter options:\n\n";
+	Enumeration enum = ((OptionHandler)filter).listOptions();
+	while (enum.hasMoreElements()) {
+	  Option option = (Option) enum.nextElement();
+	  filterOptions += option.synopsis() + '\n'
+	    + option.description() + "\n";
+	}
+      }
+
+      String genericOptions = "\nGeneral options:\n\n"
+	+ "-h\n"
+	+ "\tGet help on available options.\n"
+	+ "\t(use -b -h for help on batch mode.)\n"
+	+ "-i <file>\n"
+	+ "\tThe name of the file containing input instances.\n"
+	+ "\tIf not supplied then instances will be read from stdin.\n"
+	+ "-o <file>\n"
+	+ "\tThe name of the file output instances will be written to.\n"
+	+ "\tIf not supplied then instances will be written to stdout.\n"
+	+ "-c <class index>\n"
+	+ "\tThe number of the attribute to use as the class.\n"
+	+ "\t\"first\" and \"last\" are also valid entries.\n"
+	+ "\tIf not supplied then no class is assigned.\n";
+
+      throw new Exception('\n' + ex.getMessage()
+			  + filterOptions+genericOptions);
+    }
+    
+    if (debug) {
+      System.err.println("Setting input format");
+    }
+    boolean printedHeader = false;
+    if (filter.setInputFormat(data)) {
+      if (debug) {
+	System.err.println("Getting output format");
+      }
+      output.println(filter.getOutputFormat().toString());
+      printedHeader = true;
+    }
+    
+    // Pass all the instances to the filter
+    while (data.readInstance(input)) {
+      if (debug) {
+	System.err.println("Input instance to filter");
+      }
+      if (filter.input(data.instance(0))) {
+	if (debug) {
+	  System.err.println("Filter said collect immediately");
+	}
+	if (!printedHeader) {
+	  throw new Error("Filter didn't return true from setInputFormat() "
+			  + "earlier!");
+	}
+	if (debug) {
+	  System.err.println("Getting output instance");
+	}
+	output.println(filter.output().toString());
+      }
+      data.delete(0);
+    }
+    
+    // Say that input has finished, and print any pending output instances
+    if (debug) {
+      System.err.println("Setting end of batch");
+    }
+    if (filter.batchFinished()) {
+      if (debug) {
+	System.err.println("Filter said collect output");
+      }
+      if (!printedHeader) {
+	if (debug) {
+	  System.err.println("Getting output format");
+	}
+	output.println(filter.getOutputFormat().toString());
+      }
+      if (debug) {
+	System.err.println("Getting output instance");
+      }
+      while (filter.numPendingOutput() > 0) {
+	output.println(filter.output().toString());
+	if (debug){
+	  System.err.println("Getting output instance");
+	}
+      }
+    }
+    if (debug) {
+      System.err.println("Done");
+    }
+    
+    if (output != null) {
+      output.close();
+    }
+  }
+
+  /**
+   * Method for testing filters ability to process multiple batches.
+   *
+   * @param argv should contain the following arguments:<br>
+   * -i (first) input file <br>
+   * -o (first) output file <br>
+   * -r (second) input file <br>
+   * -s (second) output file <br>
+   * -c class_index <br>
+   * or -h for help on options
+   * @exception Exception if something goes wrong or the user requests help on
+   * command options
+   */
+  public static void batchFilterFile(Filter filter, String [] options) 
+    throws Exception {
+
+    Instances firstData = null;
+    Instances secondData = null;
+    Reader firstInput = null;
+    Reader secondInput = null;
+    PrintWriter firstOutput = null;
+    PrintWriter secondOutput = null;
+    boolean helpRequest;
+    try {
+      helpRequest = Utils.getFlag('h', options);
+
+      String fileName = Utils.getOption('i', options); 
+      if (fileName.length() != 0) {
+	firstInput = new BufferedReader(new FileReader(fileName));
+      } else {
+	throw new Exception("No first input file given.\n");
+      }
+
+      fileName = Utils.getOption('r', options); 
+      if (fileName.length() != 0) {
+	secondInput = new BufferedReader(new FileReader(fileName));
+      } else {
+	throw new Exception("No second input file given.\n");
+      }
+
+      fileName = Utils.getOption('o', options); 
+      if (fileName.length() != 0) {
+	firstOutput = new PrintWriter(new FileOutputStream(fileName));
+      } else {
+	firstOutput = new PrintWriter(System.out);
+      }
+      
+      fileName = Utils.getOption('s', options); 
+      if (fileName.length() != 0) {
+	secondOutput = new PrintWriter(new FileOutputStream(fileName));
+      } else {
+	secondOutput = new PrintWriter(System.out);
+      }
+      String classIndex = Utils.getOption('c', options);
+
+      if (filter instanceof OptionHandler) {
+	((OptionHandler)filter).setOptions(options);
+      }
+      Utils.checkForRemainingOptions(options);
+      
+      if (helpRequest) {
+	throw new Exception("Help requested.\n");
+      }
+      firstData = new Instances(firstInput, 1);
+      secondData = new Instances(secondInput, 1);
+      if (!secondData.equalHeaders(firstData)) {
+	throw new Exception("Input file formats differ.\n");
+      }
+      if (classIndex.length() != 0) {
+	if (classIndex.equals("first")) {
+	  firstData.setClassIndex(0);
+	  secondData.setClassIndex(0);
+	} else if (classIndex.equals("last")) {
+	  firstData.setClassIndex(firstData.numAttributes() - 1);
+	  secondData.setClassIndex(secondData.numAttributes() - 1);
+	} else {
+	  firstData.setClassIndex(Integer.parseInt(classIndex) - 1);
+	  secondData.setClassIndex(Integer.parseInt(classIndex) - 1);
+	}
+      }
+    } catch (Exception ex) {
+      String filterOptions = "";
+      // Output the error and also the valid options
+      if (filter instanceof OptionHandler) {
+	filterOptions += "\nFilter options:\n\n";
+	Enumeration enum = ((OptionHandler)filter).listOptions();
+	while (enum.hasMoreElements()) {
+	  Option option = (Option) enum.nextElement();
+	  filterOptions += option.synopsis() + '\n'
+	    + option.description() + "\n";
+	}
+      }
+
+      String genericOptions = "\nGeneral options:\n\n"
+	+ "-h\n"
+	+ "\tGet help on available options.\n"
+	+ "-i <filename>\n"
+	+ "\tThe file containing first input instances.\n"
+	+ "-o <filename>\n"
+	+ "\tThe file first output instances will be written to.\n"
+	+ "-r <filename>\n"
+	+ "\tThe file containing second input instances.\n"
+	+ "-s <filename>\n"
+	+ "\tThe file second output instances will be written to.\n"
+	+ "-c <class index>\n"
+	+ "\tThe number of the attribute to use as the class.\n"
+	+ "\t\"first\" and \"last\" are also valid entries.\n"
+	+ "\tIf not supplied then no class is assigned.\n";
+
+      throw new Exception('\n' + ex.getMessage()
+			  + filterOptions+genericOptions);
+    }
+    boolean printedHeader = false;
+    if (filter.setInputFormat(firstData)) {
+      firstOutput.println(filter.getOutputFormat().toString());
+      printedHeader = true;
+    }
+    
+    // Pass all the instances to the filter
+    while (firstData.readInstance(firstInput)) {
+      if (filter.input(firstData.instance(0))) {
+	if (!printedHeader) {
+	  throw new Error("Filter didn't return true from setInputFormat() "
+			  + "earlier!");
+	}
+	firstOutput.println(filter.output().toString());
+      }
+      firstData.delete(0);
+    }
+    
+    // Say that input has finished, and print any pending output instances
+    if (filter.batchFinished()) {
+      if (!printedHeader) {
+	firstOutput.println(filter.getOutputFormat().toString());
+      }
+      while (filter.numPendingOutput() > 0) {
+	firstOutput.println(filter.output().toString());
+      }
+    }
+    
+    if (firstOutput != null) {
+      firstOutput.close();
+    }    
+    printedHeader = false;
+    if (filter.isOutputFormatDefined()) {
+      secondOutput.println(filter.getOutputFormat().toString());
+      printedHeader = true;
+    }
+    // Pass all the second instances to the filter
+    while (secondData.readInstance(secondInput)) {
+      if (filter.input(secondData.instance(0))) {
+	if (!printedHeader) {
+	  throw new Error("Filter didn't return true from"
+			  + " isOutputFormatDefined() earlier!");
+	}
+	secondOutput.println(filter.output().toString());
+      }
+      secondData.delete(0);
+    }
+    
+    // Say that input has finished, and print any pending output instances
+    if (filter.batchFinished()) {
+      if (!printedHeader) {
+	secondOutput.println(filter.getOutputFormat().toString());
+      }
+      while (filter.numPendingOutput() > 0) {
+	secondOutput.println(filter.output().toString());
+      }
+    }
+    if (secondOutput != null) {
+      secondOutput.close();
+    }
+  }
+
+  /**
+   * Main method for testing this class.
+   *
+   * @param argv should contain arguments to the filter: use -h for help
+   */
+  public static void main(String [] args) {
+    
+    try {
+      if (args.length == 0) {
+        throw new Exception("First argument must be the class name of a Filter");
+      }
+      String fname = args[0];
+      Filter f = (Filter)Class.forName(fname).newInstance();
+      args[0] = "";
+      if (Utils.getFlag('b', args)) {
+	Filter.batchFilterFile(f, args);
+      } else {
+	Filter.filterFile(f, args);
+      }
+    } catch (Exception ex) {
+      ex.printStackTrace();
+      System.out.println(ex.getMessage());
+    }
+  }
+}
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/COPYING
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/COPYING	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/COPYING	(revision 10506)
@@ -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: /tags/gsdl-2_61-distribution/gsdl/packages/mg/INSTALL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/INSTALL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/INSTALL	(revision 10506)
@@ -0,0 +1,176 @@
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/INSTALL.mg
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/INSTALL.mg	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/INSTALL.mg	(revision 10506)
@@ -0,0 +1,38 @@
+                     BUILDING AND INSTALLATION OF MG
+                     ===============================
+ 
+This file explains how to build the mg system.
+ 
+(1) Follow the general GNU install instructions in the INSTALL file.
+    NOTE: this procedure has changed from version mg-1.1 which did
+    not use a GNU configure script.
+    e.g.
+      cd ~/mg-1.2
+      ./configure --prefix=`pwd`
+      make
+      make check
+      make install
+    Report portability problems to tes@kbs.citri.edu.au .
+ 
+(2) You will need to set the environment variable MGDATA which 
+    indicates where the mg data files will be created. You will also
+    need to create the directory you specify.
+ 
+    e.g.
+        setenv MGDATA ~/mgdata
+	mkdir ~/mgdata
+
+(4) You may also need to set the environment variable MGSAMPLE which
+    is used by mg_get and indicates where the sample data included
+    with this package is located.
+    If this is not specified it defaults to ``./SampleData''
+
+(4) Included with mg is an X11 interface to mgquery called xmg. 
+    Xmg is a ``wish'' script which uses the Tcl/Tk packages available
+    by anonymous ftp from allspice.berkeley.edu [128.32.150.27].
+ 
+(5) Another environment variable that you may wish to set is
+    MGIMAGEVIEWER, this variable sets the image viewer to be used
+    to display images. The image viewer must take the image from stdin.
+    If this is not specified it defaults to ``xv -''.
+ 
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/MODIFICATIONS
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/MODIFICATIONS	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/MODIFICATIONS	(revision 10506)
@@ -0,0 +1,1023 @@
+TITLE
+  Parsing of Long Words
+APPLICATION
+ mg-1, mg-2
+TYPE
+  bug
+REPORT
+  tim@cosc.canterbury.ac.nz - May 11th 1994
+FIX
+  tes@kbs.citri.edu.au - August 9th 1994
+CLAIM
+  Mg didn't handle long words properly; it crashed.
+PROBLEM
+  Invf passes calls PARSE_LONG_WORD [words.h] which uses a limit of
+  MAXLONGWORD on iterating thru the string and storing into 
+  a word. MAXLONGWORD = 8192.
+  However, mg strings generally store the length in the first
+  byte limiting them to 255 characters. The word which was passed
+  to PARSE_LONG_WORD was an allocated string of MAXSTEMLEN = 255,
+  which is as large as we should get anyway. Thus when accessing
+  a larger word than 255 chars, PARSE_LONG_WORD would allow it
+  (less than 8192) and would try storing beyond the array limit.
+SOLUTION
+  The author can't remember why PARSE_LONG_WORD was used and what
+  the significance of MAXLONGWORD = 8192 is.
+  So PARSE_LONG_WORD has been changed to PARSE_STEM_WORD which
+  uses MAXSTEMLEN as its limit.
+FILES
+ *   words.h
+ *   invf.pass1.c
+ *   invf.pass2.c
+ *   ivf.pass1.c
+ *   ivf.pass2.c
+ *   query.ranked.c
+*************************************************************
+TITLE
+  Use of Lovins stemmer
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  local - 1994
+FIX
+  linh@kbs.citri.edu.au - 1994
+CLAIM
+  Stemming was done naively.
+PROBLEM
+  Only a few types of words and their endings
+  were considered.
+SOLUTION
+  Replacement with a more elaborate "known" stemmer by Lovins.
+  The algorithm is described in:
+    J.B. Lovins, "Development of a Stemming Algorithm",
+    Mechanical Translation and Computational Linguistics, Vol 11,1968.
+FILES
+ *   stem.c
+ *   stem.h
+*************************************************************
+TITLE
+  Different term parsing
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - 23 Aug 1994
+FIX
+  tes@kbs.citri.edu.au - 23 Aug 1994
+CLAIM
+  Boolean queries did not extract words/terms using the
+  same method as is done at inverted-file creation and
+  as is used for rank query parsing.
+PROBLEM
+  The hand-written lex. analyser, query_lex, which is called by
+  the boolean query parser was not calling a common
+  word-extraction routine as used by the rest of mg. 
+  This would be ok if the code did the same things - but they didn't.
+  Query_lex, for instance, did NOT place any limit on the
+  number of digits in a term.
+  Of even more concern, it would allow arbitrary sized words
+  although it used Pascal style strings which store the length
+  in the first byte and can therefore only be 255 characters in length.
+SOLUTION
+  Query_lex in "query.bool.y", was modified to call the routine
+  PARSE_STEM_WORD which is also used by text-inversion routines and
+  ranking query routines.
+  Now all terms are extracted by the same routine.
+  To do this, the end of the line buffer had to be noted as
+  PARSE_STEM_WORD requires a pointer to the end - which is the
+  safe thing to do (don't want to run over the end).
+  This meant I had to find the length of the query line buffer.
+  This was allocated in the file "read_line.c" by the routine,
+  "readline". Its size was the literal number 1024. 
+  This was changed to a constant and placed in "read_line.h".
+  The definition for PARSE_STEM_WORD can be found in "words.h".
+FILES
+ *   query.bool.y
+ *   query.bool.c (by bison)
+ *   read_line.c
+ *   read_line.h
+*************************************************************
+TITLE
+  Highlighting of query terms
+APPLICATION
+  mg-1
+TYPE
+  extend
+REPORT
+  tes@kbs.citri.edu.au - Aug 94
+FIX
+  tes@kbs.citri.edu.au - Sep 94
+CLAIM
+  Difficult to feel happy that the query-result returned is
+  satisfying the query - need to look hard to find the queried words.
+  Need to show words in results using some highlighting method.
+PROBLEM
+  No highlighting of query terms in results.
+SOLUTION
+  Mgquery was previously outputting the decompressed text to a pager
+  such as "less(1)" or "more(1)".
+  (Except when redirected or piped elsewhere :)
+  So what was needed was some sort of highlight pager that instead of
+  displaying the text would also use some means for highlighting the
+  stemmed query words. 
+  Two common forms of highlighting were chosen: underline and bolding.
+  These are supported by "less(1)" and possibly by "more(1)" by
+  using the backspace character.
+  A highlight pager will also need to know which words need to be
+  highlighted. Therefore, the code was modified to build up a
+  string of the stemmed query words for passing to the highlight pager.
+  Design Options:
+  ---------------
+    * Could do text filtering in mgquery before passing out to pager.
+      Instead I pipe to a separate process, the "hilite_words" pager,
+      which filters and pipes into less/more.
+    * Could do different highlighting or a combination.
+    * Could use a different structure for storing the query words other
+      than the hash-table I used.
+FILES
+ *   Makefile - to include hilite_words target
+ *   mg_hilite_words.c
+ *   mgquery.c
+ *   mgquery.1
+ *   query.bool.y
+ *   query.ranked.c
+ *   environment.c
+ *   environment.h
+ *   backend.h
+*************************************************************
+TITLE
+  Mg_compression_dict did premature free
+APPLICATION
+  mg-1
+TYPE
+  bug 
+REPORT
+  R.Sosic@cit.gu.edu.au - 23 Sep 94
+FIX
+  R.Sosic@cit.gu.edu.au - 23 Sep 94
+CLAIM
+  mg_compression_dict dumped core in 
+	file: mg_compression_dict.c
+	function: Write_data
+	line: int codelen = hd->clens[i];
+PROBLEM
+  Huffman data, hd, was freed *before* it was accessed again. 
+SOLUTION
+  The freeing of hd has been moved to after all accesses
+  (just before returning).
+FILES
+ *   mg_compression_dict.c
+*************************************************************
+TITLE
+  Boolean tree optimising rewrite
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  sosic@kurango.cit.gu.edu.au - 23 Sep 94
+FIX
+  tes@kbs.citri.edu.au - Oct 94
+CLAIM
+  "I am still getting core dump in "and" queries in mgquery, 
+   where the first word does not exist, but the second one does."
+PROBLEM
+  Having freed a particular node, it tried to refree it and 
+  access one of its fields.
+
+  I.e. code-fragment...
+
+       FreeNode(curr); /* where curr = CHILD(base) for 1st term in list */
+       FreeNodes(next);
+       FreeNodes(CHILD(base)); 
+              /* but CHILD(base) has already been freed above */
+              /* if the node was the first one in the list */
+
+SOLUTION
+  A number of things in the code seemed a bit dubious to me.
+  So I have rewritten the boolean optimising stage and abstracted out
+  the various stages - each file starts with "bool".
+  Boolean query optimising seems to be a tricky problem. 
+  It is not clear that putting an expression into a certain form will
+  actually simplify it and whether simplification means faster querying.
+  I have converted a given boolean expression into DNF 
+  (Disjunctive Normal Form).  "And not" nodes, which are readily apparent 
+  in DNF, are converted to "diff" nodes.  I have only applied the idempotency 
+  laws involving TRUE and FALSE, and not the ones requiring matching of 
+  expressions - it is a potentially more complicated problem.
+  The optimiser has been tested by playing with "bool_tester", and if you are
+  having a crash or problem in a boolean query it would be worth testing the
+  query on the "bool_tester." The token "*" stands for TRUE (or all documents) 
+  and the token "_" stands for FALSE (or no documents). This should show the 
+  expression before and after optimisation in an ascii tree bracketting format.
+FILES
+ *   bool_tree.c
+ *   bool_parser.y
+ *   bool_optimiser.c
+ *   bool_query.c 
+ *   bool_tester.c
+ *   term_lists.c
+*************************************************************
+TITLE
+  Mgtic pixel placement
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  Bruce McKenzie - bruce@cosc.canterbury.ac.nz (21st Oct 1994)
+FIX
+  singlis@cs.waikato.ac.nz
+CLAIM
+  mgtic crashed on certain files.
+PROBLEM
+  Placing pixels outside of bitmap.
+SOLUTION
+  Changed the putpixel routine to truncate at borders of the image.
+FILES
+ *   mgtic.c
+*************************************************************
+TITLE
+  Improved boolean tree optimising
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  tes@kbs.citri.edu.au - 12/Dec/94
+FIX
+  tes@kbs.citri.edu.au - 21/Dec/94, 14/Mar/95
+CLAIM
+  Optimising by conversion to DNF is not necessarily such
+  a good idea - can actually slow things down.
+PROBLEM
+  The distributive law used in converting to DNF
+  duplicates expressions.
+SOLUTION
+  Introduce a query environment variable, optimise_type = 0 | 1 | 2.
+  Type 0 does nothing to the parse tree. 
+  Type 2 does the DNF conversion.
+  Type 1 is the new default and does the following...
+    Do simple tree rearrangement like flattening. 
+    Optimise for CNF queries.
+FILES
+ *   bool_query.c, .h
+ *   bool_optimiser.c
+ *   environment.c
+ *   invf_get.c
+ *   bool_tree.c, .h
+ *   bool_tester.c
+ *   lists.h
+*************************************************************
+TITLE
+  Similarity variants
+APPLICATION
+  mg-2
+TYPE
+  extend
+REPORT
+  jz@kbs.citri.edu.au/alistair - June 1994
+FIX
+  tes@kbs.citri.edu.au - July 1994 .. Feb 1995
+CLAIM
+  Can only use one type of similarity measure - the
+  standard cosine measure.
+PROBLEM
+  See CITRI/TR-95-3 for more details.
+  The standard measure can be broken up into 7 components.
+  The 7 components are  
+  Each one of these components has a number of alternatives.
+  The overall measure, S_qd, can also be altered.
+  Thus the particular similarity measure used can be specified
+  by an 8 dimensional vector.
+  What is desired is to be able to specify to mgquery an option
+  and a 8-digit string representing this vector (assuming that
+  any one alternative can have at most 9 (not using zero) variants).
+SOLUTION
+  The programs which had to be modified were:
+  (i) mgquery,
+  (ii) mg_weights_build.
+  The other mg programs in existence store the text, indexing info,
+  and the basic statistics such as N, n, ft, fdt.  
+  Other programs which had to be created were:
+  (i) mg_fmd_build,
+  (ii) mg_wt_build.
+  Mg_fmd_build will create the file to store the f_md statistic, 
+  where f_md is the largest (maximum) f_dt of any term in document, d.
+  Mg_wt_build will create the file to store the w_t primitive.
+  It only creates this for the w_t variants 6-9 which would require
+  extra passes of invf at query time if they were not stored here.
+  For details on similarity changes for mgquery and mg_weights_build,
+  please see the other modification entries.  
+FILES
+ *   mg_fmd_build.c
+ *   mg_wt_build.c
+ *   build_lib.c, build_lib.h
+*************************************************************
+TITLE
+  Similarity variants for mgquery
+APPLICATION
+  mg-2
+TYPE
+  extend
+REPORT
+  jz@kbs.citri.edu.au/alistair - June 1994
+FIX
+  tes@kbs.citri.edu.au - July 1994 .. Feb 1995
+CLAIM
+  "mgquery" needs to be altered to allow modification of
+  the similarity measure. 
+PROBLEM
+  See CITRI/TR-95-3 for more details.
+SOLUTION
+
+  Most of the similarity measures, Sqd, are of the 
+  form:   Aqd
+         -----
+          Bqd
+  where Bqd is an expression involving Wd and possibly Wq,
+  where Aqd is a sum over the common document/query terms
+  of w_qt and w_dt.
+  Building of Aqd
+  ===============
+  The calculation of Aqd is done in the file build_Aqd.c .
+  The functions for doing this used to be in the file invf_get.c .
+  Build_Aqd.c contains 4 different functions for building Aqd, each
+  of them building a different data structure:
+    (i) Array, (ii) Splay Tree, (iii) Hash Table, (iv) List Table.
+  Each of these routines seems to have been construction by modifications
+  to duplicated code. This is often the easiest way to construct variants
+  but is quite difficult to maintain consistency. 
+  As the aim of the exercise was to try out different sim. measures for
+  retrieval effectiveness, I only modified the code that constructed
+  an array. This routine was called "CosineDecode"; I changed it to
+  "build_Aqd_Array." This change reflects the fact that we are only 
+  calculating Aqd and this need not be used for the Cosine measure.
+  The other routines: "CosineDecodeSplay," "CosineDecodeHash," and
+  "CosineDecodeList" have been left unaltered - they need to be updated
+  in the future which would be best be done by abstracting out common code.
+  By the stage of building Aqd, the query terms have been looked up in
+  the inverted file dictionary and put into a list.
+  This list of common terms is traversed to lookup the corresponding
+  invf entries. Before the invf entry is processed, all query and term
+  relevant statistics and primitive quantities are calculated.
+  For example, fqt, ft, wt, rqt, wqt, Wq-partial-sum.
+  To save unnecessary calculations, there is a test for each value
+  to see whether it is needed e.g. "if (sim->variant_needs & NEEDS_wt) ... ".  
+  Aside: Variant Needs
+  --------------------
+  The idea behind the "variant_needs" field is to be able to have all
+  the code in the one place for each possible variant and this code would
+  get the information at the correct time/place only when it is needed.
+  The overhead is a "bit-and" and "test" for each component.
+  The important concern though, is that the "variant_needs" must be
+  accurate i.e. it should be carefully maintained.
+  Each possible need is stored as a bit position in a constant/macro
+  of the form "NEEDS_component" e.g. NEEDS_wt, NEEDS_nt 
+  More recently (Jan/95), I have found that the _need_ing of a component
+  may be relevant to a particular purpose, that is, it may be needed in
+  one situation and not another. This was the case for Wd. 
+  For rdt#6, Wd was needed, however, it might not be needed for Bqd, the
+  denominator of Sqd. So I changed from NEEDS_Wd to NEEDS_Wd_for_Sqd and
+  NEEDS_Wd_for_rdt. 
+  --------------------
+  To handle the different calculations of the variants, I wrote macros
+  based around a switch statement. All these macros are stored in the file
+  "similarity.h" . The point of doing this is to centralise most of the changes
+  and cut down on the number of files which have to be altered if a new
+  way of calculating a primitive is to be added.  
+  This is achieved by having a data record called, "Similarity_variant" whose
+  fields includes all the statistics and the similarity primitives.
+  So the standard procedure is to see if something is needed and if so, then
+  extract it from an mg file or calculate it using a macro - most of the
+  input and output to the macro is done via the "Similarity_variant" structure.
+  As well as calculating Aqd, it is also a convenient place to calculate Wq.
+  Previously, for Cosine measure, Wq was not needed because each Aqd was directly
+  divided by Wq and thus would not change the ordering. However, there are
+  some Sqd's which divide by a sum involving Wq and thus need Wq. 
+  Calculating Sqd and Ordering Documents
+  ====================================== 
+  The file query.ranked.c contains the code for calculating Sqd using the
+  approximate Wd in order to do the ranking of the documents.
+  The mg-1 file was cleaned up and modified slightly.
+  All the heap data structures and routines were taken out and placed in 
+  their own file, heap_weights.c/.h .
+  The major components/steps in the ranking process were abstracted into
+  macros and functions:
+    calc_MaxParas
+    insert_heap_entry
+    insert_greater_heap_entry
+    approx_guided_insert
+    fill_initial_heap
+    add_heap_remainders
+    change_heap_to_exact
+    add_remainder_exact_weights
+    Make_Exact_Root
+    build_doc_list
+  Aside: Zeroing of an Aqd Element
+  -------------------------
+  One interesting change concerned the use of zeroing out an Aqd element
+  so as to mark it as being used in the heap.
+  In the heap, the approx. Sqd is stored based on Aqd/Wd-approx.
+  Later when Aqd is required, it can be extracted from the approx. Sqd
+  by muliplication of Wd-approx i.e. Aqd = Sqd-approx * Wd-approx.
+  This, however, is not always possible for the various Sqd variants.
+  So, instead of zeroing out Aqd, I decided just to make it negative.
+  -------------------------
+  In some Sqd cases, Wd and Wd-approx. are not required. In which case,
+  step 3 which calls on "change_heap_to_exact", "Heap_Build" and
+  "add_remainder_exact_weights" is not required.
+ 
+FILES
+ *    build_Aqd.c
+ *    query.ranked.c
+ *    similarity.c/.h (in libmg)
+ *    heap_weights.c/.h
+ *    backend.c/.h
+*************************************************************
+TITLE
+  Similarity variants for mg_weights_build
+APPLICATION
+  mg-2
+TYPE
+  extend
+REPORT
+  jz@kbs.citri.edu.au/alistair - June 1994
+FIX
+  tes@kbs.citri.edu.au - July 1994 .. Feb 1995
+CLAIM
+  "mg_weights_build" needs to be altered to allow modification of
+  the similarity measure.
+PROBLEM
+  See CITRI/TR-95-3 for more details.
+SOLUTION
+  The weight files which are generated for a particular similarity
+  measure have their names extended by a suffix.
+  In the case of Wd#1 no weights are generated.
+  In the case of the standard cosine weights, Wd#2, a 3 letter suffix
+  is used to represent .
+  In the case of the other Wd variants, a one letter suffix is used
+  to represent which Wd variant it is.
+  In each case, the variant input (e.g. -q 22222222) should be the whole
+  similarity variant string and the relevant fields will be extracted out.
+  This is done for consistency in code and interface. 
+  The code is fairly similar to the original.
+  A dependency check has been added so that the dates of files and the
+  type of needed files is verified before building.
+  The dependencies include, invf dictionary, invf index, invf, fmd and wt files.
+  The major change here, is the possible use of fmd and/or wt files.
+  Later when I was having to write mg_fmd_build and mg_wt_build,
+  I decided to abstract out some macros, namely:
+    Get_ft, Get_ft_Ft, loop_invf_entry,
+  which were put into "build_lib.c" .
+  "loop_invf_entry" takes a function/macro name as a parameter and applies
+  it to the sim record (with field fdt set), current doc number and modifies
+  the return value. 
+FILES
+ *   mg_weights_build.c
+ *   build_lib.c
+*************************************************************
+TITLE
+  Mgstat with non-existent files
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  tes@kbs.citri.edu.au - 10 Aug 1994
+CLAIM
+  NaNs and Infinites would be printed out by mgstat
+  if unable to open .text or .text.dict file.
+PROBLEM
+  The NaNs etc. were output in the column stating
+  the percentage size of the file compared with the
+  number of input bytes of the source text data.
+  If it couldn't read the .text file with its
+  header describing the number of source text bytes, then
+  in working out the percentage it would divide by zero.
+  Also due to some bad control flow, it wouldn't attempt to
+  open the .text file if it failed when opening 
+  the .text.dict file.
+SOLUTION
+  Only printout the percentage if we can read the header
+  from the .text file.
+  Read in text header irrespective of text dictionary file.
+FILES
+ *   mgstat.c
+*************************************************************
+TITLE
+  Boolean tree optimisations
+APPLICATION
+  mg-2
+TYPE
+  extend
+REPORT
+  (i) tes@kbs.citri.edu.au - 28/Sep/94
+  (ii) tes@kbs.citri.edu.au - 12/Dec/94
+FIX
+  (i) tes@kbs.citri.edu.au - 18/Oct/94
+  (ii) tes@kbs.citri.edu.au - 21/Dec/94
+CLAIM
+  The initial prompt for investigating the optimisation of
+  boolean queries is noted in the mg-1 mod14.txt. 
+  The code for optimising seemed to have a number of faults.
+PROBLEM
+  Boolean optimisation was unreliable.
+SOLUTION
+  Initially (in case (i) above, see mg-1/mod14.txt), I rewrote 
+  all the boolean tree and optimising code. I converted the boolean
+  expression into DNF. I did this after reading some notes about 
+  the steps involved in optimisation and they suggested standardising
+  in some normal form. I thought that DNF would be appropriate so that
+  all the terms are converted to be part of "and" expressions and be
+  evaluated quickly using skipping.
+  This, however, can suffer quite badly if the distributive law is
+  applied to often and the query expands in size. If there was
+  some sort of cacheing of invf entries, then it might not be so
+  bad otherwise there is quite an overhead on reading the same
+  invf entry more than once.
+
+  As it happens, CNF queries are reasonably common, where the user
+  queries with a conjunction of disjunctions of similes:
+    e.g. (car | automobile | vehicle) & (fast | quick | speedy)
+  This sort of CNF query expands a hell of a lot !
+  So after speaking with Justin who wanted to benchmark Atlas with Mg on
+  these sort of queries, I looked up the MG book for other ideas.
+
+  The method that I implemented was the following:
+
+  -----------------------------------------------------------------
+  Steps of tree modifications:
+    Gets literals by pushing the nots down, detecting T/F at leaves
+    and collapsing the tree by detecting  'and' of 'and's and 'or' of
+    'or's.
+    Next it looks at the or nodes and if all the children are terms
+    then it marks the or-node as such.
+    Finally, the or-term-nodes are sorted by using the sum of their
+    ft's for comparison.
+  Steps at query evaluation:
+    If it comes across an 'and' of 'or-terms' then the evaluation is
+    done noting the distributive law.
+    I.e. a & (b | c | d) = (a & b) | (a & c) | (a & d)
+    Assuming 'a' is the c-set of documents.
+    All of 'a' is tested against 'b' and matching ones are marked.
+    Next, all the unmarked members of 'a' are tested against 'c'.
+    Likewise for 'd'.
+    Now all the marked members of our c-set are kept.
+    When we do the testing, we can use the skipping in the invf entries.
+  -----------------------------------------------------------------
+
+
+  After doing this, I added the choice of which type of optimisation
+  the user wanted by adding query-environment-variable, "optimise_type".
+  Type 0 = no parse tree modification. 
+  Type 1 = Or-term recognition and CNF query evaluation optimisation. 
+  Type 2 = Put into DNF form. [generally not recommended]
+FILES
+ *   bool_tree.c
+ *   bool_parser.y
+ *   bool_optimiser.c
+ *   bool_query.c 
+ *   bool_tester.c
+ *   term_lists.c
+ *   query_env.c
+ *   invf_get.c [GetDocsOp]
+*************************************************************
+TITLE
+  nonexistent HOME bug  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  bug 
+REPORT
+  cgn@totara.cs.waikato.ac.nz - 2/May/95
+FIX
+  tes@kbs.citri.edu.au - 2/May/95
+CLAIM
+"The big problem was that mgquery crashes when the HOME environment
+ variable is not set, which is the case when it is run by the www server."
+ [...] "I expect it happens when looking for $HOME/.mgrc."
+PROBLEM
+  The result of getenv("HOME")" was used directly in
+  a sprintf call. If the environment variable HOME
+  was not in existence then null would be used.
+  In some C libraries sprintf will convert the 0
+  string into the string "(null)" on others it will core dump.
+  (For example, Solaris seems to core dump, sunos 4 seems ok).
+SOLUTION
+  The result from getenv("HOME")" is tested before
+  being used.
+FILES
+ *   commands.c
+*************************************************************
+TITLE
+  mgquery collection name preference  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  improve
+REPORT
+  cgn@totara.cs.waikato.ac.nz - 2/May/95
+FIX
+  tes@kbs.citri.edu.au - 4/May/95
+CLAIM
+ Surely something must override mquery's preference for ./bib. 
+ If MGDATA is set correctly, I think it should prefer that collection, 
+ and -d should definitely override it. 
+ I could always say -d . if I really wanted ./bib.
+PROBLEM
+Currently the priority is:
+1.  Check if ./name is a directory,
+     If so then use it as the collection directory.
+2.  Check if ./name.text is a file,
+     If so then use ./ as the collection directory.
+3.  Check if mgdir/name is a directory,
+     If so then use mgdir/name as the collection directory.
+4.  Otherwise,
+     Use mgdir/name as the database file prefix.
+     This would be the case if one used "-f alice/alice".
+     However, one would then not specify a final name argument
+     and we'd never get here. Go figure ???
+SOLUTION
+Moved step 3 to the top instead.
+FILES
+ *   mgquery.c [search_for_collection()]
+*************************************************************
+TITLE
+  Printout of query terms
+APPLICATION
+  mg-1, mg-2
+TYPE
+  extend
+REPORT
+  tes@kbs.citri.edu.au - April 95
+FIX
+  tes@kbs.citri.edu.au - April 95
+CLAIM
+  No easy way to find out the parsed and stemmed words
+  used in the query. Would like to know these words
+  so I can call a separate highlighting program to 
+  highlight these words.
+PROBLEM
+  No facility available.
+SOLUTION
+  A ".queryterms" mgquery command was added which lists
+  out the parsed/stemmed queryterms of the last query.
+FILES
+ *    commands.c (added CmdQueryTerms)
+*************************************************************
+TITLE
+  mg_getrc  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  extend
+REPORT
+  bruce@cosc.canterbury.ac.nz - 2/May/95
+FIX
+   - 
+CLAIM
+  Repeated code had to be written for different named
+  gets but really the same type of parsing required.
+  E.g. one might want to use a standard method for inserting
+  ^Bs between paragraphs for different books. One doesn't
+  want to write duplicate code for each different named book,
+  rather note that each book should be filtered "book" style.
+PROBLEM
+  There was no way of abstracting out types of filters from
+  the name of an instance of a collection.
+SOLUTION
+  Allow information to be given with <name, type, files>.
+  This extra info can be provided in a mg_getrc file.
+  See man page for mg_get for details.
+FILES
+ *    mg_get.sh
+*************************************************************
+TITLE
+  TREC DocNo file   
+APPLICATION
+  mg-2
+TYPE
+  improve
+REPORT
+  tes@kbs.citri.edu.au - 26/May/95
+FIX
+  tes@kbs.citri.edu.au - 26/May/95
+CLAIM
+  MG has problems dealing with trec docnos for trec disk 3.
+PROBLEM
+  Trec DocNos file didn't have a wide enough field
+  to handle disk 3. 
+SOLUTION
+  Allow different width fields for file.
+  It is still fixed width but a number in the header
+  says how wide the field is.
+FILES
+ *   passes/mg.special.c
+ *   query/mgquery.c
+*************************************************************
+TITLE
+  Boolean optimiser #1 with `!'  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  bug 
+REPORT
+  triffid@iconz.co.nz - 20/7/95
+FIX
+  tes@kbs.citri.edu.au - 27/7/95
+CLAIM
+  Complained about not-nodes. 
+  e.g. complained about "croquet & !hedgehog"
+PROBLEM
+  Boolean optimiser type#1 didn't convert
+  "and not"s into diff nodes.
+SOLUTION
+  Added code to convert '&!' to '-'.
+FILES
+ *   mg/bool_optimiser.c [mg-1]
+ *   query/bool_optimiser.c [mg-2]
+*************************************************************
+TITLE
+   Autoconfiguring mg-1  
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  many people - 94/95
+FIX
+  tes@kbs.citri.edu.au - Aug/95
+CLAIM
+  Portability is limited by setting up c-macros just for particular
+  machines and operating systems.
+  People had to make changes for HP, Next, Linux, Dec Alpha, ...
+PROBLEM
+  Porting was only targetting at the machines that the author had
+  access to.
+SOLUTION
+  Use GNU's autoconfigure program.
+  This allows checking of the systems features/characteristics.
+  It also allows some checking for specific machines/OS - although
+  I have not utilised this option.
+  I used GNU's tar-1.11.8 as an example to base my changes on.
+  I also used autoscan to generate the initial "configure.in".
+  The "Makefile.in"s were done very similarly to GNU tar's.
+  The "config.h" and "sysfuncs.h" files were scrapped and 
+  rewritten. The new "config.h" file is generated by the configure
+  script - it contains all the #define's for the system features.
+  The "sysfuncs.h" file wraps up a number of system headers. 
+  For example, some systems use , while some use ;
+  which one is included is decided in "sysfuncs.h".
+  I have also used GNU tar's use of ansi2knr in its Makefiles.
+  This should hopefully allow the package to work on a system with
+  only a K&R C compiler.
+  However, there are probably problems with what I have done.
+  I am concerned about <stdarg.h> for example.
+  I also noticed that "ansi2knr" require function definitions as
+  the GNU coding style recommends ie. with function name the first
+  string on the line. This prompted me to run all the package's code
+  thru GNU's indent.
+  Setting up the configure changes is difficult. It really seems
+  necessary to try the package out on many target machines so one
+  can know what is necessary.
+  A simple check target for the main Makefile has been written.
+  It is used to see if the installation is working - it does
+  not test much of the functionality of mg.
+  It does cmp's on data files and diff's on query/result files.
+FILES
+  Most of the files in the distribution.
+*************************************************************
+TITLE
+  Consistent use of stderr
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  tes@kbs.citri.edu.au - 11 August 1994
+CLAIM
+  Inconsistent use of stdout/stderr in usage messages.
+PROBLEM
+  Sometimes used "printf" and sometimes used "fprintf(stderr"
+  in usage messages.
+SOLUTION
+  All should now use "fprintf(stderr" in usage messages.
+FILES
+ *   mg_compression_dict.c
+ *   mg_compression_dict.1
+ *   mg_fast_comp_dict.c
+ *   mg_fast_comp_dict.1
+ *   mg_invf_dict.c
+ *   mg_invf_dict.1
+ *   mg_invf_dump.c
+ *   mg_invf_dump.1
+ *   mg_invf_rebuild.c
+ *   mg_invf_rebuild.1
+ *   mg_perf_hash_build.c
+ *   mg_perf_hash_build.1
+ *   mg_text_estimate.c
+ *   mg_text_estimate.1
+ *   mg_weights_build.c
+ *   mg_weights_build.1
+*************************************************************
+TITLE
+  xmg bug
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  cgn@cpsc.ucalgary.ca - 22 April 1994
+FIX
+  cgn@cpsc.ucalgary.ca - 22 April 1994
+CLAIM
+  "Serious problem in xmg, which I fear occurs whenever a query
+   doesn't return anything."
+PROBLEM
+  ??
+SOLUTION
+  [xmg.sh 201] set rank 0
+FILES
+ *   xmg.sh
+*************************************************************
+TITLE
+  Unnecessary loading of text
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - ?? August 1994
+FIX
+  tes@kbs.citri.edu.au - 12 August 1994
+CLAIM
+  Mg was loading and uncompressing text when the
+  query did not require the text.
+PROBLEM
+  There was no test for the query mode
+  before loading and uncompressing the text.
+SOLUTION
+  Only load/uncompress text if query mode
+  is for text, headers or silent(for timing).
+FILES
+ *   mgquery.c
+*************************************************************
+TITLE
+  Man page errors
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  beebe@math.utah.edu - 16 May 1994
+CLAIM
+  Man page errors.
+PROBLEM
+  See below.
+SOLUTION
+ "The mg_make_fast_dict.1 file has been renamed mg_fast_comp_dict.1,
+  and all mg_make_fast_dict strings changed to mg_fast_comp_dict in all
+  man pages.
+  A large number of errors of spelling, typography, spacing, fonts,
+  grammar, omitted words, slang, punctuation, missing man page
+  cross-references, and man-page style have been corrected."
+FILES
+ *    mg_compression_dict.1
+ *    mg_fast_comp_dict.1
+ *    mg_get.1
+ *    mg_invf_dict.1
+ *    mg_invf_dump.1
+ *    mg_invf_rebuild.1
+ *    mg_passes.1
+ *    mg_perf_hash_build.1
+ *    mg_text_estimate.1
+ *    mg_weights_build.1
+ *    mgbilevel.1
+ *    mgbuild.1
+ *    mgdictlist.1
+ *    mgfelics.1
+ *    mgquery.1
+ *    mgstat.1
+ *    mgtic.1
+ *    mgticbuild.1
+ *    mgticdump.1
+ *    mgticprune.1
+ *    mgticstat.1
+ *    xmg.1
+*************************************************************
+TITLE
+  Man page overview
+APPLICATION
+  mg-1
+TYPE
+  extend
+REPORT
+  beebe@math.utah.edu - 
+FIX
+  tes@kbs.citri.edu.au - 17 August 1994
+CLAIM
+  "Write new mg.1 file to give a brief overview of mg, with samples
+   of how to use it.  Otherwise, users are likely to be completely
+   overwhelmed by the number of programs (about 20) which might need to
+   be used, when in reality, only 2 or 3 are likely to be run by end
+   users."
+SOLUTION
+  It was thought that mg.1, written by Nelson Beebe, was very useful
+  but a bit too comprehensive for an introduction.
+  Therefore, two man files, mgintro.1 and mgintro++.1 were written
+  with the basic stuff in mgintro.1 and slightly more advanced stuff
+  in mgintro++.1 . 
+FILES
+ *   mg.1
+ *   mgintro.1
+ *   mgintro++.1 
+*************************************************************
+TITLE
+  Parse errors not bus errors
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tim@cosc.canterbury.ac.nz - 2 Jun 94
+FIX
+  tes@kbs.citri.edu.au - 19 Aug 94
+CLAIM
+  "These two queries 
+   (which I typed in before I knew what I was doing!!)
+      > The Queen of Hearts, she made some tarts
+      > "The Queen of Hearts" and "she made some tarts"
+      produced the following result:
+      mgquery : parse error
+      Bus error
+  "
+PROBLEM
+  What is expected to happen under boolean querying:
+    Query1:
+    > The Queen of Hearts, she made some tarts
+    will produce a parse error due to the comma which
+    is not a valid TERM.
+    Query2:
+    > "The Queen of Hearts" and "she made some tarts"
+    will store a post-processing string
+    of ''The Queen of Hearts" and "she made some tarts'' and
+    will have a main boolean query of the empty string.
+    This is because the postprocessing string takes in
+    everything between the first quote and the last one.
+    An empty string is illegal for the boolean grammar and
+    hence a parse error.
+  The problem stems from the fact that the processing of
+  the parse tree is carried out, even though we have a 
+  parse error. In the case of using an empty string to build
+  a parse tree, it is likely to leave the parse tree undefined.
+SOLUTION
+  As soon as we find out that there is a parse-error,
+  we abandon any processing of the parse tree.
+FILES
+ *   query.bool.y
+ *   query.bool.c (generated from query.bool.y)
+*************************************************************
+TITLE
+  Perfect hashing on small vocab
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - July 1994
+FIX
+  alistair@cs.mu.oz.au - July 1994
+CLAIM
+  Mg could not handle small collections in the case
+  where there was only a small number of unique words.
+  The perfect hash function would report an error.
+PROBLEM
+  Rounding of the arithmetic during the calculation of the
+  parameters of the perfect hash function was resulting in a
+  combination of values such that the probability of a hash
+  function being found was very small. This led to the limit
+  on the generation loop being exceeded, and eventual
+  failure.
+SOLUTION
+  By using ceiling rather than floor when converting from a
+  floating point value to an integer parameter, the arithmetic
+  is now correct for all lexicon sizes, and the probability of
+  each iteration successfully generating a hash function is
+  sufficiently great that with _very_ high probability the
+  execution loop counter will not be exceeded unless there
+  genuinely is no hash function (for example, if the lexicon
+  contains two words the same there cannot be  a hash
+  function).
+FILES
+ *   perf_hash.c
+*************************************************************
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/Makefile.in	(revision 10506)
@@ -0,0 +1,163 @@
+# Main Makefile for GNU tar.
+# Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+ 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+ 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ 
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+@SET_MAKE@
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+ 
+
+CC = @CC@
+CFLAGS = @CFLAGS@ 
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@  
+TOUCH = echo timestamp >
+ 
+bindir = $(exec_prefix)/bin
+infodir = $(prefix)/info
+libexecdir = $(exec_prefix)/libexec
+ 
+MDEFINES = 
+#CC='$(CC)' CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' LIBS='$(LIBS)' \
+#prefix='$(prefix)' exec_prefix='$(exec_prefix)' \
+#bindir='$(bindir)' libexecdir='$(libexecdir)' \
+#infodir='$(infodir)' infodir='$(infodir)' libexecdir='$(libexecdir)'
+
+#SUBDIRS = lib src/text src/images src/scripts
+SUBDIRS = lib src/text
+
+
+.SUFFIXES:
+
+all install uninstall execinstall execuninstall maninstall manuninstall: ../../config.h
+	for subdir in $(SUBDIRS); do \
+	  echo making $@ in $$subdir; \
+	  (cd $$subdir && $(MAKE) $(MDEFINES) $@) || exit 1; \
+	done
+
+# Have not written any texinfo files for the documentation yet
+#info dvi:
+#	cd doc && $(MAKE) $@
+
+check: all
+	echo making $@ in ./test directory
+	(cd ./test && $(MAKE) all) || exit 1
+	./test/testmg `pwd`
+
+mostlyclean: mostlyclean-recursive mostlyclean-local
+
+clean: clean-recursive clean-local
+
+# the toplevel Makefile already does our subdirs.
+#distclean: distclean-recursive distclean-local
+#	rm -f config.status
+distclean:
+
+maintainer-clean: maintainer-clean-recursive maintainer-clean-local
+	rm -f config.status
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	for subdir in $(SUBDIRS); do \
+	  target=`echo $@ | sed 's/-recursive//'`; \
+	  echo making $$target in $$subdir; \
+	  (cd $$subdir && $(MAKE) $$target) || exit 1; \
+	done
+
+mostlyclean-local:
+
+clean-local: mostlyclean-local
+
+distclean-local: clean-local
+	rm -f Makefile stamp-h
+
+maintainer-clean-local: distclean-local
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+distdir = $(PACKAGE)-$(VERSION)
+
+distname = $(distdir)
+
+DISTFILES = \
+INSTALL.mg INSTALL README README.port COPYING MODIFICATIONS about_mg.html \
+Makefile.in acconfig.h aclocal.m4 configure.in install-sh mkinstalldirs \
+config.guess config.sub \
+config.h.in configure stamp-h.in sysfuncs.h
+
+dist: $(DISTFILES)
+#-----------------------------------------------------------------
+	#create distribution directory
+	-rm -rf $(distdir)
+	mkdir $(distdir)
+#
+	#link in local distribution files
+	ln $(DISTFILES) $(distdir)
+#
+	#link in SampleData
+	mkdir $(distdir)/SampleData
+	(cd SampleData; $(MAKE) "distdir=../$(distdir)/SampleData" dist)
+	# link in davinci stuff
+	mkdir $(distdir)/SampleData/davinci
+	(cd SampleData/davinci; \
+	$(MAKE) "distdir=../../$(distdir)/SampleData/davinci" dist)
+	# link in bible stuff
+	mkdir $(distdir)/SampleData/bible
+	(cd SampleData/bible; \
+	$(MAKE) "distdir=../../$(distdir)/SampleData/bible" dist)
+#
+	#link in tests
+	mkdir $(distdir)/test
+	(cd test; $(MAKE) "distdir=../$(distdir)/test" dist)
+#
+	#link in docs directory
+	mkdir $(distdir)/docs
+	(cd docs; $(MAKE) "distdir=../$(distdir)/docs" dist)
+#
+	#link in lib directory
+	mkdir $(distdir)/lib
+	(cd lib; $(MAKE) "distdir=../$(distdir)/lib" dist)
+#
+	#link in src distribution files
+	mkdir $(distdir)/src
+	for dir in src/text src/images src/scripts; do \
+	  echo makeing $@ in $$dir ; \
+	  mkdir $(distdir)/$$dir; \
+	  (cd $$dir; $(MAKE) "distdir=../../$(distdir)/$$dir" $@) ; \
+	done
+#
+	# archive and compress
+	tar -chf - $(distdir) | gzip -9 > $(distname).tar.gz
+	tar -chf - $(distdir) | compress > $(distname).tar.Z
+#
+	# cleanup
+	rm -rf $(distdir)
+#-----------------------------------------------------------------
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/README	(revision 10506)
@@ -0,0 +1,156 @@
+                 MG INFORMATION RETRIEVAL SYSTEM
+                 ===============================
+
+The MG system is a suite of programs for compressing and indexing text
+and images. Most of the functionality implemented in the suite is as
+described in the book ``Managing Gigabytes:  Compressing and Indexing
+Documents and Images'', I.H. Witten, A.  Moffat, and T.C. Bell; Van
+Nostrand Reinhold, New York, 1994, ISBN 0-442-01863-0; US $54.95; call
+1 (800) 544-0550 to order.
+
+These features include:
+
+-- text compression using a Huffman-coded semi-static word-based scheme
+-- two-level context-based compression of bi-level images
+-- FELICS lossless compression of gray-scale images
+-- combined lossy/lossless compression for textual images
+-- indexing algorithms for large volumes of text in limited main memory
+-- index compression
+-- a retrieval system that processes Boolean and ranked queries
+-- an X windows interface to the retrieval system
+
+As one example, a collection of 2 Gb of text (1,700,000 documents) can
+be indexed (on a SPARC 10 Model 512) in about four hours and compressed
+in a further four hours to make a database that in total occupies less
+than 800 Mb, or 40% of the original size. This includes a full index to
+every word and number in the original text. Boolean queries such as
+``managing AND gigabytes'' run in a few seconds, and ranked queries of
+30--50 terms are evaluated in 10--30 seconds.
+
+Details of these methods and further performance results appear in the
+MG book.
+
+The MG system comes with ABSOLUTELY NO WARRANTY; for details see the
+file COPYING.
+
+Instructions on how to build and install mg are in the file INSTALL.
+
+
+** CHANGES FROM BOOK
+
+For copyright reasons the stemmer used in this distribution of MG is
+not the same as the one illustrated in Figure 3.8 on page 108 of the MG
+book.  This means that the numbers generated by the command ``mgstat
+alice'' will not match those numbers in Figure A.1 on page 394.
+Another stemmer was initially written as a simple stopgap for version
+1.0.  That stemmer has been replaced by a stemmer based on the Lovin's
+stemming algorithm for mg-1.1.
+
+The output format of ``mgstat'' has changed since Figure A.1 (page 394)
+was prepared. The same information is displayed but formatted
+differently.
+
+** MG VERSIONS
+
+The current version is mg-1.2, September 1995. The changes from earlier 
+versions are listed in the file MODIFICATIONS. This can be accessed
+with mg by building a database using ``mgbuild mods'' and can also be
+accessed from the mg web page (see below). 
+
+The mg-1.2 extensions include:
+
+-- Source modifications for use of GNU's autoconf.
+
+The mg-1.1 extensions include:
+
+-- A new highlighting mode.
+   The output mode ``hilite'' will highlight the query terms in the
+   retrieved text documents. The variable ``hilite_style'' can be set
+   to ``bold'' or ``underline''. It works best with the pager
+   ``less''.  A .mgrc to use would include:
+	.set pager less
+	.set mode hilite
+	.set hilite_style bold
+
+-- A web site containing manual pages, documentation, and a
+   mgquery demo page (utilising cgi scripts). 
+   See: http://www.kbs.citri.edu.au/mg
+   One of these pages ``about_mg.html'' is included in this
+   distribution.
+
+-- A revised mg_get script which uses a .mg_getrc file to map
+   specific collection names to filter types.  (Modifications by Bruce
+   McKenzie). See mg_get.1 for more details.
+
+-- Code to perform merging of existing databases. This code
+   was created by Shane Hudson and is documented in the mgmerge.README
+   file found in the docs subdirectory.  This code is maintained by
+   Shane Hudson (shane@cosc.canterbury.ac.nz).
+
+-- Revised man pages, including some new entries (thanks to Nelson
+   Beebe). See mg.1, mgintro.1, mgintro++.1.
+
+-- A real (rather than toy) stemmer.
+
+** PORTABILITY
+
+Please refer to "README.port".
+
+** CREDITS
+ 
+The MG development is largely the result of research collaboration
+between:
+
+        Tim C. Bell            <tim@cosc.canterbury.ac.nz>
+        Ian Witten             <ihw@cs.waikato.ac.nz>
+        Alistair Moffat        <alistair@cs.mu.oz.au>
+        Justin Zobel           <jz@cs.rmit.oz.au>
+
+The bulk of the programming work has been carried out by:
+
+        Stuart Inglis          <singlis@cs.waikato.ac.nz>
+        Craig Nevill-Manning   <cgn@cs.waikato.ac.nz>
+        Neil Sharman           <neil@kbs.citri.edu.au>
+        Tim Shimmin            <tes@kbs.citri.edu.au>
+
+In addition to these, the following people have contributed to the
+development of the MG software:
+
+        Lachlan Andrew         <lha@kbs.citri.edu.au>
+        Gary Eddy              <gary@cs.mu.oz.au>
+        Hugh Emberson          <hugh@cosc.canterbury.ac.nz>
+        Kerry Guise            <kerry@cs.waikato.ac.nz>
+	Shane Hudson           <shane@cosc.canterbury.ac.nz>
+        Linh Huynh             <linh@kbs.citri.edu.au>
+        Bohdan S. Majewski     <bohdan@cs.uq.oz.au>
+        Bruce McKenzie         <bruce@cosc.canterbury.ac.nz>
+
+In addition to these, the following people have submitted bug reports
+and suggestions/fixes:
+
+        Rex Barzee             <rex@python.cs.byu.edu>
+        Tim A.H. Bell          <bhat@cs.mu.oz.au>
+        Tim C. Bell            <tim@cosc.canterbury.ac.nz>
+        Nelson Beebe           <beebe@math.utah.edu>
+	Rodney Brown           <RBrown@cmutual.com.au>
+        Rok Sosic              <R.Sosic@cit.gu.edu.au>
+        Carl Staelin           <staelin@cello.hpl.hp.com>
+
+Development of the MG system was supported by the Australian Research
+Council; the Universities of Melbourne, Waikato, Canterbury, and
+Calgary; RMIT; and the Collaborative Information Technology Research
+Institute (Melbourne).
+
+** BUG REPORTS
+
+Send bug reports to <alistair@cs.mu.oz.au> and <tes@kbs.citri.edu.au>.
+Back-traces from gdb are always welcome but not mandatory :-)
+
+** FURTHER READING
+
+A bibliography of MG related research work appears in the files
+MG.Bibliography.ps and MG.Bibliography.bib on the ftp site and
+is accessible through the Web page.
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/README.port
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/README.port	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/README.port	(revision 10506)
@@ -0,0 +1,125 @@
+P O R T A B I L I T Y
+=====================
+
+The main development of MG is done under Solaris on a Sun sparc.
+However, we would also like MG to be reasonably portable.
+Therefore, MG-1.2 now uses a configure stript generated by GNU's autoconf.
+Below, is a list of the machines that the s/ware has been ported to. 
+Most only need the configure script and some require manual modifications 
+mentioned in the "Problems" field.
+
+------------------------------------------------------------------------- 
+** Systems which have successfully been built.
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Sun
+System:		SunOS 4.1.2 8 sun4c
+Compiler:	gcc version 2.3.3
+Problems:	none
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Sun
+System:		SunOS 4.1.2_DB 14 sun4c
+Compiler:	gcc version 2.3.3
+Problems:	none
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Sun
+System:		SunOS 4.1.3_U1 1 sun4c
+Compiler:	gcc version 2.5.7
+Problems:	none
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Sun
+System:		SunOS 5.3 Generic_Patch sun4m sparc
+Compiler:	gcc version 2.4.3
+Problems:	none
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Silicon Graphics
+System:		IRIX 5.2 02282014 IP7
+Compiler:	gcc version 2.6.3
+Problems:	none
+
+Tester:		tes@kbs.citri.edu.au
+Date:
+Machine:	Sun
+System:		SunOS 5.4 Generic_101945-27 sun4c sparc
+Compiler:	cc: SC3.0.1 13 Jul 1994
+Problems:	none
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:
+System:		SCO 3.2v4.1
+Compiler:	gcc 2.6.1
+Problems:	requires RANLIB=true, use of tcsh
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:	HP
+System:		HP-UX A.09.04 D 9000/837 415303291 64-user license
+Compiler:	HP92453-01 A.09.73 HP C Compiler
+Problems:
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:	Data General
+System:		dgux 5.4R3.00 generic AViiON mc88110 
+Compiler:	gcc 2.4.5 (dg supplied)
+Problems:	none
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:	Pyramid MIPS R3000 box
+System:		
+Compiler:	cc (vendor supplied)
+Problems:	none
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:	IBM RS6000
+System:		AIX 3.2
+Compiler:	AIX XL C Compiler/6000
+Problems:	none
+
+Tester:		RBrown@cmutual.com.au
+Date:
+Machine:	Linux 1.2.9
+System:		
+Compiler:	gcc 2.6.3
+Problems:	none
+
+-----------------------------------------------------------------------
+** Systems which have NOT successfully been built.
+
+Tester:		RBrown@cmutual.com.au, 
+		Lloyd.Parkes@vuw.ac.nz
+Date:		Oct, Nov, 1995
+Machine:	Dec Alpha OSF/1
+System:
+Compiler:	cc
+Problems: 	Many - see below.
+
+* Problems with Dec Alpha
+  - 64 bit length longs as opposed to 32 bit longs.
+  - Lloyd.Parkes@vuw.ac.nz says that there is some bit encoding problems 
+    but the decoding seems to work.
+  - RBrown@cmutual.com.au says that it will compile but will core dump
+    when  building the test database.
+  - tes.kbs.citri.edu.au says that he needs to look into the repercussions
+    of 64 bit longs, however, he does not have access to such a machine.
+		
+-----------------------------------------------------------------------
+** Other systems. 
+
+Systems other than the above may have installation problems.
+If this is the case, please send me (tes@kbs.citri.edu.au) a log of the output
+and I will modify the configuration files in an effort to fix the problems.
+
+-----------------------------------------------------------------------
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/SampleData/MODIFICATIONS
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/SampleData/MODIFICATIONS	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/SampleData/MODIFICATIONS	(revision 10506)
@@ -0,0 +1,664 @@
+TITLE
+  Parsing of Long Words
+APPLICATION
+ mg-1, mg-2
+TYPE
+  bug
+REPORT
+  tim@cosc.canterbury.ac.nz - May 11th 1994
+FIX
+  tes@kbs.citri.edu.au - August 9th 1994
+CLAIM
+  Mg didn't handle long words properly; it crashed.
+PROBLEM
+  Invf passes calls PARSE_LONG_WORD [words.h] which uses a limit of
+  MAXLONGWORD on iterating thru the string and storing into 
+  a word. MAXLONGWORD = 8192.
+  However, mg strings generally store the length in the first
+  byte limiting them to 255 characters. The word which was passed
+  to PARSE_LONG_WORD was an allocated string of MAXSTEMLEN = 255,
+  which is as large as we should get anyway. Thus when accessing
+  a larger word than 255 chars, PARSE_LONG_WORD would allow it
+  (less than 8192) and would try storing beyond the array limit.
+SOLUTION
+  The author can't remember why PARSE_LONG_WORD was used and what
+  the significance of MAXLONGWORD = 8192 is.
+  So PARSE_LONG_WORD has been changed to PARSE_STEM_WORD which
+  uses MAXSTEMLEN as its limit.
+FILES
+ *   words.h
+ *   invf.pass1.c
+ *   invf.pass2.c
+ *   ivf.pass1.c
+ *   ivf.pass2.c
+ *   query.ranked.c
+*************************************************************
+TITLE
+  Use of Lovins stemmer
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  local - 1994
+FIX
+  linh@kbs.citri.edu.au - 1994
+CLAIM
+  Stemming was done naively.
+PROBLEM
+  Only a few types of words and their endings
+  were considered.
+SOLUTION
+  Replacement with a more elaborate "known" stemmer by Lovins.
+  The algorithm is described in:
+    J.B. Lovins, "Development of a Stemming Algorithm",
+    Mechanical Translation and Computational Linguistics, Vol 11,1968.
+FILES
+ *   stem.c
+ *   stem.h
+*************************************************************
+TITLE
+  Different term parsing
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - 23 Aug 1994
+FIX
+  tes@kbs.citri.edu.au - 23 Aug 1994
+CLAIM
+  Boolean queries did not extract words/terms using the
+  same method as is done at inverted-file creation and
+  as is used for rank query parsing.
+PROBLEM
+  The hand-written lex. analyser, query_lex, which is called by
+  the boolean query parser was not calling a common
+  word-extraction routine as used by the rest of mg. 
+  This would be ok if the code did the same things - but they didn't.
+  Query_lex, for instance, did NOT place any limit on the
+  number of digits in a term.
+  Of even more concern, it would allow arbitrary sized words
+  although it used Pascal style strings which store the length
+  in the first byte and can therefore only be 255 characters in length.
+SOLUTION
+  Query_lex in "query.bool.y", was modified to call the routine
+  PARSE_STEM_WORD which is also used by text-inversion routines and
+  ranking query routines.
+  Now all terms are extracted by the same routine.
+  To do this, the end of the line buffer had to be noted as
+  PARSE_STEM_WORD requires a pointer to the end - which is the
+  safe thing to do (don't want to run over the end).
+  This meant I had to find the length of the query line buffer.
+  This was allocated in the file "read_line.c" by the routine,
+  "readline". Its size was the literal number 1024. 
+  This was changed to a constant and placed in "read_line.h".
+  The definition for PARSE_STEM_WORD can be found in "words.h".
+FILES
+ *   query.bool.y
+ *   query.bool.c (by bison)
+ *   read_line.c
+ *   read_line.h
+*************************************************************
+TITLE
+  Highlighting of query terms
+APPLICATION
+  mg-1
+TYPE
+  extend
+REPORT
+  tes@kbs.citri.edu.au - Aug 94
+FIX
+  tes@kbs.citri.edu.au - Sep 94
+CLAIM
+  Difficult to feel happy that the query-result returned is
+  satisfying the query - need to look hard to find the queried words.
+  Need to show words in results using some highlighting method.
+PROBLEM
+  No highlighting of query terms in results.
+SOLUTION
+  Mgquery was previously outputting the decompressed text to a pager
+  such as "less(1)" or "more(1)".
+  (Except when redirected or piped elsewhere :)
+  So what was needed was some sort of highlight pager that instead of
+  displaying the text would also use some means for highlighting the
+  stemmed query words. 
+  Two common forms of highlighting were chosen: underline and bolding.
+  These are supported by "less(1)" and possibly by "more(1)" by
+  using the backspace character.
+  A highlight pager will also need to know which words need to be
+  highlighted. Therefore, the code was modified to build up a
+  string of the stemmed query words for passing to the highlight pager.
+  Design Options:
+  ---------------
+    * Could do text filtering in mgquery before passing out to pager.
+      Instead I pipe to a separate process, the "hilite_words" pager,
+      which filters and pipes into less/more.
+    * Could do different highlighting or a combination.
+    * Could use a different structure for storing the query words other
+      than the hash-table I used.
+FILES
+ *   Makefile - to include hilite_words target
+ *   mg_hilite_words.c
+ *   mgquery.c
+ *   mgquery.1
+ *   query.bool.y
+ *   query.ranked.c
+ *   environment.c
+ *   environment.h
+ *   backend.h
+*************************************************************
+TITLE
+  Mg_compression_dict did premature free
+APPLICATION
+  mg-1
+TYPE
+  bug 
+REPORT
+  R.Sosic@cit.gu.edu.au - 23 Sep 94
+FIX
+  R.Sosic@cit.gu.edu.au - 23 Sep 94
+CLAIM
+  mg_compression_dict dumped core in 
+	file: mg_compression_dict.c
+	function: Write_data
+	line: int codelen = hd->clens[i];
+PROBLEM
+  Huffman data, hd, was freed *before* it was accessed again. 
+SOLUTION
+  The freeing of hd has been moved to after all accesses
+  (just before returning).
+FILES
+ *   mg_compression_dict.c
+*************************************************************
+TITLE
+  Boolean tree optimising rewrite
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  sosic@kurango.cit.gu.edu.au - 23 Sep 94
+FIX
+  tes@kbs.citri.edu.au - Oct 94
+CLAIM
+  "I am still getting core dump in "and" queries in mgquery, 
+   where the first word does not exist, but the second one does."
+PROBLEM
+  Having freed a particular node, it tried to refree it and 
+  access one of its fields.
+
+  I.e. code-fragment...
+
+       FreeNode(curr); /* where curr = CHILD(base) for 1st term in list */
+       FreeNodes(next);
+       FreeNodes(CHILD(base)); 
+              /* but CHILD(base) has already been freed above */
+              /* if the node was the first one in the list */
+
+SOLUTION
+  A number of things in the code seemed a bit dubious to me.
+  So I have rewritten the boolean optimising stage and abstracted out
+  the various stages - each file starts with "bool".
+  Boolean query optimising seems to be a tricky problem. 
+  It is not clear that putting an expression into a certain form will
+  actually simplify it and whether simplification means faster querying.
+  I have converted a given boolean expression into DNF 
+  (Disjunctive Normal Form).  "And not" nodes, which are readily apparent 
+  in DNF, are converted to "diff" nodes.  I have only applied the idempotency 
+  laws involving TRUE and FALSE, and not the ones requiring matching of 
+  expressions - it is a potentially more complicated problem.
+  The optimiser has been tested by playing with "bool_tester", and if you are
+  having a crash or problem in a boolean query it would be worth testing the
+  query on the "bool_tester." The token "*" stands for TRUE (or all documents) 
+  and the token "_" stands for FALSE (or no documents). This should show the 
+  expression before and after optimisation in an ascii tree bracketting format.
+FILES
+ *   bool_tree.c
+ *   bool_parser.y
+ *   bool_optimiser.c
+ *   bool_query.c 
+ *   bool_tester.c
+ *   term_lists.c
+*************************************************************
+TITLE
+  Mgtic pixel placement
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  Bruce McKenzie - bruce@cosc.canterbury.ac.nz (21st Oct 1994)
+FIX
+  singlis@cs.waikato.ac.nz
+CLAIM
+  mgtic crashed on certain files.
+PROBLEM
+  Placing pixels outside of bitmap.
+SOLUTION
+  Changed the putpixel routine to truncate at borders of the image.
+FILES
+ *   mgtic.c
+*************************************************************
+TITLE
+  Improved boolean tree optimising
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  tes@kbs.citri.edu.au - 12/Dec/94
+FIX
+  tes@kbs.citri.edu.au - 21/Dec/94, 14/Mar/95
+CLAIM
+  Optimising by conversion to DNF is not necessarily such
+  a good idea - can actually slow things down.
+PROBLEM
+  The distributive law used in converting to DNF
+  duplicates expressions.
+SOLUTION
+  Introduce a query environment variable, optimise_type = 0 | 1 | 2.
+  Type 0 does nothing to the parse tree. 
+  Type 2 does the DNF conversion.
+  Type 1 is the new default and does the following...
+    Do simple tree rearrangement like flattening. 
+    Optimise for CNF queries.
+FILES
+ *   bool_query.c, .h
+ *   bool_optimiser.c
+ *   environment.c
+ *   invf_get.c
+ *   bool_tree.c, .h
+ *   bool_tester.c
+ *   lists.h
+*************************************************************
+TITLE
+  Mgstat with non-existent files
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  tes@kbs.citri.edu.au - 10 Aug 1994
+CLAIM
+  NaNs and Infinites would be printed out by mgstat
+  if unable to open .text or .text.dict file.
+PROBLEM
+  The NaNs etc. were output in the column stating
+  the percentage size of the file compared with the
+  number of input bytes of the source text data.
+  If it couldn't read the .text file with its
+  header describing the number of source text bytes, then
+  in working out the percentage it would divide by zero.
+  Also due to some bad control flow, it wouldn't attempt to
+  open the .text file if it failed when opening 
+  the .text.dict file.
+SOLUTION
+  Only printout the percentage if we can read the header
+  from the .text file.
+  Read in text header irrespective of text dictionary file.
+FILES
+ *   mgstat.c
+*************************************************************
+TITLE
+  nonexistent HOME bug  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  bug 
+REPORT
+  cgn@totara.cs.waikato.ac.nz - 2/May/95
+FIX
+  tes@kbs.citri.edu.au - 2/May/95
+CLAIM
+"The big problem was that mgquery crashes when the HOME environment
+ variable is not set, which is the case when it is run by the www server."
+ [...] "I expect it happens when looking for $HOME/.mgrc."
+PROBLEM
+  The result of getenv("HOME")" was used directly in
+  a sprintf call. If the environment variable HOME
+  was not in existence then null would be used.
+  In some C libraries sprintf will convert the 0
+  string into the string "(null)" on others it will core dump.
+  (For example, Solaris seems to core dump, sunos 4 seems ok).
+SOLUTION
+  The result from getenv("HOME")" is tested before
+  being used.
+FILES
+ *   commands.c
+*************************************************************
+TITLE
+  mgquery collection name preference  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  improve
+REPORT
+  cgn@totara.cs.waikato.ac.nz - 2/May/95
+FIX
+  tes@kbs.citri.edu.au - 4/May/95
+CLAIM
+ Surely something must override mquery's preference for ./bib. 
+ If MGDATA is set correctly, I think it should prefer that collection, 
+ and -d should definitely override it. 
+ I could always say -d . if I really wanted ./bib.
+PROBLEM
+Currently the priority is:
+1.  Check if ./name is a directory,
+     If so then use it as the collection directory.
+2.  Check if ./name.text is a file,
+     If so then use ./ as the collection directory.
+3.  Check if mgdir/name is a directory,
+     If so then use mgdir/name as the collection directory.
+4.  Otherwise,
+     Use mgdir/name as the database file prefix.
+     This would be the case if one used "-f alice/alice".
+     However, one would then not specify a final name argument
+     and we'd never get here. Go figure ???
+SOLUTION
+Moved step 3 to the top instead.
+FILES
+ *   mgquery.c [search_for_collection()]
+*************************************************************
+TITLE
+  Printout of query terms
+APPLICATION
+  mg-1, mg-2
+TYPE
+  extend
+REPORT
+  tes@kbs.citri.edu.au - April 95
+FIX
+  tes@kbs.citri.edu.au - April 95
+CLAIM
+  No easy way to find out the parsed and stemmed words
+  used in the query. Would like to know these words
+  so I can call a separate highlighting program to 
+  highlight these words.
+PROBLEM
+  No facility available.
+SOLUTION
+  A ".queryterms" mgquery command was added which lists
+  out the parsed/stemmed queryterms of the last query.
+FILES
+ *    commands.c (added CmdQueryTerms)
+*************************************************************
+TITLE
+  mg_getrc  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  extend
+REPORT
+  bruce@cosc.canterbury.ac.nz - 2/May/95
+FIX
+   - 
+CLAIM
+  Repeated code had to be written for different named
+  gets but really the same type of parsing required.
+  E.g. one might want to use a standard method for inserting
+  ^Bs between paragraphs for different books. One doesn't
+  want to write duplicate code for each different named book,
+  rather note that each book should be filtered "book" style.
+PROBLEM
+  There was no way of abstracting out types of filters from
+  the name of an instance of a collection.
+SOLUTION
+  Allow information to be given with <name, type, files>.
+  This extra info can be provided in a mg_getrc file.
+  See man page for mg_get for details.
+FILES
+ *    mg_get.sh
+*************************************************************
+TITLE
+  Boolean optimiser #1 with `!'  
+APPLICATION
+  mg-1, mg-2
+TYPE
+  bug 
+REPORT
+  triffid@iconz.co.nz - 20/7/95
+FIX
+  tes@kbs.citri.edu.au - 27/7/95
+CLAIM
+  Complained about not-nodes. 
+  e.g. complained about "croquet & !hedgehog"
+PROBLEM
+  Boolean optimiser type#1 didn't convert
+  "and not"s into diff nodes.
+SOLUTION
+  Added code to convert '&!' to '-'.
+FILES
+ *   mg/bool_optimiser.c [mg-1]
+ *   query/bool_optimiser.c [mg-2]
+*************************************************************
+TITLE
+  Consistent use of stderr
+APPLICATION
+  mg-1
+TYPE
+  improve
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  tes@kbs.citri.edu.au - 11 August 1994
+CLAIM
+  Inconsistent use of stdout/stderr in usage messages.
+PROBLEM
+  Sometimes used "printf" and sometimes used "fprintf(stderr"
+  in usage messages.
+SOLUTION
+  All should now use "fprintf(stderr" in usage messages.
+FILES
+ *   mg_compression_dict.c
+ *   mg_compression_dict.1
+ *   mg_fast_comp_dict.c
+ *   mg_fast_comp_dict.1
+ *   mg_invf_dict.c
+ *   mg_invf_dict.1
+ *   mg_invf_dump.c
+ *   mg_invf_dump.1
+ *   mg_invf_rebuild.c
+ *   mg_invf_rebuild.1
+ *   mg_perf_hash_build.c
+ *   mg_perf_hash_build.1
+ *   mg_text_estimate.c
+ *   mg_text_estimate.1
+ *   mg_weights_build.c
+ *   mg_weights_build.1
+*************************************************************
+TITLE
+  xmg bug
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  cgn@cpsc.ucalgary.ca - 22 April 1994
+FIX
+  cgn@cpsc.ucalgary.ca - 22 April 1994
+CLAIM
+  "Serious problem in xmg, which I fear occurs whenever a query
+   doesn't return anything."
+PROBLEM
+  ??
+SOLUTION
+  [xmg.sh 201] set rank 0
+FILES
+ *   xmg.sh
+*************************************************************
+TITLE
+  Unnecessary loading of text
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - ?? August 1994
+FIX
+  tes@kbs.citri.edu.au - 12 August 1994
+CLAIM
+  Mg was loading and uncompressing text when the
+  query did not require the text.
+PROBLEM
+  There was no test for the query mode
+  before loading and uncompressing the text.
+SOLUTION
+  Only load/uncompress text if query mode
+  is for text, headers or silent(for timing).
+FILES
+ *   mgquery.c
+*************************************************************
+TITLE
+  Man page errors
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  beebe@math.utah.edu - 16 May 1994
+FIX
+  beebe@math.utah.edu - 16 May 1994
+CLAIM
+  Man page errors.
+PROBLEM
+  See below.
+SOLUTION
+ "The mg_make_fast_dict.1 file has been renamed mg_fast_comp_dict.1,
+  and all mg_make_fast_dict strings changed to mg_fast_comp_dict in all
+  man pages.
+  A large number of errors of spelling, typography, spacing, fonts,
+  grammar, omitted words, slang, punctuation, missing man page
+  cross-references, and man-page style have been corrected."
+FILES
+ *    mg_compression_dict.1
+ *    mg_fast_comp_dict.1
+ *    mg_get.1
+ *    mg_invf_dict.1
+ *    mg_invf_dump.1
+ *    mg_invf_rebuild.1
+ *    mg_passes.1
+ *    mg_perf_hash_build.1
+ *    mg_text_estimate.1
+ *    mg_weights_build.1
+ *    mgbilevel.1
+ *    mgbuild.1
+ *    mgdictlist.1
+ *    mgfelics.1
+ *    mgquery.1
+ *    mgstat.1
+ *    mgtic.1
+ *    mgticbuild.1
+ *    mgticdump.1
+ *    mgticprune.1
+ *    mgticstat.1
+ *    xmg.1
+*************************************************************
+TITLE
+  Man page overview
+APPLICATION
+  mg-1
+TYPE
+  extend
+REPORT
+  beebe@math.utah.edu - 
+FIX
+  tes@kbs.citri.edu.au - 17 August 1994
+CLAIM
+  "Write new mg.1 file to give a brief overview of mg, with samples
+   of how to use it.  Otherwise, users are likely to be completely
+   overwhelmed by the number of programs (about 20) which might need to
+   be used, when in reality, only 2 or 3 are likely to be run by end
+   users."
+SOLUTION
+  It was thought that mg.1, written by Nelson Beebe, was very useful
+  but a bit too comprehensive for an introduction.
+  Therefore, two man files, mgintro.1 and mgintro++.1 were written
+  with the basic stuff in mgintro.1 and slightly more advanced stuff
+  in mgintro++.1 . 
+FILES
+ *   mg.1
+ *   mgintro.1
+ *   mgintro++.1 
+*************************************************************
+TITLE
+  Parse errors not bus errors
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tim@cosc.canterbury.ac.nz - 2 Jun 94
+FIX
+  tes@kbs.citri.edu.au - 19 Aug 94
+CLAIM
+  "These two queries 
+   (which I typed in before I knew what I was doing!!)
+      > The Queen of Hearts, she made some tarts
+      > "The Queen of Hearts" and "she made some tarts"
+      produced the following result:
+      mgquery : parse error
+      Bus error
+  "
+PROBLEM
+  What is expected to happen under boolean querying:
+    Query1:
+    > The Queen of Hearts, she made some tarts
+    will produce a parse error due to the comma which
+    is not a valid TERM.
+    Query2:
+    > "The Queen of Hearts" and "she made some tarts"
+    will store a post-processing string
+    of ''The Queen of Hearts" and "she made some tarts'' and
+    will have a main boolean query of the empty string.
+    This is because the postprocessing string takes in
+    everything between the first quote and the last one.
+    An empty string is illegal for the boolean grammar and
+    hence a parse error.
+  The problem stems from the fact that the processing of
+  the parse tree is carried out, even though we have a 
+  parse error. In the case of using an empty string to build
+  a parse tree, it is likely to leave the parse tree undefined.
+SOLUTION
+  As soon as we find out that there is a parse-error,
+  we abandon any processing of the parse tree.
+FILES
+ *   query.bool.y
+ *   query.bool.c (generated from query.bool.y)
+*************************************************************
+TITLE
+  Perfect hashing on small vocab
+APPLICATION
+  mg-1
+TYPE
+  bug
+REPORT
+  tes@kbs.citri.edu.au - July 1994
+FIX
+  alistair@cs.mu.oz.au - July 1994
+CLAIM
+  Mg could not handle small collections in the case
+  where there was only a small number of unique words.
+  The perfect hash function would report an error.
+PROBLEM
+  Rounding of the arithmetic during the calculation of the
+  parameters of the perfect hash function was resulting in a
+  combination of values such that the probability of a hash
+  function being found was very small. This led to the limit
+  on the generation loop being exceeded, and eventual
+  failure.
+SOLUTION
+  By using ceiling rather than floor when converting from a
+  floating point value to an integer parameter, the arithmetic
+  is now correct for all lexicon sizes, and the probability of
+  each iteration successfully generating a hash function is
+  sufficiently great that with _very_ high probability the
+  execution loop counter will not be exceeded unless there
+  genuinely is no hash function (for example, if the lexicon
+  contains two words the same there cannot be  a hash
+  function).
+FILES
+ *   perf_hash.c
+*************************************************************
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/SampleData/Makefile
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/SampleData/Makefile	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/SampleData/Makefile	(revision 10506)
@@ -0,0 +1,4 @@
+DISTFILES = Makefile alice13a.txt.Z MODIFICATIONS 
+
+dist:
+	ln $(DISTFILES) $(distdir)
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/about_mg.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/about_mg.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/about_mg.html	(revision 10506)
@@ -0,0 +1,75 @@
+<HTML>
+<HEAD>
+<TITLE>About MG</TITLE>
+</HEAD>
+<BODY>
+<H1>About MG</H1>
+ 
+<HR SIZE=4>
+
+MG is a public domain
+indexing and retrieval system for text, images, and textual images.
+MG is covered by a 
+<a href="http://deimos.kbs.citri.edu.au/mg/intro/copying.html">GNU 
+public licence</a>.
+<P>
+MG is available for ftp <a href="ftp://munnari.oz.au/pub/mg">here</a>
+
+<H2>Developers</H2>
+
+The MG system is an embodiment of ideas developed primarily by:
+<ul>
+<li> <a href="http://www.cosc.canterbury.ac.nz/~tim">Tim C. Bell</a>,
+	University of Canterbury;
+<li> <a href="http://www.cs.mu.oz.au/~alistair">Alistair Moffat</a>,
+	University of Melbourne;
+<li> <a href="http://www.cs.waikato.ac.nz/~ihw">Ian Witten</a>,
+	University of Waikato; and
+<li> <a href="http://www.cs.rmit.edu.au/~jz">Justin Zobel</a>,
+	RMIT.
+</ul>
+
+<H2>Programmers</H2>
+
+The bulk of the programming work has been undertaken by:
+<ul>
+<li><A HREF="http://www.cs.waikato.ac.nz/~singlis/">Stuart Inglis</A>,
+       University of Waikato;
+<li><A HREF="http://www.cs.waikato.ac.nz/~cgn/">Craig Nevill-Manning</A>,
+       University of Waikato;
+<li> Neil Sharman, University of Melbourne; and
+<li> Tim Shimmin, Collaborative Information Technology Research Institute (CITRI).
+</ul>
+A full list of contributors appears
+<A HREF="http://deimos.kbs.citri.edu.au/mg/intro/mgintro.html#xtocid2063010">
+here</a>.
+
+<H2>Institutional Support</H2>
+
+The MG project has been supported by the following organisations:
+<ul>
+<li>	The Australian Research Council;
+<li>	<a HREF="http://www.citri.edu.au/">CITRI</a>, Melbourne;
+<li>	The <a HREF="http://www.cpsc.ucalgary.ca/">University
+		of Calgary</a>, Canada;
+<li>	The <a HREF="http://www.cosc.canterbury.ac.nz/">University
+		of Canterbury</a>, New Zealand;
+<li>	The <a HREF="http://www.cs.mu.oz.au/">University
+		of Melbourne</a>, Australia;
+<li>	<a HREF="http://www.cs.rmit.edu.au/">RMIT</a>, Australia; and
+<li>	The <a HREF="http://www.cs.waikato.ac.nz/">University
+		of Waikato</a>, New Zealand.
+</ul>
+
+<H2>Backpointer</H2>
+
+If you didn't just come from there, the MG home page is accessible
+<a href="http://www.kbs.citri.edu.au/mg/">here</a>.
+
+<HR SIZE=4>
+<ADDRESS>alistair@cs.mu.oz.au</ADDRESS><BR>
+ 
+</BODY>
+</HTML>
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/acconfig.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/acconfig.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/acconfig.h	(revision 10506)
@@ -0,0 +1,35 @@
+/* Special definitions for mg, processed by autoheader.
+   Created by [TS:Aug/95] 
+   by grepping for AC_DEFINE on configure.in and using the appropriate defs 
+   of acconfig.h used by GNU tar.
+*/
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define if `union wait' is the type of the first arg to wait functions.  */
+#undef HAVE_UNION_WAIT
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/aclocal.m4
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/aclocal.m4	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/aclocal.m4	(revision 10506)
@@ -0,0 +1,141 @@
+# Local additions to Autoconf macros.
+# Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+# François Pinard <pinard@iro.umontreal.ca>, 1992.
+
+# [TS:Aug/95] - chopped out the NLS stuff which I don't support
+
+## ------------------------------- ##
+## Check for function prototypes.  ##
+## ------------------------------- ##
+
+AC_DEFUN(fp_C_PROTOTYPES,
+[AC_REQUIRE([fp_PROG_CC_STDC])
+AC_MSG_CHECKING([for function prototypes])
+if test "$ac_cv_prog_cc_stdc" != no; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(PROTOTYPES)
+  U= ANSI2KNR=
+else
+  AC_MSG_RESULT(no)
+  U=_ ANSI2KNR=ansi2knr
+fi
+AC_SUBST(U)dnl
+AC_SUBST(ANSI2KNR)dnl
+])
+
+## ----------------------------------------- ##
+## ANSIfy the C compiler whenever possible.  ##
+## ----------------------------------------- ##
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so.  This macro tries various
+# options that select ANSI C on some system or another.  It considers the
+# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and
+# handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{ac_cv_prog_cc_stdc} is set to @samp{no}.  If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN(fp_PROG_CC_STDC,
+[AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(ac_cv_prog_cc_stdc,
+[ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  AC_TRY_COMPILE(
+[#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+], [int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};],
+[ac_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CFLAGS="$ac_save_CFLAGS"
+])
+AC_MSG_RESULT($ac_cv_prog_cc_stdc)
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+])
+
+## --------------------------------------------------------- ##
+## Use AC_PROG_INSTALL, supplementing it with INSTALL_SCRIPT ##
+## substitution.					     ##
+## --------------------------------------------------------- ##
+
+AC_DEFUN(fp_PROG_INSTALL,
+[AC_PROG_INSTALL
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL} -m 755'
+AC_SUBST(INSTALL_SCRIPT)dnl
+])
+
+## ----------------------------------- ##
+## Check if --with-dmalloc was given.  ##
+## ----------------------------------- ##
+
+# I just checked, and GNU rx seems to work fine with a slightly
+# modified GNU m4.  So, I put out the test below in my aclocal.m4,
+# and will try to use it in my things.  The idea is to distribute
+# rx.[hc] and regex.[hc] together, for a while.  The WITH_REGEX symbol
+# (which should also be documented in acconfig.h) is used to decide
+# which of regex.h or rx.h should be included in the application.
+#
+# If `./configure --with-regex' is given, the package will use
+# the older regex.  Else, a check is made to see if rx is already
+# installed, as with newer Linux'es.  If not found, the package will
+# use the rx from the distribution.  If found, the package will use
+# the system's rx which, on Linux at least, will result in a smaller
+# executable file.
+
+AC_DEFUN(fp_WITH_DMALLOC,
+[AC_MSG_CHECKING(if malloc debugging is wanted)
+AC_ARG_WITH(dmalloc,
+[  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz],
+[if test "$withval" = yes; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(WITH_DMALLOC)
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  AC_MSG_RESULT(no)
+fi], [AC_MSG_RESULT(no)])
+])
+
+## --------------------------------- ##
+## Check if --with-regex was given.  ##
+## --------------------------------- ##
+
+AC_DEFUN(fp_WITH_REGEX,
+[AC_MSG_CHECKING(which of rx or regex is wanted)
+AC_ARG_WITH(regex,
+[  --with-regex            use older regex in lieu of GNU rx for matching],
+[if test "$withval" = yes; then
+  ac_with_regex=1
+  AC_MSG_RESULT(regex)
+  AC_DEFINE(WITH_REGEX)
+  LIBOBJS="$LIBOBJS regex.o"
+fi])
+if test -z "$ac_with_regex"; then
+  AC_MSG_RESULT(rx)
+  AC_CHECK_FUNC(re_rx_search, , [LIBOBJS="$LIBOBJS rx.o"])
+fi
+AC_SUBST(LIBOBJS)dnl
+])
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/build_options.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/build_options.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/build_options.in	(revision 10506)
@@ -0,0 +1,2 @@
+set stem_method = 3
+set do_indexes = 1
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/config.guess
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/config.guess	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/config.guess	(revision 10506)
@@ -0,0 +1,470 @@
+#!/bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    alpha:OSF1:V*:*)
+	# After 1.2, OSF1 uses "V1.3" for uname -r.
+	echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^V//'`
+	exit 0 ;;
+    alpha:OSF1:*:*)
+	# 1.2 uses "1.2" for uname -r.
+	echo alpha-dec-osf${UNAME_RELEASE}
+        exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit 0;;
+    Pyramid*:OSx*:*:*)
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit 0 ;;
+    sun4*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:*:*)
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit 0 ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    mips:*:5*:RISCos)
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit 0 ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit 0 ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit 0 ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    AViiON:dgux:*:*)
+	if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+	     -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	fi
+ 	exit 0 ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit 0 ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit 0 ;;
+    *:IRIX:*:*)
+	echo mips-sgi-irix${UNAME_RELEASE}
+	exit 0 ;;
+    i[34]86:AIX:*:*)
+	echo i386-ibm-aix
+	exit 0 ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		sed 's/^		//' << EOF >dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+		rm -f dummy.c dummy
+		echo rs6000-ibm-aix3.2.5
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit 0 ;;
+    *:AIX:*:4)
+	if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if grep bos410 /usr/include/stdio.h >/dev/null 2>&1; then
+		IBM_REV=4.1
+	elif grep bos411 /usr/include/stdio.h >/dev/null 2>&1; then
+		IBM_REV=4.1.1
+	else
+		IBM_REV=4.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit 0 ;;
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit 0 ;;
+    9000/[3478]??:HP-UX:*:*)
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/7?? | 9000/8?7 ) HP_ARCH=hppa1.1 ;;
+	    9000/8?? )            HP_ARCH=hppa1.0 ;;
+	esac
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    3050*:HI-UX:*:*)
+	sed 's/^	//' << EOF >dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+	rm -f dummy.c dummy
+	echo unknown-hitachi-hiuxwe2
+	exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?7:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit 0 ;;
+    hp7??:OSF1:*:* | hp8?7:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit 0 ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:UNICOS:*:*)
+	echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:UNICOS:*:*)
+	echo ymp-cray-unicos
+        exit 0 ;;
+    CRAY-2:UNICOS:*:*)
+	echo cray2-cray-unicos
+        exit 0 ;;
+    hp3[0-9][05]:NetBSD:*:*)
+	echo m68k-hp-netbsd${UNAME_RELEASE}
+	exit 0 ;;
+    i[34]86:BSD/386:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:FreeBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit 0 ;;
+    *:NetBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+	exit 0 ;;
+    *:GNU:*:*)
+	echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit 0 ;;
+    *:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux
+	exit 0 ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i[34]86:DYNIX/ptx:4*:*)
+	echo i386-sequent-sysv4
+	exit 0 ;;
+    i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+	else
+		echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit 0 ;;
+    i[34]86:*:3.2:*)
+	if /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+		echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
+	elif test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-unknown-isc$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-unknown-sysv32
+	fi
+	exit 0 ;;
+    Intel:Mach:3*:*)
+	echo i386-unknown-mach3
+	exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit 0 ;;
+    M680[234]0:*:R3V[567]*:*)
+	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
+        uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4.3 && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m680[234]0:LynxOS:2.2*:*)
+	echo m68k-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit 0 ;;
+    i[34]86:LynxOS:2.2*:*)
+	echo i386-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    TSUNAMI:LynxOS:2.2*:*)
+	echo sparc-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    rs6000:LynxOS:2.2*:*)
+	echo rs6000-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >dummy.c <<EOF
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+  printf ("m68k-sony-newsos\n"); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  printf ("%s-next-nextstep%s\n", __ARCHITECTURE__,  version==2 ? "2" : "3");
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-unknown-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+  printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+  printf ("vax-dec-bsd\n"); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
+rm -f dummy.c dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit 0 ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit 0 ;;
+    c34*)
+	echo c34-convex-bsd
+	exit 0 ;;
+    c38*)
+	echo c38-convex-bsd
+	exit 0 ;;
+    c4*)
+	echo c4-convex-bsd
+	exit 0 ;;
+    esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/config.h.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/config.h.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/config.h.in	(revision 10506)
@@ -0,0 +1,171 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro.  */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function.  */
+#undef HAVE_VPRINTF
+
+/* Define if on MINIX.  */
+#undef _MINIX
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define if you have the ftime function.  */
+#undef HAVE_FTIME
+
+/* Define if you have the ftruncate function.  */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the getpagesize function.  */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the mallinfo function.  */
+#undef HAVE_MALLINFO
+
+/* Define if you have the select function.  */
+#undef HAVE_SELECT
+
+/* Define if you have the setbuffer function.  */
+#undef HAVE_SETBUFFER
+
+/* Define if you have the strcasecmp function.  */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if you have the strstr function.  */
+#undef HAVE_STRSTR
+
+/* Define if you have the strtol function.  */
+#undef HAVE_STRTOL
+
+/* Define if you have the times function.  */
+#undef HAVE_TIMES
+
+/* Define if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <memory.h> header file.  */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <ndir.h> header file.  */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/procfs.h> header file.  */
+#undef HAVE_SYS_PROCFS_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the m library (-lm).  */
+#undef HAVE_LIBM
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/config.sub
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/config.sub	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/config.sub	(revision 10506)
@@ -0,0 +1,793 @@
+#!/bin/sh
+# Configuration validation subroutine script, version 1.1.
+#   Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can. 
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+# First pass through any local machine types.
+case $1 in
+	*local*)
+		echo $1
+		exit 0
+		;;
+	*)
+	;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS (if any).
+basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+if [ $basic_machine != $1 ]
+then os=`echo $1 | sed 's/.*-/-/'`
+else os=; fi
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp )
+		os=
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-lynx)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	tahoe | i[345]86 | i860 | m68k | m68000 | m88k | ns32k | arm | pyramid \
+		| tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
+		| alpha | we32k | ns16k | clipper | sparclite | i370 | sh \
+		| powerpc | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
+		| pdp11 | mips64el | mips64orion | mips64orionel )
+		basic_machine=$basic_machine-unknown
+		;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	vax-* | tahoe-* | i[345]86-* | i860-* | m68k-* | m68000-* | m88k-* \
+	      | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
+	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+	      | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
+	      | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
+	      | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
+	      | pdp11-* | sh-* | powerpc-* | sparc64-* | mips64-* | mipsel-* \
+	      | mips64el-* | mips64orion-* | mips64orionel-* )
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-cbm
+		;;
+	amigados)
+		basic_machine=m68k-cbm
+		os=-amigados
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-cbm
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	cray2)
+		basic_machine=cray2-cray
+		os=-unicos
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i[345]86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv32
+		;;
+	i[345]86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv4
+		;;
+	i[345]86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv
+		;;
+	i[345]86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-solaris2
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+        pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pentium-*)
+		# We will change tis to say i586 once there has been
+		# time for various packages to start to recognize that.
+		basic_machine=i486-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	xmp)
+		basic_machine=xmp-cray
+		os=-unicos
+		;;
+        xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	mips)
+		basic_machine=mips-mips
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sparc)
+		basic_machine=sparc-sun
+		;;
+        cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative must end in a *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[345]* \
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
+	      | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
+	      | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \
+	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+	      | -ptx* | -coff* | -winnt*)
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	*-acorn)
+		os=-riscix1.2
+		;;
+        pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigados
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+        *-gould)
+		os=-sysv
+		;;
+        *-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+        *-sgi)
+		os=-irix
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-lynxos*)
+				vendor=lynx
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/configure
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/configure	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/configure	(revision 10506)
@@ -0,0 +1,3073 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.12 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz"
+ac_help="$ac_help
+  --with-regex            use older regex in lieu of GNU rx for matching"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.12"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=src/text/mgquery.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+
+PACKAGE=mg
+VERSION=1.3e
+
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:567: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CXX="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+  echo "$ac_t""$CXX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:598: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext <<EOF
+#line 608 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+if { (eval echo configure:612: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  ac_cv_prog_cxx_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cxx_cross=no
+  else
+    ac_cv_prog_cxx_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+  { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:638: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:643: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.C <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:652: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gxx=yes
+else
+  ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+  GXX=yes
+  ac_test_CXXFLAGS="${CXXFLAGS+set}"
+  ac_save_CXXFLAGS="$CXXFLAGS"
+  CXXFLAGS=
+  echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:667: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+  ac_cv_prog_cxx_g=yes
+else
+  ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+  if test "$ac_test_CXXFLAGS" = set; then
+    CXXFLAGS="$ac_save_CXXFLAGS"
+  elif test $ac_cv_prog_cxx_g = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-O2"
+  fi
+else
+  GXX=
+  test "${CXXFLAGS+set}" = set || CXXFLAGS="-g"
+fi
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:699: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_AWK="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+  echo "$ac_t""$AWK" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:732: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_YACC="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+  echo "$ac_t""$YACC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:764: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:793: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  ac_prog_rejected=no
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:841: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext <<EOF
+#line 851 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+if { (eval echo configure:855: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:875: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:880: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:889: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+  ac_test_CFLAGS="${CFLAGS+set}"
+  ac_save_CFLAGS="$CFLAGS"
+  CFLAGS=
+  echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:904: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+  if test "$ac_test_CFLAGS" = set; then
+    CFLAGS="$ac_save_CFLAGS"
+  elif test $ac_cv_prog_cc_g = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-O2"
+  fi
+else
+  GCC=
+  test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:961: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      for ac_prog in ginstall installbsd scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    # OSF/1 installbsd also uses dspmsg, but is usable.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1011: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1032: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1061: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1089: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1104 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1110: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1121 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1127: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&6
+echo "configure:1150: checking for AIX" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1152 "configure"
+#include "confdefs.h"
+#ifdef _AIX
+  yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:1174: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+  echo "$ac_t""yes" 1>&6
+  ISC=yes # If later tests want to check for ISC.
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  if test "$GCC" = yes; then
+    CC="$CC -posix"
+  else
+    CC="$CC -Xp"
+  fi
+else
+  echo "$ac_t""no" 1>&6
+  ISC=
+fi
+
+ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:1196: checking for minix/config.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1201 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1206: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  MINIX=yes
+else
+  echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6
+echo "configure:1244: checking for ${CC-cc} option to accept ANSI C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  cat > conftest.$ac_ext <<EOF
+#line 1260 "configure"
+#include "confdefs.h"
+#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+
+int main() {
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+; return 0; }
+EOF
+if { (eval echo configure:1272: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_prog_cc_stdc="$ac_arg"; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+CFLAGS="$ac_save_CFLAGS"
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_stdc" 1>&6
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+
+echo $ac_n "checking for function prototypes""... $ac_c" 1>&6
+echo "configure:1293: checking for function prototypes" >&5
+if test "$ac_cv_prog_cc_stdc" != no; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define PROTOTYPES 1
+EOF
+
+  U= ANSI2KNR=
+else
+  echo "$ac_t""no" 1>&6
+  U=_ ANSI2KNR=ansi2knr
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1307: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1312 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1361: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1382: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1387 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1395: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1412 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1430 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1451 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1462: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:1486: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1491 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_off_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+  cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1519: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1524 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1552: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1557 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1566: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1587: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1592 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1600: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+cat > conftest.$ac_ext <<EOF
+#line 1623 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int main() {
+ FILE *rubbish = popen("yes", "r"); 
+; return 0; }
+EOF
+if { (eval echo configure:1631: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'
+fi
+rm -f conftest*
+fi
+
+
+echo $ac_n "checking for main in -lm""... $ac_c" 1>&6
+echo "configure:1644: checking for main in -lm" >&5
+ac_lib_var=`echo m'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lm  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1652 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1659: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lm $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1692: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1697 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1705: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1730: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1738 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1749: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1771: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1779 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1790: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1813: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1818 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1826: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1843 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1861 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1882 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1893: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h limits.h sys/time.h unistd.h string.h memory.h sys/procfs.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1920: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1925 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1930: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+cat > conftest.$ac_ext <<EOF
+#line 1957 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fread" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FREAD_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 1972 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fgetc" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FGETC_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 1987 "configure"
+#include "confdefs.h"
+#include <sys/procfs.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "pr_brksize" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_PR_BRKSIZE 1
+EOF
+
+fi
+rm -f conftest*
+
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+echo "configure:2005: checking for working alloca.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2010 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:2017: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  ac_cv_header_alloca_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+echo "configure:2038: checking for alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2043 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# if HAVE_ALLOCA_H
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+ #pragma alloca
+#  else
+#   ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#   endif
+#  endif
+# endif
+#endif
+
+int main() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:2066: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  ac_cv_func_alloca_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_alloca_works=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
+if test $ac_cv_func_alloca_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca_works = no; then
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+  # that cause trouble.  Some versions do not even contain alloca or
+  # contain a buggy version.  If you still want to use their alloca,
+  # use ar to extract alloca.o from them instead of compiling alloca.c.
+  ALLOCA=alloca.o
+  cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+echo "configure:2098: checking whether alloca needs Cray hooks" >&5
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2103 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "webecray" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_os_cray=yes
+else
+  rm -rf conftest*
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+  echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2128: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2133 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2156: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+  break
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+echo "configure:2183: checking stack direction for C alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_stack_direction=0
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2191 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
+  else
+    return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+  exit (find_stack_direction() < 0);
+}
+EOF
+if { (eval echo configure:2210: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_stack_direction=1
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_stack_direction=-1
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:2233: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <<EOF
+#line 2239 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <<EOF
+#line 2257 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2279: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2284 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2301: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:2320: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2325 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2348: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:2372: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2377 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2400: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+for ac_func in ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2427: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2432 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2455: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in ftruncate strstr strcasecmp
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2482: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2487 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2510: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.o"
+fi
+done
+
+
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+echo $ac_n "checking for HP-UX needing gmalloc""... $ac_c" 1>&6
+echo "configure:2541: checking for HP-UX needing gmalloc" >&5
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  echo "$ac_t""yes" 1>&6
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  cat >> confdefs.h <<\EOF
+#define HAVE_VALLOC 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+  for ac_func in valloc
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2554: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2559 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2582: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+echo $ac_n "checking if malloc debugging is wanted""... $ac_c" 1>&6
+echo "configure:2609: checking if malloc debugging is wanted" >&5
+# Check whether --with-dmalloc or --without-dmalloc was given.
+if test "${with_dmalloc+set}" = set; then
+  withval="$with_dmalloc"
+  if test "$withval" = yes; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_DMALLOC 1
+EOF
+
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  echo "$ac_t""no" 1>&6
+fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking which of rx or regex is wanted""... $ac_c" 1>&6
+echo "configure:2630: checking which of rx or regex is wanted" >&5
+# Check whether --with-regex or --without-regex was given.
+if test "${with_regex+set}" = set; then
+  withval="$with_regex"
+  if test "$withval" = yes; then
+  ac_with_regex=1
+  echo "$ac_t""regex" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_REGEX 1
+EOF
+
+  LIBOBJS="$LIBOBJS regex.o"
+fi
+fi
+
+if test -z "$ac_with_regex"; then
+  echo "$ac_t""rx" 1>&6
+  echo $ac_n "checking for re_rx_search""... $ac_c" 1>&6
+echo "configure:2648: checking for re_rx_search" >&5
+if eval "test \"`echo '$''{'ac_cv_func_re_rx_search'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2653 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char re_rx_search(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char re_rx_search();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_re_rx_search) || defined (__stub___re_rx_search)
+choke me
+#else
+re_rx_search();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2676: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'re_rx_search`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS rx.o"
+fi
+
+fi
+
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.12"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile src/text/Makefile src/images/Makefile 
+          src/scripts/Makefile lib/Makefile  config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@CXX@%$CXX%g
+s%@AWK@%$AWK%g
+s%@YACC@%$YACC%g
+s%@CC@%$CC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@LN_S@%$LN_S%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@RANLIB@%$RANLIB%g
+s%@CPP@%$CPP%g
+s%@U@%$U%g
+s%@ANSI2KNR@%$ANSI2KNR%g
+s%@ALLOCA@%$ALLOCA%g
+s%@LIBOBJS@%$LIBOBJS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile src/text/Makefile src/images/Makefile 
+          src/scripts/Makefile lib/Makefile "}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
+ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_uB='\([ 	]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/configure.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/configure.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/configure.in	(revision 10506)
@@ -0,0 +1,98 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(src/text/mgquery.c)
+AC_CONFIG_HEADER(config.h)
+AC_ARG_PROGRAM
+
+dnl
+PACKAGE=mg
+VERSION=1.2
+
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+
+dnl Checks for programs.
+AC_PROG_CXX
+AC_PROG_AWK
+AC_PROG_YACC
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_AIX
+AC_ISC_POSIX
+AC_MINIX
+fp_C_PROTOTYPES
+AC_C_CONST
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl --- This should be in the stdc checking -----------------
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+dnl The Pyramids running SMP_DC.OSx on MIPS r3000 chips with
+dnl /usr/opt/cc3.11/bin/cc treat -Xc as full ANSI mode - no POSIX or
+dnl XOPEN extensions (like popen).
+dnl Unfortunately -D_{XOPEN,POSIX}_SOURCE can't provide all that mg
+dnl needs. So drop back to -Xa
+AC_TRY_COMPILE(
+[#include <stdio.h>
+], [ FILE *rubbish = popen("yes", "r"); ],,
+[CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'])
+fi
+dnl ----------------------
+
+
+dnl Checks for libraries.
+dnl Replace `main' with a function in -lm:
+AC_CHECK_LIB(m, main)
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h unistd.h string.h memory.h sys/procfs.h)
+AC_EGREP_HEADER(fread, stdio.h, AC_DEFINE(HAVE_FREAD_DECL))
+AC_EGREP_HEADER(fgetc, stdio.h, AC_DEFINE(HAVE_FGETC_DECL))
+AC_EGREP_HEADER(pr_brksize, sys/procfs.h, AC_DEFINE(HAVE_PR_BRKSIZE))
+
+dnl Checks for library functions.
+AC_FUNC_ALLOCA
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize)
+AC_REPLACE_FUNCS(ftruncate strstr strcasecmp)
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+AC_MSG_CHECKING(for HP-UX needing gmalloc)
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  AC_MSG_RESULT(yes)
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  AC_DEFINE(HAVE_VALLOC)
+else
+  AC_MSG_RESULT(no)
+  AC_CHECK_FUNCS(valloc)
+fi
+
+fp_WITH_DMALLOC
+fp_WITH_REGEX
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+dnl    support functions for alloca.c
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+
+AC_OUTPUT([Makefile src/text/Makefile src/images/Makefile 
+          src/scripts/Makefile lib/Makefile ], 
+[test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h])
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/Makefile
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/Makefile	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/Makefile	(revision 10506)
@@ -0,0 +1,5 @@
+DISTFILES = Makefile mgmerge.README mg_invf_dump.changes \
+  README.man mg.1 mgintro.1 mgintro++.1
+
+dist:
+	ln $(DISTFILES) $(distdir)
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/README.man
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/README.man	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/README.man	(revision 10506)
@@ -0,0 +1,1 @@
+The rest of the man files are in the respective src directories.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mg.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mg.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mg.1	(revision 10506)
@@ -0,0 +1,462 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg 1 \*(Dt CITRI
+.\"=====================================================================
+.\" Author:
+.\"     Nelson H. F. Beebe
+.\"     Center for Scientific Computing
+.\"     Department of Mathematics
+.\"     University of Utah
+.\"     Salt Lake City, UT 84112
+.\"     USA
+.\"     Email: beebe@math.utah.edu (Internet)
+.\"=====================================================================
+.if t .ds Bi B\s-2IB\s+2T\\h'-0.1667m'\\v'0.20v'E\\v'-0.20v'\\h'-0.125m'X
+.if n .ds Bi BibTeX
+.if t .ds Te T\\h'-0.1667m'\\v'0.20v'E\\v'-0.20v'\\h'-0.125m'X
+.if n .ds Te TeX
+.\"=====================================================================
+.SH NAME
+mg \- full-text inverted index support
+.\"=====================================================================
+.SH DESCRIPTION
+.B mg
+is a suite of programs that can be used to create
+and query full-text inverted indexes for a
+collection of documents.
+.PP
+An inverted index is essentially a list of
+pointers to occurrences of every word in a
+collection of documents, so that, for example, in
+a collection of Shakespeare's works, one can pose
+questions like
+.I "How often is a fool mentioned in the plays?"
+and
+.I "Are Romeo and Juliet ever mentioned in the same sentence?"
+While search utilities like the UNIX
+.BR grep (1)
+family can be used for simple queries, they suffer
+from several limitations:
+.TP \w'\(bu'u+2n
+\(bu
+Each invocation requires a separate pass over the
+documents, which becomes impossibly slow if the
+document collection is very large.
+.TP
+\(bu
+It is difficult to compose Boolean queries like
+.IR "Caesar AND Brutus AND NOT Antony" .
+.TP
+\(bu
+They provide no mechanism for ranking matches
+according to importance, which is extremely
+important when queries are complex and numerous
+matches are found.
+.TP
+\(bu
+They provide no mechanism for displaying
+surrounding context (although the Free Software
+Foundation
+implementations for the GNU Project remedy this
+with their
+.BI \-A " num"
+(after)
+and
+.BI \-B " num"
+(before)
+switches).
+.TP
+\(bu
+They provide no mechanism for searching for
+occurrences in the same paragraph, unless
+preprocessing is done on the files to wrap
+paragraphs into long lines.  Even that will often
+fail, because input buffer sizes may be limited to
+a few hundred characters.
+.TP
+\(bu
+They provide no easy way to deal with grammatical
+word-ending variants, except by explicit
+enumeration, such as searching for
+.IR compress ,
+.IR compressed ,
+.IR compresses ,
+.IR compressing ,
+and
+.IR compression .
+.PP
+Most computer users have been faced with the
+problem of finding information from a large
+collection of files, such as electronic mail,
+on-line documentation, or source code.  Inverted
+indices provide a highly-effective solution to
+this problem.
+.PP
+The
+.B mg
+software is described in Appendix A of the book
+.RS
+.nf
+Ian H. Witten, Alistair Moffat, and Timothy C. Bell
+.I "Managing Gigabytes: Compressing and Indexing Documents and Images"
+Van Nostrand Reinhold
+1994
+xiv + 429 pages
+US$54.95
+ISBN 0-442-01863-0
+Library of Congress catalog number TA1637 .W58 1994
+.fi
+.RE
+.PP
+Many of the algorithms implemented in
+.B mg
+represent significant advances over previous work,
+both in speed, and in storage requirements.  On a
+fast workstation, in tens of minutes, or a few
+hours,
+.BR mgbuild (1)
+can create an index to
+.I all
+of the words in hundreds of thousands of documents
+occupying hundreds of megabytes, or even more than
+a gigabyte, of disk space.
+.BR mgquery (1)
+can then be used to answer complex queries, with
+responses often returned in a second or less.
+.B mg
+also contains algorithms to deal with images, so
+that with a small amount of descriptive text for
+each image, it is possible to do searches in
+collections of images, and to have retrievals
+display the images using a viewer like
+.BR xv (1).
+.PP
+.B mg
+can deal with compressed text and image files and
+surprisingly, it usually runs faster than it would
+if the files were not compressed!  Thus, the
+considerable disk space savings possible from
+file compression are not lost because of the need
+for fast document search and retrieval.
+.PP
+The Free Software Foundation GNU Project
+compression utilities
+.BR gzip (1)
+and
+.BR gunzip (1)
+are recommended for general use over older
+alternatives, like
+.BR compress (1),
+because of their speed and high compression
+ratios.
+.\"=====================================================================
+.SH AVAILABILITY
+The
+.B mg
+software can be obtained via anonymous ftp to the
+Australian archive host
+.I "munnari.oz.au [128.250.1.21]"
+from the directory
+.IR "/pub/mg" .
+.\"=====================================================================
+.SH "TYPICAL USE OF mg"
+Although
+.B mg
+consists of more than 20 separate programs, many
+of which have complicated command-line options,
+take heart: most users require only two or three
+of these programs, and nothing more than a
+document name on the command line.
+.PP
+A
+.I document
+for
+.B mg
+is a fragment of text suitable for retrieval as a
+unit when it is found to contain a requested word,
+or words.  In a collection of poetry, a document
+might be a stanza, while in a novel, it could be a
+paragraph.  In an index of first lines of poems, a
+document would likely be just a single line.
+.PP
+Just what constitutes a document is decided by a
+user-modifiable UNIX shell script,
+.BR mg_get (1).
+The default script provided with the
+.B mg
+source distribution knows about these named
+document collections:
+.TP \w'mailfiles'u+2n
+.I alice
+Lewis Carroll's
+.I "Alice in Wonderland"
+book.
+.TP
+.I allfiles
+all mail files in the directory tree
+.IR $HOME/Mail ,
+including all of its nested subdirectories.
+.TP
+.I mailfiles
+individual mail messages in
+.IR $HOME/mbox
+and
+.IR $HOME/.sentmail.
+.TP
+.I davinci
+A small collection of text and images from the
+work of Leonardo da Vinci.
+.PP
+A document collection name is used by
+.B mg
+as a
+.BR csh (1)
+.I case
+statement selector, and as a subdirectory name in the
+.B $MGDATA
+directory, or the current directory, if
+.B MGDATA
+is not defined.
+.\"=====================================================================
+.SH "EXTENDING mg_get"
+This section describes how to extend
+.BR mg_get (1)
+to handle a new document collection.
+.PP
+Let us take two examples: all \*(Bi
+.I .bib
+files, and all \*(Te files, contained in
+subdirectories under the login directory.
+.PP
+For \*(Bi, each bibliographic entry will be
+considered a separate document.  In order to
+facilitate easy identification of entries, we
+shall require them to begin at the start of a
+line; the
+.BR bibclean (1)
+utility can be used to standardize the format of
+.I .bib
+files, and to validate their string values, so
+that this requirement is met.
+.PP
+For \*(Te, each paragraph will be a separate
+document, and we assume that paragraphs are
+separated by blank lines.  We assume that files
+with extensions
+.IR .atx ,
+.IR .ltx ,
+.IR .stx ,
+and
+.I .tex
+contain input to common \*(Te macro package
+variants.
+.PP
+Make a personal copy of the
+.I mg_get
+script, using the one in the
+.B mg
+source distribution
+.RI ( mg-1.0/mg/mg_get.sh ),
+or the one in the local binary program directory,
+at many sites called
+.IR /usr/local/bin/mg_get .
+.PP
+Examination of the
+.I mg_get
+script shows that each document collection name is
+used in a
+.BR csh (1)
+.I case
+statement selector, and that most of work is done
+by very simple
+.BR awk (1)
+programs that extract documents from files.  In
+your private copy of the
+.I mg_get
+file, after the line
+.PP
+.nf
+  breaksw #davinci
+.fi
+.PP
+and before the line
+.PP
+.nf
+  default:
+.fi
+.PP
+insert this new code:
+.PP
+.nf
+  case bibfiles:
+# Takes a list of files that contain BibTeX entries, and splits them up
+#   by putting ^B after each entry. Assumes that each entry
+#   begins with a line '^@'.
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text':
+      find $HOME -name '*.bib' -print | \e
+        sort | \e
+        xargs -l100 awk \e
+          '/^@/&&NR!=1{print "^B"} {print $0} END{print "^B"}'
+    breaksw #-text
+
+    case '-cleanup':
+    breaksw #-cleanup
+
+  endsw #flag
+  breaksw #bibfiles
+
+  case texfiles:
+# Takes a list of TeX files and split them up
+#   by putting ^B after each paragraph. Assumes that each entry
+#   begins with a line '^@'.
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text':
+      find $HOME -name '*x' -print | \e
+        egrep '[.]tex$|[.]ltx$|[.]atx$|[.]stx$' | \e
+        sort | \e
+        xargs -l100 nawk '   /^ *$/ {if (b!=1) printf "^B";b=1} \e
+            \e!/^ *$/ {print;b=0} \e
+            END {printf "^B"}'
+    breaksw #-text
+
+    case '-cleanup':
+    breaksw #-cleanup
+
+  endsw #flag
+  breaksw #texfiles
+.fi
+.PP
+The ^B characters here are Control-B characters,
+.I not
+caret-B pairs.
+.PP
+If you have a large number of \*(Bi or \*(Te
+files, it is likely that a list of them would be
+too long for the UNIX shell to hold in a single
+variable, or on a single command line.  Thus,
+instead of storing the output of
+.BR find (1)
+in a variable, we proceed more cautiously, and
+employ it to produce a list of the required files,
+then pipe them to
+.BR xargs (1),
+which in turn passes up to 100 filenames at a time
+to
+.BR nawk (1)
+for document selection.
+.PP
+Install this modified
+.I mg_get
+script in your private directory for executable
+programs (e.g.
+.IR $HOME/bin ),
+create a directory
+.I $HOME/mgdata
+to hold the index, issue a
+.B rehash
+command if you are using
+.BR csh (1)
+or
+.BR tcsh (1),
+ensure that
+.I mg_get
+occurs in your search path
+.I before
+any system-wide one (the command
+.BI which " mg_get"
+will tell you which version will be selected),
+then create the inverted indexes by
+.BI mgbuild " bibfiles"
+and
+.B mgbuild
+.IR texfiles .
+These commands may take several minutes to run if
+you have a lot of \*(Bi or \*(Te files, or a large
+home directory tree.  Once they are complete, you
+can then query the index with the commands
+.BI mgquery " bibfiles"
+and
+.B mgquery
+.IR texfiles .
+These should respond very rapidly.
+.PP
+In order to keep your index up-to-date, you should
+arrange for it to be recreated automatically and
+regularly, probably every night.  You can do this
+with
+.BR cron (1).
+Use the command
+.B "crontab \-e"
+to edit your
+.I crontab
+file and add two lines like this:
+.PP
+.nf
+00 04 * * * mgbuild bibfiles >$HOME/mgdata/bibfiles.log 2>&1
+15 04 * * * mgbuild texfiles >$HOME/mgdata/texfiles.log 2>&1
+.fi
+.PP
+Save the file and exit the editor.  Now, every
+night at 4am and 4:15am,
+.BR mgbuild (1)
+will reconstruct your inverted indexes, and the
+results of the builds will be saved in log files
+in your
+.I $HOME/mgdata
+directory.
+.\"=====================================================================
+.SH "SEE ALSO"
+.na
+.BR awk (1),
+.BR bibclean (1),
+.BR bibtex (1),
+.BR compress (1),
+.BR csh (1),
+.BR grep (1),
+.BR gunzip (1),
+.BR gzip (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1),
+.BR nawk (1),
+.BR tcsh (1),
+.BR tex (1),
+.BR xargs (1),
+.BR xmg (1),
+.BR xv (1).
+.\"=====================================================================
+.\" This is for GNU Emacs file-specific customization:
+.\" Local Variables:
+.\" fill-column: 50
+.\" End:
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mgintro++.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mgintro++.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mgintro++.1	(revision 10506)
@@ -0,0 +1,212 @@
+.\"------------------------------------------------------------  
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4 
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.ds r \&\s-1MG\s0
+.if n .ds - \%--
+.if t .ds - \(em
+.\"------------------------------------------------------------  
+.am SS
+.LP
+..
+.\"------------------------------------------------------------
+.TH MGINTRO++ 1 \*(Dt CITRI
+.\"--------------------------------------------------------------
+.SH NAME
+mgintro++ \- extended introduction to the MG system
+.\"-------------------------------------------------------------
+.SH DESCRIPTION
+This manual assumes the reader has already read
+.BR mgintro (1).
+.\"-------------------------------------------------------------
+.SS Creating Different Databases
+If a user wants to build databases other than for some
+predefined ones, such as "alice", "davinci", "mailfiles", "allfiles",
+then the user has a couple of choices.
+Ultimately (s)he must produce a text file with control-Bs 
+terminating the documents. 
+To do this one can produce one or more such files, or write a
+"get" command (typically in the form of a script or c program).
+.\"-------------------------------------------------------------
+.SS Using Input Files for mgbuild
+If you don't want to write a "get" script and just want to use
+one or more text files as input, then you must first generate
+the file with control-Bs. For a simple example, you could take
+any text file(s) such as "test1.txt" and "test2.txt", and use 
+.BR vi (1)
+to insert control-Bs by typing "control-V b".
+Next you should create a file with "set" statements 
+in the following form:
+.PP
+.IP
+\fBset pipe = 0 # do not use pipe - use file instead 
+.br
+\fBset input_files = 'test1.txt test2.txt'
+.LP
+Let's call this file, "build_options".
+Now issue the command:
+.IP
+.B mgbuild -s build_options test
+.LP
+This should build a database called "test" in the $MGDATA directory,
+based on the source data of "test1.txt" and "test2.txt".
+The build_options file is simply sourced by 
+.BR mgbuild (1)
+after it has set up its variables. 
+Therefore, any settings one makes in the
+build_options file will override the standard settings.
+See 
+.BR mgbuild (1) 
+for more information.
+.\"-------------------------------------------------------------
+.SS Writing A Get Program
+Instead of using files as input, it is often more convenient to 
+write a "get" program. This program is called by 
+.BR mgbuild (1)
+to get the text data with control-Bs as document terminators.
+It should take three options:
+.br
+(i) -init; (ii) -text; (iii) -cleanup.
+.br
+Get will be called with "init" first and with "cleanup" at the end.
+It will call get with "text" when it wants the text and it should
+write the text to stdout.
+.br
+See 
+.BR mg_get (1)
+for an example.
+.\"-------------------------------------------------------------
+.SS Regular Builds
+The MG system provides a static database; 
+there are no update commands.
+So if one wants to keep one's database reasonably up-to-date
+then one can have this done automatically on a regular basis by 
+.BR cron (1).
+A crontab file can be created using:
+crontab -e
+A crontab file contains lines of the form:
+.nf
+.IP
+\fBminute hour day-of-month month day-of-week shell-command.
+.LP
+.fi
+See
+.BR crontab (1)
+for more information.
+.nf
+An example crontab entry is:
+.IP
+\fB15 02 * * * mgbuild allfiles >$MGDATA/allfiles/allfiles.log 2>&1
+.LP
+.fi
+This will build up the mg database for "allfiles", your mail in
+the folders, every morning at 2:15am. 
+.\"
+.\"-------------------------------------------------------------
+.SS Command Structure
+There are 22 commands that make up the mg system. However,
+a user may only need to be aware of a few: 
+.BR mgbuild (1),
+.BR mgquery (1), 
+and perhaps
+.BR mg_get (1). 
+Many of the commands are called by 
+.BR mgbuild(1).
+The commands can be broken up into a hierarchy.
+.PP
+--------------------------------------
+.br
+MG--+--image compression
+    |  |
+    |  +--mgbilevel
+    |  |
+    |  +--mgfelics
+    |  |
+    |  +--mgtic
+    |  |
+    |  +--mgticbuild
+    |  |
+    |  +--mgticdump
+    |  |
+    |  +--mgticprune
+    |  |
+    |  +--mgticstat
+    |
+    +--text 
+       |
+       +--compression
+       |  |
+       |  +--mg_passes -T1
+       |  |
+       |  +--mg_passes -T2
+       |  |
+       |  +--mg_compression_dict
+       |  |
+       |  +--mg_fast_comp_dict
+       |
+       +--indexing
+       |  |
+       |  +--mg_passes -N1
+       |  |
+       |  +--mg_passes -N2
+       |  |
+       |  +--mg_perf_hash_build
+       |  |
+       |  +--mg_invf_dict
+       |  |
+       |  +--mg_invf_rebuild
+       |  
+       +--weights
+       |  |
+       |  +--mg_weights_build
+       |
+       +--query
+       |  |
+       |  +--mgquery
+       |
+       +--tools
+          |
+          +--mg_invf_dump
+          |
+          +--mg_text_estimate
+          |
+          +--mgdictlist
+          |
+          +--mgstat
+.br
+--------------------------------------
+.PP
+.nf
+.BR mgbuild (1)
+calls the following commands:
+.RS
+.BR mg_passes (1), mg_compression_dict (1)
+.BR mg_perf_hash_build (1), mg_invf_dict (1), mg_invf_rebuild (1)
+.BR mg_weights_build (1)
+.RE
+.fi
+.\"--------------------------------------------
+.SH SEE ALSO
+.BR mgintro (1),
+.BR mgbuild (1),
+.BR mg_get (1)
+.br
+"Guide To The \*r System", in Appendix A of the book:
+.PP
+.RS
+.nf
+Ian H. Witten, Alistair Moffat, and Timothy C. Bell
+.I "Managing Gigabytes: Compressing and Indexing Documents and Images"
+Van Nostrand Reinhold
+1994
+xiv + 429 pages
+US$54.95 
+ISBN 0-442-01863-0
+Library of Congress catalog number TA1637 .W58 1994.
+.fi
+.RE
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mgintro.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mgintro.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mgintro.1	(revision 10506)
@@ -0,0 +1,155 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.ds r \&\s-1MG\s0
+.if n .ds - \%--
+.if t .ds - \(em
+.\"------------------------------------------------------------
+.am SS
+.LP
+..
+.\"------------------------------------------------------------
+.TH MGINTRO 1 \*(Dt CITRI
+.\"--------------------------------------------------------------
+.SH NAME
+mgintro \- introduction to the MG system
+.\"--------------------------------------------------------------
+.SH DESCRIPTION
+The MG (Managing Gigabytes) system is a collection of
+programs which comprise a full-text retrieval system.
+A full-text retrieval system allows one to create a
+database out of some given documents and then do queries
+upon it to retrieve any relevant documents.
+It is "full-text" in the sense that every word in the
+text is indexed and the query operates only on this index 
+to do the searching.
+.PP
+For example, one could have a database on the book,
+"Alice in Wonderland." A document could be represented by
+each paragraph in the book.
+Having built up the "Alice" database, one could do queries
+such as "cat alice grin" and retrieve any paragraphs which
+match the query. The matching could either be boolean, that
+is the retrieved paragraphs contain a boolean expression of
+the query terms e.g. "cat alice grin"; or the matching
+could be ranked i.e. the most relevant documents to the query
+in relevance order, using some standard heuristic measure.
+.\"--------------------------------------------------------------
+.SS Motivation
+If one wants to find some particular information which
+is stored in a computer text file then one has a few alternative
+courses of action. One can operate directly on the text files
+with utilities such as grep or can process the text files into
+some form of database. Grep is generally limited to identifying
+lines by matching on regular expressions. If the collection 
+of files which grep operates on becomes large, then continual
+passes over the entire text on each query becomes expensive.
+However, its usage is simple as no auxiliary files must be created.
+.PP
+A database consists of some data and indexes into that data. By having
+indexes one can query a large database quickly. Standard databases
+divide the data up into records of fields. This means that the granularity
+of search is a field. In a full-text system, such as \*r,
+there are no fields 
+(or there is an arbitrary sized list of word fields per document) 
+and instead every word is indexed. 
+Using this method, we can except free-form information and yet be fast on searches.
+The next question is what is the overhead of this database.
+In \*r most files which are produced are in a compressed form. The
+two notable compressed files being the given data and the index, called
+an "inverted file". By compressing the files it is possible to have the
+size of the database smaller than the size of the source data.
+.\"--------------------------------------------------------------
+.SS Typical Usage
+The most common use for \*r
+has been as a search database on unix mail files.
+However, any set of text data can be used, one just needs to determine
+what constitutes a document (see 
+.BR mgintro++ (1)
+).
+\*r has also been used on large collections such
+as Comact (Commonwealth Acts of Australia) which is around 132 megabytes 
+and also on sizes up to around 2 gigabytes for TREC 
+(a mixture of collections such as the Wall Street Journal 
+and Associated Press).
+.\"--------------------------------------------------------------
+.SS Getting Started with \*r
+The first thing to do is install the package; 
+please follow the INSTALL instructions.
+Having done this, it is necessary to set a couple of environment variables.
+MGDATA should be set to a directory which is to hold subdirectories for
+each database that you build. For example: 
+.IP
+.B mkdir ~/mgdata; setenv MGDATA ~/mgdata.
+.LP
+If you want to try out building some sample databases then there is
+some sample data such as the "Alice In Wonderland" book. To make sure
+this is accessible you should set the environment variable MGSAMPLE.
+For example: 
+.IP
+.B setenv MGSAMPLE ~/mg/SampleData
+.LP
+Here, "~/mg/SampleData" should contain alice.z .
+.PP
+To build the Alice database (to be contained in $MGDATA/alice subdirectory), 
+type the command 
+.IP
+.B mgbuild alice 
+.LP
+Assuming all went well and some status messages 
+were printed indicating the build was completed, then type 
+.IP
+.B mgquery alice 
+.LP
+to query the database. 
+You can type a few words at the prompt, hit return and
+some relevant documents, Alice paragraphs, should be retrieved.
+Type ".set query ranked" to do ranking queries. Please refer to the 
+.BR mgquery (1)
+man-page for more information on the commands and options of 
+.BR mgquery (1).
+.PP
+The next thing to do is to use \*r
+on a more personal database. If you have
+your mail stored in subdirectories of ~/Mail, such as is done if you use the
+typical set up of 
+.BR elm (1), 
+then type 
+.IP
+.B mgbuild allfiles 
+.LP
+If, however, you keep all your mail in ~/mbox or ~/sentmail, then type 
+.IP
+.B mgbuild mailfiles
+.LP
+.\"--------------------------------------------------------------
+.SH AVAILABILITY
+The \*r software for SunOS 4, Solaris, HPUX, and MIPS,
+can be ftped from: munnari.oz.au [128.250.1.21] in the directory
+/pub/mg. 
+.\"--------------------------------------------------------------
+.SH SEE ALSO
+.na
+.BR mgintro++ (1),
+.BR mgbuild (1),
+.BR mgquery (1)
+.br
+"Guide To The \*r System", in Appendix A of the book:
+.PP
+.RS
+.nf
+Ian H. Witten, Alistair Moffat, and Timothy C. Bell
+.I "Managing Gigabytes: Compressing and Indexing Documents and Images"
+Van Nostrand Reinhold
+1994
+xiv + 429 pages
+US$54.95
+ISBN 0-442-01863-0
+Library of Congress catalog number TA1637 .W58 1994.
+.fi
+.RE
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mgmerge.README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mgmerge.README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/docs/mgmerge.README	(revision 10506)
@@ -0,0 +1,230 @@
+A CRASH COURSE GUIDE TO MGMERGE
+===============================
+
+Shane Hudson
+15 November 1994
+
+
+This document is intended as a note to the maintainers of mgmerge
+outlining the mgmerge utility, the changes
+that had to be made to the existing mg code to make mgmerge
+work, and the new source code for mgmerge.
+
+
+****  NOTE:    ****
+All the NEW/CHANGED files are in the file "new_mg.tar" which
+you should have received with this; files that were
+not changed are NOT in the tar file  so it will have to be
+extracted "on top of" the existing code. You'll figure it out :)
+
+
+****  DESCRIPTION:   ****
+mgmerge adds documents to an existing mg database
+without the need to rebuild the database from scratch.
+It works by building a temporary new database from the
+new documents, then merging the "old" and "new" databases
+to give one merged database.
+
+
+The source consists of:
+    mgmerge.sh		The main script, a lot like mgbuild.sh
+    mg_get_merge.sh	Script to retrieve new documents, a lot like
+			mg_get.sh
+    mg_merge.h		header file used by mg_invf_merge.c
+			and mg_text_merge.c
+    mg_text_merge.c	Program to append one compressed text file
+			to another
+    mg_invf_merge.c	Program to merge two inverted files and
+			stemmed dictionaries
+
+See the man pages for mgmerge, mg_get_merge, mg_text_merge and
+mg_invf_merge for a brief overview.
+
+mg_get_merge.sh should really be put into mg_get.sh, with a "-merge"
+option if it is being called by the mgmerge utility, but I was
+too lazy to change it to that.
+
+
+The files updated by mgmerge are:
+
+*.text			with mg_text_merge
+*.text.idx		with mg_text_merge
+*.text.idx.wgt		with mg_weights_build (after merging)
+*.invf			with mg_invf_merge
+*.invf.idx		with      "
+*.invf.dict		with      "
+*.weight		with mg_invf_merge or mg_weights_build
+*.invf.dict.blocked	with mg_invf_dict (after merging)
+
+The *.text.stats file and *.text.dict file remain the same.
+Any other database files (ie, *.invf.dict.hash)
+will be out of date after a merge and will need to be recomputed.
+
+--------------------------------------------------------------------------
+
+MG_TEXT_MERGE
+=============
+
+The two "merging" utilities are mg_text_merge and mg_invf_merge
+
+mg_text_merge simply appends the compressed text for the new
+documents to the old compressed text file.
+For this to succeed, the two files should have been created
+with the same parameters to mg_passes and the same compression
+model must be used. So *.text.dict from the old (static) database
+is used as the model for compressing the new documents.
+The default "-C" option to mg_compression_dict in mgbuild was
+changed to "-S" so novel words in the new documents can be coded.
+The option must be the same in mgmerge -- it is "-S" there too.
+
+---------------
+
+EFFECT on FILE COMPRESSION PERFORMANCE
+
+Since the compression model is not being updated,compression
+performance for the text will slowly degrade. The only solution
+is a periodic rebuild from scratch.
+
+---------------------------------------------------------------------------
+
+MG_INVF_MERGE
+=============
+
+mg_invf_merge updates the stemmed dictionary and
+inverted file.
+For reasons of simplicity, the stemmed dictionaries merged
+are in the ".invf.dict" format, NOT the ".invf.dict.blocked"
+format. 
+So if a database is to be merged the .invf.dict file should
+not be deleted after the .invf.dict.blocked file used by mgquery
+has been created.
+Also for simplicity, level 3 inverted files are not supported, nor
+are skipped format files.
+
+
+
+Merging the inverted files requires every entry in each file
+to be decoded and merged if an entry for the same term appears
+in the other inverted file.
+This can be a slow process if the old inverted file is very large.
+Especially since each entry is decoded bit-by-bit with
+the bit-level I/O rouutines.
+As was noted on page 94 of the book "Managing Gigabytes" (hereafter 
+called "MG"), switching from bernoulli coding (called "Bblock" in
+the mg source code) to gamma or delta coding for the
+inter-document gaps would be an advantage since they require no
+parameters.
+With Bblock coding, N (the number of documents) is a parameter and
+as N changes whenever documents are added, every entry must
+be decoded and recoded.
+My approach was to keep Bblock coding, but keep the N parameter
+constant by recording the artificial N  used to code document
+gaps (called "Nstatic") as well as the real number of documents.
+
+Then, any entry in the old inverted file (called "IFold") that
+is not merged with an entry in the new inverted file (called "IFnew")
+can be copied directly to the merged inverted file (called "IFmerge").
+This can give a significant increase in speed, since usually the
+size of IFnew is very small if only a few documents are being added.
+
+To store Nstatic, a field "static_num_of_docs" was added to
+the invf_dict_header and stem_dict_header structs defined
+in invf.h
+Any program that decodes inverted file entries also had to be changed.
+(The existing mg source code that I changed has been returned with
+this document.)
+Most changes were simply altering a line that
+called BIO_Bblock_Init() so it used the static_num_of_docs
+value rather than num_of_docs.
+
+So since the file format has changed, any existing collection will
+have to be rebuilt first even using mgmerge with it is not
+intended.
+
+-------------
+
+EFFECT on INVERTED FILE COMPRESSION PERFORMANCE
+
+As more merges are accumulatively performed on a database, the
+compression performance will decline.
+The solution is an option in mg_invf_merge to do a "slow"
+merge where every inverted file entry is decoded and recoded using
+the real value of N.
+This is not a lot slower than a fast merge when compared to the
+cost of completely rebuilding the collection from scratch, and 
+the option can be used periodically (when, say, 40% of the
+inverted file has been added since the previous slow merge).
+
+-----------------
+
+THE EXACT WEIGHTS FILE
+
+Recomputing exact document weights requires a complete scan over the
+merged inverted file. This is a waste since the weights for old
+documents will (hopefully) not change much anyway, and the weights
+for new documents can be computed exactly when merging the inverted files,
+at no extra time cost.
+So mg_invf_merge computes the weights for new documents and
+updates the .weight file.
+The weights for old documents are left untouched.
+mgmerge has an option to recompute the weights file.
+This is not much more expensive in terms of time, and is only
+periodically needed.
+
+The effect of leaving the old weights unchanged is difficult to
+asess since the "correct" ranking of documents for a query is
+subjective.
+The frequency with which a rebuild of the weights file with the
+"-w" option should be done is hard to guess.
+But if most merges involves only a few documents, it makes sense
+to not bother recomputing it since the change in old weights values
+is very small and the weights only stray from their "true"
+values slowly over accumulated merging.
+
+-------------------------------------------------------------------------
+
+EXPERIMENTAL RESULTS
+====================
+
+With some small test collections (only a few Mb of text)
+and a slow merge, and a weights file rebuild,
+mgmerge typically took under 20% of the time to completely
+rebuild. Using the default options (fast merge, dont rebuild weights)
+took around 10% or more.
+For larger collections, the savings were greater, especially if the
+added text is very small.
+For example, when the last 6Kb of text of the GNUBib collection was
+added to the rest of it (14Mb) using mgmerge, the total mgmerge time
+was around 20 seconds whereas a complete mgbuild took 280 seconds.
+Only one larger collection was tested (resource contraints prevented
+testing on any really large collections): two short (one-line)
+documents were added to the Gutenberg collection, which comprised
+of nearly 74Mb of source text and had an inverted file size of 9Mb.
+mgmerge took 42 seconds (or 142 seconds with a slow merge and rebuilding the
+weights file), and I'd estimate that an mgbuild on the same machine would 
+have taken at least 20 minutes.
+
+To summarise, mgmerge is not as fast as some sophisticated method
+such as the fixed-length blocks described in section 5.7 of "MG",
+but its huge advantage is that it required almost no changes to
+the existing mg code and is still far better than using mgbuild
+every time a document needs to be added to a collection.
+
+----------------------------------------------------------------------------
+
+OTHER NOTES
+===========
+
+Since it works like mgbuild, mgmerge needs mg_get_merge
+to return the SAME text each time "mg_get_merge -text .." is called.
+
+----
+
+One other thing discovered (but not fixed) was a bug in "invf.pass2.c":
+It crashes on parsed words longer than 128 characters.
+So if any text with words >128 chars is piped to mg_passes,
+the "-N1" and "-N2" options (the memory-efficient inversion method)
+had better be used and not the "-I1"/"-I2" option (which would only
+work on small collections anyway, being the memory-inefficient
+method).
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/install-sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/install-sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/install-sh	(revision 10506)
@@ -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: /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGDocInfo.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGDocInfo.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGDocInfo.java	(revision 10506)
@@ -0,0 +1,42 @@
+/*
+ *    MGDocInfo.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.mg;
+
+
+/** DocInfo 'struct' class for a search result from mg
+ *  used by MGQueryResult
+ *
+ * @See MGQueryResult
+ */
+public class MGDocInfo
+{
+    public long num_ = 0;
+    public float rank_ = 0;
+
+    public MGDocInfo(long doc, float rank)
+    {
+	num_ = doc;
+	rank_ = rank;
+    }
+
+    public String toString()
+    {
+	return "" + num_ + " (" + rank_ + ")";
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGQueryResult.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGQueryResult.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGQueryResult.java	(revision 10506)
@@ -0,0 +1,140 @@
+/*
+ *    MGQueryResult.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.mg;
+
+
+import java.util.Vector;
+
+
+/** a java version of QueryResult for mg
+ *
+ * contains get methods for the java side, and simple
+ * set methods to be called from c side
+ *
+ */
+public class MGQueryResult
+{
+    /** the list of MGDocInfo */
+    protected Vector docs_ = null;
+    /** the list of MGTermInfo */
+    protected Vector terms_ = null;
+    /** the total number of docs found - not likely to be the size of docs_ */
+    protected long total_num_docs_ = 0;
+
+
+    MGQueryResult() {
+	docs_ = new Vector();
+	terms_ = new Vector();
+    }
+
+
+    /** clear the info from the last query
+	should be called before setting any new docs/terms */
+    public void clear() {
+	total_num_docs_ = 0;
+	docs_.clear();
+	terms_.clear();
+    }
+
+
+    /** returns the result as a String - useful for printing out results */
+    public String toString()
+    {
+	String result = "";
+	result += "docs (ranks): ";
+	for (int i = 0; i < docs_.size(); i++) {
+	    if (i > 0) result += ", ";
+	    result += ((MGDocInfo) docs_.elementAt(i)).toString();
+	}
+	result += "\nterms: ";
+	for (int i = 0; i < terms_.size(); i++) {
+	    if (i > 0) result += ", ";
+	    result += ((MGTermInfo) terms_.elementAt(i)).toString();
+	}
+	result += "\nactual number of docs found = " + total_num_docs_;
+	return result;
+    }
+
+
+    /** a shorter representation - just terms and total docs - not the 
+	individual docnums and ranks */
+    public String toShortString() {
+	String result = "";
+	result += "\nterms: ";
+	for (int i = 0; i < terms_.size(); i++) {
+	    if (i > 0) result += ", ";
+	    result += ((MGTermInfo) terms_.elementAt(i)).toString();
+	}
+	result += "\nactual number of docs found = "+total_num_docs_;
+	return result;
+    }
+
+
+    // set methods used by c++ code
+
+    public void setTotalDocs(long num) {
+	total_num_docs_=num;
+    }
+
+
+    public void addDoc(long doc, float rank) {
+	MGDocInfo doc_info = new MGDocInfo(doc, rank);
+	System.out.println("(Java) Added doc " + doc_info);
+
+	docs_.add(doc_info);
+    }
+
+
+    // public void addTerm(String term, int stem, long match, long freq)
+    public void addTerm(String term, String tag, int stem,
+			long match, long freq, String[] equivs)
+    {
+	MGTermInfo ti = new MGTermInfo();
+	ti.term_ = term;
+	ti.tag_ = tag;
+	ti.stem_method_ = stem;
+	ti.match_docs_ = match;
+	ti.term_freq_ = freq;
+	if (equivs != null) {
+	    for (int i = 0; i < equivs.length; i++) {
+		ti.equiv_terms_.add(equivs[i]);
+	    }
+	}
+	System.out.println("(Java) Added term " + ti);
+
+	terms_.add(ti);
+    }
+
+
+    // Get methods for the java side - GS2MGSearch.java, GS2MGRetrieve.java
+    public Vector getDocs() {
+	return docs_;
+    }
+
+
+    public Vector getTerms() {
+	return terms_;
+    }
+
+
+    public long getTotalDocs() {
+	return total_num_docs_;
+    }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGTermInfo.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGTermInfo.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGTermInfo.java	(revision 10506)
@@ -0,0 +1,81 @@
+/*
+ *    MGTermInfo.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.mg;
+
+
+import java.util.Vector;
+
+
+/** TermInfo 'struct' class for a search result from mg
+ *  used by MGQueryResult
+ *
+ * @see MGQueryResult
+ */
+public class MGTermInfo
+{
+    /** the term itself */
+    public String term_ = null;
+
+    /** the tag - level or metadata - for which the query was done */
+    public String tag_ = null;
+
+    /** the stem and casefold method used
+	0 = none
+	1 = casefold only
+	2 = stem only
+	3 = casefold and stem */
+    public int stem_method_ = 0;
+
+    /** the number of documents containing this term
+	(where document is defined by the tag data) */
+    public long match_docs_ = 0;
+
+    /** overall term freq - word level */
+    public long term_freq_ = 0;
+
+    /** list of stemmed and casefolded equivalent terms - if stem_method_ is non-zero 
+      - Vector of Strings */
+    public Vector equiv_terms_ = null;
+
+
+    public MGTermInfo()
+    {
+	equiv_terms_ = new Vector();
+    }
+
+
+    /** output the class as a string */
+    public String toString()
+    {
+	String result = "\"" + term_ + "\"";
+	result += " tag(" + tag_ + ")";
+	result += " stem(" + stem_method_ + ")";
+	result += " docs(" + match_docs_ + ")";
+	result += " freq(" + term_freq_ + ")";
+
+	result += " equiv terms(";
+	for (int i = 0; i < equiv_terms_.size(); i++) {
+	    if (i > 0) result += ", ";
+	    result += (String) equiv_terms_.elementAt(i);
+	}
+	result += ")";
+
+	return result;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGWrapper.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGWrapper.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/MGWrapper.java	(revision 10506)
@@ -0,0 +1,102 @@
+/*
+ *    MGWrapper.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.mg;
+
+
+/** java wrapper class for access to mg in C
+ *
+ * the native side implemented in MGWrapperImpl.c
+ * uses MGQueryResult to hold the result of a query.
+ * the result of a getDocument is a String
+ * uses the jni
+ *
+ *@see MGQueryResult
+ */
+public class MGWrapper
+{
+    /** the query result, filled in by runQuery */
+    protected MGQueryResult mg_query_result_ = null;
+
+    /** pointer to c MGWrapperData class - cached indexData and queryInfo */
+    protected long mg_data_ptr_ = 0;
+
+    static {
+	System.loadLibrary("mgjni");
+	initIDs();
+    }
+
+    public MGWrapper() {
+	mg_query_result_ = new MGQueryResult();
+	initCSide();
+    }
+
+    /** initialises field and method IDs for java side to enable access on C side */
+    private static native void initIDs();
+
+    /** initialises the mg_data_ptr_ */
+    private native boolean initCSide();
+
+    /** returns a document: number docnum at level level 
+     * the base_dir and text_path paths should join together to provide
+     * the absolute location of the mg text files eg ..../index/text/demo
+     * returns the doc in utf-8
+     */
+    public native String getDocument(String base_dir, String text_dir, long docnum);
+
+    /** unloads the data */
+    public native boolean unloadIndexData();
+
+    // query param methods
+
+    /** if on=true, sets default casefolding on - it's off by default */
+    public native void setCase(boolean on);
+    /** if on=true, sets default stemming on - it's off by default */
+    public native void setStem(boolean on);
+    /** default is 50 */
+    public native void setMaxDocs(int num);
+    /** if on=true, sorts by rank, otherwise returns in build order - 
+	default is on */
+    public native void setSortByRank(boolean on);
+    /** if on=true, a query returns term freq info - default is on */
+    public native void setReturnTerms(boolean on);
+    /** sets the index to search - default is 'dtx' */
+    public native void setIndex(String index);
+    /** sets the default boolean operator - AND(=1)/OR(=0) */
+    public native void setMatchMode(int mode);
+
+    /** returns a string with all the current query param settings */
+    public native String getQueryParams();
+
+    /** actually carry out the query.
+	Use the set methods to set query results.
+	Writes the result to query_result.
+     * - maintains state between requests as can be slow  
+     * base_dir and index_path should join together to provide
+     * the absolute location of the mg index files eg ..../index/dtx/demo 
+     * base_dir must end with a file separator (OS dependant)
+     */
+    public native void runQuery(String base_dir, String text_dir, String query_string);
+
+
+    /** get the result out of the wrapper */
+    public MGQueryResult getQueryResult()
+    {
+	return mg_query_result_;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/Makefile.in	(revision 10506)
@@ -0,0 +1,64 @@
+
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+bindir = @bindir@
+srcdir = @srcdir@
+libdir = @libdir@
+subdir = java/org/greenstone/mg
+top_srcdir = @top_srcdir@
+transform = @program_transform_name@
+
+AR = ar
+CC = @CC@
+CXX = @CXX@
+JAVAC = javac
+JAVAH = javah
+JAR = jar
+CFLAGS = @CFLAGS@ -ansi -DSILENT -DSHORT_SUFFIX
+CXXFLAGS = @CXXFLAGS@ -DSILENT -DSHORT_SUFFIX
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBS =  -lstdc++ @LIBS@
+TOUCH = echo timestamp >
+AWK = @AWK@
+
+MGHOME=../../../..
+JAVALIBDIR=$(libdir)/java
+JAVACLASSDIR=./classes
+JAVASRCDIR=../../..
+JAVACOPTIONS= -deprecation -g -O
+JAVACLASSPATH=$(JAVACLASSDIR):
+
+datadir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+localedir = $(datadir)/locale
+mandir = $(prefix)/man/man1
+
+
+all: setup compile
+
+setup:
+	mkdir -p $(JAVACLASSDIR)
+
+compile: setup
+	$(JAVAC) -d $(JAVACLASSDIR) -sourcepath $(JAVASRCDIR) $(JAVACOPTIONS) *.java
+	$(JAVAH) -classpath $(JAVACLASSPATH) -d $(MGHOME)/jni org.greenstone.mg.MGWrapper
+	$(JAR) cf mg.jar -C $(JAVACLASSDIR) org
+
+clean:
+	rm -rf $(JAVACLASSDIR) mg.jar $(MGHOME)/jni/org_greenstone_mg_MGWrapper.h
+
+install: compile
+	$(MGHOME)/mkinstalldirs $(JAVALIBDIR); \
+	cp mg.jar $(JAVALIBDIR)/
+
+distclean: clean
+	rm -f Makefile
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/Queryer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/Queryer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/java/org/greenstone/mg/Queryer.java	(revision 10506)
@@ -0,0 +1,185 @@
+/*
+ *    Queryer.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.mg;
+
+import java.util.Vector;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+/** Queryer - java port of c++ Queryer 
+ * - uses MGWrapper to access mg
+ * only has get document and search - full text browse not implemented
+ *
+ * run as:
+ * java org.greenstone.mg.Queryer <basedir> <indexdir> <textdir>
+ *@see MGWrapper
+ */
+public class Queryer {
+  
+    /** outputs to std out a help message describing the commands used by 
+     * Queryer 
+     */
+    public void printHelp()
+    {
+	System.out.println( "commands available are:\n"+
+			    "\t.q\t\tquit\n"+
+			    "\t.h\t\tprint this help message\n"+
+			    "\t.d\t\tprint the current query parameter settings\n" +
+			    "\t.i<index>\tsearch index <index>\n"+
+			    "\t.r0/.r1\t\tranking off/on\n"+
+			    "\t.t0/.t1\t\tquery type some/all\n"+
+			    "\t.c0/.c1\t\tcasefolding off/on\n"+
+			    "\t.s0/.s1\t\tstemming off/on\n"+
+			    "\t.o0/.o1\t\tshort output off/on\n"+
+			    "\t.m<num>\t\tset max docs to return to num\n\n"+
+			    "\t.p<docnum>\tprint document docnum\n"+
+			    "\t<query string>\tdo a query\n");
+    }
+
+   
+    public static void main(String[] args)
+    {
+	if (args.length != 3) {
+	    System.out.println("Usage: java org.greenstone.mg.Queryer <basedir> <indexdir> <textdir>");
+	    return;
+	}
+
+	Queryer self = new Queryer();
+
+	String base_dir = args[0];
+	String index_path = args[1];
+	String text_path = args[2];
+
+	// the jni class to access mg stuff
+	MGWrapper wrapper = new MGWrapper();
+	wrapper.setIndex(index_path);
+
+	System.out.println("Welcome to Java Queryer :-)");
+	self.printHelp();
+
+	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+	boolean shortOutput = false;
+
+	String command; // user input
+	char x; // the command letter
+	String data = null; // any auxiliary input to a command
+	while (true) {
+	    System.out.print(">"); // the prompt
+            try {
+                command = br.readLine();
+                command = command.trim();
+		if (command.startsWith(".")) {
+		    // a system command
+		    x = command.charAt(1);
+		    if (command.length() > 2) {
+			data = command.substring(2);
+			data = data.trim();
+		    }
+
+		    switch (x) {
+		    case 'q': // clean up and exit
+			wrapper.unloadIndexData();
+			return;
+		    case 'h': // print help message
+			self.printHelp();
+			break;
+		    case 'd': // print query param settings
+			String info = wrapper.getQueryParams();
+			System.out.println(info);
+			break;
+		    case 'p': // print doc
+			int docnum = Integer.parseInt(data);
+			String doc = wrapper.getDocument(base_dir, text_path, docnum);
+			System.out.println(doc);
+			break;
+		    case 'm': //match docs
+			int match = Integer.parseInt(data);
+			wrapper.setMaxDocs(match);
+			break;
+		    case 's': // set stem on/off
+			int stem = Integer.parseInt(data);
+			if (stem==0 ){
+			    wrapper.setStem(false);
+			} else if(stem==1) {
+			    wrapper.setStem(true);
+			} else {
+			    System.err.println("Error: stem should be 0 or 1");
+			}
+			break;
+		    case 'c': // set case on/off
+			int casef = Integer.parseInt(data);
+			if (casef==0) {
+			    wrapper.setCase(false);
+			} else if (casef==1) {
+			    wrapper.setCase(true);
+			} else {
+			    System.err.println("Error: case should be 0 or 1");
+			}
+			break;
+		    case 'i': // set index
+			wrapper.setIndex(data);
+			break;
+		    case 'r': // set rank on/off
+			int rank = Integer.parseInt(data);
+			if (rank==0) {
+			    wrapper.setSortByRank(false);
+			} else if (rank==1) {
+			    wrapper.setSortByRank(true);
+			} else {
+			    System.err.println("Error: rank should be 0 or 1");
+			}
+			break;
+		    case 't': // set query type some/all
+			int type = Integer.parseInt(data);
+			if (type==0 || type==1) {
+			    wrapper.setMatchMode(type);
+			} else {
+			    System.err.println("Error: type should be 0 (some) or 1 (all)");
+			}
+			break;
+		    case 'o': // set output short/long
+			int output = Integer.parseInt(data);
+			if (output==0) {
+			    shortOutput = false;
+			} else if (output==1) {
+			    shortOutput = true;
+			} else {
+			    System.err.println("Error: output should be 0 or 1");
+			}
+			break;
+		    }
+		}
+		else {
+		    // a query
+		    wrapper.runQuery(base_dir, text_path, command);
+		    MGQueryResult res = wrapper.getQueryResult();
+		    System.out.println("(Java) Matching documents: " + res.getTotalDocs());
+		    if (shortOutput) {
+			System.out.println(res.toShortString());
+		    } else {
+			System.out.println(res.toString());
+		    }
+		}
+
+	    } catch (Exception e) {
+		System.out.println("Queryer error: "+e.getClass() + " "+e.getMessage());
+	    }
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/MGWrapperImpl.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/MGWrapperImpl.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/MGWrapperImpl.c	(revision 10506)
@@ -0,0 +1,662 @@
+/*
+ *    MGWrapperImpl.c
+ *    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.
+ */
+
+
+#include "MGWrapperImpl.h"
+#include <jni.h>
+#include "org_greenstone_mg_MGWrapper.h"
+
+#include "backend.h"
+#include "environment.h"
+
+
+/*************************************************************************
+   NOTES
+
+ - Features supported by MGPP but not by MG (AFAIK)
+
+   - Sorting results by rank.
+     Done here as a post-processing operation. Could be more efficient in
+     some cases: the current solution is not very good when the number of
+     matching documents is large and the number of desired matches is
+     small. In this case it would be better to iterate through the array
+     picking out the best documents rather than sorting them all.
+
+   - Asking for query term frequencies to be returned.
+     This cannot be turned off in MG. If the term frequencies are not
+     required, they are simply not passed bassed to the Java side.
+
+   - Choosing the index for queries.
+     It is possible for MG to build Section and Document indexes (for
+     example), but these are two separate indexes, and must be loaded
+     separately. This module can load more than one index at a time, thus
+     processing queries to different indexes more quickly.
+     NOTE: This replaces TWO options in the MGPP version: returnLevel and
+           queryLevel.
+
+   - "Some" (boolean OR) queries.
+     In boolean querying mode, MG assumes query terms are joined by ANDs.
+     There is no way to tell MG to treat the query terms as if they were
+     joined by ORs. Here, "some" queries are handled by explicitly
+     inserting OR ("|") characters between the query terms.
+
+ *************************************************************************
+   TO DO
+
+   - Find out about necessity of other query term information
+     (eg. equivalent terms).
+
+ *************************************************************************/
+
+
+#define MAX_INDEXES_CACHED 2
+
+
+/*********************************************
+   initialisation stuff
+ *********************************************/
+
+/* cached ids for java stuff */
+jfieldID FID_mg_data = NULL; /* MGWrapperData */
+jfieldID FID_query_result = NULL; /* MGQueryResult */
+jmethodID MID_addDoc = NULL; /* MGQueryResult.addDoc() */
+jmethodID MID_addTerm = NULL; /* MGQueryResult.addTerm() */
+jmethodID MID_setTotalDocs = NULL; /* MGQueryResult.setTotalDocs() */
+jmethodID MID_clearResult = NULL; /* MGQueryResult.clear() */
+
+
+/* to access objects and methods on java side, need their field/method ids - 
+ this initialises them at the start to avoid recalculating them each time they
+ are needed
+Note: the descriptors need to be exactly right, otherwise you get an error 
+saying "no such field" but no reference to the fact that it has the right 
+name but the wrong type.
+Note: apparently the jclass is a local ref and should only work 
+in the method that created it. It seems to work ok, but I'll make it
+global cos the book said I should, and it may avoid future hassles.
+*/
+JNIEXPORT void JNICALL
+Java_org_greenstone_mg_MGWrapper_initIDs(JNIEnv *j_env, jclass j_cls)
+{
+  jclass JC_MGQueryResult;
+
+  /* a long-"J" */
+  FID_mg_data = (*j_env)->GetFieldID(j_env, j_cls, "mg_data_ptr_", "J");
+  assert(FID_mg_data != NULL);
+
+  /* an object -"L<class name>;" */
+  FID_query_result = (*j_env)->GetFieldID(j_env, j_cls, "mg_query_result_",
+					  "Lorg/greenstone/mg/MGQueryResult;");
+  assert(FID_query_result != NULL);
+
+  /* the methods we want to use */
+  JC_MGQueryResult = (*j_env)->FindClass(j_env, "org/greenstone/mg/MGQueryResult");
+
+  /* addDoc(long doc, float rank) */
+  MID_addDoc = (*j_env)->GetMethodID(j_env, JC_MGQueryResult, "addDoc", "(JF)V");
+  assert(MID_addDoc != NULL);
+
+  /* addTerm(String term, String tag, int stem, long match, long freq, String[] equivs) */
+  MID_addTerm = (*j_env)->GetMethodID(j_env, JC_MGQueryResult, "addTerm", "(Ljava/lang/String;Ljava/lang/String;IJJ[Ljava/lang/String;)V");
+  assert(MID_addTerm != NULL);
+
+  /* setTotalDocs(long) */
+  MID_setTotalDocs = (*j_env)->GetMethodID(j_env, JC_MGQueryResult, "setTotalDocs", "(J)V");
+  assert(MID_setTotalDocs != NULL);
+
+  /* clear(void) */
+  MID_clearResult = (*j_env)->GetMethodID(j_env, JC_MGQueryResult, "clear", "()V");
+  assert(MID_clearResult != NULL);
+}
+
+
+/* the java side MGWrapper has a pointer to a C object - MGWrapperData
+   initialise this and set the pointer 
+*/
+JNIEXPORT jboolean JNICALL
+Java_org_greenstone_mg_MGWrapper_initCSide(JNIEnv *j_env, jobject j_obj)
+{
+  /* Allocate a MGWrapperData object to store query parameters */
+  MGWrapperData* data = (MGWrapperData*) malloc(sizeof(MGWrapperData));
+  assert(data != NULL);
+
+  /* Set default values - no stemming, no case-folding, boolean OR queries */
+  data->defaultStemMethod = 0;
+  data->defaultBoolCombine = 0;
+
+  /* Allocate a QueryInfo object to store more query parameters */
+  data->queryInfo = (QueryInfo*) malloc(sizeof(QueryInfo));
+  assert(data->queryInfo != NULL);
+
+  /* Set default values - 50 documents max, return term freqs, sort by rank */
+  data->queryInfo->index = NULL;
+  data->queryInfo->maxDocs = 50;
+  data->queryInfo->needTermFreqs = 1;
+  data->queryInfo->sortByRank = 1;
+
+  /* Save the object on the Java side */
+  (*j_env)->SetIntField(j_env, j_obj, FID_mg_data, (long) data);
+
+  /* Initialise MG environment variables */
+  InitEnv();
+  SetEnv("expert", "true", NULL);
+  SetEnv("mode", "docnums", NULL);
+  return 1;  /* true - no errors */
+}
+
+
+/*******************************************
+   Index caching
+ *******************************************/
+
+query_data* cached_indexes[MAX_INDEXES_CACHED] = { NULL };
+
+
+/* Get the index data necessary to perform a query or document retrieval */
+query_data*
+loadIndexData(char* base_dir, char* index_path, char* text_path)
+{
+  char* index_path_name;
+  char* text_path_name;
+  query_data* qd;
+  int i = 0;
+
+  /* Form the path name of the desired indexes */
+  index_path_name = (char*) malloc(strlen(base_dir) + strlen(index_path) + 1);
+  assert(index_path_name != NULL);
+  strcpy(index_path_name, base_dir);
+  strcat(index_path_name, index_path);
+  printf("Index pathname: %s\n", index_path_name);
+
+  text_path_name = (char*) malloc(strlen(base_dir) + strlen(text_path) + 1);
+  assert(text_path_name != NULL);
+  strcpy(text_path_name, base_dir);
+  strcat(text_path_name, text_path);
+  printf("Text pathname: %s\n", text_path_name);
+
+  /* Search through the cached indexes for the desired one */
+  while (i < MAX_INDEXES_CACHED && cached_indexes[i] != NULL) {
+    printf("(Cached) Pathname: %s\n", cached_indexes[i]->pathname);
+    printf("(Cached) Textpathname: %s\n", cached_indexes[i]->textpathname);
+
+    /* Check if the index has already been loaded */
+    if ((strcmp(index_path_name, cached_indexes[i]->pathname) == 0) &&
+	(strcmp(text_path_name, cached_indexes[i]->textpathname) == 0)) {
+      /* Index has already been loaded and cached, so return it */
+      printf("Found index!\n");
+      free(index_path_name);
+      free(text_path_name);
+      return cached_indexes[i];
+    }
+
+    i++;
+  }
+
+  /* Text strings no longer needed */
+  free(index_path_name);
+  free(text_path_name);
+
+  /* The index is not cached, so load it now */
+  qd = InitQuerySystem(base_dir, index_path, text_path, NULL);
+  if (!qd) {
+    printf("Error: Could not InitQuerySystem()...\n");
+    return NULL;
+  }
+
+  /* The index loaded OK, so cache it */
+  /* This could be a little more sophisticated, eg. replace least frequently used index */
+  if (i >= MAX_INDEXES_CACHED)
+    i = MAX_INDEXES_CACHED - 1;
+
+  /* Free the index being replaced */
+  if (cached_indexes[i] != NULL)
+    FinishQuerySystem(cached_indexes[i]);
+
+  /* Cache the loaded index, and return it */
+  cached_indexes[i] = qd;
+  return cached_indexes[i];
+}
+
+
+/* Clean up by unloading all cached indexes */
+JNIEXPORT jboolean JNICALL
+Java_org_greenstone_mg_MGWrapper_unloadIndexData(JNIEnv* j_env, jobject j_obj)
+{
+  /* Free all the loaded indexes */
+  int i = 0;
+  while (i < MAX_INDEXES_CACHED && cached_indexes[i] != NULL) {
+    FinishQuerySystem(cached_indexes[i]);
+    cached_indexes[i] = NULL;
+    i++;
+  }
+
+  return 1;  /* true - no errors */
+}
+
+
+/****************************************************
+   retrieve a document
+ ****************************************************/
+
+/* Returns a document from mg as a string */
+JNIEXPORT jstring JNICALL
+Java_org_greenstone_mg_MGWrapper_getDocument(JNIEnv *j_env, jobject j_obj,
+					     jstring j_base_dir, jstring j_text_path,
+					     jlong j_docnum)
+{
+  MGWrapperData* data = (MGWrapperData*) (*j_env)->GetIntField(j_env, j_obj, FID_mg_data);
+
+  char* index_path;
+  const char* base_dir;
+  const char* text_path;
+  query_data* qd;
+
+  u_long pos, len;
+  u_char* c_buffer = NULL;
+  u_char* uc_buffer = NULL;
+  int ULen;
+
+  jstring result;
+
+  /* Make sure an index has been specified */
+  index_path = data->queryInfo->index;
+  assert(index_path != NULL);
+
+  /* Obtain C versions of the two string parameters */
+  base_dir = (*j_env)->GetStringUTFChars(j_env, j_base_dir, NULL);
+  if (base_dir == NULL) {
+    return NULL;
+  }
+  text_path = (*j_env)->GetStringUTFChars(j_env, j_text_path, NULL);
+  if (text_path == NULL) {
+    (*j_env)->ReleaseStringUTFChars(j_env, j_base_dir, base_dir);
+    return NULL;
+  }
+
+  /* Load the appropriate index for satisfying this request */
+  qd = loadIndexData((char*) base_dir, (char*) index_path, (char*) text_path);
+
+  /* The C text strings are no longer needed */
+  (*j_env)->ReleaseStringUTFChars(j_env, j_base_dir, base_dir);
+  (*j_env)->ReleaseStringUTFChars(j_env, j_text_path, text_path);
+
+  /* Check that the index was loaded successfully */
+  assert(qd != NULL);
+
+  /* Get the document position and length in the text file */
+  printf("Fetching document number %ld...\n", (unsigned long) j_docnum);
+  FetchDocStart(qd, (unsigned long) j_docnum, &pos, &len);
+  printf("Fetched document start. Pos: %ld, Len: %ld\n", pos, len);
+
+  /* Allocate memory for the document text (from mg/src/text/mgquery.c:RawDocOutput()) */
+  c_buffer = (u_char*) malloc(len);
+  assert(c_buffer != NULL);
+  uc_buffer = (u_char*) malloc((int) (qd->td->cth.ratio * 1.01 * len) + 100);
+  assert(uc_buffer != NULL);
+
+  /* Seek to the correct position in the file and read the document text */
+  Fseek (qd->td->TextFile, pos, 0);
+  Fread (c_buffer, 1, len, qd->td->TextFile);
+
+  /* Decode (?) the document text into another buffer, and terminate it */
+  DecodeText (qd->cd, c_buffer, len, uc_buffer, &ULen);
+  uc_buffer[ULen] = '\0';
+
+  /* Load the document text into a Java string */
+  result = (*j_env)->NewStringUTF(j_env, uc_buffer);
+  assert(result != NULL);
+
+  /* Free C buffers */
+  free(c_buffer);
+  free(uc_buffer);
+
+  /* Return the document text */
+  return result;
+}
+
+
+/*******************************************
+   do a query
+ *******************************************/
+
+/* Comparison function for sorting documents by their weight (decreasing order) */
+int
+document_weight_comp(const void *A, const void *B)
+{
+  const DocEntry *a = A;
+  const DocEntry *b = B;
+
+  /* Compare on weight, highest wins */
+  if (a->Weight < b->Weight)
+    return  1;
+  if (a->Weight > b->Weight)
+    return -1;
+  return 0;
+}
+
+
+/* do the actual query - the results are written to query_result held on the Java side */
+JNIEXPORT void JNICALL
+Java_org_greenstone_mg_MGWrapper_runQuery(JNIEnv *j_env, jobject j_obj,
+					  jstring j_base_dir, jstring j_text_path,
+					  jstring j_query)
+{
+  MGWrapperData* data = (MGWrapperData*) (*j_env)->GetIntField(j_env, j_obj, FID_mg_data);
+
+  char* index_path;
+  const char* base_dir;
+  const char* text_path;
+  query_data* qd;
+
+  jobject result_ptr;
+  char* query;
+  BooleanQueryInfo bqi;
+  int i, j;
+
+  jthrowable exc;
+
+  /* Make sure an index has been specified */
+  index_path = data->queryInfo->index;
+  assert(index_path != NULL);
+
+  /* Obtain C versions of the two string parameters */
+  base_dir = (*j_env)->GetStringUTFChars(j_env, j_base_dir, NULL);
+  if (base_dir == NULL) {
+    return;
+  }
+  text_path = (*j_env)->GetStringUTFChars(j_env, j_text_path, NULL);
+  if (text_path == NULL) {
+    (*j_env)->ReleaseStringUTFChars(j_env, j_base_dir, base_dir);
+    return;
+  }
+
+  /* Load the appropriate index for satisfying this request */
+  qd = loadIndexData((char*) base_dir, (char*) index_path, (char*) text_path);
+
+  /* The C text strings are no longer needed */
+  (*j_env)->ReleaseStringUTFChars(j_env, j_base_dir, base_dir);
+  (*j_env)->ReleaseStringUTFChars(j_env, j_text_path, text_path);
+
+  /* Check that the index was loaded successfully */
+  assert(qd != NULL);
+
+  /* Remove anything hanging around from last time */
+  FreeQueryDocs(qd);
+
+  /* The result to write to */
+  result_ptr = (*j_env)->GetObjectField(j_env, j_obj, FID_query_result);
+  assert(result_ptr != NULL);
+
+  /* Clear any previous query results */
+  (*j_env)->CallVoidMethod(j_env, result_ptr, MID_clearResult);
+  exc = (*j_env)->ExceptionOccurred(j_env);
+  if (exc) {
+    (*j_env)->ExceptionDescribe(j_env);
+    return;
+  }
+
+  /* Obtain a C version of the query string */
+  query = (char*) (*j_env)->GetStringUTFChars(j_env, j_query, NULL);
+  assert(query != NULL);
+  printf("Searching for query \"%s\"...\n", query);
+
+  /* Make sure the query isn't empty */
+  if (strlen(query) == 0) {
+    printf("Warning: Empty query.\n");
+    return;
+  }
+
+  /* Boolean OR ("some") queries: must manually insert OR ("|") tokens */
+  if (data->defaultBoolCombine == 0) {
+    int in_space = 0;
+    for (i = 0; i < strlen(query); i++) {
+      if (in_space) {
+	if (query[i] == '|') /* OR character already inserted, so remove others */
+	  query[i] = ' ';
+	else if (!isspace(query[i])) /* moving out of a space region */
+	  in_space = 0;
+      }
+      else if (!in_space && isspace(query[i])) { /* moving into a space region */
+	in_space = 1;
+	query[i] = '|'; /* insert an OR character */
+      }
+    }
+    printf("Boolean OR query string: %s\n", query);
+  }
+
+  /* If the documents need to be sorted by rank, all of them must be retrieved */
+  bqi.MaxDocsToRetrieve = ((data->queryInfo->sortByRank) ? -1 : data->queryInfo->maxDocs);
+
+  /* Perform query */
+  /* Had to add "words$o" to LIB_OBJS in mg/src/text/Makefile and recompile mg for this */
+  BooleanQuery(qd, (char*) query, &bqi, data->defaultStemMethod);
+
+  /* Finished with the C query string */
+  (*j_env)->ReleaseStringUTFChars(j_env, j_query, query);
+
+  /* Check the query was processed successfully */
+  assert(qd->DL != NULL);
+  assert(qd->QTL != NULL);
+  assert(qd->TL != NULL);
+
+  /* Record the total number of matching documents */
+  (*j_env)->CallVoidMethod(j_env, result_ptr, MID_setTotalDocs, (jlong) qd->DL->num);
+  exc = (*j_env)->ExceptionOccurred(j_env);
+  if (exc) {
+    (*j_env)->ExceptionDescribe(j_env);
+    return;
+  }
+
+  /* Sort the documents by rank, if desired */
+  if (data->queryInfo->sortByRank) {
+    qsort(qd->DL->DE, qd->DL->num, sizeof(DocEntry), document_weight_comp);
+  }
+
+  /* Record the matching documents, but only the number requested */
+  printf("Number of matching documents: %d\n", qd->DL->num);
+  for (i = 0; (i < qd->DL->num && i < data->queryInfo->maxDocs); i++) {
+    int doc_num = qd->DL->DE[i].DocNum;
+    float doc_weight = qd->DL->DE[i].Weight;
+
+    /* Call the addDoc function (Java side) to record a matching document */
+    (*j_env)->CallVoidMethod(j_env, result_ptr, MID_addDoc,
+			     (jlong) doc_num, (jfloat) doc_weight);
+    exc = (*j_env)->ExceptionOccurred(j_env);
+    if (exc) {
+      (*j_env)->ExceptionDescribe(j_env);
+      return;
+    }
+  }
+
+  /* Record the term information, if desired */
+  if (data->queryInfo->needTermFreqs) {
+    printf("Number of terms: %d\n", qd->TL->num);
+    printf("Number of query terms: %d\n", qd->QTL->num);
+
+    /* Find each query term in the term list, and grab its frequency */
+    for (i = 0; i < qd->QTL->num; i++) {
+      unsigned int query_term_length = (unsigned int) qd->QTL->QTE[i].Term[0];
+      unsigned char* query_term;
+      jstring j_query_term;
+      jint stem = qd->QTL->QTE[i].stem_method;
+      jlong match;
+      jlong freq;
+
+      /* Allocate memory to store this query term, and fill it */
+      query_term = (unsigned char*) malloc(query_term_length + 1);
+      assert(query_term != NULL);
+      strncpy(query_term, &(qd->QTL->QTE[i].Term[1]), query_term_length);
+      query_term[query_term_length] = '\0';
+      printf("Query term: %s\n", query_term);
+
+      /* Allocate a new jstring for the query term */
+      j_query_term = (*j_env)->NewStringUTF(j_env, query_term);
+      assert(j_query_term != NULL);
+
+      /* Find the matching term in the term list */
+      for (j = 0; j < qd->TL->num; j++) {
+	unsigned int term_length = (unsigned int) qd->TL->TE[j].Word[0];
+
+	/* Stemming and case-folding mean both comparisons are necessary */
+	if ((strncmp(query_term, &(qd->TL->TE[j].Word[1]), term_length) == 0) &&
+	    (strncmp(query_term, &(qd->TL->TE[j].Word[1]), query_term_length) == 0)) {
+	  /* Get the document count and total frequency of the term */
+	  match = qd->TL->TE[j].WE.doc_count;
+	  freq = qd->TL->TE[j].WE.count;
+
+	  /* Call the addTerm function (Java side) to record term information */
+	  (*j_env)->CallVoidMethod(j_env, result_ptr, MID_addTerm,
+				   j_query_term, NULL, stem, match, freq, NULL);
+	  exc = (*j_env)->ExceptionOccurred(j_env);
+	  if (exc) {
+	    (*j_env)->ExceptionDescribe(j_env);
+	    return;
+	  }
+
+	  /* There can only be one match */
+	  break;
+	}
+      }
+
+      /* Finished with this query term */
+      free(query_term);
+    }
+  }
+}
+
+
+/*******************************************
+   set query options
+ *******************************************/
+
+/* Turn casefolding on or off */
+JNIEXPORT void JNICALL
+Java_org_greenstone_mg_MGWrapper_setCase(JNIEnv *j_env, jobject j_obj, 
+					 jboolean j_on)
+{
+  MGWrapperData* data = (MGWrapperData*) (*j_env)->GetIntField(j_env, j_obj, FID_mg_data);
+
+  if (j_on) {
+    data->defaultStemMethod |= 1;
+  } else {
+    data->defaultStemMethod &= 0xe;
+  }
+}
+
+
+/* Turn stemming on or off */
+JNIEXPORT void JNICALL
+Java_org_greenstone_mg_MGWrapper_setStem(JNIEnv *j_env, jobject j_obj, 
+					 jboolean j_on)
+{
+  MGWrapperData* data = (MGWrapperData*) (*j_env)->GetIntField(j_env, j_obj, FID_mg_data);
+
+  if (j_on) {
+    data->defaultStemMethod |= 2;
+  } else {
+    data->defaultStemMethod &= 0xd;
+  }
+}
+
+
+/* Set the maximum number of documents to return from a query */
+JNIEXPORT void JNICALL
+Java_org_greenstone_mg_MGWrapper_setMaxDocs(JNIEnv *j_env, jobject j_obj, 
+					    jint j_max)
+{
+  MGWrapperData* data = (MGWrapperData*) (*j_env)->GetIntField(j_env, j_obj, FID_mg_data);
+  data->queryInfo->maxDocs = j_max;
+}
+
+
+/* Turn sorting by rank on or off */
+JNIEXPORT void JNICALL
+Java_org_greenstone_mg_MGWrapper_setSortByRank(JNIEnv *j_env, jobject j_obj, 
+                                               jboolean j_on)
+{
+  MGWrapperData* data = (MGWrapperData*) (*j_env)->GetIntField(j_env, j_obj, FID_mg_data);  
+  data->queryInfo->sortByRank = j_on;
+}
+
+
+/* Turn term frequency recording on or off */
+JNIEXPORT void JNICALL
+Java_org_greenstone_mg_MGWrapper_setReturnTerms(JNIEnv *j_env, jobject j_obj, 
+						jboolean j_on)
+{
+  MGWrapperData* data = (MGWrapperData*) (*j_env)->GetIntField(j_env, j_obj, FID_mg_data);
+  data->queryInfo->needTermFreqs = j_on;
+}
+
+
+/* Choose MG index to search */
+JNIEXPORT void JNICALL
+Java_org_greenstone_mg_MGWrapper_setIndex(JNIEnv *j_env, jobject j_obj,
+					  jstring j_index)
+{
+  MGWrapperData* data = (MGWrapperData*) (*j_env)->GetIntField(j_env, j_obj, FID_mg_data);
+
+  /* Get the index name as a C string */
+  const char* index = (*j_env)->GetStringUTFChars(j_env, j_index, NULL);
+  assert(index != NULL);
+  printf("Choosing index %s...\n", index);
+
+  /* Free the previous index name */
+  if (data->queryInfo->index)
+    free(data->queryInfo->index);
+
+  /* Allocate memory for the index name, and fill it */
+  data->queryInfo->index = (char*) malloc(strlen(index) + 1);
+  assert(data->queryInfo->index != NULL);
+  strcpy(data->queryInfo->index, index);
+
+  /* Release the index string */
+  (*j_env)->ReleaseStringUTFChars(j_env, j_index, index);
+}
+
+
+/* Choose boolean AND or boolean OR queries */
+JNIEXPORT void JNICALL 
+Java_org_greenstone_mg_MGWrapper_setMatchMode(JNIEnv *j_env, jobject j_obj,
+					      jint j_mode)
+{
+  MGWrapperData* data = (MGWrapperData*) (*j_env)->GetIntField(j_env, j_obj, FID_mg_data);
+  data->defaultBoolCombine = j_mode;
+}
+
+
+/* Get a text representation of the current parameter values */
+JNIEXPORT jstring JNICALL
+Java_org_greenstone_mg_MGWrapper_getQueryParams(JNIEnv *j_env, jobject j_obj)
+{
+  MGWrapperData* data = (MGWrapperData*) (*j_env)->GetIntField(j_env, j_obj, FID_mg_data);
+  char result[512];  /* Assume this is big enough */
+
+  /* Print the data to a character array */
+  sprintf(result, "Query params:\nindex\t\t%s\ncasefold\t%d\nstem\t\t%d\norder by rank\t%d\nquery type\t%s\nmax docs\t%d\n",
+	  (data->queryInfo->index == NULL ? "<none loaded>" : data->queryInfo->index),
+	  (data->defaultStemMethod & 1),
+	  (data->defaultStemMethod & 2),
+	  (data->queryInfo->sortByRank),
+	  (data->defaultBoolCombine == 1 ? "all" : "some"),
+	  (data->queryInfo->maxDocs));
+
+  /* Convert to a jstring, and return */
+  return (*j_env)->NewStringUTF(j_env, result);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/MGWrapperImpl.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/MGWrapperImpl.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/MGWrapperImpl.h	(revision 10506)
@@ -0,0 +1,55 @@
+/*
+ *    MGWrapperImpl.h
+ *    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.
+ */
+
+
+#include "backend.h"
+
+
+/*************************************************************************
+   NOTES
+
+ - These data structures are based on the MGPP ones but are modified
+   slightly to reflect the different capabilities of the MG system.
+
+ *************************************************************************/
+
+ 
+typedef struct QueryInfo
+{
+  /* Name of index to use */
+  char* index;
+  /* Maximum number of documents to retrieve */
+  unsigned long maxDocs;
+  /* Whether to sort the matching documents by weight (boolean value) */
+  int sortByRank;
+
+  /* Whether term frequency information is desired (boolean value) */
+  int needTermFreqs;
+} QueryInfo;
+
+
+typedef struct MGWrapperData
+{
+  /* Information about a query, see above */
+  QueryInfo* queryInfo;
+  /* Whether to perform stemming and case-folding */
+  int defaultStemMethod;
+  /* Whether to perform boolean AND (1) or boolean OR (0) queries */
+  int defaultBoolCombine;
+} MGWrapperData;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/Makefile.in	(revision 10506)
@@ -0,0 +1,62 @@
+
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+bindir = @bindir@
+srcdir = @srcdir@
+libdir = @libdir@
+subdir = jni
+top_srcdir = @top_srcdir@
+transform = @program_transform_name@
+
+AR = ar
+CC = @CC@
+CFLAGS = @CFLAGS@ -ansi -DSILENT -DSHORT_SUFFIX -DNZDL -DQUIET -DPARADOCNUM
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+#NOTE: libtextin.a needs to come before libmg.a !!!
+LIBS = ../src/text/libtextin.a ../lib/libmg.a @LIBS@
+TOUCH = echo timestamp >
+AWK = @AWK@
+
+datadir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+localedir = $(datadir)/locale
+mandir = $(prefix)/man/man1
+
+CCOMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CFLAGS)
+
+.SUFFIXES:
+
+.SUFFIXES: .c .o
+.c.o:
+	$(CCOMPILE) $<
+
+
+INCLUDES = -I.. -I../lib -I../src/text -I/usr/local/share/j2sdk1.4.0/include -I/usr/local/share/j2sdk1.4.0/include/linux
+
+all: compile link
+
+compile:
+	$(CCOMPILE) MGWrapperImpl.c
+
+link:
+	$(CC) -shared -o libmgjni.so MGWrapperImpl.o $(LIBS)
+
+clean:
+	rm -rf *.o libmgjni.so 
+
+distclean: clean
+	rm -f Makefile
+
+install:
+	../mkinstalldirs $(libdir); \
+	cp libmgjni.so  $(libdir)/;
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/org_greenstone_mg_MGWrapper.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/org_greenstone_mg_MGWrapper.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/jni/org_greenstone_mg_MGWrapper.h	(revision 10506)
@@ -0,0 +1,117 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_greenstone_mg_MGWrapper */
+
+#ifndef _Included_org_greenstone_mg_MGWrapper
+#define _Included_org_greenstone_mg_MGWrapper
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_greenstone_mg_MGWrapper_initIDs
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    initCSide
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_greenstone_mg_MGWrapper_initCSide
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    getDocument
+ * Signature: (Ljava/lang/String;Ljava/lang/String;J)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_greenstone_mg_MGWrapper_getDocument
+  (JNIEnv *, jobject, jstring, jstring, jlong);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    unloadIndexData
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_greenstone_mg_MGWrapper_unloadIndexData
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    setCase
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL Java_org_greenstone_mg_MGWrapper_setCase
+  (JNIEnv *, jobject, jboolean);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    setStem
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL Java_org_greenstone_mg_MGWrapper_setStem
+  (JNIEnv *, jobject, jboolean);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    setMaxDocs
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_org_greenstone_mg_MGWrapper_setMaxDocs
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    setSortByRank
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL Java_org_greenstone_mg_MGWrapper_setSortByRank
+  (JNIEnv *, jobject, jboolean);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    setReturnTerms
+ * Signature: (Z)V
+ */
+JNIEXPORT void JNICALL Java_org_greenstone_mg_MGWrapper_setReturnTerms
+  (JNIEnv *, jobject, jboolean);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    setIndex
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_org_greenstone_mg_MGWrapper_setIndex
+  (JNIEnv *, jobject, jstring);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    setMatchMode
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_org_greenstone_mg_MGWrapper_setMatchMode
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    getQueryParams
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_greenstone_mg_MGWrapper_getQueryParams
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_greenstone_mg_MGWrapper
+ * Method:    runQuery
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_org_greenstone_mg_MGWrapper_runQuery
+  (JNIEnv *, jobject, jstring, jstring, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/GCC.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/GCC.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/GCC.mak	(revision 10506)
@@ -0,0 +1,84 @@
+###########################################################################
+#
+# gcc win32 makefile -- mg\lib
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+AR = ar
+RANLIB = ranlib
+CC = gcc
+DELETE = del
+
+CPPFLAGS = -g
+DEFS = -DQUIET -DHAVE_CONFIG_H -D__WIN32__ -D_LITTLE_ENDIAN
+INCLUDES = -I".." -I"."
+
+o = .o
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS)
+ 
+.SUFFIXES:
+.SUFFIXES: .c $o
+.c$o:
+	$(COMPILE) $<
+
+
+HEADERS = \
+    bitio_m_random.h filestats.h local_strings.h lovinstem.h \
+    bitio_m_stdio.h getopt.h memlib.h bitio_gen.h bitio_mem.h \
+    mgheap.h messages.h bitio_m.h bitio_mems.h huffman.h \
+    timing.h bitio_m_mem.h bitio_random.h huffman_mem.h \
+    perf_hash.h bitio_m_mems.h bitio_stdio.h huffman_stdio.h \
+    sptree.h rx.h pathmax.h getpagesize.h random.h \
+    win32in.h simplefrenchstem.h unitool.h
+
+SOURCES = \
+    bitio_random.c mgheap.c memlib.c bitio_stdio.c huffman.c \
+    messages.c bitio_gen.c filestats.c huffman_mem.c \
+    perf_hash.c bitio_mem.c getopt.c huffman_stdio.c \
+    sptree.c bitio_mems.c getopt1.c local_strings.c \
+    lovinstem.c timing.c rx.c alloca.c error.c xmalloc.c \
+    strstr.c ftruncate.c strcasecmp.c random.c win32in.c \
+    simplefrenchstem.c unitool.h
+
+OBJECTS = \
+    rx$o bitio_random$o mgheap$o memlib$o bitio_stdio$o \
+    huffman$o messages$o bitio_gen$o filestats$o huffman_mem$o \
+    perf_hash$o bitio_mem$o getopt$o huffman_stdio$o sptree$o \
+    bitio_mems$o getopt1$o local_strings$o lovinstem$o \
+    timing$o error$o xmalloc$o random$o win32in$o \
+    simplefrenchstem$o unitool$o
+ 
+all : libmg.a
+
+libmg.a : $(OBJECTS)
+	$(DELETE) libmg.a
+	$(AR) cru libmg.a $(OBJECTS)
+	$(RANLIB) libmg.a
+
+install: 
+ 
+clean: 
+	$(DELETE) *$o
+	$(DELETE) libmg.a
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/Makefile.in	(revision 10506)
@@ -0,0 +1,174 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the general purpose library
+# Copyright (C) 1994  Neil Sharman; (C) 1995 Tim Shimmin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)Makefile.in	1.3 16 Mar 1994
+#
+###########################################################################
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+SHELL = /bin/sh
+srcdir = @srcdir@
+subdir = lib
+VPATH = @srcdir@
+ 
+AR = ar
+CC = @CC@
+CFLAGS = @CFLAGS@ 
+CPPFLAGS = @CPPFLAGS@
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+
+##########################################
+# Uncomment for compiling for the nzdl project
+#
+CFLAGS = @CFLAGS@ -DQUIET
+##########################################
+
+ 
+prefix = @prefix@
+datadir = $(prefix)/share
+localedir = $(datadir)/locale
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+ANSI2KNR = @ANSI2KNR@
+o = .@U@o
+ 
+.SUFFIXES: ._c ._o
+.c._c:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $@
+._c._o:
+	@echo $(COMPILE) $<
+	@rm -f _$*.c
+	@ln $< _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+.c._o:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $*._c
+	@echo $(COMPILE) $*._c
+	@rm -f _$*.c
+	@ln $*._c _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+
+ 
+INCLUDES = -I../../.. -I.. -I$(srcdir)
+ 
+HEADERS = \
+    bitio_m_random.h   filestats.h        local_strings.h    lovinstem.h \
+    bitio_m_stdio.h    getopt.h           memlib.h \
+    bitio_gen.h        bitio_mem.h        mgheap.h             messages.h \
+    bitio_m.h          bitio_mems.h       huffman.h          timing.h \
+    bitio_m_mem.h      bitio_random.h     huffman_mem.h      perf_hash.h \
+    bitio_m_mems.h     bitio_stdio.h      huffman_stdio.h    sptree.h \
+    pathmax.h          getpagesize.h \
+    random.h           simplefrenchstem.h unitool.h  longlong.h
+# regex.h            rx.h               
+
+
+SOURCES = \
+    bitio_random.c    mgheap.c            memlib.c \
+    bitio_stdio.c     huffman.c         messages.c \
+    bitio_gen.c       filestats.c       huffman_mem.c     perf_hash.c \
+    bitio_mem.c       getopt.c          huffman_stdio.c   sptree.c \
+    bitio_mems.c      getopt1.c         local_strings.c   lovinstem.c \
+    timing.c  \
+    alloca.c          error.c           xmalloc.c         strstr.c \
+    gmalloc.c         ftruncate.c       strcasecmp.c      random.c \
+    simplefrenchstem.c                  unitool.c
+# regex.c           rx.c              
+
+OBJECTS = @ALLOCA@ @LIBOBJS@ \
+    bitio_random$o    mgheap$o            memlib$o \
+    bitio_stdio$o     huffman$o         messages$o \
+    bitio_gen$o       filestats$o       huffman_mem$o     perf_hash$o \
+    bitio_mem$o       getopt$o          huffman_stdio$o   sptree$o \
+    bitio_mems$o      getopt1$o         local_strings$o   lovinstem$o \
+    timing$o \
+    error$o           xmalloc$o \
+    random$o          simplefrenchstem$o \
+    unitool$o
+#   gmalloc$o regex$o		rx$o 
+
+LIB_OBJECTS =   \
+    bitio_random$o    mgheap$o            memlib$o \
+    bitio_stdio$o     huffman$o          \
+    bitio_gen$o       filestats$o       huffman_mem$o     perf_hash$o \
+    bitio_mem$o       getopt$o          huffman_stdio$o   sptree$o \
+    bitio_mems$o      getopt1$o         local_strings$o   lovinstem$o \
+    timing$o \
+    error$o           xmalloc$o \
+    random$o          simplefrenchstem$o \
+    unitool$o
+
+
+DISTFILES = Makefile.in $(HEADERS) $(SOURCES)
+ 
+all : libmg.a gsdllibmg.a
+
+libmg.a : $(OBJECTS)
+	rm -f libmg.a
+	$(AR) cru libmg.a $(OBJECTS)
+	$(RANLIB) libmg.a
+
+$(OBJECTS): ../../../config.h
+
+gsdllibmg.a: $(LIB_OBJECTS)
+	rm -f gsdllibmg.a
+	$(AR) cru gsdllibmg.a $(LIB_OBJECTS)
+	$(RANLIB) gsdllibmg.a
+ 
+
+install: 
+installdirs:
+uninstall:
+execinstall:
+execuninstall:
+maninstall:
+manuninstall:
+ 
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $$file $(distdir) 2> /dev/null \
+	  || cp -p $$file $(distdir); \
+	done
+
+mostlyclean:
+	rm -f *.o *_.o
+ 
+clean: mostlyclean
+	rm -f libmg.a gsdllibmg.a
+ 
+distclean: clean
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+#Makefile: Makefile.in ../../../config.status
+#	cd ../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/WIN32.MAK
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/WIN32.MAK	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/WIN32.MAK	(revision 10506)
@@ -0,0 +1,104 @@
+###########################################################################
+#
+# win32 makefile -- mg\lib
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+ 
+GSDLHOME = ..\..\..
+DLL = 0
+DLLDEBUG = 0
+
+AR = lib
+CC = cl
+
+CPPFLAGS = -GX
+!IF $(DLL)
+CPPFLAGS = $(CPPFLAGS) -MD
+!ELSE
+!IF ($(DLLDEBUG))
+CPPFLAGS = $(CPPFLAGS) -MDd
+!ENDIF
+!ENDIF
+
+DEFS = -DQUIET -DHAVE_CONFIG_H -D__WIN32__ -D_LITTLE_ENDIAN -DPARADOCNUM \
+       -DSHORT_SUFFIX
+INCLUDES = -I"$(GSDLHOME)\packages\mg\lib" -I"$(GSDLHOME)\packages\mg" \
+           -I"$(GSDLHOME)"
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+ 
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+ANSI2KNR = 
+o = .obj
+ 
+HEADERS = \
+    bitio_m_random.h   filestats.h        local_strings.h    lovinstem.h \
+    bitio_m_stdio.h    getopt.h           memlib.h \
+    bitio_gen.h        bitio_mem.h        mgheap.h             messages.h \
+    bitio_m.h          bitio_mems.h       huffman.h          timing.h \
+    bitio_m_mem.h      bitio_random.h     huffman_mem.h      perf_hash.h \
+    bitio_m_mems.h     bitio_stdio.h      huffman_stdio.h    sptree.h \
+                       rx.h               pathmax.h          getpagesize.h \
+    random.h           win32in.h          simplefrenchstem.h unitool.h \
+    longlong.h	
+
+SOURCES = \
+    bitio_random.c    mgheap.c          memlib.c \
+    bitio_stdio.c     huffman.c         messages.c \
+    bitio_gen.c       filestats.c       huffman_mem.c     perf_hash.c \
+    bitio_mem.c       getopt.c          huffman_stdio.c   sptree.c \
+    bitio_mems.c      getopt1.c         local_strings.c   lovinstem.c \
+    timing.c                            rx.c              \
+    alloca.c          error.c           xmalloc.c         strstr.c \
+    ftruncate.c       strcasecmp.c      random.c          win32in.c \
+    simplefrenchstem.c                  unitool.h
+
+OBJECTS =   rx$o \
+    bitio_random$o    mgheap$o            memlib$o \
+    bitio_stdio$o     huffman$o         messages$o \
+    bitio_gen$o       filestats$o       huffman_mem$o     perf_hash$o \
+    bitio_mem$o       getopt$o          huffman_stdio$o   sptree$o \
+    bitio_mems$o      getopt1$o         local_strings$o   lovinstem$o \
+    timing$o           \
+    error$o           xmalloc$o \
+    random$o          win32in$o         simplefrenchstem$o \
+    unitool$o
+ 
+DISTFILES = Makefile.in $(HEADERS) $(SOURCES)
+ 
+all : libmg.lib
+
+libmg.lib : $(OBJECTS)
+	if EXIST libmg.lib del libmg.lib
+	$(AR) /out:libmg.lib $(OBJECTS)
+
+$(OBJECTS): "$(GSDLHOME)\win32cfg.h"
+
+install: 
+clean:
+	del *$o 
+	del libmg.lib
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/alloca.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/alloca.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/alloca.c	(revision 10506)
@@ -0,0 +1,496 @@
+/* alloca.c -- allocate automatically reclaimed memory
+   (Mostly) portable public-domain implementation -- D A Gwyn
+
+   This implementation of the PWB library alloca function,
+   which is used to allocate space off the run-time stack so
+   that it is automatically reclaimed upon procedure exit,
+   was inspired by discussions with J. Q. Johnson of Cornell.
+   J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+   There are some preprocessor constants that can
+   be defined when compiling for your specific system, for
+   improved efficiency; however, the defaults should be okay.
+
+   The general concept of this implementation is to keep
+   track of all alloca-allocated blocks, and reclaim any
+   that are found to be deeper in the stack than the current
+   invocation.  This heuristic does not reclaim storage as
+   soon as it becomes invalid, but it will do so eventually.
+
+   As a special case, alloca(0) reclaims storage without
+   allocating any.  It is a good idea to use alloca(0) in
+   your main control loop, etc. to force garbage collection.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#ifdef emacs
+#include "blockinput.h"
+#endif
+
+/* If compiling with GCC 2, this file's not needed.  */
+#if !defined (__GNUC__) || __GNUC__ < 2
+
+/* If someone has defined alloca as a macro,
+   there must be some other way alloca is supposed to work.  */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+   -- this is for usg, in which emacs must undefine static
+   in order to make unexec workable
+   */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+   provide an "address metric" ADDRESS_FUNCTION macro.  */
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#define	NULL	0
+
+/* Different portions of Emacs need to call different versions of
+   malloc.  The Emacs executable needs alloca to call xmalloc, because
+   ordinary malloc isn't protected from input signals.  On the other
+   hand, the utilities in lib-src need alloca to call malloc; some of
+   them are very simple, and don't have an xmalloc routine.
+
+   Non-Emacs programs expect this to call use xmalloc.
+
+   Callers below should use malloc.  */
+
+#ifndef emacs
+#define malloc xmalloc
+#endif
+extern pointer malloc ();
+
+/* Define STACK_DIRECTION if you know the direction of stack
+   growth for your system; otherwise it will be automatically
+   deduced at run-time.
+
+   STACK_DIRECTION > 0 => grows toward higher addresses
+   STACK_DIRECTION < 0 => grows toward lower addresses
+   STACK_DIRECTION = 0 => direction of growth unknown  */
+
+#ifndef STACK_DIRECTION
+#define	STACK_DIRECTION	0	/* Direction unknown.  */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define	STACK_DIR	STACK_DIRECTION	/* Known at compile-time.  */
+
+#else /* STACK_DIRECTION == 0; need run-time code.  */
+
+static int stack_dir;		/* 1 or -1 once known.  */
+#define	STACK_DIR	stack_dir
+
+static void
+find_stack_direction ()
+{
+  static char *addr = NULL;	/* Address of first `dummy', once known.  */
+  auto char dummy;		/* To get stack address.  */
+
+  if (addr == NULL)
+    {				/* Initial entry.  */
+      addr = ADDRESS_FUNCTION (dummy);
+
+      find_stack_direction ();	/* Recurse once.  */
+    }
+  else
+    {
+      /* Second entry.  */
+      if (ADDRESS_FUNCTION (dummy) > addr)
+	stack_dir = 1;		/* Stack grew upward.  */
+      else
+	stack_dir = -1;		/* Stack grew downward.  */
+    }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+   (a) chain together all alloca'ed blocks;
+   (b) keep track of stack depth.
+
+   It is very important that sizeof(header) agree with malloc
+   alignment chunk size.  The following default should work okay.  */
+
+#ifndef	ALIGN_SIZE
+#define	ALIGN_SIZE	sizeof(double)
+#endif
+
+typedef union hdr
+{
+  char align[ALIGN_SIZE];	/* To force sizeof(header).  */
+  struct
+    {
+      union hdr *next;		/* For chaining headers.  */
+      char *deep;		/* For stack depth measure.  */
+    } h;
+} header;
+
+static header *last_alloca_header = NULL;	/* -> last alloca header.  */
+
+/* Return a pointer to at least SIZE bytes of storage,
+   which will be automatically reclaimed upon exit from
+   the procedure that called alloca.  Originally, this space
+   was supposed to be taken from the current stack frame of the
+   caller, but that method cannot be made to work for some
+   implementations of C, for example under Gould's UTX/32.  */
+
+pointer
+alloca (size)
+     unsigned size;
+{
+  auto char probe;		/* Probes stack depth: */
+  register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+  if (STACK_DIR == 0)		/* Unknown growth direction.  */
+    find_stack_direction ();
+#endif
+
+  /* Reclaim garbage, defined as all alloca'd storage that
+     was allocated from deeper in the stack than currently. */
+
+  {
+    register header *hp;	/* Traverses linked list.  */
+
+#ifdef emacs
+    BLOCK_INPUT;
+#endif
+
+    for (hp = last_alloca_header; hp != NULL;)
+      if ((STACK_DIR > 0 && hp->h.deep > depth)
+	  || (STACK_DIR < 0 && hp->h.deep < depth))
+	{
+	  register header *np = hp->h.next;
+
+	  free ((pointer) hp);	/* Collect garbage.  */
+
+	  hp = np;		/* -> next header.  */
+	}
+      else
+	break;			/* Rest are not deeper.  */
+
+    last_alloca_header = hp;	/* -> last valid storage.  */
+
+#ifdef emacs
+    UNBLOCK_INPUT;
+#endif
+  }
+
+  if (size == 0)
+    return NULL;		/* No allocation required.  */
+
+  /* Allocate combined header + user data storage.  */
+
+  {
+    register pointer new = malloc (sizeof (header) + size);
+    /* Address of header.  */
+
+    ((header *) new)->h.next = last_alloca_header;
+    ((header *) new)->h.deep = depth;
+
+    last_alloca_header = (header *) new;
+
+    /* User storage begins just after header.  */
+
+    return (pointer) ((char *) new + sizeof (header));
+  }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+  {
+    long shgrow:32;		/* Number of times stack has grown.  */
+    long shaseg:32;		/* Size of increments to stack.  */
+    long shhwm:32;		/* High water mark of stack.  */
+    long shsize:32;		/* Current size of stack (all segments).  */
+  };
+
+/* The stack segment linkage control information occurs at
+   the high-address end of a stack segment.  (The stack
+   grows from low addresses to high addresses.)  The initial
+   part of the stack segment linkage control information is
+   0200 (octal) words.  This provides for register storage
+   for the routine which overflows the stack.  */
+
+struct stack_segment_linkage
+  {
+    long ss[0200];		/* 0200 overflow words.  */
+    long sssize:32;		/* Number of words in this segment.  */
+    long ssbase:32;		/* Offset to stack base.  */
+    long:32;
+    long sspseg:32;		/* Offset to linkage control of previous
+				   segment of stack.  */
+    long:32;
+    long sstcpt:32;		/* Pointer to task common address block.  */
+    long sscsnm;		/* Private control structure number for
+				   microtasking.  */
+    long ssusr1;		/* Reserved for user.  */
+    long ssusr2;		/* Reserved for user.  */
+    long sstpid;		/* Process ID for pid based multi-tasking.  */
+    long ssgvup;		/* Pointer to multitasking thread giveup.  */
+    long sscray[7];		/* Reserved for Cray Research.  */
+    long ssa0;
+    long ssa1;
+    long ssa2;
+    long ssa3;
+    long ssa4;
+    long ssa5;
+    long ssa6;
+    long ssa7;
+    long sss0;
+    long sss1;
+    long sss2;
+    long sss3;
+    long sss4;
+    long sss5;
+    long sss6;
+    long sss7;
+  };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+   returned by the STKSTAT library routine.  */
+struct stk_stat
+  {
+    long now;			/* Current total stack size.  */
+    long maxc;			/* Amount of contiguous space which would
+				   be required to satisfy the maximum
+				   stack demand to date.  */
+    long high_water;		/* Stack high-water mark.  */
+    long overflows;		/* Number of stack overflow ($STKOFEN) calls.  */
+    long hits;			/* Number of internal buffer hits.  */
+    long extends;		/* Number of block extensions.  */
+    long stko_mallocs;		/* Block allocations by $STKOFEN.  */
+    long underflows;		/* Number of stack underflow calls ($STKRETN).  */
+    long stko_free;		/* Number of deallocations by $STKRETN.  */
+    long stkm_free;		/* Number of deallocations by $STKMRET.  */
+    long segments;		/* Current number of stack segments.  */
+    long maxs;			/* Maximum number of stack segments so far.  */
+    long pad_size;		/* Stack pad size.  */
+    long current_address;	/* Current stack segment address.  */
+    long current_size;		/* Current stack segment size.  This
+				   number is actually corrupted by STKSTAT to
+				   include the fifteen word trailer area.  */
+    long initial_address;	/* Address of initial segment.  */
+    long initial_size;		/* Size of initial segment.  */
+  };
+
+/* The following structure describes the data structure which trails
+   any stack segment.  I think that the description in 'asdef' is
+   out of date.  I only describe the parts that I am sure about.  */
+
+struct stk_trailer
+  {
+    long this_address;		/* Address of this block.  */
+    long this_size;		/* Size of this block (does not include
+				   this trailer).  */
+    long unknown2;
+    long unknown3;
+    long link;			/* Address of trailer block of previous
+				   segment.  */
+    long unknown5;
+    long unknown6;
+    long unknown7;
+    long unknown8;
+    long unknown9;
+    long unknown10;
+    long unknown11;
+    long unknown12;
+    long unknown13;
+    long unknown14;
+  };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+   I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+  struct stk_stat status;
+  struct stk_trailer *trailer;
+  long *block, size;
+  long result = 0;
+
+  /* We want to iterate through all of the segments.  The first
+     step is to get the stack status structure.  We could do this
+     more quickly and more directly, perhaps, by referencing the
+     $LM00 common block, but I know that this works.  */
+
+  STKSTAT (&status);
+
+  /* Set up the iteration.  */
+
+  trailer = (struct stk_trailer *) (status.current_address
+				    + status.current_size
+				    - 15);
+
+  /* There must be at least one stack segment.  Therefore it is
+     a fatal error if "trailer" is null.  */
+
+  if (trailer == 0)
+    abort ();
+
+  /* Discard segments that do not contain our argument address.  */
+
+  while (trailer != 0)
+    {
+      block = (long *) trailer->this_address;
+      size = trailer->this_size;
+      if (block == 0 || size == 0)
+	abort ();
+      trailer = (struct stk_trailer *) trailer->link;
+      if ((block <= address) && (address < (block + size)))
+	break;
+    }
+
+  /* Set the result to the offset in this segment and add the sizes
+     of all predecessor segments.  */
+
+  result = address - block;
+
+  if (trailer == 0)
+    {
+      return result;
+    }
+
+  do
+    {
+      if (trailer->this_size <= 0)
+	abort ();
+      result += trailer->this_size;
+      trailer = (struct stk_trailer *) trailer->link;
+    }
+  while (trailer != 0);
+
+  /* We are done.  Note that if you present a bogus address (one
+     not in any segment), you will get a different number back, formed
+     from subtracting the address of the first block.  This is probably
+     not what you want.  */
+
+  return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+   Determine the number of the cell within the stack,
+   given the address of the cell.  The purpose of this
+   routine is to linearize, in some sense, stack addresses
+   for alloca.  */
+
+static long
+i00afunc (long address)
+{
+  long stkl = 0;
+
+  long size, pseg, this_segment, stack;
+  long result = 0;
+
+  struct stack_segment_linkage *ssptr;
+
+  /* Register B67 contains the address of the end of the
+     current stack segment.  If you (as a subprogram) store
+     your registers on the stack and find that you are past
+     the contents of B67, you have overflowed the segment.
+
+     B67 also points to the stack segment linkage control
+     area, which is what we are really interested in.  */
+
+  stkl = CRAY_STACKSEG_END ();
+  ssptr = (struct stack_segment_linkage *) stkl;
+
+  /* If one subtracts 'size' from the end of the segment,
+     one has the address of the first word of the segment.
+
+     If this is not the first segment, 'pseg' will be
+     nonzero.  */
+
+  pseg = ssptr->sspseg;
+  size = ssptr->sssize;
+
+  this_segment = stkl - size;
+
+  /* It is possible that calling this routine itself caused
+     a stack overflow.  Discard stack segments which do not
+     contain the target address.  */
+
+  while (!(this_segment <= address && address <= stkl))
+    {
+#ifdef DEBUG_I00AFUNC
+      fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+      if (pseg == 0)
+	break;
+      stkl = stkl - pseg;
+      ssptr = (struct stack_segment_linkage *) stkl;
+      size = ssptr->sssize;
+      pseg = ssptr->sspseg;
+      this_segment = stkl - size;
+    }
+
+  result = address - this_segment;
+
+  /* If you subtract pseg from the current end of the stack,
+     you get the address of the previous stack segment's end.
+     This seems a little convoluted to me, but I'll bet you save
+     a cycle somewhere.  */
+
+  while (pseg != 0)
+    {
+#ifdef DEBUG_I00AFUNC
+      fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+      stkl = stkl - pseg;
+      ssptr = (struct stack_segment_linkage *) stkl;
+      size = ssptr->sssize;
+      pseg = ssptr->sspseg;
+      result += size;
+    }
+  return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
+#endif /* not GCC version 2 */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_gen.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_gen.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_gen.c	(revision 10506)
@@ -0,0 +1,145 @@
+/**************************************************************************
+ *
+ * bitio_gen.c -- General supoport routines for bitio
+ * Copyright (C) 1994  Neil Sharman and Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "bitio_m.h"
+
+
+
+
+int fprintf (FILE *, const char *,...);
+
+unsigned long 
+BIO_Unary_Length (unsigned long val)
+{
+  register unsigned long num;
+  UNARY_LENGTH (val, num);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Binary_Length (unsigned long val, unsigned long b)
+{
+  register unsigned long num;
+  BINARY_LENGTH (val, b, num);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Gamma_Length (unsigned long val)
+{
+  register unsigned long num;
+  GAMMA_LENGTH (val, num);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Delta_Length (unsigned long val)
+{
+  register unsigned long num;
+  DELTA_LENGTH (val, num);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Elias_Length (unsigned long val, unsigned long b, double s)
+{
+  register unsigned long num;
+  ELIAS_LENGTH (val, b, s, num);
+  return (num);
+}
+
+unsigned long 
+BIO_Bblock_Length (unsigned long val, unsigned long b)
+{
+  register unsigned long num;
+  BBLOCK_LENGTH (val, b, num);
+  return (num);
+}
+
+
+int 
+BIO_Bblock_Init (int N, int p)
+{
+  int b;
+  b = (int) (0.5 + 0.6931471 * N / p);
+  return (b ? b : 1);
+}
+
+
+int 
+BIO_Bblock_Init_W (int N, int p)
+{
+  int logb;
+  FLOORLOG_2 ((N - p) / p, logb);
+  return (logb < 0 ? 1 : (1 << logb));
+}
+
+int 
+BIO_Bblock_Bound_b (int N, int p, int b)
+{
+  int clogb;
+  CEILLOG_2 (b, clogb);
+  return (p * (1 + clogb) + (N - p * ((1 << clogb) - b + 1)) / b);
+}
+
+int 
+BIO_Bblock_Bound (int N, int p)
+{
+  int b;
+  b = BIO_Bblock_Init_W (N, p);
+  return (BIO_Bblock_Bound_b (N, p, b));
+}
+
+
+/* adjustment is a hack to overcome inaccuracies in floating point,
+   where (int)(ln4/ln2) can equal 1, not 2. */
+/* copied from mg-1.3f, 17-09-01 kjm18 */
+int 
+BIO_Gamma_Bound (int N, int p)
+{
+  /* return ((int) (p * (2 * log2 ((double) N / p) + 1))); */
+  return ((int) (p * (2 * log2 (((double) N * 1.0001) / p) + 1)));
+}
+
+int 
+floorlog_2 (int b)
+{
+  int logb;
+  FLOORLOG_2 (b, logb);
+  return logb;
+}
+
+int 
+ceillog_2 (int b)
+{
+  int logb;
+  CEILLOG_2 (b, logb);
+  return logb;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_gen.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_gen.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_gen.h	(revision 10506)
@@ -0,0 +1,63 @@
+/**************************************************************************
+ *
+ * bitio_gen.h -- General supoport routines for bitio
+ * Copyright (C) 1994  Neil Sharman and Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing general bitio operations.
+ *
+ *  This file defines functions for calculation the length in bits of a number
+ *  coded unary, binary, delta, gamma, elias, and  bblock coding. It defines 
+ *  routines for calculating the parameter and bounds for bblock coding. 
+ *  Routines for calculating ceil and floor lg are also defined.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_GEN
+#define H_BITIO_GEN
+
+unsigned long BIO_Unary_Length (unsigned long val);
+
+unsigned long BIO_Binary_Length (unsigned long val, unsigned long b);
+
+unsigned long BIO_Gamma_Length (unsigned long val);
+
+unsigned long BIO_Delta_Length (unsigned long val);
+
+unsigned long BIO_Elias_Length (unsigned long val, unsigned long b, double s);
+
+unsigned long BIO_Bblock_Length (unsigned long val, unsigned long b);
+
+int BIO_Bblock_Init (int N, int p);
+
+int BIO_Bblock_Init_W (int N, int p);
+
+int BIO_Bblock_Bound_b (int N, int p, int b);
+
+int BIO_Bblock_Bound (int N, int p);
+
+int BIO_Gamma_Bound (int N, int p);
+
+int floorlog_2 (int b);
+
+int ceillog_2 (int b);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m.h	(revision 10506)
@@ -0,0 +1,543 @@
+/**************************************************************************
+ *
+ * bitio_m.h -- Macros for bitio
+ * Copyright (C) 1994  Neil Sharman and Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_BITIO_M
+#define H_BITIO_M
+
+/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
+
+#ifndef BIO_ENCODE_PROLOGUE
+#define BIO_ENCODE_PROLOGUE
+#endif
+
+#ifndef BIO_DECODE_PROLOGUE
+#define BIO_DECODE_PROLOGUE
+#endif
+
+#ifndef BIO_ENCODE_EPILOGUE
+#define BIO_ENCODE_EPILOGUE
+#endif
+
+#ifndef BIO_DECODE_EPILOGUE
+#define BIO_DECODE_EPILOGUE
+#endif
+
+#ifndef DECODE_ADD
+#define DECODE_ADD(b) (b) += (b) + DECODE_BIT
+#endif
+
+/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
+
+#define POSITIVE(f, x)							\
+  if ((x)<=0) 								\
+    fprintf(stderr,"Error: Cannot "#f" encode %lu\n",(unsigned long)x),exit(1);
+
+
+#define CEILLOG_2(x,v)							\
+do {									\
+  register int _B_x  = (x) - 1;						\
+  (v) = 0;								\
+  for (; _B_x ; _B_x>>=1, ++(v));					\
+} while(0)
+
+
+#define FLOORLOG_2(x,v)							\
+do {									\
+  register int _B_x  = (x);						\
+  (v) = -1;								\
+  for (; _B_x ; _B_x>>=1, ++(v));					\
+} while(0)
+
+
+/****************************************************************************/
+
+
+
+#define UNARY_ENCODE(x)							\
+do {									\
+  register unsigned long _B_x = (x);					\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(unary, _B_x);						\
+  while(--_B_x) ENCODE_BIT(0);						\
+  ENCODE_BIT(1);							\
+  BIO_ENCODE_EPILOGUE;							\
+} while(0)
+
+#define UNARY_ENCODE_L(x, count)					\
+do {									\
+  register unsigned long _B_x = (x);					\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(unary, _B_x);						\
+  (count) += _B_x;							\
+  while(--_B_x) ENCODE_BIT(0);						\
+  ENCODE_BIT(1);							\
+  BIO_ENCODE_EPILOGUE;							\
+} while(0)
+
+#define UNARY_DECODE(x)							\
+do {									\
+  BIO_DECODE_PROLOGUE;							\
+  (x) = 1;								\
+  while (!DECODE_BIT) ++(x);						\
+  BIO_DECODE_EPILOGUE;							\
+} while(0)
+
+#define UNARY_DECODE_L(x, count)					\
+do {									\
+  BIO_DECODE_PROLOGUE;							\
+  (x) = 1;								\
+  while (!DECODE_BIT) ++(x);						\
+  (count) += (x);							\
+  BIO_DECODE_EPILOGUE;							\
+} while(0)
+
+
+#define UNARY_LENGTH(x, count)						\
+do {									\
+  POSITIVE(unary, x);							\
+  (count) = (x);							\
+} while(0)
+
+
+/****************************************************************************/
+
+
+#define BINARY_ENCODE(x, b)						\
+do {									\
+  register unsigned long _B_x = (x);					\
+  register unsigned long _B_b = (b);					\
+  register int _B_nbits, _B_logofb, _B_thresh;				\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(binary, _B_x);						\
+  CEILLOG_2(_B_b, _B_logofb);						\
+  _B_thresh = (1<<_B_logofb) - _B_b;					\
+  if (--_B_x < _B_thresh)						\
+    _B_nbits = _B_logofb-1;						\
+  else									\
+    {									\
+      _B_nbits = _B_logofb;						\
+      _B_x += _B_thresh;						\
+    }									\
+  while (--_B_nbits>=0)							\
+    ENCODE_BIT((_B_x>>_B_nbits) & 0x1);					\
+  BIO_ENCODE_EPILOGUE;							\
+} while(0)
+
+#define BINARY_ENCODE_L(x, b, count)					\
+do {									\
+  register unsigned long _B_x = (x);					\
+  register unsigned long _B_b = (b);					\
+  register int _B_nbits, _B_logofb, _B_thresh;				\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(binary, _B_x);						\
+  CEILLOG_2(_B_b, _B_logofb);						\
+  _B_thresh = (1<<_B_logofb) - _B_b;					\
+  if (--_B_x < _B_thresh)						\
+    _B_nbits = _B_logofb-1;						\
+  else									\
+    {									\
+      _B_nbits = _B_logofb;						\
+      _B_x += _B_thresh;						\
+    }									\
+  (count) += _B_nbits;							\
+  while (--_B_nbits>=0)							\
+    ENCODE_BIT((_B_x>>_B_nbits) & 0x1);					\
+  BIO_ENCODE_EPILOGUE;							\
+} while(0)
+
+
+#define BINARY_DECODE(x, b)						\
+do {									\
+  register unsigned long _B_x = 0;					\
+  register unsigned long _B_b = (b);					\
+  register int _B_i, _B_logofb, _B_thresh;				\
+  BIO_DECODE_PROLOGUE;							\
+  if (_B_b != 1)							\
+    {									\
+      CEILLOG_2(_B_b, _B_logofb);					\
+      _B_thresh = (1<<_B_logofb) - _B_b;				\
+      --_B_logofb;							\
+      for (_B_i=0; _B_i < _B_logofb; ++_B_i)			 	\
+        DECODE_ADD(_B_x);						\
+      if (_B_x >= _B_thresh)						\
+        {								\
+          DECODE_ADD(_B_x);						\
+          _B_x -= _B_thresh;						\
+	}								\
+      (x) = _B_x+1;							\
+    }									\
+  else									\
+    (x) = 1;								\
+  BIO_DECODE_EPILOGUE;							\
+} while(0)
+
+#define BINARY_DECODE_L(x, b, count)					\
+do {									\
+  register unsigned long _B_x = 0;					\
+  register unsigned long _B_b = (b);					\
+  register int _B_i, _B_logofb, _B_thresh;				\
+  BIO_DECODE_PROLOGUE;							\
+  if (_B_b != 1)							\
+    {									\
+      CEILLOG_2(_B_b, _B_logofb);					\
+      _B_thresh = (1<<_B_logofb) - _B_b;				\
+      --_B_logofb;							\
+      (count) += _B_logofb;					       	\
+      for (_B_i=0; _B_i < _B_logofb; ++_B_i)			 	\
+        DECODE_ADD(_B_x);						\
+      if (_B_x >= _B_thresh)						\
+        {								\
+          DECODE_ADD(_B_x);						\
+          _B_x -= _B_thresh;						\
+          ++(count);							\
+	}								\
+      (x) = _B_x+1;							\
+    }									\
+  else									\
+    (x) = 1;								\
+  BIO_DECODE_EPILOGUE;							\
+} while(0)
+
+#define BINARY_LENGTH(x, b, count)					\
+do {									\
+  register unsigned long _B_x = (x);					\
+  register unsigned long _B_b = (b);					\
+  register int _B_nbits, _B_logofb, _B_thresh;				\
+  POSITIVE(binary, _B_x);						\
+  CEILLOG_2(_B_b, _B_logofb);						\
+  _B_thresh = (1<<_B_logofb) - _B_b;					\
+  if (--_B_x < _B_thresh)						\
+    _B_nbits = _B_logofb-1;						\
+  else									\
+    _B_nbits = _B_logofb;						\
+  (count) = _B_nbits;							\
+} while(0)
+
+/****************************************************************************/
+
+
+
+
+#define GAMMA_ENCODE(x)							\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register int _B_logofb;						\
+  register int _B_nbits;						\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(gamma, _B_xx);						\
+  FLOORLOG_2(_B_xx, _B_logofb);						\
+  _B_nbits = _B_logofb+1;						\
+  while(_B_logofb--) ENCODE_BIT(0);					\
+  while (--_B_nbits>=0)							\
+    ENCODE_BIT((_B_xx>>_B_nbits) & 0x1);				\
+  BIO_ENCODE_EPILOGUE;							\
+} while (0)
+
+#define GAMMA_ENCODE_L(x, count)					\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register int _B_logofb;						\
+  register int _B_nbits;						\
+  BIO_ENCODE_PROLOGUE;							\
+  POSITIVE(gamma, _B_xx);						\
+  FLOORLOG_2(_B_xx, _B_logofb);						\
+  _B_nbits = _B_logofb+1;						\
+  (count) += _B_logofb*2+1;						\
+  while(_B_logofb--) ENCODE_BIT(0);					\
+  while (--_B_nbits>=0)							\
+    ENCODE_BIT((_B_xx>>_B_nbits) & 0x1);				\
+  BIO_ENCODE_EPILOGUE;							\
+} while (0)
+
+#define GAMMA_DECODE(x)							\
+do {									\
+  register unsigned long _B_xx = 1;					\
+  register int _B_nbits = 0;						\
+  BIO_DECODE_PROLOGUE;							\
+  while(!DECODE_BIT) ++_B_nbits;					\
+  while (_B_nbits-- > 0)						\
+    DECODE_ADD(_B_xx);							\
+  (x) = _B_xx;								\
+  BIO_DECODE_EPILOGUE;							\
+} while (0)
+
+#define GAMMA_DECODE_L(x, count)					\
+do {									\
+  register unsigned long _B_xx = 1;					\
+  register int _B_nbits = 0;						\
+  BIO_DECODE_PROLOGUE;							\
+  while(!DECODE_BIT) ++_B_nbits;					\
+  (count) += _B_nbits*2+1;						\
+  while (_B_nbits-- > 0)						\
+    DECODE_ADD(_B_xx);							\
+  (x) = _B_xx;								\
+  BIO_DECODE_EPILOGUE;							\
+} while (0)
+
+#define GAMMA_LENGTH(x, count)						\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register int _B_logofb;						\
+  POSITIVE(gamma, _B_xx);						\
+  FLOORLOG_2(_B_xx, _B_logofb);						\
+  (count) = _B_logofb*2+1;						\
+} while (0)
+
+
+
+/****************************************************************************/
+
+
+#define DELTA_ENCODE(x)							\
+do {									\
+  register unsigned long _B_xxx = (x);					\
+  register int _B_logx;							\
+  FLOORLOG_2(_B_xxx, _B_logx);						\
+  GAMMA_ENCODE(_B_logx+1);						\
+  BINARY_ENCODE(_B_xxx+1, 1<<_B_logx);					\
+} while (0)
+
+#define DELTA_ENCODE_L(x, count)					\
+do {									\
+  register unsigned long _B_xxx = (x);					\
+  register int _B_logx;							\
+  FLOORLOG_2(_B_xxx, _B_logx);						\
+  GAMMA_ENCODE_L(_B_logx+1, count);					\
+  BINARY_ENCODE_L(_B_xxx+1, 1<<_B_logx, count);				\
+} while (0)
+
+
+#define DELTA_DECODE(x)							\
+do {									\
+  register unsigned long _B_xxx;					\
+  register int _B_logx;							\
+  GAMMA_DECODE(_B_logx); --_B_logx;					\
+  BINARY_DECODE(_B_xxx, 1<<_B_logx); --_B_xxx;				\
+  (x) = _B_xxx + (1<<_B_logx);						\
+} while (0)
+
+#define DELTA_DECODE_L(x, count)					\
+do {									\
+  register unsigned long _B_xxx;					\
+  register int _B_logx;							\
+  GAMMA_DECODE_L(_B_logx, count); --_B_logx;				\
+  BINARY_DECODE_L(_B_xxx, 1<<_B_logx, count); --_B_xxx;			\
+  (x) = _B_xxx + (1<<_B_logx);						\
+} while (0)
+
+#define DELTA_LENGTH(x, count)						\
+do {									\
+  register unsigned long _B_xxx = (x);					\
+  register int _B_logx, _B_dcount;					\
+  FLOORLOG_2(_B_xxx, _B_logx);						\
+  GAMMA_LENGTH(_B_logx+1, count);					\
+  BINARY_LENGTH(_B_xxx+1, 1<<_B_logx, _B_dcount);			\
+  (count) += _B_dcount;							\
+} while (0)
+
+
+/****************************************************************************/
+
+
+
+
+#define ELIAS_ENCODE(x, b, s)						\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register unsigned long _B_b = (b);					\
+  register double _B_s = (s);						\
+  register int _B_lower=1, _B_upper=1;					\
+  register int _B_k=0;							\
+  register double _B_pow=1.0;						\
+  POSITIVE(elias, _B_xx);						\
+  while (_B_xx>_B_upper) 						\
+    {									\
+      ++_B_k;								\
+      _B_lower = _B_upper+1;						\
+      _B_pow *= _B_s;							\
+      _B_upper += _B_b*_B_pow;						\
+    }									\
+  UNARY_ENCODE(_B_k+1);							\
+  BINARY_ENCODE(_B_xx-_B_lower+1, _B_upper-_B_lower+1);			\
+} while (0)
+
+#define ELIAS_ENCODE_L(x, b, s, count)					\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register unsigned long _B_b = (b);					\
+  register double _B_s = (s);						\
+  register int _B_lower=1, _B_upper=1;					\
+  register int _B_k=0;							\
+  register double _B_pow=1.0;						\
+  POSITIVE(elias, _B_xx);						\
+  while (_B_xx>_B_upper) 						\
+    {									\
+      ++_B_k;								\
+      _B_lower = _B_upper+1;						\
+      _B_pow *= _B_s;							\
+      _B_upper += _B_b*_B_pow;						\
+    }									\
+  UNARY_ENCODE_L(_B_k+1, count);					\
+  BINARY_ENCODE_L(_B_xx-_B_lower+1, _B_upper-_B_lower+1, count);	\
+} while (0)
+
+#define ELIAS_DECODE(x, b, s)						\
+do {									\
+  register unsigned long _B_xx;						\
+  register unsigned long _B_b = (b);					\
+  register double _B_s = (s);						\
+  register int _B_lower=1, _B_upper=1;					\
+  register int _B_k;							\
+  register double _B_pow=1.0;						\
+  UNARY_DECODE(_B_k); --_B_k;						\
+  while (_B_k--)							\
+    {									\
+      _B_lower = _B_upper+1;						\
+      _B_pow *= _B_s;							\
+      _B_upper += _B_b*_B_pow;						\
+    }									\
+  BINARY_DECODE(_B_xx, _B_upper-_B_lower+1); --_B_xx;			\
+  POSITIVE(gamma, _B_xx+_B_lower);				  	\
+  (x) = _B_xx+_B_lower;							\
+} while (0)
+
+#define ELIAS_DECODE_L(x, b, s, count)					\
+do {									\
+  register unsigned long _B_xx;						\
+  register unsigned long _B_b = (b);					\
+  register double _B_s = (s);						\
+  register int _B_lower=1, _B_upper=1;					\
+  register int _B_k;							\
+  register double _B_pow=1.0;						\
+  UNARY_DECODE_L(_B_k, count); --_B_k;					\
+  while (_B_k--)							\
+    {									\
+      _B_lower = _B_upper+1;						\
+      _B_pow *= _B_s;							\
+      _B_upper += _B_b*_B_pow;						\
+    }									\
+  BINARY_DECODE_L(_B_xx, _B_upper-_B_lower+1, count); --_B_xx;		\
+  POSITIVE(gamma, _B_xx+_B_lower);				  	\
+  (x) = _B_xx+_B_lower;							\
+} while (0)
+
+#define ELIAS_LENGTH(x, b, s, count)					\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register unsigned long _B_b = (b);					\
+  register double _B_s = (s);						\
+  register int _B_lower=1, _B_upper=1;					\
+  register int _B_k=0, _B_ecount;					\
+  register double _B_pow=1.0;						\
+  POSITIVE(gamma, _B_xx);						\
+  while (_B_xx>_B_upper) 						\
+    {									\
+      ++_B_k;								\
+      _B_lower = _B_upper+1;						\
+      _B_pow *= _B_s;							\
+      _B_upper += _B_b*_B_pow;						\
+    }									\
+  UNARY_LENGTH(_B_k+1, count);						\
+  BINARY_LENGTH(_B_xx-_B_lower+1, _B_upper-_B_lower+1, _B_ecount);	\
+  (count) += _B_ecount;							\
+} while (0)
+
+
+/****************************************************************************/
+
+
+#define BBLOCK_ENCODE(x, b)						\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register unsigned long _B_bb = (b);					\
+  register int _B_xdivb = 0;						\
+  POSITIVE(bblock, _B_xx);						\
+  --_B_xx;								\
+  while (_B_xx >= _B_bb) 						\
+    {									\
+      ++_B_xdivb;							\
+      _B_xx -= _B_bb;							\
+    }									\
+  UNARY_ENCODE(_B_xdivb+1);						\
+  BINARY_ENCODE(_B_xx+1, _B_bb);					\
+} while (0)
+
+#define BBLOCK_ENCODE_L(x, b, count)					\
+do {									\
+  register unsigned long _B_xx = (x);					\
+  register unsigned long _B_bb = (b);					\
+  register int _B_xdivb = 0;						\
+  POSITIVE(bblock, _B_xx);						\
+  --_B_xx;								\
+  while (_B_xx >= _B_bb) 						\
+    {									\
+      ++_B_xdivb;							\
+      _B_xx -= _B_bb;							\
+    }									\
+  UNARY_ENCODE_L(_B_xdivb+1, count);					\
+  BINARY_ENCODE_L(_B_xx+1, _B_bb, count);				\
+} while (0)
+
+#define BBLOCK_DECODE(x, b)						\
+do {									\
+  register unsigned long _B_x1, _B_xx = 0;				\
+  register unsigned long _B_bb = (b);					\
+  register int _B_xdivb;						\
+  UNARY_DECODE(_B_xdivb); --_B_xdivb;					\
+  while (_B_xdivb--)							\
+    _B_xx += _B_bb;							\
+  BINARY_DECODE(_B_x1, _B_bb);						\
+  (x) = _B_xx+_B_x1;							\
+} while (0)
+
+#define BBLOCK_DECODE_L(x, b, count)					\
+do {									\
+  register unsigned long _B_x1, _B_xx = 0;				\
+  register unsigned long _B_bb = (b);					\
+  register int _B_xdivb;						\
+  UNARY_DECODE_L(_B_xdivb, count); --_B_xdivb;				\
+  while (_B_xdivb--)							\
+    _B_xx += _B_bb;							\
+  BINARY_DECODE_L(_B_x1, _B_bb, count);					\
+  (x) = _B_xx+_B_x1;							\
+} while (0)
+
+#define BBLOCK_LENGTH(x, b, count)					\
+do {									\
+  register unsigned long _B_bcount, _B_xx = (x);			\
+  register unsigned long _B_bb = (b);					\
+  register int _B_xdivb = 0;						\
+  POSITIVE(bblock, _B_xx);						\
+  --_B_xx;								\
+  while (_B_xx >= _B_bb) 						\
+    {									\
+      ++_B_xdivb;							\
+      _B_xx -= _B_bb;							\
+    }									\
+  UNARY_LENGTH(_B_xdivb+1, count);					\
+  BINARY_LENGTH(_B_xx+1, _B_bb, _B_bcount);				\
+  (count) += _B_bcount;  						\
+} while (0)
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_mem.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_mem.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_mem.h	(revision 10506)
@@ -0,0 +1,191 @@
+/**************************************************************************
+ *
+ * bitio_m_mem.h -- Macros for bitio to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are faster than the ones in "mems" files. But 
+ *  with these routines you cannot mix reads and writes on the array of chars,
+ *  or multiple write, at the same time and guarantee them to work, also you 
+ *  cannot seek to a point and do a write. The decode routine can detect when
+ *  you run off the end of the array and will produce an approate error 
+ *  message, and the encode routine will stop when it gets to the end of the 
+ *  character array. 
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_MEM
+#define H_BITIO_M_MEM
+
+typedef struct mem_bitio_state
+  {
+    unsigned char *Base;
+    unsigned char *Pos;
+    int Remaining;
+    unsigned char Buff;
+    unsigned char Btg;
+  }
+mem_bitio_state;
+
+
+
+
+#ifndef DECODE_ERROR
+#define DECODE_ERROR (fprintf(stderr,"Unexpected EOF in \"%s\" on line %d\n",\
+				__FILE__, __LINE__), exit(1))
+#endif
+
+
+
+#define ENCODE_START(p,r)						\
+  {									\
+    register unsigned char *__pos = p;					\
+    register unsigned char *__base = p;					\
+    register int __remaining = r;					\
+    register unsigned char __buff = 0;					\
+    register unsigned char __btg = sizeof(__buff)*8;
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    register unsigned char *__pos = (b).Pos;				\
+    register unsigned char *__base = (b).Base;				\
+    register int __remaining = (b).Remaining;				\
+    register unsigned char __buff = (b).Buff;				\
+    register unsigned char __btg = (b).Btg;
+
+#define ENCODE_BIT(b)							\
+  do {									\
+    --__btg;								\
+    if (b) __buff |= (1 << __btg);					\
+    if (!__btg)								\
+      {									\
+	if (__remaining)						\
+	  {								\
+	    *__pos++ = __buff;						\
+	    --__remaining;						\
+	  }  								\
+	__buff = 0;							\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+  } while(0)
+
+#define ENCODE_PAUSE(b)							\
+    (b).Pos = __pos;							\
+    (b).Base = __base;							\
+    (b).Remaining = __remaining;					\
+    (b).Buff = __buff;							\
+    (b).Btg =  __btg;							\
+  }
+
+#define ENCODE_FLUSH							\
+  do {									\
+    if (__btg != sizeof(__buff)*8)					\
+      if (__remaining)							\
+	{								\
+          *__pos++ = __buff;						\
+          --__remaining;						\
+	}  								\
+    __btg = sizeof(__buff)*8;						\
+  } while (0)
+
+#define ENCODE_DONE							\
+    ENCODE_FLUSH;							\
+  }
+
+
+#define DECODE_START(p,r)						\
+  {									\
+    register unsigned char *__pos = p;					\
+    register unsigned char *__base = p;					\
+    register int __remaining = r;					\
+    register unsigned char __buff = 0;					\
+    register unsigned char __btg = 0;
+
+#define DECODE_CONTINUE(b)						\
+  {									\
+    register unsigned char *__pos = (b).Pos;				\
+    register unsigned char *__base = (b).Base;				\
+    register int __remaining = (b).Remaining;				\
+    register unsigned char __buff = (b).Buff;				\
+    register unsigned char __btg = (b).Btg;
+
+#define DECODE_ADD_FF(b)						\
+  do {									\
+    if (!__btg)								\
+      {									\
+	if (__remaining)						\
+	  {								\
+  	    __buff = *__pos++;						\
+	    --__remaining;						\
+	  }								\
+        else								\
+          __buff = 0xff;						\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+    (b) += (b) + ((__buff >> --__btg) & 1);				\
+  } while(0)
+
+#define DECODE_ADD_00(b)						\
+  do {									\
+    if (!__btg)								\
+      {									\
+	if (__remaining)						\
+	  {								\
+  	    __buff = *__pos++;						\
+	    --__remaining;						\
+	  }								\
+        else								\
+          __buff = 0x00;						\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+    (b) += (b) + ((__buff >> --__btg) & 1);				\
+  } while(0)
+
+#define DECODE_BIT (__btg ? (__buff >> --__btg) & 1 :			\
+   (!__remaining ? 							\
+    (DECODE_ERROR, 0) :							\
+    (__buff = *__pos++, __remaining--, __btg = sizeof(__buff)*8, 	\
+     (__buff >> --__btg) & 1)))
+
+#define DECODE_DONE	;						\
+  }
+
+#define DECODE_PAUSE(b)							\
+    (b).Pos = __pos;							\
+    (b).Base = __base;							\
+    (b).Remaining = __remaining;					\
+    (b).Buff = __buff;							\
+    (b).Btg =  __btg;							\
+  }
+
+#define DECODE_SEEK(pos)						\
+  do {									\
+    register long __new_pos = (pos);					\
+    __pos = __base + (__new_pos >> 3);					\
+    __buff = *__pos++;							\
+    __btg = 8 - (__new_pos&7);						\
+    }									\
+  while(0)
+
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_mems.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_mems.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_mems.h	(revision 10506)
@@ -0,0 +1,114 @@
+/**************************************************************************
+ *
+ * bitio_m_mems.h -- Macros for bitio to memory (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are slower than the ones in "mem" files. but 
+ *  with these routines you can mix reads and writes, or multiple writes,  on
+ *  the array of chars at the same time and guarantee them to work, also you 
+ *  can seek to a point and do a write. The decode and encode macros cannot 
+ *  detect when the end off the character is reached and just continue 
+ *  processing.
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_MEMS
+#define H_BITIO_M_MEMS
+
+typedef struct mems_bitio_state
+  {
+    unsigned char *Base;
+    unsigned long pos;
+  }
+mems_bitio_state;
+
+
+#define ENCODE_START(b,p)						\
+  {									\
+    register unsigned char *__base = b;					\
+    register unsigned long __pos = p;
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    register unsigned char *__base = (b).Base;				\
+    register unsigned long __pos = (b).pos;
+
+#define ENCODE_BIT(b)							\
+  do {									\
+    if (b)								\
+      __base[__pos>>3] |= 0x80 >> (__pos&7);				\
+    else								\
+      __base[__pos>>3] &= 0xff7f >> (__pos&7);				\
+    ++__pos;								\
+  } while(0)
+
+#define ENCODE_PAUSE(b)							\
+    (b).Base = __base;							\
+    (b).pos = __pos;							\
+  }
+
+#define ENCODE_FLUSH
+
+
+#define ENCODE_DONE							\
+    ENCODE_FLUSH;							\
+  }
+
+
+#define DECODE_START(b,p)						\
+  {									\
+    register unsigned char *__base = b;					\
+    register unsigned long __pos = p;
+
+#define DECODE_CONTINUE(b)						\
+  {									\
+    register unsigned char *__base = (b).Base;				\
+    register unsigned long __pos = (b).pos;
+
+#define DECODE_ADD_FF(b)						\
+  do {									\
+    (b) += (b) + (__base[__pos>>3] & (0x80 >> (__pos&7)) != 0);		\
+    ++__pos;								\
+  } while(0)
+
+#define DECODE_ADD_00(b) DECODE_ADD_FF(b)
+
+#define DECODE_BIT 							\
+    (__pos++, ((__base[(__pos-1)>>3] & (0x80 >> ((__pos-1)&7))) != 0))
+
+#define DECODE_DONE	;						\
+  }
+
+#define DECODE_PAUSE(b)							\
+    (b).Base = __base;							\
+    (b).pos = __pos;							\
+  }
+
+#define DECODE_SEEK(pos) __pos = (pos)
+
+#define ENCODE_SEEK(pos) __pos = (pos)
+
+
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_random.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_random.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_random.h	(revision 10506)
@@ -0,0 +1,168 @@
+/**************************************************************************
+ *
+ * bitio_m_random.h -- Macros for bitio to a file (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are slower than the ones in "mem" files. but 
+ *  with these routines you can mix reads and writes, or multiple writes,  on
+ *  the array of chars at the same time and guarantee them to work, also you 
+ *  can seek to a point and do a write. The decode and encode macros cannot 
+ *  detect when the end off the character is reached and just continue 
+ *  processing.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_RANDOM
+#define H_BITIO_M_RANDOM
+
+typedef struct random_bitio_state
+  {
+    FILE *File;
+    unsigned char *Buf;
+    unsigned long Base;
+    unsigned long Used;
+    unsigned long pos;
+    unsigned long len;
+    unsigned long sft;
+  }
+random_bitio_state;
+
+
+#define ENCODE_START(f,l)						\
+  {									\
+    register FILE *__file = f;						\
+    register unsigned char *__buf;					\
+    register unsigned long __pos = 0;					\
+    register unsigned long __base = 0;					\
+    register unsigned long __used = 0;					\
+    register unsigned long __len = (l)-1;				\
+    register unsigned long __sft = 0;					\
+    while (__len) { ++__sft; __len >>=1; }				\
+    __len = 1<<__sft;							\
+    __buf = Xmalloc(__len);						\
+    fseek(__file, 0, 0);						\
+    fread(__buf, 1, __len, __file);
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    register FILE *__file = (b).File;					\
+    register unsigned char *__buf = (b).Buf;				\
+    register unsigned long __pos = (b).pos;				\
+    register unsigned long __base = (b).Base;				\
+    register unsigned long __used = (b).Used;				\
+    register unsigned long __len = (b).len;				\
+    register unsigned long __sft = (b).sft;
+
+#define SEEK fprintf(stderr, "Seek to %d\n",__base)
+#define READ fprintf(stderr, "Read of %d\n",__len)
+#define WRITE fprintf(stderr, "Write of %d\n",__used)
+
+#define WRITE_READ 							\
+	(__used ? (fseek(__file, __base, 0),				\
+                   fwrite(__buf, 1, __len, __file)) : 0,		\
+        __base += __len,						\
+	fseek(__file, __base, 0),					\
+        fread(__buf, 1, __len, __file),					\
+	__pos = 0, __used = 0)
+
+#define ENCODE_BIT(b)							\
+  do {									\
+    if (b)								\
+      __buf[__pos>>3] |= 0x80 >> (__pos&7);				\
+    else								\
+      __buf[__pos>>3] &= 0xff7f >> (__pos&7);				\
+    __used = 1;								\
+    ++__pos;								\
+    if ((__pos>>3) >= __len)						\
+      (void)WRITE_READ;							\
+  } while(0)
+
+#define ENCODE_PAUSE(b)							\
+    (b).File = __file;							\
+    (b).Buf = __buf;							\
+    (b).pos = __pos;							\
+    (b).Base = __base;							\
+    (b).Used = __used;							\
+    (b).len = __len;							\
+    (b).sft = __sft;							\
+  }
+
+#define ENCODE_FLUSH							\
+  if (__used)								\
+    {									\
+      fseek(__file, __base, 0);						\
+      fwrite(__buf, 1, __len, __file);					\
+      __used = 0;							\
+    }
+
+
+
+#define ENCODE_DONE							\
+    ENCODE_FLUSH;							\
+    free(__buf);							\
+  }
+
+
+#define DECODE_START(f,l) ENCODE_START(f,l)
+
+#define DECODE_CONTINUE(b) ENCODE_CONTINUE(b)
+
+#define DECODE_BIT 							\
+    (__pos++, (((__pos-1)>>3) >= __len ? WRITE_READ, __pos=1 : 0),	\
+     ((__buf[(__pos-1)>>3] & (0x80 >> ((__pos-1)&7))) != 0))
+
+#define DECODE_ADD_FF(b) ((b) += (b) + DECODE_BIT)
+
+#define DECODE_ADD_00(b) DECODE_ADD_FF(b)
+
+#define DECODE_DONE ENCODE_DONE
+
+#define DECODE_PAUSE(b)	ENCODE_PAUSE(b)
+
+#define ENCODE_SEEK(pos) 						\
+  do {									\
+    if ((((pos)>>3) >= __base) && ((((pos)+7)>>3) < (__base+__len)))   	\
+      __pos = (pos)-(__base << 3); 					\
+    else								\
+      {									\
+        ENCODE_FLUSH;							\
+        __base = (pos) >> 3;						\
+        __base = ((pos)  >> (__sft+3)) << __sft;			\
+        fseek(__file, __base, 0);					\
+        fread(__buf, 1, __len, __file);					\
+        __pos = (pos)&7; 						\
+        __pos = (pos)&((8 << __sft)-1);					\
+      }									\
+  } while(0)
+
+
+#define DECODE_SEEK(pos) ENCODE_SEEK(pos)
+
+#define ENCODE_TELL ((__base << 3) + __pos)
+
+#define DECODE_TELL ENCODE_TELL
+
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_stdio.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_stdio.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_m_stdio.h	(revision 10506)
@@ -0,0 +1,147 @@
+/**************************************************************************
+ *
+ * bitio_m_stdio.h -- Macros for bitio to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on a FILE*.
+ *  With these routines you cannot mix reads and writes on the FILE,
+ *  or multiple writes, at the same time and guarantee them to work, also you 
+ *  cannot seek to a point and do a write. The decode routine can detect when
+ *  you run off the end of the file and will produce an approate error message.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_STDIO
+#define H_BITIO_M_STDIO
+
+typedef struct stdio_bitio_state
+  {
+    FILE *File;
+    unsigned char Buff;
+    unsigned char Btg;
+  }
+stdio_bitio_state;
+
+
+
+#ifndef DECODE_ERROR
+#define DECODE_ERROR (fprintf(stderr,"Unexpected EOF in \"%s\" on line %d\n",\
+				__FILE__, __LINE__), exit(1))
+#endif
+
+
+
+#define ENCODE_START(f)							\
+  {									\
+    FILE *__outfile = f;						\
+    register unsigned char __buff = 0;					\
+    register unsigned char __btg = sizeof(__buff)*8;
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    FILE *__outfile = (b).File;						\
+    register unsigned char __buff = (b).Buff;				\
+    register unsigned char __btg = (b).Btg;
+
+#define ENCODE_BIT(b)							\
+  do {									\
+    --__btg;								\
+    if (b) __buff |= (1 << __btg);					\
+    if (!__btg)								\
+      {									\
+	putc(__buff, __outfile);					\
+	__buff = 0;							\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+  } while(0)
+
+#define ENCODE_PAUSE(b)							\
+    (b).File = __outfile;						\
+    (b).Buff = __buff;							\
+    (b).Btg =  __btg;							\
+  }
+
+#define ENCODE_DONE							\
+    if (__btg != sizeof(__buff)*8)					\
+      putc(__buff,__outfile);						\
+  }
+
+
+#define DECODE_START(f)							\
+  {									\
+    FILE *__infile = f;							\
+    register unsigned char __buff = 0;					\
+    register unsigned char __btg = 0;
+
+#define DECODE_CONTINUE(b)						\
+  {									\
+    FILE *__infile = (b).File;						\
+    register unsigned char __buff = (b).Buff;				\
+    register unsigned char __btg = (b).Btg;
+
+#define DECODE_ADD_FF(b)						\
+  do {									\
+    if (!__btg)								\
+      {									\
+	register int val = getc(__infile);				\
+	__buff = val == EOF ? 0xff : val;				\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+    (b) += (b) + ((__buff >> --__btg) & 1);				\
+  } while(0)
+
+#define DECODE_ADD_00(b)						\
+  do {									\
+    if (!__btg)								\
+      {									\
+	register int val = getc(__infile);				\
+	__buff = val == EOF ? 0xff : val;				\
+	__btg = sizeof(__buff)*8;					\
+      }									\
+    (b) += (b) + ((__buff >> --__btg) & 1);				\
+  } while(0)
+
+#define DECODE_BIT (__btg ? (__buff >> --__btg) & 1 :			\
+   (__buff = getc(__infile), (feof(__infile) ?				\
+    (DECODE_ERROR, 0) :							\
+    (__btg = sizeof(__buff)*8, (__buff >> --__btg) & 1))))
+
+#define DECODE_DONE	;						\
+  }
+
+#define DECODE_PAUSE(b)							\
+    (b).File = __infile;						\
+    (b).Buff = __buff;							\
+    (b).Btg =  __btg;							\
+  }
+
+
+#define DECODE_SEEK(pos)						\
+  do {									\
+    register long __new_pos = (pos);					\
+    fseek(__infile, __new_pos >> 3, 0);					\
+    __buff = getc(__infile);						\
+    __btg = 8 - (__new_pos&7);						\
+    }									\
+  while(0)
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mem.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mem.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mem.c	(revision 10506)
@@ -0,0 +1,256 @@
+/**************************************************************************
+ *
+ * bitio_mem.c -- Functions for bitio to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:45  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:47  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:39  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+#include "sysfuncs.h"
+
+#include "bitio_m_mem.h"
+#include "bitio_m.h"
+
+int fprintf (FILE *, const char *,...);
+
+
+
+void 
+BIO_Mem_Encode_Start (void *buf, int rem, mem_bitio_state * bs)
+{
+  ENCODE_START (buf, rem)
+    ENCODE_PAUSE (*bs)
+}
+
+void 
+BIO_Mem_Encode_Done (mem_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_DONE
+}
+
+
+void 
+BIO_Mem_Decode_Start (void *buf, int rem, mem_bitio_state * bs)
+{
+  DECODE_START (buf, rem)
+    DECODE_PAUSE (*bs)
+}
+
+
+
+
+void 
+BIO_Mem_Unary_Encode (unsigned long val, mem_bitio_state * bs,
+		      unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_ENCODE_L (val, *bits);
+  else
+    UNARY_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Unary_Decode (mem_bitio_state * bs,
+		      unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_DECODE_L (val, *bits);
+  else
+    UNARY_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Mem_Binary_Encode (unsigned long val, unsigned long b,
+		       mem_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_ENCODE_L (val, b, *bits);
+  else
+    BINARY_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Binary_Decode (unsigned long b, mem_bitio_state * bs,
+		       unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_DECODE_L (val, b, *bits);
+  else
+    BINARY_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Mem_Gamma_Encode (unsigned long val, mem_bitio_state * bs,
+		      unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_ENCODE_L (val, *bits);
+  else
+    GAMMA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Gamma_Decode (mem_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_DECODE_L (val, *bits);
+  else
+    GAMMA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Mem_Delta_Encode (unsigned long val, mem_bitio_state * bs,
+		      unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_ENCODE_L (val, *bits);
+  else
+    DELTA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Delta_Decode (mem_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_DECODE_L (val, *bits);
+  else
+    DELTA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mem_Elias_Encode (unsigned long val, unsigned long b, double s,
+		      mem_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_ENCODE_L (val, b, s, *bits);
+  else
+    ELIAS_ENCODE (val, b, s);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Elias_Decode (unsigned long b, double s,
+		      mem_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_DECODE_L (val, b, s, *bits);
+  else
+    ELIAS_DECODE (val, b, s);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mem_Bblock_Encode (unsigned long val, unsigned long b,
+		       mem_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_ENCODE_L (val, b, *bits);
+  else
+    BBLOCK_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mem_Bblock_Decode (unsigned long b, mem_bitio_state * bs,
+		       unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_DECODE_L (val, b, *bits);
+  else
+    BBLOCK_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mem_Decode_Seek (unsigned long pos, mem_bitio_state * bs)
+{
+  DECODE_CONTINUE (*bs)
+    DECODE_SEEK (pos);
+  DECODE_PAUSE (*bs)
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mem.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mem.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mem.h	(revision 10506)
@@ -0,0 +1,105 @@
+/**************************************************************************
+ *
+ * bitio_mem.h -- Functions for bitio to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing bitwise input and output
+ *  of numbers on an array of chars. These routines are faster than the ones 
+ *  in "mems" files. But with these routines you cannot mix reads and writes 
+ *  on the array of chars, or multiple write, at the same time and guarantee
+ *  them to work, also you cannot seek to a point and do a write. The decode
+ *  routine can detect when you run off the end of the array and will produce
+ *  an approate error message, and the encode routine will stop when it gets
+ *  to the end of the character array. 
+ *
+ *
+ **************************************************************************/
+
+
+#ifndef H_BITIO_MEM
+#define H_BITIO_MEM
+
+
+
+typedef struct mem_bitio_state
+  {
+    unsigned char *Base;
+    unsigned char *Pos;
+    int Remaining;
+    unsigned char Buff;
+    unsigned char Btg;
+  }
+mem_bitio_state;
+
+
+/* NOTE : All bytes are filled high bit first */
+
+
+void BIO_Mem_Encode_Start (void *buf, int rem, mem_bitio_state * bs);
+void BIO_Mem_Encode_Done (mem_bitio_state * bs);
+
+
+
+void BIO_Mem_Decode_Start (void *buf, int rem, mem_bitio_state * bs);
+
+
+
+void BIO_Mem_Unary_Encode (unsigned long val, mem_bitio_state * bs,
+			   unsigned long *bits);
+unsigned long BIO_Mem_Unary_Decode (mem_bitio_state * bs,
+				    unsigned long *bits);
+
+
+
+void BIO_Mem_Binary_Encode (unsigned long val, unsigned long b,
+			    mem_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mem_Binary_Decode (unsigned long b, mem_bitio_state * bs,
+				     unsigned long *bits);
+
+
+
+void BIO_Mem_Gamma_Encode (unsigned long val, mem_bitio_state * bs,
+			   unsigned long *bits);
+unsigned long BIO_Mem_Gamma_Decode (mem_bitio_state * bs, unsigned long *bits);
+
+
+
+void BIO_Mem_Delta_Encode (unsigned long val, mem_bitio_state * bs,
+			   unsigned long *bits);
+unsigned long BIO_Mem_Delta_Decode (mem_bitio_state * bs, unsigned long *bits);
+
+
+void BIO_Mem_Elias_Encode (unsigned long val, unsigned long b, double s,
+			   mem_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mem_Elias_Decode (unsigned long b, double s,
+				 mem_bitio_state * bs, unsigned long *bits);
+
+
+void BIO_Mem_Bblock_Encode (unsigned long val, unsigned long b,
+			    mem_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mem_Bblock_Decode (unsigned long b, mem_bitio_state * bs,
+				     unsigned long *bits);
+
+
+void BIO_Mem_Decode_Seek (unsigned long pos, mem_bitio_state * bs);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mems.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mems.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mems.c	(revision 10506)
@@ -0,0 +1,265 @@
+/**************************************************************************
+ *
+ * bitio_mems.c -- Functions for bitio to memory (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:45  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:48  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:39  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#include "sysfuncs.h"
+
+#include "bitio_m_mems.h"
+#include "bitio_m.h"
+
+int fprintf (FILE *, const char *,...);
+
+
+
+void 
+BIO_Mems_Encode_Start (unsigned char *buf, unsigned long pos,
+		       mems_bitio_state * bs)
+{
+  ENCODE_START (buf, pos)
+    ENCODE_PAUSE (*bs)
+}
+
+void 
+BIO_Mems_Encode_Done (mems_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_DONE
+}
+
+
+void 
+BIO_Mems_Decode_Start (unsigned char *buf, unsigned long pos,
+		       mems_bitio_state * bs)
+{
+  DECODE_START (buf, pos)
+    DECODE_PAUSE (*bs)
+}
+
+
+
+
+void 
+BIO_Mems_Unary_Encode (unsigned long val, mems_bitio_state * bs,
+		       unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_ENCODE_L (val, *bits);
+  else
+    UNARY_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Unary_Decode (mems_bitio_state * bs,
+		       unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_DECODE_L (val, *bits);
+  else
+    UNARY_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Mems_Binary_Encode (unsigned long val, unsigned long b,
+			mems_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_ENCODE_L (val, b, *bits);
+  else
+    BINARY_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Binary_Decode (unsigned long b, mems_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_DECODE_L (val, b, *bits);
+  else
+    BINARY_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Mems_Gamma_Encode (unsigned long val, mems_bitio_state * bs,
+		       unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_ENCODE_L (val, *bits);
+  else
+    GAMMA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Gamma_Decode (mems_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_DECODE_L (val, *bits);
+  else
+    GAMMA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Mems_Delta_Encode (unsigned long val, mems_bitio_state * bs,
+		       unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_ENCODE_L (val, *bits);
+  else
+    DELTA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Delta_Decode (mems_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_DECODE_L (val, *bits);
+  else
+    DELTA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mems_Elias_Encode (unsigned long val, unsigned long b, double s,
+		       mems_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_ENCODE_L (val, b, s, *bits);
+  else
+    ELIAS_ENCODE (val, b, s);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Elias_Decode (unsigned long b, double s,
+		       mems_bitio_state * bs, unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_DECODE_L (val, b, s, *bits);
+  else
+    ELIAS_DECODE (val, b, s);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mems_Bblock_Encode (unsigned long val, unsigned long b,
+			mems_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_ENCODE_L (val, b, *bits);
+  else
+    BBLOCK_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Mems_Bblock_Decode (unsigned long b, mems_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_DECODE_L (val, b, *bits);
+  else
+    BBLOCK_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Mems_Decode_Seek (unsigned long pos, mems_bitio_state * bs)
+{
+  DECODE_CONTINUE (*bs)
+    DECODE_SEEK (pos);
+  DECODE_PAUSE (*bs)
+}
+
+void 
+BIO_Mems_Encode_Seek (unsigned long pos, mems_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_SEEK (pos);
+  ENCODE_PAUSE (*bs)
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mems.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mems.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_mems.h	(revision 10506)
@@ -0,0 +1,99 @@
+/**************************************************************************
+ *
+ * bitio_mems.h -- Functions for bitio to memory (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing bitwise input and output
+ *  of numbers on an array of chars. These routines are slower than the ones 
+ *  in "mem" files. but with these routines you can mix reads and writes, or 
+ *  multiple writes,  on the array of chars at the same time and guarantee
+ *  them to work, also you can seek to a point and do a write. The decode and 
+ *  encode functions cannot detect when the end off the character is reached
+ *  and just continue processing.
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_MEMS
+#define H_BITIO_MEMS
+
+
+
+typedef struct mems_bitio_state
+  {
+    unsigned char *Base;
+    unsigned long pos;
+  }
+mems_bitio_state;
+
+
+/* NOTE : All bytes are filled high bit first */
+
+
+void BIO_Mems_Encode_Start (char *buf, unsigned long pos, mems_bitio_state * bs);
+void BIO_Mems_Encode_Done (mems_bitio_state * bs);
+
+
+
+void BIO_Mems_Decode_Start (void *buf, unsigned long pos, mems_bitio_state * bs);
+
+
+
+void BIO_Mems_Unary_Encode (unsigned long val, mems_bitio_state * bs,
+			    unsigned long *bits);
+unsigned long BIO_Mems_Unary_Decode (mems_bitio_state * bs,
+				     unsigned long *bits);
+
+
+
+void BIO_Mems_Binary_Encode (unsigned long val, unsigned long b,
+			     mems_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mems_Binary_Decode (unsigned long b, mems_bitio_state * bs,
+				      unsigned long *bits);
+
+
+
+void BIO_Mems_Gamma_Encode (unsigned long val, mems_bitio_state * bs,
+			    unsigned long *bits);
+unsigned long BIO_Mems_Gamma_Decode (mems_bitio_state * bs, unsigned long *bits);
+
+
+
+void BIO_Mems_Delta_Encode (unsigned long val, mems_bitio_state * bs,
+			    unsigned long *bits);
+unsigned long BIO_Mems_Delta_Decode (mems_bitio_state * bs, unsigned long *bits);
+
+
+void BIO_Mems_Elias_Encode (unsigned long val, unsigned long b, double s,
+			    mems_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mems_Elias_Decode (unsigned long b, double s,
+				mems_bitio_state * bs, unsigned long *bits);
+
+
+void BIO_Mems_Bblock_Encode (unsigned long val, unsigned long b,
+			     mems_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Mems_Bblock_Decode (unsigned long b, mems_bitio_state * bs,
+				      unsigned long *bits);
+
+
+void BIO_Mems_Decode_Seek (unsigned long pos, mems_bitio_state * bs);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_random.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_random.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_random.c	(revision 10506)
@@ -0,0 +1,328 @@
+/*************************************************************************
+ *
+ * bitio_random.c -- Functions for bitio to a file (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.2  2001/09/21 12:45:03  kjm18
+   updated mg to be in line with version mg-1.3f. Now uses long long for
+   some variables to enable indexing of very large collections.
+
+   Revision 1.1  1999/08/10 21:16:46  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:50  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:40  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+#include "longlong.h"
+
+#include "bitio_m_random.h"
+#include "bitio_m.h"
+
+
+void 
+BIO_Random_Start (FILE * f, unsigned long len,
+		  random_bitio_state * bs)
+{
+  ENCODE_START (f, len)
+    ENCODE_PAUSE (*bs)
+}
+
+void 
+BIO_Random_Done (random_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_DONE
+}
+
+void 
+BIO_Random_Encode_Bit (int bit, random_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_BIT (bit);
+  ENCODE_PAUSE (*bs)
+}
+
+int 
+BIO_Random_Decode_Bit (random_bitio_state * bs)
+{
+  register int val;
+  DECODE_CONTINUE (*bs)
+    val = DECODE_BIT;
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+void 
+BIO_Random_Unary_Encode (unsigned long val, random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_ENCODE_L (val, *bits);
+  else
+    UNARY_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Unary_Decode (random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_DECODE_L (val, *bits);
+  else
+    UNARY_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Random_Binary_Encode (unsigned long val, unsigned long b,
+			  random_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_ENCODE_L (val, b, *bits);
+  else
+    BINARY_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Binary_Decode (unsigned long b,
+			  random_bitio_state * bs,
+			  unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_DECODE_L (val, b, *bits);
+  else
+    BINARY_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Random_Gamma_Encode (unsigned long val, random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_ENCODE_L (val, *bits);
+  else
+    GAMMA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Gamma_Decode (random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_DECODE_L (val, *bits);
+  else
+    GAMMA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Random_Delta_Encode (unsigned long val, random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_ENCODE_L (val, *bits);
+  else
+    DELTA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Delta_Decode (random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_DECODE_L (val, *bits);
+  else
+    DELTA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Random_Elias_Encode (unsigned long val, unsigned long b, double s,
+			 random_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_ENCODE_L (val, b, s, *bits);
+  else
+    ELIAS_ENCODE (val, b, s);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Elias_Decode (unsigned long b, double s,
+			 random_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_DECODE_L (val, b, s, *bits);
+  else
+    ELIAS_DECODE (val, b, s);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Random_Bblock_Encode (unsigned long val, unsigned long b,
+			  random_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_ENCODE_L (val, b, *bits);
+  else
+    BBLOCK_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Random_Bblock_Decode (unsigned long b,
+			  random_bitio_state * bs,
+			  unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_DECODE_L (val, b, *bits);
+  else
+    BBLOCK_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Random_Seek (unsigned long pos, random_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_SEEK (pos);
+  ENCODE_PAUSE (*bs)
+}
+void 
+BIO_Random_Flush (random_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_FLUSH;
+  ENCODE_PAUSE (*bs)
+}
+
+unsigned long 
+BIO_Random_Tell (random_bitio_state * bs)
+{
+  register unsigned long t;
+  ENCODE_CONTINUE (*bs)
+    t = ENCODE_TELL;
+  ENCODE_PAUSE (*bs)
+    return (t);
+}
+
+#ifdef USE_LONG_LONG
+
+void 
+BIO_Random_Seek_LL (mg_ullong pos, random_bitio_state * bs)
+{
+  ENCODE_CONTINUE(*bs)
+
+    if ((((pos) >> 3) >= (mg_ullong)__base) &&
+	((((pos)+7) >> 3) < (mg_ullong)(__base + __len)))
+      {
+	__pos = (long)((pos) - (mg_ullong)(__base << 3));
+      }
+    else
+      {
+        ENCODE_FLUSH;
+	__base = (long)(((pos) >> (__sft+3)) << __sft);
+	
+	fseek(__file,__base,0);
+	fread(__buf,1,__len,__file);
+	__pos = (long)((pos) & ((8 << __sft)-1));
+      }
+  
+  ENCODE_PAUSE(*bs)
+}
+
+mg_ullong 
+BIO_Random_Tell_LL (random_bitio_state * bs)
+{
+  mg_ullong t;
+  ENCODE_CONTINUE(*bs)
+    t = (((mg_ullong)__base) << 3ull) + __pos;
+  ENCODE_PAUSE(*bs)
+  return(t);  
+}
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_random.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_random.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_random.h	(revision 10506)
@@ -0,0 +1,127 @@
+/**************************************************************************
+ *
+ * bitio_random.h -- Functions for bitio to a file (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing bitwise input and output
+ *  of numbers on an array of chars. These routines are slower than the ones 
+ *  in "mem" files. but with these routines you can mix reads and writes, or 
+ *  multiple writes,  on the array of chars at the same time and guarantee
+ *  them to work, also you can seek to a point and do a write. The decode and 
+ *  encode functions cannot detect when the end off the character is reached
+ *  and just continue processing.
+ *
+ *  Modified:
+ *   - long long seek and tell ops
+ *     (1999-08-03 Tim Bell <bhat@cs.mu.oz.au>)
+ **************************************************************************/
+
+#ifndef H_BITIO_RANDOM
+#define H_BITIO_RANDOM
+
+#include "longlong.h"
+
+
+typedef struct random_bitio_state
+  {
+    FILE *File;
+    unsigned char *Buf;
+    unsigned long Base;
+    unsigned long Used;
+    unsigned long pos;
+    unsigned long len;
+    unsigned long sft;
+  }
+random_bitio_state;
+
+
+/* NOTE : All bytes are filled high bit first */
+
+
+void BIO_Random_Start (FILE * f, unsigned long len,
+		       random_bitio_state * bs);
+void BIO_Random_Done (random_bitio_state * bs);
+
+
+
+void BIO_Random_Decode_Start (void *buf, unsigned long pos,
+			      random_bitio_state * bs);
+
+void BIO_Random_Encode_Bit (int bit, random_bitio_state * bs);
+
+int BIO_Random_Decode_Bit (random_bitio_state * bs);
+
+
+void BIO_Random_Unary_Encode (unsigned long val, random_bitio_state * bs,
+			      unsigned long *bits);
+unsigned long BIO_Random_Unary_Decode (random_bitio_state * bs,
+				       unsigned long *bits);
+
+
+
+void BIO_Random_Binary_Encode (unsigned long val, unsigned long b,
+			       random_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Random_Binary_Decode (unsigned long b, random_bitio_state * bs,
+					unsigned long *bits);
+
+
+
+void BIO_Random_Gamma_Encode (unsigned long val, random_bitio_state * bs,
+			      unsigned long *bits);
+unsigned long BIO_Random_Gamma_Decode (random_bitio_state * bs,
+				       unsigned long *bits);
+
+
+
+void BIO_Random_Delta_Encode (unsigned long val, random_bitio_state * bs,
+			      unsigned long *bits);
+unsigned long BIO_Random_Delta_Decode (random_bitio_state * bs,
+				       unsigned long *bits);
+
+
+void BIO_Random_Elias_Encode (unsigned long val, unsigned long b, double s,
+			      random_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Random_Elias_Decode (unsigned long b, double s,
+				       random_bitio_state * bs,
+				       unsigned long *bits);
+
+
+void BIO_Random_Bblock_Encode (unsigned long val, unsigned long b,
+			       random_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Random_Bblock_Decode (unsigned long b,
+					random_bitio_state * bs,
+					unsigned long *bits);
+
+
+void BIO_Random_Seek (unsigned long pos, random_bitio_state * bs);
+
+void BIO_Random_Flush (random_bitio_state * bs);
+
+unsigned long BIO_Random_Tell (random_bitio_state * bs);
+
+#ifdef USE_LONG_LONG
+
+void BIO_Random_Seek_LL (mg_ullong pos, random_bitio_state * bs);
+mg_ullong BIO_Random_Tell_LL (random_bitio_state * bs);
+
+#endif /* USE_LONG_LONG */
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_stdio.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_stdio.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_stdio.c	(revision 10506)
@@ -0,0 +1,281 @@
+/**************************************************************************
+ *
+ * bitio_stdio.c -- Functions for bitio to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:47  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:52  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:41  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+#include "sysfuncs.h"
+
+#include "bitio_m_stdio.h"
+#include "bitio_m.h"
+
+
+
+void 
+BIO_Stdio_Encode_Start (FILE * f, stdio_bitio_state * bs)
+{
+  ENCODE_START (f)
+    ENCODE_PAUSE (*bs)
+}
+
+void 
+BIO_Stdio_Encode_Done (stdio_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_DONE
+}
+
+
+void 
+BIO_Stdio_Decode_Start (FILE * f, stdio_bitio_state * bs)
+{
+  DECODE_START (f)
+    DECODE_PAUSE (*bs)
+}
+
+void 
+BIO_Stdio_Encode_Bit (int bit, stdio_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    ENCODE_BIT (bit);
+  ENCODE_PAUSE (*bs)
+}
+
+
+int 
+BIO_Stdio_Decode_Bit (stdio_bitio_state * bs)
+{
+  register int val;
+  DECODE_CONTINUE (*bs)
+    val = DECODE_BIT;
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Stdio_Unary_Encode (unsigned long val, stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_ENCODE_L (val, *bits);
+  else
+    UNARY_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Unary_Decode (stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    UNARY_DECODE_L (val, *bits);
+  else
+    UNARY_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Stdio_Binary_Encode (unsigned long val, unsigned long b,
+			 stdio_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_ENCODE_L (val, b, *bits);
+  else
+    BINARY_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Binary_Decode (unsigned long b, stdio_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BINARY_DECODE_L (val, b, *bits);
+  else
+    BINARY_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+
+
+
+void 
+BIO_Stdio_Gamma_Encode (unsigned long val, stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_ENCODE_L (val, *bits);
+  else
+    GAMMA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Gamma_Decode (stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    GAMMA_DECODE_L (val, *bits);
+  else
+    GAMMA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Stdio_Delta_Encode (unsigned long val, stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_ENCODE_L (val, *bits);
+  else
+    DELTA_ENCODE (val);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Delta_Decode (stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    DELTA_DECODE_L (val, *bits);
+  else
+    DELTA_DECODE (val);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+
+void 
+BIO_Stdio_Elias_Encode (unsigned long val, unsigned long b, double s,
+			stdio_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_ENCODE_L (val, b, s, *bits);
+  else
+    ELIAS_ENCODE (val, b, s);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Elias_Decode (unsigned long b, double s,
+			stdio_bitio_state * bs,
+			unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    ELIAS_DECODE_L (val, b, s, *bits);
+  else
+    ELIAS_DECODE (val, b, s);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+
+
+void 
+BIO_Stdio_Bblock_Encode (unsigned long val, unsigned long b,
+			 stdio_bitio_state * bs, unsigned long *bits)
+{
+  ENCODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_ENCODE_L (val, b, *bits);
+  else
+    BBLOCK_ENCODE (val, b);
+  ENCODE_PAUSE (*bs)
+}
+
+
+unsigned long 
+BIO_Stdio_Bblock_Decode (unsigned long b, stdio_bitio_state * bs,
+			 unsigned long *bits)
+{
+  register unsigned long val;
+  DECODE_CONTINUE (*bs)
+    if (bits)
+    BBLOCK_DECODE_L (val, b, *bits);
+  else
+    BBLOCK_DECODE (val, b);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
+
+void 
+BIO_Stdio_Decode_Seek (unsigned long pos, stdio_bitio_state * bs)
+{
+  DECODE_CONTINUE (*bs)
+    DECODE_SEEK (pos);
+  DECODE_PAUSE (*bs)
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_stdio.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_stdio.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/bitio_stdio.h	(revision 10506)
@@ -0,0 +1,106 @@
+/**************************************************************************
+ *
+ * bitio_stdio.h -- Functions for bitio to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing bitwise input and output
+ *  of number on a FILE*. With these function you cannot mix reads and writes
+ *  on the FILE, or multiple writes, at the same time and guarantee them to 
+ *  work, also you  cannot seek to a point and do a write. The decode function
+ *  can detect when you run off the end of the file and will produce an 
+ *  approate error message.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_STDIO
+#define H_BITIO_STDIO
+
+
+typedef struct stdio_bitio_state
+  {
+    FILE *File;
+    unsigned char Buff;
+    unsigned char Btg;
+  }
+stdio_bitio_state;
+
+
+/* NOTE : All bytes are filled high bit first */
+
+
+void BIO_Stdio_Encode_Start (FILE * f, stdio_bitio_state * bs);
+void BIO_Stdio_Encode_Done (stdio_bitio_state * bs);
+
+
+
+void BIO_Stdio_Decode_Start (FILE * f, stdio_bitio_state * bs);
+
+
+
+void BIO_Stdio_Encode_Bit (int bit, stdio_bitio_state * bs);
+int BIO_Stdio_Decode_Bit (stdio_bitio_state * bs);
+
+
+void BIO_Stdio_Unary_Encode (unsigned long val, stdio_bitio_state * bs,
+			     unsigned long *bits);
+unsigned long BIO_Stdio_Unary_Decode (stdio_bitio_state * bs,
+				      unsigned long *bits);
+
+
+
+void BIO_Stdio_Binary_Encode (unsigned long val, unsigned long b,
+			      stdio_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Stdio_Binary_Decode (unsigned long b, stdio_bitio_state * bs,
+				       unsigned long *bits);
+
+
+
+void BIO_Stdio_Gamma_Encode (unsigned long val, stdio_bitio_state * bs,
+			     unsigned long *bits);
+unsigned long BIO_Stdio_Gamma_Decode (stdio_bitio_state * bs,
+				      unsigned long *bits);
+
+
+
+void BIO_Stdio_Delta_Encode (unsigned long val, stdio_bitio_state * bs,
+			     unsigned long *bits);
+unsigned long BIO_Stdio_Delta_Decode (stdio_bitio_state * bs,
+				      unsigned long *bits);
+
+
+
+void BIO_Stdio_Elias_Encode (unsigned long val, unsigned long b, double s,
+			     stdio_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Stdio_Elias_Decode (unsigned long b, double s,
+				      stdio_bitio_state * bs,
+				      unsigned long *bits);
+
+
+void BIO_Stdio_Bblock_Encode (unsigned long val, unsigned long b,
+			      stdio_bitio_state * bs, unsigned long *bits);
+unsigned long BIO_Stdio_Bblock_Decode (unsigned long b, stdio_bitio_state * bs,
+				       unsigned long *bits);
+
+
+void BIO_Stdio_Decode_Seek (unsigned long pos, stdio_bitio_state * bs);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/error.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/error.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/error.c	(revision 10506)
@@ -0,0 +1,127 @@
+/* error.c -- error handler for noninteractive utilities
+   Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#include <stdio.h>
+
+#if HAVE_VPRINTF || HAVE_DOPRNT
+# if __STDC__
+#  include <stdarg.h>
+#  define VA_START(args, lastarg) va_start(args, lastarg)
+# else
+#  include <varargs.h>
+#  define VA_START(args, lastarg) va_start(args)
+# endif
+#else
+# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
+# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
+#endif
+
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#else
+void exit ();
+#endif
+
+/* If NULL, error will flush stdout, then print on stderr the program
+   name, a colon and a space.  Otherwise, error will call this
+   function without parameters instead.  */
+void (*error_print_progname) () = NULL;
+
+/* The calling program should define program_name and set it to the
+   name of the executing program.  */
+#if 0 /* [RB/TS:10/95] do not use program_name */
+extern char *program_name;
+#endif
+
+#if HAVE_STRERROR
+char *strerror (int errnum);
+#else
+static char *
+private_strerror (errnum)
+     int errnum;
+{
+  extern char *sys_errlist[];
+  extern int sys_nerr;
+
+  if (errnum > 0 && errnum <= sys_nerr)
+    return sys_errlist[errnum];
+  return "Unknown system error";
+}
+#define strerror private_strerror
+#endif
+
+/* Print the program name and error message MESSAGE, which is a printf-style
+   format string with optional args.
+   If ERRNUM is nonzero, print its corresponding system error message.
+   Exit with status STATUS if it is nonzero.  */
+/* VARARGS */
+
+void
+#if defined(VA_START) && __STDC__
+error (int status, int errnum, const char *message, ...)
+#else
+error (status, errnum, message, va_alist)
+     int status;
+     int errnum;
+     char *message;
+     va_dcl
+#endif
+{
+#ifdef VA_START
+  va_list args;
+#endif
+
+  if (error_print_progname)
+    (*error_print_progname) ();
+  else
+    {
+      fflush (stdout);
+#if 0 /* [RB/TS:10/95] do not use program_name */
+      fprintf (stderr, "%s: ", program_name);
+#endif
+    }
+
+#ifdef VA_START
+  VA_START (args, message);
+# if HAVE_VPRINTF
+  vfprintf (stderr, message, args);
+# else
+  _doprnt (message, args, stderr);
+# endif
+  va_end (args);
+#else
+  fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
+
+  if (errnum)
+    fprintf (stderr, ": %s", strerror (errnum));
+  putc ('\n', stderr);
+  fflush (stderr);
+  if (status)
+    exit (status);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/filestats.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/filestats.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/filestats.c	(revision 10506)
@@ -0,0 +1,133 @@
+/**************************************************************************
+ *
+ * filestats.c -- Functions for keeping stats on file accesses
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:48  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:31:54  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:42  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "filestats.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+File *
+Fopen (char *name, char *mode, unsigned long magic)
+{
+  FILE *f;
+  File *F;
+  unsigned long m;
+  if (!(f = fopen (name, mode)))
+    return (NULL);
+  if (magic)
+    switch (*mode)
+      {
+      case 'r':
+	fread ((char *) &m, sizeof (m), 1, f);
+	NTOHUL(m);  /* [RPAP - Jan 97: Endian Ordering] */
+	if (m != magic)
+	  {
+	    fclose (f);
+	    return (NULL);
+	  }
+	break;
+      case 'w':
+	HTONUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+	fwrite ((char *) &magic, sizeof (magic), 1, f);
+      }
+  if (!(F = Xmalloc (sizeof (File))))
+    {
+      fclose (f);
+      return (NULL);
+    }
+  F->pathname = Xstrdup (name);
+  F->name = strrchr (F->pathname, '/');
+  F->name = F->name ? F->name + 1 : F->pathname;
+  F->f = f;
+  F->Current.NumSeeks = F->Current.NumReads = F->Current.NumBytes = 0;
+  F->Cumulative = F->Current;
+  return (F);
+}
+
+
+int 
+Fclose (File * F)
+{
+  int num;
+  if (!F)
+    return (0);
+  num = fclose (F->f);
+  if (F->pathname)
+    Xfree (F->pathname);
+  Xfree (F);
+  return (num);
+}
+
+size_t 
+Fread (void *ptr, size_t size, size_t nitems, File * F)
+{
+  int num;
+  num = fread ((char *) ptr, size, nitems, F->f);
+  F->Current.NumReads++;
+  F->Current.NumBytes += num * size;
+  return (num);
+}
+
+int 
+Fseek (File * F, long offset, int ptrname)
+{
+  int num;
+  num = fseek (F->f, offset, ptrname);
+  F->Current.NumSeeks++;
+  return (num);
+}
+
+void 
+Rewind (File * F)
+{
+  rewind (F->f);
+  F->Current.NumSeeks++;
+}
+
+
+void 
+ZeroFileStats (File * F)
+{
+  F->Cumulative.NumSeeks += F->Current.NumSeeks;
+  F->Cumulative.NumReads += F->Current.NumReads;
+  F->Cumulative.NumBytes += F->Current.NumBytes;
+  F->Current.NumSeeks = F->Current.NumReads = F->Current.NumBytes = 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/filestats.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/filestats.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/filestats.h	(revision 10506)
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * filestats.h -- Functions for keeping stats on file accesses
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_FILESTATS
+#define H_FILESTATS
+
+#include "sysfuncs.h"
+
+typedef struct FileStats
+  {
+    unsigned long NumSeeks;
+    unsigned long NumReads;
+    unsigned long NumBytes;
+  }
+FileStats;
+
+
+
+typedef struct
+  {
+    FILE *f;
+    char *pathname;
+    char *name;
+    FileStats Current;
+    FileStats Cumulative;
+  }
+File;
+
+/* if magic is 0 no magic number is read or written */
+File *Fopen (char *name, char *mode, unsigned long magic);
+
+size_t Fread (void *ptr, size_t size, size_t nitems, File * F);
+
+int Fseek (File * F, long offset, int ptrname);
+
+void Rewind (File * F);
+
+int Fclose (File * F);
+
+#define Getc(F) (F->Current.NumReads++, F->Current.NumBytes++, getc(F->f))
+
+/* This adds the Current file stats to the Cumulative stats and then zeros
+   the Current stats */
+void ZeroFileStats (File * F);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/ftruncate.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/ftruncate.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/ftruncate.c	(revision 10506)
@@ -0,0 +1,107 @@
+/* ftruncate emulations that work on some System V's.
+   This file is in the public domain.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef F_CHSIZE
+
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  return fcntl (fd, F_CHSIZE, length);
+}
+
+#else /* not F_CHSIZE */
+#ifdef F_FREESP
+
+/* By William Kucharski <kucharsk@netcom.com>.  */
+
+#include <sys/stat.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  struct flock fl;
+  struct stat filebuf;
+
+  if (fstat (fd, &filebuf) < 0)
+    return -1;
+
+  if (filebuf.st_size < length)
+    {
+      /* Extend file length. */
+      if (lseek (fd, (length - 1), SEEK_SET) < 0)
+	return -1;
+
+      /* Write a "0" byte. */
+      if (write (fd, "", 1) != 1)
+	return -1;
+    }
+  else
+    {
+
+      /* Truncate length. */
+
+      fl.l_whence = 0;
+      fl.l_len = 0;
+      fl.l_start = length;
+      fl.l_type = F_WRLCK;	/* write lock on file space */
+
+      /* This relies on the *undocumented* F_FREESP argument to fcntl,
+	 which truncates the file so that it ends at the position
+	 indicated by fl.l_start.  Will minor miracles never cease?  */
+
+      if (fcntl (fd, F_FREESP, &fl) < 0)
+	return -1;
+    }
+
+  return 0;
+}
+
+#else /* not F_CHSIZE nor F_FREESP */
+#ifdef HAVE_CHSIZE
+
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  return chsize (fd, length);
+}
+
+#else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+int
+ftruncate (fd, length)
+     int fd;
+     off_t length;
+{
+  errno = EIO;
+  return -1;
+}
+
+#endif /* not HAVE_CHSIZE */
+#endif /* not F_FREESP */
+#endif /* not F_CHSIZE */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getopt.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getopt.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getopt.c	(revision 10506)
@@ -0,0 +1,750 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#ifdef HAVE_CONFIG_H
+#include "sysfuncs.h"
+#endif
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#endif /* GNU C library.  */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+  {
+    REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+  }
+ordering;
+
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif /* GNU C library.  */
+
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* Determine how to handle the ordering of options and nonoptions.  */
+
+      if (optstring[0] == '-')
+	{
+	  ordering = RETURN_IN_ORDER;
+	  ++optstring;
+	}
+      else if (optstring[0] == '+')
+	{
+	  ordering = REQUIRE_ORDER;
+	  ++optstring;
+	}
+      else if (getenv ("POSIXLY_CORRECT") != NULL)
+	ordering = REQUIRE_ORDER;
+      else
+	ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Now skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc
+		 && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+		 && (longopts == NULL
+		     || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+	    )
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* Special ARGV-element `--' means premature end of options.
+         Skip it like a null option,
+         then exchange with previous non-options as if it were an option,
+         then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+         and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return EOF;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+         either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+	  && (longopts == NULL
+	      || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+	)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return EOF;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+         Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+	   && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+	  || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+      ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound;
+
+      while (*s && *s != '=')
+	s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+	   p++, option_index++)
+	if (!strncmp (p->name, nextchar, s - nextchar))
+	  {
+	    if (s - nextchar == strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, "%s: option `%s' is ambiguous\n",
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*s)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+	         allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = s + 1;
+	      else
+		{
+		  if (opterr)
+		    {
+		      if (argv[optind - 1][1] == '-')
+			/* --option */
+			fprintf (stderr,
+			    "%s: option `--%s' doesn't allow an argument\n",
+				 argv[0], pfound->name);
+		      else
+			/* +option or -option */
+			fprintf (stderr,
+			    "%s: option `%c%s' doesn't allow an argument\n",
+				 argv[0], argv[optind - 1][0], pfound->name);
+		    }
+		  nextchar += strlen (nextchar);
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr, "%s: option `%s' requires an argument\n",
+			     argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+         or the option starts with '--' or is not a valid short
+         option, then it's an error.
+         Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+	  || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, "%s: unrecognized option `--%s'\n",
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+#if 0
+	    if (c < 040 || c >= 0177)
+	      fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+		       argv[0], c);
+	    else
+	      fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+	    /* 1003.2 specifies the format of this message.  */
+	    fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+	  }
+	optopt = c;
+	return '?';
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = 0;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+#if 0
+		    fprintf (stderr, "%s: option `-%c' requires an argument\n",
+			     argv[0], c);
+#else
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr, "%s: option requires an argument -- %c\n",
+			     argv[0], c);
+#endif
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+	         increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getopt.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getopt.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getopt.h	(revision 10506)
@@ -0,0 +1,130 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+  extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+  extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+  extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+  extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument          (or 0) if the option does not take an argument,
+   required_argument    (or 1) if the option requires an argument,
+   optional_argument    (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+  struct option
+    {
+#if	__STDC__
+      const char *name;
+#else
+      char *name;
+#endif
+      /* has_arg can't be an enum because some compilers complain about
+         type mismatches in all the code that assumes it is an int.  */
+      int has_arg;
+      int *flag;
+      int val;
+    };
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+  extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else				/* not __GNU_LIBRARY__ */
+  extern int getopt ();
+#endif				/* not __GNU_LIBRARY__ */
+  extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+			  const struct option *longopts, int *longind);
+  extern int getopt_long_only (int argc, char *const *argv,
+			       const char *shortopts,
+			       const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+  extern int _getopt_internal (int argc, char *const *argv,
+			       const char *shortopts,
+			       const struct option *longopts, int *longind,
+			       int long_only);
+#else				/* not __STDC__ */
+  extern int getopt ();
+  extern int getopt_long ();
+  extern int getopt_long_only ();
+
+  extern int _getopt_internal ();
+#endif				/* not __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _GETOPT_H */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getopt1.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getopt1.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getopt1.c	(revision 10506)
@@ -0,0 +1,178 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+#ifdef HAVE_CONFIG_H
+#include "sysfuncs.h"
+#endif
+
+#include "getopt.h"
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef	NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+	{"add", 1, 0, 0},
+	{"append", 0, 0, 0},
+	{"delete", 1, 0, 0},
+	{"verbose", 0, 0, 0},
+	{"create", 0, 0, 0},
+	{"file", 1, 0, 0},
+	{0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+		       long_options, &option_index);
+      if (c == EOF)
+	break;
+
+      switch (c)
+	{
+	case 0:
+	  printf ("option %s", long_options[option_index].name);
+	  if (optarg)
+	    printf (" with arg %s", optarg);
+	  printf ("\n");
+	  break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case 'd':
+	  printf ("option d with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getpagesize.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getpagesize.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/getpagesize.h	(revision 10506)
@@ -0,0 +1,38 @@
+/* Emulate getpagesize on systems that lack it.  */
+
+#ifndef HAVE_GETPAGESIZE
+
+#ifdef VMS
+#define getpagesize() 512
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _SC_PAGESIZE
+#define getpagesize() sysconf(_SC_PAGESIZE)
+#else
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifndef __WIN32__
+#include <sys/param.h>
+#endif
+
+#ifdef EXEC_PAGESIZE
+#define getpagesize() EXEC_PAGESIZE
+#else
+#ifdef NBPG
+#define getpagesize() NBPG * CLSIZE
+#ifndef CLSIZE
+#define CLSIZE 1
+#endif /* no CLSIZE */
+#else /* no NBPG */
+#ifdef NBPC
+#define getpagesize() NBPC
+#endif /* NBPC */
+#endif /* no NBPG */
+#endif /* no EXEC_PAGESIZE */
+#endif /* no _SC_PAGESIZE */
+
+#endif /* not HAVE_GETPAGESIZE */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/gmalloc.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/gmalloc.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/gmalloc.c	(revision 10506)
@@ -0,0 +1,1318 @@
+/* DO NOT EDIT THIS FILE -- it is automagically generated.  -*- C -*- */
+
+#define _MALLOC_INTERNAL
+
+/* The malloc headers and source files from the C library follow here.  */
+
+/* Declarations for `malloc' and friends.
+   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef _MALLOC_H
+
+#define _MALLOC_H	1
+
+#ifdef _MALLOC_INTERNAL
+
+#ifdef	HAVE_CONFIG_H
+#include <sysfuncs.h>
+#endif
+
+#if	defined(_LIBC) || defined(STDC_HEADERS) || defined(USG)
+#include <string.h>
+#else
+#ifndef memset
+#define	memset(s, zero, n)	bzero ((s), (n))
+#endif
+#ifndef memcpy
+#define	memcpy(d, s, n)		bcopy ((s), (d), (n))
+#endif
+#endif
+
+#if	defined(__GNU_LIBRARY__) || __STDC__
+#include <limits.h>
+#else
+#define	CHAR_BIT	8
+#endif
+
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#endif	/* _MALLOC_INTERNAL.  */
+
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+#if defined (__cplusplus) || __STDC__
+#undef	__P
+#define	__P(args)	args
+#undef	__ptr_t
+#define	__ptr_t		void *
+#else /* Not C++ or ANSI C.  */
+#undef	__P
+#define	__P(args)	()
+#undef	const
+#define	const
+#undef	__ptr_t
+#define	__ptr_t		char *
+#endif /* C++ or ANSI C.  */
+
+#if	__STDC__
+#include <stddef.h>
+#else
+#undef	size_t
+#define	size_t		unsigned int
+#undef	ptrdiff_t
+#define	ptrdiff_t	int
+#endif
+
+#ifndef	NULL
+#define	NULL	0
+#endif
+
+
+/* Allocate SIZE bytes of memory.  */
+extern __ptr_t malloc __P ((size_t __size));
+/* Re-allocate the previously allocated block
+   in __ptr_t, making the new block SIZE bytes long.  */
+extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size));
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0.  */
+extern __ptr_t calloc __P ((size_t __nmemb, size_t __size));
+/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
+extern void free __P ((__ptr_t __ptr));
+
+/* Allocate SIZE bytes allocated to ALIGNMENT bytes.  */
+extern __ptr_t memalign __P ((size_t __alignment, size_t __size));
+
+/* Allocate SIZE bytes on a page boundary.  */
+extern __ptr_t valloc __P ((size_t __size));
+
+
+#ifdef _MALLOC_INTERNAL
+
+/* The allocator divides the heap into blocks of fixed size; large
+   requests receive one or more whole blocks, and small requests
+   receive a fragment of a block.  Fragment sizes are powers of two,
+   and all fragments of a block are the same size.  When all the
+   fragments in a block have been freed, the block itself is freed.  */
+#define INT_BIT		(CHAR_BIT * sizeof(int))
+#define BLOCKLOG	(INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE	(1 << BLOCKLOG)
+#define BLOCKIFY(SIZE)	(((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* Determine the amount of memory spanned by the initial heap table
+   (not an absolute limit).  */
+#define HEAP		(INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+   memory before they will be returned to the system.  */
+#define FINAL_FREE_BLOCKS	8
+
+/* Data structure giving per-block information.  */
+typedef union
+  {
+    /* Heap information for a busy block.  */
+    struct
+      {
+	/* Zero for a large block, or positive giving the
+	   logarithm to the base two of the fragment size.  */
+	int type;
+	union
+	  {
+	    struct
+	      {
+		size_t nfree;	/* Free fragments in a fragmented block.  */
+		size_t first;	/* First free fragment of the block.  */
+	      } frag;
+	    /* Size (in blocks) of a large cluster.  */
+	    size_t size;
+	  } info;
+      } busy;
+    /* Heap information for a free block
+       (that may be the first of a free cluster).  */
+    struct
+      {
+	size_t size;		/* Size (in blocks) of a free cluster.  */
+	size_t next;		/* Index of next free cluster.  */
+	size_t prev;		/* Index of previous free cluster.  */
+      } free;
+  } malloc_info;
+
+/* Pointer to first block of the heap.  */
+extern char *_heapbase;
+
+/* Table indexed by block number giving per-block information.  */
+extern malloc_info *_heapinfo;
+
+/* Address to block number and vice versa.  */
+#define BLOCK(A)	(((char *) (A) - _heapbase) / BLOCKSIZE + 1)
+#define ADDRESS(B)	((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase))
+
+/* Current search index for the heap table.  */
+extern size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+extern size_t _heaplimit;
+
+/* Doubly linked lists of free fragments.  */
+struct list
+  {
+    struct list *next;
+    struct list *prev;
+  };
+
+/* Free list headers for each fragment size.  */
+extern struct list _fraghead[];
+
+/* List of blocks allocated with `memalign' (or `valloc').  */
+struct alignlist
+  {
+    struct alignlist *next;
+    __ptr_t aligned;		/* The address that memaligned returned.  */
+    __ptr_t exact;		/* The address that malloc returned.  */
+  };
+extern struct alignlist *_aligned_blocks;
+
+/* Instrumentation.  */
+extern size_t _chunks_used;
+extern size_t _bytes_used;
+extern size_t _chunks_free;
+extern size_t _bytes_free;
+
+/* Internal version of `free' used in `morecore' (malloc.c). */
+extern void _free_internal __P ((__ptr_t __ptr));
+
+#endif /* _MALLOC_INTERNAL.  */
+
+/* Underlying allocation function; successive calls should
+   return contiguous pieces of memory.  */
+extern __ptr_t (*__morecore) __P ((ptrdiff_t __size));
+
+/* Default value of `__morecore'.  */
+extern __ptr_t __default_morecore __P ((ptrdiff_t __size));
+
+/* If not NULL, this function is called after each time
+   `__morecore' is called to increase the data size.  */
+extern void (*__after_morecore_hook) __P ((void));
+
+/* Nonzero if `malloc' has been called and done its initialization.  */
+extern int __malloc_initialized;
+
+/* Hooks for debugging versions.  */
+extern void (*__free_hook) __P ((__ptr_t __ptr));
+extern __ptr_t (*__malloc_hook) __P ((size_t __size));
+extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Return values for `mprobe': these are the kinds of inconsistencies that
+   `mcheck' enables detection of.  */
+enum mcheck_status
+  {
+    MCHECK_DISABLED = -1,	/* Consistency checking is not turned on.  */
+    MCHECK_OK,			/* Block is fine.  */
+    MCHECK_FREE,		/* Block freed twice.  */
+    MCHECK_HEAD,		/* Memory before the block was clobbered.  */
+    MCHECK_TAIL			/* Memory after the block was clobbered.  */
+  };
+
+/* Activate a standard collection of debugging hooks.  This must be called
+   before `malloc' is ever called.  ABORTFUNC is called with an error code
+   (see enum above) when an inconsistency is detected.  If ABORTFUNC is
+   null, the standard function prints on stderr and then calls `abort'.  */
+extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status))));
+
+/* Check for aberrations in a particular malloc'd block.  You must have
+   called `mcheck' already.  These are the same checks that `mcheck' does
+   when you free or reallocate a block.  */
+extern enum mcheck_status mprobe __P ((__ptr_t __ptr));
+
+/* Activate a standard collection of tracing hooks.  */
+extern void mtrace __P ((void));
+
+/* Statistics available to the user.  */
+struct mstats
+  {
+    size_t bytes_total;		/* Total size of the heap. */
+    size_t chunks_used;		/* Chunks allocated by the user. */
+    size_t bytes_used;		/* Byte total of user-allocated chunks. */
+    size_t chunks_free;		/* Chunks in the free list. */
+    size_t bytes_free;		/* Byte total of chunks in the free list. */
+  };
+
+/* Pick up the current statistics. */
+extern struct mstats mstats __P ((void));
+
+/* Call WARNFUN with a warning message when memory usage is high.  */
+extern void memory_warnings __P ((__ptr_t __start,
+				  void (*__warnfun) __P ((const char *))));
+
+
+/* Relocating allocator.  */
+
+/* Allocate SIZE bytes, and store the address in *HANDLEPTR.  */
+extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size));
+
+/* Free the storage allocated in HANDLEPTR.  */
+extern void r_alloc_free __P ((__ptr_t *__handleptr));
+
+/* Adjust the block at HANDLEPTR to be SIZE bytes long.  */
+extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size));
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* malloc.h  */
+/* Allocate memory on a page boundary.
+   Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#if defined (__GNU_LIBRARY__) || defined (_LIBC)
+#include <stddef.h>
+#include <sys/cdefs.h>
+extern size_t __getpagesize __P ((void));
+#else
+#include "getpagesize.h"
+#define	 __getpagesize()	getpagesize()
+#endif
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+static size_t pagesize;
+
+__ptr_t
+valloc (size)
+     size_t size;
+{
+  if (pagesize == 0)
+    pagesize = __getpagesize ();
+
+  return memalign (pagesize, size);
+}
+/* Memory allocator `malloc'.
+   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* How to really get more memory.  */
+__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore;
+
+/* Debugging hook for `malloc'.  */
+__ptr_t (*__malloc_hook) __P ((size_t __size));
+
+/* Pointer to the base of the first block.  */
+char *_heapbase;
+
+/* Block information table.  Allocated with align/__free (not malloc/free).  */
+malloc_info *_heapinfo;
+
+/* Number of info entries.  */
+static size_t heapsize;
+
+/* Search index in the info table.  */
+size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+size_t _heaplimit;
+
+/* Free lists for each fragment size.  */
+struct list _fraghead[BLOCKLOG];
+
+/* Instrumentation.  */
+size_t _chunks_used;
+size_t _bytes_used;
+size_t _chunks_free;
+size_t _bytes_free;
+
+/* Are you experienced?  */
+int __malloc_initialized;
+
+void (*__after_morecore_hook) __P ((void));
+
+/* Aligned allocation.  */
+static __ptr_t align __P ((size_t));
+static __ptr_t
+align (size)
+     size_t size;
+{
+  __ptr_t result;
+  unsigned long int adj;
+
+  result = (*__morecore) (size);
+  adj = (unsigned long int) ((unsigned long int) ((char *) result -
+						  (char *) NULL)) % BLOCKSIZE;
+  if (adj != 0)
+    {
+      adj = BLOCKSIZE - adj;
+      (void) (*__morecore) (adj);
+      result = (char *) result + adj;
+    }
+
+  if (__after_morecore_hook)
+    (*__after_morecore_hook) ();
+
+  return result;
+}
+
+/* Set everything up and remember that we have.  */
+static int initialize __P ((void));
+static int
+initialize ()
+{
+  heapsize = HEAP / BLOCKSIZE;
+  _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info));
+  if (_heapinfo == NULL)
+    return 0;
+  memset (_heapinfo, 0, heapsize * sizeof (malloc_info));
+  _heapinfo[0].free.size = 0;
+  _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
+  _heapindex = 0;
+  _heapbase = (char *) _heapinfo;
+
+  /* Account for the _heapinfo block itself in the statistics.  */
+  _bytes_used = heapsize * sizeof (malloc_info);
+  _chunks_used = 1;
+
+  __malloc_initialized = 1;
+  return 1;
+}
+
+/* Get neatly aligned memory, initializing or
+   growing the heap info table as necessary. */
+static __ptr_t morecore __P ((size_t));
+static __ptr_t
+morecore (size)
+     size_t size;
+{
+  __ptr_t result;
+  malloc_info *newinfo, *oldinfo;
+  size_t newsize;
+
+  result = align (size);
+  if (result == NULL)
+    return NULL;
+
+  /* Check if we need to grow the info table.  */
+  if ((size_t) BLOCK ((char *) result + size) > heapsize)
+    {
+      newsize = heapsize;
+      while ((size_t) BLOCK ((char *) result + size) > newsize)
+	newsize *= 2;
+      newinfo = (malloc_info *) align (newsize * sizeof (malloc_info));
+      if (newinfo == NULL)
+	{
+	  (*__morecore) (-size);
+	  return NULL;
+	}
+      memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info));
+      memset (&newinfo[heapsize], 0,
+	      (newsize - heapsize) * sizeof (malloc_info));
+      oldinfo = _heapinfo;
+      newinfo[BLOCK (oldinfo)].busy.type = 0;
+      newinfo[BLOCK (oldinfo)].busy.info.size
+	= BLOCKIFY (heapsize * sizeof (malloc_info));
+      _heapinfo = newinfo;
+      /* Account for the _heapinfo block itself in the statistics.  */
+      _bytes_used += newsize * sizeof (malloc_info);
+      ++_chunks_used;
+      _free_internal (oldinfo);
+      heapsize = newsize;
+    }
+
+  _heaplimit = BLOCK ((char *) result + size);
+  return result;
+}
+
+/* Allocate memory from the heap.  */
+__ptr_t
+malloc (size)
+     size_t size;
+{
+  __ptr_t result;
+  size_t block, blocks, lastblocks, start;
+  register size_t i;
+  struct list *next;
+
+  /* ANSI C allows `malloc (0)' to either return NULL, or to return a
+     valid address you can realloc and free (though not dereference).
+
+     It turns out that some extant code (sunrpc, at least Ultrix's version)
+     expects `malloc (0)' to return non-NULL and breaks otherwise.
+     Be compatible.  */
+
+#if	0
+  if (size == 0)
+    return NULL;
+#endif
+
+  if (__malloc_hook != NULL)
+    return (*__malloc_hook) (size);
+
+  if (!__malloc_initialized)
+    if (!initialize ())
+      return NULL;
+
+  if (size < sizeof (struct list))
+      size = sizeof (struct list);
+
+#ifdef SUNOS_LOCALTIME_BUG
+  if (size < 16)
+    size = 16;
+#endif
+
+  /* Determine the allocation policy based on the request size.  */
+  if (size <= BLOCKSIZE / 2)
+    {
+      /* Small allocation to receive a fragment of a block.
+	 Determine the logarithm to base two of the fragment size. */
+      register size_t log = 1;
+      --size;
+      while ((size /= 2) != 0)
+	++log;
+
+      /* Look in the fragment lists for a
+	 free fragment of the desired size. */
+      next = _fraghead[log].next;
+      if (next != NULL)
+	{
+	  /* There are free fragments of this size.
+	     Pop a fragment out of the fragment list and return it.
+	     Update the block's nfree and first counters. */
+	  result = (__ptr_t) next;
+	  next->prev->next = next->next;
+	  if (next->next != NULL)
+	    next->next->prev = next->prev;
+	  block = BLOCK (result);
+	  if (--_heapinfo[block].busy.info.frag.nfree != 0)
+	    _heapinfo[block].busy.info.frag.first = (unsigned long int)
+	      ((unsigned long int) ((char *) next->next - (char *) NULL)
+	       % BLOCKSIZE) >> log;
+
+	  /* Update the statistics.  */
+	  ++_chunks_used;
+	  _bytes_used += 1 << log;
+	  --_chunks_free;
+	  _bytes_free -= 1 << log;
+	}
+      else
+	{
+	  /* No free fragments of the desired size, so get a new block
+	     and break it into fragments, returning the first.  */
+	  result = malloc (BLOCKSIZE);
+	  if (result == NULL)
+	    return NULL;
+
+	  /* Link all fragments but the first into the free list.  */
+	  for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
+	    {
+	      next = (struct list *) ((char *) result + (i << log));
+	      next->next = _fraghead[log].next;
+	      next->prev = &_fraghead[log];
+	      next->prev->next = next;
+	      if (next->next != NULL)
+		next->next->prev = next;
+	    }
+
+	  /* Initialize the nfree and first counters for this block.  */
+	  block = BLOCK (result);
+	  _heapinfo[block].busy.type = log;
+	  _heapinfo[block].busy.info.frag.nfree = i - 1;
+	  _heapinfo[block].busy.info.frag.first = i - 1;
+
+	  _chunks_free += (BLOCKSIZE >> log) - 1;
+	  _bytes_free += BLOCKSIZE - (1 << log);
+	  _bytes_used -= BLOCKSIZE - (1 << log);
+	}
+    }
+  else
+    {
+      /* Large allocation to receive one or more blocks.
+	 Search the free list in a circle starting at the last place visited.
+	 If we loop completely around without finding a large enough
+	 space we will have to get more memory from the system.  */
+      blocks = BLOCKIFY (size);
+      start = block = _heapindex;
+      while (_heapinfo[block].free.size < blocks)
+	{
+	  block = _heapinfo[block].free.next;
+	  if (block == start)
+	    {
+	      /* Need to get more from the system.  Check to see if
+		 the new core will be contiguous with the final free
+		 block; if so we don't need to get as much.  */
+	      block = _heapinfo[0].free.prev;
+	      lastblocks = _heapinfo[block].free.size;
+	      if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
+		  (*__morecore) (0) == ADDRESS (block + lastblocks) &&
+		  (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL)
+		{
+ 		  /* Which block we are extending (the `final free
+ 		     block' referred to above) might have changed, if
+ 		     it got combined with a freed info table.  */
+ 		  block = _heapinfo[0].free.prev;
+  		  _heapinfo[block].free.size += (blocks - lastblocks);
+		  _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
+		  continue;
+		}
+	      result = morecore (blocks * BLOCKSIZE);
+	      if (result == NULL)
+		return NULL;
+	      block = BLOCK (result);
+	      _heapinfo[block].busy.type = 0;
+	      _heapinfo[block].busy.info.size = blocks;
+	      ++_chunks_used;
+	      _bytes_used += blocks * BLOCKSIZE;
+	      return result;
+	    }
+	}
+
+      /* At this point we have found a suitable free list entry.
+	 Figure out how to remove what we need from the list. */
+      result = ADDRESS (block);
+      if (_heapinfo[block].free.size > blocks)
+	{
+	  /* The block we found has a bit left over,
+	     so relink the tail end back into the free list. */
+	  _heapinfo[block + blocks].free.size
+	    = _heapinfo[block].free.size - blocks;
+	  _heapinfo[block + blocks].free.next
+	    = _heapinfo[block].free.next;
+	  _heapinfo[block + blocks].free.prev
+	    = _heapinfo[block].free.prev;
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapindex = block + blocks;
+	}
+      else
+	{
+	  /* The block exactly matches our requirements,
+	     so just remove it from the list. */
+	  _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapinfo[block].free.prev;
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapindex = _heapinfo[block].free.next;
+	  --_chunks_free;
+	}
+
+      _heapinfo[block].busy.type = 0;
+      _heapinfo[block].busy.info.size = blocks;
+      ++_chunks_used;
+      _bytes_used += blocks * BLOCKSIZE;
+      _bytes_free -= blocks * BLOCKSIZE;
+    }
+
+  return result;
+}
+
+
+#ifndef _LIBC
+
+/* On some ANSI C systems, some libc functions call _malloc, _free
+   and _realloc.  Make them use the GNU functions.  */
+
+__ptr_t
+_malloc (size)
+     size_t size;
+{
+  return malloc (size);
+}
+
+void
+_free (ptr)
+     __ptr_t ptr;
+{
+  free (ptr);
+}
+
+__ptr_t
+_realloc (ptr, size)
+     __ptr_t ptr;
+     size_t size;
+{
+  return realloc (ptr, size);
+}
+
+#endif
+/* Free a block of memory allocated by `malloc'.
+   Copyright 1990, 1991, 1992 Free Software Foundation
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* Debugging hook for free.  */
+void (*__free_hook) __P ((__ptr_t __ptr));
+
+/* List of blocks allocated by memalign.  */
+struct alignlist *_aligned_blocks = NULL;
+
+/* Return memory to the heap.
+   Like `free' but don't call a __free_hook if there is one.  */
+void
+_free_internal (ptr)
+     __ptr_t ptr;
+{
+  int type;
+  size_t block, blocks;
+  register size_t i;
+  struct list *prev, *next;
+
+  block = BLOCK (ptr);
+
+  type = _heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Get as many statistics as early as we can.  */
+      --_chunks_used;
+      _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
+      _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;
+
+      /* Find the free cluster previous to this one in the free list.
+	 Start searching at the last block referenced; this may benefit
+	 programs with locality of allocation.  */
+      i = _heapindex;
+      if (i > block)
+	while (i > block)
+	  i = _heapinfo[i].free.prev;
+      else
+	{
+	  do
+	    i = _heapinfo[i].free.next;
+	  while (i > 0 && i < block);
+	  i = _heapinfo[i].free.prev;
+	}
+
+      /* Determine how to link this block into the free list.  */
+      if (block == i + _heapinfo[i].free.size)
+	{
+	  /* Coalesce this block with its predecessor.  */
+	  _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
+	  block = i;
+	}
+      else
+	{
+	  /* Really link this block back into the free list.  */
+	  _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
+	  _heapinfo[block].free.next = _heapinfo[i].free.next;
+	  _heapinfo[block].free.prev = i;
+	  _heapinfo[i].free.next = block;
+	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
+	  ++_chunks_free;
+	}
+
+      /* Now that the block is linked in, see if we can coalesce it
+	 with its successor (by deleting its successor from the list
+	 and adding in its size).  */
+      if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
+	{
+	  _heapinfo[block].free.size
+	    += _heapinfo[_heapinfo[block].free.next].free.size;
+	  _heapinfo[block].free.next
+	    = _heapinfo[_heapinfo[block].free.next].free.next;
+	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
+	  --_chunks_free;
+	}
+
+      /* Now see if we can return stuff to the system.  */
+      blocks = _heapinfo[block].free.size;
+      if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
+	  && (*__morecore) (0) == ADDRESS (block + blocks))
+	{
+	  register size_t bytes = blocks * BLOCKSIZE;
+	  _heaplimit -= blocks;
+	  (*__morecore) (-bytes);
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapinfo[block].free.next;
+	  _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapinfo[block].free.prev;
+	  block = _heapinfo[block].free.prev;
+	  --_chunks_free;
+	  _bytes_free -= bytes;
+	}
+
+      /* Set the next search to begin at this block.  */
+      _heapindex = block;
+      break;
+
+    default:
+      /* Do some of the statistics.  */
+      --_chunks_used;
+      _bytes_used -= 1 << type;
+      ++_chunks_free;
+      _bytes_free += 1 << type;
+
+      /* Get the address of the first free fragment in this block.  */
+      prev = (struct list *) ((char *) ADDRESS (block) +
+			   (_heapinfo[block].busy.info.frag.first << type));
+
+      if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
+	{
+	  /* If all fragments of this block are free, remove them
+	     from the fragment list and free the whole block.  */
+	  next = prev;
+	  for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
+	    next = next->next;
+	  prev->prev->next = next;
+	  if (next != NULL)
+	    next->prev = prev->prev;
+	  _heapinfo[block].busy.type = 0;
+	  _heapinfo[block].busy.info.size = 1;
+
+	  /* Keep the statistics accurate.  */
+	  ++_chunks_used;
+	  _bytes_used += BLOCKSIZE;
+	  _chunks_free -= BLOCKSIZE >> type;
+	  _bytes_free -= BLOCKSIZE;
+
+	  free (ADDRESS (block));
+	}
+      else if (_heapinfo[block].busy.info.frag.nfree != 0)
+	{
+	  /* If some fragments of this block are free, link this
+	     fragment into the fragment list after the first free
+	     fragment of this block. */
+	  next = (struct list *) ptr;
+	  next->next = prev->next;
+	  next->prev = prev;
+	  prev->next = next;
+	  if (next->next != NULL)
+	    next->next->prev = next;
+	  ++_heapinfo[block].busy.info.frag.nfree;
+	}
+      else
+	{
+	  /* No fragments of this block are free, so link this
+	     fragment into the fragment list and announce that
+	     it is the first free fragment of this block. */
+	  prev = (struct list *) ptr;
+	  _heapinfo[block].busy.info.frag.nfree = 1;
+	  _heapinfo[block].busy.info.frag.first = (unsigned long int)
+	    ((unsigned long int) ((char *) ptr - (char *) NULL)
+	     % BLOCKSIZE >> type);
+	  prev->next = _fraghead[type].next;
+	  prev->prev = &_fraghead[type];
+	  prev->prev->next = prev;
+	  if (prev->next != NULL)
+	    prev->next->prev = prev;
+	}
+      break;
+    }
+}
+
+/* Return memory to the heap.  */
+void
+free (ptr)
+     __ptr_t ptr;
+{
+  register struct alignlist *l;
+
+  if (ptr == NULL)
+    return;
+
+  for (l = _aligned_blocks; l != NULL; l = l->next)
+    if (l->aligned == ptr)
+      {
+	l->aligned = NULL;	/* Mark the slot in the list as free.  */
+	ptr = l->exact;
+	break;
+      }
+
+  if (__free_hook != NULL)
+    (*__free_hook) (ptr);
+  else
+    _free_internal (ptr);
+}
+/* Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#ifdef _LIBC
+
+#include <ansidecl.h>
+#include <gnu-stabs.h>
+
+#undef	cfree
+
+function_alias(cfree, free, void, (ptr),
+	       DEFUN(cfree, (ptr), PTR ptr))
+
+#else
+
+void
+cfree (ptr)
+     __ptr_t ptr;
+{
+  free (ptr);
+}
+
+#endif
+/* Change the size of a block allocated by `malloc'.
+   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+		     Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#if  (defined (MEMMOVE_MISSING) || \
+      !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG))
+
+/* Snarfed directly from Emacs src/dispnew.c:
+   XXX Should use system bcopy if it handles overlap.  */
+#ifndef emacs
+
+/* Like bcopy except never gets confused by overlap.  */
+
+static void
+safe_bcopy (from, to, size)
+     char *from, *to;
+     int size;
+{
+  if (size <= 0 || from == to)
+    return;
+
+  /* If the source and destination don't overlap, then bcopy can
+     handle it.  If they do overlap, but the destination is lower in
+     memory than the source, we'll assume bcopy can handle that.  */
+  if (to < from || from + size <= to)
+    bcopy (from, to, size);
+
+  /* Otherwise, we'll copy from the end.  */
+  else
+    {
+      register char *endf = from + size;
+      register char *endt = to + size;
+
+      /* If TO - FROM is large, then we should break the copy into
+	 nonoverlapping chunks of TO - FROM bytes each.  However, if
+	 TO - FROM is small, then the bcopy function call overhead
+	 makes this not worth it.  The crossover point could be about
+	 anywhere.  Since I don't think the obvious copy loop is too
+	 bad, I'm trying to err in its favor.  */
+      if (to - from < 64)
+	{
+	  do
+	    *--endt = *--endf;
+	  while (endf != from);
+	}
+      else
+	{
+	  for (;;)
+	    {
+	      endt -= (to - from);
+	      endf -= (to - from);
+
+	      if (endt < to)
+		break;
+
+	      bcopy (endf, endt, to - from);
+	    }
+
+	  /* If SIZE wasn't a multiple of TO - FROM, there will be a
+	     little left over.  The amount left over is
+	     (endt + (to - from)) - to, which is endt - from.  */
+	  bcopy (from, to, endt - from);
+	}
+    }
+}     
+#endif	/* Not emacs.  */
+
+#define memmove(to, from, size) safe_bcopy ((from), (to), (size))
+
+#endif
+
+
+#define min(A, B) ((A) < (B) ? (A) : (B))
+
+/* Debugging hook for realloc.  */
+__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Resize the given region to the new size, returning a pointer
+   to the (possibly moved) region.  This is optimized for speed;
+   some benchmarks seem to indicate that greater compactness is
+   achieved by unconditionally allocating and copying to a
+   new region.  This module has incestuous knowledge of the
+   internals of both free and malloc. */
+__ptr_t
+realloc (ptr, size)
+     __ptr_t ptr;
+     size_t size;
+{
+  __ptr_t result;
+  int type;
+  size_t block, blocks, oldlimit;
+
+  if (size == 0)
+    {
+      free (ptr);
+      return malloc (0);
+    }
+  else if (ptr == NULL)
+    return malloc (size);
+
+  if (__realloc_hook != NULL)
+    return (*__realloc_hook) (ptr, size);
+
+  block = BLOCK (ptr);
+
+  type = _heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Maybe reallocate a large block to a small fragment.  */
+      if (size <= BLOCKSIZE / 2)
+	{
+	  result = malloc (size);
+	  if (result != NULL)
+	    {
+	      memcpy (result, ptr, size);
+	      _free_internal (ptr);
+	      return result;
+	    }
+	}
+
+      /* The new size is a large allocation as well;
+	 see if we can hold it in place. */
+      blocks = BLOCKIFY (size);
+      if (blocks < _heapinfo[block].busy.info.size)
+	{
+	  /* The new size is smaller; return
+	     excess memory to the free list. */
+	  _heapinfo[block + blocks].busy.type = 0;
+	  _heapinfo[block + blocks].busy.info.size
+	    = _heapinfo[block].busy.info.size - blocks;
+	  _heapinfo[block].busy.info.size = blocks;
+	  /* We have just created a new chunk by splitting a chunk in two.
+	     Now we will free this chunk; increment the statistics counter
+	     so it doesn't become wrong when _free_internal decrements it.  */
+	  ++_chunks_used;
+	  _free_internal (ADDRESS (block + blocks));
+	  result = ptr;
+	}
+      else if (blocks == _heapinfo[block].busy.info.size)
+	/* No size change necessary.  */
+	result = ptr;
+      else
+	{
+	  /* Won't fit, so allocate a new region that will.
+	     Free the old region first in case there is sufficient
+	     adjacent free space to grow without moving. */
+	  blocks = _heapinfo[block].busy.info.size;
+	  /* Prevent free from actually returning memory to the system.  */
+	  oldlimit = _heaplimit;
+	  _heaplimit = 0;
+	  _free_internal (ptr);
+	  _heaplimit = oldlimit;
+	  result = malloc (size);
+	  if (result == NULL)
+	    {
+	      /* Now we're really in trouble.  We have to unfree
+		 the thing we just freed.  Unfortunately it might
+		 have been coalesced with its neighbors.  */
+	      if (_heapindex == block)
+	        (void) malloc (blocks * BLOCKSIZE);
+	      else
+		{
+		  __ptr_t previous = malloc ((block - _heapindex) * BLOCKSIZE);
+		  (void) malloc (blocks * BLOCKSIZE);
+		  _free_internal (previous);
+		}
+	      return NULL;
+	    }
+	  if (ptr != result)
+	    memmove (result, ptr, blocks * BLOCKSIZE);
+	}
+      break;
+
+    default:
+      /* Old size is a fragment; type is logarithm
+	 to base two of the fragment size.  */
+      if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type))
+	/* The new size is the same kind of fragment.  */
+	result = ptr;
+      else
+	{
+	  /* The new size is different; allocate a new space,
+	     and copy the lesser of the new size and the old. */
+	  result = malloc (size);
+	  if (result == NULL)
+	    return NULL;
+	  memcpy (result, ptr, min (size, (size_t) 1 << type));
+	  free (ptr);
+	}
+      break;
+    }
+
+  return result;
+}
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* Allocate an array of NMEMB elements each SIZE bytes long.
+   The entire array is initialized to zeros.  */
+__ptr_t
+calloc (nmemb, size)
+     register size_t nmemb;
+     register size_t size;
+{
+  register __ptr_t result = malloc (nmemb * size);
+
+  if (result != NULL)
+    (void) memset (result, 0, nmemb * size);
+
+  return result;
+}
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU C Library; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#ifndef	__GNU_LIBRARY__
+#define	__sbrk	sbrk
+#endif
+
+#ifdef __GNU_LIBRARY__
+/* It is best not to declare this and cast its result on foreign operating
+   systems with potentially hostile include files.  */
+extern __ptr_t __sbrk __P ((int increment));
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Allocate INCREMENT more bytes of data space,
+   and return the start of data space, or NULL on errors.
+   If INCREMENT is negative, shrink data space.  */
+__ptr_t
+__default_morecore (increment)
+     ptrdiff_t increment;
+{
+  __ptr_t result = (__ptr_t) __sbrk ((int) increment);
+  if (result == (__ptr_t) -1)
+    return NULL;
+  return result;
+}
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+__ptr_t
+memalign (alignment, size)
+     size_t alignment;
+     size_t size;
+{
+  __ptr_t result;
+  unsigned long int adj;
+
+  size = ((size + alignment - 1) / alignment) * alignment;
+
+  result = malloc (size);
+  if (result == NULL)
+    return NULL;
+  adj = (unsigned long int) ((unsigned long int) ((char *) result -
+						  (char *) NULL)) % alignment;
+  if (adj != 0)
+    {
+      struct alignlist *l;
+      for (l = _aligned_blocks; l != NULL; l = l->next)
+	if (l->aligned == NULL)
+	  /* This slot is free.  Use it.  */
+	  break;
+      if (l == NULL)
+	{
+	  l = (struct alignlist *) malloc (sizeof (struct alignlist));
+	  if (l == NULL)
+	    {
+	      free (result);
+	      return NULL;
+	    }
+	  l->next = _aligned_blocks;
+	  _aligned_blocks = l;
+	}
+      l->exact = result;
+      result = l->aligned = (char *) result + alignment - adj;
+    }
+
+  return result;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman.c	(revision 10506)
@@ -0,0 +1,423 @@
+/**************************************************************************
+ *
+ * huffman.c -- Huffman coding functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:51  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:03  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:44  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "huffman.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+/* ->data on success,  
+   NULL on error 
+ */
+huff_data *
+Generate_Huffman_Data (int num, long *freqs, huff_data * data,
+		       u_long * mem)
+{
+  int HNum, i, count;
+  unsigned long *heap;
+  huff_data *hd = data;
+  if (!hd)
+    {
+      if (!(hd = Xmalloc (sizeof (huff_data))))
+	goto error0;
+    }
+  if (!(heap = Xmalloc (num * 2 * sizeof (*heap))))
+    goto error1;
+  if (!(hd->clens = Xmalloc (num * sizeof (char))))
+      goto error2;
+  hd->num_codes = num;
+  if (mem)
+    {
+      if (hd != data)
+	*mem += sizeof (huff_data);
+      *mem += num * sizeof (char);
+    }
+  bcopy ((char *) freqs, (char *) &heap[num], num * sizeof (*heap));
+  bzero ((char *) heap, num * sizeof (*heap));
+
+  /* Initialise the pointers to the leaves */
+  for (count = i = 0; i < num; i++)
+    if (heap[num + i])
+      heap[count++] = num + i;
+
+  /* Reorganise the pointers so that it is a heap */
+  HNum = count;
+  for (i = HNum / 2; i > 0; i--)
+    {
+      register int curr, child;
+      curr = i;
+      child = curr * 2;
+      while (child <= HNum)
+	{
+	  if (child < HNum && heap[heap[child]] < heap[heap[child - 1]])
+	    child++;
+	  if (heap[heap[curr - 1]] > heap[heap[child - 1]])
+	    {
+	      register u_long temp;
+	      temp = heap[child - 1];
+	      heap[child - 1] = heap[curr - 1];
+	      heap[curr - 1] = temp;
+	      curr = child;
+	      child = 2 * curr;
+	    }
+	  else
+	    break;
+	}
+    }
+
+
+  /* Form the huffman tree */
+  while (HNum > 1)
+    {
+      int pos[2];
+
+      for (i = 0; i < 2; i++)
+	{
+	  register int curr, child;
+	  pos[i] = heap[0];
+	  heap[0] = heap[--HNum];
+	  curr = 1;
+	  child = 2;
+	  while (child <= HNum)
+	    {
+	      if (child < HNum &&
+		  heap[heap[child]] < heap[heap[child - 1]])
+		child++;
+	      if (heap[heap[curr - 1]] > heap[heap[child - 1]])
+		{
+		  register int temp;
+		  temp = heap[child - 1];
+		  heap[child - 1] = heap[curr - 1];
+		  heap[curr - 1] = temp;
+		  curr = child;
+		  child = 2 * curr;
+		}
+	      else
+		break;
+	    }
+	}
+
+      heap[HNum + 1] = heap[pos[0]] + heap[pos[1]];
+      heap[pos[0]] = heap[pos[1]] = HNum + 1;
+
+      heap[HNum] = HNum + 1;
+
+      {
+	register int parent, curr;
+	HNum++;
+	curr = HNum;
+	parent = curr >> 1;
+	while (parent && heap[heap[parent - 1]] > heap[heap[curr - 1]])
+	  {
+	    register int temp;
+	    temp = heap[parent - 1];
+	    heap[parent - 1] = heap[curr - 1];
+	    heap[curr - 1] = temp;
+	    curr = parent;
+	    parent = curr >> 1;
+	  }
+      }
+    }
+
+
+  /* Calculate the code lens */
+  heap[0] = -1UL;
+  heap[1] = 0;
+  for (i = 2; i < num * 2; i++)
+    heap[i] = heap[heap[i]] + 1;
+
+  /* zero the lencount's array */
+  bzero ((char *) hd->lencount, sizeof (hd->lencount));
+  hd->maxcodelen = 0;
+  hd->mincodelen = 100;
+
+  /* Set the code length of each leaf in the huffman tree */
+  for (i = 0; i < num; i++)
+    {
+      register u_long codelen = heap[i + num];
+      hd->clens[i] = (char) codelen;
+      if (!codelen)
+	continue;
+      if (codelen > hd->maxcodelen)
+	hd->maxcodelen = codelen;
+      if (codelen < hd->mincodelen)
+	hd->mincodelen = codelen;
+      hd->lencount[codelen]++;
+    }
+
+
+  if (hd->maxcodelen == 0 && hd->mincodelen == 100)
+    {
+      hd->num_codes = 0;
+    }
+  else
+    {
+      /* Calculate the current codes for each different code length */
+      hd->min_code[hd->maxcodelen] = 0;
+      for (i = hd->maxcodelen - 1; i>=0; i--)
+	hd->min_code[i] = (hd->min_code[i + 1] + hd->lencount[i + 1]) >> 1;
+    }
+  free (heap);
+  return (hd);
+
+error2:
+  free (heap);
+error1:
+  if (!data)
+    free (hd);
+error0:
+  return (NULL);
+
+}
+
+unsigned long *
+Generate_Huffman_Codes (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *codes;
+  unsigned long mc[MAX_HUFFCODE_LEN + 1];
+
+  if (!data)
+    return (NULL);
+  if (!(codes = Xmalloc (data->num_codes * sizeof (*codes))))
+    return (NULL);
+  if (mem)
+    *mem += data->num_codes * sizeof (*codes);
+  bcopy ((char *) data->min_code, (char *) mc, sizeof (mc));
+  for (i = 0; i < data->num_codes; i++)
+    if (data->clens[i])
+      codes[i] = mc[(int) (data->clens[i])]++;
+
+  return (codes);
+}
+
+
+unsigned long **
+Generate_Huffman_Vals (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *fcode[MAX_HUFFCODE_LEN + 1];
+  unsigned long **values;
+  unsigned long *vals;
+
+  if (!data)
+    return (NULL);
+  if (!(vals = Xmalloc (data->num_codes * sizeof (*vals))))
+    return (NULL);
+  if (!(values = Xmalloc ((MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *))))
+    {
+      free (vals);
+      return (NULL);
+    }
+
+  bzero ((char *) values, (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *));
+
+  if (mem)
+    *mem += data->num_codes * sizeof (*vals) +
+      (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+  fcode[0] = values[0] = &vals[0];
+  for (i = 1; i <= data->maxcodelen; i++)
+    fcode[i] = values[i] = &vals[(values[i - 1] - vals) + data->lencount[i - 1]];
+
+  for (i = 0; i < data->num_codes; i++)
+    if (data->clens[i])
+      *fcode[(int) (data->clens[i])]++ = i;
+  return (values);
+}
+
+
+
+double 
+Calculate_Huffman_Size (int num, long *freqs, long *counts)
+{
+  double size = 0;
+  huff_data hd;
+  int i;
+  if (!Generate_Huffman_Data (num, freqs, &hd, NULL))
+    return -1;
+  for (i = 0; i < num; i++)
+    size += counts[i] * hd.clens[i];
+  Xfree (hd.clens);
+  return size;
+}
+
+
+
+int 
+Write_Huffman_Data (FILE * f, huff_data * hd)
+{
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONSI(hd->num_codes);
+  HTONSI(hd->mincodelen);
+  HTONSI(hd->maxcodelen);
+
+  if (fwrite (&hd->num_codes, sizeof (hd->num_codes), 1, f) != 1)
+    return -1;
+
+  if (fwrite (&hd->mincodelen, sizeof (hd->mincodelen), 1, f) != 1)
+    return -1;
+
+  if (fwrite (&hd->maxcodelen, sizeof (hd->maxcodelen), 1, f) != 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(hd->num_codes);
+  NTOHSI(hd->mincodelen);
+  NTOHSI(hd->maxcodelen);
+
+  if (hd->num_codes)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int i;
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+	HTONSI(hd->lencount[i]);
+      for (i = 0; i < hd->maxcodelen + 1; i++)
+	HTONUL(hd->min_code[i]);
+
+      if (fwrite (hd->lencount + hd->mincodelen, sizeof (*hd->lencount),
+		  hd->maxcodelen - hd->mincodelen + 1, f) !=
+	  hd->maxcodelen - hd->mincodelen + 1)
+	return -1;
+
+      if (fwrite (hd->min_code, sizeof (*hd->min_code), hd->maxcodelen + 1, f) !=
+	  hd->maxcodelen + 1)
+	return -1;
+
+      if (fwrite (hd->clens, sizeof (*hd->clens), hd->num_codes, f) != hd->num_codes)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+	NTOHSI(hd->lencount[i]);
+      for (i = 0; i < hd->maxcodelen + 1; i++)
+	NTOHUL(hd->min_code[i]);
+    }
+  return 0;
+}
+
+
+
+
+static int 
+General_Read_Huffman_Data (size_t (*rd) (), void *f,
+			   huff_data * hd, u_long * mem, u_long * disk)
+{
+  if (rd (&hd->num_codes, sizeof (hd->num_codes), 1, f) != 1)
+    return -1;
+
+  if (rd (&hd->mincodelen, sizeof (hd->mincodelen), 1, f) != 1)
+    return -1;
+
+  if (rd (&hd->maxcodelen, sizeof (hd->maxcodelen), 1, f) != 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(hd->num_codes);
+  NTOHSI(hd->mincodelen);
+  NTOHSI(hd->maxcodelen);
+
+  if (disk)
+    (*disk) += sizeof (hd->num_codes) + sizeof (hd->mincodelen) +
+      sizeof (hd->maxcodelen);
+
+  hd->clens = NULL;
+
+  if (hd->num_codes)
+    {
+      int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+      bzero ((char *) (hd->lencount), sizeof (hd->lencount));
+      if (rd (hd->lencount + hd->mincodelen, sizeof (*hd->lencount),
+	      hd->maxcodelen - hd->mincodelen + 1, f) !=
+	  hd->maxcodelen - hd->mincodelen + 1)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+	NTOHSI(hd->lencount[i]);
+
+      if (disk)
+	(*disk) += sizeof (*hd->lencount) * (hd->maxcodelen - hd->mincodelen + 1);
+
+      bzero ((char *) (hd->min_code), sizeof (hd->min_code));
+
+      if (rd (hd->min_code, sizeof (*hd->min_code), hd->maxcodelen + 1, f) !=
+	  hd->maxcodelen + 1)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = 0; i < hd->maxcodelen + 1; i++)
+	NTOHUL(hd->min_code[i]);
+
+      if (disk)
+	(*disk) += sizeof (*hd->min_code) * (hd->maxcodelen + 1);
+
+      if (!(hd->clens = Xmalloc (sizeof (*hd->clens) * hd->num_codes)))
+	return -1;
+
+
+      if (rd (hd->clens, sizeof (*hd->clens), hd->num_codes, f) != hd->num_codes)
+	return -1;
+
+      if (disk)
+	(*disk) += sizeof (*hd->clens) * hd->num_codes;
+    }
+
+  if (mem)
+    *mem += sizeof (*hd->clens) * hd->num_codes;
+  return 0;
+}
+
+
+
+int 
+Read_Huffman_Data (FILE * f, huff_data * hd, u_long * mem, u_long * disk)
+{
+  return General_Read_Huffman_Data (fread, f, hd, mem, disk);
+}
+
+
+
+
+int 
+F_Read_Huffman_Data (File * f, huff_data * hd, u_long * mem, u_long * disk)
+{
+  return General_Read_Huffman_Data (Fread, f, hd, mem, disk);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman.h	(revision 10506)
@@ -0,0 +1,114 @@
+/**************************************************************************
+ *
+ * huffman.h -- Huffman coding functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_HUFFMAN
+#define H_HUFFMAN
+
+#include "sysfuncs.h"
+
+#include "filestats.h"
+
+
+#define MAX_HUFFCODE_LEN 31
+
+typedef struct huff_data
+  {
+    int num_codes;
+    int mincodelen;
+    int maxcodelen;
+    int lencount[MAX_HUFFCODE_LEN + 1];
+    unsigned long min_code[MAX_HUFFCODE_LEN + 1];
+    char *clens;
+  }
+huff_data;
+
+
+huff_data *Generate_Huffman_Data (int num, long *freqs, huff_data * data,
+				  u_long * mem);
+
+unsigned long *Generate_Huffman_Codes (huff_data * data, u_long * mem);
+
+unsigned long **Generate_Huffman_Vals (huff_data * data, u_long * mem);
+
+int Write_Huffman_Data (FILE * f, huff_data * hd);
+
+int Read_Huffman_Data (FILE * f, huff_data * hd, u_long * mem, u_long * disk);
+
+int F_Read_Huffman_Data (File * f, huff_data * hd, u_long * mem, u_long * disk);
+
+/* Calculate the number of bits required to code the data with the
+   specified frequencies. Normally freqs and counts should point to
+   the same array. */
+double Calculate_Huffman_Size (int num, long *freqs, long *counts);
+
+
+
+#define HUFF_ENCODE(x, codes, lens)					\
+  do {									\
+    register int __i;							\
+    register int __clen = (lens)[x];					\
+    register unsigned long __code = (codes)[x];				\
+    for (__i=__clen-1; __i>=0; --__i)					\
+      ENCODE_BIT((__code >> __i) & 1);					\
+  } while(0)
+
+#define HUFF_ENCODE_L(x, codes, lens, count)				\
+  do {									\
+    HUFF_ENCODE(x, codes, lens);		   			\
+    (count) += (lens)[x];						\
+  } while(0)
+
+
+#define HUFF_DECODE(x, mcodes, values)					\
+  do {									\
+    register unsigned long *__min_code = (mcodes);			\
+    register unsigned long *__mclen = __min_code;			\
+    register unsigned long **__values = (values);			\
+    register unsigned long __code = 0;					\
+    do									\
+      {									\
+        DECODE_ADD(__code);						\
+      }									\
+    while (__code < *++__mclen);					\
+    (x) = __values[__mclen - __min_code][__code - *__mclen];		\
+  } while(0);
+
+
+#define HUFF_DECODE_L(x, mcodes, values, count)				\
+  do {									\
+    register unsigned long *__min_code = (mcodes);			\
+    register unsigned long *__mclen = __min_code;			\
+    register unsigned long **__values = (values);			\
+    register unsigned long __code = 0;					\
+    do									\
+      {									\
+        DECODE_ADD(__code);						\
+	(count)++;							\
+      }									\
+    while (__code < *++__mclen);					\
+    (x) = __values[__mclen - __min_code][__code - *__mclen];		\
+  } while(0);
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_mem.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_mem.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_mem.c	(revision 10506)
@@ -0,0 +1,66 @@
+/**************************************************************************
+ *
+ * huffman_mem.c -- Huffman coding functions to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:51  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:05  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:45  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "bitio_m.h"
+#include "bitio_m_mem.h"
+#include "huffman.h"
+
+#if 0
+int fprintf (FILE *, const char *,...);
+#endif
+
+void 
+BIO_Mem_Huff_Encode (unsigned long val, unsigned long *codes,
+		     char *clens, mem_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    HUFF_ENCODE (val, codes, clens);
+  ENCODE_PAUSE (*bs)
+}
+
+unsigned long 
+BIO_Mem_Huff_Decode (unsigned long *mincodes,
+		     unsigned long **values, mem_bitio_state * bs)
+{
+  unsigned long val;
+  DECODE_CONTINUE (*bs)
+    HUFF_DECODE (val, mincodes, values);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_mem.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_mem.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_mem.h	(revision 10506)
@@ -0,0 +1,36 @@
+/**************************************************************************
+ *
+ * huffman_mem.h -- Huffman coding functions to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_HUFFMAN_MEM
+#define H_HUFFMAN_MEM
+
+
+
+void BIO_Mem_Huff_Encode (unsigned long val, unsigned long *codes,
+			  char *clens, mem_bitio_state * bs);
+
+unsigned long BIO_Mem_Huff_Decode (unsigned long *mincodes,
+			      unsigned long **values, mem_bitio_state * bs);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_stdio.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_stdio.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_stdio.c	(revision 10506)
@@ -0,0 +1,70 @@
+/**************************************************************************
+ *
+ * huffman_stdio.c -- Huffman coding function to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:52  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:07  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:46  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "huffman.h"
+
+#if 0
+int fprintf (FILE *, const char *,...);
+int _filbuf (FILE *);
+int _flsbuf (unsigned, FILE *);
+#endif
+
+void 
+BIO_Stdio_Huff_Encode (unsigned long val, unsigned long *codes,
+		       char *clens, stdio_bitio_state * bs)
+{
+  ENCODE_CONTINUE (*bs)
+    HUFF_ENCODE (val, codes, clens);
+  ENCODE_PAUSE (*bs)
+}
+
+unsigned long 
+BIO_Stdio_Huff_Decode (unsigned long *mincodes,
+		       unsigned long **values,
+		       stdio_bitio_state * bs)
+{
+  unsigned long val;
+  DECODE_CONTINUE (*bs)
+    HUFF_DECODE (val, mincodes, values);
+  DECODE_PAUSE (*bs)
+    return (val);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_stdio.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_stdio.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/huffman_stdio.h	(revision 10506)
@@ -0,0 +1,38 @@
+/**************************************************************************
+ *
+ * huffman_stdio.h -- Huffman coding function to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_HUFFMAN_STDIO
+#define H_HUFFMAN_STDIO
+
+
+
+void BIO_Stdio_Huff_Encode (unsigned long val, unsigned long *codes,
+			    char *clens, stdio_bitio_state * bs);
+
+
+unsigned long BIO_Stdio_Huff_Decode (unsigned long *mincodes,
+				     unsigned long **values,
+				     stdio_bitio_state * bs);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/local_strings.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/local_strings.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/local_strings.c	(revision 10506)
@@ -0,0 +1,415 @@
+/**************************************************************************
+ *
+ * local_strings -- provides some extra string routines
+ * Copyright (C) 1994  Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "local_strings.h"
+#include "memlib.h"
+
+/* =========================================================================
+ * Function: arg_atoi
+ * Description: 
+ *      Converts an ascii string to an integer
+ *      but allows a scale string immediately following.
+ *      i.e. "10Mb" or "20Kb" or "40Megabytes"
+ *      There must be no gap between the last digit and the scale.
+ *      Only the fist letter is significant.
+ *      K = Kilo
+ *      M = Mega
+ *      G = Giga
+ * Input: 
+ *      string of form: xxxxxxK or xxxxxxxM or xxxxxxxG
+ *      where x is a digit
+ * Output: 
+ *      a scaled integer
+ * ========================================================================= */
+
+#define KILO 	1024
+#define MEGA	1024*1024
+#define GIGA	1024*1024*1024
+
+int 
+arg_atoi (char *str)
+{
+  char *str_ptr = str;
+  char ch = '\0';
+  long scale = 1;
+
+  /* find any scale letter immediately after digits */
+  ch = *str_ptr;
+  while (!isalpha (ch) && (ch != '\0'))
+    ch = *str_ptr++;
+
+  /* replace scale letter by end-of-string character */
+  *str_ptr = '\0';
+
+  /* set scale appropriately */
+  switch (ch)
+    {
+    case 'K':
+      scale = KILO;
+      break;
+    case 'M':
+      scale = MEGA;
+      break;
+    case 'G':
+      scale = GIGA;
+      break;
+    default:
+      scale = 1;
+      break;
+    }
+
+  return (atoi (str) * scale);
+
+}
+
+/* ===============================================================================
+ * Function: compare
+ * Description: Compare two strings. 
+ * Input: Two binary strings, first byte of string indicates length. 
+ * Output: Like standard strcmp.
+ *      = 0 if s1 = s2
+ *      < 0 if s1 < s2
+ *      > 0 if s1 > s2
+ * =============================================================================== */
+int 
+compare (u_char * s1, u_char * s2)
+{
+  int l1 = *s1, l2 = *s2;
+  int l = (l1 < l2) ? l1 : l2;
+
+  while (l--)
+    if (*++s1 != *++s2)
+      return (*s1 - *s2);
+  return (l1 - l2);
+
+}
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char casecharmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+/* ===============================================================================
+ * Function: casecompare   [RPAP - Jan 97: Stem Index Change]
+ * Description: Compare two strings in dictionary order
+ * Input: Two binary strings, first byte of string indicates length. 
+ * Output:
+ *      = 0 if s1 = s2
+ *      < 0 if s1 < s2
+ *      > 0 if s1 > s2
+ * =============================================================================== */
+int 
+casecompare (u_char * s1, u_char * s2)
+{
+  int l1 = *s1, l2 = *s2;
+  int l = (l1 < l2) ? l1 : l2;
+  int pos = 0;
+  register int diff = 0;
+
+  while (l--)
+    if ((diff = casecharmap[*++s1] - casecharmap[*++s2]) != 0)
+      return (diff);
+    else if ((diff = *s1 - *s2) != 0)
+      if (!pos)
+	pos = diff;
+
+  return ((l1 - l2) ? (l1 - l2) : (pos));
+
+}
+
+/* =========================================================================
+ * Function: copy_string
+ * Description: 
+ *      Copies a string with the len in 1st byte
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+u_char *
+copy_string (u_char * src_str)
+{
+  u_char *copy = Xmalloc (src_str[0] + 1);
+
+  if (!copy)
+    return NULL;
+
+  bcopy ((char *) src_str, (char *) (copy), src_str[0] + 1);
+  return copy;
+
+}
+
+
+/* ===============================================================================
+ * Function: prefixlen
+ * Description: Returns length of common prefix string between s1 and s2.
+ * Input: two binary strings
+ * Output: prefix length
+ * =============================================================================== */
+int 
+prefixlen (u_char * s1, u_char * s2)
+{
+  int l = (*s1 < *s2) ? *s1 : *s2;
+  int i = 0;
+
+  while (i < l && *++s1 == *++s2)
+    i++;
+  return (i);
+}
+
+
+/* ===============================================================================
+ * Function: char2str
+ * Description: 
+ *      Ensures that non-printable characters are converted to a string
+ *      which is printable i.e. it indentifies the character.
+ *      e.g. carriage-return = "\n".
+ * Input: character (may be non-printable)
+ * Output: pointer to static string
+ * =============================================================================== */
+
+char *
+char2str (u_char c)
+{
+  static char buf[10];
+  switch (c)
+    {
+    case '\n':
+      sprintf (buf, "\\n");
+      break;
+    case '\b':
+      sprintf (buf, "\\b");
+      break;
+    case '\f':
+      sprintf (buf, "\\f");
+      break;
+    case '\t':
+      sprintf (buf, "\\t");
+      break;
+    default:
+	if (c >= ' ' && c <= 126)
+	switch (c)
+	  {
+	  case '\\':
+	    sprintf (buf, "\\\\");
+	    break;
+	  case '\"':
+	    sprintf (buf, "\\\"");
+	    break;
+	  case '\'':
+	    sprintf (buf, "\\\'");
+	    break;
+	  default:
+	    buf[0] = c;
+	    buf[1] = '\0';
+	    break;
+	  }
+      else
+	sprintf (buf, "\\x%02x", c);
+      break;
+    }
+  return buf;
+}
+
+/* ===============================================================================
+ * Function: word2str
+ * Description: 
+ *      Converts a string with possible non-printable characters into a string
+ *      consisting entirely of printable characters.
+ * Input: string, length stored in first byte
+ * Output: pointer to static string
+ * =============================================================================== */
+
+char *
+word2str (u_char * s)
+{
+  static char buf[1024];
+  char *p = buf;
+  int i, len = (int) *s++;
+
+  bzero (buf, sizeof (buf));
+  for (i = 0; i < len; i++)
+    {
+      strcpy (p, char2str (s[i]));
+      p = strchr (p, '\0');
+    }
+  return buf;
+}
+
+
+/* =========================================================================
+ * Function: de_escape_string
+ * Description: 
+ *      Turn a string containing \ escapes into real characters
+ *      Note this destroys the string s in the process
+ * Input: string to de-escape 
+ * Output: the de-escaped string
+ * ========================================================================= */
+char *
+de_escape_string (char *s)
+{
+  char *org = s;
+  char *d = s;
+  while (*s)
+    {
+      if (*s == '\\')
+	{
+	  s++;
+	  switch (*s++)
+	    {
+	    case '\0':
+	      *d++ = '\\';
+	      s--;
+	      break;
+	    case '\\':
+	      *d++ = '\\';
+	      break;
+	    case 'b':
+	      *d++ = '\b';
+	      break;
+	    case 'f':
+	      *d++ = '\f';
+	      break;
+	    case 'n':
+	      *d++ = '\n';
+	      break;
+	    case 'r':
+	      *d++ = '\r';
+	      break;
+	    case 't':
+	      *d++ = '\r';
+	      break;
+	    case '\"':
+	      *d++ = '\"';
+	      break;
+	    case '\'':
+	      *d++ = '\'';
+	      break;
+	    case 'x':
+	      {
+		int num = 0;
+		if (isxdigit (*s))
+		  {
+		    char ch = toupper (*s++);
+		    num = ch <= '9' ? ch - '0' : ch - 'A' + 10;
+		  }
+		if (isxdigit (*s))
+		  {
+		    char ch = toupper (*s++);
+		    num = (num << 4) + (ch <= '9' ? ch - '0' : ch - 'A' + 10);
+		  }
+		*d++ = num;
+		break;
+	      }
+	    case '0':
+	    case '1':
+	    case '2':
+	    case '3':
+	    case '4':
+	    case '5':
+	    case '6':
+	    case '7':
+	      {
+		int num = *(s - 1) - '0';
+		if (*s >= '0' && *s <= '7')
+		  num = (num << 3) + *s++ - '0';
+		if (*s >= '0' && *s <= '7')
+		  num = (num << 3) + *s++ - '0';
+		*d++ = num;
+		break;
+	      }
+	    }
+	}
+      else
+	*d++ = *s++;
+    }
+  *d = '\0';
+  return (org);
+}
+
+/* =========================================================================
+ * Function: str255_to_string 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+char *
+str255_to_string (u_char * str255, char *str)
+{
+  static char buf[256];
+  char *str_base = NULL;
+  int len = *str255++;
+  int i = 0;
+
+  /* if haven't been given a str to write to then use local buffer */
+  if (!str)
+    str = &(buf[0]);
+
+  str_base = str;
+  for (i = 0; i < len; i++)
+    {
+      *str++ = *str255++;
+    }
+  *str = '\0';
+
+  return str_base;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/local_strings.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/local_strings.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/local_strings.h	(revision 10506)
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * local_strings.h -- string routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef LOCAL_STRINGS_H
+#define LOCAL_STRINGS_H
+
+#include "sysfuncs.h"
+
+int arg_atoi (char *str);
+int compare (u_char * s1, u_char * s2);
+int casecompare (u_char * s1, u_char * s2);   /* [RPAP - Jan 97: Stem Index Change] */
+u_char *copy_string (u_char * src_str);
+char *str255_to_string (u_char * str255, char *str);
+int prefixlen (u_char * s1, u_char * s2);
+char *char2str (u_char c);
+char *word2str (u_char * s);
+char *de_escape_string (char *s);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/longlong.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/longlong.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/longlong.h	(revision 10506)
@@ -0,0 +1,81 @@
+/**************************************************************************
+ *
+ * longlong.h -- Use of GCC's long long integer types
+ * Copyright (C) 1999 Tim A.H. Bell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef H_LONGLONG
+#define H_LONGLONG
+
+#ifndef __WIN32__
+#include "config.h"
+#endif
+
+/*
+  Use GCC's "long long" integer types for certain variables, to avoid
+  overflowing 32 bit integers.
+
+  Other files affected:
+  
+    lib:
+        bitio_random.c
+        bitio_random.h
+	
+    src/text:
+        ivf.pass1.c
+        ivf.pass2.c
+        build.h
+        mg_passes.c
+        text.h
+	mgstat.c
+*/
+
+/*#define TESTING_OVERFLOW*/
+
+#ifdef TESTING_OVERFLOW
+
+/* Test the overflow detection by using tiny (16-bit) types */
+typedef unsigned short int mg_ullong;
+typedef short int mg_llong;
+
+#define ULL_FS "u"
+#define LL_FS "d"
+
+#elif defined __GNUC__ && ! defined DISABLE_LONG_LONG
+
+/* We're using GCC, so it's okay to use "long long" (64-bit) types */
+#define USE_LONG_LONG
+
+typedef unsigned long long int mg_ullong;
+typedef long long int mg_llong;
+
+#define ULL_FS "llu"
+#define LL_FS "lld"
+
+#else
+
+/* Not using GCC, so fall back on plain "long" (32-bit) types */
+typedef unsigned long int mg_ullong;
+typedef long int mg_llong;
+
+#define ULL_FS "lu"
+#define LL_FS "ld"
+
+#endif /* __GNUC__ */
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/lovinstem.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/lovinstem.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/lovinstem.c	(revision 10506)
@@ -0,0 +1,1187 @@
+/**************************************************************************
+ *
+ * lovinstem.c -- Stemming code
+ * Copyright (C) 1994  Linh Huynh (linh@kbs.citri.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+
+/*****************************************************************************
+ *
+ *   Transformational Rules used in Recoding Stem Terminations
+ *
+ *   Parameter in functions:
+ *       ch : the second last character of the old ending
+ *            (after removing one of double consonants) 
+ *
+ ****************************************************************************/
+
+
+/************ Conditional rules associated with transformations **************/
+
+static int aio ();
+static int s ();
+static int pt ();
+static int m ();
+static int n ();
+
+static int 
+aio (ch)			/* Rule number 9     */
+     char ch;
+{
+  return ((ch != 'a') && (ch != 'i') && (ch != 'o'));
+}
+
+static int 
+s (ch)				/* Rule Number 24    */
+     char ch;
+{
+  return (ch != 's');
+}
+
+static int 
+pt (ch)				/* Rule number 28    */
+     char ch;
+{
+  return ((ch != 'p') && (ch != 't'));
+}
+
+static int 
+m (ch)				/* Rule number 30    */
+     char ch;
+{
+  return (ch != 'm');
+}
+
+static int 
+n (ch)				/* Rule number 32    */
+     char ch;
+{
+  return (ch != 'n');
+}
+
+
+/**************************************************************************
+ *
+ *  Context-sensitive rules associated with certain endings.
+ *
+ *  The notations of the rules are the same as in Lovins' paper
+ *  except that rule A is replaced by a NULL in the data structure.
+ *
+ *  Function parameters:
+ *      - stem_length: possible stem length
+ *      - end        : pointer points to the end of the possible stem.
+ *
+ *************************************************************************/
+
+
+/********* Context-sensitive rule function declarations ******************/
+
+static int B ();
+static int C ();
+static int D ();
+static int E ();
+static int F ();
+static int G ();
+static int H ();
+static int I ();
+static int J ();
+static int K ();
+static int L ();
+static int M ();
+static int N ();
+static int O ();
+static int P ();
+static int Q ();
+static int R ();
+static int S ();
+static int T ();
+static int U ();
+static int V ();
+static int W ();
+static int X ();
+static int Y ();
+static int Z ();
+static int AA ();
+static int BB ();
+static int CC ();
+
+static int 
+B (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (stem_length >= 3);
+}
+
+static int 
+C (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (stem_length >= 4);
+}
+
+static int 
+D (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (stem_length >= 5);
+}
+
+static int 
+E (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (*end != 'e');
+}
+
+static int 
+F (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return ((stem_length >= 3) && (*end != 'e'));
+}
+
+static int 
+G (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return ((stem_length >= 3) && (*end == 'f'));
+}
+
+static int 
+H (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+  return ((p1 == 't') || ((p1 == 'l') && (p2 == 'l')));
+}
+
+static int 
+I (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'o') && (p1 != 'e'));
+}
+
+static int 
+J (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'a') && (p1 != 'e'));
+}
+
+static int 
+K (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((stem_length >= 3) &&
+	  ((p1 == 'l') || (p1 == 'i') ||
+	   ((p1 == 'e') && (*(end - 2) == 'u'))));
+}
+
+static int 
+L (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+  if (p1 == 's')
+    return (p2 == 'o');
+  else
+    return ((p1 != 'u') && (p1 != 'x'));
+}
+
+static int 
+M (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'a') && (p1 != 'c') &&
+	  (p1 != 'e') && (p1 != 'm'));
+}
+
+static int 
+N (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  if (stem_length >= 3)
+    {
+      if (*(end - 2) == 's')
+	return (stem_length >= 4);
+      else
+	return 1;
+    }
+  else
+    return 0;
+}
+
+static int 
+O (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((p1 == 'l') || (p1 == 'i'));
+}
+
+static int 
+P (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (*end != 'c');
+}
+
+static int 
+Q (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+
+  return ((stem_length >= 3) && (p1 != 'l') && (p1 != 'n'));
+}
+
+static int 
+R (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+  return ((p1 == 'n') || (p1 == 'r'));
+}
+
+static int 
+S (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 't')
+    return (p2 != 't');
+  else
+    return ((p1 == 'r') && (p2 == 'd'));
+}
+
+static int 
+T (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 't')
+    return (p2 != 'o');
+  else
+    return (p1 == 's');
+}
+
+static int 
+U (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+
+  return ((p1 == 'l') || (p1 == 'm') ||
+	  (p1 == 'n') || (p1 == 'r'));
+}
+
+static int 
+V (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (*end == 'c');
+}
+
+static int 
+W (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+
+  return ((p1 != 's') && (p1 != 'u'));
+}
+
+static int 
+X (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1;
+  p1 = *end;
+
+  if (p1 == 'e')
+    return ((stem_length >= 3) && (*(end - 2) == 'u'));
+  else
+    return ((p1 == 'l') || (p1 == 'i'));
+}
+
+static int 
+Y (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return ((*end == 'n') && (*(end - 1) == 'i'));
+}
+
+static int 
+Z (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (*end != 'f');
+}
+
+static int 
+AA (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 'h')
+    return ((p2 == 'p') || (p2 == 't'));
+  else if (p1 == 'r')
+    return ((p2 == 'e') || (p2 == 'o'));
+  else if (p1 == 's')
+    return (p2 == 'e');
+  else
+    return ((p1 == 'd') || (p1 == 'f') ||
+	    (p1 == 'l') || (p1 == 't'));
+}
+
+static int 
+BB (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  if (stem_length >= 3)
+    {
+      if (stem_length >= 4)
+	return (strncmp (end - 3, "ryst", 4) != 0);
+      else
+	return (strncmp (end - 2, "met", 3) != 0);
+    }
+  else
+    return 0;
+}
+
+static int 
+CC (stem_length, end)
+     int stem_length;
+     char *end;
+{
+  return (*end == 'l');
+}
+
+/**************************************************************************/
+
+#define MIN_STEM_LENGTH 2
+#define MAX_ENDING_SIZE 11
+#define PREDEFINED_SIZE (MAX_ENDING_SIZE + MIN_STEM_LENGTH)
+#define EOS     '\0'
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAX_STEM_LENGTH 255
+
+static char *remove_ending (char *word, int w_len);
+static void recode_stem (char *stem_end);
+
+/* =========================================================================
+ * Function: stem
+ * Description: 
+ *      Implemetation of the Lovins' stemming algorithm described in
+ *      J.B. Lovins, "Development of a Stemming Algorithm",
+ *      Mechanical Translation and Computational Linguistics, Vol 11,1968.
+ * Input: a word string with the length in the first byte
+ * Output: the stemmed word
+ * ========================================================================= */
+
+void
+lovinstem (u_char * word)
+{
+  char *word_start;		/* points to first letter of word */
+  char *stem_end;		/* points to last character of stem portion */
+  int old_length;		/* length of word */
+  int new_length;		/* length after stemming */
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  u_char copy[MAX_STEM_LENGTH + 2];
+  bcopy ((char *) word, (char *) copy, *word + 1);
+
+  old_length = *copy; /* [RPAP - Jan 97: Stem Index Change] */
+
+  /* The word must be at least MIN_STEM_LENGTH characters long. */
+  if (old_length <= MIN_STEM_LENGTH)
+    return;
+
+  word_start = (char *) copy + 1;	/* jump over length byte */ /* [RPAP - Jan 97: Stem Index Change] */
+  copy[old_length + 1] = '\0';	/* null terminate string */ /* [RPAP - Jan 97: Stem Index Change] */
+
+  stem_end = remove_ending (word_start, old_length);
+  recode_stem (stem_end);
+
+  /* fix up new length */
+  /* have to use strlen because have no other way of telling length */
+  new_length = strlen (word_start);
+  *copy = new_length;  /* [RPAP - Jan 97: Stem Index Change] */
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  bcopy ((char *) copy, (char *) word, *copy + 1);
+
+}				/*stem_complex */
+
+/* =========================================================================
+
+ *   Data structure for recoding and the method for recoding the stem. 
+ *
+ * ========================================================================= */
+
+typedef struct
+{
+  char *old_end;		/* old ending */
+  char *new_end;		/* new ending */
+  char old_offset;		/* length of the old ending - 1 */
+  int (*cond) ();		/* condition rule */
+  char end_group;		/* signal the end of the group */
+}
+Recode_Rules;
+
+/*  
+   Stem terminations are divided into groups having the same last
+   character
+ */
+
+static Recode_Rules Rules[] =
+{
+  "uad", "uas", 2, NULL, 0,
+  "vad", "vas", 2, NULL, 0,
+  "cid", "cis", 2, NULL, 0,
+  "lid", "lis", 2, NULL, 0,
+  "erid", "eris", 3, NULL, 0,
+  "pand", "pans", 3, NULL, 0,
+  "end", "ens", 2, s, 0,
+  "end", "ens", 2, m, 0,
+  "ond", "ons", 2, NULL, 0,
+  "lud", "lus", 2, NULL, 0,
+  "rud", "rus", 2, NULL, 1,
+
+  "ul", "l", 1, aio, 1,
+
+  "istr", "ister", 3, NULL, 0,
+  "metr", "meter", 3, NULL, 0,
+  "her", "hes", 2, pt, 1,
+
+  "urs", "ur", 2, NULL, 1,
+
+  "uct", "uc", 2, NULL, 0,
+  "umpt", "um", 3, NULL, 0,
+  "rpt", "rb", 2, NULL, 0,
+  "mit", "mis", 2, NULL, 0,
+  "ert", "ers", 2, NULL, 0,
+  "et", "es", 1, n, 0,
+  "yt", "ys", 1, NULL, 1,
+
+  "iev", "ief", 2, NULL, 0,
+  "olv", "olut", 2, NULL, 1,
+
+  "bex", "bic", 2, NULL, 0,
+  "dex", "dic", 2, NULL, 0,
+  "pex", "pic", 2, NULL, 0,
+  "tex", "tic", 2, NULL, 0,
+  "ax", "ac", 1, NULL, 0,
+  "ex", "ec", 1, NULL, 0,
+  "ix", "ic", 1, NULL, 0,
+  "lux", "luc", 2, NULL, 1,
+
+  "yz", "ys", 1, NULL, 1
+};
+
+typedef struct last
+  {
+    char c;			/* The last character */
+    struct last *left;		/* used in balanced   */
+    struct last *right;		/* binary tree        */
+    Recode_Rules *pt;		/* location of approriate group */
+  }
+Last_Char_Node;
+
+/*------------
+       s
+     /   \
+    l     x
+   / \   / \
+  d   r t   z
+         \
+          v
+---------------*/
+static Last_Char_Node pr[] =
+{
+  'd', NULL, NULL, Rules,
+  'l', pr, pr + 2, Rules + 11,
+  'r', NULL, NULL, Rules + 12,
+  's', pr + 1, pr + 6, Rules + 15,
+  't', NULL, pr + 5, Rules + 16,
+  'v', NULL, NULL, Rules + 23,
+  'x', pr + 4, pr + 7, Rules + 25,
+  'z', NULL, NULL, Rules + 33,
+};
+
+
+/*****************************************************************************
+ *
+ *  Recode the stem according to the transformation rules.
+ *
+ *****************************************************************************/
+
+static void
+recode_stem (char *stem_end)
+{
+  static Last_Char_Node *root = pr + 3;
+  Last_Char_Node *p_last = root;
+  Recode_Rules *rule;		/* points to the transformation list */
+  char *h,			/* points to start of possible ending */
+    ch,				/* last character of the old ending  */
+    ch2;
+
+  h = stem_end - 1;
+  ch = *stem_end;
+  if (*h == ch)			/* Check for double consonant        */
+    {
+      if (strchr ("bdglmnprst", ch) != NULL)
+	{
+	  *stem_end = EOS;
+	  stem_end = h;
+	}
+    }
+
+  do				/* Check for the last character       */
+    {
+      ch2 = p_last->c;
+      if (ch == ch2)
+	break;
+      else if (ch > ch2)
+	p_last = p_last->right;
+      else
+	p_last = p_last->left;
+    }
+  while (p_last != NULL);
+
+  if (p_last != NULL)		/* Check for the rest of suffix list */
+    {
+      rule = p_last->pt;
+      for (;;)
+	{
+	  h = stem_end - rule->old_offset;
+	  if (strcmp (h, rule->old_end) == 0)
+	    {
+	      if (!rule->cond || (*rule->cond) (*(h - 1)))
+		{
+		  (void) strcpy (h, rule->new_end);
+		  break;
+		}
+	    }
+	  if (rule->end_group)
+	    break;
+	  rule++;
+	}
+    }
+}
+
+/* ======================================================================
+
+ *    List of endings and the method to remove the ending 
+ *
+ * ======================================================================*/
+
+/************ Data structures for list of endings  ********************/
+
+typedef struct
+{
+  char *ending;			/* old ending                */
+  int (*cond) ();		/* conditional rule          */
+  signed char left_offset;	/* used to find the siblings */
+  signed char right_offset;	/* in balanced binary tree   */
+}
+Ending_List;
+
+/*
+   The original list of endings is re-organised into groups having
+   the same length and the same first character.
+ */
+
+static Ending_List List[] =
+{
+  "a", NULL, 0, 0,
+
+  "ae", NULL, 0, 0,
+  "al", BB, -1, 2,
+  "ar", X, 0, 0,
+  "as", B, -1, 0,
+
+  "acy", NULL, 0, 1,
+  "age", B, 0, 0,
+  "aic", NULL, -2, 1,
+  "als", BB, 0, 0,
+  "ant", B, -2, 2,
+  "ars", O, 0, 0,
+  "ary", F, -1, 2,
+  "ata", NULL, 0, 0,
+  "ate", NULL, -1, 0,
+
+  "able", NULL, 0, 1,
+  "ably", NULL, 0, 0,
+  "ages", B, -2, 2,
+  "ally", B, 0, 0,
+  "ance", B, -1, 1,
+  "ancy", B, 0, 0,
+  "ants", B, -4, 4,
+  "aric", NULL, 0, 0,
+  "arly", K, -1, 1,
+  "ated", I, 0, 0,
+  "ates", NULL, -2, 2,
+  "atic", B, 0, 0,
+  "ator", NULL, -1, 0,
+
+  "acies", NULL, 0, 0,
+  "acity", NULL, -1, 1,
+  "aging", B, 0, 0,
+  "aical", NULL, -2, 2,
+  "alist", NULL, 0, 0,
+  "alism", B, -1, 0,
+  "ality", NULL, -3, 3,
+  "alize", NULL, 0, 1,
+  "allic", BB, 0, 0,
+  "anced", B, -2, 2,
+  "ances", B, 0, 0,
+  "antic", C, -1, 0,
+  "arial", NULL, -6, 6,
+  "aries", NULL, 0, 1,
+  "arily", NULL, 0, 0,
+  "arity", B, -2, 2,
+  "arize", NULL, 0, 0,
+  "aroid", NULL, -1, 0,
+  "ately", NULL, -3, 3,
+  "ating", I, 0, 1,
+  "ation", B, 0, 0,
+  "ative", NULL, -2, 2,
+  "ators", NULL, 0, 0,
+  "atory", NULL, -1, 1,
+  "ature", E, 0, 0,
+
+  "aceous", NULL, 0, 1,
+  "acious", B, 0, 0,
+  "action", G, -2, 2,
+  "alness", NULL, 0, 0,
+  "ancial", NULL, -1, 1,
+  "ancies", NULL, 0, 0,
+  "ancing", B, -4, 4,
+  "ariser", NULL, 0, 0,
+  "arized", NULL, -1, 1,
+  "arizer", NULL, 0, 0,
+  "atable", NULL, -2, 2,
+  "ations", B, 0, 0,
+  "atives", NULL, -1, 0,
+
+  "ability", NULL, 0, 1,
+  "aically", NULL, 0, 0,
+  "alistic", B, -2, 2,
+  "alities", NULL, 0, 0,
+  "ariness", E, -1, 0,
+  "aristic", NULL, -3, 3,
+  "arizing", NULL, 0, 1,
+  "ateness", NULL, 0, 0,
+  "atingly", NULL, -2, 2,
+  "ational", B, 0, 0,
+  "atively", NULL, -1, 1,
+  "ativism", NULL, 0, 0,
+
+  "ableness", NULL, 0, 1,
+  "arizable", NULL, 0, 0,
+
+  "allically", C, 0, 0,
+  "antaneous", NULL, -1, 1,
+  "antiality", NULL, 0, 0,
+  "arisation", NULL, -2, 2,
+  "arization", NULL, 0, 0,
+  "ationally", B, -1, 1,
+  "ativeness", NULL, 0, 0,
+
+  "antialness", NULL, 0, 0,
+  "arisations", NULL, -1, 1,
+  "arizations", NULL, 0, 0,
+
+  "alistically", B, 0, 1,
+  "arizability", NULL, 0, 0,
+
+  "e", NULL, 0, 0,
+
+  "ed", E, 0, 0,
+  "en", F, -1, 1,
+  "es", E, 0, 0,
+
+  "eal", Y, 0, 0,
+  "ear", Y, -1, 1,
+  "ely", E, 0, 0,
+  "ene", E, -2, 2,
+  "ent", C, 0, 0,
+  "ery", E, -1, 1,
+  "ese", NULL, 0, 0,
+
+  "ealy", Y, 0, 1,
+  "edly", E, 0, 0,
+  "eful", NULL, -2, 1,
+  "eity", NULL, 0, 0,
+  "ence", NULL, -2, 2,
+  "ency", NULL, 0, 0,
+  "ened", E, -1, 2,
+  "enly", E, 0, 0,
+  "eous", NULL, -1, 0,
+
+  "early", Y, 0, 1,
+  "ehood", NULL, 0, 0,
+  "eless", NULL, -2, 2,
+  "elity", NULL, 0, 0,
+  "ement", NULL, -1, 0,
+  "enced", NULL, -3, 3,
+  "ences", NULL, 0, 1,
+  "eness", E, 0, 0,
+  "ening", E, -2, 2,
+  "ental", NULL, 0, 0,
+  "ented", C, -1, 1,
+  "ently", NULL, 0, 0,
+
+  "eature", Z, 0, 0,
+  "efully", NULL, -1, 1,
+  "encies", NULL, 0, 0,
+  "encing", NULL, -2, 2,
+  "ential", NULL, 0, 0,
+  "enting", C, -1, 1,
+  "entist", NULL, 0, 1,
+  "eously", NULL, 0, 0,
+
+  "elihood", E, 0, 1,
+  "encible", NULL, 0, 0,
+  "entally", NULL, -2, 2,
+  "entials", NULL, 0, 0,
+  "entiate", NULL, -1, 1,
+  "entness", NULL, 0, 0,
+
+  "entation", NULL, 0, 0,
+  "entially", NULL, -1, 1,
+  "eousness", NULL, 0, 0,
+
+  "eableness", E, 0, 1,
+  "entations", NULL, 0, 0,
+  "entiality", NULL, -2, 2,
+  "entialize", NULL, 0, 0,
+  "entiation", NULL, -1, 0,
+
+  "entialness", NULL, 0, 0,
+
+  "ful", NULL, 0, 0,
+
+  "fully", NULL, 0, 0,
+
+  "fulness", NULL, 0, 0,
+
+  "hood", NULL, 0, 0,
+
+  "i", NULL, 0, 0,
+
+  "ia", NULL, 0, 0,
+  "ic", NULL, -1, 1,
+  "is", NULL, 0, 0,
+
+  "ial", NULL, 0, 0,
+  "ian", NULL, -1, 1,
+  "ics", NULL, 0, 1,
+  "ide", L, 0, 0,
+  "ied", NULL, -3, 3,
+  "ier", NULL, 0, 0,
+  "ies", P, -1, 0,
+  "ily", NULL, -1, 1,
+  "ine", M, 0, 0,
+  "ing", N, -5, 5,
+  "ion", Q, 0, 0,
+  "ish", C, -1, 1,
+  "ism", B, 0, 1,
+  "ist", NULL, 0, 0,
+  "ite", AA, -3, 3,
+  "ity", NULL, 0, 0,
+  "ium", NULL, -1, 0,
+  "ive", NULL, -1, 1,
+  "ize", F, 0, 0,
+
+  "ials", NULL, 0, 0,
+  "ians", NULL, -1, 0,
+  "ible", NULL, -1, 1,
+  "ibly", NULL, 0, 0,
+  "ical", NULL, -2, 2,
+  "ides", L, 0, 0,
+  "iers", NULL, -1, 1,
+  "iful", NULL, 0, 0,
+  "ines", M, -4, 4,
+  "ings", N, 0, 0,
+  "ions", B, -1, 1,
+  "ious", NULL, 0, 0,
+  "isms", B, -2, 2,
+  "ists", NULL, 0, 0,
+  "itic", H, -1, 1,
+  "ized", F, 0, 1,
+  "izer", F, 0, 0,
+
+  "ially", NULL, 0, 0,
+  "icant", NULL, -1, 1,
+  "ician", NULL, 0, 0,
+  "icide", NULL, -2, 2,
+  "icism", NULL, 0, 0,
+  "icist", NULL, -1, 0,
+  "icity", NULL, -3, 3,
+  "idine", I, 0, 1,
+  "iedly", NULL, 0, 0,
+  "ihood", NULL, -2, 2,
+  "inate", NULL, 0, 0,
+  "iness", NULL, -1, 0,
+  "ingly", B, -6, 6,
+  "inism", J, 0, 1,
+  "inity", CC, 0, 0,
+  "ional", NULL, -2, 2,
+  "ioned", NULL, 0, 0,
+  "ished", NULL, -1, 0,
+  "istic", NULL, -3, 3,
+  "ities", NULL, 0, 1,
+  "itous", NULL, 0, 0,
+  "ively", NULL, -2, 2,
+  "ivity", NULL, 0, 0,
+  "izers", F, -1, 1,
+  "izing", F, 0, 0,
+
+  "ialist", NULL, 0, 0,
+  "iality", NULL, -1, 1,
+  "ialize", NULL, 0, 0,
+  "ically", NULL, -2, 2,
+  "icance", NULL, 0, 0,
+  "icians", NULL, -1, 1,
+  "icists", NULL, 0, 0,
+  "ifully", NULL, -4, 4,
+  "ionals", NULL, 0, 0,
+  "ionate", D, -1, 1,
+  "ioning", NULL, 0, 0,
+  "ionist", NULL, -2, 2,
+  "iously", NULL, 0, 0,
+  "istics", NULL, -1, 1,
+  "izable", E, 0, 0,
+
+  "ibility", NULL, 0, 0,
+  "icalism", NULL, -1, 1,
+  "icalist", NULL, 0, 1,
+  "icality", NULL, 0, 0,
+  "icalize", NULL, -3, 3,
+  "ication", G, 0, 0,
+  "icianry", NULL, -1, 0,
+  "ination", NULL, -1, 1,
+  "ingness", NULL, 0, 0,
+  "ionally", NULL, -5, 5,
+  "isation", NULL, 0, 0,
+  "ishness", NULL, -1, 1,
+  "istical", NULL, 0, 1,
+  "iteness", NULL, 0, 0,
+  "iveness", NULL, -3, 3,
+  "ivistic", NULL, 0, 0,
+  "ivities", NULL, -1, 0,
+  "ization", F, -1, 1,
+  "izement", NULL, 0, 0,
+
+  "ibleness", NULL, 0, 0,
+  "icalness", NULL, -1, 1,
+  "ionalism", NULL, 0, 0,
+  "ionality", NULL, -2, 2,
+  "ionalize", NULL, 0, 0,
+  "iousness", NULL, -1, 1,
+  "izations", NULL, 0, 0,
+
+  "ionalness", NULL, 0, 1,
+  "istically", NULL, 0, 0,
+  "itousness", NULL, -2, 2,
+  "izability", NULL, 0, 0,
+  "izational", NULL, -1, 0,
+
+  "izationally", B, 0, 0,
+
+  "ly", B, 0, 0,
+
+  "less", NULL, 0, 1,
+  "lily", NULL, 0, 0,
+
+  "lessly", NULL, 0, 0,
+
+  "lessness", NULL, 0, 0,
+
+  "ness", NULL, 0, 0,
+
+  "nesses", NULL, 0, 0,
+
+  "o", NULL, 0, 0,
+
+  "on", S, 0, 1,
+  "or", T, 0, 0,
+
+  "oid", NULL, 0, 0,
+  "one", R, -1, 1,
+  "ous", NULL, 0, 0,
+
+  "ogen", NULL, 0, 0,
+
+  "oidal", NULL, 0, 0,
+  "oides", NULL, -1, 2,
+  "otide", NULL, 0, 0,
+  "ously", NULL, -1, 0,
+
+  "oidism", NULL, 0, 0,
+
+  "oidally", NULL, 0, 1,
+  "ousness", NULL, 0, 0,
+
+  "s", W, 0, 0,
+
+  "s'", NULL, 0, 0,
+
+  "um", U, 0, 1,
+  "us", V, 0, 0,
+
+  "ward", NULL, 0, 1,
+  "wise", NULL, 0, 0,
+
+  "y", B, 0, 0,
+
+  "yl", R, 0, 0,
+
+  "ying", B, 0, 1,
+  "yish", NULL, 0, 0,
+
+  "'s", NULL, 0, 0,
+};
+
+typedef struct node
+  {
+    char c;			/* First character  */
+    struct node *left;		/* used in balanced */
+    struct node *right;		/* binary tree      */
+    Ending_List *ptr[11];	/* the approriate location */
+  }
+First_Char_Node;
+
+static First_Char_Node First[] =
+{
+  '\'', NULL, NULL,
+  {NULL,
+   List + 293, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'a', First, NULL,
+  {List,
+   List + 2, List + 9, List + 20, List + 39, List + 58,
+   List + 70, List + 77, List + 82, List + 87, List + 89},
+
+  'e', First + 1, First + 4,
+  {List + 91,
+   List + 93, List + 98, List + 106, List + 116, List + 126,
+   List + 133, List + 138, List + 142, List + 145, NULL},
+
+  'f', NULL, NULL,
+  {NULL,
+   NULL, List + 146, NULL, List + 147, NULL,
+   List + 148, NULL, NULL, NULL, NULL},
+
+  'h', First + 3, First + 5,
+  {NULL,
+   NULL, NULL, List + 149, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'i', NULL, NULL,
+  {List + 150,
+   List + 152, List + 163, List + 181, List + 202, List + 222,
+   List + 239, List + 252, List + 258, NULL, List + 261},
+
+  'l', First + 2, First + 10,
+  {NULL,
+   List + 262, NULL, List + 263, NULL, List + 265,
+   NULL, List + 266, NULL, NULL, NULL},
+
+  'n', NULL, NULL,
+  {NULL,
+   NULL, NULL, List + 267, NULL, List + 268,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'o', First + 7, First + 9,
+  {List + 269,
+   List + 270, List + 273, List + 275, List + 277, List + 280,
+   List + 281, NULL, NULL, NULL, NULL},
+
+  's', NULL, NULL,
+  {List + 283,
+   List + 284, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'u', First + 8, First + 12,
+  {NULL,
+   List + 285, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'w', NULL, NULL,
+  {NULL,
+   NULL, NULL, List + 287, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'y', First + 11, NULL,
+  {List + 289,
+   List + 290, NULL, List + 291, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+};
+
+
+/******************************************************************************
+ *
+ *  Look for a match in the suffix list.
+ *  Return the pointer to the end of the new stem if there is a match.
+ *  Otherwise, return the pointer to the end of the original word.
+ *
+ *  Method:
+ *      * Search for the first character in the suffix list.
+ *      * If there is match, search for the rest of the suffix list.
+ *         
+ *****************************************************************************/
+
+static char *
+remove_ending (char *word, int w_len)
+{
+  static First_Char_Node *root = First + 6;	/* the root of binary tree is 'l' */
+  First_Char_Node *p_first;	/* Points to the first character      */
+  /* of the possible suffix             */
+  Ending_List *p_list;		/* Points to the List of Endings      */
+  char *suffix_start,		/* Points to start of possible suffix */
+   *stem_end,			/* Points to the end of possible stem */
+    ch1, ch2;
+  int s_len,			/* Possible stem length               */
+    e_offset,			/* Offset from the end to the start of */
+  /* possible suffix                    */
+    not_done = 1, cmp;
+
+  stem_end = word + w_len - 1;
+  if (w_len > PREDEFINED_SIZE)	/* find the start of suffix   */
+    suffix_start = word + w_len - MAX_ENDING_SIZE;
+  else
+    suffix_start = word + MIN_STEM_LENGTH;
+
+  ch1 = *suffix_start;
+  do				/* Search for the first character     */
+    {
+      p_first = root;
+      do
+	{
+	  ch2 = p_first->c;
+	  if (ch1 == ch2)
+	    break;
+	  else if (ch1 > ch2)
+	    p_first = p_first->right;
+	  else
+	    p_first = p_first->left;
+	}
+      while (p_first != NULL);
+
+      if (p_first != NULL)	/* Search for the rest */
+	{
+	  e_offset = stem_end - suffix_start;
+	  if ((p_list = p_first->ptr[e_offset]) != NULL)
+	    {
+	      for (;;)		/* no need to compare the first char  */
+		{
+		  cmp = strcmp (suffix_start + 1, p_list->ending + 1);
+		  if (cmp > 0)
+		    if (p_list->right_offset)
+		      p_list += p_list->right_offset;
+		    else
+		      break;
+		  else if (cmp < 0)
+		    if (p_list->left_offset)
+		      p_list += p_list->left_offset;
+		    else
+		      break;
+		  else
+		    {
+		      s_len = suffix_start - word;
+		      if (!p_list->cond ||
+			  (*p_list->cond) (s_len, suffix_start - 1))
+			{
+			  *suffix_start = EOS;
+			  stem_end = suffix_start - 1;
+			  not_done = 0;
+			}
+		      break;
+		    }
+		}
+	    }
+	}
+      suffix_start++;
+    }
+  while (not_done && ((ch1 = *suffix_start) != EOS));
+  return (stem_end);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/lovinstem.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/lovinstem.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/lovinstem.h	(revision 10506)
@@ -0,0 +1,53 @@
+/**************************************************************************
+ *
+ * lovinstem.h -- Lovins' stemmer header
+ * Copyright (C) 1994  Linh Huynh, 
+ *                     (glued into library by tes@kbs.citri.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:54  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/25 07:55:36  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:32:47  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:20:10  tes
+   * Changes made for 1.1
+   *
+   *
+ */
+#ifndef LOVINSTEM_H
+#define LOVINSTEM_H
+
+void lovinstem (unsigned char *word);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/memlib.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/memlib.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/memlib.c	(revision 10506)
@@ -0,0 +1,63 @@
+/**************************************************************************
+ *
+ * memlib.c -- Malloc wrappers
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.2  2004/11/29 02:56:09  kjdon
+   added some changes made by Emanuel Dejanu (Simple Words)
+
+   Revision 1.1  1999/08/10 21:16:54  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:10  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:47  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+/* Defined as strdup is not an ANSI function */
+/* change the name so we do not have problems with other libs */
+char *
+my_mg_strdup(const char *str)
+{
+  char *ret_str = malloc(strlen(str)+1);
+  if (ret_str) return strcpy(ret_str, str);
+  else return (char*) 0;
+}
+
+
+Malloc_func Xmalloc = malloc;
+
+Realloc_func Xrealloc = realloc;
+
+Free_func Xfree = free;
+
+Strdup_func Xstrdup = my_mg_strdup;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/memlib.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/memlib.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/memlib.h	(revision 10506)
@@ -0,0 +1,51 @@
+/**************************************************************************
+ *
+ * memlib.h -- Malloc wrappers
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_MEMLIB
+#define H_MEMLIB
+
+#ifdef STD_MEM
+
+#define Xmalloc malloc
+#define Xrealloc realloc
+#define Xfree free
+#define Xstrdup strdup
+
+#else
+
+
+#include "sysfuncs.h"
+
+typedef void *(*Malloc_func) (size_t);
+typedef void *(*Realloc_func) (void *, size_t);
+typedef void (*Free_func) (void *);
+typedef char *(*Strdup_func) (const char *);
+
+extern Malloc_func Xmalloc;
+extern Realloc_func Xrealloc;
+extern Free_func Xfree;
+extern Strdup_func Xstrdup;
+#endif
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/messages.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/messages.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/messages.c	(revision 10506)
@@ -0,0 +1,96 @@
+/**************************************************************************
+ *
+ * messages.c -- Message and error functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:55  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/23 03:38:06  rjmcnab
+
+   combined unix and windows versions of mg
+
+   Revision 1.1  1998/11/19 03:00:32  sjboddie
+   Added windows gdbm and mg versions
+
+   * Revision 1.1  1994/08/22  00:24:48  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include <stdarg.h>
+#include "messages.h"
+
+char *msg_prefix = "";
+
+
+void VOLATILE 
+FatalError (int ExitCode, const char *fmt,...)
+{
+  char buf[1024];
+  char *s, *pfx;
+  va_list args;
+  va_start (args, fmt);
+  vsprintf (buf, fmt, args);
+  s = strrchr (buf, '\n');
+  if (!s || *(s + 1) != '\0')
+    strcat (buf, "\n");
+  pfx = strrchr (msg_prefix, '/');
+  pfx = pfx ? pfx + 1 : msg_prefix;
+  fprintf (stderr, "%s%s%s", pfx, *pfx ? " : " : "", buf);
+  exit (ExitCode);
+}
+
+
+
+/*
+ * This function writes messages to stderr. Due to the fact that I can't 
+ * guarantee that the fprintf call is monatomic I have to implement a 
+ * semaphore system.
+ */
+void 
+Message (const char *fmt,...)
+{
+  char buf[1024];
+  char *s, *pfx;
+  va_list args;
+
+#ifdef QUIET
+  return; /* stop those messages!!!! */
+#endif  
+
+  va_start (args, fmt);
+  vsprintf (buf, fmt, args);
+  s = strrchr (buf, '\n');
+  if (!s || *(s + 1) != '\0')
+    strcat (buf, "\n");
+
+  pfx = strrchr (msg_prefix, '/');
+  pfx = pfx ? pfx + 1 : msg_prefix;
+  fprintf (stderr, "%s%s%s", pfx, *pfx ? " : " : "", buf);
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/messages.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/messages.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/messages.h	(revision 10506)
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * messages.h -- Message and error functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_MESSAGES
+#define H_MESSAGES
+
+#ifdef __GNUC__
+#define VOLATILE volatile
+#else
+#define VOLATILE
+#endif
+
+extern char *msg_prefix;
+
+void VOLATILE FatalError (int ExitCode, const char *fmt,...);
+
+void Message (const char *fmt,...);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/mgheap.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/mgheap.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/mgheap.c	(revision 10506)
@@ -0,0 +1,170 @@
+/**************************************************************************
+ *
+ * mgheap.c -- Heap routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:16:55  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1999/01/15 03:05:50  rjmcnab
+
+   Renamed lib/heap to be lib/mgheap (it was causing some problems with
+   some versions of the STL libraries which contained a heap.h)
+
+   Revision 1.1  1998/11/17 09:32:01  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:43  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "mgheap.h"
+
+#define SWAP(s, a, b) 						\
+do {								\
+     register int __i;						\
+     register char *__a = (a), *__b = (b);			\
+     for (__i = (s); __i; __i--)				\
+       {							\
+         register char __t = *__a;				\
+	 *__a++ = *__b; *__b++ = __t;				\
+       }							\
+} while(0)
+
+
+
+#define COPY(s, dst, src) 					\
+do {								\
+     register int __i;						\
+     register char *__dst = (dst), *__src = (src);		\
+     for (__i = (s); __i; __i--)				\
+       *__dst++ = *__src++;					\
+} while(0)
+
+
+
+static void 
+heap_heapify (void *heap, int size, int num, int curr, heap_comp hc)
+{
+  register int child = curr * 2;
+  while (child <= num)
+    {
+      if (child < num && hc ((char *) heap + child * size,
+			     (char *) heap + child * size - size) < 0)
+	child++;
+      if (hc ((char *) heap + (curr - 1) * size, (char *) heap + (child - 1) * size) > 0)
+	{
+	  SWAP (size, (char *) heap + (curr - 1) * size,
+		(char *) heap + (child - 1) * size);
+	  curr = child;
+	  child = child * 2;
+	}
+      else
+	break;
+    }
+}
+
+static void 
+heap_pullup (void *heap, int size, int num, heap_comp hc)
+{
+  register int curr = num;
+  register int parent = curr >> 1;
+  while (parent &&
+	 hc ((char *) heap + (curr - 1) * size, (char *) heap + (parent - 1) * size) < 0)
+    {
+      SWAP (size, (char *) heap + (curr - 1) * size,
+	    (char *) heap + (parent - 1) * size);
+      curr = parent;
+      parent = curr >> 1;
+    }
+}
+
+/************************************************************************
+ *
+ * NOTE: If you choose to change the comparison function the first thing 
+ *       you do after changing the function is call heap_build.
+ *
+ */
+void 
+heap_build (void *heap, int size, int num, heap_comp hc)
+{
+  register int i;
+  for (i = num / 2; i > 0; i--)
+    heap_heapify (heap, size, num, i, hc);
+}
+
+
+
+/****************************************************
+ *
+ * NOTE : The heap must be built before heap_sort is called. 
+ *        This has the effect of reversing the order of the array.
+ *		e.g. if your comparison function is designed to pull the
+ *                   biggest thing off the heap first then the result of
+ *		     sorting with this function will be to put the bigest
+ *                   thing at the end of the array.
+ *
+ */
+void 
+heap_sort (void *heap, int size, int num, heap_comp hc)
+{
+  register int i;
+  for (i = num; i > 1; i--)
+    {
+      SWAP (size, heap, (char *) heap + (i - 1) * size);
+      heap_heapify (heap, size, i - 1, 1, hc);
+    }
+}
+
+
+void 
+heap_deletehead (void *heap, int size, int *num, heap_comp hc)
+{
+  (*num)--;
+  SWAP (size, heap, (char *) heap + *num * size);
+  heap_heapify (heap, size, *num, 1, hc);
+}
+
+
+void 
+heap_changedhead (void *heap, int size, int num, heap_comp hc)
+{
+  heap_heapify (heap, size, num, 1, hc);
+}
+
+
+/***********************************************************************
+ *
+ * This assumes that the item has been added to the end of the
+ * array that is the heap. But that num has not been changed. 
+ *
+ */
+void 
+heap_additem (void *heap, int size, int *num, heap_comp hc)
+{
+  (*num)++;
+  heap_pullup (heap, size, *num, hc);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/mgheap.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/mgheap.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/mgheap.h	(revision 10506)
@@ -0,0 +1,84 @@
+/**************************************************************************
+ *
+ * mgheap.h -- Heap routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/* Care should be taken when using these routines as NO error checking is
+ * done.
+ */
+
+
+
+/* The heap comparison routine should return 
+ * <0 : If a should be before b
+ *  0 : If a and b are equal
+ * >0 : If a should be after b
+ */
+typedef int (*heap_comp) (void *a, void *b);
+
+
+/************************************************************************
+ *
+ * NOTE: If you choose to change the comparison function the first thing 
+ *       you do after changing the function is call heap_build.
+ *
+ */
+void heap_build (void *heap, int size, int num, heap_comp hc);
+
+
+
+/************************************************************************
+ *
+ * NOTE : The heap must be built before heap_sort is called.
+ *        This has the effect of reversing the order of the array.
+ *		e.g. if your comparison function is designed to pull the
+ *                   biggest thing off the heap first then the result of
+ *		     sorting with this function will be to put the bigest
+ *                   thing at the end of the array.
+ *
+ */
+void heap_sort (void *heap, int size, int num, heap_comp hc);
+
+/***********************************************************************
+ *
+ * NOTE: After deleting the head the heap will be one item shorter.
+ *       The deleted item will be placed at the end of the heap.
+ *
+ */
+void heap_deletehead (void *heap, int size, int *num, heap_comp hc);
+
+
+/***********************************************************************
+ *
+ * If you change the "value" of the root node of the heap then you
+ * should call this to re-pritorize the heap.
+ *
+ */
+void heap_changedhead (void *heap, int size, int num, heap_comp hc);
+
+
+/***********************************************************************
+ *
+ * This assumes that the item has been added to the end of the
+ * array that is the heap. But that num has not been changed. 
+ *
+ */
+void heap_additem (void *heap, int size, int *num, heap_comp hc);
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/netorder.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/netorder.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/netorder.h	(revision 10506)
@@ -0,0 +1,189 @@
+#ifndef NETORDER_H
+#define NETORDER_H
+
+#include "sysfuncs.h"
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+#include "win32in.h"
+#else
+# include <netinet/in.h>
+#endif
+
+#if defined (BIG_ENDIAN) || defined (_BIG_ENDIAN) || defined (__BIG_ENDIAN)
+# ifndef _BIG_ENDIAN
+#  define _BIG_ENDIAN
+# endif
+#endif
+
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+# ifndef _LITTLE_ENDIAN
+#  define _LITTLE_ENDIAN
+# endif
+#endif
+
+#ifdef _LITTLE_ENDIAN
+
+/* double */
+#define HTOND(d)                                                                                  \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((char *) &d, (char *) &tmph, sizeof(double) >> 1);                            \
+	     bcopy ((char *) &d + (sizeof(double) >> 1), (char *) &tmpl, sizeof (double) >> 1);   \
+	     tmph = htonl (tmph);                                                                 \
+	     tmpl = htonl (tmpl);                                                                 \
+	     bcopy ((char *) &tmpl, (char *) &d, sizeof (double) >> 1);                           \
+	     bcopy ((char *) &tmph, (char *) &d + (sizeof(double) >> 1), sizeof (double) >> 1);   \
+	}while(0)
+#define NTOHD(d)                                                                                  \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((char *) &d, (char *) &tmph, sizeof(double) >> 1);                            \
+	     bcopy ((char *) &d + (sizeof(double) >> 1), (char *) &tmpl, sizeof (double) >> 1);   \
+	     tmph = ntohl (tmph);                                                                 \
+	     tmpl = ntohl (tmpl);                                                                 \
+	     bcopy ((char *) &tmpl, (char *) &d, sizeof (double) >> 1);                           \
+	     bcopy ((char *) &tmph, (char *) &d + (sizeof(double) >> 1), sizeof (double) >> 1);   \
+        }while(0)
+#define HTOND2(hd, nd)                                                                            \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((char *) &hd, (char *) &tmph, sizeof(double) >> 1);                           \
+	     bcopy ((char *) &hd + (sizeof(double) >> 1), (char *) &tmpl, sizeof (double) >> 1);  \
+	     tmph = htonl (tmph);                                                                 \
+	     tmpl = htonl (tmpl);                                                                 \
+	     bcopy ((char *) &tmpl, (char *) &nd, sizeof (double) >> 1);                          \
+	     bcopy ((char *) &tmph, (char *) &nd + (sizeof(double) >> 1), sizeof (double) >> 1);  \
+	}while(0)
+#define NTOHD2(nd, hd)                                                                            \
+        do {                                                                                      \
+             unsigned long tmph, tmpl;                                                            \
+	     bcopy ((char *) &nd, (char *) &tmph, sizeof(double) >> 1);                           \
+	     bcopy ((char *) &nd + (sizeof(double) >> 1), (char *) &tmpl, sizeof (double) >> 1);  \
+	     tmph = ntohl (tmph);                                                                 \
+	     tmpl = ntohl (tmpl);                                                                 \
+	     bcopy ((char *) &tmpl, (char *) &hd, sizeof (double) >> 1);                          \
+	     bcopy ((char *) &tmph, (char *) &hd + (sizeof(double) >> 1), sizeof (double) >> 1);  \
+        }while(0)
+
+/* float */
+#define HTONF(f)                                                                   \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((char *) &(f), (char *) &tmp, sizeof (float));                 \
+             HTONUL (tmp);                                                         \
+	     bcopy ((char *) &tmp, (char *) &(f), sizeof (float));                 \
+	}while(0)
+#define NTOHF(f)                                                                   \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((char *) &(f), (char *) &tmp, sizeof (float));                 \
+	     NTOHUL (tmp);                                                         \
+	     bcopy ((char *) &tmp, (char *) &(f), sizeof (float));                 \
+	}while(0)
+#define HTONF2(hf, nf)                                                             \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((char *) &(hf), (char *) &tmp, sizeof (float));                \
+             HTONUL (tmp);                                                         \
+	     bcopy ((char *) &tmp, (char *) &(nf), sizeof (float));                \
+	}while(0)
+#define NTOHF2(nf, hf)                                                             \
+        do {                                                                       \
+             unsigned long tmp;                                                    \
+             bcopy ((char *) &(nf), (char *) &tmp, sizeof (float));                \
+	     NTOHUL (tmp);                                                         \
+	     bcopy ((char *) &tmp, (char *) &(hf), sizeof (float));                \
+	}while(0)
+
+/* pointers */
+#define HTONP(p)          ((p) = (void *) htonl ((unsigned long) p))
+#define NTOHP(p)          ((p) = (void *) ntohl ((unsigned long) p))
+#define HTONP2(hp, np)    ((np) = (void *) htonl ((unsigned long) hp))
+#define NTOHP2(np, hp)    ((hp) = (void *) ntohl ((unsigned long) np))
+
+/* unsigned long */
+#define HTONUL(l)         ((l) = htonl((l)))
+#define NTOHUL(l)         ((l) = ntohl((l)))
+#define HTONUL2(hl, nl)   ((nl) = htonl ((hl)))
+#define NTOHUL2(nl, hl)   ((hl) = ntohl ((nl)))
+
+/* signed long */
+#define HTONSL(l)         ((l) = (long) htonl ((unsigned long) (l)))
+#define NTOHSL(l)         ((l) = (long) ntohl ((unsigned long) (l)))
+#define HTONSL2(hl, nl)   ((nl) = (long) htonl ((unsigned long) (hl)))
+#define NTOHSL2(nl, hl)   ((hl) = (long) ntohl ((unsigned long) (nl)))
+
+/* unsigned int */
+#define HTONUI(i)         ((i) = (unsigned int) htonl ((unsigned long) (i)))
+#define NTOHUI(i)         ((i) = (unsigned int) ntohl ((unsigned long) (i)))
+#define HTONUI2(hi, ni)   ((ni) = (unsigned int) htonl ((unsigned long) (hi)))
+#define NTOHUI2(ni, hi)   ((hi) = (unsigned int) ntohl ((unsigned long) (ni)))
+
+/* signed int */
+#define HTONSI(i)         ((i) = (int) htonl ((unsigned long) (i)))
+#define NTOHSI(i)         ((i) = (int) ntohl ((unsigned long) (i)))
+#define HTONSI2(hi, ni)   ((ni) = (int) htonl ((unsigned long) (hi)))
+#define NTOHSI2(ni, hi)   ((hi) = (int) ntohl ((unsigned long) (ni)))
+
+/* unsigned short */
+#define HTONUS(s)         ((s) = htons((s)))
+#define NTOHUS(s)         ((s) = ntohs((s)))
+#define HTONUS2(hs, ns)   ((ns) = htons((hs)))
+#define NTOHUS2(ns, hs)   ((hs) = ntohs((ns)))
+
+#else   /* _BIG_ENDIAN */
+
+/* double */
+#define HTOND(d)          (d)
+#define NTOHD(d)          (d)
+#define HTOND2(hd, nd)    ((hd) = (nd))
+#define NTOHD2(nd, hd)    ((nd) = (hd))
+
+/* float */
+#define HTONF(f)          (f)
+#define NTOHF(f)          (f)
+#define HTONF2(hf, nf)    ((nf) = (hf))
+#define NTOHF2(nf, hf)    ((hf) = (nf))
+
+/* pointers */
+#define HTONP(p)          (p)
+#define NTOHP(p)          (p)
+#define HTONP2(hp, np)    ((np) = (hp))
+#define NTOHP2(np, hp)    ((hp) = (np))
+
+/* unsigned long */
+#define HTONUL(l)         (l)
+#define NTOHUL(l)         (l)
+#define HTONUL2(hl, nl)   ((nl) = (hl))
+#define NTOHUL2(nl, hl)   ((hl) = (nl))
+
+/* signed long */
+#define HTONSL(l)         (l)
+#define NTOHSL(l)         (l)
+#define HTONSL2(hl, nl)   ((nl) = (hl))
+#define NTOHSL2(nl, hl)   ((hl) = (nl))
+
+/* unsigned int */
+#define HTONUI(i)         (i)
+#define NTOHUI(i)         (i)
+#define HTONUI2(hi, ni)   ((ni) = (hi))
+#define NTOHUI2(ni, hi)   ((hi) = (ni))
+
+/* signed int */
+#define HTONSI(i)         (i)
+#define NTOHSI(i)         (i)
+#define HTONSI2(hi, ni)   ((ni) = (hi))
+#define NTOHSI2(ni, hi)   ((hi) = (ni))
+
+/* unsigned short */
+#define HTONUS(s)         (s)
+#define NTOHUS(s)         (s)
+#define HTONUS2(hs, ns)   ((ns) = (hs))
+#define NTOHUS2(ns, hs)   ((hs) = (ns))
+
+
+
+#endif
+
+#endif /* netorder.h */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/pathmax.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/pathmax.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/pathmax.h	(revision 10506)
@@ -0,0 +1,53 @@
+/* Define PATH_MAX somehow.  Requires sys/types.h.
+   Copyright (C) 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _PATHMAX_H
+#define _PATHMAX_H
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+   PATH_MAX but might cause redefinition warnings when sys/param.h is
+   later included (as on MORE/BSD 4.3).  */
+#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
+#include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+#define _POSIX_PATH_MAX 255
+#endif
+
+#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
+#define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
+#endif
+
+/* Don't include sys/param.h if it already has been.  */
+#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
+#include <sys/param.h>
+#endif
+
+#if !defined(PATH_MAX) && defined(MAXPATHLEN)
+#define PATH_MAX MAXPATHLEN
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+#endif /* _PATHMAX_H */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/perf_hash.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/perf_hash.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/perf_hash.c	(revision 10506)
@@ -0,0 +1,1108 @@
+/**************************************************************************
+ *
+ * perf_hash.c -- Perfect hashing functions
+ * Copyright (C) 1992  Bohdan S. Majewski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ * 1994 Neil Sharman
+ *      Small modifications were made to the interface so that it fitted in
+ *      with mg.
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.2  2001/02/22 01:35:03  jrm21
+   Fixed bug that caused perf_hash to fail for lexicon of < 4 words.
+   Added a #define to increase size of n (for vertices in the graph) as we
+   need to allocate more memory somewhere else before calling tree_builder()
+
+   Revision 1.1  1999/08/10 21:16:57  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:17  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/08/22  00:26:30  tes
+   * Made perf_hash take the ceiling of 1.23 * num
+   * in lieu of the floor.
+   * This was done so that perf_hash works ok on
+   * a small number of keys.
+   *
+   * Revision 1.1  1994/08/22  00:24:49  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#define STRUCT
+
+#include "sysfuncs.h"
+
+#include "local_strings.h"
+#include "memlib.h"
+#include "messages.h"
+#include "perf_hash.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#define FALSE 0
+#define TRUE  1
+
+#define STATIC 0
+
+/* Random Number stuff */
+static long seed[] = {0, 0};
+#define RANDOM() irandm(seed)
+#define SEED_RANDOM(the_seed) do{ seed[0] = the_seed; }while(0)
+
+/* Max number of keys - must be a power of 2 minus 1 */
+static int MAX_M;
+
+
+static int MAX_CH;
+
+
+/* the width of the mapping tables  */
+static int MAX_L;
+
+
+
+#define c     1.23
+static int MAX_N;
+
+/* An arbitrary amount to add to both MAX_N and n for building tree/acyclic
+   graph -- John McPherson - jrm21 (22-02-2001) */
+#define MAX_N_HEADROOM  100
+
+
+static u_char *translate;
+
+#define MEMBER 0
+#define ERASED 1
+
+
+
+/* direction constants for the edge oriented 3-graph representation */
+#define A              0
+#define B        (MAX_M)
+#define C          (2*B)
+
+/* NODEa, NODEb, NODEc, FIRST and NEXT are used to represent a 3-graph */
+static int *NODEa, *NODEb, *NODEc;
+static int *FIRST;
+static int *NEXT;
+
+
+#define norm(e) ((e) % MAX_M)
+/* in general should be ((e) % MAX_M) but MAX_M = 2^k - 1 */
+
+
+static char *mk;		/* for marking edges/vertices as removed */
+static int *g;			/* array g defines a minimal perfect hash function */
+
+
+
+/* stack of edges, created during the independency */
+/* test, used in the assignment step               */
+static struct
+  {
+    int sp;
+    int *st;
+  }
+S;
+#define push(s, e) s.st[s.sp++] = (e)
+#define pop(s, e)  e = s.st[--s.sp]
+
+#ifndef STRUCT
+static long **tb0, **tb1, **tb2;
+#else
+struct tb_entry **tb;
+#endif
+
+
+static int 
+unique (int v)
+{				/* checks if vertex v belongs to only one edge */
+  return (FIRST[v] != 0 && NEXT[FIRST[v]] == 0) ? FIRST[v] : 0;
+}				/*unique */
+
+
+
+
+
+
+
+
+static void 
+delete (int v, int e)
+{				/* deletes edge e from list of v */
+
+  int b;
+
+  b = FIRST[v];
+  assert (norm (b) != 0);
+  if (norm (b) == e)
+    FIRST[v] = NEXT[FIRST[v]];
+  else
+    {
+      while (norm (NEXT[b]) != e)
+	{
+	  b = NEXT[b];
+	  assert (norm (b) != 0);
+	}
+      NEXT[b] = NEXT[NEXT[b]];
+    }
+}				/*delete */
+
+
+
+
+
+
+#if 0
+/* recursively removes the edges of a 3-graph which have at least */
+/* one unique vertex. The removed edges are placed on stack S     */
+static void 
+ph_remove (int e, int v)
+{
+  int b;
+  mk[e] = ERASED;
+  push (S, e);
+
+  if (NODEa[e] != v)
+    delete (NODEa[e], e);
+  if (NODEb[e] != v)
+    delete (NODEb[e], e);
+  if (NODEc[e] != v)
+    delete (NODEc[e], e);
+
+  if (NODEa[e] != v && mk[b = norm (unique (NODEa[e]))] == MEMBER)
+    ph_remove (b, NODEa[e]);
+  if (NODEb[e] != v && mk[b = norm (unique (NODEb[e]))] == MEMBER)
+    ph_remove (b, NODEb[e]);
+  if (NODEc[e] != v && mk[b = norm (unique (NODEc[e]))] == MEMBER)
+    ph_remove (b, NODEc[e]);
+}
+#else
+
+
+static int StackPos, StackMax;
+static struct Stack
+  {
+    int e, v, m;
+  }
+ *Stack = NULL;
+
+#define StackAdd(_e, _v, _m)						\
+  do {									\
+    if (StackPos == StackMax)						\
+      {									\
+        StackMax <<= 1;							\
+	if (!(Stack = Xrealloc(Stack, sizeof(*Stack) * StackMax)))	\
+	  return(-1);							\
+      }									\
+    Stack[StackPos].e = (_e);						\
+    Stack[StackPos].v = (_v);						\
+    Stack[StackPos++].m = (_m);						\
+  } while(0)
+
+
+static int 
+ph_remove (int e, int v)
+{
+  if (!Stack)
+    {
+      StackMax = 256;
+      if (!(Stack = Xmalloc (sizeof (*Stack) * StackMax)))
+	return (-1);
+      StackPos = 0;
+    }
+  Stack[StackPos].e = e;
+  Stack[StackPos].v = v;
+  Stack[StackPos].m = 0;
+  StackPos++;
+  while (StackPos)
+    {
+      int m, b;
+      StackPos--;
+      e = Stack[StackPos].e;
+      v = Stack[StackPos].v;
+      m = Stack[StackPos].m;
+
+
+      switch (m)
+	{
+	case 0:
+	  {
+	    mk[e] = ERASED;
+	    push (S, e);
+
+	    if (NODEa[e] != v)
+	      delete (NODEa[e], e);
+	    if (NODEb[e] != v)
+	      delete (NODEb[e], e);
+	    if (NODEc[e] != v)
+	      delete (NODEc[e], e);
+
+	    if (NODEa[e] != v && mk[b = norm (unique (NODEa[e]))] == MEMBER)
+	      {
+		Stack[StackPos++].m = 1;
+		StackAdd (b, NODEa[e], 0);
+		break;
+	      }
+	  }
+	case 1:
+	  {
+	    if (NODEb[e] != v && mk[b = norm (unique (NODEb[e]))] == MEMBER)
+	      {
+		Stack[StackPos++].m = 2;
+		StackAdd (b, NODEb[e], 0);
+		break;
+	      }
+	  }
+	case 2:
+	  if (NODEc[e] != v && mk[b = norm (unique (NODEc[e]))] == MEMBER)
+	    StackAdd (b, NODEc[e], 0);
+	}
+    }
+  return (0);
+}
+#endif
+
+
+
+
+
+/* returns TRUE if and only if set of edges created in the tree_builder */
+/* procedure form a 3-graph with independent edges. Edges of a 3-graph  */
+/* are independent iff repeated deletion of edges containing vertices   */
+/* of degree 1 results in a graph with no edges in it.                  */
+static int 
+acyclic (int m, int n)
+{
+
+  int v, e;
+  /* build list of edges for each node */
+  for (v = 1; v <= n; FIRST[v++] = 0);
+  for (e = 1; e <= m; e++)
+    {
+      NEXT[A + e] = FIRST[NODEa[e]];
+      FIRST[NODEa[e]] = A + e;
+      NEXT[B + e] = FIRST[NODEb[e]];
+      FIRST[NODEb[e]] = B + e;
+      NEXT[C + e] = FIRST[NODEc[e]];
+      FIRST[NODEc[e]] = C + e;
+
+      /* mark edge e as belonging to the hypergraph */
+      mk[e] = MEMBER;
+    }
+
+
+  S.sp = 0;			/* empty the stack */
+  mk[0] = ERASED;		/* a sentinel for the test below */
+  for (v = 1; v <= n; v++)
+    {
+      if (mk[e = norm (unique (v))] == MEMBER)
+	ph_remove (e, v);
+    }
+
+  /* check if any edges were left in the graph */
+  return S.sp == m;
+}				/*acyclic */
+
+
+
+
+
+
+
+
+/* repeatedly maps words into edges of a 3-graph until the edges */
+/* are independent.                                              */
+static int 
+tree_builder (int num, u_char ** keys, int *n)
+{
+
+  int e, k = 0;
+  int i, j;
+  u_char *w;
+
+  do
+    {
+      /* Added variable - need to increase MAX_N on allocate as well */
+      *n = (int) (num * c + MAX_N_HEADROOM); /* john mcpherson 22-02-2001 */
+
+      /* initialize tables of random integers */
+      for (i = 0; i < MAX_CH; i++)
+	for (j = 0; j < MAX_L; j++)
+	  {
+#ifndef STRUCT
+	    tb0[i][j] = RANDOM () % *n;
+	    tb1[i][j] = RANDOM () % *n;
+	    tb2[i][j] = RANDOM () % *n;
+#else
+	    struct tb_entry *tbp = &tb[i][j];
+	    tbp->tb0 = RANDOM () % *n;
+	    tbp->tb1 = RANDOM () % *n;
+	    tbp->tb2 = RANDOM () % *n;
+#endif
+	  }
+
+      /* compute an edge (NODEa[e], NODEb[e], NODEc[e]) for each word */
+      for (e = 1; e <= num; e++)
+	{
+	  /*generate an edge corresponding to the ith word */
+	  int x = 0, y = 0, z = 0, l;
+	  w = keys[e - 1];
+
+	  l = *w++;
+	  j = (l - 1) % MAX_L;
+
+	  do
+	    {
+#ifndef STRUCT
+	      x += tb0[translate[*w]][j];
+	      y += tb1[translate[*w]][j];
+	      z += tb2[translate[*w]][j];
+#else
+	      struct tb_entry *tbp = &tb[translate[*w]][j];
+	      x += tbp->tb0;
+	      y += tbp->tb1;
+	      z += tbp->tb2;
+#endif
+	      if (++j >= MAX_L)
+		j = 0;
+	      w++;
+	    }
+	  while (--l);
+	  x = (x % *n) + 1;
+	  y = (y % *n) + 1;
+	  z = (z % *n) + 1;
+	  if (y == x && ++y > *n)
+	    y = 1;
+	  if (z == x && ++z > *n)
+	    z = 1;
+	  if (z == y)
+	    {
+	      if (++z > *n)
+		z = 1;
+	      if (z == x && ++z > *n)
+		z = 1;
+	    }
+
+	  NODEa[e] = x;
+	  NODEb[e] = y;
+	  NODEc[e] = z;
+	}
+      if (++k > 50)		/* make sure we will not wait for ever */
+	FatalError (1, "Unable to generate the perfect hash function. "
+		    "This is probably because there aren't enough words");
+    }
+  while (!acyclic (num, *n));
+  return k;
+}				/*tree_builder */
+
+
+
+
+
+
+
+
+
+/* calculates values of the g function/array so that i-th word is */
+/* placed at the (i-1)st position of a hash table.                */
+static void 
+assign (int n)
+{
+
+  int v, w = 0, e;
+
+  /* mark all the vertices of the 3-graph as unassigned */
+  for (v = 1; v <= n; mk[v++] = FALSE);
+
+  while (S.sp > 0)
+    {
+      int xor = 0;
+      pop (S, e);
+      v = NODEa[e];
+      if (mk[v])
+	xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      v = NODEb[e];
+      if (mk[v])
+	xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      v = NODEc[e];
+      if (mk[v])
+	xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      g[w] = (e - 1) ^ xor;
+    }
+}				/*assign */
+
+
+
+
+
+
+
+
+
+/*check returns 0 if no error in mphf is detected, else returns error code */
+static int 
+check (int m)
+{
+
+  int e, err_code = 0;
+
+  /*for each word compute its place in hash table and check if correct */
+  for (e = 1; e <= m; e++)
+    {
+      if ((e - 1) != (g[NODEa[e]] ^ g[NODEb[e]] ^ g[NODEc[e]]))
+	{
+	  (void) fprintf (stderr, "Error for %dth word detected.\n", e);
+	  err_code = e;
+	}
+    }
+  return err_code;
+}				/*check */
+
+
+
+
+
+
+
+#if 0
+void 
+outputh (int m, int n)
+{
+
+  int i, j, w = (int) ceil (log10 ((double) n + 1.0)) + 1;
+
+#if 0
+  char *PRG =
+  "int h(char *s)\n"
+  "{\n"
+  "  int u, v, w, i;\n"
+  "i = (strlen(s) - 1) % _HXL;\n"
+  "  u = v = w = 0;\n"
+  "  while(*s)\n"
+  "    {\n"
+  "      u += mt1[(*s) - _HFC][i];\n"
+  "      v += mt2[(*s) - _HFC][i];\n"
+  "      w += mt3[(*s++) - _HFC][i];\n"
+  "      if(++i >= _HXL) i = 0;\n"
+  "    }\n"
+  "  u %= _HFN; v %= _HFN; w %= _HFN;\n"
+  "  if(u == v && ++v >= _HFN) v = 0;\n"
+  "  if(w == u && ++w >= _HFN) w = 0;\n"
+  "  if(w == v && ++w >= _HFN) w = 0;\n"
+  "  if(w == u && ++w >= _HFN) w = 0;\n"
+  "  return (g[u] ^ g[v] ^ g[w]) % _HFM;\n"
+  "};\n\n";
+#endif
+
+  char *PRG =
+  "int h(char *s)\n"
+  "{\n"
+  "  int u, v, w, i;\n"
+  "  i = (strlen(s) - 1) % _HXL;\n"
+  "  u = v = w = 0;\n"
+  "  while(*s)\n"
+  "    {\n"
+  "      if((u += mt1[(*s) - _HFC][i]) >= _HFN) u -= _HFN;\n"
+  "      if((v += mt2[(*s) - _HFC][i]) >= _HFN) v -= _HFN;\n"
+  "      if((w += mt3[(*s++) - _HFC][i]) >= _HFN) w -= _HFN;\n"
+  "      if(++i >= _HXL) i = 0;\n"
+  "    }\n"
+  "  if(u == v && ++v >= _HFN) v = 0;\n"
+  "  if(w == v) \n"
+  "    {\n"
+  "      if(++w >= _HFN) w = 0;\n"
+  "      if(w == u && ++w >= _HFN) w = 0;\n"
+  "    }\n"
+  "  else\n"
+  "    if(w == u)\n"
+  "      {\n"
+  "	     if(++w >= _HFN) w = 0;\n"
+  "	     if(w == v && ++w >= _HFN) w = 0;\n"
+  "      }\n"
+  "  return ((g[u] ^ g[v] ^ g[w]) > _HFM)? 0 : (g[u] ^ g[v] ^ g[w]);\n"
+  "}\n\n";
+
+  printf ("#define _HFN %d\n#define _HFC %d\n", n, fc);
+  printf ("#define _HFM %d\n#define _HXL %d\n", m, MAX_L);
+  printf ("#define _HFA %d\n\nstatic int g[_HFN] = {\n", lc - fc + 1);
+  for (i = 1; i < n; i++)
+    {
+      if (i % 8 == 0)
+	putchar ('\n');
+      printf ("%5d, ", g[i]);
+    }
+  printf ("%5d};\n\n", g[n]);
+
+  printf ("static int mt1[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; j++)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; i++)
+	printf ("%*d,", w, tb0[j][i]);
+      printf ("%*d},\n", w, tb0[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; i++)
+    printf ("%*d,", w, tb0[lc][i]);
+  printf ("%*d}\n", w, tb0[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("static int mt2[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; j++)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; i++)
+	printf ("%*d,", w, tb1[j][i]);
+      printf ("%*d},\n", w, tb1[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; i++)
+    printf ("%*d,", w, tb1[lc][i]);
+  printf ("%*d}\n", w, tb1[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("static int mt3[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; j++)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; i++)
+	printf ("%*d,", w, tb2[j][i]);
+      printf ("%*d},\n", w, tb2[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; i++)
+    printf ("%*d,", w, tb2[lc][i]);
+  printf ("%*d}\n", w, tb2[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("%s", PRG);
+}				/*outputh */
+#endif
+
+
+
+
+
+
+
+static void 
+make_trans_func (int num, u_char ** keys)
+{
+  int i, j;
+
+  bzero ((char *) translate, sizeof (translate));
+
+  MAX_L = 1;
+  for (i = 0; i < num; i++)
+    {
+      unsigned len = keys[i][0];
+      u_char *s = keys[i] + 1;
+      for (; len; len--, s++)
+	translate[*s] = 1;
+      if (i)
+	{
+	  int l;
+	  l = prefixlen (keys[i - 1], keys[i]);
+	  if (l + 1 > MAX_L)
+	    MAX_L = l + 1;
+	}
+    }
+  j = 0;
+  for (i = 0; i < 256; i++)
+    if (translate[i])
+      translate[i] = j++;
+  MAX_CH = j;
+}
+
+
+static void 
+temp_free (void)
+{
+  if (NODEa)
+    Xfree (NODEa);
+  if (NODEb)
+    Xfree (NODEb);
+  if (NODEc)
+    Xfree (NODEc);
+  if (FIRST)
+    Xfree (FIRST);
+  if (NEXT)
+    Xfree (NEXT);
+  if (S.st)
+    Xfree (S.st);
+  if (mk)
+    Xfree (mk);
+}
+
+static void 
+all_free (void)
+{
+  int i;
+  temp_free ();
+  if (translate)
+    Xfree (translate);
+  if (g)
+    Xfree (g);
+#ifndef STRUCT
+  for (i = 0; i < MAX_CH; i++)
+    {
+      if (tb0 && tb0[i])
+	Xfree (tb0[i]);
+      if (tb1 && tb1[i])
+	Xfree (tb1[i]);
+      if (tb2 && tb2[i])
+	Xfree (tb2[i]);
+    }
+  if (tb0)
+    Xfree (tb0);
+  if (tb1)
+    Xfree (tb1);
+  if (tb2)
+    Xfree (tb2);
+#else
+  for (i = 0; i < MAX_CH; i++)
+    if (tb && tb[i])
+      Xfree (tb[i]);
+  if (tb)
+    Xfree (tb);
+#endif
+}
+
+static int 
+allocate_memory (void)
+{
+  int i, ok = 1;
+  NODEa = Xmalloc (sizeof (int) * (MAX_M + 1));
+  NODEb = Xmalloc (sizeof (int) * (MAX_M + 1));
+  NODEc = Xmalloc (sizeof (int) * (MAX_M + 1));
+  FIRST = Xmalloc (sizeof (int) * (MAX_N + 1));
+  NEXT = Xmalloc (sizeof (int) * (MAX_M + 1) * 3);
+  S.st = Xmalloc (sizeof (int) * MAX_M);
+  mk = Xmalloc (sizeof (char) * (MAX_N + 1));
+  g = Xmalloc (sizeof (int) * (MAX_N + 1));
+#ifndef STRUCT
+  tb0 = Xmalloc (sizeof (int *) * MAX_CH);
+  tb1 = Xmalloc (sizeof (int *) * MAX_CH);
+  tb2 = Xmalloc (sizeof (int *) * MAX_CH);
+  for (i = 0; i < MAX_CH; i++)
+    {
+      if (tb0)
+	if (!(tb0[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+      if (tb1)
+	if (!(tb1[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+      if (tb2)
+	if (!(tb2[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+    }
+
+  if (!(NODEa && NODEb && NODEc && FIRST && NEXT && S.st && mk && g &&
+	tb0 && tb1 && tb2 && ok))
+    {
+      all_free ();
+      return (-1);
+    }
+#else
+  tb = Xmalloc (sizeof (struct tb_entry *) * MAX_CH);
+  for (i = 0; i < MAX_CH; i++)
+    if (tb)
+      if (!(tb[i] = Xmalloc (sizeof (struct tb_entry) * MAX_L)))
+	  ok = 0;
+
+  if (!(NODEa && NODEb && NODEc && FIRST && NEXT && S.st && mk && g &&
+	tb && ok))
+    {
+      all_free ();
+      return (-1);
+    }
+#endif
+  return (0);
+}
+
+
+perf_hash_data *
+gen_hash_func (int num, u_char ** keys, int r)
+{
+  int n;
+  perf_hash_data *phd;
+  translate = Xmalloc (sizeof (u_char) * 256);
+  bzero ((char *) translate, sizeof (u_char) * 256);  /* [RPAP - Feb 97: WIN32 Port] */
+  make_trans_func (num, keys);
+
+  if (r <= 0)
+    SEED_RANDOM ((long) time ((time_t *) NULL));
+  else
+    SEED_RANDOM (r);
+
+  MAX_M = num + 1;
+
+  /* For extremely small lexicons (<4 words), this isn't good enough! 
+   -- John McPherson jrm21 22-02-2001 */
+  /* MAX_N = MAX_M + MAX_M / 4; */
+  MAX_N = (int)(ceil (1.25 * MAX_M)); 
+  /* Add some space for "experimentation" of n in tree_builder() */
+  MAX_N += MAX_N_HEADROOM;
+
+  if (allocate_memory () == -1)
+    return (NULL);
+
+  /* construct an "acyclic" hypergraph */
+  tree_builder (num, keys, &n);
+  /* compute function g */
+  assign (n);
+
+  if (check (num) != 0)
+    FatalError (1, "An error has been detected in the mphf.");
+  temp_free ();
+
+  if (!(phd = Xmalloc (sizeof (perf_hash_data))))
+    return (NULL);
+
+  bcopy ((char *) &g[1], (char *) g, n * sizeof (int));
+
+  phd->MAX_L = MAX_L;
+  phd->MAX_N = n;
+  phd->MAX_M = num;
+  phd->MAX_CH = MAX_CH;
+  phd->translate = translate;
+  phd->g = g;
+#ifndef STRUCT
+  phd->tb0 = tb0;
+  phd->tb1 = tb1;
+  phd->tb2 = tb2;
+#else
+  phd->tb = tb;
+#endif
+  return (phd);
+}
+
+int 
+write_perf_hash_data (FILE * f, perf_hash_data * phd)
+{
+  int tot, i;
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONSI(phd->MAX_L);
+  HTONSI(phd->MAX_N);
+  HTONSI(phd->MAX_M);
+  HTONSI(phd->MAX_CH);
+
+  tot = fwrite ((char *) &phd->MAX_L, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_N, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_M, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_CH, sizeof (int), 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(phd->MAX_L);
+  NTOHSI(phd->MAX_N);
+  NTOHSI(phd->MAX_M);
+  NTOHSI(phd->MAX_CH);
+
+  tot += fwrite ((char *) phd->translate, sizeof (u_char), 256, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    HTONSI(phd->g[i]);
+
+  tot += fwrite ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    NTOHSI(phd->g[i]);
+
+#ifndef STRUCT
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int j;
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  HTONSI(phd->tb0[i][j]);
+	  HTONSI(phd->tb1[i][j]);
+	  HTONSI(phd->tb2[i][j]);
+	}
+
+      tot += fwrite ((char *) phd->tb0[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fwrite ((char *) phd->tb1[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fwrite ((char *) phd->tb2[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSI(phd->tb0[i][j]);
+	  NTOHSI(phd->tb1[i][j]);
+	  NTOHSI(phd->tb2[i][j]);
+	}
+    }
+#else
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int j;
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  HTONSL(phd->tb[i][j].tb0);
+	  HTONSL(phd->tb[i][j].tb1);
+	  HTONSL(phd->tb[i][j].tb2);
+	}
+
+      tot += fwrite ((char *) phd->tb[i], sizeof (struct tb_entry), phd->MAX_L, f) *
+	sizeof (struct tb_entry);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSL(phd->tb[i][j].tb0);
+	  NTOHSL(phd->tb[i][j].tb1);
+	  NTOHSL(phd->tb[i][j].tb2);
+	}
+    }
+#endif
+  return (tot);
+}
+
+
+perf_hash_data *
+read_perf_hash_data (FILE * f)
+{
+  perf_hash_data *phd;
+  int i, tot, ok = 1;
+  if (!(phd = Xmalloc (sizeof (perf_hash_data))))
+    return (NULL);
+  tot = fread ((char *) &phd->MAX_L, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_N, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_M, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_CH, sizeof (int), 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(phd->MAX_L);
+  NTOHSI(phd->MAX_N);
+  NTOHSI(phd->MAX_M);
+  NTOHSI(phd->MAX_CH);
+
+  if (tot != 4 * sizeof (int))
+      return (NULL);
+  phd->translate = Xmalloc (sizeof (u_char) * 256);
+  phd->g = Xmalloc (sizeof (int) * (phd->MAX_N + 1));
+#ifndef STRUCT
+  phd->tb0 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  phd->tb1 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  phd->tb2 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      if (phd->tb0)
+	if (!(phd->tb0[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+      if (phd->tb1)
+	if (!(phd->tb1[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+      if (phd->tb2)
+	if (!(phd->tb2[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+    }
+  if (!(phd->translate && phd->g && phd->tb0 && phd->tb1 && phd->tb2 && ok))
+    {
+      if (phd->translate)
+	Xfree (phd->translate);
+      if (phd->g)
+	Xfree (phd->g);
+      for (i = 0; i < MAX_CH; i++)
+	{
+	  if (phd->tb0 && phd->tb0[i])
+	    Xfree (phd->tb0[i]);
+	  if (phd->tb1 && phd->tb1[i])
+	    Xfree (phd->tb1[i]);
+	  if (phd->tb2 && phd->tb2[i])
+	    Xfree (phd->tb2[i]);
+	}
+      if (phd->tb0)
+	Xfree (phd->tb0);
+      if (phd->tb1)
+	Xfree (phd->tb1);
+      if (phd->tb2)
+	Xfree (phd->tb2);
+      Xfree (phd);
+      return (NULL);
+    }
+  tot += fread ((char *) phd->translate, sizeof (u_char), 256, f);
+  tot += fread ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    NTOHSI(phd->g[i]);
+
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      int j;
+
+      tot += fread ((char *) phd->tb0[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fread ((char *) phd->tb1[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fread ((char *) phd->tb2[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSI(phd->tb0[i][j]);
+	  NTOHSI(phd->tb1[i][j]);
+	  NTOHSI(phd->tb2[i][j]);
+	}
+    }
+#else
+  phd->tb = Xmalloc (sizeof (struct tb_entry *) * phd->MAX_CH);
+  for (i = 0; i < phd->MAX_CH; i++)
+    if (phd->tb)
+      if (!(phd->tb[i] = Xmalloc (sizeof (struct tb_entry) * phd->MAX_L)))
+	  ok = 0;
+  if (!(phd->translate && phd->g && phd->tb && ok))
+    {
+      if (phd->translate)
+	Xfree (phd->translate);
+      if (phd->g)
+	Xfree (phd->g);
+      for (i = 0; i < MAX_CH; i++)
+	if (phd->tb && phd->tb[i])
+	  Xfree (phd->tb[i]);
+      if (phd->tb)
+	Xfree (phd->tb);
+      Xfree (phd);
+      return (NULL);
+    }
+  tot += fread ((char *) phd->translate, sizeof (u_char), 256, f);
+  tot += fread ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; i++)
+    NTOHSI(phd->g[i]);
+
+  for (i = 0; i < phd->MAX_CH; i++)
+    {
+      int j;
+
+      tot += fread ((char *) phd->tb[i], sizeof (struct tb_entry), phd->MAX_L, f) *
+	sizeof (struct tb_entry);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; j++)
+	{
+	  NTOHSL(phd->tb[i][j].tb0);
+	  NTOHSL(phd->tb[i][j].tb1);
+	  NTOHSL(phd->tb[i][j].tb2);
+	}
+    }
+#endif
+  return (phd);
+}
+
+void 
+free_perf_hash (perf_hash_data * phd)
+{
+  int i;
+  if (phd->translate)
+    Xfree (phd->translate);
+  if (phd->g)
+    Xfree (phd->g);
+  for (i = 0; i < phd->MAX_CH; i++)
+    if (phd->tb && phd->tb[i])
+      Xfree (phd->tb[i]);
+  if (phd->tb)
+    Xfree (phd->tb);
+  Xfree (phd);
+}
+
+
+int 
+perf_hash (perf_hash_data * phd, u_char * s)
+{
+  int u, v, w, i, l;
+  l = *s++;
+  i = (l - 1) % phd->MAX_L;
+  u = v = w = 0;
+  while (l)
+    {
+#ifndef STRUCT
+      if ((u += phd->tb0[phd->translate[*s]][i]) >= phd->MAX_N)
+	u -= phd->MAX_N;
+      if ((v += phd->tb1[phd->translate[*s]][i]) >= phd->MAX_N)
+	v -= phd->MAX_N;
+      if ((w += phd->tb2[phd->translate[*s]][i]) >= phd->MAX_N)
+	w -= phd->MAX_N;
+#else
+      struct tb_entry *tbp = &phd->tb[phd->translate[*s]][i];
+      if ((u += tbp->tb0) >= phd->MAX_N)
+	u -= phd->MAX_N;
+      if ((v += tbp->tb1) >= phd->MAX_N)
+	v -= phd->MAX_N;
+      if ((w += tbp->tb2) >= phd->MAX_N)
+	w -= phd->MAX_N;
+#endif
+      if (++i >= phd->MAX_L)
+	i = 0;
+      l--;
+      s++;
+    }
+  if (u == v && ++v >= phd->MAX_N)
+    v = 0;
+  if (w == v)
+    {
+      if (++w >= phd->MAX_N)
+	w = 0;
+      if (w == u && ++w >= phd->MAX_N)
+	w = 0;
+    }
+  else if (w == u)
+    {
+      if (++w >= phd->MAX_N)
+	w = 0;
+      if (w == v && ++w >= phd->MAX_N)
+	w = 0;
+    }
+  return ((phd->g[u] ^ phd->g[v] ^ phd->g[w]) > phd->MAX_M) ? 0 :
+    (phd->g[u] ^ phd->g[v] ^ phd->g[w]);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/perf_hash.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/perf_hash.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/perf_hash.h	(revision 10506)
@@ -0,0 +1,57 @@
+/**************************************************************************
+ *
+ * perf_hash.h -- Perfect hashing functions
+ * Copyright (C) 1994  Bohdan S. Majewski and Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_PERF_HASH
+#define H_PERF_HASH
+
+
+
+
+struct tb_entry
+  {
+    long tb0, tb1, tb2;
+  };
+
+typedef struct
+  {
+    int MAX_L;
+    int MAX_N;
+    int MAX_M;
+    int MAX_CH;
+    u_char *translate;
+    int *g;
+    struct tb_entry **tb;
+  }
+perf_hash_data;
+
+perf_hash_data *gen_hash_func (int num, u_char ** keys, int r);
+
+int perf_hash (perf_hash_data * phd, u_char * s);
+
+int write_perf_hash_data (FILE * f, perf_hash_data * phd);
+
+void free_perf_hash (perf_hash_data * phd);
+
+perf_hash_data *read_perf_hash_data (FILE * f);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/random.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/random.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/random.c	(revision 10506)
@@ -0,0 +1,225 @@
+/**************************************************************************
+ *
+ * random.c -- pseudo random number generator
+ * Copyright (C) 1994  Chris Wallace (csw@bruce.cs.monash.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+$Log$
+Revision 1.1  1999/08/10 21:16:57  sjboddie
+renamed mg-1.3d directory mg
+
+Revision 1.1  1998/11/17 09:32:20  rjmcnab
+*** empty log message ***
+
+*/
+
+static char *RCSID = "$Id$";
+
+/*
+ *	A random number generator called as a function by
+ *	random (iseed)	or	irandm (iseed)
+ *	The parameter should be a pointer to a 2-element long vector.
+ *	The first function returns a double uniform in 0 .. 1.
+ *	The second returns a long integer uniform in 0 .. 2**31-1
+ *	Both update iseed[] in exactly the same way.
+ *	iseed[] must be a 2-element integer vector.
+ *	The initial value of the second element may be anything.
+ *
+ *	The period of the random sequence is 2**32 * (2**32-1)
+ *	The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
+ */
+
+#define MASK ((long) 593970775)
+/*	or in hex, 23674657	*/
+
+#define SCALE ((double) 1.0 / (1024.0 * 1024.0 * 1024.0 * 2.0))
+/*	i.e. 2 to power -31	*/
+
+static long mt [128] =   {
+      902906369,
+     2030498053,
+     -473499623,
+     1640834941,
+      723406961,
+     1993558325,
+     -257162999,
+    -1627724755,
+      913952737,
+      278845029,
+     1327502073,
+    -1261253155,
+      981676113,
+    -1785280363,
+     1700077033,
+      366908557,
+    -1514479167,
+     -682799163,
+      141955545,
+     -830150595,
+      317871153,
+     1542036469,
+     -946413879,
+    -1950779155,
+      985397153,
+      626515237,
+      530871481,
+      783087261,
+    -1512358895,
+     1031357269,
+    -2007710807,
+    -1652747955,
+    -1867214463,
+      928251525,
+     1243003801,
+    -2132510467,
+     1874683889,
+     -717013323,
+      218254473,
+    -1628774995,
+    -2064896159,
+       69678053,
+      281568889,
+    -2104168611,
+     -165128239,
+     1536495125,
+      -39650967,
+      546594317,
+     -725987007,
+     1392966981,
+     1044706649,
+      687331773,
+    -2051306575,
+     1544302965,
+     -758494647,
+    -1243934099,
+      -75073759,
+      293132965,
+    -1935153095,
+      118929437,
+      807830417,
+    -1416222507,
+    -1550074071,
+      -84903219,
+     1355292929,
+     -380482555,
+    -1818444007,
+     -204797315,
+      170442609,
+    -1636797387,
+      868931593,
+     -623503571,
+     1711722209,
+      381210981,
+     -161547783,
+     -272740131,
+    -1450066095,
+     2116588437,
+     1100682473,
+      358442893,
+    -1529216831,
+     2116152005,
+     -776333095,
+     1265240893,
+     -482278607,
+     1067190005,
+      333444553,
+       86502381,
+      753481377,
+       39000101,
+     1779014585,
+      219658653,
+     -920253679,
+     2029538901,
+     1207761577,
+    -1515772851,
+     -236195711,
+      442620293,
+      423166617,
+    -1763648515,
+     -398436623,
+    -1749358155,
+     -538598519,
+     -652439379,
+      430550625,
+    -1481396507,
+     2093206905,
+    -1934691747,
+     -962631983,
+     1454463253,
+    -1877118871,
+     -291917555,
+    -1711673279,
+      201201733,
+     -474645415,
+      -96764739,
+    -1587365199,
+     1945705589,
+     1303896393,
+     1744831853,
+      381957665,
+     2135332261,
+      -55996615,
+    -1190135011,
+     1790562961,
+    -1493191723,
+      475559465,
+          69069
+		};
+
+double 
+random (long is [2])
+{
+	long it, leh, nit;
+
+	it = is [0];
+	leh = is [1];
+	if (it <= 0)	
+		it = (it + it) ^ MASK;
+	else
+		it = it + it;
+	nit = it - 1;
+/*	to ensure all-ones pattern omitted    */
+	leh = leh * mt[nit & 127] + nit;
+	is [0] = it;    is [1] = leh;
+	if (leh < 0) leh = ~leh;
+	return (SCALE * ((long) (leh | 1)));
+}
+
+
+
+long 
+irandm (long is [2])
+{
+	long it, leh, nit;
+
+	it = is [0];
+	leh = is [1];
+	if (it <= 0)	
+		it = (it + it) ^ MASK;
+	else
+		it = it + it;
+	nit = it - 1;
+/*	to ensure all-ones pattern omitted    */
+	leh = leh * mt[nit & 127] + nit;
+	is [0] = it;    is [1] = leh;
+	if (leh < 0) leh = ~leh;
+	return (leh);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/random.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/random.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/random.h	(revision 10506)
@@ -0,0 +1,54 @@
+/**************************************************************************
+ *
+ * random.h -- pseudo random number generator
+ * Copyright (C) 1994  Chris Wallace (csw@bruce.cs.monash.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+$Log$
+Revision 1.1  1999/08/10 21:16:58  sjboddie
+renamed mg-1.3d directory mg
+
+Revision 1.1  1998/11/17 09:32:21  rjmcnab
+*** empty log message ***
+
+*/
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+/*
+ *	A random number generator called as a function by
+ *	random (iseed)	or	irandm (iseed)
+ *	The parameter should be a pointer to a 2-element long vector.
+ *	The first function returns a double uniform in 0 .. 1.
+ *	The second returns a long integer uniform in 0 .. 2**31-1
+ *	Both update iseed[] in exactly the same way.
+ *	iseed[] must be a 2-element integer vector.
+ *	The initial value of the second element may be anything.
+ *
+ *	The period of the random sequence is 2**32 * (2**32-1)
+ *	The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
+ */
+
+double random (long is [2]);
+long irandm (long is [2]);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/regex.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/regex.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/regex.c	(revision 10506)
@@ -0,0 +1,5426 @@
+/* Extended regular expression matching and search library,
+   version 0.12.
+   (Implements POSIX draft P10003.2/D11.2, except for
+   internationalization features.)
+
+   Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* AIX requires this to be the first thing in the file. */
+#if defined (_AIX) && !defined (REGEX_MALLOC)
+  #pragma alloca
+#endif
+
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+/* We need this for `regex.h', and perhaps for the Emacs include files.  */
+#include <sys/types.h>
+
+/* This is for other GNU distributions with internationalized messages.  */
+#if HAVE_LIBINTL_H || defined (_LIBC)
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+/* The `emacs' switch turns on certain matching commands
+   that make sense only in Emacs. */
+#ifdef emacs
+
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+
+#else  /* not emacs */
+
+/* If we are not linking with Emacs proper,
+   we can't use the relocating allocator
+   even if sysfuncs.h says that we can.  */
+#undef REL_ALLOC
+
+#if defined (STDC_HEADERS) || defined (_LIBC)
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+#endif
+
+/* We used to test for `BSTRING' here, but only GCC and Emacs define
+   `BSTRING', as far as I know, and neither of them use this code.  */
+#ifndef INHIBIT_STRING_HEADER
+#if HAVE_STRING_H || STDC_HEADERS || defined (_LIBC)
+#include <string.h>
+#ifndef bcmp
+#define bcmp(s1, s2, n)	memcmp ((s1), (s2), (n))
+#endif
+#ifndef bcopy
+#define bcopy(s, d, n)	memcpy ((d), (s), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n)	memset ((s), 0, (n))
+#endif
+#else
+#include <strings.h>
+#endif
+#endif
+
+/* Define the syntax stuff for \<, \>, etc.  */
+
+/* This must be nonzero for the wordchar and notwordchar pattern
+   commands in re_match_2.  */
+#ifndef Sword 
+#define Sword 1
+#endif
+
+#ifdef SWITCH_ENUM_BUG
+#define SWITCH_ENUM_CAST(x) ((int)(x))
+#else
+#define SWITCH_ENUM_CAST(x) (x)
+#endif
+
+#ifdef SYNTAX_TABLE
+
+extern char *re_syntax_table;
+
+#else /* not SYNTAX_TABLE */
+
+/* How many characters in the character set.  */
+#define CHAR_SET_SIZE 256
+
+static char re_syntax_table[CHAR_SET_SIZE];
+
+static void
+init_syntax_once ()
+{
+   register int c;
+   static int done = 0;
+
+   if (done)
+     return;
+
+   bzero (re_syntax_table, sizeof re_syntax_table);
+
+   for (c = 'a'; c <= 'z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = 'A'; c <= 'Z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = '0'; c <= '9'; c++)
+     re_syntax_table[c] = Sword;
+
+   re_syntax_table['_'] = Sword;
+
+   done = 1;
+}
+
+#endif /* not SYNTAX_TABLE */
+
+#define SYNTAX(c) re_syntax_table[c]
+
+#endif /* not emacs */
+
+
+/* Get the interface, including the syntax bits.  */
+#include "regex.h"
+
+/* isalpha etc. are used for the character classes.  */
+#include <ctype.h>
+
+/* Jim Meyering writes:
+
+   "... Some ctype macros are valid only for character codes that
+   isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+   using /bin/cc or gcc but without giving an ansi option).  So, all
+   ctype uses should be through macros like ISPRINT...  If
+   STDC_HEADERS is defined, then autoconf has verified that the ctype
+   macros don't need to be guarded with references to isascii. ...
+   Defining isascii to 1 should let any compiler worth its salt
+   eliminate the && through constant folding."  */
+
+#ifndef ISASCII
+#  if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+#    define ISASCII(c) 1
+#  else
+#    define ISASCII(c) isascii(c)
+#  endif
+#endif
+
+#ifdef isblank
+#define ISBLANK(c) (ISASCII (c) && isblank (c))
+#else
+#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+#define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+#else
+#define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+#endif
+
+#define ISPRINT(c) (ISASCII (c) && isprint (c))
+#define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+#define ISALNUM(c) (ISASCII (c) && isalnum (c))
+#define ISALPHA(c) (ISASCII (c) && isalpha (c))
+#define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+#define ISLOWER(c) (ISASCII (c) && islower (c))
+#define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+#define ISSPACE(c) (ISASCII (c) && isspace (c))
+#define ISUPPER(c) (ISASCII (c) && isupper (c))
+#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+   since ours (we hope) works properly with all combinations of
+   machines, compilers, `char' and `unsigned char' argument types.
+   (Per Bothner suggested the basic approach.)  */
+#undef SIGN_EXTEND_CHAR
+#if __STDC__
+#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+#else  /* not __STDC__ */
+/* As in Harbison and Steele.  */
+#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+#endif
+
+
+/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
+   use `alloca' instead of `malloc'.  This is because using malloc in
+   re_search* or re_match* could cause memory leaks when C-g is used in
+   Emacs; also, malloc is slower and causes storage fragmentation.  On
+   the other hand, malloc is more portable, and easier to debug.  
+   
+   Because we sometimes use alloca, some routines have to be macros,
+   not functions -- `alloca'-allocated space disappears at the end of the
+   function it is called in.  */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE malloc
+#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+#define REGEX_FREE free
+
+#else /* not REGEX_MALLOC  */
+
+/* Emacs already defines alloca, sometimes.  */
+#ifndef alloca
+
+/* Make alloca work the best possible way.  */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else /* not __GNUC__ or HAVE_ALLOCA_H */
+#ifndef _AIX /* Already did AIX, up at the top.  */
+char *alloca ();
+#endif /* not _AIX */
+#endif /* not HAVE_ALLOCA_H */ 
+#endif /* not __GNUC__ */
+
+#endif /* not alloca */
+
+#define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable.  */
+#define REGEX_REALLOCATE(source, osize, nsize)				\
+  (destination = (char *) alloca (nsize),				\
+   bcopy (source, destination, osize),					\
+   destination)
+
+/* No need to do anything to free, after alloca.  */
+#define REGEX_FREE(arg) ((void)0) /* Do nothing!  But inhibit gcc warning.  */
+
+#endif /* not REGEX_MALLOC */
+
+/* Define how to allocate the failure stack.  */
+
+#ifdef REL_ALLOC
+#define REGEX_ALLOCATE_STACK(size)				\
+  r_alloc (&failure_stack_ptr, (size))
+#define REGEX_REALLOCATE_STACK(source, osize, nsize)		\
+  r_re_alloc (&failure_stack_ptr, (nsize))
+#define REGEX_FREE_STACK(ptr)					\
+  r_alloc_free (&failure_stack_ptr)
+
+#else /* not REL_ALLOC */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE_STACK malloc
+#define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
+#define REGEX_FREE_STACK free
+
+#else /* not REGEX_MALLOC */
+
+#define REGEX_ALLOCATE_STACK alloca
+
+#define REGEX_REALLOCATE_STACK(source, osize, nsize)			\
+   REGEX_REALLOCATE (source, osize, nsize)
+/* No need to explicitly free anything.  */
+#define REGEX_FREE_STACK(arg)
+
+#endif /* not REGEX_MALLOC */
+#endif /* not REL_ALLOC */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+   `string1' or just past its end.  This works if PTR is NULL, which is
+   a good thing.  */
+#define FIRST_STRING_P(ptr) 					\
+  (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail.  */
+#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+#define RETALLOC_IF(addr, n, t) \
+  if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
+#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+#define BYTEWIDTH 8 /* In bits.  */
+
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+static int re_match_2_internal ();
+
+
+/* These are the command codes that appear in compiled regular
+   expressions.  Some opcodes are followed by argument bytes.  A
+   command code can specify any interpretation whatsoever for its
+   arguments.  Zero bytes may appear in the compiled regular expression.  */
+
+typedef enum
+{
+  no_op = 0,
+
+  /* Succeed right away--no more backtracking.  */
+  succeed,
+
+        /* Followed by one byte giving n, then by n literal bytes.  */
+  exactn,
+
+        /* Matches any (more or less) character.  */
+  anychar,
+
+        /* Matches any one char belonging to specified set.  First
+           following byte is number of bitmap bytes.  Then come bytes
+           for a bitmap saying which chars are in.  Bits in each byte
+           are ordered low-bit-first.  A character is in the set if its
+           bit is 1.  A character too large to have a bit in the map is
+           automatically not in the set.  */
+  charset,
+
+        /* Same parameters as charset, but match any character that is
+           not one of those specified.  */
+  charset_not,
+
+        /* Start remembering the text that is matched, for storing in a
+           register.  Followed by one byte with the register number, in
+           the range 0 to one less than the pattern buffer's re_nsub
+           field.  Then followed by one byte with the number of groups
+           inner to this one.  (This last has to be part of the
+           start_memory only because we need it in the on_failure_jump
+           of re_match_2.)  */
+  start_memory,
+
+        /* Stop remembering the text that is matched and store it in a
+           memory register.  Followed by one byte with the register
+           number, in the range 0 to one less than `re_nsub' in the
+           pattern buffer, and one byte with the number of inner groups,
+           just like `start_memory'.  (We need the number of inner
+           groups here because we don't have any easy way of finding the
+           corresponding start_memory when we're at a stop_memory.)  */
+  stop_memory,
+
+        /* Match a duplicate of something remembered. Followed by one
+           byte containing the register number.  */
+  duplicate,
+
+        /* Fail unless at beginning of line.  */
+  begline,
+
+        /* Fail unless at end of line.  */
+  endline,
+
+        /* Succeeds if at beginning of buffer (if emacs) or at beginning
+           of string to be matched (if not).  */
+  begbuf,
+
+        /* Analogously, for end of buffer/string.  */
+  endbuf,
+ 
+        /* Followed by two byte relative address to which to jump.  */
+  jump, 
+
+	/* Same as jump, but marks the end of an alternative.  */
+  jump_past_alt,
+
+        /* Followed by two-byte relative address of place to resume at
+           in case of failure.  */
+  on_failure_jump,
+	
+        /* Like on_failure_jump, but pushes a placeholder instead of the
+           current string position when executed.  */
+  on_failure_keep_string_jump,
+  
+        /* Throw away latest failure point and then jump to following
+           two-byte relative address.  */
+  pop_failure_jump,
+
+        /* Change to pop_failure_jump if know won't have to backtrack to
+           match; otherwise change to jump.  This is used to jump
+           back to the beginning of a repeat.  If what follows this jump
+           clearly won't match what the repeat does, such that we can be
+           sure that there is no use backtracking out of repetitions
+           already matched, then we change it to a pop_failure_jump.
+           Followed by two-byte address.  */
+  maybe_pop_jump,
+
+        /* Jump to following two-byte address, and push a dummy failure
+           point. This failure point will be thrown away if an attempt
+           is made to use it for a failure.  A `+' construct makes this
+           before the first repeat.  Also used as an intermediary kind
+           of jump when compiling an alternative.  */
+  dummy_failure_jump,
+
+	/* Push a dummy failure point and continue.  Used at the end of
+	   alternatives.  */
+  push_dummy_failure,
+
+        /* Followed by two-byte relative address and two-byte number n.
+           After matching N times, jump to the address upon failure.  */
+  succeed_n,
+
+        /* Followed by two-byte relative address, and two-byte number n.
+           Jump to the address N times, then fail.  */
+  jump_n,
+
+        /* Set the following two-byte relative address to the
+           subsequent two-byte number.  The address *includes* the two
+           bytes of number.  */
+  set_number_at,
+
+  wordchar,	/* Matches any word-constituent character.  */
+  notwordchar,	/* Matches any char that is not a word-constituent.  */
+
+  wordbeg,	/* Succeeds if at word beginning.  */
+  wordend,	/* Succeeds if at word end.  */
+
+  wordbound,	/* Succeeds if at a word boundary.  */
+  notwordbound	/* Succeeds if not at a word boundary.  */
+
+#ifdef emacs
+  ,before_dot,	/* Succeeds if before point.  */
+  at_dot,	/* Succeeds if at point.  */
+  after_dot,	/* Succeeds if after point.  */
+
+	/* Matches any character whose syntax is specified.  Followed by
+           a byte which contains a syntax code, e.g., Sword.  */
+  syntaxspec,
+
+	/* Matches any character whose syntax is not that specified.  */
+  notsyntaxspec
+#endif /* emacs */
+} re_opcode_t;
+
+
+/* Common operations on the compiled pattern.  */
+
+/* Store NUMBER in two contiguous bytes starting at DESTINATION.  */
+
+#define STORE_NUMBER(destination, number)				\
+  do {									\
+    (destination)[0] = (number) & 0377;					\
+    (destination)[1] = (number) >> 8;					\
+  } while (0)
+
+/* Same as STORE_NUMBER, except increment DESTINATION to
+   the byte after where the number is stored.  Therefore, DESTINATION
+   must be an lvalue.  */
+
+#define STORE_NUMBER_AND_INCR(destination, number)			\
+  do {									\
+    STORE_NUMBER (destination, number);					\
+    (destination) += 2;							\
+  } while (0)
+
+/* Put into DESTINATION a number stored in two contiguous bytes starting
+   at SOURCE.  */
+
+#define EXTRACT_NUMBER(destination, source)				\
+  do {									\
+    (destination) = *(source) & 0377;					\
+    (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8;		\
+  } while (0)
+
+#ifdef DEBUG
+static void
+extract_number (dest, source)
+    int *dest;
+    unsigned char *source;
+{
+  int temp = SIGN_EXTEND_CHAR (*(source + 1)); 
+  *dest = *source & 0377;
+  *dest += temp << 8;
+}
+
+#ifndef EXTRACT_MACROS /* To debug the macros.  */
+#undef EXTRACT_NUMBER
+#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
+   SOURCE must be an lvalue.  */
+
+#define EXTRACT_NUMBER_AND_INCR(destination, source)			\
+  do {									\
+    EXTRACT_NUMBER (destination, source);				\
+    (source) += 2; 							\
+  } while (0)
+
+#ifdef DEBUG
+static void
+extract_number_and_incr (destination, source)
+    int *destination;
+    unsigned char **source;
+{ 
+  extract_number (destination, *source);
+  *source += 2;
+}
+
+#ifndef EXTRACT_MACROS
+#undef EXTRACT_NUMBER_AND_INCR
+#define EXTRACT_NUMBER_AND_INCR(dest, src) \
+  extract_number_and_incr (&dest, &src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+
+/* If DEBUG is defined, Regex prints many voluminous messages about what
+   it is doing (if the variable `debug' is nonzero).  If linked with the
+   main program in `iregex.c', you can enter patterns and strings
+   interactively.  And if linked with the main program in `main.c' and
+   the other test files, you can run the already-written tests.  */
+
+#ifdef DEBUG
+
+/* We use standard I/O for debugging.  */
+#include <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging.  */
+#include <assert.h>
+
+static int debug = 0;
+
+#define DEBUG_STATEMENT(e) e
+#define DEBUG_PRINT1(x) if (debug) printf (x)
+#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) 				\
+  if (debug) print_partial_compiled_pattern (s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)			\
+  if (debug) print_double_string (w, s1, sz1, s2, sz2)
+
+
+/* Print the fastmap in human-readable form.  */
+
+void
+print_fastmap (fastmap)
+    char *fastmap;
+{
+  unsigned was_a_range = 0;
+  unsigned i = 0;  
+  
+  while (i < (1 << BYTEWIDTH))
+    {
+      if (fastmap[i++])
+	{
+	  was_a_range = 0;
+          putchar (i - 1);
+          while (i < (1 << BYTEWIDTH)  &&  fastmap[i])
+            {
+              was_a_range = 1;
+              i++;
+            }
+	  if (was_a_range)
+            {
+              printf ("-");
+              putchar (i - 1);
+            }
+        }
+    }
+  putchar ('\n'); 
+}
+
+
+/* Print a compiled pattern string in human-readable form, starting at
+   the START pointer into it and ending just before the pointer END.  */
+
+void
+print_partial_compiled_pattern (start, end)
+    unsigned char *start;
+    unsigned char *end;
+{
+  int mcnt, mcnt2;
+  unsigned char *p = start;
+  unsigned char *pend = end;
+
+  if (start == NULL)
+    {
+      printf ("(null)\n");
+      return;
+    }
+    
+  /* Loop over pattern commands.  */
+  while (p < pend)
+    {
+      printf ("%d:\t", p - start);
+
+      switch ((re_opcode_t) *p++)
+	{
+        case no_op:
+          printf ("/no_op");
+          break;
+
+	case exactn:
+	  mcnt = *p++;
+          printf ("/exactn/%d", mcnt);
+          do
+	    {
+              putchar ('/');
+	      putchar (*p++);
+            }
+          while (--mcnt);
+          break;
+
+	case start_memory:
+          mcnt = *p++;
+          printf ("/start_memory/%d/%d", mcnt, *p++);
+          break;
+
+	case stop_memory:
+          mcnt = *p++;
+	  printf ("/stop_memory/%d/%d", mcnt, *p++);
+          break;
+
+	case duplicate:
+	  printf ("/duplicate/%d", *p++);
+	  break;
+
+	case anychar:
+	  printf ("/anychar");
+	  break;
+
+	case charset:
+        case charset_not:
+          {
+            register int c, last = -100;
+	    register int in_range = 0;
+
+	    printf ("/charset [%s",
+	            (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+            
+            assert (p + *p < pend);
+
+            for (c = 0; c < 256; c++)
+	      if (c / 8 < *p
+		  && (p[1 + (c/8)] & (1 << (c % 8))))
+		{
+		  /* Are we starting a range?  */
+		  if (last + 1 == c && ! in_range)
+		    {
+		      putchar ('-');
+		      in_range = 1;
+		    }
+		  /* Have we broken a range?  */
+		  else if (last + 1 != c && in_range)
+              {
+		      putchar (last);
+		      in_range = 0;
+		    }
+                
+		  if (! in_range)
+		    putchar (c);
+
+		  last = c;
+              }
+
+	    if (in_range)
+	      putchar (last);
+
+	    putchar (']');
+
+	    p += 1 + *p;
+	  }
+	  break;
+
+	case begline:
+	  printf ("/begline");
+          break;
+
+	case endline:
+          printf ("/endline");
+          break;
+
+	case on_failure_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/on_failure_jump to %d", p + mcnt - start);
+          break;
+
+	case on_failure_keep_string_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+          break;
+
+	case dummy_failure_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/dummy_failure_jump to %d", p + mcnt - start);
+          break;
+
+	case push_dummy_failure:
+          printf ("/push_dummy_failure");
+          break;
+          
+        case maybe_pop_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/maybe_pop_jump to %d", p + mcnt - start);
+	  break;
+
+        case pop_failure_jump:
+	  extract_number_and_incr (&mcnt, &p);
+  	  printf ("/pop_failure_jump to %d", p + mcnt - start);
+	  break;          
+          
+        case jump_past_alt:
+	  extract_number_and_incr (&mcnt, &p);
+  	  printf ("/jump_past_alt to %d", p + mcnt - start);
+	  break;          
+          
+        case jump:
+	  extract_number_and_incr (&mcnt, &p);
+  	  printf ("/jump to %d", p + mcnt - start);
+	  break;
+
+        case succeed_n: 
+          extract_number_and_incr (&mcnt, &p);
+          extract_number_and_incr (&mcnt2, &p);
+	  printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2);
+          break;
+        
+        case jump_n: 
+          extract_number_and_incr (&mcnt, &p);
+          extract_number_and_incr (&mcnt2, &p);
+	  printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2);
+          break;
+        
+        case set_number_at: 
+          extract_number_and_incr (&mcnt, &p);
+          extract_number_and_incr (&mcnt2, &p);
+	  printf ("/set_number_at location %d to %d", p + mcnt - start, mcnt2);
+          break;
+        
+        case wordbound:
+	  printf ("/wordbound");
+	  break;
+
+	case notwordbound:
+	  printf ("/notwordbound");
+          break;
+
+	case wordbeg:
+	  printf ("/wordbeg");
+	  break;
+          
+	case wordend:
+	  printf ("/wordend");
+          
+#ifdef emacs
+	case before_dot:
+	  printf ("/before_dot");
+          break;
+
+	case at_dot:
+	  printf ("/at_dot");
+          break;
+
+	case after_dot:
+	  printf ("/after_dot");
+          break;
+
+	case syntaxspec:
+          printf ("/syntaxspec");
+	  mcnt = *p++;
+	  printf ("/%d", mcnt);
+          break;
+	  
+	case notsyntaxspec:
+          printf ("/notsyntaxspec");
+	  mcnt = *p++;
+	  printf ("/%d", mcnt);
+	  break;
+#endif /* emacs */
+
+	case wordchar:
+	  printf ("/wordchar");
+          break;
+	  
+	case notwordchar:
+	  printf ("/notwordchar");
+          break;
+
+	case begbuf:
+	  printf ("/begbuf");
+          break;
+
+	case endbuf:
+	  printf ("/endbuf");
+          break;
+
+        default:
+          printf ("?%d", *(p-1));
+	}
+
+      putchar ('\n');
+    }
+
+  printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+void
+print_compiled_pattern (bufp)
+    struct re_pattern_buffer *bufp;
+{
+  unsigned char *buffer = bufp->buffer;
+
+  print_partial_compiled_pattern (buffer, buffer + bufp->used);
+  printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
+
+  if (bufp->fastmap_accurate && bufp->fastmap)
+    {
+      printf ("fastmap: ");
+      print_fastmap (bufp->fastmap);
+    }
+
+  printf ("re_nsub: %d\t", bufp->re_nsub);
+  printf ("regs_alloc: %d\t", bufp->regs_allocated);
+  printf ("can_be_null: %d\t", bufp->can_be_null);
+  printf ("newline_anchor: %d\n", bufp->newline_anchor);
+  printf ("no_sub: %d\t", bufp->no_sub);
+  printf ("not_bol: %d\t", bufp->not_bol);
+  printf ("not_eol: %d\t", bufp->not_eol);
+  printf ("syntax: %d\n", bufp->syntax);
+  /* Perhaps we should print the translate table?  */
+}
+
+
+void
+print_double_string (where, string1, size1, string2, size2)
+    const char *where;
+    const char *string1;
+    const char *string2;
+    int size1;
+    int size2;
+{
+  unsigned this_char;
+  
+  if (where == NULL)
+    printf ("(null)");
+  else
+    {
+      if (FIRST_STRING_P (where))
+        {
+          for (this_char = where - string1; this_char < size1; this_char++)
+            putchar (string1[this_char]);
+
+          where = string2;    
+        }
+
+      for (this_char = where - string2; this_char < size2; this_char++)
+        putchar (string2[this_char]);
+    }
+}
+
+#else /* not DEBUG */
+
+#undef assert
+#define assert(e)
+
+#define DEBUG_STATEMENT(e)
+#define DEBUG_PRINT1(x)
+#define DEBUG_PRINT2(x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+
+#endif /* not DEBUG */
+
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
+   also be assigned to arbitrarily: each pattern buffer stores its own
+   syntax, so it can be changed between regex compilations.  */
+/* This has no initializer because initialized variables in Emacs
+   become read-only after dumping.  */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation.  This provides
+   for compatibility for various utilities which historically have
+   different, incompatible syntaxes.
+
+   The argument SYNTAX is a bit mask comprised of the various bits
+   defined in regex.h.  We return the old syntax.  */
+
+reg_syntax_t
+re_set_syntax (syntax)
+    reg_syntax_t syntax;
+{
+  reg_syntax_t ret = re_syntax_options;
+  
+  re_syntax_options = syntax;
+  return ret;
+}
+
+
+/* This table gives an error message for each of the error codes listed
+   in regex.h.  Obviously the order here has to be same as there.
+   POSIX doesn't require that we do anything for REG_NOERROR,
+   but why not be nice?  */
+
+static const char *re_error_msgid[] =
+  { "Success",					/* REG_NOERROR */
+    "No match",					/* REG_NOMATCH */
+    "Invalid regular expression",		/* REG_BADPAT */
+    "Invalid collation character",		/* REG_ECOLLATE */
+    "Invalid character class name",		/* REG_ECTYPE */
+    "Trailing backslash",			/* REG_EESCAPE */
+    "Invalid back reference",			/* REG_ESUBREG */
+    "Unmatched [ or [^",			/* REG_EBRACK */
+    "Unmatched ( or \\(",			/* REG_EPAREN */
+    "Unmatched \\{",				/* REG_EBRACE */
+    "Invalid content of \\{\\}",		/* REG_BADBR */
+    "Invalid range end",			/* REG_ERANGE */
+    "Memory exhausted",				/* REG_ESPACE */
+    "Invalid preceding regular expression",	/* REG_BADRPT */
+    "Premature end of regular expression",	/* REG_EEND */
+    "Regular expression too big",		/* REG_ESIZE */
+    "Unmatched ) or \\)",			/* REG_ERPAREN */
+  };
+
+
+/* Avoiding alloca during matching, to placate r_alloc.  */
+
+/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
+   searching and matching functions should not call alloca.  On some
+   systems, alloca is implemented in terms of malloc, and if we're
+   using the relocating allocator routines, then malloc could cause a
+   relocation, which might (if the strings being searched are in the
+   ralloc heap) shift the data out from underneath the regexp
+   routines.
+
+   Here's another reason to avoid allocation: Emacs 
+   processes input from X in a signal handler; processing X input may
+   call malloc; if input arrives while a matching routine is calling
+   malloc, then we're scrod.  But Emacs can't just block input while
+   calling matching routines; then we don't notice interrupts when
+   they come in.  So, Emacs blocks input around all regexp calls
+   except the matching calls, which it leaves unprotected, in the
+   faith that they will not malloc.  */
+
+/* Normally, this is fine.  */
+#define MATCH_MAY_ALLOCATE
+
+/* When using GNU C, we are not REALLY using the C alloca, no matter
+   what sysfuncs.h may say.  So don't take precautions for it.  */
+#ifdef __GNUC__
+#undef C_ALLOCA
+#endif
+
+/* The match routines may not allocate if (1) they would do it with malloc
+   and (2) it's not safe for them to use malloc.
+   Note that if REL_ALLOC is defined, matching would not use malloc for the
+   failure stack, but we would still use it for the register vectors;
+   so REL_ALLOC should not affect this.  */
+#if (defined (C_ALLOCA) || defined (REGEX_MALLOC)) && defined (emacs)
+#undef MATCH_MAY_ALLOCATE
+#endif
+
+
+
+/* Failure stack declarations and macros; both re_compile_fastmap and
+   re_match_2 use a failure stack.  These have to be macros because of
+   REGEX_ALLOCATE_STACK.  */
+   
+
+/* Number of failure points for which to initially allocate space
+   when matching.  If this number is exceeded, we allocate more
+   space, so it is not a hard limit.  */
+#ifndef INIT_FAILURE_ALLOC
+#define INIT_FAILURE_ALLOC 5
+#endif
+
+/* Roughly the maximum number of failure points on the stack.  Would be
+   exactly that if always used MAX_FAILURE_SPACE each time we failed.
+   This is a variable only so users of regex can assign to it; we never
+   change it ourselves.  */
+#if defined (MATCH_MAY_ALLOCATE)
+int re_max_failures = 200000;
+#else
+int re_max_failures = 2000;
+#endif
+
+union fail_stack_elt
+{
+  unsigned char *pointer;
+  int integer;
+};
+
+typedef union fail_stack_elt fail_stack_elt_t;
+
+typedef struct
+{
+  fail_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;			/* Offset of next open position.  */
+} fail_stack_type;
+
+#define FAIL_STACK_EMPTY()     (fail_stack.avail == 0)
+#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
+#define FAIL_STACK_FULL()      (fail_stack.avail == fail_stack.size)
+
+
+/* Define macros to initialize and free the failure stack.
+   Do `return -2' if the alloc fails.  */
+
+#ifdef MATCH_MAY_ALLOCATE
+#define INIT_FAIL_STACK()						\
+  do {									\
+    fail_stack.stack = (fail_stack_elt_t *)				\
+      REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t));	\
+									\
+    if (fail_stack.stack == NULL)					\
+      return -2;							\
+									\
+    fail_stack.size = INIT_FAILURE_ALLOC;				\
+    fail_stack.avail = 0;						\
+  } while (0)
+
+#define RESET_FAIL_STACK()  REGEX_FREE_STACK (fail_stack.stack)
+#else
+#define INIT_FAIL_STACK()						\
+  do {									\
+    fail_stack.avail = 0;						\
+  } while (0)
+
+#define RESET_FAIL_STACK()
+#endif
+
+
+/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
+
+   Return 1 if succeeds, and 0 if either ran out of memory
+   allocating space for it or it was already too large.  
+   
+   REGEX_REALLOCATE_STACK requires `destination' be declared.   */
+
+#define DOUBLE_FAIL_STACK(fail_stack)					\
+  ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS		\
+   ? 0									\
+   : ((fail_stack).stack = (fail_stack_elt_t *)				\
+        REGEX_REALLOCATE_STACK ((fail_stack).stack, 			\
+          (fail_stack).size * sizeof (fail_stack_elt_t),		\
+          ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)),	\
+									\
+      (fail_stack).stack == NULL					\
+      ? 0								\
+      : ((fail_stack).size <<= 1, 					\
+         1)))
+
+
+/* Push pointer POINTER on FAIL_STACK. 
+   Return 1 if was able to do so and 0 if ran out of memory allocating
+   space to do so.  */
+#define PUSH_PATTERN_OP(POINTER, FAIL_STACK)				\
+  ((FAIL_STACK_FULL ()							\
+    && !DOUBLE_FAIL_STACK (FAIL_STACK))					\
+   ? 0									\
+   : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER,	\
+      1))
+
+/* Push a pointer value onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_POINTER(item)					\
+  fail_stack.stack[fail_stack.avail++].pointer = (unsigned char *) (item)
+
+/* This pushes an integer-valued item onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_INT(item)					\
+  fail_stack.stack[fail_stack.avail++].integer = (item)
+
+/* Push a fail_stack_elt_t value onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_ELT(item)					\
+  fail_stack.stack[fail_stack.avail++] =  (item)
+
+/* These three POP... operations complement the three PUSH... operations.
+   All assume that `fail_stack' is nonempty.  */
+#define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer
+#define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer
+#define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail]
+
+/* Used to omit pushing failure point id's when we're not debugging.  */
+#ifdef DEBUG
+#define DEBUG_PUSH PUSH_FAILURE_INT
+#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT ()
+#else
+#define DEBUG_PUSH(item)
+#define DEBUG_POP(item_addr)
+#endif
+
+
+/* Push the information about the state we will need
+   if we ever fail back to it.  
+   
+   Requires variables fail_stack, regstart, regend, reg_info, and
+   num_regs be declared.  DOUBLE_FAIL_STACK requires `destination' be
+   declared.
+   
+   Does `return FAILURE_CODE' if runs out of memory.  */
+
+#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code)	\
+  do {									\
+    char *destination;							\
+    /* Must be int, so when we don't save any registers, the arithmetic	\
+       of 0 + -1 isn't done as unsigned.  */				\
+    int this_reg;							\
+    									\
+    DEBUG_STATEMENT (failure_id++);					\
+    DEBUG_STATEMENT (nfailure_points_pushed++);				\
+    DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id);		\
+    DEBUG_PRINT2 ("  Before push, next avail: %d\n", (fail_stack).avail);\
+    DEBUG_PRINT2 ("                     size: %d\n", (fail_stack).size);\
+									\
+    DEBUG_PRINT2 ("  slots needed: %d\n", NUM_FAILURE_ITEMS);		\
+    DEBUG_PRINT2 ("     available: %d\n", REMAINING_AVAIL_SLOTS);	\
+									\
+    /* Ensure we have enough space allocated for what we will push.  */	\
+    while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS)			\
+      {									\
+        if (!DOUBLE_FAIL_STACK (fail_stack))				\
+          return failure_code;						\
+									\
+        DEBUG_PRINT2 ("\n  Doubled stack; size now: %d\n",		\
+		       (fail_stack).size);				\
+        DEBUG_PRINT2 ("  slots available: %d\n", REMAINING_AVAIL_SLOTS);\
+      }									\
+									\
+    /* Push the info, starting with the registers.  */			\
+    DEBUG_PRINT1 ("\n");						\
+									\
+    for (this_reg = lowest_active_reg; this_reg <= highest_active_reg;	\
+         this_reg++)							\
+      {									\
+	DEBUG_PRINT2 ("  Pushing reg: %d\n", this_reg);			\
+        DEBUG_STATEMENT (num_regs_pushed++);				\
+									\
+	DEBUG_PRINT2 ("    start: 0x%x\n", regstart[this_reg]);		\
+        PUSH_FAILURE_POINTER (regstart[this_reg]);			\
+                                                                        \
+	DEBUG_PRINT2 ("    end: 0x%x\n", regend[this_reg]);		\
+        PUSH_FAILURE_POINTER (regend[this_reg]);			\
+									\
+	DEBUG_PRINT2 ("    info: 0x%x\n      ", reg_info[this_reg]);	\
+        DEBUG_PRINT2 (" match_null=%d",					\
+                      REG_MATCH_NULL_STRING_P (reg_info[this_reg]));	\
+        DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg]));	\
+        DEBUG_PRINT2 (" matched_something=%d",				\
+                      MATCHED_SOMETHING (reg_info[this_reg]));		\
+        DEBUG_PRINT2 (" ever_matched=%d",				\
+                      EVER_MATCHED_SOMETHING (reg_info[this_reg]));	\
+	DEBUG_PRINT1 ("\n");						\
+        PUSH_FAILURE_ELT (reg_info[this_reg].word);			\
+      }									\
+									\
+    DEBUG_PRINT2 ("  Pushing  low active reg: %d\n", lowest_active_reg);\
+    PUSH_FAILURE_INT (lowest_active_reg);				\
+									\
+    DEBUG_PRINT2 ("  Pushing high active reg: %d\n", highest_active_reg);\
+    PUSH_FAILURE_INT (highest_active_reg);				\
+									\
+    DEBUG_PRINT2 ("  Pushing pattern 0x%x: ", pattern_place);		\
+    DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend);		\
+    PUSH_FAILURE_POINTER (pattern_place);				\
+									\
+    DEBUG_PRINT2 ("  Pushing string 0x%x: `", string_place);		\
+    DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2,   \
+				 size2);				\
+    DEBUG_PRINT1 ("'\n");						\
+    PUSH_FAILURE_POINTER (string_place);				\
+									\
+    DEBUG_PRINT2 ("  Pushing failure id: %u\n", failure_id);		\
+    DEBUG_PUSH (failure_id);						\
+  } while (0)
+
+/* This is the number of items that are pushed and popped on the stack
+   for each register.  */
+#define NUM_REG_ITEMS  3
+
+/* Individual items aside from the registers.  */
+#ifdef DEBUG
+#define NUM_NONREG_ITEMS 5 /* Includes failure point id.  */
+#else
+#define NUM_NONREG_ITEMS 4
+#endif
+
+/* We push at most this many items on the stack.  */
+#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+
+/* We actually push this many items.  */
+#define NUM_FAILURE_ITEMS						\
+  ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS 	\
+    + NUM_NONREG_ITEMS)
+
+/* How many items can still be added to the stack without overflowing it.  */
+#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+
+
+/* Pops what PUSH_FAIL_STACK pushes.
+
+   We restore into the parameters, all of which should be lvalues:
+     STR -- the saved data position.
+     PAT -- the saved pattern position.
+     LOW_REG, HIGH_REG -- the highest and lowest active registers.
+     REGSTART, REGEND -- arrays of string positions.
+     REG_INFO -- array of information about each subexpression.
+   
+   Also assumes the variables `fail_stack' and (if debugging), `bufp',
+   `pend', `string1', `size1', `string2', and `size2'.  */
+
+#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
+{									\
+  DEBUG_STATEMENT (fail_stack_elt_t failure_id;)			\
+  int this_reg;								\
+  const unsigned char *string_temp;					\
+									\
+  assert (!FAIL_STACK_EMPTY ());					\
+									\
+  /* Remove failure points and point to how many regs pushed.  */	\
+  DEBUG_PRINT1 ("POP_FAILURE_POINT:\n");				\
+  DEBUG_PRINT2 ("  Before pop, next avail: %d\n", fail_stack.avail);	\
+  DEBUG_PRINT2 ("                    size: %d\n", fail_stack.size);	\
+									\
+  assert (fail_stack.avail >= NUM_NONREG_ITEMS);			\
+									\
+  DEBUG_POP (&failure_id);						\
+  DEBUG_PRINT2 ("  Popping failure id: %u\n", failure_id);		\
+									\
+  /* If the saved string location is NULL, it came from an		\
+     on_failure_keep_string_jump opcode, and we want to throw away the	\
+     saved NULL, thus retaining our current position in the string.  */	\
+  string_temp = POP_FAILURE_POINTER ();					\
+  if (string_temp != NULL)						\
+    str = (const char *) string_temp;					\
+									\
+  DEBUG_PRINT2 ("  Popping string 0x%x: `", str);			\
+  DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2);	\
+  DEBUG_PRINT1 ("'\n");							\
+									\
+  pat = (unsigned char *) POP_FAILURE_POINTER ();			\
+  DEBUG_PRINT2 ("  Popping pattern 0x%x: ", pat);			\
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend);			\
+									\
+  /* Restore register info.  */						\
+  high_reg = (unsigned) POP_FAILURE_INT ();				\
+  DEBUG_PRINT2 ("  Popping high active reg: %d\n", high_reg);		\
+									\
+  low_reg = (unsigned) POP_FAILURE_INT ();				\
+  DEBUG_PRINT2 ("  Popping  low active reg: %d\n", low_reg);		\
+									\
+  for (this_reg = high_reg; this_reg >= low_reg; this_reg--)		\
+    {									\
+      DEBUG_PRINT2 ("    Popping reg: %d\n", this_reg);			\
+									\
+      reg_info[this_reg].word = POP_FAILURE_ELT ();			\
+      DEBUG_PRINT2 ("      info: 0x%x\n", reg_info[this_reg]);		\
+									\
+      regend[this_reg] = (const char *) POP_FAILURE_POINTER ();		\
+      DEBUG_PRINT2 ("      end: 0x%x\n", regend[this_reg]);		\
+									\
+      regstart[this_reg] = (const char *) POP_FAILURE_POINTER ();	\
+      DEBUG_PRINT2 ("      start: 0x%x\n", regstart[this_reg]);		\
+    }									\
+									\
+  set_regs_matched_done = 0;						\
+  DEBUG_STATEMENT (nfailure_points_popped++);				\
+} /* POP_FAILURE_POINT */
+
+
+
+
+/* Structure for per-register (a.k.a. per-group) information.
+   Other register information, such as the
+   starting and ending positions (which are addresses), and the list of
+   inner groups (which is a bits list) are maintained in separate
+   variables.  
+   
+   We are making a (strictly speaking) nonportable assumption here: that
+   the compiler will pack our bit fields into something that fits into
+   the type of `word', i.e., is something that fits into one item on the
+   failure stack.  */
+
+typedef union
+{
+  fail_stack_elt_t word;
+  struct
+  {
+      /* This field is one if this group can match the empty string,
+         zero if not.  If not yet determined,  `MATCH_NULL_UNSET_VALUE'.  */
+#define MATCH_NULL_UNSET_VALUE 3
+    unsigned match_null_string_p : 2;
+    unsigned is_active : 1;
+    unsigned matched_something : 1;
+    unsigned ever_matched_something : 1;
+  } bits;
+} register_info_type;
+
+#define REG_MATCH_NULL_STRING_P(R)  ((R).bits.match_null_string_p)
+#define IS_ACTIVE(R)  ((R).bits.is_active)
+#define MATCHED_SOMETHING(R)  ((R).bits.matched_something)
+#define EVER_MATCHED_SOMETHING(R)  ((R).bits.ever_matched_something)
+
+
+/* Call this when have matched a real character; it sets `matched' flags
+   for the subexpressions which we are currently inside.  Also records
+   that those subexprs have matched.  */
+#define SET_REGS_MATCHED()						\
+  do									\
+    {									\
+      if (!set_regs_matched_done)					\
+	{								\
+	  unsigned r;							\
+	  set_regs_matched_done = 1;					\
+	  for (r = lowest_active_reg; r <= highest_active_reg; r++)	\
+	    {								\
+	      MATCHED_SOMETHING (reg_info[r])				\
+		= EVER_MATCHED_SOMETHING (reg_info[r])			\
+		= 1;							\
+	    }								\
+	}								\
+    }									\
+  while (0)
+
+/* Registers are set to a sentinel when they haven't yet matched.  */
+static char reg_unset_dummy;
+#define REG_UNSET_VALUE (&reg_unset_dummy)
+#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
+
+
+/* Subroutine declarations and macros for regex_compile.  */
+
+static void store_op1 (), store_op2 ();
+static void insert_op1 (), insert_op2 ();
+static boolean at_begline_loc_p (), at_endline_loc_p ();
+static boolean group_in_compile_stack ();
+static reg_errcode_t compile_range ();
+
+/* Fetch the next character in the uncompiled pattern---translating it 
+   if necessary.  Also cast from a signed character in the constant
+   string passed to us by the user to an unsigned char that we can use
+   as an array index (in, e.g., `translate').  */
+#define PATFETCH(c)							\
+  do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++;						\
+    if (translate) c = translate[c]; 					\
+  } while (0)
+
+/* Fetch the next character in the uncompiled pattern, with no
+   translation.  */
+#define PATFETCH_RAW(c)							\
+  do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++; 						\
+  } while (0)
+
+/* Go backwards one character in the pattern.  */
+#define PATUNFETCH p--
+
+
+/* If `translate' is non-null, return translate[D], else just D.  We
+   cast the subscript to translate because some data is declared as
+   `char *', to avoid warnings when a string constant is passed.  But
+   when we use a character as a subscript we must make it unsigned.  */
+#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
+
+
+/* Macros for outputting the compiled pattern into `buffer'.  */
+
+/* If the buffer isn't allocated when it comes in, use this.  */
+#define INIT_BUF_SIZE  32
+
+/* Make sure we have at least N more bytes of space in buffer.  */
+#define GET_BUFFER_SPACE(n)						\
+    while (b - bufp->buffer + (n) > bufp->allocated)			\
+      EXTEND_BUFFER ()
+
+/* Make sure we have one more byte of buffer space and then add C to it.  */
+#define BUF_PUSH(c)							\
+  do {									\
+    GET_BUFFER_SPACE (1);						\
+    *b++ = (unsigned char) (c);						\
+  } while (0)
+
+
+/* Ensure we have two more bytes of buffer space and then append C1 and C2.  */
+#define BUF_PUSH_2(c1, c2)						\
+  do {									\
+    GET_BUFFER_SPACE (2);						\
+    *b++ = (unsigned char) (c1);					\
+    *b++ = (unsigned char) (c2);					\
+  } while (0)
+
+
+/* As with BUF_PUSH_2, except for three bytes.  */
+#define BUF_PUSH_3(c1, c2, c3)						\
+  do {									\
+    GET_BUFFER_SPACE (3);						\
+    *b++ = (unsigned char) (c1);					\
+    *b++ = (unsigned char) (c2);					\
+    *b++ = (unsigned char) (c3);					\
+  } while (0)
+
+
+/* Store a jump with opcode OP at LOC to location TO.  We store a
+   relative address offset by the three bytes the jump itself occupies.  */
+#define STORE_JUMP(op, loc, to) \
+  store_op1 (op, loc, (to) - (loc) - 3)
+
+/* Likewise, for a two-argument jump.  */
+#define STORE_JUMP2(op, loc, to, arg) \
+  store_op2 (op, loc, (to) - (loc) - 3, arg)
+
+/* Like `STORE_JUMP', but for inserting.  Assume `b' is the buffer end.  */
+#define INSERT_JUMP(op, loc, to) \
+  insert_op1 (op, loc, (to) - (loc) - 3, b)
+
+/* Like `STORE_JUMP2', but for inserting.  Assume `b' is the buffer end.  */
+#define INSERT_JUMP2(op, loc, to, arg) \
+  insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
+
+
+/* This is not an arbitrary limit: the arguments which represent offsets
+   into the pattern are two bytes long.  So if 2^16 bytes turns out to
+   be too small, many things would have to change.  */
+#define MAX_BUF_SIZE (1L << 16)
+
+
+/* Extend the buffer by twice its current size via realloc and
+   reset the pointers that pointed into the old block to point to the
+   correct places in the new one.  If extending the buffer results in it
+   being larger than MAX_BUF_SIZE, then flag memory exhausted.  */
+#define EXTEND_BUFFER()							\
+  do { 									\
+    unsigned char *old_buffer = bufp->buffer;				\
+    if (bufp->allocated == MAX_BUF_SIZE) 				\
+      return REG_ESIZE;							\
+    bufp->allocated <<= 1;						\
+    if (bufp->allocated > MAX_BUF_SIZE)					\
+      bufp->allocated = MAX_BUF_SIZE; 					\
+    bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
+    if (bufp->buffer == NULL)						\
+      return REG_ESPACE;						\
+    /* If the buffer moved, move all the pointers into it.  */		\
+    if (old_buffer != bufp->buffer)					\
+      {									\
+        b = (b - old_buffer) + bufp->buffer;				\
+        begalt = (begalt - old_buffer) + bufp->buffer;			\
+        if (fixup_alt_jump)						\
+          fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
+        if (laststart)							\
+          laststart = (laststart - old_buffer) + bufp->buffer;		\
+        if (pending_exact)						\
+          pending_exact = (pending_exact - old_buffer) + bufp->buffer;	\
+      }									\
+  } while (0)
+
+
+/* Since we have one byte reserved for the register number argument to
+   {start,stop}_memory, the maximum number of groups we can report
+   things about is what fits in that byte.  */
+#define MAX_REGNUM 255
+
+/* But patterns can have more than `MAX_REGNUM' registers.  We just
+   ignore the excess.  */
+typedef unsigned regnum_t;
+
+
+/* Macros for the compile stack.  */
+
+/* Since offsets can go either forwards or backwards, this type needs to
+   be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.  */
+typedef int pattern_offset_t;
+
+typedef struct
+{
+  pattern_offset_t begalt_offset;
+  pattern_offset_t fixup_alt_jump;
+  pattern_offset_t inner_group_offset;
+  pattern_offset_t laststart_offset;  
+  regnum_t regnum;
+} compile_stack_elt_t;
+
+
+typedef struct
+{
+  compile_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;			/* Offset of next open position.  */
+} compile_stack_type;
+
+
+#define INIT_COMPILE_STACK_SIZE 32
+
+#define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
+
+/* The next available element.  */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+
+/* Set the bit for character C in a list.  */
+#define SET_LIST_BIT(c)                               \
+  (b[((unsigned char) (c)) / BYTEWIDTH]               \
+   |= 1 << (((unsigned char) c) % BYTEWIDTH))
+
+
+/* Get the next unsigned number in the uncompiled pattern.  */
+#define GET_UNSIGNED_NUMBER(num) 					\
+  { if (p != pend)							\
+     {									\
+       PATFETCH (c); 							\
+       while (ISDIGIT (c)) 						\
+         { 								\
+           if (num < 0)							\
+              num = 0;							\
+           num = num * 10 + c - '0'; 					\
+           if (p == pend) 						\
+              break; 							\
+           PATFETCH (c);						\
+         } 								\
+       } 								\
+    }		
+
+#define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+#define IS_CHAR_CLASS(string)						\
+   (STREQ (string, "alpha") || STREQ (string, "upper")			\
+    || STREQ (string, "lower") || STREQ (string, "digit")		\
+    || STREQ (string, "alnum") || STREQ (string, "xdigit")		\
+    || STREQ (string, "space") || STREQ (string, "print")		\
+    || STREQ (string, "punct") || STREQ (string, "graph")		\
+    || STREQ (string, "cntrl") || STREQ (string, "blank"))
+
+
+#ifndef MATCH_MAY_ALLOCATE
+
+/* If we cannot allocate large objects within re_match_2_internal,
+   we make the fail stack and register vectors global.
+   The fail stack, we grow to the maximum size when a regexp
+   is compiled.
+   The register vectors, we adjust in size each time we
+   compile a regexp, according to the number of registers it needs.  */
+
+static fail_stack_type fail_stack;
+
+/* Size with which the following vectors are currently allocated.
+   That is so we can make them bigger as needed,
+   but never make them smaller.  */
+static int regs_allocated_size;
+
+static const char **     regstart, **     regend;
+static const char ** old_regstart, ** old_regend;
+static const char **best_regstart, **best_regend;
+static register_info_type *reg_info; 
+static const char **reg_dummy;
+static register_info_type *reg_info_dummy;
+
+/* Make the register vectors big enough for NUM_REGS registers,
+   but don't make them smaller.  */
+
+static
+regex_grow_registers (num_regs)
+     int num_regs;
+{
+  if (num_regs > regs_allocated_size)
+    {
+      RETALLOC_IF (regstart,	 num_regs, const char *);
+      RETALLOC_IF (regend,	 num_regs, const char *);
+      RETALLOC_IF (old_regstart, num_regs, const char *);
+      RETALLOC_IF (old_regend,	 num_regs, const char *);
+      RETALLOC_IF (best_regstart, num_regs, const char *);
+      RETALLOC_IF (best_regend,	 num_regs, const char *);
+      RETALLOC_IF (reg_info,	 num_regs, register_info_type);
+      RETALLOC_IF (reg_dummy,	 num_regs, const char *);
+      RETALLOC_IF (reg_info_dummy, num_regs, register_info_type);
+
+      regs_allocated_size = num_regs;
+    }
+}
+
+#endif /* not MATCH_MAY_ALLOCATE */
+
+
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+   Returns one of error codes defined in `regex.h', or zero for success.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate'
+   fields are set in BUFP on entry.
+
+   If it succeeds, results are put in BUFP (if it returns an error, the
+   contents of BUFP are undefined):
+     `buffer' is the compiled pattern;
+     `syntax' is set to SYNTAX;
+     `used' is set to the length of the compiled pattern;
+     `fastmap_accurate' is zero;
+     `re_nsub' is the number of subexpressions in PATTERN;
+     `not_bol' and `not_eol' are zero;
+   
+   The `fastmap' and `newline_anchor' fields are neither
+   examined nor set.  */
+
+/* Return, freeing storage we allocated.  */
+#define FREE_STACK_RETURN(value)		\
+  return (free (compile_stack.stack), value)
+
+static reg_errcode_t
+regex_compile (pattern, size, syntax, bufp)
+     const char *pattern;
+     int size;
+     reg_syntax_t syntax;
+     struct re_pattern_buffer *bufp;
+{
+  /* We fetch characters from PATTERN here.  Even though PATTERN is
+     `char *' (i.e., signed), we declare these variables as unsigned, so
+     they can be reliably used as array indices.  */
+  register unsigned char c, c1;
+  
+  /* A random temporary spot in PATTERN.  */
+  const char *p1;
+
+  /* Points to the end of the buffer, where we should append.  */
+  register unsigned char *b;
+  
+  /* Keeps track of unclosed groups.  */
+  compile_stack_type compile_stack;
+
+  /* Points to the current (ending) position in the pattern.  */
+  const char *p = pattern;
+  const char *pend = pattern + size;
+  
+  /* How to translate the characters in the pattern.  */
+  char *translate = bufp->translate;
+
+  /* Address of the count-byte of the most recently inserted `exactn'
+     command.  This makes it possible to tell if a new exact-match
+     character can be added to that command or if the character requires
+     a new `exactn' command.  */
+  unsigned char *pending_exact = 0;
+
+  /* Address of start of the most recently finished expression.
+     This tells, e.g., postfix * where to find the start of its
+     operand.  Reset at the beginning of groups and alternatives.  */
+  unsigned char *laststart = 0;
+
+  /* Address of beginning of regexp, or inside of last group.  */
+  unsigned char *begalt;
+
+  /* Place in the uncompiled pattern (i.e., the {) to
+     which to go back if the interval is invalid.  */
+  const char *beg_interval;
+                
+  /* Address of the place where a forward jump should go to the end of
+     the containing expression.  Each alternative of an `or' -- except the
+     last -- ends with a forward jump of this sort.  */
+  unsigned char *fixup_alt_jump = 0;
+
+  /* Counts open-groups as they are encountered.  Remembered for the
+     matching close-group on the compile stack, so the same register
+     number is put in the stop_memory as the start_memory.  */
+  regnum_t regnum = 0;
+
+#ifdef DEBUG
+  DEBUG_PRINT1 ("\nCompiling pattern: ");
+  if (debug)
+    {
+      unsigned debug_count;
+      
+      for (debug_count = 0; debug_count < size; debug_count++)
+        putchar (pattern[debug_count]);
+      putchar ('\n');
+    }
+#endif /* DEBUG */
+
+  /* Initialize the compile stack.  */
+  compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
+  if (compile_stack.stack == NULL)
+    return REG_ESPACE;
+
+  compile_stack.size = INIT_COMPILE_STACK_SIZE;
+  compile_stack.avail = 0;
+
+  /* Initialize the pattern buffer.  */
+  bufp->syntax = syntax;
+  bufp->fastmap_accurate = 0;
+  bufp->not_bol = bufp->not_eol = 0;
+
+  /* Set `used' to zero, so that if we return an error, the pattern
+     printer (for debugging) will think there's no pattern.  We reset it
+     at the end.  */
+  bufp->used = 0;
+  
+  /* Always count groups, whether or not bufp->no_sub is set.  */
+  bufp->re_nsub = 0;				
+
+#if !defined (emacs) && !defined (SYNTAX_TABLE)
+  /* Initialize the syntax table.  */
+   init_syntax_once ();
+#endif
+
+  if (bufp->allocated == 0)
+    {
+      if (bufp->buffer)
+	{ /* If zero allocated, but buffer is non-null, try to realloc
+             enough space.  This loses if buffer's address is bogus, but
+             that is the user's responsibility.  */
+          RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
+        }
+      else
+        { /* Caller did not allocate a buffer.  Do it for them.  */
+          bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
+        }
+      if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE);
+
+      bufp->allocated = INIT_BUF_SIZE;
+    }
+
+  begalt = b = bufp->buffer;
+
+  /* Loop through the uncompiled pattern until we're at the end.  */
+  while (p != pend)
+    {
+      PATFETCH (c);
+
+      switch (c)
+        {
+        case '^':
+          {
+            if (   /* If at start of pattern, it's an operator.  */
+                   p == pattern + 1
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's come before.  */
+                || at_begline_loc_p (pattern, p, syntax))
+              BUF_PUSH (begline);
+            else
+              goto normal_char;
+          }
+          break;
+
+
+        case '$':
+          {
+            if (   /* If at end of pattern, it's an operator.  */
+                   p == pend 
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's next.  */
+                || at_endline_loc_p (p, pend, syntax))
+               BUF_PUSH (endline);
+             else
+               goto normal_char;
+           }
+           break;
+
+
+	case '+':
+        case '?':
+          if ((syntax & RE_BK_PLUS_QM)
+              || (syntax & RE_LIMITED_OPS))
+            goto normal_char;
+        handle_plus:
+        case '*':
+          /* If there is no previous pattern... */
+          if (!laststart)
+            {
+              if (syntax & RE_CONTEXT_INVALID_OPS)
+                FREE_STACK_RETURN (REG_BADRPT);
+              else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+                goto normal_char;
+            }
+
+          {
+            /* Are we optimizing this jump?  */
+            boolean keep_string_p = false;
+            
+            /* 1 means zero (many) matches is allowed.  */
+            char zero_times_ok = 0, many_times_ok = 0;
+
+            /* If there is a sequence of repetition chars, collapse it
+               down to just one (the right one).  We can't combine
+               interval operators with these because of, e.g., `a{2}*',
+               which should only match an even number of `a's.  */
+
+            for (;;)
+              {
+                zero_times_ok |= c != '+';
+                many_times_ok |= c != '?';
+
+                if (p == pend)
+                  break;
+
+                PATFETCH (c);
+
+                if (c == '*'
+                    || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+                  ;
+
+                else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+                    if (!(c1 == '+' || c1 == '?'))
+                      {
+                        PATUNFETCH;
+                        PATUNFETCH;
+                        break;
+                      }
+
+                    c = c1;
+                  }
+                else
+                  {
+                    PATUNFETCH;
+                    break;
+                  }
+
+                /* If we get here, we found another repeat character.  */
+               }
+
+            /* Star, etc. applied to an empty pattern is equivalent
+               to an empty pattern.  */
+            if (!laststart)  
+              break;
+
+            /* Now we know whether or not zero matches is allowed
+               and also whether or not two or more matches is allowed.  */
+            if (many_times_ok)
+              { /* More than one repetition is allowed, so put in at the
+                   end a backward relative jump from `b' to before the next
+                   jump we're going to put in below (which jumps from
+                   laststart to after this jump).  
+
+                   But if we are at the `*' in the exact sequence `.*\n',
+                   insert an unconditional jump backwards to the .,
+                   instead of the beginning of the loop.  This way we only
+                   push a failure point once, instead of every time
+                   through the loop.  */
+                assert (p - 1 > pattern);
+
+                /* Allocate the space for the jump.  */
+                GET_BUFFER_SPACE (3);
+
+                /* We know we are not at the first character of the pattern,
+                   because laststart was nonzero.  And we've already
+                   incremented `p', by the way, to be the character after
+                   the `*'.  Do we have to do something analogous here
+                   for null bytes, because of RE_DOT_NOT_NULL?  */
+                if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
+		    && zero_times_ok
+                    && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
+                    && !(syntax & RE_DOT_NEWLINE))
+                  { /* We have .*\n.  */
+                    STORE_JUMP (jump, b, laststart);
+                    keep_string_p = true;
+                  }
+                else
+                  /* Anything else.  */
+                  STORE_JUMP (maybe_pop_jump, b, laststart - 3);
+
+                /* We've added more stuff to the buffer.  */
+                b += 3;
+              }
+
+            /* On failure, jump from laststart to b + 3, which will be the
+               end of the buffer after this jump is inserted.  */
+            GET_BUFFER_SPACE (3);
+            INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
+                                       : on_failure_jump,
+                         laststart, b + 3);
+            pending_exact = 0;
+            b += 3;
+
+            if (!zero_times_ok)
+              {
+                /* At least one repetition is required, so insert a
+                   `dummy_failure_jump' before the initial
+                   `on_failure_jump' instruction of the loop. This
+                   effects a skip over that instruction the first time
+                   we hit that loop.  */
+                GET_BUFFER_SPACE (3);
+                INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
+                b += 3;
+              }
+            }
+	  break;
+
+
+	case '.':
+          laststart = b;
+          BUF_PUSH (anychar);
+          break;
+
+
+        case '[':
+          {
+            boolean had_char_class = false;
+
+            if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+            /* Ensure that we have enough space to push a charset: the
+               opcode, the length count, and the bitset; 34 bytes in all.  */
+	    GET_BUFFER_SPACE (34);
+
+            laststart = b;
+
+            /* We test `*p == '^' twice, instead of using an if
+               statement, so we only need one BUF_PUSH.  */
+            BUF_PUSH (*p == '^' ? charset_not : charset); 
+            if (*p == '^')
+              p++;
+
+            /* Remember the first position in the bracket expression.  */
+            p1 = p;
+
+            /* Push the number of bytes in the bitmap.  */
+            BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+            /* Clear the whole map.  */
+            bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+            /* charset_not matches newline according to a syntax bit.  */
+            if ((re_opcode_t) b[-2] == charset_not
+                && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+              SET_LIST_BIT ('\n');
+
+            /* Read in characters and ranges, setting map bits.  */
+            for (;;)
+              {
+                if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                PATFETCH (c);
+
+                /* \ might escape characters inside [...] and [^...].  */
+                if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+                    SET_LIST_BIT (c1);
+                    continue;
+                  }
+
+                /* Could be the end of the bracket expression.  If it's
+                   not (i.e., when the bracket expression is `[]' so
+                   far), the ']' character bit gets set way below.  */
+                if (c == ']' && p != p1 + 1)
+                  break;
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character class.  */
+                if (had_char_class && c == '-' && *p != ']')
+                  FREE_STACK_RETURN (REG_ERANGE);
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character: if this is a hyphen not at the
+                   beginning or the end of a list, then it's the range
+                   operator.  */
+                if (c == '-' 
+                    && !(p - 2 >= pattern && p[-2] == '[') 
+                    && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+                    && *p != ']')
+                  {
+                    reg_errcode_t ret
+                      = compile_range (&p, pend, translate, syntax, b);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+                  }
+
+                else if (p[0] == '-' && p[1] != ']')
+                  { /* This handles ranges made up of characters only.  */
+                    reg_errcode_t ret;
+
+		    /* Move past the `-'.  */
+                    PATFETCH (c1);
+                    
+                    ret = compile_range (&p, pend, translate, syntax, b);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+                  }
+
+                /* See if we're at the beginning of a possible character
+                   class.  */
+
+                else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+                  { /* Leave room for the null.  */
+                    char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+                    PATFETCH (c);
+                    c1 = 0;
+
+                    /* If pattern is `[[:'.  */
+                    if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                    for (;;)
+                      {
+                        PATFETCH (c);
+                        if (c == ':' || c == ']' || p == pend
+                            || c1 == CHAR_CLASS_MAX_LENGTH)
+                          break;
+                        str[c1++] = c;
+                      }
+                    str[c1] = '\0';
+
+                    /* If isn't a word bracketed by `[:' and:`]':
+                       undo the ending character, the letters, and leave 
+                       the leading `:' and `[' (but set bits for them).  */
+                    if (c == ':' && *p == ']')
+                      {
+                        int ch;
+                        boolean is_alnum = STREQ (str, "alnum");
+                        boolean is_alpha = STREQ (str, "alpha");
+                        boolean is_blank = STREQ (str, "blank");
+                        boolean is_cntrl = STREQ (str, "cntrl");
+                        boolean is_digit = STREQ (str, "digit");
+                        boolean is_graph = STREQ (str, "graph");
+                        boolean is_lower = STREQ (str, "lower");
+                        boolean is_print = STREQ (str, "print");
+                        boolean is_punct = STREQ (str, "punct");
+                        boolean is_space = STREQ (str, "space");
+                        boolean is_upper = STREQ (str, "upper");
+                        boolean is_xdigit = STREQ (str, "xdigit");
+                        
+                        if (!IS_CHAR_CLASS (str))
+			  FREE_STACK_RETURN (REG_ECTYPE);
+
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);					
+
+                        if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                        for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+                          {
+			    /* This was split into 3 if's to
+			       avoid an arbitrary limit in some compiler.  */
+                            if (   (is_alnum  && ISALNUM (ch))
+                                || (is_alpha  && ISALPHA (ch))
+                                || (is_blank  && ISBLANK (ch))
+                                || (is_cntrl  && ISCNTRL (ch)))
+			      SET_LIST_BIT (ch);
+			    if (   (is_digit  && ISDIGIT (ch))
+                                || (is_graph  && ISGRAPH (ch))
+                                || (is_lower  && ISLOWER (ch))
+                                || (is_print  && ISPRINT (ch)))
+			      SET_LIST_BIT (ch);
+			    if (   (is_punct  && ISPUNCT (ch))
+                                || (is_space  && ISSPACE (ch))
+                                || (is_upper  && ISUPPER (ch))
+                                || (is_xdigit && ISXDIGIT (ch)))
+			      SET_LIST_BIT (ch);
+                          }
+                        had_char_class = true;
+                      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)    
+                          PATUNFETCH;
+                        SET_LIST_BIT ('[');
+                        SET_LIST_BIT (':');
+                        had_char_class = false;
+                      }
+                  }
+                else
+                  {
+                    had_char_class = false;
+                    SET_LIST_BIT (c);
+                  }
+              }
+
+            /* Discard any (non)matching list bytes that are all 0 at the
+               end of the map.  Decrease the map-length byte too.  */
+            while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) 
+              b[-1]--; 
+            b += b[-1];
+          }
+          break;
+
+
+	case '(':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_open;
+          else
+            goto normal_char;
+
+
+        case ')':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_close;
+          else
+            goto normal_char;
+
+
+        case '\n':
+          if (syntax & RE_NEWLINE_ALT)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+	case '|':
+          if (syntax & RE_NO_BK_VBAR)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+        case '{':
+           if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
+             goto handle_interval;
+           else
+             goto normal_char;
+
+
+        case '\\':
+          if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+          /* Do not translate the character after the \, so that we can
+             distinguish, e.g., \B from \b, even if we normally would
+             translate, e.g., B to b.  */
+          PATFETCH_RAW (c);
+
+          switch (c)
+            {
+            case '(':
+              if (syntax & RE_NO_BK_PARENS)
+                goto normal_backslash;
+
+            handle_open:
+              bufp->re_nsub++;
+              regnum++;
+
+              if (COMPILE_STACK_FULL)
+                { 
+                  RETALLOC (compile_stack.stack, compile_stack.size << 1,
+                            compile_stack_elt_t);
+                  if (compile_stack.stack == NULL) return REG_ESPACE;
+
+                  compile_stack.size <<= 1;
+                }
+
+              /* These are the values to restore when we hit end of this
+                 group.  They are all relative offsets, so that if the
+                 whole pattern moves because of realloc, they will still
+                 be valid.  */
+              COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
+              COMPILE_STACK_TOP.fixup_alt_jump 
+                = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
+              COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
+              COMPILE_STACK_TOP.regnum = regnum;
+
+              /* We will eventually replace the 0 with the number of
+                 groups inner to this one.  But do not push a
+                 start_memory for groups beyond the last one we can
+                 represent in the compiled pattern.  */
+              if (regnum <= MAX_REGNUM)
+                {
+                  COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
+                  BUF_PUSH_3 (start_memory, regnum, 0);
+                }
+                
+              compile_stack.avail++;
+
+              fixup_alt_jump = 0;
+              laststart = 0;
+              begalt = b;
+	      /* If we've reached MAX_REGNUM groups, then this open
+		 won't actually generate any code, so we'll have to
+		 clear pending_exact explicitly.  */
+	      pending_exact = 0;
+              break;
+
+
+            case ')':
+              if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+              if (COMPILE_STACK_EMPTY)
+                if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+                  goto normal_backslash;
+                else
+                  FREE_STACK_RETURN (REG_ERPAREN);
+
+            handle_close:
+              if (fixup_alt_jump)
+                { /* Push a dummy failure point at the end of the
+                     alternative for a possible future
+                     `pop_failure_jump' to pop.  See comments at
+                     `push_dummy_failure' in `re_match_2'.  */
+                  BUF_PUSH (push_dummy_failure);
+                  
+                  /* We allocated space for this jump when we assigned
+                     to `fixup_alt_jump', in the `handle_alt' case below.  */
+                  STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
+                }
+
+              /* See similar code for backslashed left paren above.  */
+              if (COMPILE_STACK_EMPTY)
+                if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+                  goto normal_char;
+                else
+                  FREE_STACK_RETURN (REG_ERPAREN);
+
+              /* Since we just checked for an empty stack above, this
+                 ``can't happen''.  */
+              assert (compile_stack.avail != 0);
+              {
+                /* We don't just want to restore into `regnum', because
+                   later groups should continue to be numbered higher,
+                   as in `(ab)c(de)' -- the second group is #2.  */
+                regnum_t this_group_regnum;
+
+                compile_stack.avail--;		
+                begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
+                fixup_alt_jump
+                  = COMPILE_STACK_TOP.fixup_alt_jump
+                    ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 
+                    : 0;
+                laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
+                this_group_regnum = COMPILE_STACK_TOP.regnum;
+		/* If we've reached MAX_REGNUM groups, then this open
+		   won't actually generate any code, so we'll have to
+		   clear pending_exact explicitly.  */
+		pending_exact = 0;
+
+                /* We're at the end of the group, so now we know how many
+                   groups were inside this one.  */
+                if (this_group_regnum <= MAX_REGNUM)
+                  {
+                    unsigned char *inner_group_loc
+                      = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
+                    
+                    *inner_group_loc = regnum - this_group_regnum;
+                    BUF_PUSH_3 (stop_memory, this_group_regnum,
+                                regnum - this_group_regnum);
+                  }
+              }
+              break;
+
+
+            case '|':					/* `\|'.  */
+              if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
+                goto normal_backslash;
+            handle_alt:
+              if (syntax & RE_LIMITED_OPS)
+                goto normal_char;
+
+              /* Insert before the previous alternative a jump which
+                 jumps to this alternative if the former fails.  */
+              GET_BUFFER_SPACE (3);
+              INSERT_JUMP (on_failure_jump, begalt, b + 6);
+              pending_exact = 0;
+              b += 3;
+
+              /* The alternative before this one has a jump after it
+                 which gets executed if it gets matched.  Adjust that
+                 jump so it will jump to this alternative's analogous
+                 jump (put in below, which in turn will jump to the next
+                 (if any) alternative's such jump, etc.).  The last such
+                 jump jumps to the correct final destination.  A picture:
+                          _____ _____ 
+                          |   | |   |   
+                          |   v |   v 
+                         a | b   | c   
+
+                 If we are at `b', then fixup_alt_jump right now points to a
+                 three-byte space after `a'.  We'll put in the jump, set
+                 fixup_alt_jump to right after `b', and leave behind three
+                 bytes which we'll fill in when we get to after `c'.  */
+
+              if (fixup_alt_jump)
+                STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+              /* Mark and leave space for a jump after this alternative,
+                 to be filled in later either by next alternative or
+                 when know we're at the end of a series of alternatives.  */
+              fixup_alt_jump = b;
+              GET_BUFFER_SPACE (3);
+              b += 3;
+
+              laststart = 0;
+              begalt = b;
+              break;
+
+
+            case '{': 
+              /* If \{ is a literal.  */
+              if (!(syntax & RE_INTERVALS)
+                     /* If we're at `\{' and it's not the open-interval 
+                        operator.  */
+                  || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+                  || (p - 2 == pattern  &&  p == pend))
+                goto normal_backslash;
+
+            handle_interval:
+              {
+                /* If got here, then the syntax allows intervals.  */
+
+                /* At least (most) this many matches must be made.  */
+                int lower_bound = -1, upper_bound = -1;
+
+                beg_interval = p - 1;
+
+                if (p == pend)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else
+                      FREE_STACK_RETURN (REG_EBRACE);
+                  }
+
+                GET_UNSIGNED_NUMBER (lower_bound);
+
+                if (c == ',')
+                  {
+                    GET_UNSIGNED_NUMBER (upper_bound);
+                    if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+                  }
+                else
+                  /* Interval such as `{1}' => match exactly once. */
+                  upper_bound = lower_bound;
+
+                if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+                    || lower_bound > upper_bound)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else 
+                      FREE_STACK_RETURN (REG_BADBR);
+                  }
+
+                if (!(syntax & RE_NO_BK_BRACES)) 
+                  {
+                    if (c != '\\') FREE_STACK_RETURN (REG_EBRACE);
+
+                    PATFETCH (c);
+                  }
+
+                if (c != '}')
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else 
+                      FREE_STACK_RETURN (REG_BADBR);
+                  }
+
+                /* We just parsed a valid interval.  */
+
+                /* If it's invalid to have no preceding re.  */
+                if (!laststart)
+                  {
+                    if (syntax & RE_CONTEXT_INVALID_OPS)
+                      FREE_STACK_RETURN (REG_BADRPT);
+                    else if (syntax & RE_CONTEXT_INDEP_OPS)
+                      laststart = b;
+                    else
+                      goto unfetch_interval;
+                  }
+
+                /* If the upper bound is zero, don't want to succeed at
+                   all; jump from `laststart' to `b + 3', which will be
+                   the end of the buffer after we insert the jump.  */
+                 if (upper_bound == 0)
+                   {
+                     GET_BUFFER_SPACE (3);
+                     INSERT_JUMP (jump, laststart, b + 3);
+                     b += 3;
+                   }
+
+                 /* Otherwise, we have a nontrivial interval.  When
+                    we're all done, the pattern will look like:
+                      set_number_at <jump count> <upper bound>
+                      set_number_at <succeed_n count> <lower bound>
+                      succeed_n <after jump addr> <succeed_n count>
+                      <body of loop>
+                      jump_n <succeed_n addr> <jump count>
+                    (The upper bound and `jump_n' are omitted if
+                    `upper_bound' is 1, though.)  */
+                 else 
+                   { /* If the upper bound is > 1, we need to insert
+                        more at the end of the loop.  */
+                     unsigned nbytes = 10 + (upper_bound > 1) * 10;
+
+                     GET_BUFFER_SPACE (nbytes);
+
+                     /* Initialize lower bound of the `succeed_n', even
+                        though it will be set during matching by its
+                        attendant `set_number_at' (inserted next),
+                        because `re_compile_fastmap' needs to know.
+                        Jump to the `jump_n' we might insert below.  */
+                     INSERT_JUMP2 (succeed_n, laststart,
+                                   b + 5 + (upper_bound > 1) * 5,
+                                   lower_bound);
+                     b += 5;
+
+                     /* Code to initialize the lower bound.  Insert 
+                        before the `succeed_n'.  The `5' is the last two
+                        bytes of this `set_number_at', plus 3 bytes of
+                        the following `succeed_n'.  */
+                     insert_op2 (set_number_at, laststart, 5, lower_bound, b);
+                     b += 5;
+
+                     if (upper_bound > 1)
+                       { /* More than one repetition is allowed, so
+                            append a backward jump to the `succeed_n'
+                            that starts this interval.
+                            
+                            When we've reached this during matching,
+                            we'll have matched the interval once, so
+                            jump back only `upper_bound - 1' times.  */
+                         STORE_JUMP2 (jump_n, b, laststart + 5,
+                                      upper_bound - 1);
+                         b += 5;
+
+                         /* The location we want to set is the second
+                            parameter of the `jump_n'; that is `b-2' as
+                            an absolute address.  `laststart' will be
+                            the `set_number_at' we're about to insert;
+                            `laststart+3' the number to set, the source
+                            for the relative address.  But we are
+                            inserting into the middle of the pattern --
+                            so everything is getting moved up by 5.
+                            Conclusion: (b - 2) - (laststart + 3) + 5,
+                            i.e., b - laststart.
+                            
+                            We insert this at the beginning of the loop
+                            so that if we fail during matching, we'll
+                            reinitialize the bounds.  */
+                         insert_op2 (set_number_at, laststart, b - laststart,
+                                     upper_bound - 1, b);
+                         b += 5;
+                       }
+                   }
+                pending_exact = 0;
+                beg_interval = NULL;
+              }
+              break;
+
+            unfetch_interval:
+              /* If an invalid interval, match the characters as literals.  */
+               assert (beg_interval);
+               p = beg_interval;
+               beg_interval = NULL;
+
+               /* normal_char and normal_backslash need `c'.  */
+               PATFETCH (c);	
+
+               if (!(syntax & RE_NO_BK_BRACES))
+                 {
+                   if (p > pattern  &&  p[-1] == '\\')
+                     goto normal_backslash;
+                 }
+               goto normal_char;
+
+#ifdef emacs
+            /* There is no way to specify the before_dot and after_dot
+               operators.  rms says this is ok.  --karl  */
+            case '=':
+              BUF_PUSH (at_dot);
+              break;
+
+            case 's':	
+              laststart = b;
+              PATFETCH (c);
+              BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+              break;
+
+            case 'S':
+              laststart = b;
+              PATFETCH (c);
+              BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+              break;
+#endif /* emacs */
+
+
+            case 'w':
+              laststart = b;
+              BUF_PUSH (wordchar);
+              break;
+
+
+            case 'W':
+              laststart = b;
+              BUF_PUSH (notwordchar);
+              break;
+
+
+            case '<':
+              BUF_PUSH (wordbeg);
+              break;
+
+            case '>':
+              BUF_PUSH (wordend);
+              break;
+
+            case 'b':
+              BUF_PUSH (wordbound);
+              break;
+
+            case 'B':
+              BUF_PUSH (notwordbound);
+              break;
+
+            case '`':
+              BUF_PUSH (begbuf);
+              break;
+
+            case '\'':
+              BUF_PUSH (endbuf);
+              break;
+
+            case '1': case '2': case '3': case '4': case '5':
+            case '6': case '7': case '8': case '9':
+              if (syntax & RE_NO_BK_REFS)
+                goto normal_char;
+
+              c1 = c - '0';
+
+              if (c1 > regnum)
+                FREE_STACK_RETURN (REG_ESUBREG);
+
+              /* Can't back reference to a subexpression if inside of it.  */
+              if (group_in_compile_stack (compile_stack, c1))
+                goto normal_char;
+
+              laststart = b;
+              BUF_PUSH_2 (duplicate, c1);
+              break;
+
+
+            case '+':
+            case '?':
+              if (syntax & RE_BK_PLUS_QM)
+                goto handle_plus;
+              else
+                goto normal_backslash;
+
+            default:
+            normal_backslash:
+              /* You might think it would be useful for \ to mean
+                 not to translate; but if we don't translate it
+                 it will never match anything.  */
+              c = TRANSLATE (c);
+              goto normal_char;
+            }
+          break;
+
+
+	default:
+        /* Expects the character in `c'.  */
+	normal_char:
+	      /* If no exactn currently being built.  */
+          if (!pending_exact 
+
+              /* If last exactn not at current position.  */
+              || pending_exact + *pending_exact + 1 != b
+              
+              /* We have only one byte following the exactn for the count.  */
+	      || *pending_exact == (1 << BYTEWIDTH) - 1
+
+              /* If followed by a repetition operator.  */
+              || *p == '*' || *p == '^'
+	      || ((syntax & RE_BK_PLUS_QM)
+		  ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+		  : (*p == '+' || *p == '?'))
+	      || ((syntax & RE_INTERVALS)
+                  && ((syntax & RE_NO_BK_BRACES)
+		      ? *p == '{'
+                      : (p[0] == '\\' && p[1] == '{'))))
+	    {
+	      /* Start building a new exactn.  */
+              
+              laststart = b;
+
+	      BUF_PUSH_2 (exactn, 0);
+	      pending_exact = b - 1;
+            }
+            
+	  BUF_PUSH (c);
+          (*pending_exact)++;
+	  break;
+        } /* switch (c) */
+    } /* while p != pend */
+
+  
+  /* Through the pattern now.  */
+  
+  if (fixup_alt_jump)
+    STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+  if (!COMPILE_STACK_EMPTY) 
+    FREE_STACK_RETURN (REG_EPAREN);
+
+  /* If we don't want backtracking, force success
+     the first time we reach the end of the compiled pattern.  */
+  if (syntax & RE_NO_POSIX_BACKTRACKING)
+    BUF_PUSH (succeed);
+
+  free (compile_stack.stack);
+
+  /* We have succeeded; set the length of the buffer.  */
+  bufp->used = b - bufp->buffer;
+
+#ifdef DEBUG
+  if (debug)
+    {
+      DEBUG_PRINT1 ("\nCompiled pattern: \n");
+      print_compiled_pattern (bufp);
+    }
+#endif /* DEBUG */
+
+#ifndef MATCH_MAY_ALLOCATE
+  /* Initialize the failure stack to the largest possible stack.  This
+     isn't necessary unless we're trying to avoid calling alloca in
+     the search and match routines.  */
+  {
+    int num_regs = bufp->re_nsub + 1;
+
+    /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
+       is strictly greater than re_max_failures, the largest possible stack
+       is 2 * re_max_failures failure points.  */
+    if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
+      {
+	fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
+
+#ifdef emacs
+	if (! fail_stack.stack)
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) xmalloc (fail_stack.size 
+					    * sizeof (fail_stack_elt_t));
+	else
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) xrealloc (fail_stack.stack,
+					     (fail_stack.size
+					      * sizeof (fail_stack_elt_t)));
+#else /* not emacs */
+	if (! fail_stack.stack)
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) malloc (fail_stack.size 
+					   * sizeof (fail_stack_elt_t));
+	else
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) realloc (fail_stack.stack,
+					    (fail_stack.size
+					     * sizeof (fail_stack_elt_t)));
+#endif /* not emacs */
+      }
+
+    regex_grow_registers (num_regs);
+  }
+#endif /* not MATCH_MAY_ALLOCATE */
+
+  return REG_NOERROR;
+} /* regex_compile */
+
+
+/* Subroutines for `regex_compile'.  */
+
+/* Store OP at LOC followed by two-byte integer parameter ARG.  */
+
+static void
+store_op1 (op, loc, arg)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg;
+{
+  *loc = (unsigned char) op;
+  STORE_NUMBER (loc + 1, arg);
+}
+
+
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2.  */
+
+static void
+store_op2 (op, loc, arg1, arg2)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg1, arg2;
+{
+  *loc = (unsigned char) op;
+  STORE_NUMBER (loc + 1, arg1);
+  STORE_NUMBER (loc + 3, arg2);
+}
+
+
+/* Copy the bytes from LOC to END to open up three bytes of space at LOC
+   for OP followed by two-byte integer parameter ARG.  */
+
+static void
+insert_op1 (op, loc, arg, end)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg;
+    unsigned char *end;    
+{
+  register unsigned char *pfrom = end;
+  register unsigned char *pto = end + 3;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+    
+  store_op1 (op, loc, arg);
+}
+
+
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2.  */
+
+static void
+insert_op2 (op, loc, arg1, arg2, end)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg1, arg2;
+    unsigned char *end;    
+{
+  register unsigned char *pfrom = end;
+  register unsigned char *pto = end + 5;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+    
+  store_op2 (op, loc, arg1, arg2);
+}
+
+
+/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
+   after an alternative or a begin-subexpression.  We assume there is at
+   least one character before the ^.  */
+
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+    const char *pattern, *p;
+    reg_syntax_t syntax;
+{
+  const char *prev = p - 2;
+  boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
+  
+  return
+       /* After a subexpression?  */
+       (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
+       /* After an alternative?  */
+    || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
+}
+
+
+/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
+   at least one character after the $, i.e., `P < PEND'.  */
+
+static boolean
+at_endline_loc_p (p, pend, syntax)
+    const char *p, *pend;
+    int syntax;
+{
+  const char *next = p;
+  boolean next_backslash = *next == '\\';
+  const char *next_next = p + 1 < pend ? p + 1 : NULL;
+  
+  return
+       /* Before a subexpression?  */
+       (syntax & RE_NO_BK_PARENS ? *next == ')'
+        : next_backslash && next_next && *next_next == ')')
+       /* Before an alternative?  */
+    || (syntax & RE_NO_BK_VBAR ? *next == '|'
+        : next_backslash && next_next && *next_next == '|');
+}
+
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and 
+   false if it's not.  */
+
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+    compile_stack_type compile_stack;
+    regnum_t regnum;
+{
+  int this_element;
+
+  for (this_element = compile_stack.avail - 1;  
+       this_element >= 0; 
+       this_element--)
+    if (compile_stack.stack[this_element].regnum == regnum)
+      return true;
+
+  return false;
+}
+
+
+/* Read the ending character of a range (in a bracket expression) from the
+   uncompiled pattern *P_PTR (which ends at PEND).  We assume the
+   starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
+   Then we set the translation of all bits between the starting and
+   ending characters (inclusive) in the compiled pattern B.
+   
+   Return an error code.
+   
+   We use these short variable names so we can use the same macros as
+   `regex_compile' itself.  */
+
+static reg_errcode_t
+compile_range (p_ptr, pend, translate, syntax, b)
+    const char **p_ptr, *pend;
+    char *translate;
+    reg_syntax_t syntax;
+    unsigned char *b;
+{
+  unsigned this_char;
+
+  const char *p = *p_ptr;
+  int range_start, range_end;
+  
+  if (p == pend)
+    return REG_ERANGE;
+
+  /* Even though the pattern is a signed `char *', we need to fetch
+     with unsigned char *'s; if the high bit of the pattern character
+     is set, the range endpoints will be negative if we fetch using a
+     signed char *.
+
+     We also want to fetch the endpoints without translating them; the 
+     appropriate translation is done in the bit-setting loop below.  */
+  /* The SVR4 compiler on the 3B2 had trouble with unsigned const char *.  */
+  range_start = ((const unsigned char *) p)[-2];
+  range_end   = ((const unsigned char *) p)[0];
+
+  /* Have to increment the pointer into the pattern string, so the
+     caller isn't still at the ending character.  */
+  (*p_ptr)++;
+
+  /* If the start is after the end, the range is empty.  */
+  if (range_start > range_end)
+    return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+  /* Here we see why `this_char' has to be larger than an `unsigned
+     char' -- the range is inclusive, so if `range_end' == 0xff
+     (assuming 8-bit characters), we would otherwise go into an infinite
+     loop, since all characters <= 0xff.  */
+  for (this_char = range_start; this_char <= range_end; this_char++)
+    {
+      SET_LIST_BIT (TRANSLATE (this_char));
+    }
+  
+  return REG_NOERROR;
+}
+
+
+/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
+   BUFP.  A fastmap records which of the (1 << BYTEWIDTH) possible
+   characters can start a string that matches the pattern.  This fastmap
+   is used by re_search to skip quickly over impossible starting points.
+
+   The caller must supply the address of a (1 << BYTEWIDTH)-byte data
+   area as BUFP->fastmap.
+   
+   We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
+   the pattern buffer.
+
+   Returns 0 if we succeed, -2 if an internal error.   */
+
+int
+re_compile_fastmap (bufp)
+     struct re_pattern_buffer *bufp;
+{
+  int j, k;
+#ifdef MATCH_MAY_ALLOCATE
+  fail_stack_type fail_stack;
+#endif
+#ifndef REGEX_MALLOC
+  char *destination;
+#endif
+  /* We don't push any register information onto the failure stack.  */
+  unsigned num_regs = 0;
+  
+  register char *fastmap = bufp->fastmap;
+  unsigned char *pattern = bufp->buffer;
+  unsigned long size = bufp->used;
+  unsigned char *p = pattern;
+  register unsigned char *pend = pattern + size;
+
+  /* This holds the pointer to the failure stack, when
+     it is allocated relocatably.  */
+  fail_stack_elt_t *failure_stack_ptr;
+
+  /* Assume that each path through the pattern can be null until
+     proven otherwise.  We set this false at the bottom of switch
+     statement, to which we get only if a particular path doesn't
+     match the empty string.  */
+  boolean path_can_be_null = true;
+
+  /* We aren't doing a `succeed_n' to begin with.  */
+  boolean succeed_n_p = false;
+
+  assert (fastmap != NULL && p != NULL);
+  
+  INIT_FAIL_STACK ();
+  bzero (fastmap, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
+  bufp->fastmap_accurate = 1;	    /* It will be when we're done.  */
+  bufp->can_be_null = 0;
+      
+  while (1)
+    {
+      if (p == pend || *p == succeed)
+	{
+	  /* We have reached the (effective) end of pattern.  */
+	  if (!FAIL_STACK_EMPTY ())
+	    {
+	      bufp->can_be_null |= path_can_be_null;
+
+	      /* Reset for next path.  */
+	      path_can_be_null = true;
+
+	      p = fail_stack.stack[--fail_stack.avail].pointer;
+
+	      continue;
+	    }
+	  else
+	    break;
+	}
+
+      /* We should never be about to go beyond the end of the pattern.  */
+      assert (p < pend);
+      
+      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+	{
+
+        /* I guess the idea here is to simply not bother with a fastmap
+           if a backreference is used, since it's too hard to figure out
+           the fastmap for the corresponding group.  Setting
+           `can_be_null' stops `re_search_2' from using the fastmap, so
+           that is all we do.  */
+	case duplicate:
+	  bufp->can_be_null = 1;
+          goto done;
+
+
+      /* Following are the cases which match a character.  These end
+         with `break'.  */
+
+	case exactn:
+          fastmap[p[1]] = 1;
+	  break;
+
+
+        case charset:
+          for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+	    if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+              fastmap[j] = 1;
+	  break;
+
+
+	case charset_not:
+	  /* Chars beyond end of map must be allowed.  */
+	  for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+            fastmap[j] = 1;
+
+	  for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+	    if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+              fastmap[j] = 1;
+          break;
+
+
+	case wordchar:
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) == Sword)
+	      fastmap[j] = 1;
+	  break;
+
+
+	case notwordchar:
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) != Sword)
+	      fastmap[j] = 1;
+	  break;
+
+
+        case anychar:
+	  {
+	    int fastmap_newline = fastmap['\n'];
+
+	    /* `.' matches anything ...  */
+	    for (j = 0; j < (1 << BYTEWIDTH); j++)
+	      fastmap[j] = 1;
+
+	    /* ... except perhaps newline.  */
+	    if (!(bufp->syntax & RE_DOT_NEWLINE))
+	      fastmap['\n'] = fastmap_newline;
+
+	    /* Return if we have already set `can_be_null'; if we have,
+	       then the fastmap is irrelevant.  Something's wrong here.  */
+	    else if (bufp->can_be_null)
+	      goto done;
+
+	    /* Otherwise, have to check alternative paths.  */
+	    break;
+	  }
+
+#ifdef emacs
+        case syntaxspec:
+	  k = *p++;
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) == (enum syntaxcode) k)
+	      fastmap[j] = 1;
+	  break;
+
+
+	case notsyntaxspec:
+	  k = *p++;
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) != (enum syntaxcode) k)
+	      fastmap[j] = 1;
+	  break;
+
+
+      /* All cases after this match the empty string.  These end with
+         `continue'.  */
+
+
+	case before_dot:
+	case at_dot:
+	case after_dot:
+          continue;
+#endif /* not emacs */
+
+
+        case no_op:
+        case begline:
+        case endline:
+	case begbuf:
+	case endbuf:
+	case wordbound:
+	case notwordbound:
+	case wordbeg:
+	case wordend:
+        case push_dummy_failure:
+          continue;
+
+
+	case jump_n:
+        case pop_failure_jump:
+	case maybe_pop_jump:
+	case jump:
+        case jump_past_alt:
+	case dummy_failure_jump:
+          EXTRACT_NUMBER_AND_INCR (j, p);
+	  p += j;	
+	  if (j > 0)
+	    continue;
+            
+          /* Jump backward implies we just went through the body of a
+             loop and matched nothing.  Opcode jumped to should be
+             `on_failure_jump' or `succeed_n'.  Just treat it like an
+             ordinary jump.  For a * loop, it has pushed its failure
+             point already; if so, discard that as redundant.  */
+          if ((re_opcode_t) *p != on_failure_jump
+	      && (re_opcode_t) *p != succeed_n)
+	    continue;
+
+          p++;
+          EXTRACT_NUMBER_AND_INCR (j, p);
+          p += j;		
+	  
+          /* If what's on the stack is where we are now, pop it.  */
+          if (!FAIL_STACK_EMPTY () 
+	      && fail_stack.stack[fail_stack.avail - 1].pointer == p)
+            fail_stack.avail--;
+
+          continue;
+
+
+        case on_failure_jump:
+        case on_failure_keep_string_jump:
+	handle_on_failure_jump:
+          EXTRACT_NUMBER_AND_INCR (j, p);
+
+          /* For some patterns, e.g., `(a?)?', `p+j' here points to the
+             end of the pattern.  We don't want to push such a point,
+             since when we restore it above, entering the switch will
+             increment `p' past the end of the pattern.  We don't need
+             to push such a point since we obviously won't find any more
+             fastmap entries beyond `pend'.  Such a pattern can match
+             the null string, though.  */
+          if (p + j < pend)
+            {
+              if (!PUSH_PATTERN_OP (p + j, fail_stack))
+		{
+		  RESET_FAIL_STACK ();
+		  return -2;
+		}
+            }
+          else
+            bufp->can_be_null = 1;
+
+          if (succeed_n_p)
+            {
+              EXTRACT_NUMBER_AND_INCR (k, p);	/* Skip the n.  */
+              succeed_n_p = false;
+	    }
+
+          continue;
+
+
+	case succeed_n:
+          /* Get to the number of times to succeed.  */
+          p += 2;		
+
+          /* Increment p past the n for when k != 0.  */
+          EXTRACT_NUMBER_AND_INCR (k, p);
+          if (k == 0)
+	    {
+              p -= 4;
+  	      succeed_n_p = true;  /* Spaghetti code alert.  */
+              goto handle_on_failure_jump;
+            }
+          continue;
+
+
+	case set_number_at:
+          p += 4;
+          continue;
+
+
+	case start_memory:
+        case stop_memory:
+	  p += 2;
+	  continue;
+
+
+	default:
+          abort (); /* We have listed all the cases.  */
+        } /* switch *p++ */
+
+      /* Getting here means we have found the possible starting
+         characters for one path of the pattern -- and that the empty
+         string does not match.  We need not follow this path further.
+         Instead, look at the next alternative (remembered on the
+         stack), or quit if no more.  The test at the top of the loop
+         does these things.  */
+      path_can_be_null = false;
+      p = pend;
+    } /* while p */
+
+  /* Set `can_be_null' for the last path (also the first path, if the
+     pattern is empty).  */
+  bufp->can_be_null |= path_can_be_null;
+
+ done:
+  RESET_FAIL_STACK ();
+  return 0;
+} /* re_compile_fastmap */
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
+   this memory for recording register information.  STARTS and ENDS
+   must be allocated using the malloc library routine, and must each
+   be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+    struct re_pattern_buffer *bufp;
+    struct re_registers *regs;
+    unsigned num_regs;
+    regoff_t *starts, *ends;
+{
+  if (num_regs)
+    {
+      bufp->regs_allocated = REGS_REALLOCATE;
+      regs->num_regs = num_regs;
+      regs->start = starts;
+      regs->end = ends;
+    }
+  else
+    {
+      bufp->regs_allocated = REGS_UNALLOCATED;
+      regs->num_regs = 0;
+      regs->start = regs->end = (regoff_t *) 0;
+    }
+}
+
+
+/* Searching routines.  */
+
+/* Like re_search_2, below, but only one string is specified, and
+   doesn't let you say where to stop matching. */
+
+int
+re_search (bufp, string, size, startpos, range, regs)
+     struct re_pattern_buffer *bufp;
+     const char *string;
+     int size, startpos, range;
+     struct re_registers *regs;
+{
+  return re_search_2 (bufp, NULL, 0, string, size, startpos, range, 
+		      regs, size);
+}
+
+
+/* Using the compiled pattern in BUFP->buffer, first tries to match the
+   virtual concatenation of STRING1 and STRING2, starting first at index
+   STARTPOS, then at STARTPOS + 1, and so on.
+   
+   STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
+   
+   RANGE is how far to scan while trying to match.  RANGE = 0 means try
+   only at STARTPOS; in general, the last start tried is STARTPOS +
+   RANGE.
+   
+   In REGS, return the indices of the virtual concatenation of STRING1
+   and STRING2 that matched the entire BUFP->buffer and its contained
+   subexpressions.
+   
+   Do not consider matching one past the index STOP in the virtual
+   concatenation of STRING1 and STRING2.
+
+   We return either the position in the strings at which the match was
+   found, -1 if no match, or -2 if error (such as failure
+   stack overflow).  */
+
+int
+re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+     int stop;
+{
+  int val;
+  register char *fastmap = bufp->fastmap;
+  register char *translate = bufp->translate;
+  int total_size = size1 + size2;
+  int endpos = startpos + range;
+
+  /* Check for out-of-range STARTPOS.  */
+  if (startpos < 0 || startpos > total_size)
+    return -1;
+    
+  /* Fix up RANGE if it might eventually take us outside
+     the virtual concatenation of STRING1 and STRING2.  */
+  if (endpos < -1)
+    range = -1 - startpos;
+  else if (endpos > total_size)
+    range = total_size - startpos;
+
+  /* If the search isn't to be a backwards one, don't waste time in a
+     search for a pattern that must be anchored.  */
+  if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
+    {
+      if (startpos > 0)
+	return -1;
+      else
+	range = 1;
+    }
+
+  /* Update the fastmap now if not correct already.  */
+  if (fastmap && !bufp->fastmap_accurate)
+    if (re_compile_fastmap (bufp) == -2)
+      return -2;
+  
+  /* Loop through the string, looking for a place to start matching.  */
+  for (;;)
+    { 
+      /* If a fastmap is supplied, skip quickly over characters that
+         cannot be the start of a match.  If the pattern can match the
+         null string, however, we don't need to skip characters; we want
+         the first null string.  */
+      if (fastmap && startpos < total_size && !bufp->can_be_null)
+	{
+	  if (range > 0)	/* Searching forwards.  */
+	    {
+	      register const char *d;
+	      register int lim = 0;
+	      int irange = range;
+
+              if (startpos < size1 && startpos + range >= size1)
+                lim = range - (size1 - startpos);
+
+	      d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
+   
+              /* Written out as an if-else to avoid testing `translate'
+                 inside the loop.  */
+	      if (translate)
+                while (range > lim
+                       && !fastmap[(unsigned char)
+				   translate[(unsigned char) *d++]])
+                  range--;
+	      else
+                while (range > lim && !fastmap[(unsigned char) *d++])
+                  range--;
+
+	      startpos += irange - range;
+	    }
+	  else				/* Searching backwards.  */
+	    {
+	      register char c = (size1 == 0 || startpos >= size1
+                                 ? string2[startpos - size1] 
+                                 : string1[startpos]);
+
+	      if (!fastmap[(unsigned char) TRANSLATE (c)])
+		goto advance;
+	    }
+	}
+
+      /* If can't match the null string, and that's all we have left, fail.  */
+      if (range >= 0 && startpos == total_size && fastmap
+          && !bufp->can_be_null)
+	return -1;
+
+      val = re_match_2_internal (bufp, string1, size1, string2, size2,
+				 startpos, regs, stop);
+#ifndef REGEX_MALLOC
+#ifdef C_ALLOCA
+      alloca (0);
+#endif
+#endif
+
+      if (val >= 0)
+	return startpos;
+        
+      if (val == -2)
+	return -2;
+
+    advance:
+      if (!range) 
+        break;
+      else if (range > 0) 
+        {
+          range--; 
+          startpos++;
+        }
+      else
+        {
+          range++; 
+          startpos--;
+        }
+    }
+  return -1;
+} /* re_search_2 */
+
+
+/* Declarations and macros for re_match_2.  */
+
+static int bcmp_translate ();
+static boolean alt_match_null_string_p (),
+               common_op_match_null_string_p (),
+               group_match_null_string_p ();
+
+/* This converts PTR, a pointer into one of the search strings `string1'
+   and `string2' into an offset from the beginning of that string.  */
+#define POINTER_TO_OFFSET(ptr)			\
+  (FIRST_STRING_P (ptr)				\
+   ? ((regoff_t) ((ptr) - string1))		\
+   : ((regoff_t) ((ptr) - string2 + size1)))
+
+/* Macros for dealing with the split strings in re_match_2.  */
+
+#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
+
+/* Call before fetching a character with *d.  This switches over to
+   string2 if necessary.  */
+#define PREFETCH()							\
+  while (d == dend)						    	\
+    {									\
+      /* End of string2 => fail.  */					\
+      if (dend == end_match_2) 						\
+        goto fail;							\
+      /* End of string1 => advance to string2.  */ 			\
+      d = string2;						        \
+      dend = end_match_2;						\
+    }
+
+
+/* Test if at very beginning or at very end of the virtual concatenation
+   of `string1' and `string2'.  If only one string, it's `string2'.  */
+#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
+#define AT_STRINGS_END(d) ((d) == end2)	
+
+
+/* Test if D points to a character which is word-constituent.  We have
+   two special cases to check for: if past the end of string1, look at
+   the first character in string2; and if before the beginning of
+   string2, look at the last character in string1.  */
+#define WORDCHAR_P(d)							\
+  (SYNTAX ((d) == end1 ? *string2					\
+           : (d) == string2 - 1 ? *(end1 - 1) : *(d))			\
+   == Sword)
+
+/* Test if the character before D and the one at D differ with respect
+   to being word-constituent.  */
+#define AT_WORD_BOUNDARY(d)						\
+  (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)				\
+   || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
+
+
+/* Free everything we malloc.  */
+#ifdef MATCH_MAY_ALLOCATE
+#define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL
+#define FREE_VARIABLES()						\
+  do {									\
+    REGEX_FREE_STACK (fail_stack.stack);				\
+    FREE_VAR (regstart);						\
+    FREE_VAR (regend);							\
+    FREE_VAR (old_regstart);						\
+    FREE_VAR (old_regend);						\
+    FREE_VAR (best_regstart);						\
+    FREE_VAR (best_regend);						\
+    FREE_VAR (reg_info);						\
+    FREE_VAR (reg_dummy);						\
+    FREE_VAR (reg_info_dummy);						\
+  } while (0)
+#else
+#define FREE_VARIABLES() ((void)0) /* Do nothing!  But inhibit gcc warning.  */
+#endif /* not MATCH_MAY_ALLOCATE */
+
+/* These values must meet several constraints.  They must not be valid
+   register values; since we have a limit of 255 registers (because
+   we use only one byte in the pattern for the register number), we can
+   use numbers larger than 255.  They must differ by 1, because of
+   NUM_FAILURE_ITEMS above.  And the value for the lowest register must
+   be larger than the value for the highest register, so we do not try
+   to actually save any registers when none are active.  */
+#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
+#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
+
+
+/* Matching routines.  */
+
+#ifndef emacs   /* Emacs never uses this.  */
+/* re_match is like re_match_2 except it takes only a single string.  */
+
+int
+re_match (bufp, string, size, pos, regs)
+     struct re_pattern_buffer *bufp;
+     const char *string;
+     int size, pos;
+     struct re_registers *regs;
+{
+  int result = re_match_2_internal (bufp, NULL, 0, string, size,
+				    pos, regs, size);
+  alloca (0);
+  return result;
+}
+#endif /* not emacs */
+
+
+/* re_match_2 matches the compiled pattern in BUFP against the
+   the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+   and SIZE2, respectively).  We start matching at POS, and stop
+   matching at STOP.
+   
+   If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
+   store offsets for the substring each group matched in REGS.  See the
+   documentation for exactly how many groups we fill.
+
+   We return -1 if no match, -2 if an internal error (such as the
+   failure stack overflowing).  Otherwise, we return the length of the
+   matched substring.  */
+
+int
+re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+{
+  int result = re_match_2_internal (bufp, string1, size1, string2, size2,
+				    pos, regs, stop);
+  alloca (0);
+  return result;
+}
+
+/* This is a separate function so that we can force an alloca cleanup
+   afterwards.  */
+static int
+re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+{
+  /* General temporaries.  */
+  int mcnt;
+  unsigned char *p1;
+
+  /* Just past the end of the corresponding string.  */
+  const char *end1, *end2;
+
+  /* Pointers into string1 and string2, just past the last characters in
+     each to consider matching.  */
+  const char *end_match_1, *end_match_2;
+
+  /* Where we are in the data, and the end of the current string.  */
+  const char *d, *dend;
+  
+  /* Where we are in the pattern, and the end of the pattern.  */
+  unsigned char *p = bufp->buffer;
+  register unsigned char *pend = p + bufp->used;
+
+  /* Mark the opcode just after a start_memory, so we can test for an
+     empty subpattern when we get to the stop_memory.  */
+  unsigned char *just_past_start_mem = 0;
+
+  /* We use this to map every character in the string.  */
+  char *translate = bufp->translate;
+
+  /* Failure point stack.  Each place that can handle a failure further
+     down the line pushes a failure point on this stack.  It consists of
+     restart, regend, and reg_info for all registers corresponding to
+     the subexpressions we're currently inside, plus the number of such
+     registers, and, finally, two char *'s.  The first char * is where
+     to resume scanning the pattern; the second one is where to resume
+     scanning the strings.  If the latter is zero, the failure point is
+     a ``dummy''; if a failure happens and the failure point is a dummy,
+     it gets discarded and the next next one is tried.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global.  */
+  fail_stack_type fail_stack;
+#endif
+#ifdef DEBUG
+  static unsigned failure_id = 0;
+  unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
+#endif
+
+  /* This holds the pointer to the failure stack, when
+     it is allocated relocatably.  */
+  fail_stack_elt_t *failure_stack_ptr;
+
+  /* We fill all the registers internally, independent of what we
+     return, for use in backreferences.  The number here includes
+     an element for register zero.  */
+  unsigned num_regs = bufp->re_nsub + 1;
+  
+  /* The currently active registers.  */
+  unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+  unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+
+  /* Information on the contents of registers. These are pointers into
+     the input strings; they record just what was matched (on this
+     attempt) by a subexpression part of the pattern, that is, the
+     regnum-th regstart pointer points to where in the pattern we began
+     matching and the regnum-th regend points to right after where we
+     stopped matching the regnum-th subexpression.  (The zeroth register
+     keeps track of what the whole pattern matches.)  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **regstart, **regend;
+#endif
+
+  /* If a group that's operated upon by a repetition operator fails to
+     match anything, then the register for its start will need to be
+     restored because it will have been set to wherever in the string we
+     are when we last see its open-group operator.  Similarly for a
+     register's end.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **old_regstart, **old_regend;
+#endif
+
+  /* The is_active field of reg_info helps us keep track of which (possibly
+     nested) subexpressions we are currently in. The matched_something
+     field of reg_info[reg_num] helps us tell whether or not we have
+     matched any of the pattern so far this time through the reg_num-th
+     subexpression.  These two fields get reset each time through any
+     loop their register is in.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global.  */
+  register_info_type *reg_info; 
+#endif
+
+  /* The following record the register info as found in the above
+     variables when we find a match better than any we've seen before. 
+     This happens as we backtrack through the failure points, which in
+     turn happens only if we have not yet matched the entire string. */
+  unsigned best_regs_set = false;
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **best_regstart, **best_regend;
+#endif
+  
+  /* Logically, this is `best_regend[0]'.  But we don't want to have to
+     allocate space for that if we're not allocating space for anything
+     else (see below).  Also, we never need info about register 0 for
+     any of the other register vectors, and it seems rather a kludge to
+     treat `best_regend' differently than the rest.  So we keep track of
+     the end of the best match so far in a separate variable.  We
+     initialize this to NULL so that when we backtrack the first time
+     and need to test it, it's not garbage.  */
+  const char *match_end = NULL;
+
+  /* This helps SET_REGS_MATCHED avoid doing redundant work.  */
+  int set_regs_matched_done = 0;
+
+  /* Used when we pop values we don't care about.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **reg_dummy;
+  register_info_type *reg_info_dummy;
+#endif
+
+#ifdef DEBUG
+  /* Counts the total number of registers pushed.  */
+  unsigned num_regs_pushed = 0; 	
+#endif
+
+  DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+  
+  INIT_FAIL_STACK ();
+  
+#ifdef MATCH_MAY_ALLOCATE
+  /* Do not bother to initialize all the register variables if there are
+     no groups in the pattern, as it takes a fair amount of time.  If
+     there are groups, we include space for register 0 (the whole
+     pattern), even though we never use it, since it simplifies the
+     array indexing.  We should fix this.  */
+  if (bufp->re_nsub)
+    {
+      regstart = REGEX_TALLOC (num_regs, const char *);
+      regend = REGEX_TALLOC (num_regs, const char *);
+      old_regstart = REGEX_TALLOC (num_regs, const char *);
+      old_regend = REGEX_TALLOC (num_regs, const char *);
+      best_regstart = REGEX_TALLOC (num_regs, const char *);
+      best_regend = REGEX_TALLOC (num_regs, const char *);
+      reg_info = REGEX_TALLOC (num_regs, register_info_type);
+      reg_dummy = REGEX_TALLOC (num_regs, const char *);
+      reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
+
+      if (!(regstart && regend && old_regstart && old_regend && reg_info 
+            && best_regstart && best_regend && reg_dummy && reg_info_dummy)) 
+        {
+          FREE_VARIABLES ();
+          return -2;
+        }
+    }
+  else
+    {
+      /* We must initialize all our variables to NULL, so that
+         `FREE_VARIABLES' doesn't try to free them.  */
+      regstart = regend = old_regstart = old_regend = best_regstart
+        = best_regend = reg_dummy = NULL;
+      reg_info = reg_info_dummy = (register_info_type *) NULL;
+    }
+#endif /* MATCH_MAY_ALLOCATE */
+
+  /* The starting position is bogus.  */
+  if (pos < 0 || pos > size1 + size2)
+    {
+      FREE_VARIABLES ();
+      return -1;
+    }
+    
+  /* Initialize subexpression text positions to -1 to mark ones that no
+     start_memory/stop_memory has been seen for. Also initialize the
+     register information struct.  */
+  for (mcnt = 1; mcnt < num_regs; mcnt++)
+    {
+      regstart[mcnt] = regend[mcnt] 
+        = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
+        
+      REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
+      IS_ACTIVE (reg_info[mcnt]) = 0;
+      MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+      EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+    }
+  
+  /* We move `string1' into `string2' if the latter's empty -- but not if
+     `string1' is null.  */
+  if (size2 == 0 && string1 != NULL)
+    {
+      string2 = string1;
+      size2 = size1;
+      string1 = 0;
+      size1 = 0;
+    }
+  end1 = string1 + size1;
+  end2 = string2 + size2;
+
+  /* Compute where to stop matching, within the two strings.  */
+  if (stop <= size1)
+    {
+      end_match_1 = string1 + stop;
+      end_match_2 = string2;
+    }
+  else
+    {
+      end_match_1 = end1;
+      end_match_2 = string2 + stop - size1;
+    }
+
+  /* `p' scans through the pattern as `d' scans through the data. 
+     `dend' is the end of the input string that `d' points within.  `d'
+     is advanced into the following input string whenever necessary, but
+     this happens before fetching; therefore, at the beginning of the
+     loop, `d' can be pointing at the end of a string, but it cannot
+     equal `string2'.  */
+  if (size1 > 0 && pos <= size1)
+    {
+      d = string1 + pos;
+      dend = end_match_1;
+    }
+  else
+    {
+      d = string2 + pos - size1;
+      dend = end_match_2;
+    }
+
+  DEBUG_PRINT1 ("The compiled pattern is: ");
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
+  DEBUG_PRINT1 ("The string to match is: `");
+  DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
+  DEBUG_PRINT1 ("'\n");
+  
+  /* This loops over pattern commands.  It exits by returning from the
+     function if the match is complete, or it drops through if the match
+     fails at this starting point in the input data.  */
+  for (;;)
+    {
+      DEBUG_PRINT2 ("\n0x%x: ", p);
+
+      if (p == pend)
+	{ /* End of pattern means we might have succeeded.  */
+          DEBUG_PRINT1 ("end of pattern ... ");
+          
+	  /* If we haven't matched the entire string, and we want the
+             longest match, try backtracking.  */
+          if (d != end_match_2)
+	    {
+	      /* 1 if this match ends in the same string (string1 or string2)
+		 as the best previous match.  */
+	      boolean same_str_p = (FIRST_STRING_P (match_end) 
+				    == MATCHING_IN_FIRST_STRING);
+	      /* 1 if this match is the best seen so far.  */
+	      boolean best_match_p;
+
+	      /* AIX compiler got confused when this was combined
+		 with the previous declaration.  */
+	      if (same_str_p)
+		best_match_p = d > match_end;
+	      else
+		best_match_p = !MATCHING_IN_FIRST_STRING;
+
+              DEBUG_PRINT1 ("backtracking.\n");
+              
+              if (!FAIL_STACK_EMPTY ())
+                { /* More failure points to try.  */
+
+                  /* If exceeds best match so far, save it.  */
+                  if (!best_regs_set || best_match_p)
+                    {
+                      best_regs_set = true;
+                      match_end = d;
+                      
+                      DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
+                      
+                      for (mcnt = 1; mcnt < num_regs; mcnt++)
+                        {
+                          best_regstart[mcnt] = regstart[mcnt];
+                          best_regend[mcnt] = regend[mcnt];
+                        }
+                    }
+                  goto fail;	       
+                }
+
+              /* If no failure points, don't restore garbage.  And if
+                 last match is real best match, don't restore second
+                 best one. */
+              else if (best_regs_set && !best_match_p)
+                {
+  	        restore_best_regs:
+                  /* Restore best match.  It may happen that `dend ==
+                     end_match_1' while the restored d is in string2.
+                     For example, the pattern `x.*y.*z' against the
+                     strings `x-' and `y-z-', if the two strings are
+                     not consecutive in memory.  */
+                  DEBUG_PRINT1 ("Restoring best registers.\n");
+                  
+                  d = match_end;
+                  dend = ((d >= string1 && d <= end1)
+		           ? end_match_1 : end_match_2);
+
+		  for (mcnt = 1; mcnt < num_regs; mcnt++)
+		    {
+		      regstart[mcnt] = best_regstart[mcnt];
+		      regend[mcnt] = best_regend[mcnt];
+		    }
+                }
+            } /* d != end_match_2 */
+
+	succeed_label:
+          DEBUG_PRINT1 ("Accepting match.\n");
+
+          /* If caller wants register contents data back, do it.  */
+          if (regs && !bufp->no_sub)
+	    {
+              /* Have the register data arrays been allocated?  */
+              if (bufp->regs_allocated == REGS_UNALLOCATED)
+                { /* No.  So allocate them with malloc.  We need one
+                     extra element beyond `num_regs' for the `-1' marker
+                     GNU code uses.  */
+                  regs->num_regs = MAX (RE_NREGS, num_regs + 1);
+                  regs->start = TALLOC (regs->num_regs, regoff_t);
+                  regs->end = TALLOC (regs->num_regs, regoff_t);
+                  if (regs->start == NULL || regs->end == NULL)
+		    {
+		      FREE_VARIABLES ();
+		      return -2;
+		    }
+                  bufp->regs_allocated = REGS_REALLOCATE;
+                }
+              else if (bufp->regs_allocated == REGS_REALLOCATE)
+                { /* Yes.  If we need more elements than were already
+                     allocated, reallocate them.  If we need fewer, just
+                     leave it alone.  */
+                  if (regs->num_regs < num_regs + 1)
+                    {
+                      regs->num_regs = num_regs + 1;
+                      RETALLOC (regs->start, regs->num_regs, regoff_t);
+                      RETALLOC (regs->end, regs->num_regs, regoff_t);
+                      if (regs->start == NULL || regs->end == NULL)
+			{
+			  FREE_VARIABLES ();
+			  return -2;
+			}
+                    }
+                }
+              else
+		{
+		  /* These braces fend off a "empty body in an else-statement"
+		     warning under GCC when assert expands to nothing.  */
+		  assert (bufp->regs_allocated == REGS_FIXED);
+		}
+
+              /* Convert the pointer data in `regstart' and `regend' to
+                 indices.  Register zero has to be set differently,
+                 since we haven't kept track of any info for it.  */
+              if (regs->num_regs > 0)
+                {
+                  regs->start[0] = pos;
+                  regs->end[0] = (MATCHING_IN_FIRST_STRING
+				  ? ((regoff_t) (d - string1))
+			          : ((regoff_t) (d - string2 + size1)));
+                }
+              
+              /* Go through the first `min (num_regs, regs->num_regs)'
+                 registers, since that is all we initialized.  */
+	      for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
+		{
+                  if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
+                    regs->start[mcnt] = regs->end[mcnt] = -1;
+                  else
+                    {
+		      regs->start[mcnt]
+			= (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
+                      regs->end[mcnt]
+			= (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
+                    }
+		}
+              
+              /* If the regs structure we return has more elements than
+                 were in the pattern, set the extra elements to -1.  If
+                 we (re)allocated the registers, this is the case,
+                 because we always allocate enough to have at least one
+                 -1 at the end.  */
+              for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
+                regs->start[mcnt] = regs->end[mcnt] = -1;
+	    } /* regs && !bufp->no_sub */
+
+          DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+                        nfailure_points_pushed, nfailure_points_popped,
+                        nfailure_points_pushed - nfailure_points_popped);
+          DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
+
+          mcnt = d - pos - (MATCHING_IN_FIRST_STRING 
+			    ? string1 
+			    : string2 - size1);
+
+          DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+
+          FREE_VARIABLES ();
+          return mcnt;
+        }
+
+      /* Otherwise match next pattern command.  */
+      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+	{
+        /* Ignore these.  Used to ignore the n of succeed_n's which
+           currently have n == 0.  */
+        case no_op:
+          DEBUG_PRINT1 ("EXECUTING no_op.\n");
+          break;
+
+	case succeed:
+          DEBUG_PRINT1 ("EXECUTING succeed.\n");
+	  goto succeed_label;
+
+        /* Match the next n pattern characters exactly.  The following
+           byte in the pattern defines n, and the n bytes after that
+           are the characters to match.  */
+	case exactn:
+	  mcnt = *p++;
+          DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
+
+          /* This is written out as an if-else so we don't waste time
+             testing `translate' inside the loop.  */
+          if (translate)
+	    {
+	      do
+		{
+		  PREFETCH ();
+		  if (translate[(unsigned char) *d++] != (char) *p++)
+                    goto fail;
+		}
+	      while (--mcnt);
+	    }
+	  else
+	    {
+	      do
+		{
+		  PREFETCH ();
+		  if (*d++ != (char) *p++) goto fail;
+		}
+	      while (--mcnt);
+	    }
+	  SET_REGS_MATCHED ();
+          break;
+
+
+        /* Match any character except possibly a newline or a null.  */
+	case anychar:
+          DEBUG_PRINT1 ("EXECUTING anychar.\n");
+
+          PREFETCH ();
+
+          if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
+              || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
+	    goto fail;
+
+          SET_REGS_MATCHED ();
+          DEBUG_PRINT2 ("  Matched `%d'.\n", *d);
+          d++;
+	  break;
+
+
+	case charset:
+	case charset_not:
+	  {
+	    register unsigned char c;
+	    boolean not = (re_opcode_t) *(p - 1) == charset_not;
+
+            DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
+
+	    PREFETCH ();
+	    c = TRANSLATE (*d); /* The character to match.  */
+
+            /* Cast to `unsigned' instead of `unsigned char' in case the
+               bit list is a full 32 bytes long.  */
+	    if (c < (unsigned) (*p * BYTEWIDTH)
+		&& p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+	      not = !not;
+
+	    p += 1 + *p;
+
+	    if (!not) goto fail;
+            
+	    SET_REGS_MATCHED ();
+            d++;
+	    break;
+	  }
+
+
+        /* The beginning of a group is represented by start_memory.
+           The arguments are the register number in the next byte, and the
+           number of groups inner to this one in the next.  The text
+           matched within the group is recorded (in the internal
+           registers data structure) under the register number.  */
+        case start_memory:
+	  DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
+
+          /* Find out if this group can match the empty string.  */
+	  p1 = p;		/* To send to group_match_null_string_p.  */
+          
+          if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
+            REG_MATCH_NULL_STRING_P (reg_info[*p]) 
+              = group_match_null_string_p (&p1, pend, reg_info);
+
+          /* Save the position in the string where we were the last time
+             we were at this open-group operator in case the group is
+             operated upon by a repetition operator, e.g., with `(a*)*b'
+             against `ab'; then we want to ignore where we are now in
+             the string in case this attempt to match fails.  */
+          old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                             ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
+                             : regstart[*p];
+	  DEBUG_PRINT2 ("  old_regstart: %d\n", 
+			 POINTER_TO_OFFSET (old_regstart[*p]));
+
+          regstart[*p] = d;
+	  DEBUG_PRINT2 ("  regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
+          IS_ACTIVE (reg_info[*p]) = 1;
+          MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+	  /* Clear this whenever we change the register activity status.  */
+	  set_regs_matched_done = 0;
+          
+          /* This is the new highest active register.  */
+          highest_active_reg = *p;
+          
+          /* If nothing was active before, this is the new lowest active
+             register.  */
+          if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+            lowest_active_reg = *p;
+
+          /* Move past the register number and inner group count.  */
+          p += 2;
+	  just_past_start_mem = p;
+
+          break;
+
+
+        /* The stop_memory opcode represents the end of a group.  Its
+           arguments are the same as start_memory's: the register
+           number, and the number of inner groups.  */
+	case stop_memory:
+	  DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
+             
+          /* We need to save the string position the last time we were at
+             this close-group operator in case the group is operated
+             upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
+             against `aba'; then we want to ignore where we are now in
+             the string in case this attempt to match fails.  */
+          old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                           ? REG_UNSET (regend[*p]) ? d : regend[*p]
+			   : regend[*p];
+	  DEBUG_PRINT2 ("      old_regend: %d\n", 
+			 POINTER_TO_OFFSET (old_regend[*p]));
+
+          regend[*p] = d;
+	  DEBUG_PRINT2 ("      regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
+
+          /* This register isn't active anymore.  */
+          IS_ACTIVE (reg_info[*p]) = 0;
+
+	  /* Clear this whenever we change the register activity status.  */
+	  set_regs_matched_done = 0;
+
+          /* If this was the only register active, nothing is active
+             anymore.  */
+          if (lowest_active_reg == highest_active_reg)
+            {
+              lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+              highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+            }
+          else
+            { /* We must scan for the new highest active register, since
+                 it isn't necessarily one less than now: consider
+                 (a(b)c(d(e)f)g).  When group 3 ends, after the f), the
+                 new highest active register is 1.  */
+              unsigned char r = *p - 1;
+              while (r > 0 && !IS_ACTIVE (reg_info[r]))
+                r--;
+              
+              /* If we end up at register zero, that means that we saved
+                 the registers as the result of an `on_failure_jump', not
+                 a `start_memory', and we jumped to past the innermost
+                 `stop_memory'.  For example, in ((.)*) we save
+                 registers 1 and 2 as a result of the *, but when we pop
+                 back to the second ), we are at the stop_memory 1.
+                 Thus, nothing is active.  */
+	      if (r == 0)
+                {
+                  lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+                  highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+                }
+              else
+                highest_active_reg = r;
+            }
+          
+          /* If just failed to match something this time around with a
+             group that's operated on by a repetition operator, try to
+             force exit from the ``loop'', and restore the register
+             information for this group that we had before trying this
+             last match.  */
+          if ((!MATCHED_SOMETHING (reg_info[*p])
+               || just_past_start_mem == p - 1)
+	      && (p + 2) < pend)              
+            {
+              boolean is_a_jump_n = false;
+              
+              p1 = p + 2;
+              mcnt = 0;
+              switch ((re_opcode_t) *p1++)
+                {
+                  case jump_n:
+		    is_a_jump_n = true;
+                  case pop_failure_jump:
+		  case maybe_pop_jump:
+		  case jump:
+		  case dummy_failure_jump:
+                    EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+		    if (is_a_jump_n)
+		      p1 += 2;
+                    break;
+                  
+                  default:
+                    /* do nothing */ ;
+                }
+	      p1 += mcnt;
+        
+              /* If the next operation is a jump backwards in the pattern
+	         to an on_failure_jump right before the start_memory
+                 corresponding to this stop_memory, exit from the loop
+                 by forcing a failure after pushing on the stack the
+                 on_failure_jump's jump in the pattern, and d.  */
+              if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
+                  && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
+		{
+                  /* If this group ever matched anything, then restore
+                     what its registers were before trying this last
+                     failed match, e.g., with `(a*)*b' against `ab' for
+                     regstart[1], and, e.g., with `((a*)*(b*)*)*'
+                     against `aba' for regend[3].
+                     
+                     Also restore the registers for inner groups for,
+                     e.g., `((a*)(b*))*' against `aba' (register 3 would
+                     otherwise get trashed).  */
+                     
+                  if (EVER_MATCHED_SOMETHING (reg_info[*p]))
+		    {
+		      unsigned r; 
+        
+                      EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
+                      
+		      /* Restore this and inner groups' (if any) registers.  */
+                      for (r = *p; r < *p + *(p + 1); r++)
+                        {
+                          regstart[r] = old_regstart[r];
+
+                          /* xx why this test?  */
+                          if (old_regend[r] >= regstart[r])
+                            regend[r] = old_regend[r];
+                        }     
+                    }
+		  p1++;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+
+                  goto fail;
+                }
+            }
+          
+          /* Move past the register number and the inner group count.  */
+          p += 2;
+          break;
+
+
+	/* \<digit> has been turned into a `duplicate' command which is
+           followed by the numeric value of <digit> as the register number.  */
+        case duplicate:
+	  {
+	    register const char *d2, *dend2;
+	    int regno = *p++;   /* Get which register to match against.  */
+	    DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
+
+	    /* Can't back reference a group which we've never matched.  */
+            if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+              goto fail;
+              
+            /* Where in input to try to start matching.  */
+            d2 = regstart[regno];
+            
+            /* Where to stop matching; if both the place to start and
+               the place to stop matching are in the same string, then
+               set to the place to stop, otherwise, for now have to use
+               the end of the first string.  */
+
+            dend2 = ((FIRST_STRING_P (regstart[regno]) 
+		      == FIRST_STRING_P (regend[regno]))
+		     ? regend[regno] : end_match_1);
+	    for (;;)
+	      {
+		/* If necessary, advance to next segment in register
+                   contents.  */
+		while (d2 == dend2)
+		  {
+		    if (dend2 == end_match_2) break;
+		    if (dend2 == regend[regno]) break;
+
+                    /* End of string1 => advance to string2. */
+                    d2 = string2;
+                    dend2 = regend[regno];
+		  }
+		/* At end of register contents => success */
+		if (d2 == dend2) break;
+
+		/* If necessary, advance to next segment in data.  */
+		PREFETCH ();
+
+		/* How many characters left in this segment to match.  */
+		mcnt = dend - d;
+                
+		/* Want how many consecutive characters we can match in
+                   one shot, so, if necessary, adjust the count.  */
+                if (mcnt > dend2 - d2)
+		  mcnt = dend2 - d2;
+                  
+		/* Compare that many; failure if mismatch, else move
+                   past them.  */
+		if (translate 
+                    ? bcmp_translate (d, d2, mcnt, translate) 
+                    : bcmp (d, d2, mcnt))
+		  goto fail;
+		d += mcnt, d2 += mcnt;
+
+		/* Do this because we've match some characters.  */
+		SET_REGS_MATCHED ();
+	      }
+	  }
+	  break;
+
+
+        /* begline matches the empty string at the beginning of the string
+           (unless `not_bol' is set in `bufp'), and, if
+           `newline_anchor' is set, after newlines.  */
+	case begline:
+          DEBUG_PRINT1 ("EXECUTING begline.\n");
+          
+          if (AT_STRINGS_BEG (d))
+            {
+              if (!bufp->not_bol) break;
+            }
+          else if (d[-1] == '\n' && bufp->newline_anchor)
+            {
+              break;
+            }
+          /* In all other cases, we fail.  */
+          goto fail;
+
+
+        /* endline is the dual of begline.  */
+	case endline:
+          DEBUG_PRINT1 ("EXECUTING endline.\n");
+
+          if (AT_STRINGS_END (d))
+            {
+              if (!bufp->not_eol) break;
+            }
+          
+          /* We have to ``prefetch'' the next character.  */
+          else if ((d == end1 ? *string2 : *d) == '\n'
+                   && bufp->newline_anchor)
+            {
+              break;
+            }
+          goto fail;
+
+
+	/* Match at the very beginning of the data.  */
+        case begbuf:
+          DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+          if (AT_STRINGS_BEG (d))
+            break;
+          goto fail;
+
+
+	/* Match at the very end of the data.  */
+        case endbuf:
+          DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+	  if (AT_STRINGS_END (d))
+	    break;
+          goto fail;
+
+
+        /* on_failure_keep_string_jump is used to optimize `.*\n'.  It
+           pushes NULL as the value for the string on the stack.  Then
+           `pop_failure_point' will keep the current value for the
+           string, instead of restoring it.  To see why, consider
+           matching `foo\nbar' against `.*\n'.  The .* matches the foo;
+           then the . fails against the \n.  But the next thing we want
+           to do is match the \n against the \n; if we restored the
+           string value, we would be back at the foo.
+           
+           Because this is used only in specific cases, we don't need to
+           check all the things that `on_failure_jump' does, to make
+           sure the right things get saved on the stack.  Hence we don't
+           share its code.  The only reason to push anything on the
+           stack at all is that otherwise we would have to change
+           `anychar's code to do something besides goto fail in this
+           case; that seems worse than this.  */
+        case on_failure_keep_string_jump:
+          DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+          
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+          DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+
+          PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+          break;
+
+
+	/* Uses of on_failure_jump:
+        
+           Each alternative starts with an on_failure_jump that points
+           to the beginning of the next alternative.  Each alternative
+           except the last ends with a jump that in effect jumps past
+           the rest of the alternatives.  (They really jump to the
+           ending jump of the following alternative, because tensioning
+           these jumps is a hassle.)
+
+           Repeats start with an on_failure_jump that points past both
+           the repetition text and either the following jump or
+           pop_failure_jump back to this on_failure_jump.  */
+	case on_failure_jump:
+        on_failure:
+          DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+          DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+
+          /* If this on_failure_jump comes right before a group (i.e.,
+             the original * applied to a group), save the information
+             for that group and all inner ones, so that if we fail back
+             to this point, the group's information will be correct.
+             For example, in \(a*\)*\1, we need the preceding group,
+             and in \(\(a*\)b*\)\2, we need the inner group.  */
+
+          /* We can't use `p' to check ahead because we push
+             a failure point to `p + mcnt' after we do this.  */
+          p1 = p;
+
+          /* We need to skip no_op's before we look for the
+             start_memory in case this on_failure_jump is happening as
+             the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+             against aba.  */
+          while (p1 < pend && (re_opcode_t) *p1 == no_op)
+            p1++;
+
+          if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+            {
+              /* We have a new highest active register now.  This will
+                 get reset at the start_memory we are about to get to,
+                 but we will have saved all the registers relevant to
+                 this repetition op, as described above.  */
+              highest_active_reg = *(p1 + 1) + *(p1 + 2);
+              if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+                lowest_active_reg = *(p1 + 1);
+            }
+
+          DEBUG_PRINT1 (":\n");
+          PUSH_FAILURE_POINT (p + mcnt, d, -2);
+          break;
+
+
+        /* A smart repeat ends with `maybe_pop_jump'.
+	   We change it to either `pop_failure_jump' or `jump'.  */
+        case maybe_pop_jump:
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+          DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+          {
+	    register unsigned char *p2 = p;
+
+            /* Compare the beginning of the repeat with what in the
+               pattern follows its end. If we can establish that there
+               is nothing that they would both match, i.e., that we
+               would have to backtrack because of (as in, e.g., `a*a')
+               then we can change to pop_failure_jump, because we'll
+               never have to backtrack.
+               
+               This is not true in the case of alternatives: in
+               `(a|ab)*' we do need to backtrack to the `ab' alternative
+               (e.g., if the string was `ab').  But instead of trying to
+               detect that here, the alternative has put on a dummy
+               failure point which is what we will end up popping.  */
+
+	    /* Skip over open/close-group commands.
+	       If what follows this loop is a ...+ construct,
+	       look at what begins its body, since we will have to
+	       match at least one of that.  */
+	    while (1)
+	      {
+		if (p2 + 2 < pend
+		    && ((re_opcode_t) *p2 == stop_memory
+			|| (re_opcode_t) *p2 == start_memory))
+		  p2 += 3;
+		else if (p2 + 6 < pend
+			 && (re_opcode_t) *p2 == dummy_failure_jump)
+		  p2 += 6;
+		else
+		  break;
+	      }
+
+	    p1 = p + mcnt;
+	    /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+	       to the `maybe_finalize_jump' of this case.  Examine what 
+	       follows.  */
+
+            /* If we're at the end of the pattern, we can change.  */
+            if (p2 == pend)
+	      {
+		/* Consider what happens when matching ":\(.*\)"
+		   against ":/".  I don't really understand this code
+		   yet.  */
+  	        p[-3] = (unsigned char) pop_failure_jump;
+                DEBUG_PRINT1
+                  ("  End of pattern: change to `pop_failure_jump'.\n");
+              }
+
+            else if ((re_opcode_t) *p2 == exactn
+		     || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
+	      {
+		register unsigned char c
+                  = *p2 == (unsigned char) endline ? '\n' : p2[2];
+
+                if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+                  {
+  		    p[-3] = (unsigned char) pop_failure_jump;
+                    DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
+                                  c, p1[5]);
+                  }
+                  
+		else if ((re_opcode_t) p1[3] == charset
+			 || (re_opcode_t) p1[3] == charset_not)
+		  {
+		    int not = (re_opcode_t) p1[3] == charset_not;
+                    
+		    if (c < (unsigned char) (p1[4] * BYTEWIDTH)
+			&& p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+		      not = !not;
+
+                    /* `not' is equal to 1 if c would match, which means
+                        that we can't change to pop_failure_jump.  */
+		    if (!not)
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+	      }
+            else if ((re_opcode_t) *p2 == charset)
+	      {
+#ifdef DEBUG
+		register unsigned char c
+                  = *p2 == (unsigned char) endline ? '\n' : p2[2];
+#endif
+
+                if ((re_opcode_t) p1[3] == exactn
+		    && ! ((int) p2[1] * BYTEWIDTH > (int) p1[4]
+			  && (p2[1 + p1[4] / BYTEWIDTH]
+			      & (1 << (p1[4] % BYTEWIDTH)))))
+                  {
+  		    p[-3] = (unsigned char) pop_failure_jump;
+                    DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
+                                  c, p1[5]);
+                  }
+                  
+		else if ((re_opcode_t) p1[3] == charset_not)
+		  {
+		    int idx;
+		    /* We win if the charset_not inside the loop
+		       lists every character listed in the charset after.  */
+		    for (idx = 0; idx < (int) p2[1]; idx++)
+		      if (! (p2[2 + idx] == 0
+			     || (idx < (int) p1[4]
+				 && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
+			break;
+
+		    if (idx == p2[1])
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+		else if ((re_opcode_t) p1[3] == charset)
+		  {
+		    int idx;
+		    /* We win if the charset inside the loop
+		       has no overlap with the one after the loop.  */
+		    for (idx = 0;
+			 idx < (int) p2[1] && idx < (int) p1[4];
+			 idx++)
+		      if ((p2[2 + idx] & p1[5 + idx]) != 0)
+			break;
+
+		    if (idx == p2[1] || idx == p1[4])
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+	      }
+	  }
+	  p -= 2;		/* Point at relative address again.  */
+	  if ((re_opcode_t) p[-1] != pop_failure_jump)
+	    {
+	      p[-1] = (unsigned char) jump;
+              DEBUG_PRINT1 ("  Match => jump.\n");
+	      goto unconditional_jump;
+	    }
+        /* Note fall through.  */
+
+
+	/* The end of a simple repeat has a pop_failure_jump back to
+           its matching on_failure_jump, where the latter will push a
+           failure point.  The pop_failure_jump takes off failure
+           points put on by this pop_failure_jump's matching
+           on_failure_jump; we got through the pattern to here from the
+           matching on_failure_jump, so didn't fail.  */
+        case pop_failure_jump:
+          {
+            /* We need to pass separate storage for the lowest and
+               highest registers, even though we don't care about the
+               actual values.  Otherwise, we will restore only one
+               register from the stack, since lowest will == highest in
+               `pop_failure_point'.  */
+            unsigned dummy_low_reg, dummy_high_reg;
+            unsigned char *pdummy;
+            const char *sdummy;
+
+            DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+            POP_FAILURE_POINT (sdummy, pdummy,
+                               dummy_low_reg, dummy_high_reg,
+                               reg_dummy, reg_dummy, reg_info_dummy);
+          }
+          /* Note fall through.  */
+
+          
+        /* Unconditionally jump (without popping any failure points).  */
+        case jump:
+	unconditional_jump:
+	  EXTRACT_NUMBER_AND_INCR (mcnt, p);	/* Get the amount to jump.  */
+          DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+	  p += mcnt;				/* Do the jump.  */
+          DEBUG_PRINT2 ("(to 0x%x).\n", p);
+	  break;
+
+	
+        /* We need this opcode so we can detect where alternatives end
+           in `group_match_null_string_p' et al.  */
+        case jump_past_alt:
+          DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+          goto unconditional_jump;
+
+
+        /* Normally, the on_failure_jump pushes a failure point, which
+           then gets popped at pop_failure_jump.  We will end up at
+           pop_failure_jump, also, and with a pattern of, say, `a+', we
+           are skipping over the on_failure_jump, so we have to push
+           something meaningless for pop_failure_jump to pop.  */
+        case dummy_failure_jump:
+          DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+          /* It doesn't matter what we push for the string here.  What
+             the code at `fail' tests is the value for the pattern.  */
+          PUSH_FAILURE_POINT (0, 0, -2);
+          goto unconditional_jump;
+
+
+        /* At the end of an alternative, we need to push a dummy failure
+           point in case we are followed by a `pop_failure_jump', because
+           we don't want the failure point for the alternative to be
+           popped.  For example, matching `(a|ab)*' against `aab'
+           requires that we match the `ab' alternative.  */
+        case push_dummy_failure:
+          DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+          /* See comments just above at `dummy_failure_jump' about the
+             two zeroes.  */
+          PUSH_FAILURE_POINT (0, 0, -2);
+          break;
+
+        /* Have to succeed matching what follows at least n times.
+           After that, handle like `on_failure_jump'.  */
+        case succeed_n: 
+          EXTRACT_NUMBER (mcnt, p + 2);
+          DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+          assert (mcnt >= 0);
+          /* Originally, this is how many times we HAVE to succeed.  */
+          if (mcnt > 0)
+            {
+               mcnt--;
+	       p += 2;
+               STORE_NUMBER_AND_INCR (p, mcnt);
+               DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p, mcnt);
+            }
+	  else if (mcnt == 0)
+            {
+              DEBUG_PRINT2 ("  Setting two bytes from 0x%x to no_op.\n", p+2);
+	      p[2] = (unsigned char) no_op;
+              p[3] = (unsigned char) no_op;
+              goto on_failure;
+            }
+          break;
+        
+        case jump_n: 
+          EXTRACT_NUMBER (mcnt, p + 2);
+          DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
+          /* Originally, this is how many times we CAN jump.  */
+          if (mcnt)
+            {
+               mcnt--;
+               STORE_NUMBER (p + 2, mcnt);
+	       goto unconditional_jump;	     
+            }
+          /* If don't have to jump any more, skip over the rest of command.  */
+	  else      
+	    p += 4;		     
+          break;
+        
+	case set_number_at:
+	  {
+            DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
+
+            EXTRACT_NUMBER_AND_INCR (mcnt, p);
+            p1 = p + mcnt;
+            EXTRACT_NUMBER_AND_INCR (mcnt, p);
+            DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p1, mcnt);
+	    STORE_NUMBER (p1, mcnt);
+            break;
+          }
+
+        case wordbound:
+          DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+          if (AT_WORD_BOUNDARY (d))
+	    break;
+          goto fail;
+
+	case notwordbound:
+          DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+	  if (AT_WORD_BOUNDARY (d))
+	    goto fail;
+          break;
+
+	case wordbeg:
+          DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+	  if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
+	    break;
+          goto fail;
+
+	case wordend:
+          DEBUG_PRINT1 ("EXECUTING wordend.\n");
+	  if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+              && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
+	    break;
+          goto fail;
+
+#ifdef emacs
+  	case before_dot:
+          DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+ 	  if (PTR_CHAR_POS ((unsigned char *) d) >= point)
+  	    goto fail;
+  	  break;
+  
+  	case at_dot:
+          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ 	  if (PTR_CHAR_POS ((unsigned char *) d) != point)
+  	    goto fail;
+  	  break;
+  
+  	case after_dot:
+          DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+          if (PTR_CHAR_POS ((unsigned char *) d) <= point)
+  	    goto fail;
+  	  break;
+#if 0 /* not emacs19 */
+	case at_dot:
+          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+	  if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
+	    goto fail;
+	  break;
+#endif /* not emacs19 */
+
+	case syntaxspec:
+          DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
+	  mcnt = *p++;
+	  goto matchsyntax;
+
+        case wordchar:
+          DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
+	  mcnt = (int) Sword;
+        matchsyntax:
+	  PREFETCH ();
+	  /* Can't use *d++ here; SYNTAX may be an unsafe macro.  */
+	  d++;
+	  if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
+	    goto fail;
+          SET_REGS_MATCHED ();
+	  break;
+
+	case notsyntaxspec:
+          DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
+	  mcnt = *p++;
+	  goto matchnotsyntax;
+
+        case notwordchar:
+          DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+	  mcnt = (int) Sword;
+        matchnotsyntax:
+	  PREFETCH ();
+	  /* Can't use *d++ here; SYNTAX may be an unsafe macro.  */
+	  d++;
+	  if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
+	    goto fail;
+	  SET_REGS_MATCHED ();
+          break;
+
+#else /* not emacs */
+	case wordchar:
+          DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+	  PREFETCH ();
+          if (!WORDCHAR_P (d))
+            goto fail;
+	  SET_REGS_MATCHED ();
+          d++;
+	  break;
+	  
+	case notwordchar:
+          DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+	  PREFETCH ();
+	  if (WORDCHAR_P (d))
+            goto fail;
+          SET_REGS_MATCHED ();
+          d++;
+	  break;
+#endif /* not emacs */
+          
+        default:
+          abort ();
+	}
+      continue;  /* Successfully executed one pattern command; keep going.  */
+
+
+    /* We goto here if a matching operation fails. */
+    fail:
+      if (!FAIL_STACK_EMPTY ())
+	{ /* A restart point is known.  Restore to that state.  */
+          DEBUG_PRINT1 ("\nFAIL:\n");
+          POP_FAILURE_POINT (d, p,
+                             lowest_active_reg, highest_active_reg,
+                             regstart, regend, reg_info);
+
+          /* If this failure point is a dummy, try the next one.  */
+          if (!p)
+	    goto fail;
+
+          /* If we failed to the end of the pattern, don't examine *p.  */
+	  assert (p <= pend);
+          if (p < pend)
+            {
+              boolean is_a_jump_n = false;
+              
+              /* If failed to a backwards jump that's part of a repetition
+                 loop, need to pop this failure point and use the next one.  */
+              switch ((re_opcode_t) *p)
+                {
+                case jump_n:
+                  is_a_jump_n = true;
+                case maybe_pop_jump:
+                case pop_failure_jump:
+                case jump:
+                  p1 = p + 1;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  p1 += mcnt;	
+
+                  if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+                      || (!is_a_jump_n
+                          && (re_opcode_t) *p1 == on_failure_jump))
+                    goto fail;
+                  break;
+                default:
+                  /* do nothing */ ;
+                }
+            }
+
+          if (d >= string1 && d <= end1)
+	    dend = end_match_1;
+        }
+      else
+        break;   /* Matching at this starting point really fails.  */
+    } /* for (;;) */
+
+  if (best_regs_set)
+    goto restore_best_regs;
+
+  FREE_VARIABLES ();
+
+  return -1;         			/* Failure to match.  */
+} /* re_match_2 */
+
+
+/* Subroutine definitions for re_match_2.  */
+
+
+/* We are passed P pointing to a register number after a start_memory.
+   
+   Return true if the pattern up to the corresponding stop_memory can
+   match the empty string, and false otherwise.
+   
+   If we find the matching stop_memory, sets P to point to one past its number.
+   Otherwise, sets P to an undefined byte less than or equal to END.
+
+   We don't handle duplicates properly (yet).  */
+
+static boolean
+group_match_null_string_p (p, end, reg_info)
+    unsigned char **p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  /* Point to after the args to the start_memory.  */
+  unsigned char *p1 = *p + 2;
+  
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and return true or
+	 false, as appropriate, when we get to one that can't, or to the
+         matching stop_memory.  */
+      
+      switch ((re_opcode_t) *p1)
+        {
+        /* Could be either a loop or a series of alternatives.  */
+        case on_failure_jump:
+          p1++;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          
+          /* If the next operation is not a jump backwards in the
+	     pattern.  */
+
+	  if (mcnt >= 0)
+	    {
+              /* Go through the on_failure_jumps of the alternatives,
+                 seeing if any of the alternatives cannot match nothing.
+                 The last alternative starts with only a jump,
+                 whereas the rest start with on_failure_jump and end
+                 with a jump, e.g., here is the pattern for `a|b|c':
+
+                 /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
+                 /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
+                 /exactn/1/c						
+
+                 So, we have to first go through the first (n-1)
+                 alternatives and then deal with the last one separately.  */
+
+
+              /* Deal with the first (n-1) alternatives, which start
+                 with an on_failure_jump (see above) that jumps to right
+                 past a jump_past_alt.  */
+
+              while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
+                {
+                  /* `mcnt' holds how many bytes long the alternative
+                     is, including the ending `jump_past_alt' and
+                     its number.  */
+
+                  if (!alt_match_null_string_p (p1, p1 + mcnt - 3, 
+				                      reg_info))
+                    return false;
+
+                  /* Move to right after this alternative, including the
+		     jump_past_alt.  */
+                  p1 += mcnt;	
+
+                  /* Break if it's the beginning of an n-th alternative
+                     that doesn't begin with an on_failure_jump.  */
+                  if ((re_opcode_t) *p1 != on_failure_jump)
+                    break;
+		
+		  /* Still have to check that it's not an n-th
+		     alternative that starts with an on_failure_jump.  */
+		  p1++;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
+                    {
+		      /* Get to the beginning of the n-th alternative.  */
+                      p1 -= 3;
+                      break;
+                    }
+                }
+
+              /* Deal with the last alternative: go back and get number
+                 of the `jump_past_alt' just before it.  `mcnt' contains
+                 the length of the alternative.  */
+              EXTRACT_NUMBER (mcnt, p1 - 2);
+
+              if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
+                return false;
+
+              p1 += mcnt;	/* Get past the n-th alternative.  */
+            } /* if mcnt > 0 */
+          break;
+
+          
+        case stop_memory:
+	  assert (p1[1] == **p);
+          *p = p1 + 2;
+          return true;
+
+        
+        default: 
+          if (!common_op_match_null_string_p (&p1, end, reg_info))
+            return false;
+        }
+    } /* while p1 < end */
+
+  return false;
+} /* group_match_null_string_p */
+
+
+/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
+   It expects P to be the first byte of a single alternative and END one
+   byte past the last. The alternative can contain groups.  */
+   
+static boolean
+alt_match_null_string_p (p, end, reg_info)
+    unsigned char *p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  unsigned char *p1 = p;
+  
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and break when we get 
+         to one that can't.  */
+      
+      switch ((re_opcode_t) *p1)
+        {
+	/* It's a loop.  */
+        case on_failure_jump:
+          p1++;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          p1 += mcnt;
+          break;
+          
+	default: 
+          if (!common_op_match_null_string_p (&p1, end, reg_info))
+            return false;
+        }
+    }  /* while p1 < end */
+
+  return true;
+} /* alt_match_null_string_p */
+
+
+/* Deals with the ops common to group_match_null_string_p and
+   alt_match_null_string_p.  
+   
+   Sets P to one after the op and its arguments, if any.  */
+
+static boolean
+common_op_match_null_string_p (p, end, reg_info)
+    unsigned char **p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  boolean ret;
+  int reg_no;
+  unsigned char *p1 = *p;
+
+  switch ((re_opcode_t) *p1++)
+    {
+    case no_op:
+    case begline:
+    case endline:
+    case begbuf:
+    case endbuf:
+    case wordbeg:
+    case wordend:
+    case wordbound:
+    case notwordbound:
+#ifdef emacs
+    case before_dot:
+    case at_dot:
+    case after_dot:
+#endif
+      break;
+
+    case start_memory:
+      reg_no = *p1;
+      assert (reg_no > 0 && reg_no <= MAX_REGNUM);
+      ret = group_match_null_string_p (&p1, end, reg_info);
+      
+      /* Have to set this here in case we're checking a group which
+         contains a group and a back reference to it.  */
+
+      if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
+        REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+
+      if (!ret)
+        return false;
+      break;
+          
+    /* If this is an optimized succeed_n for zero times, make the jump.  */
+    case jump:
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+      if (mcnt >= 0)
+        p1 += mcnt;
+      else
+        return false;
+      break;
+
+    case succeed_n:
+      /* Get to the number of times to succeed.  */
+      p1 += 2;		
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+      if (mcnt == 0)
+        {
+          p1 -= 4;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          p1 += mcnt;
+        }
+      else
+        return false;
+      break;
+
+    case duplicate: 
+      if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+        return false;
+      break;
+
+    case set_number_at:
+      p1 += 4;
+
+    default:
+      /* All other opcodes mean we cannot match the empty string.  */
+      return false;
+  }
+
+  *p = p1;
+  return true;
+} /* common_op_match_null_string_p */
+
+
+/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
+   bytes; nonzero otherwise.  */
+   
+static int
+bcmp_translate (s1, s2, len, translate)
+     unsigned char *s1, *s2;
+     register int len;
+     char *translate;
+{
+  register unsigned char *p1 = s1, *p2 = s2;
+  while (len)
+    {
+      if (translate[*p1++] != translate[*p2++]) return 1;
+      len--;
+    }
+  return 0;
+}
+
+
+/* Entry points for GNU code.  */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+   compiles PATTERN (of length SIZE) and puts the result in BUFP.
+   Returns 0 if the pattern was valid, otherwise an error string.
+   
+   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+   are set in BUFP on entry.
+   
+   We call regex_compile to do the actual compilation.  */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+     const char *pattern;
+     int length;
+     struct re_pattern_buffer *bufp;
+{
+  reg_errcode_t ret;
+  
+  /* GNU code is written to assume at least RE_NREGS registers will be set
+     (and at least one extra will be -1).  */
+  bufp->regs_allocated = REGS_UNALLOCATED;
+  
+  /* And GNU code determines whether or not to get register information
+     by passing null for the REGS argument to re_match, etc., not by
+     setting no_sub.  */
+  bufp->no_sub = 0;
+  
+  /* Match anchors at newline.  */
+  bufp->newline_anchor = 1;
+  
+  ret = regex_compile (pattern, length, re_syntax_options, bufp);
+
+  if (!ret)
+    return NULL;
+  return gettext (re_error_msgid[(int) ret]);
+}     
+
+
+/* Entry points compatible with 4.2 BSD regex library.  We don't define
+   them unless specifically requested.  */
+
+#ifdef _REGEX_RE_COMP
+
+/* BSD has one and only one pattern buffer.  */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+re_comp (s)
+    const char *s;
+{
+  reg_errcode_t ret;
+  
+  if (!s)
+    {
+      if (!re_comp_buf.buffer)
+	return gettext ("No previous regular expression");
+      return 0;
+    }
+
+  if (!re_comp_buf.buffer)
+    {
+      re_comp_buf.buffer = (unsigned char *) malloc (200);
+      if (re_comp_buf.buffer == NULL)
+        return gettext (re_error_msgid[(int) REG_ESPACE]);
+      re_comp_buf.allocated = 200;
+
+      re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+      if (re_comp_buf.fastmap == NULL)
+	return gettext (re_error_msgid[(int) REG_ESPACE]);
+    }
+
+  /* Since `re_exec' always passes NULL for the `regs' argument, we
+     don't need to initialize the pattern buffer fields which affect it.  */
+
+  /* Match anchors at newlines.  */
+  re_comp_buf.newline_anchor = 1;
+
+  ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+  
+  if (!ret)
+    return NULL;
+
+  /* Yes, we're discarding `const' here if !HAVE_LIBINTL.  */
+  return (char *) gettext (re_error_msgid[(int) ret]);
+}
+
+
+int
+re_exec (s)
+    const char *s;
+{
+  const int len = strlen (s);
+  return
+    0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+#endif /* _REGEX_RE_COMP */
+
+
+/* POSIX.2 functions.  Don't define these for Emacs.  */
+
+#ifndef emacs
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+   PREG is a regex_t *.  We do not expect any fields to be initialized,
+   since POSIX says we shouldn't.  Thus, we set
+
+     `buffer' to the compiled pattern;
+     `used' to the length of the compiled pattern;
+     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+       REG_EXTENDED bit in CFLAGS is set; otherwise, to
+       RE_SYNTAX_POSIX_BASIC;
+     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+     `fastmap' and `fastmap_accurate' to zero;
+     `re_nsub' to the number of subexpressions in PATTERN.
+
+   PATTERN is the address of the pattern string.
+
+   CFLAGS is a series of bits which affect compilation.
+
+     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+     use POSIX basic syntax.
+
+     If REG_NEWLINE is set, then . and [^...] don't match newline.
+     Also, regexec will try a match beginning after every newline.
+
+     If REG_ICASE is set, then we considers upper- and lowercase
+     versions of letters to be equivalent when matching.
+
+     If REG_NOSUB is set, then when PREG is passed to regexec, that
+     routine will report only success or failure, and nothing about the
+     registers.
+
+   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
+   the return codes and their meanings.)  */
+
+int
+regcomp (preg, pattern, cflags)
+    regex_t *preg;
+    const char *pattern; 
+    int cflags;
+{
+  reg_errcode_t ret;
+  unsigned syntax
+    = (cflags & REG_EXTENDED) ?
+      RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+  /* regex_compile will allocate the space for the compiled pattern.  */
+  preg->buffer = 0;
+  preg->allocated = 0;
+  preg->used = 0;
+  
+  /* Don't bother to use a fastmap when searching.  This simplifies the
+     REG_NEWLINE case: if we used a fastmap, we'd have to put all the
+     characters after newlines into the fastmap.  This way, we just try
+     every character.  */
+  preg->fastmap = 0;
+  
+  if (cflags & REG_ICASE)
+    {
+      unsigned i;
+      
+      preg->translate = (char *) malloc (CHAR_SET_SIZE);
+      if (preg->translate == NULL)
+        return (int) REG_ESPACE;
+
+      /* Map uppercase characters to corresponding lowercase ones.  */
+      for (i = 0; i < CHAR_SET_SIZE; i++)
+        preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
+    }
+  else
+    preg->translate = NULL;
+
+  /* If REG_NEWLINE is set, newlines are treated differently.  */
+  if (cflags & REG_NEWLINE)
+    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
+      syntax &= ~RE_DOT_NEWLINE;
+      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+      /* It also changes the matching behavior.  */
+      preg->newline_anchor = 1;
+    }
+  else
+    preg->newline_anchor = 0;
+
+  preg->no_sub = !!(cflags & REG_NOSUB);
+
+  /* POSIX says a null character in the pattern terminates it, so we 
+     can use strlen here in compiling the pattern.  */
+  ret = regex_compile (pattern, strlen (pattern), syntax, preg);
+  
+  /* POSIX doesn't distinguish between an unmatched open-group and an
+     unmatched close-group: both are REG_EPAREN.  */
+  if (ret == REG_ERPAREN) ret = REG_EPAREN;
+  
+  return (int) ret;
+}
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+   string STRING.
+   
+   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
+   least NMATCH elements, and we set them to the offsets of the
+   corresponding matched substrings.
+   
+   EFLAGS specifies `execution flags' which affect matching: if
+   REG_NOTBOL is set, then ^ does not match at the beginning of the
+   string; if REG_NOTEOL is set, then $ does not match at the end.
+   
+   We return 0 if we find a match and REG_NOMATCH if not.  */
+
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+    const regex_t *preg;
+    const char *string; 
+    size_t nmatch; 
+    regmatch_t pmatch[]; 
+    int eflags;
+{
+  int ret;
+  struct re_registers regs;
+  regex_t private_preg;
+  int len = strlen (string);
+  boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+  private_preg = *preg;
+  
+  private_preg.not_bol = !!(eflags & REG_NOTBOL);
+  private_preg.not_eol = !!(eflags & REG_NOTEOL);
+  
+  /* The user has told us exactly how many registers to return
+     information about, via `nmatch'.  We have to pass that on to the
+     matching routines.  */
+  private_preg.regs_allocated = REGS_FIXED;
+  
+  if (want_reg_info)
+    {
+      regs.num_regs = nmatch;
+      regs.start = TALLOC (nmatch, regoff_t);
+      regs.end = TALLOC (nmatch, regoff_t);
+      if (regs.start == NULL || regs.end == NULL)
+        return (int) REG_NOMATCH;
+    }
+
+  /* Perform the searching operation.  */
+  ret = re_search (&private_preg, string, len,
+                   /* start: */ 0, /* range: */ len,
+                   want_reg_info ? &regs : (struct re_registers *) 0);
+  
+  /* Copy the register information to the POSIX structure.  */
+  if (want_reg_info)
+    {
+      if (ret >= 0)
+        {
+          unsigned r;
+
+          for (r = 0; r < nmatch; r++)
+            {
+              pmatch[r].rm_so = regs.start[r];
+              pmatch[r].rm_eo = regs.end[r];
+            }
+        }
+
+      /* If we needed the temporary register info, free the space now.  */
+      free (regs.start);
+      free (regs.end);
+    }
+
+  /* We want zero return to mean success, unlike `re_search'.  */
+  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+   from either regcomp or regexec.   We don't use PREG here.  */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+    int errcode;
+    const regex_t *preg;
+    char *errbuf;
+    size_t errbuf_size;
+{
+  const char *msg;
+  size_t msg_size;
+
+  if (errcode < 0
+      || errcode >= (sizeof (re_error_msgid) / sizeof (re_error_msgid[0])))
+    /* Only error codes returned by the rest of the code should be passed 
+       to this routine.  If we are given anything else, or if other regex
+       code generates an invalid error code, then the program has a bug.
+       Dump core so we can fix it.  */
+    abort ();
+
+  msg = gettext (re_error_msgid[errcode]);
+
+  msg_size = strlen (msg) + 1; /* Includes the null.  */
+  
+  if (errbuf_size != 0)
+    {
+      if (msg_size > errbuf_size)
+        {
+          strncpy (errbuf, msg, errbuf_size - 1);
+          errbuf[errbuf_size - 1] = 0;
+        }
+      else
+        strcpy (errbuf, msg);
+    }
+
+  return msg_size;
+}
+
+
+/* Free dynamically allocated space used by PREG.  */
+
+void
+regfree (preg)
+    regex_t *preg;
+{
+  if (preg->buffer != NULL)
+    free (preg->buffer);
+  preg->buffer = NULL;
+  
+  preg->allocated = 0;
+  preg->used = 0;
+
+  if (preg->fastmap != NULL)
+    free (preg->fastmap);
+  preg->fastmap = NULL;
+  preg->fastmap_accurate = 0;
+
+  if (preg->translate != NULL)
+    free (preg->translate);
+  preg->translate = NULL;
+}
+
+#endif /* not emacs  */
+
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/regex.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/regex.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/regex.h	(revision 10506)
@@ -0,0 +1,497 @@
+/* Definitions for data structures and routines for the regular
+   expression library, version 0.12.
+
+   Copyright (C) 1985, 89, 90, 91, 92, 93, 95 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+   <regex.h>.  */
+
+#if !defined (_POSIX_C_SOURCE) && !defined (_POSIX_SOURCE) && defined (VMS)
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+   should be there.  */
+#include <stddef.h>
+#endif
+
+
+/* The following bits are used to determine the regexp syntax we
+   recognize.  The set/not-set meanings are chosen so that Emacs syntax
+   remains the value 0.  The bits are given in alphabetical order, and
+   the definitions shifted by one from the previous bit; thus, when we
+   add or remove a bit, only one other definition need change.  */
+typedef unsigned reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+   If set, then such a \ quotes the following character.  */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+     literals. 
+   If set, then \+ and \? are operators and + and ? are literals.  */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported.  They are:
+     [:alpha:], [:upper:], [:lower:],  [:digit:], [:alnum:], [:xdigit:],
+     [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+   If not set, then character classes are not supported.  */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+     expressions, of course).
+   If this bit is not set, then it depends:
+        ^  is an anchor if it is at the beginning of a regular
+           expression or after an open-group or an alternation operator;
+        $  is an anchor if it is at the end of a regular expression, or
+           before a close-group or an alternation operator.  
+
+   This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+   POSIX draft 11.2 says that * etc. in leading positions is undefined.
+   We already implemented a previous draft which made those constructs
+   invalid, though, so we haven't changed the code back.  */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+     regardless of where they are in the pattern.
+   If this bit is not set, then special characters are special only in
+     some contexts; otherwise they are ordinary.  Specifically, 
+     * + ? and intervals are only special when not after the beginning,
+     open-group, or alternation operator.  */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+     immediately after an alternation or begin-group operator.  */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+   If not set, then it doesn't.  */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+   If not set, then it does.  */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+   If not set, they do.  */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+     interval, depending on RE_NO_BK_BRACES. 
+   If not set, \{, \}, {, and } are literals.  */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+   If not set, they are.  */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+   If not set, newline is literal.  */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+     are literals.
+  If not set, then `\{...\}' defines an interval.  */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+   If not set, \(...\) defines a group, and ( and ) are literals.  */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+   If not set, then \<digit> is a back-reference.  */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal. 
+   If not set, then \| is an alternation operator, and | is literal.  */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+     than the starting range point, as in [z-a], is invalid.
+   If not set, then when ending range point collates higher than the
+     starting range point, the range is ignored.  */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+   If not set, then an unmatched ) is invalid.  */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+   without further backtracking.  */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+   some interfaces).  When a regexp is compiled, the syntax used is
+   stored in the pattern buffer, so changing this does not affect
+   already-compiled regexps.  */
+extern reg_syntax_t re_syntax_options;
+
+
+/* Define combinations of the above bits for the standard possibilities.
+   (The [[[ comments delimit what gets put into the Texinfo file, so
+   don't delete them!)  */ 
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK							\
+  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL			\
+   | RE_NO_BK_PARENS            | RE_NO_BK_REFS				\
+   | RE_NO_BK_VBAR               | RE_NO_EMPTY_RANGES			\
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK 						\
+  (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP							\
+  (RE_BK_PLUS_QM              | RE_CHAR_CLASSES				\
+   | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS				\
+   | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP							\
+  (RE_CHAR_CLASSES        | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE			\
+   | RE_NEWLINE_ALT       | RE_NO_BK_PARENS				\
+   | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP						\
+  (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff.  */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax.  */
+#define _RE_SYNTAX_POSIX_COMMON						\
+  (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL		\
+   | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC						\
+  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+   RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
+   isn't minimal, since other operators, such as \`, aren't disabled.  */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC					\
+  (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED					\
+  (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INDEP_OPS  | RE_NO_BK_BRACES				\
+   | RE_NO_BK_PARENS       | RE_NO_BK_VBAR				\
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+   replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added.  */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED				\
+  (_RE_SYNTAX_POSIX_COMMON  | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES				\
+   | RE_NO_BK_PARENS        | RE_NO_BK_REFS				\
+   | RE_NO_BK_VBAR	    | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+
+/* Maximum number of duplicates an interval can allow.  Some systems
+   (erroneously) define this in other header files, but we want our
+   value, so remove any previous define.  */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1) 
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp').  */
+
+/* If this bit is set, then use extended regular expression syntax.
+   If not set, then use basic regular expression syntax.  */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+   If not set, then case is significant.  */
+#define REG_ICASE (REG_EXTENDED << 1)
+ 
+/* If this bit is set, then anchors do not match at newline
+     characters in the string.
+   If not set, then anchors do match at newlines.  */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+   If not set, then returns differ between not matching and errors.  */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec).  */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+     the beginning of the string (presumably because it's not the
+     beginning of a line).
+   If not set, then the beginning-of-line operator does match the
+     beginning of the string.  */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line.  */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+   `re_error_msg' table in regex.c.  */
+typedef enum
+{
+  REG_NOERROR = 0,	/* Success.  */
+  REG_NOMATCH,		/* Didn't find a match (for regexec).  */
+
+  /* POSIX regcomp return error codes.  (In the order listed in the
+     standard.)  */
+  REG_BADPAT,		/* Invalid pattern.  */
+  REG_ECOLLATE,		/* Not implemented.  */
+  REG_ECTYPE,		/* Invalid character class name.  */
+  REG_EESCAPE,		/* Trailing backslash.  */
+  REG_ESUBREG,		/* Invalid back reference.  */
+  REG_EBRACK,		/* Unmatched left bracket.  */
+  REG_EPAREN,		/* Parenthesis imbalance.  */ 
+  REG_EBRACE,		/* Unmatched \{.  */
+  REG_BADBR,		/* Invalid contents of \{\}.  */
+  REG_ERANGE,		/* Invalid range end.  */
+  REG_ESPACE,		/* Ran out of memory.  */
+  REG_BADRPT,		/* No preceding re for repetition op.  */
+
+  /* Error codes we've added.  */
+  REG_EEND,		/* Premature end.  */
+  REG_ESIZE,		/* Compiled pattern bigger than 2^16 bytes.  */
+  REG_ERPAREN		/* Unmatched ) or \); not returned from regcomp.  */
+} reg_errcode_t;
+
+
+/* This data structure represents a compiled pattern.  Before calling
+   the pattern compiler, the fields `buffer', `allocated', `fastmap',
+   `translate', and `no_sub' can be set.  After the pattern has been
+   compiled, the `re_nsub' field is available.  All other fields are
+   private to the regex routines.  */
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+	/* Space that holds the compiled pattern.  It is declared as
+          `unsigned char *' because its elements are
+           sometimes used as array indexes.  */
+  unsigned char *buffer;
+
+	/* Number of bytes to which `buffer' points.  */
+  unsigned long allocated;
+
+	/* Number of bytes actually used in `buffer'.  */
+  unsigned long used;	
+
+        /* Syntax setting with which the pattern was compiled.  */
+  reg_syntax_t syntax;
+
+        /* Pointer to a fastmap, if any, otherwise zero.  re_search uses
+           the fastmap, if there is one, to skip over impossible
+           starting points for matches.  */
+  char *fastmap;
+
+        /* Either a translate table to apply to all characters before
+           comparing them, or zero for no translation.  The translation
+           is applied to a pattern when it is compiled and to a string
+           when it is matched.  */
+  char *translate;
+
+	/* Number of subexpressions found by the compiler.  */
+  size_t re_nsub;
+
+        /* Zero if this pattern cannot match the empty string, one else.
+           Well, in truth it's used only in `re_search_2', to see
+           whether or not we should use the fastmap, so we don't set
+           this absolutely perfectly; see `re_compile_fastmap' (the
+           `duplicate' case).  */
+  unsigned can_be_null : 1;
+
+        /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+             for `max (RE_NREGS, re_nsub + 1)' groups.
+           If REGS_REALLOCATE, reallocate space if necessary.
+           If REGS_FIXED, use what's there.  */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+  unsigned regs_allocated : 2;
+
+        /* Set to zero when `regex_compile' compiles a pattern; set to one
+           by `re_compile_fastmap' if it updates the fastmap.  */
+  unsigned fastmap_accurate : 1;
+
+        /* If set, `re_match_2' does not return information about
+           subexpressions.  */
+  unsigned no_sub : 1;
+
+        /* If set, a beginning-of-line anchor doesn't match at the
+           beginning of the string.  */ 
+  unsigned not_bol : 1;
+
+        /* Similarly for an end-of-line anchor.  */
+  unsigned not_eol : 1;
+
+        /* If true, an anchor at a newline matches.  */
+  unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+/* Type for byte offsets within the string.  POSIX mandates this.  */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in.  See
+   regex.texinfo for a full description of what registers match.  */
+struct re_registers
+{
+  unsigned num_regs;
+  regoff_t *start;
+  regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+   `re_match_2' returns information about at least this many registers
+   the first time a `regs' structure is passed.  */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers.  Aside from the different names than
+   `re_registers', POSIX uses an array of structures, instead of a
+   structure of arrays.  */
+typedef struct
+{
+  regoff_t rm_so;  /* Byte offset from string's start to substring's start.  */
+  regoff_t rm_eo;  /* Byte offset from string's start to substring's end.  */
+} regmatch_t;
+
+
+/* Declarations for routines.  */
+
+/* To avoid duplicating every routine declaration -- once with a
+   prototype (if we are ANSI), and once without (if we aren't) -- we
+   use the following macro to declare argument types.  This
+   unfortunately clutters up the declarations a bit, but I think it's
+   worth it.  */
+
+#if __STDC__
+
+#define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+#define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+   You can also simply assign to the `re_syntax_options' variable.  */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+   and syntax given by the global `re_syntax_options', into the buffer
+   BUFFER.  Return NULL if successful, and an error string if not.  */
+extern const char *re_compile_pattern
+  _RE_ARGS ((const char *pattern, int length,
+             struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+   accelerate searches.  Return 0 if successful and -2 if was an
+   internal error.  */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+   compiled into BUFFER.  Start searching at position START, for RANGE
+   characters.  Return the starting position of the match, -1 for no
+   match, or -2 for an internal error.  Also return register
+   information in REGS (if REGS and BUFFER->no_sub are nonzero).  */
+extern int re_search
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+            int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+   STRING2.  Also, stop searching at index START + STOP.  */
+extern int re_search_2
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+             int length1, const char *string2, int length2,
+             int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+   in BUFFER matched, starting at position START.  */
+extern int re_match
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+             int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'.  */
+extern int re_match_2 
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+             int length1, const char *string2, int length2,
+             int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using BUFFER and REGS will use this memory
+   for recording register information.  STARTS and ENDS must be
+   allocated with malloc, and must each be at least `NUM_REGS * sizeof
+   (regoff_t)' bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+extern void re_set_registers
+  _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+             unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+#ifdef _REGEX_RE_COMP
+/* 4.2 bsd compatibility.  */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+#endif
+
+/* POSIX compatibility.  */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+  _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+             regmatch_t pmatch[], int eflags));
+extern size_t regerror
+  _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+             size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/rx.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/rx.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/rx.c	(revision 10506)
@@ -0,0 +1,7271 @@
+/*	Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of the librx library.
+
+Librx is free software; you can redistribute it and/or modify it under
+the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+Librx is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this software; see the file COPYING.LIB.  If not,
+write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA
+02139, USA.  */
+
+/* NOTE!!!  AIX is so losing it requires this to be the first thing in the 
+ * file. 
+ * Do not put ANYTHING before it!  
+ */
+#if !defined (__GNUC__) && defined (_AIX)
+ #pragma alloca
+#endif
+
+/* To make linux happy? */
+#ifndef	_GNU_SOURCE
+#define	_GNU_SOURCE
+#endif
+
+#if HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+#  include <malloc.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+
+
+char rx_version_string[] = "GNU Rx version 0.07.1";
+
+			/* ``Too hard!''
+			 *	    -- anon.
+			 */
+
+
+
+#include <stdio.h>
+#include <ctype.h>
+#ifndef isgraph
+#define isgraph(c) (isprint (c) && !isspace (c))
+#endif
+#ifndef isblank
+#define isblank(c) ((c) == ' ' || (c) == '\t')
+#endif
+
+#include <sys/types.h>
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+#ifndef __GCC__
+#undef __inline__
+#define __inline__
+#endif
+
+/* Emacs already defines alloca, sometimes.  */
+#ifndef alloca
+
+/* Make alloca work the best possible way.  */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else /* not __GNUC__ or HAVE_ALLOCA_H */
+#ifndef _AIX /* Already did AIX, up at the top.  */
+char *alloca ();
+#endif /* not _AIX */
+#endif /* not HAVE_ALLOCA_H */ 
+#endif /* not __GNUC__ */
+
+#endif /* not alloca */
+
+/* Memory management and stuff for emacs. */
+
+#define CHARBITS 8
+#define remalloc(M, S) (M ? realloc (M, S) : malloc (S))
+
+
+/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
+ * use `alloca' instead of `malloc' for the backtracking stack.
+ *
+ * Emacs will die miserably if we don't do this.
+ */
+
+#ifdef REGEX_MALLOC
+#define REGEX_ALLOCATE malloc
+#else /* not REGEX_MALLOC  */
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#define REGEX_ALLOCATE _alloca
+#else
+#define REGEX_ALLOCATE alloca
+#endif /* __WIN32__ */
+#endif /* not REGEX_MALLOC */
+
+
+#ifdef RX_WANT_RX_DEFS
+#define RX_DECL extern
+#define RX_DEF_QUAL 
+#else
+#define RX_WANT_RX_DEFS
+#define RX_DECL static
+#define RX_DEF_QUAL static
+#endif
+#include "rx.h"
+#undef RX_DECL
+#define RX_DECL RX_DEF_QUAL
+
+
+#ifndef emacs
+
+#ifdef SYNTAX_TABLE
+extern char *re_syntax_table;
+#else /* not SYNTAX_TABLE */
+
+#ifdef __STDC__
+static void
+init_syntax_once (void)
+#else
+static void
+init_syntax_once ()
+#endif
+{
+   register int c;
+   static int done = 0;
+
+   if (done)
+     return;
+
+   bzero (re_syntax_table, sizeof re_syntax_table);
+
+   for (c = 'a'; c <= 'z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = 'A'; c <= 'Z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = '0'; c <= '9'; c++)
+     re_syntax_table[c] = Sword;
+
+   re_syntax_table['_'] = Sword;
+
+   done = 1;
+}
+#endif /* not SYNTAX_TABLE */
+#endif /* not emacs */
+
+
+/* Compile with `-DRX_DEBUG' and use the following flags.
+ *
+ * Debugging flags:
+ *   	rx_debug - print information as a regexp is compiled
+ * 	rx_debug_trace - print information as a regexp is executed
+ */
+
+#ifdef RX_DEBUG
+
+int rx_debug_compile = 0;
+int rx_debug_trace = 0;
+static struct re_pattern_buffer * dbug_rxb = 0;
+
+#ifdef __STDC__
+typedef void (*side_effect_printer) (struct rx *, void *, FILE *);
+#else
+typedef void (*side_effect_printer) ();
+#endif
+
+#ifdef __STDC__
+static void print_cset (struct rx *rx, rx_Bitset cset, FILE * fp);
+#else
+static void print_cset ();
+#endif
+
+#ifdef __STDC__
+static void
+print_rexp (struct rx *rx,
+	    struct rexp_node *node, int depth,
+	    side_effect_printer seprint, FILE * fp)
+#else
+static void
+print_rexp (rx, node, depth, seprint, fp)
+     struct rx *rx;
+     struct rexp_node *node;
+     int depth;
+     side_effect_printer seprint;
+     FILE * fp;
+#endif
+{
+  if (!node)
+    return;
+  else
+    {
+      switch (node->type)
+	{
+	case r_cset:
+	  {
+	    fprintf (fp, "%*s", depth, "");
+	    print_cset (rx, node->params.cset, fp);
+	    fputc ('\n', fp);
+	    break;
+	  }
+
+ 	case r_opt:
+	case r_star:
+	  fprintf (fp, "%*s%s\n", depth, "",
+		   node->type == r_opt ? "opt" : "star");
+	  print_rexp (rx, node->params.pair.left, depth + 3, seprint, fp);
+	  break;
+
+	case r_2phase_star:
+	  fprintf (fp, "%*s2phase star\n", depth, "");
+	  print_rexp (rx, node->params.pair.right, depth + 3, seprint, fp);
+	  print_rexp (rx, node->params.pair.left, depth + 3, seprint, fp);
+	  break;
+
+
+	case r_alternate:
+	case r_concat:
+	  fprintf (fp, "%*s%s\n", depth, "",
+		   node->type == r_alternate ? "alt" : "concat");
+	  print_rexp (rx, node->params.pair.left, depth + 3, seprint, fp);
+	  print_rexp (rx, node->params.pair.right, depth + 3, seprint, fp);
+	  break;
+	case r_side_effect:
+	  fprintf (fp, "%*sSide effect: ", depth, "");
+	  seprint (rx, node->params.side_effect, fp);
+	  fputc ('\n', fp);
+	}
+    }
+}
+
+#ifdef __STDC__
+static void
+print_nfa (struct rx * rx,
+	   struct rx_nfa_state * n,
+	   side_effect_printer seprint, FILE * fp)
+#else
+static void
+print_nfa (rx, n, seprint, fp)
+     struct rx * rx;
+     struct rx_nfa_state * n;
+     side_effect_printer seprint;
+     FILE * fp;
+#endif
+{
+  while (n)
+    {
+      struct rx_nfa_edge *e = n->edges;
+      struct rx_possible_future *ec = n->futures;
+      fprintf (fp, "node %d %s\n", n->id,
+	       n->is_final ? "final" : (n->is_start ? "start" : ""));
+      while (e)
+	{
+	  fprintf (fp, "   edge to %d, ", e->dest->id);
+	  switch (e->type)
+	    {
+	    case ne_epsilon:
+	      fprintf (fp, "epsilon\n");
+	      break;
+	    case ne_side_effect:
+	      fprintf (fp, "side effect ");
+	      seprint (rx, e->params.side_effect, fp);
+	      fputc ('\n', fp);
+	      break;
+	    case ne_cset:
+	      fprintf (fp, "cset ");
+	      print_cset (rx, e->params.cset, fp);
+	      fputc ('\n', fp);
+	      break;
+	    }
+	  e = e->next;
+	}
+
+      while (ec)
+	{
+	  int x;
+	  struct rx_nfa_state_set * s;
+	  struct rx_se_list * l;
+	  fprintf (fp, "   eclosure to {");
+	  for (s = ec->destset; s; s = s->cdr)
+	    fprintf (fp, "%d ", s->car->id);
+	  fprintf (fp, "} (");
+	  for (l = ec->effects; l; l = l->cdr)
+	    {
+	      seprint (rx, l->car, fp);
+	      fputc (' ', fp);
+	    }
+	  fprintf (fp, ")\n");
+	  ec = ec->next;
+	}
+      n = n->next;
+    }
+}
+
+static char * efnames [] =
+{
+  "bogon",
+  "re_se_try",
+  "re_se_pushback",
+  "re_se_push0",
+  "re_se_pushpos",
+  "re_se_chkpos",
+  "re_se_poppos",
+  "re_se_at_dot",
+  "re_se_syntax",
+  "re_se_not_syntax",
+  "re_se_begbuf",
+  "re_se_hat",
+  "re_se_wordbeg",
+  "re_se_wordbound",
+  "re_se_notwordbound",
+  "re_se_wordend",
+  "re_se_endbuf",
+  "re_se_dollar",
+  "re_se_fail",
+};
+
+static char * efnames2[] =
+{
+  "re_se_win",
+  "re_se_lparen",
+  "re_se_rparen",
+  "re_se_backref",
+  "re_se_iter",
+  "re_se_end_iter",
+  "re_se_tv"
+};
+
+static char * inx_names[] = 
+{
+  "rx_backtrack_point",
+  "rx_do_side_effects",
+  "rx_cache_miss",
+  "rx_next_char",
+  "rx_backtrack",
+  "rx_error_inx",
+  "rx_num_instructions"
+};
+
+
+#ifdef __STDC__
+static void
+re_seprint (struct rx * rx, void * effect, FILE * fp)
+#else
+static void
+re_seprint (rx, effect, fp)
+     struct rx * rx;
+     void * effect;
+     FILE * fp;
+#endif
+{
+  if ((int)effect < 0)
+    fputs (efnames[-(int)effect], fp);
+  else if (dbug_rxb)
+    {
+      struct re_se_params * p = &dbug_rxb->se_params[(int)effect];
+      fprintf (fp, "%s(%d,%d)", efnames2[p->se], p->op1, p->op2);
+    }
+  else
+    fprintf (fp, "[complex op # %d]", (int)effect);
+}
+
+
+/* These are so the regex.c regression tests will compile. */
+void
+print_compiled_pattern (rxb)
+     struct re_pattern_buffer * rxb;
+{
+}
+
+void
+print_fastmap (fm)
+     char * fm;
+{
+}
+
+#endif /* RX_DEBUG */
+
+
+
+
+/* This page: Bitsets.  Completely unintersting. */
+
+#ifdef __STDC__
+RX_DECL int
+rx_bitset_is_equal (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL int
+rx_bitset_is_equal (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  RX_subset s = b[0];
+  b[0] = ~a[0];
+
+  for (x = rx_bitset_numb_subsets(size) - 1; a[x] == b[x]; --x)
+    ;
+
+  b[0] = s;
+  return !x && s == a[0];
+}
+
+#ifdef __STDC__
+RX_DECL int
+rx_bitset_is_subset (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL int
+rx_bitset_is_subset (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x = rx_bitset_numb_subsets(size) - 1;
+  while (x-- && (a[x] & b[x]) == a[x]);
+  return x == -1;
+}
+
+
+#ifdef __STDC__
+RX_DECL int
+rx_bitset_empty (int size, rx_Bitset set)
+#else
+RX_DECL int
+rx_bitset_empty (size, set)
+     int size;
+     rx_Bitset set;
+#endif
+{
+  int x;
+  RX_subset s = set[0];
+  set[0] = 1;
+  for (x = rx_bitset_numb_subsets(size) - 1; !set[x]; --x)
+    ;
+  set[0] = s;
+  return !s;
+}
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_null (int size, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_null (size, b)
+     int size;
+     rx_Bitset b;
+#endif
+{
+  bzero (b, rx_sizeof_bitset(size));
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_universe (int size, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_universe (size, b)
+     int size;
+     rx_Bitset b;
+#endif
+{
+  int x = rx_bitset_numb_subsets (size);
+  while (x--)
+    *b++ = ~(RX_subset)0;
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_complement (int size, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_complement (size, b)
+     int size;
+     rx_Bitset b;
+#endif
+{
+  int x = rx_bitset_numb_subsets (size);
+  while (x--)
+    {
+      *b = ~*b;
+      ++b;
+    }
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_assign (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_assign (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] = b[x];
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_union (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_union (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] |= b[x];
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_intersection (int size,
+			rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_intersection (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] &= b[x];
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_difference (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_difference (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] &=  ~ b[x];
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_revdifference (int size,
+			 rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_revdifference (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] = ~a[x] & b[x];
+}
+
+#ifdef __STDC__
+RX_DECL void
+rx_bitset_xor (int size, rx_Bitset a, rx_Bitset b)
+#else
+RX_DECL void
+rx_bitset_xor (size, a, b)
+     int size;
+     rx_Bitset a;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  for (x = rx_bitset_numb_subsets(size) - 1; x >=0; --x)
+    a[x] ^= b[x];
+}
+
+
+#ifdef __STDC__
+RX_DECL unsigned long
+rx_bitset_hash (int size, rx_Bitset b)
+#else
+RX_DECL unsigned long
+rx_bitset_hash (size, b)
+     int size;
+     rx_Bitset b;
+#endif
+{
+  int x;
+  unsigned long hash = (unsigned long)rx_bitset_hash;
+
+  for (x = rx_bitset_numb_subsets(size) - 1; x >= 0; --x)
+    hash ^= rx_bitset_subset_val(b, x);
+
+  return hash;
+}
+
+
+RX_DECL RX_subset rx_subset_singletons [RX_subset_bits] = 
+{
+  0x1,
+  0x2,
+  0x4,
+  0x8,
+  0x10,
+  0x20,
+  0x40,
+  0x80,
+  0x100,
+  0x200,
+  0x400,
+  0x800,
+  0x1000,
+  0x2000,
+  0x4000,
+  0x8000,
+  0x10000,
+  0x20000,
+  0x40000,
+  0x80000,
+  0x100000,
+  0x200000,
+  0x400000,
+  0x800000,
+  0x1000000,
+  0x2000000,
+  0x4000000,
+  0x8000000,
+  0x10000000,
+  0x20000000,
+  0x40000000,
+  0x80000000
+};
+
+#ifdef RX_DEBUG
+
+#ifdef __STDC__
+static void
+print_cset (struct rx *rx, rx_Bitset cset, FILE * fp)
+#else
+static void
+print_cset (rx, cset, fp)
+     struct rx *rx;
+     rx_Bitset cset;
+     FILE * fp;
+#endif
+{
+  int x;
+  fputc ('[', fp);
+  for (x = 0; x < rx->local_cset_size; ++x)
+    if (RX_bitset_member (cset, x))
+      {
+	if (isprint(x))
+	  fputc (x, fp);
+	else
+	  fprintf (fp, "\\0%o ", x);
+      }
+  fputc (']', fp);
+}
+
+#endif /*  RX_DEBUG */
+
+
+
+
+static unsigned long rx_hash_masks[4] =
+{
+  0x12488421,
+  0x96699669,
+  0xbe7dd7eb,
+  0xffffffff
+};
+
+
+/* Hash tables */
+#ifdef __STDC__
+RX_DECL struct rx_hash_item * 
+rx_hash_find (struct rx_hash * table,
+	      unsigned long hash,
+	      void * value,
+	      struct rx_hash_rules * rules)
+#else
+RX_DECL struct rx_hash_item * 
+rx_hash_find (table, hash, value, rules)
+     struct rx_hash * table;
+     unsigned long hash;
+     void * value;
+     struct rx_hash_rules * rules;
+#endif
+{
+  rx_hash_eq eq = rules->eq;
+  int maskc = 0;
+  long mask = rx_hash_masks [0];
+  int bucket = (hash & mask) % 13;
+
+  while (table->children [bucket])
+    {
+      table = table->children [bucket];
+      ++maskc;
+      mask = rx_hash_masks[maskc];
+      bucket = (hash & mask) % 13;
+    }
+
+  {
+    struct rx_hash_item * it = table->buckets[bucket];
+    while (it)
+      if (eq (it->data, value))
+	return it;
+      else
+	it = it->next_same_hash;
+  }
+
+  return 0;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rx_hash_item *
+rx_hash_store (struct rx_hash * table,
+	       unsigned long hash,
+	       void * value,
+	       struct rx_hash_rules * rules)
+#else
+RX_DECL struct rx_hash_item *
+rx_hash_store (table, hash, value, rules)
+     struct rx_hash * table;
+     unsigned long hash;
+     void * value;
+     struct rx_hash_rules * rules;
+#endif
+{
+  rx_hash_eq eq = rules->eq;
+  int maskc = 0;
+  long mask = rx_hash_masks[0];
+  int bucket = (hash & mask) % 13;
+  int depth = 0;
+  
+  while (table->children [bucket])
+    {
+      table = table->children [bucket];
+      ++maskc;
+      mask = rx_hash_masks[maskc];
+      bucket = (hash & mask) % 13;
+      ++depth;
+    }
+  
+  {
+    struct rx_hash_item * it = table->buckets[bucket];
+    while (it)
+      if (eq (it->data, value))
+	return it;
+      else
+	it = it->next_same_hash;
+  }
+  
+  {
+    if (   (depth < 3)
+	&& (table->bucket_size [bucket] >= 4))
+      {
+	struct rx_hash * newtab = ((struct rx_hash *)
+				   rules->hash_alloc (rules));
+	if (!newtab)
+	  goto add_to_bucket;
+	bzero (newtab, sizeof (*newtab));
+	newtab->parent = table;
+	{
+	  struct rx_hash_item * them = table->buckets[bucket];
+	  unsigned long newmask = rx_hash_masks[maskc + 1];
+	  while (them)
+	    {
+	      struct rx_hash_item * save = them->next_same_hash;
+	      int new_buck = (them->hash & newmask) % 13;
+	      them->next_same_hash = newtab->buckets[new_buck];
+	      newtab->buckets[new_buck] = them;
+	      them->table = newtab;
+	      them = save;
+	      ++newtab->bucket_size[new_buck];
+	      ++newtab->refs;
+	    }
+	  table->refs = (table->refs - table->bucket_size[bucket] + 1);
+	  table->bucket_size[bucket] = 0;
+	  table->buckets[bucket] = 0;
+	  table->children[bucket] = newtab;
+	  table = newtab;
+	  bucket = (hash & newmask) % 13;
+	}
+      }
+  }
+ add_to_bucket:
+  {
+    struct rx_hash_item  * it = ((struct rx_hash_item *)
+				 rules->hash_item_alloc (rules, value));
+    if (!it)
+      return 0;
+    it->hash = hash;
+    it->table = table;
+    /* DATA and BINDING are to be set in hash_item_alloc */
+    it->next_same_hash = table->buckets [bucket];
+    table->buckets[bucket] = it;
+    ++table->bucket_size [bucket];
+    ++table->refs;
+    return it;
+  }
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_hash_free (struct rx_hash_item * it, struct rx_hash_rules * rules)
+#else
+RX_DECL void
+rx_hash_free (it, rules)
+     struct rx_hash_item * it;
+     struct rx_hash_rules * rules;
+#endif
+{
+  if (it)
+    {
+      struct rx_hash * table = it->table;
+      unsigned long hash = it->hash;
+      int depth = (table->parent
+		   ? (table->parent->parent
+		      ? (table->parent->parent->parent
+			 ? 3
+			 : 2)
+		      : 1)
+		   : 0);
+      int bucket = (hash & rx_hash_masks [depth]) % 13;
+      struct rx_hash_item ** pos = &table->buckets [bucket];
+      
+      while (*pos != it)
+	pos = &(*pos)->next_same_hash;
+      *pos = it->next_same_hash;
+      rules->free_hash_item (it, rules);
+      --table->bucket_size[bucket];
+      --table->refs;
+      while (!table->refs && depth)
+	{
+	  struct rx_hash * save = table;
+	  table = table->parent;
+	  --depth;
+	  bucket = (hash & rx_hash_masks [depth]) % 13;
+	  --table->refs;
+	  table->children[bucket] = 0;
+	  rules->free_hash (save, rules);
+	}
+    }
+}
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_hash_table (struct rx_hash * tab, rx_hash_freefn freefn,
+		    struct rx_hash_rules * rules)
+#else
+RX_DECL void
+rx_free_hash_table (tab, freefn, rules)
+     struct rx_hash * tab;
+     rx_hash_freefn freefn;
+     struct rx_hash_rules * rules;
+#endif
+{
+  int x;
+
+  for (x = 0; x < 13; ++x)
+    if (tab->children[x])
+      {
+	rx_free_hash_table (tab->children[x], freefn, rules);
+	rules->free_hash (tab->children[x], rules);
+      }
+    else
+      {
+	struct rx_hash_item * them = tab->buckets[x];
+	while (them)
+	  {
+	    struct rx_hash_item * that = them;
+	    them = that->next_same_hash;
+	    freefn (that);
+	    rules->free_hash_item (that, rules);
+	  }
+      }
+}
+
+
+
+
+/* Utilities for manipulating bitset represntations of characters sets. */
+
+#ifdef __STDC__
+RX_DECL rx_Bitset
+rx_cset (struct rx *rx)
+#else
+RX_DECL rx_Bitset
+rx_cset (rx)
+     struct rx *rx;
+#endif
+{
+  rx_Bitset b = (rx_Bitset) malloc (rx_sizeof_bitset (rx->local_cset_size));
+  if (b)
+    rx_bitset_null (rx->local_cset_size, b);
+  return b;
+}
+
+
+#ifdef __STDC__
+RX_DECL rx_Bitset
+rx_copy_cset (struct rx *rx, rx_Bitset a)
+#else
+RX_DECL rx_Bitset
+rx_copy_cset (rx, a)
+     struct rx *rx;
+     rx_Bitset a;
+#endif
+{
+  rx_Bitset cs = rx_cset (rx);
+
+  if (cs)
+    rx_bitset_union (rx->local_cset_size, cs, a);
+
+  return cs;
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_cset (struct rx * rx, rx_Bitset c)
+#else
+RX_DECL void
+rx_free_cset (rx, c)
+     struct rx * rx;
+     rx_Bitset c;
+#endif
+{
+  if (c)
+    free ((char *)c);
+}
+
+
+
+/* Hash table memory allocation policy for the regexp compiler */
+
+#ifdef __STDC__
+static struct rx_hash *
+compiler_hash_alloc (struct rx_hash_rules * rules)
+#else
+static struct rx_hash *
+compiler_hash_alloc (rules)
+     struct rx_hash_rules * rules;
+#endif
+{
+  return (struct rx_hash *)malloc (sizeof (struct rx_hash));
+}
+
+
+#ifdef __STDC__
+static struct rx_hash_item *
+compiler_hash_item_alloc (struct rx_hash_rules * rules, void * value)
+#else
+static struct rx_hash_item *
+compiler_hash_item_alloc (rules, value)
+     struct rx_hash_rules * rules;
+     void * value;
+#endif
+{
+  struct rx_hash_item * it;
+  it = (struct rx_hash_item *)malloc (sizeof (*it));
+  if (it)
+    {
+      it->data = value;
+      it->binding = 0;
+    }
+  return it;
+}
+
+
+#ifdef __STDC__
+static void
+compiler_free_hash (struct rx_hash * tab,
+		    struct rx_hash_rules * rules)
+#else
+static void
+compiler_free_hash (tab, rules)
+     struct rx_hash * tab;
+     struct rx_hash_rules * rules;
+#endif
+{
+  free ((char *)tab);
+}
+
+
+#ifdef __STDC__
+static void
+compiler_free_hash_item (struct rx_hash_item * item,
+			 struct rx_hash_rules * rules)
+#else
+static void
+compiler_free_hash_item (item, rules)
+     struct rx_hash_item * item;
+     struct rx_hash_rules * rules;
+#endif
+{
+  free ((char *)item);
+}
+
+
+
+/* This page: REXP_NODE (expression tree) structures. */
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rexp_node (struct rx *rx,
+	   enum rexp_node_type type)
+#else
+RX_DECL struct rexp_node *
+rexp_node (rx, type)
+     struct rx *rx;
+     enum rexp_node_type type;
+#endif
+{
+  struct rexp_node *n;
+
+  n = (struct rexp_node *)malloc (sizeof (*n));
+  bzero (n, sizeof (*n));
+  if (n)
+    n->type = type;
+  return n;
+}
+
+
+/* free_rexp_node assumes that the bitset passed to rx_mk_r_cset
+ * can be freed using rx_free_cset.
+ */
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_cset (struct rx * rx,
+	      rx_Bitset b)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_cset (rx, b)
+     struct rx * rx;
+     rx_Bitset b;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_cset);
+  if (n)
+    n->params.cset = b;
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_concat (struct rx * rx,
+		struct rexp_node * a,
+		struct rexp_node * b)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_concat (rx, a, b)
+     struct rx * rx;
+     struct rexp_node * a;
+     struct rexp_node * b;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_concat);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = b;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_alternate (struct rx * rx,
+		   struct rexp_node * a,
+		   struct rexp_node * b)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_alternate (rx, a, b)
+     struct rx * rx;
+     struct rexp_node * a;
+     struct rexp_node * b;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_alternate);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = b;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_opt (struct rx * rx,
+	     struct rexp_node * a)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_opt (rx, a)
+     struct rx * rx;
+     struct rexp_node * a;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_opt);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = 0;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_star (struct rx * rx,
+	      struct rexp_node * a)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_star (rx, a)
+     struct rx * rx;
+     struct rexp_node * a;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_star);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = 0;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_2phase_star (struct rx * rx,
+		     struct rexp_node * a,
+		     struct rexp_node * b)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_2phase_star (rx, a, b)
+     struct rx * rx;
+     struct rexp_node * a;
+     struct rexp_node * b;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_2phase_star);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = b;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_side_effect (struct rx * rx,
+		     rx_side_effect a)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_side_effect (rx, a)
+     struct rx * rx;
+     rx_side_effect a;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_side_effect);
+  if (n)
+    {
+      n->params.side_effect = a;
+      n->params.pair.right = 0;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node *
+rx_mk_r_data  (struct rx * rx,
+	       void * a)
+#else
+RX_DECL struct rexp_node *
+rx_mk_r_data  (rx, a)
+     struct rx * rx;
+     void * a;
+#endif
+{
+  struct rexp_node * n = rexp_node (rx, r_data);
+  if (n)
+    {
+      n->params.pair.left = a;
+      n->params.pair.right = 0;
+    }
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_rexp (struct rx * rx, struct rexp_node * node)
+#else
+RX_DECL void
+rx_free_rexp (rx, node)
+     struct rx * rx;
+     struct rexp_node * node;
+#endif
+{
+  if (node)
+    {
+      switch (node->type)
+	{
+	case r_cset:
+	  if (node->params.cset)
+	    rx_free_cset (rx, node->params.cset);
+
+	case r_side_effect:
+	  break;
+	  
+	case r_concat:
+	case r_alternate:
+	case r_2phase_star:
+	case r_opt:
+	case r_star:
+	  rx_free_rexp (rx, node->params.pair.left);
+	  rx_free_rexp (rx, node->params.pair.right);
+	  break;
+
+	case r_data:
+	  /* This shouldn't occur. */
+	  break;
+	}
+      free ((char *)node);
+    }
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rexp_node * 
+rx_copy_rexp (struct rx *rx,
+	   struct rexp_node *node)
+#else
+RX_DECL struct rexp_node * 
+rx_copy_rexp (rx, node)
+     struct rx *rx;
+     struct rexp_node *node;
+#endif
+{
+  if (!node)
+    return 0;
+  else
+    {
+      struct rexp_node *n = rexp_node (rx, node->type);
+      if (!n)
+	return 0;
+      switch (node->type)
+	{
+	case r_cset:
+	  n->params.cset = rx_copy_cset (rx, node->params.cset);
+	  if (!n->params.cset)
+	    {
+	      rx_free_rexp (rx, n);
+	      return 0;
+	    }
+	  break;
+
+	case r_side_effect:
+	  n->params.side_effect = node->params.side_effect;
+	  break;
+
+	case r_concat:
+	case r_alternate:
+	case r_opt:
+	case r_2phase_star:
+	case r_star:
+	  n->params.pair.left =
+	    rx_copy_rexp (rx, node->params.pair.left);
+	  n->params.pair.right =
+	    rx_copy_rexp (rx, node->params.pair.right);
+	  if (   (node->params.pair.left && !n->params.pair.left)
+	      || (node->params.pair.right && !n->params.pair.right))
+	    {
+	      rx_free_rexp  (rx, n);
+	      return 0;
+	    }
+	  break;
+	case r_data:
+	  /* shouldn't happen */
+	  break;
+	}
+      return n;
+    }
+}
+
+
+
+
+/* This page: functions to build and destroy graphs that describe nfa's */
+
+/* Constructs a new nfa node. */
+#ifdef __STDC__
+RX_DECL struct rx_nfa_state *
+rx_nfa_state (struct rx *rx)
+#else
+RX_DECL struct rx_nfa_state *
+rx_nfa_state (rx)
+     struct rx *rx;
+#endif
+{
+  struct rx_nfa_state * n = (struct rx_nfa_state *)malloc (sizeof (*n));
+  if (!n)
+    return 0;
+  bzero (n, sizeof (*n));
+  n->next = rx->nfa_states;
+  rx->nfa_states = n;
+  return n;
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_nfa_state (struct rx_nfa_state * n)
+#else
+RX_DECL void
+rx_free_nfa_state (n)
+  struct rx_nfa_state * n;
+#endif
+{
+  free ((char *)n);
+}
+
+
+/* This looks up an nfa node, given a numeric id.  Numeric id's are
+ * assigned after the nfa has been built.
+ */
+#ifdef __STDC__
+RX_DECL struct rx_nfa_state * 
+rx_id_to_nfa_state (struct rx * rx,
+		    int id)
+#else
+RX_DECL struct rx_nfa_state * 
+rx_id_to_nfa_state (rx, id)
+     struct rx * rx;
+     int id;
+#endif
+{
+  struct rx_nfa_state * n;
+  for (n = rx->nfa_states; n; n = n->next)
+    if (n->id == id)
+      return n;
+  return 0;
+}
+
+
+/* This adds an edge between two nodes, but doesn't initialize the 
+ * edge label.
+ */
+
+#ifdef __STDC__
+RX_DECL struct rx_nfa_edge * 
+rx_nfa_edge (struct rx *rx,
+	     enum rx_nfa_etype type,
+	     struct rx_nfa_state *start,
+	     struct rx_nfa_state *dest)
+#else
+RX_DECL struct rx_nfa_edge * 
+rx_nfa_edge (rx, type, start, dest)
+     struct rx *rx;
+     enum rx_nfa_etype type;
+     struct rx_nfa_state *start;
+     struct rx_nfa_state *dest;
+#endif
+{
+  struct rx_nfa_edge *e;
+  e = (struct rx_nfa_edge *)malloc (sizeof (*e));
+  if (!e)
+    return 0;
+  e->next = start->edges;
+  start->edges = e;
+  e->type = type;
+  e->dest = dest;
+  return e;
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_nfa_edge (struct rx_nfa_edge * e)
+#else
+RX_DECL void
+rx_free_nfa_edge (e)
+     struct rx_nfa_edge * e;
+#endif
+{
+  free ((char *)e);
+}
+
+
+/* This constructs a POSSIBLE_FUTURE, which is a kind epsilon-closure
+ * of an NFA.  These are added to an nfa automaticly by eclose_nfa.
+ */  
+
+#ifdef __STDC__
+static struct rx_possible_future * 
+rx_possible_future (struct rx * rx,
+		 struct rx_se_list * effects)
+#else
+static struct rx_possible_future * 
+rx_possible_future (rx, effects)
+     struct rx * rx;
+     struct rx_se_list * effects;
+#endif
+{
+  struct rx_possible_future *ec;
+  ec = (struct rx_possible_future *) malloc (sizeof (*ec));
+  if (!ec)
+    return 0;
+  ec->destset = 0;
+  ec->next = 0;
+  ec->effects = effects;
+  return ec;
+}
+
+
+#ifdef __STDC__
+static void
+rx_free_possible_future (struct rx_possible_future * pf)
+#else
+static void
+rx_free_possible_future (pf)
+     struct rx_possible_future * pf;
+#endif
+{
+  free ((char *)pf);
+}
+
+
+#ifdef __STDC__
+RX_DECL void
+rx_free_nfa (struct rx *rx)
+#else
+RX_DECL void
+rx_free_nfa (rx)
+     struct rx *rx;
+#endif
+{
+  while (rx->nfa_states)
+    {
+      while (rx->nfa_states->edges)
+	{
+	  switch (rx->nfa_states->edges->type)
+	    {
+	    case ne_cset:
+	      rx_free_cset (rx, rx->nfa_states->edges->params.cset);
+	      break;
+	    default:
+	      break;
+	    }
+	  {
+	    struct rx_nfa_edge * e;
+	    e = rx->nfa_states->edges;
+	    rx->nfa_states->edges = rx->nfa_states->edges->next;
+	    rx_free_nfa_edge (e);
+	  }
+	} /* while (rx->nfa_states->edges) */
+      {
+	/* Iterate over the partial epsilon closures of rx->nfa_states */
+	struct rx_possible_future * pf = rx->nfa_states->futures;
+	while (pf)
+	  {
+	    struct rx_possible_future * pft = pf;
+	    pf = pf->next;
+	    rx_free_possible_future (pft);
+	  }
+      }
+      {
+	struct rx_nfa_state *n;
+	n = rx->nfa_states;
+	rx->nfa_states = rx->nfa_states->next;
+	rx_free_nfa_state (n);
+      }
+    }
+}
+
+
+
+
+/* This page: translating a pattern expression into an nfa and doing the 
+ * static part of the nfa->super-nfa translation.
+ */
+
+/* This is the thompson regexp->nfa algorithm. 
+ * It is modified to allow for `side-effect epsilons.'  Those are
+ * edges that are taken whenever a similar epsilon edge would be,
+ * but which imply that some side effect occurs when the edge 
+ * is taken.
+ *
+ * Side effects are used to model parts of the pattern langauge 
+ * that are not regular (in the formal sense).
+ */
+
+#ifdef __STDC__
+RX_DECL int
+rx_build_nfa (struct rx *rx,
+	      struct rexp_node *rexp,
+	      struct rx_nfa_state **start,
+	      struct rx_nfa_state **end)
+#else
+RX_DECL int
+rx_build_nfa (rx, rexp, start, end)
+     struct rx *rx;
+     struct rexp_node *rexp;
+     struct rx_nfa_state **start;
+     struct rx_nfa_state **end;
+#endif
+{
+  struct rx_nfa_edge *edge;
+
+  /* Start & end nodes may have been allocated by the caller. */
+  *start = *start ? *start : rx_nfa_state (rx);
+
+  if (!*start)
+    return 0;
+
+  if (!rexp)
+    {
+      *end = *start;
+      return 1;
+    }
+
+  *end = *end ? *end : rx_nfa_state (rx);
+
+  if (!*end)
+    {
+      rx_free_nfa_state (*start);
+      return 0;
+    }
+
+  switch (rexp->type)
+    {
+    case r_data:
+      return 0;
+
+    case r_cset:
+      edge = rx_nfa_edge (rx, ne_cset, *start, *end);
+      if (!edge)
+	return 0;
+      edge->params.cset = rx_copy_cset (rx, rexp->params.cset);
+      if (!edge->params.cset)
+	{
+	  rx_free_nfa_edge (edge);
+	  return 0;
+	}
+      return 1;
+ 
+    case r_opt:
+      return (rx_build_nfa (rx, rexp->params.pair.left, start, end)
+	      && rx_nfa_edge (rx, ne_epsilon, *start, *end));
+
+    case r_star:
+      {
+	struct rx_nfa_state * star_start = 0;
+	struct rx_nfa_state * star_end = 0;
+	return (rx_build_nfa (rx, rexp->params.pair.left,
+			      &star_start, &star_end)
+		&& star_start
+		&& star_end
+		&& rx_nfa_edge (rx, ne_epsilon, star_start, star_end)
+		&& rx_nfa_edge (rx, ne_epsilon, *start, star_start)
+		&& rx_nfa_edge (rx, ne_epsilon, star_end, *end)
+
+		&& rx_nfa_edge (rx, ne_epsilon, star_end, star_start));
+      }
+
+    case r_2phase_star:
+      {
+	struct rx_nfa_state * star_start = 0;
+	struct rx_nfa_state * star_end = 0;
+	struct rx_nfa_state * loop_exp_start = 0;
+	struct rx_nfa_state * loop_exp_end = 0;
+
+	return (rx_build_nfa (rx, rexp->params.pair.left,
+			      &star_start, &star_end)
+		&& rx_build_nfa (rx, rexp->params.pair.right,
+				 &loop_exp_start, &loop_exp_end)
+		&& star_start
+		&& star_end
+		&& loop_exp_end
+		&& loop_exp_start
+		&& rx_nfa_edge (rx, ne_epsilon, star_start, *end)
+		&& rx_nfa_edge (rx, ne_epsilon, *start, star_start)
+		&& rx_nfa_edge (rx, ne_epsilon, star_end, *end)
+
+		&& rx_nfa_edge (rx, ne_epsilon, star_end, loop_exp_start)
+		&& rx_nfa_edge (rx, ne_epsilon, loop_exp_end, star_start));
+      }
+
+
+    case r_concat:
+      {
+	struct rx_nfa_state *shared = 0;
+	return
+	  (rx_build_nfa (rx, rexp->params.pair.left, start, &shared)
+	   && rx_build_nfa (rx, rexp->params.pair.right, &shared, end));
+      }
+
+    case r_alternate:
+      {
+	struct rx_nfa_state *ls = 0;
+	struct rx_nfa_state *le = 0;
+	struct rx_nfa_state *rs = 0;
+	struct rx_nfa_state *re = 0;
+	return (rx_build_nfa (rx, rexp->params.pair.left, &ls, &le)
+		&& rx_build_nfa (rx, rexp->params.pair.right, &rs, &re)
+		&& rx_nfa_edge (rx, ne_epsilon, *start, ls)
+		&& rx_nfa_edge (rx, ne_epsilon, *start, rs)
+		&& rx_nfa_edge (rx, ne_epsilon, le, *end)
+		&& rx_nfa_edge (rx, ne_epsilon, re, *end));
+      }
+
+    case r_side_effect:
+      edge = rx_nfa_edge (rx, ne_side_effect, *start, *end);
+      if (!edge)
+	return 0;
+      edge->params.side_effect = rexp->params.side_effect;
+      return 1;
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+/* RX_NAME_NFA_STATES identifies all nodes with outgoing non-epsilon
+ * transitions.  Only these nodes can occur in super-states.  
+ * All nodes are given an integer id. 
+ * The id is non-negative if the node has non-epsilon out-transitions, negative
+ * otherwise (this is because we want the non-negative ids to be used as 
+ * array indexes in a few places).
+ */
+
+#ifdef __STDC__
+RX_DECL void
+rx_name_nfa_states (struct rx *rx)
+#else
+RX_DECL void
+rx_name_nfa_states (rx)
+     struct rx *rx;
+#endif
+{
+  struct rx_nfa_state *n = rx->nfa_states;
+
+  rx->nodec = 0;
+  rx->epsnodec = -1;
+
+  while (n)
+    {
+      struct rx_nfa_edge *e = n->edges;
+
+      if (n->is_start)
+	n->eclosure_needed = 1;
+
+      while (e)
+	{
+	  switch (e->type)
+	    {
+	    case ne_epsilon:
+	    case ne_side_effect:
+	      break;
+
+	    case ne_cset:
+	      n->id = rx->nodec++;
+	      {
+		struct rx_nfa_edge *from_n = n->edges;
+		while (from_n)
+		  {
+		    from_n->dest->eclosure_needed = 1;
+		    from_n = from_n->next;
+		  }
+	      }
+	      goto cont;
+	    }
+	  e = e->next;
+	}
+      n->id = rx->epsnodec--;
+    cont:
+      n = n->next;
+    }
+  rx->epsnodec = -rx->epsnodec;
+}
+
+
+
+/* This page: data structures for the static part of the nfa->supernfa
+ * translation.
+ *
+ * There are side effect lists -- lists of side effects occuring
+ * along an uninterrupted, acyclic path of side-effect epsilon edges.
+ * Such paths are collapsed to single edges in the course of computing
+ * epsilon closures.  Such single edges are labled with a list of all
+ * the side effects entailed in crossing them.  Like lists of side
+ * effects are made == by the constructors below.
+ *
+ * There are also nfa state sets.  These are used to hold a list of all
+ * states reachable from a starting state for a given type of transition
+ * and side effect list.   These are also hash-consed.
+ */
+
+/* The next several functions compare, construct, etc. lists of side
+ * effects.  See ECLOSE_NFA (below) for details.
+ */
+
+/* Ordering of rx_se_list
+ * (-1, 0, 1 return value convention).
+ */
+
+#ifdef __STDC__
+static int 
+se_list_cmp (void * va, void * vb)
+#else
+static int 
+se_list_cmp (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  struct rx_se_list * a = (struct rx_se_list *)va;
+  struct rx_se_list * b = (struct rx_se_list *)vb;
+
+  return ((va == vb)
+	  ? 0
+	  : (!va
+	     ? -1
+	     : (!vb
+		? 1
+		: ((long)a->car < (long)b->car
+		   ? 1
+		   : ((long)a->car > (long)b->car
+		      ? -1
+		      : se_list_cmp ((void *)a->cdr, (void *)b->cdr))))));
+}
+
+
+#ifdef __STDC__
+static int 
+se_list_equal (void * va, void * vb)
+#else
+static int 
+se_list_equal (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  return !(se_list_cmp (va, vb));
+}
+
+static struct rx_hash_rules se_list_hash_rules =
+{
+  se_list_equal,
+  compiler_hash_alloc,
+  compiler_free_hash,
+  compiler_hash_item_alloc,
+  compiler_free_hash_item
+};
+
+
+#ifdef __STDC__
+static struct rx_se_list * 
+side_effect_cons (struct rx * rx,
+		  void * se, struct rx_se_list * list)
+#else
+static struct rx_se_list * 
+side_effect_cons (rx, se, list)
+     struct rx * rx;
+     void * se;
+     struct rx_se_list * list;
+#endif
+{
+  struct rx_se_list * l;
+  l = ((struct rx_se_list *) malloc (sizeof (*l)));
+  if (!l)
+    return 0;
+  l->car = se;
+  l->cdr = list;
+  return l;
+}
+
+
+#ifdef __STDC__
+static struct rx_se_list *
+hash_cons_se_prog (struct rx * rx,
+		   struct rx_hash * memo,
+		   void * car, struct rx_se_list * cdr)
+#else
+static struct rx_se_list *
+hash_cons_se_prog (rx, memo, car, cdr)
+     struct rx * rx;
+     struct rx_hash * memo;
+     void * car;
+     struct rx_se_list * cdr;
+#endif
+{
+  long hash = (long)car ^ (long)cdr;
+  struct rx_se_list template;
+
+  template.car = car;
+  template.cdr = cdr;
+  {
+    struct rx_hash_item * it = rx_hash_store (memo, hash,
+					      (void *)&template,
+					      &se_list_hash_rules);
+    if (!it)
+      return 0;
+    if (it->data == (void *)&template)
+      {
+	struct rx_se_list * consed;
+	consed = (struct rx_se_list *) malloc (sizeof (*consed));
+	*consed = template;
+	it->data = (void *)consed;
+      }
+    return (struct rx_se_list *)it->data;
+  }
+}
+     
+
+#ifdef __STDC__
+static struct rx_se_list *
+hash_se_prog (struct rx * rx, struct rx_hash * memo, struct rx_se_list * prog)
+#else
+static struct rx_se_list *
+hash_se_prog (rx, memo, prog)
+     struct rx * rx;
+     struct rx_hash * memo;
+     struct rx_se_list * prog;
+#endif
+{
+  struct rx_se_list * answer = 0;
+  while (prog)
+    {
+      answer = hash_cons_se_prog (rx, memo, prog->car, answer);
+      if (!answer)
+	return 0;
+      prog = prog->cdr;
+    }
+  return answer;
+}
+
+#ifdef __STDC__
+static int 
+nfa_set_cmp (void * va, void * vb)
+#else
+static int 
+nfa_set_cmp (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  struct rx_nfa_state_set * a = (struct rx_nfa_state_set *)va;
+  struct rx_nfa_state_set * b = (struct rx_nfa_state_set *)vb;
+
+  return ((va == vb)
+	  ? 0
+	  : (!va
+	     ? -1
+	     : (!vb
+		? 1
+		: (a->car->id < b->car->id
+		   ? 1
+		   : (a->car->id > b->car->id
+		      ? -1
+		      : nfa_set_cmp ((void *)a->cdr, (void *)b->cdr))))));
+}
+
+#ifdef __STDC__
+static int 
+nfa_set_equal (void * va, void * vb)
+#else
+static int 
+nfa_set_equal (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  return !nfa_set_cmp (va, vb);
+}
+
+static struct rx_hash_rules nfa_set_hash_rules =
+{
+  nfa_set_equal,
+  compiler_hash_alloc,
+  compiler_free_hash,
+  compiler_hash_item_alloc,
+  compiler_free_hash_item
+};
+
+
+#ifdef __STDC__
+static struct rx_nfa_state_set * 
+nfa_set_cons (struct rx * rx,
+	      struct rx_hash * memo, struct rx_nfa_state * state,
+	      struct rx_nfa_state_set * set)
+#else
+static struct rx_nfa_state_set * 
+nfa_set_cons (rx, memo, state, set)
+     struct rx * rx;
+     struct rx_hash * memo;
+     struct rx_nfa_state * state;
+     struct rx_nfa_state_set * set;
+#endif
+{
+  struct rx_nfa_state_set template;
+  struct rx_hash_item * node;
+  template.car = state;
+  template.cdr = set;
+  node = rx_hash_store (memo,
+			(((long)state) >> 8) ^ (long)set,
+			&template, &nfa_set_hash_rules);
+  if (!node)
+    return 0;
+  if (node->data == &template)
+    {
+      struct rx_nfa_state_set * l;
+      l = (struct rx_nfa_state_set *) malloc (sizeof (*l));
+      node->data = (void *) l;
+      if (!l)
+	return 0;
+      *l = template;
+    }
+  return (struct rx_nfa_state_set *)node->data;
+}
+
+
+#ifdef __STDC__
+static struct rx_nfa_state_set * 
+nfa_set_enjoin (struct rx * rx,
+		struct rx_hash * memo, struct rx_nfa_state * state,
+		struct rx_nfa_state_set * set)
+#else
+static struct rx_nfa_state_set * 
+nfa_set_enjoin (rx, memo, state, set)
+     struct rx * rx;
+     struct rx_hash * memo;
+     struct rx_nfa_state * state;
+     struct rx_nfa_state_set * set;
+#endif
+{
+  if (!set || state->id < set->car->id)
+    return nfa_set_cons (rx, memo, state, set);
+  if (state->id == set->car->id)
+    return set;
+  else
+    {
+      struct rx_nfa_state_set * newcdr
+	= nfa_set_enjoin (rx, memo, state, set->cdr);
+      if (newcdr != set->cdr)
+	set = nfa_set_cons (rx, memo, set->car, newcdr);
+      return set;
+    }
+}
+
+
+
+
+/* This page: computing epsilon closures.  The closures aren't total.
+ * Each node's closures are partitioned according to the side effects entailed
+ * along the epsilon edges.  Return true on success.
+ */ 
+
+struct eclose_frame
+{
+  struct rx_se_list *prog_backwards;
+};
+
+
+#ifdef __STDC__
+static int 
+eclose_node (struct rx *rx, struct rx_nfa_state *outnode,
+	     struct rx_nfa_state *node, struct eclose_frame *frame)
+#else
+static int 
+eclose_node (rx, outnode, node, frame)
+     struct rx *rx;
+     struct rx_nfa_state *outnode;
+     struct rx_nfa_state *node;
+     struct eclose_frame *frame;
+#endif
+{
+  struct rx_nfa_edge *e = node->edges;
+
+  /* For each node, we follow all epsilon paths to build the closure.
+   * The closure omits nodes that have only epsilon edges.
+   * The closure is split into partial closures -- all the states in
+   * a partial closure are reached by crossing the same list of
+   * of side effects (though not necessarily the same path).
+   */
+  if (node->mark)
+    return 1;
+  node->mark = 1;
+
+  if (node->id >= 0 || node->is_final)
+    {
+      struct rx_possible_future **ec;
+      struct rx_se_list * prog_in_order
+	= ((struct rx_se_list *)hash_se_prog (rx,
+					      &rx->se_list_memo,
+					      frame->prog_backwards));
+      int cmp;
+
+      ec = &outnode->futures;
+
+      while (*ec)
+	{
+	  cmp = se_list_cmp ((void *)(*ec)->effects, (void *)prog_in_order);
+	  if (cmp <= 0)
+	    break;
+	  ec = &(*ec)->next;
+	}
+      if (!*ec || (cmp < 0))
+	{
+	  struct rx_possible_future * saved = *ec;
+	  *ec = rx_possible_future (rx, prog_in_order);
+	  (*ec)->next = saved;
+	  if (!*ec)
+	    return 0;
+	}
+      if (node->id >= 0)
+	{
+	  (*ec)->destset = nfa_set_enjoin (rx, &rx->set_list_memo,
+					   node, (*ec)->destset);
+	  if (!(*ec)->destset)
+	    return 0;
+	}
+    }
+
+  while (e)
+    {
+      switch (e->type)
+	{
+	case ne_epsilon:
+	  if (!eclose_node (rx, outnode, e->dest, frame))
+	    return 0;
+	  break;
+	case ne_side_effect:
+	  {
+	    frame->prog_backwards = side_effect_cons (rx, 
+						      e->params.side_effect,
+						      frame->prog_backwards);
+	    if (!frame->prog_backwards)
+	      return 0;
+	    if (!eclose_node (rx, outnode, e->dest, frame))
+	      return 0;
+	    {
+	      struct rx_se_list * dying = frame->prog_backwards;
+	      frame->prog_backwards = frame->prog_backwards->cdr;
+	      free ((char *)dying);
+	    }
+	    break;
+	  }
+	default:
+	  break;
+	}
+      e = e->next;
+    }
+  node->mark = 0;
+  return 1;
+}
+
+
+#ifdef __STDC__
+RX_DECL int 
+rx_eclose_nfa (struct rx *rx)
+#else
+RX_DECL int 
+rx_eclose_nfa (rx)
+     struct rx *rx;
+#endif
+{
+  struct rx_nfa_state *n = rx->nfa_states;
+  struct eclose_frame frame;
+  static int rx_id = 0;
+  
+  frame.prog_backwards = 0;
+  rx->rx_id = rx_id++;
+  bzero (&rx->se_list_memo, sizeof (rx->se_list_memo));
+  bzero (&rx->set_list_memo, sizeof (rx->set_list_memo));
+  while (n)
+    {
+      n->futures = 0;
+      if (n->eclosure_needed && !eclose_node (rx, n, n, &frame))
+	return 0;
+      /* clear_marks (rx); */
+      n = n->next;
+    }
+  return 1;
+}
+
+
+/* This deletes epsilon edges from an NFA.  After running eclose_node,
+ * we have no more need for these edges.  They are removed to simplify
+ * further operations on the NFA.
+ */
+
+#ifdef __STDC__
+RX_DECL void 
+rx_delete_epsilon_transitions (struct rx *rx)
+#else
+RX_DECL void 
+rx_delete_epsilon_transitions (rx)
+     struct rx *rx;
+#endif
+{
+  struct rx_nfa_state *n = rx->nfa_states;
+  struct rx_nfa_edge **e;
+
+  while (n)
+    {
+      e = &n->edges;
+      while (*e)
+	{
+	  struct rx_nfa_edge *t;
+	  switch ((*e)->type)
+	    {
+	    case ne_epsilon:
+	    case ne_side_effect:
+	      t = *e;
+	      *e = t->next;
+	      rx_free_nfa_edge (t);
+	      break;
+
+	    default:
+	      e = &(*e)->next;
+	      break;
+	    }
+	}
+      n = n->next;
+    }
+}
+
+
+
+/* This page: storing the nfa in a contiguous region of memory for
+ * subsequent conversion to a super-nfa.
+ */
+
+/* This is for qsort on an array of nfa_states. The order
+ * is based on state ids and goes 
+ *		[0...MAX][MIN..-1] where (MAX>=0) and (MIN<0)
+ * This way, positive ids double as array indices.
+ */
+
+#ifdef __STDC__
+static int 
+nfacmp (void * va, void * vb)
+#else
+static int 
+nfacmp (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  struct rx_nfa_state **a = (struct rx_nfa_state **)va;
+  struct rx_nfa_state **b = (struct rx_nfa_state **)vb;
+  return (*a == *b		/* &&&& 3.18 */
+	  ? 0
+	  : (((*a)->id < 0) == ((*b)->id < 0)
+	     ? (((*a)->id  < (*b)->id) ? -1 : 1)
+	     : (((*a)->id < 0)
+		? 1 : -1)));
+}
+
+#ifdef __STDC__
+static int 
+count_hash_nodes (struct rx_hash * st)
+#else
+static int 
+count_hash_nodes (st)
+     struct rx_hash * st;
+#endif
+{
+  int x;
+  int count = 0;
+  for (x = 0; x < 13; ++x)
+    count += ((st->children[x])
+	      ? count_hash_nodes (st->children[x])
+	      : st->bucket_size[x]);
+  
+  return count;
+}
+
+
+#ifdef __STDC__
+static void 
+se_memo_freer (struct rx_hash_item * node)
+#else
+static void 
+se_memo_freer (node)
+     struct rx_hash_item * node;
+#endif
+{
+  free ((char *)node->data);
+}
+
+
+#ifdef __STDC__
+static void 
+nfa_set_freer (struct rx_hash_item * node)
+#else
+static void 
+nfa_set_freer (node)
+     struct rx_hash_item * node;
+#endif
+{
+  free ((char *)node->data);
+}
+
+
+/* This copies an entire NFA into a single malloced block of memory.
+ * Mostly this is for compatability with regex.c, though it is convenient
+ * to have the nfa nodes in an array.
+ */
+
+#ifdef __STDC__
+RX_DECL int 
+rx_compactify_nfa (struct rx *rx,
+		   void **mem, unsigned long *size)
+#else
+RX_DECL int 
+rx_compactify_nfa (rx, mem, size)
+     struct rx *rx;
+     void **mem;
+     unsigned long *size;
+#endif
+{
+  int total_nodec;
+  struct rx_nfa_state *n;
+  int edgec = 0;
+  int eclosec = 0;
+  int se_list_consc = count_hash_nodes (&rx->se_list_memo);
+  int nfa_setc = count_hash_nodes (&rx->set_list_memo);
+  unsigned long total_size;
+
+  /* This takes place in two stages.   First, the total size of the
+   * nfa is computed, then structures are copied.  
+   */   
+  n = rx->nfa_states;
+  total_nodec = 0;
+  while (n)
+    {
+      struct rx_nfa_edge *e = n->edges;
+      struct rx_possible_future *ec = n->futures;
+      ++total_nodec;
+      while (e)
+	{
+	  ++edgec;
+	  e = e->next;
+	}
+      while (ec)
+	{
+	  ++eclosec;
+	  ec = ec->next;
+	}
+      n = n->next;
+    }
+
+  total_size = (total_nodec * sizeof (struct rx_nfa_state)
+		+ edgec * rx_sizeof_bitset (rx->local_cset_size)
+		+ edgec * sizeof (struct rx_nfa_edge)
+		+ nfa_setc * sizeof (struct rx_nfa_state_set)
+		+ eclosec * sizeof (struct rx_possible_future)
+		+ se_list_consc * sizeof (struct rx_se_list)
+		+ rx->reserved);
+
+  if (total_size > *size)
+    {
+      *mem = remalloc (*mem, total_size);
+      if (*mem)
+	*size = total_size;
+      else
+	return 0;
+    }
+  /* Now we've allocated the memory; this copies the NFA. */
+  {
+    static struct rx_nfa_state **scratch = 0;
+    static int scratch_alloc = 0;
+    struct rx_nfa_state *state_base = (struct rx_nfa_state *) * mem;
+    struct rx_nfa_state *new_state = state_base;
+    struct rx_nfa_edge *new_edge =
+      (struct rx_nfa_edge *)
+	((char *) state_base + total_nodec * sizeof (struct rx_nfa_state));
+    struct rx_se_list * new_se_list =
+      (struct rx_se_list *)
+	((char *)new_edge + edgec * sizeof (struct rx_nfa_edge));
+    struct rx_possible_future *new_close =
+      ((struct rx_possible_future *)
+       ((char *) new_se_list
+	+ se_list_consc * sizeof (struct rx_se_list)));
+    struct rx_nfa_state_set * new_nfa_set =
+      ((struct rx_nfa_state_set *)
+       ((char *)new_close + eclosec * sizeof (struct rx_possible_future)));
+    char *new_bitset =
+      ((char *) new_nfa_set + nfa_setc * sizeof (struct rx_nfa_state_set));
+    int x;
+    struct rx_nfa_state *n;
+
+    if (scratch_alloc < total_nodec)
+      {
+	scratch = ((struct rx_nfa_state **)
+		   remalloc (scratch, total_nodec * sizeof (*scratch)));
+	if (scratch)
+	  scratch_alloc = total_nodec;
+	else
+	  {
+	    scratch_alloc = 0;
+	    return 0;
+	  }
+      }
+
+    for (x = 0, n = rx->nfa_states; n; n = n->next)
+      scratch[x++] = n;
+
+    qsort (scratch, total_nodec,
+	   sizeof (struct rx_nfa_state *), (int (*)())nfacmp);
+
+    for (x = 0; x < total_nodec; ++x)
+      {
+	struct rx_possible_future *eclose = scratch[x]->futures;
+	struct rx_nfa_edge *edge = scratch[x]->edges;
+	struct rx_nfa_state *cn = new_state++;
+	cn->futures = 0;
+	cn->edges = 0;
+	cn->next = (x == total_nodec - 1) ? 0 : (cn + 1);
+	cn->id = scratch[x]->id;
+	cn->is_final = scratch[x]->is_final;
+	cn->is_start = scratch[x]->is_start;
+	cn->mark = 0;
+	while (edge)
+	  {
+	    int indx = (edge->dest->id < 0
+			 ? (total_nodec + edge->dest->id)
+			 : edge->dest->id);
+	    struct rx_nfa_edge *e = new_edge++;
+	    rx_Bitset cset = (rx_Bitset) new_bitset;
+	    new_bitset += rx_sizeof_bitset (rx->local_cset_size);
+	    rx_bitset_null (rx->local_cset_size, cset);
+	    rx_bitset_union (rx->local_cset_size, cset, edge->params.cset);
+	    e->next = cn->edges;
+	    cn->edges = e;
+	    e->type = edge->type;
+	    e->dest = state_base + indx;
+	    e->params.cset = cset;
+	    edge = edge->next;
+	  }
+	while (eclose)
+	  {
+	    struct rx_possible_future *ec = new_close++;
+	    struct rx_hash_item * sp;
+	    struct rx_se_list ** sepos;
+	    struct rx_se_list * sesrc;
+	    struct rx_nfa_state_set * destlst;
+	    struct rx_nfa_state_set ** destpos;
+	    ec->next = cn->futures;
+	    cn->futures = ec;
+	    for (sepos = &ec->effects, sesrc = eclose->effects;
+		 sesrc;
+		 sesrc = sesrc->cdr, sepos = &(*sepos)->cdr)
+	      {
+		sp = rx_hash_find (&rx->se_list_memo,
+				   (long)sesrc->car ^ (long)sesrc->cdr,
+				   sesrc, &se_list_hash_rules);
+		if (sp->binding)
+		  {
+		    sesrc = (struct rx_se_list *)sp->binding;
+		    break;
+		  }
+		*new_se_list = *sesrc;
+		sp->binding = (void *)new_se_list;
+		*sepos = new_se_list;
+		++new_se_list;
+	      }
+	    *sepos = sesrc;
+	    for (destpos = &ec->destset, destlst = eclose->destset;
+		 destlst;
+		 destpos = &(*destpos)->cdr, destlst = destlst->cdr)
+	      {
+		sp = rx_hash_find (&rx->set_list_memo,
+				   ((((long)destlst->car) >> 8)
+				    ^ (long)destlst->cdr),
+				   destlst, &nfa_set_hash_rules);
+		if (sp->binding)
+		  {
+		    destlst = (struct rx_nfa_state_set *)sp->binding;
+		    break;
+		  }
+		*new_nfa_set = *destlst;
+		new_nfa_set->car = state_base + destlst->car->id;
+		sp->binding = (void *)new_nfa_set;
+		*destpos = new_nfa_set;
+		++new_nfa_set;
+	      }
+	    *destpos = destlst;
+	    eclose = eclose->next;
+	  }
+      }
+  }
+  rx_free_hash_table (&rx->se_list_memo, se_memo_freer, &se_list_hash_rules);
+  bzero (&rx->se_list_memo, sizeof (rx->se_list_memo));
+  rx_free_hash_table (&rx->set_list_memo, nfa_set_freer, &nfa_set_hash_rules);
+  bzero (&rx->set_list_memo, sizeof (rx->set_list_memo));
+
+  rx_free_nfa (rx);
+  rx->nfa_states = (struct rx_nfa_state *)*mem;
+  return 1;
+}
+
+
+
+/* The functions in the next several pages define the lazy-NFA-conversion used
+ * by matchers.  The input to this construction is an NFA such as 
+ * is built by compactify_nfa (rx.c).  The output is the superNFA.
+ */
+
+/* Match engines can use arbitrary values for opcodes.  So, the parse tree 
+ * is built using instructions names (enum rx_opcode), but the superstate
+ * nfa is populated with mystery opcodes (void *).
+ *
+ * For convenience, here is an id table.  The opcodes are == to their inxs
+ *
+ * The lables in re_search_2 would make good values for instructions.
+ */
+
+void * rx_id_instruction_table[rx_num_instructions] =
+{
+  (void *) rx_backtrack_point,
+  (void *) rx_do_side_effects,
+  (void *) rx_cache_miss,
+  (void *) rx_next_char,
+  (void *) rx_backtrack,
+  (void *) rx_error_inx
+};
+
+
+
+
+/* Memory mgt. for superstate graphs. */
+
+#ifdef __STDC__
+static char *
+rx_cache_malloc (struct rx_cache * cache, int bytes)
+#else
+static char *
+rx_cache_malloc (cache, bytes)
+     struct rx_cache * cache;
+     int bytes;
+#endif
+{
+  while (cache->bytes_left < bytes)
+    {
+      if (cache->memory_pos)
+	cache->memory_pos = cache->memory_pos->next;
+      if (!cache->memory_pos)
+	{
+	  cache->morecore (cache);
+	  if (!cache->memory_pos)
+	    return 0;
+	}
+      cache->bytes_left = cache->memory_pos->bytes;
+      cache->memory_addr = ((char *)cache->memory_pos
+			    + sizeof (struct rx_blocklist));
+    }
+  cache->bytes_left -= bytes;
+  {
+    char * addr = cache->memory_addr;
+    cache->memory_addr += bytes;
+    return addr;
+  }
+}
+
+#ifdef __STDC__
+static void
+rx_cache_free (struct rx_cache * cache,
+	       struct rx_freelist ** freelist, char * mem)
+#else
+static void
+rx_cache_free (cache, freelist, mem)
+     struct rx_cache * cache;
+     struct rx_freelist ** freelist;
+     char * mem;
+#endif
+{
+  struct rx_freelist * it = (struct rx_freelist *)mem;
+  it->next = *freelist;
+  *freelist = it;
+}
+
+
+/* The partially instantiated superstate graph has a transition 
+ * table at every node.  There is one entry for every character.
+ * This fills in the transition for a set.
+ */
+#ifdef __STDC__
+static void 
+install_transition (struct rx_superstate *super,
+		    struct rx_inx *answer, rx_Bitset trcset) 
+#else
+static void 
+install_transition (super, answer, trcset)
+     struct rx_superstate *super;
+     struct rx_inx *answer;
+     rx_Bitset trcset;
+#endif
+{
+  struct rx_inx * transitions = super->transitions;
+  int chr;
+  for (chr = 0; chr < 256; )
+    if (!*trcset)
+      {
+	++trcset;
+	chr += 32;
+      }
+    else
+      {
+	RX_subset sub = *trcset;
+	RX_subset mask = 1;
+	int bound = chr + 32;
+	while (chr < bound)
+	  {
+	    if (sub & mask)
+	      transitions [chr] = *answer;
+	    ++chr;
+	    mask <<= 1;
+	  }
+	++trcset;
+      }
+}
+
+
+#ifdef __STDC__
+static int
+qlen (struct rx_superstate * q)
+#else
+static int
+qlen (q)
+     struct rx_superstate * q;
+#endif
+{
+  int count = 1;
+  struct rx_superstate * it;
+  if (!q)
+    return 0;
+  for (it = q->next_recyclable; it != q; it = it->next_recyclable)
+    ++count;
+  return count;
+}
+
+#ifdef __STDC__
+static void
+check_cache (struct rx_cache * cache)
+#else
+static void
+check_cache (cache)
+     struct rx_cache * cache;
+#endif
+{
+  struct rx_cache * you_fucked_up = 0;
+  int total = cache->superstates;
+  int semi = cache->semifree_superstates;
+  if (semi != qlen (cache->semifree_superstate))
+    check_cache (you_fucked_up);
+  if ((total - semi) != qlen (cache->lru_superstate))
+    check_cache (you_fucked_up);
+}
+
+/* When a superstate is old and neglected, it can enter a 
+ * semi-free state.  A semi-free state is slated to die.
+ * Incoming transitions to a semi-free state are re-written
+ * to cause an (interpreted) fault when they are taken.
+ * The fault handler revives the semi-free state, patches
+ * incoming transitions back to normal, and continues.
+ *
+ * The idea is basicly to free in two stages, aborting 
+ * between the two if the state turns out to be useful again.
+ * When a free is aborted, the rescued superstate is placed
+ * in the most-favored slot to maximize the time until it
+ * is next semi-freed.
+ */
+
+#ifdef __STDC__
+static void
+semifree_superstate (struct rx_cache * cache)
+#else
+static void
+semifree_superstate (cache)
+     struct rx_cache * cache;
+#endif
+{
+  int disqualified = cache->semifree_superstates;
+  if (disqualified == cache->superstates)
+    return;
+  while (cache->lru_superstate->locks)
+    {
+      cache->lru_superstate = cache->lru_superstate->next_recyclable;
+      ++disqualified;
+      if (disqualified == cache->superstates)
+	return;
+    }
+  {
+    struct rx_superstate * it = cache->lru_superstate;
+    it->next_recyclable->prev_recyclable = it->prev_recyclable;
+    it->prev_recyclable->next_recyclable = it->next_recyclable;
+    cache->lru_superstate = (it == it->next_recyclable
+			     ? 0
+			     : it->next_recyclable);
+    if (!cache->semifree_superstate)
+      {
+	cache->semifree_superstate = it;
+	it->next_recyclable = it;
+	it->prev_recyclable = it;
+      }
+    else
+      {
+	it->prev_recyclable = cache->semifree_superstate->prev_recyclable;
+	it->next_recyclable = cache->semifree_superstate;
+	it->prev_recyclable->next_recyclable = it;
+	it->next_recyclable->prev_recyclable = it;
+      }
+    {
+      struct rx_distinct_future *df;
+      it->is_semifree = 1;
+      ++cache->semifree_superstates;
+      df = it->transition_refs;
+      if (df)
+	{
+	  df->prev_same_dest->next_same_dest = 0;
+	  for (df = it->transition_refs; df; df = df->next_same_dest)
+	    {
+	      df->future_frame.inx = cache->instruction_table[rx_cache_miss];
+	      df->future_frame.data = 0;
+	      df->future_frame.data_2 = (void *) df;
+	      /* If there are any NEXT-CHAR instruction frames that
+	       * refer to this state, we convert them to CACHE-MISS frames.
+	       */
+	      if (!df->effects
+		  && (df->edge->options->next_same_super_edge[0]
+		      == df->edge->options))
+		install_transition (df->present, &df->future_frame,
+				    df->edge->cset);
+	    }
+	  df = it->transition_refs;
+	  df->prev_same_dest->next_same_dest = df;
+	}
+    }
+  }
+}
+
+
+#ifdef __STDC__
+static void 
+refresh_semifree_superstate (struct rx_cache * cache,
+			     struct rx_superstate * super)
+#else
+static void 
+refresh_semifree_superstate (cache, super)
+     struct rx_cache * cache;
+     struct rx_superstate * super;
+#endif
+{
+  struct rx_distinct_future *df;
+
+  if (super->transition_refs)
+    {
+      super->transition_refs->prev_same_dest->next_same_dest = 0; 
+      for (df = super->transition_refs; df; df = df->next_same_dest)
+	{
+	  df->future_frame.inx = cache->instruction_table[rx_next_char];
+	  df->future_frame.data = (void *) super->transitions;
+	  /* CACHE-MISS instruction frames that refer to this state,
+	   * must be converted to NEXT-CHAR frames.
+	   */
+	  if (!df->effects
+	      && (df->edge->options->next_same_super_edge[0]
+		  == df->edge->options))
+	    install_transition (df->present, &df->future_frame,
+				df->edge->cset);
+	}
+      super->transition_refs->prev_same_dest->next_same_dest
+	= super->transition_refs;
+    }
+  if (cache->semifree_superstate == super)
+    cache->semifree_superstate = (super->prev_recyclable == super
+				  ? 0
+				  : super->prev_recyclable);
+  super->next_recyclable->prev_recyclable = super->prev_recyclable;
+  super->prev_recyclable->next_recyclable = super->next_recyclable;
+
+  if (!cache->lru_superstate)
+    (cache->lru_superstate
+     = super->next_recyclable
+     = super->prev_recyclable
+     = super);
+  else
+    {
+      super->next_recyclable = cache->lru_superstate;
+      super->prev_recyclable = cache->lru_superstate->prev_recyclable;
+      super->next_recyclable->prev_recyclable = super;
+      super->prev_recyclable->next_recyclable = super;
+    }
+  super->is_semifree = 0;
+  --cache->semifree_superstates;
+}
+
+#ifdef __STDC__
+static void
+rx_refresh_this_superstate (struct rx_cache * cache, struct rx_superstate * superstate)
+#else
+static void
+rx_refresh_this_superstate (cache, superstate)
+     struct rx_cache * cache;
+     struct rx_superstate * superstate;
+#endif
+{
+  if (superstate->is_semifree)
+    refresh_semifree_superstate (cache, superstate);
+  else if (cache->lru_superstate == superstate)
+    cache->lru_superstate = superstate->next_recyclable;
+  else if (superstate != cache->lru_superstate->prev_recyclable)
+    {
+      superstate->next_recyclable->prev_recyclable
+	= superstate->prev_recyclable;
+      superstate->prev_recyclable->next_recyclable
+	= superstate->next_recyclable;
+      superstate->next_recyclable = cache->lru_superstate;
+      superstate->prev_recyclable = cache->lru_superstate->prev_recyclable;
+      superstate->next_recyclable->prev_recyclable = superstate;
+      superstate->prev_recyclable->next_recyclable = superstate;
+    }
+}
+
+#ifdef __STDC__
+static void 
+release_superset_low (struct rx_cache * cache,
+		     struct rx_superset *set)
+#else
+static void 
+release_superset_low (cache, set)
+     struct rx_cache * cache;
+     struct rx_superset *set;
+#endif
+{
+  if (!--set->refs)
+    {
+      if (set->cdr)
+	release_superset_low (cache, set->cdr);
+
+      set->starts_for = 0;
+
+      rx_hash_free
+	(rx_hash_find
+	 (&cache->superset_table,
+	  (unsigned long)set->car ^ set->id ^ (unsigned long)set->cdr,
+	  (void *)set,
+	  &cache->superset_hash_rules),
+	 &cache->superset_hash_rules);
+      rx_cache_free (cache, &cache->free_supersets, (char *)set);
+    }
+}
+
+#ifdef __STDC__
+RX_DECL void 
+rx_release_superset (struct rx *rx,
+		     struct rx_superset *set)
+#else
+RX_DECL void 
+rx_release_superset (rx, set)
+     struct rx *rx;
+     struct rx_superset *set;
+#endif
+{
+  release_superset_low (rx->cache, set);
+}
+
+/* This tries to add a new superstate to the superstate freelist.
+ * It might, as a result, free some edge pieces or hash tables.
+ * If nothing can be freed because too many locks are being held, fail.
+ */
+
+#ifdef __STDC__
+static int
+rx_really_free_superstate (struct rx_cache * cache)
+#else
+static int
+rx_really_free_superstate (cache)
+     struct rx_cache * cache;
+#endif
+{
+  int locked_superstates = 0;
+  struct rx_superstate * it;
+
+  if (!cache->superstates)
+    return 0;
+
+  {
+    /* This is a total guess.  The idea is that we should expect as
+     * many misses as we've recently experienced.  I.e., cache->misses
+     * should be the same as cache->semifree_superstates.
+     */
+    while ((cache->hits + cache->misses) > cache->superstates_allowed)
+      {
+	cache->hits >>= 1;
+	cache->misses >>= 1;
+      }
+    if (  ((cache->hits + cache->misses) * cache->semifree_superstates)
+	< (cache->superstates		 * cache->misses))
+      {
+	semifree_superstate (cache);
+	semifree_superstate (cache);
+      }
+  }
+
+  while (cache->semifree_superstate && cache->semifree_superstate->locks)
+    {
+      refresh_semifree_superstate (cache, cache->semifree_superstate);
+      ++locked_superstates;
+      if (locked_superstates == cache->superstates)
+	return 0;
+    }
+
+  if (cache->semifree_superstate)
+    {
+      it = cache->semifree_superstate;
+      it->next_recyclable->prev_recyclable = it->prev_recyclable;
+      it->prev_recyclable->next_recyclable = it->next_recyclable;
+      cache->semifree_superstate = ((it == it->next_recyclable)
+				    ? 0
+				    : it->next_recyclable);
+      --cache->semifree_superstates;
+    }
+  else
+    {
+      while (cache->lru_superstate->locks)
+	{
+	  cache->lru_superstate = cache->lru_superstate->next_recyclable;
+	  ++locked_superstates;
+	  if (locked_superstates == cache->superstates)
+	    return 0;
+	}
+      it = cache->lru_superstate;
+      it->next_recyclable->prev_recyclable = it->prev_recyclable;
+      it->prev_recyclable->next_recyclable = it->next_recyclable;
+      cache->lru_superstate = ((it == it->next_recyclable)
+				    ? 0
+				    : it->next_recyclable);
+    }
+
+  if (it->transition_refs)
+    {
+      struct rx_distinct_future *df;
+      for (df = it->transition_refs,
+	   df->prev_same_dest->next_same_dest = 0;
+	   df;
+	   df = df->next_same_dest)
+	{
+	  df->future_frame.inx = cache->instruction_table[rx_cache_miss];
+	  df->future_frame.data = 0;
+	  df->future_frame.data_2 = (void *) df;
+	  df->future = 0;
+	}
+      it->transition_refs->prev_same_dest->next_same_dest =
+	it->transition_refs;
+    }
+  {
+    struct rx_super_edge *tc = it->edges;
+    while (tc)
+      {
+	struct rx_distinct_future * df;
+	struct rx_super_edge *tct = tc->next;
+	df = tc->options;
+	df->next_same_super_edge[1]->next_same_super_edge[0] = 0;
+	while (df)
+	  {
+	    struct rx_distinct_future *dft = df;
+	    df = df->next_same_super_edge[0];
+	    
+	    
+	    if (dft->future && dft->future->transition_refs == dft)
+	      {
+		dft->future->transition_refs = dft->next_same_dest;
+		if (dft->future->transition_refs == dft)
+		  dft->future->transition_refs = 0;
+	      }
+	    dft->next_same_dest->prev_same_dest = dft->prev_same_dest;
+	    dft->prev_same_dest->next_same_dest = dft->next_same_dest;
+	    rx_cache_free (cache, &cache->free_discernable_futures,
+			   (char *)dft);
+	  }
+	rx_cache_free (cache, &cache->free_transition_classes, (char *)tc);
+	tc = tct;
+      }
+  }
+  
+  if (it->contents->superstate == it)
+    it->contents->superstate = 0;
+  release_superset_low (cache, it->contents);
+  rx_cache_free (cache, &cache->free_superstates, (char *)it);
+  --cache->superstates;
+  return 1;
+}
+
+#ifdef __STDC__
+static char *
+rx_cache_get (struct rx_cache * cache,
+	      struct rx_freelist ** freelist)
+#else
+static char *
+rx_cache_get (cache, freelist)
+     struct rx_cache * cache;
+     struct rx_freelist ** freelist;
+#endif
+{
+  while (!*freelist && rx_really_free_superstate (cache))
+    ;
+  if (!*freelist)
+    return 0;
+  {
+    struct rx_freelist * it = *freelist;
+    *freelist = it->next;
+    return (char *)it;
+  }
+}
+
+#ifdef __STDC__
+static char *
+rx_cache_malloc_or_get (struct rx_cache * cache,
+			struct rx_freelist ** freelist, int bytes)
+#else
+static char *
+rx_cache_malloc_or_get (cache, freelist, bytes)
+     struct rx_cache * cache;
+     struct rx_freelist ** freelist;
+     int bytes;
+#endif
+{
+  if (!*freelist)
+    {
+      char * answer = rx_cache_malloc (cache, bytes);
+      if (answer)
+	return answer;
+    }
+
+  return rx_cache_get (cache, freelist);
+}
+
+#ifdef __STDC__
+static char *
+rx_cache_get_superstate (struct rx_cache * cache)
+#else
+static char *
+rx_cache_get_superstate (cache)
+	  struct rx_cache * cache;
+#endif
+{
+  char * answer;
+  int bytes = (   sizeof (struct rx_superstate)
+	       +  cache->local_cset_size * sizeof (struct rx_inx));
+  if (!cache->free_superstates
+      && (cache->superstates < cache->superstates_allowed))
+    {
+      answer = rx_cache_malloc (cache, bytes);
+      if (answer)
+	{
+	  ++cache->superstates;
+	  return answer;
+	}
+    }
+  answer = rx_cache_get (cache, &cache->free_superstates);
+  if (!answer)
+    {
+      answer = rx_cache_malloc (cache, bytes);
+      if (answer)
+	++cache->superstates_allowed;
+    }
+  ++cache->superstates;
+  return answer;
+}
+
+
+
+
+#ifdef __STDC__
+static int
+supersetcmp (void * va, void * vb)
+#else
+static int
+supersetcmp (va, vb)
+     void * va;
+     void * vb;
+#endif
+{
+  struct rx_superset * a = (struct rx_superset *)va;
+  struct rx_superset * b = (struct rx_superset *)vb;
+  return (   (a == b)
+	  || (a && b && (a->car == b->car) && (a->cdr == b->cdr)));
+}
+
+#ifdef __STDC__
+static struct rx_hash_item *
+superset_allocator (struct rx_hash_rules * rules, void * val)
+#else
+static struct rx_hash_item *
+superset_allocator (rules, val)
+     struct rx_hash_rules * rules;
+     void * val;
+#endif
+{
+  struct rx_cache * cache
+    = ((struct rx_cache *)
+       ((char *)rules
+	- (unsigned long)(&((struct rx_cache *)0)->superset_hash_rules)));
+  struct rx_superset * template = (struct rx_superset *)val;
+  struct rx_superset * newset
+    = ((struct rx_superset *)
+       rx_cache_malloc_or_get (cache,
+			       &cache->free_supersets,
+			       sizeof (*template)));
+  if (!newset)
+    return 0;
+  newset->refs = 0;
+  newset->car = template->car;
+  newset->id = template->car->id;
+  newset->cdr = template->cdr;
+  newset->superstate = 0;
+  rx_protect_superset (rx, template->cdr);
+  newset->hash_item.data = (void *)newset;
+  newset->hash_item.binding = 0;
+  return &newset->hash_item;
+}
+
+#ifdef __STDC__
+static struct rx_hash * 
+super_hash_allocator (struct rx_hash_rules * rules)
+#else
+static struct rx_hash * 
+super_hash_allocator (rules)
+     struct rx_hash_rules * rules;
+#endif
+{
+  struct rx_cache * cache
+    = ((struct rx_cache *)
+       ((char *)rules
+	- (unsigned long)(&((struct rx_cache *)0)->superset_hash_rules)));
+  return ((struct rx_hash *)
+	  rx_cache_malloc_or_get (cache,
+				  &cache->free_hash, sizeof (struct rx_hash)));
+}
+
+
+#ifdef __STDC__
+static void
+super_hash_liberator (struct rx_hash * hash, struct rx_hash_rules * rules)
+#else
+static void
+super_hash_liberator (hash, rules)
+     struct rx_hash * hash;
+     struct rx_hash_rules * rules;
+#endif
+{
+  struct rx_cache * cache
+    = ((struct rx_cache *)
+       (char *)rules - (long)(&((struct rx_cache *)0)->superset_hash_rules));
+  rx_cache_free (cache, &cache->free_hash, (char *)hash);
+}
+
+#ifdef __STDC__
+static void
+superset_hash_item_liberator (struct rx_hash_item * it,
+			      struct rx_hash_rules * rules)
+#else
+static void
+superset_hash_item_liberator (it, rules) /* Well, it does ya know. */
+     struct rx_hash_item * it;
+     struct rx_hash_rules * rules;
+#endif
+{
+}
+
+int rx_cache_bound = 128;
+static int rx_default_cache_got = 0;
+
+#ifdef __STDC__
+static int
+bytes_for_cache_size (int supers, int cset_size)
+#else
+static int
+bytes_for_cache_size (supers, cset_size)
+     int supers;
+     int cset_size;
+#endif
+{
+  /* What the hell is this? !!!*/
+  return (int)
+    ((float)supers *
+     (  (1.03 * (float) (  rx_sizeof_bitset (cset_size)
+			 + sizeof (struct rx_super_edge)))
+      + (1.80 * (float) sizeof (struct rx_possible_future))
+      + (float) (  sizeof (struct rx_superstate)
+		 + cset_size * sizeof (struct rx_inx))));
+}
+
+#ifdef __STDC__
+static void
+rx_morecore (struct rx_cache * cache)
+#else
+static void
+rx_morecore (cache)
+     struct rx_cache * cache;
+#endif
+{
+  if (rx_default_cache_got >= rx_cache_bound)
+    return;
+
+  rx_default_cache_got += 16;
+  cache->superstates_allowed = rx_cache_bound;
+  {
+    struct rx_blocklist ** pos = &cache->memory;
+    int size = bytes_for_cache_size (16, cache->local_cset_size);
+    while (*pos)
+      pos = &(*pos)->next;
+    *pos = ((struct rx_blocklist *)
+	    malloc (size + sizeof (struct rx_blocklist))); 
+    if (!*pos)
+      return;
+
+    (*pos)->next = 0;
+    (*pos)->bytes = size;
+    cache->memory_pos = *pos;
+    cache->memory_addr = (char *)*pos + sizeof (**pos);
+    cache->bytes_left = size;
+  }
+}
+
+static struct rx_cache default_cache = 
+{
+  {
+    supersetcmp,
+    super_hash_allocator,
+    super_hash_liberator,
+    superset_allocator,
+    superset_hash_item_liberator,
+  },
+  0,
+  0,
+  0,
+  0,
+  rx_morecore,
+
+  0,
+  0,
+  0,
+  0,
+  0,
+
+  0,
+  0,
+
+  0,
+
+  0,
+  0,
+  0,
+  0,
+  128,
+
+  256,
+  rx_id_instruction_table,
+
+  {
+    0,
+    0,
+    {0},
+    {0},
+    {0}
+  }
+};
+
+/* This adds an element to a superstate set.  These sets are lists, such
+ * that lists with == elements are ==.  The empty set is returned by
+ * superset_cons (rx, 0, 0) and is NOT equivelent to 
+ * (struct rx_superset)0.
+ */
+
+#ifdef __STDC__
+RX_DECL struct rx_superset *
+rx_superset_cons (struct rx * rx,
+		  struct rx_nfa_state *car, struct rx_superset *cdr)
+#else
+RX_DECL struct rx_superset *
+rx_superset_cons (rx, car, cdr)
+     struct rx * rx;
+     struct rx_nfa_state *car;
+     struct rx_superset *cdr;
+#endif
+{
+  struct rx_cache * cache = rx->cache;
+  if (!car && !cdr)
+    {
+      if (!cache->empty_superset)
+	{
+	  cache->empty_superset
+	    = ((struct rx_superset *)
+	       rx_cache_malloc_or_get (cache, &cache->free_supersets,
+				       sizeof (struct rx_superset)));
+	  if (!cache->empty_superset)
+	    return 0;
+	  bzero (cache->empty_superset, sizeof (struct rx_superset));
+	  cache->empty_superset->refs = 1000;
+	}
+      return cache->empty_superset;
+    }
+  {
+    struct rx_superset template;
+    struct rx_hash_item * hit;
+    template.car = car;
+    template.cdr = cdr;
+    template.id = car->id;
+    hit = rx_hash_store (&cache->superset_table,
+			 (unsigned long)car ^ car->id ^ (unsigned long)cdr,
+			 (void *)&template,
+			 &cache->superset_hash_rules);
+    return (hit
+	    ?  (struct rx_superset *)hit->data
+	    : 0);
+  }
+}
+
+/* This computes a union of two NFA state sets.  The sets do not have the
+ * same representation though.  One is a RX_SUPERSET structure (part
+ * of the superstate NFA) and the other is an NFA_STATE_SET (part of the NFA).
+ */
+
+#ifdef __STDC__
+RX_DECL struct rx_superset *
+rx_superstate_eclosure_union
+  (struct rx * rx, struct rx_superset *set, struct rx_nfa_state_set *ecl) 
+#else
+RX_DECL struct rx_superset *
+rx_superstate_eclosure_union (rx, set, ecl)
+     struct rx * rx;
+     struct rx_superset *set;
+     struct rx_nfa_state_set *ecl;
+#endif
+{
+  if (!ecl)
+    return set;
+
+  if (!set->car)
+    return rx_superset_cons (rx, ecl->car,
+			     rx_superstate_eclosure_union (rx, set, ecl->cdr));
+  if (set->car == ecl->car)
+    return rx_superstate_eclosure_union (rx, set, ecl->cdr);
+
+  {
+    struct rx_superset * tail;
+    struct rx_nfa_state * first;
+
+    if (set->car > ecl->car)
+      {
+	tail = rx_superstate_eclosure_union (rx, set->cdr, ecl);
+	first = set->car;
+      }
+    else
+      {
+	tail = rx_superstate_eclosure_union (rx, set, ecl->cdr);
+	first = ecl->car;
+      }
+    if (!tail)
+      return 0;
+    else
+      {
+	struct rx_superset * answer;
+	answer = rx_superset_cons (rx, first, tail);
+	if (!answer)
+	  {
+	    rx_protect_superset (rx, tail);
+	    rx_release_superset (rx, tail);
+	    return 0;
+	  }
+	else
+	  return answer;
+      }
+  }
+}
+
+
+
+
+
+/*
+ * This makes sure that a list of rx_distinct_futures contains
+ * a future for each possible set of side effects in the eclosure
+ * of a given state.  This is some of the work of filling in a
+ * superstate transition. 
+ */
+
+#ifdef __STDC__
+static struct rx_distinct_future *
+include_futures (struct rx *rx,
+		 struct rx_distinct_future *df, struct rx_nfa_state
+		 *state, struct rx_superstate *superstate) 
+#else
+static struct rx_distinct_future *
+include_futures (rx, df, state, superstate)
+     struct rx *rx;
+     struct rx_distinct_future *df;
+     struct rx_nfa_state *state;
+     struct rx_superstate *superstate;
+#endif
+{
+  struct rx_possible_future *future;
+  struct rx_cache * cache = rx->cache;
+  for (future = state->futures; future; future = future->next)
+    {
+      struct rx_distinct_future *dfp;
+      struct rx_distinct_future *insert_before = 0;
+      if (df)
+	df->next_same_super_edge[1]->next_same_super_edge[0] = 0;
+      for (dfp = df; dfp; dfp = dfp->next_same_super_edge[0])
+	if (dfp->effects == future->effects)
+	  break;
+	else
+	  {
+	    int order = rx->se_list_cmp (rx, dfp->effects, future->effects);
+	    if (order > 0)
+	      {
+		insert_before = dfp;
+		dfp = 0;
+		break;
+	      }
+	  }
+      if (df)
+	df->next_same_super_edge[1]->next_same_super_edge[0] = df;
+      if (!dfp)
+	{
+	  dfp
+	    = ((struct rx_distinct_future *)
+	       rx_cache_malloc_or_get (cache, &cache->free_discernable_futures,
+				       sizeof (struct rx_distinct_future)));
+	  if (!dfp)
+	    return 0;
+	  if (!df)
+	    {
+	      df = insert_before = dfp;
+	      df->next_same_super_edge[0] = df->next_same_super_edge[1] = df;
+	    }
+	  else if (!insert_before)
+	    insert_before = df;
+	  else if (insert_before == df)
+	    df = dfp;
+
+	  dfp->next_same_super_edge[0] = insert_before;
+	  dfp->next_same_super_edge[1]
+	    = insert_before->next_same_super_edge[1];
+	  dfp->next_same_super_edge[1]->next_same_super_edge[0] = dfp;
+	  dfp->next_same_super_edge[0]->next_same_super_edge[1] = dfp;
+	  dfp->next_same_dest = dfp->prev_same_dest = dfp;
+	  dfp->future = 0;
+	  dfp->present = superstate;
+	  dfp->future_frame.inx = rx->instruction_table[rx_cache_miss];
+	  dfp->future_frame.data = 0;
+	  dfp->future_frame.data_2 = (void *) dfp;
+	  dfp->side_effects_frame.inx
+	    = rx->instruction_table[rx_do_side_effects];
+	  dfp->side_effects_frame.data = 0;
+	  dfp->side_effects_frame.data_2 = (void *) dfp;
+	  dfp->effects = future->effects;
+	}
+    }
+  return df;
+}
+
+
+
+
+/* This constructs a new superstate from its state set.  The only 
+ * complexity here is memory management.
+ */
+#ifdef __STDC__
+RX_DECL struct rx_superstate *
+rx_superstate (struct rx *rx,
+	       struct rx_superset *set)
+#else
+RX_DECL struct rx_superstate *
+rx_superstate (rx, set)
+     struct rx *rx;
+     struct rx_superset *set;
+#endif
+{
+  struct rx_cache * cache = rx->cache;
+  struct rx_superstate * superstate = 0;
+
+  /* Does the superstate already exist in the cache? */
+  if (set->superstate)
+    {
+      if (set->superstate->rx_id != rx->rx_id)
+	{
+	  /* Aha.  It is in the cache, but belongs to a superstate
+	   * that refers to an NFA that no longer exists.
+	   * (We know it no longer exists because it was evidently
+	   *  stored in the same region of memory as the current nfa
+	   *  yet it has a different id.)
+	   */
+	  superstate = set->superstate;
+	  if (!superstate->is_semifree)
+	    {
+	      if (cache->lru_superstate == superstate)
+		{
+		  cache->lru_superstate = superstate->next_recyclable;
+		  if (cache->lru_superstate == superstate)
+		    cache->lru_superstate = 0;
+		}
+	      {
+		superstate->next_recyclable->prev_recyclable
+		  = superstate->prev_recyclable;
+		superstate->prev_recyclable->next_recyclable
+		  = superstate->next_recyclable;
+		if (!cache->semifree_superstate)
+		  {
+		    (cache->semifree_superstate
+		     = superstate->next_recyclable
+		     = superstate->prev_recyclable
+		     = superstate);
+		  }
+		else
+		  {
+		    superstate->next_recyclable = cache->semifree_superstate;
+		    superstate->prev_recyclable
+		      = cache->semifree_superstate->prev_recyclable;
+		    superstate->next_recyclable->prev_recyclable
+		      = superstate;
+		    superstate->prev_recyclable->next_recyclable
+		      = superstate;
+		    cache->semifree_superstate = superstate;
+		  }
+		++cache->semifree_superstates;
+	      }
+	    }
+	  set->superstate = 0;
+	  goto handle_cache_miss;
+	}
+      ++cache->hits;
+      superstate = set->superstate;
+
+      rx_refresh_this_superstate (cache, superstate);
+      return superstate;
+    }
+
+ handle_cache_miss:
+
+  /* This point reached only for cache misses. */
+  ++cache->misses;
+#if RX_DEBUG
+  if (rx_debug_trace > 1)
+    {
+      struct rx_superset * setp = set;
+      fprintf (stderr, "Building a superstet %d(%d): ", rx->rx_id, set);
+      while (setp)
+	{
+	  fprintf (stderr, "%d ", setp->id);
+	  setp = setp->cdr;
+	}
+      fprintf (stderr, "(%d)\n", set);
+    }
+#endif
+  superstate = (struct rx_superstate *)rx_cache_get_superstate (cache);
+  if (!superstate)
+    return 0;
+
+  if (!cache->lru_superstate)
+    (cache->lru_superstate
+     = superstate->next_recyclable
+     = superstate->prev_recyclable
+     = superstate);
+  else
+    {
+      superstate->next_recyclable = cache->lru_superstate;
+      superstate->prev_recyclable = cache->lru_superstate->prev_recyclable;
+      (  superstate->prev_recyclable->next_recyclable
+       = superstate->next_recyclable->prev_recyclable
+       = superstate);
+    }
+  superstate->rx_id = rx->rx_id;
+  superstate->transition_refs = 0;
+  superstate->locks = 0;
+  superstate->is_semifree = 0;
+  set->superstate = superstate;
+  superstate->contents = set;
+  rx_protect_superset (rx, set);
+  superstate->edges = 0;
+  {
+    int x;
+    /* None of the transitions from this superstate are known yet. */
+    for (x = 0; x < rx->local_cset_size; ++x) /* &&&&& 3.8 % */
+      {
+	struct rx_inx * ifr = &superstate->transitions[x];
+	ifr->inx = rx->instruction_table [rx_cache_miss];
+	ifr->data = ifr->data_2 = 0;
+      }
+  }
+  return superstate;
+}
+
+
+
+/* This computes the destination set of one edge of the superstate NFA.
+ * Note that a RX_DISTINCT_FUTURE is a superstate edge.
+ * Returns 0 on an allocation failure.
+ */
+
+#ifdef __STDC__
+static int 
+solve_destination (struct rx *rx, struct rx_distinct_future *df)
+#else
+static int 
+solve_destination (rx, df)
+     struct rx *rx;
+     struct rx_distinct_future *df;
+#endif
+{
+  struct rx_super_edge *tc = df->edge;
+  struct rx_superset *nfa_state;
+  struct rx_superset *nil_set = rx_superset_cons (rx, 0, 0);
+  struct rx_superset *solution = nil_set;
+  struct rx_superstate *dest;
+
+  rx_protect_superset (rx, solution);
+  /* Iterate over all NFA states in the state set of this superstate. */
+  for (nfa_state = df->present->contents;
+       nfa_state->car;
+       nfa_state = nfa_state->cdr)
+    {
+      struct rx_nfa_edge *e;
+      /* Iterate over all edges of each NFA state. */
+      for (e = nfa_state->car->edges; e; e = e->next)
+        /* If we find an edge that is labeled with 
+	 * the characters we are solving for.....
+	 */
+	if (rx_bitset_is_subset (rx->local_cset_size,
+				 tc->cset, e->params.cset))
+	  {
+	    struct rx_nfa_state *n = e->dest;
+	    struct rx_possible_future *pf;
+	    /* ....search the partial epsilon closures of the destination
+	     * of that edge for a path that involves the same set of
+	     * side effects we are solving for.
+	     * If we find such a RX_POSSIBLE_FUTURE, we add members to the
+	     * stateset we are computing.
+	     */
+	    for (pf = n->futures; pf; pf = pf->next)
+	      if (pf->effects == df->effects)
+		{
+		  struct rx_superset * old_sol;
+		  old_sol = solution;
+		  solution = rx_superstate_eclosure_union (rx, solution,
+							   pf->destset);
+		  if (!solution)
+		    return 0;
+		  rx_protect_superset (rx, solution);
+		  rx_release_superset (rx, old_sol);
+		}
+	  }
+    }
+  /* It is possible that the RX_DISTINCT_FUTURE we are working on has 
+   * the empty set of NFA states as its definition.  In that case, this
+   * is a failure point.
+   */
+  if (solution == nil_set)
+    {
+      df->future_frame.inx = (void *) rx_backtrack;
+      df->future_frame.data = 0;
+      df->future_frame.data_2 = 0;
+      return 1;
+    }
+  dest = rx_superstate (rx, solution);
+  rx_release_superset (rx, solution);
+  if (!dest)
+    return 0;
+
+  {
+    struct rx_distinct_future *dft;
+    dft = df;
+    df->prev_same_dest->next_same_dest = 0;
+    while (dft)
+      {
+	dft->future = dest;
+	dft->future_frame.inx = rx->instruction_table[rx_next_char];
+	dft->future_frame.data = (void *) dest->transitions;
+	dft = dft->next_same_dest;
+      }
+    df->prev_same_dest->next_same_dest = df;
+  }
+  if (!dest->transition_refs)
+    dest->transition_refs = df;
+  else
+    {
+      struct rx_distinct_future *dft = dest->transition_refs->next_same_dest;
+      dest->transition_refs->next_same_dest = df->next_same_dest;
+      df->next_same_dest->prev_same_dest = dest->transition_refs;
+      df->next_same_dest = dft;
+      dft->prev_same_dest = df;
+    }
+  return 1;
+}
+
+
+/* This takes a superstate and a character, and computes some edges
+ * from the superstate NFA.  In particular, this computes all edges
+ * that lead from SUPERSTATE given CHR.   This function also 
+ * computes the set of characters that share this edge set.
+ * This returns 0 on allocation error.
+ * The character set and list of edges are returned through 
+ * the paramters CSETOUT and DFOUT.
+} */
+
+#ifdef __STDC__
+static int 
+compute_super_edge (struct rx *rx, struct rx_distinct_future **dfout,
+			  rx_Bitset csetout, struct rx_superstate *superstate,
+			  unsigned char chr)  
+#else
+static int 
+compute_super_edge (rx, dfout, csetout, superstate, chr)
+     struct rx *rx;
+     struct rx_distinct_future **dfout;
+     rx_Bitset csetout;
+     struct rx_superstate *superstate;
+     unsigned char chr;
+#endif
+{
+  struct rx_superset *stateset = superstate->contents;
+
+  /* To compute the set of characters that share edges with CHR, 
+   * we start with the full character set, and subtract.
+   */
+  rx_bitset_universe (rx->local_cset_size, csetout);
+  *dfout = 0;
+
+  /* Iterate over the NFA states in the superstate state-set. */
+  while (stateset->car)
+    {
+      struct rx_nfa_edge *e;
+      for (e = stateset->car->edges; e; e = e->next)
+	if (RX_bitset_member (e->params.cset, chr))
+	  {
+	    /* If we find an NFA edge that applies, we make sure there
+	     * are corresponding edges in the superstate NFA.
+	     */
+	    {
+	      struct rx_distinct_future * saved;
+	      saved = *dfout;
+	      *dfout = include_futures (rx, *dfout, e->dest, superstate);
+	      if (!*dfout)
+		{
+		  struct rx_distinct_future * df;
+		  df = saved;
+		  df->next_same_super_edge[1]->next_same_super_edge[0] = 0;
+		  while (df)
+		    {
+		      struct rx_distinct_future *dft;
+		      dft = df;
+		      df = df->next_same_super_edge[0];
+
+		      if (dft->future && dft->future->transition_refs == dft)
+			{
+			  dft->future->transition_refs = dft->next_same_dest;
+			  if (dft->future->transition_refs == dft)
+			    dft->future->transition_refs = 0;
+			}
+		      dft->next_same_dest->prev_same_dest = dft->prev_same_dest;
+		      dft->prev_same_dest->next_same_dest = dft->next_same_dest;
+		      rx_cache_free (rx->cache,
+				     &rx->cache->free_discernable_futures,
+				     (char *)dft);
+		    }
+		  return 0;
+		}
+	    }
+	    /* We also trim the character set a bit. */
+	    rx_bitset_intersection (rx->local_cset_size,
+				    csetout, e->params.cset);
+	  }
+	else
+	  /* An edge that doesn't apply at least tells us some characters
+	   * that don't share the same edge set as CHR.
+	   */
+	  rx_bitset_difference (rx->local_cset_size, csetout, e->params.cset);
+      stateset = stateset->cdr;
+    }
+  return 1;
+}
+
+
+
+/* This is a constructor for RX_SUPER_EDGE structures.  These are
+ * wrappers for lists of superstate NFA edges that share character sets labels.
+ * If a transition class contains more than one rx_distinct_future (superstate
+ * edge), then it represents a non-determinism in the superstate NFA.
+ */
+
+#ifdef __STDC__
+static struct rx_super_edge *
+rx_super_edge (struct rx *rx,
+	       struct rx_superstate *super, rx_Bitset cset,
+	       struct rx_distinct_future *df) 
+#else
+static struct rx_super_edge *
+rx_super_edge (rx, super, cset, df)
+     struct rx *rx;
+     struct rx_superstate *super;
+     rx_Bitset cset;
+     struct rx_distinct_future *df;
+#endif
+{
+  struct rx_super_edge *tc =
+    (struct rx_super_edge *)rx_cache_malloc_or_get
+      (rx->cache, &rx->cache->free_transition_classes,
+       sizeof (struct rx_super_edge) + rx_sizeof_bitset (rx->local_cset_size));
+
+  if (!tc)
+    return 0;
+  tc->next = super->edges;
+  super->edges = tc;
+  tc->rx_backtrack_frame.inx = rx->instruction_table[rx_backtrack_point];
+  tc->rx_backtrack_frame.data = 0;
+  tc->rx_backtrack_frame.data_2 = (void *) tc;
+  tc->options = df;
+  tc->cset = (rx_Bitset) ((char *) tc + sizeof (*tc));
+  rx_bitset_assign (rx->local_cset_size, tc->cset, cset);
+  if (df)
+    {
+      struct rx_distinct_future * dfp = df;
+      df->next_same_super_edge[1]->next_same_super_edge[0] = 0;
+      while (dfp)
+	{
+	  dfp->edge = tc;
+	  dfp = dfp->next_same_super_edge[0];
+	}
+      df->next_same_super_edge[1]->next_same_super_edge[0] = df;
+    }
+  return tc;
+}
+
+
+/* There are three kinds of cache miss.  The first occurs when a
+ * transition is taken that has never been computed during the
+ * lifetime of the source superstate.  That cache miss is handled by
+ * calling COMPUTE_SUPER_EDGE.  The second kind of cache miss
+ * occurs when the destination superstate of a transition doesn't
+ * exist.  SOLVE_DESTINATION is used to construct the destination superstate.
+ * Finally, the third kind of cache miss occurs when the destination
+ * superstate of a transition is in a `semi-free state'.  That case is
+ * handled by UNFREE_SUPERSTATE.
+ *
+ * The function of HANDLE_CACHE_MISS is to figure out which of these
+ * cases applies.
+ */
+
+#ifdef __STDC__
+static void
+install_partial_transition  (struct rx_superstate *super,
+			     struct rx_inx *answer,
+			     RX_subset set, int offset)
+#else
+static void
+install_partial_transition  (super, answer, set, offset)
+     struct rx_superstate *super;
+     struct rx_inx *answer;
+     RX_subset set;
+     int offset;
+#endif
+{
+  int start = offset;
+  int end = start + 32;
+  RX_subset pos = 1;
+  struct rx_inx * transitions = super->transitions;
+  
+  while (start < end)
+    {
+      if (set & pos)
+	transitions[start] = *answer;
+      pos <<= 1;
+      ++start;
+    }
+}
+
+
+#ifdef __STDC__
+RX_DECL struct rx_inx *
+rx_handle_cache_miss
+  (struct rx *rx, struct rx_superstate *super, unsigned char chr, void *data) 
+#else
+RX_DECL struct rx_inx *
+rx_handle_cache_miss (rx, super, chr, data)
+     struct rx *rx;
+     struct rx_superstate *super;
+     unsigned char chr;
+     void *data;
+#endif
+{
+  int offset = chr / RX_subset_bits;
+  struct rx_distinct_future *df = data;
+
+  if (!df)			/* must be the shared_cache_miss_frame */
+    {
+      /* Perhaps this is just a transition waiting to be filled. */
+      struct rx_super_edge *tc;
+      RX_subset mask = rx_subset_singletons [chr % RX_subset_bits];
+
+      for (tc = super->edges; tc; tc = tc->next)
+	if (tc->cset[offset] & mask)
+	  {
+	    struct rx_inx * answer;
+	    df = tc->options;
+	    answer = ((tc->options->next_same_super_edge[0] != tc->options)
+		      ? &tc->rx_backtrack_frame
+		      : (df->effects
+			 ? &df->side_effects_frame
+			 : &df->future_frame));
+	    install_partial_transition (super, answer,
+					tc->cset [offset], offset * 32);
+	    return answer;
+	  }
+      /* Otherwise, it's a flushed or  newly encountered edge. */
+      {
+	char cset_space[1024];	/* this limit is far from unreasonable */
+	rx_Bitset trcset;
+	struct rx_inx *answer;
+
+	if (rx_sizeof_bitset (rx->local_cset_size) > sizeof (cset_space))
+	  return 0;		/* If the arbitrary limit is hit, always fail */
+				/* cleanly. */
+	trcset = (rx_Bitset)cset_space;
+	rx_lock_superstate (rx, super);
+	if (!compute_super_edge (rx, &df, trcset, super, chr))
+	  {
+	    rx_unlock_superstate (rx, super);
+	    return 0;
+	  }
+	if (!df)		/* We just computed the fail transition. */
+	  {
+	    static struct rx_inx
+	      shared_fail_frame = { 0, 0, (void *)rx_backtrack, 0 };
+	    answer = &shared_fail_frame;
+	  }
+	else
+	  {
+	    tc = rx_super_edge (rx, super, trcset, df);
+	    if (!tc)
+	      {
+		rx_unlock_superstate (rx, super);
+		return 0;
+	      }
+	    answer = ((tc->options->next_same_super_edge[0] != tc->options)
+		      ? &tc->rx_backtrack_frame
+		      : (df->effects
+			 ? &df->side_effects_frame
+			 : &df->future_frame));
+	  }
+	install_partial_transition (super, answer,
+				    trcset[offset], offset * 32);
+	rx_unlock_superstate (rx, super);
+	return answer;
+      }
+    }
+  else if (df->future) /* A cache miss on an edge with a future? Must be
+			* a semi-free destination. */
+    {				
+      if (df->future->is_semifree)
+	refresh_semifree_superstate (rx->cache, df->future);
+      return &df->future_frame;
+    }
+  else
+    /* no future superstate on an existing edge */
+    {
+      rx_lock_superstate (rx, super);
+      if (!solve_destination (rx, df))
+	{
+	  rx_unlock_superstate (rx, super);
+	  return 0;
+	}
+      if (!df->effects
+	  && (df->edge->options->next_same_super_edge[0] == df->edge->options))
+	install_partial_transition (super, &df->future_frame,
+				    df->edge->cset[offset], offset * 32);
+      rx_unlock_superstate (rx, super);
+      return &df->future_frame;
+    }
+}
+
+
+
+
+
+/* The rest of the code provides a regex.c compatable interface. */
+
+
+__const__ char *re_error_msg[] =
+{
+  0,						/* REG_NOUT */
+  "No match",					/* REG_NOMATCH */
+  "Invalid regular expression",			/* REG_BADPAT */
+  "Invalid collation character",		/* REG_ECOLLATE */
+  "Invalid character class name",		/* REG_ECTYPE */
+  "Trailing backslash",				/* REG_EESCAPE */
+  "Invalid back reference",			/* REG_ESUBREG */
+  "Unmatched [ or [^",				/* REG_EBRACK */
+  "Unmatched ( or \\(",				/* REG_EPAREN */
+  "Unmatched \\{",				/* REG_EBRACE */
+  "Invalid content of \\{\\}",			/* REG_BADBR */
+  "Invalid range end",				/* REG_ERANGE */
+  "Memory exhausted",				/* REG_ESPACE */
+  "Invalid preceding regular expression",	/* REG_BADRPT */
+  "Premature end of regular expression",	/* REG_EEND */
+  "Regular expression too big",			/* REG_ESIZE */
+  "Unmatched ) or \\)",				/* REG_ERPAREN */
+};
+
+
+
+
+/* 
+ * Macros used while compiling patterns.
+ *
+ * By convention, PEND points just past the end of the uncompiled pattern,
+ * P points to the read position in the pattern.  `translate' is the name
+ * of the translation table (`TRANSLATE' is the name of a macro that looks
+ * things up in `translate').
+ */
+
+
+/*
+ * Fetch the next character in the uncompiled pattern---translating it 
+ * if necessary. *Also cast from a signed character in the constant
+ * string passed to us by the user to an unsigned char that we can use
+ * as an array index (in, e.g., `translate').
+ */
+#define PATFETCH(c)							\
+ do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++;						\
+    c = translate[c];		 					\
+ } while (0)
+
+/* 
+ * Fetch the next character in the uncompiled pattern, with no
+ * translation.
+ */
+#define PATFETCH_RAW(c)							\
+  do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++; 						\
+  } while (0)
+
+/* Go backwards one character in the pattern.  */
+#define PATUNFETCH p--
+
+
+#define TRANSLATE(d) translate[(unsigned char) (d)]
+
+typedef unsigned regnum_t;
+
+/* Since offsets can go either forwards or backwards, this type needs to
+ * be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.
+ */
+typedef int pattern_offset_t;
+
+typedef struct
+{
+  struct rexp_node ** top_expression; /* was begalt */
+  struct rexp_node ** last_expression; /* was laststart */
+  pattern_offset_t inner_group_offset;
+  regnum_t regnum;
+} compile_stack_elt_t;
+
+typedef struct
+{
+  compile_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;			/* Offset of next open position.  */
+} compile_stack_type;
+
+
+#define INIT_COMPILE_STACK_SIZE 32
+
+#define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
+
+/* The next available element.  */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+
+/* Set the bit for character C in a list.  */
+#define SET_LIST_BIT(c)                               \
+  (b[((unsigned char) (c)) / CHARBITS]               \
+   |= 1 << (((unsigned char) c) % CHARBITS))
+
+/* Get the next unsigned number in the uncompiled pattern.  */
+#define GET_UNSIGNED_NUMBER(num) 					\
+  { if (p != pend)							\
+     {									\
+       PATFETCH (c); 							\
+       while (isdigit (c)) 						\
+         { 								\
+           if (num < 0)							\
+              num = 0;							\
+           num = num * 10 + c - '0'; 					\
+           if (p == pend) 						\
+              break; 							\
+           PATFETCH (c);						\
+         } 								\
+       } 								\
+    }		
+
+#define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+#define IS_CHAR_CLASS(string)						\
+   (!strcmp (string, "alpha") || !strcmp (string, "upper")		\
+    || !strcmp (string, "lower") || !strcmp (string, "digit")		\
+    || !strcmp (string, "alnum") || !strcmp (string, "xdigit")		\
+    || !strcmp (string, "space") || !strcmp (string, "print")		\
+    || !strcmp (string, "punct") || !strcmp (string, "graph")		\
+    || !strcmp (string, "cntrl") || !strcmp (string, "blank"))
+
+
+
+/* These predicates are used in regex_compile. */
+
+/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
+ * after an alternative or a begin-subexpression.  We assume there is at
+ * least one character before the ^.  
+ */
+
+#ifdef __STDC__
+static boolean
+at_begline_loc_p (__const__ char *pattern, __const__ char * p, reg_syntax_t syntax)
+#else
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+     __const__ char *pattern;
+     __const__ char * p;
+     reg_syntax_t syntax;
+#endif
+{
+  __const__ char *prev = p - 2;
+  boolean prev_prev_backslash = ((prev > pattern) && (prev[-1] == '\\'));
+  
+    return
+      
+      (/* After a subexpression?  */
+       ((*prev == '(') && ((syntax & RE_NO_BK_PARENS) || prev_prev_backslash))
+       ||
+       /* After an alternative?  */
+       ((*prev == '|') && ((syntax & RE_NO_BK_VBAR) || prev_prev_backslash))
+       );
+}
+
+/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
+ * at least one character after the $, i.e., `P < PEND'.
+ */
+
+#ifdef __STDC__
+static boolean
+at_endline_loc_p (__const__ char *p, __const__ char *pend, int syntax)
+#else
+static boolean
+at_endline_loc_p (p, pend, syntax)
+     __const__ char *p;
+     __const__ char *pend;
+     int syntax;
+#endif
+{
+  __const__ char *next = p;
+  boolean next_backslash = (*next == '\\');
+  __const__ char *next_next = (p + 1 < pend) ? (p + 1) : 0;
+  
+  return
+    (
+     /* Before a subexpression?  */
+     ((syntax & RE_NO_BK_PARENS)
+      ? (*next == ')')
+      : (next_backslash && next_next && (*next_next == ')')))
+    ||
+     /* Before an alternative?  */
+     ((syntax & RE_NO_BK_VBAR)
+      ? (*next == '|')
+      : (next_backslash && next_next && (*next_next == '|')))
+     );
+}
+
+
+
+unsigned char rx_id_translation[256] =
+{
+  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
+ 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
+ 250, 251, 252, 253, 254, 255
+};
+
+/* The compiler keeps an inverted translation table.
+ * This looks up/inititalize elements.
+ * VALID is an array of booleans that validate CACHE.
+ */
+
+#ifdef __STDC__
+static rx_Bitset
+inverse_translation (struct re_pattern_buffer * rxb,
+		     char * valid, rx_Bitset cache,
+		     unsigned char * translate, int c)
+#else
+static rx_Bitset
+inverse_translation (rxb, valid, cache, translate, c)
+     struct re_pattern_buffer * rxb;
+     char * valid;
+     rx_Bitset cache;
+     unsigned char * translate;
+     int c;
+#endif
+{
+  rx_Bitset cs
+    = cache + c * rx_bitset_numb_subsets (rxb->rx.local_cset_size); 
+
+  if (!valid[c])
+    {
+      int x;
+      int c_tr = TRANSLATE(c);
+      rx_bitset_null (rxb->rx.local_cset_size, cs);
+      for (x = 0; x < 256; ++x)	/* &&&& 13.37 */
+	if (TRANSLATE(x) == c_tr)
+	  RX_bitset_enjoin (cs, x);
+      valid[c] = 1;
+    }
+  return cs;
+}
+
+
+
+
+
+/* More subroutine declarations and macros for regex_compile.  */
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and 
+   false if it's not.  */
+
+#ifdef __STDC__
+static boolean
+group_in_compile_stack (compile_stack_type compile_stack, regnum_t regnum)
+#else
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+    compile_stack_type compile_stack;
+    regnum_t regnum;
+#endif
+{
+  int this_element;
+
+  for (this_element = compile_stack.avail - 1;  
+       this_element >= 0; 
+       this_element--)
+    if (compile_stack.stack[this_element].regnum == regnum)
+      return true;
+
+  return false;
+}
+
+
+/*
+ * Read the ending character of a range (in a bracket expression) from the
+ * uncompiled pattern *P_PTR (which ends at PEND).  We assume the
+ * starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
+ * Then we set the translation of all bits between the starting and
+ * ending characters (inclusive) in the compiled pattern B.
+ * 
+ * Return an error code.
+ * 
+ * We use these short variable names so we can use the same macros as
+ * `regex_compile' itself.  
+ */
+
+#ifdef __STDC__
+static reg_errcode_t
+compile_range (struct re_pattern_buffer * rxb, rx_Bitset cs,
+	       __const__ char ** p_ptr, __const__ char * pend,
+	       unsigned char * translate, reg_syntax_t syntax,
+	       rx_Bitset inv_tr,  char * valid_inv_tr)
+#else
+static reg_errcode_t
+compile_range (rxb, cs, p_ptr, pend, translate, syntax, inv_tr, valid_inv_tr)
+     struct re_pattern_buffer * rxb;
+     rx_Bitset cs;
+     __const__ char ** p_ptr;
+     __const__ char * pend;
+     unsigned char * translate;
+     reg_syntax_t syntax;
+     rx_Bitset inv_tr;
+     char * valid_inv_tr;
+#endif
+{
+  unsigned this_char;
+
+  __const__ char *p = *p_ptr;
+
+  unsigned char range_end;
+  unsigned char range_start = TRANSLATE(p[-2]);
+
+  if (p == pend)
+    return REG_ERANGE;
+
+  PATFETCH (range_end);
+
+  (*p_ptr)++;
+
+  if (range_start > range_end)
+    return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+  for (this_char = range_start; this_char <= range_end; this_char++)
+    {
+      rx_Bitset it =
+	inverse_translation (rxb, valid_inv_tr, inv_tr, translate, this_char);
+      rx_bitset_union (rxb->rx.local_cset_size, cs, it);
+    }
+  
+  return REG_NOERROR;
+}
+
+
+
+/* This searches a regexp for backreference side effects.
+ * It fills in the array OUT with 1 at the index of every register pair
+ * referenced by a backreference.
+ *
+ * This is used to help optimize patterns for searching.  The information is
+ * useful because, if the caller doesn't want register values, backreferenced
+ * registers are the only registers for which we need rx_backtrack.
+ */
+
+#ifdef __STDC__
+static void
+find_backrefs (char * out, struct rexp_node * rexp,
+	       struct re_se_params * params)
+#else
+static void
+find_backrefs (out, rexp, params)
+     char * out;
+     struct rexp_node * rexp;
+     struct re_se_params * params;
+#endif
+{
+  if (rexp)
+    switch (rexp->type)
+      {
+      case r_cset:
+      case r_data:
+	return;
+      case r_alternate:
+      case r_concat:
+      case r_opt:
+      case r_star:
+      case r_2phase_star:
+	find_backrefs (out, rexp->params.pair.left, params);
+	find_backrefs (out, rexp->params.pair.right, params);
+	return;
+      case r_side_effect:
+	if (   ((long)rexp->params.side_effect >= 0)
+	    && (params [(long)rexp->params.side_effect].se == re_se_backref))
+	  out[ params [(long)rexp->params.side_effect].op1] = 1;
+	return;
+      }
+}
+
+
+
+
+/* Returns 0 unless the pattern can match the empty string. */
+
+#ifdef __STDC__
+static int
+compute_fastset (struct re_pattern_buffer * rxb, struct rexp_node * rexp)
+#else
+static int
+compute_fastset (rxb, rexp)
+     struct re_pattern_buffer * rxb;
+     struct rexp_node * rexp;
+#endif
+{
+  if (!rexp)
+    return 1;
+  switch (rexp->type)
+    {
+    case r_data:
+      return 1;
+    case r_cset:
+      {
+	rx_bitset_union (rxb->rx.local_cset_size,
+			 rxb->fastset, rexp->params.cset);
+      }
+      return 0;
+    case r_concat:
+      return (compute_fastset (rxb, rexp->params.pair.left)
+	      && compute_fastset (rxb, rexp->params.pair.right));
+    case r_2phase_star:
+      compute_fastset (rxb, rexp->params.pair.left);
+      /* compute_fastset (rxb, rexp->params.pair.right);  nope... */
+      return 1;
+    case r_alternate:
+      return !!(compute_fastset (rxb, rexp->params.pair.left)
+		+ compute_fastset (rxb, rexp->params.pair.right));
+    case r_opt:
+    case r_star:
+      compute_fastset (rxb, rexp->params.pair.left);
+      return 1;
+    case r_side_effect:
+      return 1;
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+/* returns
+ *  1 -- yes, definately anchored by the given side effect.
+ *  2 -- maybe anchored, maybe the empty string.
+ *  0 -- definately not anchored
+ *  There is simply no other possibility.
+ */
+
+#ifdef __STDC__
+static int
+is_anchored (struct rexp_node * rexp, rx_side_effect se)
+#else
+static int
+is_anchored (rexp, se)
+     struct rexp_node * rexp;
+     rx_side_effect se;
+#endif
+{
+  if (!rexp)
+    return 2;
+  switch (rexp->type)
+    {
+    case r_cset:
+    case r_data:
+      return 0;
+    case r_concat:
+    case r_2phase_star:
+      {
+	int l = is_anchored (rexp->params.pair.left, se);
+	return (l == 2 ? is_anchored (rexp->params.pair.right, se) : l);
+      }
+    case r_alternate:
+      {
+	int l = is_anchored (rexp->params.pair.left, se);
+	int r = l ? is_anchored (rexp->params.pair.right, se) : 0;
+
+	if (l == r)
+	  return l;
+	else if ((l == 0) || (r == 0))
+	  return 0;
+	else
+	  return 2;
+      }
+    case r_opt:
+    case r_star:
+      return is_anchored (rexp->params.pair.left, se) ? 2 : 0;
+      
+    case r_side_effect:
+      return ((rexp->params.side_effect == se)
+	      ? 1 : 2);
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+/* This removes register assignments that aren't required by backreferencing.
+ * This can speed up explore_future, especially if it eliminates
+ * non-determinism in the superstate NFA.
+ * 
+ * NEEDED is an array of characters, presumably filled in by FIND_BACKREFS.
+ * The non-zero elements of the array indicate which register assignments
+ * can NOT be removed from the expression.
+ */
+
+#ifdef __STDC__
+static struct rexp_node *
+remove_unecessary_side_effects (struct rx * rx, char * needed,
+				struct rexp_node * rexp,
+				struct re_se_params * params)
+#else
+static struct rexp_node *
+remove_unecessary_side_effects (rx, needed, rexp, params)
+     struct rx * rx;
+     char * needed;
+     struct rexp_node * rexp;
+     struct re_se_params * params;
+#endif
+{
+  struct rexp_node * l;
+  struct rexp_node * r;
+  if (!rexp)
+    return 0;
+  else
+    switch (rexp->type)
+      {
+      case r_cset:
+      case r_data:
+	return rexp;
+      case r_alternate:
+      case r_concat:
+      case r_2phase_star:
+	l = remove_unecessary_side_effects (rx, needed,
+					    rexp->params.pair.left, params);
+	r = remove_unecessary_side_effects (rx, needed,
+					    rexp->params.pair.right, params);
+	if ((l && r) || (rexp->type != r_concat))
+	  {
+	    rexp->params.pair.left = l;
+	    rexp->params.pair.right = r;
+	    return rexp;
+	  }
+	else
+	  {
+	    rexp->params.pair.left = rexp->params.pair.right = 0;
+	    rx_free_rexp (rx, rexp);
+	    return l ? l : r;
+	  }
+      case r_opt:
+      case r_star:
+	l = remove_unecessary_side_effects (rx, needed,
+					    rexp->params.pair.left, params);
+	if (l)
+	  {
+	    rexp->params.pair.left = l;
+	    return rexp;
+	  }
+	else
+	  {
+	    rexp->params.pair.left = 0;
+	    rx_free_rexp (rx, rexp);
+	    return 0;
+	  }
+      case r_side_effect:
+	{
+	  int se = (long)rexp->params.side_effect;
+	  if (   (se >= 0)
+	      && (   ((enum re_side_effects)params[se].se == re_se_lparen)
+		  || ((enum re_side_effects)params[se].se == re_se_rparen))
+	      && (params [se].op1 > 0)
+	      && (!needed [params [se].op1]))
+	    {
+	      rx_free_rexp (rx, rexp);
+	      return 0;
+	    }
+	  else
+	    return rexp;
+	}
+      }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+
+#ifdef __STDC__
+static int
+pointless_if_repeated (struct rexp_node * node, struct re_se_params * params)
+#else
+static int
+pointless_if_repeated (node, params)
+     struct rexp_node * node;
+     struct re_se_params * params;
+#endif
+{
+  if (!node)
+    return 1;
+  switch (node->type)
+    {
+    case r_cset:
+      return 0;
+    case r_alternate:
+    case r_concat:
+    case r_2phase_star:
+      return (pointless_if_repeated (node->params.pair.left, params)
+	      && pointless_if_repeated (node->params.pair.right, params));
+    case r_opt:
+    case r_star:
+      return pointless_if_repeated (node->params.pair.left, params);
+    case r_side_effect:
+      switch ((enum re_side_effects) (((long)node->params.side_effect < 0)
+	      ? (enum re_side_effects) (long) node->params.side_effect
+	      : (enum re_side_effects)params[(long)node->params.side_effect].se))
+	{
+	case re_se_try:
+	case re_se_at_dot:
+	case re_se_begbuf:
+	case re_se_hat:
+	case re_se_wordbeg:
+	case re_se_wordbound:
+	case re_se_notwordbound:
+	case re_se_wordend:
+	case re_se_endbuf:
+	case re_se_dollar:
+	case re_se_fail:
+	case re_se_win:
+	  return 1;
+	case re_se_lparen:
+	case re_se_rparen:
+	case re_se_iter:
+	case re_se_end_iter:
+	case re_se_syntax:
+	case re_se_not_syntax:
+	case re_se_backref:
+	  return 0;
+	}
+    case r_data:
+    default:
+      return 0;
+    }
+}
+
+
+
+
+#ifdef __STDC__
+static int
+registers_on_stack (struct re_pattern_buffer * rxb,
+		    struct rexp_node * rexp, int in_danger,
+		    struct re_se_params * params)
+#else
+static int
+registers_on_stack (rxb, rexp, in_danger, params)
+     struct re_pattern_buffer * rxb;
+     struct rexp_node * rexp;
+     int in_danger;
+     struct re_se_params * params;
+#endif
+{
+  if (!rexp)
+    return 0;
+  else
+    switch (rexp->type)
+      {
+      case r_cset:
+      case r_data:
+	return 0;
+      case r_alternate:
+      case r_concat:
+	return (   registers_on_stack (rxb, rexp->params.pair.left,
+				       in_danger, params)
+		|| (registers_on_stack
+		    (rxb, rexp->params.pair.right,
+		     in_danger, params)));
+      case r_opt:
+	return registers_on_stack (rxb, rexp->params.pair.left, 0, params);
+      case r_star:
+	return registers_on_stack (rxb, rexp->params.pair.left, 1, params);
+      case r_2phase_star:
+	return
+	  (   registers_on_stack (rxb, rexp->params.pair.left, 1, params)
+	   || registers_on_stack (rxb, rexp->params.pair.right, 1, params));
+      case r_side_effect:
+	{
+	  int se = (long)rexp->params.side_effect;
+	  if (   in_danger
+	      && (se >= 0)
+	      && (params [se].op1 > 0)
+	      && (   ((enum re_side_effects)params[se].se == re_se_lparen)
+		  || ((enum re_side_effects)params[se].se == re_se_rparen)))
+	    return 1;
+	  else
+	    return 0;
+	}
+      }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+
+static char idempotent_complex_se[] =
+{
+#define RX_WANT_SE_DEFS 1
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#define RX_DEF_SE(IDEM, NAME, VALUE)	      
+#define RX_DEF_CPLX_SE(IDEM, NAME, VALUE)     IDEM,
+#include "rx.h"
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#undef RX_WANT_SE_DEFS
+  23
+};
+
+static char idempotent_se[] =
+{
+  13,
+#define RX_WANT_SE_DEFS 1
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#define RX_DEF_SE(IDEM, NAME, VALUE)	      IDEM,
+#define RX_DEF_CPLX_SE(IDEM, NAME, VALUE)     
+#include "rx.h"
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#undef RX_WANT_SE_DEFS
+  42
+};
+
+
+
+
+
+#ifdef __STDC__
+static int
+has_any_se (struct rx * rx,
+	    struct rexp_node * rexp)
+#else
+static int
+has_any_se (rx, rexp)
+     struct rx * rx;
+     struct rexp_node * rexp;
+#endif
+{
+  if (!rexp)
+    return 0;
+
+  switch (rexp->type)
+    {
+    case r_cset:
+    case r_data:
+      return 0;
+
+    case r_side_effect:
+      return 1;
+      
+    case r_2phase_star:
+    case r_concat:
+    case r_alternate:
+      return
+	(   has_any_se (rx, rexp->params.pair.left)
+	 || has_any_se (rx, rexp->params.pair.right));
+
+    case r_opt:
+    case r_star:
+      return has_any_se (rx, rexp->params.pair.left);
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+
+/* This must be called AFTER `convert_hard_loops' for a given REXP. */
+#ifdef __STDC__
+static int
+has_non_idempotent_epsilon_path (struct rx * rx,
+				 struct rexp_node * rexp,
+				 struct re_se_params * params)
+#else
+static int
+has_non_idempotent_epsilon_path (rx, rexp, params)
+     struct rx * rx;
+     struct rexp_node * rexp;
+     struct re_se_params * params;
+#endif
+{
+  if (!rexp)
+    return 0;
+
+  switch (rexp->type)
+    {
+    case r_cset:
+    case r_data:
+    case r_star:
+      return 0;
+
+    case r_side_effect:
+      return
+	!((long)rexp->params.side_effect > 0
+	  ? idempotent_complex_se [ params [(long)rexp->params.side_effect].se ]
+	  : idempotent_se [-(long)rexp->params.side_effect]);
+      
+    case r_alternate:
+      return
+	(   has_non_idempotent_epsilon_path (rx,
+					     rexp->params.pair.left, params)
+	 || has_non_idempotent_epsilon_path (rx,
+					     rexp->params.pair.right, params));
+
+    case r_2phase_star:
+    case r_concat:
+      return
+	(   has_non_idempotent_epsilon_path (rx,
+					     rexp->params.pair.left, params)
+	 && has_non_idempotent_epsilon_path (rx,
+					     rexp->params.pair.right, params));
+
+    case r_opt:
+      return has_non_idempotent_epsilon_path (rx,
+					      rexp->params.pair.left, params);
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+
+/* This computes rougly what it's name suggests.   It can (and does) go wrong 
+ * in the direction of returning spurious 0 without causing disasters.
+ */
+#ifdef __STDC__
+static int
+begins_with_complex_se (struct rx * rx, struct rexp_node * rexp)
+#else
+static int
+begins_with_complex_se (rx, rexp)
+     struct rx * rx;
+     struct rexp_node * rexp;
+#endif
+{
+  if (!rexp)
+    return 0;
+
+  switch (rexp->type)
+    {
+    case r_cset:
+    case r_data:
+      return 0;
+
+    case r_side_effect:
+      return ((long)rexp->params.side_effect >= 0);
+      
+    case r_alternate:
+      return
+	(   begins_with_complex_se (rx, rexp->params.pair.left)
+	 && begins_with_complex_se (rx, rexp->params.pair.right));
+
+
+    case r_concat:
+      return has_any_se (rx, rexp->params.pair.left);
+    case r_opt:
+    case r_star:
+    case r_2phase_star:
+      return 0;
+    }
+
+  /* this should never happen */
+  return 0;
+}
+
+
+
+/* This destructively removes some of the re_se_tv side effects from 
+ * a rexp tree.  In particular, during parsing re_se_tv was inserted on the
+ * right half of every | to guarantee that posix path preference could be 
+ * honored.  This function removes some which it can be determined aren't 
+ * needed.  
+ */
+
+#ifdef __STDC__
+static void
+speed_up_alt (struct rx * rx,
+	      struct rexp_node * rexp,
+	      int unposix)
+#else
+static void
+speed_up_alt (rx, rexp, unposix)
+     struct rx * rx;
+     struct rexp_node * rexp;
+     int unposix;
+#endif
+{
+  if (!rexp)
+    return;
+
+  switch (rexp->type)
+    {
+    case r_cset:
+    case r_data:
+    case r_side_effect:
+      return;
+
+    case r_opt:
+    case r_star:
+      speed_up_alt (rx, rexp->params.pair.left, unposix);
+      return;
+
+    case r_2phase_star:
+    case r_concat:
+      speed_up_alt (rx, rexp->params.pair.left, unposix);
+      speed_up_alt (rx, rexp->params.pair.right, unposix);
+      return;
+
+    case r_alternate:
+      /* the right child is guaranteed to be (concat re_se_tv <subexp>) */
+
+      speed_up_alt (rx, rexp->params.pair.left, unposix);
+      speed_up_alt (rx, rexp->params.pair.right->params.pair.right, unposix);
+      
+      if (   unposix
+	  || (begins_with_complex_se
+	      (rx, rexp->params.pair.right->params.pair.right))
+	  || !(   has_any_se (rx, rexp->params.pair.right->params.pair.right)
+	       || has_any_se (rx, rexp->params.pair.left)))
+	{
+	  struct rexp_node * conc = rexp->params.pair.right;
+	  rexp->params.pair.right = conc->params.pair.right;
+	  conc->params.pair.right = 0;
+	  rx_free_rexp (rx, conc);
+	}
+    }
+}
+
+
+
+
+
+
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+   Returns one of error codes defined in `regex.h', or zero for success.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate'
+   fields are set in BUFP on entry.
+
+   If it succeeds, results are put in BUFP (if it returns an error, the
+   contents of BUFP are undefined):
+     `buffer' is the compiled pattern;
+     `syntax' is set to SYNTAX;
+     `used' is set to the length of the compiled pattern;
+     `fastmap_accurate' is set to zero;
+     `re_nsub' is set to the number of groups in PATTERN;
+     `not_bol' and `not_eol' are set to zero.
+   
+   The `fastmap' and `newline_anchor' fields are neither
+   examined nor set.  */
+
+
+
+#ifdef __STDC__
+RX_DECL reg_errcode_t
+rx_compile (__const__ char *pattern, int size,
+	    reg_syntax_t syntax,
+	    struct re_pattern_buffer * rxb) 
+#else
+RX_DECL reg_errcode_t
+rx_compile (pattern, size, syntax, rxb)
+     __const__ char *pattern;
+     int size;
+     reg_syntax_t syntax;
+     struct re_pattern_buffer * rxb;
+#endif
+{
+  RX_subset
+    inverse_translate [CHAR_SET_SIZE * rx_bitset_numb_subsets(CHAR_SET_SIZE)];
+  char
+    validate_inv_tr [CHAR_SET_SIZE * rx_bitset_numb_subsets(CHAR_SET_SIZE)];
+
+  /* We fetch characters from PATTERN here.  Even though PATTERN is
+     `char *' (i.e., signed), we declare these variables as unsigned, so
+     they can be reliably used as array indices.  */
+  register unsigned char c, c1;
+  
+  /* A random tempory spot in PATTERN.  */
+  __const__ char *p1;
+  
+  /* Keeps track of unclosed groups.  */
+  compile_stack_type compile_stack;
+
+  /* Points to the current (ending) position in the pattern.  */
+  __const__ char *p = pattern;
+  __const__ char *pend = pattern + size;
+  
+  /* How to translate the characters in the pattern.  */
+  unsigned char *translate = (rxb->translate
+			      ? rxb->translate
+			      : rx_id_translation);
+
+  /* When parsing is done, this will hold the expression tree. */
+  struct rexp_node * rexp = 0;
+
+  /* In the midst of compilation, this holds onto the regexp 
+   * first parst while rexp goes on to aquire additional constructs.
+   */
+  struct rexp_node * orig_rexp = 0;
+  struct rexp_node * fewer_side_effects = 0;
+
+  /* This and top_expression are saved on the compile stack. */
+  struct rexp_node ** top_expression = &rexp;
+  struct rexp_node ** last_expression = top_expression;
+  
+  /* Parameter to `goto append_node' */
+  struct rexp_node * append;
+
+  /* Counts open-groups as they are encountered.  This is the index of the
+   * innermost group being compiled.
+   */
+  regnum_t regnum = 0;
+
+  /* Place in the uncompiled pattern (i.e., the {) to
+   * which to go back if the interval is invalid.  
+   */
+  __const__ char *beg_interval;
+
+  struct re_se_params * params = 0;
+  int paramc = 0;		/* How many complex side effects so far? */
+
+  rx_side_effect side;		/* param to `goto add_side_effect' */
+
+  bzero (validate_inv_tr, sizeof (validate_inv_tr));
+
+  rxb->rx.instruction_table = rx_id_instruction_table;
+
+
+  /* Initialize the compile stack.  */
+  compile_stack.stack =  (( compile_stack_elt_t *) malloc ((INIT_COMPILE_STACK_SIZE) * sizeof ( compile_stack_elt_t)));
+  if (compile_stack.stack == 0)
+    return REG_ESPACE;
+
+  compile_stack.size = INIT_COMPILE_STACK_SIZE;
+  compile_stack.avail = 0;
+
+  /* Initialize the pattern buffer.  */
+  rxb->rx.cache = &default_cache;
+  rxb->syntax = syntax;
+  rxb->fastmap_accurate = 0;
+  rxb->not_bol = rxb->not_eol = 0;
+  rxb->least_subs = 0;
+  
+  /* Always count groups, whether or not rxb->no_sub is set.  
+   * The whole pattern is implicitly group 0, so counting begins
+   * with 1.
+   */
+  rxb->re_nsub = 0;
+
+#if !defined (emacs) && !defined (SYNTAX_TABLE)
+  /* Initialize the syntax table.  */
+   init_syntax_once ();
+#endif
+
+  /* Loop through the uncompiled pattern until we're at the end.  */
+  while (p != pend)
+    {
+      PATFETCH (c);
+
+      switch (c)
+        {
+        case '^':
+          {
+            if (   /* If at start of pattern, it's an operator.  */
+                   p == pattern + 1
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's come before.  */
+                || at_begline_loc_p (pattern, p, syntax))
+	      {
+		struct rexp_node * n
+		  = rx_mk_r_side_effect (&rxb->rx, (rx_side_effect)re_se_hat);
+		if (!n)
+		  return REG_ESPACE;
+		append = n;
+		goto append_node;
+	      }
+            else
+              goto normal_char;
+          }
+          break;
+
+
+        case '$':
+          {
+            if (   /* If at end of pattern, it's an operator.  */
+                   p == pend 
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's next.  */
+                || at_endline_loc_p (p, pend, syntax))
+	      {
+		struct rexp_node * n
+		  = rx_mk_r_side_effect (&rxb->rx, (rx_side_effect)re_se_dollar);
+		if (!n)
+		  return REG_ESPACE;
+		append = n;
+		goto append_node;
+	      }
+             else
+               goto normal_char;
+           }
+           break;
+
+
+	case '+':
+        case '?':
+          if ((syntax & RE_BK_PLUS_QM)
+              || (syntax & RE_LIMITED_OPS))
+            goto normal_char;
+
+        handle_plus:
+        case '*':
+          /* If there is no previous pattern... */
+          if (pointless_if_repeated (*last_expression, params))
+            {
+              if (syntax & RE_CONTEXT_INVALID_OPS)
+                return REG_BADRPT;
+              else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+                goto normal_char;
+            }
+
+          {
+            /* 1 means zero (many) matches is allowed.  */
+            char zero_times_ok = 0, many_times_ok = 0;
+
+            /* If there is a sequence of repetition chars, collapse it
+               down to just one (the right one).  We can't combine
+               interval operators with these because of, e.g., `a{2}*',
+               which should only match an even number of `a's.  */
+
+            for (;;)
+              {
+                zero_times_ok |= c != '+';
+                many_times_ok |= c != '?';
+
+                if (p == pend)
+                  break;
+
+                PATFETCH (c);
+
+                if (c == '*'
+                    || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+                  ;
+
+                else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
+                  {
+                    if (p == pend) return REG_EESCAPE;
+
+                    PATFETCH (c1);
+                    if (!(c1 == '+' || c1 == '?'))
+                      {
+                        PATUNFETCH;
+                        PATUNFETCH;
+                        break;
+                      }
+
+                    c = c1;
+                  }
+                else
+                  {
+                    PATUNFETCH;
+                    break;
+                  }
+
+                /* If we get here, we found another repeat character.  */
+               }
+
+            /* Star, etc. applied to an empty pattern is equivalent
+               to an empty pattern.  */
+            if (!last_expression)
+              break;
+
+	    /* Now we know whether or not zero matches is allowed
+	     * and also whether or not two or more matches is allowed.
+	     */
+
+	    {
+	      struct rexp_node * inner_exp = *last_expression;
+	      int need_sync = 0;
+
+	      if (many_times_ok
+		  && has_non_idempotent_epsilon_path (&rxb->rx,
+						      inner_exp, params))
+		{
+		  struct rexp_node * pusher
+		    = rx_mk_r_side_effect (&rxb->rx,
+					   (rx_side_effect)re_se_pushpos);
+		  struct rexp_node * checker
+		    = rx_mk_r_side_effect (&rxb->rx,
+					   (rx_side_effect)re_se_chkpos);
+		  struct rexp_node * pushback
+		    = rx_mk_r_side_effect (&rxb->rx,
+					   (rx_side_effect)re_se_pushback);
+		  rx_Bitset cs = rx_cset (&rxb->rx);
+		  struct rexp_node * lit_t = rx_mk_r_cset (&rxb->rx, cs);
+		  struct rexp_node * fake_state
+		    = rx_mk_r_concat (&rxb->rx, pushback, lit_t);
+		  struct rexp_node * phase2
+		    = rx_mk_r_concat (&rxb->rx, checker, fake_state);
+		  struct rexp_node * popper
+		    = rx_mk_r_side_effect (&rxb->rx,
+					   (rx_side_effect)re_se_poppos);
+		  struct rexp_node * star
+		    = rx_mk_r_2phase_star (&rxb->rx, inner_exp, phase2);
+		  struct rexp_node * a
+		    = rx_mk_r_concat (&rxb->rx, pusher, star);
+		  struct rexp_node * whole_thing
+		    = rx_mk_r_concat (&rxb->rx, a, popper);
+		  if (!(pusher && star && pushback && lit_t && fake_state
+			&& lit_t && phase2 && checker && popper
+			&& a && whole_thing))
+		    return REG_ESPACE;
+		  RX_bitset_enjoin (cs, 't');
+		  *last_expression = whole_thing;
+		}
+	      else
+		{
+		  struct rexp_node * star =
+		    (many_times_ok ? rx_mk_r_star : rx_mk_r_opt)
+		      (&rxb->rx, *last_expression);
+		  if (!star)
+		    return REG_ESPACE;
+		  *last_expression = star;
+		  need_sync = has_any_se (&rxb->rx, *last_expression);
+		}
+	      if (!zero_times_ok)
+		{
+		  struct rexp_node * concat
+		    = rx_mk_r_concat (&rxb->rx, inner_exp,
+				      rx_copy_rexp (&rxb->rx,
+						    *last_expression));
+		  if (!concat)
+		    return REG_ESPACE;
+		  *last_expression = concat;
+		}
+	      if (need_sync)
+		{
+		  int sync_se = paramc;
+		  params = (params
+			    ? ((struct re_se_params *)
+			       realloc (params,
+					sizeof (*params) * (1 + paramc)))
+			    : ((struct re_se_params *)
+			       malloc (sizeof (*params))));
+		  if (!params)
+		    return REG_ESPACE;
+		  ++paramc;
+		  params [sync_se].se = re_se_tv;
+		  side = (rx_side_effect)sync_se;
+		  goto add_side_effect;
+		}
+	    }
+	    /* The old regex.c used to optimize `.*\n'.  
+	     * Maybe rx should too?
+	     */
+	  }
+	  break;
+
+
+	case '.':
+	  {
+	    rx_Bitset cs = rx_cset (&rxb->rx);
+	    struct rexp_node * n = rx_mk_r_cset (&rxb->rx, cs);
+	    if (!(cs && n))
+	      return REG_ESPACE;
+
+	    rx_bitset_universe (rxb->rx.local_cset_size, cs);
+	    if (!(rxb->syntax & RE_DOT_NEWLINE))
+	      RX_bitset_remove (cs, '\n');
+	    if (!(rxb->syntax & RE_DOT_NOT_NULL))
+	      RX_bitset_remove (cs, 0);
+
+	    append = n;
+	    goto append_node;
+	    break;
+	  }
+
+
+        case '[':
+	  if (p == pend) return REG_EBRACK;
+          {
+            boolean had_char_class = false;
+	    rx_Bitset cs = rx_cset (&rxb->rx);
+	    struct rexp_node * node = rx_mk_r_cset (&rxb->rx, cs);
+	    int is_inverted = *p == '^';
+	    
+	    if (!(node && cs))
+	      return REG_ESPACE;
+	    
+	    /* This branch of the switch is normally exited with
+	     *`goto append_node'
+	     */
+	    append = node;
+	    
+            if (is_inverted)
+	      p++;
+	    
+            /* Remember the first position in the bracket expression.  */
+            p1 = p;
+	    
+            /* Read in characters and ranges, setting map bits.  */
+            for (;;)
+              {
+                if (p == pend) return REG_EBRACK;
+		
+                PATFETCH (c);
+		
+                /* \ might escape characters inside [...] and [^...].  */
+                if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+                  {
+                    if (p == pend) return REG_EESCAPE;
+		    
+                    PATFETCH (c1);
+		    {
+		      rx_Bitset it = inverse_translation (rxb, 
+							  validate_inv_tr,
+							  inverse_translate,
+							  translate,
+							  c1);
+		      rx_bitset_union (rxb->rx.local_cset_size, cs, it);
+		    }
+                    continue;
+                  }
+		
+                /* Could be the end of the bracket expression.  If it's
+                   not (i.e., when the bracket expression is `[]' so
+                   far), the ']' character bit gets set way below.  */
+                if (c == ']' && p != p1 + 1)
+                  goto finalize_class_and_append;
+		
+                /* Look ahead to see if it's a range when the last thing
+                   was a character class.  */
+                if (had_char_class && c == '-' && *p != ']')
+                  return REG_ERANGE;
+		
+                /* Look ahead to see if it's a range when the last thing
+                   was a character: if this is a hyphen not at the
+                   beginning or the end of a list, then it's the range
+                   operator.  */
+                if (c == '-' 
+                    && !(p - 2 >= pattern && p[-2] == '[') 
+                    && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+                    && *p != ']')
+                  {
+                    reg_errcode_t ret
+                      = compile_range (rxb, cs, &p, pend, translate, syntax,
+				       inverse_translate, validate_inv_tr);
+                    if (ret != REG_NOERROR) return ret;
+                  }
+		
+                else if (p[0] == '-' && p[1] != ']')
+                  { /* This handles ranges made up of characters only.  */
+                    reg_errcode_t ret;
+		    
+		    /* Move past the `-'.  */
+                    PATFETCH (c1);
+                    
+                    ret = compile_range (rxb, cs, &p, pend, translate, syntax,
+					 inverse_translate, validate_inv_tr);
+                    if (ret != REG_NOERROR) return ret;
+                  }
+		
+                /* See if we're at the beginning of a possible character
+                   class.  */
+		
+		else if ((syntax & RE_CHAR_CLASSES)
+			 && (c == '[') && (*p == ':'))
+                  {
+                    char str[CHAR_CLASS_MAX_LENGTH + 1];
+		    
+                    PATFETCH (c);
+                    c1 = 0;
+		    
+                    /* If pattern is `[[:'.  */
+                    if (p == pend) return REG_EBRACK;
+		    
+                    for (;;)
+                      {
+                        PATFETCH (c);
+                        if (c == ':' || c == ']' || p == pend
+                            || c1 == CHAR_CLASS_MAX_LENGTH)
+			  break;
+                        str[c1++] = c;
+                      }
+                    str[c1] = '\0';
+		    
+                    /* If isn't a word bracketed by `[:' and:`]':
+                       undo the ending character, the letters, and leave 
+                       the leading `:' and `[' (but set bits for them).  */
+                    if (c == ':' && *p == ']')
+                      {
+                        int ch;
+                        boolean is_alnum = !strcmp (str, "alnum");
+                        boolean is_alpha = !strcmp (str, "alpha");
+                        boolean is_blank = !strcmp (str, "blank");
+                        boolean is_cntrl = !strcmp (str, "cntrl");
+                        boolean is_digit = !strcmp (str, "digit");
+                        boolean is_graph = !strcmp (str, "graph");
+                        boolean is_lower = !strcmp (str, "lower");
+                        boolean is_print = !strcmp (str, "print");
+                        boolean is_punct = !strcmp (str, "punct");
+                        boolean is_space = !strcmp (str, "space");
+                        boolean is_upper = !strcmp (str, "upper");
+                        boolean is_xdigit = !strcmp (str, "xdigit");
+                        
+                        if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
+			
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);					
+			
+                        if (p == pend) return REG_EBRACK;
+			
+                        for (ch = 0; ch < 1 << CHARBITS; ch++)
+                          {
+                            if (   (is_alnum  && isalnum (ch))
+                                || (is_alpha  && isalpha (ch))
+                                || (is_blank  && isblank (ch))
+                                || (is_cntrl  && iscntrl (ch))
+                                || (is_digit  && isdigit (ch))
+                                || (is_graph  && isgraph (ch))
+                                || (is_lower  && islower (ch))
+                                || (is_print  && isprint (ch))
+                                || (is_punct  && ispunct (ch))
+                                || (is_space  && isspace (ch))
+                                || (is_upper  && isupper (ch))
+                                || (is_xdigit && isxdigit (ch)))
+			      {
+				rx_Bitset it =
+				  inverse_translation (rxb, 
+						       validate_inv_tr,
+						       inverse_translate,
+						       translate,
+						       ch);
+				rx_bitset_union (rxb->rx.local_cset_size,
+						 cs, it);
+			      }
+                          }
+                        had_char_class = true;
+                      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)    
+                          PATUNFETCH;
+			{
+			  rx_Bitset it =
+			    inverse_translation (rxb, 
+						 validate_inv_tr,
+						 inverse_translate,
+						 translate,
+						 '[');
+			  rx_bitset_union (rxb->rx.local_cset_size,
+					   cs, it);
+			}
+			{
+			  rx_Bitset it =
+			    inverse_translation (rxb, 
+						 validate_inv_tr,
+						 inverse_translate,
+						 translate,
+						 ':');
+			  rx_bitset_union (rxb->rx.local_cset_size,
+					   cs, it);
+			}
+                        had_char_class = false;
+                      }
+                  }
+                else
+                  {
+                    had_char_class = false;
+		    {
+		      rx_Bitset it = inverse_translation (rxb, 
+							  validate_inv_tr,
+							  inverse_translate,
+							  translate,
+							  c);
+		      rx_bitset_union (rxb->rx.local_cset_size, cs, it);
+		    }
+                  }
+              }
+
+	  finalize_class_and_append:
+	    if (is_inverted)
+	      {
+		rx_bitset_complement (rxb->rx.local_cset_size, cs);
+		if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+		  RX_bitset_remove (cs, '\n');
+	      }
+	    goto append_node;
+          }
+          break;
+
+
+	case '(':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_open;
+          else
+            goto normal_char;
+
+
+        case ')':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_close;
+          else
+            goto normal_char;
+
+
+        case '\n':
+          if (syntax & RE_NEWLINE_ALT)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+	case '|':
+          if (syntax & RE_NO_BK_VBAR)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+        case '{':
+	  if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+	    goto handle_interval;
+	  else
+	    goto normal_char;
+
+
+        case '\\':
+          if (p == pend) return REG_EESCAPE;
+
+          /* Do not translate the character after the \, so that we can
+             distinguish, e.g., \B from \b, even if we normally would
+             translate, e.g., B to b.  */
+          PATFETCH_RAW (c);
+
+          switch (c)
+            {
+            case '(':
+              if (syntax & RE_NO_BK_PARENS)
+                goto normal_backslash;
+
+            handle_open:
+              rxb->re_nsub++;
+              regnum++;
+              if (COMPILE_STACK_FULL)
+                { 
+                  ((compile_stack.stack) =
+		   (compile_stack_elt_t *) realloc (compile_stack.stack, ( compile_stack.size << 1) * sizeof (
+													      compile_stack_elt_t)));
+                  if (compile_stack.stack == 0) return REG_ESPACE;
+
+                  compile_stack.size <<= 1;
+                }
+
+	      if (*last_expression)
+		{
+		  struct rexp_node * concat
+		    = rx_mk_r_concat (&rxb->rx, *last_expression, 0);
+		  if (!concat)
+		    return REG_ESPACE;
+		  *last_expression = concat;
+		  last_expression = &concat->params.pair.right;
+		}
+
+              /*
+	       * These are the values to restore when we hit end of this
+               * group.  
+	       */
+	      COMPILE_STACK_TOP.top_expression = top_expression;
+	      COMPILE_STACK_TOP.last_expression = last_expression;
+              COMPILE_STACK_TOP.regnum = regnum;
+	      
+              compile_stack.avail++;
+	      
+	      top_expression = last_expression;
+	      break;
+
+
+            case ')':
+              if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+            handle_close:
+              /* See similar code for backslashed left paren above.  */
+              if (COMPILE_STACK_EMPTY)
+                if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+                  goto normal_char;
+                else
+                  return REG_ERPAREN;
+
+              /* Since we just checked for an empty stack above, this
+                 ``can't happen''.  */
+
+              {
+                /* We don't just want to restore into `regnum', because
+                   later groups should continue to be numbered higher,
+                   as in `(ab)c(de)' -- the second group is #2.  */
+                regnum_t this_group_regnum;
+		struct rexp_node ** inner = top_expression;
+
+                compile_stack.avail--;
+		top_expression = COMPILE_STACK_TOP.top_expression;
+		last_expression = COMPILE_STACK_TOP.last_expression;
+                this_group_regnum = COMPILE_STACK_TOP.regnum;
+		{
+		  int left_se = paramc;
+		  int right_se = paramc + 1;
+
+		  params = (params
+			    ? ((struct re_se_params *)
+			       realloc (params,
+					(paramc + 2) * sizeof (params[0])))
+			    : ((struct re_se_params *)
+			       malloc (2 * sizeof (params[0]))));
+		  if (!params)
+		    return REG_ESPACE;
+		  paramc += 2;
+
+		  params[left_se].se = re_se_lparen;
+		  params[left_se].op1 = this_group_regnum;
+		  params[right_se].se = re_se_rparen;
+		  params[right_se].op1 = this_group_regnum;
+		  {
+		    struct rexp_node * left
+		      = rx_mk_r_side_effect (&rxb->rx,
+					     (rx_side_effect)left_se);
+		    struct rexp_node * right
+		      = rx_mk_r_side_effect (&rxb->rx,
+					     (rx_side_effect)right_se);
+		    struct rexp_node * c1
+		      = (*inner
+			 ? rx_mk_r_concat (&rxb->rx, left, *inner) : left);
+		    struct rexp_node * c2
+		      = rx_mk_r_concat (&rxb->rx, c1, right);
+		    if (!(left && right && c1 && c2))
+		      return REG_ESPACE;
+		    *inner = c2;
+		  }
+		}
+		break;
+	      }
+
+            case '|':					/* `\|'.  */
+              if ((syntax & RE_LIMITED_OPS) || (syntax & RE_NO_BK_VBAR))
+                goto normal_backslash;
+            handle_alt:
+              if (syntax & RE_LIMITED_OPS)
+                goto normal_char;
+
+	      {
+		struct rexp_node * alt
+		  = rx_mk_r_alternate (&rxb->rx, *top_expression, 0);
+		if (!alt)
+		  return REG_ESPACE;
+		*top_expression = alt;
+		last_expression = &alt->params.pair.right;
+		{
+		  int sync_se = paramc;
+
+		  params = (params
+			    ? ((struct re_se_params *)
+			       realloc (params,
+					(paramc + 1) * sizeof (params[0])))
+			    : ((struct re_se_params *)
+			       malloc (sizeof (params[0]))));
+		  if (!params)
+		    return REG_ESPACE;
+		  ++paramc;
+
+		  params[sync_se].se = re_se_tv;
+		  {
+		    struct rexp_node * sync
+		      = rx_mk_r_side_effect (&rxb->rx,
+					     (rx_side_effect)sync_se);
+		    struct rexp_node * conc
+		      = rx_mk_r_concat (&rxb->rx, sync, 0);
+
+		    if (!sync || !conc)
+		      return REG_ESPACE;
+
+		    *last_expression = conc;
+		    last_expression = &conc->params.pair.right;
+		  }
+		}
+	      }
+              break;
+
+
+            case '{': 
+              /* If \{ is a literal.  */
+              if (!(syntax & RE_INTERVALS)
+                     /* If we're at `\{' and it's not the open-interval 
+                        operator.  */
+                  || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+                  || (p - 2 == pattern  &&  p == pend))
+                goto normal_backslash;
+
+            handle_interval:
+              {
+                /* If got here, then the syntax allows intervals.  */
+
+                /* At least (most) this many matches must be made.  */
+                int lower_bound = -1, upper_bound = -1;
+
+                beg_interval = p - 1;
+
+                if (p == pend)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else
+                      return REG_EBRACE;
+                  }
+
+                GET_UNSIGNED_NUMBER (lower_bound);
+
+                if (c == ',')
+                  {
+                    GET_UNSIGNED_NUMBER (upper_bound);
+                    if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+                  }
+                else
+                  /* Interval such as `{1}' => match exactly once. */
+                  upper_bound = lower_bound;
+
+                if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+                    || lower_bound > upper_bound)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else 
+                      return REG_BADBR;
+                  }
+
+                if (!(syntax & RE_NO_BK_BRACES)) 
+                  {
+                    if (c != '\\') return REG_EBRACE;
+                    PATFETCH (c);
+                  }
+
+                if (c != '}')
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else 
+                      return REG_BADBR;
+                  }
+
+                /* We just parsed a valid interval.  */
+
+                /* If it's invalid to have no preceding re.  */
+                if (pointless_if_repeated (*last_expression, params))
+                  {
+                    if (syntax & RE_CONTEXT_INVALID_OPS)
+                      return REG_BADRPT;
+                    else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+                      goto unfetch_interval;
+		    /* was: else laststart = b; */
+                  }
+
+                /* If the upper bound is zero, don't want to iterate
+                 * at all.
+		 */
+                 if (upper_bound == 0)
+		   {
+		     if (*last_expression)
+		       {
+			 rx_free_rexp (&rxb->rx, *last_expression);
+			 *last_expression = 0;
+		       }
+		   }
+		else
+		  /* Otherwise, we have a nontrivial interval. */
+		  {
+		    int iter_se = paramc;
+		    int end_se = paramc + 1;
+		    params = (params
+			      ? ((struct re_se_params *)
+				 realloc (params,
+					  sizeof (*params) * (2 + paramc)))
+			      : ((struct re_se_params *)
+				 malloc (2 * sizeof (*params))));
+		    if (!params)
+		      return REG_ESPACE;
+		    paramc += 2;
+		    params [iter_se].se = re_se_iter;
+		    params [iter_se].op1 = lower_bound;
+		    params[iter_se].op2 = upper_bound;
+
+		    params[end_se].se = re_se_end_iter;
+		    params[end_se].op1 = lower_bound;
+		    params[end_se].op2 = upper_bound;
+		    {
+		      struct rexp_node * push0
+			= rx_mk_r_side_effect (&rxb->rx,
+					       (rx_side_effect)re_se_push0);
+		      struct rexp_node * start_one_iter
+			= rx_mk_r_side_effect (&rxb->rx,
+					       (rx_side_effect)iter_se);
+		      struct rexp_node * phase1
+			= rx_mk_r_concat (&rxb->rx, start_one_iter,
+					  *last_expression);
+		      struct rexp_node * pushback
+			= rx_mk_r_side_effect (&rxb->rx,
+					       (rx_side_effect)re_se_pushback);
+		      rx_Bitset cs = rx_cset (&rxb->rx);
+		      struct rexp_node * lit_t
+			= rx_mk_r_cset (&rxb->rx, cs);
+		      struct rexp_node * phase2
+			= rx_mk_r_concat (&rxb->rx, pushback, lit_t);
+		      struct rexp_node * loop
+			= rx_mk_r_2phase_star (&rxb->rx, phase1, phase2);
+		      struct rexp_node * push_n_loop
+			= rx_mk_r_concat (&rxb->rx, push0, loop);
+		      struct rexp_node * final_test
+			= rx_mk_r_side_effect (&rxb->rx,
+					       (rx_side_effect)end_se);
+		      struct rexp_node * full_exp
+			= rx_mk_r_concat (&rxb->rx, push_n_loop, final_test);
+
+		      if (!(push0 && start_one_iter && phase1
+			    && pushback && lit_t && phase2
+			    && loop && push_n_loop && final_test && full_exp))
+			return REG_ESPACE;
+
+		      RX_bitset_enjoin(cs, 't');
+
+		      *last_expression = full_exp;
+		    }
+		  }
+                beg_interval = 0;
+              }
+              break;
+
+            unfetch_interval:
+              /* If an invalid interval, match the characters as literals.  */
+               p = beg_interval;
+               beg_interval = 0;
+
+               /* normal_char and normal_backslash need `c'.  */
+               PATFETCH (c);	
+
+               if (!(syntax & RE_NO_BK_BRACES))
+                 {
+                   if (p > pattern  &&  p[-1] == '\\')
+                     goto normal_backslash;
+                 }
+               goto normal_char;
+
+#ifdef emacs
+            /* There is no way to specify the before_dot and after_dot
+               operators.  rms says this is ok.  --karl  */
+            case '=':
+	      side = (rx_side_effect)rx_se_at_dot;
+	      goto add_side_effect;
+              break;
+
+            case 's':
+	    case 'S':
+	      {
+		rx_Bitset cs = rx_cset (&rxb->rx);
+		struct rexp_node * set = rx_mk_r_cset (&rxb->rx, cs);
+		if (!(cs && set))
+		  return REG_ESPACE;
+		if (c == 'S')
+		  rx_bitset_universe (rxb->rx.local_cset_size, cs);
+
+		PATFETCH (c);
+		{
+		  int x;
+		  enum syntaxcode code = syntax_spec_code [c];
+		  for (x = 0; x < 256; ++x)
+		    {
+		      
+		      if (SYNTAX (x) == code)
+			{
+			  rx_Bitset it =
+			    inverse_translation (rxb, validate_inv_tr,
+						 inverse_translate,
+						 translate, x);
+			  rx_bitset_xor (rxb->rx.local_cset_size, cs, it);
+			}
+		    }
+		}
+		append = set;
+		goto append_node;
+	      }
+              break;
+#endif /* emacs */
+
+
+            case 'w':
+            case 'W':
+	      {
+		rx_Bitset cs = rx_cset (&rxb->rx);
+		struct rexp_node * n = (cs ? rx_mk_r_cset (&rxb->rx, cs) : 0);
+		if (!(cs && n))
+		  return REG_ESPACE;
+		if (c == 'W')
+		  rx_bitset_universe (rxb->rx.local_cset_size ,cs);
+		{
+		  int x;
+		  for (x = rxb->rx.local_cset_size - 1; x > 0; --x)
+		    if (SYNTAX(x) & Sword)
+		      RX_bitset_toggle (cs, x);
+		}
+		append = n;
+		goto append_node;
+	      }
+              break;
+
+/* With a little extra work, some of these side effects could be optimized
+ * away (basicly by looking at what we already know about the surrounding
+ * chars).  
+ */
+            case '<':
+	      side = (rx_side_effect)re_se_wordbeg;
+	      goto add_side_effect;
+              break;
+
+            case '>':
+              side = (rx_side_effect)re_se_wordend;
+	      goto add_side_effect;
+              break;
+
+            case 'b':
+              side = (rx_side_effect)re_se_wordbound;
+	      goto add_side_effect;
+              break;
+
+            case 'B':
+              side = (rx_side_effect)re_se_notwordbound;
+	      goto add_side_effect;
+              break;
+
+            case '`':
+	      side = (rx_side_effect)re_se_begbuf;
+	      goto add_side_effect;
+	      break;
+	      
+            case '\'':
+	      side = (rx_side_effect)re_se_endbuf;
+	      goto add_side_effect;
+              break;
+
+	    add_side_effect:
+	      {
+		struct rexp_node * se
+		  = rx_mk_r_side_effect (&rxb->rx, side);
+		if (!se)
+		  return REG_ESPACE;
+		append = se;
+		goto append_node;
+	      }
+	      break;
+
+            case '1': case '2': case '3': case '4': case '5':
+            case '6': case '7': case '8': case '9':
+              if (syntax & RE_NO_BK_REFS)
+                goto normal_char;
+
+              c1 = c - '0';
+
+              if (c1 > regnum)
+                return REG_ESUBREG;
+
+              /* Can't back reference to a subexpression if inside of it.  */
+              if (group_in_compile_stack (compile_stack, c1))
+		return REG_ESUBREG;
+
+	      {
+		int backref_se = paramc;
+		params = (params
+			  ? ((struct re_se_params *)
+			     realloc (params,
+				      sizeof (*params) * (1 + paramc)))
+			  : ((struct re_se_params *)
+			     malloc (sizeof (*params))));
+		if (!params)
+		  return REG_ESPACE;
+		++paramc;
+		params[backref_se].se = re_se_backref;
+		params[backref_se].op1 = c1;
+		side = (rx_side_effect)backref_se;
+		goto add_side_effect;
+	      }
+              break;
+
+            case '+':
+            case '?':
+              if (syntax & RE_BK_PLUS_QM)
+                goto handle_plus;
+              else
+                goto normal_backslash;
+
+            default:
+            normal_backslash:
+              /* You might think it would be useful for \ to mean
+                 not to translate; but if we don't translate it
+                 it will never match anything.  */
+              c = TRANSLATE (c);
+              goto normal_char;
+            }
+          break;
+
+
+	default:
+        /* Expects the character in `c'.  */
+	normal_char:
+	    {
+	      rx_Bitset cs = rx_cset(&rxb->rx);
+	      struct rexp_node * match = rx_mk_r_cset (&rxb->rx, cs);
+	      rx_Bitset it;
+	      if (!(cs && match))
+		return REG_ESPACE;
+	      it = inverse_translation (rxb, validate_inv_tr,
+					inverse_translate, translate, c);
+	      rx_bitset_union (CHAR_SET_SIZE, cs, it);
+	      append = match;
+
+	    append_node:
+	      /* This genericly appends the rexp APPEND to *LAST_EXPRESSION
+	       * and then parses the next character normally.
+	       */
+	      if (*last_expression)
+		{
+		  struct rexp_node * concat
+		    = rx_mk_r_concat (&rxb->rx, *last_expression, append);
+		  if (!concat)
+		    return REG_ESPACE;
+		  *last_expression = concat;
+		  last_expression = &concat->params.pair.right;
+		}
+	      else
+		*last_expression = append;
+	    }
+	} /* switch (c) */
+    } /* while p != pend */
+
+  
+  {
+    int win_se = paramc;
+    params = (params
+	      ? ((struct re_se_params *)
+		 realloc (params,
+			  sizeof (*params) * (1 + paramc)))
+	      : ((struct re_se_params *)
+		 malloc (sizeof (*params))));
+    if (!params)
+      return REG_ESPACE;
+    ++paramc;
+    params[win_se].se = re_se_win;
+    {
+      struct rexp_node * se
+	= rx_mk_r_side_effect (&rxb->rx, (rx_side_effect)win_se);
+      struct rexp_node * concat
+	= rx_mk_r_concat (&rxb->rx, rexp, se);
+      if (!(se && concat))
+	return REG_ESPACE;
+      rexp = concat;
+    }
+  }
+
+
+  /* Through the pattern now.  */
+
+  if (!COMPILE_STACK_EMPTY) 
+    return REG_EPAREN;
+
+      free (compile_stack.stack);
+
+  orig_rexp = rexp;
+#ifdef RX_DEBUG
+  if (rx_debug_compile)
+    {
+      dbug_rxb = rxb;
+      fputs ("\n\nCompiling ", stdout);
+      fwrite (pattern, 1, size, stdout);
+      fputs (":\n", stdout);
+      rxb->se_params = params;
+      print_rexp (&rxb->rx, orig_rexp, 2, re_seprint, stdout);
+    }
+#endif
+  {
+    rx_Bitset cs = rx_cset(&rxb->rx);
+    rx_Bitset cs2 = rx_cset(&rxb->rx);
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+    char * se_map = (char *) _alloca (paramc);
+#else
+    char * se_map = (char *) alloca (paramc);
+#endif
+    struct rexp_node * new_rexp = 0;
+
+
+    bzero (se_map, paramc);
+    find_backrefs (se_map, rexp, params);
+    fewer_side_effects =
+      remove_unecessary_side_effects (&rxb->rx, se_map,
+				      rx_copy_rexp (&rxb->rx, rexp), params);
+
+    speed_up_alt (&rxb->rx, rexp, 0);
+    speed_up_alt (&rxb->rx, fewer_side_effects, 1);
+
+    {
+      char * syntax_parens = rxb->syntax_parens;
+      if (syntax_parens == (char *)0x1)
+	rexp = remove_unecessary_side_effects
+	  (&rxb->rx, se_map, rexp, params);
+      else if (syntax_parens)
+	{
+	  int x;
+	  for (x = 0; x < paramc; ++x)
+	    if ((   (params[x].se == re_se_lparen)
+		 || (params[x].se == re_se_rparen))
+		&& (!syntax_parens [params[x].op1]))
+	      se_map [x] = 1;
+	  rexp = remove_unecessary_side_effects
+	    (&rxb->rx, se_map, rexp, params);
+	}
+    }
+
+    /* At least one more optimization would be nice to have here but i ran out 
+     * of time.  The idea would be to delay side effects.  
+     * For examle, `(abc)' is the same thing as `abc()' except that the
+     * left paren is offset by 3 (which we know at compile time).
+     * (In this comment, write that second pattern `abc(:3:)' 
+     * where `(:3:' is a syntactic unit.)
+     *
+     * Trickier:  `(abc|defg)'  is the same as `(abc(:3:|defg(:4:))'
+     * (The paren nesting may be hard to follow -- that's an alternation
+     *	of `abc(:3:' and `defg(:4:' inside (purely syntactic) parens
+     *  followed by the closing paren from the original expression.)
+     *
+     * Neither the expression tree representation nor the the nfa make
+     * this very easy to write. :(
+     */
+
+  /* What we compile is different than what the parser returns.
+   * Suppose the parser returns expression R.
+   * Let R' be R with unnecessary register assignments removed 
+   * (see REMOVE_UNECESSARY_SIDE_EFFECTS, above).
+   *
+   * What we will compile is the expression:
+   *
+   *    m{try}R{win}\|s{try}R'{win}
+   *
+   * {try} and {win} denote side effect epsilons (see EXPLORE_FUTURE).
+   * 
+   * When trying a match, we insert an `m' at the beginning of the 
+   * string if the user wants registers to be filled, `s' if not.
+   */
+    new_rexp =
+      rx_mk_r_alternate
+	(&rxb->rx,
+	 rx_mk_r_concat (&rxb->rx, rx_mk_r_cset (&rxb->rx, cs2), rexp),
+	 rx_mk_r_concat (&rxb->rx,
+			 rx_mk_r_cset (&rxb->rx, cs), fewer_side_effects));
+
+    if (!(new_rexp && cs && cs2))
+      return REG_ESPACE;
+    RX_bitset_enjoin (cs2, '\0'); /* prefixed to the rexp used for matching. */
+    RX_bitset_enjoin (cs, '\1'); /* prefixed to the rexp used for searching. */
+    rexp = new_rexp;
+  }
+
+#ifdef RX_DEBUG
+  if (rx_debug_compile)
+    {
+      fputs ("\n...which is compiled as:\n", stdout);
+      print_rexp (&rxb->rx, rexp, 2, re_seprint, stdout);
+    }
+#endif
+  {
+    struct rx_nfa_state *start = 0;
+    struct rx_nfa_state *end = 0;
+
+    if (!rx_build_nfa (&rxb->rx, rexp, &start, &end))
+      return REG_ESPACE;	/*  */
+    else
+      {
+	void * mem = (void *)rxb->buffer;
+	unsigned long size = rxb->allocated;
+	int start_id;
+	char * perm_mem;
+	int iterator_size = paramc * sizeof (params[0]);
+
+	end->is_final = 1;
+	start->is_start = 1;
+	rx_name_nfa_states (&rxb->rx);
+	start_id = start->id;
+#ifdef RX_DEBUG
+	if (rx_debug_compile)
+	  {
+	    fputs ("...giving the NFA: \n", stdout);
+	    dbug_rxb = rxb;
+	    print_nfa (&rxb->rx, rxb->rx.nfa_states, re_seprint, stdout);
+	  }
+#endif
+	if (!rx_eclose_nfa (&rxb->rx))
+	  return REG_ESPACE;
+	else
+	  {
+	    rx_delete_epsilon_transitions (&rxb->rx);
+	    
+	    /* For compatability reasons, we need to shove the
+	     * compiled nfa into one chunk of malloced memory.
+	     */
+	    rxb->rx.reserved = (   sizeof (params[0]) * paramc
+				+  rx_sizeof_bitset (rxb->rx.local_cset_size));
+#ifdef RX_DEBUG
+	    if (rx_debug_compile)
+	      {
+		dbug_rxb = rxb;
+		fputs ("...which cooks down (uncompactified) to: \n", stdout);
+		print_nfa (&rxb->rx, rxb->rx.nfa_states, re_seprint, stdout);
+	      }
+#endif
+	    if (!rx_compactify_nfa (&rxb->rx, &mem, &size))
+	      return REG_ESPACE;
+	    rxb->buffer = mem;
+	    rxb->allocated = size;
+	    rxb->rx.buffer = mem;
+	    rxb->rx.allocated = size;
+	    perm_mem = ((char *)rxb->rx.buffer
+			+ rxb->rx.allocated - rxb->rx.reserved);
+	    rxb->se_params = ((struct re_se_params *)perm_mem);
+	    bcopy (params, rxb->se_params, iterator_size);
+	    perm_mem += iterator_size;
+	    rxb->fastset = (rx_Bitset) perm_mem;
+	    rxb->start = rx_id_to_nfa_state (&rxb->rx, start_id);
+	  }
+	rx_bitset_null (rxb->rx.local_cset_size, rxb->fastset);
+	rxb->can_match_empty = compute_fastset (rxb, orig_rexp);
+	rxb->match_regs_on_stack =
+	  registers_on_stack (rxb, orig_rexp, 0, params); 
+	rxb->search_regs_on_stack =
+	  registers_on_stack (rxb, fewer_side_effects, 0, params);
+	if (rxb->can_match_empty)
+	  rx_bitset_universe (rxb->rx.local_cset_size, rxb->fastset);
+	rxb->is_anchored = is_anchored (orig_rexp, (rx_side_effect) re_se_hat);
+	rxb->begbuf_only = is_anchored (orig_rexp,
+					(rx_side_effect) re_se_begbuf);
+      }
+    rx_free_rexp (&rxb->rx, rexp);
+    if (params)
+      free (params);
+#ifdef RX_DEBUG
+    if (rx_debug_compile)
+      {
+	dbug_rxb = rxb;
+	fputs ("...which cooks down to: \n", stdout);
+	print_nfa (&rxb->rx, rxb->rx.nfa_states, re_seprint, stdout);
+      }
+#endif
+  }
+  return REG_NOERROR;
+}
+
+
+
+
+/* This table gives an error message for each of the error codes listed
+   in regex.h.  Obviously the order here has to be same as there.  */
+
+__const__ char * rx_error_msg[] =
+{ 0,						/* REG_NOERROR */
+    "No match",					/* REG_NOMATCH */
+    "Invalid regular expression",		/* REG_BADPAT */
+    "Invalid collation character",		/* REG_ECOLLATE */
+    "Invalid character class name",		/* REG_ECTYPE */
+    "Trailing backslash",			/* REG_EESCAPE */
+    "Invalid back reference",			/* REG_ESUBREG */
+    "Unmatched [ or [^",			/* REG_EBRACK */
+    "Unmatched ( or \\(",			/* REG_EPAREN */
+    "Unmatched \\{",				/* REG_EBRACE */
+    "Invalid content of \\{\\}",		/* REG_BADBR */
+    "Invalid range end",			/* REG_ERANGE */
+    "Memory exhausted",				/* REG_ESPACE */
+    "Invalid preceding regular expression",	/* REG_BADRPT */
+    "Premature end of regular expression",	/* REG_EEND */
+    "Regular expression too big",		/* REG_ESIZE */
+    "Unmatched ) or \\)",			/* REG_ERPAREN */
+};
+
+
+
+
+
+char rx_slowmap [256] =
+{
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+#ifdef __STDC__
+RX_DECL void
+rx_blow_up_fastmap (struct re_pattern_buffer * rxb)
+#else
+RX_DECL void
+rx_blow_up_fastmap (rxb)
+     struct re_pattern_buffer * rxb;
+#endif
+{
+  int x;
+  for (x = 0; x < 256; ++x)	/* &&&& 3.6 % */
+    rxb->fastmap [x] = !!RX_bitset_member (rxb->fastset, x);
+  rxb->fastmap_accurate = 1;
+}
+
+
+
+
+
+#if !defined(REGEX_MALLOC) && !defined(__GNUC__)
+#define RE_SEARCH_2_FN	inner_re_search_2
+#define RE_S2_QUAL static
+#else
+#define RE_SEARCH_2_FN	re_search_2
+#define RE_S2_QUAL 
+#endif
+
+struct re_search_2_closure
+{
+  __const__ char * string1;
+  int size1;
+  __const__ char * string2;
+  int size2;
+};
+
+
+static __inline__ enum rx_get_burst_return
+re_search_2_get_burst (pos, vclosure, stop)
+     struct rx_string_position * pos;
+     void * vclosure;
+     int stop;
+{
+  struct re_search_2_closure * closure;
+  closure = (struct re_search_2_closure *)vclosure;
+  if (!closure->string2)
+    {
+      int inset;
+
+      inset = pos->pos - pos->string;
+      if ((inset < -1) || (inset > closure->size1))
+	return rx_get_burst_no_more;
+      else
+	{
+	  pos->pos = (__const__ unsigned char *) closure->string1 + inset;
+	  pos->string = (__const__ unsigned char *) closure->string1;
+	  pos->size = closure->size1;
+	  pos->end = ((__const__ unsigned char *)
+		      MIN(closure->string1 + closure->size1,
+			  closure->string1 + stop));
+	  pos->offset = 0;
+	  return ((pos->pos < pos->end)
+		  ? rx_get_burst_ok
+		  :  rx_get_burst_no_more);
+	}
+    }
+  else if (!closure->string1)
+    {
+      int inset;
+
+      inset = pos->pos - pos->string;
+      pos->pos = (__const__ unsigned char *) closure->string2 + inset;
+      pos->string = (__const__ unsigned char *) closure->string2;
+      pos->size = closure->size2;
+      pos->end = ((__const__ unsigned char *)
+		  MIN(closure->string2 + closure->size2,
+		      closure->string2 + stop));
+      pos->offset = 0;
+      return ((pos->pos < pos->end)
+	      ? rx_get_burst_ok
+	      :  rx_get_burst_no_more);
+    }
+  else
+    {
+      int inset;
+
+      inset = pos->pos - pos->string + pos->offset;
+      if (inset < closure->size1)
+	{
+	  pos->pos = (__const__ unsigned char *) closure->string1 + inset;
+	  pos->string = (__const__ unsigned char *) closure->string1;
+	  pos->size = closure->size1;
+	  pos->end = ((__const__ unsigned char *)
+		      MIN(closure->string1 + closure->size1,
+			  closure->string1 + stop));
+	  pos->offset = 0;
+	  return rx_get_burst_ok;
+	}
+      else
+	{
+	  pos->pos = ((__const__ unsigned char *)
+		      closure->string2 + inset - closure->size1);
+	  pos->string = (__const__ unsigned char *) closure->string2;
+	  pos->size = closure->size2;
+	  pos->end = ((__const__ unsigned char *)
+		      MIN(closure->string2 + closure->size2,
+			  closure->string2 + stop - closure->size1));
+	  pos->offset = closure->size1;
+	  return ((pos->pos < pos->end)
+		  ? rx_get_burst_ok
+		  :  rx_get_burst_no_more);
+	}
+    }
+}
+
+
+static __inline__ enum rx_back_check_return
+re_search_2_back_check (pos, lparen, rparen, translate, vclosure, stop)
+     struct rx_string_position * pos;
+     int lparen;
+     int rparen;
+     unsigned char * translate;
+     void * vclosure;
+     int stop;
+{
+  struct rx_string_position there;
+  struct rx_string_position past;
+
+  there = *pos;
+  there.pos = there.string + lparen - there.offset;
+  re_search_2_get_burst (&there, vclosure, stop);
+
+  past = *pos;
+  past.pos = past.string + rparen - there.offset;
+  re_search_2_get_burst (&past, vclosure, stop);
+
+  ++pos->pos;
+  re_search_2_get_burst (pos, vclosure, stop);
+
+  while (   (there.pos != past.pos)
+	 && (pos->pos != pos->end))
+    if (TRANSLATE(*there.pos) != TRANSLATE(*pos->pos))
+      return rx_back_check_fail;
+    else
+      {
+	++there.pos;
+	++pos->pos;
+	if (there.pos == there.end)
+	  re_search_2_get_burst (&there, vclosure, stop);
+	if (pos->pos == pos->end)
+	  re_search_2_get_burst (pos, vclosure, stop);
+      }
+
+  if (there.pos != past.pos)
+    return rx_back_check_fail;
+  --pos->pos;
+  re_search_2_get_burst (pos, vclosure, stop);
+  return rx_back_check_pass;
+}
+
+static __inline__ int
+re_search_2_fetch_char (pos, offset, app_closure, stop)
+     struct rx_string_position * pos;
+     int offset;
+     void * app_closure;
+     int stop;
+{
+  struct re_search_2_closure * closure;
+  closure = (struct re_search_2_closure *)app_closure;
+  if (offset == 0)
+    {
+      if (pos->pos >= pos->string)
+	return *pos->pos;
+      else
+	{
+	  if (   (pos->string == (__const__ unsigned char *) closure->string2)
+	      && (closure->string1)
+	      && (closure->size1))
+	    return closure->string1[closure->size1 - 1];
+	  else
+	    return 0;		/* sure, why not. */
+	}
+    }
+  if (pos->pos == pos->end)
+    return *closure->string2;
+  else
+    return pos->pos[1];
+}
+     
+
+#ifdef __STDC__
+RE_S2_QUAL int
+RE_SEARCH_2_FN (struct re_pattern_buffer *rxb,
+		__const__ char * string1, int size1,
+		__const__ char * string2, int size2,
+		int startpos, int range,
+		struct re_registers *regs,
+		int stop)
+#else
+RE_S2_QUAL int
+RE_SEARCH_2_FN (rxb,
+		string1, size1, string2, size2, startpos, range, regs, stop)
+     struct re_pattern_buffer *rxb;
+     __const__ char * string1;
+     int size1;
+     __const__ char * string2;
+     int size2;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+     int stop;
+#endif
+{
+  int answer;
+  struct re_search_2_closure closure;
+  closure.string1 = string1;
+  closure.size1 = size1;
+  closure.string2 = string2;
+  closure.size2 = size2;
+  answer = rx_search (rxb, startpos, range, stop, size1 + size2,
+		      re_search_2_get_burst,
+		      re_search_2_back_check,
+		      re_search_2_fetch_char,
+		      (void *)&closure,
+		      regs,
+		      0,
+		      0);
+  switch (answer)
+    {
+    case rx_search_continuation:
+      abort ();
+    case rx_search_error:
+      return -2;
+    case rx_search_soft_fail:
+    case rx_search_fail:
+      return -1;
+    default:
+      return answer;
+    }
+}
+
+/* Export rx_search to callers outside this file.  */
+
+int
+re_rx_search (rxb, startpos, range, stop, total_size,
+	      get_burst, back_check, fetch_char,
+	      app_closure, regs, resume_state, save_state)
+     struct re_pattern_buffer * rxb;
+     int startpos;
+     int range;
+     int stop;
+     int total_size;
+     rx_get_burst_fn get_burst;
+     rx_back_check_fn back_check;
+     rx_fetch_char_fn fetch_char;
+     void * app_closure;
+     struct re_registers * regs;
+     struct rx_search_state * resume_state;
+     struct rx_search_state * save_state;
+{
+  return rx_search (rxb, startpos, range, stop, total_size,
+		    get_burst, back_check, fetch_char, app_closure,
+		    regs, resume_state, save_state);
+}
+
+#if !defined(REGEX_MALLOC) && !defined(__GNUC__)
+#ifdef __STDC__
+int
+re_search_2 (struct re_pattern_buffer *rxb,
+	     __const__ char * string1, int size1,
+	     __const__ char * string2, int size2,
+	     int startpos, int range,
+	     struct re_registers *regs,
+	     int stop)
+#else
+int
+re_search_2 (rxb, string1, size1, string2, size2, startpos, range, regs, stop)
+     struct re_pattern_buffer *rxb;
+     __const__ char * string1;
+     int size1;
+     __const__ char * string2;
+     int size2;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+     int stop;
+#endif
+{
+  int ret;
+  ret = inner_re_search_2 (rxb, string1, size1, string2, size2, startpos,
+			   range, regs, stop);
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+  _alloca (0);
+#else
+  alloca (0);
+#endif
+  return ret;
+}
+#endif
+
+
+/* Like re_search_2, above, but only one string is specified, and
+ * doesn't let you say where to stop matching.
+ */
+
+#ifdef __STDC__
+int
+re_search (struct re_pattern_buffer * rxb, __const__ char *string,
+	   int size, int startpos, int range,
+	   struct re_registers *regs)
+#else
+int
+re_search (rxb, string, size, startpos, range, regs)
+     struct re_pattern_buffer * rxb;
+     __const__ char * string;
+     int size;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+#endif
+{
+  return re_search_2 (rxb, 0, 0, string, size, startpos, range, regs, size);
+}
+
+#ifdef __STDC__
+int
+re_match_2 (struct re_pattern_buffer * rxb,
+	    __const__ char * string1, int size1,
+	    __const__ char * string2, int size2,
+	    int pos, struct re_registers *regs, int stop)
+#else
+int
+re_match_2 (rxb, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer * rxb;
+     __const__ char * string1;
+     int size1;
+     __const__ char * string2;
+     int size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+#endif
+{
+  struct re_registers some_regs;
+  regoff_t start;
+  regoff_t end;
+  int srch;
+  int save = rxb->regs_allocated;
+  struct re_registers * regs_to_pass = regs;
+
+  if (!regs)
+    {
+      some_regs.start = &start;
+      some_regs.end = &end;
+      some_regs.num_regs = 1;
+      regs_to_pass = &some_regs;
+      rxb->regs_allocated = REGS_FIXED;
+    }
+
+  srch = re_search_2 (rxb, string1, size1, string2, size2,
+		      pos, 1, regs_to_pass, stop);
+  if (regs_to_pass != regs)
+    rxb->regs_allocated = save;
+  if (srch < 0)
+    return srch;
+  return regs_to_pass->end[0] - regs_to_pass->start[0];
+}
+
+/* re_match is like re_match_2 except it takes only a single string.  */
+
+#ifdef __STDC__
+int
+re_match (struct re_pattern_buffer * rxb,
+	  __const__ char * string,
+	  int size, int pos,
+	  struct re_registers *regs)
+#else
+int
+re_match (rxb, string, size, pos, regs)
+     struct re_pattern_buffer * rxb;
+     __const__ char *string;
+     int size;
+     int pos;
+     struct re_registers *regs;
+#endif
+{
+  return re_match_2 (rxb, string, size, 0, 0, pos, regs, size);
+}
+
+
+
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
+   also be assigned to arbitrarily: each pattern buffer stores its own
+   syntax, so it can be changed between regex compilations.  */
+reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
+
+
+/* Specify the precise syntax of regexps for compilation.  This provides
+   for compatibility for various utilities which historically have
+   different, incompatible syntaxes.
+
+   The argument SYNTAX is a bit mask comprised of the various bits
+   defined in regex.h.  We return the old syntax.  */
+
+#ifdef __STDC__
+reg_syntax_t
+re_set_syntax (reg_syntax_t syntax)
+#else
+reg_syntax_t
+re_set_syntax (syntax)
+    reg_syntax_t syntax;
+#endif
+{
+  reg_syntax_t ret = re_syntax_options;
+
+  re_syntax_options = syntax;
+  return ret;
+}
+
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
+   this memory for recording register information.  STARTS and ENDS
+   must be allocated using the malloc library routine, and must each
+   be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+
+#ifdef __STDC__
+void
+re_set_registers (struct re_pattern_buffer *bufp,
+		  struct re_registers *regs,
+		  unsigned num_regs,
+		  regoff_t * starts, regoff_t * ends)
+#else
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+     struct re_pattern_buffer *bufp;
+     struct re_registers *regs;
+     unsigned num_regs;
+     regoff_t * starts;
+     regoff_t * ends;
+#endif
+{
+  if (num_regs)
+    {
+      bufp->regs_allocated = REGS_REALLOCATE;
+      regs->num_regs = num_regs;
+      regs->start = starts;
+      regs->end = ends;
+    }
+  else
+    {
+      bufp->regs_allocated = REGS_UNALLOCATED;
+      regs->num_regs = 0;
+      regs->start = regs->end = (regoff_t) 0;
+    }
+}
+
+
+
+
+
+#ifdef __STDC__
+static int 
+cplx_se_sublist_len (struct rx_se_list * list)
+#else
+static int 
+cplx_se_sublist_len (list)
+     struct rx_se_list * list;
+#endif
+{
+  int x = 0;
+  while (list)
+    {
+      if ((long)list->car >= 0)
+	++x;
+      list = list->cdr;
+    }
+  return x;
+}
+
+
+/* For rx->se_list_cmp */
+
+#ifdef __STDC__
+static int 
+posix_se_list_order (struct rx * rx,
+		     struct rx_se_list * a, struct rx_se_list * b)
+#else
+static int 
+posix_se_list_order (rx, a, b)
+     struct rx * rx;
+     struct rx_se_list * a;
+     struct rx_se_list * b;
+#endif
+{
+  int al = cplx_se_sublist_len (a);
+  int bl = cplx_se_sublist_len (b);
+
+  if (!al && !bl)
+    return ((a == b)
+	    ? 0
+	    : ((a < b) ? -1 : 1));
+  
+  else if (!al)
+    return -1;
+
+  else if (!bl)
+    return 1;
+
+  else
+    {
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+      rx_side_effect * av = ((rx_side_effect *)
+			     _alloca (sizeof (rx_side_effect) * (al + 1)));
+      rx_side_effect * bv = ((rx_side_effect *)
+			     _alloca (sizeof (rx_side_effect) * (bl + 1)));
+#else
+      rx_side_effect * av = ((rx_side_effect *)
+			     alloca (sizeof (rx_side_effect) * (al + 1)));
+      rx_side_effect * bv = ((rx_side_effect *)
+			     alloca (sizeof (rx_side_effect) * (bl + 1)));
+#endif
+      struct rx_se_list * ap = a;
+      struct rx_se_list * bp = b;
+      int ai, bi;
+      
+      for (ai = al - 1; ai >= 0; --ai)
+	{
+	  while ((long)ap->car < 0)
+	    ap = ap->cdr;
+	  av[ai] = ap->car;
+	  ap = ap->cdr;
+	}
+      av[al] = (rx_side_effect)-2;
+      for (bi = bl - 1; bi >= 0; --bi)
+	{
+	  while ((long)bp->car < 0)
+	    bp = bp->cdr;
+	  bv[bi] = bp->car;
+	  bp = bp->cdr;
+	}
+      bv[bl] = (rx_side_effect)-1;
+
+      {
+	int ret;
+	int x = 0;
+	while (av[x] == bv[x])
+	  ++x;
+ 	ret = (((unsigned *)(av[x]) < (unsigned *)(bv[x])) ? -1 : 1);
+	return ret;
+      }
+    }
+}
+
+
+
+
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+   compiles PATTERN (of length SIZE) and puts the result in RXB.
+   Returns 0 if the pattern was valid, otherwise an error string.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+   are set in RXB on entry.
+
+   We call rx_compile to do the actual compilation.  */
+
+#ifdef __STDC__
+__const__ char *
+re_compile_pattern (__const__ char *pattern,
+		    int length,
+		    struct re_pattern_buffer * rxb)
+#else
+__const__ char *
+re_compile_pattern (pattern, length, rxb)
+     __const__ char *pattern;
+     int length;
+     struct re_pattern_buffer * rxb;
+#endif
+{
+  reg_errcode_t ret;
+
+  /* GNU code is written to assume at least RE_NREGS registers will be set
+     (and at least one extra will be -1).  */
+  rxb->regs_allocated = REGS_UNALLOCATED;
+
+  /* And GNU code determines whether or not to get register information
+     by passing null for the REGS argument to re_match, etc., not by
+     setting no_sub.  */
+  rxb->no_sub = 0;
+
+  rxb->rx.local_cset_size = 256;
+
+  /* Match anchors at newline.  */
+  rxb->newline_anchor = 1;
+ 
+  rxb->re_nsub = 0;
+  rxb->start = 0;
+  rxb->se_params = 0;
+  rxb->rx.nodec = 0;
+  rxb->rx.epsnodec = 0;
+  rxb->rx.instruction_table = 0;
+  rxb->rx.nfa_states = 0;
+  rxb->rx.se_list_cmp = posix_se_list_order;
+  rxb->rx.start_set = 0;
+
+  ret = rx_compile (pattern, length, re_syntax_options, rxb);
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+  _alloca (0);
+#else
+  alloca (0);
+#endif
+  return rx_error_msg[(int) ret];
+}
+
+
+
+#ifdef __STDC__
+int
+re_compile_fastmap (struct re_pattern_buffer * rxb)
+#else
+int
+re_compile_fastmap (rxb)
+     struct re_pattern_buffer * rxb;
+#endif
+{
+  rx_blow_up_fastmap (rxb);
+  return 0;
+}
+
+
+
+
+
+/* Entry points compatible with 4.2 BSD regex library.  We don't define
+   them if this is an Emacs or POSIX compilation.  */
+
+#if (!defined (emacs) && !defined (_POSIX_SOURCE)) || defined(USE_BSD_REGEX)
+
+/* BSD has one and only one pattern buffer.  */
+static struct re_pattern_buffer rx_comp_buf;
+
+#ifdef __STDC__
+char *
+re_comp (__const__ char *s)
+#else
+char *
+re_comp (s)
+    __const__ char *s;
+#endif
+{
+  reg_errcode_t ret;
+
+  if (!s || (*s == '\0'))
+    {
+      if (!rx_comp_buf.buffer)
+	return "No previous regular expression";
+      return 0;
+    }
+
+  if (!rx_comp_buf.fastmap)
+    {
+      rx_comp_buf.fastmap = (char *) malloc (1 << CHARBITS);
+      if (!rx_comp_buf.fastmap)
+	return "Memory exhausted";
+    }
+
+  /* Since `rx_exec' always passes NULL for the `regs' argument, we
+     don't need to initialize the pattern buffer fields which affect it.  */
+
+  /* Match anchors at newlines.  */
+  rx_comp_buf.newline_anchor = 1;
+
+  rx_comp_buf.re_nsub = 0;
+  rx_comp_buf.start = 0;
+  rx_comp_buf.se_params = 0;
+  rx_comp_buf.rx.nodec = 0;
+  rx_comp_buf.rx.epsnodec = 0;
+  rx_comp_buf.rx.instruction_table = 0;
+  rx_comp_buf.rx.nfa_states = 0;
+  rx_comp_buf.rx.start = 0;
+  rx_comp_buf.rx.se_list_cmp = posix_se_list_order;
+  rx_comp_buf.rx.local_cset_size = 256;
+
+  ret = rx_compile (s, strlen (s), re_syntax_options, &rx_comp_buf);
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+  _alloca (0);
+#else
+  alloca (0);
+#endif
+
+  /* Yes, we're discarding `__const__' here.  */
+  return (char *) rx_error_msg[(int) ret];
+}
+
+
+#ifdef __STDC__
+int
+re_exec (__const__ char *s)
+#else
+int
+re_exec (s)
+    __const__ char *s;
+#endif
+{
+  __const__ int len = strlen (s);
+  return
+    0 <= re_search (&rx_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+#endif /* not emacs and not _POSIX_SOURCE */
+
+
+
+
+/* POSIX.2 functions.  Don't define these for Emacs.  */
+
+#if !defined(emacs)
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+   PREG is a regex_t *.  We do not expect any fields to be initialized,
+   since POSIX says we shouldn't.  Thus, we set
+
+     `buffer' to the compiled pattern;
+     `used' to the length of the compiled pattern;
+     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+       REG_EXTENDED bit in CFLAGS is set; otherwise, to
+       RE_SYNTAX_POSIX_BASIC;
+     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+     `fastmap' and `fastmap_accurate' to zero;
+     `re_nsub' to the number of subexpressions in PATTERN.
+
+   PATTERN is the address of the pattern string.
+
+   CFLAGS is a series of bits which affect compilation.
+
+     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+     use POSIX basic syntax.
+
+     If REG_NEWLINE is set, then . and [^...] don't match newline.
+     Also, regexec will try a match beginning after every newline.
+
+     If REG_ICASE is set, then we considers upper- and lowercase
+     versions of letters to be equivalent when matching.
+
+     If REG_NOSUB is set, then when PREG is passed to regexec, that
+     routine will report only success or failure, and nothing about the
+     registers.
+
+   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
+   the return codes and their meanings.)  */
+
+
+#ifdef __STDC__
+int
+regcomp (regex_t * preg, __const__ char * pattern, int cflags)
+#else
+int
+regcomp (preg, pattern, cflags)
+    regex_t * preg;
+    __const__ char * pattern;
+    int cflags;
+#endif
+{
+  reg_errcode_t ret;
+  unsigned syntax
+    = cflags & REG_EXTENDED ? RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+  /* regex_compile will allocate the space for the compiled pattern.  */
+  preg->buffer = 0;
+  preg->allocated = 0;
+  preg->fastmap = malloc (256);
+  if (!preg->fastmap)
+    return REG_ESPACE;
+  preg->fastmap_accurate = 0;
+
+  if (cflags & REG_ICASE)
+    {
+      unsigned i;
+
+      preg->translate = (unsigned char *) malloc (256);
+      if (!preg->translate)
+        return (int) REG_ESPACE;
+
+      /* Map uppercase characters to corresponding lowercase ones.  */
+      for (i = 0; i < CHAR_SET_SIZE; i++)
+        preg->translate[i] = isupper (i) ? tolower (i) : i;
+    }
+  else
+    preg->translate = 0;
+
+  /* If REG_NEWLINE is set, newlines are treated differently.  */
+  if (cflags & REG_NEWLINE)
+    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
+      syntax &= ~RE_DOT_NEWLINE;
+      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+      /* It also changes the matching behavior.  */
+      preg->newline_anchor = 1;
+    }
+  else
+    preg->newline_anchor = 0;
+
+  preg->no_sub = !!(cflags & REG_NOSUB);
+
+  /* POSIX says a null character in the pattern terminates it, so we
+     can use strlen here in compiling the pattern.  */
+  preg->re_nsub = 0;
+  preg->start = 0;
+  preg->se_params = 0;
+  preg->syntax_parens = 0;
+  preg->rx.nodec = 0;
+  preg->rx.epsnodec = 0;
+  preg->rx.instruction_table = 0;
+  preg->rx.nfa_states = 0;
+  preg->rx.local_cset_size = 256;
+  preg->rx.start = 0;
+  preg->rx.se_list_cmp = posix_se_list_order;
+  preg->rx.start_set = 0;
+  ret = rx_compile (pattern, strlen (pattern), syntax, preg);
+
+#ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+  _alloca (0);
+#else
+  alloca (0);
+#endif
+
+  /* POSIX doesn't distinguish between an unmatched open-group and an
+     unmatched close-group: both are REG_EPAREN.  */
+  if (ret == REG_ERPAREN) ret = REG_EPAREN;
+
+  return (int) ret;
+}
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+   string STRING.
+
+   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
+   least NMATCH elements, and we set them to the offsets of the
+   corresponding matched substrings.
+
+   EFLAGS specifies `execution flags' which affect matching: if
+   REG_NOTBOL is set, then ^ does not match at the beginning of the
+   string; if REG_NOTEOL is set, then $ does not match at the end.
+
+   We return 0 if we find a match and REG_NOMATCH if not.  */
+
+#ifdef __STDC__
+int
+regexec (__const__ regex_t *preg, __const__ char *string,
+	 size_t nmatch, regmatch_t pmatch[],
+	 int eflags)
+#else
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+    __const__ regex_t *preg;
+    __const__ char *string;
+    size_t nmatch;
+    regmatch_t pmatch[];
+    int eflags;
+#endif
+{
+  int ret;
+  struct re_registers regs;
+  regex_t private_preg;
+  int len = strlen (string);
+  boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+  private_preg = *preg;
+
+  private_preg.not_bol = !!(eflags & REG_NOTBOL);
+  private_preg.not_eol = !!(eflags & REG_NOTEOL);
+
+  /* The user has told us exactly how many registers to return
+   * information about, via `nmatch'.  We have to pass that on to the
+   * matching routines.
+   */
+  private_preg.regs_allocated = REGS_FIXED;
+
+  if (want_reg_info)
+    {
+      regs.num_regs = nmatch;
+      regs.start =  (( regoff_t *) malloc ((nmatch) * sizeof ( regoff_t)));
+      regs.end =  (( regoff_t *) malloc ((nmatch) * sizeof ( regoff_t)));
+      if (regs.start == 0 || regs.end == 0)
+        return (int) REG_NOMATCH;
+    }
+
+  /* Perform the searching operation.  */
+  ret = re_search (&private_preg,
+		   string, len,
+                   /* start: */ 0,
+		   /* range: */ len,
+                   want_reg_info ? &regs : (struct re_registers *) 0);
+
+  /* Copy the register information to the POSIX structure.  */
+  if (want_reg_info)
+    {
+      if (ret >= 0)
+        {
+          unsigned r;
+
+          for (r = 0; r < nmatch; r++)
+            {
+              pmatch[r].rm_so = regs.start[r];
+              pmatch[r].rm_eo = regs.end[r];
+            }
+        }
+
+      /* If we needed the temporary register info, free the space now.  */
+      free (regs.start);
+      free (regs.end);
+    }
+
+  /* We want zero return to mean success, unlike `re_search'.  */
+  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+   from either regcomp or regexec.   */
+
+#ifdef __STDC__
+size_t
+regerror (int errcode, __const__ regex_t *preg,
+	  char *errbuf, size_t errbuf_size)
+#else
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+    int errcode;
+    __const__ regex_t *preg;
+    char *errbuf;
+    size_t errbuf_size;
+#endif
+{
+  __const__ char *msg
+    = rx_error_msg[errcode] == 0 ? "Success" : rx_error_msg[errcode];
+  size_t msg_size = strlen (msg) + 1; /* Includes the 0.  */
+
+  if (errbuf_size != 0)
+    {
+      if (msg_size > errbuf_size)
+        {
+          strncpy (errbuf, msg, errbuf_size - 1);
+          errbuf[errbuf_size - 1] = 0;
+        }
+      else
+        strcpy (errbuf, msg);
+    }
+
+  return msg_size;
+}
+
+
+/* Free dynamically allocated space used by PREG.  */
+
+#ifdef __STDC__
+void
+regfree (regex_t *preg)
+#else
+void
+regfree (preg)
+    regex_t *preg;
+#endif
+{
+  if (preg->buffer != 0)
+    free (preg->buffer);
+  preg->buffer = 0;
+  preg->allocated = 0;
+
+  if (preg->fastmap != 0)
+    free (preg->fastmap);
+  preg->fastmap = 0;
+  preg->fastmap_accurate = 0;
+
+  if (preg->translate != 0)
+    free (preg->translate);
+  preg->translate = 0;
+}
+
+#endif /* not emacs  */
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/rx.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/rx.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/rx.h	(revision 10506)
@@ -0,0 +1,3755 @@
+#if !defined(RXH) || defined(RX_WANT_SE_DEFS)
+#define RXH
+
+/*	Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+
+This file is part of the librx library.
+
+Librx is free software; you can redistribute it and/or modify it under
+the terms of the GNU Library General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+Librx is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this software; see the file COPYING.LIB.  If not,
+write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA
+02139, USA.  */
+/*  t. lord	Wed Sep 23 18:20:57 1992	*/
+
+
+
+
+
+
+
+
+
+#ifndef RX_WANT_SE_DEFS
+
+/* This page: Bitsets */
+
+#ifndef RX_subset
+typedef unsigned int RX_subset;
+#define RX_subset_bits	(32)
+#define RX_subset_mask	(RX_subset_bits - 1)
+#endif
+
+typedef RX_subset * rx_Bitset;
+
+#ifdef __STDC__
+typedef void (*rx_bitset_iterator) (void *, int member_index);
+#else
+typedef void (*rx_bitset_iterator) ();
+#endif
+
+#define rx_bitset_subset(N)  ((N) / RX_subset_bits)
+#define rx_bitset_subset_val(B,N)  ((B)[rx_bitset_subset(N)])
+#define RX_bitset_access(B,N,OP) \
+  ((B)[rx_bitset_subset(N)] OP rx_subset_singletons[(N) & RX_subset_mask])
+#define RX_bitset_member(B,N)   RX_bitset_access(B, N, &)
+#define RX_bitset_enjoin(B,N)   RX_bitset_access(B, N, |=)
+#define RX_bitset_remove(B,N)   RX_bitset_access(B, N, &= ~)
+#define RX_bitset_toggle(B,N)   RX_bitset_access(B, N, ^= )
+#define rx_bitset_numb_subsets(N) (((N) + RX_subset_bits - 1) / RX_subset_bits)
+#define rx_sizeof_bitset(N)	(rx_bitset_numb_subsets(N) * sizeof(RX_subset))
+
+
+
+
+/* This page: Splay trees. */
+
+#ifdef __STDC__
+typedef int (*rx_sp_comparer) (void * a, void * b);
+#else
+typedef int (*rx_sp_comparer) ();
+#endif
+
+struct rx_sp_node 
+{
+  void * key;
+  void * data;
+  struct rx_sp_node * kids[2];
+};
+
+#ifdef __STDC__
+typedef void (*rx_sp_key_data_freer) (struct rx_sp_node *);
+#else
+typedef void (*rx_sp_key_data_freer) ();
+#endif
+
+
+
+/* giant inflatable hash trees */
+
+struct rx_hash_item
+{
+  struct rx_hash_item * next_same_hash;
+  struct rx_hash * table;
+  unsigned long hash;
+  void * data;
+  void * binding;
+};
+
+struct rx_hash
+{
+  struct rx_hash * parent;
+  int refs;
+  struct rx_hash * children[13];
+  struct rx_hash_item * buckets [13];
+  int bucket_size [13];
+};
+
+struct rx_hash_rules;
+
+#ifdef __STDC__
+/* should return like == */
+typedef int (*rx_hash_eq)(void *, void *);
+typedef struct rx_hash * (*rx_alloc_hash)(struct rx_hash_rules *);
+typedef void (*rx_free_hash)(struct rx_hash *,
+			    struct rx_hash_rules *);
+typedef struct rx_hash_item * (*rx_alloc_hash_item)(struct rx_hash_rules *,
+						    void *);
+typedef void (*rx_free_hash_item)(struct rx_hash_item *,
+				 struct rx_hash_rules *);
+#else
+typedef int (*rx_hash_eq)();
+typedef struct rx_hash * (*rx_alloc_hash)();
+typedef void (*rx_free_hash)();
+typedef struct rx_hash_item * (*rx_alloc_hash_item)();
+typedef void (*rx_free_hash_item)();
+#endif
+
+struct rx_hash_rules
+{
+  rx_hash_eq eq;
+  rx_alloc_hash hash_alloc;
+  rx_free_hash free_hash;
+  rx_alloc_hash_item hash_item_alloc;
+  rx_free_hash_item free_hash_item;
+};
+
+
+
+/* Forward declarations */
+
+struct rx_cache;
+struct rx_superset;
+struct rx;
+struct rx_se_list;
+
+
+
+
+/* 
+ * GLOSSARY
+ *
+ * regexp
+ * regular expression
+ * expression
+ * pattern - a `regular' expression.  The expression
+ *       need not be formally regular -- it can contain
+ *       constructs that don't correspond to purely regular
+ *       expressions.
+ *
+ * buffer
+ * string - the string (or strings) being searched or matched.
+ *
+ * pattern buffer - a structure of type `struct re_pattern_buffer'
+ *       This in turn contains a `struct rx', which holds the
+ *       NFA compiled from a pattern, as well as some of the state
+ *       of a matcher using the pattern.
+ *
+ * NFA - nondeterministic finite automata.  Some people
+ *       use this term to a member of the class of 
+ *       regular automata (those corresponding to a regular
+ *       language).  However, in this code, the meaning is
+ *       more general.  The automata used by Rx are comperable
+ *       in power to what are usually called `push down automata'.
+ *
+ *       Two NFA are built by rx for every pattern.  One is built
+ *       by the compiler.  The other is built from the first, on
+ *       the fly, by the matcher.  The latter is called the `superstate
+ *       NFA' because its states correspond to sets of states from
+ *       the first NFA.  (Joe Keane gets credit for the name
+ *       `superstate NFA').
+ *
+ * NFA edges
+ * epsilon edges
+ * side-effect edges - The NFA compiled from a pattern can have three
+ *       kinds of edges.  Epsilon edges can be taken freely anytime
+ *       their source state is reached.  Character set edges can be
+ *       taken when their source state is reached and when the next 
+ *       character in the buffer is a member of the set.  Side effect
+ *       edges imply a transition that can only be taken after the
+ *       indicated side effect has been successfully accomplished.
+ *       Some examples of side effects are:
+ *
+ *		Storing the current match position to record the
+ *              location of a parentesized subexpression.
+ *
+ *              Advancing the matcher over N characters if they
+ *              match the N characters previously matched by a 
+ *              parentesized subexpression.
+ *
+ *       Both of those kinds of edges occur in the NFA generated
+ *       by the pattern:  \(.\)\1
+ *
+ *       Epsilon and side effect edges are similar.  Unfortunately,
+ *       some of the code uses the name `epsilon edge' to mean
+ *       both epsilon and side effect edges.  For example,  the
+ *       function has_non_idempotent_epsilon_path computes the existance
+ *       of a non-trivial path containing only a mix of epsilon and
+ *       side effect edges.  In that case `nonidempotent epsilon' is being
+ *       used to mean `side effect'.
+ */
+
+
+
+
+
+
+/* LOW LEVEL PATTERN BUFFERS */
+
+/* Suppose that from some NFA state, more than one path through
+ * side-effect edges is possible.  In what order should the paths
+ * be tried?  A function of type rx_se_list_order answers that
+ * question.  It compares two lists of side effects, and says
+ * which list comes first.
+ */
+ 
+#ifdef __STDC__
+typedef int (*rx_se_list_order) (struct rx *,
+				 struct rx_se_list *, 
+				 struct rx_se_list *);
+#else
+typedef int (*rx_se_list_order) ();
+#endif
+
+
+
+/* Struct RX holds a compiled regular expression - that is, an nfa
+ * ready to be converted on demand to a more efficient superstate nfa.
+ * This is for the low level interface.  The high-level interfaces enclose
+ * this in a `struct re_pattern_buffer'.  
+ */
+struct rx
+{
+  /* The compiler assigns a unique id to every pattern.
+   * Like sequence numbers in X, there is a subtle bug here
+   * if you use Rx in a system that runs for a long time.
+   * But, because of the way the caches work out, it is almost
+   * impossible to trigger the Rx version of this bug.
+   *
+   * The id is used to validate superstates found in a cache
+   * of superstates.  It isn't sufficient to let a superstate
+   * point back to the rx for which it was compiled -- the caller
+   * may be re-using a `struct rx' in which case the superstate
+   * is not really valid.  So instead, superstates are validated
+   * by checking the sequence number of the pattern for which
+   * they were built.
+   */
+  int rx_id;
+
+  /* This is memory mgt. state for superstates.  This may be 
+   * shared by more than one struct rx.
+   */
+  struct rx_cache * cache;
+
+  /* Every regex defines the size of its own character set. 
+   * A superstate has an array of this size, with each element
+   * a `struct rx_inx'.  So, don't make this number too large.
+   * In particular, don't make it 2^16.
+   */
+  int local_cset_size;
+
+  /* After the NFA is built, it is copied into a contiguous region
+   * of memory (mostly for compatability with GNU regex).
+   * Here is that region, and it's size:
+   */
+  void * buffer;
+  unsigned long allocated;
+
+  /* Clients of RX can ask for some extra storage in the space pointed
+   * to by BUFFER.  The field RESERVED is an input parameter to the
+   * compiler.  After compilation, this much space will be available 
+   * at (buffer + allocated - reserved)
+   */
+  unsigned long reserved;
+
+  /* --------- The remaining fields are for internal use only. --------- */
+  /* --------- But! they must be initialized to 0.	       --------- */
+
+  /* NODEC is the number of nodes in the NFA with non-epsilon
+   * transitions. 
+   */
+  int nodec;
+
+  /* EPSNODEC is the number of nodes with only epsilon transitions. */
+  int epsnodec;
+
+  /* The sum (NODEC + EPSNODEC) is the total number of states in the
+   * compiled NFA.
+   */
+
+  /* Lists of side effects as stored in the NFA are `hash consed'..meaning
+   * that lists with the same elements are ==.  During compilation, 
+   * this table facilitates hash-consing.
+   */
+  struct rx_hash se_list_memo;
+
+  /* Lists of NFA states are also hashed. 
+   */
+  struct rx_hash set_list_memo;
+
+
+
+
+  /* The compiler and matcher must build a number of instruction frames.
+   * The format of these frames is fixed (c.f. struct rx_inx).  The values
+   * of the instructions is not fixed.
+   *
+   * An enumerated type (enum rx_opcode) defines the set of instructions
+   * that the compiler or matcher might generate.  When filling an instruction
+   * frame, the INX field is found by indexing this instruction table
+   * with an opcode:
+   */
+  void ** instruction_table;
+
+  /* The list of all states in an NFA.
+   * During compilation, the NEXT field of NFA states links this list.
+   * After compilation, all the states are compacted into an array,
+   * ordered by state id numbers.  At that time, this points to the base 
+   * of that array.
+   */
+  struct rx_nfa_state *nfa_states;
+
+  /* Every nfa begins with one distinguished starting state:
+   */
+  struct rx_nfa_state *start;
+
+  /* This orders the search through super-nfa paths.
+   * See the comment near the typedef of rx_se_list_order.
+   */
+  rx_se_list_order se_list_cmp;
+
+  struct rx_superset * start_set;
+};
+
+
+
+
+
+/* SYNTAX TREES */
+
+/* Compilation is in stages.  
+ *
+ * In the first stage, a pattern specified by a string is 
+ * translated into a syntax tree.  Later stages will convert
+ * the syntax tree into an NFA optimized for conversion to a
+ * superstate-NFA.
+ *
+ * This page is about syntax trees.
+ */
+
+enum rexp_node_type
+{
+  r_cset,			/* Match from a character set. `a' or `[a-z]'*/
+  r_concat,			/* Concat two subexpressions.   `ab' */
+  r_alternate,			/* Choose one of two subexpressions. `a\|b' */
+  r_opt,			/* Optional subexpression. `a?' */
+  r_star,			/* Repeated subexpression. `a*' */
+
+
+  /* A 2phase-star is a variation on a repeated subexpression.
+   * In this case, there are two subexpressions.  The first, if matched,
+   * begins a repitition (otherwise, the whole expression is matches the
+   * empth string).  
+   * 
+   * After matching the first subexpression, a 2phase star either finishes,
+   * or matches the second subexpression.  If the second subexpression is
+   * matched, then the whole construct repeats.
+   *
+   * 2phase stars are used in two circumstances.  First, they
+   * are used as part of the implementation of POSIX intervals (counted
+   * repititions).  Second, they are used to implement proper star
+   * semantics when the repeated subexpression contains paths of
+   * only side effects.  See rx_compile for more information.
+   */
+  r_2phase_star,
+
+
+  /* c.f. "typedef void * rx_side_effect" */
+  r_side_effect,
+
+  /* This is an extension type:  It is for transient use in source->source
+   * transformations (implemented over syntax trees).
+   */
+  r_data
+};
+
+/* A side effect is a matcher-specific action associated with
+ * transitions in the NFA.  The details of side effects are up
+ * to the matcher.  To the compiler and superstate constructors
+ * side effects are opaque:
+ */
+
+typedef void * rx_side_effect;
+
+/* Nodes in a syntax tree are of this type:
+ */
+struct rexp_node
+{
+  enum rexp_node_type type;
+  union
+  {
+    rx_Bitset cset;
+    rx_side_effect side_effect;
+    struct
+      {
+	struct rexp_node *left;
+	struct rexp_node *right;
+      } pair;
+    void * data;
+  } params;
+};
+
+
+
+
+/* NFA
+ *
+ * A syntax tree is compiled into an NFA.  This page defines the structure
+ * of that NFA.
+ */
+
+struct rx_nfa_state
+{
+  /* These are kept in a list as the NFA is being built. */
+  struct rx_nfa_state *next;
+
+  /* After the NFA is built, states are given integer id's.
+   * States whose outgoing transitions are all either epsilon or 
+   * side effect edges are given ids less than 0.  Other states
+   * are given successive non-negative ids starting from 0.
+   */
+  int id;
+
+  /* The list of NFA edges that go from this state to some other. */
+  struct rx_nfa_edge *edges;
+
+  /* If you land in this state, then you implicitly land
+   * in all other states reachable by only epsilon translations.
+   * Call the set of maximal paths to such states the epsilon closure
+   * of this state.
+   *
+   * There may be other states that are reachable by a mixture of
+   * epsilon and side effect edges.  Consider the set of maximal paths
+   * of that sort from this state.  Call it the epsilon-side-effect
+   * closure of the state.
+   * 
+   * The epsilon closure of the state is a subset of the epsilon-side-
+   * effect closure.  It consists of all the paths that contain 
+   * no side effects -- only epsilon edges.
+   * 
+   * The paths in the epsilon-side-effect closure  can be partitioned
+   * into equivalance sets. Two paths are equivalant if they have the
+   * same set of side effects, in the same order.  The epsilon-closure
+   * is one of these equivalance sets.  Let's call these equivalance
+   * sets: observably equivalant path sets.  That name is chosen
+   * because equivalance of two paths means they cause the same side
+   * effects -- so they lead to the same subsequent observations other
+   * than that they may wind up in different target states.
+   *
+   * The superstate nfa, which is derived from this nfa, is based on
+   * the observation that all of the paths in an observably equivalant
+   * path set can be explored at the same time, provided that the
+   * matcher keeps track not of a single nfa state, but of a set of
+   * states.   In particular, after following all the paths in an
+   * observably equivalant set, you wind up at a set of target states.
+   * That set of target states corresponds to one state in the
+   * superstate NFA.
+   *
+   * Staticly, before matching begins, it is convenient to analyze the
+   * nfa.  Each state is labeled with a list of the observably
+   * equivalant path sets who's union covers all the
+   * epsilon-side-effect paths beginning in this state.  This list is
+   * called the possible futures of the state.
+   *
+   * A trivial example is this NFA:
+   *             s1
+   *         A  --->  B
+   *
+   *             s2  
+   *            --->  C
+   *
+   *             epsilon           s1
+   *            --------->  D   ------> E
+   * 
+   * 
+   * In this example, A has two possible futures.
+   * One invokes the side effect `s1' and contains two paths,
+   * one ending in state B, the other in state E.
+   * The other invokes the side effect `s2' and contains only
+   * one path, landing in state C.
+   */
+  struct rx_possible_future *futures;
+
+
+  /* There are exactly two distinguished states in every NFA: */
+  unsigned int is_final:1;
+  unsigned int is_start:1;
+
+  /* These are used during NFA construction... */
+  unsigned int eclosure_needed:1;
+  unsigned int mark:1;
+};
+
+
+/* An edge in an NFA is typed: */
+enum rx_nfa_etype
+{
+  /* A cset edge is labled with a set of characters one of which
+   * must be matched for the edge to be taken.
+   */
+  ne_cset,
+
+  /* An epsilon edge is taken whenever its starting state is
+   * reached. 
+   */
+  ne_epsilon,
+
+  /* A side effect edge is taken whenever its starting state is
+   * reached.  Side effects may cause the match to fail or the
+   * position of the matcher to advance.
+   */
+  ne_side_effect		/* A special kind of epsilon. */
+};
+
+struct rx_nfa_edge
+{
+  struct rx_nfa_edge *next;
+  enum rx_nfa_etype type;
+  struct rx_nfa_state *dest;
+  union
+  {
+    rx_Bitset cset;
+    rx_side_effect side_effect;
+  } params;
+};
+
+
+
+/* A possible future consists of a list of side effects
+ * and a set of destination states.  Below are their
+ * representations.  These structures are hash-consed which
+ * means that lists with the same elements share a representation
+ * (their addresses are ==).
+ */
+
+struct rx_nfa_state_set
+{
+  struct rx_nfa_state * car;
+  struct rx_nfa_state_set * cdr;
+};
+
+struct rx_se_list
+{
+  rx_side_effect car;
+  struct rx_se_list * cdr;
+};
+
+struct rx_possible_future
+{
+  struct rx_possible_future *next;
+  struct rx_se_list * effects;
+  struct rx_nfa_state_set * destset;
+};
+
+
+
+
+/* This begins the description of the superstate NFA.
+ *
+ * The superstate NFA corresponds to the NFA in these ways:
+ *
+ * Every superstate NFA states SUPER correspond to sets of NFA states,
+ * nfa_states(SUPER).
+ *
+ * Superstate edges correspond to NFA paths.
+ *
+ * The superstate has no epsilon transitions;
+ * every edge has a character label, and a (possibly empty) side
+ * effect label.   The side effect label corresponds to a list of
+ * side effects that occur in the NFA.  These parts are referred
+ * to as:   superedge_character(EDGE) and superedge_sides(EDGE).
+ *
+ * For a superstate edge EDGE starting in some superstate SUPER,
+ * the following is true (in pseudo-notation :-):
+ *
+ *       exists DEST in nfa_states s.t. 
+ *         exists nfaEDGE in nfa_edges s.t.
+ *                 origin (nfaEDGE) == DEST
+ *              && origin (nfaEDGE) is a member of nfa_states(SUPER)
+ *              && exists PF in possible_futures(dest(nfaEDGE)) s.t.
+ * 	                sides_of_possible_future (PF) == superedge_sides (EDGE)
+ *
+ * also:
+ *
+ *      let SUPER2 := superedge_destination(EDGE)
+ *          nfa_states(SUPER2)
+ *           == union of all nfa state sets S s.t.
+ *                          exists PF in possible_futures(dest(nfaEDGE)) s.t.
+ * 	                       sides_of_possible_future (PF) == superedge_sides (EDGE)
+ *                          && S == dests_of_possible_future (PF) }
+ *
+ * Or in english, every superstate is a set of nfa states.  A given
+ * character and a superstate implies many transitions in the NFA --
+ * those that begin with an edge labeled with that character from a
+ * state in the set corresponding to the superstate.
+ * 
+ * The destinations of those transitions each have a set of possible
+ * futures.  A possible future is a list of side effects and a set of
+ * destination NFA states.  Two sets of possible futures can be
+ * `merged' by combining all pairs of possible futures that have the
+ * same side effects.  A pair is combined by creating a new future
+ * with the same side effect but the union of the two destination sets.
+ * In this way, all the possible futures suggested by a superstate
+ * and a character can be merged into a set of possible futures where
+ * no two elements of the set have the same set of side effects.
+ *
+ * The destination of a possible future, being a set of NFA states, 
+ * corresponds to a supernfa state.  So, the merged set of possible
+ * futures we just created can serve as a set of edges in the
+ * supernfa.
+ *
+ * The representation of the superstate nfa and the nfa is critical.
+ * The nfa has to be compact, but has to facilitate the rapid
+ * computation of missing superstates.  The superstate nfa has to 
+ * be fast to interpret, lazilly constructed, and bounded in space.
+ *
+ * To facilitate interpretation, the superstate data structures are 
+ * peppered with `instruction frames'.  There is an instruction set
+ * defined below which matchers using the supernfa must be able to
+ * interpret.
+ *
+ * We'd like to make it possible but not mandatory to use code
+ * addresses to represent instructions (c.f. gcc's computed goto).
+ * Therefore, we define an enumerated type of opcodes, and when
+ * writing one of these instructions into a data structure, use
+ * the opcode as an index into a table of instruction values.
+ * 
+ * Here are the opcodes that occur in the superstate nfa:
+ */
+ 
+
+/* Every superstate contains a table of instruction frames indexed 
+ * by characters.  A normal `move' in a matcher is to fetch the next
+ * character and use it as an index into a superstates transition
+ * table.
+ *
+ * In the fasted case, only one edge follows from that character.
+ * In other cases there is more work to do.
+ * 
+ * The descriptions of the opcodes refer to data structures that are
+ * described further below. 
+ */
+
+enum rx_opcode
+{
+  /* 
+   * BACKTRACK_POINT is invoked when a character transition in 
+   * a superstate leads to more than one edge.  In that case,
+   * the edges have to be explored independently using a backtracking
+   * strategy.
+   *
+   * A BACKTRACK_POINT instruction is stored in a superstate's 
+   * transition table for some character when it is known that that
+   * character crosses more than one edge.  On encountering this
+   * instruction, the matcher saves enough state to backtrack to this
+   * point in the match later.
+   */
+  rx_backtrack_point = 0,	/* data is (struct transition_class *) */
+
+  /* 
+   * RX_DO_SIDE_EFFECTS evaluates the side effects of an epsilon path.
+   * There is one occurence of this instruction per rx_distinct_future.
+   * This instruction is skipped if a rx_distinct_future has no side effects.
+   */
+  rx_do_side_effects = rx_backtrack_point + 1,
+
+  /* data is (struct rx_distinct_future *) */
+
+  /* 
+   * RX_CACHE_MISS instructions are stored in rx_distinct_futures whose
+   * destination superstate has been reclaimed (or was never built).
+   * It recomputes the destination superstate.
+   * RX_CACHE_MISS is also stored in a superstate transition table before
+   * any of its edges have been built.
+   */
+  rx_cache_miss = rx_do_side_effects + 1,
+  /* data is (struct rx_distinct_future *) */
+
+  /* 
+   * RX_NEXT_CHAR is called to consume the next character and take the
+   * corresponding transition.  This is the only instruction that uses 
+   * the DATA field of the instruction frame instead of DATA_2.
+   * (see EXPLORE_FUTURE in regex.c).
+   */
+  rx_next_char = rx_cache_miss + 1, /* data is (struct superstate *) */
+
+  /* RX_BACKTRACK indicates that a transition fails.
+   */
+  rx_backtrack = rx_next_char + 1, /* no data */
+
+  /* 
+   * RX_ERROR_INX is stored only in places that should never be executed.
+   */
+  rx_error_inx = rx_backtrack + 1, /* Not supposed to occur. */
+
+  rx_num_instructions = rx_error_inx + 1
+};
+
+/* An id_instruction_table holds the values stored in instruction
+ * frames.  The table is indexed by the enums declared above.
+ */
+extern void * rx_id_instruction_table[rx_num_instructions];
+
+/* The heart of the matcher is a `word-code-interpreter' 
+ * (like a byte-code interpreter, except that instructions
+ * are a full word wide).
+ *
+ * Instructions are not stored in a vector of code, instead,
+ * they are scattered throughout the data structures built
+ * by the regexp compiler and the matcher.  One word-code instruction,
+ * together with the arguments to that instruction, constitute
+ * an instruction frame (struct rx_inx).
+ *
+ * This structure type is padded by hand to a power of 2 because
+ * in one of the dominant cases, we dispatch by indexing a table
+ * of instruction frames.  If that indexing can be accomplished
+ * by just a shift of the index, we're happy.
+ *
+ * Instructions take at most one argument, but there are two
+ * slots in an instruction frame that might hold that argument.
+ * These are called data and data_2.  The data slot is only
+ * used for one instruction (RX_NEXT_CHAR).  For all other 
+ * instructions, data should be set to 0.
+ *
+ * RX_NEXT_CHAR is the most important instruction by far.
+ * By reserving the data field for its exclusive use, 
+ * instruction dispatch is sped up in that case.  There is
+ * no need to fetch both the instruction and the data,
+ * only the data is needed.  In other words, a `cycle' begins
+ * by fetching the field data.  If that is non-0, then it must
+ * be the destination state of a next_char transition, so
+ * make that value the current state, advance the match position
+ * by one character, and start a new cycle.  On the other hand,
+ * if data is 0, fetch the instruction and do a more complicated
+ * dispatch on that.
+ */
+
+struct rx_inx 
+{
+  void * data;
+  void * data_2;
+  void * inx;
+  void * fnord;
+};
+
+#ifndef RX_TAIL_ARRAY
+#define RX_TAIL_ARRAY  1
+#endif
+
+/* A superstate corresponds to a set of nfa states.  Those sets are
+ * represented by STRUCT RX_SUPERSET.  The constructors
+ * guarantee that only one (shared) structure is created for a given set.
+ */
+struct rx_superset
+{
+  int refs;			/* This is a reference counted structure. */
+
+  /* We keep these sets in a cache because (in an unpredictable way),
+   * the same set is often created again and again.  But that is also
+   * problematic -- compatibility with POSIX and GNU regex requires
+   * that we not be able to tell when a program discards a particular
+   * NFA (thus invalidating the supersets created from it).
+   *
+   * But when a cache hit appears to occur, we will have in hand the
+   * nfa for which it may have happened.  That is why every nfa is given
+   * its own sequence number.  On a cache hit, the cache is validated
+   * by comparing the nfa sequence number to this field:
+   */
+  int id;
+
+  struct rx_nfa_state * car;	/* May or may not be a valid addr. */
+  struct rx_superset * cdr;
+
+  /* If the corresponding superstate exists: */
+  struct rx_superstate * superstate;
+
+
+  /* There is another bookkeeping problem.  It is expensive to 
+   * compute the starting nfa state set for an nfa.  So, once computed,
+   * it is cached in the `struct rx'.
+   *
+   * But, the state set can be flushed from the superstate cache.
+   * When that happens, we can't know if the corresponding `struct rx'
+   * is still alive or if it has been freed or re-used by the program.
+   * So, the cached pointer to this set in a struct rx might be invalid
+   * and we need a way to validate it.
+   *
+   * Fortunately, even if this set is flushed from the cache, it is
+   * not freed.  It just goes on the free-list of supersets.
+   * So we can still examine it.  
+   *
+   * So to validate a starting set memo, check to see if the
+   * starts_for field still points back to the struct rx in question,
+   * and if the ID matches the rx sequence number.
+   */
+  struct rx * starts_for;
+
+  /* This is used to link into a hash bucket so these objects can
+   * be `hash-consed'.
+   */
+  struct rx_hash_item hash_item;
+};
+
+#define rx_protect_superset(RX,CON) (++(CON)->refs)
+
+/* The terminology may be confusing (rename this structure?).
+ * Every character occurs in at most one rx_super_edge per super-state.
+ * But, that structure might have more than one option, indicating a point
+ * of non-determinism. 
+ *
+ * In other words, this structure holds a list of superstate edges
+ * sharing a common starting state and character label.  The edges
+ * are in the field OPTIONS.  All superstate edges sharing the same
+ * starting state and character are in this list.
+ */
+struct rx_super_edge
+{
+  struct rx_super_edge *next;
+  struct rx_inx rx_backtrack_frame;
+  int cset_size;
+  rx_Bitset cset;
+  struct rx_distinct_future *options;
+};
+
+/* A superstate is a set of nfa states (RX_SUPERSET) along
+ * with a transition table.  Superstates are built on demand and reclaimed
+ * without warning.  To protect a superstate from this ghastly fate,
+ * use LOCK_SUPERSTATE. 
+ */
+struct rx_superstate
+{
+  int rx_id;			/* c.f. the id field of rx_superset */
+  int locks;			/* protection from reclamation */
+
+  /* Within a superstate cache, all the superstates are kept in a big
+   * queue.  The tail of the queue is the state most likely to be
+   * reclaimed.  The *recyclable fields hold the queue position of 
+   * this state.
+   */
+  struct rx_superstate * next_recyclable;
+  struct rx_superstate * prev_recyclable;
+
+  /* The supernfa edges that exist in the cache and that have
+   * this state as their destination are kept in this list:
+   */
+  struct rx_distinct_future * transition_refs;
+
+  /* The list of nfa states corresponding to this superstate: */
+  struct rx_superset * contents;
+
+  /* The list of edges in the cache beginning from this state. */
+  struct rx_super_edge * edges;
+
+  /* A tail of the recyclable queue is marked as semifree.  A semifree
+   * state has no incoming next_char transitions -- any transition
+   * into a semifree state causes a complex dispatch with the side
+   * effect of rescuing the state from its semifree state.
+   *
+   * An alternative to this might be to make next_char more expensive,
+   * and to move a state to the head of the recyclable queue whenever
+   * it is entered.  That way, popular states would never be recycled.
+   *
+   * But unilaterally making next_char more expensive actually loses.
+   * So, incoming transitions are only made expensive for states near
+   * the tail of the recyclable queue.  The more cache contention
+   * there is, the more frequently a state will have to prove itself
+   * and be moved back to the front of the queue.  If there is less 
+   * contention, then popular states just aggregate in the front of 
+   * the queue and stay there.
+   */
+  int is_semifree;
+
+
+  /* This keeps track of the size of the transition table for this
+   * state.  There is a half-hearted attempt to support variable sized
+   * superstates.
+   */
+  int trans_size;
+
+  /* Indexed by characters... */
+  struct rx_inx transitions[RX_TAIL_ARRAY];
+};
+
+
+/* A list of distinct futures define the edges that leave from a 
+ * given superstate on a given character.  c.f. rx_super_edge.
+ */
+
+struct rx_distinct_future
+{
+  struct rx_distinct_future * next_same_super_edge[2];
+  struct rx_distinct_future * next_same_dest;
+  struct rx_distinct_future * prev_same_dest;
+  struct rx_superstate * present;	/* source state */
+  struct rx_superstate * future;	/* destination state */
+  struct rx_super_edge * edge;
+
+
+  /* The future_frame holds the instruction that should be executed
+   * after all the side effects are done, when it is time to complete
+   * the transition to the next state.
+   *
+   * Normally this is a next_char instruction, but it may be a
+   * cache_miss instruction as well, depending on whether or not
+   * the superstate is in the cache and semifree.
+   * 
+   * If this is the only future for a given superstate/char, and
+   * if there are no side effects to be performed, this frame is
+   * not used (directly) at all.  Instead, its contents are copied
+   * into the transition table of the starting state of this dist. future.
+   */
+  struct rx_inx future_frame;
+
+  struct rx_inx side_effects_frame;
+  struct rx_se_list * effects;
+};
+
+#define rx_lock_superstate(R,S)  ((S)->locks++)
+#define rx_unlock_superstate(R,S) (--(S)->locks)
+
+
+
+/* This page destined for rx.h */
+
+struct rx_blocklist
+{
+  struct rx_blocklist * next;
+  int bytes;
+};
+
+struct rx_freelist
+{
+  struct rx_freelist * next;
+};
+
+struct rx_cache;
+
+#ifdef __STDC__
+typedef void (*rx_morecore_fn)(struct rx_cache *);
+#else
+typedef void (*rx_morecore_fn)();
+#endif
+
+/* You use this to control the allocation of superstate data 
+ * during matching.  Most of it should be initialized to 0.
+ *
+ * A MORECORE function is necessary.  It should allocate
+ * a new block of memory or return 0.
+ * A default that uses malloc is called `rx_morecore'.
+ *
+ * The number of SUPERSTATES_ALLOWED indirectly limits how much memory
+ * the system will try to allocate.  The default is 128.  Batch style
+ * applications that are very regexp intensive should use as high a number
+ * as possible without thrashing.
+ * 
+ * The LOCAL_CSET_SIZE is the number of characters in a character set.
+ * It is therefore the number of entries in a superstate transition table.
+ * Generally, it should be 256.  If your character set has 16 bits, 
+ * it is better to translate your regexps into equivalent 8 bit patterns.
+ */
+
+struct rx_cache
+{
+  struct rx_hash_rules superset_hash_rules;
+
+  /* Objects are allocated by incrementing a pointer that 
+   * scans across rx_blocklists.
+   */
+  struct rx_blocklist * memory;
+  struct rx_blocklist * memory_pos;
+  int bytes_left;
+  char * memory_addr;
+  rx_morecore_fn morecore;
+
+  /* Freelists. */
+  struct rx_freelist * free_superstates;
+  struct rx_freelist * free_transition_classes;
+  struct rx_freelist * free_discernable_futures;
+  struct rx_freelist * free_supersets;
+  struct rx_freelist * free_hash;
+
+  /* Two sets of superstates -- those that are semifreed, and those
+   * that are being used.
+   */
+  struct rx_superstate * lru_superstate;
+  struct rx_superstate * semifree_superstate;
+
+  struct rx_superset * empty_superset;
+
+  int superstates;
+  int semifree_superstates;
+  int hits;
+  int misses;
+  int superstates_allowed;
+
+  int local_cset_size;
+  void ** instruction_table;
+
+  struct rx_hash superset_table;
+};
+
+
+
+
+/* The lowest-level search function supports arbitrarily fragmented
+ * strings and (optionally) suspendable/resumable searches.
+ *
+ * Callers have to provide a few hooks.
+ */
+
+#ifndef __GNUC__
+#ifdef __STDC__
+#define __const__ const
+#else
+#define __const__
+#endif
+#endif
+
+/* This holds a matcher position */
+struct rx_string_position
+{
+  __const__ unsigned char * pos;	/* The current pos. */
+  __const__ unsigned char * string; /* The current string burst. */
+  __const__ unsigned char * end;	/* First invalid position >= POS. */
+  int offset;			/* Integer address of the current burst. */
+  int size;			/* Current string's size. */
+  int search_direction;		/* 1 or -1 */
+  int search_end;		/* First position to not try. */
+};
+
+
+enum rx_get_burst_return
+{
+  rx_get_burst_continuation,
+  rx_get_burst_error,
+  rx_get_burst_ok,
+  rx_get_burst_no_more
+};
+
+
+/* A call to get burst should make POS valid.  It might be invalid
+ * if the STRING field doesn't point to a burst that actually
+ * contains POS.
+ *
+ * GET_BURST should take a clue from SEARCH_DIRECTION (1 or -1) as to
+ * whether or not to pad to the left.  Padding to the right is always
+ * appropriate, but need not go past the point indicated by STOP.
+ *
+ * If a continuation is returned, then the reentering call to
+ * a search function will retry the get_burst.
+ */
+
+#ifdef __STDC__
+typedef enum rx_get_burst_return
+  (*rx_get_burst_fn) (struct rx_string_position * pos,
+		      void * app_closure,
+		      int stop);
+					       
+#else
+typedef enum rx_get_burst_return (*rx_get_burst_fn) ();
+#endif
+
+
+enum rx_back_check_return
+{
+  rx_back_check_continuation,
+  rx_back_check_error,
+  rx_back_check_pass,
+  rx_back_check_fail
+};
+
+/* Back_check should advance the position it is passed 
+ * over rparen - lparen characters and return pass iff
+ * the characters starting at POS match those indexed
+ * by [LPAREN..RPAREN].
+ *
+ * If a continuation is returned, then the reentering call to
+ * a search function will retry the back_check.
+ */
+
+#ifdef __STDC__
+typedef enum rx_back_check_return
+  (*rx_back_check_fn) (struct rx_string_position * pos,
+		       int lparen,
+		       int rparen,
+		       unsigned char * translate,
+		       void * app_closure,
+		       int stop);
+					       
+#else
+typedef enum rx_back_check_return (*rx_back_check_fn) ();
+#endif
+
+
+
+
+/* A call to fetch_char should return the character at POS or POS + 1.
+ * Returning continuations here isn't supported.  OFFSET is either 0 or 1
+ * and indicates which characters is desired.
+ */
+
+#ifdef __STDC__
+typedef int (*rx_fetch_char_fn) (struct rx_string_position * pos,
+				 int offset,
+				 void * app_closure,
+				 int stop);
+#else
+typedef int (*rx_fetch_char_fn) ();
+#endif
+
+
+enum rx_search_return
+{
+  rx_search_continuation = -4,
+  rx_search_error = -3,
+  rx_search_soft_fail = -2,	/* failed by running out of string */
+  rx_search_fail = -1		/* failed only by reaching failure states */
+  /* return values >= 0 indicate the position of a successful match */
+};
+
+
+
+
+
+
+
+/* regex.h
+ * 
+ * The remaining declarations replace regex.h.
+ */
+
+/* This is an array of error messages corresponding to the error codes.
+ */
+extern __const__ char *re_error_msg[];
+
+/* If any error codes are removed, changed, or added, update the
+   `re_error_msg' table in regex.c.  */
+typedef enum
+{
+  REG_NOERROR = 0,	/* Success.  */
+  REG_NOMATCH,		/* Didn't find a match (for regexec).  */
+
+  /* POSIX regcomp return error codes.  (In the order listed in the
+     standard.)  */
+  REG_BADPAT,		/* Invalid pattern.  */
+  REG_ECOLLATE,		/* Not implemented.  */
+  REG_ECTYPE,		/* Invalid character class name.  */
+  REG_EESCAPE,		/* Trailing backslash.  */
+  REG_ESUBREG,		/* Invalid back reference.  */
+  REG_EBRACK,		/* Unmatched left bracket.  */
+  REG_EPAREN,		/* Parenthesis imbalance.  */ 
+  REG_EBRACE,		/* Unmatched \{.  */
+  REG_BADBR,		/* Invalid contents of \{\}.  */
+  REG_ERANGE,		/* Invalid range end.  */
+  REG_ESPACE,		/* Ran out of memory.  */
+  REG_BADRPT,		/* No preceding re for repetition op.  */
+
+  /* Error codes we've added.  */
+  REG_EEND,		/* Premature end.  */
+  REG_ESIZE,		/* Compiled pattern bigger than 2^16 bytes.  */
+  REG_ERPAREN		/* Unmatched ) or \); not returned from regcomp.  */
+} reg_errcode_t;
+
+/* The regex.c support, as a client of rx, defines a set of possible
+ * side effects that can be added to the edge lables of nfa edges.
+ * Here is the list of sidef effects in use.
+ */
+
+enum re_side_effects
+{
+#define RX_WANT_SE_DEFS 1
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#define RX_DEF_SE(IDEM, NAME, VALUE)	      NAME VALUE,
+#define RX_DEF_CPLX_SE(IDEM, NAME, VALUE)     NAME VALUE,
+#include "rx.h"
+#undef RX_DEF_SE
+#undef RX_DEF_CPLX_SE
+#undef RX_WANT_SE_DEFS
+   re_floogle_flap = 65533
+};
+
+/* These hold paramaters for the kinds of side effects that are possible
+ * in the supported pattern languages.  These include things like the 
+ * numeric bounds of {} operators and the index of paren registers for 
+ * subexpression measurement or backreferencing.
+ */
+struct re_se_params
+{
+  enum re_side_effects se;
+  int op1;
+  int op2;
+};
+
+typedef unsigned reg_syntax_t;
+
+struct re_pattern_buffer
+{
+  struct rx rx;
+  reg_syntax_t syntax;		/* See below for syntax bit definitions. */
+
+  unsigned int no_sub:1;	/* If set, don't  return register offsets. */
+  unsigned int not_bol:1;	/* If set, the anchors ('^' and '$') don't */
+  unsigned int not_eol:1;	/*     match at the ends of the string.  */  
+  unsigned int newline_anchor:1;/* If true, an anchor at a newline matches.*/
+  unsigned int least_subs:1;	/* If set, and returning registers, return
+				 * as few values as possible.  Only 
+				 * backreferenced groups and group 0 (the whole
+				 * match) will be returned.
+				 */
+
+  /* If true, this says that the matcher should keep registers on its
+   * backtracking stack.  For many patterns, we can easily determine that
+   * this isn't necessary.
+   */
+  unsigned int match_regs_on_stack:1;
+  unsigned int search_regs_on_stack:1;
+
+  /* is_anchored and begbuf_only are filled in by rx_compile. */
+  unsigned int is_anchored:1;	/* Anchorded by ^? */
+  unsigned int begbuf_only:1;	/* Anchored to char position 0? */
+
+  
+  /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+   * for `max (RE_NREGS, re_nsub + 1)' groups.
+   * If REGS_REALLOCATE, reallocate space if necessary.
+   * If REGS_FIXED, use what's there.  
+   */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+  unsigned int regs_allocated:2;
+
+  
+  /* Either a translate table to apply to all characters before
+   * comparing them, or zero for no translation.  The translation
+   * is applied to a pattern when it is compiled and to a string
+   * when it is matched.
+   */
+  unsigned char * translate;
+
+  /* If this is a valid pointer, it tells rx not to store the extents of 
+   * certain subexpressions (those corresponding to non-zero entries).
+   * Passing 0x1 is the same as passing an array of all ones.  Passing 0x0
+   * is the same as passing an array of all zeros.
+   * The array should contain as many entries as their are subexps in the 
+   * regexp.
+   *
+   * For POSIX compatability, when using regcomp and regexec this field
+   * is zeroed and ignored.
+   */
+  char * syntax_parens;
+
+	/* Number of subexpressions found by the compiler.  */
+  size_t re_nsub;
+
+  void * buffer;		/* Malloced memory for the nfa. */
+  unsigned long allocated;	/* Size of that memory. */
+
+  /* Pointer to a fastmap, if any, otherwise zero.  re_search uses
+   * the fastmap, if there is one, to skip over impossible
+   * starting points for matches.  */
+  char *fastmap;
+
+  unsigned int fastmap_accurate:1; /* These three are internal. */
+  unsigned int can_match_empty:1;  
+  struct rx_nfa_state * start;	/* The nfa starting state. */
+
+  /* This is the list of iterator bounds for {lo,hi} constructs.
+   * The memory pointed to is part of the rx->buffer.
+   */
+  struct re_se_params *se_params;
+
+  /* This is a bitset representation of the fastmap.
+   * This is a true fastmap that already takes the translate
+   * table into account.
+   */
+  rx_Bitset fastset;
+};
+
+/* Type for byte offsets within the string.  POSIX mandates this.  */
+typedef int regoff_t;
+
+/* This is the structure we store register match data in.  See
+   regex.texinfo for a full description of what registers match.  */
+struct re_registers
+{
+  unsigned num_regs;
+  regoff_t *start;
+  regoff_t *end;
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+/* POSIX specification for registers.  Aside from the different names than
+   `re_registers', POSIX uses an array of structures, instead of a
+   structure of arrays.  */
+typedef struct
+{
+  regoff_t rm_so;  /* Byte offset from string's start to substring's start.  */
+  regoff_t rm_eo;  /* Byte offset from string's start to substring's end.  */
+} regmatch_t;
+
+
+
+/* The following bits are used to determine the regexp syntax we
+   recognize.  The set/not-set meanings are chosen so that Emacs syntax
+   remains the value 0.  The bits are given in alphabetical order, and
+   the definitions shifted by one from the previous bit; thus, when we
+   add or remove a bit, only one other definition need change.  */
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+   If set, then such a \ quotes the following character.  */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+     literals. 
+   If set, then \+ and \? are operators and + and ? are literals.  */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported.  They are:
+     [:alpha:], [:upper:], [:lower:],  [:digit:], [:alnum:], [:xdigit:],
+     [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+   If not set, then character classes are not supported.  */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+     expressions, of course).
+   If this bit is not set, then it depends:
+        ^  is an anchor if it is at the beginning of a regular
+           expression or after an open-group or an alternation operator;
+        $  is an anchor if it is at the end of a regular expression, or
+           before a close-group or an alternation operator.  
+
+   This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+   POSIX draft 11.2 says that * etc. in leading positions is undefined.
+   We already implemented a previous draft which made those constructs
+   invalid, though, so we haven't changed the code back.  */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+     regardless of where they are in the pattern.
+   If this bit is not set, then special characters are special only in
+     some contexts; otherwise they are ordinary.  Specifically, 
+     * + ? and intervals are only special when not after the beginning,
+     open-group, or alternation operator.  */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+     immediately after an alternation or begin-group operator.  */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+   If not set, then it doesn't.  */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+   If not set, then it does.  */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+   If not set, they do.  */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+     interval, depending on RE_NO_BK_BRACES. 
+   If not set, \{, \}, {, and } are literals.  */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+   If not set, they are.  */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+   If not set, newline is literal.  */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+     are literals.
+  If not set, then `\{...\}' defines an interval.  */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+   If not set, \(...\) defines a group, and ( and ) are literals.  */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+   If not set, then \<digit> is a back-reference.  */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal. 
+   If not set, then \| is an alternation operator, and | is literal.  */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+     than the starting range point, as in [z-a], is invalid.
+   If not set, then when ending range point collates higher than the
+     starting range point, the range is ignored.  */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+   If not set, then an unmatched ) is invalid.  */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+   some interfaces).  When a regexp is compiled, the syntax used is
+   stored in the pattern buffer, so changing this does not affect
+   already-compiled regexps.  */
+extern reg_syntax_t re_syntax_options;
+
+
+/* Define combinations of the above bits for the standard possibilities.
+   (The [[[ comments delimit what gets put into the Texinfo file, so
+   don't delete them!)  */ 
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK							\
+  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL			\
+   | RE_NO_BK_PARENS            | RE_NO_BK_REFS				\
+   | RE_NO_BK_VAR               | RE_NO_EMPTY_RANGES			\
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK 						\
+  (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP							\
+  (RE_BK_PLUS_QM              | RE_CHAR_CLASSES				\
+   | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS				\
+   | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP							\
+  (RE_CHAR_CLASSES        | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE			\
+   | RE_NEWLINE_ALT       | RE_NO_BK_PARENS				\
+   | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP						\
+  (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax.  */
+#define _RE_SYNTAX_POSIX_COMMON						\
+  (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL		\
+   | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC						\
+  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+   RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
+   isn't minimal, since other operators, such as \`, aren't disabled.  */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC					\
+  (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED					\
+  (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INDEP_OPS  | RE_NO_BK_BRACES				\
+   | RE_NO_BK_PARENS       | RE_NO_BK_VBAR				\
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+   replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added.  */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED				\
+  (_RE_SYNTAX_POSIX_COMMON  | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES				\
+   | RE_NO_BK_PARENS        | RE_NO_BK_REFS				\
+   | RE_NO_BK_VBAR	    | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow.  Some systems
+   (erroneously) define this in other header files, but we want our
+   value, so remove any previous define.  */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1) 
+
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp').  */
+
+/* If this bit is set, then use extended regular expression syntax.
+   If not set, then use basic regular expression syntax.  */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+   If not set, then case is significant.  */
+#define REG_ICASE (REG_EXTENDED << 1)
+ 
+/* If this bit is set, then anchors do not match at newline
+     characters in the string.
+   If not set, then anchors do match at newlines.  */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+   If not set, then returns differ between not matching and errors.  */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec).  */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+     the beginning of the string (presumably because it's not the
+     beginning of a line).
+   If not set, then the beginning-of-line operator does match the
+     beginning of the string.  */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line.  */
+#define REG_NOTEOL (1 << 1)
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ * `re_match_2' returns information about at least this many registers
+ * the first time a `regs' structure is passed. 
+ *
+ * Also, this is the greatest number of backreferenced subexpressions
+ * allowed in a pattern being matched without caller-supplied registers.
+ */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+extern int rx_cache_bound;
+extern char rx_version_string[];
+
+
+
+
+#ifdef RX_WANT_RX_DEFS
+
+/* This is decls to the interesting subsystems and lower layers
+ * of rx.  Everything which doesn't have a public counterpart in 
+ * regex.c is declared here.
+ */
+
+
+#ifdef __STDC__
+typedef void (*rx_hash_freefn) (struct rx_hash_item * it);
+#else /* ndef __STDC__ */
+typedef void (*rx_hash_freefn) ();
+#endif /* ndef __STDC__ */
+
+
+
+
+
+#ifdef __STDC__
+RX_DECL int rx_bitset_is_equal (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL int rx_bitset_is_subset (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL int rx_bitset_empty (int size, rx_Bitset set);
+RX_DECL void rx_bitset_null (int size, rx_Bitset b);
+RX_DECL void rx_bitset_universe (int size, rx_Bitset b);
+RX_DECL void rx_bitset_complement (int size, rx_Bitset b);
+RX_DECL void rx_bitset_assign (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL void rx_bitset_union (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL void rx_bitset_intersection (int size,
+				     rx_Bitset a, rx_Bitset b);
+RX_DECL void rx_bitset_difference (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL void rx_bitset_revdifference (int size,
+				      rx_Bitset a, rx_Bitset b);
+RX_DECL void rx_bitset_xor (int size, rx_Bitset a, rx_Bitset b);
+RX_DECL unsigned long rx_bitset_hash (int size, rx_Bitset b);
+RX_DECL struct rx_hash_item * rx_hash_find (struct rx_hash * table,
+					    unsigned long hash,
+					    void * value,
+					    struct rx_hash_rules * rules);
+RX_DECL struct rx_hash_item * rx_hash_store (struct rx_hash * table,
+					     unsigned long hash,
+					     void * value,
+					     struct rx_hash_rules * rules);
+RX_DECL void rx_hash_free (struct rx_hash_item * it, struct rx_hash_rules * rules);
+RX_DECL void rx_free_hash_table (struct rx_hash * tab, rx_hash_freefn freefn,
+				 struct rx_hash_rules * rules);
+RX_DECL rx_Bitset rx_cset (struct rx *rx);
+RX_DECL rx_Bitset rx_copy_cset (struct rx *rx, rx_Bitset a);
+RX_DECL void rx_free_cset (struct rx * rx, rx_Bitset c);
+RX_DECL struct rexp_node * rexp_node (struct rx *rx,
+				      enum rexp_node_type type);
+RX_DECL struct rexp_node * rx_mk_r_cset (struct rx * rx,
+					 rx_Bitset b);
+RX_DECL struct rexp_node * rx_mk_r_concat (struct rx * rx,
+					   struct rexp_node * a,
+					   struct rexp_node * b);
+RX_DECL struct rexp_node * rx_mk_r_alternate (struct rx * rx,
+					      struct rexp_node * a,
+					      struct rexp_node * b);
+RX_DECL struct rexp_node * rx_mk_r_opt (struct rx * rx,
+					struct rexp_node * a);
+RX_DECL struct rexp_node * rx_mk_r_star (struct rx * rx,
+					 struct rexp_node * a);
+RX_DECL struct rexp_node * rx_mk_r_2phase_star (struct rx * rx,
+						struct rexp_node * a,
+						struct rexp_node * b);
+RX_DECL struct rexp_node * rx_mk_r_side_effect (struct rx * rx,
+						rx_side_effect a);
+RX_DECL struct rexp_node * rx_mk_r_data  (struct rx * rx,
+					  void * a);
+RX_DECL void rx_free_rexp (struct rx * rx, struct rexp_node * node);
+RX_DECL struct rexp_node * rx_copy_rexp (struct rx *rx,
+					 struct rexp_node *node);
+RX_DECL struct rx_nfa_state * rx_nfa_state (struct rx *rx);
+RX_DECL void rx_free_nfa_state (struct rx_nfa_state * n);
+RX_DECL struct rx_nfa_state * rx_id_to_nfa_state (struct rx * rx,
+						  int id);
+RX_DECL struct rx_nfa_edge * rx_nfa_edge (struct rx *rx,
+					  enum rx_nfa_etype type,
+					  struct rx_nfa_state *start,
+					  struct rx_nfa_state *dest);
+RX_DECL void rx_free_nfa_edge (struct rx_nfa_edge * e);
+RX_DECL void rx_free_nfa (struct rx *rx);
+RX_DECL int rx_build_nfa (struct rx *rx,
+			  struct rexp_node *rexp,
+			  struct rx_nfa_state **start,
+			  struct rx_nfa_state **end);
+RX_DECL void rx_name_nfa_states (struct rx *rx);
+RX_DECL int rx_eclose_nfa (struct rx *rx);
+RX_DECL void rx_delete_epsilon_transitions (struct rx *rx);
+RX_DECL int rx_compactify_nfa (struct rx *rx,
+			       void **mem, unsigned long *size);
+RX_DECL void rx_release_superset (struct rx *rx,
+				  struct rx_superset *set);
+RX_DECL struct rx_superset * rx_superset_cons (struct rx * rx,
+					       struct rx_nfa_state *car, struct rx_superset *cdr);
+RX_DECL struct rx_superset * rx_superstate_eclosure_union
+  (struct rx * rx, struct rx_superset *set, struct rx_nfa_state_set *ecl);
+RX_DECL struct rx_superstate * rx_superstate (struct rx *rx,
+					      struct rx_superset *set);
+RX_DECL struct rx_inx * rx_handle_cache_miss
+  (struct rx *rx, struct rx_superstate *super, unsigned char chr, void *data);
+RX_DECL reg_errcode_t rx_compile (__const__ char *pattern, int size,
+				  reg_syntax_t syntax,
+				  struct re_pattern_buffer * rxb);
+RX_DECL void rx_blow_up_fastmap (struct re_pattern_buffer * rxb);
+#else /* STDC */
+RX_DECL int rx_bitset_is_equal ();
+RX_DECL int rx_bitset_is_subset ();
+RX_DECL int rx_bitset_empty ();
+RX_DECL void rx_bitset_null ();
+RX_DECL void rx_bitset_universe ();
+RX_DECL void rx_bitset_complement ();
+RX_DECL void rx_bitset_assign ();
+RX_DECL void rx_bitset_union ();
+RX_DECL void rx_bitset_intersection ();
+RX_DECL void rx_bitset_difference ();
+RX_DECL void rx_bitset_revdifference ();
+RX_DECL void rx_bitset_xor ();
+RX_DECL unsigned long rx_bitset_hash ();
+RX_DECL struct rx_hash_item * rx_hash_find ();
+RX_DECL struct rx_hash_item * rx_hash_store ();
+RX_DECL void rx_hash_free ();
+RX_DECL void rx_free_hash_table ();
+RX_DECL rx_Bitset rx_cset ();
+RX_DECL rx_Bitset rx_copy_cset ();
+RX_DECL void rx_free_cset ();
+RX_DECL struct rexp_node * rexp_node ();
+RX_DECL struct rexp_node * rx_mk_r_cset ();
+RX_DECL struct rexp_node * rx_mk_r_concat ();
+RX_DECL struct rexp_node * rx_mk_r_alternate ();
+RX_DECL struct rexp_node * rx_mk_r_opt ();
+RX_DECL struct rexp_node * rx_mk_r_star ();
+RX_DECL struct rexp_node * rx_mk_r_2phase_star ();
+RX_DECL struct rexp_node * rx_mk_r_side_effect ();
+RX_DECL struct rexp_node * rx_mk_r_data  ();
+RX_DECL void rx_free_rexp ();
+RX_DECL struct rexp_node * rx_copy_rexp ();
+RX_DECL struct rx_nfa_state * rx_nfa_state ();
+RX_DECL void rx_free_nfa_state ();
+RX_DECL struct rx_nfa_state * rx_id_to_nfa_state ();
+RX_DECL struct rx_nfa_edge * rx_nfa_edge ();
+RX_DECL void rx_free_nfa_edge ();
+RX_DECL void rx_free_nfa ();
+RX_DECL int rx_build_nfa ();
+RX_DECL void rx_name_nfa_states ();
+RX_DECL int rx_eclose_nfa ();
+RX_DECL void rx_delete_epsilon_transitions ();
+RX_DECL int rx_compactify_nfa ();
+RX_DECL void rx_release_superset ();
+RX_DECL struct rx_superset * rx_superset_cons ();
+RX_DECL struct rx_superset * rx_superstate_eclosure_union ();
+RX_DECL struct rx_superstate * rx_superstate ();
+RX_DECL struct rx_inx * rx_handle_cache_miss ();
+RX_DECL reg_errcode_t rx_compile ();
+RX_DECL void rx_blow_up_fastmap ();
+#endif /* STDC */
+
+
+#endif /* RX_WANT_RX_DEFS */
+
+
+
+
+#ifdef __STDC__
+extern int re_search_2 (struct re_pattern_buffer *rxb,
+			__const__ char * string1, int size1,
+			__const__ char * string2, int size2,
+			int startpos, int range,
+			struct re_registers *regs,
+			int stop);
+extern int re_search (struct re_pattern_buffer * rxb, __const__ char *string,
+		      int size, int startpos, int range,
+		      struct re_registers *regs);
+extern int re_match_2 (struct re_pattern_buffer * rxb,
+		       __const__ char * string1, int size1,
+		       __const__ char * string2, int size2,
+		       int pos, struct re_registers *regs, int stop);
+extern int re_match (struct re_pattern_buffer * rxb,
+		     __const__ char * string,
+		     int size, int pos,
+		     struct re_registers *regs);
+extern reg_syntax_t re_set_syntax (reg_syntax_t syntax);
+extern void re_set_registers (struct re_pattern_buffer *bufp,
+			      struct re_registers *regs,
+			      unsigned num_regs,
+			      regoff_t * starts, regoff_t * ends);
+extern __const__ char * re_compile_pattern (__const__ char *pattern,
+					int length,
+					struct re_pattern_buffer * rxb);
+extern int re_compile_fastmap (struct re_pattern_buffer * rxb);
+extern char * re_comp (__const__ char *s);
+extern int re_exec (__const__ char *s);
+extern int regcomp (regex_t * preg, __const__ char * pattern, int cflags);
+extern int regexec (__const__ regex_t *preg, __const__ char *string,
+		    size_t nmatch, regmatch_t pmatch[],
+		    int eflags);
+extern size_t regerror (int errcode, __const__ regex_t *preg,
+			char *errbuf, size_t errbuf_size);
+extern void regfree (regex_t *preg);
+
+#else /* STDC */
+extern int re_search_2 ();
+extern int re_search ();
+extern int re_match_2 ();
+extern int re_match ();
+extern reg_syntax_t re_set_syntax ();
+extern void re_set_registers ();
+extern __const__ char * re_compile_pattern ();
+extern int re_compile_fastmap ();
+extern char * re_comp ();
+extern int re_exec ();
+extern int regcomp ();
+extern int regexec ();
+extern size_t regerror ();
+extern void regfree ();
+
+#endif /* STDC */
+
+
+
+
+#ifdef RX_WANT_RX_DEFS
+
+struct rx_counter_frame
+{
+  int tag;
+  int val;
+  struct rx_counter_frame * inherited_from; /* If this is a copy. */
+  struct rx_counter_frame * cdr;
+};
+
+struct rx_backtrack_frame
+{
+  char * counter_stack_sp;
+
+  /* A frame is used to save the matchers state when it crosses a 
+   * backtracking point.  The `stk_' fields correspond to variables
+   * in re_search_2 (just strip off thes `stk_').  They are documented
+   * tere.
+   */
+  struct rx_superstate * stk_super;
+  unsigned int stk_c;
+  struct rx_string_position stk_test_pos;
+  int stk_last_l;
+  int stk_last_r;
+  int stk_test_ret;
+
+  /* This is the list of options left to explore at the backtrack
+   * point for which this frame was created. 
+   */
+  struct rx_distinct_future * df;
+  struct rx_distinct_future * first_df;
+
+#ifdef RX_DEBUG
+   int stk_line_no;
+#endif
+};
+
+struct rx_stack_chunk
+{
+  struct rx_stack_chunk * next_chunk;
+  int bytes_left;
+  char * sp;
+};
+
+enum rx_outer_entry
+{
+  rx_outer_start,
+  rx_outer_fastmap,
+  rx_outer_test,
+  rx_outer_restore_pos
+};
+
+enum rx_fastmap_return
+{
+  rx_fastmap_continuation,
+  rx_fastmap_error,
+  rx_fastmap_ok,
+  rx_fastmap_fail
+};
+
+enum rx_fastmap_entry
+{
+  rx_fastmap_start,
+  rx_fastmap_string_break
+};
+
+enum rx_test_return
+{
+  rx_test_continuation,
+  rx_test_error,
+  rx_test_fail,
+  rx_test_ok
+};
+
+enum rx_test_internal_return
+{
+  rx_test_internal_error,
+  rx_test_found_first,
+  rx_test_line_finished
+};
+
+enum rx_test_match_entry
+{
+  rx_test_start,
+  rx_test_cache_hit_loop,
+  rx_test_backreference_check,
+  rx_test_backtrack_return
+};
+
+struct rx_search_state
+{
+  /* Two groups of registers are kept.  The group with the register state
+   * of the current test match, and the group that holds the state at the end
+   * of the best known match, if any.
+   *
+   * For some patterns, there may also be registers saved on the stack.
+   */
+  unsigned num_regs;		/* Includes an element for register zero. */
+  regoff_t * lparen;		/* scratch space for register returns */
+  regoff_t * rparen;
+  regoff_t * best_lpspace;	/* in case the user doesn't want these */
+  regoff_t * best_rpspace;	/* values, we still need space to store
+				 * them.  Normally, this memoryis unused
+				 * and the space pointed to by REGS is 
+				 * used instead.
+				 */
+  
+  int last_l;			/* Highest index of a valid lparen. */
+  int last_r;			/* It's dual. */
+  
+  int * best_lparen;		/* This contains the best known register */
+  int * best_rparen;		/* assignments. 
+				 * This may point to the same mem as
+				 * best_lpspace, or it might point to memory
+				 * passed by the caller.
+				 */
+  int best_last_l;		/* best_last_l:best_lparen::last_l:lparen */
+  int best_last_r;
+
+
+  unsigned char * translate;  
+
+  struct rx_string_position outer_pos;
+
+  struct rx_superstate * start_super;
+  int nfa_choice;
+  int first_found;		/* If true, return after finding any match. */
+  int ret_val;
+
+  /* For continuations... */
+  enum rx_outer_entry outer_search_resume_pt;
+  struct re_pattern_buffer * saved_rxb;
+  int saved_startpos;
+  int saved_range;
+  int saved_stop;
+  int saved_total_size;
+  rx_get_burst_fn saved_get_burst;
+  rx_back_check_fn saved_back_check;
+  struct re_registers * saved_regs;
+  
+  /**
+   ** state for fastmap
+   **/
+  char * fastmap;
+  int fastmap_chr;
+  int fastmap_val;
+
+  /* for continuations in the fastmap procedure: */
+  enum rx_fastmap_entry fastmap_resume_pt;
+
+  /**
+   ** state for test_match 
+   **/
+
+  /* The current superNFA position of the matcher. */
+  struct rx_superstate * super;
+  
+  /* The matcher interprets a series of instruction frames.
+   * This is the `instruction counter' for the interpretation.
+   */
+  struct rx_inx * ifr;
+  
+  /* We insert a ghost character in the string to prime
+   * the nfa.  test_pos.pos, test_pos.str_half, and test_pos.end_half
+   * keep track of the test-match position and string-half.
+   */
+  unsigned char c;
+  
+  /* Position within the string. */
+  struct rx_string_position test_pos;
+
+  struct rx_stack_chunk * counter_stack;
+  struct rx_stack_chunk * backtrack_stack;
+  int backtrack_frame_bytes;
+  int chunk_bytes;
+  struct rx_stack_chunk * free_chunks;
+
+  /* To return from this function, set test_ret and 
+   * `goto test_do_return'.
+   *
+   * Possible return values are:
+   *     1   --- end of string while the superNFA is still going
+   *     0   --- internal error (out of memory)
+   *	-1   --- search completed by reaching the superNFA fail state
+   *    -2   --- a match was found, maybe not the longest.
+   *
+   * When the search is complete (-1), best_last_r indicates whether
+   * a match was found.
+   *
+   * -2 is return only if search_state.first_found is non-zero.
+   *
+   * if search_state.first_found is non-zero, a return of -1 indicates no match,
+   * otherwise, best_last_r has to be checked.
+   */
+  int test_ret;
+
+  int could_have_continued;
+  
+#ifdef RX_DEBUG
+  int backtrack_depth;
+  /* There is a search tree with every node as set of deterministic
+   * transitions in the super nfa.  For every branch of a 
+   * backtrack point is an edge in the tree.
+   * This counts up a pre-order of nodes in that tree.
+   * It's saved on the search stack and printed when debugging. 
+   */
+  int line_no;
+  int lines_found;
+#endif
+
+
+  /* For continuations within the match tester */
+  enum rx_test_match_entry test_match_resume_pt;
+  struct rx_inx * saved_next_tr_table;
+  struct rx_inx * saved_this_tr_table;
+  int saved_reg;
+  struct rx_backtrack_frame * saved_bf;
+  
+};
+
+
+
+extern char rx_slowmap[];
+extern unsigned char rx_id_translation[];
+
+static __inline__ void
+init_fastmap (rxb, search_state)
+     struct re_pattern_buffer * rxb;
+     struct rx_search_state * search_state;
+{
+  search_state->fastmap = (rxb->fastmap
+			   ? (char *)rxb->fastmap
+			   : (char *)rx_slowmap);
+  /* Update the fastmap now if not correct already. 
+   * When the regexp was compiled, the fastmap was computed
+   * and stored in a bitset.  This expands the bitset into a
+   * character array containing 1s and 0s.
+   */
+  if ((search_state->fastmap == rxb->fastmap) && !rxb->fastmap_accurate)
+    rx_blow_up_fastmap (rxb);
+  search_state->fastmap_chr = -1;
+  search_state->fastmap_val = 0;
+  search_state->fastmap_resume_pt = rx_fastmap_start;
+}
+
+static __inline__ void
+uninit_fastmap (rxb, search_state)
+     struct re_pattern_buffer * rxb;
+     struct rx_search_state * search_state;
+{
+  /* Unset the fastmap sentinel */
+  if (search_state->fastmap_chr >= 0)
+    search_state->fastmap[search_state->fastmap_chr]
+      = search_state->fastmap_val;
+}
+
+static __inline__ int
+fastmap_search (rxb, stop, get_burst, app_closure, search_state)
+     struct re_pattern_buffer * rxb;
+     int stop;
+     rx_get_burst_fn get_burst;
+     void * app_closure;
+     struct rx_search_state * search_state;
+{
+  enum rx_fastmap_entry pc;
+
+  if (0)
+    {
+    return_continuation:
+      search_state->fastmap_resume_pt = pc;
+      return rx_fastmap_continuation;
+    }
+
+  pc = search_state->fastmap_resume_pt;
+
+  switch (pc)
+    {
+    default:
+      return rx_fastmap_error;
+    case rx_fastmap_start:
+    init_fastmap_sentinal:
+      /* For the sake of fast fastmapping, set a sentinal in the fastmap.
+       * This sentinal will trap the fastmap loop when it reaches the last
+       * valid character in a string half.
+       *
+       * This must be reset when the fastmap/search loop crosses a string 
+       * boundry, and before returning to the caller.  So sometimes,
+       * the fastmap loop is restarted with `continue', othertimes by
+       * `goto init_fastmap_sentinal'.
+       */
+      if (search_state->outer_pos.size)
+	{
+	  search_state->fastmap_chr = ((search_state->outer_pos.search_direction == 1)
+				       ? *(search_state->outer_pos.end - 1)
+				       : *search_state->outer_pos.string);
+	  search_state->fastmap_val
+	    = search_state->fastmap[search_state->fastmap_chr];
+	  search_state->fastmap[search_state->fastmap_chr] = 1;
+	}
+      else
+	{
+	  search_state->fastmap_chr = -1;
+	  search_state->fastmap_val = 0;
+	}
+      
+      if (search_state->outer_pos.pos >= search_state->outer_pos.end)
+	goto fastmap_hit_bound;
+      else
+	{
+	  if (search_state->outer_pos.search_direction == 1)
+	    {
+	      if (search_state->fastmap_val)
+		{
+		  for (;;)
+		    {
+		      while (!search_state->fastmap[*search_state->outer_pos.pos])
+			++search_state->outer_pos.pos;
+		      return rx_fastmap_ok;
+		    }
+		}
+	      else
+		{
+		  for (;;)
+		    {
+		      while (!search_state->fastmap[*search_state->outer_pos.pos])
+			++search_state->outer_pos.pos;
+		      if (*search_state->outer_pos.pos != search_state->fastmap_chr)
+			return rx_fastmap_ok;
+		      else 
+			{
+			  ++search_state->outer_pos.pos;
+			  if (search_state->outer_pos.pos == search_state->outer_pos.end)
+			    goto fastmap_hit_bound;
+			}
+		    }
+		}
+	    }
+	  else
+	    {
+	      __const__ unsigned char * bound;
+	      bound = search_state->outer_pos.string - 1;
+	      if (search_state->fastmap_val)
+		{
+		  for (;;)
+		    {
+		      while (!search_state->fastmap[*search_state->outer_pos.pos])
+			--search_state->outer_pos.pos;
+		      return rx_fastmap_ok;
+		    }
+		}
+	      else
+		{
+		  for (;;)
+		    {
+		      while (!search_state->fastmap[*search_state->outer_pos.pos])
+			--search_state->outer_pos.pos;
+		      if ((*search_state->outer_pos.pos != search_state->fastmap_chr) || search_state->fastmap_val)
+			return rx_fastmap_ok;
+		      else 
+			{
+			  --search_state->outer_pos.pos;
+			  if (search_state->outer_pos.pos == bound)
+			    goto fastmap_hit_bound;
+			}
+		    }
+		}
+	    }
+	}
+      
+    case rx_fastmap_string_break:
+    fastmap_hit_bound:
+      {
+	/* If we hit a bound, it may be time to fetch another burst
+	 * of string, or it may be time to return a continuation to 
+ 	 * the caller, or it might be time to fail.
+	 */
+
+	int burst_state;
+	burst_state = get_burst (&search_state->outer_pos, app_closure, stop);
+	switch (burst_state)
+	  {
+	  default:
+	  case rx_get_burst_error:
+	    return rx_fastmap_error;
+	  case rx_get_burst_continuation:
+	    {
+	      pc = rx_fastmap_string_break;
+	      goto return_continuation;
+	    }
+	  case rx_get_burst_ok:
+	    goto init_fastmap_sentinal;
+	  case rx_get_burst_no_more:
+	    /* ...not a string split, simply no more string. 
+	     *
+	     * When searching backward, running out of string
+	     * is reason to quit.
+	     *
+	     * When searching forward, we allow the possibility
+	     * of an (empty) match after the last character in the
+	     * virtual string.  So, fall through to the matcher
+	     */
+	    return (  (search_state->outer_pos.search_direction == 1)
+		    ? rx_fastmap_ok
+		    : rx_fastmap_fail);
+	  }
+      }
+    }
+
+}
+
+
+
+
+#ifdef emacs
+/* The `emacs' switch turns on certain matching commands
+ * that make sense only in Emacs. 
+ */
+#include "sysfuncs.h"
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+#endif /* emacs */
+
+/* Setting RX_MEMDBUG is useful if you have dbmalloc.  Maybe with similar
+ * packages too.
+ */
+#ifdef RX_MEMDBUG
+#include <malloc.h>
+#endif /* RX_RX_MEMDBUG */
+
+/* We used to test for `BSTRING' here, but only GCC and Emacs define
+ * `BSTRING', as far as I know, and neither of them use this code.  
+ */
+#if HAVE_STRING_H || STDC_HEADERS
+#include <string.h>
+
+#ifndef bcmp
+#define bcmp(s1, s2, n)	memcmp ((s1), (s2), (n))
+#endif
+
+#ifndef bcopy
+#define bcopy(s, d, n)	memcpy ((d), (s), (n))
+#endif
+
+#ifndef bzero
+#define bzero(s, n)	memset ((s), 0, (n))
+#endif
+
+#else /*  HAVE_STRING_H || STDC_HEADERS */
+#include <strings.h>
+#endif   /* not (HAVE_STRING_H || STDC_HEADERS) */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else /* not STDC_HEADERS */
+char *malloc ();
+char *realloc ();
+#endif /* not STDC_HEADERS */
+
+
+
+
+
+/* How many characters in the character set.  */
+#define CHAR_SET_SIZE (1 << CHARBITS)
+
+#ifndef emacs
+/* Define the syntax basics for \<, \>, etc.
+ * This must be nonzero for the wordchar and notwordchar pattern
+ * commands in re_match_2.
+ */
+#ifndef Sword 
+#define Sword 1
+#endif
+#define SYNTAX(c) re_syntax_table[c]
+#ifdef SYNTAX_TABLE
+extern char *re_syntax_table;
+#else
+RX_DECL char re_syntax_table[CHAR_SET_SIZE];
+#endif
+#endif /* not emacs */
+
+
+/* Test if at very beginning or at very end of the virtual concatenation
+ *  of `string1' and `string2'.  If only one string, it's `string2'.  
+ */
+
+#define AT_STRINGS_BEG() \
+  (   -1		 \
+   == ((search_state.test_pos.pos - search_state.test_pos.string) \
+       + search_state.test_pos.offset))
+
+#define AT_STRINGS_END() \
+  (   (total_size - 1)	 \
+   == ((search_state.test_pos.pos - search_state.test_pos.string) \
+       + search_state.test_pos.offset))
+
+
+/* Test if POS + 1 points to a character which is word-constituent.  We have
+ * two special cases to check for: if past the end of string1, look at
+ * the first character in string2; and if before the beginning of
+ * string2, look at the last character in string1.
+ *
+ * Assumes `string1' exists, so use in conjunction with AT_STRINGS_BEG ().  
+ */
+#define LETTER_P(POS,OFF)						\
+  (   SYNTAX (fetch_char(POS, OFF, app_closure, stop))			\
+   == Sword)
+
+/* Test if the character at D and the one after D differ with respect
+ * to being word-constituent.  
+ */
+#define AT_WORD_BOUNDARY(d)						\
+  (AT_STRINGS_BEG () || AT_STRINGS_END () || LETTER_P (d,0) != LETTER_P (d, 1))
+
+
+#ifdef RX_SUPPORT_CONTINUATIONS
+#define RX_STACK_ALLOC(BYTES) malloc(BYTES)
+#define RX_STACK_FREE(MEM) free(MEM)
+#else
+#define RX_STACK_ALLOC(BYTES) alloca(BYTES)
+#define RX_STACK_FREE(MEM) \
+      ((struct rx_stack_chunk *)MEM)->next_chunk = search_state.free_chunks; \
+      search_state.free_chunks = ((struct rx_stack_chunk *)MEM);
+
+#endif
+
+#define PUSH(CHUNK_VAR,BYTES)   \
+  if (!CHUNK_VAR || (CHUNK_VAR->bytes_left < (BYTES)))  \
+    {					\
+      struct rx_stack_chunk * new_chunk;	\
+      if (search_state.free_chunks)			\
+	{				\
+	  new_chunk = search_state.free_chunks;	\
+	  search_state.free_chunks = search_state.free_chunks->next_chunk; \
+	}				\
+      else				\
+	{				\
+	  new_chunk = (struct rx_stack_chunk *)RX_STACK_ALLOC(search_state.chunk_bytes); \
+	  if (!new_chunk)		\
+	    {				\
+	      search_state.ret_val = 0;		\
+	      goto test_do_return;	\
+	    }				\
+	}				\
+      new_chunk->sp = (char *)new_chunk + sizeof (struct rx_stack_chunk); \
+      new_chunk->bytes_left = (search_state.chunk_bytes \
+			       - (BYTES) \
+			       - sizeof (struct rx_stack_chunk)); \
+      new_chunk->next_chunk = CHUNK_VAR; \
+      CHUNK_VAR = new_chunk;		\
+    } \
+  else \
+    (CHUNK_VAR->sp += (BYTES)), (CHUNK_VAR->bytes_left -= (BYTES))
+
+#define POP(CHUNK_VAR,BYTES) \
+  if (CHUNK_VAR->sp == ((char *)CHUNK_VAR + sizeof(*CHUNK_VAR))) \
+    { \
+      struct rx_stack_chunk * new_chunk = CHUNK_VAR->next_chunk; \
+      RX_STACK_FREE(CHUNK_VAR); \
+      CHUNK_VAR = new_chunk; \
+    } \
+  else \
+    (CHUNK_VAR->sp -= BYTES), (CHUNK_VAR->bytes_left += BYTES)
+
+
+
+#define SRCH_TRANSLATE(C)  search_state.translate[(unsigned char) (C)]
+
+
+
+
+
+#ifdef __STDC__
+RX_DECL __inline__ int
+rx_search  (struct re_pattern_buffer * rxb,
+	    int startpos,
+	    int range,
+	    int stop,
+	    int total_size,
+	    rx_get_burst_fn get_burst,
+	    rx_back_check_fn back_check,
+	    rx_fetch_char_fn fetch_char,
+	    void * app_closure,
+	    struct re_registers * regs,
+	    struct rx_search_state * resume_state,
+	    struct rx_search_state * save_state)
+#else
+RX_DECL __inline__ int
+rx_search  (rxb, startpos, range, stop, total_size,
+	    get_burst, back_check, fetch_char,
+	    app_closure, regs, resume_state, save_state)
+     struct re_pattern_buffer * rxb;
+     int startpos;
+     int range;
+     int stop;
+     int total_size;
+     rx_get_burst_fn get_burst;
+     rx_back_check_fn back_check;
+     rx_fetch_char_fn fetch_char;
+     void * app_closure;
+     struct re_registers * regs;
+     struct rx_search_state * resume_state;
+     struct rx_search_state * save_state;
+#endif
+{
+  int pc;
+  int test_state;
+  struct rx_search_state search_state;
+
+  search_state.free_chunks = 0;
+  if (!resume_state)
+    pc = rx_outer_start;
+  else
+    {
+      search_state = *resume_state;
+      regs = search_state.saved_regs;
+      rxb = search_state.saved_rxb;
+      startpos = search_state.saved_startpos;
+      range = search_state.saved_range;
+      stop = search_state.saved_stop;
+      total_size = search_state.saved_total_size;
+      get_burst = search_state.saved_get_burst;
+      back_check = search_state.saved_back_check;
+      pc = search_state.outer_search_resume_pt;
+      if (0)
+	{
+	return_continuation:
+	  if (save_state)
+	    {
+	      *save_state = search_state;
+	      save_state->saved_regs = regs;
+	      save_state->saved_rxb = rxb;
+	      save_state->saved_startpos = startpos;
+	      save_state->saved_range = range;
+	      save_state->saved_stop = stop;
+	      save_state->saved_total_size = total_size;
+	      save_state->saved_get_burst = get_burst;
+	      save_state->saved_back_check = back_check;
+	      save_state->outer_search_resume_pt = pc;
+	    }
+	  return rx_search_continuation;
+	}
+    }
+
+  switch (pc)
+    {
+    case rx_outer_start:
+      search_state.ret_val = rx_search_fail;
+      (  search_state.lparen
+       = search_state.rparen
+       = search_state.best_lpspace
+       = search_state.best_rpspace
+       = 0);
+      
+      /* figure the number of registers we may need for use in backreferences.
+       * the number here includes an element for register zero.  
+       */
+      search_state.num_regs = rxb->re_nsub + 1;
+      
+      
+      /* check for out-of-range startpos.  */
+      if ((startpos < 0) || (startpos > total_size))
+	return rx_search_fail;
+      
+      /* fix up range if it might eventually take us outside the string. */
+      {
+	int endpos;
+	endpos = startpos + range;
+	if (endpos < -1)
+	  range = (-1 - startpos);
+	else if (endpos > (total_size + 1))
+	  range = total_size - startpos;
+      }
+      
+      /* if the search isn't to be a backwards one, don't waste time in a
+       * long search for a pattern that says it is anchored.
+       */
+      if (rxb->begbuf_only && (range > 0))
+	{
+	  if (startpos > 0)
+	    return rx_search_fail;
+	  else
+	    range = 1;
+	}
+      
+      /* decide whether to use internal or user-provided reg buffers. */
+      if (!regs || rxb->no_sub)
+	{
+	  search_state.best_lpspace =
+	    (regoff_t *)REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t));
+	  search_state.best_rpspace =
+	    (regoff_t *)REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t));
+	  search_state.best_lparen = search_state.best_lpspace;
+	  search_state.best_rparen = search_state.best_rpspace;
+	}
+      else
+	{	
+	  /* have the register data arrays been allocated?  */
+	  if (rxb->regs_allocated == REGS_UNALLOCATED)
+	    { /* no.  so allocate them with malloc.  we need one
+		 extra element beyond `search_state.num_regs' for the `-1' marker
+		 gnu code uses.  */
+	      regs->num_regs = MAX (RE_NREGS, rxb->re_nsub + 1);
+	      regs->start = ((regoff_t *)
+			     malloc (regs->num_regs * sizeof ( regoff_t)));
+	      regs->end = ((regoff_t *)
+			   malloc (regs->num_regs * sizeof ( regoff_t)));
+	      if (regs->start == 0 || regs->end == 0)
+		return rx_search_error;
+	      rxb->regs_allocated = REGS_REALLOCATE;
+	    }
+	  else if (rxb->regs_allocated == REGS_REALLOCATE)
+	    { /* yes.  if we need more elements than were already
+		 allocated, reallocate them.  if we need fewer, just
+		 leave it alone.  */
+	      if (regs->num_regs < search_state.num_regs + 1)
+		{
+		  regs->num_regs = search_state.num_regs + 1;
+		  regs->start = ((regoff_t *)
+				 realloc (regs->start,
+					  regs->num_regs * sizeof (regoff_t)));
+		  regs->end = ((regoff_t *)
+			       realloc (regs->end,
+					regs->num_regs * sizeof ( regoff_t)));
+		  if (regs->start == 0 || regs->end == 0)
+		    return rx_search_error;
+		}
+	    }
+	  else if (rxb->regs_allocated != REGS_FIXED)
+	    return rx_search_error;
+	  
+	  if (regs->num_regs < search_state.num_regs + 1)
+	    {
+	      search_state.best_lpspace =
+		((regoff_t *)
+		 REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t)));
+	      search_state.best_rpspace =
+		((regoff_t *)
+		 REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t)));
+	      search_state.best_lparen = search_state.best_lpspace;
+	      search_state.best_rparen = search_state.best_rpspace;
+	    }
+	  else
+	    {
+	      search_state.best_lparen = regs->start;
+	      search_state.best_rparen = regs->end;
+	    }
+	}
+      
+      search_state.lparen =
+	(regoff_t *) REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t));
+      search_state.rparen =
+	(regoff_t *) REGEX_ALLOCATE (search_state.num_regs * sizeof(regoff_t)); 
+      
+      if (! (   search_state.best_rparen
+	     && search_state.best_lparen
+	     && search_state.lparen && search_state.rparen))
+	return rx_search_error;
+      
+      search_state.best_last_l = search_state.best_last_r = -1;
+      
+      search_state.translate = (rxb->translate
+				? rxb->translate
+				: rx_id_translation);
+      
+      
+      
+      /*
+       * two nfa's were compiled.  
+       * `0' is complete.
+       * `1' faster but gets registers wrong and ends too soon.
+       */
+      search_state.nfa_choice = (regs && !rxb->least_subs) ? '\0' : '\1';
+      
+      /* we have the option to look for the best match or the first
+       * one we can find.  if the user isn't asking for register information,
+       * we don't need to find the best match.
+       */
+      search_state.first_found = !regs;
+      
+      if (range >= 0)
+	{
+	  search_state.outer_pos.search_end = startpos + range;
+	  search_state.outer_pos.search_direction = 1;
+	}
+      else
+	{
+	  search_state.outer_pos.search_end = startpos + range;
+	  search_state.outer_pos.search_direction = -1;
+	}
+      
+      /* the vacuous search always turns up nothing. */
+      if ((search_state.outer_pos.search_direction == 1)
+	  ? (startpos > search_state.outer_pos.search_end)
+	  : (startpos < search_state.outer_pos.search_end))
+	return rx_search_fail;
+      
+      /* now we build the starting state of the supernfa. */
+      {
+	struct rx_superset * start_contents;
+	struct rx_nfa_state_set * start_nfa_set;
+	
+	/* we presume here that the nfa start state has only one
+	 * possible future with no side effects.  
+	 */
+	start_nfa_set = rxb->start->futures->destset;
+	if (   rxb->rx.start_set
+	    && (rxb->rx.start_set->starts_for == &rxb->rx))
+	  start_contents = rxb->rx.start_set;
+	else
+	  {
+	    start_contents =
+	      rx_superstate_eclosure_union (&rxb->rx,
+					    rx_superset_cons (&rxb->rx, 0, 0),
+					    start_nfa_set);
+	    
+	    if (!start_contents)
+	      return rx_search_fail;
+	    
+	    start_contents->starts_for = &rxb->rx;
+	    rxb->rx.start_set = start_contents;
+	  }
+	if (   start_contents->superstate
+	    && (start_contents->superstate->rx_id == rxb->rx.rx_id))
+	  {
+	    search_state.start_super = start_contents->superstate;
+	    rx_lock_superstate (&rxb->rx, search_state.start_super);
+	  }
+	else
+	  {
+	    rx_protect_superset (&rxb->rx, start_contents);
+	    
+	    search_state.start_super = rx_superstate (&rxb->rx, start_contents);
+	    if (!search_state.start_super)
+	      return rx_search_fail;
+	    rx_lock_superstate (&rxb->rx, search_state.start_super);
+	    rx_release_superset (&rxb->rx, start_contents);
+	  }
+      }
+      
+      
+      /* The outer_pos tracks the position within the strings
+       * as seen by loop that calls fastmap_search.
+       *
+       * The caller supplied get_burst function actually 
+       * gives us pointers to chars.
+       * 
+       * Communication with the get_burst function is through an
+       * rx_string_position structure.  Here, the structure for
+       * outer_pos is initialized.   It is set to point to the
+       * NULL string, at an offset of STARTPOS.  STARTPOS is out
+       * of range of the NULL string, so the first call to 
+       * getburst will patch up the rx_string_position to point
+       * to valid characters.
+       */
+
+      (  search_state.outer_pos.string
+       = search_state.outer_pos.end
+       = 0);
+
+      search_state.outer_pos.offset = 0;
+      search_state.outer_pos.size = 0;
+      search_state.outer_pos.pos = (unsigned char *)startpos;
+      init_fastmap (rxb, &search_state);
+
+      search_state.fastmap_resume_pt = rx_fastmap_start;
+    case rx_outer_fastmap:
+      /* do { */
+    pseudo_do:
+      {
+	{
+	  int fastmap_state;
+	  fastmap_state = fastmap_search (rxb, stop, get_burst, app_closure,
+					  &search_state);
+	  switch (fastmap_state)
+	    {
+	    case rx_fastmap_continuation:
+	      pc = rx_outer_fastmap;
+	      goto return_continuation;
+	    case rx_fastmap_fail:
+	      goto finish;
+	    case rx_fastmap_ok:
+	      break;
+	    }
+	}
+	
+	/* now the fastmap loop has brought us to a plausible 
+	 * starting point for a match.  so, it's time to run the
+	 * nfa and see if a match occured.
+	 */
+	startpos = (  search_state.outer_pos.pos
+		    - search_state.outer_pos.string
+		    + search_state.outer_pos.offset);
+/*|*/	if ((range > 0) && (startpos == search_state.outer_pos.search_end))
+/*|*/	  goto finish;
+      }
+
+      search_state.test_match_resume_pt = rx_test_start;
+      /* do interrupted for entry point... */
+    case rx_outer_test:
+      /* ...do continued */
+      {
+	goto test_match;
+      test_returns_to_search:
+	switch (test_state)
+	  {
+	  case rx_test_continuation:
+	    pc = rx_outer_test;
+	    goto return_continuation;
+	  case rx_test_error:
+	    search_state.ret_val = rx_search_error;
+	    goto finish;
+	  case rx_test_fail:
+	    break;
+	  case rx_test_ok:
+	    goto finish;
+	  }
+	search_state.outer_pos.pos += search_state.outer_pos.search_direction;
+	startpos += search_state.outer_pos.search_direction;
+#if 0
+/*|*/	if (search_state.test_pos.pos < search_state.test_pos.end)
+/*|*/	  break;
+#endif
+      }
+      /* do interrupted for entry point... */
+    case rx_outer_restore_pos:
+      {
+	int x;
+	x = get_burst (&search_state.outer_pos, app_closure, stop);
+	switch (x)
+	  {
+	  case rx_get_burst_continuation:
+	    pc = rx_outer_restore_pos;
+	    goto return_continuation;
+	  case rx_get_burst_error:
+	    search_state.ret_val = rx_search_error;
+	    goto finish;
+	  case rx_get_burst_no_more:
+	    if (rxb->can_match_empty)
+	      break;
+	    goto finish;
+	  case rx_get_burst_ok:
+	    break;
+	  }
+      } /* } while (...see below...) */
+
+      if ((search_state.outer_pos.search_direction == 1)
+	  ? (startpos < search_state.outer_pos.search_end)
+	  : (startpos > search_state.outer_pos.search_end))
+	goto pseudo_do;
+
+	
+    finish:
+      uninit_fastmap (rxb, &search_state);
+      if (search_state.start_super)
+	rx_unlock_superstate (&rxb->rx, search_state.start_super);
+      
+#ifdef regex_malloc
+      if (search_state.lparen) free (search_state.lparen);
+      if (search_state.rparen) free (search_state.rparen);
+      if (search_state.best_lpspace) free (search_state.best_lpspace);
+      if (search_state.best_rpspace) free (search_state.best_rpspace);
+#endif
+      return search_state.ret_val;
+    }
+
+
+ test_match:
+  {
+    enum rx_test_match_entry test_pc;
+    int inx;
+    test_pc = search_state.test_match_resume_pt;
+    if (test_pc == rx_test_start)
+      {
+#ifdef RX_DEBUG
+	search_state.backtrack_depth = 0;
+#endif
+	search_state.last_l = search_state.last_r = 0;
+	search_state.lparen[0] = startpos;
+	search_state.super = search_state.start_super;
+	search_state.c = search_state.nfa_choice;
+	search_state.test_pos.pos = search_state.outer_pos.pos - 1;    
+	search_state.test_pos.string = search_state.outer_pos.string;
+	search_state.test_pos.end = search_state.outer_pos.end;
+	search_state.test_pos.offset = search_state.outer_pos.offset;
+	search_state.test_pos.size = search_state.outer_pos.size;
+	search_state.test_pos.search_direction = 1;
+	search_state.counter_stack = 0;
+	search_state.backtrack_stack = 0;
+	search_state.backtrack_frame_bytes =
+	  (sizeof (struct rx_backtrack_frame)
+	   + (rxb->match_regs_on_stack
+	      ? sizeof (regoff_t) * (search_state.num_regs + 1) * 2
+	      : 0));
+	search_state.chunk_bytes = search_state.backtrack_frame_bytes * 64;
+	search_state.test_ret = rx_test_line_finished;
+	search_state.could_have_continued = 0;
+      }  
+    /* This is while (1)...except that the body of the loop is interrupted 
+     * by some alternative entry points.
+     */
+  pseudo_while_1:
+    switch (test_pc)
+      {
+      case rx_test_cache_hit_loop:
+	goto resume_continuation_1;
+      case rx_test_backreference_check:
+	goto resume_continuation_2;
+      case rx_test_backtrack_return:
+	goto resume_continuation_3;
+      case rx_test_start:
+#ifdef RX_DEBUG
+	/* There is a search tree with every node as set of deterministic
+	 * transitions in the super nfa.  For every branch of a 
+	 * backtrack point is an edge in the tree.
+	 * This counts up a pre-order of nodes in that tree.
+	 * It's saved on the search stack and printed when debugging. 
+	 */
+	search_state.line_no = 0;
+	search_state.lines_found = 0;
+#endif
+	
+      top_of_cycle:
+	/* A superstate is basicly a transition table, indexed by 
+	 * characters from the string being tested, and containing 
+	 * RX_INX (`instruction frame') structures.
+	 */
+	search_state.ifr = &search_state.super->transitions [search_state.c];
+	
+      recurse_test_match:
+	/* This is the point to which control is sent when the
+	 * test matcher `recurses'.  Before jumping here, some variables
+	 * need to be saved on the stack and the next instruction frame
+	 * has to be computed.
+	 */
+	
+      restart:
+	/* Some instructions don't advance the matcher, but just
+	 * carry out some side effects and fetch a new instruction.
+	 * To dispatch that new instruction, `goto restart'.
+	 */
+	
+	{
+	  struct rx_inx * next_tr_table;
+	  struct rx_inx * this_tr_table;
+	  /* The fastest route through the loop is when the instruction 
+	   * is RX_NEXT_CHAR.  This case is detected when SEARCH_STATE.IFR->DATA
+	   * is non-zero.  In that case, it points to the next
+	   * superstate. 
+	   *
+	   * This allows us to not bother fetching the bytecode.
+	   */
+	  next_tr_table = (struct rx_inx *)search_state.ifr->data;
+	  this_tr_table = search_state.super->transitions;
+	  while (next_tr_table)
+	    {
+#ifdef RX_DEBUG_0
+	      if (rx_debug_trace)
+		{
+		  struct rx_superset * setp;
+		  
+		  fprintf (stderr, "%d %d>> re_next_char @ %d (%d)",
+			   search_state.line_no,
+			   search_state.backtrack_depth,
+			   (search_state.test_pos.pos - search_state.test_pos.string
+			    + search_state.test_pos.offset), search_state.c);
+		  
+		  search_state.super =
+		    ((struct rx_superstate *)
+		     ((char *)this_tr_table
+		      - ((unsigned long)
+			 ((struct rx_superstate *)0)->transitions)));
+		  
+		  setp = search_state.super->contents;
+		  fprintf (stderr, "   superstet (rx=%d, &=%x: ",
+			   rxb->rx.rx_id, setp);
+		  while (setp)
+		    {
+		      fprintf (stderr, "%d ", setp->id);
+		      setp = setp->cdr;
+		    }
+		  fprintf (stderr, "\n");
+		}
+#endif
+	      this_tr_table = next_tr_table;
+	      ++search_state.test_pos.pos;
+	      if (search_state.test_pos.pos == search_state.test_pos.end)
+		{
+		  int burst_state;
+		try_burst_1:
+		  burst_state = get_burst (&search_state.test_pos,
+					   app_closure, stop);
+		  switch (burst_state)
+		    {
+		    case rx_get_burst_continuation:
+		      search_state.saved_this_tr_table = this_tr_table;
+		      search_state.saved_next_tr_table = next_tr_table;
+		      test_pc = rx_test_cache_hit_loop;
+		      goto test_return_continuation;
+		      
+		    resume_continuation_1:
+		      /* Continuation one jumps here to do its work: */
+		      search_state.saved_this_tr_table = this_tr_table;
+		      search_state.saved_next_tr_table = next_tr_table;
+		      goto try_burst_1;
+		      
+		    case rx_get_burst_ok:
+		      /* get_burst succeeded...keep going */
+		      break;
+		      
+		    case rx_get_burst_no_more:
+		      search_state.test_ret = rx_test_line_finished;
+		      search_state.could_have_continued = 1;
+		      goto test_do_return;
+		      
+		    case rx_get_burst_error:
+		      /* An error... */
+		      search_state.test_ret = rx_test_internal_error;
+		      goto test_do_return;
+		    }
+		}
+	      search_state.c = *search_state.test_pos.pos;
+	      search_state.ifr = this_tr_table + search_state.c;
+	      next_tr_table = (struct rx_inx *)search_state.ifr->data;
+	    } /* Fast loop through cached transition tables */
+	  
+	  /* Here when we ran out of cached next-char transitions. 
+	   * So, it will be necessary to do a more expensive
+	   * dispatch on the current instruction.  The superstate
+	   * pointer is allowed to become invalid during next-char
+	   * transitions -- now we must bring it up to date.
+	   */
+	  search_state.super =
+	    ((struct rx_superstate *)
+	     ((char *)this_tr_table
+	      - ((unsigned long)
+		 ((struct rx_superstate *)0)->transitions)));
+	}
+	
+	/* We've encountered an instruction other than next-char.
+	 * Dispatch that instruction:
+	 */
+	inx = (int)search_state.ifr->inx;
+#ifdef RX_DEBUG_0
+	if (rx_debug_trace)
+	  {
+	    struct rx_superset * setp = search_state.super->contents;
+	    
+	    fprintf (stderr, "%d %d>> %s @ %d (%d)", search_state.line_no,
+		     search_state.backtrack_depth,
+		     inx_names[inx],
+		     (search_state.test_pos.pos - search_state.test_pos.string
+		      + (test_pos.half == 0 ? 0 : size1)), search_state.c);
+	    
+	    fprintf (stderr, "   superstet (rx=%d, &=%x: ",
+		     rxb->rx.rx_id, setp);
+	    while (setp)
+	      {
+		fprintf (stderr, "%d ", setp->id);
+		setp = setp->cdr;
+	      }
+	    fprintf (stderr, "\n");
+	  }
+#endif
+	switch ((enum rx_opcode)inx)
+	  {
+	  case rx_do_side_effects:
+	    
+	    /*  RX_DO_SIDE_EFFECTS occurs when we cross epsilon 
+	     *  edges associated with parentheses, backreferencing, etc.
+	     */
+	    {
+	      struct rx_distinct_future * df =
+		(struct rx_distinct_future *)search_state.ifr->data_2;
+	      struct rx_se_list * el = df->effects;
+	      /* Side effects come in lists.  This walks down
+	       * a list, dispatching.
+	       */
+	      while (el)
+		{
+		  long effect;
+		  effect = (long)el->car;
+		  if (effect < 0)
+		    {
+#ifdef RX_DEBUG_0
+		      if (rx_debug_trace)
+			{
+			  struct rx_superset * setp = search_state.super->contents;
+			  
+			  fprintf (stderr, "....%d %d>> %s\n", search_state.line_no,
+				   search_state.backtrack_depth,
+				   efnames[-effect]);
+			}
+#endif
+		      switch ((enum re_side_effects) effect)
+
+			{
+			case re_se_pushback:
+			  search_state.ifr = &df->future_frame;
+			  if (!search_state.ifr->data)
+			    {
+			      struct rx_superstate * sup;
+			      sup = search_state.super;
+			      rx_lock_superstate (rx, sup);
+			      if (!rx_handle_cache_miss (&rxb->rx,
+							 search_state.super,
+							 search_state.c,
+							 (search_state.ifr
+							  ->data_2)))
+				{
+				  rx_unlock_superstate (rx, sup);
+				  search_state.test_ret = rx_test_internal_error;
+				  goto test_do_return;
+				}
+			      rx_unlock_superstate (rx, sup);
+			    }
+			  /* --search_state.test_pos.pos; */
+			  search_state.c = 't';
+			  search_state.super
+			    = ((struct rx_superstate *)
+			       ((char *)search_state.ifr->data
+				- (long)(((struct rx_superstate *)0)
+					 ->transitions)));
+			  goto top_of_cycle;
+			  break;
+			case re_se_push0:
+			  {
+			    struct rx_counter_frame * old_cf
+			      = (search_state.counter_stack
+				 ? ((struct rx_counter_frame *)
+				    search_state.counter_stack->sp)
+				 : 0);
+			    struct rx_counter_frame * cf;
+			    PUSH (search_state.counter_stack,
+				  sizeof (struct rx_counter_frame));
+			    cf = ((struct rx_counter_frame *)
+				  search_state.counter_stack->sp);
+			    cf->tag = re_se_iter;
+			    cf->val = 0;
+			    cf->inherited_from = 0;
+			    cf->cdr = old_cf;
+			    break;
+			  }
+			case re_se_fail:
+			  goto test_do_return;
+			case re_se_begbuf:
+			  if (!AT_STRINGS_BEG ())
+			    goto test_do_return;
+			  break;
+			case re_se_endbuf:
+			  if (!AT_STRINGS_END ())
+			    goto test_do_return;
+			  break;
+			case re_se_wordbeg:
+			  if (   LETTER_P (&search_state.test_pos, 1)
+			      && (   AT_STRINGS_BEG()
+				  || !LETTER_P (&search_state.test_pos, 0)))
+			    break;
+			  else
+			    goto test_do_return;
+			case re_se_wordend:
+			  if (   !AT_STRINGS_BEG ()
+			      && LETTER_P (&search_state.test_pos, 0)
+			      && (AT_STRINGS_END ()
+				  || !LETTER_P (&search_state.test_pos, 1)))
+			    break;
+			  else
+			    goto test_do_return;
+			case re_se_wordbound:
+			  if (AT_WORD_BOUNDARY (&search_state.test_pos))
+			    break;
+			  else
+			    goto test_do_return;
+			case re_se_notwordbound:
+			  if (!AT_WORD_BOUNDARY (&search_state.test_pos))
+			    break;
+			  else
+			    goto test_do_return;
+			case re_se_hat:
+			  if (AT_STRINGS_BEG ())
+			    {
+			      if (rxb->not_bol)
+				goto test_do_return;
+			      else
+				break;
+			    }
+			  else
+			    {
+			      char pos_c = *search_state.test_pos.pos;
+			      if (   (SRCH_TRANSLATE (pos_c)
+				      == SRCH_TRANSLATE('\n'))
+				  && rxb->newline_anchor)
+				break;
+			      else
+				goto test_do_return;
+			    }
+			case re_se_dollar:
+			  if (AT_STRINGS_END ())
+			    {
+			      if (rxb->not_eol)
+				goto test_do_return;
+			      else
+				break;
+			    }
+			  else
+			    {
+			      if (   (   SRCH_TRANSLATE (fetch_char
+						    (&search_state.test_pos, 1,
+						     app_closure, stop))
+				      == SRCH_TRANSLATE ('\n'))
+				  && rxb->newline_anchor)
+				break;
+			      else
+				goto test_do_return;
+			    }
+			  
+			case re_se_try:
+			  /* This is the first side effect in every
+			   * expression.
+			   *
+			   *  FOR NO GOOD REASON...get rid of it...
+			   */
+			  break;
+			  
+			case re_se_pushpos:
+			  {
+			    int urhere =
+			      ((int)(search_state.test_pos.pos
+				     - search_state.test_pos.string)
+			       + search_state.test_pos.offset);
+			    struct rx_counter_frame * old_cf
+			      = (search_state.counter_stack
+				 ? ((struct rx_counter_frame *)
+				    search_state.counter_stack->sp)
+				 : 0);
+			    struct rx_counter_frame * cf;
+			    PUSH(search_state.counter_stack,
+				 sizeof (struct rx_counter_frame));
+			    cf = ((struct rx_counter_frame *)
+				  search_state.counter_stack->sp);
+			    cf->tag = re_se_pushpos;
+			    cf->val = urhere;
+			    cf->inherited_from = 0;
+			    cf->cdr = old_cf;
+			    break;
+			  }
+			  
+			case re_se_chkpos:
+			  {
+			    int urhere =
+			      ((int)(search_state.test_pos.pos
+				     - search_state.test_pos.string)
+			       + search_state.test_pos.offset);
+			    struct rx_counter_frame * cf
+			      = ((struct rx_counter_frame *)
+				 search_state.counter_stack->sp);
+			    if (cf->val == urhere)
+			      goto test_do_return;
+			    cf->val = urhere;
+			    break;
+			  }
+			  break;
+			  
+			case re_se_poppos:
+			  POP(search_state.counter_stack,
+			      sizeof (struct rx_counter_frame));
+			  break;
+			  
+			  
+			case re_se_at_dot:
+			case re_se_syntax:
+			case re_se_not_syntax:
+#ifdef emacs
+			  /* 
+			   * this release lacks emacs support
+			   */
+#endif
+			  break;
+			case re_se_win:
+			case re_se_lparen:
+			case re_se_rparen:
+			case re_se_backref:
+			case re_se_iter:
+			case re_se_end_iter:
+			case re_se_tv:
+			case re_floogle_flap:
+			  search_state.ret_val = 0;
+			  goto test_do_return;
+			}
+		    }
+		  else
+		    {
+#ifdef RX_DEBUG_0
+		      if (rx_debug_trace)
+			fprintf (stderr, "....%d %d>> %s %d %d\n", search_state.line_no,
+				 search_state.backtrack_depth,
+				 efnames2[rxb->se_params [effect].se],
+				 rxb->se_params [effect].op1,
+				 rxb->se_params [effect].op2);
+#endif
+		      switch (rxb->se_params [effect].se)
+			{
+			case re_se_win:
+			  /* This side effect indicates that we've 
+			   * found a match, though not necessarily the 
+			   * best match.  This is a fancy assignment to 
+			   * register 0 unless the caller didn't 
+			   * care about registers.  In which case,
+			   * this stops the match.
+			   */
+			  {
+			    int urhere =
+			      ((int)(search_state.test_pos.pos
+				     - search_state.test_pos.string)
+			       + search_state.test_pos.offset);
+			    
+			    if (   (search_state.best_last_r < 0)
+				|| (urhere + 1 > search_state.best_rparen[0]))
+			      {
+				/* Record the best known and keep
+				 * looking.
+				 */
+				int x;
+				for (x = 0; x <= search_state.last_l; ++x)
+				  search_state.best_lparen[x] = search_state.lparen[x];
+				search_state.best_last_l = search_state.last_l;
+				for (x = 0; x <= search_state.last_r; ++x)
+				  search_state.best_rparen[x] = search_state.rparen[x];
+				search_state.best_rparen[0] = urhere + 1;
+				search_state.best_last_r = search_state.last_r;
+			      }
+			    /* If we're not reporting the match-length 
+			     * or other register info, we need look no
+			     * further.
+			     */
+			    if (search_state.first_found)
+			      {
+				search_state.test_ret = rx_test_found_first;
+				goto test_do_return;
+			      }
+			  }
+			  break;
+			case re_se_lparen:
+			  {
+			    int urhere =
+			      ((int)(search_state.test_pos.pos
+				     - search_state.test_pos.string)
+			       + search_state.test_pos.offset);
+			    
+			    int reg = rxb->se_params [effect].op1;
+#if 0
+			    if (reg > search_state.last_l)
+#endif
+			      {
+				search_state.lparen[reg] = urhere + 1;
+				/* In addition to making this assignment,
+				 * we now know that lower numbered regs
+				 * that haven't already been assigned,
+				 * won't be.  We make sure they're
+				 * filled with -1, so they can be
+				 * recognized as unassigned.
+				 */
+				if (search_state.last_l < reg)
+				  while (++search_state.last_l < reg)
+				    search_state.lparen[search_state.last_l] = -1;
+			      }
+			    break;
+			  }
+			  
+			case re_se_rparen:
+			  {
+			    int urhere =
+			      ((int)(search_state.test_pos.pos
+				     - search_state.test_pos.string)
+			       + search_state.test_pos.offset);
+			    int reg = rxb->se_params [effect].op1;
+			    search_state.rparen[reg] = urhere + 1;
+			    if (search_state.last_r < reg)
+			      {
+				while (++search_state.last_r < reg)
+				  search_state.rparen[search_state.last_r]
+				    = -1;
+			      }
+			    break;
+			  }
+			  
+			case re_se_backref:
+			  {
+			    int reg = rxb->se_params [effect].op1;
+			    if (   reg > search_state.last_r
+				|| search_state.rparen[reg] < 0)
+			      goto test_do_return;
+			    
+			    {
+			      int backref_status;
+			    check_backreference:
+			      backref_status
+				= back_check (&search_state.test_pos,
+					      search_state.lparen[reg],
+					      search_state.rparen[reg],
+					      search_state.translate,
+					      app_closure,
+					      stop);
+			      switch (backref_status)
+				{
+				case rx_back_check_continuation:
+				  search_state.saved_reg = reg;
+				  test_pc = rx_test_backreference_check;
+				  goto test_return_continuation;
+				resume_continuation_2:
+				  reg = search_state.saved_reg;
+				  goto check_backreference;
+				case rx_back_check_fail:
+				  /* Fail */
+				  goto test_do_return;
+				case rx_back_check_pass:
+				  /* pass --
+				   * test_pos now advanced to last
+				   * char matched by backref
+				   */
+				  break;
+				}
+			    }
+			    break;
+			  }
+			case re_se_iter:
+			  {
+			    struct rx_counter_frame * csp
+			      = ((struct rx_counter_frame *)
+				 search_state.counter_stack->sp);
+			    if (csp->val == rxb->se_params[effect].op2)
+			      goto test_do_return;
+			    else
+			      ++csp->val;
+			    break;
+			  }
+			case re_se_end_iter:
+			  {
+			    struct rx_counter_frame * csp
+			      = ((struct rx_counter_frame *)
+				 search_state.counter_stack->sp);
+			    if (csp->val < rxb->se_params[effect].op1)
+			      goto test_do_return;
+			    else
+			      {
+				struct rx_counter_frame * source = csp;
+				while (source->inherited_from)
+				  source = source->inherited_from;
+				if (!source || !source->cdr)
+				  {
+				    POP(search_state.counter_stack,
+					sizeof(struct rx_counter_frame));
+				  }
+				else
+				  {
+				    source = source->cdr;
+				    csp->val = source->val;
+				    csp->tag = source->tag;
+				    csp->cdr = 0;
+				    csp->inherited_from = source;
+				  }
+			      }
+			    break;
+			  }
+			case re_se_tv:
+			  /* is a noop */
+			  break;
+			case re_se_try:
+			case re_se_pushback:
+			case re_se_push0:
+			case re_se_pushpos:
+			case re_se_chkpos:
+			case re_se_poppos:
+			case re_se_at_dot:
+			case re_se_syntax:
+			case re_se_not_syntax:
+			case re_se_begbuf:
+			case re_se_hat:
+			case re_se_wordbeg:
+			case re_se_wordbound:
+			case re_se_notwordbound:
+			case re_se_wordend:
+			case re_se_endbuf:
+			case re_se_dollar:
+			case re_se_fail:
+			case re_floogle_flap:
+			  search_state.ret_val = 0;
+			  goto test_do_return;
+			}
+		    }
+		  el = el->cdr;
+		}
+	      /* Now the side effects are done,
+	       * so get the next instruction.
+	       * and move on.
+	       */
+	      search_state.ifr = &df->future_frame;
+	      goto restart;
+	    }
+	    
+	  case rx_backtrack_point:
+	    {
+	      /* A backtrack point indicates that we've reached a
+	       * non-determinism in the superstate NFA.  This is a
+	       * loop that exhaustively searches the possibilities.
+	       *
+	       * A backtracking strategy is used.  We keep track of what
+	       * registers are valid so we can erase side effects.
+	       *
+	       * First, make sure there is some stack space to hold 
+	       * our state.
+	       */
+	      
+	      struct rx_backtrack_frame * bf;
+	      
+	      PUSH(search_state.backtrack_stack,
+		   search_state.backtrack_frame_bytes);
+#ifdef RX_DEBUG_0
+	      ++search_state.backtrack_depth;
+#endif
+	      
+	      bf = ((struct rx_backtrack_frame *)
+		    search_state.backtrack_stack->sp);
+	      {
+		bf->stk_super = search_state.super;
+		/* We prevent the current superstate from being
+		 * deleted from the superstate cache.
+		 */
+		rx_lock_superstate (&rxb->rx, search_state.super);
+#ifdef RX_DEBUG_0
+		bf->stk_search_state.line_no = search_state.line_no;
+#endif
+		bf->stk_c = search_state.c;
+		bf->stk_test_pos = search_state.test_pos;
+		bf->stk_last_l = search_state.last_l;
+		bf->stk_last_r = search_state.last_r;
+		bf->df = ((struct rx_super_edge *)
+			  search_state.ifr->data_2)->options;
+		bf->first_df = bf->df;
+		bf->counter_stack_sp = (search_state.counter_stack
+					? search_state.counter_stack->sp
+					: 0);
+		bf->stk_test_ret = search_state.test_ret;
+		if (rxb->match_regs_on_stack)
+		  {
+		    int x;
+		    regoff_t * stk =
+		      (regoff_t *)((char *)bf + sizeof (*bf));
+		    for (x = 0; x <= search_state.last_l; ++x)
+		      stk[x] = search_state.lparen[x];
+		    stk += x;
+		    for (x = 0; x <= search_state.last_r; ++x)
+		      stk[x] = search_state.rparen[x];
+		  }
+	      }
+	      
+	      /* Here is a while loop whose body is mainly a function
+	       * call and some code to handle a return from that
+	       * function.
+	       *
+	       * From here on for the rest of `case backtrack_point' it
+	       * is unsafe to assume that the search_state copies of 
+	       * variables saved on the backtracking stack are valid
+	       * -- so read their values from the backtracking stack.
+	       *
+	       * This lets us use one generation fewer stack saves in
+	       * the call-graph of a search.
+	       */
+	      
+	    while_non_det_options:
+#ifdef RX_DEBUG_0
+	      ++search_state.lines_found;
+	      if (rx_debug_trace)
+		fprintf (stderr, "@@@ %d calls %d @@@\n",
+			 search_state.line_no, search_state.lines_found);
+	      
+	      search_state.line_no = search_state.lines_found;
+#endif
+	      
+	      if (bf->df->next_same_super_edge[0] == bf->first_df)
+		{
+		  /* This is a tail-call optimization -- we don't recurse
+		   * for the last of the possible futures.
+		   */
+		  search_state.ifr = (bf->df->effects
+				      ? &bf->df->side_effects_frame
+				      : &bf->df->future_frame);
+		  
+		  rx_unlock_superstate (&rxb->rx, search_state.super);
+		  POP(search_state.backtrack_stack,
+		      search_state.backtrack_frame_bytes);
+#ifdef RX_DEBUG
+		  --search_state.backtrack_depth;
+#endif
+		  goto restart;
+		}
+	      else
+		{
+		  if (search_state.counter_stack)
+		    {
+		      struct rx_counter_frame * old_cf
+			= ((struct rx_counter_frame *)search_state.counter_stack->sp);
+		      struct rx_counter_frame * cf;
+		      PUSH(search_state.counter_stack, sizeof (struct rx_counter_frame));
+		      cf = ((struct rx_counter_frame *)search_state.counter_stack->sp);
+		      cf->tag = old_cf->tag;
+		      cf->val = old_cf->val;
+		      cf->inherited_from = old_cf;
+		      cf->cdr = 0;
+		    }			
+		  /* `Call' this test-match block */
+		  search_state.ifr = (bf->df->effects
+				      ? &bf->df->side_effects_frame
+				      : &bf->df->future_frame);
+		  goto recurse_test_match;
+		}
+	      
+	      /* Returns in this block are accomplished by
+	       * goto test_do_return.  There are two cases.
+	       * If there is some search-stack left,
+	       * then it is a return from a `recursive' call.
+	       * If there is no search-stack left, then
+	       * we should return to the fastmap/search loop.
+	       */
+	      
+	    test_do_return:
+	      
+	      if (!search_state.backtrack_stack)
+		{
+#ifdef RX_DEBUG_0
+		  if (rx_debug_trace)
+		    fprintf (stderr, "!!! %d bails returning %d !!!\n",
+			     search_state.line_no, search_state.test_ret);
+#endif
+		  
+		  /* No more search-stack -- this test is done. */
+		  if (search_state.test_ret)
+		    goto return_from_test_match;
+		  else
+		    goto error_in_testing_match;
+		}
+	      
+	      /* Returning from a recursive call to 
+	       * the test match block:
+	       */
+	      
+	      bf = ((struct rx_backtrack_frame *)
+		    search_state.backtrack_stack->sp);
+#ifdef RX_DEBUG_0
+	      if (rx_debug_trace)
+		fprintf (stderr, "+++ %d returns %d (to %d)+++\n",
+			 search_state.line_no,
+			 search_state.test_ret,
+			 bf->stk_search_state.line_no);
+#endif
+	      
+	      while (search_state.counter_stack
+		     && (!bf->counter_stack_sp
+			 || (bf->counter_stack_sp
+			     != search_state.counter_stack->sp)))
+		{
+		  POP(search_state.counter_stack,
+		      sizeof (struct rx_counter_frame));
+		}
+	      
+	      if (search_state.test_ret == rx_test_error)
+		{
+		  POP (search_state.backtrack_stack,
+		       search_state.backtrack_frame_bytes);
+		  goto test_do_return;
+		}
+	      
+	      /* If a non-longest match was found and that is good 
+	       * enough, return immediately.
+	       */
+	      if (   (search_state.test_ret == rx_test_found_first)
+		  && search_state.first_found)
+		{
+		  rx_unlock_superstate (&rxb->rx, bf->stk_super);
+		  POP (search_state.backtrack_stack,
+		       search_state.backtrack_frame_bytes);
+		  goto test_do_return;
+		}
+	      
+	      search_state.test_ret = bf->stk_test_ret;
+	      search_state.last_l = bf->stk_last_l;
+	      search_state.last_r = bf->stk_last_r;
+	      bf->df = bf->df->next_same_super_edge[0];
+	      search_state.super = bf->stk_super;
+	      search_state.c = bf->stk_c;
+#ifdef RX_DEBUG_0
+	      search_state.line_no = bf->stk_search_state.line_no;
+#endif
+	      
+	      if (rxb->match_regs_on_stack)
+		{
+		  int x;
+		  regoff_t * stk =
+		    (regoff_t *)((char *)bf + sizeof (*bf));
+		  for (x = 0; x <= search_state.last_l; ++x)
+		    search_state.lparen[x] = stk[x];
+		  stk += x;
+		  for (x = 0; x <= search_state.last_r; ++x)
+		    search_state.rparen[x] = stk[x];
+		}
+	      
+	      {
+		int x;
+	      try_burst_2:
+		x = get_burst (&bf->stk_test_pos, app_closure, stop);
+		switch (x)
+		  {
+		  case rx_get_burst_continuation:
+		    search_state.saved_bf = bf;
+		    test_pc = rx_test_backtrack_return;
+		    goto test_return_continuation;
+		  resume_continuation_3:
+		    bf = search_state.saved_bf;
+		    goto try_burst_2;
+		  case rx_get_burst_no_more:
+		    /* Since we've been here before, it is some kind of
+		     * error that we can't return.
+		     */
+		  case rx_get_burst_error:
+		    search_state.test_ret = rx_test_internal_error;
+		    goto test_do_return;
+		  case rx_get_burst_ok:
+		    break;
+		  }
+	      }
+	      search_state.test_pos = bf->stk_test_pos;
+	      goto while_non_det_options;
+	    }
+	    
+	    
+	  case rx_cache_miss:
+	    /* Because the superstate NFA is lazily constructed,
+	     * and in fact may erode from underneath us, we sometimes
+	     * have to construct the next instruction from the hard way.
+	     * This invokes one step in the lazy-conversion.
+	     */
+	    search_state.ifr = rx_handle_cache_miss (&rxb->rx,
+						     search_state.super,
+						     search_state.c,
+						     search_state.ifr->data_2);
+	    if (!search_state.ifr)
+	      {
+		search_state.test_ret = rx_test_internal_error;
+		goto test_do_return;
+	      }
+	    goto restart;
+	    
+	  case rx_backtrack:
+	    /* RX_BACKTRACK means that we've reached the empty
+	     * superstate, indicating that match can't succeed
+	     * from this point.
+	     */
+	    goto test_do_return;
+	    
+	  case rx_next_char:
+	  case rx_error_inx:
+	  case rx_num_instructions:
+	    search_state.ret_val = 0;
+	    goto test_do_return;
+	  }
+	goto pseudo_while_1;
+      }
+    
+    /* Healthy exits from the test-match loop do a 
+     * `goto return_from_test_match'   On the other hand, 
+     * we might end up here.
+     */
+  error_in_testing_match:
+    test_state = rx_test_error;
+    goto test_returns_to_search;
+    
+    /***** fastmap/search loop body
+     *	      considering the results testing for a match
+     */
+    
+  return_from_test_match:
+    
+    if (search_state.best_last_l >= 0)
+      {
+	if (regs && (regs->start != search_state.best_lparen))
+	  {
+	    bcopy (search_state.best_lparen, regs->start,
+		   regs->num_regs * sizeof (int));
+	    bcopy (search_state.best_rparen, regs->end,
+		   regs->num_regs * sizeof (int));
+	  }
+	if (regs && !rxb->no_sub)
+	  {
+	    int q;
+	    int bound = (regs->num_regs > search_state.num_regs
+			 ? regs->num_regs
+			 : search_state.num_regs);
+	    regoff_t * s = regs->start;
+	    regoff_t * e = regs->end;
+	    for (q = search_state.best_last_l + 1;  q < bound; ++q)
+	      s[q] = e[q] = -1;
+	  }
+	search_state.ret_val = search_state.best_lparen[0];
+	test_state = rx_test_ok;
+	goto test_returns_to_search;
+      }
+    else
+      {
+	test_state = rx_test_fail;
+	goto test_returns_to_search;
+      }
+    
+  test_return_continuation:
+    search_state.test_match_resume_pt = test_pc;
+    test_state = rx_test_continuation;
+    goto test_returns_to_search;
+  }
+}
+
+
+
+#endif /* RX_WANT_RX_DEFS */
+
+
+
+#else /* RX_WANT_SE_DEFS */
+  /* Integers are used to represent side effects.
+   *
+   * Simple side effects are given negative integer names by these enums.
+   * 
+   * Non-negative names are reserved for complex effects.
+   *
+   * Complex effects are those that take arguments.  For example, 
+   * a register assignment associated with a group is complex because
+   * it requires an argument to tell which group is being matched.
+   * 
+   * The integer name of a complex effect is an index into rxb->se_params.
+   */
+ 
+  RX_DEF_SE(1, re_se_try, = -1)		/* Epsilon from start state */
+
+  RX_DEF_SE(0, re_se_pushback, = re_se_try - 1)
+  RX_DEF_SE(0, re_se_push0, = re_se_pushback -1)
+  RX_DEF_SE(0, re_se_pushpos, = re_se_push0 - 1)
+  RX_DEF_SE(0, re_se_chkpos, = re_se_pushpos -1)
+  RX_DEF_SE(0, re_se_poppos, = re_se_chkpos - 1)
+
+  RX_DEF_SE(1, re_se_at_dot, = re_se_poppos - 1)	/* Emacs only */
+  RX_DEF_SE(0, re_se_syntax, = re_se_at_dot - 1) /* Emacs only */
+  RX_DEF_SE(0, re_se_not_syntax, = re_se_syntax - 1) /* Emacs only */
+
+  RX_DEF_SE(1, re_se_begbuf, = re_se_not_syntax - 1) /* match beginning of buffer */
+  RX_DEF_SE(1, re_se_hat, = re_se_begbuf - 1) /* match beginning of line */
+
+  RX_DEF_SE(1, re_se_wordbeg, = re_se_hat - 1) 
+  RX_DEF_SE(1, re_se_wordbound, = re_se_wordbeg - 1)
+  RX_DEF_SE(1, re_se_notwordbound, = re_se_wordbound - 1)
+
+  RX_DEF_SE(1, re_se_wordend, = re_se_notwordbound - 1)
+  RX_DEF_SE(1, re_se_endbuf, = re_se_wordend - 1)
+
+  /* This fails except at the end of a line. 
+   * It deserves to go here since it is typicly one of the last steps 
+   * in a match.
+   */
+  RX_DEF_SE(1, re_se_dollar, = re_se_endbuf - 1)
+
+  /* Simple effects: */
+  RX_DEF_SE(1, re_se_fail, = re_se_dollar - 1)
+
+  /* Complex effects.  These are used in the 'se' field of 
+   * a struct re_se_params.  Indexes into the se array
+   * are stored as instructions on nfa edges.
+   */
+  RX_DEF_CPLX_SE(1, re_se_win, = 0)
+  RX_DEF_CPLX_SE(1, re_se_lparen, = re_se_win + 1)
+  RX_DEF_CPLX_SE(1, re_se_rparen, = re_se_lparen + 1)
+  RX_DEF_CPLX_SE(0, re_se_backref, = re_se_rparen + 1)
+  RX_DEF_CPLX_SE(0, re_se_iter, = re_se_backref + 1) 
+  RX_DEF_CPLX_SE(0, re_se_end_iter, = re_se_iter + 1)
+  RX_DEF_CPLX_SE(0, re_se_tv, = re_se_end_iter + 1)
+
+#endif
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/simplefrenchstem.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/simplefrenchstem.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/simplefrenchstem.c	(revision 10506)
@@ -0,0 +1,72 @@
+/**************************************************************************
+ *
+ * simplefrenchstem.c -- a simple french stemmer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "simplefrenchstem.h"
+
+
+
+/* =========================================================================
+ * Function: simplefrenchstem
+ * Description: a simple french stemmer
+ * Input: a word string with the length in the first byte
+ * Output: the stemmed word
+ * ========================================================================= */
+
+void simplefrenchstem (unsigned char *word) {      
+  unsigned short out[256]; /* temp space */
+  unsigned short *wordstart; /* points to first letter of word */
+  int last;                  /* last points to the last character */
+
+  /* decode */
+  utf8_word_to_unicode (word, out, 255);
+  wordstart = out + 1;
+  last = out[0]-1;
+  
+
+  if (last > 4) {
+    if (wordstart[last]=='x') {
+      if (wordstart[last-1]=='u' && wordstart[last-2]=='a') {
+	wordstart[last-1]='l';
+      }
+      last--;
+
+    } else {
+      if (last>=0 && wordstart[last]=='s') last--;
+      if (last>=0 && wordstart[last]=='r') last--;
+      if (last>=0 && wordstart[last]=='e') last--;
+
+      /* letter with accent e + ' -- there are two possible encodings  */
+      if (last>=0 && wordstart[last]==0xe9) { 
+	last--;
+      } else if (last>=1 && wordstart[last-1]=='e' && wordstart[last]==0x301) {
+	last -= 2; 
+      }
+
+      if (last >= 1 && wordstart[last]==wordstart[last-1]) last--;
+    }  /* end else */
+
+    out[0] = (unsigned char)(last+1);
+  } /* end if (len > 4) */
+
+  /* re-code, make sure the result is not longer than the input */
+  unicode_to_utf8_word (out, word, word[0]+1);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/simplefrenchstem.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/simplefrenchstem.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/simplefrenchstem.h	(revision 10506)
@@ -0,0 +1,50 @@
+/**************************************************************************
+ *
+ * simplefrenchstem.h -- a simple french stemmer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:04  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/25 07:55:37  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/24 06:37:53  rjmcnab
+
+   Incorporated the french stemmer better.
+
+
+ */
+
+#ifndef SIMPLEFRENCHSTEM_H
+#define SIMPLEFRENCHSTEM_H
+
+void simplefrenchstem (unsigned char *word);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/sptree.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/sptree.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/sptree.c	(revision 10506)
@@ -0,0 +1,391 @@
+/**************************************************************************
+ *
+ * sptree.c -- Splay tree code
+ * Copyright (C) 1994  Gary Eddy, Alistair Moffat and Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#include	"sysfuncs.h"
+#include	"sptree.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:04  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:45  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:50  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#define TRACE(w)
+
+#define POOL_SIZE 1024
+
+
+typedef struct node_rec node;
+
+struct node_rec
+  {
+    node *left, *rght;
+    node *par;
+    char *datsun;
+  };
+
+struct pool
+  {
+    int length, pos;
+    struct pool *next;
+    node nodes[POOL_SIZE];
+  };
+
+static node *SP_splay ();
+
+#define	CNULL	((char *) NULL)
+#define	NNULL	((node *) NULL)
+#define	SNULL	((Splay_Tree *) NULL)
+
+
+/*
+ *    createset():
+ *              allocates memory for and initialises a set.
+ *
+ *      Accesses outside variables:     none
+ *
+ *      Return value...:                none
+ */
+
+Splay_Tree *
+SP_createset (int (*cmp) (void *, void *))
+{
+  Splay_Tree *S;
+
+  if (!(S = (Splay_Tree *) malloc (sizeof (Splay_Tree))))
+    return (SNULL);
+  S->cmp = cmp;
+  S->root = CNULL;
+  S->no_of_items = 0;
+  S->mem_in_use = sizeof (Splay_Tree);
+  S->pool = NULL;
+  S->pool_chunks = 1024;
+  return S;
+}				/* createset() */
+
+
+
+static node *
+SP_get_node (Splay_Tree * S)
+{
+  struct pool *p = S->pool;
+  if (!p || p->pos == p->length)
+    {
+      p = malloc (sizeof (struct pool));
+      if (!p)
+	return NULL;
+      S->mem_in_use += sizeof (struct pool);
+      p->length = POOL_SIZE;
+      p->pos = 0;
+      p->next = S->pool;
+      S->pool = p;
+    }
+  return &(p->nodes[p->pos++]);
+}
+
+
+
+/*
+ *    SP_freeset():
+ *              free the memory allocated to a splay tree. Note this Does not
+ *              free the data in the tree you must do this yourself.
+ *
+ *      Accesses outside variables:     none
+ *
+ *      Return value...:                none
+ */
+
+void 
+SP_freeset (Splay_Tree * S)
+{
+  while (S->pool)
+    {
+      struct pool *p = S->pool;
+      S->pool = p->next;
+      free (p);
+    }
+  free (S);
+}
+
+
+/*
+ *    insert():
+ *              inserts the item given into the set given in the order
+ *              specified by the comparison function in the set 
+ *              definition.
+ *
+ *      Accesses outside variables:     none
+ *
+ *      Return value...:                none
+ */
+
+
+void *
+SP_insert (void *item, Splay_Tree * S)
+{
+  int dir = 0;
+  register node *curr, *prev;
+  node *tmp;
+
+  prev = NNULL;
+  curr = (node *) S->root;
+  for (; curr;)
+    {
+      prev = curr;
+      dir = S->cmp (item, curr->datsun);
+      if (dir < 0)
+	curr = curr->left;
+      else
+	curr = curr->rght;
+    }
+  if (!(tmp = SP_get_node (S)))
+    return NULL;
+  tmp->datsun = item;
+
+  if (prev == NNULL)
+    S->root = (char *) tmp;
+  else if (dir < 0)
+    prev->left = tmp;
+  else
+    prev->rght = tmp;
+
+  tmp->par = prev;
+  tmp->left = NNULL;
+  tmp->rght = NNULL;
+  S->no_of_items++;
+  S->root = (char *) SP_splay (tmp);
+  return (tmp->datsun);
+}				/* insert() */
+
+/*
+ *    get_first():
+ *              returns a pointer to the first item in the set. If the set 
+ *              is empty a NULL pointer is returned.
+ *
+ *      Accesses outside variables:     none
+ */
+
+void *
+SP_get_first (Splay_Tree * S)
+{
+  node *curr, *prev;
+
+  for (curr = (node *) S->root, prev = NNULL; curr;
+       prev = curr, curr = curr->left)
+    ;				/* NULLBODY */
+
+  if (prev)
+    S->root = (char *) SP_splay (prev);
+  return (prev ? prev->datsun : CNULL);
+}				/* get_first() */
+
+/*
+ *    get_next():
+ *              returns the in-order successor of the currently fingered
+ *              item of the set. If no item is fingered or if there is 
+ *              no in-order successor a NULL pointer is returned.
+ *
+ *      Accesses outside variables:     none
+ */
+
+void *
+SP_get_next (Splay_Tree * S)
+{
+  node *curr, *prev;
+
+  curr = (node *) S->root;
+  if (!curr || !curr->rght)
+    return (CNULL);
+
+  for (prev = curr, curr = curr->rght; curr;
+       prev = curr, curr = curr->left)
+    ;				/* NULLBODY */
+
+  if (prev)
+    S->root = (char *) SP_splay (prev);
+  return (prev ? prev->datsun : CNULL);
+}				/* get_next() */
+
+/*
+ *    deletemin():
+ *              removes the first element in the set and returns a
+ *              pointer to it. If the set is empty a NULL pointer 
+ *              is returned.
+ *
+ *      Accesses outside variables:     none
+ */
+
+void *
+SP_deletemin (Splay_Tree * S)
+{
+  node *tmp;
+  char *dat;
+
+  dat = SP_get_first (S);
+  if (dat)
+    {
+      tmp = (node *) S->root;
+      S->root = (char *) tmp->rght;
+      if (S->root)
+	((node *) S->root)->par = NULL;
+    }
+  S->no_of_items--;
+  return dat;
+}				/* deletemin() */
+
+
+/*
+ *    member():
+ *              searches the given set for an item which matches (has
+ *              the same key) and returns a pointer to a copy of that item.
+ *              If no matching item is found a NULL pointer is 
+ *              returned.
+ *
+ *      Accesses outside variables:     none
+ */
+
+void *
+SP_member (void *dat, Splay_Tree * S)
+{
+  register node *curr;
+  register int dir;
+  static int calls = 0;
+
+  TRACE ("in member");
+  for (curr = (node *) S->root; curr;)
+    {
+      TRACE ("call to cmp");
+      dir = S->cmp (dat, curr->datsun);
+      TRACE ("out of cmp");
+      if (dir < 0)
+	curr = curr->left;
+      else if (dir > 0)
+	curr = curr->rght;
+      else
+	{
+	  /* splay occasionaly to speed up execution */
+	  if ((calls++ % 4) == 0 && curr)
+	    S->root = (char *) SP_splay (curr);
+	  TRACE ("out of member");
+	  return (curr->datsun);
+	}
+    }
+  TRACE ("out of member");
+  return (CNULL);
+}				/* member() */
+
+#define	ROTATEL(p,q) 					\
+	do{						\
+		p->par = q->par;			\
+		q->par = p;				\
+		q->rght = p->left;			\
+		if(q->rght)				\
+			q->rght->par = q;		\
+		p->left = q;				\
+		if(p->par)				\
+			if(q == p->par->left)		\
+				p->par->left = p;	\
+			else				\
+				p->par->rght = p;	\
+	}while(0)
+
+#define	ROTATER(p,q) 					\
+	do{						\
+		p->par = q->par;			\
+		q->par = p;				\
+		q->left = p->rght;			\
+		if(q->left)				\
+			q->left->par = q;		\
+		p->rght = q;				\
+		if(p->par)				\
+			if(q == p->par->left)		\
+				p->par->left = p;	\
+			else				\
+				p->par->rght = p;	\
+	}while(0)
+
+
+/*
+ *    splay():
+ *              i
+ *
+ *      Accesses outside variables:     i
+ *
+ *      Return value...:                i
+ */
+
+static node *
+SP_splay (p)
+     register node *p;
+{
+  register node *q, *g;
+
+  q = p->par;
+  /* splay the tree about p */
+  while (q != NNULL)
+    {
+      g = q->par;
+      if (p == q->left)
+	{
+	  if (g == NNULL)
+	    ROTATER (p, q);
+	  else if (q == g->left)
+	    {
+	      ROTATER (q, g);
+	      ROTATER (p, q);
+	    }
+	  else
+	    {
+	      ROTATER (p, q);
+	      ROTATEL (p, g);
+	    }
+	}
+      else
+	{
+	  if (g == NNULL)
+	    ROTATEL (p, q);
+	  else if (q == g->rght)
+	    {
+	      ROTATEL (q, g);
+	      ROTATEL (p, q);
+	    }
+	  else
+	    {
+	      ROTATEL (p, q);
+	      ROTATER (p, g);
+	    }
+	}
+      q = p->par;
+    }
+  return (p);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/sptree.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/sptree.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/sptree.h	(revision 10506)
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * sptree.h -- Splay tree code
+ * Copyright (C) 1994  Gary Eddy and Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef SPTREE_H
+#define SPTREE_H
+
+typedef struct set_rec Splay_Tree;
+
+struct set_rec
+  {
+    int no_of_items;
+    unsigned long mem_in_use;
+    int (*cmp) (void *, void *);
+    void *root;
+    void *pool;
+    int pool_chunks;
+  };
+
+Splay_Tree *SP_createset (int (*cmp) (void *, void *));
+void *SP_insert (void *item, Splay_Tree * S);
+void *SP_get_first (Splay_Tree * S);
+void *SP_get_next (Splay_Tree * S);
+void *SP_deletemin (Splay_Tree * S);
+void *SP_member (void *dat, Splay_Tree * S);
+void SP_freeset (Splay_Tree * S);
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/strcasecmp.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/strcasecmp.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/strcasecmp.c	(revision 10506)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific written prior permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcasecmp.c	5.5 (Berkeley) 11/24/87";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char charmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+int
+strcasecmp(s1, s2)
+    char *s1, *s2;
+{
+    register unsigned char u1, u2;
+
+    for (;;) {
+	u1 = (unsigned char) *s1++;
+	u2 = (unsigned char) *s2++;
+	if (charmap[u1] != charmap[u2]) {
+	    return charmap[u1] - charmap[u2];
+	}
+	if (u1 == '\0') {
+	    return 0;
+	}
+    }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/strstr.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/strstr.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/strstr.c	(revision 10506)
@@ -0,0 +1,44 @@
+/* strstr.c -- return the offset of one string within another
+   Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by Mike Rendell <michael@cs.mun.ca>.  */
+
+/* Return the starting address of string S2 in S1;
+   return 0 if it is not found. */
+
+char *
+strstr (s1, s2)
+     char *s1;
+     char *s2;
+{
+  int i;
+  char *p1;
+  char *p2;
+  char *s = s1;
+
+  for (p2 = s2, i = 0; *s; p2 = s2, i++, s++)
+    {
+      for (p1 = s; *p1 && *p2 && *p1 == *p2; p1++, p2++)
+	;
+      if (!*p2)
+	break;
+    }
+  if (!*p2)
+    return s1 + i;
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/timing.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/timing.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/timing.c	(revision 10506)
@@ -0,0 +1,234 @@
+/**************************************************************************
+ *
+ * timing.c -- Program timing routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:05  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:32:49  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/08/22  00:24:53  tes
+   * Initial placement under CVS.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "timing.h"
+
+
+/*
+ * Return the time in seconds since 00:00:00 GMT, Jan. 1, 1970 to the
+ * best precision possible
+ *
+ */
+double 
+RealTime (void)
+{
+  return ((double) time (NULL));
+}
+
+
+
+/*
+ * Return the amount of system and user CPU used by the process to date to 
+ * the best precision possible. If user is non-null then it is initialised to 
+ * the user time. If sys is non-null then it is initialised to the system time.
+ *
+ */
+double 
+CPUTime (double *user, double *sys)
+{
+
+#if defined(HAVE_TIMES)
+
+  struct tms buffer;
+  static double clk_tck = 0;
+  double u, s;
+
+  times (&buffer);
+
+  if (clk_tck == 0)
+    clk_tck = CLK_TCK;
+
+  u = (double) buffer.tms_utime / clk_tck;
+  s = (double) buffer.tms_stime / clk_tck;
+  if (user)
+    *user = u;
+  if (sys)
+    *sys = s;
+  return u + s;
+
+#elif defined(HAVE_GETRUSAGE)
+
+  struct rusage ruse;
+  getrusage (RUSAGE_SELF, &ruse);
+  if (user)
+    *user = (double) ruse.ru_utime.tv_sec +
+      (double) ruse.ru_utime.tv_usec / 1000000;
+  if (sys)
+    *sys = (double) ruse.ru_stime.tv_sec +
+      (double) ruse.ru_stime.tv_usec / 1000000;
+  return ((double) ruse.ru_utime.tv_sec + ruse.ru_stime.tv_sec +
+	((double) ruse.ru_utime.tv_usec + ruse.ru_stime.tv_usec) / 1000000);
+
+#else
+
+  /* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  if (user) *user = 0.0;
+  if (sys) *sys = 0.0;
+  return 0.0;
+#else
+  -->Can NOT find a system time routine to use ! !!
+#endif  /* __WIN32__ */
+
+#endif
+
+}
+
+
+
+
+/*
+ * Get the Real and CPU time and store them in a ProgTime structure
+ */
+void 
+GetTime (ProgTime * StartTime)
+{
+  StartTime->RealTime = RealTime ();
+  StartTime->CPUTime = CPUTime (NULL, NULL);
+}
+
+
+
+
+/*
+ * Display the Real and CPU time elapsed since the StartTime anf FinishTime 
+ * structures were initialised. If FinishTime is NULL then FinishTime is
+ * Now.
+ */
+char *
+ElapsedTime (ProgTime * StartTime,
+	     ProgTime * FinishTime)
+{
+  static char buf[50];
+  double Real, CPU, hour, min, sec;
+  if (!FinishTime)
+    {
+      Real = RealTime () - StartTime->RealTime;
+      CPU = CPUTime (NULL, NULL) - StartTime->CPUTime;
+    }
+  else
+    {
+      Real = FinishTime->RealTime - StartTime->RealTime;
+      CPU = FinishTime->CPUTime - StartTime->CPUTime;
+    }
+  hour = floor (CPU / 3600);
+  min = floor ((CPU - hour * 3600) / 60);
+  sec = CPU - hour * 3600 - min * 60;
+  sprintf (buf, "%02.0f:%02.0f:%05.2f cpu, %02d:%02d:%02d elapsed.",
+	   hour, min, sec,
+	   ((int) ceil (Real)) / 3600,
+	   (((int) ceil (Real)) % 3600) / 60, ((int) ceil (Real)) % 60);
+  return (buf);
+}
+
+
+#define MILLION 1000000
+
+/* ===============================================================================
+ * Function: cputime_string
+ * Description:
+ *      Prints out given cpu time into a string buffer.
+ * Input: cpu-time in clock_t or timeval format
+ * Output: pointer to internal buffer 
+ * =============================================================================== */
+
+#ifdef HAVE_TIMES
+char *
+cputime_string (clock_t clk)
+{
+  static char buf[15];
+  double CPU, hour, min, sec;
+
+  CPU = (double) clk / (double) CLK_TCK;
+  hour = floor (CPU / 3600);
+  min = floor ((CPU - hour * 3600) / 60);
+  sec = CPU - hour * 3600 - min * 60;
+  sprintf (buf, "%02.0f:%02.0f:%05.2f", hour, min, sec);
+  return (buf);
+}
+#else
+char *
+cputime_string (struct timeval *t)
+{
+  static char buf[15];
+  double CPU, hour, min, sec;
+
+  CPU = (double) t->tv_sec + (double) t->tv_usec / MILLION;
+  hour = floor (CPU / 3600);
+  min = floor ((CPU - hour * 3600) / 60);
+  sec = CPU - hour * 3600 - min * 60;
+  sprintf (buf, "%02.0f:%02.0f:%05.2f", hour, min, sec);
+  return (buf);
+}
+#endif
+
+
+
+/* ===============================================================================
+ * Function: time_normalise
+ * Description:
+ *      If the micro-second component is negative or over a million,
+ *      then must take the over/under flow and add it to the second component.
+ * Usage:
+ *      Use this routine when you have just been doing straight addition and
+ *      subtraction on the micro-second component. For this could lead to a
+ *      negative number or over a million.
+ *
+ * =============================================================================== */
+
+#ifndef HAVE_TIMES
+
+#ifndef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+static 
+#endif
+void
+time_normalise (struct timeval *t)
+{
+  while (t->tv_usec < 0)
+    {
+      t->tv_usec += MILLION;
+      t->tv_sec--;
+    }
+  while (t->tv_usec > MILLION)
+    {
+      t->tv_usec -= MILLION;
+      t->tv_sec++;
+    }
+}
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/timing.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/timing.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/timing.h	(revision 10506)
@@ -0,0 +1,75 @@
+/**************************************************************************
+ *
+ * timing.h -- Program timing routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_TIMING
+#define H_TIMING
+
+
+#ifdef HAVE_TIMES
+# if TIME_WITH_SYS_TIME
+#  include <sys/times.h>
+#  include <time.h>
+#  ifndef CLK_TCK
+#   define CLK_TCK sysconf(_SC_CLK_TCK)
+#  endif
+# else
+#  if HAVE_SYS_TIME_H
+#   include <sys/time.h>
+#  else
+#   include <time.h>
+#  endif
+# endif
+#else
+/* [RPAP - Feb 97: WIN32 Port] */
+# ifdef __WIN32__
+   struct timeval { long tv_sec, tv_usec; };
+# else
+#  include <sys/time.h>
+#  include <sys/resource.h>
+# endif
+#endif
+
+
+typedef struct
+  {
+    double RealTime, CPUTime;
+  }
+ProgTime;
+
+double RealTime (void);
+
+double CPUTime (double *user, double *sys);
+
+void GetTime (ProgTime * StartTime);
+
+/* FinishTime may be NULL */
+char *ElapsedTime (ProgTime * StartTime, ProgTime * FinishTime);
+
+#ifdef HAVE_TIMES
+char *cputime_string (clock_t clk);
+#else
+void time_normalise (struct timeval *t);
+char *cputime_string (struct timeval *t);
+#endif
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/unitool.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/unitool.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/unitool.c	(revision 10506)
@@ -0,0 +1,1756 @@
+#include "unitool.h"
+#include "sysfuncs.h"
+
+
+/* unicode_cat_data is a combination of the letter, digit, and
+ * space information in a form that is quick to look up.
+ * The information about each byte is stored in two bits
+ *
+ * 00 - neither letter, digit or space
+ * 01 - letter
+ * 10 - space
+ * 11 - digit
+ *
+ * You can test for letter | space by looking at the right
+ * column
+ */
+unsigned long *unicode_cat_data=NULL;
+
+
+typedef struct unidecompose {
+  unsigned short ch;
+  unsigned short str[3];
+} unidecompose;
+
+typedef struct unirelate {
+  unsigned short ch1;
+  unsigned short ch2;
+} unirelate;
+
+typedef struct unirange {
+  unsigned short first;
+  unsigned short last;
+} unirange;
+
+
+
+/* This decomposition data only includes canonical decompositional
+ * characters.  Any unused bytes are set to 0x0. */
+
+#define NUM_DECOMPOSE_INFO 1269
+static const unidecompose decompose_info[NUM_DECOMPOSE_INFO] = {
+  {0xC0,0x41,0x300,0x0}, {0xC1,0x41,0x301,0x0}, {0xC2,0x41,0x302,0x0}, 
+  {0xC3,0x41,0x303,0x0}, {0xC4,0x41,0x308,0x0}, {0xC5,0x41,0x30A,0x0}, 
+  {0xC7,0x43,0x327,0x0}, {0xC8,0x45,0x300,0x0}, {0xC9,0x45,0x301,0x0}, 
+  {0xCA,0x45,0x302,0x0}, {0xCB,0x45,0x308,0x0}, {0xCC,0x49,0x300,0x0}, 
+  {0xCD,0x49,0x301,0x0}, {0xCE,0x49,0x302,0x0}, {0xCF,0x49,0x308,0x0}, 
+  {0xD1,0x4E,0x303,0x0}, {0xD2,0x4F,0x300,0x0}, {0xD3,0x4F,0x301,0x0}, 
+  {0xD4,0x4F,0x302,0x0}, {0xD5,0x4F,0x303,0x0}, {0xD6,0x4F,0x308,0x0}, 
+  {0xD9,0x55,0x300,0x0}, {0xDA,0x55,0x301,0x0}, {0xDB,0x55,0x302,0x0}, 
+  {0xDC,0x55,0x308,0x0}, {0xDD,0x59,0x301,0x0}, {0xE0,0x61,0x300,0x0}, 
+  {0xE1,0x61,0x301,0x0}, {0xE2,0x61,0x302,0x0}, {0xE3,0x61,0x303,0x0}, 
+  {0xE4,0x61,0x308,0x0}, {0xE5,0x61,0x30A,0x0}, {0xE7,0x63,0x327,0x0}, 
+  {0xE8,0x65,0x300,0x0}, {0xE9,0x65,0x301,0x0}, {0xEA,0x65,0x302,0x0}, 
+  {0xEB,0x65,0x308,0x0}, {0xEC,0x69,0x300,0x0}, {0xED,0x69,0x301,0x0}, 
+  {0xEE,0x69,0x302,0x0}, {0xEF,0x69,0x308,0x0}, {0xF1,0x6E,0x303,0x0}, 
+  {0xF2,0x6F,0x300,0x0}, {0xF3,0x6F,0x301,0x0}, {0xF4,0x6F,0x302,0x0}, 
+  {0xF5,0x6F,0x303,0x0}, {0xF6,0x6F,0x308,0x0}, {0xF9,0x75,0x300,0x0}, 
+  {0xFA,0x75,0x301,0x0}, {0xFB,0x75,0x302,0x0}, {0xFC,0x75,0x308,0x0}, 
+  {0xFD,0x79,0x301,0x0}, {0xFF,0x79,0x308,0x0}, {0x100,0x41,0x304,0x0}, 
+  {0x101,0x61,0x304,0x0}, {0x102,0x41,0x306,0x0}, {0x103,0x61,0x306,0x0}, 
+  {0x104,0x41,0x328,0x0}, {0x105,0x61,0x328,0x0}, {0x106,0x43,0x301,0x0}, 
+  {0x107,0x63,0x301,0x0}, {0x108,0x43,0x302,0x0}, {0x109,0x63,0x302,0x0}, 
+  {0x10A,0x43,0x307,0x0}, {0x10B,0x63,0x307,0x0}, {0x10C,0x43,0x30C,0x0}, 
+  {0x10D,0x63,0x30C,0x0}, {0x10E,0x44,0x30C,0x0}, {0x10F,0x64,0x30C,0x0}, 
+  {0x112,0x45,0x304,0x0}, {0x113,0x65,0x304,0x0}, {0x114,0x45,0x306,0x0}, 
+  {0x115,0x65,0x306,0x0}, {0x116,0x45,0x307,0x0}, {0x117,0x65,0x307,0x0}, 
+  {0x118,0x45,0x328,0x0}, {0x119,0x65,0x328,0x0}, {0x11A,0x45,0x30C,0x0}, 
+  {0x11B,0x65,0x30C,0x0}, {0x11C,0x47,0x302,0x0}, {0x11D,0x67,0x302,0x0}, 
+  {0x11E,0x47,0x306,0x0}, {0x11F,0x67,0x306,0x0}, {0x120,0x47,0x307,0x0}, 
+  {0x121,0x67,0x307,0x0}, {0x122,0x47,0x327,0x0}, {0x123,0x67,0x327,0x0}, 
+  {0x124,0x48,0x302,0x0}, {0x125,0x68,0x302,0x0}, {0x128,0x49,0x303,0x0}, 
+  {0x129,0x69,0x303,0x0}, {0x12A,0x49,0x304,0x0}, {0x12B,0x69,0x304,0x0}, 
+  {0x12C,0x49,0x306,0x0}, {0x12D,0x69,0x306,0x0}, {0x12E,0x49,0x328,0x0}, 
+  {0x12F,0x69,0x328,0x0}, {0x130,0x49,0x307,0x0}, {0x134,0x4A,0x302,0x0}, 
+  {0x135,0x6A,0x302,0x0}, {0x136,0x4B,0x327,0x0}, {0x137,0x6B,0x327,0x0}, 
+  {0x139,0x4C,0x301,0x0}, {0x13A,0x6C,0x301,0x0}, {0x13B,0x4C,0x327,0x0}, 
+  {0x13C,0x6C,0x327,0x0}, {0x13D,0x4C,0x30C,0x0}, {0x13E,0x6C,0x30C,0x0}, 
+  {0x143,0x4E,0x301,0x0}, {0x144,0x6E,0x301,0x0}, {0x145,0x4E,0x327,0x0}, 
+  {0x146,0x6E,0x327,0x0}, {0x147,0x4E,0x30C,0x0}, {0x148,0x6E,0x30C,0x0}, 
+  {0x14C,0x4F,0x304,0x0}, {0x14D,0x6F,0x304,0x0}, {0x14E,0x4F,0x306,0x0}, 
+  {0x14F,0x6F,0x306,0x0}, {0x150,0x4F,0x30B,0x0}, {0x151,0x6F,0x30B,0x0}, 
+  {0x154,0x52,0x301,0x0}, {0x155,0x72,0x301,0x0}, {0x156,0x52,0x327,0x0}, 
+  {0x157,0x72,0x327,0x0}, {0x158,0x52,0x30C,0x0}, {0x159,0x72,0x30C,0x0}, 
+  {0x15A,0x53,0x301,0x0}, {0x15B,0x73,0x301,0x0}, {0x15C,0x53,0x302,0x0}, 
+  {0x15D,0x73,0x302,0x0}, {0x15E,0x53,0x327,0x0}, {0x15F,0x73,0x327,0x0}, 
+  {0x160,0x53,0x30C,0x0}, {0x161,0x73,0x30C,0x0}, {0x162,0x54,0x327,0x0}, 
+  {0x163,0x74,0x327,0x0}, {0x164,0x54,0x30C,0x0}, {0x165,0x74,0x30C,0x0}, 
+  {0x168,0x55,0x303,0x0}, {0x169,0x75,0x303,0x0}, {0x16A,0x55,0x304,0x0}, 
+  {0x16B,0x75,0x304,0x0}, {0x16C,0x55,0x306,0x0}, {0x16D,0x75,0x306,0x0}, 
+  {0x16E,0x55,0x30A,0x0}, {0x16F,0x75,0x30A,0x0}, {0x170,0x55,0x30B,0x0}, 
+  {0x171,0x75,0x30B,0x0}, {0x172,0x55,0x328,0x0}, {0x173,0x75,0x328,0x0}, 
+  {0x174,0x57,0x302,0x0}, {0x175,0x77,0x302,0x0}, {0x176,0x59,0x302,0x0}, 
+  {0x177,0x79,0x302,0x0}, {0x178,0x59,0x308,0x0}, {0x179,0x5A,0x301,0x0}, 
+  {0x17A,0x7A,0x301,0x0}, {0x17B,0x5A,0x307,0x0}, {0x17C,0x7A,0x307,0x0}, 
+  {0x17D,0x5A,0x30C,0x0}, {0x17E,0x7A,0x30C,0x0}, {0x1A0,0x4F,0x31B,0x0}, 
+  {0x1A1,0x6F,0x31B,0x0}, {0x1AF,0x55,0x31B,0x0}, {0x1B0,0x75,0x31B,0x0}, 
+  {0x1CD,0x41,0x30C,0x0}, {0x1CE,0x61,0x30C,0x0}, {0x1CF,0x49,0x30C,0x0}, 
+  {0x1D0,0x69,0x30C,0x0}, {0x1D1,0x4F,0x30C,0x0}, {0x1D2,0x6F,0x30C,0x0}, 
+  {0x1D3,0x55,0x30C,0x0}, {0x1D4,0x75,0x30C,0x0}, {0x1D5,0xDC,0x304,0x0}, 
+  {0x1D6,0xFC,0x304,0x0}, {0x1D7,0xDC,0x301,0x0}, {0x1D8,0xFC,0x301,0x0}, 
+  {0x1D9,0xDC,0x30C,0x0}, {0x1DA,0xFC,0x30C,0x0}, {0x1DB,0xDC,0x300,0x0}, 
+  {0x1DC,0xFC,0x300,0x0}, {0x1DE,0xC4,0x304,0x0}, {0x1DF,0xE4,0x304,0x0}, 
+  {0x1E0,0x41,0x307,0x304}, {0x1E1,0x61,0x307,0x304}, {0x1E2,0xC6,0x304,0x0}, 
+  {0x1E3,0xE6,0x304,0x0}, {0x1E6,0x47,0x30C,0x0}, {0x1E7,0x67,0x30C,0x0}, 
+  {0x1E8,0x4B,0x30C,0x0}, {0x1E9,0x6B,0x30C,0x0}, {0x1EA,0x4F,0x328,0x0}, 
+  {0x1EB,0x6F,0x328,0x0}, {0x1EC,0x1EA,0x304,0x0}, {0x1ED,0x1EB,0x304,0x0}, 
+  {0x1EE,0x1B7,0x30C,0x0}, {0x1EF,0x292,0x30C,0x0}, {0x1F0,0x6A,0x30C,0x0}, 
+  {0x1F4,0x47,0x301,0x0}, {0x1F5,0x67,0x301,0x0}, {0x1FA,0xC5,0x301,0x0}, 
+  {0x1FB,0xE5,0x301,0x0}, {0x1FC,0xC6,0x301,0x0}, {0x1FD,0xE6,0x301,0x0}, 
+  {0x1FE,0xD8,0x301,0x0}, {0x1FF,0xF8,0x301,0x0}, {0x200,0x41,0x30F,0x0}, 
+  {0x201,0x61,0x30F,0x0}, {0x202,0x41,0x311,0x0}, {0x203,0x61,0x311,0x0}, 
+  {0x204,0x45,0x30F,0x0}, {0x205,0x65,0x30F,0x0}, {0x206,0x45,0x311,0x0}, 
+  {0x207,0x65,0x311,0x0}, {0x208,0x49,0x30F,0x0}, {0x209,0x69,0x30F,0x0}, 
+  {0x20A,0x49,0x311,0x0}, {0x20B,0x69,0x311,0x0}, {0x20C,0x4F,0x30F,0x0}, 
+  {0x20D,0x6F,0x30F,0x0}, {0x20E,0x4F,0x311,0x0}, {0x20F,0x6F,0x311,0x0}, 
+  {0x210,0x52,0x30F,0x0}, {0x211,0x72,0x30F,0x0}, {0x212,0x52,0x311,0x0}, 
+  {0x213,0x72,0x311,0x0}, {0x214,0x55,0x30F,0x0}, {0x215,0x75,0x30F,0x0}, 
+  {0x216,0x55,0x311,0x0}, {0x217,0x75,0x311,0x0}, {0x310,0x306,0x307,0x0}, 
+  {0x340,0x300,0x0,0x0}, {0x341,0x301,0x0,0x0}, {0x343,0x313,0x0,0x0}, 
+  {0x344,0x308,0x30D,0x0}, {0x374,0x2B9,0x0,0x0}, {0x37E,0x3B,0x0,0x0}, 
+  {0x385,0xA8,0x30D,0x0}, {0x386,0x391,0x30D,0x0}, {0x387,0xB7,0x0,0x0}, 
+  {0x388,0x395,0x30D,0x0}, {0x389,0x397,0x30D,0x0}, {0x38A,0x399,0x30D,0x0}, 
+  {0x38C,0x39F,0x30D,0x0}, {0x38E,0x3A5,0x30D,0x0}, {0x38F,0x3A9,0x30D,0x0}, 
+  {0x390,0x3B9,0x344,0x0}, {0x3AA,0x399,0x308,0x0}, {0x3AB,0x3A5,0x308,0x0}, 
+  {0x3AC,0x3B1,0x30D,0x0}, {0x3AD,0x3B5,0x30D,0x0}, {0x3AE,0x3B7,0x30D,0x0}, 
+  {0x3AF,0x3B9,0x30D,0x0}, {0x3B0,0x3C5,0x344,0x0}, {0x3CA,0x3B9,0x308,0x0}, 
+  {0x3CB,0x3C5,0x308,0x0}, {0x3CC,0x3BF,0x30D,0x0}, {0x3CD,0x3C5,0x30D,0x0}, 
+  {0x3CE,0x3C9,0x30D,0x0}, {0x3D3,0x3D2,0x30D,0x0}, {0x3D4,0x3D2,0x308,0x0}, 
+  {0x401,0x415,0x308,0x0}, {0x403,0x413,0x301,0x0}, {0x407,0x406,0x308,0x0}, 
+  {0x40C,0x41A,0x301,0x0}, {0x40E,0x423,0x306,0x0}, {0x419,0x418,0x306,0x0}, 
+  {0x439,0x438,0x306,0x0}, {0x451,0x435,0x308,0x0}, {0x453,0x433,0x301,0x0}, 
+  {0x457,0x456,0x308,0x0}, {0x45C,0x43A,0x301,0x0}, {0x45E,0x443,0x306,0x0}, 
+  {0x476,0x474,0x30F,0x0}, {0x477,0x475,0x30F,0x0}, {0x4C1,0x416,0x306,0x0}, 
+  {0x4C2,0x436,0x306,0x0}, {0x4D0,0x410,0x306,0x0}, {0x4D1,0x430,0x306,0x0}, 
+  {0x4D2,0x410,0x308,0x0}, {0x4D3,0x430,0x308,0x0}, {0x4D6,0x415,0x306,0x0}, 
+  {0x4D7,0x435,0x306,0x0}, {0x4DA,0x4D8,0x308,0x0}, {0x4DB,0x4D9,0x308,0x0}, 
+  {0x4DC,0x416,0x308,0x0}, {0x4DD,0x436,0x308,0x0}, {0x4DE,0x417,0x308,0x0}, 
+  {0x4DF,0x437,0x308,0x0}, {0x4E2,0x418,0x304,0x0}, {0x4E3,0x438,0x304,0x0}, 
+  {0x4E4,0x418,0x308,0x0}, {0x4E5,0x438,0x308,0x0}, {0x4E6,0x41E,0x308,0x0}, 
+  {0x4E7,0x43E,0x308,0x0}, {0x4EA,0x4E8,0x308,0x0}, {0x4EB,0x4E9,0x308,0x0}, 
+  {0x4EE,0x423,0x304,0x0}, {0x4EF,0x443,0x304,0x0}, {0x4F0,0x423,0x308,0x0}, 
+  {0x4F1,0x443,0x308,0x0}, {0x4F2,0x423,0x30B,0x0}, {0x4F3,0x443,0x30B,0x0}, 
+  {0x4F4,0x427,0x308,0x0}, {0x4F5,0x447,0x308,0x0}, {0x4F8,0x42B,0x308,0x0}, 
+  {0x4F9,0x44B,0x308,0x0}, {0x929,0x928,0x93C,0x0}, {0x931,0x930,0x93C,0x0}, 
+  {0x934,0x933,0x93C,0x0}, {0x958,0x915,0x93C,0x0}, {0x959,0x916,0x93C,0x0}, 
+  {0x95A,0x917,0x93C,0x0}, {0x95B,0x91C,0x93C,0x0}, {0x95C,0x921,0x93C,0x0}, 
+  {0x95D,0x922,0x93C,0x0}, {0x95E,0x92B,0x93C,0x0}, {0x95F,0x92F,0x93C,0x0}, 
+  {0x9B0,0x9AC,0x9BC,0x0}, {0x9CB,0x9C7,0x9BE,0x0}, {0x9CC,0x9C7,0x9D7,0x0}, 
+  {0x9DC,0x9A1,0x9BC,0x0}, {0x9DD,0x9A2,0x9BC,0x0}, {0x9DF,0x9AF,0x9BC,0x0}, 
+  {0xA59,0xA16,0xA3C,0x0}, {0xA5A,0xA17,0xA3C,0x0}, {0xA5B,0xA1C,0xA3C,0x0}, 
+  {0xA5C,0xA21,0xA3C,0x0}, {0xA5E,0xA2B,0xA3C,0x0}, {0xB48,0xB47,0xB56,0x0}, 
+  {0xB4B,0xB47,0xB3E,0x0}, {0xB4C,0xB47,0xB57,0x0}, {0xB5C,0xB21,0xB3C,0x0}, 
+  {0xB5D,0xB22,0xB3C,0x0}, {0xB5F,0xB2F,0xB3C,0x0}, {0xB94,0xB92,0xBD7,0x0}, 
+  {0xBCA,0xBC6,0xBBE,0x0}, {0xBCB,0xBC7,0xBBE,0x0}, {0xBCC,0xBC6,0xBD7,0x0}, 
+  {0xC48,0xC46,0xC56,0x0}, {0xCC0,0xCBF,0xCD5,0x0}, {0xCC7,0xCC6,0xCD5,0x0}, 
+  {0xCC8,0xCC6,0xCD6,0x0}, {0xCCA,0xCC6,0xCC2,0x0}, {0xCCB,0xCC6,0xCC2,0xCD5}, 
+  {0xD4A,0xD46,0xD3E,0x0}, {0xD4B,0xD47,0xD3E,0x0}, {0xD4C,0xD46,0xD57,0x0}, 
+  {0xE33,0xE4D,0xE32,0x0}, {0xEB3,0xECD,0xEB2,0x0}, {0xF43,0xF42,0xFB7,0x0}, 
+  {0xF4D,0xF4C,0xFB7,0x0}, {0xF52,0xF51,0xFB7,0x0}, {0xF57,0xF56,0xFB7,0x0}, 
+  {0xF5C,0xF5B,0xFB7,0x0}, {0xF69,0xF40,0xFB5,0x0}, {0xF73,0xF72,0xF71,0x0}, 
+  {0xF75,0xF71,0xF74,0x0}, {0xF76,0xFB2,0xF80,0x0}, {0xF77,0xF76,0xF71,0x0}, 
+  {0xF78,0xFB3,0xF80,0x0}, {0xF79,0xF78,0xF71,0x0}, {0xF81,0xF80,0xF71,0x0}, 
+  {0xF93,0xF92,0xFB7,0x0}, {0xF9D,0xF9C,0xFB7,0x0}, {0xFA2,0xFA1,0xFB7,0x0}, 
+  {0xFA7,0xFA6,0xFB7,0x0}, {0xFAC,0xFAB,0xFB7,0x0}, {0xFB9,0xF90,0xFB5,0x0}, 
+  {0x1E00,0x41,0x325,0x0}, {0x1E01,0x61,0x325,0x0}, {0x1E02,0x42,0x307,0x0}, 
+  {0x1E03,0x62,0x307,0x0}, {0x1E04,0x42,0x323,0x0}, {0x1E05,0x62,0x323,0x0}, 
+  {0x1E06,0x42,0x331,0x0}, {0x1E07,0x62,0x331,0x0}, {0x1E08,0xC7,0x301,0x0}, 
+  {0x1E09,0xE7,0x301,0x0}, {0x1E0A,0x44,0x307,0x0}, {0x1E0B,0x64,0x307,0x0}, 
+  {0x1E0C,0x44,0x323,0x0}, {0x1E0D,0x64,0x323,0x0}, {0x1E0E,0x44,0x331,0x0}, 
+  {0x1E0F,0x64,0x331,0x0}, {0x1E10,0x44,0x327,0x0}, {0x1E11,0x64,0x327,0x0}, 
+  {0x1E12,0x44,0x32D,0x0}, {0x1E13,0x64,0x32D,0x0}, {0x1E14,0x112,0x300,0x0}, 
+  {0x1E15,0x113,0x300,0x0}, {0x1E16,0x112,0x301,0x0}, {0x1E17,0x113,0x301,0x0}, 
+  {0x1E18,0x45,0x32D,0x0}, {0x1E19,0x65,0x32D,0x0}, {0x1E1A,0x45,0x330,0x0}, 
+  {0x1E1B,0x65,0x330,0x0}, {0x1E1C,0x114,0x327,0x0}, {0x1E1D,0x115,0x327,0x0}, 
+  {0x1E1E,0x46,0x307,0x0}, {0x1E1F,0x66,0x307,0x0}, {0x1E20,0x47,0x304,0x0}, 
+  {0x1E21,0x67,0x304,0x0}, {0x1E22,0x48,0x307,0x0}, {0x1E23,0x68,0x307,0x0}, 
+  {0x1E24,0x48,0x323,0x0}, {0x1E25,0x68,0x323,0x0}, {0x1E26,0x48,0x308,0x0}, 
+  {0x1E27,0x68,0x308,0x0}, {0x1E28,0x48,0x327,0x0}, {0x1E29,0x68,0x327,0x0}, 
+  {0x1E2A,0x48,0x32E,0x0}, {0x1E2B,0x68,0x32E,0x0}, {0x1E2C,0x49,0x330,0x0}, 
+  {0x1E2D,0x69,0x330,0x0}, {0x1E2E,0xCF,0x301,0x0}, {0x1E2F,0xEF,0x301,0x0}, 
+  {0x1E30,0x4B,0x301,0x0}, {0x1E31,0x6B,0x301,0x0}, {0x1E32,0x4B,0x323,0x0}, 
+  {0x1E33,0x6B,0x323,0x0}, {0x1E34,0x4B,0x331,0x0}, {0x1E35,0x6B,0x331,0x0}, 
+  {0x1E36,0x4C,0x323,0x0}, {0x1E37,0x6C,0x323,0x0}, {0x1E38,0x1E36,0x304,0x0}, 
+  {0x1E39,0x1E37,0x304,0x0}, {0x1E3A,0x4C,0x331,0x0}, {0x1E3B,0x6C,0x331,0x0}, 
+  {0x1E3C,0x4C,0x32D,0x0}, {0x1E3D,0x6C,0x32D,0x0}, {0x1E3E,0x4D,0x301,0x0}, 
+  {0x1E3F,0x6D,0x301,0x0}, {0x1E40,0x4D,0x307,0x0}, {0x1E41,0x6D,0x307,0x0}, 
+  {0x1E42,0x4D,0x323,0x0}, {0x1E43,0x6D,0x323,0x0}, {0x1E44,0x4E,0x307,0x0}, 
+  {0x1E45,0x6E,0x307,0x0}, {0x1E46,0x4E,0x323,0x0}, {0x1E47,0x6E,0x323,0x0}, 
+  {0x1E48,0x4E,0x331,0x0}, {0x1E49,0x6E,0x331,0x0}, {0x1E4A,0x4E,0x32D,0x0}, 
+  {0x1E4B,0x6E,0x32D,0x0}, {0x1E4C,0xD5,0x301,0x0}, {0x1E4D,0xF5,0x301,0x0}, 
+  {0x1E4E,0xD5,0x308,0x0}, {0x1E4F,0xF5,0x308,0x0}, {0x1E50,0x14C,0x300,0x0}, 
+  {0x1E51,0x14D,0x300,0x0}, {0x1E52,0x14C,0x301,0x0}, {0x1E53,0x14D,0x301,0x0}, 
+  {0x1E54,0x50,0x301,0x0}, {0x1E55,0x70,0x301,0x0}, {0x1E56,0x50,0x307,0x0}, 
+  {0x1E57,0x70,0x307,0x0}, {0x1E58,0x52,0x307,0x0}, {0x1E59,0x72,0x307,0x0}, 
+  {0x1E5A,0x52,0x323,0x0}, {0x1E5B,0x72,0x323,0x0}, {0x1E5C,0x1E5A,0x304,0x0}, 
+  {0x1E5D,0x1E5B,0x304,0x0}, {0x1E5E,0x52,0x331,0x0}, {0x1E5F,0x72,0x331,0x0}, 
+  {0x1E60,0x53,0x307,0x0}, {0x1E61,0x73,0x307,0x0}, {0x1E62,0x53,0x323,0x0}, 
+  {0x1E63,0x73,0x323,0x0}, {0x1E64,0x15A,0x307,0x0}, {0x1E65,0x15B,0x307,0x0}, 
+  {0x1E66,0x160,0x307,0x0}, {0x1E67,0x161,0x307,0x0}, {0x1E68,0x1E62,0x307,0x0}, 
+  {0x1E69,0x1E63,0x307,0x0}, {0x1E6A,0x54,0x307,0x0}, {0x1E6B,0x74,0x307,0x0}, 
+  {0x1E6C,0x54,0x323,0x0}, {0x1E6D,0x74,0x323,0x0}, {0x1E6E,0x54,0x331,0x0}, 
+  {0x1E6F,0x74,0x331,0x0}, {0x1E70,0x54,0x32D,0x0}, {0x1E71,0x74,0x32D,0x0}, 
+  {0x1E72,0x55,0x324,0x0}, {0x1E73,0x75,0x324,0x0}, {0x1E74,0x55,0x330,0x0}, 
+  {0x1E75,0x75,0x330,0x0}, {0x1E76,0x55,0x32D,0x0}, {0x1E77,0x75,0x32D,0x0}, 
+  {0x1E78,0x168,0x301,0x0}, {0x1E79,0x169,0x301,0x0}, {0x1E7A,0x16A,0x308,0x0}, 
+  {0x1E7B,0x16B,0x308,0x0}, {0x1E7C,0x56,0x303,0x0}, {0x1E7D,0x76,0x303,0x0}, 
+  {0x1E7E,0x56,0x323,0x0}, {0x1E7F,0x76,0x323,0x0}, {0x1E80,0x57,0x300,0x0}, 
+  {0x1E81,0x77,0x300,0x0}, {0x1E82,0x57,0x301,0x0}, {0x1E83,0x77,0x301,0x0}, 
+  {0x1E84,0x57,0x308,0x0}, {0x1E85,0x77,0x308,0x0}, {0x1E86,0x57,0x307,0x0}, 
+  {0x1E87,0x77,0x307,0x0}, {0x1E88,0x57,0x323,0x0}, {0x1E89,0x77,0x323,0x0}, 
+  {0x1E8A,0x58,0x307,0x0}, {0x1E8B,0x78,0x307,0x0}, {0x1E8C,0x58,0x308,0x0}, 
+  {0x1E8D,0x78,0x308,0x0}, {0x1E8E,0x59,0x307,0x0}, {0x1E8F,0x79,0x307,0x0}, 
+  {0x1E90,0x5A,0x302,0x0}, {0x1E91,0x7A,0x302,0x0}, {0x1E92,0x5A,0x323,0x0}, 
+  {0x1E93,0x7A,0x323,0x0}, {0x1E94,0x5A,0x331,0x0}, {0x1E95,0x7A,0x331,0x0}, 
+  {0x1E96,0x68,0x331,0x0}, {0x1E97,0x74,0x308,0x0}, {0x1E98,0x77,0x30A,0x0}, 
+  {0x1E99,0x79,0x30A,0x0}, {0x1E9B,0x17F,0x307,0x0}, {0x1EA0,0x41,0x323,0x0}, 
+  {0x1EA1,0x61,0x323,0x0}, {0x1EA2,0x41,0x309,0x0}, {0x1EA3,0x61,0x309,0x0}, 
+  {0x1EA4,0xC2,0x301,0x0}, {0x1EA5,0xE2,0x301,0x0}, {0x1EA6,0xC2,0x300,0x0}, 
+  {0x1EA7,0xE2,0x300,0x0}, {0x1EA8,0xC2,0x309,0x0}, {0x1EA9,0xE2,0x309,0x0}, 
+  {0x1EAA,0xC2,0x303,0x0}, {0x1EAB,0xE2,0x303,0x0}, {0x1EAC,0xC2,0x323,0x0}, 
+  {0x1EAD,0xE2,0x323,0x0}, {0x1EAE,0x102,0x301,0x0}, {0x1EAF,0x103,0x301,0x0}, 
+  {0x1EB0,0x102,0x300,0x0}, {0x1EB1,0x103,0x300,0x0}, {0x1EB2,0x102,0x309,0x0}, 
+  {0x1EB3,0x103,0x309,0x0}, {0x1EB4,0x102,0x303,0x0}, {0x1EB5,0x103,0x303,0x0}, 
+  {0x1EB6,0x102,0x323,0x0}, {0x1EB7,0x103,0x323,0x0}, {0x1EB8,0x45,0x323,0x0}, 
+  {0x1EB9,0x65,0x323,0x0}, {0x1EBA,0x45,0x309,0x0}, {0x1EBB,0x65,0x309,0x0}, 
+  {0x1EBC,0x45,0x303,0x0}, {0x1EBD,0x65,0x303,0x0}, {0x1EBE,0xCA,0x301,0x0}, 
+  {0x1EBF,0xEA,0x301,0x0}, {0x1EC0,0xCA,0x300,0x0}, {0x1EC1,0xEA,0x300,0x0}, 
+  {0x1EC2,0xCA,0x309,0x0}, {0x1EC3,0xEA,0x309,0x0}, {0x1EC4,0xCA,0x303,0x0}, 
+  {0x1EC5,0xEA,0x303,0x0}, {0x1EC6,0xCA,0x323,0x0}, {0x1EC7,0xEA,0x323,0x0}, 
+  {0x1EC8,0x49,0x309,0x0}, {0x1EC9,0x69,0x309,0x0}, {0x1ECA,0x49,0x323,0x0}, 
+  {0x1ECB,0x69,0x323,0x0}, {0x1ECC,0x4F,0x323,0x0}, {0x1ECD,0x6F,0x323,0x0}, 
+  {0x1ECE,0x4F,0x309,0x0}, {0x1ECF,0x6F,0x309,0x0}, {0x1ED0,0xD4,0x301,0x0}, 
+  {0x1ED1,0xF4,0x301,0x0}, {0x1ED2,0xD4,0x300,0x0}, {0x1ED3,0xF4,0x300,0x0}, 
+  {0x1ED4,0xD4,0x309,0x0}, {0x1ED5,0xF4,0x309,0x0}, {0x1ED6,0xD4,0x303,0x0}, 
+  {0x1ED7,0xF4,0x303,0x0}, {0x1ED8,0xD4,0x323,0x0}, {0x1ED9,0xF4,0x323,0x0}, 
+  {0x1EDA,0x1A0,0x301,0x0}, {0x1EDB,0x1A1,0x301,0x0}, {0x1EDC,0x1A0,0x300,0x0}, 
+  {0x1EDD,0x1A1,0x300,0x0}, {0x1EDE,0x1A0,0x309,0x0}, {0x1EDF,0x1A1,0x309,0x0}, 
+  {0x1EE0,0x1A0,0x303,0x0}, {0x1EE1,0x1A1,0x303,0x0}, {0x1EE2,0x1A0,0x323,0x0}, 
+  {0x1EE3,0x1A1,0x323,0x0}, {0x1EE4,0x55,0x323,0x0}, {0x1EE5,0x75,0x323,0x0}, 
+  {0x1EE6,0x55,0x309,0x0}, {0x1EE7,0x75,0x309,0x0}, {0x1EE8,0x1AF,0x301,0x0}, 
+  {0x1EE9,0x1B0,0x301,0x0}, {0x1EEA,0x1AF,0x300,0x0}, {0x1EEB,0x1B0,0x300,0x0}, 
+  {0x1EEC,0x1AF,0x309,0x0}, {0x1EED,0x1B0,0x309,0x0}, {0x1EEE,0x1AF,0x303,0x0}, 
+  {0x1EEF,0x1B0,0x303,0x0}, {0x1EF0,0x1AF,0x323,0x0}, {0x1EF1,0x1B0,0x323,0x0}, 
+  {0x1EF2,0x59,0x300,0x0}, {0x1EF3,0x79,0x300,0x0}, {0x1EF4,0x59,0x323,0x0}, 
+  {0x1EF5,0x79,0x323,0x0}, {0x1EF6,0x59,0x309,0x0}, {0x1EF7,0x79,0x309,0x0}, 
+  {0x1EF8,0x59,0x303,0x0}, {0x1EF9,0x79,0x303,0x0}, {0x1F00,0x3B1,0x313,0x0}, 
+  {0x1F01,0x3B1,0x314,0x0}, {0x1F02,0x1F00,0x300,0x0}, {0x1F03,0x1F01,0x300,0x0}, 
+  {0x1F04,0x1F00,0x301,0x0}, {0x1F05,0x1F01,0x301,0x0}, {0x1F06,0x1F00,0x342,0x0}, 
+  {0x1F07,0x1F01,0x342,0x0}, {0x1F08,0x391,0x313,0x0}, {0x1F09,0x391,0x314,0x0}, 
+  {0x1F0A,0x1F08,0x300,0x0}, {0x1F0B,0x1F09,0x300,0x0}, {0x1F0C,0x1F08,0x301,0x0}, 
+  {0x1F0D,0x1F09,0x301,0x0}, {0x1F0E,0x1F08,0x342,0x0}, {0x1F0F,0x1F09,0x342,0x0}, 
+  {0x1F10,0x3B5,0x313,0x0}, {0x1F11,0x3B5,0x314,0x0}, {0x1F12,0x1F10,0x300,0x0}, 
+  {0x1F13,0x1F11,0x300,0x0}, {0x1F14,0x1F10,0x301,0x0}, {0x1F15,0x1F11,0x301,0x0}, 
+  {0x1F18,0x395,0x313,0x0}, {0x1F19,0x395,0x314,0x0}, {0x1F1A,0x1F18,0x300,0x0}, 
+  {0x1F1B,0x1F19,0x300,0x0}, {0x1F1C,0x1F18,0x301,0x0}, {0x1F1D,0x1F19,0x301,0x0}, 
+  {0x1F20,0x3B7,0x313,0x0}, {0x1F21,0x3B7,0x314,0x0}, {0x1F22,0x1F20,0x300,0x0}, 
+  {0x1F23,0x1F21,0x300,0x0}, {0x1F24,0x1F20,0x301,0x0}, {0x1F25,0x1F21,0x301,0x0}, 
+  {0x1F26,0x1F20,0x342,0x0}, {0x1F27,0x1F21,0x342,0x0}, {0x1F28,0x397,0x313,0x0}, 
+  {0x1F29,0x397,0x314,0x0}, {0x1F2A,0x1F28,0x300,0x0}, {0x1F2B,0x1F29,0x300,0x0}, 
+  {0x1F2C,0x1F28,0x301,0x0}, {0x1F2D,0x1F29,0x301,0x0}, {0x1F2E,0x1F28,0x342,0x0}, 
+  {0x1F2F,0x1F29,0x342,0x0}, {0x1F30,0x3B9,0x313,0x0}, {0x1F31,0x3B9,0x314,0x0}, 
+  {0x1F32,0x1F30,0x300,0x0}, {0x1F33,0x1F31,0x300,0x0}, {0x1F34,0x1F30,0x301,0x0}, 
+  {0x1F35,0x1F31,0x301,0x0}, {0x1F36,0x1F30,0x342,0x0}, {0x1F37,0x1F31,0x342,0x0}, 
+  {0x1F38,0x399,0x313,0x0}, {0x1F39,0x399,0x314,0x0}, {0x1F3A,0x1F38,0x300,0x0}, 
+  {0x1F3B,0x1F39,0x300,0x0}, {0x1F3C,0x1F38,0x301,0x0}, {0x1F3D,0x1F39,0x301,0x0}, 
+  {0x1F3E,0x1F38,0x342,0x0}, {0x1F3F,0x1F39,0x342,0x0}, {0x1F40,0x3BF,0x313,0x0}, 
+  {0x1F41,0x3BF,0x314,0x0}, {0x1F42,0x1F40,0x300,0x0}, {0x1F43,0x1F41,0x300,0x0}, 
+  {0x1F44,0x1F40,0x301,0x0}, {0x1F45,0x1F41,0x301,0x0}, {0x1F48,0x39F,0x313,0x0}, 
+  {0x1F49,0x39F,0x314,0x0}, {0x1F4A,0x1F48,0x300,0x0}, {0x1F4B,0x1F49,0x300,0x0}, 
+  {0x1F4C,0x1F48,0x301,0x0}, {0x1F4D,0x1F49,0x301,0x0}, {0x1F50,0x3C5,0x313,0x0}, 
+  {0x1F51,0x3C5,0x314,0x0}, {0x1F52,0x1F50,0x300,0x0}, {0x1F53,0x1F51,0x300,0x0}, 
+  {0x1F54,0x1F50,0x301,0x0}, {0x1F55,0x1F51,0x301,0x0}, {0x1F56,0x1F50,0x342,0x0}, 
+  {0x1F57,0x1F51,0x342,0x0}, {0x1F59,0x3A5,0x314,0x0}, {0x1F5B,0x1F59,0x300,0x0}, 
+  {0x1F5D,0x1F59,0x301,0x0}, {0x1F5F,0x1F59,0x342,0x0}, {0x1F60,0x3C9,0x313,0x0}, 
+  {0x1F61,0x3C9,0x314,0x0}, {0x1F62,0x1F60,0x300,0x0}, {0x1F63,0x1F61,0x300,0x0}, 
+  {0x1F64,0x1F60,0x301,0x0}, {0x1F65,0x1F61,0x301,0x0}, {0x1F66,0x1F60,0x342,0x0}, 
+  {0x1F67,0x1F61,0x342,0x0}, {0x1F68,0x3A9,0x313,0x0}, {0x1F69,0x3A9,0x314,0x0}, 
+  {0x1F6A,0x1F68,0x300,0x0}, {0x1F6B,0x1F69,0x300,0x0}, {0x1F6C,0x1F68,0x301,0x0}, 
+  {0x1F6D,0x1F69,0x301,0x0}, {0x1F6E,0x1F68,0x342,0x0}, {0x1F6F,0x1F69,0x342,0x0}, 
+  {0x1F70,0x3B1,0x300,0x0}, {0x1F71,0x3B1,0x301,0x0}, {0x1F72,0x3B5,0x300,0x0}, 
+  {0x1F73,0x3B5,0x301,0x0}, {0x1F74,0x3B7,0x300,0x0}, {0x1F75,0x3B7,0x301,0x0}, 
+  {0x1F76,0x3B9,0x300,0x0}, {0x1F77,0x3B9,0x301,0x0}, {0x1F78,0x3BF,0x300,0x0}, 
+  {0x1F79,0x3BF,0x301,0x0}, {0x1F7A,0x3C5,0x300,0x0}, {0x1F7B,0x3C5,0x301,0x0}, 
+  {0x1F7C,0x3C9,0x300,0x0}, {0x1F7D,0x3C9,0x301,0x0}, {0x1F80,0x1F00,0x345,0x0}, 
+  {0x1F81,0x1F01,0x345,0x0}, {0x1F82,0x1F02,0x345,0x0}, {0x1F83,0x1F03,0x345,0x0}, 
+  {0x1F84,0x1F04,0x345,0x0}, {0x1F85,0x1F05,0x345,0x0}, {0x1F86,0x1F06,0x345,0x0}, 
+  {0x1F87,0x1F07,0x345,0x0}, {0x1F88,0x1F08,0x345,0x0}, {0x1F89,0x1F09,0x345,0x0}, 
+  {0x1F8A,0x1F0A,0x345,0x0}, {0x1F8B,0x1F0B,0x345,0x0}, {0x1F8C,0x1F0C,0x345,0x0}, 
+  {0x1F8D,0x1F0D,0x345,0x0}, {0x1F8E,0x1F0E,0x345,0x0}, {0x1F8F,0x1F0F,0x345,0x0}, 
+  {0x1F90,0x1F20,0x345,0x0}, {0x1F91,0x1F21,0x345,0x0}, {0x1F92,0x1F22,0x345,0x0}, 
+  {0x1F93,0x1F23,0x345,0x0}, {0x1F94,0x1F24,0x345,0x0}, {0x1F95,0x1F25,0x345,0x0}, 
+  {0x1F96,0x1F26,0x345,0x0}, {0x1F97,0x1F27,0x345,0x0}, {0x1F98,0x1F28,0x345,0x0}, 
+  {0x1F99,0x1F29,0x345,0x0}, {0x1F9A,0x1F2A,0x345,0x0}, {0x1F9B,0x1F2B,0x345,0x0}, 
+  {0x1F9C,0x1F2C,0x345,0x0}, {0x1F9D,0x1F2D,0x345,0x0}, {0x1F9E,0x1F2E,0x345,0x0}, 
+  {0x1F9F,0x1F2F,0x345,0x0}, {0x1FA0,0x1F60,0x345,0x0}, {0x1FA1,0x1F61,0x345,0x0}, 
+  {0x1FA2,0x1F62,0x345,0x0}, {0x1FA3,0x1F63,0x345,0x0}, {0x1FA4,0x1F64,0x345,0x0}, 
+  {0x1FA5,0x1F65,0x345,0x0}, {0x1FA6,0x1F66,0x345,0x0}, {0x1FA7,0x1F67,0x345,0x0}, 
+  {0x1FA8,0x1F68,0x345,0x0}, {0x1FA9,0x1F69,0x345,0x0}, {0x1FAA,0x1F6A,0x345,0x0}, 
+  {0x1FAB,0x1F6B,0x345,0x0}, {0x1FAC,0x1F6C,0x345,0x0}, {0x1FAD,0x1F6D,0x345,0x0}, 
+  {0x1FAE,0x1F6E,0x345,0x0}, {0x1FAF,0x1F6F,0x345,0x0}, {0x1FB0,0x3B1,0x306,0x0}, 
+  {0x1FB1,0x3B1,0x304,0x0}, {0x1FB2,0x1F70,0x345,0x0}, {0x1FB3,0x3B1,0x345,0x0}, 
+  {0x1FB4,0x1F71,0x345,0x0}, {0x1FB6,0x3B1,0x342,0x0}, {0x1FB7,0x1FB6,0x345,0x0}, 
+  {0x1FB8,0x391,0x306,0x0}, {0x1FB9,0x391,0x304,0x0}, {0x1FBA,0x391,0x300,0x0}, 
+  {0x1FBB,0x391,0x301,0x0}, {0x1FBC,0x391,0x345,0x0}, {0x1FBE,0x3B9,0x0,0x0}, 
+  {0x1FC1,0xA8,0x342,0x0}, {0x1FC2,0x1F74,0x345,0x0}, {0x1FC3,0x3B7,0x345,0x0}, 
+  {0x1FC4,0x1F75,0x345,0x0}, {0x1FC6,0x3B7,0x342,0x0}, {0x1FC7,0x1FC6,0x345,0x0}, 
+  {0x1FC8,0x395,0x300,0x0}, {0x1FC9,0x395,0x301,0x0}, {0x1FCA,0x397,0x300,0x0}, 
+  {0x1FCB,0x397,0x301,0x0}, {0x1FCC,0x397,0x345,0x0}, {0x1FCD,0x1FBF,0x300,0x0}, 
+  {0x1FCE,0x1FBF,0x301,0x0}, {0x1FCF,0x1FBF,0x342,0x0}, {0x1FD0,0x3B9,0x306,0x0}, 
+  {0x1FD1,0x3B9,0x304,0x0}, {0x1FD2,0x3CA,0x300,0x0}, {0x1FD3,0x3CA,0x301,0x0}, 
+  {0x1FD6,0x3B9,0x342,0x0}, {0x1FD7,0x3CA,0x342,0x0}, {0x1FD8,0x399,0x306,0x0}, 
+  {0x1FD9,0x399,0x304,0x0}, {0x1FDA,0x399,0x300,0x0}, {0x1FDB,0x399,0x301,0x0}, 
+  {0x1FDD,0x1FFE,0x300,0x0}, {0x1FDE,0x1FFE,0x301,0x0}, {0x1FDF,0x1FFE,0x342,0x0}, 
+  {0x1FE0,0x3C5,0x306,0x0}, {0x1FE1,0x3C5,0x304,0x0}, {0x1FE2,0x3CB,0x300,0x0}, 
+  {0x1FE3,0x3CB,0x301,0x0}, {0x1FE4,0x3C1,0x313,0x0}, {0x1FE5,0x3C1,0x314,0x0}, 
+  {0x1FE6,0x3C5,0x342,0x0}, {0x1FE7,0x3CB,0x342,0x0}, {0x1FE8,0x3A5,0x306,0x0}, 
+  {0x1FE9,0x3A5,0x304,0x0}, {0x1FEA,0x3A5,0x300,0x0}, {0x1FEB,0x3A5,0x301,0x0}, 
+  {0x1FEC,0x3A1,0x314,0x0}, {0x1FED,0xA8,0x300,0x0}, {0x1FEE,0xA8,0x301,0x0}, 
+  {0x1FEF,0x60,0x0,0x0}, {0x1FF2,0x1F7C,0x345,0x0}, {0x1FF3,0x3C9,0x345,0x0}, 
+  {0x1FF4,0x1F79,0x345,0x0}, {0x1FF6,0x3C9,0x342,0x0}, {0x1FF7,0x1FF6,0x345,0x0}, 
+  {0x1FF8,0x39F,0x300,0x0}, {0x1FF9,0x39F,0x301,0x0}, {0x1FFA,0x3A9,0x300,0x0}, 
+  {0x1FFB,0x3A9,0x301,0x0}, {0x1FFC,0x3A9,0x345,0x0}, {0x1FFD,0xB4,0x0,0x0}, 
+  {0x2000,0x2002,0x0,0x0}, {0x2001,0x2003,0x0,0x0}, {0x2126,0x3A9,0x0,0x0}, 
+  {0x212A,0x4B,0x0,0x0}, {0x212B,0xC5,0x0,0x0}, {0x2204,0x2203,0x338,0x0}, 
+  {0x2209,0x2208,0x338,0x0}, {0x220C,0x220B,0x338,0x0}, {0x2224,0x2223,0x338,0x0}, 
+  {0x2226,0x2225,0x338,0x0}, {0x2241,0x7E,0x338,0x0}, {0x2244,0x2243,0x338,0x0}, 
+  {0x2247,0x2245,0x338,0x0}, {0x2249,0x2248,0x338,0x0}, {0x2260,0x3D,0x338,0x0}, 
+  {0x2262,0x2261,0x338,0x0}, {0x226D,0x224D,0x338,0x0}, {0x226E,0x3C,0x338,0x0}, 
+  {0x226F,0x3E,0x338,0x0}, {0x2270,0x2264,0x338,0x0}, {0x2271,0x2265,0x338,0x0}, 
+  {0x2274,0x2272,0x338,0x0}, {0x2275,0x2273,0x338,0x0}, {0x2278,0x2276,0x338,0x0}, 
+  {0x2279,0x2277,0x338,0x0}, {0x2280,0x227A,0x338,0x0}, {0x2281,0x227B,0x338,0x0}, 
+  {0x2284,0x2282,0x338,0x0}, {0x2285,0x2283,0x338,0x0}, {0x2288,0x2286,0x338,0x0}, 
+  {0x2289,0x2287,0x338,0x0}, {0x22AC,0x22A2,0x338,0x0}, {0x22AD,0x22A8,0x338,0x0}, 
+  {0x22AE,0x22A9,0x338,0x0}, {0x22AF,0x22AB,0x338,0x0}, {0x22E0,0x227C,0x338,0x0}, 
+  {0x22E1,0x227D,0x338,0x0}, {0x22E2,0x2291,0x338,0x0}, {0x22E3,0x2292,0x338,0x0}, 
+  {0x22EA,0x22B2,0x338,0x0}, {0x22EB,0x22B3,0x338,0x0}, {0x22EC,0x22B4,0x338,0x0}, 
+  {0x22ED,0x22B5,0x338,0x0}, {0x2329,0x3008,0x0,0x0}, {0x232A,0x3009,0x0,0x0}, 
+  {0x304C,0x304B,0x3099,0x0}, {0x304E,0x304D,0x3099,0x0}, {0x3050,0x304F,0x3099,0x0}, 
+  {0x3052,0x3051,0x3099,0x0}, {0x3054,0x3053,0x3099,0x0}, {0x3056,0x3055,0x3099,0x0}, 
+  {0x3058,0x3057,0x3099,0x0}, {0x305A,0x3059,0x3099,0x0}, {0x305C,0x305B,0x3099,0x0}, 
+  {0x305E,0x305D,0x3099,0x0}, {0x3060,0x305F,0x3099,0x0}, {0x3062,0x3061,0x3099,0x0}, 
+  {0x3065,0x3064,0x3099,0x0}, {0x3067,0x3066,0x3099,0x0}, {0x3069,0x3068,0x3099,0x0}, 
+  {0x3070,0x306F,0x3099,0x0}, {0x3071,0x306F,0x309A,0x0}, {0x3073,0x3072,0x3099,0x0}, 
+  {0x3074,0x3072,0x309A,0x0}, {0x3076,0x3075,0x3099,0x0}, {0x3077,0x3075,0x309A,0x0}, 
+  {0x3079,0x3078,0x3099,0x0}, {0x307A,0x3078,0x309A,0x0}, {0x307C,0x307B,0x3099,0x0}, 
+  {0x307D,0x307B,0x309A,0x0}, {0x3094,0x3046,0x3099,0x0}, {0x309E,0x309D,0x3099,0x0}, 
+  {0x30AC,0x30AB,0x3099,0x0}, {0x30AE,0x30AD,0x3099,0x0}, {0x30B0,0x30AF,0x3099,0x0}, 
+  {0x30B2,0x30B1,0x3099,0x0}, {0x30B4,0x30B3,0x3099,0x0}, {0x30B6,0x30B5,0x3099,0x0}, 
+  {0x30B8,0x30B7,0x3099,0x0}, {0x30BA,0x30B9,0x3099,0x0}, {0x30BC,0x30BB,0x3099,0x0}, 
+  {0x30BE,0x30BD,0x3099,0x0}, {0x30C0,0x30BF,0x3099,0x0}, {0x30C2,0x30C1,0x3099,0x0}, 
+  {0x30C5,0x30C4,0x3099,0x0}, {0x30C7,0x30C6,0x3099,0x0}, {0x30C9,0x30C8,0x3099,0x0}, 
+  {0x30D0,0x30CF,0x3099,0x0}, {0x30D1,0x30CF,0x309A,0x0}, {0x30D3,0x30D2,0x3099,0x0}, 
+  {0x30D4,0x30D2,0x309A,0x0}, {0x30D6,0x30D5,0x3099,0x0}, {0x30D7,0x30D5,0x309A,0x0}, 
+  {0x30D9,0x30D8,0x3099,0x0}, {0x30DA,0x30D8,0x309A,0x0}, {0x30DC,0x30DB,0x3099,0x0}, 
+  {0x30DD,0x30DB,0x309A,0x0}, {0x30F4,0x30A6,0x3099,0x0}, {0x30F7,0x30EF,0x3099,0x0}, 
+  {0x30F8,0x30F0,0x3099,0x0}, {0x30F9,0x30F1,0x3099,0x0}, {0x30FA,0x30F2,0x3099,0x0}, 
+  {0x30FE,0x30FD,0x3099,0x0}, {0xF900,0x8C48,0x0,0x0}, {0xF901,0x66F4,0x0,0x0}, 
+  {0xF902,0x8ECA,0x0,0x0}, {0xF903,0x8CC8,0x0,0x0}, {0xF904,0x6ED1,0x0,0x0}, 
+  {0xF905,0x4E32,0x0,0x0}, {0xF906,0x53E5,0x0,0x0}, {0xF907,0x9F9C,0x0,0x0}, 
+  {0xF908,0x9F9C,0x0,0x0}, {0xF909,0x5951,0x0,0x0}, {0xF90A,0x91D1,0x0,0x0}, 
+  {0xF90B,0x5587,0x0,0x0}, {0xF90C,0x5948,0x0,0x0}, {0xF90D,0x61F6,0x0,0x0}, 
+  {0xF90E,0x7669,0x0,0x0}, {0xF90F,0x7F85,0x0,0x0}, {0xF910,0x863F,0x0,0x0}, 
+  {0xF911,0x87BA,0x0,0x0}, {0xF912,0x88F8,0x0,0x0}, {0xF913,0x908F,0x0,0x0}, 
+  {0xF914,0x6A02,0x0,0x0}, {0xF915,0x6D1B,0x0,0x0}, {0xF916,0x70D9,0x0,0x0}, 
+  {0xF917,0x73DE,0x0,0x0}, {0xF918,0x843D,0x0,0x0}, {0xF919,0x916A,0x0,0x0}, 
+  {0xF91A,0x99F1,0x0,0x0}, {0xF91B,0x4E82,0x0,0x0}, {0xF91C,0x5375,0x0,0x0}, 
+  {0xF91D,0x6B04,0x0,0x0}, {0xF91E,0x721B,0x0,0x0}, {0xF91F,0x862D,0x0,0x0}, 
+  {0xF920,0x9E1E,0x0,0x0}, {0xF921,0x5D50,0x0,0x0}, {0xF922,0x6FEB,0x0,0x0}, 
+  {0xF923,0x85CD,0x0,0x0}, {0xF924,0x8964,0x0,0x0}, {0xF925,0x62C9,0x0,0x0}, 
+  {0xF926,0x81D8,0x0,0x0}, {0xF927,0x881F,0x0,0x0}, {0xF928,0x5ECA,0x0,0x0}, 
+  {0xF929,0x6717,0x0,0x0}, {0xF92A,0x6D6A,0x0,0x0}, {0xF92B,0x72FC,0x0,0x0}, 
+  {0xF92C,0x90CE,0x0,0x0}, {0xF92D,0x4F86,0x0,0x0}, {0xF92E,0x51B7,0x0,0x0}, 
+  {0xF92F,0x52DE,0x0,0x0}, {0xF930,0x64C4,0x0,0x0}, {0xF931,0x6AD3,0x0,0x0}, 
+  {0xF932,0x7210,0x0,0x0}, {0xF933,0x76E7,0x0,0x0}, {0xF934,0x8001,0x0,0x0}, 
+  {0xF935,0x8606,0x0,0x0}, {0xF936,0x865C,0x0,0x0}, {0xF937,0x8DEF,0x0,0x0}, 
+  {0xF938,0x9732,0x0,0x0}, {0xF939,0x9B6F,0x0,0x0}, {0xF93A,0x9DFA,0x0,0x0}, 
+  {0xF93B,0x788C,0x0,0x0}, {0xF93C,0x797F,0x0,0x0}, {0xF93D,0x7DA0,0x0,0x0}, 
+  {0xF93E,0x83C9,0x0,0x0}, {0xF93F,0x9304,0x0,0x0}, {0xF940,0x9E7F,0x0,0x0}, 
+  {0xF941,0x8AD6,0x0,0x0}, {0xF942,0x58DF,0x0,0x0}, {0xF943,0x5F04,0x0,0x0}, 
+  {0xF944,0x7C60,0x0,0x0}, {0xF945,0x807E,0x0,0x0}, {0xF946,0x7262,0x0,0x0}, 
+  {0xF947,0x78CA,0x0,0x0}, {0xF948,0x8CC2,0x0,0x0}, {0xF949,0x96F7,0x0,0x0}, 
+  {0xF94A,0x58D8,0x0,0x0}, {0xF94B,0x5C62,0x0,0x0}, {0xF94C,0x6A13,0x0,0x0}, 
+  {0xF94D,0x6DDA,0x0,0x0}, {0xF94E,0x6F0F,0x0,0x0}, {0xF94F,0x7D2F,0x0,0x0}, 
+  {0xF950,0x7E37,0x0,0x0}, {0xF951,0x96FB,0x0,0x0}, {0xF952,0x52D2,0x0,0x0}, 
+  {0xF953,0x808B,0x0,0x0}, {0xF954,0x51DC,0x0,0x0}, {0xF955,0x51CC,0x0,0x0}, 
+  {0xF956,0x7A1C,0x0,0x0}, {0xF957,0x7DBE,0x0,0x0}, {0xF958,0x83F1,0x0,0x0}, 
+  {0xF959,0x9675,0x0,0x0}, {0xF95A,0x8B80,0x0,0x0}, {0xF95B,0x62CF,0x0,0x0}, 
+  {0xF95C,0x6A02,0x0,0x0}, {0xF95D,0x8AFE,0x0,0x0}, {0xF95E,0x4E39,0x0,0x0}, 
+  {0xF95F,0x5BE7,0x0,0x0}, {0xF960,0x6012,0x0,0x0}, {0xF961,0x7387,0x0,0x0}, 
+  {0xF962,0x7570,0x0,0x0}, {0xF963,0x5317,0x0,0x0}, {0xF964,0x78FB,0x0,0x0}, 
+  {0xF965,0x4FBF,0x0,0x0}, {0xF966,0x5FA9,0x0,0x0}, {0xF967,0x4E0D,0x0,0x0}, 
+  {0xF968,0x6CCC,0x0,0x0}, {0xF969,0x6578,0x0,0x0}, {0xF96A,0x7D22,0x0,0x0}, 
+  {0xF96B,0x53C3,0x0,0x0}, {0xF96C,0x585E,0x0,0x0}, {0xF96D,0x7701,0x0,0x0}, 
+  {0xF96E,0x8449,0x0,0x0}, {0xF96F,0x8AAA,0x0,0x0}, {0xF970,0x6BBA,0x0,0x0}, 
+  {0xF971,0x8FB0,0x0,0x0}, {0xF972,0x6C88,0x0,0x0}, {0xF973,0x62FE,0x0,0x0}, 
+  {0xF974,0x82E5,0x0,0x0}, {0xF975,0x63A0,0x0,0x0}, {0xF976,0x7565,0x0,0x0}, 
+  {0xF977,0x4EAE,0x0,0x0}, {0xF978,0x5169,0x0,0x0}, {0xF979,0x51C9,0x0,0x0}, 
+  {0xF97A,0x6881,0x0,0x0}, {0xF97B,0x7CE7,0x0,0x0}, {0xF97C,0x826F,0x0,0x0}, 
+  {0xF97D,0x8AD2,0x0,0x0}, {0xF97E,0x91CF,0x0,0x0}, {0xF97F,0x52F5,0x0,0x0}, 
+  {0xF980,0x5442,0x0,0x0}, {0xF981,0x5973,0x0,0x0}, {0xF982,0x5EEC,0x0,0x0}, 
+  {0xF983,0x65C5,0x0,0x0}, {0xF984,0x6FFE,0x0,0x0}, {0xF985,0x792A,0x0,0x0}, 
+  {0xF986,0x95AD,0x0,0x0}, {0xF987,0x9A6A,0x0,0x0}, {0xF988,0x9E97,0x0,0x0}, 
+  {0xF989,0x9ECE,0x0,0x0}, {0xF98A,0x529B,0x0,0x0}, {0xF98B,0x66C6,0x0,0x0}, 
+  {0xF98C,0x6B77,0x0,0x0}, {0xF98D,0x8F62,0x0,0x0}, {0xF98E,0x5E74,0x0,0x0}, 
+  {0xF98F,0x6190,0x0,0x0}, {0xF990,0x6200,0x0,0x0}, {0xF991,0x649A,0x0,0x0}, 
+  {0xF992,0x6F23,0x0,0x0}, {0xF993,0x7149,0x0,0x0}, {0xF994,0x7489,0x0,0x0}, 
+  {0xF995,0x79CA,0x0,0x0}, {0xF996,0x7DF4,0x0,0x0}, {0xF997,0x806F,0x0,0x0}, 
+  {0xF998,0x8F26,0x0,0x0}, {0xF999,0x84EE,0x0,0x0}, {0xF99A,0x9023,0x0,0x0}, 
+  {0xF99B,0x934A,0x0,0x0}, {0xF99C,0x5217,0x0,0x0}, {0xF99D,0x52A3,0x0,0x0}, 
+  {0xF99E,0x54BD,0x0,0x0}, {0xF99F,0x70C8,0x0,0x0}, {0xF9A0,0x88C2,0x0,0x0}, 
+  {0xF9A1,0x8AAA,0x0,0x0}, {0xF9A2,0x5EC9,0x0,0x0}, {0xF9A3,0x5FF5,0x0,0x0}, 
+  {0xF9A4,0x637B,0x0,0x0}, {0xF9A5,0x6BAE,0x0,0x0}, {0xF9A6,0x7C3E,0x0,0x0}, 
+  {0xF9A7,0x7375,0x0,0x0}, {0xF9A8,0x4EE4,0x0,0x0}, {0xF9A9,0x56F9,0x0,0x0}, 
+  {0xF9AA,0x5BE7,0x0,0x0}, {0xF9AB,0x5DBA,0x0,0x0}, {0xF9AC,0x601C,0x0,0x0}, 
+  {0xF9AD,0x73B2,0x0,0x0}, {0xF9AE,0x7469,0x0,0x0}, {0xF9AF,0x7F9A,0x0,0x0}, 
+  {0xF9B0,0x8046,0x0,0x0}, {0xF9B1,0x9234,0x0,0x0}, {0xF9B2,0x96F6,0x0,0x0}, 
+  {0xF9B3,0x9748,0x0,0x0}, {0xF9B4,0x9818,0x0,0x0}, {0xF9B5,0x4F8B,0x0,0x0}, 
+  {0xF9B6,0x79AE,0x0,0x0}, {0xF9B7,0x91B4,0x0,0x0}, {0xF9B8,0x96B8,0x0,0x0}, 
+  {0xF9B9,0x60E1,0x0,0x0}, {0xF9BA,0x4E86,0x0,0x0}, {0xF9BB,0x50DA,0x0,0x0}, 
+  {0xF9BC,0x5BEE,0x0,0x0}, {0xF9BD,0x5C3F,0x0,0x0}, {0xF9BE,0x6599,0x0,0x0}, 
+  {0xF9BF,0x6A02,0x0,0x0}, {0xF9C0,0x71CE,0x0,0x0}, {0xF9C1,0x7642,0x0,0x0}, 
+  {0xF9C2,0x84FC,0x0,0x0}, {0xF9C3,0x907C,0x0,0x0}, {0xF9C4,0x9F8D,0x0,0x0}, 
+  {0xF9C5,0x6688,0x0,0x0}, {0xF9C6,0x962E,0x0,0x0}, {0xF9C7,0x5289,0x0,0x0}, 
+  {0xF9C8,0x677B,0x0,0x0}, {0xF9C9,0x67F3,0x0,0x0}, {0xF9CA,0x6D41,0x0,0x0}, 
+  {0xF9CB,0x6E9C,0x0,0x0}, {0xF9CC,0x7409,0x0,0x0}, {0xF9CD,0x7559,0x0,0x0}, 
+  {0xF9CE,0x786B,0x0,0x0}, {0xF9CF,0x7D10,0x0,0x0}, {0xF9D0,0x985E,0x0,0x0}, 
+  {0xF9D1,0x516D,0x0,0x0}, {0xF9D2,0x622E,0x0,0x0}, {0xF9D3,0x9678,0x0,0x0}, 
+  {0xF9D4,0x502B,0x0,0x0}, {0xF9D5,0x5D19,0x0,0x0}, {0xF9D6,0x6DEA,0x0,0x0}, 
+  {0xF9D7,0x8F2A,0x0,0x0}, {0xF9D8,0x5F8B,0x0,0x0}, {0xF9D9,0x6144,0x0,0x0}, 
+  {0xF9DA,0x6817,0x0,0x0}, {0xF9DB,0x7387,0x0,0x0}, {0xF9DC,0x9686,0x0,0x0}, 
+  {0xF9DD,0x5229,0x0,0x0}, {0xF9DE,0x540F,0x0,0x0}, {0xF9DF,0x5C65,0x0,0x0}, 
+  {0xF9E0,0x6613,0x0,0x0}, {0xF9E1,0x674E,0x0,0x0}, {0xF9E2,0x68A8,0x0,0x0}, 
+  {0xF9E3,0x6CE5,0x0,0x0}, {0xF9E4,0x7406,0x0,0x0}, {0xF9E5,0x75E2,0x0,0x0}, 
+  {0xF9E6,0x7F79,0x0,0x0}, {0xF9E7,0x88CF,0x0,0x0}, {0xF9E8,0x88E1,0x0,0x0}, 
+  {0xF9E9,0x91CC,0x0,0x0}, {0xF9EA,0x96E2,0x0,0x0}, {0xF9EB,0x533F,0x0,0x0}, 
+  {0xF9EC,0x6EBA,0x0,0x0}, {0xF9ED,0x541D,0x0,0x0}, {0xF9EE,0x71D0,0x0,0x0}, 
+  {0xF9EF,0x7498,0x0,0x0}, {0xF9F0,0x85FA,0x0,0x0}, {0xF9F1,0x96A3,0x0,0x0}, 
+  {0xF9F2,0x9C57,0x0,0x0}, {0xF9F3,0x9E9F,0x0,0x0}, {0xF9F4,0x6797,0x0,0x0}, 
+  {0xF9F5,0x6DCB,0x0,0x0}, {0xF9F6,0x81E8,0x0,0x0}, {0xF9F7,0x7ACB,0x0,0x0}, 
+  {0xF9F8,0x7B20,0x0,0x0}, {0xF9F9,0x7C92,0x0,0x0}, {0xF9FA,0x72C0,0x0,0x0}, 
+  {0xF9FB,0x7099,0x0,0x0}, {0xF9FC,0x8B58,0x0,0x0}, {0xF9FD,0x4EC0,0x0,0x0}, 
+  {0xF9FE,0x8336,0x0,0x0}, {0xF9FF,0x523A,0x0,0x0}, {0xFA00,0x5207,0x0,0x0}, 
+  {0xFA01,0x5EA6,0x0,0x0}, {0xFA02,0x62D3,0x0,0x0}, {0xFA03,0x7CD6,0x0,0x0}, 
+  {0xFA04,0x5B85,0x0,0x0}, {0xFA05,0x6D1E,0x0,0x0}, {0xFA06,0x66B4,0x0,0x0}, 
+  {0xFA07,0x8F3B,0x0,0x0}, {0xFA08,0x884C,0x0,0x0}, {0xFA09,0x964D,0x0,0x0}, 
+  {0xFA0A,0x898B,0x0,0x0}, {0xFA0B,0x5ED3,0x0,0x0}, {0xFA0C,0x5140,0x0,0x0}, 
+  {0xFA0D,0x55C0,0x0,0x0}, {0xFA10,0x585A,0x0,0x0}, {0xFA12,0x6674,0x0,0x0}, 
+  {0xFA15,0x51DE,0x0,0x0}, {0xFA16,0x732A,0x0,0x0}, {0xFA17,0x76CA,0x0,0x0}, 
+  {0xFA18,0x793C,0x0,0x0}, {0xFA19,0x795E,0x0,0x0}, {0xFA1A,0x7965,0x0,0x0}, 
+  {0xFA1B,0x798F,0x0,0x0}, {0xFA1C,0x9756,0x0,0x0}, {0xFA1D,0x7CBE,0x0,0x0}, 
+  {0xFA1E,0x7FBD,0x0,0x0}, {0xFA20,0x8612,0x0,0x0}, {0xFA22,0x8AF8,0x0,0x0}, 
+  {0xFA25,0x9038,0x0,0x0}, {0xFA26,0x90FD,0x0,0x0}, {0xFA2A,0x98EF,0x0,0x0}, 
+  {0xFA2B,0x98FC,0x0,0x0}, {0xFA2C,0x9928,0x0,0x0}, {0xFA2D,0x9DB4,0x0,0x0}, 
+  {0xFB1F,0x5F2,0x5B7,0x0}, {0xFB2A,0x5E9,0x5C1,0x0}, {0xFB2B,0x5E9,0x5C2,0x0}, 
+  {0xFB2C,0x5E9,0x5BC,0x5C1}, {0xFB2D,0x5E9,0x5BC,0x5C2}, {0xFB2E,0x5D0,0x5B7,0x0}, 
+  {0xFB2F,0x5D0,0x5B8,0x0}, {0xFB30,0x5D0,0x5BC,0x0}, {0xFB31,0x5D1,0x5BC,0x0}, 
+  {0xFB32,0x5D2,0x5BC,0x0}, {0xFB33,0x5D3,0x5BC,0x0}, {0xFB34,0x5D4,0x5BC,0x0}, 
+  {0xFB35,0x5D5,0x5BC,0x0}, {0xFB36,0x5D6,0x5BC,0x0}, {0xFB38,0x5D8,0x5BC,0x0}, 
+  {0xFB39,0x5D9,0x5BC,0x0}, {0xFB3A,0x5DA,0x5BC,0x0}, {0xFB3B,0x5DB,0x5BC,0x0}, 
+  {0xFB3C,0x5DC,0x5BC,0x0}, {0xFB3E,0x5DE,0x5BC,0x0}, {0xFB40,0x5E0,0x5BC,0x0}, 
+  {0xFB41,0x5E1,0x5BC,0x0}, {0xFB43,0x5E3,0x5BC,0x0}, {0xFB44,0x5E4,0x5BC,0x0}, 
+  {0xFB46,0x5E6,0x5BC,0x0}, {0xFB47,0x5E7,0x5BC,0x0}, {0xFB48,0x5E8,0x5BC,0x0}, 
+  {0xFB49,0x5E9,0x5BC,0x0}, {0xFB4A,0x5EA,0x5BC,0x0}, {0xFB4B,0x5D5,0x5B9,0x0}, 
+  {0xFB4C,0x5D1,0x5BF,0x0}, {0xFB4D,0x5DB,0x5BF,0x0}, {0xFB4E,0x5E4,0x5BF,0x0} 
+};
+
+
+/* All upper-case translations are included here */
+
+#define NUM_TOUPPER_INFO 677
+static const unirelate toupper_info[NUM_TOUPPER_INFO] = {
+  {0x61,0x41}, {0x62,0x42}, {0x63,0x43}, {0x64,0x44}, {0x65,0x45}, 
+  {0x66,0x46}, {0x67,0x47}, {0x68,0x48}, {0x69,0x49}, {0x6A,0x4A}, 
+  {0x6B,0x4B}, {0x6C,0x4C}, {0x6D,0x4D}, {0x6E,0x4E}, {0x6F,0x4F}, 
+  {0x70,0x50}, {0x71,0x51}, {0x72,0x52}, {0x73,0x53}, {0x74,0x54}, 
+  {0x75,0x55}, {0x76,0x56}, {0x77,0x57}, {0x78,0x58}, {0x79,0x59}, 
+  {0x7A,0x5A}, {0xE0,0xC0}, {0xE1,0xC1}, {0xE2,0xC2}, {0xE3,0xC3}, 
+  {0xE4,0xC4}, {0xE5,0xC5}, {0xE6,0xC6}, {0xE7,0xC7}, {0xE8,0xC8}, 
+  {0xE9,0xC9}, {0xEA,0xCA}, {0xEB,0xCB}, {0xEC,0xCC}, {0xED,0xCD}, 
+  {0xEE,0xCE}, {0xEF,0xCF}, {0xF0,0xD0}, {0xF1,0xD1}, {0xF2,0xD2}, 
+  {0xF3,0xD3}, {0xF4,0xD4}, {0xF5,0xD5}, {0xF6,0xD6}, {0xF8,0xD8}, 
+  {0xF9,0xD9}, {0xFA,0xDA}, {0xFB,0xDB}, {0xFC,0xDC}, {0xFD,0xDD}, 
+  {0xFE,0xDE}, {0xFF,0x178}, {0x101,0x100}, {0x103,0x102}, {0x105,0x104}, 
+  {0x107,0x106}, {0x109,0x108}, {0x10B,0x10A}, {0x10D,0x10C}, {0x10F,0x10E}, 
+  {0x111,0x110}, {0x113,0x112}, {0x115,0x114}, {0x117,0x116}, {0x119,0x118}, 
+  {0x11B,0x11A}, {0x11D,0x11C}, {0x11F,0x11E}, {0x121,0x120}, {0x123,0x122}, 
+  {0x125,0x124}, {0x127,0x126}, {0x129,0x128}, {0x12B,0x12A}, {0x12D,0x12C}, 
+  {0x12F,0x12E}, {0x131,0x49}, {0x133,0x132}, {0x135,0x134}, {0x137,0x136}, 
+  {0x13A,0x139}, {0x13C,0x13B}, {0x13E,0x13D}, {0x140,0x13F}, {0x142,0x141}, 
+  {0x144,0x143}, {0x146,0x145}, {0x148,0x147}, {0x14B,0x14A}, {0x14D,0x14C}, 
+  {0x14F,0x14E}, {0x151,0x150}, {0x153,0x152}, {0x155,0x154}, {0x157,0x156}, 
+  {0x159,0x158}, {0x15B,0x15A}, {0x15D,0x15C}, {0x15F,0x15E}, {0x161,0x160}, 
+  {0x163,0x162}, {0x165,0x164}, {0x167,0x166}, {0x169,0x168}, {0x16B,0x16A}, 
+  {0x16D,0x16C}, {0x16F,0x16E}, {0x171,0x170}, {0x173,0x172}, {0x175,0x174}, 
+  {0x177,0x176}, {0x17A,0x179}, {0x17C,0x17B}, {0x17E,0x17D}, {0x17F,0x53}, 
+  {0x183,0x182}, {0x185,0x184}, {0x188,0x187}, {0x18C,0x18B}, {0x192,0x191}, 
+  {0x199,0x198}, {0x1A1,0x1A0}, {0x1A3,0x1A2}, {0x1A5,0x1A4}, {0x1A8,0x1A7}, 
+  {0x1AD,0x1AC}, {0x1B0,0x1AF}, {0x1B4,0x1B3}, {0x1B6,0x1B5}, {0x1B9,0x1B8}, 
+  {0x1BD,0x1BC}, {0x1C5,0x1C4}, {0x1C6,0x1C4}, {0x1C8,0x1C7}, {0x1C9,0x1C7}, 
+  {0x1CB,0x1CA}, {0x1CC,0x1CA}, {0x1CE,0x1CD}, {0x1D0,0x1CF}, {0x1D2,0x1D1}, 
+  {0x1D4,0x1D3}, {0x1D6,0x1D5}, {0x1D8,0x1D7}, {0x1DA,0x1D9}, {0x1DC,0x1DB}, 
+  {0x1DD,0x18E}, {0x1DF,0x1DE}, {0x1E1,0x1E0}, {0x1E3,0x1E2}, {0x1E5,0x1E4}, 
+  {0x1E7,0x1E6}, {0x1E9,0x1E8}, {0x1EB,0x1EA}, {0x1ED,0x1EC}, {0x1EF,0x1EE}, 
+  {0x1F2,0x1F1}, {0x1F3,0x1F1}, {0x1F5,0x1F4}, {0x1FB,0x1FA}, {0x1FD,0x1FC}, 
+  {0x1FF,0x1FE}, {0x201,0x200}, {0x203,0x202}, {0x205,0x204}, {0x207,0x206}, 
+  {0x209,0x208}, {0x20B,0x20A}, {0x20D,0x20C}, {0x20F,0x20E}, {0x211,0x210}, 
+  {0x213,0x212}, {0x215,0x214}, {0x217,0x216}, {0x253,0x181}, {0x254,0x186}, 
+  {0x256,0x189}, {0x257,0x18A}, {0x259,0x18F}, {0x25B,0x190}, {0x260,0x193}, 
+  {0x263,0x194}, {0x268,0x197}, {0x269,0x196}, {0x26F,0x19C}, {0x272,0x19D}, 
+  {0x275,0x19F}, {0x283,0x1A9}, {0x288,0x1AE}, {0x28A,0x1B1}, {0x28B,0x1B2}, 
+  {0x292,0x1B7}, {0x3AC,0x386}, {0x3AD,0x388}, {0x3AE,0x389}, {0x3AF,0x38A}, 
+  {0x3B1,0x391}, {0x3B2,0x392}, {0x3B3,0x393}, {0x3B4,0x394}, {0x3B5,0x395}, 
+  {0x3B6,0x396}, {0x3B7,0x397}, {0x3B8,0x398}, {0x3B9,0x399}, {0x3BA,0x39A}, 
+  {0x3BB,0x39B}, {0x3BC,0x39C}, {0x3BD,0x39D}, {0x3BE,0x39E}, {0x3BF,0x39F}, 
+  {0x3C0,0x3A0}, {0x3C1,0x3A1}, {0x3C2,0x3A3}, {0x3C3,0x3A3}, {0x3C4,0x3A4}, 
+  {0x3C5,0x3A5}, {0x3C6,0x3A6}, {0x3C7,0x3A7}, {0x3C8,0x3A8}, {0x3C9,0x3A9}, 
+  {0x3CA,0x3AA}, {0x3CB,0x3AB}, {0x3CC,0x38C}, {0x3CD,0x38E}, {0x3CE,0x38F}, 
+  {0x3D0,0x392}, {0x3D1,0x398}, {0x3D5,0x3A6}, {0x3D6,0x3A0}, {0x3E3,0x3E2}, 
+  {0x3E5,0x3E4}, {0x3E7,0x3E6}, {0x3E9,0x3E8}, {0x3EB,0x3EA}, {0x3ED,0x3EC}, 
+  {0x3EF,0x3EE}, {0x3F0,0x39A}, {0x3F1,0x3A1}, {0x3F2,0x3A3}, {0x430,0x410}, 
+  {0x431,0x411}, {0x432,0x412}, {0x433,0x413}, {0x434,0x414}, {0x435,0x415}, 
+  {0x436,0x416}, {0x437,0x417}, {0x438,0x418}, {0x439,0x419}, {0x43A,0x41A}, 
+  {0x43B,0x41B}, {0x43C,0x41C}, {0x43D,0x41D}, {0x43E,0x41E}, {0x43F,0x41F}, 
+  {0x440,0x420}, {0x441,0x421}, {0x442,0x422}, {0x443,0x423}, {0x444,0x424}, 
+  {0x445,0x425}, {0x446,0x426}, {0x447,0x427}, {0x448,0x428}, {0x449,0x429}, 
+  {0x44A,0x42A}, {0x44B,0x42B}, {0x44C,0x42C}, {0x44D,0x42D}, {0x44E,0x42E}, 
+  {0x44F,0x42F}, {0x451,0x401}, {0x452,0x402}, {0x453,0x403}, {0x454,0x404}, 
+  {0x455,0x405}, {0x456,0x406}, {0x457,0x407}, {0x458,0x408}, {0x459,0x409}, 
+  {0x45A,0x40A}, {0x45B,0x40B}, {0x45C,0x40C}, {0x45E,0x40E}, {0x45F,0x40F}, 
+  {0x461,0x460}, {0x463,0x462}, {0x465,0x464}, {0x467,0x466}, {0x469,0x468}, 
+  {0x46B,0x46A}, {0x46D,0x46C}, {0x46F,0x46E}, {0x471,0x470}, {0x473,0x472}, 
+  {0x475,0x474}, {0x477,0x476}, {0x479,0x478}, {0x47B,0x47A}, {0x47D,0x47C}, 
+  {0x47F,0x47E}, {0x481,0x480}, {0x491,0x490}, {0x493,0x492}, {0x495,0x494}, 
+  {0x497,0x496}, {0x499,0x498}, {0x49B,0x49A}, {0x49D,0x49C}, {0x49F,0x49E}, 
+  {0x4A1,0x4A0}, {0x4A3,0x4A2}, {0x4A5,0x4A4}, {0x4A7,0x4A6}, {0x4A9,0x4A8}, 
+  {0x4AB,0x4AA}, {0x4AD,0x4AC}, {0x4AF,0x4AE}, {0x4B1,0x4B0}, {0x4B3,0x4B2}, 
+  {0x4B5,0x4B4}, {0x4B7,0x4B6}, {0x4B9,0x4B8}, {0x4BB,0x4BA}, {0x4BD,0x4BC}, 
+  {0x4BF,0x4BE}, {0x4C2,0x4C1}, {0x4C4,0x4C3}, {0x4C8,0x4C7}, {0x4CC,0x4CB}, 
+  {0x4D1,0x4D0}, {0x4D3,0x4D2}, {0x4D5,0x4D4}, {0x4D7,0x4D6}, {0x4D9,0x4D8}, 
+  {0x4DB,0x4DA}, {0x4DD,0x4DC}, {0x4DF,0x4DE}, {0x4E1,0x4E0}, {0x4E3,0x4E2}, 
+  {0x4E5,0x4E4}, {0x4E7,0x4E6}, {0x4E9,0x4E8}, {0x4EB,0x4EA}, {0x4EF,0x4EE}, 
+  {0x4F1,0x4F0}, {0x4F3,0x4F2}, {0x4F5,0x4F4}, {0x4F9,0x4F8}, {0x561,0x531}, 
+  {0x562,0x532}, {0x563,0x533}, {0x564,0x534}, {0x565,0x535}, {0x566,0x536}, 
+  {0x567,0x537}, {0x568,0x538}, {0x569,0x539}, {0x56A,0x53A}, {0x56B,0x53B}, 
+  {0x56C,0x53C}, {0x56D,0x53D}, {0x56E,0x53E}, {0x56F,0x53F}, {0x570,0x540}, 
+  {0x571,0x541}, {0x572,0x542}, {0x573,0x543}, {0x574,0x544}, {0x575,0x545}, 
+  {0x576,0x546}, {0x577,0x547}, {0x578,0x548}, {0x579,0x549}, {0x57A,0x54A}, 
+  {0x57B,0x54B}, {0x57C,0x54C}, {0x57D,0x54D}, {0x57E,0x54E}, {0x57F,0x54F}, 
+  {0x580,0x550}, {0x581,0x551}, {0x582,0x552}, {0x583,0x553}, {0x584,0x554}, 
+  {0x585,0x555}, {0x586,0x556}, {0x1E01,0x1E00}, {0x1E03,0x1E02}, {0x1E05,0x1E04}, 
+  {0x1E07,0x1E06}, {0x1E09,0x1E08}, {0x1E0B,0x1E0A}, {0x1E0D,0x1E0C}, {0x1E0F,0x1E0E}, 
+  {0x1E11,0x1E10}, {0x1E13,0x1E12}, {0x1E15,0x1E14}, {0x1E17,0x1E16}, {0x1E19,0x1E18}, 
+  {0x1E1B,0x1E1A}, {0x1E1D,0x1E1C}, {0x1E1F,0x1E1E}, {0x1E21,0x1E20}, {0x1E23,0x1E22}, 
+  {0x1E25,0x1E24}, {0x1E27,0x1E26}, {0x1E29,0x1E28}, {0x1E2B,0x1E2A}, {0x1E2D,0x1E2C}, 
+  {0x1E2F,0x1E2E}, {0x1E31,0x1E30}, {0x1E33,0x1E32}, {0x1E35,0x1E34}, {0x1E37,0x1E36}, 
+  {0x1E39,0x1E38}, {0x1E3B,0x1E3A}, {0x1E3D,0x1E3C}, {0x1E3F,0x1E3E}, {0x1E41,0x1E40}, 
+  {0x1E43,0x1E42}, {0x1E45,0x1E44}, {0x1E47,0x1E46}, {0x1E49,0x1E48}, {0x1E4B,0x1E4A}, 
+  {0x1E4D,0x1E4C}, {0x1E4F,0x1E4E}, {0x1E51,0x1E50}, {0x1E53,0x1E52}, {0x1E55,0x1E54}, 
+  {0x1E57,0x1E56}, {0x1E59,0x1E58}, {0x1E5B,0x1E5A}, {0x1E5D,0x1E5C}, {0x1E5F,0x1E5E}, 
+  {0x1E61,0x1E60}, {0x1E63,0x1E62}, {0x1E65,0x1E64}, {0x1E67,0x1E66}, {0x1E69,0x1E68}, 
+  {0x1E6B,0x1E6A}, {0x1E6D,0x1E6C}, {0x1E6F,0x1E6E}, {0x1E71,0x1E70}, {0x1E73,0x1E72}, 
+  {0x1E75,0x1E74}, {0x1E77,0x1E76}, {0x1E79,0x1E78}, {0x1E7B,0x1E7A}, {0x1E7D,0x1E7C}, 
+  {0x1E7F,0x1E7E}, {0x1E81,0x1E80}, {0x1E83,0x1E82}, {0x1E85,0x1E84}, {0x1E87,0x1E86}, 
+  {0x1E89,0x1E88}, {0x1E8B,0x1E8A}, {0x1E8D,0x1E8C}, {0x1E8F,0x1E8E}, {0x1E91,0x1E90}, 
+  {0x1E93,0x1E92}, {0x1E95,0x1E94}, {0x1E9B,0x1E60}, {0x1EA1,0x1EA0}, {0x1EA3,0x1EA2}, 
+  {0x1EA5,0x1EA4}, {0x1EA7,0x1EA6}, {0x1EA9,0x1EA8}, {0x1EAB,0x1EAA}, {0x1EAD,0x1EAC}, 
+  {0x1EAF,0x1EAE}, {0x1EB1,0x1EB0}, {0x1EB3,0x1EB2}, {0x1EB5,0x1EB4}, {0x1EB7,0x1EB6}, 
+  {0x1EB9,0x1EB8}, {0x1EBB,0x1EBA}, {0x1EBD,0x1EBC}, {0x1EBF,0x1EBE}, {0x1EC1,0x1EC0}, 
+  {0x1EC3,0x1EC2}, {0x1EC5,0x1EC4}, {0x1EC7,0x1EC6}, {0x1EC9,0x1EC8}, {0x1ECB,0x1ECA}, 
+  {0x1ECD,0x1ECC}, {0x1ECF,0x1ECE}, {0x1ED1,0x1ED0}, {0x1ED3,0x1ED2}, {0x1ED5,0x1ED4}, 
+  {0x1ED7,0x1ED6}, {0x1ED9,0x1ED8}, {0x1EDB,0x1EDA}, {0x1EDD,0x1EDC}, {0x1EDF,0x1EDE}, 
+  {0x1EE1,0x1EE0}, {0x1EE3,0x1EE2}, {0x1EE5,0x1EE4}, {0x1EE7,0x1EE6}, {0x1EE9,0x1EE8}, 
+  {0x1EEB,0x1EEA}, {0x1EED,0x1EEC}, {0x1EEF,0x1EEE}, {0x1EF1,0x1EF0}, {0x1EF3,0x1EF2}, 
+  {0x1EF5,0x1EF4}, {0x1EF7,0x1EF6}, {0x1EF9,0x1EF8}, {0x1F00,0x1F08}, {0x1F01,0x1F09}, 
+  {0x1F02,0x1F0A}, {0x1F03,0x1F0B}, {0x1F04,0x1F0C}, {0x1F05,0x1F0D}, {0x1F06,0x1F0E}, 
+  {0x1F07,0x1F0F}, {0x1F10,0x1F18}, {0x1F11,0x1F19}, {0x1F12,0x1F1A}, {0x1F13,0x1F1B}, 
+  {0x1F14,0x1F1C}, {0x1F15,0x1F1D}, {0x1F20,0x1F28}, {0x1F21,0x1F29}, {0x1F22,0x1F2A}, 
+  {0x1F23,0x1F2B}, {0x1F24,0x1F2C}, {0x1F25,0x1F2D}, {0x1F26,0x1F2E}, {0x1F27,0x1F2F}, 
+  {0x1F30,0x1F38}, {0x1F31,0x1F39}, {0x1F32,0x1F3A}, {0x1F33,0x1F3B}, {0x1F34,0x1F3C}, 
+  {0x1F35,0x1F3D}, {0x1F36,0x1F3E}, {0x1F37,0x1F3F}, {0x1F40,0x1F48}, {0x1F41,0x1F49}, 
+  {0x1F42,0x1F4A}, {0x1F43,0x1F4B}, {0x1F44,0x1F4C}, {0x1F45,0x1F4D}, {0x1F51,0x1F59}, 
+  {0x1F53,0x1F5B}, {0x1F55,0x1F5D}, {0x1F57,0x1F5F}, {0x1F60,0x1F68}, {0x1F61,0x1F69}, 
+  {0x1F62,0x1F6A}, {0x1F63,0x1F6B}, {0x1F64,0x1F6C}, {0x1F65,0x1F6D}, {0x1F66,0x1F6E}, 
+  {0x1F67,0x1F6F}, {0x1F70,0x1FBA}, {0x1F71,0x1FBB}, {0x1F72,0x1FC8}, {0x1F73,0x1FC9}, 
+  {0x1F74,0x1FCA}, {0x1F75,0x1FCB}, {0x1F76,0x1FDA}, {0x1F77,0x1FDB}, {0x1F78,0x1FF8}, 
+  {0x1F79,0x1FF9}, {0x1F7A,0x1FEA}, {0x1F7B,0x1FEB}, {0x1F7C,0x1FFA}, {0x1F7D,0x1FFB}, 
+  {0x1F80,0x1F88}, {0x1F81,0x1F89}, {0x1F82,0x1F8A}, {0x1F83,0x1F8B}, {0x1F84,0x1F8C}, 
+  {0x1F85,0x1F8D}, {0x1F86,0x1F8E}, {0x1F87,0x1F8F}, {0x1F90,0x1F98}, {0x1F91,0x1F99}, 
+  {0x1F92,0x1F9A}, {0x1F93,0x1F9B}, {0x1F94,0x1F9C}, {0x1F95,0x1F9D}, {0x1F96,0x1F9E}, 
+  {0x1F97,0x1F9F}, {0x1FA0,0x1FA8}, {0x1FA1,0x1FA9}, {0x1FA2,0x1FAA}, {0x1FA3,0x1FAB}, 
+  {0x1FA4,0x1FAC}, {0x1FA5,0x1FAD}, {0x1FA6,0x1FAE}, {0x1FA7,0x1FAF}, {0x1FB0,0x1FB8}, 
+  {0x1FB1,0x1FB9}, {0x1FB3,0x1FBC}, {0x1FC3,0x1FCC}, {0x1FD0,0x1FD8}, {0x1FD1,0x1FD9}, 
+  {0x1FE0,0x1FE8}, {0x1FE1,0x1FE9}, {0x1FE5,0x1FEC}, {0x1FF3,0x1FFC}, {0x2170,0x2160}, 
+  {0x2171,0x2161}, {0x2172,0x2162}, {0x2173,0x2163}, {0x2174,0x2164}, {0x2175,0x2165}, 
+  {0x2176,0x2166}, {0x2177,0x2167}, {0x2178,0x2168}, {0x2179,0x2169}, {0x217A,0x216A}, 
+  {0x217B,0x216B}, {0x217C,0x216C}, {0x217D,0x216D}, {0x217E,0x216E}, {0x217F,0x216F}, 
+  {0x24D0,0x24B6}, {0x24D1,0x24B7}, {0x24D2,0x24B8}, {0x24D3,0x24B9}, {0x24D4,0x24BA}, 
+  {0x24D5,0x24BB}, {0x24D6,0x24BC}, {0x24D7,0x24BD}, {0x24D8,0x24BE}, {0x24D9,0x24BF}, 
+  {0x24DA,0x24C0}, {0x24DB,0x24C1}, {0x24DC,0x24C2}, {0x24DD,0x24C3}, {0x24DE,0x24C4}, 
+  {0x24DF,0x24C5}, {0x24E0,0x24C6}, {0x24E1,0x24C7}, {0x24E2,0x24C8}, {0x24E3,0x24C9}, 
+  {0x24E4,0x24CA}, {0x24E5,0x24CB}, {0x24E6,0x24CC}, {0x24E7,0x24CD}, {0x24E8,0x24CE}, 
+  {0x24E9,0x24CF}, {0xFF41,0xFF21}, {0xFF42,0xFF22}, {0xFF43,0xFF23}, {0xFF44,0xFF24}, 
+  {0xFF45,0xFF25}, {0xFF46,0xFF26}, {0xFF47,0xFF27}, {0xFF48,0xFF28}, {0xFF49,0xFF29}, 
+  {0xFF4A,0xFF2A}, {0xFF4B,0xFF2B}, {0xFF4C,0xFF2C}, {0xFF4D,0xFF2D}, {0xFF4E,0xFF2E}, 
+  {0xFF4F,0xFF2F}, {0xFF50,0xFF30}, {0xFF51,0xFF31}, {0xFF52,0xFF32}, {0xFF53,0xFF33}, 
+  {0xFF54,0xFF34}, {0xFF55,0xFF35}, {0xFF56,0xFF36}, {0xFF57,0xFF37}, {0xFF58,0xFF38}, 
+  {0xFF59,0xFF39}, {0xFF5A,0xFF3A} 
+};
+
+
+
+/* All lower-case translations are included here */
+
+#define NUM_TOLOWER_INFO 705
+static const unirelate tolower_info[NUM_TOLOWER_INFO] = {
+  {0x41,0x61}, {0x42,0x62}, {0x43,0x63}, {0x44,0x64}, {0x45,0x65}, 
+  {0x46,0x66}, {0x47,0x67}, {0x48,0x68}, {0x49,0x69}, {0x4A,0x6A}, 
+  {0x4B,0x6B}, {0x4C,0x6C}, {0x4D,0x6D}, {0x4E,0x6E}, {0x4F,0x6F}, 
+  {0x50,0x70}, {0x51,0x71}, {0x52,0x72}, {0x53,0x73}, {0x54,0x74}, 
+  {0x55,0x75}, {0x56,0x76}, {0x57,0x77}, {0x58,0x78}, {0x59,0x79}, 
+  {0x5A,0x7A}, {0xC0,0xE0}, {0xC1,0xE1}, {0xC2,0xE2}, {0xC3,0xE3}, 
+  {0xC4,0xE4}, {0xC5,0xE5}, {0xC6,0xE6}, {0xC7,0xE7}, {0xC8,0xE8}, 
+  {0xC9,0xE9}, {0xCA,0xEA}, {0xCB,0xEB}, {0xCC,0xEC}, {0xCD,0xED}, 
+  {0xCE,0xEE}, {0xCF,0xEF}, {0xD0,0xF0}, {0xD1,0xF1}, {0xD2,0xF2}, 
+  {0xD3,0xF3}, {0xD4,0xF4}, {0xD5,0xF5}, {0xD6,0xF6}, {0xD8,0xF8}, 
+  {0xD9,0xF9}, {0xDA,0xFA}, {0xDB,0xFB}, {0xDC,0xFC}, {0xDD,0xFD}, 
+  {0xDE,0xFE}, {0x100,0x101}, {0x102,0x103}, {0x104,0x105}, {0x106,0x107}, 
+  {0x108,0x109}, {0x10A,0x10B}, {0x10C,0x10D}, {0x10E,0x10F}, {0x110,0x111}, 
+  {0x112,0x113}, {0x114,0x115}, {0x116,0x117}, {0x118,0x119}, {0x11A,0x11B}, 
+  {0x11C,0x11D}, {0x11E,0x11F}, {0x120,0x121}, {0x122,0x123}, {0x124,0x125}, 
+  {0x126,0x127}, {0x128,0x129}, {0x12A,0x12B}, {0x12C,0x12D}, {0x12E,0x12F}, 
+  {0x130,0x69}, {0x132,0x133}, {0x134,0x135}, {0x136,0x137}, {0x139,0x13A}, 
+  {0x13B,0x13C}, {0x13D,0x13E}, {0x13F,0x140}, {0x141,0x142}, {0x143,0x144}, 
+  {0x145,0x146}, {0x147,0x148}, {0x14A,0x14B}, {0x14C,0x14D}, {0x14E,0x14F}, 
+  {0x150,0x151}, {0x152,0x153}, {0x154,0x155}, {0x156,0x157}, {0x158,0x159}, 
+  {0x15A,0x15B}, {0x15C,0x15D}, {0x15E,0x15F}, {0x160,0x161}, {0x162,0x163}, 
+  {0x164,0x165}, {0x166,0x167}, {0x168,0x169}, {0x16A,0x16B}, {0x16C,0x16D}, 
+  {0x16E,0x16F}, {0x170,0x171}, {0x172,0x173}, {0x174,0x175}, {0x176,0x177}, 
+  {0x178,0xFF}, {0x179,0x17A}, {0x17B,0x17C}, {0x17D,0x17E}, {0x181,0x253}, 
+  {0x182,0x183}, {0x184,0x185}, {0x186,0x254}, {0x187,0x188}, {0x189,0x256}, 
+  {0x18A,0x257}, {0x18B,0x18C}, {0x18E,0x1DD}, {0x18F,0x259}, {0x190,0x25B}, 
+  {0x191,0x192}, {0x193,0x260}, {0x194,0x263}, {0x196,0x269}, {0x197,0x268}, 
+  {0x198,0x199}, {0x19C,0x26F}, {0x19D,0x272}, {0x19F,0x275}, {0x1A0,0x1A1}, 
+  {0x1A2,0x1A3}, {0x1A4,0x1A5}, {0x1A7,0x1A8}, {0x1A9,0x283}, {0x1AC,0x1AD}, 
+  {0x1AE,0x288}, {0x1AF,0x1B0}, {0x1B1,0x28A}, {0x1B2,0x28B}, {0x1B3,0x1B4}, 
+  {0x1B5,0x1B6}, {0x1B7,0x292}, {0x1B8,0x1B9}, {0x1BC,0x1BD}, {0x1C4,0x1C6}, 
+  {0x1C5,0x1C6}, {0x1C7,0x1C9}, {0x1C8,0x1C9}, {0x1CA,0x1CC}, {0x1CB,0x1CC}, 
+  {0x1CD,0x1CE}, {0x1CF,0x1D0}, {0x1D1,0x1D2}, {0x1D3,0x1D4}, {0x1D5,0x1D6}, 
+  {0x1D7,0x1D8}, {0x1D9,0x1DA}, {0x1DB,0x1DC}, {0x1DE,0x1DF}, {0x1E0,0x1E1}, 
+  {0x1E2,0x1E3}, {0x1E4,0x1E5}, {0x1E6,0x1E7}, {0x1E8,0x1E9}, {0x1EA,0x1EB}, 
+  {0x1EC,0x1ED}, {0x1EE,0x1EF}, {0x1F1,0x1F3}, {0x1F2,0x1F3}, {0x1F4,0x1F5}, 
+  {0x1FA,0x1FB}, {0x1FC,0x1FD}, {0x1FE,0x1FF}, {0x200,0x201}, {0x202,0x203}, 
+  {0x204,0x205}, {0x206,0x207}, {0x208,0x209}, {0x20A,0x20B}, {0x20C,0x20D}, 
+  {0x20E,0x20F}, {0x210,0x211}, {0x212,0x213}, {0x214,0x215}, {0x216,0x217}, 
+  {0x386,0x3AC}, {0x388,0x3AD}, {0x389,0x3AE}, {0x38A,0x3AF}, {0x38C,0x3CC}, 
+  {0x38E,0x3CD}, {0x38F,0x3CE}, {0x391,0x3B1}, {0x392,0x3B2}, {0x393,0x3B3}, 
+  {0x394,0x3B4}, {0x395,0x3B5}, {0x396,0x3B6}, {0x397,0x3B7}, {0x398,0x3B8}, 
+  {0x399,0x3B9}, {0x39A,0x3BA}, {0x39B,0x3BB}, {0x39C,0x3BC}, {0x39D,0x3BD}, 
+  {0x39E,0x3BE}, {0x39F,0x3BF}, {0x3A0,0x3C0}, {0x3A1,0x3C1}, {0x3A3,0x3C3}, 
+  {0x3A4,0x3C4}, {0x3A5,0x3C5}, {0x3A6,0x3C6}, {0x3A7,0x3C7}, {0x3A8,0x3C8}, 
+  {0x3A9,0x3C9}, {0x3AA,0x3CA}, {0x3AB,0x3CB}, {0x3E2,0x3E3}, {0x3E4,0x3E5}, 
+  {0x3E6,0x3E7}, {0x3E8,0x3E9}, {0x3EA,0x3EB}, {0x3EC,0x3ED}, {0x3EE,0x3EF}, 
+  {0x401,0x451}, {0x402,0x452}, {0x403,0x453}, {0x404,0x454}, {0x405,0x455}, 
+  {0x406,0x456}, {0x407,0x457}, {0x408,0x458}, {0x409,0x459}, {0x40A,0x45A}, 
+  {0x40B,0x45B}, {0x40C,0x45C}, {0x40E,0x45E}, {0x40F,0x45F}, {0x410,0x430}, 
+  {0x411,0x431}, {0x412,0x432}, {0x413,0x433}, {0x414,0x434}, {0x415,0x435}, 
+  {0x416,0x436}, {0x417,0x437}, {0x418,0x438}, {0x419,0x439}, {0x41A,0x43A}, 
+  {0x41B,0x43B}, {0x41C,0x43C}, {0x41D,0x43D}, {0x41E,0x43E}, {0x41F,0x43F}, 
+  {0x420,0x440}, {0x421,0x441}, {0x422,0x442}, {0x423,0x443}, {0x424,0x444}, 
+  {0x425,0x445}, {0x426,0x446}, {0x427,0x447}, {0x428,0x448}, {0x429,0x449}, 
+  {0x42A,0x44A}, {0x42B,0x44B}, {0x42C,0x44C}, {0x42D,0x44D}, {0x42E,0x44E}, 
+  {0x42F,0x44F}, {0x460,0x461}, {0x462,0x463}, {0x464,0x465}, {0x466,0x467}, 
+  {0x468,0x469}, {0x46A,0x46B}, {0x46C,0x46D}, {0x46E,0x46F}, {0x470,0x471}, 
+  {0x472,0x473}, {0x474,0x475}, {0x476,0x477}, {0x478,0x479}, {0x47A,0x47B}, 
+  {0x47C,0x47D}, {0x47E,0x47F}, {0x480,0x481}, {0x490,0x491}, {0x492,0x493}, 
+  {0x494,0x495}, {0x496,0x497}, {0x498,0x499}, {0x49A,0x49B}, {0x49C,0x49D}, 
+  {0x49E,0x49F}, {0x4A0,0x4A1}, {0x4A2,0x4A3}, {0x4A4,0x4A5}, {0x4A6,0x4A7}, 
+  {0x4A8,0x4A9}, {0x4AA,0x4AB}, {0x4AC,0x4AD}, {0x4AE,0x4AF}, {0x4B0,0x4B1}, 
+  {0x4B2,0x4B3}, {0x4B4,0x4B5}, {0x4B6,0x4B7}, {0x4B8,0x4B9}, {0x4BA,0x4BB}, 
+  {0x4BC,0x4BD}, {0x4BE,0x4BF}, {0x4C1,0x4C2}, {0x4C3,0x4C4}, {0x4C7,0x4C8}, 
+  {0x4CB,0x4CC}, {0x4D0,0x4D1}, {0x4D2,0x4D3}, {0x4D4,0x4D5}, {0x4D6,0x4D7}, 
+  {0x4D8,0x4D9}, {0x4DA,0x4DB}, {0x4DC,0x4DD}, {0x4DE,0x4DF}, {0x4E0,0x4E1}, 
+  {0x4E2,0x4E3}, {0x4E4,0x4E5}, {0x4E6,0x4E7}, {0x4E8,0x4E9}, {0x4EA,0x4EB}, 
+  {0x4EE,0x4EF}, {0x4F0,0x4F1}, {0x4F2,0x4F3}, {0x4F4,0x4F5}, {0x4F8,0x4F9}, 
+  {0x531,0x561}, {0x532,0x562}, {0x533,0x563}, {0x534,0x564}, {0x535,0x565}, 
+  {0x536,0x566}, {0x537,0x567}, {0x538,0x568}, {0x539,0x569}, {0x53A,0x56A}, 
+  {0x53B,0x56B}, {0x53C,0x56C}, {0x53D,0x56D}, {0x53E,0x56E}, {0x53F,0x56F}, 
+  {0x540,0x570}, {0x541,0x571}, {0x542,0x572}, {0x543,0x573}, {0x544,0x574}, 
+  {0x545,0x575}, {0x546,0x576}, {0x547,0x577}, {0x548,0x578}, {0x549,0x579}, 
+  {0x54A,0x57A}, {0x54B,0x57B}, {0x54C,0x57C}, {0x54D,0x57D}, {0x54E,0x57E}, 
+  {0x54F,0x57F}, {0x550,0x580}, {0x551,0x581}, {0x552,0x582}, {0x553,0x583}, 
+  {0x554,0x584}, {0x555,0x585}, {0x556,0x586}, {0x10A0,0x10D0}, {0x10A1,0x10D1}, 
+  {0x10A2,0x10D2}, {0x10A3,0x10D3}, {0x10A4,0x10D4}, {0x10A5,0x10D5}, {0x10A6,0x10D6}, 
+  {0x10A7,0x10D7}, {0x10A8,0x10D8}, {0x10A9,0x10D9}, {0x10AA,0x10DA}, {0x10AB,0x10DB}, 
+  {0x10AC,0x10DC}, {0x10AD,0x10DD}, {0x10AE,0x10DE}, {0x10AF,0x10DF}, {0x10B0,0x10E0}, 
+  {0x10B1,0x10E1}, {0x10B2,0x10E2}, {0x10B3,0x10E3}, {0x10B4,0x10E4}, {0x10B5,0x10E5}, 
+  {0x10B6,0x10E6}, {0x10B7,0x10E7}, {0x10B8,0x10E8}, {0x10B9,0x10E9}, {0x10BA,0x10EA}, 
+  {0x10BB,0x10EB}, {0x10BC,0x10EC}, {0x10BD,0x10ED}, {0x10BE,0x10EE}, {0x10BF,0x10EF}, 
+  {0x10C0,0x10F0}, {0x10C1,0x10F1}, {0x10C2,0x10F2}, {0x10C3,0x10F3}, {0x10C4,0x10F4}, 
+  {0x10C5,0x10F5}, {0x1E00,0x1E01}, {0x1E02,0x1E03}, {0x1E04,0x1E05}, {0x1E06,0x1E07}, 
+  {0x1E08,0x1E09}, {0x1E0A,0x1E0B}, {0x1E0C,0x1E0D}, {0x1E0E,0x1E0F}, {0x1E10,0x1E11}, 
+  {0x1E12,0x1E13}, {0x1E14,0x1E15}, {0x1E16,0x1E17}, {0x1E18,0x1E19}, {0x1E1A,0x1E1B}, 
+  {0x1E1C,0x1E1D}, {0x1E1E,0x1E1F}, {0x1E20,0x1E21}, {0x1E22,0x1E23}, {0x1E24,0x1E25}, 
+  {0x1E26,0x1E27}, {0x1E28,0x1E29}, {0x1E2A,0x1E2B}, {0x1E2C,0x1E2D}, {0x1E2E,0x1E2F}, 
+  {0x1E30,0x1E31}, {0x1E32,0x1E33}, {0x1E34,0x1E35}, {0x1E36,0x1E37}, {0x1E38,0x1E39}, 
+  {0x1E3A,0x1E3B}, {0x1E3C,0x1E3D}, {0x1E3E,0x1E3F}, {0x1E40,0x1E41}, {0x1E42,0x1E43}, 
+  {0x1E44,0x1E45}, {0x1E46,0x1E47}, {0x1E48,0x1E49}, {0x1E4A,0x1E4B}, {0x1E4C,0x1E4D}, 
+  {0x1E4E,0x1E4F}, {0x1E50,0x1E51}, {0x1E52,0x1E53}, {0x1E54,0x1E55}, {0x1E56,0x1E57}, 
+  {0x1E58,0x1E59}, {0x1E5A,0x1E5B}, {0x1E5C,0x1E5D}, {0x1E5E,0x1E5F}, {0x1E60,0x1E61}, 
+  {0x1E62,0x1E63}, {0x1E64,0x1E65}, {0x1E66,0x1E67}, {0x1E68,0x1E69}, {0x1E6A,0x1E6B}, 
+  {0x1E6C,0x1E6D}, {0x1E6E,0x1E6F}, {0x1E70,0x1E71}, {0x1E72,0x1E73}, {0x1E74,0x1E75}, 
+  {0x1E76,0x1E77}, {0x1E78,0x1E79}, {0x1E7A,0x1E7B}, {0x1E7C,0x1E7D}, {0x1E7E,0x1E7F}, 
+  {0x1E80,0x1E81}, {0x1E82,0x1E83}, {0x1E84,0x1E85}, {0x1E86,0x1E87}, {0x1E88,0x1E89}, 
+  {0x1E8A,0x1E8B}, {0x1E8C,0x1E8D}, {0x1E8E,0x1E8F}, {0x1E90,0x1E91}, {0x1E92,0x1E93}, 
+  {0x1E94,0x1E95}, {0x1EA0,0x1EA1}, {0x1EA2,0x1EA3}, {0x1EA4,0x1EA5}, {0x1EA6,0x1EA7}, 
+  {0x1EA8,0x1EA9}, {0x1EAA,0x1EAB}, {0x1EAC,0x1EAD}, {0x1EAE,0x1EAF}, {0x1EB0,0x1EB1}, 
+  {0x1EB2,0x1EB3}, {0x1EB4,0x1EB5}, {0x1EB6,0x1EB7}, {0x1EB8,0x1EB9}, {0x1EBA,0x1EBB}, 
+  {0x1EBC,0x1EBD}, {0x1EBE,0x1EBF}, {0x1EC0,0x1EC1}, {0x1EC2,0x1EC3}, {0x1EC4,0x1EC5}, 
+  {0x1EC6,0x1EC7}, {0x1EC8,0x1EC9}, {0x1ECA,0x1ECB}, {0x1ECC,0x1ECD}, {0x1ECE,0x1ECF}, 
+  {0x1ED0,0x1ED1}, {0x1ED2,0x1ED3}, {0x1ED4,0x1ED5}, {0x1ED6,0x1ED7}, {0x1ED8,0x1ED9}, 
+  {0x1EDA,0x1EDB}, {0x1EDC,0x1EDD}, {0x1EDE,0x1EDF}, {0x1EE0,0x1EE1}, {0x1EE2,0x1EE3}, 
+  {0x1EE4,0x1EE5}, {0x1EE6,0x1EE7}, {0x1EE8,0x1EE9}, {0x1EEA,0x1EEB}, {0x1EEC,0x1EED}, 
+  {0x1EEE,0x1EEF}, {0x1EF0,0x1EF1}, {0x1EF2,0x1EF3}, {0x1EF4,0x1EF5}, {0x1EF6,0x1EF7}, 
+  {0x1EF8,0x1EF9}, {0x1F08,0x1F00}, {0x1F09,0x1F01}, {0x1F0A,0x1F02}, {0x1F0B,0x1F03}, 
+  {0x1F0C,0x1F04}, {0x1F0D,0x1F05}, {0x1F0E,0x1F06}, {0x1F0F,0x1F07}, {0x1F18,0x1F10}, 
+  {0x1F19,0x1F11}, {0x1F1A,0x1F12}, {0x1F1B,0x1F13}, {0x1F1C,0x1F14}, {0x1F1D,0x1F15}, 
+  {0x1F28,0x1F20}, {0x1F29,0x1F21}, {0x1F2A,0x1F22}, {0x1F2B,0x1F23}, {0x1F2C,0x1F24}, 
+  {0x1F2D,0x1F25}, {0x1F2E,0x1F26}, {0x1F2F,0x1F27}, {0x1F38,0x1F30}, {0x1F39,0x1F31}, 
+  {0x1F3A,0x1F32}, {0x1F3B,0x1F33}, {0x1F3C,0x1F34}, {0x1F3D,0x1F35}, {0x1F3E,0x1F36}, 
+  {0x1F3F,0x1F37}, {0x1F48,0x1F40}, {0x1F49,0x1F41}, {0x1F4A,0x1F42}, {0x1F4B,0x1F43}, 
+  {0x1F4C,0x1F44}, {0x1F4D,0x1F45}, {0x1F59,0x1F51}, {0x1F5B,0x1F53}, {0x1F5D,0x1F55}, 
+  {0x1F5F,0x1F57}, {0x1F68,0x1F60}, {0x1F69,0x1F61}, {0x1F6A,0x1F62}, {0x1F6B,0x1F63}, 
+  {0x1F6C,0x1F64}, {0x1F6D,0x1F65}, {0x1F6E,0x1F66}, {0x1F6F,0x1F67}, {0x1F88,0x1F80}, 
+  {0x1F89,0x1F81}, {0x1F8A,0x1F82}, {0x1F8B,0x1F83}, {0x1F8C,0x1F84}, {0x1F8D,0x1F85}, 
+  {0x1F8E,0x1F86}, {0x1F8F,0x1F87}, {0x1F98,0x1F90}, {0x1F99,0x1F91}, {0x1F9A,0x1F92}, 
+  {0x1F9B,0x1F93}, {0x1F9C,0x1F94}, {0x1F9D,0x1F95}, {0x1F9E,0x1F96}, {0x1F9F,0x1F97}, 
+  {0x1FA8,0x1FA0}, {0x1FA9,0x1FA1}, {0x1FAA,0x1FA2}, {0x1FAB,0x1FA3}, {0x1FAC,0x1FA4}, 
+  {0x1FAD,0x1FA5}, {0x1FAE,0x1FA6}, {0x1FAF,0x1FA7}, {0x1FB8,0x1FB0}, {0x1FB9,0x1FB1}, 
+  {0x1FBA,0x1F70}, {0x1FBB,0x1F71}, {0x1FBC,0x1FB3}, {0x1FC8,0x1F72}, {0x1FC9,0x1F73}, 
+  {0x1FCA,0x1F74}, {0x1FCB,0x1F75}, {0x1FCC,0x1FC3}, {0x1FD8,0x1FD0}, {0x1FD9,0x1FD1}, 
+  {0x1FDA,0x1F76}, {0x1FDB,0x1F77}, {0x1FE8,0x1FE0}, {0x1FE9,0x1FE1}, {0x1FEA,0x1F7A}, 
+  {0x1FEB,0x1F7B}, {0x1FEC,0x1FE5}, {0x1FF8,0x1F78}, {0x1FF9,0x1F79}, {0x1FFA,0x1F7C}, 
+  {0x1FFB,0x1F7D}, {0x1FFC,0x1FF3}, {0x2160,0x2170}, {0x2161,0x2171}, {0x2162,0x2172}, 
+  {0x2163,0x2173}, {0x2164,0x2174}, {0x2165,0x2175}, {0x2166,0x2176}, {0x2167,0x2177}, 
+  {0x2168,0x2178}, {0x2169,0x2179}, {0x216A,0x217A}, {0x216B,0x217B}, {0x216C,0x217C}, 
+  {0x216D,0x217D}, {0x216E,0x217E}, {0x216F,0x217F}, {0x24B6,0x24D0}, {0x24B7,0x24D1}, 
+  {0x24B8,0x24D2}, {0x24B9,0x24D3}, {0x24BA,0x24D4}, {0x24BB,0x24D5}, {0x24BC,0x24D6}, 
+  {0x24BD,0x24D7}, {0x24BE,0x24D8}, {0x24BF,0x24D9}, {0x24C0,0x24DA}, {0x24C1,0x24DB}, 
+  {0x24C2,0x24DC}, {0x24C3,0x24DD}, {0x24C4,0x24DE}, {0x24C5,0x24DF}, {0x24C6,0x24E0}, 
+  {0x24C7,0x24E1}, {0x24C8,0x24E2}, {0x24C9,0x24E3}, {0x24CA,0x24E4}, {0x24CB,0x24E5}, 
+  {0x24CC,0x24E6}, {0x24CD,0x24E7}, {0x24CE,0x24E8}, {0x24CF,0x24E9}, {0xFF21,0xFF41}, 
+  {0xFF22,0xFF42}, {0xFF23,0xFF43}, {0xFF24,0xFF44}, {0xFF25,0xFF45}, {0xFF26,0xFF46}, 
+  {0xFF27,0xFF47}, {0xFF28,0xFF48}, {0xFF29,0xFF49}, {0xFF2A,0xFF4A}, {0xFF2B,0xFF4B}, 
+  {0xFF2C,0xFF4C}, {0xFF2D,0xFF4D}, {0xFF2E,0xFF4E}, {0xFF2F,0xFF4F}, {0xFF30,0xFF50}, 
+  {0xFF31,0xFF51}, {0xFF32,0xFF52}, {0xFF33,0xFF53}, {0xFF34,0xFF54}, {0xFF35,0xFF55}, 
+  {0xFF36,0xFF56}, {0xFF37,0xFF57}, {0xFF38,0xFF58}, {0xFF39,0xFF59}, {0xFF3A,0xFF5A}
+};
+
+
+
+#define NUM_TOSIMPLIFIED_INFO 2145
+static const unirelate tosimplified_info[NUM_TOSIMPLIFIED_INFO] = {
+  {0x4E48,0x9EBD}, {0x4E82,0x4E71}, {0x4E9E,0x4E9A}, {0x4F47,0x4F2B}, {0x4F59,0x9980}, 
+  {0x4F86,0x6765}, {0x4F96,0x4ED1}, {0x4FE0,0x4FA0}, {0x5000,0x4F25}, {0x5006,0x4FE9}, 
+  {0x5009,0x4ED3}, {0x500B,0x4E2A}, {0x5011,0x4EEC}, {0x502B,0x4F26}, {0x5049,0x4F1F}, 
+  {0x5074,0x4FA7}, {0x5075,0x4FA6}, {0x5096,0x4F27}, {0x5098,0x4F1E}, {0x5099,0x5907}, 
+  {0x50AD,0x4F63}, {0x50B3,0x4F20}, {0x50B4,0x4F1B}, {0x50B5,0x503A}, {0x50B7,0x4F24}, 
+  {0x50BE,0x503E}, {0x50C2,0x507B}, {0x50C5,0x4EC5}, {0x50C9,0x4F65}, {0x50D1,0x4FA8}, 
+  {0x50D5,0x4EC6}, {0x50DE,0x4F2A}, {0x50E5,0x4FA5}, {0x50E8,0x507E}, {0x50F9,0x4EF7}, 
+  {0x5100,0x4EEA}, {0x5102,0x4FAC}, {0x5104,0x4EBF}, {0x5108,0x4FA9}, {0x5109,0x4FED}, 
+  {0x5110,0x50A7}, {0x5114,0x4FE6}, {0x5115,0x4FAA}, {0x511F,0x507F}, {0x512A,0x4F18}, 
+  {0x5132,0x50A8}, {0x5137,0x4FEA}, {0x513A,0x50A9}, {0x513B,0x50A5}, {0x513C,0x4FE8}, 
+  {0x5152,0x513F}, {0x5169,0x4E24}, {0x51C8,0x51C0}, {0x51CD,0x51BB}, {0x51F1,0x51EF}, 
+  {0x5244,0x522D}, {0x5247,0x5219}, {0x525B,0x521A}, {0x526E,0x5250}, {0x5274,0x5240}, 
+  {0x5275,0x521B}, {0x5283,0x5212}, {0x5287,0x5267}, {0x5289,0x5218}, {0x528A,0x523D}, 
+  {0x528C,0x523F}, {0x528D,0x5251}, {0x5291,0x5242}, {0x52C1,0x52B2}, {0x52D5,0x52A8}, 
+  {0x52D9,0x52A1}, {0x52DB,0x52CB}, {0x52DD,0x80DC}, {0x52DE,0x52B3}, {0x52E2,0x52BF}, 
+  {0x52F1,0x52A2}, {0x52F5,0x52B1}, {0x52F8,0x529D}, {0x532D,0x5326}, {0x532F,0x6C47}, 
+  {0x5331,0x532E}, {0x5340,0x533A}, {0x5354,0x534F}, {0x5399,0x538D}, {0x53A0,0x5395}, 
+  {0x53AD,0x538C}, {0x53B2,0x5389}, {0x53B4,0x53A3}, {0x53C3,0x53C2}, {0x53E2,0x4E1B}, 
+  {0x540E,0x5F8C}, {0x54BC,0x5459}, {0x54E1,0x5458}, {0x5504,0x5457}, {0x554F,0x95EE}, 
+  {0x5553,0x542F}, {0x555E,0x54D1}, {0x559A,0x5524}, {0x55AA,0x4E27}, {0x55AC,0x4E54}, 
+  {0x55AE,0x5355}, {0x55B2,0x54DF}, {0x55C6,0x545B}, {0x55C7,0x556C}, {0x55CE,0x5417}, 
+  {0x55DA,0x545C}, {0x55E9,0x5522}, {0x55F6,0x54D4}, {0x5606,0x53F9}, {0x560D,0x55BD}, 
+  {0x5614,0x5455}, {0x5616,0x5567}, {0x5617,0x5C1D}, {0x561C,0x551B}, {0x5629,0x54D7}, 
+  {0x562E,0x5520}, {0x562F,0x5578}, {0x5630,0x53FD}, {0x5635,0x54D3}, {0x5638,0x5452}, 
+  {0x565D,0x549D}, {0x5660,0x54D2}, {0x5665,0x54DD}, {0x5666,0x54D5}, {0x566F,0x55F3}, 
+  {0x5672,0x54D9}, {0x5674,0x55B7}, {0x5678,0x5428}, {0x5680,0x549B}, {0x5687,0x5413}, 
+  {0x568C,0x54DC}, {0x5695,0x565C}, {0x5699,0x556E}, {0x56A6,0x5456}, {0x56A8,0x5499}, 
+  {0x56B3,0x55BE}, {0x56B4,0x4E25}, {0x56B6,0x5624}, {0x56C0,0x556D}, {0x56C1,0x55EB}, 
+  {0x56C2,0x56A3}, {0x56C5,0x5181}, {0x56C8,0x5453}, {0x56D1,0x5631}, {0x5707,0x56F5}, 
+  {0x570B,0x56FD}, {0x570D,0x56F4}, {0x5712,0x56ED}, {0x5713,0x5706}, {0x5716,0x56FE}, 
+  {0x5718,0x56E2}, {0x57E1,0x57AD}, {0x57F7,0x6267}, {0x5805,0x575A}, {0x580A,0x57A9}, 
+  {0x5816,0x57B4}, {0x581D,0x57DA}, {0x582F,0x5C27}, {0x5831,0x62A5}, {0x5834,0x573A}, 
+  {0x584A,0x5757}, {0x584B,0x8314}, {0x584F,0x57B2}, {0x5852,0x57D8}, {0x5857,0x6D82}, 
+  {0x5862,0x575E}, {0x5864,0x57D9}, {0x5875,0x5C18}, {0x5879,0x5811}, {0x588A,0x57AB}, 
+  {0x589C,0x5760}, {0x58AE,0x5815}, {0x58B3,0x575F}, {0x58BB,0x5899}, {0x58BE,0x57A6}, 
+  {0x58C7,0x575B}, {0x58D3,0x538B}, {0x58D8,0x5792}, {0x58D9,0x5739}, {0x58DA,0x5786}, 
+  {0x58DE,0x574F}, {0x58DF,0x5784}, {0x58E0,0x5785}, {0x58E2,0x575C}, {0x58E9,0x575D}, 
+  {0x58EF,0x58EE}, {0x58FA,0x58F6}, {0x58FD,0x5BFF}, {0x5922,0x68A6}, {0x593E,0x5939}, 
+  {0x5950,0x5942}, {0x5969,0x5941}, {0x596A,0x593A}, {0x596C,0x5956}, {0x596E,0x594B}, 
+  {0x599D,0x5986}, {0x5A41,0x5A04}, {0x5A66,0x5987}, {0x5A6D,0x5A05}, {0x5AA7,0x5A32}, 
+  {0x5ABD,0x5988}, {0x5AD7,0x59AA}, {0x5AF5,0x59A9}, {0x5AFB,0x5A34}, {0x5B00,0x59AB}, 
+  {0x5B08,0x5A06}, {0x5B0B,0x5A75}, {0x5B0C,0x5A07}, {0x5B19,0x5AF1}, {0x5B21,0x5AD2}, 
+  {0x5B2A,0x5AD4}, {0x5B30,0x5A74}, {0x5B38,0x5A76}, {0x5B4C,0x5A08}, {0x5B6B,0x5B59}, 
+  {0x5B78,0x5B66}, {0x5B7F,0x5B6A}, {0x5BE2,0x5BDD}, {0x5BE6,0x5B9E}, {0x5BE7,0x5B81}, 
+  {0x5BE9,0x5BA1}, {0x5BEB,0x5199}, {0x5BEC,0x5BBD}, {0x5BF5,0x5BA0}, {0x5BF6,0x5B9D}, 
+  {0x5C07,0x5C06}, {0x5C08,0x4E13}, {0x5C0B,0x5BFB}, {0x5C0D,0x5BF9}, {0x5C0E,0x5BFC}, 
+  {0x5C37,0x5C34}, {0x5C62,0x5C61}, {0x5C64,0x5C42}, {0x5C68,0x5C66}, {0x5C6C,0x5C5E}, 
+  {0x5CA1,0x5188}, {0x5CF4,0x5C98}, {0x5CF6,0x5C9B}, {0x5CFD,0x5CE1}, {0x5D0D,0x5D03}, 
+  {0x5D17,0x5C97}, {0x5D22,0x5CE5}, {0x5D2C,0x5CBD}, {0x5D50,0x5C9A}, {0x5D81,0x5D5D}, 
+  {0x5D84,0x5D2D}, {0x5D87,0x5C96}, {0x5D97,0x5D02}, {0x5DA0,0x5CE4}, {0x5DA7,0x5CC4}, 
+  {0x5DB8,0x5D58}, {0x5DBA,0x5CAD}, {0x5DBC,0x5C7F}, {0x5DCB,0x5CBF}, {0x5DD2,0x5CE6}, 
+  {0x5DD4,0x5DC5}, {0x5DF0,0x5DEF}, {0x5E25,0x5E05}, {0x5E2B,0x5E08}, {0x5E33,0x5E10}, 
+  {0x5E36,0x5E26}, {0x5E40,0x5E27}, {0x5E43,0x5E0F}, {0x5E57,0x5E3C}, {0x5E58,0x5E3B}, 
+  {0x5E5F,0x5E1C}, {0x5E63,0x5E01}, {0x5E6B,0x5E2E}, {0x5E6C,0x5E31}, {0x5E79,0x5E72}, 
+  {0x5E7E,0x51E0}, {0x5EAB,0x5E93}, {0x5EDF,0x5E99}, {0x5EE0,0x5382}, {0x5EE1,0x5E91}, 
+  {0x5EE2,0x5E9F}, {0x5EE3,0x5E7F}, {0x5EEC,0x5E90}, {0x5EF3,0x5385}, {0x5F33,0x5F2A}, 
+  {0x5F35,0x5F20}, {0x5F48,0x5F39}, {0x5F4C,0x5F25}, {0x5F4E,0x5F2F}, {0x5F8C,0x540E}, 
+  {0x5F91,0x5F84}, {0x5F9E,0x4ECE}, {0x5FA0,0x5F95}, {0x5FA9,0x590D}, {0x5FB9,0x5F7B}, 
+  {0x60B5,0x6005}, {0x60B6,0x95F7}, {0x60E1,0x6076}, {0x60F1,0x607C}, {0x60F2,0x607D}, 
+  {0x60FB,0x607B}, {0x611B,0x7231}, {0x611C,0x60EC}, {0x6134,0x6006}, {0x6137,0x607A}, 
+  {0x613E,0x5FFE}, {0x614B,0x6001}, {0x6158,0x60E8}, {0x615A,0x60ED}, {0x615F,0x6078}, 
+  {0x6163,0x60EF}, {0x6164,0x60AB}, {0x616A,0x6004}, {0x616B,0x6002}, {0x616E,0x8651}, 
+  {0x6173,0x60AD}, {0x6176,0x5E86}, {0x6182,0x5FE7}, {0x618A,0x60EB}, {0x6190,0x601C}, 
+  {0x6191,0x51ED}, {0x6192,0x6126}, {0x619A,0x60EE}, {0x61A4,0x6124}, {0x61AB,0x60AF}, 
+  {0x61AE,0x6003}, {0x61B2,0x5BAA}, {0x61B6,0x5FC6}, {0x61C7,0x6073}, {0x61C9,0x5E94}, 
+  {0x61CC,0x603F}, {0x61DF,0x603C}, {0x61E3,0x61D1}, {0x61E8,0x6079}, {0x61F2,0x60E9}, 
+  {0x61F6,0x61D2}, {0x61F7,0x6000}, {0x61F8,0x60AC}, {0x61FA,0x5FCF}, {0x61FC,0x60E7}, 
+  {0x61FE,0x6151}, {0x6200,0x604B}, {0x6207,0x6206}, {0x6214,0x620B}, {0x6227,0x6217}, 
+  {0x6229,0x622C}, {0x6230,0x6218}, {0x6232,0x620F}, {0x633E,0x631F}, {0x6368,0x820D}, 
+  {0x636B,0x626A}, {0x6383,0x626B}, {0x6384,0x62A1}, {0x6399,0x6323}, {0x63C0,0x62E3}, 
+  {0x63DA,0x626C}, {0x63DB,0x6362}, {0x63EE,0x6325}, {0x640D,0x635F}, {0x6417,0x6363}, 
+  {0x6436,0x62A2}, {0x6451,0x63B4}, {0x645C,0x63BC}, {0x645F,0x6402}, {0x646F,0x631A}, 
+  {0x6473,0x62A0}, {0x6476,0x629F}, {0x647B,0x63BA}, {0x6488,0x635E}, {0x6493,0x6320}, 
+  {0x649F,0x6322}, {0x64A3,0x63B8}, {0x64A5,0x62E8}, {0x64AB,0x629A}, {0x64B2,0x6251}, 
+  {0x64B3,0x63FF}, {0x64BB,0x631E}, {0x64BE,0x631D}, {0x64BF,0x6361}, {0x64C1,0x62E5}, 
+  {0x64C4,0x63B3}, {0x64C7,0x62E9}, {0x64CA,0x51FB}, {0x64CB,0x6321}, {0x64D4,0x62C5}, 
+  {0x64DA,0x636E}, {0x64E0,0x6324}, {0x64EC,0x62DF}, {0x64EF,0x6448}, {0x64F0,0x62E7}, 
+  {0x64F1,0x6401}, {0x64F2,0x63B7}, {0x64F4,0x6269}, {0x64F7,0x64B7}, {0x64FA,0x6446}, 
+  {0x64FB,0x64DE}, {0x64FC,0x64B8}, {0x64FE,0x6270}, {0x6504,0x6445}, {0x6506,0x64B5}, 
+  {0x650F,0x62E2}, {0x6514,0x62E6}, {0x6516,0x6484}, {0x6519,0x6400}, {0x651B,0x64BA}, 
+  {0x651D,0x6444}, {0x6522,0x6512}, {0x6523,0x631B}, {0x6524,0x644A}, {0x652A,0x6405}, 
+  {0x652C,0x63FD}, {0x6557,0x8D25}, {0x6575,0x654C}, {0x6578,0x6570}, {0x6582,0x655B}, 
+  {0x6583,0x6BD9}, {0x6595,0x6593}, {0x65AC,0x65A9}, {0x65B7,0x65AD}, {0x6642,0x65F6}, 
+  {0x6649,0x664B}, {0x665D,0x663C}, {0x6688,0x6655}, {0x6689,0x6656}, {0x66A2,0x7545}, 
+  {0x66AB,0x6682}, {0x66C4,0x6654}, {0x66C7,0x6619}, {0x66C9,0x6653}, {0x66D6,0x66A7}, 
+  {0x66E0,0x65F7}, {0x66EC,0x6652}, {0x66F8,0x4E66}, {0x6703,0x4F1A}, {0x6727,0x80E7}, 
+  {0x6771,0x4E1C}, {0x6898,0x67A7}, {0x689D,0x6761}, {0x689F,0x67AD}, {0x68C4,0x5F03}, 
+  {0x68D6,0x67A8}, {0x68D7,0x67A3}, {0x68DF,0x680B}, {0x68E7,0x6808}, {0x68F2,0x6816}, 
+  {0x690F,0x6860}, {0x694A,0x6768}, {0x6953,0x67AB}, {0x6968,0x6862}, {0x696D,0x4E1A}, 
+  {0x6975,0x6781}, {0x69AA,0x6769}, {0x69AE,0x8363}, {0x69BF,0x6864}, {0x69CB,0x6784}, 
+  {0x69CD,0x67AA}, {0x69E7,0x6920}, {0x69F3,0x6868}, {0x6A01,0x6869}, {0x6A02,0x4E50}, 
+  {0x6A05,0x679E}, {0x6A13,0x697C}, {0x6A19,0x6807}, {0x6A1E,0x67A2}, {0x6A23,0x6837}, 
+  {0x6A38,0x6734}, {0x6A39,0x6811}, {0x6A3A,0x6866}, {0x6A48,0x6861}, {0x6A4B,0x6865}, 
+  {0x6A5F,0x673A}, {0x6A62,0x692D}, {0x6A89,0x67FD}, {0x6A94,0x6863}, {0x6A9C,0x6867}, 
+  {0x6AA2,0x68C0}, {0x6AA3,0x6A2F}, {0x6AB3,0x69DF}, {0x6AB8,0x67E0}, {0x6ABB,0x69DB}, 
+  {0x6AC3,0x67DC}, {0x6AD3,0x6A79}, {0x6ADA,0x6988}, {0x6ADB,0x6809}, {0x6ADD,0x691F}, 
+  {0x6ADE,0x6A7C}, {0x6ADF,0x680E}, {0x6AE7,0x69E0}, {0x6AE8,0x680C}, {0x6AEA,0x67A5}, 
+  {0x6AEC,0x6987}, {0x6AF3,0x680A}, {0x6AF8,0x6989}, {0x6AFB,0x6A31}, {0x6B04,0x680F}, 
+  {0x6B0A,0x6743}, {0x6B0F,0x6924}, {0x6B12,0x683E}, {0x6B16,0x6984}, {0x6B1E,0x68C2}, 
+  {0x6B3D,0x94A6}, {0x6B50,0x6B27}, {0x6B5F,0x6B24}, {0x6B61,0x6B22}, {0x6B72,0x5C81}, 
+  {0x6B77,0x5386}, {0x6B78,0x5F52}, {0x6B98,0x6B8B}, {0x6B9E,0x6B92}, {0x6BA4,0x6B87}, 
+  {0x6BAB,0x6B9A}, {0x6BAE,0x6B93}, {0x6BAF,0x6BA1}, {0x6BB2,0x6B7C}, {0x6BBA,0x6740}, 
+  {0x6BBB,0x58F3}, {0x6BC6,0x6BB4}, {0x6BFF,0x6BF5}, {0x6C08,0x6BE1}, {0x6C0C,0x6C07}, 
+  {0x6C23,0x6C14}, {0x6C2B,0x6C22}, {0x6C2C,0x6C29}, {0x6D79,0x6D43}, {0x6D87,0x6CFE}, 
+  {0x6DEA,0x6CA6}, {0x6DF5,0x6E0A}, {0x6DF6,0x6D9E}, {0x6DFA,0x6D45}, {0x6E19,0x6DA3}, 
+  {0x6E26,0x6DA1}, {0x6E2C,0x6D4B}, {0x6E3E,0x6D51}, {0x6E5E,0x6D48}, {0x6E6F,0x6C64}, 
+  {0x6E96,0x51C6}, {0x6E9D,0x6C9F}, {0x6EC4,0x6CA7}, {0x6EC5,0x706D}, {0x6ECC,0x6DA4}, 
+  {0x6ECE,0x8365}, {0x6EEC,0x6CAA}, {0x6EEF,0x6EDE}, {0x6EF2,0x6E17}, {0x6EF7,0x5364}, 
+  {0x6EF8,0x6D52}, {0x6EFF,0x6EE1}, {0x6F01,0x6E14}, {0x6F1A,0x6CA4}, {0x6F22,0x6C49}, 
+  {0x6F23,0x6D9F}, {0x6F2C,0x6E0D}, {0x6F32,0x6DA8}, {0x6F38,0x6E10}, {0x6F3F,0x6D46}, 
+  {0x6F41,0x988D}, {0x6F51,0x6CFC}, {0x6F54,0x6D01}, {0x6F59,0x6CA9}, {0x6F5B,0x6F5C}, 
+  {0x6F64,0x6DA6}, {0x6F6F,0x6D54}, {0x6F70,0x6E83}, {0x6F77,0x6ED7}, {0x6F7F,0x6DA0}, 
+  {0x6F80,0x6DA9}, {0x6F86,0x6D47}, {0x6F87,0x6D9D}, {0x6F97,0x6DA7}, {0x6FA0,0x6E11}, 
+  {0x6FA4,0x6CFD}, {0x6FA9,0x6CF6}, {0x6FAE,0x6D4D}, {0x6FB1,0x6DC0}, {0x6FC1,0x6D4A}, 
+  {0x6FC3,0x6D53}, {0x6FD5,0x6E7F}, {0x6FD8,0x6CDE}, {0x6FDF,0x6D4E}, {0x6FE4,0x6D9B}, 
+  {0x6FEB,0x6EE5}, {0x6FF0,0x6F4D}, {0x6FF1,0x6EE8}, {0x6FFA,0x6E85}, {0x6FFC,0x6CFA}, 
+  {0x6FFE,0x6EE4}, {0x7005,0x6EE2}, {0x7006,0x6E0E}, {0x7009,0x6CFB}, {0x700B,0x6E16}, 
+  {0x700F,0x6D4F}, {0x7015,0x6FD2}, {0x7018,0x6CF8}, {0x701D,0x6CA5}, {0x701F,0x6F47}, 
+  {0x7020,0x6F46}, {0x7027,0x6CF7}, {0x7028,0x6FD1}, {0x7032,0x6F4B}, {0x703E,0x6F9C}, 
+  {0x7043,0x6CA3}, {0x7044,0x6EE0}, {0x7051,0x6D12}, {0x7055,0x6F13}, {0x7058,0x6EE9}, 
+  {0x705D,0x704F}, {0x7063,0x6E7E}, {0x7064,0x6EE6}, {0x7067,0x6EDF}, {0x70CF,0x4E4C}, 
+  {0x70F4,0x70C3}, {0x7121,0x65E0}, {0x7149,0x70BC}, {0x7152,0x709C}, {0x7162,0x8315}, 
+  {0x7165,0x7115}, {0x7169,0x70E6}, {0x716C,0x7080}, {0x7192,0x8367}, {0x7197,0x709D}, 
+  {0x71B1,0x70ED}, {0x71BE,0x70BD}, {0x71C1,0x70E8}, {0x71C8,0x706F}, {0x71D2,0x70E7}, 
+  {0x71D9,0x70EB}, {0x71DC,0x7116}, {0x71DF,0x8425}, {0x71E6,0x707F}, {0x71ED,0x70DB}, 
+  {0x71F4,0x70E9}, {0x71FC,0x70EC}, {0x71FE,0x7118}, {0x720D,0x70C1}, {0x7210,0x7089}, 
+  {0x721B,0x70C2}, {0x722D,0x4E89}, {0x7232,0x4E3A}, {0x723A,0x7237}, {0x723E,0x5C14}, 
+  {0x7258,0x724D}, {0x727D,0x7275}, {0x7296,0x8366}, {0x72A2,0x728A}, {0x72A7,0x727A}, 
+  {0x72C0,0x72B6}, {0x72F9,0x72ED}, {0x72FD,0x72C8}, {0x7319,0x72F0}, {0x7336,0x72B9}, 
+  {0x733B,0x72F2}, {0x7341,0x72B8}, {0x7344,0x72F1}, {0x7345,0x72EE}, {0x7368,0x72EC}, 
+  {0x736A,0x72EF}, {0x736B,0x7303}, {0x7370,0x72DE}, {0x7372,0x83B7}, {0x7375,0x730E}, 
+  {0x7377,0x72B7}, {0x7378,0x517D}, {0x737A,0x736D}, {0x737B,0x732E}, {0x737C,0x7315}, 
+  {0x7380,0x7321}, {0x73FE,0x73B0}, {0x743F,0x73F2}, {0x744B,0x73AE}, {0x7463,0x7410}, 
+  {0x7469,0x83B9}, {0x746A,0x739B}, {0x7489,0x740F}, {0x74A3,0x7391}, {0x74A6,0x7477}, 
+  {0x74B0,0x73AF}, {0x74BD,0x73BA}, {0x74CA,0x743C}, {0x74CF,0x73D1}, {0x74D4,0x748E}, 
+  {0x74DA,0x74D2}, {0x750C,0x74EF}, {0x7523,0x4EA7}, {0x755D,0x4EA9}, {0x7562,0x6BD5}, 
+  {0x756B,0x753B}, {0x7576,0x5F53}, {0x7587,0x7574}, {0x758A,0x53E0}, {0x75D9,0x75C9}, 
+  {0x7602,0x75D6}, {0x760B,0x75AF}, {0x760D,0x75A1}, {0x7613,0x75EA}, {0x761E,0x7617}, 
+  {0x7621,0x75AE}, {0x7627,0x759F}, {0x763B,0x7618}, {0x7642,0x7597}, {0x7646,0x75E8}, 
+  {0x7647,0x75EB}, {0x7649,0x7605}, {0x7658,0x75A0}, {0x765F,0x762A}, {0x7662,0x75D2}, 
+  {0x7664,0x7596}, {0x7665,0x75C7}, {0x7667,0x75AC}, {0x7669,0x765E}, {0x766C,0x7663}, 
+  {0x766D,0x763F}, {0x766E,0x763E}, {0x7670,0x75C8}, {0x7671,0x762B}, {0x7672,0x766B}, 
+  {0x767C,0x53D1}, {0x769A,0x7691}, {0x76B8,0x76B2}, {0x76BA,0x76B1}, {0x76DE,0x76CF}, 
+  {0x76E1,0x5C3D}, {0x76E3,0x76D1}, {0x76E4,0x76D8}, {0x76E7,0x5362}, {0x775C,0x7741}, 
+  {0x775E,0x7750}, {0x7798,0x770D}, {0x779E,0x7792}, {0x77BC,0x7751}, {0x77DA,0x77A9}, 
+  {0x77EF,0x77EB}, {0x7864,0x7856}, {0x7868,0x7817}, {0x786F,0x781A}, {0x78A9,0x7855}, 
+  {0x78AD,0x7800}, {0x78B8,0x781C}, {0x78BA,0x786E}, {0x78BC,0x7801}, {0x78DA,0x7816}, 
+  {0x78E3,0x789C}, {0x78E7,0x789B}, {0x78EF,0x77F6}, {0x78FD,0x7857}, {0x790E,0x7840}, 
+  {0x7919,0x788D}, {0x7926,0x77FF}, {0x792A,0x783A}, {0x792B,0x783E}, {0x792C,0x77FE}, 
+  {0x7931,0x783B}, {0x798D,0x7978}, {0x798E,0x796F}, {0x79AA,0x7985}, {0x79AE,0x793C}, 
+  {0x79B0,0x7962}, {0x79B1,0x7977}, {0x7A2E,0x79CD}, {0x7A31,0x79F0}, {0x7A4C,0x7A23}, 
+  {0x7A4D,0x79EF}, {0x7A4E,0x9896}, {0x7A61,0x7A51}, {0x7A62,0x79FD}, {0x7A69,0x7A33}, 
+  {0x7AA9,0x7A9D}, {0x7AAA,0x6D3C}, {0x7AAE,0x7A77}, {0x7AB6,0x7AAD}, {0x7ABA,0x7AA5}, 
+  {0x7AC4,0x7A9C}, {0x7AC5,0x7A8D}, {0x7AC7,0x7AA6}, {0x7AC8,0x7076}, {0x7ACA,0x7A83}, 
+  {0x7AEA,0x7AD6}, {0x7AF6,0x7ADE}, {0x7B46,0x7B14}, {0x7B67,0x7B15}, {0x7B8B,0x7B3A}, 
+  {0x7B8F,0x7B5D}, {0x7BC0,0x8282}, {0x7BC4,0x8303}, {0x7BC9,0x7B51}, {0x7BCB,0x7BA7}, 
+  {0x7BE4,0x7B03}, {0x7BE9,0x7B5B}, {0x7BF3,0x7B5A}, {0x7C00,0x7BA6}, {0x7C0D,0x7BD3}, 
+  {0x7C1E,0x7BAA}, {0x7C21,0x7B80}, {0x7C23,0x7BD1}, {0x7C2B,0x7BAB}, {0x7C3D,0x7B7E}, 
+  {0x7C3E,0x5E18}, {0x7C43,0x7BEE}, {0x7C4C,0x7B79}, {0x7C5C,0x7BA8}, {0x7C5F,0x7C41}, 
+  {0x7C60,0x7B3C}, {0x7C69,0x7B3E}, {0x7C6A,0x7C16}, {0x7C6C,0x7BF1}, {0x7C6E,0x7BA9}, 
+  {0x7CDD,0x7CC1}, {0x7CDE,0x7CAA}, {0x7CE7,0x7CAE}, {0x7CF2,0x7C9D}, {0x7CF4,0x7C74}, 
+  {0x7CF6,0x7C9C}, {0x7CF9,0x7E9F}, {0x7CFE,0x7EA0}, {0x7D00,0x7EAA}, {0x7D02,0x7EA3}, 
+  {0x7D04,0x7EA6}, {0x7D05,0x7EA2}, {0x7D06,0x7EA1}, {0x7D07,0x7EA5}, {0x7D08,0x7EA8}, 
+  {0x7D09,0x7EAB}, {0x7D0B,0x7EB9}, {0x7D0D,0x7EB3}, {0x7D10,0x7EBD}, {0x7D13,0x7EBE}, 
+  {0x7D14,0x7EAF}, {0x7D15,0x7EB0}, {0x7D17,0x7EB1}, {0x7D19,0x7EB8}, {0x7D1A,0x7EA7}, 
+  {0x7D1B,0x7EB7}, {0x7D1C,0x7EAD}, {0x7D21,0x7EBA}, {0x7D30,0x7EC6}, {0x7D31,0x7EC2}, 
+  {0x7D32,0x7EC1}, {0x7D33,0x7EC5}, {0x7D39,0x7ECD}, {0x7D3A,0x7EC0}, {0x7D3C,0x7ECB}, 
+  {0x7D3F,0x7ED0}, {0x7D40,0x7ECC}, {0x7D42,0x7EC8}, {0x7D44,0x7EC4}, {0x7D46,0x7ECA}, 
+  {0x7D4E,0x7ED7}, {0x7D50,0x7ED3}, {0x7D5D,0x7ED4}, {0x7D5E,0x7EDE}, {0x7D61,0x7EDC}, 
+  {0x7D62,0x7EDA}, {0x7D66,0x7ED9}, {0x7D68,0x7ED2}, {0x7D71,0x7EDF}, {0x7D72,0x4E1D}, 
+  {0x7D73,0x7EDB}, {0x7D76,0x7EDD}, {0x7D79,0x7EE2}, {0x7D81,0x7ED1}, {0x7D83,0x7EE1}, 
+  {0x7D86,0x7EE0}, {0x7D88,0x7EE8}, {0x7D89,0x7EE3}, {0x7D8F,0x7EE5}, {0x7D93,0x7ECF}, 
+  {0x7D9C,0x7EFC}, {0x7D9E,0x7F0D}, {0x7DA2,0x7EF8}, {0x7DA3,0x7EFB}, {0x7DAB,0x7EBF}, 
+  {0x7DAC,0x7EF6}, {0x7DAD,0x7EF4}, {0x7DB0,0x7EFE}, {0x7DB1,0x7EB2}, {0x7DB2,0x7F51}, 
+  {0x7DB3,0x7EF7}, {0x7DB4,0x7F00}, {0x7DB8,0x7EB6}, {0x7DB9,0x7EFA}, {0x7DBA,0x7EEE}, 
+  {0x7DBB,0x7EFD}, {0x7DBD,0x7EF0}, {0x7DBE,0x7EEB}, {0x7DBF,0x7EF5}, {0x7DC4,0x7EF2}, 
+  {0x7DC7,0x7F01}, {0x7DCA,0x7D27}, {0x7DCB,0x7EEF}, {0x7DD1,0x7EFF}, {0x7DD2,0x7EEA}, 
+  {0x7DD4,0x7EF1}, {0x7DD7,0x7F03}, {0x7DD8,0x7F04}, {0x7DD9,0x7F02}, {0x7DDD,0x7F09}, 
+  {0x7DDE,0x7F0E}, {0x7DE0,0x7F14}, {0x7DE1,0x7F17}, {0x7DE3,0x7F18}, {0x7DE6,0x7F0C}, 
+  {0x7DE8,0x7F16}, {0x7DE9,0x7F13}, {0x7DEC,0x7F05}, {0x7DEF,0x7EAC}, {0x7DF1,0x7F11}, 
+  {0x7DF2,0x7F08}, {0x7DF4,0x7EC3}, {0x7DF6,0x7F0F}, {0x7DF9,0x7F07}, {0x7E08,0x8426}, 
+  {0x7E09,0x7F19}, {0x7E0A,0x7F22}, {0x7E0B,0x7F12}, {0x7E10,0x7EC9}, {0x7E11,0x7F23}, 
+  {0x7E1B,0x7F1A}, {0x7E1D,0x7F1C}, {0x7E1E,0x7F1F}, {0x7E1F,0x7F1B}, {0x7E23,0x53BF}, 
+  {0x7E27,0x7EE6}, {0x7E2B,0x7F1D}, {0x7E2D,0x7F21}, {0x7E2E,0x7F29}, {0x7E31,0x7EB5}, 
+  {0x7E32,0x7F27}, {0x7E35,0x7F26}, {0x7E36,0x7D77}, {0x7E37,0x7F15}, {0x7E39,0x7F25}, 
+  {0x7E3D,0x603B}, {0x7E3E,0x7EE9}, {0x7E45,0x7F2B}, {0x7E46,0x7F2A}, {0x7E52,0x7F2F}, 
+  {0x7E54,0x7EC7}, {0x7E55,0x7F2E}, {0x7E5A,0x7F2D}, {0x7E5E,0x7ED5}, {0x7E62,0x7F0B}, 
+  {0x7E69,0x7EF3}, {0x7E6A,0x7ED8}, {0x7E6D,0x8327}, {0x7E6E,0x7F30}, {0x7E6F,0x7F33}, 
+  {0x7E70,0x7F32}, {0x7E73,0x7F34}, {0x7E79,0x7ECE}, {0x7E7C,0x7EE7}, {0x7E7D,0x7F24}, 
+  {0x7E7E,0x7F31}, {0x7E88,0x7F2C}, {0x7E8A,0x7EA9}, {0x7E8C,0x7EED}, {0x7E8F,0x7F20}, 
+  {0x7E93,0x7F28}, {0x7E96,0x7EA4}, {0x7E98,0x7F35}, {0x7E9C,0x7F06}, {0x7F4C,0x7F42}, 
+  {0x7F70,0x7F5A}, {0x7F77,0x7F62}, {0x7F85,0x7F57}, {0x7F86,0x7F74}, {0x7F88,0x7F81}, 
+  {0x7FA5,0x7F9F}, {0x7FA9,0x4E49}, {0x7FD2,0x4E60}, {0x7FF9,0x7FD8}, {0x802C,0x8027}, 
+  {0x802E,0x8022}, {0x8056,0x5723}, {0x805E,0x95FB}, {0x806F,0x8054}, {0x8070,0x806A}, 
+  {0x8072,0x58F0}, {0x8073,0x8038}, {0x8075,0x8069}, {0x8076,0x8042}, {0x8077,0x804C}, 
+  {0x8079,0x804D}, {0x807D,0x542C}, {0x807E,0x804B}, {0x8085,0x8083}, {0x8105,0x80C1}, 
+  {0x811B,0x80EB}, {0x8139,0x80C0}, {0x814E,0x80BE}, {0x8156,0x80E8}, {0x8161,0x8136}, 
+  {0x8166,0x8111}, {0x816B,0x80BF}, {0x8178,0x80A0}, {0x819A,0x80A4}, {0x81A0,0x80F6}, 
+  {0x81A9,0x817B}, {0x81BD,0x80C6}, {0x81BE,0x810D}, {0x81BF,0x8113}, {0x81C9,0x8138}, 
+  {0x81CD,0x8110}, {0x81CF,0x8191}, {0x81D8,0x814A}, {0x81DA,0x80EA}, {0x81DF,0x810F}, 
+  {0x81E0,0x8114}, {0x81E8,0x4E34}, {0x81FA,0x53F0}, {0x8207,0x4E0E}, {0x8208,0x5174}, 
+  {0x8209,0x4E3E}, {0x820A,0x65E7}, {0x8259,0x8231}, {0x8264,0x8223}, {0x8266,0x8230}, 
+  {0x826B,0x823B}, {0x8271,0x8270}, {0x8277,0x8273}, {0x82BB,0x520D}, {0x82E7,0x82CE}, 
+  {0x838A,0x5E84}, {0x8396,0x830E}, {0x83A2,0x835A}, {0x83A7,0x82CB}, {0x83EF,0x534E}, 
+  {0x8407,0x82CC}, {0x840A,0x83B1}, {0x842C,0x4E07}, {0x8435,0x83B4}, {0x8449,0x53F6}, 
+  {0x8452,0x836D}, {0x8464,0x836E}, {0x8466,0x82C7}, {0x8477,0x8364}, {0x8493,0x83BC}, 
+  {0x8494,0x83B3}, {0x84BC,0x82CD}, {0x84C0,0x836A}, {0x84CB,0x76D6}, {0x84EE,0x83B2}, 
+  {0x84EF,0x82C1}, {0x84FD,0x835C}, {0x851E,0x848C}, {0x8523,0x848B}, {0x8526,0x8311}, 
+  {0x852D,0x836B}, {0x8541,0x8368}, {0x8546,0x8487}, {0x854E,0x835E}, {0x8552,0x836C}, 
+  {0x8553,0x82B8}, {0x8555,0x83B8}, {0x8558,0x835B}, {0x8562,0x8489}, {0x8569,0x8361}, 
+  {0x856A,0x829C}, {0x856D,0x8427}, {0x8577,0x84E3}, {0x8588,0x835F}, {0x858A,0x84DF}, 
+  {0x858C,0x8297}, {0x8594,0x8537}, {0x859F,0x83B6}, {0x85A6,0x8350}, {0x85A9,0x8428}, 
+  {0x85BA,0x8360}, {0x85CD,0x84DD}, {0x85CE,0x8369}, {0x85DD,0x827A}, {0x85E5,0x836F}, 
+  {0x85EA,0x85AE}, {0x85F4,0x8574}, {0x85F6,0x82C8}, {0x85F9,0x853C}, {0x85FA,0x853A}, 
+  {0x8604,0x8572}, {0x8606,0x82A6}, {0x8607,0x82CF}, {0x860B,0x82F9}, {0x861A,0x85D3}, 
+  {0x861E,0x8539}, {0x8622,0x830F}, {0x862D,0x5170}, {0x863A,0x84E0}, {0x863F,0x841D}, 
+  {0x8655,0x5904}, {0x865C,0x864F}, {0x865F,0x53F7}, {0x8667,0x4E8F}, {0x86FA,0x86F1}, 
+  {0x8706,0x86AC}, {0x8755,0x8680}, {0x8766,0x867E}, {0x8778,0x8717}, {0x8784,0x86F3}, 
+  {0x879E,0x8682}, {0x87A2,0x8424}, {0x87BB,0x877C}, {0x87C4,0x86F0}, {0x87C8,0x8748}, 
+  {0x87CE,0x87A8}, {0x87E3,0x866E}, {0x87EC,0x8749}, {0x87EF,0x86F2}, {0x87F2,0x866B}, 
+  {0x87F6,0x86CF}, {0x87FB,0x8681}, {0x8805,0x8747}, {0x8806,0x867F}, {0x8810,0x86F4}, 
+  {0x8811,0x877E}, {0x881F,0x8721}, {0x8823,0x86CE}, {0x8831,0x86CA}, {0x8836,0x8695}, 
+  {0x883B,0x86EE}, {0x8846,0x4F17}, {0x8853,0x672F}, {0x885B,0x536B}, {0x885D,0x51B2}, 
+  {0x8879,0x53EA}, {0x88CA,0x8885}, {0x88CF,0x91CC}, {0x88DC,0x8865}, {0x88DD,0x88C5}, 
+  {0x8932,0x88E4}, {0x8933,0x88E2}, {0x8938,0x891B}, {0x893B,0x4EB5}, {0x8947,0x88E5}, 
+  {0x8956,0x8884}, {0x895D,0x88E3}, {0x8960,0x88C6}, {0x8964,0x8934}, {0x896A,0x889C}, 
+  {0x896F,0x886C}, {0x8972,0x88AD}, {0x898B,0x89C1}, {0x898F,0x89C4}, {0x8993,0x89C5}, 
+  {0x8996,0x89C6}, {0x8998,0x89C7}, {0x89A1,0x89CB}, {0x89A6,0x89CE}, {0x89AA,0x4EB2}, 
+  {0x89AC,0x89CA}, {0x89AF,0x89CF}, {0x89B2,0x89D0}, {0x89B7,0x89D1}, {0x89BA,0x89C9}, 
+  {0x89BD,0x89C8}, {0x89BF,0x89CC}, {0x89C0,0x89C2}, {0x89F4,0x89DE}, {0x89F6,0x89EF}, 
+  {0x89F8,0x89E6}, {0x8A01,0x8BA0}, {0x8A02,0x8BA2}, {0x8A03,0x8BA3}, {0x8A08,0x8BA1}, 
+  {0x8A0A,0x8BAF}, {0x8A0C,0x8BA7}, {0x8A0E,0x8BA8}, {0x8A10,0x8BA6}, {0x8A13,0x8BAD}, 
+  {0x8A15,0x8BAA}, {0x8A16,0x8BAB}, {0x8A18,0x8BB0}, {0x8A1B,0x8BB9}, {0x8A1D,0x8BB6}, 
+  {0x8A1F,0x8BBC}, {0x8A23,0x8BC0}, {0x8A25,0x8BB7}, {0x8A2A,0x8BBF}, {0x8A2D,0x8BBE}, 
+  {0x8A31,0x8BB8}, {0x8A34,0x8BC9}, {0x8A36,0x8BC3}, {0x8A3A,0x8BCA}, {0x8A41,0x8BC2}, 
+  {0x8A46,0x8BCB}, {0x8A4E,0x8BB5}, {0x8A50,0x8BC8}, {0x8A52,0x8BD2}, {0x8A54,0x8BCF}, 
+  {0x8A55,0x8BC4}, {0x8A58,0x8BCE}, {0x8A5B,0x8BC5}, {0x8A5E,0x8BCD}, {0x8A61,0x8BE9}, 
+  {0x8A62,0x8BE2}, {0x8A63,0x8BE3}, {0x8A66,0x8BD5}, {0x8A69,0x8BD7}, {0x8A6B,0x8BE7}, 
+  {0x8A6C,0x8BDF}, {0x8A6D,0x8BE1}, {0x8A6E,0x8BE0}, {0x8A70,0x8BD8}, {0x8A71,0x8BDD}, 
+  {0x8A72,0x8BE5}, {0x8A73,0x8BE6}, {0x8A75,0x8BDC}, {0x8A7C,0x8BD9}, {0x8A7F,0x8BD6}, 
+  {0x8A84,0x8BD4}, {0x8A85,0x8BDB}, {0x8A86,0x8BD3}, {0x8A87,0x5938}, {0x8A8D,0x8BA4}, 
+  {0x8A91,0x8BF3}, {0x8A92,0x8BF6}, {0x8A95,0x8BDE}, {0x8A98,0x8BF1}, {0x8A9A,0x8BEE}, 
+  {0x8A9E,0x8BED}, {0x8AA0,0x8BDA}, {0x8AA1,0x8BEB}, {0x8AA3,0x8BEC}, {0x8AA4,0x8BEF}, 
+  {0x8AA5,0x8BF0}, {0x8AA6,0x8BF5}, {0x8AA8,0x8BF2}, {0x8AAC,0x8BF4}, {0x8AB0,0x8C01}, 
+  {0x8AB2,0x8BFE}, {0x8AB6,0x8C07}, {0x8AB9,0x8BFD}, {0x8ABC,0x8C0A}, {0x8ABF,0x8C03}, 
+  {0x8AC2,0x8C04}, {0x8AC4,0x8C06}, {0x8AC7,0x8C08}, {0x8AC9,0x8BFF}, {0x8ACB,0x8BF7}, 
+  {0x8ACD,0x8BE4}, {0x8ACF,0x8BF9}, {0x8AD1,0x8BFC}, {0x8AD2,0x8C05}, {0x8AD6,0x8BBA}, 
+  {0x8AD7,0x8C02}, {0x8ADB,0x8C00}, {0x8ADC,0x8C0D}, {0x8ADE,0x8C1D}, {0x8AE2,0x8BE8}, 
+  {0x8AE4,0x8C14}, {0x8AE6,0x8C1B}, {0x8AE7,0x8C10}, {0x8AEB,0x8C0F}, {0x8AED,0x8C15}, 
+  {0x8AEE,0x8C18}, {0x8AF1,0x8BB3}, {0x8AF3,0x8C19}, {0x8AF6,0x8C0C}, {0x8AF7,0x8BBD}, 
+  {0x8AF8,0x8BF8}, {0x8AFA,0x8C1A}, {0x8AFC,0x8C16}, {0x8AFE,0x8BFA}, {0x8B00,0x8C0B}, 
+  {0x8B01,0x8C12}, {0x8B02,0x8C13}, {0x8B04,0x8A8A}, {0x8B05,0x8BCC}, {0x8B0A,0x8C0E}, 
+  {0x8B0E,0x8C1C}, {0x8B10,0x8C27}, {0x8B14,0x8C11}, {0x8B16,0x8C21}, {0x8B17,0x8C24}, 
+  {0x8B19,0x8C26}, {0x8B1A,0x8C25}, {0x8B1B,0x8BB2}, {0x8B1D,0x8C22}, {0x8B21,0x8C23}, 
+  {0x8B28,0x8C1F}, {0x8B2B,0x8C2A}, {0x8B2C,0x8C2C}, {0x8B2D,0x8C2B}, {0x8B33,0x8BB4}, 
+  {0x8B39,0x8C28}, {0x8B3E,0x8C29}, {0x8B49,0x8BC1}, {0x8B4E,0x8C32}, {0x8B4F,0x8BA5}, 
+  {0x8B56,0x8C2E}, {0x8B58,0x8BC6}, {0x8B59,0x8C2F}, {0x8B5A,0x8C2D}, {0x8B5C,0x8C31}, 
+  {0x8B6B,0x8C35}, {0x8B6F,0x8BD1}, {0x8B70,0x8BAE}, {0x8B74,0x8C34}, {0x8B77,0x62A4}, 
+  {0x8B7D,0x8A89}, {0x8B80,0x8BFB}, {0x8B8A,0x53D8}, {0x8B8E,0x96E0}, {0x8B92,0x8C17}, 
+  {0x8B93,0x8BA9}, {0x8B95,0x8C30}, {0x8B96,0x8C36}, {0x8B9C,0x8C20}, {0x8B9E,0x8C33}, 
+  {0x8C48,0x5C82}, {0x8C50,0x4E30}, {0x8C9D,0x8D1D}, {0x8C9E,0x8D1E}, {0x8CA0,0x8D1F}, 
+  {0x8CA1,0x8D22}, {0x8CA2,0x8D21}, {0x8CA7,0x8D2B}, {0x8CA8,0x8D27}, {0x8CA9,0x8D29}, 
+  {0x8CAA,0x8D2A}, {0x8CAB,0x8D2F}, {0x8CAC,0x8D23}, {0x8CAF,0x8D2E}, {0x8CB0,0x8D33}, 
+  {0x8CB2,0x8D40}, {0x8CB3,0x8D30}, {0x8CB4,0x8D35}, {0x8CB6,0x8D2C}, {0x8CB7,0x4E70}, 
+  {0x8CB8,0x8D37}, {0x8CBA,0x8D36}, {0x8CBB,0x8D39}, {0x8CBC,0x8D34}, {0x8CBD,0x8D3B}, 
+  {0x8CBF,0x8D38}, {0x8CC0,0x8D3A}, {0x8CC1,0x8D32}, {0x8CC2,0x8D42}, {0x8CC3,0x8D41}, 
+  {0x8CC4,0x8D3F}, {0x8CC5,0x8D45}, {0x8CC7,0x8D44}, {0x8CC8,0x8D3E}, {0x8CCA,0x8D3C}, 
+  {0x8CD1,0x8D48}, {0x8CD2,0x8D4A}, {0x8CD3,0x5BBE}, {0x8CD5,0x8D47}, {0x8CDA,0x8D49}, 
+  {0x8CDC,0x8D50}, {0x8CDE,0x8D4F}, {0x8CE0,0x8D54}, {0x8CE1,0x8D53}, {0x8CE2,0x8D24}, 
+  {0x8CE3,0x5356}, {0x8CE4,0x8D31}, {0x8CE6,0x8D4B}, {0x8CE7,0x8D55}, {0x8CEA,0x8D28}, 
+  {0x8CEB,0x8D4D}, {0x8CEC,0x8D26}, {0x8CED,0x8D4C}, {0x8CF4,0x8D56}, {0x8CFA,0x8D5A}, 
+  {0x8CFB,0x8D59}, {0x8CFC,0x8D2D}, {0x8CFD,0x8D5B}, {0x8CFE,0x8D5C}, {0x8D04,0x8D3D}, 
+  {0x8D05,0x8D58}, {0x8D08,0x8D60}, {0x8D0A,0x8D5E}, {0x8D0B,0x8D5D}, {0x8D0D,0x8D61}, 
+  {0x8D0F,0x8D62}, {0x8D10,0x8D46}, {0x8D16,0x8D4E}, {0x8D1B,0x8D63}, {0x8D1C,0x8D43}, 
+  {0x8D95,0x8D76}, {0x8D99,0x8D75}, {0x8DA8,0x8D8B}, {0x8DB2,0x8DB1}, {0x8E10,0x8DF5}, 
+  {0x8E34,0x8E0A}, {0x8E4C,0x8DC4}, {0x8E55,0x8DF8}, {0x8E63,0x8E52}, {0x8E7A,0x8DF7}, 
+  {0x8E89,0x8DB8}, {0x8E8A,0x8E0C}, {0x8E8B,0x8DFB}, {0x8E8D,0x8DC3}, {0x8E91,0x8E2F}, 
+  {0x8E92,0x8DDE}, {0x8E93,0x8E2C}, {0x8E9A,0x8DF9}, {0x8EA1,0x8E51}, {0x8EA5,0x8E7F}, 
+  {0x8EA6,0x8E9C}, {0x8EAA,0x8E8F}, {0x8EC0,0x8EAF}, {0x8ECA,0x8F66}, {0x8ECB,0x8F67}, 
+  {0x8ECC,0x8F68}, {0x8ECD,0x519B}, {0x8ED2,0x8F69}, {0x8ED4,0x8F6B}, {0x8EDB,0x8F6D}, 
+  {0x8EDF,0x8F6F}, {0x8EE4,0x8F77}, {0x8EEB,0x8F78}, {0x8EF2,0x8F71}, {0x8EF8,0x8F74}, 
+  {0x8EF9,0x8F75}, {0x8EFA,0x8F7A}, {0x8EFB,0x8F72}, {0x8EFC,0x8F76}, {0x8EFE,0x8F7C}, 
+  {0x8F03,0x8F83}, {0x8F05,0x8F82}, {0x8F07,0x8F81}, {0x8F09,0x8F7D}, {0x8F0A,0x8F7E}, 
+  {0x8F12,0x8F84}, {0x8F14,0x8F85}, {0x8F15,0x8F7B}, {0x8F1B,0x8F86}, {0x8F1C,0x8F8E}, 
+  {0x8F1D,0x8F89}, {0x8F1E,0x8F8B}, {0x8F1F,0x8F8D}, {0x8F25,0x8F8A}, {0x8F26,0x8F87}, 
+  {0x8F29,0x8F88}, {0x8F2A,0x8F6E}, {0x8F2F,0x8F91}, {0x8F33,0x8F8F}, {0x8F38,0x8F93}, 
+  {0x8F3B,0x8F90}, {0x8F3E,0x8F97}, {0x8F3F,0x8206}, {0x8F42,0x6BC2}, {0x8F44,0x8F96}, 
+  {0x8F45,0x8F95}, {0x8F46,0x8F98}, {0x8F49,0x8F6C}, {0x8F4D,0x8F99}, {0x8F4E,0x8F7F}, 
+  {0x8F54,0x8F9A}, {0x8F5F,0x8F70}, {0x8F61,0x8F94}, {0x8F62,0x8F79}, {0x8F64,0x8F73}, 
+  {0x8FA6,0x529E}, {0x8FAD,0x8F9E}, {0x8FAE,0x8FAB}, {0x8FAF,0x8FA9}, {0x8FB2,0x519C}, 
+  {0x9015,0x8FF3}, {0x9019,0x8FD9}, {0x9023,0x8FDE}, {0x9032,0x8FDB}, {0x904B,0x8FD0}, 
+  {0x904E,0x8FC7}, {0x9054,0x8FBE}, {0x9055,0x8FDD}, {0x905C,0x900A}, {0x905E,0x9012}, 
+  {0x9060,0x8FDC}, {0x9069,0x9002}, {0x9072,0x8FDF}, {0x9077,0x8FC1}, {0x9078,0x9009}, 
+  {0x907A,0x9057}, {0x907C,0x8FBD}, {0x9081,0x8FC8}, {0x9084,0x8FD8}, {0x9087,0x8FE9}, 
+  {0x908A,0x8FB9}, {0x908F,0x903B}, {0x9090,0x9026}, {0x90DF,0x90CF}, {0x90F5,0x90AE}, 
+  {0x9106,0x90D3}, {0x9109,0x4E61}, {0x9112,0x90B9}, {0x9114,0x90AC}, {0x9116,0x90E7}, 
+  {0x9127,0x9093}, {0x912D,0x90D1}, {0x9130,0x90BB}, {0x9132,0x90F8}, {0x9134,0x90BA}, 
+  {0x9136,0x90D0}, {0x913A,0x909D}, {0x9148,0x90E6}, {0x9196,0x915D}, {0x919C,0x4E11}, 
+  {0x91AB,0x533B}, {0x91AC,0x9171}, {0x91C0,0x917F}, {0x91C1,0x8845}, {0x91C3,0x917E}, 
+  {0x91C5,0x917D}, {0x91CB,0x91CA}, {0x91D2,0x9485}, {0x91D3,0x9486}, {0x91D4,0x9487}, 
+  {0x91D5,0x948C}, {0x91D7,0x948A}, {0x91D8,0x9489}, {0x91D9,0x948B}, {0x91DD,0x9488}, 
+  {0x91E3,0x9493}, {0x91E4,0x9490}, {0x91E7,0x948F}, {0x91E9,0x9492}, {0x91F5,0x9497}, 
+  {0x91F7,0x948D}, {0x91F9,0x9495}, {0x91FA,0x948E}, {0x9200,0x94AF}, {0x9201,0x94AB}, 
+  {0x9204,0x94AD}, {0x9208,0x949A}, {0x9209,0x94A0}, {0x920D,0x949D}, {0x920E,0x94A9}, 
+  {0x9210,0x94A4}, {0x9211,0x94A3}, {0x9214,0x949E}, {0x9215,0x94AE}, {0x921E,0x94A7}, 
+  {0x9223,0x9499}, {0x9225,0x94AC}, {0x9226,0x949B}, {0x9227,0x94AA}, {0x922E,0x94CC}, 
+  {0x9230,0x94C8}, {0x9233,0x94B6}, {0x9234,0x94C3}, {0x9237,0x94B4}, {0x9238,0x94B9}, 
+  {0x9239,0x94CD}, {0x923A,0x94B0}, {0x923D,0x94B8}, {0x923E,0x94C0}, {0x923F,0x94BF}, 
+  {0x9240,0x94BE}, {0x9245,0x949C}, {0x9248,0x94CA}, {0x9249,0x94C9}, {0x924D,0x94CB}, 
+  {0x9251,0x94C2}, {0x9255,0x94B7}, {0x9257,0x94B3}, {0x925A,0x94C6}, {0x925B,0x94C5}, 
+  {0x925E,0x94BA}, {0x9262,0x94B5}, {0x9266,0x94B2}, {0x926C,0x94BC}, {0x926D,0x94BD}, 
+  {0x9278,0x94F0}, {0x927A,0x94D2}, {0x927B,0x94EC}, {0x927F,0x94EA}, {0x9280,0x94F6}, 
+  {0x9283,0x94F3}, {0x9285,0x94DC}, {0x9291,0x94E3}, {0x9293,0x94E8}, {0x9296,0x94E2}, 
+  {0x9298,0x94ED}, {0x929A,0x94EB}, {0x929C,0x8854}, {0x92A0,0x94D1}, {0x92A3,0x94F7}, 
+  {0x92A5,0x94F1}, {0x92A6,0x94DF}, {0x92A8,0x94F5}, {0x92A9,0x94E5}, {0x92AA,0x94D5}, 
+  {0x92AB,0x94EF}, {0x92AC,0x94D0}, {0x92B1,0x94DE}, {0x92B7,0x9500}, {0x92B9,0x9508}, 
+  {0x92BB,0x9511}, {0x92BC,0x9509}, {0x92C1,0x94DD}, {0x92C3,0x9512}, {0x92C5,0x950C}, 
+  {0x92C7,0x94A1}, {0x92CC,0x94E4}, {0x92CF,0x94D7}, {0x92D2,0x950B}, {0x92DD,0x950A}, 
+  {0x92DF,0x9513}, {0x92E3,0x94D8}, {0x92E4,0x9504}, {0x92E5,0x9503}, {0x92E6,0x9514}, 
+  {0x92E8,0x9507}, {0x92EA,0x94FA}, {0x92ED,0x9510}, {0x92EE,0x94D6}, {0x92EF,0x9506}, 
+  {0x92F0,0x9502}, {0x92F1,0x94FD}, {0x92F6,0x950D}, {0x92F8,0x952F}, {0x92FC,0x94A2}, 
+  {0x9301,0x951E}, {0x9306,0x9516}, {0x9307,0x952B}, {0x9308,0x9529}, {0x9310,0x9525}, 
+  {0x9312,0x9515}, {0x9315,0x951F}, {0x9318,0x9524}, {0x9319,0x9531}, {0x931A,0x94EE}, 
+  {0x931B,0x951B}, {0x931F,0x952C}, {0x9320,0x952D}, {0x9322,0x94B1}, {0x9326,0x9526}, 
+  {0x9328,0x951A}, {0x932B,0x9521}, {0x932E,0x9522}, {0x932F,0x9519}, {0x9332,0x5F55}, 
+  {0x9333,0x9530}, {0x9338,0x94FC}, {0x9340,0x951D}, {0x9341,0x9528}, {0x9343,0x952A}, 
+  {0x9346,0x9494}, {0x9347,0x9534}, {0x934B,0x9505}, {0x934D,0x9540}, {0x9354,0x9537}, 
+  {0x9358,0x94E1}, {0x935B,0x953B}, {0x9364,0x9538}, {0x9365,0x9532}, {0x9369,0x9518}, 
+  {0x936C,0x9539}, {0x9370,0x953E}, {0x9375,0x952E}, {0x9376,0x9536}, {0x937A,0x9517}, 
+  {0x937E,0x953A}, {0x9382,0x9541}, {0x9384,0x953F}, {0x9387,0x9545}, {0x938A,0x9551}, 
+  {0x9396,0x9501}, {0x9398,0x9549}, {0x93A2,0x94A8}, {0x93A3,0x84E5}, {0x93A6,0x954F}, 
+  {0x93A7,0x94E0}, {0x93A9,0x94E9}, {0x93AA,0x953C}, {0x93AC,0x9550}, {0x93AE,0x9547}, 
+  {0x93B0,0x9552}, {0x93B3,0x954D}, {0x93B5,0x9553}, {0x93B8,0x954C}, {0x93BF,0x954E}, 
+  {0x93C3,0x955E}, {0x93C7,0x955F}, {0x93C8,0x94FE}, {0x93CC,0x9546}, {0x93CD,0x9559}, 
+  {0x93D1,0x955D}, {0x93D7,0x94FF}, {0x93D8,0x9535}, {0x93DC,0x9557}, {0x93DD,0x9558}, 
+  {0x93DE,0x955B}, {0x93DF,0x94F2}, {0x93E1,0x955C}, {0x93E2,0x9556}, {0x93E4,0x9542}, 
+  {0x93E8,0x933E}, {0x93F5,0x94E7}, {0x93F7,0x9564}, {0x93F9,0x956A}, {0x9403,0x94D9}, 
+  {0x940B,0x94F4}, {0x9410,0x9563}, {0x9412,0x94F9}, {0x9413,0x9566}, {0x9414,0x9561}, 
+  {0x9418,0x949F}, {0x9419,0x956B}, {0x941D,0x9562}, {0x9420,0x9568}, {0x9426,0x950E}, 
+  {0x9427,0x950F}, {0x9428,0x9544}, {0x942E,0x9570}, {0x9432,0x956F}, {0x9433,0x956D}, 
+  {0x9435,0x94C1}, {0x9438,0x94CE}, {0x943A,0x94DB}, {0x943F,0x9571}, {0x9444,0x94F8}, 
+  {0x944A,0x956C}, {0x944C,0x9554}, {0x9452,0x9274}, {0x9454,0x9572}, {0x9460,0x94C4}, 
+  {0x9463,0x9573}, {0x9465,0x9565}, {0x946D,0x9567}, {0x9470,0x94A5}, {0x9472,0x9576}, 
+  {0x9477,0x954A}, {0x9479,0x9569}, {0x947C,0x9523}, {0x947D,0x94BB}, {0x947E,0x92AE}, 
+  {0x947F,0x51FF}, {0x9577,0x957F}, {0x9580,0x95E8}, {0x9582,0x95E9}, {0x9583,0x95EA}, 
+  {0x9586,0x95EB}, {0x9589,0x95ED}, {0x958B,0x5F00}, {0x958C,0x95F6}, {0x958E,0x95F3}, 
+  {0x958F,0x95F0}, {0x9591,0x95F2}, {0x9593,0x95F4}, {0x9594,0x95F5}, {0x9598,0x95F8}, 
+  {0x95A1,0x9602}, {0x95A3,0x9601}, {0x95A5,0x9600}, {0x95A8,0x95FA}, {0x95A9,0x95FD}, 
+  {0x95AB,0x9603}, {0x95AC,0x9606}, {0x95AD,0x95FE}, {0x95B2,0x9605}, {0x95B6,0x960A}, 
+  {0x95B9,0x9609}, {0x95BB,0x960E}, {0x95BC,0x960F}, {0x95BD,0x960D}, {0x95BE,0x9608}, 
+  {0x95BF,0x960C}, {0x95C3,0x9612}, {0x95C8,0x95F1}, {0x95CA,0x9614}, {0x95CB,0x9615}, 
+  {0x95CC,0x9611}, {0x95D0,0x9617}, {0x95D4,0x9616}, {0x95D5,0x9619}, {0x95D6,0x95EF}, 
+  {0x95DC,0x5173}, {0x95DE,0x961A}, {0x95E1,0x9610}, {0x95E5,0x95FC}, {0x9658,0x9649}, 
+  {0x965D,0x9655}, {0x9663,0x9635}, {0x9670,0x9634}, {0x9673,0x9648}, {0x9678,0x9646}, 
+  {0x967D,0x9633}, {0x9689,0x9667}, {0x968A,0x961F}, {0x968E,0x9636}, {0x9695,0x9668}, 
+  {0x969B,0x9645}, {0x96A8,0x968F}, {0x96AA,0x9669}, {0x96B1,0x9690}, {0x96B4,0x9647}, 
+  {0x96B8,0x96B6}, {0x96D6,0x867D}, {0x96D9,0x53CC}, {0x96DB,0x96CF}, {0x96DC,0x6742}, 
+  {0x96E2,0x79BB}, {0x96E3,0x96BE}, {0x96F2,0x4E91}, {0x96FB,0x7535}, {0x9727,0x96FE}, 
+  {0x973D,0x9701}, {0x9742,0x96F3}, {0x9744,0x972D}, {0x9748,0x7075}, {0x975A,0x9753}, 
+  {0x975C,0x9759}, {0x9768,0x9765}, {0x978F,0x5DE9}, {0x97BD,0x9792}, {0x97C3,0x9791}, 
+  {0x97C9,0x97AF}, {0x97CB,0x97E6}, {0x97CC,0x97E7}, {0x97D3,0x97E9}, {0x97D9,0x97EA}, 
+  {0x97DC,0x97EC}, {0x97DE,0x97EB}, {0x97FF,0x54CD}, {0x9801,0x9875}, {0x9802,0x9876}, 
+  {0x9803,0x9877}, {0x9805,0x9879}, {0x9806,0x987A}, {0x9807,0x9878}, {0x9808,0x987B}, 
+  {0x980A,0x987C}, {0x980C,0x9882}, {0x980E,0x9880}, {0x980F,0x9883}, {0x9810,0x9884}, 
+  {0x9811,0x987D}, {0x9812,0x9881}, {0x9813,0x987F}, {0x9817,0x9887}, {0x9818,0x9886}, 
+  {0x981C,0x988C}, {0x9821,0x9889}, {0x9824,0x9890}, {0x9826,0x988F}, {0x982D,0x5934}, 
+  {0x9830,0x988A}, {0x9837,0x9894}, {0x9838,0x9888}, {0x983B,0x9891}, {0x983D,0x9893}, 
+  {0x9846,0x9897}, {0x984C,0x9898}, {0x984D,0x989D}, {0x984E,0x989A}, {0x9853,0x989B}, 
+  {0x9854,0x989C}, {0x9858,0x613F}, {0x9859,0x98A1}, {0x985B,0x98A0}, {0x985E,0x7C7B}, 
+  {0x9862,0x989F}, {0x9865,0x98A2}, {0x9867,0x987E}, {0x986B,0x98A4}, {0x986C,0x98A5}, 
+  {0x986F,0x663E}, {0x9870,0x98A6}, {0x9871,0x9885}, {0x9873,0x989E}, {0x9874,0x98A7}, 
+  {0x98A8,0x98CE}, {0x98AE,0x98D1}, {0x98AF,0x98D2}, {0x98B6,0x98D3}, {0x98BC,0x98D5}, 
+  {0x98C4,0x98D8}, {0x98C6,0x98D9}, {0x98C8,0x98DA}, {0x98DB,0x98DE}, {0x98E0,0x9963}, 
+  {0x98E9,0x9968}, {0x98EA,0x996A}, {0x98EB,0x996B}, {0x98ED,0x996C}, {0x98EF,0x996D}, 
+  {0x98F2,0x996E}, {0x98F4,0x9974}, {0x98FC,0x9972}, {0x98FD,0x9971}, {0x98FE,0x9970}, 
+  {0x9903,0x997A}, {0x9905,0x997C}, {0x9909,0x9977}, {0x990A,0x517B}, {0x990C,0x9975}, 
+  {0x9911,0x997D}, {0x9912,0x9981}, {0x9913,0x997F}, {0x9918,0x4F59}, {0x991B,0x9984}, 
+  {0x991E,0x996F}, {0x9921,0x9985}, {0x9928,0x9986}, {0x9933,0x9967}, {0x9937,0x9987}, 
+  {0x993C,0x9969}, {0x993E,0x998F}, {0x993F,0x998A}, {0x9943,0x998D}, {0x9945,0x9992}, 
+  {0x9948,0x9990}, {0x9949,0x9991}, {0x994A,0x9993}, {0x994B,0x9988}, {0x994C,0x9994}, 
+  {0x9951,0x9965}, {0x9952,0x9976}, {0x9957,0x98E8}, {0x995C,0x990D}, {0x995E,0x998B}, 
+  {0x9962,0x9995}, {0x99AC,0x9A6C}, {0x99AD,0x9A6D}, {0x99AE,0x51AF}, {0x99B1,0x9A6E}, 
+  {0x99B3,0x9A70}, {0x99B4,0x9A6F}, {0x99C1,0x9A73}, {0x99D0,0x9A7B}, {0x99D1,0x9A7D}, 
+  {0x99D2,0x9A79}, {0x99D4,0x9A75}, {0x99D5,0x9A7E}, {0x99D8,0x9A80}, {0x99D9,0x9A78}, 
+  {0x99DB,0x9A76}, {0x99DD,0x9A7C}, {0x99DF,0x9A77}, {0x99E1,0x9A82}, {0x99E2,0x9A88}, 
+  {0x99ED,0x9A87}, {0x99F1,0x9A86}, {0x99FF,0x9A8F}, {0x9A01,0x9A8B}, {0x9A05,0x9A93}, 
+  {0x9A0D,0x9A92}, {0x9A0E,0x9A91}, {0x9A0F,0x9A90}, {0x9A16,0x9A9B}, {0x9A19,0x9A97}, 
+  {0x9A2B,0x9A9E}, {0x9A2D,0x9A98}, {0x9A2E,0x9A9D}, {0x9A30,0x817E}, {0x9A36,0x9A7A}, 
+  {0x9A37,0x9A9A}, {0x9A38,0x9A9F}, {0x9A3E,0x9AA1}, {0x9A40,0x84E6}, {0x9A41,0x9A9C}, 
+  {0x9A42,0x9A96}, {0x9A43,0x9AA0}, {0x9A44,0x9AA2}, {0x9A45,0x9A71}, {0x9A4A,0x9A85}, 
+  {0x9A4D,0x9A81}, {0x9A4F,0x9AA3}, {0x9A55,0x9A84}, {0x9A57,0x9A8C}, {0x9A5A,0x60CA}, 
+  {0x9A5B,0x9A7F}, {0x9A5F,0x9AA4}, {0x9A62,0x9A74}, {0x9A64,0x9AA7}, {0x9A65,0x9AA5}, 
+  {0x9A6A,0x9A8A}, {0x9AAF,0x80AE}, {0x9ACF,0x9AC5}, {0x9AD4,0x4F53}, {0x9AD5,0x9ACC}, 
+  {0x9AD6,0x9ACB}, {0x9B06,0x677E}, {0x9B22,0x9B13}, {0x9B25,0x6597}, {0x9B27,0x95F9}, 
+  {0x9B29,0x960B}, {0x9B2E,0x9604}, {0x9B31,0x90C1}, {0x9B4E,0x9B49}, {0x9B58,0x9B47}, 
+  {0x9B5A,0x9C7C}, {0x9B6F,0x9C81}, {0x9B74,0x9C82}, {0x9B77,0x9C7F}, {0x9B81,0x9C85}, 
+  {0x9B83,0x9C86}, {0x9B8E,0x9C87}, {0x9B90,0x9C90}, {0x9B91,0x9C8D}, {0x9B92,0x9C8B}, 
+  {0x9B9A,0x9C92}, {0x9B9D,0x9C9E}, {0x9B9E,0x9C95}, {0x9BAA,0x9C94}, {0x9BAB,0x9C9B}, 
+  {0x9BAD,0x9C91}, {0x9BAE,0x9C9C}, {0x9BC0,0x9CA7}, {0x9BC1,0x9CA0}, {0x9BC7,0x9CA9}, 
+  {0x9BC9,0x9CA4}, {0x9BCA,0x9CA8}, {0x9BD4,0x9CBB}, {0x9BD6,0x9CAD}, {0x9BDB,0x9CB7}, 
+  {0x9BDD,0x9CB4}, {0x9BE1,0x9CB1}, {0x9BE2,0x9CB5}, {0x9BE4,0x9CB2}, {0x9BE7,0x9CB3}, 
+  {0x9BE8,0x9CB8}, {0x9BEA,0x9CAE}, {0x9BEB,0x9CB0}, {0x9BF0,0x9CB6}, {0x9BF4,0x9CBA}, 
+  {0x9BFD,0x9CAB}, {0x9BFF,0x9CCA}, {0x9C08,0x9CBD}, {0x9C09,0x9CC7}, {0x9C0D,0x9CC5}, 
+  {0x9C10,0x9CC4}, {0x9C12,0x9CC6}, {0x9C13,0x9CC3}, {0x9C20,0x9CCB}, {0x9C23,0x9CA5}, 
+  {0x9C25,0x9CCF}, {0x9C28,0x9CCE}, {0x9C29,0x9CD0}, {0x9C2D,0x9CCD}, {0x9C31,0x9CA2}, 
+  {0x9C32,0x9CCC}, {0x9C33,0x9CD3}, {0x9C35,0x9CD8}, {0x9C37,0x9CA6}, {0x9C39,0x9CA3}, 
+  {0x9C3B,0x9CD7}, {0x9C3E,0x9CD4}, {0x9C45,0x9CD9}, {0x9C48,0x9CD5}, {0x9C49,0x9CD6}, 
+  {0x9C52,0x9CDF}, {0x9C54,0x9CDD}, {0x9C56,0x9CDC}, {0x9C57,0x9CDE}, {0x9C58,0x9C9F}, 
+  {0x9C5D,0x9CBC}, {0x9C5F,0x9C8E}, {0x9C67,0x9CE2}, {0x9C6D,0x9C9A}, {0x9C78,0x9C88}, 
+  {0x9C7A,0x9CA1}, {0x9CE5,0x9E1F}, {0x9CE9,0x9E20}, {0x9CEC,0x51EB}, {0x9CF3,0x51E4}, 
+  {0x9CF4,0x9E23}, {0x9CF6,0x9E22}, {0x9D06,0x9E29}, {0x9D07,0x9E28}, {0x9D09,0x9E26}, 
+  {0x9D15,0x9E35}, {0x9D1B,0x9E33}, {0x9D1D,0x9E32}, {0x9D1F,0x9E31}, {0x9D23,0x9E2A}, 
+  {0x9D26,0x9E2F}, {0x9D28,0x9E2D}, {0x9D2F,0x9E38}, {0x9D30,0x9E39}, {0x9D3B,0x9E3F}, 
+  {0x9D3F,0x9E3D}, {0x9D42,0x9E3A}, {0x9D51,0x9E43}, {0x9D52,0x9E46}, {0x9D53,0x9E41}, 
+  {0x9D5C,0x9E48}, {0x9D5D,0x9E45}, {0x9D60,0x9E44}, {0x9D61,0x9E49}, {0x9D6A,0x9E4C}, 
+  {0x9D6C,0x9E4F}, {0x9D6F,0x9E4E}, {0x9D72,0x9E4A}, {0x9D87,0x9E2B}, {0x9D89,0x9E51}, 
+  {0x9D93,0x9E4B}, {0x9D98,0x9E55}, {0x9D9A,0x9E57}, {0x9DA5,0x9E5B}, {0x9DA9,0x9E5C}, 
+  {0x9DAF,0x83BA}, {0x9DB4,0x9E64}, {0x9DBB,0x9E58}, {0x9DBC,0x9E63}, {0x9DC0,0x9E5A}, 
+  {0x9DC2,0x9E5E}, {0x9DC4,0x9E21}, {0x9DD3,0x9E67}, {0x9DD7,0x9E25}, {0x9DD9,0x9E37}, 
+  {0x9DDA,0x9E68}, {0x9DE5,0x9E36}, {0x9DE6,0x9E6A}, {0x9DEF,0x9E69}, {0x9DF2,0x9E6B}, 
+  {0x9DF3,0x9E47}, {0x9DF8,0x9E6C}, {0x9DF9,0x9E70}, {0x9DFA,0x9E6D}, {0x9E0C,0x9E71}, 
+  {0x9E15,0x9E2C}, {0x9E1A,0x9E66}, {0x9E1B,0x9E73}, {0x9E1D,0x9E42}, {0x9E1E,0x9E3E}, 
+  {0x9E7A,0x9E7E}, {0x9E7C,0x7877}, {0x9E7D,0x76D0}, {0x9E97,0x4E3D}, {0x9EA5,0x9EA6}, 
+  {0x9EA9,0x9EB8}, {0x9EBD,0x4E48}, {0x9ECC,0x9EC9}, {0x9EDE,0x70B9}, {0x9EE8,0x515A}, 
+  {0x9EF2,0x9EEA}, {0x9EF7,0x9EE9}, {0x9EFD,0x9EFE}, {0x9EFF,0x9F0B}, {0x9F09,0x9F0D}, 
+  {0x9F4A,0x9F50}, {0x9F4B,0x658B}, {0x9F4F,0x9F51}, {0x9F52,0x9F7F}, {0x9F54,0x9F80}, 
+  {0x9F59,0x9F85}, {0x9F5C,0x9F87}, {0x9F5F,0x9F83}, {0x9F60,0x9F86}, {0x9F61,0x9F84}, 
+  {0x9F66,0x9F88}, {0x9F6A,0x9F8A}, {0x9F6C,0x9F89}, {0x9F72,0x9F8B}, {0x9F77,0x9F8C}, 
+  {0x9F8D,0x9F99}, {0x9F90,0x5E9E}, {0x9F94,0x9F9A}, {0x9F95,0x9F9B}, {0x9F9C,0x9F9F}
+};
+
+
+
+/* the letters correspond to unicode characters which
+ * have Lu, Ll, Lt, Lm, Lo, Mn, Mc, or Me in their
+ * GENERAL CATEGORY */
+
+#define NUM_LETTER_INFO 274
+static const unirange letter_info[NUM_LETTER_INFO] = {
+  {0x41,0x5a}, {0x61,0x7a}, {0xaa,0xaa}, {0xb5,0xb5}, 
+  {0xba,0xba}, {0xc0,0xd6}, {0xd8,0xf6}, {0xf8,0x1f5}, 
+  {0x1fa,0x217}, {0x250,0x2a8}, {0x2b0,0x2b8}, {0x2bb,0x2c1}, 
+  {0x2d0,0x2d1}, {0x2e0,0x2e4}, {0x300,0x345}, {0x360,0x361}, 
+  {0x37a,0x37a}, {0x386,0x386}, {0x388,0x38a}, {0x38c,0x38c}, 
+  {0x38e,0x3a1}, {0x3a3,0x3ce}, {0x3d0,0x3d6}, {0x3da,0x3da}, 
+  {0x3dc,0x3dc}, {0x3de,0x3de}, {0x3e0,0x3e0}, {0x3e2,0x3f3}, 
+  {0x401,0x40c}, {0x40e,0x44f}, {0x451,0x45c}, {0x45e,0x481}, 
+  {0x483,0x486}, {0x490,0x4c4}, {0x4c7,0x4c8}, {0x4cb,0x4cc}, 
+  {0x4d0,0x4eb}, {0x4ee,0x4f5}, {0x4f8,0x4f9}, {0x531,0x556}, 
+  {0x559,0x559}, {0x561,0x587}, {0x591,0x5a1}, {0x5a3,0x5b9}, 
+  {0x5bb,0x5bd}, {0x5bf,0x5bf}, {0x5c1,0x5c2}, {0x5c4,0x5c4}, 
+  {0x5d0,0x5ea}, {0x5f0,0x5f2}, {0x621,0x63a}, {0x640,0x652}, 
+  {0x670,0x6b7}, {0x6ba,0x6be}, {0x6c0,0x6ce}, {0x6d0,0x6d3}, 
+  {0x6d5,0x6e8}, {0x6ea,0x6ed}, {0x901,0x903}, {0x905,0x939}, 
+  {0x93c,0x94d}, {0x951,0x954}, {0x958,0x963}, {0x981,0x983}, 
+  {0x985,0x98c}, {0x98f,0x990}, {0x993,0x9a8}, {0x9aa,0x9b0}, 
+  {0x9b2,0x9b2}, {0x9b6,0x9b9}, {0x9bc,0x9bc}, {0x9be,0x9c4}, 
+  {0x9c7,0x9c8}, {0x9cb,0x9cd}, {0x9d7,0x9d7}, {0x9dc,0x9dd}, 
+  {0x9df,0x9e3}, {0x9f0,0x9f1}, {0xa02,0xa02}, {0xa05,0xa0a}, 
+  {0xa0f,0xa10}, {0xa13,0xa28}, {0xa2a,0xa30}, {0xa32,0xa33}, 
+  {0xa35,0xa36}, {0xa38,0xa39}, {0xa3c,0xa3c}, {0xa3e,0xa42}, 
+  {0xa47,0xa48}, {0xa4b,0xa4d}, {0xa59,0xa5c}, {0xa5e,0xa5e}, 
+  {0xa70,0xa74}, {0xa81,0xa83}, {0xa85,0xa8b}, {0xa8d,0xa8d}, 
+  {0xa8f,0xa91}, {0xa93,0xaa8}, {0xaaa,0xab0}, {0xab2,0xab3}, 
+  {0xab5,0xab9}, {0xabc,0xac5}, {0xac7,0xac9}, {0xacb,0xacd}, 
+  {0xae0,0xae0}, {0xb01,0xb03}, {0xb05,0xb0c}, {0xb0f,0xb10}, 
+  {0xb13,0xb28}, {0xb2a,0xb30}, {0xb32,0xb33}, {0xb36,0xb39}, 
+  {0xb3c,0xb43}, {0xb47,0xb48}, {0xb4b,0xb4d}, {0xb56,0xb57}, 
+  {0xb5c,0xb5d}, {0xb5f,0xb61}, {0xb82,0xb83}, {0xb85,0xb8a}, 
+  {0xb8e,0xb90}, {0xb92,0xb95}, {0xb99,0xb9a}, {0xb9c,0xb9c}, 
+  {0xb9e,0xb9f}, {0xba3,0xba4}, {0xba8,0xbaa}, {0xbae,0xbb5}, 
+  {0xbb7,0xbb9}, {0xbbe,0xbc2}, {0xbc6,0xbc8}, {0xbca,0xbcd}, 
+  {0xbd7,0xbd7}, {0xc01,0xc03}, {0xc05,0xc0c}, {0xc0e,0xc10}, 
+  {0xc12,0xc28}, {0xc2a,0xc33}, {0xc35,0xc39}, {0xc3e,0xc44}, 
+  {0xc46,0xc48}, {0xc4a,0xc4d}, {0xc55,0xc56}, {0xc60,0xc61}, 
+  {0xc82,0xc83}, {0xc85,0xc8c}, {0xc8e,0xc90}, {0xc92,0xca8}, 
+  {0xcaa,0xcb3}, {0xcb5,0xcb9}, {0xcbe,0xcc4}, {0xcc6,0xcc8}, 
+  {0xcca,0xccd}, {0xcd5,0xcd6}, {0xcde,0xcde}, {0xce0,0xce1}, 
+  {0xd02,0xd03}, {0xd05,0xd0c}, {0xd0e,0xd10}, {0xd12,0xd28}, 
+  {0xd2a,0xd39}, {0xd3e,0xd43}, {0xd46,0xd48}, {0xd4a,0xd4d}, 
+  {0xd57,0xd57}, {0xd60,0xd61}, {0xe01,0xe2e}, {0xe30,0xe3a}, 
+  {0xe40,0xe4e}, {0xe81,0xe82}, {0xe84,0xe84}, {0xe87,0xe88}, 
+  {0xe8a,0xe8a}, {0xe8d,0xe8d}, {0xe94,0xe97}, {0xe99,0xe9f}, 
+  {0xea1,0xea3}, {0xea5,0xea5}, {0xea7,0xea7}, {0xeaa,0xeab}, 
+  {0xead,0xeae}, {0xeb0,0xeb9}, {0xebb,0xebd}, {0xec0,0xec4}, 
+  {0xec6,0xec6}, {0xec8,0xecd}, {0xedc,0xedd}, {0xf18,0xf19}, 
+  {0xf35,0xf35}, {0xf37,0xf37}, {0xf39,0xf39}, {0xf40,0xf47}, 
+  {0xf49,0xf69}, {0xf71,0xf84}, {0xf86,0xf87}, {0xf90,0xf95}, 
+  {0xf97,0xf97}, {0xf99,0xfad}, {0xfb1,0xfb7}, {0xfb9,0xfb9}, 
+  {0x10a0,0x10c5}, {0x10d0,0x10f6}, {0x1100,0x1159}, {0x115f,0x11a2}, 
+  {0x11a8,0x11f9}, {0x1e00,0x1e9b}, {0x1ea0,0x1ef9}, {0x1f00,0x1f15}, 
+  {0x1f18,0x1f1d}, {0x1f20,0x1f45}, {0x1f48,0x1f4d}, {0x1f50,0x1f57}, 
+  {0x1f59,0x1f59}, {0x1f5b,0x1f5b}, {0x1f5d,0x1f5d}, {0x1f5f,0x1f7d}, 
+  {0x1f80,0x1fb4}, {0x1fb6,0x1fbc}, {0x1fbe,0x1fbe}, {0x1fc2,0x1fc4}, 
+  {0x1fc6,0x1fcc}, {0x1fd0,0x1fd3}, {0x1fd6,0x1fdb}, {0x1fe0,0x1fec}, 
+  {0x1ff2,0x1ff4}, {0x1ff6,0x1ffc}, {0x207f,0x207f}, {0x20d0,0x20e1}, 
+  {0x2102,0x2102}, {0x2107,0x2107}, {0x210a,0x2113}, {0x2115,0x2115}, 
+  {0x2118,0x211d}, {0x2124,0x2124}, {0x2126,0x2126}, {0x2128,0x2128}, 
+  {0x212a,0x2131}, {0x2133,0x2138}, {0x3005,0x3005}, {0x302a,0x302f}, 
+  {0x3031,0x3035}, {0x3041,0x3094}, {0x3099,0x309e}, {0x30a1,0x30fa}, 
+  {0x30fc,0x30fe}, {0x3105,0x312c}, {0x3131,0x318e}, {0x4e00,0x9fa5}, 
+  {0xac00,0xd7a3}, {0xf900,0xfa2d}, {0xfb00,0xfb06}, {0xfb13,0xfb17}, 
+  {0xfb1e,0xfb28}, {0xfb2a,0xfb36}, {0xfb38,0xfb3c}, {0xfb3e,0xfb3e}, 
+  {0xfb40,0xfb41}, {0xfb43,0xfb44}, {0xfb46,0xfbb1}, {0xfbd3,0xfd3d}, 
+  {0xfd50,0xfd8f}, {0xfd92,0xfdc7}, {0xfdf0,0xfdfb}, {0xfe20,0xfe23}, 
+  {0xfe70,0xfe72}, {0xfe74,0xfe74}, {0xfe76,0xfefc}, {0xff21,0xff3a}, 
+  {0xff41,0xff5a}, {0xff66,0xffbe}, {0xffc2,0xffc7}, {0xffca,0xffcf}, 
+  {0xffd2,0xffd7}, {0xffda,0xffdc}
+};
+
+
+/* the digits correspond to unicode characters which
+ * have Nd in their GENERAL CATEGORY */
+
+#define NUM_DIGIT_INFO 16
+static const unirange digit_info[NUM_DIGIT_INFO] = {
+  {0x30,0x39}, {0x660,0x669}, {0x6f0,0x6f9}, {0x966,0x96f}, 
+  {0x9e6,0x9ef}, {0xa66,0xa6f}, {0xae6,0xaef}, {0xb66,0xb6f}, 
+  {0xbe7,0xbef}, {0xc66,0xc6f}, {0xce6,0xcef}, {0xd66,0xd6f}, 
+  {0xe50,0xe59}, {0xed0,0xed9}, {0xf20,0xf29}, {0xff10,0xff19}
+};
+
+
+/* the spaces correspond to unicode characters which
+ * have Zs, Zl, or Zp in their GENERAL CATEGORY */
+
+#define NUM_SPACE_INFO 5
+static const unirange space_info[NUM_SPACE_INFO] = {
+  {0x20,0x20}, {0xa0,0xa0}, {0x2000,0x200b}, {0x2028,0x2029}, 
+  {0x3000,0x3000}
+};
+
+
+
+/* parse_utf8_char parses the next utf-8 character, placing its
+ * unicode equivalent in *value. The length of the utf-8 character
+ * is returned */
+int parse_utf8_char(const unsigned char *here,
+		    const unsigned char *end,
+		    unsigned short *value) {
+  unsigned short c1;
+  unsigned short c2;
+  unsigned short c3;
+  
+  *value = 0; /* will be the value for illegal characters */
+  
+  if (here <= end) {
+    c1 = (unsigned short)(*here);
+    
+    if (c1 <= 0x7f) {
+      /* found a one-byte character */
+      *value = c1;
+      return 1;
+      
+    } else if (c1 >= 0xc0 && c1 <= 0xdf && here+1 <= end &&
+	       (c2=(unsigned short)(*(here+1))) >= 0x80) {
+      /* found a two-byte character */
+      *value = ((c1 & 0x1f) << 6) + (c2 & 0x3f);
+      return 2;
+      
+    } else if (c1 >= 0xe0 && c1 <= 0xef && here+2 <= end &&
+	       (c2=(unsigned int)(*(here+1))) >= 0x80 &&
+	       (c3=(unsigned int)(*(here+2))) >= 0x80) {
+      /* found a three-byte character */
+      *value = ((c1 & 0xf) << 12) + ((c2 & 0x3f) << 6) +
+	(c3 & 0x3f);
+      return 3;
+      
+    } else {
+      /* error in encoding, return the length as 1 */
+      return 1;
+    }
+  }
+
+  /* end of string */
+  return 0;
+}
+
+
+/* output_utf8_char encodes a unicode character as a UTF-8 character.
+ * The length of the encoding is returned. If the string was not
+ * long enough to encode the character 0 is returned. */
+int output_utf8_char (unsigned short value,
+		      unsigned char *here,
+		      unsigned char *end) {
+  int len = (int)(end - here + 1); /* end is the last character */
+  if (value < 0x80) {
+    /* will be encoded in one byte */
+    if (len >= 1) {
+      *here = (unsigned char)value;
+      return 1;
+    }
+
+  } else if (value < 0x800) {
+    /* will be encoded in two bytes */
+    if (len >= 2) {
+      *here++ = 0xc0 | (unsigned char)((value >> 6) & 0x1f);
+      *here = 0x80 | (unsigned char)(value & 0x3f);
+
+      return 2;
+    }
+
+  } else {
+    /* will be encoded in three bytes */
+    if (len >= 3) {
+      *here++ = 0xe0 | (unsigned char)((value >> 12) & 0xf);
+      *here++ = 0x80 | (unsigned char)((value >> 6) & 0x3f);
+      *here = 0x80 | (unsigned char)(value & 0x3f);
+      return 3;
+    }
+  }
+
+  return 0;
+}
+
+
+static int lookup_decompose_table (unsigned short value) {
+  int first = 0;
+  int last = NUM_DECOMPOSE_INFO;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < decompose_info[here].ch) {
+      last = here;
+    } else if (value > decompose_info[here].ch) {
+      first = here+1;
+    } else {
+      return here;
+    }
+  }
+
+  return -1;
+}
+
+/* decompose_str will decompose a unicode string into its canonical
+ * equivalents. NULL is returned if the input array was not 
+ * large enough to contain the fully decomposed string (the array
+ * will be in a correct, but partially decomposed state). The input 
+ * must be null-terminated. */
+unsigned short *decompose_str (unsigned short *input,
+			       int max_output_len) {
+  int curpos = 0;
+  int curlen = unicode_strlen (input);
+  int tablepos = 0;
+  int leninc;
+  int i;
+
+  while (input[curpos] != 0) {
+    tablepos = lookup_decompose_table (input[curpos]);
+    if (tablepos >= 0) {
+      /* found a decomposition */
+      leninc = unicode_strnlen (decompose_info[tablepos].str, 3)-1;
+      if (curlen+leninc < max_output_len) {
+	/* enough space for this decomposition */
+
+	if (leninc > 1) {
+	  /* we have to shift the array along */
+	  for (i=curlen-1; i>=curpos; i--) {
+	    input[i+leninc] = input[i];
+	  }
+	  input[curlen+leninc] = 0;
+	  curlen += leninc;
+	}
+
+	/* decompose the character */
+	for (i=0; i<=leninc; i++) {
+	  input[curpos+i] = decompose_info[tablepos].str[i];
+	}
+
+	/* note: curpos is not incremented because the decomposed */
+	/*       characters might need decomposing */
+
+      } else {
+	/* no space left in string */
+	return NULL;
+      }
+
+    } else {
+      /* the character cannot be decomposed */
+      curpos++;
+    }
+  }
+
+  return input;
+}
+
+
+
+/* unicode_cat_data is a combination of the letter, digit, and
+ * space information in a form that is quick to look up.
+ * The information about each byte is stored in two bits
+ *
+ * 00 - neither letter, digit or space
+ * 01 - letter
+ * 10 - space
+ * 11 - digit
+ *
+ * You can test for letter | space by looking at the right
+ * column
+ */
+unsigned long *unicode_cat_data;
+
+void create_unicat_data () {
+  int i=0;
+  int min_start=0;
+  int min_end=0;
+  register unsigned long min_value=0; /* filling the whole byte */
+  
+  const unirange *letter_here = letter_info;
+  const unirange *letter_end = letter_info+NUM_LETTER_INFO;
+  const unirange *digit_here = digit_info;
+  const unirange *digit_end = digit_info+NUM_DIGIT_INFO;
+  const unirange *space_here = space_info;
+  const unirange *space_end = space_info+NUM_SPACE_INFO;
+
+  if (unicode_cat_data != NULL) return;
+  unicode_cat_data = malloc (0x10000/4);
+  if (unicode_cat_data == NULL) return;
+  
+  while (i <= 0xffff) {
+    /* decide what to fill with next */
+    min_start = i;
+    min_end = 0xffff;
+    min_value = 0; /* 00 */
+    
+    while (letter_here < letter_end && letter_here->last < i) letter_here++;
+    if (letter_here < letter_end && letter_here->last <= min_end) {
+      min_start = letter_here->first;
+      min_end = letter_here->last;
+      min_value = 0x55555555; /* 01 */
+    }
+    
+    while (digit_here < digit_end && digit_here->last < i) digit_here++;
+    if (digit_here < digit_end && digit_here->last <= min_end) {
+      min_start = digit_here->first;
+      min_end = digit_here->last;
+      min_value = 0xffffffff; /* 11 */
+    }
+    
+    while (space_here < space_end && space_here->last < i) space_here++;
+    if (space_here < space_end && space_here->last <= min_end) {
+      min_start = space_here->first;
+      min_end = space_here->last;
+      min_value = 0xaaaaaaaa; /* 10 */
+    }
+
+    if (min_start < i) min_start = i;
+    else if (min_start > i) {
+      min_end = min_start-1;
+      min_start = i;
+      min_value = 0; /* 00 */
+    }
+
+    /* fill the entries from min_start to min_end with min_value */
+    while (i <= min_end) {
+      /* special version for common case */
+      if (i % 16 == 0) {
+	unicode_cat_data[i/16] = min_value; /* doesn't matter if too long */
+	i += 16;
+	if (i > min_end) {
+	  i = min_end+1;
+	  break;
+	}
+	
+      } else {
+	register unsigned long mask = 3 << ((i % 16) * 2);
+	unicode_cat_data[i/16] = (unicode_cat_data[i/16] & (~mask)) |
+				  (min_value & mask);
+	i++;
+      }
+    }
+  }
+}
+
+/* does a binary search on a range table */
+static int in_unirange (const unirange *info, int num_info,
+			unsigned short value) {
+  int first = 0;
+  int last = num_info;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < info[here].first) {
+      last = here;
+    } else if (value > info[here].last) {
+      first = here+1;
+    } else {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+
+
+/* tests to see whether 'value' is a valid Unicode letter */
+int is_unicode_letter (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(letter_info, NUM_LETTER_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x1);
+}
+
+/* tests to see whether 'value' is a valid Unicode digit */
+int is_unicode_digit (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(digit_info, NUM_DIGIT_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x3);
+}
+
+/* tests to see whether 'value' is a valid Unicode letter or 
+ * digit */
+int is_unicode_letdig (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return (in_unirange(letter_info, NUM_LETTER_INFO, value) ||
+	    in_unirange(digit_info, NUM_DIGIT_INFO, value));
+    
+  }
+
+  return ((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x1);
+}
+
+/* tests to see whether 'value' is a valid space
+ * The test includes both "C" spaces and "Unicode" spaces, i.e. 
+ * form-feed, newline, carriage return, horizontal tab,
+ * vertical tab, and the Zs, Zl, and Zp Unicode categorizations */
+int is_unicode_space (unsigned short value) {
+  if (value < 0x80) return isspace (value);
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(space_info, NUM_SPACE_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x2);
+}
+
+/* returns the length of the unicode string */
+int unicode_strlen (const unsigned short *str) {
+  int len = 0;
+
+  /* keep going till you find the null-terminator */
+  while (*str != 0) {
+    len++;
+    str++;
+  }
+
+  return len;
+}
+
+/* returns the length of the unicode string, up to a maximum */
+int unicode_strnlen (const unsigned short *str, int max_length) {
+  int len = 0;
+
+  /* keep going till you find the null-terminator */
+  while (*str != 0 && len < max_length ) {
+    len++;
+    str++;
+  }
+
+  return len;
+}
+
+
+/* Does a binary search on a relate table, returns -1 if it is not
+ * found. */
+static int search_unirelate (const unirelate *info, int num_info,
+			     unsigned short value) {
+  int first = 0;
+  int last = num_info;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < info[here].ch1) {
+      last = here;
+    } else if (value > info[here].ch1) {
+      first = here+1;
+    } else {
+      return here;
+    }
+  }
+
+  return -1;
+}
+
+
+/* returns the upper-case equivalent of value */
+unsigned short unicode_toupper (unsigned short value) {
+  int related = search_unirelate (toupper_info, NUM_TOUPPER_INFO, value);
+  if (related >= 0) {
+    value = toupper_info[related].ch2;
+  }
+  return value;
+}
+
+/* returns the lower-case equivalent of value */
+unsigned short unicode_tolower (unsigned short value) {
+  int related = search_unirelate (tolower_info, NUM_TOLOWER_INFO, value);
+  if (related >= 0) {
+    value = tolower_info[related].ch2;
+  }
+  return value;
+}
+
+/* returns the simplified Chinese character equivalent of 
+ * another Chinese character */
+unsigned short unicode_tosimplified (unsigned short value) {
+  int related = search_unirelate (tosimplified_info, NUM_TOSIMPLIFIED_INFO, value);
+  if (related >= 0) {
+    value = tosimplified_info[related].ch2;
+  }
+  return value;
+}
+
+
+/* converts a utf-8 word (string with length stored in the first byte
+ * to a Unicode array. To handle all situations the output buffer should
+ * be 256 unsigned shorts long. The output will also have the length as
+ * the first entry. */
+unsigned short *utf8_word_to_unicode (const unsigned char *input,
+				      unsigned short *output,
+				      int max_output_length) {
+  int inlen = *input;
+  const unsigned char *inhere = input+1;
+  const unsigned char *inend = &inhere[inlen-1];
+  unsigned short c;
+  int clen;
+  
+  int outlen = 0;
+  unsigned short *outhere = output+1;
+  
+  while (inhere <= inend && inlen < max_output_length-1) {
+    /* decode the character */
+    clen = parse_utf8_char (inhere, inend, &c);
+    inhere += clen;
+
+    if (clen > 0) {
+      /* store the character */
+      *outhere = c;
+      outhere++;
+      outlen++;
+    }
+  }
+
+  output[0] = outlen;
+  return output;
+}
+
+
+/* converts a unicode word buffer (with the length stored in the
+ * entry) to a utf8 encoded word output (with the length stored in
+ * the first byte. Only 255 bytes (not characters) can be stored 
+ * in the output. */
+unsigned char *unicode_to_utf8_word (const unsigned short *input,
+				     unsigned char *output,
+				     int max_output_length) {
+  int inlen = *input;
+  const unsigned short *word = input + 1;
+  int in_i = 0;
+  int clen;
+
+  int outlen = 0;
+  unsigned char *outhere = output+1;
+  unsigned char *outend = output+max_output_length;
+
+  while (in_i < inlen) {
+    if ((clen=output_utf8_char(word[in_i], outhere, outend)) == 0) {
+      /* ran out of space to encode the character */
+      break;
+    }
+
+    outhere += clen;
+    outlen += clen;
+    in_i++;
+  }
+
+  output[0] = outlen;
+
+  return output;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/unitool.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/unitool.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/unitool.h	(revision 10506)
@@ -0,0 +1,88 @@
+#ifndef UNITOOL_H
+#define UNITOOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* This module is based on Unicode 2.1 */
+
+
+/* parse_utf8_char parses the next utf-8 character, placing its
+ * unicode equivalent in *value. The length of the utf-8 character
+ * is returned. end is the address of the last character. */
+int parse_utf8_char (const unsigned char *here,
+		     const unsigned char *end,
+		     unsigned short *value);
+
+/* output_utf8_char encodes a unicode character as a UTF-8 character.
+ * The length of the encoding is returned. If the string was not
+ * long enough to encode the character 0 is returned. end is the
+ * address of the last character */
+int output_utf8_char (unsigned short value,
+		      unsigned char *here,
+		      unsigned char *end);
+
+/* decompose_str will decompose a unicode string into its canonical
+ * equivalents. NULL is returned if the input array was not 
+ * large enough to contain the fully decomposed string (the array
+ * will be in a correct, but partially decomposed state). The input 
+ * must be null-terminated. */
+unsigned short *decompose_str (unsigned short *input,
+			       int max_output_len);
+
+/* tests to see whether 'value' is a valid Unicode letter */
+int is_unicode_letter (unsigned short value);
+
+/* tests to see whether 'value' is a valid Unicode digit */
+int is_unicode_digit (unsigned short value);
+
+/* tests to see whether 'value' is a valid Unicode letter or 
+ * digit */
+int is_unicode_letdig (unsigned short value);
+
+/* tests to see whether 'value' is a valid space
+ * The test includes both "C" spaces and "Unicode" spaces, i.e. 
+ * form-feed, newline, carriage return, horizontal tab,
+ * vertical tab, and the Zs, Zl, and Zp Unicode categorizations */
+int is_unicode_space (unsigned short value);
+
+/* returns the length of the unicode string */
+int unicode_strlen (const unsigned short *str);
+
+/* returns the length of the unicode string, up to a maximum */
+int unicode_strnlen (const unsigned short *str, int max_length);
+
+/* returns the upper-case equivalent of value */
+unsigned short unicode_toupper (unsigned short value);
+
+/* returns the lower-case equivalent of value */
+unsigned short unicode_tolower (unsigned short value);
+
+/* returns the simplified Chinese character equivalent of 
+ * another Chinese character */
+unsigned short unicode_tosimplified (unsigned short value);
+
+
+/* converts a utf-8 word (string with length stored in the first byte
+ * to a Unicode array. To handle all situations the output buffer should
+ * be 256 unsigned shorts long. The output will also have the length as
+ * the first entry. */
+unsigned short *utf8_word_to_unicode (const unsigned char *input,
+				      unsigned short *output,
+				      int max_output_length);
+
+/* converts a unicode word buffer (with the length stored in the
+ * entry) to a utf8 encoded word output (with the length stored in
+ * the first byte. Only 255 bytes (not characters) can be stored 
+ * in the output. */
+unsigned char *unicode_to_utf8_word (const unsigned short *input,
+				     unsigned char *output,
+				     int max_output_length);
+
+#ifdef __cplusplus
+	   }
+#endif
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/win32in.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/win32in.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/win32in.c	(revision 10506)
@@ -0,0 +1,86 @@
+#include "longlong.h"
+
+/* This module provides an equivalent of <netinet/in.h> on  */
+/* unix systems. */
+
+unsigned long htonl(unsigned long x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) |
+		((x << 8) & 0x00FF0000) | ((x << 24) & 0xFF000000);
+#endif
+
+	return x;
+}
+
+mg_ullong ntohll(mg_ullong x)
+{
+#if defined (LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = 
+	  ((x >> 56) & 0x00000000000000FF) | ((x >> 40) & 0x000000000000FF00) |
+	  ((x >> 24) & 0x0000000000FF0000) | ((x >> 8)  & 0x00000000FF000000) |
+	  ((x << 8)  & 0x000000FF00000000) | ((x << 24) & 0x0000FF0000000000) |
+		((x << 40) & 0x00FF000000000000) | ((x << 56) & 0xFF00000000000000);
+#endif
+  return x;
+}
+
+unsigned long ntohl(unsigned long x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) |
+		((x << 8) & 0x00FF0000) | ((x << 24) & 0xFF000000);
+#endif
+	return x;
+}
+
+unsigned short htons(unsigned short x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 8) & 0x00FF) | ((x << 8) & 0xFF00);
+#endif
+	return x;
+}
+
+unsigned short ntohs(unsigned short x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 8) & 0x00FF) | ((x << 8) & 0xFF00);
+#endif
+	return x;
+}
+
+/* just to test stuff
+#include <stdio.h>
+
+main () {
+	long x;
+	short sx;
+
+	x = 0x000000FF;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0x0000FF00;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0x00FF0000;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0xFF000000;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n\n",(int)x);
+
+	sx = 0x00FF;
+	printf ("before %i, ",(int)sx);
+	sx = htons (sx);
+	printf ("after %i\n",(int)sx);
+
+	sx = 0xFF00;
+	printf ("before %i, ",(int)sx);
+	sx = htons (sx);
+	printf ("after %i\n",(int)sx);
+}
+*/
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/win32in.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/win32in.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/win32in.h	(revision 10506)
@@ -0,0 +1,10 @@
+/* This module provides an equivalent of <netinet/in.h> on  */
+/* unix systems. */
+
+#include "longlong.h"
+
+unsigned long htonl(unsigned long x);
+unsigned long ntohl(unsigned long x);
+mg_ullong ntohll(mg_ullong x);
+unsigned short htons(unsigned short x);
+unsigned short ntohs(unsigned short x);
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/xmalloc.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/xmalloc.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/lib/xmalloc.c	(revision 10506)
@@ -0,0 +1,111 @@
+/* xmalloc.c -- malloc with out of memory checking
+   Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#if __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#else
+VOID *malloc ();
+VOID *realloc ();
+void free ();
+#endif
+
+/* This is for other GNU distributions with internationalized messages.
+   The GNU C Library itself does not yet support such messages.  */
+#if HAVE_LIBINTL_H
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* Exit value when the requested amount of memory is not available.
+   The caller may set it to some other value.  */
+int xmalloc_exit_failure = EXIT_FAILURE;
+
+#if defined(__WIN32__)
+void error (int, int, const char *, ...);
+#else
+#if __STDC__ && (HAVE_VPRINTF || HAVE_DOPRNT)
+void error (int, int, const char *, ...);
+#else
+void error (int, int, char *, char *, char *, char *, char *, char *, char *, char *, char *);
+#endif
+#endif;
+
+static VOID *
+fixup_null_alloc (n)
+     size_t n;
+{
+  VOID *p;
+
+  p = 0;
+  if (n == 0)
+    p = malloc ((size_t) 1);
+  if (p == 0)
+    error (xmalloc_exit_failure, 0, gettext ("Memory exhausted"));
+  return p;
+}
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+VOID *
+xmalloc (n)
+     size_t n;
+{
+  VOID *p;
+
+  p = malloc (n);
+  if (p == 0)
+    p = fixup_null_alloc (n);
+  return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+   with error checking.
+   If P is NULL, run xmalloc.  */
+
+VOID *
+xrealloc (p, n)
+     VOID *p;
+     size_t n;
+{
+  if (p == 0)
+    return xmalloc (n);
+  p = realloc (p, n);
+  if (p == 0)
+    p = fixup_null_alloc (n);
+  return p;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_compression_dict.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_compression_dict.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_compression_dict.1	(revision 10506)
@@ -0,0 +1,219 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_compression_dict 1 \*(Dt CITRI
+.SH NAME
+mg_compression_dict \- build a compression dictionary.
+.SH SYNOPSIS
+.B mg_compression_dict
+[
+.B \-h
+]
+[
+.BR \-C " |"
+.BR \-P " |"
+.B  \-S
+]
+.if n .ti +9n
+[
+.BR \-0 " |"
+.BR \-1 " |"
+.BR \-2 " |"
+.B  \-3
+]
+[
+.BR \-H " |"
+.BR \-B " |"
+.BR \-D " |"
+.BR \-Y " |"
+.B  \-M
+]
+.if n .ti +9n
+.if t .ti +.5i
+[
+.BI \-l " lookback"
+]
+[
+.BI \-k " mem"
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_compression_dict
+builds a compression dictionary based on the statistics gathered
+during the first pass over the text.  The options to the program are
+mainly concerned with limiting the amount of memory the dictionary
+will use and with how the text compressor will cope with any novel
+words found during the compression phase.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-C
+Build a complete dictionary from the statistics file.  If during the
+text compression phase a novel word is found, then the compressor will
+produce an error message and stop.
+.TP
+.B \-P
+Build a partial dictionary from the statistics file.  This dictionary
+assumes that the statistics file are based on the entire text.  The
+statistics of words not includes in the dictionary are used to
+calculate the escape probability.  If novel words are being coded
+character by character, then there may not be a Huffman code for every
+possible character.  This means that the compressor may fail if a novel
+word contains a novel character.
+.TP
+.B \-S
+Build a seed dictionary from the statistics file.  This dictionary
+assumes that the statistics file is based on only a portion of the
+text to be compressed.  The probability of a novel word is based on the
+number of words that have only occurred once.  If novel words are being
+coded character by character, then the Huffman codes for characters are
+based on the frequency of characters in the dictionary.
+.TP
+.B \-0
+All words from the statistics file are included in the built
+dictionary.
+.TP
+.B \-1
+Words are included in the dictionary until the dictionary reaches the
+desired size.  Words are selected for the dictionary based on the order
+they occurred in the source text.
+.TP
+.B \-2
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.
+.TP
+.B \-3
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.  Words are the shuffled back and forth between the
+`keep' and `discard' lists to find the `optimal' set of words that
+should be in the dictionary.
+.TP
+.B \-H
+This specifies that novel words will be coded character by character
+using Huffman codes.
+.TP
+.B \-B
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using binary codes.  The binary code represents their occurrence
+position in the auxiliary dictionary.
+.TP
+.B \-D
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using delta codes.  The delta code represents their occurrence position
+in the auxiliary dictionary.
+.TP
+.B \-Y
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This generally
+produces better compression than
+.B \-B
+or
+.BR \-D .
+.TP
+.B \-M
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This method is
+adaptive within documents, and generally produces better compression
+than
+.BR \-B ,
+.B \-D
+or
+.BR \-Y .
+.TP
+.BI \-l " lookback"
+The generated dictionary is designed to be front coded when it is
+loaded into memory.  Under normal circumstances, a front-coded
+dictionary would require scanning from the beginning in order to find
+any particular word.  However, every
+.I lookback
+words in the dictionary, the whole word is stored and a pointer to that
+word maintained.  E.g., if
+.I lookback
+is 4, then every fourth word is stored in its entirety.
+.TP
+.BI \-k " mem"
+This limits the amount of memory to use for the generated
+dictionary.  Words are selected for the dictionary based of the text
+statistics, and whether
+.BR \-0 , " \-1" , " \-2"
+or
+.B \-3
+is specified.  The memory is calculated assuming a lookback of 0,
+irrespective of what actual lookback is specified.  This means that if
+a non-zero lookback is given, the dictionary will actually occupy
+less space than specified by
+.BR \-k .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.stats
+Statistics about the source text.
+.TP
+.B *.text.dict
+Compression dictionary for the source text.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_decompress_text.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_decompress_text.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_decompress_text.1	(revision 10506)
@@ -0,0 +1,78 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_decompress_text 1 \*(Dt CITRI
+.SH NAME
+mg_decompress_text \- decompresses the compressed text of a collection
+.SH SYNOPSIS
+.B mg_decompress_text
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_decompress_text
+decompresses the compressed text of a collection, inserts paragraph and
+document markers, writing the output to
+.IR stdout ".  "
+This program was created
+to be used as a type of
+.BR mg_get (1).
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.text
+Compressed documents.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.invf.paragraph
+Paragraph counts for documents.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_passes (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_fast_comp_dict.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_fast_comp_dict.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_fast_comp_dict.1	(revision 10506)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_fast_comp_dict 1 \*(Dt CITRI
+.SH NAME
+mg_fast_comp_dict \- build a fast loading compression dictionary
+.SH SYNOPSIS
+.B mg_fast_comp_dict
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_fast_comp_dict
+builds a fast-loading compression dictionary from the standard
+compression dictionary.  The new dictionary has the property that
+.BR mgquery (1)
+can load it in very quickly, making the startup time for
+.BR mgquery (1)
+much shorter.  The new dictionary is larger on disk than the original,
+but they are no different when it comes to memory usage.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.dict
+Compression dictionary.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_get.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_get.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_get.1	(revision 10506)
@@ -0,0 +1,154 @@
+.TH mg_get 1 "31 January 1994"
+.SH NAME
+mg_get \- output source texts for processing
+.SH SYNOPSIS
+ 
+.B mg_get
+.I collection-name
+.RB [ \-init | \-i | \-text\fP|\fB\-t\fP|\fB\-cleanup\fP|\fB\-c\fP]
+.SH DESCRIPTION
+.LP
+This program is the default one used by mgbuild to generate the source text for the MG system. Any program may be used to generate the source text for mgbuild as long as it confirms to the interface specified here. 
+.SH OPTIONS
+.LP
+The
+.I collection\-name
+must appear before any other option. Only the first option has any significance. If no option is specified
+.B \-text
+is assumed.
+.RS
+.TP
+.BR \-init " and " \-i
+The program is called once with this flag at the start of building a collection.
+.TP
+.BR \-text " and " \-t
+The program is called with this flag multiple times during the building of a collection. The program outputs (on stdout) the text of the collection. \*(lq\fBDocuments\fP\*(rq within the collection are separated with by ctrl-B's (ASCII code 2). \*(lq\fBParagraphs\fP\*(rq within the collection are separated with ctrl-C's (ASCII code 3). A collection need not contain paragraphs unless a level 3 inverted file is being generated (see 
+.B mgbuild 
+and 
+.BR mg_passes ). 
+.TP
+.BR \-cleanup " and " \-c
+The program is called once with this flag at the completion of building a collection.
+.SH ENVIRONMENT
+.TP
+.SB MGDATA
+If this environment variable exists then its value is used a the default 
+directory where the mg collection files are. If this variable does not exist
+then the directory \*(lq\fB.\fP\*(rq is used by default. The command line 
+option 
+.BI \-d " directory"
+overrides the directory in 
+.BR MGDATA .
+.TP
+.SB MG_GETRC
+This environment variable specifies where the file containing the users 
+mg source configurations is. If not set, mg_get uses a default of 
+.B \*\~/.mg_getrc.
+
+This file contains TAB delimited lines of the form
+.RS 
+.RS 
+.I CollectionName
+.I CollectionType
+.I files or directory
+.RE
+
+.I CollectionName
+is the name of the collection supplied to mg_get.
+
+.I CollectionType
+specifies how mg_get should process the
+named files and directories and are descibed below.
+
+.I files or directory
+is either a list of files separted by blanks or a single directory.
+Some of the
+.I CollectionTypes
+deal with files and others with just a single directory.
+Any files used ending with .gz or .Z are decompressed with gzip before
+processing. References to '~' expands to the users HOME directory.
+
+.I CollectionType
+is one of
+.RS
+.TP
+.BR PARA
+For text based documents. The list of files specified are treated as
+a series of paragraphs separated by blank lines. Each paragraph becomes
+a seperate document on the indexed collection.
+.TP
+.BR MAIL
+for mail files. The list of files specified are treated as UNIX mail
+files separated by lines starting with 'From'. Each mail message becomes
+a seperate document on the indexed collection. As a extra feature any
+embedded tarmail encoded contents (enclosed by a 'xbtoa Begin' and 'xbtoa End'
+pair are removed.
+.TP
+.BR DIR
+(and DIR2)
+For a single directory of files. Each file in the directory (and in any of
+it's subdirectories) are treated as a single document. With
+.I DIR
+the pathname of the file is prefixed to the contents of each file as an
+extra line while this is not done for
+.I DIR2
+collections.
+.TP
+.BR BIB
+for biblography files. The list of files specified are treated as
+a series of biblography files (eg BIBTEX or TROFF) separated by lines
+starting with '@'. Each reference  becomes a seperate document on the indexed
+collection.
+.TP
+.BR TXTIMG
+for integrated collections of text and images. The single directory should
+contain files that have the same prefix if they are related. For example,
+monaLisa.pgm might be a gray-level image, and monaLisa.txt would be a textual
+file describing the image. The suffixes recognised are:
+.BR   .txt
+for  ascii text
+.BR  .ptm
+for  scanned text stored as a bilevel image
+.BR  .pbm
+for a black and white image (typically a line drawing)
+.BR  .pgm
+for a gray-scale image
+.BR In addition, if no corresponding ascii text file is found for
+a .pbm or .pgm file, then one is created with suffix .tmp.txt,
+and it stores the name of the image file (in principle it could
+store the OCR of a .txt.pbm file). At present the .tmp.txt files
+are deleted by the '-cleanup' option.
+
+.SH "EXAMPLE"
+
+An example ~/.mg_getrc file might look like:
+   alice   PARA    /users/alice13a.txt.Z
+   mail95  MAIL    ~/MAIL/1995/*
+   doc     DIR     ~/documents
+   bibs    BIB     ~/etc/REFS/*.bib ~/etc/REFS/CC/*.bib
+   letters DIR     ~/LETTERS
+   davinci TXTIMG  ~/images/davinci
+
+.SH "SEE ALSO"
+.LP
+.BR mg_compression_dict (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_make_fast_dict (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1)
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_get_merge.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_get_merge.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_get_merge.1	(revision 10506)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_get_merge 1 \*(Dt CITRI
+.SH NAME
+mg_get_merge \- output source texts for processing
+.SH SYNOPSIS
+.B mg_get_merge
+.I collection-name
+.if n .ti +9n
+[
+.BR \-init " |"
+.BR \-i " |"
+.BR \-text " |"
+.BR \-t " |"
+.BR \-cleanup " |"
+.B  \-c
+]
+.SH DESCRIPTION
+This program is the default one used by
+.BR mgmerge (1)
+to generate the source text for new documents to appended to
+an
+.BR mg (1)
+system database.
+Its function is exactly the same as
+.BR mg_get (1)
+except that it generates the 
+.I new 
+documents to be added to an
+.BR mg (1)
+system database that has already been built using
+.BR mgbuild(1).
+Any program may be used to generate the source
+text for
+.BR mgmerge (1),
+as long as it confirms to the interface specified
+here.
+.SH OPTIONS
+The
+.I collection-name
+must appear before any other option.  Only the first option has any
+significance.  If no option is specified,
+.B \-text
+is assumed.
+.TP "\w'\fB\-cleanup\fP and \fB\-c\fP'u+2n"
+.BR \-init " and " \-i
+The program is called once with this flag at the start of merging a
+collection.
+.TP
+.BR \-text " and " \-t
+The program is called with this flag multiple times during the
+merging of a collection.  The program outputs (on
+.IR stdout )
+the text of the collection.
+.I Documents
+within the collection are separated by ctrl-B's (ASCII code 2).
+.TP
+.BR \-cleanup " and " \-c
+The program is called once with this flag at the completion of
+merging a collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_get (1),
+.BR mgbuild (1),
+.BR mgmerge (1),
+.BR mg_text_merge (1),
+.BR mg_invf_merge (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_hilite_words.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_hilite_words.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_hilite_words.1	(revision 10506)
@@ -0,0 +1,95 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_hilite_words 1 \*(Dt CITRI
+.SH NAME
+mg_hilite_words \- display text and highlight particular words which it contains
+.SH SYNOPSIS
+.B mg_hilite_words
+.if n .ti +9n
+[
+.B --stem_method [0-3]
+]
+.if n .ti +9n
+[
+.B --stemmer [english|lovin|french|simplefrench]
+]
+.if n .ti +9n
+[
+.B --style [bold|underline|italic|emphasis|strong]
+]
+.if n .ti +9n
+[
+.B --pager [less|more|html|???]
+]
+.if n .ti +9n
+.I list-of-words-to-highlight
+
+.SH DESCRIPTION
+.B mg_hilite_words
+reads text from stdin and outputs it into a pager such as
+less. It's command arguments include a list of stemmed words
+which if extracted from the text will be highlighted on the output
+using a highlighting style.
+
+It has been extended to output the highlighted text using html
+straight to stdout.
+
+.SH OPTIONS
+Options may appear in any order, but the
+.IR list-of-words-to-highlight ,
+must be last.
+.TP
+.B --stem_method [0-3]
+This option allows one to set the stemming method for the extraction of
+the words from the incoming text.
+This should match the way the inverted file index was created.
+The default is 3, which is fold and stem.
+.TP
+.B --stemmer [english|lovin|french|simplefrench]
+This option allows you to select the stemmer to use.  The
+default is the English stemmer.
+.TP
+.B --style [bold|underline|italic|emphasis|strong]
+This option sets the highlighting style.
+.IR Bold 
+and 
+.IR underline
+are utilised by the pager or for html output.
+.IR Italic,
+.IR emphasis,
+and
+.IR strong
+can only be used for html output.
+.TP
+.B --pager [less|more|html|???]
+One can use the standard 
+.IR less
+or
+.IR more
+pages for displaying the highlighted text.
+Or one can generate highlighted html using the paging setting of
+.IR html.
+One can also specify a custom pager of their own choosing (i.e. ???).
+.TP
+.B list-of-words-to-highlight
+Each word is taken as a command line argument.
+Each word should already be stemmed and folded according to
+the stem option.
+.SH USAGE
+This program was written primarily to be called by 
+.IR mgquery(1)
+.
+When the user selects the mode of "hilite" then this program
+is called for displaying the query-result documents instead of
+just the pager.
+.SH "SEE ALSO"
+.na
+.BR mgquery (1).
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_dict.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_dict.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_dict.1	(revision 10506)
@@ -0,0 +1,104 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_dict 1 \*(Dt CITRI
+.SH NAME
+mg_invf_dict \- build an `on-disk' stemmed dictionary
+.SH SYNOPSIS
+.B mg_invf_dict
+[
+.B \-h
+]
+[
+.B \-F
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_invf_dict
+builds an `on-disk' stemmed dictionary from the
+compressed stemmed dictionary that the
+.BR mgquery (1)
+program can access.  Each entry in the dictionary contains the disk
+pointer to the associated inverted file entry, and various other pieces
+of information about the stemmed word.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " num"
+The dictionary is stored in blocks on disk; this option is used to set
+the block size.  The default is 4-KB blocks.
+.TP
+.B \-F
+This option causes the disk blocks to be aligned on the appropriate
+boundaries.  For example, if 4-KB blocks are used, they will be aligned
+in the file on 4-KB boundaries.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_dump.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_dump.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_dump.1	(revision 10506)
@@ -0,0 +1,142 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_dump 1 \*(Dt CITRI
+.SH NAME
+mg_invf_dump \- Dump out an inverted file in ASCII
+.SH SYNOPSIS
+.B mg_invf_dump
+[
+.B \-h
+]
+[
+.B \-b
+]
+[
+.B \-w
+]
+[
+.B \-t
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program dumps out an inverted file produced by the
+.BR mg (1)
+system as ASCII numbers.  This program could be used in conjunction
+with
+.BR mgdictlist (1)
+to write simple shell programs that work with the inverted files.  The
+output from the program looks something like this:
+.LP
+.RS
+.ft 3
+.nf
+6 337
+1
+ 1 1
+1
+ 5 1
+1
+ 2 1
+1
+ 1 1
+4
+ 1 3
+ 2 7
+ 3 2
+ 5 2
+1
+ 1 1
+ . . .
+.fi
+.ft
+.RE
+The first number (6) is the number of documents in the collection.  It
+is followed by the number of different terms in the collection.  For
+each term, the number of different documents it occurs in follows. The
+document numbers that the term occurs in are listed next.  If
+.B \-w
+is specified, then the number of times the term occurred in the
+document is printed alongside the document number.
+If
+.B \-t
+is specified, the term itself is also displayed in quotes.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-b
+This option will cause the output from the program to be in fixed-size
+binary numbers, rather than in ASCII.
+.TP
+.B \-w
+If the inverted file is a level-2 or level-3 inverted file, this causes
+the word counts per document to be output.
+.TP
+.B \-t
+This option causes each term to be displayed along with the number of
+documents it appears in. The term is printed in quotes,
+as in "the".
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf.dict
+The compressed stemmed dictionary.
+.TP
+.B *.invf.ORG
+The original inverted file saved by
+.BR mg_invf_rebuild .
+.TP
+.B *.invf
+The inverted file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_merge.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_merge.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_merge.1	(revision 10506)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_merge 1 \*(Dt CITRI
+.SH NAME
+mg_invf_merge \- Merge two inverted files and stemmed dictionaries
+.SH SYNOPSIS
+.B mg_invf_merge
+[
+.B \-h
+]
+[
+.B \-s
+]
+[
+.B \-w
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program takes two
+.BR mg (1)
+database compressed text files and appends the second to
+the first.
+It is part of the
+.BR mgmerge (1)
+addition to the
+.BR mg (1)
+package.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-s
+This option will cause a slow merge to be performed on the inverted files,
+where each inverted file entry is decoded and recoded.
+The default is a fast merge. Accumulated fast merges slowly degrade
+compression performance on the resulting inverted file so
+a periodic slow merge is recommended.
+.TP
+.B \-w
+By default the database .weights file is updated with
+new weights for the new documents in
+.B mg_text_merge.
+The
+.B -w
+option turns this step off.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.old.invf.dict
+The old compressed stemmed dictionary.
+.TP
+.B *.new.invf.dict
+The new compressed stemmed dictionary.
+.TP
+.B *.invf.dict
+The resulting merged compressed stemmed dictionary.
+.TP
+.B *.old.invf.ORG
+The original inverted file saved by
+.BR mg_invf_rebuild .
+.TP
+.B *.old.invf
+The old inverted file.
+.TP
+.B *.new.invf
+The new inverted file.
+.TP
+.B *.invf
+The resulting merged inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgmerge (1),
+.BR mg_get_merge (1),
+.BR mg_text_merge (1),
+.BR mg_invf_rebuild (1),
+.BR mg_invf_dict (1),
+.BR mg_weights_build (1),
+.BR mgquery (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_rebuild.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_rebuild.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_invf_rebuild.1	(revision 10506)
@@ -0,0 +1,156 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_rebuild 1 \*(Dt CITRI
+.SH NAME
+mg_invf_rebuild \- Rebuild an mg inverted file with or without skips.
+.SH SYNOPSIS
+.B mg_invf_rebuild
+.RB [ \-h ]
+.if n .ti +9n
+[
+.BR \-0 " |"
+.B \-1
+[
+.BI \-k " num"
+] |
+.B \-2
+[
+.BI \-s " num"
+]
+[
+.BI \-m " num"
+]
+]
+.if n .ti +9n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_invf_rebuild
+builds a new inverted file, with or without skipping, from an old
+inverted file.  This file uses
+.I *.invf.ORG
+and
+.I *.invf.idx.ORG
+as the
+source from which it builds
+.I *.invf
+and
+.IR *.invf.idx .
+If
+.I *.invf.ORG
+or
+.I *.invf.idx.ORG
+do not exist, the program renames
+.I *.invf
+or
+.I *.invf.idx
+to
+.I *.invf.ORG
+or
+.I *.invf.idx.ORG
+as appropriate.  The old inverted file may contain skipping.  This
+means that it is possible to delete the
+.I *.ORG
+files
+after the new inverted file is built.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-m\fP \fInum\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-0
+This generates a non-skipped inverted file.  This option is normally
+only needed if the
+.I *.ORG
+files have been deleted.
+.TP
+.B \-1
+This generates a skipped inverted file.  The
+.BI \-k " num"
+argument specifies the number of pointers hopped over with each skip.
+.TP
+.B \-2
+This option generates a skipped inverted file.  The skipped inverted
+file is built so that it is `optimal' for ranking using a specific
+number of accumulators.  Each term in the inverted file has a
+different skip length.  The arguments
+.BR \-s " and " \-m
+control the sizes of the skips.
+.TP
+.BI \-k " num"
+This specifies the number of pointers that should be hopped over with
+each skip.  This option is only valid if
+.B \-1
+is specified.
+.TP
+.BI \-m " num"
+This specifies the intended number of accumulators that will be used
+when ranking queries are done on the collection.
+.TP
+.BI \-s " num"
+This specifies the minimum size for skips.  If the calculation of the
+optimal skip size results in a number smaller than
+.IR num ,
+the skip size is set to
+.IR num .
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.ORG
+Original inverted file.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.invf.idx.ORG
+The original index into the inverted file.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_passes.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_passes.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_passes.1	(revision 10506)
@@ -0,0 +1,441 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_passes 1 \*(Dt CITRI
+.SH NAME
+mg_passes \- builds mg databases
+.SH SYNOPSIS
+.B mg_passes
+[
+.B \-h
+]
+[
+.B \-G
+]
+[
+.B \-S
+]
+[
+.B \-D
+]
+[
+.B \-W
+]
+.if n .ti +9n
+[
+.BR \-1 " |"
+.BR \-2 " |"
+.B  \-3
+]
+[
+.BI \-C " compstatpoint"
+]
+.if n .ti +9n
+[
+.BI \-n " tracename"
+]
+.if t .ti +.5i
+[
+.BI \-b " bufsize"
+]
+[
+.BI \-m " memlimit"
+]
+.if n .ti +9n
+[
+.BI \-c " numchunks"
+]
+[
+.BI \-a " stemmer"
+]
+[
+.BI \-s " stemmethod"
+]
+[
+.BI \-t " tracepos"
+]
+.if n .ti +9n
+[
+.B \-T1
+]
+[
+.B \-T2
+]
+.if t .ti +.5i
+[
+.B \-I1
+]
+[
+.B \-I2
+]
+.if n .ti +9n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+[
+.I filename(s)
+]
+.SH DESCRIPTION
+.B mg_passes
+is the program that does most of the work when building
+.BR mg (1)
+database systems.  The input documents can come from either
+.I stdin
+or from a list of files on the command line.  Individual documents
+must be separated with control-B characters.  In general,
+.B mg_passes
+must be run twice to build a database, first with the
+.B \-T1
+and
+.B \-I1
+options, and second with the
+.B \-T2
+and
+.B \-I2
+options.  Several other programs must be run in order to get an
+.BR mg (1)
+database that is ready for the
+.BR mgquery (1)
+program.  The
+.SB EXAMPLE
+section below gives an example of how to build a complete
+.BR mg (1)
+database.
+.SH OPTIONS
+Options may appear in any order, but the
+.IR filename(s) ,
+if specified, must be last.
+.TP "\w'\fB\-C\fP \fIcompstatpoint\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-G
+Treat SGML tags as non-words when building the inverted file.  An SGML
+tag is anything between angle brackets, i.e., `<' and `>'.
+.TP
+.B \-S
+This option causes a special pass to be executed.  It is up to a user
+to modify
+.I mg.special.c
+in the source code to do something with the documents it is given.
+.TP
+.B \-D
+If
+.B mg_passes
+fails, then print the document that caused the failure to the trace
+file if tracing is active, or to
+.I stderr
+if it is not.
+.TP
+.B \-W
+This option enables the generation of the weights file when
+.B \-I2
+is specified.  It causes
+.B \-I2
+to use a little more memory and CPU.
+.TP
+.B \-1
+Produce a level-1 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+A level-1 inverted file makes it possible for
+.BR mgquery (1)
+to do Boolean queries.  Ranked queries can still be done,
+although the quality of the ranking is abysmal.
+.TP
+.B \-2
+Produce a level-2 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+This is the default when neither
+.BR \-1 ", " "\-2 " "or " \-3
+is specified.
+A level-2 inverted file makes it possible for
+.BR mgquery (1)
+to do Boolean queries and cosine-ranked queries.
+.TP
+.B \-3
+Produce a level-3 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+This has been implemented to enable paragraph-level inversion.
+Paragraphs are delimited by control-C characters in the source text.
+.TP
+.BI \-C " compstatpoint"
+This option causes statistics on the compression performance to be
+output to a file called
+.IR *.compression.stats .
+.I compstatpoint
+specifies the interval between outputting each line of statistics.  The
+units of
+.I compstatpoint
+are kilobytes of source text.  E.g., if
+.I compstatpoint
+is 10, then a line is output to the file every 10 KB of input
+source.  Each line of the file consists of 4 numbers The first number
+is the amount of input text, in bytes, processed so far.  The second
+number is the amount of input text, in bytes, processed since the
+last line was output to the file.  The third number is the number of
+output bytes generated since the last line was output to the file, and
+the fourth number is the compression achieved since the last line was
+output, i.e., the third number divided by the second number.
+.TP
+.BI \-n " tracename"
+This specifies the filename to use for the trace log, if tracing is
+enabled using the
+.B \-t
+option.  If
+.BI \-n " tracename"
+is not given and tracing is enabled, a default trace filename will be
+used.
+.TP
+.BI \-s " stemmethod"
+This specifies the method to use to \*(lqstem\*(rq the words in the
+inverted file dictionary.  This is a bit mask specifying the
+operations to do on words as they are parsed out of the text, where
+bit number 0 is the low-order (rightmost) bit.  Bit 0 does case
+folding, and bit 1 does simple stemming, so the value 3 for
+.I stemmethod
+does both case folding and stemming.
+.TP
+.BI \-a " stemmer"
+This specifies the stemmer to use when stemming words.  This
+is a description of the language the stemmer is intended for
+or a description of the stemmer.  Valid options include:
+english, lovin, french, and simplefrench.
+.TP
+.BI \-b " bufsize"
+Specify the size of the document buffer in kilobytes.  If any document
+is larger than
+.IR bufsize ,
+the program will abort with an error message.  This should probably be
+replaced with some system which automatically increases the buffer
+size as required.  The default size is 3072 KB (3 MB).
+.TP
+.BI \-m " memlimit"
+Maximum amount of memory to use for the pass-2 file inversion in
+megabytes.  This option is only useful when used in conjunction with
+the option
+.BR \-I1 .
+The larger this value, the faster the pass-2 inversion will proceed.
+The default value is 5 MB.
+.TP
+.BI \-c " numchunks"
+The maximum number of inversion chunks to write to disk.  Each chunk
+will be approximately as large as
+.IR memlimit .
+This option is only useful when used in conjunction with the option
+.BR \-I2 .
+The larger this value, the faster the pass-2 inversion will proceed.
+The default value is 5 MB.
+.TP
+.BI \-t " tracepos"
+This option activates tracing.  A line will be generated in the
+trace file for every
+.I tracepos
+input bytes processed.  The default name for the trace file can be
+overridden using the
+.BI \-n " tracename"
+option.
+.TP
+.B \-T1
+Generate the
+.I *.text.stats
+file.
+.TP
+.B \-T2
+Generate the
+.IR *.text ,
+.IR *.text.idx ,
+and possibly the
+.I *.text.dict.aux
+files.  Using this option requires that the
+.I *.text.dict
+file be present.
+.TP
+.B \-I1
+Generate the
+.IR *.invf.dict ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files.
+.TP
+.B \-I2
+Generate the
+.I *.invf
+and
+.I *.invf.idx
+files.  Using this option requires
+that the
+.IR *.invf.dict.hash ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files
+be present.  The
+.I *.invf.dict.hash
+file is generated by
+.BR mg_perf_hash_build (1)
+from the
+.I *.invf.dict.build
+file.  If the
+.B \-W
+option is specified, the
+.I *.weight
+file will also be generated.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is to be
+written.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection that will be
+created.
+.TP
+.I filename(s)
+This specifies the source text. If this is not specified, then the
+program expects the source text from
+.IR stdin .
+.SH EXAMPLE
+What follows is a UNIX
+.BR csh (1)
+script as an example of how to build an
+.BR mg (1)
+document collection.
+.LP
+.nf
+.DT
+.ft B
+.I #! /bin/csh
+.I
+# The first argument on the command line specifies the
+.I
+#   source of the text
+set source = ($1)
+.PP
+.I
+# The second argument is the name of the collection
+set text = ($2)
+.PP
+.I
+# Create *.text.stats,  *.invf.dict.build,
+.I
+#   *.invf.chunk and *.invf.chunks.trans
+${source} | mg_passes -T1 -I1 -m 1 -t 1 -f ${text}
+.PP
+.I
+# Create *.text.dict
+mg_compression_dict -f ${text}
+.PP
+.I
+# Create *.invf.dict.hash
+mg_perf_hash_build -f ${text}
+.PP
+.I
+# Create *.text,  *.text.idx,
+.I
+#   *.invf and *.invf.idx
+${source} | mg_passes -T2 -I2 -c 2 -t 1 -f ${text}
+.PP
+.I
+# Create *.text.idx.wgt and *.weight.approx
+mg_weights_build -f ${text} -b 8
+.PP
+.I
+# Create *.invf.dict
+mg_invf_dict -f ${text} -b 4096
+.PP
+.I
+# Create *.text.dict
+mg_fast_comp_dict -f ${text}
+.ft R
+.fi
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.chunk
+Inverted file chunk descriptor file.  When the inverted file is
+created it is created in chunks that use no more than a set amount of
+memory.  This file describes those chunks.
+.TP
+.B *.invf.chunk.trans
+Word-occurrence-order to lexical-order translation file.  The
+.B *.invf.chunk
+file is written in word-occurrence order but is required by
+.B \-I2
+to be in lexical order.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for an order-preserving perfect hash function.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.trace
+The default trace file.
+.TP
+.B *.compression.stats
+Statistics about the compression of the text.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_perf_hash_build.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_perf_hash_build.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_perf_hash_build.1	(revision 10506)
@@ -0,0 +1,89 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_perf_hash_build 1 \*(Dt CITRI
+.SH NAME
+mg_perf_hash_build \- generate an order-preserving hash function for the stemmed dictionary
+.SH SYNOPSIS
+.B mg_perf_hash_build
+[
+.B \-h
+]
+[
+.BI \-r " rndseed"
+]
+[
+.BI \-d  " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_perf_hash_build
+generates an order-preserving hashing function from the compressed
+stemmed dictionary and writes it out to disk.
+.BR mg_passes (1)
+will make use of the hash function when it builds the inverted file.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-r " rndseed"
+This specifies the random seed to be used in the generation of the
+hash function; it must be an integer.  If this is not specified, the
+current time will be used as the random seed.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf.dict
+Stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for a order-preserving perfect hash function.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_stem_idx.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_stem_idx.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_stem_idx.1	(revision 10506)
@@ -0,0 +1,95 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_stem_idx 1 \*(Dt CITRI
+.SH NAME
+mg_stem_idx \- builds a stem index file
+.SH SYNOPSIS
+.B mg_stem_idx
+[
+.B \-h
+]
+[
+.B \-F
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.B \-s 1|2|3
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_stem_idx
+generates a stem index file for a collection that is to be built with
+stem indexes.  This program should be called three times: once for each
+.B -s
+parameter.  It uses the stemmed dictionary to create the stem index which
+contains pointers into the stemmed dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " num"
+The dictionary is stored in blocks on disk; this option is used to set
+the block size.  The default is 4-KB blocks.
+.TP
+.B \-F
+This option causes the disk blocks to be aligned on the appropriate
+boundaries.  For example, if 4-KB blocks are used, they will be aligned
+in the file on 4-KB boundaries.
+.TP
+.B -s 1|2|3
+The stem method to apply for the stem index.
+.br
+1 = casefolded and non-stemmed
+.br
+2 = non-casefolded and stemmed
+.br
+3 = casefolded and stemmed
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.invf.dict.blocked
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked.1
+Stem index with stem index method 1.
+.TP
+.B *.invf.dict.blocked.2
+Stem index with stem index method 2.
+.TP
+.B *.invf.dict.blocked.3
+Stem index with stem index method 3.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_invf_dict (1),
+.BR mgstemidxlist (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_text_estimate.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_text_estimate.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_text_estimate.1	(revision 10506)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_text_estimate 1 \*(Dt CITRI
+.SH NAME
+mg_text_estimate \- Estimate the size of the compressed text based on the text statistics and a compression dictionary.
+.SH SYNOPSIS
+.B mg_text_estimate
+[
+.B \-h
+]
+[
+.BR \-H " |"
+.BR \-B " |"
+.BR \-D " |"
+.BR \-Y " |"
+.B \-M
+]
+.if n .ti +9n
+.I stats-dict
+.I compression-dict
+.SH DESCRIPTION
+This program estimates the size of the compressed text that would be
+generated if text with certain statistics were compressed with a
+particular dictionary.  This program has no real use in the
+.BR mg (1)
+system, except for experimenting with the
+.BR mg_compression_dict (1)
+program.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-m\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-H
+This specifies that novel words will be coded character by character
+using Huffman codes.
+.TP
+.B \-B
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using binary codes.  The binary code represents their occurrence
+position in the auxiliary dictionary.
+.TP
+.B \-D
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using delta codes.  The delta code represents their occurrence position
+in the auxiliary dictionary.
+.TP
+.B \-Y
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This generally
+produces better compression than
+.B \-B
+or
+.BR \-D .
+.TP
+.B \-M
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This method is
+adaptive within documents, and generally produces better compression
+than
+.BR \-B ,
+.B \-D
+or
+.BR \-Y .
+.SH FILES
+.TP 20
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_text_merge.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_text_merge.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_text_merge.1	(revision 10506)
@@ -0,0 +1,76 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_text_merge 1 \*(Dt CITRI
+.SH NAME
+mg_text_merge \- Append one compressed text file to another
+.SH SYNOPSIS
+.B mg_text_merge
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program takes two
+.BR mg (1)
+database inverted files and stemmed
+dictionaries, named "old" and "new" respectively, and creates
+a merged stemmed dictionary and inverted file.
+It is part of the
+.BR mgmerge (1)
+addition to the
+.BR mg (1)
+package.
+The two compressed text files are
+.IR "name" .old.text
+and
+.IR "name" .new.text.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.old.text
+The old compressed text.
+.TP
+.B *.new.text
+The new compressed text that will be appended
+.TP
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgmerge (1),
+.BR mg_get_merge (1),
+.BR mg_invf_merge (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mgquery (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_weights_build.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_weights_build.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mg_weights_build.1	(revision 10506)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_weights_build 1 \*(Dt CITRI
+.SH NAME
+mg_weights_build \- builds the approximate weights file
+.SH SYNOPSIS
+.B mg_weights_build
+[
+.B \-h
+]
+[
+.B \-s
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_weights_build
+is the program that generates the approximate weights file and the
+interleaved text index and exact weights file.  To do this, it uses
+the text index and either the exact weights file, or the inverted file
+and stemmed dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-s
+Save the weights generated from the
+.I *.invf
+and
+.I *.invf.dict
+file in a
+.I *.weight
+file.
+.TP
+.BI \-b " num"
+This specifies the number of bits of precision that should be used for
+the approximate weights.  If not specified, it defaults to 8.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgbilevel.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgbilevel.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgbilevel.1	(revision 10506)
@@ -0,0 +1,116 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbilevel 1 \*(Dt CITRI
+.SH NAME
+mgbilevel \- compresses a bilevel image using a specified template
+.SH SYNOPSIS
+.B mgbilevel
+.B \-e
+[
+.B \-t
+.I \*(lqstring\*(rq
+]
+.I infile
+[
+.I \>compressed-outfile
+]
+.nf
+or
+.fi
+.B mgbilevel
+.B \-d
+.I compressed-infile
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+.B mgbilevel
+performs (up to) a two-stage template-based compression.  The
+user can specify the template to be used in the compression process.  The
+default template size is a two-stage template 22/10.  The compressed file
+contains the template type in the stream.  The output files are written
+to
+.IR stdout .
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-t\fP \fI\*(lqstring\*(rq\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-e
+Compresses
+.I infile
+using a template specified, and writes to
+.IR compressed-outfile .
+.TP
+.B \-d
+Decompresses
+.I compressed-infile
+using the template contained in the compressed file.  Writes to
+.IR outfile .
+.TP
+\fB\-t \fP\fI\*(lqstring\*(rq\fP
+This option specifies which template combination is to
+be used in the compression.  Five different characters
+can occur in the string: `.' for a pixel not
+included in the template, `p' for a pixel included in the 1st
+level template, `2' for a pixel included in the 2nd level
+template (a subset of the 1st level), `*' denoting the position
+of the
+.I current
+pixel, and a `;' denoting the end of each template line.
+The default template is a two-level 22/10 template:
+.IP
+.RS
+.nf
+\&.ppppp.;
+pp222pp;
+p22222p;
+p22*.\|.\|.;
+.fi
+.RE
+.IP
+This would be specified on the command line as:
+.nf
+\&\fB\-T\fP ".ppppp.;pp222pp;p22222p;p22*.\|.\|.;"
+.fi
+.TP
+.I infile
+This is the input
+.I .pbm
+file to be compressed.
+.TP
+.I outfile
+This is the decompressed
+.I .pbm
+file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgbuild.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgbuild.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgbuild.1	(revision 10506)
@@ -0,0 +1,169 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbuild 1 \*(Dt CITRI
+.SH NAME
+mgbuild \- build an mg system database
+.SH SYNOPSIS
+.B mgbuild
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.BI \-d " mgdata dir"
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgbuild
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely build an
+.BR mg (1)
+system database ready for queries to be made
+by
+.BR mgquery.
+This program makes use of the
+.BR mg_get (1)
+script to obtain the text of the collection.
+.SH OPTIONS
+Options can occur in any order, but the collection name must be last.
+.TP "\w'\fIcollection-name\fP'u+2n"
+.BI \-c
+This specifies whether the
+.I get
+program is \*(lqcomplex\*(rq.  If a
+.I get
+program is \*(lqcomplex\*(rq, then it requires initialisation and
+cleanup with the
+.B \-i
+and
+.B \-c
+options.
+.TP
+.BI \-g " get"
+This specifies the program to use for getting the source text for the
+build.  If no
+.B \-g
+option is given, the default program
+.BR mg_get (1)
+is used.
+.TP
+.BI \-s " source"
+The
+.B mgbuild
+program consists of two parts.  The first part initializes variables
+to default values.  The second part uses these variables to control
+how the
+.BR mg (1)
+database is built.  This option specifies a program to execute between
+the first and second parts.  The details of what the variables are, and
+how they may be changed, are in comments in the
+.B mgbuild
+program.
+.TP
+.BI \-d " mgdata dir"
+Setting this option allows one to override the MGDATA environment variable.
+.TP
+.I collection-name
+This is the collection name, as required by the
+.BR mg_get (1)
+program.  It serves both as a
+.I case
+statement selector, and as the name of a subdirectory that holds the
+indexing files.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.chunk
+Inverted file chunk descriptor file.  When the inverted file is
+created, it is written in chunks that use no more than a set amount of
+memory.  This file describes those chunks.
+.TP
+.B *.invf.chunk.trans
+Word-occurrence-order to lexical-order translation file.  The
+.B *.invf.chunk
+file is written in word-occurrence order but is required by
+.B \-N2
+to be in lexical order.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for an order-preserving perfect hash function.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Text statistics.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgbuild_4.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgbuild_4.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgbuild_4.1	(revision 10506)
@@ -0,0 +1,53 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbuild_4 1 \*(Dt CITRI
+.SH NAME
+mgbuild_4 \- build an mg system database using 4 passes instead of 2
+.SH SYNOPSIS
+.B mgbuild_4
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.BI \-d " mgdata dir"
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgbuild_4
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely build an
+.BR mg (1)
+system database ready for queries to be made
+by
+.BR mgquery.
+This program makes use of the
+.BR mg_get (1)
+script to obtain the text of the collection.
+In 
+.BR mgbuild (1)
+the build is done by two passes over the input text. The first
+pass creates the compressed text dictionary and inverted file dictionary,
+the second pass creates the compressed text and inverted file. What 
+.BR mgbuild_4
+does is use a separate pass for each function. This will be slower but will
+not require as much RAM at one time. Therefore, if your build is failing
+due to running short of memory, then 
+.BR mgbuild_4
+is worth a try.
+.SH "SEE ALSO"
+.na
+.BR mgbuild (1)
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgdictlist.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgdictlist.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgdictlist.1	(revision 10506)
@@ -0,0 +1,72 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgdictlist 1 \*(Dt CITRI
+.SH NAME
+mgdictlist \- list the contents of a dictionary
+.SH SYNOPSIS
+.B mgdictlist
+[
+.B \-q
+]
+.I filename
+.SH DESCRIPTION
+.B mgdictlist
+lists the contents of either a compressed compression dictionary, a
+text statistics file, or a compressed stemmed dictionary.  Unlike all
+the other programs in the
+.BR mg (1)
+suite, it is necessary to specify the complete pathname of the
+dictionary to list.
+.SH OPTIONS
+The
+.I filename
+must be last.
+.TP "\w'\fIfilename\fP'u+2n"
+.B \-q
+Generate an abbreviated output (machine-readable rather than
+human-readable).
+.TP
+.I filename
+This is the name of the dictionary to list.
+.B mgdictlist
+automatically detects whether the file is a compressed compression
+dictionary, text statistics file, or a compressed stemmed dictionary.
+.SH FILES
+.TP 20
+.B *.text.dict
+Text statistics file.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.invf.build
+Compressed stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgfelics.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgfelics.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgfelics.1	(revision 10506)
@@ -0,0 +1,103 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgfelics 1 \*(Dt CITRI
+.SH NAME
+mgfelics \- fast and efficient lossless image (de)compression
+.SH SYNOPSIS
+.B mgfelics
+.B \-e
+[
+.BI \-k " n"
+]
+.I infile
+[
+.I \>compressed-outfile
+]
+.br
+or
+.br
+.B mgfelics
+.B \-d
+.I compressed-infile
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+.B mgfelics
+is a lossless compression process which can (de)compress portable
+bitmap files in
+.I pgm
+format.
+.B mgfelics
+writes to
+.IR stdout .
+.SH OPTIONS
+.TP "\w'\fB\-k\fP \fIn\fP'u+2n"
+.BI \-k " n"
+An integer parameter (< 32) which controls the compression speed and
+ratio.  The value of
+.I n
+is included in the output stream, and therefore is not needed in the
+decompression stage.  The default value of
+.I n
+is equal to the number of bits required to represent each grey level.
+.TP
+.B \-e
+Encodes the file
+.IR infile ,
+sending the output to
+.IR stdout .
+.TP
+.B \-d
+Decodes the file from
+.IR compressed-infile ,
+sending the output to
+.IR stdout .
+.SH NOTE
+.B mgfelics
+uses a combination of adjusted binary and Rice codes, the choice of
+which for any given pixel depends on the environment as determined by
+the intensity values of neighbouring pixels.  The result is a very
+fast and lossless algorithm for compressing grayscale images.  The
+optional parameter
+.BI \-k " n"
+corresponds to the maximum exponent of the same name in Rice encoding.
+Smaller values of
+.BI \-k " n"
+can result in significant improvement in compression times with a
+corresponding loss in compression ratio.  However the reduction in
+compression ratio with a small
+.BI \-k " n"
+parameter may be insignificant for many images.
+.SH REFERENCES
+Algorithm by Paul G. Howard and Jeffrey Scott Vitter
+of Brown University, RI, and Duke University, NC, respectively.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgmerge.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgmerge.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgmerge.1	(revision 10506)
@@ -0,0 +1,175 @@
+`.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgmerge 1 \*(Dt CITRI
+.SH NAME
+mgmerge \- update an mg system database with new documents
+.SH SYNOPSIS
+.B mgmerge
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.B \-S
+]
+[
+.B \-w
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgmerge
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely merge a current
+.BR mg (1)
+system database ready with some new documents, saving the need for a complete
+database rebuild with
+.B mgbuild.
+It does this by building a second
+.BR mg (1)
+system database from the new documents and then merging this database
+with the old one.
+This program makes use of the
+.BR mg_get_merge (1)
+script to obtain the text of the collection.
+.B mgmerge
+cannot edit or delete documents already in a database; only new documents
+can be added.
+.SH OPTIONS
+Options can occur in any order, but the collection name must be last.
+.TP "\w'\fIcollection-name\fP'u+2n"
+.BI \-c
+This specifies whether the
+.I get
+program is \*(lqcomplex\*(rq.  If a
+.I get
+program is \*(lqcomplex\*(rq, then it requires initialisation and
+cleanup with the
+.B \-i
+and
+.B \-c
+options.
+.TP
+.BI \-g " get"
+This specifies the program to use for getting the source text for the
+build.  If no
+.B \-g
+option is given, the default program
+.BR mg_get_merge (1)
+is used.
+.TP
+.BI \-s " source"
+The
+.B mgmerge
+program consists of two parts.  The first part initializes variables
+to default values.  The second part uses these variables to control
+how the
+.BR mg (1)
+database is built.  This option specifies a program to execute between
+the first and second parts.  The details of what the variables are, and
+how they may be changed, are in comments in the
+.B mgmerge
+program.
+If this option is used, the program should ideally be the same one that
+was called by
+.BR mgbuild (1)
+to build the database since some parameters need to be consistent between
+.B mgbuild
+and
+.B mgmerge.
+.TP
+.B \-S
+This option will cause a slow merge to be performed on the inverted files,
+where each inverted file entry is decoded and recoded.
+The default is a fast merge. Accumulated fast merges slowly degrade
+compression performance on the resulting inverted file so
+a periodic slow merge is recommended.
+.TP
+.B \-w
+Adding new documents can have an effect on the weight of the previous ones.
+By default the weights for documents already in the collection are not 
+recomputed since the change in their values is usually small.
+This option forces new weights to be recomputed.
+Periodic use of this option, as for the "-S" option, is recomended,
+otherwise query rankings may become inaccurate.
+.TP
+.I collection-name
+This is the collection name, as required by the
+.BR mg_get_merge (1)
+program.  It serves both as a
+.I case
+statement selector, and as the name of a subdirectory that holds the
+indexing files.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+Note that a temporary directory under the
+.B MGDATA
+directory is used to perform the merge.
+The default name for this directory is
+.BR MERGE .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Text statistics.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgbuild (1),
+.BR mg_get_merge (1),
+.BR mg_get (1),
+.BR mg_invf_merge (1),
+.BR mg_text_merge (1),
+.BR mg_query (1),
+.BR mg_weights_build (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgquery.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgquery.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgquery.1	(revision 10506)
@@ -0,0 +1,693 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgquery 1 \*(Dt CITRI
+.SH NAME
+mgquery \- query program for the mg system
+.SH SYNOPSIS
+.B mgquery
+[
+.B \-h
+]
+[
+.B \-D
+]
+[
+.BI \-f " name"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+[
+.I collection-name
+]
+.SH DESCRIPTION
+.B mgquery
+enables users to make Boolean or ranked queries from a data base
+generated by the
+.BR mg (1)
+system.  It accepts queries from
+.I stdin
+and sends the retrieved documents to
+.IR stdout .
+Information on the resource usage of
+.B mgquery
+as it processes queries can be obtained interactively.
+.SH OPTIONS
+Options may appear in any order, but the
+.IR collection-name ,
+if specified, must be last.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-D
+This option causes the entire text to be decompressed and sent to
+.IR stdout .
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection that will be
+used.  If a collection with the specified base
+.I name
+does not exist, an error message will be displayed and
+.B mgquery
+will exit.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.SH USAGE
+Prior to processing the command line arguments, the
+.B mgquery
+program attempts to read in a startup script called
+.IR ./.mgrc .
+If that fails, it attempts to read in the file
+.IR $HOME/.mgrc .
+The startup file can only contain commands\(emno queries are
+permitted in the
+.I .mgrc
+file.  Lines starting with \*(lq\fB#\fP\*(rq in the file are comments.
+The most common use for the
+.I .mgrc
+file is to personalise the initial values of the predefined parameters
+with
+.B .set
+commands.
+.LP
+The input to
+.B mgquery
+consists of a series of input lines.  The backslash
+character
+.RB (\*(lq \e \*(rq)
+is used at the end of lines to indicate
+that input continues on the next line.
+.LP
+Input lines on which the first character is a dot
+.RB (\*(lq . \*(rq)
+are commands to the
+.B mgquery
+program.  Input lines that do not start with a dot are queries.
+.LP
+A query consists of two parts.  One part is a Boolean or ranked query
+that identifies documents.  The second part is a post-processing
+pattern matching operation.  Any text between the first speech mark
+(\*(lq) and the last speech mark (\*(rq) is considered to be a
+post-processing pattern.
+.SH COMMANDS
+The
+.B mgquery
+program can accept the following commands.
+.TP 17
+.B .help
+Display several pages of help text.
+.TP
+.B .quit
+Quit the program.
+.TP
+.B .warranty
+Display the
+.BR mg (1)
+warranty.
+.TP
+.B .conditions
+Display the conditions of use and distribution of
+.BR mg (1).
+.TP
+.BI ".set " "name value"
+Set the parameter
+.I name
+to the specified
+.IR value .
+If the parameter is a Boolean
+.I value
+and the
+.I value
+is omitted, the parameter will be inverted (i.e., if it was
+.IR true ,
+then it will change to
+.IR false ;
+if it was
+.IR false ,
+then it will change to
+.IR true ).
+.TP
+.BI ".unset " name
+Delete the parameter
+.I name
+from the currently-defined parameters.
+.TP
+.B .reset
+Reset the parameters to the state that they had after the processing
+of the
+.B mgquery
+command line.
+.TP
+.B .display
+Display the values of all the currently-defined parameters.
+.TP
+.B .push
+Push the currently-defined parameters onto a stack.
+.TP
+.B .pop
+Pops a set of parameters off the stack, replacing the currently-defined
+ones.
+.TP
+.BI ".output " arg
+This is used to specify where to send the text of the documents.  Once
+the
+.B .output
+command is specified, all subsequent output will be sent to the place
+specified by
+.IR arg .
+If
+.I arg
+is not specified subsequent output will be directed to
+.IR stdout .
+.I Arg
+may be any of the following.
+.RS
+.TP 13
+.BI "> " filename
+Send output to the specified file.
+.TP
+.BI ">> " filename
+Append output to the specified file.
+.TP
+.BI "| " command
+Pipe the output to
+.IR command ,
+which is executed by
+.IR sh .
+.RE
+.TP
+.BI ".input " arg
+This is used to specify where input (queries and commands) comes
+from.  Once the
+.B .input
+command is specified all subsequent input will be come from the place
+specified by
+.IR arg .
+If
+.I arg
+is not specified subsequent input will come from
+.IR stdin .
+.RS
+.TP 13
+.BI "< " filename
+Get input from the specified file.
+.TP
+.BI "| " command
+The input comes from the standard output of
+.IR command ,
+which is executed by
+.IR sh .
+.RE
+.SH PARAMETERS
+The following parameters are predefined and have special
+significance.  Each parameter will be followed by its default
+value.  Parameters are initialised before the
+.I .mgrc
+file is read or the command line arguments are processed.
+.TP 17
+.BI accumulator_method " `array'"
+This parameter is used during ranking, and specifies how the
+weight for each document should be accumulated.  The following
+methods are available:
+.IR array ,
+.IR splay_tree ,
+.IR hash_table ,
+and
+.IR list .
+.TP
+.BI briefstats " `off'"
+This is a Boolean parameter that determines whether the
+totals for disk, memory and time usage statistics will be
+displayed at the end of each query.
+.IR Note :
+this takes precedence over the parameters
+.BR diskstats ,
+.BR memstats " and " timestats .
+This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI buffer " `1048576'"
+When the documents are being read in, they are read into a
+buffer of this size and then displayed from this buffer.  If
+the documents are larger than this buffer, the buffer is
+expanded automatically.  Having a large buffer gives a very
+slight performance improvement, because it allows the order of
+disk operations to be optimised.  The buffer size is measured
+in bytes.
+.TP
+.BI diskstats " `off'"
+This is a Boolean parameter that determines whether the disk
+usage statistics for the preceding query will be displayed
+after each query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI doc_sepstr " `---------------------------------- %n\en\'"
+This specifies the string that will be used to separate
+documents when they are displayed for `Boolean' or `docnums'
+queries.  The standard C escape character sequences
+may be used to place special characters in the
+string.  For example, a newline would be `\en'.  To include a `%',
+use the sequence `%%'.  To include the
+.BR mg (1)
+document number, use the sequence `%n'.  The following escape character
+sequences are available
+.nf
+.ta 1.7iL
+.B Sequence	Meaning
+`\e\e'	backslash
+`\eb'	backspace
+`\ef'	formfeed
+`\en'	newline
+`\er'	carriage return
+`\et'	tab
+`\e"'	speech marks
+`\e''	quote mark
+`\ex\fIhh\fP'	ASCII code in hexadecimal
+`\ennn'	ASCII code in octal
+.fi
+.TP
+.BI expert " `false'"
+If this is
+.IR true ,
+then much of the dialogue output is suppressed.  This parameter may
+take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI hash_tbl_size " `1000'"
+One of the options during ranking queries is to use a hash
+table to accumulate the weights for each document.  The hash
+table is a simple chained type.  This parameter specifies the
+size of the hash table and may take any value between 8 and
+268435456 (2^28).
+.TP
+.BI heads_length " `50'"
+When the mode is
+.BR heads ,
+this specifies the number of characters that will be output for each
+document.
+.TP
+.BI maxdocs " `all'"
+The maximum number of documents to display in response to a
+query.  This parameter may take on a numeric value between 1
+and 429467295 (2^32 - 1) or the word
+.IR all .
+.TP
+.BI maxparas " `1000'"
+The maximum number of paragraphs to identify during a ranked
+query with paragraph indexing.  After the paragraphs have been
+identified, the paragraphs are converted into documents, and
+because some of the paragraphs may refer to the same documents
+the final number of answers may be less than
+.BR maxparas .
+The
+.B maxdocs
+parameter will then be applied.  This parameter may take on a numeric
+value between 1 and 429467295 (2^32 - 1).
+.TP
+.BI max_accumulators " `50000'"
+This parameter limits the number of different paragraph and
+document numbers to be accumulated during ranked queries when
+the parameter
+.B accumulator_method
+is set to
+.IR splay_tree ,
+.IR hash_table ,
+or
+.IR list .
+This parameter may take any value between 8 and 268435456 (2^28).
+.TP
+.BI max_terms " `all'"
+This parameter limits the number of terms that will actually
+be used during a ranked query.  If more terms than the number
+specified by
+.B max_terms
+are entered, then the extra terms will be discarded.  If
+.B sorted_terms
+is on, then the limiting will be done after the terms have been
+sorted.  This parameter may take any value between 1 and 429467295
+(2^32 - 1), or the word
+.IR all.
+.TP
+.BI memstats " `off'"
+This is a Boolean parameter that determines whether the memory
+usage statistics for the preceding query will be displayed
+after each query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI mgdir " `.'"
+This is set to the directory where the
+.BR mg (1)
+data files may be found.  If
+the environment variable
+.B MGDATA
+exists, then this is instead initialised to the value of
+.BR MGDATA .
+The value of this parameter may be changed, either in the
+.I .mgrc
+file with a
+.BI ".set mgdir "directory
+command, or from the command line using the
+.BI \-d " directory"
+option.  Once the \*(lq\fB>\fP\*(rq prompt appears, changing this
+parameter will have no effect.
+.TP
+.BI mgname " `bible'"
+This is set to the name of the
+.BR mg (1)
+collection that is to be used for the session.  The value of this
+parameter may be changed, either in the
+.I .mgrc
+file with a
+.BI ".set mgname "name
+command, or from the command line using the
+.BI \-f " name"
+option.  Once the \*(lq\fB>\fP\*(rq prompt appears, changing this
+parameter will have no effect.
+.TP
+.BI mode " `text'"
+This specifies how documents should be displayed when they
+are retrieved.  It may take six different values:
+.IR text ,
+.IR hilite ,
+.IR docnums ,
+.IR heads ,
+.IR silent ,
+or
+.IR count .
+.I text
+displays the contents of the document.
+.I hilite
+displays the contents of the document and highlights any of the 
+stemmed query terms.
+.I docnums
+displays only the document numbers.
+.I heads
+is used to print out the head of each document.
+.I silent
+retrieves all the documents but displays nothing except how many
+documents were retrieved.  This mode is intended to be used in timing
+experiments.
+.I count
+does the minimum
+amount of work required to determine how many documents would
+be retrieved, but does not retrieve them.
+.TP
+.BI optimise_type " `1'"
+There are three types of boolean query optimisation (parse tree
+rearrangement). Type 0 leaves parse tree unaltered. Type 1 optimises
+for AND of terms and AND of OR of terms. Type 2 converts the tree
+into DNF (an experiment :-).
+.TP
+.BI pager " `more'"
+This is the name of the program that will be used to display
+the help and the retrieved documents.  If the environment
+variable
+.B PAGER
+is defined, then
+.B pager
+takes on that value.
+.TP
+.BI hilite_style " `bold'"
+This specifies the type of highlighting method.
+It may take one of two different values:
+.IR bold,
+or
+.IR underline.
+.TP
+.BI para_sepstr " `\en######## PARAGRAPH %n ########\en'"
+This specifies the string that will be used to separate paragraphs.
+The standard C escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written
+as `\en'.  To include a `%', use the sequence `%%'.  To include the
+paragraph number within the document, use the sequence `%n'.
+.TP
+.BI para_start " `***** Weight = %w *****\en'"
+This specifies the string that will be used at the head of paragraphs
+for a paragraph-level index following a ranked query.  The standard
+C-language escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written as
+`\en'.  To include a `%', use the sequence `%%'.  To include the
+paragraph weight, use the sequence `%w'.
+.TP
+.BI qfreq " `true'"
+This determine whether the ranked queries will take into account the
+number of times each query term is specified.  When this is
+.IR true ,
+the number of times a term appears in the query is used in the
+ranking.  When this is
+.IR false ,
+all query terms are assumed to occur only once.  This parameter may
+take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI query  " `Boolean'"
+This specifies the type of queries that are to be specified.
+It can take four different values:
+.IR Boolean ,
+.IR ranked ,
+.IR docnums " or " approx-ranked.
+.I Boolean
+is for Boolean queries.
+The
+.BR yacc (1)
+grammar for Boolean queries is as follows.
+.IP
+.nf
+        query   : or;
+.IP
+        or      : or '|' and
+                | and ;
+.IP
+        and     : and '&' not
+                | and not
+                | not ;
+.IP
+        not     : term
+                | '!' not ;
+.IP
+        term    : TERM
+                | '(' or ')' ;
+.fi
+.IP
+.IR ranked " and " approx-ranked
+are for queries ranked by the cosine measure.
+.I approx-ranked
+uses only the low-precision document lengths, and therefore only
+produces an approximation to full cosine ranking.
+.IP
+.nf
+        query   : TERM
+                | query TERM ;
+.fi
+.IP
+.I docnums
+allows the entry of document numbers.  Multiple numbers separated by
+spaces may be specified, or ranges separated by hyphens.
+.IP
+.nf
+        query   : range
+                | query range ;
+.IP
+        range   : num
+                | num '-' num ;
+.fi
+.TP
+.BI ranked_doc_sepstr " `-------------------------------- %n %w\en'"
+This specifies the string that will be used to separate documents when
+they are displayed for `ranked' or `approx-ranked' queries.  The
+standard C escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written as
+`\en'.  To include a `%', use the sequence `%%'.  To include the
+.BR mg (1)
+document number, use the sequence `%n'.  To include the document
+weight, use the sequence `%w'.
+.TP
+.BI sizestats " `false'"
+If this is
+.IR true ,
+then various numbers are output at the end of each query indicating
+what went on during the query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI skip_dump " `skips.%d'"
+If this parameter is set, then a file will be produced in the current
+directory during ranked queries on skipped inverted files when
+.B accumulator_method
+is set to
+.IR splay_tree ,
+.IR hash_table ,
+or
+.IR list .
+The name of the file is the value of this parameter.  A `%d' in the
+file name will be replaced with the process id of
+.BR mgquery .
+This file will contain information about the usage of skips during the
+query processing.  This option is expensive; use
+.B .unset skip_dump
+to obtain optimal performance.
+.TP
+.BI sorted_terms " `on'"
+This specifies whether or not the terms should be sorted into
+decreasing occurrence in documents so that the least-often occurring
+terms are processed first when ranked queries are being done.  When
+this is
+.IR true ,
+the terms are sorted.  When this is
+.IR false ,
+the terms are not sorted, and are instead processed in order of
+occurrence.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI stop_at_max_accum " `on'"
+This specifies what should happen when the maximum number of
+accumulators set by
+.B max_accumulators
+is reached.  When this is
+.IR true ,
+the processing of terms is stopped at the completion of the current
+term.  When this is
+.IR false ,
+processing continues but no new accumulators are created.  This
+parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI terminator " `'"
+This specifies the string that will be output after the last document
+from the previous query has been output.  The standard C escape
+character sequences may be used to place special characters in the
+string.  For example, a newline would be written as `\en'.  To include
+a `%', use the sequence `%%'.
+.TP
+.BI timestats " `false'"
+If this is
+.IR true ,
+then the time to process a query is displayed in both real time and
+CPU time.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI verbatim " `off'"
+This is a Boolean parameter that determines whether the program
+should attempt to do a regular-expression match on the retrieved
+text.  If verbatim is
+.I on
+and a post-processing string is specified with the query, then the
+post-processing string will be searched for in the documents just
+before they are displayed.  If the string is found, the document will
+be displayed; if not, the document will not be displayed.  If verbatim
+is
+.IR off ,
+the post-processing string will be considered a regular expression
+as in
+.BR egrep (1)
+or
+.BR vi (1).
+E.g., if verbatim is
+.I on,
+\*(lq\fBand.*the\fP\*(rq will look for the 8-character sequence
+\*(lq\fBand.*the\fP\*(rq.  If verbatim is
+.IR off ,
+\*(lq\fBand.*the\fP\*(rq will look for the sequence
+\*(lq\fBand\fP\*(rq followed somewhere later in the document by the
+sequence \*(lq\fBthe\fP\*(rq.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.I .mgrc
+.B mgquery
+startup file
+.TP
+.B help.mg
+Help file for
+.BR mgquery .
+The contents of this file is displayed with the
+.B .help
+command.
+.TP
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+The `on-disk' stemmed dictionary.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.dict
+Compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR egrep (1),
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1),
+.BR vi (1),
+.BR yacc (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgstat.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgstat.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgstat.1	(revision 10506)
@@ -0,0 +1,131 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgstat 1 \*(Dt CITRI
+.SH NAME
+mgstat \- print out statistics about a document collection
+.SH SYNOPSIS
+.B mgstat
+[
+.B \-h
+]
+[
+.B \-E
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgstat
+prints out various statistics about an existing
+.BR mg (1)
+document collection.  Depending on the size of the collection, sizes
+will be printed in either kilobytes or megabytes.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stdout .
+.TP
+.B \-E
+This option forces sizes to be printed in bytes rather than kilobytes
+or megabytes.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text
+Compressed documents.
+.TP
+.B *.invf
+Inverted file.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.TP
+.B *.invf.dict.blocked
+Compressed stemmed dictionary and index into the inverted file merged
+into an inverted file.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.invf.chunk
+Maps stemmed terms from occurrence order to lexical order.
+.TP
+.B *.invf.chunk.trans
+Describes where the source text is broken up into chunks for the
+inversion pass.
+.TP
+.B *.invf.dict.hash
+A perfect hash function for the terms in the stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgstemidxlist.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgstemidxlist.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgstemidxlist.1	(revision 10506)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgstemidxlist 1 \*(Dt CITRI
+.SH NAME
+mgstemidxlist \- dumps the stem index file to STDOUT in ASCII format
+.SH SYNOPSIS
+.B mgstemidxlist
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.B \-s 1|2|3
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgstemidxlist
+is a utility program which passes through the stem index and displays
+the information.  (This program was used for debugging but is included
+for completeness!)  The header information is printed out, then for each
+block in the file the block header is displayed.  For each word in the
+stem index, the output is formatted as:
+
+.RS
+.I number_of_references \*(lqword\*(rq
+.br
+.RS
+.I "->  number_of_cases block 3-in-4_block offset"
+.br
+.I "->  ..."
+.RE
+.RE
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B -s 1|2|3
+The stem index file with the associated stem method.
+.br
+1 = casefolded and non-stemmed
+.br
+2 = non-casefolded and stemmed
+.br
+3 = casefolded and stemmed
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.invf.dict.blocked.1
+Stem index with stem index method 1.
+.TP
+.B *.invf.dict.blocked.2
+Stem index with stem index method 2.
+.TP
+.B *.invf.dict.blocked.3
+Stem index with stem index method 3.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_invf_dict (1),
+.BR mg_stem_idx (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgtic.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgtic.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgtic.1	(revision 10506)
@@ -0,0 +1,137 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgtic 1 \*(Dt CITRI
+.SH NAME
+mgtic \- textual image compression.
+.SH SYNOPSIS
+.B mgtic
+.B \-e
+[
+.B \-L
+]
+[
+.B \-Q
+]
+[
+.B \-X
+]
+.I libraryfile
+.I infile
+.if n .ti +9n
+[
+.I \>compressed\-outfile
+]
+.nf
+or
+.fi
+.B mgtic
+.B \-d
+[
+.B \-L
+]
+[
+.BI \-X " libraryfile"
+]
+.I compressed-infile
+.if n .ti +9n
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+This is the main routine in the
+.B mgtic
+system.
+.B mgtic
+is used to
+processes a series of files, and by using the
+.I libraryfile
+produced by
+.BR mgticbuild (1),
+compresses input files with respect to the marks contained in the
+library.  On the CCITT test faxes, lossless mode achieved around 20:1
+compression, and lossy, around 40:1 compression.  On more textual
+images, the amount of compression is determined by the resolution of
+the original file, and the amount of noise in the image.  By default,
+.B mgtic
+will reconstruct a lossy version of the image.  This
+can be changed to lossless by using the
+.B \-L
+option.
+.SH OPTIONS
+Options may appear in any order, but must come before the input
+filenames.
+.TP "\w'\fB\-X\fP \fI[libraryfile]\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-e
+Encode
+.I infile
+with respect to the library.
+.TP
+.B \-d
+Decodes
+.IR compressed-infile
+with respect to the library.
+.TP
+.B \-l
+This specifies lossy mode, and is the default mode for (de)compression.
+Do not generate the residue.  If used in encoding mode, does not store
+the residue in the output.  If used in decoding mode, the residue (if
+it exists) is ignored.
+.TP
+.B \-L
+Use lossless mode for (de)compression, which generates the residue.
+If used in encoding mode, this stores the residue in the compressed
+output.  If used in decoding mode (assuming the residue is present),
+this allows the original file to be recovered exactly.
+.TP
+.BI \-R\  filename
+Stores the residue as an external file
+.I filename
+which could possibly be stored on another medium.  During
+decompression, if the residue file specified does not relate to the
+compressed file, the resulting decompressed image will be a mess.
+Note that only the width and height of the residue image is checked.
+.TP
+.BI \-Q
+Uses a quicker form of compression.  This option decreases the time
+spent looking for a good match during encoding.  On average this
+option decreases compression ratios, but increases compression speed.
+.TP
+.BI \-X " [libraryfile]"
+Use an external library file, instead of (de)compressing the library
+within the normal stream.  When decoding, the
+.B \-X
+option must be followed by the
+.IR libraryfile .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticbuild.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticbuild.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticbuild.1	(revision 10506)
@@ -0,0 +1,61 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticbuild 1 \*(Dt CITRI
+.SH NAME
+mgticbuild \- build a library of marks from training documents
+.SH SYNOPSIS
+.B mgticbuild
+[
+.B \-h
+]
+.I "libraryfile infile1 infile2 .\|.\|."
+.SH DESCRIPTION
+.B mgticbuild
+builds an uncompressed library of marks that have been
+extracted from a series of input files.  If the
+.I libraryfile
+does
+not exist, it is created, otherwise new marks are appended to the
+file.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.TP
+.I infile(s)
+The training files; the only currently-supported format is
+.IR pbm .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticdump.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticdump.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticdump.1	(revision 10506)
@@ -0,0 +1,55 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticdump 1 \*(Dt CITRI
+.SH NAME
+mgticdump \- displays the library in a user-friendly manner
+.SH SYNOPSIS
+.B mgticdump
+[
+.B \-h
+]
+.I libraryfile
+.SH DESCRIPTION
+.B mgticdump
+displays the marks in a library in a user-viewable form.  The output
+is to
+.I stdout
+and is in a plain ASCII form.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticprune.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticprune.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticprune.1	(revision 10506)
@@ -0,0 +1,91 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticprune 1 \*(Dt CITRI
+.SH NAME
+mgticprune \- prunes the library to remove duplicates
+.SH SYNOPSIS
+.B mgticprune
+[
+.BI \-a " n"
+]
+[
+.BI \-s " n"
+]
+[
+.B \-Q
+]
+.I libraryfile
+.if n .ti +9n
+[
+.I pruned-libraryfile
+]
+.SH DESCRIPTION
+.B mgticprune
+examines
+.I libraryfile
+and removes duplicate marks.  If
+.I pruned-libraryfile
+is not specified,
+.I libraryfile
+is overwritten with the marks in the pruned library.  The Combined
+Symbol Independent Strategy (CSIS) method is used to match marks.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIpruned-libraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-a " n"
+Prune marks when their area is under or equal to the threshold,
+.IR n .
+The default value is\ 3.
+.TP
+.BI \-s " n"
+Prune marks when their width and height is under or equal to
+the threshold,
+.IR n .
+The default value is\ 0.
+.TP
+.BI \-Q
+Use a quicker method of pruning.  The number of iterations through the
+averaging and pruning processes is decreased.  This usually reduces
+time by a half, but compression ratios decrease.
+.TP
+.I libraryfile
+This specifies the name of the library file
+.TP
+.I pruned-libraryfile
+This specifies the name of the prune library, after duplicates and
+matches have been removed.  If this file is not specified, then
+.I libraryfile
+will be overwritten.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticstat.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticstat.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/mgticstat.1	(revision 10506)
@@ -0,0 +1,57 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticstat 1 \*(Dt CITRI
+.SH NAME
+mgticstat \- displays the statistics for the library
+.SH SYNOPSIS
+.B mgticstat
+[
+.B \-h
+]
+.I libraryfile
+.SH DESCRIPTION
+.B mgticstat
+displays statistics about the
+.I libraryfile
+file.
+The output of this program contains the average mark size, average
+centroid position, and the number of marks with an area less than or
+equal to a few powers of\ 2.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/xmg.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/xmg.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/man/man1/xmg.1	(revision 10506)
@@ -0,0 +1,130 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH xmg 1 \*(Dt CITRI
+.SH NAME
+xmg \- An X interface to mgquery
+.SH SYNOPSIS
+.B xmg
+[
+.I collection-name
+]
+.SH DESCRIPTION
+.B xmg
+is an X interface to the
+.BR mg (1)
+information retrieval system.
+.PP
+Type a query in the ``Query'' box.  The escape key clears the query text.
+.PP
+The first line or so of each matching document is listed.
+.PP
+Click on any line to show the complete document.
+.PP
+Shift-click to show the document in a new window.
+.PP
+Press
+.I Next
+and
+.I Previous
+to cycle through the list of documents (shift works here too).
+.PP
+If you change the query, existing windows continue to refer to the
+original query.
+.PP
+You can select either Boolean or ranked queries:
+.RS
+.TP "\w'\fIBoolean queries:\fP'u+2n"
+.I "Boolean queries:"
+use ``&'' for AND, ``|'' for OR, ``!'' for NOT, and parentheses for
+grouping.
+.TP
+.I "Ranked queries:"
+Documents are listed in order of relevance.  A weight is shown
+alongside each.  Weights are normalized to 100 for the most relevant
+document.  Choose
+.I "Approximate Ranking"
+for greater retrieval speed.
+.RE
+.PP
+In document windows (other than the main window):
+.RS
+.br
+Typing `n' = next document;
+.br
+Typing `N' = next document in new window;
+.br
+Typing `p' = previous document;
+.br
+Typing `P' = previous document in new window;
+.br
+Typing `q' = close window.
+.RE
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.TP
+.SB Xdefaults
+To override the default font options, use RESOURCE_MANAGER properties
+like the following in your
+.I .Xdefaults
+file:
+.IP
+.RS
+.nf
+.I "xmg.textfont: fixed"
+.I "xmg.buttonfont: fixed"
+.fi
+.RE
+.IP
+To override the default query type of ranked, use
+.IP
+.RS
+.I "xmg.querytype: boolean"
+.RE
+.IP
+To override the default collection name (the first one listed by
+.BR ls (1)
+from your MGDATA environment variable), use
+.IP
+.RS
+.I "xmg.collection: mail93"
+.RE
+.SH "SEE ALSO"
+.na
+.BR ls (1),
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/mkinstalldirs
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/mkinstalldirs	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/mkinstalldirs	(revision 10506)
@@ -0,0 +1,32 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Last modified: 1994-03-25
+# Public domain
+
+errstatus=0
+
+for file in ${1+"$@"} ; do 
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d in ${1+"$@"} ; do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp" 1>&2
+        mkdir "$pathcomp" || errstatus=$?
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/Makefile.in	(revision 10506)
@@ -0,0 +1,217 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the MG system
+# Copyright (C) 1994  Neil Sharman
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)Makefile.in	1.10 22 Mar 1994
+#
+###########################################################################
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+subdir = src/images
+top_srcdir = @top_srcdir@
+transform = @program_transform_name@
+ 
+CC = @CC@
+CFLAGS = @CFLAGS@ 
+CPPFLAGS = @CPPFLAGS@
+DEFS = @DEFS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBS = ../../lib/libmg.a @LIBS@
+GSDLOS = @gsdlos@
+TOUCH = echo timestamp >
+ 
+bindir = ../../../../bin/$(GSDLOS)
+datadir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+localedir = $(datadir)/locale
+mandir = $(prefix)/man/man1
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+ 
+
+ANSI2KNR = @ANSI2KNR@
+o = .@U@o
+ 
+.SUFFIXES: ._c ._o
+.c._c:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $@
+._c._o:
+	@echo $(COMPILE) $<
+	@rm -f _$*.c
+	@ln $< _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+.c._o:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $*._c
+	@echo $(COMPILE) $*._c
+	@rm -f _$*.c
+	@ln $*._c _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+ 
+INCLUDES = -I../../../.. -I../.. -I../../lib -I.
+
+
+SOURCES = \
+  arithcode.c     extractor.c     mgbilevel.c     mgticdump.c     utils.c \
+  bilevel.c       felics.c        mgfelics.c      mgticprune.c    mgticstat.c\
+  codeoffsets.c   marklist.c      mgtic.c         pbmtools.c      lstevent.c \
+  codesyms.c      match.c         mgticbuild.c    sortmarks.c     ppm.c  
+
+
+ 
+HEADERS = \
+  arithcode.h     codeoffsets.h   marklist.h      sortmarks.h \
+  basictypes.h    codesyms.h      match.h         utils.h     \
+  bilevel.h       extractor.h     pbmtools.h      model.h
+
+MISC          = Makefile.in 
+
+ALLFILES      =	$(SOURCES) $(HEADERS) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES) 
+
+EXEC          = mgfelics mgbilevel mgtic mgticbuild mgticprune mgticstat \
+                mgticdump
+
+MAN           = mgfelics.1 mgbilevel.1 mgtic.1 mgticbuild.1  mgticprune.1 \
+                mgticstat.1 mgticdump.1
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all: $(EXEC)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+FELICS_OBJS = felics$o mgfelics$o utils$o
+
+mgfelics: $(FELICS_OBJS)
+	$(LINK) $(FELICS_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+BILEVEL_OBJS = \
+	arithcode$o bilevel$o extractor$o marklist$o mgbilevel$o \
+	pbmtools$o utils$o
+            
+mgbilevel: $(BILEVEL_OBJS)
+	$(LINK) $(BILEVEL_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+TIC_OBJS = \
+	mgtic$o extractor$o marklist$o pbmtools$o utils$o match$o \
+	sortmarks$o codesyms$o ppm$o lstevent$o arithcode$o codeoffsets$o bilevel$o
+
+mgtic: $(TIC_OBJS) 
+	$(LINK) $(TIC_OBJS) $(LIBS) 
+
+TICBUILD_OBJS = mgticbuild$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticbuild: $(TICBUILD_OBJS)
+	$(LINK) $(TICBUILD_OBJS) $(LIBS)
+ 
+TICPRUNE_OBJS = \
+	mgticprune$o extractor$o marklist$o pbmtools$o \
+	utils$o match$o
+
+mgticprune: $(TICPRUNE_OBJS)
+	$(LINK) $(TICPRUNE_OBJS) $(LIBS)
+ 
+TICSTAT_OBJS = mgticstat$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticstat: $(TICSTAT_OBJS)
+	$(LINK) $(TICSTAT_OBJS) $(LIBS) 
+ 
+TICDUMP = mgticdump$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticdump: $(TICDUMP)
+	$(LINK) $(TICDUMP) $(LIBS) 
+ 
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+ansi2knr: ansi2knr.o
+	$(LINK) ansi2knr.o $(LIBS)
+
+install: execinstall #maninstall
+uninstall: execuninstall manuninstall
+
+execinstall: $(EXEC)
+	for name in $(EXEC); do \
+	  $(INSTALL_PROGRAM) $$name \
+	  $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+execuninstall:
+	for name in $(EXEC); do \
+	 rm -f $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+
+mostlyclean:
+	rm -f *$o _*.c _*.o *._c *._o core core.*
+ 
+clean: mostlyclean
+	rm -f $(EXEC)
+ 
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+ 
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+	  || cp -p $(srcdir)/$$file $(distdir); \
+	done
+
+# screws up distclean (jrm21) 
+#Makefile: Makefile.in ../../../../config.status
+#	cd ../../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/WIN32.MAK
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/WIN32.MAK	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/WIN32.MAK	(revision 10506)
@@ -0,0 +1,201 @@
+# Generated automatically from Makefile.in by configure.
+###########################################################################
+#
+# Makefile.in -- Makefile for the MG system
+# Copyright (C) 1994  Neil Sharman
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)Makefile.in	1.10 22 Mar 1994
+#
+###########################################################################
+
+#PACKAGE = mg
+#VERSION = 1.2
+ 
+#SHELL = /bin/sh
+#exec_prefix = ${prefix}
+#prefix = /home/rpeeters/mg/mg-1.3.2
+#srcdir = .
+#subdir = src/images
+#top_srcdir = ../..
+#transform = s,x,x,
+ 
+CC = cl
+#CFLAGS = -g -O -Wall 
+CPPFLAGS = 
+DEFS = -DHAVE_CONFIG_H -D__WIN32__ -D_LITTLE_ENDIAN
+#INSTALL = /usr/local/gnu/bin/install -c
+#INSTALL_DATA = ${INSTALL} -m 644
+#INSTALL_PROGRAM = ${INSTALL}
+LDFLAGS = 
+LIBS = ..\..\lib\libmg.lib 
+#TOUCH = echo timestamp >
+ 
+#bindir = $(exec_prefix)/bin
+#datadir = $(prefix)/share
+#libexecdir = $(exec_prefix)/libexec
+#localedir = $(datadir)/locale
+#mandir = $(prefix)/man/man1
+ 
+COMPILE = $(CC) -c $(DEFS) -I. -I..\.. -I..\..\lib
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+ 
+
+o = .obj
+e = .exe
+ 
+
+SOURCES = \
+  arithcode.c     extractor.c     mgbilevel.c     mgticdump.c     utils.c \
+  bilevel.c       felics.c        mgfelics.c      mgticprune.c    mgticstat.c\
+  codeoffsets.c   marklist.c      mgtic.c         pbmtools.c      lstevent.c \
+  codesyms.c      match.c         mgticbuild.c    sortmarks.c     ppm.c  
+
+
+ 
+HEADERS = \
+  arithcode.h     codeoffsets.h   marklist.h      sortmarks.h \
+  basictypes.h    codesyms.h      match.h         utils.h     \
+  bilevel.h       extractor.h     pbmtools.h      model.h
+
+MISC          = Makefile.in 
+
+ALLFILES      =	$(SOURCES) $(HEADERS) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES) 
+
+EXEC          = mgfelics$e mgbilevel$e mgtic$e mgticbuild$e mgticprune$e mgticstat$e \
+                mgticdump$e
+
+MAN           = mgfelics.1 mgbilevel.1 mgtic.1 mgticbuild.1  mgticprune.1 \
+                mgticstat.1 mgticdump.1
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all: $(EXEC)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+FELICS_OBJS = felics$o mgfelics$o utils$o
+
+mgfelics$e: $(FELICS_OBJS)
+	$(LINK) $(FELICS_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+BILEVEL_OBJS = \
+	arithcode$o bilevel$o extractor$o marklist$o mgbilevel$o \
+	pbmtools$o utils$o
+            
+mgbilevel$e: $(BILEVEL_OBJS)
+	$(LINK) $(BILEVEL_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+TIC_OBJS = \
+	mgtic$o extractor$o marklist$o pbmtools$o utils$o match$o \
+	sortmarks$o codesyms$o ppm$o lstevent$o arithcode$o codeoffsets$o bilevel$o
+
+mgtic$e: $(TIC_OBJS) 
+	$(LINK) $(TIC_OBJS) $(LIBS) 
+
+TICBUILD_OBJS = mgticbuild$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticbuild$e: $(TICBUILD_OBJS)
+	$(LINK) $(TICBUILD_OBJS) $(LIBS)
+ 
+TICPRUNE_OBJS = \
+	mgticprune$o extractor$o marklist$o pbmtools$o \
+	utils$o match$o
+
+mgticprune$e: $(TICPRUNE_OBJS)
+	$(LINK) $(TICPRUNE_OBJS) $(LIBS)
+ 
+TICSTAT_OBJS = mgticstat$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticstat$e: $(TICSTAT_OBJS)
+	$(LINK) $(TICSTAT_OBJS) $(LIBS) 
+ 
+TICDUMP = mgticdump$o extractor$o marklist$o pbmtools$o utils$o
+
+mgticdump$e: $(TICDUMP)
+	$(LINK) $(TICDUMP) $(LIBS) 
+ 
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+#ansi2knr: ansi2knr.o
+#	$(LINK) ansi2knr.o $(LIBS)
+#
+install: execinstall maninstall
+uninstall: execuninstall manuninstall
+
+#execinstall: $(EXEC)
+#	$(top_srcdir)/mkinstalldirs $(bindir); \
+#	for name in $(EXEC); do \
+#	  $(INSTALL_PROGRAM) $$name \
+#	  $(bindir)/`echo $$name | sed '$(transform)'`; \
+#	done
+
+#execuninstall:
+#	for name in $(EXEC); do \
+#	 rm -f $(bindir)/`echo $$name | sed '$(transform)'`; \
+#	done
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+
+mostlyclean:
+	rm -f *$o _*.c _*.o *._c *._o core core.*
+ 
+clean: mostlyclean
+	rm -f $(EXEC)
+ 
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+ 
+#dist: $(DISTFILES)
+#	for file in $(DISTFILES); do \
+#	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+#	  || cp -p $(srcdir)/$$file $(distdir); \
+#	done
+ 
+#Makefile: Makefile.in ../../config.status
+#	cd ../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+#.NOEXPORT:
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/arithcode.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/arithcode.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/arithcode.c	(revision 10506)
@@ -0,0 +1,471 @@
+/**************************************************************************
+ *
+ * arithcode.c -- Arithmetic coding
+ * Copyright (C) 1994  Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *	Arithmetic encoding. Taken largely from Witten, Neal, Cleary,
+ *		CACM, 1987, p520.
+ *	Includes bitfiddling routines.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "arithcode.h"
+
+
+FILE *arith_in, *arith_out;
+
+/*
+   $log$
+ */
+
+static char *RCSID = "$Id$";
+
+#undef BECAREFUL
+#define INTEGRATED
+
+
+codevalue S_low = 0, S_high = 0, S_value = 0;
+long S_bitstofollow = 0;
+int S_buffer = 0, S_bitstogo = 0;
+
+long cmpbytes = 0, rawbytes = 0;
+
+#ifdef INTEGRATED
+long CountOfBitsOut;
+#endif
+
+
+/*==================================*/
+
+#define BITPLUSFOLLOW(b)		\
+{	OUTPUTBIT((b));			\
+	while (bitstofollow)		\
+	{	OUTPUTBIT(!(b));	\
+		bitstofollow -= 1;	\
+	}				\
+}
+
+#ifdef INTEGRATED
+#define OUTPUTBIT(b)			\
+{	buffer >>= 1;			\
+	if (b) buffer |= 0x80;	 	\
+	bitstogo -= 1;			\
+	if (bitstogo==0)		\
+	{	putc(buffer, arith_out);	\
+		bitstogo = 8;		\
+		cmpbytes += 1;		\
+	}				\
+	CountOfBitsOut++;		\
+}
+#else
+#define OUTPUTBIT(b)			\
+{	buffer >>= 1;			\
+	if (b) buffer |= 0x80;	 	\
+	bitstogo -= 1;			\
+	if (bitstogo==0)		\
+	{	putc(buffer, arith_out);	\
+		bitstogo = 8;		\
+		cmpbytes += 1;		\
+	}				\
+}
+#endif
+
+#define ADDNEXTINPUTBIT(v)		\
+{	if (bitstogo==0)		\
+	{	buffer = getc(arith_in);	\
+		bitstogo = 8;		\
+	}				\
+	v = (v<<1)+(buffer&1);		\
+	buffer >>= 1;			\
+	bitstogo -=1;			\
+}
+
+/*==================================*/
+
+void
+arithmetic_encode (lbnd, hbnd, totl)
+     int lbnd, hbnd, totl;
+{
+  register codevalue low, high;
+
+#ifdef BECAREFUL
+  if (!(0 <= lbnd && lbnd < hbnd && hbnd <= totl && totl < maxfrequency))
+    {
+      fprintf (stderr, "(corrupt file) coding error: %d %d %d\n", lbnd, hbnd, totl);
+      abort ();
+    }
+#endif
+
+  {
+    register codevalue range;
+    range = S_high - S_low + 1;
+    high = S_low + range * hbnd / totl - 1;
+    low = S_low + range * lbnd / totl;
+  }
+
+  {
+    register codevalue H;
+    register long bitstofollow;
+    register int buffer, bitstogo;
+
+    bitstofollow = S_bitstofollow;
+    buffer = S_buffer;
+    bitstogo = S_bitstogo;
+    H = half;
+
+    for (;;)
+      {
+	if (high < H)
+	  {
+	    BITPLUSFOLLOW (0);
+	  }
+	else if (low >= H)
+	  {
+	    BITPLUSFOLLOW (1);
+	    low -= H;
+	    high -= H;
+	  }
+	else if (low >= firstqtr && high < thirdqtr)
+	  {
+	    bitstofollow++;
+	    low -= firstqtr;
+	    high -= firstqtr;
+	  }
+	else
+	  break;
+	low += low;
+	high += high;
+	high++;
+      }
+    S_bitstofollow = bitstofollow;
+    S_buffer = buffer;
+    S_bitstogo = bitstogo;
+    S_low = low;
+    S_high = high;
+  }
+}
+
+/*==================================*/
+
+/* Made into a macro 
+
+   codevalue
+   arithmetic_decode_target(totl)
+   register int totl;
+   {    return (((S_value-S_low+1)*totl-1) / (S_high -S_low+1));
+   } 
+ */
+
+/*==================================*/
+
+void
+arithmetic_decode (lbnd, hbnd, totl)
+     int lbnd, hbnd, totl;
+{
+  register codevalue low, high;
+
+#ifdef BECAREFUL
+  if (!(0 <= lbnd && lbnd < hbnd && hbnd <= totl && totl < maxfrequency))
+    {
+      fprintf (stderr, "(corrupt file) coding error: %d %d %d\n", lbnd, hbnd, totl);
+      abort ();
+    }
+#endif
+
+  {
+    register codevalue range;
+    range = S_high - S_low + 1;
+    high = S_low + range * hbnd / totl - 1;
+    low = S_low + range * lbnd / totl;
+  }
+
+  {
+    register codevalue value, H;
+    register int buffer, bitstogo;
+
+    buffer = S_buffer;
+    bitstogo = S_bitstogo;
+    H = half;
+    value = S_value;
+
+    for (;;)
+      {
+	if (high < H)
+	  {			/* nothing */
+	  }
+	else if (low >= H)
+	  {
+	    value -= H;
+	    low -= H;
+	    high -= H;
+	  }
+	else if (low >= firstqtr && high < thirdqtr)
+	  {
+	    value -= firstqtr;
+	    low -= firstqtr;
+	    high -= firstqtr;
+	  }
+	else
+	  break;
+	low += low;
+	high += high;
+	high += 1;
+	ADDNEXTINPUTBIT (value);
+      }
+    S_buffer = buffer;
+    S_bitstogo = bitstogo;
+    S_low = low;
+    S_high = high;
+    S_value = value;
+  }
+}
+
+/*==================================*/
+
+
+static void
+startoutputingbits ()
+{
+  S_buffer = 0;
+  S_bitstogo = 8;
+}
+
+static void
+startinputingbits ()
+{
+  S_buffer = 0;
+  S_bitstogo = 0;
+}
+
+static void
+doneoutputingbits ()
+{				/* write another byte if necessary */
+  if (S_bitstogo < 8)
+    {
+      putc (S_buffer >> S_bitstogo, arith_out);
+      cmpbytes += 1;
+    }
+}
+
+/*==================================*/
+
+static void
+startencoding ()
+{
+  S_low = 0;
+  S_high = topvalue;
+  S_bitstofollow = 0;
+}
+
+static void
+startdecoding ()
+{
+  register int i;
+  register int buffer, bitstogo;
+  S_low = 0;
+  S_high = topvalue;
+  S_value = 0;
+  bitstogo = S_bitstogo;
+  buffer = S_buffer;
+  for (i = 0; i < codevaluebits; i++)
+    ADDNEXTINPUTBIT (S_value);
+  S_bitstogo = bitstogo;
+  S_buffer = buffer;
+}
+
+static void
+doneencoding ()
+{
+  register long bitstofollow;
+  register int buffer, bitstogo;
+  bitstofollow = S_bitstofollow;
+  buffer = S_buffer;
+  bitstogo = S_bitstogo;
+  bitstofollow += 1;
+  if (S_low < firstqtr)
+    {
+      BITPLUSFOLLOW (0);
+    }
+  else
+    {
+      BITPLUSFOLLOW (1);
+    }
+  S_bitstofollow = bitstofollow;
+  S_buffer = buffer;
+  S_bitstogo = bitstogo;
+}
+
+
+
+void 
+EncodeGammaDist (int Off)
+/* Encode Off with probability distribution derived from the Elias gamma distribution. */
+{
+  int Len, i;
+
+  Off++;
+  for (Len = 31; Len >= 0 && !(Off & (1 << Len)); Len--);
+
+  for (i = Len; i >= 0; i--)
+    arithmetic_encode (0, 1, 2);
+  arithmetic_encode (1, 2, 2);
+
+  for (i = Len - 1; i >= 0; i--)
+    if (Off & (1 << i))
+      arithmetic_encode (1, 2, 2);
+    else
+      arithmetic_encode (0, 1, 2);
+}
+
+
+
+int 
+DecodeGammaDist ()
+/* Decode next Off using probability distribution derived from the Elias gamma distribution. Inverse of EncodeGammaDist. */
+{
+  int i = 1, Len = 0, bit;
+
+  do
+    {
+      bit = arithmetic_decode_target (2) < 1 ? 0 : 1;
+      if (bit)
+	arithmetic_decode (1, 2, 2);
+      else
+	{
+	  arithmetic_decode (0, 1, 2);
+	  Len++;
+	}
+    }
+  while (!bit);
+
+  Len--;
+  while (Len-- > 0)
+    {
+      bit = arithmetic_decode_target (2) < 1 ? 0 : 1;
+      if (bit)
+	arithmetic_decode (1, 2, 2);
+      else
+	arithmetic_decode (0, 1, 2);
+      i = (i << 1) | bit;
+    }
+  return (i - 1);
+}
+
+
+
+
+
+void 
+EncodeGammaSigned (int snum, int *pos, int *neg)
+{
+  if (snum >= 0)
+    arithmetic_encode (0, *pos, *pos + (*neg)), (*pos)++;
+  else
+    arithmetic_encode (*pos, *pos + (*neg), *pos + (*neg)), (*neg)++;
+  if (*pos + (*neg) >= maxfrequency)
+    {
+      *pos = (*pos + 1) / 2;
+      *neg = (*neg + 1) / 2;
+    }
+  EncodeGammaDist (abs (snum));
+}
+
+
+int 
+DecodeGammaSigned (int *pos, int *neg)
+{
+  int signedpos = 1;
+  if (arithmetic_decode_target (*pos + (*neg)) < *pos)
+    arithmetic_decode (0, *pos, *pos + (*neg)), (*pos)++;
+  else
+    arithmetic_decode (*pos, *pos + (*neg), *pos + (*neg)), (*neg)++, signedpos = 0;
+
+  if (*pos + (*neg) >= maxfrequency)
+    {
+      *pos = (*pos + 1) / 2;
+      *neg = (*neg + 1) / 2;
+    }
+
+  if (signedpos)
+    return DecodeGammaDist ();
+  else
+    return (-DecodeGammaDist ());
+}
+
+
+void 
+InitArithEncoding (void)
+{
+  S_low = 0, S_high = 0, S_value = 0;
+  S_bitstofollow = 0;
+  S_buffer = 0, S_bitstogo = 0;
+  cmpbytes = 0, rawbytes = 0;
+
+  startoutputingbits ();
+  startencoding ();
+}
+
+void 
+InitArithDecoding (void)
+{
+  S_low = 0, S_high = 0, S_value = 0;
+  S_bitstofollow = 0;
+  S_buffer = 0, S_bitstogo = 0;
+  cmpbytes = 0, rawbytes = 0;
+
+  startinputingbits ();
+  startdecoding ();
+}
+
+void 
+CloseDownArithEncoding (void)
+{
+  doneencoding ();
+  doneoutputingbits ();
+}
+
+void 
+CloseDownArithDecoding (void)
+{
+}
+
+
+
+
+
+/* encode that famous number, 42 uses 12 bits */
+void 
+EncodeChecksum ()
+{
+  EncodeGammaDist (42);
+}
+
+void 
+DecodeChecksum (char str[])
+{
+  if (DecodeGammaDist () != 42)
+    {
+      fprintf (stderr, "%s: checksum error, file corrupt.\n", str);
+      exit (1);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/arithcode.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/arithcode.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/arithcode.h	(revision 10506)
@@ -0,0 +1,78 @@
+/**************************************************************************
+ *
+ * arithcode.h -- Arithmetic coding
+ * Copyright (C) 1994  Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef _arithcode_h
+#define _arithcode_h
+
+extern FILE *arith_in, *arith_out;
+
+#define codevaluebits 16
+#if (codevaluebits<16)
+typedef unsigned short codevalue;
+#else
+typedef unsigned long codevalue;
+#endif
+
+#define topvalue ((codevalue)((1<<codevaluebits)-1))
+#define maxfrequency ((topvalue+1)/4 + 1)
+
+#define firstqtr (topvalue/4+1)
+#define half     (2*firstqtr)
+#define thirdqtr (3*firstqtr)
+
+#define	escape_event	U->totalcnt-U->notfound, U->totalcnt, U->totalcnt
+
+void arithmetic_encode ();
+codevalue arithmetic_decode_target ();
+
+#define	arithmetic_decode_target(totl)	\
+	(  ((S_value-S_low+1)*(totl)-1) / (S_high-S_low+1)  )
+
+void arithmetic_decode ();
+
+
+extern codevalue S_low, S_high, S_value;
+extern long S_bitstofollow;
+extern int S_buffer, S_bitstogo;
+
+extern long cmpbytes, rawbytes;
+
+extern long CountOfBitsOut;
+
+void EncodeGammaDist (int Off);
+int DecodeGammaDist ();
+
+void EncodeGammaSigned (int snum, int *pos, int *neg);
+int DecodeGammaSigned (int *pos, int *neg);
+
+
+void InitArithEncoding (void);
+void InitArithDecoding (void);
+
+void CloseDownArithEncoding (void);
+void CloseDownArithDecoding (void);
+
+void EncodeChecksum ();
+void DecodeChecksum (char str[]);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/basictypes.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/basictypes.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/basictypes.h	(revision 10506)
@@ -0,0 +1,34 @@
+/**************************************************************************
+ *
+ * basictypes.h -- base data types
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ * This file contains information relating to the base data types
+ *
+ **************************************************************************/
+
+#ifndef __basictypes_h
+#define __basictypes_h
+
+typedef unsigned long Pixel;
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/bilevel.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/bilevel.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/bilevel.c	(revision 10506)
@@ -0,0 +1,747 @@
+/**************************************************************************
+ *
+ * bilevel.c -- Compress a bilevel bitmap
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ *  
+ *  
+ *  This is the code used to compress a bitmap.  The template is given in
+ *  the following format. 
+ *   '.'  = pixel not used
+ *   'p'  = pixel used in 1st order context (the superset)
+ *   '2'  = pixel used in 2nd order context (the subset)
+ *   ';'  = marker used to denote the end of a row in the template
+ *   '*'  = the current context pixel.
+ *  for instance, the common 22/10 template would be shown as:
+ *     ".ppppp.;"
+ *     "pp222pp;"
+ *     "p22222p;"
+ *     "p22*...;"
+ * 
+ **************************************************************************/
+
+
+#include "sysfuncs.h"
+
+#include "bilevel.h"
+#include "extractor.h"
+#include "pbmtools.h"
+#include "marklist.h"
+#include "arithcode.h"
+#include "utils.h"
+
+
+
+#define INITVALUE 2
+#define INCREMENT 4
+
+#define MAX_T_W 32
+
+/* note memory usage is 2*TEMPLATESIZE*sizeof(prob), which is currently 4.9 Mb */
+#define TEMPLATESIZE 612317
+
+
+#define HASH(x) ((x)%TEMPLATESIZE)
+
+
+typedef struct
+  {
+    unsigned short s, n;
+  }
+prob;				/* set and notset */
+typedef struct
+  {
+    short int x, y;
+  }
+coordinate;
+
+coordinate MM[MAX_T_W][MAX_T_W];	/* the actual (x,y) positions */
+unsigned int MMcount[MAX_T_W];	/* number of bits in this row of the template */
+unsigned int MMmask[MAX_T_W];	/* the "current" mask value */
+unsigned int MMbits[MAX_T_W];	/* the bitmask to mask out higher bits */
+unsigned int MMrows;		/* total number of rows */
+unsigned int MM2level[MAX_T_W];	/* bitmask to calculate the 2nd level mask */
+int twolevel, curr_row, surr;
+
+prob *P = NULL;			/* probability array, up to N bits */
+prob *P2 = NULL;
+
+void 
+bl_clearmodel ()
+{
+  int i;
+
+  P = (prob *) malloc (TEMPLATESIZE * sizeof (prob));
+  if (!P)
+    error_msg ("bl_clearmodel()", "not enough memory.", "");
+
+  P2 = (prob *) malloc (TEMPLATESIZE * sizeof (prob));
+  if (!P2)
+    error_msg ("bl_clearmodel()", "not enough memory.", "");
+
+  for (i = 0; i < TEMPLATESIZE; i++)
+    {
+      P[i].s = P[i].n = INITVALUE;
+      P2[i].s = P2[i].n = INITVALUE;
+    }
+}
+
+
+void 
+bl_freemodel ()
+{
+  free (P);
+  free (P2);
+}
+
+
+
+
+#define update_counts(p, pixel)                        \
+    pixel ? (p->s+=INCREMENT) : (p->n+=INCREMENT);     \
+                                                       \
+    if(p->s+p->n >= (unsigned)(maxfrequency)) {        \
+       p->s=(p->s+1)/(unsigned)2;                      \
+       p->n=(p->n+1)/(unsigned)2;                      \
+    }
+
+
+
+
+/* mask is the bigger one, mask2l is smaller one */
+static void 
+bl_encode_in_context (unsigned long mask, unsigned long mask2l, unsigned long pixel)
+{
+  register int twol, t;
+  prob *p = &P[mask];
+  prob *p2 = &P2[mask2l];
+
+  twol = twolevel && (p->s + p->n < (unsigned) (2 * INITVALUE + 5 * INCREMENT));
+
+  t = twol ? (p2->s + p2->n) : (p->s + p->n);
+
+  if (twol == 0)
+    {
+      if (pixel)
+	arithmetic_encode (0, p->s, t);
+      else
+	arithmetic_encode (p->s, t, t);
+      update_counts (p, pixel);
+    }
+  else
+    {
+      if (pixel)
+	arithmetic_encode (0, p2->s, t);
+      else
+	arithmetic_encode (p2->s, t, t);
+      update_counts (p2, pixel);
+      update_counts (p, pixel);
+    }
+}
+
+
+static void 
+bl_decode_in_context (unsigned long mask, unsigned long mask2l, unsigned long *val)
+{
+  register int twol, pixel, t;
+  prob *p = &P[mask];
+  prob *p2 = &P2[mask2l];
+
+
+  if (twolevel && (p->s + p->n < (unsigned) (2 * INITVALUE + 5 * INCREMENT)))
+    {
+      pixel = arithmetic_decode_target (p2->s + p2->n) < p2->s, twol = 1;
+    }
+  else
+    {
+      pixel = arithmetic_decode_target (p->s + p->n) < p->s, twol = 0;
+    }
+
+  t = twol ? (p2->s + p2->n) : (p->s + p->n);
+
+  if (twol == 0)
+    {
+      if (pixel)
+	arithmetic_decode (0, p->s, t);
+      else
+	arithmetic_decode (p->s, t, t);
+      update_counts (p, pixel);
+    }
+  else
+    {
+      if (pixel)
+	arithmetic_decode (0, p2->s, t);
+      else
+	arithmetic_decode (p2->s, t, t);
+      update_counts (p2, pixel);
+      update_counts (p, pixel);
+    }
+
+  *val = pixel;
+}
+
+static void 
+bl_string_to_array (char inputstr[], char parsestr[], int *w, int *h)
+{
+  int r, c;
+  int i, j, lastc, p, l;
+  int xc, yc;
+  int foundstatus;
+
+  surr = twolevel = 0;
+  for (i = 0; i < MAX_T_W; i++)
+    MMcount[i] = MM2level[i] = 0;
+  MMrows = 0;
+
+  for (i = 0; i < (int) strlen (inputstr); i++)
+    {
+      p = inputstr[i];
+      if ((p != '.') && (p != '2') && (p != '*') && (p != 'p') && (p != ';'))
+	{
+	  fprintf (stderr, "Template string can only contain [.p2*;], not \"%c\".\n", inputstr[i]);
+	  exit (1);
+	}
+    }
+
+  /* get the width and height, test rectangularity... */
+  parsestr[l = 0] = 0;
+  for (c = 0, r = 0, lastc = -1, p = 0; p < (int) strlen (inputstr); p++)
+    {
+      if ((inputstr[p] == ';'))
+	{
+	  r++;
+	  if (lastc != -1)
+	    {			/* this is the 2nd row at least */
+	      if (lastc != c)
+		{
+		  fprintf (stderr, "The rows have to be the same width. "
+			   "Row %d has width %d (previous row has width %d)\n", r, c, lastc);
+		  exit (1);
+		}
+	    }
+	  lastc = c;
+	  c = 0;
+	}
+      else
+	{
+	  c++;
+	  parsestr[l] = inputstr[p];
+	  parsestr[++l] = 0;
+	}
+    }
+
+  if (c != 0)
+    lastc = c;
+  *w = lastc;
+  *h = r;
+  if ((*w) <= 0)
+    {
+      fprintf (stderr, "Must have at least one column!\n");
+      exit (1);
+    }
+  if ((*h) <= 0)
+    {
+      fprintf (stderr, "Must have at least one row! Terminate each row with a ';'\n");
+      exit (1);
+    }
+  if ((*w > MAX_T_W) || (*h > MAX_T_W))
+    {
+      fprintf (stderr, "template size bigger than internal threshold of %d\n", MAX_T_W);
+      exit (1);
+    }
+
+  /* get the (x,y) position of the current (*) pixel */
+  for (xc = -1, yc = 0, i = 0; i < *w; i++)
+    for (j = 0; j < *h; j++)
+      if (parsestr[j * (*w) + i] == '*')
+	{
+	  if (xc >= 0)
+	    {
+	      fprintf (stderr, "There can only be ONE current ('*') pixel.\n");
+	      exit (1);
+	    }
+	  xc = i;
+	  yc = j;
+	  curr_row = j + 1;
+	}
+  if (xc < 0)
+    error_msg ("bl_string_to_array", "Error in mask, no current ('*') pixel.", "");
+  /* found the position (xc,yc) */
+
+
+  /* convert parsestr[] into a MM[][] structure */
+  for (j = 0; j < *h; j++)
+    {
+      foundstatus = 0;
+      for (i = 0; i < *w; i++)
+	{
+	  p = j * (*w) + i;
+	  if ((parsestr[p] == 'p') || (parsestr[p] == '2'))
+	    {
+	      if (!foundstatus)
+		foundstatus = 1;
+	      MM2level[j] = MM2level[j] * 2 | (parsestr[p] == '2');
+	      if (parsestr[p] == '2')
+		twolevel = 1;
+
+	      MM[j][MMcount[j]].x = i - xc;
+	      MM[j][MMcount[j]++].y = j - yc;
+	      if (((i - xc) >= 0) && ((j - yc) >= 0))
+		surr = 1;
+	    }
+	  else
+	    {
+	      if (foundstatus == 1)
+		foundstatus = 2;
+	    }
+
+	}
+      if (foundstatus)
+	MMrows++;
+      MMbits[j] = (1 << MMcount[j]) - 1;
+    }
+
+  /* reverse matrix, so [][0] is the closest to the right */
+  {
+    coordinate temp;
+    for (i = 0; i < MMrows; i++)
+      for (j = 0; j < MMcount[i] / (unsigned) 2; j++)
+	{
+	  temp = MM[i][MMcount[i] - 1 - j];
+	  MM[i][MMcount[i] - 1 - j] = MM[i][j];
+	  MM[i][j] = temp;
+	}
+  }
+}
+
+
+
+
+
+
+
+
+void 
+bl_writetemplate (char inputstr[])
+{
+  register int i, j;
+  int w, h;
+  char ind[255];
+  char *str;
+
+  str = (char *) malloc (strlen (inputstr) * sizeof (char) + 2);
+
+  bl_string_to_array (inputstr, str, &w, &h);
+
+  EncodeGammaDist (surr);
+  EncodeGammaDist (w);
+  EncodeGammaDist (h);
+  ind['.'] = 0;
+  ind['p'] = 1;
+  ind['2'] = 2;
+  ind['*'] = 3;
+  for (j = 0; j < h; j++)
+    for (i = 0; i < w; i++)
+      EncodeGammaDist (ind[(int) str[j * w + i]]);
+
+  free (str);
+}
+
+
+void 
+bl_readtemplate ()
+{
+  register int i, j;
+  int w, h, p;
+  char ind[4];
+  char *inputstr, *str;
+
+  surr = DecodeGammaDist (surr);
+  if (surr)
+    {
+      fprintf (stderr, "It's fine compressing an image using a 'surrounding' template, but I can't "
+	       "decompress it!\n");
+      exit (1);
+    }
+  w = DecodeGammaDist ();
+  h = DecodeGammaDist ();
+
+  inputstr = (char *) malloc ((w + 2) * h * sizeof (char) + 2);
+  ind[0] = '.';
+  ind[1] = 'p';
+  ind[2] = '2';
+  ind[3] = '*';
+  for (p = 0, j = 0; j < h; j++)
+    {
+      for (i = 0; i < w; i++)
+	{
+	  inputstr[p++] = ind[DecodeGammaDist ()];
+	}
+      inputstr[p++] = ';';
+      inputstr[p] = 0;
+    }
+
+  str = (char *) malloc (strlen (inputstr) * sizeof (char) + 2);
+  bl_string_to_array (inputstr, str, &w, &h);
+}
+
+
+
+
+
+/* Currently if there are more than 32 bits, the topmost 32 will be discarded, if the 
+   topbits are to be used in compression, define _MORETHAN32 */
+#undef _MORETHAN32
+
+void 
+bl_compress_mark (marktype d)
+{
+  register int r, c;
+  register int i, j;
+  register unsigned long mask, mask2level;
+  char *array[MAX_T_W];
+
+
+  for (i = 0; i < MAX_T_W; i++)
+    {
+      array[i] = (char *) calloc ((size_t) d.w + 2 * MAX_T_W + 1, (size_t) sizeof (char));
+      array[i] = array[i] + MAX_T_W;
+    }
+
+  EncodeGammaDist (d.w);
+  EncodeGammaDist (d.h);
+
+  for (r = 0; r < min (curr_row, d.h); r++)
+    for (c = 0; c < d.w; c++)
+      array[r % MAX_T_W][c] = pbm_getpixel (d.bitmap, c, r);
+
+  for (r = 0; r < d.h; r++)
+    {
+      if (V)
+	if (r && (r % 200 == 0))
+	  fprintf (stderr, ".");
+
+      if (r + curr_row < d.h)
+	for (c = 0; c < d.w; c++)
+	  array[(r + curr_row) % MAX_T_W][c] = pbm_getpixel (d.bitmap, c, r + curr_row);
+      else
+	for (c = 0; c < d.w; c++)
+	  array[(r + curr_row) % MAX_T_W][c] = 0;
+
+      for (c = 0; c < d.w; c++)
+	{
+	  for (mask = 0, mask2level = 0, i = 0; i < MMrows; i++)
+	    {
+	      if (c != 0)
+		{
+		  MMmask[i] = (MMmask[i] * 2);
+		  MMmask[i] |= array[(r + MM[i][0].y + MAX_T_W) % MAX_T_W][c + MM[i][0].x];
+		}
+	      else
+		{
+		  for (MMmask[i] = 0, j = MMcount[i] - 1; j >= 0; j--)
+		    MMmask[i] = 2 * MMmask[i] | array[(r + MM[i][j].y + MAX_T_W) % MAX_T_W][c + MM[i][j].x];
+		}
+	      MMmask[i] &= MMbits[i];
+#ifdef _MORETHAN32
+	      mask = ((mask * 8191) << MMcount[i]) | MMmask[i];
+	      mask2level = ((mask2level * 499) << MMcount[i]) | (MMmask[i] & MM2level[i]);
+#else
+	      mask = (mask << MMcount[i]) | MMmask[i];
+	      mask2level = (mask2level << MMcount[i]) | (MMmask[i] & MM2level[i]);
+#endif
+	    }
+
+	  mask = HASH (mask);
+	  mask2level = HASH (mask2level);
+
+	  bl_encode_in_context (mask, mask2level, pbm_getpixel (d.bitmap, c, r));
+	}
+    }
+  for (i = 0; i < MAX_T_W; i++)
+    free (array[i] - MAX_T_W);
+}
+
+
+
+void 
+bl_decompress_mark (marktype * d)
+{
+  register int r, c;
+  register int i, j;
+  unsigned long pix;
+  register unsigned long mask, mask2level;
+  char *array[MAX_T_W];
+
+
+  d->w = DecodeGammaDist ();
+  d->h = DecodeGammaDist ();
+
+  d->bitmap = pbm_allocarray (d->w, d->h);
+  for (i = 0; i < MAX_T_W; i++)
+    {
+      array[i] = (char *) calloc ((size_t) d->w + 2 * MAX_T_W + 1, (size_t) sizeof (char));
+      array[i] = array[i] + MAX_T_W;
+    }
+
+  for (r = 0; r < d->h; r++)
+    {
+      if (V)
+	if (r && (r % 200 == 0))
+	  fprintf (stderr, ".");
+      for (c = 0; c < d->w; c++)
+	array[r % MAX_T_W][c] = pbm_getpixel (d->bitmap, c, r);
+      for (c = 0; c < d->w; c++)
+	{
+	  for (mask = 0, mask2level = 0, i = 0; i < MMrows; i++)
+	    {
+	      if (c != 0)
+		{
+		  MMmask[i] = (MMmask[i] * 2);
+		  MMmask[i] |= array[(r + MM[i][0].y + MAX_T_W) % MAX_T_W][c + MM[i][0].x];
+		}
+	      else
+		{
+		  for (MMmask[i] = 0, j = MMcount[i] - 1; j >= 0; j--)	/* get all pixels */
+		    MMmask[i] = 2 * MMmask[i] | array[(r + MM[i][j].y + MAX_T_W) % MAX_T_W][c + MM[i][j].x];
+		}
+	      MMmask[i] &= MMbits[i];
+
+#ifdef _MORETHAN32
+	      mask = ((mask * 8191) << MMcount[i]) | MMmask[i];
+	      mask2level = ((mask2level * 499) << MMcount[i]) | (MMmask[i] & MM2level[i]);
+#else
+	      mask = (mask << MMcount[i]) | MMmask[i];
+	      mask2level = (mask2level << MMcount[i]) | (MMmask[i] & MM2level[i]);
+#endif
+	    }
+
+	  mask = HASH (mask);
+	  mask2level = HASH (mask2level);
+
+	  bl_decode_in_context (mask, mask2level, &pix);
+	  if (pix)
+	    {
+	      pbm_putpixel (d->bitmap, c, r, pix);
+	      array[r % MAX_T_W][c] = pix;
+	    }
+	}
+    }
+  for (i = 0; i < MAX_T_W; i++)
+    free (array[i] - MAX_T_W);
+}
+
+
+
+void 
+bl_compress (marktype d, char inputstr[])
+{
+  bl_clearmodel ();
+  bl_writetemplate (inputstr);
+  bl_compress_mark (d);
+  bl_freemodel ();
+}
+
+
+void 
+bl_decompress (marktype * d)
+{
+  bl_clearmodel ();
+  bl_readtemplate ();
+  bl_decompress_mark (d);
+  bl_freemodel ();
+}
+
+
+
+
+
+
+/* 
+   The bitmap in d2, can be examined clairvoyantly.  The ordering of the
+   params is therefore non-clairvoyant, and clairvoyant in that order.
+
+ */
+/*
+   coordinate M1[6]={        { 0,-2},
+   {-1,-1},{ 0,-1}, {1,-1},
+   {-2,0},  {-1, 0}};
+   };
+   coordinate M2[13]={       { 0,-2},
+   {-1,-1}, { 0,-1},   {1, -1},
+   {-2,0}, {-1, 0}, { 0, 0},   { 1, 0},  {2,0},
+   {-1, 1}, { 0, 1},   { 1, 1},
+   { 0, 2}
+ */
+
+coordinate M1[6] =
+{
+  {0, -2},
+  {-2, 0},
+  {1, -1},
+  {-1, -1},
+  {0, -1},
+  {-1, 0}};
+coordinate M2[13] =
+{
+  {0, -2},
+  {1, -1},
+  {-2, 0},
+  {2, 0},
+  {-1, 1},
+  {1, 1},
+  {0, 2},
+  {-1, -1},
+  {0, -1},
+  {1, 0},
+  {-1, 0},
+  {0, 1},
+  {0, 0}
+};
+#define M1S 6
+#define M1S_2level 3
+#define M2S 13
+#define M2S_2level 6
+
+
+void 
+bl_clair_compress (marktype d1, marktype d2)
+{
+  register int r, c;
+  register int i, j, n;
+  register unsigned long mask, mask2level = 0;
+  int cols, rows;
+  int gap;
+  Pixel **b1, **b2;
+
+
+  bl_clearmodel ();
+  twolevel = 1;
+
+  b1 = d1.bitmap;
+  b2 = d2.bitmap;
+  cols = d1.w;
+  rows = d1.h;
+
+  gap = max (50, rows / 10);
+
+  EncodeGammaDist (cols);
+  EncodeGammaDist (rows);
+
+  for (r = 0; r < rows; r++)
+    {
+      if (V)
+	if (!(r % gap))
+	  fprintf (stderr, ".");
+      for (c = 0; c < cols; c++)
+	{
+
+	  mask = 0;
+	  for (n = 0; n < M1S; n++)
+	    {
+	      i = c + M1[n].x;
+	      j = r + M1[n].y;
+	      mask = (2 * mask) | pbm_getpixel_trunc (b1, i, j, cols, rows);
+	    }
+
+	  mask2level = mask & ((1 << M1S_2level) - 1);
+
+	  for (n = 0; n < M2S; n++)
+	    {
+	      i = c + M2[n].x;
+	      j = r + M2[n].y;
+	      mask = (2 * mask) | pbm_getpixel_trunc (b2, i, j, cols, rows);
+	    }
+
+	  mask2level = (mask2level << M2S_2level) | (mask & ((1 << M2S_2level) - 1));
+
+	  bl_encode_in_context (mask, mask2level, pbm_getpixel (b1, c, r));
+
+	}
+    }
+  if (V)
+    fprintf (stderr, "\n");
+  bl_freemodel ();
+}
+
+
+void 
+bl_clair_decompress (marktype d1, marktype d2)
+{
+  register int r, c;
+  register int i, j, n;
+  register unsigned long mask, mask2level = 0;
+  unsigned long p;
+  int cols, rows;
+  int gap;
+  Pixel **b1, **b2;
+
+  bl_clearmodel ();
+  twolevel = 1;
+
+  b1 = d1.bitmap;
+  b2 = d2.bitmap;
+  cols = d1.w;
+  rows = d1.h;
+
+  gap = max (50, rows / 10);
+
+  i = DecodeGammaDist ();
+  j = DecodeGammaDist ();
+  if ((i != cols) || (j != rows))
+    error_msg ("bl_clair_decompress", "incorrect size of residue image", "");
+
+  if (V)
+    fprintf (stderr, "cols=%d rows=%d\n", cols, rows);
+
+  for (r = 0; r < rows; r++)
+    {
+      if (V)
+	if (!(r % gap))
+	  fprintf (stderr, ".");
+      for (c = 0; c < cols; c++)
+	{
+	  mask = 0;
+	  for (n = 0; n < M1S; n++)
+	    {
+	      i = c + M1[n].x;
+	      j = r + M1[n].y;
+	      mask = (2 * mask) | pbm_getpixel_trunc (b1, i, j, cols, rows);
+	    }
+	  mask2level = mask & ((1 << M1S_2level) - 1);
+	  for (n = 0; n < M2S; n++)
+	    {
+	      i = c + M2[n].x;
+	      j = r + M2[n].y;
+	      mask = (2 * mask) | pbm_getpixel_trunc (b2, i, j, cols, rows);
+	    }
+	  mask2level = (mask2level << M2S_2level) | (mask & ((1 << M2S_2level) - 1));
+
+
+	  bl_decode_in_context (mask, mask2level, &p);
+	  if (p)
+	    pbm_putpixel (b1, c, r, 1);
+	}
+    }
+  if (V)
+    fprintf (stderr, "\n");
+  bl_freemodel ();
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/bilevel.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/bilevel.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/bilevel.h	(revision 10506)
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * bilevel.h -- Compress a bilevel bitmap
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __BILEVEL_H
+#define __BILEVEL_H
+
+#include "marklist.h"
+
+/* must be called before the start of de/compression */
+void bl_clearmodel ();
+void bl_freemodel ();
+
+/* writes the template to the stream, and sets up the de/compression params */
+void bl_writetemplate (char inputstr[]);
+void bl_readtemplate ();
+
+/* actually performs the de/compression */
+void bl_compress (marktype d, char str[]);
+void bl_compress_mark (marktype d);
+void bl_decompress (marktype * d);
+void bl_decompress_mark (marktype * d);
+
+/* clairvoyantly de/compress d1 with respect to clairvoyantly viewable d2 */
+void bl_clair_compress (marktype d1, marktype d2);
+void bl_clair_decompress (marktype d1, marktype d2);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codeoffsets.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codeoffsets.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codeoffsets.c	(revision 10506)
@@ -0,0 +1,257 @@
+/**************************************************************************
+ *
+ * codeoffsets.c -- Functions which code the mark offsets
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "arithcode.h"
+#include "utils.h"
+
+#define TOP_INC 2
+#define MID_INC 1
+#define BOT_INC 1
+
+
+void 
+EncodeOffsets (marklistptr symbol_list, int nsyms)
+{
+  int xpos = 1, xneg = 1, ypos = 1, yneg = 1;
+  marklistptr step;
+  int found;
+  int dox = 0, leveltop = 1, levelmid = 1, levelbot = 1;
+  elemlist xlist, ylist;	/* all previous offsets */
+  int p, f, t, xoff, yoff, symnum, count;
+  elemlist *xcond, *ycond;	/* previous offsets conditioned on symbol num */
+
+  xcond = (elemlist *) malloc (nsyms * sizeof (elemlist));
+  if (!xcond)
+    error_msg ("EncodeOffsets", "Out of memory...", "");
+  ycond = (elemlist *) malloc (nsyms * sizeof (elemlist));
+  if (!ycond)
+    error_msg ("EncodeOffsets", "Out of memory...", "");
+
+  for (t = 0; t < nsyms; t++)
+    {
+      xcond[t].head = ycond[t].head = NULL;
+      xcond[t].tot = ycond[t].tot = 0;
+    }
+  xlist.head = NULL;
+  xlist.tot = 0;
+  ylist.head = NULL;
+  ylist.tot = 0;
+  for (step = symbol_list, count = 0; step; step = step->next, count++)
+    {
+      xoff = step->data.xoffset;
+      yoff = step->data.yoffset;
+      symnum = step->data.symnum;
+      for (dox = 1; dox >= 0; dox--)
+	{
+	  /* encode the offsets, x first then y */
+
+	  if (dox)
+	    found = elem_find (&xcond[symnum], xoff, &p, &f, &t);
+	  else
+	    found = elem_find (&ycond[symnum], yoff, &p, &f, &t);
+
+	  if (found)
+	    {
+	      arithmetic_encode (0, leveltop, leveltop + levelmid + levelbot);
+	      leveltop += TOP_INC;
+	      arithmetic_encode (p, f, t);
+	    }
+	  else
+	    {
+	      if (dox)
+		found = elem_find (&xlist, xoff, &p, &f, &t);
+	      else
+		found = elem_find (&ylist, yoff, &p, &f, &t);
+
+	      if (found)
+		{
+		  arithmetic_encode (leveltop, leveltop + levelmid, leveltop + levelmid + levelbot);
+		  levelmid += MID_INC;
+		  arithmetic_encode (p, f, t);
+		}
+	      else
+		{
+		  arithmetic_encode (leveltop + levelmid, leveltop + levelmid + levelbot, leveltop + levelmid + levelbot);
+		  levelbot += BOT_INC;
+		  if (dox)
+		    EncodeGammaSigned (xoff, &xpos, &xneg);
+		  else
+		    EncodeGammaSigned (yoff, &ypos, &yneg);
+		}
+	    }
+	  if (dox)
+	    {
+	      elem_add (&xlist, xoff);
+	      elem_add (&xcond[symnum], xoff);
+	    }
+	  else
+	    {
+	      elem_add (&ylist, yoff);
+	      elem_add (&ycond[symnum], yoff);
+	    }
+
+	  if (leveltop + levelmid >= maxfrequency)
+	    {
+	      leveltop = (leveltop + 1) / 2;
+	      levelmid = (levelmid + 1) / 2;
+	      levelbot = (levelbot + 1) / 2;
+	    }
+	}
+    }
+  for (t = 0; t < nsyms; t++)
+    {
+      elem_free (&xcond[t]);
+      elem_free (&ycond[t]);
+    }
+  elem_free (&xlist);
+  elem_free (&ylist);
+  if (V)
+    fprintf (stderr, "offset models: top %d, mid %d, bot %d\n", (leveltop - 1) / TOP_INC, (levelmid - 1) / MID_INC, (levelbot - 1) / BOT_INC);
+}
+
+
+
+
+
+void 
+DecodeOffsets (marklistptr symbol_list, int nsyms)
+{
+  int xpos = 1, xneg = 1, ypos = 1, yneg = 1;
+  marklistptr step;
+  int i, target, dox;
+  int leveltop = 1, levelmid = 1, levelbot = 1;
+  elemlist xlist, ylist;
+  int p, f, t, xoff = 0, yoff = 0, symnum, count = 0;
+  elemlist *xcond, *ycond;
+
+  xcond = (elemlist *) malloc (nsyms * sizeof (elemlist));
+  if (!xcond)
+    error_msg ("EncodeOffsets", "Out of memory...", "");
+  ycond = (elemlist *) malloc (nsyms * sizeof (elemlist));
+  if (!ycond)
+    error_msg ("EncodeOffsets", "Out of memory...", "");
+
+  for (i = 0; i < nsyms; i++)
+    {
+      xcond[i].head = ycond[i].head = NULL;
+      xcond[i].tot = ycond[i].tot = 0;
+    }
+
+  xlist.head = NULL;
+  xlist.tot = 0;
+  ylist.head = NULL;
+  ylist.tot = 0;
+
+  for (step = symbol_list, count = 0; step; step = step->next, count++)
+    {
+      symnum = step->data.symnum;
+      for (dox = 1; dox >= 0; dox--)
+	{
+	  /* decode x offset first, then y */
+	  target = arithmetic_decode_target (leveltop + levelmid + levelbot);
+	  if (target < leveltop)
+	    {
+	      arithmetic_decode (0, leveltop, leveltop + levelmid + levelbot);
+	      leveltop += TOP_INC;
+
+	      if (dox)
+		i = arithmetic_decode_target (xcond[symnum].tot);
+	      else
+		i = arithmetic_decode_target (ycond[symnum].tot);
+
+	      if (dox)
+		{
+		  elem_getrange (&xcond[symnum], i, &xoff);
+		  elem_find (&xcond[symnum], xoff, &p, &f, &t);
+		}
+	      else
+		{
+		  elem_getrange (&ycond[symnum], i, &yoff);
+		  elem_find (&ycond[symnum], yoff, &p, &f, &t);
+		}
+	      arithmetic_decode (p, f, t);
+	    }
+	  else if (target < leveltop + levelmid)
+	    {
+	      arithmetic_decode (leveltop, leveltop + levelmid, leveltop + levelmid + levelbot);
+	      levelmid += MID_INC;
+
+	      if (dox)
+		i = arithmetic_decode_target (xlist.tot);
+	      else
+		i = arithmetic_decode_target (ylist.tot);
+
+	      if (dox)
+		{
+		  elem_getrange (&xlist, i, &xoff);
+		  elem_find (&xlist, xoff, &p, &f, &t);
+		}
+	      else
+		{
+		  elem_getrange (&ylist, i, &yoff);
+		  elem_find (&ylist, yoff, &p, &f, &t);
+		}
+	      arithmetic_decode (p, f, t);
+	    }
+	  else
+	    {
+	      arithmetic_decode (leveltop + levelmid, leveltop + levelmid + levelbot, leveltop + levelmid + levelbot);
+	      levelbot += BOT_INC;
+	      if (dox)
+		xoff = DecodeGammaSigned (&xpos, &xneg);
+	      else
+		yoff = DecodeGammaSigned (&ypos, &yneg);
+	    }
+
+	  if (dox)
+	    {
+	      step->data.xoffset = xoff;
+	      elem_add (&xlist, xoff);
+	      elem_add (&xcond[symnum], xoff);
+	    }
+	  else
+	    {
+	      step->data.yoffset = yoff;
+	      elem_add (&ylist, yoff);
+	      elem_add (&ycond[symnum], yoff);
+	    }
+
+	  if (leveltop + levelmid >= maxfrequency)
+	    {
+	      leveltop = (leveltop + 1) / 2;
+	      levelmid = (levelmid + 1) / 2;
+	      levelbot = (levelbot + 1) / 2;
+	    }
+	}
+    }
+  for (t = 0; t < nsyms; t++)
+    {
+      elem_free (&xcond[t]);
+      elem_free (&ycond[t]);
+    }
+  elem_free (&xlist);
+  elem_free (&ylist);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codeoffsets.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codeoffsets.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codeoffsets.h	(revision 10506)
@@ -0,0 +1,32 @@
+/**************************************************************************
+ *
+ * codeoffsets.h -- Functions which code the mark offsets
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __CODEOFFSETS_H
+#define __CODEOFFSETS_H
+
+#include "marklist.h"
+
+void EncodeOffsets (marklistptr MarkList, int num_symbols);
+void DecodeOffsets (marklistptr MarkList, int num_symbols);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codesyms.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codesyms.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codesyms.c	(revision 10506)
@@ -0,0 +1,96 @@
+/**************************************************************************
+ *
+ * codesyms.c -- Functions which code the symbol sequence
+ * Copyright (C) 1994  Hugh Emberson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "arithcode.h"
+#include "marklist.h"
+#include "pbmtools.h"
+#include "utils.h"
+#include "codesyms.h"
+
+int charsetsize = 256;
+
+void 
+EncodeSymbols (marklistptr MarkList, int NSyms)
+{
+  marklistptr step;
+  unsigned short Events[PPM_CHUNK];
+  int j = 0;
+
+  charsetsize = max (NSyms, 256);
+
+  step = MarkList;
+  while (step)
+    {
+      Events[j] = step->data.symnum;
+
+      assert (Events[j] > 0 || Events[j] < (unsigned) NSyms);
+
+      j++;
+
+      if (j == PPM_CHUNK)
+	{
+	  encodestring (Events, PPM_CHUNK);
+	  j = 0;
+	}
+      step = step->next;
+    };
+
+  if (j != 0)
+    encodestring (Events, j);
+
+  encodestring (Events, 0);
+}
+
+
+marklistptr 
+DecodeSymbols (int NSyms)
+{
+  marklistptr MarkList = NULL;
+  unsigned short Events[PPM_CHUNK];
+  int j, n;
+  marktype d;
+
+  charsetsize = max (NSyms, 256);
+
+  do
+    {
+      decodestring (Events, &n);
+
+      for (j = 0; j < n; j++)
+	{
+	  d.symnum = Events[j];
+	  marklist_add (&MarkList, d);
+	}
+    }
+  while (n != 0);
+
+  return MarkList;
+}
+
+void 
+InitPPM (void)
+{
+  kbytes = 896;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codesyms.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codesyms.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/codesyms.h	(revision 10506)
@@ -0,0 +1,44 @@
+/**************************************************************************
+ *
+ * codesyms.h -- Functions which code the symbol sequence
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+#ifndef _CodeSymbols_h_
+#define _CodeSymbols_h_
+
+#include "marklist.h"
+#include "arithcode.h"
+
+#ifndef FIXEDORDER
+#define FIXEDORDER	3
+#endif
+
+#define PPM_CHUNK	1024
+
+extern int kbytes;
+extern void decodestring ();
+extern void encodestring ();
+
+void EncodeSymbols (marklistptr MarkList, int NSyms);
+marklistptr DecodeSymbols (int NSyms);
+
+void InitPPM (void);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/extractor.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/extractor.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/extractor.c	(revision 10506)
@@ -0,0 +1,423 @@
+/**************************************************************************
+ *
+ * extractor.c -- Functions related to extracting marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "extractor.h"
+#include "pbmtools.h"
+#include "marklist.h"
+#include "utils.h"
+
+
+/* 
+   'splitjoined' defines whether the extractor modules tries to break
+   "seemingly" merged/joined marks.
+ */
+int splitjoined = 1;
+
+#define MAX_FILL_STACK_SIZE 10000
+
+/* RunRegionFill uses line conherence to implement a better fill
+   routine.  The stack has currently got 10000 elements, although the
+   biggest I have encountered used a maximum stack size of 1294.  usage:
+   RunRegionFill(bitmap,mark,i,j,xpos,ypos); xpos and ypos are the top
+   left corners of the mark.  */
+
+int maxst = 0, st = 0;
+struct
+  {
+    int x, y;
+  }
+a[MAX_FILL_STACK_SIZE];
+
+#define push(i,j) a[st].x=i;a[st].y=j;st++;if(st>MAX_FILL_STACK_SIZE){error_msg ("extractor/flood_fill","woooo! Fill stack overflow!","");}
+#define pop(i,j) st--;i=a[st].x;j=a[st].y
+
+void 
+RunRegionFill (Pixel ** bitmap, marktype * mark, int i, int j, int xl, int yt, int cols, int rows)
+{
+  int l, r, t, start_up, start_down;
+
+  push (i, j);
+  while (st > 0)
+    {
+      if (st > maxst)
+	maxst = st;
+
+      pop (l, j);
+      r = l;
+
+      while (pbm_getpixel (bitmap, l - 1, j))
+	l--;
+      while (pbm_getpixel (bitmap, r + 1, j))
+	r++;
+      start_up = start_down = 1;
+      for (t = min (r + 1, cols - 1); t >= max (l - 1, 0); t--)
+	{
+	  if ((t >= l) && (t <= r))
+	    {
+	      pbm_putpixel (bitmap, t, j, 0);
+
+	      if (mark)
+		pbm_putpixel (mark->bitmap, t - xl, j - yt, 1);
+	    }
+
+	  if ((j - 1 >= 0) && (pbm_getpixel (bitmap, t, j - 1)))
+	    {
+	      if (start_up)
+		{
+		  push (t, j - 1);
+		  start_up = 0;
+		}
+	    }
+	  else
+	    start_up = 1;
+	  if ((j + 1 < rows) && (pbm_getpixel (bitmap, t, j + 1)))
+	    {
+	      if (start_down)
+		{
+		  push (t, j + 1);
+		  start_down = 0;
+		}
+	    }
+	  else
+	    start_down = 1;
+	}
+    }
+}
+
+
+
+
+/*
+
+   ExtractNextMark starts at (tx,ty) and looks for a set (==1) pixel.
+   The mark is then boundary traced to give an outline {The process is a
+   4-pixel exterior check -- giving 8 way connectivity}, and then
+   RunRegionFill is used to remove the mark and set the pixels in the
+   mark.
+
+   usage: ExtractNextMark(bitmap,&marklist,&startx,&starty,int cols,int rows);
+   Defines:
+   gp - gets a pixel, but returns 0 for outside regions.
+   boundary_{x,y}comp - returns the {x,y} component of the direction.
+   dir 0=right, 1=down, 2=left, 3=up.
+ */
+
+#define gp(i,j) ( (((i)<0)||((j)<0)||((i)>=cols)||((j)>=rows))? 0 : pbm_getpixel(bitmap,(i),(j)))
+
+#define boundary_xcomp(x) (x==0?1:(x==2?-1 : 0))
+#define boundary_ycomp(x) (x==1?1:(x==3?-1 : 0))
+
+int 
+ExtractNextMark (Pixel ** bitmap, marklistptr * marklist, int *tx, int *ty, int cols, int rows)
+{
+  int i, j, xl, xr, yt, yb;
+  register int dir, tempdir;
+  marktype d;
+
+  xl = INT_MAX;
+  xr = (-1);
+  yt = INT_MAX;
+  yb = (-1);
+
+  i = *tx;
+  j = *ty;
+  if ((i < 0) || (j < 0))
+    error_msg ("ExtractNextMark()", "Stupid values for x,y in findnextmark()", "");
+  while (!pbm_getpixel (bitmap, i, j))
+    {
+      i++;
+      if (i >= cols)
+	{
+	  i = 0;
+	  j++;
+	  if (j >= rows)
+	    return 0;
+	}
+    }
+
+  *tx = i;
+  *ty = j;
+  dir = 0;
+  j = j - 1;			/* start above */
+  do
+    {
+      if (i > xr)
+	xr = i - 1;
+      if (i < xl)
+	xl = i + 1;
+      if (j < yt)
+	yt = j + 1;
+      if (j > yb)
+	yb = j - 1;
+      tempdir = (dir + 1) % 4;
+      if (gp (i + boundary_xcomp (tempdir), j + boundary_ycomp (tempdir)) == 0)
+	dir = tempdir;
+      else
+	{
+	  tempdir = dir;
+	  if (gp (i + boundary_xcomp (tempdir), j + boundary_ycomp (tempdir)) == 0)
+	    dir = tempdir;
+	  else
+	    {
+	      tempdir = (dir + 3) % 4;
+	      if (gp (i + boundary_xcomp (tempdir), j + boundary_ycomp (tempdir)) == 0)
+		dir = tempdir;
+	      else
+		dir = (dir + 2) % 4;
+	    }
+	}
+      i += boundary_xcomp (dir);
+      j += boundary_ycomp (dir);
+    }
+  while ((i != (*tx)) || (j != (*ty - 1)));
+
+  d.w = (xr - xl + 1);
+  d.h = (yb - yt + 1);
+  d.xpos = xl;
+  d.ypos = yt;
+  d.bitmap = pbm_allocarray (d.w, d.h);
+
+  RunRegionFill (bitmap, &d, *tx, *ty, xl, yt, cols, rows);
+
+  marktype_calc_features (&d, "?");
+  marklist_add (marklist, d);
+
+  *tx = *tx + 1;
+  return 1;
+}
+
+
+
+
+static void 
+normalise (float *p, int w)
+{
+  int x;
+  float mx;
+
+  mx = p[0];
+  for (x = 0; x < w; x++)
+    if (p[x] > mx)
+      mx = p[x];
+  if (mx != 0)
+    {
+      for (x = 0; x < w; x++)
+	p[x] = p[x] / mx;
+    }
+}
+
+
+
+#define MAXPROFILE 1000
+float profile[MAXPROFILE], p2[MAXPROFILE];
+
+
+static int 
+possibly_joined (marktype * d)
+{
+  float aspect;
+  int i, n, x, y;
+  int leftable, l2;
+
+
+  aspect = d->w / (float) d->h;
+
+  if ((aspect >= 1.1) || (d->w < MAXPROFILE))
+    {
+      /* examine it more closely */
+
+
+      /* set up profile[] with a vertical profile */
+      for (x = 0; x < d->w; x++)
+	{
+	  profile[x] = 0;
+	  for (y = 0; y < d->h; y++)
+	    if (pbm_getpixel (d->bitmap, x, y))
+	      profile[x]++;
+	}
+
+      /* average the profile from (up to) 3 either way */
+      for (x = 0; x < d->w; x++)
+	{
+	  n = 0;
+	  p2[x] = 0;
+	  for (i = x - 3; i <= x + 3; i++)
+	    if ((i >= 0) && (i < d->w))
+	      {
+		n++;
+		p2[x] += profile[x];
+	      }
+	  p2[x] = p2[x] / (float) n;
+	}
+      for (x = 0; x < d->w; x++)
+	profile[x] = p2[x];
+
+      /* normalise profile[] */
+      normalise (profile, d->w);
+
+      /* find a little local minimum, with profile <0.25, make p2[] either 0 or 1 */
+      for (x = 0; x < d->w; x++)
+	p2[x] = 0;
+      for (x = 3; x < d->w - 3; x++)
+	{
+	  if (((profile[x - 2] - profile[x]) > 0.00) &&
+	      ((profile[x + 2] - profile[x]) > 0.00) &&
+	      (profile[x] < .25))
+	    p2[x] = 1;
+	}
+
+      /* travel rightwards, checking aspect ratio, looking at p2 now */
+      leftable = l2 = 0;
+      for (x = 0; x < d->w; x++)
+	if (p2[x] == 1)
+	  {
+	    if ((fabs ((abs (x - leftable) / (float) d->h) - 0.7) > 0.3) &&
+		(fabs ((abs (x - l2) / (float) d->h) - 0.7) > 0.3))
+	      p2[x] = 0;
+	    if (p2[x] == 1)
+	      {
+		leftable = l2;
+		l2 = x;
+	      }
+	  }
+
+      /* travel inwards, checking widths of chars, looking at p2 */
+      /* if a char has an aspect ratio of <= ? kill it */
+      l2 = 0;
+      leftable = d->w - 1;
+      x = 0;
+      y = d->w - 1;
+      while (x <= y)
+	{
+	  if (p2[x])
+	    {
+	      if (abs (x - l2) < max (d->h * 0.6, 5))
+		p2[x] = 0;
+	      if (p2[x])
+		l2 = x;
+	    }
+	  if (p2[y])
+	    {
+	      if (abs (y - leftable) < max (d->h * 0.6, 5))
+		p2[y] = 0;
+	      if (p2[y])
+		leftable = y;
+	    }
+	  x++;
+	  y--;
+	}
+
+
+      for (x = 0; x < d->w; x++)
+	if (p2[x])
+	  return 1;
+    }
+  return 0;
+}
+
+
+static void 
+split_mark (marklistptr * list, marktype * joinedmark)
+{
+  marktype new, old;
+  int x, found = 0, left = 0;
+  int i, j;
+  int oldw, oldh;
+  int overwrite = 1;
+
+  old = marktype_copy (*joinedmark);
+  oldw = joinedmark->w;
+  oldh = joinedmark->h;
+  for (x = 0; x < old.w; x++)
+    if (p2[x])
+      {
+	found = x;
+	break;
+      }
+  do
+    {
+      /* split at (found) position */
+      new.w = found + 1 - left;
+      new.h = old.h;
+      new.xpos = old.xpos + left;
+      new.ypos = old.ypos;
+      new.bitmap = pbm_allocarray (new.w, new.h);
+
+      for (i = 0; i < new.w; i++)
+	for (j = 0; j < new.h; j++)
+	  pbm_putpixel (new.bitmap, i, j, pbm_getpixel (old.bitmap, left + i, j));
+
+      marktype_adj_bound (&new);
+
+      if (overwrite)
+	{
+	  overwrite = 0;
+	  pbm_freearray (&(joinedmark->bitmap), oldh);
+	  *joinedmark = new;
+	}
+      else
+	marklist_add (list, new);
+
+
+      p2[found] = 0;
+      left = found;
+      found = 0;
+      for (x = left; x < old.w; x++)
+	if (p2[x])
+	  {
+	    found = x;
+	    break;
+	  }
+      if (left == old.w - 1)
+	break;			/* if we've got to the right */
+      if (found == 0)
+	found = old.w - 1;
+    }
+  while (found);
+  pbm_freearray (&(old.bitmap), oldh);
+}
+
+
+
+
+
+void 
+ExtractAllMarks (Pixel ** bitmap, marklistptr * list, int cols, int rows)
+{
+  int startx, starty, count;
+  marklistptr step;
+
+  startx = starty = 0;
+  while (ExtractNextMark (bitmap, list, &startx, &starty, cols, rows))
+    ;
+
+  if (splitjoined)
+    for (step = (*list), count = 0; step; step = step->next, count++)
+      if (possibly_joined (&(step->data)))
+	split_mark (list, &(step->data));
+
+  for (step = (*list), count = 0; step; step = step->next, count++)
+    step->data.symnum = count;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/extractor.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/extractor.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/extractor.h	(revision 10506)
@@ -0,0 +1,38 @@
+/**************************************************************************
+ *
+ * extractor.h -- Functions related to extracting marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef _EXTRACTOR_H_
+#define _EXTRACTOR_H_
+
+#include "marklist.h"
+#include "pbmtools.h"
+
+extern int splitjoined;
+
+void RunRegionFill (Pixel ** bitmap, marktype * mark, int i, int j, int xl, int yt, int cols, int rows);
+
+int ExtractNextMark (Pixel ** bitmap, marklistptr * marklist, int *tx, int *ty, int cols, int rows);
+void ExtractAllMarks (Pixel ** bitmap, marklistptr * marklist, int cols, int rows);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/felics.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/felics.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/felics.c	(revision 10506)
@@ -0,0 +1,340 @@
+/**************************************************************************
+ *
+ * felics.c -- The main guts of the felics algorithm
+ * Copyright (C) 1994  Neil Sharman and Kerry Guise
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+
+
+#undef putw
+#define putw(x)	{					\
+	short z;					\
+	byteptr = (unsigned char *)(x);			\
+	for (z = 0; z < sizeof(int); z++)		\
+		(void) putc((int) byteptr[z], fp_out);	\
+}
+#define INTSIZE sizeof(int) * 8
+#define BOOLEAN short
+#define TRUE 1
+#define FALSE 0
+
+#define IN_RANGE 0
+#define OUT_OF_RANGE 1
+#define BELOW_RANGE 0
+#define ABOVE_RANGE 1
+
+
+void 
+encode (unsigned int *line, int width, int height, int maxval, int maxk,
+	FILE * fp_in, FILE * fp_out, int (*get) (FILE *))
+{
+  int x, y;
+  unsigned long P, L, H, N1, N2, delta;
+  unsigned long cumul_param[256][INTSIZE];
+  unsigned max_cumul;
+
+  memset (cumul_param, '0', sizeof (cumul_param));
+
+  if (maxk)
+    max_cumul = maxk;
+  else
+    CEILLOG_2 (maxval, max_cumul);
+
+  ENCODE_START (fp_out)
+
+    for (y = 0; y < height; y++)
+    for (x = 0; x < width; x++)
+      {
+	if (y > 0)
+	  {
+	    if (x > 0)
+	      {			/* ******** */
+		N1 = line[x];	/* ****1*** */
+		N2 = line[x - 1];	/* ***2P*** */
+	      }			/* ******** */
+	    else
+	      {			/* |******* */
+		N1 = line[x];	/* |12***** */
+		N2 = line[x + 1];	/* |P***** */
+	      }			/* |******* */
+	  }
+	else
+	  {
+	    if (x > 1)
+	      {
+		N1 = line[x - 1];	/* -------- */
+		N2 = line[x - 2];	/* **12P*** */
+	      }			/* ******** */
+	    else if (x > 0)
+	      {
+		N1 = line[x - 1];	/* +------- */
+		N2 = N1;	/* |3P***** */
+	      }			/* |******* */
+	    else
+	      {
+		line[x] = get (fp_in);	/* +------- */
+		BINARY_ENCODE (line[x] + 1, maxval + 1);	/* |P****** */
+		continue;	/* |******* */
+	      }
+	  }
+
+
+	H = N1 > N2 ? N1 : N2;
+	L = N1 < N2 ? N1 : N2;
+	delta = H - L;
+
+	line[x] = P = get (fp_in);
+
+	if ((L <= P) && (P <= H))
+	  {
+	    /* IN-RANGE */
+	    unsigned long range, logofrange, thresh, numlong;
+	    int nbits;
+
+	    ENCODE_BIT (IN_RANGE);
+
+	    P -= L;
+
+	    range = delta + 1;
+
+	    if (range > 1)
+	      {
+		/* 2**i <= delta + 1 < 2**(i+1) ; find i ... */
+		CEILLOG_2 (range, logofrange);
+
+		/* number of n-bit values in the range */
+		thresh = (1 << logofrange) - range;
+
+		/* number of n+1-bit values in the range */
+		numlong = range - thresh;
+
+		/* rotate the n-bit codes into the centre */
+		P -= (numlong >> 1);
+		if ((long) P < 0)
+		  P += range;
+
+		if (P < thresh)
+		  nbits = logofrange - 1;
+		else
+		  {
+		    nbits = logofrange;
+		    P += thresh;
+		  }
+		while (--nbits >= 0)
+		  ENCODE_BIT ((P >> nbits) & 1);
+	      }
+	  }
+	else
+	  {
+	    /* OUT_OF_RANGE */
+	    unsigned long diff, parm, i, min;
+
+	    ENCODE_BIT (OUT_OF_RANGE);
+
+	    if (P < L)
+	      {
+		ENCODE_BIT (BELOW_RANGE);
+		diff = L - P - 1;
+	      }
+	    else
+	      {
+		ENCODE_BIT (ABOVE_RANGE);
+		diff = P - H - 1;
+	      }
+
+	    /* Now code 'diff' as a Golomb-Rice code */
+
+	    parm = 0;
+	    min = cumul_param[delta][0];
+	    for (i = 1; i < max_cumul; i++)
+	      if (cumul_param[delta][i] < min)
+		{
+		  min = cumul_param[delta][i];
+		  parm = i;
+		}
+
+	    UNARY_ENCODE ((diff >> parm) + 1);
+	    BINARY_ENCODE ((diff & ((1 << parm) - 1)) + 1, 1 << parm);
+
+	    for (i = 0; i < max_cumul; i++)
+	      cumul_param[delta][i] += (diff >> i) + 1 + i;
+	  }
+
+      }
+
+  ENCODE_DONE
+
+}
+
+
+
+
+
+
+void 
+decode (unsigned int *line, int width, int height, int maxval, int maxk,
+	FILE * fp_in, FILE * fp_out)
+{
+  int x, y;
+  unsigned int P, L, H, N1, N2, delta;
+  unsigned long cumul_param[256][INTSIZE];
+  unsigned max_cumul;
+
+  memset (cumul_param, '0', sizeof (cumul_param));
+
+  if (maxk)
+    max_cumul = maxk;
+  else
+    CEILLOG_2 (maxval, max_cumul);
+
+  DECODE_START (fp_in);
+
+  for (y = 0; y < height; y++)
+    for (x = 0; x < width; x++)
+      {
+	if (y > 0)
+	  {
+	    if (x > 0)
+	      {			/* ******** */
+		N1 = line[x];	/* ****1*** */
+		N2 = line[x - 1];	/* ***2P*** */
+	      }			/* ******** */
+	    else
+	      {			/* |******* */
+		N1 = line[x];	/* |12***** */
+		N2 = line[x + 1];	/* |P***** */
+	      }			/* |******* */
+	  }
+	else
+	  {
+	    if (x > 1)
+	      {
+		N1 = line[x - 1];	/* -------- */
+		N2 = line[x - 2];	/* **12P*** */
+	      }			/* ******** */
+	    else if (x > 0)
+	      {
+		N1 = line[x - 1];	/* +------- */
+		N2 = N1;	/* |3P***** */
+	      }			/* |******* */
+	    else
+	      {
+		BINARY_DECODE (line[x], maxval + 1);
+		line[x]--;
+		if (maxval < 256)
+		  putc (line[x], fp_out);	/* +------- */
+		else		/* |P****** */
+		  fprintf (fp_out, "%u ", line[x]);	/* |******* */
+		continue;
+	      }
+	  }
+
+
+	H = N1 > N2 ? N1 : N2;
+	L = N1 < N2 ? N1 : N2;
+	delta = H - L;
+
+	if (DECODE_BIT == IN_RANGE)
+	  {
+	    unsigned long i, range, logofrange, thresh, numlong;
+	    unsigned xx, l;
+
+	    range = delta + 1;
+
+	    if (range > 1)
+	      {
+		/* 2**i <= delta + 1 < 2**(i+1) ; find i ... */
+		CEILLOG_2 (range, logofrange);
+
+		/* number of n-bit values in the range */
+		thresh = (1 << logofrange) - range;
+		for (P = i = 0; i < logofrange - 1; i++)
+		  DECODE_ADD (P);
+		xx = P;
+		l = logofrange - 1;
+		if (P >= thresh)
+		  {
+		    DECODE_ADD (P);
+		    xx = P;
+		    l++;
+		    P -= thresh;
+		  }
+
+		/* number of n+1-bit values in the range */
+		numlong = range - thresh;
+
+		/* rotate the n-bit codes into the centre */
+		P += (numlong >> 1);
+		if ((long) P >= range)
+		  P -= range;
+
+		P += L;
+	      }
+	    else
+	      P = L;
+	  }
+	else
+	  {
+	    int out_of_range = DECODE_BIT;
+	    unsigned long diff, unary, binary, i, min, parm;
+
+	    /* Now code 'diff' as a Golomb-Rice code */
+
+	    parm = 0;
+	    min = cumul_param[delta][0];
+	    for (i = 1; i < max_cumul; i++)
+	      if (cumul_param[delta][i] < min)
+		{
+		  min = cumul_param[delta][i];
+		  parm = i;
+		}
+
+	    UNARY_DECODE (unary);
+	    diff = (unary - 1) << parm;
+	    BINARY_DECODE (binary, 1 << parm);
+	    diff |= binary - 1;
+
+	    for (i = 0; i < max_cumul; i++)
+	      cumul_param[delta][i] += (diff >> i) + 1 + i;
+
+	    if (out_of_range == BELOW_RANGE)
+	      {
+		P = L - diff - 1;
+	      }
+	    else
+	      {
+		P = diff + H + 1;
+	      }
+	  }
+
+	line[x] = P;
+
+	if (maxval < 256)
+	  (void) putc (P, fp_out);
+	else
+	  fprintf (fp_out, "%u ", P);
+      }
+
+  DECODE_DONE
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/lstevent.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/lstevent.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/lstevent.c	(revision 10506)
@@ -0,0 +1,421 @@
+/**************************************************************************
+ *
+ * lstevent.c -- Routines to implement "events" using MTF lists.
+ * Copyright (C) 1987  Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "arithcode.h"
+#include "model.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:26  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:33:37  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:41:40  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+void
+write_method ()
+{
+  fprintf (stderr, "C");
+}
+
+
+/*===========================================*/
+
+/*
+ * [Rodney Brown - Sep/95]
+ * On IBM RS/6000 AIX version 3.2 the compiler defines NULL as (void *)0
+ * when in ANSI mode. Hence the (event) and (point) casts
+ */
+
+
+#define GETNEWNODE(e,node)		\
+do 					\
+{	node = p32(numnodes) ;		\
+	node->eventnum = (event)e ;	\
+	node->count = increment ;	\
+	node->foll.totalcnt = 0 ;	\
+	node->foll.notfound = 0 ;	\
+	node->foll.list = (point)NULL ;	\
+	numnodes += 1 ;			\
+	nfreenodes -= 1 ;		\
+}					\
+while (false)
+
+/*===========================================*/
+
+#define INSERTNODE(U,node)		\
+do					\
+{	node->next = U->list ;		\
+	U->list = p16(node) ;		\
+	U->totalcnt += increment;	\
+}					\
+while (false)
+
+/*===========================================*/
+
+int
+halvelist (p)
+     register eventnode *p;
+{
+  register int sum = 0;
+  while (p != ENULL)
+    {
+      sum += p->count = (p->count + 1) / 2;
+      p = p32 (p->next);
+    }
+  return (sum);
+}
+
+/*===========================================*/
+
+void
+halveallcounts (U)
+     register eventset *U;
+{
+  U->notfound = (U->notfound + 1) / 2;
+  U->totalcnt = U->notfound;
+  U->totalcnt += halvelist (p32 (U->list));
+}
+
+/*===========================================*/
+
+eventnode *
+encode_event_noex (U, e, success)
+     register eventset *U;
+     event e;
+     boolean *success;
+{
+  register eventnode *pnode, *node;
+  register int lbnd, totl;
+
+  if (U->list == (point)NULL)
+    {
+      *success = false;
+      U->notfound += increment;
+      U->totalcnt += increment;
+      GETNEWNODE (e, node);
+      INSERTNODE (U, node);
+      return (node);
+    }
+
+  lbnd = 0;
+  pnode = ENULL;
+  node = p32 (U->list);
+  while (node != ENULL)
+    {
+      if (e == node->eventnum)
+	break;
+      lbnd += node->count;
+      pnode = node;
+      node = p32 (node->next);
+    }
+
+  totl = U->totalcnt;
+
+  if (node == ENULL)
+    {				/* event not found in list */
+      if ((totl > U->notfound))
+	arithmetic_encode (totl - U->notfound, totl, totl);
+      U->notfound += increment;
+      U->totalcnt += increment;
+      *success = false;
+      GETNEWNODE (e, node);
+      INSERTNODE (U, node);
+    }
+  else
+    {				/* found in the list, so go ahead and code */
+      arithmetic_encode (lbnd, lbnd + node->count, totl);
+      node->count += increment;
+      U->totalcnt += increment;
+      *success = true;
+      /* and move to front */
+      if (pnode != ENULL)
+	{
+	  pnode->next = node->next;
+	  node->next = U->list;
+	  U->list = p16 (node);
+	}
+    }
+  if (U->totalcnt > maxtotalcnt)
+    halveallcounts (U);
+  return (node);
+}
+
+/*===========================================*/
+
+eventnode *
+decode_event_noex (U, success, e)
+     register eventset *U;
+     boolean *success;
+     event *e;
+{
+  register eventnode *node, *pnode;
+  register int tget, lbnd, totl;
+
+  if (U->list == (point)NULL)
+    {
+      *success = false;
+      U->totalcnt += increment;
+      U->notfound += increment;
+      GETNEWNODE (NULL, node);
+      INSERTNODE (U, node);
+      return (node);
+    }
+  totl = U->totalcnt;
+  tget = arithmetic_decode_target (totl);
+
+  if (tget >= totl - U->notfound)
+    {
+      if (totl > U->notfound)
+	arithmetic_decode (totl - U->notfound, totl, totl);
+      U->totalcnt += increment;
+      U->notfound += increment;
+      *success = false;
+      GETNEWNODE (NULL, node);
+      INSERTNODE (U, node);
+    }
+  else
+    {
+      pnode = ENULL;
+      node = p32 (U->list);
+      lbnd = 0;
+      for (;;)
+	{
+	  if (tget < (lbnd += node->count))
+	    break;
+	  pnode = node;
+	  node = p32 (node->next);
+	}
+
+      arithmetic_decode (lbnd - node->count, lbnd, totl);
+      node->count += increment;
+      U->totalcnt += increment;
+      *e = node->eventnum;
+      *success = true;
+      /* and move to front */
+      if (pnode != ENULL)
+	{
+	  pnode->next = node->next;
+	  node->next = U->list;
+	  U->list = p16 (node);
+	}
+    }
+  if (U->totalcnt > maxtotalcnt)
+    halveallcounts (U);
+  return (node);
+}
+
+/*===========================================*/
+
+eventnode *
+encode_event (U, e, success)
+     register eventset *U;
+     event e;
+     boolean *success;
+{
+  register eventnode *pnode, *node, *p;
+  register int lbnd, totl;
+
+  if (U->list == (point)NULL)
+    {
+      *success = false;
+      U->notfound += increment;
+      U->totalcnt += increment;
+      GETNEWNODE (e, node);
+      INSERTNODE (U, node);
+      return (node);
+    }
+
+  lbnd = 0;
+  pnode = ENULL;
+  node = p32 (U->list);
+  while (node != ENULL)
+    {
+      if (!excluded[node->eventnum])
+	{
+	  if (e == node->eventnum)
+	    break;
+	  lbnd += node->count;
+	}
+      pnode = node;
+      node = p32 (node->next);
+    }
+
+  if (node == ENULL)
+    {				/* event not found in list, and whole list has been scanned */
+      totl = lbnd + U->notfound;
+      if ((totl > U->notfound))
+	arithmetic_encode (totl - U->notfound, totl, totl);
+      U->notfound += increment;
+      U->totalcnt += increment;
+      *success = false;
+      GETNEWNODE (e, node);
+      INSERTNODE (U, node);
+    }
+  else
+    {				/* found in the list, so go ahead and code */
+      /* first, total up rest of list */
+      totl = lbnd + node->count;
+      p = p32 (node->next);
+      while (p != ENULL)
+	{
+	  if (!excluded[p->eventnum])
+	    totl += p->count;
+	  p = p32 (p->next);
+	}
+      totl += U->notfound;
+
+      arithmetic_encode (lbnd, lbnd + node->count, totl);
+      node->count += increment;
+      U->totalcnt += increment;
+      *success = true;
+      /* and move to front */
+      if (pnode != ENULL)
+	{
+	  pnode->next = node->next;
+	  node->next = U->list;
+	  U->list = p16 (node);
+	}
+    }
+  if (U->totalcnt > maxtotalcnt)
+    halveallcounts (U);
+  return (node);
+}
+
+/*===========================================*/
+
+eventnode *
+decode_event (U, success, e)
+     register eventset *U;
+     boolean *success;
+     event *e;
+{
+  register eventnode *node, *pnode;
+  register int tget, lbnd, totl;
+
+  if (U->list == (point)NULL)
+    {
+      *success = false;
+      U->totalcnt += increment;
+      U->notfound += increment;
+      GETNEWNODE (NULL, node);
+      INSERTNODE (U, node);
+      return (node);
+    }
+  totl = 0;
+  node = p32 (U->list);
+  while (node != ENULL)
+    {
+      if (!excluded[node->eventnum])
+	totl += node->count;
+      node = p32 (node->next);
+    }
+  totl += U->notfound;
+  tget = arithmetic_decode_target (totl);
+
+  if (tget >= totl - U->notfound)
+    {
+      if (totl > U->notfound)
+	arithmetic_decode (totl - U->notfound, totl, totl);
+      U->totalcnt += increment;
+      U->notfound += increment;
+      *success = false;
+      GETNEWNODE (NULL, node);
+      INSERTNODE (U, node);
+    }
+  else
+    {
+      pnode = ENULL;
+      node = p32 (U->list);
+      lbnd = 0;
+      for (;;)
+	{
+	  if (!excluded[node->eventnum])
+	    {
+	      lbnd += node->count;
+	      if (tget < lbnd)
+		break;
+	    }
+	  pnode = node;
+	  node = p32 (node->next);
+	}
+
+      arithmetic_decode (lbnd - node->count, lbnd, totl);
+      node->count += increment;
+      U->totalcnt += increment;
+      *e = node->eventnum;
+      *success = true;
+      /* and move to front */
+      if (pnode != ENULL)
+	{
+	  pnode->next = node->next;
+	  node->next = U->list;
+	  U->list = p16 (node);
+	}
+    }
+  if (U->totalcnt > maxtotalcnt)
+    halveallcounts (U);
+  return (node);
+}
+
+/*===========================================*/
+
+eventnode *
+newnode (e)
+     event e;
+{
+  register eventnode *node;
+  GETNEWNODE (e, node);
+  node->next = (point)NULL;
+  node->prev = (point)NULL;
+  return (node);
+}
+
+/*===========================================*/
+
+/* not required in this version */
+
+#if 0
+eventnode *
+addevent (U, e)
+     register eventset *U;
+     event e;
+{
+  register eventnode *node;
+  /* get an event node */
+  GETNEWNODE (e, node);
+  INSERTNODE (U, node);
+  if (U->totalcnt > maxtotalcnt)
+    halveallcounts (U);
+  return (node);
+}
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/marklist.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/marklist.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/marklist.c	(revision 10506)
@@ -0,0 +1,827 @@
+/**************************************************************************
+ *
+ * marklist.c -- Functions managing the list of marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "utils.h"
+
+void 
+marktype_dump (marktype d)
+{
+  fprintf (stderr, "symnum: %d\n", d.symnum);
+  fprintf (stderr, "xpos: %d, ypos: %d\n", d.xpos, d.ypos);
+  fprintf (stderr, "w: %d, h: %d\n", d.w, d.h);
+  fprintf (stderr, "xcen: %d, ycen: %d\n", d.xcen, d.ycen);
+  write_library_mark (stderr, d);
+}
+
+
+/* copy, including make a copy of the bitmap */
+marktype 
+marktype_copy (marktype d)
+{
+  marktype d2;
+  int i, j;
+
+  d2 = d;
+  d2.bitmap = pbm_allocarray (d2.w, d2.h);
+  for (i = 0; i < d2.w; i++)
+    for (j = 0; j < d2.h; j++)
+      pbm_putpixel (d2.bitmap, i, j, pbm_getpixel (d.bitmap, i, j));
+  return d2;
+}
+
+
+float 
+marktype_density (marktype d)
+{
+  return d.set / (float) (d.w * d.h);
+}
+
+
+
+void 
+marktype_calc_centroid (marktype * b)
+{
+  int r, c;
+  int count = 0;
+  int xtot = 0, ytot = 0;
+
+  for (r = 0; r < b->h; r++)
+    for (c = 0; c < b->w; c++)
+      if (pbm_getpixel (b->bitmap, c, r))
+	{
+	  count++;
+	  xtot += c;
+	  ytot += r;
+	}
+  if (count)
+    {
+      xtot /= count;
+      ytot /= count;
+    }
+  b->xcen = xtot;
+  b->ycen = ytot;
+}
+
+
+
+static void 
+marktype_area (marktype * d)
+{
+  int x, y;
+  int set = 0;
+
+  for (y = 0; y < d->h; y++)
+    for (x = 0; x < d->w; x++)
+      if (pbm_getpixel (d->bitmap, x, y))
+	set++;
+  d->set = set;
+}
+
+
+static void 
+marktype_h_runs (marktype * d)
+{
+  int x, y;
+  int inrun = 0, num = 0;
+  int foundblack = 0;
+
+  for (y = 0; y < d->h; y++)
+    {
+      inrun = 0;
+      foundblack = 0;
+      for (x = 0; x < d->w; x++)
+	{
+	  if ((!foundblack) && (pbm_getpixel (d->bitmap, x, y)))
+	    foundblack = 1;
+	  if ((foundblack) && (pbm_getpixel (d->bitmap, x, y) == 0))
+	    inrun = 1;
+	  if ((inrun) && (pbm_getpixel (d->bitmap, x, y)))
+	    {
+	      num++;
+	      inrun = 0;
+	      foundblack = 0;
+	    }
+	}
+    }
+  d->h_runs = num;
+}
+
+static void 
+marktype_v_runs (marktype * d)
+{
+  int x, y;
+  int inrun = 0, num = 0;
+  int foundblack = 0;
+
+
+  for (x = 0; x < d->w; x++)
+    {
+      inrun = 0;
+      foundblack = 0;
+      for (y = 0; y < d->h; y++)
+	{
+	  if ((!foundblack) && (pbm_getpixel (d->bitmap, x, y)))
+	    foundblack = 1;
+	  if ((foundblack) && (pbm_getpixel (d->bitmap, x, y) == 0))
+	    inrun = 1;
+	  if ((inrun) && (pbm_getpixel (d->bitmap, x, y)))
+	    {
+	      num++;
+	      inrun = 0;
+	      foundblack = 0;
+	    }
+	}
+    }
+  d->v_runs = num;
+}
+
+
+/* assume we already have the centroid! */
+static void 
+marktype_prog_cent (marktype * d)
+{
+  int x, y;
+  int xtot = 0, ytot = 0;
+  int num = 0;
+
+  xtot = ytot = num = 0;
+  for (x = 0; x < d->xcen; x++)
+    for (y = 0; y < d->ycen; y++)
+      if (pbm_getpixel (d->bitmap, x, y))
+	{
+	  xtot += x;
+	  ytot += y;
+	  num++;
+	}
+  if (num == 0)
+    {
+      d->xcen1 = -1;
+      d->ycen1 = -1;
+    }
+  else
+    {
+      d->xcen1 = xtot / num;
+      d->ycen1 = ytot / num;
+    }
+
+
+  xtot = ytot = num = 0;
+  for (x = d->xcen; x < d->w; x++)
+    for (y = 0; y < d->ycen; y++)
+      if (pbm_getpixel (d->bitmap, x, y))
+	{
+	  xtot += x;
+	  ytot += y;
+	  num++;
+	}
+  if (num == 0)
+    {
+      d->xcen2 = -1;
+      d->ycen2 = -1;
+    }
+  else
+    {
+      d->xcen2 = xtot / num;
+      d->ycen2 = ytot / num;
+    }
+
+
+
+  xtot = ytot = num = 0;
+  for (x = 0; x < d->xcen; x++)
+    for (y = d->ycen; y < d->h; y++)
+      if (pbm_getpixel (d->bitmap, x, y))
+	{
+	  xtot += x;
+	  ytot += y;
+	  num++;
+	}
+
+
+  if (num == 0)
+    {
+      d->xcen3 = -1;
+      d->ycen3 = -1;
+    }
+  else
+    {
+      d->xcen3 = xtot / num;
+      d->ycen3 = ytot / num;
+    }
+
+  xtot = ytot = num = 0;
+  for (x = d->xcen; x < d->w; x++)
+    for (y = d->ycen; y < d->h; y++)
+      if (pbm_getpixel (d->bitmap, x, y))
+	{
+	  xtot += x;
+	  ytot += y;
+	  num++;
+	}
+  if (num == 0)
+    {
+      d->xcen4 = -1;
+      d->ycen4 = -1;
+    }
+  else
+    {
+      d->xcen4 = xtot / num;
+      d->ycen4 = ytot / num;
+    }
+}
+
+
+
+/* call this to get all features */
+void 
+marktype_calc_features (marktype * d, char str[])
+{
+  if (strlen (str))
+    strcpy (d->name, str);
+  marktype_calc_centroid (d);
+  marktype_area (d);
+  marktype_prog_cent (d);
+  marktype_h_runs (d);
+  marktype_v_runs (d);
+}
+
+
+
+
+
+void 
+marktype_adj_bound (marktype * m)
+{
+  int x, y, w, h;
+  int xpos, ypos;
+  int top = 0, left = 0, right = 0, bot = 0;
+  marktype temp;
+
+  w = m->w;
+  h = m->h;
+  xpos = m->xpos;
+  ypos = m->ypos;
+
+  for (y = 0; y < h; y++)
+    for (x = 0; x < w; x++)
+      if (pbm_getpixel (m->bitmap, x, y))
+	{
+	  top = y;
+	  x = w;
+	  y = h;
+	}
+
+  for (y = h - 1; y >= 0; y--)
+    for (x = 0; x < w; x++)
+      if (pbm_getpixel (m->bitmap, x, y))
+	{
+	  bot = y;
+	  x = w;
+	  y = -1;
+	}
+
+  for (x = 0; x < w; x++)
+    for (y = 0; y < h; y++)
+      if (pbm_getpixel (m->bitmap, x, y))
+	{
+	  left = x;
+	  x = w;
+	  y = h;
+	}
+
+  for (x = w - 1; x >= 0; x--)
+    for (y = 0; y < h; y++)
+      if (pbm_getpixel (m->bitmap, x, y))
+	{
+	  right = x;
+	  x = -1;
+	  y = h;
+	}
+
+  temp.w = right - left + 1;
+  temp.h = bot - top + 1;
+  temp.xpos = xpos + left;
+  temp.ypos = ypos + top;
+  temp.bitmap = pbm_allocarray (temp.w, temp.h);
+
+  for (x = 0; x < temp.w; x++)
+    for (y = 0; y < temp.h; y++)
+      pbm_putpixel (temp.bitmap, x, y, pbm_getpixel (m->bitmap, x + left, y + top));
+
+  pbm_freearray (&(m->bitmap), h);
+
+  marktype_calc_features (&temp, "?");
+  *m = temp;
+}
+
+
+
+
+
+
+/* returns a newly created mark reprenting the average of the marklist */
+void 
+marklist_average (marklistptr list, marktype * avgmark)
+{
+  int w = 0, h = 0;
+  int t = INT_MAX, b = 0, l = INT_MAX, r = 0, matched = 0;
+  marktype d, temp;
+  marklistptr step;
+  static int a[100][100];
+  int x, y;
+
+  if (list == NULL)
+    error_msg ("marklist_average", "Can't average 'nothing'!", "");
+
+  for (step = list; step; step = step->next)
+    {
+      matched++;
+      temp = step->data;
+      w = max (w, temp.w);
+      h = max (h, temp.h);
+      r = max (r, temp.xcen);
+      l = min (l, temp.xcen);
+      b = max (b, temp.ycen);
+      t = min (t, temp.ycen);
+    }
+  w = w + (r - l);
+  h = h + (b - t);
+  if ((w >= 100) || (h >= 100))
+    matched = 0;
+
+  if (matched > 1)
+    {
+      int x_off, y_off;
+      for (x = 0; x < w; x++)
+	for (y = 0; y < h; y++)
+	  a[x][y] = 0;
+
+      for (step = list; step; step = step->next)
+	{
+	  x_off = r - step->data.xcen;
+	  y_off = b - step->data.ycen;
+	  for (x = 0; x < step->data.w; x++)
+	    for (y = 0; y < step->data.h; y++)
+	      if (pbm_getpixel (step->data.bitmap, x, y))
+		a[x + x_off][y + y_off]++;
+	}
+
+      d.w = w;
+      d.h = h;
+      d.bitmap = pbm_allocarray (w, h);
+      for (x = 0; x < w; x++)
+	for (y = 0; y < h; y++)
+	  if (a[x][y] > max (1, (matched / 2)))		/* > gives better CR than >= */
+	    pbm_putpixel (d.bitmap, x, y, 1);
+      marktype_adj_bound (&d);
+      strcpy (d.name, "?");
+      marktype_calc_centroid (&d);
+    }
+  else
+    d = marktype_copy (list->data);
+
+  *avgmark = d;
+}
+
+
+
+
+
+
+void 
+marklist_setnull (marklistptr * list)
+{
+  *list = NULL;
+}
+
+
+marklistptr 
+marklist_add (marklistptr * list, marktype m)
+{
+  marklistptr p;
+
+  if (*list == NULL)
+    {
+      *list = (marklistptr) malloc (sizeof (marklisttype));
+      if ((*list) == NULL)
+	error_msg ("marklist_add", "OUT of Memory in marklist_add", "");
+      p = *list;
+    }
+  else
+    {
+      p = *list;
+      while (p->next != NULL)
+	p = p->next;
+      p->next = (marklistptr) malloc (sizeof (marklisttype));
+      if (p->next == NULL)
+	error_msg ("marklist_add", "OUT of Memory in marklist_add", "");
+      p = p->next;
+    }
+  p->data = m;
+  p->next = NULL;
+  return p;
+
+}
+
+
+
+marklistptr 
+marklist_addcopy (marklistptr * list, marktype m)
+{
+  marktype d;
+
+  d = marktype_copy (m);
+  return marklist_add (list, d);
+}
+
+
+
+int 
+marklist_length (marklistptr list)
+{
+  int count = 0;
+
+  while (list)
+    {
+      count++;
+      list = list->next;
+    }
+  return count;
+}
+
+
+
+
+
+void 
+marklist_dump (marklistptr list)
+{
+  int count = 0;
+  marktype d;
+
+  while (list)
+    {
+      d = list->data;
+      marktype_dump (d);
+
+      count++;
+      list = list->next;
+    }
+}
+
+
+
+
+/* pos starts from 0, to up marklist_length-1 */
+marklistptr 
+marklist_getat (marklistptr list, int pos, marktype * d)
+{
+  int count = 0;
+
+  while (list)
+    {
+      if (count == pos)
+	{
+	  *d = list->data;
+	  return list;
+	}
+      count++;
+      list = list->next;
+    }
+  fprintf (stderr, "marklist_getat(): access off ends of list: pos %d\n", pos);
+  return NULL;
+}
+
+
+
+void 
+marklist_free (marklistptr * list)
+{
+  marklistptr n;
+
+  while ((*list) != NULL)
+    {
+      n = (*list)->next;
+      pbm_freearray (&((*list)->data.bitmap), (*list)->data.h);
+      free ((*list));
+      (*list) = n;
+    }
+}
+
+
+
+int 
+marklist_removeat (marklistptr * list, int pos)
+{
+  marklistptr c, n, p = NULL;
+  int count = 0;
+
+  if ((pos == 0) && (*list))
+    {				/* if removing the 1st element */
+      *list = (*list)->next;
+      return 1;
+    }
+  else
+    {
+      c = *list;
+      while (c)
+	{
+	  if (count == pos)
+	    {			/* two cases, no previous, >=1 previous */
+	      if (p == NULL)	/* no previous */
+		{
+		  n = c->next;
+		  pbm_freearray (&c->data.bitmap, c->data.h);
+		  free (c);
+		  c = n;
+		  return 1;
+		}
+	      else
+		/* >=1 previous */
+		{
+		  n = c->next;
+		  pbm_freearray (&c->data.bitmap, c->data.h);
+		  free (c);
+		  p->next = n;
+		  return 1;
+		}
+	    }
+	  count++;
+	  p = c;
+	  c = c->next;
+	}
+    }
+  fprintf (stderr, "marklist_removeat(): access off ends of list: pos %d\n", pos);
+  return 0;			/* nothing was removed */
+}
+
+
+
+marklistptr 
+marklist_next (marklistptr list)
+{
+  return list->next;
+}
+
+
+/* only writes out ascii form */
+void 
+write_library_mark (FILE * fp, marktype d)
+{
+  int r, c, rows, cols;
+  int xtot = d.xcen, ytot = d.ycen;
+
+  rows = d.h;
+  cols = d.w;
+
+  fprintf (fp, "Mark: %d\n", d.symnum);
+  fprintf (fp, "Char: %s\n", d.name);
+  fprintf (fp, "Cols: %d Rows: %d\n", d.w, d.h);
+  for (r = 0; r < d.h; r++)
+    {
+      for (c = 0; c < d.w; c++)
+	if ((r == ytot) && (c == xtot))
+	  putc (pbm_getpixel (d.bitmap, c, r) ? 'C' : '!', fp);
+	else
+	  putc (pbm_getpixel (d.bitmap, c, r) ? 'X' : '.', fp);
+      putc ('\n', fp);
+    }
+}
+
+
+
+/* only reads in ascii library */
+int 
+read_library_mark (FILE * fp, marktype * d)
+{
+  int r, c, rows, cols, numread, ch1 = 'C';
+  char str1[100], str2[100];
+
+  numread = fscanf (fp, "%s %d\n", str1, &(d->symnum));
+  if ((numread != 2) || (strcmp (str1, "Mark:") != 0))
+    return 0;
+  fscanf (fp, "%s %s\n", str1, (d->name));
+  fscanf (fp, "%s %d %s %d\n", str1, &(d->w), str2, &(d->h));
+  cols = d->w;
+  rows = d->h;
+  d->bitmap = pbm_allocarray (cols, rows);
+  for (r = 0; r < rows; r++)
+    {
+      for (c = 0; c < cols; c++)
+	{
+	  ch1 = getc (fp);
+	  if ((ch1 == 'X') || (ch1 == 'C'))
+	    pbm_putpixel (d->bitmap, c, r, 1);
+	  else
+	    pbm_putpixel (d->bitmap, c, r, 0);
+	}
+      ch1 = getc (fp);
+    }
+  marktype_calc_features (d, "?");
+
+  return 1;
+}
+
+
+
+
+
+
+
+int 
+read_library (char libraryname[], marklistptr * library)
+{
+  int err, count;
+  FILE *lib;
+  marktype d;
+  marklistptr step;
+
+  lib = fopen (libraryname, "rb");
+  if (lib == NULL)
+    error_msg ("read_library()", "Trouble opening library file", "");
+  *library = NULL;
+  count = 0;
+  while (!isEOF (lib))
+    {
+      err = read_library_mark (lib, &d);
+      if (!err)
+	error_msg ("read_library()", "unknown format of the library file.", "");
+      d.symnum = count;
+      count++;
+      if ((*library) == NULL)
+	step = marklist_add (library, d);
+      else
+	step = marklist_add (&step, d);
+    }
+  count = marklist_length (*library);
+  fclose (lib);
+
+  return count;
+}
+
+
+
+
+
+
+/**********************************************************************
+
+'elem' routines for coding offsets
+
+the elem datatype contains the 3 params for arithmetic coding,
+stored as a no-duplicates order linked list.
+
+************************************************************************/
+
+
+
+
+void 
+elem_add (elemlist * list, int num)
+{
+  elemptr temp, nn;
+  int p, f;
+
+  list->tot++;
+  if (list->head == NULL)
+    {
+      list->head = (elemptr) malloc (sizeof (elem));
+      if ((list->head) == NULL)
+	error_msg ("", "ekk", "");
+      temp = list->head;
+      temp->next = NULL;
+      temp->num = num;
+      temp->pos = 0;
+      temp->freq = 1;
+    }
+  else
+    {				/* add to list */
+      temp = list->head;
+      p = 0;
+      f = 0;
+      while ((num > temp->num) && (temp->next != NULL))
+	{
+	  p = temp->pos;
+	  f = temp->freq;
+	  temp = temp->next;
+	}
+
+      if (temp->num == num)
+	temp->freq++;
+      else
+	{			/* insert it */
+	  nn = (elemptr) malloc (sizeof (elem));
+	  if (nn == NULL)
+	    error_msg ("", "ekk", "");
+
+	  if (num < temp->num)
+	    {
+	      nn->num = temp->num;
+	      nn->pos = temp->pos;
+	      nn->freq = temp->freq;
+	      nn->next = temp->next;
+	      temp->num = num;
+	      temp->pos = p + f;
+	      temp->freq = 1;
+	      temp->next = nn;
+	    }
+	  else
+	    {
+	      nn->next = temp->next;
+	      temp->next = nn;
+	      nn->pos = temp->pos + temp->freq;
+	      nn->num = num;
+	      nn->freq = 1;
+	      temp = nn;
+	    }
+	}
+    }
+  /* update frequencies */
+  temp = temp->next;
+  if (temp)
+    do
+      {
+	temp->pos++;
+	temp = temp->next;
+      }
+    while (temp);
+}
+
+
+void 
+elem_free (elemlist * list)
+{
+  elemptr n, p;
+
+  p = list->head;
+  while (p != NULL)
+    {
+      n = p->next;
+      free (p);
+      p = n;
+    }
+  list->head = NULL;
+}
+
+int 
+elem_find (elemlist * list, int n, int *p, int *f, int *t)
+{
+  elemptr temp;
+
+  temp = list->head;
+  while (temp)
+    {
+      if (temp->num == n)
+	{
+	  *p = temp->pos;
+	  *f = temp->freq + temp->pos;
+	  *t = list->tot;
+	  return 1;
+	}
+      temp = temp->next;
+    }
+  return 0;
+}
+
+
+int 
+elem_getrange (elemlist * list, int range, int *num)
+{
+  elemptr temp;
+
+  temp = list->head;
+  while (temp)
+    {
+      if ((range >= temp->pos) && (range < (temp->pos + temp->freq)))
+	{
+	  *num = temp->num;
+	  return 1;
+	}
+      temp = temp->next;
+    }
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/marklist.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/marklist.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/marklist.h	(revision 10506)
@@ -0,0 +1,114 @@
+/**************************************************************************
+ *
+ * marklist.h -- Functions managing the list of marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __MARKLIST_H
+#define __MARKLIST_H
+
+#include "sysfuncs.h"
+#include "basictypes.h"
+
+typedef struct
+  {
+    int symnum;
+    int xpos, ypos;
+    int w, h;
+    int xcen, ycen;
+    int xoffset, yoffset;
+    char name[10];
+    Pixel **bitmap;
+
+    int xcen1, ycen1;
+    int xcen2, ycen2;
+    int xcen3, ycen3;
+    int xcen4, ycen4;
+    int set;
+    int h_runs;
+    int v_runs;
+  }
+marktype;
+
+
+typedef struct marklisttype *marklistptr;
+typedef struct marklisttype
+  {
+    marktype data;
+    marklistptr next;
+  }
+marklisttype;
+
+
+void marktype_dump (marktype d);
+marktype marktype_copy (marktype d);
+
+float marktype_density (marktype d);
+void marktype_calc_centroid (marktype * b);
+void marktype_calc_features (marktype * d, char str[]);
+void marktype_adj_bound (marktype * m);
+
+void marklist_average (marklistptr list, marktype * avgmark);
+void marklist_setnull (marklistptr * list);
+marklistptr marklist_add (marklistptr * list, marktype m);
+marklistptr marklist_addcopy (marklistptr * list, marktype m);
+int marklist_length (marklistptr list);
+void marklist_dump (marklistptr list);
+marklistptr marklist_getat (marklistptr list, int pos, marktype * d);
+void marklist_free (marklistptr * list);
+int marklist_removeat (marklistptr * list, int pos);
+marklistptr marklist_next (marklistptr list);
+
+void write_library_mark (FILE * fp, marktype d);
+int read_library_mark (FILE * fp, marktype * d);
+int read_library (char libraryname[], marklistptr * library);
+
+
+
+
+
+
+/* 
+   The 'elem' structure is an ordered linked list, with fields corresponding
+   directly to the arithmetic coding routines.  
+ */
+typedef struct elem *elemptr;
+typedef struct elem
+  {
+    int num;
+    int pos;
+    int freq;
+    elemptr next;
+  }
+elem;
+
+typedef struct elemlist
+  {
+    elemptr head;
+    int tot;
+  }
+elemlist;
+
+void elem_add (elemlist * list, int num);
+void elem_free (elemlist * list);
+int elem_find (elemlist * list, int n, int *p, int *f, int *t);
+int elem_getrange (elemlist * list, int range, int *num);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/match.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/match.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/match.c	(revision 10506)
@@ -0,0 +1,417 @@
+/**************************************************************************
+ *
+ * match.c -- Functions related to matching marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "utils.h"
+
+
+/* error mask goes from 0..8, single pixel errors are worth nothing */
+int 
+WXOR_match (marktype b1, marktype b2)
+{
+  int r, c, i, j;
+  int minr, minc;
+  int maxr, maxc;
+  int offx, offy;
+  int p1, p2;
+  int count = 0;
+  marktype d;
+
+  offx = b1.xcen - b2.xcen;
+  offy = b1.ycen - b2.ycen;
+
+  minc = min (0, offx);
+  minr = min (0, offy);
+
+  maxc = max (b1.w, b2.w + offx);
+  maxr = max (b1.h, b2.h + offy);
+
+  d.w = maxc - minc + 1;
+  d.h = maxr - minr + 1;
+  d.bitmap = pbm_allocarray (d.w, d.h);
+
+
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      {
+	if ((r >= 0) && (c >= 0) && (r < b1.h) && (c < b1.w))
+	  p1 = pbm_getpixel (b1.bitmap, c, r);
+	else
+	  p1 = 0;		/* 0 = back ground colour */
+	if ((r - offy >= 0) && (c - offx >= 0) && (r - offy < b2.h) && (c - offx < b2.w))
+	  p2 = pbm_getpixel (b2.bitmap, c - offx, r - offy);
+	else
+	  p2 = 0;		/* background colour */
+	pbm_putpixel (d.bitmap, c - minc, r - minr, p1 != p2);
+      }
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      if (pbm_getpixel (d.bitmap, c - minc, r - minr))
+	for (i = -1; i <= 1; i++)
+	  for (j = -1; j <= 1; j++)
+	    if ((r + j >= 0) && (c + i >= 0) && (r + j < d.h) && (c + i < d.w) && ((i != 0) || (j != 0)) && (pbm_getpixel (d.bitmap, c + i - minc, r + j - minr)))
+	      count++;
+  pbm_freearray (&d.bitmap, d.h);
+  return count;
+}
+
+
+
+/* define an array for most matches, if it is a massive mark, then WXOR is called */
+#define S_SIZE 500
+
+static unsigned char scratch[S_SIZE][S_SIZE], sc2[S_SIZE][S_SIZE];
+
+
+
+
+/* Weighted AND-NOT */
+
+int 
+WAN_match (marktype b1, marktype b2)
+{
+  int r, c, i, j;
+  int minr, minc;
+  int maxr, maxc;
+  int offx, offy;
+  int p1, p2;
+  int count = 0;
+
+  offx = b1.xcen - b2.xcen;
+  offy = b1.ycen - b2.ycen;
+
+  minc = min (0, offx);
+  minr = min (0, offy);
+
+  maxc = max (b1.w, b2.w + offx);
+  maxr = max (b1.h, b2.h + offy);
+
+  if (((maxc - minc) >= S_SIZE) || ((maxr - minr) >= S_SIZE))
+    return WXOR_match (b1, b2);
+
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      {
+	scratch[r - minr][c - minc] = sc2[r - minr][c - minc] = 0;
+	if ((r >= 0) && (c >= 0) && (r < b1.h) && (c < b1.w))
+	  p1 = pbm_getpixel (b1.bitmap, c, r);
+	else
+	  p1 = 0;		/* 0 == background colour */
+	if ((r - offy >= 0) && (c - offx >= 0) && (r - offy < b2.h) && (c - offx < b2.w))
+	  p2 = pbm_getpixel (b2.bitmap, c - offx, r - offy);
+	else
+	  p2 = 0;
+
+	if ((p1 == 0) && (p2 == 1))	/* p1 not set, p2 = set */
+	  scratch[r - minr][c - minc] = 1;
+	if ((p1 == 1) && (p2 == 0))	/* p1 set, p2 not set */
+	  sc2[r - minr][c - minc] = 1;
+      }
+
+  count = 0;
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      if (scratch[r - minr][c - minc])
+	for (i = -1; i <= 1; i++)
+	  for (j = -1; j <= 1; j++)
+	    if ((r + j >= minr) && (c + i >= minc) && (r + j < maxr) && (c + i < maxc) && ((i != 0) || (j != 0)) && scratch[r - minr + j][c - minc + i])
+	      count++;
+
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      if (sc2[r - minr][c - minc])
+	for (i = -1; i <= 1; i++)
+	  for (j = -1; j <= 1; j++)
+	    if ((r + j >= minr) && (c + i >= minc) && (r + j < maxr) && (c + i < maxc) && ((i != 0) || (j != 0)) && sc2[r - minr + j][c - minc + i])
+	      count++;
+
+  return count;
+}
+
+/* oc 8 must be in a clock wise order, with oc[0] a corner */
+struct
+{
+  int x, y;
+}
+oc[8] =
+{
+  {
+    -1, -1
+  }
+  ,
+  {
+    0, -1
+  }
+  ,
+  {
+    1, -1
+  }
+  ,
+  {
+    1, 0
+  }
+  ,
+  {
+    1, 1
+  }
+  ,
+  {
+    0, 1
+  }
+  ,
+  {
+    -1, 1
+  }
+  ,
+  {
+    -1, 0
+  }
+};
+
+
+
+static void 
+xormatchscratch (marktype * b1, marktype * b2, int minr, int maxr, int minc, int maxc, int offx, int offy)
+{
+  int r, c, rmm, roo, coo;
+  int p1, p2;
+  Pixel **bm1 = b1->bitmap, **bm2 = b2->bitmap;
+  int w1 = b1->w, h1 = b1->h, w2 = b2->w, h2 = b2->h;
+
+  for (r = minr; r < maxr; r++)
+    {
+      rmm = r - minr;
+      roo = r - offy;
+      p1 = 0;
+      for (c = minc; c < 0; c++)
+	{
+	  coo = c - offx;
+	  scratch[rmm][c - minc] = sc2[rmm][c - minc] = 0;
+	  if ((coo >= 0) && (roo >= 0) && (coo < w2) && (roo < h2))
+	    p2 = pbm_getpixel (bm2, coo, roo);
+	  else
+	    p2 = 0;		/* background */
+	  scratch[rmm][c - minc] = p1 != p2;
+	}
+      for (c = 0; c < maxc; c++)
+	{
+	  coo = c - offx;
+	  scratch[rmm][c - minc] = sc2[rmm][c - minc] = 0;
+	  if ((r >= 0) && (c < w1) && (r < h1))
+	    p1 = pbm_getpixel (bm1, c, r);
+	  else
+	    p1 = 0;		/* background */
+	  if ((coo >= 0) && (roo >= 0) && (coo < w2) && (roo < h2))
+	    p2 = pbm_getpixel (bm2, coo, roo);
+	  else
+	    p2 = 0;		/* background */
+	  scratch[rmm][c - minc] = p1 != p2;
+	}
+    }
+}
+
+
+
+int 
+CSIS_match (marktype * b1, marktype * b2)
+{
+  int r, c, i;
+  int minr, minc;
+  int maxr, maxc;
+  int offx, offy, fepcount;
+  int totscratch = 0;
+
+
+  offx = b1->xcen - b2->xcen;
+  offy = b1->ycen - b2->ycen;
+
+  minc = min (0, offx);
+  minr = min (0, offy);
+
+  maxc = max (b1->w, b2->w + offx);
+  maxr = max (b1->h, b2->h + offy);
+
+  if (((maxc - minc) >= S_SIZE) || ((maxr - minr) >= S_SIZE))
+    return WXOR_match (*b1, *b2);
+
+  /* set the scratch array to 1 if there is an XOR match */
+
+  xormatchscratch (b1, b2, minr, maxr, minc, maxc, offx, offy);
+  /* We how have the XOR map. Scratch contains the number of neighbours, 1=1 neighbour set...etc */
+
+  /* CSIS rule 1, if FEP (four error pels) then exit */
+  fepcount = 0;
+  for (r = minr; r < maxr - 1; r++)
+    for (c = minc; c < maxc - 1; c++)
+      if ((scratch[r - minr][c - minc]) && (scratch[r - minr + 1][c - minc]) &&
+	  (scratch[r - minr][c - minc + 1]) && (scratch[r - minr + 1][c - minc + 1]))
+	{
+	  fepcount++;
+	  if (fepcount == 1)
+	    return 10001;
+	}
+
+  /* foreach set pixel, update scratch with the number of pels around in five dir's. 
+     FPN (five-pel neighbour hood) */
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      if (scratch[r - minr][c - minc])
+	{
+	  sc2[r - minr][c - minc] = 1;	/* itself */
+	  for (i = 1; i < 8; i += 3)
+	    if (((r + oc[i].y) >= minr) && ((c + oc[i].x) >= minc) && ((r + oc[i].y) < maxr) && ((c + oc[i].x) < maxc))
+	      if (scratch[r + oc[i].y - minr][c + oc[i].x - minc])
+		sc2[r - minr][c - minc]++;
+	}
+  /* now scratch has the value of the FPN - 1=single error, 5=4 neighbouring errors etc... */
+
+  /* set scratch and sc2 to be the same */
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      totscratch += scratch[r - minr][c - minc] = sc2[r - minr][c - minc];
+
+  for (r = minr; r < maxr; r++)
+    for (c = minc; c < maxc; c++)
+      {
+	/* CSIS rule 2i: an error pel has 2 or more neighbours---this num is the same as PMS */
+	if (scratch[r - minr][c - minc] >= 3)
+	  if ((r - minr >= 1) && (c - minc >= 1) && (r - minr < (maxr - 1)) && (c - minc < (maxc - 1)))
+	    {
+	      int i, numsep = 0;
+	      /* find how many neighbours a set pixel has, only check the 4 edges-FPN */
+	      for (i = 1; i < 8; i += 2)
+		if (scratch[r + oc[i].y - minr][c + oc[i].x - minc])	/* if a scratch pixel is set */
+		  {
+		    if ((scratch[r + oc[(i + 2) % 8].y - minr][c + oc[(i + 2) % 8].x - minc] == 0) &&
+			(scratch[r + oc[(i + 6) % 8].y - minr][c + oc[(i + 6) % 8].x - minc] == 0)
+		      )
+		      numsep++;
+		  }
+
+	      if ((b1->w >= 12) || (b2->w >= 12) || (b1->h >= 12) || (b2->h >= 12))
+		{
+
+		  /* PMS rule 2ii: at least two of its neigh. error p's aren't connected */
+		  if (numsep >= 2)
+		    {
+		      int i, j, p, p2, same;
+
+		      /* PMS rule 2(iii), look for regions in the original images of 3x3 the same */
+		      if ((c >= 0) && (r >= 0) && (c < b1->w) && (r < b1->h))
+			{
+			  p = pbm_getpixel (b1->bitmap, c, r);
+			  same = 0;
+			  for (i = -1; i <= 1; i++)
+			    for (j = -1; j <= 1; j++)
+			      {
+				if ((c + i >= 0) && (r + j >= 0) && (c + i < b1->w) && (r + j < b1->h))
+				  p2 = pbm_getpixel (b1->bitmap, c + i, r + j);
+				else
+				  p2 = 0;
+				if (p2 == p)
+				  same++;
+			      }	/* i,j loop */
+			  /* PMS rule 2(iii) */
+			  if (same == 9)
+			    {
+			      return 10002;
+			    }
+			}	/* (*b1) in range */
+
+		      if ((c - offx >= 0) && (r - offy >= 0) && (c - offx < b2->w) && (r - offy < b2->h))
+			{
+			  p = pbm_getpixel (b2->bitmap, c - offx, r - offy);
+			  same = 0;
+			  for (i = -1; i <= 1; i++)
+			    for (j = -1; j <= 1; j++)
+			      {
+				if ((c + i - offx >= 0) && (r + j - offy >= 0) && (c + i - offx < b2->w) && (r + j - offy < b2->h))
+				  p2 = pbm_getpixel (b2->bitmap, c + i - offx, r + j - offy);
+				else
+				  p2 = 0;
+				if (p2 == p)
+				  same++;
+			      }	/* i,j loop */
+			  /* PMS rule 2(iii) */
+			  if (same == 9)
+			    {
+			      return 10003;
+			    }
+			}
+		    }
+		}
+	      else
+		{		/* do the CSIS rule */
+		  /* CSIS rule 2ii: at least two of its neigh. error p's aren't connected */
+		  if (numsep >= 2)
+		    {
+		      int i, p, p2, same;
+
+		      /* PMS rule 2(iii), look for regions in the original images of 3x3 the same */
+		      if ((c >= 0) && (r >= 0) && (c < b1->w) && (r < b1->h))
+			{
+			  p = pbm_getpixel (b1->bitmap, c, r);
+			  same = 1;
+			  for (i = 1; i < 8; i += 2)
+			    if ((c + oc[i].x >= 0) && (r + oc[i].y >= 0) && (c + oc[i].x < b1->w) && (r + oc[i].y < b1->h))
+			      p2 = pbm_getpixel (b1->bitmap, c + oc[i].x, r + oc[i].y);
+			    else
+			      p2 = 0;
+			  if (p2 == p)
+			    same++;
+
+			  /* CSIS rule 2(iii) */
+			  if (same == 5)
+			    {
+			      return 10002;
+			    }
+			}
+
+		      if ((c - offx >= 0) && (r - offy >= 0) && (c - offx < b2->w) && (r - offy < b2->h))
+			{
+			  p = pbm_getpixel (b2->bitmap, c - offx, r - offy);
+			  same = 1;
+			  for (i = 1; i < 8; i += 2)
+			    if ((c + oc[i].x - offx >= 0) && (r + oc[i].y - offy >= 0) && (c + oc[i].x - offx < b2->w) && (r + oc[i].y - offy < b2->h))
+			      p2 = pbm_getpixel (b2->bitmap, c + oc[i].x - offx, r + oc[i].y - offy);
+			    else
+			      p2 = 0;
+			  if (p2 == p)
+			    same++;
+
+			  /* CSIS rule 2(iii) */
+			  if (same == 5)
+			    {
+			      return 10003;
+			    }
+			}
+		    }
+		}
+	    }
+      }
+
+  return totscratch;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/match.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/match.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/match.h	(revision 10506)
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * match.h -- Functions related to matching marks
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __MATCH_H
+#define __MATCH_H
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "utils.h"
+
+
+/*
+   #define NOT_SCREENED(b1,b2) ((abs(b1.w-b2.w)<=4) && (abs(b1.h-b2.h)<=4))
+ */
+
+#define NOT_SCREENED(b1,b2) ((abs(b1.xcen-b2.xcen)+abs(b1.ycen-b2.ycen))<=3)
+
+#define MATCH_VAL 1000
+#define MATCH(b1,b2) (CSIS_match(b1,b2))
+
+int XOR_match (marktype b1, marktype b2);
+int WXOR_match (marktype b1, marktype b2);
+int WAN_match (marktype b1, marktype b2);
+int PMS_match (marktype b1, marktype b2);
+int CSIS_match (marktype * b1, marktype * b2);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgbilevel.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgbilevel.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgbilevel.1	(revision 10506)
@@ -0,0 +1,116 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbilevel 1 \*(Dt CITRI
+.SH NAME
+mgbilevel \- compresses a bilevel image using a specified template
+.SH SYNOPSIS
+.B mgbilevel
+.B \-e
+[
+.B \-t
+.I \*(lqstring\*(rq
+]
+.I infile
+[
+.I \>compressed-outfile
+]
+.nf
+or
+.fi
+.B mgbilevel
+.B \-d
+.I compressed-infile
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+.B mgbilevel
+performs (up to) a two-stage template-based compression.  The
+user can specify the template to be used in the compression process.  The
+default template size is a two-stage template 22/10.  The compressed file
+contains the template type in the stream.  The output files are written
+to
+.IR stdout .
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-t\fP \fI\*(lqstring\*(rq\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-e
+Compresses
+.I infile
+using a template specified, and writes to
+.IR compressed-outfile .
+.TP
+.B \-d
+Decompresses
+.I compressed-infile
+using the template contained in the compressed file.  Writes to
+.IR outfile .
+.TP
+\fB\-t \fP\fI\*(lqstring\*(rq\fP
+This option specifies which template combination is to
+be used in the compression.  Five different characters
+can occur in the string: `.' for a pixel not
+included in the template, `p' for a pixel included in the 1st
+level template, `2' for a pixel included in the 2nd level
+template (a subset of the 1st level), `*' denoting the position
+of the
+.I current
+pixel, and a `;' denoting the end of each template line.
+The default template is a two-level 22/10 template:
+.IP
+.RS
+.nf
+\&.ppppp.;
+pp222pp;
+p22222p;
+p22*.\|.\|.;
+.fi
+.RE
+.IP
+This would be specified on the command line as:
+.nf
+\&\fB\-T\fP ".ppppp.;pp222pp;p22222p;p22*.\|.\|.;"
+.fi
+.TP
+.I infile
+This is the input
+.I .pbm
+file to be compressed.
+.TP
+.I outfile
+This is the decompressed
+.I .pbm
+file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgbilevel.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgbilevel.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgbilevel.c	(revision 10506)
@@ -0,0 +1,149 @@
+/**************************************************************************
+ *
+ * mgbilevel.c -- Program to compress/decompress bilevel images
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "utils.h"
+#include "pbmtools.h"
+#include "arithcode.h"
+#include "bilevel.h"
+
+
+
+static char default_template[] =
+{
+  ".ppppp.;"
+  "pp222pp;"
+  "p22222p;"
+  "p22*...;"
+};
+
+void 
+Encode_bitmap (marktype b, char template[])
+{
+  InitArithEncoding ();
+
+  bl_compress (b, template);
+
+  CloseDownArithEncoding ();
+}
+
+void 
+Decode_bitmap (marktype * b)
+{
+  InitArithDecoding ();
+
+  bl_decompress (b);
+
+  CloseDownArithDecoding ();
+}
+
+
+void 
+usage ()
+{
+  fprintf (stderr,
+	   "usage:\n"
+	   "       mgbilevel -e  [-t \"string\"]  infile      >compressed\n"
+	   "or\n"
+	   "       mgbilevel -d                 compressed  >outfile\n");
+  exit (1);
+}
+
+#define BUF_SIZE 65536
+
+void 
+main (int argc, char *args[])
+{
+  marktype d;
+  char *filename = NULL, *template = NULL;
+  Pixel **bitmap;
+  int encode = 0, decode = 0, i;
+  char buffer[BUF_SIZE];
+
+  if (argc < 2)
+    usage ();
+  template = default_template;
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (args[i], "-e") == 0)
+	encode = 1;
+      else if (strcmp (args[i], "-d") == 0)
+	decode = 1;
+      else if (strcmp (args[i], "-h") == 0)
+	usage ();
+      else if (strcmp (args[i], "-t") == 0)
+	{
+	  template = args[i + 1];
+	  i++;
+	}
+      else if (args[i][0] == '-')
+	error_msg (args[0], "unknown switch:", args[i]);
+      else if (!filename)
+	filename = args[i];
+      else
+	error_msg (args[0], "only specify 1 filename", "");
+    }
+  if (encode == decode)
+    {
+      fprintf (stderr, "You must specify either encode XOR decode.\n");
+      exit (1);
+    }
+
+  if (!filename)
+    {
+      fprintf (stderr, "You must specify a filename.\n");
+      exit (1);
+    }
+
+  if (encode)
+    {
+      bitmap = pbm_readnamedfile (filename, &d.w, &d.h);
+      if (bitmap == NULL)
+	error_msg (args[0], "problem reading bitmap", "");
+
+      arith_out = stdout;
+      setbuffer (stdout, buffer, BUF_SIZE);
+      magic_write (stdout, MAGIC_BILEVEL);
+      if (bitmap)
+	{
+	  d.bitmap = bitmap;
+	  Encode_bitmap (d, template);
+	}
+    }
+  else if (decode)
+    {
+      FILE *tpin;
+      tpin = fopen (filename, "rb");
+      if (!tpin)
+	error_msg ("mgbilevel", "Can't open file:", filename);
+      arith_in = tpin;
+      setbuffer (tpin, buffer, BUF_SIZE);
+      magic_check (tpin, MAGIC_BILEVEL);
+      Decode_bitmap (&d);
+      fclose (tpin);
+
+      setbuffer (stdout, buffer, BUF_SIZE);
+      pbm_writefile (stdout, d.bitmap, d.w, d.h);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgfelics.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgfelics.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgfelics.1	(revision 10506)
@@ -0,0 +1,103 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgfelics 1 \*(Dt CITRI
+.SH NAME
+mgfelics \- fast and efficient lossless image (de)compression
+.SH SYNOPSIS
+.B mgfelics
+.B \-e
+[
+.BI \-k " n"
+]
+.I infile
+[
+.I \>compressed-outfile
+]
+.br
+or
+.br
+.B mgfelics
+.B \-d
+.I compressed-infile
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+.B mgfelics
+is a lossless compression process which can (de)compress portable
+bitmap files in
+.I pgm
+format.
+.B mgfelics
+writes to
+.IR stdout .
+.SH OPTIONS
+.TP "\w'\fB\-k\fP \fIn\fP'u+2n"
+.BI \-k " n"
+An integer parameter (< 32) which controls the compression speed and
+ratio.  The value of
+.I n
+is included in the output stream, and therefore is not needed in the
+decompression stage.  The default value of
+.I n
+is equal to the number of bits required to represent each grey level.
+.TP
+.B \-e
+Encodes the file
+.IR infile ,
+sending the output to
+.IR stdout .
+.TP
+.B \-d
+Decodes the file from
+.IR compressed-infile ,
+sending the output to
+.IR stdout .
+.SH NOTE
+.B mgfelics
+uses a combination of adjusted binary and Rice codes, the choice of
+which for any given pixel depends on the environment as determined by
+the intensity values of neighbouring pixels.  The result is a very
+fast and lossless algorithm for compressing grayscale images.  The
+optional parameter
+.BI \-k " n"
+corresponds to the maximum exponent of the same name in Rice encoding.
+Smaller values of
+.BI \-k " n"
+can result in significant improvement in compression times with a
+corresponding loss in compression ratio.  However the reduction in
+compression ratio with a small
+.BI \-k " n"
+parameter may be insignificant for many images.
+.SH REFERENCES
+Algorithm by Paul G. Howard and Jeffrey Scott Vitter
+of Brown University, RI, and Duke University, NC, respectively.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgfelics.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgfelics.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgfelics.c	(revision 10506)
@@ -0,0 +1,155 @@
+/**************************************************************************
+ *
+ * mgfelics.c -- Program to compress/decompress grey scale images
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "utils.h"
+
+
+#define MAXKVALUE 32
+
+
+
+void encode (unsigned int *line, int width, int height, int maxval, int maxk,
+	     FILE * fp_in, FILE * fp_out, int (*get) (FILE *));
+
+void decode (unsigned int *line, int width, int height, int maxval, int maxk,
+	     FILE * fp_in, FILE * fp_out);
+
+
+void 
+usage (char *prog)
+{
+  fprintf (stderr, "usage:\n");
+  fprintf (stderr, "\t%s -e [-k n]   infile    [>compressed]\n"
+	   "or\n"
+	   "\t%s -d  compressed-infile   [>outfile]\n", prog, prog);
+  exit (1);
+}
+
+
+
+
+int 
+main (int argc, char **argv)
+{
+  FILE *fp_in = (stdin), *fp_out = (stdout);
+  int width, height, maxval;
+  u_long magic;
+  char *filename = NULL;
+  unsigned int *line;
+  int maxk = 0;
+  int i;
+  int encode_flag = 0, decode_flag = 0;
+
+  if (argc < 2)
+    usage (argv[0]);
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (argv[i], "-h"))
+	usage (argv[0]);
+      else if (!strcmp (argv[i], "-e"))
+	encode_flag = 1;
+      else if (!strcmp (argv[i], "-d"))
+	decode_flag = 1;
+      else if (!strcmp (argv[i], "-k"))
+	{
+	  maxk = atoi (argv[++i]);
+	}
+      else if (argv[i][0] == '-')
+	error_msg (argv[0], "unknown switch:", argv[i]);
+      else if (!filename)
+	filename = argv[i];
+      else
+	error_msg (argv[0], "too many filenames specified.", "");
+    }
+
+  if (encode_flag == decode_flag)
+    error_msg (argv[0], "please specify either encode XOR decode.", "");
+
+  if (!filename)
+    error_msg (argv[0], "please specify a filename.", "");
+
+  if ((encode_flag) && (maxk >= MAXKVALUE))
+    {				/* to fit into 32 bit integers */
+      fprintf (stderr, "%s: k value of %d is too large; it must be less than %d\n",
+	       argv[0], maxk, MAXKVALUE);
+      exit (1);
+    }
+
+
+  if ((fp_in = fopen (filename, "rb")) == NULL)
+    error_msg (argv[0], "unable to open file:", filename);
+
+  /* read file header to determine the type and dimensions */
+
+
+  magic = magic_read (fp_in);
+  if (magic != MAGIC_FELICS)
+    {
+      rewind (fp_in);
+      magic = getmagicno_short_pop (fp_in);
+    }
+
+  if ((decode_flag && (magic != MAGIC_FELICS)) ||
+      (encode_flag && ((magic != MAGIC_P2) && (magic != MAGIC_P5))))
+    {
+      fclose (fp_in);
+      error_msg (argv[0], encode_flag ? "only PGM files can be used." : "only felics compressed files can be used.", "");
+    }
+
+  width = gethint (fp_in);
+  height = gethint (fp_in);
+  maxval = gethint (fp_in);
+
+  if ((line = (unsigned int *) malloc (width * sizeof (int *))) == NULL)
+    {
+      fclose (fp_in);
+      error_msg (argv[0], "unable to allocate memory,", "");
+    }
+
+
+  if (encode_flag)
+    {
+      magic_write (fp_out, MAGIC_FELICS);
+      fprintf (fp_out, "%d\n%d\n%d\n%d\n", width, height, maxval, maxk);
+      encode (line, width, height, maxval, maxk, fp_in, fp_out,
+	      magic == MAGIC_P2 ? getint : fgetc);
+    }
+  else if (decode_flag)
+    {
+      if (maxk)
+	warn (argv[0], "k value not required for decompression, ignored.", "");
+
+      maxk = gethint (fp_in);
+      fprintf (fp_out, "P%d\n%d %d\n%d\n", maxval < 256 ? 5 : 2,
+	       width, height, maxval);
+      decode (line, width, height, maxval, maxk, fp_in, fp_out);
+    }
+
+
+  fclose (fp_in);
+  fclose (fp_out);
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgtic.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgtic.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgtic.1	(revision 10506)
@@ -0,0 +1,137 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgtic 1 \*(Dt CITRI
+.SH NAME
+mgtic \- textual image compression.
+.SH SYNOPSIS
+.B mgtic
+.B \-e
+[
+.B \-L
+]
+[
+.B \-Q
+]
+[
+.B \-X
+]
+.I libraryfile
+.I infile
+.if n .ti +9n
+[
+.I \>compressed\-outfile
+]
+.nf
+or
+.fi
+.B mgtic
+.B \-d
+[
+.B \-L
+]
+[
+.BI \-X " libraryfile"
+]
+.I compressed-infile
+.if n .ti +9n
+[
+.I \>outfile
+]
+.SH DESCRIPTION
+This is the main routine in the
+.B mgtic
+system.
+.B mgtic
+is used to
+processes a series of files, and by using the
+.I libraryfile
+produced by
+.BR mgticbuild (1),
+compresses input files with respect to the marks contained in the
+library.  On the CCITT test faxes, lossless mode achieved around 20:1
+compression, and lossy, around 40:1 compression.  On more textual
+images, the amount of compression is determined by the resolution of
+the original file, and the amount of noise in the image.  By default,
+.B mgtic
+will reconstruct a lossy version of the image.  This
+can be changed to lossless by using the
+.B \-L
+option.
+.SH OPTIONS
+Options may appear in any order, but must come before the input
+filenames.
+.TP "\w'\fB\-X\fP \fI[libraryfile]\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-e
+Encode
+.I infile
+with respect to the library.
+.TP
+.B \-d
+Decodes
+.IR compressed-infile
+with respect to the library.
+.TP
+.B \-l
+This specifies lossy mode, and is the default mode for (de)compression.
+Do not generate the residue.  If used in encoding mode, does not store
+the residue in the output.  If used in decoding mode, the residue (if
+it exists) is ignored.
+.TP
+.B \-L
+Use lossless mode for (de)compression, which generates the residue.
+If used in encoding mode, this stores the residue in the compressed
+output.  If used in decoding mode (assuming the residue is present),
+this allows the original file to be recovered exactly.
+.TP
+.BI \-R\  filename
+Stores the residue as an external file
+.I filename
+which could possibly be stored on another medium.  During
+decompression, if the residue file specified does not relate to the
+compressed file, the resulting decompressed image will be a mess.
+Note that only the width and height of the residue image is checked.
+.TP
+.BI \-Q
+Uses a quicker form of compression.  This option decreases the time
+spent looking for a good match during encoding.  On average this
+option decreases compression ratios, but increases compression speed.
+.TP
+.BI \-X " [libraryfile]"
+Use an external library file, instead of (de)compressing the library
+within the normal stream.  When decoding, the
+.B \-X
+option must be followed by the
+.IR libraryfile .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgtic.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgtic.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgtic.c	(revision 10506)
@@ -0,0 +1,596 @@
+/**************************************************************************
+ *
+ * mgtic.c -- Program to compress/decompress textual images
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************
+ *
+ * This file is the basis of mgtic, which compresses the components of an
+ * image. 
+ * The compressed file contains the following sections:
+ *         mgtic magic_no
+ *         mgtic version
+ *         lossy/lossless flag 
+ *         internal/external library flag 
+ *         cols, rows, number of marks, library size
+ *         [library sequence]
+ *         symbol sequence
+ *         offset sequence
+ *         [residue bitmap]
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+#include "match.h"
+#include "sortmarks.h"
+#include "codesyms.h"
+#include "arithcode.h"
+#include "codeoffsets.h"
+#include "bilevel.h"
+
+static char library_template[] =
+{
+  ".ppppp.;"
+  "pp222pp;"
+  "p22222p;"
+  "p22*...;"
+};
+
+void 
+usage ()
+{
+  fprintf (stderr, "usage: \n"
+	"\tmgtic -e [-L] [-Q] [-X]  libraryfile   infile    [>compressed]\n"
+	   "or\n"
+	   "\tmgtic -d [-L] [-X libraryfile]  compressed  [>outfile]\n");
+  exit (1);
+}
+
+
+/* encode the list of marks 'list', w.r.t. the library 'library' */
+void 
+match_sequence (marklistptr list, marklistptr library, marklistptr * symbol_list, Pixel ** recon, int quick)
+{
+  int carryx, carryy, gap;
+  int lastx = 0, lasty = 0;
+  int i, j;
+  marktype d, d2;
+  marklistptr liststep, librarystep;
+  int score, found;
+  int r, c;
+  int p;
+
+  carryx = carryy = 0;
+  gap = max (1, marklist_length (list) / 10);
+
+  for (liststep = list, i = 0; liststep; liststep = liststep->next, i++)
+    {
+      if (V)
+	if (!(i % gap))
+	  fprintf (stderr, ".");
+      d = liststep->data;
+
+      found = -1;
+      score = INT_MAX;
+      for (librarystep = library, j = 0; librarystep; librarystep = librarystep->next, j++)
+	{
+	  d2 = librarystep->data;
+
+	  if (NOT_SCREENED (d2, d))
+	    if ((p = MATCH (&d, &d2)) < MATCH_VAL)
+	      {
+		if (p < score)
+		  {
+		    score = p;
+		    found = j;
+		    if (quick)
+		      break;
+		  }
+	      }
+	}
+      /*
+         if(found<0){
+         for(librarystep=library,j=0; librarystep; librarystep=librarystep->next,j++){
+         d2=librarystep->data;
+
+         if((p=MATCH(&d,&d2))<MATCH_VAL){
+         if(p<score){
+         score=p;found=j; if(quick) break;
+         }
+         }
+         }
+         }
+       */
+      if (found >= 0)
+	{
+	  liststep->data.symnum = found;
+	  marklist_getat (library, found, &d2);
+	  d2.symnum = found;
+
+	  d2.xoffset = d.xpos - lastx + carryx;		/* propagate changes to next mark */
+	  d2.yoffset = d.ypos - lasty + carryy;
+	  carryx = (d2.xcen - d.xcen);	/* offet centroids because thats where we match them! */
+	  carryy = (d2.ycen - d.ycen);
+	  d2.xoffset -= carryx;	/* make the changes to this mark */
+	  d2.yoffset -= carryy;
+	  lastx = d.xpos + d2.w;
+	  lasty = d.ypos;
+
+	  marklist_add (symbol_list, d2);
+
+	  /* add to the reconstructed image--this is the lossy version */
+	  for (r = 0; r < d2.h; r++)
+	    for (c = 0; c < d2.w; c++)
+	      if (pbm_getpixel (d2.bitmap, c, r))
+		pbm_putpixel_trunc (recon, d.xpos + c - carryx, d.ypos + r - carryy, 1, d2.w, d2.h);
+	}
+      else
+	{
+	  /* didn't match at all..hopefully noise */
+	  if ((liststep->data.w >= 10) || (liststep->data.w >= 10))
+	    {
+	      fprintf (stderr, "mgtic: warning, unable to match a char.\n");
+	      write_library_mark (stderr, liststep->data);
+	    }
+	  if (V)
+	    fprintf (stderr, "x");
+	  liststep->data.symnum = -1;
+	}
+    }
+  if (V)
+    fprintf (stderr, "\n");
+}
+
+
+
+
+void 
+main (int argc, char *args[])
+{
+  int i, n, r, c, ch;
+  FILE *inf;
+  marklistptr library = NULL, list = NULL, step = NULL;
+  marklistptr symbol_list = NULL;
+  marktype d, d2;
+  Pixel **bitmap, **recon, **bitmapcopy;
+  char *splitfilename = NULL;
+  int cols, rows, count, librarysize, lossy = 1;
+  int quick = 0;
+  int ticencode = 0, ticdecode = 0, external = 0;
+  char *libraryname = NULL, *infile = NULL;
+  char *s1 = NULL, *s2 = NULL;
+  char bufferin[BUFSIZ], bufferout[BUFSIZ];
+
+  if (argc < 2)
+    usage ();
+
+  while ((ch = getopt (argc, args, "edlLQhvXR:")) != -1)
+    switch (ch)
+      {
+      case 'e':
+	ticencode = 1;
+	break;
+      case 'd':
+	ticdecode = 1;
+	break;
+      case 'l':
+	lossy = 1;
+	break;
+      case 'L':
+	lossy = 0;
+	break;
+      case 'Q':
+	quick = 1;
+	break;
+      case 'v':
+	V = 1;
+	break;
+      case 'X':
+	external = 1;
+	break;
+      case 'R':
+	splitfilename = optarg;
+	break;
+      case 'h':
+      case '?':
+	usage ();
+      }
+
+  for (i = 1; i < argc; i++)
+    if (args[i][0] != '-')
+      if (strcmp (args[i - 1], "-R"))
+	{			/* ignore arg following -R, ie. -R <filename> */
+	  if (!s1)
+	    s1 = args[i];
+	  else if (!s2)
+	    s2 = args[i];
+	  else
+	    error_msg (args[0], "too many filenames", "");
+	}
+
+  if (ticencode == ticdecode)
+    error_msg (args[0], "please specify either encode XOR decode", "");
+
+  if (ticencode)
+    {
+	  /*****************
+	    ENCODING STAGE
+	  *****************/
+      long PrevBits = 0;
+      long BITS_header = 0, BITS_symbols = 0, BITS_offsets = 0, BITS_residue = 0,
+        BITS_footer = 0, BITS_library = 0;
+
+      libraryname = s1;
+      if (!libraryname)
+	error_msg (args[0], "please specify a library file", "");
+      infile = s2;
+      if (!infile)
+	error_msg (args[0], "please specify a file name", "");
+
+      inf = fopen (infile, "rb");
+      if (inf == NULL)
+	error_msg (args[0], "Trouble opening file:", infile);
+      setbuf (inf, bufferin);
+
+      count = librarysize = read_library (libraryname, &library);
+
+      if (V)
+	fprintf (stderr, "%s: processing...\n", args[0]);
+
+      if (pbm_isapbmfile (inf))
+	{
+	  if (V)
+	    fprintf (stderr, "reading file %s...\n", infile);
+	  bitmap = pbm_readfile (inf, &cols, &rows);
+	  fclose (inf);
+
+	  bitmapcopy = pbm_copy (bitmap, cols, rows);
+
+	  if (V)
+	    fprintf (stderr, "extracting...");
+	  ExtractAllMarks (bitmap, &list, cols, rows);
+	  if (V)
+	    fprintf (stderr, "(%d marks)\n", marklist_length (list));
+
+	  /* sort into reading order */
+	  if (V)
+	    fprintf (stderr, "sorting...\n");
+	  list = sortmarks (list);
+
+	  pbm_freearray (&bitmap, rows);	/* clear old version */
+	  bitmap = bitmapcopy;	/* point to the copy */
+	  recon = pbm_allocarray (cols, rows);
+
+	  if (V)
+	    fprintf (stderr, "matching...");
+
+	  match_sequence (list, library, &symbol_list, recon, quick);
+
+
+	  PrevBits = 0;
+	  setbuf (stdout, bufferout);
+	  /* start output */
+	  magic_write (stdout, MAGIC_TIC);
+	  InitArithEncoding ();
+
+	  EncodeGammaDist (1);	/* version 1 of the program */
+	  EncodeGammaDist (lossy);	/* lossy=1 = no residue */
+	  EncodeGammaDist (external);	/* 1== external file */
+
+	  count = marklist_length (symbol_list);
+	  if (V)
+	    fprintf (stderr, "encoding cols, rows, and number of symbols=%d\n", count);
+
+	  EncodeGammaDist (cols);
+	  EncodeGammaDist (rows);
+	  EncodeGammaDist (count);
+	  EncodeGammaDist (librarysize);
+
+	  BITS_header = CountOfBitsOut - PrevBits;
+	  PrevBits = CountOfBitsOut;
+
+
+	  /* output the library sequence */
+	  if (external == 0)
+	    {
+	      if (V)
+		fprintf (stderr, "encoding library\n");
+
+	      bl_clearmodel ();
+	      bl_writetemplate (library_template);
+	      for (step = library; step; step = step->next)
+		bl_compress_mark (step->data);
+	      bl_freemodel ();
+	      BITS_library = CountOfBitsOut - PrevBits;
+	      PrevBits = CountOfBitsOut;
+	    }
+
+	  /* output the symbol sequence */
+	  if (V)
+	    fprintf (stderr, "encoding symbol sequence\n");
+	  InitPPM ();
+	  EncodeSymbols (symbol_list, count);
+	  BITS_symbols = CountOfBitsOut - PrevBits;
+	  PrevBits = CountOfBitsOut;
+
+
+	  /* output the offset sequence */
+	  if (V)
+	    fprintf (stderr, "encoding offset sequence\n");
+	  EncodeOffsets (symbol_list, count);
+	  BITS_offsets = CountOfBitsOut - PrevBits;
+	  PrevBits = CountOfBitsOut;
+
+	  EncodeChecksum ();	/* code lossy checksum */
+
+	  /* calculate the residue...and compress it---if need be! */
+	  if (!lossy)
+	    {
+	      if (V)
+		fprintf (stderr, "encoding residue...\n");
+
+	      d.bitmap = bitmap;
+	      d.h = rows;
+	      d.w = cols;
+	      d2.bitmap = recon;
+	      d2.h = rows;
+	      d2.w = cols;
+
+	      if (splitfilename)
+		{
+		  FILE *temp;
+
+		  CloseDownArithEncoding ();
+		  fclose (stdout);
+		  /* no residue result */
+		  BITS_footer = CountOfBitsOut - PrevBits;
+
+		  temp = fopen (splitfilename, "wb");
+		  if (temp == NULL)
+		    error_msg (args[0], "Trouble creating file:", splitfilename);
+
+		  arith_out = temp;
+		  InitArithEncoding ();
+		  bl_clair_compress (d, d2);
+		  CloseDownArithEncoding ();
+		  BITS_residue = CountOfBitsOut;
+		  fclose (temp);
+		}
+	      else
+		{
+		  bl_clair_compress (d, d2);
+		  BITS_residue = CountOfBitsOut - PrevBits;
+		  PrevBits = CountOfBitsOut;
+		  EncodeChecksum ();	/* code lossless checksum */
+		  CloseDownArithEncoding ();
+		  BITS_footer = CountOfBitsOut - PrevBits;
+		}
+	    }
+	  else
+	    {
+	      if (V)
+		fprintf (stderr, "not encoding residue..lossy mode\n");
+	      CloseDownArithEncoding ();
+	      BITS_footer = CountOfBitsOut - PrevBits;
+	    }
+
+	  /* because we edit the values above */
+	  CountOfBitsOut = BITS_header + BITS_library + BITS_symbols + BITS_offsets + BITS_residue + BITS_footer;
+
+	  fprintf (stderr, "bits: header=%ld, library=%ld, "
+		   "symbols=%ld, offsets=%ld, residue=%ld, footer=%ld\n",
+		   BITS_header, BITS_library, BITS_symbols,
+		   BITS_offsets, BITS_residue, BITS_footer);
+	  fprintf (stderr, "total bits: %ld, ", CountOfBitsOut);
+	  fprintf (stderr, "Lossy CR: %4.2f", (cols * rows) / (float) (CountOfBitsOut - BITS_residue));
+	  if (external)
+	    fprintf (stderr, " (excluding external lib)");
+	  fprintf (stderr, ", Lossless CR: %4.2f\n", (!lossy) * (cols * rows) / (float) (CountOfBitsOut));
+	}
+      else
+	error_msg (args[0], "unknown format of bitmap--expecting PBM.", "");
+    }
+  else
+    {
+	  /*****************
+	    DECODING STAGE
+	  *****************/
+      int lastx, lasty;
+      librarysize = 0;
+
+      if (external)
+	{
+	  libraryname = s1;
+	  infile = s2;
+	  count = librarysize = read_library (libraryname, &library);
+	}
+      else
+	{
+	  infile = s1;
+	  if (infile && s2)
+	    error_msg (args[0], "too many filenames", "");
+	}
+
+      if (!freopen (infile, "rb", stdin))
+	error_msg (args[0], "Trouble opening file:", infile);
+
+
+      if (V)
+	fprintf (stderr, "decompressing...\n");
+
+      setbuf (stdin, bufferin);
+      magic_check (stdin, MAGIC_TIC);
+
+      InitArithDecoding ();
+
+      {
+	int version = DecodeGammaDist ();
+	if (version != 1)
+	  error_msg (args[0], "Need later version of decompressor.", "");
+      }
+
+      {
+	int templossy = DecodeGammaDist ();
+	if (!lossy)
+	  lossy = templossy;	/* can only choose if encoded file is lossless */
+	if (V)
+	  {
+	    if (lossy)
+	      fprintf (stderr, "lossy mode\n");
+	    else
+	      fprintf (stderr, "lossless mode\n");
+	  }
+      }
+
+      if (DecodeGammaDist ())
+	{			/* if compressed file doesn't contain library */
+	  if (!external)
+	    error_msg (args[0], "compressed file doesn't contain library, specify externally", "");
+	  external = 1;
+	}
+      else
+	{			/* if compressed file contains library */
+	  if (external)
+	    fprintf (stderr, "ignoring external library file\n");
+	  external = 0;
+	}
+
+      cols = DecodeGammaDist ();
+      rows = DecodeGammaDist ();
+      count = DecodeGammaDist ();
+
+      i = DecodeGammaDist ();	/* librarysize */
+      if (external)
+	{
+	  if (i > librarysize)
+	    error_msg (args[0], "external library file is too small!", "");
+	  else if (i < librarysize)
+	    fprintf (stderr, "%s: warning, expecting a different (smaller) library.\n", args[0]);
+	}
+      librarysize = i;
+
+      if (V)
+	fprintf (stderr, "cols %d, rows %d, num syms %d, library size %d\n", cols, rows, count, librarysize);
+
+      /* decode library */
+      if (external == 0)
+	{
+	  if (V)
+	    fprintf (stderr, "reading library\n");
+	  bl_clearmodel ();
+	  bl_readtemplate ();
+	  for (n = 0; n < librarysize; n++)
+	    {
+	      bl_decompress_mark (&d);
+	      d.symnum = n;
+	      if (library == NULL)
+		step = marklist_add (&library, d);
+	      else
+		step = marklist_add (&step, d);
+	    }
+	  bl_freemodel ();
+	  if (V)
+	    fprintf (stderr, "read %d marks from library\n", marklist_length (library));
+	}
+
+      recon = pbm_allocarray (cols, rows);
+
+      /* decode symbols */
+      InitPPM ();
+      if (V)
+	fprintf (stderr, "decompressing %d symbols\n", count);
+      symbol_list = DecodeSymbols (count);
+
+      /* decode offsets */
+      if (V)
+	fprintf (stderr, "reading offsets...\n");
+      DecodeOffsets (symbol_list, count);
+      lastx = lasty = 0;
+      for (step = symbol_list; step; step = step->next)
+	{
+	  lastx = lastx + step->data.xoffset;
+	  lasty = lasty + step->data.yoffset;
+
+	  marklist_getat (library, step->data.symnum, &d2);
+	  for (r = 0; r < d2.h; r++)
+	    for (c = 0; c < d2.w; c++)
+	      if (pbm_getpixel (d2.bitmap, c, r))
+		pbm_putpixel_trunc (recon, lastx + c, lasty + r, 1, cols, rows);	/* we don't care, already warned them! */
+	  lastx += d2.w;
+	}
+
+      DecodeChecksum (args[0]);
+
+      /* decode the residue */
+      if (!lossy)
+	{
+	  if (V)
+	    fprintf (stderr, "decoding residue...\n");
+
+	  bitmap = pbm_allocarray (cols, rows);
+	  d.bitmap = bitmap;
+	  d.w = d2.w = cols;
+	  d.h = d2.h = rows;
+
+	  d2.bitmap = recon;
+
+	  /* NOTE: the 2nd argument is clairvoyantly compressed */
+	  if (splitfilename)
+	    {
+	      FILE *temp;
+
+	      CloseDownArithDecoding ();
+	      fclose (stdin);
+
+	      temp = fopen (splitfilename, "rb");
+	      if (temp == NULL)
+		error_msg (args[0], "Trouble opening file:", splitfilename);
+
+	      arith_in = temp;
+	      InitArithDecoding ();
+	      bl_clair_decompress (d, d2);
+	      CloseDownArithDecoding ();
+	      fclose (temp);
+	    }
+	  else
+	    {
+	      bl_clair_decompress (d, d2);
+	      DecodeChecksum (args[0]);
+	      CloseDownArithDecoding ();
+	    }
+	  pbm_freearray (&recon, rows);
+	  recon = bitmap;	/* point to the bitmap */
+	}
+      else
+	{
+	  CloseDownArithDecoding ();
+	}
+
+      if (V)
+	fprintf (stderr, "writing pbm file...\n");
+      setbuf (stdout, bufferout);
+      pbm_writefile (stdout, recon, cols, rows);
+      pbm_freearray (&recon, rows);
+    }				/* end decoding */
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticbuild.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticbuild.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticbuild.1	(revision 10506)
@@ -0,0 +1,61 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticbuild 1 \*(Dt CITRI
+.SH NAME
+mgticbuild \- build a library of marks from training documents
+.SH SYNOPSIS
+.B mgticbuild
+[
+.B \-h
+]
+.I "libraryfile infile1 infile2 .\|.\|."
+.SH DESCRIPTION
+.B mgticbuild
+builds an uncompressed library of marks that have been
+extracted from a series of input files.  If the
+.I libraryfile
+does
+not exist, it is created, otherwise new marks are appended to the
+file.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.TP
+.I infile(s)
+The training files; the only currently-supported format is
+.IR pbm .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticbuild.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticbuild.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticbuild.c	(revision 10506)
@@ -0,0 +1,145 @@
+/**************************************************************************
+ *
+ * mgticbuild.c -- Program to build the textual image library
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+
+
+void 
+usage ()
+{
+  fprintf (stderr, "usage: \n"
+	"\tmgticbuild   libraryfile   infile.pbm  [infile2 infile3 ...]\n");
+  exit (1);
+}
+
+void 
+main (int argc, char *args[])
+{
+  int i;
+  FILE *lib = NULL, *inf = NULL;
+  marklistptr list = NULL, step;
+  Pixel **bitmap;
+  int cols, rows;
+  int count, pos = 0;
+  char *libraryname = NULL;
+
+  if (argc < 2)
+    usage ();
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (args[i], "-v"))
+	V = 1;
+      else if (!strcmp (args[i], "-h"))
+	usage ();
+      else if (args[i][0] == '-')
+	error_msg (args[0], "unknown switch:", args[i]);
+      else if (!libraryname)
+	libraryname = args[i];
+      else
+	pos = i;
+    }
+
+  if (!libraryname)
+    error_msg (args[0], "please specify a library file", "");
+  if (pos < 2)
+    usage ();
+
+  count = 0;
+  for (i = pos; i < argc; i++)
+    if (args[i][0] != '-')
+      {
+	inf = fopen (args[i], "rb");
+	count = 0;
+	if (inf == NULL)
+	  fprintf (stderr, "Trouble opening file: %s\n", args[i]);
+	else
+	  {
+	    if (pbm_isapbmfile (inf))
+	      {
+		if (V)
+		  fprintf (stderr, "%s: processing...\n", args[0]);
+		if (V)
+		  fprintf (stderr, "reading file %s...", args[i]);
+		bitmap = pbm_readfile (inf, &cols, &rows);
+		if (V && (count == 0))
+		  fprintf (stderr, "building...");
+
+		list = NULL;
+
+		ExtractAllMarks (bitmap, &list, cols, rows);
+
+		if (V)
+		  fprintf (stderr, "writing...");
+
+		if ((!lib) && (marklist_length (list)))
+		  {
+		    lib = fopen (libraryname, "r");
+		    if (lib)
+		      {
+			fclose (lib);
+			lib = fopen (libraryname, "ab");
+			if (lib == NULL)
+			  error_msg (args[0], "trouble appending library file", "");
+			fprintf (stderr, "\nwarning: appending library file: %s\n", libraryname);
+		      }
+		    else
+		      {
+			lib = fopen (libraryname, "wb");
+			if (lib == NULL)
+			  error_msg (args[0], "trouble creating library file", "");
+		      }
+		  }		/* if !lib */
+
+		step = list;
+		while (step)
+		  {
+		    step->data.symnum = count;
+		    write_library_mark (lib, step->data);
+		    count++;
+		    step = step->next;
+		  }
+		pbm_freearray (&bitmap, rows);
+	      }
+	    else
+	      fprintf (stderr, "warning: %s is not a PBM file.\n", args[i]);
+	    fclose (inf);
+	  }
+	if (count)
+	  {
+	    if (V)
+	      fprintf (stderr, "%d marks written.\n", count);
+	  }
+	else
+	  fprintf (stderr, "No marks written!\n");
+      }
+
+  if (lib)
+    fclose (lib);
+  marklist_free (&list);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticdump.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticdump.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticdump.1	(revision 10506)
@@ -0,0 +1,55 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticdump 1 \*(Dt CITRI
+.SH NAME
+mgticdump \- displays the library in a user-friendly manner
+.SH SYNOPSIS
+.B mgticdump
+[
+.B \-h
+]
+.I libraryfile
+.SH DESCRIPTION
+.B mgticdump
+displays the marks in a library in a user-viewable form.  The output
+is to
+.I stdout
+and is in a plain ASCII form.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticdump.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticdump.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticdump.c	(revision 10506)
@@ -0,0 +1,86 @@
+/**************************************************************************
+ *
+ * mgticdump.c -- Program to dump out a library in a human readable form
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+
+
+void 
+usage ()
+{
+  fprintf (stderr, "usage:\n"
+	   "\tmgticdump   libraryfile\n");
+  exit (1);
+}
+
+
+
+void 
+main (int argc, char *args[])
+{
+  FILE *lib;
+  int count, i;
+  marktype d;
+  char *libraryname = NULL;
+  FILE *outf = (stdout);
+
+  if (argc < 2)
+    usage ();
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (args[i], "-h"))
+	usage ();
+      else if (args[i][0] == '-')
+	error_msg (args[0], "unknown switch:", args[i]);
+      else if (!libraryname)
+	libraryname = args[i];
+      else
+	error_msg (args[0], "too many filenames", "");
+    }
+
+  if (!libraryname)
+    error_msg (args[0], "please specify a library file", "");
+
+
+  lib = fopen (libraryname, "rb");
+  if (lib == NULL)
+    error_msg (args[0], "trouble opening library file:", libraryname);
+
+  count = 0;
+  while (!isEOF (lib))
+    {
+      read_library_mark (lib, &d);
+
+      write_library_mark (outf, d);
+      count++;
+
+      pbm_freearray (&d.bitmap, d.h);
+    }
+  fprintf (stderr, "count=%d", count);
+  fclose (lib);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticprune.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticprune.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticprune.1	(revision 10506)
@@ -0,0 +1,91 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticprune 1 \*(Dt CITRI
+.SH NAME
+mgticprune \- prunes the library to remove duplicates
+.SH SYNOPSIS
+.B mgticprune
+[
+.BI \-a " n"
+]
+[
+.BI \-s " n"
+]
+[
+.B \-Q
+]
+.I libraryfile
+.if n .ti +9n
+[
+.I pruned-libraryfile
+]
+.SH DESCRIPTION
+.B mgticprune
+examines
+.I libraryfile
+and removes duplicate marks.  If
+.I pruned-libraryfile
+is not specified,
+.I libraryfile
+is overwritten with the marks in the pruned library.  The Combined
+Symbol Independent Strategy (CSIS) method is used to match marks.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIpruned-libraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-a " n"
+Prune marks when their area is under or equal to the threshold,
+.IR n .
+The default value is\ 3.
+.TP
+.BI \-s " n"
+Prune marks when their width and height is under or equal to
+the threshold,
+.IR n .
+The default value is\ 0.
+.TP
+.BI \-Q
+Use a quicker method of pruning.  The number of iterations through the
+averaging and pruning processes is decreased.  This usually reduces
+time by a half, but compression ratios decrease.
+.TP
+.I libraryfile
+This specifies the name of the library file
+.TP
+.I pruned-libraryfile
+This specifies the name of the prune library, after duplicates and
+matches have been removed.  If this file is not specified, then
+.I libraryfile
+will be overwritten.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticprune.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticprune.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticprune.c	(revision 10506)
@@ -0,0 +1,393 @@
+/**************************************************************************
+ *
+ * mgticprune.c -- Program to prune a textual image library
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+#include "match.h"
+
+marklistptr *avglib = NULL;
+int avglibsize;
+int libsize = 0;
+
+
+void 
+usage ()
+{
+  fprintf (stderr, "usage:\n"
+    "\tmgticbuild [-a n]  [-s n]  [-Q]   libraryfile   [pruned-library]\n");
+  exit (1);
+}
+
+
+
+
+/* foreach list in the avglib[] array, an average mark is returned */
+marklistptr 
+average_library ()
+{
+  marklistptr librarylist;
+  int i;
+  marktype avgmark;
+
+  librarylist = NULL;
+  for (i = 0; i < libsize; i++)
+    {
+      if (avglib[i])
+	{
+	  marklist_average (avglib[i], &avgmark);
+	  avgmark.symnum = i;
+	  marklist_addcopy (&librarylist, avgmark);
+	}
+    }
+  return librarylist;
+}
+
+
+void 
+average_space_enlarge ()
+{
+  int j;
+
+  if (libsize >= avglibsize)
+    {
+      avglib = (marklistptr *) realloc (avglib, (avglibsize + 100) * sizeof (marklistptr));
+      if (!avglib)
+	error_msg ("mgticprune", "out of memory in reallocating..", "");
+      for (j = avglibsize; j < avglibsize + 100; j++)
+	avglib[j] = NULL;
+      avglibsize += 100;
+    }
+}
+
+
+/* for each mark in 'origlist', if it can't be matched with one in 
+   'librarylist', then add to the librarylist, and update the relevant
+   avglib[] position */
+void 
+greedy_add (marklistptr origlist, marklistptr * librarylist)
+{
+  marklistptr step, step_i;
+  int i, j, notfound;
+  marktype d_i;
+
+  for (i = 0, step_i = origlist; step_i; i++, step_i = step_i->next)
+    {
+      d_i = step_i->data;
+
+      notfound = 1;
+      for (j = 0, step = *librarylist; step; j++, step = step->next)
+	{
+	  if (NOT_SCREENED (d_i, step->data))
+	    if (MATCH (&d_i, &step->data) < MATCH_VAL)
+	      {
+		d_i.symnum = j;
+		marklist_addcopy (&avglib[j], d_i);
+		notfound = 0;
+		break;
+	      }
+	}
+
+      if (notfound)
+	{
+	  d_i.symnum = libsize;
+	  marklist_addcopy (librarylist, d_i);
+	  marklist_addcopy (&avglib[libsize], d_i);
+	  libsize++;
+	  if (libsize >= avglibsize)
+	    average_space_enlarge ();
+	}
+    }
+}
+
+
+
+/* for each mark in 'library', if another matches with it, remove
+   one copy from the library, and erase the relevant avglib[] */
+void 
+greedy_prune (marklistptr * library)
+{
+  int count;
+  int i, j;
+  marklistptr step;
+  marktype d;
+
+  count = marklist_length (*library);
+  /* an invariant, all marks <i have been kept in the pruned library */
+  for (i = 0; i < count; i++)
+    {
+      marklist_getat (*library, i, &d);
+
+      for (j = 0, step = *library; j < i; j++, step = step->next)
+	{
+	  if (NOT_SCREENED (d, step->data))
+	    if (MATCH (&d, &step->data) < MATCH_VAL)
+	      {
+		/* [i,d] has matched with library element [j,d2]. */
+		marklist_removeat (library, i);		/* because we kill it here */
+		marklist_free (&avglib[d.symnum]);
+		avglib[d.symnum] = NULL;
+		i--, count--;
+		break;
+	      }
+	}
+    }
+}
+
+
+void 
+prune_on_size (marklistptr * list, int sizethres)
+{
+  int count, i;
+  marktype d;
+
+  if (sizethres)
+    {
+      count = marklist_length (*list);
+      i = 0;
+      do
+	{
+	  marklist_getat (*list, i, &d);
+	  if ((d.w <= sizethres) && (d.h <= sizethres))
+	    {
+	      marklist_removeat (list, i);
+	      i--;
+	      count--;
+	    }
+	  i++;
+	}
+      while (i < count);
+    }
+}
+
+
+
+void 
+prune_on_area (marklistptr * list, int areathres)
+{
+  int count, i;
+  marktype d;
+
+  if (areathres)
+    {
+      count = marklist_length (*list);
+      i = 0;
+      do
+	{
+	  marklist_getat (*list, i, &d);
+	  if (d.set <= areathres)
+	    {
+	      marklist_removeat (list, i);
+	      i--;
+	      count--;
+	    }
+	  i++;
+	}
+      while (i < count);
+    }
+}
+
+
+void 
+averagedout_addagain (marklistptr origlist, marklistptr * librarylist)
+{
+  marklistptr step, stepi;
+  int notfound;
+  int i, j;
+
+  for (i = 0, step = origlist; step; i++, step = step->next)
+    {
+      notfound = 1;
+
+      for (j = 0, stepi = *librarylist; stepi; j++, stepi = stepi->next)
+	if (NOT_SCREENED (step->data, stepi->data))
+	  if (MATCH (&step->data, &stepi->data) < MATCH_VAL)
+	    {
+	      notfound = 0;
+	      break;
+	    }
+
+      if (notfound)
+	{
+	  marklist_addcopy (librarylist, step->data);
+	  marklist_addcopy (&avglib[libsize], step->data);
+	  libsize++;
+	  if (libsize >= avglibsize)
+	    average_space_enlarge ();
+	}
+    }
+}
+
+
+
+
+
+void 
+main (int argc, char *args[])
+{
+  int i;
+  FILE *lib;
+
+  marklistptr origlist = NULL, librarylist = NULL;
+  marklistptr step;
+  char tempn[1000], sysstr[1000];
+  int count;
+  char *libraryname = NULL, *prunename = NULL;
+  int sizethres = 3, areathres = 0;
+  int pass;
+  int num_passes = 3;
+  int overwrite = 0;
+
+  V = 0;
+
+  if (argc < 2)
+    usage ();
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (args[i], "-v"))
+	V = 1;
+      else if (!strcmp (args[i], "-h"))
+	usage ();
+      else if (!strcmp (args[i], "-Q"))
+	{
+	  num_passes = 0;
+	}
+      else if (!strcmp (args[i], "-s"))
+	{
+	  i++;
+	  if ((i < argc) && (isinteger (args[i])))
+	    sizethres = atoi (args[i]);
+	  else
+	    error_msg (args[0], "follow the -s option with a numeric arg >=0", "");
+	}
+      else if (!strcmp (args[i], "-a"))
+	{
+	  i++;
+	  if ((i < argc) && (isinteger (args[i])))
+	    areathres = atoi (args[i]);
+	  else
+	    error_msg (args[0], "follow the -a option with a numeric arg >=0", "");
+	}
+      else if (args[i][0] == '-')
+	error_msg (args[0], "unknown switch:", args[i]);
+      else if (!libraryname)
+	libraryname = args[i];
+      else if (!prunename)
+	prunename = args[i];
+      else
+	error_msg (args[0], "too many filenames", "");
+    }
+
+  if (!libraryname)
+    error_msg (args[0], "please specify a library file", "");
+
+  if (V)
+    fprintf (stderr, "%s: processing...\n", args[0]);
+
+  overwrite = 0;
+  if (!prunename)
+    {
+      prunename = libraryname;
+      if (V)
+	fprintf (stderr, "overwriting previous library file.\n");
+      overwrite = 1;
+    }
+
+  if (overwrite)
+    {
+      tmpnam (tempn);
+    }
+  else
+    strcpy (tempn, prunename);
+
+
+  avglibsize = count = read_library (libraryname, &origlist);
+  if (V)
+    fprintf (stderr, "%d marks...", count);
+
+  avglib = (marklistptr *) malloc (count * sizeof (marklistptr));
+  if (!avglib)
+    error_msg (args[0], "out of memory", "");
+  for (i = 0; i < avglibsize; i++)
+    avglib[i] = NULL;
+
+
+  prune_on_size (&origlist, sizethres);
+
+  prune_on_area (&origlist, areathres);
+  if (V)
+    fprintf (stderr, "after threshold pruning, %d marks\n", count = marklist_length (origlist));
+
+
+  if (V)
+    fprintf (stderr, "starting greedy library creation...\n");
+
+  greedy_add (origlist, &librarylist);
+
+
+  for (pass = 0; pass < num_passes; pass++)
+    {
+      marklist_free (&librarylist);
+      if (V)
+	fprintf (stderr, "averaging...\n");
+      librarylist = average_library ();
+      averagedout_addagain (origlist, &librarylist);
+      greedy_prune (&librarylist);
+      if (V)
+	fprintf (stderr, "after pass %d greedy prune %d marks\n", 1 + pass, marklist_length (librarylist));
+    }
+
+
+  lib = fopen (tempn, "wb");
+  if (lib == NULL)
+    error_msg (args[0], "trouble creating prune-library file.", "");
+
+
+  if (V)
+    fprintf (stderr, "writing to file: %s...", prunename);
+  for (step = librarylist, count = 0; step; step = step->next, count++)
+    {
+      step->data.symnum = count;
+      write_library_mark (lib, step->data);
+    }
+
+  if (V)
+    fprintf (stderr, "%d marks.\n", count);
+  fclose (lib);
+
+  if (overwrite)
+    {
+      sprintf (sysstr, "mv %s %s", tempn, prunename);
+      system (sysstr);		/* move temp to proper name */
+    }
+
+  for (i = 0; i < avglibsize; i++)
+    {
+      marklist_free (&avglib[i]);
+      free (avglib[i]);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticstat.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticstat.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticstat.1	(revision 10506)
@@ -0,0 +1,57 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgticstat 1 \*(Dt CITRI
+.SH NAME
+mgticstat \- displays the statistics for the library
+.SH SYNOPSIS
+.B mgticstat
+[
+.B \-h
+]
+.I libraryfile
+.SH DESCRIPTION
+.B mgticstat
+displays statistics about the
+.I libraryfile
+file.
+The output of this program contains the average mark size, average
+centroid position, and the number of marks with an area less than or
+equal to a few powers of\ 2.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fIlibraryfile\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.I libraryfile
+This specifies the name of the library file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticstat.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticstat.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/mgticstat.c	(revision 10506)
@@ -0,0 +1,130 @@
+/**************************************************************************
+ *
+ * mgticstat.c -- Program to print out stats about a textual image library
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+
+void 
+usage ()
+{
+  fprintf (stderr, "usage:\n"
+	   "\tmgticstat   libraryfile\n");
+  exit (1);
+}
+
+void 
+main (int argc, char *args[])
+{
+  FILE *lib, *outf = (stdout);
+  int count;
+  int small1, small2, small4, small9, small16, small25, small36, small49,
+    small64, small81, small100;
+  marktype d;
+  int avx, avy;
+  int hhh, www, i;
+  int avruns_h = 0, avruns_v = 0;
+  int av_area = 0;
+  char *libraryname = NULL;
+
+
+  if (argc < 2)
+    usage ();
+
+  for (i = 1; i < argc; i++)
+    {
+      if (!strcmp (args[i], "-v"))
+	V = 1;
+      else if (!strcmp (args[i], "-h"))
+	usage ();
+      else if (args[i][0] == '-')
+	error_msg (args[0], "unknown switch:", args[i]);
+      else if (!libraryname)
+	libraryname = args[i];
+      else
+	error_msg (args[0], "too many filenames", "");
+    }
+
+  if (!libraryname)
+    error_msg (args[0], "please specify a library file", "");
+
+
+  lib = fopen (libraryname, "r");
+  if (lib == NULL)
+    error_msg (args[0], "Trouble opening library file", "");
+
+  count = 0;
+  small1 = small2 = small4 = small9 = small16 = small25 = small36 = small49 = small64 = small81 = small100 = 0;
+  avx = avy = 0;
+  www = hhh = 0;
+  while (!isEOF (lib))
+    {
+      if (!read_library_mark (lib, &d))
+	error_msg (args[0], "error in library file", "");
+
+      av_area += d.set;
+      if (d.set <= 1)
+	small1++;
+      if (d.set <= 2)
+	small2++;
+      if (d.set <= 4)
+	small4++;
+      if (d.set <= 9)
+	small9++;
+      if (d.set <= 16)
+	small16++;
+      if (d.set <= 25)
+	small25++;
+      if (d.set <= 36)
+	small36++;
+      if (d.set <= 49)
+	small49++;
+      if (d.set <= 64)
+	small64++;
+      if (d.set <= 81)
+	small81++;
+      if (d.set <= 100)
+	small100++;
+      avx += d.xcen;
+      avy += d.ycen;
+      www += d.w;
+      hhh += d.h;
+      avruns_h += d.h_runs;
+      avruns_v += d.v_runs;
+      pbm_freearray (&d.bitmap, d.h);
+      count++;
+      if (count % 5000 == 0)
+	fprintf (outf, "%dk ", count / 1000);
+    }
+  fprintf (outf, "number of marks=%d\n", count);
+  fprintf (outf, "average area=%d\n", av_area / count);
+  fprintf (outf, "area <=1:%d, <=2:%d, <=4:%d, <=9:%d, <=16:%d, <=25:%d, <=36:%d, <=49:%d, <=64:%d, <=81:%d, <=100:%d\n", small1, small2, small4, small9, small16, small25, small36, small49, small64, small81, small100);
+
+  fprintf (outf, "average num runs, horizontal=%d, vertical=%d\n", avruns_h / count, avruns_v / count);
+  fprintf (outf, "average centroid position=(%d,%d)\n", avx / count, avy / count);
+  fprintf (outf, "average width=%d, average height=%d\n", www / count, hhh / count);
+  fclose (lib);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/model.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/model.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/model.h	(revision 10506)
@@ -0,0 +1,92 @@
+/**************************************************************************
+ *
+ * model.h -- Part pf PPM data compression
+ * Copyright (C) 1987  Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#define defaultkbytes	896
+#define minkbytes	56
+#define maxkbytes	((65536/1024)*sizeof(eventnode))
+
+#ifndef increment
+#define	increment	8
+#endif
+#ifndef halveat
+#define halveat		64
+#endif
+#define maxtotalcnt 	(increment*halveat)
+
+typedef int boolean;
+#define false           0
+#define true            1
+
+typedef short event;
+typedef unsigned short point;
+
+typedef struct
+  {
+    short totalcnt;
+    short notfound;
+    point list;			/* list storing the event records */
+  }
+eventset;
+
+typedef struct
+  {
+    event eventnum;
+    short count;
+    point next, prev;
+    eventset foll;
+  }
+eventnode, *eventptr;
+
+#define memsize		(kbytes*1024)
+#define maxnodes	(memsize/sizeof(eventnode))
+/* #define charsetsize     256 -- MAHE */
+#define nchars          (charsetsize+1)
+
+extern int charsetsize;		/* -- MAHE */
+
+extern eventptr E;
+extern long kbytes;
+extern point numnodes, nfreenodes;
+extern boolean excluded[];	/* -- MAHE */
+
+#define ENULL		(E)
+
+typedef unsigned u;
+#define p32(p)	(E+p)
+#define p16(p)	(p-E)
+
+/* in ppm.c */
+void write_model ();
+void encodestring ();
+void decodestring ();
+void encodefile ();
+void decodefile ();
+
+/* in lstevent.c */
+void write_method ();
+eventnode *encode_event_noex ();
+eventnode *decode_event_noex ();
+eventnode *encode_event ();
+eventnode *decode_event ();
+/* eventnode *addevent(); */
+eventnode *newnode ();
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/pbmtools.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/pbmtools.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/pbmtools.c	(revision 10506)
@@ -0,0 +1,288 @@
+/**************************************************************************
+ *
+ * pbmtools.c -- Routines for dealing with portable bitmap files (PBM)
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "pbmtools.h"
+#include "extractor.h"
+#include "utils.h"
+
+
+
+void 
+pbm_putpixel_range (Pixel ** bitmap, int c, int r, int val, int cols, int rows)
+{
+  if (((c) >= 0) && ((c) < cols) && ((r) >= 0) && ((r) < rows))
+    pbm_putpixel (bitmap, c, r, val);
+  else
+    fprintf (stderr, "putpitxel (%d %d) outside (%d %d)\n", c, r, cols, rows);
+}
+
+int 
+pbm_getpixel_range (Pixel ** bitmap, int c, int r, int cols, int rows)
+{
+  if (((c) >= 0) && ((c) < cols) && ((r) >= 0) && ((r) < rows))
+    return pbm_getpixel (bitmap, c, r);
+  else
+    {
+      fprintf (stderr, "getpixel (%d %d) outside (%d %d)\n", c, r, cols, rows);
+      return 0;
+    }
+}
+
+
+
+
+
+/*
+   Returns 1 if *fp points to a PBM (magic is P1 or P4) file.
+   leaves the fp in it's original position.
+   usage: if(pbm_isapbmfile(fp)) process(fp);
+ */
+int 
+pbm_isapbmfile (FILE * fp)
+{
+  u_long magic;
+
+  magic = getmagicno_short (fp);
+  if ((magic == MAGIC_P4) || (magic == MAGIC_P1))
+    return 1;
+  else
+    return 0;
+}
+
+
+/*
+   Frees the memory used in the bitmap structure.
+   usage: pbm_freearray(&bitmap);
+   Sets bitmap to be NULL on return.
+ */
+void 
+pbm_freearray (Pixel *** bitmap, int rows)
+{
+  int r;
+  if (rows == 0)
+    rows++;
+  for (r = 0; r < rows; r++)
+    free ((*bitmap)[r]);
+  free (*bitmap);
+  (*bitmap) = NULL;
+}
+
+
+/*
+   This function allocates the bitmap.
+   usage: bitmap=pbm_allocarray(cols,rows);
+ */
+Pixel **
+pbm_allocarray (int cols, int rows)
+{
+  Pixel **p;
+  int i, newc = (cols + PBITS) / PBITS;
+
+  if (cols == 0)
+    cols++;
+  if (rows == 0)
+    rows++;
+  p = (Pixel **) malloc (rows * sizeof (Pixel *));
+  if (p == NULL)
+    error_msg ("pbm_allocarray", "out of memory", "");
+  for (i = 0; i < rows; i++)
+    {
+      p[i] = (Pixel *) calloc (newc, sizeof (Pixel));
+      if (p[i] == NULL)
+	error_msg ("pbm_allocarray", "out of memory", "");
+    }
+  return p;
+}
+
+
+
+Pixel **
+pbm_copy (Pixel ** bitmap, int cols, int rows)
+{
+  Pixel **p;
+  int newc = (cols + PBITS) / PBITS;
+  int x, y;
+
+  p = pbm_allocarray (cols, rows);
+  for (x = 0; x < newc; x++)
+    for (y = 0; y < rows; y++)
+      p[y][x] = bitmap[y][x];
+  return p;
+}
+
+
+
+
+/*
+   Reads in a pbm file and returns a pointer to the allocated bitmap, 
+   in the P4 format.
+   Assumes fp was opened and keeps it that way.
+   usage: bitmap=pbm_readfile(fp,&cols,&rows);
+ */
+Pixel **
+pbm_readfile (FILE * fp, int *cols, int *rows)
+{
+  Pixel **p = NULL;
+  char s[100];
+  unsigned char *buf;
+  int r, c, ii = 0;
+  int p1 = 0;
+  int arg;
+
+
+  do
+    {
+      readline (s, fp);
+    }
+  while (s[0] == '#');
+
+  if (strcmp (s, "P1") == 0)
+    p1 = 1;
+  else if (strcmp (s, "P4") == 0)
+    p1 = 0;
+  else
+    error_msg ("pbm_readfile", "only pbm files are supported", "");
+
+  do
+    {
+      readline (s, fp);
+    }
+  while (s[0] == '#');
+
+  arg = sscanf (s, "%d %d", cols, rows);
+  if (arg == 1)
+    {
+      readline (s, fp);
+      arg = sscanf (s, "%d", rows);
+      if (arg != 1)
+	error_msg ("pbm_readfile", "bizzare pbm format", "");
+    }
+  p = pbm_allocarray (*cols, *rows);
+  buf = (unsigned char *) malloc ((*cols + 2) * sizeof (unsigned char));
+  if (!buf)
+    error_msg ("pbm_readfile", "out of memory", "");
+
+  if (p1)
+    {
+      for (r = 0; r < *rows; r++)
+	for (c = 0; c < *cols; c++)
+	  {
+	    fscanf (fp, "%d", &ii);
+	    pbm_putpixel (p, c, r, ii);
+	  }
+    }
+  else
+    {
+      for (r = 0; r < *rows; r++)
+	{
+	  c = 0;
+	  fread (buf, 1, (*cols + 7) / 8, fp);
+	  for (c = 0; c < *cols; c++)
+	    {
+	      if (!(c % 8))
+		ii = buf[c / 8];
+	      if (ii < 0)
+		error_msg ("pbm_readfile", "file reading error", "");
+	      pbm_putpixel (p, c, r, (ii & 128) ? 1 : 0);
+	      ii <<= 1;
+	    }
+	}
+    }				/* p4 type */
+  free (buf);
+  return p;
+}
+
+
+/*
+   Writes a pbm file given a file pointer and bitmap. Assumes that
+   fp is already open, and keeps in that way.
+   usage: pbm_writefile(fp,bitmap,cols,rows);
+ */
+void 
+pbm_writefile (FILE * fp, Pixel ** bitmap, int cols, int rows)
+{
+  int r, c, ii = 0, j;
+  unsigned char *buf;
+
+  buf = (unsigned char *) malloc (((cols + 14) / 8) * sizeof (unsigned char));
+
+  fprintf (fp, "%s\n", "P4");
+  fprintf (fp, "%d %d\n", cols, rows);
+
+  for (r = 0; r < rows; r++)
+    {
+      for (c = 0; c < cols; c += 8)
+	{
+	  ii = 0;
+	  for (j = 0; j < 8; j++)
+	    if (c + j < cols)
+	      {
+		if (pbm_getpixel (bitmap, c + j, r))
+		  ii |= (128 >> j);
+	      }
+	  buf[c / 8] = ii;
+	}
+      fwrite (buf, 1, (cols + 7) / 8, fp);
+    }
+  free (buf);
+/*      putc('\n',fp);   if this line is included programs don't say things like 'short image' &c, but then again,
+   in most cases a 'cmp' between the original will fail because of the last byte...sigh, "standards". */
+}
+
+#define BUF_SIZE 131072
+char buffer[BUF_SIZE];
+
+void 
+pbm_writenamedfile (char fn[], Pixel ** bitmap, int cols, int rows)
+{
+  FILE *tempfp;
+
+  tempfp = fopen (fn, "wb");
+  if (tempfp == NULL)
+    error_msg ("pbm_writenamedfile", "can't open file:", fn);
+  setbuffer (tempfp, buffer, BUF_SIZE);
+  pbm_writefile (tempfp, bitmap, cols, rows);
+  fclose (tempfp);
+}
+
+
+
+Pixel **
+pbm_readnamedfile (char fn[], int *cols, int *rows)
+{
+  FILE *tempfp;
+  Pixel **temp;
+
+  tempfp = fopen (fn, "rb");
+  if (tempfp == NULL)
+    return NULL;
+  setbuffer (tempfp, buffer, BUF_SIZE);
+
+  temp = pbm_readfile (tempfp, cols, rows);
+
+  fclose (tempfp);
+  return temp;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/pbmtools.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/pbmtools.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/pbmtools.h	(revision 10506)
@@ -0,0 +1,86 @@
+/**************************************************************************
+ *
+ * pbmtools.h -- Routines for dealing with portable bitmap files (PBM)
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __PBMTOOLS_H
+#define __PBMTOOLS_H
+
+#include "sysfuncs.h"
+#include "basictypes.h"
+
+#include "utils.h"
+#include "marklist.h"
+
+#define PBITS 32
+#define PSH 5
+
+
+/* The next two are ordered pixels col0=left, cols31=right */
+
+/*
+   #define pbm_getpixel(bitmap,c,r)  \
+   ((bitmap[r][(c)>>PSH] >> ((PBITS-1)-((c)&(PBITS-1))))&1)
+   #define pbm_putpixel(bitmap,c,r,val) \
+   if((val))  \
+   bitmap[r][(c)>>PSH] |=  (((unsigned)1<<(PBITS-1)) >> ((c)&(PBITS-1))); \
+   else \
+   bitmap[r][(c)>>PSH] &= ~(((unsigned)1<<(PBITS-1)) >> ((c)&(PBITS-1))) 
+ */
+
+
+
+
+/* The next two defines are ordered pixel cols0=right, cols31=left */
+
+#define pbm_getpixel(bitmap,c,r)                            \
+         ((bitmap[r][(c)>>PSH] >> ((c)&(PBITS-1)))&1)
+#define pbm_putpixel(bitmap,c,r,val)                        \
+         if((val))                                          \
+              bitmap[r][(c)>>PSH] |= (1<<((c)&(PBITS-1)));  \
+         else                                               \
+              bitmap[r][(c)>>PSH] &= ~(1<<((c)&(PBITS-1)))
+
+
+#define pbm_putpixel_trunc(bitmap,c,r,val,cols,rows) \
+       if(((c)>=0)&&((c)<cols)&&((r)>=0)&&((r)<rows)) \
+             pbm_putpixel(bitmap,c,r,val)
+
+#define pbm_getpixel_trunc(bitmap,c,r,cols,rows)       \
+       ((((c)>=0)&&((c)<cols)&&((r)>=0)&&((r)<rows)) ?  \
+             pbm_getpixel(bitmap,c,r) : 0)
+
+
+
+
+int pbm_isapbmfile (FILE * fp);
+void pbm_freearray (Pixel *** bitmap, int rows);
+Pixel **pbm_copy (Pixel ** bitmap, int cols, int rows);
+Pixel **pbm_allocarray (int cols, int rows);
+Pixel **pbm_readfile (FILE * fp, int *cols, int *rows);
+Pixel **pbm_readnamedfile (char fn[], int *cols, int *rows);
+void pbm_writefile (FILE * fp, Pixel ** bitmap, int cols, int rows);
+void pbm_writenamedfile (char fn[], Pixel ** bitmap, int cols, int rows);
+
+void pbm_putpixel_range (Pixel ** bitmap, int c, int r, int val, int cols, int rows);
+int pbm_getpixel_range (Pixel ** bitmap, int c, int r, int cols, int rows);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/ppm.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/ppm.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/ppm.c	(revision 10506)
@@ -0,0 +1,585 @@
+/**************************************************************************
+ *
+ * ppm.c -- PPM data compression
+ * Copyright (C) 1987  Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "arithcode.h"
+#include "model.h"
+
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:33  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:33:55  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:42:02  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+/* FIXEDORDER sets the maximum context length that will be used.
+   Making FIXEDORDER large increases the compression if there is enough
+   space to store the model, but when space limit is reached increasing
+   FIXEDORDER will decrease compression because of model thrashing.
+   Third order (FIXEDORDER=3) is suitable for a few hundred Kb of model
+   space, FIXEDORDER=1 is suitable for a few tens of kB.
+   This version requires that FIXEDORDER be a preprocessor rather
+   than runtime variable to allow loops to be unrolled and make for faster
+   execution. Maximum in this implementation is 3 */
+
+#ifndef FIXEDORDER
+#define FIXEDORDER	3
+#endif
+
+/* global variables */
+eventptr E = NULL;		/* array of eventnodes */
+point numnodes = 0, nfreenodes = 0;
+long kbytes = defaultkbytes;
+/*boolean               excluded[nchars]={false};  - MAHE */
+boolean excluded[16384] =
+{false};			/* excluded characters */
+
+/* local variables */
+#define defaultchunksize        4096	/* compression chunks */
+
+#define EOSchar         (charsetsize)
+
+unsigned chunksize = defaultchunksize;
+eventptr s[FIXEDORDER + 1] =
+{NULL},				/* current contexts */
+  t[FIXEDORDER + 1] =
+{NULL};				/* new contexts */
+
+#if (FIXEDORDER==3)
+#define SHIFT_ST	s[1] = t[0]; s[2] = t[1] ; s[3] = t[2]
+#else
+#if (FIXEDORDER==2)
+#define SHIFT_ST	s[1] = t[0]; s[2] = t[1]
+#else
+#if (FIXEDORDER==1)
+#define SHIFT_ST	s[1] = t[0]
+#else
+#define SHIFT_ST
+#endif
+#endif
+#endif
+
+/* follow a character list and set the exclusions */
+#define SET_EX(p)				\
+do						\
+{	register eventptr q;			\
+	q = p32((p32(p))->next);		\
+	for (; q!=ENULL; q=p32(q->next))	\
+		excluded[q->eventnum] = true;	\
+}						\
+while (false)
+
+/* clear the exclusions */
+#define CLEAR_EX(p)				\
+do						\
+{	register eventptr q;			\
+	q = p32((p32(p))->next);		\
+	for (; q!=ENULL; q=p32(q->next))	\
+		excluded[q->eventnum] = false;	\
+}						\
+while (false)
+
+/*==================================*/
+
+void
+write_model ()
+{
+  fprintf (stderr, "ppm");
+  write_method ();
+#ifdef NOEXCLUSIONS
+  fprintf (stderr, "nx");
+#endif
+  fprintf (stderr, "-o%1d", FIXEDORDER);
+  fprintf (stderr, "-k%ld", kbytes);
+}
+
+/*==================================*/
+
+void
+encode_in_order (n, e)
+     int n;
+     event e;
+/* encode character e in order n */
+{
+  boolean encoded;
+  int i, c;
+  t[n] = encode_event_noex (&s[n]->foll, e, &encoded);
+  if (encoded)
+    c = n;
+  else
+    for (c = n - 1; c >= 0; c--)
+      {
+#ifdef NOEXCLUSIONS
+	t[c] = encode_event_noex (&s[c]->foll, e, &encoded);
+#else
+	SET_EX (s[c + 1]->foll.list);
+	t[c] = encode_event (&s[c]->foll, e, &encoded);
+#endif
+	if (encoded)
+	  break;
+      }
+  if (!encoded)
+    arithmetic_encode (e, e + 1, nchars);
+  for (i = c + 1; i <= n; i++)
+    if (i > 0)
+      t[i]->prev = p16 (t[i - 1]);
+    else
+      t[0]->prev = p16 (s[0]);
+  for (i = c - 1; i >= 0; i--)
+    t[i] = p32 (t[i + 1]->prev);
+#ifndef NOEXCLUSIONS
+  if (c != n)
+    CLEAR_EX (s[c + 1]->foll.list);
+#endif
+  SHIFT_ST;
+}
+
+/*==================================*/
+
+/* not required in this version */
+
+#if 0
+
+void
+decode_in_order (n, e)
+     int n;
+     event *e;
+{
+  boolean decoded;
+  int i, c;
+  t[n] = decode_event_noex (&s[n]->foll, &decoded, e);
+  if (decoded)
+    c = n;
+  else
+    for (c = n - 1; c >= 0; c--)
+      {
+#ifdef NOEXCLUSIONS
+	t[c] = decode_event_noex (&s[c]->foll, &decoded, e);
+#else
+	SET_EX (s[c + 1]->foll.list);
+	t[c] = decode_event (&s[c]->foll, &decoded, e);
+#endif
+	if (decoded)
+	  break;
+      }
+  if (!decoded)
+    {
+      *e = arithmetic_decode_target (nchars);
+      arithmetic_decode (*e, *e + 1, nchars);
+    }
+  for (i = c + 1; i <= n; i++)
+    {
+      t[i]->eventnum = *e;
+      if (i > 0)
+	t[i]->prev = p16 (t[i - 1]);
+      else
+	t[0]->prev = p16 (s[0]);
+    }
+  {
+    register int i;
+    for (i = c - 1; i >= 0; i--)
+      t[i] = p32 (t[i + 1]->prev);
+  }
+#ifndef NOEXCLUSIONS
+  if (c != n)
+    CLEAR_EX (s[c + 1]->foll.list);
+#endif
+  SHIFT_ST;
+}
+
+#endif
+
+/*==================================*/
+
+void
+start_model ()
+{
+  int i;
+  /* is this the first call? */
+  if (E == NULL)
+    E = (eventptr) malloc ((unsigned) kbytes * 1024);
+  /* start off with no information */
+  numnodes = 0;
+  nfreenodes = maxnodes;
+  for (i = 0; i <= FIXEDORDER; i++)
+    {
+      s[i] = newnode (NULL);
+      if (i > 0)
+	s[i]->prev = p16 (s[i - 1]);
+    }
+}
+
+/*==================================*/
+
+void
+encodestring (str, n)
+     unsigned short *str;
+     int n;
+/* encode all n characters of the supplied string str */
+{
+  event e;
+  boolean encoded;
+  register eventptr S, T;
+  int i;
+#ifndef NOEXCLUSIONS
+  register eventptr Sex;
+#endif
+
+  if (E == NULL)
+    start_model ();
+  /* set the initial context node */
+  S = s[FIXEDORDER];
+
+  for (i = 0; i < n; i++)
+    {
+      /* encode one character */
+      e = *str++;
+      /* this next monstrosity is logically equivalent to 
+         encode_in_order(FIXEDORDER,e)
+         the loop has been unrolled to make it all go faster */
+      for (;;)
+	{
+	  T = encode_event_noex (&S->foll, e, &encoded);
+	  if (encoded)
+	    break;
+	  t[FIXEDORDER] = T;
+
+#ifdef NOEXCLUSIONS
+#if (FIXEDORDER>2)
+	  S = p32 (S->prev);
+	  t[2] = encode_event_noex (&S->foll, e, &encoded);
+	  t[3]->prev = p16 (t[2]);
+	  if (encoded)
+	    break;
+#endif
+
+#if (FIXEDORDER>1)
+	  S = p32 (S->prev);
+	  t[1] = encode_event_noex (&S->foll, e, &encoded);
+	  t[2]->prev = p16 (t[1]);
+	  if (encoded)
+	    break;
+#endif
+
+#if (FIXEDORDER>0)
+	  S = p32 (S->prev);
+	  t[0] = encode_event_noex (&S->foll, e, &encoded);
+	  t[1]->prev = p16 (t[0]);
+	  if (encoded)
+	    break;
+#endif
+#else
+#if (FIXEDORDER>2)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[2] = encode_event (&S->foll, e, &encoded);
+	  t[3]->prev = p16 (t[2]);
+	  if (encoded)
+	    {
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>1)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[1] = encode_event (&S->foll, e, &encoded);
+	  t[2]->prev = p16 (t[1]);
+	  if (encoded)
+	    {
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>0)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[0] = encode_event (&S->foll, e, &encoded);
+	  t[1]->prev = p16 (t[0]);
+	  if (encoded)
+	    {
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+	  CLEAR_EX (Sex->foll.list);
+#endif
+#endif
+
+	  arithmetic_encode (e, e + 1, nchars);
+	  t[0]->prev = p16 (s[0]);
+	  break;
+	}
+      /* phew! Update the current context to the latest node */
+      S = p32 (T->prev);
+
+      /* is there a danger of running out of space? */
+      if (nfreenodes <= FIXEDORDER)
+	{
+	  start_model ();
+	  S = s[FIXEDORDER];
+	}
+    }
+
+  /* save the current contexts for the various order submodels */
+  s[FIXEDORDER] = S;
+  for (i = FIXEDORDER; i > 0; i--)
+    s[i - 1] = p32 (s[i]->prev);
+  /* and send the terminator character */
+  encode_in_order (FIXEDORDER, EOSchar);
+  /* and check the space again */
+  if (nfreenodes <= FIXEDORDER)
+    start_model ();
+}
+
+/*==================================*/
+
+void
+decodestring (str, n)
+     unsigned short *str;
+     int *n;
+{
+  event e;
+  boolean decoded;
+  register eventptr S, T;
+#ifndef NOEXCLUSIONS
+  register eventptr Sex;
+#endif
+
+  /* just mimic the corresponding encoding actions */
+  if (E == NULL)
+    start_model ();
+  S = s[FIXEDORDER];
+
+  *n = 0;
+  for (;;)
+    {				/* logically equivalent to "decode_in_order(FIXEDORDER,&e)" */
+
+      for (;;)
+	{
+	  T = decode_event_noex (&S->foll, &decoded, &e);
+	  if (decoded)
+	    break;
+	  t[FIXEDORDER] = T;
+
+#ifdef NOEXCLUSIONS
+#if (FIXEDORDER>2)
+	  S = p32 (S->prev);
+	  t[2] = decode_event_noex (&S->foll, &decoded, &e);
+	  t[3]->prev = p16 (t[2]);
+	  if (decoded)
+	    {
+	      t[3]->eventnum = e;
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>1)
+	  S = p32 (S->prev);
+	  t[1] = decode_event_noex (&S->foll, &decoded, &e);
+	  t[2]->prev = p16 (t[1]);
+	  if (decoded)
+	    {
+#if (FIXEDORDER>2)
+	      t[3]->eventnum =
+#endif
+		t[2]->eventnum = e;
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>0)
+	  S = p32 (S->prev);
+	  t[0] = decode_event_noex (&S->foll, &decoded, &e);
+	  t[1]->prev = p16 (t[0]);
+	  if (decoded)
+	    {
+#if (FIXEDORDER>2)
+	      t[3]->eventnum =
+#endif
+#if (FIXEDORDER>1)
+		t[2]->eventnum =
+#endif
+		t[1]->eventnum = e;
+	      break;
+	    }
+#endif
+#else
+#if (FIXEDORDER>2)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[2] = decode_event (&S->foll, &decoded, &e);
+	  t[3]->prev = p16 (t[2]);
+	  if (decoded)
+	    {
+	      t[3]->eventnum = e;
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>1)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[1] = decode_event (&S->foll, &decoded, &e);
+	  t[2]->prev = p16 (t[1]);
+	  if (decoded)
+	    {
+#if (FIXEDORDER>2)
+	      t[3]->eventnum =
+#endif
+		t[2]->eventnum = e;
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+#endif
+
+#if (FIXEDORDER>0)
+	  Sex = S;
+	  SET_EX (Sex->foll.list);
+	  S = p32 (S->prev);
+	  t[0] = decode_event (&S->foll, &decoded, &e);
+	  t[1]->prev = p16 (t[0]);
+	  if (decoded)
+	    {
+#if (FIXEDORDER>2)
+	      t[3]->eventnum =
+#endif
+#if (FIXEDORDER>1)
+		t[2]->eventnum =
+#endif
+		t[1]->eventnum = e;
+	      CLEAR_EX (Sex->foll.list);
+	      break;
+	    }
+	  CLEAR_EX (Sex->foll.list);
+#endif
+#endif
+
+	  e = arithmetic_decode_target (nchars);
+	  arithmetic_decode (e, e + 1, nchars);
+#if (FIXEDORDER>2)
+	  t[3]->eventnum =
+#endif
+#if (FIXEDORDER>1)
+	    t[2]->eventnum =
+#endif
+#if (FIXEDORDER>0)
+	    t[1]->eventnum =
+#endif
+	    t[0]->eventnum = e;
+	  t[0]->prev = p16 (s[0]);
+	  break;
+	}
+      S = p32 (T->prev);
+
+      /* check the space requirements */
+      if (nfreenodes <= FIXEDORDER)
+	{
+	  start_model ();
+	  S = s[FIXEDORDER];
+	}
+      /* are we done?  or do we save the char */
+      if (e == EOSchar)
+	break;
+      *str++ = e;
+      (*n)++;
+    }
+  s[FIXEDORDER] = S;
+}
+
+
+#if 0				/* Writing my own version of this - MAHE */
+void
+encodefile ()
+/* encodes a file by breaking into a sequence of fixed length chunks */
+{
+  unsigned char *str;
+  int c, n = 0;
+
+  str = (unsigned char *) malloc ((unsigned) chunksize);
+  startoutputingbits ();
+  startencoding ();
+
+  /* to encode the file, break it into chunks and encode the
+     chunks one by one */
+  while ((c = getchar ()) != EOF)
+    {
+      str[n++] = c;
+      if (n == chunksize)
+	{
+	  encodestring (str, n);
+	  rawbytes += n;
+	  n = 0;
+	}
+    }
+  /* send final partial chunk */
+  if (n > 0)
+    {
+      encodestring (str, n);
+      rawbytes += n;
+    }
+  /* send EOF as an empty string */
+  encodestring (str, 0);
+  doneencoding ();
+  doneoutputingbits ();
+}
+
+void
+decodefile ()
+{
+  unsigned char *str;
+  int n, i;
+
+  str = (unsigned char *) malloc ((unsigned) chunksize);
+  startinputingbits ();
+  startdecoding ();
+  for (;;)
+    {
+      decodestring (str, &n);
+      if (n == 0)
+	break;
+      for (i = 0; i < n; i++)
+	putchar ((int) str[i]);
+      rawbytes += n;
+    }
+}
+
+#endif /* #if 0 */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/sortmarks.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/sortmarks.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/sortmarks.c	(revision 10506)
@@ -0,0 +1,93 @@
+/**************************************************************************
+ *
+ * sortmarks.c -- Functions which sort the marks into a "readable sequence"
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "marklist.h"
+#include "sortmarks.h"
+
+#define GAP 4
+
+
+
+static int 
+CmpOnY (const void *e1, const void *e2)
+{
+  return (((marktype *) e1)->ycen * 0 + ((marktype *) e1)->ypos) -
+    (((marktype *) e2)->ycen * 0 + ((marktype *) e2)->ypos);
+}
+
+static int 
+CmpOnX (const void *e1, const void *e2)
+{
+  return (((marktype *) e1)->xcen * 0 + ((marktype *) e1)->xpos) -
+    (((marktype *) e2)->xcen * 0 + ((marktype *) e2)->xpos);
+}
+
+
+
+
+
+
+
+
+marklistptr 
+sortmarks (marklistptr listofmarks)
+{
+  marktype *table;
+  int count = 0;
+  int i, s, e;
+
+
+  table = calloc ((unsigned int) marklist_length (listofmarks), sizeof (marklisttype));
+
+  while (listofmarks)
+    {
+      table[count] = listofmarks->data;
+      marklist_removeat (&listofmarks, 0);
+      count++;
+    }
+
+  /* sort first on the y position of their centroids */
+  qsort ((void *) table, (unsigned int) (count), sizeof (*table), CmpOnY);
+
+  for (s = 0; s < count;)
+    {
+      int c;
+
+      for (e = s + 1, c = 0; (e < count) &&
+	   ((table[e].ypos + table[e].ycen * 0) - (table[e - 1].ypos + table[e - 1].ycen * 0) <= GAP); c++, e++);
+
+      if (e < count && c >= 1)
+	qsort (&table[s], (unsigned int) (e - s), sizeof (*table), CmpOnX);
+      s = e;
+    }
+
+  for (i = 0; i < count; i++)
+    {
+      table[i].symnum = i;
+      marklist_add (&listofmarks, table[i]);
+    }
+
+  return listofmarks;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/sortmarks.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/sortmarks.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/sortmarks.h	(revision 10506)
@@ -0,0 +1,30 @@
+/**************************************************************************
+ *
+ * sortmarks.h -- Functions which sort the marks into a "readable sequence"
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef _SortMarks_h_
+#define _SortMarks_h_
+
+marklistptr sortmarks (marklistptr listofmarks);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/utils.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/utils.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/utils.c	(revision 10506)
@@ -0,0 +1,270 @@
+/**************************************************************************
+ *
+ * utils.c -- Functions which are common utilities for the image programs
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "utils.h"
+
+
+int V = 0;
+
+
+int 
+isEOF (FILE * fp)
+{
+  int ch;
+
+  ch = getc (fp);
+  ungetc (ch, fp);
+  if (ch == EOF)
+    return 1;
+  return 0;
+}
+
+
+int 
+getmagicno_short (FILE * fp)
+{
+  int ch1, ch2;
+  ch1 = getc (fp);
+  if (ch1 == EOF)
+    {
+      ungetc (ch1, fp);
+      return 0;
+    }
+  ch2 = getc (fp);
+  if (ch2 == EOF)
+    {
+      ungetc (ch2, fp);
+      return 0;
+    }
+  ungetc (ch2, fp);
+  ungetc (ch1, fp);
+
+  return ((ch1 << 8) | ch2);
+}
+
+int 
+getmagicno_short_pop (FILE * fp)
+{
+  int ch1, ch2;
+  ch1 = getc (fp);
+  if (ch1 == EOF)
+    return 0;
+  ch2 = getc (fp);
+  if (ch2 == EOF)
+    return 0;
+
+  return ((ch1 << 8) | ch2);  
+}
+
+int 
+getmagicno_byte (FILE * fp)
+{
+  int ch1;
+  ch1 = getc (fp);
+  if (ch1 == EOF)
+    {
+      ungetc (ch1, fp);
+      return 0;
+    }
+  ungetc (ch1, fp);
+  return (ch1);
+}
+
+
+int 
+getmagicno_long (FILE * fp)
+{
+  int ch1, ch2, ch3, ch4;
+  ch1 = getc (fp);
+  if (ch1 == EOF)
+    {
+      ungetc (ch1, fp);
+      return 0;
+    }
+  ch2 = getc (fp);
+  if (ch2 == EOF)
+    {
+      ungetc (ch2, fp);
+      return 0;
+    }
+  ch3 = getc (fp);
+  if (ch3 == EOF)
+    {
+      ungetc (ch3, fp);
+      return 0;
+    }
+  ch4 = getc (fp);
+  if (ch4 == EOF)
+    {
+      ungetc (ch4, fp);
+      return 0;
+    }
+  ungetc (ch4, fp);
+  ungetc (ch3, fp);
+  ungetc (ch2, fp);
+  ungetc (ch1, fp);
+
+  return ((ch1 << 24) | (ch2 << 16) | (ch3 << 8) | (ch4));
+}
+
+
+
+
+void 
+error_msg (char *prog, char *message, char *extra)
+{
+  fprintf (stderr, "%s: %s %s\n", prog, message, extra);
+  exit (1);
+}
+
+void 
+warn (char *prog, char *message, char *extra)
+{
+  fprintf (stderr, "%s: %s %s\n", prog, message, extra);
+}
+
+
+
+void 
+readline (char str[], FILE * fp)
+{
+  int i = 0, ch;
+
+  while (((ch = fgetc (fp)) != '\n') && (!feof (fp)))
+    str[i++] = ch;
+  str[i] = '\0';
+}
+
+
+
+
+
+
+
+int 
+getint (FILE * fp)
+{
+  register char ch;
+  register unsigned int i = 0;
+
+  do
+    {
+      ch = getc (fp);
+      if (feof (fp))
+	return EOF;
+    }
+  while (ch < '0' || ch > '9');
+
+  do
+    {
+      i = i * 10 + ch - '0';
+      ch = getc (fp);
+      if (feof (fp))
+	return EOF;
+    }
+  while (ch >= '0' && ch <= '9');
+
+  return i;
+}
+
+/* get_header_int i.e. get an integer from a PNM header ; basically  
+   the same as
+   above except for comment checking ; above kept because of lower  
+   overhead */
+
+unsigned int 
+gethint (FILE * fp)
+{
+  register char ch, prev = '\0';
+  register unsigned int i = 0;
+
+  do
+    {
+      ch = getc (fp);
+      if ((ch == '#') && (prev == '\n'))
+	while (((ch = getc (fp)) != '\n') && !(feof (fp)));
+      prev = ch;
+      if (feof (fp))
+	return EOF;
+    }
+  while (ch < '0' || ch > '9');
+
+  do
+    {
+      i = i * 10 + ch - '0';
+      ch = getc (fp);
+      if (feof (fp))
+	return EOF;
+    }
+  while (ch >= '0' && ch <= '9');
+
+  return i;
+}
+
+
+
+
+void 
+magic_write (FILE * fp, u_long magic_num)
+{
+  HTONUL(magic_num);  /* [RPAP - Jan 97: Endian Ordering] */
+  if (fwrite (&magic_num, sizeof (magic_num), 1, fp) != 1)
+    error_msg ("magic num", "Couldn't write magic number.", "");
+}
+
+
+void 
+magic_check (FILE * fp, u_long magic_num)
+{
+  u_long magic;
+  if (fread (&magic, sizeof (magic), 1, fp) != 1 || NTOHUL(magic) != magic_num)  /* [RPAP - Jan 97: Endian Ordering] */
+    error_msg ("magic num", "Incorrect magic number.", "");
+}
+
+
+u_long 
+magic_read (FILE * fp)
+{
+  u_long magic;
+  if (fread (&magic, sizeof (magic), 1, fp) != 1)
+    error_msg ("magic num", "Couldn't read magic number.", "");
+  return NTOHUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+}
+
+
+
+
+int 
+isinteger (char s[])
+{
+  int i = 0;
+
+  for (i = 0; s[i] != '\0'; i++)
+    if (!isdigit (s[i]))
+      return 0;
+  return 1;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/utils.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/utils.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/images/utils.h	(revision 10506)
@@ -0,0 +1,75 @@
+/**************************************************************************
+ *
+ * utils.h -- Functions which are common utilities for the image programs
+ * Copyright (C) 1994  Stuart Inglis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef __UTILS_H
+#define __UTILS_H
+
+#include "sysfuncs.h"
+
+extern int V;
+
+#define DEBUG
+
+#define min(a,b) ((a)<(b) ? (a) : (b))
+#define max(a,b) ((a)>(b) ? (a) : (b))
+
+#define GEN_MAGIC(a,b,c,d) ((unsigned long)(((a)<<24) + ((b)<<16) + \
+                                            ((c)<<8) + (d)))
+ 
+/* --- MG magic file codes [TS:Aug/95] --- */
+#define MAGIC_FELICS            GEN_MAGIC('M','G','F','X')
+#define MAGIC_BILEVEL           GEN_MAGIC('M','G','B','I')
+#define MAGIC_TIC               GEN_MAGIC('M','G','T','C')
+#define IS_MAGIC(a) ((((u_long)(a)) & 0xffff0000) == MAGIC_XXXX)
+/* --------------------------------------- */
+
+#define MAGIC_P1      0x5031	/* P1   - pbm */
+#define MAGIC_P2      0x5032	/* P2   - pgm */
+#define MAGIC_P3      0x5033	/* P3   - ppm */
+#define MAGIC_P4      0x5034	/* P4   - rawbits pbm */
+#define MAGIC_P5      0x5035	/* P5   - rawbits pgm */
+#define MAGIC_P6      0x5036	/* P6   - rawbits ppm */
+
+int isEOF (FILE * fp);
+int getmagicno_byte (FILE * fp);
+int getmagicno_short (FILE * fp);
+int getmagicno_short_pop (FILE * fp);
+int getmagicno_long (FILE * fp);
+
+
+
+void error_msg (char *prog, char *message, char *extra);
+void warn (char *prog, char *message, char *extra);
+
+void readline (char str[], FILE * fp);
+
+void magic_write (FILE * fp, u_long magic_num);
+void magic_check (FILE * fp, u_long magic_num);
+u_long magic_read (FILE * fp);
+/* kerry's code */
+
+int getint (FILE * fp);
+unsigned int gethint (FILE * fp);
+int isinteger (char s[]);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/Makefile.in	(revision 10506)
@@ -0,0 +1,152 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the MG system
+# Copyright (C) 1994  Neil Sharman
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)Makefile.in	1.10 22 Mar 1994
+#
+###########################################################################
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+subdir = src/scripts
+top_srcdir = @top_srcdir@
+transform = @program_transform_name@
+GSDLOS = @gsdlos@
+ 
+DEFS = @DEFS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+TOUCH = echo timestamp >
+ 
+bindir = ../../../../bin/$(GSDLOS)
+datadir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+localedir = $(datadir)/locale
+mandir = $(prefix)/man/man1
+ 
+SHFILES       =	mgbuild.sh mgbuild_4.sh mg_get.sh xmg.sh  mg_get_merge.sh mgmerge.sh
+
+MISC          = Makefile.in 
+
+ALLFILES      =	$(SHFILES) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES) 
+
+EXEC          = mgbuild mg_get xmg mg_get_merge mgmerge mgbuild_4
+
+MAN           = mgbuild.1 mgbuild_4.1 mg_get.1 xmg.1 mg_get_merge.1 mgmerge.1
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all:	$(EXEC)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+mgbuild : mgbuild.sh
+	@rm -f $@
+	cat mgbuild.sh >$@
+	chmod +x $@
+
+mgbuild_4 : mgbuild_4.sh
+	@rm -f $@
+	cat mgbuild_4.sh >$@
+	chmod +x $@
+
+mg_get : mg_get.sh
+	@rm -f $@
+	cat mg_get.sh >$@
+	chmod +x $@
+
+mgmerge : mgmerge.sh
+	@rm -f $@
+	cat mgmerge.sh >$@
+	chmod +x $@
+
+mg_get_merge : mg_get_merge.sh
+	@rm -f $@
+	cat mg_get_merge.sh >$@
+	chmod +x $@
+
+xmg : xmg.sh
+	@rm -f $@
+	cat xmg.sh >$@
+	chmod +x $@
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+install: execinstall #maninstall
+uninstall: execuninstall manuninstall
+
+execinstall: $(EXEC)
+	for name in $(EXEC); do \
+	  $(INSTALL_PROGRAM) $$name \
+	  $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+execuninstall:
+	for name in $(EXEC); do \
+	 rm -f $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+mostlyclean:
+ 
+clean: mostlyclean
+	rm -f $(EXEC)
+ 
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+ 
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+	  || cp -p $(srcdir)/$$file $(distdir); \
+	done
+
+# screws up distclean (jrm21) 
+#Makefile: Makefile.in ../../../../config.status
+#	cd ../../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get.1	(revision 10506)
@@ -0,0 +1,154 @@
+.TH mg_get 1 "31 January 1994"
+.SH NAME
+mg_get \- output source texts for processing
+.SH SYNOPSIS
+ 
+.B mg_get
+.I collection-name
+.RB [ \-init | \-i | \-text\fP|\fB\-t\fP|\fB\-cleanup\fP|\fB\-c\fP]
+.SH DESCRIPTION
+.LP
+This program is the default one used by mgbuild to generate the source text for the MG system. Any program may be used to generate the source text for mgbuild as long as it confirms to the interface specified here. 
+.SH OPTIONS
+.LP
+The
+.I collection\-name
+must appear before any other option. Only the first option has any significance. If no option is specified
+.B \-text
+is assumed.
+.RS
+.TP
+.BR \-init " and " \-i
+The program is called once with this flag at the start of building a collection.
+.TP
+.BR \-text " and " \-t
+The program is called with this flag multiple times during the building of a collection. The program outputs (on stdout) the text of the collection. \*(lq\fBDocuments\fP\*(rq within the collection are separated with by ctrl-B's (ASCII code 2). \*(lq\fBParagraphs\fP\*(rq within the collection are separated with ctrl-C's (ASCII code 3). A collection need not contain paragraphs unless a level 3 inverted file is being generated (see 
+.B mgbuild 
+and 
+.BR mg_passes ). 
+.TP
+.BR \-cleanup " and " \-c
+The program is called once with this flag at the completion of building a collection.
+.SH ENVIRONMENT
+.TP
+.SB MGDATA
+If this environment variable exists then its value is used a the default 
+directory where the mg collection files are. If this variable does not exist
+then the directory \*(lq\fB.\fP\*(rq is used by default. The command line 
+option 
+.BI \-d " directory"
+overrides the directory in 
+.BR MGDATA .
+.TP
+.SB MG_GETRC
+This environment variable specifies where the file containing the users 
+mg source configurations is. If not set, mg_get uses a default of 
+.B \*\~/.mg_getrc.
+
+This file contains TAB delimited lines of the form
+.RS 
+.RS 
+.I CollectionName
+.I CollectionType
+.I files or directory
+.RE
+
+.I CollectionName
+is the name of the collection supplied to mg_get.
+
+.I CollectionType
+specifies how mg_get should process the
+named files and directories and are descibed below.
+
+.I files or directory
+is either a list of files separted by blanks or a single directory.
+Some of the
+.I CollectionTypes
+deal with files and others with just a single directory.
+Any files used ending with .gz or .Z are decompressed with gzip before
+processing. References to '~' expands to the users HOME directory.
+
+.I CollectionType
+is one of
+.RS
+.TP
+.BR PARA
+For text based documents. The list of files specified are treated as
+a series of paragraphs separated by blank lines. Each paragraph becomes
+a seperate document on the indexed collection.
+.TP
+.BR MAIL
+for mail files. The list of files specified are treated as UNIX mail
+files separated by lines starting with 'From'. Each mail message becomes
+a seperate document on the indexed collection. As a extra feature any
+embedded tarmail encoded contents (enclosed by a 'xbtoa Begin' and 'xbtoa End'
+pair are removed.
+.TP
+.BR DIR
+(and DIR2)
+For a single directory of files. Each file in the directory (and in any of
+it's subdirectories) are treated as a single document. With
+.I DIR
+the pathname of the file is prefixed to the contents of each file as an
+extra line while this is not done for
+.I DIR2
+collections.
+.TP
+.BR BIB
+for biblography files. The list of files specified are treated as
+a series of biblography files (eg BIBTEX or TROFF) separated by lines
+starting with '@'. Each reference  becomes a seperate document on the indexed
+collection.
+.TP
+.BR TXTIMG
+for integrated collections of text and images. The single directory should
+contain files that have the same prefix if they are related. For example,
+monaLisa.pgm might be a gray-level image, and monaLisa.txt would be a textual
+file describing the image. The suffixes recognised are:
+.BR   .txt
+for  ascii text
+.BR  .ptm
+for  scanned text stored as a bilevel image
+.BR  .pbm
+for a black and white image (typically a line drawing)
+.BR  .pgm
+for a gray-scale image
+.BR In addition, if no corresponding ascii text file is found for
+a .pbm or .pgm file, then one is created with suffix .tmp.txt,
+and it stores the name of the image file (in principle it could
+store the OCR of a .txt.pbm file). At present the .tmp.txt files
+are deleted by the '-cleanup' option.
+
+.SH "EXAMPLE"
+
+An example ~/.mg_getrc file might look like:
+   alice   PARA    /users/alice13a.txt.Z
+   mail95  MAIL    ~/MAIL/1995/*
+   doc     DIR     ~/documents
+   bibs    BIB     ~/etc/REFS/*.bib ~/etc/REFS/CC/*.bib
+   letters DIR     ~/LETTERS
+   davinci TXTIMG  ~/images/davinci
+
+.SH "SEE ALSO"
+.LP
+.BR mg_compression_dict (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_make_fast_dict (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1)
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get.sh	(revision 10506)
@@ -0,0 +1,447 @@
+#! /bin/csh -f
+###########################################################################
+#
+# mg_get.sh -- script to get text for mgbuild
+# Copyright (C) 1994  Tim Bell
+# Changed to allow it to be driven from a file ~/.mg_getrc
+# by Bruce McKenzie, Oct 1994
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)mg_get.sh	1.11 25 Mar 1994
+#
+###########################################################################
+#
+# "mg_get" formats the text for mgbuild by collecting the appropriate
+#   documents, and outputing them with control-B after each document.
+#   The name of the text must be supplied as an argument.
+#   mg_get is called with -i (init) first, then with -t (text) each time the 
+#   text is needed, then with -c (cleanup).
+#   e.g. mg_get alice -t
+#
+# The file ~/.mg_get contains lines of the form:
+#     name	TYPE	files and directories
+# where name is the name supplied to mg_get, TYPE is one of
+# PARA, MAIL, DIR, DIR2, BIB or TXTIMG and says how mg_get should process the
+# named files and directories
+#
+###########################################################################
+
+if ($?MG_GETRC) then
+  set mg_getrc = $MG_GETRC
+else
+  set mg_getrc = ~/.mg_getrc
+endif
+
+# Added by [TS:May/95]
+# if we don't have an mg_getrc file in existence then create a default one
+if !(-e $mg_getrc) then 
+  echo "Can not find a .mg_getrc, so creating a default one: $mg_getrc"
+
+  if ($?MGSAMPLE) then
+    set SampleData = $MGSAMPLE
+  else
+    set SampleData = ./SampleData
+  endif
+
+  cat > $mg_getrc << END
+alice	PARA	$SampleData/alice13a.txt.Z
+davinci	TXTIMG	$SampleData/davinci
+mailfiles	MAIL	~/mbox ~/.sentmail
+allfiles	DIR	~/Mail
+mods	LINESEP	$SampleData/MODIFICATIONS
+bible	PLAIN	$SampleData/bible/genesis.txt.Z $SampleData/bible/revelation.txt.Z
+END
+endif
+
+if (! $?MGIMAGEVIEWER) then
+  setenv MGIMAGEVIEWER "xv -"
+endif
+
+set rm = /bin/rm
+
+switch ($#argv)
+  case 1:
+  set flag = '-text'
+  breaksw
+
+  case 2:
+  set flag = $2
+  switch ($flag)
+     case '-i':
+	set flag = '-init'
+	breaksw
+     case '-t':
+	set flag = '-text'
+	breaksw
+     case '-c':
+	set flag = '-cleanup'
+	breaksw
+     case '-init':
+     case '-text':
+     case '-cleanup':
+     breaksw
+     default:
+     echo 'Usage: mg_get <document> [-i | -t | -c]'
+     exit(1)
+     endsw
+  breaksw
+
+  default:
+  echo 'Usage: get <document> [-i | -t | -c]'
+  exit(1)
+  endsw
+
+set COLLECTION = $1
+set TYPE  = `grep \^$1 $mg_getrc | cut -f2`
+set FILES = `grep \^$1 $mg_getrc | cut -f3`
+
+set bindir = $0
+set bindir = $bindir:h
+
+switch ($TYPE)
+  case PLAIN:
+# Just outputs the given text, assumes ^Bs already inserted 
+  switch ($flag)
+     case '-init':
+     breaksw
+
+     case '-text':
+      foreach f ($FILES)
+	if ($f:e == 'Z') then
+	  set decoder=zcat
+	else if ($f:e == 'gz') then
+	  set decoder=gunzip
+	else
+	  set decoder=cat
+	endif
+        $decoder < $f
+      end
+     breaksw #-text
+
+     case '-cleanup':
+     breaksw
+  endsw #flag
+  breaksw
+
+  case LINESEP:
+# Assumes that the documents are separated by a line of =====
+  switch ($flag)
+     case '-init':
+     breaksw
+
+     case '-text':
+      foreach f ($FILES)
+	if ($f:e == 'Z') then
+	  set decoder=zcat
+	else if ($f:e == 'gz') then
+	  set decoder=gunzip
+	else
+	  set decoder=cat
+	endif
+        $decoder < $f |  sed -e '/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/s/.*//' < $f
+      end
+     breaksw #-text
+
+     case '-cleanup':
+     breaksw
+  endsw #flag
+  breaksw
+
+  case PARA:
+# Splits the file at blank lines, which corresponds to paragraphs.
+  switch ($flag)
+     case '-init':
+     breaksw
+
+     case '-text':
+      foreach f ($FILES)
+	if ($f:e == 'Z') then
+	  set decoder=zcat
+	else if ($f:e == 'gz') then
+	  set decoder=gunzip
+	else
+	  set decoder=cat
+	endif
+      $decoder <$f |awk '   /^ *$/ {if (b!=1) printf "";b=1} \
+		\!/^ *$/ {print;b=0} \
+		 END {printf ""}'
+       end #foreach
+     breaksw #-text
+
+     case '-cleanup':
+     breaksw
+  endsw #flag
+  breaksw
+
+  case BIB:
+# Takes a list of files that contain bibliographies, and splits them up 
+#   by putting ^B after each reference. Assumes that each reference
+#   begins with a line '^@'.
+
+  switch ($flag)
+    case '-init':
+    breaksw
+ 
+    case '-text':
+      foreach f ($FILES)
+	if ($f:e == 'Z') then
+	  set decoder=zcat
+	else if ($f:e == 'gz') then
+	  set decoder=gunzip
+	else
+	  set decoder=cat
+	endif
+      $decoder <$f |awk '/^@/&&NR!=1{printf ""} {print $0} END{print ""}'
+      end # foreach
+    breaksw #-text
+ 
+    case '-cleanup':
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #BIB
+
+  case MAIL:
+# Takes a list of files that contain mail, and splits them up 
+#   by putting ^B after each message. Assumes that each message
+#   begins with a line '^From '.
+
+  switch ($flag)
+    case '-init':
+    breaksw
+ 
+    case '-text':
+      foreach f ($FILES)
+	if ($f:e == 'Z') then
+	  set decoder=zcat
+	else if ($f:e == 'gz') then
+	  set decoder=gunzip
+	else
+	  set decoder=cat
+	endif
+      $decoder <$f| awk '/xbtoa Begin/,/xbtoa End/ {next} /^From /&&NR!=1{printf ""} {print $0} END{print ""}'
+      end # foreach
+    breaksw #-text
+ 
+    case '-cleanup':
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #MAIL
+
+  case DIR:
+# Recursively concatenates every file in every subdirectory of the given
+#   directory.
+
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text'
+      find $FILES -type f -name '*.gz' -exec echo '<' {} '>' \;		\
+			 -exec gzcat {} \; -exec echo -n '' \;
+      find $FILES -type f -name '*.Z' -exec echo '<' {} '>' \;		\
+			 -exec zcat {} \; -exec echo -n '' \;
+#     find $FILES -type f -not -regex '.*\.\(gz\|Z\)' -exec echo '<' {} \
+#			'>' \; -exec cat {} \; -exec echo -n '' \;
+      find $FILES -type f \! \( -name '*.gz' -o -name '*.Z' \) \
+			-exec echo '<' {} '>' \; \
+			-exec cat {} \; -exec echo -n '' \;
+
+    breaksw
+
+    case '-cleanup':
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #DIR
+
+
+
+  case DIR2:
+# Recursively concatenates every file in every subdirectory of the given
+#   directory. Does not include filename
+
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text'
+      find $FILES -type f -name '*.gz'  		\
+			 -exec gzcat {} \; -exec echo -n '' \;
+      find $FILES -type f -name '*.Z' 	 		\
+			 -exec zcat {} \; -exec echo -n '' \;
+#     find $FILES -type f -not -regex '.*\.\(gz\|Z\)'	\
+#			-exec cat {} \; -exec echo -n '' \;
+      find $FILES -type f \! \( -name '*.gz' -o -name '*.Z' \) \
+			-exec cat {} \; -exec echo -n '' \;
+    breaksw
+
+    case '-cleanup':
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #DIR2
+
+
+
+
+  case TXTIMG:
+# compress and index the collection of text and images
+# (this code is suitable for all sorts of integrated collections
+#  of text and images)
+# Files that are related have the same prefix. For example,
+#  monaLisa.pgm might be a gray-level image, and
+#  monaLisa.txt would be a textual file describing the image.
+# The suffixes recognised are:
+#    .txt	ascii text
+#    .ptm	scanned text stored as a bilevel image
+#    .pbm	a black and white image (typically a line drawing)
+#    .pgm	a gray-scale image
+# In addition, if no corresponding ascii text file is found for
+#  a .pbm or .pgm file, then one is created with suffix .tmp.txt,
+#  and it stores the name of the image file (in principle it could
+#  store the OCR of a .txt.pbm file). At present the .tmp.txt files
+#  are deleted by the '-cleanup' option.
+  
+#### the next two 'set' statements define which directory the files
+#    come from, and where they will be stored. This is the only
+#    part of this code that is specific to the 'davinci' collection
+  set sourceDir = $FILES
+  set targetDir = $MGDATA/$COLLECTION
+
+  switch ($flag)
+    case '-init':
+      mkdir $targetDir >&/dev/null	   # create the directory to store
+					   # compressed images in
+      $rm -rf $targetDir/* >&/dev/null     # in case it already existed
+    
+      # take care if no match to foreach statements
+      set nonomatch
+
+      # process all pbm (black and white) images of text
+      foreach f ($sourceDir/*.ptm)
+        if ($f == "$sourceDir/*.ptm") then
+                break
+        endif
+	set base = $f:t
+	
+        $bindir/mgticbuild $targetDir/$base:r.ticlib.$$ $f
+        $bindir/mgticprune $targetDir/$base:r.ticlib.$$
+
+	$bindir/mgtic -L -e $targetDir/$base:r.ticlib.$$ $f >$targetDir/$base:r.tic
+	$rm $targetDir/$base:r.ticlib.$$
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do OCR here to get its contents
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '#######' $f > $r.tmp
+	endif
+      end
+      # process all pgm (gray scale) images
+      foreach f ($sourceDir/*.pgm)
+        if ($f == "$sourceDir/*.pgm") then
+                break
+        endif
+	set base = $f:t
+	$bindir/mgfelics -e $f >$targetDir/$base:r.flx
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do image recognition here to create one(!)
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '#######' $f > $r.tmp
+	endif
+      end
+      # process all pbm (black and white) images
+      foreach f ($sourceDir/*.pbm)
+        if ($f == "$sourceDir/*.pbm") then
+                break
+        endif
+	set base = $f:t
+	$bindir/mgbilevel -e $f >$targetDir/$base:r.blv
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do drawing recognition here to create one(!)
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '####### No corresponding text file available for this image' >$r.tmp
+	    echo 'Original image file name was' $f >> $r.tmp
+	endif
+      end
+      unset nonomatch
+    breaksw #-init
+
+    case '-text'
+      # take care if no match to foreach statements
+      set nonomatch
+
+      #output each text file and tmp.txt, with names of other associated files
+
+      foreach f ($sourceDir/*.txt $sourceDir/*.tmp)
+        if ($f == "$sourceDir/*.txt") then
+           continue
+        endif
+        if ($f == "$sourceDir/*.tmp") then
+           continue
+        endif
+	set r = $f:r	#root name of file
+	set base = $r:t
+        set first_image = 1 # set so that I print out image header once
+                            # also signifies if header printed out at all
+
+	foreach d ($targetDir/$base.*)
+          if ($d == "$targetDir/$base.*") then
+                break
+          endif
+
+          if ($first_image) then
+            set first_image = 0
+            echo '::::::::::'  #separate the image information from the text
+            echo 'Image(s) available:'
+          endif
+
+	  switch ($d:e)	# work out decoding method from suffix
+            case 'tic':
+              echo 'MGDATA (mgtic -d ' $d '  | '$MGIMAGEVIEWER') '
+            breaksw
+            case 'flx':
+              echo 'MGDATA (mgfelics -d ' $d '  | '$MGIMAGEVIEWER')'
+            breaksw
+            case 'blv':
+              echo 'MGDATA (mgbilevel -d ' $d '  | '$MGIMAGEVIEWER')'
+	    breaksw
+	  endsw # $d:e (suffix)
+
+	end #foreach d (associated file)
+
+        if (! $first_image) then
+	  echo '::::::::::'  #separate the image information from the text
+        endif
+
+	cat $f  # output the text associated with the images
+	echo -n ''
+      end #foreach f (text file)
+      unset nonomatch
+    breaksw #-text
+
+    case '-cleanup':
+      #remove temporary text files
+      $rm $sourceDir/*.tmp
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #IMGTXT
+
+
+  default:
+    echo 'Sorry, I do not know how to get' $1
+    exit 1	
+endsw
+exit 0
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get_merge.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get_merge.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get_merge.1	(revision 10506)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_get_merge 1 \*(Dt CITRI
+.SH NAME
+mg_get_merge \- output source texts for processing
+.SH SYNOPSIS
+.B mg_get_merge
+.I collection-name
+.if n .ti +9n
+[
+.BR \-init " |"
+.BR \-i " |"
+.BR \-text " |"
+.BR \-t " |"
+.BR \-cleanup " |"
+.B  \-c
+]
+.SH DESCRIPTION
+This program is the default one used by
+.BR mgmerge (1)
+to generate the source text for new documents to appended to
+an
+.BR mg (1)
+system database.
+Its function is exactly the same as
+.BR mg_get (1)
+except that it generates the 
+.I new 
+documents to be added to an
+.BR mg (1)
+system database that has already been built using
+.BR mgbuild(1).
+Any program may be used to generate the source
+text for
+.BR mgmerge (1),
+as long as it confirms to the interface specified
+here.
+.SH OPTIONS
+The
+.I collection-name
+must appear before any other option.  Only the first option has any
+significance.  If no option is specified,
+.B \-text
+is assumed.
+.TP "\w'\fB\-cleanup\fP and \fB\-c\fP'u+2n"
+.BR \-init " and " \-i
+The program is called once with this flag at the start of merging a
+collection.
+.TP
+.BR \-text " and " \-t
+The program is called with this flag multiple times during the
+merging of a collection.  The program outputs (on
+.IR stdout )
+the text of the collection.
+.I Documents
+within the collection are separated by ctrl-B's (ASCII code 2).
+.TP
+.BR \-cleanup " and " \-c
+The program is called once with this flag at the completion of
+merging a collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_get (1),
+.BR mgbuild (1),
+.BR mgmerge (1),
+.BR mg_text_merge (1),
+.BR mg_invf_merge (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get_merge.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get_merge.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mg_get_merge.sh	(revision 10506)
@@ -0,0 +1,313 @@
+#! /bin/csh -f
+###########################################################################
+#
+# mg_get_merge.sh -- script to get text for mgbuild
+# Copyright (C) 1994  Tim Bell, Shane Hudson (mods. for merging)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#
+###########################################################################
+#
+# "mg_get_merge" formats the text for mgbuild by collecting the appropriate
+#   documents, and outputing them with control-B after each document.
+#   The name of the text must be supplied as an argument.
+#   mg_get is called with -i (init) first, then with -t (text) each time the 
+#   text is needed, then with -c (cleanup).
+#   e.g. mg_get alice -t
+#
+###########################################################################
+
+
+
+# The directory containing the data files is stored in the environment
+#   variable MGSAMPLE
+
+if ($?MGSAMPLE) then
+  set SampleData = $MGSAMPLE
+else
+  set SampleData = ./SampleData
+endif
+
+if (! $?MGIMAGEVIEWER) then
+  setenv MGIMAGEVIEWER "xv -"
+endif
+
+set rm = /bin/rm
+
+switch ($#argv)
+  case 1:
+  set flag = '-text'
+  breaksw
+
+  case 2:
+  set flag = $2
+  switch ($flag)
+     case '-i':
+	set flag = '-init'
+	breaksw
+     case '-t':
+	set flag = '-text'
+	breaksw
+     case '-c':
+	set flag = '-cleanup'
+	breaksw
+     case '-init':
+     case '-text':
+     case '-cleanup':
+     breaksw
+     default:
+     echo 'Usage: get <document> [-i | -t | -c]'
+     exit(1)
+     endsw
+  breaksw
+
+  default:
+  echo 'Usage: get <document> [-i | -t | -c]'
+  exit(1)
+  endsw
+
+set bindir = $0
+set bindir = $bindir:h
+
+switch ($1)
+  case alice:
+  switch ($flag)
+     case '-init':
+     breaksw
+
+     case '-text':
+	echo "This is a test document 1 2 3 4 5 6 7 8 9 "
+	echo ""
+	echo "A B C"
+     breaksw
+
+     case '-cleanup':
+     breaksw
+  endsw #flag
+  breaksw
+
+  case bible:
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text':
+       # use uncompressed file if it exists
+       # revelation.txt already contains '^B' characters between verses
+       if (-e $SampleData/bible/revelation.txt) then
+          cat $SampleData/bible/revelation.txt
+       else
+          uncompress <$SampleData/bible/revelation.txt.Z
+    breaksw #-text
+
+    case '-cleanup':
+    breaksw #-cleanup
+
+  endsw #flag
+  breaksw #bible
+
+
+
+  case mailfiles:
+# Takes a list of files that contain mail, and splits them up 
+#   by putting ^B after each message. Assumes that each message
+#   begins with a line '^From '.
+# If messages are already in individual files, use "get allfiles"
+#   rather than this one.
+# The EXTRA documents added are in files in the directory mailextra
+#### The variable 'mailfiles' contains a list of files to be split up
+  set mailfiles = '~/mbox ~/.sentmail'
+  set mailextra = '~/extra/*'
+
+  switch ($flag)
+    case '-init':
+    breaksw
+
+    case '-text':
+      foreach f ($mailextra)
+	awk '/^From /&&NR!=1{print ""} {print $0} END{print ""}' $f
+      end # foreach
+    breaksw #-text
+
+    case '-cleanup':
+    breaksw #-cleanup
+
+  endsw #flag
+  breaksw #mailfiles
+
+
+
+  case allfiles:
+# Recursively concatenates every file in every subdirectory of the given
+#   directory.
+
+# The variable 'directory' on the next line contains the directory to be used
+  set directory = ~/Mail
+
+# The date of the file ".mgbuildtime" in 'directory' is the last
+# build or merge. At the start of the merge ("-init" argument) the
+# file ".mgmergetime" is touched. Only files newer than ".mgbuildtime"
+# but older than ".mgmergetime" are output by mg_get_merge
+
+  switch ($flag)
+    case '-init':
+        touch $directory/.mgmergetime
+    breaksw
+
+    case '-text'
+      find $directory -type f -newer $directory/.mgbuildtime \! -newer $directory/.mgmergetime \! -name '.*' -exec echo '<' {} '>' \; -exec cat {} \; -exec echo -n '' \;
+    breaksw
+
+    case '-cleanup':
+        touch $directory/.mgmergetime
+        touch $directory/.mgbuildtime
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #allfiles
+
+
+
+
+  case davinci:
+# compress and index the DaVinci collection of text and images
+# (this code is suitable for all sorts of integrated collections
+#  of text and images)
+# It assumes that all files are in one directory ($sourceDir).
+# Files that are related have the same prefix. For example,
+#  monaLisa.img.pgm might be a gray-level image, and
+#  monaLisa.txt.txt would be a textual file describing the image.
+# The suffixes recognised are:
+#    .txt.txt	ascii text
+#    .txt.pbm	scanned text stored as a bilevel image
+#    .img.pbm	a black and white image (typically a line drawing)
+#    .img.pgm	a gray-scale image
+# In addition, if no corresponding ascii text file is found for
+#  a .pbm or .pgm file, then one is created with suffix .tmp.txt,
+#  and it stores the name of the image file (in principle it could
+#  store the OCR of a .txt.pbm file). At present the .tmp.txt files
+#  are deleted by the '-cleanup' option.
+  
+#### the next two 'set' statements define which directory the files
+#    come from, and where they will be stored. This is the only
+#    part of this code that is specific to the 'davinci' collection
+  set sourceDir = $SampleData/davinci
+  set targetDir = $MGDATA/davinci
+
+  switch ($flag)
+    case '-init':
+      mkdir $targetDir >&/dev/null	   #create the directory to store
+					   # compressed images in
+      $rm -rf $targetDir/* >&/dev/null #in case it already existed
+    
+      # process all pbm (black and white) images of text
+      foreach f ($sourceDir/*.ptm)
+	set base = $f:t
+	
+        $bindir/mgticbuild $targetDir/$base:r.ticlib.$$ $f
+        $bindir/mgticprune $targetDir/$base:r.ticlib.$$
+
+	$bindir/mgtic -L -e $targetDir/$base:r.ticlib.$$ $f >$targetDir/$base:r.tic
+	$rm $targetDir/$base:r.ticlib.$$
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do OCR here to get its contents
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '#######' $f > $r.tmp
+	endif
+      end
+      # process all pgm (gray scale) images
+      foreach f ($sourceDir/*.pgm)
+	set base = $f:t
+	$bindir/mgfelics -e $f >$targetDir/$base:r.flx
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do image recognition here to create one(!)
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '#######' $f > $r.tmp
+	endif
+      end
+      # process all pbm (black and white) images
+      foreach f ($sourceDir/*.pbm)
+	set base = $f:t
+	$bindir/mgbilevel -e $f >$targetDir/$base:r.blv
+	set r = $f:r	#root name of file
+	if (! (-e $r.txt || -e $r.tmp)) then
+	# creates a file; could do drawing recognition here to create one(!)
+	    echo "No corresponding txt file for" $f "- creating" $r.tmp
+	    echo '####### No corresponding text file available for this image' >$r.tmp
+	    echo 'Original image file name was' $f >> $r.tmp
+	endif
+      end
+    breaksw #-init
+
+    case '-text'
+      #output each text file and tmp.txt, with names of other associated files
+      foreach f ($sourceDir/*.txt $sourceDir/*.tmp)
+	set r = $f:r	#root name of file
+	set base = $r:t
+	set n = `/bin/ls $sourceDir/$base.* | wc -l`
+	if ($n != 1) then # more files than just the text one
+	 echo '::::::::::'  #separate the image information from the text
+	 echo 'Image(s) available:'
+	 foreach d ($targetDir/$base.*)
+	  switch ($d:e)	# work out decoding method from suffix
+            case 'tic':
+              echo 'MGDATA (mgtic -d ' $d '  | '$MGIMAGEVIEWER') '
+            breaksw
+            case 'flx':
+              echo 'MGDATA (mgfelics -d ' $d '  | '$MGIMAGEVIEWER')'
+            breaksw
+            case 'blv':
+              echo 'MGDATA (mgbilevel -d ' $d '  | '$MGIMAGEVIEWER')'
+	    breaksw
+	  endsw # $d:e (suffix)
+	 end #foreach d (associated file)
+	echo '::::::::::'  #separate the image information from the text
+	endif # if more than one file
+	cat $f  # output the text associated with the images
+	echo -n ''
+      end #foreach f (text file)
+    breaksw #-text
+
+    case '-cleanup':
+      #remove temporary text files
+      $rm $sourceDir/*.tmp
+    breaksw #-cleanup
+  endsw #flag
+  breaksw #davinci
+
+
+#---------------------------
+  case mods:
+# Splits the modifications file at the mod separator "--------"
+  switch ($flag)
+     case '-init':
+     breaksw
+ 
+     case '-text':
+       sed -e 's/^---.*//g' < ${SampleData}/MODIFICATIONS
+     breaksw
+ 
+     case '-cleanup':
+     breaksw
+  endsw #flag
+  breaksw #mods
+
+  default:
+    echo 'Sorry, I do not know how to get' $1
+    exit 1	
+endsw
+exit 0
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild.1	(revision 10506)
@@ -0,0 +1,169 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbuild 1 \*(Dt CITRI
+.SH NAME
+mgbuild \- build an mg system database
+.SH SYNOPSIS
+.B mgbuild
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.BI \-d " mgdata dir"
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgbuild
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely build an
+.BR mg (1)
+system database ready for queries to be made
+by
+.BR mgquery.
+This program makes use of the
+.BR mg_get (1)
+script to obtain the text of the collection.
+.SH OPTIONS
+Options can occur in any order, but the collection name must be last.
+.TP "\w'\fIcollection-name\fP'u+2n"
+.BI \-c
+This specifies whether the
+.I get
+program is \*(lqcomplex\*(rq.  If a
+.I get
+program is \*(lqcomplex\*(rq, then it requires initialisation and
+cleanup with the
+.B \-i
+and
+.B \-c
+options.
+.TP
+.BI \-g " get"
+This specifies the program to use for getting the source text for the
+build.  If no
+.B \-g
+option is given, the default program
+.BR mg_get (1)
+is used.
+.TP
+.BI \-s " source"
+The
+.B mgbuild
+program consists of two parts.  The first part initializes variables
+to default values.  The second part uses these variables to control
+how the
+.BR mg (1)
+database is built.  This option specifies a program to execute between
+the first and second parts.  The details of what the variables are, and
+how they may be changed, are in comments in the
+.B mgbuild
+program.
+.TP
+.BI \-d " mgdata dir"
+Setting this option allows one to override the MGDATA environment variable.
+.TP
+.I collection-name
+This is the collection name, as required by the
+.BR mg_get (1)
+program.  It serves both as a
+.I case
+statement selector, and as the name of a subdirectory that holds the
+indexing files.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.chunk
+Inverted file chunk descriptor file.  When the inverted file is
+created, it is written in chunks that use no more than a set amount of
+memory.  This file describes those chunks.
+.TP
+.B *.invf.chunk.trans
+Word-occurrence-order to lexical-order translation file.  The
+.B *.invf.chunk
+file is written in word-occurrence order but is required by
+.B \-N2
+to be in lexical order.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for an order-preserving perfect hash function.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Text statistics.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild.sh	(revision 10506)
@@ -0,0 +1,339 @@
+#!/bin/csh -f
+###########################################################################
+#
+# mgbuild.sh -- Script used to build mg text collection.
+# Copyright (C) 1994  Neil Sharman
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)mgbuild.sh	1.9 16 Mar 1994
+#
+###########################################################################
+#  mg.build
+# Creates a Full Text Retrieval database
+#
+#  @(#)mgbuild.sh	1.9 16 Mar 1994
+#
+
+set complex = ""
+
+# Parse the command line arguments
+while ($#argv >= 1)
+  if ("$1" == "-s") then
+    shift
+    if ($#argv >= 1) then
+      set source = $1
+      shift
+    endif
+  else if ("$1" == "-d") then
+    shift
+    if ($#argv >= 1) then
+      set mgdata = $1
+      shift
+    endif
+  else if ("$1" == "-g") then
+    shift
+    if ($#argv >= 1) then
+      set get = $1
+      shift
+    endif
+  else if ("$1" == "-c") then
+    set complex = "-text"
+    shift
+  else
+    if ($?text == "0") then
+      set text = $1
+    endif
+    shift
+  endif
+    
+end
+
+if ($?text == "0") then
+  set prog = $0
+  echo "USAGE:"
+  echo "     "$prog:t" [-s config-script] [-g get-program] [-d mgdata dir] [-c] source"
+  echo ""
+  echo " The config-script is only needed if a non-standard build is required."
+  echo " The get-program defaults to mg_get if not specified."
+  exit 1	
+endif
+
+set bindir = $0
+set bindir = $bindir:h
+
+# if $pipe == 1 then pipe in the source text using $get and $text otherwise
+# read the source text directly from the file names specified in $input_files
+set pipe = 1
+
+if ($?get == "0") then
+  set complex = "-text"
+  set get = $bindir/mg_get
+endif
+
+if ($?mgdata) then
+  setenv MGDATA $mgdata
+endif
+
+if (-e $MGDATA/${text}.chunks) then
+  set input_files = `cat $MGDATA/${text}.chunks`
+endif
+
+# Set the stemming method
+#   Bit 0 = case folding
+#   Bit 1 = S stemmer
+set stem_method = 3
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then build collection with full indexes to blocked file
+# overriding stem_method (stem_method will be set to 0)
+# Otherwise don't build with indexes
+set do_indexes = 0
+
+
+# If do_text == 1 then do the text component of building a mg database. 
+# Otherwise don't do the text component.
+set do_text = 1
+
+
+# If do_invf == 1 then do the inversion component of building a mg database. 
+# Otherwise don't do the inversion component.
+set do_invf = 1
+
+
+# If do_pass1 == 1 then do pass1 of building a mg database. 
+# Otherwise don't do pass1.
+set do_pass1 = 1
+
+# If do_pass2 == 1 then do pass2 of building a mg database. 
+# Otherwise don't do pass2.
+set do_pass2 = 1
+
+
+# $invf_mem specifies the amount of memory to use for the pass2 inversion
+set invf_mem = 32
+
+
+# $num_chunks specifies the number of interium chunks of inverted file that
+# may be written to disc before a merge into the invf file is done
+set num_chunks = 3
+
+# $invf_level specifies the level of the inverted file that will be generated.
+set invf_level = 2
+
+
+# If $strip_sgml == 1 then sgml tags are stripped from the inversion phase.
+# Otherwise sgml tags are kepted.
+set strip_sgml = 1
+
+
+# $trace specifies the interval between trace entries in Mb.
+# If this is not set no trace entries will be generated.
+set trace = 10
+
+
+# $weight_bits specifies the number of bits of precision bo be given to the 
+# approximate weights.
+set weight_bits = 6
+
+
+# $mcd specifies the commandline arguments for the mg_compression_dict program
+#### Note: Set -S so novel words can be encoded, as this will happen if
+#### mgmerge is used.
+set mcd = -S
+
+
+# Source the parameter file to modify parameters of the build.
+if ($?source) then
+  source ${source}
+endif
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then set stem_method = 0
+if ("$do_indexes" == "1") then
+  set stem_method = 0
+endif
+
+
+# Generate the collection name.
+set coll_name = ${text}
+if ("$invf_level" == "3") then
+  set coll_name = ${text}-p
+endif
+
+# Generate the directory for the collection.
+if (-e $MGDATA/${coll_name}) then
+else
+  mkdir $MGDATA/${coll_name}
+endif
+
+# Generate the base name for the collection.
+set bname = ${coll_name}/${coll_name}
+
+
+#build up the command lines for pass 1 and 2
+set pass1 = (-f ${bname} -${invf_level} -m ${invf_mem} -s ${stem_method})
+set pass2 = (-f ${bname} -${invf_level} -c ${num_chunks})
+
+if ($strip_sgml) then
+  set pass1 = (${pass1} -G)
+  set pass2 = (${pass2} -G)
+endif
+
+if ($?trace) then
+  set pass1 = (${pass1} -t ${trace})
+  set pass2 = (${pass2} -t ${trace})
+endif
+
+if ($do_text) then
+  set pass1 = (${pass1} -T1)
+  set pass2 = (${pass2} -T2)
+endif
+
+if ($do_invf) then
+  set pass1 = (${pass1} -I1)
+  set pass2 = (${pass2} -I2)
+endif
+  
+if ($?trace_name) then
+  set pass1 = (${pass1} -n ${trace_name})
+  set pass2 = (${pass2} -n ${trace_name})
+endif
+  
+if ($?comp_stats) then
+  set pass2 = (${pass2} -C ${comp_stats})
+endif
+
+echo "-----------------------------------"
+echo "`uname -n`, `date`"
+echo "${text} --> ${bname}"
+echo "-----------------------------------"
+if ($pipe) then
+  if ("$complex" != "") then
+    echo "$get $text -init"
+    $get $text -init
+    if ("$status" != "0") exit 1 
+    echo "-----------------------------------"
+  endif  
+endif
+
+if (${do_pass1}) then
+  if ($pipe) then
+    if ($?pass1filter) then
+      echo "$get $text $complex | $pass1filter | mg_passes ${pass1}"
+      $get $text $complex| $pass1filter | $bindir/mg_passes ${pass1}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass1}"
+      $get $text $complex| $bindir/mg_passes ${pass1}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass1} ${input_files}
+    $bindir/mg_passes ${pass1} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+
+  echo "mg_perf_hash_build -f ${bname}"
+  $bindir/mg_perf_hash_build -f ${bname}
+  if ("$status" != "0") exit 1 
+
+  echo "-----------------------------------"
+  echo "mg_compression_dict -f ${bname} ${mcd}"
+  $bindir/mg_compression_dict -f ${bname} ${mcd}
+  if ("$status" != "0") exit 1 
+  echo "-----------------------------------"
+endif
+
+if (${do_pass2}) then
+  if ($pipe) then
+    if ($?pass2filter) then
+      echo "$get $text $complex | $pass2filter | mg_passes ${pass2}"
+      $get $text $complex | $pass2filter | $bindir/mg_passes ${pass2}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass2}"
+      $get $text $complex | $bindir/mg_passes ${pass2}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass2} ${input_files}
+    $bindir/mg_passes ${pass2} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+endif
+
+echo "mg_weights_build -f ${bname} -b ${weight_bits}"
+$bindir/mg_weights_build -f ${bname} -b ${weight_bits}
+if ("$status" != "0") exit 1 
+
+echo "-----------------------------------"
+
+echo "mg_invf_dict -f ${bname} -b 4096"
+$bindir/mg_invf_dict -f ${bname} -b 4096
+if ("$status" != "0") exit 1 
+
+echo "-----------------------------------"
+
+# [RPAP - Jan 97: Stem Index Change]
+if ("$do_indexes" == "1") then
+  echo "mg_stem_idx -f ${bname} -b 4096 -s1"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s1
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${bname} -b 4096 -s2"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s2
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${bname} -b 4096 -s3"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s3
+  if ("$status" != "0") exit 1 
+
+  echo "-----------------------------------"
+endif
+
+echo "mgstat -f ${bname} -E"
+$bindir/mgstat -f ${bname} -E
+if ("$status" != "0") exit 1 
+
+if ($pipe) then
+  if ("$complex" != "") then
+    echo "-----------------------------------"
+    echo "$get $text -cleanup"
+    $get $text -cleanup
+    if ("$status" != "0") exit 1 
+  endif
+endif
+
+echo "-----------------------------------"
+echo "`uname -n`, `date`"
+echo "-----------------------------------"
+
+echo "-- The fast-loading compression dictionary has not been built."
+echo "-- If you wish to build it, execute the following command:"
+echo "-- "$bindir/mg_fast_comp_dict -f ${bname}
+
+echo "-----------------------------------"
+
+echo ""
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild_4.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild_4.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild_4.1	(revision 10506)
@@ -0,0 +1,53 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgbuild_4 1 \*(Dt CITRI
+.SH NAME
+mgbuild_4 \- build an mg system database using 4 passes instead of 2
+.SH SYNOPSIS
+.B mgbuild_4
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.BI \-d " mgdata dir"
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgbuild_4
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely build an
+.BR mg (1)
+system database ready for queries to be made
+by
+.BR mgquery.
+This program makes use of the
+.BR mg_get (1)
+script to obtain the text of the collection.
+In 
+.BR mgbuild (1)
+the build is done by two passes over the input text. The first
+pass creates the compressed text dictionary and inverted file dictionary,
+the second pass creates the compressed text and inverted file. What 
+.BR mgbuild_4
+does is use a separate pass for each function. This will be slower but will
+not require as much RAM at one time. Therefore, if your build is failing
+due to running short of memory, then 
+.BR mgbuild_4
+is worth a try.
+.SH "SEE ALSO"
+.na
+.BR mgbuild (1)
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild_4.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild_4.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgbuild_4.sh	(revision 10506)
@@ -0,0 +1,435 @@
+#!/bin/csh -f
+###########################################################################
+#
+# mgbuild_4.sh -- Script used to build mg text collection in 4 passes.
+# Copyright (C) 1994  Neil Sharman; Modified by tes@kbs 1995
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#
+###########################################################################
+#
+# Does an mgbuild in 4 passes instead of 2 passes.
+# This is useful if one does not have as much RAM and a large collection.
+#
+
+set complex = ""
+
+# ************ parse the command line arguments ************
+
+while ($#argv >= 1)
+  if ("$1" == "-s" || "$1" == "--source") then
+    shift
+    if ($#argv >= 1) then
+      set source = $1
+      shift
+    endif
+  else if ("$1" == "-g" || "$1" == "--get") then
+    shift
+    if ($#argv >= 1) then
+      set get = $1
+      shift
+    endif
+  else if ("$1" == "-c" || "$1" == "--complex") then
+    set complex = "-text"
+    shift
+  else
+    if (! $?text ) then
+      set text = $1
+    endif
+    shift
+  endif
+    
+end
+
+if (! $?text ) then
+  set prog = $0
+  echo "USAGE:"
+  echo "     "$prog:t" [-s config-script] [-g get-program] [-c] source"
+  echo ""
+  echo " The config-script is only needed if a non-standard build is required."
+  echo " The get-program defaults to mg_get if not specified."
+  exit 1	
+endif
+
+set bindir = `which $0` # find which one we are executing
+set bindir = $bindir:h # use it as the bindir path
+
+# ************ set up shell variables ************
+# Override these by providing a script to source using the -s option
+
+# if $pipe == 1 then pipe in the source text using $get and $text otherwise
+# read the source text directly from the file names specified in $input_files
+set pipe = 1
+
+set get_options = ""
+
+
+if (! $?get ) then
+  set complex = "-text"
+  set get = $bindir/mg_get $get_options
+endif
+
+
+if (-e $MGDATA/${text}.chunks) then
+  set input_files = `cat $MGDATA/${text}.chunks`
+endif
+
+# Set the stemming method
+#   Bit 0 = case folding
+#   Bit 1 = S stemmer
+set stem_method = 3
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then build collection with full indexes to blocked file
+# overriding stem_method (stem_method will be set to 0)
+# Otherwise don't build with indexes
+set do_indexes = 0
+
+
+# whether to build weights or not
+set do_weights = 1
+
+# If do_pass1 == 1 then do pass1 of building a mg database. 
+# Otherwise don't do pass1.
+# Text 1st pass
+set do_pass1 = 1
+
+# If do_pass2 == 1 then do pass2 of building a mg database. 
+# Otherwise don't do pass2.
+# Text 2nd pass
+set do_pass2 = 1
+
+# If do_pass3 == 1 then do pass3 of building a mg database. 
+# Otherwise don't do pass3.
+# Invf 1st pass
+set do_pass3 = 1
+
+# If do_pass4 == 1 then do pass4 of building a mg database. 
+# Otherwise don't do pass4.
+# Invf 2nd pass
+set do_pass4 = 1
+
+# Buffer size used by mg_passes
+# Should be big enough to hold largest document
+# In Kilobytes
+set buf_size = 3072
+
+# $invf_mem specifies the amount of memory to use for the pass2 inversion
+set invf_mem = 5
+
+# $num_chunks specifies the number of interium chunks of inverted file that
+# may be written to disc before a merge into the invf file is done
+set num_chunks = 3
+
+# $invf_level specifies the level of the inverted file that will be generated.
+set invf_level = 2
+
+
+# If $strip_sgml == 1 then sgml tags are stripped from the inversion phase.
+# Otherwise sgml tags are kepted.
+set strip_sgml = 1
+
+
+# $trace specifies the interval between trace entries in Mb.
+# If this is not set no trace entries will be generated.
+set trace = 10
+
+
+# $weight_bits specifies the number of bits of precision bo be given to the 
+# approximate weights.
+set weight_bits = 6
+
+
+# $mcd specifies the commandline arguments for the mg_compression_dict program
+set mcd = -C
+
+
+# Source the parameter file to modify parameters of the build.
+if ($?source) then
+  source ${source}
+endif
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then set stem_method = 0
+if ("$do_indexes" == "1") then
+  set stem_method = 0
+endif
+
+
+# Generate the collection name.
+set coll_name = ${text}
+if ("$invf_level" == "3") then
+  set coll_name = ${text}-p
+endif
+
+# Generate the directory for the collection.
+if (-e $MGDATA/${coll_name}) then
+else
+  mkdir $MGDATA/${coll_name}
+endif
+
+# Generate the base name for the collection.
+set bname = ${coll_name}/${coll_name}
+
+# ************ set up pass parameters ************
+
+if ($do_pass1) then
+  set pass1_text = (-f ${bname} -T1)
+endif
+
+if ($do_pass2) then
+  set pass2_text = (-f ${bname} -T2)
+endif
+
+if ($do_pass3) then
+  set pass3_invf = (-f ${bname} -${invf_level} -m ${invf_mem} -s ${stem_method})
+  set pass3_invf = (${pass3_invf} -N1)
+endif
+
+if ($do_pass4) then
+  set pass4_invf = (-f ${bname} -${invf_level} -N2)
+endif
+
+if ($strip_sgml) then
+  set pass1_text = (${pass1_text} -G)
+  set pass2_text = (${pass2_text} -G)
+  set pass3_invf = (${pass3_invf} -G)
+  set pass4_invf = (${pass4_invf} -G)
+endif
+
+if ($?trace) then
+  set pass1_text = (${pass1_text} -t ${trace})
+  set pass2_text = (${pass2_text} -t ${trace})
+  set pass3_invf = (${pass3_invf} -t ${trace})
+  set pass4_invf = (${pass4_invf} -t ${trace})
+endif
+
+if ($?trace_name) then
+  set pass1_text = (${pass1_text} -n ${trace_name})
+  set pass2_text = (${pass2_text} -n ${trace_name})
+  set pass3_invf = (${pass3_invf} -n ${trace_name})
+  set pass4_invf = (${pass4_invf} -n ${trace_name})
+endif
+
+if ($buf_size) then
+  set pass1_text = (${pass1_text} -b ${buf_size})
+  set pass2_text = (${pass2_text} -b ${buf_size})
+  set pass3_invf = (${pass3_invf} -b ${buf_size})
+  set pass4_invf = (${pass4_invf} -b ${buf_size})
+endif
+  
+if ($?comp_stats) then
+  set pass2_text = (${pass2_text} -C ${comp_stats})
+endif
+
+echo "-----------------------------------"
+echo "`uname -n`, `date`"
+echo "${text} --> ${bname}"
+echo "-----------------------------------"
+
+# ************ init get ************
+
+if ($pipe) then
+  if ("$complex" != "") then
+    echo "$get $text -init"
+    $get $text -init
+    if ("$status" != "0") exit 1 
+    echo "-----------------------------------"
+  endif  
+endif
+
+# ************************************* T E X T **********************************
+
+# ************ pass 1_text ************
+
+if (${do_pass1}) then
+  if ($pipe) then
+    if ($?pass1filter) then
+      echo "$get $text $complex | $pass1filter | mg_passes ${pass1_text}"
+      $get $text $complex| $pass1filter | $bindir/mg_passes ${pass1_text}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass1_text}"
+      $get $text $complex| $bindir/mg_passes ${pass1_text}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass1_text} ${input_files}
+    $bindir/mg_passes ${pass1_text} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+endif
+
+# ************ compression dict  ************
+if ($do_pass2) then 
+  echo "mg_compression_dict -f ${bname} ${mcd}"
+  $bindir/mg_compression_dict -f ${bname} ${mcd}
+  if ("$status" != "0") exit 1 
+  echo "-----------------------------------"
+endif
+
+# ************ pass 2_text ************
+if (${do_pass2}) then
+  if ($pipe) then
+    if ($?pass2filter) then
+      echo "$get $text $complex | $pass2filter | mg_passes ${pass2_text}"
+      $get $text $complex| $pass2filter | $bindir/mg_passes ${pass2_text}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass2_text}"
+      $get $text $complex| $bindir/mg_passes ${pass2_text}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass2_text} ${input_files}
+    $bindir/mg_passes ${pass2_text} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+endif
+
+# ************************************* I N V F **********************************
+
+# ************ pass 3_invf ************
+if (${do_pass3}) then
+  if ($pipe) then
+    if ($?pass3filter) then
+      echo "$get $text $complex | $pass3filter | mg_passes ${pass3_invf}"
+      $get $text $complex| $pass3filter | $bindir/mg_passes ${pass3_invf}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass3_invf}"
+      $get $text $complex| $bindir/mg_passes ${pass3_invf}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass3_invf} ${input_files}
+    $bindir/mg_passes ${pass3_invf} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+endif
+
+# ************ perfect hash  ************
+if ($do_pass4) then
+  echo "mg_perf_hash_build -f ${bname}"
+  $bindir/mg_perf_hash_build -f ${bname}
+  if ("$status" != "0") exit 1 
+
+  echo "-----------------------------------"
+endif
+
+# ************ pass 4_invf ************
+if (${do_pass4}) then
+  if ($pipe) then
+    if ($?pass4filter) then
+      echo "$get $text $complex | $pass4filter | mg_passes ${pass4_invf}"
+      $get $text $complex| $pass4filter | $bindir/mg_passes ${pass4_invf}
+      if ("$status" != "0") exit 1 
+    else
+      echo "$get $text $complex | mg_passes ${pass4_invf}"
+      $get $text $complex| $bindir/mg_passes ${pass4_invf}
+      if ("$status" != "0") exit 1 
+    endif
+  else
+    echo mg_passes ${pass4_invf} ${input_files}
+    $bindir/mg_passes ${pass4_invf} ${input_files}
+    if ("$status" != "0") exit 1 
+  endif
+  echo "-----------------------------------"
+endif
+
+
+# ************ build invf dictionary ************
+
+if ($do_pass4) then
+  echo "mg_invf_dict -f ${bname} -b 4096"
+  $bindir/mg_invf_dict -f ${bname} -b 4096
+  if ("$status" != "0") exit 1 
+  echo "-----------------------------------"
+endif
+
+# ******** build indexes to stem dict *********
+
+# [RPAP - Jan 97: Stem Index Change]
+if ($do_pass4 && "$do_indexes" == "1") then
+  echo "mg_stem_idx -f ${bname} -b 4096 -s1"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s1
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${bname} -b 4096 -s2"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s2
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${bname} -b 4096 -s3"
+  $bindir/mg_stem_idx -f ${bname} -b 4096 -s3
+  if ("$status" != "0") exit 1 
+
+  echo "-----------------------------------"
+endif
+
+# ************ build weights ************
+
+if ($do_pass4 && $do_weights) then
+  echo "mg_weights_build -f ${bname} -b ${weight_bits} "
+  $bindir/mg_weights_build -f ${bname} -b ${weight_bits}
+  if ("$status" != "0") exit 1 
+  echo "-----------------------------------"
+endif
+
+# *******************************************************************************
+
+
+# ************ print out statistics ************
+if ($do_pass1 && $do_pass2 && $do_pass3 && $do_pass4) then
+  echo "mgstat -f ${bname} -E"
+  $bindir/mgstat -f ${bname} -E
+  if ("$status" != "0") exit 1 
+endif
+
+
+# ************ cleanup get ************
+
+if ($pipe) then
+  if ("$complex" != "") then
+    echo "-----------------------------------"
+    echo "$get $text -cleanup"
+    $get $text -cleanup
+    if ("$status" != "0") exit 1 
+  endif
+endif
+
+echo "-----------------------------------"
+echo "`uname -n`, `date`"
+echo "-----------------------------------"
+
+if ($do_pass2) then
+  echo "-- The fast-loading compression dictionary has not been built."
+  echo "-- If you wish to build it, execute the following command:"
+  echo "-- "$bindir/mg_fast_comp_dict -f ${bname}
+
+  echo "-----------------------------------"
+endif
+
+echo ""
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgmerge.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgmerge.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgmerge.1	(revision 10506)
@@ -0,0 +1,175 @@
+`.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgmerge 1 \*(Dt CITRI
+.SH NAME
+mgmerge \- update an mg system database with new documents
+.SH SYNOPSIS
+.B mgmerge
+[
+.B \-c
+]
+[
+.BI \-g " get"
+]
+[
+.BI \-s " source"
+]
+[
+.B \-S
+]
+[
+.B \-w
+]
+.I collection-name
+.SH DESCRIPTION
+.B mgmerge
+is a
+.B csh
+script that executes all the appropriate programs in the correct order
+to completely merge a current
+.BR mg (1)
+system database ready with some new documents, saving the need for a complete
+database rebuild with
+.B mgbuild.
+It does this by building a second
+.BR mg (1)
+system database from the new documents and then merging this database
+with the old one.
+This program makes use of the
+.BR mg_get_merge (1)
+script to obtain the text of the collection.
+.B mgmerge
+cannot edit or delete documents already in a database; only new documents
+can be added.
+.SH OPTIONS
+Options can occur in any order, but the collection name must be last.
+.TP "\w'\fIcollection-name\fP'u+2n"
+.BI \-c
+This specifies whether the
+.I get
+program is \*(lqcomplex\*(rq.  If a
+.I get
+program is \*(lqcomplex\*(rq, then it requires initialisation and
+cleanup with the
+.B \-i
+and
+.B \-c
+options.
+.TP
+.BI \-g " get"
+This specifies the program to use for getting the source text for the
+build.  If no
+.B \-g
+option is given, the default program
+.BR mg_get_merge (1)
+is used.
+.TP
+.BI \-s " source"
+The
+.B mgmerge
+program consists of two parts.  The first part initializes variables
+to default values.  The second part uses these variables to control
+how the
+.BR mg (1)
+database is built.  This option specifies a program to execute between
+the first and second parts.  The details of what the variables are, and
+how they may be changed, are in comments in the
+.B mgmerge
+program.
+If this option is used, the program should ideally be the same one that
+was called by
+.BR mgbuild (1)
+to build the database since some parameters need to be consistent between
+.B mgbuild
+and
+.B mgmerge.
+.TP
+.B \-S
+This option will cause a slow merge to be performed on the inverted files,
+where each inverted file entry is decoded and recoded.
+The default is a fast merge. Accumulated fast merges slowly degrade
+compression performance on the resulting inverted file so
+a periodic slow merge is recommended.
+.TP
+.B \-w
+Adding new documents can have an effect on the weight of the previous ones.
+By default the weights for documents already in the collection are not 
+recomputed since the change in their values is usually small.
+This option forces new weights to be recomputed.
+Periodic use of this option, as for the "-S" option, is recomended,
+otherwise query rankings may become inaccurate.
+.TP
+.I collection-name
+This is the collection name, as required by the
+.BR mg_get_merge (1)
+program.  It serves both as a
+.I case
+statement selector, and as the name of a subdirectory that holds the
+indexing files.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+Note that a temporary directory under the
+.B MGDATA
+directory is used to perform the merge.
+The default name for this directory is
+.BR MERGE .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Text statistics.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgbuild (1),
+.BR mg_get_merge (1),
+.BR mg_get (1),
+.BR mg_invf_merge (1),
+.BR mg_text_merge (1),
+.BR mg_query (1),
+.BR mg_weights_build (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgmerge.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgmerge.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/mgmerge.sh	(revision 10506)
@@ -0,0 +1,417 @@
+#!/bin/csh -f
+###########################################################################
+#
+# mgmerge.sh -- Script used to build mg text collection.
+# Copyright (C) 1994  Neil Sharman, Shane Hudson (mods. for merging)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#
+###########################################################################
+
+set complex = ""
+set slow_merge = ""
+set guess_weights = "-w "
+# [RPAP - Feb 97: Level 3 Merge]
+set text_pass = 1
+
+# Parse the command line arguments
+while ($#argv >= 1)
+  if ("$1" == "-s") then
+    shift
+    if ($#argv >= 1) then
+      set source = $1
+      shift
+    endif
+  else if ("$1" == "-g") then
+    shift
+    if ($#argv >= 1) then
+      set get = $1
+      shift
+    endif
+  else if ("$1" == "-c") then
+    set complex = "-text"
+    shift
+  else if ("$1" == "-S") then
+# set slow merge option in mg_invf_merge
+    set slow_merge = "-s "
+    shift
+  else if ("$1" == "-w") then
+# turn weights guessing off (rebuild weights file from scratch)
+    set guess_weights = ""
+    shift
+
+# [RPAP - Feb 97: Level 3 Merge]
+  else if ("$1" == "-T") then
+# turn text pass off
+    set text_pass = 0
+    shift
+
+  else
+    if ($?text == "0") then
+      set text = $1
+    endif
+    shift
+  endif
+    
+end
+
+if ($?text == "0") then
+  set prog = $0
+  echo "USAGE:"
+  echo "     "$prog:t" [-s config-script] [-g get-program] [-c] source"
+  echo ""
+  echo " The config-script is only needed if a non-standard build is required."
+  echo " The get-program defaults to mg_get if not specified."
+  exit 1	
+endif
+
+set bindir = $0
+set bindir = $bindir:h
+
+# if $pipe == 1 then pipe in the source text using $get and $text otherwise
+# read the source text directly from the file names specified in $input_files
+set pipe = 1
+
+if ($?get == "0") then
+  set complex = "-text"
+  set get = $bindir/mg_get_merge
+endif
+
+if (-e $MGDATA/${text}.chunks) then
+  set input_files = `cat $MGDATA/${text}.chunks`
+endif
+
+# Set the inversion method this may be either "I" or "N"
+# N is memory-efficient, I is faster for small collections
+set invf_method = N
+
+
+# Set the stemming method
+#   Bit 0 = case folding
+#   Bit 1 = S stemmer
+set stem_method = 3
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then build collection with full indexes to blocked file
+# overriding stem_method (stem_method will be set to 0)
+# Otherwise don't build with indexes
+set do_indexes = 0
+
+
+# $invf_mem specifies the amount of memory to use for the pass2 inversion
+# This only has an effect if $invf_method is "N".
+set invf_mem = 32
+
+
+# $num_chunks specifies the number of interium chunks of inverted file that
+# may be written to disc before a merge into the invf file is done
+# This only has an effect if $invf_method is "N".
+set num_chunks = 3
+
+# $invf_level specifies the level of the inverted file that will be generated.
+# Note: The value *MUST* be the same as was used to build the collection
+# that is being merged.
+# In the current mg_invf_merge implementation the maximum level is 2. 
+# Paragraph-level inversion (invf_level = 3) is NOT supported.
+set invf_level = 2
+
+
+# If $strip_sgml == 1 then sgml tags are stripped from the inversion phase.
+# Otherwise sgml tags are kepted.
+set strip_sgml = 1
+
+
+# $trace specifies the interval between trace entries in Mb.
+# If this is not set no trace entries will be generated.
+set trace = 10
+
+
+# $weight_bits specifies the number of bits of precision bo be given to the 
+# approximate weights.
+set weight_bits = 6
+
+
+# $mcd specifies the commandline arguments for the mg_compression_dict program
+set mcd = -S
+
+# $merge_name is the name of the subdirectory under ${MGDATA} where
+# the mergeing steps will be performed. There should NOT be an mg
+# collection with this name! The default is "MERGE"
+set merge = "MERGE"
+
+# Source the parameter file to modify parameters of the build.
+if ($?source) then
+  source ${source}
+endif
+
+
+# [RPAP - Jan 97: Stem Index Change]
+# If do_indexes == 1 then set stem_method = 0
+if ($do_indexes) then
+  set stem_method = 0
+endif
+
+
+# Generate the collection name.
+set coll_name = ${text}
+
+# Generate the directory where merging will take place
+if (-e $MGDATA/${merge}) then
+else
+  mkdir $MGDATA/${merge}
+endif
+
+# Generate the base name for the collection.
+# [RPAP - Feb 97: Level 3 Merge]
+set bname = ${coll_name}
+
+# generate the old, new and merge names in the $merge directory
+set oldname = ${merge}/${coll_name}.old
+set newname = ${merge}/${coll_name}.new
+set mergename = ${merge}/${coll_name}
+
+# build up the command lines for pass 1 and 2 to build a
+# dummy collection for the new documents
+set pass1 = (-f ${newname} -${invf_level} -m ${invf_mem} -s ${stem_method})
+set pass2 = (-f ${newname} -${invf_level} -c ${num_chunks})
+
+if ($strip_sgml) then
+  set pass1 = (${pass1} -G)
+  set pass2 = (${pass2} -G)
+endif
+
+if ($?trace) then
+  set pass1 = (${pass1} -t ${trace})
+  set pass2 = (${pass2} -t ${trace})
+endif
+
+# Note that a -T1 pass isnt done since the old .text.stats file is used
+# as the compression model for compressing the new documents.
+
+# [RPAP - Feb 97: Level 3 Merge]
+# Do not perform -T2 pass if text_pass == 0
+if ($text_pass) then
+  set pass2 = (${pass2} -T2)
+endif
+
+set pass1 = (${pass1} -${invf_method}1)
+set pass2 = (${pass2} -${invf_method}2)
+
+
+if ($?trace_name) then
+  set pass1 = (${pass1} -n ${trace_name})
+  set pass2 = (${pass2} -n ${trace_name})
+endif
+  
+if ($?comp_stats) then
+  set pass2 = (${pass2} -C ${comp_stats})
+endif
+
+########################################################################
+# Here is where mgmerge goes to work.
+
+echo "--------------------------------------------------------------"
+echo "`uname -n`, `date`"
+echo "MGMERGE collection: ${bname}"
+echo "--------------------------------------------------------------"
+echo "FIRST PHASE: build new collection from new documents"
+echo "--------------------------------------------------------------"
+
+# move and rename the text dictionary file
+# [RPAP - Feb 97: Level 3 Merge] - only if performing text pass
+if ($text_pass) then
+  mv $MGDATA/${bname}.text.dict $MGDATA/${newname}.text.dict
+endif
+
+if ($pipe) then
+  if ("$complex" != "") then
+    echo ">> $get $text -init"
+    $get $text -init
+    if ("$status" != "0") exit 1 
+    echo "-----------------------------------"
+  endif  
+endif
+
+if ($pipe) then
+  if ($?pass1filter) then
+    echo ">> $get $text $complex | $pass1filter | mg_passes ${pass1}"
+    $get $text $complex| $pass1filter | $bindir/mg_passes ${pass1}
+    if ("$status" != "0") exit 1 
+  else
+    echo ">> $get $text $complex | mg_passes ${pass1}"
+    $get $text $complex| $bindir/mg_passes ${pass1}
+    if ("$status" != "0") exit 1 
+  endif
+else
+  echo ">> mg_passes ${pass1} ${input_files}"
+  $bindir/mg_passes ${pass1} ${input_files}
+  if ("$status" != "0") exit 1 
+endif
+echo "-----------------------------------"
+
+echo "mg_perf_hash_build -f ${newname}"
+$bindir/mg_perf_hash_build -f ${newname}
+if ("$status" != "0") exit 1 
+echo "-----------------------------------"
+
+if ($pipe) then
+  if ($?pass2filter) then
+    echo ">> $get $text $complex | $pass2filter | mg_passes ${pass2}"
+    $get $text $complex | $pass2filter | $bindir/mg_passes ${pass2}
+    if ("$status" != "0") exit 1 
+  else
+    echo ">> $get $text $complex | mg_passes ${pass2}"
+    $get $text $complex | $bindir/mg_passes ${pass2}
+    if ("$status" != "0") exit 1 
+  endif
+else
+  echo ">> mg_passes ${pass2} ${input_files}"
+  $bindir/mg_passes ${pass2} ${input_files}
+  if ("$status" != "0") exit 1 
+endif
+echo "-----------------------------------"
+
+if ($pipe) then
+  if ("$complex" != "") then
+    echo "-----------------------------------"
+    echo ">> $get $text -cleanup"
+    $get $text -cleanup
+    if ("$status" != "0") exit 1 
+  endif
+endif
+
+echo "---------------------------------------"
+date
+echo "--------------------------------------------------------------"
+echo "SECOND PHASE: merge the two collections"
+echo "--------------------------------------------------------------"
+
+# move the appropriate files from the base directory to the merge dir
+echo "(moving files....)"
+# [RPAP - Feb 97: Level 3 Merge]
+# Move files if doing text pass
+if ($text_pass) then
+  mv $MGDATA/${bname}.text       $MGDATA/${oldname}.text
+  mv $MGDATA/${bname}.text.idx   $MGDATA/${oldname}.text.idx
+else
+# Need this file if building weights
+  cp -d $MGDATA/${bname}.text.idx   $MGDATA/${mergename}.text.idx
+endif
+mv $MGDATA/${bname}.invf       $MGDATA/${oldname}.invf
+mv $MGDATA/${bname}.invf.idx   $MGDATA/${oldname}.invf.idx
+mv $MGDATA/${bname}.invf.dict  $MGDATA/${oldname}.invf.dict
+# the old weight file may be used for the new file
+mv $MGDATA/${bname}.weight     $MGDATA/${mergename}.weight
+# EOC: the old invf.paragraph file may be used for the new file for Level 3 Invf
+if (-e $MGDATA/${bname}.invf.paragraph) then
+  mv $MGDATA/${bname}.invf.paragraph  $MGDATA/${mergename}.invf.paragraph
+endif
+echo "---------------------------------------"
+
+# [RPAP - Feb 97: Level 3 Merge]
+# Only merge text if doing text pass
+if ($text_pass) then
+  echo ">> mg_text_merge -f ${mergename}"
+  $bindir/mg_text_merge -f $mergename
+  echo "---------------------------------------"
+endif
+
+echo ">> mg_invf_merge ${slow_merge}${guess_weights} -f ${mergename}"
+$bindir/mg_invf_merge ${slow_merge}${guess_weights} -f ${mergename}
+echo "---------------------------------------"
+
+#remove .weight file, so a new one will be created by mg_weights_build
+if ("$guess_weights" == "") then
+  echo "rm ${mergename}.weight"
+  rm $MGDATA/${mergename}.weight
+endif
+
+# mv $MGDATA/${mergename}.weight $MGDATA/${mergename}.w2
+
+echo ">> mg_weights_build -f ${mergename} -b ${weight_bits}"
+$bindir/mg_weights_build -f ${mergename} -b ${weight_bits}
+if ("$status" != "0") exit 1 
+
+echo "---------------------------------------"
+
+echo ">> mg_invf_dict -f ${mergename} -b 4096"
+$bindir/mg_invf_dict -f ${mergename} -b 4096
+
+# [RPAP - Jan 97: Stem Index Change]
+if ($do_indexes) then
+  echo "-----------------------------------"
+
+  echo "mg_stem_idx -f ${mergename} -b 4096 -s1"
+  $bindir/mg_stem_idx -f ${mergename} -b 4096 -s1
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${mergename} -b 4096 -s2"
+  $bindir/mg_stem_idx -f ${mergename} -b 4096 -s2
+  if ("$status" != "0") exit 1 
+
+  echo ""
+
+  echo "mg_stem_idx -f ${mergename} -b 4096 -s3"
+  $bindir/mg_stem_idx -f ${mergename} -b 4096 -s3
+  if ("$status" != "0") exit 1 
+endif
+
+echo "--------------------------------------------------------------"
+
+# move files back to base dir
+# [RPAP - Feb 97: Level 3 Merge]
+# mv the text files if doing text pass
+if ($text_pass) then
+  mv $MGDATA/${oldname}.text         $MGDATA/${bname}.text
+  mv $MGDATA/${mergename}.text.idx   $MGDATA/${bname}.text.idx
+  mv $MGDATA/${newname}.text.dict    $MGDATA/${bname}.text.dict
+endif
+mv $MGDATA/${mergename}.invf       $MGDATA/${bname}.invf
+mv $MGDATA/${mergename}.invf.idx   $MGDATA/${bname}.invf.idx
+mv $MGDATA/${mergename}.invf.dict  $MGDATA/${bname}.invf.dict
+mv $MGDATA/${mergename}.invf.dict.blocked  $MGDATA/${bname}.invf.dict.blocked
+
+# [RPAP - Jan 97: Stem Index Change]
+if ($do_indexes) then
+  mv $MGDATA/${mergename}.invf.dict.blocked.1 $MGDATA/${bname}.invf.dict.blocked.1
+  mv $MGDATA/${mergename}.invf.dict.blocked.2 $MGDATA/${bname}.invf.dict.blocked.2
+  mv $MGDATA/${mergename}.invf.dict.blocked.3 $MGDATA/${bname}.invf.dict.blocked.3
+endif
+
+mv $MGDATA/${mergename}.weight     $MGDATA/${bname}.weight
+mv $MGDATA/${mergename}.weight.approx $MGDATA/${bname}.weight.approx
+mv $MGDATA/${mergename}.text.idx.wgt $MGDATA/${bname}.text.idx.wgt
+
+# EOC: mv .invf.paragraph file if exists
+if (-e $MGDATA/${mergename}.invf.paragraph) then
+  mv $MGDATA/${mergename}.invf.paragraph   $MGDATA/${bname}.invf.paragraph
+endif
+
+# remove old files in the MERGE directory
+rm -f $MGDATA/${merge}/*
+
+echo "mgstat -f ${bname} -E"
+$bindir/mgstat -f ${bname} -E
+if ("$status" != "0") exit 1 
+
+echo "--------------------------------------------------------------"
+echo "`uname -n`, `date`"
+echo "--------------------------------------------------------------"
+
+echo ""
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/xmg.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/xmg.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/xmg.1	(revision 10506)
@@ -0,0 +1,130 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH xmg 1 \*(Dt CITRI
+.SH NAME
+xmg \- An X interface to mgquery
+.SH SYNOPSIS
+.B xmg
+[
+.I collection-name
+]
+.SH DESCRIPTION
+.B xmg
+is an X interface to the
+.BR mg (1)
+information retrieval system.
+.PP
+Type a query in the ``Query'' box.  The escape key clears the query text.
+.PP
+The first line or so of each matching document is listed.
+.PP
+Click on any line to show the complete document.
+.PP
+Shift-click to show the document in a new window.
+.PP
+Press
+.I Next
+and
+.I Previous
+to cycle through the list of documents (shift works here too).
+.PP
+If you change the query, existing windows continue to refer to the
+original query.
+.PP
+You can select either Boolean or ranked queries:
+.RS
+.TP "\w'\fIBoolean queries:\fP'u+2n"
+.I "Boolean queries:"
+use ``&'' for AND, ``|'' for OR, ``!'' for NOT, and parentheses for
+grouping.
+.TP
+.I "Ranked queries:"
+Documents are listed in order of relevance.  A weight is shown
+alongside each.  Weights are normalized to 100 for the most relevant
+document.  Choose
+.I "Approximate Ranking"
+for greater retrieval speed.
+.RE
+.PP
+In document windows (other than the main window):
+.RS
+.br
+Typing `n' = next document;
+.br
+Typing `N' = next document in new window;
+.br
+Typing `p' = previous document;
+.br
+Typing `P' = previous document in new window;
+.br
+Typing `q' = close window.
+.RE
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.TP
+.SB Xdefaults
+To override the default font options, use RESOURCE_MANAGER properties
+like the following in your
+.I .Xdefaults
+file:
+.IP
+.RS
+.nf
+.I "xmg.textfont: fixed"
+.I "xmg.buttonfont: fixed"
+.fi
+.RE
+.IP
+To override the default query type of ranked, use
+.IP
+.RS
+.I "xmg.querytype: boolean"
+.RE
+.IP
+To override the default collection name (the first one listed by
+.BR ls (1)
+from your MGDATA environment variable), use
+.IP
+.RS
+.I "xmg.collection: mail93"
+.RE
+.SH "SEE ALSO"
+.na
+.BR ls (1),
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/xmg.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/xmg.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/scripts/xmg.sh	(revision 10506)
@@ -0,0 +1,1376 @@
+#!/usr/local/bin/wish -f
+# Edit the line above to point to your version of wish
+#
+###############################################################################
+#
+# xmg -- X interface to the mg information retrieval system
+# Copyright (C) 1994  Bruce McKenzie, Ian Witten and Craig Nevill-Manning
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)xmg.sh	1.4 25 Mar 1994
+#
+###############################################################################
+#
+# "xmg" is an X interface to the mg information retrieval system.
+#
+# Type a query in the "Query" box.
+# The first line or so of each matching document is listed.
+# Click on any line to show the complete document.
+# Shift-click to show the document in a new window.
+# Press Next and Previous to cycle through the list of documents (Shift works
+#   here too). 
+# If you change the query, existing windows continue to refer to the original
+#   query. 
+# 
+# You can select either Boolean or Ranked queries.
+# Boolean queries: use "&" for AND, "|" for OR, "!" for NOT, and parentheses
+# for grouping 
+# Ranked queries:  - documents are listed in order of relevance; a weight is
+# 		     shown alongside each 
+#                  - weights are normalized to 100 for the most relevant
+#		     document 
+#                  - choose Approximate Ranking for greater retrieval speed. 
+# 
+# In document windows (other than the main window): 
+#		Typing 'n' = next document
+#		Typing 'N' = next document in new window
+#		Typing 'p' = previous document
+#		Typing 'P' = previous document in new window
+#		Typing 'q' = close window
+#
+###############################################################################
+
+# Date: 13 March 1994
+# Authors: Bruce McKenzie, Ian Witten and Craig Nevill-Manning
+
+###############################################################################
+# Customizing xmg
+###############################################################################
+
+# To override the default font options, use RESOURCE_MANAGER properties like
+# the following in your .Xdefaults file
+#
+#	xmg.textfont: fixed
+#	xmg.buttonfont: fixed
+#
+# To override the default query type of ranked, use
+#
+#	xmg.querytype: boolean
+#
+# To override the default collection name (the first one listed by /bin/ls from
+# your MGDATA environment variable), use
+#
+#	xmg.collection: mail93
+
+###############################################################################
+# Global variables
+###############################################################################
+
+#   genuine constants:
+#
+#	env		the environment variables
+#	Terminator	terminator for mgquery
+#	MaxWindowHeight	the maximum height permitted for a document window
+#	ListBoxLength	the number of items in the document list
+#	HeadLength	the length document head displayed in the list box
+#	ImageString	the string at the start of a document associated
+#			with an image
+#
+#   things that rarely get changed:
+#
+#	querytype	the current query type (boolean, ranked, approx-ranked)
+#	booleanquery	says whether the query is boolean or ranked
+#	approxquery	says whether ranking is to be approximate or not
+#	collection	the name of the document collection being used
+#	fileId		file identifer for a pipe to the mgquery process
+#       errorOccurred	flag to say that there has been an I/O error on the
+#			current collection
+#
+#   things that reflect items in the main panel
+#
+#	query		the current query
+#	hits		number of hits for the current query
+#	display		shell command to display the image associated with
+#			the last document retrieved
+#	scrolledto	document prefixes have been obtained for all documents
+#			up to this position in the document list
+#
+#   static variable needed in just one procedure
+#
+#	top_rank	weight associated with the first document retrieved
+#	windowname	unique id for each document window
+
+###############################################################################
+# High-level procedures
+###############################################################################
+
+proc SaveDocument {w} {
+  set file [FSBox "Save document to file:"]
+
+  if {$file != ""} {
+    if [file exists $file] {
+      toplevel .r
+      wm title .r "\n"
+      .r configure -borderwidth 2 -relief raised 
+      focus .r
+      label .r.message -text "The file already exists"
+      button .r.replace -text "Replace" -width 10 -height 2 \
+          -command "destroy .r; WriteDocument $file \"w\" $w" 
+      button .r.append -text "Append" -width 10 -height 2 \
+          -command "destroy .r; WriteDocument $file \"a\" $w"
+      button .r.cancel -text "Cancel" -command {destroy .r} -width 10 -height 2
+      pack .r.message -side top -pady 10 -padx 20
+      pack .r.replace .r.append .r.cancel -side left -pady 10 -padx 20
+
+    } else {
+       WriteDocument $file "w" $w
+    }
+  }
+}
+
+proc Dialog {text command} {
+      if {![winfo exists .r] } { toplevel .r }
+      wm title .r "\n"
+      .r configure -borderwidth 2 -relief raised 
+      focus .r
+      label .r.message -text $text
+      button .r.ok -text "OK" -width 10 -height 2 \
+          -command "destroy .r $command"
+      pack .r.message -side top -pady 10 -padx 20
+      pack .r.ok -side bottom -pady 10 -padx 20
+}
+
+proc WriteDocument {file mode w} {
+    if {[catch {set f [open $file $mode]}] == 0} {
+        if [winfo exists $w] {
+            puts $f [$w get 0.0 end]
+        } else {
+            Dialog "Unable to save text" ""
+        }
+        flush $f
+        close $f
+    } else {
+        Dialog "Unable to open file for writing" "; SaveDocument $w"
+    }
+}
+
+# Send a query to mg and enter the response in the document list
+#
+proc sendQuery {window} {
+    global query hits querytype errorOccurred scrolledto
+
+    .m.t.q.retrieved.label configure -foreground Gray
+    .m.t.q.retrieved.hits configure -foreground Gray
+
+    sendto ".set query \"$querytype\""
+    sendto ".set mode \"docnums\""
+    foreach f "sdocnums sdocs srank" { $window.$f delete 0 end }
+    disableButton .m.d.buttons.previous
+    disableButton .m.d.buttons.next
+    if {[string index $query 0] == "." || [string length $query] > 255} {
+        set doclist ""
+    } else { set doclist [sendandget $query] }
+
+    if {$errorOccurred} {
+        enterText .m.d.text [mgqueryFailure]
+        .m.t.q.retrieved.label configure -foreground Black
+        .m.t.q.retrieved.hits configure -foreground Black 
+        update
+        return
+    }
+    sendto ".set query \"DocNums\""
+    sendto ".set mode  \"text\""
+    .m.t.q.retrieved.label configure -foreground Black
+    .m.t.q.retrieved.hits configure -foreground Black 
+    set hits [llength $doclist]
+    set i 0
+    global top_rank
+
+    scan [lindex $doclist 0] "%d %f %d" d rank size
+    set top_rank $rank
+    if {$top_rank == 0} {set top_rank 1}
+
+    while {$i < $hits} {
+	scan [lindex $doclist $i] "%d %f %d" d rank size
+        if {$rank == "Inf"} {set rank 1}
+	if {$querytype == "boolean"} {
+	    $window.srank insert end ""
+	} else {
+	    $window.srank insert end \
+		[format "%3.0f" [expr $rank / $top_rank * 99 + 1]]
+	}
+	$window.sdocnums insert end [format " %d" $d]
+	incr i
+    }
+
+    set scrolledto 0
+    scroll $window 0
+    bind $window.sdocs <ButtonRelease-1> \
+	"showDocument $window.sdocs %y .m.d \"$doclist\" \"$query\""
+    bind $window.sdocs <Shift-ButtonRelease-1> \
+	"showDocument $window.sdocs %y New \"$doclist\" \"$query\""
+    enterText .m.d.text ""
+}
+
+# Scrolling routine for the document list
+#
+proc scroll {window n} {
+    global hits scrolledto ListBoxLength Terminator fileId ImageString
+
+    $window.sdocnums yview $n
+    $window.sdocs yview $n
+    $window.srank yview $n
+    set last $n
+    if {$last <= 0} {set last 0}
+    incr last $ListBoxLength
+    if {$last > $hits} {set last $hits}
+
+#    .m config -cursor {watch}
+#    update
+    sendto ".set mode \"heads\""
+    sendto ".set terminator \"\""
+    while {$scrolledto < $last} {
+	if {[scan [$window.sdocnums get $scrolledto] "%d" d] == 1} {
+            sendto $d
+            gets $fileId line
+            set i [string first " " $line]
+            if {$i != -1} {set line [string range $line [expr $i + 1] end]}
+            if {[string compare $ImageString [string range $line 0 9]] == 0} {
+                set line [getImageDocumentHead $d]
+            }
+	    $window.sdocs insert $scrolledto $line
+	}
+	incr scrolledto
+    }
+    sendto ".set terminator \"$Terminator\\n\""
+    sendto ".set mode text"
+#   .m config -cursor {}
+}
+
+proc getImageDocumentHead {d} {
+    global HeadLength ImageString fileId
+
+    sendto ".set heads_length 1000"
+    sendto $d
+    gets $fileId line
+
+    set line [string range $line 11 end]
+
+    set s [string first $ImageString $line]
+    if {$s != -1} {
+        incr s 11
+        set line [string range $line $s [expr $s + $HeadLength]]
+    }
+  
+    sendto ".set heads_length $HeadLength"
+
+    return "* $line"
+}
+
+# Show document from the document list
+#
+proc showDocument {window y newWindow doclist query} {
+    showThisDocument [$window nearest $y] $doclist $newWindow $query
+}
+
+proc adjacentDocument {index doclist window q button} {
+    global ListBoxLength
+
+    showThisDocument $index $doclist $window $q
+
+    if {$window == ".m.d"} {
+      set first [.m.t.q.r.sdocs nearest 0]
+      if {$index < $first || $index >= $first + $ListBoxLength} {
+          scroll .m.t.q.r [expr $index - $ListBoxLength / 2]
+      }
+      .m.t.q.r.sdocs select from $index
+    } 
+}
+
+
+# Show document with this index in the document list
+#
+proc showThisDocument {index doclist window q} {
+    global collection MaxWindowHeight display windowname
+
+    set document ""
+    scan [lindex $doclist $index] "%d %f" document rank
+    if {$document == ""} { return }
+    set textlist [sendandget $document]
+	
+    if {[string length $display] != 0} { exec csh -c $display >& /dev/null & }
+	
+# throw away the first line
+    set text [join [lrange $textlist 1 end] "\n"]
+
+# if necessary, create a new window for this document
+    if {$window == "New"} {
+        .m.t.q.r.sdocs select clear
+	set window .m.document$windowname
+        incr windowname
+        set existing ""
+        set raised 0
+        foreach w [lrange [winfo children .m] 2 end] {
+           if {[lindex [$w.docnum configure -text] 4] == $index && \
+               [lindex [$w.query configure -text] 4] == $q} {
+              if {$raised} {
+                 closeDocumentWindow $w
+              } else {
+                  raise $w
+		  getFocus $w
+                  set window $w
+                  set raised 1
+              }
+           }
+        }
+  
+        if {!$raised} {
+   	    toplevel $window
+            $window configure -borderwidth 2 -relief raised
+            wm protocol $window WM_TAKE_FOCUS "getFocus $window"
+	    getFocus $window
+	    makeDocumentPanel $window
+            bind $window q "$window.buttons.close invoke"
+            label $window.docnum -text $index
+            label $window.query -text $q
+       }
+    }
+
+# configure the window for this document
+    set rows [expr [llength $textlist] - 1]
+    if {$window != ".m.d"} {
+	wm title $window "$collection \"$q\""
+	wm iconname $window "$document"
+	$window.text configure -height $rows
+	if {$rows > $MaxWindowHeight} {
+	    $window.text configure -height $MaxWindowHeight
+	}
+    }
+
+# show the document text in the window
+    enterText $window.text $text
+
+# configure the window's Previous and Next buttons
+    if {$index == 0} {
+        disableButton $window.buttons.previous
+    } else {
+	set newindex [expr $index-1]
+	bindBoth $window previous $newindex $doclist $q
+        bind $window p [bind $window.buttons.previous <1>]
+        bind $window P [bind $window.buttons.previous <Shift-1>]
+    }
+    if {$index == [expr [llength $doclist]-1]} {
+	disableButton $window.buttons.next 
+    } else {
+	set newindex [expr $index+1]
+	bindBoth $window next $newindex $doclist $q
+        bind $window n [bind $window.buttons.next <1>]
+        bind $window N [bind $window.buttons.next <Shift-1>]
+    }
+
+    if {$window != ".m.d"} { $window.docnum configure -text $index }
+
+    if {[string length $display] != 0} { 
+        set on "{
+            if \[winfo exists $window\] \{
+                 $window.buttons.image configure \
+                   -foreground Black
+                 update\}
+        }"
+        set off "{
+            if \[winfo exists $window\] \{
+                 $window.buttons.image configure \
+                   -foreground [lindex [.m.d configure -background] 4]
+                 update\}
+        }"
+        set t 0
+        while {$t < 5} {
+            after [expr $t * 1000] eval $on
+            after [expr $t * 1000 + 500] eval $off
+            incr t
+        }   
+    }
+}
+
+# Bind both Button-1 and Shift-Button-1 commands
+#
+proc bindBoth {window button index doclist query} {
+    $window.buttons.$button configure -state normal
+    bind $window.buttons.$button <Button-1> \
+	"adjacentDocument $index \"$doclist\" $window \"$query\" $button"
+    bind $window.buttons.$button <Shift-Button-1> \
+	"adjacentDocument $index \"$doclist\" New \"$query\" $button"
+}
+
+# Change the type of query
+#
+proc changeQuerytype {name element op} {
+    global querytype booleanquery approxquery
+
+    if {$booleanquery} {
+	.m.t.b.type.approx configure -state disabled
+	.m.t.q.retrieved.weight configure \
+             -foreground [lindex [.m configure -background] 4]
+	set querytype boolean
+    } else {
+	.m.t.b.type.approx configure -state normal
+	.m.t.q.retrieved.weight configure -foreground Black
+	if {$approxquery} {
+	    set querytype "approx-ranked"
+	} else {
+	    set querytype "ranked"
+	}
+    }
+}
+
+proc enterText {window text} {
+    $window configure -state normal
+    $window delete 0.0 end
+    $window insert 0.0 $text
+    $window configure -state disabled
+}
+
+###############################################################################
+# IO and initialization
+###############################################################################
+
+# Send a message to mg and return the reply
+#
+proc sendandget {message} {
+    global fileId Terminator display errorOccurred ImageString
+    set display ""
+
+    .m config -cursor {watch}
+    update idletasks
+    set reply ""
+    sendto "$message\n"
+    if {$message != "" && !$errorOccurred} {
+        gets $fileId line
+    	while {[string compare $Terminator $line] != 0} {
+            lappend reply $line;
+            gets $fileId line
+        }
+
+        if {[string compare $ImageString [lindex $reply 1]] == 0 } {
+          if {[string compare "MGDATA" [string range [lindex $reply 3] 0 5]] == 0} {
+             set display [string range [lindex $reply 3] 7 end];
+          }
+          set reply [lrange $reply 4 end]
+        }
+    }
+
+    .m config -cursor {}
+    return $reply
+}
+    
+# Send a message to mg
+#
+proc sendto {message} {
+    global fileId errorOccurred
+
+    puts $fileId $message
+    set errorOccurred [catch {flush $fileId}]
+}
+
+# Reinitialise mgquery to work with a new document collection
+#
+proc reInitMG {c} {
+    global fileId
+    catch {close $fileId}
+    initMG $c
+}
+
+# Initialize mgquery to work with a specified text collection
+#
+proc initMG {c} {
+    global query hits fileId collection Terminator env errorOccurred
+    global HeadLength
+
+    set collection $c
+    set query ""
+    set hits 0
+    set errorOccurred 0
+
+    foreach f "sdocs srank" { .m.t.q.r.$f delete 0 end }
+    enterText .m.d.text ""
+    .m.t.b.collect.m configure -text $collection
+    foreach w [winfo children .m] {
+	if {[string first ".m.document" $w] == 0} { closeDocumentWindow $w }
+    }
+
+    disableButton .m.d.buttons.previous 
+    disableButton .m.d.buttons.next
+
+    if {$c != ""} {
+        set f $env(MGDATA)/$c
+
+        if {[file exists $f] && [file readable $f]} {
+    	    set fileId [open "| mgquery $collection" RDWR]
+	    sendto ".set expert \"true\""
+	    sendto ".set terminator \"$Terminator\\n\""
+	    sendto ".set pager \"cat\""
+            sendto ".set heads_length $HeadLength"
+	    return
+        }
+    }
+    bind .m.t.q.e.entry <Return> {null}
+    enterText .m.d.text [initializationFailure]
+    update
+}
+
+# Routine to obtain values from RESOURCE_MANAGER
+#
+proc query_resource {option class default} {
+	set val [option get . $option $class]
+	if {[string length $val] == 0} { return $default }
+	return $val
+}
+
+
+proc disableButton {b} {
+    bind $b <Button-1> {null}
+    bind $b <Shift-Button-1> {null}
+    $b configure -state disabled
+}
+
+proc null {} {}
+
+###############################################################################
+# Setting up windows
+###############################################################################
+
+proc removeFromWindowList {window} {
+    global stacking
+
+    set i 0
+    while {$i < [llength $stacking]} {
+      if {$window == [lindex $stacking $i]} {
+         set stacking [lreplace $stacking $i $i]
+      }
+      incr i
+    }
+}
+
+proc getFocus {window} {
+    global stacking
+
+    focus $window
+    removeFromWindowList $window
+    set stacking [linsert $stacking 0 $window]
+}
+
+proc closeDocumentWindow {w} {
+   global stacking
+   removeFromWindowList $w
+   set t [lindex $stacking 0]
+
+   if {$t != ""} {
+     focus $t
+     raise $t
+  }
+  destroy $w
+}
+
+# Make a "document" panel, including Previous, Next, and Close buttons
+#
+proc makeDocumentPanel {window} {
+    frame $window.buttons
+    button $window.buttons.previous -text "Previous" -width 10 -state disabled
+    button $window.buttons.next -text "Next" -width 10 -state disabled
+    button $window.buttons.close -text "Close" -width 10 \
+	-command "closeDocumentWindow $window"
+    button $window.buttons.save -text "Save" -width 10 \
+        -command "SaveDocument $window.text"
+
+    label $window.buttons.image -text "Fetching image..." \
+            -foreground [lindex [$window configure -background] 4]
+    pack $window.buttons.previous $window.buttons.next -side left
+    pack $window.buttons.image -side left -padx 10
+    pack $window.buttons.close $window.buttons.save -side right 
+    pack $window.buttons -side top -fill x 
+
+    text $window.text -borderwidth 2 -relief raised \
+             -setgrid true -width 80 -state disabled
+
+    $window.text configure -yscrollcommand "$window.sy set" 
+    scrollbar $window.sy -relief flat -command "$window.text yview"
+    pack $window.sy -side right -fill y 
+    pack $window.text -side top -expand yes -fill both
+}
+
+# Make the "buttons" panel, with the query type and collection name
+#
+proc mkButtons {window} {
+    global collection booleanquery approxquery env
+    frame $window.type
+    label $window.type.label -text "Query type"
+
+    radiobutton $window.type.boolean -text "Boolean" -variable booleanquery \
+	  -value 1 -relief flat
+
+    radiobutton $window.type.ranked -text "Ranked" -variable booleanquery \
+	  -value 0 -relief flat
+
+    checkbutton $window.type.approx -text "Approximate" -variable approxquery \
+	  -relief flat
+
+    trace variable booleanquery w changeQuerytype
+    trace variable approxquery w changeQuerytype
+
+    pack $window.type.label   -side top -anchor w
+    pack $window.type.boolean -side top -anchor w -padx 12
+    pack $window.type.ranked  -side top -anchor w -padx 12
+    pack $window.type.approx  -side top -anchor w -padx 36
+
+    pack $window.type -side top -anchor w -pady 12
+
+    frame $window.collect
+    label $window.collect.label -text "Collection: "
+    pack $window.collect.label -side left -anchor w
+
+    getViewer
+
+    set dirs [getMGDATA]
+    set collection ""
+    if {$dirs != ""} { set collection [lindex $dirs 0] }
+   
+    menubutton $window.collect.m -menu $window.collect.m.menu \
+	-relief sunken
+    menu $window.collect.m.menu
+    foreach c $dirs {
+        if {[file readable $env(MGDATA)/$c] && 
+            [file isdirectory $env(MGDATA)/$c]} {
+    	    $window.collect.m.menu add command -label $c \
+	        -command "reInitMG $c"
+        }
+    }
+    pack $window.collect.m -side left
+    pack $window.collect -side bottom -anchor w
+
+
+}
+
+# Check that the MGDATA environment variable is set, and is non-null
+#
+proc getMGDATA {} {
+    global env
+
+    set MGDATA 0
+    foreach i [array names env] {
+	if {$i == "MGDATA"} {
+	    set dirs [exec /bin/ls $env(MGDATA)]
+	    if {[info exists dirs]} { return $dirs }
+	}
+    }
+
+    return ""
+}
+
+proc getViewer {} {
+    global env
+
+    set viewer 0
+    foreach i [array names env] {
+	if {$i == "MGIMAGEVIEWER"} {set viewer $env(MGIMAGEVIEWER)}
+    }
+
+    if {$viewer == 0} {set env(MGIMAGEVIEWER) "xloadimage -quiet -fit stdin"}
+}
+
+# Make the "query" panel, with the query and list of retrieved documents
+#
+proc mkQuery {window} {
+    global hits ListBoxLength
+
+# at the top of the "query" panel is the "entry" frame
+    frame $window.e
+    label $window.e.label -text "Query"
+    entry $window.e.entry -relief sunk -width 47 -textvariable query
+    pack $window.e.label -side left
+    pack $window.e.entry -side right -expand yes -fill x
+    focus default $window.e.entry
+    focus $window.e.entry
+
+    bind $window.e.entry <Control-Key> {null}
+    bind $window.e.entry <Return> "sendQuery $window.r"
+    bind $window.e.entry <Escape> { set query "" }
+    bind $window.e.entry <2> {
+	%W insert insert [selection get STRING]
+	tk_entrySeeCaret %W
+    }
+
+# next is the "retrieved" frame
+    frame $window.retrieved
+    label $window.retrieved.weight -text "Weight"
+    label $window.retrieved.label -text "   Documents retrieved: "
+    label $window.retrieved.hits -width 4 -relief sunk -textvariable hits
+    set documentsRetrieved 0
+    pack $window.retrieved.weight $window.retrieved.label \
+        $window.retrieved.hits -side left
+
+# next is the "results" frame (note that the docnums listbox doesn't appear on
+# the screen)
+    frame $window.r
+    scrollbar $window.r.sscroll -relief sunken -command "scroll $window.r"
+#    bind $window.r.sscroll <ButtonRelease-1> "updateSdocs $window.r.sdocs $window.r.sdocnums"
+    listbox $window.r.sdocnums
+    listbox $window.r.sdocs -relief sunken \
+            -setgrid 1 -geometry 50x$ListBoxLength
+    listbox $window.r.srank -yscroll "$window.r.sscroll set" \
+            -setgrid 1 -geometry 4x$ListBoxLength
+  
+    bind $window.r.srank <Any-1> {null}
+    bind $window.r.srank <Any-2> {null}
+    bind $window.r.srank <Any-3> {null}
+
+    bind $window.r.srank <Any-B1-Motion> {null}
+    bind $window.r.srank <Any-B2-Motion> {null}
+    bind $window.r.srank <Any-B3-Motion> {null}
+
+    bind $window.r.sdocs <Any-2> {null}
+    bind $window.r.sdocs <Any-B2-Motion> {null}
+
+    pack $window.r.sscroll -side right -fill y
+    pack $window.r.srank -side left 
+    pack $window.r.sdocs -side left -fill x -expand yes
+
+# pack them up
+    pack $window.e -side top -anchor e -pady 10 -fill x -expand yes
+    pack $window.retrieved -anchor w
+    pack $window.r -side bottom -anchor e -pady 10 -fill x -expand yes
+}
+
+# Make a "help" window
+#
+proc mkHelp {} {
+    if [winfo exists .help] { destroy .help }
+    toplevel .help
+    wm title .help "X interface to the mg information retrieval system"
+    wm iconname .help "About xmg"
+    frame .help.buttons
+    button .help.buttons.close -text Close -command "destroy .help" -width 10
+    button .help.buttons.help -text Help -width 10
+    button .help.buttons.conditions -text Conditions -width 10
+    button .help.buttons.warranty -text Warranty -width 10
+    button .help.buttons.bugs -text Bugs -width 10
+
+    frame .help.t
+    text .help.t.text -relief raised -bd 2 -setgrid true -height 24 -width 95
+    .help.t.text configure -yscrollcommand ".help.t.sy set" 
+    scrollbar .help.t.sy -relief flat -command ".help.t.text yview"
+    
+    pack .help.buttons.close .help.buttons.help -side right -fill x
+    pack .help.buttons.conditions .help.buttons.warranty \
+         .help.buttons.bugs -side left
+    pack .help.buttons -side bottom -fill x
+
+    pack .help.t.text -side left -expand yes -fill both
+    pack .help.t.sy -side right -fill y 
+    pack .help.t -side top -fill both -expand yes
+    enterText .help.t.text [HelpText]
+    grayButton help
+}
+
+proc grayButton {button} {
+    bind .help.buttons.help <1> "enterText .help.t.text \[HelpText\]
+         grayButton help" 
+    .help.buttons.help configure -state normal
+
+    bind .help.buttons.bugs <1> "enterText .help.t.text \[Bugs\]
+         grayButton bugs" 
+    .help.buttons.bugs configure -state normal
+
+    bind .help.buttons.warranty <1> "enterText .help.t.text \[Warranty\]
+         grayButton warranty"
+    .help.buttons.warranty configure -state normal
+
+    bind .help.buttons.conditions <1> "enterText .help.t.text \[Conditions\]
+         grayButton conditions" 
+    .help.buttons.conditions configure -state normal
+    disableButton .help.buttons.$button
+}
+
+# The text for errors in the MG environment variable
+#
+
+
+proc bookDetails {} {
+  return { \
+
+ This X interface was written by Bruce McKenzie, Ian Witten and Craig Nevill-Manning.  
+ For information on mg, see
+             Witten, I.H.,  Moffat, A. and Bell, T.C. (1994) "Managing gigabytes: compressing
+             and indexing documents and images." Van Nostrand Reinhold, New York.
+             ISBN 0-442-01863-0, US $54.95; call 1 (800) 544-0550 to order.
+}
+}
+
+proc initializationFailure {} {
+    return [format "%s\n%s" {\
+In order to run XMG you need to have already created and indexed some document collections,
+ and placed them in a directory whose name is given by the environment variable MGDATA.
+ Your MGDATA variable is unset or does not specify a directory with files in; therefore XMG
+ cannot proceed.
+} [bookDetails]]
+}
+
+proc mgqueryFailure {} {
+    return [format "%s\n%s" {\
+In order to run XMG you need to have already created and indexed some document collections,
+ and placed them in a directory whose name is given by the environment variable MGDATA.
+ There is a problem with the collection that you have chosen. Please re-index the collection before
+ you use it again.
+} [bookDetails]]
+
+}
+
+# The text for the help message
+#
+proc HelpText {} {
+    return [format "%s\n%s" {\
+This is an X interface to the mg information retrieval system.
+
+ Type a query in the "Query" box.
+ The first line or so of each matching document is listed. 
+ Click on any line to show the complete document.
+ Shift-click to show the document in its own window
+ Press Next and Previous to cycle through the list of documents (Shift works here too).
+ In document windows (other than the main window), typing n or p shows the next and previous 
+ documents; N or P creates a new window for them. q closes the most recently created window.
+ If you change the query, existing windows continue to refer to the original query.
+ 
+ You can select either Boolean or Ranked queries.
+ Boolean queries: use & for AND, | for OR, ! for NOT, and parentheses for grouping
+ Ranked queries:  documents are listed in order of relevance; a weight is shown alongside each
+                                  weights are normalized to 100 for the most relevant document
+                                  choose Approximate Ranking for greater retrieval speed. 
+ } [bookDetails]]
+}
+
+proc reformat {text} {
+    regsub -all "\n *\n *" $text "BLEQUEWFI" text
+    regsub -all "\[ \t\n\r\]+" $text " " text
+    regsub -all "BLEQUEWFI" $text "\n\n" text
+    return $text
+}
+
+proc Conditions {} {
+    return [reformat [join [sendandget ".conditions\nTHISWILLNEVERMATCHANYTHING\n"] "\n"]]
+}
+
+proc Warranty {} {
+    return [reformat [join [sendandget ".warranty\nTHISWILLNEVERMATCHANYTHING\n"] "\n"]]
+}
+
+proc Bugs {} {
+    return [reformat {
+Known shortcomings of xmg include:
+
+    Slow picture viewing.  Pictures are decompressed in their entirety before a window is created 
+        for the picture.  This often results in a long delay with no feedback. Moreover, when 
+        an image's document is displayed repeatedly, multiple identical images are shown.
+
+    Sequential viewing.  There is no way of going to the next document in the collection to see the
+        context of documents that have been retrieved.  This would be trivial to implement but
+        conflicts with the interpretation of the "previous" and "next" buttons.
+    }]
+}
+
+###############################################################################
+# The main program
+###############################################################################
+
+scan [info tclversion] "%d.%d" major minor
+
+if {$major < 7} {
+    puts "xmg requires version 7.0 of the tcl interpreter. You are using version $major.$minor"
+    exit
+}
+
+# Default font settings
+set defaulttextfont   -adobe-times-medium-r-normal--14-140-75-75-p-74-iso8859-1
+set defaultbuttonfont -adobe-times-bold-r-normal--14-140-75-75-p-77-iso8859-1
+set textfont   [query_resource textfont Textfont $defaulttextfont]
+set buttonfont [query_resource buttonfont Buttonfont $defaultbuttonfont]
+
+set MaxWindowHeight 10
+set HeadLength 100
+set scrolledto 0
+set ListBoxLength 12
+set windowname 0
+set Terminator "RECORD_END"
+set fileId ""
+set query ""
+set ImageString "::::::::::"
+set stacking ".m.t"
+
+tk_listboxSingleSelect Listbox
+option add *Text.wrap word
+
+option add *Text.font $textfont
+option add *Listbox.font $textfont
+option add *Entry.font $textfont
+
+option add *Button.font $buttonfont
+option add *Menubutton.font $buttonfont
+option add *Radiobutton.font $buttonfont
+option add *Checkbutton.font $buttonfont
+option add *Label.font $buttonfont
+option add *Menu.font $buttonfont
+
+wm title . "Managing Gigabytes"
+wm iconname . "xmg"
+frame .m -borderwidth 5 -relief raised
+
+# top part of frame
+frame .m.t
+
+# on the left side of the top part is the "buttons" panel
+frame .m.t.b
+mkButtons .m.t.b
+
+# on the right side is the "query" panel
+frame .m.t.q
+mkQuery .m.t.q
+
+set q [query_resource querytype Querytype approx-ranked]
+set booleanquery [expr \"$q\" == \"boolean\"]
+set approxquery [expr \"$q\" == \"approx-ranked\"]
+# the above lines will trigger changeQuerytype
+
+pack .m.t.b -side left -anchor nw
+pack .m.t.q -side right -anchor ne -fill both -expand yes
+
+# at the bottom is the "document" panel
+frame .m.d
+makeDocumentPanel .m.d
+
+.m.d.buttons.close configure -text "Exit" \
+    -command "destroy ."
+button .m.d.buttons.help -text "Help" -width 10 \
+	-command "mkHelp"
+
+pack .m.d.buttons.help -side right
+pack .m.t -side top -fill x -expand yes
+pack .m.d -side bottom -fill both -expand yes
+
+pack .m -fill both -expand yes
+wm geometry . +300+85
+
+set collection [query_resource collection Collection $collection]
+if {$argc>0} { set collection $argv }
+
+enterText .m.d.text [HelpText]
+
+initMG $collection
+
+###############################################################################
+###############################################################################
+# The following file selection box procedure was written by Andrew Donkin
+# of the University of Waikato. 
+###############################################################################
+
+proc FSBox { {fsBoxMessage "Select file:"}} {
+# xf ignore me 5
+  global fsBox
+
+  set fsBox(name) ""
+  set fsBox(internalPath) [pwd]
+  set fsBox(pattern) "*"
+  set fsBox(all) 0
+
+  # build widget structure
+
+  # start build of toplevel
+  if {"[info commands XFDestroy]" != ""} {
+    catch {XFDestroy .fsBox}
+  } {
+    catch {destroy .fsBox}
+  }
+  toplevel .fsBox -borderwidth 0
+  wm geometry .fsBox 350x300 
+  wm title .fsBox {File select box}
+  wm maxsize .fsBox 1000 1000
+  wm minsize .fsBox 100 100
+  # end build of toplevel
+
+  label .fsBox.message1 -anchor c -text "$fsBoxMessage"
+  frame .fsBox.frame1  -borderwidth 0  -relief raised
+
+  button .fsBox.frame1.ok  -text "OK"  -command "
+      global fsBox
+      set fsBox(name) \[.fsBox.file.file get\]
+      set fsBox(path) \[.fsBox.path.path get\]
+
+      set fsBox(internalPath) \[.fsBox.path.path get\]
+
+      if {\"\[info commands XFDestroy\]\" != \"\"} {
+        catch {XFDestroy .fsBox}
+      } {
+        catch {destroy .fsBox}
+      }"
+
+  button .fsBox.frame1.rescan -text "Rescan" -command {
+      global fsBox
+      FSBoxFSShow [.fsBox.path.path get] [.fsBox.pattern.pattern get] $fsBox(all)
+  }
+
+  button .fsBox.frame1.cancel -text "Cancel" -command "
+      global fsBox
+      set fsBox(name) {}
+      set fsBox(path) {}
+
+      if {\"\[info commands XFDestroy\]\" != \"\"} {
+        catch {XFDestroy .fsBox}
+      } {
+        catch {destroy .fsBox}
+      }"
+
+  frame .fsBox.path -borderwidth 0 -relief raised
+  frame .fsBox.path.paths 
+  label .fsBox.path.paths.paths -borderwidth 0 -text "Pathname:"
+
+  entry .fsBox.path.path -relief sunken
+  .fsBox.path.path insert 0 $fsBox(internalPath)
+  frame .fsBox.pattern -borderwidth 0 -relief raised
+  frame .fsBox.pattern.patterns 
+
+  label .fsBox.pattern.patterns.patterns -borderwidth 0 -text "Selection pattern:"
+  entry .fsBox.pattern.pattern -relief sunken
+  .fsBox.pattern.pattern insert 0 $fsBox(pattern)
+  
+  frame .fsBox.files -borderwidth 0 -relief raised
+  scrollbar .fsBox.files.vscroll -relief raised -command ".fsBox.files.files yview"
+  scrollbar .fsBox.files.hscroll -orient horiz -relief raised -command ".fsBox.files.files xview" 
+  listbox .fsBox.files.files -exportselection false -relief raised -xscrollcommand \
+        ".fsBox.files.hscroll set" -yscrollcommand ".fsBox.files.vscroll set"
+  frame .fsBox.file -borderwidth 0 -relief raised
+  label .fsBox.file.labelfile -text "Filename:"
+  entry .fsBox.file.file -relief sunken
+  focus .fsBox.file.file
+
+  .fsBox.file.file delete 0 end
+  .fsBox.file.file insert 0 $fsBox(name)
+  
+  checkbutton .fsBox.pattern.all -offvalue 0 -onvalue 1 -text "Show all files" -variable fsBox(all) -command {
+      global fsBox
+      FSBoxFSShow [.fsBox.path.path get] [.fsBox.pattern.pattern get] $fsBox(all)
+    }
+
+  FSBoxFSShow $fsBox(internalPath) $fsBox(pattern) $fsBox(all)
+
+  # bindings
+  bind .fsBox.files.files <Double-Button-1> "FSBoxFSFileSelectDouble %W %y"
+  bind .fsBox.files.files <ButtonPress-1> "FSBoxFSFileSelect %W %y"
+  bind .fsBox.files.files <Button1-Motion> "FSBoxFSFileSelect %W %y"
+  bind .fsBox.files.files <Shift-Button1-Motion> "FSBoxFSFileSelect %W %y"
+  bind .fsBox.files.files <Shift-ButtonPress-1> "FSBoxFSFileSelect %W %y"
+
+  bind .fsBox.path.path <Return> {
+    global fsBox
+    FSBoxFSShow [.fsBox.path.path get] [.fsBox.pattern.pattern get] $fsBox(all)
+    .fsBox.file.file icursor end
+    focus .fsBox.file.file}
+  catch "bind .fsBox.path.path <Up> {}"
+  bind .fsBox.path.path <Down> {
+    .fsBox.file.file icursor end
+    focus .fsBox.file.file}
+
+  bind .fsBox.file.file <Return> "
+    global fsBox
+    set fsBox(name) \[.fsBox.file.file get\]
+    set fsBox(path) \[.fsBox.path.path get\]
+    set fsBox(internalPath) \[.fsBox.path.path get\]
+
+    if {\"\[info commands XFDestroy\]\" != \"\"} {
+      catch {XFDestroy .fsBox}
+    } {
+      catch {destroy .fsBox}
+    }"
+  bind .fsBox.file.file <Up> {.fsBox.path.path icursor end
+    focus .fsBox.path.path}
+  bind .fsBox.file.file <Down> {.fsBox.pattern.pattern icursor end
+    focus .fsBox.pattern.pattern}
+
+  bind .fsBox.pattern.pattern <Return> {
+    global fsBox
+    FSBoxFSShow [.fsBox.path.path get] [.fsBox.pattern.pattern get] $fsBox(all)}
+  bind .fsBox.pattern.pattern <Up> {
+    .fsBox.file.file icursor end
+    focus .fsBox.file.file}
+  catch "bind .fsBox.pattern.pattern <Down> {}"
+
+  # packing
+  pack .fsBox.files.vscroll -side left -fill y 
+  pack .fsBox.files.hscroll -side bottom -fill x
+  pack .fsBox.files.files -side left -fill both -expand yes
+
+  pack .fsBox.file.labelfile -side left
+  pack .fsBox.file.file -side left -fill  both -expand yes
+
+  pack .fsBox.frame1.ok -side left -fill both -expand yes
+  pack .fsBox.frame1.rescan -side left -fill both -expand yes
+  pack .fsBox.frame1.cancel -side left -fill both -expand yes
+
+  pack .fsBox.path.paths.paths -side left
+
+  pack .fsBox.pattern.patterns.patterns -side left
+
+  pack .fsBox.path.paths -side left
+  pack .fsBox.path.path -side left -fill both -expand yes
+
+  pack .fsBox.pattern.patterns -side left
+  pack .fsBox.pattern.all -side right -fill both
+  pack .fsBox.pattern.pattern -side left -fill both -expand yes
+
+  pack .fsBox.message1 -side top -fill both
+  pack .fsBox.frame1 -side bottom -fill both
+  pack .fsBox.pattern -side bottom -fill both
+  pack .fsBox.file -side bottom -fill both
+  pack .fsBox.path -side bottom -fill both
+  pack .fsBox.files -side left -fill both -expand yes
+
+  update idletask
+  grab .fsBox
+  tkwait window .fsBox
+
+  if {"[string trim $fsBox(path)]" != "" ||
+      "[string trim $fsBox(name)]" != ""} {
+    if {"[string trimleft [string trim $fsBox(name)] /]" == ""} {
+      return [string trimright [string trim $fsBox(path)] /]
+    } {
+      return [string trimright [string trim $fsBox(path)] /]/[string trimleft [string trim $fsBox(name)] /]
+    }
+  }
+}
+
+proc FSBoxBindSelectOne { fsBoxW fsBoxY} {
+# xf ignore me 6
+
+  set fsBoxNearest [$fsBoxW nearest $fsBoxY]
+  if {$fsBoxNearest >= 0} {
+    $fsBoxW select from $fsBoxNearest
+    $fsBoxW select to $fsBoxNearest
+  }
+}
+
+proc FSBoxFSFileSelect { fsBoxW fsBoxY} {
+# xf ignore me 6
+  global fsBox
+
+  FSBoxBindSelectOne $fsBoxW $fsBoxY
+  set fsBoxNearest [$fsBoxW nearest $fsBoxY]
+  if {$fsBoxNearest >= 0} {
+    set fsBoxTmpEntry [$fsBoxW get $fsBoxNearest]
+    if {"[string index $fsBoxTmpEntry           [expr [string length $fsBoxTmpEntry]-1]]" == "/" ||
+        "[string index $fsBoxTmpEntry           [expr [string length $fsBoxTmpEntry]-1]]" == "@"} {
+      set fsBoxFileName [string range $fsBoxTmpEntry 0             [expr [string length $fsBoxTmpEntry]-2]]
+      if {![IsADir [string trimright $fsBox(internalPath)/$fsBoxFileName @]] &&
+          ![IsASymlink [string trimright $fsBox(internalPath)/$fsBoxFileName @]]} {
+        set fsBoxFileName $fsBoxTmpEntry
+      }
+    } {
+      if {"[string index $fsBoxTmpEntry             [expr [string length $fsBoxTmpEntry]-1]]" == "*"} {
+        set fsBoxFileName [string range $fsBoxTmpEntry 0           [expr [string length $fsBoxTmpEntry]-2]]
+        if {![file executable $fsBox(internalPath)/$fsBoxFileName]} {
+          set fsBoxFileName $fsBoxTmpEntry
+        }
+      } {
+        set fsBoxFileName $fsBoxTmpEntry
+      }
+    }
+    if {![IsADir [string trimright $fsBox(internalPath)/$fsBoxFileName @]]} {
+      set fsBox(name) $fsBoxFileName
+      .fsBox.file.file delete 0 end
+      .fsBox.file.file insert 0 $fsBox(name)
+    }
+  }
+}
+
+proc FSBoxFSFileSelectDouble { fsBoxW fsBoxY} {
+# xf ignore me 6
+  global fsBox
+
+  FSBoxBindSelectOne $fsBoxW $fsBoxY
+  set fsBoxNearest [$fsBoxW nearest $fsBoxY]
+  if {$fsBoxNearest >= 0} {
+    set fsBoxTmpEntry [$fsBoxW get $fsBoxNearest]
+    if {"$fsBoxTmpEntry" == "../"} {
+      set fsBoxTmpEntry [string trimright [string trim $fsBox(internalPath)] "@/"]
+      if {"$fsBoxTmpEntry" == ""} {
+        return
+      }
+      FSBoxFSShow [file dirname $fsBoxTmpEntry]         [.fsBox.pattern.pattern get] $fsBox(all)
+      .fsBox.path.path delete 0 end
+      .fsBox.path.path insert 0 $fsBox(internalPath)
+    } {
+      if {"[string index $fsBoxTmpEntry [expr [string length $fsBoxTmpEntry]-1]]" == "/" ||
+          "[string index $fsBoxTmpEntry [expr [string length $fsBoxTmpEntry]-1]]" == "@"} {
+        set fsBoxFileName [string range $fsBoxTmpEntry 0               [expr [string length $fsBoxTmpEntry]-2]]
+        if {![IsADir [string trimright $fsBox(internalPath)/$fsBoxFileName @]] &&
+            ![IsASymlink [string trimright $fsBox(internalPath)/$fsBoxFileName @]]} {
+          set fsBoxFileName $fsBoxTmpEntry
+        }
+      } {
+        if {"[string index $fsBoxTmpEntry [expr [string length $fsBoxTmpEntry]-1]]" == "*"} {
+          set fsBoxFileName [string range $fsBoxTmpEntry 0                 [expr [string length $fsBoxTmpEntry]-2]]
+          if {![file executable $fsBox(internalPath)/$fsBoxFileName]} {
+            set fsBoxFileName $fsBoxTmpEntry
+          }
+        } {
+          set fsBoxFileName $fsBoxTmpEntry
+        }
+      }
+      if {[IsADir [string trimright $fsBox(internalPath)/$fsBoxFileName @]]} {
+        set fsBox(internalPath) "[string trimright $fsBox(internalPath) {/@}]/$fsBoxFileName"
+        FSBoxFSShow $fsBox(internalPath) [.fsBox.pattern.pattern get] $fsBox(all)
+        .fsBox.path.path delete 0 end
+        .fsBox.path.path insert 0 $fsBox(internalPath)
+      } {
+        set fsBox(name) $fsBoxFileName
+        set fsBox(path) $fsBox(internalPath)
+        if {"[info commands XFDestroy]" != ""} {
+          catch {XFDestroy .fsBox}
+        } {
+          catch {destroy .fsBox}
+        }
+      }
+    }
+  }
+}
+
+proc FSBoxFSShow { fsBoxPath fsBoxPattern fsBoxAll} {
+# xf ignore me 6
+  global fsBox
+
+  set fsBox(pattern) $fsBoxPattern
+
+  if {[file exists $fsBoxPath] && [file readable $fsBoxPath] &&
+      [IsADir $fsBoxPath]} {
+    set fsBox(internalPath) $fsBoxPath
+  } {
+    if {[file exists $fsBoxPath] && [file readable $fsBoxPath] &&
+        [IsAFile $fsBoxPath]} {
+      set fsBox(internalPath) [file dirname $fsBoxPath]
+      .fsBox.file.file delete 0 end
+      .fsBox.file.file insert 0 [file tail $fsBoxPath]
+      set fsBoxPath $fsBox(internalPath)
+    } {
+      while {"$fsBoxPath" != "" && "$fsBoxPath" != "/" &&
+             ![file isdirectory $fsBoxPath]} {
+        set fsBox(internalPath) [file dirname $fsBoxPath]
+         set fsBoxPath $fsBox(internalPath)
+      }
+    }
+  }
+  if {"$fsBoxPath" == ""} {
+    set fsBoxPath "/"
+    set fsBox(internalPath) "/"
+  }
+  .fsBox.path.path delete 0 end
+  .fsBox.path.path insert 0 $fsBox(internalPath)
+
+  if {[.fsBox.files.files size] > 0} {
+    .fsBox.files.files delete 0 end
+  }
+  if {$fsBoxAll} {
+    if {[catch "exec ls -F -a $fsBoxPath" fsBoxResult]} {
+      puts stderr "$fsBoxResult"
+    }
+  } {
+    if {[catch "exec ls -F $fsBoxPath" fsBoxResult]} {
+      puts stderr "$fsBoxResult"
+    }
+  }
+  set fsBoxElementList [lsort $fsBoxResult]
+
+  foreach fsBoxCounter [winfo children .fsBox.pattern.patterns.patterns] {
+    if {[string length [info commands XFDestroy]] > 0} {
+      catch {XFDestroy $fsBoxCounter}
+    } {
+      catch {destroy $fsBoxCounter}
+    }
+  }
+  menu .fsBox.pattern.patterns.patterns.menu
+
+  if {"$fsBoxPath" != "/"} {
+    .fsBox.files.files insert end "../"
+  }
+  foreach fsBoxCounter $fsBoxElementList {
+    if {[string match $fsBoxPattern $fsBoxCounter] ||
+        [IsADir [string trimright $fsBoxPath/$fsBoxCounter "/@"]]} {
+      if {"$fsBoxCounter" != "../" &&
+          "$fsBoxCounter" != "./"} {
+        .fsBox.files.files insert end $fsBoxCounter
+      }
+    }
+  }
+}
+
+proc IsADir { pathName} {
+# xf ignore me 5
+  if {[file isdirectory $pathName]} {
+    return 1
+  } {
+    catch "file type $pathName" fileType
+    if {"$fileType" == "link"} {
+      if {[catch "file readlink $pathName" linkName]} {
+        return 0
+      }
+      catch "file type $linkName" fileType
+      while {"$fileType" == "link"} {
+        if {[catch "file readlink $linkName" linkName]} {
+          return 0
+        }
+        catch "file type $linkName" fileType
+      }
+      return [file isdirectory $linkName]
+    }
+  }
+  return 0
+}
+
+proc IsAFile { fileName} {
+# xf ignore me 5
+  if {[file isfile $fileName]} {
+    return 1
+  } {
+    catch "file type $fileName" fileType
+    if {"$fileType" == "link"} {
+      if {[catch "file readlink $fileName" linkName]} {
+        return 0
+      }
+      catch "file type $linkName" fileType
+      while {"$fileType" == "link"} {
+        if {[catch "file readlink $linkName" linkName]} {
+          return 0
+        }
+        catch "file type $linkName" fileType
+      }
+      return [file isfile $linkName]
+    }
+  }
+  return 0
+}
+
+proc IsASymlink { fileName} {
+# xf ignore me 5
+  catch "file type $fileName" fileType
+  if {"$fileType" == "link"} {
+    return 1
+  }
+  return 0
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/GCC.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/GCC.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/GCC.mak	(revision 10506)
@@ -0,0 +1,205 @@
+###########################################################################
+#
+# gcc win32 makefile -- mg\src\text
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+AR = ar
+RANLIB = ranlib
+CC = gcc
+DELETE = del
+INSTALL = copy
+
+o = .o
+e = .exe
+/ = \\
+
+CPPFLAGS = -g
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DHAVE_CONFIG_H \
+       -D_LITTLE_ENDIAN
+LIBS = ..$/..$/lib$/libmg.a
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c $o
+.c$o:
+	$(COMPILE) $<
+ 
+INCLUDES = -I"..$/.." -I"..$/..$/lib"
+
+
+SOURCES = \
+  backend.c               locallib.c              mg_weights_build.c   \
+  bool_optimiser.c        mg.special.c            mgdictlist.c         \
+  bool_parser.c           mg_compression_dict.c   mgquery.c            \
+  bool_query.c            mg_errors.c             mgstat.c             \
+  bool_tester.c           mg_fast_comp_dict.c     mg_decompress_text.c \
+  bool_tree.c             mg_files.c              query.docnums.c      \
+  commands.c              mg_hilite_words.c       query.ranked.c       \
+  comp_dict.c             mg_invf_dict.c          read_line.c          \
+  environment.c           mg_invf_dump.c          stem_search.c        \
+  mg_invf_merge.c         stemmer.c               mg_stem_idx.c        \
+  mg_invf_rebuild.c       term_lists.c            mgstemidxlist.c      \
+  invf_get.c              mg_passes.c             text.pass1.c         \
+  ivf.pass1.c             mg_perf_hash_build.c    text.pass2.c         \
+  ivf.pass2.c             mg_text_estimate.c      text_get.c           \
+  lists.c                 mg_text_merge.c         weights.c            \
+  query_term_list.c       words.c
+
+HEADERS = \
+  backend.h          conditions.h       locallib.h         term_lists.h \
+  bool_optimiser.h   environment.h      mg.h               text.h       \
+  bool_parser.h      globals.h          mg_errors.h        text_get.h   \
+  bool_query.h       hash.h             mg_files.h         warranty.h   \
+  bool_tree.h        help.mg.h          mg_merge.h         weights.h    \
+  build.h            invf.h             read_line.h        words.h      \
+  commands.h         invf_get.h         stem_search.h                   \
+  comp_dict.h        lists.h            stemmer.h                       \
+  query_term_list.h
+
+EXEC = \
+  mgquery$e mg_weights_build$e mgstat$e mg_invf_dump$e \
+  mg_invf_dict$e mg_invf_rebuild$e mgdictlist$e \
+  mg_passes$e mg_perf_hash_build$e mg_compression_dict$e \
+  mg_text_estimate$e mg_fast_comp_dict$e mg_hilite_words$e \
+  mg_invf_merge$e mg_text_merge$e bool_tester$e \
+  mg_stem_idx$e  mgstemidxlist$e mg_decompress_text$e
+
+all:    $(EXEC) libtextin.a
+
+HILITE_OBJS = mg_hilite_words$o stemmer$o locallib$o words$o
+mg_hilite_words$e: $(HILITE_OBJS)
+	$(LINK) $(HILITE_OBJS) $(LIBS)
+
+BOOL_OBJS = bool_tree$o bool_parser$o bool_optimiser$o bool_tester$o \
+	    term_lists$o stemmer$o stem_search$o mg_errors$o query_term_list$o \
+	    words$o
+bool_tester$e: $(BOOL_OBJS)
+	$(LINK) $(BOOL_OBJS) $(LIBS)
+
+QUERY_OBJS = \
+	mgquery$o locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o bool_query$o \
+	query_term_list$o words$o
+mgquery$e: $(QUERY_OBJS)
+	$(LINK) $(QUERY_OBJS) $(LIBS)
+
+commands$o : help.mg.h warranty.h conditions.h
+
+PASSES_OBJS = \
+	mg_passes$o text.pass1$o comp_dict$o stemmer$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o \
+	words$o
+mg_passes$e: $(PASSES_OBJS)
+	$(LINK) $(PASSES_OBJS) $(LIBS)
+
+WEIGHTS_BUILD_OBJS = mg_weights_build$o mg_files$o
+mg_weights_build$e: $(WEIGHTS_BUILD_OBJS)
+	$(LINK) $(WEIGHTS_BUILD_OBJS) $(LIBS)
+
+COMP_DICT_OBJS = mg_compression_dict$o mg_files$o locallib$o
+mg_compression_dict$e: $(COMP_DICT_OBJS)
+	$(LINK) $(COMP_DICT_OBJS) $(LIBS)
+
+FAST_COMP_OBJS = mg_fast_comp_dict$o mg_files$o locallib$o
+mg_fast_comp_dict$e: $(FAST_COMP_OBJS)
+	$(LINK) $(FAST_COMP_OBJS) $(LIBS)
+
+TEXT_EST_OBJS = mg_text_estimate$o locallib$o comp_dict$o mg_files$o
+mg_text_estimate$e: $(TEXT_EST_OBJS)
+	$(LINK) $(TEXT_EST_OBJS) $(LIBS)
+
+STAT_OBJS = mgstat$o mg_files$o locallib$o
+mgstat$e: $(STAT_OBJS)
+	$(LINK) $(STAT_OBJS) $(LIBS)
+
+INVF_DUMP_OBJS = mg_invf_dump$o locallib$o mg_files$o
+mg_invf_dump$e: $(INVF_DUMP_OBJS)
+	$(LINK) $(INVF_DUMP_OBJS) $(LIBS)
+
+INVF_DICT_OBJS = mg_invf_dict$o mg_files$o locallib$o
+mg_invf_dict$e: $(INVF_DICT_OBJS)
+	$(LINK) $(INVF_DICT_OBJS) $(LIBS)
+
+INVF_REB_OBJS = mg_invf_rebuild$o locallib$o
+mg_invf_rebuild$e: $(INVF_REB_OBJS)
+	$(LINK) $(INVF_REB_OBJS) $(LIBS)
+
+DICTLIST_OBJS = mgdictlist$o locallib$o
+mgdictlist$e: $(DICTLIST_OBJS)
+	$(LINK) $(DICTLIST_OBJS) $(LIBS)
+
+PERF_HASH_OBJS = mg_perf_hash_build$o mg_files$o
+mg_perf_hash_build$e: $(PERF_HASH_OBJS)
+	$(LINK) $(PERF_HASH_OBJS) $(LIBS)
+
+STEM_IDX_OBJS = mg_stem_idx$o mg_files$o stemmer$o locallib$o \
+                mg_errors$o term_lists$o
+mg_stem_idx$e: $(STEM_IDX_OBJS)
+	$(LINK) $(STEM_IDX_OBJS) $(LIBS)
+
+STEM_IDX_LIST_OBJS = mgstemidxlist$o mg_files$o
+mgstemidxlist$e: $(STEM_IDX_LIST_OBJS)
+	$(LINK) $(STEM_IDX_LIST_OBJS) $(LIBS)
+
+DECOMPRESS_TEXT_OBJS = mg_decompress_text$o query_term_list$o mg_files$o mg_errors$o \
+                       text_get$o locallib$o backend$o stem_search$o \
+                       term_lists$o stemmer$o weights$o invf_get$o lists$o
+mg_decompress_text$e: $(DECOMPRESS_TEXT_OBJS)
+	$(LINK) $(DECOMPRESS_TEXT_OBJS) $(LIBS)
+
+TEXT_MERGE_OBJS = mg_text_merge$o mg_files$o locallib$o
+mg_text_merge$e: $(TEXT_MERGE_OBJS)
+	$(LINK) $(TEXT_MERGE_OBJS) $(LIBS)
+
+INVF_MERGE_OBJS = mg_invf_merge$o mg_files$o locallib$o
+mg_invf_merge$e: $(INVF_MERGE_OBJS)
+	$(LINK) $(INVF_MERGE_OBJS) $(LIBS)
+
+install: 
+	$(INSTALL) *$e ..$/..$/..$/..$/bin$/windows
+
+LIB_OBJS = \
+	query_term_list$o \
+	locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o \
+	bool_query$o words$o
+
+libtextin.a: $(LIB_OBJS)
+	$(DELETE) libtextin.a
+	$(AR) cru libtextin.a $(LIB_OBJS)
+	$(RANLIB) libtextin.a
+
+clean:
+	$(DELETE) *$o 
+	$(DELETE) *$e
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/Makefile.in	(revision 10506)
@@ -0,0 +1,386 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the MG system
+# Copyright (C) 1994  Neil Sharman;  1995 Tim Shimmin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)Makefile.in	1.10 22 Mar 1994
+#
+###########################################################################
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+subdir = src/text
+top_srcdir = @top_srcdir@
+transform = @program_transform_name@
+ 
+AR = ar
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+#LIBS = ../../lib/libmg.a -lm
+LIBS = ../../lib/libmg.a @LIBS@
+TOUCH = echo timestamp >
+AWK = @AWK@
+YACC = @YACC@
+GSDLOS = @gsdlos@
+
+##########################################
+# Uncomment for compiling for the nzdl project
+#
+CFLAGS = @CFLAGS@ -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM
+##########################################
+
+ 
+bindir = ../../../../bin/$(GSDLOS)
+datadir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+localedir = $(datadir)/locale
+mandir = $(prefix)/man/man1
+ 
+COMPILE = $(CC) -c $(DEFS) $(TREC_MODE) $(READLINE) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+ 
+
+ANSI2KNR = @ANSI2KNR@
+o = .@U@o
+ 
+.SUFFIXES: ._c ._o
+.c._c:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $@
+._c._o:
+	@echo $(COMPILE) $<
+	@rm -f _$*.c
+	@ln $< _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+.c._o:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $*._c
+	@echo $(COMPILE) $*._c
+	@rm -f _$*.c
+	@ln $*._c _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+ 
+INCLUDES = -I../../../.. -I../.. -I../../lib -I.
+
+#############################################################################
+#
+# Uncomment (and possibly edit) the following lines if you wish
+# to use the GNU readline library for the input in mgquery
+# 
+#READLINE = -DGNU_READLINE -I/opt/gnu/include/readline -L/opt/gnu/lib
+#READLINE_LIBS = -lreadline -ltermcap
+#
+#
+#############################################################################
+
+#############################################################################
+#
+# When working with the trec collection this should be uncommented.
+#
+# TREC_MODE = -DTREC_MODE
+#
+#
+#############################################################################
+
+SOURCES = \
+  backend.c               locallib.c              mg_weights_build.c   \
+  bool_optimiser.c        mg.special.c            mgdictlist.c         \
+  bool_parser.c           mg_compression_dict.c   mgquery.c            \
+  bool_query.c            mg_errors.c             mgstat.c             \
+  bool_tester.c           mg_fast_comp_dict.c     mg_decompress_text.c \
+  bool_tree.c             mg_files.c              query.docnums.c      \
+  commands.c              mg_hilite_words.c       query.ranked.c       \
+  comp_dict.c             mg_invf_dict.c          read_line.c          \
+  environment.c           mg_invf_dump.c          stem_search.c        \
+  mg_invf_merge.c         stemmer.c               mg_stem_idx.c        \
+  mg_invf_rebuild.c       term_lists.c            mgstemidxlist.c      \
+  invf_get.c              mg_passes.c             text.pass1.c         \
+  ivf.pass1.c             mg_perf_hash_build.c    text.pass2.c         \
+  ivf.pass2.c             mg_text_estimate.c      text_get.c           \
+  lists.c                 mg_text_merge.c         weights.c            \
+  query_term_list.c       words.c
+
+HEADERS = \
+  backend.h          conditions.h       locallib.h         term_lists.h \
+  bool_optimiser.h   environment.h      mg.h               text.h       \
+  bool_parser.h      globals.h          mg_errors.h        text_get.h   \
+  bool_query.h       hash.h             mg_files.h         warranty.h   \
+  bool_tree.h        help.mg.h          mg_merge.h         weights.h    \
+  build.h            invf.h             read_line.h        words.h      \
+  commands.h         invf_get.h         stem_search.h                   \
+  comp_dict.h        lists.h            stemmer.h                       \
+  query_term_list.h
+
+
+MISC          = Makefile.in help.mg.src bool_parser.y warranty.src conditions.src
+
+ALLFILES      =	$(SOURCES) $(HEADERS) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES) 
+
+EXEC          = mgquery mg_weights_build mgstat mg_invf_dump mg_invf_dict \
+                mg_invf_rebuild mgdictlist mg_passes mg_perf_hash_build \
+                mg_compression_dict mg_text_estimate mg_fast_comp_dict \
+                mg_hilite_words mg_invf_merge mg_text_merge bool_tester \
+                mg_stem_idx mgstemidxlist mg_decompress_text
+
+MAN           = mgquery.1 mg_weights_build.1 mgstat.1 mg_invf_dump.1 mg_invf_dict.1 \
+                mg_invf_rebuild.1 mgdictlist.1 mg_passes.1 mg_perf_hash_build.1 \
+                mg_compression_dict.1 mg_text_estimate.1 mg_fast_comp_dict.1 \
+                mg_hilite_words.1 mg_invf_merge.1 mg_text_merge.1 \
+                mg_stem_idx.1 mgstemidxlist.1 mg_decompress_text.1 
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all:	$(EXEC) libtextin.a 
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+help.mg.h : help.mg.src
+	sed -e 's/\\/\\\\/g' -e 's/\"/\\\"/g' help.mg.src | $(AWK) '/^#/ { next; };{ if (x == 0) printf("static char *help_str[] = {\n\"%s\\n\"", $$0); else printf(",\n\"%s\\n\"", $$0); x = 1; }; END { printf("};\n"); }' - >help.mg.h
+
+warranty.h : warranty.src
+	sed  -e 's/\\/\\\\/g' -e 's/\"/\\\"/g' warranty.src | $(AWK) '/^#/ { next; };{ if (x == 0) printf("static char *warranty_str[] = {\n\"%s\\n\"", $$0); else printf(",\n\"%s\\n\"", $$0); x = 1; }; END { printf("};\n"); }' - >warranty.h
+
+conditions.h : conditions.src
+	sed -e 's/\\/\\\\/g' -e 's/\"/\\\"/g' conditions.src | $(AWK) '/^#/ { next; };{ if (x == 0) printf("static char *cond_str[] = {\n\"%s\\n\"", $$0); else printf(",\n\"%s\\n\"", $$0); x = 1; }; END { printf("};\n"); }' - >conditions.h
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+HILITE_OBJS = mg_hilite_words$o stemmer$o locallib$o words$o environment$o
+
+mg_hilite_words: $(HILITE_OBJS)
+	$(LINK) $(HILITE_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+bool_parser.c: bool_parser.y
+	$(YACC) $?
+	mv y.tab.c $@
+
+BOOL_OBJS = bool_tree$o bool_parser$o bool_optimiser$o bool_tester$o \
+            term_lists$o stemmer$o stem_search$o mg_errors$o query_term_list$o \
+	    words$o environment$o
+
+bool_tester: $(BOOL_OBJS)
+	$(LINK) $(BOOL_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+QUERY_OBJS = \
+	mgquery$o locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o bool_query$o \
+	query_term_list$o words$o
+
+mgquery: $(QUERY_OBJS)	
+	$(LINK) $(READLINE) $(QUERY_OBJS) $(READLINE_LIBS) $(LIBS)
+
+commands$o : help.mg.h warranty.h conditions.h
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+PASSES_OBJS = \
+	mg_passes$o text.pass1$o comp_dict$o stemmer$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o \
+	words$o environment$o
+
+mg_passes: $(PASSES_OBJS)
+	$(LINK) $(PASSES_OBJS) $(LIBS) 
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+WEIGHTS_BUILD_OBJS = mg_weights_build$o mg_files$o
+
+mg_weights_build: $(WEIGHTS_BUILD_OBJS)
+	$(LINK) $(WEIGHTS_BUILD_OBJS) $(LIBS)
+
+COMP_DICT_OBJS = mg_compression_dict$o mg_files$o locallib$o
+
+mg_compression_dict: $(COMP_DICT_OBJS)
+	$(LINK) $(COMP_DICT_OBJS) $(LIBS)
+
+FAST_COMP_OBJS = mg_fast_comp_dict$o mg_files$o locallib$o
+
+mg_fast_comp_dict: $(FAST_COMP_OBJS)
+	$(LINK) $(FAST_COMP_OBJS) $(LIBS)
+
+TEXT_EST_OBJS = mg_text_estimate$o locallib$o comp_dict$o mg_files$o
+
+mg_text_estimate: $(TEXT_EST_OBJS)
+	$(LINK) $(TEXT_EST_OBJS) $(LIBS)
+
+STAT_OBJS = mgstat$o mg_files$o locallib$o
+
+mgstat:	$(STAT_OBJS)
+	$(LINK) $(STAT_OBJS) $(LIBS)
+
+INVF_DUMP_OBJS = mg_invf_dump$o locallib$o mg_files$o
+
+mg_invf_dump: $(INVF_DUMP_OBJS)
+	$(LINK) $(INVF_DUMP_OBJS) $(LIBS)
+
+INVF_DICT_OBJS = mg_invf_dict$o mg_files$o locallib$o
+
+mg_invf_dict: $(INVF_DICT_OBJS)
+	$(LINK) $(INVF_DICT_OBJS) $(LIBS)
+
+INVF_REB_OBJS = mg_invf_rebuild$o locallib$o
+
+mg_invf_rebuild: $(INVF_REB_OBJS)
+	$(LINK) $(INVF_REB_OBJS) $(LIBS)
+
+DICTLIST_OBJS = mgdictlist$o locallib$o
+
+mgdictlist: $(DICTLIST_OBJS)
+	$(LINK) $(DICTLIST_OBJS) $(LIBS)
+
+PERF_HASH_OBJS = mg_perf_hash_build$o mg_files$o
+
+mg_perf_hash_build: $(PERF_HASH_OBJS)
+	$(LINK) $(PERF_HASH_OBJS) $(LIBS)
+
+STEM_IDX_OBJS = \
+                mg_stem_idx$o mg_files$o stemmer$o locallib$o \
+                mg_errors$o term_lists$o
+
+mg_stem_idx: $(STEM_IDX_OBJS)
+	$(LINK) $(STEM_IDX_OBJS) $(LIBS)
+
+STEM_IDX_LIST_OBJS = mgstemidxlist$o mg_files$o
+
+mgstemidxlist: $(STEM_IDX_LIST_OBJS)
+	$(LINK) $(STEM_IDX_LIST_OBJS) $(LIBS)
+
+DECOMPRESS_TEXT_OBJS = \
+                mg_decompress_text.o query_term_list.o mg_files.o mg_errors.o \
+                text_get.o locallib.o backend.o stem_search.o \
+                term_lists.o stemmer.o weights.o invf_get.o lists.o
+
+mg_decompress_text: $(DECOMPRESS_TEXT_OBJS)
+	$(LINK) $(DECOMPRESS_TEXT_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+TEXT_MERGE_OBJS = mg_text_merge$o mg_files$o locallib$o
+
+mg_text_merge: $(TEXT_MERGE_OBJS)
+	$(LINK) $(TEXT_MERGE_OBJS) $(LIBS)
+
+INVF_MERGE_OBJS = mg_invf_merge$o mg_files$o locallib$o
+
+mg_invf_merge: $(INVF_MERGE_OBJS)
+	$(LINK) $(INVF_MERGE_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+ansi2knr: ansi2knr.o
+	$(LINK) ansi2knr.o $(LIBS)
+
+install: execinstall #maninstall
+uninstall: execuninstall manuninstall
+
+execinstall: $(EXEC)
+	for name in $(EXEC); do \
+	  $(INSTALL_PROGRAM) $$name \
+	  $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+execuninstall:
+	for name in $(EXEC); do \
+	 rm -f $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+# words$o,  removed to avoid conflict with mgpp libtextin.a
+LIB_OBJS = \
+	query_term_list$o \
+	locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o \
+	bool_query$o 
+
+libtextin.a: $(LIB_OBJS)
+	rm -f libtextin.a
+	$(AR) cru libtextin.a $(LIB_OBJS)
+	$(RANLIB) libtextin.a
+
+mostlyclean:
+	rm -f *$o _*.c _*.o *._c *._o core core.*
+ 
+clean: mostlyclean
+	rm -f $(EXEC) libtextin.a
+ 
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+ 
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+	  || cp -p $(srcdir)/$$file $(distdir); \
+	done
+ 
+# This screws up distclean, and isn't needed as configure makes the
+# Makefile. (jrm21)
+#Makefile: Makefile.in ../../../../config.status
+#	cd ../../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exc
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/WIN32.MAK
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/WIN32.MAK	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/WIN32.MAK	(revision 10506)
@@ -0,0 +1,227 @@
+###########################################################################
+#
+# win32 makefile -- mg\src\text
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..\..\..\..
+DLL = 0
+DLLDEBUG = 0
+
+CC = cl
+
+CPPFLAGS = -GX
+!IF $(DLL)
+CPPFLAGS = $(CPPFLAGS) -MD
+!ELSE
+!IF ($(DLLDEBUG))
+CPPFLAGS = $(CPPFLAGS) -MDd
+!ENDIF
+!ENDIF
+
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DHAVE_CONFIG_H \
+       -D__WIN32__ -D_LITTLE_ENDIAN
+INCLUDES = -I"$(GSDLHOME)\packages\mg\src\text" -I"$(GSDLHOME)\packages\mg" \
+	   -I"$(GSDLHOME)\packages\mg\lib" -I"$(GSDLHOME)"
+LDFLAGS =
+
+LIBS = "$(GSDLHOME)\packages\mg\lib\libmg.lib"
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .c .obj .cpp
+.c.obj:
+	$(COMPILE) $<
+.cpp.obj:
+	$(COMPILE) $<
+
+o = .obj
+e = .exe
+
+SOURCES = \
+  backend.c               locallib.c              mg_weights_build.c   \
+  bool_optimiser.c        mg.special.c            mgdictlist.c         \
+  bool_parser.c           mg_compression_dict.c   mgquery.c            \
+  bool_query.c            mg_errors.c             mgstat.c             \
+  bool_tester.c           mg_fast_comp_dict.c     mg_decompress_text.c \
+  bool_tree.c             mg_files.c              query.docnums.c      \
+  commands.c              mg_hilite_words.c       query.ranked.c       \
+  comp_dict.c             mg_invf_dict.c          read_line.c          \
+  environment.c           mg_invf_dump.c          stem_search.c        \
+  mg_invf_merge.c         stemmer.c               mg_stem_idx.c        \
+  mg_invf_rebuild.c       term_lists.c            mgstemidxlist.c      \
+  invf_get.c              mg_passes.c             text.pass1.c         \
+  ivf.pass1.c             mg_perf_hash_build.c    text.pass2.c         \
+  ivf.pass2.c             mg_text_estimate.c      text_get.c           \
+  lists.c                 mg_text_merge.c         weights.c            \
+  query_term_list.c       words.c
+
+HEADERS = \
+  backend.h          conditions.h       locallib.h         term_lists.h \
+  bool_optimiser.h   environment.h      mg.h               text.h       \
+  bool_parser.h      globals.h          mg_errors.h        text_get.h   \
+  bool_query.h       hash.h             mg_files.h         warranty.h   \
+  bool_tree.h        help.mg.h          mg_merge.h         weights.h    \
+  build.h            invf.h             read_line.h        words.h      \
+  commands.h         invf_get.h         stem_search.h                   \
+  comp_dict.h        lists.h            stemmer.h          query_term_list.h
+
+EXEC          = mgquery$e mg_weights_build$e mgstat$e \
+		mg_invf_dump$e     mg_invf_dict$e \
+		mg_invf_rebuild$e     mgdictlist$e \
+		mg_passes$e     mg_perf_hash_build$e \
+		mg_compression_dict$e     mg_text_estimate$e \
+		mg_fast_comp_dict$e \
+		mg_hilite_words$e     mg_invf_merge$e \
+		mg_text_merge$e     bool_tester$e \
+		mg_stem_idx$e  mgstemidxlist$e \
+                mg_decompress_text$e
+
+all:    $(EXEC) libtextin.lib
+
+HILITE_OBJS = mg_hilite_words$o stemmer$o locallib$o words$o environment$o
+mg_hilite_words$e: $(HILITE_OBJS)
+	$(LINK) $(HILITE_OBJS) $(LIBS)
+
+BOOL_OBJS = bool_tree$o bool_parser$o bool_optimiser$o bool_tester$o \
+	    term_lists$o stemmer$o stem_search$o mg_errors$o query_term_list$o \
+	    words$o environment$o
+bool_tester$e: $(BOOL_OBJS)
+	$(LINK) $(BOOL_OBJS) $(LIBS)
+
+QUERY_OBJS = \
+	mgquery$o locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o bool_query$o \
+	query_term_list$o words$o
+mgquery$e: $(QUERY_OBJS)
+	$(LINK) $(READLINE) $(QUERY_OBJS) $(READLINE_LIBS) $(LIBS)
+
+commands$o : help.mg.h warranty.h conditions.h
+
+PASSES_OBJS = \
+	mg_passes$o text.pass1$o comp_dict$o stemmer$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o \
+	words$o environment$o
+mg_passes$e: $(PASSES_OBJS)
+	$(LINK) $(PASSES_OBJS) $(LIBS)
+
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib
+
+BUILDER_OBJS = \
+	builder$o
+builder$e: $(BUILDER_OBJS)
+	$(LINK) $(BUILDER_OBJS) $(LIBS) $(LINK32_FLAGS)
+
+WEIGHTS_BUILD_OBJS = mg_weights_build$o mg_files$o
+mg_weights_build$e: $(WEIGHTS_BUILD_OBJS)
+	$(LINK) $(WEIGHTS_BUILD_OBJS) $(LIBS)
+
+COMP_DICT_OBJS = mg_compression_dict$o mg_files$o locallib$o
+mg_compression_dict$e: $(COMP_DICT_OBJS)
+	$(LINK) $(COMP_DICT_OBJS) $(LIBS)
+
+FAST_COMP_OBJS = mg_fast_comp_dict$o mg_files$o locallib$o
+mg_fast_comp_dict$e: $(FAST_COMP_OBJS)
+	$(LINK) $(FAST_COMP_OBJS) $(LIBS)
+
+TEXT_EST_OBJS = mg_text_estimate$o locallib$o comp_dict$o mg_files$o
+mg_text_estimate$e: $(TEXT_EST_OBJS)
+	$(LINK) $(TEXT_EST_OBJS) $(LIBS)
+
+STAT_OBJS = mgstat$o mg_files$o locallib$o
+mgstat$e: $(STAT_OBJS)
+	$(LINK) $(STAT_OBJS) $(LIBS)
+
+INVF_DUMP_OBJS = mg_invf_dump$o locallib$o mg_files$o
+mg_invf_dump$e: $(INVF_DUMP_OBJS)
+	$(LINK) $(INVF_DUMP_OBJS) $(LIBS)
+
+INVF_DICT_OBJS = mg_invf_dict$o mg_files$o locallib$o
+mg_invf_dict$e: $(INVF_DICT_OBJS)
+	$(LINK) $(INVF_DICT_OBJS) $(LIBS)
+
+INVF_REB_OBJS = mg_invf_rebuild$o locallib$o
+mg_invf_rebuild$e: $(INVF_REB_OBJS)
+	$(LINK) $(INVF_REB_OBJS) $(LIBS)
+
+DICTLIST_OBJS = mgdictlist$o locallib$o
+mgdictlist$e: $(DICTLIST_OBJS)
+	$(LINK) $(DICTLIST_OBJS) $(LIBS)
+
+PERF_HASH_OBJS = mg_perf_hash_build$o mg_files$o
+mg_perf_hash_build$e: $(PERF_HASH_OBJS)
+	$(LINK) $(PERF_HASH_OBJS) $(LIBS)
+
+STEM_IDX_OBJS = mg_stem_idx$o mg_files$o stemmer$o locallib$o \
+                mg_errors$o term_lists$o
+mg_stem_idx$e: $(STEM_IDX_OBJS)
+	$(LINK) $(STEM_IDX_OBJS) $(LIBS)
+
+STEM_IDX_LIST_OBJS = mgstemidxlist$o mg_files$o
+mgstemidxlist$e: $(STEM_IDX_LIST_OBJS)
+	$(LINK) $(STEM_IDX_LIST_OBJS) $(LIBS)
+
+DECOMPRESS_TEXT_OBJS = mg_decompress_text$o query_term_list$o mg_files$o mg_errors$o \
+                       text_get$o locallib$o backend$o stem_search$o \
+                       term_lists$o stemmer$o weights$o invf_get$o lists$o
+mg_decompress_text$e: $(DECOMPRESS_TEXT_OBJS)
+	$(LINK) $(DECOMPRESS_TEXT_OBJS) $(LIBS)
+
+TEXT_MERGE_OBJS = mg_text_merge$o mg_files$o locallib$o
+mg_text_merge$e: $(TEXT_MERGE_OBJS)
+	$(LINK) $(TEXT_MERGE_OBJS) $(LIBS)
+
+INVF_MERGE_OBJS = mg_invf_merge$o mg_files$o locallib$o
+mg_invf_merge$e: $(INVF_MERGE_OBJS)
+	$(LINK) $(INVF_MERGE_OBJS) $(LIBS)
+
+install: 
+	if NOT EXIST "$(GSDLHOME)\bin\windows" mkdir "$(GSDLHOME)\bin\windows"
+	for %%i in ($(EXEC)) do \
+	  copy %%i "$(GSDLHOME)\bin\windows"
+
+# words$o,  removed to avoid conflict with mgpp libtextin.a
+LIB_OBJS = \
+	query_term_list$o \
+	locallib$o lists$o \
+	query.ranked$o query.docnums$o stem_search$o \
+	environment$o commands$o weights$o text_get$o stemmer$o \
+	read_line$o mg_errors$o backend$o invf_get$o \
+	term_lists$o bool_tree$o bool_parser$o bool_optimiser$o \
+	bool_query$o
+
+libtextin.lib: $(LIB_OBJS)
+	if EXIST libtextin.lib del libtextin.lib
+	lib /out:libtextin.lib $(LIB_OBJS)
+
+clean:
+	del *$o 
+	del $(EXEC)
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/backend.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/backend.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/backend.c	(revision 10506)
@@ -0,0 +1,838 @@
+/**************************************************************************
+ *
+ * backend.c -- Underlying routines for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "timing.h"
+#include "filestats.h"
+#include "sptree.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+#include "mg_files.h"
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "stem_search.h"
+#include "invf_get.h"
+#include "text_get.h"
+#include "weights.h"
+#include "locallib.h"
+#include "mg_errors.h"
+
+
+static File *
+OpenFile (char *base, char *suffix, unsigned long magic, int *ok)
+{
+  char FileName[512];
+  File *F;
+  sprintf (FileName, "%s%s", base, suffix);
+  if (!(F = Fopen (FileName, "rb", 0)))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      mg_errno = MG_NOFILE;
+      MgErrorData (FileName);
+      if (ok)
+	*ok = 0;
+      return (NULL);
+    }
+  if (magic)
+    {
+      unsigned long m;
+      if (fread ((char *) &m, sizeof (m), 1, F->f) == 0)
+	{
+	  mg_errno = MG_READERR;
+	  MgErrorData (FileName);
+	  if (ok)
+	    *ok = 0;
+	  Fclose (F);
+	  return (NULL);
+	}
+      NTOHUL(m);  /* [RPAP - Jan 97: Endian Ordering] */
+      if (m != magic)
+	{
+	  mg_errno = MG_BADMAGIC;
+	  MgErrorData (FileName);
+	  if (ok)
+	    *ok = 0;
+	  Fclose (F);
+	  return (NULL);
+	}
+    }
+  return (F);
+}
+
+
+static int 
+open_all_files (query_data * qd)
+{
+  int ok = 1;
+
+  qd->File_text = OpenFile (qd->textpathname, TEXT_SUFFIX, /* [RJM 06/97: text filename] */
+			    MAGIC_TEXT, &ok);
+  qd->File_fast_comp_dict = OpenFile (qd->textpathname, /* [RJM 06/97: text filename] */
+				      TEXT_DICT_FAST_SUFFIX, MAGIC_FAST_DICT, NULL);
+  if (!qd->File_fast_comp_dict)
+    {
+      qd->File_comp_dict = OpenFile (qd->textpathname, /* [RJM 06/97: text filename] */
+				     TEXT_DICT_SUFFIX, MAGIC_DICT, &ok);
+      qd->File_aux_dict = OpenFile (qd->textpathname, /* [RJM 06/97: text filename] */
+				    TEXT_DICT_AUX_SUFFIX, MAGIC_AUX_DICT, NULL);
+    }
+  else
+    qd->File_comp_dict = qd->File_aux_dict = NULL;
+
+  qd->File_stem = OpenFile (qd->pathname, INVF_DICT_BLOCKED_SUFFIX,
+			    MAGIC_STEM, &ok);
+
+  /* [RPAP - Jan 97: Stem Index Change]
+     These will fail if collection not built with stem indexes */
+  qd->File_stem1 = OpenFile (qd->pathname, INVF_DICT_BLOCKED_1_SUFFIX,
+			     MAGIC_STEM_1, NULL);
+  qd->File_stem2 = OpenFile (qd->pathname, INVF_DICT_BLOCKED_2_SUFFIX,
+			     MAGIC_STEM_2, NULL);
+  qd->File_stem3 = OpenFile (qd->pathname, INVF_DICT_BLOCKED_3_SUFFIX,
+			     MAGIC_STEM_3, NULL);
+
+  qd->File_invf = OpenFile (qd->pathname, INVF_SUFFIX,
+			    MAGIC_INVF, &ok);
+
+  /* These will fail if a level 1 inverted file was created because there 
+     will be no document weights */
+  qd->File_text_idx_wgt = OpenFile (qd->pathname, TEXT_IDX_WGT_SUFFIX,
+				    MAGIC_TEXI_WGT, NULL);
+  qd->File_weight_approx = OpenFile (qd->pathname, APPROX_WEIGHTS_SUFFIX,
+				     MAGIC_WGHT_APPROX, NULL);
+  if (qd->File_text_idx_wgt == NULL && qd->File_weight_approx == NULL)
+    qd->File_text_idx = OpenFile (qd->textpathname, /* [RJM 06/97: text filename] */
+				  TEXT_IDX_SUFFIX, MAGIC_TEXI, NULL);
+  else
+    qd->File_text_idx = NULL;
+
+
+  if (!ok)
+    {
+      Fclose (qd->File_text);
+      if (qd->File_fast_comp_dict)
+	Fclose (qd->File_fast_comp_dict);
+      if (qd->File_comp_dict)
+	Fclose (qd->File_comp_dict);
+      Fclose (qd->File_stem);
+
+      /* [RPAP - Jan 97: Stem Index Change] */
+      if (qd->File_stem1)
+	Fclose (qd->File_stem1);
+      if (qd->File_stem2)
+	Fclose (qd->File_stem2);
+      if (qd->File_stem3)
+	Fclose (qd->File_stem3);
+
+      Fclose (qd->File_invf);
+      if (qd->File_text_idx_wgt)
+	Fclose (qd->File_text_idx_wgt);
+      if (qd->File_weight_approx)
+	Fclose (qd->File_weight_approx);
+      if (qd->File_text_idx)
+	Fclose (qd->File_text_idx);
+      return (-1);
+    }
+  return (0);
+
+}
+
+static void 
+close_all_files (query_data * qd)
+{
+  Fclose (qd->File_text);
+  if (qd->File_fast_comp_dict)
+    Fclose (qd->File_fast_comp_dict);
+  if (qd->File_aux_dict)
+    Fclose (qd->File_aux_dict);
+  if (qd->File_comp_dict)
+    Fclose (qd->File_comp_dict);
+  Fclose (qd->File_stem);
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (qd->File_stem1)
+    Fclose (qd->File_stem1);
+  if (qd->File_stem2)
+    Fclose (qd->File_stem2);
+  if (qd->File_stem3)
+    Fclose (qd->File_stem3);
+
+  Fclose (qd->File_invf);
+  if (qd->File_text_idx_wgt)
+    Fclose (qd->File_text_idx_wgt);
+  if (qd->File_weight_approx)
+    Fclose (qd->File_weight_approx);
+  if (qd->File_text_idx)
+    Fclose (qd->File_text_idx);
+}
+
+/* If textname is equal to null then name will be used instead */
+/* [RJM 06/97: text filename] */
+query_data *
+InitQuerySystem (char *dir, char *name, char *textname, InitQueryTimes * iqt)
+{
+  query_data *qd;
+  char *s;
+
+  if (textname == NULL) textname = name; /* [RJM 06/97: text filename] */
+
+  if (!(qd = Xmalloc (sizeof (query_data))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  bzero ((char *) qd, sizeof (*qd));
+
+  qd->mem_in_use = qd->max_mem_in_use = 0;
+
+  qd->doc_pos = qd->buf_in_use = 0;
+  qd->TextBufferLen = 0;
+  qd->DL = NULL;
+
+  /* [RPAP - Feb 97: Term Frequency] */
+  qd->TL = NULL;
+  qd->QTL = NULL;
+
+  qd->TextBuffer = NULL;
+
+  qd->tot_hops_taken = 0;
+  qd->tot_num_of_ptrs = 0;
+  qd->tot_num_of_accum = 0;
+  qd->tot_num_of_terms = 0;
+  qd->tot_num_of_ans = 0;
+  qd->tot_text_idx_lookups = 0;
+
+  qd->hops_taken = 0;
+  qd->num_of_ptrs = 0;
+  qd->num_of_accum = 0;
+  qd->num_of_terms = 0;
+  qd->num_of_ans = 0;
+  qd->text_idx_lookups = 0;
+
+  qd->pathname = NULL; /* RJM 06/97: text filename] */
+  qd->textpathname = NULL; /* RJM 06/97: text filename] */
+
+  s = strrchr (dir, '/');
+  if (s && *(s + 1) == '\0')
+    {
+      /* [RJM 06/97: text filename] */
+      if (!(qd->pathname = Xmalloc (strlen (dir) + strlen (name) + 1)) ||
+	  !(qd->textpathname = Xmalloc (strlen (dir) + strlen (textname) + 1)))
+	{
+	  mg_errno = MG_NOMEM;
+	  if (qd->pathname) Xfree (qd->pathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+      sprintf (qd->pathname, "%s%s", dir, name);
+      sprintf (qd->textpathname, "%s%s", dir, textname); /* [RJM 06/97: text filename] */
+    }
+
+  else
+    {
+      /* [RJM 06/97: text filename] */
+      if (!(qd->pathname = Xmalloc (strlen (dir) + strlen (name) + 2)) ||
+	  !(qd->textpathname = Xmalloc (strlen (dir) + strlen (textname) + 2)))
+	{
+	  mg_errno = MG_NOMEM;
+	  if (qd->pathname) Xfree (qd->pathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+      if (dir == NULL || dir[0] == '\0') {
+	sprintf (qd->pathname, "%s", name);
+	sprintf (qd->textpathname, "%s", textname); /* [RJM 06/97: text filename] */
+      } else {
+	sprintf (qd->pathname, "%s%s", dir, name);
+	sprintf (qd->textpathname, "%s%s", dir, textname); /* [RJM 06/97: text filename] */
+      }
+#else
+      sprintf (qd->pathname, "%s/%s", dir, name);
+      sprintf (qd->textpathname, "%s/%s", dir, textname); /* [RJM 06/97: text filename] */
+#endif
+    }
+
+  if (open_all_files (qd) == -1)
+    {
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+
+  if (iqt)
+    GetTime (&iqt->Start);
+
+  /* Initialise the stemmed dictionary system */
+  if (!(qd->sd = ReadStemDictBlk (qd->File_stem)))
+    {
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if ((qd->sd->sdh.indexed & 7) && qd->File_stem1 && qd->File_stem2 && qd->File_stem3)
+    {
+      if (!(qd->sd->stem1 = ReadStemIdxBlk (qd->File_stem1)))
+	{
+	  FreeStemDict (qd->sd);
+	  close_all_files (qd);
+	  Xfree (qd->pathname);
+	  Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+      if (!(qd->sd->stem2 = ReadStemIdxBlk (qd->File_stem2)))
+	{
+	  FreeStemDict (qd->sd);
+	  close_all_files (qd);
+	  Xfree (qd->pathname);
+	  Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+      if (!(qd->sd->stem3 = ReadStemIdxBlk (qd->File_stem3)))
+	{
+	  FreeStemDict (qd->sd);
+	  close_all_files (qd);
+	  Xfree (qd->pathname);
+	  Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+      }
+  else if (qd->sd->sdh.indexed != 0)
+    {
+      FreeStemDict (qd->sd);
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+  else
+    {
+      if (qd->File_stem1)
+	Fclose (qd->File_stem1);
+      if (qd->File_stem2)
+	Fclose (qd->File_stem2);
+      if (qd->File_stem3)
+	Fclose (qd->File_stem3);
+      qd->File_stem1 = NULL;
+      qd->File_stem2 = NULL;
+      qd->File_stem3 = NULL;
+      qd->sd->stem1 = NULL;
+      qd->sd->stem2 = NULL;
+      qd->sd->stem3 = NULL;
+    }
+
+  if (iqt)
+    GetTime (&iqt->StemDict);
+  if (qd->File_weight_approx)
+    {
+      if (!(qd->awd = LoadDocWeights (qd->File_weight_approx,
+				      qd->sd->sdh.num_of_docs)))
+	{
+	  FreeStemDict (qd->sd);
+	  close_all_files (qd);
+	  Xfree (qd->pathname);
+	  Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+	  Xfree (qd);
+	  return (NULL);
+	}
+    }
+  else
+    qd->awd = NULL;
+
+
+  if (iqt)
+    GetTime (&iqt->ApproxWeights);
+
+  if (!(qd->cd = LoadCompDict (qd->File_comp_dict, qd->File_aux_dict,
+			       qd->File_fast_comp_dict)))
+    {
+      if (qd->awd)
+	FreeWeights (qd->awd);
+      FreeStemDict (qd->sd);
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+
+  if (iqt)
+    GetTime (&iqt->CompDict);
+
+  if (!(qd->id = InitInvfFile (qd->File_invf, qd->sd)))
+    {
+      FreeCompDict (qd->cd);
+      if (qd->awd)
+	FreeWeights (qd->awd);
+      FreeStemDict (qd->sd);
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+  if ((qd->File_text_idx_wgt == NULL || qd->File_weight_approx == NULL) &&
+      qd->id->ifh.InvfLevel >= 2)
+    {
+      FreeInvfData (qd->id);
+      FreeCompDict (qd->cd);
+      if (qd->awd)
+	FreeWeights (qd->awd);
+      FreeStemDict (qd->sd);
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      mg_errno = MG_INVERSION;
+      return (NULL);
+    }
+  if (iqt)
+    GetTime (&iqt->Invf);
+
+  if (!(qd->td = LoadTextData (qd->File_text, qd->File_text_idx_wgt,
+			       qd->File_text_idx)))
+    {
+      FreeInvfData (qd->id);
+      FreeCompDict (qd->cd);
+      if (qd->awd)
+	FreeWeights (qd->awd);
+      FreeStemDict (qd->sd);
+      close_all_files (qd);
+      Xfree (qd->pathname);
+      Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+      Xfree (qd);
+      return (NULL);
+    }
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) || defined(NZDL)
+
+/*
+
+This code is based on the TREC_MODE code below to read the .paragraph
+file to determine what document numbers correspond to what paragraphs.
+This code is more space efficient, reading in the .paragraph file
+into memory as an accumulate docnum array.  Eg.  the .paragraph may contain
+
+	[5 3 6 4 7 9 4]
+
+indicating the first document has 5 paragraphs, the next 3, etc.
+This will be stored in memory as
+
+	[0 5 8 14 18 25 34 38]
+
+so a binary search can be performed.  The first 0 is for convenience;
+it prevents testing boundary conditions.
+
+
+The TREC_MODE code does this differently; it stores the array
+
+	[1 1 1 1 1 2 2 2 3 3 3 3 3 3 ....]
+
+allowing directy paragraph to docnum conversion, at the expense
+of memory.
+
+*/ 
+  qd->paragraph = NULL;
+
+  if (qd->id->ifh.InvfLevel == 3)
+    {
+      unsigned long magic;
+      FILE *paragraph;
+      int i;
+      char paraFile[512];
+
+      sprintf(paraFile, "%s%s", qd->pathname, INVF_PARAGRAPH_SUFFIX);
+      paragraph = fopen(paraFile, "rb");
+      if (!paragraph)
+	FatalError(1, "Unable to open 'paraFile'.", paraFile);
+
+      fread((void *)&magic, sizeof(magic), 1, paragraph);
+      qd->paragraph = Xmalloc((qd->td->cth.num_of_docs+1)*sizeof(int));
+      qd->paragraph[0] = 0;
+      for (i = 1; i <= qd->td->cth.num_of_docs; i++)
+	{
+	  int count;
+
+	  if (fread((void *)&count, sizeof(count), 1, paragraph) != 1)
+	    FatalError(1, "Unexpected EOF while reading '%s'.", paraFile);
+	  NTOHSI(count);  /* [RPAP - Jan 97: Endian Ordering] */
+	  qd->paragraph[i] = qd->paragraph[i-1]+count;
+	}
+
+      fclose (paragraph); /* [RJM 07/98: Memory Leak] */
+    }
+  
+  
+#endif
+
+#ifdef TREC_MODE
+  {
+    extern char *trec_ids;
+    extern long *trec_paras;
+    int size;
+    char FileName[512];
+    FILE *f;
+    if (!strstr (qd->pathname, "trec"))
+      goto error;
+    sprintf (FileName, "%s%s", qd->pathname, ".DOCIDS");
+    if (!(f = fopen (FileName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+      {
+	Message ("Unable to open \"%s\"", FileName);
+	goto error;
+      }
+    fseek (f, 0, 2);
+    size = ftell (f);
+    fseek (f, 0, 0);
+    trec_ids = Xmalloc (size);
+    if (!trec_ids)
+      {
+	fclose (f);
+	goto error;
+      }
+    fread (trec_ids, 1, size, f);
+    fclose (f);
+    if (qd->id->ifh.InvfLevel == 3)
+      {
+	int i, d;
+	unsigned long magic;
+	trec_paras = Xmalloc (qd->sd->sdh.num_of_docs * sizeof (long));
+	if (!trec_paras)
+	  {
+	    Xfree (trec_ids);
+	    trec_ids = NULL;
+	    goto error;
+	  }
+	sprintf (FileName, "%s%s", qd->pathname, INVF_PARAGRAPH_SUFFIX);
+	if (!(f = fopen (FileName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+	  {
+	    Message ("Unable to open \"%s\"", FileName);
+	    goto error;
+	  }
+	if (fread ((char *) &magic, sizeof (magic), 1, f) != 1 ||
+	    NTOHUL(magic) != MAGIC_PARAGRAPH)  /* [RPAP - Jan 97: Endian Ordering] */
+	  {
+	    fclose (f);
+	    Message ("Bad magic number in \"%s\"", FileName);
+	    goto error;
+	  }
+
+	for (d = i = 0; i < qd->td->cth.num_of_docs; i++)
+	  {
+	    int count;
+	    if (fread ((char *) &count, sizeof (count), 1, f) != 1)
+	      {
+		fclose (f);
+		goto error;
+	      }
+	    NTOHSI(count);  /* [RPAP - Jan 97: Endian Ordering] */
+	    while (count--)
+	      trec_paras[d++] = i;
+	  }
+	fclose (f);
+      }
+    goto ok;
+  error:
+    if (trec_ids)
+      Xfree (trec_ids);
+    if (trec_paras)
+      Xfree (trec_paras);
+    trec_ids = NULL;
+    trec_paras = NULL;
+  ok:
+    ;
+  }
+#endif
+
+  if (iqt)
+    GetTime (&iqt->Text);
+
+  return (qd);
+}
+
+
+
+
+
+
+/*
+ * Change the amount of memory currently in use
+ *
+ */
+void 
+ChangeMemInUse (query_data * qd, long delta)
+{
+  qd->mem_in_use += delta;
+  if (qd->mem_in_use > qd->max_mem_in_use)
+    qd->max_mem_in_use = qd->mem_in_use;
+}
+
+
+void 
+FinishQuerySystem (query_data * qd)
+{
+/* [RJM 07/98: Memory Leak] */
+#if defined(PARADOCNUM) || defined(NZDL)
+  if (qd->paragraph != NULL) {
+    Xfree (qd->paragraph);
+    qd->paragraph = NULL;
+  }
+#endif
+
+  FreeTextData (qd->td);
+  FreeInvfData (qd->id);
+  FreeCompDict (qd->cd);
+  if (qd->awd)
+    FreeWeights (qd->awd);
+  FreeStemDict (qd->sd);
+  close_all_files (qd);
+  Xfree (qd->textpathname); /* [RJM 06/97: text filename] */
+  Xfree (qd->pathname);
+  FreeQueryDocs (qd);
+  if (qd->TL != NULL) FreeTermList(&qd->TL);         /* [RJM 07/98: Memory Leak] */
+  if (qd->QTL != NULL) FreeQueryTermList(&qd->QTL);  /* [RJM 07/98: Memory Leak] */
+  Xfree (qd);
+
+  /* other global stuff hanging around */
+  MgErrorDeinit ();
+}
+
+
+void 
+ResetFileStats (query_data * qd)
+{
+  ZeroFileStats (qd->File_text);
+  if (qd->File_comp_dict)
+    ZeroFileStats (qd->File_comp_dict);
+  if (qd->File_fast_comp_dict)
+    ZeroFileStats (qd->File_fast_comp_dict);
+  ZeroFileStats (qd->File_stem);
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (qd->File_stem1)
+    ZeroFileStats (qd->File_stem1);
+  if (qd->File_stem2)
+    ZeroFileStats (qd->File_stem2);
+  if (qd->File_stem3)
+    ZeroFileStats (qd->File_stem3);
+
+  ZeroFileStats (qd->File_invf);
+  if (qd->File_text_idx_wgt)
+    ZeroFileStats (qd->File_text_idx_wgt);
+  if (qd->File_weight_approx)
+    ZeroFileStats (qd->File_weight_approx);
+  if (qd->File_text_idx)
+    ZeroFileStats (qd->File_text_idx);
+}
+
+
+void 
+TransFileStats (query_data * qd)
+{
+  qd->File_text->Current = qd->File_text->Cumulative;
+  if (qd->File_comp_dict)
+    qd->File_comp_dict->Current = qd->File_comp_dict->Cumulative;
+  if (qd->File_fast_comp_dict)
+    qd->File_fast_comp_dict->Current = qd->File_fast_comp_dict->Cumulative;
+  qd->File_stem->Current = qd->File_stem->Cumulative;
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (qd->File_stem1)
+    qd->File_stem1->Current = qd->File_stem1->Cumulative;
+  if (qd->File_stem2)
+    qd->File_stem2->Current = qd->File_stem2->Cumulative;
+  if (qd->File_stem3)
+    qd->File_stem3->Current = qd->File_stem3->Cumulative;
+
+  qd->File_invf->Current = qd->File_invf->Cumulative;
+  if (qd->File_text_idx_wgt)
+    qd->File_text_idx_wgt->Current = qd->File_text_idx_wgt->Cumulative;
+  if (qd->File_weight_approx)
+    qd->File_weight_approx->Current = qd->File_weight_approx->Cumulative;
+  if (qd->File_text_idx)
+    qd->File_text_idx->Current = qd->File_text_idx->Cumulative;
+}
+
+
+void 
+FreeTextBuffer (query_data * qd)
+{
+  if (qd->TextBuffer)
+    {
+      Xfree (qd->TextBuffer);
+      ChangeMemInUse (qd, -qd->TextBufferLen);
+    }
+  qd->TextBuffer = NULL;
+  qd->TextBufferLen = 0;
+}
+
+void 
+FreeQueryDocs (query_data * qd)
+{
+  qd->doc_pos = 0;
+  qd->buf_in_use = 0;
+  if (qd->DL)
+    {
+      int i;
+      for (i = 0; i < qd->DL->num; i++)
+	if (qd->DL->DE[i].CompTextBuffer)
+	  {
+	    Xfree (qd->DL->DE[i].CompTextBuffer);
+	    qd->DL->DE[i].CompTextBuffer = NULL;
+	    ChangeMemInUse (qd, -qd->DL->DE[i].Len);
+	  }
+      Xfree (qd->DL);
+    }
+  qd->DL = NULL;
+  FreeTextBuffer (qd);
+}
+
+int 
+LoadCompressedText (query_data * qd, int max_mem)
+{
+  DocEntry *DE;
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return -1;
+
+  DE = &qd->DL->DE[qd->doc_pos];
+  if (!DE->CompTextBuffer)
+    {
+      int i;
+      DocEntry *de;
+      for (i = 0, de = qd->DL->DE; i < qd->DL->num; i++, de++)
+	if (de->CompTextBuffer)
+	  {
+	    Xfree (de->CompTextBuffer);
+	    de->CompTextBuffer = NULL;
+	    ChangeMemInUse (qd, -de->Len);
+	  }
+      if (LoadBuffers (qd, &qd->DL->DE[qd->doc_pos], max_mem,
+		       qd->DL->num - qd->doc_pos) == -1)
+	return -1;
+    }
+  return 0;
+}
+
+int 
+GetDocNum (query_data * qd)
+{
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return -1;
+  return qd->DL->DE[qd->doc_pos].DocNum;
+}
+
+DocEntry *
+GetDocChain (query_data * qd)
+{
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return NULL;
+  return &(qd->DL->DE[qd->doc_pos]);
+}
+
+float 
+GetDocWeight (query_data * qd)
+{
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return -1;
+  return qd->DL->DE[qd->doc_pos].Weight;
+}
+
+long 
+GetDocCompLength (query_data * qd)
+{
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return -1;
+  return qd->DL->DE[qd->doc_pos].Len;
+}
+
+
+u_char *
+GetDocText (query_data * qd, unsigned long *len)
+{
+  DocEntry *DE;
+  int ULen;
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return NULL;
+
+  DE = &qd->DL->DE[qd->doc_pos];
+
+  if (!DE->CompTextBuffer)
+    {
+      fprintf (stderr, "The compressed text buffer is NULL\n");
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  FreeTextBuffer (qd);
+
+  qd->TextBufferLen = (int) (qd->td->cth.ratio * 1.01 *
+			     DE->Len) + 100;
+  if (!(qd->TextBuffer = Xmalloc (qd->TextBufferLen)))
+    {
+      fprintf (stderr, "No memory for TextBuffer\n");
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  DecodeText (qd->cd, (u_char *) (DE->CompTextBuffer), DE->Len,
+	      (u_char *) (qd->TextBuffer), &ULen);
+  qd->TextBuffer[ULen] = '\0';
+
+  if (ULen >= qd->TextBufferLen)
+    {
+      fprintf (stderr, "%d >= %d\n", ULen, qd->TextBufferLen);
+      mg_errno = MG_BUFTOOSMALL;
+      return (NULL);
+    }
+
+  if (len)
+    *len = ULen;
+
+  return qd->TextBuffer;
+}
+
+int 
+NextDoc (query_data * qd)
+{
+  if (qd->DL == NULL || qd->doc_pos >= qd->DL->num)
+    return 0;
+  qd->doc_pos++;
+  return qd->doc_pos < qd->DL->num;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/backend.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/backend.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/backend.h	(revision 10506)
@@ -0,0 +1,261 @@
+/**************************************************************************
+ *
+ * backend.h -- Underlying routines and datastructures for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef BACKEND_H
+#define BACKEND_H
+
+#include "sysfuncs.h"
+
+#include "timing.h"
+#include "lists.h"
+#include "term_lists.h"
+#include "query_term_list.h"  /* [RPAP - Feb 97: Term Frequency] */
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+
+
+typedef struct invf_data
+  {
+    File *InvfFile;
+    unsigned long N;
+    unsigned long Nstatic;	/* N parameter for decoding inverted file entries */
+    struct invf_file_header ifh;
+  }
+invf_data;
+
+typedef struct text_data
+  {
+    File *TextFile;
+    File *TextIdxFile;
+    File *TextIdxWgtFile;
+    long current_pos;
+    struct
+      {
+	unsigned long Start;
+	float Weight;
+      }
+     *idx_data;
+    compressed_text_header cth;
+  }
+text_data;
+
+
+typedef struct auxiliary_dict
+  {
+    aux_frags_header afh[2];
+    u_char *word_data[2];
+    u_char **words[2];
+    int blk_start[2][33], blk_end[2][33];	/* blk_start and blk_end are required
+						   for the hybrid methods */
+  }
+auxiliary_dict;
+
+
+typedef struct compression_dict
+  {
+    compression_dict_header cdh;
+    comp_frags_header *cfh[2];
+    unsigned long MemForCompDict;
+    u_char ***values[2];
+    u_char *escape[2];
+    huff_data *chars_huff[2];
+    u_long **chars_vals[2];
+    huff_data *lens_huff[2];
+    u_long **lens_vals[2];
+    auxiliary_dict *ad;
+    int fast_loaded;
+  }
+compression_dict;
+
+
+typedef struct stemmed_idx   /* [RPAP - Jan 97: Stem Index Change] */
+  {
+    File *stem_idx_file;
+    struct stem_idx_header sih;
+    u_char **index;
+    unsigned long *pos;
+    int active;
+    u_char *buffer;
+    unsigned long MemForStemIdx;
+  }
+stemmed_idx;
+
+
+typedef struct stemmed_dict
+  {
+    File *stem_file;
+    struct stem_dict_header sdh;
+    u_char **index;
+    unsigned long *pos;
+    int active;
+    u_char *buffer;
+    unsigned long MemForStemDict;
+
+    /* [RPAP - Jan 97: Stem Index Change] */
+    stemmed_idx *stem1;
+    stemmed_idx *stem2;
+    stemmed_idx *stem3;
+  }
+stemmed_dict;
+
+
+typedef struct approx_weights_data
+  {
+    double L;
+    double B;
+    unsigned long *DocWeights;
+    char bits;
+    float *table;
+    unsigned long mask;
+    unsigned long MemForWeights;
+    unsigned long num_of_docs;
+  }
+approx_weights_data;
+
+
+typedef struct RankedQueryInfo
+  {
+    int QueryFreqs;
+    int Exact;           /* use exact weights for ranking or not */
+    long MaxDocsToRetrieve;	/* may be -1 for all */
+    long MaxParasToRetrieve;
+    int Sort;        
+    char AccumMethod;		/* 'A' = array,  'S' = splay tree,  'H' = hash_table */
+    long MaxAccums;		/* may be -1 for all */
+    long MaxTerms;		/* may be -1 for all */
+    int StopAtMaxAccum; /* Stop at maximum accumulator or not */
+    long HashTblSize;
+    char *skip_dump;
+  }
+RankedQueryInfo;
+
+
+
+typedef struct BooleanQueryInfo
+  {
+    long MaxDocsToRetrieve;
+  }
+BooleanQueryInfo;
+
+
+/* [TS:24/Aug/94] - maximum number of characters in term string */
+#define MAXTERMSTRLEN 1023
+
+typedef struct query_data
+  {
+    stemmed_dict *sd;
+    compression_dict *cd;
+    approx_weights_data *awd;
+    invf_data *id;
+    text_data *td;
+#if defined(PARADOCNUM) || defined(NZDL)
+    int *paragraph;
+#endif
+    char *pathname;
+    char *textpathname; /* [RJM 06/97: text filename] */
+    File *File_text;
+    File *File_comp_dict;
+    File *File_aux_dict;
+    File *File_fast_comp_dict;
+    File *File_text_idx_wgt;
+    File *File_text_idx;
+    File *File_stem;
+
+    /* [RPAP - Jan 97: Stem Index Change] */
+    File *File_stem1;
+    File *File_stem2;
+    File *File_stem3;
+
+    File *File_invf;
+    File *File_weight_approx;
+    unsigned long mem_in_use, max_mem_in_use;
+    unsigned long num_of_ptrs, tot_num_of_ptrs;
+    unsigned long num_of_terms, tot_num_of_terms;
+    unsigned long num_of_accum, tot_num_of_accum;
+    unsigned long num_of_ans, tot_num_of_ans;
+    unsigned long hops_taken, tot_hops_taken;
+    unsigned long text_idx_lookups, tot_text_idx_lookups;
+    unsigned long max_buffers;
+    unsigned doc_pos;
+    unsigned buf_in_use;
+    DocList *DL;
+    TermList *TL;		/* [TS:Oct/94] - so term list for query can easily be accessed */
+    u_char *TextBuffer;
+    int TextBufferLen;
+    QueryTermList *QTL;    /* [RPAP - Feb 97: Term Frequency] */
+  }
+query_data;
+
+
+
+typedef struct InitQueryTimes
+  {
+    ProgTime Start;
+    ProgTime StemDict;
+    ProgTime ApproxWeights;
+    ProgTime CompDict;
+    ProgTime Invf;
+    ProgTime Text;
+  }
+InitQueryTimes;
+
+
+/* [RJM 06/97: text filename] */
+query_data *InitQuerySystem (char *dir, char *name, char *textname, InitQueryTimes * iqt);
+
+void ChangeMemInUse (query_data * qd, long delta);
+
+void FinishQuerySystem (query_data * qd);
+
+void ResetFileStats (query_data * qd);
+
+void TransFileStats (query_data * qd);
+
+void RankedQuery (query_data * qd, char *Query, RankedQueryInfo * rqi);
+
+void BooleanQuery (query_data * qd, char *Query, BooleanQueryInfo * bqi,
+		   int stem_method);
+
+void DocnumsQuery (query_data * qd, char *QueryLine);
+
+void FreeTextBuffer (query_data * qd);
+
+void FreeQueryDocs (query_data * qd);
+
+int LoadCompressedText (query_data * qd, int max_mem);
+
+int GetDocNum (query_data * qd);
+
+float GetDocWeight (query_data * qd);
+
+long GetDocCompLength (query_data * qd);
+
+u_char *GetDocText (query_data * qd, unsigned long *len);
+
+DocEntry *GetDocChain (query_data * qd);
+
+int NextDoc (query_data * qd);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_optimiser.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_optimiser.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_optimiser.c	(revision 10506)
@@ -0,0 +1,1108 @@
+/**************************************************************************
+ *
+ * bool_optimiser -- optimise boolean parse tree
+ * Copyright (C) 1994,95  Tim Shimmin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:42  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:20  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1995/07/27  04:54:55  tes
+   * Committing optimiser before I add the code
+   * to find diff-nodes in any kind of tree.
+   *
+   * Revision 1.3  1994/10/20  00:02:55  tes
+   * Fixed bug with bool_optimiser:
+   *   - it couldn't handle "false | false"
+   *   - it couldn't handle "true & true"
+   * These would collapse into an empty list and cause an error.
+   *
+   * Revision 1.2  1994/10/18  06:11:02  tes
+   * The boolean optimiser seems to be modifying the parse tree
+   * like it is supposed to.
+   * Paragraph ranking now works without any text files if required to.
+   *
+   * Revision 1.1  1994/10/12  01:15:28  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "bool_tree.h"
+#include "term_lists.h"
+#include "messages.h"
+
+typedef int (*CompFunc) (const void *, const void *);
+typedef void (*TreeFunc) (bool_tree_node *);
+
+/* --- routines --- */
+static void PermeateNots (bool_tree_node * tree);
+static void DoubleNeg (bool_tree_node * not_tree);
+static void AndDeMorgan (bool_tree_node * not_tree);
+static void OrDeMorgan (bool_tree_node * not_tree);
+static int AndDistribute (bool_tree_node * tree);
+static void DNF_Distribute (bool_tree_node * tree);
+static void ReplaceWithChildren (bool_tree_node * tree);
+static void CollapseTree (bool_tree_node * tree);
+static void AndTrueFalse (bool_tree_node * and_tree);
+static void OrTrueFalse (bool_tree_node * or_tree);
+static void TF_Idempotent (bool_tree_node * tree);
+static void AndNotToDiff (bool_tree_node * and_tree, TreeFunc recurs_func);
+static void DiffDNF (bool_tree_node * or_node);
+static void DiffTree (bool_tree_node * tree);
+static void AndSort (bool_tree_node * and_tree, TermList * tl, CompFunc comp);
+static void AndOrSort (bool_tree_node * tree, TermList * tl);
+static void AndSortDNF (bool_tree_node * or_node, TermList * tl);
+static void MarkOrTerms (bool_tree_node * tree, TermList * tl);
+static int calc_sum_ft (bool_tree_node * term_tree, TermList * tl);
+static int AndOrSort_comp (const void *A, const void *B);
+static int AndSort_comp (const void *A, const void *B);
+
+/* =========================================================================
+ * Function: OptimiseBoolTree
+ * Description: 
+ *      For case 2:
+ *        Do three major steps:
+ *        (i) put into standard form
+ *            -> put into DNF (disjunctive normal form - or of ands)
+ *            Use DeMorgan's, Double-negative, Distributive rules
+ *        (ii) simplify
+ *             apply idempotency rules
+ *        (iii) ameliorate
+ *              convert &! to diff nodes, order terms by frequency,...
+ *     Could also do the matching idempotency laws i.e. ...
+ *     (A | A), (A | !A), (A & !A), (A & A), (A & (A | B)), (A | (A & B)) 
+ *     Job for future.... ;-) 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+OptimiseBoolTree (bool_tree_node * parse_tree, TermList * tl, int type)
+{
+  switch (type)
+    {
+    case 1:
+      /* --- sorts for and of or-terms --- */
+      PermeateNots (parse_tree);
+      TF_Idempotent (parse_tree);
+      CollapseTree (parse_tree);
+      DiffTree (parse_tree);
+      MarkOrTerms (parse_tree, tl);
+      AndOrSort (parse_tree, tl);
+      break;
+    case 2:
+      /* --- put into DNF --- */
+      PermeateNots (parse_tree);
+      TF_Idempotent (parse_tree);
+      DNF_Distribute (parse_tree);
+      CollapseTree (parse_tree);
+      AndSortDNF (parse_tree, tl);
+      DiffDNF (parse_tree);
+      break;
+    default:
+      /* --- do nothing --- */
+      break;
+    }				/*switch */
+}				/*OptimiseBoolTree */
+
+/* =========================================================================
+ * Function: DoubleNeg
+ * Description: 
+ *      !(!(a) = a
+ *      Assumes binary tree.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+static void
+DoubleNeg (bool_tree_node * not_tree)
+{
+  bool_tree_node *child = BOOL_CHILD (not_tree);
+  bool_tree_node *a = BOOL_CHILD (child);
+  bool_tree_node *sibling = BOOL_SIBLING (not_tree);
+
+  /* copy a into not tree */
+  bcopy (a, not_tree, sizeof (bool_tree_node));
+
+  BOOL_SIBLING (not_tree) = sibling;
+
+  Xfree (child);
+  Xfree (a);
+
+}
+
+/* =========================================================================
+ * Function: AndDeMorgan
+ * Description: 
+ *      DeMorgan's rule for 'not' of an 'and'  i.e. !(a & b) <=> (!a) | (!b)
+ *      Assumes Binary Tree
+ * Input: 
+ *      not of and tree
+ * Output: 
+ *      or of not trees
+ * ========================================================================= */
+
+static void
+AndDeMorgan (bool_tree_node * not_tree)
+{
+  bool_tree_node *child = BOOL_CHILD (not_tree);
+  bool_tree_node *a = BOOL_CHILD (child);
+  bool_tree_node *b = BOOL_SIBLING (a);
+  bool_tree_node *new_not = NULL;
+
+  /* change 'not' to 'or' */
+  BOOL_TAG (not_tree) = N_or;
+
+  /* change 'and' to 'not' */
+  BOOL_TAG (child) = N_not;
+
+  /* 'a' no longer has a sibling */
+  BOOL_SIBLING (a) = NULL;
+
+  /* 'a's old sibling is now a child of a new not */
+  new_not = CreateBoolTreeNode (N_not, b, NULL);
+  BOOL_SIBLING (child) = new_not;
+}
+
+/* =========================================================================
+ * Function: OrDeMorgan
+ * Description: 
+ *      DeMorgan's rule for 'not' of an 'or' i.e. !(a | b) <=> (!a) & (!b)
+ *      Assumes Binary Tree
+ * Input: 
+ *      not of and tree
+ * Output: 
+ *      or of not trees
+ * ========================================================================= */
+
+static void
+OrDeMorgan (bool_tree_node * not_tree)
+{
+  bool_tree_node *child = BOOL_CHILD (not_tree);
+  bool_tree_node *a = BOOL_CHILD (child);
+  bool_tree_node *b = BOOL_SIBLING (a);
+  bool_tree_node *new_not = NULL;
+
+  /* change 'not' to 'and' */
+  BOOL_TAG (not_tree) = N_and;
+
+  /* change 'or' to 'not' */
+  BOOL_TAG (child) = N_not;
+
+  /* 'a' no longer has a sibling */
+  BOOL_SIBLING (a) = NULL;
+
+  /* 'a's old sibling is now a child of a new not */
+  new_not = CreateBoolTreeNode (N_not, b, NULL);
+  BOOL_SIBLING (child) = new_not;
+}
+
+/* =========================================================================
+ * Function: PermeateNots
+ * Description: 
+ *      Use DeMorgan's and Double-negative
+ *      Assumes tree in binary form (i.e. No ands/ors collapsed)
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+PermeateNots (bool_tree_node * tree)
+{
+  if (!tree)
+    return;
+
+  if (BOOL_TAG (tree) == N_not)
+    {
+      switch (BOOL_TAG (BOOL_CHILD (tree)))
+	{
+	case N_not:
+	  DoubleNeg (tree);
+/** NOTE: I do not go on to do the children **/
+	  /* I permeate the nots on the tree here & leave it at that */
+	  /* In this case I do not know what type 'tree' will end up */
+	  PermeateNots (tree);
+	  return;
+	case N_and:
+	  AndDeMorgan (tree);
+	  break;
+	case N_or:
+	  OrDeMorgan (tree);
+	  break;
+	default:
+	  /* leave alone */
+	  break;
+	}
+    }
+
+  /* Permeate Nots for children */
+  if (BOOL_HAS_CHILD (tree))
+    {
+      PermeateNots (BOOL_CHILD (tree));
+      PermeateNots (BOOL_SIBLING (BOOL_CHILD (tree)));
+    }
+
+}
+
+/* =========================================================================
+ * Function: DNF_Distribute
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+
+#define ITER_LIMIT 500		/* if reach limit then probably in trouble */
+
+static void
+DNF_Distribute (bool_tree_node * tree)
+{
+  int i = 0;
+
+  /* multiple passes until no change */
+  /* not very smart :-( */
+  while (1)
+    {
+      if (AndDistribute (tree) == 0)
+	return;
+      if (i == ITER_LIMIT)
+	FatalError (1, "DNF infinite loop");
+      i++;
+    }				/*while */
+
+}
+
+/* =========================================================================
+ * Function: AndDistribute
+ * Description: 
+ *      (a | b) & A <=> (a & A) | (b & A)
+ * Input: 
+ *      binary tree of "AND" , "OR"s.
+ * Output: 
+ *      return 1 if changed the tree
+ *      return 0 if there was NO change (no distributive rule to apply)
+ * ========================================================================= */
+
+static int
+AndDistribute (bool_tree_node * tree)
+{
+  if (!tree)
+    return 0;
+
+  if (BOOL_TAG (tree) != N_and)
+    {
+      /* try the children if got some */
+      if (BOOL_TAG (tree) == N_or)
+	{
+	  bool_tree_node *left_child = BOOL_CHILD (tree);
+	  int left = AndDistribute (left_child);
+	  int right = AndDistribute (BOOL_SIBLING (left_child));
+	  return (left || right);
+	}
+
+      /* no children, then no change */
+      return 0;
+    }
+
+  /* AND case */
+  {
+    /* we have to check the children to see if can distribute */
+    bool_tree_node *left_child = BOOL_CHILD (tree);
+    bool_tree_node *right_child = BOOL_SIBLING (left_child);
+    int swap = 0;
+
+    /* If "or" on the right side then do a swap */
+    /* This is done for code simplicity */
+    if (BOOL_TAG (right_child) == N_or)
+      {
+	/* do a swap */
+	bool_tree_node *temp;
+	temp = right_child;
+	right_child = left_child;
+	left_child = temp;
+
+	BOOL_SIBLING (left_child) = right_child;
+	BOOL_SIBLING (right_child) = NULL;
+	BOOL_CHILD (tree) = left_child;
+
+	swap = 1;
+      }
+
+    /* do the actual distribution */
+    if (swap || BOOL_TAG (left_child) == N_or)
+      {
+	bool_tree_node *A = right_child;
+	bool_tree_node *A_copy = CopyBoolTree (A);
+	bool_tree_node *a = BOOL_CHILD (left_child);
+	bool_tree_node *b = BOOL_SIBLING (a);
+
+	/* then can distribute away ... */
+	BOOL_TAG (tree) = N_or;
+	BOOL_TAG (left_child) = N_and;
+	BOOL_SIBLING (left_child) = CreateBoolTreeNode (N_and, b, A);
+	BOOL_SIBLING (a) = A_copy;
+
+	AndDistribute (tree);
+	return 1;
+      }
+
+    /* if "and" of something other than "or" s then try the children */
+    {
+      int left = AndDistribute (left_child);
+      int right = AndDistribute (right_child);
+      return (left || right);
+    }
+  }				/* AND case */
+
+}				/*AndDistribute */
+
+/* =========================================================================
+ * Function: CollapseTree
+ * Description: 
+ *      Collapse "and" and "or"s.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+CollapseTree (bool_tree_node * tree)
+{
+  if (!tree)
+    return;
+
+  if ((BOOL_TAG (tree) == N_and) || (BOOL_TAG (tree) == N_or))
+    {
+      bool_tree_node *child = BOOL_CHILD (tree);
+      while (child)
+	{
+	  while (BOOL_TAG (child) == BOOL_TAG (tree))
+	    {
+	      ReplaceWithChildren (child);
+	    }
+	  CollapseTree (child);
+	  child = BOOL_SIBLING (child);
+	}
+    }
+
+  /* assume "not"s permeated */
+  return;
+}
+
+/* =========================================================================
+ * Function: ReplaceWithChildren
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+ReplaceWithChildren (bool_tree_node * tree)
+{
+  bool_tree_node *next = BOOL_SIBLING (tree);
+  bool_tree_node *child = BOOL_CHILD (tree);
+  bool_tree_node *last = LastBoolSibling (child);
+
+  bcopy ((char *) child, (char *) tree, sizeof (bool_tree_node));
+  Xfree (child);
+  BOOL_SIBLING (last) = next;
+
+}
+
+/* =========================================================================
+ * Function: TF_Idempotent
+ * Description: 
+ *      Applies Idempotency laws which refer to True or False (hence "TF")
+ *      uses the true or false idempotent rules
+ * Input: 
+ *      operates on n-ary trees (not restricted to binary)
+ * Output: 
+ * ========================================================================= */
+
+static void
+TF_Idempotent (bool_tree_node * tree)
+{
+  bool_tree_node *child = NULL;
+
+  while (tree)
+    {
+      if (BOOL_HAS_CHILD (tree))
+	{
+	  child = BOOL_CHILD (tree);
+	  TF_Idempotent (child);
+	}
+
+      /* --- process node --- */
+      switch (BOOL_TAG (tree))
+	{
+	case N_not:
+	  child = BOOL_CHILD (tree);
+
+	  /* if true then falsify */
+	  if (BOOL_TAG (child) == N_all)
+	    {
+	      BOOL_TAG (tree) = N_none;
+	      BOOL_CHILD (tree) = NULL;
+	      Xfree (child);
+	      break;
+	    }
+
+	  /* if false then trueify */
+	  if (BOOL_TAG (child) == N_none)
+	    {
+	      BOOL_TAG (tree) = N_all;
+	      BOOL_CHILD (tree) = NULL;
+	      Xfree (child);
+	      break;
+	    }
+
+	  break;
+	case N_and:
+	  AndTrueFalse (tree);
+	  break;
+	case N_or:
+	  OrTrueFalse (tree);
+	  break;
+
+	default:
+	  /* do nothing */
+	  break;
+	}			/*switch */
+
+      tree = BOOL_SIBLING (tree);
+    }				/*while */
+}				/*TF_Idempotent */
+
+/* =========================================================================
+ * Function: AndTrueFalse
+ * Description: 
+ *      If any "false" then falsify whole tree 
+ *      If any "true" then delete them
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+AndTrueFalse (bool_tree_node * and_tree)
+{
+  bool_tree_node *child = BOOL_CHILD (and_tree);
+
+  bool_tree_node *prev = NULL;
+
+  while (child)
+    {
+      if (BOOL_TAG (child) == N_none)
+	{
+	  FreeBoolTree (&(BOOL_CHILD (and_tree)));
+	  BOOL_TAG (and_tree) = N_none;
+	  return;
+	}
+
+      if (BOOL_TAG (child) == N_all)
+	{
+	  bool_tree_node *sibling = BOOL_SIBLING (child);
+
+	  /* --- link over child --- */
+	  if (!prev)
+	    {
+	      BOOL_CHILD (and_tree) = sibling;
+	    }
+	  else
+	    {
+	      BOOL_SIBLING (prev) = sibling;
+	    }
+
+	  Xfree (child);
+	  child = sibling;
+	}
+      else
+	{
+	  prev = child;
+	  child = BOOL_SIBLING (child);
+	}
+    }				/*while */
+
+  child = BOOL_CHILD (and_tree);
+
+  /* if no children ... */
+  /* => all have been true */
+  if (!child)
+    {
+      BOOL_TAG (and_tree) = N_all;
+      return;
+    }
+
+  /* If only one child ... */
+  if (!BOOL_SIBLING (child))
+    {
+      /* replace the parent with child - move it up */
+      bool_tree_node *save_sibling = BOOL_SIBLING (and_tree);
+      bcopy ((char *) child, (char *) and_tree, sizeof (bool_tree_node));
+      BOOL_SIBLING (and_tree) = save_sibling;
+      Xfree (child);
+    }
+
+}				/*AndTrueFalse */
+
+/* =========================================================================
+ * Function: OrTrueFalse
+ * Description: 
+ *      If any "true" then trueify whole tree 
+ *      If any "false" then delete them 
+ *      ***** NOTE: This is a reflection of AndTrueFalse *****
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+OrTrueFalse (bool_tree_node * or_tree)
+{
+  bool_tree_node *child = BOOL_CHILD (or_tree);
+
+  bool_tree_node *prev = NULL;
+
+  while (child)
+    {
+      if (BOOL_TAG (child) == N_all)
+	{
+	  FreeBoolTree (&(BOOL_CHILD (or_tree)));
+	  BOOL_TAG (or_tree) = N_all;
+	  return;
+	}
+
+      if (BOOL_TAG (child) == N_none)
+	{
+	  bool_tree_node *sibling = BOOL_SIBLING (child);
+	  if (!prev)
+	    {
+	      BOOL_CHILD (or_tree) = sibling;
+	    }
+	  else
+	    {
+	      BOOL_SIBLING (prev) = sibling;
+	    }
+	  Xfree (child);
+	  child = sibling;
+
+	}
+      else
+	{
+	  prev = child;
+	  child = BOOL_SIBLING (child);
+	}
+    }				/*while */
+
+  child = BOOL_CHILD (or_tree);
+
+  /* if no children ... */
+  /* => all have been false */
+  if (!child)
+    {
+      BOOL_TAG (or_tree) = N_none;
+      return;
+    }
+
+  /* If only one child ... */
+  if (!BOOL_SIBLING (child))
+    {
+      /* replace the parent with child - move it up */
+      bool_tree_node *save_sibling = BOOL_SIBLING (or_tree);
+      bcopy ((char *) child, (char *) or_tree, sizeof (bool_tree_node));
+      BOOL_SIBLING (or_tree) = save_sibling;
+      Xfree (child);
+    }
+
+}				/*AndTrueFalse */
+
+/* =========================================================================
+ * Function: AndNotToDiff
+ * Description: 
+ *      Convert an "And" tree with possibly some negated terms into
+ *      a "And - neg-terms". 
+ * Input: 
+ *      Expects "And" of only literals - as tree should be in DNF form.
+ *      This means that no recursion is necessary.
+ * Output: 
+ * ========================================================================= */
+
+static void
+AndNotToDiff (bool_tree_node * and_tree, TreeFunc recurs_func)
+{
+
+  /* -------------------------------------------------- */
+  /* --- Divide the children up into positive and negative literals --- */
+  /* Preserves ordering of children */
+  bool_tree_node *pos = NULL;
+  bool_tree_node *neg = NULL;
+  bool_tree_node *last_pos = NULL;
+  bool_tree_node *last_neg = NULL;
+
+  bool_tree_node *child = BOOL_CHILD (and_tree);
+  while (child)
+    {
+      bool_tree_node *next = BOOL_SIBLING (child);
+      if (BOOL_TAG (child) == N_not)
+	{
+	  /* add to end of neg list */
+	  if (!neg)
+	    neg = child;
+	  else
+	    BOOL_SIBLING (last_neg) = child;
+	  last_neg = child;
+	}
+      else
+	{
+	  /* add to end of pos list */
+	  if (!pos)
+	    pos = child;
+	  else
+	    BOOL_SIBLING (last_pos) = child;
+	  last_pos = child;
+	}
+      child = next;
+    }				/*while */
+  if (last_pos)
+    BOOL_SIBLING (last_pos) = NULL;
+  if (last_neg)
+    BOOL_SIBLING (last_neg) = NULL;
+  /* -------------------------------------------------- */
+
+  if (!neg)			/* no negtives => no subtraction */
+    {
+      /* fix up parent's child link */
+      BOOL_CHILD (and_tree) = pos;
+      return;
+    }
+
+  if (!pos)			/* no positives = all negatives */
+    {
+      /* Choose one of the negs for the left-hand-side of the subtraction */
+      /* In particular, choose the first */
+      pos = neg;
+      neg = BOOL_SIBLING (neg);
+      BOOL_SIBLING (pos) = NULL;
+    }
+
+  /* Get rid of all '!' from not nodes */
+  /* Make a list out of the children */
+  {
+    bool_tree_node *n = neg;
+    bool_tree_node *next = NULL;
+
+    neg = BOOL_CHILD (neg);
+    while (n)
+      {
+	bool_tree_node *c = BOOL_CHILD (n);
+	next = BOOL_SIBLING (n);
+	Xfree (n);
+	if (next)
+	  BOOL_SIBLING (c) = BOOL_CHILD (next);
+	n = next;
+      }
+  }
+
+  /* --- restructure the tree with "and" and "diff" --- */
+  BOOL_TAG (and_tree) = N_diff;
+  if (!BOOL_SIBLING (pos))	/* i.e. only one pos */
+    {
+      /* (A & !B & !C & !D & ...) ==> A - (B,C,D,...) */
+
+      BOOL_CHILD (and_tree) = pos;
+      BOOL_SIBLING (pos) = neg;
+    }
+  else
+    {
+      /* (A & !C & B & !D & ...) ==> (A & B & ....) - (C, D, ...) */
+
+      bool_tree_node *n = CreateBoolNode (N_and);
+      BOOL_CHILD (and_tree) = n;
+      BOOL_CHILD (n) = pos;
+      BOOL_SIBLING (n) = neg;
+    }				/*if */
+
+  if (recurs_func)
+    {
+      recurs_func (BOOL_CHILD (and_tree));
+    }
+
+}				/*AndNotToDiff */
+
+/* =========================================================================
+ * Function: DiffTree
+ * Description: 
+ *      Applies "AndNotToNeg" to each conjunct.
+ *      Unlike DiffDNF, this routine will search throughout the tree for
+ *      "and"-nodes. It will call AndNotToNeg with this as its recursive 
+ *      routine.
+ * Date: 27/July/95
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+DiffTree (bool_tree_node * tree)
+{
+  bool_tree_node *t = tree;
+
+  while (t)
+    {
+      if (BOOL_TAG (t) == N_and)
+	{
+	  AndNotToDiff (t, DiffTree);
+	}
+      t = BOOL_SIBLING (t);
+    }				/*while */
+
+}				/*DiffTree */
+
+/* =========================================================================
+ * Function: DiffDNF
+ * Description: 
+ *      Applies "AndNotToNeg" to each conjunct.
+ * Input: 
+ *      A DNF tree
+ * Output: 
+ *      A tree possibly with some diffs in it.
+ * ========================================================================= */
+
+static void
+DiffDNF (bool_tree_node * DNF_tree)
+{
+
+  if (BOOL_TAG (DNF_tree) == N_or)
+    {
+      bool_tree_node *child = BOOL_CHILD (DNF_tree);
+
+      while (child)
+	{
+	  if (BOOL_TAG (child) == N_and)
+	    {
+	      AndNotToDiff (child, NULL);
+	    }
+	  child = BOOL_SIBLING (child);
+	}
+    }
+  else if (BOOL_TAG (DNF_tree) == N_and)
+    {
+      AndNotToDiff (DNF_tree, NULL);
+    }
+}
+
+/* =========================================================================
+ * Function: AndSort_comp 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+/* Module variable, "term_list",  used as parameter for comparison function */
+/* The comparison function only allows certain fixed parameters */
+static TermList *term_list;
+
+static int
+AndSort_comp (const void *A, const void *B)
+{
+  const bool_tree_node *const *a = A;
+  const bool_tree_node *const *b = B;
+
+  if (BOOL_TAG (*a) == N_term && BOOL_TAG (*b) == N_term)
+    {
+      /* look up in term list */
+      int a_doc_count = GetNthWE (term_list, BOOL_TERM (*a))->doc_count;
+      int b_doc_count = GetNthWE (term_list, BOOL_TERM (*b))->doc_count;
+
+      return a_doc_count - b_doc_count;
+    }
+
+  if (BOOL_TAG (*a) == N_term && BOOL_TAG (*b) != N_term)
+    return -1;
+
+  if (BOOL_TAG (*a) != N_term && BOOL_TAG (*b) == N_term)
+    return 1;
+
+  return 0;
+}				/*AndSort_comp */
+
+/* =========================================================================
+ * Function: AndSort
+ * Description: 
+ *      Sort the list of nodes by increasing doc_count 
+ *      Using some Neil Sharman code - pretty straight forward.
+ *      Note: not-terms are sent to the end of the list
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+AndSort (bool_tree_node * and_tree, TermList * tl, CompFunc comp)
+{
+  bool_tree_node **list = NULL;
+  bool_tree_node *child = NULL;
+  int count = 0;
+  int i = 0;
+
+  if (BOOL_TAG (and_tree) != N_and)
+    return;
+
+  /* --- Convert linked list into an array for sorting --- */
+  child = BOOL_CHILD (and_tree);
+  count = 0;
+  while (child)
+    {
+      count++;
+      child = BOOL_SIBLING (child);
+    }
+
+  if (!(list = Xmalloc (sizeof (bool_tree_node *) * count)))
+    return;
+
+  child = BOOL_CHILD (and_tree);
+  for (i = 0; i < count; i++)
+    {
+      list[i] = child;
+      child = BOOL_SIBLING (child);
+    }
+  /* ----------------------------------------------------- */
+
+  term_list = tl;
+  qsort (list, count, sizeof (bool_tree_node *), comp);
+
+  /* --- Convert array back into linked list --- */
+  for (i = 0; i < count - 1; i++)
+    BOOL_SIBLING (list[i]) = list[i + 1];
+  BOOL_SIBLING (list[count - 1]) = NULL;
+  BOOL_CHILD (and_tree) = list[0];
+  Xfree (list);
+  /* ----------------------------------------------------- */
+
+}				/*AndSort */
+
+/* =========================================================================
+ * Function: AndSortDNF
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+
+static void
+AndSortDNF (bool_tree_node * DNF_tree, TermList * tl)
+{
+
+  if (BOOL_TAG (DNF_tree) == N_or)
+    {
+      bool_tree_node *child = BOOL_CHILD (DNF_tree);
+
+      while (child)
+	{
+	  if (BOOL_TAG (child) == N_and)
+	    {
+	      AndSort (child, tl, AndSort_comp);
+	    }
+	  child = BOOL_SIBLING (child);
+	}
+    }
+  else if (BOOL_TAG (DNF_tree) == N_and)
+    {
+      AndSort (DNF_tree, tl, AndSort_comp);
+    }
+}
+
+/* =========================================================================
+ * Function: MarkOrTerms
+ * Description: 
+ *      Mark or-nodes whose children are all terms.
+ *      Also store the sum of the ft's of these nodes.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+MarkOrTerms (bool_tree_node * tree, TermList * tl)
+{
+  if (BOOL_TAG (tree) == N_or)
+    {
+      int found_non_term = 0;
+      bool_tree_node *child = BOOL_CHILD (tree);
+
+      /* --- check to see if got all terms --- */
+      while (child)
+	{
+	  if (BOOL_TAG (child) != N_term)
+	    {
+	      found_non_term = 1;
+	    }
+	  if (BOOL_HAS_CHILD (tree))
+	    {
+	      MarkOrTerms (child, tl);
+	    }
+	  child = BOOL_SIBLING (child);
+	}			/*while */
+
+      if (!found_non_term)
+	{
+	  /* Must have all terms for the OR node */
+	  /* So change its tag and calculate its sum */
+	  BOOL_TAG (tree) = N_or_terms;
+	  BOOL_SUM_FT (tree) = calc_sum_ft (tree, tl);
+	}			/*if */
+      /* ------------------------------------- */
+
+    }				/*if OR node */
+
+  else if (BOOL_HAS_CHILD (tree))
+    {
+      bool_tree_node *child = BOOL_CHILD (tree);
+      while (child)
+	{
+	  MarkOrTerms (child, tl);
+	  child = BOOL_SIBLING (child);
+	}
+    }
+
+}				/*MarkOrTerms */
+
+/* =========================================================================
+ * Function: calc_sum_ft
+ * Description: 
+ *      Sums up the ft's of all the terms 
+ * Input: 
+ *      Assumes that the tree only contains terms in it 
+ * Output: 
+ *      the ft sum
+ * ========================================================================= */
+static int
+calc_sum_ft (bool_tree_node * term_tree, TermList * tl)
+{
+  int sum_ft = 0;
+  bool_tree_node *child = BOOL_CHILD (term_tree);
+  while (child)
+    {
+      sum_ft += GetNthWE (tl, BOOL_TERM (child))->doc_count;
+      child = BOOL_SIBLING (child);
+    }
+  return sum_ft;
+}
+
+/* =========================================================================
+ * Function: AndOrSort
+ * Description: 
+ *      This is like an AndSort of just terms. 
+ *      The difference is that we are now also 
+ *      considering sorting with <or of terms> by using the sum of f_t's.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+static void
+AndOrSort (bool_tree_node * tree, TermList * tl)
+{
+  if (BOOL_HAS_CHILD (tree))
+    {
+
+      if (BOOL_TAG (tree) == N_and)
+	{
+	  AndSort (tree, tl, AndOrSort_comp);
+	}
+
+      /* Check out any children down the tree */
+      /* Probably a waste of time */
+      {
+	bool_tree_node *child = BOOL_CHILD (tree);
+	while (child)
+	  {
+	    AndOrSort (child, tl);
+	    child = BOOL_SIBLING (child);
+	  }
+      }				/*do the tree */
+
+    }				/*if has children */
+}				/*AndOrSort */
+
+/* =========================================================================
+ * Function: AndOrSort_comp
+ * Description: 
+ *      Comparison function used to order "term"s and "or_terms"s.
+ *      It's purpose is to be used by a sort routine.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+static int
+AndOrSort_comp (const void *A, const void *B)
+{
+  const bool_tree_node *const *a = A;
+  const bool_tree_node *const *b = B;
+
+  if (BOOL_TAG (*a) == N_term && BOOL_TAG (*b) == N_term)
+    {
+      /* look up in term list */
+      int a_doc_count = GetNthWE (term_list, BOOL_TERM (*a))->doc_count;
+      int b_doc_count = GetNthWE (term_list, BOOL_TERM (*b))->doc_count;
+
+      return a_doc_count - b_doc_count;
+    }
+
+  if (BOOL_TAG (*a) == N_term && BOOL_TAG (*b) == N_or_terms)
+    {
+      /* look up in term list */
+      int a_doc_count = GetNthWE (term_list, BOOL_TERM (*a))->doc_count;
+      int b_doc_count = BOOL_SUM_FT (*b);
+
+      return a_doc_count - b_doc_count;
+    }
+
+  if (BOOL_TAG (*a) == N_or_terms && BOOL_TAG (*b) == N_term)
+    {
+      /* look up in term list */
+      int a_doc_count = BOOL_SUM_FT (*a);
+      int b_doc_count = GetNthWE (term_list, BOOL_TERM (*b))->doc_count;
+
+      return a_doc_count - b_doc_count;
+    }
+
+  if (BOOL_TAG (*a) == N_or_terms && BOOL_TAG (*b) == N_or_terms)
+    {
+      /* look up in term list */
+      int a_doc_count = BOOL_SUM_FT (*a);
+      int b_doc_count = BOOL_SUM_FT (*b);
+
+      return a_doc_count - b_doc_count;
+    }
+
+  if ((BOOL_TAG (*a) == N_term || BOOL_TAG (*a) == N_or_terms) &&
+      (BOOL_TAG (*b) != N_term && BOOL_TAG (*b) != N_or_terms))
+    return -1;
+
+  if ((BOOL_TAG (*a) != N_term && BOOL_TAG (*a) != N_or_terms) &&
+      (BOOL_TAG (*b) == N_term || BOOL_TAG (*b) == N_or_terms))
+    return 1;
+
+  return 0;
+}				/*AndOrSort_comp */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_optimiser.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_optimiser.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_optimiser.h	(revision 10506)
@@ -0,0 +1,62 @@
+/**************************************************************************
+ *
+ * bool_optimiser -- optimise boolean parse tree
+ * Copyright (C) 1994  Tim Shimmin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:42  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:23  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1995/03/14  05:15:21  tes
+   * Updated the boolean query optimiser to do different types of optimisation.
+   * A query environment variable "optimise_type" specifies which one is to be
+   * used. Type 1 is the new one which is faster than 2.
+   *
+   * Revision 1.1  1994/10/20  03:56:32  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/10/18  06:11:03  tes
+   * The boolean optimiser seems to be modifying the parse tree
+   * like it is supposed to.
+   * Paragraph ranking now works without any text files if required to.
+   *
+   * Revision 1.1  1994/10/12  01:15:29  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+#ifndef BOOL_OPTIMISER_H
+#define BOOL_OPTIMISER_H
+
+#include "bool_tree.h"
+#include "term_lists.h"
+
+void OptimiseBoolTree (bool_tree_node * parse_tree, TermList * term_list, int type);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_parser.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_parser.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_parser.c	(revision 10506)
@@ -0,0 +1,1196 @@
+
+/*  A Bison parser, made from bool_parser.y
+ by  GNU Bison version 1.27
+  */
+
+#define YYBISON 1  /* Identify Bison output.  */
+
+#define	TERM	257
+
+#line 24 "bool_parser.y"
+
+ 
+#include "sysfuncs.h"
+
+#include "messages.h"
+ 
+#include "memlib.h"
+#include "words.h"
+#include "stemmer.h"
+#include "term_lists.h"
+#include "bool_tree.h"
+/* [RPAP - Jan 97: Stem Index Change] */
+#include "backend.h"     /* for stemmed_dict def */
+#include "stem_search.h"
+
+#include "query_term_list.h"  /* [RPAP - Feb 97: Term Frequency] */
+
+/* --- routines --- */
+static int query_lex();
+static int yyerror(char *);
+#define yylex() query_lex(&ch_buf, end_buf)
+ 
+/* --- module variables --- */
+static char *ch_buf; /* ptr to the character query line buffer */
+static char *end_buf; /* ptr to the last character of the line buffer */
+static bool_tree_node *tree_base = NULL;
+static TermList **term_list;
+static int stemmer_num;
+static int stem_method;
+/* [RPAP - Jan 97: Stem Index Change] */
+stemmed_dict *p__sd;
+static int indexed;
+/* [RPAP - Feb 97: Term Frequency] */
+static QueryTermList **query_term_list;
+static int word_num;
+static u_long count;
+static u_long doc_count;
+static u_long invf_ptr;
+static u_long invf_len;
+
+#line 66 "bool_parser.y"
+typedef union {
+  char *text;
+  bool_tree_node *node;
+} YYSTYPE;
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define	YYFINAL		20
+#define	YYFLAG		-32768
+#define	YYNTBASE	11
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 257 ? yytranslate[x] : 16)
+
+static const char yytranslate[] = {     0,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     8,     2,     2,     2,     2,     9,     2,     4,
+     5,     6,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     7,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,    10,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     1,     3
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = {     0,
+     0,     2,     4,     8,    10,    12,    14,    17,    21,    24,
+    26,    30
+};
+
+static const short yyrhs[] = {    15,
+     0,     3,     0,     4,    15,     5,     0,     6,     0,     7,
+     0,    12,     0,     8,    13,     0,    14,     9,    13,     0,
+    14,    13,     0,    13,     0,    15,    10,    14,     0,    14,
+     0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+    76,    80,    81,    82,    83,    86,    87,    90,    91,    92,
+    95,    96
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = {   "$","error","$undefined.","TERM","'('",
+"')'","'*'","'_'","'!'","'&'","'|'","query","term","not","and","or", NULL
+};
+#endif
+
+static const short yyr1[] = {     0,
+    11,    12,    12,    12,    12,    13,    13,    14,    14,    14,
+    15,    15
+};
+
+static const short yyr2[] = {     0,
+     1,     1,     3,     1,     1,     1,     2,     3,     2,     1,
+     3,     1
+};
+
+static const short yydefact[] = {     0,
+     2,     0,     4,     5,     0,     6,    10,    12,     1,     0,
+     7,     0,     9,     0,     3,     8,    11,     0,     0,     0
+};
+
+static const short yydefgoto[] = {    18,
+     6,     7,     8,     9
+};
+
+static const short yypact[] = {    10,
+-32768,    10,-32768,-32768,    10,-32768,-32768,     2,    -9,    14,
+-32768,    10,-32768,    10,-32768,-32768,     2,     4,    15,-32768
+};
+
+static const short yypgoto[] = {-32768,
+-32768,    -5,   -12,    18
+};
+
+
+#define	YYLAST		24
+
+
+static const short yytable[] = {    11,
+    14,    17,    13,    19,     1,     2,    16,     3,     4,     5,
+    12,    13,     1,     2,    20,     3,     4,     5,    15,    10,
+     0,     0,     0,    14
+};
+
+static const short yycheck[] = {     5,
+    10,    14,     8,     0,     3,     4,    12,     6,     7,     8,
+     9,    17,     3,     4,     0,     6,     7,     8,     5,     2,
+    -1,    -1,    -1,    10
+};
+/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
+#line 3 "/usr/lib/bison.simple"
+/* This file comes from bison-1.27.  */
+
+/* Skeleton output parser for bison,
+   Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* This is the parser code that is written into each bison parser
+  when the %semantic_parser declaration is not specified in the grammar.
+  It was written by Richard Stallman by simplifying the hairy parser
+  used when %semantic_parser is specified.  */
+
+#ifndef YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C.  */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C.  */
+/* This used to test MSDOS, but that is a bad idea
+   since that symbol is in the user namespace.  */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+	 instead, just don't use alloca.  */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+   So I turned it off.   rms, 2 May 1997.  */
+/* #include <malloc.h>  */
+ #pragma alloca
+#define YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
+		 and on HPUX 10.  Eventually we can turn this on.  */
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#ifdef YYSTACK_USE_ALLOCA
+#define YYSTACK_ALLOC alloca
+#else
+#define YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+   It is replaced by the list of actions, each action
+   as one case of the switch.  */
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		-2
+#define YYEOF		0
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT 	goto yyabortlab
+#define YYERROR		goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+   This remains here temporarily to ease the
+   transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+#define YYFAIL		goto yyerrlab
+#define YYRECOVERING()  (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    { yychar = (token), yylval = (value);			\
+      yychar1 = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    { yyerror ("syntax error: cannot back up"); YYERROR; }	\
+while (0)
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+#ifndef YYPURE
+#define YYLEX		yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int	yychar;			/*  the lookahead symbol		*/
+YYSTYPE	yylval;			/*  the semantic value of the		*/
+				/*  lookahead symbol			*/
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc;			/*  location data for the lookahead	*/
+				/*  symbol				*/
+#endif
+
+int yynerrs;			/*  number of parse errors so far       */
+#endif  /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug;			/*  nonzero means print parse trace	*/
+/* Since this is uninitialized, it does not stop multiple parsers
+   from coexisting.  */
+#endif
+
+/*  YYINITDEPTH indicates the initial size of the parser's stacks	*/
+
+#ifndef	YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/*  YYMAXDEPTH is the maximum size the stacks can grow to
+    (effective only if the built-in stack extension method is used).  */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+
+/* Define __yy_memcpy.  Note that the size argument
+   should be passed with type unsigned int, because that is what the non-GCC
+   definitions require.  With GCC, __builtin_memcpy takes an arg
+   of type size_t, but it can handle unsigned int.  */
+
+#if __GNUC__ > 1		/* GNU C and GNU C++ define this.  */
+#define __yy_memcpy(TO,FROM,COUNT)	__builtin_memcpy(TO,FROM,COUNT)
+#else				/* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (to, from, count)
+     char *to;
+     char *from;
+     unsigned int count;
+{
+  register char *f = from;
+  register char *t = to;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (char *to, char *from, unsigned int count)
+{
+  register char *t = to;
+  register char *f = from;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#endif
+#endif
+
+
+#line 216 "/usr/lib/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+   into yyparse.  The argument should have type void *.
+   It should actually point to an object.
+   Grammar actions can access the variable by casting it
+   to the proper pointer type.  */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes.  */
+#ifdef __GNUC__
+#ifdef YYPARSE_PARAM
+int yyparse (void *);
+#else
+int yyparse (void);
+#endif
+#endif
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+     YYPARSE_PARAM_DECL
+{
+  register int yystate;
+  register int yyn;
+  register short *yyssp;
+  register YYSTYPE *yyvsp;
+  int yyerrstatus;	/*  number of tokens to shift before error messages enabled */
+  int yychar1 = 0;		/*  lookahead token as an internal (translated) token number */
+
+  short	yyssa[YYINITDEPTH];	/*  the state stack			*/
+  YYSTYPE yyvsa[YYINITDEPTH];	/*  the semantic value stack		*/
+
+  short *yyss = yyssa;		/*  refer to the stacks thru separate pointers */
+  YYSTYPE *yyvs = yyvsa;	/*  to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylsa[YYINITDEPTH];	/*  the location stack			*/
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+
+#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+#endif
+
+  int yystacksize = YYINITDEPTH;
+  int yyfree_stacks = 0;
+
+#ifdef YYPURE
+  int yychar;
+  YYSTYPE yylval;
+  int yynerrs;
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylloc;
+#endif
+#endif
+
+  YYSTYPE yyval;		/*  the variable used to return		*/
+				/*  semantic values from the action	*/
+				/*  routines				*/
+
+  int yylen;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Starting parse\n");
+#endif
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss - 1;
+  yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+  yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in  yystate  .  */
+/* In all cases, when you get here, the value and location stacks
+   have just been pushed. so pushing a state here evens the stacks.  */
+yynewstate:
+
+  *++yyssp = yystate;
+
+  if (yyssp >= yyss + yystacksize - 1)
+    {
+      /* Give user a chance to reallocate the stack */
+      /* Use copies of these so that the &'s don't force the real ones into memory. */
+      YYSTYPE *yyvs1 = yyvs;
+      short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+      YYLTYPE *yyls1 = yyls;
+#endif
+
+      /* Get the current used size of the three stacks, in elements.  */
+      int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      /* Each stack pointer address is followed by the size of
+	 the data in use in that stack, in bytes.  */
+#ifdef YYLSP_NEEDED
+      /* This used to be a conditional around just the two extra args,
+	 but that might be undefined if yyoverflow is a macro.  */
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yyls1, size * sizeof (*yylsp),
+		 &yystacksize);
+#else
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yystacksize);
+#endif
+
+      yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+      yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+      /* Extend the stack our own way.  */
+      if (yystacksize >= YYMAXDEPTH)
+	{
+	  yyerror("parser stack overflow");
+	  if (yyfree_stacks)
+	    {
+	      free (yyss);
+	      free (yyvs);
+#ifdef YYLSP_NEEDED
+	      free (yyls);
+#endif
+	    }
+	  return 2;
+	}
+      yystacksize *= 2;
+      if (yystacksize > YYMAXDEPTH)
+	yystacksize = YYMAXDEPTH;
+#ifndef YYSTACK_USE_ALLOCA
+      yyfree_stacks = 1;
+#endif
+      yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+      __yy_memcpy ((char *)yyss, (char *)yyss1,
+		   size * (unsigned int) sizeof (*yyssp));
+      yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+      __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+		   size * (unsigned int) sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+      yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+      __yy_memcpy ((char *)yyls, (char *)yyls1,
+		   size * (unsigned int) sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + size - 1;
+      yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+      yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+      if (yyssp >= yyss + yystacksize - 1)
+	YYABORT;
+    }
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+  goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* yychar is either YYEMPTY or YYEOF
+     or a valid token in external form.  */
+
+  if (yychar == YYEMPTY)
+    {
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Reading a token: ");
+#endif
+      yychar = YYLEX;
+    }
+
+  /* Convert token to internal form (in yychar1) for indexing tables with */
+
+  if (yychar <= 0)		/* This means end of input. */
+    {
+      yychar1 = 0;
+      yychar = YYEOF;		/* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Now at end of input.\n");
+#endif
+    }
+  else
+    {
+      yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+      if (yydebug)
+	{
+	  fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+	  /* Give the individual parser a way to print the precise meaning
+	     of a token, for further debugging info.  */
+#ifdef YYPRINT
+	  YYPRINT (stderr, yychar, yylval);
+#endif
+	  fprintf (stderr, ")\n");
+	}
+#endif
+    }
+
+  yyn += yychar1;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+    goto yydefault;
+
+  yyn = yytable[yyn];
+
+  /* yyn is what to do for this token type in this state.
+     Negative => reduce, -yyn is rule number.
+     Positive => shift, yyn is new state.
+       New state is final state => don't bother to shift,
+       just return success.
+     0, or most negative number => error.  */
+
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrlab;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  /* count tokens shifted since error; after three, turn off error status.  */
+  if (yyerrstatus) yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+/* Do the default action for the current state.  */
+yydefault:
+
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+
+/* Do a reduction.  yyn is the number of a rule to reduce with.  */
+yyreduce:
+  yylen = yyr2[yyn];
+  if (yylen > 0)
+    yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      int i;
+
+      fprintf (stderr, "Reducing via rule %d (line %d), ",
+	       yyn, yyrline[yyn]);
+
+      /* Print the symbols being reduced, and their result.  */
+      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+	fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+      fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+    }
+#endif
+
+
+  switch (yyn) {
+
+case 1:
+#line 76 "bool_parser.y"
+{ tree_base = yyvsp[0].node;;
+    break;}
+case 2:
+#line 80 "bool_parser.y"
+{ yyval.node = CreateBoolTermNode(term_list, yyvsp[0].text, 1, word_num, count, doc_count, invf_ptr, invf_len, stemmer_num); ;
+    break;}
+case 3:
+#line 81 "bool_parser.y"
+{ yyval.node = yyvsp[-1].node; ;
+    break;}
+case 4:
+#line 82 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_all, NULL, NULL); ;
+    break;}
+case 5:
+#line 83 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_none, NULL, NULL); ;
+    break;}
+case 7:
+#line 87 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_not, yyvsp[0].node, NULL); ;
+    break;}
+case 8:
+#line 90 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_and, yyvsp[-2].node, yyvsp[0].node); ;
+    break;}
+case 9:
+#line 91 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_and, yyvsp[-1].node, yyvsp[0].node); ;
+    break;}
+case 11:
+#line 95 "bool_parser.y"
+{ yyval.node = CreateBoolTreeNode(N_or, yyvsp[-2].node, yyvsp[0].node); ;
+    break;}
+}
+   /* the action file gets copied in in place of this dollarsign */
+#line 542 "/usr/lib/bison.simple"
+
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+  yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+  *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+  yylsp++;
+  if (yylen == 0)
+    {
+      yylsp->first_line = yylloc.first_line;
+      yylsp->first_column = yylloc.first_column;
+      yylsp->last_line = (yylsp-1)->last_line;
+      yylsp->last_column = (yylsp-1)->last_column;
+      yylsp->text = 0;
+    }
+  else
+    {
+      yylsp->last_line = (yylsp+yylen-1)->last_line;
+      yylsp->last_column = (yylsp+yylen-1)->last_column;
+    }
+#endif
+
+  /* Now "shift" the result of the reduction.
+     Determine what state that goes to,
+     based on the state we popped back to
+     and the rule number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTBASE];
+
+  goto yynewstate;
+
+yyerrlab:   /* here on detecting error */
+
+  if (! yyerrstatus)
+    /* If not already recovering from an error, report this error.  */
+    {
+      ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (yyn > YYFLAG && yyn < YYLAST)
+	{
+	  int size = 0;
+	  char *msg;
+	  int x, count;
+
+	  count = 0;
+	  /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */
+	  for (x = (yyn < 0 ? -yyn : 0);
+	       x < (sizeof(yytname) / sizeof(char *)); x++)
+	    if (yycheck[x + yyn] == x)
+	      size += strlen(yytname[x]) + 15, count++;
+	  msg = (char *) malloc(size + 15);
+	  if (msg != 0)
+	    {
+	      strcpy(msg, "parse error");
+
+	      if (count < 5)
+		{
+		  count = 0;
+		  for (x = (yyn < 0 ? -yyn : 0);
+		       x < (sizeof(yytname) / sizeof(char *)); x++)
+		    if (yycheck[x + yyn] == x)
+		      {
+			strcat(msg, count == 0 ? ", expecting `" : " or `");
+			strcat(msg, yytname[x]);
+			strcat(msg, "'");
+			count++;
+		      }
+		}
+	      yyerror(msg);
+	      free(msg);
+	    }
+	  else
+	    yyerror ("parse error; also virtual memory exceeded");
+	}
+      else
+#endif /* YYERROR_VERBOSE */
+	yyerror("parse error");
+    }
+
+  goto yyerrlab1;
+yyerrlab1:   /* here on error raised explicitly by an action */
+
+  if (yyerrstatus == 3)
+    {
+      /* if just tried and failed to reuse lookahead token after an error, discard it.  */
+
+      /* return failure if at end of input */
+      if (yychar == YYEOF)
+	YYABORT;
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+      yychar = YYEMPTY;
+    }
+
+  /* Else will try to reuse lookahead token
+     after shifting the error token.  */
+
+  yyerrstatus = 3;		/* Each real token shifted decrements this */
+
+  goto yyerrhandle;
+
+yyerrdefault:  /* current state does not do anything special for the error token. */
+
+#if 0
+  /* This is wrong; only states that explicitly want error tokens
+     should shift them.  */
+  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
+  if (yyn) goto yydefault;
+#endif
+
+yyerrpop:   /* pop the current state because it cannot handle the error token */
+
+  if (yyssp == yyss) YYABORT;
+  yyvsp--;
+  yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+  yylsp--;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "Error: state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+yyerrhandle:
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yyerrdefault;
+
+  yyn += YYTERROR;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+    goto yyerrdefault;
+
+  yyn = yytable[yyn];
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrpop;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrpop;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting error token, ");
+#endif
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  yystate = yyn;
+  goto yynewstate;
+
+ yyacceptlab:
+  /* YYACCEPT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 0;
+
+ yyabortlab:
+  /* YYABORT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 1;
+}
+#line 99 "bool_parser.y"
+
+ 
+/* Bison on one mips machine defined "const" to be nothing but
+   then did not undef it */
+#ifdef const
+#undef const
+#endif
+
+/**************************************************************************/ 
+
+
+/* =========================================================================
+ * Function: query_lex
+ * Description:
+ *      Hand written lexical analyser for the parser.
+ * Input:
+ *      ptr = ptr to a ptr into character query-line buffer
+ *      end = ptr to last char in buffer
+ * Output:
+ *      yylval.text = the token's text
+ * Notes:
+ *      does NOT produce WILD tokens at the moment
+ * ========================================================================= */
+ 
+/* [RPAP - Jan 97: Stem Index Change]
+   state mode:
+      0 = Read next token
+      1 = Output word
+      2 = Output '|' or ')'
+ */
+static int query_lex(char **ptr, const char *end)
+{
+  char *buf_ptr = *ptr;
+  static int mode = 0;
+  static int termnum = 0;
+  static TermList *Terms = NULL;
+
+  if (mode == 0)
+    {
+      /* jump over whitespace */
+      buf_ptr = skipspace(buf_ptr, end);
+
+      if (inaword(buf_ptr, end))
+	{
+	  static char word[MAXSTEMLEN + 1]; /* [RJM 07/98: Memory Leak] */
+	  char *sWord = Xmalloc(MAXSTEMLEN + 1);
+	  int stem_to_apply, method_using = -1;
+
+	  PARSE_STEM_WORD(word, buf_ptr, end);
+
+	  /* Extract any parameters */
+	  stem_to_apply = stem_method;
+	  while (buf_ptr <= end)
+	    {
+	      int stem_param, param_type;
+	      char param[MAXPARAMLEN + 1];
+
+	      param_type = 0;
+	      PARSE_OPT_TERM_PARAM (param, param_type, buf_ptr, end);
+	      if (!param_type)
+		break;
+
+	      if (param_type == STEMPARAM)
+		{
+		  stem_param = atoi (param);
+		  if (errno != ERANGE && indexed && stem_param >= 0 && stem_param <= 3)
+		    method_using = stem_to_apply = stem_param;
+		}
+	    }
+
+	  bcopy ((char *) word, (char *) sWord, *word + 1);
+	  stemmer (stem_to_apply, stemmer_num, sWord);
+
+	  if (stem_to_apply == 0 || !indexed || p__sd == NULL)
+	    {
+	      /* [RPAP - Feb 97: Term Frequency] */
+	      word_num = FindWord (p__sd, sWord, &count, &doc_count, &invf_ptr, &invf_len);
+	      if (word_num == -1)
+		count = doc_count = invf_ptr = invf_len = 0;
+	      AddQueryTerm (query_term_list, (u_char *) word, count, method_using);
+
+	      yylval.text = word;
+	      *ptr = buf_ptr; /* fix up ptr */
+	      Xfree (sWord);
+	      return TERM;
+	    }
+	  else
+	    {
+	      *ptr = buf_ptr; /* fix up ptr */
+	      termnum = 0;
+	      ResetTermList (&Terms);
+	      if (FindWords (p__sd, (u_char *) sWord, stem_to_apply, &Terms) > 0)
+		{
+		  /* [RPAP - Feb 97: Term Frequency] */ 
+		  int i, freq = 0;
+		  for (i = 0; i < Terms->num; i++)
+		    freq += Terms->TE[i].WE.count;
+		  AddQueryTerm (query_term_list, word, freq, method_using);
+
+		  Xfree (sWord);
+		  mode = 1;
+		  return '(';
+		}
+	      else
+		{
+		  /* Word does not exists - include in tree anyway */
+		  Xfree (sWord);
+
+		  /* [RPAP - Feb 97: Term Frequency] */
+		  word_num = -1;
+		  count = doc_count = invf_ptr = invf_len = 0;
+		  AddQueryTerm (query_term_list, (u_char *) word, count, method_using);
+
+		  yylval.text = word;
+		  return TERM;
+		}
+	    }
+	}
+      else /* NON-WORD */
+	{
+	  if (*buf_ptr == '\0')
+	    {
+	      /* return null-char if it is one */
+	      *ptr = buf_ptr; /* fix up ptr */
+	      return 0;
+	    }
+	  else
+	    {
+	      /* return 1st char, and delete from buffer */
+	      char c = *buf_ptr++;
+	      *ptr = buf_ptr; /* fix up ptr */
+	      return c;
+	    }
+	}
+    }
+  else if (mode == 1)
+    {
+      yylval.text = Terms->TE[termnum].Word;
+      
+      /* [RPAP - Feb 97: Term Frequency] */
+      word_num = Terms->TE[termnum].WE.word_num;
+      count = Terms->TE[termnum].WE.count;
+      doc_count = Terms->TE[termnum].WE.doc_count;
+      invf_ptr = Terms->TE[termnum].WE.invf_ptr;
+      invf_len = Terms->TE[termnum].WE.invf_len;
+
+      termnum++;
+      mode = 2;
+      return TERM;
+    }
+  else  /* mode == 2 */
+    {
+      if (termnum >= Terms->num)
+	{
+	  mode = 0;
+	  return ')';
+	}
+      else
+	{
+	  mode = 1;
+	  return '|';
+	}
+    }
+}/*query_lex*/
+
+/* =========================================================================
+ * Function: yyerror
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */ 
+static int yyerror(char *s)
+{
+  Message("%s", s);
+  return(1);
+}
+
+ 
+/* =========================================================================
+ * Function: ParseBool
+ * Description:
+ *      Parse a boolean query string into a term-list and a boolean parse tree
+ * Input:
+ *      query_line = query line string
+ *      query_len = query line length
+ *      the_stem_method = stem method id used for stemming
+ * Output:
+ *      the_term_list = the list of terms
+ *      res = parser result code
+ * ========================================================================= */
+ 
+bool_tree_node *
+ParseBool(char *query_line, int query_len,
+          TermList **the_term_list, int the_stemmer_num, int the_stem_method, int *res,
+	  stemmed_dict * the_sd, int is_indexed,   /* [RPAP - Jan 97: Stem Index Change] */
+	  QueryTermList **the_query_term_list)  /* [RPAP - Feb 97: Term Frequency] */
+{
+  /* global variables to be accessed by bison/yacc created parser */
+  term_list = the_term_list;
+  stemmer_num = the_stemmer_num;
+  stem_method = the_stem_method;
+  ch_buf = query_line;
+  end_buf = query_line + query_len;
+  p__sd = the_sd;   /* [RPAP - Jan 97: Stem Index Change] */
+  indexed = is_indexed;  /* [RPAP - Jan 97: Stem Index Change] */
+  query_term_list = the_query_term_list; /* [RPAP - Feb 97: Term Frequency] */
+
+  FreeBoolTree(&(tree_base));
+ 
+  ResetTermList(term_list);
+  ResetQueryTermList(query_term_list);  /* [RPAP - Feb 97: Term Frequency] */
+
+  *res = yyparse();
+ 
+  return tree_base;
+}
+ 
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_parser.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_parser.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_parser.h	(revision 10506)
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * filename -- description
+ * Copyright (C) 1994  Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:43  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:40  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:26  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:56:33  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.1  1994/10/12  01:15:31  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+#ifndef BOOL_PARSER_H
+#define BOOL_PARSER_H
+
+#include "backend.h"
+#include "term_lists.h"
+#include "invf.h"
+
+bool_tree_node *ParseBool (char *query_line, int query_len,
+			   TermList ** the_term_list, int the_stemmer_num, 
+			   int the_stem_method, int *res,
+			   stemmed_dict * the_sd, int is_indexed,  /* [RPAP - Jan 97: Stem Index Change] */
+			   QueryTermList ** the_query_term_list);  /* [RPAP - Feb 97: Term Frequency] */
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_parser.y
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_parser.y	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_parser.y	(revision 10506)
@@ -0,0 +1,316 @@
+/**************************************************************************
+ *
+ * bool_parser - boolean query parser
+ * Copyright (C) 1994  Neil Sharman & Tim Shimmin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************/
+ 
+/**************************************************************************/
+%{
+ 
+#include "sysfuncs.h"
+
+#include "messages.h"
+ 
+#include "memlib.h"
+#include "words.h"
+#include "stemmer.h"
+#include "term_lists.h"
+#include "bool_tree.h"
+/* [RPAP - Jan 97: Stem Index Change] */
+#include "backend.h"     /* for stemmed_dict def */
+#include "stem_search.h"
+
+#include "query_term_list.h"  /* [RPAP - Feb 97: Term Frequency] */
+
+/* --- routines --- */
+static int query_lex();
+static int yyerror(char *);
+#define yylex() query_lex(&ch_buf, end_buf)
+ 
+/* --- module variables --- */
+static char *ch_buf; /* ptr to the character query line buffer */
+static char *end_buf; /* ptr to the last character of the line buffer */
+static bool_tree_node *tree_base = NULL;
+static TermList **term_list;
+static int stemmer_num;
+static int stem_method;
+/* [RPAP - Jan 97: Stem Index Change] */
+stemmed_dict *p__sd;
+static int indexed;
+/* [RPAP - Feb 97: Term Frequency] */
+static QueryTermList **query_term_list;
+static int word_num;
+static u_long count;
+static u_long doc_count;
+static u_long invf_ptr;
+static u_long invf_len;
+%}
+ 
+ 
+%union {
+  char *text;
+  bool_tree_node *node;
+}
+ 
+%token <text> TERM
+%type <node> query term not and or
+ 
+%%
+ 
+query: or  { tree_base = $1;}
+;
+ 
+ 
+term:     TERM  { $$ = CreateBoolTermNode(term_list, $1, 1, word_num, count, doc_count, invf_ptr, invf_len, stemmer_num); }
+        | '(' or ')' { $$ = $2; }
+        | '*' { $$ = CreateBoolTreeNode(N_all, NULL, NULL); }
+        | '_' { $$ = CreateBoolTreeNode(N_none, NULL, NULL); }
+;
+ 
+not:      term
+        | '!' not { $$ = CreateBoolTreeNode(N_not, $2, NULL); }
+;
+ 
+and:      and '&' not { $$ = CreateBoolTreeNode(N_and, $1, $3); }
+        | and not { $$ = CreateBoolTreeNode(N_and, $1, $2); }
+        | not
+;
+ 
+or:       or '|' and { $$ = CreateBoolTreeNode(N_or, $1, $3); }
+        | and
+;
+ 
+%%
+ 
+/* Bison on one mips machine defined "const" to be nothing but
+   then did not undef it */
+#ifdef const
+#undef const
+#endif
+
+/**************************************************************************/ 
+
+
+/* =========================================================================
+ * Function: query_lex
+ * Description:
+ *      Hand written lexical analyser for the parser.
+ * Input:
+ *      ptr = ptr to a ptr into character query-line buffer
+ *      end = ptr to last char in buffer
+ * Output:
+ *      yylval.text = the token's text
+ * Notes:
+ *      does NOT produce WILD tokens at the moment
+ * ========================================================================= */
+ 
+/* [RPAP - Jan 97: Stem Index Change]
+   state mode:
+      0 = Read next token
+      1 = Output word
+      2 = Output '|' or ')'
+ */
+static int query_lex(char **ptr, const char *end)
+{
+  char *buf_ptr = *ptr;
+  static int mode = 0;
+  static int termnum = 0;
+  static TermList *Terms = NULL;
+
+  if (mode == 0)
+    {
+      /* jump over whitespace */
+      buf_ptr = skipspace(buf_ptr, end);
+      
+      if (inaword(buf_ptr, end))
+	{
+	  static char word[MAXSTEMLEN + 1]; /* [RJM 07/98: Memory Leak] */
+	  char *sWord = Xmalloc(MAXSTEMLEN + 1);
+	  int stem_to_apply, method_using = -1;
+
+	  PARSE_STEM_WORD(word, buf_ptr, end);
+
+	  /* Extract any parameters */
+	  stem_to_apply = stem_method;
+	  while (buf_ptr <= end)
+	    {
+	      int stem_param, param_type;
+	      char param[MAXPARAMLEN + 1];
+
+	      param_type = 0;
+	      PARSE_OPT_TERM_PARAM (param, param_type, buf_ptr, end);
+	      if (!param_type)
+		break;
+
+	      if (param_type == STEMPARAM)
+		{
+		  stem_param = atoi (param);
+		  if (errno != ERANGE && indexed && stem_param >= 0 && stem_param <= 3)
+		    method_using = stem_to_apply = stem_param;
+		}
+	    }
+
+	  bcopy ((char *) word, (char *) sWord, *word + 1);
+	  stemmer (stem_to_apply, stemmer_num, sWord);
+
+	  if (stem_to_apply == 0 || !indexed || p__sd == NULL)
+	    {
+	      /* [RPAP - Feb 97: Term Frequency] */
+	      word_num = FindWord (p__sd, sWord, &count, &doc_count, &invf_ptr, &invf_len);
+	      if (word_num == -1)
+		count = doc_count = invf_ptr = invf_len = 0;
+	      AddQueryTerm (query_term_list, (u_char *) word, count, method_using);
+
+	      yylval.text = word;
+	      *ptr = buf_ptr; /* fix up ptr */
+	      Xfree (sWord);
+	      return TERM;
+	    }
+	  else
+	    {
+	      *ptr = buf_ptr; /* fix up ptr */
+	      termnum = 0;
+	      ResetTermList (&Terms);
+	      if (FindWords (p__sd, (u_char *) sWord, stem_to_apply, &Terms) > 0)
+		{
+		  /* [RPAP - Feb 97: Term Frequency] */ 
+		  int i, freq = 0;
+		  for (i = 0; i < Terms->num; i++)
+		    freq += Terms->TE[i].WE.count;
+		  AddQueryTerm (query_term_list, word, freq, method_using);
+
+		  Xfree (sWord);
+		  mode = 1;
+		  return '(';
+		}
+	      else
+		{
+		  /* Word does not exists - include in tree anyway */
+		  Xfree (sWord);
+
+		  /* [RPAP - Feb 97: Term Frequency] */
+		  word_num = -1;
+		  count = doc_count = invf_ptr = invf_len = 0;
+		  AddQueryTerm (query_term_list, (u_char *) word, count, method_using);
+
+		  yylval.text = word;
+		  return TERM;
+		}
+	    }
+	}
+      else /* NON-WORD */
+	{
+	  if (*buf_ptr == '\0')
+	    {
+	      /* return null-char if it is one */
+	      *ptr = buf_ptr; /* fix up ptr */
+	      return 0;
+	    }
+	  else
+	    {
+	      /* return 1st char, and delete from buffer */
+	      char c = *buf_ptr++;
+	      *ptr = buf_ptr; /* fix up ptr */
+	      return c;
+	    }
+	}
+    }
+  else if (mode == 1)
+    {
+      yylval.text = Terms->TE[termnum].Word;
+      
+      /* [RPAP - Feb 97: Term Frequency] */
+      word_num = Terms->TE[termnum].WE.word_num;
+      count = Terms->TE[termnum].WE.count;
+      doc_count = Terms->TE[termnum].WE.doc_count;
+      invf_ptr = Terms->TE[termnum].WE.invf_ptr;
+      invf_len = Terms->TE[termnum].WE.invf_len;
+
+      termnum++;
+      mode = 2;
+      return TERM;
+    }
+  else  /* mode == 2 */
+    {
+      if (termnum >= Terms->num)
+	{
+	  mode = 0;
+	  return ')';
+	}
+      else
+	{
+	  mode = 1;
+	  return '|';
+	}
+    }
+}/*query_lex*/
+
+/* =========================================================================
+ * Function: yyerror
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */ 
+static int yyerror(char *s)
+{
+  Message("%s", s);
+  return(1);
+}
+
+ 
+/* =========================================================================
+ * Function: ParseBool
+ * Description:
+ *      Parse a boolean query string into a term-list and a boolean parse tree
+ * Input:
+ *      query_line = query line string
+ *      query_len = query line length
+ *      the_stem_method = stem method id used for stemming
+ * Output:
+ *      the_term_list = the list of terms
+ *      res = parser result code
+ * ========================================================================= */
+ 
+bool_tree_node *
+ParseBool(char *query_line, int query_len,
+          TermList **the_term_list, int the_stemmer_num, int the_stem_method, int *res,
+	  stemmed_dict * the_sd, int is_indexed,   /* [RPAP - Jan 97: Stem Index Change] */
+	  QueryTermList **the_query_term_list)  /* [RPAP - Feb 97: Term Frequency] */
+{
+  /* global variables to be accessed by bison/yacc created parser */
+  term_list = the_term_list;
+  stemmer_num = the_stemmer_num;
+  stem_method = the_stem_method;
+  ch_buf = query_line;
+  end_buf = query_line + query_len;
+  p__sd = the_sd;   /* [RPAP - Jan 97: Stem Index Change] */
+  indexed = is_indexed;  /* [RPAP - Jan 97: Stem Index Change] */
+  query_term_list = the_query_term_list; /* [RPAP - Feb 97: Term Frequency] */
+
+  FreeBoolTree(&(tree_base));
+ 
+  ResetTermList(term_list);
+  ResetQueryTermList(query_term_list);  /* [RPAP - Feb 97: Term Frequency] */
+
+  *res = yyparse();
+ 
+  return tree_base;
+}
+ 
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_query.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_query.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_query.c	(revision 10506)
@@ -0,0 +1,353 @@
+/**************************************************************************
+ *
+ * bool_query.c -- Boolean query evaluation
+ * Copyright (C) 1994  Neil Sharman & Tim Shimmin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "filestats.h"
+#include "timing.h"
+#include "sptree.h"
+
+
+#include "mg.h"
+#include "text.h"
+#include "invf.h"
+#include "lists.h"
+#include "term_lists.h"
+#include "backend.h"
+#include "words.h"
+#include "stemmer.h"
+#include "stem_search.h"
+#include "invf_get.h"
+#include "text_get.h"
+#include "read_line.h"
+#include "bool_tree.h"
+#include "bool_parser.h"
+#include "bool_optimiser.h"
+#include "environment.h"
+
+
+/**********************
+  [RPAP - Feb 97: Term Frequency]
+
+  Shifted to bool_parser.y
+
+  *********************/
+
+/* =========================================================================
+ * Function: ReadInTermInfo
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+/**************************
+static void 
+ReadInTermInfo (query_data * qd)
+{
+  int i;
+  TermList *tl = qd->TL;
+
+  for (i = 0; i < tl->num; i++)
+    {
+      TermEntry *te = &(tl->TE[i]);
+      WordEntry *we = &(te->WE);
+
+       we->word_num = FindWord (qd->sd, te->Word,
+			       &we->count, &we->doc_count,
+			       &we->invf_ptr, &we->invf_len);
+      if (we->word_num == -1)
+	we->count = we->doc_count = 0;
+    }
+}
+
+***********************/
+
+
+
+/* =========================================================================
+ * Function: FindNoneTerms 
+ * Description: 
+ *      Set any terms which are not in dictionary to N_none (i.e. false)
+ *      Assumes a prior call to ReadInTermInfo
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void 
+FindNoneTerms (query_data * qd, bool_tree_node * tree)
+{
+  if (BOOL_HAS_CHILD (tree))
+    {
+      bool_tree_node *child = BOOL_CHILD (tree);
+      while (child)
+	{
+	  FindNoneTerms (qd, child);
+	  child = BOOL_SIBLING (child);
+	}
+    }
+  else if (BOOL_TAG (tree) == N_term)
+    {
+      int doc_count = qd->TL->TE[BOOL_TERM (tree)].WE.doc_count;
+      if (!doc_count)
+	BOOL_TAG (tree) = N_none;
+    }
+
+}				/*FindNoneTerms */
+
+/* =========================================================================
+ * Function: ReduceList
+ * Description: 
+ *      Go thru doc-set and get rid of all docs which are unmarked
+ *      The motivation for this routine is in the case of CNF queries.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+ReduceList (DocList * cset)
+{
+  DocEntry *src;
+  DocEntry *dest;
+
+  src = dest = cset->DE;
+  for (src = dest = cset->DE; src < cset->DE + cset->num; src++)
+    {
+      if (src->or_included)
+	{
+	  src->or_included = 0;
+	  *dest++ = *src;
+	}
+    }
+  cset->num = dest - cset->DE;
+
+}				/*ReduceList */
+
+/* =========================================================================
+ * Function: BooleanGet
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+static DocList *
+BooleanGet (query_data * qd, bool_tree_node * n,
+	    BooleanQueryInfo * bqi)
+{
+  if (n)
+    {
+      DocList *res = NULL;
+      switch (BOOL_TAG (n))
+	{
+	case N_all:
+	  Message ("Unexpected \"all\" node in the parse tree.");
+	  res = MakeDocList (0);
+	  break;
+	case N_not:
+	  Message ("Unexpected \"not\" node in the parse tree.");
+	  res = MakeDocList (0);
+	  break;
+	case N_none:
+	  {
+	    res = MakeDocList (0);
+	    break;
+	  }
+	case N_diff:
+	  {
+	    res = BooleanGet (qd, BOOL_CHILD (n), bqi);
+	    n = BOOL_SIBLING (BOOL_CHILD (n));
+	    while (n)
+	      {
+		bool_tree_node *next = BOOL_SIBLING (n);
+		if (BOOL_TAG (n) == N_term)
+		  {
+		    WordEntry *we = GetNthWE (qd->TL, BOOL_TERM (n));
+		    res = GetDocsOp (qd, we, op_diff_terms, res);
+		  }
+		else
+		  res = DiffLists (res, BooleanGet (qd, n, bqi));
+		n = next;
+	      }
+	    break;
+	  }
+	case N_and:
+	  {
+	    res = BooleanGet (qd, BOOL_CHILD (n), bqi);		/* initial fill of c-set */
+	    n = BOOL_SIBLING (BOOL_CHILD (n));
+	    while (n)
+	      {
+		bool_tree_node *next = BOOL_SIBLING (n);
+		switch (BOOL_TAG (n))
+		  {
+		  case N_term:
+		    {
+		      WordEntry *we = GetNthWE (qd->TL, BOOL_TERM (n));
+		      res = GetDocsOp (qd, we, op_and_terms, res);
+		    }
+		    break;
+		  case N_or_terms:
+		    {
+		      bool_tree_node *child = BOOL_CHILD (n);
+		      /* note: all children are terms - predetermined */
+		      while (child)
+			{
+			  WordEntry *we = GetNthWE (qd->TL, BOOL_TERM (child));
+			  res = GetDocsOp (qd, we, op_and_or_terms, res);
+			  child = BOOL_SIBLING (child);
+			}
+		      ReduceList (res);
+		    }
+		    break;
+		  default:
+		    res = IntersectLists (res, BooleanGet (qd, n, bqi));
+		  }		/*switch */
+		n = next;
+	      }
+	    break;
+	  }
+	case N_or:
+	case N_or_terms:
+	  {
+	    res = BooleanGet (qd, BOOL_CHILD (n), bqi);
+	    n = BOOL_SIBLING (BOOL_CHILD (n));
+	    while (n)
+	      {
+		bool_tree_node *next = BOOL_SIBLING (n);
+		res = MergeLists (res, BooleanGet (qd, n, bqi));
+		n = next;
+	      }
+	    break;
+	  }
+	case N_term:
+	  {
+	    res = GetDocsOp (qd, GetNthWE (qd->TL, BOOL_TERM (n)), op_term, NULL);
+	    break;
+	  }
+	}
+      return (res ? res : MakeDocList (0));
+    }
+  else
+    return MakeDocList (0);
+}
+
+/* =========================================================================
+ * Function: AdjustParaDocs
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+static int 
+DE_comp (void *a, void *b)
+{
+  return ((DocEntry *) a)->SeekPos - ((DocEntry *) b)->SeekPos;
+}
+
+static void
+AdjustParaDocs (query_data * qd, DocList * Docs)
+{
+  DocEntry *DE = Docs->DE;
+  int s, d;
+  Splay_Tree *SP;
+
+
+  /* Make the doc-list contain only references to unique
+   * real documents. So can get rid of cases where there
+   * are multiple paragraphs for a real document.
+   */
+
+  /* Note: [TS: 29/Sep/94] */
+  /* reads in seek-pos for docnums so can compare docs */
+  /* seek-pos used as real doc identifier */
+  /* whereas doc-num entries refer to paragraphs -- I think */
+  for (s = 0; s < Docs->num; s++)
+    FetchDocStart (qd, DE[s].DocNum, &DE[s].SeekPos, &DE[s].Len);
+
+  Message ("Original Number = %d\n", Docs->num);
+  SP = SP_createset (DE_comp);
+  d = 0;
+  for (s = 0; s < Docs->num; s++)
+    if (!SP_member (&DE[s], SP))
+      {
+	DE[d] = DE[s];
+	SP_insert (&DE[d], SP);
+	d++;
+      }
+  SP_freeset (SP);
+  Docs->num = d;
+  Message ("Final Number = %d\n", Docs->num);
+}
+
+/* =========================================================================
+ * Function: BooleanQuery 
+ * Description: 
+ *      The main control function for the boolean query.
+ * Input: 
+ * Output: 
+ *      qd->DL
+ * ========================================================================= */
+
+void 
+BooleanQuery (query_data * qd, char *Query, BooleanQueryInfo * bqi,
+	      int stem_method)
+{
+  bool_tree_node *tree;
+  DocList *Docs;
+  int res = 0;
+
+  tree = ParseBool (Query, MAXLINEBUFFERLEN, &(qd->TL), 
+		    qd->sd->sdh.stemmer_num, stem_method, &res,
+		    qd->sd, qd->sd->sdh.indexed,         /* [RPAP - Jan 97: Stem Index Change] */
+		    &(qd->QTL));                         /* [RPAP - Feb 97: Term Frequency] */
+
+  /* [TS:Aug/94] no longer tries to continue after parse failure */
+  if (res != 0)			/* failed the parse */
+    {
+      qd->DL = NULL;		/* have empty doc-list */
+      return;
+    }
+
+  /* [RPAP - Feb 97: Term Frequency] */
+  /*  ReadInTermInfo (qd); */
+
+  FindNoneTerms (qd, tree);
+
+  OptimiseBoolTree (tree, qd->TL, atoi (GetEnv ("optimise_type")));
+
+  qd->hops_taken = qd->num_of_ptrs = 0;
+  qd->num_of_terms = 0;
+
+  Docs = BooleanGet (qd, tree, bqi);
+
+/* [RPAP - Feb 97: NZDL Specifics] */
+#if !defined(PARABOOLEANMATCHES) && !defined(NZDL)
+  if (qd->id->ifh.InvfLevel == 3)
+    {
+      AdjustParaDocs (qd, Docs);
+    }
+#endif
+
+  if (bqi->MaxDocsToRetrieve != -1 && Docs->num > bqi->MaxDocsToRetrieve)
+    Docs->num = bqi->MaxDocsToRetrieve;
+
+  FreeQueryDocs (qd);
+
+  qd->DL = Docs;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_query.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_query.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_query.h	(revision 10506)
@@ -0,0 +1,52 @@
+/**************************************************************************
+ *
+ * bool_query.h -- boolean query processing
+ * Copyright (C) 1994  Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:45  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:28  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:56:36  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.1  1994/10/12  01:15:33  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+#ifndef BOOL_QUERY_H
+#define BOOL_QUERY_H
+
+#include "backend.h"
+
+void BooleanQuery (query_data * qd, char *Query, BooleanQueryInfo * bqi,
+		   int stem_method);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_tester.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_tester.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_tester.c	(revision 10506)
@@ -0,0 +1,182 @@
+/**************************************************************************
+ *
+ * bool_tester -- used to test bool_tree, bool_parser, bool_optimiser
+ * Copyright (C) 1994  Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.2  2000/03/05 22:58:24  sjboddie
+   compiler complained about using stdin and stdout to do global
+   initialization - variables were never changed so they were
+   replaced with #defines
+
+   Revision 1.1  1999/08/10 21:17:45  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:41  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:29  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1995/03/14  05:15:23  tes
+   * Updated the boolean query optimiser to do different types of optimisation.
+   * A query environment variable "optimise_type" specifies which one is to be
+   * used. Type 1 is the new one which is faster than 2.
+   *
+   * Revision 1.2  1994/10/18  06:11:05  tes
+   * The boolean optimiser seems to be modifying the parse tree
+   * like it is supposed to.
+   * Paragraph ranking now works without any text files if required to.
+   *
+   * Revision 1.1  1994/10/12  01:15:33  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "local_strings.h"
+#include "term_lists.h"
+#include "bool_tree.h"
+#include "bool_parser.h"
+#include "bool_optimiser.h"
+#include "query_term_list.h"  /* [RPAP - Feb 97: Term Frequency] */
+
+#define MAX_LINE_LEN  255
+#define STEMMER_NUM 0 /* Lovin's stemmer */
+#define STEM_METHOD 3
+
+/* Newer compilers complain when you use stdin and stdout to do global 
+initialization. Since they're static we'll just use #defines instead
+static FILE *file_in = stdin;
+static FILE *file_out = stdout;
+*/
+#define FILE_IN stdin
+#define FILE_OUT stdout
+
+static char line[MAX_LINE_LEN + 1];
+
+/* --- prototypes --- */
+static char *prompt (char *str);
+
+
+/* =========================================================================
+ * Function: main
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int main (int argc, char *argv[])
+{
+  bool_tree_node *tree = NULL;
+  TermList *term_list = NULL;
+  QueryTermList *query_term_list = NULL;  /* [RPAP - Feb 97: Term Frequency] */
+  int opt_type = 0;
+
+  while (1)
+    {
+      int res = 0;
+      int len = 0;
+
+      /* get a line */
+      if (!prompt ("Please enter boolean expression..."))
+	break;
+
+      len = strlen (line) - 1;	/* -1 => ignore the \n */
+
+      tree = ParseBool (line, len, &term_list, STEMMER_NUM, STEM_METHOD, &res,
+			NULL, 0,             /* [RPAP - Jan 97: Stem Index Change] */
+			&query_term_list);   /* [RPAP - Feb 97: Term Frequency] */
+
+      {
+	int done = 0;
+	while (!done)
+	  {
+	    if (!prompt ("Which type of optimisation 1 or 2 ?"))
+	      break;
+	    opt_type = atoi (line);
+	    done = (opt_type == 1 || opt_type == 2);
+	  }
+      }
+
+      if (!prompt ("Do you want to assign doc_counts to terms ?"))
+	break;
+
+      if (toupper (line[0]) == 'Y')
+	{
+	  /* cycle thru terms asking for doc_counts */
+	  int i;
+	  for (i = 0; i < term_list->num; i++)
+	    {
+	      char str[80];
+	      TermEntry *te = &(term_list->TE[i]);
+
+	      sprintf (str, "Please enter doc count for term '%s'",
+		       str255_to_string (te->Word, NULL));
+	      prompt (str);
+	      te->WE.doc_count = atoi (line);
+	      printf ("doc_count = %ld\n", te->WE.doc_count);
+	    }			/*for */
+	}			/*if */
+
+
+      if (res == 0)
+	{
+	  fprintf (FILE_OUT, "\n***Parsed Expression***\n");
+	  PrintBoolTree (tree, FILE_OUT);
+	  fputc ('\n', FILE_OUT);
+	  OptimiseBoolTree (tree, term_list, opt_type);
+	  fprintf (FILE_OUT, "\n***Optimised Expression ***\n");
+	  PrintBoolTree (tree, FILE_OUT);
+	  fputc ('\n', FILE_OUT);
+	}
+
+    }
+  return 0;
+}
+
+/* =========================================================================
+ * Function: 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static char *
+prompt (char *str)
+{
+  fprintf (FILE_OUT, "\n%s\n", str);
+  return fgets (line, MAX_LINE_LEN, FILE_IN);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_tree.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_tree.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_tree.c	(revision 10506)
@@ -0,0 +1,292 @@
+/**************************************************************************
+ *
+ * bool_tree.c -- Boolean parse tree ADT
+ * Copyright (C) 1994  Tim Shimmin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *       @(#)query.bool.y	1.9 16 Mar 1994
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "bool_tree.h"
+
+static char *RCSID = "$Id$";
+
+
+/* =========================================================================
+ * Function: CreateBoolNode
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+bool_tree_node *
+CreateBoolNode (N_Tag tag)
+{
+  bool_tree_node *n;
+  if (!(n = Xmalloc (sizeof (bool_tree_node))))
+    FatalError (1, "Can not create bool_tree_node for boolean query");
+  n->tag = tag;
+  BOOL_SIBLING (n) = NULL;
+  return n;
+}
+
+/* =========================================================================
+ * Function: 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+bool_tree_node *
+CreateBoolTermNode (TermList ** tl, char *text, int Count, int word_num,
+		    u_long count, u_long doc_count, u_long invf_ptr, u_long invf_len,  /* [RPAP - Feb 97: Term Frequency] */
+		    int stemmer_num) 
+{
+  bool_tree_node *n = NULL;
+
+  /* allocate bool_tree_node */
+  n = CreateBoolNode (N_term);
+
+  BOOL_TERM (n) = AddTerm (tl, (u_char *) text, Count, word_num, count, doc_count, 
+			   invf_ptr, invf_len, stemmer_num);  /* [RPAP - Feb 97: Term Frequency] */
+
+  return n;
+}
+
+
+/* =========================================================================
+ * Function: CreateTreeNode
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+bool_tree_node *
+CreateBoolTreeNode (N_Tag tag, bool_tree_node * left, bool_tree_node * right)
+{
+  bool_tree_node *n = CreateBoolNode (tag);
+
+  BOOL_CHILD (n) = left;
+  if (left)
+    BOOL_SIBLING (left) = right;
+  if (right)
+    BOOL_SIBLING (right) = NULL;
+
+  return (n);
+}
+
+/* =========================================================================
+ * Function: 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+EqualBoolNodes (bool_tree_node * a, bool_tree_node * b)
+{
+  if (BOOL_TAG (a) == N_term && BOOL_TAG (a) == N_term)
+    return BOOL_TERM (a) == BOOL_TERM (b);
+  return 0;
+}
+
+/* =========================================================================
+ * Function: FreeBoolTree
+ * Description: 
+ *      Notes: does not fix up any parent or sibling links around given tree
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void 
+FreeTree (bool_tree_node * tree)
+{
+  bool_tree_node *sibling;
+
+  while (tree)
+    {
+      if (BOOL_HAS_CHILD (tree))
+	FreeTree (BOOL_CHILD (tree));
+      sibling = BOOL_SIBLING (tree);
+      Xfree (tree);
+      tree = sibling;
+    }
+}
+
+void 
+FreeBoolTree (bool_tree_node ** the_tree)
+{
+  bool_tree_node *tree = *the_tree;
+
+  if (!tree)
+    return;
+
+  FreeTree (tree);
+  *the_tree = NULL;
+/*********************************/
+  /* THIS IS POTENTIALLY DANGEROUS */
+  /* FIX UP LATER */
+  /* Need to correct the links for parent/siblings */
+/*********************************/
+
+}
+
+/* =========================================================================
+ * Function: PrintBoolTree
+ * Description: 
+ *      Print out a text version of the tree to the file
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+PrintBinaryOp (bool_tree_node * tree, FILE * file, char op)
+{
+  bool_tree_node *child = NULL;
+  assert (BOOL_HAS_CHILD (tree));
+
+  child = BOOL_CHILD (tree);
+  while (child)
+    {
+      PrintBoolTree (child, file);
+      child = BOOL_SIBLING (child);
+      if (child)
+	fprintf (file, " %c ", op);
+    }
+}
+
+static void
+PrintUnaryOp (bool_tree_node * tree, FILE * file, char op)
+{
+  bool_tree_node *child = NULL;
+
+  fprintf (file, " %c ", op);
+  assert (BOOL_HAS_CHILD (tree));
+  child = BOOL_CHILD (tree);
+  PrintBoolTree (child, file);
+}
+
+void
+PrintBoolTree (bool_tree_node * tree, FILE * file)
+{
+  if (!tree)
+    return;
+
+  fprintf (file, "(");
+  switch (BOOL_TAG (tree))
+    {
+    case N_term:
+      fprintf (file, "term %d", BOOL_TERM (tree));
+      break;
+    case N_and:
+      PrintBinaryOp (tree, file, '&');
+      break;
+    case N_or:
+      PrintBinaryOp (tree, file, '|');
+      break;
+    case N_or_terms:
+      PrintBinaryOp (tree, file, '+');
+      break;
+    case N_diff:
+      PrintBinaryOp (tree, file, '-');
+      break;
+    case N_not:
+      PrintUnaryOp (tree, file, '!');
+      break;
+    case N_all:
+      fprintf (file, " TRUE ");
+      break;
+    case N_none:
+      fprintf (file, " FALSE ");
+      break;
+    default:
+      break;
+    }
+
+  fprintf (file, ")");
+}
+
+
+/* =========================================================================
+ * Function: CopyBoolTree
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+bool_tree_node *
+CopyBoolTree (bool_tree_node * tree)
+{
+  bool_tree_node *sibling = NULL;
+  bool_tree_node *tree_copy = NULL;
+  bool_tree_node *prev = NULL;
+
+  if (!tree)
+    return NULL;
+
+  sibling = tree;
+  prev = NULL;
+  while (sibling)
+    {
+      /* copy sibling */
+      bool_tree_node *sibling_copy = (bool_tree_node *) malloc (sizeof (bool_tree_node));
+      if (!sibling_copy)
+	FatalError (1, "No memory for bool tree copy");
+      bcopy ((char *) sibling, (char *) sibling_copy, sizeof (bool_tree_node));
+
+      if (BOOL_HAS_CHILD (sibling))
+	{
+	  BOOL_CHILD (sibling_copy) = CopyBoolTree (BOOL_CHILD (sibling));
+	}
+
+      /* do the link up of copies */
+      if (prev)
+	BOOL_SIBLING (prev) = sibling_copy;
+      else
+	tree_copy = sibling_copy;
+      prev = sibling_copy;
+
+      sibling = BOOL_SIBLING (sibling);
+    }
+  return tree_copy;
+}
+
+
+/* =========================================================================
+ * Function: LastBoolSibling
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+bool_tree_node *
+LastBoolSibling (bool_tree_node * tree)
+{
+
+  if (!tree)
+    return NULL;
+
+  do
+    {
+      tree = BOOL_SIBLING (tree);
+    }
+  while (BOOL_SIBLING (tree));
+
+  return tree;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_tree.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_tree.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/bool_tree.h	(revision 10506)
@@ -0,0 +1,110 @@
+/**************************************************************************
+ *
+ * bool_tree.h -- description
+ * Copyright (C) 1994  Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:46  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:42  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:31  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1995/03/14  05:15:25  tes
+   * Updated the boolean query optimiser to do different types of optimisation.
+   * A query environment variable "optimise_type" specifies which one is to be
+   * used. Type 1 is the new one which is faster than 2.
+   *
+   * Revision 1.2  1994/10/18  06:11:07  tes
+   * The boolean optimiser seems to be modifying the parse tree
+   * like it is supposed to.
+   * Paragraph ranking now works without any text files if required to.
+   *
+   * Revision 1.1  1994/10/12  01:15:35  tes
+   * Found bugs in the existing boolean query optimiser.
+   * So decided to rewrite it.
+   * I accidentally deleted query.bool.y, but I have replaced it
+   * with bool_parser.y (which I have forgotten to add here ! ;-(
+   *
+ */
+
+#ifndef BOOL_TREE_H
+#define BOOL_TREE_H
+
+#include "sysfuncs.h"
+#include "term_lists.h"
+
+typedef enum
+  {
+    N_term, N_and, N_or, N_diff, N_none, N_all,
+    N_not, N_or_terms
+  }
+N_Tag;
+
+typedef struct bool_tree_node
+  {
+    N_Tag tag;
+    struct bool_tree_node *sibling;
+    union
+      {
+	struct bool_tree_node *child;
+	int term_id;
+      }
+    fields;
+    int sum_ft;			/* for or_terms nodes */
+  }
+bool_tree_node;
+
+
+#define BOOL_HAS_CHILD(n) (\
+			(n)->tag==N_and || \
+			(n)->tag==N_or || (n)->tag==N_or_terms || \
+			(n)->tag==N_not || (n)->tag==N_diff)
+#define BOOL_TAG(n) ((n)->tag)
+#define BOOL_SIBLING(n) ((n)->sibling)
+#define BOOL_TERM(n) ((n)->fields.term_id)
+#define BOOL_CHILD(n) ((n)->fields.child)
+#define BOOL_SUM_FT(n) ((n)->sum_ft)
+
+bool_tree_node *CreateBoolNode (N_Tag tag);
+bool_tree_node *CopyBoolTree (bool_tree_node * tree);
+bool_tree_node *CreateBoolTermNode (TermList ** tl, char *text, int Count, int word_num,
+				    u_long count, u_long doc_count, u_long invf_ptr, 
+				    u_long invf_len, int stemmer_num);
+bool_tree_node *CreateBoolTreeNode (N_Tag tag,
+			     bool_tree_node * left, bool_tree_node * right);
+void FreeBoolTree (bool_tree_node ** tree);
+void PrintBoolTree (bool_tree_node * tree, FILE * file);
+bool_tree_node *LastBoolSibling (bool_tree_node * tree);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/build.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/build.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/build.h	(revision 10506)
@@ -0,0 +1,171 @@
+/**************************************************************************
+ *
+ * build.h -- Global information for the passes of mg_passes
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_BUILD
+#define H_BUILD
+
+#include "longlong.h"
+
+#define	TERMPARAGRAPH	'\003'
+
+
+int init_special (char *file_name);
+int init_text_1 (char *file_name);
+int init_text_2 (char *file_name);
+int init_invf_1 (char *file_name);
+int init_invf_2 (char *file_name);
+int init_ivf_1 (char *file_name);
+int init_ivf_2 (char *file_name);
+/*
+ * file_name  IN      The name of the dictionary file
+ * 
+ * returns      COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot read file
+ */
+
+
+
+
+
+int process_special (u_char * s_in, int l_in);
+int process_text_1 (u_char * s_in, int l_in);
+int process_text_2 (u_char * s_in, int l_in);
+int process_invf_1 (u_char * s_in, int l_in);
+int process_invf_2 (u_char * s_in, int l_in);
+int process_ivf_1 (u_char * s_in, int l_in);
+int process_ivf_2 (u_char * s_in, int l_in);
+/*
+ * s_in               IN      The binary string to be compressed
+ * l_in         IN      The number of characters in s_in
+ *
+ * returns      COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot read file
+ *
+ * The calling routine is responsible for ensuring that s_out is long 
+ * enough.
+ */
+
+
+
+
+
+int done_special (char *filename);
+int done_text_1 (char *filename);
+int done_text_2 (char *filename);
+int done_invf_1 (char *filename);
+int done_invf_2 (char *filename);
+int done_ivf_1 (char *filename);
+int done_ivf_2 (char *filename);
+/*
+ * returns    COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot write file
+ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern char InvfLevel;
+/*
+ * This will determine the level of the inverted file it can take on the
+ * values 1, 2, or 3.
+ *
+ * Level 1: The inverted file contains only document numbers making it possible
+ *          to do only boolean queries.
+ * 
+ * Level 2: The inverted file also contains word counts per document making it
+ *          possible to do cosine ranked queries.
+ *
+ * Level 3: The inverted file contains word positions.
+ */
+
+
+extern unsigned long buf_size;
+/*
+ * The size of the document input buffer.
+ */
+
+extern unsigned long ChunkLimit;
+/*
+ * The maximum number of chunks that can be written to disk.
+ */
+
+extern unsigned long invf_buffer_size;
+/*
+ * The amount of memory to allocate to the invertion buffer.
+ */
+
+extern char SkipSGML;
+/*
+ * 1 if SGML tags are to be considered non-words when building the 
+ * inverted file.
+ */
+
+extern char MakeWeights;
+/*
+ * 1 if the weights file should be generated.
+ */
+
+extern FILE *Comp_Stats;
+/*
+ * Contains a file pointer to the file where compression stats should be sent
+ */
+
+extern int comp_stat_point;
+/*
+ * Generate a compression stat entry every comp_stat_point bytes 
+ */
+
+extern mg_ullong bytes_processed;
+/*
+ * The number of bytes processed. NOTE: This excludes document separators.
+ */
+
+extern mg_ullong bytes_received;
+/*
+ * The number of bytes processed. NOTE: This includes document separators.
+ */
+
+
+extern int stemmer_num;
+/*
+ * The stemmer to use for stemming words for the inverted file.
+ * see stemmer.h
+ */
+
+extern int stem_method;
+/*
+ * The method to use for stemming words for the inverted file.
+ * see stemmer.h
+ */
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/commands.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/commands.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/commands.c	(revision 10506)
@@ -0,0 +1,582 @@
+/**************************************************************************
+ *
+ * commands.c -- mgquery command processing functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:47  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:32  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:41:22  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+
+#include "environment.h"
+#include "mg.h"
+#include "locallib.h"
+#include "backend.h"		/* for qd */
+#include "term_lists.h"		/* for MAXTERMSTRLEN */
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+# define OPENPIPE        _popen
+# define CLOSEPIPE       _pclose
+#else
+# define OPENPIPE        popen
+# define CLOSEPIPE       pclose
+#endif
+
+extern char *PathName;
+extern FILE *OutFile, *InFile;
+extern int OutPipe, InPipe;
+extern int Quitting;
+
+char *CommandsErrorStr = NULL;
+
+/* [TS: June/95] */
+/* current qd for use by any commands */
+static query_data *the_qd = NULL;
+
+
+#include "help.mg.h"
+#include "warranty.h"
+#include "conditions.h"
+
+static void 
+CmdQuit (void)
+{
+  Quitting = 1;
+}
+
+static void 
+CmdPush (void)
+{
+  PushEnv ();
+}
+
+
+static void 
+CmdPop (void)
+{
+  PopEnv ();
+  if (EnvStackHeight () == 1)
+    PushEnv ();
+}
+
+static void 
+CmdHelp (void)
+{
+  FILE *more;
+  int i;
+
+  if (!(more = OPENPIPE (GetDefEnv ("pager", "more"), "w")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fprintf (stderr, "ERROR : Unable to run more\n");
+      return;
+    }
+  for (i = 0; i < sizeof (help_str) / sizeof (help_str[0]); i++)
+    fputs (help_str[i], more);
+
+  CLOSEPIPE (more);  /* [RPAP - Feb 97: WIN32 Port] */
+}
+
+
+static void 
+CmdWarranty (void)
+{
+  FILE *more;
+  int i;
+
+  if (!(more = OPENPIPE (GetDefEnv ("pager", "more"), "w")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fprintf (stderr, "ERROR : Unable to run more\n");
+      return;
+    }
+  for (i = 0; i < sizeof (warranty_str) / sizeof (warranty_str[0]); i++)
+    fputs (warranty_str[i], more);
+
+  CLOSEPIPE (more);  /* [RPAP - Feb 97: WIN32 Port] */
+}
+
+
+static void 
+CmdConditions (void)
+{
+  FILE *more;
+  int i;
+
+  if (!(more = OPENPIPE (GetDefEnv ("pager", "more"), "w")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fprintf (stderr, "ERROR : Unable to run more\n");
+      return;
+    }
+  for (i = 0; i < sizeof (cond_str) / sizeof (cond_str[0]); i++)
+    fputs (cond_str[i], more);
+
+  CLOSEPIPE (more);
+}
+
+static void 
+CmdReset (void)
+{
+  while (EnvStackHeight () > 1)
+    PopEnv ();
+  PushEnv ();
+}
+
+static void 
+CmdDisplay (void)
+{
+  int i;
+  size_t l = 0;
+  char *name;
+  for (i = 0; (name = GetEnvName (i)) != NULL; i++)
+    if (strlen (name) > l)
+      l = strlen (name);
+
+  for (i = 0; (name = GetEnvName (i)) != NULL; i++)
+    printf ("%-*s = \"%s\"\n", (int) l, name, GetEnv (name));
+}
+
+static void 
+CmdQueryTerms (void)
+{
+  static char terms_str[MAXTERMSTRLEN + 1];
+
+  if (the_qd && the_qd->TL)
+    {
+      ConvertTermsToString (the_qd->TL, terms_str);
+      printf ("%s\n", terms_str);
+      fflush (stdout);
+    }
+
+}
+
+
+static void 
+CmdSet (char *name, char *value)
+{
+  if (!*name)
+    {
+      CommandsErrorStr = "Blank names are not permitted";
+      return;
+    }
+  switch (SetEnv (name, value, NULL))
+    {
+    case -1:
+      CommandsErrorStr = "Out of memory\n";
+      break;
+    case -2:
+      CommandsErrorStr = ConstraintErrorStr;
+      break;
+    }
+}
+
+static void 
+CmdUnset (char *name)
+{
+  if (!*name)
+    {
+      CommandsErrorStr = "Blank names are not permitted";
+      return;
+    }
+  if (UnsetEnv (name, 0) == -1)
+    CommandsErrorStr = "Specified name does not exist";
+}
+
+
+
+
+
+
+/*
+ * Do the .input command 
+ */
+static void 
+CmdInput (char *param1, char *param2)
+{
+  enum
+  {
+    READ, APPEND, PIPEFROM
+  }
+  mode;
+  FILE *NewInput;
+  char *buf, *s;
+
+  /* join the two parameters together */
+  buf = Xmalloc (strlen (param1) + strlen (param2) + 1);
+  strcpy (buf, param1);
+  strcat (buf, param2);
+  s = buf;
+
+
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  if (*s == '<')
+    {
+      s++;
+      mode = READ;
+    }
+  else if (*s == '|')
+    {
+      mode = PIPEFROM;
+      s++;
+    }
+  else
+    {
+      if (InPipe)
+	CLOSEPIPE (InFile);  /* [RPAP - Feb 97: WIN32 Port] */
+      else if (InFile != stdin)
+	fclose (InFile);
+      InPipe = 0;
+      InFile = stdin;
+      Xfree (buf);
+      return;
+    }
+
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  if (*s)
+    {
+      if (mode == READ)
+	NewInput = fopen (s, "r");
+      else
+	NewInput = OPENPIPE (s, "r");  /* [RPAP - Feb 97: WIN32 Port] */
+
+      if (NewInput)
+	{
+	  if (InPipe)
+	    CLOSEPIPE (InFile);  /* [RPAP - Feb 97: WIN32 Port] */
+	  else if (InFile != stdin)
+	    fclose (InFile);
+	  InPipe = (mode == PIPEFROM);
+	  InFile = NewInput;
+	}
+      else
+	CommandsErrorStr = "Bad input file/pipe";
+    }
+  else
+    {
+      if (InPipe)
+	CLOSEPIPE (InFile);  /* [RPAP - Feb 97: WIN32 Port] */
+      else if (InFile != stdin)
+	fclose (InFile);
+      InPipe = 0;
+      InFile = stdin;
+    }
+  Xfree (buf);
+}
+
+
+
+static void 
+CmdOutput (char *param1, char *param2)
+{
+  enum
+  {
+    WRITE, APPEND, PIPETO
+  }
+  mode;
+  char *buf, *s;
+  FILE *NewOutput;
+
+  /* join the two parameters together */
+  buf = Xmalloc (strlen (param1) + strlen (param2) + 1);
+  strcpy (buf, param1);
+  strcat (buf, param2);
+  s = buf;
+
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  if (*s == '>')
+    {
+      s++;
+      mode = APPEND;
+      if (*s == '>')
+	s++;
+      else
+	mode = WRITE;
+    }
+  else if (*s == '|')
+    {
+      mode = PIPETO;
+      s++;
+    }
+  else
+    {
+      if (OutPipe)
+	CLOSEPIPE (OutFile);  /* [RPAP - Feb 97: WIN32 Port] */
+      else if (OutFile != stdout)
+	fclose (OutFile);
+      OutPipe = 0;
+      OutFile = stdout;
+      Xfree (buf);
+      return;
+    }
+
+  while (*s == ' ' || *s == '\t')
+    s++;
+
+  if (*s)
+    {
+      if (mode == PIPETO)
+	NewOutput = OPENPIPE (s, "w");  /* [RPAP - Feb 97: WIN32 Port] */
+      else
+	NewOutput = fopen (s, mode == WRITE ? "w" : "a");
+      if (NewOutput)
+	{
+	  if (OutPipe)
+	    CLOSEPIPE (OutFile);  /* [RPAP - Feb 97: WIN32 Port] */
+	  else if (OutFile != stdout)
+	    fclose (OutFile);
+	  OutPipe = (mode == PIPETO);
+	  OutFile = NewOutput;
+	}
+      else
+	CommandsErrorStr = "Bad output file/pipe";
+    }
+  else
+    {
+      if (OutPipe)
+	CLOSEPIPE (OutFile);  /* [RPAP - Feb 97: WIN32 Port] */
+      else if (OutFile != stdout)
+	fclose (OutFile);
+      OutPipe = 0;
+      OutFile = stdout;
+    }
+  Xfree (buf);
+}
+
+
+
+static char *
+ParseArg (char *line, char *buffer)
+{
+  if (*line == '\"')
+    {
+      line++;
+      while (*line != '\"' && *line != '\0')
+	{
+	  if (*line == '\\')
+	    *buffer++ = *line++;
+	  if (*line != '\0')
+	    *buffer++ = *line++;
+	}
+      if (*line == '\"')
+	line++;
+    }
+  else
+    while (*line != ' ' && *line != '\t' && *line != '\0')
+      {
+	if (*line == '\\')
+	  line++;
+	if (*line != '\0')
+	  *buffer++ = *line++;
+      }
+  *buffer = '\0';
+  while (*line == ' ' || *line == '\t')
+    line++;
+  return (line);
+}
+
+
+
+char *
+ProcessCommands (char *line, query_data * qd)
+{
+  struct
+  {
+    char *Command;
+    void (*action) (void);
+    void (*action1) (char *);
+    void (*action2) (char *, char *);
+  }
+   *dc, dot_command[] =
+  {
+    {
+      "set", NULL, NULL, CmdSet
+    }
+    ,
+    {
+      "input", NULL, NULL, CmdInput
+    }
+    ,
+    {
+      "output", NULL, NULL, CmdOutput
+    }
+    ,
+    {
+      "unset", NULL, CmdUnset, NULL
+    }
+    ,
+    {
+      "help", CmdHelp, NULL, NULL
+    }
+    ,
+    {
+      "reset", CmdReset, NULL, NULL
+    }
+    ,
+    {
+      "display", CmdDisplay, NULL, NULL
+    }
+    ,
+    {
+      "push", CmdPush, NULL, NULL
+    }
+    ,
+    {
+      "quit", CmdQuit, NULL, NULL
+    }
+    ,
+    {
+      "pop", CmdPop, NULL, NULL
+    }
+    ,
+    {
+      "warranty", CmdWarranty, NULL, NULL
+    }
+    ,
+    {
+      "conditions", CmdConditions, NULL, NULL
+    }
+    ,
+    {
+      "queryterms", CmdQueryTerms, NULL, NULL
+    }
+  };
+
+
+  char command[512];
+  char param1[512], param2[512];
+  CommandsErrorStr = NULL;
+  the_qd = qd;			/* set globally to be accessed by command functions if needed */
+  while (*line == ' ' || *line == '\t')
+    line++;
+  while (*line == '.')
+    {
+      int i;
+      line++;
+      for (i = 0; isalpha (*line) && i < 512; i++, line++)
+	command[i] = tolower (*line);
+      while (*line == ' ' || *line == '\t')
+	line++;
+      if (i != 512)
+	{
+	  command[i] = '\0';
+	  for (i = 0, dc = dot_command; i < NUMOF (dot_command); i++, dc++)
+	    if (!strcmp (dc->Command, command))
+	      {
+		if (dc->action)
+		  dc->action ();
+		else if (dc->action1)
+		  {
+		    line = ParseArg (line, param1);
+		    dc->action1 (param1);
+		    break;
+		  }
+		else if (dc->action2)
+		  {
+		    line = ParseArg (line, param1);
+		    line = ParseArg (line, param2);
+		    dc->action2 (param1, param2);
+		    break;
+		  }
+		if (CommandsErrorStr)
+		  *line = '\0';
+		break;
+	      }
+	  if (i == NUMOF (dot_command))
+	    i = 100;
+	}
+      if (i == 100)
+	{
+	  CommandsErrorStr = "Illegal command";
+	  *line = '\0';
+	}
+      while (*line == ' ' || *line == '\t')
+	line++;
+    }
+  return (line);
+}
+
+
+
+
+
+void 
+read_mgrc_file (void)
+{
+  char line[1000];
+  char FileName[256];
+  int LineNum = 0;
+  FILE *mgrc;
+
+  strcpy (FileName, ".mgrc");
+  mgrc = fopen (FileName, "r");
+
+  if (!mgrc)
+    {
+      char *home_path = getenv ("HOME");
+      if (home_path)
+	{
+	  sprintf (FileName, "%s/.mgrc", home_path);
+	  mgrc = fopen (FileName, "r");
+	}
+    }
+
+  if (!mgrc)
+    return;
+
+  while (fgets (line, sizeof (line), mgrc))
+    {
+      char *s, linebuf[1000];
+      LineNum++;
+      if ((s = strchr (line, '\n')) != NULL)
+	*s = '\0';
+      strcpy (linebuf, line);
+      if ((s = strchr (line, '#')) != NULL)
+	*s = '\0';
+      if (!*line)
+	continue;
+      ProcessCommands (line, NULL);
+      if (CommandsErrorStr)
+	Message ("%s\n%s : ERROR in line %d of %s\n%s : %s\n",
+		 linebuf,
+		 msg_prefix, LineNum, FileName,
+		 msg_prefix, CommandsErrorStr);
+    }
+  fclose (mgrc);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/commands.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/commands.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/commands.h	(revision 10506)
@@ -0,0 +1,33 @@
+/**************************************************************************
+ *
+ * commands.h -- mgquery command processing functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef COMMANDS_H
+#define COMMANDS_H
+
+#include "backend.h"
+
+extern char *CommandsErrorStr;
+char *ProcessCommands (char *line, query_data * qd);
+void read_mgrc_file (void);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/comp_dict.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/comp_dict.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/comp_dict.c	(revision 10506)
@@ -0,0 +1,255 @@
+/**************************************************************************
+ *
+ * comp_dict.c -- Functions for loading the compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "huffman.h"
+#include "local_strings.h"
+#include "memlib.h"
+#include "messages.h"
+
+#include "mg.h"
+#include "hash.h"
+#include "text.h"
+#include "comp_dict.h"
+#include "locallib.h"
+#include "mg_files.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:17:48  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:34  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:41  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:24  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+compression_dict_header cdh;
+compressed_text_header cth;
+comp_frags_header cfh[2];
+
+dict_hash_table *ht[2];
+
+huff_data char_huff[2];
+huff_data lens_huff[2];
+u_long *char_codes[2], *lens_codes[2];
+u_long Words_disk = 0;
+u_long Chars_disk = 0;
+
+
+static dict_hash_table *
+ReadInWords (FILE * dict, comp_frags_header * cfh,
+	     int esc)
+{
+  int i;
+  u_char *allwords, *prev = NULL;
+  dict_hash_table *ht;
+  u_char **words;
+  u_long ht_size;
+
+  ht_size = prime (cfh->hd.num_codes * HASH_RATIO);
+  if (!(ht = Xmalloc (sizeof (dict_hash_table) +
+		      (ht_size - 1) * sizeof (ht->table[0]))))
+    {
+      Message ("no memory for hash_table\n");
+      return NULL;
+    }
+
+  ht->size = ht_size;
+  ht->hd = &cfh->hd;
+
+  if (!(ht->codes = Generate_Huffman_Codes (&cfh->hd, NULL)))
+    {
+      Message ("no memory for huffman codes\n");
+      return NULL;
+    }
+
+  if (!(ht->words = Xmalloc (sizeof (u_char *) * cfh->hd.num_codes)))
+    {
+      Message ("no memory for word pointers\n");
+      return NULL;
+    }
+  words = ht->words;
+
+  bzero ((char *) ht->table, ht_size * sizeof (ht->table[0]));
+
+  if (!(allwords = Xmalloc (sizeof (u_char) * cfh->uncompressed_size)))
+    {
+      Message ("no memory for words\n");
+      return NULL;
+    }
+
+  for (i = 0; i < cfh->hd.num_codes; i++, words++)
+    {
+      register int val, copy;
+      val = fgetc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      *words = allwords;
+
+      memcpy (allwords + 1, prev + 1, copy);
+      fread (allwords + copy + 1, sizeof (u_char), val, dict);
+      *allwords = val + copy;
+
+      Words_disk += val + 1;
+
+      /* insert into the hash table */
+      if (i < cfh->hd.num_codes - esc)
+	{
+	  register u_char **wptr;
+	  register int tsize = ht->size;
+	  register unsigned long hashval, step;
+
+	  HASH (hashval, step, allwords, tsize);
+
+	  wptr = ht->table[hashval];
+	  for (; wptr;)
+	    {
+	      hashval += step;
+	      if (hashval >= tsize)
+		hashval -= tsize;
+	      wptr = ht->table[hashval];
+	    }
+	  ht->table[hashval] = words;
+	}
+      prev = allwords;
+      allwords += *allwords + 1;
+    }
+  return ht;
+}
+
+
+
+int 
+LoadCompressionDictionary (char *dict_file_name)
+{
+  FILE *dict;
+  int which;
+  if (!(dict = open_named_file (dict_file_name, "rb", MAGIC_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+
+  Words_disk = sizeof (u_long);
+
+  if (Read_cdh (dict, &cdh, NULL, &Words_disk) == -1)
+    goto error;
+
+  for (which = 0; which < 2; which++)
+    switch (cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  if (Read_cfh (dict, &cfh[which], NULL, &Words_disk) == -1)
+	    goto error;
+
+	  if (!(ht[which] = ReadInWords (dict, &cfh[which], 0)))
+	    goto error;
+
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    {
+	      if (Read_cfh (dict, &cfh[which], NULL, &Words_disk) == -1)
+		goto error;
+	      if (!(ht[which] = ReadInWords (dict, &cfh[which], 1)))
+		goto error;
+	    }
+	  else
+	    ht[which] = NULL;
+	  if (Read_Huffman_Data (dict, &char_huff[which], NULL,
+				 &Chars_disk) == -1)
+	    goto error;
+	  if (!(char_codes[which] =
+		Generate_Huffman_Codes (&char_huff[which], NULL)))
+	    goto error;
+	  if (Read_Huffman_Data (dict, &lens_huff[which], NULL,
+				 &Chars_disk) == -1)
+	    goto error;
+	  if (!(lens_codes[which] =
+		Generate_Huffman_Codes (&lens_huff[which], NULL)))
+	    goto error;
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    {
+	      if (Read_cfh (dict, &cfh[which], NULL, &Words_disk) == -1)
+		goto error;
+	      if (!(ht[which] = ReadInWords (dict, &cfh[which], 1)))
+		goto error;
+	    }
+	  else
+	    ht[which] = NULL;
+	  switch (cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      if (Read_Huffman_Data (dict, &char_huff[which], NULL,
+				     &Chars_disk) == -1)
+		goto error;
+	      if (!(char_codes[which] =
+		    Generate_Huffman_Codes (&char_huff[which], NULL)))
+		goto error;
+	      if (Read_Huffman_Data (dict, &lens_huff[which], NULL,
+				     &Chars_disk) == -1)
+		goto error;
+	      if (!(lens_codes[which] =
+		    Generate_Huffman_Codes (&lens_huff[which], NULL)))
+		goto error;
+	      break;
+	    case MG_NOVEL_BINARY:
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    case MG_NOVEL_HYBRID_MTF:
+	      break;
+	    default:
+	      FatalError (1, "Bad novel method");
+	    }
+	}
+	break;
+      default:
+	FatalError (1, "Bad dictionary kind\n");
+      }
+
+  return (COMPALLOK);
+
+
+error:
+  fclose (dict);
+  return (COMPERROR);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/comp_dict.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/comp_dict.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/comp_dict.h	(revision 10506)
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * comp_dict.h -- Functions for loading the compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+
+
+#define HASH_RATIO 2
+
+
+
+
+typedef struct dict_hash_table
+  {
+    u_long size;
+    huff_data *hd;
+    u_long *codes;
+    u_char **words;
+    u_char **table[1];
+  }
+dict_hash_table;
+
+
+
+
+extern compression_dict_header cdh;
+extern compressed_text_header cth;
+extern comp_frags_header cfh[2];
+
+extern dict_hash_table *ht[2];
+
+extern huff_data char_huff[2];
+extern huff_data lens_huff[2];
+extern u_long *char_codes[2], *lens_codes[2];
+extern u_long Words_disk;
+extern u_long Chars_disk;
+
+
+
+int LoadCompressionDictionary (char *dict_file_name);
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/conditions.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/conditions.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/conditions.h	(revision 10506)
@@ -0,0 +1,226 @@
+static char *cond_str[] = {
+"		    GNU GENERAL PUBLIC LICENSE\n",
+"   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n",
+"\n",
+"  0. This License applies to any program or other work which contains\n",
+"a notice placed by the copyright holder saying it may be distributed\n",
+"under the terms of this General Public License.  The \"Program\", below,\n",
+"refers to any such program or work, and a \"work based on the Program\"\n",
+"means either the Program or any derivative work under copyright law:\n",
+"that is to say, a work containing the Program or a portion of it,\n",
+"either verbatim or with modifications and/or translated into another\n",
+"language.  (Hereinafter, translation is included without limitation in\n",
+"the term \"modification\".)  Each licensee is addressed as \"you\".\n",
+"\n",
+"Activities other than copying, distribution and modification are not\n",
+"covered by this License; they are outside its scope.  The act of\n",
+"running the Program is not restricted, and the output from the Program\n",
+"is covered only if its contents constitute a work based on the\n",
+"Program (independent of having been made by running the Program).\n",
+"Whether that is true depends on what the Program does.\n",
+"\n",
+"  1. You may copy and distribute verbatim copies of the Program's\n",
+"source code as you receive it, in any medium, provided that you\n",
+"conspicuously and appropriately publish on each copy an appropriate\n",
+"copyright notice and disclaimer of warranty; keep intact all the\n",
+"notices that refer to this License and to the absence of any warranty;\n",
+"and give any other recipients of the Program a copy of this License\n",
+"along with the Program.\n",
+"\n",
+"You may charge a fee for the physical act of transferring a copy, and\n",
+"you may at your option offer warranty protection in exchange for a fee.\n",
+"\n",
+"  2. You may modify your copy or copies of the Program or any portion\n",
+"of it, thus forming a work based on the Program, and copy and\n",
+"distribute such modifications or work under the terms of Section 1\n",
+"above, provided that you also meet all of these conditions:\n",
+"\n",
+"    a) You must cause the modified files to carry prominent notices\n",
+"    stating that you changed the files and the date of any change.\n",
+"\n",
+"    b) You must cause any work that you distribute or publish, that in\n",
+"    whole or in part contains or is derived from the Program or any\n",
+"    part thereof, to be licensed as a whole at no charge to all third\n",
+"    parties under the terms of this License.\n",
+"\n",
+"    c) If the modified program normally reads commands interactively\n",
+"    when run, you must cause it, when started running for such\n",
+"    interactive use in the most ordinary way, to print or display an\n",
+"    announcement including an appropriate copyright notice and a\n",
+"    notice that there is no warranty (or else, saying that you provide\n",
+"    a warranty) and that users may redistribute the program under\n",
+"    these conditions, and telling the user how to view a copy of this\n",
+"    License.  (Exception: if the Program itself is interactive but\n",
+"    does not normally print such an announcement, your work based on\n",
+"    the Program is not required to print an announcement.)\n",
+"
+\n",
+"These requirements apply to the modified work as a whole.  If\n",
+"identifiable sections of that work are not derived from the Program,\n",
+"and can be reasonably considered independent and separate works in\n",
+"themselves, then this License, and its terms, do not apply to those\n",
+"sections when you distribute them as separate works.  But when you\n",
+"distribute the same sections as part of a whole which is a work based\n",
+"on the Program, the distribution of the whole must be on the terms of\n",
+"this License, whose permissions for other licensees extend to the\n",
+"entire whole, and thus to each and every part regardless of who wrote it.\n",
+"\n",
+"Thus, it is not the intent of this section to claim rights or contest\n",
+"your rights to work written entirely by you; rather, the intent is to\n",
+"exercise the right to control the distribution of derivative or\n",
+"collective works based on the Program.\n",
+"\n",
+"In addition, mere aggregation of another work not based on the Program\n",
+"with the Program (or with a work based on the Program) on a volume of\n",
+"a storage or distribution medium does not bring the other work under\n",
+"the scope of this License.\n",
+"\n",
+"  3. You may copy and distribute the Program (or a work based on it,\n",
+"under Section 2) in object code or executable form under the terms of\n",
+"Sections 1 and 2 above provided that you also do one of the following:\n",
+"\n",
+"    a) Accompany it with the complete corresponding machine-readable\n",
+"    source code, which must be distributed under the terms of Sections\n",
+"    1 and 2 above on a medium customarily used for software interchange; or,\n",
+"\n",
+"    b) Accompany it with a written offer, valid for at least three\n",
+"    years, to give any third party, for a charge no more than your\n",
+"    cost of physically performing source distribution, a complete\n",
+"    machine-readable copy of the corresponding source code, to be\n",
+"    distributed under the terms of Sections 1 and 2 above on a medium\n",
+"    customarily used for software interchange; or,\n",
+"\n",
+"    c) Accompany it with the information you received as to the offer\n",
+"    to distribute corresponding source code.  (This alternative is\n",
+"    allowed only for noncommercial distribution and only if you\n",
+"    received the program in object code or executable form with such\n",
+"    an offer, in accord with Subsection b above.)\n",
+"\n",
+"The source code for a work means the preferred form of the work for\n",
+"making modifications to it.  For an executable work, complete source\n",
+"code means all the source code for all modules it contains, plus any\n",
+"associated interface definition files, plus the scripts used to\n",
+"control compilation and installation of the executable.  However, as a\n",
+"special exception, the source code distributed need not include\n",
+"anything that is normally distributed (in either source or binary\n",
+"form) with the major components (compiler, kernel, and so on) of the\n",
+"operating system on which the executable runs, unless that component\n",
+"itself accompanies the executable.\n",
+"\n",
+"If distribution of executable or object code is made by offering\n",
+"access to copy from a designated place, then offering equivalent\n",
+"access to copy the source code from the same place counts as\n",
+"distribution of the source code, even though third parties are not\n",
+"compelled to copy the source along with the object code.\n",
+"
+\n",
+"  4. You may not copy, modify, sublicense, or distribute the Program\n",
+"except as expressly provided under this License.  Any attempt\n",
+"otherwise to copy, modify, sublicense or distribute the Program is\n",
+"void, and will automatically terminate your rights under this License.\n",
+"However, parties who have received copies, or rights, from you under\n",
+"this License will not have their licenses terminated so long as such\n",
+"parties remain in full compliance.\n",
+"\n",
+"  5. You are not required to accept this License, since you have not\n",
+"signed it.  However, nothing else grants you permission to modify or\n",
+"distribute the Program or its derivative works.  These actions are\n",
+"prohibited by law if you do not accept this License.  Therefore, by\n",
+"modifying or distributing the Program (or any work based on the\n",
+"Program), you indicate your acceptance of this License to do so, and\n",
+"all its terms and conditions for copying, distributing or modifying\n",
+"the Program or works based on it.\n",
+"\n",
+"  6. Each time you redistribute the Program (or any work based on the\n",
+"Program), the recipient automatically receives a license from the\n",
+"original licensor to copy, distribute or modify the Program subject to\n",
+"these terms and conditions.  You may not impose any further\n",
+"restrictions on the recipients' exercise of the rights granted herein.\n",
+"You are not responsible for enforcing compliance by third parties to\n",
+"this License.\n",
+"\n",
+"  7. If, as a consequence of a court judgment or allegation of patent\n",
+"infringement or for any other reason (not limited to patent issues),\n",
+"conditions are imposed on you (whether by court order, agreement or\n",
+"otherwise) that contradict the conditions of this License, they do not\n",
+"excuse you from the conditions of this License.  If you cannot\n",
+"distribute so as to satisfy simultaneously your obligations under this\n",
+"License and any other pertinent obligations, then as a consequence you\n",
+"may not distribute the Program at all.  For example, if a patent\n",
+"license would not permit royalty-free redistribution of the Program by\n",
+"all those who receive copies directly or indirectly through you, then\n",
+"the only way you could satisfy both it and this License would be to\n",
+"refrain entirely from distribution of the Program.\n",
+"\n",
+"If any portion of this section is held invalid or unenforceable under\n",
+"any particular circumstance, the balance of the section is intended to\n",
+"apply and the section as a whole is intended to apply in other\n",
+"circumstances.\n",
+"\n",
+"It is not the purpose of this section to induce you to infringe any\n",
+"patents or other property right claims or to contest validity of any\n",
+"such claims; this section has the sole purpose of protecting the\n",
+"integrity of the free software distribution system, which is\n",
+"implemented by public license practices.  Many people have made\n",
+"generous contributions to the wide range of software distributed\n",
+"through that system in reliance on consistent application of that\n",
+"system; it is up to the author/donor to decide if he or she is willing\n",
+"to distribute software through any other system and a licensee cannot\n",
+"impose that choice.\n",
+"\n",
+"This section is intended to make thoroughly clear what is believed to\n",
+"be a consequence of the rest of this License.\n",
+"
+\n",
+"  8. If the distribution and/or use of the Program is restricted in\n",
+"certain countries either by patents or by copyrighted interfaces, the\n",
+"original copyright holder who places the Program under this License\n",
+"may add an explicit geographical distribution limitation excluding\n",
+"those countries, so that distribution is permitted only in or among\n",
+"countries not thus excluded.  In such case, this License incorporates\n",
+"the limitation as if written in the body of this License.\n",
+"\n",
+"  9. The Free Software Foundation may publish revised and/or new versions\n",
+"of the General Public License from time to time.  Such new versions will\n",
+"be similar in spirit to the present version, but may differ in detail to\n",
+"address new problems or concerns.\n",
+"\n",
+"Each version is given a distinguishing version number.  If the Program\n",
+"specifies a version number of this License which applies to it and \"any\n",
+"later version\", you have the option of following the terms and conditions\n",
+"either of that version or of any later version published by the Free\n",
+"Software Foundation.  If the Program does not specify a version number of\n",
+"this License, you may choose any version ever published by the Free Software\n",
+"Foundation.\n",
+"\n",
+"  10. If you wish to incorporate parts of the Program into other free\n",
+"programs whose distribution conditions are different, write to the author\n",
+"to ask for permission.  For software which is copyrighted by the Free\n",
+"Software Foundation, write to the Free Software Foundation; we sometimes\n",
+"make exceptions for this.  Our decision will be guided by the two goals\n",
+"of preserving the free status of all derivatives of our free software and\n",
+"of promoting the sharing and reuse of software generally.\n",
+"\n",
+"			    NO WARRANTY\n",
+"\n",
+"  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
+"FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
+"OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
+"PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
+"OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
+"MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
+"TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
+"PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
+"REPAIR OR CORRECTION.\n",
+"\n",
+"  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
+"WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
+"REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
+"INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
+"OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
+"TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
+"YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
+"PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
+"POSSIBILITY OF SUCH DAMAGES.\n",
+"\n",
+"		     END OF TERMS AND CONDITIONS\n"};
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/conditions.src
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/conditions.src	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/conditions.src	(revision 10506)
@@ -0,0 +1,225 @@
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/environment.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/environment.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/environment.c	(revision 10506)
@@ -0,0 +1,688 @@
+/**************************************************************************
+ *
+ * environment.c -- mgquery environment functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.2  2003/04/18 01:41:46  sjboddie
+   Added a new -M option to mg_passes, allowing "maxnumeric" to be altered.
+
+   Revision 1.1  1999/08/10 21:17:50  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:37  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.5  1995/03/14  05:15:26  tes
+   * Updated the boolean query optimiser to do different types of optimisation.
+   * A query environment variable "optimise_type" specifies which one is to be
+   * used. Type 1 is the new one which is faster than 2.
+   *
+   * Revision 1.4  1994/11/25  03:47:43  tes
+   * Committing files before adding the merge stuff.
+   *
+   * Revision 1.3  1994/10/20  03:56:43  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:25  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "locallib.h"
+#include "local_strings.h"
+#include "messages.h"
+
+#include "environment.h"
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+# define STRCASECMP      stricmp
+#else
+# define STRCASECMP      strcasecmp
+#endif
+
+typedef struct
+  {
+    char *Name, *Data;
+    char *(*Constraint) (char *Old, char *New);
+  }
+EEntry;
+
+typedef struct Env
+  {
+    EEntry *Environment;
+    int NumEnv;
+    struct Env *Next;
+  }
+Env;
+
+
+char *ConstraintErrorStr;
+
+static Env Base =
+{NULL, 0, NULL};
+
+
+/*
+ * Add name and data to the environment (data may be NULL)
+ * All names are converted to lower case
+ * returns 0 on success, -1 on memory failure or -2 on constraint failure
+ */
+int 
+SetEnv (char *name, char *data, char *(*Constraint) (char *, char *))
+{
+  int i;
+  EEntry *newenv, *env = Base.Environment;
+
+  if (data && *data == '\0')
+    data = NULL;
+
+  /* search for name in the environment */
+  for (i = 0; i < Base.NumEnv && STRCASECMP (name, env->Name); i++, env++);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* if not found the increase the environment size */
+  if (i >= Base.NumEnv)
+    {
+      if (Constraint)
+	{
+	  data = Constraint (NULL, data);
+	  if (!data)
+	    return (-2);
+	}
+      /* allocate memory for the new environment */
+      newenv = Base.Environment ?
+	Xrealloc (Base.Environment, sizeof (EEntry) * (Base.NumEnv + 1)) :
+	Xmalloc (sizeof (EEntry) * (Base.NumEnv + 1));
+      if (!newenv)
+	return (-1);
+      Base.Environment = newenv;
+      env = &newenv[Base.NumEnv];
+      env->Data = NULL;
+      env->Name = NULL;
+      env->Constraint = Constraint;
+      env->Name = Xstrdup (name);
+      if (!env->Name)
+	return (-1);
+      Base.NumEnv++;
+      for (i = 0; env->Name[i]; i++)
+	env->Name[i] = tolower (env->Name[i]);
+    }
+  if (env->Constraint)
+    {
+      data = env->Constraint (env->Data, data);
+      if (!data)
+	return (-2);
+    }
+  if (env->Data)
+    Xfree (env->Data);
+  env->Data = NULL;
+  if (data && *data != '\0')
+    {
+      env->Data = Xstrdup (data);
+      if (!env->Data)
+	return (-1);
+    }
+  return (0);
+}
+
+
+
+/*
+ * Returns the data associated with name. If Data = NULL then this routine
+ * returns a pointer to "". If the specified name does not exist then this 
+ * routine returns NULL.
+ */
+char *
+GetEnv (char *name)
+{
+  int i;
+  EEntry *env = Base.Environment;
+  /* search for name in the environment */
+  for (i = 0; i < Base.NumEnv && STRCASECMP (name, env->Name); i++, env++);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  if (i >= Base.NumEnv)
+    return (NULL);
+
+  return (env->Data ? env->Data : "");
+}
+
+/*
+ * Returns the data associated with name. If Data = NULL then this routine
+ * returns a pointer to "". If the specified name does not exist then this 
+ * routine returns default.
+ */
+char *
+GetDefEnv (char *name, char *def)
+{
+  char *data = GetEnv (name);
+  return (data ? data : def);
+}
+
+
+
+/*
+ * This function pushes the environment on to a stack and duplicated it in 
+ * the current stack.
+ *
+ */
+int 
+PushEnv (void)
+{
+  Env *env = Xmalloc (sizeof (Env));
+  int i;
+  *env = Base;
+  Base.Next = env;
+  Base.Environment = NULL;
+  Base.NumEnv = 0;
+  for (i = 0; i < env->NumEnv; i++)
+    if (SetEnv (env->Environment[i].Name, env->Environment[i].Data,
+		env->Environment[i].Constraint))
+      return (-1);
+  return (0);
+}
+
+int 
+PopEnv (void)
+{
+  Env *env;
+  int i;
+  if (!Base.Next)
+    return (-1);
+  for (i = 0; i < Base.NumEnv; i++)
+    {
+      Xfree (Base.Environment[i].Name);
+      if (Base.Environment[i].Data)
+	Xfree (Base.Environment[i].Data);
+    }
+  if (Base.Environment)
+    Xfree (Base.Environment);
+  env = Base.Next;
+  Base = *env;
+  Xfree (env);
+  return (0);
+}
+
+
+/*
+ * Count the number of environments on the stack, including the current one.
+ *
+ */
+int 
+EnvStackHeight (void)
+{
+  int i = 1;
+  Env *env = &Base;
+  while (env->Next)
+    {
+      i++;
+      env = env->Next;
+    }
+  return (i);
+}
+
+/*
+ * Delete environment variable name. If name does not exist it returns -1
+ * otherwise it returns 0
+ */
+int 
+UnsetEnv (char *name, int Force)
+{
+  int i;
+  EEntry *env = Base.Environment;
+  /* search for name in the environment */
+  for (i = 0; i < Base.NumEnv && STRCASECMP (name, env->Name); i++, env++);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  if (i >= Base.NumEnv ||
+      (Base.Environment[i].Constraint && !Force))
+    return (-1);
+  Xfree (Base.Environment[i].Name);
+  if (Base.Environment[i].Data)
+    Xfree (Base.Environment[i].Data);
+  for (i++; i < Base.NumEnv; i++)
+    Base.Environment[i - 1] = Base.Environment[i];
+  Base.NumEnv--;
+  if (Base.NumEnv == 0)
+    {
+      Xfree (Base.Environment);
+      Base.Environment = NULL;
+    }
+  return (0);
+}
+
+
+
+
+
+
+
+
+/*
+ * Returns the name of environment variable number i or NULL if i is greater 
+ * than or equal to the number of environment variables. Names start from
+ * zero. 
+ */
+char *
+GetEnvName (int i)
+{
+  return (i < Base.NumEnv ? Base.Environment[i].Name : NULL);
+}
+
+static char *BooleanStrs[] =
+{"false", "true", "no", "yes", "off", "on"};
+
+static char *
+BooleanCons (char *Old, char *New)
+{
+  int i;
+  int old = -1, new = -1;
+  if (Old)
+    for (i = 0; i < sizeof (BooleanStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (Old, BooleanStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  old = i;
+	  break;
+	}
+  if (New)
+    for (i = 0; i < sizeof (BooleanStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (New, BooleanStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  new = i;
+	  break;
+	}
+  if (new >= 0)
+    return (New);
+  if (!New)
+    return (BooleanStrs[Old ? old ^ 1 : 0]);
+  ConstraintErrorStr = "Invalid argument [true|false|yes|no|on|off] required";
+  return (NULL);
+}
+
+/*
+ * returns 0 or 1  for a boolean string
+ * or default on a error
+ */
+int 
+BooleanEnv (char *data, int def)
+{
+  int i;
+  if (!data)
+    return (def);
+  for (i = 0; i < sizeof (BooleanStrs) / sizeof (char *); i++)
+    if (!STRCASECMP (data, BooleanStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+      return (i & 1);
+  return (def);
+}
+
+/*
+ * returns the value for a integer string
+ * or default on a error
+ */
+long 
+IntEnv (char *data, long def)
+{
+  long val;
+  char *ptr;
+  if (!data)
+    return (def);
+  val = strtol (data, &ptr, 10);
+  return *ptr ? def : val;
+}
+
+static char *
+NumberCmp (char *num, int min, int max)
+{
+  char *err;
+  int val;
+  static char Err[100];
+  ConstraintErrorStr = "Not a valid number";
+  if (!num)
+    return (NULL);
+  val = strtol (num, &err, 10);
+  if (*err)
+    return (NULL);
+  sprintf (Err, "Not in legal range [%d <= num <= %d]", min, max);
+  ConstraintErrorStr = Err;
+  if (val < min || val > max)
+    return (NULL);
+  return (num);
+}
+
+/*ARGSUSED */
+static char *
+MaxDocsCons (char *Old, char *New)
+{
+  if (!STRCASECMP (New, "all"))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (New);
+  return (NumberCmp (New, 1, ((unsigned) (~0)) >> 1));
+}
+
+/*ARGSUSED */
+static char *
+MaxTermsCons (char *Old, char *New)
+{
+  if (!STRCASECMP (New, "all"))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (New);
+  return (NumberCmp (New, 1, ((unsigned) (~0)) >> 1));
+}
+
+/* ARGSUSED */
+static char *
+BufferCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 0, 16 * 1024 * 1024));
+}
+
+/* ARGSUSED */
+static char *
+MaxNodesCons (char *Old, char *New)
+{
+  if (!STRCASECMP (New, "all"))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (New);
+  return (NumberCmp (New, 8, 256 * 1024 * 1024));
+}
+
+/* ARGSUSED */
+static char *
+MaxHashCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 8, 256 * 1024 * 1024));
+}
+
+/* ARGSUSED */
+static char *
+MaxParasCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 1, 256 * 1024 * 1024));
+}
+
+/* ARGSUSED */
+static char *
+MaxHeadsCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 1, 1000));
+}
+
+/* ARGSUSED */
+char *
+OptimiseCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 0, 2));
+}
+
+/* ARGSUSED */
+char *
+MaxNumericCons (char *Old, char *New)
+{
+  return (NumberCmp (New, 4, 512));
+}
+
+
+/*
+ * Makes sure that New is a valid query type
+ *
+ */
+/* ARGSUSED */
+static char *
+QueryCons (char *Old, char *New)
+{
+  static char *QueryStrs[] =
+  {
+    "boolean", "ranked",
+    "docnums", "approx-ranked"};
+  int i;
+  int new = -1;
+  if (New)
+    for (i = 0; i < sizeof (QueryStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (New, QueryStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  new = i;
+	  break;
+	}
+  if (new >= 0)
+    return (New);
+  ConstraintErrorStr = "Invalid argument [boolean|ranked|docnums|approx-ranked] required";
+  return (NULL);
+}
+
+/*
+ * Makes sure that New is a valid accum type
+ *
+ */
+/* ARGSUSED */
+static char *
+AccumCons (char *Old, char *New)
+{
+  static char *AccumStrs[] =
+  {
+    "array", "splay_tree", "hash_table", "list"};
+  int i;
+  int new = -1;
+  if (New)
+    for (i = 0; i < sizeof (AccumStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (New, AccumStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  new = i;
+	  break;
+	}
+  if (new >= 0)
+    return (New);
+  ConstraintErrorStr = "Invalid argument "
+    "[array|splay_tree|hash_table|list] required";
+  return (NULL);
+}
+
+
+
+/*
+ * Makes sure that New is a valid output type type
+ *
+ */
+/* ARGSUSED */
+static char *
+OutputTypeCons (char *Old, char *New)
+{
+  static char *OutputTypeStrs[] =
+  {"text", "silent", "docnums",
+   "count", "heads", "hilite"
+#ifdef TREC_MODE
+   ,"extras_for_trec"
+#endif
+  };
+
+  int i;
+  int new = -1;
+  if (New)
+    for (i = 0; i < sizeof (OutputTypeStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (New, OutputTypeStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  new = i;
+	  break;
+	}
+  if (new >= 0)
+    return (New);
+  ConstraintErrorStr = "Invalid argument [text|silent|docnums|heads|count|hilite"
+#ifdef TREC_MODE
+    "|extras_for_trec"
+#endif
+    "] required";
+  return (NULL);
+}
+
+/*
+ * Makes sure that New is a valid query type
+ *
+ */
+/* ARGSUSED */
+char *
+HiliteStyleCons (char *Old, char *New)
+{
+  static char *StyleStrs[] =
+  {"bold", "underline"};
+  int i;
+  int new = -1;
+  if (New)
+    for (i = 0; i < sizeof (StyleStrs) / sizeof (char *); i++)
+      if (!STRCASECMP (New, StyleStrs[i]))  /* [RPAP - Feb 97: WIN32 Port] */
+	{
+	  new = i;
+	  break;
+	}
+  if (new >= 0)
+    return (New);
+  ConstraintErrorStr = "Invalid argument [bold|underline] required";
+  return (NULL);
+}
+
+/* =========================================================================
+ * Function: get_output_type
+ * Description:
+ *      Map a mode string onto a mode char e.g. OUTPUT_????
+ * Input:
+ * Output:
+ *      The mode char which is a subrange value.
+ * ========================================================================= */
+
+char
+get_output_type (void)
+{
+  char *env_str = GetDefEnv ("mode", "text");
+  char ch1 = toupper (env_str[0]);
+  char ch2 = toupper (env_str[1]);
+
+  switch (ch1)
+    {
+    case 'T':
+      return OUTPUT_TEXT;
+    case 'S':
+      return OUTPUT_SILENT;
+    case 'E':
+      return OUTPUT_EXTRAS;
+    case 'C':
+      return OUTPUT_COUNT;
+    case 'D':
+      return OUTPUT_DOCNUMS;
+    case 'H':
+      if (ch2 == 'E')
+	return OUTPUT_HEADERS;
+      else
+	return OUTPUT_HILITE;
+    default:
+      FatalError (1, "Problem in output type switch");
+    }
+
+  return '\0';			/*shouldn't reach here -- keep compiler happy */
+}
+
+/* =========================================================================
+ * Function: get_query_type
+ * Description:
+ *      Map a query type string onto a char.
+ * Input:
+ * Output:
+ *      Query type char.
+ * ========================================================================= */
+
+char
+get_query_type (void)
+{
+  char *env_str = GetDefEnv ("query", "boolean");
+  char ch1 = toupper (env_str[0]);
+
+  switch (ch1)
+    {
+    case 'R':
+      return QUERY_RANKED;
+    case 'A':
+      return QUERY_APPROX;
+    case 'B':
+      return QUERY_BOOLEAN;
+    case 'D':
+      return QUERY_DOCNUMS;
+    default:
+      FatalError (1, "Problem in query type switch");
+    }
+
+  return '\0';			/*shouldn't reach here */
+}
+
+
+
+/*
+ * This initialises certain environment variables
+ *
+ */
+void 
+InitEnv (void)
+{
+  SetEnv ("hilite_style", "underline", HiliteStyleCons);	/*[TS:Sep/94] */
+  SetEnv ("briefstats", "off", BooleanCons);
+  SetEnv ("diskstats", "off", BooleanCons);
+  SetEnv ("expert", "false", BooleanCons);
+  SetEnv ("mgdir", getenv ("MGDATA") ? getenv ("MGDATA") : ".", NULL);
+  SetEnv ("mgname", "", NULL);
+  SetEnv ("maxdocs", "all", MaxDocsCons);
+  SetEnv ("memstats", "off", BooleanCons);
+  SetEnv ("mode", "text", OutputTypeCons);
+  SetEnv ("pager", getenv ("PAGER") ? getenv ("PAGER") : "more", NULL);
+  SetEnv ("qfreq", "true", BooleanCons);
+  SetEnv ("query", "boolean", QueryCons);
+  SetEnv ("sizestats", "off", BooleanCons);
+  SetEnv ("timestats", "off", BooleanCons);
+  SetEnv ("verbatim", "off", BooleanCons);
+  SetEnv ("sorted_terms", "on", BooleanCons);
+  SetEnv ("accumulator_method", "array", AccumCons);
+  SetEnv ("stop_at_max_accum", "off", BooleanCons);
+  SetEnv ("buffer", "1048576", BufferCons);
+  SetEnv ("max_accumulators", "50000", MaxNodesCons);
+  SetEnv ("max_terms", "all", MaxTermsCons);
+  SetEnv ("maxparas", "1000", MaxParasCons);
+  SetEnv ("hash_tbl_size", "1000", MaxHashCons);
+  SetEnv ("skip_dump", "skips.%d", NULL);
+  SetEnv ("ranked_doc_sepstr", "---------------------------------- %n %w\\n", NULL);
+  SetEnv ("doc_sepstr", "---------------------------------- %n\\n", NULL);
+  SetEnv ("para_sepstr", "\\n######## PARAGRAPH %n ########\\n", NULL);
+  SetEnv ("para_start", "***** Weight = %w *****\\n", NULL);
+  SetEnv ("terminator", "", NULL);
+  SetEnv ("heads_length", "50", MaxHeadsCons);
+  SetEnv ("optimise_type", "1", OptimiseCons);	/*[TS:Mar/95] */
+  SetEnv ("casefold", "on", BooleanCons);  /* [RPAP - Jan 97: Stem Index Change] */
+  SetEnv ("stem", "on", BooleanCons);  /* [RPAP - Jan 97: Stem Index Change] */
+  SetEnv ("term_freq", "off", BooleanCons);  /* [RPAP - Feb 97: Term Frequency] */
+  SetEnv ("maxnumeric", "4", MaxNumericCons);  /* [sjboddie - Jun 2002: Max Numeric word length] */
+}
+
+
+void 
+UninitEnv (void)
+{
+  char *name;
+  while (PopEnv () == 0);
+  while ((name = GetEnvName (0)) != 0)
+    UnsetEnv (name, 1);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/environment.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/environment.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/environment.h	(revision 10506)
@@ -0,0 +1,61 @@
+/**************************************************************************
+ *
+ * environment.h -- mgquery environment functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef ENVIRONMENT_H
+#define ENVIRONMENT_H
+
+#define OUTPUT_TEXT     'T'
+#define OUTPUT_HEADERS  'H'
+#define OUTPUT_SILENT   'S'
+#define OUTPUT_EXTRAS   'E'
+#define OUTPUT_HILITE   'I'
+#define OUTPUT_COUNT    'C'
+#define OUTPUT_DOCNUMS  'D'
+
+#define QUERY_RANKED    'R'
+#define QUERY_APPROX    'A'
+#define QUERY_BOOLEAN   'B'
+#define QUERY_DOCNUMS   'D'
+
+
+char get_output_type (void);
+char get_query_type (void);
+
+extern char *ConstraintErrorStr;
+int SetEnv (char *name, char *data, char *(*Constraint) (char *, char *));
+char *GetEnv (char *name);
+char *GetDefEnv (char *name, char *def);
+int UnsetEnv (char *name, int Force);
+char *de_escape_string (char *s);
+int PushEnv (void);
+int PopEnv (void);
+int EnvStackHeight (void);
+char *GetEnvName (int i);
+int BooleanEnv (char *data, int def);
+long IntEnv (char *data, long def);
+
+void InitEnv (void);
+void UninitEnv (void);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/globals.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/globals.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/globals.h	(revision 10506)
@@ -0,0 +1,32 @@
+/**************************************************************************
+ *
+ * globals.h -- Some global stuff for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_GLOBALS
+#define H_GLOBALS
+
+
+extern FILE *OutFile;
+extern FILE *InFile;
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/hash.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/hash.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/hash.h	(revision 10506)
@@ -0,0 +1,44 @@
+/**************************************************************************
+ *
+ * hash.h -- Hash function
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_HASH
+#define H_HASH
+
+
+
+#define HASH(h, step, wd, tablesize)			\
+	do {						\
+		register u_char *p=wd;			\
+		register long len = *p++;		\
+		register unsigned long hval;		\
+		if (len>25) len = 25;			\
+		for (hval=0; len; --len)		\
+		  hval = (hval << 5) - hval + *p++;	\
+		step = hval % (tablesize - 2) + 1;	\
+		h = hval % tablesize;			\
+	} while (0)
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/help.mg.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/help.mg.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/help.mg.h	(revision 10506)
@@ -0,0 +1,320 @@
+static char *help_str[] = {
+"\n",
+"			  HELP for mgquery\n",
+"		   ================================\n",
+"\n",
+"The text is a summary of the information in the \"mgquery\" manual pages.\n",
+"\n",
+"The input to 'mgquery' consists of a series of input lines. The backslash\n",
+"character (\"\\\") is used at the end of lines to indicate that input \n",
+"continues on the next line.\n",
+"\n",
+"Input lines on which the first character is a dot (\".\") are commands to\n",
+"the mgquery program. Input lines that do not start with a dot are queries.\n",
+"\n",
+"A query consists of two parts. One part is a boolean or ranked query that\n",
+"identifies documents. The second part is a post-processing pattern matching\n",
+"operation. Any text between the first speech mark (\") and the last speech\n",
+"mark is considered to the a post-processing pattern. \n",
+"\n",
+"\n",
+"The following command are available :-\n",
+"\n",
+"    .help	     - displays this text.\n",
+"    .quit            - quits the program.\n",
+"    .set name value  - sets parameter \"name\" to \"value\" . If the parameter\n",
+"                       is a boolean parameter and value is omitted the\n",
+"	    	       parameter will be inverted (i.e. if it is true it\n",
+"		       will change to false, if it is false it will change\n",
+"		       to true).\n",
+"    .unset name      - deletes parameter \"name\"\n",
+"    .reset           - sets all the parameters to their initial state.\n",
+"    .display         - displays the values of all the current parameters.\n",
+"    .push            - pushes the current parameters on to a stack.\n",
+"    .pop             - destroys the current parameters and pops a new set\n",
+"                       of parameters off the stack.\n",
+"    .output arg      - This is used to specify where to send the documents.\n",
+"                       Arg may one be of the following:\n",
+"		       > filename  : Send output to the specified file.\n",
+"		       >> filename : Append output to the specified file.\n",
+"                       | command   : The output is piped into command, \n",
+"                                     which is executed by sh.\n",
+"    .input arg       - This is used to specify where input comes from.\n",
+"                       Arg may one be of the following:\n",
+"		       < filename  : Get the input from the specified\n",
+"                                     file.\n",
+"                       | command   : The input comes from the standard\n",
+"                                     output of command, which is executed\n",
+"                                     by sh.\n",
+"\n",
+"On startup the mgquery program reads from the file .mgrc a sequence \n",
+"of commands (NOTE: The .mgrc file may not contain any queries). mgquery \n",
+"first looks for .mgrc in the current directory and then in the users home \n",
+"directory. Lines starting with a '#' in the .mgrc file are considered to\n",
+"be comments and are ignored.\n",
+"\n",
+"The following parameters (used in the .set and .unset commands) are \n",
+"predefined and have special significance :-\n",
+"\n",
+"accumulator_method = `array'\n",
+"	This parameter is used during ranking, and specifies how the\n",
+"	weight for each document should be accumulated. The following\n",
+"	methods are available `array', `splay_tree', `hash_table', and\n",
+"	`list'.\n",
+"\n",
+"briefstats = `off'\n",
+"	This is a boolean parameter that determines whether the the\n",
+"	totals for disk, memory and time usage statistics will be \n",
+"	displayed. at the end of each query. \n",
+"	NOTE: this takes precedence over the parameters \"diskstats\",\n",
+"	\"memstats\" and \"timestats\". This parameter may take the values \n",
+"	`yes', `no', `true', `false', `on' or `off'.\n",
+"\n",
+"buffer = `1048576'\n",
+"	When the documents are being read in they are read into a \n",
+"	buffer of this size and then displayed from this buffer. If \n",
+"        the documents are larger than this buffer the buffer is\n",
+"	expanded automatically. Having a large buffer gives a very\n",
+"	slight performance improvement because it allows the order of \n",
+"	disk operations to be optimised. The buffer size is measured\n",
+"	in bytes.\n",
+"\n",
+"diskstats = `off'\n",
+"	This is a boolean parameter that determines whether the disk\n",
+"	usage statistics for the preceding query will be displayed\n",
+"	after each query. This parameter may take the values `yes',\n",
+"	`no', `true', `false', `on' or `off'.\n",
+"\n",
+"doc_sepstr = `---------------------------------- %n\\n'\n",
+"	This specifies the string that will be used to separate \n",
+"	documents when they are displayed for `boolean' or `docnums'\n",
+"	queries. The standard C escape character sequences (see the \n",
+"	man page) may be used to place special characters in the \n",
+"	string. For example, a newline would the `\\n'. To include a `%'\n",
+"	use the sequence `%%'. To include the MG document number use\n",
+"	the sequence `%n'.\n",
+"\n",
+"expert = `false'\n",
+"	If this is true then a lot of the waffle that the program \n",
+"	spits out is suppressed. This parameter may take the values\n",
+"	`yes', `no', `true', `false', `on' or `off'.\n",
+"\n",
+"hash_tbl_size = `1000'\n",
+"	One of the options during ranking queries is to use a hash \n",
+"	table to accumulate the weights for each document. The hash \n",
+"	table is a simple chained type. This parameter specifies the \n",
+"	size of the hash table and may take any value between 8 and\n",
+"	268435456. \n",
+"\n",
+"heads_length = `50'\n",
+"	When the mode is `heads' this specifies the number of \n",
+"	characters that	will be output for each document.\n",
+"\n",
+"maxdocs = `all'\n",
+"	The maximum number of documents to display in response to a\n",
+"	query. This parameter may take on a numeric value between 1 \n",
+"	and 429467295 or the word `all'.\n",
+"\n",
+"maxparas = `1000'\n",
+"	The maximum number of paragraphs to identify during a ranked\n",
+"	query with paragraph indexing. After the paragraphs have been\n",
+"	identified the paragraphs are converted into documents, and \n",
+"	because some of the paragraphs may refer to the same documents \n",
+"	the final number of answers may be less that maxparas. The \n",
+"	maxdocs parameter will then be applied. This parameter may \n",
+"	take on a numeric value between 1 and 429467295.\n",
+"\n",
+"max_accumulators = `50000'\n",
+"	This parameter limits the number of different paragraph/\n",
+"	document numbers to be accumulated during ranked queries when \n",
+"	the parameter `accumulator_method` is set to `splay_tree',\n",
+"	`hash_table', or `list'.  This parameter may take any value \n",
+"	between 8 and 268435456.\n",
+"\n",
+"max_terms = `all'\n",
+"	This parameter limits the number of terms that will actually\n",
+"	be used during a ranked query. If more terms than the number\n",
+"	specified by max_terms are entered, then the extra terms will\n",
+"	be discarded. If `sorted_terms' is on then the limiting will \n",
+"	be done after the terms have been sorted. This parameter may\n",
+"	take any value between 1 and 429467295 or the word `all'.\n",
+"\n",
+"memstats = `off'\n",
+"	This is a boolean parameter that determines whether the memory \n",
+"	usage statistics for the preceding query will be displayed\n",
+"	after each query. This parameter may take the values `yes', \n",
+"	`no', `true', `false', `on' or `off'.\n",
+"\n",
+"mgdir = `.'\n",
+"	This specifies the directory where the MG files may be found.\n",
+"	If the environment variable `MGDATA' is set then `mgdir' is\n",
+"	initialised to the value in `MGDATA'.\n",
+"\n",
+"mgname = `'\n",
+"	This specifies the name of the MG database to process.\n",
+"\n",
+"mode = `text'\n",
+"	This specifies how documents should be displayed when they\n",
+"	are retrieved it may take four different values `text', \n",
+"	`docnums', `silent', `heads' or `count'. `text' displays \n",
+"	the contents of the document. `docnums' displays only the\n",
+"	document numbers. `Silent' retrieves all the documents but\n",
+"	displays nothing except how many documents were retrieved.\n",
+"	This mode is intended to be used in timing experiments. \n",
+"	`Heads` is used to print out the head of each document.\n",
+"	`Count' does the minimum amount of work required to determine\n",
+"	how many documents would be retrieved, but does not retrieve\n",
+"	them.\n",
+"\n",
+"pager = `more'\n",
+"	This is the name of the program that will be used to display\n",
+"	the help and the retrieved documents. If the environment \n",
+"	variable \"PAGER\" is defined then `pager' takes on that value.\n",
+"\n",
+"para_sepstr = `\\n######## PARAGRAPH %n ########\\n'\n",
+"	This specifies the string that will be used to separate \n",
+"	paragraphs. The standard C escape character sequences (see the \n",
+"	man page) may be used to place special characters in the \n",
+"	string. For example, a newline would the `\\n'. To include a `%'\n",
+"	use the sequence `%%'. To include the paragraph number within\n",
+"	the document use the sequence `%n'.\n",
+"\n",
+"para_start = `***** Weight = %w *****\\n'\n",
+"	This specifies the string that will be used at the head of \n",
+"	paragraphs for a paraghaph level index following a ranked query.\n",
+"	The standard C escape character sequences (see the man page)\n",
+"	may be used to place special characters in the string. For \n",
+"	example, a newline would the `\\n'. To include a `%' use the\n",
+"	sequence `%%'. To include the paragraph weight use the \n",
+"	sequence `%w'.\n",
+"\n",
+"qfreq = `true'\n",
+"	This determine whether the ranked queries will take into \n",
+"	account the number of times each query term is specified.\n",
+"	When this is `true' the number of times a term appears in\n",
+"	the query is used in the ranking. When this is `false' all \n",
+"	query term are assumed to occur only once. This parameter\n",
+"	may take the values `yes', `no', `true', `false', `on' or\n",
+"	`off'.\n",
+"\n",
+"query = `boolean'\n",
+"	This specifies the type of queries that are to be specified.\n",
+"	It can take four different values `boolean', `ranked', \n",
+"	`docnums' or `approx-ranked'. \n",
+"\n",
+"	`boolean' is for boolean queries. \n",
+"		The yacc grammar for boolean queries is as follows :-\n",
+"\n",
+"		query   : or;\n",
+" \n",
+"		or      : or '|' and\n",
+"		        | and ;	\n",
+" \n",
+"		and     : and '&' not\n",
+"        		| and not\n",
+"        		| not ;\n",
+"\n",
+"		not     : term\n",
+"		        | '!' not ;\n",
+" \n",
+"		term    : TERM\n",
+"		        | '(' or ')' ;\n",
+" \n",
+"\n",
+"\n",
+"\n",
+"	`ranked' and `approx-ranked' are for queries ranked by the\n",
+"		cosine measure. `approx-ranked' uses only the low\n",
+"		precision document lengths, and therefore only\n",
+"		produces an approximation to full cosine ranking.\n",
+"\n",
+"		query   : TERM\n",
+"      			| query TERM ;\n",
+"	\n",
+"	`docnums' allows the entry of document numbers. Multiple \n",
+"		numbers separated by spaces may be specified\n",
+"		or ranges separated by hyphens.\n",
+"\n",
+"\n",
+"		query   : range\n",
+"			| query range ;\n",
+"\n",
+"\n",
+"		range   : num\n",
+"			| num '-' num ;\n",
+"\n",
+"\n",
+"ranked_doc_sepstr = `---------------------------------- %n %w\\n'\n",
+"	This specifies the string that will be used to separate \n",
+"	documents when they are displayed for `ranked' or \n",
+"	`approx-ranked'	queries. The standard C escape character \n",
+"	sequences (see the man page) may be used to place special\n",
+"	characters in the string. For example, a newline would the\n",
+"	`\\n'. To include a `%' use the sequence `%%'. To include the\n",
+"	MG document number use the sequence `%n'. To include the\n",
+"	document weight use the sequence `%w'.\n",
+"\n",
+"sizestats = `false'\n",
+"	If this is true then various numbers are output at the end\n",
+"	of each query indicating what went on during the query. \n",
+"	This parameter may take the values `yes', `no', `true', \n",
+"	`false', `on' or `off'.\n",
+"\n",
+"skip_dump = `skips.%d'\n",
+"	If this parameter is set then during ranked queries on skipped\n",
+"	inverted files when `accumulator_method' is set to `splay_tree',\n",
+"	`hash_table', or `list` a file will be produced in the current\n",
+"	directory. The name of the file is the value of this parameter,\n",
+"	a `%d' in the file name will be replaced with the process id of\n",
+"	mgquery. This file will contain information about the usage of\n",
+"	skips during the query processing. This option is expensive; \n",
+"	use `.unset skip_dump' to obtain optimal performance.\n",
+"\n",
+"sorted_terms = `on'\n",
+"	This specifies whether of not the terms should be sorted into\n",
+"	decreasing occurrence in documents so that the least often\n",
+"	occurring terms are processed first when ranked queries are\n",
+"	being done. When this is true the terms are sorted. When this\n",
+"	is false the terms are not sorted and are instead processed in\n",
+"	order of occurrence. This parameter may take the values `yes',\n",
+"	`no', `true', `false', `on' or `off'.\n",
+"\n",
+"\n",
+"stop_at_max_accum = `on'\n",
+"	This specifies what should happen when the maximum number of\n",
+"	accumulators set by `max_accumulators' is reached. When this\n",
+"	is true the the processing of terms is stopped at the completion\n",
+"	of the current term. When this is false processing continues but\n",
+"	no new accumulators are created. This parameter may take the \n",
+"	values `yes', `no', `true', `false', `on' or `off'.\n",
+"\n",
+"terminator = `'\n",
+"	This specifies the string that will be output after the	last\n",
+"	document from the previous query has been output. The standard\n",
+"	C escape character sequences (see the man page) may be used to\n",
+"	place special characters in the string. For example, a newline\n",
+"	would the `\\n'. To include a `%' use the sequence `%%'.\n",
+"	\n",
+"\n",
+"timestats = `false'\n",
+"	If this is true then the time to process a query is displayed\n",
+"	in both real time and CPU time. This parameter may take the\n",
+"	values `yes', `no', `true', `false', `on' or `off'.\n",
+"\n",
+"verbatim = `off'\n",
+"	This is a boolean parameter that determines whether the program\n",
+"	should attempt to do a regular expression match on the retrieved\n",
+"	text. If verbatim is `on' and a post-processing strng is specified\n",
+"	with the query then the post-processing string will be searched for\n",
+"	in the documents just before they are displayed. If the string is\n",
+"	found the document will be displayed, if not the document will not\n",
+"	be displayed. If verbatim is `off' the post-processing string will\n",
+"	be considered a regular expression like in `vi' or `egrep'.\n",
+"	E.G. If verbatim is `on', \"and.*the\" will look for the 8 character\n",
+"	     sequence \"and.*the\". If verbatim is `off', \"and.*the\" will\n",
+"	     look for the sequence \"and\" followed somewhere later in the\n",
+"	     document by the sequence \"the\".\n",
+"	This parameter may take the values `yes', `no', `true', `false',\n",
+"	`on' or `off'.\n",
+"\n",
+"\n"};
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/help.mg.src
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/help.mg.src	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/help.mg.src	(revision 10506)
@@ -0,0 +1,347 @@
+###########################################################################
+#
+# help.mg.src -- Source for the help command
+# Copyright (C) 1994  Neil Sharman
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)help.mg.src	1.8 21 Mar 1994
+#
+###########################################################################
+#
+# The help file for mgquery.  
+# Lines starting with '#' are treated as comments and are discarded when
+# the 'help.mg.h' file is produced
+#
+###########################################################################
+
+			  HELP for mgquery
+		   ================================
+
+The text is a summary of the information in the "mgquery" manual pages.
+
+The input to 'mgquery' consists of a series of input lines. The backslash
+character ("\") is used at the end of lines to indicate that input 
+continues on the next line.
+
+Input lines on which the first character is a dot (".") are commands to
+the mgquery program. Input lines that do not start with a dot are queries.
+
+A query consists of two parts. One part is a boolean or ranked query that
+identifies documents. The second part is a post-processing pattern matching
+operation. Any text between the first speech mark (") and the last speech
+mark is considered to the a post-processing pattern. 
+
+
+The following command are available :-
+
+    .help	     - displays this text.
+    .quit            - quits the program.
+    .set name value  - sets parameter "name" to "value" . If the parameter
+                       is a boolean parameter and value is omitted the
+	    	       parameter will be inverted (i.e. if it is true it
+		       will change to false, if it is false it will change
+		       to true).
+    .unset name      - deletes parameter "name"
+    .reset           - sets all the parameters to their initial state.
+    .display         - displays the values of all the current parameters.
+    .push            - pushes the current parameters on to a stack.
+    .pop             - destroys the current parameters and pops a new set
+                       of parameters off the stack.
+    .output arg      - This is used to specify where to send the documents.
+                       Arg may one be of the following:
+		       > filename  : Send output to the specified file.
+		       >> filename : Append output to the specified file.
+                       | command   : The output is piped into command, 
+                                     which is executed by sh.
+    .input arg       - This is used to specify where input comes from.
+                       Arg may one be of the following:
+		       < filename  : Get the input from the specified
+                                     file.
+                       | command   : The input comes from the standard
+                                     output of command, which is executed
+                                     by sh.
+
+On startup the mgquery program reads from the file .mgrc a sequence 
+of commands (NOTE: The .mgrc file may not contain any queries). mgquery 
+first looks for .mgrc in the current directory and then in the users home 
+directory. Lines starting with a '#' in the .mgrc file are considered to
+be comments and are ignored.
+
+The following parameters (used in the .set and .unset commands) are 
+predefined and have special significance :-
+
+accumulator_method = `array'
+	This parameter is used during ranking, and specifies how the
+	weight for each document should be accumulated. The following
+	methods are available `array', `splay_tree', `hash_table', and
+	`list'.
+
+briefstats = `off'
+	This is a boolean parameter that determines whether the the
+	totals for disk, memory and time usage statistics will be 
+	displayed. at the end of each query. 
+	NOTE: this takes precedence over the parameters "diskstats",
+	"memstats" and "timestats". This parameter may take the values 
+	`yes', `no', `true', `false', `on' or `off'.
+
+buffer = `1048576'
+	When the documents are being read in they are read into a 
+	buffer of this size and then displayed from this buffer. If 
+        the documents are larger than this buffer the buffer is
+	expanded automatically. Having a large buffer gives a very
+	slight performance improvement because it allows the order of 
+	disk operations to be optimised. The buffer size is measured
+	in bytes.
+
+diskstats = `off'
+	This is a boolean parameter that determines whether the disk
+	usage statistics for the preceding query will be displayed
+	after each query. This parameter may take the values `yes',
+	`no', `true', `false', `on' or `off'.
+
+doc_sepstr = `---------------------------------- %n\n'
+	This specifies the string that will be used to separate 
+	documents when they are displayed for `boolean' or `docnums'
+	queries. The standard C escape character sequences (see the 
+	man page) may be used to place special characters in the 
+	string. For example, a newline would the `\n'. To include a `%'
+	use the sequence `%%'. To include the MG document number use
+	the sequence `%n'.
+
+expert = `false'
+	If this is true then a lot of the waffle that the program 
+	spits out is suppressed. This parameter may take the values
+	`yes', `no', `true', `false', `on' or `off'.
+
+hash_tbl_size = `1000'
+	One of the options during ranking queries is to use a hash 
+	table to accumulate the weights for each document. The hash 
+	table is a simple chained type. This parameter specifies the 
+	size of the hash table and may take any value between 8 and
+	268435456. 
+
+heads_length = `50'
+	When the mode is `heads' this specifies the number of 
+	characters that	will be output for each document.
+
+maxdocs = `all'
+	The maximum number of documents to display in response to a
+	query. This parameter may take on a numeric value between 1 
+	and 429467295 or the word `all'.
+
+maxparas = `1000'
+	The maximum number of paragraphs to identify during a ranked
+	query with paragraph indexing. After the paragraphs have been
+	identified the paragraphs are converted into documents, and 
+	because some of the paragraphs may refer to the same documents 
+	the final number of answers may be less that maxparas. The 
+	maxdocs parameter will then be applied. This parameter may 
+	take on a numeric value between 1 and 429467295.
+
+max_accumulators = `50000'
+	This parameter limits the number of different paragraph/
+	document numbers to be accumulated during ranked queries when 
+	the parameter `accumulator_method` is set to `splay_tree',
+	`hash_table', or `list'.  This parameter may take any value 
+	between 8 and 268435456.
+
+max_terms = `all'
+	This parameter limits the number of terms that will actually
+	be used during a ranked query. If more terms than the number
+	specified by max_terms are entered, then the extra terms will
+	be discarded. If `sorted_terms' is on then the limiting will 
+	be done after the terms have been sorted. This parameter may
+	take any value between 1 and 429467295 or the word `all'.
+
+memstats = `off'
+	This is a boolean parameter that determines whether the memory 
+	usage statistics for the preceding query will be displayed
+	after each query. This parameter may take the values `yes', 
+	`no', `true', `false', `on' or `off'.
+
+mgdir = `.'
+	This specifies the directory where the MG files may be found.
+	If the environment variable `MGDATA' is set then `mgdir' is
+	initialised to the value in `MGDATA'.
+
+mgname = `'
+	This specifies the name of the MG database to process.
+
+mode = `text'
+	This specifies how documents should be displayed when they
+	are retrieved it may take four different values `text', 
+	`docnums', `silent', `heads' or `count'. `text' displays 
+	the contents of the document. `docnums' displays only the
+	document numbers. `Silent' retrieves all the documents but
+	displays nothing except how many documents were retrieved.
+	This mode is intended to be used in timing experiments. 
+	`Heads` is used to print out the head of each document.
+	`Count' does the minimum amount of work required to determine
+	how many documents would be retrieved, but does not retrieve
+	them.
+
+pager = `more'
+	This is the name of the program that will be used to display
+	the help and the retrieved documents. If the environment 
+	variable "PAGER" is defined then `pager' takes on that value.
+
+para_sepstr = `\n######## PARAGRAPH %n ########\n'
+	This specifies the string that will be used to separate 
+	paragraphs. The standard C escape character sequences (see the 
+	man page) may be used to place special characters in the 
+	string. For example, a newline would the `\n'. To include a `%'
+	use the sequence `%%'. To include the paragraph number within
+	the document use the sequence `%n'.
+
+para_start = `***** Weight = %w *****\n'
+	This specifies the string that will be used at the head of 
+	paragraphs for a paraghaph level index following a ranked query.
+	The standard C escape character sequences (see the man page)
+	may be used to place special characters in the string. For 
+	example, a newline would the `\n'. To include a `%' use the
+	sequence `%%'. To include the paragraph weight use the 
+	sequence `%w'.
+
+qfreq = `true'
+	This determine whether the ranked queries will take into 
+	account the number of times each query term is specified.
+	When this is `true' the number of times a term appears in
+	the query is used in the ranking. When this is `false' all 
+	query term are assumed to occur only once. This parameter
+	may take the values `yes', `no', `true', `false', `on' or
+	`off'.
+
+query = `boolean'
+	This specifies the type of queries that are to be specified.
+	It can take four different values `boolean', `ranked', 
+	`docnums' or `approx-ranked'. 
+
+	`boolean' is for boolean queries. 
+		The yacc grammar for boolean queries is as follows :-
+
+		query   : or;
+ 
+		or      : or '|' and
+		        | and ;	
+ 
+		and     : and '&' not
+        		| and not
+        		| not ;
+
+		not     : term
+		        | '!' not ;
+ 
+		term    : TERM
+		        | '(' or ')' ;
+ 
+
+
+
+	`ranked' and `approx-ranked' are for queries ranked by the
+		cosine measure. `approx-ranked' uses only the low
+		precision document lengths, and therefore only
+		produces an approximation to full cosine ranking.
+
+		query   : TERM
+      			| query TERM ;
+	
+	`docnums' allows the entry of document numbers. Multiple 
+		numbers separated by spaces may be specified
+		or ranges separated by hyphens.
+
+
+		query   : range
+			| query range ;
+
+
+		range   : num
+			| num '-' num ;
+
+
+ranked_doc_sepstr = `---------------------------------- %n %w\n'
+	This specifies the string that will be used to separate 
+	documents when they are displayed for `ranked' or 
+	`approx-ranked'	queries. The standard C escape character 
+	sequences (see the man page) may be used to place special
+	characters in the string. For example, a newline would the
+	`\n'. To include a `%' use the sequence `%%'. To include the
+	MG document number use the sequence `%n'. To include the
+	document weight use the sequence `%w'.
+
+sizestats = `false'
+	If this is true then various numbers are output at the end
+	of each query indicating what went on during the query. 
+	This parameter may take the values `yes', `no', `true', 
+	`false', `on' or `off'.
+
+skip_dump = `skips.%d'
+	If this parameter is set then during ranked queries on skipped
+	inverted files when `accumulator_method' is set to `splay_tree',
+	`hash_table', or `list` a file will be produced in the current
+	directory. The name of the file is the value of this parameter,
+	a `%d' in the file name will be replaced with the process id of
+	mgquery. This file will contain information about the usage of
+	skips during the query processing. This option is expensive; 
+	use `.unset skip_dump' to obtain optimal performance.
+
+sorted_terms = `on'
+	This specifies whether of not the terms should be sorted into
+	decreasing occurrence in documents so that the least often
+	occurring terms are processed first when ranked queries are
+	being done. When this is true the terms are sorted. When this
+	is false the terms are not sorted and are instead processed in
+	order of occurrence. This parameter may take the values `yes',
+	`no', `true', `false', `on' or `off'.
+
+
+stop_at_max_accum = `on'
+	This specifies what should happen when the maximum number of
+	accumulators set by `max_accumulators' is reached. When this
+	is true the the processing of terms is stopped at the completion
+	of the current term. When this is false processing continues but
+	no new accumulators are created. This parameter may take the 
+	values `yes', `no', `true', `false', `on' or `off'.
+
+terminator = `'
+	This specifies the string that will be output after the	last
+	document from the previous query has been output. The standard
+	C escape character sequences (see the man page) may be used to
+	place special characters in the string. For example, a newline
+	would the `\n'. To include a `%' use the sequence `%%'.
+	
+
+timestats = `false'
+	If this is true then the time to process a query is displayed
+	in both real time and CPU time. This parameter may take the
+	values `yes', `no', `true', `false', `on' or `off'.
+
+verbatim = `off'
+	This is a boolean parameter that determines whether the program
+	should attempt to do a regular expression match on the retrieved
+	text. If verbatim is `on' and a post-processing strng is specified
+	with the query then the post-processing string will be searched for
+	in the documents just before they are displayed. If the string is
+	found the document will be displayed, if not the document will not
+	be displayed. If verbatim is `off' the post-processing string will
+	be considered a regular expression like in `vi' or `egrep'.
+	E.G. If verbatim is `on', "and.*the" will look for the 8 character
+	     sequence "and.*the". If verbatim is `off', "and.*the" will
+	     look for the sequence "and" followed somewhere later in the
+	     document by the sequence "the".
+	This parameter may take the values `yes', `no', `true', `false',
+	`on' or `off'.
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/invf.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/invf.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/invf.h	(revision 10506)
@@ -0,0 +1,79 @@
+/**************************************************************************
+ *
+ * invf.h -- Data structures for inverted files
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+
+#ifndef H_INVF
+#define H_INVF
+
+/* NOTE: This does not include the magic number */
+struct invf_dict_header
+  {
+    unsigned long lookback;
+    unsigned long dict_size;
+    unsigned long total_bytes;
+    unsigned long index_string_bytes;
+    double input_bytes; /* [RJM 07/97: 4G limit] */
+    unsigned long num_of_docs;
+    unsigned long static_num_of_docs;
+    unsigned long num_of_words;
+    unsigned long stemmer_num;
+    unsigned long stem_method;
+  };
+
+struct stem_dict_header
+  {
+    unsigned long lookback;
+    unsigned long block_size;
+    unsigned long num_blocks;
+    unsigned long blocks_start;
+    unsigned long index_chars;
+    unsigned long num_of_docs;
+    unsigned long static_num_of_docs;
+    unsigned long num_of_words;
+    unsigned long stemmer_num;
+    unsigned long stem_method;
+    unsigned long indexed;       /* [RPAP - Jan 97: Stem Index Change] */
+  };
+
+struct invf_file_header
+  {
+    unsigned long no_of_words;
+    unsigned long no_of_ptrs;
+    unsigned long skip_mode;
+    unsigned long params[16];
+    unsigned long InvfLevel;
+  };
+
+/* [RPAP - Jan 97: Stem Index Change] */
+struct stem_idx_header
+  {
+    unsigned long lookback;
+    unsigned long block_size;
+    unsigned long num_blocks;
+    unsigned long blocks_start;
+    unsigned long index_chars;
+    unsigned long num_of_words;
+  };
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/invf_get.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/invf_get.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/invf_get.c	(revision 10506)
@@ -0,0 +1,1666 @@
+/**************************************************************************
+ *
+ * invf_get.c -- Inverted file reading routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "filestats.h"
+#include "timing.h"
+#include "bitio_gen.h"
+#include "bitio_m_mem.h"
+#include "bitio_m.h"
+#include "sptree.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "invf_get.h"
+#include "mg_errors.h"
+
+#define SKIPPING
+#define SHORT_CUT
+
+struct pool
+  {
+    int length, pos;
+    struct pool *next;
+    Invf_Doc_Entry ide[1];
+  };
+
+static int skip_header = 0;
+
+static char skip_header_text0[] =
+"#######################################################################\n"
+"#\n"
+"# 1\tWord number.\n"
+"# 2\tNumber of time the word occurs in the collection.\n"
+"# 3\tNumber of documents the word occurs in.\n"
+"# 4\tThe word.\n"
+"# 5\tNumber of docnum/word_count entries decoded.\n"
+"# 6\tNumber of hits.\n"
+"# 7\tNumber of entries in the splay tree or hash table.\n"
+"# 8\tAmount added to the accumulators while while processing this word.\n"
+"#\n"
+"#######################################################################\n";
+
+static char skip_header_text1[] =
+"#######################################################################\n"
+"#\n"
+"# 1\tWord number.\n"
+"# 2\tNumber of time the word occurs in the collection.\n"
+"# 3\tNumber of documents the word occurs in.\n"
+"# 4\tThe word.\n"
+"# 5\tNumber of skips taken in evaluating the inverted file entry.\n"
+"# 6\tNumber of docnum/word_count entries decoded.\n"
+"# 7\tNumber of hits.\n"
+"# 8\tNumber of entries in the splay tree or hash table.\n"
+"# 9\tAmount added to the accumulators while while processing this word.\n"
+"#\n"
+"#######################################################################\n";
+
+
+static char skip_header_text2[] =
+"#######################################################################\n"
+"#\n"
+"#  1\tWord number.\n"
+"#  2\tNumber of time the word occurs in the collection.\n"
+"#  3\tNumber of documents the word occurs in.\n"
+"#  4\tThe word.\n"
+"#  5\tSkip size.\n"
+"#  6\tNumber of skips taken in evaluating the inverted file entry.\n"
+"#  7\tNumber of docnum/word_count entries decoded.\n"
+"#  8\tNumber of hits.\n"
+"#  9\tNumber of entries in the splay tree or hash table.\n"
+"# 10\tAmount added to the accumulators while while processing this word.\n"
+"#\n"
+"#######################################################################\n";
+
+static char *skip_header_text[] =
+{skip_header_text0,
+ skip_header_text1,
+ skip_header_text2};
+
+
+
+
+
+
+
+
+/**************************************************************************
+ *
+ * Code for the hash table.
+ *
+ */
+
+static Hash_Table *
+HT_create (query_data * qd, unsigned max_entries,
+	   unsigned max_size)
+{
+  unsigned es, hts;
+  Hash_Table *HT;
+  if (max_entries == 0)
+    max_entries = 8192;
+  es = sizeof (Hash_Table) + sizeof (Invf_Doc_EntryH) * (max_entries - 1);
+  hts = sizeof (Invf_Doc_EntryH *) * max_size;
+
+  HT = Xmalloc (es);
+  if (!HT)
+    return NULL;
+
+  HT->HashTable = Xmalloc (hts);
+  if (!(HT->HashTable))
+    {
+      Xfree (HT);
+      return NULL;
+    }
+
+  ChangeMemInUse (qd, es + hts);
+  bzero ((char *) (HT->HashTable), hts);
+  HT->max = max_entries;
+  HT->num = 0;
+  HT->Suplimentary_Entries = NULL;
+  HT->Suplimentary_Size = 0;
+  HT->Suplimentary_Num = 0;
+  HT->Head = NULL;
+  HT->size = max_size;
+  return HT;
+}
+
+
+static void 
+HT_Sup_create (query_data * qd, Hash_Table * HT, unsigned max_size)
+{
+  int es = sizeof (Invf_Doc_EntryH) * max_size;
+  HT->Suplimentary_Entries = Xmalloc (es);
+  if (!HT->Suplimentary_Entries)
+    return;
+  HT->Suplimentary_Size = max_size;
+  HT->Suplimentary_Num = 0;
+  ChangeMemInUse (qd, es);
+}
+
+static void 
+HT_Sup_Add (Hash_Table * HT, unsigned long DN, float Sum)
+{
+  Invf_Doc_EntryH *IDEH;
+  IDEH = &HT->Suplimentary_Entries[HT->Suplimentary_Num++];
+  IDEH->next = NULL;
+  IDEH->IDE.DocNum = DN;
+  IDEH->IDE.Sum = Sum;
+}
+
+Invf_Doc_Entry *
+HT_find (Hash_Table * HT, unsigned long DN)
+{
+  Invf_Doc_EntryH *IDEH;
+  if (!HT->HashTable)
+    FatalError (1, "Accessing the hash_table through HT_find after HT_sort");
+  IDEH = HT->HashTable[DN % HT->size];
+  while (IDEH)
+    {
+      if (IDEH->IDE.DocNum == DN)
+	return &(IDEH->IDE);
+      IDEH = IDEH->next;
+    }
+  return NULL;
+}
+
+
+static int 
+HT_insert (Hash_Table * HT,
+	   unsigned long DN, float Sum)
+{
+  Invf_Doc_EntryH **IDEH;
+  if (HT->num == HT->max)
+    return 0;
+  IDEH = &(HT->HashTable[DN % HT->size]);
+  while (*IDEH)
+    IDEH = &((*IDEH)->next);
+  *IDEH = &(HT->IDEH[HT->num++]);
+  (*IDEH)->next = NULL;
+  (*IDEH)->IDE.DocNum = DN;
+  (*IDEH)->IDE.Sum = Sum;
+  return 1;
+}
+
+
+void 
+HT_free (query_data * qd, Hash_Table * HT)
+{
+  unsigned es;
+  es = sizeof (Hash_Table) + sizeof (Invf_Doc_EntryH) * HT->max +
+    sizeof (Invf_Doc_EntryH *) * HT->size;
+  if (HT->HashTable)
+    Xfree (HT->HashTable);
+  if (HT->Suplimentary_Entries)
+    {
+      Xfree (HT->Suplimentary_Entries);
+      es += sizeof (Invf_Doc_EntryH) * HT->Suplimentary_Size;
+    }
+  Xfree (HT);
+  ChangeMemInUse (qd, -es);
+}
+
+
+static int 
+IDEH_comp (const void *a, const void *b)
+{
+  const Invf_Doc_EntryH *A = a;
+  const Invf_Doc_EntryH *B = b;
+  return A->IDE.DocNum - B->IDE.DocNum;
+}
+
+static void 
+HT_sort (query_data * qd, Hash_Table * HT)
+{
+  int i;
+  Invf_Doc_EntryH *l, *r, **b;
+  unsigned es = sizeof (Invf_Doc_EntryH *) * HT->size;
+  if (HT->HashTable)
+    Xfree (HT->HashTable);
+  HT->size = 0;
+  HT->HashTable = NULL;
+  ChangeMemInUse (qd, -es);
+
+  qsort (HT->IDEH, HT->num, sizeof (Invf_Doc_EntryH), IDEH_comp);
+
+  for (i = 0; i < HT->num - 1; i++)
+    HT->IDEH[i].next = &HT->IDEH[i + 1];
+  HT->IDEH[i].next = NULL;
+  l = HT->IDEH;
+
+  if (HT->Suplimentary_Entries)
+    {
+      for (i = 0; i < HT->Suplimentary_Num - 1; i++)
+	HT->Suplimentary_Entries[i].next = &HT->Suplimentary_Entries[i + 1];
+      HT->Suplimentary_Entries[i].next = NULL;
+    }
+  r = HT->Suplimentary_Entries;
+
+  b = &HT->Head;
+
+  while (l || r)
+    {
+      if (r && (!l || (l->IDE.DocNum > r->IDE.DocNum)))
+	{
+	  *b = r;
+	  b = &r->next;
+	  r = *b;
+	}
+      else
+	{
+	  *b = l;
+	  b = &l->next;
+	  l = *b;
+	}
+    }
+  *b = NULL;
+}
+
+
+
+
+
+
+/**************************************************************************
+ *
+ * Code for the hash table.
+ *
+ */
+
+static List_Table *
+LT_create (query_data * qd, unsigned max_entries)
+{
+  unsigned es;
+  List_Table *LT;
+  if (max_entries == 0)
+    max_entries = 8192;
+  es = sizeof (List_Table) + sizeof (Invf_Doc_Entry) * (max_entries - 1);
+
+  LT = Xmalloc (es);
+  if (!LT)
+    return NULL;
+
+  ChangeMemInUse (qd, es);
+  LT->max = max_entries;
+  LT->num = 0;
+  return LT;
+}
+
+
+
+Invf_Doc_Entry *
+LT_find (List_Table * LT, unsigned long DN)
+{
+  int l = 0;
+  int r = LT->num - 1;
+  int m, c;
+  while (l <= r)
+    {
+      m = (l + r) / 2;
+      c = DN - LT->IDE[m].DocNum;
+      if (c < 0)
+	r = m - 1;
+      else if (c > 0)
+	l = m + 1;
+      else
+	return &LT->IDE[m];
+    }
+  return NULL;
+}
+
+static List_Table *
+LT_add (query_data * qd, List_Table * LT,
+	unsigned long DN, float Sum)
+{
+  Invf_Doc_Entry *ide;
+
+  /* increase the size of the list if there is not enough */
+  /* room for this entry */
+  if (LT->num == LT->max)
+    {
+      int old, new, max_entries;
+      old = sizeof (List_Table) + sizeof (Invf_Doc_Entry) * LT->max;
+      max_entries = LT->max + (LT->max >> 1);
+      new = sizeof (List_Table) + sizeof (Invf_Doc_Entry) * max_entries;
+
+      LT = Xrealloc (LT, new);
+      if (!LT)
+	return NULL;
+
+      ChangeMemInUse (qd, new - old);
+      LT->max = max_entries;
+    }
+
+  /* add the entry to the end of the list */
+  ide = &LT->IDE[LT->num];
+  ide->DocNum = DN;
+  ide->Sum = Sum;
+  LT->num++;
+
+  return LT;
+}
+
+
+void 
+LT_free (query_data * qd, List_Table * LT)
+{
+  unsigned es;
+  es = sizeof (List_Table) + sizeof (Invf_Doc_Entry) * LT->max;
+  Xfree (LT);
+  ChangeMemInUse (qd, -es);
+}
+
+
+static int 
+IDE_comp (const void *a, const void *b)
+{
+  const Invf_Doc_Entry *A = a;
+  const Invf_Doc_Entry *B = b;
+  return A->DocNum - B->DocNum;
+}
+
+static void 
+LT_sort (List_Table * LT)
+{
+  qsort (LT->IDE, LT->num, sizeof (Invf_Doc_Entry), IDE_comp);
+}
+
+
+/* [RJM 07/97: Ranked Required Terms] */
+/* accumulators with a sum less than or equal to 0.0 are to be deleted */
+static void 
+LT_pack (List_Table * LT)
+{
+  int s, d = 0;
+  for (s = 0; s < LT->num; s++) {
+      if (LT->IDE[s].Sum <= 0.0) {
+	/* ignore this accumulator */
+
+      } else if (d > 0 && LT->IDE[s].DocNum == LT->IDE[d-1].DocNum) {
+	LT->IDE[d-1].Sum += LT->IDE[s].Sum;
+
+      } else {
+	if (d != s) LT->IDE[d] = LT->IDE[s];
+	d++;
+      }
+  }
+
+  if (LT->num) LT->num = d;
+}
+
+
+/**************************************************************************/
+
+
+
+invf_data *
+InitInvfFile (File * InvfFile, stemmed_dict * sd)
+{
+  invf_data *id;
+  if (!(id = Xmalloc (sizeof (invf_data))))
+    {
+      mg_errno = MG_NOMEM;
+      return NULL;
+    }
+
+  id->InvfFile = InvfFile;
+
+  Fread (&id->ifh, sizeof (id->ifh), 1, InvfFile);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  {
+    int i;
+    
+    NTOHUL(id->ifh.no_of_words);
+    NTOHUL(id->ifh.no_of_ptrs);
+    NTOHUL(id->ifh.skip_mode);
+    for (i = 0; i < 16; i++)
+      NTOHUL(id->ifh.params[i]);
+    NTOHUL(id->ifh.InvfLevel);
+  }
+
+  id->N = sd->sdh.num_of_docs;
+  id->Nstatic = sd->sdh.static_num_of_docs;
+
+  return (id);
+}
+
+
+void 
+FreeInvfData (invf_data * id)
+{
+  Xfree (id);
+}
+
+/****************************************************************************/
+
+
+static void 
+CalcBlks (query_data * qd, WordEntry * we, int *blk,
+	  int *dn_blk, int *len_blk, int *k, int *p)
+{
+  *p = we->doc_count;
+
+  *blk = BIO_Bblock_Init (qd->id->Nstatic, *p);
+  switch (qd->id->ifh.skip_mode)
+    {
+    case 1:
+      {
+	unsigned long len;
+	if (*p <= qd->id->ifh.params[0])
+	  *k = 0;
+	else
+	  {
+	    *k = qd->id->ifh.params[0];
+	    len = BIO_Bblock_Bound (qd->id->N, *p);
+	    if (qd->id->ifh.InvfLevel >= 2)
+	      len += we->count;
+	    *dn_blk = BIO_Bblock_Init (qd->sd->sdh.num_of_docs, (*p + *k - 1) / *k);
+	    *len_blk = BIO_Bblock_Init (len, (*p + *k - 1) / *k);
+	  }
+	break;
+      }
+    case 2:
+      {
+	unsigned long len;
+	if (*p <= qd->id->ifh.params[1])
+	  *k = 0;
+	else
+	  {
+	    *k = (int) (2 * sqrt (((double) (*p)) / qd->id->ifh.params[0]));
+	    if (*k <= qd->id->ifh.params[1])
+	      *k = qd->id->ifh.params[1];
+	    len = BIO_Bblock_Bound (qd->id->N, *p);
+	    if (qd->id->ifh.InvfLevel >= 2)
+	      len += we->count;
+	    *dn_blk = BIO_Bblock_Init (qd->sd->sdh.num_of_docs,
+				       (*p + *k - 1) / *k);
+	    *len_blk = BIO_Bblock_Init (len, (*p + *k - 1) / *k);
+	  }
+	break;
+      }
+    default:
+      *k = 0;
+    }
+}
+
+
+/* =========================================================================
+ * Function: GetDocsOp
+ * Description: 
+ *      if op == op_term then 
+ *        look up term in invf and decode all its entries/documents
+ *      if op == op_and_terms then 
+ *        go thru L, testing if it exists in invf using skips  
+ *        if it does exist then overwrite the entry nearer the start of the list
+ *      if op == op_and_or_terms then
+ *        go thru L, testing if it exists in invf using skips  
+ *        BUT only mark ones which are found - keep list intact
+ *      if op == op_diff_terms then     >>>> NOT tested <<<<
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+DocList *
+GetDocsOp (query_data * qd, WordEntry * we, Op_types op, DocList * L)
+{
+  u_char *buffer;
+  DocEntry *src = NULL, *dest = NULL;
+  int i;			/* index counter into inverted list */
+  unsigned long pos;
+  int next_start, next_doc_num, next_i;
+  int block_counter;		/* within counter in block */
+  int dn_blk = 0, len_blk = 0;
+  int skip_size, have_skipping;
+  int blk;			/* bblock control parameter */
+  int ft;			/* The number of documents the word occurs in */
+  unsigned long CurrDoc = 0;	/* NOTE: Document numbers start at 1 */
+  float Weight;
+
+  /* ... AND empty */
+  if (op == op_and_terms && (!L || !L->num))
+    {
+      if (L)
+	Xfree (L);
+      return MakeDocList (0);
+    }
+
+  if (op == op_term)
+    L = MakeDocList (we->doc_count);
+
+  CalcBlks (qd, we, &blk, &dn_blk, &len_blk, &skip_size, &ft);
+  have_skipping = (skip_size != 0);
+  if (!(buffer = Xmalloc (we->invf_len)))
+    return MakeDocList (0);
+
+  ChangeMemInUse (qd, we->invf_len);
+
+  qd->num_of_terms++;
+
+  /* --- Read an inverted file entry for the given word --- */
+  Fseek (qd->File_invf, we->invf_ptr, 0);
+  Fread (buffer, sizeof (char), we->invf_len, qd->File_invf);
+
+  /* Read from the buffer */
+  DECODE_START (buffer, we->invf_len);
+
+  Weight = qd->sd->sdh.num_of_words / (100 * log2 ((float) we->count + 1));
+
+  if (op != op_term)
+    dest = src = L->DE;
+  i = pos = 0;
+  next_i = next_start = next_doc_num = 0;
+  block_counter = skip_size - 1;
+
+  /* Go thru the elements of an inverted list for a term */
+  /* May not go sequentially if skipping is done */
+  while (i < ft && ((op == op_term) || src - L->DE < L->num))
+    {
+      unsigned long diff, Temp;
+
+      if (have_skipping)
+	{
+
+	  /* --- Skip to next block --- */
+	  if (op != op_term && i + skip_size < ft &&
+	      src->DocNum > next_doc_num && next_doc_num >= 0)
+	    {
+	    ShortCut:
+	      i = next_i;
+	      DECODE_SEEK (next_start);
+	      pos = next_start;
+	      CurrDoc = next_doc_num;
+	      qd->hops_taken++;
+	      block_counter = skip_size - 1;
+	    }
+
+	  /* --- Decode the skip block header --- */
+	  if (block_counter == skip_size - 1)
+	    {
+	      if (i + skip_size < ft)
+		{
+		  /* --- Decode the skip block header --- */
+		  int doc_diff, pos_diff;
+		  BBLOCK_DECODE_L (doc_diff, dn_blk, pos);
+		  next_doc_num += doc_diff;
+		  next_i += skip_size;
+		  BBLOCK_DECODE_L (pos_diff, len_blk, pos);
+		  next_start = pos + pos_diff;
+		}
+	      else
+		next_doc_num = -1;
+	    }
+
+	  /* --- Do a skip if c-set doc is higher than block header doc --- */
+	  if (op != op_term && i + skip_size < ft &&
+	      src->DocNum > next_doc_num && next_doc_num >= 0)
+	    goto ShortCut;
+
+
+	}			/*if skipping */
+
+      /* --- increment CurrDoc --- */
+      if (have_skipping && block_counter == 0 && i != ft - 1)
+	CurrDoc = next_doc_num;
+      else
+	{
+	  BBLOCK_DECODE_L (diff, blk, pos);
+	  CurrDoc += diff;
+	}
+
+      /* --- If have f_dt's then eat them up --- */
+      if (qd->id->ifh.InvfLevel >= 2)
+	GAMMA_DECODE_L (Temp, pos);	/* discard word count */
+
+      /* --- Increment counters --- */
+      qd->num_of_ptrs++;
+      i++;
+      block_counter--;
+      if (block_counter < 0)	/* ??? Why would this happen ? */
+	block_counter = skip_size - 1;
+
+      switch (op)
+	{
+	case op_term:
+	  /* --- Add the doc from invf onto the c-set list --- */
+	  L->DE[L->num].DocNum = CurrDoc;
+	  L->DE[L->num].Weight = Weight;
+	  L->DE[L->num].SeekPos = 0;
+	  L->DE[L->num].Len = 0;
+	  L->DE[L->num].CompTextBuffer = NULL;
+	  L->DE[L->num].Next = NULL;
+	  L->DE[L->num].or_included = 0;
+	  L->num++;
+	  break;
+
+	case op_and_terms:
+	case op_and_or_terms:
+	  /* --- see if have a match and save it --- */
+
+	  while (src < (L->DE + L->num) && CurrDoc > src->DocNum)
+	    {
+	      src++;
+	    }
+	  /* Unless at end of list, assert(CurrDoc <= src->DocNum) */
+
+	  /* --- Accept the doc as a candidate --- */
+	  if (src < (L->DE + L->num) && CurrDoc == src->DocNum)
+	    {
+	      if (op == op_and_terms)
+		{
+		  *dest++ = *src;
+		}
+	      else
+		{
+		  src->or_included = 1;
+		}
+	      src++;		/* Move onto next one */
+	    }
+
+	  /* If the next one to try has already been tried then move on again */
+	  if (op == op_and_or_terms)
+	    {
+	      while (src < (L->DE + L->num) && src->or_included)
+		src++;
+	    }
+
+	  break;
+
+	case op_diff_terms:
+	  while (src < (L->DE + L->num) && src->DocNum < CurrDoc)
+	    *dest++ = *src++;
+	  if (src < (L->DE + L->num) && src->DocNum == CurrDoc)
+	    src++;
+	  break;
+
+	default:
+	  break;
+	}			/*switch */
+
+    }				/*while traversing invf */
+
+  if (op == op_and_terms || op == op_diff_terms)
+    {
+      if (op == op_diff_terms)
+	while (src - L->DE < L->num)
+	  *dest++ = *src++;
+
+      /* update size of c-set */
+      L->num = dest - L->DE;
+    }
+  DECODE_DONE
+
+    Xfree (buffer);
+  ChangeMemInUse (qd, -we->invf_len);
+
+  return (L);
+}
+
+
+
+
+
+
+
+float *
+CosineDecode (query_data * qd, TermList * Terms, RankedQueryInfo * rqi)
+{
+  float *AccumulatedWeights;
+  int j, num_docs, num_terms;
+  int seen_must_match = 0; /* [RJM 07/97: Ranked Required Terms] says whether to 'and' queries or not */
+
+  num_docs = qd->sd->sdh.num_of_docs;
+  /* Create the array for the documents */
+  if (!(AccumulatedWeights = Xmalloc (num_docs * sizeof (float))))
+      return (NULL);
+
+  bzero ((char *) AccumulatedWeights, sizeof (float) * num_docs);
+  ChangeMemInUse (qd, sizeof (float) * num_docs);
+
+  if (rqi->MaxTerms == -1)
+    num_terms = Terms->num;
+  else
+    num_terms = rqi->MaxTerms < Terms->num ? rqi->MaxTerms : Terms->num;
+
+
+  /* For each word in the list . . . */
+  for (j = 0; j < num_terms; j++)
+    {
+      u_char *buffer;
+      int i, kd;
+      unsigned long next_mjr_dn = 0;
+      unsigned long CurrDocNum = 0;	/* NOTE: Document numbers start at 1 */
+      unsigned long LastDocNum = 0; /* [RJM 07/97: Ranked Required Terms] */
+      unsigned long TempDocNum = 0; /* [RJM 07/97: Ranked Required Terms] */
+      double Wqt, WordLog;
+      int dn_blk = 0, len_blk = 0, k;
+      int blk;			/* bblock control parameter */
+      int p;			/* The number of documents the word occurs in */
+      int require_match = Terms->TE[j].require_match; /* [RJM 07/97: Ranked Required Terms] */
+      WordEntry *we = &Terms->TE[j].WE;
+      CalcBlks (qd, we, &blk, &dn_blk, &len_blk, &k, &p);
+      if (!(buffer = Xmalloc (we->invf_len)))
+	break;
+
+      ChangeMemInUse (qd, we->invf_len);
+
+      Fseek (qd->File_invf, we->invf_ptr, 0);
+      Fread (buffer, sizeof (char), we->invf_len, qd->File_invf);
+
+      /* Read from the buffer */
+      DECODE_START (buffer, we->invf_len);
+
+      WordLog = log ((double) num_docs / (double) we->max_doc_count);  /* [RPAP - Jan 97: Stem Index Change] */
+
+      Wqt = (rqi->QueryFreqs ? Terms->TE[j].Count : 1) * WordLog;
+
+      qd->num_of_terms++;
+
+      kd = 0;
+      for (i = 0; i < p; i++, kd++)
+	{
+	  int Count;		/* The number of times the word occurs in a document */
+	  double Wdt;
+	  unsigned long diff;
+	  if (kd == k)
+	    {
+	      kd = 0;
+	    }
+	  if (k && kd == 0)
+	    if (i + k < p)
+	      {
+		int temp;
+		BBLOCK_DECODE (next_mjr_dn, dn_blk);
+		next_mjr_dn += CurrDocNum;
+		BBLOCK_DECODE (temp, len_blk);
+	      }
+	  if (k && kd == k - 1 && i != p - 1)
+	    CurrDocNum = next_mjr_dn;
+	  else
+	    {
+	      BBLOCK_DECODE (diff, blk);
+	      CurrDocNum += diff;
+	    }
+	  if (qd->id->ifh.InvfLevel >= 2)
+	    GAMMA_DECODE (Count);
+	  else
+	    Count = (double) we->count / p;
+	  Wdt = Count * WordLog;
+
+	  /* [RJM 07/97: Ranked Required Terms] */
+	  /* zero the weights of intermediate documents if this term is required to match */
+	  if (require_match == 1) {
+	    for (TempDocNum = LastDocNum+1; TempDocNum < CurrDocNum; TempDocNum++)
+	      AccumulatedWeights[TempDocNum - 1] = 0.0;
+	  }
+
+	  /* [RJM 07/97: Ranked Required Terms] */
+	  /* if a term has been required to match before, the weight we are */
+	  /* adding to must be non-zero */
+	  if (!seen_must_match || (AccumulatedWeights[CurrDocNum - 1] > 0.0)) {
+	      AccumulatedWeights[CurrDocNum - 1] += Wqt * Wdt;
+	  }
+
+	  qd->num_of_ptrs++;
+	  LastDocNum = CurrDocNum; /* [RJM 07/97: Ranked Required Terms] */
+	}
+
+      DECODE_DONE
+
+	Xfree (buffer);
+      ChangeMemInUse (qd, -we->invf_len);
+
+      /* [RJM 07/97: Ranked Required Terms] */
+      /* zero the remaining weights if this term is required to match */
+      if (require_match == 1) {
+	for (TempDocNum = LastDocNum+1; TempDocNum <= num_docs; TempDocNum++)
+	  AccumulatedWeights[TempDocNum - 1] = 0.0;
+	seen_must_match = 1;
+      }
+    }
+  return AccumulatedWeights;
+}
+
+
+
+static int 
+doc_comp (void *a, void *b)
+{
+  return ((Invf_Doc_Entry *) a)->DocNum - ((Invf_Doc_Entry *) b)->DocNum;
+}
+
+
+static Invf_Doc_Entry *
+get_ide (query_data * qd, Invf_Doc_Entry_Pool * pool)
+{
+  struct pool *p = pool->pool;
+  if (!p || p->pos == p->length)
+    {
+      register unsigned size = sizeof (struct pool) +
+      (pool->pool_chunks - 1) * sizeof (Invf_Doc_Entry);
+      p = malloc (size);
+      if (!p)
+	return NULL;
+      ChangeMemInUse (qd, size);
+      p->length = pool->pool_chunks;
+      p->pos = 0;
+      p->next = pool->pool;
+      pool->pool = p;
+    }
+  return &(p->ide[p->pos++]);
+}
+
+
+void 
+free_ide_pool (query_data * qd, Invf_Doc_Entry_Pool * pool)
+{
+  while (pool->pool)
+    {
+      struct pool *p = pool->pool;
+      pool->pool = p->next;
+      ChangeMemInUse (qd, -(sizeof (struct pool) + (p->length - 1) *
+			    sizeof (Invf_Doc_Entry)));
+      free (p);
+    }
+  pool->pool = NULL;
+}
+
+
+FILE *
+open_skip (char *sd)
+{
+  char buf[256];
+  if (sd == NULL || *sd == '\0')
+    return NULL;
+  sprintf (buf, sd, getpid ());
+  return fopen (buf, "a");
+}
+
+
+
+Splay_Tree *
+CosineDecodeSplay (query_data * qd, TermList * Terms,
+		   RankedQueryInfo * rqi, Invf_Doc_Entry_Pool * pool)
+{
+  Splay_Tree *Doc_Set;
+  int j, num_docs, num_terms, MoreAccum;
+  int Anding = 0;
+  FILE *sk = open_skip (rqi->skip_dump);
+  u_char indent = 0;
+  if (sk)
+    {
+      if (!skip_header)
+	{
+	  skip_header = 1;
+	  fprintf (sk, "%s", skip_header_text[qd->id->ifh.skip_mode]);
+	  fprintf (sk, "\nSkipping method %ld\n", qd->id->ifh.skip_mode);
+	  switch (qd->id->ifh.skip_mode)
+	    {
+	    case 1:
+	      fprintf (sk, "Skipping is every %ld docnums\n",
+		       qd->id->ifh.params[0]);
+	      break;
+	    case 2:
+	      fprintf (sk, "Max nodes = %ld\nNo skips smaller or equal to %ld\n",
+		       qd->id->ifh.params[0], qd->id->ifh.params[1]);
+	      break;
+	    }
+	}
+      fprintf (sk, "\n\t\t\t-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n");
+      for (j = 0; j < Terms->num; j++)
+	if (Terms->TE[j].Word[0] > indent)
+	  indent = Terms->TE[j].Word[0];
+    }
+
+  num_docs = qd->sd->sdh.num_of_docs;
+  /* Create the array for the documents */
+  Doc_Set = SP_createset (doc_comp);
+
+  pool->pool = NULL;
+  pool->pool_chunks = 1024;
+
+  if (rqi->MaxTerms == -1)
+    num_terms = Terms->num;
+  else
+    num_terms = rqi->MaxTerms < Terms->num ? rqi->MaxTerms : Terms->num;
+
+  MoreAccum = 1;
+
+  /* For each word in the list . . . */
+  for (j = 0; j < num_terms; j++)
+    {
+      int Abort = 0;
+      u_char *buffer;
+      int pos, i;
+      unsigned long CurrDocNum = 0;	/* NOTE: Document numbers start at 1 */
+      double Wqt, WordLog;
+      int dn_blk = 0, len_blk = 0, k, kd;
+      int blk;			/* bblock control parameter */
+      int p;			/* The number of documents the word occurs in */
+      WordEntry *we = &Terms->TE[j].WE;
+      Invf_Doc_Entry *next = NULL;
+      int next_i, next_doc_num, next_start;
+      int skips_taken = 0, ptrs_dec = 0;
+      double total_added = 0.0;
+      int hits = 0;
+      if (sk)
+	{
+	  fprintf (sk, "%3d : %8ld %6ld \"%.*s\"%*s", j, we->count,
+		 we->doc_count, Terms->TE[j].Word[0], Terms->TE[j].Word + 1,
+		   indent - Terms->TE[j].Word[0], "");
+	}
+
+      CalcBlks (qd, we, &blk, &dn_blk, &len_blk, &k, &p);
+      if (!(buffer = Xmalloc (we->invf_len)))
+	break;
+
+      ChangeMemInUse (qd, we->invf_len);
+
+      if (sk && qd->id->ifh.skip_mode == 2)
+	fprintf (sk, "%4d", k);
+
+      Fseek (qd->File_invf, we->invf_ptr, 0);
+      Fread (buffer, sizeof (char), we->invf_len, qd->File_invf);
+
+      /* Read from the buffer */
+      DECODE_START (buffer, we->invf_len);
+
+      WordLog = log ((double) num_docs / (double) we->max_doc_count);  /* [RPAP - Jan 97: Stem Index Change] */
+
+      Wqt = (rqi->QueryFreqs ? Terms->TE[j].Count : 1) * WordLog;
+
+      qd->num_of_terms++;
+
+      if (rqi->MaxAccums != -1 && Doc_Set->no_of_items >= rqi->MaxAccums)
+	{
+	  MoreAccum = 0;
+	  Anding = 1;
+	  next = SP_get_first (Doc_Set);
+	}
+      i = pos = 0;
+      next_i = next_start = next_doc_num = 0;
+      kd = k - 1;
+      while (i < p && (!Anding || next))
+	{
+	  int Count;		/* The number of times the occurs in a document */
+	  double Wdt;
+	  unsigned long diff;
+	  Invf_Doc_Entry ent, *mem;
+	  if (k)
+	    {
+	      if (Anding && i + k < p && next->DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		{
+		  i = next_i;
+		  DECODE_SEEK (next_start);
+		  pos = next_start;
+		  CurrDocNum = next_doc_num;
+		  qd->hops_taken++;
+		  skips_taken++;
+		  kd = k - 1;
+		}
+	      if (kd == k - 1)
+		if (i + k < p)
+		  {
+		    int doc_diff, pos_diff;
+		    BBLOCK_DECODE_L (doc_diff, dn_blk, pos);
+		    next_doc_num += doc_diff;
+		    next_i += k;
+		    BBLOCK_DECODE_L (pos_diff, len_blk, pos);
+		    next_start = pos + pos_diff;
+		  }
+		else
+		  next_doc_num = -1;
+	      if (Anding && i + k < p && next->DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		continue;
+	    }
+	  if (k && kd == 0 && i != p - 1)
+	    CurrDocNum = next_doc_num;
+	  else
+	    {
+	      BBLOCK_DECODE_L (diff, blk, pos);
+	      CurrDocNum += diff;
+	    }
+	  qd->num_of_ptrs++;
+	  ptrs_dec++;
+	  if (qd->id->ifh.InvfLevel >= 2)
+	    GAMMA_DECODE_L (Count, pos);
+	  else
+	    Count = (double) we->count / p;
+	  i++;
+	  kd--;
+	  if (kd < 0)
+	    kd = k - 1;
+	  Wdt = Count * WordLog;
+
+
+	  if (Anding)
+	    {
+	      while (next && next->DocNum < CurrDocNum - 1)
+		next = SP_get_next (Doc_Set);
+	      if (next && next->DocNum == CurrDocNum - 1)
+		{
+		  next->Sum += Wqt * Wdt;
+		  total_added += Wqt * Wdt;
+		  hits++;
+		}
+	      if (next && next->DocNum <= CurrDocNum - 1)
+		next = SP_get_next (Doc_Set);
+	      goto NextDocNum;
+	    }
+	  ent.DocNum = CurrDocNum - 1;
+	  if ((mem = SP_member (&ent, Doc_Set)) == NULL)
+	    {
+	      hits++;
+	      if (rqi->MaxAccums != -1 &&
+		  Doc_Set->no_of_items >= rqi->MaxAccums &&
+		  !MoreAccum)
+		goto NextDocNum;
+	      if ((mem = get_ide (qd, pool)) == NULL)
+		return NULL;
+	      ChangeMemInUse (qd, sizeof (*mem));
+	      mem->DocNum = CurrDocNum - 1;
+	      mem->Sum = 0;
+	      ChangeMemInUse (qd, -Doc_Set->mem_in_use);
+	      if (SP_insert (mem, Doc_Set) == NULL)
+		{
+		  Message ("Unable to allocate memory for a splay node");
+		  Abort = 1;
+		  goto FastAbort;
+		}
+	      ChangeMemInUse (qd, Doc_Set->mem_in_use);
+	      if (rqi->MaxAccums != -1 &&
+		  Doc_Set->no_of_items >= rqi->MaxAccums &&
+		  rqi->StopAtMaxAccum)
+		Abort = 1;
+	    }
+
+	  mem->Sum += Wqt * Wdt;
+	  total_added += Wqt * Wdt;
+
+	NextDocNum:
+	  ;
+	}
+
+    FastAbort:
+
+      DECODE_DONE
+
+	Xfree (buffer);
+      ChangeMemInUse (qd, -we->invf_len);
+      if (sk)
+	{
+	  if (qd->id->ifh.skip_mode != 0)
+	    fprintf (sk, " %6d", skips_taken);
+	  fprintf (sk, " %6d %6d %6d%12.2f\n",
+		   ptrs_dec, hits, Doc_Set->no_of_items, total_added);
+	}
+      if (Abort)
+	break;
+    }
+  if (sk)
+    fclose (sk);
+  return Doc_Set;
+}
+
+
+
+
+Hash_Table *
+CosineDecodeHash (query_data * qd, TermList * Terms,
+		  RankedQueryInfo * rqi)
+{
+  int j, num_docs, num_terms, MoreAccum;
+  Hash_Table *HT;
+  int Anding = 0;
+  int Sorted = 0;
+  FILE *sk = open_skip (rqi->skip_dump);
+  u_char indent = 0;
+  if (sk)
+    {
+      if (!skip_header)
+	{
+	  skip_header = 1;
+	  fprintf (sk, "%s", skip_header_text[qd->id->ifh.skip_mode]);
+	  fprintf (sk, "\nSkipping method %ld\n", qd->id->ifh.skip_mode);
+	  switch (qd->id->ifh.skip_mode)
+	    {
+	    case 1:
+	      fprintf (sk, "Skipping is every %ld docnums\n",
+		       qd->id->ifh.params[0]);
+	      break;
+	    case 2:
+	      fprintf (sk, "Max nodes = %ld\nNo skips smaller or equal to %ld\n",
+		       qd->id->ifh.params[0], qd->id->ifh.params[1]);
+	      break;
+	    }
+	}
+      fprintf (sk, "\n\t\t\t-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n");
+      for (j = 0; j < Terms->num; j++)
+	if (Terms->TE[j].Word[0] > indent)
+	  indent = Terms->TE[j].Word[0];
+    }
+
+  num_docs = qd->sd->sdh.num_of_docs;
+  /* Create the array for the documents */
+  HT = HT_create (qd, rqi->MaxAccums, rqi->HashTblSize);
+  if (!HT)
+    return NULL;
+
+  if (rqi->MaxTerms == -1)
+    num_terms = Terms->num;
+  else
+    num_terms = rqi->MaxTerms < Terms->num ? rqi->MaxTerms : Terms->num;
+
+  MoreAccum = 1;
+
+  /* For each word in the list . . . */
+  for (j = 0; j < num_terms; j++)
+    {
+      int Abort = 0;
+      u_char *buffer;
+      int pos;
+      int i;
+      unsigned long CurrDocNum = 0;	/* NOTE: Document numbers start at 1 */
+      double Wqt, WordLog;
+      int dn_blk = 0, len_blk = 0, k, kd;
+      int blk;			/* bblock control parameter */
+      int p;			/* The number of documents the word occurs in */
+      WordEntry *we = &Terms->TE[j].WE;
+      Invf_Doc_EntryH *next = NULL;
+      int next_i, next_doc_num, next_start;
+      int skips_taken = 0, ptrs_dec = 0;
+      double total_added = 0.0;
+      int hits = 0;
+      if (sk)
+	{
+	  fprintf (sk, "%3d : %8ld %6ld \"%.*s\"%*s", j, we->count,
+		 we->doc_count, Terms->TE[j].Word[0], Terms->TE[j].Word + 1,
+		   indent - Terms->TE[j].Word[0], "");
+	}
+
+      CalcBlks (qd, we, &blk, &dn_blk, &len_blk, &k, &p);
+      if (!(buffer = Xmalloc (we->invf_len)))
+	break;
+
+      ChangeMemInUse (qd, we->invf_len);
+
+      if (sk && qd->id->ifh.skip_mode == 2)
+	fprintf (sk, "%4d", k);
+
+      Fseek (qd->File_invf, we->invf_ptr, 0);
+      Fread (buffer, sizeof (char), we->invf_len, qd->File_invf);
+
+      /* Read from the buffer */
+      DECODE_START (buffer, we->invf_len);
+
+      WordLog = log ((double) num_docs / (double) we->max_doc_count);  /* [RPAP - Jan 97: Stem Index Change] */
+
+      Wqt = (rqi->QueryFreqs ? Terms->TE[j].Count : 1) * WordLog;
+
+      qd->num_of_terms++;
+
+      if (rqi->MaxAccums != -1 && HT->num >= rqi->MaxAccums)
+	{
+	  MoreAccum = 0;
+	  Anding = 1;
+	  if (!Sorted)
+	    {
+	      HT_sort (qd, HT);
+	      Sorted = 1;
+	    }
+	  next = HT->Head;
+	}
+      i = pos = 0;
+      next_i = next_start = next_doc_num = 0;
+      kd = k - 1;
+      while (i < p && (!Anding || next))
+	{
+	  int Count;		/* The number of times the occurs in a document */
+	  double Wdt;
+	  unsigned long diff;
+	  Invf_Doc_Entry *mem;
+	  if (k)
+	    {
+	      if (Anding && i + k < p && next->IDE.DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		{
+#ifdef SHORT_CUT
+		ShortCut:
+#endif
+		  i = next_i;
+		  DECODE_SEEK (next_start);
+		  pos = next_start;
+		  CurrDocNum = next_doc_num;
+		  qd->hops_taken++;
+		  skips_taken++;
+		  kd = k - 1;
+		}
+	      if (kd == k - 1)
+		{
+		  if (i + k < p)
+		    {
+		      int doc_diff, pos_diff;
+		      BBLOCK_DECODE_L (doc_diff, dn_blk, pos);
+		      next_doc_num += doc_diff;
+		      next_i += k;
+		      BBLOCK_DECODE_L (pos_diff, len_blk, pos);
+		      next_start = pos + pos_diff;
+		    }
+		  else
+		    next_doc_num = -1;
+		}
+#ifdef SHORT_CUT
+	      if (Anding && i + k < p && next->IDE.DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		goto ShortCut;
+#else
+	      if (Anding && i + k < p && next->IDE.DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		continue;
+#endif
+	    }
+	  if (k && kd == 0 && i != p - 1)
+	    {
+	      CurrDocNum = next_doc_num;
+	    }
+	  else
+	    {
+	      BBLOCK_DECODE_L (diff, blk, pos);
+	      CurrDocNum += diff;
+	    }
+	  qd->num_of_ptrs++;
+	  ptrs_dec++;
+	  if (qd->id->ifh.InvfLevel >= 2)
+	    GAMMA_DECODE_L (Count, pos);
+	  else
+	    Count = (double) we->count / p;
+	  i++;
+	  kd--;
+	  if (kd < 0)
+	    kd = k - 1;
+
+
+	  if (Anding)
+	    {
+	      while (next && next->IDE.DocNum < CurrDocNum - 1)
+		next = next->next;
+	      if (next && next->IDE.DocNum == CurrDocNum - 1)
+		{
+		  Wdt = Count * WordLog;
+		  next->IDE.Sum += Wqt * Wdt;
+		  total_added += Wqt * Wdt;
+		  hits++;
+		}
+	      if (next && next->IDE.DocNum <= CurrDocNum - 1)
+		next = next->next;
+	      goto NextDocNum;
+	    }
+	  if ((mem = HT_find (HT, CurrDocNum - 1)) == NULL)
+	    {
+	      if (rqi->MaxAccums != -1 && HT->num >= rqi->MaxAccums &&
+		  !MoreAccum)
+		goto NextDocNum;
+	      Wdt = Count * WordLog;
+	      if (!HT_insert (HT, CurrDocNum - 1, Wqt * Wdt))
+		{
+		  if (!HT->Suplimentary_Entries)
+		    HT_Sup_create (qd, HT, we->doc_count - i + 1);
+		  HT_Sup_Add (HT, CurrDocNum - 1, Wqt * Wdt);
+		}
+	      if (rqi->MaxAccums != -1 && HT->num >= rqi->MaxAccums &&
+		  rqi->StopAtMaxAccum)
+		Abort = 1;
+	    }
+	  else
+	    {
+	      Wdt = Count * WordLog;
+	      mem->Sum += Wqt * Wdt;
+	      total_added += Wqt * Wdt;
+	      hits++;
+	    }
+
+	NextDocNum:
+	  ;
+	}
+
+      DECODE_DONE
+
+	Xfree (buffer);
+      ChangeMemInUse (qd, -we->invf_len);
+      if (sk)
+	{
+	  if (qd->id->ifh.skip_mode != 0)
+	    fprintf (sk, " %6d", skips_taken);
+	  fprintf (sk, " %6d %6d %6d%12.2f\n",
+	       ptrs_dec, hits, HT->num + HT->Suplimentary_Num, total_added);
+	}
+      if (Abort)
+	break;
+    }
+  if (sk)
+    fclose (sk);
+  if (!HT->Head)
+    HT_sort (qd, HT);
+  return HT;
+}
+
+
+
+List_Table *
+CosineDecodeList (query_data * qd, TermList * Terms,
+		  RankedQueryInfo * rqi)
+{
+  int j, num_docs, num_terms, MoreAccum;
+  List_Table *LT;
+  int Anding = 0;
+  int Sorted = 0;
+  int has_grown = 0; /* [RJM 07/97: Ranked Required Match] whether elements have been added lately */
+  FILE *sk = open_skip (rqi->skip_dump);
+  u_char indent = 0;
+  if (sk)
+    {
+      if (!skip_header)
+	{
+	  skip_header = 1;
+	  fprintf (sk, "%s", skip_header_text[qd->id->ifh.skip_mode]);
+	  fprintf (sk, "\nSkipping method %ld\n", qd->id->ifh.skip_mode);
+	  switch (qd->id->ifh.skip_mode)
+	    {
+	    case 1:
+	      fprintf (sk, "Skipping is every %ld docnums\n",
+		       qd->id->ifh.params[0]);
+	      break;
+	    case 2:
+	      fprintf (sk, "Max nodes = %ld\nNo skips smaller or equal to %ld\n",
+		       qd->id->ifh.params[0], qd->id->ifh.params[1]);
+	      break;
+	    }
+	}
+      fprintf (sk, "\n\t\t\t-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n");
+      for (j = 0; j < Terms->num; j++)
+	if (Terms->TE[j].Word[0] > indent)
+	  indent = Terms->TE[j].Word[0];
+    }
+
+  num_docs = qd->sd->sdh.num_of_docs;
+
+  /* Create the list for the documents */
+  LT = LT_create (qd, rqi->MaxAccums);
+  if (!LT)
+    return NULL;
+
+  if (rqi->MaxTerms == -1)
+    num_terms = Terms->num;
+  else
+    num_terms = rqi->MaxTerms < Terms->num ? rqi->MaxTerms : Terms->num;
+
+  MoreAccum = 1;
+
+  /* For each word in the list . . . */
+  for (j = 0; j < num_terms; j++)
+    {
+      int Abort = 0;
+      u_char *buffer;
+      int pos;
+      int i, n = 0;
+      unsigned long CurrDocNum = 0;	/* NOTE: Document numbers start at 1 */
+      unsigned long LastDocNum = 0;	/* [RJM 07/97: Ranked Required Match] */
+      int this_item = 0; /* [RJM 07/97: Ranked Required Match] points to the next possible LT to delete */
+      double Wqt, WordLog;
+      int dn_blk = 0, len_blk = 0, k, kd;
+      int blk;			/* bblock control parameter */
+      int p;			/* The number of documents the word occurs in */
+      int require_match = Terms->TE[j].require_match; /* [RJM 07/97: Ranked Required Match] */
+      WordEntry *we = &Terms->TE[j].WE;
+      Invf_Doc_Entry *next = NULL;
+      int next_i, next_doc_num, next_start;
+      int skips_taken = 0, ptrs_dec = 0;
+      double total_added = 0.0;
+      int hits = 0;
+
+      if (sk)
+	{
+	  fprintf (sk, "%3d : %8ld %6ld \"%.*s\"%*s", j, we->count,
+		 we->doc_count, Terms->TE[j].Word[0], Terms->TE[j].Word + 1,
+		   indent - Terms->TE[j].Word[0], "");
+	}
+
+      CalcBlks (qd, we, &blk, &dn_blk, &len_blk, &k, &p);
+      if (!(buffer = Xmalloc (we->invf_len)))
+	break;
+
+      ChangeMemInUse (qd, we->invf_len);
+
+      if (sk && qd->id->ifh.skip_mode == 2)
+	fprintf (sk, "%4d", k);
+
+      Fseek (qd->File_invf, we->invf_ptr, 0);
+      Fread (buffer, sizeof (char), we->invf_len, qd->File_invf);
+
+      /* Read from the buffer */
+      DECODE_START (buffer, we->invf_len);
+
+      WordLog = log ((double) num_docs / (double) we->max_doc_count);  /* [RPAP - Jan 97: Stem Index Change] */
+
+      Wqt = (rqi->QueryFreqs ? Terms->TE[j].Count : 1) * WordLog;
+
+      qd->num_of_terms++;
+
+      if (rqi->MaxAccums != -1 && LT->num >= rqi->MaxAccums)
+	MoreAccum = 0;
+
+      if ((rqi->MaxAccums != -1 && LT->num >= rqi->MaxAccums) || Anding)
+	{
+	  Anding = 1;
+	  if (!Sorted || has_grown)
+	    {
+	      LT_sort (LT);
+	      LT_pack (LT);
+	      Sorted = 1;
+	      has_grown = 0;
+	    }
+	  next = LT->IDE;
+	  n = 0;
+	}
+
+      /* [RJM 07/97: Ranked Required Terms] */
+      /* make sure that the document list is set up correctly for */
+      /* requiring a term to match */
+      if (require_match == 1) {
+	if (!Sorted || has_grown) {
+	  LT_sort (LT);
+	  LT_pack (LT);
+	  Sorted = 1;
+	  has_grown = 0;
+	}
+	/* this_item is already set to zero */
+      }
+
+      i = pos = 0;
+      next_i = next_start = next_doc_num = 0;
+      kd = k - 1;
+      while (i < p && (!Anding || n < LT->num))
+	{
+	  int Count;		/* The number of times the occurs in a document */
+	  double Wdt;
+	  unsigned long diff;
+	  Invf_Doc_Entry *mem;
+
+	  /* deal with skipping */
+	  if (k)
+	    {
+	      /* see if we should take a skip */
+	      if (Anding && i + k < p && next->DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		{
+		  i = next_i;
+		  DECODE_SEEK (next_start);
+		  pos = next_start;
+		  CurrDocNum = next_doc_num;
+		  qd->hops_taken++;
+		  skips_taken++;
+		  kd = k - 1;
+		}
+	      if (kd == k - 1)
+		if (i + k < p)
+		  {
+		    int doc_diff, pos_diff;
+		    BBLOCK_DECODE_L (doc_diff, dn_blk, pos);
+		    next_doc_num += doc_diff;
+		    next_i += k;
+		    BBLOCK_DECODE_L (pos_diff, len_blk, pos);
+		    next_start = pos + pos_diff;
+		  }
+		else
+		  next_doc_num = -1;
+
+	      /* should we take another skip? */
+	      if (Anding && i + k < p && next->DocNum > next_doc_num &&
+		  next_doc_num >= 0)
+		continue;
+	    }
+	  if (k && kd == 0 && i != p - 1)
+	    CurrDocNum = next_doc_num;
+	  else
+	    {
+	      BBLOCK_DECODE_L (diff, blk, pos);
+	      CurrDocNum += diff;
+	    }
+	  qd->num_of_ptrs++;
+	  ptrs_dec++;
+	  if (qd->id->ifh.InvfLevel >= 2)
+	    GAMMA_DECODE_L (Count, pos);
+	  else
+	    Count = (double) we->count / p;
+	  i++;
+	  kd--;
+	  if (kd < 0)
+	    kd = k - 1;
+	  Wdt = Count * WordLog;
+
+	  /* [RJM 07/97: Ranked Required Terms] */
+	  /* if this is a required match we must remove all accumulators */
+	  /* of intermediate documents */
+	  if (require_match == 1) {
+	    while (this_item < LT->num && LT->IDE[this_item].DocNum < CurrDocNum - 1) {
+	      if (LastDocNum==0 ||(LT->IDE[this_item].DocNum > LastDocNum - 1))
+		LT->IDE[this_item].Sum = -1000.0; /* mark for deletion */
+	      this_item++;
+	    }
+	  }
+
+	  if (Anding)
+	    {
+	      while (n < LT->num && next->DocNum < CurrDocNum - 1)
+		{
+		  next++;
+		  n++;
+		}
+	      if (n < LT->num && next->DocNum == CurrDocNum - 1)
+		{
+		  next->Sum += Wqt * Wdt;
+		  total_added += Wqt * Wdt;
+		  hits++;
+		}
+	      if (n < LT->num && next->DocNum <= CurrDocNum - 1)
+		{
+		  next++;
+		  n++;
+		}
+	      goto NextDocNum;
+	    }
+	  if (!Anding)
+	    {
+	      if (rqi->MaxAccums != -1 && LT->num >= rqi->MaxAccums &&
+		  !MoreAccum)
+		goto NextDocNum;
+	      LT = LT_add (qd, LT, CurrDocNum - 1, Wqt * Wdt);
+	      if (!LT)
+		{
+		  Abort = 1;
+		  goto FastAbort;
+		}
+
+	      /* the list of accumulators just got bigger */
+	      has_grown = 1;
+
+	      if (rqi->MaxAccums != -1 && LT->num >= rqi->MaxAccums &&
+		  rqi->StopAtMaxAccum)
+		Abort = 1;
+
+
+	    }
+	  else if ((mem = LT_find (LT, CurrDocNum - 1)))
+	    {
+	      mem->Sum += Wqt * Wdt;
+	      total_added += Wqt * Wdt;
+	      hits++;
+	    }
+
+	NextDocNum:
+
+	  LastDocNum = CurrDocNum;
+	}
+
+    FastAbort:
+
+      DECODE_DONE
+
+	Xfree (buffer);
+      ChangeMemInUse (qd, -we->invf_len);
+      if (sk)
+	{
+	  if (qd->id->ifh.skip_mode != 0)
+	    fprintf (sk, " %6d", skips_taken);
+	  fprintf (sk, " %6d %6d %6d%12.2f\n",
+		   ptrs_dec, hits, LT->num, total_added);
+	}
+      if (Abort)
+	break;
+
+      /* [RJM 07/97: Ranked Required Terms] */
+      /* remove the remaining accumulators if this term is required to match */
+      if (require_match == 1) {
+	while (this_item < LT->num) {
+	  if (LT->IDE[this_item].DocNum > LastDocNum - 1)
+	    LT->IDE[this_item].Sum = -1000.0; /* mark for deletion */
+	  this_item++;
+	}
+	Anding = 1; /* no more documents should be added */
+
+	/* Get rid of any documents which have been deleted */
+	LT_pack (LT);
+      }
+    }
+
+  if (sk)
+    fclose (sk);
+  return LT;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/invf_get.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/invf_get.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/invf_get.h	(revision 10506)
@@ -0,0 +1,103 @@
+/**************************************************************************
+ *
+ * invf_get.h -- Inverted file reading routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_INVF_GET
+#define H_INVF_GET
+
+typedef struct Invf_Doc_Entry
+  {
+    int DocNum;
+    float Sum;
+  }
+Invf_Doc_Entry;
+
+typedef struct Invf_Doc_Entry_Pool
+  {
+    void *pool;
+    unsigned pool_chunks;
+  }
+Invf_Doc_Entry_Pool;
+
+typedef struct Invf_Doc_EntryH
+  {
+    Invf_Doc_Entry IDE;
+    struct Invf_Doc_EntryH *next;
+  }
+Invf_Doc_EntryH;
+
+typedef struct Hash_Table
+  {
+    Invf_Doc_EntryH *Suplimentary_Entries;
+    int Suplimentary_Size;
+    int Suplimentary_Num;
+    unsigned max;
+    unsigned num;
+    unsigned size;
+    Invf_Doc_EntryH **HashTable;
+    Invf_Doc_EntryH *Head;
+    Invf_Doc_EntryH IDEH[1];
+  }
+Hash_Table;
+
+typedef struct List_Table
+  {
+    unsigned max;
+    unsigned num;
+    Invf_Doc_Entry IDE[1];
+  }
+List_Table;
+
+typedef enum
+  {
+    op_term, op_and_terms, op_and_or_terms, op_diff_terms
+  }
+Op_types;
+
+/*Invf_Doc_Entry *HT_find(Hash_Table *HT, unsigned long DN); */
+void HT_free (query_data * qd, Hash_Table * HT);
+void LT_free (query_data * qd, List_Table * LT);
+
+invf_data *InitInvfFile (File * InvfFile, stemmed_dict * sd);
+void FreeInvfData (invf_data * id);
+
+DocList *GetDocs (query_data * qd, WordEntry * we, BooleanQueryInfo * bqi);
+
+float *CosineDecode (query_data * qd, TermList * Terms, RankedQueryInfo * rqi);
+
+void free_ide_pool (query_data * qd, Invf_Doc_Entry_Pool * pool);
+
+Splay_Tree *CosineDecodeSplay (query_data * qd, TermList * Terms,
+			 RankedQueryInfo * rqi, Invf_Doc_Entry_Pool * pool);
+
+Hash_Table *CosineDecodeHash (query_data * qd, TermList * Terms,
+			      RankedQueryInfo * rqi);
+List_Table *CosineDecodeList (query_data * qd, TermList * Terms,
+			      RankedQueryInfo * rqi);
+
+
+DocList *GetDocsOp (query_data * qd, WordEntry * we, Op_types op, DocList * L);
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/ivf.pass1.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/ivf.pass1.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/ivf.pass1.c	(revision 10506)
@@ -0,0 +1,822 @@
+/**************************************************************************
+ *
+ * ivf.pass1.c -- Memory efficient pass 1 inversion
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include "local_strings.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "mg.h"
+#include "build.h"
+#include "locallib.h"
+#include "words.h"
+#include "stemmer.h"
+#include "hash.h"
+
+#include "longlong.h"
+
+/*
+   $Log$
+   Revision 1.2  2001/09/21 12:46:42  kjm18
+   updated mg to be in line with mg_1.3f. Now uses long long for some variables
+   to enable indexing of very large collections.
+
+   Revision 1.1  1999/08/10 21:17:54  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1998/12/17 09:12:50  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:43  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:44  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.6  1995/01/16  03:57:05  tes
+   * Fixed bug for index_string_bytes which was calculated
+   * by adding the suffix lengths except for every lookback (block)
+   * number of words. This was incorrect as invf.dict is fully
+   * front coded - perhaps it was partially coded in the past.
+   * This would only affect a statistic - hence the reason why the
+   * bug could exist ;-)
+   *
+   * Revision 1.5  1994/11/29  00:31:59  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:56:48  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:34  tes
+   * For version 1.1
+   *
+ */
+
+/*
+ *  Modified:
+ *   - long long bit counts for inverted file
+ *     (1999-08-05 Tim Bell <bhat@cs.mu.oz.au>)
+ */
+static char *RCSID = "$Id$";
+
+#define LOGLOOKBACK	2
+#define POOL_SIZE 1024*1024
+#define HASH_POOL_SIZE 8192
+#define INITIAL_HASH_SIZE 7927
+
+#define INIT_CHECK_FRAC 0.10
+#define CHECK_FRAC 0.75
+#define CHECK_CLOSE 0.999
+#define PARA_DIV 1.5
+#define NORM_DIV 1.0
+
+
+typedef struct hash_rec
+  {
+    unsigned long fcnt;		/* fragment frequency */
+    unsigned long lfcnt;	/* local fragment frequency */
+    unsigned long fnum;		/* last fragment to use stem */
+    unsigned long wcnt;		/* stem frequency */
+    unsigned long lwcnt;	/* local stem frequency */
+    u_char *word;
+  }
+hash_rec;
+
+
+
+
+
+
+
+
+static unsigned long words_read = 0, words_diff = 0, bytes_diff = 0;
+static unsigned long outputbytes = 0;
+static unsigned long inputbytes = 0;
+static unsigned long MaxMemInUse = 0;
+static unsigned long MemInUse = 0;
+static unsigned long ChunksWritten = 0;
+
+
+static FILE *ic;		/* The invf block file */
+static stdio_bitio_state sbs;
+
+static hash_rec **HashTable;
+static unsigned long HashSize;
+static unsigned long HashUsed;
+static u_char *Pool;
+static int PoolLeft;
+
+static hash_rec *hr_pool;
+static int hr_PoolLeft;
+
+static hash_rec **first_occr;
+static int max_first_occr;
+
+static mg_ullong L1_bits = 0;
+static mg_ullong L2_bits = 0;
+static mg_ullong L3_bits = 0;
+static unsigned long L1_ohead = 0;
+static unsigned long L2_ohead = 0;
+static unsigned long L3_ohead = 0;
+static unsigned long callnum = 0, lcallnum = 0, wordnum = 0, lwordnum = 0;
+static unsigned long ptrcnt = 0;
+static unsigned long checknum;
+static long max_mem = 0;
+
+
+static void 
+ChangeMem (int Change)
+{
+  MemInUse += Change;
+  if (MemInUse > MaxMemInUse)
+    MaxMemInUse = MemInUse;
+}
+
+
+
+int 
+init_ivf_1 (char *file_name)
+{
+  if (!(ic = create_file (file_name, INVF_CHUNK_SUFFIX, "wb", MAGIC_CHUNK,
+			  MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+  fwrite ("    ", sizeof (u_long), 1, ic);	/* Space for the maxmem */
+  ENCODE_START (ic)
+    ENCODE_PAUSE (sbs)
+
+    if (!(Pool = Xmalloc (POOL_SIZE)))
+    {
+      Message ("Unable to allocate memory for pool");
+      return (COMPERROR);
+    }
+  PoolLeft = POOL_SIZE;
+  ChangeMem (POOL_SIZE);
+
+  if (!(hr_pool = Xmalloc (HASH_POOL_SIZE * sizeof (hash_rec))))
+    {
+      Message ("Unable to allocate memory for pool");
+      return (COMPERROR);
+    }
+  hr_PoolLeft = HASH_POOL_SIZE;
+  ChangeMem (HASH_POOL_SIZE * sizeof (hash_rec));
+
+  HashSize = INITIAL_HASH_SIZE;
+  HashUsed = 0;
+  if (!(HashTable = Xmalloc (sizeof (hash_rec *) * HashSize)))
+    {
+      Message ("Unable to allocate memory for table");
+      return (COMPERROR);
+    }
+  ChangeMem (sizeof (hash_rec *) * HashSize);
+  bzero ((char *) HashTable, sizeof (hash_rec *) * HashSize);
+  max_first_occr = 8192;
+  if (!(first_occr = Xmalloc (sizeof (hash_rec *) * max_first_occr)))
+    {
+      Message ("Unable to allocate memory for first_occur");
+      return (COMPERROR);
+    }
+  ChangeMem (sizeof (hash_rec *) * max_first_occr);
+
+  checknum = (invf_buffer_size * INIT_CHECK_FRAC) /
+    (InvfLevel == 3 ? PARA_DIV : NORM_DIV);
+
+  return (COMPALLOK);
+}
+
+
+
+static unsigned long 
+mem_reqd (void)
+{
+  register int i;
+  register unsigned long total = 0;
+/*  register unsigned long N = InvfLevel == 3 ? lwordnum : lcallnum; */
+  register unsigned long N = lcallnum;
+  for (i = 0; i < HashUsed; i++)
+    {
+      register hash_rec *ent = first_occr[i];
+/*      register unsigned long p = InvfLevel == 3 ? ent->lwcnt : ent->lfcnt; */
+      register unsigned long p = ent->lfcnt;
+      if (p)
+	total += BIO_Bblock_Bound (N, p);
+      if (InvfLevel >= 2)
+	total += ent->lwcnt;
+    }
+
+  total = (total + 7) >> 3;
+  return total;
+}
+
+static unsigned long 
+max_mem_reqd (void)
+{
+  register int i;
+  register unsigned long total = 0;
+/*  register unsigned long N = InvfLevel == 3 ? wordnum : callnum; */
+  register unsigned long N = callnum;
+  for (i = 0; i < HashUsed; i++)
+    {
+      register hash_rec *ent = first_occr[i];
+/*      register unsigned long p = InvfLevel == 3 ? ent->wcnt : ent->fcnt; */
+      register unsigned long p = ent->fcnt;
+      if (p)
+	total += BIO_Bblock_Bound (N, p);
+      if (InvfLevel >= 2)
+	total += ent->wcnt;
+    }
+
+  total = (total + 7) >> 3;
+  return total;
+}
+
+
+static void 
+dump_dict (unsigned long mem)
+{
+  int i;
+
+  ChunksWritten++;
+
+  ENCODE_CONTINUE (sbs)
+
+    GAMMA_ENCODE (lcallnum + 1);
+  if (mem > max_mem)
+    max_mem = mem;
+  GAMMA_ENCODE (mem + 1);
+  lwordnum = lcallnum = 0;
+  GAMMA_ENCODE (HashUsed + 1);
+  for (i = 0; i < HashUsed; i++)
+    {
+      hash_rec *ent = first_occr[i];
+      GAMMA_ENCODE (ent->lwcnt + 1);
+      if (ent->lwcnt >= 2)
+	GAMMA_ENCODE (ent->lfcnt);
+      ent->lwcnt = ent->lfcnt = 0;
+    }
+  ptrcnt = 0;
+  ENCODE_PAUSE (sbs)
+}
+
+
+
+static int 
+process_doc (u_char * s_in, int l_in)
+{
+  u_char *end = s_in + l_in - 1;
+
+  callnum++;
+  lcallnum++;
+  inputbytes += l_in;
+
+  if (!inaword (s_in, end))
+    if (SkipSGML)
+      PARSE_NON_STEM_WORD_OR_SGML_TAG (s_in, end);
+    else
+      PARSE_NON_STEM_WORD (s_in, end);
+  /*
+   ** Alternately parse off words and non-words from the input
+   ** stream beginning with a non-word. Each token is then
+   ** inserted into the set if it does not exist or has it's
+   ** frequency count incremented if it does.
+   */
+  while (s_in <= end)
+    {
+      u_char Word[MAXSTEMLEN + 1];
+
+      PARSE_STEM_WORD (Word, s_in, end);
+      
+      stemmer (stem_method, stemmer_num, Word);
+      if (SkipSGML)
+	PARSE_NON_STEM_WORD_OR_SGML_TAG (s_in, end);
+      else
+	PARSE_NON_STEM_WORD (s_in, end);
+
+      words_read++;
+      wordnum++;
+      lwordnum++;
+      /* Search the hash table for Word */
+      {
+	register unsigned long hashval, step;
+	register int hsize = HashSize;
+	HASH (hashval, step, Word, hsize);
+	for (;;)
+	  {
+	    register u_char *s1;
+	    register u_char *s2;
+	    register int len;
+	    register hash_rec *ent;
+	    ent = HashTable[hashval];
+	    if (!ent)
+	      {
+		int len = *Word + 1;
+		if (!hr_PoolLeft)
+		  {
+		    if (!(hr_pool = Xmalloc (HASH_POOL_SIZE *
+					     sizeof (hash_rec))))
+		      {
+			Message ("Unable to allocate memory for pool");
+			return (COMPERROR);
+		      }
+		    hr_PoolLeft = HASH_POOL_SIZE;
+		    ChangeMem (HASH_POOL_SIZE * sizeof (hash_rec));
+		  }
+		ent = hr_pool++;
+		hr_PoolLeft--;
+		if (len > PoolLeft)
+		  {
+		    if (!(Pool = Xmalloc (POOL_SIZE)))
+		      {
+			Message ("Unable to allocate memory for pool");
+			return (COMPERROR);
+		      }
+		    PoolLeft = POOL_SIZE;
+		    ChangeMem (POOL_SIZE);
+		  }
+		ent->wcnt = 1;
+		ent->fcnt = 1;
+		ent->lwcnt = 1;
+		ent->lfcnt = 1;
+		ent->fnum = callnum;
+		ent->word = Pool;
+		memcpy (Pool, Word, len);
+		Pool += len;
+		PoolLeft -= len;
+		if (HashUsed == max_first_occr - 1)
+		  {
+		    ChangeMem (-sizeof (hash_rec *) * max_first_occr);
+		    max_first_occr *= 2;
+		    if (!(first_occr = Xrealloc (first_occr, sizeof (hash_rec *) *
+						 max_first_occr)))
+		      {
+			Message ("Unable to allocate memory for first_occr");
+			return (COMPERROR);
+		      }
+		    ChangeMem (sizeof (hash_rec *) * max_first_occr);
+		  }
+		first_occr[HashUsed] = ent;
+		HashUsed++;
+		HashTable[hashval] = ent;
+		bytes_diff += Word[0];
+		break;
+	      }
+
+	    /* Compare the words */
+	    s1 = Word;
+	    s2 = ent->word;
+	    len = *s1 + 1;
+	    for (; len; len--)
+	      if (*s1++ != *s2++)
+		break;
+
+	    if (len)
+	      {
+		hashval = (hashval + step);
+		if (hashval >= hsize)
+		  hashval -= hsize;
+	      }
+	    else
+	      {
+		ent->wcnt++;
+		ent->lwcnt++;
+		if (callnum > ent->fnum)
+		  {
+		    ptrcnt++;
+		    ent->fcnt++;
+		    ent->lfcnt++;
+		    ent->fnum = callnum;
+		  }
+		break;
+	      }
+	  }
+      }
+
+      if (HashUsed >= HashSize >> 1)
+	{
+	  hash_rec **ht;
+	  unsigned long size;
+	  unsigned long i;
+	  size = prime (HashSize * 2);
+	  if (!(ht = Xmalloc (sizeof (hash_rec *) * size)))
+	    {
+	      Message ("Unable to allocate memory for table");
+	      return (COMPERROR);
+	    }
+	  bzero ((char *) ht, sizeof (hash_rec *) * size);
+	  ChangeMem (sizeof (hash_rec *) * size);
+
+	  for (i = 0; i < HashSize; i++)
+	    if (HashTable[i])
+	      {
+		register u_char *wptr;
+		hash_rec *ent;
+		register unsigned long hashval, step;
+
+		wptr = HashTable[i]->word;
+		HASH (hashval, step, wptr, size);
+		ent = ht[hashval];
+		while (ent)
+		  {
+		    hashval += step;
+		    if (hashval >= size)
+		      hashval -= size;
+		    ent = ht[hashval];
+		  }
+		ht[hashval] = HashTable[i];
+	      }
+	  Xfree (HashTable);
+	  ChangeMem (-sizeof (hash_rec *) * HashSize);
+	  HashTable = ht;
+	  HashSize = size;
+	}
+
+    }
+
+  if (ptrcnt >= checknum)
+    {
+      unsigned long mem;
+      /*fprintf(stderr, "Checking at %u . . . ", ptrcnt); */
+      mem = mem_reqd ();
+      if (mem >= invf_buffer_size * CHECK_CLOSE)
+	{
+	  /*fprintf(stderr, "Got a match\n"); */
+	  dump_dict (mem);
+	  checknum = (invf_buffer_size * INIT_CHECK_FRAC) /
+	    (InvfLevel == 3 ? PARA_DIV : NORM_DIV);
+	}
+      else
+	{
+	  checknum = checknum * ((CHECK_FRAC * (invf_buffer_size - mem)) / mem) +
+	    checknum;
+	  if (checknum <= ptrcnt)
+	    checknum = ptrcnt + 1;
+	  /*fprintf(stderr, "Next check at %u\n", checknum); */
+	}
+    }
+  return (COMPALLOK);
+
+}				/* encode */
+
+
+int 
+process_ivf_1 (u_char * s_in, int l_in)
+{
+  if (InvfLevel <= 2)
+    return process_doc (s_in, l_in);
+  else
+    {
+      int pos = 0;
+      u_char *start = s_in;
+      while (pos < l_in)
+	{
+	  if (s_in[pos] == TERMPARAGRAPH)
+	    {
+	      int len = pos + s_in + 1 - start;
+	      if (process_doc (start, len) != COMPALLOK)
+		return (COMPERROR);
+	      start = s_in + pos + 1;
+	    }
+	  pos++;
+	}
+      if (start < s_in + pos)
+	return process_doc (start, pos + s_in - start);
+    }
+  return COMPALLOK;
+}
+
+static int 
+PackHashTable (void)
+{
+  int s, d;
+  for (s = d = 0; s < HashSize; s++)
+    if (HashTable[s])
+      HashTable[d++] = HashTable[s];
+  ChangeMem (-sizeof (hash_rec *) * HashSize);
+  ChangeMem (sizeof (hash_rec *) * HashUsed);
+  if (!(HashTable = Xrealloc (HashTable, sizeof (hash_rec *) * HashUsed)))
+    {
+      Message ("Out of memory");
+      return COMPERROR;
+    }
+  HashSize = HashUsed;
+  return COMPALLOK;
+}
+
+
+
+
+
+static int 
+ent_comp (const void *A, const void *B)
+{
+  u_char *s1 = (*((hash_rec **) A))->word;
+  u_char *s2 = (*((hash_rec **) B))->word;
+
+  return (casecompare (s1, s2)); /* [RPAP - Jan 97: Stem Index Change] */
+}				/* stem_comp */
+
+
+
+
+
+/*
+ * void count_text()
+ *
+ * The maths used in this function is described in the paper "Coding for 
+ * Compression in Full-Text Retrieval Systems"
+ *
+ */
+static void 
+count_text ()
+{
+  int i;
+  mg_ullong oldL12_bits = 0;
+  for (i = 0; i < HashUsed; i++)
+    {
+      hash_rec *wrd = HashTable[i];
+      /* estimate size of a level 1 inverted file */
+      L1_bits += (int) (0.99 + wrd->fcnt * (1.6 + log2 (1.0 * callnum / wrd->fcnt)));
+      L1_ohead += BIO_Gamma_Length (wrd->fcnt);
+
+      L2_bits += BIO_Unary_Length (wrd->wcnt);
+      L2_ohead += BIO_Gamma_Length (wrd->wcnt - wrd->fcnt + 1);
+
+      L3_bits += (int) (0.99 + wrd->wcnt *
+		  (1.6 + log2 (1.0 * words_read / (wrd->wcnt + callnum))));
+      L3_ohead += 0;
+
+      /* check for overflow */
+      if (L1_bits + L2_bits < oldL12_bits) {
+	fprintf(stderr, "ERROR: Inverted file size will probably overflow %d byte unsigned integer\n", sizeof (mg_ullong));
+	fprintf(stderr, "       counter in pass 2.\n");
+	if (sizeof (mg_ullong) < 8) {
+	  fprintf(stderr, "       Try compiling with GCC to enable use of 8 bytes for this counter.\n");
+	}
+	fprintf(stderr, "       Build aborted.\n");
+	exit(1);
+      }
+      oldL12_bits = L1_bits + L2_bits;
+    }
+  L3_bits = (L3_bits + L2_bits + L1_bits + 7) / 8;
+  L3_ohead = (L3_ohead + L2_ohead + L1_ohead + 7) / 8;
+  L2_bits = (L2_bits + L1_bits + 7) / 8;
+  L2_ohead = (L2_ohead + L1_ohead + 7) / 8;
+  L1_bits = (L1_bits + 7) / 8;
+  L1_ohead = (L1_ohead + 7) / 8;
+}				/* count_text */
+
+
+
+/*
+ *    write_stem_file():
+ *              writes out the stemmed dictionary file
+ *              in the following format 
+ *                      lookback value (int)
+ *                      totalbytes value (int)
+ *                      indexstringbytes (int)
+ *                      for each word 
+ *                        wordlen (4 bits)
+ *                        prefix match (4 bits)
+ *                        word (wordlen bytes)
+ *                        word frequency (int)
+ *                        word count (int)
+ *
+ *      Accesses outside variables:     
+ *
+ *      Return value...:                
+ */
+
+static void 
+write_stem_file (char *file_name)
+{
+  long j;
+  struct invf_dict_header idh;
+  long lookback = (1 << LOGLOOKBACK);	/* ???? */
+  long totalbytes = 0;		/* The sum of the length of all words, including 
+				   the length byte */
+  long indexstringbytes = 0;	/* The amount of space required to store the 
+				   words in the diction, this takes into account 
+				   the prefixes */
+  u_char *lastword = NULL;	/* A pointer to the last word processed */
+  FILE *sp;
+
+
+  /* Calculate the size of certain things */
+  for (j = 0; j < HashSize; j++)
+    {
+      u_char *word = HashTable[j]->word;
+      indexstringbytes += word[0] + 2;
+      totalbytes += word[0] + 1;
+      if (lastword)
+	indexstringbytes -= prefixlen (lastword, word);
+      lastword = word;
+    }
+
+  lastword = NULL;
+
+  if (!(sp = create_file (file_name, INVF_DICT_SUFFIX, "wb", MAGIC_STEM_BUILD,
+			  MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL2(lookback, idh.lookback);
+  HTONUL2(HashSize, idh.dict_size);
+  HTONUL2(totalbytes, idh.total_bytes);
+  HTONUL2(indexstringbytes, idh.index_string_bytes);
+  HTOND2(inputbytes, idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  HTONUL2(callnum, idh.num_of_docs);
+  HTONUL2(callnum, idh.static_num_of_docs);
+  HTONUL2(words_read, idh.num_of_words);
+  HTONUL2(stemmer_num, idh.stemmer_num);
+  HTONUL2(stem_method, idh.stem_method);
+
+  fwrite ((char *) &idh, sizeof (idh), 1, sp);
+  outputbytes += sizeof (idh);
+
+  for (j = 0; j < HashSize; j++)
+    {
+      int i;
+      unsigned long wcnt, fcnt;  /* [RPAP - Jan 97: Endian Ordering] */
+      hash_rec *ent = HashTable[j];
+      if (lastword != NULL)
+	/* look for prefix match with prev string */
+	i = prefixlen (lastword, ent->word);
+      else
+	i = 0;
+      fputc (i, sp);
+      fputc (ent->word[0] - i, sp);
+      fwrite ((char *) ent->word + i + 1, sizeof (u_char), ent->word[0] - i, sp);
+      outputbytes += ent->word[0] - i + 1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL2(ent->fcnt, fcnt);
+      fwrite ((char *) &(fcnt), sizeof (fcnt), 1, sp);
+
+      outputbytes += sizeof (ent->fcnt);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL2(ent->wcnt, wcnt);
+      fwrite ((char *) &(wcnt), sizeof (wcnt), 1, sp);
+
+      outputbytes += sizeof (ent->wcnt);
+      lastword = ent->word;
+    }
+
+  fclose (sp);
+}				/* write_stem_file() */
+
+
+
+/*
+ *    write_codes():
+ *              calls functions to assign and write out codes and
+ *              then prints out stats about execution results.
+ *
+ *      Accesses outside variables:     z
+ *
+ *      Return value...:                z
+ */
+
+static void 
+write_codes (char *file_name)
+{
+  unsigned long dicts = 0;
+  outputbytes = 0;
+  write_stem_file (file_name);
+  dicts = outputbytes;
+
+#ifndef SILENT
+  Message ("Chunks written      : %d\n",
+	   ChunksWritten);
+  if (InvfLevel == 3)
+    Message ("Paragraphs          : %8d\n", callnum);
+  Message ("Peak memory usage   : %10.1f Mb\n",
+	   (double) MaxMemInUse / 1024.0 / 1024.0);
+  Message ("Stems size          : %10.1f kB  %5.2f%%\n",
+	   (double) dicts / 1024, (double) 100 * dicts / inputbytes);
+  Message ("Lev 1 inverted file : %10.1f kB  %5.2f%%\n",
+	   (double) (L1_bits + L1_ohead) / 1024,
+	   (double) 100 * (L1_bits + L1_ohead) / inputbytes);
+  Message ("Lev 2 inverted file : %10.1f kB  %5.2f%%\n",
+	   (double) (L2_bits + L2_ohead) / 1024,
+	   (double) 100 * (L2_bits + L2_ohead) / inputbytes);
+  Message ("Lev 3 inverted file : %10.1f kB  %5.2f%%\n",
+	   (double) (L3_bits + L3_ohead) / 1024,
+	   (double) 100 * (L3_bits + L3_ohead) / inputbytes);
+  Message ("Record addresses    : %10.1f kB  %5.2f%%\n",
+	   (double) words_diff * 4 / 1024, (double) 100 * words_diff * 4 / inputbytes);
+#endif
+}				/* write_codes() */
+
+
+
+void 
+write_num_file (char *file_name)
+{
+
+  int i;
+  FILE *f;
+
+  for (i = 0; i < HashSize; i++)
+    HashTable[i]->fnum = i;
+
+  if (!(f = create_file (file_name, INVF_CHUNK_TRANS_SUFFIX, "wb",
+			 MAGIC_CHUNK_TRANS, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return;
+
+#if 1
+  ENCODE_START (f)
+
+    for (i = 0; i < HashSize; i++)
+    BINARY_ENCODE (first_occr[i]->fnum + 1, HashSize + 1);
+
+  ENCODE_DONE;
+#else
+  for (i = 0; i < HashSize; i++)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      unsigned long fnum;
+      HTONUL2(first_occur[i]->fnum, fnum);
+      fwrite ((char *) &fnum, sizeof (unsigned long), 1, f);
+    }
+#endif
+
+  fclose (f);
+}
+
+
+
+
+int 
+done_ivf_1 (char *FileName)
+{
+  char *temp_str = msg_prefix;
+  msg_prefix = "ivf.pass1";
+#ifndef SILENT
+  Message ("Mem reqd for 1 chunk: %8u bytes\n",
+	   max_mem_reqd ());
+#endif
+  if (lcallnum)
+    dump_dict (mem_reqd ());
+
+  if (PackHashTable () == COMPERROR)
+    return COMPERROR;
+
+  qsort (HashTable, HashUsed, sizeof (hash_rec *), ent_comp);
+
+  count_text ();
+  write_codes (FileName);
+
+  ENCODE_CONTINUE (sbs)
+    GAMMA_ENCODE (1);
+  ENCODE_DONE
+    fseek (ic, sizeof (long), 0);
+  
+  HTONSL(max_mem);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&max_mem, sizeof (max_mem), 1, ic);
+  NTOHSL(max_mem);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  fclose (ic);
+
+  write_num_file (FileName);
+
+  msg_prefix = temp_str;
+
+  return (COMPALLOK);
+}				/* done_encode */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/ivf.pass2.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/ivf.pass2.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/ivf.pass2.c	(revision 10506)
@@ -0,0 +1,1145 @@
+/**************************************************************************
+ *
+ * ivf.pass2.c -- Memory efficient pass 2 inversion
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.2  2001/09/21 12:46:42  kjm18
+   updated mg to be in line with mg_1.3f. Now uses long long for some variables
+   to enable indexing of very large collections.
+
+ * Revision 1.2  1997/08/02  05:01:57  wew
+ * changed literal values of 32 for the bit size of magic numbers of
+ * files to sizeof (unsigned long) * 8, increased the gap at the start
+ * of the invf during processing to 200 bytes
+
+   Revision 1.1  1999/08/10 21:17:54  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1998/12/17 09:12:51  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:43  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:45  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:49  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:35  tes
+   * For version 1.1
+   *
+ */
+
+/*
+ *  Modified:
+ *   - long long disk pointers and bit counts for inverted file
+ *     (1999-08-03 Tim Bell <bhat@cs.mu.oz.au>)
+ *     Code provided by Owen de Kretser <oldk@cs.mu.oz.au>
+ */
+
+static char *RCSID = "$Id$";
+
+#include "local_strings.h"
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "stemmer.h"
+#include "perf_hash.h"
+#include "bitio_m.h"
+#include "bitio_m_mems.h"
+#include "bitio_gen.h"
+#include "bitio_random.h"
+#include "bitio_stdio.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "locallib.h"
+#include "mg.h"
+#include "build.h"
+#include "words.h"
+#include "hash.h"
+
+#include "longlong.h"
+
+#ifdef USE_LONG_LONG
+#define BIO_Random_Seek_X BIO_Random_Seek_LL
+#define BIO_Random_Tell_X BIO_Random_Tell_LL
+#else
+#define BIO_Random_Seek_X BIO_Random_Seek
+#define BIO_Random_Tell_X BIO_Random_Tell
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+#include <io.h>
+#endif
+
+#ifndef RND_BUF_SIZE
+#define RND_BUF_SIZE 8*1024
+/*#define RND_BUF_SIZE 128 */
+#endif
+
+#define print_fsize(file)\
+do\
+  {\
+    struct stat file_state;\
+    fstat(fileno(invf_out), &file_state);\
+    Message("len(invf) = %ld", file_state.st_size);\
+  }while(0)
+
+typedef struct word_rec
+  {
+    unsigned long ptr;
+    unsigned long last;
+  }
+word_rec;
+
+typedef struct invf_state_rec
+  {
+    mg_ullong Disk_Ptr;
+    mg_ullong Disk_Last;
+    unsigned long Disk_B;
+  }
+invf_state_rec;
+
+typedef struct chunk
+  {
+    unsigned long start_doc;
+    unsigned long params_pos;
+    unsigned long disk_pos;
+    unsigned long N;
+  }
+chunk;
+
+
+static FILE *dict;		/* Stemmed dictionary file */
+static FILE *hash;		/* Stemmed dictionary hash file */
+static FILE *invf;		/* Inverted file */
+static FILE *invf_in;		/* Inverted file */
+static FILE *invf_out;		/* Inverted file */
+static FILE *invf_idx;		/* Inverted index file */
+static FILE *count;		/* Count file */
+static FILE *count_trans;	/* Count translation file */
+static FILE *invf_state;	/* Inverted file State */
+static FILE *chunk_state;	/* Chunk state */
+static FILE *chunks;		/* Chunk state */
+static FILE *invf_para = NULL;	/* Paragraph counts file */
+static FILE *weights = NULL;	/* Weights file */
+
+static stdio_bitio_state sbs;
+static random_bitio_state crbs;
+static chunk *chunk_data = NULL;
+static random_bitio_state rbs, rbsp;
+
+static int docs_left = 0, next_docs_left = 0;
+static unsigned long N;
+
+static word_rec *WordRecs;
+static u_char *lg_bs;
+static float *idf = NULL;
+
+static char *MemoryBuffer = NULL;
+static unsigned long MemBufSize;
+static unsigned long BufToUse;
+static struct invf_dict_header idh;
+
+static perf_hash_data *phd;
+
+static unsigned long *word_list = NULL;
+static unsigned long wl_size = 0;
+
+static unsigned long dict_size;
+static unsigned long no_of_ptrs = 0;
+static unsigned long chunks_read = 0;
+static unsigned long Disk_pos = 0;
+static unsigned long callnum = 0;
+static unsigned long wordnum = 0;
+
+static unsigned long totalIbytes = 0;
+static unsigned long totalDbytes = 0;
+static unsigned long totalHbytes = 0;
+
+static unsigned long MemInUse = 0;
+static unsigned long MaxMemInUse = 0;
+static unsigned long max_buffer_len;
+
+void 
+ChangeMemInUse (int mem)
+{
+  MemInUse += mem;
+  if (MemInUse > MaxMemInUse)
+    MaxMemInUse = MemInUse;
+}
+
+
+
+
+static int 
+open_files (char *file_name)
+{
+  char FName[200];
+
+  if (!(dict = open_file (file_name, INVF_DICT_SUFFIX, "rb",
+			  MAGIC_STEM_BUILD, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+
+  if (!(hash = open_file (file_name, INVF_DICT_HASH_SUFFIX, "rb",
+			  MAGIC_HASH, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+
+  if (!(count = open_file (file_name, INVF_CHUNK_SUFFIX, "rb",
+			   MAGIC_CHUNK, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+  fread (&max_buffer_len, sizeof (max_buffer_len), 1, count);
+  NTOHUL(max_buffer_len);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  BIO_Stdio_Decode_Start (count, &sbs);
+  next_docs_left = BIO_Stdio_Gamma_Decode (&sbs, NULL) - 1;
+
+  if (!(count_trans = open_file (file_name, INVF_CHUNK_TRANS_SUFFIX, "rb",
+				 MAGIC_CHUNK_TRANS, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+
+  if (!(invf = create_file (file_name, INVF_SUFFIX, "w+b",
+			    MAGIC_INVF, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+  fflush (invf);
+  if (!(invf_in = open_file (file_name, INVF_SUFFIX, "rb",
+			     MAGIC_INVF, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+  if (!(invf_out = create_file (file_name, INVF_SUFFIX, "wb",
+				MAGIC_INVF, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+  BIO_Random_Start (invf, RND_BUF_SIZE, &rbs);
+  BIO_Random_Start (invf, RND_BUF_SIZE, &rbsp);
+  ChangeMemInUse (RND_BUF_SIZE * 2);
+
+  if (!(invf_idx = create_file (file_name, INVF_IDX_SUFFIX, "wb",
+				MAGIC_INVI, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return (COMPERROR);
+
+  if (InvfLevel == 3)
+    if (!(invf_para = create_file (file_name, INVF_PARAGRAPH_SUFFIX, "wb",
+				   MAGIC_PARAGRAPH, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+      return (COMPERROR);
+
+  sprintf (FName, FILE_NAME_FORMAT ".%ld", get_basepath (), file_name,
+	   ".invf.state", (long) getpid ());  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(invf_state = fopen (FName, "w+b")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      Message ("Unable to create \"%s\"", FName);
+      return (COMPERROR);
+    }
+  unlink (FName);
+
+  sprintf (FName, FILE_NAME_FORMAT ".%ld", get_basepath (), file_name,
+	   ".chunk.state", (long) getpid ());  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(chunk_state = fopen (FName, "w+b")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      Message ("Unable to create \"%s\"", FName);
+      return (COMPERROR);
+    }
+  unlink (FName);
+  BIO_Random_Start (chunk_state, RND_BUF_SIZE, &crbs);
+  ChangeMemInUse (RND_BUF_SIZE);
+
+  sprintf (FName, FILE_NAME_FORMAT ".%ld", get_basepath (), file_name,
+	   ".chunks", (long) getpid ());  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(chunks = fopen (FName, "w+b")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      Message ("Unable to create \"%s\"", FName);
+      return (COMPERROR);
+    }
+  unlink (FName);
+
+  return (COMPALLOK);
+}
+
+
+
+
+
+#define ISR_CACHE 1024
+#define ISR_ENTRY_SIZE (sizeof(mg_ullong)*2 + sizeof(unsigned long))
+
+invf_state_rec *
+in_cache (int pos)
+{
+  static char isr_data[ISR_CACHE * ISR_ENTRY_SIZE];
+  static invf_state_rec isr;
+  static int isr_base = 0, isr_num = -1, isr_pos = -1;
+  if (isr_pos >= 0)
+    bcopy ((char *) &isr, &isr_data[isr_pos * ISR_ENTRY_SIZE], ISR_ENTRY_SIZE);
+  if (pos < isr_base || pos >= isr_base + isr_num)
+    {
+      if (isr_num >= 0)
+	{
+	  fseek (invf_state, isr_base * ISR_ENTRY_SIZE, 0);
+	  fwrite (isr_data, 1, ISR_ENTRY_SIZE * isr_num, invf_state);
+	}
+      isr_base = pos;
+      fseek (invf_state, isr_base * ISR_ENTRY_SIZE, 0);
+      fread (isr_data, 1, ISR_ENTRY_SIZE * ISR_CACHE, invf_state);
+      isr_num = ISR_CACHE;
+    }
+  isr_pos = pos - isr_base;
+  bcopy (&isr_data[isr_pos * ISR_ENTRY_SIZE], (char *) &isr, ISR_ENTRY_SIZE);
+  return &isr;
+}
+
+
+
+
+
+unsigned long 
+occur_to_lexical (long occ)
+{
+  static long pos = -1;
+  static random_bitio_state rbs;
+  static int val = 0;
+  if (pos == -1)
+    {
+      BIO_Random_Start (count_trans, RND_BUF_SIZE, &rbs);
+      pos = 0x7fffffff;
+    }
+  if (occ < pos)
+    {
+      if (occ == -1)
+	{
+	  BIO_Random_Done (&rbs);
+	  return 0;
+	}
+      BIO_Random_Seek_X (sizeof (unsigned long) * 8, &rbs);
+      pos = 0;
+    }
+  while (pos <= occ)
+    {
+      val = BIO_Random_Binary_Decode (dict_size + 1, &rbs, NULL) - 1;
+      pos++;
+    }
+  return (val);
+}
+
+
+void 
+add_chunk_state (unsigned long pos, unsigned long start_doc,
+		 unsigned long N)
+{
+  chunk_data[chunks_read].params_pos = pos;
+  chunk_data[chunks_read].start_doc = start_doc;
+  chunk_data[chunks_read].N = N;
+  chunks_read++;
+}
+
+
+int 
+init_ivf_2 (char *file_name)
+{
+  u_char prev[MAXSTEMLEN + 1];
+  int i;
+  mg_ullong totalIbits;
+  mg_ullong lasttotalIbits;
+  double logN = 0.0;
+
+  
+  if (open_files (file_name) == COMPERROR)
+    return COMPERROR;
+
+
+  /* Read in the stemmed dictionary file header */
+  fread ((char *) &idh, sizeof (idh), 1, dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  dict_size = idh.dict_size;
+
+  N = idh.num_of_docs;
+
+  if (!(phd = read_perf_hash_data (hash)))
+    {
+      Message ("Unable to read in hash data");
+      return COMPERROR;
+    }
+  totalHbytes = sizeof (perf_hash_data) + sizeof (u_char) * 256 +
+    sizeof (int) * (phd->MAX_N + 1) + sizeof (int *) * 3 * phd->MAX_CH +
+    sizeof (long) * phd->MAX_CH * phd->MAX_L;
+
+  if (!(WordRecs = Xmalloc (sizeof (word_rec) * idh.dict_size)))
+    {
+      Message ("No memory for word entries");
+      return COMPERROR;
+    }
+  totalDbytes += sizeof (word_rec) * idh.dict_size;
+
+  /* separate storage for the log(b) values, one byte each */
+  if (!(lg_bs = Xmalloc (sizeof (u_char) * idh.dict_size)))
+    {
+      Message ("No memory for lg b's");
+      return COMPERROR;
+    }
+  totalDbytes += sizeof (u_char) * idh.dict_size;
+
+  if (MakeWeights)
+    {
+      /* separate storage for the idf values, one single each */
+      if (!(idf = Xmalloc (sizeof (float) * idh.dict_size)))
+	{
+	  Message ("No memory for idf's");
+	  return COMPERROR;
+	}
+      totalDbytes += sizeof (float) * idh.dict_size;
+
+      if (!(weights = create_file (file_name, WEIGHTS_SUFFIX, "wb",
+				 MAGIC_WGHT, MG_CONTINUE))) { /* [RPAP - Feb 97: WIN32 Port] */
+	Message ("Couldn't open weights file for writing");
+	return (COMPERROR);
+      }
+    }
+  else
+    {
+      unlink (make_name (file_name, WEIGHTS_SUFFIX, NULL));
+    }
+
+  chunk_data = Xmalloc (sizeof (chunk) * (ChunkLimit + 2));
+  totalDbytes += sizeof (chunk) * (ChunkLimit + 2);
+
+  totalIbits = sizeof (unsigned long) * 8;		/* The magic number */
+  totalIbits += 8 * 200;	/* A 200 byte gap */
+
+  if (MakeWeights)
+    {
+      wl_size = 1024;
+      if (!(word_list = Xmalloc (sizeof (*word_list) * wl_size)))
+	{
+	  Message ("No memory for word_list");
+	  return COMPERROR;
+	}
+
+      logN = log ((double) N);
+    }
+
+  for (i = 0; i < idh.dict_size; i++)
+    {
+      invf_state_rec *isr;
+      register unsigned long copy, suff, p;
+      unsigned long fcnt, wcnt;
+
+      lasttotalIbits = totalIbits;
+      
+      copy = fgetc (dict);
+      suff = fgetc (dict);
+      *prev = copy + suff;
+      fread (prev + copy + 1, sizeof (u_char), suff, dict);
+
+      fread ((char *) &fcnt, sizeof (fcnt), 1, dict);
+      fread ((char *) &wcnt, sizeof (wcnt), 1, dict);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      WordRecs[i].last = 0;
+      WordRecs[i].ptr = 0;
+
+      p = fcnt;
+
+      if (MakeWeights)
+	idf[i] = logN - log ((double) fcnt);
+
+
+      isr = in_cache (i);
+
+      isr->Disk_Last = 0;
+      isr->Disk_Ptr = totalIbits;
+
+      isr->Disk_B = BIO_Bblock_Init (N, p);
+
+      totalIbits += BIO_Bblock_Bound_b (N, p, isr->Disk_B);
+
+      if (InvfLevel >= 2)
+	totalIbits += BIO_Gamma_Bound (wcnt, fcnt);
+
+#ifdef USE_LONG_LONG
+      totalIbits = (totalIbits + 7ull) & 0xfffffffffffffff8ull;
+#else
+      totalIbits = (totalIbits + 7ul) & 0xfffffff8ul;
+#endif
+
+      if (totalIbits < lasttotalIbits) {
+	fprintf(stderr, "ERROR: The totalIbits counter (%d byte unsigned integer) has overflowed.\n", sizeof (mg_ullong));
+	if (sizeof (mg_ullong) < 8) {
+	  fprintf(stderr, "       Try compiling with GCC to enable use of 8 bytes for this counter.\n");
+	}
+	fprintf(stderr, "       Build aborted.\n");
+	exit(1);
+      }
+    }
+
+
+  /* now convert to bytes, and actually get the space */
+#ifdef USE_LONG_LONG
+  totalIbytes = (totalIbits + 7ull) >> 3ull;
+#else
+  totalIbytes = (totalIbits + 7ul) >> 3ul;
+#endif
+
+  return (COMPALLOK);
+
+}
+
+
+
+
+
+static void 
+LoadCounts (void)
+{
+  unsigned long numwords, i, last_total;
+  static unsigned long local_N = 0;
+  unsigned long totalIbits, crbs_pos;
+  word_rec *wr;
+  unsigned long *counts;
+
+  if (MemoryBuffer == NULL)
+    {
+      MemBufSize = sizeof (unsigned long) * dict_size;
+      if (max_buffer_len > MemBufSize)
+	MemBufSize = max_buffer_len;
+      if (!(MemoryBuffer = Xmalloc (MemBufSize)))
+	FatalError (1, "Unable to allocate memory for buffer");
+      ChangeMemInUse (MemBufSize);
+    }
+
+  counts = (unsigned long *) MemoryBuffer;
+  bzero ((char *) counts, sizeof (unsigned long) * dict_size);
+
+  docs_left = next_docs_left;
+  if (!docs_left)
+    FatalError (1, "The number of docs in the current chunk is 0");
+
+  BufToUse = BIO_Stdio_Gamma_Decode (&sbs, NULL) - 1;
+
+  numwords = BIO_Stdio_Gamma_Decode (&sbs, NULL) - 1;
+
+  local_N = docs_left;
+
+
+
+  for (wr = WordRecs, i = 0; i < dict_size; i++, wr++)
+    wr->ptr = 0;
+
+  bzero ((char *) lg_bs, dict_size);
+
+  for (i = 0; i < numwords; i++)
+    {
+      unsigned long word_num, wcnt, fcnt, p;
+      word_num = occur_to_lexical (i);
+
+      wr = &WordRecs[word_num];
+
+      wcnt = BIO_Stdio_Gamma_Decode (&sbs, NULL) - 1;
+      if (wcnt >= 2)
+	fcnt = BIO_Stdio_Gamma_Decode (&sbs, NULL);
+      else
+	fcnt = wcnt;
+
+      p = fcnt;
+
+      if (wcnt)
+	{
+	  register unsigned long length;
+	  counts[word_num] = p;
+	  length = BIO_Bblock_Bound (local_N, p);
+	  if (InvfLevel >= 2)
+	    length += wcnt;
+	  wr->ptr = length;
+	  lg_bs[word_num] = floorlog_2 (BIO_Bblock_Init_W (local_N, p));
+	}
+
+    }
+
+  crbs_pos = BIO_Random_Tell (&crbs);
+
+  totalIbits = 0;
+  last_total = 0;
+  for (wr = WordRecs, i = 0; i < dict_size; i++, wr++)
+    {
+      register unsigned long length;
+      length = wr->ptr;
+      wr->last = callnum;
+      BIO_Random_Gamma_Encode (counts[i] + 1, &crbs, NULL);
+      if (counts[i])
+	{
+	  if (i)
+	    BIO_Random_Delta_Encode (totalIbits - last_total + 1, &crbs, NULL);
+	  else
+	    BIO_Random_Delta_Encode (1, &crbs, NULL);
+
+	  last_total = totalIbits;
+	}
+      wr->ptr = totalIbits;
+      totalIbits += length;
+    }
+  add_chunk_state (crbs_pos, callnum, local_N);
+
+  if ((totalIbits + 7ul) >> 3ul > BufToUse)
+    FatalError (1, "Pointers exceed buffer size");
+
+  next_docs_left = BIO_Stdio_Gamma_Decode (&sbs, NULL) - 1;
+}
+
+
+
+
+static void 
+DumpChunk (void)
+{
+  chunk_data[chunks_read - 1].disk_pos = Disk_pos << 3;
+  fseek (chunks, Disk_pos, 0);
+  fwrite (MemoryBuffer, sizeof (char), BufToUse, chunks);
+  Disk_pos += BufToUse;
+}
+
+
+
+
+static void 
+DiskMerge (void)
+{
+  random_bitio_state *rbsi;
+  random_bitio_state *chks = NULL;
+  unsigned long *chunk_ptrs;
+  int i;
+
+  BIO_Random_Flush (&crbs);
+
+  chunk_ptrs = Xmalloc (chunks_read * sizeof (unsigned long));
+  ChangeMemInUse (chunks_read * sizeof (unsigned long));
+  bzero ((char *) chunk_ptrs, chunks_read * sizeof (unsigned long));
+
+  rbsi = Xmalloc (chunks_read * sizeof (random_bitio_state));
+  ChangeMemInUse (chunks_read * sizeof (random_bitio_state));
+  for (i = 0; i < chunks_read; i++)
+    {
+      rbsi[i] = crbs;
+      rbsi[i].Buf = Xmalloc (rbsi[i].len);
+      ChangeMemInUse (rbsi[i].len);
+      bcopy ((char *) (crbs.Buf), (char *) (rbsi[i].Buf), rbsi[i].len);
+      BIO_Random_Seek (chunk_data[i].params_pos, &rbsi[i]);
+    }
+
+  if (chunks_read > 1)
+    {
+      int j;
+      chks = Xmalloc ((chunks_read - 1) * sizeof (random_bitio_state));
+      ChangeMemInUse ((chunks_read - 1) * sizeof (random_bitio_state));
+      BIO_Random_Start (chunks, RND_BUF_SIZE, &chks[0]);
+      ChangeMemInUse (RND_BUF_SIZE);
+      for (j = 1; j < chunks_read - 1; j++)
+	{
+	  chks[j] = chks[0];
+	  chks[j].Buf = Xmalloc (chks[0].len);
+	  ChangeMemInUse (chks[0].len);
+	  bcopy ((char *) (chks[0].Buf), (char *) (chks[j].Buf), chks[0].len);
+	}
+    }
+  for (i = 0; i < dict_size; i++)
+    {
+      int j;
+      invf_state_rec *isr = in_cache (i);
+      register int B;
+
+      BIO_Random_Seek_X (isr->Disk_Ptr, &rbs);	/* Position in invf file */
+
+      B = isr->Disk_B;
+
+      for (j = 0; j < chunks_read; j++)
+	{
+	  int p;
+	  p = BIO_Random_Gamma_Decode (&rbsi[j], NULL) - 1;
+
+	  if (p)
+	    {
+	      int ptr, b;
+	      chunk_ptrs[j] += BIO_Random_Delta_Decode (&rbsi[j], NULL) - 1;
+	      ptr = chunk_ptrs[j];
+	      b = 1 << floorlog_2 (BIO_Bblock_Init_W (chunk_data[j].N, p));
+
+	      if (j == chunks_read - 1)
+		{
+		  int k, CurrDoc;
+		  DECODE_START ((u_char *) MemoryBuffer, ptr)
+		    CurrDoc = isr->Disk_Last;
+		  for (k = 0; k < p; k++)
+		    {
+		      register unsigned long x, tf;
+		      BBLOCK_DECODE (x, b);
+		      if (k == 0)
+			x = x + chunk_data[j].start_doc - isr->Disk_Last;
+		      CurrDoc += x;
+		      BIO_Random_Bblock_Encode (x, B, &rbs, NULL);
+		      if (InvfLevel >= 2)
+			{
+			  UNARY_DECODE (tf);
+			  BIO_Random_Gamma_Encode (tf, &rbs, NULL);
+			}
+		    }
+		  DECODE_DONE
+		    isr->Disk_Last = CurrDoc;
+		}
+	      else
+		{
+		  int k, CurrDoc;
+		  random_bitio_state *Chks = chks + j;
+		  BIO_Random_Seek (chunk_data[j].disk_pos + ptr, Chks);
+		  CurrDoc = isr->Disk_Last;
+		  for (k = 0; k < p; k++)
+		    {
+		      register unsigned long x, tf;
+		      x = BIO_Random_Bblock_Decode (b, Chks, NULL);
+		      if (k == 0)
+			x = x + chunk_data[j].start_doc - isr->Disk_Last;
+		      CurrDoc += x;
+		      BIO_Random_Bblock_Encode (x, B, &rbs, NULL);
+		      if (InvfLevel >= 2)
+			{
+			  tf = BIO_Random_Unary_Decode (Chks, NULL);
+			  BIO_Random_Gamma_Encode (tf, &rbs, NULL);
+			}
+		    }
+		  isr->Disk_Last = CurrDoc;
+		}
+	    }
+	}
+
+      isr->Disk_Ptr = BIO_Random_Tell_X (&rbs);
+
+    }
+  if (chunks_read > 1)
+    {
+      int j;
+      for (j = 0; j < chunks_read - 1; j++)
+	{
+	  Xfree (chks[j].Buf);
+	  ChangeMemInUse (-chks[j].len);
+	}
+      Xfree (chks);
+      ChangeMemInUse (-(chunks_read - 1) * sizeof (random_bitio_state));
+    }
+
+  for (i = 0; i < chunks_read; i++)
+    {
+      Xfree (rbsi[i].Buf);
+      ChangeMemInUse (-rbsi[i].len);
+    }
+  Xfree (rbsi);
+  ChangeMemInUse (-chunks_read * sizeof (random_bitio_state));
+  chunks_read = 0;
+  Xfree (chunk_ptrs);
+  ChangeMemInUse (-chunks_read * sizeof (unsigned long));
+  Disk_pos = 0;
+  BIO_Random_Seek (0, &crbs);
+}
+
+static void 
+MergeIn (void)
+{
+  static int disk_chunks = 0;
+  static header = 0;
+  if (!header)
+    {
+      fprintf (stderr, "ivf.pass2 : ");
+      header = 1;
+    }
+  if (disk_chunks == ChunkLimit || next_docs_left == 0)
+    {
+      fprintf (stderr, "M");
+      DiskMerge ();
+      disk_chunks = 0;
+    }
+  else
+    {
+      fprintf (stderr, "-");
+      DumpChunk ();
+      disk_chunks++;
+    }
+  if (next_docs_left == 0)
+    fprintf (stderr, "\n");
+}
+
+
+static int 
+wl_comp (const void *a, const void *b)
+{
+  return *((int *) a) - *((int *) b);
+}
+
+static int 
+process_doc (u_char * s_in, int l_in)
+{
+  int res;
+  u_char *end = s_in + l_in - 1;
+  unsigned long tocode;
+  unsigned long wl_pos = 0;
+
+  if (!docs_left)
+    LoadCounts ();
+
+  callnum++;
+
+  if (!inaword (s_in, end))
+    if (SkipSGML)
+      PARSE_NON_STEM_WORD_OR_SGML_TAG (s_in, end);
+    else
+      PARSE_NON_STEM_WORD (s_in, end);
+
+  while (s_in <= end)
+    {
+      u_char Word[MAXSTEMLEN + 1];
+
+      PARSE_STEM_WORD (Word, s_in, end);
+      stemmer (idh.stem_method, idh.stemmer_num, Word);
+      if (SkipSGML)
+	PARSE_NON_STEM_WORD_OR_SGML_TAG (s_in, end);
+      else
+	PARSE_NON_STEM_WORD (s_in, end);
+
+      if (*Word == 0)
+	continue;
+
+      res = perf_hash (phd, Word);
+
+      {
+	word_rec *arr = &WordRecs[res];
+	int b = 1 << lg_bs[res];
+	wordnum++;
+
+	tocode = callnum;
+
+	ENCODE_START ((u_char *) MemoryBuffer, arr->ptr)
+
+	  if (tocode > arr->last)
+	  {
+	    register int x;
+	    x = tocode - arr->last - 1;
+	    BBLOCK_ENCODE (x + 1, b);
+	    if (InvfLevel >= 2)
+	      ENCODE_BIT (1);
+	    no_of_ptrs++;
+	    arr->last = tocode;
+	  }
+	else if (InvfLevel >= 2)
+	  {
+	    __pos--;
+	    ENCODE_BIT (0);
+	    ENCODE_BIT (1);
+	  }
+	arr->ptr = __pos;
+	ENCODE_DONE
+      }
+
+      if (MakeWeights)
+	{
+	  if (wl_pos >= wl_size)
+	    {
+	      wl_size += (wl_size >> 1);
+	      word_list = Xrealloc (word_list, sizeof (*word_list) * wl_size);
+	    }
+	  word_list[wl_pos++] = res;
+	}
+    }
+  if (MakeWeights)
+    {
+      float doc_weight = 0.0;
+      if (wl_pos)
+	{
+	  unsigned long *wl = word_list;
+	  unsigned long i, count, val;
+	  qsort (wl, wl_pos, sizeof (*wl), wl_comp);
+	  count = 1;
+	  val = *wl++;
+	  for (i = 1; i <= wl_pos; i++, wl++)
+	    if (i == wl_pos || val != *wl)
+	      {
+		double weight = count * idf[val];
+		doc_weight += weight * weight;
+		count = 1;
+		val = *wl;
+	      }
+	    else
+	      count++;
+	}
+      HTONF(doc_weight);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite ((char *) &doc_weight, sizeof (doc_weight), 1, weights);
+    }
+  docs_left--;
+  if (!docs_left)
+    MergeIn ();
+
+  return COMPALLOK;
+}
+
+int 
+process_ivf_2 (u_char * s_in, int l_in)
+{
+  if (InvfLevel <= 2)
+    return process_doc (s_in, l_in);
+  else
+    {
+      int count = 0;
+      int pos = 0;
+      u_char *start = s_in;
+      while (pos < l_in)
+	{
+	  if (s_in[pos] == TERMPARAGRAPH)
+	    {
+	      int len = pos + s_in + 1 - start;
+	      if (process_doc (start, len) != COMPALLOK)
+		return (COMPERROR);
+	      start = s_in + pos + 1;
+	      count++;
+	    }
+	  pos++;
+	}
+      if (start < s_in + pos)
+	{
+	  if (process_doc (start, pos + s_in - start) != COMPALLOK)
+	    return (COMPERROR);
+	  count++;
+	}
+      HTONSI(count);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite ((char *) &count, sizeof (count), 1, invf_para);
+    }
+  return COMPALLOK;
+}
+
+
+
+
+
+static void 
+stats (unsigned long len)
+{
+#ifndef SILENT
+  fseek (count, 0, 2);
+  fseek (count_trans, 0, 2);
+  fseek (invf_state, 0, 2);
+  fseek (invf, 0, 0);
+  fseek (invf, 0, 2);
+  fseek (chunks, 0, 2);
+  fseek (chunk_state, 0, 2);
+  Message ("File sizes\n");
+  Message ("  Chunk desc    : %10u bytes\n", ftell (count));
+  Message ("  Chunk trans   : %10u bytes\n", ftell (count_trans));
+  Message ("  Chunks        : %10u bytes\n", ftell (chunks));
+  Message ("  Chunk state   : %10u bytes\n", ftell (chunk_state));
+  Message ("  Invf state    : %10u bytes\n", ftell (invf_state));
+  Message ("  Peak invf     : %10u bytes\n", len);
+  Message ("  Final invf    : %10u bytes\n", ftell (invf));
+  Message ("Peak disk usage : %10.2f %%\n",
+	   (double) (ftell (count) + ftell (count_trans) +
+		     ftell (invf_state) + ftell (chunks) +
+		     ftell (chunk_state) + len) / ftell (invf) * 100.0);
+#endif
+}
+
+
+/* ARGSUSED */
+int 
+done_ivf_2 (char *FileName)
+{
+  long i;
+  mg_ullong totalIbits;
+  unsigned long invf_len;
+  unsigned long bytes_output;
+  struct invf_file_header ifh;
+
+  if (weights)
+    fclose (weights);
+  if (invf_para)
+    fclose (invf_para);
+
+  free_perf_hash (phd);
+
+  free (MemoryBuffer);
+  ChangeMemInUse (-MemBufSize);
+
+  BIO_Random_Done (&rbs);
+  BIO_Random_Done (&rbsp);
+  fflush (invf);
+
+  fseek (invf, 0, 2);
+  invf_len = ftell (invf);
+
+  fseek (invf_out, sizeof (long), 0);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL2(dict_size, ifh.no_of_words);
+  HTONUL2(no_of_ptrs, ifh.no_of_ptrs);
+  ifh.skip_mode = 0;
+  bzero ((char *) ifh.params, sizeof (ifh.params));
+  HTONUL2(InvfLevel, ifh.InvfLevel);
+  fwrite ((char *) &ifh, sizeof (ifh), 1, invf_out);
+
+  bytes_output = ftell (invf_out);
+
+  totalIbits = sizeof (unsigned long) * 8;		/* The magic number */
+  totalIbits += 8 * 200;	/* A 200 byte gap */
+
+  /* find the right place in the file to start reading p values */
+  fseek (dict, sizeof (unsigned long) + sizeof (struct invf_dict_header), 0);
+  for (i = 0; i < dict_size; i++)
+    {
+      invf_state_rec *isr;
+      unsigned long fcnt, wcnt, s, e;
+      register unsigned long p;
+      u_char dummy1, dummy2[MAXSTEMLEN + 1];
+
+      /* output location to the invf_idx  */
+      HTONUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite ((char *) &bytes_output, sizeof (bytes_output), 1, invf_idx);
+      NTOHUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+
+      /* read an entry for a word, just to get p value */
+      dummy1 = fgetc (dict);
+      dummy1 = fgetc (dict);
+      fread (dummy2, sizeof (u_char), dummy1, dict);
+      fread ((char *) &fcnt, sizeof (fcnt), 1, dict);
+      fread ((char *) &wcnt, sizeof (wcnt), 1, dict);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      p = fcnt;
+
+      isr = in_cache (i);
+
+      e = (isr->Disk_Ptr + 7ul) >> 3ul;
+      s = totalIbits >> 3;
+
+      fseek (invf_in, s, 0);
+      while (s < e)
+	{
+	  u_char c = getc (invf_in);
+	  if (s == e - 1)
+	    {
+	      u_char ands[8] =
+	      {0xff, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
+	      c &= ands[isr->Disk_Ptr & 7ul];
+	    }
+	  putc (c, invf_out);
+	  bytes_output++;
+	  s++;
+	}
+
+      totalIbits += BIO_Bblock_Bound_b (N, p, isr->Disk_B);
+      if (InvfLevel >= 2)
+	totalIbits += BIO_Gamma_Bound (wcnt, fcnt);
+#ifdef USE_LONG_LONG
+      totalIbits = (totalIbits + 7ull) & 0xfffffffffffffff8ull;
+#else
+      totalIbits = (totalIbits + 7ul) & 0xfffffff8ul;
+#endif
+
+    }
+
+  fclose (invf_in);
+
+  /* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  if (!(_chsize (_fileno (invf_out), bytes_output)))
+    Message ("Could not truncate invf.");
+#else
+  ftruncate (fileno (invf_out), bytes_output);
+#endif
+
+  fclose (invf_out);
+
+  HTONUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite ((char *) &bytes_output, sizeof (bytes_output), 1, invf_idx);
+  NTOHUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  fclose (invf_idx);
+
+#ifndef SILENT
+  {
+    char *temp_str = msg_prefix;
+    unsigned long total;
+    msg_prefix = "ivf.pass2";
+    stats (invf_len);
+    Message ("Pass two data structures      : %6.3f Mbyte\n",
+	     (double) totalDbytes / 1024 / 1024);
+    total = totalDbytes;
+    Message ("Pass two hash structure(s)    : %6.3f Mbyte\n",
+	     (double) totalHbytes / 1024 / 1024);
+    total += totalHbytes;
+    Message ("Peak extra memory in use      : %6.3f Mbyte\n",
+	     (double) MaxMemInUse / 1024 / 1024);
+    total += MaxMemInUse;
+    Message ("Peak total memory in use      : %6.3f Mbyte\n",
+	     (double) total / 1024 / 1024);
+    msg_prefix = temp_str;
+  }
+#endif
+
+  Xfree (WordRecs);
+  Xfree (lg_bs);
+
+  /* Free the memory allocated for the BIO_Random */
+  occur_to_lexical (-1);
+
+  BIO_Random_Done (&crbs);
+
+  fclose (invf);
+  fclose (dict);
+  fclose (hash);
+  fclose (count);
+  fclose (count_trans);
+  fclose (chunk_state);
+  fclose (chunks);
+  fclose (invf_state);
+  return (COMPALLOK);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/lists.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/lists.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/lists.c	(revision 10506)
@@ -0,0 +1,214 @@
+/**************************************************************************
+ *
+ * lists.c -- List processing functions for boolean queries
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+
+#include "lists.h"
+#include "local_strings.h"
+#include "locallib.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:01  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1999/07/01 09:30:48  rjmcnab
+   Changes for better match reporting.
+
+   Revision 1.1  1998/11/17 09:34:47  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:50  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:37  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+
+
+/*
+ * Make a DocList large enough to hold num entries 
+ */
+DocList *
+MakeDocList (int num)
+{
+  DocList *d;
+  if (!(d = Xmalloc (sizeof (DocList) + sizeof (DocEntry) * (num - 1))))
+    return (NULL);
+  d->num = 0;
+  d->total_retrieved = 0;
+  d->is_approx = 0;
+  return (d);
+}
+
+
+/*
+ * Change the size of a DocList so that it can hold num entries 
+ */
+DocList *
+ResizeDocList (DocList * d, int num)
+{
+  if (!(d = Xrealloc (d, sizeof (DocList) + sizeof (DocEntry) * (num - 1))))
+    return (NULL);
+  return (d);
+}
+
+
+/* IntersectLists () */
+/* Returns the intersection of List1 and List2 by deleting from List1 all */
+/* entries not in List2.  All of List2 is freed, and the nodes of List1 not */
+/* included in the resultant list are freed. */
+/* On exit the intersection of the lists is returned, or NULL on empty */
+/* intersection. */
+/* Assumes that both lists are ordered on increasing Value. */
+DocList *
+IntersectLists (DocList * List1, DocList * List2)
+{
+  DocEntry *s1, *d1, *s2;
+  if (!List2 || !List1)
+    {
+      if (List1)
+	Xfree (List1);
+      if (List2)
+	Xfree (List2);
+      return (MakeDocList (0));
+    }
+  d1 = s1 = List1->DE;
+  s2 = List2->DE;
+  while (s1 - List1->DE < List1->num && s2 - List2->DE < List2->num)
+    {
+      if (s1->DocNum == s2->DocNum)
+	*d1++ = *s1++;
+      if (s1 - List1->DE < List1->num)
+	while (s2 - List2->DE < List2->num && s2->DocNum < s1->DocNum)
+	  s2++;
+      if (s2 - List2->DE < List2->num)
+	while (s1 - List1->DE < List1->num && s1->DocNum < s2->DocNum)
+	  s1++;
+    }
+  List1->num = d1 - List1->DE;
+  Xfree (List2);
+  return (List1);
+}
+
+
+/* DiffLists () */
+/* Returns the difference of List1 and List2 by deleting from List1 all */
+/* entries in List2.  All of List2 is freed, and the nodes of List1 not */
+/* included in the resultant list are freed. */
+/* On exit the differrence of the lists is returned, or NULL on empty */
+/* intersection. */
+/* Assumes that both lists are ordered on increasing Value. */
+DocList *
+DiffLists (DocList * List1, DocList * List2)
+{
+  DocEntry *s1, *d1, *s2;
+  if (!List1)
+    {
+      if (List2)
+	Xfree (List2);
+      return (MakeDocList (0));
+    }
+  if (!List2)
+    return (List1);
+  d1 = s1 = List1->DE;
+  s2 = List2->DE;
+  while (s1 - List1->DE < List1->num)
+    {
+      if (s2 - List2->DE == List2->num)
+	*d1++ = *s1++;
+      else
+	{
+	  if (s1->DocNum == s2->DocNum)
+	    {
+	      s1++;
+	      s2++;
+	    }
+	  else if (s1->DocNum < s2->DocNum)
+	    *d1++ = *s1++;
+	  else
+	    s2++;
+	}
+    }
+  List1->num = d1 - List1->DE;
+  Xfree (List2);
+  return (List1);
+}
+
+/* MergeLists () */
+/* Finds the union of two lists and returns the head of the new list formed. */
+/* Assumes that both lists are ordered on increasing Value. */
+DocList *
+MergeLists (DocList * List1, DocList * List2)
+{
+  DocList *NewList;
+  DocEntry *d, *s1, *s2;
+  if (!List1)
+    {
+      if (List2)
+	return (List2);
+      else
+	return (MakeDocList (0));
+    }
+  if (!List2)
+    return (List1);
+  if (!(NewList = MakeDocList (List1->num + List2->num)))
+    {
+      Xfree (List1);
+      Xfree (List2);
+      return (NULL);
+    }
+
+  s1 = List1->DE;
+  s2 = List2->DE;
+  d = NewList->DE;
+  while (s1 - List1->DE < List1->num || s2 - List2->DE < List2->num)
+    {
+      if (s1 - List1->DE >= List1->num)
+	*d++ = *s2++;
+      else if (s2 - List2->DE >= List2->num)
+	*d++ = *s1++;
+      else if (s1->DocNum == s2->DocNum)
+	{
+	  *d = *s1++;
+	  (d++)->Weight += (s2++)->Weight;
+	}
+      else if (s1->DocNum < s2->DocNum)
+	*d++ = *s1++;
+      else
+	*d++ = *s2++;
+    }
+  NewList->num = d - NewList->DE;
+  Xfree (List1);
+  Xfree (List2);
+  return (NewList);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/lists.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/lists.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/lists.h	(revision 10506)
@@ -0,0 +1,59 @@
+/**************************************************************************
+ *
+ * lists.h -- List processing functions for boolean queries
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_LISTS
+#define H_LISTS
+
+
+
+typedef struct DocEntry
+  {
+    float Weight;
+    int DocNum;
+    unsigned long SeekPos;	/* position in the text file in bytes */
+    unsigned long Len;		/* length of the document in bytes */
+    char *CompTextBuffer;
+    struct DocEntry *Next;
+    short or_included;		/*[TS:Mar/95] whether included in an AND of ORed-terms */
+  }
+DocEntry;
+
+typedef struct DocList
+  {
+    int num;
+    int total_retrieved; /* valid if > 0 */
+    int is_approx;       /* whether total_retrieved is approximate */
+    DocEntry DE[1];
+  }
+DocList;
+
+DocList *MakeDocList (int num);
+DocList *ResizeDocList (DocList * d, int num);
+DocList *IntersectLists (DocList * List1, DocList * List2);
+DocList *DiffLists (DocList * List1, DocList * List2);
+DocList *MergeLists (DocList * List1, DocList * List2);
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/locallib.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/locallib.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/locallib.c	(revision 10506)
@@ -0,0 +1,304 @@
+/**************************************************************************
+ *
+ * locallib.c -- Misc functions
+ * Copyright (C) 1994  Gary Eddy, Alistair Moffat and Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "bitio_gen.h"
+#include "huffman.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "locallib.h"
+#include "text.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:02  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:49  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:51  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:38  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+int 
+vecentropy (int *A, int n)
+{
+  int total = 0, i;
+  double bits = 0.0;
+
+  for (i = 0; i < n; i++)
+    total += A[i];
+  for (i = 0; i < n; i++)
+    if (A[i])
+      bits += A[i] * log2 (1.0 * total / A[i]);
+  return ((int) (bits + 0.9999));
+
+}
+
+static void 
+siftdown (int *A, int i, int n)
+{
+  int ms, t;
+
+  while (2 * i + 1 <= n - 1)
+    {
+      if (2 * i + 1 == n - 1 || A[2 * i + 1] < A[2 * i + 2])
+	ms = 2 * i + 1;
+      else
+	ms = 2 * i + 2;
+      if (A[i] > A[ms])
+	{
+	  t = A[i];
+	  A[i] = A[ms];
+	  A[ms] = t;
+	}
+      i = ms;
+    }
+}
+
+static void 
+buildheap (int *A, int n)
+{
+  int i;
+  for (i = n / 2 - 1; i >= 0; i--)
+    siftdown (A, i, n);
+}
+
+int 
+huffcodebits (unsigned long *A, int n)
+{
+  int i, j, tot = 0, bits = 0, v1, v2, *B;
+
+  B = (int *) Xmalloc (n * sizeof (int));
+  j = 0;
+  for (i = 0; i < n; i++)
+    {
+      if (A[i])
+	{
+	  tot += (B[j++] = A[i]);
+	}
+    }
+  n = j;
+
+  if (n == 0 || tot == 0)
+    return (0);
+
+  buildheap (B, n);
+  while (n > 1)
+    {
+      v1 = B[0];
+      B[0] = B[n - 1];
+      n--;
+      siftdown (B, 0, n);
+      v2 = B[0];
+      B[0] = v1 + v2;
+      siftdown (B, 0, n);
+      bits += v1 + v2;
+    }
+  Xfree (B);
+  return (bits);
+}
+
+
+int 
+modelbits (unsigned long *A, int n)
+{
+  int i, bits = 0, last, N = 0;
+
+  last = -1;
+  for (i = 0; i < n; i++)
+    {
+      if (A[i])
+	{
+	  bits += BIO_Gamma_Length (i - last) + BIO_Gamma_Length (A[i]);
+	  last = i;
+	  N++;
+	}
+    }
+  if (N == 0)
+    return (0);
+  bits += BIO_Gamma_Length (N);
+  return (bits);
+}
+
+
+
+
+
+/* Find the next prime number larger than p */
+int 
+prime (int p)
+{
+  int limit;
+  p += (p & 1) + 1;
+  limit = (int) sqrt ((double) p) + 1;
+  do
+    {
+      int j;
+      while (limit * limit < p)
+	limit++;
+      for (j = 3; j <= limit && p % j; j += 2)
+	;			/* NULLBODY */
+      if (j > limit)
+	break;
+      p += 2;
+    }
+  while (1);
+  return (p);
+}
+
+
+
+int 
+Read_cdh (FILE * f, compression_dict_header * cdh, u_long * mem,
+	  u_long * disk)
+{
+  if (disk)
+    (*disk) += sizeof (*cdh);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  if (fread (cdh, sizeof (*cdh), 1, f) == 1)
+    {
+      int i;
+      NTOHUL(cdh->dict_type);
+      NTOHUL(cdh->novel_method);
+      for (i = 0; i < TEXT_PARAMS; i++)
+	NTOHUL(cdh->params[i]);
+      NTOHUL(cdh->num_words[0]);
+      NTOHUL(cdh->num_words[1]);
+      NTOHUL(cdh->num_word_chars[0]);
+      NTOHUL(cdh->num_word_chars[1]);
+      NTOHUL(cdh->lookback);
+      return 0;
+    }
+  else
+    return -1;
+}
+
+
+int 
+F_Read_cdh (File * f, compression_dict_header * cdh, u_long * mem,
+	    u_long * disk)
+{
+  if (disk)
+    (*disk) += sizeof (*cdh);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  if (Fread (cdh, sizeof (*cdh), 1, f) == 1)
+    {
+      int i;
+      NTOHUL(cdh->dict_type);
+      NTOHUL(cdh->novel_method);
+      for (i = 0; i < TEXT_PARAMS; i++)
+	NTOHUL(cdh->params[i]);
+      NTOHUL(cdh->num_words[0]);
+      NTOHUL(cdh->num_words[1]);
+      NTOHUL(cdh->num_word_chars[0]);
+      NTOHUL(cdh->num_word_chars[1]);
+      NTOHUL(cdh->lookback);
+      return 0;
+    }
+  else
+    return -1;
+}
+
+
+int 
+Read_cfh (FILE * f, comp_frags_header * cfh, u_long * mem, u_long * disk)
+{
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (Read_Huffman_Data (f, &cfh->hd, mem, disk) == -1)
+    return -1;
+  if (fread (&cfh->uncompressed_size,
+	     sizeof (cfh->uncompressed_size), 1, f) != 1)
+    return -1;
+  NTOHUL(cfh->uncompressed_size);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (disk)
+    (*disk) += sizeof (cfh->uncompressed_size);
+
+  bzero ((char *) cfh->huff_words_size, sizeof (cfh->huff_words_size));
+
+  if (fread (cfh->huff_words_size + cfh->hd.mincodelen,
+	     sizeof (*cfh->huff_words_size),
+	     cfh->hd.maxcodelen - cfh->hd.mincodelen + 1, f) !=
+      cfh->hd.maxcodelen - cfh->hd.mincodelen + 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = cfh->hd.mincodelen; i < cfh->hd.maxcodelen + 1; i++)
+    NTOHUL(cfh->huff_words_size[i]);
+
+  if (disk)
+    (*disk) += sizeof (*cfh->huff_words_size) *
+      (cfh->hd.maxcodelen - cfh->hd.mincodelen + 1);
+  return 0;
+}
+
+
+
+int 
+F_Read_cfh (File * f, comp_frags_header * cfh, u_long * mem, u_long * disk)
+{
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (F_Read_Huffman_Data (f, &cfh->hd, mem, disk) == -1)
+    return -1;
+  if (Fread (&cfh->uncompressed_size,
+	     sizeof (cfh->uncompressed_size), 1, f) != 1)
+    return -1;
+  NTOHUL(cfh->uncompressed_size);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (disk)
+    (*disk) += sizeof (cfh->uncompressed_size);
+
+  bzero ((char *) cfh->huff_words_size, sizeof (cfh->huff_words_size));
+
+  if (Fread (cfh->huff_words_size + cfh->hd.mincodelen,
+	     sizeof (*cfh->huff_words_size),
+	     cfh->hd.maxcodelen - cfh->hd.mincodelen + 1, f) !=
+      cfh->hd.maxcodelen - cfh->hd.mincodelen + 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = cfh->hd.mincodelen; i < cfh->hd.maxcodelen + 1; i++)
+    NTOHUL(cfh->huff_words_size[i]);
+
+  if (disk)
+    (*disk) += sizeof (*cfh->huff_words_size) *
+      (cfh->hd.maxcodelen - cfh->hd.mincodelen + 1);
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/locallib.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/locallib.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/locallib.h	(revision 10506)
@@ -0,0 +1,52 @@
+/**************************************************************************
+ *
+ * locallib.h -- Misc functions
+ * Copyright (C) 1994  Gary Eddy, Alistair Moffat and Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef LOCALLIB_H
+#define LOCALLIB_H
+
+#include "sysfuncs.h"
+
+#include "text.h"
+
+#define NUMOF(a) (sizeof(a)/sizeof((a)[0]))
+
+int vecentropy (int *A, int n);
+
+int huffcodebits (unsigned long *A, int n);
+
+int modelbits (unsigned long *A, int n);
+
+int prime (int p);
+
+
+int Read_cdh (FILE * f, compression_dict_header * cdh, u_long * mem, u_long * disk);
+
+int Read_cfh (FILE * f, comp_frags_header * cfh, u_long * mem, u_long * disk);
+
+int F_Read_cdh (File * f, compression_dict_header * cdh, u_long * mem,
+		u_long * disk);
+
+int F_Read_cfh (File * f, comp_frags_header * cfh, u_long * mem, u_long * disk);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg.h	(revision 10506)
@@ -0,0 +1,42 @@
+/**************************************************************************
+ *
+ * mg.h -- General header file
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_MG
+#define H_MG
+
+
+#define COMPALLOK	(0)
+#define COMPERROR	(-1)
+
+#define MAXSTRING       3000000
+#define BUFFERSIZE      (MAXSTRING+30000)
+
+
+
+
+#define	MAXLN	65536
+#define WORDS           1
+#define NONWORDS        0
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg.special.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg.special.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg.special.c	(revision 10506)
@@ -0,0 +1,115 @@
+/**************************************************************************
+ *
+ * mg.special.c -- Special pass for mg_passes
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "mg.h"
+#include "build.h"
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:03  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:34:51  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:53  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:44  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+FILE *fp;
+
+
+int 
+init_special (char *FileName)
+{
+  char FName[200];
+  sprintf (FName, "%s%s", FileName, ".docnums");
+  if (!(fp = fopen (FName, "w")))
+    return (COMPERROR);
+  return (COMPALLOK);
+}
+
+
+
+
+int 
+process_special (u_char * s_in, int l_in)
+{
+  static int un = 1;
+  char *s_done = (char *) (s_in + l_in);
+  for (; (char *) s_in != s_done; s_in++)
+    if (*s_in == '<')
+      {
+	if (strncmp ((char *) s_in, "<DOCNO>", 7) == 0)
+	  {
+	    char *s_end = (char *) (s_in + 1);
+	    for (; s_end != s_done; s_end++)
+	      if (*s_end == '<')
+		if (strncmp (s_end, "</DOCNO>", 8) == 0)
+		  break;
+	    if (s_end == s_done)
+	      {
+		fprintf (fp, "NO DOC ID %d\n", un++);
+		return COMPALLOK;
+	      }
+	    s_in += 7;
+	    while (s_end != (char *) s_in &&
+		   (*(s_end - 1) == ' ' || *(s_end - 1) == '\n'))
+	      s_end--;
+	    while ((char *) s_in != s_end &&
+		   (*s_in == ' ' || *s_in == '\n'))
+	      s_in++;
+	    for (; (char *) s_in != s_end; s_in++)
+	      putc (*s_in, fp);
+	    putc ('\n', fp);
+	    return (COMPALLOK);
+	  }
+      }
+  fprintf (fp, "NO DOC ID %d\n", un++);
+  return (COMPALLOK);
+}
+
+
+
+
+
+
+
+
+int 
+done_special (char *FileName)
+{
+  fclose (fp);
+  return COMPALLOK;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_compression_dict.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_compression_dict.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_compression_dict.1	(revision 10506)
@@ -0,0 +1,219 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_compression_dict 1 \*(Dt CITRI
+.SH NAME
+mg_compression_dict \- build a compression dictionary.
+.SH SYNOPSIS
+.B mg_compression_dict
+[
+.B \-h
+]
+[
+.BR \-C " |"
+.BR \-P " |"
+.B  \-S
+]
+.if n .ti +9n
+[
+.BR \-0 " |"
+.BR \-1 " |"
+.BR \-2 " |"
+.B  \-3
+]
+[
+.BR \-H " |"
+.BR \-B " |"
+.BR \-D " |"
+.BR \-Y " |"
+.B  \-M
+]
+.if n .ti +9n
+.if t .ti +.5i
+[
+.BI \-l " lookback"
+]
+[
+.BI \-k " mem"
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_compression_dict
+builds a compression dictionary based on the statistics gathered
+during the first pass over the text.  The options to the program are
+mainly concerned with limiting the amount of memory the dictionary
+will use and with how the text compressor will cope with any novel
+words found during the compression phase.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-C
+Build a complete dictionary from the statistics file.  If during the
+text compression phase a novel word is found, then the compressor will
+produce an error message and stop.
+.TP
+.B \-P
+Build a partial dictionary from the statistics file.  This dictionary
+assumes that the statistics file are based on the entire text.  The
+statistics of words not includes in the dictionary are used to
+calculate the escape probability.  If novel words are being coded
+character by character, then there may not be a Huffman code for every
+possible character.  This means that the compressor may fail if a novel
+word contains a novel character.
+.TP
+.B \-S
+Build a seed dictionary from the statistics file.  This dictionary
+assumes that the statistics file is based on only a portion of the
+text to be compressed.  The probability of a novel word is based on the
+number of words that have only occurred once.  If novel words are being
+coded character by character, then the Huffman codes for characters are
+based on the frequency of characters in the dictionary.
+.TP
+.B \-0
+All words from the statistics file are included in the built
+dictionary.
+.TP
+.B \-1
+Words are included in the dictionary until the dictionary reaches the
+desired size.  Words are selected for the dictionary based on the order
+they occurred in the source text.
+.TP
+.B \-2
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.
+.TP
+.B \-3
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.  Words are the shuffled back and forth between the
+`keep' and `discard' lists to find the `optimal' set of words that
+should be in the dictionary.
+.TP
+.B \-H
+This specifies that novel words will be coded character by character
+using Huffman codes.
+.TP
+.B \-B
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using binary codes.  The binary code represents their occurrence
+position in the auxiliary dictionary.
+.TP
+.B \-D
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using delta codes.  The delta code represents their occurrence position
+in the auxiliary dictionary.
+.TP
+.B \-Y
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This generally
+produces better compression than
+.B \-B
+or
+.BR \-D .
+.TP
+.B \-M
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This method is
+adaptive within documents, and generally produces better compression
+than
+.BR \-B ,
+.B \-D
+or
+.BR \-Y .
+.TP
+.BI \-l " lookback"
+The generated dictionary is designed to be front coded when it is
+loaded into memory.  Under normal circumstances, a front-coded
+dictionary would require scanning from the beginning in order to find
+any particular word.  However, every
+.I lookback
+words in the dictionary, the whole word is stored and a pointer to that
+word maintained.  E.g., if
+.I lookback
+is 4, then every fourth word is stored in its entirety.
+.TP
+.BI \-k " mem"
+This limits the amount of memory to use for the generated
+dictionary.  Words are selected for the dictionary based of the text
+statistics, and whether
+.BR \-0 , " \-1" , " \-2"
+or
+.B \-3
+is specified.  The memory is calculated assuming a lookback of 0,
+irrespective of what actual lookback is specified.  This means that if
+a non-zero lookback is given, the dictionary will actually occupy
+less space than specified by
+.BR \-k .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.stats
+Statistics about the source text.
+.TP
+.B *.text.dict
+Compression dictionary for the source text.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_compression_dict.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_compression_dict.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_compression_dict.c	(revision 10506)
@@ -0,0 +1,1084 @@
+/**************************************************************************
+ *
+ * mg_compression_dict.c -- Routines for reading the compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_gen.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "timing.h"
+#include "mgheap.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "invf.h"
+#include "text.h"
+#include "words.h"
+#include "mg.h"
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+/*
+   $Log$
+   Revision 1.2  1999/12/10 15:04:25  cs025
+   Incorrect use of NTOHUL on a double value (num_bytes).
+
+   Revision 1.1  1999/08/10 21:18:04  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.4  1999/01/15 03:05:51  rjmcnab
+
+   Renamed lib/heap to be lib/mgheap (it was causing some problems with
+   some versions of the STL libraries which contained a heap.h)
+
+   Revision 1.3  1998/12/17 09:12:52  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:44  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:52  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:54  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:45  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+/* #define DEBUG1 */
+
+/* #define DEBUG */
+
+#define is_power_of_two(a) ((a) != 0 && (((a) & ((a)-1)) == 0))
+
+#define MAX_RECALCULATIONS 100
+
+typedef struct WordData
+  {
+    u_long freq, occur_num;
+    float saving;
+    float char_bit_cost;
+    u_long num_trans;
+    u_char *word;
+  }
+WordData;
+
+static WordData *Words[2];
+static u_long Num[2];
+static u_long chars[2];
+
+#define KIND(p) (((p) >= Words[0] && (p) < Words[0] + Num[0]) ? 0 : 1)
+#define IsWord(p) (((p) >= Words[1] && (p) < Words[1] + Num[1]) ? 1 : 0)
+#define IsNonWord(p) (((p) >= Words[0] && (p) < Words[0] + Num[0]) ? 1 : 0)
+
+
+typedef struct DictData
+  {
+    WordData **wd;
+    u_long num_wds;
+    u_long chars;
+  }
+DictData;
+
+typedef DictData DictInfo[2];
+
+static DictInfo keep, discard, all;
+static compression_stats_header csh;
+
+static char *file_name = "";
+static u_long novel_method = MG_NOVEL_HUFFMAN_CHARS;
+
+
+static void ReadInWords (char *);
+static void Select_on (int k, heap_comp hc);
+static void Method3 (int k);
+static void Select_all (void);
+static u_long WriteOutWords (char *, u_long, int);
+static int DecFreqIncWL (void *a, void *b);
+static int OccuranceOrder (void *a, void *b);
+
+
+
+int main (int argc, char **argv)
+{
+  ProgTime StartTime;
+  int ch;
+  char type = 'C';
+  char mode = '0';
+  int lookback = 2;
+  double k = 0;
+  u_long mem_reqd;
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "0123CPSf:d:l:hk:HBDYM")) != -1)
+    switch (ch)
+      {
+      case 'H':
+	novel_method = MG_NOVEL_HUFFMAN_CHARS;
+	break;
+      case 'B':
+	novel_method = MG_NOVEL_BINARY;
+	break;
+      case 'D':
+	novel_method = MG_NOVEL_DELTA;
+	break;
+      case 'Y':
+	novel_method = MG_NOVEL_HYBRID;
+	break;
+      case 'M':
+	novel_method = MG_NOVEL_HYBRID_MTF;
+	break;
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'C':
+      case 'P':
+      case 'S':
+	type = ch;
+	break;
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+	mode = ch;
+	break;
+      case 'l':
+	lookback = atoi (optarg);
+	if (!is_power_of_two (lookback))
+	  FatalError (1, "The lookback value must be a power of 2");
+	lookback = floorlog_2 (lookback);
+	break;
+      case 'k':
+	k = atof (optarg) * 1024;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-l lookback] [-f input_file]"
+	"[-d data directory] [-h] [-0|-1|-2|-3] [-C|-P|-S] [-k mem (Kb)]\n",
+		 argv[0]);
+	exit (1);
+      }
+  GetTime (&StartTime);
+
+  ReadInWords (file_name);
+
+  if (type == 'C')
+    {
+      Select_all ();
+      mem_reqd = WriteOutWords (file_name, MG_COMPLETE_DICTIONARY, lookback);
+    }
+  else
+    {
+      switch (mode)
+	{
+	case '0':
+	  Select_all ();
+	  break;
+	case '1':
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+	  Select_on ((int) k, OccuranceOrder);
+	  break;
+	case '2':
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+	  Select_on ((int) k, DecFreqIncWL);
+	  break;
+	case '3':
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+	  Method3 ((int) k);
+	  break;
+	}
+      if (type == 'P')
+	{
+	  mem_reqd = WriteOutWords (file_name, MG_PARTIAL_DICTIONARY, lookback);
+	}
+      else
+	{
+	  mem_reqd = WriteOutWords (file_name, MG_SEED_DICTIONARY, lookback);
+	}
+    }
+
+  Message ("Num words           : %8u -> %8u\n", Num[1], keep[1].num_wds);
+  Message ("Num non-words       : %8u -> %8u\n", Num[0], keep[0].num_wds);
+  Message ("Chars of words      : %8u -> %8u\n", chars[1], keep[1].chars);
+  Message ("Chars of non-words  : %8u -> %8u\n", chars[0], keep[0].chars);
+  Message ("Mem usage           : %8u -> %8u\n",
+	   (Num[0] + Num[1]) * sizeof (char *) + chars[0] + chars[1],
+	     (keep[0].num_wds + keep[1].num_wds) * sizeof (char *) +
+	   keep[0].chars + keep[1].chars);
+  Message ("Actual mem required : %8u\n", mem_reqd);
+
+  Message ("%s", ElapsedTime (&StartTime, NULL));
+  return 0;
+}
+
+
+
+
+static void 
+ReadInWords (char *filename)
+{
+  FILE *f;
+  unsigned long i;
+  f = open_file (filename, TEXT_STATS_DICT_SUFFIX, "rb",
+		 MAGIC_STATS_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread (&csh, sizeof (csh), 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes);
+
+  for (i = 0; i < 2; i++)
+    {
+      frags_stats_header fsh;
+      char *buf;
+      WordData *wd;
+      int j;
+      chars[i] = 0;
+
+      fread (&fsh, sizeof (fsh), 1, f);
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fsh.num_frags);
+      NTOHUL(fsh.mem_for_frags);
+
+      Num[i] = all[i].num_wds = fsh.num_frags;
+
+      /* The +1 on the following line is to leave room for the esc code. */
+      all[i].wd = Xmalloc (sizeof (WordData *) * Num[i] + 1);
+
+      buf = Xmalloc (fsh.mem_for_frags);
+      wd = Words[i] = Xmalloc (sizeof (WordData) * Num[i]);
+      for (j = 0; j < Num[i]; j++, wd++)
+	{
+	  int len;
+	  fread (&wd->freq, sizeof (wd->freq), 1, f);
+	  NTOHUL(wd->freq);  /* [RPAP - Jan 97: Endian Ordering] */
+	  fread (&wd->occur_num, sizeof (wd->occur_num), 1, f);
+	  NTOHUL(wd->occur_num);  /* [RPAP - Jan 97: Endian Ordering] */
+	  len = fgetc (f);
+	  wd->word = (u_char *) buf;
+	  *buf++ = len;
+	  fread (buf, len, 1, f);
+	  buf += len;
+	  all[i].wd[j] = wd;
+	}
+      chars[i] = fsh.mem_for_frags - fsh.num_frags;
+    }
+  fclose (f);
+}
+
+
+static void 
+Alloc_keep_discard (void)
+{
+  keep[0].num_wds = 0;
+  keep[0].wd = Xmalloc ((Num[0] + 1) * sizeof (WordData *));
+  keep[1].num_wds = 0;
+  keep[1].wd = Xmalloc ((Num[1] + 1) * sizeof (WordData *));
+  discard[0].num_wds = 0;
+  discard[0].wd = Xmalloc ((Num[0] + 1) * sizeof (WordData *));
+  discard[1].num_wds = 0;
+  discard[1].wd = Xmalloc ((Num[1] + 1) * sizeof (WordData *));
+}
+
+
+static int 
+sort_comp (const void *a, const void *b)
+{
+  WordData *aa = *(WordData **) a;
+  WordData *bb = *(WordData **) b;
+  return casecompare (aa->word, bb->word);  /* [RPAP - Jan 97: Stem Index Change] */
+}
+
+
+
+static void 
+SortAndCount_DictData (DictData * dd)
+{
+  int i;
+  WordData **wd;
+  qsort (dd->wd, dd->num_wds, sizeof (WordData *), sort_comp);
+  dd->chars = 0;
+  wd = dd->wd;
+  for (i = 0; i < dd->num_wds; i++, wd++)
+    dd->chars += (*wd)->word[0];
+}
+
+
+static void 
+Select_all (void)
+{
+  int i;
+  Alloc_keep_discard ();
+  keep[0].num_wds = Num[0];
+  for (i = 0; i < Num[0]; i++)
+    keep[0].wd[i] = Words[0] + i;
+  keep[1].num_wds = Num[1];
+  for (i = 0; i < Num[1]; i++)
+    keep[1].wd[i] = Words[1] + i;
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+}
+
+
+
+
+static int 
+DecFreqIncWL (void *a, void *b)
+{
+  WordData *aa = *(WordData **) a;
+  WordData *bb = *(WordData **) b;
+  if (aa->freq > bb->freq)
+    return -1;
+  else if (aa->freq < bb->freq)
+    return 1;
+  else
+    return bb->word[0] - aa->word[0];
+}
+
+
+static int 
+OccuranceOrder (void *a, void *b)
+{
+  WordData *aa = *(WordData **) a;
+  WordData *bb = *(WordData **) b;
+  if (aa->occur_num > bb->occur_num)
+    return 1;
+  else if (aa->occur_num < bb->occur_num)
+    return -1;
+  else
+    return 0;
+}
+
+
+static void 
+Select_on (int k, heap_comp hc)
+{
+  int i, num, mem;
+  WordData **wd;
+
+  Alloc_keep_discard ();
+
+  num = Num[0] + Num[1];
+  wd = Xmalloc (num * sizeof (WordData *));
+  for (i = 0; i < Num[0]; i++)
+    wd[i] = Words[0] + i;
+  for (i = 0; i < Num[1]; i++)
+    wd[i + Num[0]] = Words[1] + i;
+
+  heap_build (wd, sizeof (*wd), num, hc);
+
+  mem = 0;
+  while (k > mem && num)
+    {
+      int idx;
+      WordData *word = wd[0];
+#ifdef DEBUG
+      fprintf (stderr, "%4d:%4d:%8d :%8d :%8d : \"%s\"\n",
+	       keep[0].num_wds, keep[1].num_wds,
+	       mem, word->freq, word->occur_num, word2str (word->word));
+#endif
+      mem += sizeof (u_char *) + word->word[0];
+      heap_deletehead (wd, sizeof (*wd), &num, hc);
+      idx = KIND (word);
+      keep[idx].wd[keep[idx].num_wds++] = word;
+    }
+
+  for (i = 0; i < num; i++)
+    {
+      WordData *word = wd[i];
+      int idx = KIND (word);
+      discard[idx].wd[discard[idx].num_wds++] = word;
+    }
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+  SortAndCount_DictData (&discard[0]);
+  SortAndCount_DictData (&discard[1]);
+
+  assert (keep[0].num_wds + discard[0].num_wds == Num[0]);
+  assert (keep[1].num_wds + discard[1].num_wds == Num[1]);
+
+}
+
+
+
+static int 
+BigSaving (void *a, void *b)
+{
+  WordData *aa = *(WordData **) a;
+  WordData *bb = *(WordData **) b;
+  return (aa->saving > bb->saving) ? -1 : (aa->saving < bb->saving);
+}
+
+static int 
+SmallSaving (void *a, void *b)
+{
+  WordData *aa = *(WordData **) a;
+  WordData *bb = *(WordData **) b;
+  return (aa->saving < bb->saving) ? -1 : (aa->saving > bb->saving);
+}
+
+
+static void 
+CalcCharCounts (WordData ** wd, int num,
+		char *char_lens[2], char *len_lens[2],
+		u_long escape[2])
+{
+  long char_freqs[2][256];
+  long len_freqs[2][16];
+  huff_data hd;
+  int i;
+  escape[0] = 0;
+  escape[1] = 0;
+  bzero ((char *) char_freqs, sizeof (char_freqs));
+  bzero ((char *) len_freqs, sizeof (len_freqs));
+  for (i = 0; i < num; i++, wd++)
+    {
+      u_long freq = (*wd)->freq;
+      u_char *buf = (*wd)->word;
+      int len = *buf++;
+      int idx = KIND (*wd);
+      len_freqs[idx][len] += freq;
+      escape[idx] += freq;
+      for (; len; len--, buf++)
+	char_freqs[idx][(u_long) (*buf)] += freq;
+    }
+  Generate_Huffman_Data (256, char_freqs[0], &hd, NULL);
+  char_lens[0] = hd.clens;
+  Generate_Huffman_Data (256, char_freqs[1], &hd, NULL);
+  char_lens[1] = hd.clens;
+
+  Generate_Huffman_Data (16, len_freqs[0], &hd, NULL);
+  len_lens[0] = hd.clens;
+  Generate_Huffman_Data (16, len_freqs[1], &hd, NULL);
+  len_lens[1] = hd.clens;
+}
+
+
+
+
+
+
+
+
+
+void 
+CalcBitCost (WordData ** discard_word, int discard_num,
+	     WordData ** keep_word, int keep_num, double freqs_trans[2],
+	     u_long escape[2], int num_trans)
+{
+  char *char_lens[2];
+  char *len_lens[2];
+  double esc[2];
+  int j;
+  CalcCharCounts (discard_word, discard_num, char_lens, len_lens, escape);
+  esc[0] = -log2 (escape[0] / (freqs_trans[0] + escape[0]));
+  esc[1] = -log2 (escape[1] / (freqs_trans[1] + escape[1]));
+  for (j = 0; j < discard_num; j++, discard_word++)
+    {
+      float cbc, wbc;
+      u_char *buf = (*discard_word)->word;
+      int len = *buf++;
+      u_long freq = (*discard_word)->freq;
+      int idx = KIND (*discard_word);
+
+      cbc = len_lens[idx][len];
+      for (; len; len--, buf++)
+	cbc += char_lens[idx][(u_long) (*buf)];
+
+      (*discard_word)->char_bit_cost = (cbc + esc[idx]) * freq;
+
+      wbc = -log2 (freq / (freqs_trans[idx] + escape[idx])) * freq;
+
+      (*discard_word)->saving = ((*discard_word)->char_bit_cost - wbc) /
+	(sizeof (char *) + (*discard_word)->word[0]);
+
+      (*discard_word)->num_trans = num_trans;
+    }
+  for (j = 0; j < keep_num; j++, keep_word++)
+    {
+      float cbc, wbc;
+      u_char *buf = (*keep_word)->word;
+      int len = *buf++;
+      u_long freq = (*keep_word)->freq;
+      int idx = KIND (*keep_word);
+
+      cbc = len_lens[idx][len];
+      for (; len; len--, buf++)
+	cbc += char_lens[idx][(u_long) (*buf)];
+
+      (*keep_word)->char_bit_cost = (cbc + esc[idx]) * freq;
+
+      wbc = -log2 (freq / (freqs_trans[idx] + escape[idx])) * freq;
+
+      (*keep_word)->saving = ((*keep_word)->char_bit_cost - wbc) /
+	(sizeof (char *) + (*keep_word)->word[0]);
+
+      (*keep_word)->num_trans = num_trans;
+    }
+  Xfree (char_lens[0]);
+  Xfree (char_lens[1]);
+  Xfree (len_lens[0]);
+  Xfree (len_lens[1]);
+}
+
+
+
+static void 
+Method3 (int k)
+{
+  int i, keep_num, discard_num, mem, num_trans, recalc_reqd;
+  int keep_to_discard = 0;
+  int discard_to_keep = 0;
+  int recalcs = 0;
+  double freqs_trans[2], total;
+  u_long escape[2];
+  WordData **keep_heap, **discard_heap;
+
+  freqs_trans[0] = freqs_trans[1] = 0;
+  num_trans = 0;
+
+  discard_num = Num[0] + Num[1];
+  discard_heap = Xmalloc (discard_num * sizeof (WordData *));
+
+  keep_num = 0;
+  keep_heap = Xmalloc (discard_num * sizeof (WordData *));
+
+
+  for (i = 0; i < Num[0]; i++)
+    discard_heap[i] = Words[0] + i;
+  for (i = 0; i < Num[1]; i++)
+    discard_heap[i + Num[0]] = Words[1] + i;
+
+  heap_build (discard_heap, sizeof (*discard_heap), discard_num, DecFreqIncWL);
+
+  mem = 0;
+  while (k > mem && discard_num)
+    {
+      WordData *word = discard_heap[0];
+      mem += sizeof (u_char *) + word->word[0];
+      heap_deletehead (discard_heap, sizeof (word), &discard_num, DecFreqIncWL);
+      keep_heap[keep_num++] = word;
+      freqs_trans[KIND (word)] += word->freq;
+      num_trans++;
+    }
+
+  CalcBitCost (discard_heap, discard_num, keep_heap, keep_num,
+	       freqs_trans, escape, num_trans);
+  heap_build (discard_heap, sizeof (*discard_heap), discard_num, BigSaving);
+  heap_build (keep_heap, sizeof (*keep_heap), keep_num, SmallSaving);
+
+  total = 0;
+  recalc_reqd = 0;
+  while (keep_num && discard_num)
+    {
+      if ((keep_num && keep_heap[0]->num_trans < num_trans) ||
+	  (discard_num && discard_heap[0]->num_trans < num_trans))
+	{
+	  if (keep_num && keep_heap[0]->num_trans < num_trans)
+	    {
+	      WordData *word = keep_heap[0];
+	      int idx = KIND (word);
+	      float wbc;
+#ifdef DEBUG1
+	      fprintf (stderr, "KEEP \"%s\" %.2f ->", word2str (word->word),
+		       word->saving);
+#endif
+	      wbc = -log2 (word->freq / (freqs_trans[idx] + escape[idx])) *
+		word->freq;
+	      word->saving = (word->char_bit_cost - wbc) /
+		(sizeof (char *) + word->word[0]);
+#ifdef DEBUG1
+	      fprintf (stderr, " %.2f\n", word->saving);
+#endif
+	      word->num_trans = num_trans;
+	      heap_changedhead (keep_heap, sizeof (word), keep_num, SmallSaving);
+	    }
+
+	  if (discard_num && discard_heap[0]->num_trans < num_trans)
+	    {
+	      WordData *word = discard_heap[0];
+	      int idx = KIND (word);
+	      float wbc;
+#ifdef DEBUG1
+	      fprintf (stderr, "DISCARD \"%s\" %.2f ->", word2str (word->word),
+		       word->saving);
+#endif
+	      wbc = -log2 (word->freq / (freqs_trans[idx] + escape[idx])) *
+		word->freq;
+	      word->saving = (word->char_bit_cost - wbc) /
+		(sizeof (char *) + word->word[0]);
+#ifdef DEBUG1
+	      fprintf (stderr, " %.2f\n", word->saving);
+#endif
+	      word->num_trans = num_trans;
+	      heap_changedhead (discard_heap, sizeof (word),
+				discard_num, BigSaving);
+	    }
+	}
+      else if (keep_heap[0]->saving < discard_heap[0]->saving)
+	{
+	  assert (keep_num && discard_num);
+	  if (keep_num && mem + sizeof (char *) + discard_heap[0]->word[0] > k)
+	    {
+	      /* Transfer the word at the top of the keep heap to the
+	         discard heap. */
+	      WordData *word = keep_heap[0];
+	      int idx = KIND (word);
+	      heap_deletehead (keep_heap, sizeof (word), &keep_num, SmallSaving);
+	      discard_heap[discard_num] = word;
+	      heap_additem (discard_heap, sizeof (word), &discard_num,
+			    BigSaving);
+	      freqs_trans[idx] -= word->freq;
+	      mem -= sizeof (u_char *) + word->word[0];
+	      num_trans++;
+	      total += word->saving;
+	      keep_to_discard++;
+#ifdef DEBUG
+	      fprintf (stderr,
+		       "KEEP -> DISCARD %8d :%8d :%8.0f :%8.0f : \"%s\"\n",
+		       mem, word->freq, word->char_bit_cost,
+		       word->saving, word2str (word->word));
+#endif
+	    }
+	  else
+	    {
+	      /* Transfer the word at the top of the discard heap to the
+	         keep heap. */
+	      WordData *word = discard_heap[0];
+	      int idx = KIND (word);
+	      heap_deletehead (discard_heap, sizeof (word),
+			       &discard_num, BigSaving);
+	      keep_heap[keep_num] = word;
+	      heap_additem (keep_heap, sizeof (word), &keep_num, SmallSaving);
+	      freqs_trans[idx] += word->freq;
+	      mem += sizeof (u_char *) + word->word[0];
+	      num_trans++;
+	      total += word->saving;
+	      discard_to_keep++;
+#ifdef DEBUG
+	      fprintf (stderr,
+		       "DISCARD -> KEEP %8d :%8d :%8.0f :%8.0f : \"%s\"\n",
+		       mem, word->freq, word->char_bit_cost,
+		       word->saving, word2str (word->word));
+#endif
+	    }
+
+	  recalc_reqd = 1;
+
+	}
+      else
+	{
+	  if (recalc_reqd == 0)
+	    break;
+#ifdef DEBUG1
+	  fprintf (stderr, "--------------\n");
+#endif
+	  if (recalcs == MAX_RECALCULATIONS)
+	    break;
+	  CalcBitCost (discard_heap, discard_num, keep_heap, keep_num,
+		       freqs_trans, escape, num_trans);
+	  heap_build (discard_heap, sizeof (*discard_heap),
+		      discard_num, BigSaving);
+	  heap_build (keep_heap, sizeof (keep_heap), keep_num, SmallSaving);
+	  recalc_reqd = 0;
+	  recalcs++;
+	}
+    }
+
+  Alloc_keep_discard ();
+
+  for (i = 0; i < discard_num; i++)
+    {
+      WordData *word = discard_heap[i];
+      int idx = KIND (word);
+      assert (IsWord (word) || IsNonWord (word));
+      discard[idx].wd[discard[idx].num_wds++] = word;
+    }
+  for (i = 0; i < keep_num; i++)
+    {
+      WordData *word = keep_heap[i];
+      int idx = KIND (word);
+      assert (IsWord (word) || IsNonWord (word));
+      keep[idx].wd[keep[idx].num_wds++] = word;
+    }
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+  SortAndCount_DictData (&discard[0]);
+  SortAndCount_DictData (&discard[1]);
+
+  assert (keep[0].num_wds + discard[0].num_wds == Num[0]);
+  assert (keep[1].num_wds + discard[1].num_wds == Num[1]);
+  Message ("Keep -> Discard        : %8d", keep_to_discard);
+  Message ("Discard -> Keep        : %8d", discard_to_keep);
+  Message ("Huffman Recalculations : %8d", recalcs);
+  if (recalcs == MAX_RECALCULATIONS)
+    Message ("WARNING: The number of recalculations == %d", MAX_RECALCULATIONS);
+}
+
+
+
+
+
+
+
+
+
+
+/****************************************************************************
+ *****									*****
+ *****			Dictionary saving code				*****
+ *****									*****
+ ****************************************************************************/
+
+
+
+static void 
+Write_cdh (FILE * f, compression_dict_header * cdh)
+{
+  /* [RPAP - Jan 97: Endian Ordering] */
+  int i;
+  compression_dict_header tmp = *cdh;
+  HTONUL(tmp.dict_type);
+  HTONUL(tmp.novel_method);
+  for (i = 0; i < TEXT_PARAMS; i++)
+    HTONUL(tmp.params[i]);
+  HTONUL(tmp.num_words[0]);
+  HTONUL(tmp.num_words[1]);
+  HTONUL(tmp.num_word_chars[0]);
+  HTONUL(tmp.num_word_chars[1]);
+  HTONUL(tmp.lookback);
+
+  fwrite (&tmp, sizeof (tmp), 1, f);
+}
+
+
+static void 
+Write_words (FILE * f, DictData * dd)
+{
+  int i;
+  u_char *curr, *prev = NULL;
+  for (i = 0; i < dd->num_wds; i++)
+    {
+      int len;
+      curr = dd->wd[i]->word;
+      if (prev)
+	/* look for prefix match with prev string */
+	len = prefixlen (prev, curr);
+      else
+	len = 0;
+      fputc ((len << 4) + (curr[0] - len), f);
+      fwrite (curr + len + 1, sizeof (u_char), curr[0] - len, f);
+      prev = curr;
+    }
+
+}
+
+
+static int 
+Uncompressed_size (DictData * dd)
+{
+  int i, us;
+  for (us = i = 0; i < dd->num_wds; i++)
+    us += dd->wd[i]->word[0];
+  return us;
+}
+
+
+static u_long 
+Write_data (FILE * f, DictData * dd, int lookback)
+{
+  u_long mem_reqd;
+  huff_data *hd;
+  int i; 
+  u_long us = dd->num_wds;
+  long *freqs;
+  u_long huff_words_size[MAX_HUFFCODE_LEN + 1];
+  u_long lencounts[MAX_HUFFCODE_LEN + 1];
+  u_char *lastword[MAX_HUFFCODE_LEN + 1];
+
+  if (!(freqs = Xmalloc ((dd->num_wds) * sizeof (*freqs))))
+    FatalError (1, "Unable to allocate memory for freqs");
+
+  for (i = 0; i < dd->num_wds; i++)
+    {
+      freqs[i] = dd->wd[i]->freq;
+      us += dd->wd[i]->word[0];
+    }
+
+  if (!(hd = Generate_Huffman_Data (dd->num_wds, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  Xfree (freqs), freqs = NULL;
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+  HTONUL(us);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&us, sizeof (us), 1, f);
+  NTOHUL(us);  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+/* Calculate the amount of memory that will be required to store the text for
+   each different huffman code len. Every 1<<lookback words for each different
+   codelen length will not be prefixed by previous strings. */
+
+
+  bzero ((char *) &huff_words_size, sizeof (huff_words_size));
+  bzero ((char *) &lencounts, sizeof (lencounts));
+
+  mem_reqd = 0;
+
+  for (i = 0; i < dd->num_wds; i++)
+    {
+      int codelen = hd->clens[i];
+      u_char *word = dd->wd[i]->word;
+
+      if (!codelen)
+	FatalError (1, "The length of a code for a word was zero");
+
+      huff_words_size[codelen] += word[0] + 1;
+      mem_reqd += word[0] + (lookback != 0);
+#if 0
+      if ((lencounts[codelen] & ((1 << lookback) - 1)) == 0)
+	lastword[codelen] = word;
+      else
+	huff_words_size[codelen] -= prefixlen (lastword[codelen], word);
+#else
+      if ((lencounts[codelen] & ((1 << lookback) - 1)) != 0)
+	{
+	  int save = prefixlen (lastword[codelen], word);
+	  mem_reqd -= save;
+	  huff_words_size[codelen] -= save;
+	}
+      else
+	{
+	  mem_reqd += sizeof (u_char *);
+	}
+      lastword[codelen] = word;
+#endif
+      lencounts[codelen]++;
+    }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+    HTONUL(huff_words_size[i]);
+
+  fwrite (huff_words_size + hd->mincodelen, sizeof (*huff_words_size),
+	  hd->maxcodelen - hd->mincodelen + 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = hd->mincodelen; i < hd->maxcodelen + 1; i++)
+    NTOHUL(huff_words_size[i]);
+
+  Write_words (f, dd);
+
+  Xfree (hd->clens);
+  Xfree (hd);
+
+  return mem_reqd;
+}
+
+
+
+static void 
+Write_charfreqs (FILE * f, DictData * dd, int words,
+		 int zero_freq_permitted)
+{
+  int j;
+  long freqs[256];
+  WordData **wd = dd->wd;
+  huff_data *hd;
+
+  bzero ((char *) freqs, sizeof (freqs));
+
+  for (j = 0; j < dd->num_wds; j++, wd++)
+    {
+      u_char *buf = (*wd)->word;
+      int len = *buf++;
+      for (; len; len--, buf++)
+	freqs[(u_long) (*buf)] += (*wd)->freq;
+    }
+
+  if (!zero_freq_permitted)
+    for (j = 0; j < 256; j++)
+      if (!freqs[j] && PESINAWORD (j) == words)
+	freqs[j] = 1;
+
+  if (!(hd = Generate_Huffman_Data (256, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+  Xfree (hd->clens);
+  Xfree (hd);
+}
+
+
+
+
+static void 
+Write_wordlens (FILE * f, DictData * dd, int zero_freq_permitted)
+{
+  int j;
+  long freqs[16];
+  WordData **wd = dd->wd;
+  huff_data *hd;
+
+  bzero ((char *) freqs, sizeof (freqs));
+
+  for (j = 0; j < dd->num_wds; j++, wd++)
+    freqs[(*wd)->word[0]] += (*wd)->freq;
+
+  if (!zero_freq_permitted)
+    for (j = 0; j < 16; j++)
+      if (!freqs[j])
+	freqs[j] = 1;
+
+  if (!(hd = Generate_Huffman_Data (16, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+
+  Xfree (hd->clens);
+  Xfree (hd);
+}
+
+
+
+static u_long 
+WriteOutWords (char *file_name, u_long type, int lookback)
+{
+  FILE *f;
+  int i;
+  u_long mem_reqd = 0;
+
+  compression_dict_header cdh;
+  f = create_file (file_name, TEXT_DICT_SUFFIX, "w+b",
+		   MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  bzero((char *) &cdh, sizeof(cdh));
+
+  cdh.dict_type = type;
+  cdh.novel_method = (type == MG_SEED_DICTIONARY) ? novel_method :
+    MG_NOVEL_HUFFMAN_CHARS;
+
+  cdh.num_words[1] = keep[1].num_wds;
+  cdh.num_words[0] = keep[0].num_wds;
+  cdh.num_word_chars[1] = Uncompressed_size (&keep[1]);
+  cdh.num_word_chars[0] = Uncompressed_size (&keep[0]);
+  cdh.lookback = lookback;
+
+  Write_cdh (f, &cdh);
+
+  for (i = 0; i < 2; i++)
+    switch (type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  mem_reqd += Write_data (f, &keep[i], lookback);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (keep[i].num_wds)
+	    {
+	      int j;
+	      WordData esc;
+	      esc.freq = 0;
+	      esc.word = (u_char *) "";
+	      keep[i].wd[keep[i].num_wds++] = &esc;
+	      for (j = 0; j < discard[i].num_wds; j++)
+		esc.freq += discard[i].wd[j]->freq;
+	      if (!esc.freq)
+		esc.freq++;
+	      mem_reqd += Write_data (f, &keep[i], lookback);
+	    }
+	  Write_charfreqs (f, &discard[i], i, 1);
+	  Write_wordlens (f, &discard[i], 1);
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (keep[i].num_wds)
+	    {
+	      int j;
+	      WordData esc;
+	      esc.freq = 0;
+	      esc.word = (u_char *) "";
+	      keep[i].wd[keep[i].num_wds++] = &esc;
+	      for (j = 0; j < all[i].num_wds; j++)
+		if (all[i].wd[j]->freq == 1)
+		  esc.freq++;
+	      if (!esc.freq)
+		esc.freq++;
+	      mem_reqd += Write_data (f, &keep[i], lookback);
+	    }
+	  switch (novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      Write_charfreqs (f, &all[i], i, 0);
+	      Write_wordlens (f, &all[i], 0);
+	      break;
+	    case MG_NOVEL_BINARY:
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    case MG_NOVEL_HYBRID_MTF:
+	      break;
+	    default:
+	      FatalError (1, "Bad novel method");
+	    }
+	}
+	break;
+      }
+  fclose (f);
+  return mem_reqd;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_decompress_text.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_decompress_text.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_decompress_text.1	(revision 10506)
@@ -0,0 +1,78 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_decompress_text 1 \*(Dt CITRI
+.SH NAME
+mg_decompress_text \- decompresses the compressed text of a collection
+.SH SYNOPSIS
+.B mg_decompress_text
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_decompress_text
+decompresses the compressed text of a collection, inserts paragraph and
+document markers, writing the output to
+.IR stdout ".  "
+This program was created
+to be used as a type of
+.BR mg_get (1).
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.text
+Compressed documents.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.invf.paragraph
+Paragraph counts for documents.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_passes (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_decompress_text.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_decompress_text.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_decompress_text.c	(revision 10506)
@@ -0,0 +1,167 @@
+#include "sysfuncs.h"
+
+#include "filestats.h"
+#include "netorder.h"
+#include "memlib.h"
+#include "messages.h"
+#include "huffman.h"
+#include "bitio_m_mem.h"
+#include "bitio_m.h"
+#include "bitio_stdio.h"
+#include "huffman_stdio.h"
+
+#include "mg_files.h"
+#include "mg.h"
+#include "backend.h"  /* compressed_dict struct */
+#include "text_get.h"
+#include "words.h"
+
+#define EOD         '\002'
+#define EOP         '\003'
+
+/* These are defined in mgquery, and they need to be here for backend.o */
+/* Messy I know but this was meant to be a quick hack :-) */
+#if defined(PARADOCNUM) || defined(NZDL)
+int *Paragraph = NULL;
+int Documents = 0;
+#endif
+
+int
+main (int argc, char **argv)
+{
+  FILE *text, *text_idx, *para;
+  File *text_comp_dict = NULL, *text_aux_dict = NULL, *text_fast_comp_dict = NULL;
+
+  int ch;
+  unsigned long start, finish, len;
+  u_long total_chars = 0;
+  u_char *c_buffer = 0;
+  int buf_len = -1;
+  u_char *uc_buffer = 0;
+  int ULen;
+  compression_dict *cd = NULL;
+  compressed_text_header cth;
+  u_long doc;
+  int count;
+  char *filename = "";
+  char path[512];
+  opterr = 0;
+  msg_prefix = argv[0];
+
+  while ((ch = getopt (argc, argv, "f:d:h")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	filename = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-h] [-d directory] -f name\n",
+		 argv[0]);
+	exit (1);
+      }
+
+  /* Open files */
+  text = open_file (filename, TEXT_SUFFIX, "rb", MAGIC_TEXT, MG_ABORT);
+  fread ((char *)&cth, sizeof (cth), 1, text);
+
+  text_idx = open_file (filename, TEXT_IDX_SUFFIX, "rb", MAGIC_TEXI, MG_ABORT);
+  fread ((char *)&cth, sizeof (cth), 1, text_idx);
+
+  NTOHUL(cth.num_of_docs);
+  NTOHD(cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(cth.num_of_words);
+  NTOHUL(cth.length_of_longest_doc);
+  NTOHD(cth.ratio);
+
+  para = open_file (filename, INVF_PARAGRAPH_SUFFIX, "rb", MAGIC_PARAGRAPH, MG_CONTINUE);
+
+  sprintf (path, FILE_NAME_FORMAT, get_basepath(), filename, TEXT_DICT_FAST_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(text_fast_comp_dict = Fopen (path, "rb", MAGIC_FAST_DICT)))
+    {
+      sprintf (path, FILE_NAME_FORMAT, get_basepath(), filename, TEXT_DICT_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+      text_comp_dict = Fopen (path, "rb", MAGIC_DICT);
+      if (!text_comp_dict)
+	FatalError (1, "Could not open compressed dictionary");
+      sprintf (path, FILE_NAME_FORMAT, get_basepath(), filename, TEXT_DICT_AUX_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+      text_aux_dict = Fopen (path, "rb", MAGIC_AUX_DICT);
+    }
+
+  cd = LoadCompDict (text_comp_dict, text_aux_dict, text_fast_comp_dict);
+
+
+  /* Uncompress text */
+
+  doc = 1;
+  fread ((char *)&start, sizeof (start), 1, text_idx);
+  if (para)
+    fread ((char *)&count, sizeof (count), 1, para);
+  else
+    count = 1;
+
+  for (;;)
+    {
+      fread ((char *) &finish, sizeof (finish), 1, text_idx);
+      len = finish - start;
+      
+      if ((int) len > buf_len)
+	{
+	  if (c_buffer)
+	    {
+	      Xfree (c_buffer);
+	      Xfree (uc_buffer);
+	    }
+	  if (!(c_buffer = Xmalloc (len)))
+	    FatalError (1, "Cannot allocate memory for compressed buffer");
+	  if (!(uc_buffer = Xmalloc ((int) (cth.ratio * 1.01 * len) + 100)))
+	    FatalError (1, "Cannot allocate memory for uncompressed buffer");
+	  buf_len = len;
+	}
+
+      fread (c_buffer, 1, len, text);
+      DecodeText (cd, c_buffer, len, uc_buffer, &ULen);
+      fwrite (uc_buffer, ULen, sizeof (u_char), stdout);
+      fflush (stdout);
+
+      total_chars += ULen;
+
+      if (++doc > cth.num_of_docs)
+	{
+	  if (para)
+	    fputc (EOP, stdout);
+	  fputc (EOD, stdout);
+	  fflush (stdout);
+	  break;
+	}
+
+      if (!--count)
+	{
+	  /* End of document */
+	  fputc (EOD, stdout);
+	  if (para)
+	    fread ((char *)&count, sizeof (count), 1, para);
+	  else
+	    count = 1;
+	}
+      else
+	fputc (EOP, stdout);
+      fflush (stdout);
+      start = finish;
+    }
+
+  /* Close files */
+
+  fclose (text);
+  fclose (text_idx);
+  if (para)
+    fclose (para);
+
+#if 0
+  printf ("\n#Total chars output = %lu\n", total_chars);
+#endif
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_errors.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_errors.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_errors.c	(revision 10506)
@@ -0,0 +1,73 @@
+/**************************************************************************
+ *
+ * mg_errors.c -- Error related stuff for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+#include "mg_errors.h"
+
+
+
+int mg_errno = MG_NOERROR;
+
+char *mg_errorstrs[] =
+{
+  "No error",
+  "Out of memory",
+  "File \"%s\" not found",
+  "Bad magic number in \"%s\"",
+  "Error reading \"%s\"",
+  "MG_BUFTOOSMALL",
+  "Files required for level 2 and 3 inversion are missing"};
+
+
+/* [RJM 07/98: Memory Leak] -- rest of file */
+
+static char null_data[] = "";
+char *mg_error_data = null_data;
+
+
+void MgErrorData (char *s)
+{
+  /* free the current error string, unless it is the null string */
+  if ((mg_error_data != NULL) && (mg_error_data != null_data)) {
+    Xfree (mg_error_data);
+    mg_error_data = null_data;
+  }
+
+  /* make a copy of the string */
+  mg_error_data = Xstrdup (s);
+
+  /* if the alloc failed set the error to the null string */
+  if (!mg_error_data) mg_error_data = null_data;
+}
+
+
+void MgErrorDeinit (void)
+{
+  /* free the current error string, unless it is the null string */
+  if ((mg_error_data != NULL) && (mg_error_data != null_data)) {
+    Xfree (mg_error_data);
+    mg_error_data = null_data;
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_errors.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_errors.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_errors.h	(revision 10506)
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * mg_errors.h -- Error related stuff for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+extern int mg_errno;
+extern char *mg_error_data;
+extern char *mg_errorstrs[];
+
+
+#define MG_NOERROR 0
+#define MG_NOMEM 1
+#define MG_NOFILE 2
+#define MG_BADMAGIC 3
+#define MG_READERR 4
+#define MG_BUFTOOSMALL 5
+#define MG_INVERSION 6
+
+void MgErrorData (char *s);
+void MgErrorDeinit (void);
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_fast_comp_dict.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_fast_comp_dict.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_fast_comp_dict.1	(revision 10506)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_fast_comp_dict 1 \*(Dt CITRI
+.SH NAME
+mg_fast_comp_dict \- build a fast loading compression dictionary
+.SH SYNOPSIS
+.B mg_fast_comp_dict
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_fast_comp_dict
+builds a fast-loading compression dictionary from the standard
+compression dictionary.  The new dictionary has the property that
+.BR mgquery (1)
+can load it in very quickly, making the startup time for
+.BR mgquery (1)
+much shorter.  The new dictionary is larger on disk than the original,
+but they are no different when it comes to memory usage.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.dict
+Compression dictionary.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_fast_comp_dict.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_fast_comp_dict.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_fast_comp_dict.c	(revision 10506)
@@ -0,0 +1,798 @@
+/**************************************************************************
+ *
+ * mg_fast_comp_dict.c -- Program to generate a fast compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:06  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:44  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:34:57  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:55  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:47  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "filestats.h"
+#include "huffman.h"
+#include "timing.h"
+#include "messages.h"
+#include "memlib.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "local_strings.h"
+#include "mg.h"
+#include "text.h"
+#include "invf.h"
+#include "lists.h"
+#include "backend.h"
+#include "mg_files.h"
+#include "locallib.h"
+#include "words.h"
+
+
+
+#define ALIGN_SIZE(p,t) (((p) + (sizeof(t)-1)) & (~(sizeof(t)-1)))
+
+#define WORDNO(p, base) ((((char*)(p))-((char*)(base)))/sizeof(u_char*))
+#define FIXUP(p) (fixup[WORDNO(p,buffer)/8] |= (1<<(WORDNO(p, buffer) & 7)))
+
+#define IS_FIXUP(p) ((fixup[WORDNO(p,buffer)/8] & (1<<(WORDNO(p, buffer) & 7))) != 0)
+
+#define FIXUP_VALS(vals) do {						\
+	int i;								\
+	for (i=0; i < MAX_HUFFCODE_LEN+1; i++)				\
+	  FIXUP(&vals[i]);						\
+      } while(0)
+
+
+
+static u_long mem_for_comp_dict (char *filename);
+static void load_comp_dict (char *filename);
+static void save_fast_dict (char *filename);
+static void unfixup_buffer (void);
+
+
+static void *buffer;
+static void *cur;
+static u_char *fixup;
+static u_long mem, fixup_mem;
+
+int main (int argc, char **argv)
+{
+  ProgTime StartTime;
+  int ch;
+  char *filename = "";
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "f:d:h")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	filename = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file] [-d data directory] [-h]\n",
+		 argv[0]);
+	exit (1);
+      }
+  GetTime (&StartTime);
+
+  mem = mem_for_comp_dict (filename);
+
+  fixup_mem = (ALIGN_SIZE (mem, u_char *) / sizeof (u_char *) + 7) / 8;
+
+  cur = buffer = Xmalloc (mem);
+  bzero (buffer, mem);
+  fixup = Xmalloc (fixup_mem);
+  bzero (fixup, fixup_mem);
+
+  Message ("Estimated memory for fast_dict %u", mem);
+  Message ("Estimated memory for fixups %u", fixup_mem);
+
+  load_comp_dict (filename);
+
+  Message ("Actual memory for fast_dict %u", (char *) cur - (char *) buffer);
+
+  if ((u_long) cur > (u_long) buffer + mem)
+    FatalError (1, "The buffer was not big enough for the dictionary");
+
+  {
+    /* [RPAP - Jan 97: Endian Ordering] */
+    compression_dict *cd = (compression_dict *) buffer;
+    int i, which;
+
+    /* cfh */
+    for (which = 0; which <= 1; which++)
+      {
+	int j;
+	
+	HTONSI(cd->cfh[which]->hd.num_codes);
+	HTONSI(cd->cfh[which]->hd.mincodelen);
+	HTONSI(cd->cfh[which]->hd.maxcodelen);
+	for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	  {
+	    HTONSI(cd->cfh[which]->hd.lencount[j]);
+	    HTONUL(cd->cfh[which]->hd.min_code[j]);
+	  }
+	HTONUL(cd->cfh[which]->uncompressed_size);
+	for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	  HTONUL(cd->cfh[which]->huff_words_size[j]);
+      }
+    HTONUL(cd->MemForCompDict);
+    /* ad */
+    if (cd->cdh.novel_method == MG_NOVEL_BINARY ||
+	cd->cdh.novel_method == MG_NOVEL_DELTA ||
+	cd->cdh.novel_method == MG_NOVEL_HYBRID ||
+	cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+      for (which = 0; which <= 1; which++)
+	{
+	  int j;
+	  
+	  HTONUL(cd->ad->afh[which].num_frags);
+	  HTONUL(cd->ad->afh[which].mem_for_frags);
+	  for (j = 0; j < 33; j++)
+	    {
+	      HTONSI(cd->ad->blk_start[which][j]);
+	      HTONSI(cd->ad->blk_end[which][j]);
+	    }
+	}
+    /* cdh */
+    HTONUL(cd->cdh.dict_type);
+    HTONUL(cd->cdh.novel_method);
+    for (i = 0; i < TEXT_PARAMS; i++)
+      HTONUL(cd->cdh.params[which]);
+    HTONUL(cd->cdh.num_words[0]);
+    HTONUL(cd->cdh.num_words[1]);
+    HTONUL(cd->cdh.num_word_chars[0]);
+    HTONUL(cd->cdh.num_word_chars[1]);
+    HTONUL(cd->cdh.lookback);
+    HTONSI(cd->fast_loaded);
+  }
+
+  unfixup_buffer ();
+
+  save_fast_dict (filename);
+
+  Message ("%s", ElapsedTime (&StartTime, NULL));
+  return 0;
+}
+
+
+
+static void 
+unfixup_buffer ()
+{
+  u_long *p;
+  for (p = buffer; (u_long) p < (u_long) cur; p++)
+    {
+      if (IS_FIXUP (p))
+	*p = *p - (u_long) buffer;
+    }
+}
+
+
+
+
+static u_long 
+mem_for_aux_dict (compression_dict_header * cdh, char *filename)
+{
+  int i;
+  u_long mem = sizeof (auxiliary_dict);
+  FILE *aux;
+
+  aux = open_file (filename, TEXT_DICT_AUX_SUFFIX, "rb",
+		   MAGIC_AUX_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  for (i = 0; i <= 1; i++)
+    {
+      aux_frags_header afh;
+      fread (&afh, sizeof (afh), 1, aux);
+      NTOHUL(afh.num_frags);  /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(afh.mem_for_frags);  /* [RPAP - Jan 97: Endian Ordering] */
+      mem += afh.num_frags * sizeof (u_char *);
+      mem = ALIGN_SIZE (mem + afh.mem_for_frags, u_char *);
+      fseek (aux, afh.mem_for_frags, SEEK_CUR);
+    }
+  fclose (aux);
+
+  return mem;
+}
+
+
+
+static u_long 
+mem_for_words (FILE * dict, compression_dict_header * cdh,
+	       comp_frags_header * cfh)
+{
+  u_long mem = 0;
+  u_long i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+
+  lookback = cdh->lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; i++)
+    {
+      ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+      mem_reqd += cfh->huff_words_size[i];
+    }
+
+  mem += ptrs_reqd * sizeof (u_char *);
+  mem += (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **);
+  mem += mem_reqd;
+
+  for (i = 0; i < cfh->hd.num_codes; i++)
+    {
+      register int val;
+      for (val = getc (dict) & 0xf; val; val--)
+	getc (dict);
+    }
+  return ALIGN_SIZE (mem, u_char *);
+}
+
+
+
+
+static u_long 
+mem_for_comp_dict (char *filename)
+{
+  u_long mem = sizeof (compression_dict);
+  compression_dict_header cdh;
+  comp_frags_header cfh;
+  FILE *dict;
+  int which;
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  dict = open_file (filename, TEXT_DICT_SUFFIX, "rb",
+		    MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread (&cdh, sizeof (cdh), 1, dict);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cdh.dict_type);
+  NTOHUL(cdh.novel_method);
+  for (i = 0; i < TEXT_PARAMS; i++)
+    NTOHUL(cdh.params[i]);
+  NTOHUL(cdh.num_words[0]);
+  NTOHUL(cdh.num_words[1]);
+  NTOHUL(cdh.num_word_chars[0]);
+  NTOHUL(cdh.num_word_chars[1]);
+  NTOHUL(cdh.lookback);
+
+  for (which = 0; which < 2; which++)
+    switch (cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  mem += sizeof (comp_frags_header);
+	  Read_cfh (dict, &cfh, NULL, NULL);
+
+	  /* Don't need to count the space for the clens of the huffman data */
+
+	  mem += mem_for_words (dict, &cdh, &cfh);
+	  if (cfh.hd.clens)
+	    Xfree (cfh.hd.clens);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  huff_data hd;
+	  if (cdh.num_words[which])
+	    {
+	      mem += sizeof (comp_frags_header);
+	      Read_cfh (dict, &cfh, NULL, NULL);
+
+	      /* Don't need to count the space for the clens of the
+	         huffman data */
+
+	      mem += mem_for_words (dict, &cdh, &cfh);
+	      if (cfh.hd.clens)
+		Xfree (cfh.hd.clens);
+
+	    }
+
+	  mem += sizeof (hd);
+	  Read_Huffman_Data (dict, &hd, NULL, NULL);
+	  if (hd.clens)
+	    Xfree (hd.clens);
+	  mem += hd.num_codes * sizeof (unsigned long);
+	  mem += (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+	  mem += sizeof (hd);
+	  Read_Huffman_Data (dict, &hd, NULL, NULL);
+	  if (hd.clens)
+	    Xfree (hd.clens);
+	  mem += hd.num_codes * sizeof (unsigned long);
+	  mem += (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  huff_data hd;
+	  if (cdh.num_words[which])
+	    {
+	      mem += sizeof (comp_frags_header);
+	      Read_cfh (dict, &cfh, NULL, NULL);
+
+	      /* Don't need to count the space for the clens of the
+	         huffman data */
+
+	      mem += mem_for_words (dict, &cdh, &cfh);
+	      if (cfh.hd.clens)
+		Xfree (cfh.hd.clens);
+
+	    }
+	  switch (cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      mem += sizeof (hd);
+	      Read_Huffman_Data (dict, &hd, NULL, NULL);
+	      if (hd.clens)
+		Xfree (hd.clens);
+	      mem += hd.num_codes * sizeof (unsigned long);
+	      mem += (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+	      mem += sizeof (hd);
+	      Read_Huffman_Data (dict, &hd, NULL, NULL);
+	      if (hd.clens)
+		Xfree (hd.clens);
+	      mem += hd.num_codes * sizeof (unsigned long);
+	      mem += (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+	      break;
+	    case MG_NOVEL_BINARY:
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    case MG_NOVEL_HYBRID_MTF:
+	      break;
+	    }
+	  break;
+	}
+      }
+  fclose (dict);
+
+  if (cdh.novel_method == MG_NOVEL_BINARY ||
+      cdh.novel_method == MG_NOVEL_DELTA ||
+      cdh.novel_method == MG_NOVEL_HYBRID ||
+      cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    mem += mem_for_aux_dict (&cdh, filename);
+
+  return ALIGN_SIZE (mem, u_char *);
+}
+
+
+
+void *
+getmem (u_long size, int align)
+{
+  void *res;
+  cur = (void *) (((u_long) cur + (align - 1)) & (~(align - 1)));
+  res = cur;
+  cur = (char *) cur + size;
+  if ((long) cur > (long) buffer + mem)
+    FatalError (1, "The buffer was not big enough for the dictionary");
+  return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+static auxiliary_dict *
+LoadAuxDict (compression_dict_header * cdh,
+	     char *filename)
+{
+  auxiliary_dict *ad;
+  int i;
+  FILE *aux;
+
+  aux = open_file (filename, TEXT_DICT_AUX_SUFFIX, "rb",
+		   MAGIC_AUX_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  ad = getmem (sizeof (auxiliary_dict), sizeof (u_char *));
+
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+      u_char *pos;
+
+      fread (&ad->afh[i], sizeof (aux_frags_header), 1, aux);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(ad->afh[i].num_frags);
+      NTOHUL(ad->afh[i].mem_for_frags);
+
+      ad->word_data[i] = getmem (ad->afh[i].mem_for_frags, 1);
+      FIXUP (&ad->word_data[i]);
+
+      ad->words[i] = getmem (ad->afh[i].num_frags * sizeof (u_char *),
+			     sizeof (u_char *));
+      FIXUP (&ad->words[i]);
+
+      fread (ad->word_data[i], ad->afh[i].mem_for_frags, sizeof (u_char), aux);
+
+      pos = ad->word_data[i];
+      for (j = 0; j < ad->afh[i].num_frags; j++)
+	{
+	  ad->words[i][j] = pos;
+	  FIXUP (&ad->words[i][j]);
+	  pos += *pos + 1;
+	}
+      if (cdh->novel_method == MG_NOVEL_HYBRID ||
+	  cdh->novel_method == MG_NOVEL_HYBRID_MTF)
+	{
+	  int num;
+	  num = 1;
+	  ad->blk_start[i][0] = 0;
+	  ad->blk_end[i][0] = cdh->num_words[i] - 1;
+	  while (num < 33)
+	    {
+	      ad->blk_start[i][num] = ad->blk_end[i][num - 1] + 1;
+	      ad->blk_end[i][num] = ad->blk_start[i][num] +
+		(ad->blk_end[i][num - 1] - ad->blk_start[i][num - 1]) * 2;
+	      num++;
+	    }
+	}
+    }
+  fclose (aux);
+  return (ad);
+}
+
+
+
+
+
+static u_char ***
+ReadInWords (FILE * dict, compression_dict * cd,
+	     comp_frags_header * cfh, u_char ** escape)
+{
+  int i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+  int num_set[MAX_HUFFCODE_LEN + 1];
+  u_char *next_word[MAX_HUFFCODE_LEN + 1];
+  u_char **vals;
+  u_char ***values;
+  u_char word[MAXWORDLEN + 1];
+  u_char last_word[MAX_HUFFCODE_LEN + 1][MAXWORDLEN + 1];
+
+  lookback = cd->cdh.lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; i++)
+    {
+      ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+      mem_reqd += cfh->huff_words_size[i];
+    }
+
+  vals = getmem (ptrs_reqd * sizeof (*vals), sizeof (u_char *));
+
+  values = getmem ((MAX_HUFFCODE_LEN + 1) * sizeof (u_char **), sizeof (u_char **));
+
+  next_word[0] = getmem (mem_reqd, sizeof (char));
+
+  cd->MemForCompDict += ptrs_reqd * sizeof (*vals) +
+    (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **) +
+    mem_reqd;
+
+  values[0] = vals;
+  FIXUP (&values[0]);
+  values[0][0] = next_word[0];
+  FIXUP (&values[0][0]);
+  for (i = 1; i <= cfh->hd.maxcodelen; i++)
+    {
+      int next_start = (values[i - 1] - vals) +
+      ((cfh->hd.lencount[i - 1] + ((1 << lookback) - 1)) >> lookback);
+      values[i] = &vals[next_start];
+      FIXUP (&values[i]);
+      next_word[i] = next_word[i - 1] + cfh->huff_words_size[i - 1];
+      values[i][0] = next_word[i];
+      FIXUP (&values[i][0]);
+    }
+
+  bzero ((char *) num_set, sizeof (num_set));
+
+  for (i = 0; i < cfh->hd.num_codes; i++)
+    {
+      register int val, copy;
+      register int len = cfh->hd.clens[i];
+      val = getc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      fread (word + copy + 1, sizeof (u_char), val, dict);
+      *word = val + copy;
+
+      if ((num_set[len] & ((1 << lookback) - 1)) == 0)
+	{
+	  values[len][num_set[len] >> lookback] = next_word[len];
+	  FIXUP (&values[len][num_set[len] >> lookback]);
+	  memcpy (next_word[len], word, *word + 1);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    {
+	      *escape = next_word[len];
+	      FIXUP (escape);
+	    }
+	  next_word[len] += *word + 1;
+	}
+      else
+	{
+	  copy = prefixlen (last_word[len], word);
+	  memcpy (next_word[len] + 1, word + copy + 1, *word - copy);
+	  *next_word[len] = (copy << 4) + (*word - copy);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    {
+	      *escape = next_word[len];
+	      FIXUP (escape);
+	    }
+	  next_word[len] += (*word - copy) + 1;
+	}
+      memcpy (last_word[len], word, *word + 1);
+      num_set[len]++;
+    }
+  if (cfh->hd.clens)
+    Xfree (cfh->hd.clens);
+  cfh->hd.clens = NULL;
+  return values;
+}
+
+
+static unsigned long **
+Generate_Fast_Huffman_Vals (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *fcode[MAX_HUFFCODE_LEN + 1];
+  unsigned long **values;
+  unsigned long *vals;
+
+  if (!data)
+    return (NULL);
+  vals = getmem (data->num_codes * sizeof (*vals), sizeof (long *));
+  values = getmem ((MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *),
+		   sizeof (long *));
+
+  bzero ((char *) values, (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *));
+
+  if (mem)
+    *mem += data->num_codes * sizeof (*vals) +
+      (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+  fcode[0] = values[0] = &vals[0];
+  FIXUP (&values[0]);
+  for (i = 1; i <= data->maxcodelen; i++)
+    {
+      fcode[i] = values[i] = &vals[(values[i - 1] - vals) + data->lencount[i - 1]];
+      FIXUP (&values[i]);
+    }
+
+  for (i = 0; i < data->num_codes; i++)
+    if (data->clens[i])
+      *fcode[(int) (data->clens[i])]++ = i;
+  return (values);
+}
+
+
+
+static void 
+load_comp_dict (char *filename)
+{
+  FILE *dict;
+  int which;
+  compression_dict *cd;
+
+  cd = getmem (sizeof (compression_dict), sizeof (u_char *));
+  cd->fast_loaded = 1;
+
+  dict = open_file (filename, TEXT_DICT_SUFFIX, "rb",
+		    MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  Read_cdh (dict, &cd->cdh, NULL, NULL);
+
+  for (which = 0; which < 2; which++)
+    switch (cd->cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  cd->cfh[which] = getmem (sizeof (*cd->cfh[which]), sizeof (u_char *));
+	  cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	  Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL);
+
+	  cd->values[which] = ReadInWords (dict, cd, cd->cfh[which], NULL);
+	  FIXUP (&cd->cfh[which]);
+	  FIXUP (&cd->values[which]);
+	  cd->escape[which] = NULL;
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  huff_data *hd;
+	  u_long **vals;
+	  if (cd->cdh.num_words[which])
+	    {
+	      cd->cfh[which] = getmem (sizeof (*cd->cfh[which]), sizeof (u_char *));
+	      cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	      Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL);
+	      cd->values[which] = ReadInWords (dict, cd, cd->cfh[which],
+					       &cd->escape[which]);
+	      FIXUP (&cd->cfh[which]);
+	      FIXUP (&cd->values[which]);
+	      FIXUP (&cd->escape[which]);
+	    }
+
+	  hd = getmem (sizeof (huff_data), sizeof (char *));
+	  cd->MemForCompDict += sizeof (huff_data);
+	  Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL);
+	  vals = Generate_Fast_Huffman_Vals (hd, &cd->MemForCompDict);
+	  cd->chars_huff[which] = hd;
+	  FIXUP (&cd->chars_huff[which]);
+	  cd->chars_vals[which] = vals;
+	  FIXUP (&cd->chars_vals[which]);
+	  if (hd->clens)
+	    Xfree (hd->clens);
+	  hd->clens = NULL;
+
+	  hd = getmem (sizeof (huff_data), sizeof (char *));
+	  cd->MemForCompDict += sizeof (huff_data);
+	  Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL);
+	  vals = Generate_Fast_Huffman_Vals (hd, &cd->MemForCompDict);
+	  cd->lens_huff[which] = hd;
+	  FIXUP (&cd->lens_huff[which]);
+	  cd->lens_vals[which] = vals;
+	  FIXUP (&cd->lens_vals[which]);
+	  if (hd->clens)
+	    Xfree (hd->clens);
+	  hd->clens = NULL;
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  huff_data *hd;
+	  u_long **vals;
+	  if (cd->cdh.num_words[which])
+	    {
+	      cd->cfh[which] = getmem (sizeof (*cd->cfh[which]), sizeof (u_char *));
+	      cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	      Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL);
+	      cd->values[which] = ReadInWords (dict, cd, cd->cfh[which],
+					       &cd->escape[which]);
+	      FIXUP (&cd->cfh[which]);
+	      FIXUP (&cd->values[which]);
+	      FIXUP (&cd->escape[which]);
+	    }
+	  switch (cd->cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      hd = getmem (sizeof (huff_data), sizeof (char *));
+	      cd->MemForCompDict += sizeof (huff_data);
+	      Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL);
+	      vals = Generate_Fast_Huffman_Vals (hd, &cd->MemForCompDict);
+	      cd->chars_huff[which] = hd;
+	      FIXUP (&cd->chars_huff[which]);
+	      cd->chars_vals[which] = vals;
+	      FIXUP (&cd->chars_vals[which]);
+	      if (hd->clens)
+		Xfree (hd->clens);
+	      hd->clens = NULL;
+
+	      hd = getmem (sizeof (huff_data), sizeof (char *));
+	      cd->MemForCompDict += sizeof (huff_data);
+	      Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL);
+	      vals = Generate_Fast_Huffman_Vals (hd, &cd->MemForCompDict);
+	      cd->lens_huff[which] = hd;
+	      FIXUP (&cd->lens_huff[which]);
+	      cd->lens_vals[which] = vals;
+	      FIXUP (&cd->lens_vals[which]);
+	      if (hd->clens)
+		Xfree (hd->clens);
+	      hd->clens = NULL;
+	      break;
+	    case MG_NOVEL_BINARY:
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    case MG_NOVEL_HYBRID_MTF:
+	      break;
+	    }
+	  break;
+	}
+      }
+  fclose (dict);
+
+
+  if (cd->cdh.novel_method == MG_NOVEL_BINARY ||
+      cd->cdh.novel_method == MG_NOVEL_DELTA ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    {
+      cd->ad = LoadAuxDict (&cd->cdh, filename);
+      FIXUP (&cd->ad);
+    }
+}
+
+
+static void 
+save_fast_dict (char *filename)
+{
+  FILE *fdict;
+
+  fdict = create_file (filename, TEXT_DICT_FAST_SUFFIX, "wb",
+		       MAGIC_FAST_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  {
+    u_long *p;
+    for (p = buffer; (u_long) p < (u_long) cur; p++)
+      {
+	if (IS_FIXUP (p))
+	  HTONUL(*p);
+      }
+  }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(mem);
+  HTONUL(fixup_mem);
+
+  fwrite (&mem, sizeof (mem), 1, fdict);
+  fwrite (&fixup_mem, sizeof (fixup_mem), 1, fdict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(mem);
+  NTOHUL(fixup_mem);
+
+  fwrite (buffer, sizeof (u_char), mem, fdict);
+  fwrite (fixup, sizeof (u_char), fixup_mem, fdict);
+
+  fclose (fdict);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_files.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_files.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_files.c	(revision 10506)
@@ -0,0 +1,261 @@
+/**************************************************************************
+ *
+ * mg_files.c -- Routines for handling files for the auxillary programs
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+
+
+/* This must contain a valid path without a trailing slash */
+static char *basepath = NULL;
+
+
+
+/* This sets the base path for all file operations */
+void 
+set_basepath (const char *bp)
+{
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  basepath = "";
+#else
+  char *s;
+  /* Free the memory for the base path if it has already been allocated */
+  if (basepath)
+    {
+      Xfree (basepath);
+      basepath = NULL;
+    }
+
+  if (!bp || *bp == '\0')
+    bp = ".";
+
+  s = strrchr (bp, '/');
+  if (s && *(s + 1) == '\0')
+    {
+      basepath = Xmalloc (strlen (bp) + 2);
+      if (!basepath)
+	return;
+      strcpy (basepath, bp);
+      strcat (basepath, ".");
+    }
+  else
+    basepath = Xstrdup (bp);
+#endif
+}
+
+
+
+/* return the currently defined basepath */
+char *
+get_basepath (void)
+{
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  return basepath;
+}
+
+
+
+/* This generates the name of a file. It places the name in the buffer
+   specified or if that is NULL it uses a static buffer. */
+char *
+make_name (const char *name, const char *suffix, char *buffer)
+{
+  static char path[512];
+  if (!buffer)
+    buffer = path;
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (buffer, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return buffer;
+}
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+open_named_file (const char *name, const char *mode,
+		 u_long magic_num, int err_mode)
+{
+  unsigned long magic;
+  FILE *f = NULL;
+  char *err;
+  f = fopen (name, mode);
+
+  if (!f)
+    {
+      err = "Unable to open \"%s\"";
+      goto error;
+    }
+
+  if (magic_num)
+    {
+      if (fread (&magic, sizeof (magic), 1, f) != 1)
+	{
+	  err = "No magic number \"%s\"";
+	  goto error;
+	}
+
+      NTOHUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+
+      if (!IS_MAGIC (magic))
+	{
+	  err = "No MG magic number \"%s\"";
+	  goto error;
+	}
+
+      if (magic != magic_num)
+	{
+	  err = "Wrong MG magic number \"%s\"";
+	  goto error;
+	}
+    }
+  return f;
+
+error:
+  if (f)
+    fclose (f);
+  if (err_mode == MG_ABORT)
+    FatalError (1, err, name);
+  if (err_mode == MG_MESSAGE)
+    Message (err, name);
+  return NULL;
+}
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+open_file (const char *name, const char *suffix, const char *mode,
+	   u_long magic_num, int err_mode)
+{
+  char path[512];
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (path, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return open_named_file (path, mode, magic_num, err_mode);
+}
+
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+create_named_file (const char *name, const char *mode,
+		   u_long magic_num, int err_mode)
+{
+  FILE *f = NULL;
+  char *err;
+  f = fopen (name, mode);
+
+  if (!f)
+    {
+      err = "Unable to open \"%s\"";
+      goto error;
+    }
+
+  if (magic_num)
+    HTONUL(magic_num);  /* [RPAP - Jan 97: Endian Ordering] */
+    if (fwrite (&magic_num, sizeof (magic_num), 1, f) != 1)
+      {
+	err = "Couldn't write magic number \"%s\"";
+	goto error;
+      }
+
+  return f;
+
+error:
+  if (f)
+    fclose (f);
+  if (err_mode == MG_ABORT)
+    FatalError (1, err, name);
+  if (err_mode == MG_MESSAGE)
+    Message (err, name);
+  return NULL;
+}
+
+
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+create_file (const char *name, const char *suffix, const char *mode,
+	     u_long magic_num, int err_mode)
+{
+  char path[512];
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (path, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return create_named_file (path, mode, magic_num, err_mode);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_files.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_files.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_files.h	(revision 10506)
@@ -0,0 +1,329 @@
+/**************************************************************************
+ *
+ * mg_files.h -- Routines for handling files for the auxillary programs
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef MG_FILES_H
+#define MG_FILES_H
+
+#include "sysfuncs.h"
+
+/* Magic numbers for the different types of files */
+
+#define GEN_MAGIC(a,b,c,d) ((unsigned long)(((a)<<24) + ((b)<<16) + \
+					    ((c)<<8) + (d)))
+
+#define MAGIC_XXXX		GEN_MAGIC('M','G', 0 , 0)
+#define MAGIC_STATS_DICT	GEN_MAGIC('M','G','S','D')
+#define MAGIC_AUX_DICT		GEN_MAGIC('M','G','A','D')
+#define MAGIC_FAST_DICT		GEN_MAGIC('M','G','F','D')
+#define MAGIC_DICT		GEN_MAGIC('M','G','D', 0 )
+#define MAGIC_STEM_BUILD	GEN_MAGIC('M','G','S', 0 )
+#define MAGIC_HASH		GEN_MAGIC('M','G','H', 0 )
+#define MAGIC_STEM		GEN_MAGIC('M','G','s', 0 )
+#define MAGIC_CHUNK		GEN_MAGIC('M','G','C', 0 )
+#define MAGIC_CHUNK_TRANS	GEN_MAGIC('M','G','c', 0 )
+#define MAGIC_TEXT		GEN_MAGIC('M','G','T', 0 )
+#define MAGIC_TEXI		GEN_MAGIC('M','G','t', 0 )
+#define MAGIC_TEXI_WGT		GEN_MAGIC('M','G','t','W')
+#define MAGIC_INVF		GEN_MAGIC('M','G','I', 0 )
+#define MAGIC_INVI		GEN_MAGIC('M','G','i', 0 )
+#define MAGIC_WGHT		GEN_MAGIC('M','G','W', 0 )
+#define MAGIC_WGHT_APPROX	GEN_MAGIC('M','G','w', 0 )
+#define MAGIC_PARAGRAPH		GEN_MAGIC('M','G','P', 0 )
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAGIC_STEM_1            GEN_MAGIC('M','G','s','1')
+#define MAGIC_STEM_2            GEN_MAGIC('M','G','s','2')
+#define MAGIC_STEM_3            GEN_MAGIC('M','G','s','3')
+
+#define IS_MAGIC(a) ((((u_long)(a)) & 0xffff0000) == MAGIC_XXXX)
+
+
+/* err_mode values for open_file and create_file */
+#define MG_ABORT 0
+#define MG_MESSAGE 1
+#define MG_CONTINUE 2
+
+
+
+
+
+/* File suffixes */
+
+
+/* The compression dictionary built by txt.pass1 */
+#ifdef SHORT_SUFFIX
+# define TEXT_STATS_DICT_SUFFIX	 ".tsd"
+#else
+# define TEXT_STATS_DICT_SUFFIX	 ".text.stats"
+#endif
+
+/* The compression dictionary built by text.pass1 and comp_dict.process */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_SUFFIX	 ".td"
+#else
+# define TEXT_DICT_SUFFIX	 ".text.dict"
+#endif
+
+/* The compression dictionary built by mg_make_fast_dict */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_FAST_SUFFIX	 ".tdf"
+#else
+# define TEXT_DICT_FAST_SUFFIX	 ".text.dict.fast"
+#endif
+
+/* The auxilary dictionary built by text.pass2 */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_AUX_SUFFIX	 ".tda"
+#else
+# define TEXT_DICT_AUX_SUFFIX	 ".text.dict.aux"
+#endif
+
+/* The compressed text build by text.pass2 */
+#ifdef SHORT_SUFFIX
+# define TEXT_SUFFIX		 ".t"
+#else
+# define TEXT_SUFFIX		 ".text"
+#endif
+
+/* The combined compressed text index and document weight file */
+#ifdef SHORT_SUFFIX
+# define TEXT_IDX_WGT_SUFFIX	 ".tiw"
+#else
+# define TEXT_IDX_WGT_SUFFIX	 ".text.idx.wgt"
+#endif
+
+/* The compressed text index file */
+#ifdef SHORT_SUFFIX
+# define TEXT_IDX_SUFFIX	 	".ti"
+#else
+# define TEXT_IDX_SUFFIX	 	".text.idx"
+#endif
+
+/* The dictionary of stemmed words build by invf.pass1 and ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_SUFFIX         ".id"
+#else
+# define INVF_DICT_SUFFIX         ".invf.dict"
+#endif
+
+/* The dictionary of stemmed words build by stem.process */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_SUFFIX ".idb"
+#else
+# define INVF_DICT_BLOCKED_SUFFIX ".invf.dict.blocked"
+#endif
+
+/* The exact document weights file build by make.weights, invf.pass2,
+   or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define WEIGHTS_SUFFIX           ".w"
+#else
+# define WEIGHTS_SUFFIX           ".weight"
+#endif
+
+/* The approximate weights file built by make.weights */
+#ifdef SHORT_SUFFIX
+# define APPROX_WEIGHTS_SUFFIX    ".wa"
+#else
+# define APPROX_WEIGHTS_SUFFIX    ".weight.approx"
+#endif
+
+/* The inverted file build by invf.pass2 or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define INVF_SUFFIX              ".i"
+#else
+# define INVF_SUFFIX              ".invf"
+#endif
+
+/* The inverted file index build by invf.pass2 or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define INVF_IDX_SUFFIX          ".ii"
+#else
+# define INVF_IDX_SUFFIX          ".invf.idx"
+#endif
+
+/* The inverted file chunk descriptor built by ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_CHUNK_SUFFIX        ".ic"
+#else
+# define INVF_CHUNK_SUFFIX        ".invf.chunk"
+#endif
+
+/* The word index translation file built by ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_CHUNK_TRANS_SUFFIX  ".ict"
+#else
+# define INVF_CHUNK_TRANS_SUFFIX  ".invf.chunk.trans"
+#endif
+
+/* The hashed stemmed dictionary built by make.perf_hash */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_HASH_SUFFIX    ".idh"
+#else
+# define INVF_DICT_HASH_SUFFIX    ".invf.dict.hash"
+#endif
+
+/* The paragraph descriptior file built by invf.pass1 or ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_PARAGRAPH_SUFFIX    ".ip"
+#else
+# define INVF_PARAGRAPH_SUFFIX    ".invf.paragraph"
+#endif
+
+/* The trace file build by mg.builder. */
+#ifdef SHORT_SUFFIX
+# define TRACE_SUFFIX             ".trc"
+#else
+# define TRACE_SUFFIX             ".trace"
+#endif
+
+/* The compression stats file build by mg.builder. */
+#ifdef SHORT_SUFFIX
+# define COMPRESSION_STATS_SUFFIX ".cs"
+#else
+# define COMPRESSION_STATS_SUFFIX ".compression.stats"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The casefolded index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_1_SUFFIX ".ib1"
+#else
+# define INVF_DICT_BLOCKED_1_SUFFIX ".invf.dict.blocked.1"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The stemmed index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_2_SUFFIX ".ib2"
+#else
+# define INVF_DICT_BLOCKED_2_SUFFIX ".invf.dict.blocked.2"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The casefolded and stemmed  index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_3_SUFFIX ".ib3"
+#else
+# define INVF_DICT_BLOCKED_3_SUFFIX ".invf.dict.blocked.3"
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+#define FILE_NAME_FORMAT "%s%s%s"
+#else
+#define FILE_NAME_FORMAT "%s/%s%s"
+#endif
+
+
+/* This sets the base path for all file operations */
+void set_basepath (const char *bp);
+
+
+/* return the currently defined basepath */
+char *get_basepath (void);
+
+
+
+
+/* This generates the name of a file. It places the name in the buffer
+   specified or if that is NULL it uses a static buffer. */
+char *make_name (const char *name, const char *suffix, char *buffer);
+
+
+
+
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *open_named_file (const char *name, const char *mode,
+		       u_long magic_num, int err_mode);
+
+
+
+
+/* This will open the specified file and check its magic number.
+
+   err_mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *open_file (const char *name, const char *suffix, const char *mode,
+		 u_long magic_num, int err_mode);
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *create_named_file (const char *name, const char *mode,
+			 u_long magic_num, int err_mode);
+
+
+
+/* This will create the specified file and set its magic number.
+
+   err_mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *create_file (const char *name, const char *suffix, const char *mode,
+		   u_long magic_num, int err_mode);
+
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_hilite_words.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_hilite_words.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_hilite_words.1	(revision 10506)
@@ -0,0 +1,95 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_hilite_words 1 \*(Dt CITRI
+.SH NAME
+mg_hilite_words \- display text and highlight particular words which it contains
+.SH SYNOPSIS
+.B mg_hilite_words
+.if n .ti +9n
+[
+.B --stem_method [0-3]
+]
+.if n .ti +9n
+[
+.B --stemmer [english|lovin|french|simplefrench]
+]
+.if n .ti +9n
+[
+.B --style [bold|underline|italic|emphasis|strong]
+]
+.if n .ti +9n
+[
+.B --pager [less|more|html|???]
+]
+.if n .ti +9n
+.I list-of-words-to-highlight
+
+.SH DESCRIPTION
+.B mg_hilite_words
+reads text from stdin and outputs it into a pager such as
+less. It's command arguments include a list of stemmed words
+which if extracted from the text will be highlighted on the output
+using a highlighting style.
+
+It has been extended to output the highlighted text using html
+straight to stdout.
+
+.SH OPTIONS
+Options may appear in any order, but the
+.IR list-of-words-to-highlight ,
+must be last.
+.TP
+.B --stem_method [0-3]
+This option allows one to set the stemming method for the extraction of
+the words from the incoming text.
+This should match the way the inverted file index was created.
+The default is 3, which is fold and stem.
+.TP
+.B --stemmer [english|lovin|french|simplefrench]
+This option allows you to select the stemmer to use.  The
+default is the English stemmer.
+.TP
+.B --style [bold|underline|italic|emphasis|strong]
+This option sets the highlighting style.
+.IR Bold 
+and 
+.IR underline
+are utilised by the pager or for html output.
+.IR Italic,
+.IR emphasis,
+and
+.IR strong
+can only be used for html output.
+.TP
+.B --pager [less|more|html|???]
+One can use the standard 
+.IR less
+or
+.IR more
+pages for displaying the highlighted text.
+Or one can generate highlighted html using the paging setting of
+.IR html.
+One can also specify a custom pager of their own choosing (i.e. ???).
+.TP
+.B list-of-words-to-highlight
+Each word is taken as a command line argument.
+Each word should already be stemmed and folded according to
+the stem option.
+.SH USAGE
+This program was written primarily to be called by 
+.IR mgquery(1)
+.
+When the user selects the mode of "hilite" then this program
+is called for displaying the query-result documents instead of
+just the pager.
+.SH "SEE ALSO"
+.na
+.BR mgquery (1).
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_hilite_words.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_hilite_words.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_hilite_words.c	(revision 10506)
@@ -0,0 +1,693 @@
+/**************************************************************************
+ *
+ * mg_hilite_words -- display text and highlight particular words which 
+ *                    it contains
+ * Copyright (C) 1994 Tim Shimmin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "getopt.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "stemmer.h"
+#include "words.h"
+
+
+/*
+ * Description
+ * -----------
+ *   Hilite_words reads text from stdin and outputs it into a pager such as
+ *   less. It's command arguments include a list of stemmed words 
+ *   which if extracted from the text will be highlighted on the output.
+ *
+ * Implementation
+ * --------------
+ *   Extracting of words - using PARSE_STEM_WORD & stemmer
+ *   
+ *   Highlighting of words - for standard pager:
+ *                             using back-space character code
+ *                             e.g. bolded a = "a\ba", underlined a = "_\ba"
+ *                         - for pager==html:
+ *                             use some of the standard html character 
+ *                             formatting tags
+ *
+ *   Storage of words - using hashtable (set) of size equalling a constant
+ *                      times the number of words
+ * 
+ * Usage
+ * -----
+ *   mg_hilite_words --stem_method [0-3] 
+ *                   --style [bold|underline|italic|emphasis|strong]
+ *                   --pager [less|more|html|???]
+ *                   --terminator [terminator-string]
+ *                   list-of-words-to-highlight
+ */
+
+/*
+ * Modifications:
+ *
+ * 21/Apr/95: To handle outputting html tags to stdout
+ *
+ */
+
+/* --- constants --- */
+
+/* highlighting styles */
+#define HILITE_MAX      5	/* the number of styles */
+#define BOLD 		0
+#define UNDERLINE	1
+#define ITALIC     	2
+#define EMPHASIS     	3
+#define STRONG     	4
+
+/* maximum length of line buffer */
+#define MAX_LINE_BUFFER 200
+
+/* set pager to this to get html hilited text to stdout */
+#define HTML_OUT "html"
+
+/* output types */
+#define PAGER 0
+#define HTML  1
+
+/* --- types --- */
+
+typedef u_char *Word;
+
+/* --- globals --- */
+
+/* keep in synch with constants */
+static char *hilite_names[] =
+{"bold", "underline", "italic", "emphasis", "strong"};
+static char *hilite_tags[] =
+{"B", "", "I", "EM", "STRONG"};
+static short hilite_style = BOLD;
+static char *pager = "less";
+static int stemmer_num = 0;	/* Lovin's stemmer */
+static int stem_method = 3;	/* fold & stem */
+static char **word_list;
+static int num_of_words = 0;
+static int output_type = PAGER;
+static char *terminator = NULL;
+
+/* --- prototypes --- */
+
+static Word copy_c_word (char *w);
+static void process_words (char **words, int num_of_words);
+static int get_line (u_char * line, int n, FILE * stream);
+static void process_text (FILE * input_file, FILE * output_file);
+static void copy_word (u_char * w1, u_char * w2);
+static void process_buffer (u_char * s_in, int len, FILE * output_file);
+static void output_word (u_char * s_start, u_char * s_finish, FILE * output_file);
+static void output_hilite_word (u_char * s_start, u_char * s_finish,
+				FILE * output_file);
+static void process_args (int argc, char *argv[]);
+static void print_line (u_char * line, int n, FILE * stream);
+
+
+/******************************** word set ************************************/
+
+#include "hash.h"
+#include "locallib.h"
+
+#define SIZE_FACTOR 2
+
+typedef Word *WordSet;
+static WordSet set_of_words = NULL;
+static int hash_size = 0;
+
+/* prototypes - set routines */
+static void set_create (int num_of_words);
+static void set_add (Word word);
+static int set_member (Word word);
+static void set_print (void);
+
+/* =========================================================================
+ * Function: set_print
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+set_print (void)
+{
+  int i = 0;
+
+  for (i = 0; i < hash_size; i++)
+    {
+      Word word = set_of_words[i];
+
+      if (word)
+	{
+	  int len = *word++;
+
+	  fprintf (stderr, "[%d] = ", i);
+	  while (len--)
+	    fputc (*word++, stderr);
+	  fputc ('\n', stderr);
+	}
+    }
+
+}
+
+
+/* =========================================================================
+ * Function: set_create
+ * Description: 
+ *      Allocate memory for the set
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+set_create (int num_of_words)
+{
+  WordSet set;
+
+  hash_size = prime (num_of_words * SIZE_FACTOR);
+  set = (WordSet) malloc (hash_size * sizeof (Word));
+  if (!set)
+    FatalError (1, "Runout of memory for word hashtable");
+  bzero ((char *) set, hash_size * sizeof (Word));  /* [RPAP - Feb 97: WIN32 Port] */
+
+  set_of_words = set;
+
+}
+
+/* =========================================================================
+ * Function: set_add
+ * Description: 
+ *      Add a string element to the set.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+set_add (Word word)
+{
+  int hash_val;
+  int hash_step;
+
+  HASH (hash_val, hash_step, word, hash_size);
+
+  /* loop around in case of collisions and need to step */
+  while (1)
+    {
+
+      Word entry = set_of_words[hash_val];
+
+      /* if doesn't exist then */
+      if (!entry)
+	{
+	  set_of_words[hash_val] = word;
+	  break;
+	}
+
+      /* if we have a matching word */
+      if (compare (entry, word) == 0)
+	break;
+
+      /* if collides with a different word */
+      hash_val = (hash_val + hash_step) % hash_size;
+
+    }
+}
+
+
+/* =========================================================================
+ * Function: set_member
+ * Description: 
+ *      Tests whether a string is a member of the set
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static int
+set_member (Word word)
+{
+  int hash_val;
+  int hash_step;
+
+  HASH (hash_val, hash_step, word, hash_size);
+
+  /* loop around in case of collisions and need to step */
+  while (1)
+    {
+
+      Word entry = set_of_words[hash_val];
+
+      /* if doesn't exist then */
+      if (!entry)
+	return 0;
+
+      /* if we have a matching word */
+      if (compare (entry, word) == 0)
+	return 1;
+
+      /* if collides with a different word */
+      hash_val = (hash_val + hash_step) % hash_size;
+
+    }
+}
+
+/******************************** end of word set ******************************/
+
+
+
+/* =========================================================================
+ * Function: copy_c_word
+ * Description: 
+ *      Allocate enough memory and copy word over
+ * Input: 
+ *      w = null terminated string (c_word)
+ * Output: 
+ *      word with length in 1st byte
+ * ========================================================================= */
+
+static Word
+copy_c_word (char *w)
+{
+  int len = strlen (w);
+  Word w_copy = (Word) malloc (len + 1);
+  Word w_ptr = NULL;
+  int j = 0;
+
+  if (!w_copy)
+    FatalError (1, "Not enough memory to copy a word");
+
+  w_copy[0] = len;
+  w_ptr = w_copy + 1;
+  for (j = 0; j < len; j++)
+    *w_ptr++ = *w++;
+
+  return w_copy;
+}
+
+/* =========================================================================
+ * Function: process_words
+ * Description: 
+ *      Go through the stemmed words and add to word set
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+process_words (char **words, int num_of_words)
+{
+  int i = 0;
+
+  set_create (num_of_words);
+
+  for (i = 0; i < num_of_words; i++)
+    {
+      Word word = copy_c_word (words[i]);
+      set_add (word);
+    }
+
+}
+
+/* =========================================================================
+ * Function: get_line
+ * Description: 
+ *      Equivalent of fgets for u_char*.
+ *      But returns length of read-in line.
+ *      Expects to see a '\n' before an EOF
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static int
+get_line (u_char * line, int n, FILE * stream)
+{
+  int i = 0;
+  int ch = '\0';
+
+  while (1)
+    {
+      if (i == n)
+	return i;
+
+      ch = fgetc (stream);
+
+      if (ch == EOF)
+	{
+	  if (!feof (stream))
+	    FatalError (1, "Error on reading a line from stdin");
+	  return EOF;
+	}
+
+      if (ch == '\n')
+	return i;
+
+      *line++ = ch;
+      i++;
+    }
+
+}
+
+/* =========================================================================
+ * Function: print_line
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+print_line (u_char * line, int n, FILE * stream)
+{
+
+  while (n--)
+    {
+      fputc (*line++, stream);
+    }
+  fputc ('\n', stream);
+
+}
+
+/* =========================================================================
+ * Function: process_text
+ * Description: 
+ *      Go through the text from input_file and highlight to output_file 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+process_text (FILE * input_file, FILE * output_file)
+{
+  static u_char line_buffer[MAX_LINE_BUFFER];
+
+
+  while (1)
+    {
+      int len = get_line (line_buffer, MAX_LINE_BUFFER, input_file);
+
+      if (len == EOF)
+	break;
+      process_buffer (line_buffer, len, output_file);
+
+    }
+}
+
+/* =========================================================================
+ * Function: copy_word
+ * Description: 
+ *      Copies w2 into w1. Assumes both have storage allocated.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+copy_word (u_char * w1, u_char * w2)
+{
+  int i;
+  int len = w2[0];
+
+  for (i = 0; i <= len; i++)
+    *w1++ = *w2++;
+
+}
+
+/* =========================================================================
+ * Function: process_buffer
+ * Description: 
+ *      Parse & stem words of line buffer
+ *      Based on the usage of PARSEing in other mg files.
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+static void
+process_buffer (u_char * s_in, int len, FILE * output_file)
+{
+  u_char *end = s_in + len - 1;
+  u_char *s_start = NULL;
+
+  if (!inaword (s_in, end))
+    {
+      s_start = s_in;
+      PARSE_NON_STEM_WORD (s_in, end);
+      output_word (s_start, s_in - 1, output_file);
+    }
+
+  while (s_in <= end)
+    {
+      u_char word[MAXSTEMLEN + 1];
+
+      s_start = s_in;
+      PARSE_STEM_WORD (word, s_in, end);
+
+      stemmer (stem_method, stemmer_num, word);
+
+      if (set_member (word))	/* output with highlighting */
+	{
+	  output_hilite_word (s_start, s_start + word[0] - 1, output_file);
+	  s_start += word[0];	/* step over hilited output */
+	}
+      output_word (s_start, s_in - 1, output_file);
+
+      s_start = s_in;
+      PARSE_NON_STEM_WORD (s_in, end);
+      output_word (s_start, s_in - 1, output_file);
+
+    }				/*while */
+
+  fputc ('\n', output_file);
+  fflush (output_file);
+
+}				/*process_buffer */
+
+/* =========================================================================
+ * Function: output_word
+ * Description: 
+ *      Output a word which lies from s_start to s_finish in buffer
+ * Input: 
+ *      s_start = ptr to 1st char
+ *      s_finish = ptr to last char
+ * Output: 
+ * ========================================================================= */
+
+static void
+output_word (u_char * s_start, u_char * s_finish, FILE * output_file)
+{
+  while (s_start <= s_finish)
+    {
+      fputc (*s_start++, output_file);
+    }
+}
+
+
+/* =========================================================================
+ * Function: output_hilite_word
+ * Description: 
+ *      Highlight a word (with length in 1st byte)
+ *      Pager highlighting:
+ *        Highlighting is either by bolding or underlining using
+ *        the method used by UNIX utilities More(1) and Less(1)
+ *      HTML highlighting:
+ *        use the appropriate start and end tags around the word
+ * ========================================================================= */
+
+static void
+output_hilite_word (u_char * s_start, u_char * s_finish, FILE * output_file)
+{
+
+  if (output_type == HTML)
+    {
+      char *hilite_tag = hilite_tags[hilite_style];
+
+      /* print start tag */
+      fprintf (output_file, "<%s>", hilite_tag);
+
+      output_word (s_start, s_finish, output_file);
+
+      /* print end tag */
+      fprintf (output_file, "</%s>", hilite_tag);
+    }
+
+  else
+    /* PAGER */
+    {
+      /* use backspaces around each letter */
+      while (s_start <= s_finish)
+	{
+	  switch (hilite_style)
+	    {
+	    case BOLD:
+	      fputc (*s_start, output_file);
+	      fputc ('\b', output_file);
+	      fputc (*s_start, output_file);
+	      break;
+	    case UNDERLINE:
+	      fputc ('_', output_file);
+	      fputc ('\b', output_file);
+	      fputc (*s_start, output_file);
+	      break;
+	    default:
+	      fputc (*s_start, output_file);
+	    }
+	  s_start++;
+	}			/*while */
+    }
+}
+
+/* =========================================================================
+ * Function: process_args
+ * Description: 
+ *      sets the global variables:
+ *              hilite_style, pager, num_of_words, word_list
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+struct option long_opts[] =
+{
+  {"style", required_argument, 0, 's'},
+  {"terminator", required_argument, 0, 't'},
+  {"pager", required_argument, 0, 'p'},
+  {"stem_method", required_argument, 0, 'm'},
+  {"stemmer", required_argument, 0, 'a'},
+  {0, 0, 0, 0}
+};
+
+static void
+process_args (int argc, char *argv[])
+{
+  int ch;
+
+
+  opterr = 0;
+  while ((ch = getopt_long (argc, argv, "s:p:t:m:a:", long_opts, (int *) 0)) != -1)
+    {
+      switch (ch)
+	{
+	case 's':
+	  {
+	    int i;
+	    for (i = 0; i < HILITE_MAX; i++)
+	      if (strcmp (optarg, hilite_names[i]) == 0)
+		break;
+
+	    if (i < HILITE_MAX)
+	      hilite_style = i;
+	  }
+	  break;
+	case 'a':
+	  stemmer_num = stemmernumber (optarg);
+	  break;
+	case 't':
+	  terminator = optarg;
+	  break;
+	case 'm':
+	  stem_method = atoi (optarg);
+	  break;
+	case 'p':
+	  pager = optarg;
+	  break;
+	default:
+	  FatalError (1, "Usage: \n"
+		      "mg_hilite_words --stem_method [0-3]\n"
+	  "                --stemmer [english|lovin|french|simplefrench]\n"
+	  "                --style [bold|underline|italic|emphasis|strong]\n"
+		      "                --pager [less|more|html|???]\n");
+	}
+    }
+
+  num_of_words = argc - optind;
+
+  word_list = &argv[optind];
+
+  /* fix up output type */
+  if (strcmp (pager, HTML_OUT) == 0)
+    output_type = HTML;
+  else
+    output_type = PAGER;
+
+}
+
+/* =========================================================================
+ * Function: main
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+main (int argc, char *argv[])
+{
+  FILE *output = NULL;
+
+  process_args (argc, argv);
+
+  /* set output file */
+  if (output_type == PAGER)
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+    output = _popen (pager, "w");
+#else
+    output = popen (pager, "w");
+#endif
+  else
+    output = stdout;
+
+  if (!output)
+    FatalError (1, "Unable to run \"%s\"\n", pager);
+
+  if (num_of_words < 1)
+    {
+      int ch;
+
+      /* just echo the input */
+      /* better not to call this program at all ;-) */
+      while ((ch = fgetc (stdin)) != EOF)
+	{
+	  fputc (ch, output);
+	}
+    }
+  else
+    {
+      /* set up hash table for words */
+      process_words (word_list, num_of_words);
+
+
+      /* Go thru lines of text from stdin and 
+       * output words with hilite info if
+       * words parse into existence in the hash table 
+       */
+      process_text (stdin, output);
+    }
+
+  if (terminator)
+    fprintf (output, "%s\n", terminator);
+
+  if (output != stdout)
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+    _pclose (output);
+#else
+    pclose (output);
+#endif
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dict.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dict.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dict.1	(revision 10506)
@@ -0,0 +1,104 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_dict 1 \*(Dt CITRI
+.SH NAME
+mg_invf_dict \- build an `on-disk' stemmed dictionary
+.SH SYNOPSIS
+.B mg_invf_dict
+[
+.B \-h
+]
+[
+.B \-F
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_invf_dict
+builds an `on-disk' stemmed dictionary from the
+compressed stemmed dictionary that the
+.BR mgquery (1)
+program can access.  Each entry in the dictionary contains the disk
+pointer to the associated inverted file entry, and various other pieces
+of information about the stemmed word.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " num"
+The dictionary is stored in blocks on disk; this option is used to set
+the block size.  The default is 4-KB blocks.
+.TP
+.B \-F
+This option causes the disk blocks to be aligned on the appropriate
+boundaries.  For example, if 4-KB blocks are used, they will be aligned
+in the file on 4-KB boundaries.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dict.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dict.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dict.c	(revision 10506)
@@ -0,0 +1,344 @@
+/**************************************************************************
+ *
+ * mg_invf_dict.c -- Program to build the blocked stemmed dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "locallib.h"
+#include "words.h"
+#include "mg.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:08  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:45  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:03  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/29  00:32:00  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:56:56  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:49  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+int block_size = 1024 * 4;
+
+int force = 0;
+
+static void process_files (char *filename);
+
+int main (int argc, char **argv)
+{
+  char *file_name = "";
+  int ch;
+  msg_prefix = argv[0];
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "f:d:b:Fh")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'b':
+	block_size = atoi (optarg);
+	break;
+      case 'F':
+	force = 1;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file]"
+		 "[-d data directory] [-b num] [-F] [-h]\n", argv[0]);
+	exit (1);
+      }
+
+  process_files (file_name);
+  return 0;
+}
+
+
+
+
+static void 
+process_files (char *filename)
+{
+  FILE *id, *idb, *tmp, *ii;
+  unsigned long i, pos, num, First_word, invf_ptr, invf_len;
+  unsigned long last_ptr = 0;
+  char *FName;
+  struct invf_dict_header idh;
+  struct stem_dict_header sdh;
+  u_char prev[MAXSTEMLEN + 1];
+  u_char *buffer;
+  unsigned short *pointers;
+  int buf_in_use;
+  unsigned short ptrs_in_use, word_num;
+
+  id = open_file (filename, INVF_DICT_SUFFIX, "rb", MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  ii = open_file (filename, INVF_IDX_SUFFIX, "rb", MAGIC_INVI, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  idb = create_file (filename, INVF_DICT_BLOCKED_SUFFIX, "w+b", MAGIC_STEM,
+		     MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  FName = make_name (filename, ".tmp", NULL);
+  if (!(tmp = fopen (FName, "w+b")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open \"%s\".\n", FName);
+
+  /* Delete the file now */
+  unlink (FName);
+
+  fread (&idh, sizeof (idh), 1, id);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  sdh.lookback = idh.lookback;
+  sdh.block_size = block_size;
+  sdh.num_blocks = 0;
+  sdh.index_chars = 0;
+  sdh.blocks_start = 0;
+  sdh.num_of_docs = idh.num_of_docs;
+  sdh.static_num_of_docs = idh.static_num_of_docs;
+  sdh.num_of_words = idh.num_of_words;
+  sdh.stemmer_num = idh.stemmer_num;
+  sdh.stem_method = idh.stem_method;
+  sdh.indexed = 0;  /* [RPAP - Jan 97: Stem Index Change] */
+
+  fwrite (&sdh, sizeof (sdh), 1, idb);
+
+  if (!(buffer = Xmalloc (block_size + 512)))
+    FatalError (1, "Unable to allocate memory for \"buffer\"\n");
+  if (!(pointers = Xmalloc (block_size + 512)))
+    FatalError (1, "Unable to allocate memory for \"buffer\"\n");
+
+  buf_in_use = 0;
+  pos = 0;
+  word_num = 0;
+  ptrs_in_use = 0;
+  First_word = 0;
+  for (i = 0; i < idh.dict_size; i++)
+    {
+      register unsigned long extra, copy, suff;
+      unsigned long wcnt, fcnt;
+
+      /* build a new word on top of prev */
+      copy = getc (id);
+      suff = getc (id);
+      *prev = copy + suff;
+      fread (prev + copy + 1, sizeof (u_char), suff, id);
+
+      /* read other data, but no need to store it */
+      fread (&fcnt, sizeof (fcnt), 1, id);
+      fread (&wcnt, sizeof (wcnt), 1, id);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      /* read in the inverted file position */
+      fread (&invf_ptr, sizeof (invf_ptr), 1, ii);
+      NTOHUL(invf_ptr);  /* [RPAP - Jan 97: Endian Ordering] */
+      if (word_num % idh.lookback == 0)
+	extra = copy + sizeof (*pointers);
+      else
+	extra = 0;
+      if ((ptrs_in_use + 1) * sizeof (*pointers) + sizeof (ptrs_in_use) + extra +
+	  buf_in_use + suff + 1 + sizeof (fcnt) + sizeof (wcnt) +
+	  sizeof (First_word) + sizeof (invf_ptr) + sizeof (invf_len) > block_size)
+	{
+	  int chunk;
+	  invf_len = invf_ptr - last_ptr;
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  HTONUL(First_word);
+	  HTONUL(invf_len);
+	  HTONUS(word_num);
+
+	  fwrite (&First_word, sizeof (First_word), 1, tmp);
+	  fwrite (&invf_len, sizeof (invf_len), 1, tmp);
+	  fwrite (&word_num, sizeof (word_num), 1, tmp);
+	  fwrite (pointers, sizeof (*pointers), ptrs_in_use, tmp);
+	  fwrite (buffer, sizeof (u_char), buf_in_use, tmp);
+	  bzero ((char *) buffer, block_size);
+	  chunk = buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	    sizeof (ptrs_in_use) + sizeof (First_word) + sizeof (invf_len);
+	  if (force && chunk < block_size)
+	    {
+	      fwrite (buffer, sizeof (u_char), block_size - chunk, tmp);
+	      chunk = block_size;
+	    }
+
+	  pos += chunk;
+
+	  buf_in_use = 0;
+	  word_num = 0;
+	  ptrs_in_use = 0;
+	  sdh.num_blocks++;
+	}
+
+      if (word_num % idh.lookback == 0)
+	{
+	  HTONUS2(buf_in_use, pointers[ptrs_in_use++]);  /* [RPAP - Jan 97: Endian Ordering] */
+	  suff += copy;
+	  copy = 0;
+	}
+      buffer[buf_in_use++] = copy;
+      buffer[buf_in_use++] = suff;
+      bcopy ((char *) (prev + copy + 1), (char *) (buffer + buf_in_use), suff);
+      buf_in_use += suff;
+      HTONUL(fcnt);  /* [RPAP - Jan 97: Endian Ordering] */
+      bcopy ((char *) &fcnt, (char *) (buffer + buf_in_use), sizeof (fcnt));
+      buf_in_use += sizeof (fcnt);
+      HTONUL(wcnt);  /* [RPAP - Jan 97: Endian Ordering] */
+      bcopy ((char *) &wcnt, (char *) (buffer + buf_in_use), sizeof (wcnt));
+      buf_in_use += sizeof (wcnt);
+      last_ptr = invf_ptr;
+      HTONUL(invf_ptr);  /* [RPAP - Jan 97: Endian Ordering] */
+      bcopy ((char *) &invf_ptr, (char *) (buffer + buf_in_use), sizeof (invf_ptr));
+      NTOHUL(invf_ptr);  /* [RPAP - Jan 97: Endian Ordering] */
+      buf_in_use += sizeof (invf_ptr);
+      if (buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	  sizeof (ptrs_in_use) > block_size)
+	FatalError (1, "Fatal Internal Error # 34876234\n");
+      if (word_num == 0)
+	{
+	  fwrite (prev, sizeof (u_char), *prev + 1, idb);
+	  HTONUL(pos);  /* [RPAP - Jan 97: Endian Ordering] */
+	  fwrite (&pos, sizeof (pos), 1, idb);
+	  NTOHUL(pos);  /* [RPAP - Jan 97: Endian Ordering] */
+	  sdh.index_chars += *prev + 1;
+	  First_word = i;
+	}
+      word_num++;
+    }
+  if (buf_in_use)
+    {
+      int chunk;
+      fread (&invf_ptr, sizeof (invf_ptr), 1, ii);
+      NTOHUL(invf_ptr);  /* [RPAP - Jan 97: Endian Ordering] */
+      invf_len = invf_ptr - last_ptr;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(First_word);
+      HTONUL(invf_len);
+      HTONUS(word_num);
+
+      fwrite (&First_word, sizeof (First_word), 1, tmp);
+      fwrite (&invf_len, sizeof (invf_len), 1, tmp);
+      fwrite (&word_num, sizeof (word_num), 1, tmp);
+      fwrite (pointers, sizeof (*pointers), ptrs_in_use, tmp);
+      fwrite (buffer, sizeof (u_char), buf_in_use, tmp);
+      bzero ((char *) buffer, block_size);
+      chunk = buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	sizeof (ptrs_in_use) + sizeof (First_word) + sizeof (invf_len);
+      if (force && chunk < block_size)
+	{
+	  fwrite (buffer, sizeof (u_char), block_size - chunk, tmp);
+	  chunk = block_size;
+	}
+
+      sdh.num_blocks++;
+    }
+  fclose (id);
+  fclose (ii);
+
+  rewind (tmp);
+  sdh.blocks_start = sdh.index_chars + sizeof (u_long) + sizeof (sdh) +
+    sdh.num_blocks * sizeof (pos);
+  if (force)
+    {
+      int amount;
+      amount = sdh.blocks_start % block_size;
+      if (amount != 0)
+	{
+	  bzero ((char *) buffer, block_size);
+	  fwrite (buffer, sizeof (u_char), block_size - amount, idb);
+	  sdh.blocks_start += block_size - amount;
+	}
+    }
+
+  while ((num = fread (buffer, sizeof (u_char), block_size, tmp)) != 0)
+    fwrite (buffer, sizeof (u_char), num, idb);
+  fclose (tmp);
+
+  /* skip over the magic number */
+  fseek (idb, sizeof (u_long), 0);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(sdh.lookback);
+  HTONUL(sdh.block_size);
+  HTONUL(sdh.num_blocks);
+  HTONUL(sdh.blocks_start);
+  HTONUL(sdh.index_chars);
+  HTONUL(sdh.num_of_docs);
+  HTONUL(sdh.static_num_of_docs);
+  HTONUL(sdh.num_of_words);
+  HTONUL(sdh.stemmer_num);
+  HTONUL(sdh.stem_method);
+  HTONUL(sdh.indexed);
+
+  fwrite (&sdh, sizeof (sdh), 1, idb);
+  fclose (idb);
+
+
+  Message ("Block size = %d\n", block_size);
+  Message ("Number of blocks written = %d\n", NTOHUL(sdh.num_blocks));
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dump.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dump.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dump.1	(revision 10506)
@@ -0,0 +1,142 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_dump 1 \*(Dt CITRI
+.SH NAME
+mg_invf_dump \- Dump out an inverted file in ASCII
+.SH SYNOPSIS
+.B mg_invf_dump
+[
+.B \-h
+]
+[
+.B \-b
+]
+[
+.B \-w
+]
+[
+.B \-t
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program dumps out an inverted file produced by the
+.BR mg (1)
+system as ASCII numbers.  This program could be used in conjunction
+with
+.BR mgdictlist (1)
+to write simple shell programs that work with the inverted files.  The
+output from the program looks something like this:
+.LP
+.RS
+.ft 3
+.nf
+6 337
+1
+ 1 1
+1
+ 5 1
+1
+ 2 1
+1
+ 1 1
+4
+ 1 3
+ 2 7
+ 3 2
+ 5 2
+1
+ 1 1
+ . . .
+.fi
+.ft
+.RE
+The first number (6) is the number of documents in the collection.  It
+is followed by the number of different terms in the collection.  For
+each term, the number of different documents it occurs in follows. The
+document numbers that the term occurs in are listed next.  If
+.B \-w
+is specified, then the number of times the term occurred in the
+document is printed alongside the document number.
+If
+.B \-t
+is specified, the term itself is also displayed in quotes.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-b
+This option will cause the output from the program to be in fixed-size
+binary numbers, rather than in ASCII.
+.TP
+.B \-w
+If the inverted file is a level-2 or level-3 inverted file, this causes
+the word counts per document to be output.
+.TP
+.B \-t
+This option causes each term to be displayed along with the number of
+documents it appears in. The term is printed in quotes,
+as in "the".
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf.dict
+The compressed stemmed dictionary.
+.TP
+.B *.invf.ORG
+The original inverted file saved by
+.BR mg_invf_rebuild .
+.TP
+.B *.invf
+The inverted file.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dump.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dump.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_dump.c	(revision 10506)
@@ -0,0 +1,226 @@
+/**************************************************************************
+ *
+ * mg_invf_dump.c -- Program to dump uot an inverted fil
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "messages.h"
+#include "timing.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "words.h"
+#include "invf.h"
+
+extern unsigned long S_btg;
+
+/*
+   $Log$
+   Revision 1.2  2001/06/12 01:41:39  kjm18
+   changed the help message
+
+   Revision 1.1  1999/08/10 21:18:09  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:46  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:05  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/11/29  00:32:01  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.2  1994/09/20  04:41:50  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+static void process_files (char *filename);
+
+int binary = 0;
+int word_counts = 0;
+int term_dump = 0;
+
+
+int main (int argc, char **argv)
+{
+  ProgTime start;
+  char *dir_name, *file_name = "";
+  int ch;
+  msg_prefix = argv[0];
+  dir_name = getenv ("MGDATA");
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "hbwtf:d:")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+        set_basepath(optarg);
+	break;
+      case 'b':
+	binary = 1;
+	break;
+      case 'w':
+	word_counts = 1;
+	break;
+      case 't':
+	term_dump = 1;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-h] [-b] [-w] [-t] [-f input_file]"
+		 "[-d data directory]\n"
+		 "(b - binary mode, w - wordcount, t - term dump)\n", argv[0]);
+	exit (1);
+      }
+  GetTime (&start);
+  process_files (file_name);
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  return 0;
+}
+
+static void 
+process_files (char *name)
+{
+  unsigned long N, Nstatic, k;
+  FILE *dict;
+  FILE *invf;
+  struct invf_dict_header idh;
+  struct invf_file_header ifh;
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  dict = open_file (name, INVF_DICT_SUFFIX, "rb", MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread ((char *) &idh, sizeof (idh), 1, dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  if (!(invf = open_file (name, INVF_SUFFIX ".ORG", "rb", MAGIC_INVF, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    invf = open_file (name, INVF_SUFFIX, "rb", MAGIC_INVF, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread ((char *) &ifh, sizeof (ifh), 1, invf);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(ifh.no_of_words);
+  NTOHUL(ifh.no_of_ptrs);
+  NTOHUL(ifh.skip_mode);
+  for (i = 0; i < 16; i++)
+    NTOHUL(ifh.params[i]);
+  NTOHUL(ifh.InvfLevel);
+
+  if (ifh.skip_mode != 0)
+    FatalError (1, "The invf file contains skips. Unable to dump.");
+
+  DECODE_START (invf)
+    N = idh.num_of_docs;
+  Nstatic = idh.static_num_of_docs;
+  if (binary)
+    {
+      fwrite ((char *) &N, sizeof (N), 1, stdout);
+      fwrite ((char *) &ifh.no_of_words, sizeof (ifh.no_of_words), 1, stdout);
+    }
+  else
+    printf ("%ld %ld\n", N, ifh.no_of_words);
+  for (k = 0; k < ifh.no_of_words; k++)
+    {
+      int i, blk, doc;
+      register unsigned long suff, prefix;
+      unsigned long fcnt, wcnt;
+      char term[MAXSTEMLEN + 1];
+
+      prefix = fgetc (dict);
+      suff = fgetc (dict);
+      fread (&term[prefix], sizeof (char), suff, dict);
+      fread ((char *) &fcnt, sizeof (fcnt), 1, dict);
+      fread ((char *) &wcnt, sizeof (wcnt), 1, dict);
+      term[prefix + suff] = '\0';
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      if (binary)
+	fwrite ((char *) &fcnt, sizeof (fcnt), 1, stdout);
+      else
+	{
+	  if (term_dump)
+	    printf ("%ld    \"%s\"\n", fcnt, term);
+	  else
+	    printf ("%ld\n", fcnt);
+	}
+      blk = BIO_Bblock_Init (Nstatic, fcnt);
+      for (doc = i = 0; i < fcnt; i++)
+	{
+	  int num;
+	  BBLOCK_DECODE (num, blk);
+	  doc += num;
+	  if (binary)
+	    fwrite ((char *) &doc, sizeof (doc), 1, stdout);
+	  else
+	    printf (" %d", doc);
+	  if (ifh.InvfLevel >= 2)
+	    {
+	      int count;
+	      GAMMA_DECODE (count);
+	      if (word_counts)
+		if (binary)
+		  fwrite ((char *) &count, sizeof (count), 1, stdout);
+		else
+		  printf (" %d", count);
+	    }
+	  if (!binary)
+	    putchar ('\n');
+	}
+      while (__btg)
+	DECODE_BIT;
+    }
+  DECODE_DONE
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_merge.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_merge.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_merge.1	(revision 10506)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_merge 1 \*(Dt CITRI
+.SH NAME
+mg_invf_merge \- Merge two inverted files and stemmed dictionaries
+.SH SYNOPSIS
+.B mg_invf_merge
+[
+.B \-h
+]
+[
+.B \-s
+]
+[
+.B \-w
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program takes two
+.BR mg (1)
+database compressed text files and appends the second to
+the first.
+It is part of the
+.BR mgmerge (1)
+addition to the
+.BR mg (1)
+package.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-s
+This option will cause a slow merge to be performed on the inverted files,
+where each inverted file entry is decoded and recoded.
+The default is a fast merge. Accumulated fast merges slowly degrade
+compression performance on the resulting inverted file so
+a periodic slow merge is recommended.
+.TP
+.B \-w
+By default the database .weights file is updated with
+new weights for the new documents in
+.B mg_text_merge.
+The
+.B -w
+option turns this step off.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.old.invf.dict
+The old compressed stemmed dictionary.
+.TP
+.B *.new.invf.dict
+The new compressed stemmed dictionary.
+.TP
+.B *.invf.dict
+The resulting merged compressed stemmed dictionary.
+.TP
+.B *.old.invf.ORG
+The original inverted file saved by
+.BR mg_invf_rebuild .
+.TP
+.B *.old.invf
+The old inverted file.
+.TP
+.B *.new.invf
+The new inverted file.
+.TP
+.B *.invf
+The resulting merged inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgmerge (1),
+.BR mg_get_merge (1),
+.BR mg_text_merge (1),
+.BR mg_invf_rebuild (1),
+.BR mg_invf_dict (1),
+.BR mg_weights_build (1),
+.BR mgquery (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_merge.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_merge.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_merge.c	(revision 10506)
@@ -0,0 +1,852 @@
+/**************************************************************************
+ *
+ * mg_invf_merge.c -- description
+ * Copyright (C) 1995  Shane Hudson (shane@cosc.canterbury.ac.nz)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Last edited:  31 March, 1995 
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "locallib.h"
+#include "local_strings.h"
+#include "messages.h"
+#include "timing.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "bitio_m.h"
+#include "bitio_gen.h"
+#include "bitio_stdio.h"
+
+#include "mg.h"
+#include "mg_merge.h"
+#include "mg_files.h"
+#include "invf.h"
+#include "words.h"
+
+typedef char FileName[256];
+
+
+/*
+ *  The merge_info struct contains all the data for an inverted file and
+ *  lexicon. We declare 3 merge_info variables, m[OLD] m[NEW] and m[MERGE].
+ */
+typedef struct merge_info_type
+  {
+    FileName fname;
+    FILE *invf;
+    FILE *dict;
+    FILE *idx;
+    FILE *para;  /* [RPAP - Feb 97: Level 3 Merge] */
+    struct invf_dict_header idh;
+    struct invf_file_header ifh;
+    u_long nDocs;
+
+    /* Lexicon processing variables */
+    u_long fcnt, wcnt;
+    int suff, pref;
+    unsigned char term[MAXSTEMLEN + 1];
+    u_long term_count;
+    int done;
+
+    /* Variables used for merging */
+    struct stdio_bitio_state sbs;	/* for bit-based I/O on inverted files */
+    u_long nTerms;		/* = number of invf entries */
+    int *fcntlist;		/* store fcnt values read in from the lexicons */
+
+  }
+merge_info;
+
+
+/***************************************************
+ **** GLOBALS ****
+ ***************************************************/
+
+merge_info m[3];		/*  m[OLD], m[NEW] and m[MERGE] */
+u_long magicsize;		/* how big is magic number? currently always 4 */
+u_long Nstatic;			/* static # of documents in file */
+
+float *DocWeightBuffer;
+int weightOption = 0;		/* true if weights file is to be appended */
+
+/*** Globals for processing the lexicons -- see readTerm() and writeTerm() 
+ ***/
+ProgTime start;			/* for printing elapsed time */
+unsigned char prevTerm[MAXSTEMLEN + 1];
+
+/*** Globals for merging -- see processEntry() 
+ ***/
+char *mergedata;		/* stores value OLD/NEW/MERGE for each term */
+int fastMerge = 1;		/* True if fast merge selected. Default = true */
+
+u_long oldIdxValue;		/* stores last read value from m[OLD].idx
+				   Used to calculate entry lengths */
+u_long bytes_output;		/* for writing .invf.idx file */
+u_long oldOnlyBits = 0;		/* entries in old only */
+u_long oldMergeBits = 0;	/* entries in old that are merged with 
+				   a new entry */
+
+/**************************************************************************/
+
+
+/*=======================================================================
+ * init_merge_invf(): open files, initialise globals, etc
+ *=======================================================================*/
+int 
+init_merge_invf ()
+{
+  prevTerm[0] = prevTerm[1] = 0;
+
+    /***
+     *  open .dict files
+     ***/
+  m[OLD].dict = open_file (m[OLD].fname, INVF_DICT_SUFFIX, "rb",
+			   MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  magicsize = ftell (m[OLD].dict);
+  fread (&(m[OLD].idh), sizeof (m[OLD].idh), 1, m[OLD].dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[OLD].idh.lookback);
+  NTOHUL(m[OLD].idh.dict_size);
+  NTOHUL(m[OLD].idh.total_bytes);
+  NTOHUL(m[OLD].idh.index_string_bytes);
+  NTOHD(m[OLD].idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(m[OLD].idh.num_of_docs);
+  NTOHUL(m[OLD].idh.static_num_of_docs);
+  NTOHUL(m[OLD].idh.num_of_words);
+  NTOHUL(m[OLD].idh.stemmer_num);
+  NTOHUL(m[OLD].idh.stem_method);
+
+  m[NEW].dict = open_file (m[NEW].fname, INVF_DICT_SUFFIX, "rb",
+			   MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  fread (&(m[NEW].idh), sizeof (m[NEW].idh), 1, m[NEW].dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[NEW].idh.lookback);
+  NTOHUL(m[NEW].idh.dict_size);
+  NTOHUL(m[NEW].idh.total_bytes);
+  NTOHUL(m[NEW].idh.index_string_bytes);
+  NTOHD(m[NEW].idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(m[NEW].idh.num_of_docs);
+  NTOHUL(m[NEW].idh.static_num_of_docs);
+  NTOHUL(m[NEW].idh.num_of_words);
+  NTOHUL(m[NEW].idh.stemmer_num);
+  NTOHUL(m[NEW].idh.stem_method);
+
+  m[MERGE].dict = create_file (m[MERGE].fname, INVF_DICT_SUFFIX, "wb",
+			       MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* write space for header */
+  fwrite ((char *) &(m[OLD].idh), sizeof (m[OLD].idh), 1, m[MERGE].dict);
+
+  m[OLD].nDocs = m[OLD].idh.num_of_docs;
+  m[NEW].nDocs = m[NEW].idh.num_of_docs;
+  Nstatic = m[OLD].idh.static_num_of_docs;
+  m[OLD].nTerms = m[OLD].idh.dict_size;
+  m[NEW].nTerms = m[NEW].idh.dict_size;
+  m[MERGE].nDocs = m[OLD].nDocs + m[NEW].nDocs;
+  m[MERGE].nTerms = 0;
+
+  /* Set up weight buffer for weights of new documents */
+  if (!(DocWeightBuffer = Xmalloc (m[NEW].nDocs * sizeof (*DocWeightBuffer))))
+    {
+      Message ("Insufficient memory\n");
+      return COMPERROR;
+    }
+  bzero ((char *) DocWeightBuffer, m[NEW].nDocs * sizeof (*DocWeightBuffer));
+
+    /***
+     *  open .invf files
+     *  Try ".ORG" extension first for m[OLD].invf since an inverted file
+     *  with skips may have been created.
+     ****/
+  if (!(m[OLD].invf = open_file (m[OLD].fname, INVF_SUFFIX ".ORG", "rb",
+				 MAGIC_INVF, MG_CONTINUE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    m[OLD].invf = open_file (m[OLD].fname, INVF_SUFFIX, "rb",
+			     MAGIC_INVF, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  fread (&(m[OLD].ifh), sizeof (m[OLD].ifh), 1, m[OLD].invf);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[OLD].ifh.no_of_words);
+  NTOHUL(m[OLD].ifh.no_of_ptrs);
+  NTOHUL(m[OLD].ifh.skip_mode);
+  {
+    int i;
+    for (i = 0; i < 16; i++)
+      NTOHUL(m[OLD].ifh.params[i]);
+  }
+  NTOHUL(m[OLD].ifh.InvfLevel);
+
+  m[NEW].invf = open_file (m[NEW].fname, INVF_SUFFIX, "rb",
+			   MAGIC_INVF, MG_ABORT);
+  fread (&(m[NEW].ifh), sizeof (m[NEW].ifh), 1, m[NEW].invf);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[NEW].ifh.no_of_words);
+  NTOHUL(m[NEW].ifh.no_of_ptrs);
+  NTOHUL(m[NEW].ifh.skip_mode);
+  {
+    int i;
+    for (i = 0; i < 16; i++)
+      NTOHUL(m[NEW].ifh.params[i]);
+  }
+  NTOHUL(m[NEW].ifh.InvfLevel);
+
+  if (m[OLD].ifh.skip_mode != 0)
+    FatalError (1, "The old invf file contains skips. Unable to merge.");
+
+  if (m[OLD].ifh.InvfLevel != m[NEW].ifh.InvfLevel)
+    FatalError (1, "The two invf files have different inversion levels!");
+
+  /********** [RPAP - Feb 97: Level 3 Merge]
+
+  if ((m[OLD].ifh.InvfLevel > 2) || (m[NEW].ifh.InvfLevel > 2))
+    FatalError (1, "mgmerge cannot handle level 3 inverted files!");
+
+    *************/
+
+  m[MERGE].invf = create_file (m[MERGE].fname, INVF_SUFFIX, "wb",
+			       MAGIC_INVF, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* write space for header in inverted file */
+  m[MERGE].ifh.no_of_words = m[MERGE].ifh.no_of_ptrs = 0;
+  m[MERGE].ifh.skip_mode = 0;
+  m[MERGE].ifh.InvfLevel = 2;
+  {
+    int i;
+    for (i = 0; i < 16; i++)
+      m[MERGE].ifh.params[i] = 0;
+  }
+  fwrite ((char *) &(m[MERGE].ifh), sizeof (m[MERGE].ifh), 1, m[MERGE].invf);
+
+    /***
+     *  open .invf.idx files
+     ***/
+  m[OLD].idx = open_file (m[OLD].fname, INVF_IDX_SUFFIX, "rb",
+			  MAGIC_INVI, MG_ABORT);
+  fread (&oldIdxValue, sizeof (u_long), 1, m[OLD].idx);
+  NTOHUL(oldIdxValue);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  m[NEW].idx = open_file (m[NEW].fname, INVF_IDX_SUFFIX, "rb",
+			  MAGIC_INVI, MG_ABORT);
+
+  m[MERGE].idx = create_file (m[MERGE].fname, INVF_IDX_SUFFIX, "wb",
+			      MAGIC_INVI, MG_ABORT);
+
+
+  /* [RPAP - Feb 97: Level 3 Merge] */
+
+    /***
+     *  open .invf.parargraph files
+     ***/
+  if (m[OLD].ifh.InvfLevel == 3)
+    {
+      m[OLD].para = NULL;
+      m[NEW].para = open_file (m[NEW].fname, INVF_PARAGRAPH_SUFFIX, "rb",
+			       MAGIC_PARAGRAPH, MG_ABORT);
+      m[MERGE].para = open_file (m[MERGE].fname, INVF_PARAGRAPH_SUFFIX, "rb+",
+				 MAGIC_PARAGRAPH, MG_ABORT);
+    }
+  else
+    {
+      m[OLD].para = NULL;
+      m[NEW].para = NULL;
+      m[MERGE].para = NULL;
+    }
+
+  return OK;
+}
+
+
+/*=======================================================================
+ * procEntry_slow(): merge an entry, slow method
+ *=======================================================================*/
+void 
+procEntry_slow (int tnum, int type, u_long oldN, u_long newN, u_long mergeN)
+/* 
+ *  Process an invf entry. 
+ *  Slow Merge. (Always decode/re-encode).
+ *
+ *  tnum is the entry number, type = OLD or NEW or MERGE.
+ *  oldN, newN and mergeN are the N parameters for Bblock coding.
+ *  They are passed so other procEntry_fast can call this one
+ *  when a decode/recode is needed to save repeating code.
+ */
+{
+  int doc = 0;
+  int fcntOLD = m[OLD].fcntlist[tnum];
+  int fcntNEW = m[NEW].fcntlist[tnum];
+  int inblk, outblk;
+  u_long inbits = 0, outbits = 0;
+
+  /* write .invf.idx pointer */
+  HTONUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&bytes_output, sizeof (u_long), 1, m[MERGE].idx);
+  NTOHUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  outblk = BIO_Bblock_Init (mergeN, (fcntOLD + fcntNEW));
+
+/*** OLD entry -> merge entry ***/
+  if (type != NEW)
+    {
+      int i;
+      inblk = BIO_Bblock_Init (oldN, fcntOLD);
+      for (i = 0; i < fcntOLD; i++)
+	{
+	  int num;
+	  num = BIO_Stdio_Bblock_Decode (inblk, &(m[OLD].sbs), &inbits);
+	  doc += num;
+	  BIO_Stdio_Bblock_Encode (num, outblk, &(m[MERGE].sbs), &outbits);
+	  if (m[OLD].ifh.InvfLevel >= 2)	/* frequencies */
+	    {
+	      num = BIO_Stdio_Gamma_Decode (&(m[OLD].sbs), &inbits);
+	      BIO_Stdio_Gamma_Encode (num, &(m[MERGE].sbs), &outbits);
+	    }
+	}
+      if (type == OLD)
+	oldOnlyBits += (inbits + m[OLD].sbs.Btg);
+      else
+	oldMergeBits += (inbits + m[OLD].sbs.Btg);
+    }
+
+/*** NEW entry -> merge entry ***/
+  if (type != OLD)
+    {
+      int i;
+      int offset;
+      double logN = log ((double) m[MERGE].nDocs);
+      double idf = logN - log ((double) (fcntOLD + fcntNEW));
+
+      inblk = BIO_Bblock_Init (newN, fcntNEW);
+      offset = (m[OLD].nDocs - doc);	/* amount to be added to 1ST pointer */
+      for (i = 0; i < fcntNEW; i++)
+	{
+	  register int num;
+	  register double weight;
+	  num = BIO_Stdio_Bblock_Decode (inblk, &(m[NEW].sbs), &inbits);
+	  if (i == 0)
+	    num += offset;
+	  doc += num;
+	  BIO_Stdio_Bblock_Encode (num, outblk, &(m[MERGE].sbs), &outbits);
+	  if (m[OLD].ifh.InvfLevel >= 2)	/* frequencies */
+	    {
+	      num = BIO_Stdio_Gamma_Decode (&(m[NEW].sbs), &inbits);
+	      BIO_Stdio_Gamma_Encode (num, &(m[MERGE].sbs), &outbits);
+	      weight = num * idf;
+	      DocWeightBuffer[doc - m[OLD].nDocs - 1] += weight * weight;
+	    }
+	}
+    }
+/*** Now the padding bits ***/
+  while (m[OLD].sbs.Btg)
+    BIO_Stdio_Decode_Bit (&(m[OLD].sbs));
+  while (m[NEW].sbs.Btg)
+    BIO_Stdio_Decode_Bit (&(m[NEW].sbs));
+  while (m[MERGE].sbs.Btg != 8)
+    {
+      BIO_Stdio_Encode_Bit (0, &(m[MERGE].sbs));
+      outbits++;
+    }
+  bytes_output += (outbits >> 3);
+  return;
+}
+
+
+/*=======================================================================
+ * procEntry_fast(): merge an entry, WITHOUT decoding if it's in the
+ *                   old inverted file only
+ *=======================================================================*/
+void 
+procEntry_fast (int tnum, int type)
+/*
+ *  Merge an invf entry. 
+ *  Faster Method : Copy (don't re-code) entries for terms only in IFold.
+ *  The N parameter is Nstatic, from m[OLD].idh.static_num_of_docs.
+ *  If entry type isnt OLD, just call procEntry_slow()
+ */
+{
+  u_long newIdxValue, len = 0;
+
+  /* Calculate IFold entry length in bytes if not NEW type */
+  if (type != NEW)		/* read in an index number from m[OLD].idx */
+    {
+      fread (&newIdxValue, sizeof (u_long), 1, m[OLD].idx);
+      NTOHUL(newIdxValue);  /* [RPAP - Jan 97: Endian Ordering] */
+      len = newIdxValue - oldIdxValue;
+      oldIdxValue = newIdxValue;
+    }
+
+  if (type != OLD)		/* must decode/recode */
+    procEntry_slow (tnum, type, Nstatic, m[NEW].nDocs, Nstatic);
+  else
+    {
+      /* write .invf.idx pointer */
+      HTONUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite (&bytes_output, sizeof (u_long), 1, m[MERGE].idx);
+      NTOHUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+
+      /* copy entry */
+      {
+	int i;
+	char c;
+	for (i = 0; i < len; i++)
+	  {
+	    c = fgetc (m[OLD].invf);
+	    fputc (c, m[MERGE].invf);
+	  }
+      }
+      bytes_output += len;
+      oldOnlyBits += (len * 8);
+    }
+  return;
+}
+
+
+/*=======================================================================
+ * processEntry(): merge an entry. Call either procEntry_slow() or
+ *                 procEntry_fast.
+ *=======================================================================*/
+void 
+processEntry (int tnum, int type)
+/* 
+ *  Read an entry from IFold and/or IFnew, and write to IFmerge.
+ *  tnum is the term number, type is OLD or NEW or MERGE
+ */
+{
+  if (fastMerge)
+    procEntry_fast (tnum, type);
+  else
+    procEntry_slow (tnum, type, Nstatic, m[NEW].nDocs, m[MERGE].nDocs);
+  return;
+}
+
+
+/*=======================================================================
+ * readTerm()
+ *=======================================================================*/
+void 
+readTerm (int x)
+/*
+ *  Read the next term from the appropriate ".invf.dict" file.
+ *  x should be either OLD or NEW.
+ *  Sets m[x].done to true when that lexicon has been completely read.
+ */
+{
+  int i;
+
+  if (m[x].term_count >= m[x].nTerms)
+    {
+      m[x].term[0] = 0;
+      m[x].done = 1;
+      return;
+    }
+  m[x].pref = fgetc (m[x].dict);
+  m[x].suff = fgetc (m[x].dict);
+  m[x].term[0] = m[x].pref + m[x].suff;
+
+  for (i = 0; i < m[x].suff; i++)
+    {
+      m[x].term[m[x].pref + i + 1] = fgetc (m[x].dict);
+    }
+  m[x].term_count = m[x].term_count + 1;
+
+  fread ((char *) &(m[x].fcnt), sizeof (u_long), 1, m[x].dict);
+  fread ((char *) &(m[x].wcnt), sizeof (u_long), 1, m[x].dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[x].fcnt);
+  NTOHUL(m[x].wcnt);
+
+  return;
+}
+
+
+/*=======================================================================
+ * writeTerm()
+ *=======================================================================*/
+void 
+writeTerm (int x)
+/*
+ *  Write the current term to m[MERGE].dict file.
+ *  x is OLD, NEW or MERGE.
+ */
+{
+  unsigned char i, prefix, suffix;
+  if (x == MERGE)
+    {
+      m[MERGE].fcnt = m[OLD].fcnt + m[NEW].fcnt;
+      m[MERGE].wcnt = m[OLD].wcnt + m[NEW].wcnt;
+      m[MERGE].pref = m[OLD].pref;
+      m[MERGE].suff = m[OLD].suff;
+      memcpy (m[MERGE].term, m[OLD].term, m[OLD].term[0] + 1);
+    }
+  if (x == OLD)
+    {
+      m[MERGE].fcnt = m[OLD].fcnt;
+      m[MERGE].wcnt = m[OLD].wcnt;
+    }
+  if (x == NEW)
+    {
+      m[MERGE].fcnt = m[NEW].fcnt;
+      m[MERGE].wcnt = m[NEW].wcnt;
+    }
+  prefix = prefixlen (prevTerm, m[x].term);
+  suffix = m[x].term[0] - prefix;
+  fputc (prefix, m[MERGE].dict);	/* prefix length */
+  fputc (suffix, m[MERGE].dict);	/* suffix length */
+  for (i = 0; i < suffix; i++)
+    fputc (m[x].term[prefix + i + 1], m[MERGE].dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(m[MERGE].fcnt);
+  HTONUL(m[MERGE].wcnt);
+
+  fwrite ((char *) &(m[MERGE].fcnt), sizeof (m[MERGE].fcnt), 1, m[MERGE].dict);
+  fwrite ((char *) &(m[MERGE].wcnt), sizeof (m[MERGE].wcnt), 1, m[MERGE].dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(m[MERGE].fcnt);
+  NTOHUL(m[MERGE].wcnt);
+
+  memcpy (prevTerm, m[x].term, prefix + suffix + 1);
+  m[MERGE].idh.total_bytes += m[x].term[0] + 1;
+  m[MERGE].idh.index_string_bytes += m[x].term[0] + 2 - prefix;
+  fflush (m[MERGE].dict);
+}
+
+
+/*=======================================================================
+ * process_merge_invf(): The main loop
+ *=======================================================================*/
+int 
+process_merge_invf (void)
+/*
+ *  The main function to merge the lexicons and inverted files.
+ */
+{
+/*** Some extra Initialisation stuff first ***/
+
+  m[OLD].term[0] = m[NEW].term[0] = '\0';
+  m[OLD].term_count = m[NEW].term_count = 0;
+  m[OLD].done = m[NEW].done = 0;
+  m[MERGE].idh.total_bytes = m[MERGE].idh.index_string_bytes = 0;
+
+/*** malloc arrays: mergedata, m[OLD].fcntlist, m[NEW].fcntlist ***/
+  mergedata = malloc ((m[OLD].nTerms + m[NEW].nTerms) * sizeof (char));
+  if (mergedata == 0)
+    {
+      fprintf (stderr, "MALLOC error!\n");
+      exit (1);
+    }
+  {
+    int i;
+    for (i = 0; i < 2; i++)
+      {
+	m[i].fcntlist = malloc ((m[OLD].nTerms + m[NEW].nTerms) * sizeof (int));
+	if (m[i].fcntlist == 0)
+	  {
+	    fprintf (stderr, "MALLOC error!\n");
+	    exit (1);
+	  }
+      }
+  }
+
+/*========================*/
+/***    LEXICON PASS    ***/
+/*========================*/
+
+/*** read first terms ***/
+  readTerm (OLD);
+  readTerm (NEW);
+
+  m[MERGE].nTerms = 0;
+  while (m[OLD].done == 0 || m[NEW].done == 0)
+    {
+      int i;
+      if (m[OLD].done)
+	i = 1; /* NEW will always be greater */
+      else if (m[NEW].done)
+	i = -1; /* OLD will always be greater */
+      else
+	i = casecompare (m[OLD].term, m[NEW].term);
+
+      if (i < 0)
+	{			/* term in OLD only */
+	  mergedata[m[MERGE].nTerms] = (char) OLD;
+	  m[OLD].fcntlist[m[MERGE].nTerms] = m[OLD].fcnt;
+	  m[NEW].fcntlist[m[MERGE].nTerms] = 0;
+	  m[MERGE].nTerms++;
+	  writeTerm (OLD);
+	  readTerm (OLD);
+	}
+      if (i == 0)
+	{			/* term in both lexions */
+	  mergedata[m[MERGE].nTerms] = (char) MERGE;
+	  m[OLD].fcntlist[m[MERGE].nTerms] = m[OLD].fcnt;
+	  m[NEW].fcntlist[m[MERGE].nTerms] = m[NEW].fcnt;
+	  m[MERGE].nTerms++;
+	  writeTerm (MERGE);
+	  readTerm (OLD);
+	  readTerm (NEW);
+	}
+      if (i > 0)
+	{			/* term in NEW only */
+	  mergedata[m[MERGE].nTerms] = (char) NEW;
+	  m[NEW].fcntlist[m[MERGE].nTerms] = m[NEW].fcnt;
+	  m[OLD].fcntlist[m[MERGE].nTerms] = 0;
+	  m[MERGE].nTerms++;
+	  writeTerm (NEW);
+	  readTerm (NEW);
+	}
+    }/*while*/
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  /* print some results about terms */
+  {
+    fprintf (stderr, "   Terms: OLD = %ld,  NEW = %ld,  MERGE = %ld\n",
+	     m[OLD].nTerms, m[NEW].nTerms, m[MERGE].nTerms);
+    fprintf (stderr, "   In OLD only: %ld,  In NEW only: %ld,  BOTH: %ld\n",
+	     (m[MERGE].nTerms - m[NEW].nTerms),
+	     (m[MERGE].nTerms - m[OLD].nTerms),
+	     (m[OLD].nTerms + m[NEW].nTerms - m[MERGE].nTerms));
+  }
+
+
+/*========================*/
+/***      INVF PASS     ***/
+/*========================*/
+
+  bytes_output = ftell (m[MERGE].invf);
+  BIO_Stdio_Decode_Start (m[OLD].invf, &m[OLD].sbs);
+  BIO_Stdio_Decode_Start (m[NEW].invf, &m[NEW].sbs);
+  BIO_Stdio_Encode_Start (m[MERGE].invf, &m[MERGE].sbs);
+  {
+    int i;
+    for (i = 0; i < m[MERGE].nTerms; i++)
+      {
+	processEntry (i, mergedata[i]);
+      }
+    /* write final .invf.idx pointer */
+    HTONUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+    fwrite (&bytes_output, sizeof (u_long), 1, m[MERGE].idx);
+    NTOHUL(bytes_output);  /* [RPAP - Jan 97: Endian Ordering] */
+
+    fprintf (stderr, "Old invf: old only bits: %ld, merged bits: %ld\n",
+	     oldOnlyBits, oldMergeBits);
+  }
+
+  return OK;
+}
+
+
+/*=======================================================================
+ * done_merge_invf(): write headers, close files, append weights to
+ *                     weights file
+ *=======================================================================*/
+int 
+done_merge_invf (void)
+{
+/*** write new lexicon header ***/
+  m[MERGE].idh.dict_size = m[MERGE].nTerms;
+  m[MERGE].idh.lookback = m[OLD].idh.lookback;
+  m[MERGE].idh.input_bytes = m[OLD].idh.input_bytes + m[NEW].idh.input_bytes;
+  m[MERGE].idh.total_bytes = m[OLD].idh.total_bytes + m[NEW].idh.total_bytes;
+  m[MERGE].idh.num_of_docs = m[MERGE].nDocs;
+  m[MERGE].idh.num_of_words = m[OLD].idh.num_of_words + m[NEW].idh.num_of_words;
+  m[MERGE].idh.stemmer_num = m[OLD].idh.stemmer_num;
+  m[MERGE].idh.stem_method = m[OLD].idh.stem_method;
+
+  /* if fastMerge, static num of docs stays the same! */
+  if (fastMerge)
+    m[MERGE].idh.static_num_of_docs = m[OLD].idh.static_num_of_docs;
+  else
+    m[MERGE].idh.static_num_of_docs = m[MERGE].nDocs;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(m[MERGE].idh.lookback);
+  HTONUL(m[MERGE].idh.dict_size);
+  HTONUL(m[MERGE].idh.total_bytes);
+  HTONUL(m[MERGE].idh.index_string_bytes);
+  HTOND(m[MERGE].idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  HTONUL(m[MERGE].idh.num_of_docs);
+  HTONUL(m[MERGE].idh.static_num_of_docs);
+  HTONUL(m[MERGE].idh.num_of_words);
+  HTONUL(m[MERGE].idh.stemmer_num);
+  HTONUL(m[MERGE].idh.stem_method);
+
+  fseek (m[MERGE].dict, magicsize, 0);
+  fwrite (&(m[MERGE].idh), sizeof (struct invf_dict_header), 1, m[MERGE].dict);
+
+/*** write new inverted file header ***/
+  m[MERGE].ifh.no_of_words = m[MERGE].nTerms;
+  m[MERGE].ifh.no_of_ptrs = m[OLD].ifh.no_of_ptrs + m[NEW].ifh.no_of_ptrs;
+  m[MERGE].ifh.skip_mode = m[OLD].ifh.skip_mode;
+  m[MERGE].ifh.InvfLevel = m[OLD].ifh.InvfLevel;
+
+  /* ifh.params[16] -- I have NO IDEA what these do!!!!! */
+  /* only set if a inverted file is in skipped format, I think */
+  {
+    int i;
+    for (i = 0; i < 16; i++)
+      m[MERGE].ifh.params[i] = m[OLD].ifh.params[i];
+  }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(m[MERGE].ifh.no_of_words);
+  HTONUL(m[MERGE].ifh.no_of_ptrs);
+  HTONUL(m[MERGE].ifh.skip_mode);
+  {
+    int i;
+    for (i = 0; i < 16; i++)
+      HTONUL(m[MERGE].ifh.params[i]);
+  }
+  HTONUL(m[MERGE].ifh.InvfLevel);
+
+  fseek (m[MERGE].invf, magicsize, 0);	/* go to start of header */
+  fwrite (&(m[MERGE].ifh), sizeof (struct invf_file_header), 1, m[MERGE].invf);
+
+/*** Write new document weights --- leave old weights alone ***/
+  if ((weightOption) && (m[OLD].ifh.InvfLevel >= 2))
+    {
+      FILE *weightfile = open_file (m[MERGE].fname, WEIGHTS_SUFFIX, "r+b",
+				    MAGIC_WGHT, MG_CONTINUE);  /* [RPAP - Feb 97: WIN32 Port] */
+      if (weightfile)
+	{
+	  u_long i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+	  fprintf (stderr, "writing new weights: Nnew = %ld\n", m[NEW].nDocs);
+	  fseek (weightfile, 0, 2);	/* end of file */
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  for (i = 0; i < m[NEW].nDocs; i++)
+	    HTONF(DocWeightBuffer[i]);
+
+	  fwrite ((char *) DocWeightBuffer, sizeof (float), m[NEW].nDocs,
+		  weightfile);
+	}
+      fclose (weightfile);
+    }
+
+
+  /* [RPAP - Feb 97: Level 3 Merge] */
+  if (m[OLD].ifh.InvfLevel == 3)
+    {
+      /* Update paragraph file */
+      int buffer_size = 1000;
+      u_char *buffer;
+      int num;
+
+      if (!(buffer = (u_char *) Xmalloc (buffer_size)))
+	FatalError (1, "Could not allocate memory for paragraph buffer");
+
+      fseek (m[MERGE].para, 0, SEEK_END);
+      while ((num = fread ((char *) buffer, sizeof (*buffer), buffer_size, m[NEW].para)) != 0)
+	fwrite ((char *) buffer, sizeof (*buffer), num, m[MERGE].para);
+
+      Xfree (buffer);
+    }
+
+/*** close files ***/
+  fclose (m[MERGE].invf);
+  fclose (m[OLD].invf);
+  fclose (m[NEW].invf);
+  fclose (m[MERGE].dict);
+  fclose (m[OLD].dict);
+  fclose (m[NEW].dict);
+  fclose (m[MERGE].idx);
+  fclose (m[OLD].idx);
+  fclose (m[NEW].idx);
+
+  /* [RPAP - Feb 97: Level 3 Merge] */
+  if (m[OLD].ifh.InvfLevel == 3)
+    {
+      fclose (m[NEW].para);
+      fclose (m[MERGE].para);
+    }
+
+  return OK;
+}
+
+
+/*=======================================================================
+ * usage()
+ *=======================================================================*/
+void 
+usage (char *progname)
+{
+  fprintf (stderr, "usage:  %s [-s] [-w] [-d directory] -f mg_collection\n",
+	   progname);
+  fprintf (stderr, "  example: %s -s -w -f MERGE/mailfiles\n", progname);
+  exit (1);
+}
+
+
+/*=======================================================================
+ * main()
+ *=======================================================================*/
+int 
+main (int argc, char *argv[])
+{
+  int ch;
+  char *progname;
+  progname = argv[0];
+  m[MERGE].fname[0] = '\0';
+
+  /* message and timing information */
+  msg_prefix = argv[0];
+
+  while ((ch = getopt (argc, argv, "f:d:swh")) != -1)
+    switch (ch)
+      {
+      case 'f':
+	strcpy (m[MERGE].fname, optarg);
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 's':
+	fastMerge = 0;
+	break;
+      case 'w':
+	weightOption = 1;
+	break;
+      case 'h':
+      case '?':
+      default:
+	usage (progname);
+      }
+
+  if (m[MERGE].fname[0] == '\0')
+    usage (progname);
+  strcpy (m[OLD].fname, m[MERGE].fname);
+  strcat (m[OLD].fname, ".old");
+  strcpy (m[NEW].fname, m[MERGE].fname);
+  strcat (m[NEW].fname, ".new");
+
+  GetTime (&start);
+  init_merge_invf ();
+  process_merge_invf ();
+  done_merge_invf ();
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  exit (0);
+}
+
+/*************************************************************************/
+/*   EOF: mg_invf_merge_new.c                                            */
+/*************************************************************************/
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_rebuild.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_rebuild.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_rebuild.1	(revision 10506)
@@ -0,0 +1,156 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_invf_rebuild 1 \*(Dt CITRI
+.SH NAME
+mg_invf_rebuild \- Rebuild an mg inverted file with or without skips.
+.SH SYNOPSIS
+.B mg_invf_rebuild
+.RB [ \-h ]
+.if n .ti +9n
+[
+.BR \-0 " |"
+.B \-1
+[
+.BI \-k " num"
+] |
+.B \-2
+[
+.BI \-s " num"
+]
+[
+.BI \-m " num"
+]
+]
+.if n .ti +9n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_invf_rebuild
+builds a new inverted file, with or without skipping, from an old
+inverted file.  This file uses
+.I *.invf.ORG
+and
+.I *.invf.idx.ORG
+as the
+source from which it builds
+.I *.invf
+and
+.IR *.invf.idx .
+If
+.I *.invf.ORG
+or
+.I *.invf.idx.ORG
+do not exist, the program renames
+.I *.invf
+or
+.I *.invf.idx
+to
+.I *.invf.ORG
+or
+.I *.invf.idx.ORG
+as appropriate.  The old inverted file may contain skipping.  This
+means that it is possible to delete the
+.I *.ORG
+files
+after the new inverted file is built.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-m\fP \fInum\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-0
+This generates a non-skipped inverted file.  This option is normally
+only needed if the
+.I *.ORG
+files have been deleted.
+.TP
+.B \-1
+This generates a skipped inverted file.  The
+.BI \-k " num"
+argument specifies the number of pointers hopped over with each skip.
+.TP
+.B \-2
+This option generates a skipped inverted file.  The skipped inverted
+file is built so that it is `optimal' for ranking using a specific
+number of accumulators.  Each term in the inverted file has a
+different skip length.  The arguments
+.BR \-s " and " \-m
+control the sizes of the skips.
+.TP
+.BI \-k " num"
+This specifies the number of pointers that should be hopped over with
+each skip.  This option is only valid if
+.B \-1
+is specified.
+.TP
+.BI \-m " num"
+This specifies the intended number of accumulators that will be used
+when ranking queries are done on the collection.
+.TP
+.BI \-s " num"
+This specifies the minimum size for skips.  If the calculation of the
+optimal skip size results in a number smaller than
+.IR num ,
+the skip size is set to
+.IR num .
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.ORG
+Original inverted file.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.invf.idx.ORG
+The original index into the inverted file.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_rebuild.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_rebuild.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_invf_rebuild.c	(revision 10506)
@@ -0,0 +1,564 @@
+/**************************************************************************
+ *
+ * mg_invf_rebuild.c -- Program to rebuild an inverted file with skipping
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "timing.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "locallib.h"
+#include "words.h"
+#include "mg.h"
+
+#define LEN 40
+#define WRD 1
+
+typedef struct invf_info
+  {
+    unsigned long doc_num, count, bits_so_far, count_bits;
+  }
+invf_info;
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:11  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:46  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:10  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/29  00:32:03  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:56:56  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:51  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+static char pathname[256];
+
+static void process_files (char *filename);
+
+static int k = -1;
+static int mode = 0;
+static int max_nodes = -1;
+static int mins = -1;
+
+void 
+usage (char *pgname)
+{
+  fprintf (stderr, "usage: %s [-f input_file]"
+       "[-d data directory] -0|-1|-2 [-k num] [-m num] [-s num]\n", pgname);
+  printf ("Mode 0: (the default)\n");
+  printf ("\tk, m, and s have no meaning and if specified produce an error\n");
+  printf ("Mode 1:\n");
+  printf ("\tm, and s have no meaning and if specified produce an error\n");
+  printf ("\tk The size of skips\n");
+  printf ("Mode 2:\n");
+  printf ("\tk has no meaning and if specified will produce an error\n");
+  printf ("\tm is the the number of accumulators that will be used for the\n");
+  printf ("\t  ranking. The program builds an inverted file that is \n");
+  printf ("\t  \"optimal\" for that number of accumulators.\n");
+  printf ("\ts is the minimum size for skips.\n");
+  exit (1);
+}
+
+
+
+int main (int argc, char **argv)
+{
+  ProgTime start;
+  char *dir_name, *file_name = "";
+  int ch;
+  msg_prefix = argv[0];
+  dir_name = getenv ("MGDATA");
+  strcpy (pathname, dir_name ? dir_name : ".");
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "012hf:d:k:b:s:m:")) != -1)
+    switch (ch)
+      {
+      case '0':
+	mode = 0;
+	break;
+      case '1':
+	mode = 1;
+	break;
+      case '2':
+	mode = 2;
+	break;
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	strcpy (pathname, optarg);
+	break;
+      case 'k':
+	k = atoi (optarg);
+	break;
+      case 'm':
+	max_nodes = atoi (optarg);
+	break;
+      case 's':
+	mins = atoi (optarg);
+	if (mins < 1)
+	  FatalError (1, "The number for the -m option must be greater"
+		      " than or equal to 1");
+	break;
+      case 'h':
+      case '?':
+	usage (argv[0]);
+      }
+
+  if ((mode == 0 && (k != -1 || max_nodes != -1 || mins != -1)) ||
+      (mode == 1 && (max_nodes != -1 || mins != -1)) ||
+      (mode == 2 && (k != -1)))
+    {
+      Message ("Illegal parameters for mode");
+      usage (argv[0]);
+    }
+
+  if (mode == 1 && k == -1)
+    {
+      k = 8;
+      Message ("k is required for mode 1: defaulting k to %d", k);
+    }
+  if (mode == 2 && max_nodes == -1)
+    {
+      max_nodes = 1024;
+      Message ("m is required for mode 2: defaulting m to %d", max_nodes);
+    }
+  if (mode == 2 && mins == -1)
+    {
+      mins = 1;
+      Message ("s is required for mode 2: defaulting s to %d", mins);
+    }
+
+
+  GetTime (&start);
+  process_files (file_name);
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  Message ("**** Don\'t forget to rebuild the stemmed dictionary with mg_invf_dict. ****\n");
+  Message ("**** If the collection was built with stem indexes don\'t forget to     ****\n");
+  Message ("**** rebuild them with mg_stem_idx.                                     ****\n");
+
+  return 0;
+}
+
+
+
+
+
+static void 
+process_files (char *filename)
+{
+  FILE *in, *out, *idx, *odx, *dict;
+  unsigned long magic, outmode, N, in_k, out_k;
+  unsigned long bits_out, bytes_out, i, j;
+  stdio_bitio_state out_buf, in_buf;
+  struct invf_dict_header idh;
+  struct invf_file_header ifh_in, ifh_out;
+  char FName[256];
+
+  outmode = mode;
+
+  /* open .invf.ORG, rename .invf if have to */
+  sprintf (FName, FILE_NAME_FORMAT ".ORG", pathname, filename, INVF_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(in = fopen (FName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      char fname[256];
+      sprintf (fname, FILE_NAME_FORMAT, pathname, filename, INVF_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+      rename (fname, FName);
+      if (!(in = fopen (FName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+	FatalError (1, "Unable to open \"%s\".\n", FName);
+    }
+  else
+    {
+      char fname[256];
+      sprintf (fname, FILE_NAME_FORMAT, pathname, filename, INVF_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+      unlink (fname);
+    }
+  Message ("Opening \"%s\"\n", FName);
+
+  /* check the magic number for .invf.ORG */
+  if (fread (&magic, sizeof (magic), 1, in) != 1 || NTOHUL(magic) != MAGIC_INVF)  /* [RPAP - Jan 97: Endian Ordering] */
+    FatalError (1, "Bad magic number in \"%s\".\n", FName);
+
+
+  /* open .invf.idx.ORG, rename .invf.idx if have to */
+  sprintf (FName, FILE_NAME_FORMAT ".ORG", pathname, filename, INVF_IDX_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  if (!(idx = fopen (FName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      char fname[256];
+      sprintf (fname, FILE_NAME_FORMAT, pathname, filename, INVF_IDX_SUFFIX);
+      rename (fname, FName);
+      if (!(idx = fopen (FName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+	FatalError (1, "Unable to open \"%s\".\n", FName);
+    }
+  else
+    {
+      char fname[256];
+      sprintf (fname, FILE_NAME_FORMAT, pathname, filename, INVF_IDX_SUFFIX);
+      unlink (fname);
+    }
+  Message ("Opening \"%s\"\n", FName);
+
+  /* check the magic number for .invf.idx.ORG */
+  if (fread (&magic, sizeof (magic), 1, idx) != 1 || NTOHUL(magic) != MAGIC_INVI)  /* [RPAP - Jan 97: Endian Ordering] */
+    FatalError (1, "Bad magic number in \"%s\".\n", FName);
+
+  sprintf (FName, FILE_NAME_FORMAT, pathname, filename, INVF_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  Message ("Creating \"%s\"\n", FName);
+  if (!(out = fopen (FName, "wb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open \"%s\".\n", FName);
+
+  sprintf (FName, FILE_NAME_FORMAT, pathname, filename, INVF_IDX_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  Message ("Creating \"%s\"\n", FName);
+  if (!(odx = fopen (FName, "wb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open \"%s\".\n", FName);
+
+  sprintf (FName, FILE_NAME_FORMAT, pathname, filename, INVF_DICT_SUFFIX);  /* [RPAP - Feb 97: WIN32 Port] */
+  Message ("Opening \"%s\"\n", FName);
+  if (!(dict = fopen (FName, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open \"%s\".\n", FName);
+
+  if (fread (&magic, sizeof (magic), 1, dict) != 1 || NTOHUL(magic) != MAGIC_STEM_BUILD)  /* [RPAP - Jan 97: Endian Ordering] */
+    FatalError (1, "Bad magic number in \"%s\".\n", FName);
+
+  fread ((char *) &idh, sizeof (idh), 1, dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  HTONUL2(MAGIC_INVF, magic);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite ((char *) &magic, sizeof (magic), 1, out);
+
+  fread ((char *) &ifh_in, sizeof (ifh_in), 1, in);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(ifh_in.no_of_words);
+  NTOHUL(ifh_in.no_of_ptrs);
+  NTOHUL(ifh_in.skip_mode);
+  for (i = 0; i < 16; i++)
+    NTOHUL(ifh_in.params[i]);
+  NTOHUL(ifh_in.InvfLevel);
+
+  ifh_out = ifh_in;
+  ifh_out.skip_mode = outmode;
+  bzero ((char *) ifh_out.params, sizeof (ifh_out.params));
+  switch (outmode)
+    {
+    case 0:
+      break;
+    case 1:
+      ifh_out.params[0] = k;
+      break;
+    case 2:
+      ifh_out.params[0] = max_nodes;
+      ifh_out.params[1] = mins;
+      break;
+    }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(ifh_out.no_of_words);
+  HTONUL(ifh_out.no_of_ptrs);
+  HTONUL(ifh_out.skip_mode);
+  for (i = 0; i < 16; i++)
+    HTONUL(ifh_out.params[i]);
+  HTONUL(ifh_out.InvfLevel);
+
+  fwrite ((char *) &ifh_out, sizeof (ifh_out), 1, out);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(ifh_out.no_of_words);
+  NTOHUL(ifh_out.no_of_ptrs);
+  NTOHUL(ifh_out.skip_mode);
+  for (i = 0; i < 16; i++)
+    NTOHUL(ifh_out.params[i]);
+  NTOHUL(ifh_out.InvfLevel);
+
+  Message ("The file is a level %d inverted file.\n", ifh_in.InvfLevel);
+
+  bits_out = ftell (out) * 8;
+
+
+  HTONUL2(MAGIC_INVI, magic);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite ((char *) &magic, sizeof (magic), 1, odx);
+
+  DECODE_START (in)
+    DECODE_PAUSE (in_buf)
+
+    ENCODE_START (out)
+    ENCODE_PAUSE (out_buf)
+
+    N = idh.num_of_docs;
+
+  for (i = 0; i < ifh_in.no_of_words; i++)
+    {
+      unsigned long blk, p;
+      unsigned long odn_blk = 0, olen_blk = 0;
+      unsigned long idn_blk = 0, ilen_blk = 0;
+      register unsigned long suff;
+      unsigned long fcnt, wcnt, doc_num, bits_so_far, last_major;
+      unsigned long next_mjr_dn, kd;
+      char dummy2[MAXSTEMLEN + 1];
+      invf_info *ii;
+
+      fgetc (dict);
+      suff = fgetc (dict);
+      fread (dummy2, sizeof (u_char), suff, dict);
+      fread ((char *) &fcnt, sizeof (fcnt), 1, dict);
+      fread ((char *) &wcnt, sizeof (wcnt), 1, dict);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      HTONUL2(bits_out >> 3, bytes_out);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite ((char *) &bytes_out, sizeof (bytes_out), 1, odx);
+      NTOHUL(bytes_out);  /* [RPAP - Jan 97: Endian Ordering] */
+
+      p = fcnt;
+      blk = BIO_Bblock_Init (idh.static_num_of_docs, p);
+      switch (outmode)
+	{
+	case 1:
+	  {
+	    unsigned long len;
+	    if (p <= ifh_out.params[0])
+	      out_k = 0;
+	    else
+	      {
+		out_k = ifh_out.params[0];
+		len = BIO_Bblock_Bound (N, p);
+		if (ifh_in.InvfLevel >= 2)
+		  len += wcnt;
+		odn_blk = BIO_Bblock_Init (idh.num_of_docs, (p + out_k - 1) / out_k);
+		olen_blk = BIO_Bblock_Init (len, (p + out_k - 1) / out_k);
+	      }
+	    break;
+	  }
+	case 2:
+	  {
+	    unsigned long len;
+	    if (p <= mins)
+	      out_k = 0;
+	    else
+	      {
+		out_k = (int) (2 * sqrt ((double) p / max_nodes));
+		if (out_k <= mins)
+		  out_k = mins;
+		len = BIO_Bblock_Bound (N, p);
+		if (ifh_in.InvfLevel >= 2)
+		  len += wcnt;
+		odn_blk = BIO_Bblock_Init (idh.num_of_docs,
+					   (p + out_k - 1) / out_k);
+		olen_blk = BIO_Bblock_Init (len, (p + out_k - 1) / out_k);
+	      }
+	    break;
+	  }
+	default:
+	  out_k = 0;
+	}
+
+      switch (ifh_in.skip_mode)
+	{
+	case 1:
+	  {
+	    unsigned long len;
+	    if (p <= ifh_in.params[0])
+	      in_k = 0;
+	    else
+	      {
+		in_k = ifh_in.params[0];
+		len = BIO_Bblock_Bound (N, p);
+		if (ifh_in.InvfLevel >= 2)
+		  len += wcnt;
+		idn_blk = BIO_Bblock_Init (idh.num_of_docs, (p + in_k - 1) / in_k);
+		ilen_blk = BIO_Bblock_Init (len, (p + in_k - 1) / in_k);
+	      }
+	    break;
+	  }
+	case 2:
+	  {
+	    unsigned long len;
+	    if (p <= ifh_in.params[1])
+	      {
+		in_k = 0;
+	      }
+	    else
+	      {
+		in_k = (int) (2 * sqrt ((double) p / ifh_in.params[0]));
+		if (in_k <= ifh_in.params[1])
+		  in_k = ifh_in.params[1];
+		len = BIO_Bblock_Bound (N, p);
+		if (ifh_in.InvfLevel >= 2)
+		  len += wcnt;
+		idn_blk = BIO_Bblock_Init (idh.num_of_docs,
+					   (p + in_k - 1) / in_k);
+		ilen_blk = BIO_Bblock_Init (len, (p + in_k - 1) / in_k);
+	      }
+	    break;
+	  }
+	default:
+	  in_k = 0;
+	}
+
+      if (!(ii = Xmalloc (sizeof (invf_info) * p)))
+	FatalError (1, "Unable to allocate memory for \"ii\"\n");
+
+      doc_num = bits_so_far = 0;
+      next_mjr_dn = 0;
+      kd = 0;
+      DECODE_CONTINUE (in_buf)
+	for (j = 0; j < p; j++, kd++)
+	{
+	  unsigned long doc_diff, count = 0;
+	  if (kd == in_k)
+	    kd = 0;
+	  if (in_k && kd == 0 && j + in_k < p)
+	    {
+	      int temp;
+	      BBLOCK_DECODE (next_mjr_dn, idn_blk);
+	      next_mjr_dn += doc_num;
+	      BBLOCK_DECODE (temp, ilen_blk);
+	    }
+	  ii[j].bits_so_far = bits_so_far;
+	  if (in_k && kd == in_k - 1 && j != p - 1)
+	    {
+	      int count;
+	      BBLOCK_LENGTH (next_mjr_dn - doc_num, blk, count);
+	      bits_so_far += count;
+	      doc_num = next_mjr_dn;
+	    }
+	  else
+	    {
+	      BBLOCK_DECODE_L (doc_diff, blk, bits_so_far);
+	      doc_num += doc_diff;
+	    }
+	  ii[j].doc_num = doc_num;
+	  if (ifh_in.InvfLevel >= 2)
+	    {
+	      int count_bits = 0;
+	      GAMMA_DECODE_L (count, count_bits);
+	      ii[j].count_bits = count_bits;
+	      bits_so_far += count_bits;
+	      ii[j].count = count;
+	    }
+	}
+
+      /* read till a byte boundary */
+      while (__btg)
+	{
+	  DECODE_BIT;
+	  bits_so_far++;
+	}
+
+      DECODE_PAUSE (in_buf)
+
+	doc_num = bits_so_far = 0;
+      last_major = 0;
+      kd = 0;
+      ENCODE_CONTINUE (out_buf)
+	for (j = 0; j < p; j++, kd++)
+	{
+	  if (kd == out_k)
+	    kd = 0;
+	  if (out_k && kd == 0)
+	    {
+	      if (j + out_k < p)
+		{
+		  int num = ii[j + out_k - 1].doc_num - last_major;
+		  BBLOCK_ENCODE_L (num, odn_blk, bits_out);
+		  last_major = ii[j + out_k - 1].doc_num;
+
+		  num = ii[j + out_k - 1].bits_so_far + ii[j + out_k - 1].count_bits -
+		    bits_so_far;
+		  BBLOCK_ENCODE_L (num, olen_blk, bits_out);
+		  bits_so_far = ii[j + out_k].bits_so_far;
+		}
+	    }
+	  if (!(out_k && kd == out_k - 1 && j != p - 1))
+	    BBLOCK_ENCODE_L (ii[j].doc_num - doc_num, blk, bits_out);
+	  doc_num = ii[j].doc_num;
+	  if (ifh_in.InvfLevel >= 2)
+	    GAMMA_ENCODE_L (ii[j].count, bits_out);
+	}
+
+      /* write till a byte boundary */
+      while (__btg != 8)
+	{
+	  ENCODE_BIT (0);
+	  bits_out++;
+	}
+      ENCODE_PAUSE (out_buf)
+
+	Xfree (ii);
+
+    }
+  ENCODE_CONTINUE (out_buf)
+    ENCODE_DONE
+
+    HTONUL2(bits_out >> 3, bytes_out);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite ((char *) &bytes_out, sizeof (bytes_out), 1, odx);
+  NTOHUL(bytes_out);
+
+  fclose (idx);
+  fclose (odx);
+  fclose (in);
+  fclose (out);
+  fclose (dict);
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_merge.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_merge.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_merge.h	(revision 10506)
@@ -0,0 +1,37 @@
+/**************************************************************************
+ *
+ * mgmerge.h --- mgmerge #defines, etc
+ * Copyright (C) 1995  Shane Hudson (shane@cosc.canterbury.ac.nz)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ * Last edtited: November 12 1994
+ *
+ **************************************************************************/
+
+#ifndef MGMERGE_H
+#define MGMERGE_H
+
+typedef unsigned char byte;
+
+#define OLD 0
+#define NEW 1
+#define MERGE 2
+
+#define OK 0
+#define ERROR_MGMERGE 1
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_passes.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_passes.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_passes.1	(revision 10506)
@@ -0,0 +1,441 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_passes 1 \*(Dt CITRI
+.SH NAME
+mg_passes \- builds mg databases
+.SH SYNOPSIS
+.B mg_passes
+[
+.B \-h
+]
+[
+.B \-G
+]
+[
+.B \-S
+]
+[
+.B \-D
+]
+[
+.B \-W
+]
+.if n .ti +9n
+[
+.BR \-1 " |"
+.BR \-2 " |"
+.B  \-3
+]
+[
+.BI \-C " compstatpoint"
+]
+.if n .ti +9n
+[
+.BI \-n " tracename"
+]
+.if t .ti +.5i
+[
+.BI \-b " bufsize"
+]
+[
+.BI \-m " memlimit"
+]
+.if n .ti +9n
+[
+.BI \-c " numchunks"
+]
+[
+.BI \-a " stemmer"
+]
+[
+.BI \-s " stemmethod"
+]
+[
+.BI \-t " tracepos"
+]
+.if n .ti +9n
+[
+.B \-T1
+]
+[
+.B \-T2
+]
+.if t .ti +.5i
+[
+.B \-I1
+]
+[
+.B \-I2
+]
+.if n .ti +9n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+[
+.I filename(s)
+]
+.SH DESCRIPTION
+.B mg_passes
+is the program that does most of the work when building
+.BR mg (1)
+database systems.  The input documents can come from either
+.I stdin
+or from a list of files on the command line.  Individual documents
+must be separated with control-B characters.  In general,
+.B mg_passes
+must be run twice to build a database, first with the
+.B \-T1
+and
+.B \-I1
+options, and second with the
+.B \-T2
+and
+.B \-I2
+options.  Several other programs must be run in order to get an
+.BR mg (1)
+database that is ready for the
+.BR mgquery (1)
+program.  The
+.SB EXAMPLE
+section below gives an example of how to build a complete
+.BR mg (1)
+database.
+.SH OPTIONS
+Options may appear in any order, but the
+.IR filename(s) ,
+if specified, must be last.
+.TP "\w'\fB\-C\fP \fIcompstatpoint\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-G
+Treat SGML tags as non-words when building the inverted file.  An SGML
+tag is anything between angle brackets, i.e., `<' and `>'.
+.TP
+.B \-S
+This option causes a special pass to be executed.  It is up to a user
+to modify
+.I mg.special.c
+in the source code to do something with the documents it is given.
+.TP
+.B \-D
+If
+.B mg_passes
+fails, then print the document that caused the failure to the trace
+file if tracing is active, or to
+.I stderr
+if it is not.
+.TP
+.B \-W
+This option enables the generation of the weights file when
+.B \-I2
+is specified.  It causes
+.B \-I2
+to use a little more memory and CPU.
+.TP
+.B \-1
+Produce a level-1 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+A level-1 inverted file makes it possible for
+.BR mgquery (1)
+to do Boolean queries.  Ranked queries can still be done,
+although the quality of the ranking is abysmal.
+.TP
+.B \-2
+Produce a level-2 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+This is the default when neither
+.BR \-1 ", " "\-2 " "or " \-3
+is specified.
+A level-2 inverted file makes it possible for
+.BR mgquery (1)
+to do Boolean queries and cosine-ranked queries.
+.TP
+.B \-3
+Produce a level-3 inverted file.  This option is only useful when
+specified with
+.BR "\-I1 ".
+This has been implemented to enable paragraph-level inversion.
+Paragraphs are delimited by control-C characters in the source text.
+.TP
+.BI \-C " compstatpoint"
+This option causes statistics on the compression performance to be
+output to a file called
+.IR *.compression.stats .
+.I compstatpoint
+specifies the interval between outputting each line of statistics.  The
+units of
+.I compstatpoint
+are kilobytes of source text.  E.g., if
+.I compstatpoint
+is 10, then a line is output to the file every 10 KB of input
+source.  Each line of the file consists of 4 numbers The first number
+is the amount of input text, in bytes, processed so far.  The second
+number is the amount of input text, in bytes, processed since the
+last line was output to the file.  The third number is the number of
+output bytes generated since the last line was output to the file, and
+the fourth number is the compression achieved since the last line was
+output, i.e., the third number divided by the second number.
+.TP
+.BI \-n " tracename"
+This specifies the filename to use for the trace log, if tracing is
+enabled using the
+.B \-t
+option.  If
+.BI \-n " tracename"
+is not given and tracing is enabled, a default trace filename will be
+used.
+.TP
+.BI \-s " stemmethod"
+This specifies the method to use to \*(lqstem\*(rq the words in the
+inverted file dictionary.  This is a bit mask specifying the
+operations to do on words as they are parsed out of the text, where
+bit number 0 is the low-order (rightmost) bit.  Bit 0 does case
+folding, and bit 1 does simple stemming, so the value 3 for
+.I stemmethod
+does both case folding and stemming.
+.TP
+.BI \-a " stemmer"
+This specifies the stemmer to use when stemming words.  This
+is a description of the language the stemmer is intended for
+or a description of the stemmer.  Valid options include:
+english, lovin, french, and simplefrench.
+.TP
+.BI \-b " bufsize"
+Specify the size of the document buffer in kilobytes.  If any document
+is larger than
+.IR bufsize ,
+the program will abort with an error message.  This should probably be
+replaced with some system which automatically increases the buffer
+size as required.  The default size is 3072 KB (3 MB).
+.TP
+.BI \-m " memlimit"
+Maximum amount of memory to use for the pass-2 file inversion in
+megabytes.  This option is only useful when used in conjunction with
+the option
+.BR \-I1 .
+The larger this value, the faster the pass-2 inversion will proceed.
+The default value is 5 MB.
+.TP
+.BI \-c " numchunks"
+The maximum number of inversion chunks to write to disk.  Each chunk
+will be approximately as large as
+.IR memlimit .
+This option is only useful when used in conjunction with the option
+.BR \-I2 .
+The larger this value, the faster the pass-2 inversion will proceed.
+The default value is 5 MB.
+.TP
+.BI \-t " tracepos"
+This option activates tracing.  A line will be generated in the
+trace file for every
+.I tracepos
+input bytes processed.  The default name for the trace file can be
+overridden using the
+.BI \-n " tracename"
+option.
+.TP
+.B \-T1
+Generate the
+.I *.text.stats
+file.
+.TP
+.B \-T2
+Generate the
+.IR *.text ,
+.IR *.text.idx ,
+and possibly the
+.I *.text.dict.aux
+files.  Using this option requires that the
+.I *.text.dict
+file be present.
+.TP
+.B \-I1
+Generate the
+.IR *.invf.dict ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files.
+.TP
+.B \-I2
+Generate the
+.I *.invf
+and
+.I *.invf.idx
+files.  Using this option requires
+that the
+.IR *.invf.dict.hash ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files
+be present.  The
+.I *.invf.dict.hash
+file is generated by
+.BR mg_perf_hash_build (1)
+from the
+.I *.invf.dict.build
+file.  If the
+.B \-W
+option is specified, the
+.I *.weight
+file will also be generated.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is to be
+written.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection that will be
+created.
+.TP
+.I filename(s)
+This specifies the source text. If this is not specified, then the
+program expects the source text from
+.IR stdin .
+.SH EXAMPLE
+What follows is a UNIX
+.BR csh (1)
+script as an example of how to build an
+.BR mg (1)
+document collection.
+.LP
+.nf
+.DT
+.ft B
+.I #! /bin/csh
+.I
+# The first argument on the command line specifies the
+.I
+#   source of the text
+set source = ($1)
+.PP
+.I
+# The second argument is the name of the collection
+set text = ($2)
+.PP
+.I
+# Create *.text.stats,  *.invf.dict.build,
+.I
+#   *.invf.chunk and *.invf.chunks.trans
+${source} | mg_passes -T1 -I1 -m 1 -t 1 -f ${text}
+.PP
+.I
+# Create *.text.dict
+mg_compression_dict -f ${text}
+.PP
+.I
+# Create *.invf.dict.hash
+mg_perf_hash_build -f ${text}
+.PP
+.I
+# Create *.text,  *.text.idx,
+.I
+#   *.invf and *.invf.idx
+${source} | mg_passes -T2 -I2 -c 2 -t 1 -f ${text}
+.PP
+.I
+# Create *.text.idx.wgt and *.weight.approx
+mg_weights_build -f ${text} -b 8
+.PP
+.I
+# Create *.invf.dict
+mg_invf_dict -f ${text} -b 4096
+.PP
+.I
+# Create *.text.dict
+mg_fast_comp_dict -f ${text}
+.ft R
+.fi
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.chunk
+Inverted file chunk descriptor file.  When the inverted file is
+created it is created in chunks that use no more than a set amount of
+memory.  This file describes those chunks.
+.TP
+.B *.invf.chunk.trans
+Word-occurrence-order to lexical-order translation file.  The
+.B *.invf.chunk
+file is written in word-occurrence order but is required by
+.B \-I2
+to be in lexical order.
+.TP
+.B *.invf.dict.build
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for an order-preserving perfect hash function.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.trace
+The default trace file.
+.TP
+.B *.compression.stats
+Statistics about the compression of the text.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_passes.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_passes.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_passes.c	(revision 10506)
@@ -0,0 +1,639 @@
+/**************************************************************************
+ *
+ * mg_passes.c -- Driver for the various passes
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#ifdef HAVE_MALLINFO
+# include <malloc.h> 
+#endif
+
+#include <stdlib.h>
+#include "memlib.h"
+#include "messages.h"
+#include "timing.h"
+
+#include "longlong.h"
+
+#include "mg_files.h"
+#include "mg.h"
+#include "build.h"
+#include "text.h"
+#include "stemmer.h"
+
+#include "words.h"
+
+/*
+   $Log$
+   Revision 1.5  2004/11/29 02:56:09  kjdon
+   added some changes made by Emanuel Dejanu (Simple Words)
+
+   Revision 1.4  2003/04/18 01:41:46  sjboddie
+   Added a new -M option to mg_passes, allowing "maxnumeric" to be altered.
+
+   Revision 1.3  2001/09/21 12:46:42  kjm18
+   updated mg to be in line with mg_1.3f. Now uses long long for some variables
+   to enable indexing of very large collections.
+
+   Revision 1.2  2001/06/12 23:23:42  jrm21
+   fixed a bug where mg_passes segfaults when trying to print the usage message.
+
+   Revision 1.1  1999/08/10 21:18:12  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1998/12/17 09:12:53  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:47  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:13  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:57  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:52  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#define MAX_PASSES 5
+
+#define SPECIAL 1
+#define TEXT_PASS_1 2
+#define TEXT_PASS_2 4
+#define IVF_PASS_1 8
+#define IVF_PASS_2 16
+
+#define MIN_BUF 8192
+#define	TERMRECORD	'\002'
+
+unsigned long buf_size = 3 * 1024 * 1024;	/* 3Mb */
+unsigned long invf_buffer_size = 5 * 1024 * 1024;	/* 5Mb */
+unsigned long ChunkLimit = 0;
+char InvfLevel = 2;
+char SkipSGML = 0;
+char MakeWeights = 0;
+FILE *Comp_Stats = NULL;
+int comp_stat_point = 0;
+mg_ullong bytes_processed = 0;
+mg_ullong bytes_received = 0;
+int stemmer_num = 0; /* default to the lovin stemmer */
+int stem_method = 0;
+
+static char Passes = 0;
+static unsigned long trace = 0;
+static int Dump = 0;
+static char **files = NULL;
+static int num_files = 0;
+static char *trace_name = NULL;
+
+
+typedef struct pass_data
+  {
+    char *name;
+    int (*init) (char *);
+    int (*process) (u_char *, int);
+    int (*done) (char *);
+#ifdef HAVE_TIMES
+    clock_t init_time;
+    clock_t process_time;
+    clock_t done_time;
+#else
+    struct timeval init_time;
+    struct timeval process_time;
+    struct timeval done_time;
+#endif
+  }
+pass_data;
+
+#ifdef HAVE_TIMES
+#define NULL_TIMES 0, 0, 0
+#else
+#define NULL_TIMES {0, 0}, {0, 0}, {0, 0}
+#endif
+
+static pass_data PassData[MAX_PASSES] =
+{
+  {"special", init_special, process_special, done_special, NULL_TIMES},
+  {"text.pass1", init_text_1, process_text_1, done_text_1, NULL_TIMES},
+  {"text.pass2", init_text_2, process_text_2, done_text_2, NULL_TIMES},
+  {"ivf.pass1", init_ivf_1, process_ivf_1, done_ivf_1, NULL_TIMES},
+  {"ivf.pass2", init_ivf_2, process_ivf_2, done_ivf_2, NULL_TIMES},
+};
+
+static char *usage_str = "\nUSAGE:\n"
+"  %s [-h] [-G] [-D] [-1|-2|-3] [-T1] [-T2] [-I1] [-I2] [-N1]\n"
+"  %*s [-N2] [-W] [-S] [-b buffer-size] [-d dictionary-directory]\n"
+"  %*s [-t trace-point Mb] [-m invf-memory] [-c chunk-limit]\n"
+"  %*s [-n trace-name] [-C comp-stat-size] [-s stem_method]\n"
+"  %*s [-a stemmer] [-M max-numeric] -f doc-collection-name\n";
+
+
+static void 
+usage (char *err)
+{
+  if (err)
+    Message (err);
+  fprintf (stderr, usage_str, msg_prefix, strlen (msg_prefix), "",
+	   strlen (msg_prefix), "",strlen (msg_prefix), "",
+	   strlen (msg_prefix),"");
+  exit (1);
+}
+
+
+
+
+#if 0
+static char *
+str_comma (unsigned long u)
+{
+  static char buf[20];
+  unsigned long a, b, c, d;
+  a = u / 1000000000;
+  u -= a * 1000000000;
+  b = u / 1000000;
+  u -= b * 1000000;
+  c = u / 1000;
+  u -= c * 1000;
+  d = u;
+
+  if (a)
+    sprintf (buf, "%u,%03u,%03u,%03u", a, b, c, d);
+  else if (b)
+    sprintf (buf, "%u,%03u,%03u", b, c, d);
+  else if (c)
+    sprintf (buf, "%u,%03u", c, d);
+  else
+    sprintf (buf, "%u", d);
+  return (buf);
+}
+#endif
+
+
+
+
+int 
+open_next_file (int in_fd)
+{
+  if (in_fd > 0)
+    close (in_fd);
+  if (num_files == 0)
+    return (-1);
+  if ((in_fd = open (files[0], O_RDONLY)) == -1)
+    FatalError (1, "Cannot open %s", files[0]);
+  files++;
+  num_files--;
+  return (in_fd);
+}
+
+
+static void 
+driver (int in_fd, FILE * Trace, char *file_name)
+{
+  int pass, num = 1;
+
+  char *buffer = Xmalloc (buf_size);
+  unsigned long num_docs = 0;
+  unsigned long block_bytes = 0;
+  register int buf_left = buf_size;
+  register char *look_pos = buffer;
+  register char *end_pos = buffer;
+
+  ProgTime StartTime, InitTime, ProcTime, DoneTime;
+
+  GetTime (&StartTime);
+
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+      {
+	pass_data *pd = &PassData[pass];
+#ifdef HAVE_TIMES
+	struct tms tims;
+	times (&tims);
+	pd->init_time -= tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	struct rusage ru;
+
+	getrusage (RUSAGE_SELF, &ru);
+	pd->init_time.tv_sec -= ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	pd->init_time.tv_usec -= ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+#endif
+	if (pd->init (file_name) == COMPERROR)
+	  FatalError (1, "Error during init of \"%s\"", pd->name);
+
+#ifdef HAVE_TIMES
+	times (&tims);
+	pd->init_time += tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	getrusage (RUSAGE_SELF, &ru);
+	pd->init_time.tv_sec += ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	pd->init_time.tv_usec += ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+	time_normalise (&pd->init_time);
+#endif
+      }
+
+  GetTime (&InitTime);
+  for (;;)
+    {
+      int len = 0;
+      char *base = look_pos;
+
+      while (look_pos != end_pos && *look_pos != TERMRECORD)
+	look_pos++;
+
+      while (look_pos == end_pos)
+	{
+	  if (buf_left < MIN_BUF)
+	    {
+	      bcopy (base, buffer, end_pos - base);
+	      look_pos = buffer + (end_pos - base);
+	      buf_left = buf_size - (end_pos - base);
+	      end_pos = look_pos;
+	      base = buffer;
+	    }
+	  if (buf_left)
+	    {
+    	      num = read (in_fd, end_pos, buf_left);
+	      if (num < 0) num = 0; /* RJM - quick hack :-) */
+	      if (num == 0)
+		if ((in_fd = open_next_file (in_fd)) != -1)
+		  num = read (in_fd, end_pos, buf_left);
+	      bytes_received += num;
+	      buf_left -= num;
+	      end_pos += num;
+	    }
+	  while (look_pos < end_pos && *look_pos != TERMRECORD)
+	    look_pos++;
+	  if (buf_left == 0 && base == buffer && look_pos == end_pos)
+	    {
+	      Message ("Unable to find document terminator (i.e ^B)"
+		       " in the document");
+	      FatalError (1, "The document is in excess of %d chars long",
+			  look_pos - base);
+	    }
+	  if (!num)
+	    break;
+	}
+      len = look_pos++ - base;
+
+      if (!num && base == end_pos)
+	break;
+
+      bytes_processed += len;
+
+#ifndef QUIET
+      if (!len)
+	Message ("Warning : Processing zero length document");
+#endif
+
+      for (pass = 0; pass < MAX_PASSES; pass++)
+	if (Passes & (1 << pass))
+	  {
+	    register pass_data *pd = &PassData[pass];
+
+#ifdef HAVE_TIMES
+	    struct tms tims;
+	    times (&tims);
+	    pd->process_time -= tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	    struct rusage ru;
+	    register struct timeval *tv = &pd->process_time;
+
+	    getrusage (RUSAGE_SELF, &ru);
+	    tv->tv_sec -= ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	    tv->tv_usec -= ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+#endif
+
+	    if (pd->process ((u_char *) base, len) == COMPERROR)
+	      {
+		Message ("Error during processing of \"%s\"", pd->name);
+		if (Dump || Trace)
+		  {
+		    int i;
+		    FILE *f = Trace ? Trace : stderr;
+		    fprintf (f, "-=- * -=- * -=- * -=- * -=- * -=- * -=-\n");
+		    for (i = 0; i < len; i++)
+		      {
+			char ch = base[i];
+			if (ch == '\1' || ch == '\2')
+			  ch = '\n';
+			putc (ch, f);
+		      }
+		    fprintf (f, "-=- * -=- * -=- * -=- * -=- * -=- * -=-\n");
+		  }
+		if (Trace)
+		  fprintf (Trace, "%11" ULL_FS " bytes |%7lu docs | %s\n",
+			   bytes_processed, num_docs,
+			   ElapsedTime (&StartTime, NULL));
+		exit (1);
+	      }
+
+#ifdef HAVE_TIMES
+	    times (&tims);
+	    pd->process_time += tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	    getrusage (RUSAGE_SELF, &ru);
+	    tv->tv_sec += ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	    tv->tv_usec += ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+#endif
+	  }
+      num_docs++;
+      if (Trace)
+	{
+	  block_bytes += (look_pos - base);
+	  if (block_bytes >= trace)
+	    {
+#ifdef HAVE_MALLINFO
+	      struct mallinfo mi;
+	      mi = mallinfo ();
+	      block_bytes -= trace;
+	      fprintf (Trace, "%11" ULL_FS " bytes |%7lu docs |%7.3f Mb | %s\n",
+		       bytes_processed, num_docs, mi.arena / 1024.0 / 1024.0,
+		       ElapsedTime (&StartTime, NULL));
+#else
+	      block_bytes -= trace;
+	      fprintf (Trace, "%11" ULL_FS " bytes |%7lu docs | %s\n",
+		       bytes_processed, num_docs,
+		       ElapsedTime (&StartTime, NULL));
+#endif
+	    }
+	}
+      if (!num && look_pos - 1 == end_pos)
+	break;
+    }
+
+#ifndef HAVE_TIMES
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+      time_normalise (&PassData[pass].process_time);
+#endif
+
+  GetTime (&ProcTime);
+
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+      {
+	pass_data *pd = &PassData[pass];
+#ifdef HAVE_TIMES
+	struct tms tims;
+	times (&tims);
+	pd->done_time -= tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	struct rusage ru;
+
+	getrusage (RUSAGE_SELF, &ru);
+	pd->done_time.tv_sec -= ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	pd->done_time.tv_usec -= ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+#endif
+	if (pd->done (file_name) == COMPERROR)
+	  FatalError (1, "Error during done of \"%s\"", pd->name);
+
+#ifdef HAVE_TIMES
+	times (&tims);
+	pd->done_time += tims.tms_utime + tims.tms_stime;
+#elif defined(HAVE_GETRUSAGE)  /* [RPAP - Feb 97: WIN32 Port] */
+	getrusage (RUSAGE_SELF, &ru);
+	pd->done_time.tv_sec += ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
+	pd->done_time.tv_usec += ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
+	time_normalise (&pd->done_time);
+#endif
+      }
+  if (Trace)
+    {
+#ifdef HAVE_MALLINFO
+      struct mallinfo mi;
+      mi = mallinfo ();
+      fprintf (Trace, "%11" ULL_FS " bytes |%7lu docs |%7.3f Mb | %s\n",
+	       bytes_processed, num_docs, mi.arena / 1024.0 / 1024.0,
+	       ElapsedTime (&StartTime, NULL));
+#else
+      fprintf (Trace, "%11" ULL_FS " bytes |%7lu docs | %s\n",
+	       bytes_processed, num_docs,
+	       ElapsedTime (&StartTime, NULL));
+#endif
+    }
+
+  GetTime (&DoneTime);
+
+  Message ("");
+  Message ("%10s      :    init         process        done", "");
+  for (pass = 0; pass < MAX_PASSES; pass++)
+    if (Passes & (1 << pass))
+      {
+	pass_data *pd = &PassData[pass];
+	char it[15], pt[15], dt[15];
+#ifdef HAVE_TIMES
+	strcpy (it, cputime_string (pd->init_time));
+	strcpy (pt, cputime_string (pd->process_time));
+	strcpy (dt, cputime_string (pd->done_time));
+#else
+	strcpy (it, cputime_string (&pd->init_time));
+	strcpy (pt, cputime_string (&pd->process_time));
+	strcpy (dt, cputime_string (&pd->done_time));
+#endif
+	Message ("%-10s      : %s   %s   %s", pd->name, it, pt, dt);
+      }
+  Message ("");
+  Message ("Init time       : %s", ElapsedTime (&StartTime, &InitTime));
+  Message ("Process time    : %s", ElapsedTime (&InitTime, &ProcTime));
+  Message ("Done time       : %s", ElapsedTime (&ProcTime, &DoneTime));
+  Message ("Total time      : %s", ElapsedTime (&StartTime, &DoneTime));
+  Message ("Documents       : %u", num_docs);
+  Message ("Bytes received  : %" ULL_FS, bytes_received);
+  Message ("Bytes processed : %" ULL_FS, bytes_processed);
+  Message ("Process Rate    : %.1f kB per cpu second",
+   (double) bytes_processed / (ProcTime.CPUTime - InitTime.CPUTime) / 1024);
+  free (buffer);
+}
+
+
+
+int main (int argc, char **argv)
+{
+  int ch, in_fd;
+  char *filename = NULL;
+  FILE *Trace = NULL;
+
+  msg_prefix = argv[0];
+
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "hC:WGSD123f:d:b:T:I:t:m:N:c:n:s:a:M:")) != -1)
+    {
+      switch (ch)
+	{
+	case 'G':
+	  SkipSGML = 1;
+	  break;
+	case 'S':
+	  Passes |= SPECIAL;
+	  break;
+	case '1':
+	  InvfLevel = 1;
+	  break;
+	case '2':
+	  InvfLevel = 2;
+	  break;
+	case '3':
+	  InvfLevel = 3;
+	  break;
+	case 'f':
+	  filename = optarg;
+	  break;
+	case 'n':
+	  trace_name = optarg;
+	  break;
+	case 'D':
+	  Dump = 1;
+	  break;
+	case 'W':
+	  MakeWeights = 1;
+	  break;
+	case 'd':
+	  set_basepath (optarg);
+	  break;
+	case 'a':
+	  stemmer_num = stemmernumber (optarg);
+	  break;
+	case 's':
+	  stem_method = atoi (optarg) & STEMMER_MASK;
+	  break;
+	case 'b':
+	  buf_size = atoi (optarg) * 1024;
+	  break;
+	case 'C':
+	  comp_stat_point = atoi (optarg) * 1024;
+	  break;
+	case 'c':
+	  ChunkLimit = atoi (optarg);
+	  break;
+	case 'm':
+	  invf_buffer_size = (int) (atof (optarg) * 1024 * 1024);
+	  break;
+	case 'I':
+	case 'N': /* N kept for compatability */
+	  if (*optarg == '1')
+	    Passes |= IVF_PASS_1;
+	  else if (*optarg == '2')
+	    Passes |= IVF_PASS_2;
+	  else
+	    usage ("Invalid pass number");
+	  break;
+	case 'T':
+	  if (*optarg == '1')
+	    Passes |= TEXT_PASS_1;
+	  else if (*optarg == '2')
+	    Passes |= TEXT_PASS_2;
+	  else
+	    usage ("Invalid pass number");
+	  break;
+	case 't':
+	  trace = (unsigned long) (atof (optarg) * 1024 * 1024);
+	  break;
+	case 'M':
+	  SetEnv ("maxnumeric", optarg, NULL);
+	  break;
+	case 'h':
+	case '?':
+	  usage (NULL);
+	}
+    }
+
+  if (!filename || *filename == '\0')
+    FatalError (1, "A document collection name must be specified.");
+
+  if (buf_size < MIN_BUF)
+    FatalError (1, "The buffer size must exceed 1024 bytes.");
+
+  if ((Passes & (IVF_PASS_1 | IVF_PASS_2)) == (IVF_PASS_1 | IVF_PASS_2))
+    FatalError (1, "I1 and I2 cannot be done simultaneously.");
+
+  if ((Passes & (TEXT_PASS_1 | TEXT_PASS_2)) == (TEXT_PASS_1 | TEXT_PASS_2))
+    FatalError (1, "T1 and T2 cannot be done simultaneously.");
+
+  if (!Passes)
+    FatalError (1, "S, T1, T2, I1 or I2 must be specified.");
+
+  if (optind < argc)
+    {
+      if ((in_fd = open (argv[optind], O_RDONLY)) == -1)
+	FatalError (1, "Cannot open %s", argv[optind]);
+      files = &argv[optind + 1];
+      num_files = argc - (optind + 1);
+    }
+  else
+    in_fd = 0;			/* stdin */
+
+
+  if (trace)
+    {
+      if (!trace_name)
+	trace_name = make_name (filename, TRACE_SUFFIX, NULL);
+      if (!(Trace = fopen (trace_name, "a")))
+	Message ("Unable to open \"%s\". No tracing will be done.", trace_name);
+      else
+	setbuf (Trace, NULL);
+    }
+  else
+    Trace = NULL;
+
+  if (comp_stat_point)
+    {
+      char *name = make_name (filename, COMPRESSION_STATS_SUFFIX, NULL);
+      if (!(Comp_Stats = fopen (name, "wb")))  /* [RPAP - Feb 97: WIN32 Port] */
+	Message ("Unable to open \"%s\". No comp. stats. will be generated.",
+		 name);
+    }
+
+
+  if (Trace)
+    {
+      int i;
+      fprintf (Trace, "\n\n\t\t-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n");
+      for (i = 0; i < argc; i++)
+	fprintf (Trace, "%s ", argv[i]);
+      fprintf (Trace, "\n\n");
+    }
+
+  driver (in_fd, Trace, filename);
+
+  if (Trace)
+    fclose (Trace);
+
+  if (Comp_Stats)
+    fclose (Comp_Stats);
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_perf_hash_build.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_perf_hash_build.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_perf_hash_build.1	(revision 10506)
@@ -0,0 +1,89 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_perf_hash_build 1 \*(Dt CITRI
+.SH NAME
+mg_perf_hash_build \- generate an order-preserving hash function for the stemmed dictionary
+.SH SYNOPSIS
+.B mg_perf_hash_build
+[
+.B \-h
+]
+[
+.BI \-r " rndseed"
+]
+[
+.BI \-d  " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_perf_hash_build
+generates an order-preserving hashing function from the compressed
+stemmed dictionary and writes it out to disk.
+.BR mg_passes (1)
+will make use of the hash function when it builds the inverted file.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-r " rndseed"
+This specifies the random seed to be used in the generation of the
+hash function; it must be an integer.  If this is not specified, the
+current time will be used as the random seed.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf.dict
+Stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for a order-preserving perfect hash function.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_perf_hash_build.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_perf_hash_build.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_perf_hash_build.c	(revision 10506)
@@ -0,0 +1,183 @@
+/**************************************************************************
+ *
+ * mg_perf_hash_build.c -- Program to build a perfect hash function
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "timing.h"
+#include "local_strings.h"
+#include "perf_hash.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "locallib.h"
+#include "words.h"
+#include "mg.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:13  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:47  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:15  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:58  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:53  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+#define POOL_SIZE 1024*1024
+
+static void process_files (char *filename);
+
+int r = -1;
+
+int main (int argc, char **argv)
+{
+  ProgTime start;
+  char *file_name = "";
+  int ch;
+  msg_prefix = argv[0];
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "f:d:r:h")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'r':
+	r = atoi (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file]"
+		 "[-d data directory] [-r random seed] [-h]\n", argv[0]);
+	exit (1);
+      }
+
+  GetTime (&start);
+  process_files (file_name);
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  return 0;
+}
+
+
+
+
+
+static void 
+process_files (char *filename)
+{
+  FILE *dict, *hash;
+  unsigned long i;
+  u_char prev[MAXSTEMLEN + 1];
+  struct invf_dict_header idh;
+  perf_hash_data *phd;
+  u_char *pool;
+  int pool_left;
+  u_char **starts;
+
+
+  dict = open_file (filename, INVF_DICT_SUFFIX, "rb",
+		    MAGIC_STEM_BUILD, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread ((char *) &idh, sizeof (idh), 1, dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  hash = create_file (filename, INVF_DICT_HASH_SUFFIX, "wb",
+		      MAGIC_HASH, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  if (!(pool = Xmalloc (POOL_SIZE)))
+    FatalError (1, "Out of memory");
+  pool_left = POOL_SIZE;
+
+  if (!(starts = Xmalloc (sizeof (u_char *) * idh.dict_size)))
+    FatalError (1, "Out of memory");
+
+  for (i = 0; i < idh.dict_size; i++)
+    {
+      register unsigned long copy, suff, l;
+      unsigned long wcnt, fcnt;
+
+      /* build a new word on top of prev */
+      copy = getc (dict);
+      suff = getc (dict);
+      *prev = copy + suff;
+      fread (prev + copy + 1, sizeof (u_char), suff, dict);
+
+      /* read other data, but no need to store it */
+      fread (&fcnt, sizeof (fcnt), 1, dict);
+      fread (&wcnt, sizeof (wcnt), 1, dict);
+
+      l = *prev + 1;
+      if (pool_left < l)
+	{
+	  pool = Xmalloc (POOL_SIZE);
+	  pool_left = POOL_SIZE;
+	}
+      starts[i] = pool;
+      bcopy ((char *) prev, (char *) pool, l);
+      pool += l;
+      pool_left -= l;
+    }
+  if (!(phd = gen_hash_func (idh.dict_size, starts, r)))
+    FatalError (1, "Unable to generate hash function");
+  if (write_perf_hash_data (hash, phd) == -1)
+    FatalError (1, "Unable to write hash function");
+  fclose (dict);
+  fclose (hash);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_stem_idx.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_stem_idx.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_stem_idx.1	(revision 10506)
@@ -0,0 +1,95 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_stem_idx 1 \*(Dt CITRI
+.SH NAME
+mg_stem_idx \- builds a stem index file
+.SH SYNOPSIS
+.B mg_stem_idx
+[
+.B \-h
+]
+[
+.B \-F
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.B \-s 1|2|3
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_stem_idx
+generates a stem index file for a collection that is to be built with
+stem indexes.  This program should be called three times: once for each
+.B -s
+parameter.  It uses the stemmed dictionary to create the stem index which
+contains pointers into the stemmed dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " num"
+The dictionary is stored in blocks on disk; this option is used to set
+the block size.  The default is 4-KB blocks.
+.TP
+.B \-F
+This option causes the disk blocks to be aligned on the appropriate
+boundaries.  For example, if 4-KB blocks are used, they will be aligned
+in the file on 4-KB boundaries.
+.TP
+.B -s 1|2|3
+The stem method to apply for the stem index.
+.br
+1 = casefolded and non-stemmed
+.br
+2 = non-casefolded and stemmed
+.br
+3 = casefolded and stemmed
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.invf.dict.blocked
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked.1
+Stem index with stem index method 1.
+.TP
+.B *.invf.dict.blocked.2
+Stem index with stem index method 2.
+.TP
+.B *.invf.dict.blocked.3
+Stem index with stem index method 3.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_invf_dict (1),
+.BR mgstemidxlist (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_stem_idx.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_stem_idx.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_stem_idx.c	(revision 10506)
@@ -0,0 +1,892 @@
+/**************************************************************************
+ *
+ * mg_stem_idx.c -- Memory efficient stem index builder
+ * Copyright (C) 1997  Ross Peeters
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "filestats.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "invf.h"
+#include "mg.h"
+#include "locallib.h"
+#include "backend.h"     /* For struct stemmed_dict */
+#include "words.h"
+#include "stemmer.h"
+#include "hash.h"
+#include "local_strings.h"
+
+typedef struct PosEntry
+{
+  unsigned int num_cases;
+  unsigned int blk;
+  unsigned short blk_index;
+  unsigned short offset;
+}
+PosEntry;
+
+
+typedef struct PosList
+{
+  unsigned int list_size;
+  unsigned int num_entries;
+  PosEntry PE[1];
+}
+PosList;
+
+
+typedef struct idx_hash_rec
+{
+  u_char *word;
+  PosList *PL;
+}
+idx_hash_rec;
+
+
+#define POOL_SIZE 1024*1024
+#define HASH_POOL_SIZE 8192
+#define INITIAL_HASH_SIZE 7927
+
+
+static unsigned long MaxMemInUse = 0;
+static unsigned long MemInUse = 0;
+
+static idx_hash_rec **IdxHashTable;
+static unsigned long IdxHashSize;
+static unsigned long IdxHashUsed;
+static u_char *IdxPool;
+static int IdxPoolLeft;
+
+static idx_hash_rec *idx_hr_pool;
+static int idx_hr_PoolLeft;
+
+static idx_hash_rec **idx_first_occr;
+static int idx_max_first_occr;
+
+int block_size = 1024 * 4;
+
+int force = 0;
+
+static long lookback = 4;
+
+static void 
+ChangeMem (int Change)
+{
+  MemInUse += Change;
+  if (MemInUse > MaxMemInUse)
+    MaxMemInUse = MemInUse;
+}
+
+
+/* =========================================================================
+ * Function: MakePosList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+PosList *
+MakePosList (int n)
+{
+  PosList *pl;
+  int list_size = (n == 0 ? 1 : n);	/* always allocate at least one node */
+
+  pl = Xmalloc (sizeof (PosList) + (list_size - 1) * sizeof (PosEntry));
+  if (!pl)
+    FatalError (1, "Unable to allocate term list");
+  ChangeMem (sizeof (PosList) + (list_size - 1) * sizeof (PosEntry));
+
+  pl->num_entries = n;
+  pl->list_size = list_size;
+
+  return pl;
+}
+
+/* =========================================================================
+ * Function: ResizePosList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+#define GROWTH_FACTOR 2
+#define MIN_SIZE 2
+
+static void
+ResizePosList (PosList ** pos_list)
+{
+  PosList *pl = *pos_list;
+
+  ChangeMem (-(sizeof (PosList) + (pl->list_size - 1) * sizeof (PosEntry)));
+  if (pl->num_entries > pl->list_size)
+    {
+      if (pl->list_size)
+	pl->list_size *= GROWTH_FACTOR;
+      else
+	pl->list_size = MIN_SIZE;
+    }
+  pl = Xrealloc (pl, sizeof (PosList) + (pl->list_size - 1) * sizeof (PosEntry));
+
+  if (!pl)
+    FatalError (1, "Unable to resize pos list");
+  ChangeMem (sizeof (PosList) + (pl->list_size - 1) * sizeof (PosEntry));
+
+  *pos_list = pl;
+}
+
+
+/* =========================================================================
+ * Function: FreePosList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+void
+FreePosList (PosList ** the_pl)
+{
+  PosList *pl = *the_pl;
+
+  ChangeMem (-(sizeof(PosList) + sizeof (PosEntry) * (pl->list_size - 1)));
+  Xfree (pl);
+
+  *the_pl = NULL;
+}
+
+
+/* =========================================================================
+ * Function: ResetPosList
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+ResetPosList (PosList ** pl)
+{
+  if (*pl)
+    FreePosList (pl);
+  *pl = MakePosList (0);
+}
+
+/* =========================================================================
+ * Function: AddPosEntry
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+AddPosEntry (PosList ** pos_list, PosEntry * pe)
+{
+  PosList *pl = *pos_list;
+
+  pl->num_entries++;
+  ResizePosList (pos_list);
+  pl = *pos_list;
+
+  /* copy the structure contents */
+  bcopy ((char *) pe, (char *) &(pl->PE[pl->num_entries - 1]), sizeof (PosEntry));
+
+  return pl->num_entries - 1;
+}
+
+
+/* Modified from stem_search.c */
+stemmed_dict *
+ReadStemDictBlk (File * stem_file)
+{
+  unsigned long i;
+  stemmed_dict *sd;
+  u_char *buffer;
+
+  if (!(sd = Xmalloc (sizeof (stemmed_dict))))
+    FatalError (1, "Could not allocate memory for stemmed dict");
+
+
+  sd->stem_file = stem_file;
+  sd->MemForStemDict = 0;
+
+  Fread (&sd->sdh, sizeof (sd->sdh), 1, stem_file);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(sd->sdh.lookback);
+  NTOHUL(sd->sdh.block_size);
+  NTOHUL(sd->sdh.num_blocks);
+  NTOHUL(sd->sdh.blocks_start);
+  NTOHUL(sd->sdh.index_chars);
+  NTOHUL(sd->sdh.num_of_docs);
+  NTOHUL(sd->sdh.static_num_of_docs);
+  NTOHUL(sd->sdh.num_of_words);
+  NTOHUL(sd->sdh.stemmer_num);
+  NTOHUL(sd->sdh.stem_method);
+  NTOHUL(sd->sdh.indexed);
+
+  if (!(buffer = Xmalloc (sd->sdh.index_chars)))
+    {
+      Xfree (sd);
+      FatalError (1, "Could not allocate memory for stemmed dict");
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.index_chars;
+
+  if (!(sd->index = Xmalloc (sd->sdh.num_blocks * sizeof (*sd->index))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      FatalError (1, "Could not allocate memory for stemmed dict");
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.num_blocks * sizeof (*sd->index);
+
+  if (!(sd->pos = Xmalloc (sd->sdh.num_blocks * sizeof (*sd->pos))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      Xfree (sd->index);
+      FatalError (1, "Could not allocate memory for stemmed dict");
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.num_blocks * sizeof (*sd->pos);
+
+  if (!(sd->buffer = Xmalloc (sd->sdh.block_size * sizeof (*sd->buffer))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      Xfree (sd->index);
+      Xfree (sd->buffer);
+      FatalError (1, "Could not allocate memory for stemmed dict");
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.block_size * sizeof (*sd->buffer);
+
+  sd->active = -1;
+
+  for (i = 0; i < sd->sdh.num_blocks; i++)
+    {
+      register u_char len;
+      sd->index[i] = buffer;
+      len = Getc (stem_file);
+      *buffer++ = len;
+      Fread (buffer, sizeof (u_char), len, stem_file);
+      buffer += len;
+      Fread (&sd->pos[i], sizeof (*sd->pos), 1, stem_file);
+      NTOHUL(sd->pos[i]);  /* [RPAP - Jan 97: Endian Ordering] */
+    }
+
+  return sd;
+}
+
+
+void
+mg_init_process ()
+{
+  /* Allocate memory for idx hash table */
+
+  if (!(IdxPool = Xmalloc (POOL_SIZE)))
+    FatalError (1, "Unable to allocate memory for idx pool");
+  IdxPoolLeft = POOL_SIZE;
+  ChangeMem (POOL_SIZE);
+
+  if (!(idx_hr_pool = Xmalloc (HASH_POOL_SIZE * sizeof (idx_hash_rec))))
+    FatalError (1, "Unable to allocate memory for idx pool");
+  idx_hr_PoolLeft = HASH_POOL_SIZE;
+  ChangeMem (HASH_POOL_SIZE * sizeof (idx_hash_rec));
+
+  IdxHashSize = INITIAL_HASH_SIZE;
+  IdxHashUsed = 0;
+  if (!(IdxHashTable = Xmalloc (sizeof (idx_hash_rec *) * IdxHashSize)))
+    FatalError (1, "Unable to allocate memory for idx table");
+  ChangeMem (sizeof (idx_hash_rec *) * IdxHashSize);
+  bzero ((char *) IdxHashTable, sizeof (idx_hash_rec *) * IdxHashSize);
+  idx_max_first_occr = 8192;
+  if (!(idx_first_occr = Xmalloc (sizeof (idx_hash_rec *) * idx_max_first_occr)))
+    FatalError (1, "Unable to allocate memory for idx_first_occur");
+  ChangeMem (sizeof (idx_hash_rec *) * idx_max_first_occr);
+}
+
+
+void
+PackIdxHashTable (void)
+{
+  int s, d;
+  for (s = d = 0; s < IdxHashSize; s++)
+    if (IdxHashTable[s])
+      IdxHashTable[d++] = IdxHashTable[s];
+  ChangeMem (-sizeof (idx_hash_rec *) * IdxHashSize);
+  ChangeMem (sizeof (idx_hash_rec *) * IdxHashUsed);
+  if (!(IdxHashTable = Xrealloc (IdxHashTable, sizeof (idx_hash_rec *) * IdxHashUsed)))
+    FatalError (1, "Out of memory");
+  IdxHashSize = IdxHashUsed;
+}
+
+
+void
+process_stem_dict (stemmed_dict * sd, int stem_method)
+{
+  int block;
+  short blk_index = -1;
+  int wordnum = -1;
+  PosEntry *prevPE = NULL;
+  idx_hash_rec *prevIdx = NULL;
+  u_char word[MAXSTEMLEN + 1];
+  u_char prev[MAXSTEMLEN + 1];
+
+  /* For each block in stem dict... */
+  for (block = 0; block < sd->sdh.num_blocks; block++)
+    {
+      register unsigned int res;
+      int num_indexes;
+      unsigned long *first_word, *last_invf_len;
+      unsigned short *num_words;
+      u_char *base;
+      unsigned short *index;
+
+      /* Read block into buffer */
+      Fseek (sd->stem_file, sd->pos[block] + sd->sdh.blocks_start, 0);
+      Fread (sd->buffer, sd->sdh.block_size, sizeof (u_char), sd->stem_file);
+      sd->active = sd->pos[block];
+
+      /* Move through block header */
+      first_word = (unsigned long *) (sd->buffer);
+      NTOHUL(*first_word);  /* [RPAP - Jan 97: Endian Ordering] */
+      last_invf_len = (unsigned long *) (first_word + 1);
+      NTOHUL(*last_invf_len);  /* [RPAP - Jan 97: Endian Ordering] */
+      num_words = (unsigned short *) (last_invf_len + 1);
+      NTOHUS(*num_words);  /* [RPAP - Jan 97: Endian Ordering] */
+      index = num_words + 1;
+      num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+
+      {
+	/* [RPAP - Jan 97: Endian Ordering] */
+	int i;
+	for (i = 0; i < num_indexes; i++)
+	  NTOHUS(index[i]);
+      }
+
+      base = (u_char *) (index + num_indexes);
+      blk_index = -1;
+
+      /* For each word in block... */
+      for (res = 0; res < *num_words; res++)
+	{
+	  unsigned copy, suff;
+	  register idx_hash_rec *idx_ent = 0;
+
+	  /* Update blk_index */
+	  if (!(res % sd->sdh.lookback))
+	    blk_index++;
+
+	  copy = *base++;
+	  suff = *base++;
+	  bcopy ((char *) base, (char *) (prev + copy + 1), suff);
+	  base += suff;
+	  *prev = copy + suff;
+
+	  /* Skip irrelevant word info */
+	  base += sizeof (u_long);
+	  base += sizeof (u_long);
+	  base += sizeof (u_long);
+
+	  /* Stem word */
+	  bcopy ((char *) prev, (char *) word, *prev + 1);
+	  stemmer (stem_method, sd->sdh.stemmer_num, word);
+
+	  /* Check if word follows straight on from previous word */
+	  if (prevIdx && !compare (word, prevIdx->word))
+	    prevPE->num_cases++;
+
+	  else 
+	    {
+	      /* Search the idx hash table for word */
+	      register unsigned long hashval, step;
+	      register int hsize = IdxHashSize;
+	      HASH (hashval, step, word, hsize);
+	      for (;;)
+		{
+		  register u_char *s1;
+		  register u_char *s2;
+		  register int len;
+		  idx_ent = IdxHashTable[hashval];
+		  if (!idx_ent)
+		    {
+		      /* Create a next entry in the hash table */
+		      int len = *word + 1;
+		      if (!idx_hr_PoolLeft)
+			{
+			  if (!(idx_hr_pool = Xmalloc (HASH_POOL_SIZE *
+						       sizeof (idx_hash_rec))))
+			    FatalError (1, "Unable to allocate memory for pool");
+			  idx_hr_PoolLeft = HASH_POOL_SIZE;
+			  ChangeMem (HASH_POOL_SIZE * sizeof (idx_hash_rec));
+			}
+		      idx_ent = idx_hr_pool++;
+		      idx_hr_PoolLeft--;
+		      if (len > IdxPoolLeft)
+			{
+			  if (!(IdxPool = Xmalloc (POOL_SIZE)))
+			    FatalError (1, "Unable to allocate memory for pool");
+			  IdxPoolLeft = POOL_SIZE;
+			  ChangeMem (POOL_SIZE);
+			}
+		      wordnum++;
+
+		      idx_ent->word = IdxPool;
+		      idx_ent->PL = MakePosList (0);
+		      {
+			PosEntry PE;
+			PE.num_cases = 1;
+			PE.blk = block;
+			PE.blk_index = (unsigned short) blk_index;
+			PE.offset = res % sd->sdh.lookback;
+			AddPosEntry (&(idx_ent->PL), &PE);
+		      }
+		      prevIdx = idx_ent;
+		      prevPE = &(idx_ent->PL->PE[idx_ent->PL->num_entries - 1]);
+
+		      bcopy ((char *) word, (char *) IdxPool, len);
+		      IdxPool += len;
+		      IdxPoolLeft -= len;
+		      if (IdxHashUsed == idx_max_first_occr - 1)
+			{
+			  ChangeMem (-sizeof (idx_hash_rec *) * idx_max_first_occr);
+			  idx_max_first_occr *= 2;
+			  if (!(idx_first_occr = Xrealloc (idx_first_occr, sizeof (idx_hash_rec *) *
+							   idx_max_first_occr)))
+			    FatalError (1, "Unable to allocate memory for idx_first_occr");
+			  ChangeMem (sizeof (idx_hash_rec *) * idx_max_first_occr);
+			}
+		      idx_first_occr[IdxHashUsed] = idx_ent;
+		      IdxHashUsed++;
+		      IdxHashTable[hashval] = idx_ent;
+		      break;
+		    } /* if (!idx_ent) */
+		  
+		  /* Compare the words */
+		  s1 = word;
+		  s2 = idx_ent->word;
+		  len = *s1 + 1;
+		  for (; len; len--)
+		    if (*s1++ != *s2++)
+		      break;
+		  
+		  if (len)
+		    {
+		      /* Entry is not the right one - move to next hash index */
+		      hashval = (hashval + step);
+		      if (hashval >= hsize)
+			hashval -= hsize;
+		    }
+		  else
+		    {
+		      /* Entry is correct - added PosEntry to word */
+		      PosEntry PE;
+		      PE.num_cases = 1;
+		      PE.blk = block;
+		      PE.blk_index = (unsigned short) blk_index;
+		      PE.offset = res % sd->sdh.lookback;
+		      AddPosEntry (&(idx_ent->PL), &PE);
+		      prevIdx = idx_ent;
+		      prevPE = &(idx_ent->PL->PE[idx_ent->PL->num_entries - 1]);
+		      break;
+		    }
+		} /* for (;;) */
+	    } /* else (the word does not follow on from previous one) */
+
+	  if (IdxHashUsed >= IdxHashSize >> 1)
+	    {
+	      idx_hash_rec **ht;
+	      unsigned long size;
+	      unsigned long i;
+	      size = prime (IdxHashSize * 2);
+	      if (!(ht = Xmalloc (sizeof (idx_hash_rec *) * size)))
+		FatalError (1, "Unable to allocate memory for idx table");
+	      bzero ((char *) ht, sizeof (idx_hash_rec *) * size);
+	      ChangeMem (sizeof (idx_hash_rec *) * size);
+
+	      for (i = 0; i < IdxHashSize; i++)
+		if (IdxHashTable[i])
+		  {
+		    register u_char *wptr;
+		    idx_hash_rec *ent;
+		    register unsigned long hashval, step;
+		    
+		    wptr = IdxHashTable[i]->word;
+		    HASH (hashval, step, wptr, size);
+		    ent = ht[hashval];
+		    while (ent)
+		      {
+			hashval += step;
+			if (hashval >= size)
+			  hashval -= size;
+			ent = ht[hashval];
+		      }
+		    ht[hashval] = IdxHashTable[i];
+		  }
+	      Xfree (IdxHashTable);
+	      ChangeMem (-sizeof (idx_hash_rec *) * IdxHashSize);
+	      IdxHashTable = ht;
+	      IdxHashSize = size;
+	    }
+	  
+	} /* end for each word */
+
+    } /* end for each block */
+
+}
+ 
+static int 
+idx_comp (const void *A, const void *B)
+{
+  u_char *s1 = (*((idx_hash_rec **) A))->word;
+  u_char *s2 = (*((idx_hash_rec **) B))->word;
+  return (casecompare (s1, s2));
+}
+
+
+void
+save_idx (char * filename, int stem_method)
+{
+  char *FName;
+  unsigned long i, j, pos, First_word, num;
+  struct stem_idx_header sih;
+  u_char *buffer, *last_word = NULL;
+  unsigned short *pointers;
+  int buf_in_use;
+  unsigned short ptrs_in_use, word_num;
+  FILE *idbi = NULL, *tmp = NULL;
+
+  FName = make_name (filename, ".tmp", NULL);
+  if (!(tmp = fopen (FName, "w+b")))
+    FatalError (1, "Unable to open \"%s\".\n", FName);
+
+  /* Delete the file now */
+  unlink (FName);
+
+  /* Create appropriate stem index file */
+  switch (stem_method)
+    {
+    case (1):
+      {
+	idbi = create_file (filename, INVF_DICT_BLOCKED_1_SUFFIX, "wb", MAGIC_STEM_1,
+			    MG_ABORT);
+	break;
+      }
+
+    case (2):
+      {
+	idbi = create_file (filename, INVF_DICT_BLOCKED_2_SUFFIX, "wb", MAGIC_STEM_2,
+			    MG_ABORT);
+	break;
+      }
+    case (3):
+      {
+	idbi = create_file (filename, INVF_DICT_BLOCKED_3_SUFFIX, "wb", MAGIC_STEM_3,
+			    MG_ABORT);
+	break;
+      }
+    }
+
+  if (!idbi)
+    FatalError (1, "Could NOT create .invf.blocked.%d file", stem_method);
+
+  PackIdxHashTable();
+  qsort (IdxHashTable, IdxHashUsed, sizeof (idx_hash_rec *), idx_comp);
+
+  sih.lookback = lookback;
+  sih.block_size = block_size;
+  sih.num_blocks = 0;
+  sih.blocks_start = 0;
+  sih.index_chars = 0;
+  sih.num_of_words = IdxHashUsed;
+
+  fwrite ((char *) &sih, sizeof (sih), 1, idbi);
+
+  if (!(buffer = Xmalloc (block_size + 512)))
+    FatalError (1, "Unable to allocate memory for \"buffer\"\n");
+  if (!(pointers = Xmalloc (block_size + 512)))
+    FatalError (1, "Unable to allocate memory for \"buffer\"\n");
+
+  buf_in_use = 0;
+  pos = 0;
+  word_num = 0;
+  ptrs_in_use = 0;
+  First_word = 0;
+
+  /* For each word in the hashtable... */
+  for (i = 0; i < IdxHashUsed; i++)
+    {
+      register unsigned long extra, copy, suff;
+      register struct idx_hash_rec *ent = IdxHashTable[i];
+
+      /* build a new word on top of prev */
+      if (last_word != NULL)
+	copy = prefixlen (last_word, ent->word);
+      else
+	copy = 0;
+      suff = *(ent->word) - copy;
+      last_word = ent->word;
+
+      if (word_num % sih.lookback == 0)
+	/* Will need copy chars to add + a pointer in index */
+	extra = copy + sizeof (*pointers);
+      else
+	extra = 0;
+      if ((ptrs_in_use + 1) * sizeof (*pointers) + sizeof (ptrs_in_use) + extra +
+	  buf_in_use + sizeof (First_word) + suff + 1 + sizeof (ent->PL->num_entries) + 
+	  ent->PL->num_entries * sizeof (PosEntry) > block_size)
+	{
+	  /* Dump buffer to tmp file */
+	  int chunk;
+	  HTONUL(First_word);  /* [RPAP - Jan 97: Endian Ordering] */
+	  HTONUS(word_num);  /* [RPAP - Jan 97: Endian Ordering] */
+	  fwrite (&First_word, sizeof (First_word), 1, tmp);
+	  fwrite (&word_num, sizeof (word_num), 1, tmp);
+	  fwrite (pointers, sizeof (*pointers), ptrs_in_use, tmp);
+	  fwrite (buffer, sizeof (u_char), buf_in_use, tmp);
+	  bzero ((char *) buffer, block_size);
+	  chunk = buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	    sizeof (ptrs_in_use) + sizeof (First_word);
+	  if (force && chunk < block_size)
+	    {
+	      fwrite (buffer, sizeof (u_char), block_size - chunk, tmp);
+	      chunk = block_size;
+	    }
+
+	  pos += chunk;
+
+	  buf_in_use = 0;
+	  word_num = 0;
+	  ptrs_in_use = 0;
+	  sih.num_blocks++;
+
+	  /* Check that entry will fit into new block */
+	  if (sizeof (*pointers) + sizeof (ptrs_in_use) + extra + sizeof (First_word) +
+	      suff + 1 + sizeof (ent->PL->num_entries) + 
+	      ent->PL->num_entries * sizeof (PosEntry) > block_size)
+	    FatalError (1, "Block size to small");
+
+	} /* if size > block_size */
+
+      if (word_num % sih.lookback == 0)
+	{
+	  HTONUS2(buf_in_use, pointers[ptrs_in_use++]);  /* [RPAP - Jan 97: Endian Ordering] */
+	  suff += copy;
+	  copy = 0;
+	}
+
+      /* Output Word information */
+      buffer[buf_in_use++] = copy;
+      buffer[buf_in_use++] = suff;
+      bcopy ((char *) (ent->word + copy + 1), (char *) (buffer + buf_in_use), suff);
+      buf_in_use += suff;
+      HTONUI(ent->PL->num_entries);  /* [RPAP - Jan 97: Endian Ordering] */
+      bcopy ((char *) &(ent->PL->num_entries), (char *) (buffer + buf_in_use), sizeof (ent->PL->num_entries));
+      NTOHUI(ent->PL->num_entries);  /* [RPAP - Jan 97: Endian Ordering] */
+      buf_in_use += sizeof (ent->PL->num_entries);
+
+      for (j = 0; j < ent->PL->num_entries; j++)
+	{
+	  register PosEntry *pe = &(ent->PL->PE[j]);
+	  HTONUI(pe->num_cases);  /* [RPAP - Jan 97: Endian Ordering] */
+	  bcopy ((char *) &(pe->num_cases), (char *) (buffer + buf_in_use), sizeof (pe->num_cases));
+	  buf_in_use += sizeof (pe->num_cases);
+	  HTONUI(pe->blk);  /* [RPAP - Jan 97: Endian Ordering] */
+	  bcopy ((char *) &(pe->blk), (char *) (buffer + buf_in_use), sizeof (pe->blk));
+	  buf_in_use += sizeof (pe->blk);
+	  HTONUS(pe->blk_index);  /* [RPAP - Jan 97: Endian Ordering] */
+	  bcopy ((char *) &(pe->blk_index), (char *) (buffer + buf_in_use), sizeof (pe->blk_index));
+	  buf_in_use += sizeof (pe->blk_index);
+	  HTONUS(pe->offset);  /* [RPAP - Jan 97: Endian Ordering] */
+	  bcopy ((char *) &(pe->offset), (char *) (buffer + buf_in_use), sizeof (pe->offset));
+	  buf_in_use += sizeof (pe->offset);
+	}
+
+      if (buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	  sizeof (ptrs_in_use) > block_size)
+	FatalError (1, "Fatal Internal Error # 64209258\n");
+
+      if (word_num == 0) /* the first word in each block - word_num set to 0 when buffer written to tmp file */
+	{
+	  /* Write word to main index */
+	  fwrite (ent->word, sizeof (u_char), *(ent->word) + 1, idbi);
+	  HTONUL(pos);  /* [RPAP - Jan 97: Endian Ordering] */
+	  fwrite (&pos, sizeof (pos), 1, idbi);
+	  NTOHUL(pos);  /* [RPAP - Jan 97: Endian Ordering] */
+	  sih.index_chars += *(ent->word) + 1;
+	  First_word = i;
+	}
+      word_num++;
+    } /* end for each word */ /* for each hash entry */
+
+  if (buf_in_use)
+    {
+      /* Write last buffer to tmp file */
+      int chunk;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(First_word);
+      HTONUS(word_num);
+
+      fwrite (&First_word, sizeof (First_word), 1, tmp);
+      fwrite (&word_num, sizeof (word_num), 1, tmp);
+      fwrite (pointers, sizeof (*pointers), ptrs_in_use, tmp);
+      fwrite (buffer, sizeof (u_char), buf_in_use, tmp);
+      bzero ((char *) buffer, block_size);
+      chunk = buf_in_use + ptrs_in_use * sizeof (*pointers) +
+	sizeof (ptrs_in_use) + sizeof (First_word);
+      if (force && chunk < block_size)
+	{
+	  fwrite (buffer, sizeof (u_char), block_size - chunk, tmp);
+	  chunk = block_size;
+	}
+
+      sih.num_blocks++;
+    }
+
+  rewind (tmp);
+  sih.blocks_start = sih.index_chars + sizeof (u_long) + sizeof (sih) +
+    sih.num_blocks * sizeof (pos);
+  if (force)
+    {
+      int amount;
+      amount = sih.blocks_start % block_size;
+      if (amount != 0)
+	{
+	  bzero ((char *) buffer, block_size);
+	  fwrite (buffer, sizeof (u_char), block_size - amount, idbi);
+	  sih.blocks_start += block_size - amount;
+	}
+    }
+
+  while ((num = fread (buffer, sizeof (u_char), block_size, tmp)) != 0)
+    fwrite (buffer, sizeof (u_char), num, idbi);
+  fclose (tmp);
+
+  /* skip over the magic number */
+  fseek (idbi, sizeof (u_long), 0);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(sih.lookback);
+  HTONUL(sih.block_size);
+  HTONUL(sih.num_blocks);
+  HTONUL(sih.blocks_start);
+  HTONUL(sih.index_chars);
+  HTONUL(sih.num_of_words);
+
+  fwrite (&sih, sizeof (sih), 1, idbi);
+  fclose (idbi);
+
+#ifndef SILENT
+  Message ("Stem %d:\n", stem_method);
+  Message ("     Block size   : %10d\n", block_size);
+  Message ("     Num_blocks   : %10d\n", NTOHUL(sih.num_blocks));  /* [RPAP - Jan 97: Endian Ordering] */
+  Message ("     Max mem used : %10.1f Mb\n", (double) MaxMemInUse / 1024.0 / 1024.0);
+  Message ("     Num_of_words : %10d\n", NTOHUL(sih.num_of_words));  /* [RPAP - Jan 97: Endian Ordering] */
+#endif
+}
+
+
+void
+UpdateStemDict (char * filename, int stem_method)
+{
+  FILE *idb;
+  struct stem_dict_header sdh;
+
+  if (!(idb = open_file (filename, INVF_DICT_BLOCKED_SUFFIX, "r+b",
+			 MAGIC_STEM, MG_CONTINUE)))
+    FatalError (1, "Could not update stemmed dict");
+
+  fread ((char *) &sdh, sizeof (sdh), 1, idb);
+  NTOHUL(sdh.indexed);  /* [RPAP - Jan 97: Endian Ordering] */
+  sdh.indexed |= 1 << (stem_method - 1);
+  HTONUL(sdh.indexed);
+  fseek (idb, sizeof (u_long), 0);
+  fwrite ((char *) &sdh, sizeof (sdh), 1, idb);
+  fclose (idb);
+}
+
+
+
+/* Main */
+int main (int argc, char **argv)
+{
+  File *idb;    /* File to .invf.dict.blocked */
+  char *filename = "";
+  stemmed_dict *sd;   /* Stemmed dictionary */
+  int ch;
+  char path[512];
+  int stem_method = 0;
+
+  msg_prefix = argv[0];
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "f:d:b:hFs:")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	filename = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'b':
+	block_size = atoi (optarg);
+	break;
+      case 'F':
+	force = 1;
+	break;
+      case 's':
+	stem_method = atoi (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-d directory] "
+		 "[-b num] [-F] [-h] -s 1|2|3 -f name\n", argv[0]);
+	exit (1);
+      }
+
+  if (stem_method < 1 || stem_method > 3)
+    FatalError (1, "Stem method must be 1, 2 or 3");
+
+  /* Open required stem dict file */
+  sprintf (path, FILE_NAME_FORMAT, get_basepath (), filename, INVF_DICT_BLOCKED_SUFFIX);
+  if (!(idb = Fopen (path, "rb", MAGIC_STEM)))
+    FatalError (1, "Unable to open \"%s\"", path);
+
+  /* Read in idb header and index to blocks */
+  if (!(sd = ReadStemDictBlk (idb)))
+    FatalError (1, "Could not read stemmed dictionary");
+
+  /* Process stemmed dictionary */
+  mg_init_process ();
+  process_stem_dict (sd, stem_method);
+  save_idx (filename, stem_method);
+ 
+  /* Close stemmed dict */
+  Fclose (idb);
+
+  /* Update stemmed dict */
+  UpdateStemDict (filename, stem_method);
+
+  return 0;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_estimate.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_estimate.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_estimate.1	(revision 10506)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_text_estimate 1 \*(Dt CITRI
+.SH NAME
+mg_text_estimate \- Estimate the size of the compressed text based on the text statistics and a compression dictionary.
+.SH SYNOPSIS
+.B mg_text_estimate
+[
+.B \-h
+]
+[
+.BR \-H " |"
+.BR \-B " |"
+.BR \-D " |"
+.BR \-Y " |"
+.B \-M
+]
+.if n .ti +9n
+.I stats-dict
+.I compression-dict
+.SH DESCRIPTION
+This program estimates the size of the compressed text that would be
+generated if text with certain statistics were compressed with a
+particular dictionary.  This program has no real use in the
+.BR mg (1)
+system, except for experimenting with the
+.BR mg_compression_dict (1)
+program.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-m\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-H
+This specifies that novel words will be coded character by character
+using Huffman codes.
+.TP
+.B \-B
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using binary codes.  The binary code represents their occurrence
+position in the auxiliary dictionary.
+.TP
+.B \-D
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using delta codes.  The delta code represents their occurrence position
+in the auxiliary dictionary.
+.TP
+.B \-Y
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This generally
+produces better compression than
+.B \-B
+or
+.BR \-D .
+.TP
+.B \-M
+This specifies that the size of an auxiliary dictionary will be
+estimated.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This method is
+adaptive within documents, and generally produces better compression
+than
+.BR \-B ,
+.B \-D
+or
+.BR \-Y .
+.SH FILES
+.TP 20
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_estimate.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_estimate.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_estimate.c	(revision 10506)
@@ -0,0 +1,581 @@
+/**************************************************************************
+ *
+ * mg_text_estimate.c -- Program to estimate the compressed text size
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_gen.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "timing.h"
+#include "mgheap.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "invf.h"
+#include "text.h"
+#include "words.h"
+#include "mg.h"
+#include "comp_dict.h"
+#include "hash.h"
+
+
+
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:14  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.4  1999/01/15 03:05:51  rjmcnab
+
+   Renamed lib/heap to be lib/mgheap (it was causing some problems with
+   some versions of the STL libraries which contained a heap.h)
+
+   Revision 1.3  1998/12/17 09:12:53  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:48  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:19  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:56:59  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:54  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+typedef struct stats_t
+  {
+    u_long freq, occur;
+    u_long len;
+  }
+stats_t;
+
+static u_long huff_count = 0;
+static u_long escape_count = 0;
+
+
+char mode = 'H';
+
+/* [RJM 07/97: 4G limit] */
+static double ReadInWordsStandard (char *name, double *num_bytes);
+static double ReadInWordsSpecial (char *name, double *num_bytes,
+				  double *num_extra_bytes,
+				  u_long *aux_compressed);
+
+
+
+
+int main (int argc, char **argv)
+{
+  char *stats_dict = NULL, *comp_dict = NULL;
+  ProgTime StartTime;
+  double num_bytes, num_extra_bytes = 0; /* [RJM 07/97: 4G limit] */
+  u_long aux_compressed;
+  int ch;
+  double bytes;
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "BMDYHh")) != -1)
+    switch (ch)
+      {
+      case 'B':
+	Message ("The compressed text size for this method cannot be\n"
+		 "estimated exactly, so an upper bound will be calculated.");
+	mode = ch;
+	break;
+      case 'M':
+	Message ("The compressed text size for this method cannot be\n"
+		 "estimated exactly, so an upper bound will be calculated.");
+	mode = 'Y';
+	break;
+      case 'D':
+      case 'Y':
+      case 'H':
+	mode = ch;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-h] [B|M|D|Y|H] stats_dict comp_dict\n",
+		 argv[0]);
+	exit (1);
+      }
+
+  if (optind < argc)
+    stats_dict = argv[optind++];
+  else
+    stats_dict = NULL;
+  if (optind < argc)
+    comp_dict = argv[optind++];
+  else
+    {
+      fprintf (stderr, "usage: %s [-h] [B|M|D|Y|H] stats_dict comp_dict\n",
+	       argv[0]);
+      exit (1);
+    }
+
+
+
+  GetTime (&StartTime);
+
+  if (LoadCompressionDictionary (comp_dict) == COMPERROR)
+    exit (1);
+
+  if (mode == 'H')
+    bytes = ReadInWordsStandard (stats_dict, &num_bytes);
+  else
+    bytes = ReadInWordsSpecial (stats_dict, &num_bytes, &num_extra_bytes,
+				&aux_compressed);
+
+
+  Message ("Compressed Text %.2f Mb ( %.0f bytes   %0.3f %%)",
+	   bytes / 1024.0 / 1024, bytes, bytes * 100 / num_bytes);
+  Message ("Words portion of the dictionary %.2f Mb ( %.0f bytes   %0.3f %%)",
+	   Words_disk / 1024.0 / 1024, Words_disk * 1.0,
+	   (Words_disk * 100.0) / num_bytes);
+  if (mode == 'H')
+    Message ("Huffman info for chars in dictionary %.2f Mb ( %.0f bytes   %0.3f %%)",
+	     Chars_disk / 1024.0 / 1024, Chars_disk * 1.0,
+	     (Chars_disk * 100.0) / num_bytes);
+  else
+    {
+      Message ("Aux dictionary (Uncompressed) %.2f Mb ( %.0f bytes   %0.3f %%)",
+	       num_extra_bytes / 1024.0 / 1024, num_extra_bytes * 1.0,
+	       (num_extra_bytes * 100.0) / num_bytes);
+      Message ("Aux dictionary (Compressed)   %.2f Mb ( %.0f bytes   %0.3f %%)",
+	       aux_compressed / 1024.0 / 1024, aux_compressed * 1.0,
+	       (aux_compressed * 100.0) / num_bytes);
+    }
+  Message ("Words and non-words in the text %u", huff_count + escape_count);
+  Message ("Words and non-words coded by escapes %u ( %0.3f %%)", escape_count,
+	   escape_count * 100.0 / huff_count);
+  Message ("%s", ElapsedTime (&StartTime, NULL));
+  return 0;
+}
+
+
+
+
+
+static double 
+ReadInWordsStandard (char *name, double *num_bytes)
+{
+  compression_stats_header csh;
+  FILE *f;
+  u_long which;
+  double bytes, bits = 0;
+
+  f = open_named_file (name, "rb", MAGIC_STATS_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread (&csh, sizeof (csh), 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  for (which = 0; which < 2; which++)
+    {
+      frags_stats_header fsh;
+      int j;
+      fread (&fsh, sizeof (fsh), 1, f);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fsh.num_frags);
+      NTOHUL(fsh.mem_for_frags);
+
+      for (j = 0; j < fsh.num_frags; j++)
+	{
+	  int len, freq, res, occur_num;
+	  u_char Word[16];
+	  fread (&freq, sizeof (freq), 1, f);
+	  fread (&occur_num, sizeof (occur_num), 1, f);
+	  len = fgetc (f);
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  NTOHSI(freq);
+	  NTOHSI(occur_num);
+
+	  Word[0] = len;
+	  fread (Word + 1, len, 1, f);
+
+	  /* Search the hash table for Word */
+	  if (ht[which])
+	    {
+	      register unsigned long hashval, step;
+	      register int tsize = ht[which]->size;
+	      register u_char **wptr;
+	      HASH (hashval, step, Word, tsize);
+	      for (;;)
+		{
+		  register u_char *s1;
+		  register u_char *s2;
+		  register int len;
+		  wptr = ht[which]->table[hashval];
+		  if (wptr == NULL)
+		    {
+		      res = COMPERROR;
+		      break;
+		    }
+
+		  /* Compare the words */
+		  s1 = Word;
+		  s2 = *wptr;
+		  len = *s1 + 1;
+		  for (; len; len--)
+		    if (*s1++ != *s2++)
+		      break;
+
+		  if (len)
+		    {
+		      hashval += step;
+		      if (hashval >= tsize)
+			hashval -= tsize;
+		    }
+		  else
+		    {
+		      res = ht[which]->table[hashval] - ht[which]->words;
+		      break;
+		    }
+		}
+	    }
+	  else
+	    res = COMPERROR;
+
+	  /* Check that the word was found in the dictionary */
+	  if (res == COMPERROR)
+	    {
+	      escape_count += freq;
+	      if (cdh.dict_type == MG_COMPLETE_DICTIONARY)
+		Message ("Unknown word \"%.*s\"\n", *Word, Word + 1);
+	      if (cdh.dict_type == MG_PARTIAL_DICTIONARY)
+		{
+		  unsigned i;
+		  if (ht[which])
+		    {
+		      res = ht[which]->hd->num_codes - 1;
+		      bits += ht[which]->hd->clens[res] * freq;
+		    }
+		  bits += lens_huff[which].clens[Word[0]] * freq;
+		  for (i = 0; i < Word[0]; i++)
+		    bits += char_huff[which].clens[Word[i + 1]] * freq;
+		}
+	      if (cdh.dict_type == MG_SEED_DICTIONARY)
+		{
+		  unsigned i;
+		  if (ht[which])
+		    {
+		      res = ht[which]->hd->num_codes - 1;
+		      bits += ht[which]->hd->clens[res] * freq;
+		    }
+		  bits += lens_huff[which].clens[Word[0]] * freq;
+		  for (i = 0; i < Word[0]; i++)
+		    bits += char_huff[which].clens[Word[i + 1]] * freq;
+		}
+	    }
+	  else
+	    {
+	      bits += ht[which]->hd->clens[res] * freq;
+	      huff_count += freq;
+	    }
+	}
+    }
+  fclose (f);
+
+
+  /*
+   * The 5.5 bits added on per document consist of
+   *   1 bit for the word/non-word flag at the start of the document.
+   *   1 bit on average for document termination.
+   *   3.5 bits on average for padding to a byte boundary.
+   */
+  bits += 5.5 * csh.num_docs;
+
+  bytes = bits / 8 + sizeof (compressed_text_header) + sizeof (u_long);
+
+  *num_bytes = csh.num_bytes;
+
+  return bytes;
+}
+
+
+static int 
+stats_comp (const void *a, const void *b)
+{
+  return ((stats_t *) a)->occur - ((stats_t *) b)->occur;
+}
+
+
+
+
+
+static double 
+ReadInWordsSpecial (char *name, double *num_bytes,
+		    double *num_extra_bytes,
+		    u_long *aux_compressed)
+{
+  compression_stats_header csh;
+  FILE *f;
+  u_long magic, which;
+  double bytes, bits = 0;
+  double size[2];
+
+  if (!(f = fopen (name, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open file \"%s\"\n", name);
+
+  if (fread (&magic, sizeof (magic), 1, f) != 1)
+    FatalError (1, "Unable to read magic number");
+
+  NTOHUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (magic != MAGIC_STATS_DICT)
+    FatalError (1, "Bad magic number");
+
+  fread (&csh, sizeof (csh), 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  for (which = 0; which < 2; which++)
+    {
+      stats_t *stats;
+      frags_stats_header fsh;
+      int j, num = 0;
+      long lens[16], chars[256];
+
+      bzero ((char *) lens, sizeof (lens));
+      bzero ((char *) chars, sizeof (chars));
+
+      fread (&fsh, sizeof (fsh), 1, f);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fsh.num_frags);
+      NTOHUL(fsh.mem_for_frags);
+
+      stats = Xmalloc (fsh.num_frags * sizeof (*stats));
+      if (!stats)
+	FatalError (1, "Unable to allocate memory for stats");
+      for (j = 0; j < fsh.num_frags; j++)
+	{
+	  int len, res;
+	  u_char Word[16];
+	  fread (&stats[num].freq, sizeof (stats[num].freq), 1, f);
+	  fread (&stats[num].occur, sizeof (stats[num].occur), 1, f);
+	  len = fgetc (f);
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  NTOHSI(stats[num].freq);
+	  NTOHSI(stats[num].occur);
+
+	  stats[num].len = len + 1;
+
+	  Word[0] = len;
+	  fread (Word + 1, len, 1, f);
+
+	  /* Search the hash table for Word */
+	  if (ht[which])
+	    {
+	      register unsigned long hashval, step;
+	      register int tsize = ht[which]->size;
+	      register u_char **wptr;
+	      HASH (hashval, step, Word, tsize);
+	      for (;;)
+		{
+		  register u_char *s1;
+		  register u_char *s2;
+		  register int len;
+		  wptr = ht[which]->table[hashval];
+		  if (wptr == NULL)
+		    {
+		      res = COMPERROR;
+		      break;
+		    }
+
+		  /* Compare the words */
+		  s1 = Word;
+		  s2 = *wptr;
+		  len = *s1 + 1;
+		  for (; len; len--)
+		    if (*s1++ != *s2++)
+		      break;
+
+		  if (len)
+		    {
+		      hashval += step;
+		      if (hashval >= tsize)
+			hashval -= tsize;
+		    }
+		  else
+		    {
+		      res = ht[which]->table[hashval] - ht[which]->words;
+		      break;
+		    }
+		}
+	    }
+	  else
+	    res = COMPERROR;
+
+	  assert (stats[num].freq > 0);
+
+	  /* Check that the word was found in the dictionary */
+	  if (res == COMPERROR)
+	    {
+	      if (cdh.dict_type == MG_COMPLETE_DICTIONARY)
+		Message ("Unknown word \"%.*s\"\n", *Word, Word + 1);
+	      if ((cdh.dict_type == MG_PARTIAL_DICTIONARY ||
+		   cdh.dict_type == MG_SEED_DICTIONARY) &&
+		  ht[which])
+		{
+		  int k;
+		  res = ht[which]->hd->num_codes - 1;
+		  bits += ht[which]->hd->clens[res] * stats[num].freq;
+		  lens[Word[0]]++;
+		  for (k = 0; k < (int) Word[0]; k++)
+		    chars[Word[k + 1]]++;
+		}
+	      num++;
+	    }
+	  else
+	    {
+	      bits += ht[which]->hd->clens[res] * stats[num].freq;
+	    }
+	}
+
+      {
+	int j, num_buckets = 0;
+	int start[10], end[10];
+	long flens[16], fchars[256];
+
+	for (j = 0; j < 256; j++)
+	  if (!chars[j] && PESINAWORD (j) == which)
+	    fchars[j] = 1;
+	  else
+	    fchars[j] = chars[j];
+	for (j = 0; j < 16; j++)
+	  if (!lens[j])
+	    flens[j] = 1;
+	  else
+	    flens[j] = lens[j];
+
+	size[which] = Calculate_Huffman_Size (16, flens, lens) +
+	  Calculate_Huffman_Size (256, fchars, chars);
+
+
+	qsort (stats, num, sizeof (*stats), stats_comp);
+
+
+	if (mode == 'Y')
+	  {
+	    int k;
+	    num_buckets = 1;
+	    start[0] = 0;
+	    end[0] = cdh.num_words[which] - 1;
+	    Message ("There are %d novel %swords", num, which ? "" : "non-");
+	    while (end[num_buckets - 1] < num)
+	      {
+		start[num_buckets] = end[num_buckets - 1] + 1;
+		end[num_buckets] = start[num_buckets] +
+		  (end[num_buckets - 1] - start[num_buckets - 1]) * 2;
+		num_buckets++;
+	      }
+	    for (k = 0; k < num_buckets; k++)
+	      Message ("Bucket %d   %d <= x <= %d\n", k + 1, start[k], end[k]);
+	  }
+
+	for (j = 0; j < num; j++)
+	  {
+	    (*num_extra_bytes) += stats[j].len;
+	    switch (mode)
+	      {
+	      case 'D':
+		bits += BIO_Delta_Length (j + 1) * stats[j].freq;
+		break;
+	      case 'B':
+		bits += BIO_Binary_Length (j + 1, num) * stats[j].freq;
+		break;
+	      case 'Y':
+		{
+		  int k = 0;
+		  while (j > end[k])
+		    k++;
+		  if (!(j - start[k] + 1 >= 1 &&
+			j - start[k] + 1 <= end[k] - start[k] + 1))
+		    {
+		      Message ("k = %d, j = %d", k, j);
+		      assert (j - start[k] + 1 >= 1 &&
+			      j - start[k] + 1 <= end[k] - start[k] + 1);
+		    }
+		  else
+		    {
+		      bits += (BIO_Gamma_Length (k + 1) +
+			       BIO_Binary_Length (j - start[k] + 1,
+						  end[k] - start[k] + 1)) *
+			stats[j].freq;
+		    }
+		}
+	      }
+	  }
+	if (mode == 'B' && num)
+	  bits += BIO_Delta_Length (num) * csh.num_docs;
+      }
+      Xfree (stats);
+    }
+  fclose (f);
+
+  *aux_compressed = (size[0] + size[1]) / 8;
+
+  /*
+   * The 5.5 bits added on per document consist of
+   *   1 bit for the word/non-word flag at the start of the document.
+   *   1 bit on average for document termination.
+   *   3.5 bits on average for padding to a byte boundary.
+   */
+  bits += 5.5 * csh.num_docs;
+
+  bytes = bits / 8 + sizeof (compressed_text_header) + sizeof (u_long);
+
+  *num_bytes = csh.num_bytes;
+
+  return bytes;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_merge.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_merge.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_merge.1	(revision 10506)
@@ -0,0 +1,76 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_text_merge 1 \*(Dt CITRI
+.SH NAME
+mg_text_merge \- Append one compressed text file to another
+.SH SYNOPSIS
+.B mg_text_merge
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+This program takes two
+.BR mg (1)
+database inverted files and stemmed
+dictionaries, named "old" and "new" respectively, and creates
+a merged stemmed dictionary and inverted file.
+It is part of the
+.BR mgmerge (1)
+addition to the
+.BR mg (1)
+package.
+The two compressed text files are
+.IR "name" .old.text
+and
+.IR "name" .new.text.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.old.text
+The old compressed text.
+.TP
+.B *.new.text
+The new compressed text that will be appended
+.TP
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mgmerge (1),
+.BR mg_get_merge (1),
+.BR mg_invf_merge (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mgquery (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_merge.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_merge.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_text_merge.c	(revision 10506)
@@ -0,0 +1,249 @@
+/**************************************************************************
+ *
+ * mg_text_merge.c --- merge  *.text, *.text.idx files
+ *                     part of the mgmerge utility
+ * Copyright (C) 1995 Shane Hudson (shane@cosc.canterbury.ac.nz)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ * Last edited:  November 11 1994
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "messages.h"
+#include "timing.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "locallib.h"
+#include "mg.h"
+#include "mg_merge.h"
+#include "mg_files.h"
+#include "text.h"
+
+
+/**** GLOBALS ****/
+FILE *text[3], *idx[3];
+
+typedef char FileName[256];
+FileName old_name, new_name, merge_name;
+
+long magicsize;			/* == where the header in a file begins */
+
+compressed_text_header cth[3];
+
+/*=======================================================================
+ * init_merge_text(): open files, set up global variables, etc
+ *=======================================================================*/
+int 
+init_merge_text ()
+{
+
+  /* open .text files */
+  text[OLD] = open_file (old_name, TEXT_SUFFIX, "r+b",
+			 MAGIC_TEXT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  magicsize = ftell (text[OLD]);
+  fread (&cth[OLD], sizeof (cth[OLD]), 1, text[OLD]);
+
+  text[NEW] = open_file (new_name, TEXT_SUFFIX, "rb+",
+			 MAGIC_TEXT, MG_ABORT);
+  fread (&cth[NEW], sizeof (cth[NEW]), 1, text[NEW]);
+
+  /* open .text.idx files */
+  idx[OLD] = open_file (old_name, TEXT_IDX_SUFFIX, "rb+",
+			MAGIC_TEXI, MG_ABORT);
+  fread (&cth[OLD], sizeof (cth[OLD]), 1, idx[OLD]);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cth[OLD].num_of_docs);
+  NTOHD(cth[OLD].num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(cth[OLD].num_of_words);
+  NTOHUL(cth[OLD].length_of_longest_doc);
+  NTOHD(cth[OLD].ratio);
+
+  idx[NEW] = open_file (new_name, TEXT_IDX_SUFFIX, "rb+",
+			MAGIC_TEXI, MG_ABORT);
+  fread (&cth[NEW], sizeof (cth[NEW]), 1, idx[NEW]);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cth[NEW].num_of_docs);
+  NTOHD(cth[NEW].num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(cth[NEW].num_of_words);
+  NTOHUL(cth[NEW].length_of_longest_doc);
+  NTOHD(cth[NEW].ratio);
+
+  idx[MERGE] = create_file (merge_name, TEXT_IDX_SUFFIX, "wb",
+			    MAGIC_TEXI, MG_ABORT);
+  return OK;
+}
+
+
+/*=======================================================================
+ * process_merge_text(): merge the files
+ *=======================================================================*/
+int 
+process_merge_text (void)
+{
+  int i;
+  u_long data, offset;
+  byte c;
+
+  /* update and write merged header to .text and .text.idx files */
+  /* they have the exact same header */
+  cth[MERGE].num_of_docs = cth[OLD].num_of_docs
+    + cth[NEW].num_of_docs;
+  cth[MERGE].num_of_bytes = cth[OLD].num_of_bytes
+    + cth[NEW].num_of_bytes;
+  cth[MERGE].num_of_words = cth[OLD].num_of_words;
+  cth[MERGE].length_of_longest_doc =
+    (cth[OLD].length_of_longest_doc > cth[NEW].length_of_longest_doc
+     ? cth[OLD].length_of_longest_doc
+     : cth[NEW].length_of_longest_doc);
+  cth[MERGE].ratio = ((cth[OLD].num_of_bytes * cth[OLD].ratio) +
+		      (cth[NEW].num_of_bytes * cth[NEW].ratio))
+    / cth[MERGE].num_of_bytes;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(cth[MERGE].num_of_docs);
+  HTOND(cth[MERGE].num_of_bytes); /* [RJM 07/97: 4G limit] */
+  HTONUL(cth[MERGE].num_of_words);
+  HTONUL(cth[MERGE].length_of_longest_doc);
+  HTOND(cth[MERGE].ratio);
+
+  fwrite (&cth[MERGE], sizeof (cth[MERGE]), 1, idx[MERGE]);
+  fseek (text[OLD], magicsize, 0);
+  fwrite (&cth[MERGE], sizeof (cth[MERGE]), 1, text[OLD]);
+
+  /*
+   *  Update *.text.idx:  need to know where each new doc starts
+   *  in the appended .text file
+   */
+  for (i = 0; i < cth[OLD].num_of_docs; i++)
+    {
+      fread (&data, sizeof (u_long), 1, idx[OLD]);
+      fwrite (&data, sizeof (u_long), 1, idx[MERGE]);
+    }
+
+  /* offset is the amount to add to each entry from idx[NEW] */
+  fread (&offset, sizeof (u_long), 1, idx[OLD]);
+  NTOHUL(offset);  /* [RPAP - Jan 97: Endian Ordering] */
+  offset -= (4 + sizeof (cth[OLD]));	/* 4 for the magic number */
+
+  for (i = 0; i < cth[NEW].num_of_docs; i++)
+    {
+      fread (&data, sizeof (u_long), 1, idx[NEW]);
+      NTOHUL(data);  /* [RPAP - Jan 97: Endian Ordering] */
+      data += offset;
+      HTONUL(data);  /* [RPAP - Jan 97: Endian Ordering] */
+      fwrite (&data, sizeof (u_long), 1, idx[MERGE]);
+    }
+  /* write last u_long in idx[MERGE] (= length of file) */
+  fread (&data, sizeof (u_long), 1, idx[NEW]);
+  NTOHUL(data);  /* [RPAP - Jan 97: Endian Ordering] */
+  data += offset;
+  HTONUL(data);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&data, sizeof (u_long), 1, idx[MERGE]);
+
+/******* update .text *******/
+  /* simply cat's the files together, except for the headers 
+   * and magic numbers, of course
+   */
+  fseek (text[OLD], 0L, 2);
+  while (!feof (text[NEW]))
+    {
+      fread (&c, sizeof (c), 1, text[NEW]);
+      if (!feof (text[NEW]))
+	fwrite (&c, sizeof (c), 1, text[OLD]);
+    }
+
+  return OK;
+}
+
+
+
+/*=======================================================================
+ * done_merge_text(): close files.
+ *=======================================================================*/
+int 
+done_merge_text (void)
+{
+  fclose (idx[MERGE]);
+  fclose (text[OLD]);
+  fclose (idx[OLD]);
+  fclose (text[NEW]);
+  fclose (idx[NEW]);
+
+  fprintf (stderr, "mg_text_merge: %ld documents added to %s\n",
+	   cth[NEW].num_of_docs, merge_name);
+
+  return OK;
+}
+
+
+/*=======================================================================
+ * usage()
+ *=======================================================================*/
+void 
+usage (char *progname)
+{
+  fprintf (stderr, "usage:  %s -f collection_name\n", progname);
+  exit (1);
+}
+
+
+/*=======================================================================
+ * main()
+ *=======================================================================*/
+int main (int argc, char *argv[])
+{
+  char *progname;
+  ProgTime start;
+  int ch;			/* for command line processing */
+
+  progname = argv[0];
+  msg_prefix = argv[0];
+  merge_name[0] = '\0';
+
+  while ((ch = getopt (argc, argv, "f:d:h")) != -1)
+    switch (ch)
+      {
+      case 'f':
+	strcpy (merge_name, optarg);
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'h':
+      case '?':
+      default:
+	usage (progname);
+      }
+
+  if (merge_name[0] == '\0')
+    usage (progname);
+  strcpy (old_name, merge_name);
+  strcat (old_name, ".old");
+  strcpy (new_name, merge_name);
+  strcat (new_name, ".new");
+
+  GetTime (&start);
+  init_merge_text ();
+  process_merge_text ();
+  done_merge_text ();
+  Message ("%s\n", ElapsedTime (&start, NULL));
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_weights_build.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_weights_build.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_weights_build.1	(revision 10506)
@@ -0,0 +1,112 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mg_weights_build 1 \*(Dt CITRI
+.SH NAME
+mg_weights_build \- builds the approximate weights file
+.SH SYNOPSIS
+.B mg_weights_build
+[
+.B \-h
+]
+[
+.B \-s
+]
+[
+.BI \-b " num"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mg_weights_build
+is the program that generates the approximate weights file and the
+interleaved text index and exact weights file.  To do this, it uses
+the text index and either the exact weights file, or the inverted file
+and stemmed dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-s
+Save the weights generated from the
+.I *.invf
+and
+.I *.invf.dict
+file in a
+.I *.weight
+file.
+.TP
+.BI \-b " num"
+This specifies the number of bits of precision that should be used for
+the approximate weights.  If not specified, it defaults to 8.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_weights_build.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_weights_build.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mg_weights_build.c	(revision 10506)
@@ -0,0 +1,508 @@
+/**************************************************************************
+ *
+ * mg_weights_build.c -- Program to build the document weights file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_gen.h"
+#include "bitio_m.h"
+#include "bitio_m_stdio.h"
+#include "timing.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "invf.h"
+#include "text.h"
+#include "words.h"
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:16  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:49  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:22  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/29  00:32:05  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:57:00  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:55  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+unsigned char bits = 8;
+static char *file_name = "";
+static char *text_file_name = "";
+static unsigned long NumPara = 0;
+static unsigned long StaticNumOfDocs = 0;
+
+unsigned long get_NumPara (void);
+unsigned long get_StaticNumOfDocs (void);
+void GenerateWeights (void);
+void Make_weight_approx (void);
+void Make_text_idx_wgt (void);
+
+
+int main (int argc, char **argv)
+{
+  ProgTime StartTime;
+  int ch;
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "f:t:d:b:sh")) != -1) /* [RJM 10/98 - Text Filename] */
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	file_name = optarg;
+	if (strlen(text_file_name) == 0) text_file_name = optarg;
+	break;
+      /* [RJM 10/98 - Text Filename] */
+      case 't':		/* text input file */
+	text_file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'b':
+	bits = atoi (optarg);
+	if (bits > 32)
+	  {
+	    fprintf (stderr, "b may only take values 0-32\n");
+	    exit (1);
+	  }
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file]"
+		 "[-d data directory] [-b bits] [-s] [-h]\n", argv[0]);
+	exit (1);
+      }
+  GetTime (&StartTime);
+
+  GenerateWeights ();
+
+  Make_weight_approx ();
+
+  Make_text_idx_wgt ();
+
+  Message ("%s", ElapsedTime (&StartTime, NULL));
+
+  return 0;
+}
+
+
+
+
+unsigned long 
+get_NumPara (void)
+{
+  struct invf_dict_header idh;
+  FILE *invf_dict;
+  if (NumPara)
+    return (NumPara);
+  invf_dict = open_file (file_name, INVF_DICT_SUFFIX, "rb", MAGIC_STEM_BUILD,
+			 MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  fread ((char *) &idh, sizeof (idh), 1, invf_dict);
+  fclose (invf_dict);
+  NTOHUL2(idh.num_of_docs, NumPara);  /* [RPAP - Jan 97: Endian Ordering] */
+  return NumPara;
+}
+
+
+
+unsigned long 
+get_StaticNumOfDocs (void)
+/* the static number of documents is the N parameter used to
+ * decode document gaps in the inverted file encoded using
+ * the Bblock method.
+ */
+{
+  struct invf_dict_header idh;
+  FILE *invf_dict;
+  if (StaticNumOfDocs)
+    return (StaticNumOfDocs);
+  invf_dict = open_file (file_name, INVF_DICT_SUFFIX, "rb", MAGIC_STEM_BUILD,
+			 MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  fread ((char *) &idh, sizeof (idh), 1, invf_dict);
+  fclose (invf_dict);
+  NTOHUL2(idh.static_num_of_docs, StaticNumOfDocs);  /* [RPAP - Jan 97: Endian Ordering] */
+  return StaticNumOfDocs;
+}
+
+
+
+void GenerateWeights (void) {
+  FILE *dict, *invf, *f, *idx;
+  struct invf_dict_header idh;
+  struct invf_file_header ifh;
+  int i;
+  double logN;
+  float *DocWeights;
+
+  /* make sure the globals NumPara and StaticNumOfDocs are loaded */
+  get_NumPara ();
+  get_StaticNumOfDocs ();
+
+  /* check to see if the weights file has already been built */
+  if ((f = open_file (file_name, WEIGHTS_SUFFIX, "rb", MAGIC_WGHT,
+		      MG_CONTINUE)) != NULL) {
+      fclose (f);
+      return;
+  }
+  Message ("The file \"%s.weight\" does not exist.", file_name);
+  Message ("Building the weight data from the file \"%s.invf\".", file_name);
+
+  logN = log ((double) NumPara);
+
+  /* allocate memory for the weights */
+  if (!(DocWeights = Xmalloc (sizeof (float) * (NumPara + 1))))
+      FatalError (1, "No memory for doc weights");
+  bzero ((char *) DocWeights, sizeof (float) * (NumPara + 1));
+
+  /* open the .invf.dict file and read in its header */
+  dict = open_file (file_name, INVF_DICT_SUFFIX, "rb", MAGIC_STEM_BUILD,
+		    MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  fread ((char *) &idh, sizeof (idh), 1, dict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  /* open .invf.idx */
+  idx = open_file (file_name, INVF_IDX_SUFFIX, "rb", MAGIC_INVI,
+		   MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* open .invf and read in its header */
+  invf = open_file (file_name, INVF_SUFFIX, "rb", MAGIC_INVF,
+		    MG_ABORT);
+  fread ((char *) &ifh, sizeof (ifh), 1, invf);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(ifh.no_of_words);
+  NTOHUL(ifh.no_of_ptrs);
+  NTOHUL(ifh.skip_mode);
+  for (i = 0; i <= 15; i++)
+    NTOHUL(ifh.params[i]);
+  NTOHUL(ifh.InvfLevel);
+
+  /* make sure the inverted file does not contain skips and is not level 1 */
+  if (ifh.skip_mode != 0)
+    FatalError (0, "Can\'t make weights file from a skipped inverted file.");
+  if (ifh.InvfLevel == 1)
+    FatalError (0, "Can\'t make weights file from level 1 inverted file.");
+
+  DECODE_START (invf)
+
+    /* process each word adding its contributions to the document weights */
+    for (i = 0; i < ifh.no_of_words; i++)
+    {
+      u_char dummy1, dummy2[MAXSTEMLEN + 1];
+      unsigned long fcnt, wcnt, blk, CurrDoc, p, j;
+      float idf;
+
+      /* give a little feedback every 4096 words */
+      if ((i & 0xfff) == 0)
+	fprintf (stderr, ".");
+
+      /* read an entry for a word, just to get p value */
+      dummy1 = fgetc (dict);
+      dummy1 = fgetc (dict);
+      fread (dummy2, sizeof (u_char), dummy1, dict);
+      fread ((char *) &fcnt, sizeof (fcnt), 1, dict);
+      fread ((char *) &wcnt, sizeof (wcnt), 1, dict);
+
+      dummy2[dummy1] = '\0';
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      p = fcnt;
+
+      idf = logN - log ((double) fcnt);
+      blk = BIO_Bblock_Init (StaticNumOfDocs, p);
+      CurrDoc = 0;
+
+      /* check the inverted file index entry for this word */
+      {
+	unsigned long loc;
+	fread ((char *) &loc, sizeof (loc), 1, idx);
+	NTOHUL(loc);  /* [RPAP - Jan 97: Endian Ordering] */
+	if (ftell (invf) != loc)
+	  {
+	    FatalError (1, "Word %d  %d != %d", i, ftell (invf), loc);
+	  }
+      }
+
+      for (j = 0; j < p; j++)
+	{
+	  unsigned long x, tf;
+	  BBLOCK_DECODE (x, blk);
+	  CurrDoc += x;
+
+	  if (CurrDoc > idh.num_of_docs) {
+	    FatalError (1, "CurrDoc = %d, number of documents = %d", 
+			CurrDoc, idh.num_of_docs);
+	  }	  
+
+	  if (ifh.InvfLevel >= 2)
+	    {
+	      double weight;
+	      GAMMA_DECODE (tf);
+	      weight = tf * idf;
+	      DocWeights[CurrDoc - 1] += weight * weight;
+	    }
+	}
+      
+      while (__btg)
+	DECODE_BIT;
+    }
+
+  DECODE_DONE
+
+  fclose (dict);
+  fclose (invf);
+  fprintf (stderr, "\n");
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < NumPara; i++)
+    HTONF(DocWeights[i]);
+
+  f = create_file (file_name, WEIGHTS_SUFFIX, "wb", MAGIC_WGHT,
+		   MG_ABORT);
+
+  fwrite ((char *) DocWeights, sizeof (float), NumPara, f);
+  fclose (f);
+  Xfree (DocWeights);
+}
+
+
+
+
+
+
+
+
+
+
+
+void 
+Make_weight_approx (void)
+{
+  int i, pos, max;
+  unsigned long buf;
+  double U, L, B;
+  FILE *approx, *exact;
+
+  exact = open_file (file_name, WEIGHTS_SUFFIX, "rb", MAGIC_WGHT,
+		     MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* calculate U and L */
+  L = 1e300;
+  U = 0;
+  for (i = 0; i < NumPara; i++)
+    {
+      float wgt;
+      fread ((char *) &wgt, sizeof (wgt), 1, exact);
+      NTOHF(wgt);  /* [RPAP - Jan 97: Endian Ordering] */
+      wgt = sqrt (wgt);
+      if (wgt > U)
+	U = wgt;
+      if (wgt > 0 && wgt < L)
+	L = wgt;
+
+    }
+  fseek (exact, sizeof (u_long), SEEK_SET);
+
+  B = pow (U / L, pow (2.0, -(double) bits));
+
+  fprintf (stderr, "L = %f\n", L);
+  fprintf (stderr, "U = %f\n", U);
+  fprintf (stderr, "B = %f\n", B);
+
+
+
+  approx = create_file (file_name, APPROX_WEIGHTS_SUFFIX, "wb",
+			MAGIC_WGHT_APPROX, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fwrite ((char *) &bits, sizeof (bits), 1, approx);
+  HTOND(L);  /* [RPAP - Jan 97: Endian Ordering] */
+  HTOND(B);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite ((char *) &L, sizeof (L), 1, approx);
+  fwrite ((char *) &B, sizeof (B), 1, approx);
+  NTOHD(L);  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHD(B);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  max = bits == 32 ? 0xffffffff : (1 << bits) - 1;
+  for (buf = pos = i = 0; i < NumPara; i++)
+    {
+      unsigned long fx;
+      float wgt;
+      fread ((char *) &wgt, sizeof (wgt), 1, exact);
+      NTOHF(wgt);  /* [RPAP - Jan 97: Endian Ordering] */
+      wgt = sqrt (wgt);
+      if (wgt == 0)
+	{
+	  wgt = L;
+#ifndef QUIET
+	  Message ("Warning: Document %d had a weight of 0.", i);
+#endif
+	}
+      fx = (int) floor (log (wgt / L) / log (B));
+
+      if (fx > max)
+	fx = max;
+
+      buf |= (fx << pos);
+      pos += bits;
+
+      if (pos >= MAXBITS)
+	{
+	  HTONUL(buf);
+	  fwrite ((char *) &buf, sizeof (buf), 1, approx);
+	  buf = fx >> (bits - (pos - MAXBITS));
+	  pos = pos - MAXBITS;
+	}
+    }
+  if (pos > 0)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(buf);
+      fwrite ((char *) &buf, sizeof (buf), 1, approx);
+    }
+
+  fclose (approx);
+  fclose (exact);
+}
+
+
+
+
+
+void 
+Make_text_idx_wgt (void)
+{
+  compressed_text_header cth;
+  int i;
+  FILE *idx_wgt, *idx, *para, *exact;
+
+  idx_wgt = create_file (file_name, TEXT_IDX_WGT_SUFFIX, "wb", MAGIC_TEXI_WGT,
+			 MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  /* [RJM 10/98 - Text Filename] */
+  idx = open_file (text_file_name, TEXT_IDX_SUFFIX, "rb", MAGIC_TEXI,
+		   MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+  if (fread (&cth, sizeof (cth), 1, idx) != 1)
+    FatalError (1, "Unable to read header of index file");
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cth.num_of_docs);
+  NTOHD(cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(cth.num_of_words);
+  NTOHUL(cth.length_of_longest_doc);
+  NTOHD(cth.ratio);
+
+  exact = open_file (file_name, WEIGHTS_SUFFIX, "rb", MAGIC_WGHT,
+		     MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  get_NumPara ();
+  if (cth.num_of_docs != NumPara)
+    {
+      Message ("The number of documents does not equal "
+	       "the number of paragraphs.");
+      Message ("Using the \"%s.invf.paragraph\" file\n", file_name);
+      para = open_file (file_name, INVF_PARAGRAPH_SUFFIX, "rb", MAGIC_PARAGRAPH,
+			MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+    }
+  else
+    para = NULL;
+
+  {
+    struct
+      {
+	unsigned long Start;
+	float Weight;
+      }
+    data;
+    for (i = 0; i < cth.num_of_docs; i++)
+      {
+	int count;
+	fread ((char *) &data.Start, sizeof (unsigned long), 1, idx);
+	if (para && i < cth.num_of_docs)
+	  {
+	    /* [RPAP - Jan 97: Endian Ordering] */
+	    fread ((char *) &count, sizeof (count), 1, para);
+	    NTOHSI(count);
+	  }
+	else
+	  count = 1;
+	while (count--)
+	  {
+	    fread ((char *) &data.Weight, sizeof (float), 1, exact);
+	    NTOHF(data.Weight);  /* [RPAP - Jan 97: Endian Ordering] */
+	    data.Weight = sqrt (data.Weight);
+	    HTONF(data.Weight);  /* [RPAP - Jan 97: Endian Ordering] */
+	    fwrite ((char *) &data, sizeof (data), 1, idx_wgt);
+	  }
+      }
+    /* Write out the extra entry for the idx file */
+    fread ((char *) &data.Start, sizeof (unsigned long), 1, idx);
+    data.Weight = 0;
+    fwrite((char*)&data, sizeof(data), 1, idx_wgt);
+  }
+
+  fclose (idx_wgt);
+  fclose (idx);
+  fclose (exact);
+  if (para)
+    fclose (para);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgdictlist.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgdictlist.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgdictlist.1	(revision 10506)
@@ -0,0 +1,72 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgdictlist 1 \*(Dt CITRI
+.SH NAME
+mgdictlist \- list the contents of a dictionary
+.SH SYNOPSIS
+.B mgdictlist
+[
+.B \-q
+]
+.I filename
+.SH DESCRIPTION
+.B mgdictlist
+lists the contents of either a compressed compression dictionary, a
+text statistics file, or a compressed stemmed dictionary.  Unlike all
+the other programs in the
+.BR mg (1)
+suite, it is necessary to specify the complete pathname of the
+dictionary to list.
+.SH OPTIONS
+The
+.I filename
+must be last.
+.TP "\w'\fIfilename\fP'u+2n"
+.B \-q
+Generate an abbreviated output (machine-readable rather than
+human-readable).
+.TP
+.I filename
+This is the name of the dictionary to list.
+.B mgdictlist
+automatically detects whether the file is a compressed compression
+dictionary, text statistics file, or a compressed stemmed dictionary.
+.SH FILES
+.TP 20
+.B *.text.dict
+Text statistics file.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.invf.build
+Compressed stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgdictlist.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgdictlist.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgdictlist.c	(revision 10506)
@@ -0,0 +1,405 @@
+/**************************************************************************
+ *
+ * mgdictlist.c -- Program to list a dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "messages.h"
+#include "memlib.h"
+#include "local_strings.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "text.h"
+#include "invf.h"
+#include "locallib.h"
+#include "words.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:17  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:49  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:24  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/29  00:32:07  tes
+   * Committing the new merged files and changes.
+   *
+   * Revision 1.3  1994/10/20  03:57:01  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:56  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+int quick = 0;
+int no_of_words[2];
+u_long maxcodelen[2];
+
+char *dictname = "";
+
+
+
+
+void 
+DumpStemDict (FILE * f)
+{
+  struct invf_dict_header idh;
+  int i;
+  u_char prev[MAXSTEMLEN + 1];
+
+  fread (&idh, sizeof (idh), 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(idh.lookback);
+  NTOHUL(idh.dict_size);
+  NTOHUL(idh.total_bytes);
+  NTOHUL(idh.index_string_bytes);
+  NTOHD(idh.input_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(idh.num_of_docs);
+  NTOHUL(idh.static_num_of_docs);
+  NTOHUL(idh.num_of_words);
+  NTOHUL(idh.stemmer_num);
+  NTOHUL(idh.stem_method);
+
+  if (quick)
+    printf ("%ld\n", idh.dict_size);
+  else
+    {
+      printf ("# lookback           = %lu\n", idh.lookback);
+      printf ("# dict size          = %lu\n", idh.dict_size);
+      printf ("# total bytes        = %lu\n", idh.total_bytes);
+      printf ("# index string bytes = %lu\n", idh.index_string_bytes);
+      printf ("# input bytes        = %.0f\n", idh.input_bytes); /* [RJM 07/97: 4G limit] */
+      printf ("# num of docs        = %lu\n", idh.num_of_docs);
+      printf ("# static num of docs = %lu\n", idh.static_num_of_docs);
+      printf ("# num of words       = %lu\n", idh.num_of_words);
+      printf ("#\n");
+    }
+
+  for (i = 0; i < idh.dict_size; i++)
+    {
+      register unsigned long copy, suff;
+      unsigned long wcnt, fcnt;
+
+      /* build a new word on top of prev */
+      copy = getc (f);
+      suff = getc (f);
+      *prev = copy + suff;
+      fread (prev + copy + 1, sizeof (u_char), suff, f);
+
+      /* read other data, but no need to store it */
+      fread (&fcnt, sizeof (fcnt), 1, f);
+      fread (&wcnt, sizeof (wcnt), 1, f);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fcnt);
+      NTOHUL(wcnt);
+
+      if (!quick)
+	{
+	  printf ("%d: %8ld ", i, wcnt);
+	  printf ("/ %5ld ", fcnt);
+	  printf ("%2d %2ld\t\"", *prev, copy);
+	}
+      printf ("%s", word2str (prev));
+      if (quick)
+	printf (" %ld %ld\n", wcnt, fcnt);
+      else
+	{
+	  putchar ('"');
+	  putchar ('\n');
+	}
+    }
+}
+
+
+
+
+void 
+ReadInWords (FILE * f)
+{
+  comp_frags_header cfh;
+  u_long *codes;
+  u_char prev[MAXSTEMLEN + 1];
+  int i;
+
+  if (Read_cfh (f, &cfh, NULL, NULL) == -1)
+    FatalError (1, "Unable to read in the dictionary");
+
+  printf ("#\n");
+  printf ("#   max code len       = %u\n", cfh.hd.maxcodelen);
+  printf ("#   total bytes        = %lu\n", cfh.uncompressed_size);
+  printf ("#\n");
+
+  if (!(codes = Generate_Huffman_Codes (&cfh.hd, NULL)))
+    FatalError (1, "no memory for huffman codes\n");
+
+  for (i = 0; i < cfh.hd.num_codes; i++)
+    {
+      register int val, copy, j, k;
+      char code[33];
+      val = fgetc (f);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      fread (prev + copy + 1, sizeof (u_char), val, f);
+      *prev = val + copy;
+
+      for (k = 0, j = cfh.hd.clens[i] - 1; j >= 0; j--, k++)
+	code[k] = '0' + ((codes[i] >> j) & 1);
+      code[k] = '\0';
+
+      printf ("%d: %2d : %*s : \"%s\"\n", i, cfh.hd.clens[i],
+	      cfh.hd.maxcodelen, code, word2str (prev));
+    }
+  Xfree (codes);
+  Xfree (cfh.hd.clens);
+}
+
+
+void 
+ReadCharHuffman (FILE * f, char *title)
+{
+  int i;
+  huff_data hd;
+  u_long *codes;
+
+  if (Read_Huffman_Data (f, &hd, NULL, NULL) == -1)
+    FatalError (1, "Unable to read huffman data");
+
+  if (!(codes = Generate_Huffman_Codes (&hd, NULL)))
+    FatalError (1, "no memory for huffman codes\n");
+
+  printf ("#\n# %s\n#\n", title);
+  for (i = 0; i < hd.num_codes; i++)
+    if (hd.clens[i])
+      {
+	int j, k;
+	char code[33];
+	for (k = 0, j = hd.clens[i] - 1; j >= 0; j--, k++)
+	  code[k] = '0' + ((codes[i] >> j) & 1);
+	code[k] = '\0';
+	printf ("%2d : %*s : \"%s\"\n", hd.clens[i],
+		hd.maxcodelen, code, char2str (i));
+      }
+  Xfree (codes);
+  Xfree (hd.clens);
+}
+
+
+void 
+ReadLenHuffman (FILE * f, char *title)
+{
+  int i;
+  huff_data hd;
+  u_long *codes;
+
+  if (Read_Huffman_Data (f, &hd, NULL, NULL) == -1)
+    FatalError (1, "Unable to read huffman data");
+
+  if (!(codes = Generate_Huffman_Codes (&hd, NULL)))
+    FatalError (1, "no memory for huffman codes\n");
+
+  printf ("#\n# %s\n#\n", title);
+  for (i = 0; i < hd.num_codes; i++)
+    if (hd.clens[i])
+      {
+	int j, k;
+	char code[33];
+	for (k = 0, j = hd.clens[i] - 1; j >= 0; j--, k++)
+	  code[k] = '0' + ((codes[i] >> j) & 1);
+	code[k] = '\0';
+	printf ("%2d : %*s : %d\n", hd.clens[i],
+		hd.maxcodelen, code, i);
+      }
+  Xfree (codes);
+  Xfree (hd.clens);
+}
+
+
+
+
+
+void 
+DumpTextDict (FILE * f)
+{
+  struct compression_dict_header cdh;
+  int which;
+
+  if (Read_cdh (f, &cdh, NULL, NULL) == -1)
+    FatalError (1, "Unable to read dictionary header");
+  switch (cdh.dict_type)
+    {
+    case MG_COMPLETE_DICTIONARY:
+      printf ("# COMPLETE DICTIONARY\n");
+      break;
+    case MG_PARTIAL_DICTIONARY:
+      printf ("# PARTIAL DICTIONARY\n");
+      break;
+    case MG_SEED_DICTIONARY:
+      printf ("# SEED DICTIONARY\n");
+      break;
+    }
+  printf ("# num words          = %lu\n", cdh.num_words[1]);
+  printf ("# num word chars     = %lu\n", cdh.num_word_chars[1]);
+  printf ("# num non-words      = %lu\n", cdh.num_words[0]);
+  printf ("# num non-word chars = %lu\n", cdh.num_word_chars[0]);
+  printf ("# lookback           = %lu\n", cdh.lookback);
+
+  for (which = 0; which < 2; which++)
+    switch (cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  ReadInWords (f);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    ReadInWords (f);
+
+	  ReadCharHuffman (f, "Characters");
+	  ReadLenHuffman (f, "Lengths");
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    ReadInWords (f);
+
+	  ReadCharHuffman (f, "Characters");
+	  ReadLenHuffman (f, "Lengths");
+	}
+	break;
+      }
+}
+
+
+
+
+void 
+DumpStatsDict (FILE * f)
+{
+  int i;
+  compression_stats_header csh;
+
+  fread (&csh, sizeof (csh), 1, f);
+
+  for (i = 0; i < 2; i++)
+    {
+      int j;
+      frags_stats_header fsh;
+
+      fread (&fsh, sizeof (fsh), 1, f);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fsh.num_frags);
+      NTOHUL(fsh.mem_for_frags);
+
+      if (!quick)
+	printf ("#\n# num %9s      = %lu\n#\n", i ? "words" : "non-words",
+		fsh.num_frags);
+
+      for (j = 0; j < fsh.num_frags; j++)
+	{
+	  u_char Word[16];
+	  u_long freq, occur_num;
+
+	  fread (&freq, sizeof (freq), 1, f);
+	  fread (&occur_num, sizeof (occur_num), 1, f);
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  NTOHUL(freq);
+	  NTOHUL(occur_num);
+
+	  Word[0] = fgetc (f);
+	  fread (Word + 1, Word[0], 1, f);
+	  printf ("%d: %7ld : %7ld : \"%s\"\n", j, freq,
+		  occur_num, word2str (Word));
+	}
+    }
+}
+
+
+int main (int argc, char **argv)
+{
+  FILE *fp;
+  unsigned long magic = 0;
+
+  if (argc < 2)
+    FatalError (1, "A file name must be specified");
+  dictname = argv[1];
+  if (strcmp (dictname, "-q") == 0)
+    {
+      quick = 1;
+      if (argc < 3)
+	FatalError (1, "A file name must be specified");
+      dictname = argv[2];
+    }
+  if (!(fp = fopen (dictname, "rb")))  /* [RPAP - Feb 97: WIN32 Port] */
+    FatalError (1, "Unable to open \"%s\"", dictname);
+
+  fread (&magic, sizeof (magic), 1, fp);
+
+  NTOHUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  switch (magic)
+    {
+    case MAGIC_STEM_BUILD:
+      if (!quick)
+	printf ("# Contents of STEM file \"%s\"\n#\n", dictname);
+      DumpStemDict (fp);
+      break;
+    case MAGIC_DICT:
+      if (!quick)
+	printf ("# Contents of DICT file \"%s\"\n#\n", dictname);
+      DumpTextDict (fp);
+      break;
+    case MAGIC_STATS_DICT:
+      if (!quick)
+	printf ("# Contents of STATS file \"%s\"\n#\n", dictname);
+      DumpStatsDict (fp);
+      break;
+    default:
+      FatalError (1, "Bad magic number. \"%s\" cannot be dumped", dictname);
+    }
+  fclose (fp);
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgquery.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgquery.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgquery.1	(revision 10506)
@@ -0,0 +1,693 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgquery 1 \*(Dt CITRI
+.SH NAME
+mgquery \- query program for the mg system
+.SH SYNOPSIS
+.B mgquery
+[
+.B \-h
+]
+[
+.B \-D
+]
+[
+.BI \-f " name"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +9n
+[
+.I collection-name
+]
+.SH DESCRIPTION
+.B mgquery
+enables users to make Boolean or ranked queries from a data base
+generated by the
+.BR mg (1)
+system.  It accepts queries from
+.I stdin
+and sends the retrieved documents to
+.IR stdout .
+Information on the resource usage of
+.B mgquery
+as it processes queries can be obtained interactively.
+.SH OPTIONS
+Options may appear in any order, but the
+.IR collection-name ,
+if specified, must be last.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-D
+This option causes the entire text to be decompressed and sent to
+.IR stdout .
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection that will be
+used.  If a collection with the specified base
+.I name
+does not exist, an error message will be displayed and
+.B mgquery
+will exit.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.SH USAGE
+Prior to processing the command line arguments, the
+.B mgquery
+program attempts to read in a startup script called
+.IR ./.mgrc .
+If that fails, it attempts to read in the file
+.IR $HOME/.mgrc .
+The startup file can only contain commands\(emno queries are
+permitted in the
+.I .mgrc
+file.  Lines starting with \*(lq\fB#\fP\*(rq in the file are comments.
+The most common use for the
+.I .mgrc
+file is to personalise the initial values of the predefined parameters
+with
+.B .set
+commands.
+.LP
+The input to
+.B mgquery
+consists of a series of input lines.  The backslash
+character
+.RB (\*(lq \e \*(rq)
+is used at the end of lines to indicate
+that input continues on the next line.
+.LP
+Input lines on which the first character is a dot
+.RB (\*(lq . \*(rq)
+are commands to the
+.B mgquery
+program.  Input lines that do not start with a dot are queries.
+.LP
+A query consists of two parts.  One part is a Boolean or ranked query
+that identifies documents.  The second part is a post-processing
+pattern matching operation.  Any text between the first speech mark
+(\*(lq) and the last speech mark (\*(rq) is considered to be a
+post-processing pattern.
+.SH COMMANDS
+The
+.B mgquery
+program can accept the following commands.
+.TP 17
+.B .help
+Display several pages of help text.
+.TP
+.B .quit
+Quit the program.
+.TP
+.B .warranty
+Display the
+.BR mg (1)
+warranty.
+.TP
+.B .conditions
+Display the conditions of use and distribution of
+.BR mg (1).
+.TP
+.BI ".set " "name value"
+Set the parameter
+.I name
+to the specified
+.IR value .
+If the parameter is a Boolean
+.I value
+and the
+.I value
+is omitted, the parameter will be inverted (i.e., if it was
+.IR true ,
+then it will change to
+.IR false ;
+if it was
+.IR false ,
+then it will change to
+.IR true ).
+.TP
+.BI ".unset " name
+Delete the parameter
+.I name
+from the currently-defined parameters.
+.TP
+.B .reset
+Reset the parameters to the state that they had after the processing
+of the
+.B mgquery
+command line.
+.TP
+.B .display
+Display the values of all the currently-defined parameters.
+.TP
+.B .push
+Push the currently-defined parameters onto a stack.
+.TP
+.B .pop
+Pops a set of parameters off the stack, replacing the currently-defined
+ones.
+.TP
+.BI ".output " arg
+This is used to specify where to send the text of the documents.  Once
+the
+.B .output
+command is specified, all subsequent output will be sent to the place
+specified by
+.IR arg .
+If
+.I arg
+is not specified subsequent output will be directed to
+.IR stdout .
+.I Arg
+may be any of the following.
+.RS
+.TP 13
+.BI "> " filename
+Send output to the specified file.
+.TP
+.BI ">> " filename
+Append output to the specified file.
+.TP
+.BI "| " command
+Pipe the output to
+.IR command ,
+which is executed by
+.IR sh .
+.RE
+.TP
+.BI ".input " arg
+This is used to specify where input (queries and commands) comes
+from.  Once the
+.B .input
+command is specified all subsequent input will be come from the place
+specified by
+.IR arg .
+If
+.I arg
+is not specified subsequent input will come from
+.IR stdin .
+.RS
+.TP 13
+.BI "< " filename
+Get input from the specified file.
+.TP
+.BI "| " command
+The input comes from the standard output of
+.IR command ,
+which is executed by
+.IR sh .
+.RE
+.SH PARAMETERS
+The following parameters are predefined and have special
+significance.  Each parameter will be followed by its default
+value.  Parameters are initialised before the
+.I .mgrc
+file is read or the command line arguments are processed.
+.TP 17
+.BI accumulator_method " `array'"
+This parameter is used during ranking, and specifies how the
+weight for each document should be accumulated.  The following
+methods are available:
+.IR array ,
+.IR splay_tree ,
+.IR hash_table ,
+and
+.IR list .
+.TP
+.BI briefstats " `off'"
+This is a Boolean parameter that determines whether the
+totals for disk, memory and time usage statistics will be
+displayed at the end of each query.
+.IR Note :
+this takes precedence over the parameters
+.BR diskstats ,
+.BR memstats " and " timestats .
+This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI buffer " `1048576'"
+When the documents are being read in, they are read into a
+buffer of this size and then displayed from this buffer.  If
+the documents are larger than this buffer, the buffer is
+expanded automatically.  Having a large buffer gives a very
+slight performance improvement, because it allows the order of
+disk operations to be optimised.  The buffer size is measured
+in bytes.
+.TP
+.BI diskstats " `off'"
+This is a Boolean parameter that determines whether the disk
+usage statistics for the preceding query will be displayed
+after each query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI doc_sepstr " `---------------------------------- %n\en\'"
+This specifies the string that will be used to separate
+documents when they are displayed for `Boolean' or `docnums'
+queries.  The standard C escape character sequences
+may be used to place special characters in the
+string.  For example, a newline would be `\en'.  To include a `%',
+use the sequence `%%'.  To include the
+.BR mg (1)
+document number, use the sequence `%n'.  The following escape character
+sequences are available
+.nf
+.ta 1.7iL
+.B Sequence	Meaning
+`\e\e'	backslash
+`\eb'	backspace
+`\ef'	formfeed
+`\en'	newline
+`\er'	carriage return
+`\et'	tab
+`\e"'	speech marks
+`\e''	quote mark
+`\ex\fIhh\fP'	ASCII code in hexadecimal
+`\ennn'	ASCII code in octal
+.fi
+.TP
+.BI expert " `false'"
+If this is
+.IR true ,
+then much of the dialogue output is suppressed.  This parameter may
+take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI hash_tbl_size " `1000'"
+One of the options during ranking queries is to use a hash
+table to accumulate the weights for each document.  The hash
+table is a simple chained type.  This parameter specifies the
+size of the hash table and may take any value between 8 and
+268435456 (2^28).
+.TP
+.BI heads_length " `50'"
+When the mode is
+.BR heads ,
+this specifies the number of characters that will be output for each
+document.
+.TP
+.BI maxdocs " `all'"
+The maximum number of documents to display in response to a
+query.  This parameter may take on a numeric value between 1
+and 429467295 (2^32 - 1) or the word
+.IR all .
+.TP
+.BI maxparas " `1000'"
+The maximum number of paragraphs to identify during a ranked
+query with paragraph indexing.  After the paragraphs have been
+identified, the paragraphs are converted into documents, and
+because some of the paragraphs may refer to the same documents
+the final number of answers may be less than
+.BR maxparas .
+The
+.B maxdocs
+parameter will then be applied.  This parameter may take on a numeric
+value between 1 and 429467295 (2^32 - 1).
+.TP
+.BI max_accumulators " `50000'"
+This parameter limits the number of different paragraph and
+document numbers to be accumulated during ranked queries when
+the parameter
+.B accumulator_method
+is set to
+.IR splay_tree ,
+.IR hash_table ,
+or
+.IR list .
+This parameter may take any value between 8 and 268435456 (2^28).
+.TP
+.BI max_terms " `all'"
+This parameter limits the number of terms that will actually
+be used during a ranked query.  If more terms than the number
+specified by
+.B max_terms
+are entered, then the extra terms will be discarded.  If
+.B sorted_terms
+is on, then the limiting will be done after the terms have been
+sorted.  This parameter may take any value between 1 and 429467295
+(2^32 - 1), or the word
+.IR all.
+.TP
+.BI memstats " `off'"
+This is a Boolean parameter that determines whether the memory
+usage statistics for the preceding query will be displayed
+after each query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI mgdir " `.'"
+This is set to the directory where the
+.BR mg (1)
+data files may be found.  If
+the environment variable
+.B MGDATA
+exists, then this is instead initialised to the value of
+.BR MGDATA .
+The value of this parameter may be changed, either in the
+.I .mgrc
+file with a
+.BI ".set mgdir "directory
+command, or from the command line using the
+.BI \-d " directory"
+option.  Once the \*(lq\fB>\fP\*(rq prompt appears, changing this
+parameter will have no effect.
+.TP
+.BI mgname " `bible'"
+This is set to the name of the
+.BR mg (1)
+collection that is to be used for the session.  The value of this
+parameter may be changed, either in the
+.I .mgrc
+file with a
+.BI ".set mgname "name
+command, or from the command line using the
+.BI \-f " name"
+option.  Once the \*(lq\fB>\fP\*(rq prompt appears, changing this
+parameter will have no effect.
+.TP
+.BI mode " `text'"
+This specifies how documents should be displayed when they
+are retrieved.  It may take six different values:
+.IR text ,
+.IR hilite ,
+.IR docnums ,
+.IR heads ,
+.IR silent ,
+or
+.IR count .
+.I text
+displays the contents of the document.
+.I hilite
+displays the contents of the document and highlights any of the 
+stemmed query terms.
+.I docnums
+displays only the document numbers.
+.I heads
+is used to print out the head of each document.
+.I silent
+retrieves all the documents but displays nothing except how many
+documents were retrieved.  This mode is intended to be used in timing
+experiments.
+.I count
+does the minimum
+amount of work required to determine how many documents would
+be retrieved, but does not retrieve them.
+.TP
+.BI optimise_type " `1'"
+There are three types of boolean query optimisation (parse tree
+rearrangement). Type 0 leaves parse tree unaltered. Type 1 optimises
+for AND of terms and AND of OR of terms. Type 2 converts the tree
+into DNF (an experiment :-).
+.TP
+.BI pager " `more'"
+This is the name of the program that will be used to display
+the help and the retrieved documents.  If the environment
+variable
+.B PAGER
+is defined, then
+.B pager
+takes on that value.
+.TP
+.BI hilite_style " `bold'"
+This specifies the type of highlighting method.
+It may take one of two different values:
+.IR bold,
+or
+.IR underline.
+.TP
+.BI para_sepstr " `\en######## PARAGRAPH %n ########\en'"
+This specifies the string that will be used to separate paragraphs.
+The standard C escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written
+as `\en'.  To include a `%', use the sequence `%%'.  To include the
+paragraph number within the document, use the sequence `%n'.
+.TP
+.BI para_start " `***** Weight = %w *****\en'"
+This specifies the string that will be used at the head of paragraphs
+for a paragraph-level index following a ranked query.  The standard
+C-language escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written as
+`\en'.  To include a `%', use the sequence `%%'.  To include the
+paragraph weight, use the sequence `%w'.
+.TP
+.BI qfreq " `true'"
+This determine whether the ranked queries will take into account the
+number of times each query term is specified.  When this is
+.IR true ,
+the number of times a term appears in the query is used in the
+ranking.  When this is
+.IR false ,
+all query terms are assumed to occur only once.  This parameter may
+take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI query  " `Boolean'"
+This specifies the type of queries that are to be specified.
+It can take four different values:
+.IR Boolean ,
+.IR ranked ,
+.IR docnums " or " approx-ranked.
+.I Boolean
+is for Boolean queries.
+The
+.BR yacc (1)
+grammar for Boolean queries is as follows.
+.IP
+.nf
+        query   : or;
+.IP
+        or      : or '|' and
+                | and ;
+.IP
+        and     : and '&' not
+                | and not
+                | not ;
+.IP
+        not     : term
+                | '!' not ;
+.IP
+        term    : TERM
+                | '(' or ')' ;
+.fi
+.IP
+.IR ranked " and " approx-ranked
+are for queries ranked by the cosine measure.
+.I approx-ranked
+uses only the low-precision document lengths, and therefore only
+produces an approximation to full cosine ranking.
+.IP
+.nf
+        query   : TERM
+                | query TERM ;
+.fi
+.IP
+.I docnums
+allows the entry of document numbers.  Multiple numbers separated by
+spaces may be specified, or ranges separated by hyphens.
+.IP
+.nf
+        query   : range
+                | query range ;
+.IP
+        range   : num
+                | num '-' num ;
+.fi
+.TP
+.BI ranked_doc_sepstr " `-------------------------------- %n %w\en'"
+This specifies the string that will be used to separate documents when
+they are displayed for `ranked' or `approx-ranked' queries.  The
+standard C escape character sequences may be used to place special
+characters in the string.  For example, a newline would be written as
+`\en'.  To include a `%', use the sequence `%%'.  To include the
+.BR mg (1)
+document number, use the sequence `%n'.  To include the document
+weight, use the sequence `%w'.
+.TP
+.BI sizestats " `false'"
+If this is
+.IR true ,
+then various numbers are output at the end of each query indicating
+what went on during the query.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI skip_dump " `skips.%d'"
+If this parameter is set, then a file will be produced in the current
+directory during ranked queries on skipped inverted files when
+.B accumulator_method
+is set to
+.IR splay_tree ,
+.IR hash_table ,
+or
+.IR list .
+The name of the file is the value of this parameter.  A `%d' in the
+file name will be replaced with the process id of
+.BR mgquery .
+This file will contain information about the usage of skips during the
+query processing.  This option is expensive; use
+.B .unset skip_dump
+to obtain optimal performance.
+.TP
+.BI sorted_terms " `on'"
+This specifies whether or not the terms should be sorted into
+decreasing occurrence in documents so that the least-often occurring
+terms are processed first when ranked queries are being done.  When
+this is
+.IR true ,
+the terms are sorted.  When this is
+.IR false ,
+the terms are not sorted, and are instead processed in order of
+occurrence.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI stop_at_max_accum " `on'"
+This specifies what should happen when the maximum number of
+accumulators set by
+.B max_accumulators
+is reached.  When this is
+.IR true ,
+the processing of terms is stopped at the completion of the current
+term.  When this is
+.IR false ,
+processing continues but no new accumulators are created.  This
+parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI terminator " `'"
+This specifies the string that will be output after the last document
+from the previous query has been output.  The standard C escape
+character sequences may be used to place special characters in the
+string.  For example, a newline would be written as `\en'.  To include
+a `%', use the sequence `%%'.
+.TP
+.BI timestats " `false'"
+If this is
+.IR true ,
+then the time to process a query is displayed in both real time and
+CPU time.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.TP
+.BI verbatim " `off'"
+This is a Boolean parameter that determines whether the program
+should attempt to do a regular-expression match on the retrieved
+text.  If verbatim is
+.I on
+and a post-processing string is specified with the query, then the
+post-processing string will be searched for in the documents just
+before they are displayed.  If the string is found, the document will
+be displayed; if not, the document will not be displayed.  If verbatim
+is
+.IR off ,
+the post-processing string will be considered a regular expression
+as in
+.BR egrep (1)
+or
+.BR vi (1).
+E.g., if verbatim is
+.I on,
+\*(lq\fBand.*the\fP\*(rq will look for the 8-character sequence
+\*(lq\fBand.*the\fP\*(rq.  If verbatim is
+.IR off ,
+\*(lq\fBand.*the\fP\*(rq will look for the sequence
+\*(lq\fBand\fP\*(rq followed somewhere later in the document by the
+sequence \*(lq\fBthe\fP\*(rq.  This parameter may take the values
+.IR yes ", " no ", "
+.IR true ", " false ", "
+.IR on " or " off .
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.I .mgrc
+.B mgquery
+startup file
+.TP
+.B help.mg
+Help file for
+.BR mgquery .
+The contents of this file is displayed with the
+.B .help
+command.
+.TP
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+The `on-disk' stemmed dictionary.
+.TP
+.B *.text
+Compressed documents.
+.TP
+.B *.text.dict
+Compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR egrep (1),
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgstat (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1),
+.BR vi (1),
+.BR yacc (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgquery.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgquery.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgquery.c	(revision 10506)
@@ -0,0 +1,1495 @@
+/**************************************************************************
+ *
+ * mgquery.c -- The   M G Q U E R Y   program
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:18  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1999/01/08 00:33:46  rjmcnab
+
+   Enabled mg and the library software to read in more than one index
+   at a time.
+
+   Revision 1.2  1998/11/25 07:55:49  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:29  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:02  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:41:58  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#if defined(HAVE_SYS_PROCFS_H) && defined(HAVE_PR_BRKSIZE) && \
+    (__STDC__ == 0)
+/* STDC test was included to allow cc -Xc on SunOS 5 to work */
+#define USE_PROCESS_MEM
+#endif
+
+#ifdef USE_PROCESS_MEM
+# include <sys/procfs.h>
+#endif
+
+#ifdef HAVE_GETRUSAGE
+# ifdef HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# endif
+# include <sys/resource.h>
+#endif
+
+#ifndef HAVE_GETPAGESIZE
+# include "getpagesize.h"
+#endif
+ 
+#if WITH_REGEX
+# include <regex.h>
+#else
+# include <rx.h>
+#endif
+
+
+#include <stdarg.h>
+#include <signal.h>
+
+#include "messages.h"
+#include "timing.h"
+#include "memlib.h"
+#include "local_strings.h"  /* [RPAP - Feb 97: Term Frequency] */
+
+#include "filestats.h"
+#include "invf.h"
+#include "text.h"
+#include "mg.h"
+#include "lists.h"
+#include "backend.h"
+#include "environment.h"
+#include "globals.h"
+#include "read_line.h"
+#include "mg_errors.h"
+#include "commands.h"
+#include "text_get.h"
+#include "term_lists.h"
+#include "query_term_list.h"
+
+
+FILE *OutFile = NULL, *InFile = NULL;
+int OutPipe = 0, InPipe = 0;
+int Quitting = 0;
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) ||  defined(NZDL)
+int GetDocNumFromParaNum(query_data *qd, int paranum) {
+  int Documents = qd->td->cth.num_of_docs;
+  int *Paragraph = qd->paragraph;
+  int low = 1, high = Documents;
+  int mid = (low+high)/2;
+
+  while ((mid = (low+high)/2) >=1 && mid <= Documents)
+    {
+      if (paranum > Paragraph[mid])
+	low = mid+1;
+      else if (paranum <= Paragraph[mid-1])
+	high = mid-1;
+      else
+	return mid;
+    }
+  FatalError(1, "Bad paragraph number.\n");
+}
+#endif
+
+#ifdef TREC_MODE
+char *trec_ids = NULL;
+long *trec_paras = NULL;
+#endif
+
+static volatile int PagerRunning = 0;
+static volatile int Ctrl_C = 0;
+
+
+/*****************************************************************************/
+
+typedef enum
+  {
+    S_Time, S_Mem, S_Size, S_File
+  }
+S_Type;
+
+static struct Stat
+  {
+    S_Type typ;
+    char *name;
+    char *text;
+  }
+ *Stats = NULL;
+static int NumStats = 0;
+
+static void 
+Clear_Stats (void)
+{
+  if (Stats)
+    {
+      int i;
+      for (i = 0; i < NumStats; i++)
+	{
+	  if (Stats[i].name)
+	    Xfree (Stats[i].name);
+	  if (Stats[i].text)
+	    Xfree (Stats[i].text);
+	}
+      Xfree (Stats);
+      Stats = NULL;
+      NumStats = 0;
+    }
+}
+
+static void 
+Add_Stats (S_Type typ, char *name, char *fmt,...)
+{
+  char buf[1024];
+  va_list args;
+  va_start (args, fmt);
+  vsprintf (buf, fmt, args);
+  if (Stats)
+    Stats = Xrealloc (Stats, (++NumStats) * sizeof (*Stats));
+  else
+    Stats = Xmalloc ((++NumStats) * sizeof (*Stats));
+  Stats[NumStats - 1].typ = typ;
+  Stats[NumStats - 1].name = Xstrdup (name);
+  Stats[NumStats - 1].text = Xstrdup (buf);
+}
+
+static void 
+Display_Stats (FILE * f)
+{
+  static char *sep = "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
+  "-=-=-=-=-=-=-=-=-=-=-";
+  char *names[] =
+  {"Time:  ", "Memory:", "Sizes: ", "Disk:  ", "       "};
+  int i, last_typ = -1;
+  size_t len = 0;
+  if (NumStats == 0)
+    return;
+  fprintf (f, "%s\n", sep);
+  for (i = 0; i < NumStats; i++)
+    if (strlen (Stats[i].name) > len)
+      len = strlen (Stats[i].name);
+  for (i = 0; i < NumStats; i++)
+    {
+      int typ = 4;
+      if (Stats[i].typ != last_typ)
+	typ = last_typ = Stats[i].typ;
+      fprintf (f, "%s %-*s %s\n", names[typ], (int) len, Stats[i].name, Stats[i].text);
+    }
+  fprintf (f, "%s\n", sep);
+}
+
+/*****************************************************************************/
+
+
+static void 
+QueryTimeStats (ProgTime * Start, ProgTime * invf, ProgTime * text)
+{
+  if (!BooleanEnv (GetEnv ("briefstats"), 0))
+    {
+      Add_Stats (S_Time, "invf", ElapsedTime (Start, invf));
+      Add_Stats (S_Time, "text", ElapsedTime (invf, text));
+    }
+  Add_Stats (S_Time, "total", ElapsedTime (Start, text));
+}
+
+static void 
+StartUpTimeStats (InitQueryTimes * iqt)
+{
+  if (!BooleanEnv (GetEnv ("briefstats"), 0))
+    {
+      Add_Stats (S_Time, "dict [stem]", ElapsedTime (&iqt->Start,
+						     &iqt->StemDict));
+      Add_Stats (S_Time, "weights", ElapsedTime (&iqt->StemDict,
+						 &iqt->ApproxWeights));
+      Add_Stats (S_Time, "dict [text]", ElapsedTime (&iqt->ApproxWeights,
+						     &iqt->CompDict));
+      Add_Stats (S_Time, "Inverted", ElapsedTime (&iqt->CompDict,
+						  &iqt->Invf));
+      Add_Stats (S_Time, "Compressed", ElapsedTime (&iqt->Invf,
+						    &iqt->Text));
+    }
+  Add_Stats (S_Time, "total", ElapsedTime (&iqt->Start, &iqt->Text));
+}
+
+
+
+
+#ifdef USE_PROCESS_MEM
+static u_long 
+process_mem (void)
+{
+  prstatus_t pr;
+  static int fd = -1;
+  if (fd == -1)
+    {
+      char buf[128];
+      sprintf (buf, "/proc/%ld", (long) getpid ());
+      fd = open (buf, O_RDONLY);
+    }
+  if (fd == -1 || ioctl (fd, PIOCSTATUS, &pr) == -1)
+    return 0;
+  return pr.pr_brksize;
+}
+#endif
+
+
+
+
+static void 
+MemStats (query_data * qd)
+{
+  if (!BooleanEnv (GetEnv ("briefstats"), 0))
+    {
+#ifdef HAVE_GETRUSAGE
+      struct rusage rusage;
+      getrusage (RUSAGE_SELF, &rusage);
+
+      Add_Stats (S_Mem, "process mem", "%7.3f Mb",
+	    (double) (rusage.ru_maxrss * getpagesize () / 1024.0 / 1024.0));
+#endif
+#ifdef USE_PROCESS_MEM
+      Add_Stats (S_Mem, "process mem", "%7.3f Mb",
+		 (double) (process_mem () / 1024.0 / 1024.0));
+#endif
+      Add_Stats (S_Mem, "dict [stem]", "%7.1f kB",
+		 (double) qd->sd->MemForStemDict / 1024);
+      Add_Stats (S_Mem, "dict [text]", "%7.1f kB",
+		 (double) qd->cd->MemForCompDict / 1024);
+      if (qd->awd)
+	Add_Stats (S_Mem, "weights", "%7.1f kB",
+		   (double) qd->awd->MemForWeights / 1024);
+    }
+  if (qd->awd)
+    Add_Stats (S_Mem, "total [peak]", "%7.1f kB",
+	       (double) (qd->max_mem_in_use + qd->sd->MemForStemDict +
+		   qd->cd->MemForCompDict + qd->awd->MemForWeights) / 1024);
+  else
+    Add_Stats (S_Mem, "total [peak]", "%7.1f kB",
+	       (double) (qd->max_mem_in_use + qd->sd->MemForStemDict +
+			 qd->cd->MemForCompDict) / 1024);
+
+}
+
+
+
+static void 
+SizeStats (query_data * qd)
+{
+  Add_Stats (S_Size, "skips", "%7d", qd->hops_taken);
+  Add_Stats (S_Size, "pointers", "%7d", qd->num_of_ptrs);
+  Add_Stats (S_Size, "accumulators", "%7d", qd->num_of_accum);
+  Add_Stats (S_Size, "terms", "%7d", qd->num_of_terms);
+  Add_Stats (S_Size, "answers", "%7d", qd->num_of_ans);
+  Add_Stats (S_Size, "index lookups", "%7d", qd->text_idx_lookups);
+}
+
+static void 
+TotalSizeStats (query_data * qd)
+{
+  Add_Stats (S_Size, "skips", "%7d", qd->tot_hops_taken);
+  Add_Stats (S_Size, "pointers", "%7d", qd->tot_num_of_ptrs);
+  Add_Stats (S_Size, "accumulators", "%7d", qd->tot_num_of_accum);
+  Add_Stats (S_Size, "terms", "%7d", qd->tot_num_of_terms);
+  Add_Stats (S_Size, "answers", "%7d", qd->tot_num_of_ans);
+  Add_Stats (S_Size, "index lookups", "%7d", qd->tot_text_idx_lookups);
+}
+
+
+static void 
+StatFile (File * F)
+{
+  static unsigned long NumBytes = 0, NumSeeks = 0, NumReads = 0;
+  if (F)
+    if ((int) F != -1)
+      {
+	if (!BooleanEnv (GetEnv ("briefstats"), 0))
+	  Add_Stats (S_File, F->name, "%7.1f kB (%3d seeks, %7d reads)",
+		   (double) F->Current.NumBytes / 1024, F->Current.NumSeeks,
+		     F->Current.NumReads);
+	NumBytes += F->Current.NumBytes;
+	NumSeeks += F->Current.NumSeeks;
+	NumReads += F->Current.NumReads;
+      }
+    else
+      {
+	Add_Stats (S_File, "total", "%7.1f kB (%3d seeks, %7d reads)",
+		   (double) NumBytes / 1024, NumSeeks, NumReads);
+	NumSeeks = NumReads = NumBytes = 0;
+      }
+
+}
+
+
+static void 
+File_Stats (query_data * qd)
+{
+  StatFile (qd->File_comp_dict);
+  StatFile (qd->File_fast_comp_dict);
+  StatFile (qd->File_text_idx_wgt);
+  StatFile (qd->File_text);
+  StatFile (qd->File_stem);
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (qd->sd->sdh.indexed)
+    {
+      StatFile (qd->File_stem1);
+      StatFile (qd->File_stem2);
+      StatFile (qd->File_stem3);
+    }
+
+  StatFile (qd->File_invf);
+  StatFile (qd->File_weight_approx);
+  StatFile (qd->File_text_idx);
+  StatFile ((File *) (-1));
+}
+
+
+char *
+get_query (query_data * qd)
+{
+  char *line, *LinePtr;
+  WritePrompt ();
+  do
+    {
+      do
+	{
+	  line = GetMultiLine ();
+	  if (line == NULL)
+	    {
+	      if (stdin == InFile)
+		return (NULL);	/* EOF */
+	      if (InPipe)
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+		_pclose (InFile);
+#else
+		pclose (InFile);
+#endif
+	      else
+		fclose (InFile);
+	      InPipe = 0;
+	      InFile = stdin;
+	    }
+	}
+      while (line == NULL);
+      LinePtr = ProcessCommands (line, qd);
+      if (CommandsErrorStr)
+	fprintf (stderr, "%s\n", CommandsErrorStr);
+    }
+  while (*LinePtr == '\0' && !Quitting);
+  return (LinePtr);
+}
+
+
+/* This is executed when a SIGPIPE is detected
+   i.e. If some one quits out of the PAGER, this is executed */
+#ifdef HAVE_SIGCONTEXT
+static RETSIGTYPE 
+SIGPIPE_handler (int sig, int code,
+		 struct sigcontext *scp, char *addr)
+#else
+static RETSIGTYPE 
+SIGPIPE_handler (int sig)
+#endif
+{
+  /* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  signal (sig, SIG_IGN);
+#else
+  signal (SIGPIPE, SIG_IGN);
+#endif
+  PagerRunning = 0;
+}
+
+/* This is executed when a SIGINT (i.e. CTRL-C) is detected */
+#ifdef  HAVE_SIGCONTEXT
+static RETSIGTYPE 
+SIGINT_handler (int sig, int code,
+		struct sigcontext *scp, char *addr)
+#else
+static RETSIGTYPE 
+SIGINT_handler (int sig)
+#endif
+{
+  Ctrl_C = 1;
+}
+
+
+
+static char *post_proc = NULL;
+
+
+
+void 
+GetPostProc (char *line)
+{
+  char *start, *finish;
+  if (post_proc)
+    {
+      Xfree (post_proc);
+      post_proc = NULL;
+    }
+  start = strchr (line, '\"');
+  finish = strrchr (line, '\"');
+  if (start != finish)
+    {
+      /* found a pattern */
+      *finish = '\0';
+      post_proc = Xstrdup (start + 1);
+      strcpy (start, finish + 1);
+      if (BooleanEnv (GetEnv ("verbatim"), 1) == 0)
+	{
+	  char *s;
+	  s = re_comp (post_proc);
+	  if (!s)
+	    {
+	      Xfree (post_proc);
+	      post_proc = NULL;
+	    }
+	}
+    }
+  else if (start != NULL)
+    {
+      /* found a single speech mark. Delete It. */
+      strcpy (start, start + 1);
+    }
+}
+
+int 
+PostProc (char *UDoc, int verbatim)
+{
+  if (!post_proc)
+    return 1;
+
+  if (verbatim) {
+    return (strstr (UDoc, post_proc) != NULL);
+  }
+  return re_exec ((char *) UDoc);
+}
+
+
+
+static DocEntry *
+in_chain (int para, int ip, DocEntry * dc)
+{
+  while (dc)
+    {
+      if (dc->DocNum - ip == para)
+	return dc;
+      dc = dc->Next;
+    }
+  return NULL;
+}
+
+/* num should be greater than or equal to 1 */
+int 
+RawDocOutput (query_data * qd, u_long num, FILE * Output)
+{
+  static last_pos = 0;
+  static u_char *c_buffer = 0;
+  static int buf_len = -1;
+  static u_char *uc_buffer = 0;
+  u_long pos, len;
+  int ULen;
+
+  FetchDocStart (qd, num, &pos, &len);
+
+  if ((int) len > buf_len)
+    {
+      if (c_buffer)
+	{
+	  Xfree (c_buffer);
+	  Xfree (uc_buffer);
+	}
+      if (!(c_buffer = Xmalloc (len)))
+	return -1;
+      if (!(uc_buffer = Xmalloc ((int) (qd->td->cth.ratio * 1.01 *
+					len) + 100)))
+	return -1;
+      buf_len = len;
+    }
+  if (last_pos != pos)
+    Fseek (qd->td->TextFile, pos, 0);
+  Fread (c_buffer, 1, len, qd->td->TextFile);
+  last_pos = pos + len;
+  DecodeText (qd->cd, c_buffer, len, uc_buffer, &ULen);
+  fwrite (uc_buffer, ULen, sizeof (u_char), Output);
+  return 0;
+}
+
+
+void 
+StringOut (FILE * Output, char *string,
+	   int intvalid, unsigned long intval,
+	   int floatvalid, double floatval)
+{
+  char *s;
+  for (s = string; *s; s++)
+    if (*s == '%' &&
+	(*(s + 1) == 'n' || *(s + 1) == 'w' || *(s + 1) == '%'))
+      {
+	s++;
+	switch (*s)
+	  {
+	  case 'n':
+	    if (intvalid)
+	      fprintf (Output, "%lu", intval);
+	    else
+	      fprintf (Output, "%%n");
+	    break;
+	  case 'w':
+	    if (floatvalid)
+	      fprintf (Output, "%f", floatval);
+	    else
+	      fprintf (Output, "%%w");
+	    break;
+	  case '%':
+	    fputc ('%', Output);
+	  }
+      }
+    else
+      fputc (*s, Output);
+}
+
+
+void 
+HeaderOut (FILE * Output, u_char * UDoc, unsigned long ULen, int heads_length)
+{
+  int i, space = 1, num = 0;
+  for (i = 0; i < ULen && num < heads_length; i++)
+    {
+      char c = UDoc[i];
+      if (c == '\02')
+	break;
+
+      if (isspace (c) || c == '\01' || c == '\03')
+	{
+	  if (!space)
+	    {
+	      fputc (' ', Output);
+	      num++;
+	    }
+	  space = 1;
+	}
+      else
+	{
+	  space = 0;
+	  fputc (c, Output);
+	  num++;
+	}
+    }
+}
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) || defined(NZDL)
+void PrintDocNum(FILE *output, char query_type,
+		 int docnum, int indexnum, float weight)
+{
+  if (query_type == 'R' || query_type == 'A')
+    fprintf(output, "%7d.%-7d  %6.4f\n", docnum, indexnum, weight);
+  else
+    fprintf(output, "%7d.%-7d\n", docnum, indexnum);
+}
+#endif
+
+static int 
+ProcessDocs (query_data * qd, int num, int verbatim,
+	     char OutputType, FILE * Output)
+{
+  int max_buf = 0;
+  int DocCount = 0;
+  char *doc_sepstr = NULL;
+  char *para_sepstr = NULL;
+  char *para_start = NULL;
+  int heads_length = atoi (GetDefEnv ("heads_length", "50"));
+  char QueryType = get_query_type ();
+  int need_text = (OutputType == OUTPUT_TEXT || OutputType == OUTPUT_HILITE ||
+		   OutputType == OUTPUT_HEADERS || OutputType == OUTPUT_SILENT || 
+		   post_proc); /* [RJM June 1997 -- fixing post retrieval scan] */
+
+  if (OutputType == OUTPUT_TEXT || OutputType == OUTPUT_HILITE)
+    {
+      if (QueryType == QUERY_APPROX || QueryType == QUERY_RANKED)
+	{
+	  doc_sepstr = de_escape_string (
+				    Xstrdup (GetDefEnv ("ranked_doc_sepstr",
+			   "---------------------------------- %n %w\\n")));
+	}
+      else
+	{
+	  doc_sepstr = de_escape_string (
+					  Xstrdup (GetDefEnv ("doc_sepstr",
+			      "---------------------------------- %n\\n")));
+	}
+      para_sepstr = de_escape_string (
+				       Xstrdup (GetDefEnv ("para_sepstr",
+				  "\\n######## PARAGRAPH %n ########\\n")));
+
+      para_start = de_escape_string (
+				      Xstrdup (GetDefEnv ("para_start",
+					    "***** Weight = %w *****\\n")));
+    }
+
+  if (need_text)
+    {
+      max_buf = atoi (GetDefEnv ("buffer", "1048576"));
+    }
+
+  do
+    {
+      u_char *UDoc = NULL;
+      unsigned long ULen;
+
+      if (need_text)
+	{
+	  /* load the compressed text */
+	  if (LoadCompressedText (qd, max_buf))
+	    {
+	      Message ("Unable to load compressed text.");
+	      FatalError (1, "This is probably due to lack of memory.");
+	    }
+
+	  /* uncompress the loaded text */
+	  UDoc = GetDocText (qd, &ULen);
+	  if (UDoc == NULL)
+	    FatalError (1, "UDoc is unexpectedly NULL");
+	}
+
+      if (!UDoc || PostProc ((char *) UDoc, verbatim))
+	{
+	  switch (OutputType)
+	    {
+	    case OUTPUT_COUNT:
+	    case OUTPUT_SILENT:
+	      break;
+	    case OUTPUT_DOCNUMS:	/* This prints out the docnums string */
+	      if (PagerRunning)
+		{
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) || defined(NZDL)
+		  int doc_num = GetDocNum(qd);
+
+		  if (qd->paragraph)
+		    {
+		      if (qd->id->ifh.InvfLevel == 3 &&
+			  (QueryType == 'R' || QueryType == 'A'))
+			{
+			  /* Print weights for each paragraph in document */
+			  
+
+			  int true_doc_num = GetDocNumFromParaNum(qd, doc_num);
+
+			  /* Get number of paragraphs in this document */
+
+			  int num_paragraphs = 
+			    qd->paragraph[true_doc_num]-qd->paragraph[true_doc_num-1];
+
+			  int init_para = FetchInitialParagraph(qd->td,
+								doc_num);
+			  DocEntry *de, *doc_chain = GetDocChain(qd);
+			  int i;
+
+			  for (i = 0; i < num_paragraphs; i++)
+			    {
+			      if ((de = in_chain(i, init_para, doc_chain)))
+				PrintDocNum(Output, QueryType,
+					    true_doc_num, init_para+i,
+					    de->Weight);
+			    }
+			}
+		      else
+			PrintDocNum(Output, QueryType,
+				    GetDocNumFromParaNum(qd, GetDocNum(qd)),
+				    GetDocNum(qd),
+				    GetDocWeight(qd));
+		    }
+		  else
+		    {
+		      PrintDocNum(Output, QueryType,
+				  doc_num, doc_num, GetDocWeight(qd));
+		    }
+#else
+		fprintf (Output, "%7d   %6.4f   %7lu\n", GetDocNum (qd),
+			 GetDocWeight (qd), GetDocCompLength (qd));
+#endif
+		}
+	      break;
+	    case OUTPUT_HEADERS:	/* This prints out the headers of the documents */
+	      if (PagerRunning)
+		fprintf (Output, "%d ", GetDocNum (qd));
+	      HeaderOut (Output, UDoc, ULen, heads_length);
+	      if (PagerRunning)
+		fputc ('\n', Output);
+	      break;
+#if TREC_MODE
+	    case OUTPUT_EXTRAS:	/* This prints out the docnums string */
+	      if (PagerRunning && trec_ids)
+		{
+		  long DN, PN = GetDocNum (qd) - 1;
+		  if (trec_paras)
+		    DN = trec_paras[PN];
+		  else
+		    DN = PN;
+		  fprintf (Output, "%-14.14s  %8ld  %10.5f\n",
+			   &trec_ids[DN * 14], PN + 1, GetDocWeight (qd));
+		}
+	      break;
+#endif
+	    case OUTPUT_TEXT:
+	    case OUTPUT_HILITE:
+	      {
+		int j, para = -1, curr_para = 0;
+		int init_para = -1;
+		DocEntry *de, *doc_chain = NULL;
+		register char ch = ' ';
+		register char lch = '\n';
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) || defined(NZDL)
+		if (qd->id->ifh.InvfLevel == 3)
+		  {
+		    init_para = FetchInitialParagraph(qd->td, GetDocNum(qd));
+		    
+		    StringOut(Output, para_sepstr, 
+			      1, init_para+curr_para,
+			      0, 0);
+
+		  }
+		else
+		  StringOut(Output, doc_sepstr, 
+			    1, GetDocNum(qd),
+			    QueryType == 'A' || QueryType == 'R',
+			    GetDocWeight(qd));
+
+#else
+		int p_on = 0;
+
+		if (PagerRunning)
+		  {
+		    StringOut (Output, doc_sepstr,
+			       1, GetDocNum (qd),
+			       QueryType == 'A' || QueryType == 'R',
+			       GetDocWeight (qd));
+		  }
+		if (qd->id->ifh.InvfLevel == 3)
+		  {
+		    init_para = FetchInitialParagraph (qd->td, GetDocNum (qd));
+		    doc_chain = GetDocChain (qd);
+		    para = GetDocNum (qd) - init_para;
+
+		    StringOut (Output, para_sepstr,
+			       1, curr_para + 1,
+			       0, 0);
+
+		    if ((de = in_chain (0, init_para, doc_chain)))
+		      StringOut (Output, para_start,
+				 0, 0,
+				 1, de->Weight);
+
+		    if (doc_chain->DocNum - init_para == 0)
+		      p_on = 1;
+		  }
+#endif
+		for (j = 0; j < ULen; j++)
+		  {
+		    ch = UDoc[j];
+		    switch (ch)
+		      {
+		      case '\02':
+			break;
+		      case '\01':
+			ch = '\n';
+		      case '\03':
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(PARADOCNUM) || defined(NZDL)
+			/* print paragraph numbers only if this is
+			   a level 3 index */
+			if (qd->id->ifh.InvfLevel == 3)
+			  {
+			    curr_para++;
+			    StringOut(Output, para_sepstr, 
+				      1, init_para+curr_para,
+				      0, 0);
+			  }
+#else
+			p_on = 0;
+			curr_para++;
+			StringOut (Output, para_sepstr,
+				   1, curr_para + 1,
+				   0, 0);
+			lch = *(strchr (para_sepstr, '\0') - 1);
+			if ((de = in_chain (curr_para, init_para, doc_chain)))
+			  StringOut (Output, para_start,
+				     0, 0,
+				     1, de->Weight);
+			if (doc_chain &&
+			    doc_chain->DocNum - init_para == curr_para)
+			  p_on = 1;
+#endif
+			break;
+		      default:
+			{
+			  if (PagerRunning)
+			    {
+			      fputc (ch, Output);
+/* [RPAP - Feb 97: NZDL Additions] */
+#if !defined(PARADOCNUM) && !defined(NZDL)
+			      if (p_on && isprint (ch))
+				{
+				  fputc ('\b', Output);
+				  fputc ('_', Output);
+				}
+#endif
+			    }
+
+			  lch = ch;
+			}
+		      }
+		  }
+		if (PagerRunning && lch != '\n')
+		  fputc ('\n', Output);
+/* [RPAP - Feb 97: NZDL Additions] */
+#if !defined(PARADOCNUM) && !defined(NZDL)
+		p_on = 0;
+#endif
+	      }
+	    }
+	  if (PagerRunning)
+	    fflush (Output);
+
+	  DocCount++; /* moved within if statement [RJM June 1997 -- fixing post retrieval scan] */
+	}
+    }
+  while (NextDoc (qd) && PagerRunning && (!Ctrl_C));
+
+  if (need_text)
+    {
+      FreeTextBuffer (qd);
+    }
+
+  if (OutputType == OUTPUT_TEXT || OutputType == OUTPUT_HILITE)
+    {
+      Xfree (doc_sepstr);
+      Xfree (para_sepstr);
+      Xfree (para_start);
+    }
+
+  return (DocCount);
+}
+
+
+void 
+output_terminator (FILE * out)
+{
+  char *terminator = Xstrdup (GetDefEnv ("terminator", ""));
+  de_escape_string (terminator);
+  fputs (terminator, out);
+  Xfree (terminator);
+}
+
+
+
+
+/* MoreDocs () */
+/* Displays all documents in list  DocList. */
+/* Documents are fetched, then decompressed and displayed according to the */
+/* format implied in  FormString(). */
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+# define HILITE_PAGER "mg_hilite_words.exe"
+#else
+# define HILITE_PAGER "mg_hilite_words"
+#endif
+
+#define MAX_HILITE_PAGER_STR 80	/* for command & its options */
+
+static void 
+MoreDocs (query_data * qd, char *Query, char OutputType)
+{
+  static char terms_str[MAXTERMSTRLEN + 1];
+  int DocCount = 0;		/* number of actual matches */
+  FILE *Output = NULL;
+  int using_pipe = 0;
+  char *pager = NULL;
+
+  Ctrl_C = 0;
+
+  qd->num_of_ans = qd->DL->num;
+
+  /* [RPAP - Feb 97: WIN32 Port] */
+#ifndef __WIN32__
+  signal (SIGPIPE, SIGPIPE_handler);
+#endif
+  signal (SIGINT, SIGINT_handler);
+
+  PagerRunning = 1;
+  if (isatty (fileno (OutFile)) && GetEnv ("pager") &&
+      OutputType != OUTPUT_HILITE &&
+      OutputType != OUTPUT_SILENT && OutputType != OUTPUT_COUNT)
+    {
+      pager = GetEnv ("pager");
+    }
+  else if (isatty (fileno (OutFile)) && OutputType == OUTPUT_HILITE)
+    {
+      /* concat the pager and its word argument strings */
+      ConvertTermsToString (qd->TL, terms_str);
+      pager = Xmalloc (MAX_HILITE_PAGER_STR + strlen (terms_str) + 1);
+      if (!pager)
+	{
+	  fprintf (stderr, "Unable to allocate memory for highlighting\n");
+	  return;
+	}
+      sprintf (pager, "%s --style=%s --pager=%s --stem_method=%ld --stemmer=%ld %s",
+	       HILITE_PAGER,
+	       GetEnv ("hilite_style"),
+	       GetEnv ("pager"),
+	       qd->sd->sdh.stem_method,
+	       qd->sd->sdh.stemmer_num,
+	       terms_str);
+
+    }
+  else
+    {
+      Output = OutFile;
+    }
+
+/* [RPAP - Feb 97: NZDL Additions] */
+#if defined(OUTPUTSTEMMEDWORDS) || defined(NZDL)
+  if (!isatty(fileno(OutFile)) && get_query_type() != QUERY_DOCNUMS)
+    {
+      ConvertTermsToString(qd->TL, terms_str);
+      fprintf(Output, "%s\n", terms_str);
+    }
+#endif
+  if (pager)
+    {
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+      Output = _popen (pager, "w");
+#else
+      Output = popen (pager, "w");
+#endif
+      using_pipe = (Output != NULL);
+      if (!using_pipe)
+	{
+	  fprintf (stderr, "Unable to run \"%s\"\n", pager);
+	  return;
+	}
+    }
+
+
+  if (qd->DL->num > 0)
+    {
+      if (OutputType == OUTPUT_COUNT && !post_proc)
+	DocCount = qd->DL->num;
+      else {
+	DocCount = ProcessDocs (qd, qd->DL->num,
+				BooleanEnv (GetEnv ("verbatim"), 1),
+				OutputType, Output);
+      }
+    }
+
+  if (PagerRunning)
+    {
+      output_terminator (Output);
+      fflush (Output);
+    }
+
+  if (OutputType == OUTPUT_HILITE && pager)
+    free (pager);		/* as needed to malloc to create the pager string */
+
+  if (using_pipe)
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+    _pclose (Output);
+#else
+    pclose (Output);
+#endif
+
+  if (qd->DL->num == 0)
+    fprintf (stderr, "No entries correspond to that query.\n");
+  else
+    {
+      if (OutputType == OUTPUT_COUNT)
+	fprintf (stderr, "%d documents match.\n", DocCount);
+      else
+	fprintf (stderr, "%d documents retrieved.\n", DocCount);
+    }
+
+  signal (SIGINT, SIG_DFL);
+}
+
+
+void 
+start_up_stats (query_data * qd, InitQueryTimes iqt)
+{
+  Clear_Stats ();
+  if (BooleanEnv (GetEnv ("timestats"), 0) ||
+      BooleanEnv (GetEnv ("briefstats"), 0))
+    StartUpTimeStats (&iqt);
+
+  if (BooleanEnv (GetEnv ("diskstats"), 0) ||
+      BooleanEnv (GetEnv ("briefstats"), 0))
+    File_Stats (qd);
+
+  if (BooleanEnv (GetEnv ("memstats"), 0) ||
+      BooleanEnv (GetEnv ("briefstats"), 0))
+    MemStats (qd);
+
+}
+
+
+void 
+shut_down_stats (query_data * qd, ProgTime * start,
+		 ProgTime * invf, ProgTime * text)
+{
+  Clear_Stats ();
+  if (BooleanEnv (GetEnv ("timestats"), 0) ||
+      BooleanEnv (GetEnv ("briefstats"), 0))
+    QueryTimeStats (start, invf, text);
+
+  if (BooleanEnv (GetEnv ("diskstats"), 0) ||
+      BooleanEnv (GetEnv ("briefstats"), 0))
+    {
+      TransFileStats (qd);
+      File_Stats (qd);
+    }
+
+  if (BooleanEnv (GetEnv ("sizestats"), 0))
+    TotalSizeStats (qd);
+}
+
+
+
+char *wordfreqword2str (u_char * s)
+{
+  static char buf[1024];
+  int i, len = (int) *s++;
+
+  for (i = 0; i < len; i++)
+    {
+      buf[i] = (char)s[i];
+    }
+  buf[len] = '\0';
+
+  return buf;
+}
+
+
+/* [RPAP - Feb 97: Term Frequency] */
+/*********************************
+ * PrintQueryTermFreq
+ *
+ * Prints the query terms and their respective frequencies within the collection
+ *********************************/
+void
+PrintQueryTermFreqs (QueryTermList *qtl)
+{
+  int i;
+
+  /* Print the number of terms */
+  fprintf (OutFile, "%d\n", qtl->num);
+
+  /* Print the terms and their respective frequency within the collection */
+  for (i = 0; i < qtl->num; i++)
+    if (qtl->QTE[i].stem_method == -1)
+      /* Using default stem method - don't print stem method beside term */
+      fprintf (OutFile, "%s %d\n", wordfreqword2str (qtl->QTE[i].Term), qtl->QTE[i].Count);
+    else
+      /* Term was forced with a stem, print stem method with term */
+      fprintf (OutFile, "%s#%d %d\n", wordfreqword2str (qtl->QTE[i].Term), qtl->QTE[i].stem_method, qtl->QTE[i].Count);
+}
+
+
+void 
+query (void)
+{
+  ProgTime TotalStartTime, TotalInvfTime, TotalTextTime;
+  InitQueryTimes iqt;
+  query_data *qd;
+
+  TotalStartTime.RealTime = TotalStartTime.CPUTime = 0;
+  TotalInvfTime.RealTime = TotalInvfTime.CPUTime = 0;
+  TotalTextTime.RealTime = TotalTextTime.CPUTime = 0;
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  qd = InitQuerySystem (GetDefEnv ("mgdir", ".\\"),
+                        GetDefEnv ("mgname", ""),
+			GetDefEnv ("textname", NULL), /* [RJM 06/97: text filename] */
+			&iqt);
+#else
+  qd = InitQuerySystem (GetDefEnv ("mgdir", "./"),
+                        GetDefEnv ("mgname", ""),
+			GetDefEnv ("textname", NULL), /* [RJM 06/97: text filename] */
+                        &iqt);
+#endif
+
+  if (!qd)
+    FatalError (1, mg_errorstrs[mg_errno], mg_error_data);
+  start_up_stats (qd, iqt);
+
+
+  while (1)
+    {
+      ProgTime StartTime, InvfTime, TextTime;
+      char QueryType;
+      char OutputType;
+      char *line;
+      ResetFileStats (qd);
+      qd->max_mem_in_use = qd->mem_in_use = 0;
+
+      qd->tot_hops_taken += qd->hops_taken;
+      qd->tot_num_of_ptrs += qd->num_of_ptrs;
+      qd->tot_num_of_accum += qd->num_of_accum;
+      qd->tot_num_of_terms += qd->num_of_terms;
+      qd->tot_num_of_ans += qd->num_of_ans;
+      qd->tot_text_idx_lookups += qd->text_idx_lookups;
+      qd->hops_taken = qd->num_of_ptrs = 0;
+      qd->num_of_accum = qd->num_of_ans = qd->num_of_terms = 0;
+      qd->text_idx_lookups = 0;
+
+      Display_Stats (stderr);
+      Clear_Stats ();
+      line = get_query (qd);
+      if (!line || Quitting)
+	break;
+
+      GetPostProc (line);
+
+      GetTime (&StartTime);
+
+      FreeQueryDocs (qd);
+
+      QueryType = get_query_type ();
+      OutputType = get_output_type ();
+      /* No point in hiliting words on a docnum query */
+      if (OutputType == OUTPUT_HILITE && QueryType == QUERY_DOCNUMS)
+	OutputType = OUTPUT_TEXT;
+
+      switch (QueryType)
+	{
+	case QUERY_BOOLEAN:
+	  {
+	    char *maxdocs;
+	    BooleanQueryInfo bqi;
+	    maxdocs = GetDefEnv ("maxdocs", "all");
+	    bqi.MaxDocsToRetrieve = strcmp (maxdocs, "all") ? atoi (maxdocs) : -1;
+	    /* [RPAP - Jan 97: Stem Index Change] */
+	    if (qd->sd->sdh.indexed)
+	      BooleanQuery (qd, line, &bqi, (BooleanEnv (GetEnv ("casefold"), 0) |
+					     (BooleanEnv (GetEnv ("stem"), 0) << 1)));
+	    else
+	      BooleanQuery (qd, line, &bqi, qd->sd->sdh.stem_method);
+
+	    break;
+	  }
+	case QUERY_APPROX:
+	case QUERY_RANKED:
+	  {
+	    char *maxdocs;
+	    char *maxterms;
+	    char *maxaccum;
+	    RankedQueryInfo rqi;
+	    maxdocs = GetDefEnv ("maxdocs", "all");
+	    maxterms = GetDefEnv ("max_terms", "all");
+	    maxaccum = GetDefEnv ("max_accumulators", "all");
+	    rqi.Sort = BooleanEnv (GetEnv ("sorted_terms"), 0);
+	    rqi.QueryFreqs = BooleanEnv (GetEnv ("qfreq"), 1);
+	    rqi.Exact = QueryType == QUERY_RANKED;
+	    rqi.MaxDocsToRetrieve = strcmp (maxdocs, "all") ? atoi (maxdocs) : -1;
+	    rqi.MaxTerms = strcmp (maxterms, "all") ? atoi (maxterms) : -1;
+	    rqi.MaxParasToRetrieve = rqi.MaxDocsToRetrieve;
+	    if (qd->id->ifh.InvfLevel == 3 && GetEnv ("maxparas"))
+	      rqi.MaxParasToRetrieve = atoi (GetEnv ("maxparas"));
+	    rqi.AccumMethod = toupper (*GetDefEnv ("accumulator_method", "A"));
+	    rqi.MaxAccums = strcmp (maxaccum, "all") ? atoi (maxaccum) : -1;
+	    rqi.HashTblSize = IntEnv (GetEnv ("hash_tbl_size"), 1000);
+	    rqi.StopAtMaxAccum = BooleanEnv (GetEnv ("stop_at_max_accum"), 0);
+	    rqi.skip_dump = GetEnv ("skip_dump");
+	    RankedQuery (qd, line, &rqi);
+	    break;
+	  }
+	case QUERY_DOCNUMS:
+	  {
+	    DocnumsQuery (qd, line);
+	    break;
+	  }
+	}
+
+      GetTime (&InvfTime);
+
+      /* [RPAP - Feb 97: Term Frequency] */
+      if (qd->QTL && BooleanEnv (GetEnv ("term_freq"), 0))
+	PrintQueryTermFreqs (qd->QTL);
+
+      if (qd->DL)
+	MoreDocs (qd, line, OutputType);
+
+      GetTime (&TextTime);
+
+      if (BooleanEnv (GetEnv ("timestats"), 0) ||
+	  BooleanEnv (GetEnv ("briefstats"), 0))
+	QueryTimeStats (&StartTime, &InvfTime, &TextTime);
+
+      if (BooleanEnv (GetEnv ("diskstats"), 0) ||
+	  BooleanEnv (GetEnv ("briefstats"), 0))
+	File_Stats (qd);
+
+      if (BooleanEnv (GetEnv ("memstats"), 0) ||
+	  BooleanEnv (GetEnv ("briefstats"), 0))
+	MemStats (qd);
+
+      if (BooleanEnv (GetEnv ("sizestats"), 0))
+	SizeStats (qd);
+
+      TotalInvfTime.RealTime += InvfTime.RealTime - StartTime.RealTime;
+      TotalInvfTime.CPUTime += InvfTime.CPUTime - StartTime.CPUTime;
+      TotalTextTime.RealTime += TextTime.RealTime - StartTime.RealTime;
+      TotalTextTime.CPUTime += TextTime.CPUTime - StartTime.CPUTime;
+    }
+
+  if (isatty (fileno (InFile)) && !Quitting)
+    fprintf (stderr, "\n");
+
+  shut_down_stats (qd, &TotalStartTime, &TotalInvfTime, &TotalTextTime);
+
+  Display_Stats (stderr);
+
+}
+
+
+void 
+search_for_collection (char *name)
+{
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  char *dir = GetDefEnv ("mgdir", ".\\");
+#else
+  char *dir = GetDefEnv ("mgdir", "./");
+#endif
+  char buffer[512];
+  struct stat stat_buf;
+  if (strrchr (dir, '/') && *(strrchr (dir, '/') + 1) != '\0')
+    {
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+      sprintf (buffer, "%s", dir);
+#else
+      sprintf (buffer, "%s/", dir);
+#endif
+      SetEnv ("mgdir", buffer, NULL);
+      dir = GetEnv ("mgdir");
+    }
+
+  sprintf (buffer, "%s.text", name);
+  if (stat (buffer, &stat_buf) != -1)
+    {
+      if ((stat_buf.st_mode & S_IFREG) != 0)
+	{
+	  /* The name is a directory */
+	  SetEnv ("mgname", name, NULL);
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+          SetEnv ("mgdir", ".\\", NULL);
+#else
+	  SetEnv ("mgdir", "./", NULL);
+#endif
+	  return;
+	}
+    }
+
+  sprintf (buffer, "%s%s", dir, name);
+  if (stat (buffer, &stat_buf) != -1)
+    {
+      if ((stat_buf.st_mode & S_IFDIR) != 0)
+	{
+	  /* The name is a directory */
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+          sprintf (buffer, "%s%s", name, name);
+#else
+	  sprintf (buffer, "%s/%s", name, name);
+#endif
+	  SetEnv ("mgname", buffer, NULL);
+	  return;
+	}
+    }
+
+  /* Look in the current directory last */
+  if (stat (name, &stat_buf) != -1)
+    {
+      if ((stat_buf.st_mode & S_IFDIR) != 0)
+	{
+	  /* The name is a directory */
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+          sprintf (buffer, "%s%s", name, name);
+          SetEnv ("mgdir", ".\\", NULL);
+#else
+	  sprintf (buffer, "%s/%s", name, name);
+          SetEnv ("mgdir", "./", NULL);
+#endif
+	  SetEnv ("mgname", buffer, NULL);
+	  return;
+	}
+    }
+
+  SetEnv ("mgname", name, NULL);
+}
+
+/* main () */
+/* Initialises global variables based on command line switches, and opens */
+/* files.  Then calls  query ()  to perform the querying. */
+int main (int argc, char **argv)
+{
+  ProgTime StartTime;
+  int decomp = 0;
+  int ch;
+
+  msg_prefix = argv[0];
+  GetTime (&StartTime);
+
+  /* Initialise the environment with default values */
+
+  InitEnv ();
+
+  read_mgrc_file ();
+
+  OutFile = stdout;
+  InFile = stdin;
+
+  opterr = 0;
+  /* [RJM 06/97: text filename] */
+  while ((ch = getopt (argc, argv, "Df:d:t:h")) != -1) {
+    switch (ch) {
+      case 'f':
+	SetEnv ("mgname", optarg, NULL);
+	break;
+      case 'd':
+	SetEnv ("mgdir", optarg, NULL);
+	break;
+      case 't': /* [RJM 06/97: text filename] */
+	SetEnv ("textname", optarg, NULL);
+	break;
+      case 'D':
+	decomp = 1;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-D] [-f base name of collection] "
+		 "[-t base name of files for text] " /* [RJM 06/97: text filename] */
+		 "[-d data directory] [collection]\n", argv[0]);
+	exit (1);
+    }      
+  }
+
+  PushEnv ();
+
+  if (decomp == 0)
+    {
+
+      Init_ReadLine ();
+
+      /* write a first prompt, let the user start thinking */
+      if (!BooleanEnv (GetEnv ("expert"), 0) && isatty (fileno (InFile)))
+	{
+	  fprintf (stderr, "\n\n\t     FULL TEXT RETRIEVAL QUERY PROGRAM\n");
+	  fprintf (stderr, "%24s%s\n\n", "", *"21 Mar 1994" == '%' ? __DATE__ : "21 Mar 1994");
+	  fprintf (stderr, "\n");
+	  fprintf (stderr, "  mgquery version " VERSION ", Copyright (C) 1994 Neil Sharman\n");
+	  fprintf (stderr, "  mgquery comes with ABSOLUTELY NO WARRANTY; for details type `.warranty'\n");
+	  fprintf (stderr, "  This is free software, and you are welcome to redistribute it\n");
+	  fprintf (stderr, "  under certain conditions; type `.conditions' for details.\n");
+	  fprintf (stderr, "\n");
+	}
+    }
+  if (optind < argc)
+    search_for_collection (argv[optind]);
+
+  if (decomp == 0)
+    {
+      query ();
+    }
+  else
+    {
+      int i;
+      InitQueryTimes iqt;
+      query_data *qd;
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+      qd = InitQuerySystem (GetDefEnv ("mgdir", ".\\"),
+                            GetDefEnv ("mgname", ""),
+                            GetDefEnv ("textname", NULL), /* [RJM 06/97: text filename] */
+                            &iqt);
+#else
+      qd = InitQuerySystem (GetDefEnv ("mgdir", "./"),
+			    GetDefEnv ("mgname", ""),
+                            GetDefEnv ("textname", NULL), /* [RJM 06/97: text filename] */
+			    &iqt);
+#endif
+      if (!qd)
+	FatalError (1, mg_errorstrs[mg_errno], mg_error_data);
+
+
+      start_up_stats (qd, iqt);
+
+      Display_Stats (stderr);
+      for (i = 0; i < qd->td->cth.num_of_docs; i++)
+	{
+	  RawDocOutput (qd, i + 1, stdout);
+	  putc ('\2', stdout);
+	}
+      Message ("%s", ElapsedTime (&StartTime, NULL));
+
+      FinishQuerySystem (qd);
+    }
+
+  UninitEnv ();
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstat.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstat.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstat.1	(revision 10506)
@@ -0,0 +1,131 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgstat 1 \*(Dt CITRI
+.SH NAME
+mgstat \- print out statistics about a document collection
+.SH SYNOPSIS
+.B mgstat
+[
+.B \-h
+]
+[
+.B \-E
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgstat
+prints out various statistics about an existing
+.BR mg (1)
+document collection.  Depending on the size of the collection, sizes
+will be printed in either kilobytes or megabytes.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stdout .
+.TP
+.B \-E
+This option forces sizes to be printed in bytes rather than kilobytes
+or megabytes.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text
+Compressed documents.
+.TP
+.B *.invf
+Inverted file.
+.TP
+.B *.text.idx.wgt
+Interleaved index into the compressed documents and document weights.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.TP
+.B *.invf.dict.blocked
+Compressed stemmed dictionary and index into the inverted file merged
+into an inverted file.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.invf.chunk
+Maps stemmed terms from occurrence order to lexical order.
+.TP
+.B *.invf.chunk.trans
+Describes where the source text is broken up into chunks for the
+inversion pass.
+.TP
+.B *.invf.dict.hash
+A perfect hash function for the terms in the stemmed dictionary.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_compression_dict (1),
+.BR mg_fast_comp_dict (1),
+.BR mg_get (1),
+.BR mg_invf_dict (1),
+.BR mg_invf_dump (1),
+.BR mg_invf_rebuild (1),
+.BR mg_passes (1),
+.BR mg_perf_hash_build (1),
+.BR mg_text_estimate (1),
+.BR mg_weights_build (1),
+.BR mgbilevel (1),
+.BR mgbuild (1),
+.BR mgdictlist (1),
+.BR mgfelics (1),
+.BR mgquery (1),
+.BR mgtic (1),
+.BR mgticbuild (1),
+.BR mgticdump (1),
+.BR mgticprune (1),
+.BR mgticstat (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstat.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstat.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstat.c	(revision 10506)
@@ -0,0 +1,403 @@
+/**************************************************************************
+ *
+ * mgstat.c -- Program to generate statistics on a text collection
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "mg.h"
+#include "words.h"
+#include "invf.h"
+#include "text.h"
+#include "longlong.h"
+
+/*
+   $Log$
+   Revision 1.2  2001/09/21 12:46:42  kjm18
+   updated mg to be in line with mg_1.3f. Now uses long long for some variables
+   to enable indexing of very large collections.
+
+   Revision 1.1  1999/08/10 21:18:19  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:50  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:31  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:41:59  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+char *search_for_collection (char *name);
+int process_file (char *, char *, int);
+void ProcessDict (char *);
+void ProcessStem (char *);
+long ProcessStemBlk (char *name);  /* [RPAP - Jan 97: Stem Index Change] */
+
+static mg_ullong inputbytes = 0;
+static mg_ullong total = 0;
+
+
+
+
+
+int main (int argc, char **argv)
+{
+  mg_ullong sub_total;
+  int fast;
+  char *file_name = "";
+  int ch;
+  int exact = 0;
+  long indexed = 0; /* [RPAP - Jan 97: Stem Index Change] */
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "Ehf:d:")) != -1)
+    switch (ch)
+      {
+      case 'E':
+	exact = 1;
+	break;
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file]"
+		 "[-d data directory] [-h]\n", argv[0]);
+	exit (1);
+      }
+
+  if (optind < argc)
+    file_name = search_for_collection (argv[optind]);
+
+  ProcessDict (file_name);
+  ProcessStem (file_name);
+  indexed = ProcessStemBlk (file_name); /* [RPAP - Jan 97: Stem Index Change] */
+
+  {
+    char Name[256];
+    char *s;
+    sprintf (Name, FILE_NAME_FORMAT, get_basepath (), file_name, "");
+    s = strrchr (Name, '/');
+    if (s)
+      *s = '\0';
+    printf ("\nThe collection is in \"%s\"\n", Name);
+  }
+
+
+  printf ("\n\t\tFiles required by mgquery\n");
+  process_file (file_name, TEXT_SUFFIX, exact);
+  process_file (file_name, INVF_SUFFIX, exact);
+  process_file (file_name, TEXT_IDX_WGT_SUFFIX, exact);
+  process_file (file_name, APPROX_WEIGHTS_SUFFIX, exact);
+  process_file (file_name, INVF_DICT_BLOCKED_SUFFIX, exact);
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (indexed)
+    {
+      process_file (file_name, INVF_DICT_BLOCKED_1_SUFFIX, exact);
+      process_file (file_name, INVF_DICT_BLOCKED_2_SUFFIX, exact);
+      process_file (file_name, INVF_DICT_BLOCKED_3_SUFFIX, exact);
+    }
+
+  fast = process_file (file_name, TEXT_DICT_FAST_SUFFIX, exact);
+  if (!fast)
+    {
+      process_file (file_name, TEXT_DICT_SUFFIX, exact);
+      process_file (file_name, TEXT_DICT_AUX_SUFFIX, exact);
+    }
+
+
+  process_file (NULL, "SUB TOTAL", exact);
+  sub_total = total;
+  total = 0;
+
+  printf ("\n\t\tFiles NOT required by mgquery\n");
+  if (fast)
+    {
+      process_file (file_name, TEXT_DICT_SUFFIX, exact);
+      process_file (file_name, TEXT_DICT_AUX_SUFFIX, exact);
+    }
+  process_file (file_name, INVF_DICT_SUFFIX, exact);
+  process_file (file_name, INVF_IDX_SUFFIX, exact);
+  process_file (file_name, TEXT_STATS_DICT_SUFFIX, exact);
+  process_file (file_name, TEXT_IDX_SUFFIX, exact);
+  process_file (file_name, WEIGHTS_SUFFIX, exact);
+  process_file (file_name, INVF_CHUNK_SUFFIX, exact);
+  process_file (file_name, INVF_CHUNK_TRANS_SUFFIX, exact);
+  process_file (file_name, INVF_DICT_HASH_SUFFIX, exact);
+  process_file (file_name, INVF_PARAGRAPH_SUFFIX, exact);
+  process_file (NULL, "SUB TOTAL", exact);
+  total += sub_total;
+  printf ("\n");
+  process_file (NULL, "TOTAL", exact);
+  return 0;
+
+}
+
+
+
+char *
+search_for_collection (char *name)
+{
+  char *dir = get_basepath ();
+  static char buffer[512];
+  struct stat stat_buf;
+
+  /* Look in the current directory first */
+  if (stat (name, &stat_buf) != -1)
+    {
+      if (S_ISDIR(stat_buf.st_mode))
+	{
+	  /* The name is a directory */
+	  sprintf (buffer, "%s/%s", name, name);
+	  set_basepath (".");
+	  return buffer;
+	}
+    }
+
+  sprintf (buffer, "%s.text", name);
+  if (stat (buffer, &stat_buf) != -1)
+    {
+      if (S_ISREG(stat_buf.st_mode))
+	{
+	  /* The name is a directory */
+	  set_basepath (".");
+	  return name;
+	}
+    }
+  sprintf (buffer, "%s/%s", dir, name);
+  if (stat (buffer, &stat_buf) != -1)
+    {
+      if (S_ISDIR(stat_buf.st_mode))
+	{
+	  /* The name is a directory */
+	  sprintf (buffer, "%s/%s", name, name);
+	  return buffer;
+	}
+    }
+  return name;
+}
+
+
+
+
+
+
+void 
+ProcessDict (char *name)
+{
+  FILE *f;
+  compression_dict_header cdh;
+  int have_cdh = 0;
+  compressed_text_header cth;
+  int have_cth = 0;
+
+  if ((f = open_file (name, TEXT_DICT_SUFFIX, "rb", MAGIC_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      Read_cdh (f, &cdh, NULL, NULL);
+      fclose (f);
+      have_cdh = 1;
+    }
+
+  if ((f = open_file (name, TEXT_SUFFIX, "rb", MAGIC_TEXT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fread ((char *) &cth, sizeof (cth), 1, f);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(cth.num_of_docs);
+      NTOHD(cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+      NTOHUL(cth.num_of_words);
+      NTOHUL(cth.length_of_longest_doc);
+      NTOHD(cth.ratio);
+
+      fclose (f);
+      have_cth = 1;
+    }
+
+  if (have_cth)
+    {
+      inputbytes = cth.num_of_bytes;
+      printf ("Input bytes                        : %10" ULL_FS ", %8.2f Mbyte\n",
+	      cth.num_of_bytes, (double) cth.num_of_bytes / 1024 / 1024);
+      printf ("Documents                          : %10lu\n", cth.num_of_docs);
+      printf ("Words in collection [dict]         : %10lu\n", cth.num_of_words);
+      printf ("Longest doc in collection [dict]   : %10lu characters\n",
+	      cth.length_of_longest_doc);
+      printf ("Maximum ratio                      : %10.2f\n", cth.ratio);
+    }
+
+  if (have_cdh)
+    {
+      printf ("Words in dict                      : %10lu\n", cdh.num_words[1]);
+      printf ("Non-words in dict                  : %10lu\n", cdh.num_words[0]);
+      printf ("Total chars of distinct words      : %10lu\n", cdh.num_word_chars[1]);
+      printf ("Total chars of distinct non-words  : %10lu\n", cdh.num_word_chars[0]);
+    }
+
+}
+
+
+
+
+
+
+
+
+void 
+ProcessStem (char *name)
+{
+  FILE *f;
+  struct invf_dict_header idh;
+
+  if (!(f = open_file (name, INVF_DICT_SUFFIX, "rb",
+		       MAGIC_STEM_BUILD, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return;
+  fread ((char *) &idh, sizeof (idh), 1, f);
+  printf ("Words in collection [stem]         : %10ld\n", NTOHUL(idh.num_of_words));  /* [RPAP - Jan 97: Endian Ordering] */
+  printf ("Words in stem                      : %10ld\n", NTOHUL(idh.dict_size));  /* [RPAP - Jan 97: Endian Ordering] */
+  printf ("Indexed fragments                  : %10ld\n", NTOHUL(idh.num_of_docs));  /* [RPAP - Jan 97: Endian Ordering] */
+  printf ("Total chars of stem words          : %10ld\n", NTOHUL(idh.total_bytes));  /* [RPAP - Jan 97: Endian Ordering] */
+  fclose (f);
+}
+
+
+
+
+
+/* [RPAP - Jan 97: Stem Index Change] */
+long 
+ProcessStemBlk (char *name)
+{
+  FILE *f;
+  struct stem_dict_header sdh;
+
+  if (!(f = open_file (name, INVF_DICT_BLOCKED_SUFFIX, "rb",
+		       MAGIC_STEM, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return 0;
+  fread ((char *) &sdh, sizeof (sdh), 1, f);
+  fclose (f);
+  return NTOHUL(sdh.indexed);  /* [RPAP - Jan 97: Endian Ordering] */
+}
+
+
+
+
+int 
+process_file (char *name, char *ext, int exact)
+{
+  static double scale = 0;
+  static char *units;
+  struct stat buf;
+  if (scale == 0)
+    {
+      /* So can get output in Mb or Kb, */
+      /* will divide by a scale of 1024(Kb) or 1024*1024(Mb) */
+      /* Note: if inputbytes==0, then use 1024 as default */
+      scale = inputbytes > 10 * 1000 * 1000 ? 1024 * 1024 : 1024;
+      units = scale == 1024 ? "Kb" : "Mb";
+    }
+  if (name)
+    {
+      char Name[256];
+      sprintf (Name, FILE_NAME_FORMAT, get_basepath (), name, ext);
+      if (!stat (Name, &buf))
+	{
+	  char fname[256];
+	  char *nam = strrchr (name, '/');
+	  nam = nam ? nam + 1 : name;
+	  sprintf (fname, "%s%s", nam, ext);
+
+	  if (inputbytes == 0.0)
+	    {
+	      if (exact)
+		printf ("%s%*s: %10ld bytes   %7.3f%%\n", fname,
+			35 - (int) strlen (fname), "",
+			buf.st_size,
+			100.0 * buf.st_size / inputbytes);
+	      else
+		printf ("%s%*s: %8.2f %s   %7.3f%%\n", fname,
+			35 - (int) strlen (fname), "",
+			buf.st_size / scale,
+			units,
+			100.0 * buf.st_size / inputbytes);
+	    }
+	  else
+	    {
+	      if (exact)
+		printf ("%s%*s: %10ld bytes\n", fname,
+			35 - (int) strlen (fname), "",
+			buf.st_size);
+	      else
+		printf ("%s%*s: %8.2f %s\n", fname,
+			35 - (int) strlen (fname), "",
+			buf.st_size / scale,
+			units);
+	    }
+	  total += buf.st_size;
+	  return 1;
+	}
+      else
+	return 0;
+    }
+  else
+    {
+      if (inputbytes == 0.0)
+	{
+	  if (exact)
+	    printf ("%-34s : %10" ULL_FS " bytes   %7.3f%%\n", ext,
+		    total,
+		    100.0 * total / inputbytes);
+	  else
+	    printf ("%-34s : %8.2f %s   %7.3f%%\n", ext,
+		    total / scale, units,
+		    100.0 * total / inputbytes);
+	}
+      else
+	{
+	  if (exact)
+	    printf ("%-34s : %10" ULL_FS " bytes\n", ext, total);
+	  else
+	    printf ("%-34s : %8.2f %s\n", ext,
+		    total / scale, units);
+	}
+    }
+  return 1;
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstemidxlist.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstemidxlist.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstemidxlist.1	(revision 10506)
@@ -0,0 +1,86 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.Id $Id$
+.\"------------------------------------------------------------
+.TH mgstemidxlist 1 \*(Dt CITRI
+.SH NAME
+mgstemidxlist \- dumps the stem index file to STDOUT in ASCII format
+.SH SYNOPSIS
+.B mgstemidxlist
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.B \-s 1|2|3
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgstemidxlist
+is a utility program which passes through the stem index and displays
+the information.  (This program was used for debugging but is included
+for completeness!)  The header information is printed out, then for each
+block in the file the block header is displayed.  For each word in the
+stem index, the output is formatted as:
+
+.RS
+.I number_of_references \*(lqword\*(rq
+.br
+.RS
+.I "->  number_of_cases block 3-in-4_block offset"
+.br
+.I "->  ..."
+.RE
+.RE
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B -s 1|2|3
+The stem index file with the associated stem method.
+.br
+1 = casefolded and non-stemmed
+.br
+2 = non-casefolded and stemmed
+.br
+3 = casefolded and stemmed
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the
+.BR mg (1)
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 25
+.B *.invf.dict.blocked.1
+Stem index with stem index method 1.
+.TP
+.B *.invf.dict.blocked.2
+Stem index with stem index method 2.
+.TP
+.B *.invf.dict.blocked.3
+Stem index with stem index method 3.
+.SH "SEE ALSO"
+.na
+.BR mg (1),
+.BR mg_invf_dict (1),
+.BR mg_stem_idx (1).
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstemidxlist.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstemidxlist.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/mgstemidxlist.c	(revision 10506)
@@ -0,0 +1,245 @@
+/**************************************************************************
+ *
+ * mgstemidxlist.c -- Text dumper for the stem indexes
+ * Copyright (C) 1997  Ross Peeters
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "messages.h"
+#include "memlib.h"
+#include "local_strings.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "mg.h"
+#include "invf.h"
+#include "words.h"
+#include "backend.h"
+
+void
+read_3_in_4 (FILE * idbi)
+{
+  unsigned long i;
+  stemmed_idx *si;
+  u_char *buffer;
+  int block = 0;
+
+  if (!(si = Xmalloc (sizeof (stemmed_idx))))
+    {
+      return;
+    }
+
+  si->MemForStemIdx = 0;
+
+  fread (&(si->sih), sizeof (si->sih), 1, idbi);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(si->sih.lookback);
+  NTOHUL(si->sih.block_size);
+  NTOHUL(si->sih.num_blocks);
+  NTOHUL(si->sih.blocks_start);
+  NTOHUL(si->sih.index_chars);
+  NTOHUL(si->sih.num_of_words);
+
+  if (!(buffer = Xmalloc (si->sih.index_chars)))
+    {
+      Xfree (si);
+      return;
+    };
+  si->MemForStemIdx += si->sih.index_chars;
+
+  if (!(si->index = Xmalloc (si->sih.num_blocks * sizeof (*si->index))))
+    {
+      Xfree (si);
+      Xfree (buffer);
+      return;
+    };
+  si->MemForStemIdx += si->sih.num_blocks * sizeof (*si->index);
+
+  if (!(si->pos = Xmalloc (si->sih.num_blocks * sizeof (*si->pos))))
+    {
+      Xfree (si->index);
+      Xfree (si);
+      Xfree (buffer);
+      return;
+    };
+  si->MemForStemIdx += si->sih.num_blocks * sizeof (*si->pos);
+
+  if (!(si->buffer = Xmalloc (si->sih.block_size * sizeof (*si->buffer))))
+    {
+      Xfree (buffer);
+      Xfree (si->index);
+      Xfree (si->buffer);
+      Xfree (si);
+      return;
+    };
+  si->MemForStemIdx += si->sih.block_size * sizeof (*si->buffer);
+
+  si->active = -1;
+
+  for (i = 0; i < si->sih.num_blocks; i++)
+    {
+      register u_char len;
+      si->index[i] = buffer;
+      len = fgetc (idbi);
+      *buffer++ = len;
+      fread (buffer, sizeof (u_char), len, idbi);
+      buffer += len;
+      fread (&si->pos[i], sizeof (*si->pos), 1, idbi);
+      NTOHUL(si->pos[i]);  /* [RPAP - Jan 97: Endian Ordering] */
+    }
+
+  printf ("# lookback     = %lu\n", si->sih.lookback);
+  printf ("# block_size   = %lu\n", si->sih.block_size);
+  printf ("# num_blocks   = %lu\n", si->sih.num_blocks);
+  printf ("# blocks_start = %lu\n", si->sih.blocks_start);
+  printf ("# index_chars  = %lu\n", si->sih.index_chars);
+  printf ("# num_of_words = %lu\n", si->sih.num_of_words);
+
+  block = 0;
+  while (block < si->sih.num_blocks)
+    {
+      unsigned long *first_word;
+      unsigned short *num_words;
+      unsigned short *index;
+      long res;
+      u_char *base;
+      int num_indexes;
+
+      /* Read in next block */
+      fseek (idbi, si->pos[block] + si->sih.blocks_start, 0);
+      fread (si->buffer, si->sih.block_size, sizeof (u_char), idbi);
+      si->active = si->pos[block];
+
+      first_word = (unsigned long *) (si->buffer);
+      NTOHUL(*first_word);  /* [RPAP - Jan 97: Endian Ordering] */
+      num_words = (unsigned short *) (first_word + 1);
+      NTOHUS(*num_words);  /* [RPAP - Jan 97: Endian Ordering] */
+      index = num_words + 1;
+      num_indexes = ((*num_words - 1) / si->sih.lookback) + 1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = 0; i < num_indexes; i++)
+	NTOHUS(index[i]);
+
+      base = (u_char *) (index + num_indexes);
+      base += index[0];
+
+      printf ("\n# block      = %d\n", block);
+      printf ("# first_word = %lu\n", *first_word);
+      printf ("# num_words  = %u\n", *num_words);
+
+      res = 0;
+      while (res < *num_words)
+	{
+	  unsigned copy, suff;
+	  u_char prev[MAXSTEMLEN + 1];
+	  unsigned int num_entries, num_cases, blk;
+	  unsigned short blk_index, offset;
+
+	  /* Read word entry */
+	  copy = *base++;
+	  suff = *base++;
+	  bcopy ((char *) base, (char *) (prev + copy + 1), suff);
+	  *prev = copy + suff;
+	  base += suff;
+	  bcopy ((char *) base, (char *) &num_entries, sizeof (num_entries));
+	  base += sizeof (num_entries);
+	  NTOHUI(num_entries);  /* [RPAP - Jan 97: Endian Ordering] */
+	  printf ("%u \"%s\"\n", num_entries, word2str (prev));
+
+	  /* For all the PosEntries for the word... */
+	  for (i = 0; i < num_entries; i++)
+	    {
+	      bcopy ((char *) base, (char *) &num_cases, sizeof (num_cases));
+	      NTOHUI(num_cases);  /* [RPAP - Jan 97: Endian Ordering] */
+	      base += sizeof (num_cases);
+	      bcopy ((char *) base, (char *) &blk, sizeof (blk));
+	      NTOHUI(blk);  /* [RPAP - Jan 97: Endian Ordering] */
+	      base += sizeof (blk);
+	      bcopy ((char *) base, (char *) &blk_index, sizeof (blk_index));
+	      NTOHUS(blk_index);  /* [RPAP - Jan 97: Endian Ordering] */
+	      base += sizeof (blk_index);
+	      bcopy ((char *) base, (char *) &offset, sizeof (offset));
+	      NTOHUS(offset);  /* [RPAP - Jan 97: Endian Ordering] */
+	      base += sizeof (offset);
+
+	      printf ("    -> %4u %4u %4u %4u\n", num_cases, blk, blk_index, offset);
+	    }
+	  res++;
+	}
+      block++;
+    }
+  fclose (idbi);
+}
+
+int
+main (int argc, char **argv)
+{
+  FILE *idbi;
+  char *filename = "";
+  int ch;
+  int stem_method = 0;
+
+  msg_prefix = argv[0];
+  opterr = 0;
+  while ((ch = getopt (argc, argv, "f:d:hs:")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	filename = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 's':
+	stem_method = atoi (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-d data directory] [-h] -s 1|2|3 -f name\n", argv[0]);
+	exit (1);
+      }
+
+  /* Open required files */
+  switch (stem_method)
+    {
+    case (1):
+      idbi = open_file (filename, INVF_DICT_BLOCKED_1_SUFFIX, "rb", MAGIC_STEM_1,
+			MG_ABORT);
+      break;
+    case (2):
+      idbi = open_file (filename, INVF_DICT_BLOCKED_2_SUFFIX, "rb", MAGIC_STEM_2,
+			MG_ABORT);
+      break;
+    case (3):
+      idbi = open_file (filename, INVF_DICT_BLOCKED_3_SUFFIX, "rb", MAGIC_STEM_3,
+			MG_ABORT);
+      break;
+    default:
+      FatalError (1, "Stem method must be 1, 2 or 3\n");
+    }
+
+  if (!idbi)
+    FatalError (1, "Could NOT open file");
+
+  read_3_in_4 (idbi);
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query.docnums.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query.docnums.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query.docnums.c	(revision 10506)
@@ -0,0 +1,100 @@
+/**************************************************************************
+ *
+ * query.docnums.c -- Docnums query evaluation
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "filestats.h"
+#include "timing.h"
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+
+
+static DocList *
+AddToDocList (DocList * Docs, int res)
+{
+  int j;
+  /* Search the list for the word */
+  for (j = 0; j < Docs->num; j++)
+    if (Docs->DE[j].DocNum == res)
+      break;
+
+  /* Increment the weight if the word is in the list */
+  if (j < Docs->num)
+    Docs->DE[j].Weight++;
+  else
+    {
+      /* Create a new entry in the list for the new document */
+      Docs = ResizeDocList (Docs, Docs->num + 1);
+      Docs->DE[Docs->num].DocNum = res;
+      Docs->DE[Docs->num].Weight = 1;
+      Docs->DE[Docs->num].SeekPos = 0;
+      Docs->DE[Docs->num].Len = 0;
+      Docs->DE[Docs->num].CompTextBuffer = NULL;
+      Docs->DE[Docs->num].Next = NULL;
+      Docs->num++;
+    }
+  return (Docs);
+}
+
+void 
+DocnumsQuery (query_data * qd, char *QueryLine)
+{
+  DocList *Docs = MakeDocList (0);
+  unsigned long start = 0, finish;
+  int range = 0; /* is there a range or not ? */
+
+  /* find the start of the first word */
+  while (*QueryLine)
+    {
+      char *end;
+      finish = strtol (QueryLine, &end, 10);
+      if (end != (char *) QueryLine && finish >= 1 &&
+	  finish <= qd->sd->sdh.num_of_docs)
+	{
+	  unsigned long i;
+	  if (!range)
+	    start = finish;
+	  else
+	    range = 0;
+	  for (i = start; i <= finish; i++)
+	    Docs = AddToDocList (Docs, i);
+	  while (*end == ' ' || *end == '\t' || *end == '\n')
+	    end++;
+	  if (*end == '-')
+	    {
+	      start = finish;
+	      range = 1;
+	      end++;
+	    }
+	}
+      else
+	break;
+      QueryLine = end;
+    }
+  FreeQueryDocs (qd);
+
+  qd->DL = Docs;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query.ranked.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query.ranked.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query.ranked.c	(revision 10506)
@@ -0,0 +1,991 @@
+/**************************************************************************
+ *
+ * query.ranked.c -- Ranked query evaluation
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "filestats.h"
+#include "messages.h"
+#include "timing.h"
+#include "sptree.h"
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "stem_search.h"
+#include "weights.h"
+#include "text_get.h"
+#include "invf_get.h"
+#include "words.h"
+#include "stemmer.h"
+#include "locallib.h"
+#include "environment.h"
+#include "term_lists.h"
+#include "local_strings.h"
+#include "query_term_list.h"  /* [RPAP - Feb 97: Term Frequency] */
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:20  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:50  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:34  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.4  1994/11/25  03:47:46  tes
+   * Committing files before adding the merge stuff.
+   *
+   * Revision 1.3  1994/10/20  03:57:03  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:04  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+/*************************************************************************/
+
+typedef struct HeapEntry
+  {
+    float Weight;
+    float *OrgWeight;
+    int DocNum;
+    u_long SeekPos;		/* position in the text file in bytes */
+    u_long Len;			/* length of the document in bytes */
+  }
+HeapEntry;
+
+typedef int (*HeapComp) (HeapEntry *, HeapEntry *);
+
+typedef struct Heap
+  {
+    int NumItems;
+    int MaxSize;
+    HeapComp HC;
+    HeapEntry HE[1];
+  }
+Heap;
+
+
+Heap *
+Heap_Make (int size, HeapComp hc)
+{
+  Heap *H;
+  H = Xmalloc (sizeof (Heap) + (size - 1) * sizeof (HeapEntry));
+  if (!H)
+    return NULL;
+  H->NumItems = 0;
+  H->MaxSize = size;
+  H->HC = hc;
+  return H;
+}
+
+int 
+Heap_Size (Heap * H)
+{
+  return sizeof (Heap) + H->MaxSize * sizeof (HeapEntry);
+}
+
+HeapEntry *
+Heap_GetHead (Heap * H)
+{
+  if (H && H->NumItems)
+    return &H->HE[0];
+  else
+    return NULL;
+}
+
+
+
+void 
+Heap_Heapify (Heap * H, int i)
+{
+  register int curr, child;
+  curr = i;
+  child = curr * 2;
+  while (child <= H->NumItems)
+    {
+      if (child < H->NumItems && H->HC (&H->HE[child], &H->HE[child - 1]) > 0)
+	child++;
+      if (H->HC (&H->HE[curr - 1], &H->HE[child - 1]) < 0)
+	{
+	  HeapEntry temp = H->HE[child - 1];
+	  H->HE[child - 1] = H->HE[curr - 1];
+	  H->HE[curr - 1] = temp;
+	  curr = child;
+	  child = 2 * child;
+	}
+      else
+	break;
+    }
+}
+
+
+void 
+Heap_Build (Heap * H)
+{
+  register int i;
+  for (i = H->NumItems / 2; i > 0; i--)
+    Heap_Heapify (H, i);
+}
+
+
+void 
+Heap_Sort (Heap * H)
+{
+  register int i;
+  for (i = H->NumItems; i > 1; i--)
+    {
+      HeapEntry temp = H->HE[0];
+      H->HE[0] = H->HE[i - 1];
+      H->HE[i - 1] = temp;
+      H->NumItems--;
+      Heap_Heapify (H, 1);
+    }
+}
+
+
+void 
+Heap_DeleteHead (Heap * H)
+{
+  H->HE[0] = H->HE[--H->NumItems];
+  Heap_Heapify (H, 1);
+}
+
+int 
+Heap_Lesser (HeapEntry * a, HeapEntry * b)
+{
+  return (a->Weight > b->Weight ? -1 :
+	  (a->Weight == b->Weight ? 0 : 1));
+}
+
+
+int 
+Heap_Greater (HeapEntry * a, HeapEntry * b)
+{
+  return (a->Weight > b->Weight ? 1 :
+	  (a->Weight == b->Weight ? 0 : -1));
+}
+
+int 
+Make_Exact_Root (query_data * qd, Heap * H)
+{
+  int num = 0;
+  HeapEntry *he = H->HE;
+  while (he->SeekPos == 0)
+    {
+      he->Weight = he->Weight *
+	GetLowerApproxDocWeight (qd->awd, he->DocNum - 1) /
+	FetchDocStart (qd, he->DocNum, &he->SeekPos, &he->Len);
+      Heap_Heapify (H, 1);
+      num++;
+    }
+  return num;
+}
+
+void 
+Heap_Dump (Heap * H, int num)
+{
+  int i, l, lines, r;
+  if (num > H->NumItems)
+    num = H->NumItems;
+  lines = (num + 3) / 4;
+  for (l = 0; l < lines; l++)
+    for (r = 0; r < 4; r++)
+      {
+	i = lines * r + l;
+	if (i < num)
+	  fprintf (stderr, "[%2d] %7.4f", i, H->HE[i].Weight);
+	fprintf (stderr, r == 3 ? "\n" : "        ");
+      }
+  fprintf (stderr, "\n");
+}
+
+/*************************************************************************/
+
+
+
+
+
+
+int 
+doc_count_comp (const void *A, const void *B)
+{
+  const TermEntry *a = A;
+  const TermEntry *b = B;
+  return (a->WE.doc_count - b->WE.doc_count);
+}
+
+/* =========================================================================
+ * Function: ParseRankedQuery
+ * Description:
+ *      Takes a string query line and extracts the terms in the query
+ *      which exist in the stemmed dictionary.
+ *      Optionally sorts the terms into ascending order by doc. number.
+ * Input:
+ *      stemmed dictionary, query line, sort-flag
+ * Output:
+ *      A list of terms.
+ * ========================================================================= */
+
+/* [RPAP - Jan 97: Stem Index Change] */
+static TermList *
+ParseRankedQuery (stemmed_dict * sd, char *QueryLine, int Sort, int indexed,
+		  QueryTermList **query_term_list)  /* [RPAP - Feb 97: Term Frequency] */
+{
+  u_char Word[MAXSTEMLEN + 1];
+  u_char sWord[MAXSTEMLEN + 1];
+  u_char *end, *s_in;
+  int default_stem_method = 0;
+  TermList *Terms = MakeTermList(0);
+
+  s_in = (u_char *) QueryLine;
+  end = s_in + strlen ((char *) s_in) - 1;
+  *query_term_list = MakeQueryTermList(0);  /* [RPAP - Feb 97: Term Frequency] */
+
+  if (indexed)
+    default_stem_method = BooleanEnv (GetEnv ("casefold"), 0) | (BooleanEnv (GetEnv ("stem"), 0) << 1);
+  else
+    default_stem_method = sd->sdh.stem_method;
+
+  while (s_in <= end)
+    {
+      int j;
+      long num_entries, word_num;
+      unsigned long count, doc_count, invf_ptr, invf_len;
+      int weight_to_apply, stem_to_apply;
+      int method_using = -1;
+
+      /* 0=optional, 1=mustmatch */
+      int require_match = 0; /* [RJM 07/97: Ranked Required Terms] */
+
+      /* Skip over the non word separator taking note of any parameters */
+      PARSE_RANKED_NON_STEM_WORD (require_match, s_in, end); /* [RJM 07/97: Ranked Required Terms] */
+      if (s_in > end) break;
+
+      /* Get a word and stem it */
+      PARSE_STEM_WORD (Word, s_in, end);
+
+      /* Extract any parameters */
+      weight_to_apply = 1;
+      stem_to_apply = default_stem_method;
+      while (s_in <= end)
+	{
+	  int stem_param, weight_param, param_type;
+	  char param[MAXPARAMLEN + 1];
+
+	  param_type = 0;
+	  PARSE_OPT_TERM_PARAM (param, param_type, s_in, end);
+	  if (!param_type)
+	    break;
+
+	  switch (param_type)
+	    {
+	    case (WEIGHTPARAM):
+	      weight_param = atoi (param);
+	      if (errno != ERANGE && weight_param > 0)
+		weight_to_apply = weight_param;
+	      break;
+
+	    case (STEMPARAM):
+	      stem_param = atoi (param);
+	      if (errno != ERANGE && indexed && stem_param >= 0 && stem_param <= 3)
+		method_using = stem_to_apply = stem_param;
+	      break;
+	    }
+	}
+
+      bcopy ((char *) Word, (char *) sWord, *Word + 1);
+      stemmer (stem_to_apply, sd->sdh.stemmer_num, sWord);
+
+      if (!indexed || stem_to_apply == 0)
+	{
+	  /* Look for the word in the already identified terms */
+	  for (j = 0; j < Terms->num; j++)
+	    if (compare (Terms->TE[j].Word, Word) == 0)
+	      break;
+
+	  /* Increment the weight if the word is in the list */
+	  /* Update the require match attribute */
+	  if (j < Terms->num)
+	    {
+	      Terms->TE[j].Count = ((Terms->TE[j].Count + weight_to_apply > INT_MAX) ?
+				    INT_MAX : (Terms->TE[j].Count + weight_to_apply));
+	      Terms->TE[j].require_match = require_match; /* [RJM 07/97: Ranked Require match] */
+	      AddQueryTerm (query_term_list, Word, Terms->TE[j].WE.count, method_using);  /* [RPAP - Feb 97: Term Frequency] */
+	    }
+	  else
+	    {
+	      /* Look for it in the stemmed dictionary */
+	      if ((word_num = FindWord (sd, sWord, &count, &doc_count,
+					&invf_ptr, &invf_len)) != -1)
+		{
+		  /* Search the list for the word */
+		  for (j = 0; j < Terms->num; j++)
+		    if (Terms->TE[j].WE.word_num == word_num)
+		      break;
+
+		  /* Increment the weight if the word is in the list */
+		  if (j < Terms->num)
+		    {
+		      Terms->TE[j].Count = ((Terms->TE[j].Count + weight_to_apply > INT_MAX) ?
+					    INT_MAX : (Terms->TE[j].Count + weight_to_apply));
+		      Terms->TE[j].require_match = require_match; /* [RJM 07/97: Ranked Require match] */
+		      AddQueryTerm (query_term_list, Word, Terms->TE[j].WE.count, method_using);  /* [RPAP - Feb 97: Term Frequency] */
+		    }
+		  else
+		    {
+		      /* Create a new entry in the list for the new word */
+		      TermEntry te;
+
+		      te.WE.word_num = word_num;
+		      te.WE.count = count;
+		      te.WE.doc_count = doc_count;
+		      te.WE.max_doc_count = doc_count;
+		      te.WE.invf_ptr = invf_ptr;
+		      te.WE.invf_len = invf_len;
+		      te.Count = weight_to_apply;
+		      te.Word = copy_string (Word);
+		      if (!te.Word)
+			FatalError (1, "Could NOT create memory to add term");
+		      te.Stem = NULL;
+		      te.require_match = require_match;
+
+		      AddTermEntry (&Terms, &te);
+
+		      /* [RPAP - Feb 97: Term Frequency] */
+		      AddQueryTerm (query_term_list, Word, count, method_using);
+		    }
+		}
+	      /* [RPAP - Feb 97: Term Frequency] */
+	      else
+		AddQueryTerm (query_term_list, Word, 0, method_using);
+	    }
+	}
+      else
+	{
+	  int total_count = 0;  /* [RPAP - Feb 97: Term Frequency] */
+	  TermList *tempList = MakeTermList (0);
+	  if ((num_entries = FindWords (sd, sWord, stem_to_apply, &tempList)) > 0)
+	    {
+	      int i;
+	      u_long max_doc_count = 0;
+
+	      /* get the maximum doc count */
+	      for (i = 0; i < tempList->num; i++)
+		{
+		  if (tempList->TE[i].WE.doc_count > max_doc_count)
+		    max_doc_count = tempList->TE[i].WE.doc_count;
+		  total_count += tempList->TE[i].WE.count;  /* [RPAP - Feb 97: Term Frequency] */
+		}
+
+	      for (i = 0; i < tempList->num; i++)
+		{
+		  /* Look for the word(s) in the already identified terms */
+		  for (j = 0; j < Terms->num; j++) 
+		    {
+		      if (compare (Terms->TE[j].Word, tempList->TE[i].Word) == 0)
+			{
+			  /* found the word */
+			  /* Modify weight */
+			  Terms->TE[j].Count = ((Terms->TE[j].Count + weight_to_apply > INT_MAX) ?
+						INT_MAX : (Terms->TE[j].Count + weight_to_apply));
+			  if (Terms->TE[j].WE.max_doc_count < max_doc_count)
+			    Terms->TE[j].WE.max_doc_count = max_doc_count;
+			  break;
+			}
+		    }
+
+		  if (j == Terms->num)
+		    {
+		      /* word was not found */
+		      tempList->TE[i].WE.max_doc_count = max_doc_count;
+		      tempList->TE[i].Count = weight_to_apply;
+
+		      /* We cannot require a term to match if it is expanded */
+		      /* into multiple terms :-( */
+		      tempList->TE[i].require_match = 0; /* [RJM 07/97: Ranked Required Terms] */
+
+		      AddTermEntry (&Terms, &tempList->TE[i]);
+		    }
+		}
+	    }
+	  /* [RPAP - Feb 97: Term Frequency] */
+	  AddQueryTerm (query_term_list, Word, total_count, method_using);
+
+	  if (tempList != NULL) Xfree(tempList); /* [RJM 07/98: Memory Leak] */
+	} /* end indexed */
+    } /* end while */
+
+  if (Sort)
+    /* Sort the terms in ascending order by doc_count */
+    qsort (Terms->TE, Terms->num, sizeof (TermEntry), doc_count_comp);
+  return (Terms);
+}
+
+
+
+
+static int 
+DE_comp (void *a, void *b)
+{
+  return ((DocEntry *) a)->SeekPos - ((DocEntry *) b)->SeekPos;
+}
+
+
+
+
+
+/*
+ * This function is given a list of term numbers and it returns a list
+ * of document numbers based on the cosine document weighting system.
+ * This puts the entries in an array.
+ * inverted file.
+ * If MaxDocs == -1 then it means all 
+ */
+static DocList *
+CosineGet (query_data * qd, TermList * Terms, RankedQueryInfo * rqi) {
+  DocList *Docs;
+  float *AccumulatedWeights = NULL;
+  Splay_Tree *ST = NULL;
+  Splay_Tree *Para_ST = NULL;
+  Hash_Table *HT = NULL;
+  List_Table *LT = NULL;
+  Heap *H;
+  HeapEntry *he;
+  register float *fptr = NULL;
+  register Invf_Doc_Entry *ide = NULL;
+  register Invf_Doc_EntryH *ideh = NULL;
+  int BackEnd, NumExact, MaxExact, NumParas;
+  int MaxDocs = 0, MaxParas = 0;
+  int i;
+  Invf_Doc_Entry_Pool ide_pool;
+  ide_pool.pool = NULL;
+
+  qd->hops_taken = qd->num_of_ptrs = qd->num_of_accum = 0;
+
+  switch (rqi->AccumMethod)
+    {
+    case 'S':
+      ST = CosineDecodeSplay (qd, Terms, rqi, &ide_pool);
+      if (!ST)
+	return NULL;
+      break;
+    case 'A':
+      AccumulatedWeights = CosineDecode (qd, Terms, rqi);
+      if (!AccumulatedWeights)
+	return NULL;
+      break;
+    case 'H':
+      HT = CosineDecodeHash (qd, Terms, rqi);
+      if (!HT)
+	return NULL;
+      break;
+    case 'L':
+      LT = CosineDecodeList (qd, Terms, rqi);
+      if (!LT)
+	return NULL;
+      break;
+    }
+
+#if 0
+  if (rqi->UseSplayTree)
+    {
+
+      AccumulatedWeights = CosineDecode (qd, Terms, rqi);
+      fptr = AccumulatedWeights;
+      ide = SP_get_first (ST);
+      for (i = 0; i < qd->sd->sdh.num_of_docs; i++)
+	{
+	  if (AccumulatedWeights[i] != 0)
+	    {
+	      if (i != ide->DocNum)
+		fprintf (stderr, "Sum mismatch for %d %f %d %f\n", i + 1,
+			 AccumulatedWeights[i], ide->DocNum + 1, ide->Sum);
+	      ide = SP_get_next (ST);
+	    }
+	}
+    }
+#endif
+
+  switch (rqi->AccumMethod)
+    {
+    case 'S':
+      MaxParas = ST->no_of_items;
+      break;
+    case 'A':
+      {				/* count the number of non-zero document weights */
+	register int i = qd->sd->sdh.num_of_docs;
+	register float *d;
+	MaxParas = 0;
+	for (d = AccumulatedWeights; i; i--, d++)
+	  if (*d)
+	    MaxParas++;
+      }
+      break;
+    case 'H':
+      MaxParas = HT->num + HT->Suplimentary_Num;
+      break;
+    case 'L':
+      MaxParas = LT->num;
+      break;
+    }
+
+  if (rqi->MaxParasToRetrieve != -1 && MaxParas > rqi->MaxParasToRetrieve)
+    MaxParas = rqi->MaxParasToRetrieve;
+  MaxDocs = MaxParas;
+
+  /* Allocate memory for the heap */
+  Docs = MakeDocList (MaxDocs);
+  ChangeMemInUse (qd, sizeof (DocEntry) * MaxDocs);
+
+  H = Heap_Make (MaxDocs, Heap_Lesser);
+
+
+  /* Get the sums from the array divide the sums by the 
+     document weights which we retrieve from the ".idx.wgt" file and put
+     the resulting data into a heap */
+
+
+  he = H->HE;
+  H->NumItems = MaxDocs;
+  switch (rqi->AccumMethod)
+    {
+    case 'S':
+      {
+	ide = SP_get_first (ST);
+	for (i = 0; i < H->NumItems; i++, ide = SP_get_next (ST), he++)
+	  {
+	    he->DocNum = ide->DocNum + 1;
+	    he->OrgWeight = &ide->Sum;
+	    qd->num_of_accum++;
+	  }
+      }
+      break;
+    case 'A':
+      {
+	fptr = AccumulatedWeights;
+	for (i = 0; i < H->NumItems; i++, fptr++, he++)
+	  {
+	    he->DocNum = i + 1;
+	    he->OrgWeight = fptr;
+	    if (*fptr)
+	      qd->num_of_accum++;
+	  }
+      }
+      break;
+    case 'H':
+      {
+	ideh = HT->Head;
+	for (i = 0; i < H->NumItems; i++, ideh = ideh->next, he++)
+	  {
+	    he->DocNum = ideh->IDE.DocNum + 1;
+	    he->OrgWeight = &ideh->IDE.Sum;
+	    qd->num_of_accum++;
+	  }
+      }
+      break;
+    case 'L':
+      {
+	ide = LT->IDE;
+	for (i = 0; i < H->NumItems; i++, ide++, he++)
+	  {
+	    he->DocNum = ide->DocNum + 1;
+	    he->OrgWeight = &ide->Sum;
+	    qd->num_of_accum++;
+	  }
+      }
+      break;
+    }
+
+  he = H->HE;
+  for (i = 0; i < H->NumItems; i++, he++)
+    {
+      *he->OrgWeight /= GetLowerApproxDocWeight (qd->awd, he->DocNum - 1);
+      he->Weight = *he->OrgWeight;
+      *he->OrgWeight = 0;
+      he->SeekPos = he->Len = 0;
+    }
+
+  Heap_Build (H);
+
+  he = H->HE;
+  switch (rqi->AccumMethod)
+    {
+    case 'S':
+      {
+	for (i = MaxDocs; i < ST->no_of_items; i++, ide = SP_get_next (ST))
+	  {
+	    ide->Sum /= GetLowerApproxDocWeight (qd->awd, ide->DocNum);
+	    qd->num_of_accum++;
+	    if (ide->Sum <= he->Weight)
+	      continue;
+	    *he->OrgWeight = he->Weight;
+	    he->DocNum = ide->DocNum + 1;
+	    he->Weight = ide->Sum;
+	    he->OrgWeight = &ide->Sum;
+	    *he->OrgWeight = 0;
+	    Heap_Heapify (H, 1);
+	  }
+      }
+      break;
+    case 'A':
+      {
+	for (i = MaxDocs; i < qd->sd->sdh.num_of_docs; i++, fptr++)
+	  {
+	    if (!*fptr)
+	      continue;
+	    qd->num_of_accum++;
+	    *fptr /= GetLowerApproxDocWeight (qd->awd, i);
+	    if (*fptr <= he->Weight)
+	      continue;
+	    *he->OrgWeight = he->Weight;
+	    he->DocNum = i + 1;
+	    he->Weight = *fptr;
+	    he->OrgWeight = fptr;
+	    *he->OrgWeight = 0;
+	    Heap_Heapify (H, 1);
+	  }
+      }
+      break;
+    case 'H':
+      {
+	for (; ideh; ideh = ideh->next)
+	  {
+	    qd->num_of_accum++;
+	    ideh->IDE.Sum /=
+	      GetLowerApproxDocWeight (qd->awd, ideh->IDE.DocNum);
+	    if (ideh->IDE.Sum <= he->Weight)
+	      continue;
+	    *he->OrgWeight = he->Weight;
+	    he->DocNum = ideh->IDE.DocNum + 1;
+	    he->Weight = ideh->IDE.Sum;
+	    he->OrgWeight = &ideh->IDE.Sum;
+	    *he->OrgWeight = 0;
+	    Heap_Heapify (H, 1);
+	  }
+      }
+      break;
+    case 'L':
+      {
+	for (i = MaxDocs; i < LT->num; i++, ide++)
+	  {
+	    qd->num_of_accum++;
+	    ide->Sum /=
+	      GetLowerApproxDocWeight (qd->awd, ide->DocNum);
+	    if (ide->Sum <= he->Weight)
+	      continue;
+	    *he->OrgWeight = he->Weight;
+	    he->DocNum = ide->DocNum + 1;
+	    he->Weight = ide->Sum;
+	    he->OrgWeight = &ide->Sum;
+	    *he->OrgWeight = 0;
+	    Heap_Heapify (H, 1);
+	  }
+      }
+      break;
+    }
+
+
+  if (rqi->Exact && qd->id->ifh.InvfLevel != 3)
+    {
+      HeapEntry *he = H->HE;
+
+      for (i = 0; i < H->NumItems; i++, he++)
+	{
+	  he->Weight = he->Weight *
+	    GetLowerApproxDocWeight (qd->awd, he->DocNum - 1) /
+	    FetchDocStart (qd, he->DocNum, &he->SeekPos, &he->Len);
+	}
+
+      Heap_Build (H);
+
+      he = H->HE;
+
+      switch (rqi->AccumMethod)
+	{
+	case 'S':
+	  {
+	    ide = SP_get_first (ST);
+	    for (i = 0; i < ST->no_of_items; i++, ide = SP_get_next (ST))
+	      {
+		u_long SeekPos, Len;
+		float Weight;
+		if (!ide->Sum)
+		  continue;
+		if (ide->Sum <= he->Weight)
+		  continue;
+		Weight = ide->Sum *
+		  GetLowerApproxDocWeight (qd->awd, ide->DocNum) /
+		  FetchDocStart (qd, ide->DocNum + 1, &SeekPos, &Len);
+		if (Weight <= he->Weight)
+		  continue;
+		he->DocNum = ide->DocNum + 1;
+		he->OrgWeight = &ide->Sum;
+		he->Weight = Weight;
+		he->SeekPos = SeekPos;
+		he->Len = Len;
+		ide->Sum = 0;
+		Heap_Heapify (H, 1);
+	      }
+	  }
+	  break;
+
+	  /* up to here */
+
+	case 'A':
+	  {
+	    fptr = AccumulatedWeights;
+	    for (i = 0; i < qd->sd->sdh.num_of_docs; i++, fptr++)
+	      {
+		u_long SeekPos, Len;
+		float Weight;
+		if (!*fptr)
+		  continue;
+		if (*fptr <= he->Weight)
+		  continue;
+		Weight = *fptr *
+		  GetLowerApproxDocWeight (qd->awd, i) /
+		  FetchDocStart (qd, i + 1, &SeekPos, &Len);
+		if (Weight <= he->Weight)
+		  continue;
+		he->DocNum = i + 1;
+		he->OrgWeight = fptr;
+		he->Weight = Weight;
+		he->SeekPos = SeekPos;
+		he->Len = Len;
+		*fptr = 0;
+		Heap_Heapify (H, 1);
+	      }
+	  }
+	  break;
+	case 'H':
+	  {
+	    ideh = HT->Head;
+	    for (ideh = HT->Head; ideh; ideh = ideh->next)
+	      {
+		u_long SeekPos, Len;
+		float Weight;
+		if (!ideh->IDE.Sum)
+		  continue;
+		if (ideh->IDE.Sum <= he->Weight)
+		  continue;
+		Weight = ideh->IDE.Sum *
+		  GetLowerApproxDocWeight (qd->awd, ideh->IDE.DocNum) /
+		  FetchDocStart (qd, ideh->IDE.DocNum + 1, &SeekPos, &Len);
+		if (Weight <= he->Weight)
+		  continue;
+		he->DocNum = ideh->IDE.DocNum + 1;
+		he->OrgWeight = &ideh->IDE.Sum;
+		he->Weight = Weight;
+		he->SeekPos = SeekPos;
+		he->Len = Len;
+		ideh->IDE.Sum = 0;
+		Heap_Heapify (H, 1);
+	      }
+	  }
+	  break;
+	case 'L':
+	  {
+	    ide = LT->IDE;
+	    for (i = 0; i < LT->num; i++, ide++)
+	      {
+		u_long SeekPos, Len;
+		float Weight;
+		if (!ide->Sum)
+		  continue;
+		if (ide->Sum <= he->Weight)
+		  continue;
+		Weight = ide->Sum *
+		  GetLowerApproxDocWeight (qd->awd, ide->DocNum) /
+		  FetchDocStart (qd, ide->DocNum + 1, &SeekPos, &Len);
+		if (Weight <= he->Weight)
+		  continue;
+		he->DocNum = ide->DocNum + 1;
+		he->OrgWeight = &ide->Sum;
+		he->Weight = Weight;
+		he->SeekPos = SeekPos;
+		he->Len = Len;
+		ide->Sum = 0;
+		Heap_Heapify (H, 1);
+	      }
+	  }
+	  break;
+	}
+    }
+
+
+
+  H->HC = Heap_Greater;
+  Heap_Build (H);
+
+
+  MaxDocs = H->NumItems;
+  if (rqi->MaxDocsToRetrieve != -1 && MaxDocs > rqi->MaxDocsToRetrieve)
+    MaxDocs = rqi->MaxDocsToRetrieve;
+
+  /* Alarm */
+
+  he = H->HE;
+  BackEnd = H->NumItems - 1;
+  NumExact = 0;
+  MaxExact = H->NumItems;
+  NumParas = 0;
+  Para_ST = SP_createset (DE_comp);
+  while (H->NumItems && Docs->num < MaxDocs)
+    {
+      DocEntry DocEnt;
+      DocEntry *mem;
+
+      if (rqi->Exact)
+	{
+	  if (H->HE[0].SeekPos == 0)
+	    NumExact += Make_Exact_Root (qd, H);
+	}
+      else
+	FetchDocStart (qd, he->DocNum, &he->SeekPos, &he->Len);
+
+      NumParas++;
+
+      DocEnt.DocNum = he->DocNum;
+      DocEnt.Weight = he->Weight;
+      DocEnt.Len = he->Len;
+      DocEnt.SeekPos = he->SeekPos;
+      DocEnt.CompTextBuffer = NULL;
+      DocEnt.Next = NULL;
+
+      Heap_DeleteHead (H);
+
+      if (!(mem = SP_member (&DocEnt, Para_ST)))
+	{
+	  Docs->DE[Docs->num] = DocEnt;
+	  SP_insert (&Docs->DE[Docs->num], Para_ST);
+	  Docs->num++;
+	}
+      else
+	{
+	  DocEnt.Next = mem->Next;
+	  Docs->DE[BackEnd] = DocEnt;
+	  mem->Next = &Docs->DE[BackEnd--];
+	}
+    }
+  SP_freeset (Para_ST);
+
+  if (qd->id->ifh.InvfLevel == 3)
+    {
+      Message ("%d Paragraphs were required to get %d documents",
+	       NumParas, Docs->num);
+      if (NumExact == MaxExact)
+	{
+	  Message ("The exact weights of all %d paragraphs had to be calculated", MaxExact);
+	  Message ("to obtain %d paragraphs. This may mean that the the documents", NumParas);
+	  Message ("returned do not necessarly represent an exact cosine ranking.");
+	  Message ("This problem may be corrected by increasing \'maxparas\'.");
+	}
+    }
+#if 0
+  {
+    int i;
+    FILE *f = fopen ("top.paras", "w");
+    fprintf (f, "=========================\nTop Paragraphs\n");
+    for (i = 0; i < Docs->num; i++)
+      {
+	DocEntry *d;
+	fprintf (f, "<%d(%f)>  ", Heap[i].DocNum, Heap[i].Weight);
+	for (d = Heap[i].Next; d; d = d->Next)
+	  fprintf (f, "%d(%f)  ", d->DocNum, d->Weight);
+	fprintf (f, "\n");
+      }
+    fprintf (f, "=========================\n");
+    fclose (f);
+  }
+#endif
+
+  if (AccumulatedWeights)
+    {
+      Xfree (AccumulatedWeights);
+      ChangeMemInUse (qd, -sizeof (float) * qd->sd->sdh.num_of_docs);
+    }
+  if (ST)
+    {
+      int mem = ST->mem_in_use;
+      SP_freeset (ST);
+      ChangeMemInUse (qd, -mem);
+      free_ide_pool (qd, &ide_pool);
+    }
+  if (HT)
+    HT_free (qd, HT);
+
+  if (LT)
+    LT_free (qd, LT);
+
+  if (H) Xfree (H); /* [RJM 07/98: Memory Leak] */
+
+  return (Docs);
+}
+
+
+
+
+/* if MaxDocs == -1 it means all */
+void 
+RankedQuery (query_data *qd, char *Query, RankedQueryInfo *rqi)
+{
+  DocList *dl;
+
+  if (qd->TL)
+    FreeTermList (&(qd->TL));
+
+  /* [RPAP - Feb 97: Term Frequency] */
+  if (qd->QTL)
+    FreeQueryTermList (&(qd->QTL));
+
+  qd->TL = ParseRankedQuery (qd->sd, Query, rqi->Sort, qd->sd->sdh.indexed,  /* [RPAP - Jan 97: Stem Index Change] */
+			     &(qd->QTL));  /* [RPAP - Feb 97: Term Frequency] */
+
+  /*  PrintTermList (qd->TL, stderr); */
+
+  dl = CosineGet (qd, qd->TL, rqi);
+
+  if (!dl)
+    FatalError (1, "Out of memory\n");
+
+  FreeQueryDocs (qd);
+
+  qd->DL = dl;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query_term_list.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query_term_list.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query_term_list.c	(revision 10506)
@@ -0,0 +1,225 @@
+/**************************************************************************
+ *
+ * filename -- description
+ * Copyright (C) 1994  Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:21  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:35:36  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:57:07  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+ */
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "local_strings.h"
+#include "query_term_list.h"
+#include "term_lists.h"  /* for MAXTERMSTRLEN */
+#include "messages.h"
+
+
+/* =========================================================================
+ * Function: MakeQueryTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+QueryTermList *
+MakeQueryTermList (int n)
+{
+  QueryTermList *t;
+  int list_size = (n == 0 ? 1 : n);	/* always allocate at least one node */
+
+  t = Xmalloc (sizeof (QueryTermList) + (list_size - 1) * sizeof (QueryTermEntry));
+  if (!t)
+    FatalError (1, "Unable to allocate query term list");
+
+  t->num = n;
+  t->list_size = list_size;
+
+  return t;
+}
+
+/* =========================================================================
+ * Function: ResizeQueryTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+#define GROWTH_FACTOR 2
+#define MIN_SIZE 2
+
+static void
+ResizeQueryTermList (QueryTermList ** query_list)
+{
+  QueryTermList *qtl = *query_list;
+
+  if (qtl->num > qtl->list_size)
+    {
+      if (qtl->list_size)
+	qtl->list_size *= GROWTH_FACTOR;
+      else
+	qtl->list_size = MIN_SIZE;
+    }
+  qtl = Xrealloc (qtl, sizeof (QueryTermList) + (qtl->list_size - 1) * sizeof (QueryTermEntry));
+
+  if (!qtl)
+    FatalError (1, "Unable to resize query term list");
+
+  *query_list = qtl;
+}
+
+/* =========================================================================
+ * Function: ConvertQueryTermsToString
+ * Description:
+ *      Convert term list into null-terminated string
+ * Input:
+ *      query_term_list = query list
+ * Output:
+ *      str = term string
+ * ========================================================================= */
+
+void
+ConvertQueryTermsToString (QueryTermList * query_term_list, char *str)
+{
+  int i = 0;
+  int total_len = 0;
+
+  /* terms_str should be preallocated */
+  if (!str)
+    return;
+
+  for (i = 0; i < query_term_list->num; i++)
+    {
+      unsigned char *word = query_term_list->QTE[i].Term;
+      int len = word[0];
+      total_len += len + 1;	/* +1 for space */
+      if (query_term_list->QTE[i].stem_method >= 0)
+	total_len += 2;         /* '#' and the stem number */
+      if (total_len > MAXTERMSTRLEN)
+	break;
+      strncpy (str, (char *) word + 1, len);
+      str += len;
+      if (query_term_list->QTE[i].stem_method >= 0)
+	{
+	  *str++ = '#';
+	  *str++ = '0' + query_term_list->QTE[i].stem_method;
+	}
+      if (i != (query_term_list->num) - 1)
+	{
+	  *str = ' ';
+	  str++;		/* add space gap */
+	}
+
+    }
+  *str = '\0';
+}
+
+/* =========================================================================
+ * Function: ResetTermList
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+ResetQueryTermList (QueryTermList ** qtl)
+{
+  if (*qtl)
+    FreeQueryTermList (qtl);
+  *qtl = MakeQueryTermList (0);
+}
+
+/* =========================================================================
+ * Function: AddQueryTermEntry
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+AddQueryTermEntry (QueryTermList ** query_term_list, QueryTermEntry * qte)
+{
+  QueryTermList *qtl = *query_term_list;
+
+  qtl->num++;
+  ResizeQueryTermList (query_term_list);
+  qtl = *query_term_list;
+
+  /* copy the structure contents */
+  bcopy ((char *) qte, (char *) &(qtl->QTE[qtl->num - 1]), sizeof (QueryTermEntry));
+
+  return qtl->num - 1;
+}
+
+
+
+/* =========================================================================
+ * Function: AddQueryTerm
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+AddQueryTerm (QueryTermList ** query_term_list, u_char * Term, int Count, int stem_method)
+{
+  /* Create a new entry in the list for the new word */
+  QueryTermEntry qte;
+
+  qte.Count = Count;
+  qte.stem_method = stem_method;
+  qte.Term = copy_string (Term);
+  if (!qte.Term)
+    FatalError (1, "Could NOT create memory to add term");
+
+  return AddQueryTermEntry (query_term_list, &qte);
+}
+
+/* =========================================================================
+ * Function: FreeQueryTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+void
+FreeQueryTermList (QueryTermList ** the_qtl)
+{
+  int j;
+  QueryTermList *qtl = *the_qtl;
+
+  for (j = 0; j < qtl->num; j++)
+    if (qtl->QTE[j].Term)
+      Xfree (qtl->QTE[j].Term);
+  Xfree (qtl);
+
+  *the_qtl = NULL;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query_term_list.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query_term_list.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/query_term_list.h	(revision 10506)
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * term_lists.h -- description
+ * Copyright (C) 1994  Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:21  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:35:37  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:57:08  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+ */
+
+#ifndef QUERY_TERM_LIST_H
+#define QUERY_TERM_LIST_H
+
+#include "sysfuncs.h"
+
+typedef struct QueryTermEntry
+  {
+    int Count;			/* The number of times the word occurs in the query */
+    u_char *Term;		/* The query term */
+    int stem_method;            /* The steming method to apply to the term : -1 is default */
+  }
+QueryTermEntry;
+
+typedef struct QueryTermList
+  {
+    int list_size;
+    int num;
+    QueryTermEntry QTE[1];
+  }
+QueryTermList;
+
+/* --- prototypes --- */
+void ConvertQueryTermsToString (QueryTermList * query_term_list, char *str);
+int AddQueryTerm (QueryTermList ** query_term_list, u_char * Term, int Count, int stem_method);
+void ResetQueryTermList (QueryTermList ** tl);
+void FreeQueryTermList (QueryTermList ** the_qtl);
+QueryTermList *MakeQueryTermList (int n);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/read_line.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/read_line.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/read_line.c	(revision 10506)
@@ -0,0 +1,214 @@
+/**************************************************************************
+ *
+ * read_line.c -- Input line reading routines for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+#ifdef GNU_READLINE
+#include "readline.h"
+#include "chardefs.h"
+#include "history.h"
+#endif
+
+
+#include "globals.h"
+#include "environment.h"
+#include "read_line.h"
+
+
+
+#ifdef GNU_READLINE
+int rl_bind_key (int, int (*)());
+
+
+void 
+Init_ReadLine (void)
+{
+  /* Make TAB just insert itself rather than do a file name completion */
+  rl_bind_key (TAB, rl_insert);
+}
+#else
+
+static FILE *rl_instream = NULL;
+static FILE *rl_outstream = NULL;
+
+void 
+Init_ReadLine (void)
+{
+  rl_instream = stdin;
+  rl_outstream = stdout;
+}
+
+static char *
+readline (char *pmt)
+{
+  static char buf[MAXLINEBUFFERLEN + 1];
+  char *s;
+
+  fprintf (rl_outstream, "%s", pmt);
+  s = fgets (buf, sizeof (buf), rl_instream);
+  if (s)
+    {
+      char *s1 = strrchr (s, '\n');
+      if (s1 && *(s1 + 1) == '\0')
+	*s1 = '\0';
+    }
+  return s ? Xstrdup (s) : NULL;
+}
+#endif
+
+/* WritePrompt() */
+/* Write out a prompt if user is a TTY */
+void 
+WritePrompt (void)
+{
+  if (isatty (fileno (InFile)))
+    {
+      if (!BooleanEnv (GetEnv ("expert"), 0))
+	fprintf (stderr, "Enter a command or query (.quit to terminate, .help for assistance).\n");
+    }
+}
+
+#ifdef GNU_READLINE
+static void memory_error_and_abort ();
+
+char *
+xmalloc (bytes)
+     int bytes;
+{
+  char *temp = (char *) Xmalloc (bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+  return (temp);
+}
+
+char *
+xrealloc (pointer, bytes)
+     char *pointer;
+     int bytes;
+{
+  char *temp;
+
+  if (!pointer)
+    temp = (char *) xmalloc (bytes);
+  else
+    temp = (char *) Xrealloc (pointer, bytes);
+
+  if (!temp)
+    memory_error_and_abort ();
+
+  return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+  fprintf (stderr, "history: Out of virtual memory!\n");
+  abort ();
+}
+#endif
+
+
+/*
+ * This routine returns a pointer to the users entered line 
+ *
+ */
+static char *
+GetLine (char *pmt)
+{
+  static char *the_line = NULL;
+  if (the_line)
+    Xfree (the_line);
+  the_line = NULL;
+  rl_instream = InFile;
+  if (isatty (fileno (InFile)))
+    {
+      fputc ('\r', stderr);
+      if (!isatty (fileno (OutFile)))
+	rl_outstream = stderr;
+      else
+	rl_outstream = OutFile;
+      the_line = readline (pmt);
+    }
+  else
+    {
+      if (isatty (fileno (OutFile)))
+	{
+	  the_line = readline (pmt);
+	  fprintf (stderr, "%s\n", the_line ? the_line : "");
+	}
+      else
+	{
+	  the_line = readline ("");
+	  if (the_line)
+	    fprintf (stderr, "%s%s\n", pmt, the_line);
+	}
+    }
+#ifdef GNU_READLINE
+  if (the_line && *the_line)
+    add_history (the_line);
+#endif
+  return (the_line);
+}
+
+
+
+
+
+
+char *
+GetMultiLine (void)
+{
+  static char *line = NULL;
+  char *s;
+  if (line)
+    Xfree (line);
+  line = NULL;
+  if (!(s = GetLine ("> ")))
+    return (NULL);
+  if (!(line = Xstrdup (s)))
+    {
+      fprintf (stderr, "Unable to allocate memory for the line\n");
+      abort ();
+    }
+
+  while ((s = strrchr (line, '\\')) && *(s + 1) == '\0')
+    {
+      char *new;
+      *strrchr (line, '\\') = '\0';
+      if (!(s = GetLine ("? ")))
+	return (NULL);
+      if (!(new = Xmalloc (strlen (line) + strlen (s) + 2)))
+	{
+	  fprintf (stderr, "Unable to allocate memory for the line\n");
+	  abort ();
+	}
+      strcpy (new, line);
+      strcat (new, "\n");
+      strcat (new, s);
+      Xfree (line);
+      line = new;
+    }
+  return (line);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/read_line.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/read_line.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/read_line.h	(revision 10506)
@@ -0,0 +1,34 @@
+/**************************************************************************
+ *
+ * read_line.h -- Input line reading routines for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef READ_LINE_H
+#define READ_LINE_H
+
+#define MAXLINEBUFFERLEN  65535
+
+void Init_ReadLine (void);
+void WritePrompt (void);
+char *GetMultiLine (void);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stem_search.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stem_search.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stem_search.c	(revision 10506)
@@ -0,0 +1,772 @@
+/**************************************************************************
+ *
+ * stem_search.c -- Functions for searching the blocked stemmed dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "filestats.h"
+#include "timing.h"
+#include "local_strings.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "words.h"
+#include "locallib.h"
+#include "stem_search.h"
+#include "mg_errors.h"
+#include "term_lists.h"
+#include "stemmer.h"
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:22  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1999/07/02 00:18:55  rjmcnab
+   Changed so FindWords could be used in new ways.
+
+   Revision 1.2  1998/11/25 07:55:51  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:39  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:04  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:08  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+stemmed_dict *
+ReadStemDictBlk (File * stem_file)
+{
+  unsigned long i;
+  stemmed_dict *sd;
+  u_char *buffer;
+
+  if (!(sd = Xmalloc (sizeof (stemmed_dict))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  sd->stem_file = stem_file;
+  sd->MemForStemDict = 0;
+
+  Fread (&sd->sdh, sizeof (sd->sdh), 1, stem_file);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(sd->sdh.lookback);
+  NTOHUL(sd->sdh.block_size);
+  NTOHUL(sd->sdh.num_blocks);
+  NTOHUL(sd->sdh.blocks_start);
+  NTOHUL(sd->sdh.index_chars);
+  NTOHUL(sd->sdh.num_of_docs);
+  NTOHUL(sd->sdh.static_num_of_docs);
+  NTOHUL(sd->sdh.num_of_words);
+  NTOHUL(sd->sdh.stem_method);
+  NTOHUL(sd->sdh.indexed);
+
+  if (!(buffer = Xmalloc (sd->sdh.index_chars)))
+    {
+      Xfree (sd);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.index_chars;
+
+  if (!(sd->index = Xmalloc (sd->sdh.num_blocks * sizeof (*sd->index))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.num_blocks * sizeof (*sd->index);
+
+  if (!(sd->pos = Xmalloc (sd->sdh.num_blocks * sizeof (*sd->pos))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      Xfree (sd->index);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.num_blocks * sizeof (*sd->pos);
+
+  if (!(sd->buffer = Xmalloc (sd->sdh.block_size * sizeof (*sd->buffer))))
+    {
+      Xfree (sd);
+      Xfree (buffer);
+      Xfree (sd->index);
+      Xfree (sd->buffer);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  sd->MemForStemDict += sd->sdh.block_size * sizeof (*sd->buffer);
+
+  sd->active = -1;
+
+  for (i = 0; i < sd->sdh.num_blocks; i++)
+    {
+      register u_char len;
+      sd->index[i] = buffer;
+      len = Getc (stem_file);
+      *buffer++ = len;
+      Fread (buffer, sizeof (u_char), len, stem_file);
+      buffer += len;
+      Fread (&sd->pos[i], sizeof (*sd->pos), 1, stem_file);
+      NTOHUL(sd->pos[i]); /* [RPAP - Jan 97: Endian Ordering] */
+    }
+
+  mg_errno = MG_NOERROR;
+
+  /*  fprintf (stderr, "mem for stem dict = %i\n", sd->MemForStemDict); */
+
+  return sd;
+}
+
+
+/* [RPAP - Jan 97: Stem Index Change] */
+stemmed_idx *
+ReadStemIdxBlk (File * stem_idx_file)
+{
+  unsigned long i;
+  stemmed_idx *si;
+  u_char *buffer;
+
+  if (!(si = Xmalloc (sizeof (stemmed_idx))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  si->stem_idx_file = stem_idx_file;
+  si->MemForStemIdx = 0;
+
+  Fread (&si->sih, sizeof (si->sih), 1, stem_idx_file);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(si->sih.lookback);
+  NTOHUL(si->sih.block_size);
+  NTOHUL(si->sih.num_blocks);
+  NTOHUL(si->sih.blocks_start);
+  NTOHUL(si->sih.index_chars);
+  NTOHUL(si->sih.num_of_words);
+
+  if (!(buffer = Xmalloc (si->sih.index_chars)))
+    {
+      Xfree (si);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  si->MemForStemIdx += si->sih.index_chars;
+
+  if (!(si->index = Xmalloc (si->sih.num_blocks * sizeof (*si->index))))
+    {
+      Xfree (si);
+      Xfree (buffer);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  si->MemForStemIdx += si->sih.num_blocks * sizeof (*si->index);
+
+  if (!(si->pos = Xmalloc (si->sih.num_blocks * sizeof (*si->pos))))
+    {
+      Xfree (si->index);
+      Xfree (si);
+      Xfree (buffer);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  si->MemForStemIdx += si->sih.num_blocks * sizeof (*si->pos);
+
+  if (!(si->buffer = Xmalloc (si->sih.block_size * sizeof (*si->buffer))))
+    {
+      Xfree (buffer);
+      Xfree (si->index);
+      Xfree (si->buffer);
+      Xfree (si);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    };
+  si->MemForStemIdx += si->sih.block_size * sizeof (*si->buffer);
+
+  si->active = -1;
+
+  for (i = 0; i < si->sih.num_blocks; i++)
+    {
+      register u_char len;
+      si->index[i] = buffer;
+      len = Getc (stem_idx_file);
+      *buffer++ = len;
+      Fread (buffer, sizeof (u_char), len, stem_idx_file);
+      buffer += len;
+      Fread (&si->pos[i], sizeof (*si->pos), 1, stem_idx_file);
+      NTOHUL(si->pos[i]);  /* [RPAP - Jan 97: Endian Ordering] */
+    }
+  mg_errno = MG_NOERROR;
+
+  /*  fprintf (stderr, "mem for stem idx = %i\n", si->MemForStemIdx); */
+
+  return si;
+}
+
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* word should be appropriately stemed */
+static int
+GetIdxBlock (stemmed_idx * si, u_char * word)
+{
+  register int lo = 0, hi = si->sih.num_blocks - 1;
+  register int mid = 0, c = 0;
+
+  while (lo <= hi)
+    {
+      mid = (lo + hi) / 2;
+      c = casecompare (word, si->index[mid]);
+      if (c < 0)
+	hi = mid - 1;
+      else if (c > 0)
+	lo = mid + 1;
+      else
+	return mid;
+    }
+  return hi < 0 ? 0 : (c < 0 ? mid - 1 : mid);
+}
+
+
+static int 
+GetBlock (stemmed_dict * sd, u_char * Word)
+{
+  register int lo = 0, hi = sd->sdh.num_blocks - 1;
+  register int mid = 0, c = 0;
+  while (lo <= hi)
+    {
+      mid = (lo + hi) / 2;
+      c = casecompare (Word, sd->index[mid]);  /* [RPAP - Jan 97: Stem Index Change] */
+      if (c < 0)
+	hi = mid - 1;
+      else if (c > 0)
+	lo = mid + 1;
+      else
+	return mid;
+    }
+  return hi < 0 ? 0 : (c < 0 ? mid - 1 : mid);
+}
+
+
+/*
+ * This function looks up a word in the stemmed dictionary, it returns -1
+ * if the word cound not be found, and 0 if it successfully finds the word.
+ * If count is non-null the ulong it is pointing to is set to the number of 
+ * occurances of the stemmed word in the collection. i.e wcnt.
+ * If doc_count is non-null the ulong it is pointing to is set to the number
+ * of documents that the word occurs in. i.e fcnt
+ * If invf_ptr is non-null the ulong it is pointing to is set to the position
+ * of the inverted file where the entry for this word start.
+ */
+int 
+FindWord (stemmed_dict * sd, u_char * Word, unsigned long *count,
+	  unsigned long *doc_count, unsigned long *invf_ptr,
+	  unsigned long *invf_len)
+{
+  register int lo, hi, mid, c;
+  register unsigned int res;
+  int block, num_indexes;
+  unsigned long *first_word, *last_invf_len;
+  unsigned short *num_words;
+  u_char *base;
+  unsigned short *index;
+  u_char prev[MAXSTEMLEN + 1];
+
+  block = GetBlock (sd, Word);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  if (sd->active != sd->pos[block])
+    {
+      int i;
+
+      Fseek (sd->stem_file, sd->pos[block] + sd->sdh.blocks_start, 0);
+      Fread (sd->buffer, sd->sdh.block_size, sizeof (u_char), sd->stem_file);
+      sd->active = sd->pos[block];
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      first_word = (unsigned long *) (sd->buffer);
+      NTOHUL(*first_word);
+      last_invf_len = (unsigned long *) (first_word + 1);
+      NTOHUL(*last_invf_len);
+      num_words = (unsigned short *) (last_invf_len + 1);
+      NTOHUS(*num_words);
+      index = num_words + 1;
+      num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+
+      for (i = 0; i < num_indexes; i++)
+	NTOHUS(index[i]);
+    }
+  else
+    {
+      first_word = (unsigned long *) (sd->buffer);
+      last_invf_len = (unsigned long *) (first_word + 1);
+      num_words = (unsigned short *) (last_invf_len + 1);
+      index = num_words + 1;
+      num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+    }
+  base = (u_char *) (index + num_indexes);
+
+  lo = 0;
+  hi = num_indexes - 1;
+  while (lo <= hi)
+    {
+      mid = (lo + hi) / 2;
+      c = casecompare (Word, base + index[mid] + 1);  /* [RPAP - Jan 97: Stem Index Change] */
+      if (c < 0)
+	hi = mid - 1;
+      else if (c > 0)
+	lo = mid + 1;
+      else
+	{
+	  hi = mid;
+	  break;
+	}
+    }
+  if (hi < 0)
+    hi = 0;
+
+  res = hi * sd->sdh.lookback;
+  base += index[hi];
+
+  for (;;)
+    {
+      unsigned copy, suff;
+      unsigned long invfp;
+      if (res >= *num_words)
+	return (-1);
+      copy = *base++;
+      suff = *base++;
+      bcopy ((char *) base, (char *) (prev + copy + 1), suff);
+      base += suff;
+      *prev = copy + suff;
+
+      c = casecompare (Word, prev);   /* [RPAP - Jan 97: Stem Index Change] */
+      if (c < 0)
+	return (-1);
+
+      if (c == 0 && doc_count)
+	{
+	  bcopy ((char *) base, (char *) doc_count, sizeof (*doc_count));
+	  NTOHUL(*doc_count);  /* [RPAP - Jan 97: Endian Ordering] */
+	}
+      base += sizeof (*doc_count);
+
+      if (c == 0 && count)
+	{
+	  bcopy ((char *) base, (char *) count, sizeof (*count));
+	  NTOHUL(*count);  /* [RPAP - Jan 97: Endian Ordering] */
+	}
+      base += sizeof (*count);
+
+      if (c == 0 && invf_ptr)
+	{
+	  bcopy ((char *) base, (char *) &invfp, sizeof (invf_ptr));
+	  NTOHUL(invfp);  /* [RPAP - Jan 97: Endian Ordering] */
+	  *invf_ptr = invfp;
+	}
+      base += sizeof (*invf_ptr);
+
+      if (c == 0)
+	{
+	  /* Calculate invf_len is necessary */
+	  unsigned long next_invfp;
+	  if (!invf_len)
+	    return (*first_word + res);
+
+	  /* If the current word is the last word of the block the get the 
+	     length from last_invf_len */
+	  if (res == *num_words - 1)
+	    {
+	      *invf_len = *last_invf_len;
+	      return (*first_word + res);
+	    }
+
+	  /* Skip over most of the next word to get to the invf_ptr */
+	  base++;
+	  suff = *base++;
+	  base += suff + sizeof (unsigned long) * 2;
+	  bcopy ((char *) base, (char *) &next_invfp, sizeof (next_invfp));
+	  NTOHUL(next_invfp);  /* [RPAP - Jan 97: Endian Ordering] */
+	  *invf_len = next_invfp - invfp;
+	  return (*first_word + res);
+	}
+      res++;
+    }
+}
+
+
+/* [RPAP - Jan 97: Stem Index Change] */
+int 
+FindWords (stemmed_dict * sd, u_char * sWord, int stem_method, TermList ** tl)
+{
+  register unsigned int res;
+  unsigned int idx_res;
+  unsigned copy, suff;
+  int j, k;
+
+  int block, num_indexes;
+  unsigned long *first_word, *last_invf_len;
+  unsigned short *num_words;
+  u_char *base;
+  unsigned short *index;
+  u_char prev[MAXSTEMLEN + 1];
+
+  int idx_block, idx_num_indexes;
+  unsigned long *idx_first_word;
+  unsigned short *idx_num_words;
+  u_char *idx_base;
+  unsigned short *idx_index;
+  u_char idx_prev[MAXSTEMLEN + 1];
+
+  unsigned int num_entries, num_cases;
+  unsigned short blk_index, offset;
+  stemmed_idx * si = NULL;
+
+  /* handle stem_method 0 seperately */
+  if (stem_method == 0) {
+    TermEntry te;
+    if ((te.WE.word_num = FindWord (sd, sWord, &te.WE.count, &te.WE.doc_count,
+				   &te.WE.invf_ptr, &te.WE.invf_len)) != -1) {
+      te.WE.max_doc_count = te.WE.doc_count;
+
+      te.Count = 1;
+      te.Word = copy_string (sWord);
+      if (!te.Word)
+	FatalError (1, "Could NOT create memory to add term");
+      te.Stem = copy_string (sWord);
+      if (!te.Stem)
+	FatalError (1, "Could NOT create memory to add term");
+      /*      te.query_mask = NULL;*/
+      
+      AddTermEntry (tl, &te);
+      return (*tl)->num;
+      
+    } else {
+      /* didn't match */
+      return 0;
+    }
+  }
+  
+  if (stem_method == 1)
+    si = sd->stem1;
+  else if (stem_method == 2)
+    si = sd->stem2;
+  else
+    si = sd->stem3;
+
+  /* Locate block */
+  idx_block = GetIdxBlock (si, sWord);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  if (si->active != si->pos[idx_block])
+    {
+      Fseek (si->stem_idx_file, si->pos[idx_block] + si->sih.blocks_start, 0);
+      Fread (si->buffer, si->sih.block_size, sizeof (u_char), si->stem_idx_file);
+      si->active = si->pos[idx_block];
+
+      idx_first_word = (unsigned long *) (si->buffer);
+      NTOHUL(*idx_first_word);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_num_words = (unsigned short *) (idx_first_word + 1);
+      NTOHUS(*idx_num_words);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_index = idx_num_words + 1;
+      idx_num_indexes = ((*idx_num_words - 1) / si->sih.lookback) + 1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < idx_num_indexes; j++)
+	NTOHUS(idx_index[j]);
+    }
+  else
+    {
+      idx_first_word = (unsigned long *) (si->buffer);
+      idx_num_words = (unsigned short *) (idx_first_word + 1);
+      idx_index = idx_num_words + 1;
+      idx_num_indexes = ((*idx_num_words - 1) / si->sih.lookback) + 1;
+    }
+  idx_base = (u_char *) (idx_index + idx_num_indexes);
+  
+  {
+    /* Locate 3-in-4 block */
+    register int lo, hi, mid, c;
+    lo = 0;
+    hi = idx_num_indexes - 1;
+    while (lo <= hi)
+      {
+	mid = (lo + hi) / 2;
+	c = casecompare (sWord, idx_base + idx_index[mid] + 1);
+	if (c < 0)
+	  hi = mid - 1;
+	else if (c > 0)
+	  lo = mid + 1;
+	else
+	  {
+	    hi = mid;
+	    break;
+	  }
+      }
+    if (hi < 0)
+      hi = 0;
+
+    idx_res = hi * si->sih.lookback;
+    idx_base += idx_index[hi];
+  }
+
+  /* Locate actual word entry */
+  for (;;)
+    {
+      int c;
+      if (idx_res >= *idx_num_words)
+	return (-1);
+      copy = *idx_base++;
+      suff = *idx_base++;
+      bcopy ((char *) idx_base, (char *) (idx_prev + copy + 1), suff);
+      idx_base += suff;
+      *idx_prev = copy + suff;
+
+      c = casecompare (sWord, idx_prev);
+      if (c < 0)
+	return (-1);
+     
+      bcopy ((char *) idx_base, (char *) &num_entries, sizeof (num_entries));
+      NTOHUI(num_entries);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_base += sizeof (num_entries);
+      
+      if (c > 0)
+	idx_base += num_entries * (sizeof (num_cases) + sizeof (block) + 
+				   sizeof (blk_index) + sizeof (offset));
+
+      else
+	break;
+
+      idx_res++;
+    }
+
+  for (k = 0; k < num_entries; k++)
+    {
+      unsigned copy, suff;
+      unsigned long invfp;
+      /* Read next stem index pos */
+      bcopy ((char *) idx_base, (char *) &num_cases, sizeof (num_cases));
+      NTOHUI(num_cases);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_base += sizeof (num_cases);
+      bcopy ((char *) idx_base, (char *) &block, sizeof (block));
+      NTOHUI(block);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_base += sizeof (block);
+      bcopy ((char *) idx_base, (char *) &blk_index, sizeof (blk_index));
+      NTOHUS(blk_index);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_base += sizeof (blk_index);
+      bcopy ((char *) idx_base, (char *) &offset, sizeof (offset));
+      NTOHUS(offset);  /* [RPAP - Jan 97: Endian Ordering] */
+      idx_base += sizeof (offset);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      if (sd->active != sd->pos[block])
+	{
+	  Fseek (sd->stem_file, sd->pos[block] + sd->sdh.blocks_start, 0);
+	  Fread (sd->buffer, sd->sdh.block_size, sizeof (u_char), sd->stem_file);
+	  sd->active = sd->pos[block];
+
+	  first_word = (unsigned long *) (sd->buffer);
+	  NTOHUL(*first_word);  /* [RPAP - Jan 97: Endian Ordering] */
+	  last_invf_len = (unsigned long *) (first_word + 1);
+	  NTOHUL(*last_invf_len);  /* [RPAP - Jan 97: Endian Ordering] */
+	  num_words = (unsigned short *) (last_invf_len + 1);
+	  NTOHUS(*num_words);  /* [RPAP - Jan 97: Endian Ordering] */
+	  index = num_words + 1;
+	  num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+
+	  /* [RPAP - Jan 97: Endian Ordering] */
+	  for (j = 0; j < num_indexes; j++)
+	    NTOHUS(index[j]);
+	}
+      else
+	{
+	  first_word = (unsigned long *) (sd->buffer);
+	  last_invf_len = (unsigned long *) (first_word + 1);
+	  num_words = (unsigned short *) (last_invf_len + 1);
+	  index = num_words + 1;
+	  num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+	}
+      base = (u_char *) (index + num_indexes);
+      
+      res = blk_index * sd->sdh.lookback;
+      base += index[blk_index];
+      
+      for (j = 0; j < offset; j++)
+	{
+	  copy = *base++;
+	  suff = *base++;
+	  bcopy ((char *) base, (char *) (prev + copy + 1), suff);
+	  base += suff;
+	  *prev = copy + suff;
+	  base += sizeof (unsigned long);   /* skip doc_count */
+	  base += sizeof (unsigned long);   /* skip count */
+	  base += sizeof (unsigned long);   /* skip invf_ptr */
+	  res++;
+	}
+
+      for (j = 0; j < num_cases; j++)
+	{
+	  TermEntry te;
+	  
+	  if (res >= *num_words)
+	    return (-1);
+	  copy = *base++;
+	  suff = *base++;
+	  bcopy ((char *) base, (char *) (prev + copy + 1), suff);
+	  base += suff;
+	  *prev = copy + suff;
+	      
+	  te.Word = copy_string (prev);
+	  if (!te.Word)
+	    FatalError (1, "Could NOT create memory to add term");
+	  te.Stem = copy_string (prev);
+	  if (!te.Stem)
+	    FatalError (1, "Could NOT create memory to add term");
+	  stemmer (2, sd->sdh.stemmer_num, te.Stem);
+
+	  te.Count = 1;
+	  te.WE.word_num = *first_word + res;
+	  bcopy ((char *) base, (char *) &te.WE.doc_count, sizeof (te.WE.doc_count));
+	  NTOHUL(te.WE.doc_count);  /* [RPAP - Jan 97: Endian Ordering] */
+	  te.WE.max_doc_count = te.WE.doc_count;
+	  base += sizeof (te.WE.doc_count);
+	      
+	  bcopy ((char *) base, (char *) &te.WE.count, sizeof (te.WE.count));
+	  NTOHUL(te.WE.count);
+	  base += sizeof (te.WE.count);
+	      
+	  bcopy ((char *) base, (char *) &invfp, sizeof (te.WE.invf_ptr));
+	  NTOHUL(invfp);  /* [RPAP - Jan 97: Endian Ordering] */
+	  te.WE.invf_ptr = invfp;
+	  base += sizeof (te.WE.invf_ptr);
+		
+	  /* If the current word is the last word of the block the get the 
+	     length from last_invf_len */
+	  if (res == *num_words - 1)
+	    te.WE.invf_len = *last_invf_len;
+	  else
+	    {
+	      unsigned long next_invfp;
+	      u_char *oldbase = base;
+		  
+	      /* Skip over most of the next word to get to the invf_ptr */
+	      base++;
+	      suff = *base++;
+	      base += suff + sizeof (unsigned long) * 2;
+	      bcopy ((char *) base, (char *) &next_invfp, sizeof (next_invfp));
+	      NTOHUL(next_invfp);  /* [RPAP - Jan 97: Endian Ordering] */
+	      te.WE.invf_len = next_invfp - invfp;
+	      base = oldbase;
+	    }
+	      
+	  /* Add term entry to term list */
+	  /*	  te.query_mask = NULL;*/
+	  AddTermEntry (tl, &te);
+	      
+	  if (res == *num_words - 1 && j + 1 < num_cases)
+	    {
+	      int ii;
+	      /* Read in next block */
+	      block++;
+	      Fseek (sd->stem_file, sd->pos[block] + sd->sdh.blocks_start, 0);
+	      Fread (sd->buffer, sd->sdh.block_size, sizeof (u_char), sd->stem_file);
+	      sd->active = sd->pos[block];
+
+	      first_word = (unsigned long *) (sd->buffer);
+	      NTOHUL(*first_word);  /* [RPAP - Jan 97: Endian Ordering] */
+	      last_invf_len = (unsigned long *) (first_word + 1);
+	      NTOHUL(*last_invf_len);  /* [RPAP - Jan 97: Endian Ordering] */
+	      num_words = (unsigned short *) (last_invf_len + 1);
+	      NTOHUS(*num_words);  /* [RPAP - Jan 97: Endian Ordering] */
+	      index = num_words + 1;
+	      num_indexes = ((*num_words - 1) / sd->sdh.lookback) + 1;
+
+	      /* [RPAP - Jan 97: Endian Ordering] */
+	      for (ii = 0; ii < num_indexes; ii++)
+		NTOHUS(index[ii]);
+
+	      base = (u_char *) (index + num_indexes);
+	      base += index[0];
+	      res = 0;
+	      blk_index = 0;
+	    }
+	  else
+	    res++;
+	} /* end for num_cases */
+    } /* end for num_entries */
+  return (*tl)->num;
+}
+
+
+void 
+FreeStemDict (stemmed_dict * sd)
+{
+  /* [RPAP - Jan 97: Stem Index Change] */
+  if (sd->stem1)
+    FreeStemIdx (sd->stem1);
+  if (sd->stem2)
+    FreeStemIdx (sd->stem2);
+  if (sd->stem3)
+    FreeStemIdx (sd->stem3);
+
+  Xfree (sd->index[0]);
+  Xfree (sd->index);
+  Xfree (sd->buffer);
+  Xfree (sd->pos);
+  Xfree (sd);
+}
+
+/* [RPAP - Jan 97: Stem Index Change] */
+void
+FreeStemIdx (stemmed_idx * si)
+{
+  Xfree (si->index[0]);
+  Xfree (si->index);
+  Xfree (si->buffer);
+  Xfree (si->pos);
+  Xfree (si);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stem_search.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stem_search.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stem_search.h	(revision 10506)
@@ -0,0 +1,43 @@
+/**************************************************************************
+ *
+ * stem_search.h -- Functions for searching the blocked stemmed dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_STEM_SEARCH
+#define H_STEM_SEARCH
+
+stemmed_dict *ReadStemDictBlk (File * stem_file);
+
+stemmed_idx *ReadStemIdxBlk (File * stem_idx_file);
+
+int FindWord (stemmed_dict * sd, u_char * Word, unsigned long *count,
+	      unsigned long *doc_count, unsigned long *invf_ptr,
+	      unsigned long *invf_len);
+
+/* [RPAP - Jan 97: Stem Index Change] */
+int FindWords (stemmed_dict * sd, u_char * sWord, int stem_method, TermList ** tl);
+
+void FreeStemDict (stemmed_dict * sd);
+
+/* [RPAP - Jan 97: Stem Index Change] */
+void FreeStemIdx (stemmed_idx * si);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stemmer.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stemmer.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stemmer.c	(revision 10506)
@@ -0,0 +1,142 @@
+/**************************************************************************
+ *
+ * stemmer.c -- The stemmer/case folder
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "stemmer.h"
+
+#include "lovinstem.h"
+#include "simplefrenchstem.h"
+#include "unitool.h"
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:23  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.3  1998/12/17 09:12:54  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.2  1998/11/25 07:55:51  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:42  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:05  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:10  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+#define LOVINSTEMMER        0
+#define SIMPLEFRENCHSTEMMER 1
+
+
+/* decode the utf-8 encoded unicode, casefold and then recode 
+ * making sure the final length doesn't exceed the original
+ * length */
+static void unicode_casefold (u_char *word) {
+  unsigned short out[256]; /* temp space */
+  int i;
+  int len;
+
+  /* decode */
+  utf8_word_to_unicode (word, out, 255);
+  len = out[0];
+
+  /* casefold and simplify-fold */
+  for (i=0; i<len; i++) {
+    out[i+1] = unicode_tosimplified(unicode_tolower(out[i+1]));
+  }
+
+  /* re-code */
+  unicode_to_utf8_word (out, word, word[0]+1);
+}
+
+
+int stemmernumber (u_char *stemmerdescription) {
+  u_char descript[MAX_STEM_DESCRIPTION_LEN];
+  int i;
+
+  /* copy and case-fold the description */
+  for (i=0; (stemmerdescription[i] != '\0') && 
+	 (i < MAX_STEM_DESCRIPTION_LEN-1); i++)
+    descript[i] = tolower (stemmerdescription[i]);
+  descript[i] = '\0';
+
+  /* map the description to its number */
+
+  if ((strcmp (descript, "0") == 0) ||
+      (strcmp (descript, "english") == 0) ||
+      (strcmp (descript, "lovin") == 0))
+    return LOVINSTEMMER;
+
+  if ((strcmp (descript, "1") == 1) ||
+      (strcmp (descript, "french") == 0) ||
+      (strcmp (descript, "simplefrench") == 0))
+    return SIMPLEFRENCHSTEMMER;
+
+  return -1;
+}
+
+
+
+/*
+ * Method 0 - Do not stem or case fold.
+ * Method 1 - Case fold.
+ * Method 2 - Stem.
+ * Method 3 - Case fold and stem.
+ *
+ * The stemmer number should be obtained using
+ * the stemmernumber function above.
+ */
+void 
+stemmer (int method, int stemmer, u_char *word) {
+  if (method & 1) {
+    unicode_casefold (word);
+  }
+
+  if (method & 2) {
+    switch (stemmer) {
+    case LOVINSTEMMER: lovinstem (word);
+      break;
+    case SIMPLEFRENCHSTEMMER: simplefrenchstem (word);
+      break;
+    }
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stemmer.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stemmer.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/stemmer.h	(revision 10506)
@@ -0,0 +1,64 @@
+/**************************************************************************
+ *
+ * stemmer.h -- The stemmer/case folder
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef STEMMER_H
+#define STEMMER_H
+
+#include "sysfuncs.h"
+
+#define STEMMER_MASK 3
+#define MAX_STEM_DESCRIPTION_LEN 16
+
+/* stemmernumber will return the stemmer for
+ * a description of the stemmer. Stemmer descriptions
+ * are not case sensitive. Valid descriptions are:
+ *
+ *   'English'
+ *   'Lovin'
+ *   'French'
+ *   'SimpleFrench'
+ *
+ * More than one description might result in the same
+ * stemmer number (for example, for stemming 'English'
+ * we currently use the 'Lovin' stemmer).
+ *
+ * stemmerdescription is a normal C, null-terminated,
+ * string.
+ *
+ * stemmernumber will return -1 if it doesn't know the
+ * stemmer description.
+ */
+int stemmernumber (u_char *stemmerdescription);
+
+/*
+ * Method 0 - Do not stem or case fold.
+ * Method 1 - Case fold.
+ * Method 2 - Stem.
+ * Method 3 - Case fold and stem.
+ *
+ * The stemmer number should be obtained using function
+ * stemmernumber above.
+ */
+void stemmer (int method, int stemmer, u_char * word);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/term_lists.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/term_lists.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/term_lists.c	(revision 10506)
@@ -0,0 +1,331 @@
+/**************************************************************************
+ *
+ * filename -- description
+ * Copyright (C) 1994  Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:24  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:52  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:43  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:57:07  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "local_strings.h"
+#include "term_lists.h"
+#include "messages.h"
+#include "stemmer.h"
+
+TermList *query_term_list = NULL;
+
+/* =========================================================================
+ * Function: MakeTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+TermList *
+MakeTermList (int n)
+{
+  TermList *t;
+  int list_size = (n == 0 ? 1 : n);	/* always allocate at least one node */
+
+  t = Xmalloc (sizeof (TermList) + (list_size - 1) * sizeof (TermEntry));
+  if (!t)
+    FatalError (1, "Unable to allocate term list");
+
+  t->num = n;
+  t->list_size = list_size;
+
+  return t;
+}
+
+/* =========================================================================
+ * Function: ResizeTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+#define GROWTH_FACTOR 2
+#define MIN_SIZE 2
+
+static void
+ResizeTermList (TermList ** term_list)
+{
+  TermList *tl = *term_list;
+
+  if (tl->num > tl->list_size)
+    {
+      if (tl->list_size)
+	tl->list_size *= GROWTH_FACTOR;
+      else
+	tl->list_size = MIN_SIZE;
+    }
+  tl = Xrealloc (tl, sizeof (TermList) + (tl->list_size - 1) * sizeof (TermEntry));
+
+  if (!tl)
+    FatalError (1, "Unable to resize term list");
+
+  *term_list = tl;
+}
+
+/* =========================================================================
+ * Function: ConvertTermsToString
+ * Description:
+ *      Convert term list into null-terminated string
+ * Input:
+ *      query_term_list = term list
+ * Output:
+ *      str = term string
+ * ========================================================================= */
+
+void
+ConvertTermsToString (TermList * query_term_list, char *str)
+{
+  int i = 0;
+  int total_len = 0;
+
+  /* terms_str should be preallocated */
+  if (!str)
+    return;
+
+  for (i = 0; i < query_term_list->num; i++)
+    {
+      unsigned char *word = query_term_list->TE[i].Word;
+      int len = word[0];
+      total_len += len + 1;	/* +1 for space */
+      if (total_len > MAXTERMSTRLEN)
+	break;
+      strncpy (str, (char *) word + 1, len);
+      str += len;
+      if (i != (query_term_list->num) - 1)
+	{
+	  *str = ' ';
+	  str++;		/* add space gap */
+	}
+
+    }
+  *str = '\0';
+}
+
+/* =========================================================================
+ * Function: ResetTermList
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+ResetTermList (TermList ** tl)
+{
+  if (*tl)
+    FreeTermList (tl);
+  *tl = MakeTermList (0);
+}
+
+/* =========================================================================
+ * Function: AddTermEntry
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+AddTermEntry (TermList ** query_term_list, TermEntry * te)
+{
+  TermList *tl = *query_term_list;
+
+  tl->num++;
+  ResizeTermList (query_term_list);
+  tl = *query_term_list;
+
+  /* copy the structure contents */
+  bcopy ((char *) te, (char *) &(tl->TE[tl->num - 1]), sizeof (TermEntry));
+
+  return tl->num - 1;
+}
+
+
+
+/* =========================================================================
+ * Function: AddTerm
+ * Description: Used in boolean parser - see bool_tree   [RPAP - Feb 97: Term Frequency] 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+int
+AddTerm (TermList ** query_term_list, u_char * Word, int Count, int word_num,
+	 u_long count, u_long doc_count, u_long invf_ptr, u_long invf_len, int stemmer_num)  /* [RPAP - Feb 97: Term Frequency] */
+{
+  int j;
+  TermList *tl = *query_term_list;
+
+  /* Look for the word in the already identified terms */
+  for (j = 0; j < tl->num; j++)
+    {
+      TermEntry *te = &(tl->TE[j]);
+      if (compare (te->Word, Word) == 0)
+	{
+	  te->Count++;
+	  return j;
+	}
+    }
+
+
+  {
+    /* Create a new entry in the list for the new word */
+    TermEntry te;
+
+    /* [RPAP - Feb 97: Term Frequency] */
+    te.WE.word_num = word_num;
+    te.WE.count = count;
+    te.WE.doc_count = doc_count;
+    te.WE.max_doc_count = doc_count;   /* [RPAP - Jan 97: Stem Index Change] */
+    te.WE.invf_ptr = invf_ptr;
+    te.WE.invf_len = invf_len;
+    te.Count = Count;
+    te.Word = copy_string (Word);
+    if (!te.Word)
+      FatalError (1, "Could NOT create memory to add term");
+
+    /* [RPAP - Jan 97: Stem Index Change] */
+    te.Stem = copy_string (Word);
+    if (!te.Stem)
+      FatalError (1, "Could NOT create memory to add term");
+    stemmer (2, stemmer_num, te.Stem);
+
+    te.require_match = 0;  /* [RJM - 07/97: Ranked Required Terms] */
+
+    return AddTermEntry (query_term_list, &te);
+  }
+
+}
+
+/* =========================================================================
+ * Function: FreeTermList
+ * Description:
+ * Input:
+ * Output:
+ * ========================================================================= */
+
+void
+FreeTermList (TermList ** the_tl)
+{
+  int j;
+  TermList *tl = *the_tl;
+
+  for (j = 0; j < tl->num; j++)
+    {
+      if (tl->TE[j].Word)
+	Xfree (tl->TE[j].Word);
+      /* [RPAP - Jan 97: Stem Index Change] */
+      if (tl->TE[j].Stem)
+	Xfree (tl->TE[j].Stem);
+    }
+  Xfree (tl);
+
+  *the_tl = NULL;
+}
+
+/* =========================================================================
+ * Function: PrintWordEntry
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+PrintWordEntry (WordEntry * we, FILE * file)
+{
+  fprintf (file, "we->word_num = %d\n", we->word_num);
+  fprintf (file, "we->count = %ld\n", we->count);
+  fprintf (file, "we->doc_count = %ld\n", we->doc_count);
+  fprintf (file, "we->max_doc_count = %ld\n", we->max_doc_count);
+  fprintf (file, "we->invf_ptr = %ld\n", we->invf_ptr);
+  fprintf (file, "we->invf_len = %ld\n", we->invf_len);
+}
+
+/* =========================================================================
+ * Function: PrintTermEntry
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+PrintTermEntry (TermEntry * te, FILE * file)
+{
+
+  fprintf (file, "Term Entry\n");
+  fprintf (file, "te->Count = %d\n", te->Count);
+  fprintf (file, "te->Word = %s\n", str255_to_string (te->Word, NULL));
+  if (te->Stem != NULL)
+    fprintf (file, "te->Stem = %s\n", str255_to_string (te->Stem, NULL));  /* [RPAP - Jan 97: Stem Index Change] */
+  fprintf (file, "te->require_match = %i\n", te->require_match);  /* [RJM 07/97: Ranked Required Terms] */
+  PrintWordEntry (&(te->WE), file);
+
+}
+
+/* =========================================================================
+ * Function: PrintTermList
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+void
+PrintTermList (TermList * tl, FILE * file)
+{
+  int i;
+
+  fprintf (file, "Term List\n");
+  fprintf (file, "tl->list_size = %d\n", tl->list_size);
+  fprintf (file, "tl->num = %d\n", tl->num);
+
+  for (i = 0; i < tl->num; i++)
+    {
+      fprintf (file, "[%d]\n", i);
+      PrintTermEntry (&(tl->TE[i]), file);
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/term_lists.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/term_lists.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/term_lists.h	(revision 10506)
@@ -0,0 +1,102 @@
+/**************************************************************************
+ *
+ * term_lists.h -- description
+ * Copyright (C) 1994  Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:24  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/11/25 07:55:52  rjmcnab
+
+   Modified mg to that you can specify the stemmer you want
+   to use via a command line option. You specify it to
+   mg_passes during the build process. The number of the
+   stemmer that you used is stored within the inverted
+   dictionary header and the stemmed dictionary header so
+   the correct stemmer is used in later stages of building
+   and querying.
+
+   Revision 1.1  1998/11/17 09:35:44  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.1  1994/10/20  03:57:08  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+ */
+
+#ifndef TERM_LISTS_H
+#define TERM_LISTS_H
+
+#include "sysfuncs.h"
+
+#define MAXTERMSTRLEN 1023	/* maximum number of characters in term string */
+
+typedef struct WordEntry
+  {
+    int word_num;		/* Unique number for each different word */
+    u_long count;		/* Number of times the word occurs in the text */
+    u_long doc_count;		/* Number of documents that contain the word */
+    u_long max_doc_count;       /* [RPAP - Jan 97: Stem Index Change] */
+    u_long invf_ptr;		/* This is a byte position of the  
+				   inverted file entry corresponding to the word */
+    u_long invf_len;		/* This is the length of the inverted 
+				   file entry in bytes */
+  }
+WordEntry;
+
+typedef struct TermEntry
+  {
+    WordEntry WE;
+    int Count;			/* The number of times the word occurs in the query */
+    u_char *Word;		/* The word. */
+    u_char *Stem;               /* [RPAP - Jan 97: Stem Index Change] - The stemmed non-cf version of Word */
+    int require_match;          /* [RJM 07/97: Ranked Required Terms] 0=optional match, 1=must match */
+  }
+TermEntry;
+
+typedef struct TermList
+  {
+    int list_size;
+    int num;
+    TermEntry TE[1];
+  }
+TermList;
+
+#define GetNthWE(term_list, n) (&((term_list)->TE[(n)].WE))
+
+/* --- prototypes --- */
+void ConvertTermsToString (TermList * query_term_list, char *str);
+int AddTermEntry (TermList ** query_term_list, TermEntry * te);
+int AddTerm (TermList ** query_term_list, u_char * Word, int Count, int word_num,
+	     u_long count, u_long doc_count, u_long invf_ptr, u_long invf_len, /* [RPAP - Feb 97: Term Frequency] */
+	     int stemmer_num);  
+void ResetTermList (TermList ** tl);
+void FreeTermList (TermList ** the_tl);
+void PrintWordEntry (WordEntry * we, FILE * file);
+void PrintTermEntry (TermEntry * te, FILE * file);
+void PrintTermList (TermList * tl, FILE * file);
+TermList *MakeTermList (int n);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text.h	(revision 10506)
@@ -0,0 +1,176 @@
+/**************************************************************************
+ *
+ * text.h -- Header file for compression related stuff
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+
+#ifndef H_TEXT
+#define H_TEXT
+
+#include "huffman.h"
+
+
+
+
+
+/*****************************************************************************
+ *
+ * There are several different methods of compressing the text of the
+ * database. The following defines list the different methods of text
+ * compression
+ *
+ */
+
+
+/* The dictionary contains all the fragments that occur in the collection
+   i.e. escapes are not possible */
+#define MG_COMPLETE_DICTIONARY 0
+
+
+/* Certain words have been deleted from the dictionary. The words deleted
+   have been used to create the frequency huffman codes of the characters. 
+   This dictionary has an escape code and may be used to compress novel
+   words. This dictionary may fail if there is a novel character. */
+#define MG_PARTIAL_DICTIONARY 1
+
+
+/* This dictionary has an escape so that novel words and non-words can be 
+   coded. The method for coding the novel words and non-words is determined
+   by a dictionary parameter. */
+#define MG_SEED_DICTIONARY 2
+
+
+
+
+
+
+
+
+
+/*****************************************************************************
+ *
+ * With a seed dictionary there are several methods for coding the novel
+ * words and non-words the following defined values specify the different
+ * methods of coding.
+ *
+ */
+
+
+/* Code novel words and non-words character by character using huffman codes.
+   The huffman codes for the word and non-word lengths and characters are 
+   generated from the distribution of lengths and characters in the
+   dictionary. */
+#define MG_NOVEL_HUFFMAN_CHARS 0
+
+
+/* This method codes novel words using binary codes. The novel words are stored
+   in a auxillary dictionary which is built by pass two. */
+#define MG_NOVEL_BINARY 1
+
+
+/* This method codes novel words using delta codes. The novel words are stored
+   in a auxillary dictionary which is built by pass two. */
+#define MG_NOVEL_DELTA 2
+
+
+/* This method codes novel words using hybrid version of delta. The novel
+   words are stored in a auxillary dictionary which is built by pass two. */
+#define MG_NOVEL_HYBRID 3
+
+
+/* This method codes novel words using hybrid version of delta and a MTF
+   operation. The novel words are stored in a auxillary dictionary which
+   is built by pass two. */
+#define MG_NOVEL_HYBRID_MTF 4
+
+
+
+
+
+
+/* This specified an amount of extra space allocated in the
+   compression_dict_header for adding new parameters. As new
+   parameters are added this should be decreased. */
+#define TEXT_PARAMS 15
+
+
+
+typedef struct compression_dict_header
+  {
+    u_long dict_type;
+    u_long novel_method;
+    u_long params[TEXT_PARAMS];
+    u_long num_words[2];
+    u_long num_word_chars[2];
+    u_long lookback;
+  }
+compression_dict_header;
+
+
+typedef struct comp_frags_header
+  {
+    huff_data hd;
+    u_long uncompressed_size;
+    u_long huff_words_size[MAX_HUFFCODE_LEN + 1];
+  }
+comp_frags_header;
+
+
+
+typedef struct compressed_text_header
+  {
+    u_long num_of_docs;
+    u_long num_of_words;	/* number of words in collection */
+    double num_of_bytes; /* [RJM 07/97: 4G limit] */
+    double ratio;
+    u_long length_of_longest_doc;	/* (characters) */
+    u_long dummy;    /* added to make the structure the same on different architectures */
+  }
+compressed_text_header;
+
+
+typedef struct compression_stats_header
+  {
+    u_long num_docs;
+    u_long dummy;   /* added to make the structure the same on different architectures */
+    double num_bytes; /* [RJM 07/97: 4G limit] */
+  }
+compression_stats_header;
+
+
+typedef struct frags_stats_header
+  {
+    u_long num_frags;
+    u_long mem_for_frags;
+  }
+frags_stats_header;
+
+
+typedef struct aux_frags_header
+  {
+    u_long num_frags;
+    u_long mem_for_frags;
+  }
+aux_frags_header;
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text.pass1.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text.pass1.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text.pass1.c	(revision 10506)
@@ -0,0 +1,409 @@
+/**************************************************************************
+ *
+ * text.pass1.c -- Text compression (Pass 1)
+ * Copyright (C) 1994  Neil Sharman, Gary Eddy and Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "huffman.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+#include "mg_files.h"
+#include "mg.h"
+#include "build.h"
+#include "locallib.h"
+#include "words.h"
+#include "text.h"
+#include "hash.h"
+#include "local_strings.h"
+/* for more meaningful messages - jrm21 (gsdl) */
+#ifdef HAVE_STRERROR
+#include <string.h>
+#include <errno.h>
+#endif
+
+#define POOL_SIZE 1024*1024
+#define INITIAL_HASH_SIZE 7927
+
+
+typedef struct hash_rec
+  {
+    unsigned long wcnt;		/* word frequency */
+    unsigned long occurance_num;
+    u_char *word;
+  }
+hash_rec;
+
+typedef struct dict_data
+  {
+    hash_rec *HashTable;
+    unsigned long HashSize;
+    unsigned long HashUsed;
+    unsigned long wordnum;
+    unsigned long words_read;
+    unsigned long bytes_diff;
+    huff_data hd;
+  }
+dict_data;
+
+
+
+static unsigned long LongestDoc = 0;
+static unsigned long occurance_num = 0;
+static dict_data DictData[2];
+
+static u_char *Pool;
+static int PoolLeft;
+static double inputbytes = 0; /* [RJM 07/97: 4G limit] */
+static unsigned long MaxMemInUse = 0;
+static unsigned long MemInUse = 0;
+static compression_stats_header csh =
+{0, 0.0}; /* [RJM 07/97: 4G limit] */
+
+
+static void 
+ChangeMem (int Change)
+{
+  MemInUse += Change;
+  if (MemInUse > MaxMemInUse)
+    MaxMemInUse = MemInUse;
+}
+
+
+
+
+int 
+init_text_1 (char *FileName)
+{
+  int which;
+
+  if (!(Pool = Xmalloc (POOL_SIZE)))
+    {
+      Message ("Unable to allocate memory for pool");
+      return (COMPERROR);
+    }
+  PoolLeft = POOL_SIZE;
+  ChangeMem (POOL_SIZE);
+
+  for (which = 1; which >= 0; which--)
+    {
+      u_char *word;
+      hash_rec *ent;
+      dict_data *dd = &DictData[which];
+
+      dd->wordnum = 0;
+      dd->words_read = 0;
+      dd->bytes_diff = 0;
+      dd->HashSize = INITIAL_HASH_SIZE;
+      dd->HashUsed = 0;
+
+      if (!(dd->HashTable = Xmalloc (sizeof (hash_rec) * dd->HashSize)))
+	{
+	  Message ("Unable to allocate memory for table");
+	  return (COMPERROR);
+	}
+      ChangeMem (sizeof (hash_rec) * dd->HashSize);
+      bzero ((char *) (dd->HashTable), sizeof (hash_rec) * dd->HashSize);
+
+      word = Pool;
+      *Pool++ = '\0';
+      PoolLeft--;
+      {
+	register u_char *wptr;
+	register int hsize = dd->HashSize;
+	register unsigned long hashval, step;
+
+	HASH (hashval, step, word, hsize);
+	wptr = (dd->HashTable + hashval)->word;
+	while (wptr)
+	  {
+	    hashval += step;
+	    if (hashval >= hsize)
+	      hashval -= hsize;
+	    wptr = (dd->HashTable + hashval)->word;
+	  }
+	ent = dd->HashTable + hashval;
+      }
+      ent->wcnt = 1;
+      ent->word = word;
+      dd->HashUsed = 1;
+    }
+  return (COMPALLOK);
+}
+
+
+
+
+int 
+process_text_1 (u_char * s_in, int l_in)
+{
+  int which;
+  u_char *end = s_in + l_in - 1;
+
+  if (l_in > LongestDoc)
+    LongestDoc = l_in;
+
+  csh.num_docs++;
+  csh.num_bytes += l_in;
+
+  which = inaword (s_in, end);
+  /*
+   ** Alternately parse off words and non-words from the input
+   ** stream beginning with a non-word. Each token is then
+   ** inserted into the set if it does not exist or has it's
+   ** frequency count incremented if it does.
+   */
+  for (; s_in <= end; which = !which)
+    {
+      u_char Word[MAXWORDLEN + 1];
+      dict_data *dd = &DictData[which];
+
+      /* First parse a word or non-word out of the string */
+      if (which)
+	PARSE_WORD (Word, s_in, end);
+      else
+	PARSE_NON_WORD (Word, s_in, end);
+
+      dd->wordnum++;
+      inputbytes += *Word;
+      dd->words_read++;
+
+      /* Search the hash table for Word */
+      {
+	register unsigned long hashval, step;
+	register int hsize = dd->HashSize;
+	HASH (hashval, step, Word, hsize);
+	for (;;)
+	  {
+	    register u_char *s1;
+	    register u_char *s2;
+	    register int len;
+	    register hash_rec *ent;
+	    ent = dd->HashTable + hashval;
+	    if (!ent->word)
+	      {
+		int len = *Word + 1;
+		if (len > PoolLeft)
+		  {
+		    if (!(Pool = Xmalloc (POOL_SIZE)))
+		      {
+			Message ("Unable to allocate memory for pool");
+			return (COMPERROR);
+		      }
+		    PoolLeft = POOL_SIZE;
+		    ChangeMem (POOL_SIZE);
+		  }
+		ent->occurance_num = occurance_num++;
+		ent->wcnt = 1;
+		ent->word = Pool;
+		memcpy (Pool, Word, len);
+		Pool += len;
+		PoolLeft -= len;
+		dd->HashUsed++;
+		dd->bytes_diff += Word[0];
+		break;
+	      }
+
+	    /* Compare the words */
+	    s1 = Word;
+	    s2 = ent->word;
+	    len = *s1 + 1;
+	    for (; len; len--)
+	      if (*s1++ != *s2++)
+		break;
+
+	    if (len)
+	      {
+		hashval = (hashval + step);
+		if (hashval >= hsize)
+		  hashval -= hsize;
+	      }
+	    else
+	      {
+		ent->wcnt++;
+		break;
+	      }
+	  }
+      }
+
+
+      if (dd->HashUsed >= dd->HashSize >> 1)
+	{
+	  hash_rec *ht;
+	  unsigned long size;
+	  unsigned long i;
+	  size = prime (dd->HashSize * 2);
+	  if (!(ht = Xmalloc (sizeof (hash_rec) * size)))
+	    {
+	      Message ("Unable to allocate memory for table");
+	      return (COMPERROR);
+	    }
+	  ChangeMem (sizeof (hash_rec) * size);
+	  bzero ((char *) ht, sizeof (hash_rec) * size);
+
+	  for (i = 0; i < dd->HashSize; i++)
+	    if (dd->HashTable[i].word)
+	      {
+		register u_char *wptr;
+		register unsigned long hashval, step;
+
+		wptr = dd->HashTable[i].word;
+		HASH (hashval, step, wptr, size);
+		wptr = (ht + hashval)->word;
+		while (wptr)
+		  {
+		    hashval += step;
+		    if (hashval >= size)
+		      hashval -= size;
+		    wptr = (ht + hashval)->word;
+		  }
+		ht[hashval] = dd->HashTable[i];
+	      }
+	  Xfree (dd->HashTable);
+	  ChangeMem (-sizeof (hash_rec) * dd->HashSize);
+	  dd->HashTable = ht;
+	  dd->HashSize = size;
+
+
+	}
+    }
+  return (COMPALLOK);
+}				/* encode */
+
+
+
+static int 
+PackHashTable (dict_data * dd)
+{
+  int s, d;
+  for (s = d = 0; s < dd->HashSize; s++)
+    if (dd->HashTable[s].word)
+      dd->HashTable[d++] = dd->HashTable[s];
+  ChangeMem (-sizeof (hash_rec) * dd->HashSize);
+  ChangeMem (sizeof (hash_rec) * dd->HashUsed);
+  if (!(dd->HashTable = Xrealloc (dd->HashTable,
+				  sizeof (hash_rec) * dd->HashUsed)))
+    {
+      Message ("Out of memory");
+      return COMPERROR;
+    }
+  dd->HashSize = dd->HashUsed;
+  return COMPALLOK;
+}
+
+
+
+
+
+static int 
+ent_comp (const void *s1, const void *s2)
+{
+  return casecompare (((hash_rec *) s1)->word, ((hash_rec *) s2)->word);
+}
+
+
+
+static void 
+WriteHashTable (FILE * fp, dict_data * dd)
+{
+  frags_stats_header fsh;
+  u_long j = 0;
+  u_char *curr;
+
+  if (PackHashTable (dd) == COMPERROR)
+    return;
+
+  qsort (dd->HashTable, dd->HashUsed, sizeof (hash_rec), ent_comp);
+
+  fsh.num_frags = dd->HashSize;
+  fsh.mem_for_frags = dd->HashSize;
+  for (j = 0; j < dd->HashSize; j++)
+    fsh.mem_for_frags += dd->HashTable[j].word[0];
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(fsh.num_frags);
+  HTONUL(fsh.mem_for_frags);
+
+  fwrite (&fsh, sizeof (fsh), 1, fp);
+
+  for (j = 0; j < dd->HashSize; j++)
+    {
+      curr = dd->HashTable[j].word;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(dd->HashTable[j].wcnt);
+      HTONUL(dd->HashTable[j].occurance_num);
+
+      fwrite (&dd->HashTable[j].wcnt, sizeof (dd->HashTable[j].wcnt), 1, fp);
+      fwrite (&dd->HashTable[j].occurance_num,
+	      sizeof (dd->HashTable[j].occurance_num), 1, fp);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(dd->HashTable[j].wcnt);
+      NTOHUL(dd->HashTable[j].occurance_num);
+
+      fwrite (curr, sizeof (u_char), curr[0] + 1, fp);
+    }
+}
+
+
+int 
+done_text_1 (char *file_name)
+{
+  char *temp_str;
+  FILE *fp;
+
+  if (!(fp = create_file (file_name, TEXT_STATS_DICT_SUFFIX, "wb",
+			  MAGIC_STATS_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fprintf(stderr,"Couldn't create file %s%s:%s\n",
+	      file_name, TEXT_STATS_DICT_SUFFIX,
+#if defined(HAVE_STRERROR) || defined(__WIN32__)
+	      strerror(errno)
+#else
+	      " "
+#endif
+	      );
+      return COMPERROR;
+    }
+
+  temp_str = msg_prefix;
+  msg_prefix = "text.pass1";
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(csh.num_docs);
+  HTOND(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  fwrite (&csh, sizeof (csh), 1, fp);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  WriteHashTable (fp, &DictData[0]);
+  WriteHashTable (fp, &DictData[1]);
+  msg_prefix = temp_str;
+  fclose(fp);
+  return COMPALLOK;
+}				/* done_encode */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text.pass2.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text.pass2.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text.pass2.c	(revision 10506)
@@ -0,0 +1,788 @@
+/**************************************************************************
+ *
+ * text.pass2.c -- Text compression (Pass 2)
+ * Copyright (C) 1994  Neil Sharman, Gary Eddy and Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_m_mem.h"
+#include "bitio_m.h"
+#include "huffman.h"
+#include "bitio_stdio.h"
+#include "huffman_stdio.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg.h"
+#include "mg_files.h"
+#include "build.h"
+#include "words.h"
+#include "text.h"
+#include "hash.h"
+#include "locallib.h"
+#include "comp_dict.h"
+
+
+
+
+/*
+   $Log$
+   Revision 1.2  2002/01/22 02:41:14  jrm21
+   Try to print out an error if the aux file couldn't be written to.
+
+   Revision 1.1  1999/08/10 21:18:25  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.2  1998/12/17 09:12:54  rjmcnab
+
+   Altered mg to process utf-8 encoded Unicode. The main changes
+   are in the parsing of the input, the casefolding, and the stemming.
+
+   Revision 1.1  1998/11/17 09:35:47  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:10  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:14  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+#define POOL_SIZE 1024*256
+
+typedef struct char_pool
+  {
+    struct char_pool *next;
+    u_long left;
+    u_char *ptr;
+    u_char pool[POOL_SIZE];
+  }
+char_pool;
+
+typedef struct novel_hash_rec
+  {
+    u_long ordinal_num;
+    u_char *word;
+  }
+novel_hash_rec;
+
+
+#define INITIAL_HASH_SIZE 7927
+#define MAX_SWAPS 10000
+
+typedef struct novel_hash_table
+  {
+    novel_hash_rec *HashTable;
+    u_long HashSize, HashUsed;
+    char_pool *first_pool;
+    char_pool *pool;
+    u_long next_num, binary_start;
+    novel_hash_rec **code_to_nhr;
+  }
+novel_hash_table;
+
+
+static FILE *text, *text_idx;
+
+static u_char *comp_buffer;
+
+static u_long text_length;
+
+/* [RJM 07/97: 4G limit] */
+static double stats_in_tot_bytes = 0.0;
+static double stats_in_bytes = 0.0;
+static double stats_out_bytes = 0.0;
+
+
+static novel_hash_table nht[2];
+
+static u_long prefix_len = 0;
+
+int blk_start[2][33], blk_end[2][33];
+
+
+static char_pool *
+new_pool (char_pool * pool)
+{
+  char_pool *p = Xmalloc (sizeof (char_pool));
+  if (!p)
+    FatalError (1, "Unable to allocate memory for pool");
+  if (pool)
+    pool->next = p;
+  p->next = NULL;
+  p->left = POOL_SIZE;
+  p->ptr = p->pool;
+  return p;
+}
+
+
+
+int 
+init_text_2 (char *file_name)
+{
+  char path[512];
+  int i;
+
+  if (LoadCompressionDictionary (make_name (file_name, TEXT_DICT_SUFFIX,
+					    path)) == COMPERROR)
+    return COMPERROR;
+
+  if (!(text = create_file (file_name, TEXT_SUFFIX, "w+b",
+			    MAGIC_TEXT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+
+  bzero ((char *) &cth, sizeof (cth));
+
+  if (fwrite (&cth, sizeof (cth), 1, text) != 1)
+    return COMPERROR;
+
+  text_length = sizeof (u_long) + sizeof (cth);
+
+  if (!(text_idx = create_file (file_name, TEXT_IDX_SUFFIX, "w+b",
+				MAGIC_TEXI, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+
+  if (fwrite (&cth, sizeof (cth), 1, text_idx) != 1)
+    return COMPERROR;
+
+  if (!(comp_buffer = Xmalloc (sizeof (u_char) * buf_size)))
+    {
+      Message ("No memory for compression buffer");
+      return (COMPERROR);
+    }
+
+#if 0
+  MaxMemInUse += sizeof (u_char) * buf_size;
+#endif
+
+  if (cdh.novel_method != MG_NOVEL_HUFFMAN_CHARS)
+    for (i = 0; i <= 1; i++)
+      {
+	nht[i].HashSize = INITIAL_HASH_SIZE;
+	nht[i].HashTable = Xmalloc (sizeof (novel_hash_rec) * nht[i].HashSize);
+	bzero ((char *) nht[i].HashTable,
+	       sizeof (novel_hash_rec) * nht[i].HashSize);
+	nht[i].HashUsed = 0;
+	nht[i].HashSize = INITIAL_HASH_SIZE;
+	nht[i].pool = nht[i].first_pool = new_pool (NULL);
+	nht[i].next_num = 1;
+	nht[i].binary_start = 1;
+	if (cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+	  nht[i].code_to_nhr = Xmalloc (sizeof (novel_hash_rec *) *
+					((nht[i].HashSize >> 1) + 2));
+	else
+	  nht[i].code_to_nhr = NULL;
+	if (cdh.novel_method == MG_NOVEL_HYBRID ||
+	    cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+	  {
+	    int num;
+	    num = 1;
+	    blk_start[i][0] = 0;
+	    blk_end[i][0] = cdh.num_words[i] - 1;
+	    while (num < 33)
+	      {
+		blk_start[i][num] = blk_end[i][num - 1] + 1;
+		blk_end[i][num] = blk_start[i][num] +
+		  (blk_end[i][num - 1] - blk_start[i][num - 1]) * 2;
+		num++;
+	      }
+	  }
+      }
+
+  return (COMPALLOK);
+}
+
+
+
+int 
+ic (void *a, void *b)
+{
+  return *((int *) a) - *((int *) b);
+}
+
+
+
+/* #define DOCDUMP 477 */
+
+int 
+process_text_2 (u_char * s_in, int l_in)
+{
+  int which, byte_length;
+  u_char *end = s_in + l_in - 1;
+  int novels_used[2];
+  int swaps[2][MAX_SWAPS];
+
+  which = inaword (s_in, end);
+
+  ENCODE_START (comp_buffer, buf_size)
+
+    ENCODE_BIT (which);
+
+  if (cdh.novel_method == MG_NOVEL_BINARY)
+    {
+      DELTA_ENCODE_L (nht[0].binary_start, prefix_len);
+      DELTA_ENCODE_L (nht[1].binary_start, prefix_len);
+    }
+
+  novels_used[0] = novels_used[1] = 0;
+
+#ifdef DOCDUMP
+  if (cth.num_of_docs == DOCDUMP)
+    {
+      printf ("---------------------------------------------------\n");
+      printf ("which = %d\n", which);
+    }
+#endif
+
+  for (; s_in <= end; which = !which)
+    {
+      u_char Word[MAXWORDLEN + 1];
+      int res;
+
+      if (which)
+	cth.num_of_words++;
+
+      /* First parse a word or non-word out of the string */
+      if (which)
+	PARSE_WORD (Word, s_in, end);
+      else
+	PARSE_NON_WORD (Word, s_in, end);
+
+#ifdef DOCDUMP
+      if (cth.num_of_docs == DOCDUMP)
+	{
+	  printf ("%sword : \"%.*s\"", which ? "    " : "non-", Word[0], Word + 1);
+	}
+#endif
+
+      /* Search the hash table for Word */
+      if (ht[which])
+	{
+	  register unsigned long hashval, step;
+	  register int tsize = ht[which]->size;
+	  register u_char **wptr;
+	  HASH (hashval, step, Word, tsize);
+	  for (;;)
+	    {
+	      register u_char *s1;
+	      register u_char *s2;
+	      register int len;
+	      wptr = ht[which]->table[hashval];
+	      if (wptr == NULL)
+		{
+		  res = COMPERROR;
+		  break;
+		}
+
+	      /* Compare the words */
+	      s1 = Word;
+	      s2 = *wptr;
+	      len = *s1 + 1;
+	      for (; len; len--)
+		if (*s1++ != *s2++)
+		  break;
+
+	      if (len)
+		{
+		  hashval += step;
+		  if (hashval >= tsize)
+		    hashval -= tsize;
+		}
+	      else
+		{
+		  res = ht[which]->table[hashval] - ht[which]->words;
+		  break;
+		}
+	    }
+	}
+      else
+	res = COMPERROR;
+      /* Check that the word was found in the dictionary */
+      if (res == COMPERROR)
+	{
+	  if (cdh.dict_type == MG_COMPLETE_DICTIONARY)
+	    {
+	      Message ("Unknown word \"%.*s\"\n", *Word, Word + 1);
+	      return (COMPERROR);
+	    }
+	  if (cdh.dict_type == MG_PARTIAL_DICTIONARY)
+	    {
+	      u_long i;
+	      if (ht[which])
+		{
+		  res = ht[which]->hd->num_codes - 1;
+		  HUFF_ENCODE (res, ht[which]->codes, ht[which]->hd->clens);
+		}
+	      HUFF_ENCODE (Word[0], lens_codes[which], lens_huff[which].clens);
+	      for (i = 0; i < Word[0]; i++)
+		HUFF_ENCODE (Word[i + 1], char_codes[which],
+			     char_huff[which].clens);
+	    }
+	  if (cdh.dict_type == MG_SEED_DICTIONARY)
+	    {
+	      if (ht[which])
+		{
+		  res = ht[which]->hd->num_codes - 1;
+		  HUFF_ENCODE (res, ht[which]->codes, ht[which]->hd->clens);
+		}
+	      switch (cdh.novel_method)
+		{
+		case MG_NOVEL_HUFFMAN_CHARS:
+		  {
+		    u_long i;
+		    HUFF_ENCODE (Word[0], lens_codes[which],
+				 lens_huff[which].clens);
+		    for (i = 0; i < Word[0]; i++)
+		      HUFF_ENCODE (Word[i + 1], char_codes[which],
+				   char_huff[which].clens);
+		  }
+		  break;
+		case MG_NOVEL_BINARY:
+		case MG_NOVEL_DELTA:
+		case MG_NOVEL_HYBRID:
+		case MG_NOVEL_HYBRID_MTF:
+		  {
+		    register unsigned long hashval, step;
+		    register novel_hash_table *h = &nht[which];
+		    register int hsize = h->HashSize;
+		    register novel_hash_rec *ent;
+		    HASH (hashval, step, Word, hsize);
+		    for (;;)
+		      {
+			register u_char *s1, *s2;
+			register int len;
+			ent = h->HashTable + hashval;
+			if (!ent->word)
+			  {
+			    int len = *Word + 1;
+			    if (len > h->pool->left)
+			      h->pool = new_pool (h->pool);
+			    ent->word = h->pool->ptr;
+			    ent->ordinal_num = h->next_num++;
+			    if (cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+			      h->code_to_nhr[ent->ordinal_num - 1] = ent;
+			    memcpy (h->pool->ptr, Word, len);
+			    h->pool->ptr += len;
+			    h->pool->left -= len;
+			    h->HashUsed++;
+			    break;
+			  }
+			/* Compare the words */
+			s1 = Word;
+			s2 = ent->word;
+			len = *s1 + 1;
+			for (; len; len--)
+			  if (*s1++ != *s2++)
+			    break;
+
+			if (!len)
+			  break;
+
+			hashval = (hashval + step);
+			if (hashval >= hsize)
+			  hashval -= hsize;
+		      }
+
+		    switch (cdh.novel_method)
+		      {
+		      case MG_NOVEL_BINARY:
+			{
+			  BINARY_ENCODE (ent->ordinal_num, h->binary_start);
+			  if (ent->ordinal_num == h->binary_start)
+			    h->binary_start++;
+			}
+			break;
+		      case MG_NOVEL_DELTA:
+			{
+			  DELTA_ENCODE (ent->ordinal_num);
+			}
+			break;
+		      case MG_NOVEL_HYBRID:
+			{
+			  int k = 0;
+			  int j = ent->ordinal_num - 1;
+			  while (j > blk_end[which][k])
+			    k++;
+			  assert (j - blk_start[which][k] + 1 >= 1 &&
+				  j - blk_start[which][k] + 1 <=
+			       blk_end[which][k] - blk_start[which][k] + 1);
+
+			  GAMMA_ENCODE (k + 1);
+			  BINARY_ENCODE (j - blk_start[which][k] + 1,
+					 blk_end[which][k] -
+					 blk_start[which][k] + 1);
+			}
+			break;
+		      case MG_NOVEL_HYBRID_MTF:
+			{
+			  int k = 0;
+			  int j = ent->ordinal_num - 1;
+			  while (j > blk_end[which][k])
+			    k++;
+			  assert (j - blk_start[which][k] + 1 >= 1 &&
+				  j - blk_start[which][k] + 1 <=
+			       blk_end[which][k] - blk_start[which][k] + 1);
+			  GAMMA_ENCODE (k + 1);
+			  BINARY_ENCODE (j - blk_start[which][k] + 1,
+					 blk_end[which][k] -
+					 blk_start[which][k] + 1);
+
+			  if (ent->ordinal_num - 1 >= novels_used[which])
+			    {
+			      int a = novels_used[which];
+			      int b = ent->ordinal_num - 1;
+			      novel_hash_rec *temp;
+
+
+/*                            fprintf(stderr, "a = %d , b = %d\n", a, b);
+ */
+			      temp = h->code_to_nhr[a];
+			      h->code_to_nhr[a] = h->code_to_nhr[b];
+			      h->code_to_nhr[b] = temp;
+			      h->code_to_nhr[a]->ordinal_num = a + 1;
+			      h->code_to_nhr[b]->ordinal_num = b + 1;
+			      if (novels_used[which] == MAX_SWAPS)
+				FatalError (1, "Not enough mem for swapping");
+			      swaps[which][novels_used[which]] = b;
+			      novels_used[which]++;
+			    }
+			}
+			break;
+		      }
+		    if (h->HashUsed >= h->HashSize >> 1)
+		      {
+			novel_hash_rec *ht;
+			unsigned long size;
+			unsigned long i;
+			size = prime (h->HashSize * 2);
+			if (cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+			  {
+			    Xfree (h->code_to_nhr);
+			    h->code_to_nhr = Xmalloc (sizeof (novel_hash_rec *) *
+						      ((size >> 1) + 2));
+			  }
+			if (!(ht = Xmalloc (sizeof (novel_hash_rec) * size)))
+			  {
+			    Message ("Unable to allocate memory for table");
+			    return (COMPERROR);
+			  }
+			bzero ((char *) ht, sizeof (novel_hash_rec) * size);
+
+			for (i = 0; i < h->HashSize; i++)
+			  if (h->HashTable[i].word)
+			    {
+			      register u_char *wptr;
+			      register unsigned long hashval, step;
+
+			      wptr = h->HashTable[i].word;
+			      HASH (hashval, step, wptr, size);
+			      wptr = (ht + hashval)->word;
+			      while (wptr)
+				{
+				  hashval += step;
+				  if (hashval >= size)
+				    hashval -= size;
+				  wptr = (ht + hashval)->word;
+				}
+			      ht[hashval] = h->HashTable[i];
+			      if (cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+				h->code_to_nhr[ht[hashval].ordinal_num - 1] =
+				  &ht[hashval];
+			    }
+			Xfree (h->HashTable);
+			h->HashTable = ht;
+			h->HashSize = size;
+		      }
+		  }
+		  break;
+		}
+	    }
+	}
+      else
+	{
+	  HUFF_ENCODE (res, ht[which]->codes, ht[which]->hd->clens);
+#ifdef DOCDUMP
+	  if (cth.num_of_docs == DOCDUMP)
+	    {
+	      printf ("   %d %d\n", ht[which]->hd->clens[res],
+		      ht[which]->codes[res]);
+	    }
+#endif
+	}
+    }
+
+
+  /* Add a 1 bit onto the end of the buffer the remaining bits in the last
+     byte will all be zero */
+
+  ENCODE_BIT (1);
+
+  ENCODE_FLUSH;
+
+  byte_length = __pos - __base;
+  if (!__remaining)
+    {
+      Message ("The end of the buffer was probably overrun");
+      return COMPERROR;
+    }
+
+  ENCODE_DONE
+
+#ifdef DOCDUMP
+    if (cth.num_of_docs == DOCDUMP)
+    {
+      printf ("unused bits = %d\n", bits_unused);
+    }
+#endif
+
+  HTONUL(text_length);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&text_length, sizeof (text_length), 1, text_idx);
+  NTOHUL(text_length);  /* [RPAP - Jan 97: Endian Ordering] */
+  text_length += byte_length;
+
+#ifdef DOCDUMP
+  if (cth.num_of_docs == DOCDUMP)
+    {
+      int i;
+      for (i = 0; i < byte_length; i++)
+	printf ("%02x ", comp_buffer[i]);
+      printf ("\n");
+    }
+#endif
+
+  if (cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    for (which = 0; which <= 1; which++)
+      for (novels_used[which]--; novels_used[which] >= 0; novels_used[which]--)
+	{
+	  int a = novels_used[which];
+	  int b = swaps[which][novels_used[which]];
+	  novel_hash_rec *temp;
+	  temp = nht[which].code_to_nhr[a];
+	  nht[which].code_to_nhr[a] = nht[which].code_to_nhr[b];
+	  nht[which].code_to_nhr[b] = temp;
+	  nht[which].code_to_nhr[a]->ordinal_num = a + 1;
+	  nht[which].code_to_nhr[b]->ordinal_num = b + 1;
+	}
+
+
+  fwrite (comp_buffer, sizeof (*comp_buffer), byte_length, text);
+
+  if ((double) l_in / (double) byte_length > cth.ratio)
+    cth.ratio = (double) l_in / (double) byte_length;
+
+  cth.num_of_docs++;
+  if (l_in > cth.length_of_longest_doc)
+    cth.length_of_longest_doc = l_in;
+
+  cth.num_of_bytes += l_in;
+
+  if (Comp_Stats)
+    {
+      stats_in_tot_bytes += l_in;
+      stats_in_bytes += l_in;
+      stats_out_bytes += byte_length;
+      if (stats_in_bytes >= comp_stat_point)
+	{
+	  fprintf (Comp_Stats, "%10.0f %10.0f %10.0f %f\n", stats_in_tot_bytes,
+		   stats_in_bytes, stats_out_bytes,
+		   (double) stats_out_bytes / (double) stats_in_bytes);
+	  stats_in_bytes = 0.0;
+	  stats_out_bytes = 0.0;
+	}
+    }
+
+  return COMPALLOK;
+}
+
+
+
+
+
+
+int 
+write_aux_dict (char *FileName)
+{
+  int i;
+  FILE *aux;
+  if (!(aux = create_file (FileName, TEXT_DICT_AUX_SUFFIX, "wb",
+			   MAGIC_AUX_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fprintf(stderr,"Couldn't create file %s%s:%s\n",
+              FileName, TEXT_DICT_AUX_SUFFIX,
+#if defined(HAVE_STRERROR) || defined(__WIN32__)
+              strerror(errno)
+#else
+              " "
+#endif
+              );
+      return COMPERROR;
+    }
+  for (i = 0; i <= 1; i++)
+    {
+      aux_frags_header afh;
+      char_pool *cp;
+
+      afh.num_frags = nht[i].HashUsed;
+      afh.mem_for_frags = 0;
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	afh.mem_for_frags += POOL_SIZE - cp->left;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(afh.num_frags);
+      HTONUL(afh.mem_for_frags);
+
+      fwrite (&afh, sizeof (afh), 1, aux);
+
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	fwrite (cp->pool, POOL_SIZE - cp->left, sizeof (u_char), aux);
+    }
+  fclose (aux);
+  return COMPALLOK;
+}
+
+
+void 
+estimate_compressed_aux_dict (void)
+{
+  int i;
+  u_long aux_compressed = 0, total_uncomp = 0;
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+      long chars[256], fchars[256];
+      long lens[16], flens[16];
+      char_pool *cp;
+      bzero ((char *) chars, sizeof (chars));
+      bzero ((char *) lens, sizeof (lens));
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	{
+	  u_char *buf = cp->pool;
+	  while (buf != cp->ptr)
+	    {
+	      int len = *buf++;
+	      lens[len]++;
+	      total_uncomp += len + 4;
+	      for (; len; len--)
+		chars[*buf++]++;
+	    }
+	}
+      for (j = 0; j < 256; j++)
+	if (!chars[j] && PESINAWORD (j) == i)
+	  fchars[j] = 1;
+	else
+	  fchars[j] = chars[j];
+      for (j = 0; j < 16; j++)
+	if (!lens[j])
+	  flens[j] = 1;
+	else
+	  flens[j] = lens[j];
+
+      aux_compressed += (Calculate_Huffman_Size (16, flens, lens) +
+			 Calculate_Huffman_Size (256, fchars, chars)) / 8;
+
+    }
+
+  Message ("Aux dictionary (Uncompressed) %.2f Mb ( %u bytes   %0.3f %%)",
+	   total_uncomp / 1024.0 / 1024, total_uncomp,
+	   (total_uncomp * 100.0) / bytes_processed);
+  Message ("Aux dictionary (Compressed)   %.2f Mb ( %.0f bytes   %0.3f %%)",
+	   aux_compressed / 1024.0 / 1024, aux_compressed * 1.0,
+	   (aux_compressed * 100.0) / bytes_processed);
+}
+
+
+
+
+
+
+int 
+done_text_2 (char *FileName)
+{
+  if (Comp_Stats)
+    fprintf (Comp_Stats, "%10.0f %10.0f %10.0f %f\n", stats_in_tot_bytes,
+	     stats_in_bytes, stats_out_bytes,
+	     (double) stats_out_bytes / (double) stats_in_bytes);
+
+  HTONUL(text_length);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&text_length, sizeof (text_length), 1, text_idx);
+  NTOHUL(text_length);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(cth.num_of_docs);
+  HTOND(cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+  HTONUL(cth.num_of_words);
+  HTONUL(cth.length_of_longest_doc);
+  HTOND(cth.ratio);
+
+  if (fseek (text_idx, sizeof (u_long), SEEK_SET) == -1 ||
+      fwrite (&cth, sizeof (cth), 1, text_idx) != 1)
+    return COMPERROR;
+  fclose (text_idx);
+
+  if (fseek (text, sizeof (u_long), SEEK_SET) == -1 ||
+      fwrite (&cth, sizeof (cth), 1, text) != 1)
+    return COMPERROR;
+  fclose (text);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cth.num_of_docs);
+  NTOHD(cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(cth.num_of_words);
+  NTOHUL(cth.length_of_longest_doc);
+  NTOHD(cth.ratio);
+  
+
+  Message ("Compressed Text %.2f Mb ( %u bytes   %0.3f %%)",
+	   text_length / 1024.0 / 1024.0, text_length,
+	   (text_length * 100.0) / bytes_processed);
+  Message ("Words portion of the dictionary %.2f Mb ( %.0f bytes   %0.3f %%)",
+	   Words_disk / 1024.0 / 1024, Words_disk * 1.0,
+	   (Words_disk * 100.0) / bytes_processed);
+
+  if (cdh.dict_type != MG_COMPLETE_DICTIONARY &&
+      (cdh.novel_method == MG_NOVEL_BINARY ||
+       cdh.novel_method == MG_NOVEL_DELTA ||
+       cdh.novel_method == MG_NOVEL_HYBRID ||
+       cdh.novel_method == MG_NOVEL_HYBRID_MTF))
+    {
+      if (write_aux_dict (FileName) == COMPERROR)
+	return COMPERROR;
+      estimate_compressed_aux_dict ();
+    }
+  else
+    {
+      if (cdh.dict_type != MG_COMPLETE_DICTIONARY)
+	Message ("Huffman info for chars in dictionary %.2f Mb"
+		 " ( %u bytes   %0.3f %%)",
+		 Chars_disk / 1024.0 / 1024, Chars_disk,
+		 (Chars_disk * 100.0) / bytes_processed);
+      unlink (make_name (FileName, TEXT_DICT_AUX_SUFFIX, NULL));
+    }
+
+  return (COMPALLOK);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text_get.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text_get.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text_get.c	(revision 10506)
@@ -0,0 +1,1087 @@
+/**************************************************************************
+ *
+ * text_get.c -- Function for reading documents from the compressed text
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "filestats.h"
+#include "timing.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "huffman.h"
+#include "bitio_m_mem.h"
+#include "bitio_m.h"
+#include "bitio_stdio.h"
+#include "huffman_stdio.h"
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "text_get.h"
+#include "locallib.h"
+#include "words.h"
+#include "mg_errors.h"
+#include "local_strings.h"
+
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:26  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:35:48  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.3  1994/10/20  03:57:11  tes
+   * I have rewritten the boolean query optimiser and abstracted out the
+   * components of the boolean query.
+   *
+   * Revision 1.2  1994/09/20  04:42:15  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+
+
+/* FetchDocStart () 
+ * Reads into DocEnt the starting position of the document in the *.text file
+ * Where the first document is document number 1
+ * It returns the true weight of the document.
+ */
+
+
+
+
+static double 
+FetchDocStartLev1 (text_data * td, u_long DN,
+		   u_long * seek_pos, u_long * len)
+{
+  unsigned long data[2];
+  /* [TS:Sep/94] Fixed up the seek call to give the correct offset */
+  Fseek (td->TextIdxFile,
+	 sizeof (unsigned long) * (DN - 1) +	/* the doc offsets */
+	 sizeof (unsigned long) +	/* the magic number */
+	 sizeof (compressed_text_header),	/* the header */
+	 0);
+  Fread ((char *) &data, sizeof (data), 1, td->TextIdxFile);
+  
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(data[0]);
+  NTOHUL(data[1]);
+
+  *seek_pos = data[0];
+  *len = data[1] - data[0];
+  return (1.0);
+}
+
+#define MG_PAGE_SIZE 2048
+
+static int 
+LoadIdx (text_data * td, unsigned long DN)
+{
+  if (!td->idx_data)
+    {
+      td->idx_data = Xmalloc (sizeof (*(td->idx_data)) * MG_PAGE_SIZE);
+      if (!td->idx_data)
+	FatalError (1, "Out of memory in FDSL2");
+    }
+  if (td->current_pos == -1 || DN >= td->current_pos + MG_PAGE_SIZE - 1 ||
+      DN < td->current_pos)
+    {
+      int i, num;  /* [RPAP - Jan 97: Endian Ordering] */
+
+      long rn = (long) DN - (MG_PAGE_SIZE >> 1);
+      if (rn < 1)
+	rn = 1;
+      Fseek (td->TextIdxWgtFile, (sizeof (unsigned long) + sizeof (float)) *
+	       (rn - 1) + sizeof (unsigned long), 0);
+      num = Fread ((char *) td->idx_data, sizeof (*(td->idx_data)), MG_PAGE_SIZE, /* [RPAP - Jan 97: Endian Ordering] */
+		   td->TextIdxWgtFile);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = 0; i < num; i++)
+	{
+	  NTOHUL(td->idx_data[i].Start);
+	  NTOHF(td->idx_data[i].Weight);
+	}
+
+      td->current_pos = rn;
+    }
+  return DN - td->current_pos;
+}
+
+static double 
+FDSL2 (text_data * td, unsigned long DN, unsigned long *Pos)
+{
+  unsigned long pos = LoadIdx (td, DN);
+  *Pos = td->idx_data[pos].Start;
+  return (td->idx_data[pos].Weight);
+}
+
+
+static double 
+FetchDocStartLev2 (text_data * td, u_long DN,
+		   u_long * seek_pos, u_long * len)
+{
+  double Weight;
+  unsigned long s1, s2;
+  Weight = FDSL2 (td, DN, &s1);
+  do
+    {
+      DN++;
+      FDSL2 (td, DN, &s2);
+    }
+  while (s2 == s1);
+  *seek_pos = s1;
+  *len = s2 - s1;
+  return (Weight);
+}
+
+
+
+
+double 
+FetchDocStart (query_data * qd, u_long DN, u_long * seek_pos, u_long * len)
+{
+  qd->text_idx_lookups++;
+  if (qd->td->TextIdxWgtFile)
+    return FetchDocStartLev2 (qd->td, DN, seek_pos, len);
+  else
+    return FetchDocStartLev1 (qd->td, DN, seek_pos, len);
+}
+
+unsigned long 
+FetchInitialParagraph (text_data * td, unsigned long ParaNum)
+{
+  if (td->TextIdxWgtFile)
+    {
+      unsigned long pos;
+      unsigned long start;
+      int PN = ParaNum - 1;
+      pos = LoadIdx (td, ParaNum);
+      start = td->idx_data[pos].Start;
+      while (PN > 0)
+	{
+	  pos = LoadIdx (td, PN);
+	  if (td->idx_data[pos].Start != start)
+	    return PN + 1;
+	  PN--;
+	}
+      return PN + 1;
+    }
+  else
+    return ParaNum;
+}
+
+
+
+/* FetchCompressed () 
+ * Reads into buffer DocBuff the compressed form of document DocNum. 
+ * Where the first document is document number 1
+ */
+int 
+FetchCompressed (query_data * qd, char **DocBuff, DocEntry * DocEnt)
+{
+  if (!DocEnt->SeekPos)
+    FetchDocStart (qd, DocEnt->DocNum, &DocEnt->SeekPos, &DocEnt->Len);
+  if (!(*DocBuff = Xmalloc (DocEnt->Len)))
+    return (-1);
+
+  if (Fseek (qd->td->TextFile, DocEnt->SeekPos, 0) == -1)
+    FatalError (1, "Error when seeking into text file");
+#if 0
+  printf ("Loading compressed text %d %d\n", DocEnt->SeekPos, DocEnt->Len);
+#endif
+  if (Fread (*DocBuff, 1, DocEnt->Len, qd->td->TextFile) != DocEnt->Len)
+    FatalError (1, "Error when reading data");
+
+  return (DocEnt->Len);
+
+}
+
+
+text_data *
+LoadTextData (File * text, File * text_idx_wgt, File * text_idx)
+{
+  text_data *td;
+
+  if (!(td = Xmalloc (sizeof (text_data))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  td->TextFile = text;
+  td->TextIdxWgtFile = text_idx_wgt;
+  td->TextIdxFile = text_idx;
+  td->current_pos = -1;
+  td->idx_data = NULL;
+  Fread (&td->cth, sizeof (td->cth), 1, text);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(td->cth.num_of_docs);
+  NTOHD(td->cth.num_of_bytes); /* [RJM 07/97: 4G limit] */
+  NTOHUL(td->cth.num_of_words);
+  NTOHUL(td->cth.length_of_longest_doc);
+  NTOHD(td->cth.ratio);
+
+  return (td);
+}
+
+
+void 
+FreeTextData (text_data * td)
+{
+  if (td)
+    {
+      if (td->idx_data)
+	Xfree (td->idx_data);
+      Xfree (td);
+    }
+}
+
+
+static int 
+pts_comp (const void *A, const void *B)
+{
+  const DocEntry *const *a = A;
+  const DocEntry *const *b = B;
+  return (*a)->DocNum - (*b)->DocNum;
+}
+
+
+
+
+int 
+GetPosLens (query_data * qd, DocEntry * Docs, int num)
+{
+  DocEntry **pts;
+  int i, j;
+  if (!(pts = Xmalloc (num * sizeof (DocEntry *))))
+    {
+      mg_errno = MG_NOMEM;
+      return (-1);
+    }
+  for (i = j = 0; i < num; i++, Docs++)
+    if (!Docs->SeekPos)
+      pts[j++] = Docs;
+
+  if (j)
+    {
+      qsort (pts, j, sizeof (DocEntry *), pts_comp);
+      for (i = 0; i < j; i++)
+	FetchDocStart (qd, pts[i]->DocNum, &pts[i]->SeekPos, &pts[i]->Len);
+    }
+
+  Xfree (pts);
+  return (0);
+}
+
+
+
+
+
+int 
+LoadBuffers (query_data * qd, DocEntry * Docs, int max_mem, int num)
+{
+  DocEntry **pts;
+  int i, j;
+  int mem;
+
+  if (!num)
+    return (0);
+  if (!(pts = Xmalloc (num * sizeof (DocEntry *))))
+    {
+      mg_errno = MG_NOMEM;
+      return (-1);
+    }
+
+  mem = i = 0;
+  do
+    {
+      pts[i] = Docs;
+      mem += Docs->Len;
+      i++;
+      Docs++;
+    }
+  while (i < num && mem < max_mem);
+  if (i > 1)
+    qsort (pts, i, sizeof (DocEntry *), pts_comp);
+  for (j = 0; j < i; j++)
+    {
+      if (FetchCompressed (qd, &pts[j]->CompTextBuffer, pts[j]) == -1)
+	return (-1);
+      ChangeMemInUse (qd, pts[j]->Len);
+    }
+
+  Xfree (pts);
+
+  return (i);
+}
+
+
+
+
+
+void 
+FreeBuffers (query_data * qd, DocEntry * Docs, int num)
+{
+  int i;
+  for (i = 0; i < num; i++, Docs++)
+    if (Docs->CompTextBuffer)
+      {
+	Xfree (Docs->CompTextBuffer);
+	Docs->CompTextBuffer = NULL;
+	ChangeMemInUse (qd, -Docs->Len);
+      }
+}
+
+
+
+/****************************************************************************/
+
+static void 
+FreeAuxDict (auxiliary_dict * ad)
+{
+  if (!ad)
+    return;
+  if (ad->word_data[0])
+    Xfree (ad->word_data[0]);
+  if (ad->word_data[1])
+    Xfree (ad->word_data[1]);
+  if (ad->words[0])
+    Xfree (ad->words[0]);
+  if (ad->words[1])
+    Xfree (ad->words[1]);
+  Xfree (ad);
+}
+
+static auxiliary_dict *
+LoadAuxDict (compression_dict * cd, File * text_aux_dict)
+{
+  auxiliary_dict *ad;
+  int i;
+
+  if (!(ad = Xmalloc (sizeof (auxiliary_dict))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  bzero ((char *) ad, sizeof (*ad));
+
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+      u_char *pos;
+
+      Fread (&ad->afh[i], sizeof (aux_frags_header), 1, text_aux_dict);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(ad->afh[i].num_frags);
+      NTOHUL(ad->afh[i].mem_for_frags);
+
+      if (!(ad->word_data[i] = Xmalloc (ad->afh[i].mem_for_frags)))
+	{
+	  mg_errno = MG_NOMEM;
+	  FreeAuxDict (ad);
+	  return (NULL);
+	}
+      if (!(ad->words[i] = Xmalloc (ad->afh[i].num_frags * sizeof (u_char *))))
+	{
+	  mg_errno = MG_NOMEM;
+	  FreeAuxDict (ad);
+	  return (NULL);
+	}
+
+      Fread (ad->word_data[i], ad->afh[i].mem_for_frags, sizeof (u_char),
+	     text_aux_dict);
+
+      pos = ad->word_data[i];
+      for (j = 0; j < ad->afh[i].num_frags; j++)
+	{
+	  ad->words[i][j] = pos;
+	  pos += *pos + 1;
+	}
+      if (cd->cdh.novel_method == MG_NOVEL_HYBRID ||
+	  cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+	{
+	  int num;
+	  num = 1;
+	  ad->blk_start[i][0] = 0;
+	  ad->blk_end[i][0] = cd->cdh.num_words[i] - 1;
+	  while (num < 33)
+	    {
+	      ad->blk_start[i][num] = ad->blk_end[i][num - 1] + 1;
+	      ad->blk_end[i][num] = ad->blk_start[i][num] +
+		(ad->blk_end[i][num - 1] - ad->blk_start[i][num - 1]) * 2;
+	      num++;
+	    }
+	}
+    }
+  return (ad);
+}
+
+
+
+
+
+
+static u_char ***
+ReadInWords (File * dict, compression_dict * cd,
+	     comp_frags_header * cfh, u_char ** escape)
+{
+  int i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+  int num_set[MAX_HUFFCODE_LEN + 1];
+  u_char *next_word[MAX_HUFFCODE_LEN + 1];
+  u_char **vals;
+  u_char ***values;
+  u_char word[MAXWORDLEN + 1];
+  u_char last_word[MAX_HUFFCODE_LEN + 1][MAXWORDLEN + 1];
+
+  lookback = cd->cdh.lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; i++)
+    {
+      ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+      mem_reqd += cfh->huff_words_size[i];
+    }
+
+  if (!(vals = Xmalloc (ptrs_reqd * sizeof (*vals))))
+    return (NULL);
+
+  if (!(values = Xmalloc ((MAX_HUFFCODE_LEN + 1) * sizeof (u_char **))))
+    return (NULL);
+
+  if (!(next_word[0] = Xmalloc (mem_reqd))) return (NULL);
+
+  cd->MemForCompDict += ptrs_reqd * sizeof (*vals) +
+    (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **) +
+    mem_reqd;
+
+  values[0] = vals;
+  values[0][0] = next_word[0];
+  for (i = 1; i <= cfh->hd.maxcodelen; i++)
+    {
+      int next_start = (values[i - 1] - vals) +
+      ((cfh->hd.lencount[i - 1] + ((1 << lookback) - 1)) >> lookback);
+      values[i] = &vals[next_start];
+      next_word[i] = next_word[i - 1] + cfh->huff_words_size[i - 1];
+      values[i][0] = next_word[i];
+    }
+
+  bzero ((char *) num_set, sizeof (num_set));
+
+  for (i = 0; i < cfh->hd.num_codes; i++)
+    {
+      register int val, copy;
+      register int len = cfh->hd.clens[i];
+      val = Getc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      Fread (word + copy + 1, sizeof (u_char), val, dict);
+      *word = val + copy;
+
+      if ((num_set[len] & ((1 << lookback) - 1)) == 0)
+	{
+	  values[len][num_set[len] >> lookback] = next_word[len];
+	  memcpy (next_word[len], word, *word + 1);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    *escape = next_word[len];
+	  next_word[len] += *word + 1;
+	}
+      else
+	{
+	  copy = prefixlen (last_word[len], word);
+	  memcpy (next_word[len] + 1, word + copy + 1, *word - copy);
+	  *next_word[len] = (copy << 4) + (*word - copy);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    *escape = next_word[len];
+	  next_word[len] += (*word - copy) + 1;
+	}
+      memcpy (last_word[len], word, *word + 1);
+      num_set[len]++;
+    }
+  if (cfh->hd.clens)
+    Xfree (cfh->hd.clens);
+  cfh->hd.clens = NULL;
+  return values;
+}
+
+
+static compression_dict *
+Load_Comp_Dict (File * dict, File * aux_dict)
+{
+  int which;
+  compression_dict *cd;
+
+  if (!(cd = Xmalloc (sizeof (compression_dict))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  bzero ((char *) cd, sizeof (compression_dict));
+
+  cd->MemForCompDict = sizeof (compression_dict);
+
+  if (F_Read_cdh (dict, &cd->cdh, &cd->MemForCompDict, NULL) == -1)
+    return NULL;
+
+  for (which = 0; which < 2; which++)
+    switch (cd->cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  if (!(cd->cfh[which] = Xmalloc (sizeof (*cd->cfh[which]))))
+	    return NULL;
+	  cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	  if (F_Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL) == -1)
+	    return NULL;
+
+	  if (!(cd->values[which] = ReadInWords (dict, cd, cd->cfh[which],
+						 NULL)))
+	    return NULL;
+	  cd->escape[which] = NULL;
+
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  huff_data *hd;
+	  u_long **vals;
+	  if (cd->cdh.num_words[which])
+	    {
+	      if (!(cd->cfh[which] = Xmalloc (sizeof (*cd->cfh[which]))))
+		return NULL;
+	      cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	      if (F_Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL) == -1)
+		return NULL;
+
+	      if (!(cd->values[which] = ReadInWords (dict, cd, cd->cfh[which],
+						     &cd->escape[which])))
+		return NULL;
+	    }
+	  if (!(hd = Xmalloc (sizeof (huff_data))))
+	    return NULL;
+	  cd->MemForCompDict += sizeof (huff_data);
+	  if (F_Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL) == -1)
+	    return NULL;
+	  if (!(vals = Generate_Huffman_Vals (hd, &cd->MemForCompDict)))
+	    return NULL;
+	  if (hd->clens)
+	    Xfree (hd->clens);
+	  hd->clens = NULL;
+	  cd->chars_huff[which] = hd;
+	  cd->chars_vals[which] = vals;
+	  if (!(hd = Xmalloc (sizeof (huff_data))))
+	    return NULL;
+	  cd->MemForCompDict += sizeof (huff_data);
+	  if (F_Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL) == -1)
+	    return NULL;
+	  if (!(vals = Generate_Huffman_Vals (hd, &cd->MemForCompDict)))
+	    return NULL;
+	  cd->lens_huff[which] = hd;
+	  cd->lens_vals[which] = vals;
+	  if (hd->clens)
+	    Xfree (hd->clens);
+	  hd->clens = NULL;
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  huff_data *hd;
+	  u_long **vals;
+	  if (cd->cdh.num_words[which])
+	    {
+	      if (!(cd->cfh[which] = Xmalloc (sizeof (*cd->cfh[which]))))
+		return NULL;
+	      cd->MemForCompDict += sizeof (*cd->cfh[which]);
+	      if (F_Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL) == -1)
+		return NULL;
+
+	      if (!(cd->values[which] = ReadInWords (dict, cd, cd->cfh[which],
+						     &cd->escape[which])))
+		return NULL;
+	    }
+	  switch (cd->cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      if (!(hd = Xmalloc (sizeof (huff_data))))
+		return NULL;
+	      cd->chars_huff[which] = hd;
+	      cd->MemForCompDict += sizeof (huff_data);
+	      if (F_Read_Huffman_Data (dict, hd, &cd->MemForCompDict,
+				       NULL) == -1)
+		return NULL;
+	      if (!(vals = Generate_Huffman_Vals (hd, &cd->MemForCompDict)))
+		return NULL;
+	      cd->chars_vals[which] = vals;
+	      if (hd->clens)
+		Xfree (hd->clens);
+	      hd->clens = NULL;
+	      if (!(hd = Xmalloc (sizeof (huff_data))))
+		return NULL;
+	      cd->MemForCompDict += sizeof (huff_data);
+	      cd->lens_huff[which] = hd;
+	      if (F_Read_Huffman_Data (dict, hd, &cd->MemForCompDict
+				       ,NULL) == -1)
+		return NULL;
+	      if (!(vals = Generate_Huffman_Vals (hd, &cd->MemForCompDict)))
+		return NULL;
+	      cd->lens_vals[which] = vals;
+	      if (hd->clens)
+		Xfree (hd->clens);
+	      hd->clens = NULL;
+	      break;
+	    case MG_NOVEL_BINARY:
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    case MG_NOVEL_HYBRID_MTF:
+	      break;
+	    }
+	  break;
+	}
+      }
+
+  if (cd->cdh.novel_method == MG_NOVEL_BINARY ||
+      cd->cdh.novel_method == MG_NOVEL_DELTA ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    {
+      if (!aux_dict)
+	{
+	  mg_errno = MG_NOFILE;
+	  FreeCompDict (cd);
+	  return (NULL);
+	}
+
+      if (!(cd->ad = LoadAuxDict (cd, aux_dict)))
+	{
+	  FreeCompDict (cd);
+	  return (NULL);
+	}
+    }
+
+
+  mg_errno = MG_NOERROR;
+
+  cd->fast_loaded = 0;
+  return (cd);
+}
+
+#define WORDNO(p, base) ((((char*)(p))-((char*)(base)))/sizeof(u_char*))
+
+#define IS_FIXUP(p) ((fixup[WORDNO(p,cd)/8] & (1<<(WORDNO(p, cd) & 7))) != 0)
+
+
+static compression_dict *
+Load_Fast_Comp_Dict (File * text_fast_comp_dict)
+{
+  compression_dict *cd;
+  u_long *p, *end;
+  u_char *fixup;
+  u_long mem;
+  u_long fixup_mem;
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  Fread (&mem, sizeof (mem), 1, text_fast_comp_dict);
+  NTOHUL(mem);  /* [RPAP - Jan 97: Endian Ordering] */
+  Fread (&fixup_mem, sizeof (fixup_mem), 1, text_fast_comp_dict);
+  NTOHUL(fixup_mem);  /* [RPAP - Jan 97: Endian Ordering] */
+  if (!(cd = Xmalloc (mem)))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  end = (u_long *) (((u_char *) cd) + mem);
+  Fread (cd, sizeof (u_char), mem, text_fast_comp_dict);
+
+  if (!(fixup = Xmalloc (fixup_mem)))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  Fread (fixup, fixup_mem, sizeof (u_char), text_fast_comp_dict);
+
+  for (p = (u_long *) cd; (u_long) p < (u_long) end; p++)
+    if (IS_FIXUP (p))
+      {
+	NTOHUL(*p);  /* [RPAP - Jan 97: Endian Ordering] */
+	*p = *p + (u_long) cd;
+      }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  /* cdh */
+  NTOHUL(cd->cdh.dict_type);
+  NTOHUL(cd->cdh.novel_method);
+  for (i = 0; i < TEXT_PARAMS; i++)
+    NTOHUL(cd->cdh.params[i]);
+  NTOHUL(cd->cdh.num_words[0]);
+  NTOHUL(cd->cdh.num_words[1]);
+  NTOHUL(cd->cdh.num_word_chars[0]);
+  NTOHUL(cd->cdh.num_word_chars[1]);
+  NTOHUL(cd->cdh.lookback);
+  /* cfh */
+  for (i = 0; i <= 1; i++)
+    {
+      int j;
+
+      NTOHSI(cd->cfh[i]->hd.num_codes);
+      NTOHSI(cd->cfh[i]->hd.mincodelen);
+      NTOHSI(cd->cfh[i]->hd.maxcodelen);
+      for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	{
+	  NTOHSI(cd->cfh[i]->hd.lencount[j]);
+	  NTOHUL(cd->cfh[i]->hd.min_code[j]);
+	}
+      NTOHUL(cd->cfh[i]->uncompressed_size);
+      for (j = 0; j < MAX_HUFFCODE_LEN + 1; j++)
+	NTOHUL(cd->cfh[i]->huff_words_size[j]);
+    }
+  NTOHUL(cd->MemForCompDict);
+  /* ad */
+  if (cd->cdh.novel_method == MG_NOVEL_BINARY ||
+      cd->cdh.novel_method == MG_NOVEL_DELTA ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    for (i = 0; i <= 1; i++)
+      {
+	int j;
+	
+	NTOHUL(cd->ad->afh[i].num_frags);
+	NTOHUL(cd->ad->afh[i].mem_for_frags);
+	for (j = 0; j < 33; j++)
+	  {
+	    NTOHSI(cd->ad->blk_start[i][j]);
+	    NTOHSI(cd->ad->blk_end[i][j]);
+	  }
+      }
+  NTOHSI(cd->fast_loaded);
+
+  Xfree (fixup);
+  return (cd);
+}
+
+
+
+
+compression_dict *
+LoadCompDict (File * text_comp_dict,
+	      File * text_aux_dict,
+	      File * text_fast_comp_dict)
+{
+  return text_fast_comp_dict ?
+    Load_Fast_Comp_Dict (text_fast_comp_dict) :
+    Load_Comp_Dict (text_comp_dict, text_aux_dict);
+}
+
+
+
+
+void 
+FreeCompDict (compression_dict * cd)
+{
+  int which;
+  if (cd->fast_loaded)
+    {
+      Xfree (cd);
+      return;
+    }
+  for (which = 0; which < 2; which++)
+    {
+      if (cd->cfh[which])
+	Xfree (cd->cfh[which]);
+      if (cd->chars_huff[which])
+	Xfree (cd->chars_huff[which]);
+      if (cd->lens_huff[which])
+	Xfree (cd->lens_huff[which]);
+      if (cd->values[which])
+	{
+	  Xfree (cd->values[which][0][0]); /* [RJM 07/98: Memory Leak] */
+	  Xfree (cd->values[which][0]);
+	  Xfree (cd->values[which]);
+	}
+      if (cd->chars_vals[which])
+	{
+	  Xfree (cd->chars_vals[which][0]);
+	  Xfree (cd->chars_vals[which]);
+	}
+      if (cd->lens_vals[which])
+	{
+	  Xfree (cd->lens_vals[which][0]);
+	  Xfree (cd->lens_vals[which]);
+	}
+    }
+  if (cd->ad)
+    FreeAuxDict (cd->ad);
+  Xfree (cd);
+}
+
+
+
+
+
+#define MY_HUFF_DECODE(len, code, mcodes)				\
+  do {									\
+    register unsigned long *__min_code = (mcodes);			\
+    register unsigned long *__mclen = __min_code;			\
+    register unsigned long __code = 0;					\
+    do									\
+      {									\
+        DECODE_ADD(__code);						\
+      }									\
+    while (__code < *++__mclen);					\
+    (len) = __mclen - __min_code;					\
+    (code) = __code - *__mclen;						\
+  } while(0);
+
+
+/*#define DUMPDOC */
+
+#define MAX_SWAPS 10000
+
+int 
+DecodeText (compression_dict * cd,
+	    u_char * s_in, int l_in, u_char * s_out, int *l_out)
+{
+  auxiliary_dict *ad = cd->ad;
+  int which;
+  u_long num_bits, bits;
+  u_char *ptr = s_out;
+  static int num = 0;
+  u_long binary_start[2];
+  int novels_used[2];
+  int swaps[2][MAX_SWAPS];
+  novels_used[0] = novels_used[1] = 0;
+
+  {
+    unsigned char bf = s_in[l_in - 1];
+    num_bits = 1;
+    while ((bf & 1) != 1)
+      {
+	num_bits++;
+	bf >>= 1;
+      }
+    num_bits = l_in * 8 - num_bits;
+  }
+
+  DECODE_START (s_in, l_in)
+
+    which = DECODE_BIT;
+  bits = 1;
+
+  if (cd->cdh.novel_method == MG_NOVEL_BINARY)
+    {
+      DELTA_DECODE_L (binary_start[0], bits);
+      DELTA_DECODE_L (binary_start[1], bits);
+    }
+
+
+  while (bits < num_bits)
+    {
+      register unsigned code, len;
+      register int r;
+      register u_char *t, *b = NULL;
+      u_char word[MAXWORDLEN + 1];
+
+#ifdef DUMPDOC
+      printf ("\n%d %d  ", bits, num_bits);
+#endif
+      if (cd->cfh[which])
+	{
+	  MY_HUFF_DECODE (len, code, cd->cfh[which]->hd.min_code);
+	  bits += len;
+
+	  r = code & ((1 << cd->cdh.lookback) - 1);
+	  t = cd->values[which][len][code >> cd->cdh.lookback];
+
+	  /* step through from base pointer */
+	  b = word + 1;
+	  while (r--)
+	    {
+	      register int copy = *t >> 4;
+	      memcpy (word + copy + 1, t + 1, *t & 0xf);
+	      word[0] = copy + (*t & 0xf);
+	      t += ((*t) & 0xf) + 1;
+	    }
+	}
+      else
+	t = NULL;
+      if (t == cd->escape[which])
+	{
+	  switch (cd->cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      {
+		int len, i;
+		int c;
+		HUFF_DECODE_L (len, cd->lens_huff[which]->min_code,
+			       cd->lens_vals[which], bits);
+		for (i = 0; i < len; i++)
+		  {
+		    HUFF_DECODE_L (c, cd->chars_huff[which]->min_code,
+				   cd->chars_vals[which], bits);
+		    *ptr++ = c;
+		  }
+	      }
+	      break;
+	    case MG_NOVEL_BINARY:
+	    case MG_NOVEL_DELTA:
+	    case MG_NOVEL_HYBRID:
+	    case MG_NOVEL_HYBRID_MTF:
+	      {
+		int idx = 0, len;
+		u_char *base;
+		switch (cd->cdh.novel_method)
+		  {
+		  case MG_NOVEL_BINARY:
+		    {
+		      BINARY_DECODE_L (idx, binary_start[which], bits);
+		      if (idx == binary_start[which])
+			binary_start[which]++;
+		      idx--;
+		    }
+		    break;
+		  case MG_NOVEL_DELTA:
+		    {
+		      DELTA_DECODE_L (idx, bits);
+		      idx--;
+		    }
+		    break;
+		  case MG_NOVEL_HYBRID:
+		    {
+		      int k;
+		      GAMMA_DECODE_L (k, bits);
+		      k--;
+		      BINARY_DECODE_L (idx,
+				       ad->blk_end[which][k] -
+				       ad->blk_start[which][k] + 1, bits);
+		      idx += ad->blk_start[which][k] - 1;
+		    }
+		    break;
+		  case MG_NOVEL_HYBRID_MTF:
+		    {
+		      int k;
+		      GAMMA_DECODE_L (k, bits);
+		      k--;
+		      BINARY_DECODE_L (idx,
+				       ad->blk_end[which][k] -
+				       ad->blk_start[which][k] + 1, bits);
+		      idx += ad->blk_start[which][k] - 1;
+		      if (idx >= novels_used[which])
+			{
+			  u_char *temp;
+			  temp = ad->words[which][idx];
+			  ad->words[which][idx] =
+			    ad->words[which][novels_used[which]];
+			  ad->words[which][novels_used[which]] = temp;
+			  swaps[which][novels_used[which]] = idx;
+			  idx = novels_used[which]++;
+			}
+		    }
+		    break;
+		  }
+		base = ad->words[which][idx];
+		len = *base++;
+#ifdef DUMPDOC
+		printf ("[[");
+#endif
+		for (; len; len--)
+		  {
+		    *ptr++ = *base++;
+#ifdef DUMPDOC
+		    putchar (*(base - 1));
+#endif
+		  }
+#ifdef DUMPDOC
+		printf ("]]");
+#endif
+	      }
+	      break;
+	    }
+	}
+      else
+	{
+	  /* copy over the matching prefix */
+	  r = (*t >> 4);
+	  while (r--)
+#ifndef DUMPDOC
+	    *ptr++ = *b++;
+#else
+	    {
+	      *ptr = *b++;
+	      putchar (*ptr);
+	      ptr++;
+	    }
+#endif
+
+	  /* and the stored suffix */
+	  r = ((*t) & 0xf);
+	  while (r--)
+#ifndef DUMPDOC
+	    *ptr++ = *++t;
+#else
+	    {
+	      *ptr = *++t;
+	      putchar (*ptr);
+	      ptr++;
+	    }
+#endif
+	}
+      which = !which;
+    }
+
+  DECODE_DONE
+
+    * l_out = ptr - s_out;
+  num += *l_out + 1;
+
+  if (cd->cdh.novel_method == MG_NOVEL_HYBRID_MTF)
+    for (which = 0; which <= 1; which++)
+      for (novels_used[which]--; novels_used[which] >= 0; novels_used[which]--)
+	{
+	  int a = novels_used[which];
+	  int b = swaps[which][novels_used[which]];
+	  u_char *temp;
+	  temp = ad->words[which][a];
+	  ad->words[which][a] = ad->words[which][b];
+	  ad->words[which][b] = temp;
+	}
+  return (COMPALLOK);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text_get.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text_get.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/text_get.h	(revision 10506)
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * text_get.h -- Function for reading documents from the compressed text
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_TEXT_GET
+#define H_TEXT_GET
+
+
+
+/* FetchDocStart () 
+ * Reads into DocEnt the starting position of the document in the *.text file
+ * Where the first document is document number 1
+ * It returns the true weight of the document.
+ */
+double FetchDocStart (query_data * qd, u_long DN, u_long * seek_pos, u_long * len);
+
+unsigned long FetchInitialParagraph (text_data * td, unsigned long ParaNum);
+
+
+/* FetchCompressed () 
+ * Reads into buffer DocBuff the compressed form of document DocNum. 
+ * Where the first document is document number 1
+ */
+int FetchCompressed (query_data * qd, char **DocBuff, DocEntry * DocEnt);
+
+text_data *LoadTextData (File * text, File * text_idx_wgt, File * text_idx);
+
+void FreeTextData (text_data * td);
+
+int GetPosLens (query_data * qd, DocEntry * Docs, int num);
+
+int LoadBuffers (query_data * qd, DocEntry * Docs, int max_mem, int num);
+
+void FreeBuffers (query_data * qd, DocEntry * Docs, int num);
+
+
+
+compression_dict *LoadCompDict (File * text_comp_dict,
+				File * text_aux_dict,
+				File * text_fast_comp_dict);
+
+void FreeCompDict (compression_dict * cd);
+
+
+int DecodeText (compression_dict * cd,
+		u_char * s_in, int l_in, u_char * s_out, int *l_out);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/warranty.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/warranty.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/warranty.h	(revision 10506)
@@ -0,0 +1,24 @@
+static char *warranty_str[] = {
+"			    NO WARRANTY\n",
+"\n",
+"  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
+"FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
+"OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
+"PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
+"OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
+"MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
+"TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
+"PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
+"REPAIR OR CORRECTION.\n",
+"\n",
+"  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
+"WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
+"REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
+"INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
+"OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
+"TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
+"YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
+"PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
+"POSSIBILITY OF SUCH DAMAGES.\n",
+"\n",
+"		     END OF TERMS AND CONDITIONS\n"};
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/warranty.src
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/warranty.src	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/warranty.src	(revision 10506)
@@ -0,0 +1,23 @@
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/weights.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/weights.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/weights.c	(revision 10506)
@@ -0,0 +1,158 @@
+/**************************************************************************
+ *
+ * weights.c -- Functions for reading the weights file in mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "filestats.h"
+#include "memlib.h"
+#include "messages.h"
+#include "timing.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg.h"
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "weights.h"
+#include "locallib.h"
+#include "mg_errors.h"
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+/*
+   $Log$
+   Revision 1.1  1999/08/10 21:18:27  sjboddie
+   renamed mg-1.3d directory mg
+
+   Revision 1.1  1998/11/17 09:35:51  rjmcnab
+   *** empty log message ***
+
+   * Revision 1.2  1994/09/20  04:42:18  tes
+   * For version 1.1
+   *
+ */
+
+static char *RCSID = "$Id$";
+
+
+
+approx_weights_data *
+LoadDocWeights (File * weight_file,
+		unsigned long num_of_docs)
+{
+  approx_weights_data *awd;
+  int num;
+
+  if (!(awd = Xmalloc (sizeof (*awd))))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  Fseek (weight_file, sizeof (long), 0);
+  Fread (&awd->bits, sizeof (awd->bits), 1, weight_file);
+  Fread (&awd->L, sizeof (awd->L), 1, weight_file);
+  NTOHD(awd->L);  /* [RPAP - Jan 97: Endian Ordering] */
+  Fread (&awd->B, sizeof (awd->B), 1, weight_file);
+  NTOHD(awd->B);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  awd->mask = awd->bits == 32 ? 0xffffffff : (1 << awd->bits) - 1;
+
+  num = (num_of_docs * awd->bits + 31) / 32;
+  if (!(awd->DocWeights = Xmalloc (sizeof (unsigned long) * num)))
+    {
+      Xfree (awd);
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  Fread (awd->DocWeights, sizeof (unsigned long), num, weight_file);
+  {
+    /* [RPAP - Jan 97: Endian Ordering] */
+    unsigned long i;
+    for (i = 0; i < num; i++)
+      NTOHUL(awd->DocWeights[i]);
+  }
+
+  awd->MemForWeights = num * sizeof (unsigned long);
+  awd->num_of_docs = num_of_docs;
+
+  mg_errno = MG_NOERROR;
+
+  if (awd->bits <= 12)
+    {
+      int i, size = (1 << awd->bits);
+      if (!(awd->table = (float *) Xmalloc (size * sizeof (float))))
+	  return (awd);
+      awd->table[0] = awd->L;
+      for (i = 1; i < size; i++)
+	awd->table[i] = awd->table[i - 1] * awd->B;
+    }
+  else
+    awd->table = NULL;
+  return awd;
+}
+
+
+
+
+
+
+/*
+ * the first document in the collection has DocNum = 0
+ */
+float 
+GetLowerApproxDocWeight (approx_weights_data * awd, register int DocNum)
+{
+  register unsigned long c, Pos;
+  register unsigned long *dw;
+  if (awd == NULL)
+    return 1.0;
+#if 0
+  if (DocNum < 0 || DocNum >= awd->num_of_docs)
+    FatalError (1, "Something is wrong in \"GetDocWeight\" DocNum = %d\n",
+		DocNum);
+#endif
+  Pos = DocNum * awd->bits;
+  dw = &(awd->DocWeights[Pos / MAXBITS]);
+  Pos &= (MAXBITS - 1);
+  c = *dw >> Pos;
+  if (Pos + awd->bits > MAXBITS)
+    c |= *(dw + 1) << (MAXBITS - Pos);
+  c &= awd->mask;
+  if (awd->table)
+    return (awd->table[c]);
+  else
+    return (awd->L * pow (awd->B, (double) c));
+
+}
+
+void 
+FreeWeights (approx_weights_data * awd)
+{
+  Xfree (awd->DocWeights);
+  if (awd->table)
+    Xfree (awd->table);
+  Xfree (awd);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/weights.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/weights.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/weights.h	(revision 10506)
@@ -0,0 +1,34 @@
+/**************************************************************************
+ *
+ * weights.h -- Functions for reading the weights file in mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+#ifndef H_WEIGHTS
+#define H_WEIGHTS
+
+approx_weights_data *LoadDocWeights (File * weight_file,
+				     unsigned long num_of_docs);
+
+float GetLowerApproxDocWeight (approx_weights_data * awd, register int DocNum);
+
+void FreeWeights (approx_weights_data * awd);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/words.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/words.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/words.c	(revision 10506)
@@ -0,0 +1,34 @@
+#include "words.h"
+
+
+/* Takes the place of the old INAWORD macro. It determines
+   whether a given place in a UTF-8 encoded Unicode string
+   is part of a word. */
+int inaword (const u_char *here, const u_char *end) {
+  unsigned short c;
+  if (parse_utf8_char(here, end, &c) > 0) return is_unicode_letdig (c);
+  return 0;
+}
+
+/* Return a the UTF-8 encoded Unicode string with begining
+   unicode spaces skipped. */
+u_char *skipspace(u_char *here, u_char *end)
+{
+  unsigned short c;	
+  int length;
+  while(here != end) {
+    length = parse_utf8_char(here, end, &c);
+    if (length == 0 || !is_unicode_space(c)) break;
+    here += length;
+  }
+  return here;
+}
+
+/* It determines whether a given place in a UTF-8 encoded 
+   Unicode string is a unicode space. */
+int isaspace (const u_char *here, const u_char *end)
+{
+  unsigned short c;
+  if (parse_utf8_char(here, end, &c) > 0) return is_unicode_space(c);
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/words.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/words.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/src/text/words.h	(revision 10506)
@@ -0,0 +1,395 @@
+/**************************************************************************
+ *
+ * words.h -- Macros for parsing out words from the source text
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#include "sysfuncs.h"
+#include "unitool.h"
+
+/*
+ * This has been cleaned up by Tim Shimmin. 
+ */
+
+/*
+ * ---NOTE---
+ *
+ * "WORD" refers to a word in the compressed text.
+ * "STEM" or "STEM_WORD" refers to a word for indexing on
+ *
+ */
+
+#define MAXWORDLEN	15
+	/* Maximum length in bytes of any word or non-word. Note that
+	   variations to MAXWORDLEN may have dramatic effects on the rest
+	   of the program, as the length and the prefix match are packed
+	   together into a four bit nibble, and there is not check that
+	   this is possible, i.e., leave MAXWORDLEN alone... */
+
+#define MAXSTEMLEN	255
+	/* Maximum length in bytes of any stem. Note that
+	   variations to MAXSTEMLEN may have dramatic effects on the rest
+	   of the program, , i.e., leave MAXSTEMLEN alone... */
+
+/*#define MAXNUMERIC	4*/
+
+	/* Maximum number of numeric characters permitted in a word.
+	   This avoids long sequences of numbers creating just one
+	   word occurrence for each number. At most 10,000 all numeric
+	   words will be permitted. */
+
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAXPARAMLEN     20
+        /* Maximum number of bytes to read for a parameter value for a
+	   term in a query. */
+#define WEIGHTPARAM     '/'
+#define STEMPARAM       '#'
+
+/* [RJM 07/97: Ranked Required Terms] */
+#define MUSTMATCHPARAM     '+'
+
+
+#define PESINAWORD(c)      (isalnum(c) || ((c) >= 0x80 && (c) <= 0xff))
+        /* The definition of what characters are permitted in a word.
+	   This macro is pessimistic, you cannot tell from a particular
+	   byte above 0x80 whether it is a character or not. This function
+	   is needed by various functions relating to huffman coding
+	   where frequency counts need to be primed, it should not be
+	   used in parsing the UTF-8 encoded input. */
+
+int inaword (const u_char *here, const u_char *end);
+        /* Takes the place of the old INAWORD macro. It determines
+	   whether a given place in a UTF-8 encoded Unicode string
+	   is part of a word. */
+
+int isaspace (const u_char *here, const u_char *end);
+        /* It determines whether a given place in a UTF-8 encoded 
+	   Unicode string is a unicode space. */
+ 
+u_char *skipspace(u_char *here, u_char *end);
+        /* Return a the UTF-8 encoded Unicode string with beginning 
+	   unicode spaces skipped. */
+ 
+
+/* =========================================================================
+ * Macro: PARSE_WORD
+ * Description: 
+ *      Extract a word out for compressing text
+ * Input: 
+ *      s_in = string start in buffer
+ *      end = string end in buffer
+ * Output: 
+ *      Word = extracted word with length in 1st byte
+ *      s_in = ptr to next character in buffer yet to be processed
+ * ========================================================================= */
+#define PARSE_WORD(Word, s_in, end)                                \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    register u_char *wptr = (Word)+1;                              \
+    register int length = 0;                                       \
+    register int numeric = 0;                                      \
+    unsigned short c;                                              \
+    register int maxnumeric = IntEnv (GetEnv ("maxnumeric"), 4);   \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (length+charlength <= MAXWORDLEN && charlength > 0 &&    \
+	   (is_unicode_letter(c) || (is_unicode_digit(c) &&        \
+				     ++numeric <= maxnumeric))) {  \
+      while (charlength-- > 0) {                                   \
+        *wptr++ = *(s_in)++; ++length;                             \
+      }                                                            \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+    *(Word) = length;                                              \
+  }while(0)
+
+  /*  
+#define PARSE_WORD(Word, s_in, end)                                  \
+  do {                                                               \
+	  register u_char  *wptr = (Word)+1;                         \
+	  register int    length = 0;                                \
+	  register int    c = *(s_in);                               \
+	  register int	numeric = 0;                                 \
+                                                                     \
+	  while( length < MAXWORDLEN && INAWORD(c) && (s_in)<=(end)) \
+	    {                                                        \
+	      if ((numeric += INNUMBER(c)) > MAXNUMERIC)             \
+		break;                                               \
+	      *wptr++ = c;                                           \
+	      ++length;                                              \
+	      c = *++(s_in);                                         \
+	    }                                                        \
+	  *(Word) = length;                                          \
+  }while(0)
+  */
+
+
+/* =========================================================================
+ * Macro: PARSE_NON_WORD
+ * Description: 
+ *      Extract a non-word out for storing compressed text
+ * Input: as above
+ * Output: as above
+ * ========================================================================= */
+#define PARSE_NON_WORD(Word, s_in, end)                            \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    register u_char *wptr = (Word)+1;                              \
+    register int length = 0;                                       \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (length+charlength <= MAXWORDLEN && charlength > 0 &&    \
+	   !is_unicode_letdig(c)) {                                \
+      while (charlength-- > 0) {                                   \
+        *wptr++ = *(s_in)++; ++length;                             \
+      }                                                            \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+    *(Word) = length;                                              \
+  }while(0)
+
+    /*
+#define PARSE_NON_WORD(Word, s_in, end)                            \
+  do {                                                             \
+	  register u_char  *wptr = (Word)+1;                       \
+	  register int    length = 0;                              \
+	  register int    c = *(s_in);                             \
+                                                                   \
+	  while( length < MAXWORDLEN && !INAWORD(c) && (s_in)<=(end) ) \
+	    {                                                      \
+	      *wptr++ = c;                                         \
+	      ++length;                                            \
+	      c = *++(s_in);                                       \
+	    }                                                      \
+	  *(Word) = length;                                        \
+  }while(0)
+    */
+
+
+/* =========================================================================
+ * Macro: PARSE_STEM_WORD 
+ * Description: 
+ *      Extracts out Word.      
+ * Input: 
+ *      s_in points to 1st letter in buffer to test
+ *      end points to last letter in buffer
+ * Output: 
+ *      s_in is modified to move to next word
+ *      Returns Word filled in with length in 1st byte.
+ * ========================================================================= */
+#define PARSE_STEM_WORD(Word, s_in, end)                           \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    register u_char *wptr = (Word)+1;                              \
+    register int length = 0;                                       \
+    register int numeric = 0;                                      \
+    unsigned short c;                                              \
+    register int maxnumeric = IntEnv (GetEnv ("maxnumeric"), 4);   \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (length+charlength <= MAXSTEMLEN && charlength > 0 &&    \
+	   (is_unicode_letter(c) || (is_unicode_digit(c) &&        \
+				     ++numeric <= maxnumeric))) {  \
+      while (charlength-- > 0) {                                   \
+        *wptr++ = *(s_in)++; ++length;                             \
+      }                                                            \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+    *(Word) = length;                                              \
+  }while(0)
+    /*
+#define PARSE_STEM_WORD(Word, s_in, end)                      \
+  do                                                          \
+    {                                                         \
+      register u_char  *wptr = (Word)+1;                      \
+      register int    length = 0;                             \
+      register int    c = *(s_in);                            \
+      register int    numeric = 0;                            \
+                                                              \
+      while ( length < MAXSTEMLEN && INAWORD(c) && (s_in)<=(end)) \
+        {                                                     \
+ 	  if ((numeric += INNUMBER(c)) > MAXNUMERIC)          \
+	    break;                                            \
+	  *wptr++ = c;                                        \
+	  ++length;                                           \
+	  c = *++(s_in);                                      \
+	}                                                     \
+      *(Word) = length;                                       \
+    }while(0)
+    */
+
+
+/* =========================================================================
+ * Macro: PARSE_NON_STEM_WORD 
+ * Description: 
+ *      Eat up non-word. Do not store non-word.
+ *      It is not needed in index only in text !
+ *      
+ * Input: as above but no Word needed
+ * Output: as above
+ * ========================================================================= */
+#define PARSE_NON_STEM_WORD(s_in, end)                             \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (charlength > 0 && !is_unicode_letdig(c)) {              \
+      (s_in) += charlength;                                        \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+  }while(0)
+
+    /*
+#define PARSE_NON_STEM_WORD(s_in, end)           \
+  do                                             \
+    {                                            \
+      while (!INAWORD(*(s_in)) && (s_in)<=(end)) \
+	(s_in)++;                                \
+    }while(0)
+    */
+
+
+/* =========================================================================
+ * Macro: PARSE_NON_STEM_WORD_OR_SGML_TAG 
+ * Description: 
+ *      Like PARSE_NON_STEM_WORD but also eats up SGML tags
+ * Input: as above
+ * Output: as above
+ * ========================================================================= */
+#define PARSE_NON_STEM_WORD_OR_SGML_TAG(s_in, end)                 \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (charlength > 0 && !is_unicode_letdig(c)) {              \
+      if (c == '<') {                                              \
+	while (charlength > 0 && c != '>') {                       \
+	  (s_in) += charlength;                                    \
+	  charlength = parse_utf8_char((s_in),(end),&c);           \
+	}                                                          \
+      }                                                            \
+      (s_in) += charlength;                                        \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+  }while(0)
+
+    /*
+#define PARSE_NON_STEM_WORD_OR_SGML_TAG(s_in, end) \
+  do                                               \
+    {                                              \
+      register int    c = *(s_in);                 \
+                                                   \
+      while (!INAWORD(c) && (s_in)<=(end))         \
+        {                                          \
+	  if (c == '<')                            \
+            {                                      \
+	      while (c != '>' && (s_in)<=(end))    \
+		c = *++(s_in);                     \
+            }                                      \
+	  if ((s_in)<=(end))                       \
+	    c = *++(s_in);                         \
+	}                                          \
+    }while(0)
+    */
+
+
+/* =========================================================================
+ * Macro: PARSE_OPT_TERM_PARAM     [RPAP - Jan 97: Stem Index Change]
+ * Description: 
+ *      Extracts out optional paramater for query term.
+ *      Needed only in parsing the query line !
+ *
+ *      Note: that this function has not been converted to use UTF-8
+ *            as it should still work as it is (only uses ascii
+ *            characters)
+ *      
+ * Input: as above but no Word needed
+ * Output: as above
+ * ========================================================================= */
+#define PARSE_OPT_TERM_PARAM(Param, type, s_in, end)                       \
+  do                                                                       \
+    {                                                                      \
+	  register u_char  *wptr = (Param);                                \
+	  register int    length = 0;                                      \
+	  register int    c = *(s_in);                                     \
+                                                                           \
+          if (c == WEIGHTPARAM || c == STEMPARAM)                          \
+	    {                                                              \
+	      type = c;                                                    \
+	      c = *++(s_in);                                               \
+	      while( length < MAXPARAMLEN && isdigit(c) && (s_in)<=(end))  \
+		{                                                          \
+	           *wptr++ = c;                                            \
+	           ++length;                                               \
+	           c = *++(s_in);                                          \
+	        }                                                          \
+	      *wptr = '\0';                                                \
+              for (; isdigit(c) && (s_in)<=(end); c = *++(s_in))           \
+                ;                                                          \
+            }							           \
+    }while(0)
+
+/* =========================================================================
+ * Macro: PARSE_RANKED_NON_STEM_WORD    [RJM 07/97: Ranked Required Terms]
+ * Description: 
+ *      Eat up non-word. Do not store non-word.
+ *      If come across a match requirement store it in require_match
+ *      It is not needed in index only in text !
+ *      
+ * Input: as above
+ * Output: the requirement mode for the next term. -1=must not match,
+ *      0=optional match, 1=must match
+ * ========================================================================= */
+#define PARSE_RANKED_NON_STEM_WORD(require_match, s_in, end)       \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    unsigned short c;                                              \
+    (require_match) = 0;                                           \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (charlength > 0 && !is_unicode_letdig(c)) {              \
+      if (c == MUSTMATCHPARAM) (require_match) = 1;                \
+      (s_in) += charlength;                                        \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+  }while(0)
+
+    /*
+#define PARSE_RANKED_NON_STEM_WORD(require_match, s_in, end)         \
+  do {                                            \
+    (require_match) = 0;                          \
+    while (!INAWORD(*(s_in)) && (s_in)<=(end)) {  \
+      if (*(s_in) == MUSTMATCHPARAM) {            \
+        (require_match) = 1;                      \
+      }                                           \
+      (s_in)++;                                   \
+    }                                             \
+  } while (0)
+    */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/stamp-h.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/stamp-h.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/stamp-h.in	(revision 10506)
@@ -0,0 +1,1 @@
+timestamp
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/stemmerinterface.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/stemmerinterface.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/stemmerinterface.c	(revision 10506)
@@ -0,0 +1,39 @@
+#include "lib/lovinstem.h"
+#include <stdio.h>
+#include <ctype.h>
+
+int main () {
+  char word[256];
+  char c;
+  int len;
+
+  c = fgetc (stdin);
+  while (!feof (stdin)) {
+    /* output non words */
+    while (!feof (stdin) && !isalnum (c)) {
+      fputc (c, stdout);
+      c = fgetc (stdin);
+    }
+
+    /* get the word */
+    len = 0;
+    while (!feof (stdin) && isalnum (c) && len < 255) {
+      len++;
+      word[len] = c;
+      c = fgetc (stdin);
+    }
+    word[0] = len;
+
+    /* if we found a word stem and output it */
+    if (len > 0) {
+      lovinstem (word);
+      len = 0;
+      while (len < word[0]) {
+        len++;
+        fputc(word[len], stdout);
+      }
+    }
+  }
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/sysfuncs.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/sysfuncs.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/sysfuncs.h	(revision 10506)
@@ -0,0 +1,362 @@
+/* System dependent definitions for GNU tar.
+   Copyright (C) 1994 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * [TS:Aug/95]
+ * Based on code from system.h file in GNU's tar package 
+ *
+ */
+
+#ifndef SYSFUNCS_H
+#define SYSFUNCS_H
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__
+#  include <WIN32cfg.h>
+# else
+#  include <config.h>
+# endif
+#endif
+
+/* Declare alloca.  AIX requires this to be the first thing in the file.  */
+
+#ifdef __GNUC__
+#ifndef alloca
+#define alloca __builtin_alloca
+#endif
+#else
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+#pragma alloca
+#else
+#ifndef alloca
+char *alloca ();
+#endif
+#endif
+#endif
+#endif
+
+#include <sys/types.h>
+
+/* ------------------------------------------------- */
+/* [TS:Aug/95]
+ * Some extra include files that mg needs
+ */
+#include <stdlib.h>
+#include <math.h>
+
+#ifndef log2
+# ifndef M_LN2
+#  define M_LN2 0.69314718055994530942
+# endif
+# define log2(x) (log(x)/M_LN2)
+#endif
+
+
+#ifndef HAVE_SETBUFFER
+# define setbuffer(f, b, s)  setvbuf(f, b, _IOFBF, s)
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#if defined(__MSDOS__)  && !defined(__WIN32__)
+# define SHORT_SUFFIX 1
+#endif
+
+
+
+#include <assert.h>
+
+/* ------------------------------------------------- */
+
+/* Declare a generic pointer type.  */
+#if __STDC__ || defined(__TURBOC__)
+#define voidstar void *
+#else
+#define voidstar char *
+#endif
+
+/* Declare ISASCII.  */
+
+#include <ctype.h>
+
+#if STDC_HEADERS
+#define ISASCII(Char) 1
+#else
+#ifdef isascii
+#define ISASCII(Char) isascii (Char)
+#else
+#if HAVE_ISASCII
+#define ISASCII(Char) isascii (Char)
+#else
+#define ISASCII(Char) 1
+#endif
+#endif
+#endif
+
+
+/* ------------------------------------------------- */
+/* [TS:Aug/95] 
+ * The following is copied from GNU Autoconf.Info (1.1)   
+ * It sets up the approriate string and memory functions.
+ */
+
+#if STDC_HEADERS || HAVE_STRING_H
+#include <string.h>
+   /* An ANSI string.h and pre-ANSI memory.h might conflict */
+#if !STDC_HEADERS && HAVE_MEMORY_H
+#include <memory.h>
+#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
+#ifndef index
+/*#define index strchr 
+ *
+ * this is stuffing up our code so its commented out */
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy((d), (s), (n))
+#endif
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n) memset((s), 0, (n))
+#endif
+#else /* not STDC_HEADERS and not HAVE_STRING_H */
+#include <strings.h>
+   /* memory.h and strings.h conflict on some systems */
+#endif
+/* ------------------------------------------------- */
+
+
+/* Declare errno.  */
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+/* Declare open parameters.  */
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif
+
+#ifndef	O_BINARY
+#define O_BINARY 0
+#endif
+#ifndef O_CREAT
+#define O_CREAT 0
+#endif
+#ifndef	O_NDELAY
+#define O_NDELAY 0
+#endif
+#ifndef	O_RDONLY
+#define O_RDONLY 0
+#endif
+#ifndef O_RDWR
+#define O_RDWR 2
+#endif
+
+/* Declare file status routines and bits.  */
+
+#include <sys/stat.h>
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISMPB
+#undef S_ISMPC
+#undef S_ISNWK
+#undef S_ISREG
+#undef S_ISSOCK
+#endif
+
+/* On MSDOS, there are missing things from <sys/stat.h>.  */
+#if defined(__MSDOS__)
+#define S_ISUID 0
+#define S_ISGID 0
+#define S_ISVTX 0
+#endif
+
+#if defined(__GNUC__) && defined(__WIN32__)
+#include <limits.h>
+#endif
+
+#ifndef S_ISREG			/* POSIX.1 stat stuff missing */
+#define mode_t unsigned short
+#endif
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(Mode) (((Mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(Mode) (((Mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(Mode) (((Mode) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(Mode) (((Mode) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(Mode) (((Mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB)	/* V7 */
+#define S_ISMPB(Mode) (((Mode) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(Mode) (((Mode) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK)	/* HP/UX */
+#define S_ISNWK(Mode) (((Mode) & S_IFMT) == S_IFNWK)
+#endif
+
+#if !defined(S_ISCTG) && defined(S_IFCTG)	/* contiguous file */
+#define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
+#endif
+#if !defined(S_ISVTX)
+#define S_ISVTX 0001000
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#if !defined(_POSIX_SOURCE) && !defined(__WIN32__)
+#include <sys/param.h>
+#endif
+
+/* Include <unistd.h> before any preprocessor test of _POSIX_VERSION.  */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+/* Declare standard functions.  */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+voidstar malloc ();
+voidstar realloc ();
+char *getenv ();
+#endif
+
+#include <stdio.h>
+
+#ifndef _POSIX_VERSION
+#if defined(__WIN32__)
+#include <io.h>
+#define lseek _lseek
+#elif defined(__MSDOS__)
+#include <io.h>
+#else
+off_t lseek ();
+#endif
+#endif
+
+#include <pathmax.h>
+
+/* jrm21 2003 - this is in unistd.h now */
+#ifndef HAVE_UNISTD_H
+#include <getopt.h>
+#endif
+
+#ifdef WITH_DMALLOC
+#undef HAVE_VALLOC
+#define DMALLOC_FUNC_CHECK
+#include <dmalloc.h>
+#endif
+
+/* Prototypes for external functions.  */
+
+#ifndef __P
+#if PROTOTYPES
+#define __P(Args) Args
+#else
+#define __P(Args) ()
+#endif
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#if ENABLE_NLS
+#include <libintl.h>
+#define _(Text) gettext (Text)
+#else
+#define textdomain(Domain)
+#define _(Text) Text
+#endif
+
+/* Library modules.  */
+
+#if (HAVE_VPRINTF || HAVE_DOPRNT) && __STDC__
+/*void error __P ((int, int, const char *,...));*/
+void error (int, int, const char *,...);
+#else
+void error (int, int, char *, char *, char *, char *, char *, char *, char *, char *, char *);
+#endif
+
+#ifndef HAVE_STRSTR
+char *strstr __P ((const char *, const char *));
+#endif
+
+/* [RB/TS:Oct/95] commented out. Used by lib/gmalloc.c - but it defines it anyway ???
+ *#ifndef HAVE_VALLOC
+ *#define valloc(Size) malloc (Size)
+ *#endif
+ */
+
+voidstar xmalloc __P ((size_t));
+voidstar xrealloc __P ((voidstar, size_t));
+char *xstrdup __P ((const char *));
+
+/* [TS:Aug/95] 
+ * These were required by files which referred 
+ * to these as function pointers. 
+ * e.g. huffman.c - fread,  mgfelics.c - fgetc
+ */
+#ifndef HAVE_FREAD_DECL
+extern size_t   fread __P ((void *, size_t, size_t, FILE *));
+#endif
+#ifndef HAVE_FGETC_DECL
+extern int      fgetc __P ((FILE *));
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifndef u_long
+# define u_long unsigned long
+#endif
+#ifndef u_char
+# define u_char unsigned char
+#endif
+
+
+#endif /* SYSFUNCS_H */
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/Makefile
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/Makefile	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/Makefile	(revision 10506)
@@ -0,0 +1,10 @@
+DISTFILES = Makefile q1 q2 q3 r1 r2 r3 mgrc1 mgrc2 mgrc3 testmg \
+            alice.sum simple_sum.c alice.len
+
+all: simple_sum
+
+dist:
+	ln $(DISTFILES) $(distdir)
+
+simple_sum: simple_sum.c
+	cc -o $@ $?
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/alice.len
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/alice.len	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/alice.len	(revision 10506)
@@ -0,0 +1,2 @@
+./mgdata/alice/alice.invf.dict.hash: 13256
+./mgdata/alice/alice.text.dict: 19321
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/alice.sum
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/alice.sum	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/alice.sum	(revision 10506)
@@ -0,0 +1,8 @@
+./mgdata/alice/alice.invf: 2618428 19209
+./mgdata/alice/alice.invf.chunk: 189460 2134
+./mgdata/alice/alice.invf.chunk.trans: 331998 2585
+./mgdata/alice/alice.invf.dict.blocked: 1030626 33214
+./mgdata/alice/alice.invf.idx: 309022 7572
+./mgdata/alice/alice.text: 5075885 40099
+./mgdata/alice/alice.text.idx: 185535 3380
+./mgdata/alice/alice.text.stats: 2432380 49146
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/mgrc1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/mgrc1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/mgrc1	(revision 10506)
@@ -0,0 +1,2 @@
+.set mode text
+.set query boolean
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/mgrc2
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/mgrc2	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/mgrc2	(revision 10506)
@@ -0,0 +1,2 @@
+.set mode text
+.set query ranked
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/mgrc3
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/mgrc3	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/mgrc3	(revision 10506)
@@ -0,0 +1,2 @@
+.set mode docnums
+.set query boolean
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/q1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/q1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/q1	(revision 10506)
@@ -0,0 +1,1 @@
+flamingo
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/q2
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/q2	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/q2	(revision 10506)
@@ -0,0 +1,1 @@
+flamingo
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/q3
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/q3	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/q3	(revision 10506)
@@ -0,0 +1,2 @@
+Rabbit & !(Alice | she)
+laser
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/r1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/r1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/r1	(revision 10506)
@@ -0,0 +1,46 @@
+> flamingo
+flamingo
+---------------------------------- 482
+  The chief difficulty Alice found at first was in managing her 
+flamingo:  she succeeded in getting its body tucked away, 
+comfortably enough, under her arm, with its legs hanging down, 
+but generally, just as she had got its neck nicely straightened 
+out, and was going to give the hedgehog a blow with its head, it 
+WOULD twist itself round and look up in her face, with such a 
+puzzled expression that she could not help bursting out laughing:  
+and when she had got its head down, and was going to begin again, 
+it was very provoking to find that the hedgehog had unrolled 
+itself, and was in the act of crawling away:  besides all this, 
+there was generally a ridge or furrow in the way wherever she 
+wanted to send the hedgehog to, and, as the doubled-up soldiers 
+were always getting up and walking off to other parts of the 
+ground, Alice soon came to the conclusion that it was a very 
+difficult game indeed. 
+---------------------------------- 487
+  Alice waited till the eyes appeared, and then nodded.  `It's no 
+use speaking to it,' she thought, `till its ears have come, or at 
+least one of them.'  In another minute the whole head appeared, 
+and then Alice put down her flamingo, and began an account of the 
+game, feeling very glad she had someone to listen to her.  The 
+Cat seemed to think that there was enough of it now in sight, and 
+no more of it appeared. 
+---------------------------------- 502
+  The hedgehog was engaged in a fight with another hedgehog, 
+which seemed to Alice an excellent opportunity for croqueting one 
+of them with the other:  the only difficulty was, that her 
+flamingo was gone across to the other side of the garden, where 
+Alice could see it trying in a helpless sort of way to fly up 
+into a tree. 
+---------------------------------- 503
+  By the time she had caught the flamingo and brought it back, 
+the fight was over, and both the hedgehogs were out of sight:  
+`but it doesn't matter much,' thought Alice, `as all the arches 
+are gone from the side of the ground.'  So she tucked it away 
+under her arm, that it might not escape again, and went back for 
+a little more conversation with her friend. 
+---------------------------------- 526
+  `I dare say you're wondering why I don't put my arm round your 
+waist,' the Duchess said after a pause:  `the reason is, that I'm 
+doubtful about the temper of your flamingo.  Shall I try the 
+experiment?' 
+5 documents retrieved.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/r2
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/r2	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/r2	(revision 10506)
@@ -0,0 +1,46 @@
+> flamingo
+flamingo
+---------------------------------- 526 1.322623
+  `I dare say you're wondering why I don't put my arm round your 
+waist,' the Duchess said after a pause:  `the reason is, that I'm 
+doubtful about the temper of your flamingo.  Shall I try the 
+experiment?' 
+---------------------------------- 503 1.013693
+  By the time she had caught the flamingo and brought it back, 
+the fight was over, and both the hedgehogs were out of sight:  
+`but it doesn't matter much,' thought Alice, `as all the arches 
+are gone from the side of the ground.'  So she tucked it away 
+under her arm, that it might not escape again, and went back for 
+a little more conversation with her friend. 
+---------------------------------- 502 1.009519
+  The hedgehog was engaged in a fight with another hedgehog, 
+which seemed to Alice an excellent opportunity for croqueting one 
+of them with the other:  the only difficulty was, that her 
+flamingo was gone across to the other side of the garden, where 
+Alice could see it trying in a helpless sort of way to fly up 
+into a tree. 
+---------------------------------- 487 0.882496
+  Alice waited till the eyes appeared, and then nodded.  `It's no 
+use speaking to it,' she thought, `till its ears have come, or at 
+least one of them.'  In another minute the whole head appeared, 
+and then Alice put down her flamingo, and began an account of the 
+game, feeling very glad she had someone to listen to her.  The 
+Cat seemed to think that there was enough of it now in sight, and 
+no more of it appeared. 
+---------------------------------- 482 0.529432
+  The chief difficulty Alice found at first was in managing her 
+flamingo:  she succeeded in getting its body tucked away, 
+comfortably enough, under her arm, with its legs hanging down, 
+but generally, just as she had got its neck nicely straightened 
+out, and was going to give the hedgehog a blow with its head, it 
+WOULD twist itself round and look up in her face, with such a 
+puzzled expression that she could not help bursting out laughing:  
+and when she had got its head down, and was going to begin again, 
+it was very provoking to find that the hedgehog had unrolled 
+itself, and was in the act of crawling away:  besides all this, 
+there was generally a ridge or furrow in the way wherever she 
+wanted to send the hedgehog to, and, as the doubled-up soldiers 
+were always getting up and walking off to other parts of the 
+ground, Alice soon came to the conclusion that it was a very 
+difficult game indeed. 
+5 documents retrieved.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/r3
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/r3	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/r3	(revision 10506)
@@ -0,0 +1,21 @@
+> Rabbit & !(Alice | she)
+Rabbit Alice she
+     14.14     
+    126.126    
+    143.143    
+    478.478    
+    701.701    
+    704.704    
+    705.705    
+    755.755    
+    774.774    
+    786.786    
+    788.788    
+    791.791    
+    793.793    
+    801.801    
+    803.803    
+15 documents retrieved.
+> laser
+laser
+No entries correspond to that query.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/simple_sum.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/simple_sum.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/mg/test/simple_sum.c	(revision 10506)
@@ -0,0 +1,100 @@
+/**************************************************************************
+ *
+ * sum.c -- byte summing program
+ * Copyright (C) 1995  Tim Shimmin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+/*
+$Log$
+Revision 1.1  1999/08/10 21:18:33  sjboddie
+renamed mg-1.3d directory mg
+
+Revision 1.1  1998/11/17 09:36:00  rjmcnab
+*** empty log message ***
+
+*/
+
+/*
+ * If given -l option then just prints the length.
+ * Normally prints the sum and the length for the file.
+ */
+
+static int length_only = 0;
+
+#include <stdio.h>
+
+void 
+output_sum(fname, input_file, output_file)
+char *fname;
+FILE *input_file;
+FILE *output_file;
+{
+  int ch = '\0';
+  unsigned long sum = 0;
+  unsigned long num_bytes = 0;
+
+  while((ch = getc(input_file))!=EOF){
+    sum += ch;
+    num_bytes++;
+  }
+
+  if (length_only)
+    fprintf(output_file, "%s: %ld\n", fname, num_bytes);
+  else
+    fprintf(output_file, "%s: %ld %ld\n", fname, sum, num_bytes);
+}
+
+void
+main(argc, argv)
+int argc;
+char *argv[];
+{
+  int i = 0;
+
+  /* use stdin */
+  if (argc == 1){
+    output_sum("-", stdin, stdout);
+    exit(0);
+  }
+
+  /* use args as file names for input */
+  for (i=1;i<argc; i++){
+    char *fname = argv[i];
+    FILE *input_file = NULL;
+    
+    if (!length_only && (argv[i][0] == '-') && (argv[i][1] =='l') ) 
+      { 
+        length_only = 1; 
+        continue;
+      }
+
+    input_file = fopen(fname, "r");
+    if (!input_file){
+      fprintf(stderr,"Could not open %s\n", fname);
+      continue;
+    }
+    else{
+      output_sum(fname, input_file, stdout);
+      fclose(input_file);
+    }
+  }/*for*/
+  exit(0);
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/pdftohtml/readme-gs.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/pdftohtml/readme-gs.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/pdftohtml/readme-gs.txt	(revision 10506)
@@ -0,0 +1,16 @@
+This is pdftohtml, which was based at:
+     http://www.ra.informatik.uni-stuttgart.de/~gosho/pdftohtml/
+
+It has recently been picked up again, and is currently based at:
+    http://pdftohtml.sourceforge.net/
+
+We're currently using version 0.34 as downloaded from
+http://pdftohtml.sourceforge.net. The only alterations made to the source
+package were to remove some "CVS" directories and tidy up the makefiles
+slightly (to use ./configure as with the rest of Greenstone).
+
+Also, the #pragma statements were removed to work around a compiler bug
+on Mac OS X.
+
+Stefan Boddie
+December 2002
Index: /tags/gsdl-2_61-distribution/gsdl/packages/rtftohtml/rtftohtml-gs.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/rtftohtml/rtftohtml-gs.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/rtftohtml/rtftohtml-gs.txt	(revision 10506)
@@ -0,0 +1,56 @@
+RTF TO HTML
+-----------
+
+This is based on version 2.7.5 of rtftohtml, which was last modified in
+November, 1994.
+It contains the text:
+###
+Initial Implementation by Chris Hector (cjh@cray.com)
+(c) 1994 by Chris Hector
+May be freely distributed.
+This translator was based on rtfskel.
+###
+The last known email address I can find for him is <cjh@cray.com>.
+I think that <chris@sunpack.com> might reach him, but I'm not sure.
+
+
+Versions 3.0 of rtftohtml and up are released under a shareware license,
+and available from http://www.logictran.com (although it now has a new
+name). You can download a free binary version of the software for most
+platforms from this site.
+
+
+
+
+rtftohtml is based on RTF Tools, which is (c) April 1994 by Paul DuBois
+<dubois@primate.wisc.edu>
+
+RTF Tools has the notice:
+##
+Distribution Availability
+This software may be redistributed without restriction and used for any
+purpose whatsoever.
+##
+
+The supplied version understands RTF version 1.2, while the
+latest version of the specification is RTF 1.6 (May 1999).
+
+I have added some of the newer rtf codes that were preventing some files from
+being parsed properly, but they are not acted on. Most of them do not
+actually affect the content anyway. Depending on how the rtf was created,
+there might be tags that cause us to trip up and fail. If you have
+rtf files that Greenstone is not extracting text from, please send me
+some email (jrm21@cs.waikato.ac.nz).
+
+Note - we extract but do not convert Windows Metafile Format (.wmf) images.
+On unix systems, these can be converted with newer versions of ImageMagick
+(ie "convert" version 4.2.9 or newer).
+Also, libwmf (for unix and windows) is available for conversion at:
+http://wvware.sourceforge.net/projects/libwmf.html
+but we do not include it here due to its dependencies
+(eg libttf for truetype fonts).
+
+Embedded images such as jpegs and pngs are extracted fine, though.
+
+John McPherson (jrm21@cs.waikato.ac.nz)
+June 2001.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.pm	(revision 10506)
@@ -0,0 +1,198 @@
+#
+# $Id$
+
+package MIME::Base64;
+
+=head1 NAME
+
+MIME::Base64 - Encoding and decoding of base64 strings
+
+=head1 SYNOPSIS
+
+ use MIME::Base64;
+
+ $encoded = encode_base64('Aladdin:open sesame');
+ $decoded = decode_base64($encoded);
+
+=head1 DESCRIPTION
+
+This module provides functions to encode and decode strings into the
+Base64 encoding specified in RFC 2045 - I<MIME (Multipurpose Internet
+Mail Extensions)>. The Base64 encoding is designed to represent
+arbitrary sequences of octets in a form that need not be humanly
+readable. A 65-character subset ([A-Za-z0-9+/=]) of US-ASCII is used,
+enabling 6 bits to be represented per printable character.
+
+The following functions are provided:
+
+=over 4
+
+=item encode_base64($str, [$eol])
+
+Encode data by calling the encode_base64() function.  The first
+argument is the string to encode.  The second argument is the line
+ending sequence to use (it is optional and defaults to C<"\n">).  The
+returned encoded string is broken into lines of no more than 76
+characters each and it will end with $eol unless it is empty.  Pass an
+empty string as second argument if you do not want the encoded string
+broken into lines.
+
+=item decode_base64($str)
+
+Decode a base64 string by calling the decode_base64() function.  This
+function takes a single argument which is the string to decode and
+returns the decoded data.
+
+Any character not part of the 65-character base64 subset set is
+silently ignored.  Characters occuring after a '=' padding character
+are never decoded.
+
+If the length of the string to decode (after ignoring
+non-base64 chars) is not a multiple of 4 or padding occurs too ealy,
+then a warning is generated if perl is running under C<-w>.
+
+=back
+
+If you prefer not to import these routines into your namespace you can
+call them as:
+
+    use MIME::Base64 ();
+    $encoded = MIME::Base64::encode($decoded);
+    $decoded = MIME::Base64::decode($encoded);
+
+=head1 DIAGNOSTICS
+
+The following warnings might be generated if perl is invoked with the
+C<-w> switch:
+
+=over 4
+
+=item Premature end of base64 data
+
+The number of characters to decode is not a multiple of 4.  Legal
+base64 data should be padded with one or two "=" characters to make
+its length a multiple of 4.  The decoded result will anyway be as if
+the padding was there.
+
+=item Premature padding of base64 data
+
+The '=' padding character occurs as the first or second character
+in a base64 quartet.
+
+=back
+
+=head1 EXAMPLES
+
+If you want to encode a large file, you should encode it in chunks
+that are a multiple of 57 bytes.  This ensures that the base64 lines
+line up and that you do not end up with padding in the middle. 57
+bytes of data fills one complete base64 line (76 == 57*4/3):
+
+   use MIME::Base64 qw(encode_base64);
+
+   open(FILE, "/var/log/wtmp") or die "$!";
+   while (read(FILE, $buf, 60*57)) {
+       print encode_base64($buf);
+   }
+
+or if you know you have enough memory
+
+   use MIME::Base64 qw(encode_base64);
+   local($/) = undef;  # slurp
+   print encode_base64(<STDIN>);
+
+=head1 COPYRIGHT
+
+Copyright 1995-1999 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+Distantly based on LWP::Base64 written by Martijn Koster
+<m.koster@nexor.co.uk> and Joerg Reichelt <j.reichelt@nexor.co.uk> and
+code posted to comp.lang.perl <3pd2lp$6gf@wsinti07.win.tue.nl> by Hans
+Mulder <hansm@wsinti07.win.tue.nl>
+
+The XS implementation use code from metamail.  Copyright 1991 Bell
+Communications Research, Inc. (Bellcore)
+
+=cut
+
+use strict;
+use vars qw(@ISA @EXPORT $VERSION $OLD_CODE);
+
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+@EXPORT = qw(encode_base64 decode_base64);
+
+$VERSION = '2.11';
+
+eval { bootstrap MIME::Base64 $VERSION; };
+if ($@) {
+    # can't bootstrap XS implementation, use perl implementation
+    *encode_base64 = \&old_encode_base64;
+    *decode_base64 = \&old_decode_base64;
+
+    $OLD_CODE = $@;
+    #warn $@ if $^W;
+}
+
+# Historically this module has been implemented as pure perl code.
+# The XS implementation runs about 20 times faster, but the Perl
+# code might be more portable, so it is still here.
+
+use integer;
+
+sub old_encode_base64 ($;$)
+{
+    my $res = "";
+    my $eol = $_[1];
+    $eol = "\n" unless defined $eol;
+    pos($_[0]) = 0;                          # ensure start at the beginning
+    while ($_[0] =~ /(.{1,45})/gs) {
+	$res .= substr(pack('u', $1), 1);
+	chop($res);
+    }
+    $res =~ tr|` -_|AA-Za-z0-9+/|;               # `# help emacs
+    # fix padding at the end
+    my $padding = (3 - length($_[0]) % 3) % 3;
+    $res =~ s/.{$padding}$/'=' x $padding/e if $padding;
+    # break encoded string into lines of no more than 76 characters each
+    if (length $eol) {
+	$res =~ s/(.{1,76})/$1$eol/g;
+    }
+    $res;
+}
+
+
+sub old_decode_base64 ($)
+{
+    local($^W) = 0; # unpack("u",...) gives bogus warning in 5.00[123]
+
+    my $str = shift;
+    my $res = "";
+
+    $str =~ tr|A-Za-z0-9+=/||cd;            # remove non-base64 chars
+    if (length($str) % 4) {
+	require Carp;
+	Carp::carp("Length of base64 data not a multiple of 4")
+    }
+    $str =~ s/=+$//;                        # remove padding
+    $str =~ tr|A-Za-z0-9+/| -_|;            # convert to uuencoded format
+    while ($str =~ /(.{1,60})/gs) {
+	my $len = chr(32 + length($1)*3/4); # compute length byte
+	$res .= unpack("u", $len . $1 );    # uudecode
+    }
+    $res;
+}
+
+# Set up aliases so that these functions also can be called as
+#
+#    MIME::Base64::encode();
+#    MIME::Base64::decode();
+
+*encode = \&encode_base64;
+*decode = \&decode_base64;
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.xs
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.xs	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Base64.xs	(revision 10506)
@@ -0,0 +1,215 @@
+/* $Id$
+
+Copyright 1997-1998 Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+The tables and some of the code that used to be here was borrowed from
+metamail, which comes with this message:
+
+  Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
+
+  Permission to use, copy, modify, and distribute this material 
+  for any purpose and without fee is hereby granted, provided 
+  that the above copyright notice and this permission notice 
+  appear in all copies, and that the name of Bellcore not be 
+  used in advertising or publicity pertaining to this 
+  material without the specific, prior written permission 
+  of an authorized representative of Bellcore.	BELLCORE 
+  MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY 
+  OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", 
+  WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
+
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#ifdef __cplusplus
+}
+#endif
+
+#include "patchlevel.h"
+#if PATCHLEVEL <= 4 && !defined(PL_dowarn)
+   #define PL_dowarn dowarn
+#endif
+
+#define MAX_LINE  76 /* size of encoded lines */
+
+static char basis_64[] =
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define XX      255	/* illegal base64 char */
+#define EQ      254	/* padding */
+#define INVALID XX
+
+static unsigned char index_64[256] = {
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
+    52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,EQ,XX,XX,
+    XX, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
+    15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
+    XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+    41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
+
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+};
+
+
+
+MODULE = MIME::Base64		PACKAGE = MIME::Base64
+
+SV*
+encode_base64(sv,...)
+	SV* sv
+	PROTOTYPE: $;$
+
+	PREINIT:
+	char *str;     /* string to encode */
+	SSize_t len;   /* length of the string */
+	char *eol;     /* the end-of-line sequence to use */
+	STRLEN eollen; /* length of the EOL sequence */
+	char *r;       /* result string */
+	STRLEN rlen;   /* length of result string */
+	unsigned char c1, c2, c3;
+	int chunk;
+
+	CODE:
+	str = SvPV(sv, rlen); /* SvPV(sv, len) gives warning for signed len */
+	len = (SSize_t)rlen;
+
+	/* set up EOL from the second argument if present, default to "\n" */
+	if (items > 1 && SvOK(ST(1))) {
+	    eol = SvPV(ST(1), eollen);
+	} else {
+	    eol = "\n";
+	    eollen = 1;
+	}
+
+	/* calculate the length of the result */
+	rlen = (len+2) / 3 * 4;	 /* encoded bytes */
+	if (rlen) {
+	    /* add space for EOL */
+	    rlen += ((rlen-1) / MAX_LINE + 1) * eollen;
+	}
+
+	/* allocate a result buffer */
+	RETVAL = newSV(rlen ? rlen : 1);
+	SvPOK_on(RETVAL);	
+	SvCUR_set(RETVAL, rlen);
+	r = SvPVX(RETVAL);
+
+	/* encode */
+	for (chunk=0; len > 0; len -= 3, chunk++) {
+	    if (chunk == (MAX_LINE/4)) {
+		char *c = eol;
+		char *e = eol + eollen;
+		while (c < e)
+		    *r++ = *c++;
+		chunk = 0;
+	    }
+	    c1 = *str++;
+	    c2 = *str++;
+	    *r++ = basis_64[c1>>2];
+	    *r++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
+	    if (len > 2) {
+		c3 = *str++;
+		*r++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
+		*r++ = basis_64[c3 & 0x3F];
+	    } else if (len == 2) {
+		*r++ = basis_64[(c2 & 0xF) << 2];
+		*r++ = '=';
+	    } else { /* len == 1 */
+		*r++ = '=';
+		*r++ = '=';
+	    }
+	}
+	if (rlen) {
+	    /* append eol to the result string */
+	    char *c = eol;
+	    char *e = eol + eollen;
+	    while (c < e)
+		*r++ = *c++;
+	}
+	*r = '\0';  /* every SV in perl should be NUL-terminated */
+
+	OUTPUT:
+	RETVAL
+
+SV*
+decode_base64(sv)
+	SV* sv
+	PROTOTYPE: $
+
+	PREINIT:
+	STRLEN len;
+	register unsigned char *str = (unsigned char*)SvPV(sv, len);
+	unsigned char const* end = str + len;
+	char *r;
+	unsigned char c[4];
+
+	CODE:
+	{
+	    /* always enough, but might be too much */
+	    STRLEN rlen = len * 3 / 4;
+	    RETVAL = newSV(rlen ? rlen : 1);
+	}
+        SvPOK_on(RETVAL);
+        r = SvPVX(RETVAL);
+
+	while (str < end) {
+	    int i = 0;
+            do {
+		unsigned char uc = index_64[*str++];
+		if (uc != INVALID)
+		    c[i++] = uc;
+
+		if (str == end) {
+		    if (i < 4) {
+			if (i && PL_dowarn)
+			    warn("Premature end of base64 data");
+			if (i < 2) goto thats_it;
+			if (i == 2) c[2] = EQ;
+			c[3] = EQ;
+		    }
+		    break;
+		}
+            } while (i < 4);
+	    
+	    if (c[0] == EQ || c[1] == EQ) {
+		if (PL_dowarn) warn("Premature padding of base64 data");
+		break;
+            }
+	    /* printf("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]);/**/
+
+	    *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
+
+	    if (c[2] == EQ)
+		break;
+	    *r++ = ((c[1] & 0x0F) << 4) | ((c[2] & 0x3C) >> 2);
+
+	    if (c[3] == EQ)
+		break;
+	    *r++ = ((c[2] & 0x03) << 6) | c[3];
+	}
+
+      thats_it:
+	SvCUR_set(RETVAL, r - SvPVX(RETVAL));
+	*r = '\0';
+
+	OUTPUT:
+	RETVAL
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Changes
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Changes	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Changes	(revision 10506)
@@ -0,0 +1,119 @@
+1998-02-27   Gisle Aas <gisle@aas.no>
+
+   Release 2.11
+
+   Fixed bogues "Premature end of base64 data" warning.  Bug spotted
+   by Dwayne Jacques Fontenot.
+
+   Workaround for Redhat shipping trial releases of perl.
+
+
+
+1998-12-18   Gisle Aas <aas@sn.no>
+
+   Release 2.10
+
+   A tweak that should make compilation with some old perl5.00[23]
+   perls better.
+
+   A cast that make some compilers more happy.
+
+
+
+1998-11-13   Gisle Aas <aas@sn.no>
+
+   Release 2.09
+
+   The 2.08 release did not compile with perl5.005_53, because
+   all simple globals now need to be prefixed with "PL_".
+
+
+
+1998-10-22   Gisle Aas <aas@sn.no>
+
+   Release 2.08
+
+   Found another tweak to speed up decode_base64() with another 3%.
+
+   Improved MIME::Base64 documentation a little.
+
+
+
+1998-10-21   Gisle Aas <aas@sn.no>
+
+   Release 2.07
+
+   Faster and smarter C implementation of the decode_base64()
+   function.  The new decode_base64() was 25% faster when tested
+   on Linux, i586, gcc -O2.
+
+
+
+1998-07-15   Gisle Aas <aas@sn.no>
+
+   Release 2.06
+
+   The decode_base64() implemented in pure perl will only carp
+   (not croak) if length of data to decode is not a multiple 4.  This
+   actually made 'make test' fail after 'rm Base64.xs'.
+
+
+
+1998-01-27   Gisle Aas <aas@sn.no>
+
+   Release 2.05
+
+   The decode_base64() would previously allocate a too short buffer for the
+   result string when the trailing "==" padding was missing in the string to
+   be decoded.
+
+   The encode_base64() now allocate one byte less space in the result
+   strings returned.
+
+
+
+1997-12-02   Gisle Aas <aas@sn.no>
+
+   Release 2.04
+
+   Documentation expanded a bit.
+
+
+
+1997-07-10   Gisle Aas <aas@sn.no>
+
+   Release 2.03
+
+   Decode_base64() doesn't croak on premature ended data any more.
+   A warning is generated instead if running under -w.
+   
+
+
+1997-06-27   Gisle Aas <aas@sn.no>
+
+   Release 2.02
+
+   QuotedPrint fix by Roderick Schertler <roderick@argon.org>:
+
+      - Long lines were not broken unless they're at the beginning
+        of the text
+
+      - Lines near but not over 76 chars were broken when they
+        shouldn't be
+
+
+
+1997-06-13   Gisle Aas <aas@sn.no>
+
+   Release 2.01
+
+   Base64.xs: Avoid type convertion warnings with some compilers
+
+   Minor documentation updates
+
+
+
+1997-04-24   Gisle Aas <aas@sn.no>
+
+   Release 2.00, based on libwww-perl-5.08.
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/INSTALL.w3mir
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/INSTALL.w3mir	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/INSTALL.w3mir	(revision 10506)
@@ -0,0 +1,27 @@
+- You also have to get the MIME-Base64 package
+  (http://www.perl.com/CPAN/modules/by-module/MIME/)
+
+- Unpack it:
+
+    gzip -dc MIME-Base64-*.tar.gz | tar xvBf -
+
+- Install it:
+
+    cd MIME-Base64-*
+
+  Then, as above, either
+
+    perl Makefile.PL
+
+  or
+
+    perl Makefile.PL PREFIX=/some/dir
+
+  Continue:
+
+    make
+    make test      (it should print 'All tests successful.')
+    make install
+
+  Now MIME-Base64 should be installed and working.
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/MANIFEST
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/MANIFEST	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/MANIFEST	(revision 10506)
@@ -0,0 +1,9 @@
+Base64.pm	Bootstrap and perl implementation of MIME::Base64
+Base64.xs	Encoder and decoder written in C
+Changes		What's new
+MANIFEST	This file
+Makefile.PL	Writes the Makefile
+QuotedPrint.pm  MIME::QuotedPrint module, encoder and decoder
+README		Please do!
+t/base64.t	Test that it works
+t/quoted-print.t
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Makefile.PL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Makefile.PL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/Makefile.PL	(revision 10506)
@@ -0,0 +1,8 @@
+require 5.002;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+    NAME	 => 'MIME::Base64',
+    VERSION_FROM => 'Base64.pm',
+    dist         => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
+);
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/QuotedPrint.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/QuotedPrint.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/QuotedPrint.pm	(revision 10506)
@@ -0,0 +1,115 @@
+#
+# $Id$
+
+package MIME::QuotedPrint;
+
+=head1 NAME
+
+MIME::QuotedPrint - Encoding and decoding of quoted-printable strings
+
+=head1 SYNOPSIS
+
+ use MIME::QuotedPrint;
+
+ $encoded = encode_qp($decoded);
+ $decoded = decode_qp($encoded);
+
+=head1 DESCRIPTION
+
+This module provides functions to encode and decode strings into the
+Quoted-Printable encoding specified in RFC 2045 - I<MIME (Multipurpose
+Internet Mail Extensions)>.  The Quoted-Printable encoding is intended
+to represent data that largely consists of bytes that correspond to
+printable characters in the ASCII character set.  Non-printable
+characters (as defined by english americans) are represented by a
+triplet consisting of the character "=" followed by two hexadecimal
+digits.
+
+The following functions are provided:
+
+=over 4
+
+=item encode_qp($str)
+
+This function will return an encoded version of the string given as
+argument.
+
+Note that encode_qp() does not change newlines C<"\n"> to the CRLF
+sequence even though this might be considered the right thing to do
+(RFC 2045 (Q-P Rule #4)).
+
+=item decode_qp($str);
+
+This function will return the plain text version of the string given
+as argument.
+
+=back
+
+
+If you prefer not to import these routines into your namespace you can
+call them as:
+
+  use MIME::QuotedPrint ();
+  $encoded = MIME::QuotedPrint::encode($decoded);
+  $decoded = MIME::QuotedPrint::decode($encoded);
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+use strict;
+use vars qw(@ISA @EXPORT $VERSION);
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(encode_qp decode_qp);
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+
+sub encode_qp ($)
+{
+    my $res = shift;
+    $res =~ s/([^ \t\n!-<>-~])/sprintf("=%02X", ord($1))/eg;  # rule #2,#3
+    $res =~ s/([ \t]+)$/
+      join('', map { sprintf("=%02X", ord($_)) }
+		   split('', $1)
+      )/egm;                        # rule #3 (encode whitespace at eol)
+
+    # rule #5 (lines must be shorter than 76 chars, but we are not allowed
+    # to break =XX escapes.  This makes things complicated :-( )
+    my $brokenlines = "";
+    $brokenlines .= "$1=\n"
+	while $res =~ s/(.*?^[^\n]{73} (?:
+		 [^=\n]{2} (?! [^=\n]{0,1} $) # 75 not followed by .?\n
+		|[^=\n]    (?! [^=\n]{0,2} $) # 74 not followed by .?.?\n
+		|          (?! [^=\n]{0,3} $) # 73 not followed by .?.?.?\n
+	    ))//xsm;
+
+    "$brokenlines$res";
+}
+
+
+sub decode_qp ($)
+{
+    my $res = shift;
+    $res =~ s/[ \t]+?(\r?\n)/$1/g;  # rule #3 (trailing space must be deleted)
+    $res =~ s/=\r?\n//g;            # rule #5 (soft line breaks)
+    $res =~ s/=([\da-fA-F]{2})/pack("C", hex($1))/ge;
+    $res;
+}
+
+# Set up aliases so that these functions also can be called as
+#
+# MIME::QuotedPrint::encode();
+# MIME::QuotedPrint::decode();
+
+*encode = \&encode_qp;
+*decode = \&decode_qp;
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/README	(revision 10506)
@@ -0,0 +1,38 @@
+This package contains a base64 encoder/decoder and a quoted-printable
+encoder/decoder.  These encoding methods are specified in RFC 2045 -
+MIME (Multipurpose Internet Mail Extensions).
+
+The Base64 encoding is designed to represent arbitrary sequences of
+octets in a form that need not be humanly readable. A 65-character
+subset ([A-Za-z0-9+/=]) of US-ASCII is used, enabling 6 bits to be
+represented per printable character.
+
+The quoted-printable encoding is intended to represent data that
+largely consists of bytes that correspond to printable characters in
+the ASCII character set.  Non-printable characters are represented by
+a triplet consisting of the character "=" followed by two hexadecimal
+digits.
+
+The MIME::Base64 and MIME::QuotedPrint modules used to be part of
+libwww-perl package.  They are now distributed separately (as this
+package).  The main improvement is that the base64 encoder/decoder is
+implemented by XS functions.  This makes it about 20 times faster than
+the old implementation as pure Perl.
+
+In order to install and use this package you will need Perl version
+5.002 or better.  Installation as usual:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+The library can also be installed without XS support (for instance because
+you don't have a working C compiler installed).  Simply remove the Base64.xs
+file before running 'perl Makefile.PL' and everything should work the same,
+although encoding and decoding will be much slower.
+
+Copyright 1995-1999 Gisle Aas <gisle@aas.no>
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/install.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/install.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/install.sh	(revision 10506)
@@ -0,0 +1,10 @@
+#!/bin/sh -v
+
+export PERL5LIB=$GSDLHOME/perllib/cpan/lib:$PERL5LIB
+export PATH=$GSDLHOME/perllib/cpan/bin:$PATH
+
+perl Makefile.PL PREFIX=$GSDLHOME/perllib/cpan
+
+make
+make test
+make install
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/t/base64.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/t/base64.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/t/base64.t	(revision 10506)
@@ -0,0 +1,362 @@
+use MIME::Base64;
+
+print "1..282\n";
+
+print "Testing MIME::Base64-", $MIME::Base64::VERSION, "\n";
+
+$testno = 1;
+
+encodeTest();
+decodeTest();
+
+# This used to generate a warning
+print "not " unless decode_base64(encode_base64("foo")) eq "foo";
+print "ok ", $testno++, "\n";
+
+sub encodeTest
+{
+    print "encode test\n";
+
+    my @encode_tests = (
+        [''    => ''],
+	['a'   => 'YQ=='],
+	['aa'  => 'YWE='],
+	['aaa' => 'YWFh'],
+
+	['aaa' => 'YWFh'],
+	['aaa' => 'YWFh'],
+	['aaa' => 'YWFh'],
+
+	["\000\377" => "AP8="],
+	["\377\000" => "/wA="],
+	["\000\000\000" => "AAAA"],
+
+	# from HTTP spec
+	['Aladdin:open sesame' => 'QWxhZGRpbjpvcGVuIHNlc2FtZQ=='],
+
+	['a' x 100 => 'YWFh' x 33 . 'YQ=='],
+
+	['Multipurpose Internet Mail Extensions: The Base64 Content-Transfer-Encoding is designed to represent sequences of octets in a form that is not humanly readable. '
+	=> "TXVsdGlwdXJwb3NlIEludGVybmV0IE1haWwgRXh0ZW5zaW9uczogVGhlIEJhc2U2NCBDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nIGlzIGRlc2lnbmVkIHRvIHJlcHJlc2VudCBzZXF1ZW5jZXMgb2Ygb2N0ZXRzIGluIGEgZm9ybSB0aGF0IGlzIG5vdCBodW1hbmx5IHJlYWRhYmxlLiA="],
+
+	# All values
+	["\000" => "AA=="],
+	["\001" => "AQ=="],
+	["\002" => "Ag=="],
+	["\003" => "Aw=="],
+	["\004" => "BA=="],
+	["\005" => "BQ=="],
+	["\006" => "Bg=="],
+	["\007" => "Bw=="],
+	["\010" => "CA=="],
+	["\011" => "CQ=="],
+	["\012" => "Cg=="],
+	["\013" => "Cw=="],
+	["\014" => "DA=="],
+	["\015" => "DQ=="],
+	["\016" => "Dg=="],
+	["\017" => "Dw=="],
+	["\020" => "EA=="],
+	["\021" => "EQ=="],
+	["\022" => "Eg=="],
+	["\023" => "Ew=="],
+	["\024" => "FA=="],
+	["\025" => "FQ=="],
+	["\026" => "Fg=="],
+	["\027" => "Fw=="],
+	["\030" => "GA=="],
+	["\031" => "GQ=="],
+	["\032" => "Gg=="],
+	["\033" => "Gw=="],
+	["\034" => "HA=="],
+	["\035" => "HQ=="],
+	["\036" => "Hg=="],
+	["\037" => "Hw=="],
+	["\040" => "IA=="],
+	["\041" => "IQ=="],
+	["\042" => "Ig=="],
+	["\043" => "Iw=="],
+	["\044" => "JA=="],
+	["\045" => "JQ=="],
+	["\046" => "Jg=="],
+	["\047" => "Jw=="],
+	["\050" => "KA=="],
+	["\051" => "KQ=="],
+	["\052" => "Kg=="],
+	["\053" => "Kw=="],
+	["\054" => "LA=="],
+	["\055" => "LQ=="],
+	["\056" => "Lg=="],
+	["\057" => "Lw=="],
+	["\060" => "MA=="],
+	["\061" => "MQ=="],
+	["\062" => "Mg=="],
+	["\063" => "Mw=="],
+	["\064" => "NA=="],
+	["\065" => "NQ=="],
+	["\066" => "Ng=="],
+	["\067" => "Nw=="],
+	["\070" => "OA=="],
+	["\071" => "OQ=="],
+	["\072" => "Og=="],
+	["\073" => "Ow=="],
+	["\074" => "PA=="],
+	["\075" => "PQ=="],
+	["\076" => "Pg=="],
+	["\077" => "Pw=="],
+	["\100" => "QA=="],
+	["\101" => "QQ=="],
+	["\102" => "Qg=="],
+	["\103" => "Qw=="],
+	["\104" => "RA=="],
+	["\105" => "RQ=="],
+	["\106" => "Rg=="],
+	["\107" => "Rw=="],
+	["\110" => "SA=="],
+	["\111" => "SQ=="],
+	["\112" => "Sg=="],
+	["\113" => "Sw=="],
+	["\114" => "TA=="],
+	["\115" => "TQ=="],
+	["\116" => "Tg=="],
+	["\117" => "Tw=="],
+	["\120" => "UA=="],
+	["\121" => "UQ=="],
+	["\122" => "Ug=="],
+	["\123" => "Uw=="],
+	["\124" => "VA=="],
+	["\125" => "VQ=="],
+	["\126" => "Vg=="],
+	["\127" => "Vw=="],
+	["\130" => "WA=="],
+	["\131" => "WQ=="],
+	["\132" => "Wg=="],
+	["\133" => "Ww=="],
+	["\134" => "XA=="],
+	["\135" => "XQ=="],
+	["\136" => "Xg=="],
+	["\137" => "Xw=="],
+	["\140" => "YA=="],
+	["\141" => "YQ=="],
+	["\142" => "Yg=="],
+	["\143" => "Yw=="],
+	["\144" => "ZA=="],
+	["\145" => "ZQ=="],
+	["\146" => "Zg=="],
+	["\147" => "Zw=="],
+	["\150" => "aA=="],
+	["\151" => "aQ=="],
+	["\152" => "ag=="],
+	["\153" => "aw=="],
+	["\154" => "bA=="],
+	["\155" => "bQ=="],
+	["\156" => "bg=="],
+	["\157" => "bw=="],
+	["\160" => "cA=="],
+	["\161" => "cQ=="],
+	["\162" => "cg=="],
+	["\163" => "cw=="],
+	["\164" => "dA=="],
+	["\165" => "dQ=="],
+	["\166" => "dg=="],
+	["\167" => "dw=="],
+	["\170" => "eA=="],
+	["\171" => "eQ=="],
+	["\172" => "eg=="],
+	["\173" => "ew=="],
+	["\174" => "fA=="],
+	["\175" => "fQ=="],
+	["\176" => "fg=="],
+	["\177" => "fw=="],
+	["\200" => "gA=="],
+	["\201" => "gQ=="],
+	["\202" => "gg=="],
+	["\203" => "gw=="],
+	["\204" => "hA=="],
+	["\205" => "hQ=="],
+	["\206" => "hg=="],
+	["\207" => "hw=="],
+	["\210" => "iA=="],
+	["\211" => "iQ=="],
+	["\212" => "ig=="],
+	["\213" => "iw=="],
+	["\214" => "jA=="],
+	["\215" => "jQ=="],
+	["\216" => "jg=="],
+	["\217" => "jw=="],
+	["\220" => "kA=="],
+	["\221" => "kQ=="],
+	["\222" => "kg=="],
+	["\223" => "kw=="],
+	["\224" => "lA=="],
+	["\225" => "lQ=="],
+	["\226" => "lg=="],
+	["\227" => "lw=="],
+	["\230" => "mA=="],
+	["\231" => "mQ=="],
+	["\232" => "mg=="],
+	["\233" => "mw=="],
+	["\234" => "nA=="],
+	["\235" => "nQ=="],
+	["\236" => "ng=="],
+	["\237" => "nw=="],
+	["\240" => "oA=="],
+	["\241" => "oQ=="],
+	["\242" => "og=="],
+	["\243" => "ow=="],
+	["\244" => "pA=="],
+	["\245" => "pQ=="],
+	["\246" => "pg=="],
+	["\247" => "pw=="],
+	["\250" => "qA=="],
+	["\251" => "qQ=="],
+	["\252" => "qg=="],
+	["\253" => "qw=="],
+	["\254" => "rA=="],
+	["\255" => "rQ=="],
+	["\256" => "rg=="],
+	["\257" => "rw=="],
+	["\260" => "sA=="],
+	["\261" => "sQ=="],
+	["\262" => "sg=="],
+	["\263" => "sw=="],
+	["\264" => "tA=="],
+	["\265" => "tQ=="],
+	["\266" => "tg=="],
+	["\267" => "tw=="],
+	["\270" => "uA=="],
+	["\271" => "uQ=="],
+	["\272" => "ug=="],
+	["\273" => "uw=="],
+	["\274" => "vA=="],
+	["\275" => "vQ=="],
+	["\276" => "vg=="],
+	["\277" => "vw=="],
+	["\300" => "wA=="],
+	["\301" => "wQ=="],
+	["\302" => "wg=="],
+	["\303" => "ww=="],
+	["\304" => "xA=="],
+	["\305" => "xQ=="],
+	["\306" => "xg=="],
+	["\307" => "xw=="],
+	["\310" => "yA=="],
+	["\311" => "yQ=="],
+	["\312" => "yg=="],
+	["\313" => "yw=="],
+	["\314" => "zA=="],
+	["\315" => "zQ=="],
+	["\316" => "zg=="],
+	["\317" => "zw=="],
+	["\320" => "0A=="],
+	["\321" => "0Q=="],
+	["\322" => "0g=="],
+	["\323" => "0w=="],
+	["\324" => "1A=="],
+	["\325" => "1Q=="],
+	["\326" => "1g=="],
+	["\327" => "1w=="],
+	["\330" => "2A=="],
+	["\331" => "2Q=="],
+	["\332" => "2g=="],
+	["\333" => "2w=="],
+	["\334" => "3A=="],
+	["\335" => "3Q=="],
+	["\336" => "3g=="],
+	["\337" => "3w=="],
+	["\340" => "4A=="],
+	["\341" => "4Q=="],
+	["\342" => "4g=="],
+	["\343" => "4w=="],
+	["\344" => "5A=="],
+	["\345" => "5Q=="],
+	["\346" => "5g=="],
+	["\347" => "5w=="],
+	["\350" => "6A=="],
+	["\351" => "6Q=="],
+	["\352" => "6g=="],
+	["\353" => "6w=="],
+	["\354" => "7A=="],
+	["\355" => "7Q=="],
+	["\356" => "7g=="],
+	["\357" => "7w=="],
+	["\360" => "8A=="],
+	["\361" => "8Q=="],
+	["\362" => "8g=="],
+	["\363" => "8w=="],
+	["\364" => "9A=="],
+	["\365" => "9Q=="],
+	["\366" => "9g=="],
+	["\367" => "9w=="],
+	["\370" => "+A=="],
+	["\371" => "+Q=="],
+	["\372" => "+g=="],
+	["\373" => "+w=="],
+	["\374" => "/A=="],
+	["\375" => "/Q=="],
+	["\376" => "/g=="],
+	["\377" => "/w=="],
+    );
+
+    for $test (@encode_tests) {
+	my($plain, $expected) = ($$test[0], $$test[1]);
+
+	my $encoded = encode_base64($plain, '');
+	if ($encoded ne $expected) {
+	    print "test $testno ($plain): expected $expected, got $encoded\n";
+            print "not ";
+	}
+	my $decoded = decode_base64($encoded);
+	if ($decoded ne $plain) {
+	    print "test $testno ($plain): expected $expected, got $encoded\n";
+            print "not ";
+	}
+
+	# Try the old C versions too
+	if ($encoded ne MIME::Base64::old_encode_base64($plain, '')) {
+	    print "old_encode_base64 give different result.\n";
+	    print "not ";
+        }
+	if ($plain ne MIME::Base64::old_decode_base64($encoded)) {
+	    print "old_decode_base64 give different result.\n";
+	    print "not ";
+        }
+		
+	print "ok $testno\n";
+	$testno++;
+    }
+}
+
+sub decodeTest
+{
+    print "decode test:\n";
+    local $SIG{__WARN__} = sub { print $_[0] };  # avoid warnings on stderr
+
+    my @decode_tests = (
+	['YWE='   => 'aa'],
+	[' YWE='  => 'aa'],
+	['Y WE='  => 'aa'],
+	['YWE= '  => 'aa'],
+	["Y\nW\r\nE=" => 'aa'],
+
+	# These will generate some warnings
+        ['YWE=====' => 'aa'],    # extra padding
+	['YWE'      => 'aa'],    # missing padding
+        ['YWFh====' => 'aaa'],
+        ['YQ'       => 'a'],
+        ['Y'        => ''],
+        [''         => ''],
+        [undef()    => ''],
+    );
+
+    for $test (@decode_tests) {
+	my($encoded, $expected) = ($$test[0], $$test[1]);
+
+	my $decoded = decode_base64($encoded);
+	if ($decoded ne $expected) {
+	    die "test $testno ($encoded): expected $expected, got $decoded\n";
+	}
+	print "ok $testno\n";
+	$testno++;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/t/quoted-print.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/t/quoted-print.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/MIME-Base64-2.11/t/quoted-print.t	(revision 10506)
@@ -0,0 +1,106 @@
+#!/local/bin/perl -w
+
+use MIME::QuotedPrint;
+
+$x70 = "x" x 70;
+
+@tests =
+  (
+   # plain ascii should not be encoded
+   ["quoted printable"  =>
+    "quoted printable"],
+
+   # 8-bit chars should be encoded
+   ["våre kjære norske tegn bør æres" =>
+    "v=E5re kj=E6re norske tegn b=F8r =E6res"],
+
+   # trailing space should be encoded
+   ["  " => "=20=20"],
+   ["\tt\t" => "\tt=09"],
+   ["test  \ntest\n\t \t \n" => "test=20=20\ntest\n=09=20=09=20\n"],
+
+   # "=" is special an should be decoded
+   ["=\n" => "=3D\n"],
+   ["\0\xff" => "=00=FF"],
+
+   # Very long lines should be broken (not more than 76 chars
+   ["The Quoted-Printable encoding is intended to represent data that largly consists of octets that correspond to printable characters in the ASCII character set." =>
+    "The Quoted-Printable encoding is intended to represent data that largly con=
+sists of octets that correspond to printable characters in the ASCII charac=
+ter set."
+    ],
+
+   # Long lines after short lines were broken through 2.01.
+   ["short line
+In America, any boy may become president and I suppose that's just one of the risks he takes. -- Adlai Stevenson" =>
+    "short line
+In America, any boy may become president and I suppose that's just one of t=
+he risks he takes. -- Adlai Stevenson"],
+
+   # My (roderick@argon.org) first crack at fixing that bug failed for
+   # multiple long lines.
+   ["College football is a game which would be much more interesting if the faculty played instead of the students, and even more interesting if the
+trustees played.  There would be a great increase in broken arms, legs, and necks, and simultaneously an appreciable diminution in the loss to humanity. -- H. L. Mencken" =>
+    "College football is a game which would be much more interesting if the facu=
+lty played instead of the students, and even more interesting if the
+trustees played.  There would be a great increase in broken arms, legs, and=
+ necks, and simultaneously an appreciable diminution in the loss to humanit=
+y. -- H. L. Mencken"],
+
+   # Don't break a line that's near but not over 76 chars.
+   ["$x70!23"		=> "$x70!23"],
+   ["$x70!234"		=> "$x70!234"],
+   ["$x70!2345"		=> "$x70!2345"],
+   ["$x70!23456"	=> "$x70!23456"],
+   ["$x70!23\n"		=> "$x70!23\n"],
+   ["$x70!234\n"	=> "$x70!234\n"],
+   ["$x70!2345\n"	=> "$x70!2345\n"],
+   ["$x70!23456\n"	=> "$x70!23456\n"],
+
+   # Not allowed to break =XX escapes using soft line break
+   ["$x70===xxxx" => "$x70=3D=\n=3D=3Dxxxx"],
+   ["$x70!===xxx" => "$x70!=3D=\n=3D=3Dxxx"],
+   ["$x70!!===xx" => "$x70!!=3D=\n=3D=3Dxx"],
+   ["$x70!!!===x" => "$x70!!!=\n=3D=3D=3Dx"],
+   #                            ^
+   #                    70123456|
+   #                           max
+   #                        line width
+);
+
+$notests = @tests + 2;
+print "1..$notests\n";
+
+$testno = 0;
+for (@tests) {
+    $testno++;
+    ($plain, $encoded) = @$_;
+    $x = encode_qp($plain);
+    if ($x ne $encoded) {
+	print "Encode test failed\n";
+	print "Got:      '$x'\n";
+	print "Expected: '$encoded'\n";
+	print "not ok $testno\n";
+	next;
+    }
+    $x = decode_qp($encoded);
+    if ($x ne $plain) {
+	print "Decode test failed\n";
+	print "Got:      '$x'\n";
+	print "Expected: '$plain'\n";
+	print "not ok $testno\n";
+	next;
+    }
+    print "ok $testno\n";
+}
+
+# Some extra testing for a case that was wrong until libwww-perl-5.09
+print "not " unless decode_qp("foo  \n\nfoo =\n\nfoo=20\n\n") eq
+                                "foo\n\nfoo \nfoo \n\n";
+$testno++; print "ok $testno\n";
+
+# Same test but with "\r\n" terminated lines
+print "not " unless decode_qp("foo  \r\n\r\nfoo =\r\n\r\nfoo=20\r\n\r\n") eq
+                                "foo\r\n\r\nfoo \r\nfoo \r\n\r\n";
+$testno++; print "ok $testno\n";
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/ChangeLog
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/ChangeLog	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/ChangeLog	(revision 10506)
@@ -0,0 +1,1535 @@
+Tue Aug  4 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.36
+
+ o  The lwp-download script will call $ua->env_proxy now.
+
+ o  The lwp-request script allows content types (specified with the -c
+    option) with optional parameters like: multipart/mixed; boundary="--".
+
+ o  LWP::UserAgent will lowercase all authentication parameter names
+    before passing it to the authentication module.  Previous releases
+    ignored parameters like; Realm="Foo" (bacause Realm contained
+    upper case letters).
+
+ o  LWP::Protocol::ftp test for If-Modified-Since was wrong.
+
+ o  How the $url->abs method works can now be configured with the global
+    variables $URI::URL::ABS_ALLOW_RELATIVE_SCHEME and
+    $URI::URL::ABS_REMOTE_LEADING_DOTS.
+
+ o  The anonymous password guesser for ftp URLs will now call the external
+    `whoami` program any more.  Patch by Charles C. Fu <ccwf@bacchus.com>.
+
+ o  LWP::Protocol::http now allow dynamic requests without any
+    Content-Length specified when Content-Type is multipart/*
+
+ o  HTTP::Request::Common can now upload infinite files.
+    (Controlled by the $DYNAMIC_FILE_UPLOAD configuration variable.)
+
+
+
+Fri Jul 10 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.35
+
+ o  More lwp-rget patches from David D. Kilzer <ddkilzer@madison.dseg.ti.com>.
+    Adds the following new options: --iis, --keepext, --tolower
+
+ o  LWP::MediaTypes patches from MacEachern <dougm@pobox.com>.  Adds new
+    functions: add_type(), add_encoding(), read_media_types()
+
+
+
+Tue Jul  7 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.34
+
+ o  LWP::Protocol::ftp now try to use the MDTM command to support
+    the Last-Modified response header as well as
+    If-Modified-Since in requests.  Original and final patch by
+    Charles C. Fu <ccwf@bacchus.com>
+
+ o  $url->path_components will not escape "." any more.
+
+ o  WWW::RobotRules will now work for Mac text files too (lines delimited
+    by CR only).  Patch by Olly Betts <olly@muscat.co.uk>
+
+ o  lwp-rget support <area ..> links too.
+
+
+
+Thu May  7 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.33
+
+ o  LWP::Simple::get() did try to handle too many of the 3xx
+    codes as redirect when it bypasses full LWP.
+
+ o  LWP::UserAgent->mirror will now use utime(2) to set the
+    file modification time corresponding to the Last-Modified
+    header.
+
+ o  LWP::Protocol::http will not modify the HTTP::Request that
+    it is processing.  This avoids sticky Host header for
+    redirects.
+
+ o  URI::Heuristic and lwp-download documentation update.
+
+
+
+Wed Apr 15 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.32
+
+ o  Much improved HTTP::Daemon class. We now support persistent
+    connections.  Changes include:
+       - $c->get_request can be told to return after reading and
+         parsing headers only.
+       - $c->reason (new method)
+       - $c->read_buffer (new method)
+       - $c->proto_ge (new method)
+       - $c->force_last_request (new method)
+       - $c->send_response now support CODE reference content
+         and will use chunked transfer encoding for HTTP/1.1 clients.
+       - expanded the documentation.
+
+
+
+Fri Apr 10 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.31
+
+ o  Makefile.PL now checks that HTML::HeadParser is present.
+
+ o  Updated HTTP::Cookies according to draft-ietf-http-state-man-mec-08.txt
+    It now supports the .local domain and value less 'port' attribute in
+    the Set-Cookie2 header.
+
+ o  HTTP::Headers update:
+       - $h->content_type now always return a defined value
+       - $h->header($field) will now concatenate multi-valued header
+         fields with "," as separator in scalar context.
+
+ o  HTTP::Request::Common update:
+       - used to destroy the content of the  hash/array arguments
+         passed to its constructor functions.
+       - allow a hash reference to specify form-data content.
+       - you can override Content-Disposition for form-data now.
+       - set content-encoding for files if applicable
+       - default boundary string is now always "--000"
+
+ o  LWP::UserAgent will not follow more than 13 redirects
+    automatically.
+
+
+
+Wed Apr  1 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.30
+
+ o  Unbundled the following modules:
+
+       * HTML-Parser  (HTML::Parser, HTML::Entites, HTML::LinkExtor,...)
+       * HTML-Tree    (HTML::Element, HTML::TreeBuilder,...)
+       * Font-AFM     (Font::AFM, Font::Metrics::*)
+       * File-CounterFile
+
+ o  Simplified internal structure of HTML::Headers.  Hopefully,
+    nobody will notice.
+
+ o  New modules HTTP::Headers::Auth,  HTTP::Headers::ETag that adds
+    additional convenience methods to the HTTP::Headers class.
+
+ o  Removed split_etag_list() from HTTP::Headers::Util, in the hope
+    that nobody had starting using it.
+
+
+
+Tue Mar 24 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.22
+
+ o  HTTP::Cookies made more compatible with Netscape cookies.  Allow
+    the domain to match host, allow dots in the part of the hostname
+    not covered by domain.  Don't quote the cookie value even when it
+    contains non-token chars.  Based on patch from Kartik Subbarao
+    <subbarao@computer.org>.
+
+ o  Updated HTTP::Status to reflect <draft-ietf-http-v11-spec-rev-03>.
+    RC_MOVED_TEMPORARILY renamed to RC_FOUND.  Added codes
+    RC_TEMPORARY_REDIRECT (307) and RC_EXPECTATION_FAILED (417).
+    Slightly more documentation too.
+
+ o  The split_header_words() function HTTP::Headers::Util could go
+    into infinite loop on some header values.  Implemented split_etag_list()
+    too.  Added more documentation and test script for this module.
+
+ o  LWP::Simple now switch to full LWP implementation even for systems
+    that force all environment keys to be upper case.  Modification
+    suggested by Dale Couch <dcouch@training.orl.lmco.com>.
+
+ o  LWP::UserAgent allows redirects to a relative URL with scheme to be
+    made.  Suggested by Chris W. Unger <cunger@cas.org>.
+
+ o  Applied dtd2pm.pl patches from <peterm@zeta.org.au>.  It can now
+    extract information from the HTML40.dtd
+
+
+
+Thu Mar 12 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.21
+
+ o  lwp-rget patches from David D. Kilzer <ddkilzer@madison.dseg.ti.com>
+    (modified by Gisle).  Support the --hier  and the --auth options
+    and <frame>s.
+
+ o  File::CounterFile protect against bad $/ and $\ as suggested
+    by Frank Hoehne.
+ 
+ o  File::Listing used "next" when return was more appropriate.
+    Patch by erik@mediator.uni-c.dk.
+
+ o  HTML::Element support for multiple boolean attributes for a single
+    element.  Patch by Philip Guenther.
+
+ o  Can set $HTTP::Headers::TRANSLATE_UNDERSCORE to FALSE value to
+    suppress tr/_/-/ of header keys.
+
+ o  LWP::Protocol::http will not initialize the Host header if it is
+    already set. Patch by Ed Jordan.
+
+ o  LWP::Protocol::http did not handle responses with no header lines
+    correctly.  Patch by Daniel Buenzli <buenzli@rzu.unizh.ch>
+
+ o  $url->rel() handles path segments without leading "/" better.
+
+
+
+Fri Feb 13 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.20
+
+ o  Fixed the "500 Offset outside string" bug that affected perl
+    5.004_03 and older version of Perl.
+
+ o  Fixed a documentation typo spotted by Michael Quaranta
+    <quaranta@vnet.IBM.COM>
+
+ o  HTTP::Date: Protect against croaking from timegm/timelocal.
+
+
+
+Mon Jan 26 1998   Gisle Aas <aas@sn.no>
+
+ o  Release 5.19
+
+ o  HTML::Parser does not call $self->text() callback for empty text
+    any more.
+
+ o  LWP::Protocol::https was noisy when connections failed and the
+    script was running with '-w' (noise inherited from IO::Socket::INET)
+
+ o  $ua->use_alarm(BOOL) now gives a warning if running with -w
+
+
+
+Tue Jan 20 1998   Gisle Aas <aas@sn.no>
+
+ o  Developer release 5.18_05
+
+ o  HTTPS support based on my Crypt-SSLeay module.  The Net-SSLeay module
+    is not supported any more.
+
+ o  lwp-request documentation typo spotted Martijn Koster.
+
+ o  Removed superfluous \\ in the URI::Escape regex. This was also
+    spotted by Martijn.
+
+ o  File::Listing now handles timezones correctly.
+
+ o  Added $VERSION to modules that was missing it.
+
+ o  Added 'use strict' to several modules that was missing it.
+
+ o  LWP::Protocol::http now adds the Client-Peer header to responses and
+    has hooks for more callbacks.
+
+ o  LWP::Protocol::https adds Client-SSL-Cipher, Client-SSL-Cert-Subject
+    and Client-SSL-Cert-Issuer headers to the response.  The requests can
+    also be made conditional based on the peer certificate using the
+    If-SSL-Cert-Subject header in requests.
+
+ o  HTML::Parse is back.  (It was even used in lwpcook.pod)
+
+
+
+Wed Dec 17 1997   Gisle Aas <aas@sn.no>
+
+ o  Developer release 5.18_04
+
+ o  Makefile.PL fix based on report from Pon Hwa Lin <koala@fragment.com>
+
+ o  lwp-request will now print the response code message with -s and -S
+    options.
+
+ o  Hide IO::Socket::INET noise when running under -w
+
+ o  Don't set 'Content-Length: 0' in HTTP requests.
+
+ o  LWP::Protocol::http now calls LWP::Debug::conns again
+
+
+
+Tue Dec 16 1997   Gisle Aas <aas@sn.no>
+
+ o  Developer release 5.18_03
+
+ o  Got rid of alarms() and replaced LWP::Socket with IO::Socket::INET.
+    New protocol implementations for http, https, gopher, nntp.
+    $ua->use_alarm() is now a noop.
+
+ o  LWP::Protocol::ftp patch from  Tony Finch <fanf@demon.net>.
+
+ o  Removed depreciated modules from the distibution; HTML::Parse,
+    LWP::Socket, LWP::SecureSocket, LWP::IO, LWP::TkIO.
+
+
+
+Fri Dec 12 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.18
+
+ o  HTTP authorization patches from Tony Finch <fanf@demon.net>.
+    Allows "user:pass@" in HTTP URLs.
+
+ o  HTML::Parser patch by Brian McCauley <B.A.McCauley@bham.ac.uk>.
+    Pass original text to end() method.
+
+ o  The HTML::Parser->netscape_buggy_comment method is depreciated.
+    Use HTML::Parser->strict_comment instead.  The default value
+    has changed with the name.
+
+ o  Some HTML::Parser optimization tweaks.
+
+ o  New module named HTML::Filter
+
+ o  Updated HTTP::Headers to the latest HTTP spec.  Added knowledge
+    about the "Trailer", "Expect", "TE", "Accept-Range" headers.
+    "Public" header is gone.
+
+ o  Added some more header convenience methods: if_unmodified_since,
+    content_language, and proxy_authorization methods.
+
+ o  HTTP::{Request,Response}->clone can handle subclasses now.
+
+ o  HTTP::Request->url() can now undefine the URL.
+
+ o  HTTP::{Request,Response}->as_string format looks more like
+    the HTTP protocol formatting now.  Dashed lines above and
+    below is gone.
+
+ o  Documented HTTP::Response->status_line method
+
+ o  Compressed HTML::Response->error_as_HTML output
+
+ o  HTTP::Status updated to latest HTTP spec.  Added 
+    RC_REQUEST_RANGE_NOT_SATISFIABLE (416)
+
+
+
+Tue Dec  2 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.17
+
+ o  All authentication handling moved out of LWP::UserAgent and into
+    LWP::Authen::Basic and LWP::Authen::Digest.  We now also support
+    PROXY_AUTHENTICATION_REQUIRED responses.
+
+ o  HTML::Formatter will always add a blank line for <br>.
+
+ o  Avoid use of uninitialized value in HTTP::Daemon.
+
+ o  HTTP::Date allows seconds when recognizing 'ls -l' dates.  This
+    allows us to parse syslog time stamps.
+
+ o  HTTP::Request::Common::POST allows a hash reference as second
+    argument (in addition to an array reference).
+
+ o  LWP::Simple will initialize the $ua if it is exported.
+
+ o  Various documentation updates.
+
+
+
+Fri Nov 21 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.16
+
+ o  LWP::Simple::head() would die in array context because str2time
+    was not imported any more.
+
+ o  HTTP::Daemon->accept now takes an optional package argument like
+    IO::Socket->accept does.
+
+ o  Made HTTP::Request and HTTP::Response subclassable.
+
+ o  Added Proxy-Authorization example to lwpcook.
+
+
+
+Thu Nov  6 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.15
+
+ o  New module URI::Heuristic
+
+ o  The lwp-request script now use URI::Heuristic for it's URL arguments.
+    It means that 'lwp-request perl' will not get a file called "./perl"
+    but will fetch the page "http://www.perl.com" or something similar.
+    If you want to get the file you have to prefix it with "./".  Full
+    URLs are never affected by this.
+
+ o  LWP::Simple::get() will bypass LWP for simple HTTP requests.  This
+    should make it somewhat faster.
+
+ o  LWP::RobotUA has a new method called $ua->use_sleep() that
+    controls how niceness towards the servers are enforced.
+    Previously $ua->use_alarm() used to control this, but this did
+    not work well on Win32 systems.
+
+ o  URI::URL::rel() will handle URLs to a fragment within the same
+    document better. Initial patch from Nicolai Langfeldt
+    <janl@math.uio.no>.
+
+ o  HTML::Element don't consider </th>, </tr> and </td> optional any
+    more.  I wonder how Netscape managed to not implement this
+    correctly all this time.
+
+ o  Added lots of modern tags to HTML::AsSubs.
+
+ o  HTTP::Request::Common will read uploaded files in binmode().
+    This should be better for Win32 systems.  Contributed by
+    <Steve_Kilbane@cegelecproj.co.uk>.
+
+
+
+Sun Oct 12 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.14
+
+ o  HTML::Formatter patches from Andreas Gustafsson <gson@araneus.fi>.
+    The formatters handling of whitespace is much better now.  Thanks!
+
+ o  HTML::FormatText: can specify margins in the constructor.
+
+ o  URI::URL: the base will be absolutized internally now.
+
+ o  URI::URL will take advantage of void context provided by perl5.004.
+    This means that using $u->path and $u->query should be safer now.
+
+ o  URI::URL->print_on defaults to STDERR now (used to be STDOUT).
+
+ o  URI::URL: removed version 3 compatibility stuff ($COMPAT_VER_3).
+
+ o  $ua->mirror should work better on dosish systems (can not
+    rename when target file exists).
+
+ o  Typo in lwp-download prevented it from compiling.
+
+ o  Some minor documentations typos corrected.
+
+
+
+Sat Sep 20 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.13
+
+ o  Brand new module called HTTP::Cookies.  It stores cookies
+    (Set-Cookie and Set-Cookie2 headers) from responses and can
+    create appropriate Cookie headers for requests.  It can also
+    share cookie files with Netscape.
+
+ o  LWP::UserAgent now support the cookie_jar() attribute.  When
+    set to an HTTP::Cookies object, it will automatically manage
+    the cookies sent to the servers.  Off by default.
+
+ o  New header utility functions in HTTP::Headers::Util.
+
+ o  Win32 and OS/2 patches for the lwp-xxx utilities.  Turn on
+    binary mode by default (option to turn it off), avoid modifying $0,
+    and don't be confused about suffixes in the script names.
+    Contributed by Ben Coleman <bcoleman@mindspring.com>
+
+ o  OpenVMS patch for Font:AFM by Brad Hughes <brad@tmc.naecker.com>
+
+
+
+Fri Sep  5 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.12
+
+ o  decode_entities() would sometimes introduce ";" after
+    things that looked like they were entities.
+
+ o  HTML::LinkExtor knows about <applet code="...">
+
+ o  Patch from Gary Shea <shea@gtsdesign.com> that makes the
+    tests work even if perl is not called "perl"
+
+ o  HTTP::Date handles 12:00PM correctly now. Patch from
+    William York <william@mathworks.com>
+
+ o  HTTP::Request::Common don't quote the boundary string for
+    multipart/form-data messages any more.
+
+ o  Font::AFM works for encodings where .notdef is defined to
+    have some size.  Documentation and efficiency update.
+
+
+
+Wed Aug  6 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.11
+
+ o  Perl version 5.004 is now required for libwww-perl.
+
+ o  Win32 patches from Gurusamy Sarathy <gsar@engin.umich.edu>.
+    Now passes all tests on that platform.
+
+ o  HTTPS support contributed by Josh Kronengold <mneme@mcny.com>
+
+ o  Support hex entities &#xFF;  HTML::Entities::(en|de)code only
+    modify their argument in void context.
+
+ o  Fixed formatter bug with <font> tags which did not specify size.
+
+ o  Better HTML::HeadParser documentation
+
+ o  Fixed HTML::LinkExtor documentation typo spotted by Martijn.
+
+ o  HTTP::Request::Common now use CRLF for multipart/form-data
+
+
+
+Fri Jun 20 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.10
+
+ o  Make '+' a reserved URL character.  Decode unescaped '+' as
+    space in $url->query_form().
+
+ o  Use $Config{d_alarm} to determine default for $ua->use_alarm()
+
+
+
+Tue Jun 10 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.09
+
+ o  Removed the MIME modules from the distribution.  They are distributed
+    separately now.
+
+ o  Added a new module called HTTP::Request::Common
+
+ o  Improved HTTP::Status documentation.  It is now also possible
+    to import the is_client_error/is_server_error functions.
+
+ o  LWP::MediaTypes::guess_media_type() can now take an optional
+    HTTP::Header parameter.
+
+ o  LWP::Protocol ensures that scheme is legal as module name.
+
+ o  LWP::Protocol::http is not as strict when trying to verify the
+    method name.  It now also accepts responses without a message
+    on the status line.
+
+ o  WWW::RobotRules::AnyDBM_File: Some DBMs fail to allow multiple
+    opens of the same file.  Patch from Mark James <jamesm@skate.org>
+
+ o  Created Bundle::LWP
+
+
+
+Sat Apr  5 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.08
+
+ o  Made libwww-perl warning compatible with upcoming perl5.004beta2
+    (aka 5.003_98)
+
+ o  encode_base64() did not work properly if pos() of the string to
+    encode was different from 0.
+
+ o  HTML::Parser was confused about "</" when it did not start an end tag.
+
+ o  HTML::FormatPS will provide ISOLatin1Encoding in its output.
+
+ o  Calling HTML::LinkExtor->links will clear out old links.
+
+ o  url()->rel($base) would ignore the $base argument.
+
+ o  Don't croak() when setting url()->path().
+
+
+
+Tue Feb 11 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.07
+
+ o  Can limit the size of the response content with $ua->max_size()
+
+ o  Added time2iso() functions to HTTP::Date.
+
+ o  Made LWP::Protocol::http more portable to the MacPerl. /./ match
+    different things on MacPerl.
+
+
+
+Mon Jan 27 1997   Gisle Aas <aas@sn.no>
+
+ o  Release 5.06
+
+ o  URI::URL is now compatible with perl5.004 overloading.
+
+ o  HTML::HeadParser makes X-Meta-Name headers for <meta> elements
+    that does not specify an 'http-equiv' attribute.
+
+ o  URI::URL::ftp does not die if Net::Domain is not installed and
+    you ask for an anonymous username or password.
+
+ o  WWW::RobotRules:  The robots.txt parser did not ignore comment lines
+    as it should.
+
+ o  LWP::Protocol::http is more forgiving towards servers that return
+    bad responses.
+
+ o  Allow "?" before search string in gopher URLs.
+
+ o  LWP::Protocol::file did not escape funny filenames when generating
+    HTML directory listings.
+
+ o  LWP::Protocol::ftp now gets the Content-Encoding correct. 'CODE'
+    content in PUT requests also work now.
+
+ o  Relative locations in redirects did not work with URI::URL::strict.
+
+ o  OS/2 portability patches from Ilya Zakharevich
+
+ o  LWP::Authen::* patch from Doug MacEachern
+
+ o  Support experimental data:- URLs
+
+ o  Some tests (those using HTTP::Daemon) now die more gracefully if
+    IO::* modules is not installed.
+
+
+
+Wed Dec  4 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.05
+
+ o  LWP::UserAgent::simple_request: local($SIG{__DIE__}) protects us
+    against user defined die handlers.
+ 	
+ o  Use Net::Domain (instead of Sys::Hostname) to determine FQDN.  It
+    is used by URI::URL when it determines anonymous ftp login address.
+	
+ o  lwp-download: New program in the bin directory
+
+ o  HTML::Parser: Allow '_' in attribute names.  This makes it possible
+    to parse Netscape's bookmarks.html file.
+
+ o  HTTP::Daemon: Fixed chunked transfer encoding and multipart content
+    in get_request().  Support HTTP/0.9 clients.
+
+ o  Don't clobber regex variables when HTTP::Message delegates methods
+    to the header.
+
+ o  Base64::decode_base64 now checks that the length input string to
+    decode is a multiple of 4.
+
+ o  t/robot/rules-dbm.t clean up better and will use AnyDBM for dumping
+
+ o  File::CounterFile: $/ strikes again by Andreas König
+
+ o  File::Listing updates from William York <william@mathworks.com>. We
+    can now parse the MS-Windows ftp server listings.
+
+ o  HTTP::Date now supports the MS-Windows 'dir' date format.  Patch by
+    William York.
+
+ o  LWP::MediaTypes::media_suffix will return first type in scalar context.
+
+
+
+Tue Oct 22 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.04
+
+ o  Added HTTP::Daemon.  This is a HTTP/1.1 server class.  This means
+    that libwww-perl no longer is a client library only.  The HTTP::Daemon
+    is also used in the new test suite.
+
+ o  HTTP::Message support the protocol() method.  Used by HTTP::Daemon.
+
+ o  HTTP::Response can be constructed with a header and content as
+    argument.
+
+ o  Typo corrections in the documentation.
+
+ o  File::Listing::parse_dir accepts "GMT" as timezone now.
+
+ o  HTML::Parser will call the start() method with two new parameters;
+    $attrseq, $origtext.
+
+ o  Integrated HTML::FormatPS patches from
+    Jim Stern <jstern@world.northgrum.com>
+
+ o  Class modules don't inherit from AutoLoader any more.  They just
+    import the AUTOLOAD method.
+
+ o  LWP::Protocol will untaints scheme before loading protocol module.
+
+ o  Digest does not send "opaque" if it was not present in the request.
+    The "Extension" header is not returned any more.
+
+ o  New method: $url->crack that will return a list of the various
+    elements in a URI::URL.
+
+ o  WWW::RobotRules did not use the agent() method when determining
+    who we are.  This affected WWW::RobotRules::AnyDBM_File parsing
+    for robots.txt.  Visit count did not increment for
+    WWW::RobotRules::InCore.
+
+
+
+Tue Oct  1 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.03
+
+ o  Hakan Ardo's persistent robot rules is now part of the standard
+    distribution.  This is still experimental and might change in the
+    future.  It includes the new WWW::RobotRules::AnyDBM_File class
+    and updates to LWP::RobotUA.
+
+ o  HTML::Parser now supports buggy Netscape comment parsing.  Enable
+    it by calling $p->netscape_buggy_comment(1).  The previous version
+    of the parser could also (under very unlucky and unlikely
+    circumstances) call the $self->comment() method several times for
+    the same comment text.
+
+ o  HTML::Parser: Use new $p->eof to signal end of document instead of
+    $p->parse(undef).
+
+ o  HTML::Element::starttag() is now smarter about which quotes it
+    use around attribute values.
+
+ o  New HTTP::Response methods: current_age(), freshness_lifetime(),
+    is_fresh(), fresh_until().
+
+ o  HTTP::Message:  New method ($mess->content_ref) which will return
+    a reference to the current content.
+
+ o  URI::URL:  New method ($url->rel) which does the opposite of abs().
+    Example: url("http://host/a/b/c", "http://host/c/d/e")->rel would
+    return url("../../a/b/c", "http://host/c/d/e").  This was
+    suggested by Nicolai Langfeldt <janl@ifi.uio.no>
+
+ o  URI::URL:  $url->query_form can now take array references as value
+    specification.  For instance: $url->query_form(foo => ['bar', 'baz']
+
+ o  Avoid '"my" variable $var masks earlier declaration in same scope'
+    warnings in perl5.003_05.
+
+
+
+Wed Sep 11 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.02
+
+ o  lwp-rget:  Initialize proxy settings from envirionment
+
+ o  HTML::Entities::encode_entities: Don't encode $ and %
+
+ o  HTML::LinkExtor::links: Now works when no links were found.
+
+ o  HTTP::Headers::as_string: Allow \n in header value
+
+
+
+Tue Aug  1 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.01.
+
+ o  Updated ftp protocol module to be compatible with Net::FTP 
+    version 2.00 (the version found in libnet-1.00)
+
+ o  New HTML parser module called HTML::LinkExtor
+
+ o  Various documentation typo corrections.  Most of these contributed
+    by Bob Dalgleish.
+
+ o  HTML::HeadParser updates 'Content-Base' instead of 'Base'.  It also
+    updates the 'Link' header based on <link ...>
+
+ o  HTTP::Headers and HTTP::Status updated according to
+    draft-ietf-http-v11-spec-06
+
+ o  HTTP::Headers can now use "_" as alternative to "-" in field names.
+
+ o  HTTP::Response::base now looks for 'Content-Base',
+    'Content-Location' and 'Base' headers.
+
+ o  Avoid warning in LWP::MediaTypes if $ENV{HOME} is not defined.
+
+ o  The new $ua->parse_head() method can be used to turn off
+    automatic initialization of response headers from the <HEAD>
+    section of HTML documents.
+
+ o  Added eq() method for URI::URL objects
+
+ o  The HTML::Formatter recovers even if a handle method is not defined
+    for all tags found during traversal
+
+
+
+Sun May 26 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5.00.
+
+ o  LWP::Simple::head() now return something useful in scalar context.
+
+ o  Rewritten the HTML::Parse stuff.  Introduced the HTML::Parser class
+    that will tokenize a HTML document.  The rest of the old
+    HTML::Parse functionality has moved to HTML::TreeBuilder class.
+    Note, that the HTML stuff is still alpha.
+
+ o  Implemented HTML::HeadParser.  This is a lightweight parser for
+    the <HEAD> section of a HTML document.
+
+ o  HTML::Element had problem with presenting things like <foo
+    bar="bar">.
+
+ o  HTML::Entities: Included additional ISO-8859/1 entities listed in
+    RFC1866.
+
+ o  HTML::AsSubs exported 'header' instead of 'head'
+
+ o  We know about a few more of the HTML 3.2 element.
+
+ o  HTTP::Date had problems with years before 1970, because Time::Local
+    went into an infinite loop.  Check for this.
+
+ o  Added $header->title method.
+
+ o  Made $header->authorization_basic return "uname:passwd" in scalar
+    context
+
+ o  LWP::Protocol::collect() will let the HTML::HeadParser look at the
+    document content as it arrives.  This will initialize headers from
+    elements like <base href="...">, <title>...</title> and <meta
+    http-equiv="..." ...>.
+
+ o  Simplified $response->base implementation, because we don't have
+    to look into the content any more.
+
+ o  Added -quiet option to lwp-rget
+
+ o  Typo fixes and some documentation additions.
+
+
+
+Thu May  9 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b13
+
+ o  Made URI::URL::strict(0) the default.  I got tired of all this
+    eval { } stuff just to recover.  The URI::URL::strict'ness also
+    determine if calling some standard method that happens to be
+    illegal for some protocol scheme will croak or just be ignored.
+
+ o  Ensure correct $INPUT_RECORD_SEPARATOR and $OUTPUT_RECORD_SEPARATOR
+    at places where we <> or print.
+
+ o  Always localize $_ before any 'while(<FILE>) {}'-loops
+
+ o  Implemented $protocol->collect_once() and simplified several
+    of the protocol implementations by using it.
+
+ o  The HTML parser used to get it wrong if you were unlucky about the
+    breakup of the text. An example of broken behaviour was this:
+
+        $html = parse_html "<!-- A comment -";
+        $html = parse_html "-> and some text.";
+
+ o  The HTML parser does not ignore whitespace-only text any more.
+
+ o  HTML::Parse warnings are now optional and turned off by default.
+
+ o  New start for $html->as_HTML().
+
+ o  Fixed some typos
+
+
+
+Wed Apr 24 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b12
+
+ o  New utility program called 'lwp-rget'.
+
+ o  $response->base was broken for HTML documents
+
+ o  New fancy LWP::Debug import() method.  Can now turn on debugging with
+    "use LWP::Debug '+';"
+
+ o  Trap exceptions (die) from the response callback routine
+
+ o  The RobotUA now requires an e-mail address of the person reponsible
+    for the robot.
+
+ o  New $ua->from() method.
+
+ o  Support for gopher Index-Search (gopher type '7' requests).
+    Contributed by Harry Bochner <bochner@das.harvard.edu>
+
+ o  Cleaned up white-space usage in the source.
+
+
+
+Wed Apr  3 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b11
+
+ o  Implemented a NNTP protocol module.  The library can now fetch and
+    post news articles.
+
+ o  More documentation
+
+ o  Don't look at the URI header for redirects
+
+ o  New $res->base() method for HTTP::Responses
+
+ o  Graham Barr's patch to File::Listing to make it more OO internally
+
+ o  content_type() return value is canonicalized
+
+ o  $ua->request() does not die on bad URLs any more
+
+ o  LWP::MediaTypes merge all media.types files that if finds
+
+ o  FTP request with content to file or callback did not work
+
+ o  The value of HTTP Host: header is now $url->netloc;
+
+ o  The URI::URL constructor now accept URLs wrapped up in "<>"
+
+ o  $url->abs() now has a second optional argument that makes it accept
+    that relative URLs can have scheme, i.e. treat "http:img.gif" as a
+    relative URL.
+
+ o  Added prototypes to the HTTP::Status::is_xxx() functions
+
+ o  Added prototypes to the MIME:: encoding/decoding functions
+
+ o  Always return scheme for mailto and news URLs (as_string)
+
+ o  RobotRules patches from Henry A Rowley.
+
+ o  More tests
+
+ o  <SMALL> and <BIG> again
+
+
+
+Thu Mar 14 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b10
+
+ o  GET ftp://host/doc was never successful for normal files.
+
+ o  LWP::Socket: read_until() did not notice EOF condidtion.  I.e. if
+    a HTTP server closed the connection before any output was generated,
+    the we continued to read 0 bytes in a busy loop until the alarm()
+    killed us.
+
+ o  Added support for Digest Access Authentication.  Contributed by
+    Doug MacEachern <dougm@osf.org>.
+
+ o  Makefile.PL: check for MD5 library
+
+ o  No longer print message content in HTTP::Response::error_as_HTML()
+
+ o  Access to "file:/path" gave warning when the envirionment variable
+    no_proxy was set.
+
+ o  The http-post test sends a Content-Type header.  Some servers hang
+    if this header is missing.
+
+ o  HTML::Parse:
+     -   allow <SMALL> and <BIG> tags
+     -   allow empty attribute values
+
+
+
+Tue Mar  5 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b9
+
+ o  Started to write on the libwww-perl cookbook (lwpcook.pod)
+
+ o  The URI::URL module now exports the function url().  This is an
+    alternative (easy to use) constructor function.
+
+ o  Expanding relative file URLs starting with "#" did not work.
+
+ o  Fixed autoloaded DESTROY problem by adding empty DESTROY routine
+    to URI::URL.
+
+ o  Does not try generate password for ftp-URLs unless the username is
+    "anonymous" or "ftp"
+
+ o  The LWP::Simple user agent proxy settings are intialized from
+    the proxy environment variables. 
+
+ o  LWP::Protocol::ftp: Use the Net::FTP library to access ftp servers.
+    Convert directories to HTML on request (Accept: text/html).
+
+ o  New module HTTP::Negotiate
+
+ o  New module File::Listing
+
+ o  HTTP::Date::str2time can parse a few more formats, like the 'ls -l'
+    format and ISO 8601.  The function now also takes an optional second
+    parameter which specify a default time zone.
+
+ o  Added prototypes to the HTTP::Date functions.
+
+ o  The library adds a timestamp to responses ("Client-Date")
+
+ o  HTTP::Status:  Updated to proposed HTTP/1.1
+
+ o  HTTP::Headers: Updated to proposed HTTP/1.1
+
+ o  LWP::Protocol::http:  Updated to HTTP/1.1 methods
+
+ o  Took out stringify overloading in HTML::Element.
+
+
+
+Mon Feb 26 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b8
+
+ o  Renamed functions using thisStyleOfNames to this_style_of_names.
+    Provided a script called 'update_from_5b7'
+
+ o  Renamed the 'request' and 'mirror' scripts to 'lwp-request' and
+    'lwp-mirror'.  The GET, POST, HEAD aliases for 'lwp-request' are
+    the same.
+
+ o  Implemented LWP::RobotUA
+
+ o  Class name for RobotRules did not match the file name
+
+ o  URI::URL
+      - perl5.002gamma is required (because use vars).
+      - The leading slash in now part of the path if it is present.
+      - More documentation
+      - Use AutoLoader to speed things up.
+      - New class URI::URL::_login and made telnet, rlogin, tn3270
+        subclasses from this one.
+      - URI::URL::wais is better supported.
+      - URI::URL::news is better supported.
+      - New URI::URL::mailto methods: user/host
+
+ o  HTTP::Date::time2str now works correctly with '0' as argument
+
+ o  HTTP::Message delegates unknown methods to the headers.
+
+ o  HTTP::Request::uri is an alias for HTTP::Request::url.  Can set
+    the URL to undef.
+
+ o  Added convenience methods to HTTP::Headers for easy access to
+    frequently used headers.
+
+ o  Simplified LWP::Debug
+
+ o  Use standard AutoLoader for LWP::IO functions.
+
+ o  Played with the profiler (Devel::DProf) and made some things
+    go quicker.
+
+ o  Included the File::CounterFile module.  Excluded Mail::Cap module
+    as it is also part of the MailTools package.
+
+
+
+Mon Feb  5 1996   Gisle Aas <aas@sn.no>
+
+ o  Release 5b7
+
+ o  Perl5.002 is required now
+
+ o  Rewrite of the URI::URL module (version 4.00)
+      - escaping/unsafe stuff redone (and removed)
+      - URI::URL::_generic moved out of URL.pm
+      - netloc, path, params, query is now stored internally in escaped form
+      - new methods for URI::URL::_generic are:
+           epath
+           eparams
+           equery
+	   path_components
+           absolute_path
+      - new methods for URI::URL::http are:
+           keywords
+           query_form
+      - new methods for URI::URL::file are:
+           newlocal
+           local_path
+           unix_path
+           dos_path
+           mac_path
+           vms_path
+
+ o  URI::Escape now semi-compile regular expressions (by evaling an
+    anonymous sub).  Same techinque is also used in HTML::Entities.
+
+ o  HTTP::Date parser rewritten using regular expressions.
+
+ o  HTTP::Headers->as_string() now croaks if any field values
+    contain newline.
+
+ o  HTTP::Status constants use empty prototype.
+
+ o  Font metrics moved to a new subdirectory (lib/Font/Metrics)
+
+ o  Don't use the VERSION script any more (even if it was very clever)
+
+ o  HTML::Entities will now export the names decode_entities() and
+    encode_entities().
+
+ o  Andreas Koenig's black patch to HTML::Element.
+
+ o  The HTML::Formatter now knows about <menu> and <dir> tags
+
+ o  The construct "defined ref($arg)" did not work on perl5.002
+    becase ref now always return something defined.
+
+ o  LWP::UserAgent sends by default an 'User-Agent' header.
+
+ o  LWP::Simple sends 'User-Agent' header to servers.
+
+ o  Updated the LWP::Socket module to use the new Socket.pm interface.
+
+ o  LWP::Protocol::http sends the new HTTP/1.1 'Host' header.
+
+ o  LWP::Protocol::file use $url->local_path to get a file to open.
+    It also inserts a <BASE> tag in directories instead of a redirect.
+
+ o  MIME::Base64 routines can be called as MIME::Base64::encode() and
+    MIME::Base64::decode().  Same kind of thing for QuotedPrint.
+
+
+
+Mon Nov  6 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Release 5b6
+
+ o  Installation should work better for those that still runs
+    perl4 as 'perl'.  The mirror script is not installed by
+    default.
+
+ o  LWP::Socket::_getaddress() Numerical IP adresses did not work.
+
+ o  LWP::Socket::pushback() did not work.  This also avoids the bad
+    pp_select() core dump from perl.
+
+ o  LWP::IO now also selects on socket exceptions.
+
+ o  HTML::Parse:  Ignore <!DOCTYPE ...> regardless for case.  Some
+    bad insertElement() calls made infinite loops.
+
+ o  The uri.t test works better for places where /tmp is a sym-link.
+
+
+
+Sat Sep 16 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Release 5b5
+
+ o  newlocal URI::URL does not put "//localhost" into the URLs any
+    longer.
+
+ o  The request program: New -o option to reformat the HTML code
+    New -C option to provide credentials on the command line.
+    The -b option never worked.
+
+ o  LWP::Protocol::file now returns redirect for access to directories
+    where the trailing slash is missing.
+
+
+
+Thu Sep 14 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Speedups and bug fixes in the HTML parser.  The parser now
+    understands some more depreciated tags (like <xmp> and <listing>).
+
+ o  HTML::Elements are now stingified using perl overloading.
+    The interface to the traverse() callback has changed.
+
+ o  Implemented HTML formatters for plain text and Postscript.
+
+ o  Added lib/Font stuff to support the Postscript formatter.
+
+ o  Inspired by Tim Bunce, I implemented the HTML::AsSubs module.
+    Don't know if it is really useful.
+
+ o  The local/get test does not use /etc/passwd any more.
+
+
+
+Thu Sep  7 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Changed package name to libwww-perl-5xx
+
+ o  Made LWP::Protocol::ftp actually transfer data
+
+ o  Implemented methods for LWP::Socket to act as a server:
+    bind(), listen(), accept(), getsockname(), host(), port()
+
+
+
+Wed Sep  6 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Release 0.04
+
+ o  Implemented modules to parse HTML.
+
+
+
+Mon Sep  4 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Implemented Mail::Cap which will become part of the MailTools
+    package.
+
+ o  Moved Base64 to MIME::Base64.  Reimplemented MIME::Base64 by using
+    [un]pack("u",...)   Implemented LWP::MIME::QuotedPrint for
+    completness sake.  Routine names has changed as suggested by Tim
+    Bunce.
+
+ o  LWP::MediaType reads default types from media.types file.
+    guessMediaType() now also returns encodings.  New function mediaSuffix()
+
+ o  Pass $url to $ua->getBasicCredentials().  This also fixes security
+    hole with the old implementation of getBasicCredentials().
+
+ o  LWP::Protocol::file now sets Content-Encoding headers
+
+ o  Allow request content to be provided by a callback routine.
+
+ o  Fix bug that prevented response callback to work.  The first parameter
+    (data) is no longer a reference, because $_[0] is already a reference.
+    Don't callback unless successful response.  Callbacks during redirects
+    was confusing.
+
+ o  URI::URL.  Remove port from netloc if it is the default port.
+    Don't use anything, just require.
+
+ o  HTTP::Message->addContent() does not need a reference parameter.
+
+ o  LWP::Socket->open() has been renamed top LWP::Socket->connect()
+    LWP::Socket->close has gone.  Implemented new method LWP::Socket->read()
+    that returns as fast as it has some data to offer.  Implemented
+    LWP::Socket->pushback().
+
+ o  Does not die in LWP::UserAgent->request()
+
+ o  LWP::Socket now use LWP::IO for low level IO
+
+ o  Implemented LWP::TkIO as a replacement module for LWP::IO when using Tk.
+
+
+
+Thu Aug 17 1995   Gisle Aas <aas@oslonett.no>
+
+ o  $ua->redirectOK() for checking redirects
+
+ o  reorganized tests in the "t" directory.
+
+
+
+Fri Aug 11 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Release 0.03
+
+ o  Included RobotRules.pm from Martijn Koster
+
+
+
+Thu Aug 10 1995   Gisle Aas <aas@oslonett.no>
+
+ o  New module URI::Escape (URI::URL use this module for default
+    escaping) that provide the uri_escape() and uri_unescape()
+    functions.
+
+ o  Setting $url->scheme now changes the class of the object.
+
+ o  Made $httpurl->user() and $httpurl->password() illegal.
+    Likewise for other URL schemes.
+
+
+
+
+Wed Aug  9 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Reorganisation as discussed on <libwww-perl@ics.uci.edu>
+       LWP::Date       --> HTTP::Date
+       LWP::MIMEheader --> HTTP::Headers
+       LWP::StatusCode --> HTTP::Status
+       LWP::Message    --> HTTP::Message
+       LWP::Request    --> HTTP::Request
+       LWP::Response   --> HTTP::Response
+       LWP::MIMEtypes  --> LWP::MediaTypes
+
+ o  HTTP::Date parses ctime format with missing timezone as suggested
+    by Roy Fielding <fielding@beach.w3.org>
+
+ o  HTTP::Status and LWP::MediaTypes exports their functions by default.
+
+ o  Splitted up the URI::URL module.  Schemes are implemented by separate
+    files that are autoloaded when used.  Self test moved to "t/uri.t".
+
+
+       
+Mon Aug  7 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Applied patch from Marc Hedlund <hedlund@best.com>
+       - Update the @header_order according to the August 3rd draft.
+       - Added Response Header fields: 'Location', 'Public', 'Retry-After',
+         'Server', and 'WWW-Authenticate'.
+       - Moved 'unknown header' handling from &scan to &header. The old
+         implementation was forcing all unknown header-words to begin with
+	 an uppercase (as it should be), but disallowed other uppercase
+	 letters.
+       - updates the status code messages under the August
+         3rd HTTP/1.0 draft.  '203' became 'Non-Authoritative Information',
+	 '303' became 'See Other', and a new code,
+	 '411 Authorization Refused', was added.
+
+ o  Can remove multiple headers with single removeHeader() call in MIMEheader.
+
+ o  Can assign multiple field/value pairs in header() method of MIMEheader.
+
+ o  A field with multiple values is printed as separate values in
+    MIMEheader::as_string().
+
+ o  LWP::Response contain new attributes: previous() and request().  These
+    attributes are updated by the UserAgent.
+
+ o  Appended \n to some die statements in Socket so that line numbers are
+    suppressed in error messages.
+
+ o  Made UserAgent::clone work for reference members
+
+ o  Check for redirect loops and multiple authorization failures by
+    examination of the response chain.
+
+ o  Use "\015\012" instead of "\r\n" in protocol modules.  Some systems
+    define \r and \n differently.
+
+ o  request program can now handle documents that needs autorization by
+    prompting the user for username/password. Added new -S option to print
+    request/response chain.
+
+
+  
+Tue Jul 25 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Release 0.02
+
+ o  Included URI::URL in the release
+
+
+
+Mon Jul 24 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Incorporated Makemake.PL and VERSION from Andreas Koenig <koenig@mind.de>
+    As a result of this the following things have changed:
+       - programs in "bin" are extracted from .PL-files
+       - reintroduced "lib"
+       - "test" has been renamed as "t"
+       - test programs in "t" has been made Test::Harness compatible
+       - we now have a MANIFEST file
+       - no more need fro update_version, make-dist, lwp-install
+
+ o  Renamed bin/get to bin/request.  Links to it are now all upper case.
+
+ o  Proxy support in bin/request (provided by Martijn Koster)
+
+ o  UserAgent can now load proxy settings from environment
+
+ o  LWP::Protocol::ftp is under way but not really finished
+
+
+
+Tue Jul 18 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Implemented LWP::Protocol::gopher
+
+ o  Implemented LWP::Protocol::mailto
+
+ o  Fixed proxy typo
+
+
+
+Mon Jul 17 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Made release 0.01
+
+
+
+Mon Jul 17 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Don't loose first line of HTTP/0.9 requests
+
+ o  LWP::Socket use syswrite() for writing
+
+ o  Added RC_* documentation to LWP::StatusCode
+
+ o  LWP::Date now use hash to look up month numbers
+
+ o  Added -f option to "get"
+
+ o  Untabify
+
+ o  Added a "TODO" list
+
+ o  Fixed various typos
+
+
+
+Fri Jul 14 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Reorganized directories.  Moved LWP.pm up.  Moved file.pm and http.pm
+    into the LWP::Protocol direcotory.  Moved LWP out of the lib directory
+    and removed lib.
+
+ o  Implemented the "get" and "mirror" scripts in the "bin" directory.
+
+ o  Implemented "install-lwp", "update_version" and "make-dist".  The library
+    version number is found in the VERSION file.
+
+ o  Always adds 1900 to the year in LWP::Date
+
+ o  In LWP::MIMEheader:  Implemented clone(), removeHeader() and scan() 
+    methods.  Reimplemented asString.  Removed asMIME().  Moved "Good
+    Practice" into this file, and reimplemented it.
+
+ o  Moved "header" and "content" into LWP::Message class.  This change made
+    LWP::Request and LWP::Response much simpler.  Made clone() method
+    actually work.
+
+ o  LWP::Protocol::implementor does not die if it cannot load package.
+
+ o  Moved UserAgent convenience methods into LWP::Simple.  Made LWP::Simple
+    export LWP::StatusCode symbols and functions.
+
+ o  Implemented $ua->isProtocolSupported($scheme) method.
+
+ o  Nicer directory listing in LWP::Protocol::file.pm
+
+ o  Rely on URI::URL 3.00 behaviour for $url->full_path
+
+ o  Library version number now in LWP.pm.  You should be able to say
+    "use LWP 1.0;" if you need at least this version.
+
+ o  Various cleanups and arranging layout as I like it.  Use fooBar-style
+    (as opposed to foo_bar stype) everywhere.  This means that as_string()
+    now is called asString().
+
+ o  Added more documentation.
+
+
+
+Wed Jun 14 1995   Gisle Aas <aas@oslonett.no>
+
+ o  Removed lot of rendundant & before function calls.
+
+ o  $this --> $self
+
+ o  &collector passes content as a reference, don't want to copy so much
+
+ o  parameterlist to collect callback has been rearranged
+
+ o  Response::addContent gets a reference to the data
+
+ o  Added some callback documentation to UserAgent.pm
+
+ o  Protocol::file now uses the collector
+
+ o  Introduced LWP::Simple
+
+
+
+Sun Jun 11 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Added basic authentication support
+
+ o  Added mirroring of single documents
+
+ o  Change Protocol construction from whacky URL.pm (constructor returns
+    subclass) to more normal C++'ish way.
+
+
+
+Wed June 7 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Minor cleanups from printed code inspection
+
+
+
+Wed May 24 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Added redirection resolution
+
+ o  Added optional autoloading of protocols
+
+
+
+Tue May 23 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Separated socket stuff into separate module
+
+ o  Added HTTP proxy support
+
+ o  Made alarm handling optional
+
+ o  Added a LWP::Message for completeness sake
+
+ o  Added LWP::MemberMixin to reduce code duplication
+
+ o  Cosmetic changes to LWP::Date
+
+ o  Renamed LWP::Error to LWP::StatusCode
+
+ o  Renamed LWP::MIME to LWP::MIMEtype
+
+ o  Changed the tests to cope with all this
+
+It's getting there...
+
+
+
+Mon May 22 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Changed the socket reading to use sysread.  This will have to go
+    into a module of its own.
+
+
+
+Thu 18 May 1995   Martijn Koster <m.koster@nexor.co.uk>
+
+ o  Mentioned on libwww-perl that I had changed the classes around lots.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/INSTALL.w3mir
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/INSTALL.w3mir	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/INSTALL.w3mir	(revision 10506)
@@ -0,0 +1,48 @@
+
+- Get libwww-perl from CPAN 
+  (http://www.perl.com/CPAN/modules/by-module/WWW/).  W3mir does not work
+  with LWP 5.40 and later versions.  Please get an earlier version.
+  It also does not work with the new URI package.  Use the URI package
+  enclosed in the older LWP.
+
+- Unpack it:
+
+    gzip -dc libwww-perl-*.tar.gz | tar xvBf -
+
+- Install it.  W3mir does not require the whole libwww-perl package and
+  all the packages that goes with it to work so you may follow these
+  install instructions instead of the libwww-perl install instructions
+  to get an easier install which will work with w3mir.
+
+    cd libwww-perl-*
+
+  Are you going to install it in the standard perl place (you need to
+  be the system administrator to do this)? If so:
+
+    perl Makefile.PL
+
+  If not (if you are a user):
+
+    perl Makefile.PL PREFIX=/some/dir
+
+  /some/dir could be ~ (as in your home directory).
+
+  IF you are installing an old LWP just for w3mir you can install both
+  the old LWP, the Base64 module and w3mir in a special PREFIX
+  separate from your usual install PREFIX.  This ensures that w3mir will
+  access the older version of LWP and that other software will access
+  the newer version.  If you do this make sure you install all of LWP,
+  Base64 and w3mir with the same PREFIX.
+
+  This step might produce some complaints;  A standard perl
+  installation will typically get messages about missing these
+  modules: IO::Socket, NET::FTP and MD5.  None of these need be
+  installed to run w3mir and so any error messages about these may
+  safely be ignored.
+
+    make
+    make test      (robot/ua and local/http might fail, that's OK)
+    make install
+
+  Now libwww-perl should be installed and working.
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/MANIFEST
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/MANIFEST	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/MANIFEST	(revision 10506)
@@ -0,0 +1,106 @@
+ChangeLog			History of this package
+MANIFEST			This file
+Makefile.PL			Makefile generator
+README				Get you started with this package
+TODO				The To-Do list for the library
+bin/lwp-download.PL             Writes bin/lwp-download script
+bin/lwp-mirror.PL		Writes bin/lwp-mirror script
+bin/lwp-request.PL		Writes bin/lwp-request script
+bin/lwp-rget.PL			Writes bin/lwp-rget script
+lwpcook.pod			Libwww-perl examples
+lib/Bundle/LWP.pm               Defines prereq modules
+lib/File/Listing.pm		Parse directory listings
+lib/HTTP/Cookies.pm             Cookie storage and management
+lib/HTTP/Daemon.pm		A simple httpd
+lib/HTTP/Date.pm		Date conversion routines
+lib/HTTP/Headers.pm		Class encapsulating HTTP Message headers
+lib/HTTP/Headers/Auth.pm	Some methods that deal with authorization.
+lib/HTTP/Headers/ETag.pm	Some methods that deal with entity tags
+lib/HTTP/Headers/Util.pm        Some utility functions for header values.
+lib/HTTP/Message.pm		Class encapsulating HTTP messages
+lib/HTTP/Negotiate.pm		Evaluate HTTP content negotiation algoritm
+lib/HTTP/Request.pm		Class encapsulating HTTP Requests
+lib/HTTP/Request/Common.pm      Generate common requests
+lib/HTTP/Response.pm		Class encapsulating HTTP Responses
+lib/HTTP/Status.pm		HTTP Status code processing
+lib/LWP.pm			Includes what you need
+lib/LWP/Authen/Basic.pm		Basic authentication scheme
+lib/LWP/Authen/Digest.pm	Digest authentication scheme
+lib/LWP/Debug.pm		Debugging support
+lib/LWP/MediaTypes.pm		Library for guessing media types
+lib/LWP/MemberMixin.pm		Helps you access %$self
+lib/LWP/Protocol.pm		Virtual base class for LWP protocols
+lib/LWP/Protocol/data.pm        Access to data URLs
+lib/LWP/Protocol/file.pm	Access local files
+lib/LWP/Protocol/ftp.pm		Access with the FTP protocol
+lib/LWP/Protocol/gopher.pm	Access with the Gopher protocol
+lib/LWP/Protocol/http.pm	Access with HTTP protocol
+lib/LWP/Protocol/https.pm	Access with HTTP protocol over SSL
+lib/LWP/Protocol/mailto.pm	Allows you to POST mail using sendmail
+lib/LWP/Protocol/nntp.pm	Handles access to news: and nntp: URLs
+lib/LWP/RobotUA.pm		Easy creation of conforming robots
+lib/LWP/Simple.pm		Procedural LWP interface
+lib/LWP/UserAgent.pm		A WWW UserAgent class
+lib/LWP/media.types		Mapping from file extentions media types
+lib/URI/Escape.pm		General URI escaping functions
+lib/URI/Heuristic.pm            User friendly URLs
+lib/URI/URL.pm			Class encapsulating URLs
+lib/URI/URL/_generic.pm		Implements generic hierarchical RL (RFC 1808)
+lib/URI/URL/_login.pm		Base class for telnet, tn3270 and rlogin
+lib/URI/URL/data.pm             Implements data URLs
+lib/URI/URL/file.pm		Implements file URLs
+lib/URI/URL/finger.pm		Implements finger URLs
+lib/URI/URL/ftp.pm		Implements ftp URLs
+lib/URI/URL/gopher.pm		Implements gopher URLs
+lib/URI/URL/http.pm		Implements http URLs
+lib/URI/URL/https.pm		Implements https URLs
+lib/URI/URL/mailto.pm		Implements mailto URLs
+lib/URI/URL/news.pm		Implements news URLs
+lib/URI/URL/nntp.pm		Implements nntp URLs
+lib/URI/URL/prospero.pm		Implements prospero URLs
+lib/URI/URL/rlogin.pm		Implements rlogin URLs
+lib/URI/URL/telnet.pm		Implements telnet URLs
+lib/URI/URL/tn3270.pm		Implements tn3270 URLs
+lib/URI/URL/wais.pm		Implements wais URLs
+lib/URI/URL/webster.pm		Implements webster URLs
+lib/URI/URL/whois.pm		Implements whois URLs
+lib/WWW/RobotRules.pm		Parse robot.txt files
+lib/WWW/RobotRules/AnyDBM_File.pm	Persistent robot rules
+t/README			How to run and set up tests
+t/TEST				Run tests
+t/base/common-req.t		Test HTTP::Request::Common module
+t/base/cookies.t                Test HTTP::Cookies module
+t/base/date.t			Test HTTP::Date module
+t/base/headers.t		Test HTTP::Headers module
+t/base/headers-auth.t		Test HTTP::Headers::Auth module
+t/base/headers-etag.t		Test HTTP::Headers::ETag module
+t/base/headers-util.t		Test HTTP::Headers::Util module
+t/base/listing.t		Test File::Listing module
+t/base/mediatypes.t		Test LWP::MediaTypes module
+t/base/message.t		Test HTTP::Request/HTTP::Response
+t/base/negotiate.t		Test HTTP::Negotiation module
+t/base/response.t		Test additional HTTP::Response methods
+t/base/status.t			Test HTTP::Status module
+t/local/autoload.t		Test autoloading of LWP::Protocol modules
+t/local/get.t			Try to get a local file
+t/local/http.t			Test http to local server
+t/local/protosub.t              Test with other protocol module
+t/net/cgi-bin/moved
+t/net/cgi-bin/nph-slowdata
+t/net/cgi-bin/slowread
+t/net/cgi-bin/test
+t/net/cgi-bin/timeout
+t/net/config.pl.dist		Suggested configuration for net tests
+t/net/http-get.t
+t/net/http-post.t
+t/net/http-timeout.t
+t/net/mirror.t
+t/net/moved.t
+t/net/proxy.t
+t/robot/rules-dbm.t		Test WWW::RobotRules::AnyDBM_File
+t/robot/rules.t			Test WWW::RobotRules
+t/robot/ua.t			Test LWP::RobotUA
+t/uri/abs-config.t              Test URI::URL configuration variables
+t/uri/base.t			Test URI::URL module
+t/uri/rel-base.t		Test URI::URL module some more
+t/uri/heuristic.t               Test URI::Heuristic module
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/Makefile.PL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/Makefile.PL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/Makefile.PL	(revision 10506)
@@ -0,0 +1,184 @@
+# This -*- perl -*- script writes the Makefile for libwww-perl
+# $Id$
+
+require 5.004;
+use strict;
+
+#--- Configuration section ---
+
+my @programs_to_install = qw(lwp-request lwp-mirror lwp-rget lwp-download);
+my @request_aliases     = qw(GET HEAD POST);
+
+#--- End Configuration - You should not have to change anything below this line
+
+
+# Allow us to suppress all program installation with the -n (library only)
+# option.  This is for those that don't want to mess with the configuration
+# section of this file.
+use Getopt::Std;
+use vars qw($opt_n);
+unless (getopts("n")) {
+    die "Usage: $0 [-n]\n";
+}
+@programs_to_install = () if $opt_n;
+
+
+# Check for non-standard modules that are used by this library.
+$| = 1;
+my $missing_modules = 0;
+
+print "Checking for HTML::Parser..";
+eval {
+    require HTML::HeadParser;
+};
+if ($@) {
+    print " failed\n";
+    $missing_modules++;
+    print <<EOT;
+$@
+The HTML::Parser is needed to extract correct <BASE> information from
+HTML so that we can resolv relative links correctly.
+
+EOT
+    sleep(2);  # Don't hurry too much
+} else {
+    print " ok\n";
+}
+
+print "Checking for MIME::Base64..";
+eval {
+    require MIME::Base64;
+    #MIME::Base64->require_version('2.00');
+};
+if ($@) {
+    print " failed\n";
+    $missing_modules++;
+    print <<EOT;
+$@
+The Base64 encoding is used in authentication headers in HTTP.
+
+EOT
+    sleep(2);  # Don't hurry too much
+} else {
+    print " ok\n";
+}
+
+print "Checking for Net::FTP......";
+eval {
+    require Net::FTP;
+    Net::FTP->require_version('2.00');
+};
+if ($@) {
+    print " failed\n";
+    $missing_modules++;
+    print <<EOT;
+$@
+The libwww-perl library normally use the Net::FTP module when
+accessing ftp servers.  You would have to install this package or
+configure your application to use a proxy server for making ftp
+requests work.  Net::FTP is part of the 'libnet' distribution.
+
+EOT
+    sleep(2);  # Don't hurry too much
+} else {
+    print " ok\n";
+}
+
+print "Checking for MD5 ..........";
+eval {
+    require MD5;
+};
+if ($@) {
+    print " failed\n";
+    $missing_modules++;
+    print <<EOT;
+$@
+The MD5 library is needed if you want to be able use the experimental
+"Digest Access Authentication" scheme.  Since very few servers
+implement this authentication scheme, you should normally not worry
+too much about this.
+
+EOT
+} else {
+    print " ok\n";
+}
+
+print <<EOT if $missing_modules;
+The missing modules can be obtained from CPAN.  Visit
+<URL:http://www.perl.com/CPAN/> to find a CPAN site near you.
+
+EOT
+
+
+# Ok, now it is time to really generate the Makefile
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+   NAME          => 'libwww-perl',
+   VERSION_FROM  => 'lib/LWP.pm',
+   PL_FILES      => { map {("bin/$_.PL" => "bin/$_")} @programs_to_install },
+   EXE_FILES     => [ map {"bin/$_"} @programs_to_install ],
+   'clean'       => { FILES => '$(EXE_FILES)' },
+   'dist'        => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
+);
+
+
+
+package MY;
+
+sub postamble
+{
+    my @m;
+    if (@request_aliases && grep($_ eq 'lwp-request', @programs_to_install)) {
+	push @m, "all ::\n";
+	if ($^O eq 'MSWin32') {
+	    push @m, "\t\$(FULLPERL) -e \"use Config; chdir q[\$(INST_EXE)]; "
+		    ."foreach (qw(@request_aliases)) { \" \\\n";
+	    push @m, <<'EOT';
+	-e "unlink \"$$_\"; " \
+	-e "system(\"copy lwp-request $$_\") && die; }"
+EOT
+	} else {
+	    push @m, "\t\$(FULLPERL) -e 'use Config; chdir q{\$(INST_EXE)}; "
+		    ."foreach (qw(@request_aliases)) {' \\\n";
+	    push @m, <<'EOT';
+	-e 'unlink "$$_";' \
+	-e 'system("$$Config{\"lns\"} lwp-request $$_") && die; }'
+EOT
+	}
+    }
+    join "", @m;
+}
+
+# What happens when we say 'make test'
+sub test
+{
+    q(
+TEST_VERBOSE=0
+
+test: all
+	$(FULLPERL) t/TEST $(TEST_VERBOSE)
+
+);
+}
+
+
+# Determine things that should *not* be installed
+sub libscan
+{
+    my($self, $path) = @_;
+    return '' if $path =~ m/.(pl|dtd|sgml)$/;
+    return '' if $path =~ m:\bCVS/:;
+    return '' if $path =~ m/~$/;
+    $path;
+}
+
+# Pass libwww-perl version number to pod2man
+sub manifypods
+{
+    my $self = shift;
+    my $ver = $self->{VERSION} || "";
+    local($_) = $self->SUPER::manifypods(@_);
+    s/pod2man\s*$/pod2man --release libwww-perl-$ver/m;
+    $_;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/README	(revision 10506)
@@ -0,0 +1,124 @@
+                     L I B W W W - P E R L - 5
+                   -----------------------------
+
+Libwww-perl is a collection of Perl modules which provides a simple
+and consistent programming interface (API) to the World-Wide Web.  The
+main focus of the library is to provide classes and functions that
+allow you to write WWW clients, thus libwww-perl said to be a WWW
+client library. The library also contain modules that are of more
+general use and even classes that helps you implement simple HTTP
+servers.
+
+There are actually two versions of libwww-perl: one for Perl4, and one
+for Perl5. Both have a similar architecture, loosely based on the CERN
+Library of Common Code (nowadays known as 'w3c-libwww').
+
+The Perl4 version is still(?) maintained by Roy Fielding, and was the
+basis for tools such as MOMSpider. The perl4 version of libwww-perl
+and much more information about its libraries can be found at:
+http://www.ics.uci.edu/pub/websoft/libwww-perl/
+
+The Perl5 version (this package) is a complete rewrite for Perl5: the
+code is organized in Modules, provides an Object Oriented API, is
+updated for the latest HTTP and URL specification, and offers some
+extended functionality.
+
+Full HTTP/1.1 support is on its way.  Alpha releases of the LWPng
+package is currently available from CPAN.
+
+
+PREREQUISITES
+
+In order to install and use this package you will need Perl version
+5.004 or better.  Some modules within this package depend on other
+packages that are distributed separately from Perl.  We recommend that
+you have the following packages installed before you install
+libwww-perl:
+
+  MIME-Base64
+  HTML-Parser
+  libnet
+  MD5
+
+These packages should be available on CPAN.
+
+If you want to access sites using the https protocol, then you need to
+install the Crypt-SSLeay modules first.  (The Net::SSLeay module is not
+supported any more.)
+
+
+INSTALLATION
+
+You install libwww-perl, as you would install any perl module library,
+by running these commands:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+You can edit the configuration section of Makefile.PL to select which
+programs to install in addition to the library itself.  If you don't
+want to install any programs (only the library files) and don't want
+to mess with the Makefile.PL then pass the '-n' option to Makefile.PL:
+
+   perl Makefile.PL -n
+
+If you want to install a private copy of libwww-perl in your home
+directory, then you should try to produce the initial Makefile with
+something like this command:
+
+  perl Makefile.PL LIB=~/perl
+
+The Makefile.PL program will start out by checking your perl
+installation for a few packages that are recommended to be installed
+together with libwww-perl.
+
+Optional network tests are _not_ enabled automatically when you unpack
+this package.  Consult the t/README file for instructions on how to
+enable these tests.
+
+
+DOCUMENTATION
+
+See lib/LWP.pm for an overview of the library. See ChangeLog for
+recent changes.  POD style documentation is included in all modules
+and scripts.  These are normally converted to manual pages and
+installed as part of the "make install" process.  You should also be
+able to use the 'perldoc' utility to extract and read documentation
+from the module files directly.
+
+
+SUPPORT
+
+Question about how to use this library should be directed to the
+comp.lang.perl.modules USENET Newsgroup.  Bug reports and suggestions
+for improvements can be sendt to the <libwww-perl@ics.uci.edu> mailing
+list.  This mailing list is also the place for general discussions and
+development of the libwww-perl package.
+
+You can join the mailing list by sending a message to
+<libwww-perl-request@ics.uci.edu> with "Subscribe" as subject.
+            ^^^^^^^^
+
+AVAILABILITY
+
+The latest version of libwww-perl should always be available from:
+
+     http://www.linpro.no/lwp/
+
+The library is also available from the Comprehensive Perl Archive
+Network (CPAN).  Visit <URL:http://www.perl.com/CPAN/> to find a CPAN
+site near you.
+
+
+COPYRIGHT
+
+  © 1995-1998 Gisle Aas. All rights reserved.
+  © 1995 Martijn Koster. All rights reserved.
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+
+Enjoy!
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/TODO
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/TODO	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/TODO	(revision 10506)
@@ -0,0 +1,46 @@
+                                            $Date$
+
+This is a list over things that we plan to implement in libwww-perl-5.
+The order of items does not reflect priority.
+
+  o  HTTP/1.1 support is on its way.  This also includes support of
+     multiple parallel connections.  Take a look at LWPng (aka
+     libwww-perl-6).
+
+  o  Provide initial credentials so that we don't always have to get a
+     401 response first.  Both for Basic and Digest authentication.  This
+     is in fact implemented for LWPng.
+
+  o  HTTP::Request::Common::POST() should be able to create large
+     file upload requests by making a closure content.
+
+  o  Support PICS??
+
+  o  Cache previous ftp connections.  "Keep-Alive"?
+
+  o  Support MOVE, DELETE method for ftp.
+
+  o  Support If-Modified-Since for ftp.
+
+  o  Use Mail::Send to implement LWP::Protocol::mailto.  Today we just
+     invoke sendmail directly, which is not very portable.
+
+  o  The lwp-request -o processing should check for Content-Encoding as
+     well as Content-Type.
+
+  o  The lwp-request script should optionally consult Mail::Cap for
+     handling of media types.
+
+  o  The lwp-request script should use the callback interface so that it
+     prints data as it is received.
+
+  o  The lwp-mirror script should be able to work recursively.
+
+  o  Include more useful programs
+
+  o  More documentation
+
+  o  More tests
+
+  o  Fix bugs, if there are any...
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-download.PL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-download.PL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-download.PL	(revision 10506)
@@ -0,0 +1,248 @@
+use Config;
+use File::Basename qw(basename dirname);
+chdir(dirname($0));
+($file = basename($0)) =~ s/\.PL$//;
+$file =~ s/\.pl$//
+	if ($Config{'osname'} eq 'VMS' or
+	    $Config{'osname'} eq 'OS2');  # "case-forgiving"
+open OUT,">$file" or die "Can't create $file: $!";
+chmod(0755, $file);
+print "Extracting $file (with variable substitutions)\n";
+
+print OUT <<"!GROK!THIS!";
+$Config{'startperl'} -w
+
+!GROK!THIS!
+
+print OUT <<'!NO!SUBS!';
+# $Id$
+
+=head1 NAME
+
+lwp-download - fetch large files from the net
+
+=head1 SYNOPSIS
+
+ lwp-download [-a] <url> [<local file>]
+
+=head1 DESCRIPTION
+
+The I<lwp-download> program will down load the document specified by the URL
+given as the first command line argument to a local file.  The local
+filename used to save the document is guessed from the URL unless
+specified as the second command line argument.
+
+The I<lwp-download> program is implemented using the I<libwww-perl>
+library.  It is better suited to down load big files than the
+I<lwp-request> program because it does not store the file in memory.
+Another benefit is that it will keep you updated about its progress
+and that you don't have much options to worry about.
+
+Use the C<-a> option to save the file in text (ascii) mode.  Might make a
+difference on dosish systems.
+
+=head1 EXAMPLE
+
+Fetch the newest and greatest perl version:
+
+ $ lwp-download http://www.perl.com/CPAN/src/latest.tar.gz
+ Saving to 'latest.tar.gz'...
+ 1.47 MB received in 22 seconds (68.7 KB/sec)
+
+=head1 AUTHOR
+
+Gisle Aas <gisle@aas.no>
+
+=cut
+
+use LWP::UserAgent;
+use LWP::MediaTypes;
+use URI::URL;
+use strict;
+
+my $progname = $0;
+$progname =~ s,.*/,,;    # only basename left in progname
+$progname =~ s/\.\w*$//; # strip extension if any
+
+#parse option
+use Getopt::Std;
+my %opts;
+unless (getopts('a', \%opts)) {
+    usage();
+}
+my $opt_a = $opts{a}; # save in binary mode
+
+my $url = url(shift || usage());
+my $argfile = shift;
+
+my $ua = new LWP::UserAgent;
+
+$ua->agent("lwp-download/0.1 " . $ua->agent);
+$ua->env_proxy;
+
+my $req = new HTTP::Request GET => $url;
+
+my $file;      # name of file we download into
+my $length;    # total number of bytes to download
+my $flength;   # formatted length
+my $size = 0;  # number of bytes received
+my $start_t;   # start time of download
+my $last_dur;  # time of last callback
+
+my $shown = 0; # have we called the show() function yet
+
+$SIG{INT} = sub { die "Interrupted\n"; };
+
+$| = 1;  # autoflush
+
+my $res = $ua->request($req,
+  sub {
+      unless($file) {
+	  my $res = $_[1];
+	  unless ($argfile) {
+	      # must find a suitable name to use.  First thing
+	      # to do is to look for the "Content-Disposition"
+	      # header defined by RFC1806.  This is also supported
+	      # by Netscape
+	      my $cd = $res->header("Content-Disposition");
+	      if ($cd && $cd =~ /\bfilename\s*=\s*(\S+)/) {
+		  $file = $1;
+		  $file =~ s/;$//;
+		  $file =~ s/^([\"\'])(.*)\1$/$2/;
+	      }
+		
+	      # if this fails we try to make something from the URL
+	      unless ($file) {
+		  my $req = $res->request;  # now always there
+		  my $rurl = $req ? $req->url : $url;
+		  
+		  $file = ($rurl->path_components)[-1];
+		  unless (length $file) {
+		      $file = "index";
+		      my $suffix = media_suffix($res->content_type);
+		      $file .= ".$suffix" if $suffix;
+		  } elsif ($rurl->scheme eq 'ftp' ||
+			   $file =~ /\.tgz$/      ||
+			   $file =~ /\.tar(\.(Z|gz))?$/
+			  ) {
+		      # leave the filename as it was
+		  } else {
+		      my $ct = guess_media_type($file);
+		      unless ($ct eq $res->content_type) {
+			  # need a better suffix for this type
+			  my $suffix = media_suffix($res->content_type);
+			  $file .= ".$suffix" if $suffix;
+		      }
+		  }
+	      }
+
+	      # Check if the file is already present
+	      if (-f $file && -t) {
+		  print "Overwrite $file? [y] ";
+		  my $ans = <STDIN>;
+		  exit if !defined($ans) || !($ans =~ /^y?\n/);
+	      } else {
+		  print "Saving to '$file'...\n";
+	      }
+	  } else {
+	      $file = $argfile;
+	  }
+	  open(FILE, ">$file") || die "Can't open $file: $!";
+          binmode FILE unless $opt_a;
+	  $length = $res->content_length;
+	  $flength = fbytes($length) if defined $length;
+	  $start_t = time;
+	  $last_dur = 0;
+      }
+      $size += length($_[0]);
+      print FILE $_[0];
+      if (defined $length) {
+	  my $dur  = time - $start_t;
+	  if ($dur != $last_dur) {  # don't update too often
+	      $last_dur = $dur;
+	      my $perc = $size / $length;
+	      my $speed;
+	      $speed = fbytes($size/$dur) . "/sec" if $dur > 3;
+	      my $secs_left = fduration($dur/$perc - $dur);
+	      $perc = int($perc*100);
+	      my $show = "$perc% of $flength";
+	      $show .= " (at $speed, $secs_left remaining)" if $speed;
+	      show($show);
+	  }
+      } else {
+	  show( fbytes($size) . " received");
+      }
+  }
+);
+
+if ($res->is_success || $res->message =~ /^Interrupted/) {
+    show("");  # clear text
+    print "\r";
+    print fbytes($size);
+    print " of ", fbytes($length) if defined($length) && $length != $size;
+    print " received";
+    my $dur = time - $start_t;
+    if ($dur) {
+	my $speed = fbytes($size/$dur) . "/sec";
+	print " in ", fduration($dur), " ($speed)";
+    }
+    print "\n";
+    my $died = $res->header("X-Died");
+    if ($died || !$res->is_success) {
+	if (-t) {
+	    print "Transfer aborted.  Delete $file? [n] ";
+	    my $ans = <STDIN>;
+	    unlink($file) if defined($ans) && $ans =~ /^y\n/;
+	} else {
+	    print "Transfer aborted, $file kept\n";
+	}
+    }
+} else {
+    print "\n" if $shown;
+    print "$progname: Can't download: ", $res->code, " ", $res->message, "\n";
+    exit 1;
+}
+
+
+sub fbytes
+{
+    my $n = int(shift);
+    if ($n >= 1024 * 1024) {
+	return sprintf "%.3g MB", $n / (1024.0 * 1024);
+    } elsif ($n >= 1024) {
+	return sprintf "%.3g KB", $n / 1024.0;
+    } else {
+	return "$n bytes";
+    }
+}
+
+sub fduration
+{
+    use integer;
+    my $secs = int(shift);
+    my $hours = $secs / (60*60);
+    $secs -= $hours * 60*60;
+    my $mins = $secs / 60;
+    $secs %= 60;
+    if ($hours) {
+	return "$hours hours $mins minutes";
+    } elsif ($mins >= 2) {
+	return "$mins minutes";
+    } else {
+	$secs += $mins * 60;
+	return "$secs seconds";
+    }
+}
+
+sub show
+{
+    my $mess = shift;
+    print "\r$mess", (" " x (75 - length $mess));
+    $shown++;
+}
+
+sub usage
+{
+    die "Usage: $progname [-a] <url> [<lpath>]\n";
+}
+!NO!SUBS!
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-mirror.PL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-mirror.PL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-mirror.PL	(revision 10506)
@@ -0,0 +1,120 @@
+use Config;
+use File::Basename qw(basename dirname);
+chdir(dirname($0));
+($file = basename($0)) =~ s/\.PL$//;
+$file =~ s/\.pl$//
+	if ($Config{'osname'} eq 'VMS' or
+	    $Config{'osname'} eq 'OS2');  # "case-forgiving"
+open OUT,">$file" or die "Can't create $file: $!";
+chmod(0755, $file);
+print "Extracting $file (with variable substitutions)\n";
+
+print OUT <<"!GROK!THIS!";
+$Config{'startperl'} -w
+
+!GROK!THIS!
+
+print OUT <<'!NO!SUBS!';
+# $Id$
+#
+# Simple mirror utility using LWP
+
+=head1 NAME
+
+lwp-mirror - Simple mirror utility for WWW
+
+=head1 SYNOPSIS
+
+ lwp-mirror [-v] [-t timeout] <url> <local file>
+
+=head1 DESCRIPTION
+
+This program can be used to mirror a document from a WWW server.  The
+document is only transfered if the remote copy is newer than the local
+copy.  If the local copy is newer nothing happens.
+
+Use the C<-v> option to print the version number of this program.
+
+The timeout value specified with the C<-t> option.  The timeout value
+is the time that the program will wait for response from the remote
+server before it fails.  The default unit for the timeout value is
+seconds.  You might append "m" or "h" to the timeout value to make it
+minutes or hours, repectively.
+
+Because this program is implemented using the LWP library, it only
+supports the protocols that LWP supports.
+
+=head1 SEE ALSO
+
+L<lwp-request>, L<LWP>
+
+=head1 AUTHOR
+
+Gisle Aas <aas@a.sn.no>
+
+=cut
+
+
+use LWP::Simple;
+use Getopt::Std;
+
+$progname = $0;
+$progname =~ s,.*/,,;  # use basename only
+$progname =~ s/\.\w*$//; #strip extension if any
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+$opt_h = undef;  # print usage
+$opt_v = undef;  # print version
+$opt_t = undef;  # timeout
+
+unless (getopts("hvt:")) {
+    usage();
+}
+
+if ($opt_v) {
+    require LWP;
+    my $DISTNAME = 'libwww-perl-' . LWP::Version();
+    die <<"EOT";
+This is lwp-mirror version $VERSION ($DISTNAME)
+
+Copyright 1995-1996, Gisle Aas.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+EOT
+}
+
+$url  = shift or usage();
+$file = shift or usage();
+usage() if $opt_h or @ARGV;
+
+if (defined $opt_t) {
+    $opt_t =~ /^(\d+)([smh])?/;
+    die "$progname: Illegal timeout value!\n" unless defined $1;
+    $timeout = $1;
+    $timeout *= 60   if ($2 eq "m");
+    $timeout *= 3600 if ($2 eq "h");
+    $LWP::Simple::ua->timeout($timeout);
+}
+
+$rc = mirror($url, $file);
+
+if ($rc == 304) {
+    print STDERR "$progname: $file is up to date\n"
+} elsif (!is_success($rc)) {
+    print STDERR "$progname: $rc ", status_message($rc), "   ($url)\n";
+    exit 1;
+}
+exit;
+
+
+sub usage
+{
+    die <<"EOT";
+Usage: $progname [-options] <url> <file>
+    -v           print version number of program
+    -t <timeout> Set timeout value
+EOT
+}
+!NO!SUBS!
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-request.PL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-request.PL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-request.PL	(revision 10506)
@@ -0,0 +1,521 @@
+use Config;
+use File::Basename qw(basename dirname);
+chdir(dirname($0));
+($file = basename($0)) =~ s/\.PL$//;
+$file =~ s/\.pl$//
+	if ($Config{'osname'} eq 'VMS' or
+	    $Config{'osname'} eq 'OS2');  # "case-forgiving"
+open OUT,">$file" or die "Can't create $file: $!";
+chmod(0755, $file);
+print "Extracting $file (with variable substitutions)\n";
+
+print OUT <<"!GROK!THIS!";
+$Config{'startperl'} -w
+
+!GROK!THIS!
+
+print OUT <<'!NO!SUBS!';
+# $Id$
+#
+# Simple user agent using LWP library.
+
+=head1 NAME
+
+lwp-request, GET, HEAD, POST - Simple WWW user agent
+
+=head1 SYNOPSIS
+
+ lwp-request [-aeEdvhx] [-m method] [-b <base URL>] [-t <timeout>]
+             [-i <if-modified-since>] [-c <content-type>] [-C <credentials>]
+             [-p <proxy-url>] [-o <format>] <url>...
+
+=head1 DESCRIPTION
+
+This program can be used to send requests to WWW servers and your
+local file system. The request content for POST, PUT and CHECKIN
+methods is read from stdin.  The content of the response is printed on
+stdout.  Error messages are printed on stderr.  The program returns a
+status value indicating the number of URLs that failed.
+
+The options are:
+
+=over 4
+
+=item -m <method>
+
+Set which method to use for the request.  If this option is not used,
+then the method is derived from the name of the program.
+
+=item -f
+
+Force request through, even if the program believes that the method is
+illegal.  The server will probably reject the request.
+
+=item -b <url>
+
+This URL will be used as the base URL for the URLs that the method is
+applied to.  The base URL only takes effect for relative URLs.  If you
+do not provide this option and the URLs are relative, then they will
+be treated as files in the local file system.
+
+=item -t <timeout>
+
+Set the timeout value for the requests.  The timeout is the amount of
+time that the program will wait for a response from the remote server
+before it fails.  The default unit for the timeout value is seconds.
+You might append "m" or "h" to the timeout value to make it minutes or
+hours, respectively.  The default timeout is '3m', i.e. 3 minutes.
+
+=item -i <time>
+
+Set the If-Modified-Since header in the request. If I<time> it the
+name of a file, use the modification timestamp for this file. If
+I<time> is not a file, it is parsed as a literal date. Take a look at
+L<HTTP::Date> for recogniced formats.
+
+=item -c <content-type>
+
+Set the Content-Type for the request.  This option is only allowed for
+requests that take a content, i.e. POST, PUT and CHECKIN.  You can
+force methods to take content by using the C<-f> option together with
+C<-c>.  The default Content-Type for POST is
+C<application/x-www-form-urlencoded>.  The default Content-type for
+the others is C<text/plain>.
+
+=item -p <proxy-url>
+
+Set the proxy to be used for the requests.  The program also loads
+proxy settings from the environment.  You can disable this with the
+C<-P> option.
+
+=item -C <username>:<password>
+
+Provide credentials for documents that are protected by Basic
+Authentication.  If the document is protected and you did not specify
+the username and password with this option, then you will be prompted
+to provide these values.
+
+=back
+
+The following options controls what is displayed by the program:
+
+=over 4
+
+=item -u
+
+Print request method and absolute URL as requests are made.
+
+=item -U
+
+Print request headers in addition to request method and absolute URL.
+
+=item -s
+
+Print response status code.  This option is always on for HEAD requests.
+
+=item -S
+
+Print response status chain. This shows redirect and autorization
+requests that are handled by the library.
+
+=item -e
+
+Print response headers.  This option is always on for HEAD requests.
+
+=item -d
+
+Do B<not> print the content of the response.
+
+=item -o <format>
+
+Process HTML content in various ways before printing it.  If the
+content type of the response is not HTML, then this option has no
+effect.  The legal format values are; I<text>, I<ps>, I<links>,
+I<html> and I<dump>.
+
+If you specify the I<text> format then the HTML will be formatted as
+plain latin1 text.  If you specify the I<ps> format then it will be
+formatted as Postscript.
+
+The I<links> format will output all links found in the HTML document.
+Relative links will be expanded to absolute ones.
+
+The I<html> format will reformat the HTML code and the I<dump> format
+will just dump the HTML syntax tree.
+
+=item -v
+
+Print the version number of the program and quit.
+
+=item -h
+
+Print usage message and quit.
+
+=item -x
+
+Extra debugging output.
+
+=item -a
+
+Set text(ascii) mode for content input and output.  If this option is not 
+used, content input and output is done in binary mode.
+
+=back
+
+Because this program is implemented using the LWP library, it will
+only support the protocols that LWP supports.
+
+=head1 SEE ALSO
+
+L<lwp-mirror>, L<LWP>
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 AUTHOR
+
+Gisle Aas <aas@sn.no>
+
+=cut
+
+$progname = $0;
+$progname =~ s,.*/,,;  # use basename only
+$progname =~ s/\.\w*$//; # strip extension, if any
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+
+require LWP;
+require LWP::Debug;
+require URI::URL;
+
+use URI::Heuristic qw(uf_url);
+
+use HTTP::Status qw(status_message);
+use HTTP::Date qw(time2str str2time);
+
+
+# This table lists the methods that are allowed.  It should really be
+# a superset for all methods supported for every scheme that may be
+# supported by the library.  Currently it might be a bit too HTTP
+# specific.  You might use the -f option to force a method through.
+#
+# "" = No content in request, "C" = Needs content in request
+#
+%allowed_methods = (
+    GET        => "",
+    HEAD       => "",
+    POST       => "C",
+    PUT        => "C",
+    DELETE     => "",
+    TRACE      => "",
+    OPTIONS    => "",
+);
+
+
+# We make our own specialization of LWP::UserAgent that asks for
+# user/password if document is protected.
+{
+    package RequestAgent;
+    @ISA = qw(LWP::UserAgent);
+
+    sub new
+    { 
+	my $self = LWP::UserAgent::new(@_);
+	$self->agent("lwp-request/$main::VERSION");
+	$self;
+    }
+
+    sub get_basic_credentials
+    {
+	my($self, $realm, $uri) = @_;
+	if ($main::opt_C) {
+	    return split(':', $main::opt_C, 2);
+	} elsif (-t) {
+	    my $netloc = $uri->netloc;
+	    print "Enter username for $realm at $netloc: ";
+	    my $user = <STDIN>;
+	    chomp($user);
+	    return (undef, undef) unless length $user;
+	    print "Password: ";
+	    system("stty -echo");
+	    my $password = <STDIN>;
+	    system("stty echo");
+	    print "\n";  # because we disabled echo
+	    chomp($password);
+	    return ($user, $password);
+	} else {
+	    return (undef, undef)
+	}
+    }
+}
+
+$method = uc(lc($progname) eq "lwp-request" ? "GET" : $progname);
+
+# Parse command line
+use Getopt::Std;
+
+$opt_a = undef;  # content i/o in text(ascii) mode
+$opt_m = undef;  # set method
+$opt_f = undef;  # make request even if method is not in %allowed_methods
+$opt_b = undef;  # base url
+$opt_t = undef;  # timeout
+$opt_i = undef;  # if-modified-since
+$opt_c = undef;  # content type for POST
+$opt_C = undef;  # credidentials for basic authorization
+
+$opt_u = undef;  # display method, URL and headers of request
+$opt_U = undef;  # display request headers also
+$opt_s = undef;  # display status code
+$opt_S = undef;  # display whole chain of status codes
+$opt_e = undef;  # display response headers (default for HEAD)
+$opt_d = undef;  # don't display content
+
+$opt_h = undef;  # print usage
+$opt_v = undef;  # print version
+
+$opt_x = undef;  # extra debugging info
+$opt_p = undef;  # proxy URL
+$opt_P = undef;  # don't load proxy setting from environment
+
+$opt_o = undef;  # output format
+
+unless (getopts("axhvuUsSedPp:b:t:i:c:C:m:fo:")) {
+    usage();
+}
+
+if ($opt_v) {
+    require LWP;
+    my $DISTNAME = 'libwww-perl-' . LWP::Version();
+    die <<"EOT";
+This is lwp-request version $VERSION ($DISTNAME)
+
+Copyright 1995-1997, Gisle Aas.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+EOT
+}
+
+usage() if $opt_h || !@ARGV;
+
+LWP::Debug::level('+') if $opt_x;
+
+# Create the user agent object
+$ua = new RequestAgent;
+
+# Load proxy settings from *_proxy environment variables.
+$ua->env_proxy unless $opt_P;
+
+$method = uc($opt_m) if defined $opt_m;
+
+if ($opt_f) {
+    if ($opt_c) {
+        $allowed_methods{$method} = "C";  # force content
+    } else {
+        $allowed_methods{$method} = "";
+    }
+} elsif (!defined $allowed_methods{$method}) {
+    die "$progname: $method is not an allowed method\n";
+}
+
+if ($method eq "HEAD") {
+    $opt_s = 1;
+    $opt_e = 1 unless $opt_d;
+    $opt_d = 1;
+}
+
+if (defined $opt_t) {
+    $opt_t =~ /^(\d+)([smh])?/;
+    die "$progname: Illegal timeout value!\n" unless defined $1;
+    $timeout = $1;
+    $timeout *= 60   if ($2 eq "m");
+    $timeout *= 3600 if ($2 eq "h");
+    $ua->timeout($timeout);
+}
+
+if (defined $opt_i) {
+    if (-e $opt_i) {
+        $time = (stat _)[9];
+    } else {
+        $time = str2time($opt_i);
+        die "$progname: Illegal time syntax for -i option\n"
+            unless defined $time;
+    }
+    $opt_i = time2str($time);
+}
+
+$content = undef;
+if ($allowed_methods{$method} eq "C") {
+    # This request needs some content
+    unless (defined $opt_c) {
+        # set default content type
+        $opt_c = ($method eq "POST") ?
+              "application/x-www-form-urlencoded"
+            : "text/plain";
+    } else {
+        die "$progname: Illegal Content-type format\n"
+            unless $opt_c =~ m,^[\w\-]+/[\w\-]+(?:\s*;.*)?$,
+    }
+    print "Please enter content ($opt_c) to be ${method}ed:\n"
+        if -t;
+    binmode STDIN unless -t or $opt_a;
+    $content = join("", <STDIN>);
+} else {
+    die "$progname: Can't set Content-type for $method requests\n"
+        if defined $opt_c;
+}
+
+# Set up a request.  We will use the same request object for all URLs.
+$request = new HTTP::Request $method;
+$request->header('If-Modified-Since', $opt_i) if defined $opt_i;
+#$request->header('Accept', '*/*');
+if ($opt_c) { # will always be set for request that wants content
+    $request->header('Content-Type', $opt_c);
+    $request->header('Content-Length', length $content);  # Not really needed
+    $request->content($content);
+}
+
+
+$errors = 0;
+
+# Ok, now we perform the requests, one URL at a time
+while ($url = shift) {
+    # Create the URL object, but protect us against bad URLs
+    eval {
+	if ($url =~ /^\w+:/ || $opt_b) {  # is there any scheme specification
+	    $url = URI::URL->new($url, $opt_b);
+	} else {
+	    $url = uf_url($url);
+        }
+    };
+    if ($@) {
+	$@ =~ s/at\s+\S+\s+line\s\d+//;
+	print STDERR $@;
+	$errors++;
+	next;
+    }
+
+    $ua->proxy($url->scheme, $opt_p) if $opt_p;
+
+    # Send the request and get a response back from the server
+    $request->url($url);
+    $response = $ua->request($request);
+
+    if ($opt_u || $opt_U) {
+        my $url = $response->request->url->as_string;
+        print "$method $url\n";
+        print $response->request->headers_as_string, "\n" if $opt_U;
+    }
+
+    if ($opt_S) {
+	printResponseChain($response);
+    } elsif ($opt_s) {
+        print $response->status_line, "\n";
+    }
+
+    if ($opt_e) {
+        # Display headers
+        print $response->headers_as_string;
+        print "\n";  # separate headers and content
+    }
+
+    if ($response->is_success) {
+	unless ($opt_d) {
+	    if ($opt_o &&
+		$response->content_type eq 'text/html') {
+		require HTML::Parse;
+		my $html = HTML::Parse::parse_html($response->content);
+		{
+		    $opt_o eq 'ps' && do {
+			require HTML::FormatPS;
+			my $f = new HTML::FormatPS;
+			print $f->format($html);
+			last;
+		    };
+		    $opt_o eq 'text' && do {
+			require HTML::FormatText;
+			my $f = new HTML::FormatText;
+			print $f->format($html);
+			last;
+		    };
+		    $opt_o eq 'html' && do {
+			print $html->as_HTML;
+			last;
+		    };
+		    $opt_o eq 'links' && do {
+			my $base = $response->base;
+			for ( @{ $html->extract_links } ) {
+			    my($link, $elem) = @$_;
+			    my $tag = uc $elem->tag;
+			    $link = new URI::URL $link, $base;
+			    print "$tag\t", $link->abs->as_string, "\n";
+			}
+			last;
+		    };
+		    $opt_o eq 'dump' && do {
+			$html->dump;
+			last;
+		    };
+		    # It is bad to not notice this before now :-(
+		    die "Illegal -o option value ($opt_o)\n";
+		}
+	    } else {
+                binmode STDOUT unless $opt_a;
+		print $response->content;
+	    }
+	}
+    } else {
+        print STDERR $response->error_as_HTML unless $opt_d;
+        $errors++;
+    }
+}
+
+exit $errors;
+
+
+sub printResponseChain
+{
+    my($response) = @_;
+    return unless defined $response;
+    printResponseChain($response->previous);
+    my $method = $response->request->method;
+    my $url = $response->request->url->as_string;
+    my $code = $response->code;
+    print "$method $url --> ", $response->status_line, "\n";
+}
+
+
+sub usage
+{
+    die <<"EOT";
+Usage: $progname [-options] <url>...
+    -m <method>   use method for the request (default is '$method')
+    -f            make request even if $progname believes method is illegal
+    -b <base>     Use the specified URL as base
+    -t <timeout>  Set timeout value
+    -i <time>     Set the If-Modified-Since header on the request
+    -c <conttype> use this content-type for POST, PUT, CHECKIN
+    -a            Use text mode for content I/O
+    -p <proxyurl> use this as a proxy
+    -P            don't load proxy settings from environment
+
+    -u            Display method and URL before any response
+    -U            Display request headers (implies -u)
+    -s            Display response status code
+    -S            Display response status chain
+    -e            Display response headers
+    -d            Do not display content
+    -o <format>   Process HTML content in various ways
+
+    -v            Show program version
+    -h            Print this message
+
+    -x            Extra debugging output
+EOT
+}
+!NO!SUBS!
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-rget.PL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-rget.PL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/bin/lwp-rget.PL	(revision 10506)
@@ -0,0 +1,600 @@
+use Config;
+use File::Basename qw(basename dirname);
+chdir(dirname($0));
+($file = basename($0)) =~ s/\.PL$//;
+$file =~ s/\.pl$//
+	if ($Config{'osname'} eq 'VMS' or
+	    $Config{'osname'} eq 'OS2');  # "case-forgiving"
+open OUT,">$file" or die "Can't create $file: $!";
+chmod(0755, $file);
+print "Extracting $file (with variable substitutions)\n";
+
+print OUT <<"!GROK!THIS!";
+$Config{'startperl'} -w
+
+!GROK!THIS!
+
+print OUT <<'!NO!SUBS!';
+#line 18
+
+=head1 NAME
+
+lwp-rget - Retrieve WWW documents recursively
+
+=head1 SYNOPSIS
+
+ lwp-rget [--verbose] [--auth=USER:PASS] [--depth=N] [--hier] [--iis]
+	  [--keepext=mime/type[,mime/type]] [--limit=N] [--nospace]
+	  [--prefix=URL] [--sleep=N] [--tolower] <URL>
+ lwp-rget --version
+
+=head1 DESCRIPTION
+
+This program will retrieve a document and store it in a local file.  It
+will follow any links found in the document and store these documents
+as well, patching links so that they refer to these local copies.
+This process continues until there are no more unvisited links or the
+process is stopped by the one or more of the limits which can be
+controlled by the command line arguments.
+
+This program is useful if you want to make a local copy of a
+collection of documents or want to do web reading off-line.
+
+All documents are stored as plain files in the current directory. The
+file names chosen are derived from the last component of URL paths.
+
+The options are:
+
+=over 3
+
+=item --auth=USER:PASS<n>
+
+Set the authentication credentials to user "USER" and password "PASS" if
+any restricted parts of the web site are hit.  If there are restricted
+parts of the web site and authentication credentials are not available,
+those pages will not be downloaded.
+
+=item --depth=I<n>
+
+Limit the recursive level. Embedded images are always loaded, even if
+they fall outside the I<--depth>. This means that one can use
+I<--depth=0> in order to fetch a single document together with all
+inline graphics.
+
+The default depth is 5.
+
+=item --hier
+
+Download files into a hierarchy that mimics the web site structure.
+The default is to put all files in the current directory.
+
+=item --iis
+
+Sends an "Accept: */*" on all URL requests as a workaround for a bug in
+IIS 2.0.  If no Accept MIME header is present, IIS 2.0 returns with a
+"406 No acceptable objects were found" error.  Also converts any back
+slashes (\\) in URLs to forward slashes (/).
+
+=item --keepext=I<mime/type[,mime/type]>
+
+Keeps the current extension for the list MIME types.  Useful when
+downloading text/plain documents that shouldn't all be translated to
+*.txt files.
+
+=item --limit=I<n>
+
+Limit the number of documents to get.  The default limit is 50.
+
+=item --nospace
+
+Changes spaces in all URLs to underscore characters (_).  Useful when
+downloading files from sites serving URLs with spaces in them.	Does not
+remove spaces from fragments, e.g., "file.html#somewhere in here".
+
+=item --prefix=I<url_prefix>
+
+Limit the links to follow. Only URLs that start the prefix string are
+followed.
+
+The default prefix is set as the "directory" of the initial URL to
+follow.	 For instance if we start lwp-rget with the URL
+C<http://www.sn.no/foo/bar.html>, then prefix will be set to
+C<http://www.sn.no/foo/>.
+
+Use C<--prefix=''> if you don't want the fetching to be limited by any
+prefix.
+
+=item --sleep=I<n>
+
+Sleep I<n> seconds before retrieving each document. This options allows
+you to go slowly, not loading the server you visiting too much.
+
+=item --tolower
+
+Translates all links to lowercase.  Useful when downloading files from
+IIS since it does not serve files in a case sensitive manner.
+
+=item --verbose
+
+Make more noise while running.
+
+=item --quiet
+
+Don't make any noise.
+
+=item --version
+
+Print program version number and quit.
+
+=item --help
+
+Print the usage message and quit.
+
+=back
+
+Before the program exits the name of the file, where the initial URL
+is stored, is printed on stdout.  All used filenames are also printed
+on stderr as they are loaded.  This printing can be suppressed with
+the I<--quiet> option.
+
+=head1 SEE ALSO
+
+L<lwp-request>, L<LWP>
+
+=head1 AUTHOR
+
+Gisle Aas <aas@sn.no>
+
+=cut
+
+use strict;
+
+use Getopt::Long    qw(GetOptions);
+use URI::URL	    qw(url);
+use LWP::MediaTypes qw(media_suffix);
+
+use vars qw($VERSION);
+use vars qw($MAX_DEPTH $MAX_DOCS $PREFIX $VERBOSE $QUIET $SLEEP $HIER $AUTH $IIS $TOLOWER $NOSPACE %KEEPEXT);
+
+my $progname = $0;
+$progname =~ s|.*/||;  # only basename left
+$progname =~ s/\.\w*$//; #strip extension if any
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+#$Getopt::Long::debug = 1;
+#$Getopt::Long::ignorecase = 0;
+
+# Defaults
+$MAX_DEPTH = 5;
+$MAX_DOCS  = 50;
+
+GetOptions('version'  => \&print_version,
+	   'help'     => \&usage,
+	   'depth=i'  => \$MAX_DEPTH,
+	   'limit=i'  => \$MAX_DOCS,
+	   'verbose!' => \$VERBOSE,
+	   'quiet!'   => \$QUIET,
+	   'sleep=i'  => \$SLEEP,
+	   'prefix:s' => \$PREFIX,
+	   'hier'     => \$HIER,
+	   'auth=s'   => \$AUTH,
+	   'iis'      => \$IIS,
+	   'tolower'  => \$TOLOWER,
+	   'nospace'  => \$NOSPACE,
+	   'keepext=s' => \$KEEPEXT{'OPT'},
+	  ) || usage();
+
+sub print_version {
+    require LWP;
+    my $DISTNAME = 'libwww-perl-' . LWP::Version();
+    print <<"EOT";
+This is lwp-rget version $VERSION ($DISTNAME)
+
+Copyright 1996-1998, Gisle Aas.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+EOT
+    exit 0;
+}
+
+my $start_url = shift || usage();
+usage() if @ARGV;
+
+require LWP::UserAgent;
+my $ua = new LWP::UserAgent;
+$ua->agent("$progname/$VERSION " . $ua->agent);
+$ua->env_proxy;
+
+unless (defined $PREFIX) {
+    $PREFIX = url($start_url);	 # limit to URLs below this one
+    eval {
+	$PREFIX->eparams(undef);
+	$PREFIX->equery(undef);
+    };
+
+    $_ = $PREFIX->epath;
+    s|[^/]+$||;
+    $PREFIX->epath($_);
+    $PREFIX = $PREFIX->as_string;
+}
+
+%KEEPEXT = map { lc($_) => 1 } split(/\s*,\s*/, $KEEPEXT{'OPT'});
+
+print <<"" if $VERBOSE;
+START	  = $start_url
+MAX_DEPTH = $MAX_DEPTH
+MAX_DOCS  = $MAX_DOCS
+PREFIX	  = $PREFIX
+
+
+my $no_docs = 0;
+my %seen = ();	   # mapping from URL => local_file
+
+my $filename = fetch($start_url);
+print "$filename\n" unless $QUIET;
+
+sub fetch
+{
+    my($url, $type, $depth) = @_;
+
+    # Fix http://sitename.com/../blah/blah.html to
+    #	  http://sitename.com/blah/blah.html
+    $url = $url->as_string if (ref($url));
+    while ($url =~ s#(https?://[^/]+/)\.\.\/#$1#) {}
+
+    # Fix backslashes (\) in URL if $IIS defined
+    $url = fix_backslashes($url) if (defined $IIS);
+
+    $url = url($url) unless ref($url);
+    $type  ||= 'a';
+    # Might be the background attribute
+    $type = 'img' if ($type eq 'body' || $type eq 'td');
+    $depth ||= 0;
+
+    # Print the URL before we start checking...
+    my $out = (" " x $depth) . $url . " ";
+    $out .= "." x (60 - length($out));
+    print STDERR $out . " " if $VERBOSE;
+
+    # Can't get mailto things
+    if ($url->scheme eq 'mailto') {
+	print STDERR "*skipping mailto*\n" if $VERBOSE;
+	return $url->as_string;
+    }
+
+    # The $plain_url is a URL without the fragment part
+    my $plain_url = $url->clone;
+    $plain_url->frag(undef);
+
+    # Check PREFIX, but not for <IMG ...> links
+    if ($type ne 'img' and  $url->as_string !~ /^\Q$PREFIX/o) {
+	print STDERR "*outsider*\n" if $VERBOSE;
+	return $url->as_string;
+    }
+
+    # Translate URL to lowercase if $TOLOWER defined
+    $plain_url = to_lower($plain_url) if (defined $TOLOWER);
+
+    # If we already have it, then there is nothing to be done
+    my $seen = $seen{$plain_url->as_string};
+    if ($seen) {
+	my $frag = $url->frag;
+	$seen .= "#$frag" if defined($frag);
+	$seen = protect_frag_spaces($seen);
+	print STDERR "$seen (again)\n" if $VERBOSE;
+	return $seen;
+    }
+
+    # Too much or too deep
+    if ($depth > $MAX_DEPTH and $type ne 'img') {
+	print STDERR "*too deep*\n" if $VERBOSE;
+	return $url;
+    }
+    if ($no_docs > $MAX_DOCS) {
+	print STDERR "*too many*\n" if $VERBOSE;
+	return $url;
+    }
+
+    # Fetch document 
+    $no_docs++;
+    sleep($SLEEP) if $SLEEP;
+    my $req = HTTP::Request->new(GET => $url);
+    # See: http://ftp.sunet.se/pub/NT/mirror-microsoft/kb/Q163/7/74.TXT
+    $req->header ('Accept', '*/*') if (defined $IIS);  # GIF/JPG from IIS 2.0
+    $req->authorization_basic(split (/:/, $AUTH)) if (defined $AUTH);
+    my $res = $ua->request($req);
+
+    # Check outcome
+    if ($res->is_success) {
+	my $doc = $res->content;
+	my $ct = $res->content_type;
+	my $name = find_name($res->request->url, $ct);
+	print STDERR "$name\n" unless $QUIET;
+	$seen{$plain_url->as_string} = $name;
+
+	# If the file is HTML, then we look for internal links
+	if ($ct eq "text/html") {
+	    # Save an unprosessed version of the HTML document.	 This
+	    # both reserves the name used, and it also ensures that we
+	    # don't loose everything if this program is killed before
+	    # we finish.
+	    save($name, $doc);
+	    my $base = $res->base;
+
+	    # Follow and substitute links...
+	    $doc =~
+s/
+  (
+    <(img|a|body|area|frame|td)\b   # some interesting tag
+    [^>]+			    # still inside tag (not strictly correct)
+    \b(?:src|href|background)	    # some link attribute
+    \s*=\s*			    # =
+  )
+    (?:				    # scope of OR-ing
+	 (")([^"]*)"	|	    # value in double quotes  OR
+	 (')([^']*)'	|	    # value in single quotes  OR
+	    ([^\s>]+)		    # quoteless value
+    )
+/
+  new_link($1, lc($2), $3||$5, $4||$6||$7, $base, $name, $depth+1)
+/giex;
+	   # XXX
+	   # The regular expression above is not strictly correct.
+	   # It is not really possible to parse HTML with a single
+	   # regular expression, but it is faster.  Tags that might
+	   # confuse us include:
+	   #	<a alt="href" href=link.html>
+	   #	<a alt=">" href="link.html">
+	   #
+	}
+	save($name, $doc);
+	return $name;
+    } else {
+	print STDERR $res->code . " " . $res->message . "\n" if $VERBOSE;
+	$seen{$plain_url->as_string} = $url->as_string;
+	return $url->as_string;
+    }
+}
+
+sub new_link
+{
+    my($pre, $type, $quote, $url, $base, $localbase, $depth) = @_;
+
+    $url = protect_frag_spaces($url);
+
+    $url = fetch(url($url, $base)->abs, $type, $depth);
+    $url = url("file:$url", "file:$localbase")->rel
+	unless $url =~ /^[.+\-\w]+:/;
+
+    $url = unprotect_frag_spaces($url);
+
+    return $pre . $quote . $url . $quote;
+}
+
+
+sub protect_frag_spaces
+{
+    my ($url) = @_;
+
+    $url = $url->as_string if (ref($url));
+
+    if ($url =~ m/^([^#]*#)(.+)$/)
+    {
+      my ($base, $frag) = ($1, $2);
+      $frag =~ s/ /%20/g;
+      $url = $base . $frag;
+    }
+
+    return $url;
+}
+
+
+sub unprotect_frag_spaces
+{
+    my ($url) = @_;
+
+    $url = $url->as_string if (ref($url));
+
+    if ($url =~ m/^([^#]*#)(.+)$/)
+    {
+      my ($base, $frag) = ($1, $2);
+      $frag =~ s/%20/ /g;
+      $url = $base . $frag;
+    }
+
+    return $url;
+}
+
+
+sub fix_backslashes
+{
+    my ($url) = @_;
+    my ($base, $frag);
+
+    $url = $url->as_string if (ref($url));
+
+    if ($url =~ m/([^#]+)(#.*)/)
+    {
+      ($base, $frag) = ($1, $2);
+    }
+    else
+    {
+      $base = $url;
+      $frag = "";
+    }
+
+    $base =~ tr/\\/\//;
+    $base =~ s/%5[cC]/\//g;	# URL-encoded back slash is %5C
+
+    return $base . $frag;
+}
+
+
+sub to_lower
+{
+    my ($url) = @_;
+    my $was_object = 0;
+
+    if (ref($url))
+    {
+      $url = $url->as_string;
+      $was_object = 1;
+    }
+
+    if ($url =~ m/([^#]+)(#.*)/)
+    {
+      $url = lc($1) . $2;
+    }
+    else
+    {
+      $url = lc($url);
+    }
+
+    if ($was_object == 1)
+    {
+      return url($url);
+    }
+    else
+    {
+      return $url;
+    }
+}
+
+
+sub translate_spaces
+{
+    my ($url) = @_;
+    my ($base, $frag);
+
+    $url = $url->as_string if (ref($url));
+
+    if ($url =~ m/([^#]+)(#.*)/)
+    {
+      ($base, $frag) = ($1, $2);
+    }
+    else
+    {
+      $base = $url;
+      $frag = "";
+    }
+
+    $base =~ s/^ *//;	# Remove initial spaces from base
+    $base =~ s/ *$//;	# Remove trailing spaces from base
+
+    $base =~ tr/ /_/;
+    $base =~ s/%20/_/g; # URL-encoded space is %20
+
+    return $base . $frag;
+}
+
+
+sub mkdirp
+{
+    my($directory, $mode) = @_;
+    my @dirs = split(/\//, $directory);
+    my $path = shift(@dirs);   # build it as we go
+    my $result = 1;   # assume it will work
+
+    unless (-d $path) {
+	$result &&= mkdir($path, $mode);
+    }
+
+    foreach (@dirs) {
+	$path .= "/$_";
+	if ( ! -d $path) {
+	    $result &&= mkdir($path, $mode);
+	}
+    }
+
+    return $result;
+}
+
+
+sub find_name
+{
+    my($url, $type) = @_;
+    #print "find_name($url, $type)\n";
+
+    # Translate spaces in URL to underscores (_) if $NOSPACE defined
+    $url = translate_spaces($url) if (defined $NOSPACE);
+
+    # Translate URL to lowercase if $TOLOWER defined
+    $url = to_lower($url) if (defined $TOLOWER);
+
+    $url = url($url) unless ref($url);
+
+    my $path = $url->path;
+
+    # trim path until only the basename is left
+    $path =~ s|(.*/)||;
+    my $dirname = ".$1";
+    if (!$HIER) {
+	$dirname = "";
+    } elsif (! -d $dirname) {
+	mkdirp($dirname, 0775);
+    }
+
+    my $extra = "";  # something to make the name unique
+    my $suffix;
+
+    if ($KEEPEXT{lc($type)}) {
+        $suffix = ($path =~ m/\.(.*)/) ? $1 : "";
+    } else {
+        $suffix = media_suffix($type);
+    }
+
+    $path =~ s|\..*||;	# trim suffix
+    $path = "index" unless length $path;
+
+    while (1) {
+	# Construct a new file name
+	my $file = $dirname . $path . $extra;
+	$file .= ".$suffix" if $suffix;
+	# Check if it is unique
+	return $file unless -f $file;
+
+	# Try something extra
+	unless ($extra) {
+	    $extra = "001";
+	    next;
+	}
+	$extra++;
+    }
+}
+
+
+sub save
+{
+    my $name = shift;
+    #print "save($name,...)\n";
+    open(FILE, ">$name") || die "Can't save $name: $!";
+    binmode FILE;
+    print FILE $_[0];
+    close(FILE);
+}
+
+
+sub usage
+{
+    die <<"";
+Usage: $progname [options] <URL>
+Allowed options are:
+  --auth=USER:PASS  Set authentication credentials for web site
+  --depth=N	    Maximum depth to traverse (default is $MAX_DEPTH)
+  --hier	    Download into hierarchy (not all files into cwd)
+  --iis		    Workaround IIS 2.0 bug by sending "Accept: */*" MIME
+		    header; translates backslashes (\\) to forward slashes (/)
+  --keepext=type    Keep file extension for MIME types (comma-separated list)
+  --limit=N	    A limit on the number documents to get (default is $MAX_DOCS)
+  --nospace	    Translate spaces URLs (not #fragments) to underscores (_)
+  --version	    Print version number and quit
+  --verbose	    More output
+  --quiet	    No output
+  --sleep=SECS	    Sleep between gets, ie. go slowly
+  --prefix=PREFIX   Limit URLs to follow to those which begin with PREFIX
+  --tolower	    Translate all URLs to lowercase (useful with IIS servers)
+
+}
+!NO!SUBS!
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/install.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/install.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/install.sh	(revision 10506)
@@ -0,0 +1,10 @@
+#!/bin/sh -v
+
+export PERL5LIB=$GSDLHOME/perllib/cpan/lib:$PERL5LIB
+export PATH=$GSDLHOME/perllib/cpan/bin:$PATH
+
+perl Makefile.PL PREFIX=$GSDLHOME/perllib/cpan
+
+make
+make test
+make install
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/Bundle/LWP.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/Bundle/LWP.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/Bundle/LWP.pm	(revision 10506)
@@ -0,0 +1,38 @@
+package Bundle::LWP;
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bundle::LWP - A bundle to install all libwww-perl related modules
+
+=head1 SYNOPSIS
+
+ perl -MCPAN -e 'install Bundle::LWP'
+
+=head1 CONTENTS
+
+Net::FTP 2.00      - If you want ftp://-support
+
+MIME::Base64       - Used in authentication headers
+
+MD5                - Needed to do Digest authentication
+
+HTML::HeadParser   - To get the correct $res->base
+
+LWP                - The reason why you need the modules above
+
+=head1 DESCRIPTION
+
+This bundle defines all reqreq modules for libwww-perl.
+
+
+=head1 AUTHOR
+
+Gisle Aas E<lt>aas@sn.no>
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/File/Listing.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/File/Listing.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/File/Listing.pm	(revision 10506)
@@ -0,0 +1,314 @@
+#
+# $Id$
+
+package File::Listing;
+
+sub Version { $VERSION; }
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+=head1 NAME
+
+parse_dir - parse directory listing
+
+=head1 SYNOPSIS
+
+ use File::Listing;
+ for (parse_dir(`ls -l`)) {
+     ($name, $type, $size, $mtime, $mode) = @$_;
+     next if $type ne 'f'; # plain file
+     #...
+ }
+
+ # directory listing can also be read from a file
+ open(LISTING, "zcat ls-lR.gz|");
+ $dir = parse_dir(\*LISTING, '+0000');
+
+=head1 DESCRIPTION
+
+The parse_dir() routine can be used to parse directory
+listings. Currently it only understand Unix C<'ls -l'> and C<'ls -lR'>
+format.  It should eventually be able to most things you might get
+back from a ftp server file listing (LIST command), i.e. VMS listings,
+NT listings, DOS listings,...
+
+The first parameter to parse_dir() is the directory listing to parse.
+It can be a scalar, a reference to an array of directory lines or a
+glob representing a filehandle to read the directory listing from.
+
+The second parameter is the time zone to use when parsing time stamps
+in the listing. If this value is undefined, then the local time zone is
+assumed.
+
+The third parameter is the type of listing to assume.  The values will
+be strings like 'unix', 'vms', 'dos'.  Currently only 'unix' is
+implemented and this is also the default value.  Ideally, the listing
+type should be determined automatically.
+
+The fourth parameter specify how unparseable lines should be treated.
+Values can be 'ignore', 'warn' or a code reference.  Warn means that
+the perl warn() function will be called.  If a code reference is
+passed, then this routine will be called and the return value from it
+will be incorporated in the listing.  The default is 'ignore'.
+
+Only the first parameter is mandatory.  The parse_dir() prototype is
+($;$$$).
+
+The return value from parse_dir() is a list of directory entries.  In
+scalar context the return value is a reference to the list.  The
+directory entries are represented by an array consisting of [
+$filename, $filetype, $filesize, $filetime, $filemode ].  The
+$filetype value is one of the letters 'f', 'd', 'l' or '?'.  The
+$filetime value is converted to seconds since Jan 1, 1970.  The
+$filemode is a bitmask like the mode returned by stat().
+
+=head1 CREDITS
+
+Based on lsparse.pl (from Lee McLoughlin's ftp mirror package) and
+Net::FTP's parse_dir (Graham Barr).
+
+=cut
+
+require Exporter;
+@ISA = qw(Exporter);
+
+@EXPORT = qw(parse_dir);
+
+use strict;
+
+use Carp ();
+use HTTP::Date qw(str2time);
+
+sub parse_dir ($;$$$)
+{
+   my($dir, $tz, $fstype, $error) = @_;
+
+   $fstype ||= 'unix';
+   $fstype = "File::Listing::" . lc $fstype;
+
+   my @args = $_[0];
+   push(@args, $tz) if(@_ >= 2);
+   push(@args, $error) if(@_ >= 4);
+
+   $fstype->parse(@args);
+}
+
+sub line { Carp::croak("Not implemented yet"); }
+sub init { } # Dummy sub
+
+sub file_mode ($)
+{
+    # This routine was originally borrowed from Graham Barr's
+    # Net::FTP package.
+
+    local $_ = shift;
+    my $mode = 0;
+    my($type,$ch);
+
+    s/^(.)// and $type = $1;
+
+    while (/(.)/g) {
+	$mode <<= 1;
+	$mode |= 1 if $1 ne "-" &&
+		      $1 ne 'S' &&
+		      $1 ne 't' &&
+		      $1 ne 'T';
+    }
+
+    $type eq "d" and $mode |= 0040000 or	# Directory
+      $type eq "l" and $mode |= 0120000 or	# Symbolic Link
+	$mode |= 0100000;			# Regular File
+
+    $mode |= 0004000 if /^...s....../i;
+    $mode |= 0002000 if /^......s.../i;
+    $mode |= 0001000 if /^.........t/i;
+
+    $mode;
+}
+
+sub parse
+{
+   my($pkg, $dir, $tz, $error) = @_;
+
+   # First let's try to determine what kind of dir parameter we have
+   # received.  We allow both listings, reference to arrays and
+   # file handles to read from.
+
+   if (ref($dir) eq 'ARRAY') {
+       # Already splitted up
+   } elsif (ref($dir) eq 'GLOB') {
+       # A file handle
+   } elsif (ref($dir)) {
+      Carp::croak("Illegal argument to parse_dir()");
+   } elsif ($dir =~ /^\*\w+(::\w+)+$/) {
+      # This scalar looks like a file handle, so we assume it is
+   } else {
+      # A normal scalar listing
+      $dir = [ split(/\n/, $dir) ];
+   }
+
+   $pkg->init();
+
+   my @files = ();
+   if (ref($dir) eq 'ARRAY') {
+       for (@$dir) {
+	   push(@files, $pkg->line($_, $tz, $error));
+       }
+   } else {
+       local($_);
+       while (<$dir>) {
+	   chomp;
+	   push(@files, $pkg->line($_, $tz, $error));
+       }
+   }
+   wantarray ? @files : \@files;
+}
+
+
+package File::Listing::unix;
+
+use HTTP::Date qw(str2time);
+
+# A place to remember current directory from last line parsed.
+use vars qw($curdir);
+no strict qw(vars);
+
+@ISA = qw(File::Listing);
+
+
+sub init
+{
+    $curdir = '';
+}
+
+sub line
+{
+    shift; # package name
+    local($_) = shift;
+    my($tz, $error) = @_;
+
+    s/\015//g;
+    #study;
+
+    my ($kind, $size, $date, $name);
+    if (($kind, $size, $date, $name) =
+	/^([\-FlrwxsStTdD]{10})                   # Type and permission bits
+	 .*                                       # Graps
+	 \D(\d+)                                  # File size
+	 \s+                                      # Some space
+	 (\w{3}\s+\d+\s+(?:\d{1,2}:\d{2}|\d{4}))  # Date
+	 \s+                                      # Some more space
+	 (.*)$                                    # File name
+	/x )
+
+    {
+	return if $name eq '.' || $name eq '..';
+	$name = "$curdir/$name" if length $curdir;
+	my $type = '?';
+	if ($kind =~ /^l/ && $name =~ /(.*) -> (.*)/ ) {
+	    $name = $1;
+	    $type = "l $2";
+	} elsif ($kind =~ /^[\-F]/) { # (hopefully) a regular file
+	    $type = 'f';
+	} elsif ($kind =~ /^[dD]/) {
+	    $type = 'd';
+	    $size = undef;  # Don't believe the reported size
+	}
+	return [$name, $type, $size, str2time($date, $tz), 
+              File::Listing::file_mode($kind)];
+
+    } elsif (/^(.+):$/ && !/^[dcbsp].*\s.*\s.*:$/ ) {
+	my $dir = $1;
+	return () if $dir eq '.';
+	$curdir = $dir;
+	return ();
+    } elsif (/^[Tt]otal\s+(\d+)$/ || /^\s*$/) {
+	return ();
+    } elsif (/not found/    || # OSF1, HPUX, and SunOS return
+             # "$file not found"
+             /No such file/ || # IRIX returns
+             # "UX:ls: ERROR: Cannot access $file: No such file or directory"
+                               # Solaris returns
+             # "$file: No such file or directory"
+             /cannot find/     # Windows NT returns
+             # "The system cannot find the path specified."
+             ) {
+	return () unless defined $error;
+	&$error($_) if ref($error) eq 'CODE';
+	warn "Error: $_\n" if $error eq 'warn';
+	return ();
+    } elsif ($_ eq '') {       # AIX, and Linux return nothing
+	return () unless defined $error;
+	&$error("No such file or directory") if ref($error) eq 'CODE';
+	warn "Warning: No such file or directory\n" if $error eq 'warn';
+	return ();
+    } else {
+        # parse failed, check if the dosftp parse understands it
+        return(File::Listing::dosftp->line($_,$tz,$error));
+    }
+
+}
+
+package File::Listing::dosftp;
+
+use HTTP::Date qw(str2time);
+
+# A place to remember current directory from last line parsed.
+use vars qw($curdir);
+no strict qw(vars);
+
+@ISA = qw(File::Listing);
+
+sub init
+{
+    $curdir = '';
+}
+
+sub line
+{
+    shift; # package name
+    local($_) = shift;
+    my($tz, $error) = @_;
+
+    s/\015//g;
+
+    my ($kind, $size, $date, $name);
+
+    # 02-05-96  10:48AM                 1415 src.slf
+    # 09-10-96  09:18AM       <DIR>          sl_util
+    if (($date,$size_or_dir,$name) =
+        /^(\d\d-\d\d-\d\d\s+\d\d:\d\d\wM)         # Date and time info
+         \s+                                      # Some space
+         (<\w{3}>|\d+)                            # Dir or Size
+         \s+                                      # Some more space
+         (.+)$                                    # File name
+        /x )
+    {
+	return if $name eq '.' || $name eq '..';
+	$name = "$curdir/$name" if length $curdir;
+	my $type = '?';
+	if ($size_or_dir eq '<DIR>') {
+	    $type = "d";
+            $size = ""; # directories have no size in the pc listing
+        } else {
+	    $type = 'f';
+            $size = $size_or_dir;
+	}
+	return [$name, $type, $size, str2time($date, $tz),
+              File::Listing::file_mode($kind)];
+
+    } else {
+	return () unless defined $error;
+	&$error($_) if ref($error) eq 'CODE';
+	warn "Can't parse: $_\n" if $error eq 'warn';
+	return ();
+    }
+
+}
+
+package File::Listing::vms;
+@File::Listing::unix::ISA = qw(File::Listing);
+
+package File::Listing::netware;
+@File::Listing::unix::ISA = qw(File::Listing);
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Cookies.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Cookies.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Cookies.pm	(revision 10506)
@@ -0,0 +1,725 @@
+package HTTP::Cookies;
+
+# Based on draft-ietf-http-state-man-mec-08.txt and
+# http://www.netscape.com/newsref/std/cookie_spec.html
+
+use strict;
+use HTTP::Date qw(str2time time2str);
+use HTTP::Headers::Util qw(split_header_words join_header_words);
+use LWP::Debug ();
+
+use vars qw($VERSION);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+=head1 NAME
+
+HTTP::Cookies - Cookie storage and management
+
+=head1 SYNOPSIS
+
+ use HTTP::Cookies;
+ $cookie_jar = HTTP::Cookies->new;
+
+ $cookie_jar->add_cookie_header($request);
+ $cookie_jar->extract_cookies($response);
+
+=head1 DESCRIPTION
+
+Cookies are a general mechanism which server side connections can use
+to both store and retrieve information on the client side of the
+connection.  For more information about cookies referrer to
+<URL:http://www.netscape.com/newsref/std/cookie_spec.html> and
+<URL:http://www.cookiecentral.com/>.  This module also implements the
+new style cookies as described in I<draft-ietf-http-state-man-mec-08.txt>.
+The two variants of cookies is supposed to be able to coexist happily.
+
+Instances of the class I<HTTP::Cookies> are able to store a collection
+of Set-Cookie2: and Set-Cookie:-headers and is able to use this
+information to initialize Cookie-headers in I<HTTP::Request> objects.
+The state of the I<HTTP::Cookies> can be saved and restored from
+files.
+
+=head1 METHODS
+
+The following methods are provided:
+
+=over 4
+
+=cut
+
+# A HTTP::Cookies object is a hash.  The main attribute is the
+# COOKIES 3 level hash:  $self->{COOKIES}{$domain}{$path}{$key}.
+
+
+=item $cookie_jar = HTTP::Cookies->new;
+
+The constructor.  Takes hash style parameters.  The following
+parameters are recognized:
+
+  file:            name of the file to restore and save cookies to
+  autosave:        should we save during destruction (bool)
+  ignore_discard:  save even cookies that are requested to be discarded (bool)
+
+Future parameters might include (not yet implemented):
+
+  max_cookies               300
+  max_cookies_per_domain    20
+  max_cookie_size           4096
+
+  no_cookies   list of domain names that we never return cookies to
+
+=cut
+
+sub new
+{
+    my $class = shift;
+    my $self = bless {
+	COOKIES => {},
+    }, $class;
+    my %cnf = @_;
+    for (keys %cnf) {
+	$self->{lc($_)} = $cnf{$_};
+    }
+    $self->load;
+    $self;
+}
+
+
+=item $cookie_jar->add_cookie_header($request);
+
+The add_cookie_header() method will set the appropriate Cookie:-header
+for the I<HTTP::Request> object given as argument.  The $request must
+have a valid url() attribute before this method is called.
+
+=cut
+
+sub add_cookie_header
+{
+    my $self = shift;
+    my $request = shift || return;
+    my $url = $request->url;
+    my $domain = $url->host;
+    $domain = "$domain.local" unless $domain =~ /\./;
+    my $secure_request = ($url->scheme eq "https");
+    my $req_path = $url->epath;
+    my $req_port = $url->port;
+    my $now = time();
+    $self->_normalize_path($req_path) if $req_path =~ /%/;
+
+    my @cval;    # cookie values for the "Cookie" header
+    my $set_ver;
+
+    while (($domain =~ tr/././) >= 2 || # must be at least 2 dots
+           $domain =~ /\.local$/)
+    {
+
+        LWP::Debug::debug("Checking $domain for cookies");
+	my $cookies = $self->{COOKIES}{$domain};
+	next unless $cookies;
+
+	# Want to add cookies corresponding to the most specific paths
+	# first (i.e. longest path first)
+	my $path;
+	for $path (sort {length($b) <=> length($a) } keys %$cookies) {
+            LWP::Debug::debug("- checking cookie path=$path");
+	    if (index($req_path, $path) != 0) {
+	        LWP::Debug::debug("  path $path:$req_path does not fit");
+		next;
+	    }
+
+	    my($key,$array);
+	    while (($key,$array) = each %{$cookies->{$path}}) {
+		my($version,$val,$port,$path_spec,$secure,$expires) = @$array;
+	        LWP::Debug::debug(" - checking cookie $key=$val");
+		if ($secure && !$secure_request) {
+		    LWP::Debug::debug("   not a secure requests");
+		    next;
+		}
+		if ($expires && $expires < $now) {
+		    LWP::Debug::debug("   expired");
+		    next;
+		}
+		if ($port) {
+		    my $found;
+		    if ($port =~ s/^_//) {
+			# The correponding Set-Cookie attribute was empty
+			$found++ if $port eq $req_port;
+			$port = "";
+		    } else {
+			my $p;
+			for $p (split(/,/, $port)) {
+			    $found++, last if $p eq $req_port;
+			}
+		    }
+		    unless ($found) {
+		        LWP::Debug::debug("   port $port:$req_port does not fit");
+			next;
+		    }
+		}
+	        LWP::Debug::debug("   it's a match");
+
+		# set version number of cookie header.
+	        # XXX: What should it be if multiple matching
+                #      Set-Cookie headers have different versions themselves
+		if (!$set_ver++) {
+		    if ($version >= 1) {
+			push(@cval, "\$Version=$version");
+		    } else {
+			$request->header(Cookie2 => "\$Version=1");
+		    }
+		}
+
+		# do we need to quote the value
+		if ($val =~ /\W/ && $version) {
+		    $val =~ s/([\\\"])/\\$1/g;
+		    $val = qq("$val");
+		}
+
+		# and finally remember this cookie
+		push(@cval, "$key=$val");
+		if ($version >= 1) {
+		    push(@cval, qq(\$Path="$path"))     if $path_spec;
+		    push(@cval, qq(\$Domain="$domain")) if $domain =~ /^\./;
+		    if (defined $port) {
+			my $p = '$Port';
+			$p .= qq(="$port") if length $port;
+			push(@cval, $p);
+		    }
+		}
+
+	    }
+        }
+
+    } continue {
+	# Try with a more general domain:  www.sol.no ==> .sol.no
+	$domain =~ s/^\.?[^.]*//;
+    }
+
+    $request->header(Cookie => join("; ", @cval)) if @cval;
+
+    $request;
+}
+
+
+=item $cookie_jar->extract_cookies($response);
+
+The extract_cookies() method will look for Set-Cookie: and
+Set-Cookie2:-headers in the I<HTTP::Response> object passed as
+argument.  If some of these headers are found they are used to update
+the state of the $cookie_jar.
+
+=cut
+
+sub extract_cookies
+{
+    my $self = shift;
+    my $response = shift || return;
+    my @set = split_header_words($response->_header("Set-Cookie2"));
+    my $netscape_cookies;
+    unless (@set) {
+	@set = $response->_header("Set-Cookie");
+	return $response unless @set;
+	$netscape_cookies++;
+    }
+
+    my $url = $response->request->url;
+    my $req_host = $url->host;
+    $req_host = "$req_host.local" unless $req_host =~ /\./;
+    my $req_port = $url->port;
+    my $req_path = $url->epath;
+    $self->_normalize_path($req_path) if $req_path =~ /%/;
+    
+    if ($netscape_cookies) {
+	# The old Netscape cookie format for Set-Cookie
+        # http://www.netscape.com/newsref/std/cookie_spec.html
+	# can for instance contain an unquoted "," in the expires
+	# field, so we have to use this ad-hoc parser.
+	my $now = time();
+	my @old = @set;
+	@set = ();
+	my $set;
+	for $set (@old) {
+	    my @cur;
+	    my $param;
+	    my $expires;
+	    for $param (split(/\s*;\s*/, $set)) {
+		my($k,$v) = split(/\s*=\s*/, $param, 2);
+		#print "$k => $v\n";
+		my $lc = lc($k);
+		if ($lc eq "expires") {
+		    push(@cur, "Max-Age" => str2time($v) - $now);
+		    $expires++;
+		} else {
+		    push(@cur, $k => $v);
+		}
+	    }
+	    push(@cur, "Port" => $req_port);
+	    push(@cur, "Discard" => undef) unless $expires;
+	    push(@cur, "Version" => 0);
+	    push(@set, \@cur);
+	}
+    }
+
+  SET_COOKIE:
+    for my $set (@set) {
+	next unless @$set >= 2;
+
+	my $key = shift @$set;
+	my $val = shift @$set;
+
+        LWP::Debug::debug("Set cookie $key => $val");
+
+	my %hash;
+	while (@$set) {
+	    my $k = shift @$set;
+	    my $v = shift @$set;
+	    my $lc = lc($k);
+	    # don't loose case distinction for unknown fields
+	    $k = $lc if $lc =~ /^(?:discard|domain|max-age|
+                                    path|port|secure|version)$/x;
+	    if ($k eq "discard" || $k eq "secure") {
+		$v = 1 unless defined $v;
+	    }
+	    next if exists $hash{$k};  # only first value is signigicant
+	    $hash{$k} = $v;
+	};
+
+	my %orig_hash = %hash;
+	my $version   = delete $hash{version};
+	$version = 1 unless defined($version);
+	my $discard   = delete $hash{discard};
+	my $secure    = delete $hash{secure};
+	my $maxage    = delete $hash{'max-age'};
+
+	# Check domain
+	my $domain  = delete $hash{domain};
+	if (defined($domain) && $domain ne $req_host) {
+	    if ($domain !~ /\./ && $domain ne "local") {
+	        LWP::Debug::debug("Domain $domain contains no dot");
+		next SET_COOKIE;
+	    }
+	    $domain = ".$domain" unless $domain =~ /^\./;
+	    if ($domain =~ /\.\d+$/) {
+	        LWP::Debug::debug("IP-address $domain illeagal as domain");
+		next SET_COOKIE;
+	    }
+	    my $len = length($domain);
+	    unless (substr($req_host, -$len) eq $domain) {
+	        LWP::Debug::debug("Domain $domain does not match host $req_host");
+		next SET_COOKIE;
+	    }
+	    my $hostpre = substr($req_host, 0, length($req_host) - $len);
+	    if ($hostpre =~ /\./ && !$netscape_cookies) {
+	        LWP::Debug::debug("Host prefix contain a dot: $hostpre => $domain");
+		next SET_COOKIE;
+	    }
+	} else {
+	    $domain = $req_host;
+	}
+
+	my $path = delete $hash{path};
+	my $path_spec;
+	if (defined $path) {
+	    $path_spec++;
+	    $self->_normalize_path($path) if $path =~ /%/;
+	    if (!$netscape_cookies &&
+                substr($req_path, 0, length($path)) ne $path) {
+	        LWP::Debug::debug("Path $path is not a prefix of $req_path");
+		next SET_COOKIE;
+	    }
+	} else {
+	    $path = $req_path;
+	    $path =~ s,/[^/]*$,,;
+	    $path = "/" unless length($path);
+	}
+
+	my $port;
+	if (exists $hash{port}) {
+	    $port = delete $hash{port};
+	    if (defined $port) {
+		$port =~ s/\s+//g;
+		my $found;
+		for my $p (split(/,/, $port)) {
+		    unless ($p =~ /^\d+$/) {
+		      LWP::Debug::debug("Bad port $port (not numeric)");
+			next SET_COOKIE;
+		    }
+		    $found++ if $p eq $req_port;
+		}
+		unless ($found) {
+		    LWP::Debug::debug("Request port ($req_port) not found in $port");
+		    next SET_COOKIE;
+		}
+	    } else {
+		$port = "_$req_port";
+	    }
+	}
+	$self->set_cookie($version,$key,$val,$path,$domain,$port,$path_spec,$secure,$maxage,$discard, \%hash)
+	    if $self->set_cookie_ok(\%orig_hash);
+    }
+
+    $response;
+}
+
+sub set_cookie_ok { 1 };
+
+=item $cookie_jar->set_cookie($version, $key, $val, $path, $domain, $port, $path_spec, $secure, $maxage, $discard, \%rest)
+
+The set_cookie() method updates the state of the $cookie_jar.  The
+$key, $val, $domain, $port and $path arguments are strings.  The
+$path_spec, $secure, $discard arguments are boolean values. The $maxage
+value is a number indicating number of seconds that this cookie will
+live.  A value <= 0 will delete this cookie.  The %rest are a place
+for various other attributes like "Comment" and "CommentURL".
+
+=cut
+
+sub set_cookie
+{
+    my $self = shift;
+    my($version,
+       $key, $val, $path, $domain, $port,
+       $path_spec, $secure, $maxage, $discard, $rest) = @_;
+
+    # there must always be at least 2 dots in a domain
+    return $self if ($domain =~ tr/././) < 2 &&
+                     $domain !~ /\.local$/;
+
+    # path and key can not be empty (key can't start with '$')
+    return $self if !defined($path) || $path !~ m,^/, ||
+	            !defined($key)  || $key  !~ m,[^\$],;
+
+    # ensure legal port
+    if (defined $port) {
+	return $self unless $port =~ /^_?\d+(?:,\d+)*$/;
+    }
+
+    my $expires;
+    if (defined $maxage) {
+	if ($maxage <= 0) {
+	    delete $self->{COOKIES}{$domain}{$path}{$key};
+	    return $self;
+	}
+	$expires = time() + $maxage;
+    }
+    $version = 0 unless defined $version;
+
+    my @array = ($version, $val,$port,
+		 $path_spec,
+		 $secure, $expires, $discard);
+    push(@array, {%$rest}) if defined($rest) && %$rest;
+    # trim off undefined values at end
+    pop(@array) while !defined $array[-1];
+
+    $self->{COOKIES}{$domain}{$path}{$key} = \@array;
+    $self;
+}
+
+=item $cookie_jar->save( [$file] );
+
+Calling this method file save the state of the $cookie_jar to a file.
+The state can then be restored later using the load() method.  If a
+filename is not specified we will use the name specified during
+construction.  If the attribute I<ignore_discared> is set, then we
+will even save cookies that are marked to be discarded.
+
+The default is to save a sequence of "Set-Cookie3" lines.  The
+"Set-Cookie3" is a proprietary LWP format, not known to be compatible
+with any other browser.  The I<HTTP::Cookies::Netscape> sub-class can
+be used to save in a format compatible with Netscape.
+
+=cut
+
+sub save
+{
+    my $self = shift;
+    my $file = shift || $self->{'file'} || return;
+    local(*FILE);
+    open(FILE, ">$file") or die "Can't open $file: $!";
+    print FILE "#LWP-Cookies-1.0\n";
+    print FILE $self->as_string(!$self->{ignore_discard});
+    close(FILE);
+    1;
+}
+
+=item $cookie_jar->load( [$file] );
+
+This method will read the cookies from the file and add them to the
+$cookie_jar.  The file must be in the format written by the save()
+method.
+
+=cut
+
+sub load
+{
+    my $self = shift;
+    my $file = shift || $self->{'file'} || return;
+    local(*FILE, $_);
+    open(FILE, $file) or return;
+    my $magic = <FILE>;
+    unless ($magic =~ /^\#LWP-Cookies-(\d+\.\d+)/) {
+	warn "$file does not seem to contain cookies";
+	return;
+    }
+    while (<FILE>) {
+	next unless s/^Set-Cookie3:\s*//;
+	chomp;
+	my $cookie;
+	for $cookie (split_header_words($_)) {
+	    my($key,$val) = splice(@$cookie, 0, 2);
+	    my %hash;
+	    while (@$cookie) {
+		my $k = shift @$cookie;
+		my $v = shift @$cookie;
+		$hash{$k} = $v;
+	    }
+	    my $version   = delete $hash{version};
+	    my $path      = delete $hash{path};
+	    my $domain    = delete $hash{domain};
+	    my $port      = delete $hash{port};
+	    my $expires   = str2time(delete $hash{expires});
+
+	    my $path_spec = exists $hash{path_spec}; delete $hash{path_spec};
+	    my $secure    = exists $hash{secure};    delete $hash{secure};
+	    my $discard   = exists $hash{discard};   delete $hash{discard};
+
+	    my @array =	($version,$val,$port,
+			 $path_spec,$secure,$expires,$discard);
+	    push(@array, \%hash) if %hash;
+	    $self->{COOKIES}{$domain}{$path}{$key} = \@array;
+	}
+    }
+    close(FILE);
+    1;
+}
+
+=item $cookie_jar->revert;
+
+Will revert to the state of last save.
+
+=cut
+
+sub revert
+{
+    my $self = shift;
+    $self->clear->load;
+    $self;
+}
+
+=item $cookie_jar->clear( [$domain, [$path, [$key] ] ]);
+
+Invoking this method without arguments will empty the whole
+$cookie_jar.  If given a single argument only cookies belonging to
+that domain will be removed.  If given two arguments, cookies
+belonging to the specified path within that domain is removed.  If
+given three arguments, then the cookie with the specified key, path
+and domain is removed.
+
+=cut
+
+sub clear
+{
+    my $self = shift;
+    if (@_ == 0) {
+	$self->{COOKIES} = {};
+    } elsif (@_ == 1) {
+	delete $self->{COOKIES}{$_[0]};
+    } elsif (@_ == 2) {
+	delete $self->{COOKIES}{$_[0]}{$_[1]};
+    } elsif (@_ == 3) {
+	delete $self->{COOKIES}{$_[0]}{$_[1]}{$_[2]};
+    } else {
+	require Carp;
+        Carp::carp('Usage: $c->clear([domain [,path [,key]]])');
+    }
+    $self;
+}
+
+sub DESTROY
+{
+    my $self = shift;
+    $self->save if $self->{'autosave'};
+}
+
+
+=item $cookie_jar->scan( \&callback );
+
+The argument is a subroutine that will be invoked for each cookie
+stored within the $cookie_jar.  The subroutine will be invoked with
+the following arguments:
+
+  0  version
+  1  key
+  2  val
+  3  path
+  4  domain
+  5  port
+  6  path_spec
+  7  secure
+  8  expires
+  9  discard
+ 10  hash
+
+=cut
+
+sub scan
+{
+    my($self, $cb) = @_;
+    my($domain,$path,$key);
+    for $domain (sort keys %{$self->{COOKIES}}) {
+	for $path (sort keys %{$self->{COOKIES}{$domain}}) {
+	    for $key (sort keys %{$self->{COOKIES}{$domain}{$path}}) {
+		my($version,$val,$port,$path_spec,
+		   $secure,$expires,$discard,$rest) =
+		       @{$self->{COOKIES}{$domain}{$path}{$key}};
+		$rest = {} unless defined($rest);
+		&$cb($version,$key,$val,$path,$domain,$port,
+		     $path_spec,$secure,$expires,$discard,$rest);
+	    }
+	}
+    }
+}
+
+=item $cookie_jar->as_string( [$skip_discard] );
+
+The as_string() method will return the state of the $cookie_jar
+represented as a sequence of "Set-Cookie3" header lines separated by
+"\n".  If given a argument that is TRUE, it will not return lines for
+cookies with the I<Discard> attribute.
+
+=cut
+
+sub as_string
+{
+    my($self, $skip_discard) = @_;
+    my @res;
+    $self->scan(sub {
+	my($version,$key,$val,$path,$domain,$port,
+	   $path_spec,$secure,$expires,$discard,$rest) = @_;
+	return if $discard && $skip_discard;
+	my @h = ($key, $val);
+	push(@h, "path", $path);
+	push(@h, "domain" => $domain);
+	push(@h, "port" => $port) if defined $port;
+	push(@h, "path_spec" => undef) if $path_spec;
+	push(@h, "secure" => undef) if $secure;
+	push(@h, "expires" => HTTP::Date::time2isoz($expires)) if $expires;
+	push(@h, "discard" => undef) if $discard;
+	my $k;
+	for $k (sort keys %$rest) {
+	    push(@h, $k, $rest->{$k});
+	}
+	push(@h, "version" => $version);
+	push(@res, "Set-Cookie3: " . join_header_words(\@h));
+    });
+    join("\n", @res, "");
+}
+
+
+sub _normalize_path  # so that plain string compare can be used
+{
+    shift;  # $self
+    my $x;
+    $_[0] =~ s/%([0-9a-fA-F][0-9a-fA-F])/
+	         $x = uc($1);
+                 $x eq "2F" || $x eq "25" ? "%$x" :
+                                            pack("c", hex($x));
+              /eg;
+    $_[0] =~ s/([\0-\x20\x7f-\xff])/sprintf("%%%02X",ord($1))/eg;
+}
+
+
+
+=back
+
+=head1 SUB CLASSES
+
+We also provide a subclass called I<HTTP::Cookies::Netscape> which make
+cookie loading and saving compatible with Netscape cookie files.  You
+should be able to have LWP share Netscape's cookies by constructing
+your $cookie_jar like this:
+
+ $cookie_jar = HTTP::Cookies::Netscape->new(
+                   File     => "$ENV{HOME}/.netscape/cookies",
+                   AutoSave => 1,
+               );
+
+Please note that the Netscape cookie file format is not able to store
+all the information available in the Set-Cookie2 headers, so you will
+probably loose some information if you save using this format.
+
+=cut
+
+package HTTP::Cookies::Netscape;
+
+use vars qw(@ISA);
+@ISA=qw(HTTP::Cookies);
+
+sub load
+{
+    my($self, $file) = @_;
+    $file ||= $self->{'file'} || return;
+    local(*FILE, $_);
+    my @cookies;
+    open(FILE, $file) || return;
+    my $magic = <FILE>;
+    unless ($magic =~ /^\# Netscape HTTP Cookie File/) {
+	warn "$file does not look like a netscape cookies file" if $^W;
+	close(FILE);
+	return;
+    }
+    my $now = time();
+    while (<FILE>) {
+	next if /^\s*\#/;
+	next if /^\s*$/;
+	chomp;
+	my($domain,$bool1,$path,$secure, $expires,$key,$val) = split(/\t/, $_);
+	$secure = ($secure eq "TRUE");
+	$self->set_cookie(undef,$key,$val,$path,$domain,undef,
+			  0,$secure,$expires-$now, 0);
+    }
+    close(FILE);
+    1;
+}
+
+sub save
+{
+    my($self, $file) = @_;
+    $file ||= $self->{'file'} || return;
+    local(*FILE, $_);
+    open(FILE, ">$file") || return;
+
+    print FILE <<EOT;
+# Netscape HTTP Cookie File
+# http://www.netscape.com/newsref/std/cookie_spec.html
+# This is a generated file!  Do not edit.
+
+EOT
+
+    my $now = time;
+    $self->scan(sub {
+	my($version,$key,$val,$path,$domain,$port,
+	   $path_spec,$secure,$expires,$discard,$rest) = @_;
+	return if $discard && !$self->{ignore_discard};
+	$expires ||= 0;
+	return if $now > $expires;
+	$secure = $secure ? "TRUE" : "FALSE";
+	my $bool = $domain =~ /^\./ ? "TRUE" : "FALSE";
+	print FILE join("\t", $domain, $bool, $path, $secure, $expires, $key, $val), "\n";
+    });
+    close(FILE);
+    1;
+}
+
+1;
+
+__END__
+
+=head1 COPYRIGHT
+
+Copyright 1997, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Daemon.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Daemon.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Daemon.pm	(revision 10506)
@@ -0,0 +1,805 @@
+# $Id$
+#
+
+use strict;
+
+package HTTP::Daemon;
+
+=head1 NAME
+
+HTTP::Daemon - a simple http server class
+
+=head1 SYNOPSIS
+
+  use HTTP::Daemon;
+  use HTTP::Status;
+
+  my $d = new HTTP::Daemon;
+  print "Please contact me at: <URL:", $d->url, ">\n";
+  while (my $c = $d->accept) {
+      while (my $r = $c->get_request) {
+	  if ($r->method eq 'GET' and $r->url->path eq "/xyzzy") {
+              # remember, this is *not* recommened practice :-)
+	      $c->send_file_response("/etc/passwd");
+	  } else {
+	      $c->send_error(RC_FORBIDDEN)
+	  }
+      }
+      $c->close;
+      undef($c);
+  }
+
+=head1 DESCRIPTION
+
+Instances of the I<HTTP::Daemon> class are HTTP/1.1 servers that
+listens on a socket for incoming requests. The I<HTTP::Daemon> is a
+sub-class of I<IO::Socket::INET>, so you can do socket operations
+directly on it too.
+
+The accept() method will return when a connection from a client is
+available. The returned value will be a reference to a object of the
+I<HTTP::Daemon::ClientConn> class which is another I<IO::Socket::INET>
+subclass. Calling the get_request() method on this object will read
+data from the client and return an I<HTTP::Request> object reference.
+
+This HTTP daemon does not fork(2) for you.  Your application, i.e. the
+user of the I<HTTP::Daemon> is reponsible for forking if that is
+desirable.  Also note that the user is responsible for generating
+responses that conforms to the HTTP/1.1 protocol.  The
+I<HTTP::Daemon::ClientConn> provide some methods that make this easier.
+
+=head1 METHODS
+
+The following is a list of methods that are new (or enhanced) relative
+to the I<IO::Socket::INET> base class.
+
+=over 4
+
+=cut
+
+
+use vars qw($VERSION @ISA $PROTO $DEBUG);
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use IO::Socket ();
+@ISA=qw(IO::Socket::INET);
+
+$PROTO = "HTTP/1.1";
+
+=item $d = new HTTP::Daemon
+
+The object constructor takes the same parameters as the
+I<IO::Socket::INET> constructor.  It can be called without specifying
+any parameters. The daemon will then set up a listen queue of 5
+connections and allocate some random port number.  A server that want
+to bind to some specific address on the standard HTTP port will be
+constructed like this:
+
+  $d = new HTTP::Daemon
+        LocalAddr => 'www.someplace.com',
+        LocalPort => 80;
+
+=cut
+
+sub new
+{
+    my($class, %args) = @_;
+    $args{Listen} ||= 5;
+    $args{Proto}  ||= 'tcp';
+    my $self = $class->SUPER::new(%args);
+    return undef unless $self;
+
+    my $host = $args{LocalAddr};
+    unless ($host) {
+	require Sys::Hostname;
+	$host = Sys::Hostname::hostname();
+    }
+    ${*$self}{'httpd_server_name'} = $host;
+    $self;
+}
+
+
+=item $c = $d->accept([$pkg])
+
+Same as I<IO::Socket::accept> but will return an
+I<HTTP::Daemon::ClientConn> reference by default.  It will return
+undef if you have specified a timeout and no connection is made within
+that time.
+
+=cut
+
+sub accept
+{
+    my $self = shift;
+    my $pkg = shift || "HTTP::Daemon::ClientConn";
+    my $sock = $self->SUPER::accept($pkg);
+    ${*$sock}{'httpd_daemon'} = $self if $sock;
+    $sock;
+}
+
+
+=item $d->url
+
+Returns a URL string that can be used to access the server root.
+
+=cut
+
+sub url
+{
+    my $self = shift;
+    my $url = "http://";
+    $url .= ${*$self}{'httpd_server_name'};
+    my $port = $self->sockport;
+    $url .= ":$port" if $port != 80;
+    $url .= "/";
+    $url;
+}
+
+
+=item $d->product_tokens
+
+Returns the name that this server will use to identify itself.  This
+is the string that is sent with the I<Server> response header.  The
+main reason to have this method is that subclasses can override it if
+they want to use another product name.
+
+=cut
+
+sub product_tokens
+{
+    "libwww-perl-daemon/$HTTP::Daemon::VERSION";
+}
+
+
+package HTTP::Daemon::ClientConn;
+
+use vars qw(@ISA $DEBUG);
+use IO::Socket ();
+@ISA=qw(IO::Socket::INET);
+*DEBUG = \$HTTP::Daemon::DEBUG;
+
+use HTTP::Request  ();
+use HTTP::Response ();
+use HTTP::Status;
+use HTTP::Date qw(time2str);
+use URI::URL qw(url);
+use LWP::MediaTypes qw(guess_media_type);
+use Carp ();
+
+my $CRLF = "\015\012";   # "\r\n" is not portable
+my $HTTP_1_0 = _http_version("HTTP/1.0");
+my $HTTP_1_1 = _http_version("HTTP/1.1");
+
+=back
+
+The I<HTTP::Daemon::ClientConn> is also a I<IO::Socket::INET>
+subclass. Instances of this class are returned by the accept() method
+of the I<HTTP::Daemon>.  The following additional methods are
+provided:
+
+=over 4
+
+=item $c->get_request([$headers_only])
+
+This method will read data from the client and turn it into a
+I<HTTP::Request> object which is then returned.  It returns C<undef>
+if reading of the request fails.  If it fails, then the
+I<HTTP::Daemon::ClientConn> object ($c) should be discarded, and you
+should not call this method again.  The $c->reason method might give
+you some information on why $c->get_request returned C<undef>.
+
+The $c->get_request method support HTTP/1.1 request content bodies,
+including I<chunked> transfer encoding with footer and self delimiting
+I<multipart/*> content types.
+
+The $c->get_request method will normally not return until the whole
+request has been received from the client.  This might not be what you
+want if the request is an upload of a multi-mega-byte file (and with
+chunked transfer encoding HTTP can even support infinite request
+messages - uploading live audio for instance).  If you pass a TRUE
+value as the $headers_only argument, then $c->get_request will return
+immediately after parsing the request headers and you are responsible
+for reading the rest of the request content (and if you are going to
+call $c->get_request again on the same connection you better read the
+correct number of bytes).
+
+=cut
+
+sub get_request
+{
+    my($self, $only_headers) = @_;
+    if (${*$self}{'httpd_nomore'}) {
+        $self->reason("No more requests from this connection");
+	return;
+    }
+
+    $self->reason("");
+    my $buf = ${*$self}{'httpd_rbuf'};
+    $buf = "" unless defined $buf;
+    
+    my $timeout = $ {*$self}{'io_socket_timeout'};
+    my $fdset = "";
+    vec($fdset, $self->fileno, 1) = 1;
+    local($_);
+
+  READ_HEADER:
+    while (1) {
+	# loop until we have the whole header in $buf
+	$buf =~ s/^(?:\015?\012)+//;  # ignore leading blank lines
+	if ($buf =~ /\012/) {  # potential, has at least one line
+	    if ($buf =~ /^\w+[^\012]+HTTP\/\d+\.\d+\015?\012/) {
+		if ($buf =~ /\015?\012\015?\012/) {
+		    last READ_HEADER;  # we have it
+		} elsif (length($buf) > 16*1024) {
+		    $self->send_error(413); # REQUEST_ENTITY_TOO_LARGE
+		    $self->reason("Very long header");
+		    return;
+		}
+	    } else {
+		last READ_HEADER;  # HTTP/0.9 client
+	    }
+	} elsif (length($buf) > 16*1024) {
+	    $self->send_error(414); # REQUEST_URI_TOO_LARGE
+	    $self->reason("Very long first line");
+	    return;
+	}
+	print STDERR "Need more data for complete header\n" if $DEBUG;
+	return unless $self->_need_more($buf, $timeout, $fdset);
+    }
+    if ($buf !~ s/^(\w+)[ \t]+(\S+)(?:[ \t]+(HTTP\/\d+\.\d+))?[^\012]*\012//) {
+	$self->send_error(400);  # BAD_REQUEST
+	$self->reason("Bad request line");
+	return;
+    }
+    my $proto = $3 || "HTTP/0.9";
+    my $r = HTTP::Request->new($1, url($2, $self->daemon->url));
+    $r->protocol($proto);
+    ${*$self}{'httpd_client_proto'} = $proto = _http_version($proto);
+
+    if ($proto >= $HTTP_1_0) {
+	# we expect to find some headers
+	my($key, $val);
+      HEADER:
+	while ($buf =~ s/^([^\012]*)\012//) {
+	    $_ = $1;
+	    s/\015$//;
+	    if (/^([\w\-]+)\s*:\s*(.*)/) {
+		$r->push_header($key, $val) if $key;
+		($key, $val) = ($1, $2);
+	    } elsif (/^\s+(.*)/) {
+		$val .= " $1";
+	    } else {
+		last HEADER;
+	    }
+	}
+	$r->push_header($key, $val) if $key;
+    }
+
+    my $conn = $r->header('Connection');
+    if ($proto >= $HTTP_1_1) {
+	${*$self}{'httpd_nomore'}++ if $conn && lc($conn) =~ /\bclose\b/;
+    } else {
+	${*$self}{'httpd_nomore'}++ unless $conn &&
+                                           lc($conn) =~ /\bkeep-alive\b/;
+    }
+
+    if ($only_headers) {
+	${*$self}{'httpd_rbuf'} = $buf;
+        return $r;
+    }
+
+    # Find out how much content to read
+    my $te  = $r->header('Transfer-Encoding');
+    my $ct  = $r->header('Content-Type');
+    my $len = $r->header('Content-Length');
+
+    if ($te && lc($te) eq 'chunked') {
+	# Handle chunked transfer encoding
+	my $body = "";
+      CHUNK:
+	while (1) {
+	    print STDERR "Chunked\n" if $DEBUG;
+	    if ($buf =~ s/^([^\012]*)\012//) {
+		my $chunk_head = $1;
+		unless ($chunk_head =~ /^([0-9A-Fa-f]+)/) {
+		    $self->send_error(400);
+		    $self->reason("Bad chunk header $chunk_head");
+		    return;
+		}
+		my $size = hex($1);
+		last CHUNK if $size == 0;
+
+		my $missing = $size - length($buf) + 2; # 2=CRLF at chunk end
+		# must read until we have a complete chunk
+		while ($missing > 0) {
+		    print STDERR "Need $missing more bytes\n" if $DEBUG;
+		    my $n = $self->_need_more($buf, $timeout, $fdset);
+		    return unless $n;
+		    $missing -= $n;
+		}
+		$body .= substr($buf, 0, $size);
+		substr($buf, 0, $size+2) = '';
+
+	    } else {
+		# need more data in order to have a complete chunk header
+		return unless $self->_need_more($buf, $timeout, $fdset);
+	    }
+	}
+	$r->content($body);
+
+	# pretend it was a normal entity body
+	$r->remove_header('Transfer-Encoding');
+	$r->header('Content-Length', length($body));
+
+	my($key, $val);
+      FOOTER:
+	while (1) {
+	    if ($buf !~ /\012/) {
+		# need at least one line to look at
+		return unless $self->_need_more($buf, $timeout, $fdset);
+	    } else {
+		$buf =~ s/^([^\012]*)\012//;
+		$_ = $1;
+		s/\015$//;
+		if (/^([\w\-]+)\s*:\s*(.*)/) {
+		    $r->push_header($key, $val) if $key;
+		    ($key, $val) = ($1, $2);
+		} elsif (/^\s+(.*)/) {
+		    $val .= " $1";
+		} elsif (!length) {
+		    last FOOTER;
+		} else {
+		    $self->reason("Bad footer syntax");
+		    return;
+		}
+	    }
+	}
+	$r->push_header($key, $val) if $key;
+
+    } elsif ($te) {
+	$self->send_error(501); 	# Unknown transfer encoding
+	$self->reason("Unknown transfer encoding '$te'");
+	return;
+
+    } elsif ($ct && lc($ct) =~ m/^multipart\/\w+\s*;.*boundary\s*=\s*(\w+)/) {
+	# Handle multipart content type
+	my $boundary = "$CRLF--$1--$CRLF";
+	my $index;
+	while (1) {
+	    $index = index($buf, $boundary);
+	    last if $index >= 0;
+	    # end marker not yet found
+	    return unless $self->_need_more($buf, $timeout, $fdset);
+	}
+	$index += length($boundary);
+	$r->content(substr($buf, 0, $index));
+	substr($buf, 0, $index) = '';
+
+    } elsif ($len) {
+	# Plain body specified by "Content-Length"
+	my $missing = $len - length($buf);
+	while ($missing > 0) {
+	    print "Need $missing more bytes of content\n" if $DEBUG;
+	    my $n = $self->_need_more($buf, $timeout, $fdset);
+	    return unless $n;
+	    $missing -= $n;
+	}
+	if (length($buf) > $len) {
+	    $r->content(substr($buf,0,$len));
+	    substr($buf, 0, $len) = '';
+	} else {
+	    $r->content($buf);
+	    $buf='';
+	}
+    }
+    ${*$self}{'httpd_rbuf'} = $buf;
+
+    $r;
+}
+
+sub _need_more
+{
+    my $self = shift;
+    #my($buf,$timeout,$fdset) = @_;
+    if ($_[1]) {
+	my($timeout, $fdset) = @_[1,2];
+	print STDERR "select(,,,$timeout)\n" if $DEBUG;
+	my $n = select($fdset,undef,undef,$timeout);
+	unless ($n) {
+	    $self->reason(defined($n) ? "Timeout" : "select: $!");
+	    return;
+	}
+    }
+    print STDERR "sysread()\n" if $DEBUG;
+    my $n = sysread($self, $_[0], 2048, length($_[0]));
+    $self->reason(defined($n) ? "Client closed" : "sysread: $!") unless $n;
+    $n;
+}
+
+=item $c->read_buffer([$new_value])
+
+Bytes read by $c->get_request, but not used are placed in the I<read
+buffer>.  The next time $c->get_request is called it will consume the
+bytes in this buffer before reading more data from the network
+connection itself.  The read buffer is invalid after $c->get_request
+has returned an undefined value.
+
+If you handle the reading of the request content yourself you need to
+empty this buffer before you read more and you need to place
+unconsumed bytes here.  You also need this buffer if you implement
+services like I<101 Switching Protocols>.
+
+This method always return the old buffer content and can optionally
+update the buffer content if you pass it an argument.
+
+=cut
+
+sub read_buffer
+{
+    my $self = shift;
+    my $old = ${*$self}{'httpd_rbuf'};
+    if (@_) {
+	${*$self}{'httpd_rbuf'} = shift;
+    }
+    $old;
+}
+
+
+=item $c->reason
+
+When $c->get_request returns C<undef> you can obtain a short string
+describing why it happened by calling $c->reason.
+
+=cut
+
+sub reason
+{
+    my $self = shift;
+    my $old = ${*$self}{'httpd_reason'};
+    if (@_) {
+        ${*$self}{'httpd_reason'} = shift;
+    }
+    $old;
+}
+
+
+=item $c->proto_ge($proto)
+
+Returns TRUE if the client announced a protocol with version number
+greater or equal to the given argument.  The $proto argument can be a
+string like "HTTP/1.1" or just "1.1".
+
+=cut
+
+sub proto_ge
+{
+    my $self = shift;
+    ${*$self}{'httpd_client_proto'} >= _http_version(shift);
+}
+
+sub _http_version
+{
+    local($_) = shift;
+    return 0 unless m,^(?:HTTP/)?(\d+)\.(\d+)$,i;
+    $1 * 1000 + $2;
+}
+
+=item $c->antique_client
+
+Returns TRUE if the client speaks the HTTP/0.9 protocol.  No status
+code and no headers should be returned to such a client.  This should
+be the same as !$c->proto_ge("HTTP/1.0").
+
+=cut
+
+sub antique_client
+{
+    my $self = shift;
+    ${*$self}{'httpd_client_proto'} < $HTTP_1_0;
+}
+
+
+=item $c->force_last_request
+
+Make sure that $c->get_request will not try to read more requests off
+this connection.  If you generate a response that is not self
+delimiting, then you should signal this fact by calling this method.
+
+This attribute is turned on automatically if the client announce
+protocol HTTP/1.0 or worse and does not include a "Connection:
+Keep-Alive" header.  It is also turned on automatically when HTTP/1.1
+or better clients send the "Connection: close" request header.
+
+=cut
+
+sub force_last_request
+{
+    my $self = shift;
+    ${*$self}{'httpd_nomore'}++;
+}
+
+
+=item $c->send_status_line( [$code, [$mess, [$proto]]] )
+
+Sends the status line back to the client.  If $code is omitted 200 is
+assumed.  If $mess is omitted, then a message corresponding to $code
+is inserted.  If $proto is missing the content of the
+$HTTP::Daemon::PROTO variable is used.
+
+=cut
+
+sub send_status_line
+{
+    my($self, $status, $message, $proto) = @_;
+    return if $self->antique_client;
+    $status  ||= RC_OK;
+    $message ||= status_message($status) || "";
+    $proto   ||= $HTTP::Daemon::PROTO || "HTTP/1.1";
+    print $self "$proto $status $message$CRLF";
+}
+
+=item $c->send_crlf
+
+Send the CRLF sequence to the client.
+
+=cut
+
+
+sub send_crlf
+{
+    my $self = shift;
+    print $self $CRLF;
+}
+
+
+=item $c->send_basic_header( [$code, [$mess, [$proto]]] )
+
+Sends the status line and the "Date:" and "Server:" headers back to
+the client.  This header is assumed to be continued and does not end
+with an empty CRLF line.
+
+=cut
+
+sub send_basic_header
+{
+    my $self = shift;
+    return if $self->antique_client;
+    $self->send_status_line(@_);
+    print $self "Date: ", time2str(time), $CRLF;
+    my $product = $self->daemon->product_tokens;
+    print $self "Server: $product$CRLF" if $product;
+}
+
+
+=item $c->send_response( [$res] )
+
+Takes a I<HTTP::Response> object as parameter and write it back to the
+client as the response.  We try hard to make sure that the response is
+self delimiting so that the connection can stay persistent for further
+request/response exchanges.
+
+The content attribute of the I<HTTP::Response> object can be a normal
+string or a subroutine reference.  If it is a subroutine, then
+whatever this callback routine returns will be written back to the
+client as the response content.  The routine will be called until it
+return an undefined or empty value.  If the client is HTTP/1.1 aware
+then we will use the chunked transfer encoding for the response.
+
+=cut
+
+sub send_response
+{
+    my $self = shift;
+    my $res = shift;
+    if (!ref $res) {
+	$res ||= RC_OK;
+	$res = HTTP::Response->new($res, @_);
+    }
+    my $content = $res->content;
+    my $chunked;
+    unless ($self->antique_client) {
+	my $code = $res->code;
+	$self->send_basic_header($code, $res->message, $res->protocol);
+	if ($code =~ /^(1\d\d|[23]04)$/) {
+	    # make sure content is empty
+	    $res->remove_header("Content-Length");
+	    $content = "";
+	} elsif ($res->request && $res->request->method eq "HEAD") {
+	    # probably OK
+	} elsif (ref($content) eq "CODE") {
+	    if ($self->proto_ge("HTTP/1.1")) {
+		$res->push_header("Transfer-Encoding" => "chunked");
+		$chunked++;
+	    } else {
+		$self->force_last_request;
+	    }
+	} elsif (length($content)) {
+	    $res->header("Content-Length" => length($content));
+	} else {
+	    $self->force_last_request;
+	}
+	print $self $res->headers_as_string($CRLF);
+	print $self $CRLF;  # separates headers and content
+    }
+    if (ref($content) eq "CODE") {
+	while (1) {
+	    my $chunk = &$content();
+	    last unless defined($chunk) && length($chunk);
+	    if ($chunked) {
+		printf $self "%x%s%s%s", length($chunk), $CRLF, $chunk, $CRLF;
+	    } else {
+		print $self $chunk;
+	    }
+	}
+	print $self "0$CRLF$CRLF" if $chunked;  # no trailers either
+    } elsif (length $content) {
+	print $self $content;
+    }
+}
+
+
+=item $c->send_redirect( $loc, [$code, [$entity_body]] )
+
+Sends a redirect response back to the client.  The location ($loc) can
+be an absolute or a relative URL. The $code must be one the redirect
+status codes, and it defaults to "301 Moved Permanently"
+
+=cut
+
+sub send_redirect
+{
+    my($self, $loc, $status, $content) = @_;
+    $status ||= RC_MOVED_PERMANENTLY;
+    Carp::croak("Status '$status' is not redirect") unless is_redirect($status);
+    $self->send_basic_header($status);
+    $loc = url($loc, $self->daemon->url) unless ref($loc);
+    $loc = $loc->abs;
+    print $self "Location: $loc$CRLF";
+    if ($content) {
+	my $ct = $content =~ /^\s*</ ? "text/html" : "text/plain";
+	print $self "Content-Type: $ct$CRLF";
+    }
+    print $self $CRLF;
+    print $self $content if $content;
+    $self->force_last_request;  # no use keeping the connection open
+}
+
+
+=item $c->send_error( [$code, [$error_message]] )
+
+Send an error response back to the client.  If the $code is missing a
+"Bad Request" error is reported.  The $error_message is a string that
+is incorporated in the body of the HTML entity body.
+
+=cut
+
+sub send_error
+{
+    my($self, $status, $error) = @_;
+    $status ||= RC_BAD_REQUEST;
+    Carp::croak("Status '$status' is not an error") unless is_error($status);
+    my $mess = status_message($status);
+    $error  ||= "";
+    $mess = <<EOT;
+<title>$status $mess</title>
+<h1>$status $mess</h1>
+$error
+EOT
+    unless ($self->antique_client) {
+        $self->send_basic_header($status);
+        print $self "Content-Type: text/html$CRLF";
+	print $self "Content-Length: " . length($mess) . $CRLF;
+        print $self $CRLF;
+    }
+    print $self $mess;
+    $status;
+}
+
+
+=item $c->send_file_response($filename)
+
+Send back a response with the specified $filename as content.  If the
+file happen to be a directory we will try to generate an HTML index
+of it.
+
+=cut
+
+sub send_file_response
+{
+    my($self, $file) = @_;
+    if (-d $file) {
+	$self->send_dir($file);
+    } elsif (-f _) {
+	# plain file
+	local(*F);
+	sysopen(F, $file, 0) or 
+	  return $self->send_error(RC_FORBIDDEN);
+	my($ct,$ce) = guess_media_type($file);
+	my($size,$mtime) = (stat _)[7,9];
+	unless ($self->antique_client) {
+	    $self->send_basic_header;
+	    print $self "Content-Type: $ct$CRLF";
+	    print $self "Content-Encoding: $ce$CRLF" if $ce;
+	    print $self "Content-Length: $size$CRLF" if $size;
+	    print $self "Last-Modified: ", time2str($mtime), "$CRLF" if $mtime;
+	    print $self $CRLF;
+	}
+	$self->send_file(\*F);
+	return RC_OK;
+    } else {
+	$self->send_error(RC_NOT_FOUND);
+    }
+}
+
+
+sub send_dir
+{
+    my($self, $dir) = @_;
+    $self->send_error(RC_NOT_FOUND) unless -d $dir;
+    $self->send_error(RC_NOT_IMPLEMENTED);
+}
+
+
+=item $c->send_file($fd);
+
+Copies the file back to the client.  The file can be a string (which
+will be interpreted as a filename) or a reference to an I<IO::Handle>
+or glob.
+
+=cut
+
+sub send_file
+{
+    my($self, $file) = @_;
+    my $opened = 0;
+    if (!ref($file)) {
+	local(*F);
+	open(F, $file) || return undef;
+	binmode(F);
+	$file = \*F;
+	$opened++;
+    }
+    my $cnt = 0;
+    my $buf = "";
+    my $n;
+    while ($n = sysread($file, $buf, 8*1024)) {
+	last if !$n;
+	$cnt += $n;
+	print $self $buf;
+    }
+    close($file) if $opened;
+    $cnt;
+}
+
+
+=item $c->daemon
+
+Return a reference to the corresponding I<HTTP::Daemon> object.
+
+=cut
+
+sub daemon
+{
+    my $self = shift;
+    ${*$self}{'httpd_daemon'};
+}
+
+=back
+
+=head1 SEE ALSO
+
+RFC 2068
+
+L<IO::Socket>, L<Apache>
+
+=head1 COPYRIGHT
+
+Copyright 1996-1998, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Date.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Date.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Date.pm	(revision 10506)
@@ -0,0 +1,330 @@
+# $Id$
+#
+package HTTP::Date;
+
+=head1 NAME
+
+HTTP::Date - date conversion routines
+
+=head1 SYNOPSIS
+
+ use HTTP::Date;
+
+ $string = time2str($time);    # Format as GMT ASCII time
+ $time = str2time($string);    # convert ASCII date to machine time
+
+=head1 DESCRIPTION
+
+This module provides two functions that deal with the HTTP date
+format.  The following functions are provided:
+
+=over 4
+
+=item time2str([$time])
+
+The time2str() function converts a machine time (seconds since epoch)
+to a string.  If the function is called without an argument, it will
+use the current time.
+
+The string returned is in the format defined by the HTTP/1.0
+specification.  This is a fixed length subset of the format defined by
+RFC 1123, represented in Universal Time (GMT).  An example of this
+format is:
+
+   Thu, 03 Feb 1994 17:09:00 GMT
+
+=item str2time($str [, $zone])
+
+The str2time() function converts a string to machine time.  It returns
+C<undef> if the format is unrecognized, or the year is not between 1970
+and 2038.  The function is able to parse the following formats:
+
+ "Wed, 09 Feb 1994 22:23:32 GMT"       -- HTTP format
+ "Thu Feb  3 17:03:55 GMT 1994"        -- ctime(3) format
+ "Thu Feb  3 00:00:00 1994",           -- ANSI C asctime() format
+ "Tuesday, 08-Feb-94 14:15:29 GMT"     -- old rfc850 HTTP format
+ "Tuesday, 08-Feb-1994 14:15:29 GMT"   -- broken rfc850 HTTP format
+
+ "03/Feb/1994:17:03:55 -0700"   -- common logfile format
+ "09 Feb 1994 22:23:32 GMT"     -- HTTP format (no weekday)
+ "08-Feb-94 14:15:29 GMT"       -- rfc850 format (no weekday)
+ "08-Feb-1994 14:15:29 GMT"     -- broken rfc850 format (no weekday)
+
+ "1994-02-03 14:15:29 -0100"    -- ISO 8601 format
+ "1994-02-03 14:15:29"          -- zone is optional
+ "1994-02-03"                   -- only date
+ "1994-02-03T14:15:29"          -- Use T as separator
+ "19940203T141529Z"             -- ISO 8601 compact format
+ "19940203"                     -- only date
+
+ "08-Feb-94"         -- old rfc850 HTTP format    (no weekday, no time)
+ "08-Feb-1994"       -- broken rfc850 HTTP format (no weekday, no time)
+ "09 Feb 1994"       -- proposed new HTTP format  (no weekday, no time)
+ "03/Feb/1994"       -- common logfile format     (no time, no offset)
+
+ "Feb  3  1994"      -- Unix 'ls -l' format
+ "Feb  3 17:03"      -- Unix 'ls -l' format
+
+ "11-15-96  03:52PM" -- Windows 'dir' format
+
+The parser ignores leading and trailing whitespace.  It also allow the
+seconds to be missing and the month to be numerical in most formats.
+
+The str2time() function takes an optional second argument that
+specifies the default time zone to use when converting the date.  This
+zone specification should be numerical (like "-0800" or "+0100") or
+"GMT".  This parameter is ignored if the zone is specified in the date
+string itself.  It this parameter is missing, and the date string
+format does not contain any zone specification then the local time
+zone is assumed.
+
+If the year is missing, then we assume that the date is the first
+matching date I<before> current time.
+
+=back
+
+=head1 BUGS
+
+Non-numerical time zones (like MET, PST) are all treated like GMT.
+Do not use them.  HTTP does not use them.
+
+The str2time() function has been told how to parse far too many
+formats.  This makes the module name misleading. To be sure it is
+really misleading you can also import the time2iso() and time2isoz()
+functions.  They work like time2str() but produce ISO-8601 formated
+strings (YYYY-MM-DD hh:mm:ss).
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+sub Version { $VERSION; }
+
+require 5.002;
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(time2str str2time);
+@EXPORT_OK = qw(time2iso time2isoz);
+
+use Time::Local ();
+
+use strict;
+use vars qw(@DoW @MoY %MoY);
+
+#@DoW = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday);
+@DoW = qw(Sun Mon Tue Wed Thu Fri Sat);
+@MoY = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+# Build %MoY hash
+my $i = 0;
+foreach(@MoY) {
+   $MoY{lc $_} = $i++;
+}
+
+my($current_month, $current_year) = (localtime)[4, 5];
+
+
+
+
+sub time2str (;$)
+{
+   my $time = shift;
+   $time = time unless defined $time;
+   my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($time);
+   sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
+	   $DoW[$wday],
+	   $mday, $MoY[$mon], $year+1900,
+	   $hour, $min, $sec);
+}
+
+
+
+sub str2time ($;$)
+{
+   local($_) = shift;
+   return undef unless defined;
+   my($default_zone) = @_;
+
+   # Remove useless weekday, if it exists
+   s/^\s*(?:sun|mon|tue|wed|thu|fri|sat)\w*,?\s*//i;
+
+   my($day, $mon, $yr, $hr, $min, $sec, $tz, $aorp);
+   my $offset = 0;  # used when compensating for timezone
+
+ PARSEDATE: {
+      # Then we are able to check for most of the formats with this regexp
+      ($day,$mon,$yr,$hr,$min,$sec,$tz) =
+	/^\s*
+	 (\d\d?)               # day
+	    (?:\s+|[-\/])
+	 (\w+)                 # month
+	    (?:\s+|[-\/])
+	 (\d+)                 # year
+	 (?:
+	       (?:\s+|:)       # separator before clock
+	    (\d\d?):(\d\d)     # hour:min
+	    (?::(\d\d))?       # optional seconds
+	 )?                    # optional clock
+	    \s*
+	 ([-+]?\d{2,4}|GMT|gmt)? # timezone
+	    \s*$
+	/x
+	  and last PARSEDATE;
+
+      # Try the ctime and asctime format
+      ($mon, $day, $hr, $min, $sec, $tz, $yr) =
+	/^\s*                  # allow intial whitespace
+	 (\w{1,3})             # month
+	    \s+
+	 (\d\d?)               # day
+	    \s+
+	 (\d\d?):(\d\d)        # hour:min
+	 (?::(\d\d))?          # optional seconds
+	    \s+
+	 (?:(GMT|gmt)\s+)?     # optional GMT timezone
+	 (\d+)                 # year
+	    \s*$               # allow trailing whitespace
+	/x
+	  and last PARSEDATE;
+
+      # Then the Unix 'ls -l' date format
+      ($mon, $day, $yr, $hr, $min, $sec) =
+	/^\s*
+	 (\w{3})               # month
+	    \s+
+	 (\d\d?)               # day
+	    \s+
+	 (?:
+	    (\d\d\d\d) |       # year
+	    (\d{1,2}):(\d{2})  # hour:min
+            (?::(\d\d))?       # optional seconds
+	 )
+	 \s*$
+       /x
+	 and last PARSEDATE;
+
+      # ISO 8601 format '1996-02-29 12:00:00 -0100' and variants
+      ($yr, $mon, $day, $hr, $min, $sec, $tz) =
+	/^\s*
+	  (\d{4})              # year
+	     [-\/]?
+	  (\d\d?)              # numerical month
+	     [-\/]?
+	  (\d\d?)              # day
+	 (?:
+	       (?:\s+|:|T|-)   # separator before clock
+	    (\d\d?):?(\d\d)    # hour:min
+	    (?::?(\d\d))?      # optional seconds
+	 )?                    # optional clock
+	    \s*
+	 ([-+]?\d\d?:?(:?\d\d)?
+	  |Z|z)?               # timezone  (Z is "zero meridian", i.e. GMT)
+	    \s*$
+	/x
+	  and last PARSEDATE;
+
+      # Windows 'dir' 11-12-96  03:52PM
+      ($mon, $day, $yr, $hr, $min, $aorp) =
+        /^\s*
+          (\d{2})                # numerical month
+             -
+          (\d{2})                # day
+             -
+          (\d{2})                # year
+             \s+
+          (\d\d?):(\d\d)([apAP][mM])  # hour:min AM or PM
+             \s*$
+        /x
+          and last PARSEDATE;
+
+      # If it is not recognized by now we give up
+      return undef;
+   }
+
+   # Translate month name to number
+   if ($mon =~ /^\d+$/) {
+     # numeric month
+     return undef if $mon < 1 || $mon > 12;
+     $mon--;
+   } else {
+     $mon = lc $mon;
+     return undef unless exists $MoY{$mon};
+     $mon = $MoY{$mon};
+   }
+
+   # If the year is missing, we assume some date before the current,
+   # because these date are mostly present on "ls -l" listings.
+   unless (defined $yr) {
+	$yr = $current_year;
+	$yr-- if $mon > $current_month;
+    }
+
+   # Then we check if the year is acceptable
+   return undef if $yr > 99 && $yr < 1900;  # We ignore these years
+   $yr += 100 if $yr < 50;  # a stupid thing to do???
+   $yr -= 1900 if $yr >= 1900;
+   # The $yr is now relative to 1900 (as expected by timelocal())
+
+   # timelocal() seems to go into an infinite loop if it is given out
+   # of range parameters.  Let's check the year at least.
+
+   # Epoch counter maxes out in year 2038, assuming "time_t" is 32 bit
+   return undef if $yr > 138;
+   return undef if $yr <  70;  # 1970 is Unix epoch
+
+   # Compensate for AM/PM
+   if ($aorp) {
+       $aorp = uc $aorp;
+       $hr = 0 if $hr == 12 && $aorp eq 'AM';
+       $hr += 12 if $aorp eq 'PM' && $hr != 12;
+   }
+
+   # Make sure things are defined
+   for ($sec, $min, $hr) {  $_ = 0 unless defined   }
+
+   # Should we compensate for the timezone?
+   $tz = $default_zone unless defined $tz;
+   return eval {Time::Local::timelocal($sec, $min, $hr, $day, $mon, $yr)}
+     unless defined $tz;
+
+   # We can calculate offset for numerical time zones
+   if ($tz =~ /^([-+])?(\d\d?):?(\d\d)?$/) {
+       $offset = 3600 * $2;
+       $offset += 60 * $3 if $3;
+       $offset *= -1 if $1 && $1 ne '-';
+   }
+   eval{Time::Local::timegm($sec, $min, $hr, $day, $mon, $yr) + $offset};
+}
+
+
+
+# And then some bloat because I happen to like the ISO 8601 time
+# format.
+
+sub time2iso (;$)
+{
+   my $time = shift;
+   $time = time unless defined $time;
+   my($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
+   sprintf("%04d-%02d-%02d %02d:%02d:%02d",
+	   $year+1900, $mon+1, $mday, $hour, $min, $sec);
+}
+
+
+sub time2isoz (;$)
+{
+    my $time = shift;
+    $time = time unless defined $time;
+    my($sec,$min,$hour,$mday,$mon,$year) = gmtime($time);
+    sprintf("%04d-%02d-%02d %02d:%02d:%02dZ",
+            $year+1900, $mon+1, $mday, $hour, $min, $sec);
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers.pm	(revision 10506)
@@ -0,0 +1,540 @@
+#
+# $Id$
+
+package HTTP::Headers;
+
+=head1 NAME
+
+HTTP::Headers - Class encapsulating HTTP Message headers
+
+=head1 SYNOPSIS
+
+ require HTTP::Headers;
+ $h = new HTTP::Headers;
+
+=head1 DESCRIPTION
+
+The C<HTTP::Headers> class encapsulates HTTP-style message headers.
+The headers consist of attribute-value pairs, which may be repeated,
+and which are printed in a particular order.
+
+Instances of this class are usually created as member variables of the
+C<HTTP::Request> and C<HTTP::Response> classes, internal to the
+library.
+
+The following methods are available:
+
+=over 4
+
+=cut
+
+use strict;
+use vars qw($VERSION $TRANSLATE_UNDERSCORE);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use Carp ();
+
+# Could not use the AutoLoader becase several of the method names are
+# not unique in the first 8 characters.
+#use SelfLoader;
+
+
+# "Good Practice" order of HTTP message headers:
+#    - General-Headers
+#    - Request-Headers
+#    - Response-Headers
+#    - Entity-Headers
+# (From draft-ietf-http-v11-spec-rev-01, Nov 21, 1997)
+
+my @header_order = qw(
+   Cache-Control Connection Date Pragma Transfer-Encoding Upgrade Trailer Via
+
+   Accept Accept-Charset Accept-Encoding Accept-Language
+   Authorization Expect From Host
+   If-Modified-Since If-Match If-None-Match If-Range If-Unmodified-Since
+   Max-Forwards Proxy-Authorization Range Referer TE User-Agent
+
+   Accept-Ranges Age Location Proxy-Authenticate Retry-After Server Vary
+   Warning WWW-Authenticate
+
+   Allow Content-Base Content-Encoding Content-Language Content-Length
+   Content-Location Content-MD5 Content-Range Content-Type
+   ETag Expires Last-Modified
+);
+
+# Make alternative representations of @header_order.  This is used
+# for sorting and case matching.
+my $i = 0;
+my %header_order;
+my %standard_case;
+for (@header_order) {
+    my $lc = lc $_;
+    $header_order{$lc} = $i++;
+    $standard_case{$lc} = $_;
+}
+
+$TRANSLATE_UNDERSCORE = 1 unless defined $TRANSLATE_UNDERSCORE;
+
+
+
+=item $h = new HTTP::Headers
+
+Constructs a new C<HTTP::Headers> object.  You might pass some initial
+attribute-value pairs as parameters to the constructor.  I<E.g.>:
+
+ $h = new HTTP::Headers
+     Date         => 'Thu, 03 Feb 1994 00:00:00 GMT',
+     Content_Type => 'text/html; version=3.2',
+     Content_Base => 'http://www.sn.no/';
+
+=cut
+
+sub new
+{
+    my($class) = shift;
+    my $self = bless {}, $class;
+    $self->header(@_); # set up initial headers
+    $self;
+}
+
+
+=item $h->header($field [=> $value],...)
+
+Get or set the value of a header.  The header field name is not case
+sensitive.  To make the life easier for perl users who wants to avoid
+quoting before the => operator, you can use '_' as a synonym for '-'
+in header names (this behaviour can be suppressed by setting
+$HTTP::Headers::TRANSLATE_UNDERSCORE to a FALSE value).
+
+The header() method accepts multiple ($field => $value) pairs, so you
+can update several fields with a single invocation.
+
+The optional $value argument may be a scalar or a reference to a list
+of scalars. If the $value argument is undefined or not given, then the
+header is not modified.
+
+The old value of the last of the $field values is returned.
+Multi-valued fields will be concatenated with "," as separator in
+scalar context.
+
+ $header->header(MIME_Version => '1.0',
+		 User_Agent   => 'My-Web-Client/0.01');
+ $header->header(Accept => "text/html, text/plain, image/*");
+ $header->header(Accept => [qw(text/html text/plain image/*)]);
+ @accepts = $header->header('Accept');
+
+=cut
+
+sub header
+{
+    my $self = shift;
+    my($field, $val, @old);
+    while (($field, $val) = splice(@_, 0, 2)) {
+	@old = $self->_header($field, $val);
+    }
+    return @old if wantarray;
+    return $old[0] if @old <= 1;
+    join(", ", @old);
+}
+
+sub _header
+{
+    my($self, $field, $val, $push) = @_;
+    $field =~ tr/_/-/ if $TRANSLATE_UNDERSCORE;
+
+    # $push is only used interally sub push_header
+    Carp::croak('Need a field name') unless length($field);
+
+    my $lc_field = lc $field;
+    unless(defined $standard_case{$lc_field}) {
+	# generate a %stadard_case entry for this field
+	$field =~ s/\b(\w)/\u$1/g;
+	$standard_case{$lc_field} = $field;
+    }
+
+    my $h = $self->{$lc_field};
+    my @old = ref($h) ? @$h : (defined($h) ? ($h) : ());
+
+    if (defined $val) {
+	my @new = $push ? @old : ();
+	if (!ref($val)) {
+	    push(@new, $val);
+	} elsif (ref($val) eq 'ARRAY') {
+	    push(@new, @$val);
+	} else {
+	    Carp::croak("Unexpected field value $val");
+	}
+	$self->{$lc_field} = @new > 1 ? \@new : $new[0];
+    }
+    @old;
+}
+
+
+# Compare function which makes it easy to sort headers in the
+# recommended "Good Practice" order.
+sub _header_cmp
+{
+    # Unknown headers are assign a large value so that they are
+    # sorted last.  This also helps avoiding a warning from -w
+    # about comparing undefined values.
+    $header_order{$a} = 999 unless defined $header_order{$a};
+    $header_order{$b} = 999 unless defined $header_order{$b};
+
+    $header_order{$a} <=> $header_order{$b} || $a cmp $b;
+}
+
+
+=item $h->scan(\&doit)
+
+Apply a subroutine to each header in turn.  The callback routine is
+called with two parameters; the name of the field and a single value.
+If the header has more than one value, then the routine is called once
+for each value.  The field name passed to the callback routine has
+case as suggested by HTTP Spec, and the headers will be visited in the
+recommended "Good Practice" order.
+
+=cut
+
+sub scan
+{
+    my($self, $sub) = @_;
+    my $key;
+    foreach $key (sort _header_cmp keys %$self) {
+        next if $key =~ /^_/;
+	my $vals = $self->{$key};
+	if (ref($vals)) {
+	    my $val;
+	    for $val (@$vals) {
+		&$sub($standard_case{$key} || $key, $val);
+	    }
+	} else {
+	    &$sub($standard_case{$key} || $key, $vals);
+	}
+    }
+}
+
+
+=item $h->as_string([$endl])
+
+Return the header fields as a formatted MIME header.  Since it
+internally uses the C<scan()> method to build the string, the result
+will use case as suggested by HTTP Spec, and it will follow
+recommended "Good Practice" of ordering the header fieds.  Long header
+values are not folded. 
+
+The optional parameter specifies the line ending sequence to use.  The
+default is C<"\n">.  Embedded "\n" characters in the header will be
+substitued with this line ending sequence.
+
+=cut
+
+sub as_string
+{
+    my($self, $endl) = @_;
+    $endl = "\n" unless defined $endl;
+
+    my @result = ();
+    $self->scan(sub {
+	my($field, $val) = @_;
+	if ($val =~ /\n/) {
+	    # must handle header values with embedded newlines with care
+	    $val =~ s/\s+$//;          # trailing newlines and space must go
+	    $val =~ s/\n\n+/\n/g;      # no empty lines
+	    $val =~ s/\n([^\040\t])/\n $1/g;  # intial space for continuation
+	    $val =~ s/\n/$endl/g;      # substitute with requested line ending
+	}
+	push(@result, "$field: $val");
+    });
+
+    join($endl, @result, '');
+}
+
+
+# The remaining functions should autoloaded only when needed
+
+# A bug in 5.002gamma makes it risky to have POD text inside the
+# autoloaded section of the code, so we keep the documentation before
+# the __DATA__ token.
+
+=item $h->push_header($field, $val)
+
+Add a new field value of the specified header.  The header field name
+is not case sensitive.  The field need not already have a
+value. Previous values for the same field are retained.  The argument
+may be a scalar or a reference to a list of scalars.
+
+ $header->push_header(Accept => 'image/jpeg');
+
+=item $h->remove_header($field,...)
+
+This function removes the headers with the specified names.
+
+=item $h->clone
+
+Returns a copy of this HTTP::Headers object.
+
+=back
+
+=head1 CONVENIENCE METHODS
+
+The most frequently used headers can also be accessed through the
+following convenience methods.  These methods can both be used to read
+and to set the value of a header.  The header value is set if you pass
+an argument to the method.  The old header value is always returned.
+
+Methods that deal with dates/times always convert their value to system
+time (seconds since Jan 1, 1970) and they also expect this kind of
+value when the header value is set.
+
+=over 4
+
+=item $h->date
+
+This header represents the date and time at which the message was
+originated. I<E.g.>:
+
+  $h->date(time);  # set current date
+
+=item $h->expires
+
+This header gives the date and time after which the entity should be
+considered stale.
+
+=item $h->if_modified_since
+
+=item $h->if_unmodified_since
+
+This header is used to make a request conditional.  If the requested
+resource has (not) been modified since the time specified in this field,
+then the server will return a C<"304 Not Modified"> response instead of
+the document itself.
+
+=item $h->last_modified
+
+This header indicates the date and time at which the resource was last
+modified. I<E.g.>:
+
+  # check if document is more than 1 hour old
+  if ($h->last_modified < time - 60*60) {
+	...
+  }
+
+=item $h->content_type
+
+The Content-Type header field indicates the media type of the message
+content. I<E.g.>:
+
+  $h->content_type('text/html');
+
+The value returned will be converted to lower case, and potential
+parameters will be chopped off and returned as a separate value if in
+an array context.  This makes it safe to do the following:
+
+  if ($h->content_type eq 'text/html') {
+     # we enter this place even if the real header value happens to
+     # be 'TEXT/HTML; version=3.0'
+     ...
+  }
+
+=item $h->content_encoding
+
+The Content-Encoding header field is used as a modifier to the
+media type.  When present, its value indicates what additional
+encoding mechanism has been applied to the resource.
+
+=item $h->content_length
+
+A decimal number indicating the size in bytes of the message content.
+
+=item $h->content_language
+
+The natural language(s) of the intended audience for the message
+content.  The value is one or more language tags as defined by RFC
+1766.  Eg. "no" for Norwegian and "en-US" for US-English.
+
+=item $h->title
+
+The title of the document.  In libwww-perl this header will be
+initialized automatically from the E<lt>TITLE>...E<lt>/TITLE> element
+of HTML documents.  I<This header is no longer part of the HTTP
+standard.>
+
+=item $h->user_agent
+
+This header field is used in request messages and contains information
+about the user agent originating the request.  I<E.g.>:
+
+  $h->user_agent('Mozilla/1.2');
+
+=item $h->server
+
+The server header field contains information about the software being
+used by the originating server program handling the request.
+
+=item $h->from
+
+This header should contain an Internet e-mail address for the human
+user who controls the requesting user agent.  The address should be
+machine-usable, as defined by RFC822.  E.g.:
+
+  $h->from('Gisle Aas <aas@sn.no>');
+
+=item $h->referer
+
+Used to specify the address (URI) of the document from which the
+requested resouce address was obtained.
+
+=item $h->www_authenticate
+
+This header must be included as part of a "401 Unauthorized" response.
+The field value consist of a challenge that indicates the
+authentication scheme and parameters applicable to the requested URI.
+
+=item $h->proxy_authenticate
+
+This header must be included in a "407 Proxy Authentication Required"
+response.
+
+=item $h->authorization
+
+=item $h->proxy_authorization
+
+A user agent that wishes to authenticate itself with a server or a
+proxy, may do so by including these headers.
+
+=item $h->authorization_basic
+
+This method is used to get or set an authorization header that use the
+"Basic Authentication Scheme".  In array context it will return two
+values; the user name and the password.  In scalar context it will
+return I<"uname:password"> as a single string value.
+
+When used to set the header value, it expects two arguments.  I<E.g.>:
+
+  $h->authorization_basic($uname, $password);
+
+The method will croak if the $uname contains a colon ':'.
+
+=item $h->proxy_authorization_basic
+
+Same as authorization_basic() but will set the "Proxy-Authorization"
+header instead.
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright 1995-1998 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+1;
+
+#__DATA__
+
+sub clone
+{
+    my $self = shift;
+    my $clone = new HTTP::Headers;
+    $self->scan(sub { $clone->push_header(@_);} );
+    $clone;
+}
+
+sub push_header
+{
+    Carp::croak('Usage: $h->push_header($field, $val)') if @_ != 3;
+    shift->_header(@_, 'PUSH');
+}
+
+
+sub remove_header
+{
+    my($self, @fields) = @_;
+    my $field;
+    foreach $field (@fields) {
+	$field =~ tr/_/-/ if $TRANSLATE_UNDERSCORE;
+	delete $self->{lc $field};
+    }
+}
+
+# Convenience access functions
+
+sub _date_header
+{
+    require HTTP::Date;
+    my($self, $header, $time) = @_;
+    my($old) = $self->_header($header);
+    if (defined $time) {
+	$self->_header($header, HTTP::Date::time2str($time));
+    }
+    HTTP::Date::str2time($old);
+}
+
+sub date                { shift->_date_header('Date',                @_); }
+sub expires             { shift->_date_header('Expires',             @_); }
+sub if_modified_since   { shift->_date_header('If-Modified-Since',   @_); }
+sub if_unmodified_since { shift->_date_header('If-Unmodified-Since', @_); }
+sub last_modified       { shift->_date_header('Last-Modified',       @_); }
+
+# This is used as a private LWP extention.  The Client-Date header is
+# added as a timestamp to a response when it has been received.
+sub client_date         { shift->_date_header('Client-Date',         @_); }
+
+# The retry_after field is dual format (can also be a expressed as
+# number of seconds from now), so we don't provide an easy way to
+# access it until we have know how both these interfaces can be
+# addressed.  One possibility is to return a negative value for
+# relative seconds and a positive value for epoch based time values.
+#sub retry_after       { shift->_date_header('Retry-After',       @_); }
+
+sub content_type      {
+  my $ct = (shift->_header('Content-Type', @_))[0];
+  return '' unless defined($ct) && length($ct);
+  my @ct = split(/\s*;\s*/, lc($ct));
+  wantarray ? @ct : $ct[0];
+}
+
+sub title             { (shift->_header('Title',            @_))[0] }
+sub content_encoding  { (shift->_header('Content-Encoding', @_))[0] }
+sub content_language  { (shift->_header('Content-Language', @_))[0] }
+sub content_length    { (shift->_header('Content-Length',   @_))[0] }
+
+sub user_agent        { (shift->_header('User-Agent',       @_))[0] }
+sub server            { (shift->_header('Server',           @_))[0] }
+
+sub from              { (shift->_header('From',             @_))[0] }
+sub referer           { (shift->_header('Referer',          @_))[0] }
+sub warning           { (shift->_header('Warning',          @_))[0] }
+
+sub www_authenticate  { (shift->_header('WWW-Authenticate', @_))[0] }
+sub authorization     { (shift->_header('Authorization',    @_))[0] }
+
+sub proxy_authenticate  { (shift->_header('Proxy-Authenticate',  @_))[0] }
+sub proxy_authorization { (shift->_header('Proxy-Authorization', @_))[0] }
+
+sub authorization_basic       { shift->_basic_auth("Authorization",       @_) }
+sub proxy_authorization_basic { shift->_basic_auth("Proxy-Authorization", @_) }
+
+sub _basic_auth {
+    require MIME::Base64;
+    my($self, $h, $user, $passwd) = @_;
+    my($old) = $self->_header($h);
+    if (defined $user) {
+	Carp::croak("Basic authorization user name can't contain ':'")
+	  if $user =~ /:/;
+	$passwd = '' unless defined $passwd;
+	$self->_header($h => 'Basic ' .
+                             MIME::Base64::encode("$user:$passwd", ''));
+    }
+    if (defined $old && $old =~ s/^\s*Basic\s+//) {
+	my $val = MIME::Base64::decode($old);
+	return $val unless wantarray;
+	return split(/:/, $val, 2);
+    }
+    return;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Auth.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Auth.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Auth.pm	(revision 10506)
@@ -0,0 +1,94 @@
+package HTTP::Headers::Auth;
+
+use strict;
+use vars qw($VERSION);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+require HTTP::Headers;
+package HTTP::Headers;
+
+BEGIN {
+    # we provide a new (and better) implementations below
+    undef(&www_authenticate);
+    undef(&proxy_authenticate);
+}
+
+require HTTP::Headers::Util;
+
+sub _parse_authenticate
+{
+    my @ret;
+    for (HTTP::Headers::Util::split_header_words(@_)) {
+	if (!defined($_->[1])) {
+	    # this is a new auth scheme
+	    push(@ret, lc(shift @$_) => {});
+	    shift @$_;
+	}
+	if (@ret) {
+	    # this a new parameter pair for the last auth scheme
+	    while (@$_) {
+		my $k = lc(shift @$_);
+		my $v = shift @$_;
+	        $ret[-1]{$k} = $v;
+	    }
+	} else {
+	    # something wrong, parameter pair without any scheme seen
+	    # IGNORE
+	}
+    }
+    @ret;
+}
+
+sub _authenticate
+{
+    my $self = shift;
+    my $header = shift;
+    my @old = $self->_header($header);
+    if (@_) {
+	$self->remove_header($header);
+	my @new = @_;
+	while (@new) {
+	    my $a_scheme = shift(@new);
+	    if ($a_scheme =~ /\s/) {
+		# assume complete valid value, pass it through
+		$self->push_header($header, $a_scheme);
+	    } else {
+		my @param;
+		if (@new) {
+		    my $p = $new[0];
+		    if (ref($p) eq "ARRAY") {
+			@param = @$p;
+			shift(@new);
+		    } elsif (ref($p) eq "HASH") {
+			@param = %$p;
+			shift(@new);
+		    }
+		}
+		my $val = ucfirst(lc($a_scheme));
+		if (@param) {
+		    my $sep = " ";
+		    while (@param) {
+			my $k = shift @param;
+			my $v = shift @param;
+			if ($v =~ /[^0-9a-zA-Z]/ || lc($k) eq "realm") {
+			    # must quote the value
+			    $v =~ s,([\\\"]),\\$1,g;
+			    $v = qq("$v");
+			}
+			$val .= "$sep$k=$v";
+			$sep = ", ";
+		    }
+		}
+		$self->push_header($header, $val);
+	    }
+	}
+    }
+    return unless defined wantarray;
+    wantarray ? _parse_authenticate(@old) : join(", ", @old);
+}
+
+
+sub www_authenticate    { shift->_authenticate("WWW-Authenticate", @_)   }
+sub proxy_authenticate  { shift->_authenticate("Proxy-Authenticate", @_) }
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/ETag.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/ETag.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/ETag.pm	(revision 10506)
@@ -0,0 +1,88 @@
+package HTTP::Header::ETag;
+
+use strict;
+use vars qw($VERSION);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+require HTTP::Date;
+
+require HTTP::Headers;
+package HTTP::Headers;
+
+sub _etags
+{
+    my $self = shift;
+    my $header = shift;
+    my @old = _split_etag_list($self->_header($header));
+    if (@_) {
+	$self->_header($header => join(", ", _split_etag_list(@_)));
+    }
+    wantarray ? @old : join(", ", @old);
+}
+
+sub etag          { shift->_etags("ETag", @_); }
+sub if_match      { shift->_etags("If-Match", @_); }
+sub if_none_match { shift->_etags("If-None-Match", @_); }
+
+sub if_range {
+    # Either a date or an entity-tag
+    my $self = shift;
+    my @old = $self->_header("If-Range");
+    if (@_) {
+	my $new = shift;
+	if (!defined $new) {
+	    $self->remove_header("If-Range");
+	} elsif ($new =~ /^\d+$/) {
+	    $self->_date_header("If-Range", $new);
+	} else {
+	    $self->_etags("If-Range", $new);
+	}
+    }
+    return unless defined(wantarray);
+    for (@old) {
+	my $t = HTTP::Date::str2time($_);
+	$_ = $t if $t;
+    }
+    wantarray ? @old : join(", ", @old);
+}
+
+
+# Split a list of entity tag values.  The return value is a list
+# consisting of one element per entity tag.  Suitable for parsing
+# headers like C<If-Match>, C<If-None-Match>.  You might even want to
+# use it on C<ETag> and C<If-Range> entity tag values, because it will
+# normalize them to the common form.
+#
+#  entity-tag	  = [ weak ] opaque-tag
+#  weak		  = "W/"
+#  opaque-tag	  = quoted-string
+
+
+sub _split_etag_list
+{
+    my(@val) = @_;
+    my @res;
+    for (@val) {
+        while (length) {
+            my $weak = "";
+	    $weak = "W/" if s,^\s*[wW]/,,;
+            my $etag = "";
+	    if (s/^\s*(\"[^\"\\]*(?:\\.[^\"\\]*)*\")//) {
+		push(@res, "$weak$1");
+            } elsif (s/^\s*,//) {
+                push(@res, qq(W/"")) if $weak;
+            } elsif (s/^\s*([^,\s]+)//) {
+                $etag = $1;
+		$etag =~ s/([\"\\])/\\$1/g;
+	        push(@res, qq($weak"$etag"));
+            } elsif (s/^\s+// || !length) {
+                push(@res, qq(W/"")) if $weak;
+            } else {
+	 	die "This should not happen: '$_'";
+            }
+        }
+   }
+   @res;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Util.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Util.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Headers/Util.pm	(revision 10506)
@@ -0,0 +1,180 @@
+package HTTP::Headers::Util;
+
+use strict;
+use vars qw($VERSION @ISA @EXPORT_OK);
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+require Exporter;
+@ISA=qw(Exporter);
+
+@EXPORT_OK=qw(split_header_words join_header_words);
+
+=head1 NAME
+
+HTTP::Headers::Util - Header value parsing utility functions
+
+=head1 SYNOPSIS
+
+  use HTTP::Headers::Util qw(split_header_words);
+  @values = split_header_words($h->header("Content-Type"));
+
+=head1 DESCRIPTION
+
+This module provide a few functions that helps parsing and
+construction of valid HTTP header values.  None of the functions are
+exported by default.
+
+The following functions are provided:
+
+=over 4
+
+
+=item split_header_words( @header_values )
+
+This function will parse the header values given as argument into a
+list of anonymous arrays containing key/value pairs.  The function
+know how to deal with ",", ";" and "=" as well as quoted values after
+"=".  A list of space separated tokens are parsed as if they were
+separated by ";".
+
+If the @header_values passed as argument contains multiple values,
+then they are treated as if they were a single value separated by
+comma ",".
+
+This means that this function is useful to parse header fields that
+follow this syntax (BNF as from the HTTP/1.1 specification, but we relax
+the requirement for tokens).
+
+  headers           = #header
+  header            = (token | parameter) *( [";"] (token | parameter))
+
+  token             = 1*<any CHAR except CTLs or separators>
+  separators        = "(" | ")" | "<" | ">" | "@"
+                    | "," | ";" | ":" | "\" | <">
+                    | "/" | "[" | "]" | "?" | "="
+                    | "{" | "}" | SP | HT
+
+  quoted-string     = ( <"> *(qdtext | quoted-pair ) <"> )
+  qdtext            = <any TEXT except <">>
+  quoted-pair       = "\" CHAR
+
+  parameter         = attribute "=" value
+  attribute         = token
+  value             = token | quoted-string
+
+Each I<header> is represented by an anonymous array of key/value
+pairs.  If a token is recognized then the value will be C<undef>.
+Syntactically incorrect headers will not necessary be parsed as you
+would want.
+
+This is easier to describe with some examples:
+
+   split_header_words('foo="bar"; port="80,81"; discard, bar=baz')
+   split_header_words('text/html; charset="iso-8859-1");
+   split_header_words('Basic realm="\"foo\\bar\""');
+
+will return
+
+   [foo=>'bar', port=>'80,81', discard=> undef], [bar=>'baz' ]
+   ['text/html' => undef, charset => 'iso-8859-1']
+   [Basic => undef, realm => '"foo\bar"']
+
+=cut
+
+
+sub split_header_words
+{
+    my(@val) = @_;
+    my @res;
+    for (@val) {
+	my @cur;
+	while (length) {
+	    if (s/^\s*(=*[^\s=;,]+)//) {  # 'token' or parameter 'attribute'
+		push(@cur, $1);
+		# a quoted value
+		if (s/^\s*=\s*\"([^\"\\]*(?:\\.[^\"\\]*)*)\"//) {
+		    my $val = $1;
+		    $val =~ s/\\(.)/$1/g;
+		    push(@cur, $val);
+		# some unquoted value
+		} elsif (s/^\s*=\s*([^;,\s]*)//) {
+		    my $val = $1;
+		    $val =~ s/\s+$//;
+		    push(@cur, $val);
+		# no value, a lone token
+		} else {
+		    push(@cur, undef);
+		}
+	    } elsif (s/^\s*,//) {
+		push(@res, [@cur]) if @cur;
+		@cur = ();
+	    } elsif (s/^\s*;// || s/^\s+//) {
+		# continue
+	    } else {
+		die "This should not happen: '$_'";
+	    }
+	}
+	push(@res, \@cur) if @cur;
+    }
+    @res;
+}
+
+
+=item join_header_words( @arrays )
+
+This will do the opposite convertion of what split_header_words()
+does.  It takes a list of anonymous arrays as argument (or a list of
+key/value pairs) and produce a single header value.  Attribute values
+are quoted if needed.
+
+Example:
+
+   join_header_words(["text/plain" => undef, charset => "iso-8859/1"]);
+   join_header_words(""text/plain" => undef, charset => "iso-8859/1");
+
+will both return the string:
+
+   text/plain; charset="iso-8859/1"
+
+=cut
+
+sub join_header_words
+{
+    @_ = ([@_]) if @_ && !ref($_[0]);
+    my @res;
+    for (@_) {
+	my @cur = @$_;
+	my @attr;
+	while (@cur) {
+	    my $k = shift @cur;
+	    my $v = shift @cur;
+	    if (defined $v) {
+		if ($v =~ /^\w+$/) {
+		    $k .= "=$v";
+		} else {
+		    $v =~ s/([\"\\])/\\$1/g;  # escape " and \
+		    $k .= qq(="$v");
+		}
+	    }
+	    push(@attr, $k);
+	}
+	push(@res, join("; ", @attr)) if @attr;
+    }
+    join(", ", @res);
+}
+
+1;
+
+__END__
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright 1997-1998, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Message.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Message.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Message.pm	(revision 10506)
@@ -0,0 +1,208 @@
+#
+# $Id$
+
+package HTTP::Message;
+
+=head1 NAME
+
+HTTP::Message - Class encapsulating HTTP messages
+
+=head1 SYNOPSIS
+
+ package HTTP::Request;  # or HTTP::Response
+ require HTTP::Message;
+ @ISA=qw(HTTP::Message);
+
+=head1 DESCRIPTION
+
+A C<HTTP::Message> object contains some headers and a content (body).
+The class is abstract, i.e. it only used as a base class for
+C<HTTP::Request> and C<HTTP::Response> and should never instantiated
+as itself.
+
+The following methods are available:
+
+=over 4
+
+=cut
+
+#####################################################################
+
+require HTTP::Headers;
+require Carp;
+use strict;
+use vars qw($VERSION $AUTOLOAD);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+=item $mess = new HTTP::Message;
+
+This is the object constructor.  It should only be called internally
+by this library.  External code should construct C<HTTP::Request> or
+C<HTTP::Response> objects.
+
+=cut
+
+sub new
+{
+    my($class, $header, $content) = @_;
+    if (defined $header) {
+	Carp::croak("Bad header argument") unless ref $header;
+	$header = $header->clone;
+    } else {
+	$header = HTTP::Headers->new;
+    }
+    $content = '' unless defined $content;
+    bless {
+	'_headers' => $header,
+	'_content' => $content,
+    }, $class;
+}
+
+
+=item $mess->clone()
+
+Returns a copy of the object.
+
+=cut
+
+sub clone
+{
+    my $self  = shift;
+    my $clone = HTTP::Message->new($self->{'_headers'}, $self->{'_content'});
+    $clone;
+}
+
+=item $mess->protocol([$proto])
+
+Sets the HTTP protocol used for the message.  The protocol() is a string
+like "HTTP/1.0" or "HTTP/1.1".
+
+=cut
+
+sub protocol { shift->_elem('_protocol',  @_); }
+
+=item $mess->content([$content])
+
+The content() method sets the content if an argument is given.  If no
+argument is given the content is not touched.  In either case the
+previous content is returned.
+
+=item $mess->add_content($data)
+
+The add_content() methods appends more data to the end of the previous
+content.
+
+=cut
+
+sub content   { shift->_elem('_content',  @_); }
+
+sub add_content
+{
+    my $self = shift;
+    if (ref($_[0])) {
+	$self->{'_content'} .= ${$_[0]};  # for backwards compatability
+    } else {
+	$self->{'_content'} .= $_[0];
+    }
+}
+
+=item $mess->content_ref
+
+The content_ref() method will return a reference to content string.
+It can be more efficient to access the content this way if the content
+is huge, and it can be used for direct manipulation of the content,
+for instance:
+
+  ${$res->content_ref} =~ s/\bfoo\b/bar/g;
+
+=cut
+
+sub content_ref
+{
+    my $self = shift;
+    \$self->{'_content'};
+}
+
+sub as_string
+{
+    "";  # To be overridden in subclasses
+}
+
+=item $mess->headers;
+
+Return the embedded HTTP::Headers object.
+
+=item $mess->headers_as_string([$endl])
+
+Call the HTTP::Headers->as_string() method for the headers in the
+message.
+
+=cut
+
+sub headers            { shift->{'_headers'};                }
+sub headers_as_string  { shift->{'_headers'}->as_string(@_); }
+
+=back
+
+All unknown C<HTTP::Message> methods are delegated to the
+C<HTTP::Headers> object that is part of every message.  This allows
+convenient access to these methods.  Refer to L<HTTP::Headers> for
+details of these methods:
+
+  $mess->header($field => $val);
+  $mess->scan(\&doit);
+  $mess->push_header($field => $val);
+  $mess->remove_header($field);
+
+  $mess->date;
+  $mess->expires;
+  $mess->if_modified_since;
+  $mess->if_unmodified_since;
+  $mess->last_modified;
+  $mess->content_type;
+  $mess->content_encoding;
+  $mess->content_length;
+  $mess->content_language
+  $mess->title;
+  $mess->user_agent;
+  $mess->server;
+  $mess->from;
+  $mess->referer;
+  $mess->www_authenticate;
+  $mess->authorization;
+  $mess->proxy_authorization;
+  $mess->authorization_basic;
+  $mess->proxy_authorization_basic;
+
+=cut
+
+
+# delegate all other method calls the the _headers object.
+sub AUTOLOAD
+{
+    my $self = shift;
+    my $method = substr($AUTOLOAD, rindex($AUTOLOAD, '::')+2);
+    return if $method eq "DESTROY";
+    $self->{'_headers'}->$method(@_);
+}
+
+# Private method to access members in %$self
+sub _elem
+{
+    my $self = shift;
+    my $elem = shift;
+    my $old = $self->{$elem};
+    $self->{$elem} = $_[0] if @_;
+    return $old;
+}
+
+1;
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Negotiate.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Negotiate.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Negotiate.pm	(revision 10506)
@@ -0,0 +1,505 @@
+# $Id$
+#
+
+package HTTP::Negotiate;
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+sub Version { $VERSION; }
+
+require 5.002;
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(choose);
+
+require HTTP::Headers;
+
+$DEBUG = 0;
+
+sub choose ($;$)
+{
+    my($variants, $request) = @_;
+    my(%accept);
+
+    unless (defined $request) {
+	# Create a request object from the CGI envirionment variables
+	$request = new HTTP::Headers;
+	$request->header('Accept', $ENV{HTTP_ACCEPT})
+	  if $ENV{HTTP_ACCEPT};
+	$request->header('Accept-Charset', $ENV{HTTP_ACCEPT_CHARSET})
+	  if $ENV{HTTP_ACCEPT_CHARSET};
+	$request->header('Accept-Encoding', $ENV{HTTP_ACCEPT_ENCODING})
+	  if $ENV{HTTP_ACCEPT_ENCODING};
+	$request->header('Accept-Language', $ENV{HTTP_ACCEPT_LANGUAGE})
+	  if $ENV{HTTP_ACCEPT_LANGUAGE};
+    }
+
+    # Get all Accept values from the request.  Build a hash initialized
+    # like this:
+    #
+    #   %accept = ( type =>     { 'audio/*'     => { q => 0.2, mbx => 20000 },
+    #                             'audio/basic' => { q => 1 },
+    #                           },
+    #               language => { 'no'          => { q => 1 },
+    #                           }
+    #             );
+
+    $request->scan(sub {
+	my($key, $val) = @_;
+	return unless $key =~ s/^Accept-?//;
+	my $type = lc $key;
+	$type = "type" unless length $key;
+	$val =~ s/\s+//g;
+	my $name;
+	for $name (split(/,/, $val)) {
+	    my(%param, $param);
+	    if ($name =~ s/;(.*)//) {
+		for $param (split(/;/, $1)) {
+		    my ($pk, $pv) = split(/=/, $param, 2);
+		    $param{$pk} = $pv;
+		}
+	    }
+	    $name = lc $name;
+	    if (defined $param{'q'}) {
+		$param{'q'} = 1 if $param{'q'} > 1;
+		$param{'q'} = 0 if $param{'q'} < 0;
+	    } else {
+		$param{'q'} = 1;
+	    }
+
+	    $param{'q'} = 1 unless defined $param{'q'};
+	    $accept{$type}{$name} = \%param;
+	}
+    });
+
+    # Check if any of the variants specify a language.  We do this
+    # because it influence how we treat those without (they default to
+    # 0.5 instead of 1).
+    my $any_lang = 0;
+    for $var (@$variants) {
+	if ($var->[5]) {
+	    $any_lang = 1;
+	    last;
+	}
+    }
+
+    if ($DEBUG) {
+	print "Netgotiantion parameters in the request\n";
+	for $type (keys %accept) {
+	    print " $type:\n";
+	    for $name (keys %{$accept{$type}}) {
+		print "    $name\n";
+		for $pv (keys %{$accept{$type}{$name}}) {
+		    print "      $pv = $accept{$type}{$name}{$pv}\n";
+		}
+	    }
+	}
+    }
+
+    my @Q = ();  # This is where we collect the results of the
+		 # quality calcualtions
+
+    # Calculate quality for all the variant's that are available.
+    for (@$variants) {
+	my($id, $qs, $ct, $enc, $cs, $lang, $bs) = @$_;
+	$qs = 1 unless defined $qs;
+	$bs = 0 unless defined $bs;
+	if ($DEBUG) {
+	    print "\nEvaluating $id ($ct)\n";
+	    printf "  qs   = %.3f\n", $qs;
+	    print  "  enc  = $enc\n"  if $enc && !ref($enc);
+	    print  "  enc  = @$enc\n" if $enc && ref($enc);
+	    print  "  cs   = $cs\n"   if $cs;
+	    print  "  lang = $lang\n" if $lang;
+	    print  "  bs   = $bs\n"   if $bs;
+	}
+
+	# Calculate encoding quality
+	my $qe = 1;
+	# If the variant has no assignes Content-Encoding, or if no
+	# Accept-Encoding field is present, then the value assigned
+	# is "qe=1".  If *all* of the variant's content encoddings
+	# are listed in the Accept-Encoding field, then the value
+	# assigned is "qw=1".  If *any* of the variant's content
+	# encodings are not listed in the provided Accept-Encoding
+	# field, then the value assigned is "qe=0"
+	if (exists $accept{'encoding'} && $enc) {
+	    my @enc = ref($enc) ? @$enc : ($enc);
+	    for (@enc) {
+		print "Is encoding $_ accepted? " if $DEBUG;
+		unless(exists $accept{'encoding'}{$_}) {
+		    print "no\n" if $DEBUG;
+		    $qe = 0;
+		    last;
+		} else {
+		    print "yes\n" if $DEBUG;
+		}
+	    }
+	}
+
+	# Calculate charset quality
+	my $qc  = 1;
+	# If the variant's media-type has not charset parameter,
+	# or the variant's charset is US-ASCII, or if no Accept-Charset
+	# field is present, then the value assigned is "qc=1".  If the
+	# variantæs charset is listed in the Accept-Charset field,
+	# then the value assigned is "qc=1.  Otherwise, if the variant's
+	# charset is not listed in the provided Accept-Encoding field,
+	# then the value assigned is "qc=0".
+	if (exists $accept{'charset'} && $cs && $cs ne 'us-ascii' ) {
+	    $qc = 0 unless $accept{'charset'}{$cs};
+	}
+
+	# Calculate language quality
+	my $ql  = 1;
+	if ($lang && exists $accept{'language'}) {
+	    my @lang = ref($lang) ? @$lang : ($lang);
+	    # If any of the variant's content languages are listed
+	    # in the Accept-Language field, the the value assigned is
+	    # the maximus of the "q" paramet values for thos language
+	    # tags.
+	    my $q = undef;
+	    for (@lang) {
+		next unless exists $accept{'language'}{$_};
+		my $this_q = $accept{'language'}{$_}{'q'};
+		$q = $this_q unless defined $q;
+		$q = $this_q if $this_q > $q;
+	    }
+	    unless (defined $q) {
+		# If there was no exact match and at least one of
+		# the Accept-Language field values is a complete
+		# subtag prefix of the content language tag(s), then
+		# the "q" parameter value of the largest matching
+		# prefix is used.
+		my $selected = undef;
+		for $al (keys %{ $accept{'language'} }) {
+		    if (substr($lang, 0, length($al)) eq $al) {
+			$selected = $al unless defined $selected;
+			$selected = $al if length($al) > length($selected);
+		    }
+		}
+		$q = $accept{'language'}{$selected}{'q'} if $selected;
+
+		# If none of the variant's content language tags or
+		# tag prefixes are listed in the provided
+		# Accept-Language field, then the value assigned
+		# is "ql=0.001"
+		$q = 0.001 unless defined $q;
+	    }
+	    $ql = $q;
+	} else {
+	    $ql = 0.5 if $any_lang && exists $accept{'language'};
+	}
+
+	my $q   = 1;
+	my $mbx = undef;
+	# If no Accept field is given, then the value assigned is "q=1".
+	# If at least one listed media range matches the variant's media
+	# type, then the "q" parameter value assigned to the most specific
+	# of those matched is used (e.g. "text/html;version=3.0" is more
+	# specific than "text/html", which is more specific than "text/*",
+	# which in turn is more specific than "*/*"). If not media range
+	# in the provided Accept field matches the variant's media type,
+	# then the value assigned is "q=0".
+	if (exists $accept{'type'} && $ct) {
+	    # First we clean up our content-type
+	    $ct =~ s/\s+//g;
+	    my $params = "";
+	    $params = $1 if $ct =~ s/;(.*)//;
+	    my($type, $subtype) = split("/", $ct, 2);
+	    my %param = ();
+	    for $param (split(/;/, $params)) {
+		my($pk,$pv) = split(/=/, $param, 2);
+		$param{$pk} = $pv;
+	    }
+
+	    my $sel_q = undef;
+	    my $sel_mbx = undef;
+	    my $sel_specificness = 0;
+
+	    ACCEPT_TYPE:
+	    for $at (keys %{ $accept{'type'} }) {
+		print "Consider $at...\n" if $DEBUG;
+		my($at_type, $at_subtype) = split("/", $at, 2);
+		# Is it a match on the type
+		next if $at_type    ne '*' && $at_type    ne $type;
+		next if $at_subtype ne '*' && $at_subtype ne $subtype;
+		my $specificness = 0;
+		$specificness++ if $at_type ne '*';
+		$specificness++ if $at_subtype ne '*';
+		# Let's see if content-type parameters also match
+		while (($pk, $pv) = each %param) {
+		    print "Check if $pk = $pv is true\n" if $DEBUG;
+		    next unless exists $accept{'type'}{$at}{$pk};
+		    next ACCEPT_TYPE
+		      unless $accept{'type'}{$at}{$pk} eq $pv;
+		    print "yes it is!!\n" if $DEBUG;
+		    $specificness++;
+		}
+		print "Hurray, type match with specificness = $specificness\n"
+		  if $DEBUG;
+
+		if (!defined($sel_q) || $sel_specificness < $specificness) {
+		    $sel_q   = $accept{'type'}{$at}{'q'};
+		    $sel_mbx = $accept{'type'}{$at}{'mbx'};
+		    $sel_specificness = $specificness;
+		}
+	    }
+	    $q   = $sel_q || 0;
+	    $mbx = $sel_mbx;
+	}
+
+	my $Q;
+	if (!defined($mbx) || $mbx >= $bs) {
+	    $Q = $qs * $qe * $qc * $ql * $q;
+	} else {
+	    $Q = 0;
+	    print "Variant's size is too large ==> Q=0\n" if $DEBUG;
+	}
+
+	if ($DEBUG) {
+	    $mbx = "undef" unless defined $mbx;
+	    printf "Q=%.3f", $Q;
+	    print "  (q=$q, mbx=$mbx, qe=$qe, qc=$qc, ql=$ql, qs=$qs)\n";
+	}
+
+	push(@Q, [$id, $Q, $bs]);
+    }
+
+
+    @Q = sort { $b->[1] <=> $a->[1] || $a->[2] <=> $b->[2] } @Q;
+
+    return @Q if wantarray;
+    return undef unless @Q;
+    return undef if $Q[0][1] == 0;
+    $Q[0][0];
+}
+
+1;
+
+__END__
+
+
+=head1 NAME
+
+choose - choose a variant of a document to serve (HTTP content negotiation)
+
+=head1 SYNOPSIS
+
+ use HTTP::Negotiate;
+
+ #  ID       QS     Content-Type   Encoding Char-Set        Lang   Size
+ $variants =
+  [['var1',  1.000, 'text/html',   undef,   'iso-8859-1',   'en',   3000],
+   ['var2',  0.950, 'text/plain',  'gzip',  'us-ascii',     'no',    400],
+   ['var3',  0.3,   'image/gif',   undef,   undef,          undef, 43555],
+  ];
+
+ @prefered = choose($variants, $request_headers);
+ $the_one  = choose($variants);
+
+=head1 DESCRIPTION
+
+This module provide a complete implementation of the HTTP content
+negotiation algorithm specified in F<draft-ietf-http-v11-spec-00.ps>
+chapter 12.  Content negotiation allows for the selection of a
+preferred content representation based upon attributes of the
+negotiable variants and the value of the various Accept* header fields
+in the request.
+
+The variants are ordered by preference by calling the function
+choose().
+
+The first parameter is a description of the variants that we can
+choose among.  The variants are described by a reference to an array.
+Each element in this array is an array with the values [$id, $qs,
+$content_type, $content_encoding, $charset, $content_language,
+$content_length].  The meaning of these values are described
+below. The $content_encoding and $content_language can be either a
+single scalar value or an array reference if there are several values.
+
+The second optional parameter is a reference to the request headers.
+This is used to look for "Accept*" headers.  You can pass a reference
+to either a HTTP::Request or a HTTP::Headers object.  If this
+parameter is missing, then the accept specification is initialized
+from the CGI environment variables HTTP_ACCEPT, HTTP_ACCEPT_CHARSET,
+HTTP_ACCEPT_ENCODING and HTTP_ACCEPT_LANGUAGE.
+
+In array context, choose() returns a list of variant
+identifier/calculated quality pairs.  The values are sorted by
+quality, highest quality first.  If the calculated quality is the same
+for two variants, then they are sorted by size (smallest first). I<E.g.>:
+
+  (['var1' => 1], ['var2', 0.3], ['var3' => 0]);
+
+Note that also zero quality variants are included in the return list
+even if these should never be served to the client.
+
+In scalar context, it returns the identifier of the variant with the
+highest score or C<undef> if none have non-zero quality.
+
+If the $HTTP::Negotiate::DEBUG variable is set to TRUE, then a lot of
+noise is generated on STDOUT during evaluation of choose().
+
+=head1 VARIANTS
+
+A variant is described by a list of the following values.  If the
+attribute does not make sense or is unknown for a variant, then use
+C<undef> instead.
+
+=over 3
+
+=item identifier
+
+This is just some string that you use as a name for the variant.  The
+identifier of the preferred variant is returned by choose().
+
+=item qs
+
+This is a number between 0.000 and 1.000 that describes the "source
+quality".  This is what F<draft-ietf-http-v11-spec-00.ps> says about this
+value:
+
+Source quality is measured by the content provider as representing the
+amount of degradation from the original source.  For example, a
+picture in JPEG form would have a lower qs when translated to the XBM
+format, and much lower qs when translated to an ASCII-art
+representation.  Note, however, that this is a function of the source
+- an original piece of ASCII-art may degrade in quality if it is
+captured in JPEG form.  The qs values should be assigned to each
+variant by the content provider; if no qs value has been assigned, the
+default is generally "qs=1".
+
+=item content-type
+
+This is the media type of the variant.  The media type does not
+include a charset attribute, but might contain other parameters.
+Examples are:
+
+  text/html
+  text/html;version=2.0
+  text/plain
+  image/gif
+  image/jpg
+
+=item content-encoding
+
+This is one or more content encodings that has been applied to the
+variant.  The content encoding is generally used as a modifier to the
+content media type.  The most common content encodings are:
+
+  gzip
+  compress
+
+=item content-charset
+
+This is the character set used when the variant contains textual
+content.  The charset value should generally be C<undef> or one of these:
+
+  us-ascii
+  iso-8859-1 ... iso-8859-9
+  iso-2022-jp
+  iso-2022-jp-2
+  iso-2022-kr
+  unicode-1-1
+  unicode-1-1-utf-7
+  unicode-1-1-utf-8
+
+=item content-language
+
+This describes one or more languages that are used in the variant.
+Language is described like this in F<draft-ietf-http-v11-spec-00.ps>: A
+language is in this context a natural language spoken, written, or
+otherwise conveyed by human beings for communication of information to
+other human beings.  Computer languages are explicitly excluded.
+
+The language tags are the same as those defined by RFC-1766.  Examples
+are:
+
+  no               Norwegian
+  en               International English
+  en-US            US English
+  en-cockney
+
+=item content-length
+
+This is the number of bytes used to represent the content.
+
+=back
+
+=head1 ACCEPT HEADERS
+
+The following Accept* headers can be used for describing content
+preferences in a request (This description is an edited extract from
+F<draft-ietf-http-v11-spec-00.ps>):
+
+=over 3
+
+=item Accept
+
+This header can be used to indicate a list of media ranges which are
+acceptable as a reponse to the request.  The "*" character is used to
+group media types into ranges, with "*/*" indicating all media types
+and "type/*" indicating all subtypes of that type.
+
+The parameter q is used to indicate the quality factor, which
+represents the user's preference for that range of media types.  The
+parameter mbx gives the maximum acceptable size of the response
+content. The default values are: q=1 and mbx=infinity. If no Accept
+header is present, then the client accepts all media types with q=1.
+
+For example:
+
+  Accept: audio/*;q=0.2;mbx=200000, audio/basic
+
+would mean: "I prefer audio/basic (of any size), but send me any audio
+type if it is the best available after an 80% mark-down in quality and
+its size is less than 200000 bytes"
+
+
+=item Accept-Charset
+
+Used to indicate what character sets are acceptable for the response.
+The "us-ascii" character set is assumed to be acceptable for all user
+agents.  If no Accept-Charset field is given, the default is that any
+charset is acceptable.  Example:
+
+  Accept-Charset: iso-8859-1, unicode-1-1
+
+
+=item Accept-Encoding
+
+Restricts the Content-Encoding values which are acceptable in the
+response.  If no Accept-Encoding field is present, the server may
+assume that the client will accept any content encoding.  An empty
+Accept-Encoding means that no content encoding is acceptable.  Example:
+
+  Accept-Encoding: compress, gzip
+
+
+=item Accept-Language
+
+This field is similar to Accept, but restrict the set of natural
+languages that are preferred as a response.  Each language may be
+given an associated quality value which represents an estimate of the
+user's comprehension of that language.  For example:
+
+  Accept-Language: no, en-gb;q=0.8, de;q=0.55
+
+would mean: "I prefer Norwegian, but will accept British English (with
+80% comprehension) or German (with 55% comprehension).
+
+=back
+
+
+=head1 COPYRIGHT
+
+Copyright 1996, Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 AUTHOR
+
+Gisle Aas <aas@sn.no>
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request.pm	(revision 10506)
@@ -0,0 +1,160 @@
+#
+# $Id$
+
+package HTTP::Request;
+
+=head1 NAME
+
+HTTP::Request - Class encapsulating HTTP Requests
+
+=head1 SYNOPSIS
+
+ require HTTP::Request;
+ $request = HTTP::Request->new(GET => 'http://www.oslonett.no/');
+
+=head1 DESCRIPTION
+
+C<HTTP::Request> is a class encapsulating HTTP style requests,
+consisting of a request line, some headers, and some (potentially empty)
+content. Note that the LWP library also uses this HTTP style requests
+for non-HTTP protocols.
+
+Instances of this class are usually passed to the C<request()> method
+of an C<LWP::UserAgent> object:
+
+ $ua = LWP::UserAgent->new;
+ $request = HTTP::Request->new(GET => 'http://www.oslonett.no/');
+ $response = $ua->request($request);
+
+C<HTTP::Request> is a subclass of C<HTTP::Message> and therefore
+inherits its methods.  The inherited methods often used are header(),
+push_header(), remove_header(), headers_as_string() and content().
+See L<HTTP::Message> for details.
+
+The following additional methods are available:
+
+=over 4
+
+=cut
+
+require HTTP::Message;
+@ISA = qw(HTTP::Message);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use URI::URL ();
+use strict;
+
+=item $r = HTTP::Request->new($method, $url, [$header, [$content]])
+
+Constructs a new C<HTTP::Request> object describing a request on the
+object C<$url> using method C<$method>.  The C<$url> argument can be
+either a string, or a reference to a C<URI::URL> object.  The $header
+argument should be a reference to an C<HTTP::Headers> object.
+
+=cut
+
+sub new
+{
+    my($class, $method, $url, $header, $content) = @_;
+    my $self = $class->SUPER::new($header, $content);
+    $self->method($method);
+    $self->url($url);
+    $self;
+}
+
+
+sub clone
+{
+    my $self = shift;
+    my $clone = bless $self->SUPER::clone, ref($self);
+    $clone->method($self->method);
+    $clone->url($self->url);
+    $clone;
+}
+
+
+=item $r->method([$val])
+
+=item $r->url([$val])
+
+These methods provide public access to the member variables containing
+respectively the method of the request and the URL object of the
+request.
+
+If an argument is given the member variable is given that as its new
+value. If no argument is given the value is not touched. In either
+case the previous value is returned.
+
+The url() method accept both a reference to a URI::URL object and a
+string as its argument.  If a string is given, then it should be
+parseable as an absolute URL.
+
+=cut
+
+sub method  { shift->_elem('_method', @_); }
+
+sub url
+{
+    my $self = shift;
+    my $old = $self->{'_url'};
+    if (@_) {
+	my $url = shift;
+	if (!defined $url) {
+	    # that's ok
+	} elsif (ref $url) {
+	    $url = $url->abs;
+	} else {
+	    $url = eval { URI::URL->new($url) };
+	}
+	$self->{'_url'} = $url;
+    }
+    $old;
+}
+
+*uri = \&url;  # this is the same for now
+
+=item $r->as_string()
+
+Method returning a textual representation of the request.
+Mainly useful for debugging purposes. It takes no arguments.
+
+=cut
+
+sub as_string
+{
+    my $self = shift;
+    my @result;
+    #push(@result, "---- $self -----");
+    my $req_line = $self->method || "[NO METHOD]";
+    my $url = $self->url;
+    $url = (defined $url) ? $url->as_string : "[NO URL]";
+    $req_line .= " $url";
+    my $proto = $self->protocol;
+    $req_line .= " $proto" if $proto;
+
+    push(@result, $req_line);
+    push(@result, $self->headers_as_string);
+    my $content = $self->content;
+    if (defined $content) {
+	push(@result, $content);
+    }
+    #push(@result, ("-" x 40));
+    join("\n", @result, "");
+}
+
+1;
+
+=back
+
+=head1 SEE ALSO
+
+L<HTTP::Headers>, L<HTTP::Message>, L<HTTP::Request::Common>
+
+=head1 COPYRIGHT
+
+Copyright 1995-1998 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request/Common.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request/Common.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Request/Common.pm	(revision 10506)
@@ -0,0 +1,389 @@
+# $Id$
+#
+package HTTP::Request::Common;
+
+use strict;
+use vars qw(@EXPORT @EXPORT_OK $VERSION $DYNAMIC_FILE_UPLOAD);
+
+$DYNAMIC_FILE_UPLOAD ||= 0;  # make it defined (don't know why)
+
+require Exporter;
+*import = \&Exporter::import;
+@EXPORT =qw(GET HEAD PUT POST);
+@EXPORT_OK = qw($DYNAMIC_FILE_UPLOAD);
+
+require HTTP::Request;
+use Carp();
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+my $CRLF = "\015\012";   # "\r\n" is not portable
+
+sub GET  { _simple_req('GET',  @_); }
+sub HEAD { _simple_req('HEAD', @_); }
+sub PUT  { _simple_req('PUT' , @_); }
+
+sub POST
+{
+    my $url = shift;
+    my $req = HTTP::Request->new(POST => $url);
+    my $content;
+    $content = shift if @_ and ref $_[0];
+    my($k, $v);
+    while (($k,$v) = splice(@_, 0, 2)) {
+	if (lc($k) eq 'content') {
+	    $content = $v;
+	} else {
+	    $req->push_header($k, $v);
+	}
+    }
+    my $ct = $req->header('Content-Type');
+    unless ($ct) {
+	$ct = 'application/x-www-form-urlencoded';
+    } elsif ($ct eq 'form-data') {
+	$ct = 'multipart/form-data';
+    }
+
+    if (ref $content) {
+	if (lc($ct) eq 'multipart/form-data') {    #XXX: boundary="..."
+	    my $boundary;
+	    ($content, $boundary) = form_data($content, $boundary);
+	    $boundary = qq("$boundary") if $boundary =~ /\W/;
+	    $ct = qq(multipart/form-data; boundary=$boundary);
+	} else {
+	    # We use a temporary URI::URL object to format
+	    # the application/x-www-form-urlencoded content.
+	    require URI::URL;
+	    my $url = URI::URL->new('http:');
+	    $url->query_form(ref($content) eq "HASH" ? %$content : @$content);
+	    $content = $url->equery;
+	}
+    }
+
+    $req->header('Content-Type' => $ct);  # might be redundant
+    if (defined($content)) {
+	$req->header('Content-Length' =>
+		     length($content)) unless ref($content);
+	$req->content($content);
+    }
+    $req;
+}
+
+
+sub _simple_req
+{
+    my($method, $url) = splice(@_, 0, 2);
+    my $req = HTTP::Request->new($method => $url);
+    my($k, $v);
+    while (($k,$v) = splice(@_, 0, 2)) {
+	if (lc($k) eq 'content') {
+	    $req->add_content($v);
+	} else {
+	    $req->push_header($k, $v);
+	}
+    }
+    $req;
+}
+
+
+sub form_data   # RFC1867
+{
+    my($data, $boundary) = @_;
+    my @data = ref($data) eq "HASH" ? %$data : @$data;  # copy
+    my $fhparts;
+    my @parts;
+    my($k,$v);
+    while (($k,$v) = splice(@data, 0, 2)) {
+	if (!ref($v)) {
+	    $k =~ s/([\\\"])/\\$1/g;  # escape quotes and backslashes
+	    push(@parts,
+		 qq(Content-Disposition: form-data; name="$k"$CRLF$CRLF$v));
+	} else {
+	    my($file, $usename, @headers) = @$v;
+	    unless (defined $usename) {
+		$usename = $file;
+		$usename =~ s,.*/,, if defined($usename);
+	    }
+	    my $disp = qq(form-data; name="$k");
+	    $disp .= qq(; filename="$usename") if $usename;
+	    my $content = "";
+	    my $h = HTTP::Headers->new(@headers);
+	    my $ct = $h->header("Content-Type");
+	    if ($file) {
+		require Symbol;
+		my $fh = Symbol::gensym();
+		open($fh, $file) or Carp::croak("Can't open file $file: $!");
+		binmode($fh);
+		if ($DYNAMIC_FILE_UPLOAD) {
+		    # will read file later
+		    $content = $fh;
+		} else {
+		    local($/) = undef; # slurp files
+		    $content = <$fh>;
+		    close($fh);
+		    $h->header("Content-Length" => length($content));
+		}
+		unless ($ct) {
+		    require LWP::MediaTypes;
+		    $ct = LWP::MediaTypes::guess_media_type($file, $h);
+		}
+	    }
+	    if ($h->header("Content-Disposition")) {
+		# just to get it sorted first
+		$disp = $h->header("Content-Disposition");
+		$h->remove_header("Content-Disposition");
+	    }
+	    if ($h->header("Content")) {
+		$content = $h->header("Content");
+		$h->remove_header("Content");
+	    }
+	    my $head = join($CRLF, "Content-Disposition: $disp",
+			           $h->as_string($CRLF),
+			           "");
+	    if (ref $content) {
+		push(@parts, [$head, $content]);
+		$fhparts++;
+	    } else {
+		push(@parts, $head . $content);
+	    }
+	}
+    }
+    return "" unless @parts;
+
+    my $content;
+    if ($fhparts) {
+	$boundary = boundary(10) # hopefully enough randomness
+	    unless $boundary;
+
+	# add the boundaries to the @parts array
+	for (1..@parts-1) {
+	    splice(@parts, $_*2-1, 0, "$CRLF--$boundary$CRLF");
+	}
+	unshift(@parts, "--$boundary$CRLF");
+	push(@parts, "$CRLF--$boundary--$CRLF");
+
+	# set up a closure that will return content piecemeal
+	$content = sub {
+	    for (;;) {
+		return unless @parts;
+		my $p = shift @parts;
+		unless (ref $p) {
+		    $p .= shift @parts while @parts && !ref($parts[0]);
+		    return $p;
+		}
+		my($buf, $fh) = @$p;
+		my $n = read($fh, $buf, 2048, length($buf));
+		if ($n) {
+		    unshift(@parts, ["", $fh]);
+		} else {
+		    close($fh);
+		}
+		return $buf if length $buf;
+	    }
+	};
+
+    } else {
+	$boundary = boundary() unless $boundary;
+
+	my $bno = 0;
+      CHECK_BOUNDARY:
+	{
+	    for (@parts) {
+		if (index($_, "--$boundary") >= 0) {
+		    # must have a better boundary
+		    #warn "Need something better that '$boundary' as boundary\n";
+		    $boundary = boundary(++$bno);
+		    redo CHECK_BOUNDARY;
+		}
+	    }
+	    last;
+	}
+	$content = "--$boundary$CRLF" .
+	           join("$CRLF--$boundary$CRLF", @parts) .
+		   "$CRLF--$boundary--$CRLF";
+    }
+
+    wantarray ? ($content, $boundary) : $content;
+}
+
+
+sub boundary
+{
+    my $size = shift || return "000";
+    require MIME::Base64;
+    my $b = MIME::Base64::encode(join("", map chr(rand(256)), 1..$size*3), "");
+    $b =~ s/[\W]/X/g;  # ensure alnum only
+    $b;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+HTTP::Request::Common - Construct common HTTP::Request objects
+
+=head1 SYNOPSIS
+
+  use HTTP::Request::Common;
+  $ua = LWP::UserAgent->new;
+  $ua->request(GET 'http://www.sn.no/');
+  $ua->request(POST 'http://somewhere/foo', [foo => bar, bar => foo]);
+
+=head1 DESCRIPTION
+
+This module provide functions that return newly created HTTP::Request
+objects.  These functions are usually more convenient to use than the
+standard HTTP::Request constructor for these common requests.  The
+following functions are provided.
+
+=over 4
+
+=item GET $url, Header => Value,...
+
+The GET() function returns a HTTP::Request object initialized with the
+GET method and the specified URL.  Without additional arguments it
+is exactly equivalent to the following call
+
+  HTTP::Request->new(GET => $url)
+
+but is less clutter.  It also reads better when used together with the
+LWP::UserAgent->request() method:
+
+  my $ua = new LWP::UserAgent;
+  my $res = $ua->request(GET 'http://www.sn.no')
+  if ($res->is_success) { ...
+
+You can also initialize the header values in the request by specifying
+some key/value pairs as optional arguments.  For instance:
+
+  $ua->request(GET 'http://www.sn.no',
+	           If_Match => 'foo',
+                   From     => 'gisle@aas.no',
+              );
+
+A header key called 'Content' is special and when seen the value will
+initialize the content part of the request instead of setting a header.
+
+=item HEAD $url, [Header => Value,...]
+
+Like GET() but the method in the request is HEAD.
+
+=item PUT $url, [Header => Value,...]
+
+Like GET() but the method in the request is PUT.
+
+=item POST $url, [$form_ref], [Header => Value,...]
+
+This works mostly like GET() with POST as method, but this function
+also takes a second optional array or hash reference parameter
+($form_ref).  This argument can be used to pass key/value pairs for
+the form content.  By default we will initialize a request using the
+C<application/x-www-form-urlencoded> content type.  This means that
+you can emulate a HTML E<lt>form> POSTing like this:
+
+  POST 'http://www.perl.org/survey.cgi',
+       [ name   => 'Gisle Aas',
+         email  => 'gisle@aas.no',
+         gender => 'M',
+         born   => '1964',
+         perc   => '3%',
+       ];
+
+This will create a HTTP::Request object that looks like this:
+
+  POST http://www.perl.org/survey.cgi
+  Content-Length: 66
+  Content-Type: application/x-www-form-urlencoded
+
+  name=Gisle%20Aas&email=gisle%40aas.no&gender=M&born=1964&perc=3%25
+
+The POST method also supports the C<multipart/form-data> content used
+for I<Form-based File Upload> as specified in RFC 1867.  You trigger
+this content format by specifying a content type of C<'form-data'> as
+one of the request headers.  If one of the values in the $form_ref is
+an array reference, then it is treated as a file part specification
+with the following interpretation:
+
+  [ $file, $filename, Header => Value... ]
+
+The first value in the array ($file) is the name of a file to open.
+This file will be read an its content placed in the request.  The
+routine will croak if the file can't be opened.  Use an C<undef> as $file
+value if you want to specify the content directly.  The $filename is
+the filename to report in the request.  If this value is undefined,
+then the basename of the $file will be used.  You can specify an empty
+string as $filename if you don't want any filename in the request.
+
+Sending my F<~/.profile> to the survey used as example above can be
+achieved by this:
+
+  POST 'http://www.perl.org/survey.cgi',
+       Content_Type => 'form-data',
+       Content      => [ name  => 'Gisle Aas',
+                         email => 'gisle@aas.no',
+                         gender => 'M',
+                         born   => '1964',
+                         init   => ["$ENV{HOME}/.profile"],
+                       ]
+
+This will create a HTTP::Request object that almost looks this (the
+boundary and the content of your F<~/.profile> is likely to be
+different):
+
+  POST http://www.perl.org/survey.cgi
+  Content-Length: 388
+  Content-Type: multipart/form-data; boundary="6G+f"
+
+  --6G+f
+  Content-Disposition: form-data; name="name"
+  
+  Gisle Aas
+  --6G+f
+  Content-Disposition: form-data; name="email"
+  
+  gisle@aas.no
+  --6G+f
+  Content-Disposition: form-data; name="gender"
+  
+  M
+  --6G+f
+  Content-Disposition: form-data; name="born"
+  
+  1964
+  --6G+f
+  Content-Disposition: form-data; name="init"; filename=".profile"
+  Content-Type: text/plain
+  
+  PATH=/local/perl/bin:$PATH
+  export PATH
+
+  --6G+f--
+
+If you set the $DYNAMIC_FILE_UPLOAD variable (exportable) to some TRUE
+value, then you get back a request object with a subroutine closure as
+the content attribute.  This subroutine will read the content of any
+files on demand and return it in suitable chunks.  This allow you to
+upload arbitrary big files without using lots of memory.  You can even
+upload infinite files like F</dev/audio> if you wish.  Another
+difference is that there will be no Content-Length header defined for
+the request if you use this feature.  Not all servers (or server
+applications) like this.
+
+=back
+
+=head1 SEE ALSO
+
+L<HTTP::Request>, L<LWP::UserAgent>
+
+
+=head1 COPYRIGHT
+
+Copyright 1997-1998, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Response.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Response.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Response.pm	(revision 10506)
@@ -0,0 +1,396 @@
+#
+# $Id$
+
+package HTTP::Response;
+
+
+=head1 NAME
+
+HTTP::Response - Class encapsulating HTTP Responses
+
+=head1 SYNOPSIS
+
+ require HTTP::Response;
+
+=head1 DESCRIPTION
+
+The C<HTTP::Response> class encapsulate HTTP style responses.  A
+response consist of a response line, some headers, and a (potential
+empty) content. Note that the LWP library will use HTTP style
+responses also for non-HTTP protocol schemes.
+
+Instances of this class are usually created and returned by the
+C<request()> method of an C<LWP::UserAgent> object:
+
+ #...
+ $response = $ua->request($request)
+ if ($response->is_success) {
+     print $response->content;
+ } else {
+     print $response->error_as_HTML;
+ }
+
+C<HTTP::Response> is a subclass of C<HTTP::Message> and therefore
+inherits its methods.  The inherited methods often used are header(),
+push_header(), remove_header(), headers_as_string(), and content().
+The header convenience methods are also available.  See
+L<HTTP::Message> for details.
+
+The following additional methods are available:
+
+=over 4
+
+=cut
+
+
+require HTTP::Message;
+@ISA = qw(HTTP::Message);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use HTTP::Status ();
+use URI::URL ();
+use strict;
+
+
+=item $r = HTTP::Response->new($rc, [$msg, [$header, [$content]]])
+
+Constructs a new C<HTTP::Response> object describing a response with
+response code C<$rc> and optional message C<$msg>.  The message is a
+short human readable single line string that explains the response
+code.
+
+=cut
+
+sub new
+{
+    my($class, $rc, $msg, $header, $content) = @_;
+    my $self = $class->SUPER::new($header, $content);
+    $self->code($rc);
+    $self->message($msg);
+    $self;
+}
+
+
+sub clone
+{
+    my $self = shift;
+    my $clone = bless $self->SUPER::clone, ref($self);
+    $clone->code($self->code);
+    $clone->message($self->message);
+    $clone->request($self->request->clone) if $self->request;
+    # we don't clone previous
+    $clone;
+}
+
+=item $r->code([$code])
+
+=item $r->message([$message])
+
+=item $r->request([$request])
+
+=item $r->previous([$previousResponse])
+
+These methods provide public access to the member variables.  The
+first two containing respectively the response code and the message
+of the response.
+
+The request attribute is a reference the request that gave this
+response.  It does not have to be the same request as passed to the
+$ua->request() method, because there might have been redirects and
+authorization retries in between.
+
+The previous attribute is used to link together chains of responses.
+You get chains of responses if the first response is redirect or
+unauthorized.
+
+=cut
+
+sub code      { shift->_elem('_rc',      @_); }
+sub message   { shift->_elem('_msg',     @_); }
+sub previous  { shift->_elem('_previous',@_); }
+sub request   { shift->_elem('_request', @_); }
+
+=item $r->status_line
+
+Returns the string "E<lt>code> E<lt>message>".  If the message attribute
+is not set then the official name of E<lt>code> (see L<HTTP::Status>)
+is substituted.
+
+=cut
+
+sub status_line
+{
+    my $self = shift;
+    my $code = $self->{'_rc'}  || "000";
+    my $mess = $self->{'_msg'} || HTTP::Status::status_message($code) || "?";
+    return "$code $mess";
+}
+
+=item $r->base
+
+Returns the base URL for this response.  The return value will be a
+reference to a URI::URL object.
+
+The base URL is obtained from one the following sources (in priority
+order):
+
+=over 4
+
+=item 1.
+
+Embedded in the document content, for instance <BASE HREF="...">
+in HTML documents.
+
+=item 2.
+
+A "Content-Base:" or a "Content-Location:" header in the response.
+
+For backwards compatability with older HTTP implementations we will
+also look for the "Base:" header.
+
+
+=item 3.
+
+The URL used to request this response. This might not be the original
+URL that was passed to $ua->request() method, because we might have
+received some redirect responses first.
+
+=back
+
+When the LWP protocol modules produce the HTTP::Response object, then
+any base URL embedded in the document (step 1) will already have
+initialized the "Content-Base:" header. This means that this method
+only perform the last 2 steps (the content is not always available
+either).
+
+=cut
+
+sub base
+{
+    my $self = shift;
+    my $base = $self->header('Content-Base')     ||  # HTTP/1.1
+               $self->header('Content-Location') ||  # HTTP/1.1
+               $self->header('Base')             ||  # backwards compatability HTTP/1.0
+               $self->request->url;
+    $base = URI::URL->new($base) unless ref $base;
+    $base;
+}
+
+
+=item $r->as_string
+
+Method returning a textual representation of the response.  Mainly
+useful for debugging purposes. It takes no arguments.
+
+=cut
+
+sub as_string
+{
+    require HTTP::Status;
+    my $self = shift;
+    my @result;
+    #push(@result, "---- $self ----");
+    my $code = $self->code;
+    my $status_message = HTTP::Status::status_message($code) || "Unknown code";
+    my $message = $self->message || "";
+
+    my $status_line = "$code";
+    my $proto = $self->protocol;
+    $status_line = "$proto $status_line" if $proto;
+    $status_line .= " ($status_message)" if $status_message ne $message;
+    $status_line .= " $message";
+    push(@result, $status_line);
+    push(@result, $self->headers_as_string);
+    my $content = $self->content;
+    if (defined $content) {
+	push(@result, $content);
+    }
+    #push(@result, ("-" x 40));
+    join("\n", @result, "");
+}
+
+=item $r->is_info
+
+=item $r->is_success
+
+=item $r->is_redirect
+
+=item $r->is_error
+
+These methods indicate if the response was informational, sucessful, a
+redirection, or an error.
+
+=cut
+
+sub is_info     { HTTP::Status::is_info     (shift->{'_rc'}); }
+sub is_success  { HTTP::Status::is_success  (shift->{'_rc'}); }
+sub is_redirect { HTTP::Status::is_redirect (shift->{'_rc'}); }
+sub is_error    { HTTP::Status::is_error    (shift->{'_rc'}); }
+
+
+=item $r->error_as_HTML()
+
+Return a string containing a complete HTML document indicating what
+error occurred.  This method should only be called when $r->is_error
+is TRUE.
+
+=cut
+
+sub error_as_HTML
+{
+    my $self = shift;
+    my $title = 'An Error Occurred';
+    my $body  = $self->status_line;
+    return <<EOM;
+<HTML>
+<HEAD><TITLE>$title</TITLE></HEAD>
+<BODY>
+<H1>$title</h1>
+$body
+</BODY>
+</HTML>
+EOM
+}
+
+
+=item $r->current_age
+
+This function will calculate the "current age" of the response as
+specified by E<lt>draft-ietf-http-v11-spec-07> section 13.2.3.  The
+age of a response is the time since it was sent by the origin server.
+The returned value is a number representing the age in seconds.
+
+=cut
+
+sub current_age
+{
+    my $self = shift;
+    # Implementation of <draft-ietf-http-v11-spec-07> section 13.2.3
+    # (age calculations)
+    my $response_time = $self->client_date;
+    my $date = $self->date;
+
+    my $age = 0;
+    if ($response_time && $date) {
+	$age = $response_time - $date;  # apparent_age
+	$age = 0 if $age < 0;
+    }
+
+    my $age_v = $self->header('Age');
+    if ($age_v && $age_v > $age) {
+	$age = $age_v;   # corrected_received_age
+    }
+
+    my $request = $self->request;
+    if ($request) {
+	my $request_time = $request->date;
+	if ($request_time) {
+	    # Add response_delay to age to get 'corrected_initial_age'
+	    $age += $response_time - $request_time;
+	}
+    }
+    if ($response_time) {
+	$age += time - $response_time;
+    }
+    return $age;
+}
+
+
+=item $r->freshness_lifetime
+
+This function will calculate the "freshness lifetime" of the response
+as specified by E<lt>draft-ietf-http-v11-spec-07> section 13.2.4.  The
+"freshness lifetime" is the length of time between the generation of a
+response and its expiration time.  The returned value is a number
+representing the freshness lifetime in seconds.
+
+If the response does not contain an "Expires" or a "Cache-Control"
+header, then this function will apply some simple heuristic based on
+'Last-Modified' to determine a suitable lifetime.
+
+=cut
+
+sub freshness_lifetime
+{
+    my $self = shift;
+
+    # First look for the Cache-Control: max-age=n header
+    my @cc = $self->header('Cache-Control');
+    if (@cc) {
+	my $cc;
+	for $cc (@cc) {
+	    my $cc_dir;
+	    for $cc_dir (split(/\s*,\s*/, $cc)) {
+		if ($cc_dir =~ /max-age\s*=\s*(\d+)/i) {
+		    return $1;
+		}
+	    }
+	}
+    }
+
+    # Next possibility is to look at the "Expires" header
+    my $date = $self->date || $self->client_date || time;      
+    my $expires = $self->expires;
+    unless ($expires) {
+	# Must apply heuristic expiration
+	my $last_modified = $self->last_modified;
+	if ($last_modified) {
+	    my $h_exp = ($date - $last_modified) * 0.10;  # 10% since last-mod
+	    if ($h_exp < 60) {
+		return 60;  # minimum
+	    } elsif ($h_exp > 24 * 3600) {
+		# Should give a warning if more than 24 hours according to
+		# <draft-ietf-http-v11-spec-07> section 13.2.4, but I don't
+		# know how to do it from this function interface, so I just
+		# make this the maximum value.
+		return 24 * 3600;
+	    }
+	    return $h_exp;
+	} else {
+	    return 3600;  # 1 hour is fallback when all else fails
+	}
+    }
+    return $expires - $date;
+}
+
+
+=item $r->is_fresh
+
+Returns TRUE if the response is fresh, based on the values of
+freshness_lifetime() and current_age().  If the response is not longer
+fresh, then it has to be refetched or revalidated by the origin
+server.
+
+=cut
+
+sub is_fresh
+{
+    my $self = shift;
+    $self->freshness_lifetime > $self->current_age;
+}
+
+
+=item $r->fresh_until
+
+Returns the time when this entiy is no longer fresh.
+
+=cut
+
+sub fresh_until
+{
+    my $self = shift;
+    return $self->freshness_lifetime - $self->current_age + time;
+}
+
+1;
+
+=back 
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Status.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Status.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/HTTP/Status.pm	(revision 10506)
@@ -0,0 +1,233 @@
+#
+# $Id$
+
+package HTTP::Status;
+
+use strict;
+require 5.002;   # becase we use prototypes
+
+=head1 NAME
+
+HTTP::Status - HTTP Status code processing
+
+=head1 SYNOPSIS
+
+ use HTTP::Status;
+
+ if ($rc != RC_OK) {
+     print status_message($rc), "\n";
+ }
+
+ if (is_success($rc)) { ... }
+ if (is_error($rc)) { ... }
+ if (is_redirect($rc)) { ... }
+
+=head1 DESCRIPTION
+
+I<HTTP::Status> is a library of routines for defining and
+classification of HTTP status codes for libwww-perl.  Status codes are
+used to encode the overall outcome of a HTTP response message.  Codes
+correspond to those defined in F<draft-ietf-http-v11-spec-rev-03> (an
+update to RFC 2068).
+
+=head1 CONSTANTS
+
+The following constant functions can be used as mnemonic status code
+names:
+
+   RC_CONTINUE				(100)
+   RC_SWITCHING_PROTOCOLS		(101)
+
+   RC_OK				(200)
+   RC_CREATED				(201)
+   RC_ACCEPTED				(202)
+   RC_NON_AUTHORITATIVE_INFORMATION	(203)
+   RC_NO_CONTENT			(204)
+   RC_RESET_CONTENT			(205)
+   RC_PARTIAL_CONTENT			(206)
+
+   RC_MULTIPLE_CHOICES			(300)
+   RC_MOVED_PERMANENTLY			(301)
+   RC_FOUND				(302)
+   RC_SEE_OTHER				(303)
+   RC_NOT_MODIFIED			(304)
+   RC_USE_PROXY				(305)
+   RC_TEMPORARY_REDIRECT		(307)
+
+   RC_BAD_REQUEST			(400)
+   RC_UNAUTHORIZED			(401)
+   RC_PAYMENT_REQUIRED			(402)
+   RC_FORBIDDEN				(403)
+   RC_NOT_FOUND				(404)
+   RC_METHOD_NOT_ALLOWED		(405)
+   RC_NOT_ACCEPTABLE			(406)
+   RC_PROXY_AUTHENTICATION_REQUIRED	(407)
+   RC_REQUEST_TIMEOUT			(408)
+   RC_CONFLICT				(409)
+   RC_GONE				(410)
+   RC_LENGTH_REQUIRED			(411)
+   RC_PRECONDITION_FAILED		(412)
+   RC_REQUEST_ENTITY_TOO_LARGE		(413)
+   RC_REQUEST_URI_TOO_LARGE		(414)
+   RC_UNSUPPORTED_MEDIA_TYPE		(415)
+   RC_REQUEST_RANGE_NOT_SATISFIABLE     (416)
+   RC_EXPECTATION_FAILED		(417)
+
+   RC_INTERNAL_SERVER_ERROR		(500)
+   RC_NOT_IMPLEMENTED			(501)
+   RC_BAD_GATEWAY			(502)
+   RC_SERVICE_UNAVAILABLE		(503)
+   RC_GATEWAY_TIMEOUT			(504)
+   RC_HTTP_VERSION_NOT_SUPPORTED	(505)
+
+=cut
+
+#####################################################################
+
+use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(is_info is_success is_redirect is_error status_message);
+@EXPORT_OK = qw(is_client_error is_server_error);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+# Note also addition of mnemonics to @EXPORT below
+
+my %StatusCode = (
+    100 => 'Continue',
+    101 => 'Switching Protocols',
+    200 => 'OK',
+    201 => 'Created',
+    202 => 'Accepted',
+    203 => 'Non-Authoritative Information',
+    204 => 'No Content',
+    205 => 'Reset Content',
+    206 => 'Partial Content',
+    300 => 'Multiple Choices',
+    301 => 'Moved Permanently',
+    302 => 'Found',
+    303 => 'See Other',
+    304 => 'Not Modified',
+    305 => 'Use Proxy',
+    307 => 'Temporary Redirect',
+    400 => 'Bad Request',
+    401 => 'Unauthorized',
+    402 => 'Payment Required',
+    403 => 'Forbidden',
+    404 => 'Not Found',
+    405 => 'Method Not Allowed',
+    406 => 'Not Acceptable',
+    407 => 'Proxy Authentication Required',
+    408 => 'Request Timeout',
+    409 => 'Conflict',
+    410 => 'Gone',
+    411 => 'Length Required',
+    412 => 'Precondition Failed',
+    413 => 'Request Entity Too Large',
+    414 => 'Request-URI Too Large',
+    415 => 'Unsupported Media Type',
+    416 => 'Request Range Not Satisfiable',
+    417 => 'Expectation Failed',
+    500 => 'Internal Server Error',
+    501 => 'Not Implemented',
+    502 => 'Bad Gateway',
+    503 => 'Service Unavailable',
+    504 => 'Gateway Timeout',
+    505 => 'HTTP Version Not Supported',
+);
+
+my $mnemonicCode = '';
+my ($code, $message);
+while (($code, $message) = each %StatusCode) {
+    # create mnemonic subroutines
+    $message =~ tr/a-z \-/A-Z__/;
+    $mnemonicCode .= "sub RC_$message () { $code }\t";
+    # make them exportable
+    $mnemonicCode .= "push(\@EXPORT, 'RC_$message');\n";
+}
+# warn $mnemonicCode; # for development
+eval $mnemonicCode; # only one eval for speed
+die if $@;
+
+# backwards compatibility
+*RC_MOVED_TEMPORARILY = \&RC_FOUND;  # 302 was renamed in the standard
+push(@EXPORT, "RC_MOVED_TEMPORARILY");
+
+
+=head1 FUNCTIONS
+
+The following additional functions are provided.  Most of them are
+exported by default.
+
+=over 4
+
+=item status_message($code)
+
+The status_message() function will translate status codes to human
+readable strings. The string is the same as found in the constant
+names above.  If the $code is unknown, then C<undef> is returned.
+
+=cut
+
+sub status_message ($)
+{
+    $StatusCode{$_[0]};
+}
+
+=item is_info($code)
+
+Return TRUE if C<$code> is an I<Informational> status code.  This
+class of status code indicates a provisional response which can't have
+any content.
+
+=item is_success($code)
+
+Return TRUE if C<$code> is a I<Successful> status code.
+
+=item is_redirect($code)
+
+Return TRUE if C<$code> is a I<Redirection> status code. This class of
+status code indicates that further action needs to be taken by the
+user agent in order to fulfill the request.
+
+=item is_error($code)
+
+Return TRUE if C<$code> is an I<Error> status code.  The function
+return TRUE for both client error or a server error status codes.
+
+=item is_client_error($code)
+
+Return TRUE if C<$code> is an I<Client Error> status code. This class
+of status code is intended for cases in which the client seems to have
+erred.
+
+This function is B<not> exported by default.
+
+=item is_server_error($code)
+
+Return TRUE if C<$code> is an I<Server Error> status code. This class
+of status codes is intended for cases in which the server is aware
+that it has erred or is incapable of performing the request.
+
+This function is B<not> exported by default.
+
+=back
+
+=cut
+
+sub is_info         ($) { $_[0] >= 100 && $_[0] < 200; }
+sub is_success      ($) { $_[0] >= 200 && $_[0] < 300; }
+sub is_redirect     ($) { $_[0] >= 300 && $_[0] < 400; }
+sub is_error        ($) { $_[0] >= 400 && $_[0] < 600; }
+sub is_client_error ($) { $_[0] >= 400 && $_[0] < 500; }
+sub is_server_error ($) { $_[0] >= 500 && $_[0] < 600; }
+
+1;
+
+=head1 BUGS
+
+Wished @EXPORT_OK had been used instead of @EXPORT in the beginning.
+Now too much is exported by default.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP.pm	(revision 10506)
@@ -0,0 +1,593 @@
+#
+# $Id$
+
+package LWP;
+
+$VERSION = "5.36";
+sub Version { $VERSION; }
+
+require 5.004;
+require LWP::UserAgent;  # this should load everything you need
+
+1;
+
+__END__
+
+=head1 NAME
+
+LWP - Library for WWW access in Perl
+
+=head1 SYNOPSIS
+
+  use LWP;
+  print "This is libwww-perl-$LWP::VERSION\n";
+
+
+=head1 DESCRIPTION
+
+Libwww-perl is a collection of Perl modules which provides a simple
+and consistent programming interface (API) to the World-Wide Web.  The
+main focus of the library is to provide classes and functions that
+allow you to write WWW clients, thus libwww-perl said to be a WWW
+client library. The library also contain modules that are of more
+general use.
+
+Most modules in this library are object oriented.  The user
+agent, requests sent and responses received from the WWW server are
+all represented by objects.  This makes a simple and powerful
+interface to these services.  The interface should be easy to extend
+and customize for your needs.
+
+The main features of the library are:
+
+=over 3
+
+=item *
+
+Contains various reusable components (modules) that can be
+used separately or together.
+
+=item *
+
+Provides an object oriented model of HTTP-style communication.  Within
+this framework we currently support access to http, https, gopher, ftp, news,
+file, and mailto resources.
+
+=item *
+
+The library be used through the full object oriented interface or
+through a very simple procedural interface.
+
+=item *
+
+Support the basic and digest authorization schemes.
+
+=item *
+
+Transparent redirect handling.
+
+=item *
+
+Supports access through proxy servers.
+
+=item *
+
+URL handling (both absolute and relative URLs are supported).
+
+=item *
+
+A parser for F<robots.txt> files and a framework for constructing robots.
+
+=item *
+
+The library can cooperate with Tk.  A simple Tk-based GUI browser
+called 'tkweb' is distributed with the Tk extension for perl.
+
+=item *
+
+An implementation of the HTTP content negotiation algorithm that can
+be used both in protocol modules and in server scripts (like CGI
+scripts).
+
+=item *
+
+It can deal with HTTP cookies.
+
+=item *
+
+A simple command line client application called C<lwp-request>.
+
+=back
+
+
+=head1 HTTP STYLE COMMUNICATION
+
+
+The libwww-perl library is based on HTTP style communication. This
+section try to describe what that means.
+
+Let us start with this quote from the HTTP specification document
+<URL:http://www.w3.org/pub/WWW/Protocols/>:
+
+=over 3
+
+=item
+
+The HTTP protocol is based on a request/response paradigm. A client
+establishes a connection with a server and sends a request to the
+server in the form of a request method, URI, and protocol version,
+followed by a MIME-like message containing request modifiers, client
+information, and possible body content. The server responds with a
+status line, including the message's protocol version and a success or
+error code, followed by a MIME-like message containing server
+information, entity meta-information, and possible body content.
+
+=back
+
+What this means to libwww-perl is that communication always take place
+through these steps: First a I<request> object is created and
+configured. This object is then passed to a server and we get a
+I<response> object in return that we can examine. A request is always
+independent of any previous requests, i.e. the service is stateless.
+The same simple model is used for any kind of service we want to
+access.
+
+For example, if we want to fetch a document from a remote file server,
+then we send it a request that contains a name for that document and
+the response will contain the document itself.  If we access a search
+engine, then the content of the request will contain the query
+parameters and the response will contain the query result.  If we want
+to send a mail message to somebody then we send a request object which
+contains our message to the mail server and the response object will
+contain an acknowledgment that tells us that the message has been
+accepted and will be forwarded to the recipient(s).
+
+It is as simple as that!
+
+
+=head2 The Request Object
+
+The request object has the class name C<HTTP::Request> in
+libwww-perl. The fact that the class name use C<HTTP::> as a name
+prefix only implies that we use the HTTP model of communication. It
+does not limit the kind of services we can try to pass this I<request>
+to.  For instance, we will send C<HTTP::Request>s both to ftp and
+gopher servers, as well as to the local file system.
+
+The main attributes of the request objects are:
+
+=over 3
+
+=item *
+
+The B<method> is a short string that tells what kind of
+request this is.  The most used methods are B<GET>, B<PUT>,
+B<POST> and B<HEAD>.
+
+=item *
+
+The B<url> is a string denoting the protocol, server and
+the name of the "document" we want to access.  The B<url> might
+also encode various other parameters.
+
+=item *
+
+The B<headers> contain additional information about the
+request and can also used to describe the content.  The headers
+is a set of keyword/value pairs.
+
+=item *
+
+The B<content> is an arbitrary amount of data.
+
+=back
+
+=head2 The Response Object
+
+The response object has the class name C<HTTP::Response> in
+libwww-perl.  The main attributes of objects of this class are:
+
+=over 3
+
+=item *
+
+The B<code> is a numerical value that encode the overall
+outcome of the request.
+
+=item *
+
+The B<message> is a short (human readable) string that
+corresponds to the I<code>.
+
+=item *
+
+The B<headers> contain additional information about the
+response and they also describe the content.
+
+=item *
+
+The B<content> is an arbitrary amount of data.
+
+=back
+
+Since we don't want to handle all possible I<code> values directly in
+our programs, the libwww-perl response object have methods that can be
+used to query what kind of response this is.  The most commonly used
+response classification methods are:
+
+=over 3
+
+=item is_success()
+
+The request was was successfully received, understood or accepted.
+
+=item is_error()
+
+The request failed.  The server or the resource might not be
+available, access to the resource might be denied or other things might
+have failed for some reason.
+
+=back
+
+=head2 The User Agent
+
+Let us assume that we have created a I<request> object. What do we
+actually do with it in order to receive a I<response>?
+
+The answer is that you pass it on to a I<user agent> object and this
+object will take care of all the things that need to be done
+(low-level communication and error handling). The user agent will give
+you back a I<response> object. The user agent represents your
+application on the network and it provides you with an interface that
+can accept I<requests> and will return I<responses>.
+
+You should think about the user agent as an interface layer between
+your application code and the network.  Through this interface you are
+able to access the various servers on the network.
+
+The libwww-perl class name for the user agent is
+C<LWP::UserAgent>. Every libwww-perl application that wants to
+communicate should create at least one object of this kind. The main
+method provided by this object is request(). This method takes an
+C<HTTP::Request> object as argument and will (eventually) return a
+C<HTTP::Response> object.
+
+The user agent has many other attributes that lets you
+configure how it will interact with the network and with your
+application code.
+
+=over 3
+
+=item *
+
+The B<timeout> specify how much time we give remote servers in
+creating responses before the library disconnect and creates an
+internal I<timeout> response.
+
+=item *
+
+The B<agent> specify the name that your application should use when it
+presents itself on the network.
+
+=item *
+
+The B<from> attribute can be set to the e-mail address of the person
+responsible for running the application.  If this is set, then the
+address will be sent to the servers with every request.
+
+=item *
+
+The B<parse_head> specify whether we should initialize response
+headers from the E<lt>head> section of HTML documents.
+
+=item *
+
+The B<proxy> and B<no_proxy> specify if and when communication should
+go through a proxy server. <URL:http://www.w3.org/pub/WWW/Proxies/>
+
+=item *
+
+The B<credentials> provide a way to set up user names and
+passwords that is needed to access certain services.
+
+=back
+
+Many applications would want even more control over how they interact
+with the network and they get this by specializing the
+C<LWP::UserAgent> by sub-classing.  The library provide a
+specialization called C<LWP::RobotUA> that is used by robot
+applications.
+
+=head2 An Example
+
+This example shows how the user agent, a request and a response are
+represented in actual perl code:
+
+  # Create a user agent object
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+  $ua->agent("AgentName/0.1 " . $ua->agent);
+
+  # Create a request
+  my $req = new HTTP::Request POST => 'http://www.perl.com/cgi-bin/BugGlimpse';
+  $req->content_type('application/x-www-form-urlencoded');
+  $req->content('match=www&errors=0');
+
+  # Pass request to the user agent and get a response back
+  my $res = $ua->request($req);
+
+  # Check the outcome of the response
+  if ($res->is_success) {
+      print $res->content;
+  } else {
+      print "Bad luck this time\n";
+  }
+
+The $ua is created once when the application starts up.  New request
+objects are normally created for each request sent.
+
+
+=head1 NETWORK SUPPORT
+
+This section goes through the various protocol schemes and describe
+the HTTP style methods that are supported and the headers that might
+have any effect.
+
+For all requests, a "User-Agent" header is added and initialized from
+the $ua->agent value before the request is handed to the network
+layer.  In the same way, a "From" header is initialized from the
+$ua->from value.
+
+For all responses, the library will add a header called "Client-Date".
+This header will encode the time when the response was received by
+your application.  This format and semantics of the header is just
+like the server created "Date" header.  You can also encounter other
+"Client-XXX" headers.  They are all generated by the library
+internally and not something really passed on from the servers.
+
+=head2 HTTP Requests
+
+HTTP request are really just handed off to an HTTP server and it will
+decide what happens.  Few servers implement methods beside the usual
+"GET", "HEAD", "POST" and "PUT" but CGI-scripts can really implement
+any method they like.
+
+If the server is not available then the library will generate an
+internal error response.
+
+The library automatically adds a "Host" and a "Content-Length" header
+to the HTTP request before it is sent over the network.
+
+For GET request you might want to add the "If-Modified-Since" header
+to make the request conditional.
+
+For POST request you should add the "Content-Type" header.  When you
+try to emulate HTML E<lt>FORM> handling you should usually let the value
+of the "Content-Type" header be "application/x-www-form-urlencoded".
+See L<lwpcook> for examples of this.
+
+The libwww-perl HTTP implementation currently support the HTTP/1.0
+protocol.  HTTP/0.9 servers are also handled correctly.
+
+The library allows you to access proxy server through HTTP.  This
+means that you can set up the library to forward all types of request
+through the HTTP protocol module.  See L<LWP::UserAgent> for
+documentation of this.
+
+
+=head2 HTTPS Requests
+
+HTTPS requests are HTTP requests over an encrypted network connection
+using the SSL protocol developed by Netscape.  Everything about HTTP
+requests above also hold for HTTPS requests.  In addition the library
+will add the headers "Client-SSL-Cipher", "Client-SSL-Cert-Subject" and
+"Client-SSL-Cert-Issuer" to the response.  These headers denote the
+encryption method used and the name of the server owner.
+
+The request can contain the header "If-SSL-Cert-Subject" in order to
+make the request conditional on the content of the server certificate.
+If the certificate subject does not match, no request is sent to the
+server and an internally generated error response is returned.  The
+value of the "If-SSL-Cert-Subject" header is interpreted as a Perl
+regular expression.
+
+
+=head2 FTP Requests
+
+The library currently support GET, HEAD and PUT requests.  GET will
+retrieve a file or a directory listing from an FTP server.  PUT will
+store a file on a ftp server.
+
+You can specify a ftp account for servers that want this in addition
+user name and password.  This is specified by passing an "Account"
+header in the request.
+
+User name/password can be specified using basic authorization or be
+encoded in the URL.  Bad logins return an UNAUTHORIZED response with
+"WWW-Authenticate: Basic" and can be treated as basic authorization
+for HTTP.
+
+The library support ftp ASCII transfer mode by specifying the "type=a"
+parameter in the URL.
+
+Directory listings are by default returned unprocessed (as returned
+from the ftp server) with the content media type reported to be
+"text/ftp-dir-listing". The C<File::Listing> module provide functionality
+for parsing of these directory listing.
+
+The ftp module is also able to convert directory listings to HTML and
+this can be requested via the standard HTTP content negotiation
+mechanisms (add an "Accept: text/html" header in the request if you
+want this).
+
+The normal file retrievals, the "Content-Type" is guessed based on the
+file name suffix. See L<LWP::MediaTypes>.
+
+The "If-Modified-Since" request header works for servers that implement
+the MDTM command.  It will probably not work for directory listings though.
+
+Example:
+
+  $req = HTTP::Request->new(GET => 'ftp://me:passwd@ftp.some.where.com/');
+  $req->header(Accept => "text/html, */*;q=0.1");
+
+=head2 News Requests
+
+Access to the USENET News system is implemented through the NNTP
+protocol.  The name of the news server is obtained from the
+NNTP_SERVER environment variable and defaults to "news".  It is not
+possible to specify the hostname of the NNTP server in the news:-URLs.
+
+The library support GET and HEAD to retrieve news articles through the
+NNTP protocol.  You can also post articles to newsgroups by using
+(surprise!) the POST method.
+
+GET on newsgroups is not implemented yet.
+
+Examples:
+
+  $req = HTTP::Request->new(GET => 'news:abc1234@a.sn.no');
+
+  $req = HTTP::Request->new(POST => 'news:comp.lang.perl.test');
+  $req->header(Subject => 'This is a test',
+               From    => 'me@some.where.org');
+  $req->content(<<EOT);
+  This is the content of the message that we are sending to
+  the world.
+  EOT
+
+
+=head2 Gopher Request
+
+The library supports the GET and HEAD method for gopher request.  All
+request header values are ignored.  HEAD cheats and will return a
+response without even talking to server.
+
+Gopher menus are always converted to HTML.
+
+The response "Content-Type" is generated from the document type
+encoded (as the first letter) in the request URL path itself.
+
+Example:
+
+  $req = HTTP::Request->new(GET => 'gopher://gopher.sn.no/');
+
+
+
+=head2 File Request
+
+The library supports GET and HEAD methods for file requests.  The
+"If-Modified-Since" header is supported.  All other headers are
+ignored.  The I<host> component of the file URL must be empty or set
+to "localhost".  Any other I<host> value will be treated as an error.
+
+Directories are always converted to an HTML document.  For normal
+files, the "Content-Type" and "Content-Encoding" in the response are
+guessed based on the file suffix.
+
+Example:
+
+  $req = HTTP::Request->new(GET => 'file:/etc/passwd');
+
+
+=head2 Mailto Request
+
+You can send (aka "POST") mail messages using the library.  All
+headers specified for the request are passed on to the mail system.
+The "To" header is initialized from the mail address in the URL.
+
+Example:
+
+  $req = HTTP::Request->new(POST => 'mailto:libwww-perl-request@ics.uci.edu');
+  $req->header(Subject => "subscribe");
+  $req->content("Please subscribe me to the libwww-perl mailing list!\n");
+
+
+=head1 OVERVIEW OF CLASSES AND PACKAGES
+
+This table should give you a quick overview of the classes provided by the
+library. Indentation shows class inheritance.
+
+ LWP::MemberMixin   -- Access to member variables of Perl5 classes
+   LWP::UserAgent   -- WWW user agent class
+     LWP::RobotUA   -- When developing a robot applications
+   LWP::Protocol          -- Interface to various protocol schemes
+     LWP::Protocol::http  -- http:// access
+     LWP::Protocol::file  -- file:// access
+     LWP::Protocol::ftp   -- ftp:// access
+     ...
+
+ LWP::Authen::Basic -- Handle 401 and 407 responses
+ LWP::Authen::Digest
+
+ HTTP::Headers      -- MIME/RFC822 style header (used by HTTP::Message)
+ HTTP::Message      -- HTTP style message
+   HTTP::Request    -- HTTP request
+   HTTP::Response   -- HTTP response
+ HTTP::Daemon       -- A HTTP server class
+
+ URI::URL           -- Uniform Resource Locators
+
+ WWW::RobotRules    -- Parse robots.txt files
+   WWW::RobotRules::AnyDBM_File -- Persistent RobotRules
+
+The following modules provide various functions and definitions.
+
+ LWP                -- This file.  Library version number and documentation.
+ LWP::MediaTypes    -- MIME types configuration (text/html etc.)
+ LWP::Debug         -- Debug logging module
+ LWP::Simple        -- Simplified procedural interface for common functions
+ HTTP::Status       -- HTTP status code (200 OK etc)
+ HTTP::Date         -- Date parsing module for HTTP date formats
+ HTTP::Negotiate    -- HTTP content negotiation calculation
+ File::Listing      -- Parse directory listings
+
+
+=head1 MORE DOCUMENTATION
+
+All modules contain detailed information on the interfaces they
+provide.  The I<lwpcook> manpage is the libwww-perl cookbook that contain
+examples of typical usage of the library.  You might want to take a
+look at how the scripts C<lwp-request>, C<lwp-rget> and C<lwp-mirror>
+are implemented.
+
+=head1 BUGS
+
+The library can not handle multiple simultaneous requests yet.  Also,
+check out what's left in the TODO file.
+
+=head1 ACKNOWLEDGEMENTS
+
+This package owes a lot in motivation, design, and code, to the
+libwww-perl library for Perl 4, maintained by Roy Fielding
+E<lt>fielding@ics.uci.edu>.
+
+That package used work from Alberto Accomazzi, James Casey, Brooks
+Cutter, Martijn Koster, Oscar Nierstrasz, Mel Melchner, Gertjan van
+Oosten, Jared Rhine, Jack Shirazi, Gene Spafford, Marc VanHeyningen,
+Steven E. Brenner, Marion Hakanson, Waldemar Kebsch, Tony Sanders, and
+Larry Wall; see the libwww-perl-0.40 library for details.
+
+The primary architect for this Perl 5 library is Martijn Koster and
+Gisle Aas, with lots of help from Graham Barr, Tim Bunce, Andreas
+Koenig, Jared Rhine, and Jack Shirazi.
+
+
+=head1 COPYRIGHT
+
+  Copyright 1995-1998, Gisle Aas
+  Copyright 1995, Martijn Koster
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 AVAILABILITY
+
+The latest version of this library is likely to be available from:
+
+ http://www.sn.no/libwww-perl/
+
+The best place to discuss this code is on the
+<libwww-perl@ics.uci.edu> mailing list.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Basic.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Basic.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Basic.pm	(revision 10506)
@@ -0,0 +1,36 @@
+package LWP::Authen::Basic;
+use strict;
+
+require MIME::Base64;
+
+sub authenticate
+{
+    my($class, $ua, $proxy, $auth_param, $response,
+       $request, $arg, $size) = @_;
+
+    my($user, $pass) = $ua->get_basic_credentials($auth_param->{realm},
+                                                  $request->url, $proxy);
+    return $response unless defined $user and defined $pass;
+
+    my $auth_header = $proxy ? "Proxy-Authorization" : "Authorization";
+    my $auth_value = "Basic " . MIME::Base64::encode("$user:$pass", "");
+
+    # Need to check this isn't a repeated fail!
+    my $r = $response;
+    while ($r) {
+	my $auth = $r->request->header($auth_header);
+	if ($auth && $auth eq $auth_value) {
+	    # here we know this failed before
+	    $response->header("Client-Warning" =>
+			      "Credentials for '$user' failed before");
+	    return $response;
+	}
+	$r = $r->previous;
+    }
+
+    my $referral = $request->clone;
+    $referral->header($auth_header => $auth_value);
+    return $ua->request($referral, $arg, $size, $response);
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Digest.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Digest.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Authen/Digest.pm	(revision 10506)
@@ -0,0 +1,73 @@
+package LWP::Authen::Digest;
+use strict;
+
+require MD5;
+
+sub authenticate
+{
+    my($class, $ua, $proxy, $auth_param, $response,
+       $request, $arg, $size) = @_;
+
+    my($user, $pass) = $ua->get_basic_credentials($auth_param->{realm},
+                                                  $request->url, $proxy);
+    return $response unless defined $user and defined $pass;
+
+    my $md5 = new MD5;
+
+    my(@digest);
+    $md5->add(join(":", $user, $auth_param->{realm}, $pass));
+    push(@digest, $md5->hexdigest);
+    $md5->reset;
+
+    push(@digest, $auth_param->{nonce});
+
+    $md5->add(join(":", $request->method, $request->url->path));
+    push(@digest, $md5->hexdigest);
+    $md5->reset;
+
+    $md5->add(join(":", @digest));
+    my($digest) = $md5->hexdigest;
+    $md5->reset;
+
+    my %resp = map { $_ => $auth_param->{$_} } qw(realm nonce opaque);
+    @resp{qw(username uri response)} = ($user, $request->url->path, $digest);
+
+    my(@order) = qw(username realm nonce uri response);
+    if($request->method =~ /^(?:POST|PUT)$/) {
+	$md5->add($request->content);
+	my $content = $md5->hexdigest;
+	$md5->reset;
+	$md5->add(join(":", @digest[0..1], $content));
+	$md5->reset;
+	$resp{"message-digest"} = $md5->hexdigest;
+	push(@order, "message-digest");
+    }
+    push(@order, "opaque");
+    my @pairs;
+    for (@order) {
+	next unless defined $resp{$_};
+	push(@pairs, "$_=" . qq("$resp{$_}"));
+    }
+
+    my $auth_header = $proxy ? "Proxy-Authorization" : "Authorization";
+    my $auth_value  = "Digest " . join(", ", @pairs);
+    
+    # Need to check this isn't a repeated fail!
+    my $r = $response;
+    while ($r) {
+	my $auth = $r->request->header($auth_header);
+	if ($auth && $auth eq $auth_value) {
+	    # here we know this failed before
+	    $response->header("Client-Warning" =>
+			      "Credentials for '$user' failed before");
+	    return $response;
+	}
+	$r = $r->previous;
+    }
+
+    my $referral = $request->clone;
+    $referral->header($auth_header => $auth_value);
+    return $ua->request($referral, $arg, $size, $response);
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Debug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Debug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Debug.pm	(revision 10506)
@@ -0,0 +1,129 @@
+#!/usr/local/bin/perl -w
+#
+# $Id$
+#
+package LWP::Debug;
+
+=head1 NAME
+
+LWP::Debug - debug routines for the libwww-perl library
+
+=head1 SYNOPSIS
+
+ use LWP::Debug qw(+ -conns);
+
+ # Used internally in the library
+ LWP::Debug::trace('send()');
+ LWP::Debug::debug('url ok');
+ LWP::Debug::conns("read $n bytes: $data");
+
+=head1 DESCRIPTION
+
+LWP::Debug provides tracing facilities. The trace(), debug() and
+conns() function are called within the library and they log
+information at increasing levels of detail. Which level of detail is
+actually printed is controlled with the C<level()> function.
+
+The following functions are available:
+
+=over 4
+
+=item level(...)
+
+The C<level()> function controls the level of detail being
+logged. Passing '+' or '-' indicates full and no logging
+respectively. Inidividual levels can switched on and of by passing the
+name of the level with a '+' or '-' prepended.  The levels are:
+
+  trace   : trace function calls
+  debug   : print debug messages
+  conns   : show all data transfered over the connections
+
+The LWP::Debug module provide a special import() method that allows
+you to pass the level() arguments with initial use statement.  If a
+use argument start with '+' or '-' then it is passed to the level
+function, else the name is exported as usual.  The following two
+statements are thus equivalent (if you ignore that the second pollutes
+your namespace):
+
+  use LWP::Debug qw(+);
+  use LWP::Debug qw(level); level('+');
+
+=item trace($msg)
+
+The C<trace()> function is used for tracing function
+calls. The package and calling subroutine name is
+printed along with the passed argument. This should
+be called at the start of every major function.
+
+=item debug($msg)
+
+The C<debug()> function is used for high-granularity
+reporting of state in functions.
+
+=item conns($msg)
+
+The C<conns()> function is used to show data being
+transferred over the connections. This may generate
+considerable output.
+
+=back
+
+=cut
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(level trace debug conns);
+
+use Carp ();
+
+my @levels = qw(trace debug conns);
+%current_level = ();
+
+sub import
+{
+    my $pack = shift;
+    my $callpkg = caller(0);
+    my @symbols = ();
+    my @levels = ();
+    for (@_) {
+	if (/^[-+]/) {
+	    push(@levels, $_);
+	} else {
+	    push(@symbols, $_);
+	}
+    }
+    Exporter::export($pack, $callpkg, @symbols);
+    level(@levels);
+}
+
+sub level
+{
+    for (@_) {
+	if ($_ eq '+') {              # all on
+	    # switch on all levels
+	    %current_level = map { $_ => 1 } @levels;
+	} elsif ($_ eq '-') {           # all off
+	    %current_level = ();
+	} elsif (/^([-+])(\w+)$/) {
+	    $current_level{$2} = $1 eq '+';
+	} else {
+	    Carp::croak("Illegal level format $_");
+	}
+    }
+}
+
+sub trace  { _log(@_) if $current_level{'trace'}; }
+sub debug  { _log(@_) if $current_level{'debug'}; }
+sub conns  { _log(@_) if $current_level{'conns'}; }
+
+sub _log
+{
+    my $msg = shift;
+    $msg .= "\n" unless $msg =~ /\n$/;  # ensure trailing "\n"
+
+    my($package,$filename,$line,$sub) = caller(2);
+    print STDERR "$sub: $msg";
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MediaTypes.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MediaTypes.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MediaTypes.pm	(revision 10506)
@@ -0,0 +1,298 @@
+#
+# $Id$
+
+package LWP::MediaTypes;
+
+=head1 NAME
+
+LWP::MediaTypes - guess media type for a file or a URL
+
+=head1 SYNOPSIS
+
+ use LWP::MediaTypes qw(guess_media_type);
+ $type = guess_media_type("/tmp/foo.gif");
+
+=head1 DESCRIPTION
+
+This module provides functions for handling of media (also known as
+MIME) types and encodings.  The mapping from file extentions to media
+types is defined by the F<media.types> file.  If the F<~/.media.types>
+file exist it is used as a replacement.
+For backwards compatability we will also look for F<~/.mime.types>.
+
+The following functions are exported by default:
+
+=over 4
+
+=cut
+
+####################################################################
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(guess_media_type media_suffix);
+@EXPORT_OK = qw(add_type add_encoding);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+require LWP::Debug;
+use strict;
+
+# note: These hashes will also be filled with the entries found in
+# the 'media.types' file.
+
+my %suffixType = (
+    'txt'   => 'text/plain',
+    'html'  => 'text/html',
+    'gif'   => 'image/gif',
+    'jpg'   => 'image/jpeg',
+);
+
+my %suffixExt = (
+    'text/plain' => 'txt',
+    'text/html'  => 'h',
+    'image/gif'  => 'gif',
+    'image/jpeg' => 'jpg',
+);
+
+#XXX: there should be some way to define this in the media.types files.
+my %suffixEncoding = (
+    'Z'   => 'compress',
+    'gz'  => 'gzip',
+    'hqx' => 'x-hqx',
+    'uu'  => 'x-uuencode',
+    'z'   => 'x-pack'
+);
+
+sub _dump {
+    require Data::Dumper;
+    Data::Dumper->new([\%suffixType, \%suffixExt, \%suffixEncoding],
+		      [qw(*suffixType *suffixExt *suffixEncoding)])->Dump;
+}
+
+read_media_types();
+
+
+
+=item guess_media_type($filename_or_url, [$header_to_modify])
+
+This function tries to guess media type and encoding for given file.
+It returns the content-type, which is a string like C<"text/html">.
+In array context it also returns any content-encodings applied (in the
+order used to encode the file).  You can pass a URI::URL object
+reference, instead of the file name, as the first parameter too.
+
+If the type can not be deduced from looking at the file name only,
+then guess_media_type() will let the C<-T> Perl operator take a look.
+If this works (and C<-T> returns a TRUE value) then we return
+I<text/plain> as the type, otherwise we return
+I<application/octet-stream> as the type.
+
+The optional second argument should be a reference to a HTTP::Headers
+object (or any object that implement the $obj->header method in a
+similar way).  When present we will set the values of the
+'Content-Type' and 'Content-Encoding' for this header.
+
+=cut
+
+sub guess_media_type
+{
+    my($file, $header) = @_;
+    return undef unless defined $file;
+
+    my $fullname;
+    if (ref($file)) {
+	# assume URI::URL object
+	$file = $file->path;
+	#XXX should handle non http:, file: or ftp: URLs differently
+    } else {
+	$fullname = $file;  # enable peek at actual file
+    }
+
+    my @encoding = ();
+    my $ct = undef;
+    for (file_exts($file)) {
+	# first check this dot part as encoding spec
+	if (exists $suffixEncoding{$_}) {
+	    unshift(@encoding, $suffixEncoding{$_});
+	    next;
+	}
+	if (exists $suffixEncoding{lc $_}) {
+	    unshift(@encoding, $suffixEncoding{lc $_});
+	    next;
+	}
+
+	# check content-type
+	if (exists $suffixType{$_}) {
+	    $ct = $suffixType{$_};
+	    last;
+	}
+	if (exists $suffixType{lc $_}) {
+	    $ct = $suffixType{lc $_};
+	    last;
+	}
+
+	# don't know nothing about this dot part, bail out
+	last;
+    }
+    unless (defined $ct) {
+	# Take a look at the file
+	if (defined $fullname) {
+	    $ct = (-T $fullname) ? "text/plain" : "application/octet-stream";
+	} else {
+	    $ct = "application/octet-stream";
+	}
+    }
+
+    if ($header) {
+	$header->header('Content-Type' => $ct);
+	$header->header('Content-Encoding' => \@encoding) if @encoding;
+    }
+
+    wantarray ? ($ct, @encoding) : $ct;
+}
+
+
+=item media_suffix($type,...)
+
+This function will return all suffixes that can be used to denote the
+specified media type(s).  Wildcard types can be used.  In scalar
+context it will return the first suffix found.
+
+Examples:
+
+  @suffixes = media_suffix('image/*', 'audio/basic');
+  $suffix = media_suffix('text/html');
+
+=cut
+
+sub media_suffix {
+    if (!wantarray && @_ == 1 && $_[0] !~ /\*/) {
+	return $suffixExt{$_[0]};
+    }
+    my(@type) = @_;
+    my(@suffix, $ext, $type);
+    foreach (@type) {
+	if (s/\*/.*/) {
+	    while(($ext,$type) = each(%suffixType)) {
+		push(@suffix, $ext) if $type =~ /^$_$/;
+	    }
+	} else {
+	    while(($ext,$type) = each(%suffixType)) {
+		push(@suffix, $ext) if $type eq $_;
+	    }
+	}
+    }
+    wantarray ? @suffix : $suffix[0];
+}
+
+
+sub file_exts 
+{
+    my($file) = @_;
+    $file =~ s,.*/,,;   # only basename left
+    my @parts = reverse split(/\./, $file);
+    pop(@parts);        # never concider first part
+    @parts;
+}
+
+
+=back
+
+The following functions are only exported by explict request:
+
+=over 4
+
+=item add_type($type, @exts)
+
+Associate a list of file extensions with the given media type.
+
+Example:
+
+    add_type("x-world/x-vrml" => qw(wrl vrml));
+
+=cut
+
+sub add_type 
+{
+    my($type, @exts) = @_;
+    for my $ext (@exts) {
+	$ext =~ s/^\.//;
+	$suffixType{$ext} = $type;
+    }
+    $suffixExt{$type} = $exts[0] if @exts;
+}
+
+
+=item add_encoding($type, @ext)
+
+Associate a list of file extensions with and encoding type.
+
+Example:
+
+ add_encoding("x-gzip" => "gz");
+
+=cut
+
+sub add_encoding
+{
+    my($type, @exts) = @_;
+    for my $ext (@exts) {
+	$ext =~ s/^\.//;
+	$suffixEncoding{$ext} = $type;
+    }
+}
+
+
+=item read_media_types(@files)
+
+Parse a media types file from disk and add the type mappings found there.
+
+Example:
+
+    read_media_types("conf/mime.types");
+
+=cut
+
+sub read_media_types 
+{
+    my(@files) = @_;
+
+    local($/, $_) = ("\n", undef);  # ensure correct $INPUT_RECORD_SEPARATOR
+
+    my @priv_files = ();
+    push(@priv_files, "$ENV{HOME}/.media.types", "$ENV{HOME}/.mime.types")
+	if defined $ENV{HOME};  # Some doesn't have a home (for instance Win32)
+
+    # Try to locate "media.types" file, and initialize %suffixType from it
+    my $typefile;
+    unless (@files) {
+	@files = map {"$_/LWP/media.types"} @INC;
+	push @files, @priv_files;
+    }
+    for $typefile (@files) {
+	local(*TYPE);
+	open(TYPE, $typefile) || next;
+        LWP::Debug::debug("Reading media types from $typefile");
+	while (<TYPE>) {
+	    next if /^\s*#/; # comment line
+	    next if /^\s*$/; # blank line
+	    s/#.*//;         # remove end-of-line comments
+	    my($type, @exts) = split(' ', $_);
+	    add_type($type, @exts);
+	}
+	close(TYPE);
+    }
+}
+
+1;
+
+=back 
+
+=head1 COPYRIGHT
+
+Copyright 1995-1998 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MemberMixin.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MemberMixin.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/MemberMixin.pm	(revision 10506)
@@ -0,0 +1,46 @@
+#
+# $Id$
+
+package LWP::MemberMixin;
+
+=head1 NAME
+
+LWP::MemberMixin - Member access mixin class
+
+=head1 SYNOPSIS
+
+ package Foo;
+ require LWP::MemberMixin;
+ @ISA=qw(LWP::MemberMixin);
+
+=head1 DESCRIPTION
+
+A mixin class to get methods that provide easy access to member
+variables in the %$self.
+Ideally there should be better Perl langauge support for this.
+
+There is only one method provided:
+
+=over 4
+
+=item _elem($elem [, $val])
+
+Internal method to get/set the value of member variable
+C<$elem>. If C<$val> is defined it is used as the new value
+for the member variable.  If it is undefined the current
+value is not touched. In both cases the previous value of
+the member variable is returned.
+
+=back
+
+=cut
+
+sub _elem
+{
+    my($self, $elem, $val) = @_;
+    my $old = $self->{$elem};
+    $self->{$elem} = $val if defined $val;
+    return $old;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol.pm	(revision 10506)
@@ -0,0 +1,303 @@
+# $Id$
+
+package LWP::Protocol;
+
+=head1 NAME
+
+LWP::Protocol - Base class for LWP protocols
+
+=head1 SYNOPSIS
+
+ package LWP::Protocol::foo;
+ require LWP::Protocol;
+ @ISA=qw(LWP::Protocol);
+
+=head1 DESCRIPTION
+
+This class is used a the base class for all protocol implementations
+supported by the LWP library.
+
+When creating an instance of this class using
+C<LWP::Protocol::create($url)>, and you get an initialised subclass
+appropriate for that access method. In other words, the
+LWP::Protocol::create() function calls the constructor for one of its
+subclasses.
+
+All derived LWP::Protocol classes need to override the request()
+method which is used to service a request. The overridden method can
+make use of the collect() function to collect together chunks of data
+as it is received.
+
+The following methods and functions are provided:
+
+=over 4
+
+=cut
+
+#####################################################################
+
+require LWP::MemberMixin;
+@ISA = qw(LWP::MemberMixin);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use strict;
+use Carp ();
+use HTTP::Status 'RC_INTERNAL_SERVER_ERROR';
+require HTML::HeadParser;
+
+my %ImplementedBy = (); # scheme => classname
+
+
+=item $prot = new HTTP::Protocol;
+
+The LWP::Protocol constructor is inherited by subclasses. As this is a
+virtual base class this method should B<not> be called directly.
+
+=cut
+
+sub new
+{
+    my($class) = @_;
+
+    my $self = bless {
+	'timeout' => 0,
+	'parse_head' => 1,
+    }, $class;
+    $self;
+}
+
+
+=item $prot = LWP::Protocol::create($url)
+
+Create an object of the class implementing the protocol to handle the
+given scheme. This is a function, not a method. It is more an object
+factory than a constructor. This is the function user agents should
+use to access protocols.
+
+=cut
+
+sub create
+{
+    my $scheme = shift;
+    my $impclass = LWP::Protocol::implementor($scheme) or
+	Carp::croak("Protocol scheme '$scheme' is not supported");
+
+    # hand-off to scheme specific implementation sub-class
+    return $impclass->new($scheme);
+}
+
+
+=item $class = LWP::Protocol::implementor($scheme, [$class])
+
+Get and/or set implementor class for a scheme.  Returns '' if the
+specified scheme is not supported.
+
+=cut
+
+sub implementor
+{
+    my($scheme, $impclass) = @_;
+
+    if ($impclass) {
+	$ImplementedBy{$scheme} = $impclass;
+    }
+    my $ic = $ImplementedBy{$scheme};
+    return $ic if $ic;
+
+    return '' unless $scheme =~ /^([.+\-\w]+)$/;  # check valid URL schemes
+    $scheme = $1; # untaint
+    $scheme =~ s/[.+\-]/_/g;  # make it a legal module name
+
+    # scheme not yet known, look for a 'use'd implementation
+    $ic = "LWP::Protocol::$scheme";  # default location
+    $ic = "LWP::Protocol::nntp" if $scheme eq 'news'; #XXX ugly hack
+    no strict 'refs';
+    # check we actually have one for the scheme:
+    unless (defined @{"${ic}::ISA"}) {
+	# try to autoload it
+	eval "require $ic";
+	if ($@) {
+	    if ($@ =~ /^Can't locate/) { #' #emacs get confused by '
+		$ic = '';
+	    } else {
+		die "$@\n";
+	    }
+	}
+    }
+    $ImplementedBy{$scheme} = $ic if $ic;
+    $ic;
+}
+
+
+=item $prot->request(...)
+
+ $response = $protocol->request($request, $proxy, undef);
+ $response = $protocol->request($request, $proxy, '/tmp/sss');
+ $response = $protocol->request($request, $proxy, \&callback, 1024);
+
+Dispactches a request over the protocol, and returns a response
+object. This method needs to be overridden in subclasses.  Referer to
+L<LWP::UserAgent> for description of the arguments.
+
+=cut
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
+    Carp::croak('LWP::Protocol::request() needs to be overridden in subclasses');
+}
+
+
+=item $prot->timeout($seconds)
+
+Get and set the timeout value in seconds
+
+
+=item $prot->parse_head($yesno)
+
+Should we initialize response headers from the <head> section of HTML
+documents.
+
+=cut
+
+sub timeout    { shift->_elem('timeout',    @_); }
+sub parse_head { shift->_elem('parse_head', @_); }
+sub max_size   { shift->_elem('max_size',   @_); }
+
+
+=item $prot->collect($arg, $response, $collector)
+
+Called to collect the content of a request, and process it
+appropriately into a scalar, file, or by calling a callback.  If $arg
+is undefined, then the content is stored within the $response.  If
+$arg is a simple scalar, then $arg is interpreted as a file name and
+the content is written to this file.  If $arg is a reference to a
+routine, then content is passed to this routine.
+
+The $collector is a routine that will be called and which is
+reponsible for returning pieces (as ref to scalar) of the content to
+process.  The $collector signals EOF by returning a reference to an
+empty sting.
+
+The return value from collect() is the $response object reference.
+
+B<Note:> We will only use the callback or file argument if
+$response->is_success().  This avoids sendig content data for
+redirects and authentization responses to the callback which would be
+confusing.
+
+=cut
+
+sub collect
+{
+    my ($self, $arg, $response, $collector) = @_;
+    my $content;
+    my($parse_head, $timeout, $max_size) =
+      @{$self}{qw(parse_head timeout max_size)};
+
+    my $parser;
+    if ($parse_head && $response->content_type eq 'text/html') {
+	$parser = HTML::HeadParser->new($response->{'_headers'});
+    }
+    my $content_size = 0;
+
+    if (!defined($arg) || !$response->is_success) {
+	# scalar
+	while ($content = &$collector, length $$content) {
+	    if ($parser) {
+		$parser->parse($$content) or undef($parser);
+	    }
+	    LWP::Debug::debug("read " . length($$content) . " bytes");
+	    $response->add_content($$content);
+	    $content_size += length($$content);
+	    if ($max_size && $content_size > $max_size) {
+		LWP::Debug::debug("Aborting because size limit exceeded");
+		my $tot = $response->header("Content-Length") || 0;
+		$response->header("X-Content-Range", "bytes 0-$content_size/$tot");
+		last;
+	    }
+	}
+    }
+    elsif (!ref($arg)) {
+	# filename
+	open(OUT, ">$arg") or
+	    return new HTTP::Response RC_INTERNAL_SERVER_ERROR,
+			  "Cannot write to '$arg': $!";
+        binmode(OUT);
+        local($\) = ""; # ensure standard $OUTPUT_RECORD_SEPARATOR
+	while ($content = &$collector, length $$content) {
+	    if ($parser) {
+		$parser->parse($$content) or undef($parser);
+	    }
+	    LWP::Debug::debug("read " . length($$content) . " bytes");
+	    print OUT $$content;
+	    $content_size += length($$content);
+	    if ($max_size && $content_size > $max_size) {
+		LWP::Debug::debug("Aborting because size limit exceeded");
+		my $tot = $response->header("Content-Length") || 0;
+		$response->header("X-Content-Range", "bytes 0-$content_size/$tot");
+		last;
+	    }
+	}
+	close(OUT);
+    }
+    elsif (ref($arg) eq 'CODE') {
+	# read into callback
+	while ($content = &$collector, length $$content) {
+	    if ($parser) {
+		$parser->parse($$content) or undef($parser);
+	    }
+	    LWP::Debug::debug("read " . length($$content) . " bytes");
+            eval {
+		&$arg($$content, $response, $self);
+	    };
+	    if ($@) {
+	        chomp($@);
+		$response->header('X-Died' => $@);
+		last;
+	    }
+	}
+    }
+    else {
+	return new HTTP::Response RC_INTERNAL_SERVER_ERROR,
+				  "Unexpected collect argument  '$arg'";
+    }
+    $response;
+}
+
+
+=item $prot->collect_once($arg, $response, $content)
+
+Can be called when the whole response content is available as
+$content.  This will invoke collect() with a collector callback that
+returns a reference to $content the first time and an empty string the
+next.
+
+=cut
+
+sub collect_once
+{
+    my($self, $arg, $response) = @_;
+    my $content = \ $_[3];
+    my $first = 1;
+    $self->collect($arg, $response, sub {
+	return $content if $first--;
+	return \ "";
+    });
+}
+
+1;
+
+=head1 SEE ALSO
+
+Inspect the F<LWP/Protocol/file.pm> and F<LWP/Protocol/http.pm> files
+for examples of usage.
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/data.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/data.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/data.pm	(revision 10506)
@@ -0,0 +1,53 @@
+#
+# $Id$
+#
+# Implements access to data:-URLs as specified in
+# draft-masinter-url-data-02.txt
+
+package LWP::Protocol::data;
+
+require HTTP::Response;
+require HTTP::Status;
+
+require LWP::Protocol;
+@ISA = qw(LWP::Protocol);
+
+use HTTP::Date qw(time2str);
+require LWP;  # needs version number
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size) = @_;
+
+    # check proxy
+    if (defined $proxy)
+    {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'You can not proxy with data';
+    }
+
+    # check method
+    if ($request->method ne 'GET') {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'Library does not allow method ' .
+				  "$method for 'data:' URLs";
+    }
+
+    my $url = $request->url;
+    my $response = new HTTP::Response &HTTP::Status::RC_OK, "Document follows";
+
+    my($media_type, $params) = $url->media_type;
+    $media_type .= ";$params" if $params;
+
+    my $data = $url->data;
+    $response->header('Content-Type'   => $media_type,
+		      'Content-Length' => length($data),
+		      'Date'           => time2str(time),
+		      'Server'         => "libwww-perl-internal/$LWP::VERSION"
+		     );
+    $response->content($data);
+
+    return $response;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/file.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/file.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/file.pm	(revision 10506)
@@ -0,0 +1,154 @@
+#
+# $Id$
+
+package LWP::Protocol::file;
+
+require LWP::Protocol;
+require LWP::MediaTypes;
+require HTTP::Request;
+require HTTP::Response;
+require HTTP::Status;
+require HTTP::Date;
+
+require URI::Escape;
+require HTML::Entities;
+
+use Carp;
+
+@ISA = qw(LWP::Protocol);
+
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size) = @_;
+
+    LWP::Debug::trace('()');
+
+    $size = 4096 unless defined $size and $size > 0;
+
+    # check proxy
+    if (defined $proxy)
+    {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'You can not proxy through the filesystem';
+    }
+
+    # check method
+    $method = $request->method;
+
+    unless ($method eq 'GET' || $method eq 'HEAD') {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'Library does not allow method ' .
+				  "$method for 'file:' URLs";
+    }
+
+    # check url
+    my $url = $request->url;
+
+    my $scheme = $url->scheme;
+    if ($scheme ne 'file') {
+	return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				  "LWP::file::request called for '$scheme'";
+    }
+
+    my $host = $url->host;
+    if ($host and $host !~ /^localhost$/i) {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST_CLIENT,
+				  'Only file://localhost/ allowed';
+    }
+
+    # URL OK, look at file
+    my $path  = $url->local_path;
+
+    # test file exists and is readable
+    unless (-e $path) {
+	return new HTTP::Response &HTTP::Status::RC_NOT_FOUND,
+				  "File `$path' does not exist";
+    }
+    unless (-r _) {
+	return new HTTP::Response &HTTP::Status::RC_FORBIDDEN,
+				  'User does not have read permission';
+    }
+
+    # looks like file exists
+    my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$filesize,
+       $atime,$mtime,$ctime,$blksize,$blocks)
+	    = stat(_);
+
+    # XXX should check Accept headers?
+
+    # check if-modified-since
+    my $ims = $request->header('If-Modified-Since');
+    if (defined $ims) {
+	my $time = HTTP::Date::str2time($ims);
+	if (defined $time and $time >= $mtime) {
+	    return new HTTP::Response &HTTP::Status::RC_NOT_MODIFIED,
+				      "$method $path";
+	}
+    }
+
+    # Ok, should be an OK response by now...
+    $response = new HTTP::Response &HTTP::Status::RC_OK;
+
+    # fill in response headers
+    $response->header('Last-Modified', HTTP::Date::time2str($mtime));
+
+    if (-d _) {         # If the path is a directory, process it
+	# generate the HTML for directory
+	opendir(D, $path) or
+	   return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				     "Cannot read directory '$path': $!";
+	my(@files) = sort readdir(D);
+	closedir(D);
+
+	# Make directory listing
+	for (@files) {
+	    $_ .= "/" if -d "$path/$_";
+	    my $furl = URI::Escape::uri_escape($_);
+	    my $desc = HTML::Entities::encode($_);
+	    $_ = qq{<LI><A HREF="$furl">$desc</A>};
+	}
+	# Ensure that the base URL is "/" terminated
+	my $base = $url->clone;
+	unless ($base->epath =~ m|/$|) {
+	    $base->epath($base->epath . "/");
+	}
+	my $html = join("\n",
+			"<HTML>\n<HEAD>",
+			"<TITLE>Directory $path</TITLE>",
+			"<BASE HREF=\"$base\">",
+			"</HEAD>\n<BODY>",
+			"<H1>Directory listing of $path</H1>",
+			"<UL>", @files, "</UL>",
+			"</BODY>\n</HTML>\n");
+
+	$response->header('Content-Type',   'text/html');
+	$response->header('Content-Length', length $html);
+
+	return $self->collect_once($arg, $response, $html);
+
+    } else {            # path is a regular file
+	my($type, @enc) = LWP::MediaTypes::guess_media_type($path);
+	$response->header('Content-Type',   $type) if $type;
+	$response->header('Content-Length', $filesize);
+	for (@enc) {
+	    $response->push_header('Content-Encoding', $_);
+	}
+
+	# read the file
+	open(F, $path) or return new
+	   HTTP::Response(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+			  "Cannot read file '$path': $!");
+	$response =  $self->collect($arg, $response, sub {
+	    my $content = "";
+	    my $bytes = sysread(F, $content, $size);
+	    return \$content if $bytes > 0;
+	    return \ "";
+	});
+	close(F);
+    }
+
+    $response;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/ftp.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/ftp.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/ftp.pm	(revision 10506)
@@ -0,0 +1,396 @@
+#
+# $Id$
+
+# Implementation of the ftp protocol (RFC 959). We let the Net::FTP
+# package do all the dirty work.
+
+package LWP::Protocol::ftp;
+
+use Carp ();
+
+use HTTP::Status ();
+use HTTP::Negotiate ();
+use HTTP::Response ();
+use LWP::MediaTypes ();
+use File::Listing ();
+
+require LWP::Protocol;
+@ISA = qw(LWP::Protocol);
+
+use strict;
+eval {
+    require Net::FTP;
+    Net::FTP->require_version(2.00);
+};
+my $init_failed = $@;
+
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
+
+    $size = 4096 unless $size;
+
+    LWP::Debug::trace('()');
+
+    # check proxy
+    if (defined $proxy)
+    {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'You can not proxy through the ftp');
+    }
+
+    my $url = $request->url;
+    if ($url->scheme ne 'ftp') {
+	my $scheme = $url->scheme;
+	return HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+		       "LWP::Protocol::ftp::request called for '$scheme'");
+    }
+
+    # check method
+    my $method = $request->method;
+
+    unless ($method eq 'GET' || $method eq 'HEAD' || $method eq 'PUT') {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'Library does not allow method ' .
+				   "$method for 'ftp:' URLs");
+    }
+
+    if ($init_failed) {
+	return HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				   $init_failed);
+    }
+
+    my $host     = $url->host;
+    my $port     = $url->port;
+    my $user     = $url->user;
+    my $password = $url->password;
+
+    # If a basic autorization header is present than we prefer these over
+    # the username/password specified in the URL.
+    {
+	my($u,$p) = $request->authorization_basic;
+	if (defined $u) {
+	    $user = $u;
+	    $password = $p;
+	}
+    }
+
+    # We allow the account to be specified in the "Account" header
+    my $acct     = $request->header('Account');
+
+    # try to make a connection
+    my $ftp = Net::FTP->new($host, Port => $port);
+    unless ($ftp) {
+       $@ =~ s/^Net::FTP: //;
+       return HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR, $@);
+    }
+
+    # Create an initial response object
+    my $response = HTTP::Response->new(&HTTP::Status::RC_OK,
+				       "Document follows");
+    $response->request($request);
+
+    my $mess = $ftp->message;  # welcome message
+    LWP::Debug::debug($mess);
+    $mess =~ s|\n.*||s; # only first line left
+    $mess =~ s|\s*ready\.?$||;
+    # Make the version number more HTTP like
+    $mess =~ s|\s*\(Version\s*|/| and $mess =~ s|\)$||;
+    $response->header("Server", $mess);
+
+    $ftp->timeout($timeout) if $timeout;
+
+    LWP::Debug::debug("Logging in as $user (password $password)...");
+    unless ($ftp->login($user, $password, $acct)) {
+	# Unauthorized.  Let's fake a RC_UNAUTHORIZED response
+	my $res =  HTTP::Response->new(&HTTP::Status::RC_UNAUTHORIZED,
+				       scalar($ftp->message));
+	$res->header("WWW-Authenticate", qq(Basic Realm="FTP login"));
+	return $res;
+    }
+    LWP::Debug::debug($ftp->message);
+
+    # Get & fix the path
+    my @path =  $url->path_components;
+    shift(@path);  # There will always be an empty first component
+    pop(@path) while @path && $path[-1] eq '';  # remove empty tailing comps
+    my $remote_file = pop(@path);
+    $remote_file = '' unless defined $remote_file;
+
+    my $params = $url->params;
+    if (defined($params) && $params eq 'type=a') {
+	$ftp->ascii;
+    } else {
+	$ftp->binary;
+    }
+
+    for (@path) {
+	LWP::Debug::debug("CWD $_");
+	unless ($ftp->cwd($_)) {
+	    return HTTP::Response->new(&HTTP::Status::RC_NOT_FOUND,
+				       "Can't chdir to $_");
+	}
+    }
+
+    if ($method eq 'GET' || $method eq 'HEAD') {
+	LWP::Debug::debug("MDTM");
+	if (my $mod_time = $ftp->mdtm($remote_file)) {
+	    $response->last_modified($mod_time);
+	    if (my $ims = $request->if_modified_since) {
+		if ($mod_time <= $ims) {
+		    $response->code(&HTTP::Status::RC_NOT_MODIFIED);
+		    $response->message("Not modified");
+		    return $response;
+		}
+	    }
+	}
+
+	my $data;  # the data handle
+	LWP::Debug::debug("retrieve file?");
+	if (length($remote_file) and $data = $ftp->retr($remote_file)) {
+	    my($type, @enc) = LWP::MediaTypes::guess_media_type($remote_file);
+	    $response->header('Content-Type',   $type) if $type;
+	    for (@enc) {
+		$response->push_header('Content-Encoding', $_);
+	    }
+	    my $mess = $ftp->message;
+	    LWP::Debug::debug($mess);
+	    if ($mess =~ /\((\d+)\s+bytes\)/) {
+		$response->header('Content-Length', "$1");
+	    }
+
+	    if ($method ne 'HEAD') {
+		# Read data from server
+		$response = $self->collect($arg, $response, sub {
+		    my $content = '';
+		    my $result = $data->read($content, $size);
+		    return \$content;
+		} );
+	    }
+	    unless ($data->close) {
+		# Something did not work too well
+		if ($method ne 'HEAD') {
+		    $response->code(&HTTP::Status::RC_INTERNAL_SERVER_ERROR);
+		    $response->message("FTP close response: " . $ftp->code .
+				       " " . $ftp->message);
+		}
+	    }
+	} elsif (!length($remote_file) || $ftp->code == 550) {
+	    # 550 not a plain file, try to list instead
+	    if (length($remote_file) && !$ftp->cwd($remote_file)) {
+		LWP::Debug::debug("chdir before listing failed");
+		return HTTP::Response->new(&HTTP::Status::RC_NOT_FOUND,
+					   "File '$remote_file' not found");
+	    }
+
+	    # It should now be safe to try to list the directory
+	    LWP::Debug::debug("dir");
+	    my @lsl = $ftp->dir;
+
+	    # Try to figure out if the user want us to convert the
+	    # directory listing to HTML.
+	    my @variants =
+	      (
+	       ['html',  0.60, 'text/html'            ],
+	       ['dir',   1.00, 'text/ftp-dir-listing' ]
+	      );
+	    #$HTTP::Negotiate::DEBUG=1;
+	    my $prefer = HTTP::Negotiate::choose(\@variants, $request);
+
+	    my $content = '';
+
+	    if (!defined($prefer)) {
+		return HTTP::Response->new(&HTTP::Status::RC_NOT_ACCEPTABLE,
+			       "Neither HTML nor directory listing wanted");
+	    } elsif ($prefer eq 'html') {
+		$response->header('Content-Type' => 'text/html');
+		$content = "<HEAD><TITLE>File Listing</TITLE>\n";
+		my $base = $request->url->clone;
+		my $path = $base->epath;
+		$base->epath("$path/") unless $path =~ m|/$|;
+		$content .= qq(<BASE HREF="$base">\n</HEAD>\n);
+		$content .= "<BODY>\n<UL>\n";
+		for (File::Listing::parse_dir(\@lsl, 'GMT')) {
+		    my($name, $type, $size, $mtime, $mode) = @$_;
+		    $content .= qq(  <LI> <a href="$name">$name</a>);
+		    $content .= " $size bytes" if $type eq 'f';
+		    $content .= "\n";
+		}
+		$content .= "</UL></body>\n";
+	    } else {
+		$response->header('Content-Type', 'text/ftp-dir-listing');
+		$content = join("\n", @lsl, '');
+	    }
+
+	    $response->header('Content-Length', length($content));
+
+	    if ($method ne 'HEAD') {
+		$response = $self->collect_once($arg, $response, $content);
+	    }
+	} else {
+	    my $res = HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+			  "FTP return code " . $ftp->code);
+	    $res->content_type("text/plain");
+	    $res->content($ftp->message);
+	    return $res;
+	}
+    } elsif ($method eq 'PUT') {
+	# method must be PUT
+	unless (length($remote_file)) {
+	    return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				       "Must have a file name to PUT to");
+	}
+	my $data;
+	if ($data = $ftp->stor($remote_file)) {
+	    LWP::Debug::debug($ftp->message);
+	    LWP::Debug::debug("$data");
+	    my $content = $request->content;
+	    my $bytes = 0;
+	    if (defined $content) {
+		if (ref($content) eq 'SCALAR') {
+		    $bytes = $data->write($$content, length($$content));
+		} elsif (ref($content) eq 'CODE') {
+		    my($buf, $n);
+		    while (length($buf = &$content)) {
+			$n = $data->write($buf, length($buf));
+			last unless $n;
+			$bytes += $n;
+		    }
+		} elsif (!ref($content)) {
+		    if (defined $content && length($content)) {
+			$bytes = $data->write($content, length($content));
+		    }
+		} else {
+		    die "Bad content";
+		}
+	    }
+	    $data->close;
+	    LWP::Debug::debug($ftp->message);
+
+	    $response->code(&HTTP::Status::RC_CREATED);
+	    $response->header('Content-Type', 'text/plain');
+	    $response->content("$bytes bytes stored as $remote_file on $host\n")
+
+	} else {
+	    my $res = HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+					  "FTP return code " . $ftp->code);
+	    $res->content_type("text/plain");
+	    $res->content($ftp->message);
+	    return $res;
+	}
+    } else {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   "Illegal method $method");
+    }
+
+    $response;
+}
+
+1;
+
+__END__
+
+# This is what RFC 1738 has to say about FTP access:
+# --------------------------------------------------
+#
+# 3.2. FTP
+#
+#    The FTP URL scheme is used to designate files and directories on
+#    Internet hosts accessible using the FTP protocol (RFC959).
+#
+#    A FTP URL follow the syntax described in Section 3.1.  If :<port> is
+#    omitted, the port defaults to 21.
+#
+# 3.2.1. FTP Name and Password
+#
+#    A user name and password may be supplied; they are used in the ftp
+#    "USER" and "PASS" commands after first making the connection to the
+#    FTP server.  If no user name or password is supplied and one is
+#    requested by the FTP server, the conventions for "anonymous" FTP are
+#    to be used, as follows:
+#
+#         The user name "anonymous" is supplied.
+#
+#         The password is supplied as the Internet e-mail address
+#         of the end user accessing the resource.
+#
+#    If the URL supplies a user name but no password, and the remote
+#    server requests a password, the program interpreting the FTP URL
+#    should request one from the user.
+#
+# 3.2.2. FTP url-path
+#
+#    The url-path of a FTP URL has the following syntax:
+#
+#         <cwd1>/<cwd2>/.../<cwdN>/<name>;type=<typecode>
+#
+#    Where <cwd1> through <cwdN> and <name> are (possibly encoded) strings
+#    and <typecode> is one of the characters "a", "i", or "d".  The part
+#    ";type=<typecode>" may be omitted. The <cwdx> and <name> parts may be
+#    empty. The whole url-path may be omitted, including the "/"
+#    delimiting it from the prefix containing user, password, host, and
+#    port.
+#
+#    The url-path is interpreted as a series of FTP commands as follows:
+#
+#       Each of the <cwd> elements is to be supplied, sequentially, as the
+#       argument to a CWD (change working directory) command.
+#
+#       If the typecode is "d", perform a NLST (name list) command with
+#       <name> as the argument, and interpret the results as a file
+#       directory listing.
+#
+#       Otherwise, perform a TYPE command with <typecode> as the argument,
+#       and then access the file whose name is <name> (for example, using
+#       the RETR command.)
+#
+#    Within a name or CWD component, the characters "/" and ";" are
+#    reserved and must be encoded. The components are decoded prior to
+#    their use in the FTP protocol.  In particular, if the appropriate FTP
+#    sequence to access a particular file requires supplying a string
+#    containing a "/" as an argument to a CWD or RETR command, it is
+#    necessary to encode each "/".
+#
+#    For example, the URL <URL:ftp://myname@host.dom/%2Fetc/motd> is
+#    interpreted by FTP-ing to "host.dom", logging in as "myname"
+#    (prompting for a password if it is asked for), and then executing
+#    "CWD /etc" and then "RETR motd". This has a different meaning from
+#    <URL:ftp://myname@host.dom/etc/motd> which would "CWD etc" and then
+#    "RETR motd"; the initial "CWD" might be executed relative to the
+#    default directory for "myname". On the other hand,
+#    <URL:ftp://myname@host.dom//etc/motd>, would "CWD " with a null
+#    argument, then "CWD etc", and then "RETR motd".
+#
+#    FTP URLs may also be used for other operations; for example, it is
+#    possible to update a file on a remote file server, or infer
+#    information about it from the directory listings. The mechanism for
+#    doing so is not spelled out here.
+#
+# 3.2.3. FTP Typecode is Optional
+#
+#    The entire ;type=<typecode> part of a FTP URL is optional. If it is
+#    omitted, the client program interpreting the URL must guess the
+#    appropriate mode to use. In general, the data content type of a file
+#    can only be guessed from the name, e.g., from the suffix of the name;
+#    the appropriate type code to be used for transfer of the file can
+#    then be deduced from the data content of the file.
+#
+# 3.2.4 Hierarchy
+#
+#    For some file systems, the "/" used to denote the hierarchical
+#    structure of the URL corresponds to the delimiter used to construct a
+#    file name hierarchy, and thus, the filename will look similar to the
+#    URL path. This does NOT mean that the URL is a Unix filename.
+#
+# 3.2.5. Optimization
+#
+#    Clients accessing resources via FTP may employ additional heuristics
+#    to optimize the interaction. For some FTP servers, for example, it
+#    may be reasonable to keep the control connection open while accessing
+#    multiple URLs from the same server. However, there is no common
+#    hierarchical model to the FTP protocol, so if a directory change
+#    command has been given, it is impossible in general to deduce what
+#    sequence should be given to navigate to another directory for a
+#    second retrieval, if the paths are different.  The only reliable
+#    algorithm is to disconnect and reestablish the control connection.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/gopher.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/gopher.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/gopher.pm	(revision 10506)
@@ -0,0 +1,215 @@
+#
+# $Id$
+
+# Implementation of the gopher protocol (RFC 1436)
+#
+# This code is based on 'wwwgopher.pl,v 0.10 1994/10/17 18:12:34 shelden'
+# which in turn is a vastly modified version of Oscar's http'get()
+# dated 28/3/94 in <ftp://cui.unige.ch/PUBLIC/oscar/scripts/http.pl>
+# including contributions from Marc van Heyningen and Martijn Koster.
+#
+
+package LWP::Protocol::gopher;
+
+use strict;
+use vars qw(@ISA);
+
+require HTTP::Response;
+require HTTP::Status;
+require IO::Socket;
+require IO::Select;
+
+require LWP::Protocol;
+@ISA = qw(LWP::Protocol);
+
+
+my %gopher2mimetype = (
+    '0' => 'text/plain',                # 0 file
+    '1' => 'text/html',                 # 1 menu
+					# 2 CSO phone-book server
+					# 3 Error
+    '4' => 'application/mac-binhex40',  # 4 BinHexed Macintosh file
+    '5' => 'application/zip',           # 5 DOS binary archive of some sort
+    '6' => 'application/octet-stream',  # 6 UNIX uuencoded file.
+    '7' => 'text/html',                 # 7 Index-Search server
+					# 8 telnet session
+    '9' => 'application/octet-stream',  # 9 binary file
+    'h' => 'text/html',                 # html
+    'g' => 'image/gif',                 # gif
+    'I' => 'image/*',                   # some kind of image
+);
+
+my %gopher2encoding = (
+    '6' => 'x_uuencode',                # 6 UNIX uuencoded file.
+);
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
+
+    LWP::Debug::trace('()');
+
+    $size = 4096 unless $size;
+
+    # check proxy
+    if (defined $proxy) {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'You can not proxy through the gopher');
+    }
+
+    my $url = $request->url;
+    die "bad scheme" if $url->scheme ne 'gopher';
+
+
+    my $method = $request->method;
+    unless ($method eq 'GET' || $method eq 'HEAD') {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'Library does not allow method ' .
+				   "$method for 'gopher:' URLs");
+    }
+
+    my $gophertype = $url->gtype;
+    unless (exists $gopher2mimetype{$gophertype}) {
+	return HTTP::Response->new(&HTTP::Status::RC_NOT_IMPLEMENTED,
+				   'Library does not support gophertype ' .
+				   $gophertype);
+    }
+
+    my $response = HTTP::Response->new(&HTTP::Status::RC_OK, "OK");
+    $response->header('Content-type' => $gopher2mimetype{$gophertype}
+					|| 'text/plain');
+    $response->header('Content-Encoding' => $gopher2encoding{$gophertype})
+	if exists $gopher2encoding{$gophertype};
+
+    if ($method eq 'HEAD') {
+	# XXX: don't even try it so we set this header
+	$response->header('Client-Warning' => 'Client answer only');
+	return $response;
+    }
+    
+    if ($gophertype eq '7' && ! $url->search) {
+      # the url is the prompt for a gopher search; supply boiler-plate
+      return $self->collect_once($arg, $response, <<"EOT");
+<HEAD>
+<TITLE>Gopher Index</TITLE>
+<ISINDEX>
+</HEAD>
+<BODY>
+<H1>$url<BR>Gopher Search</H1>
+This is a searchable Gopher index.
+Use the search function of your browser to enter search terms.
+</BODY>
+EOT
+    }
+
+    my $host = $url->host;
+    my $port = $url->port;
+
+    my $requestLine = "";
+
+    my $selector = $url->selector;
+    if (defined $selector) {
+	$requestLine .= $selector;
+	my $search = $url->search;
+	if (defined $search) {
+	    $requestLine .= "\t$search";
+	    my $string = $url->string;
+	    if (defined $string) {
+		$requestLine .= "\t$string";
+	    }
+	}
+    }
+    $requestLine .= "\015\012";
+
+    # potential request headers are just ignored
+
+    # Ok, lets make the request
+    my $socket = IO::Socket::INET->new(PeerAddr => $host,
+				       PeerPort => $port,
+				       Timeout  => $timeout);
+    die "Can't connect to $host:$port" unless $socket;
+    my $sel = IO::Select->new($socket);
+
+    {
+	die "write timeout" if $timeout && !$sel->can_write($timeout);
+	my $n = syswrite($socket, $requestLine, length($requestLine));
+	die $! unless defined($n);
+	die "short write" if $n != length($requestLine);
+    }
+
+    my $user_arg = $arg;
+
+    # must handle menus in a special way since they are to be
+    # converted to HTML.  Undefing $arg ensures that the user does
+    # not see the data before we get a change to convert it.
+    $arg = undef if $gophertype eq '1' || $gophertype eq '7';
+
+    # collect response
+    my $buf = '';
+    $response = $self->collect($arg, $response, sub {
+	die "read timeout" if $timeout && !$sel->can_read($timeout);
+        my $n = sysread($socket, $buf, $size);
+	die $! unless defined($n);
+	return \$buf;
+      } );
+
+    # Convert menu to HTML and return data to user.
+    if ($gophertype eq '1' || $gophertype eq '7') {
+	my $content = menu2html($response->content);
+	if (defined $user_arg) {
+	    $response = $self->collect_once($user_arg, $response, $content);
+	} else {
+	    $response->content($content);
+	}
+    }
+
+    $response;
+}
+
+
+sub gopher2url
+{
+    my($gophertype, $path, $host, $port) = @_;
+
+    my $url;
+
+    if ($gophertype eq '8' || $gophertype eq 'T') {
+	# telnet session
+	$url = URI::URL->new($gophertype eq '8' ? 'telnet:' : 'tn3270:');
+	$url->user($path) if defined $path;
+    } else {
+	$path = URI::Escape::uri_escape($path);
+	$url = URI::URL->new("gopher:/$gophertype$path");
+    }
+    $url->host($host);
+    $url->port($port);
+    $url;
+}
+
+sub menu2html {
+    my($menu) = @_;
+
+    $menu =~ s/\015//g;  # remove carriage return
+    my $tmp = <<"EOT";
+<HTML>
+<HEAD>
+   <TITLE>Gopher menu</TITLE>
+</HEAD>
+<BODY>
+<H1>Gopher menu</H1>
+EOT
+    for (split("\n", $menu)) {
+	last if /^\./;
+	my($pretty, $path, $host, $port) = split("\t");
+
+	$pretty =~ s/^(.)//;
+	my $type = $1;
+
+	my $url = gopher2url($type, $path, $host, $port)->as_string;
+	$tmp .= qq{<A HREF="$url">$pretty</A><BR>\n};
+    }
+    $tmp .= "</BODY>\n</HTML>\n";
+    $tmp;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/http.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/http.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/http.pm	(revision 10506)
@@ -0,0 +1,252 @@
+#
+# $Id$
+
+package LWP::Protocol::http;
+
+require LWP::Debug;
+require HTTP::Response;
+require HTTP::Status;
+require IO::Socket;
+require IO::Select;
+
+require LWP::Protocol;
+@ISA = qw(LWP::Protocol);
+
+use strict;
+my $CRLF         = "\015\012";     # how lines should be terminated;
+				   # "\r\n" is not correct on all systems, for
+				   # instance MacPerl defines it to "\012\015"
+
+sub _new_socket
+{
+    my($self, $host, $port, $timeout) = @_;
+
+    local($^W) = 0;  # IO::Socket::INET can be noisy
+    my $sock = IO::Socket::INET->new(PeerAddr => $host,
+				     PeerPort => $port,
+				     Proto    => 'tcp',
+				     Timeout  => $timeout,
+				    );
+    unless ($sock) {
+	# IO::Socket::INET leaves additional error messages in $@
+	$@ =~ s/^.*?: //;
+	die "Can't connect to $host:$port ($@)";
+    }
+    $sock;
+}
+
+
+sub _check_sock
+{
+    #my($self, $req, $sock) = @_;
+}
+
+sub _get_sock_info
+{
+    my($self, $res, $sock) = @_;
+    $res->header("Client-Peer" =>
+		 $sock->peerhost . ":" . $sock->peerport);
+}
+
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
+    LWP::Debug::trace('()');
+
+    $size ||= 4096;
+
+    # check method
+    my $method = $request->method;
+    unless ($method =~ /^[A-Za-z0-9_!\#\$%&\'*+\-.^\`|~]+$/) {  # HTTP token
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'Library does not allow method ' .
+				  "$method for 'http:' URLs";
+    }
+
+    my $url = $request->url;
+    my($host, $port, $fullpath);
+
+    # Check if we're proxy'ing
+    if (defined $proxy) {
+	# $proxy is an URL to an HTTP server which will proxy this request
+	$host = $proxy->host;
+	$port = $proxy->port;
+	$fullpath = $url->as_string;
+    }
+    else {
+	$host = $url->host;
+	$port = $url->port;
+	$fullpath = $url->full_path;
+    }
+
+    # connect to remote site
+    my $socket = $self->_new_socket($host, $port, $timeout);
+    $self->_check_sock($request, $socket);
+	    
+    my $sel = IO::Select->new($socket) if $timeout;
+
+    my $request_line = "$method $fullpath HTTP/1.0$CRLF";
+
+    my $h = $request->headers->clone;
+    my $cont_ref = $request->content_ref;
+    $cont_ref = $$cont_ref if ref($$cont_ref);
+    my $ctype = ref($cont_ref);
+
+    # If we're sending content we *have* to specify a content length
+    # otherwise the server won't know a messagebody is coming.
+    if ($ctype eq 'CODE') {
+	die 'No Content-Length header for request with dynamic content'
+	    unless defined($h->header('Content-Length')) ||
+		   $h->content_type =~ /^multipart\//;
+	# For HTTP/1.1 we could have used chunked transfer encoding...
+    } else {
+	$h->header('Content-Length' => length $$cont_ref)
+	        if defined($$cont_ref) && length($$cont_ref);
+    }
+    
+    # HTTP/1.1 will require us to send the 'Host' header, so we might
+    # as well start now.
+    my $hhost = $url->netloc;
+    $hhost =~ s/^([^\@]*)\@//;  # get rid of potential "user:pass@"
+    $h->header('Host' => $hhost) unless defined $h->header('Host');
+
+    # add authorization header if we need them.  HTTP URLs do
+    # not really support specification of user and password, but
+    # we allow it.
+    if (defined($1) && not $h->header('Authorization')) {
+	$h->authorization_basic($url->user, $url->password);
+    }
+
+    my $buf = $request_line . $h->as_string($CRLF) . $CRLF;
+    my $n;  # used for return value from syswrite/sysread
+
+    die "write timeout" if $timeout && !$sel->can_write($timeout);
+    $n = $socket->syswrite($buf, length($buf));
+    die $! unless defined($n);
+    die "short write" unless $n == length($buf);
+    LWP::Debug::conns($buf);
+
+    if ($ctype eq 'CODE') {
+	while ( ($buf = &$cont_ref()), defined($buf) && length($buf)) {
+	    die "write timeout" if $timeout && !$sel->can_write($timeout);
+	    $n = $socket->syswrite($buf, length($buf));
+	    die $! unless defined($n);
+	    die "short write" unless $n == length($buf);
+	    LWP::Debug::conns($buf);
+	}
+    } elsif (defined($$cont_ref) && length($$cont_ref)) {
+	die "write timeout" if $timeout && !$sel->can_write($timeout);
+	$n = $socket->syswrite($$cont_ref, length($$cont_ref));
+	die $! unless defined($n);
+	die "short write" unless $n == length($$cont_ref);
+	LWP::Debug::conns($buf);
+    }
+    
+    # read response line from server
+    LWP::Debug::debug('reading response');
+
+    my $response;
+    $buf = '';
+
+    # Inside this loop we will read the response line and all headers
+    # found in the response.
+    while (1) {
+	{
+	    die "read timeout" if $timeout && !$sel->can_read($timeout);
+	    $n = $socket->sysread($buf, $size, length($buf));
+	    die $! unless defined($n);
+	    die "unexpected EOF before status line seen" unless $n;
+	    LWP::Debug::conns($buf);
+	}
+	if ($buf =~ s/^(HTTP\/\d+\.\d+)[ \t]+(\d+)[ \t]*([^\012]*)\012//) {
+	    # HTTP/1.0 response or better
+	    my($ver,$code,$msg) = ($1, $2, $3);
+	    $msg =~ s/\015$//;
+	    LWP::Debug::debug("$ver $code $msg");
+	    $response = HTTP::Response->new($code, $msg);
+	    $response->protocol($ver);
+
+	    # ensure that we have read all headers.  The headers will be
+	    # terminated by two blank lines
+	    until ($buf =~ /^\015?\012/ || $buf =~ /\015?\012\015?\012/) {
+		# must read more if we can...
+		LWP::Debug::debug("need more header data");
+		die "read timeout" if $timeout && !$sel->can_read($timeout);
+		$n = $socket->sysread($buf, $size, length($buf));
+		die $! unless defined($n);
+		die "unexpected EOF before all headers seen" unless $n;
+		#LWP::Debug::conns($buf);
+	    }
+
+	    # now we start parsing the headers.  The strategy is to
+	    # remove one line at a time from the beginning of the header
+	    # buffer ($res).
+	    my($key, $val);
+	    while ($buf =~ s/([^\012]*)\012//) {
+		my $line = $1;
+
+		# if we need to restore as content when illegal headers
+		# are found.
+		my $save = "$line\012"; 
+
+		$line =~ s/\015$//;
+		last unless length $line;
+
+		if ($line =~ /^([a-zA-Z0-9_\-]+)\s*:\s*(.*)/) {
+		    $response->push_header($key, $val) if $key;
+		    ($key, $val) = ($1, $2);
+		} elsif ($line =~ /^\s+(.*)/) {
+		    unless ($key) {
+			$response->header("Client-Warning" =>
+					 => "Illegal continuation header");
+			$buf = "$save$buf";
+			last;
+		    }
+		    $val .= " $1";
+		} else {
+		    $response->header("Client-Warning" =>
+				      "Illegal header '$line'");
+		    $buf = "$save$buf";
+		    last;
+		}
+	    }
+	    $response->push_header($key, $val) if $key;
+	    last;
+
+	} elsif ((length($buf) >= 5 and $buf !~ /^HTTP\//) or
+		 $buf =~ /\012/ ) {
+	    # HTTP/0.9 or worse
+	    LWP::Debug::debug("HTTP/0.9 assume OK");
+	    $response = HTTP::Response->new(&HTTP::Status::RC_OK, "OK");
+	    $response->protocol('HTTP/0.9');
+	    last;
+
+	} else {
+	    # need more data
+	    LWP::Debug::debug("need more status line data");
+	}
+    };
+    $response->request($request);
+    $self->_get_sock_info($response, $socket);
+
+
+    my $usebuf = length($buf) > 0;
+    $response = $self->collect($arg, $response, sub {
+        if ($usebuf) {
+	    $usebuf = 0;
+	    return \$buf;
+	}
+	die "read timeout" if $timeout && !$sel->can_read($timeout);
+	my $n = $socket->sysread($buf, $size);
+	die $! unless defined($n);
+	#LWP::Debug::conns($buf);
+	return \$buf;
+	} );
+
+    $socket->close;
+
+    $response;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/https.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/https.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/https.pm	(revision 10506)
@@ -0,0 +1,59 @@
+#
+# $Id$
+
+use strict;
+
+package LWP::Protocol::https;
+require Net::SSL;  # from Crypt-SSLeay
+
+use vars qw(@ISA);
+
+require LWP::Protocol::http;
+@ISA=qw(LWP::Protocol::http);
+
+sub _new_socket
+{
+    my($self, $host, $port, $timeout) = @_;
+    local($^W) = 0;  # IO::Socket::INET can be noisy
+    my $sock = Net::SSL->new(PeerAddr => $host,
+			     PeerPort => $port,
+			     Proto    => 'tcp',
+			     Timeout  => $timeout,
+			    );
+    unless ($sock) {
+	# IO::Socket::INET leaves additional error messages in $@
+	$@ =~ s/^.*?: //;
+	die "Can't connect to $host:$port ($@)";
+    }
+    $sock;
+}
+
+sub _check_sock
+{
+    my($self, $req, $sock) = @_;
+    my $check = $req->header("If-SSL-Cert-Subject");
+    if (defined $check) {
+	my $cert = $sock->get_peer_certificate ||
+	    die "Missing SSL certificate";
+	my $subject = $cert->subject_name;
+	die "Bad SSL certificate subject: '$subject' !~ /$check/"
+	    unless $subject =~ /$check/;
+	$req->remove_header("If-SSL-Cert-Subject");  # don't pass it on
+    }
+}
+
+sub _get_sock_info
+{
+    my $self = shift;
+    $self->SUPER::_get_sock_info(@_);
+    my($res, $sock) = @_;
+    $res->header("Client-SSL-Cipher" => $sock->get_cipher);
+    my $cert = $sock->get_peer_certificate;
+    if ($cert) {
+	$res->header("Client-SSL-Cert-Subject" => $cert->subject_name);
+	$res->header("Client-SSL-Cert-Issuer" => $cert->issuer_name);
+    }
+    $res->header("Client-SSL-Warning" => "Peer certificate not verified");
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/mailto.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/mailto.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/mailto.pm	(revision 10506)
@@ -0,0 +1,87 @@
+#
+# $Id$
+#
+# This module implements the mailto protocol.  It is just a simple
+# frontend to the Unix sendmail program.  In the long run this module
+# will built using the Mail::Send module.
+
+package LWP::Protocol::mailto;
+
+require LWP::Protocol;
+require HTTP::Request;
+require HTTP::Response;
+require HTTP::Status;
+
+use Carp;
+
+@ISA = qw(LWP::Protocol);
+
+$SENDMAIL = "/usr/lib/sendmail";
+
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size) = @_;
+
+    # check proxy
+    if (defined $proxy)
+    {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'You can not proxy with mail';
+    }
+
+    # check method
+    $method = $request->method;
+
+    if ($method ne 'POST') {
+	return new HTTP::Response &HTTP::Status::RC_BAD_REQUEST,
+				  'Library does not allow method ' .
+				  "$method for 'mailto:' URLs";
+    }
+
+    # check url
+    my $url = $request->url;
+
+    my $scheme = $url->scheme;
+    if ($scheme ne 'mailto') {
+	return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				  "LWP::file::request called for '$scheme'";
+    }
+    unless (-x $SENDMAIL) {
+	return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				  "You don't have $SENDMAIL";
+    }
+
+    open(SENDMAIL, "| $SENDMAIL -oi -t") or
+	return new HTTP::Response &HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				  "Can't run $SENDMAIL: $!";
+
+    my $addr = $url->encoded822addr;
+
+    $request->header('To', $addr);
+    print SENDMAIL $request->headers_as_string;
+    print SENDMAIL "\n";
+    my $content = $request->content;
+    if (defined $content) {
+	my $contRef = ref($content) ? $content : \$content;
+	if (ref($contRef) eq 'SCALAR') {
+	    print SENDMAIL $$contRef;
+	} elsif (ref($contRef) eq 'CODE') {
+	    # Callback provides data
+	    my $d;
+	    while (length($d = &$contRef)) {
+		print SENDMAIL $d;
+	    }
+	}
+    }
+    close(SENDMAIL);
+
+    my $response = new HTTP::Response &HTTP::Status::RC_ACCEPTED,
+				     'Mail accepted by sendmail';
+    $response->header('Content-Type', 'text/plain');
+    $response->content("Mail sent to <$addr>\n");
+
+    return $response;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/nntp.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/nntp.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Protocol/nntp.pm	(revision 10506)
@@ -0,0 +1,142 @@
+#
+# $Id$
+
+# Implementation of the Network News Transfer Protocol (RFC 977)
+#
+
+package LWP::Protocol::nntp;
+
+require LWP::Protocol;
+@ISA = qw(LWP::Protocol);
+
+require LWP::Debug;
+require HTTP::Response;
+require HTTP::Status;
+require Net::NNTP;
+
+use strict;
+
+
+sub request
+{
+    my($self, $request, $proxy, $arg, $size, $timeout) = @_;
+
+    LWP::Debug::trace('()');
+
+    $size = 4096 unless $size;
+
+    # Check for proxy
+    if (defined $proxy) {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'You can not proxy through NNTP');
+    }
+
+    # Check that the scheme is as expected
+    my $url = $request->url;
+    my $scheme = $url->scheme;
+    unless ($scheme eq 'news') {
+	return HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				   "LWP::Protocol::nntp::request called for '$scheme'");
+    }
+
+    # check for a valid method
+    my $method = $request->method;
+    unless ($method eq 'GET' || $method eq 'HEAD' || $method eq 'POST') {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   'Library does not allow method ' .
+				   "$method for 'news:' URLs");
+    }
+
+    # extract the identifier and check against posting to an article
+    my $groupart = $url->groupart;
+    my $is_art = $groupart =~ /@/;
+
+    if ($is_art && $method eq 'POST') {
+	return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST,
+				   "Can't post to an article <$groupart>");
+    }
+
+    my $nntp = Net::NNTP->new(undef,
+			      #Port    => 18574,
+			      Timeout => $timeout,
+			      #Debug   => 1,
+			     );
+    die "Can't connect to nntp server" unless $nntp;
+
+    # Check the initial welcome message from the NNTP server
+    if ($nntp->status != 2) {
+	return HTTP::Response->new(&HTTP::Status::RC_SERVICE_UNAVAILABLE,
+				   $nntp->message);
+    }
+    my $response = HTTP::Response->new(&HTTP::Status::RC_OK, "OK");
+
+    my $mess = $nntp->message;
+    LWP::Debug::debug($mess);
+
+    # Try to extract server name from greating message.
+    # Don't know if this works well for a large class of servers, but
+    # this works for our server.
+    $mess =~ s/\s+ready\b.*//;
+    $mess =~ s/^\S+\s+//;
+    $response->header(Server => $mess);
+
+
+    # First we handle posting of articles
+    if ($method eq 'POST') {
+	return HTTP::Response->new(&HTTP::Status::RC_NOT_IMPLEMENTED,
+				   "POST not implemented yet");
+    }
+
+    # The method must be "GET" or "HEAD" by now
+    if (!$is_art) {
+	if (!$nntp->group($groupart)) {
+	    return HTTP::Response->new(&HTTP::Status::RC_NOT_FOUND,
+				       $nntp->message);
+	}
+	return HTTP::Response->new(&HTTP::Status::RC_NOT_IMPLEMENTED,
+				   "GET newsgroup not implemented yet");
+    }
+
+    # Send command to server to retrieve an article (or just the headers)
+    my $get = $method eq 'HEAD' ? "head" : "article";
+    my $art = $nntp->$get("<$groupart>");
+    unless ($art) {
+	return HTTP::Response->new(&HTTP::Status::RC_NOT_FOUND,
+				   $nntp->message);
+    }
+    LWP::Debug::debug($nntp->message);
+    
+    # Parse headers
+    my($key, $val);
+    while ($_ = shift @$art) {
+	if (/^\s+$/) {
+	    last;  # end of headers
+	} elsif (/^(\S+):\s*(.*)/) {
+	    $response->push_header($key, $val) if $key;
+	    ($key, $val) = ($1, $2);
+	} elsif (/^\s+(.*)/) {
+	    next unless $key;
+	    $val .= $1;
+	} else {
+	    unshift(@$art, $_);
+	    last;
+	}
+    }
+    $response->push_header($key, $val) if $key;
+
+    # Ensure that there is a Content-Type header
+    $response->header("Content-Type", "text/plain")
+	unless $response->header("Content-Type");
+
+    # Collect the body
+    $response = $self->collect_once($arg, $response, join("", @$art))
+      if @$art;
+
+    # Say godbye to the server
+    $nntp->quit;
+    $nntp = undef;
+
+    $response;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/RobotUA.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/RobotUA.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/RobotUA.pm	(revision 10506)
@@ -0,0 +1,285 @@
+# $Id$
+
+package LWP::RobotUA;
+
+require LWP::UserAgent;
+@ISA = qw(LWP::UserAgent);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+require WWW::RobotRules;
+require HTTP::Request;
+require HTTP::Response;
+
+use Carp ();
+use LWP::Debug ();
+use HTTP::Status ();
+use HTTP::Date qw(time2str);
+use strict;
+
+=head1 NAME
+
+LWP::RobotUA - A class for Web Robots
+
+=head1 SYNOPSIS
+
+  require LWP::RobotUA;
+  $ua = new LWP::RobotUA 'my-robot/0.1', 'me@foo.com';
+  $ua->delay(10);  # be very nice, go slowly
+  ...
+  # just use it just like a normal LWP::UserAgent
+  $res = $ua->request($req);
+
+=head1 DESCRIPTION
+
+This class implements a user agent that is suitable for robot
+applications.  Robots should be nice to the servers they visit.  They
+should consult the F<robots.txt> file to ensure that they are welcomed
+and they should not send too frequent requests.
+
+But, before you consider writing a robot take a look at
+<URL:http://info.webcrawler.com/mak/projects/robots/robots.html>.
+
+When you use a I<LWP::RobotUA> as your user agent, then you do not
+really have to think about these things yourself.  Just send requests
+as you do when you are using a normal I<LWP::UserAgent> and this
+special agent will make sure you are nice.
+
+=head1 METHODS
+
+The LWP::RobotUA is a sub-class of LWP::UserAgent and implements the
+same methods. In addition the following methods are provided:
+
+=over 4
+
+=cut
+
+
+#
+# Additional attributes in addition to those found in LWP::UserAgent:
+#
+# $self->{'delay'}    Required delay between request to the same
+#                     server in minutes.
+#
+# $self->{'rules'}     A WWW::RobotRules object
+#
+
+
+=item $ua = LWP::RobotUA->new($agent_name, $from, [$rules])
+
+Your robot's name and the mail address of the human responsible for
+the robot (i.e. you) is required by the constructor.
+
+Optionally it allows you to specify the I<WWW::RobotRules> object to
+use.
+
+=cut
+
+sub new
+{
+    my($class,$name,$from,$rules) = @_;
+
+    Carp::croak('LWP::RobotUA name required') unless $name;
+    Carp::croak('LWP::RobotUA from address required') unless $from;
+
+    my $self = new LWP::UserAgent;
+    $self = bless $self, $class;
+
+    $self->{'delay'} = 1;   # minutes
+    $self->{'agent'} = $name;
+    $self->{'from'}  = $from;
+    $self->{'use_sleep'} = 1;
+
+    if ($rules) {
+	$rules->agent($name);
+	$self->{'rules'} = $rules;
+    } else {
+	$self->{'rules'} = new WWW::RobotRules $name;
+    }
+
+    $self;
+}
+
+
+=item $ua->delay([$minutes])
+
+Set the minimum delay between requests to the same server.  The
+default is 1 minute.
+
+=item $ua->use_sleep([$boolean])
+
+Get/set a value indicating wether the UA should sleep() if request
+arrive to fast (before $ua->delay minutes has passed).  The default is
+TRUE.  If this value is FALSE then an internal SERVICE_UNAVAILABLE
+response will be generated.  It will have an Retry-After header that
+indicate when it is OK to send another request to this server.
+
+=cut
+
+sub delay     { shift->_elem('delay',     @_); }
+sub use_sleep { shift->_elem('use_sleep', @_); }
+
+sub agent
+{
+    my $self = shift;
+    my $old = $self->SUPER::agent(@_);
+    if (@_) {
+	# Changing our name means to start fresh
+	$self->{'rules'}->agent($self->{'agent'}); 
+    }
+    $old;
+}
+
+
+=item $ua->rules([$rules])
+
+Set/get which I<WWW::RobotRules> object to use. 
+
+=cut
+
+sub rules {
+    my $self = shift;
+    my $old = $self->_elem('rules', @_);
+    $self->{'rules'}->agent($self->{'agent'}) if @_;
+    $old;
+}
+
+
+=item $ua->no_visits($netloc)
+
+Returns the number of documents fetched from this server host. Yes I
+know, this method should probably have been named num_visits() or
+something like that :-(
+
+=cut
+
+sub no_visits
+{
+    my($self, $netloc) = @_;
+    $self->{'rules'}->no_visits($netloc);
+}
+
+*host_count = \&no_visits;  # backwards compatibility with LWP-5.02
+
+
+=item $ua->host_wait($netloc)
+
+Returns the number of seconds (from now) you must wait before you can
+make a new request to this host.
+
+=cut
+
+sub host_wait
+{
+    my($self, $netloc) = @_;
+    return undef unless defined $netloc;
+    my $last = $self->{'rules'}->last_visit($netloc);
+    if ($last) {
+	my $wait = int($self->{'delay'} * 60 - (time - $last));
+	$wait = 0 if $wait < 0;
+	return $wait;
+    }
+    return 0;
+}
+
+
+sub simple_request
+{
+    my($self, $request, $arg, $size) = @_;
+
+    LWP::Debug::trace('()');
+
+    # Do we try to access a new server?
+    my $allowed = $self->{'rules'}->allowed($request->url);
+
+    if ($allowed < 0) {
+	LWP::Debug::debug("Host is not visited before, or robots.txt expired.");
+	# fetch "robots.txt"
+	my $robot_url = $request->url->clone;
+	$robot_url->path("robots.txt");
+	$robot_url->params(undef);
+	$robot_url->query(undef);
+	LWP::Debug::debug("Requesting $robot_url");
+
+	# make access to robot.txt legal since this will be a recursive call
+	$self->{'rules'}->parse($robot_url, ""); 
+
+	my $robot_req = new HTTP::Request 'GET', $robot_url;
+	my $robot_res = $self->request($robot_req);
+	my $fresh_until = $robot_res->fresh_until;
+	if ($robot_res->is_success) {
+	    LWP::Debug::debug("Parsing robot rules");
+	    $self->{'rules'}->parse($robot_url, $robot_res->content, 
+				    $fresh_until);
+	} else {
+	    LWP::Debug::debug("No robots.txt file found");
+	    $self->{'rules'}->parse($robot_url, "", $fresh_until);
+	}
+
+	# recalculate allowed...
+	$allowed = $self->{'rules'}->allowed($request->url);
+    }
+
+    # Check rules
+    unless ($allowed) {
+	return new HTTP::Response
+	  &HTTP::Status::RC_FORBIDDEN, 'Forbidden by robots.txt';
+    }
+
+    my $netloc = $request->url->netloc;
+    my $wait = $self->host_wait($netloc);
+
+    if ($wait) {
+	LWP::Debug::debug("Must wait $wait seconds");
+	if ($self->{'use_sleep'}) {
+	    sleep($wait)
+	} else {
+	    my $res = new HTTP::Response
+	      &HTTP::Status::RC_SERVICE_UNAVAILABLE, 'Please, slow down';
+	    $res->header('Retry-After', time2str(time + $wait));
+	    return $res;
+	}
+    }
+
+    # Perform the request
+    my $res = $self->SUPER::simple_request($request, $arg, $size);
+
+    $self->{'rules'}->visit($netloc);
+
+    $res;
+}
+
+
+=item $ua->as_string
+
+Returns a text that describe the state of the UA.
+Mainly useful for debugging.
+
+=cut
+
+sub as_string
+{
+    my $self = shift;
+    my @s;
+    push(@s, "Robot: $self->{'agent'} operated by $self->{'from'}  [$self]");
+    push(@s, "    Minimum delay: " . int($self->{'delay'}*60) . "s");
+    push(@s, "    Will sleep if too early") if $self->{'use_sleep'};
+    push(@s, "    Rules = $self->{'rules'}");
+    join("\n", @s, '');
+}
+
+1;
+
+=back
+
+=head1 SEE ALSO
+
+L<LWP::UserAgent>, L<WWW::RobotRules>
+
+=head1 COPYRIGHT
+
+Copyright 1996-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Simple.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Simple.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/Simple.pm	(revision 10506)
@@ -0,0 +1,329 @@
+#
+# $Id$
+
+=head1 NAME
+
+get, head, getprint, getstore, mirror - Procedural LWP interface
+
+=head1 SYNOPSIS
+
+ perl -MLWP::Simple -e 'getprint "http://www.sn.no"'
+
+ use LWP::Simple;
+ $content = get("http://www.sn.no/")
+ if (mirror("http://www.sn.no/", "foo") == RC_NOT_MODIFIED) {
+     ...
+ }
+
+ if (is_success(getprint("http://www.sn.no/"))) {
+     ...
+ }
+
+=head1 DESCRIPTION
+
+This interface is intended for those who want a simplified view of the
+libwww-perl library.  It should also be suitable for one-liners.  If
+you need more control or access to the header fields in the requests
+sent and responses received you should use the full object oriented
+interface provided by the C<LWP::UserAgent> module.
+
+The following functions are provided (and exported) by this module:
+
+=over 3
+
+=item get($url)
+
+The get() function will fetch the document identified by the given URL
+and return it.  It returns C<undef> if it fails.  The $url argument can
+be either a simple string or a reference to a URI::URL object.
+
+You will not be able to examine the response code or response headers
+(like 'Content-Type') when you are accessing the web using this
+function.  If you need this information you should use the full OO
+interface (see L<LWP::UserAgent>).
+
+=item head($url)
+
+Get document headers. Returns the following 5 values if successful:
+($content_type, $document_length, $modified_time, $expires, $server)
+
+Returns an empty list if it fails.  In scalar context returns TRUE if
+successful.
+
+=item getprint($url)
+
+Get and print a document identified by a URL. The document is printed
+on STDOUT as data is received from the network.  If the request fails,
+then the status code and message is printed on STDERR.  The return
+value is the HTTP response code.
+
+=item getstore($url, $file)
+
+Gets a document identified by a URL and stores it in the file. The
+return value is the HTTP response code.
+
+=item mirror($url, $file)
+
+Get and store a document identified by a URL, using
+I<If-modified-since>, and checking of the I<Content-Length>.  Returns
+the HTTP response code.
+
+=back
+
+This module also exports the HTTP::Status constants and procedures.
+These can be used when you check the response code from getprint(),
+getstore() and mirror().  The constants are:
+
+   RC_CONTINUE
+   RC_SWITCHING_PROTOCOLS
+   RC_OK
+   RC_CREATED
+   RC_ACCEPTED
+   RC_NON_AUTHORITATIVE_INFORMATION
+   RC_NO_CONTENT
+   RC_RESET_CONTENT
+   RC_PARTIAL_CONTENT
+   RC_MULTIPLE_CHOICES
+   RC_MOVED_PERMANENTLY
+   RC_MOVED_TEMPORARILY
+   RC_SEE_OTHER
+   RC_NOT_MODIFIED
+   RC_USE_PROXY
+   RC_BAD_REQUEST
+   RC_UNAUTHORIZED
+   RC_PAYMENT_REQUIRED
+   RC_FORBIDDEN
+   RC_NOT_FOUND
+   RC_METHOD_NOT_ALLOWED
+   RC_NOT_ACCEPTABLE
+   RC_PROXY_AUTHENTICATION_REQUIRED
+   RC_REQUEST_TIMEOUT
+   RC_CONFLICT
+   RC_GONE
+   RC_LENGTH_REQUIRED
+   RC_PRECONDITION_FAILED
+   RC_REQUEST_ENTITY_TOO_LARGE
+   RC_REQUEST_URI_TOO_LARGE
+   RC_UNSUPPORTED_MEDIA_TYPE
+   RC_INTERNAL_SERVER_ERROR
+   RC_NOT_IMPLEMENTED
+   RC_BAD_GATEWAY
+   RC_SERVICE_UNAVAILABLE
+   RC_GATEWAY_TIMEOUT
+   RC_HTTP_VERSION_NOT_SUPPORTED
+
+The HTTP::Status classification functions are:
+
+=over 3
+
+=item is_success($rc)
+
+Check if response code indicated successfull request.
+
+=item is_error($rc)
+
+Check if response code indicated that an error occured.
+
+=back
+
+The module will also export the LWP::UserAgent object as C<$ua> if you
+ask for it explicitly.
+
+The user agent created by this module will identify itself as
+"LWP::Simple/#.##" (where "#.##" is the libwww-perl version number)
+and will initialize its proxy defaults from the environment (by
+calling $ua->env_proxy).
+
+=head1 SEE ALSO
+
+L<LWP>, L<LWP::UserAgent>, L<HTTP::Status>, L<lwp-request>,
+L<lwp-mirror>
+
+=cut
+
+
+package LWP::Simple;
+
+use strict;
+use vars qw($ua %loop_check $FULL_LWP @EXPORT @EXPORT_OK $VERSION);
+
+require Exporter;
+
+@EXPORT = qw(get head getprint getstore mirror);
+@EXPORT_OK = qw($ua);
+
+# I really hate this.  I was a bad idea to do it in the first place.
+# Wonder how to get rid of it???  (It even makes LWP::Simple 7% slower
+# for trivial tests)
+use HTTP::Status;
+push(@EXPORT, @HTTP::Status::EXPORT);
+
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+$FULL_LWP++ if grep {lc($_) eq "http_proxy"} keys %ENV;
+
+
+sub import
+{
+    my $pkg = shift;
+    my $callpkg = caller;
+    if (grep $_ eq '$ua', @_) {
+	$FULL_LWP++;
+	_init_ua();
+    }
+    Exporter::export($pkg, $callpkg, @_);
+}
+
+
+sub _init_ua
+{
+    require LWP;
+    require LWP::UserAgent;
+    require HTTP::Status;
+    require HTTP::Date;
+    $ua = new LWP::UserAgent;  # we create a global UserAgent object
+    my $ver = $LWP::VERSION = $LWP::VERSION;  # avoid warning
+    $ua->agent("LWP::Simple/$LWP::VERSION");
+    $ua->env_proxy;
+}
+
+
+sub get ($)
+{
+    %loop_check = ();
+    goto \&_get;
+}
+
+
+sub get_old ($)
+{
+    my($url) = @_;
+    _init_ua() unless $ua;
+
+    my $request = HTTP::Request->new(GET => $url);
+    my $response = $ua->request($request);
+
+    return $response->content if $response->is_success;
+    return undef;
+}
+
+
+sub head ($)
+{
+    my($url) = @_;
+    _init_ua() unless $ua;
+
+    my $request = HTTP::Request->new(HEAD => $url);
+    my $response = $ua->request($request);
+
+    if ($response->is_success) {
+	return $response unless wantarray;
+	return ($response->header('Content-Type'),
+		$response->header('Content-Length'),
+		HTTP::Date::str2time($response->header('Last-Modified')),
+		HTTP::Date::str2time($response->header('Expires')),
+		$response->header('Server'),
+	       );
+    }
+    return;
+}
+
+
+sub getprint ($)
+{
+    my($url) = @_;
+    _init_ua() unless $ua;
+
+    my $request = HTTP::Request->new(GET => $url);
+    local($\) = ""; # ensure standard $OUTPUT_RECORD_SEPARATOR
+    my $response = $ua->request($request, sub { print $_[0] });
+    unless ($response->is_success) {
+	print STDERR $response->status_line, " <URL:$url>\n";
+    }
+    $response->code;
+}
+
+
+sub getstore ($$)
+{
+    my($url, $file) = @_;
+    _init_ua() unless $ua;
+
+    my $request = HTTP::Request->new(GET => $url);
+    my $response = $ua->request($request, $file);
+
+    $response->code;
+}
+
+
+sub mirror ($$)
+{
+    my($url, $file) = @_;
+    _init_ua() unless $ua;
+    my $response = $ua->mirror($url, $file);
+    $response->code;
+}
+
+
+sub _get
+{
+    my $url = shift;
+    my $ret;
+    if (!$FULL_LWP && $url =~ m,^http://([^/:]+)(?::(\d+))?(/\S*)?$,) {
+	my $host = $1;
+	my $port = $2 || 80;
+	my $path = $3;
+	$path = "/" unless defined($path);
+	return _trivial_http_get($host, $port, $path);
+    } else {
+        _init_ua() unless $ua;
+	my $request = HTTP::Request->new(GET => $url);
+	my $response = $ua->request($request);
+	return $response->is_success ? $response->content : undef;
+    }
+}
+
+
+sub _trivial_http_get
+{
+   my($host, $port, $path) = @_;
+   #print "HOST=$host, PORT=$port, PATH=$path\n";
+
+   require IO::Socket;
+   local($^W) = 0;
+   my $sock = IO::Socket::INET->new(PeerAddr => $host,
+                                    PeerPort => $port,
+                                    Proto    => 'tcp',
+                                    Timeout  => 60) || return;
+   $sock->autoflush;
+   my $netloc = $host;
+   $netloc .= ":$port" if $port != 80;
+   print $sock join("\015\012" =>
+                    "GET $path HTTP/1.0",
+                    "Host: $netloc",
+                    "User-Agent: lwp-trivial/$VERSION",
+                    "", "");
+
+   my $buf = "";
+   my $n;
+   1 while $n = sysread($sock, $buf, 8*1024, length($buf));
+   return undef unless defined($n);
+
+   if ($buf =~ m,^HTTP/\d+\.\d+\s+(\d+)[^\012]*\012,) {
+       my $code = $1;
+       #print "CODE=$code\n$buf\n";
+       if ($code =~ /^30[1237]/ && $buf =~ /\012Location:\s*(\S+)/) {
+           # redirect
+           my $url = $1;
+           return undef if $loop_check{$url}++;
+           return _get($url);
+       }
+       return undef unless $code =~ /^2/;
+       $buf =~ s/.+?\015?\012\015?\012//s;  # zap header
+   }
+
+   return $buf;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/UserAgent.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/UserAgent.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/UserAgent.pm	(revision 10506)
@@ -0,0 +1,732 @@
+# $Id$
+
+package LWP::UserAgent;
+use strict;
+
+=head1 NAME
+
+LWP::UserAgent - A WWW UserAgent class
+
+=head1 SYNOPSIS
+
+ require LWP::UserAgent;
+ $ua = new LWP::UserAgent;
+
+ $request = new HTTP::Request('GET', 'file://localhost/etc/motd');
+
+ $response = $ua->request($request); # or
+ $response = $ua->request($request, '/tmp/sss'); # or
+ $response = $ua->request($request, \&callback, 4096);
+
+ sub callback { my($data, $response, $protocol) = @_; .... }
+
+=head1 DESCRIPTION
+
+The C<LWP::UserAgent> is a class implementing a simple World-Wide Web
+user agent in Perl. It brings together the HTTP::Request,
+HTTP::Response and the LWP::Protocol classes that form the rest of the
+core of libwww-perl library. For simple uses this class can be used
+directly to dispatch WWW requests, alternatively it can be subclassed
+for application-specific behaviour.
+
+In normal usage the application creates a UserAgent object, and then
+configures it with values for timeouts proxies, name, etc. The next
+step is to create an instance of C<HTTP::Request> for the request that
+needs to be performed. This request is then passed to the UserAgent
+request() method, which dispatches it using the relevant protocol,
+and returns a C<HTTP::Response> object.
+
+The basic approach of the library is to use HTTP style communication
+for all protocol schemes, i.e. you will receive an C<HTTP::Response>
+object also for gopher or ftp requests.  In order to achieve even more
+similarities with HTTP style communications, gopher menus and file
+directories will be converted to HTML documents.
+
+The request() method can process the content of the response in one of
+three ways: in core, into a file, or into repeated calls of a
+subroutine.  You choose which one by the kind of value passed as the
+second argument to request().
+
+The in core variant simply returns the content in a scalar attribute
+called content() of the response object, and is suitable for small
+HTML replies that might need further parsing.  This variant is used if
+the second argument is missing (or is undef).
+
+The filename variant requires a scalar containing a filename as the
+second argument to request(), and is suitable for large WWW objects
+which need to be written directly to the file, without requiring large
+amounts of memory. In this case the response object returned from
+request() will have empty content().  If the request fails, then the
+content() might not be empty, and the file will be untouched.
+
+The subroutine variant requires a reference to callback routine as the
+second argument to request() and it can also take an optional chuck
+size as third argument.  This variant can be used to construct
+"pipe-lined" processing, where processing of received chuncks can
+begin before the complete data has arrived.  The callback function is
+called with 3 arguments: the data received this time, a reference to
+the response object and a reference to the protocol object.  The
+response object returned from request() will have empty content().  If
+the request fails, then the the callback routine will not have been
+called, and the response->content() might not be empty.
+
+The request can be aborted by calling die() within the callback
+routine.  The die message will be available as the "X-Died" special
+response header field.
+
+The library also accepts that you put a subroutine reference as
+content in the request object.  This subroutine should return the
+content (possibly in pieces) when called.  It should return an empty
+string when there is no more content.
+
+=head1 METHODS
+
+The following methods are available:
+
+=over 4
+
+=cut
+
+
+use vars qw(@ISA $VERSION);
+
+require LWP::MemberMixin;
+@ISA = qw(LWP::MemberMixin);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+
+require URI::URL;
+require HTTP::Request;
+require HTTP::Response;
+
+use HTTP::Date ();
+
+use LWP ();
+use LWP::Debug ();
+use LWP::Protocol ();
+
+use Carp ();
+
+use AutoLoader ();
+*AUTOLOAD = \&AutoLoader::AUTOLOAD;  # import the AUTOLOAD method
+
+
+=item $ua = new LWP::UserAgent;
+
+Constructor for the UserAgent.  Returns a reference to a
+LWP::UserAgent object.
+
+=cut
+
+sub new
+{
+    my($class, $init) = @_;
+    LWP::Debug::trace('()');
+
+    my $self;
+    if (ref $init) {
+	$self = $init->clone;
+    } else {
+	$self = bless {
+		'agent'       => "libwww-perl/$LWP::VERSION",
+		'from'        => undef,
+		'timeout'     => 3*60,
+		'proxy'       => undef,
+		'cookie_jar'  => undef,
+		'use_eval'    => 1,
+                'parse_head'  => 1,
+                'max_size'    => undef,
+		'no_proxy'    => [],
+	}, $class;
+    }
+}
+
+
+=item $ua->simple_request($request, [$arg [, $size]])
+
+This method dispatches a single WWW request on behalf of a user, and
+returns the response received.  The C<$request> should be a reference
+to a C<HTTP::Request> object with values defined for at least the
+method() and url() attributes.
+
+If C<$arg> is a scalar it is taken as a filename where the content of
+the response is stored.
+
+If C<$arg> is a reference to a subroutine, then this routine is called
+as chunks of the content is received.  An optional C<$size> argument
+is taken as a hint for an appropriate chunk size.
+
+If C<$arg> is omitted, then the content is stored in the response
+object itself.
+
+=cut
+
+sub simple_request
+{
+    my($self, $request, $arg, $size) = @_;
+    local($SIG{__DIE__});  # protect agains user defined die handlers
+
+    my($method, $url) = ($request->method, $request->url);
+
+    # Check that we have a METHOD and a URL first
+    return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST, "Method missing")
+	unless $method;
+    return HTTP::Response->new(&HTTP::Status::RC_BAD_REQUEST, "URL missing")
+	unless $url;
+
+    LWP::Debug::trace("$method $url");
+
+    # Locate protocol to use
+    my $scheme = '';
+    my $proxy = $self->_need_proxy($url);
+    if (defined $proxy) {
+	$scheme = $proxy->scheme;
+    } else {
+	$scheme = $url->scheme;
+    }
+    my $protocol;
+    eval {
+	$protocol = LWP::Protocol::create($scheme);
+    };
+    if ($@) {
+	$@ =~ s/\s+at\s+\S+\s+line\s+\d+\.?\s*//;  # remove file/line number
+	return HTTP::Response->new(&HTTP::Status::RC_NOT_IMPLEMENTED, $@)
+    }
+
+    # Extract fields that will be used below
+    my ($agent, $from, $timeout, $cookie_jar,
+        $use_eval, $parse_head, $max_size) =
+      @{$self}{qw(agent from timeout cookie_jar
+                  use_eval parse_head max_size)};
+
+    # Set User-Agent and From headers if they are defined
+    $request->header('User-Agent' => $agent) if $agent;
+    $request->header('From' => $from) if $from;
+    $cookie_jar->add_cookie_header($request) if $cookie_jar;
+
+    # Transfer some attributes to the protocol object
+    $protocol->parse_head($parse_head);
+    $protocol->max_size($max_size);
+    
+    my $response;
+    if ($use_eval) {
+	# we eval, and turn dies into responses below
+	eval {
+	    $response = $protocol->request($request, $proxy,
+					   $arg, $size, $timeout);
+	};
+	if ($@) {
+	    $@ =~ s/\s+at\s+\S+\s+line\s+\d+\.?\s*//;
+	    $response =
+	      HTTP::Response->new(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
+				  $@);
+	}
+    } else {
+	$response = $protocol->request($request, $proxy,
+				       $arg, $size, $timeout);
+	# XXX: Should we die unless $response->is_success ???
+    }
+
+    $response->request($request);  # record request for reference
+    $cookie_jar->extract_cookies($response) if $cookie_jar;
+    $response->header("Client-Date" => HTTP::Date::time2str(time));
+    return $response;
+}
+
+
+=item $ua->request($request, $arg [, $size])
+
+Process a request, including redirects and security.  This method may
+actually send several different simple reqeusts.
+
+The arguments are the same as for C<simple_request()>.
+
+=cut
+
+sub request
+{
+    my($self, $request, $arg, $size, $previous) = @_;
+
+    LWP::Debug::trace('()');
+
+    my $response = $self->simple_request($request, $arg, $size);
+
+    my $code = $response->code;
+    $response->previous($previous) if defined $previous;
+
+    LWP::Debug::debug('Simple result: ' . HTTP::Status::status_message($code));
+
+    if ($code == &HTTP::Status::RC_MOVED_PERMANENTLY or
+	$code == &HTTP::Status::RC_MOVED_TEMPORARILY) {
+
+	# Make a copy of the request and initialize it with the new URI
+	my $referral = $request->clone;
+
+	# And then we update the URL based on the Location:-header.
+	# Some servers erroneously return a relative URL for redirects,
+	# so make it absolute if it not already is.
+	my $referral_uri = (URI::URL->new($response->header('Location'),
+					  $response->base))->abs(undef,1);
+
+	$referral->url($referral_uri);
+
+	return $response unless $self->redirect_ok($referral);
+
+	# Check for loop in the redirects
+	my $count = 0;
+	my $r = $response;
+	while ($r) {
+	    if (++$count > 13 ||
+                $r->request->url->as_string eq $referral_uri->as_string) {
+		$response->header("Client-Warning" =>
+				  "Redirect loop detected");
+		return $response;
+	    }
+	    $r = $r->previous;
+	}
+
+	return $self->request($referral, $arg, $size, $response);
+
+    } elsif ($code == &HTTP::Status::RC_UNAUTHORIZED ||
+	     $code == &HTTP::Status::RC_PROXY_AUTHENTICATION_REQUIRED
+	    )
+    {
+	my $proxy = ($code == &HTTP::Status::RC_PROXY_AUTHENTICATION_REQUIRED);
+	my $ch_header = $proxy ?  "Proxy-Authenticate" : "WWW-Authenticate";
+	my $challenge = $response->header($ch_header);
+	unless (defined $challenge) {
+	    $response->header("Client-Warning" => 
+			      "Missing Authenticate header");
+	    return $response;
+	}
+
+	require HTTP::Headers::Util;
+	$challenge =~ tr/,/;/;  # "," is used to separate auth-params!!
+	($challenge) = HTTP::Headers::Util::split_header_words($challenge);
+	my $scheme = lc(shift(@$challenge));
+	shift(@$challenge); # no value
+	$challenge = { @$challenge };  # make rest into a hash
+	for (keys %$challenge) {       # make sure all keys are lower case
+	    $challenge->{lc $_} = delete $challenge->{$_};
+	}
+
+	unless ($scheme =~ /^([a-z]+(?:-[a-z]+)*)$/) {
+	    $response->header("Client-Warning" => 
+			      "Bad authentication scheme '$scheme'");
+	    return $response;
+	}
+	$scheme = $1;  # untainted now
+	my $class = "LWP::Authen::\u$scheme";
+	$class =~ s/-/_/g;
+	
+	no strict 'refs';
+	unless (defined %{"$class\::"}) {
+	    # try to load it
+	    eval "require $class";
+	    if ($@) {
+		if ($@ =~ /^Can\'t locate/) {
+		    $response->header("Client-Warning" =>
+				      "Unsupport authentication scheme '$scheme'");
+		} else {
+		    $response->header("Client-Warning" => $@);
+		}
+		return $response;
+	    }
+	}
+	return $class->authenticate($self, $proxy, $challenge, $response,
+				    $request, $arg, $size);
+    }
+    return $response;
+}
+
+
+=item $ua->redirect_ok
+
+This method is called by request() before it tries to do any
+redirects.  It should return a true value if the redirect is allowed
+to be performed. Subclasses might want to override this.
+
+The default implementation will return FALSE for POST request and TRUE
+for all others.
+
+=cut
+
+sub redirect_ok
+{
+    # draft-ietf-http-v10-spec-02.ps from www.ics.uci.edu, specify:
+    #
+    # If the 30[12] status code is received in response to a request using
+    # the POST method, the user agent must not automatically redirect the
+    # request unless it can be confirmed by the user, since this might change
+    # the conditions under which the request was issued.
+
+    my($self, $request) = @_;
+    return 0 if $request->method eq "POST";
+    1;
+}
+
+
+=item $ua->credentials($netloc, $realm, $uname, $pass)
+
+Set the user name and password to be used for a realm.  It is often more
+useful to specialize the get_basic_credentials() method instead.
+
+=cut
+
+sub credentials
+{
+    my($self, $netloc, $realm, $uid, $pass) = @_;
+    @{ $self->{'basic_authentication'}{$netloc}{$realm} } = ($uid, $pass);
+}
+
+
+=item $ua->get_basic_credentials($realm, $uri, [$proxy])
+
+This is called by request() to retrieve credentials for a Realm
+protected by Basic Authentication or Digest Authentication.
+
+Should return username and password in a list.  Return undef to abort
+the authentication resolution atempts.
+
+This implementation simply checks a set of pre-stored member
+variables. Subclasses can override this method to e.g. ask the user
+for a username/password.  An example of this can be found in
+C<lwp-request> program distributed with this library.
+
+=cut
+
+sub get_basic_credentials
+{
+    my($self, $realm, $uri, $proxy) = @_;
+    return if $proxy;
+
+    my $netloc = $uri->netloc;
+    if (exists $self->{'basic_authentication'}{$netloc}{$realm}) {
+	return @{ $self->{'basic_authentication'}{$netloc}{$realm} };
+    }
+
+    return (undef, undef);
+}
+
+
+=item $ua->agent([$product_id])
+
+Get/set the product token that is used to identify the user agent on
+the network.  The agent value is sent as the "User-Agent" header in
+the requests. The default agent name is "libwww-perl/#.##", where
+"#.##" is substitued with the version numer of this library.
+
+The user agent string should be one or more simple product identifiers
+with an optional version number separated by the "/" character.
+Examples are:
+
+  $ua->agent('Checkbot/0.4 ' . $ua->agent);
+  $ua->agent('Mozilla/5.0');
+
+=item $ua->from([$email_address])
+
+Get/set the Internet e-mail address for the human user who controls
+the requesting user agent.  The address should be machine-usable, as
+defined in RFC 822.  The from value is send as the "From" header in
+the requests.  There is no default.  Example:
+
+  $ua->from('aas@sn.no');
+
+=item $ua->timeout([$secs])
+
+Get/set the timeout value in seconds. The default timeout() value is
+180 seconds, i.e. 3 minutes.
+
+=item $ua->cookie_jar([$cookies])
+
+Get/set the I<HTTP::Cookies> object to use.  The default is to have no
+cookie_jar, i.e. never automatically add "Cookie" headers to the
+requests.
+
+=item $ua->parse_head([$boolean])
+
+Get/set a value indicating wether we should initialize response
+headers from the E<lt>head> section of HTML documents. The default is
+TRUE.  Do not turn this off, unless you know what you are doing.
+
+=item $ua->max_size([$bytes])
+
+Get/set the size limit for response content.  The default is undef,
+which means that there is not limit.  If the returned response content
+is only partial, because the size limit was exceeded, then a
+"X-Content-Range" header will be added to the response.
+
+=cut
+
+sub timeout    { shift->_elem('timeout',   @_); }
+sub agent      { shift->_elem('agent',     @_); }
+sub from       { shift->_elem('from',      @_); }
+sub cookie_jar { shift->_elem('cookie_jar',@_); }
+sub parse_head { shift->_elem('parse_head',@_); }
+sub max_size   { shift->_elem('max_size',  @_); }
+
+# depreciated
+sub use_eval   { shift->_elem('use_eval',  @_); }
+sub use_alarm
+{
+    Carp::carp("LWP::UserAgent->use_alarm(BOOL) is a no-op")
+	if @_ > 1 && $^W;
+    "";
+}
+
+
+# Declarations of AutoLoaded methods
+sub clone;
+sub is_protocol_supported;
+sub mirror;
+sub proxy;
+sub env_proxy;
+sub no_proxy;
+sub _need_proxy;
+
+
+1;
+__END__
+
+
+=item $ua->clone;
+
+Returns a copy of the LWP::UserAgent object
+
+=cut
+
+
+sub clone
+{
+    my $self = shift;
+    my $copy = bless { %$self }, ref $self;  # copy most fields
+
+    # elements that are references must be handled in a special way
+    $copy->{'no_proxy'} = [ @{$self->{'no_proxy'}} ];  # copy array
+
+    $copy;
+}
+
+
+=item $ua->is_protocol_supported($scheme)
+
+You can use this method to query if the library currently support the
+specified C<scheme>.  The C<scheme> might be a string (like 'http' or
+'ftp') or it might be an URI::URL object reference.
+
+=cut
+
+sub is_protocol_supported
+{
+    my($self, $scheme) = @_;
+    if (ref $scheme) {
+	# assume we got a reference to an URI::URL object
+	$scheme = $scheme->abs->scheme;
+    } else {
+	Carp::croak("Illeal scheme '$scheme' passed to is_protocol_supported")
+	    if $scheme =~ /\W/;
+	$scheme = lc $scheme;
+    }
+    return LWP::Protocol::implementor($scheme);
+}
+
+
+=item $ua->mirror($url, $file)
+
+Get and store a document identified by a URL, using If-Modified-Since,
+and checking of the Content-Length.  Returns a reference to the
+response object.
+
+=cut
+
+sub mirror
+{
+    my($self, $url, $file) = @_;
+
+    LWP::Debug::trace('()');
+    my $request = new HTTP::Request('GET', $url);
+
+    if (-e $file) {
+	my($mtime) = (stat($file))[9];
+	if($mtime) {
+	    $request->header('If-Modified-Since' =>
+			     HTTP::Date::time2str($mtime));
+	}
+    }
+    my $tmpfile = "$file-$$";
+
+    my $response = $self->request($request, $tmpfile);
+    if ($response->is_success) {
+
+	my $file_length = (stat($tmpfile))[7];
+	my($content_length) = $response->header('Content-length');
+
+	if (defined $content_length and $file_length < $content_length) {
+	    unlink($tmpfile);
+	    die "Transfer truncated: " .
+		"only $file_length out of $content_length bytes received\n";
+	} elsif (defined $content_length and $file_length > $content_length) {
+	    unlink($tmpfile);
+	    die "Content-length mismatch: " .
+		"expected $content_length bytes, got $file_length\n";
+	} else {
+	    # OK
+	    if (-e $file) {
+		# Some dosish systems fail to rename if the target exists
+		chmod 0777, $file;
+		unlink $file;
+	    }
+	    rename($tmpfile, $file) or
+		die "Cannot rename '$tmpfile' to '$file': $!\n";
+
+	    if (my $lm = $response->last_modified) {
+		# make sure the file has the same last modification time
+		utime $lm, $lm, $file;
+	    }
+	}
+    } else {
+	unlink($tmpfile);
+    }
+    return $response;
+}
+
+=item $ua->proxy(...)
+
+Set/retrieve proxy URL for a scheme:
+
+ $ua->proxy(['http', 'ftp'], 'http://proxy.sn.no:8001/');
+ $ua->proxy('gopher', 'http://proxy.sn.no:8001/');
+
+The first form specifies that the URL is to be used for proxying of
+access methods listed in the list in the first method argument,
+i.e. 'http' and 'ftp'.
+
+The second form shows a shorthand form for specifying
+proxy URL for a single access scheme.
+
+=cut
+
+sub proxy
+{
+    my($self, $key, $proxy) = @_;
+
+    LWP::Debug::trace("$key, $proxy");
+
+    if (!ref($key)) {   # single scalar passed
+	my $old = $self->{'proxy'}{$key};
+	$self->{'proxy'}{$key} = $proxy;
+	return $old;
+    } elsif (ref($key) eq 'ARRAY') {
+	for(@$key) {    # array passed
+	    $self->{'proxy'}{$_} = $proxy;
+	}
+    }
+    return undef;
+}
+
+=item $ua->env_proxy()
+
+Load proxy settings from *_proxy environment variables.  You might
+specify proxies like this (sh-syntax):
+
+  gopher_proxy=http://proxy.my.place/
+  wais_proxy=http://proxy.my.place/
+  no_proxy="my.place"
+  export gopher_proxy wais_proxy no_proxy
+
+Csh or tcsh users should use the C<setenv> command to define these
+envirionment variables.
+
+=cut
+
+sub env_proxy {
+    my ($self) = @_;
+    my($k,$v);
+    while(($k, $v) = each %ENV) {
+	$k = lc($k);
+	next unless $k =~ /^(.*)_proxy$/;
+	$k = $1;
+	if ($k eq 'no') {
+	    $self->no_proxy(split(/\s*,\s*/, $v));
+	}
+	else {
+	    $self->proxy($k, $v);
+	}
+    }
+}
+
+=item $ua->no_proxy($domain,...)
+
+Do not proxy requests to the given domains.  Calling no_proxy without
+any domains clears the list of domains. Eg:
+
+ $ua->no_proxy('localhost', 'no', ...);
+
+=cut
+
+sub no_proxy {
+    my($self, @no) = @_;
+    if (@no) {
+	push(@{ $self->{'no_proxy'} }, @no);
+    }
+    else {
+	$self->{'no_proxy'} = [];
+    }
+}
+
+
+# Private method which returns the URL of the Proxy configured for this
+# URL, or undefined if none is configured.
+sub _need_proxy
+{
+    my($self, $url) = @_;
+
+    $url = new URI::URL($url) unless ref $url;
+
+    LWP::Debug::trace("($url)");
+
+    # check the list of noproxies
+
+    if (@{ $self->{'no_proxy'} }) {
+	my $host = $url->host;
+	return undef unless defined $host;
+	my $domain;
+	for $domain (@{ $self->{'no_proxy'} }) {
+	    if ($host =~ /$domain$/) {
+		LWP::Debug::trace("no_proxy configured");
+		return undef;
+	    }
+	}
+    }
+
+    # Currently configured per scheme.
+    # Eventually want finer granularity
+
+    my $scheme = $url->scheme;
+    if (exists $self->{'proxy'}{$scheme}) {
+
+	LWP::Debug::debug('Proxied');
+	return new URI::URL($self->{'proxy'}{$scheme});
+    }
+
+    LWP::Debug::debug('Not proxied');
+    undef;
+}
+
+1;
+
+=back
+
+=head1 SEE ALSO
+
+See L<LWP> for a complete overview of libwww-perl5.  See F<lwp-request> and
+F<lwp-mirror> for examples of usage.
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/media.types
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/media.types	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/LWP/media.types	(revision 10506)
@@ -0,0 +1,120 @@
+# $Id$
+#
+# This file defines the mapping from file name extentions to media types.
+# Media types where the subtype does not have the "x-" prefix should be
+# registered by IANA:
+#
+#   ftp://www.isi.edu/in-notes/iana/assignments/media-types/
+#
+# See also: RFC-1590
+
+# Text formats
+text/html			html htm
+text/plain			txt text pm el c h cc hh cxx hxx f90
+text/richtext			rtx
+text/tab-separated-values	tsv
+
+text/x-setext			etx
+text/x-pod			pod			# Perl documentation
+
+# Image formats
+image/png			png
+image/gif			gif			# Compuserve
+image/ief			ief
+image/jpeg			jpeg jpg jpe jfif
+image/tiff			tiff tif
+
+image/x-cmu-raster		ras
+image/x-portable-anymap		pnm
+image/x-portable-bitmap		pbm
+image/x-portable-graymap	pgm
+image/x-portable-pixmap		ppm
+image/x-rgb			rgb			# SGI IRIS
+image/x-xbitmap			xbm			# X Windows
+image/x-xpixmap			xpm			# X Windows
+image/x-xwindowdump		xwd			# X Windows
+image/x-bmp			bmp			# MS Windows
+image/x-targa			tga
+image/x-fits			fts
+
+
+# Audio formats
+audio/basic			au snd
+audio/x-aiff			aif aiff aifc
+audio/x-wav			wav			# MS Windows
+audio/x-mpeg-2			mp2			# MPEG layer 2 audio
+
+# Video formats
+video/mpeg			mpeg mpg mpe
+video/quicktime			qt
+video/x-msvideo			avi
+video/x-sgi-movie		mov
+
+# Message
+message/rfc822			mail
+message/partial
+message/external-body
+message/news			art
+
+# Applications
+application/octet-stream	bin
+application/postscript		ai eps ps
+application/oda			oda
+application/atomicmail
+application/andrew-insert
+application/slate
+application/wita
+application/dec-dx
+application/dca-rtf
+application/activemessage
+application/rtf			rft			# MS Word
+application/applefile
+application/mac-binhex40	hqx
+application/news-message-id
+application/news-transmission
+application/wordperfect5.1
+application/pdf			pdf
+application/zip			zip
+application/macwriteii
+application/msword
+application/remote-printing
+application/mathematica
+application/cybercash
+application/commonground
+application/iges
+application/riscos
+application/eshop
+
+application/x-mif		mif			# FrameMaker
+application/x-maker		fm
+application/x-csh		csh
+application/x-dvi		dvi
+application/x-hdf		hdf
+application/x-latex		latex
+application/x-netcdf		nc cdf
+application/x-sh		sh
+application/x-tcl		tcl
+application/x-perl		pl
+application/x-tex		tex
+application/x-texinfo		texinfo texi
+application/x-troff		t tr roff
+application/x-troff-man		man 1 2 3 4 5 6 7 8
+application/x-troff-me		me
+application/x-troff-ms		ms
+application/x-wais-source	src
+application/x-bcpio		bcpio
+application/x-cpio		cpio
+application/x-gtar		gtar			# GNU tar
+application/x-shar		shar
+application/x-sv4cpio		sv4cpio
+application/x-sv4crc		sv4crc
+application/x-tar		tar
+application/x-ustar		ustar
+
+# Multipart
+multipart/mixed
+multipart/alternative
+multipart/digest
+multipart/parallel
+multipart/appledouble
+multipart/header-set
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Escape.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Escape.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Escape.pm	(revision 10506)
@@ -0,0 +1,119 @@
+#
+# $Id$
+#
+
+package URI::Escape;
+use strict;
+
+=head1 NAME
+
+URI::Escape - Escape and unescape unsafe characters
+
+=head1 SYNOPSIS
+
+ use URI::Escape;
+ $safe = uri_escape("10% is enough\n");
+ $verysafe = uri_escape("foo", "\0-\377");
+ $str  = uri_unescape($safe);
+
+=head1 DESCRIPTION
+
+This module provide functions to escape and unescape URI strings.
+Some characters are regarded as "unsafe" and must be escaped in
+accordance with RFC 1738.  Escaped characters are represented by a
+triplet consisting of the character "%" followed by two hexadecimal
+digits.  The following functions are provided (and exported by
+default):
+
+=over 4
+
+=item uri_escape($string, [$unsafe])
+
+This function replaces all unsafe characters in the $string with their
+escape sequence and return the result.
+
+The uri_escape() function takes an optional second argument that
+overrides the set of characters that are to be escaped.  The set is
+specified as a string that can be used in a regular expression
+character class (between [ ]).  E.g.:
+
+  \x00-\x1f\x7f-\xff          # all control and hi-bit characters
+  a-z                         # all lower case characters
+  ^A-Za-z                     # everything not a letter
+
+The default set of characters to be escaped is:
+
+  \x00-\x20"#%;<>?{}|\\^~`\[\]\x7F-\xFF
+
+=item uri_unescape($string)
+
+Returns a string with all %XX sequences replaced with the actual
+character.
+
+=back
+
+The module can also export the %escapes hash which contains the
+mapping from all characters to the corresponding escape code.
+
+=head1 SEE ALSO
+
+L<URI::URL>
+
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+
+This program is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
+use vars qw(%escapes);
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(uri_escape uri_unescape);
+@EXPORT_OK = qw(%escapes);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use Carp ();
+
+# Build a char->hex map
+for (0..255) {
+    $escapes{chr($_)} = sprintf("%%%02X", $_);
+}
+
+my %subst;  # compiled patternes
+
+sub uri_escape
+{
+    my($text, $patn) = @_;
+    return undef unless defined $text;
+    if (defined $patn){
+	unless (exists  $subst{$patn}) {
+	    # Because we can't compile regex we fake it with a cached sub
+	    $subst{$patn} =
+	      eval "sub {\$_[0] =~ s/([$patn])/\$escapes{\$1}/g; }";
+	    Carp::croak("uri_escape: $@") if $@;
+	}
+	&{$subst{$patn}}($text);
+    } else {
+	# Default unsafe characters. (RFC1738 section 2.2)
+	$text =~ s/([\x00-\x20\"#%;<>?{}|\\^~`\[\]\x7F-\xFF])/$escapes{$1}/g;
+    }
+    $text;
+}
+
+sub uri_unescape
+{
+    # Note from RFC1630:  "Sequences which start with a percent sign
+    # but are not followed by two hexadecimal characters are reserved
+    # for future extension"
+    my @copy = @_;
+    for (@copy) { s/%([\dA-Fa-f]{2})/chr(hex($1))/eg; }
+    wantarray ? @copy : $copy[0];
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Heuristic.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Heuristic.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/Heuristic.pm	(revision 10506)
@@ -0,0 +1,191 @@
+package URI::Heuristic;
+
+# $Id$
+
+=head1 NAME
+
+uf_urlstr - Expand URL using heuristics
+
+=head1 SYNOPSIS
+
+ use URI::Heuristic qw(uf_urlstr);
+ $url = uf_urlstr("perl");             # http://www.perl.com
+ $url = uf_urlstr("www.sol.no/sol");   # http://www.sol.no/sol
+ $url = uf_urlstr("aas");              # http://www.aas.no
+ $url = uf_urlstr("ftp.funet.fi");     # ftp://ftp.funet.fi
+ $url = uf_urlstr("/etc/passwd");      # file:/etc/passwd
+
+=head1 DESCRIPTION
+
+This module provide functions that expand strings into real absolute
+URLs using some builtin heuristics.  Strings that already represent
+absolute URLs (i.e. start with a C<scheme:> part) are never modified
+and are returned unchanged.  The main use of these functions are to
+allow abbreviated URLs similar to what many web browsers allow for URLs
+typed in by the user.
+
+The following functions are provided:
+
+=over 4
+
+=item uf_urlstr($str)
+
+The uf_urlstr() function will try to make the string passed as
+argument into a proper absolute URL string.  The "uf_" prefix stands
+for "User Friendly".
+
+=item uf_url($str)
+
+This functions work the same way as uf_urlstr() but it will
+return a C<URI::URL> object.
+
+=back
+
+=head1 ENVIRONMENT
+
+If the hostname portion of a URL does not contain any dots, then
+certain qualified guesses will be made.  These guesses are governed be
+the following two environment variables.
+
+=over 10
+
+=item COUNTRY
+
+This is the two letter country code (ISO 3166) for your location.  If
+the domain name of your host ends with two letters, then it is taken
+to be the default country. See also L<Locale::Country>.
+
+=item URL_GUESS_PATTERN
+
+Contain a space separated list of URL patterns to try.  The string
+"ACME" is for some reason used as a placeholder for the host name in
+the URL provided.  Example:
+
+ URL_GUESS_PATTERN="www.ACME.no www.ACME.se www.ACME.com"
+ export URL_GUESS_PATTERN
+
+Specifying URL_GUESS_PATTERN disables any guessing rules based on
+country.  An empty URL_GUESS_PATTERN disables any guessing that
+involves host name lookups.
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright 1997-1998, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
+
+use strict;
+
+use vars qw(@EXPORT_OK $VERSION $MY_COUNTRY %LOCAL_GUESSING $DEBUG);
+
+require Exporter;
+*import = \&Exporter::import;
+@EXPORT_OK = qw(uf_url uf_urlstr);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+eval {
+    require Net::Domain;
+    my $fqdn = Net::Domain::hostfqdn();
+    $MY_COUNTRY = lc($1) if $fqdn =~ /\.([a-zA-Z]{2})$/;
+
+    # Some other heuristics to guess country?  Perhaps looking
+    # at some environment variable (LANG, LC_ALL, ???)
+    $MY_COUNTRY = $ENV{COUNTRY} if exists $ENV{COUNTRY};
+};
+
+%LOCAL_GUESSING =
+(
+ 'us' => [qw(www.ACME.gov www.ACME.mil)],
+ 'uk' => [qw(www.ACME.co.uk www.ACME.org.uk www.ACME.ac.uk)],
+ 'au' => [qw(www.ACME.com.au www.ACME.org.au www.ACME.edu.au)],
+ 'il' => [qw(www.ACME.co.il www.ACME.org.il www.ACME.net.il)],
+ # send corrections and new entries to <aas@sn.no>
+);
+
+
+sub uf_url ($)
+{
+    require URI::URL;
+    URI::URL->new(uf_urlstr($_[0]));
+}
+
+
+sub uf_urlstr ($)
+{
+    local($_) = @_;
+    print STDERR "uf_urlstr: resolving $_\n" if $DEBUG;
+    return unless defined;
+
+    s/^\s+//;
+    s/\s+$//;
+
+    if (/^(www|web|home)\./) {
+	$_ = "http://$_";
+
+    } elsif (/^(ftp|gopher|news|wais|http|https)\./) {
+	$_ = "$1://$_";
+
+    } elsif (m,^/,      ||          # absolute file name
+	     m,^\.\.?/, ||          # relative file name
+	     m,^[a-zA-Z]:[/\\],)    # dosish file name
+    {
+	$_ = "file:$_";
+
+    } elsif (/^\w+([\.\-]\w+)*\@(\w+\.)+\w{2,3}$/) {
+	$_ = "mailto:$_";
+
+    } elsif (!/^[.+\-\w]+:/) {      # no scheme specified
+	if (s/^(\w+(?:\.\w+)*)([\/:\?\#]|$)/$2/) {
+	    my $host = $1;
+
+	    if ($host !~ /\./ && $host ne "localhost") {
+		my @guess;
+		if (exists $ENV{URL_GUESS_PATTERN}) {
+		    @guess = map { s/\bACME\b/$host/; $_ }
+		             split(' ', $ENV{URL_GUESS_PATTERN});
+		} else {
+		    if ($MY_COUNTRY) {
+			my $special = $LOCAL_GUESSING{$MY_COUNTRY};
+			if ($special) {
+			    my @special = @$special;
+			    push(@guess, map { s/\bACME\b/$host/; $_ }
+                                               @special);
+			} else {
+			    push(@guess, "www.$host.$MY_COUNTRY");
+			}
+		    }
+		    push(@guess, map "www.$host.$_",
+			             "com", "org", "net", "edu", "int");
+		}
+
+
+		my $guess;
+		for $guess (@guess) {
+		    print STDERR "uf_urlstr: gethostbyname('$guess')..."
+		      if $DEBUG;
+		    if (gethostbyname($guess)) {
+			print STDERR "yes\n" if $DEBUG;
+			$host = $guess;
+			last;
+		    }
+		    print STDERR "no\n" if $DEBUG;
+		}
+	    }
+	    $_ = "http://$host$_";
+
+	} else {
+	    # pure junk, just return it unchanged...
+
+	}
+    }
+    print STDERR "uf_urlstr: ==> $_\n" if $DEBUG;
+
+    $_;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL.pm	(revision 10506)
@@ -0,0 +1,949 @@
+package URI::URL;
+
+$VERSION = "4.15";   # $Date$
+sub Version { $VERSION; }
+
+require 5.004;
+
+require Exporter;
+@ISA = qw(Exporter);
+@EXPORT = qw(url);
+
+require AutoLoader;
+*AUTOLOAD = \&AutoLoader::AUTOLOAD;
+
+use Carp ();
+
+# Basic lexical elements, taken from RFC 1738:
+#
+#  safe         = "$" | "-" | "_" | "." | "+"
+#  extra        = "!" | "*" | "'" | "(" | ")" | ","
+#  national     = "{" | "}" | "|" | "\" | "^" | "~" | "[" | "]" | "`"
+#  punctuation  = "<" | ">" | "#" | "%" | <">
+#  reserved     = ";" | "/" | "?" | ":" | "@" | "&" | "="
+#  escape       = "%" hex hex
+#  unreserved   = alpha | digit | safe | extra
+#  uchar        = unreserved | escape
+#  xchar        = unreserved | reserved | escape
+
+# draft-fielding-url-syntax-05.txt adds '+' to the reserved chars and
+# takes '~' out
+
+use strict;
+use vars qw($reserved $reserved_no_slash $reserved_no_form $unsafe
+	    $Debug $Strict_URL
+	   );
+
+$reserved          = ";\\/?:\\@&=+#%"; # RFC 1738 reserved pluss '#' and '%'
+$reserved_no_slash = ";?:\\@&=+#%";    # used when escaping path
+$reserved_no_form  = ";\\/?:\\@#%";    # used when escaping params and query
+
+# This is the unsafe characters (excluding those reserved)
+$unsafe   = "\x00-\x20{}|\\\\^\\[\\]`<>\"\x7F-\xFF";
+#$unsafe .= "~";  # according to RFC1738 but not to common practice
+
+$Debug         = 0;     # set to 1 to print URLs on creation
+$Strict_URL    = 0;     # see new()
+
+use overload ( '""' => 'as_string', 'fallback' => 1 );
+
+my %Implementor = (); # mapping from scheme to implementation class
+
+
+# Easy to use constructor
+sub url ($;$)
+{
+    URI::URL->new(@_);
+}
+
+
+# URI::URL objects are implemented as blessed hashes:
+#
+# Each of the URL components (scheme, netloc, user, password, host,
+# port, path, params, query, fragment) are stored under their
+# name. The netloc, path, params and query is stored in quoted
+# (escaped) form.  The others is stored unquoted (unescaped).
+#
+# Netloc is special since it is rendundant (same as
+# "user:password@host:port") and must be kept in sync with those.
+#
+# The '_str' key stores a cached stringified version of the URL
+# (by definition in quoted form).
+# The '_base' key stores the optional base of a relative URL.
+#
+# The '_orig_url' is used while debugging is on.
+#
+# Subclasses may add their own keys but must take great care to
+# avoid names which might be used in later verions of this module.
+
+sub new
+{
+    my($class, $init, $base) = @_;
+
+    my $self;
+    if (ref $init) {
+	$self = $init->clone;
+	$self->base($base) if $base;
+    } else {
+	$init = "" unless defined $init;
+	# RFC 1738 appendix suggest that we just ignore extra whitespace
+	$init =~ s/\s+//g;
+	# Also get rid of any <URL: > wrapper
+	$init =~ s/^<(?:URL:)?(.*)>$/$1/;
+
+	# We need a scheme to determine which class to use
+	my($scheme) = $init =~ m/^([.+\-\w]+):/;
+	if (!$scheme and $base){ # get scheme from base
+	    if (ref $base){ # may be object or just a string
+		$scheme = $base->scheme;
+	    } else {
+		$scheme = $1 if $base =~ m/^([.+\-\w]+):/;
+	    }
+	}
+	unless($scheme){
+	    Carp::croak("Unable to determine scheme for '$init'")
+		if $Strict_URL;
+	    $scheme = 'http';
+	}
+	my $impclass = URI::URL::implementor($scheme);
+	unless ($impclass) {
+	    Carp::croak("URI::URL scheme '$scheme' is not supported")
+		if $Strict_URL;
+	    # use generic as fallback
+	    require URI::URL::_generic;
+	    URI::URL::implementor($scheme, 'URI::URL::_generic');
+	    $impclass = 'URI::URL::_generic';
+	}
+
+	# hand-off to scheme specific implementation sub-class
+	$self->{'_orig_url'} = $init if $Debug;
+	$self = $impclass->new($init, $base);
+    }
+    $self->print_on('STDERR') if $Debug;
+    return $self;
+}
+
+
+sub clone
+{
+    my $self = shift;
+    # this work as long as none of the components are references themselves
+    bless { %$self }, ref $self;
+}
+
+
+sub implementor
+{
+    my($scheme, $impclass) = @_;
+    unless (defined $scheme) {
+	require URI::URL::_generic;
+	return 'URI::URL::_generic';
+    }
+
+    $scheme = lc($scheme);
+    if ($impclass) {
+	$impclass->_init_implementor($scheme);
+	my $old = $Implementor{$scheme};
+	$Implementor{$scheme} = $impclass;
+	return $old;
+    }
+
+    my $ic = $Implementor{$scheme};
+    return $ic if $ic;
+
+    # scheme not yet known, look for internal or
+    # preloaded (with 'use') implementation
+    $ic = "URI::URL::$scheme";  # default location
+    no strict 'refs';
+    # check we actually have one for the scheme:
+    unless (defined @{"${ic}::ISA"}) {
+	# Try to load it
+	eval { require "URI/URL/$scheme.pm"; };
+	die $@ if $@ && $@ !~ /Can\'t locate/;
+	$ic = '' unless defined @{"${ic}::ISA"};
+    }
+    if ($ic) {
+	$ic->_init_implementor($scheme);
+	$Implementor{$scheme} = $ic;
+    }
+    $ic;
+}
+
+
+sub _init_implementor
+{
+    my($class, $scheme) = @_;
+    # Remember that one implementor class may actually
+    # serve to implement several URL schemes.
+
+    if ($] < 5.003_17) {
+	no strict qw(refs);
+	# Setup overloading inheritace - experimental
+	%{"${class}::OVERLOAD"} = %URI::URL::OVERLOAD
+	    unless defined %{"${class}::OVERLOAD"};
+    }
+}
+
+
+# This private method help us implement access to the elements in the
+# URI::URL object hash (%$self).  You can set up access to an element
+# with a routine similar to this one:
+#
+#  sub component { shift->_elem('component', @_); }
+
+sub _elem
+{
+    my $self = shift;
+    my $elem = shift;
+    my $old = $self->{$elem};
+    if (@_) {
+	$self->{$elem} = shift;
+	$self->{'_str'} = '';        # void cached string
+    }
+    $old;
+}
+
+
+# Make all standard methods available to all kinds of URLs.  This allow
+# us to call these without to much worry when URI::URL::strict(0);
+
+sub bad_method;
+
+*netloc       = \&bad_method;
+*user         = \&bad_method;
+*password     = \&bad_method;
+*host         = \&bad_method;
+*port         = \&bad_method;
+*default_port = \&bad_method;
+
+*full_path    = \&bad_method;
+*epath        = \&bad_method;
+*eparams      = \&bad_method;
+*equery       = \&bad_method;
+
+*path         = \&bad_method;
+*path_components = \&bad_method;
+*params       = \&bad_method;
+*query        = \&bad_method;
+*frag         = \&bad_method;
+
+
+#
+# A U T O  L O A D I N G
+#
+# The rest of the methods are autoloaded because they should be less
+# frequently used.  We define stubs here so that inheritance works as
+# it should.
+sub newlocal;
+sub strict;
+sub base;
+sub scheme;
+sub crack;
+sub abs;
+sub rel;
+sub as_string;
+sub eq;
+sub print_on;
+
+# Don't need DESTROY but avoid trying to AUTOLOAD it.
+sub DESTROY { }
+
+1;
+__END__
+
+sub newlocal
+{
+    require URI::URL::file;
+    my $class = shift;
+    URI::URL::file->newlocal(@_);  # pass it on the the file class
+}
+
+sub strict
+{
+    return $Strict_URL unless @_;
+    my $old = $Strict_URL;
+    $Strict_URL = $_[0];
+    $old;
+}
+
+# Access some attributes of a URL object:
+sub base {
+    my $self = shift;
+    my $base  = $self->{'_base'};
+
+    if (@_) { # set
+	my $new_base = shift;
+	$new_base = $new_base->abs if ref($new_base);  # unsure absoluteness
+	$self->{_base} = $new_base;
+    }
+    return unless defined wantarray;
+
+    # The base attribute supports 'lazy' conversion from URL strings
+    # to URL objects. Strings may be stored but when a string is
+    # fetched it will automatically be converted to a URL object.
+    # The main benefit is to make it much cheaper to say:
+    #   new URI::URL $random_url_string, 'http:'
+    if (defined($base) && !ref($base)) {
+	$base = new URI::URL $base;
+	$self->_elem('_base', $base); # set new object
+    }
+    $base;
+}
+
+sub scheme {
+    my $self = shift;
+    my $old = $self->{'scheme'};
+    if (@_) {
+	my $new_scheme = shift;
+	if (defined($new_scheme) && length($new_scheme)) {
+	    # reparse URL with new scheme
+	    my $str = $self->as_string;
+	    $str =~ s/^[\w+\-.]+://;
+	    my $newself = new URI::URL "$new_scheme:$str";
+	    %$self = %$newself;
+	    bless $self, ref($newself);
+	} else {
+	    $self->{'scheme'} = undef;
+	}
+    }
+    $old;
+}
+
+sub crack
+{
+    # should be overridden by subclasses
+    my $self = shift;
+    ($self->scheme,  # 0: scheme
+     undef,          # 1: user
+     undef,          # 2: passwd
+     undef,          # 3: host
+     undef,          # 4: port
+     undef,          # 5: path
+     undef,          # 6: params
+     undef,          # 7: query
+     undef           # 8: fragment
+    )
+}
+
+# These are overridden by _generic (this is just a noop for those schemes that
+# do not wish to be a subclass of URI::URL::_generic)
+sub abs { shift->clone; }
+sub rel { shift->clone; }
+
+# This method should always be overridden in subclasses
+sub as_string {
+    "<URL>";
+}
+
+# Compare two URLs, subclasses will provide a more correct implementation
+sub eq {
+    my($self, $other) = @_;
+    $other = URI::URL->new($other, $self) unless ref $other;
+    ref($self) eq ref($other) &&
+      $self->scheme eq $other->scheme &&
+      $self->as_string eq $other->as_string;  # Case-sensitive
+}
+
+# This is set up as an alias for various methods
+sub bad_method {
+    my $self = shift;
+    my $scheme = $self->scheme;
+    Carp::croak("Illegal method called for $scheme: URL")
+	if $Strict_URL;
+    # Carp::carp("Illegal method called for $scheme: URL")
+    #     if $^W;
+    undef;
+}
+
+sub print_on
+{
+    no strict qw(refs);  # because we use strings as filehandles
+    my $self = shift;
+    my $fh = shift || 'STDERR';
+    my($k, $v);
+    print $fh "Dump of URI::URL $self...\n";
+    foreach $k (sort keys %$self){
+	$v = $self->{$k};
+	$v = 'UNDEF' unless defined $v;
+	print $fh "  $k\t'$v'\n";
+    }
+}
+
+1;
+
+
+#########################################################################
+#### D O C U M E N T A T I O N
+#########################################################################
+
+=head1 NAME
+
+URI::URL - Uniform Resource Locators (absolute and relative)
+
+=head1 SYNOPSIS
+
+ use URI::URL;
+
+ # Constructors
+ $url1 = new URI::URL 'http://www.perl.com/%7Euser/gisle.gif';
+ $url2 = new URI::URL 'gisle.gif', 'http://www.com/%7Euser';
+ $url3 = url 'http://www.sn.no/'; # handy constructor
+ $url4 = $url2->abs;       # get absolute url using base
+ $url5 = $url2->abs('http:/other/path');
+ $url6 = newlocal URI::URL 'test';
+
+ # Stringify URL
+ $str1 = $url->as_string;  # complete escaped URL string
+ $str2 = $url->full_path;  # escaped path+params+query
+ $str3 = "$url";           # use operator overloading
+
+ # Retrieving Generic-RL components:
+ $scheme   = $url->scheme;
+ $netloc   = $url->netloc; # see user,password,host,port below
+ $path     = $url->path;
+ $params   = $url->params;
+ $query    = $url->query;
+ $frag     = $url->frag;
+
+ # Accessing elements in their escaped form
+ $path     = $url->epath;
+ $params   = $url->eparams;
+ $query    = $url->equery;
+
+ # Retrieving Network location (netloc) components:
+ $user     = $url->user;
+ $password = $url->password;
+ $host     = $url->host;
+ $port     = $url->port;   # returns default if not defined
+
+ # Retrieve escaped path components as an array
+ @path     = $url->path_components;
+
+ # HTTP query-string access methods
+ @keywords = $url->keywords;
+ @form     = $url->query_form;
+
+ # All methods above can set the field values, e.g:
+ $url->scheme('http');
+ $url->host('www.w3.org');
+ $url->port($url->default_port);
+ $url->base($url5);                      # use string or object
+ $url->keywords(qw(dog bones));
+
+ # File methods
+ $url = new URI::URL "file:/foo/bar";
+ open(F, $url->local_path) or die;
+
+ # Compare URLs
+ if ($url->eq("http://www.sn.no")) or die;
+
+=head1 DESCRIPTION
+
+This module implements the URI::URL class representing Uniform
+Resource Locators (URL). URLs provide a compact string representation
+for resources available via the Internet. Both absolute (RFC 1738) and
+relative (RFC 1808) URLs are supported.
+
+URI::URL objects are created by calling new(), which takes as argument
+a string representation of the URL or an existing URL object reference
+to be cloned. Specific individual elements can then be accessed via
+the scheme(), user(), password(), host(), port(), path(), params(),
+query() and frag() methods.  In addition escaped versions of the path,
+params and query can be accessed with the epath(), eparams() and
+equery() methods.  Note that some URL schemes will support all these
+methods.
+
+The object constructor new() must be able to determine the scheme for
+the URL.  If a scheme is not specified in the URL itself, it will use
+the scheme specified by the base URL. If no base URL scheme is defined
+then new() will croak if URI::URL::strict(1) has been invoked,
+otherwise I<http> is silently assumed.  Once the scheme has been
+determined new() then uses the implementor() function to determine
+which class implements that scheme.  If no implementor class is
+defined for the scheme then new() will croak if URI::URL::strict(1)
+has been invoked, otherwise the internal generic URL class is assumed.
+
+Internally defined schemes are implemented by the
+URI::URL::I<scheme_name> module.  The URI::URL::implementor() function
+can be used to explicitly set the class used to implement a scheme if
+you want to override this.
+
+
+=head1 HOW AND WHEN TO ESCAPE
+
+
+=over 3
+
+=item This is an edited extract from a URI specification:
+
+The printability requirement has been met by specifying a safe set of
+characters, and a general escaping scheme for encoding "unsafe"
+characters. This "safe" set is suitable, for example, for use in
+electronic mail.  This is the canonical form of a URI.
+
+There is a conflict between the need to be able to represent many
+characters including spaces within a URI directly, and the need to be
+able to use a URI in environments which have limited character sets
+or in which certain characters are prone to corruption. This conflict
+has been resolved by use of an hexadecimal escaping method which may
+be applied to any characters forbidden in a given context. When URLs
+are moved between contexts, the set of characters escaped may be
+enlarged or reduced unambiguously.  The canonical form for URIs has
+all white spaces encoded.
+
+=item Notes:
+
+A URL string I<must>, by definition, consist of escaped
+components. Complete URLs are always escaped.
+
+The components of a URL string must be I<individually> escaped.  Each
+component of a URL may have a separate requirements regarding what
+must be escaped, and those requirements are also dependent on the URL
+scheme.
+
+Never escape an already escaped component string.
+
+=back
+
+This implementation expects an escaped URL string to be passed to
+new() and will return a fully escaped URL string from as_string()
+and full_path().
+
+Individual components can be manipulated in unescaped or escaped
+form. The following methods return/accept unescaped strings:
+
+    scheme                  path
+    user                    params
+    password                query
+    host                    frag
+    port
+
+The following methods return/accept partial I<escaped> strings:
+
+    netloc                  eparams
+    epath                   equery
+
+I<Partial escaped> means that only reserved characters
+(i.e. ':', '@', '/', ';', '?', '=', '&' in addition to '%', '.' and '#')
+needs to be escaped when they are to be treated as normal characters.
+I<Fully escaped> means that all unsafe characters are escaped. Unsafe
+characters are all all control characters (%00-%1F and %7F), all 8-bit
+characters (%80-%FF) as well
+as '{', '}', '|', '\', '^', '[', ']' '`', '"', '<' and '>'.
+Note that the character '~' is B<not> considered
+unsafe by this library as it is common practice to use it to reference
+personal home pages, but it is still unsafe according to RFC 1738.
+
+=head1 ADDING NEW URL SCHEMES
+
+New URL schemes or alternative implementations for existing schemes
+can be added to your own code. To create a new scheme class use code
+like:
+
+   package MYURL::foo;
+   @ISA = (URI::URL::implementor());   # inherit from generic scheme
+
+The 'URI::URL::implementor()' function call with no parameters returns
+the name of the class which implements the generic URL scheme
+behaviour (typically C<URI::URL::_generic>). All hierarchical schemes
+should be derived from this class.
+
+Your class can then define overriding methods (e.g., new(), _parse()
+as required).
+
+To register your new class as the implementor for a specific scheme
+use code like:
+
+   URI::URL::implementor('x-foo', 'MYURL::foo');
+
+Any new URL created for scheme 'x-foo' will be implemented by your
+C<MYURL::foo> class. Existing URLs will not be affected.
+
+
+=head1 FUNCTIONS
+
+=over 3
+
+=item $url = URI::URL->new( $url_string [, $base_url] )
+
+This is the object constructor.  It will create a new URI::URL object,
+initialized from the URL string.
+
+=item $url = URI::URL->newlocal($path);
+
+Returns an URL object that denotes a path within the local filesystem.
+Paths not starting with '/' are interpreted relative to the current
+working directory.  This constructor always return an absolute 'file'
+URL.
+
+=item $url = url($url_string, [, $base_url])
+
+Alternative constructor function.  The url() function is exported by
+the URI::URL module and is easier both to type and read than calling
+C<URI::URL->new> directly.  Useful for constructs like this:
+
+   $h = url($str)->host;
+
+This function is just a wrapper for URI::URL->new.
+
+=item URI::URL::strict($bool)
+
+If strict is true then we croak on errors.  The function returns the
+previous value.
+
+=item URI::URL::implementor([$scheme, [$class]])
+
+Use this function to get or set implementor class for a scheme.
+Returns '' if specified scheme is not supported.  Returns generic URL
+class if no scheme specified.
+
+=back
+
+=head1 METHODS
+
+This section describes the methods available for an URI::URL object.
+Note that some URL schemes will disallow some of these methods and
+will croak if they are used.  Some URL schemes add additional methods
+that are described in the sections to follow.
+
+Attribute access methods marked with (*) can take an optional argument
+to set the value of the attribute, and they always return the old
+value.
+
+=over 3
+
+=item $url->abs([$base])
+
+The abs() method attempts to return a new absolute URI::URL object
+for a given URL.  In order to convert a relative URL into an absolute
+one, a I<base> URL is required. You can associate a default base with a
+URL either by passing a I<base> to the new() constructor when a
+URI::URL is created or using the base() method on the object later.
+Alternatively you can specify a one-off base as a parameter to the
+abs() method.
+
+The rel() method will do the opposite transformation.
+
+Some older parsers used to allow the scheme name to be present in the
+relative URL if it was the same as the base URL scheme.  RFC1808 says
+that this should be avoided, but you can enable this old behaviour by
+setting the $URI::URL::ABS_ALLOW_RELATIVE_SCHEME variable to a TRUE
+value.  The difference is demonstrated by the following examples:
+
+  url("http:foo")->abs("http://host/a/b")     ==>  "http:foo"
+
+  local $URI::URL::ABS_ALLOW_RELATIVE_SCHEME = 1;
+  url("http:foo")->abs("http://host/a/b")     ==>  "http:/host/a/foo"
+
+You can also have the abs() method ignore if there is too many ".."
+segments in the relative URL by setting
+$URI::URL::ABS_REMOTE_LEADING_DOTS to a TRUE value.  The difference is
+demonstrated by the following examples:
+
+  url("../../../foo")->abs("http://host/a/b")   ==> "http://host/../../foo"
+
+  local $URI::URL::ABS_REMOTE_LEADING_DOTS = 1;
+  url("../../../foo")->abs("http://host/a/b")   ==> "http://host/foo"
+
+
+=item $url->as_string
+
+Returns a string representing the URL in its canonical form.  All
+unsafe characters will be escaped.  This method is overloaded as the
+perl "stringify" operator, which means that URLs can be used as
+strings in many contexts.
+
+=item $url->base (*)
+
+Get/set the base URL associated with the current URI::URL object.  The
+base URL matters when you call the abs() method.
+
+=item $url->clone
+
+Returns a copy of the current URI::URL object.
+
+=item $url->crack
+
+Return a 9 element array with the following content:
+
+   0: $url->scheme *)
+   1: $url->user
+   2: $url->password
+   3: $url->host
+   4: $url->port
+   5: $url->epath
+   6: $url->eparams
+   7: $url->equery
+   8: $url->frag
+
+All elements except I<scheme> will be undefined if the corresponding
+URL part is not available.
+
+B<Note:> The scheme (first element) returned by crack will aways be
+defined.  This is different from what the $url->scheme returns, since
+it will return I<undef> for relative URLs.
+
+=item $url->default_port
+
+Returns the default port number for the URL scheme that the URI::URL
+belongs too.
+
+=item $url->eparams (*)
+
+Get/set the URL parameters in escaped form.
+
+=item $url->epath (*)
+
+Get/set the URL path in escaped form.
+
+=item $url->eq($other_url)
+
+Compare two URLs to decide if they match or not.  The rules for how
+comparison is made varies for different parts of the URLs; scheme and
+netloc comparison is case-insensitive, and escaped chars match their
+%XX encoding unless they are "reserved" or "unsafe".
+
+=item $url->equery (*)
+
+Get/set the URL query string in escaped form.
+
+=item $url->full_path
+
+Returns the string "/path;params?query".  This is the string that is
+passed to a remote server in order to access the document.
+
+=item $url->frag (*)
+
+Get/set the fragment (unescaped)
+
+=item $url->host (*)
+
+Get/set the host (unescaped)
+
+=item $url->netloc (*)
+
+Get/set the network location in escaped form.  Setting the network
+location will affect 'user', 'password', 'host' and 'port'.
+
+=item $url->params (*)
+
+Get/set the URL parameters (unescaped)
+
+=item $url->password (*)
+
+Get/set the password (unescaped)
+
+=item $url->path (*)
+
+Get/set the path (unescaped).  This method will croak if any of the
+path components in the return value contain the "/" character.  You
+should use the epath() method to be safe.
+
+=item $url->path_components (*)
+
+Get/set the path using a list of unescaped path components.  The
+return value will loose the distinction beween '.' and '%2E'.  When
+setting a value, a '.' is converted to be a literal '.' and is
+therefore encoded as '%2E'.
+
+=item $url->port (*)
+
+Get/set the network port (unescaped)
+
+=item $url->rel([$base])
+
+Return a relative URL if possible.  This is the opposite of what the
+abs() method does.  For instance:
+
+   url("http://www.math.uio.no/doc/mail/top.html",
+       "http://www.math.uio.no/doc/linux/")->rel
+
+will return a relative URL with path set to "../mail/top.html" and
+with the same base as the original URL.
+
+If the original URL already is relative or the scheme or netloc does
+not match the base, then a copy of the original URL is returned.
+
+
+=item $url->print_on(*FILEHANDLE);
+
+Prints a verbose presentation of the contents of the URL object to
+the specified file handle (default STDERR).  Mainly useful for
+debugging.
+
+=item $url->scheme (*)
+
+Get/set the scheme for the URL.
+
+=item $url->query (*)
+
+Get/set the query string (unescaped).  This method will croak if the
+string returned contains both '+' and '%2B' or '=' together with '%3D'
+or '%26'.  You should use the equery() method to be safe.
+
+=item $url->user (*)
+
+Get/set the URL user name (unescaped)
+
+=back
+
+=head1 HTTP METHODS
+
+For I<http> URLs you may also access the query string using the
+keywords() and the query_form() methods.  Both will croak if the query
+is not of the correct format.  The encodings look like this:
+
+  word1+word2+word3..        # keywords
+  key1=val1&key2=val2...     # query_form
+
+Note: These functions does not return the old value when they are used
+to set a value of the query string.
+
+=over 3
+
+=item $url->keywords (*)
+
+The keywords() method returns a list of unescaped strings.  The method
+can also be used to set the query string by passing in the keywords as
+individual arguments to the method.
+
+=item $url->query_form (*)
+
+The query_form() method return a list of unescaped key/value pairs.
+If you assign the return value to a hash you might loose some values
+if the key is repeated (which it is allowed to do).
+
+This method can also be used to set the query sting of the URL like this:
+
+  $url->query_form(foo => 'bar', foo => 'baz', equal => '=');
+
+If the value part of a key/value pair is a reference to an array, then
+it will be converted to separate key/value pairs for each value.  This
+means that these two calls are equal:
+
+  $url->query_form(foo => 'bar', foo => 'baz');
+  $url->query_form(foo => ['bar', 'baz']);
+
+=back
+
+=head1 FILE METHODS
+
+The I<file> URLs implement the local_path() method that returns a path
+suitable for access to files within the current filesystem.  These
+methods can B<not> be used to set the path of the URL.
+
+=over 3
+
+=item $url->local_path
+
+This method is really just an alias for one of the methods below
+depending on what system you run on.
+
+=item $url->unix_path
+
+Returns a path suitable for use on a Unix system.  This method will
+croak if any of the path segments contains a "/" or a NULL character.
+
+=item $url->dos_path
+
+Returns a path suitable for use on a MS-DOS or MS-Windows system.
+
+=item $url->mac_path
+
+Returns a path suitable for use on a Macintosh system.
+
+=item $url->vms_path
+
+Returns a path suitable for use on a VMS system.  VMS is a trademark
+of Digital.
+
+=back
+
+=head1 GOPHER METHODS
+
+The methods access the parts that are specific for the gopher URLs.
+These methods access different parts of the $url->path.
+
+=over 3
+
+=item $url->gtype (*)
+
+=item $url->selector (*)
+
+=item $url->search (*)
+
+=item $url->string (*)
+
+=back
+
+=head1 NEWS METHODS
+
+=over 3
+
+=item $url->group (*)
+
+=item $url->article (*)
+
+=back
+
+=head1 WAIS METHODS
+
+The methods access the parts that are specific for the wais URLs.
+These methods access different parts of the $url->path.
+
+=over 3
+
+=item $url->database (*)
+
+=item $url->wtype (*)
+
+=item $url->wpath (*)
+
+=back
+
+=head1 MAILTO METHODS
+
+=over 3
+
+=item $url->address (*)
+
+The mail address can also be accessed with the netloc() method.
+
+=back
+
+
+=head1 WHAT A URL IS NOT
+
+URL objects do not, and should not, know how to 'get' or 'put' the
+resources they specify locations for, anymore than a postal address
+'knows' anything about the postal system. The actual access/transfer
+should be achieved by some form of transport agent class (see
+L<LWP::UserAgent>). The agent class can use the URL class, but should
+not be a subclass of it.
+
+=head1 AUTHORS / ACKNOWLEDGMENTS
+
+This module is (distantly) based on the C<wwwurl.pl> code in the
+libwww-perl distribution developed by Roy Fielding
+<fielding@ics.uci.edu>, as part of the Arcadia project at the
+University of California, Irvine, with contributions from Brooks
+Cutter.
+
+Gisle Aas <aas@sn.no>, Tim Bunce <Tim.Bunce@ig.co.uk>, Roy Fielding
+<fielding@ics.uci.edu> and Martijn Koster <m.koster@webcrawler.com>
+(in English alphabetical order) have collaborated on the complete
+rewrite for Perl 5, with input from other people on the libwww-perl
+mailing list.
+
+If you have any suggestions, bug reports, fixes, or enhancements, send
+them to the libwww-perl mailing list at <libwww-perl@ics.uci.edu>.
+
+=head1 COPYRIGHT
+
+Copyright 1995-1997 Gisle Aas.
+Copyright 1995 Martijn Koster.
+
+This program is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_generic.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_generic.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_generic.pm	(revision 10506)
@@ -0,0 +1,514 @@
+#####################################################################
+#
+#       Internal pre-defined generic scheme support
+#
+# In this implementation all schemes are subclassed from
+# URI::URL::_generic. This turns out to have reasonable mileage.
+# See also draft-ietf-uri-relative-url-06.txt
+
+package URI::URL::_generic;           # base support for generic-RL's
+require URI::URL;
+@ISA = qw(URI::URL);
+
+use URI::Escape qw(uri_escape uri_unescape %escapes);
+
+
+sub new {                               # inherited by subclasses
+    my($class, $init, $base) = @_;
+    my $url = bless { }, $class;        # create empty object
+    $url->_parse($init);                # parse $init into components
+    $url->base($base) if $base;
+    $url;
+}
+
+
+# Generic-RL parser
+# See draft-ietf-uri-relative-url-06.txt Section 2
+
+sub _parse {
+    my($self, $u, @comps) = @_;
+    return unless defined $u;
+
+    # Deside which components to parse (scheme & path is manatory)
+    @comps = qw(netloc query params frag) unless (@comps);
+    my %parse = map {$_ => 1} @comps;
+
+    # This parsing code is based on
+    #   draft-ietf-uri-relative-url-06.txt Section 2.4
+
+    # 2.4.1
+    $self->{'frag'} = uri_unescape($1)
+      if $parse{'frag'} && $u =~ s/#(.*)$//;
+    # 2.4.2
+    $self->{'scheme'} = lc($1) if $u =~ s/^\s*([\w\+\.\-]+)://;
+    # 2.4.3
+    $self->netloc("$1")	# passing $1 directly fails if netloc is autoloaded
+      if $parse{'netloc'} && $u =~ s!^//([^/]*)!!;
+    # 2.4.4
+    $self->{'query'} = $1
+      if $parse{'query'} && $u =~ s/\?(.*)//;
+    # 2.4.5
+    $self->{'params'} = $1
+      if $parse{'params'} && $u =~ s/;(.*)//;
+
+    # 2.4.6
+    #
+    # RFC 1738 says:
+    #
+    #     Note that the "/" between the host (or port) and the
+    #     url-path is NOT part of the url-path.
+    #
+    # however, RFC 1808, 2.4.6. says:
+    #
+    #    Even though the initial slash is not part of the URL path,
+    #    the parser must remember whether or not it was present so
+    #    that later processes can differentiate between relative
+    #    and absolute paths.  Often this is done by simply storing
+    #    he preceding slash along with the path.
+    #
+    # In version < 4.01 of URI::URL we used to strip the leading
+    # "/" when asked for $self->path().  This created problems for
+    # the consitency of the interface, so now we just consider the
+    # slash to be part of the path and we also make an empty path
+    # default to "/".
+
+    # we don't test for $parse{path} becase it is mandatory
+    $self->{'path'} = $u;
+}
+
+
+# Generic-RL stringify
+#
+sub as_string
+{
+    my $self = shift;
+    return $self->{'_str'} if $self->{'_str'};
+
+    my($scheme, $netloc, $frag) = @{$self}{qw(scheme netloc frag)};
+
+    my $u = $self->full_path(1);  # path+params+query
+
+    # rfc 1808 says:
+    #    Note that the fragment identifier (and the "#" that precedes
+    #    it) is not considered part of the URL.  However, since it is
+    #    commonly used within the same string context as a URL, a parser
+    #    must be able to recognize the fragment when it is present and
+    #    set it aside as part of the parsing process.
+    $u .= "#" . uri_escape($frag, $URI::URL::unsafe) if defined $frag;
+
+    $u = "//$netloc$u" if defined $netloc;
+    $u = "$scheme:$u" if $scheme;
+    # Inline: uri_escape($u, $URI::URL::unsafe);
+    $u =~ s/([$URI::URL::unsafe])/$escapes{$1}/go;
+    $self->{'_str'} = $u;  # set cache and return
+}
+
+# Generic-RL stringify full path "path;params?query"
+#
+sub full_path
+{
+    my($self, $dont_escape)  = @_;
+    my($path, $params, $query) = @{$self}{'path', 'params', 'query'};
+    my $p = '';
+    $p .= $path if defined $path;
+    # see comment in _parse 2.4.6 about the next line
+    $p = "/$p" if defined($self->{netloc}) && $p !~ m:^/:;
+    $p .= ";$params" if defined $params;
+    $p .= "?$query"  if defined $query;
+    return $p if $dont_escape;
+    # Inline: URI::Escape::uri_escape($p, $URI::URL::unsafe);
+    $p =~ s/([$URI::URL::unsafe])/$escapes{$1}/go;
+    $p;
+}
+
+# default_port()
+#
+# subclasses will usually want to override this
+#
+sub default_port { undef; }
+
+
+#####################################################################
+#
+# Methods to handle URL's elements
+
+# These methods always return the current value,
+# so you can use $url->path to read the current value.
+# If a new value is passed, e.g. $url->path('foo'),
+# it also sets the new value, and returns the previous value.
+# Use $url->path(undef) to set the value to undefined.
+
+sub netloc {
+    my $self = shift;
+    my $old = $self->_elem('netloc', @_);
+    return $old unless @_;
+
+    # update fields derived from netloc
+    my $nl = $self->{'netloc'} || '';
+    if ($nl =~ s/^([^:@]*):?(.*?)@//){
+	$self->{'user'}     = uri_unescape($1);
+	$self->{'password'} = uri_unescape($2) if $2 ne '';
+    }
+    if ($nl =~ /^([^:]*):?(\d*)$/){
+	my $port = $2;
+	# Since this happes so frequently, we inline this call:
+	#    my $host = uri_unescape($1);
+	my $host = $1;
+	$host =~ s/%([\dA-Fa-f]{2})/chr(hex($1))/eg;
+	$self->{'host'} = $host;
+	if ($port ne '') {
+	    $self->{'port'} = $port;
+	    if ($self->default_port == $port) {
+		$self->{'netloc'} =~ s/:\d+//;
+	    }
+	} elsif (defined $self->{'netloc'}) {
+	    $self->{'netloc'} =~ s/:$//;  # handle empty port spec
+	}
+    }
+    $self->{'_str'} = '';
+    $old;
+}
+
+
+# A U T O  L O A D E R
+# Don't remove this comment, it keeps AutoSplit happy!!
+# @ISA = qw(AutoLoader)
+#
+# The rest of the methods are only loaded on demand.  Stubs are neccesary
+# for inheritance to work.
+
+#sub netloc;  # because netloc is used by the _parse()
+sub user;
+sub password;
+sub host;
+sub port;
+sub _netloc_elem;
+sub epath;
+sub path;
+sub path_components;
+sub eparams;
+sub params;
+sub equery;
+sub query;
+sub frag;
+sub crack;
+sub abs;
+sub rel;
+sub eq;
+
+1;
+__END__
+
+
+# Fields derived from generic netloc:
+sub user     { shift->_netloc_elem('user',    @_); }
+sub password { shift->_netloc_elem('password',@_); }
+sub host     { shift->_netloc_elem('host',    @_); }
+
+sub port {
+    my $self = shift;
+    my $old = $self->_netloc_elem('port', @_);
+    defined($old) ? $old : $self->default_port;
+}
+
+sub _netloc_elem {
+    my($self, $elem, @val) = @_;
+    my $old = $self->_elem($elem, @val);
+    return $old unless @val;
+
+    # update the 'netloc' element
+    my $nl = '';
+    my $host = $self->{'host'};
+    if (defined $host) {  # can't be any netloc without any host
+	my $user = $self->{'user'};
+	$nl .= uri_escape($user, $URI::URL::reserved) if defined $user;
+	$nl .= ":" . uri_escape($self->{'password'}, $URI::URL::reserved)
+	  if defined($user) and defined($self->{'password'});
+	$nl .= '@' if length $nl;
+	$nl .= uri_escape($host, $URI::URL::reserved);
+	my $port = $self->{'port'};
+	$nl .= ":$port" if defined($port) && $port != $self->default_port;
+    }
+    $self->{'netloc'} = $nl;
+    $self->{'_str'} = '';
+    $old;
+}
+
+sub epath {
+     my $self = shift;
+     my $old = $self->_elem('path', @_);
+     return '/' if !defined($old) || !length($old);
+     return "/$old" if $old !~ m|^/| && defined $self->{'netloc'};
+     $old;
+}
+
+sub path {
+    my $self = shift;
+    my $old = $self->_elem('path',
+		      map uri_escape($_, $URI::URL::reserved_no_slash), @_);
+    return unless defined wantarray;
+    return '/' if !defined($old) || !length($old);
+    Carp::croak("Path components contain '/' (you must call epath)")
+	if $old =~ /%2[fF]/ and !@_;
+    $old = "/$old" if $old !~ m|^/| && defined $self->{'netloc'};
+    return uri_unescape($old);
+}
+
+sub path_components {
+    my $self = shift;
+    my $old = $self->{'path'};
+    $old = '' unless defined $old;
+    $old = "/$old" if $old !~ m|^/| && defined $self->{'netloc'};
+    if (@_) {
+	$self->_elem('path',
+		     join("/", map {uri_escape($_, $URI::URL::reserved)} @_));
+    }
+    map { uri_unescape($_) } split("/", $old, -1);
+}
+
+sub eparams  { shift->_elem('params',  @_); }
+
+sub params {
+    my $self = shift;
+    my $old = $self->_elem('params', map {uri_escape($_,$URI::URL::reserved_no_form)} @_);
+    return uri_unescape($old) if defined $old;
+    undef;
+}
+
+sub equery   { shift->_elem('query',   @_); }
+
+sub query {
+    my $self = shift;
+    my $old = $self->_elem('query', map { uri_escape($_, $URI::URL::reserved_no_form) } @_);
+    if (defined(wantarray) && defined($old)) {
+	if ($old =~ /%(?:26|2[bB]|3[dD])/) {  # contains escaped '=' '&' or '+'
+	    my $mess;
+	    for ($old) {
+		$mess = "Query contains both '+' and '%2B'"
+		  if /\+/ && /%2[bB]/;
+		$mess = "Form query contains escaped '=' or '&'"
+		  if /=/  && /%(?:3[dD]|26)/;
+	    }
+	    if ($mess) {
+		Carp::croak("$mess (you must call equery)");
+	    }
+	}
+	# Now it should be safe to unescape the string without loosing
+	# information
+	return uri_unescape($old);
+    }
+    undef;
+
+}
+
+# No efrag method because the fragment is always stored unescaped
+sub frag     { shift->_elem('frag', @_); }
+
+sub crack
+{
+    my $self = shift;
+    return $self unless wantarray;
+    my @c = @{$self}{qw(scheme user password host port path params query frag)};
+    if (!$c[0]) {
+	# try to determine scheme
+	my $base = $self->base;
+	$c[0] = $base->scheme if $base;
+	$c[0] ||= 'http';  # last resort, default in URI::URL::new
+    }
+    $c[4] ||= $self->default_port;
+    @c;
+}
+
+# Generic-RL: Resolving Relative URL into an Absolute URL
+#
+# Based on RFC1808 section 4
+#
+sub abs
+{
+    my($self, $base, $allow_relative_scheme) = @_;
+    $allow_relative_scheme = $URI::URL::ABS_ALLOW_RELATIVE_SCHEME if @_ < 3;
+    my $embed = $self->clone;
+
+    $base = $self->base unless $base;      # default to default base
+    return $embed unless $base;            # we have no base (step1)
+
+    $base = new URI::URL $base unless ref $base; # make obj if needed
+
+    my($scheme, $host, $path, $params, $query, $frag) =
+	@{$embed}{qw(scheme host path params query frag)};
+
+    # just use base if we are empty             (2a)
+    return $base->clone
+      unless grep(defined($_) && $_ ne '',
+		  $scheme,$host,$port,$path,$params,$query,$frag);
+
+    # if we have a scheme we must already be absolute   (2b),
+    #
+    # but sec. 5.2 also says: Some older parsers allow the scheme name
+    # to be present in a relative URL if it is the same as the base
+    # URL scheme.  This is considered to be a loophole in prior
+    # specifications of the partial URLs and should be avoided by
+    # future parsers.
+    #
+    # The old behavoir can be enabled by passing a TRUE value to the
+    # $allow_relative_scheme parameter.
+    return $embed if $scheme &&
+      (!$allow_relative_scheme || $scheme ne $base->{'scheme'});
+
+    $embed->{'_str'} = '';                      # void cached string
+    $embed->{'scheme'} = $base->{'scheme'};     # (2c)
+
+    return $embed if $embed->{'netloc'};        # (3)
+    $embed->netloc($base->{'netloc'});          # (3)
+
+    return $embed if $path =~ m:^/:;            # (4)
+
+    if ($path eq '') {                          # (5)
+	$embed->{'path'} = $base->{'path'};     # (5)
+
+	return $embed if defined $embed->{'params'}; # (5a)
+	$embed->{'params'} = $base->{'params'};      # (5a)
+
+	return $embed if defined $embed->{'query'};  # (5b)
+	$embed->{'query'} = $base->{'query'};        # (5b)
+
+	return $embed;
+    }
+
+    # (Step 6)  # draft 6 suggests stack based approach
+
+    my $basepath = $base->{'path'};
+    my $relpath  = $embed->{'path'};
+
+    $basepath =~ s!^/!!;
+    $basepath =~ s!/$!/.!;                # prevent empty segment
+    my @path = split('/', $basepath);     # base path into segments
+    pop(@path);                           # remove last segment
+
+    $relpath =~ s!/$!/.!;                 # prevent empty segment
+
+    push(@path, split('/', $relpath));    # append relative segments
+
+    my @newpath = ();
+    my $isdir = 0;
+    my $segment;
+
+    foreach $segment (@path) {            # left to right
+	if ($segment eq '.') {            # ignore "same" directory
+	    $isdir = 1;
+	}
+	elsif ($segment eq '..') {
+	    $isdir = 1;
+	    my $last = pop(@newpath);
+	    if (!defined $last) {         # nothing to pop
+		push(@newpath, $segment); # so must append
+	    }
+	    elsif ($last eq '..') {       # '..' cannot match '..'
+		# so put back again, and append
+		push(@newpath, $last, $segment);
+	    }
+	    #else
+		# it was a component,
+		# keep popped
+	} else {
+	    $isdir = 0;
+	    push(@newpath, $segment);
+	}
+    }
+
+    if ($URI::URL::ABS_REMOTE_LEADING_DOTS) {
+	shift @newpath while @newpath && $newpath[0] =~ /^\.\.?$/;
+    }
+
+    $embed->{'path'} = '/' . join('/', @newpath) .
+	($isdir && @newpath ? '/' : '');
+
+    $embed;
+}
+
+# The oposite of $url->abs.  Return a URL as much relative as possible
+sub rel {
+    my($self, $base) = @_;
+    my $rel = $self->clone;
+    $base = $self->base unless $base;
+    return $rel unless $base;
+    $base = new URI::URL $base unless ref $base;
+    $rel->base($base);
+
+    my($scheme, $netloc, $path) = @{$rel}{qw(scheme netloc path)};
+    if (!defined($scheme) && !defined($netloc)) {
+	# it is already relative
+	return $rel;
+    }
+
+    my($bscheme, $bnetloc, $bpath) = @{$base}{qw(scheme netloc path)};
+    for ($bscheme, $bnetloc, $netloc) { $_ = '' unless defined }
+
+    unless ($scheme eq $bscheme && $netloc eq $bnetloc) {
+	# different location, can't make it relative
+	return $rel;
+    }
+
+    for ($path, $bpath) {  $_ = "/$_" unless m,^/,; }
+
+    # Make it relative by eliminating scheme and netloc
+    $rel->{'scheme'} = undef;
+    $rel->netloc(undef);
+
+    # This loop is based on code from Nicolai Langfeldt <janl@ifi.uio.no>.
+    # First we calculate common initial path components length ($li).
+    my $li = 1;
+    while (1) {
+	my $i = index($path, '/', $li);
+	last if $i < 0 ||
+                $i != index($bpath, '/', $li) ||
+	        substr($path,$li,$i-$li) ne substr($bpath,$li,$i-$li);
+	$li=$i+1;
+    }
+    # then we nuke it from both paths
+    substr($path, 0,$li) = '';
+    substr($bpath,0,$li) = '';
+
+    if ($path eq $bpath && defined($rel->frag) && !defined($rel->equery)) {
+        $rel->epath('');
+    } else {
+        # Add one "../" for each path component left in the base path
+        $path = ('../' x $bpath =~ tr|/|/|) . $path;
+	$path = "./" if $path eq "";
+        $rel->epath($path);
+    }
+
+    $rel;
+}
+
+
+# Compare two URLs
+sub eq {
+    my($self, $other) = @_;
+    local($^W) = 0; # avoid warnings if we compare undef values
+    $other = URI::URL->new($other, $self) unless ref $other;
+
+    # Compare scheme and netloc
+    return 0 if ref($self) ne ref($other);                # must be same class
+    return 0 if $self->scheme ne $other->scheme;          # Always lower case
+    return 0 if lc($self->netloc) ne lc($other->netloc);  # Case-insensitive
+
+    # Compare full_path:
+    # According to <draft-ietf-http-v11-spec-05>:
+    # Characters other than those in the "reserved" and "unsafe" sets
+    # are equivalent to their %XX encodings.
+    my $fp1 = $self->full_path;
+    my $fp2 = $other->full_path;
+    for ($fp1, $fp2) {
+	s,%([\dA-Fa-f]{2}),
+	  my $x = $1;
+	  my $c = chr(hex($x));
+	  $c =~ /^[;\/?:\@&=+\"\#%<>\0-\040\177]/ ? "%\L$x" : $c;
+	,eg;
+    }
+    return 0 if $fp1 ne $fp2;
+    return 0 if $self->frag ne $other->frag;
+    1;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_login.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_login.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/_login.pm	(revision 10506)
@@ -0,0 +1,25 @@
+package URI::URL::_login;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+
+# Generic terminal logins.  This is used as a base class for 'telnet',
+# 'tn3270', and 'rlogin' URL schemes.
+
+
+sub _parse {
+    my($self, $init) = @_;
+    # All we want from _generic is the 'netloc' handling.
+    $self->URI::URL::_generic::_parse($init, 'netloc');
+}
+
+
+*path      = \&URI::URL::bad_method;
+*epath     = \&URI::URL::bad_method;
+*query     = \&URI::URL::bad_method;
+*equery    = \&URI::URL::bad_method;
+*params    = \&URI::URL::bad_method;
+*eparams   = \&URI::URL::bad_method;
+*frag      = \&URI::URL::bad_method;
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/data.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/data.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/data.pm	(revision 10506)
@@ -0,0 +1,160 @@
+package URI::URL::data;
+
+# Implements data:-URLs as specified in draft-masinter-url-data-02.txt
+#
+# Abstract
+#
+# A new URL scheme, "data", is defined. It allows inclusion of small
+# data items as "immediate" data, as if it had been included externally.
+#
+# Description
+#
+# Some applications that use URLs also have a need to embed (small)
+# media type data directly inline. This document defines a new URL
+# scheme that would work like 'immediate addressing'. The URLs are of
+# the form:
+#
+#        data:[<mediatype>][;base64],<data>
+#
+
+require URI::URL;
+@ISA = qw(URI::URL);
+
+use URI::Escape;
+use MIME::Base64 ();
+
+# as defined in rfc1522.txt
+my $tspecial  = qq(()<>@,;:/[]?.=);
+my $tokenchar = qq([^\\s\000-\037\177-\377\Q$tspecial\E]);
+
+
+sub new {
+    my($class, $init, $base) = @_;
+
+    my $self = bless { }, $class;
+
+    $self->{'scheme'} = lc($1) if $init =~ s/^\s*([\w\+\.\-]+)://;
+    $self->{'frag'} = $1 if $init =~ s/\#(.*)$//;
+
+    my $type = "";
+    if ($init =~ s/^($tokenchar+\/$tokenchar+)//o) {
+	$type = $1;
+    }
+    while ($init =~ s/^;($tokenchar+)=([^,;]*)//o) {
+	# XXX should we unescape the parst
+	$type .= ";$1=$2";
+    }
+
+    $self->{'media_type'} = $type;
+
+    my $base64;
+    if ($init =~ s/^;base64//i) {
+	$base64 = 1;
+    }
+    
+    $init =~ s/^,//;
+    if ($base64) {
+	$self->{'base64'} = uri_unescape($init);
+    } else {
+	$self->{'data'} = uri_unescape($init);
+    }
+    $self->base($base) if $base;
+    $self;
+}
+
+sub media_type
+{
+    my $self = shift;
+    my $old = $self->{'media_type'};
+    if (@_) {
+	$self->{'media_type'} = shift || "";
+	delete $self->{'_str'};
+    }
+    my($type, $param) = split(/;/, $old, 2);
+    if ($type) {
+	$type = lc $type;
+    } else {
+	$type = "text/plain";
+	$param = "charset=US-ASCII" unless $param;
+    }
+    if (wantarray) {
+	return ($type, $param);
+    } else {
+	return $type;
+    }
+}
+
+sub data
+{
+    my $self = shift;
+    my $old_data;
+    my $old_base64;
+    $old_data = $self->{'data'};
+    $old_base64 = $self->{'base64'};
+    if (@_) {
+	if ($_[1]) { # base64 flag
+	    $self->{'base64'} = $_[0];
+	    delete $self->{'data'};
+	} else {
+	    $self->{'data'} = $_[0];
+	    delete $self->{'base64'};
+	}
+	delete $self->{'_str'};
+    }
+    unless (defined $old_data) {
+	$old_data = MIME::Base64::decode($old_base64);
+	$self->{'data'} = $old_data unless @_;
+    }
+    $old_data;
+}
+
+
+sub crack
+{
+    my $self = shift;
+    ($self->{'scheme'}
+     || 'data',          # scheme
+     undef,              # user
+     undef,              # passwd
+     undef,              # host
+     undef,              # port
+     $self->data,        # path
+     $self->{'media_type'},  # params
+     undef,              # query
+     $self->{'frag'}     # fragment
+    )
+}
+
+sub as_string {
+    my $self = shift;
+    return $self->{'_str'} if $self->{'_str'};
+    my $str = ($self->{'scheme'} || 'data') . ":";
+    $str .= $self->{'media_type'};
+    if (defined $self->{'base64'}) {
+	$str .= ";base64,$self->{'base64'}";
+    } else {
+	my $urlenc = uri_escape($self->{'data'});
+	my $base64 = MIME::Base64::encode($self->{'data'});
+	if (length($base64) + 7 < length($urlenc)) {
+	    $str .= ";base64,$base64";
+	    $self->{'base64'} = $base64;
+	} else {
+	    $str .= ",$urlenc";
+	}
+    }
+    $self->{'_str'} = $str;
+}
+
+sub eq {
+    my($self, $other) = @_;
+    return 0 if ref($self) ne ref($other);
+    return 0 if $self->scheme ne $other->scheme;
+
+    my $mt1 = join(";", $self->media_type);
+    my $mt2 = join(";", $other->media_type);
+    return 0 if $mt1 ne $mt2;
+
+    $self->data eq $other->data;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/file.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/file.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/file.pm	(revision 10506)
@@ -0,0 +1,165 @@
+package URI::URL::file;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+require Carp;
+require Config;
+
+# First we try to determine what kind of system we run on
+my $os = $Config::Config{'osname'};
+OS: {
+    $ostype = 'vms', last if $os eq 'VMS';
+    $ostype = 'dos', last if $os =~ /^(?:os2|mswin32|msdos)$/i;
+    $ostype = 'mac', last if $os eq "Mac";
+    $ostype = 'unix';  # The default
+}
+# NOTE: If you add more types to this list, remember to add a xxx_path
+# method as well.
+
+# This is the BNF found in RFC 1738:
+#
+# fileurl        = "file://" [ host | "localhost" ] "/" fpath
+# fpath          = fsegment *[ "/" fsegment ]
+# fsegment       = *[ uchar | "?" | ":" | "@" | "&" | "=" ]
+# Note that fsegment can contain '?' (query) but not ';' (param)
+
+sub _parse {
+    my($self, $init) = @_;
+    # The file URL can't have query
+    $self->URI::URL::_generic::_parse($init, qw(netloc path params frag));
+}
+
+# sub local_path { ... }
+#
+# Returns a path suitable for use on the local system (we just
+# set up an alias (derived from $ostype) to one of the path methods
+# defined below)
+*local_path = \&{$ostype . "_path"};
+
+*query  = \&URI::URL::bad_method;
+*equery = \&URI::URL::bad_method;
+
+# A U T O  L O A D E R
+# Don't remove this comment, it keeps AutoSplit happy!!
+# @ISA = qw(AutoLoader)
+#
+# These methods are autoloaded as needed
+sub newlocal;
+sub unix_path;
+sub dos_path ;
+sub mac_path ;
+sub vms_path ;
+1;
+__END__
+
+sub newlocal {
+    my($class, $path) = @_;
+
+    Carp::croak("Only implemented for Unix and OS/2 file systems")
+      unless $ostype eq "unix" or $^O =~ /os2|mswin32/i;
+    # XXX: Should implement the same thing for other systems
+
+    my $url = new URI::URL "file:";
+    unless (defined $path and
+    	    ($path =~ m:^/: or 
+	     ($^O eq 'os2' and Cwd::sys_is_absolute($path)) or
+	     ($^O eq 'MSWin32' and $path =~ m<^[A-Za-z]:[\\/]|^[\\/]{2}>))) {
+	require Cwd;
+	my $cwd = Cwd::fastcwd();
+	$cwd =~ s:/?$:/:; # force trailing slash on dir
+	$path = (defined $path) ? $cwd . $path : $cwd;
+    }
+    $url->path($path);
+    $url;
+}
+
+sub unix_path
+{
+    my $self = shift;
+    my @p;
+    for ($self->path_components) {
+	Carp::croak("Path component contains '/' or '\0'") if m|[\0/]|;
+	if (@p) {
+	    next unless length $_;   # skip empty path segments
+	    next if $_ eq '.';       # skip these too
+	    if ($_ eq '..' && $p[-1] ne '..') {  # go up one level
+		pop(@p) if $p[-1] ne '';
+		next;
+	    }
+	}
+	push(@p, $_);
+    }
+    shift(@p) if @p > 1 && $p[0] eq '.';   # './' rendundant if there is more
+    return '/' if !@p || (@p == 1 && $p[0] eq '');
+    join('/', @p);
+}
+
+sub dos_path
+{
+    my $self = shift;
+    my @p;
+    for ($self->path_components) {
+	Carp::croak("Path component contains '/' or '\\'") if m|[/\\]|;
+	push(@p, uc $_);
+    }
+    my $p = join("\\", @p);
+    $p =~ s/^\\([A-Z]:)/$1/;  # Fix drive letter specification
+    $p;
+}
+
+sub mac_path
+{
+    my $self = shift;
+    my @p;
+    for ($self->path_components) {
+	Carp::croak("Path component contains ':'") if /:/;
+	# XXX: Should probably want to do something about ".." and "."
+	# path segments.  I don't know how these are represented in
+	# the Machintosh file system.  If these are valid file names
+	# then we should split the path ourself, as $u->path_components
+	# loose the distinction between '.' and '%2E'.
+	push(@p, $_);
+    }
+    if (@p && $p[0] eq '') {
+	shift @p;
+    } else {
+	unshift(@p, '');
+    }
+    join(':', @p);
+}
+
+sub vms_path
+{
+    # ????? Can some VMS people please redo this function ??????
+
+    # This is implemented based on what RFC1738 (sec 3.10) says in the
+    # VMS file example:
+    #
+    #  DISK$USER:[MY.NOTES]NOTE123456.TXT
+    #
+    #      that might become
+    #
+    #  file:/disk$user/my/notes/note12345.txt
+    #
+    # BEWARE: I don't have a VMS machine myself so this is pure guesswork!!!
+
+    my $self = shift;
+    my @p = $self->path_components;
+    my $abs = 0;
+    if (@p && $p[0] eq '') {
+	shift @p;
+	$abs = 1;
+    }
+    # First I assume there must be a dollar in a disk spesification
+    my $p = '';
+    $p = uc(shift(@p)) . ":"  if @p && $p[0] =~ /\$/;
+    my $file = pop(@p);
+    $p .= "[" . join(".", map{uc($_)} @p) . "]" if @p;
+    $p .= uc $file;
+    # XXX: How is an absolute path different from a relative one??
+    $p =~ s/\[/[./ unless $abs;
+    # XXX: How is a directory denoted??
+    $p;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/finger.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/finger.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/finger.pm	(revision 10506)
@@ -0,0 +1,6 @@
+package URI::URL::finger;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+sub default_port { 79 }
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/ftp.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/ftp.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/ftp.pm	(revision 10506)
@@ -0,0 +1,76 @@
+package URI::URL::ftp;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+sub default_port { 21 }
+
+sub _parse {
+    my($self, $init) = @_;
+    # The ftp URLs can't have any query string
+    $self->URI::URL::_generic::_parse($init, qw(netloc path params frag));
+    1;
+}
+
+
+sub user
+{
+    my($self, @val) = @_;
+    my $old = $self->SUPER::user(@val);
+    defined $old ? $old : "anonymous";
+}
+
+BEGIN {
+    $whoami = undef;
+    $fqdn   = undef;
+}
+
+sub password
+{
+    my($self, @val) = @_;
+    my $old = $self->SUPER::password(@val);
+    unless (defined $old) {
+	my $user = $self->user;
+	if ($user eq 'anonymous' || $user eq 'ftp') {
+	    # anonymous ftp login password
+	    unless (defined $fqdn) {
+		eval {
+		    require Net::Domain;
+		    $fqdn = Net::Domain::hostfqdn();
+		};
+		if ($@) {
+		    $fqdn = '';
+		}
+	    }
+	    unless (defined $whoami) {
+		$whoami = $ENV{USER} || $ENV{LOGNAME} || $ENV{USERNAME};
+		unless ($whoami) {
+		    if ($^O eq 'MSWin32') { $whoami = Win32::LoginName() }
+		    else {
+		        $whoami = getlogin || getpwuid($<) || 'unknown';
+		    }
+		}
+	    }
+	    $old = "$whoami\@$fqdn";
+	} else {
+	    $old = "";
+	}
+    }
+    $old;
+}
+
+sub crack
+{
+    my $self = shift;
+    my @c = $self->SUPER::crack;
+    if ($c[3] && !$c[1]) {
+	# hostname defined, but user is undefined
+	$c[1] = $self->user;
+	$c[2] = $self->password;
+    }
+    @c;
+}
+
+*query  = \&URI::URL::bad_method;
+*equery = \&URI::URL::bad_method;
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/gopher.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/gopher.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/gopher.pm	(revision 10506)
@@ -0,0 +1,82 @@
+package URI::URL::gopher;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+use URI::Escape qw(uri_unescape);
+
+sub default_port { 70 }
+
+sub _parse {
+    my($self, $init)   = @_;
+    $self->URI::URL::_generic::_parse($init, qw(netloc path));
+    $self->_parse_gopherpath;
+}
+
+sub path {
+    my $self = shift;
+    my $old = $self->URI::URL::_generic::path(@_);
+    return $old unless @_;
+    $self->_parse_gopherpath;
+    $old;
+}
+
+sub epath {
+    my $self = shift;
+    my $old = $self->URI::URL::_generic::epath(@_);
+    return $old unless @_;
+    $self->_parse_gopherpath;
+    $old;
+}
+
+sub _parse_gopherpath {
+    my $self = shift;
+    my $p = $self->{'path'};
+    # not according to RFC1738, but many popular browsers accept
+    # gopher URLs with a '?' before the search string.
+    $p =~ s/\?/\t/;
+    $p = uri_unescape($p);
+
+    if (defined($p) && $p ne '/' && $p =~ s!^/?(.)!!) {
+	$self->{'gtype'} = $1;
+    } else {
+	$self->{'gtype'} = "1";
+	$p = "";
+    }
+
+    delete $self->{'selector'};
+    delete $self->{'search'};
+    delete $self->{'string'};
+
+    my @parts = split(/\t/, $p, 3);
+    $self->{'selector'} = shift @parts if @parts;
+    $self->{'search'}   = shift @parts if @parts;
+    $self->{'string'}   = shift @parts if @parts;
+}
+
+
+sub gtype    { shift->_path_elem('gtype',    @_); }
+sub selector { shift->_path_elem('selector', @_); }
+sub search   { shift->_path_elem('search',   @_); }
+sub string   { shift->_path_elem('string',   @_); }
+
+sub _path_elem {
+    my($self, $elem, @val) = @_;
+    my $old = $self->_elem($elem, @val);
+    return $old unless @val;
+
+    # construct new path based on elements
+    my $path = "/$self->{'gtype'}";
+    $path .= "$self->{'selector'}" if defined $self->{'selector'};
+    $path .= "\t$self->{'search'}" if defined $self->{'search'};
+    $path .= "\t$self->{'string'}" if defined $self->{'string'};
+    $self->{'path'} = $path;
+
+    $old;
+}
+
+*params  = \&URI::URL::bad_method;
+*qparams = \&URI::URL::bad_method;
+*query   = \&URI::URL::bad_method;
+*equery  = \&URI::URL::bad_method;
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/http.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/http.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/http.pm	(revision 10506)
@@ -0,0 +1,57 @@
+package URI::URL::http;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+sub default_port { 80 }
+
+require Carp;
+
+# @ISA = qw(AutoLoader)      # This comment is needed by AutoSplit.
+sub keywords;
+sub query_form;
+1;
+__END__
+
+# Handle ...?dog+bones type of query
+sub keywords {
+    my $self = shift;
+    $old = $self->{'query'};
+    if (@_) {
+	# Try to set query string
+	$self->equery(join('+', map { URI::Escape::uri_escape($_, $URI::URL::reserved) } @_));
+    }
+    return if !defined($old) || !defined(wantarray);
+
+    Carp::croak("Query is not keywords") if $old =~ /=/;
+    map { URI::Escape::uri_unescape($_) } split(/\+/, $old);
+}
+
+# Handle ...?foo=bar&bar=foo type of query
+sub query_form {
+    my $self = shift;
+    $old = $self->{'query'};
+    if (@_) {
+	# Try to set query string
+	my @query;
+	my($key,$vals);
+        my $esc = $URI::URL::reserved . $URI::URL::unsafe;
+	while (($key,$vals) = splice(@_, 0, 2)) {
+	    $key = '' unless defined $key;
+	    $key =  URI::Escape::uri_escape($key, $esc);
+	    $vals = [$vals] unless ref($vals) eq 'ARRAY';
+	    my $val;
+	    for $val (@$vals) {
+		$val = '' unless defined $val;
+		$val = URI::Escape::uri_escape($val, $esc);
+		push(@query, "$key=$val");
+	    }
+	}
+	$self->equery(join('&', @query));
+    }
+    return if !defined($old) || length($old) == 0 || !defined(wantarray);
+    Carp::croak("Query is not a form") unless $old =~ /=/;
+    map { s/\+/ /g; URI::Escape::uri_unescape($_) }
+	 map { /=/ ? split(/=/, $_, 2) : ($_ => '')} split(/&/, $old);
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/https.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/https.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/https.pm	(revision 10506)
@@ -0,0 +1,6 @@
+package URI::URL::https;
+require URI::URL::http;
+@ISA = qw(URI::URL::http);
+
+sub default_port { 443 }
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/mailto.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/mailto.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/mailto.pm	(revision 10506)
@@ -0,0 +1,78 @@
+package URI::URL::mailto;
+require URI::URL;
+@ISA = qw(URI::URL);
+
+use URI::Escape;
+
+sub new {
+    my($class, $init, $base) = @_;
+
+    my $self = bless { }, $class;
+    $self->{'scheme'} = lc($1) if $init =~ s/^\s*([\w\+\.\-]+)://;
+    $self->{'address'} = uri_unescape($init);
+    $self->base($base) if $base;
+    $self;
+}
+
+sub address { shift->_elem('address', @_); }
+
+# can use these as aliases
+*encoded822addr = \&address;   # URI::URL v3 compatibility
+*netloc         = \&address;
+
+sub user {
+    my $self = shift;
+    $old = $self->{'address'};
+    if (@_) {
+	my $new = $old;
+	$new =~ s/.*\@?/$_[0]\@/;
+	$self->{'address'} = $new;
+    }
+    $old =~ s/\@.*//;
+    $old;
+}
+
+sub host {
+    my $self = shift;
+    $old = $self->{'address'};
+    if (@_) {
+	my $new = $old;
+	$new =~ s/\@.*/\@$_[0]/;
+	$self->{'address'} = $new;
+    }
+    $old =~ s/.*\@//;
+    $old;
+}
+
+sub crack
+{
+    my $self = shift;
+    ('mailto',           # scheme
+     $self->user,        # user
+     undef,              # passwd
+     $self->host,        # host
+     undef,              # port
+     $self->{'address'}, # path
+     undef,              # params
+     undef,              # query
+     undef               # fragment
+    )
+}
+
+sub as_string {
+    my $self = shift;
+    my $str = ($self->{'scheme'} || "mailto") . ":";
+    $str .= uri_escape($self->{'address'}) if defined $self->{'address'};
+    $str;
+}
+
+sub eq {
+    my($self, $other) = @_;
+    $other = URI::URL->new($other) unless ref $other;
+
+    # Mail adresses are case-insensitive
+    $self->scheme eq $other->scheme &&
+      lc($self->{'address'}) eq lc($other->{'address'});
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/news.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/news.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/news.pm	(revision 10506)
@@ -0,0 +1,73 @@
+package URI::URL::news;
+require URI::URL;
+@ISA = qw(URI::URL);
+
+use URI::Escape;
+
+sub new {
+    my($class, $init, $base) = @_;
+    my $self = bless { }, $class;
+    $self->{'scheme'}  = lc($1) if $init =~ s/^\s*([\w\+\.\-]+)://;
+    $self->groupart(uri_unescape($init));
+    $self->base($base) if $base;
+    $self;
+}
+
+sub groupart {
+    my $self = shift;
+    my $old = $self->{'path'};
+    if (@_) {
+	my $p = shift;
+	if (defined $p && $p =~ /\@/) {
+	    # it is an message id
+	    $p =~ s/^<(.*)>$/$1/;  # "<" and ">" should not be part of it
+	}
+	$self->{'path'} = $p;
+    }
+    $old;
+}
+
+*path = \&groupart;
+
+sub article   {
+    my $self = shift;
+    Carp::croak("Illegal article id name (does not contain '\@')")
+      if @_ && $_[0] !~ /\@/;
+    my $old = $self->groupart(@_);
+    return undef if $old !~ /\@/;
+    $old;
+}
+
+
+sub group {
+    my $self = shift;
+    Carp::croak("Illegal group name (contains '\@')")
+      if @_ && $_[0] =~ /\@/;
+    my $old = $self->groupart(@_);
+    return undef if $old =~ /\@/;
+    $old;
+}
+
+sub crack
+{
+    my $self = shift;
+    ('news',             # scheme
+     undef,              # user
+     undef,              # passwd
+     undef,              # host
+     undef,              # port
+     $self->{'path'},    # path
+     undef,              # params
+     undef,              # query
+     undef               # fragment
+    )
+}
+
+
+sub as_string {
+    my $self = shift;
+    my $scheme = $self->{'scheme'} || "news";
+    "$scheme:" . uri_escape($self->{'path'});
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/nntp.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/nntp.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/nntp.pm	(revision 10506)
@@ -0,0 +1,44 @@
+package URI::URL::nntp;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+use URI::Escape;
+
+sub default_port { 119 }
+
+sub _parse {
+    my($self, $init) = @_;
+    $self->URI::URL::_generic::_parse($init, qw(netloc path frag));
+
+    my @parts = $self->path_components;
+    shift @parts if @parts && $parts[0] eq '';
+
+    $self->{'group'} = uri_unescape($parts[0]);
+    $self->{'digits'}= uri_unescape($parts[1]);
+}
+
+sub group   { shift->_elem('group',  @_); }
+sub digits  { shift->_elem('digits', @_); }
+sub article { shift->_elem('digits', @_); }
+
+sub as_string {
+    my $self = shift;
+    my $str = "$self->{'scheme'}:";
+    $str .= "//$self->{'netloc'}" if defined $self->{'netloc'};
+    $str .= "/" . uri_escape($self->{'group'}) . "/" .
+		  uri_escape($self->{'digits'});
+    $str;
+}
+
+# Standard methods are not legal for nntp URLs
+*path      = \&URI::URL::bad_method;
+*epath     = \&URI::URL::bad_method;
+*query     = \&URI::URL::bad_method;
+*equery    = \&URI::URL::bad_method;
+*params    = \&URI::URL::bad_method;
+*eparams   = \&URI::URL::bad_method;
+*frag      = \&URI::URL::bad_method;
+*user      = \&URI::URL::bad_method;
+*password  = \&URI::URL::bad_method;
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/prospero.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/prospero.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/prospero.pm	(revision 10506)
@@ -0,0 +1,27 @@
+package URI::URL::prospero;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+# RFC 1738 says:
+#
+#   A prospero URLs takes the form:
+#
+#      prospero://<host>:<port>/<hsoname>;<field>=<value>
+#
+#   where <host> and <port> are as described in Section 3.1. If :<port>
+#   is omitted, the port defaults to 1525. No username or password is
+#   allowed.
+#
+#   The <hsoname> is the host-specific object name in the Prospero
+#   protocol, suitably encoded.  This name is opaque and interpreted by
+#   the Prospero server.  The semicolon ";" is reserved and may not
+#   appear without quoting in the <hsoname>.
+
+sub default_port { 1525 }       # says rfc1738, section 3.11
+
+sub _parse {
+    my($self, $init) = @_;
+    $self->URI::URL::_generic::_parse($init, qw(netloc path params frag));
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/rlogin.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/rlogin.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/rlogin.pm	(revision 10506)
@@ -0,0 +1,7 @@
+package URI::URL::rlogin;
+require URI::URL::_login;
+@ISA = qw(URI::URL::_login);
+
+sub default_port { 513 }
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/telnet.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/telnet.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/telnet.pm	(revision 10506)
@@ -0,0 +1,7 @@
+package URI::URL::telnet;
+require URI::URL::_login;
+@ISA = qw(URI::URL::_login);
+
+sub default_port { 23 }
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/tn3270.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/tn3270.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/tn3270.pm	(revision 10506)
@@ -0,0 +1,7 @@
+package URI::URL::tn3270;
+require URI::URL::_login;
+@ISA = qw(URI::URL::_login);
+
+# sub default_port { 0 }
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/wais.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/wais.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/wais.pm	(revision 10506)
@@ -0,0 +1,50 @@
+package URI::URL::wais;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+use URI::Escape;
+
+# RFC 1738 says:
+#
+#   A WAIS URL takes one of the following forms:
+#
+#     wais://<host>:<port>/<database>
+#     wais://<host>:<port>/<database>?<search>
+#     wais://<host>:<port>/<database>/<wtype>/<wpath>
+#
+#   where <host> and <port> are as described in Section 3.1. If :<port>
+#   is omitted, the port defaults to 210.  The first form designates a
+#   WAIS database that is available for searching. The second form
+#   designates a particular search.  <database> is the name of the WAIS
+#   database being queried.
+
+
+sub default_port { 210 }
+
+sub _parse {
+    my($self, $init) = @_;
+    $self->URI::URL::_generic::_parse($init, qw(netloc path query frag));
+}
+
+# Set the path component with the specified number
+sub _path_comp
+{
+    my $self = shift;
+    my $no   = shift;
+    my @p = $self->path_components;
+    shift(@p) if @p && $p[0] eq '';
+    my $old = $p[$no];
+    if (@_) {
+	$p[$no] = $_[0];
+	$self->path_components(@p);
+    }
+    $old;
+}
+
+sub database { shift->_path_comp(0, @_); }
+sub wtype    { shift->_path_comp(1, @_); }
+sub wpath    { shift->_path_comp(2, @_); }
+
+*params   = \&URI::URL::bad_method;
+*eparams  = \&URI::URL::bad_method;
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/webster.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/webster.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/webster.pm	(revision 10506)
@@ -0,0 +1,6 @@
+package URI::URL::webster;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+sub default_port { 765 }
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/whois.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/whois.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/URI/URL/whois.pm	(revision 10506)
@@ -0,0 +1,6 @@
+package URI::URL::whois;
+require URI::URL::_generic;
+@ISA = qw(URI::URL::_generic);
+
+sub default_port { 43 }
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules.pm	(revision 10506)
@@ -0,0 +1,364 @@
+# $Id$
+
+package WWW::RobotRules;
+
+=head1 NAME
+
+WWW::RobotsRules - Parse robots.txt files
+
+=head1 SYNOPSIS
+
+ require WWW::RobotRules;
+ my $robotsrules = new WWW::RobotRules 'MOMspider/1.0';
+
+ use LWP::Simple qw(get);
+
+ $url = "http://some.place/robots.txt";
+ my $robots_txt = get $url;
+ $robotsrules->parse($url, $robots_txt);
+
+ $url = "http://some.other.place/robots.txt";
+ my $robots_txt = get $url;
+ $robotsrules->parse($url, $robots_txt);
+
+ # Now we are able to check if a URL is valid for those servers that
+ # we have obtained and parsed "robots.txt" files for.
+ if($robotsrules->allowed($url)) {
+     $c = get $url;
+     ...
+ }
+
+=head1 DESCRIPTION
+
+This module parses a F<robots.txt> file as specified in
+"A Standard for Robot Exclusion", described in
+<URL:http://info.webcrawler.com/mak/projects/robots/norobots.html>
+Webmasters can use the F<robots.txt> file to disallow conforming
+robots access to parts of their WWW server.
+
+The parsed file is kept in the WWW::RobotRules object, and this object
+provide methods to check if access to a given URL is prohibited.  The
+same WWW::RobotRules object can parse multiple F<robots.txt> files.
+
+The following methods are provided:
+
+=over 4
+
+=cut
+
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+sub Version { $VERSION; }
+
+
+use URI::URL ();
+use strict;
+
+
+=item $rules = new WWW::RobotRules 'MOMspider/1.0'
+
+This is the constructor for WWW::RobotRules objects.  The first 
+argument given to new() is the name of the robot. 
+
+=cut
+
+sub new {
+    my($class, $ua) = @_;
+
+    # This ugly hack is needed to ensure backwards compatability.
+    # The "WWW::RobotRules" class is now really abstract.
+    $class = "WWW::RobotRules::InCore" if $class eq "WWW::RobotRules";
+
+    my $self = bless { }, $class;
+    $self->agent($ua);
+    $self;
+}
+
+
+=item $rules->parse($url, $content, $fresh_until)
+
+The parse() method takes as arguments the URL that was used to
+retrieve the F</robots.txt> file, and the contents of the file.
+
+=cut
+
+sub parse {
+    my($self, $url, $txt, $fresh_until) = @_;
+
+    $url = new URI::URL $url unless ref($url);	# make it URL
+    my $netloc = $url->netloc;
+
+    $self->clear_rules($netloc);
+    $self->fresh_until($netloc, $fresh_until || (time + 365*24*3600));
+
+    my $ua;
+    my $is_me = 0;		# 1 iff this record is for me
+    my $is_anon = 0;		# 1 iff this record is for *
+    my @me_disallowed = ();	# rules disallowed for me
+    my @anon_disallowed = ();	# rules disallowed for *
+
+    # blank lines are significant, so turn CRLF into LF to avoid generating
+    # false ones
+    $txt =~ s/\015\012/\012/g;
+
+    # split at \012 (LF) or \015 (CR) (Mac text files have just CR for EOL)
+    for(split(/[\012\015]/, $txt)) {
+
+	# Lines containing only a comment are discarded completely, and
+        # therefore do not indicate a record boundary.
+	next if /^\s*\#/;
+
+	s/\s*\#.*//;        # remove comments at end-of-line
+
+	if (/^\s*$/) {	    # blank line
+	    last if $is_me; # That was our record. No need to read the rest.
+	    $is_anon = 0;
+	}
+        elsif (/^User-Agent:\s*(.*)/i) {
+	    $ua = $1;
+	    $ua =~ s/\s+$//;
+	    if ($is_me) {
+		# This record already had a User-agent that
+		# we matched, so just continue.
+	    }
+	    elsif ($ua eq '*') {
+		$is_anon = 1;
+	    }
+	    elsif($self->is_me($ua)) {
+		$is_me = 1;
+	    }
+	}
+	elsif (/^Disallow:\s*(.*)/i) {
+	    unless (defined $ua) {
+		warn "RobotRules: Disallow without preceding User-agent\n";
+		$is_anon = 1;  # assume that User-agent: * was intended
+	    }
+	    my $disallow = $1;
+	    $disallow =~ s/\s+$//;
+	    if (length $disallow) {
+		$disallow = URI::URL->new($disallow, $url)->full_path;
+	    }
+
+	    if ($is_me) {
+		push(@me_disallowed, $disallow);
+	    }
+	    elsif ($is_anon) {
+		push(@anon_disallowed, $disallow);
+	    }
+	}
+	else {
+	    warn "RobotRules: Unexpected line: $_\n";
+	}
+    }
+
+    if ($is_me) {
+	$self->push_rules($netloc, @me_disallowed);
+    } else {
+	$self->push_rules($netloc, @anon_disallowed);
+    }
+}
+
+# is_me()
+#
+# Returns TRUE if the given name matches the
+# name of this robot
+#
+sub is_me {
+    my($self, $ua) = @_;
+    my $me = $self->agent;
+    return index(lc($ua), lc($me)) >= 0;
+}
+
+=item $rules->allowed($url)
+
+Returns TRUE if this robot is allowed to retrieve this URL.
+
+=cut
+
+sub allowed {
+    my($self, $url) = @_;
+    $url = URI::URL->new($url) unless ref $url;	# make it URL
+
+    my $netloc = $url->netloc;
+
+    my $fresh_until = $self->fresh_until($netloc);
+    return -1 if !defined($fresh_until) || $fresh_until < time;
+
+    my $str = $url->full_path;
+    my $rule;
+    for $rule ($self->rules($netloc)) {
+	return 1 unless length $rule;
+	return 0 if index($str, $rule) == 0;
+    }
+    return 1;
+}
+
+# The following methods must be provided by the subclass.
+sub agent;
+sub visit;
+sub no_visits;
+sub last_visits;
+sub fresh_until;
+sub push_rules;
+sub clear_rules;
+sub rules;
+sub dump;
+
+package WWW::RobotRules::InCore;
+
+use vars qw(@ISA);
+@ISA = qw(WWW::RobotRules);
+
+=item $rules->agent([$name])
+
+Get/set the agent name. NOTE: Changing the agent name will clear the robots.txt
+rules and expire times out of the cache.
+
+=cut
+
+sub agent {
+    my ($self, $name) = @_;
+    my $old = $self->{'ua'};
+    if ($name) {
+	delete $self->{'loc'};   # all old info is now stale
+	$name =~ s!/?\s*\d+.\d+\s*$!!;  # loose version
+	$self->{'ua'}=$name;
+    }
+    $old;
+}
+
+sub visit {
+    my($self, $netloc, $time) = @_;
+    $time ||= time;
+    $self->{'loc'}{$netloc}{'last'} = $time;
+    
+    my $count = \$self->{'loc'}{$netloc}{'count'};
+    if (!defined $$count) {
+	$$count = 1;
+    } else {
+	$$count++;
+    }
+}
+
+sub no_visits {
+    my ($self, $netloc) = @_;
+    $self->{'loc'}{$netloc}{'count'};
+}
+
+sub last_visit {
+    my ($self, $netloc) = @_;
+    $self->{'loc'}{$netloc}{'last'};
+}
+
+sub fresh_until {
+    my ($self, $netloc, $fresh_until) = @_;
+    my $old = $self->{'loc'}{$netloc}{'fresh'};
+    if (defined $fresh_until) {
+	$self->{'loc'}{$netloc}{'fresh'} = $fresh_until;
+    }
+    $old;
+}
+
+sub push_rules {
+    my($self, $netloc, @rules) = @_;
+    push (@{$self->{'loc'}{$netloc}{'rules'}}, @rules);
+}
+
+sub clear_rules {
+    my($self, $netloc) = @_;
+    delete $self->{'loc'}{$netloc}{'rules'};
+}
+
+sub rules {
+    my($self, $netloc) = @_;
+    if (defined $self->{'loc'}{$netloc}{'rules'}) {
+	return @{$self->{'loc'}{$netloc}{'rules'}};
+    } else {
+	return ();
+    }
+}
+
+sub dump
+{
+    my $self = shift;
+    for (keys %$self) {
+	next if $_ eq 'loc';
+	print "$_ = $self->{$_}\n";
+    }
+    for (keys %{$self->{'loc'}}) {
+	my @rules = $self->rules($_);
+	print "$_: ", join("; ", @rules), "\n";
+	
+    }
+}
+
+1;
+
+__END__
+
+=back
+
+=head1 ROBOTS.TXT
+
+The format and semantics of the "/robots.txt" file are as follows
+(this is an edited abstract of
+<URL:http://info.webcrawler.com/mak/projects/robots/norobots.html>):
+
+The file consists of one or more records separated by one or more
+blank lines. Each record contains lines of the form
+
+  <field-name>: <value>
+
+The field name is case insensitive.  Text after the '#' character on a
+line is ignored during parsing.  This is used for comments.  The
+following <field-names> can be used:
+
+=over 3
+
+=item User-Agent
+
+The value of this field is the name of the robot the record is
+describing access policy for.  If more than one I<User-Agent> field is
+present the record describes an identical access policy for more than
+one robot. At least one field needs to be present per record.  If the
+value is '*', the record describes the default access policy for any
+robot that has not not matched any of the other records.
+
+=item Disallow
+
+The value of this field specifies a partial URL that is not to be
+visited. This can be a full path, or a partial path; any URL that
+starts with this value will not be retrieved
+
+=back
+
+=head1 ROBOTS.TXT EXAMPLES
+
+The following example "/robots.txt" file specifies that no robots
+should visit any URL starting with "/cyberworld/map/" or "/tmp/":
+
+  User-agent: *
+  Disallow: /cyberworld/map/ # This is an infinite virtual URL space
+  Disallow: /tmp/ # these will soon disappear
+
+This example "/robots.txt" file specifies that no robots should visit
+any URL starting with "/cyberworld/map/", except the robot called
+"cybermapper":
+
+  User-agent: *
+  Disallow: /cyberworld/map/ # This is an infinite virtual URL space
+
+  # Cybermapper knows where to go.
+  User-agent: cybermapper
+  Disallow:
+
+This example indicates that no robots should visit this site further:
+
+  # go away
+  User-agent: *
+  Disallow: /
+
+=head1 SEE ALSO
+
+L<LWP::RobotUA>, L<WWW::RobotRules::AnyDBM_File>
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules/AnyDBM_File.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules/AnyDBM_File.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lib/WWW/RobotRules/AnyDBM_File.pm	(revision 10506)
@@ -0,0 +1,170 @@
+# $Id$
+
+package WWW::RobotRules::AnyDBM_File;
+
+require  WWW::RobotRules;
+@ISA = qw(WWW::RobotRules);
+$VERSION = sprintf("%d.%02d", q$Revision$ =~ /(\d+)\.(\d+)/);
+
+use Carp ();
+use AnyDBM_File;
+use Fcntl;
+use strict;
+
+=head1 NAME
+
+WWW::RobotRules::AnyDBM_File - Persistent RobotRules
+
+=head1 SYNOPSIS
+
+ require WWW::RobotRules::AnyDBM_File;
+ require LWP::RobotUA;
+
+ # Create a robot useragent that uses a diskcaching RobotRules
+ my $rules = new WWW::RobotRules::AnyDBM_File 'my-robot/1.0', 'cachefile';
+ my $ua = new WWW::RobotUA 'my-robot/1.0', 'me@foo.com', $rules;
+
+ # Then just use $ua as usual
+ $res = $ua->request($req);
+
+=head1 DESCRIPTION
+
+This is a subclass of I<WWW::RobotRules> that uses the AnyDBM_File
+package to implement persistent diskcaching of F<robots.txt> and host
+visit information.
+
+The constructor (the new() method) takes an extra argument specifying
+the name of the DBM file to use.  If the DBM file already exists, then
+you can specify undef as agent name as the name can be obtained from
+the DBM database.
+
+=cut
+
+sub new 
+{ 
+  my ($class, $ua, $file) = @_;
+  Carp::croak('WWW::RobotRules::AnyDBM_File filename required') unless $file;
+
+  my $self = bless { }, $class;
+  $self->{'filename'} = $file;
+  tie %{$self->{'dbm'}}, 'AnyDBM_File', $file, O_CREAT|O_RDWR, 0640
+    or Carp::croak("Can't open $file: $!");
+  
+  if ($ua) {
+      $self->agent($ua);
+  } else {
+      # Try to obtain name from DBM file
+      $ua = $self->{'dbm'}{"|ua-name|"};
+      Carp::croak("No agent name specified") unless $ua;
+  }
+
+  $self;
+}
+
+sub agent {
+    my($self, $newname) = @_;
+    my $old = $self->{'dbm'}{"|ua-name|"};
+    if (defined $newname) {
+	$newname =~ s!/?\s*\d+.\d+\s*$!!;  # loose version
+	unless ($old && $old eq $newname) {
+	# Old info is now stale.
+	    my $file = $self->{'filename'};
+	    untie %{$self->{'dbm'}};
+	    tie %{$self->{'dbm'}}, 'AnyDBM_File', $file, O_TRUNC|O_RDWR, 0640;
+	    $self->{'dbm'}{"|ua-name|"} = $newname;
+	}
+    }
+    $old;
+}
+
+sub no_visits {
+    my ($self, $netloc) = @_;
+    my $t = $self->{'dbm'}{"$netloc|vis"};
+    return 0 unless $t;
+    (split(/;\s*/, $t))[0];
+}
+
+sub last_visit {
+    my ($self, $netloc) = @_;
+    my $t = $self->{'dbm'}{"$netloc|vis"};
+    return undef unless $t;
+    (split(/;\s*/, $t))[1];
+}
+
+sub fresh_until {
+    my ($self, $netloc, $fresh) = @_;
+    my $old = $self->{'dbm'}{"$netloc|exp"};
+    if ($old) {
+	$old =~ s/;.*//;  # remove cleartext
+    }
+    if (defined $fresh) {
+	$fresh .= "; " . localtime($fresh);
+	$self->{'dbm'}{"$netloc|exp"} = $fresh;
+    }
+    $old;
+}
+
+sub visit {
+    my($self, $netloc, $time) = @_;
+    $time ||= time;
+
+    my $count = 0;
+    my $old = $self->{'dbm'}{"$netloc|vis"};
+    if ($old) {
+	my $last;
+	($count,$last) = split(/;\s*/, $old);
+	$time = $last if $last > $time;
+    }
+    $count++;
+    $self->{'dbm'}{"$netloc|vis"} = "$count; $time; " . localtime($time);
+}
+
+sub push_rules {
+    my($self, $netloc, @rules) = @_;
+    my $cnt = 1;
+    $cnt++ while $self->{'dbm'}{"$netloc|r$cnt"};
+
+    foreach (@rules) {
+	$self->{'dbm'}{"$netloc|r$cnt"} = $_;
+	$cnt++;
+    }
+}
+
+sub clear_rules {
+    my($self, $netloc) = @_;
+    my $cnt = 1;
+    while ($self->{'dbm'}{"$netloc|r$cnt"}) {
+	delete $self->{'dbm'}{"$netloc|r$cnt"};
+	$cnt++;
+    }
+}
+
+sub rules {
+    my($self, $netloc) = @_;
+    my @rules = ();
+    my $cnt = 1;
+    while (1) {
+	my $rule = $self->{'dbm'}{"$netloc|r$cnt"};
+	last unless $rule;
+	push(@rules, $rule);
+	$cnt++;
+    }
+    @rules;
+}
+
+sub dump
+{
+}
+
+1;
+
+=head1 SEE ALSO
+
+L<WWW::RobotRules>, L<LWP::RobotUA>
+
+=head1 AUTHORS
+
+Hakan Ardo E<lt>hakan@munin.ub2.lu.se>, Gisle Aas E<lt>aas@sn.no>
+
+=cut
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lwpcook.pod
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lwpcook.pod	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/lwpcook.pod	(revision 10506)
@@ -0,0 +1,343 @@
+=head1 NAME
+
+lwpcook - libwww-perl cookbook
+
+=head1 DESCRIPTION
+
+This document contain some examples that show typical usage of the
+libwww-perl library.  You should consult the documentation for the
+individual modules for more detail.
+
+All examples should be runnable programs. You can, in most cases, test
+the code sections by piping the program text directly to perl.
+
+
+
+=head1 GET
+
+It is very easy to use this library to just fetch documents from the
+net.  The LWP::Simple module provides the get() function that return
+the document specified by its URL argument:
+
+  use LWP::Simple;
+  $doc = get 'http://www.sn.no/libwww-perl/';
+
+or, as a perl one-liner using the getprint() function:
+
+  perl -MLWP::Simple -e 'getprint "http://www.sn.no/libwww-perl/"'
+
+or, how about fetching the latest perl by running this command:
+
+  perl -MLWP::Simple -e '
+    getstore "ftp://ftp.sunet.se/pub/lang/perl/CPAN/src/latest.tar.gz",
+             "perl.tar.gz"'
+
+You will probably first want to find a CPAN site closer to you by
+running something like the following command:
+
+  perl -MLWP::Simple -e 'getprint "http://www.perl.com/perl/CPAN/CPAN.html"'
+
+Enough of this simple stuff!  The LWP object oriented interface gives
+you more control over the request sent to the server.  Using this
+interface you have full control over headers sent and how you want to
+handle the response returned.
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+  $ua->agent("$0/0.1 " . $ua->agent);
+  # $ua->agent("Mozilla/8.0") # pretend we are very capable browser
+
+  $req = new HTTP::Request 'GET' => 'http://www.sn.no/libwww-perl';
+  $req->header('Accept' => 'text/html');
+
+  # send request
+  $res = $ua->request($req);
+
+  # check the outcome
+  if ($res->is_success) {
+     print $res->content;
+  } else {
+     print "Error: " . $res->status_line . "\n";
+  }
+
+The lwp-request program (alias GET) that is distributed with the
+library can also be used to fetch documents from WWW servers.
+  
+
+
+=head1 HEAD
+
+If you just want to check if a document is present (i.e. the URL is
+valid) try to run code that looks like this:
+
+  use LWP::Simple;
+
+  if (head($url)) {
+     # ok document exists
+  }
+
+The head() function really returns a list of meta-information about
+the document.  The first three values of the list returned are the
+document type, the size of the document, and the age of the document.
+
+More control over the request or access to all header values returned
+require that you use the object oriented interface described for GET
+above.  Just s/GET/HEAD/g.
+
+
+=head1 POST
+
+There is no simple procedural interface for posting data to a WWW server.  You
+must use the object oriented interface for this. The most common POST
+operation is to access a WWW form application:
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+
+  my $req = new HTTP::Request 'POST','http://www.perl.com/cgi-bin/BugGlimpse';
+  $req->content_type('application/x-www-form-urlencoded');
+  $req->content('match=www&errors=0');
+
+  my $res = $ua->request($req);
+  print $res->as_string;
+
+Lazy people use the HTTP::Request::Common module to set up a suitable
+POST request message (it handles all the escaping issues) and has a
+suitable default for the content_type:
+
+  use HTTP::Request::Common qw(POST);
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+
+  my $req = POST 'http://www.perl.com/cgi-bin/BugGlimpse',
+                [ search => 'www', errors => 0 ];
+
+  print $ua->request($req)->as_string;
+
+The lwp-request program (alias POST) that is distributed with the
+library can also be used for posting data.
+
+
+
+=head1 PROXIES
+
+Some sites use proxies to go through fire wall machines, or just as
+cache in order to improve performance.  Proxies can also be used for
+accessing resources through protocols not supported directly (or
+supported badly :-) by the libwww-perl library.
+
+You should initialize your proxy setting before you start sending
+requests:
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+  $ua->env_proxy; # initialize from environment variables
+  # or
+  $ua->proxy(ftp  => 'http://proxy.myorg.com');
+  $ua->proxy(wais => 'http://proxy.myorg.com');
+  $ua->no_proxy(qw(no se fi));
+
+  my $req = new HTTP::Request 'wais://xxx.com/';
+  print $ua->request($req)->as_string;
+
+The LWP::Simple interface will call env_proxy() for you automatically.
+Applications that use the $ua->env_proxy() method will normally not
+use the $ua->proxy() and $ua->no_proxy() methods.
+
+Some proxies also require that you send it a username/password in
+order to let requests through.  You should be able to add the
+required header, with something like this:
+
+ use LWP::UserAgent;
+
+ $ua = new LWP::UserAgent;
+ $ua->proxy(['http', 'ftp'] => 'http://proxy.myorg.com');
+
+ $req = new HTTP::Request 'GET',"http://www.perl.com";
+ $req->proxy_authorization_basic("proxy_user", "proxy_password");
+
+ $res = $ua->request($req);
+ print $res->content if $res->is_success;
+
+Replace C<proxy.myorg.com>, C<proxy_user> and
+C<proxy_password> with something suitable for your site.
+
+
+=head1 ACCESS TO PROTECTED DOCUMENTS
+
+Documents protected by basic authorization can easily be accessed
+like this:
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+  $req = new HTTP::Request GET => 'http://www.sn.no/secret/';
+  $req->authorization_basic('aas', 'mypassword');
+  print $ua->request($req)->as_string;
+
+The other alternative is to provide a subclass of I<LWP::UserAgent> that
+overrides the get_basic_credentials() method. Study the I<lwp-request>
+program for an example of this.
+
+
+=head1 MIRRORING
+
+If you want to mirror documents from a WWW server, then try to run
+code similar to this at regular intervals:
+
+  use LWP::Simple;
+
+  %mirrors = (
+     'http://www.sn.no/'             => 'sn.html',
+     'http://www.perl.com/'          => 'perl.html',
+     'http://www.sn.no/libwww-perl/' => 'lwp.html',
+     'gopher://gopher.sn.no/'        => 'gopher.html',
+  );
+
+  while (($url, $localfile) = each(%mirrors)) {
+     mirror($url, $localfile);
+  }
+
+Or, as a perl one-liner:
+
+  perl -MLWP::Simple -e 'mirror("http://www.perl.com/", "perl.html")';
+
+The document will not be transfered unless it has been updated.
+
+
+
+=head1 LARGE DOCUMENTS
+
+If the document you want to fetch is too large to be kept in memory,
+then you have two alternatives.  You can instruct the library to write
+the document content to a file (second $ua->request() argument is a file
+name):
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+
+  my $req = new HTTP::Request 'GET',
+                'http://www.sn.no/~aas/perl/www/libwww-perl-5.00.tar.gz';
+  $res = $ua->request($req, "libwww-perl.tar.gz");
+  if ($res->is_success) {
+     print "ok\n";
+  }
+
+Or you can process the document as it arrives (second $ua->request()
+argument is a code reference):
+
+  use LWP::UserAgent;
+  $ua = new LWP::UserAgent;
+  $URL = 'ftp://ftp.unit.no/pub/rfc/rfc-index.txt';
+
+  my $expected_length;
+  my $bytes_received = 0;
+  $ua->request(HTTP::Request->new('GET', $URL),
+               sub {
+                   my($chunk, $res) = @_;
+                   $bytes_received += length($chunk);
+	           unless (defined $expected_length) {
+	              $expected_length = $res->content_length || 0;
+                   }
+		   if ($expected_length) {
+		        printf STDERR "%d%% - ",
+	                          100 * $bytes_received / $expected_length;
+                   }
+	           print STDERR "$bytes_received bytes received\n";
+
+                   # XXX Should really do something with the chunk itself
+	           # print $chunk;
+               });
+
+
+
+=head1 HTML FORMATTING
+
+It is easy to convert HTML code to "readable" text.
+
+  use LWP::Simple;
+  use HTML::Parse;
+  print parse_html(get 'http://www.sn.no/libwww-perl/')->format;
+
+
+
+=head1 PARSE URLS
+
+To access individual elements of a URL, try this:
+
+  use URI::URL;
+  $host = url("http://www.sn.no/")->host;
+
+or
+
+  use URI::URL;
+  $u = url("ftp://ftp.sn.no/test/aas;type=i");
+  print "Protocol scheme is ", $u->scheme, "\n";
+  print "Host is ", $u->host, " at port ", $u->port, "\n";
+
+or even
+
+  use URI::URL;
+  my($host,$port) = (url("ftp://ftp.sn.no/test/aas;type=i")->crack)[3,4];
+
+
+=head1 EXPAND RELATIVE URLS
+
+This code reads URLs and print expanded version.
+
+  use URI::URL;
+  $BASE = "http://www.sn.no/some/place?query";
+  while (<>) {
+     print url($_, $BASE)->abs->as_string, "\n";
+  }
+
+We can expand URLs in an HTML document by using the parser to build a
+tree that we then traverse:
+
+  %link_elements =
+  (
+   'a'    => 'href',
+   'img'  => 'src',
+   'form' => 'action',
+   'link' => 'href',
+  );
+
+  use HTML::Parse;
+  use URI::URL;
+
+  $BASE = "http://somewhere/root/";
+  $h = parse_htmlfile("xxx.html");
+  $h->traverse(\&expand_urls, 1);
+
+  print $h->as_HTML;
+
+  sub expand_urls
+  {
+     my($e, $start) = @_;
+     return 1 unless $start;
+     my $attr = $link_elements{$e->tag};
+     return 1 unless defined $attr;
+     my $url = $e->attr($attr);
+     return 1 unless defined $url;
+     $e->attr($attr, url($url, $BASE)->abs->as_string);
+  }
+
+
+
+=head1 BASE URL
+
+If you want to resolve relative links in a page you will have to
+determine which base URL to use.  The HTTP::Response objects now has a
+base() method.
+
+  $BASE = $res->base;
+
+
+
+=head1 COPYRIGHT
+
+Copyright 1996-1997, Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/README	(revision 10506)
@@ -0,0 +1,24 @@
+Self test suite for the libwww-perl library
+-------------------------------------------
+
+Tests are invoked by running the ./TEST script, but usually you run
+the tests with "make test" at the top libwww-perl directory.  Use -v
+option for verbose tests.  You might run an individual test like this:
+
+  ./TEST -v base/date
+
+or all tests in a directory like this
+
+  ./TEST base
+
+You enable network tests by creating the "net/config.pl" file.  A good
+start is to make a copy of the "net/config.pl.dist" file.  For network
+tests you should also make a link from the cgi-bin directory of your
+http server to the "net/cgi-bin" directory.  You might also have to
+check that the interpreter line (#!.../perl) in the scripts is ok for
+your system.  The following setup works for my site:
+
+  ln -s `pwd`/net/cgi-bin ~www/cgi-bin/lwp
+  cp net/config.pl.dist net/config.pl
+  emacs net/config.pl                        # fix if necessary
+  ./TEST net
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/TEST
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/TEST	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/TEST	(revision 10506)
@@ -0,0 +1,39 @@
+#!/usr/local/bin/perl
+
+# This script is run Test::Harness on the tests found under the
+# "t" directory.
+
+# First we check if we already are within the "t" directory
+unless (-d "base") {
+    # try to move into test directory
+    chdir "t" or die "Can't chdir: $!";
+
+    # fix all relative library locations
+    foreach (@INC) {
+	$_ = "../$_" unless m,^/,;
+    }
+}
+# Pick up the library files from the ../blib directory
+unshift(@INC, "../blib/lib", "../blib/arch");
+#print "@INC\n";
+
+
+use Test::Harness;
+$Test::Harness::verbose = shift
+  if $ARGV[0] =~ /^\d+$/ || $ARGV[0] eq "-v";
+
+if (@ARGV) {
+    for (@ARGV) {
+	if (-d $_) {
+	    push(@tests, <$_/*.t>);
+	} else {
+            $_ .= ".t" unless /\.t$/;
+	    push(@tests, $_);
+	}
+    }
+} else {
+    @tests = (<base/*.t>, <uri/*.t>, <robot/*.t>, <local/*.t>);
+    push(@tests, <net/*.t>) if -f "net/config.pl";
+}
+
+runtests @tests;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/common-req.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/common-req.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/common-req.t	(revision 10506)
@@ -0,0 +1,193 @@
+print "1..19\n";
+
+use HTTP::Request::Common;
+
+$r = GET 'http://www.sn.no/';
+print $r->as_string;
+
+print "not " unless $r->method eq "GET" and $r->url eq "http://www.sn.no/";
+print "ok 1\n";
+
+$r = HEAD "http://www.sn.no/",
+     If_Match => 'abc',
+     From => 'aas@sn.no';
+print $r->as_string;
+
+print "not " unless $r->method eq "HEAD" and $r->url->eq("http://www.sn.no");
+print "ok 2\n";
+
+print "not " unless $r->header('If-Match') eq "abc" and $r->header("from") eq "aas\@sn.no";
+print "ok 3\n";
+
+$r = PUT "http://www.sn.no",
+     Content => 'foo';
+print $r->as_string;
+
+print "not " unless $r->method eq "PUT" and $r->url->netloc eq "www.sn.no";
+print "ok 4\n";
+
+print "not " if defined($r->header("Content"));
+print "ok 5\n";
+
+print "not " unless ${$r->content_ref} eq "foo" and
+                    $r->content eq "foo";
+print "ok 6\n";
+
+#--- Test POST requests ---
+
+$r = POST "http://www.sn.no", [foo => 'bar',
+                               baz => [qw(a b c)],
+                               foo => 'zoo=&',
+                               "space " => " + ",
+                              ],
+                              bar => 'foo';
+print $r->as_string;
+
+print "not " unless $r->method eq "POST" and
+                    $r->content_type eq "application/x-www-form-urlencoded" and
+                    $r->content_length == 58 and
+                    $r->header("bar") eq "foo";
+print "ok 7\n";
+
+print "not " unless $r->content eq "foo=bar&baz=a&baz=b&baz=c&foo=zoo%3D%26&space%20=%20%2B%20";
+print "ok 8\n";
+
+$r = POST "mailto:gisle\@aas.no",
+     Subject => "Heisan",
+     Content_Type => "text/plain",
+     Content => "Howdy\n";
+print $r->as_string;
+
+print "not " unless $r->method eq "POST" and
+                    $r->header("Subject") eq "Heisan" and
+                    $r->content eq "Howdy\n" and
+	            $r->content_type eq "text/plain";
+print "ok 9\n";
+
+#
+# POST for File upload
+#
+$file = "test-$$";
+open(FILE, ">$file") or die "Can't create $file: $!";
+print FILE "foo\nbar\nbaz\n";
+close(FILE);
+
+$r = POST 'http://www.perl.org/survey.cgi',
+       Content_Type => 'form-data',
+       Content      => [ name  => 'Gisle Aas',
+                         email => 'gisle@aas.no',
+                         gender => 'm',
+                         born   => '1964',
+                         file   => [$file],
+                       ];
+print $r->as_string;
+
+unlink($file) or warn "Can't unlink $file: $!";
+
+print "not " unless $r->method eq "POST" and
+	            $r->url->path eq "/survey.cgi" and
+                    $r->content_type eq "multipart/form-data" and
+	            $r->header(Content_type) =~ /boundary="?([^"]+)"?/;
+print "ok 10\n";
+$boundary = $1;
+
+$c = $r->content;
+$c =~ s/\r//g;
+@c = split(/--\Q$boundary/, $c);
+print "$c[5]\n";
+
+print "not " unless @c == 7 and $c[6] =~ /^--\n/;  # 5 parts + header & trailer
+print "ok 11\n";
+
+print "not " unless $c[2] =~ /^Content-Disposition:\s*form-data;\s*name="email"/m and
+                    $c[2] =~ /^gisle\@aas.no$/m;
+print "ok 12\n";
+
+print "not " unless $c[5] =~ /^Content-Disposition:\s*form-data;\s*name="file";\s*filename="$file"/m and
+	            $c[5] =~ /^Content-Type:\s*text\/plain$/m and
+	            $c[5] =~ /^foo\nbar\nbaz/m;
+print "ok 13\n";
+
+$r = POST 'http://www.perl.org/survey.cgi',
+      [ file => [ undef, "xxx", Content_type => "text/html", Content => "<h1>Hello, world!</h1>" ]],
+      Content_type => 'multipart/form-data';
+print $r->as_string;
+
+print "not " unless $r->content =~ /^--\S+\015\012Content-Disposition:\s*form-data;\s*name="file";\s*filename="xxx"/m and
+	            $r->content =~ /^Content-Type: text\/html/m and
+	            $r->content =~ /^<h1>Hello, world/m;
+print "ok 14\n";
+
+
+$r = POST 'http://www.perl.org/survey.cgi',
+      Content_type => 'multipart/form-data',
+      Content => [ file => [ undef, undef, Content => "foo"]];
+print $r->as_string;
+
+print "not " if $r->content =~ /filename=/;
+print "ok 15\n";
+
+
+# The POST routine can now also take a hash reference.
+my %hash = (foo => 42, bar => 24);
+$r = POST 'http://www.perl.org/survey.cgi', \%hash;
+print $r->as_string;
+print "not " unless $r->content =~ /foo=42/ &&
+                    $r->content =~ /bar=24/ &&
+                    $r->content_type eq "application/x-www-form-urlencoded" &&
+                    $r->content_length == 13;
+print "ok 16\n";
+
+ 
+#
+# POST for File upload
+#
+use HTTP::Request::Common qw($DYNAMIC_FILE_UPLOAD);
+
+$file = "test-$$";
+open(FILE, ">$file") or die "Can't create $file: $!";
+for (1..1000) {
+   print FILE "a" .. "z";
+}
+close(FILE);
+
+$DYNAMIC_FILE_UPLOAD++;
+$r = POST 'http://www.perl.org/survey.cgi',
+       Content_Type => 'form-data',
+       Content      => [ name  => 'Gisle Aas',
+                         email => 'gisle@aas.no',
+                         gender => 'm',
+                         born   => '1964',
+                         file   => [$file],
+                       ];
+print $r->as_string;
+
+print "not " unless $r->method eq "POST" and
+	            $r->url->path eq "/survey.cgi" and
+                    $r->content_type eq "multipart/form-data" and
+	            $r->header(Content_type) =~ /boundary="?([^"]+)"?/ and
+		    ref($r->content) eq "CODE";
+print "ok 17\n";
+$boundary = $1;
+
+print "not " unless length($boundary) > 10;
+print "ok 18\n";
+
+$code = $r->content;
+my $chunk;
+my @chunks;
+while (defined($chunk = &$code) && length $chunk) {
+   push(@chunks, $chunk);
+}
+
+unlink($file) or warn "Can't unlink $file: $!";
+
+$_ = join("", @chunks);
+
+print int(@chunks), " chunks, total size is ", length($_), " bytes\n";
+
+# should be close to expected size and number of chunks
+print "not " unless abs(@chunks - 15 < 3) and
+                    abs(length($_) - 26589) < 20;
+print "ok 19\n";
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/cookies.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/cookies.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/cookies.t	(revision 10506)
@@ -0,0 +1,515 @@
+print "1..32\n";
+
+#use LWP::Debug '+';
+
+use HTTP::Cookies;
+use HTTP::Request;
+use HTTP::Response;
+
+#-------------------------------------------------------------------
+# First we check that it works for the original example at
+# http://www.netscape.com/newsref/std/cookie_spec.html
+
+# Client requests a document, and receives in the response:
+# 
+#       Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
+# 
+# When client requests a URL in path "/" on this server, it sends:
+# 
+#       Cookie: CUSTOMER=WILE_E_COYOTE
+# 
+# Client requests a document, and receives in the response:
+# 
+#       Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
+# 
+# When client requests a URL in path "/" on this server, it sends:
+# 
+#       Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
+# 
+# Client receives:
+# 
+#       Set-Cookie: SHIPPING=FEDEX; path=/fo
+# 
+# When client requests a URL in path "/" on this server, it sends:
+# 
+#       Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
+# 
+# When client requests a URL in path "/foo" on this server, it sends:
+# 
+#       Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX
+# 
+# The last Cookie is buggy, because both specifications says that the
+# most specific cookie must be sent first.  SHIPPING=FEDEX is the
+# most specific and should thus be first.
+
+$c = HTTP::Cookies->new;
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/");
+
+$res = HTTP::Response->new(200, "OK");
+$res->request($req);
+$res->header("Set-Cookie" => "CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT");
+$c->extract_cookies($res);
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/");
+$c->add_cookie_header($req);
+
+print "not " unless $req->header("Cookie") eq "CUSTOMER=WILE_E_COYOTE" &&
+                    $req->header("Cookie2") eq "\$Version=1";
+print "ok 1\n";
+
+$res->request($req);
+$res->header("Set-Cookie" => "PART_NUMBER=ROCKET_LAUNCHER_0001; path=/");
+$c->extract_cookies($res);
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/foo/bar");
+$c->add_cookie_header($req);
+
+$h = $req->header("Cookie");
+print "not " unless $h =~ /PART_NUMBER=ROCKET_LAUNCHER_0001/ &&
+                    $h =~ /CUSTOMER=WILE_E_COYOTE/;
+print "ok 2\n";
+
+$res->request($req);
+$res->header("Set-Cookie", "SHIPPING=FEDEX; path=/foo");
+$c->extract_cookies($res);
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/");
+$c->add_cookie_header($req);
+
+$h = $req->header("Cookie");
+print "not " unless $h =~ /PART_NUMBER=ROCKET_LAUNCHER_0001/ &&
+	            $h =~ /CUSTOMER=WILE_E_COYOTE/ &&
+	            $h !~ /SHIPPING=FEDEX/;
+print "ok 3\n";
+
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/foo/");
+$c->add_cookie_header($req);
+
+$h = $req->header("Cookie");
+print "not " unless $h =~ /PART_NUMBER=ROCKET_LAUNCHER_0001/ &&
+	            $h =~ /CUSTOMER=WILE_E_COYOTE/ &&
+		    $h =~ /^SHIPPING=FEDEX;/;
+print "ok 4\n";
+
+print $c->as_string;
+
+
+# Second Example transaction sequence:
+# 
+# Assume all mappings from above have been cleared.
+# 
+# Client receives:
+# 
+#       Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
+# 
+# When client requests a URL in path "/" on this server, it sends:
+# 
+#       Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
+# 
+# Client receives:
+# 
+#       Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
+# 
+# When client requests a URL in path "/ammo" on this server, it sends:
+# 
+#       Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
+# 
+#       NOTE: There are two name/value pairs named "PART_NUMBER" due to
+#       the inheritance of the "/" mapping in addition to the "/ammo" mapping. 
+
+$c = HTTP::Cookies->new;  # clear it
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/");
+$res = HTTP::Response->new(200, "OK");
+$res->request($req);
+$res->header("Set-Cookie", "PART_NUMBER=ROCKET_LAUNCHER_0001; path=/");
+
+$c->extract_cookies($res);
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/");
+$c->add_cookie_header($req);
+
+print "not " unless $req->header("Cookie") eq "PART_NUMBER=ROCKET_LAUNCHER_0001";
+print "ok 5\n";
+
+$res->request($req);
+$res->header("Set-Cookie", "PART_NUMBER=RIDING_ROCKET_0023; path=/ammo");
+$c->extract_cookies($res);
+
+$req = HTTP::Request->new(GET => "http://www.acme.com/ammo");
+$c->add_cookie_header($req);
+
+print "not " unless $req->header("Cookie") =~
+       /^PART_NUMBER=RIDING_ROCKET_0023;\s*PART_NUMBER=ROCKET_LAUNCHER_0001/;
+print "ok 6\n";
+
+print $c->as_string;
+undef($c);
+
+
+#-------------------------------------------------------------------
+# When there are no "Set-Cookie" header, then even responses
+# without any request URLs connected should be allowed.
+
+$c = HTTP::Cookies->new;
+$c->extract_cookies(HTTP::Response->new("200", "OK"));
+print "not " if count_cookies($c) != 0;
+print "ok 7\n";
+
+
+#-------------------------------------------------------------------
+# Then we test with the examples from draft-ietf-http-state-man-mec-03.txt
+#
+# 5.  EXAMPLES
+
+$c = HTTP::Cookies->new;
+
+# 
+# 5.1  Example 1
+# 
+# Most detail of request and response headers has been omitted.  Assume
+# the user agent has no stored cookies.
+# 
+#   1.  User Agent -> Server
+# 
+#       POST /acme/login HTTP/1.1
+#       [form data]
+# 
+#       User identifies self via a form.
+# 
+#   2.  Server -> User Agent
+# 
+#       HTTP/1.1 200 OK
+#       Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"
+# 
+#       Cookie reflects user's identity.
+
+$cookie = interact($c, 'http://www.acme.com/acme/login',
+                       'Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"');
+print "not " if $cookie;
+print "ok 8\n";
+
+# 
+#   3.  User Agent -> Server
+# 
+#       POST /acme/pickitem HTTP/1.1
+#       Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
+#       [form data]
+# 
+#       User selects an item for ``shopping basket.''
+# 
+#   4.  Server -> User Agent
+# 
+#       HTTP/1.1 200 OK
+#       Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
+#               Path="/acme"
+# 
+#       Shopping basket contains an item.
+
+$cookie = interact($c, 'http://www.acme.com/acme/pickitem',
+		       'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"');
+print "not " unless $cookie =~ m(^\$Version="?1"?; Customer="?WILE_E_COYOTE"?; \$Path="/acme"$);
+print "ok 9\n";
+
+# 
+#   5.  User Agent -> Server
+# 
+#       POST /acme/shipping HTTP/1.1
+#       Cookie: $Version="1";
+#               Customer="WILE_E_COYOTE"; $Path="/acme";
+#               Part_Number="Rocket_Launcher_0001"; $Path="/acme"
+#       [form data]
+# 
+#       User selects shipping method from form.
+# 
+#   6.  Server -> User Agent
+# 
+#       HTTP/1.1 200 OK
+#       Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme"
+# 
+#       New cookie reflects shipping method.
+
+$cookie = interact($c, "http://www.acme.com/acme/shipping",
+		   'Shipping="FedEx"; Version="1"; Path="/acme"');
+
+print "not " unless $cookie =~ /^\$Version="?1"?;/ &&
+     $cookie =~ /Part_Number="?Rocket_Launcher_0001"?;\s*\$Path="\/acme"/ &&
+     $cookie =~ /Customer="?WILE_E_COYOTE"?;\s*\$Path="\/acme"/;
+print "ok 10\n";
+
+# 
+#   7.  User Agent -> Server
+# 
+#       POST /acme/process HTTP/1.1
+#       Cookie: $Version="1";
+#               Customer="WILE_E_COYOTE"; $Path="/acme";
+#               Part_Number="Rocket_Launcher_0001"; $Path="/acme";
+#               Shipping="FedEx"; $Path="/acme"
+#       [form data]
+# 
+#       User chooses to process order.
+# 
+#   8.  Server -> User Agent
+# 
+#       HTTP/1.1 200 OK
+# 
+#       Transaction is complete.
+
+$cookie = interact($c, "http://www.acme.com/acme/process");
+print "FINAL COOKIE: $cookie\n";
+print "not " unless $cookie =~ /Shipping="?FedEx"?;\s*\$Path="\/acme"/ &&
+                    $cookie =~ /WILE_E_COYOTE/;
+print "ok 11\n";
+
+# 
+# The user agent makes a series of requests on the origin server, after
+# each of which it receives a new cookie.  All the cookies have the same
+# Path attribute and (default) domain.  Because the request URLs all have
+# /acme as a prefix, and that matches the Path attribute, each request
+# contains all the cookies received so far.
+
+print $c->as_string;
+
+
+# 5.2  Example 2
+# 
+# This example illustrates the effect of the Path attribute.  All detail
+# of request and response headers has been omitted.  Assume the user agent
+# has no stored cookies.
+
+$c = HTTP::Cookies->new;
+
+# Imagine the user agent has received, in response to earlier requests,
+# the response headers
+# 
+# Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1";
+#         Path="/acme"
+# 
+# and
+# 
+# Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1";
+#         Path="/acme/ammo"
+
+interact($c, "http://www.acme.com/acme/ammo/specific",
+             'Part_Number="Rocket_Launcher_0001"; Version="1"; Path="/acme"',
+             'Part_Number="Riding_Rocket_0023"; Version="1"; Path="/acme/ammo"');
+
+# A subsequent request by the user agent to the (same) server for URLs of
+# the form /acme/ammo/...  would include the following request header:
+# 
+# Cookie: $Version="1";
+#         Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
+#         Part_Number="Rocket_Launcher_0001"; $Path="/acme"
+# 
+# Note that the NAME=VALUE pair for the cookie with the more specific Path
+# attribute, /acme/ammo, comes before the one with the less specific Path
+# attribute, /acme.  Further note that the same cookie name appears more
+# than once.
+
+$cookie = interact($c, "http://www.acme.com/acme/ammo/...");
+print "not " unless $cookie =~ /Riding_Rocket_0023.*Rocket_Launcher_0001/;
+print "ok 12\n";
+
+# A subsequent request by the user agent to the (same) server for a URL of
+# the form /acme/parts/ would include the following request header:
+# 
+# Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"
+# 
+# Here, the second cookie's Path attribute /acme/ammo is not a prefix of
+# the request URL, /acme/parts/, so the cookie does not get forwarded to
+# the server.
+
+$cookie = interact($c, "http://www.acme.com/acme/parts/");
+print "not " unless $cookie =~ /Rocket_Launcher_0001/ &&
+		    $cookie !~ /Riding_Rocket_0023/;
+print "ok 13\n";
+
+print $c->as_string;
+
+#-----------------------------------------------------------------------
+
+# Test rejection of Set-Cookie2 responses based on domain, path or port
+
+$c = HTTP::Cookies->new;
+
+# illegal domain (no embedded dots)
+$cookie = interact($c, "http://www.acme.com", 'foo=bar; domain=".com"');
+print "not " if count_cookies($c) > 0;
+print "ok 14\n";
+
+# legal domain
+$cookie = interact($c, "http://www.acme.com", 'foo=bar; domain="acme.com"');
+print "not " if count_cookies($c) != 1;
+print "ok 15\n";
+
+# illegal domain (host prefix "www.a" contains a dot)
+$cookie = interact($c, "http://www.a.acme.com", 'foo=bar; domain="acme.com"');
+print "not " if count_cookies($c) != 1;
+print "ok 16\n";
+
+# legal domain
+$cookie = interact($c, "http://www.a.acme.com", 'foo=bar; domain=".a.acme.com"');
+print "not " if count_cookies($c) != 2;
+print "ok 17\n";
+
+# can't use a IP-address as domain
+$cookie = interact($c, "http://125.125.125.125", 'foo=bar; domain="125.125.125"');
+print "not " if count_cookies($c) != 2;
+print "ok 18\n";
+
+# illegal path (must be prefix of request path)
+$cookie = interact($c, "http://www.sol.no", 'foo=bar; domain=".sol.no"; path="/foo"');
+print "not " if count_cookies($c) != 2;
+print "ok 19\n";
+
+# legal path
+$cookie = interact($c, "http://www.sol.no/foo/bar", 'foo=bar; domain=".sol.no"; path="/foo"');
+print "not " if count_cookies($c) != 3;
+print "ok 20\n";
+
+# illegal port (request-port not in list)
+$cookie = interact($c, "http://www.sol.no", 'foo=bar; domain=".sol.no"; port="90,100"');
+print "not " if count_cookies($c) != 3;
+print "ok 21\n";
+
+# legal port
+$cookie = interact($c, "http://www.sol.no", 'foo=bar; domain=".sol.no"; port="90,100, 80,8080"; max-age=100; Comment = "Just kidding! (\"|\\\\) "');
+print "not " if count_cookies($c) != 4;
+print "ok 22\n";
+
+# port attribute without any value (current port)
+$cookie = interact($c, "http://www.sol.no", 'foo9=bar; domain=".sol.no"; port; max-age=100;');
+print "not " if count_cookies($c) != 5;
+print "ok 23\n";
+
+# encoded path
+$cookie = interact($c, "http://www.sol.no/foo/", 'foo8=bar; path="/%66oo"');
+print "not " if count_cookies($c) != 6;
+print "ok 24\n";
+
+my $file = "lwp-cookies-$$.txt";
+$c->save($file);
+$old = $c->as_string;
+undef($c);
+
+$c = HTTP::Cookies->new;
+$c->load($file);
+unlink($file) || warn "Can't unlink $file: $!";
+
+print "not " unless $old eq $c->as_string;
+print "ok 25\n";
+
+undef($c);
+
+#
+# Try some URL encodings of the PATHs
+#
+$c = HTTP::Cookies->new;
+interact($c, "http://www.acme.com/foo%2f%25/%40%40%0Anew%E5/%E5", 'foo  =   bar; version    =   1');
+print $c->as_string;
+
+$cookie = interact($c, "http://www.acme.com/foo%2f%25/@@%0anewå/æøå", "bar=baz; path=\"/foo/\"; version=1");
+print "not " unless $cookie =~ /foo=bar/ && $cookie =~ /^\$version=\"?1\"?/i;
+print "ok 26\n";
+
+$cookie = interact($c, "http://www.acme.com/foo/%25/@@%0anewå/æøå");
+print "not " if $cookie;
+print "ok 27\n";
+
+undef($c);
+
+#
+# Try to use the Netscape cookie file format for saving
+#
+$file = "cookies-$$.txt";
+$c = HTTP::Cookies::Netscape->new(file => $file);
+interact($c, "http://www.acme.com/", "foo1=bar; max-age=100");
+interact($c, "http://www.acme.com/", "foo2=bar; port=\"80\"; max-age=100; Discard; Version=1");
+interact($c, "http://www.acme.com/", "foo3=bar; secure; Version=1");
+$c->save;
+undef($c);
+
+$c = HTTP::Cookies::Netscape->new(file => $file);
+print "not " unless count_cookies($c) == 1;     # 2 of them discarded on save
+print "ok 28\n";
+
+print "not " unless $c->as_string =~ /foo1=bar/;
+print "ok 29\n";
+undef($c);
+unlink($file);
+
+
+#
+# Some additional Netscape cookies test
+#
+$c = HTTP::Cookies->new;
+$req = HTTP::Request->new(POST => "http://foo.bar.acme.com/foo");
+
+# Netscape allows a host part that contains dots
+$res = HTTP::Response->new(200, "OK");
+$res->header(set_cookie => 'Customer=WILE_E_COYOTE; domain=.acme.com');
+$res->request($req);
+$c->extract_cookies($res);
+
+# and that the domain is the same as the host without adding a leading
+# dot to the domain.  Should not quote even if strange chars are used
+# in the cookie value.
+$res = HTTP::Response->new(200, "OK");
+$res->header(set_cookie => 'PART_NUMBER=3,4; domain=foo.bar.acme.com');
+$res->request($req);
+$c->extract_cookies($res);
+
+print $c->as_string;
+
+$req = HTTP::Request->new(POST => "http://foo.bar.acme.com/foo");
+$c->add_cookie_header($req);
+#print $req->as_string;
+print "not " unless $req->header("Cookie") =~ /PART_NUMBER=3,4/ &&
+	            $req->header("Cookie") =~ /Customer=WILE_E_COYOTE/;
+print "ok 30\n";
+
+
+
+# Test handling of local intranet hostnames without a dot
+$c->clear;
+print "---\n";
+#require LWP::Debug;
+#LWP::Debug::level('+');
+
+interact($c, "http://example/", "foo1=bar; PORT; Discard;");
+$_=interact($c, "http://example/", 'foo2=bar; domain=".local"');
+print "not " unless /foo1=bar/;
+print "ok 31\n";
+
+$_=interact($c, "http://example/", 'foo3=bar');
+$_=interact($c, "http://example/");
+print "Cookie: $_\n";
+print "not " unless /foo2=bar/ && count_cookies($c) == 3;
+print "ok 32\n";
+print $c->as_string;
+
+#-------------------------------------------------------------------
+
+sub interact
+{
+    my $c = shift;
+    my $url = shift;
+    my $req = HTTP::Request->new(POST => $url);
+    $c->add_cookie_header($req);
+    my $cookie = $req->header("Cookie");
+    my $res = HTTP::Response->new(200, "OK");
+    $res->request($req);
+    for (@_) { $res->push_header("Set-Cookie2" => $_) }
+    $c->extract_cookies($res);
+    return $cookie;
+}
+
+sub count_cookies
+{
+    my $c = shift;
+    my $no = 0;
+    $c->scan(sub { $no++ });
+    $no;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/date.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/date.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/date.t	(revision 10506)
@@ -0,0 +1,165 @@
+use HTTP::Date;
+
+print "1..59\n";
+
+$no = 1;
+$| = 1;
+sub ok {
+   print "not " if $_[0];
+   print "ok $no\n";
+   $no++;
+}
+
+# test str2time for supported dates
+my(@tests) =
+(
+ 'Thu Feb  3 00:00:00 GMT 1994',        # ctime format
+ 'Thu Feb  3 00:00:00 1994',            # same as ctime, except no TZ
+
+ 'Thu, 03 Feb 1994 00:00:00 GMT',       # proposed new HTTP format
+ 'Thursday, 03-Feb-94 00:00:00 GMT',    # old rfc850 HTTP format
+ 'Thursday, 03-Feb-1994 00:00:00 GMT',  # broken rfc850 HTTP format
+
+ '03/Feb/1994:00:00:00 0000',   # common logfile format
+ '03/Feb/1994:01:00:00 +0100',  # common logfile format
+ '02/Feb/1994:23:00:00 -0100',  # common logfile format
+
+ '03 Feb 1994 00:00:00 GMT',    # HTTP format (no weekday)
+ '03-Feb-94 00:00:00 GMT',      # old rfc850 (no weekday)
+ '03-Feb-1994 00:00:00 GMT',    # broken rfc850 (no weekday)
+ '03-Feb-1994 00:00 GMT',       # broken rfc850 (no weekday, no seconds)
+ '03-Feb-1994 00:00',           # VMS dir listing format
+
+ '03-Feb-94',    # old rfc850 HTTP format    (no weekday, no time)
+ '03-Feb-1994',  # broken rfc850 HTTP format (no weekday, no time)
+ '03 Feb 1994',  # proposed new HTTP format  (no weekday, no time)
+ '03/Feb/1994',  # common logfile format     (no time, no offset)
+
+ #'Feb  3 00:00',     # Unix 'ls -l' format (can't really test it here)
+ 'Feb  3 1994',       # Unix 'ls -l' format
+
+ "02-03-94  12:00AM", # Windows 'dir' format
+
+ # ISO 8601 formats
+ '1994-02-03 00:00:00 +0000',
+ '1994-02-03',
+ '19940203',
+ '1994-02-03T00:00:00+0000',
+ '1994-02-02T23:00:00-0100',
+ '1994-02-02T23:00:00-01:00',
+ '1994-02-03T00:00:00 Z',
+ '19940203T000000Z',
+ '199402030000',
+
+ # A few tests with extra space at various places
+ '  03/Feb/1994      ',
+ '  03   Feb   1994  0:00  ',
+);
+
+my $time = 760233600;  # assume broken POSIX counting of seconds
+for (@tests) {
+    if (/GMT/i) {
+	$t = str2time($_);
+    } else {
+	$t = str2time($_, "GMT");
+    }
+    $t = "UNDEF" unless defined $t;
+    print "'$_'  =>  $t\n";
+    print $@ if $@;
+    print "not " if $t eq 'UNDEF' || $t != $time;
+    ok;
+}
+
+# test time2str
+die "time2str failed"
+    unless time2str($time) eq 'Thu, 03 Feb 1994 00:00:00 GMT';
+
+# test the 'ls -l' format with missing year$
+# round to nearest minute 3 days ago.
+$time = int((time - 3 * 24*60*60) /60)*60;
+($min, $hr, $mday, $mon) = (localtime $time)[1,2,3,4];
+$mon = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[$mon];
+$str = sprintf("$mon %02d %02d:%02d", $mday, $hr, $min);
+$t = str2time($str);
+$t = "UNDEF" unless defined $t;
+print "'$str'  =>  $t ($time)\n";
+print "not " if $t != $time;
+ok;
+
+# try some out of bounds date and some garbage.
+for ('03-Feb-1969', '03-Feb-2039',
+     undef, '', 'Garbage',
+     'Mandag 16. September 1996',
+     'Thu Feb  3 00:00:00 CET 1994',
+     'Thu, 03 Feb 1994 00:00:00 CET',
+     'Wednesday, 31-Dec-69 23:59:59 GMT',
+
+     '1980-00-01',
+     '1980-13-01',
+     '1980-01-00',
+     '1980-01-32',
+     '1980-01-01 25:00:00',
+     '1980-01-01 00:61:00',
+     '1980-01-01 00:00:61',
+    )
+{
+    my $bad = 0;
+    eval {
+	if (defined str2time $_) {
+	    print "str2time($_) is not undefined\n";
+	    $bad++;
+	}
+    };
+    print defined($_) ? "'$_'\n" : "undef\n";
+    print $@ if $@;
+    print "not " if $bad;
+    ok;
+}
+
+print "Testing AM/PM gruff...\n";
+
+$t = time2iso(str2time("11-12-96  0:00AM"));print "$t\n";
+ok($t ne "1996-11-12 00:00:00");
+
+$t = time2iso(str2time("11-12-96 12:00AM"));print "$t\n";
+ok($t ne "1996-11-12 00:00:00");
+
+$t = time2iso(str2time("11-12-96  0:00PM"));print "$t\n";
+ok($t ne "1996-11-12 12:00:00");
+
+$t = time2iso(str2time("11-12-96 12:00PM"));print "$t\n";
+ok($t ne "1996-11-12 12:00:00");
+
+
+$t = time2iso(str2time("11-12-96  1:05AM"));print "$t\n";
+ok($t ne "1996-11-12 01:05:00");
+
+$t = time2iso(str2time("11-12-96 12:05AM"));print "$t\n";
+ok($t ne "1996-11-12 00:05:00");
+
+$t = time2iso(str2time("11-12-96  1:05PM"));print "$t\n";
+ok($t ne "1996-11-12 13:05:00");
+
+$t = time2iso(str2time("11-12-96 12:05PM"));print "$t\n";
+ok($t ne "1996-11-12 12:05:00");
+
+
+
+# Test the str2iso routines
+use HTTP::Date qw(time2iso time2isoz);
+
+print "Testing time2iso functions\n";
+
+$a = time2iso;
+$b = time2iso(500000);
+print "LOCAL $a  $b\n";
+$az = time2isoz;
+$bz = time2isoz(500000);
+print "GMT   $az $bz\n";
+
+for ($a,  $b)  { ok if /^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d$/;  }
+for ($az, $bz) { ok if /^\d{4}-\d\d-\d\d \d\d:\d\d:\d\dZ$/; }
+
+
+
+print "HTTP::Date $HTTP::Date::VERSION tested ok\n";
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-auth.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-auth.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-auth.t	(revision 10506)
@@ -0,0 +1,40 @@
+print "1..4\n";
+
+use HTTP::Response;
+use HTTP::Headers::Auth;
+
+$res = HTTP::Response->new(401);
+$res->push_header(WWW_Authenticate => qq(Foo realm="WallyWorld", foo=bar, Bar realm="WallyWorld2"));
+$res->push_header(WWW_Authenticate => qq(Basic Realm="WallyWorld", foo=bar, bar=baz));
+
+print $res->as_string;
+
+%auth = $res->www_authenticate;
+
+print "not " unless keys(%auth) == 3;
+print "ok 1\n";
+
+print "not " unless $auth{basic}{realm} eq "WallyWorld" &&
+                    $auth{bar}{realm} eq "WallyWorld2";
+print "ok 2\n";
+
+$a = $res->www_authenticate;
+print "not " unless $a eq 'Foo realm="WallyWorld", foo=bar, Bar realm="WallyWorld2", Basic Realm="WallyWorld", foo=bar, bar=baz';
+print "ok 3\n";
+
+$res->www_authenticate("Basic realm=foo1");
+print $res->as_string;
+
+$res->www_authenticate(Basic => {realm => foo2});
+print $res->as_string;
+
+$res->www_authenticate(Basic => [realm => foo3, foo=>33],
+Digest => {nonce=>"bar", foo=>'foo'});
+print $res->as_string;
+
+$_ = $res->as_string;
+
+print "not " unless /WWW-Authenticate: Basic realm="foo3", foo=33/ &&
+                    /WWW-Authenticate: Digest nonce=bar, foo=foo/;
+print "ok 4\n";
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-etag.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-etag.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-etag.t	(revision 10506)
@@ -0,0 +1,28 @@
+print "1..4\n";
+
+require HTTP::Headers::ETag;
+
+$h = HTTP::Headers->new;
+$h->etag("tag1");
+print "not " unless $h->etag eq qq("tag1");
+print "ok 1\n";
+
+$h->etag("w/tag2");
+print "not " unless $h->etag eq qq(W/"tag2");
+print "ok 2\n";
+
+$h->if_match(qq(W/"foo", bar, baz), "bar");
+$h->if_none_match(333);
+
+$h->if_range("tag3");
+print "not " unless $h->if_range eq qq("tag3");
+print "ok 3\n";
+
+$t = time;
+$h->if_range($t);
+print "not " unless $h->if_range == $t;
+print "ok 4\n";
+
+
+print $h->as_string;
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-util.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-util.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers-util.t	(revision 10506)
@@ -0,0 +1,61 @@
+use strict;
+use HTTP::Headers::Util qw(split_header_words join_header_words);
+
+my $extra_tests = 2;
+
+my @s_tests = (
+
+   ["foo"                     => "foo"],
+   ["foo=bar"                 => "foo=bar"],
+   ["   foo   "               => "foo"],
+   ["foo="                    => 'foo=""'],
+   ["foo=bar bar=baz"         => "foo=bar; bar=baz"],
+   ["foo=bar;bar=baz"         => "foo=bar; bar=baz"],
+   ['foo bar baz'             => "foo; bar; baz"],
+   ['foo="\"" bar="\\\\"'     => 'foo="\""; bar="\\\\"'],
+   ['foo,,,bar'               => 'foo, bar'],
+   ['foo=bar,bar=baz'         => 'foo=bar, bar=baz'],
+
+   ['text/html; charset=iso-8859-1' =>
+    'text/html; charset="iso-8859-1"'],
+
+   ['foo="bar"; port="80,81"; discard, bar=baz' =>
+    'foo=bar; port="80,81"; discard, bar=baz'],
+
+   ['Basic realm="\"foo\\\\bar\""' =>
+    'Basic; realm="\"foo\\\\bar\""'],
+);
+
+print "1..", @s_tests + $extra_tests, "\n";
+
+my $testno = 1;
+
+print "split_header_words() tests\n";
+for (@s_tests) {
+   my($arg, $expect) = @$_;
+   my @arg = ref($arg) ? @$arg : $arg;
+
+   my $res = join_header_words(split_header_words(@arg));
+   if ($res ne $expect) {
+       print "\nUnexpected result: '$res'\n";
+       print "         Expected: '$expect'\n";
+       print "  when parsing '", join(", ", @arg), "'\n";
+       eval {
+	   require Data::Dumper;
+           my @p = split_header_words(@arg);
+           print Data::Dumper::Dumper(\@p);
+       };
+       print "not ";
+   }
+   print "ok ", $testno++, "\n";
+}
+
+
+print "Extra tests\n";
+# some extra tests
+print "not " unless join_header_words("foo" => undef, "bar" => "baz")
+                    eq "foo; bar=baz";
+print "ok ", $testno++, "\n";
+
+print "not " unless join_header_words() eq "";
+print "ok ", $testno++, "\n";
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/headers.t	(revision 10506)
@@ -0,0 +1,128 @@
+require HTTP::Headers;
+
+print "1..11\n";
+
+$h = new HTTP::Headers
+	mime_version  => "1.0",
+	content_type  => "text/html";
+
+$h->header(URI => "http://www.oslonett.no/");
+
+if ($h->header("MIME-Version") eq "1.0") {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+if ($h->header('Uri') =~ /^http:/) {
+    print "ok 2\n";
+} else {
+    print "not ok 2\n";
+}
+
+
+$h->header("MY-header" => "foo",
+	   "Date" => "somedate",
+	   "Accept" => ["text/plain", "image/*"],
+	  );
+$h->push_header("accept" => "audio/basic");
+
+if ($h->header("date") eq "somedate") {
+     print "ok 3\n";
+}
+
+@accept = $h->header("accept");
+if (@accept == 3) {
+    print "ok 4\n";
+}
+
+$h->remove_header("uri", "date");
+
+
+$str = $h->as_string;
+print "\nHeader looks like this now:\n$str\n";
+
+$lines = ($str =~ tr/\n/\n/);
+
+if ($lines == 6) {
+    print "ok 5\n";
+} else {
+    print "Header has $lines lines\n";
+    print "not ok 5\n";
+}
+
+$h2 = $h->clone;
+
+$h->header("accept", "*/*");
+$h->remove_header("my-header");
+
+@accept = $h2->header("accept");
+if (@accept == 3) {
+    print "ok 6\n";
+}
+
+@accept = $h->header("accept");
+if (@accept == 1) {
+    print "ok 7\n";
+}
+
+# Check order of headers, but first remove this one
+$h2->remove_header('mime_version');
+
+# and add this general header
+$h2->header(Connection => 'close');
+
+@x = ();
+$h2->scan(sub {push(@x, shift);});
+
+$str = join(";", @x);
+$expected = "Connection;Accept;Accept;Accept;Content-Type;MY-Header";
+
+if ($str eq $expected) {
+    print "ok 8\n";
+} else {
+    print "Headers are '$str',\nexpected    '$expected'\n";
+    print "not ok 8\n";
+}
+
+# Check headers with embedded newlines:
+
+$h = new HTTP::Headers
+	a => "foo\n\n",
+	b => "foo\nbar",
+	c => "foo\n\nbar\n\n",
+	d => "foo\n\tbar";
+$str = $h->as_string("<<\n");
+print "-----\n$str------\n";
+
+print "not " unless $str =~ /^A:\s*foo<<\n
+                              B:\s*foo<<\n
+	                        \s+bar<<\n
+                              C:\s*foo<<\n
+                                \s+bar<<\n
+	                      D:\s*foo<<\n
+                                \t bar<<\n
+                             $/x;
+print "ok 9\n";
+
+
+# Check with FALSE $HTML::Headers::TRANSLATE_UNDERSCORE
+
+local($HTTP::Headers::TRANSLATE_UNDERSCORE);
+$HTTP::Headers::TRANSLATE_UNDERSCORE = undef;  # avoid -w warning
+
+$h = HTTP::Headers->new;
+
+$h->header(abc_abc   => "foo");
+$h->header("abc-abc" => "bar");
+
+#print $h->as_string;
+
+print "not " unless $h->header("ABC_ABC") eq "foo" &&
+                    $h->header("ABC-ABC") eq "bar";
+print "ok 10\n";
+
+$h->remove_header("Abc_Abc");
+print "not " unless !defined($h->header("abc_abc")) &&
+                    $h->header("ABC-ABC") eq "bar";
+print "ok 11\n";
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/listing.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/listing.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/listing.t	(revision 10506)
@@ -0,0 +1,86 @@
+print "1..6\n";
+
+
+use File::Listing;
+
+$dir = <<'EOL';
+total 68
+drwxr-xr-x   4 aas      users        1024 Mar 16 15:47 .
+drwxr-xr-x  11 aas      users        1024 Mar 15 19:22 ..
+drwxr-xr-x   2 aas      users        1024 Mar 16 15:47 CVS
+-rw-r--r--   1 aas      users        2384 Feb 26 21:14 Debug.pm
+-rw-r--r--   1 aas      users        2145 Feb 26 20:09 IO.pm
+-rw-r--r--   1 aas      users        3960 Mar 15 18:05 MediaTypes.pm
+-rw-r--r--   1 aas      users         792 Feb 26 20:12 MemberMixin.pm
+drwxr-xr-x   3 aas      users        1024 Mar 15 18:05 Protocol
+-rw-r--r--   1 aas      users        5613 Feb 26 20:16 Protocol.pm
+-rw-r--r--   1 aas      users        5963 Feb 26 21:27 RobotUA.pm
+-rw-r--r--   1 aas      users        5071 Mar 16 12:25 Simple.pm
+-rw-r--r--   1 aas      users        8817 Mar 15 18:05 Socket.pm
+-rw-r--r--   1 aas      users        2121 Feb  5 14:22 TkIO.pm
+-rw-r--r--   1 aas      users       19628 Mar 15 18:05 UserAgent.pm
+-rw-r--r--   1 aas      users        2841 Feb  5 19:06 media.types
+
+CVS:
+total 5
+drwxr-xr-x   2 aas      users        1024 Mar 16 15:47 .
+drwxr-xr-x   4 aas      users        1024 Mar 16 15:47 ..
+-rw-r--r--   1 aas      users         545 Mar 16 15:47 Entries
+-rw-r--r--   1 aas      users          39 Mar 10 09:05 Repository
+-rw-r--r--   1 aas      users          19 Mar 10 09:05 Root
+
+Protocol:
+total 37
+drwxr-xr-x   3 aas      users        1024 Mar 15 18:05 .
+drwxr-xr-x   4 aas      users        1024 Mar 16 15:47 ..
+drwxr-xr-x   2 aas      users        1024 Mar 15 18:05 CVS
+-rw-r--r--   1 aas      users        4646 Feb 26 20:13 file.pm
+-rw-r--r--   1 aas      users       13006 Mar 15 18:05 ftp.pm
+-rw-r--r--   1 aas      users        5935 Mar  6 10:29 gopher.pm
+-rw-r--r--   1 aas      users        5453 Mar  6 10:29 http.pm
+-rw-r--r--   1 aas      users        2365 Feb 26 20:13 mailto.pm
+
+Protocol/CVS:
+total 5
+drwxr-xr-x   2 aas      users        1024 Mar 15 18:05 .
+drwxr-xr-x   3 aas      users        1024 Mar 15 18:05 ..
+-rw-r--r--   1 aas      users         238 Mar 15 18:05 Entries
+-rw-r--r--   1 aas      users          48 Mar 10 09:05 Repository
+-rw-r--r--   1 aas      users          19 Mar 10 09:05 Root
+EOL
+
+@dir = parse_dir($dir, undef, 'unix');
+
+print int(@dir) ." lines found\n";
+@dir != 25 && print "not ";
+print "ok 1\n";
+
+for (@dir) {
+   ($name, $type, $size, $mtime, $mode) = @$_;
+   $size ||= 0;  # ensure that it is defined
+   printf "%-25s $type %6d  ", $name, $size;
+   print scalar(localtime($mtime));
+   printf "  %06o", $mode;
+   print "\n";
+}
+
+# Pick out the Socket.pm line as the sample we check carefully
+($name, $type, $size, $mtime, $mode) = @{$dir[9]};
+
+$name eq "Socket.pm" || print "not ";
+print "ok 2\n";
+
+$type eq "f" || print "not ";
+print "ok 3\n";
+
+$size == 8817 || print "not ";
+print "ok 4\n";
+
+# Must be careful when checking the time stamps because we don't know
+# which year if this script lives for a long time.
+$timestring = scalar(localtime($mtime));
+$timestring =~ /Mar\s+15\s+18:05/ or print "not ";
+print "ok 5\n";
+
+$mode == 0100644 || print "not ";
+print "ok 6\n";
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/mediatypes.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/mediatypes.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/mediatypes.t	(revision 10506)
@@ -0,0 +1,87 @@
+use LWP::MediaTypes;
+
+require URI::URL;
+
+$url1 = new URI::URL 'http://www/foo/test.gif?search+x#frag';
+$url2 = new URI::URL 'http:test';
+
+$file = "/etc/passwd";
+-r $file or $file = "./README";
+
+@tests =
+(
+ ["/this.dir/file.html" => "text/html",],
+ ["test.gif.htm"        => "text/html",],
+ ["test.txt.gz"         => "text/plain", "gzip"],
+ ["gif.foo"             => "application/octet-stream",],
+ ["lwp-0.03.tar.Z"      => "application/x-tar", "compress"],
+ [$file		        => "text/plain",],
+ ["/random/file"        => "application/octet-stream",],
+ ["/dev/null"	        => "text/plain",],
+ [$url1	        	=> "image/gif",],
+ [$url2	        	=> "application/octet-stream",],
+ ["x.ppm.Z.UU"		=> "image/x-portable-pixmap","compress","x-uuencode",],
+);
+
+$notests = @tests + 3;
+print "1..$notests\n";
+
+if (-f "$ENV{HOME}/.mime.types") {
+   warn "
+The MediaTypes test might fail because you have a private ~/.mime.types file
+If you get a failed test, try to move it away while testing.
+";
+}
+
+
+$testno = 1;
+for (@tests) {
+    ($file, $expectedtype, @expectedEnc) = @$_;
+    $type1 = guess_media_type($file);
+    ($type, @enc) = guess_media_type($file);
+    if ($type1 ne $type) {
+       print "guess_media_type does not return same content-type in scalar and array conext.\n";
+	next;
+    }
+    $type = "undef" unless defined $type;
+    if ($type eq $expectedtype and "@enc" eq "@expectedEnc") {
+	print "ok $testno\n";
+    } else {
+	print "expected '$expectedtype' for '$file', got '$type'\n";
+	print "encoding: expected: '@expectedEnc', got '@enc'\n"
+	  if @expectedEnc || @enc;
+	print "nok ok $testno\n";
+    }
+    $testno++;
+}
+
+@imgSuffix = media_suffix('image/*');
+print "Image suffixes: @imgSuffix\n";
+
+print "\n";
+require HTTP::Response;
+$r = new HTTP::Response 200, "Document follows";
+$r->title("file.tar.gz.uu");
+guess_media_type($r->title, $r);
+print $r->as_string;
+
+print "not " unless $r->content_type eq "application/x-tar";
+print "ok $testno\n"; $testno++;
+
+@enc = $r->header("Content-Encoding");
+print "not " unless "@enc" eq "gzip x-uuencode";
+print "ok $testno\n"; $testno++;
+
+#
+use LWP::MediaTypes qw(add_type add_encoding);
+add_type("x-world/x-vrml", qw(wrl vrml));
+add_encoding("x-gzip" => "gz");
+add_encoding(rot13 => "r13");
+
+@x = guess_media_type("foo.vrml.r13.gz");
+#print "@x\n";
+print "not " unless "@x" eq "x-world/x-vrml rot13 x-gzip";
+print "ok $testno\n"; $testno++;
+
+#print LWP::MediaTypes::_dump();
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/message.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/message.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/message.t	(revision 10506)
@@ -0,0 +1,104 @@
+print "1..15\n";
+
+require HTTP::Request;
+require HTTP::Response;
+
+$req = new HTTP::Request 'GET', "http://www.sn.no/";
+$req->header(
+	"if-modified-since" => "Thu, 03 Feb 1994 00:00:00 GMT",
+	"mime-version"      => "1.0");
+
+$str = $req->as_string;
+
+print $str;
+
+$str =~ /^GET/m || print "not ";
+print "ok 1\n";
+
+$req->header("MIME-Version") eq "1.0" || print "not ";
+print "ok 2\n";
+
+$req->content("gisle");
+$req->add_content(" aas");
+$req->add_content(\ " old interface is depreciated");
+
+${$req->content_ref} =~ s/\s+is\s+depreciated//;
+
+print "Content is: ", $req->content, "\n";
+
+$req->content eq "gisle aas old interface" || print "not ";
+print "ok 3\n";
+
+$req->if_modified_since == 760233600 || print "not ";
+print "ok 4\n";
+
+$time = time;
+
+$req->date($time);
+$timestr = gmtime($time);
+($month) = ($timestr =~ /^\S+\s+(\S+)/);  # extract month;
+
+print "These should represent the same time:\n\t", $req->header('Date'), "\n\t$timestr\n";
+
+$req->header('Date') =~ /\Q$month/ || print "not ";
+print "ok 5\n";
+
+$req->authorization_basic("gisle", "passwd");
+$auth = $req->header("Authorization");
+
+print "$auth\n";
+$auth =~ /Z2lzbGU6cGFzc3dk/ || print "not ";
+print "ok 6\n";
+
+($user, $pass) = $req->authorization_basic;
+($user eq "gisle" && $pass eq "passwd") || print "not ";
+print "ok 7\n";
+
+# Check the response
+$res = new HTTP::Response 200, "This message";
+
+$html = $res->error_as_HTML;
+print $html;
+
+($html =~ /<head>/i && $html =~ /This message/) || print "not ";
+print "ok 8\n";
+
+$res->is_success || print "not ";
+print "ok 9\n";
+
+$res->content_type("text/html;version=3.0");
+$res->content("<html>...</html>\n");
+
+$res2 = $res->clone;
+
+print $res2->as_string;
+
+$res2->header("cOntent-TYPE") eq "text/html;version=3.0" || print "not ";
+print "ok 10\n";
+
+$res2->code == 200 || print "not ";
+print "ok 11\n";
+
+$res2->content =~ />\.\.\.</ || print "not ";
+print "ok 12\n";
+
+# Check the base method:
+
+$res = new HTTP::Response 200, "This message";
+$res->request($req);
+$res->content_type("image/gif");
+
+$res->base eq "http://www.sn.no/" || print "not ";
+print "ok 13\n";
+
+$res->header('Base', 'http://www.sn.no/xxx/');
+
+$res->base eq "http://www.sn.no/xxx/" || print "not ";
+print "ok 14\n";
+
+# Check the AUTLOAD delegate method with regular expressions
+"This string contains text/html" =~ /(\w+\/\w+)/;
+$res->content_type($1);
+
+$res->content_type eq "text/html" || print "not ";
+print "ok 15\n";
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/negotiate.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/negotiate.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/negotiate.t	(revision 10506)
@@ -0,0 +1,105 @@
+print "1..3\n";
+
+use HTTP::Request;
+use HTTP::Negotiate;
+
+
+$no = 1;
+sub ok
+{
+    print "ok " . $no++ . "\n";
+}
+
+sub not_ok
+{
+    print "not ";
+    ok;
+}
+
+
+ #  ID       QS     Content-Type             Encoding     Char-Set      Lang    Size
+ $variants =
+  [
+   ['var1',  0.950, 'text/plain',           ['uuencode',
+					     'compress'], 'iso-8859-2', 'se',    400],
+   ['var2',  1.000, 'text/html;version=2.0', 'gzip',      'iso-8859-1', 'en',   3000],
+   ['var3',  0.333, 'image/gif',            undef,        undef,        undef, 43555],
+ ];
+
+
+# First we try a request with not accept headers
+$request = new HTTP::Request 'GET', 'http://localhost/';
+@a = choose($variants, $request);
+show_res(@a);
+expect(\@a, [['var2' => 1],
+	     ['var1' => 0.95],
+	     ['var3' => 0.333]
+	    ]
+);
+
+
+$a = choose($variants, $request);
+print "The chosen one is '$a'\n";
+if ($a eq 'var2') {
+    ok;
+} else {
+    not_ok;
+}
+
+#------------------
+
+$request = new HTTP::Request 'GET', 'http://localhost/';
+$request->header('Accept', 'text/plain; q=0.55, image/gif; mbx=10000');
+$request->push_header('Accept', 'text/*; q=0.25');
+$request->header('Accept-Language', 'no, en');
+$request->header('Accept-Charset', 'iso-8859-1');
+$request->header('Accept-Encoding', 'gzip');
+
+@a = choose($variants, $request);
+show_res(@a);
+expect(\@a, [['var2' => 0.25],
+	     ['var1' => 0],
+	     ['var3' => 0]
+	    ]
+);
+
+
+
+
+#------------------
+
+sub expect
+{
+    my($res, $exp) = @_;
+    do {
+	$a = shift @$res;
+	$b = shift @$exp;
+	last if defined($a) ne defined($b);
+	if (defined($a)) {
+	    ($va, $qa) = @$a;
+	    ($vb, $qb) = @$b;
+	    if ($va ne $vb) {
+		print "$va == $vb ?\n";
+		not_ok;
+		return;
+	    }
+	    if (abs($qa - $qb) > 0.002) {
+		print "$qa ~= $qb ?\n";
+		not_ok;
+		return;
+	    }
+	}
+
+    } until (!defined($a) || !defined($b));
+    return not_ok if defined($a) ne defined($b);
+    ok;
+}
+
+sub show_res
+{
+    print "-------------\n";
+    for (@_) {
+	printf "%-6s %.3f\n", @$_;
+    }
+    print "-------------\n";
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/response.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/response.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/response.t	(revision 10506)
@@ -0,0 +1,86 @@
+
+# Test extra HTTP::Response methods.  Basic operation is tested in the
+# message.t test suite.
+
+
+print "1..7\n";
+
+
+use HTTP::Date;
+use HTTP::Request;
+use HTTP::Response;
+
+my $time = time;
+
+$req = HTTP::Request->new(GET => 'http://www.sn.no');
+$req->date($time - 30);
+
+$r = new HTTP::Response 200, "OK";
+$r->client_date($time - 20);
+$r->date($time - 25);
+$r->last_modified($time - 5000000);
+$r->request($req);
+
+print $r->as_string;
+
+$current_age = $r->current_age;
+
+if ($current_age < 35  || $current_age > 40) {
+    print "not ";
+}
+print "ok 1\n";
+
+$freshness_lifetime = $r->freshness_lifetime;
+if ($freshness_lifetime < 12 * 3600) {
+    print "not ";
+}
+print "ok 2\n";
+
+$is_fresh = $r->is_fresh;
+
+print "not " unless $is_fresh;
+print "ok 3\n";
+
+print "current_age        = $current_age\n";
+print "freshness_lifetime = $freshness_lifetime\n";
+print "response is ";
+print "not " unless $is_fresh;
+print "fresh\n";
+
+
+print "it will be fresh is ";
+print $freshness_lifetime - $current_age;
+print " more seconds\n";
+
+# OK, now we add an Expires header
+$r->expires($time);
+print $r->as_string;
+
+$freshness_lifetime = $r->freshness_lifetime;
+print "freshness_lifetime = $freshness_lifetime\n";
+print "not " unless $freshness_lifetime == 25;
+print "ok 4\n";
+$r->remove_header('expires');
+
+# Now we try the 'Age' header and the Cache-Contol:
+
+$r->header('Age', 300);
+$r->push_header('Cache-Control', 'junk');
+$r->push_header(Cache_Control => 'max-age = 10');
+
+print $r->as_string;
+
+$current_age = $r->current_age;
+$freshness_lifetime = $r->freshness_lifetime;
+
+print "current_age        = $current_age\n";
+print "freshness_lifetime = $freshness_lifetime\n";
+
+print "not " if $current_age < 300;
+print "ok 5\n";
+
+print "not " if $freshness_lifetime != 10;
+print "ok 6\n";
+
+print "not " unless $r->fresh_until;  # should return something
+print "ok 7\n";
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/status.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/status.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/base/status.t	(revision 10506)
@@ -0,0 +1,32 @@
+use HTTP::Status;
+
+print "1..8\n";
+
+200 == RC_OK || print "not ";
+print "ok 1\n";
+
+is_success(RC_ACCEPTED) || print "not ";
+print "ok 2\n";
+
+is_error(RC_BAD_REQUEST) || print "not ";
+print "ok 3\n";
+
+is_redirect(RC_MOVED_PERMANENTLY) || print "not ";
+print "ok 4\n";
+
+is_success(RC_NOT_FOUND) && print "not ";
+print "ok 5\n";
+
+$mess = status_message(0);
+
+defined $mess && print "not ";
+print "ok 6\n";
+
+$mess = status_message(200);
+
+if ($mess =~ /ok/i) {
+    print "ok 7\n";
+}
+
+is_info(RC_CONTINUE) || print "not ";
+print "ok 8\n";
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/autoload.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/autoload.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/autoload.t	(revision 10506)
@@ -0,0 +1,30 @@
+#
+# See if autoloading of protocol schemes work
+#
+
+print "1..1\n";
+
+require LWP::UserAgent;
+# note no LWP::Protocol::file;
+
+# localhost will not work on win32 (when networking is disabled)
+$url = $^O eq 'MSWin32' ? 'file:.' : 'file://localhost/';
+
+print "Trying to fetch " . (new URI::URL $url)->local_path . " ...\n";
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+$ua->timeout(30);               # timeout in seconds
+#$ua->use_alarm(0);               # don't use alarms
+#$ua->use_eval(0);                # don't eval, just die when thing go wrong
+				# (easier to read while debugging)
+
+my $request = new HTTP::Request('GET', $url);
+
+my $response = $ua->request($request, undef, undef);
+if ($response->is_success) {
+    print "ok 1\n";
+} else {
+    print $response->error_as_HTML;
+    print "not ok 1\n";
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/get.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/get.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/get.t	(revision 10506)
@@ -0,0 +1,85 @@
+#
+# Test retrieving a file with a 'file://' URL,
+#
+
+# First locate some suitable tmp-dir.  We need an absolute path.
+$TMPDIR = undef;
+for ("/tmp/", "/var/tmp", "/usr/tmp", "/local/tmp") {
+    if (open(TEST, ">$_/test-$$")) {
+        close(TEST);
+	unlink("$_/test-$$");
+	$TMPDIR = $_;
+	last;
+    }
+}
+$TMPDIR ||= $ENV{TEMP} if $^O eq 'MSWin32';
+unless ($TMPDIR) {
+   # Can't run any tests
+   print "1..0\n";
+   print "ok 1\n";
+   exit;
+}
+$TMPDIR =~ tr|\\|/|;
+print "1..2\n";
+
+use LWP::Simple;
+require LWP::Protocol::file;
+
+my $orig = "$TMPDIR/lwp-orig-$$";          # local file
+my $copy = "$TMPDIR/lwp-copy-$$"; 	    # downloaded copy
+
+# First we create the original
+open(OUT, ">$orig") or die "Cannot open $orig: $!";
+for (1..100) {
+    print OUT "This is line $_ of $orig\n";
+}
+close(OUT);
+
+
+# Then we make a test using getprint(), so we need to capture stdout
+open (OUT, ">$copy") or die "Cannot open $copy: $!";
+select(OUT);
+
+# do the retrieval
+getprint("file://localhost" . ($orig =~ m|^/| ? $orig : "/$orig"));
+
+close(OUT);
+select(STDOUT);
+
+# read and compare the files
+open(IN, $orig) or die "Cannot open '$orig': $!";
+undef($/);
+$origtext = <IN>;
+close(IN);
+open(IN, $copy) or die "Cannot open '$copy': $!";
+undef($/);
+$copytext = <IN>;
+close(IN);
+
+unlink($copy);
+
+if ($origtext eq $copytext) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+
+# Test getstore() function
+
+getstore("file:$orig", $copy);
+
+# Take a look at the new copy
+open(IN, $copy) or die "Cannot open '$copy': $!";
+undef($/);
+$copytext = <IN>;
+close(IN);
+
+unlink($orig);
+unlink($copy);
+
+if ($origtext eq $copytext) {
+    print "ok 2\n";
+} else {
+    print "not ok 2\n";
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/http.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/http.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/http.t	(revision 10506)
@@ -0,0 +1,319 @@
+$| = 1; # autoflush
+
+require IO::Socket;  # make sure this work before we try to make a HTTP::Daemon
+
+# First we make ourself a daemon in another process
+my $D = shift || '';
+if ($D eq 'daemon') {
+
+    require HTTP::Daemon;
+
+    my $d = new HTTP::Daemon Timeout => 10;
+
+    print "Please to meet you at: <URL:", $d->url, ">\n";
+    open(STDOUT, ">/dev/null");
+
+    while ($c = $d->accept) {
+	$r = $c->get_request;
+	if ($r) {
+	    my $p = ($r->url->path_components)[1];
+	    my $func = lc("httpd_" . $r->method . "_$p");
+	    if (defined &$func) {
+		&$func($c, $r);
+	    } else {
+		$c->send_error(404);
+	    }
+	}
+	$c = undef;  # close connection
+    }
+    print STDERR "HTTP Server terminated\n";
+    exit;
+}
+else {
+    use Config;
+    open(DAEMON, "$Config{'perlpath'} local/http.t daemon |") or die "Can't exec daemon: $!";
+}
+
+print "1..18\n";
+
+
+my $greeting = <DAEMON>;
+$greeting =~ /(<[^>]+>)/;
+
+require URI::URL;
+URI::URL->import;
+my $base = new URI::URL $1;
+
+print "Will access HTTP server at $base\n";
+
+require LWP::UserAgent;
+require HTTP::Request;
+$ua = new LWP::UserAgent;
+$ua->agent("Mozilla/0.01 " . $ua->agent);
+$ua->from('gisle@aas.no');
+
+#----------------------------------------------------------------
+print "Bad request...\n";
+$req = new HTTP::Request GET => url("/not_found", $base);
+$req->header(X_Foo => "Bar");
+$res = $ua->request($req);
+
+print "not " unless $res->is_error
+                and $res->code == 404
+                and $res->message =~ /not\s+found/i;
+print "ok 1\n";
+# we also expect a few headers
+print "not " if !$res->server and !$res->date;
+print "ok 2\n";
+
+#----------------------------------------------------------------
+print "Simple echo...\n";
+sub httpd_get_echo
+{
+    my($c, $req) = @_;
+    $c->send_basic_header(200);
+    print $c "Content-Type: text/plain\015\012";
+    $c->send_crlf;
+    print $c $req->as_string;
+}
+
+$req = new HTTP::Request GET => url("/echo/path_info?query", $base);
+$req->push_header(Accept => 'text/html');
+$req->push_header(Accept => 'text/plain; q=0.9');
+$req->push_header(Accept => 'image/*');
+$req->if_modified_since(time - 300);
+$req->header(Long_text => 'This is a very long header line
+which is broken between
+more than one line.');
+$req->header(X_Foo => "Bar");
+
+$res = $ua->request($req);
+#print $res->as_string;
+
+print "not " unless $res->is_success
+               and  $res->code == 200 && $res->message eq "OK";
+print "ok 3\n";
+
+$_ = $res->content;
+@accept = /^Accept:\s*(.*)/mg;
+
+print "not " unless /^From:\s*gisle\@aas\.no$/m
+                and /^Host:/m
+                and @accept == 3
+	        and /^Accept:\s*text\/html/m
+	        and /^Accept:\s*text\/plain/m
+	        and /^Accept:\s*image\/\*/m
+		and /^If-Modified-Since:\s*\w{3},\s+\d+/m
+                and /^Long-Text:\s*This.*broken between/m
+		and /^X-Foo:\s*Bar$/m
+		and /^User-Agent:\s*Mozilla\/0.01/m;
+print "ok 4\n";
+
+#----------------------------------------------------------------
+print "Send file...\n";
+
+my $file = "test-$$.html";
+open(FILE, ">$file") or die "Can't create $file: $!";
+binmode FILE or die "Can't binmode $file: $!";
+print FILE <<EOT;
+<html><title>En prøve</title>
+<h1>Dette er en testfil</h1>
+Jeg vet ikke hvor stor fila behøver å være heller, men dette
+er sikkert nok i massevis.
+EOT
+close(FILE);
+
+sub httpd_get_file
+{
+    my($c, $r) = @_;
+    my %form = $r->url->query_form;
+    my $file = $form{'name'};
+    $c->send_file_response($file);
+    unlink($file);
+}
+
+$req = new HTTP::Request GET => url("/file?name=$file", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+
+print "not " unless $res->is_success
+                and $res->content_type eq 'text/html'
+		and $res->content_length == 147
+		and $res->title eq 'En prøve'
+		and $res->content =~ /å være/;
+print "ok 5\n";		
+
+
+# A second try on the same file, should fail because we unlink it
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->is_error
+                and $res->code == 404;   # not found
+print "ok 6\n";
+		
+# Then try to list current directory
+$req = new HTTP::Request GET => url("/file?name=.", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->code == 501;   # NYI
+print "ok 7\n";
+
+
+#----------------------------------------------------------------
+print "Check redirect...\n";
+sub httpd_get_redirect
+{
+   my($c) = @_;
+   $c->send_redirect("/echo/redirect");
+}
+
+$req = new HTTP::Request GET => url("/redirect/foo", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+
+print "not " unless $res->is_success
+                and $res->content =~ m|/echo/redirect|;
+print "ok 8\n";
+print "not " unless $res->previous->is_redirect
+                and $res->previous->code == 301;
+print "ok 9\n";
+
+# Let's test a redirect loop too
+sub httpd_get_redirect2 { shift->send_redirect("/redirect3/") }
+sub httpd_get_redirect3 { shift->send_redirect("/redirect4/") }
+sub httpd_get_redirect4 { shift->send_redirect("/redirect5/") }
+sub httpd_get_redirect5 { shift->send_redirect("/redirect6/") }
+sub httpd_get_redirect6 { shift->send_redirect("/redirect2/") }
+
+$req->url(url("/redirect2", $base));
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->is_redirect
+                and $res->header("Client-Warning") =~ /loop detected/i;
+print "ok 10\n";
+$i = 1;
+while ($res->previous) {
+   $i++;
+   $res = $res->previous;
+}
+print "not " unless $i == 6;
+print "ok 11\n";
+
+#----------------------------------------------------------------
+print "Check basic authorization...\n";
+sub httpd_get_basic
+{
+    my($c, $r) = @_;
+    #print STDERR $r->as_string;
+    my($u,$p) = $r->authorization_basic;
+    if (defined($u) && $u eq 'ok 12' && $p eq 'xyzzy') {
+        $c->send_basic_header(200);
+	print $c "Content-Type: text/plain";
+	$c->send_crlf;
+	$c->send_crlf;
+	$c->print("$u\n");
+    } else {
+        $c->send_basic_header(401);
+	$c->print("WWW-Authenticate: Basic realm=\"libwww-perl\"\015\012");
+	$c->send_crlf;
+    }
+}
+
+{
+   package MyUA; @ISA=qw(LWP::UserAgent);
+   sub get_basic_credentials {
+      my($self, $realm, $uri, $proxy) = @_;
+      my $x =  $uri->rel($base);
+      if ($realm eq "libwww-perl" && $uri->rel($base) eq "basic") {
+	  return ("ok 12", "xyzzy");
+      } else {
+          return undef;
+      }
+   }
+}
+$req = new HTTP::Request GET => url("/basic", $base);
+$res = MyUA->new->request($req);
+#print $res->as_string;
+
+print "not " unless $res->is_success;
+print $res->content;
+
+# Let's try with a $ua that does not pass out credentials
+$res = $ua->request($req);
+print "not " unless $res->code == 401;
+print "ok 13\n";
+
+# Let's try to set credentials for this realm
+$ua->credentials($req->url->netloc, "libwww-perl", "ok 12", "xyzzy");
+$res = $ua->request($req);
+print "not " unless $res->is_success;
+print "ok 14\n";
+
+# Then illegal credentials
+$ua->credentials($req->url->netloc, "libwww-perl", "user", "passwd");
+$res = $ua->request($req);
+print "not " unless $res->code == 401;
+print "ok 15\n";
+
+
+#----------------------------------------------------------------
+print "Check proxy...\n";
+sub httpd_get_proxy
+{
+   my($c,$r) = @_;
+   if ($r->method eq "GET" and
+       $r->url->scheme eq "ftp") {
+       $c->send_basic_header(200);
+       $c->send_crlf;
+   } else {
+       $c->send_error;
+   }
+}
+
+$ua->proxy(ftp => $base);
+$req = new HTTP::Request GET => "ftp://ftp.perl.com/proxy";
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->is_success;
+print "ok 16\n";
+
+#----------------------------------------------------------------
+print "Check POSTing...\n";
+sub httpd_post_echo
+{
+   my($c,$r) = @_;
+   $c->send_basic_header;
+   $c->print("Content-Type: text/plain");
+   $c->send_crlf;
+   $c->send_crlf;
+   $c->print($r->as_string);
+}
+
+$req = new HTTP::Request POST => url("/echo/foo", $base);
+$req->content_type("application/x-www-form-urlencoded");
+$req->content("foo=bar&bar=test");
+$res = $ua->request($req);
+#print $res->as_string;
+
+$_ = $res->content;
+print "not " unless $res->is_success
+                and /^Content-Length:\s*16$/mi
+		and /^Content-Type:\s*application\/x-www-form-urlencoded$/mi
+		and /^foo=bar&bar=test/m;
+print "ok 17\n";		
+
+#----------------------------------------------------------------
+print "Terminating server...\n";
+sub httpd_get_quit
+{
+    my($c) = @_;
+    $c->send_error(503, "Bye, bye");
+    exit;  # terminate HTTP server
+}
+
+$req = new HTTP::Request GET => url("/quit", $base);
+$res = $ua->request($req);
+
+print "not " unless $res->code == 503 and $res->content =~ /Bye, bye/;
+print "ok 18\n";
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/protosub.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/protosub.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/local/protosub.t	(revision 10506)
@@ -0,0 +1,73 @@
+#!perl
+
+print "1..6\n";
+
+# This test tries to make a custom protocol implementation by
+# subclassing of LWP::Protocol.
+
+
+use LWP::UserAgent ();
+use LWP::Protocol ();
+
+LWP::Protocol::implementor(http => 'myhttp');
+
+$ua = LWP::UserAgent->new;
+$ua->proxy('ftp' => "http://www.sn.no/");
+
+$req = HTTP::Request->new(GET => 'ftp://foo/');
+$req->header(Cookie => "perl=cool");
+
+$res = $ua->request($req);
+
+print $res->as_string;
+
+print "not " unless $res->code == 200;
+print "ok 5\n";
+print "not " unless $res->content eq "Howdy\n";
+print "ok 6\n";
+exit;
+
+
+#----------------------------------
+package myhttp;
+
+BEGIN {
+   @ISA=qw(LWP::Protocol);
+}
+
+sub new
+{
+    my $class = shift;
+    print "CTOR: $class->new(@_)\n";
+    my($prot) = @_;
+    print "not " unless $prot eq "http";
+    print "ok 1\n";
+    my $self = $class->SUPER::new(@_);
+    for (keys %$self) {
+	print "$_: $self->{$_}\n";
+    }
+    $self;
+}
+
+sub request
+{
+    my $self = shift;
+    print "REQUEST: $self->request(",
+       join(",", (map defined($_)? $_ : "UNDEF", @_)), ")\n";
+
+    my($request, $proxy, $arg, $size, $timeout) = @_;
+    print $request->as_string;
+
+    print "not " unless $proxy eq "http://www.sn.no/";
+    print "ok 2\n";
+    print "not " unless $request->url eq "ftp://foo/";
+    print "ok 3\n";
+    print "not " unless $request->header("cookie") eq "perl=cool";
+    print "ok 4\n";
+
+    my $res = HTTP::Response->new(200 => "OK");
+    $res->content_type("text/plain");
+    $res->date(time);
+    $self->collect_once($arg, $res, "Howdy\n");
+    $res;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/moved
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/moved	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/moved	(revision 10506)
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+echo "Location: http://$SERVER_NAME:$SERVER_PORT/"
+echo
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/nph-slowdata
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/nph-slowdata	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/nph-slowdata	(revision 10506)
@@ -0,0 +1,26 @@
+#!/usr/local/bin/perl
+
+# This script outputs some data slowly. It can be used to check that
+# pipelined processing of response content really works.  We use syswrite
+# so that the script will notice when the connection is broken.
+
+out("HTTP/1.0 200 OK\r
+Content-Type: text/plain\r
+\r
+");
+
+for (1..5) {
+    out("The number is now $_\n");
+    sleep(1);
+}
+exit;
+
+
+sub out
+{
+    my $data = shift;
+    my $l = length $data;
+    if (syswrite(STDOUT, $data, $l) != $l) {
+	exit 1;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/slowread
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/slowread	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/slowread	(revision 10506)
@@ -0,0 +1,31 @@
+#!/usr/local/bin/perl
+
+# You might post large amount of data to this script.  It will read
+# it slowly.
+
+{ local($!) = 1; print "Content-Type: text/plain\n\n"; }
+
+$len = $ENV{CONTENT_LENGTH};
+
+unless ($len) {
+    system "env";
+    exit;
+}
+
+$size = 20;  # chunk size
+
+$content = '';
+$bytes = 0;
+
+sleep(1);
+while ($len > 0) {
+    $n = sysread(STDIN, $b, $size);
+    last if $n <= 0;
+    $len -= $n;
+    $bytes += $n;
+    $content .= $b;
+    sleep(1);
+}
+print "$bytes bytes read\n";
+
+	
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/test
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/test	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/test	(revision 10506)
@@ -0,0 +1,28 @@
+#!/usr/local/bin/perl
+
+$| = 1;
+print "Content-type: text/plain
+
+";
+
+if (@ARGV) {
+    print "ARGS: ";
+    print join(", ", map { $_ = qq{"$_"} } @ARGV);
+    print "\n\n";
+} else {
+    print "No command line arguments passed to script\n\n";
+}
+
+while (($key,$val) = each %ENV) {
+   print "$key=$val\n";
+}
+
+if ($ENV{CONTENT_LENGTH}) {
+    $len = $ENV{CONTENT_LENGTH};
+    while ($len) {
+	$n = sysread(STDIN, $content, $len, length $content);
+	last unless defined $n;
+	$len -= $n;
+    }
+    print "\nContent\n-------\n$content";
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/timeout
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/timeout	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/cgi-bin/timeout	(revision 10506)
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+sleep 20;
+
+echo "Content-type: text/plain"
+echo
+echo "Test"
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/config.pl.dist
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/config.pl.dist	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/config.pl.dist	(revision 10506)
@@ -0,0 +1,10 @@
+package net;
+
+# Configure these for you local system
+$httpserver  = "localhost:80";
+$cgidir      = "/cgi-bin/lwp";
+
+# Used for proxy test
+$ftp_proxy = "http://localhost/";
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-get.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-get.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-get.t	(revision 10506)
@@ -0,0 +1,43 @@
+#!/usr/local/bin/perl -w
+#
+# Check GET via HTTP.
+#
+
+print "1..2\n";
+
+require "net/config.pl";
+require LWP::Protocol::http;
+require LWP::UserAgent;
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+$netloc = $net::httpserver;
+$script = $net::cgidir . "/test";
+
+$url = new URI::URL("http://$netloc$script?query");
+
+my $request = new HTTP::Request('GET', $url);
+
+print "GET $url\n\n";
+
+my $response = $ua->request($request, undef, undef);
+
+my $str = $response->as_string;
+
+print "$str\n";
+
+if ($response->is_success and $str =~ /^REQUEST_METHOD=GET$/m) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+if ($str =~ /^QUERY_STRING=query$/m) {
+    print "ok 2\n";
+} else {
+    print "not ok 2\n";
+}
+
+# avoid -w warning
+$dummy = $net::httpserver;
+$dummy = $net::cgidir;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-post.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-post.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-post.t	(revision 10506)
@@ -0,0 +1,44 @@
+#!/usr/local/bin/perl -w
+#
+# Check POST via HTTP.
+#
+
+print "1..2\n";
+
+require "net/config.pl";
+require LWP::Protocol::http;
+require LWP::UserAgent;
+
+$netloc = $net::httpserver;
+$script = $net::cgidir . "/test";
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+$url = new URI::URL("http://$netloc$script");
+
+my $form = 'searchtype=Substring';
+
+my $request = new HTTP::Request('POST', $url, undef, $form);
+$request->header('Content-Type', 'application/x-www-form-urlencoded');
+
+my $response = $ua->request($request, undef, undef);
+
+my $str = $response->as_string;
+
+print "$str\n";
+
+if ($response->is_success and $str =~ /^REQUEST_METHOD=POST$/m) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+if ($str =~ /^CONTENT_LENGTH=(\d+)$/m && $1 == length($form)) {
+    print "ok 2\n";
+} else {
+    print "not ok 2\n";
+}
+
+# avoid -w warning
+$dummy = $net::httpserver;
+$dummy = $net::cgidir;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-timeout.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-timeout.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/http-timeout.t	(revision 10506)
@@ -0,0 +1,41 @@
+#
+# Check timeouts via HTTP.
+#
+
+print "1..1\n";
+
+require "net/config.pl";
+require HTTP::Status;
+require LWP::Protocol::http;
+require LWP::UserAgent;
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+$ua->timeout(4);
+
+$netloc = $net::httpserver;
+$script = $net::cgidir . "/timeout";
+
+$url = new URI::URL("http://$netloc$script");
+
+my $request = new HTTP::Request('GET', $url);
+
+print $request->as_string;
+
+my $response = $ua->request($request, undef);
+
+my $str = $response->as_string;
+
+print "$str\n";
+
+if ($response->is_error and
+    $str =~ /timeout/) {
+    print "ok 1\n";
+}
+else {
+    print "nok ok 1\n";
+}
+
+# avoid -w warning
+$dummy = $net::httpserver;
+$dummy = $net::cgidir;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/mirror.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/mirror.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/mirror.t	(revision 10506)
@@ -0,0 +1,34 @@
+#
+# Test mirroring a file
+#
+
+require "net/config.pl";
+require LWP::Protocol::http;
+require LWP::UserAgent;
+require HTTP::Status;
+
+print "1..2\n";
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+my $url = "http://$net::httpserver/";
+my $copy = "lwp-test-$$"; # downloaded copy
+
+my $response = $ua->mirror($url, $copy);
+
+if ($response->code == &HTTP::Status::RC_OK) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+# OK, so now do it again, should get Not-Modified
+$response = $ua->mirror($url, $copy);
+if ($response->code == &HTTP::Status::RC_NOT_MODIFIED) {
+    print "ok 2\n";
+} else {
+    print "nok ok 2\n";
+}
+unlink($copy);
+
+$net::httpserver = $net::httpserver;  # avoid -w warning
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/moved.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/moved.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/moved.t	(revision 10506)
@@ -0,0 +1,34 @@
+#!/usr/local/bin/perl -w
+#
+
+print "1..1\n";
+
+require "net/config.pl";
+require LWP::Debug;
+require LWP::UserAgent;
+
+$url = "http://$net::httpserver$net::cgidir/moved";
+
+#LWP::Debug::level('+trace');
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+$ua->timeout(30);               # timeout in seconds
+
+my $request = new HTTP::Request('GET', $url);
+
+print $request->as_string;
+
+my $response = $ua->request($request, undef, undef);
+
+print $response->as_string, "\n";
+
+if ($response->is_success) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
+
+
+# avoid -w warning
+$dummy = $net::httpserver;
+$dummy = $net::cgidir;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/proxy.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/proxy.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/net/proxy.t	(revision 10506)
@@ -0,0 +1,36 @@
+#!/usr/local/bin/perl -w
+#
+# Test retrieving a file with a 'ftp://' URL,
+# via a HTTP proxy.
+#
+
+print "1..1\n";
+
+require "net/config.pl";
+unless (defined $net::ftp_proxy) {
+    print "not ok 1\n";
+    exit 0;
+}
+
+require LWP::Debug;
+require LWP::UserAgent;
+
+#LWP::Debug::level('+');
+
+my $ua = new LWP::UserAgent;    # create a useragent to test
+
+$ua->proxy('ftp', $net::ftp_proxy);
+
+my $url = new URI::URL('ftp://ftp.uninett.no/');
+
+my $request = new HTTP::Request('GET', $url);
+
+my $response = $ua->request($request, undef, undef);
+
+my $str = $response->as_string;
+
+if ($response->is_success) {
+    print "ok 1\n";
+} else {
+    print "not ok 1\n";
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules-dbm.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules-dbm.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules-dbm.t	(revision 10506)
@@ -0,0 +1,128 @@
+
+print "1..13\n";
+
+
+use WWW::RobotRules::AnyDBM_File;
+
+$file = "test-$$";
+
+$r = new WWW::RobotRules::AnyDBM_File "myrobot/2.0", $file;
+
+$r->parse("http://www.aas.no/robots.txt", "");
+
+$r->visit("www.aas.no");
+
+print "not " if $r->no_visits("www.aas.no") != 1;
+print "ok 1\n";
+
+
+$r->push_rules("www.sn.no", "/aas", "/per");
+$r->push_rules("www.sn.no", "/god", "/old");
+
+@r = $r->rules("www.sn.no");
+print "Rules: @r\n";
+
+print "not " if "@r" ne "/aas /per /god /old";
+print "ok 2\n";
+
+$r->clear_rules("per");
+$r->clear_rules("www.sn.no");
+
+@r = $r->rules("www.sn.no");
+print "Rules: @r\n";
+
+print "not " if "@r" ne "";
+print "ok 3\n";
+
+$r->visit("www.aas.no", time+10);
+$r->visit("www.sn.no");
+
+print "No visits: ", $r->no_visits("www.aas.no"), "\n";
+print "Last visit: ", $r->last_visit("www.aas.no"), "\n";
+print "Fresh until: ", $r->fresh_until("www.aas.no"), "\n";
+
+print "not " if $r->no_visits("www.aas.no") != 2;
+print "ok 4\n";
+
+print "not " if abs($r->last_visit("www.sn.no") - time) > 2;
+print "ok 5\n";
+
+$r = undef;
+
+# Try to reopen the database without a name specified
+$r = new WWW::RobotRules::AnyDBM_File undef, $file;
+$r->visit("www.aas.no");
+
+print "not " if $r->no_visits("www.aas.no") != 3;
+print "ok 6\n";
+
+print "Agent-Name: ", $r->agent, "\n";
+print "not " if $r->agent ne "myrobot";
+print "ok 7\n";
+
+$r = undef;
+
+print "*** Dump of database ***\n";
+tie(%cat, AnyDBM_File, $file, 0, 0644) or die "Can't tie: $!";
+while (($key,$val) = each(%cat)) {
+    print "$key\t$val\n";
+}
+print "******\n";
+
+untie %cat;
+
+# Try to open database with a different agent name
+$r = new WWW::RobotRules::AnyDBM_File "MOMSpider/2.0", $file;
+
+print "not " if $r->no_visits("www.sn.no");
+print "ok 8\n";
+
+# Try parsing
+$r->parse("http://www.sn.no:8080/robots.txt", <<EOT, (time + 3));
+
+User-Agent: *
+Disallow: /
+
+User-Agent: Momspider
+Disallow: /foo
+Disallow: /bar
+
+EOT
+
+@r = $r->rules("www.sn.no:8080");
+print "not " if "@r" ne "/foo /bar";
+print "ok 9\n";
+
+print "not " if $r->allowed("http://www.sn.no") >= 0;
+print "ok 10\n";
+
+print "not " if $r->allowed("http://www.sn.no:8080/foo/gisle");
+print "ok 11\n";
+
+sleep(5);  # wait until file has expired
+print "not " if $r->allowed("http://www.sn.no:8080/foo/gisle") >= 0;
+print "ok 12\n";
+
+
+$r = undef;
+
+print "*** Dump of database ***\n";
+tie(%cat, AnyDBM_File, $file, 0, 0644) or die "Can't tie: $!";
+while (($key,$val) = each(%cat)) {
+    print "$key\t$val\n";
+}
+print "******\n";
+
+untie %cat;			# Otherwise the next line fails on DOSish
+
+unlink "$file", "$file.pag", "$file.dir", "$file.db";
+
+# Try open a an emty database without specifying a name
+eval { 
+   $r = new WWW::RobotRules::AnyDBM_File undef, $file;
+};
+print $@;
+print "not " unless $@;  # should fail
+print "ok 13\n";
+
+unlink "$file", "$file.pag", "$file.dir", "$file.db";
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/rules.t	(revision 10506)
@@ -0,0 +1,138 @@
+#!/local/bin/perl
+
+=head1 NAME
+
+robot-rules.t
+
+=head1 DESCRIPTION
+
+Test a number of different A</robots.txt> files against a number
+of different User-agents.
+
+=cut
+
+require WWW::RobotRules;
+use Carp;
+use strict;
+
+print "1..26\n"; # for Test::Harness
+
+# We test a number of different /robots.txt files,
+#
+
+my $content1 = <<EOM;
+# http://foo/robots.txt
+User-agent: *
+Disallow: /private
+Disallow: http://foo/also_private
+
+User-agent: MOMspider
+Disallow:
+EOM
+
+my $content2 = <<EOM;
+# http://foo/robots.txt
+User-agent: MOMspider
+ # comment which should be ignored
+Disallow: /private
+EOM
+
+my $content3 = <<EOM;
+# http://foo/robots.txt
+EOM
+
+my $content4 = <<EOM;
+# http://foo/robots.txt
+User-agent: *
+Disallow: /private
+
+User-agent: MOMspider
+Disallow: /this
+
+User-agent: Another
+Disallow: /that
+EOM
+
+# and a number of different robots:
+
+my @tests1 = (
+	   [$content1, 'MOMspider' =>
+	    1 => 'http://foo/private' => 1,
+	    2 => 'http://foo/also_private' => 1,
+	   ],
+
+	   [$content1, 'Wubble' =>
+	    3 => 'http://foo/private' => 0,
+	    4 => 'http://foo/also_private' => 0,
+	    5 => 'http://foo/other' => 1,
+	   ],
+
+	   [$content2, 'MOMspider' =>
+	    6 => 'http://foo/private' => 0,
+	    7 => 'http://foo/other' => 1,
+	   ],
+
+	   [$content2, 'Wubble' =>
+	    8  => 'http://foo/private' => 1,
+	    9  => 'http://foo/also_private' => 1,
+	    10 => 'http://foo/other' => 1,
+	   ],
+
+	   [$content3, 'MOMspider' =>
+	    11 => 'http://foo/private' => 1,
+	    12 => 'http://foo/other' => 1,
+	   ],
+
+	   [$content3, 'Wubble' =>
+	    13 => 'http://foo/private' => 1,
+	    14 => 'http://foo/other' => 1,
+	   ],
+
+	   [$content4, 'MOMspider' =>
+	    15 => 'http://foo/private' => 1,
+	    16 => 'http://foo/this' => 0,
+	    17 => 'http://foo/that' => 1,
+	   ],
+
+	   [$content4, 'Another' =>
+	    18 => 'http://foo/private' => 1,
+	    19 => 'http://foo/this' => 1,
+	    20 => 'http://foo/that' => 0,
+	   ],
+
+	   [$content4, 'Wubble' =>
+	    21 => 'http://foo/private' => 0,
+	    22 => 'http://foo/this' => 1,
+	    23 => 'http://foo/that' => 1,
+	   ],
+
+	   [$content4, 'Another/1.0' =>
+	    24 => 'http://foo/private' => 1,
+	    25 => 'http://foo/this' => 1,
+	    26 => 'http://foo/that' => 0,
+	   ],
+
+	   # when adding tests, remember to increase
+	   # the maximum at the top
+
+	  );
+
+my $t;
+
+for $t (@tests1) {
+    my ($content, $ua) = splice(@$t, 0, 2);
+
+    my $robotsrules = new WWW::RobotRules($ua);
+    $robotsrules->parse('http://foo/robots.txt', $content);
+
+    my ($num, $path, $expected);
+    while(($num, $path, $expected) = splice(@$t, 0, 3)) {
+	my $allowed = $robotsrules->allowed($path);
+	$allowed = 1 if $allowed;
+	if($allowed != $expected) {
+	    $robotsrules->dump;
+	    confess "Test Failed: $ua => $path ($allowed != $expected)";
+	}
+	print "ok $num\n";
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/ua.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/ua.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/robot/ua.t	(revision 10506)
@@ -0,0 +1,135 @@
+$| = 1; # autoflush
+
+require IO::Socket;  # make sure this work before we try to make a HTTP::Daemon
+
+# First we make ourself a daemon in another process
+my $D = shift || '';
+if ($D eq 'daemon') {
+
+    require HTTP::Daemon;
+
+    my $d = new HTTP::Daemon Timeout => 10;
+
+    print "Please to meet you at: <URL:", $d->url, ">\n";
+    open(STDOUT, $^O eq 'MSWin32' ? ">nul" : ">/dev/null");
+
+    while ($c = $d->accept) {
+	$r = $c->get_request;
+	if ($r) {
+	    my $p = ($r->url->path_components)[1];
+	    $p =~ s/\W//g;
+	    my $func = lc("httpd_" . $r->method . "_$p");
+	    #print STDERR "Calling $func...\n";
+            if (defined &$func) {
+		&$func($c, $r);
+	    } else {
+		$c->send_error(404);
+	    }
+	}
+	$c = undef;  # close connection
+    }
+    print STDERR "HTTP Server terminated\n";
+    exit;
+}
+else {
+    use Config;
+    open(DAEMON , "$Config{'perlpath'} robot/ua.t daemon |") or die "Can't exec daemon: $!";
+}
+
+print "1..7\n";
+
+
+$greating = <DAEMON>;
+$greating =~ /(<[^>]+>)/;
+
+require URI::URL;
+URI::URL->import;
+my $base = new URI::URL $1;
+
+print "Will access HTTP server at $base\n";
+
+require LWP::RobotUA;
+require HTTP::Request;
+$ua = new LWP::RobotUA 'lwp-spider/0.1', 'gisle@aas.no';
+$ua->delay(0.05);  # rather quick robot
+
+#----------------------------------------------------------------
+sub httpd_get_robotstxt
+{
+   my($c,$r) = @_;
+   $c->send_basic_header;
+   $c->print("Content-Type: text/plain");
+   $c->send_crlf;
+   $c->send_crlf;
+   $c->print("User-Agent: *
+Disallow: /private
+
+");
+}
+
+sub httpd_get_someplace
+{
+   my($c,$r) = @_;
+   $c->send_basic_header;
+   $c->print("Content-Type: text/plain");
+   $c->send_crlf;
+   $c->send_crlf;
+   $c->print("Okidok\n");
+}
+
+$req = new HTTP::Request GET => url("/someplace", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->is_success;
+print "ok 1\n";
+
+$req = new HTTP::Request GET => url("/private/place", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->code == 403
+                and $res->message =~ /robots.txt/;
+print "ok 2\n";
+
+$req = new HTTP::Request GET => url("/foo", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->code == 404;  # not found
+print "ok 3\n";
+
+# Let the robotua generate "Service unavailable/Retry After response";
+$ua->delay(1);
+$ua->use_sleep(0);
+$req = new HTTP::Request GET => url("/foo", $base);
+$res = $ua->request($req);
+#print $res->as_string;
+print "not " unless $res->code == 503   # Unavailable
+                and $res->header("Retry-After");
+print "ok 4\n";
+
+#----------------------------------------------------------------
+print "Terminating server...\n";
+sub httpd_get_quit
+{
+    my($c) = @_;
+    $c->send_error(503, "Bye, bye");
+    exit;  # terminate HTTP server
+}
+
+$ua->delay(0);
+$req = new HTTP::Request GET => url("/quit", $base);
+$res = $ua->request($req);
+
+print "not " unless $res->code == 503 and $res->content =~ /Bye, bye/;
+print "ok 5\n";
+
+#---------------------------------------------------------------
+$ua->delay(1);
+
+# host_wait() should be around 60s now
+print "not " unless abs($ua->host_wait($base->netloc) - 60) < 5;
+print "ok 6\n";
+
+# Number of visits to this place should be 
+print "not " unless $ua->no_visits($base->netloc) == 4;
+print "ok 7\n";
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/abs-config.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/abs-config.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/abs-config.t	(revision 10506)
@@ -0,0 +1,35 @@
+print "1..6\n";
+
+use URI::URL qw(url);
+
+# Test configuration via some global variables.
+
+$URI::URL::ABS_REMOTE_LEADING_DOTS = 1;
+$URI::URL::ABS_ALLOW_RELATIVE_SCHEME = 1;
+
+$u1 = url("../../../../abc", "http://web/a/b");
+
+print "not " unless $u1->abs->as_string eq "http://web/abc";
+print "ok 1\n";
+
+{
+    local $URI::URL::ABS_REMOTE_LEADING_DOTS;
+    print "not " unless $u1->abs->as_string eq "http://web/../../../abc";
+    print "ok 2\n";
+}
+
+
+$u1 = url("http:../../../../abc", "http://web/a/b");
+print "not " unless $u1->abs->as_string eq "http://web/abc";
+print "ok 3\n";
+
+{
+   local $URI::URL::ABS_ALLOW_RELATIVE_SCHEME;
+   print "not " unless $u1->abs->as_string eq "http:../../../../abc";
+   print "ok 4\n";
+   print "not " unless $u1->abs(undef,1)->as_string eq "http://web/abc";
+   print "ok 5\n";
+}
+
+print "not " unless $u1->abs(undef,0)->as_string eq "http:../../../../abc";
+print "ok 6\n";
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/base.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/base.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/base.t	(revision 10506)
@@ -0,0 +1,955 @@
+#!/local/bin/perl -w
+
+use URI::URL qw(url);
+use URI::Escape qw(uri_escape uri_unescape);
+
+use Carp;
+
+# _expect()
+#
+# Handy low-level object method tester which we insert as a method
+# in the URI::URL class
+#
+sub URI::URL::_expect {
+    my($self, $method, $expect, @args) = @_;
+    my $result = $self->$method(@args);
+    $expect = 'UNDEF' unless defined $expect;
+    $result = 'UNDEF' unless defined $result;
+    return 1 if $expect eq $result;
+    warn "'$self'->$method(@args) = '$result' " .
+		"(expected '$expect')\n";
+    $self->print_on('STDERR');
+    confess "Test Failed";
+}
+
+package main;
+
+# Must ensure that there is no relative paths in @INC because we will
+# chdir in the newlocal tests.
+chomp($pwd = ($^O =~ /mswin32/i ? `cd` : `pwd`));
+for (@INC) {
+    next if m|^/| or $^O =~ /os2|mswin32/i and m|^\w:[\\/]|;
+    print "Turn lib path $_ into $pwd/$_\n";
+    $_ = "$pwd/$_";
+
+}
+
+$| = 1;
+
+print "1..8\n";  # for Test::Harness
+
+# Do basic tests first.
+# Dies if an error has been detected, prints "ok" otherwise.
+
+print "Self tests for URI::URL version $URI::URL::VERSION...\n";
+
+scheme_parse_test();
+print "ok 1\n";
+
+parts_test();
+print "ok 2\n";
+
+escape_test();
+print "ok 3\n";
+
+newlocal_test();
+print "ok 4\n";
+
+absolute_test();
+print "ok 5\n";
+
+eq_test();
+print "ok 6\n";
+
+# Let's test makeing our own things
+URI::URL::strict(0);
+# This should work after URI::URL::strict(0)
+$url = new URI::URL "x-myscheme:something";
+# Since no implementor is registered for 'x-myscheme' then it will
+# be handeled by the URI::URL::_generic class
+$url->_expect('as_string' => 'x-myscheme:something');
+$url->_expect('path' => 'something');
+URI::URL::strict(1);
+
+# Let's try to make our URL subclass
+{
+    package MyURL;
+    @ISA = URI::URL::implementor();
+
+    sub _parse {
+	my($self, $init) = @_;
+	$self->URI::URL::_generic::_parse($init, qw(netloc path));
+    }
+
+    sub foo {
+	my $self = shift;
+	print ref($self)."->foo called for $self\n";
+    }
+}
+# Let's say that it implements the 'x-a+b.c' scheme (alias 'x-foo')
+URI::URL::implementor('x-a+b.c', 'MyURL');
+URI::URL::implementor('x-foo', 'MyURL');
+
+# Now we are ready to try our new URL scheme
+$url = new URI::URL 'x-a+b.c://foo/bar;a?b';
+$url->_expect('as_string', 'x-a+b.c://foo/bar;a?b');
+$url->_expect('path', '/bar;a?b');
+$url->foo;
+$newurl = new URI::URL 'xxx', $url;
+$newurl->foo;
+$url = new URI::URL 'yyy', 'x-foo:';
+$url->foo;
+
+print "ok 7\n";
+
+# Test the new wash&go constructor
+print "not " if url("../foo.html", "http://www.sn.no/a/b")->abs->as_string
+		ne 'http://www.sn.no/foo.html';
+print "ok 8\n";
+
+print "URI::URL version $URI::URL::VERSION ok\n";
+
+exit 0;
+
+
+
+
+#####################################################################
+#
+# scheme_parse_test()
+#
+# test parsing and retrieval methods
+
+sub scheme_parse_test {
+
+    print "scheme_parse_test:\n";
+
+    $tests = {
+	'hTTp://web1.net/a/b/c/welcome#intro'
+	=> {    'scheme'=>'http', 'host'=>'web1.net', 'port'=>80,
+		'path'=>'/a/b/c/welcome', 'frag'=>'intro','query'=>undef,
+		'epath'=>'/a/b/c/welcome', 'equery'=>undef,
+		'params'=>undef, 'eparams'=>undef,
+		'as_string'=>'http://web1.net/a/b/c/welcome#intro',
+		'full_path' => '/a/b/c/welcome' },
+
+	'http://web:1/a?query+text'
+	=> {    'scheme'=>'http', 'host'=>'web', 'port'=>1,
+		'path'=>'/a', 'frag'=>undef, 'query'=>'query+text' },
+
+	'http://web.net/'
+	=> {    'scheme'=>'http', 'host'=>'web.net', 'port'=>80,
+		'path'=>'/', 'frag'=>undef, 'query'=>undef,
+		'full_path' => '/',
+		'as_string' => 'http://web.net/' },
+
+	'http://web.net'
+	=> {    'scheme'=>'http', 'host'=>'web.net', 'port'=>80,
+		'path'=>'/', 'frag'=>undef, 'query'=>undef,
+		'full_path' => '/',
+		'as_string' => 'http://web.net/' },
+
+	'http:0'
+	 => {   'scheme'=>'http', 'path'=>'0', 'query'=>undef,
+		'as_string'=>'http:0', 'full_path'=>'0', },
+
+	'http:/0?0'
+	 => {   'scheme'=>'http', 'path'=>'/0', 'query'=>'0',
+		'as_string'=>'http:/0?0', 'full_path'=>'/0?0', },
+
+	'http://0:0/0/0;0?0#0'
+	 => {   'scheme'=>'http', 'host'=>'0', 'port'=>'0',
+		'path' => '/0/0', 'query'=>'0', 'params'=>'0',
+		'netloc'=>'0:0',
+		'frag'=>0, 'as_string'=>'http://0:0/0/0;0?0#0' },
+
+	'ftp://0%3A:%40@h:0/0?0'
+	=>  {   'scheme'=>'ftp', 'user'=>'0:', 'password'=>'@',
+		'host'=>'h', 'port'=>'0', 'path'=>'/0?0',
+		'query'=>undef, params=>undef,
+		'netloc'=>'0%3A:%40@h:0',
+		'as_string'=>'ftp://0%3A:%40@h:0/0?0' },
+
+	'ftp://usr:pswd@web:1234/a/b;type=i'
+	=> {    'host'=>'web', 'port'=>1234, 'path'=>'/a/b',
+		'user'=>'usr', 'password'=>'pswd',
+		'params'=>'type=i',
+		'as_string'=>'ftp://usr:pswd@web:1234/a/b;type=i' },
+
+	'ftp://host/a/b'
+	=> {    'host'=>'host', 'port'=>21, 'path'=>'/a/b',
+		'user'=>'anonymous',
+		'as_string'=>'ftp://host/a/b' },
+
+	'file://host/fseg/fs?g/fseg'
+	# don't escape ? for file: scheme
+	=> {    'host'=>'host', 'path'=>'/fseg/fs?g/fseg',
+		'as_string'=>'file://host/fseg/fs?g/fseg' },
+
+	'gopher://host'
+	=> {     'gtype'=>'1', 'as_string' => 'gopher://host/', },
+
+	'gopher://host/'
+	=> {     'gtype'=>'1', 'as_string' => 'gopher://host/', },
+
+	'gopher://gopher/2a_selector'
+	=> {    'gtype'=>'2', 'selector'=>'a_selector',
+		'as_string' => 'gopher://gopher/2a_selector', },
+
+	'mailto:libwww-perl@ics.uci.edu'
+	=> {    'address'       => 'libwww-perl@ics.uci.edu',
+		'encoded822addr'=> 'libwww-perl@ics.uci.edu',
+		'user'          => 'libwww-perl',
+		'host'          => 'ics.uci.edu',
+		'as_string'     => 'mailto:libwww-perl@ics.uci.edu', },
+
+	'news:*'
+	=> {    'groupart'=>'*', 'group'=>'*', as_string=>'news:*' },
+	'news:comp.lang.perl'
+	=> {    'group'=>'comp.lang.perl' },
+	'news:perl-faq/module-list-1-794455075@ig.co.uk'
+	=> {    'article'=>
+		    'perl-faq/module-list-1-794455075@ig.co.uk' },
+
+	'nntp://news.com/comp.lang.perl/42'
+	=> {    'group'=>'comp.lang.perl', 'digits'=>42 },
+
+	'telnet://usr:pswd@web:12345/'
+	=> {    'user'=>'usr', 'password'=>'pswd', 'host'=>'web' },
+	'rlogin://aas@a.sn.no'
+	=> {    'user'=>'aas', 'host'=>'a.sn.no' },
+	'tn3270://aas@ibm'
+	=> {    'user'=>'aas', 'host'=>'ibm',
+		'as_string'=>'tn3270://aas@ibm/'},
+
+	'wais://web.net/db'
+	=> { 'database'=>'db' },
+	'wais://web.net/db?query'
+	=> { 'database'=>'db', 'query'=>'query' },
+	'wais://usr:pswd@web.net/db/wt/wp'
+	=> {    'database'=>'db', 'wtype'=>'wt', 'wpath'=>'wp',
+		'password'=>'pswd' },
+    };
+
+    foreach $url_str (sort keys %$tests ){
+	print "Testing '$url_str'\n";
+	my $url = new URI::URL $url_str;
+	my $tests = $tests->{$url_str};
+	while( ($method, $exp) = each %$tests ){
+	    $exp = 'UNDEF' unless defined $exp;
+	    $url->_expect($method, $exp);
+	}
+    }
+}
+
+
+#####################################################################
+#
+# parts_test()          (calls netloc_test test)
+#
+# Test individual component part access functions
+#
+sub parts_test {
+    print "parts_test:\n";
+
+    # test storage part access/edit methods (netloc, user, password,
+    # host and port are tested by &netloc_test)
+
+    $url = new URI::URL 'file://web/orig/path';
+    $url->scheme('http');
+    $url->path('1info');
+    $url->query('key words');
+    $url->frag('this');
+    $url->_expect('as_string' => 'http://web/1info?key%20words#this');
+
+    $url->epath('%2f/%2f');
+    $url->equery('a=%26');
+    $url->_expect('full_path' => '/%2f/%2f?a=%26');
+
+    # At this point it should be impossible to access the members path()
+    # and query() without complaints.
+    eval { my $p = $url->path; print "Path is $p\n"; };
+    die "Path exception failed" unless $@;
+    eval { my $p = $url->query; print "Query is $p\n"; };
+    die "Query exception failed" unless $@;
+
+    # but we should still be able to set it 
+    $url->path("howdy");
+    $url->_expect('as_string' => 'http://web/howdy?a=%26#this');
+
+    # Test the path_components function
+    $url = new URI::URL 'file:%2f/%2f';
+    my $p;
+    $p = join('-', $url->path_components);
+    die "\$url->path_components returns '$p', expected '/-/'"
+      unless $p eq "/-/";
+    $url->host("localhost");
+    $p = join('-', $url->path_components);
+    die "\$url->path_components returns '$p', expected '-/-/'"
+      unless $p eq "-/-/";
+    $url->epath("/foo/bar/");
+    $p = join('-', $url->path_components);
+    die "\$url->path_components returns '$p', expected '-foo-bar-'"
+      unless $p eq "-foo-bar-";
+    $url->path_components("", "/etc", "\0", "..", "øse", "");
+    $url->_expect('full_path' => '/%2Fetc/%00/../%F8se/');
+
+    # Setting undef
+    $url = new URI::URL 'http://web/p;p?q#f';
+    $url->epath(undef);
+    $url->equery(undef);
+    $url->eparams(undef);
+    $url->frag(undef);
+    $url->_expect('as_string' => 'http://web/');
+
+    # Test http query access methods
+    $url->keywords('dog');
+    $url->_expect('as_string' => 'http://web/?dog');
+    $url->keywords(qw(dog bones));
+    $url->_expect('as_string' => 'http://web/?dog+bones');
+    $url->keywords(0,0);
+    $url->_expect('as_string' => 'http://web/?0+0');
+    $url->keywords('dog', 'bones', '#+=');
+    $url->_expect('as_string' => 'http://web/?dog+bones+%23%2B%3D');
+    $a = join(":", $url->keywords);
+    die "\$url->keywords did not work (returned '$a')" unless $a eq 'dog:bones:#+=';
+    # calling query_form is an error
+    eval { my $foo = $url->query_form; };
+    die "\$url->query_form should croak since query contains keywords not a form."
+      unless $@;
+
+    $url->query_form(a => 'foo', b => 'bar');
+    $url->_expect('as_string' => 'http://web/?a=foo&b=bar');
+    my %a = $url->query_form;
+    die "\$url->query_form did not work"
+      unless $a{a} eq 'foo' && $a{b} eq 'bar';
+
+    $url->query_form(a => undef, a => 'foo', '&=' => '&=+');
+    $url->_expect('as_string' => 'http://web/?a=&a=foo&%26%3D=%26%3D%2B');
+
+    my @a = $url->query_form;
+    die "Wrong length" unless @a == 6;
+    die "Bad keys from query_form"
+      unless $a[0] eq 'a' && $a[2] eq 'a' && $a[4] eq '&=';
+    die "Bad values from query_form"
+      unless $a[1] eq '' && $a[3] eq 'foo' && $a[5] eq '&=+';
+
+    # calling keywords is an error
+    eval { my $foo = $url->keywords; };
+    die "\$url->keywords should croak when query is a form"
+      unless $@;
+    # Try this odd one
+    $url->equery('&=&=b&a=&a&a=b=c&&a=b');
+    @a = $url->query_form;
+    #print join(":", @a), "\n";
+    die "Wrong length" unless @a == 16;
+    die "Wrong sequence" unless $a[4]  eq ""  && $a[5]  eq "b" &&
+                                $a[10] eq "a" && $a[11] eq "b=c";
+
+    # Try array ref values in the key value pairs
+    $url->query_form(a => ['foo', 'bar'], b => 'foo', c => ['bar', 'foo']);
+    $url->_expect('as_string', 'http://web/?a=foo&a=bar&b=foo&c=bar&c=foo');
+
+
+    netloc_test();
+    port_test();
+
+    $url->query(undef);
+    $url->_expect('query', undef);
+
+    $url = new URI::URL 'gopher://gopher/';
+    $url->port(33);
+    $url->gtype("3");
+    $url->selector("S");
+    $url->search("query");
+    $url->_expect('as_string', 'gopher://gopher:33/3S%09query');
+
+    $url->epath("45%09a");
+    $url->_expect('gtype' => '4');
+    $url->_expect('selector' => '5');
+    $url->_expect('search' => 'a');
+    $url->_expect('string' => undef);
+    $url->_expect('path' => "/45\ta");
+    $url->path("00\t%09gisle");
+    $url->_expect('search', '%09gisle');
+
+    # Let's test som other URL schemes
+    $url = new URI::URL 'news:';
+    $url->group("comp.lang.perl.misc");
+    $url->_expect('as_string' => 'news:comp.lang.perl.misc');
+    $url->article('<1234@a.sn.no>');
+    $url->_expect('as_string' => 'news:1234@a.sn.no'); # "<" and ">" are gone
+    # This one should be illegal
+    eval { $url->article("no.perl"); };
+    die "This one should really complain" unless $@;
+
+    $url = new URI::URL 'mailto:';
+    $url->user("aas");
+    $url->host("a.sn.no");
+    $url->_expect("as_string" => 'mailto:aas@a.sn.no');
+    $url->address('foo@bar');
+    $url->_expect("host" => 'bar');
+    $url->_expect("user" => 'foo');
+
+    $url = new URI::URL 'wais://host/database/wt/wpath';
+    $url->database('foo');
+    $url->_expect('as_string' => 'wais://host/foo/wt/wpath');
+    $url->wtype('bar');
+    $url->_expect('as_string' => 'wais://host/foo/bar/wpath');
+
+    # Test crack method for various URLs
+    my(@crack, $crack);
+    @crack = URI::URL->new("http://host/path;param?query#frag")->crack;
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "http*UNDEF*UNDEF*host*80*/path*param*query*frag";
+
+    @crack = URI::URL->new("foo/bar", "ftp://aas\@ftp.sn.no/")->crack;
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "ftp*UNDEF*UNDEF*UNDEF*21*foo/bar*UNDEF*UNDEF*UNDEF";
+
+    @crack = URI::URL->new('ftp://u:p@host/q?path')->crack;
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "ftp*u*p*host*21*/q?path*UNDEF*UNDEF*UNDEF";
+
+    @crack = URI::URL->new("ftp://ftp.sn.no/pub")->crack;    # Test anon ftp
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    die "No passwd in anonymous crack" unless $crack[2];
+    $crack[2] = 'passwd';  # easier to test when we know what it is
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "ftp*anonymous*passwd*ftp.sn.no*21*/pub*UNDEF*UNDEF*UNDEF";
+
+    @crack = URI::URL->new('mailto:aas@sn.no')->crack;
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "mailto*aas*UNDEF*sn.no*UNDEF*aas\@sn.no*UNDEF*UNDEF*UNDEF";
+
+    @crack = URI::URL->new('news:comp.lang.perl.misc')->crack;
+    die "Cracked result should be 9 elements" unless @crack == 9;
+    $crack = join("*", map { defined($_) ? $_ : "UNDEF" } @crack);
+    print "Cracked result: $crack\n";
+    die "Bad crack result" unless
+      $crack eq "news*UNDEF*UNDEF*UNDEF*UNDEF*comp.lang.perl.misc*UNDEF*UNDEF*UNDEF";
+}
+
+#
+# netloc_test()
+#
+# Test automatic netloc synchronisation
+#
+sub netloc_test {
+    print "netloc_test:\n";
+
+    my $url = new URI::URL 'ftp://anonymous:p%61ss@håst:12345';
+    $url->_expect('user', 'anonymous');
+    $url->_expect('password', 'pass');
+    $url->_expect('host', 'håst');
+    $url->_expect('port', 12345);
+    # Can't really know how netloc is represented since it is partially escaped
+    #$url->_expect('netloc', 'anonymous:pass@hst:12345');
+    $url->_expect('as_string' => 'ftp://anonymous:p%61ss@h%E5st:12345/');
+
+    # The '0' is sometimes tricky to get right
+    $url->user(0);
+    $url->password(0);
+    $url->host(0);
+    $url->port(0);
+    $url->_expect('netloc' => '0:0@0:0');
+    $url->host(undef);
+    $url->_expect('netloc' => '');
+    $url->host('h');
+    $url->user(undef);
+    $url->_expect('netloc' => 'h:0');
+    $url->user('');
+    $url->_expect('netloc' => ':0@h:0');
+    $url->password('');
+    $url->_expect('netloc' => ':@h:0');
+    $url->user('foo');
+    $url->_expect('netloc' => 'foo:@h:0');
+
+    # Let's try a simple one
+    $url->user('nemo');
+    $url->password('p2');
+    $url->host('hst2');
+    $url->port(2);
+    $url->_expect('netloc' => 'nemo:p2@hst2:2');
+
+    $url->user(undef);
+    $url->password(undef);
+    $url->port(undef);
+    $url->_expect('netloc' => 'hst2');
+    $url->_expect('port' => '21');  # the default ftp port
+
+    $url->port(21);
+    $url->_expect('netloc' => 'hst2');
+
+    # Let's try some reserved chars
+    $url->user("@");
+    $url->password(":-#-;-/-?");
+    $url->_expect('as_string' => 'ftp://%40:%3A-%23-%3B-%2F-%3F@hst2/');
+
+}
+
+#
+# port_test()
+#
+# Test port behaviour
+#
+sub port_test {
+    print "port_test:\n";
+
+    $url = URI::URL->new('http://foo/root/dir/');
+    my $port = $url->port;
+    die "Port undefined" unless defined $port;
+    die "Wrong port $port" unless $port == 80;
+    die "Wrong string" unless $url->as_string eq
+	'http://foo/root/dir/';
+
+    $url->port(8001);
+    $port = $url->port;
+    die "Port undefined" unless defined $port;
+    die "Wrong port $port" unless $port == 8001;
+    die "Wrong string" unless $url->as_string eq
+	'http://foo:8001/root/dir/';
+
+    $url->port(80);
+    $port = $url->port;
+    die "Port undefined" unless defined $port;
+    die "Wrong port $port" unless $port == 80;
+    die "Wrong string" unless $url->as_string eq
+	'http://foo/root/dir/';
+
+    $url->port(8001);
+    $url->port(undef);
+    $port = $url->port;
+    die "Port undefined" unless defined $port;
+    die "Wrong port $port" unless $port == 80;
+    die "Wrong string" unless $url->as_string eq
+	'http://foo/root/dir/';
+}
+
+
+#####################################################################
+#
+# escape_test()
+#
+# escaping functions
+
+sub escape_test {
+    print "escape_test:\n";
+
+    # supply escaped URL
+    $url = new URI::URL 'http://web/this%20has%20spaces';
+    # check component is unescaped
+    $url->_expect('path', '/this has spaces');
+
+    # modify the unescaped form
+    $url->path('this ALSO has spaces');
+    # check whole url is escaped
+    $url->_expect('as_string',
+		  'http://web/this%20ALSO%20has%20spaces');
+
+    $url = new URI::URL uri_escape('http://web/try %?#" those');
+    $url->_expect('as_string',
+		  'http://web/try%20%25%3F%23%22%20those');
+
+    my $all = pack('c*',0..255);
+    my $esc = uri_escape($all);
+    my $new = uri_unescape($esc);
+    die "uri_escape->uri_unescape mismatch" unless $all eq $new;
+    $url->path($all);
+    $url->_expect('full_path' => '/%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20!%22%23$%25%26\'()*%2B,-./0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~%7F%80%81%82%83%84%85%86%87%88%89%8A%8B%8C%8D%8E%8F%90%91%92%93%94%95%96%97%98%99%9A%9B%9C%9D%9E%9F%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF');
+
+    # test escaping uses uppercase (preferred by rfc1837)
+    $url = new URI::URL 'file://h/';
+    $url->path(chr(0x7F));
+    $url->_expect('as_string', 'file://h/%7F');
+
+    # reserved characters differ per scheme
+
+    ## XXX is this '?' allowed to be unescaped
+    $url = new URI::URL 'file://h/test?ing';
+    $url->_expect('path', '/test?ing');
+
+    $url = new URI::URL 'file://h/';
+    $url->epath('question?mark');
+    $url->_expect('as_string', 'file://h/question?mark');
+    # XXX Why should this be any different???
+    #     Perhaps we should not expect too much :-)
+    $url->path('question?mark');
+    $url->_expect('as_string', 'file://h/question%3Fmark');
+
+    # See what happens when set different elements to this ugly sting
+    my $reserved = ';/?:@&=#%';
+    $url->path($reserved . "foo");
+    $url->_expect('as_string', 'file://h/%3B/%3F%3A%40%26%3D%23%25foo');
+
+    $url->scheme('http');
+    $url->path('');
+    $url->_expect('as_string', 'http://h/');
+    $url->query($reserved);
+    $url->params($reserved);
+    $url->frag($reserved);
+    $url->_expect('as_string', 'http://h/;%3B%2F%3F%3A%40&=%23%25?%3B%2F%3F%3A%40&=%23%25#;/?:@&=#%');
+
+    $str = $url->as_string;
+    $url = new URI::URL $str;
+    die "URL changed" if $str ne $url->as_string;
+
+    $url = new URI::URL 'ftp:foo';
+    $url->user($reserved);
+    $url->host($reserved);
+    $url->_expect('as_string', 'ftp://%3B%2F%3F%3A%40%26%3D%23%25@%3B%2F%3F%3A%40%26%3D%23%25/foo');
+
+}
+
+
+#####################################################################
+#
+# newlocal_test()
+#
+
+sub newlocal_test {
+    print "newlocal_test:\n";
+    my $pwd = ($^O eq 'MSWin32' ? 'cd' : (-e '/bin/pwd' ? '/bin/pwd' : 'pwd'));
+    my $tmpdir = ($^O eq 'MSWin32' ? $ENV{TEMP} : '/tmp');
+    $tmpdir =~ tr|\\|/|;
+
+    my $savedir = `$pwd`;     # we don't use Cwd.pm because we want to check
+			      # that it get require'd corretly by URL.pm
+    chomp $savedir;
+
+    # cwd
+    chdir($tmpdir) or die $!;
+    my $dir = `$pwd`; $dir =~ tr|\\|/|;
+    chomp $dir; $dir = uri_escape($dir, ':');
+    $url = newlocal URI::URL;
+    $url->_expect('as_string', URI::URL->new("file:$dir/")->as_string);
+
+    print "Local directory is ". $url->local_path . "\n";
+
+    # absolute dir
+    chdir('/') or die $!;
+    $url = newlocal URI::URL '/usr/';
+    $url->_expect('as_string', 'file:/usr/');
+
+    # absolute file
+    $url = newlocal URI::URL '/vmunix';
+    $url->_expect('as_string', 'file:/vmunix');
+
+    # relative file
+    chdir($tmpdir) or die $!;
+    $dir = `$pwd`; $dir =~ tr|\\|/|;
+    chomp $dir; $dir = uri_escape($dir, ':');
+    $url = newlocal URI::URL 'foo';
+    $url->_expect('as_string', "file:$dir/foo");
+
+    # relative dir
+    chdir($tmpdir) or die $!;
+    $dir = `$pwd`; $dir =~ tr|\\|/|;
+    chomp $dir; $dir = uri_escape($dir, ':');
+    $url = newlocal URI::URL 'bar/';
+    $url->_expect('as_string', "file:$dir/bar/");
+
+    # 0
+    chdir('/') or die $!;
+    $dir = `$pwd`; $dir =~ tr|\\|/|;
+    chomp $dir; $dir = uri_escape($dir, ':');
+    $url = newlocal URI::URL '0';
+    $url->_expect('as_string', "file:${dir}0");
+
+    # Test access methods for file URLs
+    $url = new URI::URL 'file:/c:/dos';
+    $url->_expect('dos_path', 'C:\\DOS');
+    $url->_expect('unix_path', '/c:/dos');
+    $url->_expect('vms_path', '[C:]DOS');
+    eval { $url->mac_path; };  # This is not allowed since we have ':' in path
+    die "Mac_path generated when it should fail." unless $@;
+    $url = new URI::URL 'file:/foo/bar';
+    $url->_expect('unix_path', '/foo/bar');
+    $url->_expect('mac_path', 'foo:bar');
+
+    # Some edge cases
+    $url = new URI::URL 'file:';
+    $url->_expect('unix_path', '/');
+    $url = new URI::URL 'file:/';
+    $url->_expect('unix_path', '/');
+    $url = new URI::URL 'file:.';
+    $url->_expect('unix_path', '.');
+    $url = new URI::URL 'file:./foo';
+    $url->_expect('unix_path', 'foo');
+    $url = new URI::URL 'file:0';
+    $url->_expect('unix_path', '0');
+    $url = new URI::URL 'file:../../foo';
+    $url->_expect('unix_path', '../../foo');
+    $url = new URI::URL 'file:foo/../bar';
+    $url->_expect('unix_path', 'bar');
+
+    # Relative files
+    $url = new URI::URL 'file:foo/b%61r/Note.txt';
+    $url->_expect('unix_path', 'foo/bar/Note.txt');
+    $url->_expect('mac_path', ':foo:bar:Note.txt');
+    $url->_expect('dos_path', 'FOO\\BAR\\NOTE.TXT');
+    $url->_expect('vms_path', '[.FOO.BAR]NOTE.TXT');
+
+    # The VMS path found in RFC 1738 (section 3.10)
+    $url = new URI::URL 'file://vms.host.edu/disk$user/my/notes/note12345.txt';
+    $url->_expect('vms_path', 'DISK$USER:[MY.NOTES]NOTE12345.TXT');
+    $url->_expect('mac_path', 'disk$user:my:notes:note12345.txt');
+
+    chdir($savedir) or die $!;
+}
+
+
+#####################################################################
+#
+# absolute_test()
+#
+sub absolute_test {
+
+    print "Test relative/absolute URI::URL parsing:\n";
+
+    # Tests from draft-ietf-uri-relative-url-06.txt
+    # Copied verbatim from the draft, parsed below
+
+    @URI::URL::g::ISA = qw(URI::URL::_generic); # for these tests
+
+    my $base = 'http://a/b/c/d;p?q#f';
+
+    $absolute_tests = <<EOM;
+5.1.  Normal Examples
+
+      g:h        = <URL:g:h>
+      g          = <URL:http://a/b/c/g>
+      ./g        = <URL:http://a/b/c/g>
+      g/         = <URL:http://a/b/c/g/>
+      /g         = <URL:http://a/g>
+      //g        = <URL:http://g>
+      ?y         = <URL:http://a/b/c/d;p?y>
+      g?y        = <URL:http://a/b/c/g?y>
+      g?y/./x    = <URL:http://a/b/c/g?y/./x>
+      #s         = <URL:http://a/b/c/d;p?q#s>
+      g#s        = <URL:http://a/b/c/g#s>
+      g#s/./x    = <URL:http://a/b/c/g#s/./x>
+      g?y#s      = <URL:http://a/b/c/g?y#s>
+      ;x         = <URL:http://a/b/c/d;x>
+      g;x        = <URL:http://a/b/c/g;x>
+      g;x?y#s    = <URL:http://a/b/c/g;x?y#s>
+      .          = <URL:http://a/b/c/>
+      ./         = <URL:http://a/b/c/>
+      ..         = <URL:http://a/b/>
+      ../        = <URL:http://a/b/>
+      ../g       = <URL:http://a/b/g>
+      ../..      = <URL:http://a/>
+      ../../     = <URL:http://a/>
+      ../../g    = <URL:http://a/g>
+
+5.2.  Abnormal Examples
+
+   Although the following abnormal examples are unlikely to occur
+   in normal practice, all URL parsers should be capable of resolving
+   them consistently.  Each example uses the same base as above.
+
+   An empty reference resolves to the complete base URL:
+
+      <>         = <URL:http://a/b/c/d;p?q#f>
+
+   Parsers must be careful in handling the case where there are more
+   relative path ".." segments than there are hierarchical levels in
+   the base URL's path.  Note that the ".." syntax cannot be used to
+   change the <net_loc> of a URL.
+
+     ../../../g = <URL:http://a/../g>
+     ../../../../g = <URL:http://a/../../g>
+
+   Similarly, parsers must avoid treating "." and ".." as special
+   when they are not complete components of a relative path.
+
+      /./g       = <URL:http://a/./g>
+      /../g      = <URL:http://a/../g>
+      g.         = <URL:http://a/b/c/g.>
+      .g         = <URL:http://a/b/c/.g>
+      g..        = <URL:http://a/b/c/g..>
+      ..g        = <URL:http://a/b/c/..g>
+
+   Less likely are cases where the relative URL uses unnecessary or
+   nonsensical forms of the "." and ".." complete path segments.
+
+      ./../g     = <URL:http://a/b/g>
+      ./g/.      = <URL:http://a/b/c/g/>
+      g/./h      = <URL:http://a/b/c/g/h>
+      g/../h     = <URL:http://a/b/c/h>
+
+   Finally, some older parsers allow the scheme name to be present in
+   a relative URL if it is the same as the base URL scheme.  This is
+   considered to be a loophole in prior specifications of partial
+   URLs [1] and should be avoided by future parsers.
+
+      http:g     = <URL:http:g>
+      http:      = <URL:http:>
+EOM
+    # convert text to list like
+    # @absolute_tests = ( ['g:h' => 'g:h'], ...)
+
+    for $line (split("\n", $absolute_tests)) {
+	next unless $line =~ /^\s{6}/;
+	if ($line =~ /^\s+(\S+)\s*=\s*<URL:([^>]*)>/) {
+	    my($rel, $abs) = ($1, $2);
+	    $rel = '' if $rel eq '<>';
+	    push(@absolute_tests, [$rel, $abs]);
+	}
+	else {
+	    warn "illegal line '$line'";
+	}
+    }
+
+    # add some extra ones for good measure
+
+    push(@absolute_tests, ['x/y//../z' => 'http://a/b/c/x/y/z'],
+			  ['1'         => 'http://a/b/c/1'    ],
+			  ['0'         => 'http://a/b/c/0'    ],
+			  ['/0'        => 'http://a/0'        ],
+			  ['%2e/a'     => 'http://a/b/c/%2e/a'],  # %2e is '.'
+			  ['%2e%2e/a'  => 'http://a/b/c/%2e%2e/a'],
+	);
+
+    print "  Relative    +  Base  =>  Expected Absolute URL\n";
+    print "================================================\n";
+    for $test (@absolute_tests) {
+	my($rel, $abs) = @$test;
+	my $abs_url = new URI::URL $abs;
+	my $abs_str = $abs_url->as_string;
+
+	printf("  %-10s  +  $base  =>  %s\n", $rel, $abs);
+	my $u   = new URI::URL $rel, $base;
+	my $got = $u->abs;
+	$got->_expect('as_string', $abs_str);
+    }
+
+    # bug found and fixed in 1.9 by "J.E. Fritz" <FRITZ@gems.vcu.edu>
+    $base = new URI::URL 'http://host/directory/file';
+    my $relative = new URI::URL 'file', $base;
+    my $result = $relative->abs;
+
+    my ($a, $b) = ($base->path, $result->path);
+	die "'$a' and '$b' should be the same" unless $a eq $b;
+
+    # Counter the expectation of least surprise,
+    # section 6 of the draft says the URL should
+    # be canonicalised, rather than making a simple
+    # substitution of the last component.
+    # Better doublecheck someone hasn't "fixed this bug" :-)
+    $base = new URI::URL 'http://host/dir1/../dir2/file';
+    $relative = new URI::URL 'file', $base;
+    $result = $relative->abs;
+    die 'URL not canonicalised' unless $result eq 'http://host/dir2/file';
+
+    print "--------\n";
+    # Test various other kinds of URLs and how they like to be absolutized
+    for (["http://abc/", "news:45664545", "http://abc/"],
+	 ["news:abc",    "http://abc/",   "news:abc"],
+	 ["abc",         "file:/test?aas", "file:/abc"],
+	 ["gopher:",     "",               "gopher:"],
+	 ["?foo",        "http://abc/a",   "http://abc/a?foo"],
+	 ["?foo",        "file:/abc",      "file:/?foo"],
+	 ["#foo",        "http://abc/a",   "http://abc/a#foo"],
+	 ["#foo",        "file:a",         "file:a#foo"],
+	 ["#foo",        "file:/a",         "file:/a#foo"],
+	 ["#foo",        "file:/a",         "file:/a#foo"],
+	 ["#foo",        "file://localhost/a", "file://localhost/a#foo"],
+	 ['123@sn.no',   "news:comp.lang.perl.misc", 'news:123@sn.no'],
+	 ['no.perl',     'news:123@sn.no',           'news:no.perl'],
+	 ['mailto:aas@a.sn.no', "http://www.sn.no/", 'mailto:aas@a.sn.no'],
+
+	 # Test absolutizing with old behaviour.
+	 ['http:foo',     'http://h/a/b',   'http://h/a/foo'],
+	 ['http:/foo',    'http://h/a/b',   'http://h/foo'],
+	 ['http:?foo',    'http://h/a/b',   'http://h/a/b?foo'],
+	 ['http:#foo',    'http://h/a/b',   'http://h/a/b#foo'],
+	 ['http:?foo#bar','http://h/a/b',   'http://h/a/b?foo#bar'],
+	 ['file:/foo',    'http://h/a/b',   'file:/foo'],
+
+	)
+    {
+	my($url, $base, $expected_abs) = @$_;
+	my $rel = new URI::URL $url, $base;
+	my $abs = $rel->abs($base, 1);
+	printf("  %-12s+  $base  =>  %s\n", $rel, $abs);
+	$abs->_expect('as_string', $expected_abs);
+    }
+    print "absolute test ok\n";
+
+    # Test relative function
+    for (
+	 ["http://abc/a",   "http://abc",        "a"],
+	 ["http://abc/a",   "http://abc/b",      "a"],
+	 ["http://abc/a?q", "http://abc/b",      "a?q"],
+	 ["http://abc/a;p", "http://abc/b",      "a;p"],
+	 ["http://abc/a",   "http://abc/a/b/c/", "../../../a"],
+         ["http://abc/a/",  "http://abc/a/",     "./"],
+         ["http://abc/a#f", "http://abc/a",      "#f"],
+
+	 ["file:/etc/motd", "file:/",            "etc/motd"],
+	 ["file:/etc/motd", "file:/etc/passwd",  "motd"],
+	 ["file:/etc/motd", "file:/etc/rc2.d/",  "../motd"],
+	 ["file:/etc/motd", "file:/usr/lib/doc", "../../etc/motd"],
+         ["file:",          "file:/etc/",        "../"],
+         ["file:foo",       "file:/etc/",        "../foo"],
+
+	 ["mailto:aas",     "http://abc",        "mailto:aas"],
+
+	 # Nicolai Langfeldt's original example
+	 ["http://www.math.uio.no/doc/mail/top.html",
+	  "http://www.math.uio.no/doc/linux/", "../mail/top.html"],
+        )
+    {
+	my($abs, $base, $expect) = @$_;
+	printf "url('$abs', '$base')->rel eq '$expect'\n";
+	my $rel = URI::URL->new($abs, $base)->rel;
+	$rel->_expect('as_string', $expect);
+    }
+    print "relative test ok\n";
+}
+
+
+sub eq_test
+{
+    my $u1 = new URI::URL 'http://abc.com:80/~smith/home.html';
+    my $u2 = new URI::URL 'http://ABC.com/%7Esmith/home.html';
+    my $u3 = new URI::URL 'http://ABC.com:/%7esmith/home.html';
+
+    # Test all permutations of these tree
+    $u1->eq($u2) or die "1: $u1 ne $u2";
+    $u1->eq($u3) or die "2: $u1 ne $u3";
+    $u2->eq($u1) or die "3: $u2 ne $u1";
+    $u2->eq($u3) or die "4: $u2 ne $u3";
+    $u3->eq($u1) or die "5: $u3 ne $u1";
+    $u3->eq($u2) or die "6: $u3 ne $u2";
+
+    # Test empty path
+    my $u4 = new URI::URL 'http://www.sn.no';
+    $u4->eq("HTTP://WWW.SN.NO:80/") or die "7: $u4";
+    $u4->eq("http://www.sn.no:81") and die "8: $u4";
+
+    # Test mailto
+    my $u5 = new URI::URL 'mailto:AAS@SN.no';
+    $u5->eq('mailto:aas@sn.no') or die "9: $u5";
+
+    # Test reserved char
+    my $u6 = new URI::URL 'ftp://ftp/%2Fetc';
+    $u6->eq("ftp://ftp/%2fetc") or die "10: $u6";
+    $u6->eq("ftp://ftp://etc") and die "11: $u6";
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/heuristic.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/heuristic.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/heuristic.t	(revision 10506)
@@ -0,0 +1,61 @@
+print "1..14\n";
+
+use URI::Heuristic qw(uf_urlstr uf_url);
+$URI::Heuristic::DEBUG++;
+open(STDERR, ">&STDOUT");  # redirect STDERR
+
+print "not " unless uf_urlstr("http://www.sn.no/") eq "http://www.sn.no/";
+print "ok 1\n";
+
+print "not " unless uf_urlstr("/etc/passwd") eq "file:/etc/passwd";
+print "ok 2\n";
+
+print "not " unless uf_urlstr("./foo.txt") eq "file:./foo.txt";
+print "ok 3\n";
+
+print "not " unless uf_urlstr("ftp.aas.no/lwp.tar.gz") eq "ftp://ftp.aas.no/lwp.tar.gz";
+print "ok 4\n";
+
+print "not " unless uf_urlstr("C:\\CONFIG.SYS") eq "file:C:\\CONFIG.SYS";
+print "ok 5\n";
+
+if (gethostbyname("www.netscape.com")) {
+    # DNS probably work, lets run test 6..8
+
+    $URI::Heuristic::MY_COUNTRY = "no";
+    print "not " unless uf_urlstr("perl/camel.gif") eq "http://www.perl.com/camel.gif";
+    print "ok 6\n";
+
+    $URI::Heuristic::MY_COUNTRY = "uk";
+    print "not " unless uf_urlstr("perl/camel.gif") eq "http://www.perl.co.uk/camel.gif";
+    print "ok 7\n";
+   
+    $ENV{URL_GUESS_PATTERN} = "www.ACME.org www.ACME.com";
+    print "not " unless uf_urlstr("perl") eq "http://www.perl.org";
+    print "ok 8\n";
+
+} else {
+    # don't make the inocent worry
+    print "Skipping test 6-8 because DNS does not work\n";
+    for (6..8) { print "ok $_\n"; }
+
+}
+
+$ENV{URL_GUESS_PATTERN} = "";
+print "not " unless uf_urlstr("perl") eq "http://perl";
+print "ok 9\n";
+
+print "not " unless uf_urlstr("http:80") eq "http:80";
+print "ok 10\n";
+
+print "not " unless uf_urlstr("mailto:gisle\@aas.no") eq "mailto:gisle\@aas.no";
+print "ok 11\n";
+
+print "not " unless uf_urlstr("gisle\@aas.no") eq "mailto:gisle\@aas.no";
+print "ok 12\n";
+
+print "not " unless uf_urlstr("Gisle.Aas\@aas.perl.org") eq "mailto:Gisle.Aas\@aas.perl.org";
+print "ok 13\n";
+
+print "not " unless uf_url("gopher.sn.no")->scheme eq "gopher";
+print "ok 14\n";
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/rel-base.t
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/rel-base.t	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/libwww-perl-5.36/t/uri/rel-base.t	(revision 10506)
@@ -0,0 +1,24 @@
+print "1..3\n";
+
+use URI::URL;
+
+# We used to have problems with URLs that used a base that was
+# not absolute itself.
+
+$u1 = url("/foo/bar", "http://www.acme.com/");
+$u2 = url("../foo/", $u1);
+$u3 = url("zoo/foo", $u2);
+
+$a1 = $u1->abs->as_string;
+$a2 = $u2->abs->as_string;
+$a3 = $u3->abs->as_string;
+
+print "$a1\n$a2\n$a3\n";
+
+print "not " unless $a1 eq "http://www.acme.com/foo/bar";
+print "ok 1\n";
+print "not " unless $a2 eq "http://www.acme.com/foo/";
+print "ok 2\n";
+print "not " unless $a3 eq "http://www.acme.com/foo/zoo/foo";
+print "ok 3\n";
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/Artistic
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/Artistic	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/Artistic	(revision 10506)
@@ -0,0 +1,131 @@
+
+
+
+
+			 The "Artistic License"
+
+				Preamble
+
+The intent of this document is to state the conditions under which a
+Package may be copied, such that the Copyright Holder maintains some
+semblance of artistic control over the development of the package,
+while giving the users of the package the right to use and distribute
+the Package in a more-or-less customary fashion, plus the right to make
+reasonable modifications.
+
+Definitions:
+
+	"Package" refers to the collection of files distributed by the
+	Copyright Holder, and derivatives of that collection of files
+	created through textual modification.
+
+	"Standard Version" refers to such a Package if it has not been
+	modified, or has been modified in accordance with the wishes
+	of the Copyright Holder as specified below.
+
+	"Copyright Holder" is whoever is named in the copyright or
+	copyrights for the package.
+
+	"You" is you, if you're thinking about copying or distributing
+	this Package.
+
+	"Reasonable copying fee" is whatever you can justify on the
+	basis of media cost, duplication charges, time of people involved,
+	and so on.  (You will not be required to justify it to the
+	Copyright Holder, but only to the computing community at large
+	as a market that must bear the fee.)
+
+	"Freely Available" means that no fee is charged for the item
+	itself, though there may be fees involved in handling the item.
+	It also means that recipients of the item may redistribute it
+	under the same conditions they received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications
+derived from the Public Domain or from the Copyright Holder.  A Package
+modified in such a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided
+that you insert a prominent notice in each changed file stating how and
+when you changed that file, and provided that you do at least ONE of the
+following:
+
+    a) place your modifications in the Public Domain or otherwise make them
+    Freely Available, such as by posting said modifications to Usenet or
+    an equivalent medium, or placing the modifications on a major archive
+    site such as uunet.uu.net, or by allowing the Copyright Holder to include
+    your modifications in the Standard Version of the Package.
+
+    b) use the modified Package only within your corporation or organization.
+
+    c) rename any non-standard executables so the names do not conflict
+    with standard executables, which must also be provided, and provide
+    a separate manual page for each non-standard executable that clearly
+    documents how it differs from the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or
+executable form, provided that you do at least ONE of the following:
+
+    a) distribute a Standard Version of the executables and library files,
+    together with instructions (in the manual page or equivalent) on where
+    to get the Standard Version.
+
+    b) accompany the distribution with the machine-readable source of
+    the Package with your modifications.
+
+    c) give non-standard executables non-standard names, and clearly
+    document the differences in manual pages (or equivalent), together
+    with instructions on where to get the Standard Version.
+
+    d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package.  You may charge any fee you choose for support of this
+Package.  You may not charge a fee for this Package itself.  However,
+you may distribute this Package in aggregate with other (possibly
+commercial) programs as part of a larger (possibly commercial) software
+distribution provided that you do not advertise this Package as a
+product of your own.  You may embed this Package's interpreter within
+an executable of yours (by linking); this shall be construed as a mere
+form of aggregation, provided that the complete Standard Version of the
+interpreter is so embedded.
+
+6. The scripts and library files supplied as input to or produced as
+output from the programs of this Package do not automatically fall
+under the copyright of this Package, but belong to whomever generated
+them, and may be sold commercially, and may be aggregated with this
+Package.  If such scripts or library files are aggregated with this
+Package via the so-called "undump" or "unexec" methods of producing a
+binary executable image, then distribution of such an image shall
+neither be construed as a distribution of this Package nor shall it
+fall under the restrictions of Paragraphs 3 and 4, provided that you do
+not represent such an executable image as a Standard Version of this
+Package.
+
+7. C subroutines (or comparably compiled subroutines in other
+languages) supplied by you and linked into this Package in order to
+emulate subroutines and variables of the language defined by this
+Package shall not be considered part of this Package, but are the
+equivalent of input as in Paragraph 6, provided these subroutines do
+not change the language in any way that would cause it to fail the
+regression tests for the language.
+
+8. Aggregation of this Package with a commercial distribution is always
+permitted provided that the use of this Package is embedded; that is,
+when no overt attempt is made to make this Package's interfaces visible
+to the end user of the commercial distribution.  Such use shall not be
+construed as a distribution of this Package.
+
+9. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+				The End
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/Changes
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/Changes	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/Changes	(revision 10506)
@@ -0,0 +1,51 @@
+Fixes in 1.0.6:
+- -f works with binary files
+- w3mir will no longer use 'Referer: (commandline)' when a URL is derived
+  from the commandline/config file.
+- More errormessage fixes
+- Fixed install instructions to warn against LWP 5.40.
+
+Fixes in 1.0.5: 
+- Better error-messaged in -quiet mode 
+- Fixed quoting. Both " and ' quotes in documents are accepted. 
+- Fixed timeout handling. 
+- Fixed broken connection handling. Incomplete documents are 
+  deleted and retried.
+- Fixed URL mangling problem. In 1.0.3 URLs like ``foo.html#bar'' would
+  be rewritten to ``#bar''. This is quite bad and makes a lot of mirrors
+  un-useable. 
+- -v now prints LWPs version as well as w3mirs version
+
+Features/bugs in 1.0.5 
+- As earlier, w3mir does not support cookies. I have received a patch for
+  basic cookie support but have not yet incorporated it due to
+  time-restraints.
+- There actually exists web servers that break the HTTP standard rather
+  thoroughly by not sending a Content-type header (this is mandatory in
+  the standard). W3mir will not discover that a HTML file is HTML in this
+  case and will not extract URLs from it.
+- If you rewrite the ending filename URLs with Apply rules (as in 
+  index.htm -> index.html) and there are links to index.htm#foo the link
+  will be incorrect after mirroring. The solution is to avoid those
+  kinds of rules. This was meant to be fixed in 1.0.3 (which broke it as
+  described above), I will fix it when I get more time. The fix is to
+  remove the #fragment part of URLs when they pass thru the apply
+  machinery. Patches accepted. 
+
+Fixes in 1.0.3: 
+- The -R/remove option to remove files is no longer more destructive
+  than intended.
+- Files with 'unsafe' characters in their filename is now saved as
+  "foo bar" instead of "foo%20bar" 
+- The -B switch works once again. 
+
+Fixes in 1.0.2: 
+- W3mir now only newline converts HTML files, all other files are handled
+  as binary. This should ensure file-integrety even when working with
+   mis-configured servers. 
+
+Fixes in 1.0.1: 
+-fa option and corresponding configuration file directive works again. 
+- Added -nnc option and a corresponding configuration file directive. It
+  disables newline conversions, which could corrupt files the Webserver
+  mis-declares. The HOWTO explains the uses of -nnc 
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL	(revision 10506)
@@ -0,0 +1,117 @@
+This is how you install w3mir on a Unix system. Please see the file
+INSTALL.w32 for install instructions for win32 systems.
+
+INSTALLING PREREQUISITES:
+
+The prerequisites are the perl packages libwww-perl, and MIME-Base64.
+The w3mir install procedure will check for their presence and complain
+if they are not there, so if you are unsure what you have you might
+skip this part for now.
+
+- Get libwww-perl from CPAN 
+  (http://www.perl.com/CPAN/modules/by-module/WWW/).  W3mir does not work
+  with LWP 5.40 and later versions.  Please get an earlier version.
+  It also does not work with the new URI package.  Use the URI package
+  enclosed in the older LWP.
+
+- Unpack it:
+
+    gzip -dc libwww-perl-*.tar.gz | tar xvBf -
+
+- Install it.  W3mir does not require the whole libwww-perl package and
+  all the packages that goes with it to work so you may follow these
+  install instructions instead of the libwww-perl install instructions
+  to get an easier install which will work with w3mir.
+
+    cd libwww-perl-*
+
+  Are you going to install it in the standard perl place (you need to
+  be the system administrator to do this)? If so:
+
+    perl Makefile.PL
+
+  If not (if you are a user):
+
+    perl Makefile.PL PREFIX=/some/dir
+
+  /some/dir could be ~ (as in your home directory).
+
+  IF you are installing an old LWP just for w3mir you can install both
+  the old LWP, the Base64 module and w3mir in a special PREFIX
+  separate from your usual install PREFIX.  This ensures that w3mir will
+  access the older version of LWP and that other software will access
+  the newer version.  If you do this make sure you install all of LWP,
+  Base64 and w3mir with the same PREFIX.
+
+  This step might produce some complaints;  A standard perl
+  installation will typically get messages about missing these
+  modules: IO::Socket, NET::FTP and MD5.  None of these need be
+  installed to run w3mir and so any error messages about these may
+  safely be ignored.
+
+    make
+    make test      (robot/ua and local/http might fail, that's OK)
+    make install
+
+  Now libwww-perl should be installed and working.
+
+- You also have to get the MIME-Base64 package
+  (http://www.perl.com/CPAN/modules/by-module/MIME/)
+
+- Unpack it:
+
+    gzip -dc MIME-Base64-*.tar.gz | tar xvBf -
+
+- Install it:
+
+    cd MIME-Base64-*
+
+  Then, as above, either
+
+    perl Makefile.PL
+
+  or
+
+    perl Makefile.PL PREFIX=/some/dir
+
+  Continue:
+
+    make
+    make test      (it should print 'All tests successful.')
+    make install
+
+  Now MIME-Base64 should be installed and working.
+
+INSTALLING W3MIR:
+
+- Get w3mir (http://www.math.uio.no/~janl/w3mir/ or from CPAN)
+
+- Unpack it:
+
+     gzip -dc w3mir-*.tar.gz | tar xvBf -
+
+- Install it:
+
+     cd w3mir-*
+
+  Are you going to install it in the standard perl place? (You
+  probably need to be the system administrator to do this.)  If so:
+
+    perl Makefile.PL
+
+  If not (if you're a user):
+
+    perl Makefile.PL PREFIX=/some/dir
+
+  /some/dir could be ~ (as in your home directory).
+
+  then
+
+     make
+     make install
+
+w3mir should now be installed correctly.  And if it's installed in
+your path you can even run it.  If you use csh or tcsh you want to run
+'rehash' before the shell will find it.
+
+1999/04/14 - Nicolai Langfeldt
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL.w32
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL.w32	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/INSTALL.w32	(revision 10506)
@@ -0,0 +1,92 @@
+This file contains installation instructions for two different ports
+of Perl to win32.  One port is known as the 'ActivePerl' port, the
+other is known as 'the GS port'.
+
+********************************* ActivePerl **********************************
+
+This was written and submitted by Roland Bauer.  Thanks.  I have
+edited them slightly.
+
+How to install w3mir on Win95/AS-port (April 1999):
+===================================================
+
++ get and install winzip from http://www.winzip.com/
++ get and install ActivePerl (now Build 509) from http://www.activestate.com/
++ get nmake.exe from 
+  ftp://ftp.microsoft.com/Softlib/MSLFILES/nmake15.exe
+  (or set switch make=nmake to make=dmake in Config.pm
+  and get dmake from GS port)
+
++ perl makefile.pl
++ nmake
++ nmake install
+
++ perl w3mir -h
++ perl w3mir http://xx.zz.zz/dir/
+
+
+Caveats:
+========
+
++ archive 1.0.6 from CPAN seems to be corrupted
+
++ &mkdir does not seem to work with dos-paths
+like 'D:/DIR1/DIR2'
+(so it is not possible to save to another harddisk)
+
+*********************************** GS Perl ***********************************
+
+These win32 installation instructions were written by Paul Hsiao and
+slightly edited by me. My thanks to Paul. It was current as of
+22-May-1998.
+
+
+WINZIP DOWNLOAD INSTRUCTIONS
+
+    The WinZip program can be accessed from the "Start" button, if the
+    program came with your system.  This software can be obtained from:
+ 
+                http://www.winzip.com/
+ 
+    Follow the installation instructions for the WinZip software as needed.
+
+ 
+PERL DOWNLOAD INSTRUCTIONS
+ 
+    The w3mir code will need access to version 5.003 or higher of the 
+    Perl interpreter and LWP library extensions in order for it to run. 
+    This software can be obtained from:
+ 
+                ftp://sunsite.uio.no/pub/languages/perl/CPAN/ports/win32/Standard
+ 
+    From this URL, select perl5.00402-bindist04-bc.tar.gz and download
+    to your PC into a folder of your choice.  In the folder, run WinZip
+    on this file.  For MS Windows 95, you need to update the registration: 
+    open C:\autoexec.bat  and add a line
+
+                path %path%;C:\Perl\bin;       
+    (C:\Perl\ is the path of the perl folder)  
+
+
+W3MIR DOWNLOAD AND INSTALLATION INSTRUCTIONS
+
+    You already have w3mir. Right? Unpack the .tar.gz file with
+    winzip.
+ 
+    Open a DOS prompt screen and go to the w3mir folder:
+ 
+        cd C:\w3mir-1.0.3
+ 
+    Type the install command for w3mir:
+ 
+        perl.exe Makefile.PL
+        make
+        make install
+ 
+    To test w3mir, type:
+ 
+    perl w3mir -h
+ 
+    If the screen displays all options (about 25 options), then 
+    w3mir is installed correctly.
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/MANIFEST
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/MANIFEST	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/MANIFEST	(revision 10506)
@@ -0,0 +1,15 @@
+Artistic
+Changes
+INSTALL
+INSTALL.w32
+MANIFEST
+Makefile.PL
+README
+example.cfg
+multiscope.cfg
+w3mir.PL
+w3mir-HOWTO.html
+w3mfix.PL
+htmlop.pm
+w3http.pm
+w3pdfuri.pm
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/Makefile.PL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/Makefile.PL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/Makefile.PL	(revision 10506)
@@ -0,0 +1,116 @@
+# -*-perl-*-
+# Makefile.PL for w3mir.
+# Note that the file 'MANIFEST' is quite significant in this context
+#
+# Notes:  Should unpack any tar.gz files in current directory and install
+#   them with identical arguments to Makefile.PL to this invocation.
+#   This is especially for making installation of w3mir easy 
+#   by installing libwww-perl and mime-base64 for the user before
+#   installing w3mir.  Cool eh?  That would require some changes.
+#
+# - janl 18/4/1997
+#
+# 19/04/99 janl: Added 'clean' target on tip from  Lupe Christoph
+#	and LWP max-version check to the LWP detection.
+# 
+
+# First just write the Makefile
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+    NAME	=> 'w3mir',
+    VERSION_FROM => 'w3mir.PL', # finds $VERSION
+    EXE_FILES => [ 'w3mir', 'w3mfix' ],
+    clean => { FILES => 'w3mir w3mfix' },
+    dist => { COMPRESS => 'gzip -f9', SUFFIX => 'gz' },
+);
+
+print "\n";
+
+# Find value of INSTALLSITELIB
+
+&read_makefile;
+$islib = resolve_make_var('INSTALLSITELIB');
+
+# Check for prerequisites
+
+$| = 1;
+my $missing_modules = 0;
+
+# libwww-perl
+print "Checking for libwww-perl:";
+
+eval "use lib '$islib'; require LWP;";
+
+if (!defined($LWP::VERSION)) {
+  print ' failed
+
+libwww seems to be missing.
+
+';
+  $missing_modules++;
+  sleep(2);
+} elsif ($LWP::VERSION<5.08 or $LWP::VERSION>=5.40) {
+  print ' failed
+
+libwww is version ',$LWP::VERSION,', I need version 5.08 to 5.39.
+Please see the INSTALL file.
+
+';
+  $missing_modules++;
+  sleep(2);
+} else {  
+  print " ok\n\n";
+}
+
+# MIME::Base64
+print "Checking for MIME::Base64:";
+
+eval "use lib '$islib'; require MIME::Base64;";
+
+if (!defined(&MIME::Base64::encode)) {
+  print ' failed
+
+MIME::Base64 seems to be missing.
+
+';
+  $missing_modules++;
+  sleep(2);
+} else {
+  print " ok\n\n";
+}
+
+
+print 'Please see the INSTALL file for instructions on how to get the
+missing/too old modules.
+
+' if $missing_modules;
+
+
+sub resolve_make_var ($) {
+
+  my($var) = shift @_;
+  my($val) = $make{$var};
+
+#  print "Resolving: ",$var,"=",$val,"\n";
+  
+  while ($val =~ s~\$\((\S+)\)~$make{$1}~g) {}
+#  print "Resolved: $var: $make{$var} -> $val\n";
+  $val;
+}
+
+
+sub read_makefile {
+
+  open(MAKEFILE, 'Makefile') || 
+    die "Could not open Makefile for reading: $!\n";
+
+  while (<MAKEFILE>) {
+    chomp;
+    next unless m/^([A-Z]+)\s*=\s*(\S+)$/;
+    $make{$1}=$2;
+#    print "Makevar: $1 = $2\n";
+  }
+
+  close(MAKEFILE)
+}
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/README	(revision 10506)
@@ -0,0 +1,133 @@
+PROPAGANDA:
+
+See http://www.math.uio.no/~janl/w3mir/ for propaganda.
+
+--------------------------------------------------------------------------
+Q: Where can I get a new version of w3mir?
+A: The w3mir homepage is at http://www.math.uio.no/~janl/w3mir/.
+   W3mir is also distributed on CPAN: http://www.perl.com/
+
+Q: Are there any mailing lists?
+A: Yes, see below.
+
+Q: Should I subscribe to any of the mailinglists?
+A: Yes, if you use w3mir at all you should subscribe to 
+   w3mir-info@usit.uio.no, send e-mail to janl@math.uio.no to be
+   subscribed.
+
+Q: I found a bug!
+A: See below.
+
+Q: How do it...
+A: There is a w3mir-HOWTO.html file in the distribution.  Read it.
+
+--------------------------------------------------------------------------
+BUGS:
+
+- -lc switch does not work too well.
+
+Please see below for how to report bugs.
+
+--------------------------------------------------------------------------
+FEATURES (NOT bugs):
+
+- URLs with two /es ('//') in the path component does not work
+  as some might expect.  According to my reading of the http/url spec.
+  it is an illegal construct, which is a Good Thing, because I don't
+  know how to handle it if it's legal.
+- If you start at http://foo/bar/ then index.html might be gotten twice.
+- Some documents point to a point above the server root, i.e.,
+  http://some.server/../stuff.html.  Netscape, and other browsers, in
+  defiance of the URL standard documents will change the URL to
+  http://some.server/stuff.html.  W3mir will not.
+
+--------------------------------------------------------------------------
+MAIL LISTS, REPORTING BUGS:
+
+Please send ideas (see todo lists further down please) and bug reports
+to w3mir-core@usit.uio.no, please include URL and command line/config
+file that triggered the bug. w3mir-info@usit.uio.no is mainly used for
+announcing new versions or bugs to w3mir users. You will get more
+information following that list than anywhere else. And it's very low
+volume. To subscribe to these lists email janl@math.uio.no. The
+w3mir-core list is intended for w3mir hackers only.
+
+--------------------------------------------------------------------------
+COPYRIGTHS:
+
+w3mir, w3http.pm, w3pdfuri.pm and htmlop.pm are free but it is
+Copyrighted by the various involved hackers.  If you want to copy,
+hack or distribte w3mir you can do that providing you comply with the
+'Artistic License' enclosed in the w3mir distribution in the file
+named Artistic.
+
+--------------------------------------------------------------------------
+CREDITS:
+
+- Oscar Nierstrasz: Wrote htget
+- Gorm Haug Eriksen: Started w3mir on the foundations of htget,
+	contributed code later.
+- Nicolai Langfeldt: Learning from Oscar and Gorms mistakes, rewrote
+  everything.
+- Chris Szurgot: Adapting to win32, good ideas and code contribs, 
+  Debugging.  And criticism.
+- Rik Faith: Uses w3mir extensively, not shy about complaining and
+  commenting and suggesting.  
+- The libwww-perl author(s) that made adding some new featres
+  ridicolously easy.
+
+--------------------------------------------------------------------------
+TODO LIST:
+
+* TODO, version 1.1:
+
+Some of these are speculative, some others are very useful.
+
+- CSS parsing/support at the same level as HTML
+- Full support for APPLETS/OBJECT tags.
+- Alias rules.  These would enable w3mir to map ukoln.bath.ac.uk and 
+  bubl.bath.ac.uk to www.ukoln.ac.uk and know that the objects contained
+  in these are all the same.  Another use would be to mirror from a mirror
+  instead of the _real_ site, since the original site to which you have
+  references are on a slow link while the mirror is on a fast link.
+- FTP support (easy if through a http style ftp proxy, but is that what
+  we want?)
+- SHTTP/SSL support
+- Add a 3rd argument to URL/Also that denotes the depth of documents to
+  be retrived under each, this would autimatically generate fetch/ignore
+  rules.  How well these work would be dependent on the order of the
+  URL/Also directives though.  Must be documented.
+- Retrive recursively until N-th order links are reached.  This
+  differs siginificantly from directory recursion which we do now.  When
+  this is done w3mir should also know the difference between inline and
+  external links, inline links should always be retrived.  Trivia question:
+  What order is needed to reach every findable document on the web from
+  Yahoo?
+- Integrate with cvs or rcs (or other version controll system) to make
+  retriver able to reproduce mirrored site for any given date.
+- Some text processing:  Adding and removing text/sgml comments when suitable
+  options and tags are found.
+- Put retrival date-stamps as comments in html files, to document the when
+  and how of how this document was retrived.
+- Example: If you're mirroring a site primarily to get to the papers, but
+  the site has n versions of each paper: foo.ps.gz, foo.ps.Z, foo.dvi.gz
+  foo.dvi.Z, foo.tar.gz, foo.zip and you only need one version.  Implement
+  a way to get only one version of documents provided in multipele versions,
+  something like multi axis preference list to get only the most attractive
+  version of the doc.
+- Logging of retrivals to file, need to change every print to a functioncall.
+- Your suggestion here.
+
+* TODO, http related
+- Use Keep-alive.  Then we should probably stop using 30 second pauses
+  between document retrivals.
+- HTTP/1.1?  HTTP/1.1 servers should do keep-alive even with 1.0 requests.
+- Separate quenes for each server, interleave requests.
+- Authentication is only done if challenged now.  If a document in a
+  directory needs authentication it is very likely that all other documents
+  in that directory and subdirectories require authentication.
+
+* If perl gets threads:
+- Make the retrival and analysis engines separate threads, and have each
+  one retrival thread pr. method/server/port and do paralell retrivals.
+- This makes http/1.1 easier too.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/example.cfg
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/example.cfg	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/example.cfg	(revision 10506)
@@ -0,0 +1,120 @@
+# This is a example w3mir config file.  The file and options are fully
+# documented in the w3mir man page, and a lot is spelled out in the 
+# w3mir-HOWTO.  This file might not be completely updated, but the man
+# page should be.
+#
+# Comment lines start with '#'.  Comments are not allowed at end of
+# lines.  The keywords are not casesensitive, but some settings are,
+# notably fetch/ignore/apply settings, as well as the urls given.
+#
+# Available options: recurse, no-date-check, only-nonexistent, list-urls,
+# lowercase.  It is not default to recurse.  Options must be the
+# first directive to appear in the config file.
+# The options directive needs to be the first directive in the config file
+# and there can only be one.
+Options: recurse
+# Multipele options:
+# Options: recurse, only-nonexistent
+# This directive was previously named 'Fetch-options'
+#
+# Start here:
+URL: http://www.stud.ifi.uio.no/~janl/
+#
+#
+# How much noise to make, one of quiet, brief or chatty.  Default is brief
+#Verbosity: brief
+#
+# Initial referer.  Some servers are very picky....
+#Initial-Referer: http://foo.bar/
+#
+# Headers to disable for anonymitys sake: 
+#Disable-headers: referer, user
+#
+# Nicenes, robotrules can be true or false
+#Robot-Rules: true
+# Default pause between http connections is now 0 seconds 
+# Pause: 0
+# Pause between retries, in seconds.  If w3mir runs as a once-a-day thing
+# this can and should be high.  I suggest at least one hour (3600 seconds).
+#Retry-Pause: 600
+# How many times a failed retrival is retried.
+#Retries: 3
+#
+# URL selection.  Order is significant, first Fetch/Ignore rule overrides
+# later rules.  Supply as many as you want.  If not matched by ignore rules
+# a doc is gotten.  
+#Fetch: *.html
+#
+# Ignore urls we can't copy anyway.  Actually w3mir can copy
+# many cgi things with no problems.  But not always.
+Ignore: *.cgi
+Ignore: *-cgi
+Ignore: *.map
+#
+# RE variants are full perl REs.  Mix freely with the others.  These
+# must be legal perl REs, including the starting m and any
+# options you want, like 'i'.
+#
+#Fetch-RE: m/jpeg/
+#Ignore-RE: m/\.gif$/
+#
+# URL manipulation.  _All_ rules are applied in order.  If lowercasing
+# options is given that is done first.  This must be a legal perl
+# substitution RE.  Including the starting s and any options you want,
+# like 'g' and 'i'.
+#
+# This changes the name of all .gif files to .fif
+#Apply: s/\.gif$/.fif/
+#
+# HTTP Proxy server:
+#HTTP-Proxy: www-cache.uio.no:3128
+#
+# HTTP Proxy options: 
+# - 'revalidate': Force proxy to revalidate cached documents.
+# - 'refresh': Force proxy to get cached documents from server _again_.
+# - 'no-store': Use if the contents of the documents is sensitive.
+# - 'no-pragma': Force use of HTTP/1.1 'Cache-Control:' header.
+# If only 'refresh' is specified the default is to use the 'Pragma: no-cache'
+# HTTP/1.0 header, this can be overruled with the 'no-pragma' option.
+# You can be fairly sure any proxy will understand 'refresh', ONLY HTTP/1.1
+# proxies will understand 'revalidate' and 'no-store'.
+#proxy-options: refresh
+#
+# HTTP Proxy authentication.  The mechanism  is simpleminded, we either need
+# to authenticate ourselves with the proxy or not, and there can only be
+# one user/password tuple, domain/realm information is ignored...
+# HTTP-Proxy-user: foo
+# HTTP-Proxy-passwd: bar
+#
+# What to do with files, one of save, stdout or forget.
+#File-disposition: save
+#
+# Debug level
+#Debug: 0|1|2
+#
+# Umask, if not the default
+#Umask: 077
+#
+# HTML document editing options
+#Header: Mirrored from http://www.ifi.uio.no/~janl/ts/
+#Remove-nomirror: true
+#
+# Authentication:
+#Auth-domain: server:port/realm
+#Auth-user: me
+#Auth-passwd: my_password
+#
+# You can use '*' in place of server:port and/or realm:
+#Auth-domain: */*
+#Auth-user: otherme
+#Auth-passwd: otherpassword
+#
+
+# 'Fixup' is done by the external w3mfix program.  If you want a
+# mirror that's browseable in a filesystem (as opposed to via a http
+# server) just put this in:
+Fixup: run
+
+# Related is this, what is the name of the file the http server serves
+# when a directory URL is requested?  w3mir default is index.html.
+#Index-name: welcome.html
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/htmlop.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/htmlop.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/htmlop.pm	(revision 10506)
@@ -0,0 +1,656 @@
+# -*-perl-*-
+# htmlop.pl: Do operations on html documents.
+$VERSION=0.2.4;
+#
+# Original source from Bjørn Borud, without it I would not have atempted
+# this. In this incarnation it bears no resemblance to Bjørns code.
+# - Nicolai Langfeldt 18/11/95.
+# 
+# htmlop.pl does operations on html files, possebly many at a time.
+# Operations:
+# - Absolitify urls
+# - Relativify urls
+# - Gather list of urls
+# - Callback with url
+# - Canonify document w.r.t. SGML.
+#
+# Authors:
+# - Nicolai Langfeldt (janl@ifi.uio.no)
+# - Chris Szurgot (szurgot@itribe.net)
+#
+# Changes:
+# janl    18/11/95 - Initial version
+# szurgot 09/02/96 - Code in htmlop'process to remove <BASE> Tag if we are 
+#                    returning the form. An unchanged base destroys local 
+#                    fragments.
+# janl    22/02/96 - Added URLSUB functions.  <BASE> will only be removed from
+#		     the returned doc, never from the origninal doc.
+# janl    16/05/96 - Removed I* options and added single NODOC option/modifier
+#		     to replace them.
+# janl	  09/09/96 - Added URLPROC and NREL opcodes, for a better URL
+#		     processing model. -> 0.1.7
+# janl    24/09/96 - Various cosmetics, no longer inserting a !SGML tag,
+#		     only !DOCTYPE and HTML tags. -> 0.1.8
+# janl    11/10/96 - URLs in HTML 3.2 tags are now found.
+# janl     6/11/96 - Added netscape SCRIPT tag.
+# janl    20/11/96 - 'BORDER' is different from 'BORDER=0' -> 0.1.10
+# janl    06/11/96 - Added userdata argument to URLPROC.
+#   			Added SAVEURLS and USESAVED opcodes. -> 0.1.11
+# janl    11/04/97 - Changed to URI::URL and got into strict harness
+# janl	  13/04/97 - Fixed comment processing, extended it to processing
+#			directives. Bug reported by Chris Johnson. -> 0.1.12
+# janl    08/04/97 - Made ISMAP into ISMAP=, bad! -> 0.1.13
+# janl	  23/05/97 - Treating <script> and <style> as verbatim -> 0.1.14
+# janl	  06/06/97 - Canonify: <!SGML tag confused it and !DOCTYPE was mangled
+#			-> 0.1.15
+# janl	  30/07/97 - Now supporting <BASE> tag.
+#		   - Added TAGCALLBACK opcode -> 0.1.16
+# janl    16/10/97 - Empty string must be quoted, reported by Bart Barenburg
+#			-> 0.1.17
+# janl	  01/12/97 - More HTML URL tags/attributes recognized (Greg Lindhorst) 
+# janl	  13/12/97 - Can't delete the whole <BASE> tag.  Netscape has
+#		     extended it for frame use.  So only delete the HREF
+#		     attr -> 0.1.18
+# janl    01/01/98 - Realized applet/object support can't work and changed
+#		     so it's able to work, if conditions are right.
+# janl    04/01/98 - Added html 4.0 tags and attributes.
+# janl    08/02/98 - Hacked for speed.  Went from 43s to 9s on a 170K
+#		     document -> 0.2.  Thanks to Rune Frøysa who taunted me.
+# janl	  09/04/98 - More tolerant about what constitutes a newline -> 0.2.1
+# janl	  09/05/98 - Export %isdir -> 0.2.2
+# janl    13/04/99 - Remove leading /../ sequences in path component in
+#		     ABS code. -> 0.2.3
+# janl    28/05/99 - The code was buggy, now it's not. -> 0.2.4
+
+package htmlop;
+
+use URI::URL;
+
+use strict;
+# Global variables
+use vars qw($ABS $REL $LIST $CANON $URLSUB $NODOC $URLPROC $NREL);
+use vars qw($SAVEURL $USESAVED $TAGCALLBACK $debug %isdir);
+
+# These are for the smartrel routines
+my $url_origin;
+my $doc_top;
+my $doc_top_re;
+my $choped_url_or;
+
+# HTML operation codes for process_html.  The first argument is the
+# html document to do operations on.  It will not be changed.  If
+# NODOC is not passed a new document edited as specified will be
+# returned.  No more than one document will be returned by one
+# invocation of htmlop.
+
+$ABS = 1;			# Absolutify urls. Arg: Origin. The
+                                # ABS function absolutifies URLS,
+                                # assuming they are relative to the
+                                # argument.
+				# If a <BASE> tag is found the origin
+				# given by it will be used instead of
+				# the arguemnt given.
+
+$REL = 2;			# Relativize all urls. Arg: Origin.
+                                # The REL function simply removes the
+                                # argument string from any urls
+                                # matching it.  For this reason the
+                                # origin string is interprated as a
+                                # RE, which may have unexpected
+                                # results, unless RE specials are
+                                # escaped, which they should be.
+
+$LIST = 3;			# List all urls, Ret: urls
+
+$CANON = 4;			# See that missing opening (and
+                                # ending) SGML tags are injected.
+
+$URLSUB = 5;			# Do regular expression substitution
+                                # on urls.  Arg: RE, substitute.
+
+$NODOC = 6;			# Do not return a rebuilt document.
+                                # Saves memory, and time
+
+# NOTE: I SUSPECT URLPROC IS BROKEN IF A BASE TAG APPEARS IN THE TEXT.
+# THE URL PROCESSOR NEEDS TO BE PASSED htmlop::process' IDEA OF WHAT THE
+# BASE URL IS.
+
+$URLPROC = 7;			# Apply function on urls (process
+                                # urls).  Arg: Pointer to function to
+				# apply, userdata.  The function will
+				# be passed the url, modified by any
+				# previous operations and the
+				# userdata.  The function must return
+				# the new url.
+
+$NREL = 8;			# New relativisation function, works
+                                # much better than the old one. Arg:
+                                # Origin, Top.
+
+$SAVEURL = 9;			# Save urls in tag with modified name.
+				# Arg: attribute prefix.
+				# Example: <a href=foo> becomes
+				# <a href=foo w3mir-href=foo> if no other
+				# processing of the url is done.
+
+$USESAVED = 10;			# Use saved urls. Arg: attribute prefix
+
+$TAGCALLBACK = 11;		# Procedure to call for each Tag.
+				# Args: procedure, userdata (one item)
+
+				# Args to procedure: userdata, Base
+				# URL, tag name, reference to array of
+				# URL attributes, reference to hash of
+				# all attributes.  The base url is
+				# derived from the one used in ABS or
+				# the BASE tag.
+
+$debug=0;			# Debugging level in this package
+
+# process_html returns a array.  The first component of the array is
+# the new html document. The rest of the array is the urls.  If a
+# document is not to be returned a empty string is returned. If a url
+# list is not to be returned a empty array is returned.
+
+# HERE BE DRAGONS:
+
+# Where to find URLs in various tags.  The second compoent is a array
+# reference.
+
+my(%urls) = (
+	HEAD    => [ 'PROFILE' ],
+        BLOCKQUOTE => [ 'CITE' ],
+        Q 	=> [ 'CITE' ],
+        INS	=> [ 'CITE' ],
+	DEL	=> [ 'CITE' ],
+	A	=> [ 'HREF' ] ,
+	IMG	=> [ 'SRC' ,'LOWSRC' ,'USEMAP', 'LONGDESC' ] ,
+	EMBED	=> [ 'SRC' ],
+	FRAME	=> [ 'SRC', 'LONGDESC' ],
+        IFRAME  => [ 'SRC', 'LONGDESC' ],
+	BODY	=> [ 'BACKGROUND' ],
+	AREA	=> [ 'HREF' ],
+	LINK	=> [ 'HREF' ],
+
+	# The APPLET and OBJECT tags do not fit into my model for URL
+	# manipulation.  Just looking at CODEBASE might work, if the
+	# URL it names is a browseable directory...
+	APPLET	=> [ 'CODEBASE' ],  # If the codebase dir is browseable
+	OBJECT  => [ 'CODEBASE' ],  # Ditto.  Can't handle DATA attribute now
+
+	INPUT	=> [ 'SRC', 'USEMAP' ],
+	MAP	=> [ 'HREF' ],
+	SCRIPT	=> [ 'SRC', 'FOR' ],# 'FOR's semantics is not defined, the
+				    # attribute is just reserved for possible
+				    # future use...
+	BGSOUND => [ 'SRC' ],
+	FORM	=> [ 'ACTION' ],    # Is this asking for trouble?
+				    # Maybe it should just be absolutized...
+	     			    # On the other hand: It's CGI...
+	);
+
+my(%relative) = (
+	# Identify URL attributes containing urls that are relative to
+	# the named URL attribute.   When processing these they should
+        # be absolitized and then relativized relative to the BASE attribute.
+        # This is just window dressing for now; it is not used for anything.
+
+	# ARCHIVE is really a URI _list_.
+	CODEBASE => [ 'CLASSID', 'DATA', 'CODE', 'ARCHIVE' ],
+        );
+
+%isdir = (
+	# These tags refer to directories:
+	CODEBASE => 1
+	);
+
+# Tags that enclose bits we want to leave absolutely alone because they
+# are not very like HTML, or some such.
+
+# The material between the start and end tags is copied with no
+# processing at all.  The end tag is left to be processed.
+# The endtag match is case insensitive.
+my(%verbatim) = (
+        SCRIPT	=> quotemeta('</SCRIPT>'),	# Embeded scripts
+	STYLE	=> quotemeta('</STYLE>'),	# Embeded stylesheet
+	);
+
+# These are the functions that pick the HTML to pieces.  It will not
+# work esp. good on a random SGML document since the HTML application
+# of SGML has simpler quoting than it might.
+
+sub gettoken {
+  # Get one token from the argument, removing it from the argument.
+  # BUG: There should be whitespace at the end of the examined string.
+  my($c,$token,$i);
+  
+  # Skip whitespace and newlines
+  return '' unless defined(@_) && defined($_[0]);
+  $_[0] =~ s/^[\r\n\s]*//;
+  
+  return '' if ($_[0] eq '');
+  
+  $c = substr($_[0],0,1);
+  substr($_[0],0,1)='';
+  
+  if ($c eq '"' || $c eq "\'") { # Quoted material
+    $i=index($_[0],$c);
+    # End-quote missing, just gobble the rest of the doc
+    $i=length($_[0]) if $i == -1;
+    # Extract and remove token
+    $token=substr($_[0],0,$i);
+    substr($_[0],0,$i+1)='';
+  } elsif ($c eq '=') {
+    $token='=';
+  } else {			# Non-quoted material, ends in whitespace or =
+    $_[0] =~ m/[=\s\n\r]/;
+    $_[0] = $&.$';
+    $token=$c.$`;
+  }
+  # print "Token: '$token'\t\tRest: '",$_[0],"'\n";
+  return $token;
+}
+
+
+sub tagtoken {
+  # Pick the tag to pieces (also knonw as tokens). Return an
+  # associative array of attributes.  The attribute-names are changed
+  # to uppercase.  The attribute-values are left as is.
+  my($tok,$lasttok,%tokens);
+  # Append a space, gettoken needs it - silly? Yes! 
+  # Change it to test on boundrary things rather than ...?
+  $_[0].=' ';
+
+  $lasttok='';
+  while (1) {
+    last if (($tok=uc &gettoken($_[0])) eq '');
+
+    if ($tok eq '=') {
+#      print STDERR " -bad html-" if ($lasttok eq '');
+      $tokens{$lasttok}.=&gettoken($_[0]);
+      print STDERR "STORED: $lasttok = ",$tokens{$lasttok},"\n" if $debug;
+    } else {
+      $tokens{$tok}=undef;
+      $lasttok=$tok;
+    }
+  }
+  return %tokens;
+}
+
+
+sub gettag {
+  # Pick out the following things from the remaining html doc:
+  # Everything leading up to the first tag.  The first tag, and its
+  # contents.  Modify @_ directly to reduce number of copies of
+  # possebly huge documents kept in memory at once.  Return the body,
+  # the tag name, and the attributes (associative array)
+  my(%attr,$tagn,$tagc,$body,$tag,$doc);
+
+  $doc=\$_[0];
+
+  my($start,$end,$length);
+  
+  $start=index($$doc,'<');
+
+  if ($start<$[) {
+    # EOF
+    $body=$$doc;
+    $$doc='';
+    return ($body,'',());
+  }
+
+  $end=index($$doc,'>',$start+1);
+  
+  if ($end<$[) {
+    # This sucks, found no end of the tag...
+    $body=$$doc;
+    $$doc='';
+    return ($body,'',());
+  }
+
+  $length=$end-$start-1;
+
+  $body=substr($$doc,0,$start);
+  $tag=substr($$doc,$start+1,$length);
+
+  # This shortens the string in each itteration, some kind of mechanism
+  # to do it once in a while would speed things up further.  HOWEVER, when
+  # I tried to code this all I got was a _nasty_ memory leak.
+  substr($$doc,0,$end+1)='';
+
+#  print STDERR "------\n";
+  
+#  print STDERR "BODY: /$body/\n";
+  print STDERR "COMPLETE TAG: /$tag/\n" if $debug;
+#  print STDERR "REST: /",substr($$doc,0,20),"/\n";
+
+#  print STDERR "------\n";
+
+  # Examine tag contents
+  if ($tag =~ /^([!?]--)/ || $tag =~ /^(!\w+)/) {
+    # Comment or processing dicective, handle specially
+    $tagn=$&;
+    $tagc=$';
+    return ($body,$tagn,("$tagc",undef));
+  }
+
+  # Everything else
+  ($tagn,$tagc) = split(/[\s\n\r]+/,$tag,2);
+  $tagn="\U$tagn";
+
+  return ($body,$tagn,()) if !defined($tagc);
+  
+  return ($body,$tagn,&tagtoken($tagc));
+}
+
+
+# This is meant for general consumption:
+
+sub process {
+  # Process a html file.  Into one end you put a html file.  Out
+  # of the other end you get something dependent on the operations
+  # you specified.
+  # I cannot gobble my arguments. I need to examine them several times.
+  
+  my($arg,$doc,$i,$retdoc,$canon,$newdoc,@urllist,$Q,$cont);
+  my($origin,$baseurl);
+  
+  $origin=$baseurl='';
+
+  $retdoc=$canon=0;
+  
+  # Get the document from the argument list
+  $doc=shift(@_);
+  
+  $retdoc=1;
+  $i=0;
+  # Argument checking
+  while (defined($arg=$_[$i++])) {
+    if (! ($arg =~ /^\d+$/)) {
+      print STDERR "ERROR IN HTMLOP::process:\n";
+      print STDERR "Args: ",join(',',@_),"\n";
+      print STDERR "ARG: $arg is not a opcode.\n";
+      exit(1);
+    }
+    if ($arg == $ABS) {
+      $baseurl=$origin=$_[$i++];
+    } elsif ($arg == $REL || $arg == $SAVEURL || $arg == $USESAVED) {
+      $i++; # Skip one arg
+    } elsif ($arg == $URLSUB || $arg == $NREL || $arg == $URLPROC ||
+	     $arg == $TAGCALLBACK ) {
+      $i += 2; # Skip two args
+    } elsif ($arg == $LIST) { 
+      # do nothing
+    } elsif ($arg == $CANON) {
+      $canon=1;
+    } elsif ($arg == $NODOC) {
+      $retdoc=0;
+    } else {
+      die "htmlop: Incorrect invocation of html_process\n";
+    }
+  }
+  
+  my($endhtml)=0;	# Have we seen </html>?
+  my($SGML)=1;		# 1: !DOCTYPE not seen, 2: !DOCTYPE seen, -1: it's OK
+
+  # These are used to store the tag components
+  my($textpart);
+  my($tagname);
+  my(%attrval);
+
+  my($wholetag);	# The whole tag, put together again
+  my($moretag);		# TMP storage of tag attributes
+  my($attr);		# Looping thru attributes, misnomer.
+  my($RE);
+  my($subst);
+  my($prefix);
+  my($fun);		# Function to apply to url
+  my($verbatim)='';
+  my($url_o,$path);		# URL object Used in ABS to remove leading ..
+
+  # Welcome to the machine
+
+  $newdoc='';
+  while ($doc ne '') {
+    ($textpart,$tagname,%attrval)=&gettag($doc);
+    
+    # Process the tag
+    { # Need a way to get out of this, last is my friend
+      # 'Canonize'
+      if ($canon) {
+	$endhtml=1 if ($tagname eq '/HTML');
+	if ($SGML!=-1 && $canon && $tagname ne '!--' && $tagname ne '!SGML') {
+	  $wholetag=$tagname;
+	  $moretag=join('',keys %attrval);
+	  $wholetag.=' '.$moretag if ($moretag ne '');
+	  if ($SGML==1) {
+	    $SGML=2;
+	    if ($tagname eq '!DOCTYPE') {
+	      $tagname=$wholetag;
+	      %attrval=();
+	      last;
+	    }
+
+	    # We have no idea what DTD this doc follows so we put in
+	    # something kinda non-comitting
+	    $newdoc.='<!DOCTYPE HTML PUBLIC "html.dtd">'."\n";
+	  }
+	  if ($SGML==2) {
+	    $SGML=-1;
+	    if ($tagname eq 'HTML') {
+	      $tagname=$wholetag;
+	      %attrval=();
+	      last;
+	    }
+	    $newdoc.='<HTML>'."\n";
+	  }
+	}			# sgml!=-1
+      }				#canon
+
+      # Tack on text part before I bail out, if wanted
+      $newdoc.=$textpart if $retdoc;
+
+      if ($tagname eq 'BASE') {
+	if (exists($attrval{'HREF'})) {
+	  if ($origin) {
+	    $baseurl=(url($attrval{'HREF'})->abs($origin,1))->as_string;
+	  } else {
+	    $baseurl=$attrval{'HREF'};
+	  }
+	  # Get rid of the HREF attribute.  Netscape 4.0 puts (other) stuff
+	  # into BASE that is not found in the HTML 4.0 spec.
+	  delete $attrval{'HREF'};
+	  print STDERR "\nBase tag: $baseurl\n" if $debug;
+	}
+      }
+
+      # URL processing
+      $i=0;
+      while (defined($arg=$_[$i])) {
+	if (! ($arg =~ /^\d+$/)) {
+	  print STDERR "Args: ",join(',',@_),"\n";
+	  print STDERR "ARG: $arg ($i) is not a opcode.\n";
+	  exit(1);
+	}
+	$i++;
+	if ($arg == $ABS) {
+	  $origin=$baseurl || $_[$i++];
+	  $i++;
+	  # Want it to be a URL object
+	  $origin=url $origin unless ref $origin;
+	  print STDERR 'ABS: ',$origin->as_string,"\n" if $debug;
+	  next unless defined($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    if (defined($attrval{$attr})) {
+	      # Ugly: Remove leading /../ sequences in path component
+	      $url_o=url($attrval{$attr})->abs($origin,1);
+	      if (defined($path=$url_o->path)) {
+		# mailto: URLs does not have path components
+		$path =~ s~/\.\.(?=/)~~g;
+		$url_o->path($path);
+	      }
+	      $attrval{$attr}=$url_o->as_string;
+	    }
+	  }
+	} elsif ($arg == $REL) {
+	  $origin=$_[$i++];
+	  # Want it to be a string
+	  $origin=$origin->as_string if ref $origin;
+	  print STDERR 'REL: ',$origin,"\n" if $debug;
+	  next unless defined($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    $attrval{$attr} =~ s/^$origin//
+	      if defined($attrval{$attr});
+	  }
+	} elsif ($arg == $URLSUB) {
+	  $RE=$_[$i++];
+	  $subst=$_[$i++];
+	  warn "URLSUB: $RE -> $subst\n" if $debug;
+	  next unless defined($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    $attrval{$attr} =~ s/$RE/$subst/
+	      if defined($attrval{$attr});
+	  }
+	} elsif ($arg == $LIST) {
+	  warn "LIST;\n" if $debug;
+	  next unless exists($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    if (exists($attrval{$attr})) {
+	      $attrval{$attr}.='/'
+		if $isdir{$attr} && $attrval{$attr} =~ m~[^/]$~;
+	      push(@urllist,$attrval{$attr});
+	    }
+	  }
+	} elsif ($arg == $SAVEURL) {
+	  warn "SAVEURL;\n" if $debug;
+	  $prefix=$_[$i++];
+	  next unless exists($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    $attrval{"$prefix$attr"}=$attrval{$attr}
+	      if defined($attrval{$attr});
+	  }
+	} elsif ($arg == $USESAVED) {
+	  warn "USESAVED;\n" if $debug;
+	  $prefix=$_[$i++];
+	  next unless exists($urls{$tagname});
+	  foreach $attr (@{$urls{$tagname}}) {
+	    $attrval{$attr}=$attrval{"$prefix$attr"}
+	      if (defined($attrval{"$prefix$attr"}));
+	    # bug compatability, drop sometime after w3mir 1.0
+	    $attrval{$attr}=$attrval{"$prefix-$attr"}
+	      if (defined($attrval{"$prefix-$attr"}));
+	  }
+	} elsif ($arg == $NODOC) {
+	  warn "NODOC;\n" if $debug;
+	} elsif ($arg == $CANON) {
+	  warn "CANON;\n" if $debug;
+	} elsif ($arg == $URLPROC || $arg == $NREL) {
+	  # Apply a function to all urls.
+	  # NREL = Special case of $URLPROC, apply internal function.
+	  if ($arg == $URLPROC) {
+	    warn "URLPROC;\n" if $debug;
+	    $fun=$_[$i++];
+	    $arg=$_[$i++];
+	  } else {
+	    $fun=\&smartrel;
+	    $arg=undef;
+	    $url_origin=$_[$i++];
+	    $doc_top=$_[$i++];
+	    $doc_top_re=quotemeta $doc_top;
+	    ($choped_url_or=$url_origin) =~ s/^$doc_top_re//;
+	    warn "NREL $url_origin $doc_top\n" if $debug;
+	  }
+
+	  next unless (defined($urls{$tagname}));
+
+	  foreach $attr (@{$urls{$tagname}}) {
+	    $attrval{$attr}=&$fun($attrval{$attr},$arg)
+	      if defined($attrval{$attr});
+	  }
+	} elsif ($arg == $TAGCALLBACK) {
+	  $fun=$_[$i++];
+	  $arg=$_[$i++];
+	  warn "TAGCALLBACK($tagname);\n" if $debug;
+	  &$fun($arg,$baseurl,$tagname, 
+		(defined($urls{$tagname})?($urls{$tagname}):undef),
+		\%attrval);
+	} else {
+	  print STDERR "Internal error. opcode: $arg, i: $i, args: ",
+	  join(',',@_),"\n";
+	}
+      }
+      last;
+    }
+
+    # That ends URL processing
+
+    # Was this a verbatim leadin tag?  If yes, atempt to fish out text
+    # between here and the end tag, (minimal match) and substitute it
+    # with nothing.  The end tag is kept.  And the fished out text is
+    # re-inserted in the result with no changes.
+
+    $verbatim=$1 
+      if defined($verbatim{$tagname}) &&
+	($doc =~ s/^(.*?)($verbatim{$tagname})/$2/is);
+    
+    # Tack on the tag, if wanted.
+    if ($retdoc) {
+      if ($tagname) {
+	$newdoc.='<'.$tagname;
+	foreach $attr (keys %attrval) {
+	  $newdoc.=' '.$attr;
+	  if (defined($cont=$attrval{$attr})) {
+	    $Q='"';
+	    $Q="'" if $cont =~ m/\"/;
+	    $newdoc.='='.$Q.$cont.$Q;
+	  }
+	}
+	$newdoc.='>'.$verbatim;
+	$verbatim='';
+      }
+    }
+    print STDERR "NEW: $newdoc\n" if $debug > 2;
+  }
+  $newdoc.="</HTML>\n" if ($canon && !$endhtml);
+  return ($newdoc,@urllist);
+}
+
+
+sub smartrel {
+  # 'smart' relativisation function, uses .. to refer to things up to
+  # $doc_top level.  Outside that scope it stays absolute.
+  #
+  # The rel function itself is now in libwww-perl
+  
+  my($url_o)=@_;
+
+  return if (!(defined($url_o) && $url_o));
+  
+  $url_o=url $url_o unless ref $url_o;
+
+#  print STDERR "\nsmartrel: $url_o->as_string\n",
+#                 "    from: $url_origin\n",
+#                 "  within: $doc_top\n";
+  
+  # Check if within scope of our doc
+  $url_o = $url_o->rel($url_origin)
+    if $url_o->as_string =~ m/^$doc_top_re/;
+
+  return $url_o->as_string;
+}
+
+
+sub smart_setup {
+  # Setup routine for smartrel.
+
+  ($url_origin,$doc_top) = @_;
+
+  $url_origin=$url_origin->as_string if ref $url_origin;
+  $doc_top=$doc_top->as_string if ref $doc_top;
+
+  $doc_top_re=quotemeta $doc_top;
+
+  ($choped_url_or=$url_origin) =~ s/^$doc_top_re//;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/install.sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/install.sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/install.sh	(revision 10506)
@@ -0,0 +1,9 @@
+#!/bin/sh -v
+
+export PERL5LIB=$GSDLHOME/perllib/cpan/lib:$PERL5LIB
+export PATH=$GSDLHOME/perllib/cpan/bin:$PATH
+
+perl Makefile.PL PREFIX=$GSDLHOME/perllib/cpan
+
+make
+make install
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/multiscope.cfg
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/multiscope.cfg	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/multiscope.cfg	(revision 10506)
@@ -0,0 +1,46 @@
+# This file is meant to illustrate multiscope retrival.
+#
+# Available options: recurse, no-date-check, only-nonexistent, list-urls,
+# lowercase.  It is not default to recurse.  options must be the 
+# first directive in the the config file.
+Options: recurse
+# This directive was previously known as 'Fetch-options'
+#
+# This is the two argument form of URL:.  It fetches the first into the second
+URL: http://www.math.uio.no/~janl/ math/janl
+#
+# These says that any documents refered to that lives under these places
+# should be gotten too.  Into the named directories.  Two arguments are
+# required for 'Also:'.
+Also: http://www.math.uio.no/drift/personer/ math/drift
+Also: http://www.stud.ifi.uio.no/~janl/ ifi/janl
+Also: http://www.mi.uib.no/~nicolai/ math-uib/nicolai
+#
+# A more typical use would perhaps be:
+#   URL: http://www.math.uio.no/~janl/ janl
+#   Also: http://www.math.uio.no/images/ images
+# which would retrive the images refered to under
+# http://www.math.uio.no/~janl/ into a directory called images
+#
+# CD here before doing any work
+#cd: janlhomes
+#
+# Default pause is now 0.
+#Pause: 0
+#
+# Ignore urls we can't copy anyway.  Actually w3mir can copy
+# many cgi things with no problems.  But not always.
+Ignore: *.cgi
+Ignore: *-cgi
+Ignore: *.map
+#
+# Run fixup to get a filesystem browseable mirror
+Fixup: run
+# The options above will result in this directory hierarchy under
+# where you started w3mir:
+#
+# w3mir/math/janl		files from http://www.math.uio.no/~janl
+# w3mir/math/drift		from http://www.math.uio.no/drift/personer/
+# w3mir/ifi/janl		from http://www.stud.ifi.uio.no/~janl/
+# w3mir/math-uib/nicolai	from http://www.mi.uib.no/~nicolai/
+#
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3http.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3http.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3http.pm	(revision 10506)
@@ -0,0 +1,765 @@
+# -*- perl -*-
+# w3http.pm	--- send http requests, janl's 12" mix for w3mir
+#
+$VERSION=1.0.22;
+#
+# This implements http/1.0 requests.  We'll have problems with http/0.9
+# This is in no way specific to w3mir.
+#
+# IMPORTANT: The caller should initialize the C locale for some of the
+#   things here to work correctly (specifically the strftime function).
+#
+# This is a rewrite of http.pl by Oscar Nierstrasz; I copied the code he he
+# copied from the camel book.  Some functions written by Gorm Haug Eriksen
+# (gorm@usit.uio.no) has been used as is.
+#
+# Contributors:
+#   Nicolai Langfeldt, janl@ifi.uio.no
+#   Gorm Haug Eriksen, gorm@usit.uio.no
+#   Chris Szurgot, szurgot@itribe.net
+#   Bernhard Weisshuh, bkw@weisshuhn.de
+# Copying and modification is governed by the "Artistic License" enclosed in
+# the w3mir distribution
+#
+# gorm :
+# &w3http::get_last_modified  return the last modified stamp on a file in
+#                         the right format for use with http
+#
+# janl:
+# &http::query: Send a http query.  A completely general function to send a
+#   http query.  Will extract header values, http response code and, optionaly,
+#   convert text files to local linefeed format.
+#
+# Variables to examine after a query
+# $w3http::document: The document returned by the query, if any.
+# $w3http::doclen: The length of the document
+# $w3http::result: The numerical http result code.  It may take these values:
+# - Normal HTTP reply codes
+# -  98: OS error, permanent, errormessage in $!
+# -  99: Other permanent error: see $restext.
+# - 100: Transient error: Timeout/connection broken
+# $w3http::restext: The english(?) HTTP result or w3http generated message
+# $w3http::header: The http header returned.
+# $w3http::plaintexthtml: 1 if this doc is non-content-encoded text/html
+#	(as opposed to content-encoding: compressed content-type: text/html
+#       which needs decompression before we can inspect the html) 
+#	The tests are somewhat longwinded so I do it just once here.
+# %w3http::headval: Associative array of header values
+# $w3http::headval{'CONTENT-TYPE'}: Derived content type, stripped of charset
+#		qualifiers and other distractions.
+# $w3http::xfbytes: Transfered bytes, cumulative.  Document part only.
+# $w3http::headbytes: Bytes of headers received, cumulative.
+#
+# Variables that change http's behaviour/requests:
+# $w3http::agent: User agent, default is basename of $0
+# $w3http::from: Request is from, default is user@host
+# $w3http::version: The http version to use, only 1.0 is known to me.
+# $w3http::timeout: How long to wait for new data to arrive, default is 600sec
+# $w3http::buflen: Network read buffer size, default is 4096.  It might give a
+#	speedup to tune this for specific servers' so it matches their send
+#	size.  This size can be detected if we want to, I think.
+# $w3http::debug: 1 debuging output, 2, more, 3 queries and replies
+# $w3http::verbose: 0: say nothing, 1: print progress info
+# $w3http::convert: Convert text/* documents to local newline convention?
+#	The default is to do it.
+# $w3http::proxyserver: The name of the proxyserver to use.
+# $w3http::proxyport: The port of the proxyserver to use. 0 if no proxyserver.
+# $w3http::proxyuser: If this is set proxy authentication will be used.
+# $w3http::proxypasswd: The password for proxy authentication
+#
+# Things gotten from main:
+# - $main::win32: 1 if win32 restrictions apply to this system
+# - $main::nulldevice: Bit sink file/device on this system.
+#
+# History (european date format dd/mm/yy):
+#     janl ??/??/95 -- Rewrite finished
+#  szurgot ??/??/95 -- Win32 compatability
+#     janl 16/05/96 -- Added SAVEBIN option, based on idea by szurgot
+#  szurgot 03/05/96 -- Corrected typo in check for content-length against
+#                      retreive document length. Added test for zero-length
+#		       documents (Not retreived because not-modified)
+#  szurgot 19/05/96 -- Win32 adaptions, fixes.
+#     janl 19/05/96 -- Chris won an argument, and janl simplified http 
+#		       retrival loop (-> version 1.0.4)
+#     janl 09/09/96 -- Incorporated a patch submited by Michael Kriby -> 1.0.5
+#     janl 16/09/96 -- Support for authorization. -> 1.0.6
+#     janl 27/09/96 -- Support for Accept header, lack pointed out by
+# 			charles@ermine.ox.ac.uk: ... HTTP/1.1 (§14.1) says 
+#			``If no Accept header field is present, then it is
+#			assumed that the client accepts all media types,
+#			earlier versions of the protocol suggest that only
+#			text/plain and text/html will be offered by default.''
+#			This contradicts my memory of a http/1.0 draft.
+#			Also added $ACCEPT option.
+#     janl 20/10/96 -- Now uses HTTP::Date to produce HTTP timestamps -> 1.0.7
+#     janl 27/10/96 -- Didn't use to check if gethostbyname worked -> 1.0.8
+#     janl 02/12/96 -- Forgot a unlink when renaming temporary files.
+#     janl 21/02/97 -- Multipele $ACCEPT options work. -> 1.0.9
+#     janl 19/03/97 -- Now issues Host: header -> 1.0.10
+#     janl 10/04/97 -- Changed from wwwurl to URI::URL, and various related
+#                      changes. -> 1.0.11
+#     janl 09/05/97 -- Microsoft ISS servers are _so_ broken -> 1.0.12
+#                      (don't close the write end of the HTTP socket after
+#			sending a query to them)
+#     janl 12/05/97 -- New version of perl caught some typos, fixed
+#			longstanding bug in the newline conversion bit.
+#			-> 1.0.13
+#     janl 06/06/97 -- Demand Loading of MIME::BASE64 -> 1.0.14
+#     janl 01/12/97 -- FAT filesystems drops LSB of modtime.  Patch from
+#			Greg Lindhorst (gregli@microsoft.com)
+#                   -- whoami does not exist on win32, hardwire a default
+#			value (unknown) (also Greg L.) -> 1.0.15
+#     janl 01/22/98 -- Proxy authentication as outlined by Christian Geuer
+#     janl 02/20/98 -- Complex 'content-type' headers handled. -> 1.0.17
+#     janl 04/20/98 -- Only newline convert text/html, everything else is
+#			handled as binary. -> 1.0.18
+#     janl 12/05/98 -- Store tmpfile in its final destination directory
+#			avoiding asking movefile move it across filesystems.
+#			-> 1.0.19
+#     janl 01/08/98 -- Timeout fix from Michael Gusev, also flag short doc
+#			as error.
+#     janl 24/09/98 -- Better error handling -> 1.0.20
+#     bkw  17/12/98 -- Fixed problem with tempfile-generation when
+#                      running in forget-mode (-f)
+#     janl 05/01/99 -- Referer: dropped if argument not true -> 1.0.21
+#     janl 13/04/99 -- Added workaround for broken win32 perl resolving.
+
+package w3http;
+
+require 5.002;
+use Socket;
+use HTTP::Date;
+use Sys::Hostname;
+use URI::URL;
+
+# Suplementary libwww-perl:
+sub URI::URL::_generic::basename {
+  my $self = shift;
+  my @p = $self->path_components;
+  my $old = $p[-1];
+  if (@_) {
+    splice(@p, -1, 1, shift);
+    $self->path_components(@p)
+  }
+  $old;
+}
+
+
+END { 
+  # Remove tmp file and such in here.  That means that main:: gotta catch
+  # interrupt signals and exit on them, so ENDs are executed.
+}
+
+use strict;
+# Global variables, we want to share them:
+use vars qw($GET $HEAD $GETURL $HEADURL $IFMOD $IFMODF $AUTHORIZ $REFERER);
+use vars qw($SAVEBIN $ACCEPT $NOUSER $FREEHEAD $agent $version $timeout);
+use vars qw($debug $convert $proxyserver $proxyport $xfbytes $headbytes);
+use vars qw($verbose $result $restext $header $document);
+use vars qw($plaintexthtml %headval $progress $doclen $proxyuser);
+use vars qw($proxypasswd);
+
+my $hasAlarm;   # Win32 does not have any alarm
+my $chime;	# Has the alarm gone off yet?
+my %address;	# My own DNS cache
+my $savALRM;	# Saved ALRM handler
+my $savPIPE;	# Saved PIPE handler
+
+# The main:: program should detect if we're running on win32 or not,
+# somehow
+if ($main::win32) {
+  warn "win32\n";
+  # Compensate for lacks of win32 perl. 
+  $hasAlarm=0;
+  # Seems to be unavailable in win32/perl5.001.  It has to be in 5.003!
+#  eval "sub sockaddr_in {
+#	($port, $thataddr) = @_;
+#	$sockaddr = 'S n a4 x8';
+#	return pack($sockaddr, &AF_INET, $port, $thataddr);
+#    }";
+} else {
+  $hasAlarm=1;
+}
+
+
+# Find out some things
+my $thishost = hostname();
+my $proto = getprotobyname("tcp");
+
+(my $name, undef) = gethostbyname($thishost);
+chomp(my $user = $ENV{'LOGNAME'} || $ENV{'USER'} || `whoami` || 'unknown');
+my $from   = "$user\@$name";
+
+my $nl = "\r\n";
+# Default values, change by assignment in using-program.
+$agent  = $0; $agent =~ s~.*/~~; # Basename 
+$version= "1.0";
+$timeout= 600;			# Timeout while waiting for data/connection
+my $buflen = 4096;		# recv buffer length
+$debug = 0;			# Debuging output?
+$convert = 1;			# Convert newlines of text docs to local format
+$proxyserver='';		# Proxy server.
+$proxyport=0;			# Proxy server port. 0 if no proxy.
+$proxyuser='';			# Username for proxy authentication
+$proxypasswd='';		# Password for proxy authentication
+$xfbytes=0;			# 0 bytes transfered, cumulative
+$headbytes=0;			# 0 bytes of headers, cumulative
+$doclen=0;			# 0 bytes in doc, pr. document
+my $tmpfile="w3mir$$.tmp";	# Temporary filename
+$verbose=0;			# Verbosenes, 0: silent, 1: progress info
+
+# Query opcodes
+$GET = 1;			# GET query. Arg: host,port,path
+$HEAD = 2;			# HEAD query. Arg: host,port,path
+$GETURL = 3;			# GET query. Arg: url
+$HEADURL = 4;			# HEAD query. Arg: url
+# Here we lack PUT, which is not implemented
+# Modify query thus:
+$IFMOD = 101;			# If-modified after: Arg: HTTP-date-str
+$IFMODF = 102;			# If-modified after file: Arg: local-file-name
+$AUTHORIZ= 103;			# Basic authorization. Arg: 'user:password'
+$REFERER = 104;			# Referer: Arg: Referer 
+$SAVEBIN = 105;			# Write binary files to disk. Arg: File name
+				# If this opcode is used then main must provide
+				# a &main::movefile(oldname,newname) procedure
+				# that handles moving the tmp file to the
+				# final name/location.
+$ACCEPT  = 106;			# Accept header value: Arg: value
+$NOUSER  = 107;			# Don't insert user header.  Arg: none
+$FREEHEAD= 999;			# Freeform header, one line.  Arg: header
+
+sub query {
+  # Build and send a HTTP query.  And also receive response - janl 95/09/18
+  #
+  # Return codes: 0 if it didn't work.  1 if it did work.
+  # HTTP style result code in w3http::$result and message in w3http::$restext
+  
+  # We do next to no argument type checking btw.
+  
+  my($host,$port,$request,$query,$method,$inp,$linp,$saveto,$save,$arg);
+  my($start,$wantbytes,$thataddr,$err,$headb,$tmpf,$ldoc,$nouser,$q,$accept);
+  my($origreq,$req_o,$plaintext);
+  
+  # Something ought to be said
+  $result=99;
+  $restext='w3http: internal error';
+  $nouser=0;
+  
+  if ($version ne '1.0') {
+    warn "Unknown HTTP version $version, no request sent\n";
+    return 0;
+  }
+  
+  $accept=$saveto=$query='';
+  
+  # Find out what to ask for
+  
+  while (defined($arg=shift)) {
+    if ($arg == $GET) {
+      $host=shift;
+      $port=shift;
+      $request=shift;
+      $req_o=url 'http://'.$host.':'.$port.$request;
+      if ($proxyport) {
+	$query.='GET http://'.$req_o->as_string;
+      } else {
+	$query.='GET '.$req_o->epath;
+      }
+      $query.=' HTTP/'.$version.$nl;
+    } elsif ($arg == $HEAD) {
+      $host=shift;
+      $port=shift;
+      $request=shift;
+      $req_o=url 'http://'.$host.':'.$port.$request;
+      if ($proxyport) {
+	$query.='HEAD '.$req_o->as_string;
+      } else {
+	$query.='HEAD '.$req_o->epath;
+      }
+      $query.=' HTTP/'.$version.$nl;
+    } elsif ($arg == $GETURL) {
+      $req_o=shift;
+      $req_o=url $req_o unless ref $req_o;
+      ($method,undef,undef,$host,$port,$request,undef,$q) = $req_o->crack;
+      if ($proxyport) {
+	$query.='GET '.$req_o->as_string;
+      } else {
+	$q=$req_o->equery;
+	$query.='GET '.$request.($q?"?$q":'');
+      }
+      $query.=' HTTP/'.$version.$nl;
+    } elsif ($arg == $HEADURL) {
+      $req_o=shift;
+      $req_o=url $req_o unless ref $req_o;
+      if ($proxyport) {
+	$query.='HEAD '.$req_o->as_string;
+      } else {
+	$q=$req_o->equery;
+	$query.='HEAD '.$req_o->epath.($q?"?$q":'');
+      }
+      $query.=' HTTP/'.$version.$nl;
+    } elsif ($arg == $IFMOD) {
+      $query.='If-Modified-Since: '.(shift).$nl;
+    } elsif ($arg == $IFMODF) {
+      $query.='If-Modified-Since: '.&last_modified(shift).$nl;
+    } elsif ($arg == $AUTHORIZ) {
+      # Demand-load MIME::Base64
+      if (!defined(&MIME::Base64::encode)) {
+	eval "use MIME::Base64;";
+	die "w3http: Could not load MIME::Base64 module necessary for authentication\n"
+	  unless defined(&MIME::Base64::encode);
+      }
+      $query.='Authorization: Basic '.MIME::Base64::encode(shift,'').$nl;
+    } elsif ($arg == $REFERER) {
+      my($referer)=shift;
+      $query.='Referer: '.$referer.$nl if $referer;
+    } elsif ($arg == $SAVEBIN) {
+      $saveto=shift;
+    } elsif ($arg == $ACCEPT) {
+      $accept.='Accept: '.(shift).$nl;
+    } elsif ($arg == $NOUSER) {
+      $nouser=1;
+    } elsif ($arg == $FREEHEAD) {
+      $query.=(shift).$nl;
+    } else {
+      warn "Unknown http query opcode: $arg\n";
+    } 
+    # Insert the last parts of the query:
+  }
+  
+  $query.='Host: '.$req_o->netloc.$nl;
+  $query.='From: '.$from.$nl unless $nouser;
+
+  $accept='Accept: */*'.$nl unless $accept;
+
+  if ($proxyport) {
+    # Use proxy instead of originserver
+    $host=$proxyserver;
+    $port=$proxyport;
+
+    # Add authentication stuff to query
+    if ($proxyuser) {
+      # Demand-load MIME::Base64
+      if (!defined(&MIME::Base64::encode)) {
+	eval "use MIME::Base64;";
+	die "w3http: Could not load MIME::Base64 module necessary for authentication\n"
+	  unless defined(&MIME::Base64::encode);
+      }
+      
+      $query.='Proxy-Authorization: Basic '.
+	MIME::Base64::encode($proxyuser.':'.$proxypasswd);
+
+      print STDERR "\nProxyuser: [$proxyuser]\nProxypasswd: [$proxypasswd]\n"
+	if $debug>=2;
+    }
+  }
+  
+  $query.='User-Agent: '.$agent.$nl.$accept.$nl;
+  
+  # If we're using proxy then set up things...
+  print STDERR "\nQUERY:\n",$query,"---\n" if $debug>=2;
+
+  # win32 fix: this should be added in case of troubles with
+  # gethostbyname. possible reason: nameserver down?
+  if ($host =~ /^\d+(\.\d+){3}$/) {
+    # in case gethostbyname will not work ... ;-)
+    $address{$host} = pack 'C4', (split /\./, $host);
+  }
+  
+  # Find out who to ask, check if we know already
+  if (exists($address{$host})) {
+    # We know
+    $thataddr=$address{$host};
+  } else {
+    # Cache miss, get and remember.
+    (my $fqdn, undef, undef, undef, $thataddr) = gethostbyname($host);
+    # Hostname lookup failure?  Cache even misses.
+    if (defined($fqdn)) {
+      print STDERR "Lookup of $host:\nFQDN: $fqdn\n"
+	if $debug;
+      $address{$host}=$thataddr;
+      $address{$fqdn}=$thataddr if $fqdn ne $host;
+    } else {
+      $thataddr=$address{$host}=undef;
+    }
+  }    
+
+  # Check if lookup failure, return
+  if (!defined($thataddr)) {
+    $restext='Host lookup failure';
+    return;
+  }
+
+  $port=80 unless defined($port) && $port;
+
+  # When connected we might receive SIGPIPE.  I'm not sure if the
+  # default behaviour of dying is beneficial in that case.  If we get
+  # alarm a timeout has expired.
+  $savPIPE = $SIG{'PIPE'};
+  $savALRM = $SIG{'ALRM'};
+
+  $chime=0;			# There has been no alarm yet
+  $SIG{'ALRM'} = \&timeout;
+  $SIG{'PIPE'} = \&ignore;
+
+  # Close the socket, just in case, and ignore error returns
+  close(FS);
+  
+  socket(FS, AF_INET, SOCK_STREAM, $proto) or return &oserror;
+  warn "Got my socks on\n" if $debug;
+  
+  my $paddr = sockaddr_in($port, $thataddr);
+  connect(FS, $paddr) or return &oserror;
+  warn "Connected\n" if $debug;
+  
+  # Arrange timeout
+  alarm($timeout) if $hasAlarm;
+  
+  # We have, in fact, received SIGPIPE on this line:
+  send(FS,$query,0) or return &oserror;
+
+  if ($chime) {
+    $result=100;
+    $restext='timeout sending query';
+    return &resetsign;
+  }
+  
+  $header='';
+  $document='';
+  $inp=' 'x$buflen;
+  $doclen=$chime=$plaintext=$plaintexthtml=$save=0;
+
+  # Breaks some M$ ISS servers:
+  # shutdown(FS,1);  # Half-close socket, sending now not allowed
+  
+  print STDERR ", receiving header" if $verbose>0;
+  
+  # Retrive HTTP response HEADER.  Why do I use recv and not <FS>?
+  # Because then the timeout can work correctly!
+  while (1) {
+    # Set up alarm to ensure recv returns within a reasonable timeframe
+    alarm($timeout) if $hasAlarm;
+    $err = recv(FS,$inp,$buflen,0);
+    # recv returned, cancel alarm.
+    alarm(0) if $hasAlarm;
+    
+    # If there has been a timeout, then we quit now.  The recv man page
+    # does not seem to allow recv to return the bytes received up to
+    # the timeout.
+    if ($chime) {
+      $result=100;  
+      $restext='timeout fetching document';
+      $!=0;
+      if ($save) {
+	unlink($tmpf) || 
+	  warn "Could not unlink $tmpf: $!\n";
+      }
+      return &resetsign;
+    }
+    
+    # recv returnes the undefined value on error
+    if (!defined($err)) {
+      warn "Error in recv: $!\n";
+      last;
+    }
+    
+    $linp=length($inp);
+    
+    # If the returned input was 0 in length then we've gotten to the 
+    # end of the response.
+    last unless $linp;
+    
+    # Accounting
+    $xfbytes += $linp;
+    $doclen += $linp;
+    
+    # Accumulate input
+    $header.=$inp;
+
+    # eof(SOCKET) has strange semantics it seems
+    # last if eof(FS);
+    
+    # Check if header is complete
+    last if ($header =~ m/(\r?\n\r?\n)/);
+  }
+  
+  if (length($header)==0) {
+    $restext='the HTTP reply header is empty!';
+    return &resetsign;
+  }
+  
+  if ($header =~ m/(\r?\n\r?\n)/) {
+    $header=$`;
+    $document=$';
+  } else {
+    $header=$document;
+  }
+  
+  # Adjust accounting
+  $headb = length($header)+length($1);
+  $headbytes += $headb;
+  $xfbytes -= $headb;
+  $doclen -= $headb;
+  
+  # Pick headers to pieces
+  ($result,$restext,%headval)=&analyze_header($header);
+
+  print STDERR "REPLY:\n",$header,"\n---\n" if $debug>=2;
+
+  # Check if the document is a non-encoded text document. The contents
+  # could be (x-)?compress or (x-)gzip coded (compressed in other
+  # words).
+  
+  $plaintext=defined($headval{'CONTENT-TYPE'}) &&
+    (substr($headval{'CONTENT-TYPE'},0,5) eq 'text/' || 0) &&
+      !defined($headval{'content-encoding'});
+  $plaintexthtml=$plaintext && 
+    ($headval{'CONTENT-TYPE'} eq 'text/html');
+  
+  if ($result==200) {
+    
+    # Save this to a file, or not?  Never save html files.
+    if ($saveto && !$plaintexthtml) {
+      # We're going to save this document directly into a file.  This
+      # stresses the VM less when getting the large binares so often
+      # found at cool sites.
+      $save=1;
+
+      # Find a temporary filename
+      $tmpf=url "file:$saveto";
+      $tmpf->basename($tmpfile);
+      $tmpf=$tmpf->unix_path;
+      
+      # Find suitable final filename, one with no URL escapes
+      $saveto=(url "file:$saveto")->unix_path;
+
+      # If output to stdout then send it directly there rather than
+      # using disk unnecesarily.
+      $tmpf='-' if ($saveto eq '-');
+
+      # If output is nulldevice (running -f), use it also for tmpfile,
+      # since it would otherwise try to create it in /dev under unix.
+      $tmpf=$main::nulldevice if ($saveto eq $main::nulldevice);
+      
+      warn "USING TMPFILE: $tmpf\n" if $debug;
+      
+      open(SAVE,">$tmpf") || 
+	die "Could not open tmp file: $tmpf: $!\n";
+      binmode SAVE;		# It's a binary file...
+    }
+    
+    if ($verbose>0) {
+      print STDERR ", document";
+      print STDERR "->disk" if $save;
+    }
+    
+    # Now retrive document itself.  Se comments in header loop
+    $start=time;
+    $wantbytes = defined($headval{'content-length'})?
+      $headval{'content-length'}:0;
+    
+    $ldoc=length($document);
+    
+    while (1) {
+      alarm($timeout) if $hasAlarm;
+      recv(FS,$inp,$buflen,0);
+      alarm(0) if $hasAlarm;
+      
+      if ($chime) {
+	$result=100;
+	$restext='timeout fetching document';
+	$!=0;
+	if ($save) {
+	  unlink($tmpf) || 
+	    warn "Could not unlink $tmpf: $!\n";
+	}
+	return &resetsign;
+      }
+      
+      $linp=length($inp);
+      
+      last unless $linp || $ldoc;
+      $ldoc = 0;
+      
+      $xfbytes += $linp;
+      $doclen += $linp;
+      
+      if ($verbose>0 && time-$start>5) {
+	# Write progress info ... 
+	if ($wantbytes) {
+	  $progress = sprintf " %3d%%", $doclen/$wantbytes*100;
+	} else {
+	  $progress = sprintf " %d", $doclen;
+	}
+	print STDERR $progress, "\ch"x(length($progress));
+	# ...every 5 seconds
+	$start=time;
+      }
+      
+      $document.=$inp;
+      
+      if ($save) {
+	$err = print SAVE $document;
+	die "Error writing $tmpf: $!\n" unless $err;
+	$document='';
+      }
+
+      # The eof test seems to work very oddly for sockets.
+      # last if eof(FS);
+    }
+
+    close(FS);  # Close socket completely
+    
+    print STDERR "DOCUMENT:\n----\n",$document,"\n----\n" if $debug>=255;
+  
+    if ($wantbytes &&
+	$wantbytes != $doclen) {
+      $result=100;
+      $restext='transfer error; too many bytes in document';
+      $restext='document was incomplete' if ($wantbytes > $doclen) ;
+      print STDERR "SHORT DOCUMENT" if $debug>=16;
+      if ($save) {
+	unlink($tmpf) || warn "Could not unlink $tmpf: $!\n";
+      }
+      return &resetsign;
+    }
+    
+    # warn "XFB: $xfbytes, DL: $doclen\n";
+    if ($save) {
+      close(SAVE);
+      &main::movefile($tmpf,$saveto);
+    }
+    
+    # If this is a non-encoded text file and we're supposed to convert
+    # foreign newlines then we do it. It would be faster to do this
+    # with each chunk of input in the input loop, but this gives us
+    # two problems:
+    # - A \r\n newline could be split into two chunks.  Thus escaping
+    #   newline conversion.
+    # - It messes up the received bytes accounting rather badly.
+    #
+    # This used to be a test for $plaintext, the problem is that too
+    # many documents were typed as text/plain and so we corrupted
+    # binary files. This is bad. So now we're more paranoid about it:
+    # Only HTML gets converted.
+    if ($convert && $plaintexthtml) {
+      # Change non unix newlines to unix newlines. bare \r is known
+      # from macintosh (they hadta be different didn't they?), \r\n is
+      # known as 'network format' and from numerous systems, among
+      # them ms-dos.
+      $document =~ s~\r~\n~g unless $document =~ s~\r\n~\n~g;
+      warn "Newlines converted(?)\n" if $debug;
+    }
+    
+  }				# if $result == 200
+  
+  &resetsign;
+  return 1;
+}
+
+
+sub analyze_header {
+  my($header)=@_;
+  my($result,$restext,%headval,$hdln,$key,$value);
+  
+  # Summary of the http spec on headers (with my comments):
+  # - Each header line ends in CRLF (or just LF, or maybe even just CR,
+  #   anyways, it's easier if all is LF).
+  $header =~ s/\r/\n/mg unless $header =~ s/\r\n/\n/mg;
+  # - If a line starts with space then it's a continuation of the previous
+  #   line (these I fold into one line).
+  $header =~ s/\n\s/ /mg;
+  # - The header field names are case insensitive (so I convert them to
+  #   lowercase)
+  # - A field may appear twice, that is equivalent to listing the values
+  #   in a comma separated list (so I fold them into a comma separated list)n
+  # - The field name and the field value are separated by ': '
+  ($result,$restext) = $header =~ m~^HTTP/\d\.\d (\d\d\d) (.*)~;
+  # Shave off http result code from the header
+  $header =~ s~^.*\n~~;
+  
+  warn "Header:\n$header\n---\n" if $debug>=3;
+  
+  warn "Result: $result, Text: $restext\n" if $debug>=2;
+  
+  %headval=();
+  
+  foreach $hdln (split(/\r?\n/m,$header)) {
+    ($key,$value)=split(': ',$hdln,2);
+    $key="\L$key";
+    # Strip leading&trailing space off the reply, some servers use
+    # copious space after.
+    $value =~ s/^\s+|\s+$//g;
+    print STDERR "K: '$key', V: '$value'\n" if $debug>=2;
+    if (defined($headval{$key})) {
+      $headval{$key}.=", ".$value;
+    } else {
+      $headval{$key}=$value;
+    }
+  }
+
+  # See if there are any type parameters in the content-type header
+  # and if so remove them.
+  if (defined($headval{'content-type'})) {
+    my $val=$headval{'content-type'};
+    ($val,undef)=split(';',$val,2) if ($val =~ /;/);
+    $headval{'CONTENT-TYPE'}=$val;
+  }
+  
+  return ($result,$restext,%headval);
+}
+
+
+sub last_modified {
+  # will return the last modified time for a local file as a HTTP
+  # timestamp.
+  
+  my(@tmp) = stat($_[0]);	# file doesn't exist ok to fetch
+
+  # FAT file systems strip the LSB of the file time.  Add it back in
+  # here before asking the server about a modified file.  The only way
+  # this can fail is if the newer server file was saved one second
+  # after the first version (very unlikely).  This isn't needed for
+  # NTFS file systems, but there is no good portable Perl way to
+  # determine the file system type.
+  $tmp[9] = $tmp[9] | 1 if ( $main::win32 );
+
+  # now we got the last modified in a 32 bit integer.  time to convert
+  # it and return
+  return time2str($tmp[9]);
+}
+
+
+sub timeout {
+  # Set timeout flag.  The using procedure has to set other result codes.
+  $chime=1;			# When this is 1 then the alarm has gone off
+  print STDERR "TIMEOUT!!!!\n" if $debug>=16;
+}
+
+
+sub ignore {
+  warn "I got SIGPIPE, ignoring it...\n";
+}
+
+
+sub resetsign {
+  return 0 if !defined($savALRM);
+  $SIG{'ALRM'}=$savALRM;
+  undef $savALRM;
+#  $SIG{'PIPE'}=$savPIPE;
+  return 0;
+}
+
+
+sub oserror {
+  
+  resetsign;
+
+  $result=98;
+  $restext='w3http: OS error';
+  return 0;
+
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3mfix.PL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3mfix.PL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3mfix.PL	(revision 10506)
@@ -0,0 +1,1070 @@
+# -*-perl-*-
+
+use Config;
+
+&read_makefile;
+$fullperl = resolve_make_var('FULLPERL') || $Config{'perlpath'};
+$islib = resolve_make_var('INSTALLSITELIB');
+
+$name = $0;
+$name =~ s~^.*/~~;
+$name =~ s~.PL$~~;
+
+open(OUT,"> $name") || 
+  die "Could open $name for writing: $!\n";
+
+print "writing $name\n";
+
+while (<DATA>) {
+  if (m~^\#!/.*/perl.*$~o) {
+    # This substitutes the path perl was installed at on this system
+    # _and_ removed any (-w) options.
+    print OUT "#!",$fullperl,$1,"\n";
+    next;
+  }
+  if (/^use lib/o) {
+    # This substitutes the actuall library install path
+    print OUT "use lib '$islib';\n";
+    next;
+  }
+  print OUT;
+}
+
+close(OUT);
+
+# Make it executable too, and writeable
+chmod 0755, $name;
+
+#### The library
+
+sub resolve_make_var ($) {
+
+  my($var) = shift @_;
+  my($val) = $make{$var};
+
+#  print "Resolving: ",$var,"=",$val,"\n";
+  
+  while ($val =~ s~\$\((\S+)\)~$make{$1}~g) {}
+#  print "Resolved: $var: $make{$var} -> $val\n";
+  $val;
+}
+
+
+sub read_makefile {
+
+  open(MAKEFILE, 'Makefile') || 
+    die "Could not open Makefile for reading: $!\n";
+
+  while (<MAKEFILE>) {
+    chomp;
+    next unless m/^([A-Z]+)\s*=\s*(\S+)$/;
+    $make{$1}=$2;
+#    print "Makevar: $1 = $2\n";
+  }
+
+  close(MAKEFILE)
+}
+
+__END__
+#!/local/bin/perl5 -w
+# Perl 5.002 or later.  w3mir is mostly tested with perl 5.004
+#
+# You might want to change or comment out this:
+use lib '/hom/janl/lib/perl';
+#
+# Can perform the following fixes:
+# - Rewrite redirected to URLs
+# - change .../ into .../index.html (or .../Welcome.html)
+# - change external links to point to some helpfull .html file ---- NOT IMPLEMENTED
+# - change links to documents not retrived to point to some helpfull
+#   .html file --- NOT IMPLEMENTED
+# - After adding a 'Also' directive we can edit the urls pointing to within
+#   the new space of the retrival scope, making the pointers consistent.
+
+# Method: 
+# 1 Gather list of all URLs to be rewritten:
+#   - Redirects: Just read the .redirs file
+#   - .../ into .../index.html: All can be found in the .referers file
+#     Remember to rewrite missing / redirects too...
+#   - external links: in the .referers file too
+#   - non-retrived documents: What files should be here (according to
+#	.referers file) but are not?
+# 2 Gather list of all documents needing editing
+# 3 Edit them
+#
+# 09/05/98 janl		- Only rewrite .../ to .../$indexname if the attribute
+#			  does not refer to a directory. -> 0.6.2
+# 12/05/98 janl		- Use ->local_path to determine filename -> 0.6.3
+# 22/05/98 janl		- .../#foo was not being rewritten to 
+#			  .../$indexname#foo -> 0.6.4
+#
+require 5.002;
+
+use vars qw($win32);
+
+# To figure out what kind of system this is
+BEGIN {
+  use Config;
+  $win32 = ( $Config{'osname'} eq 'MSWin32' ); 
+}
+
+use Carp;
+use htmlop;
+use URI::URL;
+use URI::Escape;
+
+use strict;
+
+my $VERSION;
+$VERSION='0.6.5';
+
+my $debug=0;			# Not debugging
+my $verbose=0;
+
+my $indexname='index.html';
+my $chdirto='';			# Place to chdir to after reading
+                                # config file
+
+my $infoloss=0;			# 1 if any URL translations (which
+                                # cause information loss) are in
+                                # effect.  If this is true we use the
+                                # SAVEURL operation.  What to get, and
+                                # not.  Text of user supplied
+                                # fetch/ignore rules
+
+my $doindex=1;			# append $indexname to /$ ?
+
+my $editthis='';		# Edit references matching this expression.
+
+my $files=0;			# How many files have I edited?
+my $rc='';
+
+my $rule_text="# User defined fetch/ignore rules\n";
+# Code ref to the rule procedure
+my $rule_code;
+
+# Code to prefix and postfix the generated code.  Prefix should make
+# $_ contain the url to match.  Postfix should return 1, the default
+# is to get the url/file.
+my $rule_prefix='$rule_code = sub { local($_) = shift;'."\n";
+my $rule_postfix=' return 1; } ';
+
+# Scope tests generated by URL/Also directives in cfg. The scope code
+# is just like the rule code, but used for program generated
+# fetch/ignore rules related to multiscope retrival.
+my $scope_fetch="# Automatic fetch rules for multiscope retrival\n";
+my $scope_ignore="# Automatic ignore rules for multiscope retrival\n";
+my $scope_code;
+
+my $scope_prefix='$scope_code = sub { local($_) = shift;'."\n";
+my $scope_postfix=' return 0; } ';
+
+# Function to apply to urls, se rule comments.
+my $user_apply_code;	# User specified apply code
+my $apply_code;		# w3mirs apply code
+my $apply_prefix='$apply_code = sub { local($_) = @_;'."\n";
+my $apply_lc=' $_ = lc $_; ';
+my $apply_postfix=' return $_; } ';
+my @user_apply;		# List of users apply rules.
+my @internal_apply;	# List of w3mirs apply rules.
+
+
+my $iinline='';			# inline RE code to make RE caseinsensitive 
+my $ipost='';			# RE postfix to make it caseinsensitive
+my $lc=0;			# Convert urls/filenames to lowercase?
+my $abs=0;			# Absolutify URLs?
+my $fixrc='';			# Name of w3mfix config file
+my $fixup=0;			# Do things needed to run fixup
+my $r=0;			# Recurse? no recursion = absolutify links
+my %rum_referers=();		# Array of referers, key: rum_url
+my %rum_redirected=();		# Array of redirected url: key: original url
+my %lf_edited=();		# Edited this file yet?
+my $list;			# List url on STDOUT?
+
+my %stat=();			# stat($lf_url): 'd' for dir, 'f' for others
+
+# ######################### Libwww-perl addons:
+
+sub URI::URL::_generic::unix_path {
+  my $self = (shift)->clone;
+
+  $self->frag(undef);
+  $self->scheme("file");
+  $self->unix_path;
+}
+
+
+sub URI::URL::_generic::basename {
+  my $self = shift;
+  my @p = $self->path_components;
+  my $old = $p[-1];
+  if (@_) {
+    splice(@p, -1, 1, shift);
+    $self->path_components(@p)
+  }
+  $old;
+}
+
+
+sub URI::URL::_generic::path_components {
+    my $self = shift;
+    my $old = $self->{'path'};
+    $old = '' unless defined $old;
+    $old = "/$old" if $old !~ m|^/| && defined $self->{'netloc'};
+    if (@_) {
+	$self->_elem('path',
+		     join("/", map { uri_escape($_,$URI::URL::reserved)
+				   } @_));
+    }
+    map { uri_unescape($_) } split("/", $old, -1);
+}
+
+
+# ######################### Configuration/argument parsing
+
+sub parse_args {
+  my $f;
+  my $i;
+
+  $i=0;
+
+  while ($f=shift) {
+    $i++;
+    # This is a demonstration against Getopts::Long.
+    if ($f =~ s/^-+//) {
+      $verbose=-1,next if $f eq 'q'; 		# Quiet
+      $verbose=1,next if $f eq 'c';		# Chatty
+      die "w3mfix version $VERSION\n" if $f eq 'v';	# Version
+      die "rtfm\n" if ($f eq 'help' || $f eq 'h' || $f eq '?');
+
+      if ($f eq 'editref') {
+	die "Sorry, can only have one -editref pr. run\n"
+	  if $editthis;
+	$editthis=quotemeta(shift);
+	next;
+      }
+
+      if ($f eq 'd') {	# Debugging level
+	$f=shift;
+	unless (($debug = $f) > 0) {
+	  die "w3mfix: debug level must be a number greater than zero.\n";
+	}
+	next;
+      }
+
+      # Those were all the options...
+      warn "w3mfix: Unknown option: -$f.  Use -h for usage info.\n";
+      exit(1);
+    } else {
+      # If we get this far then ... it's a configuration file name:
+      $rc = $f;
+      die "w3mfix: Got a non-option argument that wasn't the name of a\n".
+	"(configuration) file either\n"
+	  unless -f $f;
+    }
+  }
+}
+
+
+sub parse_cfg_file {
+  # Read the configuration file.  Aborts on errors.
+  # Ignores w3mir options w3mfix does not need itself.
+
+  my ( $file ) = @_ ;
+  my ($key, $value, $authserver,$authrealm,$authuser,$authpasswd);
+  my $i;
+
+  die "w3mfix: config file $file is not a file.\n" unless -f $file;
+  open(CFGF, $file) || die "Could not open config file $file: $!\n";
+
+  # print STDERR "Reading $file\n";
+
+  $i=0;
+
+  while (<CFGF>) {
+    # Trim off various junk
+    chomp;
+    s/^#.*//;
+    s/^\s+|\s$//g;
+    # Anything left?
+    next if $_ eq '';
+    # Examine remains
+    $i++;
+    ($key, $value) = split(/\s*:\s*/,$_,2);
+    $key = lc $key;
+
+    # These are no-ops in w3mfix
+    next if ( $key eq 'initial-referer' );
+    next if ( $key eq 'header' );
+    next if ( $key eq 'pause' );
+    next if ( $key eq 'retry-pause' );
+    next if ( $key eq 'retries' );
+    next if ( $key eq 'robot-rules' );
+    next if ( $key eq 'remove-nomirror' );
+    next if ( $key eq 'file-disposition' );
+    next if ( $key eq 'http-proxy' );
+    next if ( $key eq 'proxy-options' );
+    next if ( $key eq 'auth-domain' );
+    next if ( $key eq 'auth-user' );
+    next if ( $key eq 'auth-passwd' );
+    next if ( $key eq 'disable-headers' );
+    next if ( $key eq 'agent' );
+
+    $debug=numeric($value),next if ( $key eq 'debug' );
+    umask(numeric($value)),next if ( $key eq 'umask' );
+    $indexname=$value,next if ($key eq 'index-name');
+    $verbose=nway($value,'quiet','brief','chatty')-1,next
+      if ( $key eq 'verbosity' );
+
+    if ( $key eq 'cd' ) {
+      $chdirto=$value;
+      next;
+    }
+
+    if ($key eq 'url') {
+      my ($rum_url_o,$lf_dir,$rum_reurl,$rum_rebase);
+
+      # A two argument URL: line?
+      if ($value =~ m/^(.+)\s+(.+)/i) {
+	# Two arguments.
+	$rum_url_o=url $1;
+	# The last is a directory, it must end in /
+	$lf_dir=$2;
+	$lf_dir.='/' unless $lf_dir =~ m~/$~;
+
+	# The first is a URL, make it more canonical, find the base.
+	# The namespace confusion in this section is correct.(??)
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+	# print "URL: ",$rum_url_o->as_string,"\n";
+	# print "Base: $rum_rebase\n";
+
+	# Translate from rum space to lf space:
+	push(@internal_apply,"s/^".$rum_rebase."/".quotemeta($lf_dir)."/");
+
+	# That translation could lead to information loss.
+	$infoloss=1;
+
+	# Fetch rules tests the rum_url_o->as_string.  Fetch whatever
+	# matches the base.
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+
+	# Ignore whatever did not match the base.
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+
+      } else {
+	# $rum_url_o=root_quene($value);
+
+	$rum_url_o=url $value;
+
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+	# Translate from rum space to lf space:
+	push(@internal_apply,"s/^".$rum_rebase."//");
+
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+      }
+      next;
+    }
+
+    if ($key eq 'also' || $key eq 'also-quene') {
+      if ($value =~ m/^(.+)\s+(.+)/i) {
+	my ($rum_url_o,$lf_dir,$rum_reurl,$rum_rebase);
+	# Two arguments.
+	$rum_url_o=url $1;
+	$rum_url_o->host(lc $rum_url_o->host);
+	# The last is a directory, it must end in /
+	$lf_dir=$2;
+	$lf_dir.='/' unless $lf_dir =~ m~/$~;
+
+	# The first is a URL, find the base
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+	# Ok, now we can transform and select stuff the right way
+	push(@internal_apply,"s/^".$rum_rebase."/".quotemeta($lf_dir)."/");
+	$infoloss=1;
+
+	# Fetch rules tests the rum_url_o->as_string.  Fetch whatever
+	# matches the base.
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+
+	# Ignore whatever did not match the base.  This cures problem
+	# with '..' from base in in rum space pointing within the the
+	# scope in ra space.  We introduced a extra level (or more) of
+	# directories with the apply above.  Must do same with 'Also:'
+	# directives.
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+      } else {
+	die "Also: requires 2 arguments\n";
+      }
+      next;
+    }
+
+    if ($key eq 'quene') {
+      # root_quene($value);
+      next;
+    }
+
+    if ($key eq 'ignore-re' || $key eq 'fetch-re') {
+      # Check that it's a re, better that I am strict than for perl to
+      # make compilation errors.
+      unless ($value =~ /^m(.).*\1[gimosx]*$/) {
+	print STDERR "w3mfix: $value is not a recognized regular expression\n";
+	exit 1;
+      }
+    }
+
+    if ($key eq 'fetch' || $key eq 'fetch-re') {
+      my $expr=$value;
+      $expr = wild_re($expr).$ipost if ($key eq 'fetch');
+      $rule_text.=' return 1 if '.$expr.";\n";
+      next;
+    }
+
+    if ($key eq 'ignore' || $key eq 'ignore-re') {
+      my $expr=$value;
+      $expr = wild_re($expr).$ipost if ($key eq 'ignore');
+      $rule_text.=' return 0 if '.$expr.";\n";
+      next;
+    }
+
+
+    if ($key eq 'apply') {
+      unless ($value =~ /^s(.).*\1.*\1[gimosxe]*$/) {
+	print STDERR
+	  "w3mfix: '$value' is not a recognized regular expression\n";
+	exit 1;
+      }
+      push(@user_apply,$value) ;
+      $infoloss=1;
+      next;
+    }
+
+    if ($key eq 'options') {
+      
+      my($val,$nval);
+      foreach $val (split(/\s*,\s*/,lc $value)) {
+	if ($i==1) {
+	  $nval=nway($val,'recurse','no-date-check','only-nonexistent',
+		     'list-urls','lowercase','remove','batch','read-urls',
+		     'abs');
+	  $r=1,next if $nval==0;
+	  next if $nval==1;
+	  next if $nval==2;
+	  $list=1,next if $nval==3;
+	  if ($nval==4) {
+	    $lc=1;
+	    $iinline=($lc?"(?i)":"");
+	    $ipost=($lc?"i":"");
+	    next ;
+	  }
+	  next if $nval==5;
+	  next if $nval==6;
+	  next if $nval==7;
+	  $abs=1,next if $nval==8;
+        } else {
+	  die "w3mfix: options must be the first directive in the config file.\n";
+	}
+      }
+    }
+
+    if ($key eq 'fixup') {
+
+#      chomp($fixrc=`pwd` || '.');
+#      $fixrc.="/$file";
+#      warn "Fixrc: $fixrc\n";
+#      $fixup=1;
+
+      my($val,$nval);
+      foreach $val (split(/\s*,\s*/,lc $value)) {
+	$nval=nway($val,'on','run','noindex');
+	next if $nval==0;
+	next if $nval==1;
+	$doindex=0 if $nval==2;
+	# Ignore everyting else
+      }
+    }
+
+  }
+  close(CFGF);
+}
+
+sub wild_re {
+  # Here we translate unix wildcard subset to to perlre
+  local($_) = shift;
+  s#\*#\.\*#;
+  s#\?#\.#;
+  s#([\/\(\)\\\|\{\}\+)\$\^])#\\$1#g;
+  return $_ = '/'.$_.'/';
+}
+
+
+sub numeric {
+  # Check if argument is numeric?
+  my ( $number ) = @_ ;
+  return oct($number) if ($number =~ /\d+/ || $number =~ /\d+.\d+/);
+  die "Expected a number, got \"$number\"\n";
+}
+
+
+sub boolean {
+  my ( $boolean ) = @_ ;
+
+  $boolean = lc $boolean;
+
+  return 0 if ($boolean eq 'false' || $boolean eq 'off' || $boolean eq '0');
+  return 1 if ($boolean eq 'true' || $boolean eq 'on' || $boolean eq '1');
+  die "Expected a boolean, got \"$boolean\"\n";
+}
+
+
+sub nway {
+  my ( $value ) = shift;
+  my ( @values ) = @_;
+  my ( $val ) = 0;
+
+  $value = lc $value;
+  while (@_) {
+    return $val if $value eq shift;
+    $val++;
+  }
+  die "Expected one of ".join(", ",@values).", got \"$value\"\n";
+}
+
+
+sub stat {
+
+  my $file = shift;
+
+  if (exists($stat{$file})) {
+    print STDERR "++Cache hit: $file\n" if $debug;
+  } else {
+    stat($file);
+    if (-e _) {
+      $stat{$file}=(-d _)?'d':'f';
+    } else {
+      $stat{$file}='n';
+    }
+    print STDERR "--Cache miss: $file\n" if $debug;
+  }
+  return $stat{$file};
+}
+
+# ######################## Read 'state' files ##############################
+
+sub read_state {
+
+  my $reffile='.referers';
+  my $refered;
+  my @referers;
+
+  $reffile="referers" if $win32;
+
+  print STDERR "reading $reffile\n" if $verbose>0;
+  open(REFERERS,"< $reffile") ||
+    die "Could not open $reffile for reading: $!\n";
+
+  while (<REFERERS>) {
+    chomp;
+    ($refered,undef,@referers) = split(/\s+/);
+    $rum_referers{$refered}= [ @referers ];
+    # print STDERR $refered," <- ",join(' and ',@referers),"\n";
+  }
+
+  close(REFERERS);
+
+
+  # Read redirection report
+
+  my $redirfile='.redirs';
+  my $wrong;
+  my $right;
+  my $tmp;
+
+  $redirfile="redirs" if $win32;
+
+  print STDERR "reading $redirfile\n" if $verbose>0;
+  open(REDIRS,"< $redirfile") ||
+    die "Could not open $redirfile for reading: $!\n";
+
+  while (<REDIRS>) {
+    chomp;
+    ($wrong,undef,$right) = split(/\s+/);
+
+    $rum_redirected{$wrong}=$right;
+  }
+
+  close(REDIRS);
+}
+
+# ######################### Process every single tag ########################
+
+sub process_tag {
+  # Process a tag in html file
+  my $lf_referer = shift;
+  my $base_url = shift;
+  my $tag_name = shift;
+  my $url_attrs = shift;
+
+  # Retrun quickly if no URL attributes
+  return unless defined($url_attrs);
+
+  my $attrs = shift;
+
+  # Information loss through apply or processing in this procedure?
+  my $il = $infoloss; 
+  my $redirs;
+  my $stat;
+
+  my $rum_url;	# The absolute URL
+  my $lf_url;	# The local filesystem url
+  my $lf_url_o; # ... and it's object
+  my $key;
+  my $orig_rum_url;
+#  my $debug = 1;
+
+#  print STDERR "\nProcess Tag: $tag_name, URL attributes: ", join(', ',@{$url_attrs}),"\nOrigin:",$base_url,"\n"; # if $debug>2;
+
+  substr($lf_referer,0,0)='./' unless substr($lf_referer,0,1) eq '/';
+
+  foreach $key (@{$url_attrs}) {
+    if (defined($$attrs{$key})) {
+      $orig_rum_url=$rum_url=$$attrs{$key};
+
+      print STDERR "\n$key = $rum_url\n" if $debug;
+
+      # Apply redirects:
+      $redirs=0;
+      if (exists($rum_redirected{$rum_url})) {
+	$il=1;
+	while (exists($rum_redirected{$rum_url})) {
+	  die "Too many redirects in a row\n" if $redirs++>32;
+	  print STDERR "$rum_url -> ".$rum_redirected{$rum_url}."\n"
+	    if $debug;
+	  $rum_url=$rum_redirected{$rum_url};
+	}
+      }
+
+      # Apply program/user apply rules
+      $lf_url=apply($rum_url);
+
+      if (defined($lf_url)) {
+	# Apply directory/file check here
+	$stat=&stat($lf_url);
+
+	if ($stat eq 'f' && $lf_url =~ m~/$~) {
+	  # It's a file, remove trailing /
+	  print STDERR "****** File / fixup of $lf_url\n" if $debug;
+	  $il=1;
+	  substr($lf_url,length($lf_url)) = '';
+	} elsif ($stat eq 'd' && !($lf_url =~ m~/$~) ) {
+	  # It's a directory, add a trailing /
+	  print STDERR "****** Directory / fixup of $lf_url\n" if $debug;
+	  $il=1;
+	  $lf_url .= '/';
+	}
+
+	substr($lf_url,0,0)='./' unless substr($lf_url,0,1) eq '/';
+
+	$lf_url_o=url $lf_url;
+	my $tmp=$lf_url_o->clone;
+	$tmp->basename($indexname);
+
+	if ( $doindex && $lf_url_o->basename eq "" && 
+	     &stat($tmp->unix_path) eq 'f' &&
+	     !$htmlop::isdir{$key}) {
+	  $lf_url_o=$tmp;
+	  $il=1;
+	  print STDERR "indexname adjusted to ",$lf_url_o->as_string,"\n"
+	    if $debug;
+	}
+		 
+	# Save new value in the hash, make it a file url to get 'rel' working
+	$lf_url_o->scheme('file');
+	$$attrs{$key} = ($lf_url_o->rel("file:".$lf_referer))->as_string;
+
+	printf STDERR "Saved ".$$attrs{$key}."\n" if $debug;
+
+	# If there is potential information loss save the old value too
+	$$attrs{"W3MIR".$key}=$orig_rum_url if $il;
+
+      } elsif ($redirs>0) {
+	$$attrs{$key}=$rum_url;
+	print STDERR "Saved ".$$attrs{$key}."\n" if $debug;
+	$$attrs{"W3MIR".$key}=$orig_rum_url;
+      }
+    }
+  }
+}
+
+
+# ###################### Edit the URLs in one file... ########################
+
+sub edit_html_file {
+  # Check if it's a html file.  I know this tag is in all html
+  # files, because w3mir put it there.
+
+  my($lf_url)=shift;
+  my($rum_url)=shift;
+
+  # Figure out the filename for our local filesystem.
+  $lf_url.=$indexname if $lf_url =~ m~/$~ || $lf_url eq '';
+
+  # Stuff in need of unquoting?
+  $lf_url = (url "file:$lf_url")->local_path if $lf_url =~ /\%\d\d/;
+
+  if (exists($lf_edited{$lf_url})) {
+    print STDERR "Already edited $lf_url\n" if $debug;
+    return ;
+  }
+
+  $lf_edited{$lf_url}=1;
+
+  my $page;
+  my $newpage;
+  my $read;
+  my $atime;
+  my $mtime;
+
+  # dev  uno   mode  nlink uid   gid   rdev  size  atime mtime
+  (undef,undef,undef,undef,undef,undef,undef,undef,$atime,$mtime)
+    = stat($lf_url);
+
+  if (!open(TMPF,"< $lf_url\n")) {
+    warn "Cannot read $lf_url: $!\n" if $verbose>=0;
+    return;
+  }
+
+  $read=sysread(TMPF,$page,10240,0);
+  close(TMPF);
+
+  if (! $page =~ /<HTML/i) {
+    print STDERR "$lf_url is not html\n" if $verbose>0;
+    return ;
+  }
+
+  $files++;
+
+  print STDERR "w3mfix: $lf_url" if $verbose>=0;
+  
+  print STDERR "$lf_url is a html file\n" if $debug;
+
+  print STDERR " reading" if $verbose>0;
+  
+  open(TMPF,$lf_url) || 
+    die "Could not open $lf_url for reading: $!\n";
+  # read the whole file.
+  {
+    local($/)=undef;
+    $page = <TMPF>;
+  }
+  close(TMPF);
+
+  print STDERR " ",length($page)," bytes" if $verbose>0;
+
+  # It's a html document
+
+  print STDERR ", editing" if $verbose>0;
+
+  ($newpage,undef) = 
+    &htmlop::process($page, # $htmlop::NODOC,
+		     $htmlop::ABS,$rum_url,
+		     $htmlop::USESAVED,'W3MIR',
+		     $htmlop::TAGCALLBACK,\&process_tag,$lf_url);
+
+  open(TMPF,">$lf_url") ||
+    die "\nCould not open $lf_url for writing: $!\n";
+  
+  print STDERR ", saving" if $verbose>0;
+
+  if (length($newpage)) {
+    # This is ODD: close does not seem to flush the buffers.  So we
+    # force the issue.
+    local($|)=1;
+    print TMPF $newpage || 
+      die "\nCould not write to $lf_url (disk full?): $!\n";
+  }
+
+  close(TMPF) || 
+    die "\nCould not close $lf_url after writing: $!\n";
+
+  # Set times back to what they were.
+  utime $atime,$mtime,$lf_url;
+
+  print STDERR ".\n" if $verbose>=0;
+}
+
+# ############################### Scope test
+
+sub want_this {
+  # Find out if we want the url passed.  Just pass it on to the
+  # generated functions.
+  my($rum_url)=shift;
+
+  # Does scope rule want this?
+  return &$scope_code($rum_url) &&
+    # Does user rule want this too?
+    &$rule_code($rum_url) 
+  
+}
+
+# ############################### Apply the apply rules
+
+sub user_apply {
+  # Apply the user apply rules
+  return &$user_apply_code(shift);
+}
+
+
+sub internal_apply {
+  # Apply the w3mir generated apply rules
+  return &$apply_code(shift);
+}
+
+
+sub apply {
+  # Apply the user apply rules.  Then if URL is wanted return result of
+  # w3mir apply rules.  Return the undefined value otherwise.
+
+  my $url = user_apply(shift);
+
+  return undef unless want_this($url);
+
+  internal_apply($url);
+}
+
+# ############################### Decide what URLs to edit
+
+sub edit_as_needed {
+  my $rum_redirected;
+  my $rum_url;
+  my $o_rum_url;
+  my $rum_referer;
+  my $lf_url;
+  my $foo;
+  my $redirs;
+
+  if ($editthis) {
+
+    # Find the URLs that match $edithis
+    foreach $o_rum_url (keys %rum_referers) {
+      # Work on them if they (now) fall within the scope of retrival
+      $redirs=0;
+      $rum_url=$o_rum_url;
+      if (exists($rum_redirected{$o_rum_url})) {
+	while (exists($rum_redirected{$rum_url})) {
+	  die "Too many redirects in a row\n" if $redirs++>32;
+	  print STDERR "$rum_url -> ".$rum_redirected{$rum_url}."\n"
+	    if $debug;
+	  $rum_url=$rum_redirected{$rum_url};
+	}
+      }
+      next unless $rum_url =~ /$editthis/io;
+      next unless want_this($rum_url);
+      # Find and edit the documents containing references to $o_rum_url
+      foreach $rum_referer (@{$rum_referers{$o_rum_url}}) {
+	next if $rum_referer eq '(commandline)';
+	$lf_url=apply($rum_referer);
+	next unless defined($lf_url);
+	edit_html_file($lf_url,$rum_referer);
+      }
+    }
+    
+    # Don't do anything else when invoked thus
+    return;
+  }
+
+  if ($doindex) {
+    # Edit everything that refers anything with trailing /
+    foreach $rum_url (grep(/\/$/,keys %rum_referers)) {
+      foreach $rum_referer (@{$rum_referers{$rum_url}}) {
+	next if $rum_referer eq '(commandline)';
+	$lf_url=apply($rum_referer);
+	next unless defined($lf_url);
+	edit_html_file($lf_url,$rum_referer);
+      }
+    }
+  }
+
+  # Edit only redirected stuff
+  foreach $rum_redirected (keys %rum_redirected) {
+    # print "Redirected $rum_redirected\n";
+    foreach $rum_url (@{$rum_referers{$rum_redirected}}) {
+      # print "- Found in $rum_url\n";
+      $lf_url=apply($rum_url);
+      next unless defined($lf_url);
+      edit_html_file($lf_url,$rum_url);
+    }
+  }
+}
+
+# ############################### 'main'
+
+&parse_args(@ARGV);
+
+if (!$rc) {
+  $rc='.w3mirc';
+  $rc='w3mir.ini' if $win32;
+}
+
+print STDERR "w3mfix: rc file: $rc\n" if $verbose>0;
+
+&parse_cfg_file($rc);
+
+# $chdirto is ignored, w3mir already did it
+
+# Compile second order code
+
+# - The rum scope tests
+my $full_rules=$scope_prefix.$scope_fetch.$scope_ignore.$scope_postfix;
+eval $full_rules;
+
+# warn "Scope rules:\n-------------\n$full_rules\n---------------\n";
+
+die "Program generated rules did not compile.  The code is:\n----\n".
+  $full_rules."\n----\n"
+  if !defined($scope_code);
+
+$full_rules=$rule_prefix.$rule_text.$rule_postfix;
+eval $full_rules;
+
+# warn "User rules:\n-------------\n$full_rules\n---------------\n";
+
+# - The user specified rum tests
+die "Ignore/Fetch rules did not compile.  The code is:\n----\n".
+  $full_rules."\n----\n"
+  if !defined($rule_code);
+
+# - The user specified apply rules
+
+my $full_apply=$apply_prefix.($lc?$apply_lc:'').
+  join($ipost.";\n",@user_apply).(($#user_apply>=0)?$ipost:"").";\n".
+  $apply_postfix;
+eval $full_apply;
+
+die "User apply rules did not compile. The code is:
+----
+".$full_apply."
+----\n" if !defined($apply_code);
+
+$user_apply_code=$apply_code;
+
+# - The w3mir generated apply rules
+
+$full_apply=$apply_prefix.($lc?$apply_lc:'').
+  join($ipost.";\n",@internal_apply).(($#internal_apply>=0)?$ipost:"").";\n".
+  $apply_postfix;
+eval $full_apply;
+
+die "Internal apply rules did not compile.  The code is:
+----
+".$full_apply."
+----\n" if !defined($apply_code);
+
+&read_state;
+
+&edit_as_needed;
+
+exit 0;
+__END__
+# -*- perl -*-  There must be a blank line here:
+
+=head1 NAME
+
+w3mfix - fixup program for w3mir
+
+=head1 SYNOPSIS
+
+B<w3mfix> [B<options>] [B<configuration-file>]
+
+=head1 DESCRIPTION
+
+B<w3mfix> is the companion program to L<w3mir>.  It can be used for
+several URL editing operations usefull in different situations.  
+
+When starting B<w3mfix> will read it's configuration file.  It's name is 
+either .w3mirc (w3mir.ini on win32) or specified on the commandline.
+
+B<w3mfix> is controlled by the 'Fixup' directive of the configuration
+file (described in the L<w3mir> documentation).  B<w3mfix> is also
+affected by 'Index-name' and the one special commandline option it
+knows, as well as the directives/options controlling verbosity and
+debugging information.
+
+=head1 DESCRIPTION
+
+B<w3mfix> can rewrite URLs in these ways:
+
+=over 4
+
+=item * Rewrite URLs that resutled in redirects to point to the place
+redirected to.  This is needed in all cases and will always be fixed
+by B<w3mfix>.
+
+=item * Change URLs ending in .../ into .../index.html (or
+.../Welcome.html).  This is, probably, not needed when the mirror is
+meant do be used with a web-server.  It is usefull for browsing
+directly from disk or CDROM, but in this case it's, most often,
+required.  To disable this specify the I<noindex> option with the
+'Fixup' directive.
+
+The default is to transform URLs ending in .../ into .../index.html.
+
+To controll the name of the index file use the I<Index-name> directive
+as documented in L<w3mir>
+
+=item * Change URL links to documents outside the mirror to point to
+some local document.  Could be usefull if the mirror is destined for a
+CDROM to be used on a unconnected machine.
+
+THIS IS NOT YET IMPLEMENTED
+
+=item * Change URL links to documents that L<w3mir> was
+unable/forbidden to retrive to point to some local document.  Pointing
+these to a nice informative document is probably better than random
+error messages from the browser.
+
+THIS IS NOT YET IMPLEMENTED
+
+=item * And, least, but far from last, B<w3mfix> can be used to
+prepare an established mirror for enlargement.
+
+This feature is used thus: Add the new site or subsite to be mirrored
+on the configuration file (by adding B<Also:> and B<Also-quene:>
+directives).  Then run B<w3mfix> with the B<-editref> option.  When
+the B<-editref> option is specified B<w3mfix> will not perform any
+other editing tasks.
+
+E.g.; To add I<http://www.yahoo.com/Science/Artificial_Life/> to your
+mirror add something like
+
+	  Also: http://www.yahoo.com/Science/Artificial_Life/ yahoo
+
+to the configuration file, then run w3mfix:
+
+	  w3mfix -editref www.yahoo.com/Science/Artificial_Life
+
+This will cause all references to
+I<www.yahoo.com/Science/Artificial_Life> (and under) to be edited so they
+point to within the mirror.  After B<w3mfix> has finished you can run
+L<w3mir> in the normal manner.
+
+=back
+
+=head1 BUGS
+
+Naah.
+
+=head1 SEE ALSO
+
+L<w3mir>
+
+=head1 AUTHORS
+
+B<w3mir>s authors can be reached at I<w3mir-core@usit.uio.no>.
+B<w3mir>s home page is at http://www.math.uio.no/~janl/w3mir/
+
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3mir-HOWTO.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3mir-HOWTO.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3mir-HOWTO.html	(revision 10506)
@@ -0,0 +1,943 @@
+<!doctype html public "-//W3C//DTD HTML 4.0//EN">
+<html>
+<head>
+<title>W3MIR HOWTO</title>
+<style type="text/css">
+<!--
+  body { background-color: white }
+  h1, h2, h3, b { font-family: sans-serif }
+  .red { color: red }
+-->
+</style>
+<body>
+<h1>W3MIR HOWTO</h1>
+
+<p><b>Corresponding to w3mir version 1.0.2 and above</b>
+
+<p>W3mir is an all purpose WWW copying and mirroring program.  Its
+main focus is copying complete directory structures keeping your copy
+browseable through a web server, or directly off a disk or CDROM if
+you want.  W3mir will fix URLs that are redirected and everything else
+that needs to be fixed to make your copy browseable.  But it also does
+odd jobs, retrieving single documents, batch getting several documents
+and more.  You may tell w3mir not to change anything in the retrieved
+documents.  W3mir has been in development quite a long time so you
+find options to do a lot of things needed when copying things off the
+web.
+
+<p>With w3mir you may copy the entire contents a web server.  Or just
+a directory hierarchy, or several related hierarchies off as many
+servers as you like.  They don't even have to be related.
+
+<p>W3mir supports HTML4, and has partial support for CSS, Java,
+ActiveX and Adobe Acrobat (PDF) files.  And it works on Win32
+machines.
+
+<p><b>Warning:</b> W3mir enables you to copy a lot of things off the
+Web, but remember, the things you retrieve might be copyrighted and
+the copy you make with w3mir might in fact be illegal to make and
+posses.
+
+<hr>
+
+<h2><a name="contents">Contents</a></h2>
+
+<p><a href="#intro">README</a> (You want to read this!  <b
+class="red">Really!</b>)
+
+<p><b>How do I...</b>
+<ol>
+  <li><p><a href="#copy">copy a file?</a>
+  <li><p><a href="#recurse">copy a directory hierarchy?</a>
+  <li><p><a href="#resources">copy the needed resource files from another
+    directory hierarchy?</a>
+  <li><p><a href="#ignore">avoid copying files I don't want or copy only
+    files I want?</a>
+  <li><p><a href="#rm">remove the files that are no longer on the
+    original site from the mirror?</a>
+  <li><p><a href="#depth">limit how deep w3mir will recurse?</a>
+  <li><p><a href="#memory">limit w3mirs memory usage?</a>
+  <li><p><a href="#multi">copy files from multiple sites?</a>
+  <li><p><a href="#alias">copy files from one server with several names?</a>
+  <li><p><a href="#aborted">restart a mirror process after stopping it
+    prematurely?</a>
+  <li><p><a href="#enlarge">enlarge or prune an established mirror?</a>
+  <li><p><a href="#cat">'cat' a file?</a>
+  <li><p><a href="#list">list URLs in a document?</a>
+  <li><p><a href="#robots">disable robots.txt obedience?</a>
+  <li><p><a href="#corrupt">stop w3mir from corrupting binary files?</a>
+  <li><p><a href="#auth">copy a site that wants user-name and password?</a>
+  <li><p><a href="#mauth">access a site that wants several different
+    user-names and passwords?</a>
+  <li><p><a href="#proxy">use a proxy server?</a>
+  <li><p><a href="#pauth">authenticate myself to a proxy server?</a>
+  <li><p><a href="#proxytweak">ensure that the proxy server ...?</a>
+  <li><p><a href="#batchget">batch get files with w3mir?</a>
+  <li><p><a href="#cgi">handle CGI?</a>
+  <li><p><a href="#imap">handle server side image-maps?</a>
+  <li><p><a href="#java">handle Java and ActiveX?</a>
+  <li><p><a href="#script">handle java-script and other script languages?</a>
+  <li><p><a href="#css">handle the other things with 'partial support'?</a>
+  <li><p><a href="#anon">keep my identity secret?</a>
+  <li><p><a href="#ns">pretend that I'm using Netscape, Internet
+    Explorer or Lynx?</a>
+  <li><p><a href="#other">do other things?</a>
+</ol>
+
+<hr>
+
+<h2><a name="intro">README</a></h2>
+
+<p>W3mir may be used in two, main, ways:
+
+<ul>
+  <li><p>To copy something random once.
+  <li><p>To keep a local mirror of some remote site
+</ul>
+
+<p>To copy something random once there is a high likeliness you can
+just start w3mir with some simple options and it will do the job you
+want it to.  Providing that the remote site is not too complex and
+your expectations of the copy aren't high :-) This is what wget, the
+gnu w3 mirroring program, does and is good at.
+
+<h3>Configuration file</h3>
+
+<p>Once you want to keep a copy of a remote site up-to-date over time,
+mirror something with server side image-maps, redirects or
+authentication you have to write a configuration file for w3mir.  This
+is what w3mir is good at, compared to wget.  Writing the file is not
+hard, and there are two example files in the w3mir distribution.  It
+will also be explained here.  The configuration file is typically
+called <tt>.w3mirc</tt> (<tt>w3mir.ini</tt> on win32 machines), and
+can be written with a simple text editor.  It is kept in the top
+directory of the mirror, where w3mir will find it when it starts.
+Please refer to the <a href="#contents">contents</a> for how to handle
+a specific problem with a configuration file.
+
+<hr>
+
+<h2>The answers:</h2>
+
+<hr>
+
+<h3><a name="copy">How do I copy a file?</a></h3>
+
+<p>To copy the top page off www.starwars.com:
+
+<p><tt>w3mir http://www.starwars.com/</tt>
+
+<p><b>Note:</b> it is <em>important</em> that you give the trailing
+slash for server names and directories.
+
+<hr>
+
+<h3><a name="recurse">How to I copy a directory hierarchy?</a></h3>
+
+<p>To copy the entire stuff about episode I from www.starwars.com
+which is stored in <tt>http://www.starwars.com/episode-i/</tt> (I don't
+recommend this, it's quite a lot of data):
+
+<p><tt>w3mir -r http://www.starwars.com/episode-i/</tt>
+
+<p>The corresponding configuration file is simple:
+
+<pre>
+Options: recurse
+URL: http://www.starwars.com/episode-i/
+Fixup: run
+</pre>
+
+<p>The <tt>-r</tt> option makes w3mir recurse down from the starting
+point.  It will only copy all the documents under
+http://www.starwars.com/episode-i/ that it sees referenced from those
+same documents.  W3mir will <em>not</em> retrieve documents from
+http://www.starwars.com/ because it is considered to be 'over' the
+starting point.
+
+<p>The command-line will get you a copy that is definitely browseable
+via a WEB server, and possibly browseable directly from a CDROM or
+hard-disk.  To ensure that it is browseable from CDROM and disk you
+need to use a configuration file with the <tt>Fixup: run</tt> line in.
+It causes w3mir to edit anything that needs editing after the mirror
+has completed, including fixing URLs that caused redirects.  The dirty
+work is done by w3mirs helper program w3mfix.  The directive will
+cause w3mfix to be run each time w3mir completes the mirror.
+
+<p><b>Note:</b> it is <em>important</em> that you give the trailing
+slash after the directory name.  Specifying
+<tt>http://www.starwars.com/episode-i</tt> and
+<tt>http://www.starwars.com/episode-i/</tt> is quite different in
+w3mirs eyes.  In the former case episode-i is considered to be a
+document within the / (top) directory of www.starwars.com and w3mir
+will recurse from /, which is a lot more than you wanted.  In the
+latter case w3mir understands that episode-i is a directory and will
+consider that directory to be the staring point, which is what you
+wanted.
+
+<hr>
+
+<h3><a name="resources">How do I copy the needed resource files from
+another directory hierarchy?</a></h3>
+
+<p>Some sites store their documents in one place, and puts their
+banners, icons and such in a separate directory called
+<tt>/images</tt>, <tt>/banners</tt>, <tt>/icons</tt>,
+<tt>/resources</tt> or some such.  Unless you retrieve these as well as
+the documents things will probably not be too colorful.  So, imagine
+that the starwars site stored all the images in one holding directory
+called <tt>/imagery</tt> and you want to copy all the stuff in it that
+the episode-i pages need.  Then you do this:
+
+<pre>
+Options: recurse
+URL: http://www.starwars.com/episode-i/ episode-i
+Also: http://www.starwars.com/imagery/ imagery
+Fixup: run
+</pre>
+
+<p>There are two changes here compared to the simpler file we started
+with: There is an extra argument at the end of the URL directive.  It
+tells w3mir to store everything gotten from
+<tt>http://www.starwars.com/episode-i/</tt> in the subdirectory
+<tt>episode-i</tt>.  The directory can be omitted, but I think its
+neater this way.  Then the new directive 'Also:'.  It tells w3mir that
+you also want whatever the documents under
+<tt>http://www.starwars.com/episode-i/</tt> references under
+<tt>http://www.starwars.com/imagery/</tt>.
+
+<p><b>Note:</b> this will only get stuff that was used by the
+documents under <tt>http://www.starwars.com/episode-i/</tt>, anything
+stored under <tt>http://www.starwars.com/imagery/</tt> which is not
+used will not be retrieved. If you want everything under
+<tt>imagery</tt> to be retrived use the <tt>Also-quene:</tt>
+directive.
+
+<hr>
+
+<h3><a name="ignore">How do I avoid copying files I don't want or copy
+only files I want?</a></h3>
+
+<p>To control what files w3mir copies you can use the
+<tt>Ignore:</tt>, <tt>Fetch:</tt>, <tt>Ignore-RE:</tt> and
+<tt>Fetch-RE:</tt> directives in the configuration file.  The embeded
+references to any file you chose to ignore, i.e., not copy, will point
+at the original site, <em>not</em> to the mirror.  This means that the
+mirror user may still get ahold of the file from the original source
+by simply clicking if she so desires.
+
+<p>If a site contains huge .wav audio files that you are not
+interested in you put
+
+<pre>
+Ignore: *.wav
+</pre>
+
+<p>in the configuration file.  You may ignore as many different
+filename patterns as you want.  If you are mirroring a site you want
+very few, specific files from, say all HTML (named
+<em>something</em><tt>.html</tt>) and all Mpeg video files (named
+<em>something</em><tt>.mpg</tt>) you can write this:
+
+<pre>
+Fetch: *.html
+Fetch: *.mpg
+Ignore: *
+</pre>
+
+<p>W3mir will test each filename against each Fetch/Ignore rule in
+sequence.  A html file will match the first line and be fetched.  Any
+mpg file will match the second line and be fetched.  All other files
+will match the third line, and be ignored.  This last line is needed
+because the default is to get any files which are not ignored.  By
+arranging fetch and ignore rules carefully you may retrieve exactly
+the filename patterns you want and not retrieve anything else.
+
+<p>If you decide you also want all Mpeg Layer 3 audio files
+(<em>something.</em><tt>mp3</tt>) from the site, after the mirror has
+been established.  Then you add this:
+
+<pre>
+Fetch: *.mp3
+</pre>
+
+<p>as the third line, making the <tt>Ignore: *</tt> line the forth and
+last.  Then you must fix all references to .mp3 files within the
+mirror by running w3mfix thus:
+
+<pre>
+w3mfix -editref .mp3
+</pre>
+
+<p>which will edit all references to .mp3 files, pointing them the
+right place, on your disk. Ditto when you remove a fetch rule, or add
+or remove an ignore rule. See the answer about <a
+href="#enlarge">enlarging and pruning</a> mirrors for more examples of
+using <tt>w3mfix -editme ...</tt>
+
+<p><b>Note:</b> when retrieving only a very limited set of files, as
+in the example above, you <em>must</em> retrieve the html files,
+because how else will w3mir find URLs of files to retrieve? Only html
+files contain links to other files.
+
+<p>Similarly, you may chose to not mirror whole branches of the
+original site.  If you for example mirror my home-pages, and you decide
+not to mirror the comics pages you can put
+
+<pre>
+Ignore: /ts/
+</pre>
+
+<p>or more precisely
+
+<pre>
+Ignore: http://www.ifi.uio.no/~janl/ts/
+</pre>
+
+<p>in the configuration file.  If you do this after having established
+the mirror you use w3mfix to fix the references:
+
+<pre>
+w3mfix -editref /ts/
+</pre>
+
+<p><tt>Fetch:</tt> and <tt>Ignore:</tt> rules can only use a very
+limited subset of the Unix wild-cards.  w3mir understands only '?',
+'*', and '[a-z]' ranges.
+
+<p><tt>Ignore-RE:</tt> and <tt>Fetch-RE:</tt> are the same as
+<tt>Fetch:</tt> and <tt>Ignore:</tt> except that they give you access
+to the full power of Regular Expressions to make rules for that to get
+or not to get. They support perls superset of the normal Unix regular
+expression syntax.  They must be completely specified, including the
+prefixed m, a delimiter of your choice (except the paired delimiters:
+parenthesis, brackets and braces), and any of the RE modifiers. I.e.,
+
+<pre>
+Ignore-RE: m/.gif$/i
+</pre>
+
+<p>or
+
+<pre>
+Ignore-RE: m~/.*/.*/.*/~
+</pre>
+
+<p>and so on.  "#" cannot be used as delimiter as it is the comment
+character in the configuration file.
+
+<p>There are some traps when using <tt>Ignore-RE</tt> and
+<tt>Fetch-RE</tt>, please see their documentation in <tt>mandoc
+w3mir</tt> for a more complete explanation.
+
+<hr>
+
+<h3><a name="depth">How do I limit how deep w3mir will recurse?</a></h3>
+
+<p>W3mir has no explicit mechanism to limit the depth of recursion,
+but the same result can be achieved with a simple <tt>Ignore</tt> rule:
+
+<pre>
+Ignore: /*/*/*/*/*/*/
+</pre>
+
+<p>This will ignore any URLs that contain at least 7 slashes ("/").
+Note that a URL contains three slashes that does not have anything to
+do with depth:
+
+<pre>
+http://www.ifi.uio.no/
+</pre>
+
+<p>so only the surplus slashes are used for depth in this match.  In the
+example above the limit is 4 levels from the top.  The
+<tt>Ignore:</tt> rule that is used to limit recursion depth must be
+listed before any <tt>Fetch:</tt> rules to be effective.
+
+<hr>
+
+<h3><a name="memory">How do I limit w3mirs memory usage?</a></h3>
+
+<p>In a mirror consisting of <em>many</em> files, such as a archive of
+an active mailinglist w3mir will build a very large referer table, in
+part for w3mir to use in the <tt>Referer:</tt> header and in part for
+w3mfix to use in fixing references.
+
+<p>If you disable both the <tt>Referer:</tt> header and don't use
+w3mfix w3mir will not build a referer table.  You do this in the
+configuration file:
+
+<pre>
+Disable-headers: referer
+Fixup: off
+</pre>
+
+<p>Please note the potential problems of turning off fixup described
+earlier in this howto.  There are normaly no problems associated with
+simple sites, but if there are redirects fixup <em>is</em> needed for
+a consistent mirror.
+
+<hr>
+
+<h3><a name="rm">How do I remove the files are no longer on the
+original site from the mirror?</a></h3>
+
+<p>Over time the site you mirror will add files, and quite possibly
+remove files.  Or you might introduce new <tt>Ignore:</tt> rules after
+establishing the mirror that reduces the files wanted in the mirror.
+
+<p>By default w3mir will not delete such old files, some people might
+want to keep the files even if they are removed from the original
+site.  To remove the old/unwanted files you add 'remove' to the
+<tt>Options:</tt> line.
+
+<hr>
+
+<h3><a name="multi">How do I copy files from multiple sites?</a></h3>
+
+<p>In the answer to the previous question we see how to mirror several
+related sites.  For example, say you want to mirror all my home-pages
+into one mirror:
+
+<pre>
+Option: recurse
+URL: http://www.math.uio.no/~janl/ math/janl
+Also: http://www.math.uio.no/drift/personer/ math/drift
+Also: http://www.ifi.uio.no/~janl/ ifi/janl
+Also: http://www.mi.uib.no/~nicolai/ math-uib/nicolai
+</pre>
+
+<p>As in the previous example this will only get documents that are
+referenced.  Any documents that are stored at these location but to
+which w3mir finds no references will not be retrieved.  So this will
+fail if the sites are not in any way related, or if you wanted
+<em>everything</em> stored at each site.
+
+<p>To mirror unrelated sites, or get it all you may specify that the
+given URL should be considered a starting-point as well:
+
+<pre>
+Also-quene: http://www.math.uio.no/drift/personer/ math/drift
+</pre>
+
+<p>and, if you want to add an additional starting-point within a already
+named site:
+
+<pre>
+Quene: http://www.math.uio.no/drift/personer/foo.html
+</pre>
+
+<p>Armed with that you should be able to get pretty much anything you
+like.
+
+<hr>
+
+<h3><a name="alias">How do I copy files from one server with several
+names?</a></h3>
+
+<p>Simple, the same way you mirror several servers with different
+names. The math department at University of Oslo has a web server
+known under two names: math-www.uio.no and www.math.uio.no, and both
+names are used in documents stored on it. To copy the whole server,
+one time only, give these URL and Also lines:
+
+<pre>
+URL: http://www.math.uio.no/ .
+Also: http://math-www.uio.no/ .
+</pre>
+
+<p>Note the period/dot (.) at the end of each line.  It means that
+w3mir will store the files in the current directory, i.e. documents
+from both servers will be stored in the same place.  But since w3mir
+asks to only get documents that are newer than the ones it already has
+any document gotten from the server under the www.math.uio.no name
+will not be gotten from the math-www.uio.no name as well.  ... w3mir
+will ask for the document, but the server will tell w3mir that its
+copy is current and there will be no additional transfer of the
+document.
+
+<hr>
+
+<h3><a name="enlarge">How do I enlarge or prune an established
+mirror?</a></h3>
+
+<p>This only works if you use a configuration file.
+
+<p>If you want to add a site or directory to a mirror you simply add
+the needed <tt>Also:</tt> or <tt>Also-Quene:</tt> to the configuration
+file and then you run w3mfix manually, with the -editref option.  If,
+you for example have established a mirror of my home-pages, but want to
+add my wife's home-page you add this
+
+<pre>
+Also: http://www.ifi.uio.no/~annen/ ifi/annen
+</pre>
+
+<p>to the configuration shown earlier.  Then you run w3mfix, and you want
+it to fix all URLs referencing her home-page, the distinguishing
+characteristic is the name 'annen':
+
+<pre>
+w3mfix -editref annen
+</pre>
+
+<p>but 
+
+<pre>
+w3mirx -editref http://www.ifi.uio.no/~annen/
+</pre>
+
+<p>would work too, but it's a lot more to type.  This fixes all the
+references to her home-page so that they point to the mirror instead of
+the original pages.
+
+<p>To prune (cut out something) a mirror you do the same.  Make the
+change in the configuration file and run 'w3mfix -editme ...' to fix
+the references to that which you removed.
+
+<hr>
+
+<h3><a name="cat">How do I 'cat' a file?</a></h3>
+
+<p>W3mir will output the fetched document to its standard output
+(normally your screen/window) if you specify the '-s' command line
+option.  The corresponding configuration file directive is 
+
+<pre>
+File-Disposition: stdout
+</pre>
+
+<hr>
+
+<h3><a name="list">How do I list URLs in a document?</a></h3>
+
+<p>To list the URLs in http://www.math.uio.no/:
+
+<pre>
+w3mir -q -f -l http://www.math.uio.no/
+</pre>
+
+<p>The <tt>-q</tt> switch causes w3mir to produce no other output
+which would disturb the URL listing.  The <tt>-f</tt> switch tells
+w3mir to forget the document once it has been analyzed, i.e., not save
+it on disk.  And finally, the <tt>-l</tt> switch makes w3mir list the
+URLs in the document.  You may combine <tt>-l</tt> with <tt>-r</tt>
+and you need not use it with <tt>-f</tt>.
+
+<p>In the configuration file you put <tt>list</tt> on the
+<tt>Options:</tt> line.
+
+<hr>
+
+<h3><a name="aborted">How to I restart a mirror process after stopping
+it prematurely?</a></h3>
+
+<p>You may just rerun the same command once more.  But that makes
+w3mir request all the documents you have already once more to see if a
+more recent version is available on the server.  You can save time by
+using the <tt>-fs</tt> (Fetch Some) option.  This makes w3mir only
+request documents it does not find on your disk.  E.g.:
+
+<p><tt>w3mir -fs -r http://www.starwars.com/</tt>
+
+<p>This is not something you would normally put in the configuration
+file, but you can, by adding 'only-nonexistent' on the 'Options:' line.
+
+<hr>
+
+<h3><a name="robots">How do I disable robots.txt obedience?</a></h3>
+
+<p>Normally w3mir will read and obey each sites robots.txt file,
+because w3mir wants to be a nice tool. However robots.txt was designed
+with something slightly different than the normal use of w3mir in
+mind, so if you want w3mir to disregard the robot rules you can use
+<tt>-drr</tt> (Disable Robot Rules) on the command-line, or the line
+
+<pre>
+Robot-Rules: off
+</pre>
+
+<p>in the configuration file.  The robot exclusion standard is
+described in <a
+href="http://info.webcrawler.com/mak/projects/robots/norobots.html">http://info.webcrawler.com/mak/projects/robots/norobots.htm</a>.
+
+<hr>
+
+<h3><a name="corrupt">How do I stop w3mir from corrupting binary
+files?</a></h3>
+     
+<p>During the normal course of events w3mir converts the newline
+format of fetched HTML documents to your systems native newline
+format. On Unix a newline consists of a single ASCII LF character, on
+Macintoshes it's a single ASCII CR character and on Dos/Windows it's a
+ASCII CR/LF pair. W3mir understands all these and all HTML files are
+saved in the format your operating system prefers.
+
+<p>If, and this is very unlikely, a web server identifies a binary
+file as HTML w3mir will very likely corrupt the file. If you discover
+a file which is obviously ruined in the mirror, but is not ruined when
+you view it on the original site do this:
+
+<ol>
+
+<li>Notify the webmaster on the original site that the file has the
+wrong MIME type
+
+<li>Use the <tt>-nnc</tt> (No Newline Conversion) option on the
+command line, or
+
+<pre>
+Options: no-newline-conv
+</pre>
+
+in the configuration file.
+
+<li>Remove the corrupt file(s).
+
+<li>Run "<tt>w3mir -fs</tt>...", to fetch only the deleted file(s)
+again.
+
+</ol>
+
+<hr>
+
+<h3><a name="auth">How do I copy a site that wants user-name and
+password?</a></h3>
+
+<p>This can only be done with a configuration file.  Being able to
+give this on the command-line would give the user-name and password away
+to other users of the system, so the ability to give authentication
+information that way has not been put in w3mir.
+
+<p>In the configuration file you put:
+
+<pre>
+Auth-domain: */*
+Auth-user: me
+Auth-passwd: my-password
+</pre>
+
+<p>This will cause w3mir to give the user-name and password each time
+the server asks.  There is no way to make w3mir give the user-name and
+password each time no matter if the server asks or not.
+
+<hr>
+
+<h3><a name="mauth">How do I access a site that wants several
+different user-names and passwords?</a></h3>
+
+<p>If you have several user-names and passwords across
+the server(s) that are copied you need a slightly more advanced
+version of this that associates each user-name/password with a
+authentication "domain".  "Domain" is a HTTP concept.  It is simply a
+grouping of files and documents within a "realm".  One file or a whole
+directory hierarchy can belong to a realm.  One server may have many
+realms.  A user may have separate passwords for each realm, or the
+same password for all the realms the user has access to.  A
+combination of a server name, server port and a realm is called a
+domain.
+
+<pre>
+Auth-domain: theserver:theport/therealm
+Auth-user: me
+Auth-passwd: my-password
+
+Auth-domain: theserver:theport/otherrealm
+Auth-user: other-me
+Auth-password: other-password
+</pre>
+
+W3mir will tell you what the name of the realm is if it is unable to
+authenticate itself with the server. You may also use '*' as the realm
+name if you only copy documents from one realm on that server.
+
+<hr>
+
+<h3><a name="proxy">How do I use a proxy server?</a></h3>
+
+<p>On some secured sites you have to access the Internet through proxy
+servers to get out of the internal network.
+
+<p>A proxy server has a host name, and a port you must use. On the
+command line you simply specify <tt>-P proxy-host-name:proxy-port</tt>. In
+the configuration file you put this:
+
+<pre>
+HTTP-Proxy: proxy-host-name:proxyport
+</pre>
+
+<p>The main advantage of working through proxy servers other than
+security is that you take advantage of any caching the proxy server
+which can speed up retrievals enormously.
+
+<p>Another use of the proxy option is to "prime" the proxy servers
+cache.  I.e. you can use w3mir to fetch the documents through the proxy
+server to ensure that the documents are cached there later when you
+want to read them with your browser.  If you also specify 
+
+<pre>
+File-Disposition: forget
+</pre>
+
+<p>it won't even use any space on your disk, w3mir will just process
+the documents looking for URLs and then <em>not</em> save them.
+
+<hr>
+
+<h3><a name="pauth">How do I authenticate myself to a proxy
+server?</a></h3>
+
+<p>Some proxy servers demands a user-name and password to let you use
+them.  W3mir does not support the domain concept in connection with
+proxy authentication because the author cannot imagine that it will be
+needed.  You need to put this in your configuration file:
+
+<pre>
+HTTP-Proxy-user: proxy-username
+HTTP-Proxy-passwd: proxy-password
+</pre>
+
+<hr>
+
+<h3><a name="proxytweak">How do I ensure that the proxy server
+...?</a></h3>
+
+<p>HTTP/1.0 proxy servers may be told to not use its current copy of
+a document if you specify the <tt>-pflush</tt> command-line option.  Or 
+
+<pre>
+Proxy-Options: refresh
+</pre>
+
+<p>in the configuration file.  This is useful if the proxy has an old
+copy of some document and does not realize that a newer version exists
+on the origin site.  W3mir uses the HTTP/1.0 version of this command
+by default.  You can force w3mir to use the HTTP/1.1 version by adding
+<tt>no-pragma</tt> to the line.  If you do this it will not work at
+all as you want unless the server knows the HTTP/1.1 protocol.
+
+
+<p>HTTP/1.1 proxy servers can be manipulated in a few more ways.  The
+configuration file <tt>Proxy-Options:</tt> directive also takes
+<tt>revalidate</tt> and <tt>no-store</tt> options.  The former tells
+the proxy server to check if there is any newer version available.
+This is, in principle, more network friendly than the <tt>refresh</tt>
+option since it will only cause a copy if there is a newer file
+available.  The <tt>no-store</tt> option tells the proxy server to not
+store the documents you transfer.  This might be useful if the
+documents are 'sensitive' or something like that, but if the proxy
+server does not understand HTTP/1.1 it will not obey this option, and
+it might store the document anyway because the functionality is not
+implemented, so you should not count on this to work.
+
+<hr>
+
+<h3><a name="batchget">How do I batch get files with w3mir?</a></h3>
+
+<p>Normally when fetching files w3mir will process each html (and PDF)
+file to find URLs in them for further retrievals.  This is
+time-consuming, and not always wanted.  Sometimes you simply want to
+get a file, or more, and save it, untouched:
+
+<pre>
+w3mir -B http://www.starwars.com/ http://www.ifi.uio.no/~janl/
+</pre>
+
+<p>There is a companion switch for <tt>-B</tt>, namely <tt>-I</tt>, it
+makes w3mir read URLs from its standard input, one pr. line.  Thus you
+can use w3mir in a pipe to batch get several files whose URLs you find
+in some way.  This is a stupid example:
+
+<pre>
+w3mir -q -l -f http://www.ifi.uio.no/ | w3mir -I -B
+</pre>
+
+<p><tt>-B</tt> may also be used with <tt>-r</tt>, but the only effect
+it will have then is to save the html files unchanged on disk, because
+to recurse w3mir <em>has</em> to examine all the html the documents
+for URLs.
+
+<p><b>Please note</b> that using <tt>-B</tt> combined with <tt>-r</tt>
+for mirroring will probably lead to a unstable mirror, because w3mir
+does not get a chance to manipulate the URLs in the documents as it
+needs to be able to maintain a mirror later, and most important of
+all, w3mir needs all html files to contain a &lt;HTML&gt; tag to be
+able to recognize a HTML file as a HTML file. When running with the
+<tt>-B</tt> switch w3mir will not ensure the presence of this and thus
+we must rely on the original documents author to be nice. This is a
+bad bet. In other words, <b>don't use <tt>-B</tt> for recursive
+mirroring</b>, only for batch copying/mirroring of single documents.
+
+<hr>
+
+<h3><a name="cgi">How do I handle CGI?</a></h3>
+
+<p>There is no way w3mir can duplicate the process that happens on the
+Web server when it comes to CGI.  For some CGI programs w3mir can
+simply copy the output and store on disk.  For other CGI programs this
+is not possible, and the only way out is to make w3mir not get the
+involved files using Ignore rules in the configuration file.  These
+will avoid a lot of cgi programs:
+
+<pre>
+Ignore: *.cgi
+Ignore: *-cgi
+</pre>
+
+<p>You might have to add other/more rules for some sites if they have
+other naming conventions or if it's simply impossible to tell from the
+file-name if it's a CGI or not.
+
+<p>When you add ignore rules this causes two things:
+
+<ol>
+<li><p>W3mir will not retrieve documents matching the rules
+<li><p>W3mir will make all references to matching documents point to
+  the site you mirrored from instead of pointing to a non-existent
+  file in the mirror.
+</ol>
+
+<hr>
+
+<h3><a name="imap">How do I handle server side image-maps?</a></h3>
+
+<p>Server side image-maps is yet another thing it's impossible for
+w3mir to relate to.  w3mir simply cannot handle them.  Put ignore
+rules in the configuration file:
+
+<pre>
+Ignore: *.map
+</pre>
+
+<p>W3mir has full support for client side image-maps though.
+
+<hr>
+
+<h3><a name="java">How do I handle Java and ActiveX?</a></h3>
+
+<p>Java and Active X objects are are included in html pages with a
+<tt>&lt;OBJECT&gt;</tt> or <tt>&lt;APPLET&gt;</tt> tag.  W3mir can
+handle these on one condition: The CODEBASE attribute names the
+directory where the program stores its resources (such as
+subprograms, graphic files, sound, text, and so on) and w3mir must
+have read access to this directory.  Otherwise w3mir is without hope,
+it's impossible to extract the name of the resources the program needs
+in any reliable way.
+
+<p>HTML4 supports a attribute that enumerates the resources the
+program needs, w3mir is not able to use this yet.
+
+<hr>
+
+<h3><a name="script">How do I handle java-script and other script
+languages?</a></h3>
+
+<p>W3mir does its best to pass scripts (java-script, perl-script,
+etc...) embedded in the HTML undamaged.  It cannot, however, extract
+any URLs the script generates and the browser would cause the document
+to refer to or embed in a page. 
+
+<p>It will however work if the script generates relative references
+and there is some other way for w3mir to access the referenced file in
+some other manner.  Or if the script generates absolute references and
+the person browsing the mirror has access to the site named, then the
+user will be able to browse the referenced documents via that other
+server.
+
+<hr>
+
+<h3><a name="css">How to I handle the other things with 'partial
+support'</a></h3>
+
+<p>W3mir has partial support for CSS.  This means that
+<tt>&lt;style&gt</tt> tags and the enclosed style data are passed
+undamaged by w3mir.  W3mir will also retrieve the external CSSes named
+in HTML documents.  But w3mir will <em>not</em> (yet) analyze the
+CSSes data to find URLs of other resources (such as fonts) named in
+these.
+
+<p>W3mir also has partial support for Adobe Acrobat (PDF) files.  This
+means that w3mir can extract URLs from PDF files, and get the named
+documents if you want them.  But w3mir cannot edit those URLs so that
+the PDF files point to the mirror instead of wherever on the original
+site they were pointing.  If the PDF files contain absolute URLs they
+will continue pointing to where they were pointing before.  However,
+if the PDF files contain relative references things will work out.
+
+<p>The reason that URLs in PDF files cannot be edited is that they are
+binary and contain byte pointers.  If the URLs length is changed the
+byte pointers will point to the wrong place in the document.  Writing
+code to correct these pointers would be quite complex.  But if you
+write it I will use it.
+
+<hr>
+
+<h3><a name="anon">How do I keep my identity secret?</a></h3>
+
+<p>The HTTP protocol has a header, <tt>User:</tt> which is recommended
+to use by robots, such as w3mir.  Another way to track you is looking
+at the 'Referer:' header w3mir gives in HTTP requests.  Both can be
+disabled:
+
+<pre>
+Disable-headers: referer, user
+</pre>
+
+<p>If you in addition use a proxy server that many other users use
+there is little probability you can be tracked (easily) by the server
+you are copying things from.  You are however much easier to track
+from the logs in the proxy server.  And a court order is quite likely
+to get you tracked in spite of any precautions you take.  
+
+<p>W3mir does not support cookies and thus you cannot be tracked with
+the help of that mechanism.
+
+<hr>
+
+<h3><a name="ns">How do I pretend that I'm using Netscape, Internet
+Explorer or Lynx?</a></h3>
+
+<p>Some web sites give you different documents when you ask for a
+specific URL based on what browser you use, or even what OS you appear
+to be using.  w3mir identifies itself with a string that looks like
+this:
+
+<p><tt>w3mir/<em>version</em>-<em>release-date</em></tt>
+
+<p>Netscape identifies itself with strings that look something like
+this:
+
+<p><tt>Mozilla/3.01 (X11; I; Linux 2.0.30 i586)</tt>
+
+<p>and Internet Explorer says it's something like this:
+
+<p><tt>Mozilla/2.0 (compatible; MSIE 3.02; Windows NT)</tt>
+
+<p>and Lynx says something like this
+
+<p><tt>Lynx/2.6  libwww-FM/2.14</tt>
+
+<p>You can change w3mirs identification with <tt>-agent 'string'</tt>
+on the command line.  In the configuration file you put
+
+<pre>
+Agent: Mozilla/3.01 (X11; I; Linux 2.0.30 i586)
+</pre>
+
+<p>to pretend w3mir is netscape 3.01.
+
+<hr>
+
+<h3><a name="other">How do I do other things?</a></h3>
+
+<p>This document is by no means a complete list of the things you can
+do with w3mir.  The w3mir man page (<tt>man w3mir</tt> or <tt>perldoc
+w3mir</tt> lists more things, and goes into more detail of how things
+work so you can use the knowledge to do neat things.  There are
+several things mentioned only in the man-page that helps you with
+tricky multi-server mirroring, and gives you better control of what to
+get and not to get and under what name to save it on disk.  And a
+couple of other things...
+
+<hr>
+<address>Nicolai Langfeldt 9/7/1998</address>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3mir.PL
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3mir.PL	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3mir.PL	(revision 10506)
@@ -0,0 +1,3291 @@
+# -*-perl-*-
+
+use Config;
+
+&read_makefile;
+$fullperl = resolve_make_var('FULLPERL') || $Config{'perlpath'};
+$islib = resolve_make_var('INSTALLSITELIB');
+
+$name = $0;
+$name =~ s~^.*/~~;
+$name =~ s~.PL$~~;
+
+open(OUT,"> $name") || 
+  die "Could open $name for writing: $!\n";
+
+print "writing $name\n";
+
+while (<DATA>) {
+  if (m~^\#!/.*/perl.*$~o) {
+    # This substitutes the path perl was installed at on this system
+    # _and_ removed any (-w) options.
+    print OUT "#!",$fullperl,$1,"\n";
+    next;
+  }
+  if (/^use lib/o) {
+    # This substitutes the actuall library install path
+    print OUT "use lib '$islib';\n";
+    next;
+  }
+  print OUT;
+}
+
+close(OUT);
+
+# Make it executable too, and writeable
+chmod 0755, $name;
+
+#### The library
+
+sub resolve_make_var ($) {
+
+  my($var) = shift @_;
+  my($val) = $make{$var};
+
+#  print "Resolving: ",$var,"=",$val,"\n";
+  
+  while ($val =~ s~\$\((\S+)\)~$make{$1}~g) {}
+#  print "Resolved: $var: $make{$var} -> $val\n";
+  $val;
+}
+
+
+sub read_makefile {
+
+  open(MAKEFILE, 'Makefile') || 
+    die "Could not open Makefile for reading: $!\n";
+
+  while (<MAKEFILE>) {
+    chomp;
+    next unless m/^([A-Z]+)\s*=\s*(\S+)$/;
+    $make{$1}=$2;
+#    print "Makevar: $1 = $2\n";
+  }
+
+  close(MAKEFILE)
+}
+
+__END__
+#!/local/bin/perl5 -w
+# Perl 5.002 or later.  w3mir is mostly tested with perl 5.004
+#
+# You might want to change or comment out this:
+use lib '/hom/janl/lib/perl';
+#
+# Once upon a long time ago this was Oscar Nierstrasz's
+# <oscar@cui.unige.ch> htget script.
+#
+# Retrieves HTML pages, creating local copies in the _current_ 
+# directory. The script will check for the last-modified stamp on the
+# document, and will not fetch it if the document isn't changed.
+#
+# Bug list is in w3mir-README.
+#
+# Test cases for janl to use:
+#   w3mir -r -fs http://www.eff.org/ - infinite recursion!
+#     --- but cursory examination seems to indicate confused server...
+#   http://java.sun.com/progGuide/index.html check out the img things.
+#
+# Copyright Holders:
+#   Nicolai Langfeldt, janl@ifi.uio.no
+#   Gorm Haug Eriksen, gorm@usit.uio.no
+#   Chris Szurgot, szurgot@itribe.net
+#   Ed Jordan, ed@olympus.itl.net
+#   Alex Knowles, aknowles@avs.com aka ark.
+# Copying and modification is governed by the "Artistic License" enclosed in
+# the w3mir distribution
+#
+# History (European format date: dd/mm/yy):
+#  oscar 25/03/94 -- added -s option to send output to stdout
+#  oscar 28/03/94 -- made HTTP 1.0 the default
+#  oscar 30/05/94 -- special handling of directory URLs missing a trailing "/"
+#   gorm 20/02/95 -- added mirror capacity + fixed a couple of bugs
+#   janl 28/03/95 -- added a working commandline parser.
+#   janl 18/09/95 -- Changed to use a net http library.  Removed dependency of
+#		     url.pl.
+#   janl 19/09/95 -- Extensive rewrite. Simplified a lot, works better. 
+#		     HTML files are now saved in a new and improved manner,
+#		     which means they can be recognized as such w/o fancy
+#		     filename extention type rules.
+# szurgot 27/01/96-- Added "Plaintextmode" wrapper to binmode PAGE. 
+#                    binmode page is required under Win32, but broke modified
+#                    checking
+#                 -- Minor change added ; to "# '" strings for Emacs cperl-mode
+# szurgot 07/02/96-- When reading in local file for checking of URLs changed
+#                    local ($/) =0; to equal undef;
+#   janl 08/02/96 -- Added szurgot's changes and changed them :-)
+# szurgot 09/02/96-- Added code to strip /#.*$/ from urls when reading from 
+#                    local file
+#                 -- Added hasAlarm variable to w3http.pl. Set to 1 if you have
+#                    alarm(). 0 otherwise.
+#                 -- Moved code setting up the valid extensions list into the
+#                    args processing where it belonged
+#   janl 20/02/96 -- Added szurgot changes again.
+#		  -- Make timeout code work.
+#   		  -- and made another win32 test.
+#   janl 19/03/96 -- Worked through the code for handling not-modified 
+#    		     documents, it was a bit shabby after htmlop was intro'ed.
+#   janl 20/03/96 -- -l fix
+#   janl 23/04/96 -- Added -fs by request (by Rik Faith)
+#   janl 16/05/96 -- Made -R mandatory, added use and support for
+#			w3http::SAVEBIN
+# szurgot 19/05/96-- Win95 adaptions.
+#   janl 19/05/96 -- -C did not exactly work as expected.  Thanks to Petr
+#		     Novak for bug descriptions.
+#   janl 19/05/96 -- Changed logic for @didntget, @got and so on to use
+#		     @queue and %urlstat.
+#   janl 09/09/96 -- Removed -R switch.
+#   janl 14/09/96 -- Added ir (initial referer) switch
+#   janl 21/09/96 -- Made retry code saner.  There probably needs to be a
+#                    sleep before retry comencing switch.  When no tty is
+#                    present it should be fairly long.
+#   gorm 15/09/96 -- Added cr (check robot) switch. Default to 1 (on)
+#   janl 22/09/96 -- Modified gorms patch to use WWW::RobotRules.  Changed
+#		     robot switch to be consistent with current w3mir
+#                    practice.
+#   janl 27/09/96 -- Spelling corrections from charles.curran@ox.ac.uk
+#                 -- Folded in manual diffs from ark.
+#    ark 24/09/96 -- Simple facilities to edit the incomming file(s)
+#   janl 27/09/96 -- Added switch to enable <!--NOMIRROR--> editing and
+#		     foolproofed ark's patch a bit.
+#   janl 02/10/96 -- Added -umask switch.
+#		  -- Redirected documents did not have a meaningful referer
+#		     value (it was undefined).
+#		  -- Got w3mir into strict discipline, found some typos...
+#   janl 20/10/96 -- Mtime is preserved
+#   janl 21/10/96 -- -lc switch added.  Mtime preservation works better.
+#   janl 06/11/96 -- Treat 301 like 302.
+#   janl 02/12/96 -- Added config file code, fetch/ignore rules, apply
+#   janl 04/12/96 -- Better checking of config input.
+#   janl 06/12/96 -- Putting together the URL selection/editing brains.
+#   janl 07/12/96 -- Checking out some bugs.  Adding multiscope options.
+#   janl 12/12/96 -- Adding to and defeaturing the multiscope options.
+#   janl 13/12/96 -- Continuing work in multiscope stuff
+#                 -- Unreferenced file and empty directory removal works.
+#   janl 19/02/97 -- Can extract urls from adobe acrobat pdf files :-)
+#		     Important: It does _not_ edit urls, so they still
+#		     point at the original site(s).
+#   janl 21/02/97 -- Fix -lc bug related to case and the apply things.
+#		  -- only use SAVEURL if needed
+#   janl 11/03/97 -- Finish work on SAVEURL conditional.
+#		  -- Fixed directory removal code.
+#                 -- parse_args did not abort when unknown option/argument
+#		     was specified.
+#   janl 12/03/97 -- Made test case for -lc.  Didn't work.  Fixed it.  I think.
+#		     Realized we have bug w.r.t. hostname caseing.
+#   janl 13/03/97 -- All redirected to URLs within scope are now queued.  
+#		     That should make the mirror more complete, but it won't
+#		     help browsability when it comes to the redirected doc.
+#		  -- Moved robot retrival to the inside of the mirror loop
+#		     since we now possebly mirror several sites.
+#		  -- Changed 'fetch-options' to 'options'.
+#                 -- Added 'proxy-options'/-pflush to controll proxy server(s).
+#   janl 09/04/97 -- Started using URI::URL.
+#   janl 11/04/97 -- Debugging and using URI::URL more correctly various places
+#   janl 09/05/97 -- Added --agent switch
+#   janl 12/05/97 -- Simplified scope checks for root URL, changed URL 'apply'
+#		     processing.
+#		  -- Small output formating fix in the robot rules code.
+#		  -- Version is now 0.99
+#   janl 14/05/97 -- htmpop no-longer puts '<!DOCTYPE...' into doc, so check 
+#		     for '<HTML' instead
+#   janl 11/06/97 -- Made :port optional in server part of auth-domain.
+#			Always removing :80 from server part to match netloc.
+#   janl 22/07/97 -- More debugging of rewrite for new features -B, -I.
+#   janl 01/08/97 -- Fixed bug in RE quoting for Ignore/Fetch
+#   janl 04/08/97 -- s/writepage/write_page/g
+#   janl 07/09/97 -- 0.99b1 is released
+#   janl 19/09/97 -- Kaj Hejer discovers omissions in non-html-url-mining code.
+#                 -- 0.99b2 is released
+#   janl 24/09/97 -- Matt Chapman found bug in realm-name extraction.
+#   janl 10/10/97 -- Referer: header supression supressed User: header instead
+#		  -- Added fixup handling, writes .redirs and .referers
+#		     (no dot in win32)
+#  		  -- Read .w3mirc (w3mir.ini on win32) if present
+#		  -- Stop file removal code from removing these files
+#   janl 16/10/97 -- process_tag was mangling url attributes in tags with more
+#		     than one of them.  Problem found by Robert L. Binkley
+#   janl 04/12/97 -- Fixed problem with authentication, misplaced +
+#		  -- default inter-docuent pause is 0.  I figure it's better
+#		     to keep one httpd occupied in a steady stream than to
+#		     wait for it to die before we talk to it again.
+#   janl 13/12/97 -- The arguments to index.html in the form of index.html/foo
+#		     handling code was incomplete.  To make it complete would
+#		     have been hard, so it was removed.
+#		  -- If a URL changes from file to directory or vice versa
+#		     this is now handled.
+#   janl 11/01/98 -- PDF files with no URLs does not cause warnings now.
+#		  -- Close REFERERS and REDIRECTS before calling w3mfix
+#   janl 22/01/98 -- Proxy authentication as outlined by Christian Geuer
+#   janl 04/02/98 -- Version 1pre1
+#   janl 18/02/98 -- Fixed wild_re after tip by Prentiss Riddle.
+#		  -- Version 1pre2
+#   janl 20/02/98 -- w3http updated to handle complex content-types.
+#		  -- Fix wild_re more, bug noted by James Dumser
+#		  -- 1.0pre3
+#   janl 18/03/98 -- Version 1.0 is released
+#   janl 09/04/98 -- Added feature so user can disable newline conversion.
+#   janl 20/04/98 -- Only convert newlines in HTML files. -> 1.0.2
+#   janl 09/05/98 -- More carefull clean_disk code.
+#		  -- Check if the redirected URL was a root url, if so
+#		     issue a warning and exit.
+#   janl 12/05/98 -- use ->unix_path instead of ->as_string to derive local
+#		     filename.
+#   janl 25/05/98 -- -B didn't work too well.
+#   janl 09/07/98 -- Redirect to fragment broke us, less broken now -> 1.0.4
+#   janl 24/09/98 -- Better errormessages on errors -> 1.0.5
+#   janl 21/11/98 -- Fix errormessages better.
+#   janl 05/01/99 -- Drop 'Referer: (commandline)'
+#   janl 13/04/99 -- Add initial referer to root urls in batch mode.
+#
+# Variable name discipline:
+# - remote, umodified URL.  Variables prefixed 'rum_'
+# - local, filesystem.  Variables prefixed 'lf_'.
+# Use these prefixes so we know what we're working with at all times.
+# Also, URL objects are postfixed _o
+#
+# The apply rules and scope rules work this way:
+# - First apply the user rules to the remote url.
+# - Check if document is within scope after this.
+# - Then apply w3mir's rules to the result.  This results is the local,
+#   filesystem, name.
+#
+# We use features introduced in 5.002.
+require 5.002;
+
+# win32 and $nulldevice need to be globals, other modules use them.
+use vars qw($win32 $nulldevice);
+
+# To figure out what kind of system this is
+BEGIN {
+  use Config;
+  $win32 = ( $Config{'osname'} eq 'MSWin32' ); 
+}
+# More ways to die:
+use Carp;
+# Http module:
+use w3http;
+# html url extraction and manupulation:
+use htmlop;
+# Extract urls from adobe acrobat pdf files:
+use w3pdfuri;
+# Date computer:
+use HTTP::Date;
+# URLs:
+use URI::URL;
+# For flush method
+use FileHandle;
+
+# Full discipline:
+use strict;
+
+# Set params in the http package, HTTP protocol version:
+$w3http::version="1.0";
+
+# The defaults should be for a robotic http agent on good behaviour.
+my $debug=0;			# Debug level
+my $verbose=0;			# Verbosity level, -1 = quiet, 0 = normal, 1...
+my $pause=0;			# Pause between http requests
+my $retryPause=600;		# Pause between retries. 10 minutes.
+my $retry=3;			# Max 3 stabs pr. url.
+my $r=0;			# Recurse? no recursion = absolutify links
+my $remove=0;			# Remove files that are not there?
+my $s=0;			# 0: save on disk 1: stdout 2: just forget 'em
+my $useauth=0;			# Use authorization
+my %authdata;			# Authorization data
+my $check_robottxt = 1;		# Check robots.txt
+my $do_referer = 1;		# Send referers header
+my $do_user = 1;		# Send user header
+my $cache_header = '';		# The cache-control/pragma: no-cache header
+my $using_proxy = 0;		# Using proxy server or not?
+my $batch=0;			# Batch get URLs?
+my $read_urls=0;		# Get urls from STDIN?
+my $abs=0;			# Absolutify URLs?
+my $immediate_redir=0;		# Immediately follow a redirect?
+my @root_urls;			# This is where we start, the root documents
+my @root_dirs;			# The corresponding directories.  for remove
+my $chdirto='';			# Place to chdir to after reading config file
+my %nodelete=();		# Files that should not be deleted
+my $numarg=0;			# Number of arguments accepted.
+
+# Fixup related things
+my $fixrc='';			# Name of w3mfix config file
+my $fixup=1;			# Do things needed to run fixup
+my $runfix=0;			# Run w3mfix for user?
+my $fixopen=0;			# Fixup files open?
+
+my $indexname='index.html';
+
+my $VERSION;
+$VERSION='1.0.8';
+$w3http::agent = my $w3mir_agent = "w3mir/$VERSION-1999-05-28";
+my $iref='';			# Initial referer.  Must evaluate to false
+
+# Derived settings	
+my $mine_urls=0;		# Mine URLs from documents?
+my $process_urls=0;		# Perform (URL) processing of documents?
+
+# Queue of urls to get.
+my @rum_queue = ();
+my @urls = ();
+# URL status map.
+my %rum_urlstat = ();
+# Status codes:
+my $QUEUED   = 0;		# Queued but not gotten yet.
+my $TERROR   = 100;		# Transient error, retry later
+my $HLERR    = 101;		# Permanent error, give up
+my $GOTIT    = 200;		# Gotten. Note similarity to http result code
+my $NOTMOD   = 304;		# Not modified.
+# Negative codes for nonexistent files, easier to check.
+my $NEVERMIND= -1;		# Don't want it
+my $REDIR    = -302;		# Does not exist, redirected
+my $ENOTFND  = -404;		# Does not exist.
+my $OTHERERR = -600;		# Some other error happened
+my $FROBOTS  = -601;		# Forbidden by robots.txt rule
+
+# Directory/files survey:
+my %lf_file;		# What files are present in FS?  Disposition?  One of:
+my $FILEDEL=0;		# Delete file
+my $FILEHERE=1;		# File present in filesystem only
+my $FILETHERE=2;	# File present on server too.
+my %lf_dir;		# Number of files/dirs in dir.  If 0 dir is 
+			# eligible for deletion.
+
+my %fiddled=();		# If a file becomes a directory or a directory
+                        # becomes a file it is considered fiddled and
+                        # w3mir will not fiddle with it again in this
+                        # run.
+
+# Bitbucket device, very OS dependent.
+$nulldevice='/dev/null';
+$nulldevice='nul:' if ($win32);
+
+# What to get, and not.
+# Text of user supplied fetch/ignore rules
+my $rule_text=" # User defined fetch/ignore rules\n";
+# Code ref to the rule procedure
+my $rule_code;
+
+# Code to prefix and postfix the generated code.  Prefix should make
+# $_ contain the url to match.  Postfix should return 1, the default
+# is to get the url/file.
+my $rule_prefix='$rule_code = sub { local($_) = shift;'."\n";
+my $rule_postfix=" return 1;\n}";
+
+# Scope tests generated by URL/Also directives in cfg. The scope code
+# is just like the rule code, but used for program generated
+# fetch/ignore rules related to multiscope retrival.
+my $scope_fetch=" # Automatic fetch rules for multiscope retrival\n";
+my $scope_ignore=" # Automatic ignore rules for multiscope retrival\n";
+my $scope_code;
+
+my $scope_prefix='$scope_code = sub { local($_) = shift;'."\n";
+my $scope_postfix=" return 0;\n}";
+
+# Function to apply to urls, se rule comments.
+my $user_apply_code;	# User specified apply code
+my $apply_code;		# w3mirs apply code
+my $apply_prefix='$apply_code = sub { local($_) = @_;'."\n";
+my $apply_lc=' $_ = lc $_; ';
+my $apply_postfix='  return $_;'."\n}";
+my @user_apply;		# List of users apply rules.
+my @internal_apply;	# List of w3mirs apply rules.
+
+my $infoloss=0;		# 1 if any URL translations (which cause
+                        # information loss) are in effect.  If this is
+                        # true we use the SAVEURL operation.
+my $list;		# List url on STDOUT?
+my $edit;		# Edit doc? Remove <!--NOMIRROR>...<!--/NOMIRROR-->
+my $header;		# Text to insert in header
+my $lc=0;		# Convert urls/filenames to lowercase?
+my $fetch=0;		# What to fetch: -1: Some, 0: not modified 1: all
+my $convertnl=1;	# Convert newlines?
+
+# Non text/html formats we can extract urls from.  Function must take one
+# argument: the filename.
+my %knownformats = ( 'application/pdf', \&w3pdfuri::list,
+		     'application/x-pdf', \&w3pdfuri::list,
+		   );
+
+# Known 'magic numbers' of the known formats.  The value is used as
+# key in %knownformats.  the key part is a exact match for the
+# following <string> beginning at the first byte of the file.
+# This should probably be made more flexible, but not until we need it.
+
+my %knownmagic = ( '%PDF-', 'application/pdf' );
+
+my $iinline='';	# inline RE code to make RE caseinsensitive 
+my $ipost='';	# RE postfix to make it caseinsensitive
+
+usage() unless parse_args(@ARGV);
+
+{
+  my $w3mirc='.w3mirc';
+  
+  $w3mirc='w3mir.ini' if $win32;
+  
+  if (-f $w3mirc) {
+    parse_cfg_file($w3mirc);
+    $nodelete{$w3mirc}=1;
+  }
+}
+
+# Check arguments and options
+if ($#root_urls>=0) {
+  # OK
+} else {
+  print "URLs: $#rum_queue\n";
+  usage("No URLs given");
+}
+
+# Are we converting newlines today?
+$w3http::convert=0 unless $convertnl;
+
+if ($chdirto) {
+  &mkdir($chdirto.'/this-is-not-created-odd-or-what');
+  chdir($chdirto) || 
+    die "w3mir: Can't change working directory to '$chdirto': $!\n";
+}
+
+$SIG{'INT'}=sub { print STDERR "\nCaught SIGINT!\n"; exit 1; };
+$SIG{'QUIT'}=sub { print STDERR "\nCaught SIGQUIT!\n"; exit 1; };
+$SIG{'HUP'}=sub { print STDERR "\nCaught SIGHUP!\n"; exit 1; };
+
+&open_fixup if $fixup;
+
+# Derive how much document processing we should do.
+$mine_urls=( $r || $list );
+$process_urls=(!$batch && !$edit && !$header);
+# $abs can be set explicitly with -abs, and implicitly if not recursing
+$abs = 1 unless $r;
+print "Absolute references\n" if $abs && $debug;
+
+# Cache_controll specified but proxy not in use?
+die "w3mir: If you want to control a cache, use a proxy server!\n"
+  if ($cache_header && !$using_proxy);
+
+# Compile the second order code
+
+# - The rum scope tests
+my $full_rules=$scope_prefix.$scope_fetch.$scope_ignore.$scope_postfix;
+# warn "Scope rules:\n-------------\n$full_rules\n---------------\n";
+eval $full_rules;
+
+die "w3mir: Program generated rules did not compile.\nPlease report to w3mir-core\@usit.uio.no.  The code is:\n----\n".
+  $full_rules."\n----\n"
+  if !defined($scope_code);
+
+$full_rules=$rule_prefix.$rule_text.$rule_postfix;
+# warn "Fetch rules:\n-------------\n$full_rules\n---------------\n";
+eval $full_rules;
+
+# - The user specified rum tests
+die "w3mir: Ignore/Fetch rules did not compile.\nPlease report to w3mir-core\@usit.uio.no.  The code is:\n----\n".
+  $full_rules."\n----\n"
+  if !defined($rule_code);
+
+# - The user specified apply rules
+
+my $full_apply=$apply_prefix.($lc?$apply_lc:'').
+  join($ipost.";\n",@user_apply).(($#user_apply>=0)?$ipost:"").";\n".
+  $apply_postfix;
+eval $full_apply;
+
+die "w3mir: User apply rules did not compile.\nPlease report to w3mir-core\@usit.uio.no. The code is:
+----
+".$full_apply."
+----\n" if !defined($apply_code);
+
+$user_apply_code=$apply_code;
+
+# - The w3mir generated apply rules
+
+$full_apply=$apply_prefix.($lc?$apply_lc:'').
+  join($ipost.";\n",@internal_apply).(($#internal_apply>=0)?$ipost:"").";\n".
+  $apply_postfix;
+eval $full_apply;
+
+die "Internal apply rules did not compile.  The code is:
+----
+".$full_apply."
+----\n" if !defined($apply_code);
+
+# - Information loss via -lc?  There are other sources as well.
+$infoloss=1 if $lc;
+
+warn "Infoloss is $infoloss\n" if $debug;
+
+# More setup:
+
+$w3http::debug=$debug;
+
+$w3http::verbose=$verbose;
+
+my %rum_referers=();	# Array of referers, key: rum_url
+my $Robot_Blob;		# WWW::RobotsRules object, decides if rum_url is 
+			# forbidden to access for us.
+my $rum_url_o;		# rum url, mostly the current, the one we're getting
+my %gotrobots;		# Did I get robots.txt from site? key: url->netloc
+my($authuser,$authpass);# Username and password for authentication with server
+my @rum_newurls;	# List of rum_urls in document
+
+if ($check_robottxt) {
+  # Eval is only way to defer loading of module until we know it's needed?
+  eval 'use WWW::RobotRules;';
+
+  die "Could not load WWW::RobotRules, try -drr switch\n"
+    unless defined(&WWW::RobotRules::parse);
+
+  $Robot_Blob = new WWW::RobotRules $w3mir_agent;
+}
+
+# We have several main-modes of operation.  Here we select one
+if ($r) {
+
+  die "w3mir: No URLs?  Try 'w3mir -h' for help.\n"
+    if $#root_urls==-1;
+
+  warn "Recursive retrival comencing\n" if $debug;
+
+  die "w3mir: Sorry, you cannot combine -r/recurse with -I/read_urls\n"
+    if $read_urls;
+
+  # Recursive
+  my $url;
+  foreach $url (@root_urls) {
+    warn "Root url dequeued: $url\n" if $debug;
+    if (want_this($url)) {
+      queue($url);
+      &add_referer($url,$iref);
+    } else {
+      die "w3mir: Inconsistent configuration: Specified $url is not inside retrival scope\n";
+    }
+  }
+  mirror();
+
+} else {
+  if ($batch) {
+    warn "Batch retrival commencing\n" if $debug;
+    # Batch get
+    if ($read_urls) { 
+      # Get URLs from <STDIN>
+      while (<STDIN>) {
+	chomp;
+	&add_referer($_,$iref);
+	batch_get($_);
+      }
+    } else {
+      # Get URLs from commandline
+      my $url;
+      foreach $url (@root_urls) {
+	&add_referer($url,$iref);
+      }
+      foreach $url (@root_urls) {
+	batch_get($url);
+      }
+    }
+  } else {
+    warn "Single url retrival commencing\n" if $debug;
+
+    # A single URL, with all processing on
+    die "w3mir: You specified several URLs and not -B/batch\n"
+      if $#root_urls>0;
+    queue($root_urls[0]);
+    &add_referer($root_urls[0],$iref);
+    mirror();
+  }
+}
+
+&close_fixup if $fixup;
+
+# This should clean up files:
+&clean_disk if $remove;
+
+warn "w3mir: That's all (".$w3http::xfbytes.'+',$w3http::headbytes.
+  " bytes of it).\n" unless $verbose<0;
+
+if ($runfix) {
+  eval 'use Config;';
+  warn "Running w3mfix\n";
+  if ($win32) {
+    system($Config{'perlpath'}." w3mfix $fixrc");
+  } else {
+    system("w3mfix $fixrc");
+  }
+}
+
+exit 0;
+
+sub get_document {
+  # Get one document by HTTP ($1/rum_url_o).  Save in given filename ($2).
+  # Possebly returning references found in the document.  Caller must
+  # set up referer array, check wantedness and everything else.  We
+  # handle authentication here though.
+
+  my($rum_url_o)=shift;
+  my($lf_url)=shift;
+  croak("\$rum_url_o is empty") if !defined($rum_url_o) || !$rum_url_o;
+  croak("$lf_url is empty") if !defined($lf_url) || !$lf_url;
+
+  # Make sure it's an object
+  $rum_url_o = url $rum_url_o 
+    unless ref $rum_url_o;
+  
+  # Derive a filename from the url, the filename contains no URL-quoting
+  my($lf_name) = (url "file:$lf_url")->unix_path;
+
+  # Make all intermediate directories
+  &mkdir($lf_name) if $s==0;
+
+  my($rum_as_string) = $rum_url_o->as_string;
+
+  print STDERR "GET_DOCUMENT: '",$rum_as_string,"' -> '",$lf_name,"'\n"
+    if $debug;
+
+  my $hostport;
+  my $www_auth='';	# Value of that http reply header
+  my $page_ref;
+  my @rum_newurls;	# List of URLs extracted
+  my $url_extractor;
+  my $do_query;		# Do query or not?
+
+  if (defined($rum_urlstat{$rum_as_string}) && 
+      $rum_urlstat{$rum_as_string}>0) {
+    warn "w3mir: Internal error, ".$rum_as_string.
+      " queued several times\n";
+    next;
+  }
+
+  # Goto here if we want to retry b/c of authentication
+  try_again:
+
+  # Start building the extra http::query arguments again
+  my @EXTRASTUFF=();
+
+  # We'll start by assuming that we're doing the query.
+  $do_query=1;
+    
+  # If we're not checking the timestamp, or the file does not exist
+  # then we get the file unconditionally.  Otherwise we only want it
+  # if it's updated.
+
+  if ($fetch==1) {
+    # Nothing do do?
+  } else {
+    if (-f $lf_name) {
+      if ($fetch==-1) {
+	print STDERR "w3mir: ".($infoloss?$rum_as_string:$lf_name).
+	  ", already have it" if $verbose>=0;
+	if (!$mine_urls) {
+	  # If -fs and the file exists and we don't need to mine URLs
+	  # we're finished!
+	  warn "Already have it, no mining, returning!\n" if $debug;
+	  print STDERR "\n" if $verbose>=0;
+	  return;
+	}
+	$w3http::result=1304;	# Pretend it was 'not modified'
+	$do_query=0;
+      } else {
+	push(@EXTRASTUFF,$w3http::IFMODF,$lf_name);
+      }
+    }
+  }
+
+  if ($do_query) {
+
+    # Does the server want authorization for this file?  $www_auth is
+    # only set if authentication was requested the first time around.
+
+    # For testing:
+    # $www_auth='Basic realm="foo"';
+
+    if ($www_auth) {
+      my($authdata,$method,$realm);
+
+      ($method,$realm)= $www_auth =~ m/^(\S+)\s+realm=\"([^\"]+)\"/i;
+      $method=lc $method;
+      $realm=lc $realm;
+      die "w3mir: '$method' authentication needed, don't know that.\n"
+	if ($method ne 'basic');
+      
+      $hostport = $rum_url_o->netloc;
+      $authdata=$authdata{$hostport}{$realm} || $authdata{$hostport}{'*'} ||
+	$authdata{'*'}{$realm} || $authdata{'*'}{'*'};
+
+      if ($authdata) {
+	push(@EXTRASTUFF,$w3http::AUTHORIZ,$authdata);
+      } else {
+	print STDERR "w3mir: No authorization data for $hostport/$realm\n";
+	$rum_urlstat{$rum_as_string}=$NEVERMIND;
+	next;
+      }
+    }
+    
+    push(@EXTRASTUFF,$w3http::FREEHEAD,$cache_header)
+      if ($cache_header);
+
+    # Insert referer header data if at all
+    push(@EXTRASTUFF,$w3http::REFERER,$rum_referers{$rum_as_string}[0])
+      if ($do_referer && exists($rum_referers{$rum_as_string}));
+
+    push(@EXTRASTUFF,$w3http::NOUSER)
+      unless ($do_user);
+
+    # YES, $lf_url is right, w3http::query handles this like an url so
+    # the quoting must all be in place.
+    my $binfile=$lf_url;
+    $binfile='-' if $s==1;
+    $binfile=$nulldevice if $s==2;
+
+    if ($pause) {
+      print STDERR "w3mir: sleeping\n" if $verbose>0;
+      sleep($pause);
+    }
+
+    print STDERR "w3mir: ".($infoloss?$rum_as_string:$lf_name) 
+      unless $verbose<0;
+    print STDERR "\nFile: $lf_name\n" if $debug;
+
+    &w3http::query($w3http::GETURL,$rum_as_string,
+		   $w3http::SAVEBIN,$binfile,
+		   @EXTRASTUFF);
+
+    print STDERR "w3http::result: '",$w3http::result,
+    "' doc size: ", length($w3http::document),
+    " doc type: -",$w3http::headval{'CONTENT-TYPE'},
+    "- plaintexthtml: ",$w3http::plaintexthtml,"\n"
+      if $debug;
+
+    print "Result: ",$w3http::result," Recurse: $r, html: ",
+    $w3http::plaintexthtml,"\n" 
+      if $debug;
+
+  } # if $do_query
+    
+  if ($w3http::result==200) { # 200 OK 
+    $rum_urlstat{$rum_as_string}=$GOTIT;
+
+    if ($mine_urls || $process_urls) {
+
+      if ($w3http::plaintexthtml) {
+	# Only do URL manipulations if this is a html document with no
+	# special content-encoding.  We do not handle encodings, yet.
+
+	my $page;
+
+	print STDERR ($process_urls)?", processing":", url mining"
+	  if $verbose>0;
+	  
+	print STDERR "\nurl:'$lf_url'\n" 
+	  if $debug;
+
+	print "\nMining URLs: $mine_urls, Process: $process_urls\n" 
+	  if $debug;
+	    
+	($page,@rum_newurls) = 
+	  &htmlop::process($w3http::document,
+			   # Only get a new document if wanted
+			   $process_urls?():($htmlop::NODOC),
+			   $htmlop::CANON,
+			   $htmlop::ABS,$rum_url_o,
+			   # Only list urls if wanted
+			   $mine_urls?($htmlop::LIST):(),
+
+			   # If user wants absolute URLs do not
+			   # relativize them
+
+			   $abs?
+			   ():
+			   (
+			    $htmlop::TAGCALLBACK,\&process_tag,$lf_url,
+			    )
+			  );
+
+#	print "URL: ",join("\nURL: ",@rum_newurls),"\n";
+
+	if ($process_urls) {
+	  $page_ref=\$page;
+	  $w3http::document='';
+	} else {
+	  $page_ref=\$w3http::document;
+	}
+
+      } elsif ($s == 0 &&
+	       ($url_extractor = 
+		$knownformats{$w3http::headval{'CONTENT-TYPE'}})) {
+
+	# The knownformats extractors only work on disk files so write
+	# doc to disk if not there already (non-html text will not be)
+	write_page($lf_name,$w3http::document,1);
+
+	# Now we try our hand at fetching URIs from non-html files.
+	print STDERR ", mining URLs" if $verbose>=1;
+	@rum_newurls = &$url_extractor($lf_name);
+	# warn "URLs from PDF: ",join(', ',@rum_newurls),"\n";
+      }
+      
+      
+    } # if ($mine_urls || $process_urls)
+
+#    print "page_ref defined: ",defined($page_ref),"\n";
+#    print "plaintext: ",$w3http::plaintext,"\n";
+
+    $page_ref=\$w3http::document 
+      if !defined($page_ref) && $w3http::plaintexthtml;
+
+    if ($w3http::plaintexthtml) {
+      # ark: this is where I want to do my changes to the page strip
+      # out the <!--NOMIRROR-->...<!--/NOMIRROR--> Stuff.
+      $$page_ref=~ s/<(!--)?\s*NO\s*MIRROR\s*(--)?>[^\000]*?<(!--)?\s*\/NO\s*MIRROR\s*(--)?>//g 
+	if $edit;
+	  
+      if ($header) {
+	# ark: insert a header string at the start of the page
+	my $mirrorstr=$header;
+	$mirrorstr =~ s/\$url/$rum_as_string/g;
+	insert_at_start( $mirrorstr, $page_ref );
+      }
+    }
+
+    write_page($lf_name,$page_ref,0);
+
+    # print "New urls: ",join("\n",@rum_newurls),"\n";
+
+    return @rum_newurls;
+  }
+
+  if ($w3http::result==304 || #  304 Not modified
+      $w3http::result==1304) { # 1304 Have it
+
+    { 
+      # last = out of nesting
+
+      my $rum_urlstat;
+      my $rum_newurls;
+      
+      @rum_newurls=();
+      
+      print STDERR ", not modified"
+	if $verbose>=0 && $w3http::result==304;
+      
+      $rum_urlstat{$rum_as_string}=$NOTMOD;
+
+      last unless $mine_urls;
+      
+      $rum_newurls=get_references($lf_name);
+
+      # print "New urls: ",ref($rum_newurls),"\n";
+      
+      if (!ref($rum_newurls)) {
+	last;
+      } elsif (ref($rum_newurls) eq 'SCALAR') {
+	$page_ref=$rum_newurls;
+      } elsif (ref($rum_newurls) eq 'ARRAY') {
+	@rum_newurls=@$rum_newurls;
+	last;
+      } else {
+	die "\nw3mir: internal error: Unknown return type from get_references\n";
+      }
+      
+      # Check if it's a html file.  I know this tag is in all html
+      # files, because I put it there as I pull them in.
+      last unless $$page_ref =~ /<HTML/i;
+      
+      warn "$lf_name is a html file\n" if $debug;
+      
+      # It's a html document
+      print STDERR ", mining URLs" if $verbose>=1;
+      
+      # This will give us a list of absolute urls
+      (undef,@rum_newurls) = 
+	&htmlop::process($$page_ref,$htmlop::NODOC,
+			 $htmlop::ABS,$rum_as_string,
+			 $htmlop::USESAVED,'W3MIR',
+			 $htmlop::LIST);
+    }
+
+    print STDERR "\n" if $verbose>=0;
+    return @rum_newurls;
+  }
+	
+  if ($w3http::result==302 || $w3http::result==301) { # Redirect
+    # Cern and NCSA httpd sends 302 'redirect' if a ending / is
+    # forgotten on a url.  More recent httpds send 301 'permanent
+    # redirect' in this case.  Here we check if the difference in URLs
+    # is just a / and if so push the url again with the / added.  This
+    # code only works if the http server has the right idea about its
+    # own name.
+    #
+    # 18/3/97: Added code to queue redirected-to-URLs that are within
+    # the scope of the retrival.
+    my $new_rum_url;
+
+    $rum_urlstat{$rum_as_string}=$REDIR;
+
+    # Absolutify the new url, it might be relative to the requested
+    # document.  That's a ugly wart on some servers/admins.
+    $new_rum_url=url $w3http::headval{'location'};
+    $new_rum_url=$new_rum_url->abs($rum_url_o);
+
+    print REDIRS $rum_as_string,' -> ',$new_rum_url->as_string,"\n"
+      if $fixup;
+
+    if ($immediate_redir) {
+      print STDERR " =>> ",$new_rum_url->as_string,", getting that instead\n";
+      return get_document($new_rum_url,$lf_url);
+    }
+
+    # Some redirect to a fragment of another doc...
+    $new_rum_url->frag(undef);
+    $new_rum_url=$new_rum_url->as_string;
+
+    if ($rum_as_string.'/' eq $new_rum_url) {
+      if (grep { $rum_as_string eq $_; } @root_urls) {
+	print STDERR "\nw3mir: missing / in a start URL detected.  Please fix commandline/config file.\n";
+	exit(1);
+      }
+      print STDERR ", missing /\n";
+      queue($new_rum_url);
+      # Initialize referer to something meaningful
+      $rum_referers{$new_rum_url}=$rum_referers{$rum_as_string};
+    } else {
+      print STDERR " =>> $new_rum_url";
+      if (want_this($new_rum_url)) {
+	print STDERR ", getting that\n";
+	queue($new_rum_url);
+	$rum_referers{$new_rum_url}=$rum_referers{$rum_as_string};
+      } else {
+	print STDERR ", don't want it\n";
+      }
+    }
+    return ();
+  }
+
+  if ($w3http::result==403 || # Forbidden
+      $w3http::result==404 || # Not found
+      $w3http::result==406 || # Not Acceptable, hmm, belongs here?
+      $w3http::result==410) { # Gone - no forwarding address known
+
+    $rum_urlstat{$rum_as_string}=$ENOTFND;
+    &handleerror;
+    print STDERR "Was refered from: ",
+      join(',',@{$rum_referers{$rum_as_string}}),
+      "\n" if defined(@{$rum_referers{$rum_as_string}});
+    return ();
+  }
+
+  if ($w3http::result==407) {
+    # Proxy authentication requested
+    die "Proxy server requests authentication but failed to return the\n".
+      "REQUIRED Proxy-Authenticate header for this condition\n"
+	unless exists($w3http::headval{'proxy-authenticate'});
+
+    die "Proxy authentication is required for ".$w3http::headval{'proxy-authenticate'}."\n";
+  }
+
+  if ($w3http::result==401) {
+    # A www-authenticate reply header should acompany a 401 message.
+    if (!exists($w3http::headval{'www-authenticate'})) {
+      warn "w3mir: Server indicated authentication failure but gave no www-authenticate reply\n";
+      $rum_urlstat{$rum_as_string}=$NEVERMIND;
+    } else {
+      # Unauthorized
+      if ($www_auth) {
+	# Failed when authorization data was supplied.
+	$rum_urlstat{$rum_as_string}=$NEVERMIND;
+	print STDERR ", authorization failed data needed for ",
+	$w3http::headval{'www-authenticate'},"\n"
+	  if ($verbose>=0);
+      } else {
+	if ($useauth) {
+	  # First time failure, send back and retry at once with some known
+	  # user/passwd.
+	  $www_auth=$w3http::headval{'www-authenticate'};
+	  print STDERR ", retrying with authorization\n" unless $verbose<0;
+	  goto try_again;
+	} else {
+	  print ", authorization needed: ",
+	    $w3http::headval{'www-authenticate'},"\n";
+	  $rum_urlstat{$rum_as_string}=$NEVERMIND;
+	}
+      }
+    }
+    return ();
+  }
+   
+  # Something else.  
+  &handleerror;
+}
+
+
+sub robot_check {
+  # Check if URL is allowed by robots.txt, if we respect it at all
+  # that is.  Return 1 it allowed, 0 otherwise.
+
+  my($rum_url_o)=shift;
+  my $hostport;
+
+  if ($check_robottxt) {
+    
+    $hostport = $rum_url_o->netloc;
+    if (!exists($gotrobots{$hostport})) {
+      # Get robots.txt from the server
+      $gotrobots{$hostport}=1;
+      my $robourl="http://$hostport/robots.txt";
+      print STDERR "w3mir: $robourl" if ($verbose>=0);
+      &w3http::query($w3http::GETURL,$robourl);
+      $w3http::document='' if ($w3http::result != 200);
+      print STDERR ", processing" if $verbose>=1;
+      print STDERR "\n" if ($verbose>=0);
+      $Robot_Blob->parse($robourl,$w3http::document);
+    }
+
+    if (!$Robot_Blob->allowed($rum_url_o->as_string)) {
+      # It is forbidden
+      $rum_urlstat{$rum_url_o->as_string}=$FROBOTS;
+      warn "w3mir: ",$rum_url_o->as_string,": forbidden by robots.txt\n";
+      return 0;
+    }
+  }
+  return 1;
+}
+
+
+
+sub batch_get {
+  # Batch get _one_ document.
+  my $rum_url=shift;
+  my $lf_url;
+
+  $rum_url_o = url $rum_url;
+
+  return unless robot_check($rum_url_o);
+
+  ($lf_url=$rum_url) =~ s~.*/~~;
+  if (!defined($lf_url) || $lf_url eq '') {
+    ($lf_url=$rum_url) =~ s~/$~~;
+    $lf_url =~ s~.*/~~;
+    $lf_url .= "-$indexname";
+  }
+
+  warn "Batch get: $rum_url -> $lf_url\n" if $debug;
+
+  $immediate_redir=1; # Do follow redirects immediately
+
+  get_document($rum_url,$lf_url);
+}
+
+
+
+sub mirror {
+  # Mirror (or get) the requested url(s). Possibly recursively.
+  # Working from whatever cwd is at invocation we'll retrieve all
+  # files under it in the file hierarchy.
+  
+  my $rum_url;	# URL of the document we're getting now, defined at main level
+  my $lf_url;	# rum_url after apply - and 
+  my $new_lf_url;
+  my @new_rum_urls;
+  my $rum_ref;
+  
+  while (defined($rum_url = pop(@rum_queue))) {
+
+    warn "mirror: Poped $rum_url from queue\n" if $debug;
+
+    # Unwanted URLs should not be queued
+    die "Found url $rum_url that I don't want in queue!\n" 
+      unless defined($lf_url=apply($rum_url));
+
+    $rum_url_o = url $rum_url;
+
+    next unless robot_check($rum_url_o);
+
+    # Figure out the filename for our local filesystem.
+    $lf_url.=$indexname if $lf_url =~ m~/$~ || $lf_url eq '';
+
+    @new_rum_urls = get_document($rum_url_o,$lf_url);
+
+    print join("\n",@new_rum_urls),"\n" if ($list);
+
+    if ($r) {
+      foreach $rum_ref (@new_rum_urls) {
+	# warn "Recursive url: $rum_ref\n";
+	$new_lf_url=apply($rum_ref);
+	next unless $new_lf_url;
+
+	# warn "Want it\n";
+	$rum_ref =~ s/\#.*$//s;		# Clip off section marks
+	
+	add_referer($rum_ref,$rum_url_o->as_string);
+	queue($rum_ref);
+      }
+    }
+
+    @new_rum_urls=();
+
+    # Is the URL queue empty? Are there outstanding retries?  Refill
+    # the queue from the retry list.
+    if ($#rum_queue<0 && $retry-->0) {
+      foreach $rum_url_o (keys %rum_urlstat) {
+	$rum_url_o = url $rum_url_o;
+	if ($rum_urlstat{$rum_url_o->as_string}==100) {
+	  push(@rum_queue,$rum_url_o->as_string);
+	  $rum_urlstat{$rum_url_o->as_string}=0;
+	}
+      }
+      if ($#rum_queue>=0) {
+	warn "w3mir: Sleeping before retrying.  $retry more times left\n"
+	  if $verbose>=0;
+	sleep($retryPause);
+      }
+    }
+
+  }
+}
+
+
+sub get_references {
+  # Get references from a non-html-on-disk file.  Return references if
+  # we know how to find them.  Return reference do the complete page
+  # if it's html.  Return single numerical 0 if unknown format.
+
+  my($lf_url)=shift;
+  my($urlextractor)=shift;
+
+  my $read; # Buffer of stuff read from file to check filetype
+  my $magic;
+  my $url_extractor;
+  my $rum_ref;
+  my $page;
+
+  warn "w3mir: Looking at local $lf_url\n" if $debug;
+	
+  # Open file and read the first 10kilobytes for file-type-test
+  # purposes.
+  if (!open(TMPF,$lf_url)) {
+    warn "Unable to open $lf_url for reading: $!\n";
+    last;
+  }
+	
+  $page=' 'x10240;
+  $read=sysread(TMPF,$page,length($page),0);
+  close(TMPF);
+	
+  die "Error reading $lf_url: $!\n" if (!defined($read));
+
+  if (!defined($url_extractor)) {
+    $url_extractor=0;
+
+    # Check file against list of magic numbers.
+    foreach $magic (keys %knownmagic) {
+      if (substr($page,0,length($magic)) eq $magic) {
+	$url_extractor = $knownformats{$knownmagic{$magic}};
+	last;
+      }
+    }
+  }
+
+  # Found a extraction method, apply.
+  if ($url_extractor) {
+    print STDERR ", mining URLs" if $verbose>=1;
+    return [&$url_extractor($lf_url)];
+  }
+
+  if ($page =~ /<HTML/i) {
+    open(TMPF,$lf_url) || 
+      die "Could not open $lf_url for reading: $!\n";
+    # read the whole file.
+    local($/)=undef;
+    $page = <TMPF>;
+    close(TMPF);
+    return \$page;
+  }
+
+  return 0;
+}
+
+
+sub open_fixup {
+  # Open the referers and redirects files
+
+  my $reffile='.referers';
+  my $redirfile='.redirs';
+
+  if ($win32) {
+    $reffile="referers";
+    $redirfile="redirs";
+  }
+
+  $nodelete{$reffile} = $nodelete{$redirfile} = 1;
+
+  open(REDIRS,"> $redirfile") || 
+    die "Could not open $redirfile for writing: $!\n";
+
+  autoflush REDIRS 1;
+
+  open(REFERERS,"> $reffile") ||
+    die "Could not open $reffile for writing: $!\n";
+
+  $fixopen=1;
+  eval 'END { close_fixup; 0; }';
+}
+
+
+sub close_fixup {
+  # Close the fixup data files.  In the case of the referer file also
+  # write the entire content
+
+  return unless $fixopen;
+
+  my $referer;
+
+  foreach $referer (keys %rum_referers) {
+    print REFERERS $referer," <- ",join(' ',@{$rum_referers{$referer}}),"\n";
+  }
+
+  close(REFERERS) || warn "Error closing referers file: $!\n";
+  close(REDIRS) || warn "Error closing redirects file: $!\n";
+  $fixopen=0;
+}
+
+
+sub clean_disk {
+  # This procedure removes files that are not present on the server(s)
+  # anymore.
+  
+  # - To avoid removing files that were not fetched due to network
+  #   problems we only do blanket removal IFF all documents were
+  #   fetched w/o problems, eventually.  
+  # - In any case we can remove files the server said were not found
+
+  # The strategy has three main parts:
+  # 1. Find all files we have
+  # 2. Find what files we ought to have
+  # 3. Remove the difference
+  
+  my $complete_retrival=1;	# Flag saying IFF all documents were fetched
+  my $urlstat;			# Tmp storage
+  my $rum_url;
+  my $lf_url;
+  my $lf_dir;
+  my $dirs_to_remove;
+
+  # For fileremoval code
+  eval "use File::Find;" unless defined(&find);
+
+  die "w3mir: Could not load File::Find module.  Don't use -R switch.\n"
+    unless defined(&find);
+  
+  # This to shut up -w
+  $lf_dir=$File::Find::dir;
+
+  # ***** 1. Find out what files we have *****
+  #
+  # This does two things:  For each file or directory found:
+  # - Increases entry count for the container directory
+  # - If it's a file: $lf_file{relative_path}=$FILEHERE;
+
+  chop(@root_dirs);
+  print STDERR "Looking in: ",join(", ",@root_dirs),"\n" if $debug;
+
+  find(\&find_files,@root_dirs);
+
+  # ***** 2. Find out what files we ought to have *****
+  #
+  # First we loop over %rum_urlstat to determine what files are not
+  # present on the server(s).
+  foreach $rum_url (keys %rum_urlstat) {
+    # Figure out name of local file from rum_url
+    next unless defined($lf_url=apply($rum_url));
+
+    $lf_url.=$indexname if $lf_url =~ m~/$~ || $lf_url eq '';
+
+    # find prefixes ./, we must too.
+    $lf_url="./".$lf_url unless substr($lf_url,0,1) eq '/';
+
+    # Ignore if file does not exist here.
+    next unless exists($lf_file{$lf_url});
+    
+    # The apply rules can map several remote files to same local
+    # file.  If we decided to keep file already we stay with that.
+    next if $lf_file{$lf_url}==$FILETHERE;
+    
+    $urlstat=$rum_urlstat{$rum_url};
+
+    # Figure out the status code.
+    if ($urlstat==$GOTIT || $urlstat==$NOTMOD) {
+      # Present on server.  Keep.
+      $lf_file{$lf_url}=$FILETHERE;
+      next;
+    } elsif ($urlstat==$ENOTFND || $urlstat==$NEVERMIND ) {
+      # One of: not on server, can't get, don't want, access forbiden:
+      # Schedule for removal.
+      $lf_file{$lf_url}=$FILEDEL if exists($lf_file{$lf_url});
+      next;
+    } elsif ($urlstat==$OTHERERR || $urlstat==$TERROR) {
+      # Some error occured transfering.
+      $complete_retrival=0;	# The retrival was not complete. Delete less
+    } elsif ($urlstat==$QUEUED) {
+      warn "w3mir: Internal inconsistency, $rum_url marked as queued after retrival terminated\n";
+      $complete_retrival=0;	# Fishy. Be conservative about removing
+    } else {
+      $complete_retrival=0;
+      warn "w3mir: Warning: $rum_url is marked as $urlstat.\n".
+	"w3mir: Please report to w3mir-core\@usit.uio.no.\n";
+    }
+  }				# foreach %rum_urlstat
+
+  # ***** 3. Remove the difference *****
+
+  # Loop over all found files:
+  # - Should we have this file?
+  # - If not: Remove file and decrease directory entry count
+  # Loop as long as there are directories with 0 entry count:
+  # - Loop over all directories with 0 entry count:
+  #   - Remove directory
+  #   - Decrease entry count of parent
+  
+  warn "w3mir: Some error occured, conservative file removal\n"
+    if !$complete_retrival && $verbose>=0;
+
+  # Remove all files we don't want removed from list of files present:
+  foreach $lf_url (keys %nodelete) {
+    print STDERR "Not deleting: $lf_url\n" if $verbose>=1;
+    delete $lf_file{$lf_url} || delete $lf_file{'./'.$lf_url};
+  }
+  
+  # Remove files
+  foreach $lf_url (keys %lf_file) {
+    if (($complete_retrival && $lf_file{$lf_url}==$FILEHERE) ||
+	($lf_file{$lf_url} == $FILEDEL)) {
+      if (unlink $lf_url) {
+	($lf_dir)= $lf_url =~ m~^(.+)/~;
+	$lf_dir{$lf_dir}--;
+	$dirs_to_remove=1 if ($lf_dir{$lf_dir}==0);
+	warn "w3mir: removed file $lf_url\n" if $verbose>=0;
+      } else {
+	warn "w3mir: removal of file $lf_url failed: $!\n";
+      }
+    }
+  }
+  
+  # Remove empty directories
+  while ($dirs_to_remove) {
+    $dirs_to_remove=0;
+    foreach $lf_url (keys %lf_dir) {
+      next if $lf_url eq '.';
+      if ($lf_dir{$lf_url}==0) {
+	if (rmdir($lf_url)) {
+	  warn "w3mir: removed directory $lf_dir\n" if $verbose>=0;
+	  delete $lf_dir{$lf_url};
+	  ($lf_dir)= $lf_url =~ m~^(.+)/~;
+	  $lf_dir{$lf_dir}--;
+	  $dirs_to_remove=1 if ($lf_dir{$lf_dir}==0);
+	} else {
+	  warn "w3mir: removal of directory $lf_dir failed: $!\n";
+	}
+      }
+    }
+  }
+}
+
+
+sub find_files {
+  # This is called by the find procedure for every file/dir found.
+  
+  # This builds two hashes:
+  # lf_file{<file>}: 1: file exists
+  # lf_dir{<dir>): Number of files in directory.
+  
+  lstat($_);
+
+  $lf_dir{$File::Find::dir}++;
+
+  if (-f _) {
+    $lf_file{$File::Find::name}=$FILEHERE;
+  } elsif (-d _) {
+    # null
+    # Bug: If an empty directory exists it will not be removed
+  } else {
+    warn "w3mir: File $File::Find::name has unknown type.  Ignoring.\n";
+  }
+  return 0;
+  
+}
+
+
+sub handleerror {
+  # Handle error status of last http connection, will set the rum_urlstat
+  # appropriately and print a error message.
+
+  my $msg;
+  
+  if ($verbose<0) {
+    $msg="w3mir: ".$rum_url_o->as_string.": ";
+  } else {
+    $msg=": ";
+  }
+
+  if ($w3http::result == 98) {
+    # OS/Network error
+    $msg .= "$!";
+    $rum_urlstat{$rum_url_o->as_string}=$OTHERERR;
+  } elsif ($w3http::result == 100) {
+    # Some kind of error connecting or sending request
+    $msg .= $w3http::restext || "Timeout";
+    $rum_urlstat{$rum_url_o->as_string}=$TERROR;
+  } else {
+    # Other HTTP error
+    $rum_urlstat{$rum_url_o->as_string}=$OTHERERR;
+    $msg .= " ".$w3http::result." ".$w3http::restext;
+    $msg .= " =>> ".$w3http::headval{'location'}
+    if (defined($w3http::headval{'location'}));
+  }
+  print STDERR "$msg\n";
+}
+
+
+sub queue {
+  # Queue given url if appropriate and create a status entry for it
+  my($rum_url_o)=url $_[0];
+
+  croak("BUG: undefined \$rum_url_o")
+    if !defined($rum_url_o);
+
+  croak("BUG: undefined \$rum_url_o->as_string")
+    if !defined($rum_url_o->as_string);
+
+  croak("BUG: ".$rum_url_o->as_string." (fragnent) queued")
+    if $rum_url_o->as_string =~ /\#/;
+  
+  return if exists($rum_urlstat{$rum_url_o->as_string});
+  return unless want_this($rum_url_o->as_string);
+
+  warn "QUEUED: ",$rum_url_o->as_string,"\n" if $debug;
+  
+  # Note lack of scope checks.
+  $rum_urlstat{$rum_url_o->as_string}=$QUEUED;
+  push(@rum_queue,$rum_url_o->as_string);
+}
+
+
+sub root_queue {
+  # Queue function for root urls and directories.  One or the other might
+  # be boolean false, in that case, don't queue it.
+
+  my $root_url_o;
+
+  my($root_url)=shift;
+  my($root_dir)=shift;
+
+  die "w3mir: No fragments in start URLs :".$root_url."\n"
+    if $root_url =~ /\#/;
+
+  if ($root_dir) {
+    print "Root dir: $root_dir\n" if $debug;
+    $root_dir="./$root_dir" unless substr($root_dir,0,1) eq '/' or
+      substr($root_dir,0,2) eq './';
+    push(@root_dirs,$root_dir);
+  }
+
+
+  if ($root_url) {
+    $root_url_o=url $root_url;
+
+    # URL canonification, or what we do of it at least.
+    $root_url_o->host($root_url_o->host);
+
+    warn "Root queue: ".$root_url_o->as_string."\n" if $debug;
+
+    push(@root_urls,$root_url_o->as_string); 
+
+    return $root_url_o;
+ }
+
+}
+
+
+sub write_page {
+  # write a retrieved page to wherever it's supposed to be written.
+  # Added difficulty: all files but plaintext files have already been
+  # written to disk in w3http.
+  
+  # $s == 0 save to disk
+  # $s == 1 dump to stdout
+  # $s == 2 forget
+
+  my($lf_name,$page_ref,$silent) = @_;
+  my($verb);
+
+  if ($silent) {
+    $verb=-1;
+  } else {
+    $verb=$verbose;
+  }
+
+#  confess("\n\$page_ref undefined") if !defined($page_ref);
+  
+  if ($w3http::plaintexthtml) {
+    # I have it in memory
+    if ($s==0) {
+      print STDERR ", saving" if $verb>0;
+
+      while (-d $lf_name) {
+	# This will run once, maybe twice, $fiddled will be canged the
+	# first time
+	if (exists($fiddled{$lf_name})) {
+	  warn "Cannot save $lf_name, there is a directory in the way\n";
+	  return;
+	}
+
+	$fiddled{$lf_name}=1;
+
+	rm_rf($lf_name);
+	print STDERR "w3mir: $lf_name" if $verbose>=0;
+      }
+
+      if (!open(PAGE,">$lf_name")) {
+	warn "\nw3mir: can't open $lf_name for writing: $!\n";
+	return;
+      }
+      if (!$convertnl) {
+	binmode PAGE;
+	warn "BINMODE\n" if $debug;
+      }
+      if ($$page_ref ne '') {
+	print PAGE $$page_ref || die "w3mir: Error writing $lf_name: $!\n";
+      }
+      close(PAGE) || die "w3mir: Error closing $lf_name: $!\n";
+      print STDERR ": ", length($$page_ref), " bytes\n"
+	if $verb>=0;
+      setmtime($lf_name,$w3http::headval{'last-modified'})
+	if exists($w3http::headval{'last-modified'});
+    } elsif ($s==1) {
+      print $$page_ref ;
+    } elsif ($s==2) {
+      print STDERR ", got and forgot it.\n" unless $verb<0;
+    }
+  } else {
+    # Already written by http module, just emit a message if wanted
+    if ($s==0) {
+      print STDERR ": ",$w3http::doclen," bytes\n"
+	if $verb>=0;
+      setmtime($lf_name,$w3http::headval{'last-modified'})
+	  if exists($w3http::headval{'last-modified'});
+    } elsif ($s==2) {
+      print STDERR ", got and forgot it.\n" if $verb>=0;
+    }
+  }
+}
+
+
+sub setmtime {
+  # Set mtime of the given file
+  my($file,$time)=@_;
+  my($tm_sec,$tm_min,$tm_hour,$tm_mday,$tm_mon,$tm_year,$tm_wday,$tm_yday,
+     $tm_isdst,$tics);
+
+  $tm_isdst=0;
+  $tm_yday=-1;
+
+  carp("\$time is undefined"),return if !defined($time);
+
+  $tics=str2time($time);
+  utime(time, $tics, $file) || 
+      warn "Could not change mtime of $file: $!\n";
+}
+
+
+sub movefile {
+  # Rename a file.  Note that copy is not a good alternative, since
+  # copying over NFS is something we want to Avoid.
+
+  # Returns 0 if failure and 1 in case of sucess.
+
+  (my $old,my $new) = @_;
+
+  # Remove anything that might have the name already.
+  if (-d $new) {
+    print STDERR "\n" if $verbose>=0;
+    rm_rf($new);
+    $fiddled{$new}=1;
+    print STDERR "w3mir: $new" if $verbose>=0;
+  } elsif (-e $new) {
+    $fiddled{$new}=1;
+    if (unlink($new)) {
+      print STDERR "\nw3mir: removed $new\nw3mir: $new"
+	if $verbose>=0;
+    } else {
+      return 0;
+    }
+
+  }
+
+  if ($new ne '-' && $new ne $nulldevice) {
+    warn "MOVING $old -> $new\n" if $debug;
+    rename($old,$new) || 
+      warn "Could not rename $old to $new: $!\n",return 0;
+  }
+  return 1;
+}
+
+
+sub mkdir {
+  # Make all intermediate directories needed for a file, the file name
+  # is expected to be included in the argument!
+
+  # Reasons for not using File::Path::mkpath:
+  # - I already wrote this.
+  # - I get to be able to produce as good and precise errormessages as
+  #   unix and perl will allow me.  mkpath will not.
+  # - It's easier to find out if it worked or not.
+  
+  my($file) = @_;
+  my(@dirs) = split("/",$file);
+  my $path;
+  my $dir;
+  my $moved=0;
+
+  if (!$dirs[0]) {
+    shift @dirs;
+    $path='';
+  } else {
+    $path = '.';
+  }
+
+  # This removes the last element of the array, it's meant to shave
+  # off the file name leaving only the directory name, as a
+  # convenience, for the caller.
+  pop @dirs;
+  foreach $dir (@dirs) {
+    $path .= "/$dir";
+    stat($path);
+    # only make if it isn't already there
+    next if -d _;
+
+    while (!-d _) {
+      if (exists($fiddled{$path})) {
+	warn "Cannot make directory $path, there is a file in the way.\n";
+	return;
+      }
+
+      $fiddled{$path}=1;
+
+      if (!-e _) {
+	mkdir($path,0777);
+	last;
+      }
+
+      if (unlink($path)) {
+	warn "w3mir: removed file $path\n" if $verbose>=0;
+      } else {
+	warn "Unable to remove $path: $!\n";
+	next;
+      }
+    
+      warn "mkdir $path\n" if $debug;
+      mkdir($path,0777) ||
+	warn "Unable to create directory $path: $!\n";
+
+      stat($path);
+    }
+  }
+}
+
+
+sub add_referer {
+  # Add a referer to the list of referers of a document.  Unless it's
+  # already there.
+  # Don't mail me if you (only) think this is a bit like a toungetwiser:
+
+  # Don't remember referers if BOTH fixup and referer header is disabled.
+  return if $fixup==0 && $do_referer==0;
+
+  my($rum_referee,$rum_referer) = @_ ;
+  my $re_rum_referer;
+
+  if (exists($rum_referers{$rum_referee})) {
+    $re_rum_referer=quotemeta $rum_referer;
+    if (!grep(m/^$re_rum_referer$/,@{$rum_referers{$rum_referee}})) {
+      push(@{$rum_referers{$rum_referee}},$rum_referer);
+      # warn "$rum_referee <- $rum_referer pushed\n";
+    } else {
+      # warn "$rum_referee <- $rum_referer NOT pushed\n";
+    }
+  } else {
+    $rum_referers{$rum_referee}=[$rum_referer];
+    # warn "$rum_referee <- $rum_referer pushed\n";
+  }
+}
+
+
+sub user_apply {
+  # Apply the user apply rules
+
+  return &$user_apply_code(shift);
+
+# Debug version:
+#  my ($foo,$bar);
+#  $foo=shift;
+#  $bar=&$apply_code($foo);
+#  print STDERR "Apply: $foo -> $bar\n";
+#  return $bar;
+}
+
+sub internal_apply {
+  # Apply the w3mir generated apply rules
+
+  return &$apply_code(shift);
+}
+
+
+sub apply {
+  # Apply the user apply rules.  Then if URL is wanted return result of
+  # w3mir apply rules.  Return the undefined value otherwise.
+
+  my $url = user_apply(shift);
+
+  return undef unless want_this($url);
+
+  internal_apply($url);
+}
+
+
+sub want_this {
+  # Find out if we want the url passed.  Just pass it on to the
+  # generated functions.
+  my($rum_url)=shift;
+
+  # What about robot rules?
+
+  # Does scope rule want this?
+  return &$scope_code($rum_url) &&
+    # Does user rule want this too?
+    &$rule_code($rum_url) 
+  
+}
+
+
+sub process_tag {
+  # Process a tag in html file
+  my $lf_referer = shift;	# User argument
+  my $base_url = shift;		# Not used... why not?
+  my $tag_name = shift;
+  my $url_attrs = shift;
+
+  # Retrun quickly if no URL attributes
+  return unless defined($url_attrs);
+
+  my $attrs = shift;
+
+  my $rum_url;	# The absolute URL
+  my $lf_url;	# The local filesystem url
+  my $lf_url_o; # ... and it's object
+  my $key;
+
+  print STDERR "\nProcess Tag: $tag_name, URL attributes: ", 
+  join(', ',@{$url_attrs}),"\nbase_url: ",$base_url,"\nlf_referer: ",
+  $lf_referer,"\n" 
+    if $debug>2;
+
+  $lf_referer =~ s~^/~~;
+  $lf_referer = "file:/$lf_referer";
+
+  foreach $key (@{$url_attrs}) {
+    if (defined($$attrs{$key})) {
+      $rum_url=$$attrs{$key};
+      printf STDERR "$key = $rum_url\n" if $debug;
+      $lf_url=apply($rum_url);
+      if (defined($lf_url)) {
+
+	printf STDERR "Transformed to $lf_url\n" if $debug>2;
+
+	$lf_url =~ s~^/~~;  # Remove leading / to avoid doubeling
+	$lf_url_o=url "file:/$lf_url";
+
+	# Save new value in the hash
+	$$attrs{$key}=($lf_url_o->rel($lf_referer))->as_string;
+	print STDERR "New value: ",$$attrs{$key},"\n" if $debug>2;
+
+	# If there is potential information loss save the old value too
+	$$attrs{"W3MIR".$key}=$rum_url if $infoloss;
+      }
+    }
+  }
+}
+
+
+sub version {
+  eval 'require LWP;';
+  print $w3mir_agent,"\n";
+  print "LWP version ",$LWP::VERSION,"\n" if defined $LWP::VERSION;
+  print "Perl version: ",$],"\n";
+  exit(0);
+}
+
+
+sub parse_args {
+  my $f;
+  my $i;
+
+  $i=0;
+
+  while ($f=shift) {
+    $i++;
+    $numarg++;
+    # This is a demonstration against Getopts::Long.
+    if ($f =~ s/^-+//) {
+      $s=1,next if $f eq 's';			# Stdout
+      $r=1,next if $f eq 'r';			# Recurse
+      $fetch=1,next if $f eq 'fa';		# Fetch all, no date test
+      $fetch=-1,next if $f eq 'fs';	# Fetch those we don't already have.
+      $verbose=-1,next if $f eq 'q'; 		# Quiet
+      $verbose=1,next if $f eq 'c';		# Chatty
+      &version,next if $f eq 'v';		# Version
+      $pause=shift,next if $f eq 'p';		# Pause between requests
+      $retryPause=shift,next if $f eq 'rp';	# Pause between retries.
+      $s=2,$convertnl=0,next if $f eq 'f';	# Forget
+      $retry=shift,next if $f eq 't';		# reTry
+      $list=1,next if $f eq 'l';		# List urls
+      $iref=shift,next if $f eq 'ir';		# Initial referer
+      $check_robottxt = 0,next if $f eq 'drr';	# Disable robots.txt rules.
+      umask(oct(shift)),next if $f eq 'umask';
+      parse_cfg_file(shift),next if $f eq 'cfgfile';
+      usage(),exit 0 if ($f eq 'help' || $f eq 'h' || $f eq '?');
+      $remove=1,next if $f eq 'R';
+      $cache_header = 'Pragma: no-cache',next if $f eq 'pflush';
+      $w3http::agent=$w3mir_agent=shift,next if $f eq 'agent';
+      $abs=1,next if $f eq 'abs';
+      $convertnl=0,$batch=1,next if $f eq 'B';
+      $read_urls = 1,next if $f eq 'I';
+      $convertnl=0,next if $f eq 'nnc';
+
+      if ($f eq 'lc') {
+	if ($i == 1) {
+	  $lc=1;
+	  $iinline=($lc?"(?i)":"");
+	  $ipost=($lc?"i":"");
+	  next;
+	} else {
+	  die "w3mir: -lc must be the first argument on the commandline.\n";
+	}
+      }
+
+      if ($f eq 'P') {				# Proxy
+	($w3http::proxyserver,$w3http::proxyport)= 
+	  shift =~ /([^:]+):?(\d+)?/;
+	$w3http::proxyport=80 unless $w3http::proxyport;
+	$using_proxy=1;
+	next;
+      }
+    
+      if ($f eq 'd') {		# Debugging level
+	$f=shift;
+	unless (($debug = $f) > 0) {
+	  die "w3mir: debug level must be a number greater than zero.\n";
+	}
+	next;
+      }
+
+      # Those were all the options...
+      warn "w3mir: Unknown option: -$f.  Use -h for usage info.\n";
+      exit(1);
+      
+    } elsif ($f =~ /^http:/) {
+      my ($rum_url_o,$rum_reurl,$rum_rebase,$server);
+
+      $rum_url_o=root_queue($f,'./');
+
+      $rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+      push(@internal_apply,"s/^".$rum_rebase."//");
+      $scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+      $scope_ignore.="return 0 if m/^".
+	quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+
+    } else {
+      # If we get this far then the commandline is broken
+      warn "Unknown commandline argument: $f.  Use -h for usage info.\n";
+      $numarg--;
+      exit(1);
+    }
+  }
+  return 1;
+}
+
+
+sub parse_cfg_file {
+  # Read the configuration file.  Aborts on errors.  Not good to
+  # mirror something using the wrong config.
+
+  my ( $file ) = @_ ;
+  my ($key, $value, $authserver,$authrealm,$authuser,$authpasswd);
+  my $i;
+
+  die "w3mir: config file $file is not a file.\n" unless -f $file;
+  open(CFGF, $file) || die "Could not open config file $file: $!\n";
+
+  $i=0;
+
+  while (<CFGF>) {
+    # Trim off various junk
+    chomp;
+    s/^#.*//;
+    s/^\s+|\s$//g;
+    # Anything left?
+    next if $_ eq '';
+    # Examine remains
+    $i++;
+    $numarg++;
+
+    ($key, $value) = split(/\s*:\s*/,$_,2);
+    $key = lc $key;
+
+    $iref=$value,next if ( $key eq 'initial-referer' );
+    $header=$value,next if ( $key eq 'header' );
+    $pause=numeric($value),next if ( $key eq 'pause' );
+    $retryPause=numeric($value),next if ( $key eq 'retry-pause' );
+    $debug=numeric($value),next if ( $key eq 'debug' );
+    $retry=numeric($value),next if ( $key eq 'retries' );
+    umask(numeric($value)),next if ( $key eq 'umask' );
+    $check_robottxt=boolean($value),next if ( $key eq 'robot-rules' );
+    $edit=boolean($value),next if ($key eq 'remove-nomirror');
+    $indexname=$value,next if ($key eq 'index-name');
+    $s=nway($value,'save','stdout','forget'),next 
+      if ( $key eq 'file-disposition' );
+    $verbose=nway($value,'quiet','brief','chatty')-1,next
+      if ( $key eq 'verbosity' );
+    $w3http::proxyuser=$value,next if $key eq 'http-proxy-user';
+    $w3http::proxypasswd=$value,next if $key eq 'http-proxy-passwd';
+
+    if ( $key eq 'cd' ) {
+      $chdirto=$value;
+      warn "Use of 'cd' is discouraged\n" unless $verbose==-1;
+      next;
+    }
+    
+    if ($key eq 'http-proxy') {
+      ($w3http::proxyserver,$w3http::proxyport)= 
+	$value =~ /([^:]+):?(\d+)?/;
+      $w3http::proxyport=80 unless $w3http::proxyport;
+      $using_proxy=1;
+      next;
+    }
+
+    if ($key eq 'proxy-options') {
+      my($val,$nval,@popts,$pragma);
+      $pragma=1;
+      foreach $val (split(/\s*,\*/,lc $value)) {
+	$nval=nway($val,'no-pragma','revalidate','refresh','no-store',);
+	# Force use of Cache-control: header
+	$pragma=0 if ($nval==0);
+	# use to force proxy to revalidate
+	$pragma=0,push(@popts,'max-age=0') if ($nval==1);
+	# use to force proxy to refresh
+	push(@popts,'no-cache') if ($nval==2);
+	# use if information transfered is sensitive
+	$pragma=0,push(@popts,'no-store') if ($nval==3);
+      }
+      $cache_header=($pragma?'Pragma: ':'Cache-control: ').join(', ',@popts);
+      next;
+    }
+
+
+    if ($key eq 'url') {
+      my ($rum_url_o,$lf_dir,$rum_reurl,$rum_rebase);
+
+      # A two argument URL: line?
+      if ($value =~ m/^(.+)\s+(.+)/i) {
+	# Two arguments.
+	# The last is a directory, it must end in /
+	$lf_dir=$2;
+	$lf_dir.='/' unless $lf_dir =~ m~/$~;
+
+	$rum_url_o=root_queue($1,$lf_dir);
+
+	# The first is a URL, make it more canonical, find the base.
+	# The namespace confusion in this section is correct.(??)
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+	# print "URL: ",$rum_url_o->as_string,"\n";
+	# print "Base: $rum_rebase\n";
+
+	# Translate from rum space to lf space:
+	push(@internal_apply,"s/^".$rum_rebase."/".quotemeta($lf_dir)."/");
+
+	# That translation could lead to information loss.
+	$infoloss=1;
+
+	# Fetch rules tests the rum_url_o->as_string.  Fetch whatever
+	# matches the base.
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+
+	# Ignore whatever did not match the base.
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+
+      } else {
+	$rum_url_o=root_queue($value,'./');
+
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+	# Translate from rum space to lf space:
+	push(@internal_apply,"s/^".$rum_rebase."//");
+
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+      }
+      next;
+    }
+
+    if ($key eq 'also-quene') {
+      print STDERR 
+	"Found 'also-quene' keyword, please replace with 'also-queue'\n";
+      $key='also-queue';
+    }
+
+    if ($key eq 'also' || $key eq 'also-queue') {
+      if ($value =~ m/^(.+)\s+(.+)/i) {
+	my ($rum_url_o,$lf_dir,$rum_reurl,$rum_rebase);
+	# Two arguments.
+	# The last is a directory, it must end in /
+	# print STDERR "URL ",$1," DIR ",$2,"\n";
+	$lf_dir=$2;
+	$lf_dir.='/' unless $lf_dir =~ m~/$~;
+
+	if ($key eq 'also-queue') {
+	  $rum_url_o=root_queue($1,$lf_dir);
+	} else {
+	  root_queue("",$lf_dir);
+	  $rum_url_o=url $1;
+	  $rum_url_o->host(lc $rum_url_o->host);
+	}
+
+	# The first is a URL, find the base
+	$rum_rebase = quotemeta( ($rum_url_o->as_string =~ m~^(.*/)~)[0] );
+
+#	print "URL: $rum_url_o->as_string\n";
+#	print "Base: $rum_rebase\n";
+#	print "Server: $server\n";
+
+	# Ok, now we can transform and select stuff the right way
+	push(@internal_apply,"s/^".$rum_rebase."/".quotemeta($lf_dir)."/");
+	$infoloss=1;
+
+	# Fetch rules tests the rum_url_o->as_string.  Fetch whatever
+	# matches the base.
+	$scope_fetch.="return 1 if m/^".$rum_rebase."/".$ipost.";\n";
+
+	# Ignore whatever did not match the base.  This cures problem
+	# with '..' from base in in rum space pointing within the the
+	# scope in ra space.  We introduced a extra level (or more) of
+	# directories with the apply above.  Must do same with 'Also:'
+	# directives.
+	$scope_ignore.="return 0 if m/^".
+	  quotemeta("http://".$rum_url_o->netloc."/")."/".$ipost.";\n";
+      } else {
+	die "Also: requires 2 arguments\n";
+      }
+      next;
+    }
+
+    if ($key eq 'quene') {
+      print STDERR "Found 'quene' keyword, please replace with 'queue'\n";
+      $key='queue';
+    }
+
+    if ($key eq 'queue') {
+      root_queue($value,"");
+      next;
+    }
+
+    if ($key eq 'ignore-re' || $key eq 'fetch-re') {
+      # Check that it's a re, better that I am strict than for perl to
+      # make compilation errors.
+      unless ($value =~ /^m(.).*\1[gimosx]*$/) {
+	print STDERR "w3mir: $value is not a recognized regular expression\n";
+	exit 1;
+      }
+      # Fall-through to next cases!
+    }
+
+    if ($key eq 'fetch' || $key eq 'fetch-re') {
+      my $expr=$value;
+      $expr = wild_re($expr).$ipost if ($key eq 'fetch');
+      $rule_text.=' return 1 if '.$expr.";\n";
+      next;
+    }
+
+    if ($key eq 'ignore' || $key eq 'ignore-re') {
+      my $expr=$value;
+      $expr = wild_re($expr).$ipost if ($key eq 'ignore');
+      # print STDERR "Ignore expression: $expr\n";
+      $rule_text.=' return 0 if '.$expr.";\n";
+      next;
+    }
+
+
+    if ($key eq 'apply') {
+      unless ($value =~ /^s(.).*\1.*\1[gimosxe]*$/) {
+	print STDERR
+	  "w3mir: '$value' is not a recognized regular expression\n";
+	exit 1;
+      }
+      push(@user_apply,$value) ;
+      $infoloss=1;
+      next;
+    }
+
+    if ($key eq 'agent') {
+      $w3http::agent=$w3mir_agent=$value;
+      next;
+    }
+
+    # The authorization stuff:
+    if ($key eq 'auth-domain') {
+      $useauth=1;
+      ($authserver, $authrealm) = split('/',$value,2);
+      die "w3mir: server part of auth-domain has format server[:port]\n"
+	unless $authserver =~ /^(\S+(:\d+)?)$|^\*$/;
+      $authserver =~ s/:80$//;
+      die "w3mir: auth-domain '$value' is not valid\n"
+	if !defined($authserver) || !defined($authrealm);
+      $authrealm=lc $authrealm;
+    }
+
+    $authuser=$value if ($key eq 'auth-user');
+    $authpasswd=$value if ($key eq 'auth-passwd');
+
+    # Got a full authentication spec?
+    if ($authserver && $authrealm && $authuser && $authpasswd) {
+      $authdata{$authserver}{$authrealm}=$authuser.":".$authpasswd;
+      print "Authentication for $authserver/$authrealm is ".
+	"$authuser/$authpasswd\n" if $verbose>=0;
+      # exit;
+      # Invalidate tmp vars
+      $authserver=$authrealm=$authuser=$authpasswd=undef;
+      next;
+    }
+
+    next if $key eq 'auth-user' || $key eq 'auth-passwd' || 
+      $key eq 'auth-domain';
+
+    if ($key eq 'fetch-options') {
+      warn "w3mir: The 'fetch-options' directive has been renamed to 'options'\nw3mir: Please change your configuration file.\n";
+      $key='options';
+      # Fall through to 'options'!
+    }
+
+    if ($key eq 'options') {
+      
+      my($val,$nval);
+      foreach $val (split(/\s*,\s*/,lc $value)) {
+	if ($i==1) {
+	  $nval=nway($val,'recurse','no-date-check','only-nonexistent',
+		     'list-urls','lowercase','remove','batch','read-urls',
+		     'abs','no-newline-conv');
+	  $r=1,next if $nval==0;
+	  $fetch=1,next if $nval==1;
+	  $fetch=-1,next if $nval==2;
+	  $list=1,next if $nval==3;
+	  if ($nval==4) {
+	    $lc=1;
+	    $iinline=($lc?"(?i)":"");
+	    $ipost=($lc?"i":"");
+	    next ;
+	  }
+	  $remove=1,next if $nval==5;
+	  $convertnl=0,$batch=1,next if $nval==6;
+	  $read_urls=1,next if $nval==7;
+	  $abs=1,next if $nval==8;
+	  $convertnl=0,next if $nval==9;
+        } else {
+	    die "w3mir: options must be the first directive in the config file.\n";
+	}
+      }
+      next;
+    }
+
+    if ($key eq 'disable-headers') {
+      my($val,$nval);
+      foreach $val (split(/\s*,\s*/,lc $value)) {
+	$nval=nway($val,'referer','user');
+	$do_referer=0,next if $nval==0;
+	$do_user=0,next if $nval==1;
+      }
+      next;
+    }
+
+
+    if ($key eq 'fixup') {
+
+      $fixrc="$file";
+      # warn "Fixrc: $fixrc\n";
+
+      my($val,$nval);
+      foreach $val (split(/\s*,\s*/,lc $value)) {
+	$nval=nway($val,'on','run','noindex','off');
+	$runfix=1,next if $nval==1;
+	# Disable fixup
+	$fixup=0,next if $nval==3;
+	# Ignore everyting else
+      }
+      next;
+    }
+
+    die "w3mir: Unrecognized directive ('$key') in config file $file at line $.\n";
+
+  }
+  close(CFGF);
+
+  if (defined($w3http::proxypasswd) && $w3http::proxyuser) {
+    warn "Proxy authentication: ".$w3http::proxyuser.":".
+      $w3http::proxypasswd."\n" if $verbose>=0;
+  }
+
+}
+
+
+sub wild_re {
+  # Here we translate unix wildcard subset to to perlre
+  local($_) = shift;
+
+  # Quote anything that's RE and not wildcard: / ( ) \ | { } + $ ^
+  s~([\/\(\)\\\|\{\}\+)\$\^])~\\$1~g;
+  # . -> \.
+  s~\.~\\.~g;
+  # * -> .*
+  s~\*~\.\*~g;
+  # ? -> .
+  s~\?~\.~g;
+
+  # print STDERR "wild_re: $_\n";
+
+  return $_ = '/'.$_.'/';
+}
+
+
+sub numeric {
+  # Check if argument is numeric?
+  my ( $number ) = @_ ;
+  return oct($number) if ($number =~ /\d+/ || $number =~ /\d+.\d+/);
+  die "Expected a number, got \"$number\"\n";
+}
+
+
+sub boolean {
+  my ( $boolean ) = @_ ;
+
+  $boolean = lc $boolean;
+
+  return 0 if ($boolean eq 'false' || $boolean eq 'off' || $boolean eq '0');
+  return 1 if ($boolean eq 'true' || $boolean eq 'on' || $boolean eq '1');
+  die "Expected a boolean, got \"$boolean\"\n";
+}
+
+
+sub nway {
+  my ( $value ) = shift;
+  my ( @values ) = @_;
+  my ( $val ) = 0;
+
+  $value = lc $value;
+  while (@_) {
+    return $val if $value eq shift;
+    $val++;
+  }
+  die "Expected one of ".join(", ",@values).", got \"$value\"\n";
+}
+
+
+sub insert_at_start {
+  # ark: inserts the first arg at the top of the html in the second arg
+  # janl: The second arg must be a reference to a scalar.
+  my( $str, $text_ref ) = @_;
+  my( @possible ) =("<BODY.*?>", "</HEAD.*?>", "</TITLE.*?>", "<HTML.*?>" );
+  my( $f, $done );
+  
+  $done=0;
+  @_=@possible;
+  
+  while( $done!=1 && ($f=shift) ){
+    print "Searching for: $f\n";
+    if( $$text_ref =~ /$f/i ){
+      print "found it!\n";
+      $$text_ref =~ s/($f)/$1\n$str/i;
+      $done=1;
+    }
+  }
+}
+
+
+
+sub rm_rf {
+  # Recursively remove directories and other files
+  # File::Path::rmtree does a similar thing but the messages are wrong
+
+  my($remove)=shift;
+
+  eval "use File::Find;" unless defined(&finddepth);
+
+  die "w3mir: Could not load File::Find module when trying to remove $remove\n"
+    unless defined(&find);
+
+  finddepth(\&remove_everything,$remove);
+
+  if (rmdir($remove)) {
+    print STDERR "\nw3mir: removed directory $remove\n" if $verbose>=0;
+  } else {
+    print STDERR "w3mir: could not remove $remove: $!\n";
+  }
+}
+
+
+sub remove_everything {
+  # This does the removal
+  ((-d && rmdir($_)) || unlink($_)) && $verbose>=0 &&
+    print STDERR "w3mir: removed $File::Find::name\n";
+}
+
+
+
+sub usage {
+  my($message)=shift @_;
+
+  print STDERR "w3mir: $message\n" if $message;
+  
+  die 'w3mir: usage: w3mir [options] <single-http-url>
+          or: w3mir -B [-I] [options] [<http-urls>]
+
+    Options :
+	-agent <agent>	- Set the agent name.  Default is w3mir
+	-abs		- Force all URLs to be absolute.
+	-B		- Batch-get documents.
+	-I		- The URLs to get are read from standard input.
+	-c		- be more Chatty.
+	-cfgfile <file> - Read config from file
+	-d <debug-level>- set debug level to 1 or 2
+	-drr		- Disable robots.txt rules.
+	-f		- Forget all files, nothing is saved to disk.
+	-fa		- Fetch All, will not check timestamps.
+	-fs		- Fetch Some, do not fetch the files we already have.
+	-ir <referer>	- Initial referer.  For picky servers.
+	-l		- List URLs in the documents retrived.
+	-lc		- Convert all URLs (and filenames) to lowercase.
+				This does not work reliably.
+	-p <n>		- Pause n seconds before retriving each doc.
+	-q		- Quiet, error-messages only
+        -rp <n>		- Retry Pause in seconds.
+	-P <server:port>- Use host/port for proxy http requests
+        -pflush		- Flush proxy server.
+	-r		- Recursive mirroring.
+        -R		- Remove files not referenced or not present on server.
+	-s		- Send output to stdout instead of file
+	-t <n>		- How many times to (re)try getting a failed doc?
+        -umask <umask>  - Set umask for mirroring, must be usual octal format.
+	-nnc		- No Newline Conversion.  Disable newline conversions.
+	-v		- Show w3mir version.
+';
+}
+__END__
+# -*- perl -*- There must be a blank line here
+
+=head1 NAME
+
+w3mir - all purpose HTTP-copying and mirroring tool
+
+=head1 SYNOPSIS
+
+B<w3mir> [B<options>] [I<HTTP-URL>]
+
+B<w3mir> B<-B> [B<options>] <I<HTTP-URLS>>
+
+B<w3mir> is a all purpose HTTP copying and mirroring tool.  The
+main focus of B<w3mir> is to create and maintain a browsable copy of
+one, or several, remote WWW site(s).
+
+Used to the max w3mir can retrive the contents of several related
+sites and leave the mirror browseable via a local web server, or from
+a filesystem, such as directly from a CDROM.  
+
+B<w3mir> has options for all operations that are simple enough for
+options.  For authentication and passwords, multiple site retrievals
+and such you will have to resort to a L</CONFIGURATION-FILE>.  If
+browsing from a filesystem references ending in '/' needs to be
+rewritten to end in '/index.html', and in any case, if there are URLs
+that are redirected will need to be changed to make the mirror
+browseable, see the documentation of B<Fixup> in the
+L</CONFIGURATION-FILE> secton.
+
+B<w3mir>s default behavior is to do as little as possible and to be as
+nice as possible to the server(s) it is getting documents from.  You
+will need to read through the options list to make B<w3mir> do more
+complex, and, useful things.  Most of the things B<w3mir> can do is
+also documented in the w3mir-HOWTO which is available at the B<w3mir>
+home-page (F<http://www.math.uio.no/~janl/w3mir/>) as well as in the
+w3mir distribution bundle.
+
+=head1 DESCRIPTION
+
+You may specify many options and one HTTP-URL on the w3mir
+command line.
+
+A single HTTP URL I<must> be specified either on the command line or
+in a B<URL> directive in a configuration file.  If the URL refers to a
+directory it I<must> end with a "/", otherwise you might get surprised
+at what gets retrieved (e.g. rather more than you expect).
+
+Options must be prefixed with at least one - as shown below, you can
+use more if you want to. B<-cfgfile> is equivalent to B<--cfgfile> or
+even B<------cfgfile>.  Options cannot be I<clustered>, i.e., B<-r -R>
+is not equivalent to B<-rR>.
+
+=over 4
+
+=item B<-h> | B<-help> | B<-?>
+
+prints a brief summary of all command line options and exits.
+
+=item B<-cfgfile> F<file>
+
+Makes B<w3mir> read the given configuration file.  See the next section
+for how to write such a file.
+
+=item B<-r>
+
+Puts B<w3mir> into recursive mode.  The default is to fetch only one
+document and then quit.  'I<recursive>' mode means that all the
+documents linked to the given document that are fetched, and all they
+link to in turn and so on.  But only I<Iff> they are in the same
+directory or under the same directory as the start document.  Any
+document that is in or under the starting documents directory is said
+to be within the I<scope of retrieval>.
+
+=item B<-fa>
+
+Fetch All.  Normally B<w3mir> will only get the document if it has been
+updated since the last time it was fetched.  This switch turns that
+check off.
+
+=item B<-fs>
+
+Fetch Some.  Not the opposite of B<-fa>, but rather, fetch the ones we
+don't have already.  This is handy to restart copying of a site
+incompletely copied by earlier, interrupted, runs of B<w3mir>.
+
+=item B<-p> I<n>
+
+Pause for I<n> seconds between getting each document.  The default is
+30 seconds.
+
+=item B<-rp> I<n>
+
+Retry Pause, in seconds.  When B<w3mir> fails to get a document for some
+technical reason (timeout mainly) the document will be queued for a
+later retry.  The retry pause is how long B<w3mir> waits between
+finishing a mirror pass before starting a new one to get the still
+missing documents.  This should be a long time, so network conditions
+have a chance to get better.  The default is 600 seconds (10 minutes),
+which might be a bit too short, for batch running B<w3mir> I would
+suggest an hour (3600 seconds) or more.
+
+=item B<-t> I<n>
+
+Number of reTries.  If B<w3mir> cannot get all the documents by the
+I<n>th retry B<w3mir> gives up.  The default is 3.
+
+=item B<-drr>
+
+Disable Robot Rules.  The robot exclusion standard is described in
+http://info.webcrawler.com/mak/projects/robots/norobots.html.  By
+default B<w3mir> honors this standard.  This option causes B<w3mir> to
+ignore it.
+
+=item B<-nnc>
+
+No Newline Conversion.  Normally w3mir converts the newline format of
+all files that the web server says is a text file.  However, not all
+web servers are reliable, and so binary files may become corrupted due
+to the newline conversion w3mir performs.  Use this option to stop
+w3mir from converting newlines.  This also causes the file to be
+regarded as binary when written to disk, to disable the implicit
+newline conversion when saving text files on most non-Unix systems.
+
+This will probably be on by default in version 1.1 of w3mir, but not
+in version 1.0.
+
+=item B<-R>
+
+Remove files.  Normally B<w3mir> will not remove files that are no
+longer on the server/part of the retrieved web of files.  When this
+option is specified all files no longer needed or found on the servers
+will be removed.  If B<w3mir> fails to get a document for I<any> other
+reason the file will not be removed.
+
+=item B<-B>
+
+Batch fetch documents whose URLs are given on the commandline.
+
+In combination with the B<-r> and/or B<-l> switch all HTML and PDF
+documents will be mined for URLs, but the documents will be saved on
+disk unchanged.  When used with the B<-r> switch only one single URL
+is allowed.  When not used with the B<-r> switch no HTML/URL
+processing will be performed at all.  When the B<-B> switch is used
+with B<-r> w3mir will not do repeated mirrorings reliably since the
+changes w3mir needs to do, in the documents, to work reliably are not
+done.  In any case it's best not to use B<-R> in combination with
+B<-B> since that can result in deleting rather more documents than
+expected.  Hwowever, if the person writing the documents being copied
+is good about making references relative and placing the <HTML> tag at
+the beginning of documents there is a fair chance that things will
+work even so.  But I wouln't bet on it.  It will, however, work
+reliably for repeated mirroring if the B<-r> switch is not used.
+
+When the B<-B> switch is specified redirects for a given document will
+be followed no matter where they point.  The redirected-to document
+will be retrieved in the place of the original document.  This is a
+potential weakness, since w3mir can be directed to fetch any document
+anywhere on the web.
+
+Unless used with B<-r> all retrived files will be stored in one
+directory using the remote filename as the local filename.  I.e.,
+F<http://foo/bar/gazonk.html> will be saved as F<gazonk.html>.
+F<http://foo/bar/> will be saved as F<bar-index.html> so as to avoid
+name colitions for the common case of URLs ending in /.
+
+=item B<-I>
+
+This switch can only be used with the B<-B> switch, and only after it
+on the commandline or configuration file.  When given w3mir will get
+URLs from standard input (i.e., w3mir can be used as the end of a pipe
+that produces URLs.)  There should only be one URL pr. line of input.
+
+=item B<-q>
+
+Quiet.  Turns off all informational messages, only errors will be
+output.
+
+=item B<-c>
+
+Chatty.  B<w3mir> will output more progress information.  This can be
+used if you're watching B<w3mir> work.
+
+=item B<-v>
+
+Version.  Output B<w3mir>s version.
+
+=item B<-s>
+
+Copy the given document(s) to STDOUT.
+
+=item B<-f>
+
+Forget.  The retrieved documents are not saved on disk, they are just
+forgotten.  This can be used to prime the cache in proxy servers, or
+not save documents you just want to list the URLs in (see B<-l>).
+
+=item B<-l>
+
+List the URLs referred to in the retrieved document(s) on STDOUT.
+
+=item B<-umask> I<n>
+
+Sets the umask, i.e., the permission bits of all retrieved files.  The
+number is taken as octal unless it starts with a 0x, in which case
+it's taken as hexadecimal.  No matter what you set this to make sure
+you get write as well as read access to created files and directories.
+
+Typical values are: 
+
+=over 8
+
+=item 022
+
+let everyone read the files (and directories), only you can change
+them. 
+
+=item 027
+
+you and everyone in the same file-group as you can read, only you can
+change them.
+
+=item 077
+
+only you can read the files, only you can change them.
+
+=item 0
+
+everyone can read, write and change everything.
+
+=back
+
+The default is whatever was set when B<w3mir> was invoked.  022 is a
+reasonable value.
+
+This option has no meaning, or effect, on Win32 platforms.
+
+=item B<-P> I<server:port>
+
+Use the given server and port is a HTTP proxy server.  If no port is
+given port 80 is assumed (this is the normal HTTP port).  This is
+useful if you are inside a firewall, or use a proxy server to save
+bandwidth.
+
+=item B<-pflush>
+
+Proxy flush, force the proxy server to flush it's cache and re-get the
+document from the source.  The I<Pragma: no-cache> HTTP/1.0 header is
+used to implement this.
+
+=item B<-ir> I<referrer>
+
+Initial Referrer.  Set the referrer of the first retrieved document.
+Some servers are reluctant to serve certain documents unless this is
+set right.
+
+=item B<-agent> I<agent>
+
+Set the HTTP User-Agent fields value.  Some servers will serve
+different documents according to the WWW browsers capabilities.
+B<w3mir> normally has B<w3mir>/I<version> in this header field.
+Netscape uses things like B<Mozilla/3.01 (X11; I; Linux 2.0.30 i586)>
+and MSIE uses things like B<Mozilla/2.0 (compatible; MSIE 3.02;
+Windows NT)> (remember to enclose agent strings with spaces in with
+double quotes ("))
+
+=item B<-lc>
+
+Lower Case URLs. Some OSes, like W95 and NT, are not case sensitive
+when it comes to filenames.  Thus web masters using such OSes can case
+filenames differently in different places (apps.html, Apps.html,
+APPS.HTML).  If you mirror to a Unix machine this can result in one
+file on the server becoming many in the mirror.  This option
+lowercases all filenames so the mirror corresponds better with the
+server.
+
+If given it must be the first option on the command line.
+
+This option does not work perfectly.  Most especially for mixed case
+host-names.
+
+=item B<-d> I<n>
+
+Set the debug level.  A debug level higher than 0 will produce lots of
+extra output for debugging purposes.
+
+=item B<-abs>
+
+Force all URLs to be absolute.  If you retrive
+F<http://www.ifi.uio.no/~janl/index.html> and it references foo.html
+the referense is absolutified into
+F<http://www.ifi.uio.no/~janl/foo.html>.  In other words, you get
+absolute references to the origin site if you use this option.
+
+=back
+
+=head1 CONFIGURATION-FILE
+
+Most things can be mirrored with a (long) command line.  But multi
+server mirroring, authentication and some other things are only
+available through a configuration file.  A configuration file can
+either be specified with the B<-cfgfile> switch, but w3mir also looks
+for .w3mirc (w3mir.ini on Win32 platforms) in the directory where
+w3mir is started from.
+
+The configuration file consists of lines of comments and directives.
+A directive consists of a keyword followed by a colon (:) and then one
+or several arguments.
+
+ # This is a comment.  And the next line is a directive:
+ Options: recurse, remove
+
+A comment can only start at the beginning of a line.  The directive
+keywords are not case-sensitive, but the arguments I<might> be.
+
+=over 4
+
+=item Options: I<recurse> | I<no-date-check> | I<only-nonexistent> | I<list-urls> | I<lowercase> | I<remove> | I<batch> | I<input-urls> | I<no-newline-conv>
+
+This must be the first directive in a configuration file.  
+
+=over 8
+
+=item I<recurse>
+
+see B<-r> switch.
+
+=item I<no-date-check>
+
+see B<-fa> switch.
+
+=item I<only-nonexistent>
+
+see B<-fs> switch.
+
+=item I<list-urls>
+
+see B<-l> option.
+
+=item I<lowercase>
+
+see B<-lc> option. 
+
+=item I<remove>
+
+see B<-R> option.
+
+=item I<batch>
+
+see B<-B> option.
+
+=item I<input-urls>
+
+see B<-I> option.
+
+=item I<no-newline-conv>
+
+see B<-nnc> option.
+
+=back
+
+=item URL: I<HTTP-URL> [I<target-directory>]
+
+The URL directive may only appear once in any configuration file.
+
+Without the optional target directory argument it corresponds directly
+to the I<single-HTTP-URL> argument on the command line.  
+
+If the optional target directory is given all documents from under the
+given URL will be stored in that directory, and under.  The target
+directory is most likely only specified if the B<Also> directive is
+also specified.
+
+If the URL given refers to a directory it I<must> end in a "/",
+otherwise you might get quite surprised at what gets retrieved.
+
+Either one URL: directive or the single-HTTP-URL at the command-line
+I<must> be given.
+
+=item Also: I<HTTP-URL directory>
+
+This directive is only meaningful if the I<recurse> (or B<-r>)
+option is given.
+
+The directive enlarges the scope of a recursive retrieval to contain
+the given HTTP-URL and all documents in the same directory or under.
+Any documents retrieved because of this directive will be stored in the
+given directory of the mirror.
+
+In practice this means that if the documents to be retrieved are stored
+on several servers, or in several hierarchies on one server or any
+combination of those.  Then the B<Also> directive ensures that we get
+everything into one single mirror.
+
+This also means that if you're retrieving
+
+  URL: http://www.foo.org/gazonk/
+
+but it has inline icons or images stored in http://www.foo.org/icons/
+which you will also want to get, then that will be retrieved as well by
+entering
+
+  Also: http://www.foo.org/icons/ icons
+
+As with the URL directive, if the URL refers to a directory it I<must>
+end in a "/".
+
+Another use for it is when mirroring sites that have several names
+that all refer to the same (logical) server:
+
+  URL: http://www.midifest.com/
+  Also: http://midifest.com/ .
+
+At this point in time B<w3mir> has no mechanism to easily enlarge the
+scope of a mirror after it has been established.  That means that you
+should survey the documents you are going to retrieve to find out what
+icons, graphics and other things they refer to that you want.  And
+what other sites you might like to retrieve.  If you find out that
+something is missing you will have to delete the whole mirror, add the
+needed B<Also> directives and then reestablish the mirror.  This lack
+of flexibility in what to retrieve will be addressed at a later date.
+
+See also the B<Also-quene> directive.
+
+=item Also-quene: I<HTTP-URL directory>
+
+This is like Also, except that the URL itself is also quened.  The
+Also directive will not cause any documents to be retrived UNLESS they
+are referenced by some other document w3mir has already retrived.
+
+=item Quene: I<HTTP-URL>
+
+This is quenes the URL for retrival, but does not enlarge the scope of
+the retrival.  If the URL is outside the scope of retrival it will not
+be retrived anyway.
+
+The observant reader will see that B<Also-quene> is like B<Also>
+combined with B<Quene>.
+
+=item Initial-referer: I<referer>
+
+see B<-ir> option.
+
+=item Ignore: F<wildcard>
+
+=item Fetch: F<wildcard>
+
+=item Ignore-RE: F<regular-expression>
+
+=item Fetch-RE: F<regular-expression>
+
+These four are used to set up rules about which documents, within the
+scope of retrieval, should be gotten and which not.  The default is to
+get I<anything> that is within the scope of retrieval.  That may not
+be practical though.  This goes for CGI scripts, and especially server
+side image maps and other things that are executed/evaluated on the
+server.  There might be other things you want unfetched as well.
+
+B<w3mir> stores the I<Ignore>/I<Fetch> rules in a list.  When a
+document is considered for retrieval the URL is checked against the
+list in the same order that the rules appeared in the configuration
+file.  If the URL matches any rule the search stops at once.  If it
+matched a I<Ignore> rule the document is not fetched and any URLs in
+other documents pointing to it will point to the document at the
+original server (not inside the mirror).  If it matched a I<Fetch>
+rule the document is gotten.  If not matched by any ruøes the document
+is gotten.
+
+The F<wildcard>s are a very limited subset of Unix-wildcards.
+B<w3mir> understands only 'I<?>', 'I<*>', and 'I<[x-y]>' ranges.
+
+The F<perl-regular-expression> is perls superset of the normal Unix
+regular expression syntax.  They must be completely specified,
+including the prefixed m, a delimiter of your choice (except the
+paired delimiters: parenthesis, brackets and braces), and any of the
+RE modifiers. E.g.,
+
+  Ignore-RE: m/.gif$/i
+
+or
+
+  Ignore-RE: m~/.*/.*/.*/~
+
+and so on.  "#" cannot be used as delimiter as it is the comment
+character in the configuration file.  This also has the bad
+side-effect of making you unable to match fragment names (#foobar)
+directly.  Fortunately perl allows writing ``#'' as ``\043''.
+
+You must be very carefull of using the RE anchors (``^'' and ``$''
+with the RE versions of these and the I<Apply> directive. Given the
+rules:
+
+  Fetch-RE: m/foobar.cgi$/
+  Ignore: *.cgi
+
+the all files called ``foobar.cgi'' will be fetched. However, if the
+file is referenced as ``foobar.cgi?query=mp3'' it will I<not> be
+fetched since the ``$'' anchor will prevent it from matching the
+I<Fetch-RE> directive and then it will match the I<Ignore> directive
+instead. If you want to match ``foobar.cgi'' but not ``foobar.cgifu''
+you can use perls ``\b'' character class which matches a word
+boundrary:
+
+  Fetch-RE: m/foobar.cgi\b/
+  Ignore: *.cgi
+
+which will get ``foobar.cgi'' as well as ``foobar.cgi?query=mp3'' but
+not ``foobar.cgifu''. BUT, you must keep in mind that a lot of
+diffetent characters make a word boundrary, maybe something more
+subtle is needed.
+
+=item Apply: I<regular-expression>
+
+This is used to change a URL into another URL.  It is a potentially
+I<very> powerful feature, and it also provides ample chance for you to
+shoot your own foot. The whole aparatus is somewhat tenative, if you
+find there is a need for changes in how Apply rules work please
+E-mail. If you are going to use this feature please read the
+documentation for I<Fetch-RE> and I<Ignore-RE> first.
+
+The B<Apply> expressions are applied, in sequence, to the URLs in
+their absolute form. I.e., with the whole
+http://host:port/dir/ec/tory/file URL. It is only after this B<w3mir>
+checks if a document is within the scope of retrieval or not. That
+means that B<Apply> rules can be used to change certain URLs to fall
+inside the scope of retrieval, and vice versa.
+
+The I<regular-expression> is perls superset of the usual Unix regular
+expressions for substitution.  As with I<Fetch> and I<Ignore> rules it
+must be specified fully, with the I<s> and delimiting character.  It
+has the same restrictions with regards to delimiters. E.g.,
+
+  Apply: s~/foo/~/bar/~i
+
+to translate the path element I<foo> to I<bar> in all URLs.
+
+"#" cannot be used as delimiter as it is the comment character in the
+configuration file.
+
+Please note that w3mir expects that URLs identifying 'directories'
+keep idenfifying directories after application of Apply rules.  Ditto
+for files.
+
+=item Agent: I<agent>
+
+see B<-agent> option.
+
+=item Pause: I<n>
+
+see B<-p> option.
+
+=item Retry-Pause: I<n>
+
+see B<-rp> option.
+
+=item Retries: I<n>
+
+see B<-t> option.
+
+=item debug: I<n>
+
+see B<-d> option.
+
+=item umask I<n>
+
+see B<-umask> option.
+
+=item Robot-Rules: I<on> | I<off>
+
+Turn robot rules on of off.  See B<-drr> option.
+
+=item Remove-Nomirror: I<on> | I<off>
+
+If this is enabled sections between two consecutive
+
+  <!--NO MIRROR-->
+
+comments in a mirrored document will be removed.  This editing is
+performed even if batch getting is specified.
+
+=item Header: I<html/text>
+
+Insert this I<complete> html/text into the start of the document.
+This will be done even if batch is specified.
+
+=item File-Disposition: I<save> | I<stdout> | I<forget>
+
+What to do with a retrieved file.  The I<save> alternative is default.
+The two others correspond to the B<-s> and B<-f> options.  Only one
+may be specified.
+
+=item Verbosity: I<quiet> | I<brief> | I<chatty>
+
+How much B<w3mir> informs you of it's progress.  I<Brief> is the
+default.  The two others correspond to the B<-q> and B<-c> switches.
+
+=item Cd: I<directory>
+
+Change to given directory before starting work.  If it does not exist
+it will be quietly created.  Using this option breaks the 'fixup'
+code so consider not using it, ever.
+
+=item HTTP-Proxy: I<server:port>
+
+see the B<-P> switch.
+
+=item HTTP-Proxy-user: I<username>
+
+=item HTTP-Proxy-passwd: I<password>
+
+These two are is used to activate authentication with the proxy
+server.  L<w3mir> only supports I<basic> proxy autentication, and is
+quite simpleminded about it, if proxy authentication is on L<w3mir>
+will always give it to the proxy.  The domain concept is not supported
+with proxy-authentication.
+
+=item Proxy-Options: I<no-pragma> | I<revalidate> | I<refresh> | I<no-store>
+
+Set proxy options.  There are two ways to pass proxy options, HTTP/1.0
+compatible and HTTP/1.1 compatible.  Newer proxy-servers will
+understand the 1.1 way as well as 1.0.  With old proxy-servers only
+the 1.0 way will work.  L<w3mir> will prefer the 1.0 way.
+
+The only 1.0 compatible proxy-option is I<refresh>, it corresponds to
+the B<-pflush> option and forces the proxy server to pass the request
+to a upstream server to retrieve a I<fresh> copy of the document. 
+
+The I<no-pragma> option forces w3mir to use the HTTP/1.1 proxy
+control header, use this only with servers you know to be new,
+otherwise it won't work at all.  Use of any option but I<refresh> will
+also cause HTTP/1.1 to be used.  
+
+I<revalidate> forces the proxy server to contact the upstream server
+to validate that it has a fresh copy of the document.  This is nicer
+to the net than I<refresh> option which forces re-get of the document
+no matter if the server has a fresh copy already.
+
+I<no-store> forbids the proxy from storing the document in other than
+in transient storage.  This can be used when transferring sensitive
+documents, but is by no means any warranty that the document can't be
+found on any storage device on the proxy-server after the transfer.
+Cryptography, if legal in your contry, is the solution if you want the
+contents to be secret.
+
+I<refresh> corresponds to the HTTP/1.0 header I<Pragma: no-cache> or
+the identical HTTP/1.1 I<Cache-control> option.  I<revalidate> and
+I<no-store> corresponds to I<max-age=0> and I<no-store> respectively.
+
+=item Authorization
+
+B<w3mir> supports only the I<basic> authentication of HTTP/1.0.  This
+method can assign a password to a given user/server/I<realm>.  The
+"user" is your user-name on the server.  The "server" is the server.
+The I<realm> is a HTTP concept.  It is simply a grouping of files and
+documents.  One file or a whole directory hierarchy can belong to a
+realm.  One server may have many realms.  A user may have separate
+passwords for each realm, or the same password for all the realms the
+user has access to.  A combination of a server and a realm is called a
+I<domain>.
+
+=over 8
+
+=item Auth-Domain: I<server:port/realm>
+
+Give the server and port, and the belonging realm (making a domain)
+that the following authentication data holds for.  You may specify "*"
+wildcard for either of I<server:port> and I<realm>, this will work
+well if you only have one usernme and password on all the servers
+mirrored.
+
+=item Auth-User: I<user>
+
+Your user-name.
+
+=item Auth-Passwd: I<password>
+
+Your password.
+
+=back
+
+These three directives may be repeated, in clusters, as many times as
+needed to give the necessary authentication information
+
+=item Disable-Headers: I<referer> | I<user>
+
+Stop B<w3mir> from sending the given headers.  This can be used for
+anonymity, making your retrievals harder to track.  It will be even
+harder if you specify a generic B<Agent>, like Netscape.
+
+=item Fixup: I<...>
+
+This directive controls some aspects of the separate program w3mfix.
+w3mfix uses the same configuration file as w3mir since it needs a lot
+of the information in the B<w3mir> configuration file to do it's work
+correctly.  B<w3mfix> is used to make mirrors more browseable on
+filesystems (disk or CDROM), and to fix redirected URLs and some other
+URL editing.  If you want a mirror to be browseable of disk or CDROM
+you almost certainly need to run w3mfix.  In many cases it is not
+necessary when you run a mirror to be used through a WWW server.
+
+To make B<w3mir> write the data files B<w3mfix> needs, and do nothing
+else, simply put
+
+=over 8
+
+  Fixup: on
+
+=back
+
+in the configuration file.  To make B<w3mir> run B<w3mfix>
+automatically after each time B<w3mir> has completed a mirror run
+specify
+
+=over 8
+
+  Fixup: run
+
+=back
+
+L<w3mfix> is documented in a separate man page in a effort to not
+prolong I<this> manpage unnecessarily.
+
+=item Index-name: I<name-of-index-file>
+
+When retriving URLs ending in '/' w3mir needs to append a filename to
+store it localy.  The default value for this is 'index.html' (this is
+the most used, its use originated in the NCSA HTTPD as far as I know).
+Some WWW servers use the filename 'Welcome.html' or 'welcome.html'
+instead (this was the default in the old CERN HTTPD).  And servers
+running on limited OSes frequently use 'index.htm'.  To keep things
+consistent and sane w3mir and the server should use the same name.
+Put
+
+  Index-name: welcome.html
+
+when mirroring from a site that uses that convention.
+
+When doing a multiserver retrival where the servers use two or more
+different names for this you should use B<Apply> rules to make the
+names consistent within the mirror.
+
+When making a mirror for use with a WWW server, the mirror should use
+the same name as the new server for this, to acomplish that
+B<Index-name> should be combined with B<Apply>.
+
+Here is an example of use in the to latter cases when Welcome.html is
+the prefered I<index> name:
+
+  Index-name: Welcome.html
+  Apply: s~/index.html$~/Welcome.html~
+
+Similarly, if index.html is the prefered I<index> name.
+
+  Apply: s~/Welcome.html~/index.html~
+
+I<Index-name> is not needed since index.html is the default index name.
+
+=back
+
+=head1 EXAMPLES
+
+=over 4
+
+=item * Just get the latest Dr-Fun if it has been changed since the last
+time
+
+ w3mir http://sunsite.unc.edu/Dave/Dr-Fun/latest.jpg
+
+=item * Recursively fetch everything on the Star Wars site, remove
+what is no longer at the server from the mirror:
+
+ w3mir -R -r http://www.starwars.com/
+
+=item * Fetch the contents of the Sega site through a proxy, pausing
+for 30 seconds between each document
+
+ w3mir -r -p 30 -P www.foo.org:4321 http://www.sega.com/
+
+=item * Do everything according to F<w3mir.cfg>
+
+ w3mir -cfgfile w3mir.cfg
+
+=item * A simple configuration file
+
+ # Remember, options first, as many as you like, comma separated
+ Options: recurse, remove
+ #
+ # Start here:
+ URL: http://www.starwars.com/
+ #
+ # Speed things up
+ Pause: 0
+ #
+ # Don't get junk
+ Ignore: *.cgi
+ Ignore: *-cgi
+ Ignore: *.map
+ #
+ # Proxy:
+ HTTP-Proxy: www.foo.org:4321
+ #
+ # You _should_ cd away from the directory where the config file is.
+ cd: starwars
+ #
+ # Authentication:
+ Auth-domain: server:port/realm
+ Auth-user: me
+ Auth-passwd: my_password
+ #
+ # You can use '*' in place of server:port and/or realm:
+ Auth-domain: */*
+ Auth-user: otherme
+ Auth-user: otherpassword
+
+=item Also:
+
+ # Retrive all of janl's home pages:
+ Options: recurse
+ #
+ # This is the two argument form of URL:.  It fetches the first into the second
+ URL: http://www.math.uio.no/~janl/ math/janl
+ #
+ # These says that any documents refered to that lives under these places
+ # should be gotten too.  Into the named directories.  Two arguments are
+ # required for 'Also:'.
+ Also: http://www.math.uio.no/drift/personer/ math/drift
+ Also: http://www.ifi.uio.no/~janl/ ifi/janl
+ Also: http://www.mi.uib.no/~nicolai/ math-uib/nicolai
+ #
+ # The options above will result in this directory hierarchy under
+ # where you started w3mir:
+ # w3mir/math/janl		files from http://www.math.uio.no/~janl
+ # w3mir/math/drift		from http://www.math.uio.no/drift/personer/
+ # w3mir/ifi/janl		from http://www.ifi.uio.no/~janl/
+ # w3mir/math-uib/nicolai	from http://www.mi.uib.no/~nicolai/
+
+=item Ignore-RE and Fetch-RE
+
+ # Get only jpeg/jpg files, no gifs
+ Fetch-RE: m/\.jp(e)?g$/
+ Ignore-RE: m/\.gif$/
+
+=item Apply
+
+As I said earlier, B<Apply> has not been used for Real Work yet, that
+I know of.  But B<Apply> I<could>, be used to map all web servers at
+the university of Oslo inside the scope of retrieval very easily:
+
+  # Start at the main server
+  URL: http://www.uio.no/
+  # Change http://*.uio.no and http://129.240.* to be a subdirectory
+  # of http://www.uio.no/.
+  Apply: s~^http://(.*\.uio\.no(?:\d+)?)/~http://www.uio.no/$1/~i
+  Apply: s~^http://(129\.240\.[^:]*(?:\d+)?)/~http://www.uio.no/$1/~i
+
+
+=back
+
+There are two rather extensive example files in the B<w3mir> distribution.
+
+=head1 BUGS
+
+=over 4
+
+=item The -lc switch does not work too well.
+
+=back
+
+=head1 FEATURES
+
+These are not bugs.
+
+=over 4
+
+=item URLs with two /es ('//') in the path component does not work as
+some might expect.  According to my reading of the URL spec. it is an
+illegal construct, which is a Good Thing, because I don't know how to
+handle it if it's legal.
+
+=item If you start at http://foo/bar/ then index.html might be gotten
+twice.
+
+=item Some documents point to a point above the server root, i.e.,
+http://some.server/../stuff.html.  Netscape, and other browsers, in
+defiance of the URL standard documents will change the URL to
+http://some.server/stuff.html.  W3mir will not.
+
+=item Authentication is I<only> tried if the server requests it.  This
+might lead to a lot of extra connections going up and down, but that's
+the way it's gotta work for now.
+
+=back
+
+=head1 SEE ALSO
+
+L<w3mfix>
+
+=head1 AUTHORS
+
+B<w3mir>s authors can be reached at I<w3mir-core@usit.uio.no>.
+B<w3mir>s home page is at http://www.math.uio.no/~janl/w3mir/
Index: /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3pdfuri.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3pdfuri.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/w3mir/w3mir-1.0.8/w3pdfuri.pm	(revision 10506)
@@ -0,0 +1,64 @@
+# -*- perl -*-
+#
+# w3pdfuri.pm -- extract uris from a adobe acrobat pdf file.
+#     version 0.1
+$VERSION=0.1;
+#
+# Assumptions:
+# - File starts with %PDF
+# - All URLS match this RE: ^\/URI\s+\(([^)]*)\)\s*$  (found by inspection of
+#   one (1) pdf file (the reader.pdf in the acrobat distribution).
+# - pdf files are potentially very large, so we read it from disk
+#   record by record.
+# - Record separator is ^M
+#
+# History:
+# - 19/02/97 janl: Version 0.1, seems to work with PDF-1.2
+#
+
+package w3pdfuri;
+
+use strict;
+
+sub list ($) {
+  my ($file) = @_;
+
+  my @urls=();
+  local($/)="\r";
+
+  unless (open(PDF,"< $file")) {
+    warn "Could not open $file for input: $!\n";
+    return;
+  }
+
+  $_ = <PDF>;
+  unless (/^%PDF-/) {
+    warn "$file is not a PDF file.\n";
+    close(PDF);
+    return;
+  }
+  
+  while (<PDF>) {
+    chomp;
+    push(@urls,$1) if (m~^/URI\s+\(([^)]*)\)\s*$~);
+  }
+
+  close(PDF);
+
+  return @urls;
+}
+
+1;
+
+__END__
+
+# Test code
+print "reader.pdf: ",
+  join(",",list("/local/lib/acrobat/Reader/help/reader.pdf")),"\n";
+print "Acrobat.pdf: ",
+  join(",",list("/local/lib/acrobat/Reader/Acrobat.pdf")),"\n";
+print "License.pdf: ",
+  join(",",list("/local/lib/acrobat/Reader/License.pdf")),"\n";
+print "MapTypes.pdf: ",
+  join(",",list("/local/lib/acrobat/Reader/MapTypes.pdf")),"\n";
+list("/etc/services");
Index: /tags/gsdl-2_61-distribution/gsdl/packages/wget/README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/wget/README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/wget/README	(revision 10506)
@@ -0,0 +1,19 @@
+wget - web site mirroring software
+
+This directory contains a version of the GNU wget program that was written by
+Hrvoje Niksic and others and distributed under the GNU General Public Licence
+
+The GNU wget homepage is http://www.cg.tuwien.ac.at/~prikryl/wget.html
+
+A couple of very small changes were made to this package by Stefan Boddie
+(sjboddie@cs.waikato.ac.nz). The USE_STDARG preprocessor definition was
+added to the VC++ makefile as it appeared to need it to compile on either
+VC++ 4.2 or VC++ 6.0. A change was also made to prevent backslashes from
+mistakenly being converted to "@5c" on windows.
+
+2003/11/27 - sjboddie@cs.waikato.ac.nz made a few more small changes to fix
+h_errno bug preventing code from compiling on latest versions of GCC.
+
+2004/06/30 - kjdon@cs.waikato.ac.nz replaced version 1.5.3 with version 1.9.
+It compiled as is under Windows XP, using VC++ 6.0, under Linux using GCC 3.2.3 and GCC 2.95.3. So I haven't made any changes. 
+Under Windows, I haven't compiled it with openssl, so it doesn't support https://. OpenSSL comes with a warning about it being illegal in some countries to distribute cryptographic technology, so I haven't used it. Look at wget-1.9/windows/README for Windows compiling instructions if you want to add it in.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/windows/crypt/README.TXT
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/windows/crypt/README.TXT	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/windows/crypt/README.TXT	(revision 10506)
@@ -0,0 +1,7 @@
+This directory contains a win32 port of the crypt library (see the enclosed
+README files for details). To compile with Microsoft Visual C++ unzip
+crypt.zip and run "nmake /f win32.mak" in the top level directory.
+
+Link crypt.lib with your project when compiling Greenstone.
+
+Stefan Boddie (sjboddie@cs.waikato.ac.nz)
Index: /tags/gsdl-2_61-distribution/gsdl/packages/windows/gdbm/README.TXT
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/windows/gdbm/README.TXT	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/windows/gdbm/README.TXT	(revision 10506)
@@ -0,0 +1,7 @@
+This directory contains a win32 port of gdbm. To compile with Microsoft
+Visual C++ unzip gdbm.zip and run "nmake /f win32.mak" in the top level
+directory.
+
+Link gdbm.lib with your project when compiling Greenstone.
+
+Stefan Boddie (sjboddie@cs.waikato.ac.nz)
Index: /tags/gsdl-2_61-distribution/gsdl/packages/wv/README
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/wv/README	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/wv/README	(revision 10506)
@@ -0,0 +1,16 @@
+wv - Microsoft Word converter
+
+This directory contains a version of the wv program.  It was originally
+written by Caolan McNamara and distributed under the GNU General Public
+License.  wv is now maintained by Dom Lachowicz and Martin Vermeer.  wv
+incorporates code from a variety of GPL programs from other sources.
+Thank you all.
+
+The wv homepage is http://wvware.sourceforge.net/
+
+We have included the source code here.  It is a slimmed-down version
+of wv version 0.7.1. It should handle documents created with Word 2 up
+to Word 2000. We have tested it on Linux (slackware 7), darwin (OS X
+10.1.3), cygwin, and solaris 2.8 (via sourceforge's compile farm).
+
+John McPherson -- Apr 2002
Index: /tags/gsdl-2_61-distribution/gsdl/packages/xlhtml/README.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/xlhtml/README.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/xlhtml/README.txt	(revision 10506)
@@ -0,0 +1,19 @@
+This package contains two programs:
+* ppthtml, which converts Microsoft PowerPoint 95 and 97 files
+into html or xml, and
+* xlhtml, which converts Microsoft Excel 95 and 97 files.
+
+It has been slightly modified for greenstone use as we only want the
+ppt to html program and the xls to html program, and none of the other
+programs (summary/diagnostics, man pages, etc).
+
+This version (0.4.9.0) was the latest development snapshot at the
+time of writing.
+
+See http://www.xlhtml.org/ for newer versions or more info.
+
+xlhtml is released under the GNU GPL.
+
+20 Feb 2002
+John McPherson
+NZDL.
Index: /tags/gsdl-2_61-distribution/gsdl/packages/yaz/GSDL_USAGE.html
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/yaz/GSDL_USAGE.html	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/yaz/GSDL_USAGE.html	(revision 10506)
@@ -0,0 +1,124 @@
+<html>
+<head>
+<title>Using the Z39.50 Client in Greenstone</title>
+</head>
+
+<body>
+<a name=top>
+<h1>Using the Z39.50 Client in Greenstone</h1>
+</a>
+<b>Table of Contents</b><br>
+<a href="#whatis">About: What is Z39.50?</a><br>
+<a href="#config">Configuring Greenstone - Adding Servers</a><br>
+<a href="#todo">Currently known problems, and TODO list</a><br>
+<a href="#contact">Contacting Us</a><br>
+
+
+
+<a name=whatis>
+<h2>What is Z39.50?</h2>
+</a>
+Z39.50 is an international client/server protocol for searching bibliographic
+data. It can use the Internet Protocol (TCP/IP), which makes the databases
+on a server available from almost anywhere around the globe. It is widely
+used, for example, in on-line library catalogues. It allows a user to search
+one or more databases and retrieve the results of the query.
+
+<p>
+Our implementation uses the YAZ z39.50 toolkit, written by
+<a href="http://www.indexdata.dk">Index Data</a>.
+
+
+
+<a name=config>
+<h2>Adding Servers</h2>
+</a>
+The file z3950.cfg in the etc/packages directory contains entries for
+each server. By default, no servers are set up, although the config file
+comes with two (commented out) example Z39.50 servers, both for servers
+of the United States' <b>Library of Congress</b>.
+<p>
+Each entry consists of:
+<ul>
+<li>A unique "short name" for internal use by Greenstone.</li>
+<li>The internet name or address of the server, and optionally the
+port that the server is running on if not the default port 210.</li>
+<li>The name of the database to search on that server.</li>
+<li>A string that provides a meaningful name for the "collection".</li>
+<li>An optional "About" string, providing some information about the database
+and/or server.</li>
+<li>Optional icon fields, which are displayed instead of the text on the
+front page.</li>
+</ul>
+The entries need only be separated by whitespace, but for the purposes of
+clarity the sample entry uses newlines and tabs.
+<p>
+The sample Library of Congress entry looks like this:
+<pre>
+LOC
+        z3950.loc.gov:7090
+        Voyager
+        "Library of Congress z39.50 server"
+        About  en  "This is the z39.50 interface to the US LoC catalogue
+           system. It contains approximately 12 million bibliographic records.
+           For server capabilities, look at
+	   &lt;a href=\"http://lcweb.loc.gov/z3950/lcserver.html\"&gt;their web pages&lt;/a&gt;."
+</pre>
+There is a list at the Library Of Congress website containing some 
+<a href="http://lcweb.loc.gov/z3950/agency/resources/testport.html">servers 
+publicly available for testing</a>.
+
+
+<a name=todo>
+<h2>Known Problems/Issues list</h2>
+</a>
+<ul>
+<li>Because of the open nature of the standard, our client may not work with
+some servers. Please notify the author (contact details below) of any
+such problems.</li>
+<li>Because of the large number of Marc fields, only the most frequently
+used fields have been given explicit names in the results. Furthermore,
+these are currently hard-coded to correspond to the USMARC field names.</li>
+<li><b>The z39.50 client will not work when fast-cgi is used!</b>. Currently,
+the use of the fast-cgi package (off by default) will disable the
+use of the z39.50 client code for Greenstone.</li>
+<li>There are spurious &lt;B&gt; tags in the title of the window when
+viewing an individual record.</li>
+<li>Greenstone will claim there are no collections if there are no
+sub-directories in the "collect" directory, even if there are configured
+z39.50 servers, although it will work if there are unbuilt collections.</li>
+</ul>
+
+<b>History</b><br>
+Jul 2001 - finally tracked down and fixed an annoying bug that caused
+greenstone to segfault when retrieving documents for some queries.<br>
+Jun 2001 - decided to drop href for field 856, as some examples have 
+explanatory text in the field as well as the URI.<br>
+Oct 2000 - cache results from server, so cut down the number of connections for
+a single query/document. Also added href for MARC field 856.<br>
+Aug 2000 - Various bug fixes and minor modifications.<br>
+Fri Aug 4 2000 - The z39.50 code is now "stable" in the main source code (in CVS).<br>
+Tue 1 Aug 2000 - selecting a field from the drop-down box now actually works. 
+This results in both quicker replies and more accurate results.<br>
+Mon 24 Jul 2000 - queries are now "AND"ed - for example, the query "computer 
+science" will now only return records that contain both words.<br>
+May-June 2000 - Code written.<br>
+
+<a name=contact>
+<h2>Contact Details</h2>
+</a>
+For general comments about Greenstone, or suggestions for improvements, send
+email to
+<a href="mailto:greenstone@cs.waikato.ac.nz?subject=z39.50 client in Greenstone">greenstone@cs.waikato.ac.nz</a><br>
+<br>
+For bug reports or questions about the z39.50 code itself, send email to
+the author, John McPherson -
+<a href="mailto:jrm21@cs.waikato.ac.nz?subject=z39.50 client in Greenstone"
+>jrm21@cs.waikato.ac.nz</a>.
+
+<p>
+<a href="#top">Back to top</a>
+<p>
+<address>Last modified: July 12, 2001 by John McPherson</address>
+</body>
+</html>
Index: /tags/gsdl-2_61-distribution/gsdl/packages/yaz/README.gsdl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/packages/yaz/README.gsdl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/packages/yaz/README.gsdl	(revision 10506)
@@ -0,0 +1,24 @@
+The YAZ toolkit is used by the GSDL receptionist
+when acting as a z39.50 client.
+
+June 2005, kjdon:
+Changed to use yaz version 2.1.4. This is also used by the new z3950server.
+The original yaz download has been added to cvs - this is unzipped and untared by the configure script, then only the src and client directories are compiled.
+Greenstone uses the libyaz.a library. yaz_zclient.o is modified from the sample client.o, and now lives in the colservr directory.
+
+Two files are linked against: 
+ client/yaz_client.o, which was modified from Index Data's sample 
+	client code, and
+
+ lib/libyaz.a, which contains all the z39.50 and MARC formatting code.
+	There is probably a lot of stuff in this library that does
+	not need to be there for our purposes, but for now it is,
+	merely wasting some disk space and some compile-time CPU.
+
+John McPherson
+3 August 2000
+
+yaz version 1.6
+
+September 2000:
+removed "ill" "server" "ztest" and "retrieval" subdirs.
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/DateExtract.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/DateExtract.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/DateExtract.pm	(revision 10506)
@@ -0,0 +1,275 @@
+package DateExtract;
+
+##use BasPlug; ## no, DON'T use BasPlug, BasPlug uses us....
+use sorttools;
+use util;
+
+#75% of the instances of the word century use full name ordinals
+my %ordinals = ("first" => 1, "second" => 2, "third" => 3, "fourth" => 4,
+             "fifth" => 5, "sixth" => 6, "seventh" => 7, "eighth" => 8,
+             "ninth" => 9, "tenth" => 10, "eleventh" => 11, "twelfth" => 12,
+             "thirteenth" => 13, "fourteenth" => 14, "fifteenth" => 15,
+             "sixteenth" => 16, "seventeenth" => 17, "eighteenth" => 18,
+             "nineteenth" => 19, "twentieth" => 20);
+
+
+             
+
+#definitions for a date grammar.
+my $fulOrd = join('|',(keys %ordinals));
+
+my @months = ("january","february","march","april","may","june","july",
+              "august","september","october","november","december");
+
+my $shortmth = "";
+foreach $m (@months) { $shortmth .= (substr($m,0,3)."\\.?|"); }
+chop($shortmth);
+
+my $longmth = join('|',@months);
+
+
+my $Qualifier = "(B(\\.)?C(\\.)?(E(\\.)?)?)|(A(\\.)?D(\\.)?)|(C(\\.)E(\\.)?)";
+my $Century = "Cent(\\.|ur(y|ies))";
+my $Ord = "st|nd|rd|th";
+my $seasonref = "(spring|fall|autumn|winter|summer)";
+my $sep = " ?- ?";
+my $tri_digit = "(in|since|(the year)|($seasonref of)) \\d{3}\\D( ($Qualifier))?";
+my $centurydate = "(((\\d{1,2})($Ord))|($fulOrd)) ($Century)( ($Qualifier))?";
+my $qualified = "(($Qualifier) ?(\\d{1,4}))|((\\d{1,4}) ?($Qualifier))";
+my $millenium = "[1-9]\\d{3}";
+my $range = "(($millenium)($sep)($millenium))|(($millenium)($sep)(\\d{1,2}))|(($qualified)($sep)($qualified))|(($Qualifier) ?(\\d{1,3})($sep)(\\d{1,3}))|((\\d{1,3})($sep)(\\d{1,3}) ?($Qualifier))";
+
+my $pgnum = "(p(p|g)?\\.? ?\\d+((-|,)(\\d+))?)|(page \\d+)|(pages \\d+((-|,)(\\d+))?)";
+my $lgnum = "\\d{1,3},(\\d{3})+";
+my $colon = ":\\d+";
+my $money = "\$(\\d{1,3}(((,\\d{3})+)|\\d+))";  $money = "\\" . $money; 
+my $microfilm = " reel([^\\.\\)])*(\\.|\\))";
+my $lastaltered = "last (edited|updated)";
+my $references = "reference(s?)(:?)\\n";
+my $cited = "work(s?) cited";
+my $biblio = "bibliography(:?)( ?)\\n";
+
+my $direction = "(N(\\.|o\\.|th\\.|orth))|(S(\\.|th\\.|outh))|(E(\\.|ast))|(W(\\.|est))";
+my $street_id = "(st\\.)|(street[^A-Za-z])|(ave\\.)|(avenue[^A-Za-z])|(boulevard[^A-Za-z])|(blvd\\.)|(rd\\.)|(road[^A-Za-z])";
+my $streetname = "(\\d{1,2}(<SUP>)?($Ord)(</SUP>)?)|([A-Za-z]+( [A-Za-z]+)?)|([A-Za-z]+-[A-Za-z]+($Ord))";
+my $address = "\\d{1,4} (($direction) )?($streetname) ($street_id)";
+
+my $bracket = "\\($millenium\\)";
+my $ref_end = ", ?$millenium\\)";
+my $colonsp = ": $millenium";
+my $reprint = "[Rr]eprint of \\d{4} edition";
+my $comma = ", $millenium\\.";
+my $fullstop = "\\. $millenium\\.";
+my $semi = "; $millenium\\.";
+
+my $lookalikes = "($pgnum)|($lgnum)|($colon)|($money)|($microfilm)|($address)";
+my $spurious = "($lastaltered)";
+my $bibheader = "($references)|($cited)|($biblio)";
+
+
+sub get_date_metadata {
+    #get the text of the document, the "document object" concerned,
+    #and the current section within the document
+    local ($text, $doc, $cursection, $keep_bib, $max_year, $max_century) = @_;
+    
+    #format a prechristian maximum century value to be negative so that it can
+    #be used in numeric comparison
+    if($max_century =~ /B/)
+    {
+        $max_century = $`;
+        $max_century =~ /\d+/;
+        $max_century = $&;
+        $max_century *=-1
+    }
+   
+    local $extr = &remove_excess($text);    
+    #print "EXTRACTION TEXT:\n $extr";
+    $extr = &remove_tags($extr);
+    if(!$keep_bib){
+        $extr = &remove_biblio($extr);
+    }
+  
+
+    local @datelist = ();
+    while($extr =~ m!($range)|($millenium)|($qualified)|($centurydate)|($tri_digit)!i)
+    { 
+        $extr = $';
+        my $fulldate = $&;
+        if ($fulldate =~ /$centurydate/i)
+        {
+            if($max_century!=-1)
+            {
+
+                local $date = $fulldate; if($date =~ /\d+/) {$date = $&;} 
+                else 
+                {
+                    $date=$fulldate; $date =~ m! ($Century)!i; $date = $`;
+                    $date =~ tr/A-Z/a-z/;
+                    $date = $ordinals{$date};
+                }
+                if($max_century >= $date){
+                    $date = ($date-1)*100 +1;
+                    #if it BC, make it negative
+                    $date = &convert_bc($fulldate,$date);
+                    $end = $date + 99; 
+                    @century = ($date..$end);
+                    @datelist = (@datelist,@century);
+                }
+            }
+        }
+        
+        elsif($fulldate =~ /$range/)
+        {
+            $fulldate =~ /$sep/;
+            my @addlist = ();
+            #print "Range: $fulldate\n";
+            $fullfirst = $`; 
+            $fullsecond = $'; 
+            $fullfirst =~ /\d+/; $first = $&; 
+            $fullsecond =~ /\d+/; $second = $&;
+            $len1 = length($first);
+            $len2 = length($second);
+            $second = (substr($first,0,($len1-$len2))).$second;
+            $first = &convert_bc($fullfirst,$first);
+            $second = &convert_bc($fullsecond,$second);
+            @addlist = ($first..$second);
+            @datelist = (@datelist,@addlist);
+            
+        }
+        else {
+            
+            my $date = $fulldate; $date =~ /\d+/; $date = $&;  
+            $date = &convert_bc($fulldate,$date);
+            #add the date metadata
+            push(@datelist,$date);
+            #print "datelist @datelist\n"
+        }
+        
+    }
+    
+    if(@datelist){
+        @datelist = sort { $a <=> $b } @datelist;
+        @datelist = &post_process($max_year, @datelist);
+        foreach $date (@datelist)
+        {
+            if($date>0){
+                $doc->add_metadata($cursection,"Coverage",$date);}
+            else{
+                $doc->add_metadata($cursection,"Coverage","bc".(-1*$date));}
+                
+        }
+    }
+}
+sub convert_bc {
+    local ($full,$num) = @_;
+    if ($full =~ /B/) { $num *= -1; }
+    $num;
+}
+
+sub post_process {
+    local ($max_year, @list) = @_;
+    @cleanlist = ();
+    $prev = 0;
+    foreach $e (@list) {
+        if ($e!=$prev && $e <= $max_year) {
+            push(@cleanlist, $e);
+        }
+        $prev = $e;
+    }
+    @cleanlist;
+}
+
+
+#removes all html tags from that data, as they will not contain dates which
+#are part of the content of the document, and therefore interesting, but do
+#contain date lookalikes
+sub remove_tags {
+    local ($tmp) = @_;
+   
+    local $parsed = "";
+    #while there is still text to be parsed and tags are still found
+    while($tmp=~ m!<([^>])*(>|$)! && $tmp ne "")
+    {
+        $parsed .= $`;#keep all that is not in a tag
+        $tmp = $';    #restart the search after then end of the tag
+    }
+    $parsed .= $tmp; #add anything after the last match
+    $parsed;
+}
+
+
+sub remove_excess {
+    local ($tmp) = @_;
+    local $parsed = "";
+   
+
+    if(($tmp =~ m!($spurious)|($lookalikes)!i) == 0 )
+    { 
+        $parsed = $tmp;
+    }
+    else { 
+        while ($tmp =~ m!($spurious)|($lookalikes)!i 
+               && $tmp ne "")
+        {
+            $parsed .= $`;
+            $storage = $&;
+            $tmp = $';
+            #match the pattern which indicates most recent alteration 
+            if ($storage =~ m!$lastaltered!i)
+            {
+                #match a four digit year or up until the first / 
+                #(as in last edited 3/97). 
+                $tmp =~ m!($millenium)|(\/)!;
+                $tmp = $';
+            }
+                
+        }
+        
+        $parsed .= $tmp;
+           
+    }
+    #print "Parsed:\n $parsed\n\n";
+    $parsed;
+    
+}
+
+sub remove_biblio{
+    local ($tmp) = @_;
+    local $parsed = "";
+    
+    if($tmp =~ m!$bibheader!i)
+    {
+        $tmp=$`;
+    }
+    
+    $tmp =~ s/( |\t)+/ /g;
+    if(($tmp =~ m!($ref_end)|($bracket)|($colonsp)|($reprint)|($comma)|($fullstop)|($semi)|($seasonref) ($millenium)!i) == 0)
+    {
+        $parsed = $tmp;
+    }
+    else{
+
+        #print "removing bib\n";
+        while ($tmp =~ m!($ref_end)|($bracket)|($colonsp)|($reprint)|($comma)|($fullstop)|($semi)|(($seasonref) ($millenium))|($bibheader)!i && $tmp ne "")
+        {
+            
+            $parsed .= $`;
+            $tmp = $';
+            if($&=~m!($comma)|($fullstop)!)
+            {
+                
+                local  $date = $&;
+                if($parsed =~ m!((\d)($Ord)$)|(($shortmth)$)|(($longmth)$)!i)
+                {
+                    $parsed .= $date;
+                }
+            }  
+            
+        }
+                   $parsed .= $tmp;
+    }
+    $parsed;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/Kea.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/Kea.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/Kea.pm	(revision 10506)
@@ -0,0 +1,124 @@
+package Kea;
+
+# This function is called by BasPlug.pm when a flag in a collection
+# configuration document specifies that keyphrase metadata must be gathered for
+# that collection.
+# It is passed as arguments, the documents text and possibly some options for
+# how the keyphrase data is to be collected if the keyphrase option flag was
+# set in the collection configuration file.  This module then writes the
+# documents text to a file in a temporary directory because the stand-alone program Kea which will be
+# called to do the actual extraction of the keyphrases expects a directory with one or more files as argument.
+# Once Kea has been called upon, the file containing the keyphrase data
+# gathered by Kea should be stored in gsdl/tmp and this file is read, the data
+# we are interested in is extracted and passed back to BasPlug.pm in an
+# appropriate format.
+
+# returns a string containing comma-separated keyphrases
+sub extract_KeyPhrases {
+
+    # Parsing arguments of the function
+    my $doc = shift(@_); # documents text  
+    my $args = shift(@_); # any options
+    my @optionlist = split(/\s+/, $args) if (defined($args)); #list of options
+
+    # Specifying directory names
+    my $gsdlhome = $ENV{'GSDLHOME'}; 
+    my $keahome = "$gsdlhome/packages/kea/kea-3.0";
+    my $defaultmodel = "$keahome/CSTR";
+    
+    # Initializing variables:
+    my $command = ""; 
+    my @keylist; 
+    my @options = ();
+    $modelspec = 0;
+
+    # Settings for the java executable: 
+
+    # CLASSPATH:
+    $java_classpath = ".:$keahome";
+
+    # See if java executable is on path
+    my $java_exec="";
+    if (system("which java >/dev/null 2>/dev/null")==0) {
+	$java_exec=`which java`;
+	chomp $java_exec;
+    } else {
+	$java_exec="$java_home/bin/java";
+    }
+    
+    # The actual java command is based on these other variables:
+    $java_command = "$java_exec -classpath \"$java_classpath\"";
+    
+    # end of java settings
+
+    # Parsing options for keyphrase extraction:
+    if (@optionlist) {
+	foreach $element (@optionlist){ #for each option
+	    if (length($element) == 1) {
+		push(@options, "-$element");
+	    } else {
+		$option = substr($element, 0, 1);
+		$value = substr($element,1);
+		if (($option eq "m") && (-e "$keahome/$value")) {
+		    $modelspec = 1;
+		    push(@options, "-$option $keahome/$value");
+		} elsif ($option eq "m") {		    
+		    $modelspec = 1;
+		    print STDERR "Couldn't find model $value. Using the default model instead\n";
+		    push(@options, "-$option $defaultmodel");
+		} else {
+		    push(@options, "-$option $value");
+		}
+		
+	    }
+	}
+	# if none of the option specifies the model, set the default one:
+	if ($modelspec != 1) {
+	    push(@options, "-m $defaultmodel");	
+	}
+	$options = join(" ",@options);
+	# print STDERR "OPTIONS: $options\n";
+    } else {
+	# If no options were specified: Set default value for the model
+	$options = "-m $defaultmodel";	
+    }
+
+    # Remove all HTML tags from the original text
+    $doc =~ s/<P[^>]*>/\n/sgi;
+    $doc =~ s/<H[^>]*>/\n/sgi;
+    $doc =~ s/<[^>]*>//sgi;
+    $doc =~ tr/\n/\n/s;
+
+    # Write text to a temporary file doc.txt 
+    open(OUT, ">$gsdlhome/tmp/doc.txt") or die "In Kea.pm doc.txt could not be created\n";  
+    print OUT $doc;
+    close(OUT);
+
+
+    # EXECUTE KEA with specific options:
+    $command = "$java_command KEAKeyphraseExtractor -l $gsdlhome/tmp $options";
+    system ("$command");
+
+    # Read the resulting doc.key, which contains keyphrases:
+
+    open(IN, "<$gsdlhome/tmp/doc.key") or return "";
+                                          #this means doc.key does not exist
+                                          #either because an option was wrongly specified
+	                                  #or no keyphrases were found
+    while(<IN>){
+	chomp;
+	push(@keylist,$_);
+    }
+    close(IN);
+
+    $keylist = join(", ", @keylist);
+
+    # Delete doc.key so that in future it will not be opened and read.
+    # Otherwise KEA sees it as more keyphrases!
+
+    unlink("$gsdlhome/tmp/doc.key");
+	
+    return $keylist;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/XMLParser.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/XMLParser.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/XMLParser.pm	(revision 10506)
@@ -0,0 +1,33 @@
+# Wrapper that ensures the right version of XML::Parser is loaded given
+# the version of Perl being used.  Need to distinguish between Perl 5.6 and
+# Perl 5.8
+
+
+sub BEGIN {
+    my $perl_dir;
+
+    # Note: $] encodes the version number of perl
+    if ($]>5.008) { 
+	# perl 5.8.1 or above
+	$perl_dir = "perl-5.8";
+    }
+    elsif ($]<5.008) {
+	# assume perl 5.6
+	$perl_dir = "perl-5.6";
+    }
+    else {
+	print STDERR "Warning: Perl 5.8.0 is not a maintained release.\n";
+	print STDERR "         Please upgrade to a newer version of Perl.\n";
+	$perl_dir = "perl-5.8";
+    }
+
+    if ($ENV{'GSDLOS'} !~ /^windows$/i) {
+	# Use push to put this on the end, so an existing XML::Parser will be used by default
+	push (@INC, "$ENV{'GSDLHOME'}/perllib/cpan/$perl_dir");
+    }
+}
+
+use XML::Parser;
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/acronym.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/acronym.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/acronym.pm	(revision 10506)
@@ -0,0 +1,697 @@
+##########################################################################
+#
+# acronym.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+#    class to handle acronyms
+###########################################################################
+
+eval "require diagnostics"; # some perl distros (eg mac) don't have this
+
+package acronym;
+
+###########################################################################
+#    global variables
+###########################################################################
+# valiables to control the recall/precision tradeoff
+
+#the maximum range to look for acronyms 
+my $max_offset = 30;
+#acronyms must be upper case
+my $upper_case = 1;
+#acronym case must match
+my $case_match = 1;
+#minimum acronym length
+my $min_def_length = 3;
+#minimum acronym length
+my $min_acro_length = 3;
+#minimum acronym length saving
+my $min_length_saving = 4;
+#allow recusive acronyms
+my $allow_recursive = 0;
+#let definitions be all capitals
+my $allow_all_caps = 0;
+
+my @stop_words = split / /, "OF AT THE IN TO AND";
+
+#the text split into an array, one word per element
+my @split_text = ();
+my @acronym_list = ();
+
+#the file to collate acronyms into
+my $acronym_accumulate_file = $ENV{'GSDLCOLLECTDIR'} . "/etc/acronym_definitions.pm";
+my $acronym_options_file = $ENV{'GSDLCOLLECTDIR'} . "/etc/acronym_options.pm";
+
+my %acronyms_found_in_collection = ();
+my %acronyms_banned_from_collection = ();
+
+my $writing_acronyms = 1;
+my $accumulate_acronyms = 1;
+my $markup_accumulate_acronyms = 1;
+my $markup_local_acronyms = 1;
+
+
+
+###########################################################################
+#   file saving / loading stuff
+###########################################################################
+
+sub initialise_acronyms {
+
+    my $local_max_offset = $max_offset;
+    my $local_upper_case = $upper_case;
+    my $local_case_match = $case_match ;
+    my $local_min_def_length = $min_def_length;
+    my $local_min_acro_length = $min_acro_length;
+    my $local_min_length_saving = $min_length_saving;
+    my $local_allow_recursive = $allow_recursive;
+    my $local_allow_all_caps = $allow_all_caps;
+    my @local_stop_words = @stop_words;
+    my $local_acronym_accumulate_file = $acronym_accumulate_file;
+    
+    
+    my $file_text = "";
+    if (open ACRONYM_HANDLE, "<$acronym_options_file")
+    {
+	$file_text = do { local $/; <ACRONYM_HANDLE> };  
+    }
+    if ($file_text eq "")
+    {
+	print STDERR "failed to open $acronym_options_file\n";
+	open ACRONYM_HANDLE, ">$acronym_options_file\n";
+	print ACRONYM_HANDLE "#Config file for acronym extraction. EDIT THIS FILE, it should\n";
+	print ACRONYM_HANDLE "#not be overridden by the software. It's read by GSDL using perl's\n";
+	print ACRONYM_HANDLE "#'eval' function, so pretty much anything that's valid in perl is \n";
+	print ACRONYM_HANDLE "#valid here.\n\n";
+	print ACRONYM_HANDLE "#Quite a few things here are defined in terms of recall and precision\n";
+	print ACRONYM_HANDLE "#which are the key measures from Information Retreval (IR). If you\n";
+	print ACRONYM_HANDLE "#don't understand recall and precision, any good IR textbook should\n";
+	print ACRONYM_HANDLE "#explain them fully \n\n";
+	print ACRONYM_HANDLE "#the maximum range to look for acronyms (raise to raise precision)\n"; 
+	print ACRONYM_HANDLE "\$local_max_offset = $max_offset;\n\n"; 
+	print ACRONYM_HANDLE "#acronyms must be upper case (0 = false, 1 = true (high precision))\n";
+	print ACRONYM_HANDLE "\$local_upper_case = $upper_case;\n\n";
+	print ACRONYM_HANDLE "#acronym case must match (0 = false, 1 = true (high precision))\n";
+	print ACRONYM_HANDLE "\$local_case_match = $case_match;\n\n";
+	print ACRONYM_HANDLE "#minimum acronym length (raise to raise precision)\n";
+	print ACRONYM_HANDLE "\$local_min_def_length = $min_def_length;\n\n";
+	print ACRONYM_HANDLE "#let definitions be all capitals\n";
+	print ACRONYM_HANDLE "\$local_allow_all_caps = $allow_all_caps;\n\n";
+	print ACRONYM_HANDLE "#minimum acronym length (raise to raise precision)\n";
+	print ACRONYM_HANDLE "\$local_min_acro_length = 3;\n\n";
+	print ACRONYM_HANDLE "#minimum acronym length saving (raise to raise precision)\n";
+	print ACRONYM_HANDLE "\$local_min_length_saving = 4;\n\n";
+	print ACRONYM_HANDLE "#allow recusive acronyms (0 = false (high precision), 1 = true)\n";
+	print ACRONYM_HANDLE "\$local_allow_recursive = 0;\n\n";
+	print ACRONYM_HANDLE "#stop words-words allowed in acronyms (the multi-lingual version\n";
+	print ACRONYM_HANDLE "#slows down acronym extraction slightly so is not the default)\n";
+	print ACRONYM_HANDLE "#\@local_stop_words = split / /, \"A OF AT THE IN TO AND VON BEI DER DIE DAS DEM DEN DES UND DE DU A LA LE LES L DANS ET S\";\n";
+	print ACRONYM_HANDLE "\@local_stop_words = split / /, \"OF AT THE IN TO AND\";\n"; 
+	print ACRONYM_HANDLE "\n"; 
+	print ACRONYM_HANDLE "#the file to collate acronyms into\n";
+	print ACRONYM_HANDLE "\$local_acronym_accumulate_file = \$ENV{'GSDLCOLLECTDIR'} . \"/etc/acronym_definitions.pm\";\n";
+	print ACRONYM_HANDLE "\n";
+	print ACRONYM_HANDLE "# any acronym definitions which should always be marked up can be copied here\n";
+	print ACRONYM_HANDLE "# from the acronym_accumulate_file file ...\n";
+	print ACRONYM_HANDLE "# \n";
+	print ACRONYM_HANDLE "# \n";
+	print ACRONYM_HANDLE "# \n";
+	print STDERR "written new options file to $acronym_options_file...\n";
+    } else {
+	print STDERR "read file $acronym_options_file...\n";
+	eval $file_text ;
+	warn $@ if $@;
+	print STDERR "evaluated file $acronym_options_file...\n";
+    }
+
+    $max_offset = $local_max_offset;
+    $upper_case = $local_upper_case;
+    $case_match = $local_case_match ;
+    $min_def_length = $local_min_def_length;
+    $min_acro_length = $local_min_acro_length;
+    $min_length_saving = $local_min_length_saving;
+    $allow_recursive = $local_allow_recursive;
+    $allow_all_caps = $local_allow_all_caps;
+    @stop_words = @local_stop_words;
+    
+    $local_acronym_accumulate_file = $local_acronym_accumulate_file;
+    
+
+    &read_all_acronyms_from_file();
+#    rename $acronym_file, $acronym_file . "." . int(rand (2<<7)). 
+#	int(rand (2<<7)). int(rand (2<<7)). int(rand (2<<7));
+    if ($writing_acronyms && open ACRONYM_HANDLE, ">$acronym_accumulate_file")
+    {
+	print ACRONYM_HANDLE "#This is an automatically generated file.\n";
+	print ACRONYM_HANDLE "#\n";
+	print ACRONYM_HANDLE "#If you edit this file and it will be overwritten the next\n";
+	print ACRONYM_HANDLE "#time the acronym code runs unless you set the file to \n";
+	print ACRONYM_HANDLE "#read-only. \n";
+	print ACRONYM_HANDLE "#\n";
+	print ACRONYM_HANDLE "#start of acronyms...\n";
+	$writing_acronyms = 1;
+    } else {
+	warn "failed to open $acronym_accumulate_file for writing\n";
+	$writing_acronyms = 0;
+    }
+}
+
+#close the list of accumulated acronyms
+sub finalise_acronyms {
+    if ($writing_acronyms)
+    {
+	print ACRONYM_HANDLE "#end of acronyms.\n";  
+	close ACRONYM_HANDLE;
+    }
+}
+
+#eval a file of accumulated acronyms
+sub read_all_acronyms_from_file {
+    
+    my $file_text = " ";
+    if (open ACRONYM_HANDLE, "<$acronym_accumulate_file")
+    {
+	$file_text = do { local $/; <ACRONYM_HANDLE> };  
+    } else {
+	print STDERR "failed to open $acronym_accumulate_file for reading (this is the first pass?).\n";
+    }
+    eval $file_text;
+    #promotes warnings/errors from evaluated file to current context 
+    warn $@ if $@;
+}
+
+#called from within the file of accumulated acronyms to indicate a good acronym
+sub add {
+    my $self = shift (@_);
+    if (defined ($acronyms_found_in_collection{$self->[0]}))
+    {
+	my $def = $self->to_def_string();
+	if ($acronyms_found_in_collection{$self->[0]} =~ m/(^|\|)$def(\||$)/)
+	{
+	    return;
+	}
+	$acronyms_found_in_collection{$self->[0]} = 
+	    $acronyms_found_in_collection{$self->[0]} . "|" . $self->to_def_string();
+    } else {
+	$acronyms_found_in_collection{$self->[0]} = $self->to_def_string();
+    }
+}
+
+#called from within the file of accumulated acronyms to indicate a bad acronym
+sub ban {
+    my $self = shift (@_);
+    
+    if (!defined $acronyms_banned_from_collection{$self->[0]})
+    {
+	$acronyms_banned_from_collection{$self->[0]} = $self->to_def_string();
+    } else {
+	$acronyms_banned_from_collection{$self->[0]} = $acronyms_banned_from_collection{$self->[0]} . "|" . $self->to_def_string();
+    }
+}
+
+
+#write a good acronym to the accumulated acronyms file
+sub write_to_file {
+    my $self = shift (@_);
+    if ($writing_acronyms)
+    {
+	print ACRONYM_HANDLE "new acronym(\"$self->[0]\",\"" . 
+	    $self->to_def_string() . 
+		"\")->add();\n";
+    }
+}
+
+
+###########################################################################
+# mark functionality    
+###########################################################################
+
+#small routine to sort by length 
+sub sort_by_length {
+    length($b) <=> length($a) or $a cmp $b
+}
+
+sub markup_acronyms {
+    my  $text = shift (@_);
+    my  $verbosity_obj = shift (@_);
+    if (defined $text)
+    {
+	for my $acro (sort sort_by_length keys %acronyms_found_in_collection)
+	{
+	    $text  =~ s/^((?:[^\<\n]|(?:\<[^\>\n]*\>))*)$acro([^\<A-Z])/$1$acro\<img src=\"\" width=8 height=8 alt=\"$acronyms_found_in_collection{$acro}\"\>$2/gm;
+	    printf STDERR " " .  $acro . ","
+		if ($verbosity_obj->{'verbosity'} >= 2);
+	}
+    }
+    return $text;
+}
+
+
+
+###########################################################################
+#    member functions 
+###########################################################################
+
+
+sub new {
+    my $trash = shift (@_); 
+    my $acro = shift (@_); 
+    my $def  = shift (@_); 
+    
+    my $self = [
+		"", # 0 acronym
+		[], # 1 definition
+               ];
+    
+    $self->[0] = $acro                    if defined $acro;
+    push @{$self->[1]},  split / /, $def  if defined $def;
+    
+    bless $self;
+}
+
+sub clone  {
+    my $self = shift (@_);
+
+    my $copy = new acronym;
+
+    $copy->[0] = $self->[0];
+    push @{$copy->[1]}, @{$self->[1]};
+    bless $copy;
+
+    return $copy;
+}
+
+#return the acronym
+sub to_acronym {
+    my $self = shift (@_);
+    my @array = @{$self->[1]};
+
+    return $self->[0];
+}
+
+#return the number of words in the acronym definition
+sub words_in_acronym_definition {
+    my $self = shift (@_);
+    my @array = @{$self->[1]};
+
+    return $#array + 1;
+}
+
+#return the number of letters in the acronym definition
+sub letters_in_acronym_definition {
+    my $self = shift (@_);
+
+    return length($self->to_def_string());
+}
+
+#return the number of letters in the acronym definition
+sub letters_in_acronym {
+    my $self = shift (@_);
+
+    return length($self->to_acronym());
+}
+
+#return the acronym definition
+sub to_def_string {
+    my $self = shift (@_);
+
+    my $result = "";
+
+    # do the definition
+    my @array = @{$self->[1]};
+    my $i = 0;
+    while ($i <= $#array)
+    {
+	$result = $result . $array[$i];
+
+	if ($i+1 <= $#array)
+	{
+	    $result = $result . " ";
+	}
+	$i++;
+    }
+    return $result;
+}
+
+
+#print out the kwic for the acronym
+sub to_string_kwic {
+    my $self = shift (@_);
+
+    # the list of all possible combinations
+    my @list = ();
+
+    my $result = "";
+
+    my $j = 0;
+    my @array = @{$self->[1]};
+    while ($j <= $#array)
+    {
+
+	# do the definition
+	my $i = 0;
+
+	#add the key word
+	$result = "<td halign=left>"  . $array[$j] . "</td><td halign=right>";
+
+	#add the proceeding words
+	while ($i < $j)
+	{
+	    $result = $result .  $array[$i] . " ";
+	    $i++;
+	}
+	#add the key word
+	$result = $result . "</td><td halign=left>"  . $array[$j] . 
+	    "</td><td halign=left>";
+
+	#add the trailing words
+	$i++;
+	while ($i <= $#array )
+	{
+	    $result = $result .  $array[$i] . " ";
+	    $i++;
+	}
+
+	#add the actual acronym
+
+	$result = $result . "</td><td halign=left>" . $self->[0] . "</td>";
+
+	push @list, $result;
+	$j++;
+    }
+    return @list;
+}
+
+#this is the one used when building the collection ...
+sub to_string {
+    my $self = shift (@_);
+
+    my $result = $self->[0] . " ";
+
+    # do the definition
+    my @array = @{$self->[1]};
+    my $i = 0;
+    while ($i <= $#array)
+    {
+	$result = $result . $array[$i];
+	if ($i+1 <= $#array)
+	{
+	    $result = $result . " ";
+	}
+	$i++;
+    }
+    return $result;
+}
+
+sub check {
+    my $self = shift (@_);
+
+    if (length($self->to_acronym()) < $min_acro_length) 
+    {
+#	print "acronym " . $self->to_string() . " rejected (too short I)\n";
+	return 0;
+    }
+    if ($self->words_in_acronym_definition() < $min_def_length) 
+    {
+#	print "acronym " . $self->to_string() . " rejected (too short II)\n";
+	return 0;
+    }
+    if ($min_length_saving * $self->letters_in_acronym() > 
+	$self->letters_in_acronym_definition()) 
+    {
+#	print "acronym " . $self->to_string() . " rejected (too short III)\n";
+#	print "" . $min_length_saving .
+#	    "|" . $self->letters_in_acronym() .
+#	    "|" . $self->letters_in_acronym_definition() . "\n";
+	return 0;
+    }
+    if (!$allow_all_caps && 
+	$self->to_def_string() eq uc($self->to_def_string()))
+    {
+#	print "acronym " . $self->to_string() . " rejected (all upper)\n";
+	return 0;
+    }
+    if (!$allow_all_caps)
+    {
+	my $upper_count = 0;
+	my $lower_count = 0;
+	my @letters = $self->to_def_string();
+	for my $letter (split //, $self->to_def_string())
+	{
+	    if ($letter eq uc($letter))
+	    { 
+		$upper_count++;
+	    } else {
+		$lower_count++;
+	    }		
+	}
+	return 0 if ($upper_count > $lower_count);
+    }
+    if (!$allow_recursive && $self->to_def_string() =~ /$self->to_acronym()/i )
+    {
+	return 0;
+    }
+#    print "acronym " . $self->to_string() . " not rejected\n";
+    return 1;
+}
+
+###########################################################################
+#    static functions 
+###########################################################################
+
+sub recurse {
+    my ($acro_offset,       #offset of word we're finding acronyms for
+	$text_offset,       
+	$letter_offset, 
+	@def_so_far) = @_;
+
+    my $word = $split_text[$text_offset];
+    my $acro = $split_text[$acro_offset];
+    $word = "" if !defined $word;
+    $acro = "" if !defined $acro;
+    
+#    print "recurse(" . $acro_offset . ", " . $text_offset . ", " . 
+#	$letter_offset  . ", " . @def_so_far . ")\n";
+
+    #check for termination ...
+    if ($letter_offset >= length($acro))
+    {	
+	my $acronym = new acronym();
+	$acronym->[0] = $acro;
+	push @{$acronym->[1]}, @def_so_far;
+	if ($acronym->check())
+	{
+	    push @acronym_list, ( $acronym );
+	}
+#	print "acronym created\n";
+	return;
+    }
+    #check for recursion
+    if (!$allow_recursive)
+    {
+	if ($word eq $acro)
+	{
+#	    print "recursion detected\n";
+	    return;
+	}
+    }
+    
+    #skip a stop-word
+    my $i = 0;
+    if ($letter_offset != 0)
+    {
+	while ($i <= $#stop_words)
+	{
+	    if ($stop_words[$i] eq uc($word))
+	    {
+#	    print "::found stop word::" . $stop_words[$i] . "\n";
+		&recurse($acro_offset,
+			 $text_offset+1,
+			 $letter_offset,
+			 @def_so_far, $word);
+	    }
+	    $i++;
+	}
+    }
+    $i = 1;
+    #using the first $i letters ...
+    while ($letter_offset+$i <= length($acro) )
+    {
+#	print "". ((substr $word, 0, $i) . " " . 
+#	    (substr $acro, $letter_offset, $i) . "\n");
+	if (((!$case_match) &&
+	     (uc(substr $word, 0, $i) eq
+	      uc(substr $acro, $letter_offset, $i)))
+	    ||
+	    (($case_match) &&
+	     ((substr $word, 0, $i) eq
+	      (substr $acro, $letter_offset, $i))))
+	{
+#	    print "::match::\n";
+#	    print "" . ((substr $word, 0, $i) . " " . 
+#		   (substr $acro, $letter_offset, $i) . "\n");
+	    &recurse($acro_offset,
+		     $text_offset+1,
+		     $letter_offset+$i,
+		     @def_so_far, $word);
+	} else {
+	    return;
+	}	    
+	$i++;
+    }
+    return;
+}
+
+#the main
+sub acronyms {
+    #clean up the text
+    my $processed_text =  shift @_;
+    $$processed_text =~ s/<[^>]*>/ /g;
+    $$processed_text =~ s/\W/ /g;
+    $$processed_text =~ s/[0-9_]/ /g;
+    $$processed_text =~ s/\s+/ /g;
+    $$processed_text =~ s/(\n|\>)References.*/ /i;
+    $$processed_text =~ s/(\n|\>)Bibliography.*/ /i;
+    $$processed_text =~ s/(\n|\>)(Cited Works?).*/ /i;
+    $$processed_text =~ s/(\n|\>)(Works? Cited).*/ /i;
+
+    #clear some global variables
+    @split_text = ();
+    @acronym_list = ();
+
+    return &acronyms_from_clean_text($processed_text);
+}
+
+sub acronyms_from_clean_text {
+    my ($processed_text) = @_;
+
+    @split_text = split / /, $$processed_text;
+
+#    my $i = 0;
+#    while ($i <= $#split_text)
+#    {
+#	print $split_text[$i] . "\n";
+#	$i++;
+#    }
+
+    my $first = 0;
+    my $last = $#split_text +1;
+    my $acro_counter = $first;
+    
+    while ($acro_counter < $last)
+    {
+	my $word = $split_text[$acro_counter];
+
+	if ((!$upper_case) ||
+	    (uc($word) eq $word))
+	{
+	    
+	    if (length $word >= $min_acro_length)
+	    {
+		my $def_counter = 0;
+		if ($acro_counter - $max_offset > 0)
+		{
+		    $def_counter = $acro_counter - $max_offset;
+		}
+		my $local_last = $acro_counter  + $max_offset;
+		if ($local_last > $last)
+		{
+		    $local_last = $last;
+		}
+		while ($def_counter <= $local_last)
+		{
+		    &recurse($acro_counter,$def_counter,0,());
+		    $def_counter++;
+		}
+	    }
+	}
+	$acro_counter++;
+    }
+
+    return \@acronym_list;
+}
+
+
+
+sub test {
+
+#    my $blarg = new acronym();
+#    my $simple;
+#    $simple = 10;
+#    $blarg->initialise($simple, $simple, $simple);
+#    my $blarg2 = $blarg->clone();
+#    print $blarg->to_string();
+#    print $blarg2;
+#    print "\n";
+#    
+    my $tla = new acronym();
+    $tla->[0] = "TLA";
+
+    my @array = ("Three", "Letter", "Acronym");
+#    my $i = 0;
+#    while ($i <= $#array)
+#    {
+#	print @array[$i] . "\n";
+#	$i++;
+#    }
+
+    print "\n";
+    push @{$tla->[1]}, ("Three" );
+    push @{$tla->[1]}, ("Letter" );
+    push @{$tla->[1]}, ("Acronym" );
+    print $tla->to_string(). "\n";
+    print "\n";
+    print "\n";
+    my $tla2 = $tla->clone();
+    push @{$tla2->[1]}, ("One");
+    push @{$tla2->[1]}, ("Two");
+    $tla2->[0] = "ALT";
+    print $tla->to_string(). "\n";
+    print $tla2->to_string(). "\n";
+
+    print "\n";
+    print "\n";
+
+    print "Testing recursion ...\n";
+    my $acros = &acronyms("TLA Three Letter Acronym in tla TlA");
+    
+    foreach my $acro (@$acros)
+    {
+	if ($acro->check)
+        {
+           print "accepted: " .$acro->to_string() . "\n";
+#           print "|" .  $acro->to_acronym() . "|" .  $acro->to_def_string() .
+#              "|" .  $acro->words_in_acronym_definition() .
+#              "|" .  $acro->letters_in_acronym_definition() . 
+#              "|" .  $acro->letters_in_acronym() . "|\n";
+        } else {
+#          print "found but rejected: " .$acro->to_string() . "\n";
+        }
+    }
+}
+
+#uncomment this line to test this package
+#&test();
+
+1;
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/arcinfo.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/arcinfo.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/arcinfo.pm	(revision 10506)
@@ -0,0 +1,226 @@
+###########################################################################
+#
+# arcinfo.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# This module stores information about the archives. At the moment
+# this information just consists of the file name (relative to the
+# directory the archives information file is in) and its OID.
+
+# This module assumes there is a one to one correspondance between
+# a file in the archives directory and an OID.
+
+
+package arcinfo;
+
+use constant ORDER_OID_INDEX  => 0;
+use constant ORDER_SORT_INDEX => 1;
+
+use constant INFO_FILE_INDEX    => 0;
+use constant INFO_STATUS_INDEX  => 1;
+
+# File format read in: OID <tab> Filename <tab> Optional-Index-Status
+
+# Index status can be:
+#  I = Index for the first time
+#  R = Reindex
+#  D = Delete
+#  B = Been indexed
+
+sub new {
+    my ($class) = @_;
+    my $self = {'info'=>{},
+		'order'=>[]};
+
+    return bless $self, $class;
+}
+
+sub load_info {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    $self->{'info'} = {};
+ 
+    if (-e $filename) {
+	open (INFILE, $filename) || 
+	    die "arcinfo::load_info couldn't read $filename\n";
+
+	my ($line, @line);
+	while (defined ($line = <INFILE>)) {
+	    $line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	    @line = split ("\t", $line); # filename, 
+	    if (scalar(@line) >= 2) {
+		$self->add_info (@line);
+	    }
+	}
+	close (INFILE);
+    }
+}
+
+sub save_info {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    my ($OID, $info);
+
+    open (OUTFILE, ">$filename") || 
+	die "arcinfo::save_info couldn't write $filename\n";
+  
+    foreach $info (@{$self->get_OID_list()}) {
+	if (defined $info) {
+	    print OUTFILE join("\t", @$info), "\n";
+	}
+    }
+    close (OUTFILE);
+}
+
+sub delete_info {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    if (defined $self->{'info'}->{$OID}) {
+	delete $self->{'info'}->{$OID};
+	
+	my $i = 0;
+	while ($i < scalar (@{$self->{'order'}})) {
+	    if ($self->{'order'}->[$i]->[ORDER_OID_INDEX] eq $OID) {
+		splice (@{$self->{'order'}}, $i, 1);
+		last;
+	    }
+	    
+	    $i ++;
+	}
+    }
+}
+
+sub add_info {
+    my $self = shift (@_);
+    my ($OID, $doc_file, $index_status, $sortmeta) = @_;
+    $sortmeta = "" unless defined $sortmeta;
+    $index_status = "I" unless defined $index_status; # I = needs indexing
+
+    if (! defined($OID)) {
+	# only happens when no files can be processed?
+	return undef;
+    }
+
+    $self->delete_info ($OID);
+    $self->{'info'}->{$OID} = [$doc_file,$index_status];
+    push (@{$self->{'order'}}, [$OID, $sortmeta]);
+}
+
+sub set_status_info {
+    my $self = shift (@_);
+    my ($OID, $index_status) = @_;
+
+    my $OID_info = $self->{'info'}->{$OID};
+    $OID_info->[INFO_STATUS_INDEX] = $index_status;
+}
+
+
+sub get_status_info {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    my $index_status = undef;
+
+    my $OID_info = $self->{'info'}->{$OID};
+    if (defined $OID_info) {
+	$index_status = $OID_info->[INFO_STATUS_INDEX];
+    }
+    else {
+	die "Unable to find document id $OID\n";
+    }
+
+    return $index_status;
+
+}
+
+
+# returns a list of the form [[OID, doc_file, index_status], ...]
+sub get_OID_list 
+{
+    my $self = shift (@_);
+
+    my $order = $self->{'order'};
+
+    my @sorted_order 
+	= sort {$a->[ORDER_SORT_INDEX] cmp $b->[ORDER_SORT_INDEX]} @$order;
+
+    my @list = ();
+
+    foreach my $OID_order (@sorted_order) {
+	my $OID = $OID_order->[ORDER_OID_INDEX];
+	my $OID_info = $self->{'info'}->{$OID};
+
+	push (@list, [$OID, $OID_info->[INFO_FILE_INDEX], 
+		      $OID_info->[INFO_STATUS_INDEX]]);
+    }
+
+    return \@list;
+}
+
+# returns a list of the form [[doc_file, OID], ...]
+sub get_file_list {
+    my $self = shift (@_);
+
+    my $order = $self->{'order'};
+
+    my @sorted_order 
+	= sort {$a->[ORDER_SORT_INDEX] cmp $b->[ORDER_SORT_INDEX]} @$order;
+
+    my @list = ();
+
+    foreach $OID_order (@sorted_order) {
+	my $OID = $OID_order->[ORDER_OID_INDEX];
+	my $OID_info = $self->{'info'}->{$OID};
+
+	push (@list, [$OID_info->[INFO_FILE_INDEX], $OID]);
+    }
+
+    return \@list;
+}
+
+
+# returns a list of the form [doc_file]
+sub get_info {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    if (defined $self->{'info'}->{$OID}) {
+	return $self->{'info'}->{$OID};
+    }
+
+    return undef;
+}
+
+
+# returns the number of documents so far
+sub size {
+    my $self = shift (@_);
+    return (scalar(@{$self->{'order'}}));
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/basebuilder.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/basebuilder.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/basebuilder.pm	(revision 10506)
@@ -0,0 +1,625 @@
+###########################################################################
+#
+# basebuilder.pm -- base class for collection builders
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package basebuilder;
+
+use classify;
+use cfgread;
+use colcfg;
+use plugin;
+use util;
+use FileHandle;
+
+BEGIN {
+    # set autoflush on for STDERR and STDOUT so that mgpp
+    # doesn't get out of sync with plugins
+    STDOUT->autoflush(1);
+    STDERR->autoflush(1);
+}
+
+END {
+    STDOUT->autoflush(0);
+    STDERR->autoflush(0);
+}
+
+our $maxdocsize = 12000;
+
+sub new {
+    my ($class, $collection, $source_dir, $build_dir, $verbosity, 
+	$maxdocs, $debug, $keepold, $remove_empty_classifications, 
+	$outhandle, $no_text, $failhandle, $gli) = @_;
+
+    $outhandle = STDERR unless defined $outhandle;
+    $no_text = 0 unless defined $no_text;
+    $failhandle = STDERR unless defined $failhandle;
+
+    # create a builder object
+    my $self = bless {'collection'=>$collection,
+		      'source_dir'=>$source_dir,
+		      'build_dir'=>$build_dir,
+		      'verbosity'=>$verbosity,
+		      'maxdocs'=>$maxdocs,
+		      'debug'=>$debug,
+		      'keepold'=>$keepold,
+		      'remove_empty_classifications'=>$remove_empty_classifications,
+		      'outhandle'=>$outhandle,
+		      'no_text'=>$no_text,
+		      'failhandle'=>$failhandle,
+		      'notbuilt'=>{},    # indexes not built
+		      'gli'=>$gli
+		      }, $class;
+
+    $self->{'gli'} = 0 unless defined $self->{'gli'};
+
+    # read in the collection configuration file
+    my $colcfgname = "$ENV{'GSDLCOLLECTDIR'}/etc/collect.cfg";
+    if (!-e $colcfgname) {
+	die "mgbuilder::new - couldn't find collect.cfg for collection $collection\n";
+    }
+    $self->{'collect_cfg'} = &colcfg::read_collect_cfg ($colcfgname);
+    
+    # get the list of plugins for this collection
+    my $plugins = [];
+    if (defined $self->{'collect_cfg'}->{'plugin'}) {
+	$plugins = $self->{'collect_cfg'}->{'plugin'};
+    }
+    
+    # load all the plugins
+
+    #build up the extra global options for the plugins
+    my @global_opts = ();
+    if (defined $self->{'collect_cfg'}->{'separate_cjk'} && $self->{'collect_cfg'}->{'separate_cjk'} =~ /^true$/i) {
+	push @global_opts, "-separate_cjk";
+    }
+    $self->{'pluginfo'} = &plugin::load_plugins ($plugins, $verbosity, $outhandle, $failhandle, \@global_opts, $keepold);
+   
+    if (scalar(@{$self->{'pluginfo'}}) == 0) {
+	print $outhandle "No plugins were loaded.\n";
+	die "\n";
+    }
+
+    # get the list of classifiers for this collection
+    my $classifiers = [];
+    if (defined $self->{'collect_cfg'}->{'classify'}) {
+	$classifiers = $self->{'collect_cfg'}->{'classify'};
+    }
+    
+    # load all the classifiers
+    $self->{'classifiers'} = &classify::load_classifiers ($classifiers, $build_dir, $outhandle);
+
+    # load up any dontgdbm fields
+    $self->{'dontgdbm'} = {};
+    if (defined ($self->{'collect_cfg'}->{'dontgdbm'})) {
+	foreach my $dg (@{$self->{'collect_cfg'}->{'dontgdbm'}}) {
+	    $self->{'dontgdbm'}->{$dg} = 1;
+	}
+    }
+
+    return $self;
+}
+
+# stuff has been moved here from new, so we can use subclass methods
+sub init {
+    my $self = shift(@_);
+    
+    $self->generate_index_list();
+    
+    # sort out subcollection indexes
+    if (defined $self->{'collect_cfg'}->{'indexsubcollections'}) {
+	my $indexes = $self->{'collect_cfg'}->{'indexes'};
+	$self->{'collect_cfg'}->{'indexes'} = [];
+	foreach my $subcollection (@{$self->{'collect_cfg'}->{'indexsubcollections'}}) {
+	    foreach my $index (@$indexes) {
+		push (@{$self->{'collect_cfg'}->{'indexes'}}, "$index:$subcollection");
+	    }
+	}
+    }
+
+    # sort out language subindexes
+    if (defined $self->{'collect_cfg'}->{'languages'}) {
+	my $indexes = $self->{'collect_cfg'}->{'indexes'};
+	$self->{'collect_cfg'}->{'indexes'} = [];
+	foreach my $language (@{$self->{'collect_cfg'}->{'languages'}}) {
+	    foreach my $index (@$indexes) {
+		if (defined ($self->{'collect_cfg'}->{'indexsubcollections'})) {
+		    push (@{$self->{'collect_cfg'}->{'indexes'}}, "$index:$language");
+		}
+		else { # add in an empty subcollection field
+		    push (@{$self->{'collect_cfg'}->{'indexes'}}, "$index\:\:$language");
+		}
+	    }
+	}
+    }
+
+    if (defined($self->{'collect_cfg'}->{'indexes'})) {
+	# make sure that the same index isn't specified more than once
+	my %tmphash = ();
+	my @tmparray = @{$self->{'collect_cfg'}->{'indexes'}};
+	$self->{'collect_cfg'}->{'indexes'} = [];
+	foreach my $i (@tmparray) {
+	    if (!defined ($tmphash{$i})) {
+		push (@{$self->{'collect_cfg'}->{'indexes'}}, $i);
+		$tmphash{$i} = 1;
+	    }
+	}
+    } else {
+	$self->{'collect_cfg'}->{'indexes'} = [];
+    }
+
+    # load up the document processor for building
+    # if a buildproc class has been created for this collection, use it
+    # otherwise, use the mg buildproc
+    my ($buildprocdir, $buildproctype);
+    my $collection = $self->{'collection'};
+    if (-e "$ENV{'GSDLCOLLECTDIR'}/perllib/${collection}buildproc.pm") {
+	$buildprocdir = "$ENV{'GSDLCOLLECTDIR'}/perllib";
+	$buildproctype = "${collection}buildproc";
+    } else {
+	$buildprocdir = "$ENV{'GSDLHOME'}/perllib";
+	$buildproctype = $self->default_buildproc();
+    }
+    require "$buildprocdir/$buildproctype.pm";
+
+    eval("\$self->{'buildproc'} = new $buildproctype(\$collection, " .
+	 "\$source_dir, \$build_dir, \$keepold, \$verbosity, \$outhandle)");
+    die "$@" if $@;
+
+    if (!$self->{'debug'} && !$self->{'keepold'}) {
+	# remove any old builds
+	&util::rm_r($self->{'build_dir'});
+	&util::mk_all_dir($self->{'build_dir'});
+        
+	# make the text directory
+	my $textdir = "$self->{'build_dir'}/text";
+	&util::mk_all_dir($textdir);
+    }
+    
+}
+
+sub deinit {
+    my $self = shift (@_);
+    
+    &plugin::deinit($self->{'pluginfo'},$self->{'buildproc'});
+}
+
+sub set_sections_index_document_metadata {
+    my $self = shift (@_);
+    my ($index) = @_;
+  
+    $self->{'buildproc'}->set_sections_index_document_metadata($index);
+}
+
+sub set_strip_html {
+    my $self = shift (@_);
+    my ($strip) = @_;
+    
+    $self->{'strip_html'} = $strip;
+    $self->{'buildproc'}->set_strip_html($strip);
+}
+
+sub compress_text {
+    my $self = shift (@_);
+    my ($textindex) = @_;
+
+    print STDERR "compress_text() should be implemented in subclass!!";
+    return;
+}
+
+
+sub build_indexes {
+    my $self = shift (@_);
+    my ($indexname) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $indexes = [];
+    if (defined $indexname && $indexname =~ /\w/) {
+	push @$indexes, $indexname;
+    } else {
+	$indexes = $self->{'collect_cfg'}->{'indexes'};
+    }
+
+    # create the mapping between the index descriptions 
+    # and their directory names (includes subcolls and langs)
+    $self->{'index_mapping'} = $self->create_index_mapping ($indexes);
+
+    # build each of the indexes
+    foreach my $index (@$indexes) {
+	if ($self->want_built($index)) {
+	    print $outhandle "\n*** building index $index in subdirectory " . 
+		"$self->{'index_mapping'}->{$index}\n" if ($self->{'verbosity'} >= 1);
+	    print STDERR "<Stage name='Index' source='$index'>\n" if $self->{'gli'};
+	    $self->build_index($index);
+	} else {
+	    print $outhandle "\n*** ignoring index $index\n" if ($self->{'verbosity'} >= 1);
+	}
+    }
+
+    $self->build_indexes_extra();
+
+}
+
+sub build_indexes_extra {
+    my $self = shift(@_);
+    
+}
+
+sub build_index {
+    my $self = shift (@_);
+    my ($index) = @_;
+    
+    print STDERR "build_index should be implemented in subclass\n";
+    return;
+}
+
+sub make_infodatabase {
+    my $self = shift (@_);
+    my $outhandle = $self->{'outhandle'};
+
+    my $textdir = &util::filename_cat($self->{'build_dir'}, "text");
+    my $assocdir = &util::filename_cat($self->{'build_dir'}, "assoc");
+    &util::mk_all_dir ($textdir);
+    &util::mk_all_dir ($assocdir);
+
+    # get db name
+    my $dbext = ".bdb";
+    $dbext = ".ldb" if &util::is_little_endian();
+    my $fulldbname = &util::filename_cat ($textdir, "$self->{'collection'}$dbext");
+    $fulldbname =~ s/\//\\/g if ($ENV{'GSDLOS'} =~ /^windows$/i);
+
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $exe = &util::get_os_exe ();
+    my $txt2db_exe = &util::filename_cat($exedir, "txt2db$exe");
+
+    print $outhandle "\n*** creating the info database and processing associated files\n" 
+	if ($self->{'verbosity'} >= 1);
+    print STDERR "<Stage name='CreateInfoData'>\n" if $self->{'gli'};
+
+    # init all the classifiers
+    &classify::init_classifiers ($self->{'classifiers'});
+    
+    # set up the document processor
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$txt2db_exe" || !open (PIPEOUT, "| txt2db$exe \"$fulldbname\"")) {
+	    print STDERR "<FatalError name='NoRunText2DB'/>\n</Stage>\n" if $self->{'gli'};
+	    die "builder::make_infodatabase - couldn't run $txt2db_exe\n";
+	}
+	$handle = basebuilder::PIPEOUT;
+    }
+    
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('infodb');
+    $self->{'buildproc'}->set_assocdir ($assocdir);
+    $self->{'buildproc'}->set_dontgdbm ($self->{'dontgdbm'});
+    $self->{'buildproc'}->set_classifiers ($self->{'classifiers'});
+    $self->{'buildproc'}->set_indexing_text (0);
+    $self->{'buildproc'}->set_store_text(1);
+    # make_infodatabase does not support incremental build 
+    # => full reset needed
+    $self->{'buildproc'}->zero_reset();
+   
+    # do we need this anymore if we get coll meta from config file??
+    $self->output_collection_meta($handle);
+
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'},0, $self->{'gli'});
+    
+    # output classification information
+    &classify::output_classify_info ($self->{'classifiers'}, $handle,
+				     $self->{'remove_empty_classifications'}, 
+				     $self->{'gli'});
+
+
+    #output doclist
+    my @doclist = $self->{'buildproc'}->get_doc_list();
+    my $docs = join (";",@doclist);
+    print $handle "[browselist]\n";
+    print $handle "<hastxt>0\n";
+    print $handle "<childtype>VList\n";
+    print $handle "<numleafdocs>" . ($#doclist+1) . "\n";
+    print $handle "<thistype>Invisible\n";
+    print $handle "<contains>$docs";
+    print $handle "\n" . ('-' x 70) . "\n";
+
+    close ($handle) if !$self->{'debug'};
+
+    print STDERR "</Stage>\n" if $self->{'gli'};
+}
+
+sub make_auxiliary_files {
+    my $self = shift (@_);
+    my ($index);
+    my $build_cfg = {};
+    # subclasses may have already defined stuff in here
+    if (defined $self->{'build_cfg'}) {
+	$build_cfg = $self->{'build_cfg'};
+    }
+
+    my $outhandle = $self->{'outhandle'};
+
+    print $outhandle "\n*** creating auxiliary files \n" if ($self->{'verbosity'} >= 1);
+    print STDERR "<Stage name='CreatingAuxilary'>\n" if $self->{'gli'};
+
+    # get the text directory
+    &util::mk_all_dir ($self->{'build_dir'});
+
+    # store the build date
+    $build_cfg->{'builddate'} = time;
+    $build_cfg->{'buildtype'} = $self->{'buildtype'};
+    $build_cfg->{'indexstem'} = $self->{'collection'};
+    # store the number of documents and number of bytes
+    $build_cfg->{'numdocs'} = $self->{'buildproc'}->get_num_docs();
+    $build_cfg->{'numbytes'} = $self->{'buildproc'}->get_num_bytes();
+
+    
+    # store the mapping between the index names and the directory names
+    # the index map is used to determine what indexes there are, so any that are not built should not be put into the map.
+    my @indexmap = ();
+    foreach my $index (@{$self->{'index_mapping'}->{'indexmaporder'}}) {
+	if (not defined ($self->{'notbuilt'}->{$index})) {
+	    push (@indexmap, "$index\-\>$self->{'index_mapping'}->{'indexmap'}->{$index}");
+	}
+    }
+    $build_cfg->{'indexmap'} = \@indexmap;
+
+    my @subcollectionmap = ();
+    foreach my $subcollection (@{$self->{'index_mapping'}->{'subcollectionmaporder'}}) {
+	push (@subcollectionmap, "$subcollection\-\>" .
+	      $self->{'index_mapping'}->{'subcollectionmap'}->{$subcollection});
+    }
+    $build_cfg->{'subcollectionmap'} = \@subcollectionmap if scalar (@subcollectionmap);
+
+    my @languagemap = ();
+    foreach my $language (@{$self->{'index_mapping'}->{'languagemaporder'}}) {
+	push (@languagemap, "$language\-\>" .
+	      $self->{'index_mapping'}->{'languagemap'}->{$language});
+    }
+    $build_cfg->{'languagemap'} = \@languagemap if scalar (@languagemap);
+
+    my @notbuilt = ();
+    foreach my $nb (keys %{$self->{'notbuilt'}}) {
+	push (@notbuilt, $nb);
+    }
+    $build_cfg->{'notbuilt'} = \@notbuilt if scalar (@notbuilt);
+
+    $build_cfg->{'maxnumeric'} = 4;
+    if (defined($self->{'collect_cfg'}->{'maxnumeric'}) &&
+	$self->{'collect_cfg'}->{'maxnumeric'} =~ /^\d+$/) {
+	$build_cfg->{'maxnumeric'} = $self->{'collect_cfg'}->{'maxnumeric'};
+    }
+
+    $self->build_cfg_extra($build_cfg);
+    
+    $self->write_cfg_file($build_cfg);
+    print STDERR "</Stage>\n" if $self->{'gli'};
+}
+
+sub collect_specific {
+    my $self = shift (@_);
+}
+
+sub want_built {
+    my $self = shift (@_);
+    my ($index) = @_;
+
+    if (defined ($self->{'collect_cfg'}->{'dontbuild'})) {
+	foreach my $checkstr (@{$self->{'collect_cfg'}->{'dontbuild'}}) {
+	    if ($index =~ /^$checkstr$/) {
+		$self->{'notbuilt'}->{$index} = 1;
+		return 0;
+	    }
+	}
+    }
+
+    return 1;
+}
+
+sub create_index_mapping {
+    my $self = shift (@_);
+    my ($indexes) = @_;
+
+    print STDERR "create_index_mapping should be implemented in subclass\n";
+    my %mapping = ();
+    return \%mapping;
+}
+
+# returns a processed version of a field.
+# if the field has only one component the processed
+# version will contain the first character and next consonant
+# of that componant - otherwise it will contain the first 
+# character of the first two components 
+sub process_field {
+    my $self = shift (@_);
+    my ($field) = @_;
+ 
+    return "" unless (defined ($field) && $field =~ /\w/);
+
+    my @components = split /,/, $field;
+    if (scalar @components >= 2) {
+	splice (@components, 2);
+	map {s/^(.).*$/$1/;} @components;
+	return join("", @components);
+    } else {
+	my ($a, $b) = $field =~ /^(.).*?([bcdfghjklmnpqrstvwxyz])/i;
+	($a, $b) = $field =~ /^(.)(.)/ unless defined $a && defined $b;
+	return "$a$b";
+    }
+}
+
+sub get_next_version {
+    my $self = shift (@_);
+    my ($nameref) = @_;
+    my $num=0;
+    if ($$nameref =~ /(\d\d)$/) {
+	$num = $1; $num ++;
+	$$nameref =~ s/\d\d$/$num/;
+    } elsif ($$nameref =~ /(\d)$/) {
+	$num = $1;
+	if ($num == 9) {$$nameref =~ s/\d$/10/;}
+	else {$num ++; $$nameref =~ s/\d$/$num/;}
+    } else {
+	$$nameref =~ s/.$/0/;
+    }
+}
+
+# implement this in subclass if want to add extra stuff to build.cfg
+sub build_cfg_extra {
+   my $self = shift(@_);
+   my ($build_cfg) = @_;
+   
+}
+
+sub write_cfg_file {
+    my $self = shift(@_);
+    my ($build_cfg) = @_;
+    
+    # write out the build information
+    &cfgread::write_cfg_file("$self->{'build_dir'}/build.cfg", $build_cfg,
+			     '^(builddate|buildtype|numdocs|numbytes|numwords|numsections|maxnumeric|indexstem)$', 
+                             '^(indexmap|subcollectionmap|languagemap|notbuilt)$');
+
+}
+
+
+sub output_collection_meta {
+    my $self = shift(@_);
+    my ($handle) = @_;
+    my $outhandle = $self->{'outhandle'};
+    if (defined $self->{'collect_cfg'}->{'collectionmeta'}) {
+	
+        if (!defined $self->{'index_mapping'}) {
+	    $self->{'index_mapping'} = 
+		$self->create_index_mapping ($self->{'collect_cfg'}->{'indexes'});
+	}
+	
+	print $handle "[collection]\n";
+     
+	foreach my $cmeta (keys (%{$self->{'collect_cfg'}->{'collectionmeta'}})) {
+	    my $defaultfound=0;
+	    my $first=1;
+	    my $metadata_entry = "";
+	    my $default="";
+	    my $cmetamap = "";
+	    if ($cmeta =~ s/^\.//) {
+    		if (defined $self->{'index_mapping'}->{$cmeta}) {
+		    $cmetamap = $self->{'index_mapping'}->{$cmeta};
+		    $cmeta = ".$cmeta";
+		}
+		else {
+		    print $outhandle "mgbuilder: warning bad collectionmeta option '$cmeta' - ignored\n";
+		    next; #ignore this one
+		}
+	    }
+	    else {
+		$cmetamap = $cmeta; # just using the same name
+	    }
+	    #iterate through the languages
+	    foreach my $lang (keys (%{$self->{'collect_cfg'}->{'collectionmeta'}->{$cmeta}})) {
+		if ($first) {
+		    $first=0;
+		    #set the default default to the first entry
+		    $default=$self->{'collect_cfg'}->{'collectionmeta'}->{$cmeta}->{$lang};
+		}
+		if ($lang =~ /default/) {
+		    $defaultfound=1;
+		    #the default entry goes first
+		    $metadata_entry = "<$cmetamap>" .
+			$self->{'collect_cfg'}->{'collectionmeta'}->{$cmeta}->{'default'} . "\n" . $metadata_entry;
+		}
+		else {
+		    my ($l) = $lang =~ /^\[l=(\w*)\]$/;
+		    if ($l) {
+			$metadata_entry .= "<$cmetamap:$l>" . 
+			    $self->{'collect_cfg'}->{'collectionmeta'}->{$cmeta}->{$lang} . "\n";
+
+			# Use the English value as the default if no default is specified
+			if ($l =~ /en/i) {
+			    $default=$self->{'collect_cfg'}->{'collectionmeta'}->{$cmeta}->{$lang};
+			}
+		    }
+		}
+	    }
+	    #if we haven't found a default, put one in
+	    if (!$defaultfound) {
+		$metadata_entry = "<$cmetamap>$default\n" . $metadata_entry;
+	    }
+	#write the entry to the file
+	print $handle $metadata_entry;
+
+	}
+	
+	print $handle "\n" . ('-' x 70) . "\n";
+    }
+    
+}
+  
+sub print_stats {
+    my $self = shift (@_);
+
+    my $outhandle = $self->{'outhandle'};
+    my $indexing_text = $self->{'buildproc'}->get_indexing_text();
+    my $index = $self->{'buildproc'}->get_index();
+    my $num_bytes = $self->{'buildproc'}->get_num_bytes();
+    my $num_processed_bytes = $self->{'buildproc'}->get_num_processed_bytes();
+
+    if ($indexing_text) {
+	print $outhandle "Stats (Creating index $index)\n";
+    } else {
+	print $outhandle "Stats (Compressing text from $index)\n";
+    }
+    print $outhandle "Total bytes in collection: $num_bytes\n";
+    print $outhandle "Total bytes in $index: $num_processed_bytes\n";
+
+    if ($num_processed_bytes < 50 && ($indexing_text || !$self->{'no_text'})) {
+	
+	if ($self->{'keepold'}) {
+	    if ($num_processed_bytes == 0) {
+		if ($indexing_text) {
+		    print $outhandle "No additional text was added to $index\n";
+		} elsif (!$self->{'no_text'}) {
+		    print $outhandle "No additional text was compressed\n";
+		}	
+	    }	
+	}
+	else {
+	    print $outhandle "***************\n";
+	    if ($indexing_text) {
+		print $outhandle "WARNING: There is very little or no text to process for $index\n";
+	    } elsif (!$self->{'no_text'}) {
+		print $outhandle "WARNING: There is very little or no text to compress\n";
+	    }	   
+	    print $outhandle "         Was this your intention?\n";
+	    print $outhandle "***************\n";
+	}
+
+    }
+
+}
+
+  
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/basebuildproc.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/basebuildproc.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/basebuildproc.pm	(revision 10506)
@@ -0,0 +1,596 @@
+###########################################################################
+#
+# basebuildproc.pm -- 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# This document processor outputs a document for indexing (should be 
+# implemented by subclass) and storing in gdbm database
+
+package basebuildproc;
+
+eval {require bytes};
+
+use classify;
+use doc;
+use docproc;
+use util;
+
+BEGIN {
+    @basebuildproc::ISA = ('docproc');
+}
+
+sub new {
+    my ($class, $collection, $source_dir, $build_dir, $keepold,
+	$verbosity, $outhandle) = @_; 
+    my $self = new docproc ();
+
+    # outhandle is where all the debugging info goes
+    # output_handle is where the output of the plugins is piped
+    # to (i.e. mg, gdbm etc.)
+    $outhandle = STDERR unless defined $outhandle;
+
+    $self->{'collection'} = $collection;
+    $self->{'source_dir'} = $source_dir;
+    $self->{'build_dir'}  = $build_dir;
+    $self->{'keepold'}    = $keepold;
+    $self->{'verbosity'}  = $verbosity;
+    $self->{'outhandle'}  = $outhandle;
+
+    $self->{'classifiers'} = [];
+    $self->{'mode'} = "text";
+    $self->{'assocdir'} = $build_dir;
+    $self->{'dontgdbm'} = {};
+
+    $self->{'index'} = "section:text";
+    $self->{'indexexparr'} = [];
+
+    my $found_num_data = 0;
+    my $buildconfigfile = undef;
+
+    if ($keepold) {
+	# For incremental building need to seed num_docs etc from values
+	# stored in build.cfg (if present)
+
+	$buildconfigfile = &util::filename_cat($build_dir, "build.cfg");
+
+	if (-e $buildconfigfile) {
+	    $found_num_data = 1;
+	}
+	else {
+	    # try the index dir
+	    $buildconfigfile = &util::filename_cat($ENV{'GSDLCOLLECTDIR'}, 
+						   "index", "build.cfg");
+	    if (-e $buildconfigfile) {
+		$found_num_data = 1;
+	    }
+	}
+
+    } 
+
+    if ($found_num_data) {
+	my $buildcfg = &colcfg::read_build_cfg($buildconfigfile);
+	
+	$self->{'starting_num_docs'}     = $buildcfg->{'numdocs'};
+	$self->{'starting_num_sections'} = $buildcfg->{'numsections'};
+	$self->{'starting_num_bytes'}    = $buildcfg->{'numbytes'};
+    }
+    else {
+	$self->{'starting_num_docs'}     = 0;
+	$self->{'starting_num_sections'} = 0;
+	$self->{'starting_num_bytes'}    = 0;
+    }
+
+    $self->{'output_handle'} = "STDOUT";
+    $self->{'num_docs'}      = $self->{'starting_num_docs'};
+    $self->{'num_sections'}  = $self->{'starting_num_sections'};
+    $self->{'num_bytes'}     = $self->{'starting_num_bytes'};
+
+    $self->{'num_processed_bytes'} = 0;
+    $self->{'store_text'} = 1;
+
+    # what level (section/document) the gdbm database - indexer intersection is
+    $self->{'gdbm_level'} = "section";
+    #used by browse interface
+    $self->{'doclist'} = [];
+
+    $self->{'indexing_text'} = 0;
+
+    return bless $self, $class;
+
+}
+
+sub reset {
+    my $self = shift (@_);
+
+    $self->{'num_docs'}      = $self->{'starting_num_docs'};
+    $self->{'num_sections'}  = $self->{'starting_num_sections'};
+    $self->{'num_bytes'}     = $self->{'starting_num_bytes'};
+    
+    $self->{'num_processed_bytes'} = 0;
+}
+
+sub zero_reset {
+    my $self = shift (@_);
+
+    $self->{'num_docs'}      = 0;
+    $self->{'num_sections'}  = 0;
+    $self->{'num_bytes'}     = 0;
+    
+    $self->{'num_processed_bytes'} = 0;
+}
+
+sub is_incremental_capable
+{
+    # By default we return 'no' as the answer
+    # Safer to assume non-incremental to start with, and then override in
+    # inherited classes that are.
+
+    return 0;
+}
+
+sub get_num_docs {
+    my $self = shift (@_);
+
+    return $self->{'num_docs'};
+}
+
+sub get_num_sections {
+    my $self = shift (@_);
+
+    return $self->{'num_sections'};
+}
+
+# num_bytes is the actual number of bytes in the collection
+# this is normally the same as what's processed during text compression
+sub get_num_bytes {
+    my $self = shift (@_);
+
+    return $self->{'num_bytes'};
+}
+
+# num_processed_bytes is the number of bytes actually passed
+# to mg for the current index
+sub get_num_processed_bytes {
+    my $self = shift (@_);
+
+    return $self->{'num_processed_bytes'};
+}
+
+sub set_output_handle {
+    my $self = shift (@_);
+    my ($handle) = @_;
+
+    $self->{'output_handle'} = $handle;
+}
+
+
+sub set_mode {
+    my $self = shift (@_);
+    my ($mode) = @_;
+
+    $self->{'mode'} = $mode;
+}
+
+sub get_mode {
+    my $self = shift (@_);
+
+    return $self->{'mode'};
+}
+
+sub set_assocdir {
+    my $self = shift (@_);
+    my ($assocdir) = @_;
+
+    $self->{'assocdir'} = $assocdir;
+}
+
+sub set_dontgdbm {
+    my $self = shift (@_);
+    my ($dontgdbm) = @_;
+
+    $self->{'dontgdbm'} = $dontgdbm;
+}
+
+sub set_index {
+    my $self = shift (@_);
+    my ($index, $indexexparr) = @_;
+
+    $self->{'index'} = $index;
+    $self->{'indexexparr'} = $indexexparr if defined $indexexparr;
+}
+
+sub set_index_languages {
+    my $self = shift (@_);
+    my ($lang_meta, $langarr) = @_;
+    $self->{'lang_meta'} = $lang_meta;
+    $self->{'langarr'} = $langarr;
+}
+
+sub get_index {
+    my $self = shift (@_);
+
+    return $self->{'index'};
+}
+
+sub set_classifiers {
+    my $self = shift (@_);
+    my ($classifiers) = @_;
+
+    $self->{'classifiers'} = $classifiers;
+}
+
+sub set_indexing_text {
+    my $self = shift (@_);
+    my ($indexing_text) = @_;
+
+    $self->{'indexing_text'} = $indexing_text;
+}
+
+sub get_indexing_text {
+    my $self = shift (@_);
+
+    return $self->{'indexing_text'};
+}
+
+sub set_store_text {
+    my $self = shift (@_);
+    my ($store_text) = @_;
+
+    $self->{'store_text'} = $store_text;
+}
+sub get_doc_list {
+    my $self = shift(@_);
+    
+    return @{$self->{'doclist'}};
+}
+
+# the standard gdbm level is section, but you may want to change it to document
+sub set_gdbm_level {
+    my $self= shift (@_);
+    my ($gdbm_level) = @_;
+
+    $self->{'gdbm_level'} = $gdbm_level;
+}
+
+sub set_sections_index_document_metadata {
+    my $self= shift (@_);
+    my ($index_type) = @_;
+    
+    $self->{'sections_index_document_metadata'} = $index_type;
+}
+sub process {
+    my $self = shift (@_);
+    my $method = $self->{'mode'};
+
+    $self->$method(@_);
+}
+
+sub infodb {
+    my $self = shift (@_);
+    my ($doc_obj, $filename) = @_;
+    my $handle = $self->{'output_handle'};
+
+    my $doctype = $doc_obj->get_doc_type();
+
+    # only output this document if it is one to be indexed
+    return if ($doctype ne "indexed_doc");
+
+    my ($archivedir) = $filename =~ /^(.*?)(?:\/|\\)[^\/\\]*$/;
+    $archivedir = "" unless defined $archivedir;
+    $archivedir =~ s/\\/\//g;
+    $archivedir =~ s/^\/+//;
+    $archivedir =~ s/\/+$//;
+
+    # resolve the final filenames of the files associated with this document
+    $self->assoc_files ($doc_obj, $archivedir);
+
+    #GRB: moved 1/06/2004 from GRB01062004
+    #add this document to the browse structure
+    push(@{$self->{'doclist'}},$doc_obj->get_OID()) 
+	unless ($doctype eq "classification");
+
+    # classify this document
+    &classify::classify_doc ($self->{'classifiers'}, $doc_obj);
+    #GRB: end of moved block
+
+    # this is another document
+    $self->{'num_docs'} += 1 unless ($doctype eq "classification");
+
+    # is this a paged or a hierarchical document
+    my ($thistype, $childtype) = $self->get_document_type ($doc_obj);
+
+    my $section = $doc_obj->get_top_section ();
+    my $doc_OID = $doc_obj->get_OID();
+    my $first = 1;
+    my $url = "";
+    while (defined $section) {
+	# update a few statistics
+	$self->{'num_bytes'} += $doc_obj->get_text_length ($section);
+	$self->{'num_sections'} += 1 unless ($doctype eq "classification");
+
+	# output the section name
+	if ($section eq "") { print $handle "[$doc_OID]\n"; }
+	else { print $handle "[$doc_OID.$section]\n"; }
+
+	# output the fact that this document is a document (unless doctype
+	# has been set to something else from within a plugin
+	my $dtype = $doc_obj->get_metadata_element ($section, "doctype");
+	if (!defined $dtype || $dtype !~ /\w/) {
+	    print $handle "<doctype>doc\n";
+	}
+
+	# output whether this node contains text
+	if ($doc_obj->get_text_length($section) > 0) {
+	    print $handle "<hastxt>1\n";
+	} else {
+	    print $handle "<hastxt>0\n";
+	}
+
+	# output all the section metadata
+	my $metadata = $doc_obj->get_all_metadata ($section);
+	foreach my $pair (@$metadata) {
+	    my ($field, $value) = (@$pair);
+
+	    if ($field ne "Identifier" && $field !~ /^gsdl/ && 
+		defined $value && $value ne "") {	    
+
+		# escape problematic stuff
+		$value =~ s/\\/\\\\/g;
+		$value =~ s/\n/\\n/g;
+		$value =~ s/\r/\\r/g;
+		if ($value =~ /-{70,}/) {
+		    # if value contains 70 or more hyphens in a row we need
+		    # to escape them to prevent txt2db from treating them
+		    # as a separator
+		    $value =~ s/-/&\#045;/gi;
+		}
+
+		# special case for URL metadata
+		if ($field =~ /^URL$/i) {
+                    $url .= "[$value]\n";
+                    if ($section eq "") {$url .= "<section>$doc_OID\n";}
+                    else {$url .= "<section>$doc_OID.$section\n";}
+                    $url .= '-' x 70 . "\n";
+		}
+
+		if (!defined $self->{'dontgdbm'}->{$field}) {
+		    print $handle "<$field>$value\n";
+		}
+	    }
+	}
+
+	# output archivedir if at top level
+	if ($section eq $doc_obj->get_top_section()) {
+	    print $handle "<archivedir>$archivedir\n";
+	}
+
+	# output document display type
+	if ($first) {
+	    print $handle "<thistype>$thistype\n";
+	}
+
+	if ($self->{'gdbm_level'} eq "document") {
+	    # doc num is num_docs not num_sections
+	    # output the matching document number
+	    print $handle "<docnum>$self->{'num_docs'}\n";
+	} else {
+	    # output a list of children
+	    my $children = $doc_obj->get_children ($section);
+	    if (scalar(@$children) > 0) {
+		print $handle "<childtype>$childtype\n";
+		print $handle "<contains>";
+		my $firstchild = 1;
+		foreach my $child (@$children) {
+		    print $handle ";" unless $firstchild;
+		    $firstchild = 0;
+		    if ($child =~ /^.*?\.(\d+)$/) {
+			print $handle "\".$1";
+		    } else {
+			print $handle "\".$child";
+		    }
+#		if ($child eq "") { print $handle "$doc_OID"; }
+#		elsif ($section eq "") { print $handle "$doc_OID.$child"; }
+#		else { print $handle "$doc_OID.$section.$child"; }
+		}
+		print $handle "\n";
+	    }
+	    #output the matching doc number
+	    print $handle "<docnum>$self->{'num_sections'}\n";
+	    
+	} 
+	
+	print $handle '-' x 70, "\n";
+
+	
+	# output a database entry for the document number
+	if ($self->{'gdbm_level'} eq "document") {
+	    print $handle "[$self->{'num_docs'}]\n";
+	    print $handle "<section>$doc_OID\n";
+	}
+	else {
+	    print $handle "[$self->{'num_sections'}]\n";
+	    if ($section eq "") { print $handle "<section>$doc_OID\n"; }
+	    else { print $handle "<section>$doc_OID.$section\n"; }
+	}
+	print $handle '-' x 70, "\n";
+	
+        # output entry for url
+        if ($url ne "") {
+            print $handle $url;
+        }
+
+	$first = 0;
+	$section = $doc_obj->get_next_section($section);
+	last if ($self->{'gdbm_level'} eq "document"); # if no sections wanted, only gdbm the docs
+    }
+
+    #GRB01062004: see code above moved from here
+}
+
+
+sub text {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+    
+    my $handle = $self->{'outhandle'};
+    print $handle "basebuildproc::text function must be implemented in sub classes\n";
+    die "\n";
+}
+
+# should the document be indexed - according to the subcollection and language
+# specification.
+sub is_subcollection_doc {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+    
+    my $indexed_doc = 1;
+    foreach my $indexexp (@{$self->{'indexexparr'}}) {
+	$indexed_doc = 0;
+	my ($field, $exp, $options) = split /\//, $indexexp;
+	if (defined ($field) && defined ($exp)) {
+	    my ($bool) = $field =~ /^(.)/;
+	    $field =~ s/^.// if $bool eq '!';
+	    my @metadata_values;
+	    if ($field =~ /^filename$/i) {
+		push(@metadata_values, $doc_obj->get_source_filename());
+	    }
+	    else {
+		@metadata_values = @{$doc_obj->get_metadata($doc_obj->get_top_section(), $field)};
+	    }
+	    next unless @metadata_values;
+	    foreach my $metadata_value (@metadata_values) {
+		if ($bool eq '!') {
+		    if ($options =~ /^i$/i) {
+			if ($metadata_value !~ /$exp/i) {$indexed_doc = 1; last;}
+		    } else {
+			if ($metadata_value !~ /$exp/) {$indexed_doc = 1; last;}
+		    }
+		} else {
+		    if ($options =~ /^i$/i) {
+			if ($metadata_value =~ /$exp/i) {$indexed_doc = 1; last;}
+		    } else {
+			if ($metadata_value =~ /$exp/) {$indexed_doc = 1; last;}
+		    }
+		}
+	    }
+
+	    last if ($indexed_doc == 1);
+	}
+    }
+    
+    # if this doc is so far in the sub collection, and we have lang info, 
+    # now we check the languages to see if it matches
+    if($indexed_doc && defined $self->{'lang_meta'}) {
+	$indexed_doc = 0;
+	my $field = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $self->{'lang_meta'});
+	if (defined $field) {
+	    foreach my $lang (@{$self->{'langarr'}}) {
+		my ($bool) = $lang =~ /^(.)/;
+		if ($bool eq '!') {
+		    $lang =~ s/^.//;
+		    if ($field !~ /$lang/) {
+			$indexed_doc = 1; last;
+		    }
+		} else {
+		    if ($field =~ /$lang/) {
+			$indexed_doc = 1; last;
+		    }
+		}
+	    }
+	} 
+    }
+    return $indexed_doc;
+    
+}
+
+# use 'Paged' if document has no more than 2 levels
+# and each section at second level has a number for
+# Title metadata
+# also use Paged if gsdlthistype metadata is set to Paged
+sub get_document_type {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $thistype = "VList";
+    my $childtype = "VList";
+    my $title;
+    my @tmp = ();
+    
+    my $section = $doc_obj->get_top_section ();
+    
+    my $gsdlthistype = $doc_obj->get_metadata_element ($section, "gsdlthistype");
+    if (defined $gsdlthistype) {
+	if ($gsdlthistype eq "Paged") {
+	    $childtype = "Paged";
+	    if ($doc_obj->get_text_length ($doc_obj->get_top_section())) {
+		$thistype = "Paged";
+	    } else {
+		$thistype = "Invisible";
+	    }
+	    
+	    return ($thistype, $childtype);
+	} elsif ($gsdlthistype eq "Hierarchy") {
+	    return ($thistype, $childtype); # use VList, VList
+	}
+    }
+    my $first = 1;
+    while (defined $section) {
+	@tmp = split /\./, $section;
+	if (scalar(@tmp) > 1) {
+	    return ($thistype, $childtype);
+	}
+	if (!$first) {
+	    $title = $doc_obj->get_metadata_element ($section, "Title");
+	    if (!defined $title || $title !~ /^\d+$/) {
+		return ($thistype, $childtype);
+	    }
+	}
+	$first = 0;
+	$section = $doc_obj->get_next_section($section);
+    }
+    if ($doc_obj->get_text_length ($doc_obj->get_top_section())) {
+	$thistype = "Paged";
+    } else {
+	$thistype = "Invisible";
+    }
+    $childtype = "Paged";
+    return ($thistype, $childtype);
+}
+
+sub assoc_files {
+    my $self = shift (@_);
+    my ($doc_obj, $archivedir) = @_;
+    my ($afile);
+    
+    foreach my $assoc_file (@{$doc_obj->get_assoc_files()}) {
+	# if assoc file starts with a slash, we put it relative to the assoc
+	# dir, otherwise it is relative to the HASH... directory
+	if ($assoc_file->[1] =~ m@^[/\\]@) {
+	    $afile = &util::filename_cat($self->{'assocdir'},$assoc_file->[1]);
+	} else {
+	    $afile = &util::filename_cat($self->{'assocdir'}, $archivedir, $assoc_file->[1]);
+	}
+	&util::hard_link ($assoc_file->[0], $afile);
+    }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cfgread.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cfgread.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cfgread.pm	(revision 10506)
@@ -0,0 +1,178 @@
+###########################################################################
+#
+# cfgread.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# reads in configuration files
+
+package cfgread;
+
+
+sub read_cfg_line {
+    my ($handle) = @_;
+    my $line = "";
+    my @line = ();
+    my $linecontinues = 0;
+
+    while (defined($line = <$handle>)) {
+	$line =~ s/^\#.*$//;   # remove comments
+	$line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	$line =~ s/^\s+//;     # remove initial white space
+	# Merge with following line if a quoted phrase is left un-closed.
+	if ($line =~ m/[^\\]([\"\'])/) {
+	    my $quote=$1;
+	    while ($line !~ m/$quote(.*?[^\\])?(\\\\)*$quote/) {
+		my $nextline = <$handle>;
+		if (defined($nextline)) {
+		    $nextline =~ s/\r?\n//; # remove end-of-line
+		    $line .= " " . $nextline;
+		} else {
+		    return undef; # parse error?
+		}
+	    }
+	}
+	$linecontinues = $line =~ s/\\$//;
+
+	while ($line =~ s/\s*(\".*?[^\\](\\\\)*\"|\'.*?[^\\](\\\\)*\'|\S+)\s*//) {
+	    if (defined $1) {
+		# remove any enclosing quotes
+		my $entry = $1;
+		$entry =~ s/^([\"\'])(.*)\1$/$2/;
+
+		# substitute an environment variables
+##		$entry =~ s/\$(\w+)/$ENV{$1}/g;
+		$entry =~ s/\$\{(\w+)\}/$ENV{$1}/g;
+		push (@line, $entry);
+	    } else {
+		push (@line, "");
+	    }
+	}
+
+	if (scalar(@line) > 0 && !$linecontinues) {
+#	    print STDERR "line: \"" . join ("\" \"", @line) . "\"\n";
+	    return \@line;
+	}
+    }
+
+    return undef;
+}
+
+sub write_cfg_line {
+    my ($handle, $line) = @_;
+    print $handle join ("\t", @$line), "\n";
+}
+
+
+# stringexp, arrayexp, hashexp,arrayarrayexp and hashhashexp
+# should be something like '^(this|that)$'
+sub read_cfg_file {
+    my ($filename, $stringexp, $arrayexp, $hashexp, $arrayarrayexp,
+	$hashhashexp) = @_;
+    my ($line);
+    my $data = {};
+
+    if (open (COLCFG, $filename)) {
+	while (defined ($line = &read_cfg_line('COLCFG'))) {
+	    if (scalar(@$line) >= 2) {
+		my $key = shift (@$line);
+		if (defined $stringexp && $key =~ /$stringexp/) {
+		    $data->{$key} = shift (@$line);
+
+		} elsif (defined $arrayexp && $key =~ /$arrayexp/) {
+		    push (@{$data->{$key}}, @$line);
+
+		} elsif (defined $hashexp && $key =~ /$hashexp/) {
+		    my $k = shift @$line;
+		    my $v = shift @$line;
+		    $data->{$key}->{$k} = $v;
+		} elsif (defined $arrayarrayexp && $key =~ /$arrayarrayexp/) {
+		    if (!defined $data->{$key}) {
+			$data->{$key} = [];
+		    }
+		    push (@{$data->{$key}}, $line);
+		}
+		elsif (defined $hashhashexp && $key =~ /$hashhashexp/) {
+		    my $k = shift @$line;
+		    my $p = shift @$line;
+		    my $v = shift @$line;
+		    if (!defined $v) {
+			$v = $p;
+			$p = 'default';
+		    }
+		    $data->{$key}->{$k}->{$p} = $v;
+		}
+	    }
+	}
+	close (COLCFG);
+
+    } else {
+	print STDERR "cfgread::read_cfg_file couldn't read the cfg file $filename\n";
+    }
+
+    return $data;
+}
+
+
+# stringexp, arrayexp, hashexp and arrayarrayexp 
+# should be something like '^(this|that)$'
+sub write_cfg_file {
+    my ($filename, $data, $stringexp, $arrayexp, $hashexp, $arrayarrayexp,
+	$hashhashexp) = @_;
+    
+    if (open (COLCFG, ">$filename")) {
+	foreach $key (sort(keys(%$data))) {
+	    if ($key =~ /$stringexp/) {
+		&write_cfg_line ('COLCFG', [$key, $data->{$key}]);
+	    } elsif ($key =~ /$arrayexp/) {
+		&write_cfg_line ('COLCFG', [$key, @{$data->{$key}}]);
+	    } elsif ($key =~ /$hashexp/) {
+		foreach $k (keys (%{$data->{$key}})) {
+		    &write_cfg_line ('COLCFG', [$key, $k, $data->{$key}->{$k}]);
+		}
+	    } elsif ($key =~ /$arrayarrayexp/) {
+		foreach $k (@{$data->{$key}}) {
+		    &write_cfg_line ('COLCFG', [$key, @$k]);
+		}
+	    } elsif ($key =~ /$hashhashexp/) {
+		foreach $k (keys (%{$data->{$key}})) {
+		    foreach $p (keys (%{$data->{$key}->{$k}})) {
+			if ($p =~ /default/) {
+			    &write_cfg_line ('COLCFG', 
+					     [$key, $k, $data->{$key}->{$k}]);
+			}
+			else {
+			    &write_cfg_line ('COLCFG', 
+			       [$key, $k, $p, $data->{$key}->{$k}->{$p}]);
+			}
+		    }
+		}
+	    }
+	}
+	close (COLCFG);
+    } else {
+	print STDERR "cfgread::write_cfg_file couldn't write the cfg file $filename\n";
+    }
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify.pm	(revision 10506)
@@ -0,0 +1,289 @@
+###########################################################################
+#
+# classify.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# functions to handle classifiers
+
+package classify;
+
+require util;
+require AllList;
+use gsprintf;
+
+
+sub gsprintf
+{
+    return &gsprintf::gsprintf(@_);
+}
+
+
+$next_classify_num = 1;
+sub load_classifier_for_info {
+    my ($classifier) = shift @_;
+
+    # find the classifier
+    my $colclassname = &util::filename_cat($ENV{'GSDLCOLLECTDIR'},
+					   "perllib/classify", 
+					   "${classifier}.pm");
+    my $mainclassname = &util::filename_cat($ENV{'GSDLHOME'},
+					    "perllib/classify", 
+					    "${classifier}.pm");
+
+    if (-e $colclassname) { require $colclassname; }
+    elsif (-e $mainclassname) { require $mainclassname; }
+    else { 
+	&gsprintf(STDERR, "{classify.could_not_find_classifier}\n", $classifier) && die "\n";
+    }
+    my ($classobj);
+    my $options = "-gsdlinfo";
+    eval ("\$classobj = new \$classifier([],[$options])");
+    die "$@" if $@;
+
+    return $classobj;
+}
+
+sub load_classifiers {
+    my ($classify_list, $build_dir, $outhandle) = @_;
+    my @classify_objects = ();
+    my $classify_number  = 1;
+    
+    foreach $classifyoption (@$classify_list) {
+
+	# get the classifier name
+	my $classname = shift @$classifyoption;
+	next unless defined $classname;
+
+	# find the classifier
+	my $colclassname = &util::filename_cat($ENV{'GSDLCOLLECTDIR'},"perllib/classify", 
+					       "${classname}.pm");
+	my $mainclassname = &util::filename_cat($ENV{'GSDLHOME'},"perllib/classify", 
+						"${classname}.pm");
+
+	if (-e $colclassname) { require $colclassname; }
+	elsif (-e $mainclassname) { require $mainclassname; }
+	else { &gsprintf(STDERR, "{classify.could_not_find_classifier}\n", $classname) && die "\n";
+	       # die "ERROR - couldn't find classifier \"$classname\"\n";
+	   }
+
+	# create the classify object
+	my ($classobj);
+
+	my @newoptions;
+
+	# do these first so they can be overriden by user supplied options
+	push @newoptions, "-builddir", "$build_dir" if ($build_dir);
+	push @newoptions, "-outhandle", "$outhandle" if ($outhandle);
+	push @newoptions, "-verbosity", "2";
+
+	# backwards compatability hack: if the classifier options are 
+	# in "x=y" format, convert them to parsearg ("-x y") format.
+	my ($opt, $key, $value);
+	foreach $opt (@$classifyoption) {
+	    if ($opt =~ /^(\w+)=(.*)$/) {
+		push @newoptions, "-$1", $2;
+	    } else {
+		push @newoptions, $opt;
+	    }
+	}
+
+	map { $_ = "\"$_\""; } @newoptions;
+	my $options .= join (",", @newoptions);
+
+
+	eval ("\$classobj = new \$classname([],[$options])");
+	die "$@" if $@;
+
+	$classobj->set_number($classify_number);
+	$classify_number ++;
+
+       	# add this object to the list
+	push (@classify_objects, $classobj);
+    }
+
+    my ($classobj);
+    eval ("\$classobj = new AllList()");
+    die "$@" if $@;
+    push (@classify_objects, $classobj);
+
+    return \@classify_objects;
+}
+
+# init_classifiers resets all the classifiers and readys them to process
+# the documents.
+sub init_classifiers {
+    my ($classifiers) = @_;
+    
+    foreach $classobj (@$classifiers) {
+	$classobj->init();
+    }
+}
+
+# classify_doc lets each of the classifiers classify a document
+sub classify_doc {
+    my ($classifiers, $doc_obj) = @_;
+    
+    foreach $classobj (@$classifiers) {
+	my $title = $classobj->{'title'};
+	$classobj->classify($doc_obj);
+    }
+}
+
+# output_classify_info outputs all the info needed for the classification
+# to the gdbm
+sub output_classify_info {
+    my ($classifiers, $handle, $remove_empty_classifications, $gli) = @_;
+#    $handle = "main::STDOUT";
+
+    $gli = 0 unless defined $gli;
+
+    # create a classification containing all the info
+    my $classifyinfo = {'classifyOID'=>'browse',
+			'contains'=>[]};
+
+    # get each of the classifications
+    foreach $classobj (@$classifiers) {
+	my $tempinfo = $classobj->get_classify_info($gli);
+	my $classID = $tempinfo->{'classifyOID'};
+
+	$tempinfo->{'classifyOID'} = "CL$next_classify_num" unless defined($tempinfo->{'classifyOID'});
+	$next_classify_num++;
+	push (@{$classifyinfo->{'contains'}}, $tempinfo);
+    }
+
+    &print_classify_info ($handle, $classifyinfo, "", $remove_empty_classifications);
+}
+
+sub print_classify_info {
+    my ($handle, $classifyinfo, $OID, $remove_empty_classifications) = @_;
+
+    $OID =~ s/^\.+//; # just for good luck
+
+    # book information is printed elsewhere
+    return if (defined ($classifyinfo->{'OID'}));
+ 
+    # don't want empty classifications
+    return if (&check_contents ($classifyinfo, $remove_empty_classifications) == 0 && $remove_empty_classifications);
+   
+    $OID = $classifyinfo->{'classifyOID'} if defined ($classifyinfo->{'classifyOID'});
+	
+    my $outputtext = "[$OID]\n";
+    $outputtext .= "<doctype>classify\n";
+    $outputtext .= "<hastxt>0\n";
+    $outputtext .= "<childtype>$classifyinfo->{'childtype'}\n" 
+	if defined $classifyinfo->{'childtype'};
+    $outputtext .= "<Title>$classifyinfo->{'Title'}\n" 
+	if defined $classifyinfo->{'Title'};
+    $outputtext .= "<numleafdocs>$classifyinfo->{'numleafdocs'}\n" 
+	if defined $classifyinfo->{'numleafdocs'};
+    $outputtext .= "<thistype>$classifyinfo->{'thistype'}\n" 
+	if defined $classifyinfo->{'thistype'};
+    $outputtext .= "<parameters>$classifyinfo->{'parameters'}\n" 
+	if defined $classifyinfo->{'parameters'};
+    $outputtext .= "<supportsmemberof>$classifyinfo->{'supportsmemberof'}\n"
+	if defined $classifyinfo->{'supportsmemberof'};
+    
+    my $contains_text = "<contains>";
+    my $mdoffset_text = "<mdoffset>";
+    
+    my $next_subOID = 1;
+    my $first = 1;
+    foreach $tempinfo (@{$classifyinfo->{'contains'}}) {
+	# empty contents were made undefined by clean_contents()
+	next unless defined $tempinfo;
+	
+	if (!defined ($tempinfo->{'classifyOID'}) ||
+	    $tempinfo->{'classifyOID'} ne "oai") {
+	    $contains_text .= ";" unless $first;
+	}
+	$mdoffset_text .= ";" unless $first;
+	$first = 0;
+	
+	if (defined ($tempinfo->{'classifyOID'})) {
+	    if ($tempinfo->{'classifyOID'} ne "oai") {
+		$contains_text .= $tempinfo->{'classifyOID'};
+	    }
+	    &print_classify_info ($handle, $tempinfo, $tempinfo->{'classifyOID'},
+				  $remove_empty_classifications);
+	} elsif (defined ($tempinfo->{'OID'})) {
+	    $contains_text .= $tempinfo->{'OID'};
+	    $mdoffset_text .= $tempinfo->{'offset'}
+	    if (defined ($tempinfo->{'offset'}))
+		# note: we don't want to print the contents of the books
+	    } else {
+		
+		# Supress having top-level node in Collage classifier
+		# so no bookshelf icon appears, top-level, along with the
+		# applet
+		
+		if (!defined ($tempinfo->{'Title'}) || $tempinfo->{'Title'} ne "Collage") {
+		    $contains_text .= "\".$next_subOID"; 
+		}
+		
+		&print_classify_info ($handle, $tempinfo, "$OID.$next_subOID",
+				      $remove_empty_classifications);
+		$next_subOID++;
+	    }
+    }
+    
+    $outputtext .= "$contains_text\n";
+    $outputtext .= "<mdtype>$classifyinfo->{'mdtype'}\n" 
+	if defined $classifyinfo->{'mdtype'};
+    $outputtext .= "$mdoffset_text\n"
+	if ($mdoffset_text !~ m/^<mdoffset>;+$/);
+    
+    $outputtext .= '-' x 70 . "\n";
+    
+    print $handle $outputtext;
+
+}
+
+sub check_contents {
+    my ($classifyinfo,$remove_empty_classifications) = @_;
+    $remove_empty_classifications = 0 unless ($remove_empty_classifications);
+    my $num_leaf_docs = 0;
+    my $sub_num_leaf_docs = 0;
+
+    return $classifyinfo->{'numleafdocs'} if (defined $classifyinfo->{'numleafdocs'});
+
+    foreach $content (@{$classifyinfo->{'contains'}}) {
+	if (defined $content->{'OID'}) {
+	    # found a book
+	    $num_leaf_docs ++;
+	} elsif (($sub_num_leaf_docs = &check_contents ($content,$remove_empty_classifications)) > 0) {
+	    # there's a book somewhere below
+	    $num_leaf_docs += $sub_num_leaf_docs;
+	} else {
+	    if ($remove_empty_classifications){
+		# section contains no books so we want to remove 
+		# it from its parents contents
+		$content = undef;
+	    }
+	}
+    }
+
+    $classifyinfo->{'numleafdocs'} = $num_leaf_docs;
+    return $num_leaf_docs;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZCompactList.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZCompactList.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZCompactList.pm	(revision 10506)
@@ -0,0 +1,824 @@
+###########################################################################
+#
+# AZCompactList.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+# classifier plugin for sorting alphabetically
+# options are:
+
+package AZCompactList;
+
+use BasClas;
+use sorttools;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @AZCompactList::ISA = ('BasClas');
+}
+
+my $doclevel_list = 
+    [ {	'name' => "top",
+ 	'desc' => "{AZCompactList.doclevel.top}" },
+      { 'name' => "section",
+	'desc' => "{AZCompactList.doclevel.section}" } ];
+
+my $arguments = 
+    [ { 'name' => "metadata",
+	'desc' => "{AZCompactList.metadata}",
+	'type' => "metadata",
+	'reqd' => "yes" },
+      { 'name' => "firstvalueonly",
+	'desc' => "{AZCompactList.firstvalueonly}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "allvalues",
+	'desc' => "{AZCompactList.allvalues}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "buttonname",
+  	'desc' => "{BasClas.buttonname}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "sort",
+	'desc' => "{AZCompactList.sort}",
+	'type' => "string",
+#	'deft' => "Title",
+	'reqd' => "no" },
+      { 'name' => "removeprefix",
+	'desc' => "{BasClas.removeprefix}",
+	'type' => "regexp",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "removesuffix",
+	'desc' => "{BasClas.removesuffix}",
+	'type' => "regexp",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "mingroup",
+	'desc' => "{AZCompactList.mingroup}",
+	'type' => "int",
+	'deft' => "2",
+	'range' => "1,",
+	'reqd' => "no" },
+      { 'name' => "minnesting",
+	'desc' => "{AZCompactList.minnesting}",
+	'type' => "int",
+	'deft' => "20",
+	'range' => "2,",
+	'reqd' => "no" },
+      { 'name' => "mincompact",
+	'desc' => "{AZCompactList.mincompact}",
+	'type' => "int",
+	'deft' => "10",
+	'range' => "1,",
+	'reqd' => "no" },
+      { 'name' => "maxcompact",
+	'desc' => "{AZCompactList.maxcompact}",
+	'type' => "int",
+	'deft' => "30",
+	'range' => "1,",
+	'reqd' => "no" },
+      { 'name' => "doclevel",
+	'desc' => "{AZCompactList.doclevel}",
+	'type' => "enum",
+	'list' => $doclevel_list,
+	'deft' => "top",
+	'reqd' => "no" },
+      { 'name' => "freqsort",
+	'desc' => "{AZCompactList.freqsort}",
+	'type' => "flag"},
+      { 'name' => "recopt",
+	'desc' => "{AZCompactList.recopt}",
+	'type' => "flag",
+	'reqd' => "no" } ];
+
+my $options = 
+{ 	'name'     => "AZCompactList",
+	'desc'     => "{AZCompactList.desc}",
+	'abstract' => "no",
+	'inherits' => "yes",
+	'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasClas($pluginlist,$inputargs,$hashArgOptLists): new BasClas($pluginlist,$inputargs);
+
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+    
+    if (!$self->{"metadata"}) {
+	my $outhandle = $self->{'outhandle'};
+	print $outhandle "AZCompactList Error: required option -metadata not supplied\n";
+	$self->print_txt_usage("");  
+	die "AZCompactList Error: required option -metadata not supplied\n";
+    }
+
+    # Manually set $self parameters.
+    $self->{'list'} = {};
+    $self->{'listmetavalue'} = {};
+    $self->{'list_mvpair'} = {};
+    $self->{'reclassify'} = {};
+    $self->{'reclassifylist'} = {};
+
+    $self->{'buttonname'} = $self->generate_title_from_metadata($self->{'metadata'}) unless ($self->{'buttonname'});
+    
+    if (defined($self->{"removeprefix"}) && $self->{"removeprefix"}) {
+	$self->{"removeprefix"} =~ s/^\^//; # don't need a leading ^
+    }
+    if (defined($self->{"removesuffix"}) && $self->{"removesuffix"}) {
+	$self->{"removesuffix"} =~ s/\$$//; # don't need a trailing $
+    }
+	
+    $self->{'recopt'} = ($self->{'recopt'} == 0) ? undef : "on";
+
+    # Clean out the unused keys
+    if($self->{"removeprefix"} eq "") {delete $self->{"removeprefix"};}
+    if($self->{"removesuffix"} eq "") {delete $self->{"removesuffix"};}
+
+    return bless $self, $class;
+}
+
+sub init 
+{
+    my $self = shift (@_);
+    
+    $self->{'list'} = {};
+    $self->{'listmetavalue'} = {};
+    $self->{'list_mvpair'} = {};
+    $self->{'reclassify'} = {};
+    $self->{'reclassifylist'} = {};
+}
+
+my $tmp = 0;
+
+sub classify
+{
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+
+    my @sectionlist = ();
+    my $topsection = $doc_obj->get_top_section();
+    my $metaname = $self->{'metadata'};
+    my $outhandle = $self->{'outhandle'};
+
+    $metaname =~ s/(\/|\|).*//; # grab first name in n1/n2/n3 or n1|n2|n3 list
+    my @commameta_list = split(/,/, $metaname);
+
+    if ($self->{'doclevel'} =~ /^top(level)?/i)
+    {
+	push(@sectionlist,$topsection);
+    }
+    else
+    {
+	my $thissection = $doc_obj->get_next_section($topsection);
+	while (defined $thissection) 
+	{
+	    push(@sectionlist,$thissection);
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    }
+
+    my $thissection;
+    foreach $thissection (@sectionlist)
+    {
+	my $full_doc_OID 
+	    = ($thissection ne "") ? "$doc_OID.$thissection" : $doc_OID;
+	if (defined $self->{'list_mvpair'}->{$full_doc_OID}) 
+	{
+	    print $outhandle "WARNING: AZCompactList::classify called multiple times for $full_doc_OID\n";
+	} 
+	$self->{'list'}->{$full_doc_OID} = [];	
+	$self->{'listmetavalue'}->{$full_doc_OID} = [];
+	$self->{'list_mvpair'}->{$full_doc_OID} = [];
+
+	my $metavalues = [];
+	foreach my $cmn (@commameta_list) {
+	    my $cmvalues = $doc_obj->get_metadata($thissection,$cmn);
+	    push(@$metavalues,@$cmvalues) if (@{$cmvalues});
+	    last if (@{$cmvalues} && !$self->{'allvalues'});
+	}
+
+	my $metavalue;
+	foreach $metavalue (@$metavalues) 
+	{
+	    # Tidy up use of white space in metavalue for classifying
+	    $metavalue =~ s/^\s*//s;
+	    $metavalue =~ s/\s*$//s;
+	    $metavalue =~ s/\n/ /s;
+	    $metavalue =~ s/\s{2,}/ /s;
+
+	    # if this document doesn't contain the metadata element we're
+	    # sorting by we won't include it in this classification
+	    if (defined $metavalue && $metavalue =~ /\w/) 
+	    {
+		if (defined($self->{'removeprefix'}) &&
+		    length($self->{'removeprefix'})) {
+		    $metavalue =~ s/^$self->{'removeprefix'}//;
+
+		    # check that it's not now empty
+		    if (!$metavalue) {next;}
+		}
+
+		if (defined($self->{'removesuffix'}) &&
+		    length($self->{'removesuffix'})) {
+		    $metavalue =~ s/$self->{'removesuffix'}$//;
+
+		    # check that it's not now empty
+		    if (!$metavalue) {next;}
+		}
+
+		my $formatted_metavalue =
+		  sorttools::format_metadata_for_sorting($self->{'metadata'},
+							 $metavalue, $doc_obj);
+		
+		#### prefix-str
+		if (! defined($formatted_metavalue)) {
+		    print $outhandle "Warning: AZCompactList: metavalue is ";
+		    print $outhandle "empty\n";
+		    $formatted_metavalue="";
+		}
+
+		my $mv_pair = { 'mv' => $metavalue, 'fmv' => $formatted_metavalue };
+		push(@{$self->{'list'}->{$full_doc_OID}},$formatted_metavalue);
+		push(@{$self->{'listmetavalue'}->{$full_doc_OID}} ,$metavalue);
+		push(@{$self->{'list_mvpair'}->{$full_doc_OID}},$mv_pair);
+
+
+		last if ($self->{'firstvalueonly'});
+	    }
+	}
+
+	# This is used in reclassify below for AZCompactSectionList
+	my $sortmeta = $doc_obj->get_metadata_element($thissection, $self->{'sort'});
+	$self->{'reclassify'}->{$full_doc_OID} = [$doc_obj,$sortmeta];
+    }
+}
+
+sub reinit 
+{
+    my ($self,$classlist_ref) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    my %mtfreq = ();
+    my @single_classlist = ();
+    my @multiple_classlist = ();
+
+    # find out how often each metavalue occurs
+    map 
+    { 
+	foreach my $mvp (@{$self->{'list_mvpair'}->{$_}} )
+	{
+###	    print STDERR "*** plain mv = $mvp->{'mv'}\n";
+###	    print STDERR "*** format mv = $mvp->{'fmv'}\n";
+
+	    my $metavalue = $mvp->{'mv'};
+	    $metavalue =~ s!^-!\\-!; # in case it starts with "-"
+	    $mtfreq{$metavalue}++;
+	}
+    } @$classlist_ref;
+
+    # use this information to split the list: single metavalue/repeated value
+    map
+    { 
+	my $i = 1;
+	my $metavalue;
+	foreach my $mvp (@{$self->{'list_mvpair'}->{$_}})
+	{
+	    my $metavalue = $mvp->{'mv'};
+	    $metavalue =~ s!^-!\\-!; # in case it starts with "-"
+	    my $cs_metavalue = $mvp->{'mv'}; # case sensative
+	    if ($mtfreq{$metavalue} >= $self->{'mingroup'})
+	    {
+###		print STDERR "*** pushing on $cs_metavalue\n";
+		push(@multiple_classlist,[$_,$i,$metavalue]); 
+	    } 
+	    else
+	    {
+		push(@single_classlist,[$_,$cs_metavalue]); 
+		$metavalue =~ tr/[A-Z]/[a-z]/;
+		$self->{'reclassifylist'}->{"Metavalue_$i.$_"} = $metavalue;
+	    }
+	    $i++;
+	}
+    } @$classlist_ref;
+    
+    
+    # Setup sub-classifiers for multiple list
+
+    $self->{'classifiers'} = {};
+
+    my $pm;
+    foreach $pm ("List", "SectionList")
+    {
+	my $listname 
+	    = &util::filename_cat($ENV{'GSDLHOME'},"perllib/classify/$pm.pm");
+	if (-e $listname) { require $listname; }
+	else 
+	{ 
+	    print $outhandle "AZCompactList ERROR - couldn't find classifier \"$listname\"\n"; 
+	    die "\n";
+	}
+    }
+
+    # Create classifiers objects for each entry >= mingroup
+    my $metavalue;
+    my $doclevel = $self->{'doclevel'};
+    my $mingroup = $self->{'mingroup'};
+    my @metaname_list = split(/\/|\|/,$self->{'metadata'});
+    my $metaname = shift(@metaname_list);
+    my $hierarchical = 0;
+    if (scalar(@metaname_list) > 1) {
+	$hierarchical = 1;
+	$metaname = join('/',@metaname_list);
+    }
+    foreach $metavalue (keys %mtfreq)
+    {
+	if ($mtfreq{$metavalue} >= $mingroup)
+	{
+	    # occurs more often than minimum required to compact into a group
+	    my $listclassobj;
+	    
+	    if (!$hierarchical) 
+	    {	
+		my @args;
+		push @args, ("-metadata", "$metaname");
+		# buttonname is also used for the node's title
+		push @args, ("-buttonname", "$metavalue");
+		push @args, ("-sort", $self->{'sort'});
+
+		my $ptArgs = \@args;
+		if ($doclevel =~ m/^top(level)?/i)
+		{
+		    eval ("\$listclassobj = new List([],\$ptArgs)"); 
+		}
+		else
+		{
+		    eval ("\$listclassobj = new SectionList([],\$ptArgs)");
+		}
+	    }
+	    else
+	    {
+		
+		my @args;
+		push @args, ("-metadata", "$metaname");
+		# buttonname is also used for the node's title
+		push @args, ("-buttonname", "$metavalue");
+		push @args, ("-sort", $self->{'sort'});
+
+		if (defined $self->{'removeprefix'}) {
+		    push @args, ("-removeprefix", $self->{'removeprefix'});
+		}
+		if (defined $self->{'removesuffix'}) {
+		    push @args, ("-removesuffix", $self->{'removesuffix'});
+		}
+		
+		push @args, ("-doclevel", "$doclevel");
+		push @args, ("-mingroup", $mingroup);
+		push @args, "-recopt ";
+
+		my $ptArgs = \@args;
+		eval ("\$listclassobj = new AZCompactList([],\$ptArgs)");
+	    }
+	    
+	    if ($@) {
+		print $outhandle "$@";
+		die "\n";
+	    }
+	    
+	    $listclassobj->init();
+
+	    if (defined $metavalue && $metavalue =~ /\w/) 
+	    {
+		my $formatted_node = $metavalue;
+
+		if (defined($self->{'removeprefix'}) &&
+		    length($self->{'removeprefix'})) {
+		    $formatted_node =~ s/^$self->{'removeprefix'}//;
+		    # check that it's not now empty
+		    if (!$formatted_node) {next;}
+		}
+		if (defined($self->{'removesuffix'}) &&
+		    length($self->{'removesuffix'})) {
+		    $formatted_node =~ s/$self->{'removesuffix'}$//;
+		    # check that it's not now empty
+		    if (!$formatted_node) {next;}
+		}
+
+		$formatted_node = &sorttools::format_metadata_for_sorting($self->{'metadata'}, $formatted_node); 
+
+		# In case our formatted string is empty...
+		if (! defined($formatted_node)) {
+		    print $outhandle "Warning: AZCompactList: metavalue is ";
+		    print $outhandle "empty\n";
+		    $formatted_node="";
+		}
+
+		# use the lower case, for speed of lookup.
+		my $meta_lc=lc($metavalue);
+		$self->{'classifiers'}->{$meta_lc}
+		= { 'classifyobj'   => $listclassobj,
+		    'formattednode' => $formatted_node };
+	    }
+	}
+    }
+
+
+    return (\@single_classlist,\@multiple_classlist);
+}
+
+
+sub reclassify 
+{
+    my ($self,$multiple_cl_ref) = @_;
+
+    # Entries in the current classify list that are "book nodes"
+    # should be recursively classified.
+    #--
+    foreach my $dm_pair (@$multiple_cl_ref) 
+    {
+	my ($doc_OID,$mdoffset,$metavalue,$cs_metavalue) = @$dm_pair;
+        my $listclassobj;
+
+	# find metavalue in list of sub-classifiers
+	# check if we have a key (lower case) for this metadata value
+	my $node_name=lc($metavalue);
+	if (exists $self->{'classifiers'}->{$node_name})
+	{
+	    my ($doc_obj, $sortmeta) = @{$self->{'reclassify'}->{$doc_OID}};
+
+	    # record the metadata value offset temporarily, so eg AZList can
+	    # get the correct metadata value (for multi-valued metadata fields)
+	    $doc_obj->{'mdoffset'}=$mdoffset;
+
+	    if ($doc_OID =~ m/^[^\.]*\.([\d\.]+)$/)
+	    {
+		my $section=$1;
+		if ($self->{'doclevel'} =~ m/^top/i) { # toplevel
+		    $self->{'classifiers'}->{$node_name}->{'classifyobj'}
+		    ->classify($doc_obj, "Section=$section");
+		} else { # section level
+		    # Thanks to Don Gourley for this...
+		    # classify can't handle multi-level section
+		    $self->{'classifiers'}->{$node_name}->{'classifyobj'}
+		    ->classify_section($section, $doc_obj, $sortmeta);
+		}
+	    }
+	    else
+	    {
+		$self->{'classifiers'}->{$node_name}->{'classifyobj'}
+		->classify($doc_obj); 
+	    }
+	} else { # this key is not in the hash
+	    my $outhandle=$self->{outhandle};
+	    print $outhandle "Warning: AZCompactList::reclassify ";
+	    print $outhandle "could not find sub-node for metadata=`$metavalue' with doc_OID $doc_OID\n";
+	}
+    }
+}
+
+
+
+sub get_reclassify_info 
+{
+    my $self = shift (@_);
+    
+    my $node_name;
+    foreach $node_name (keys %{$self->{'classifiers'}}) 
+    {
+        my $classifyinfo 
+	    = $self->{'classifiers'}->{$node_name}->{'classifyobj'}
+	        ->get_classify_info();
+        $self->{'classifiers'}->{$node_name}->{'classifyinfo'} 
+	    = $classifyinfo;
+        $self->{'reclassifylist'}->{"CLASSIFY.$node_name"} 
+	    = $self->{'classifiers'}->{$node_name}->{'formattednode'};
+    }
+}
+
+
+sub alpha_numeric_cmp
+{
+    my ($self,$a,$b) = @_;
+
+    my $title_a = $self->{'reclassifylist'}->{$a};
+    my $title_b = $self->{'reclassifylist'}->{$b};
+    
+    if ($title_a =~ m/^(\d+(\.\d+)?)/)
+    {
+	my $val_a = $1;
+	if ($title_b =~ m/^(\d+(\.\d+)?)/)
+	{
+	    my $val_b = $1;
+	    if ($val_a != $val_b)
+	    {
+		return ($val_a <=> $val_b);
+	    }
+	}
+    }
+    
+    return ($title_a cmp $title_b);
+}
+
+sub frequency_cmp
+{
+    my ($self,$a,$b) = @_;
+
+
+    my $title_a = $self->{'reclassifylist'}->{$a};
+    my $title_b = $self->{'reclassifylist'}->{$b};
+
+    my $a_freq = 1;
+    my $b_freq = 1;
+
+    if ($a =~ m/^CLASSIFY\.(.*)$/)
+    {
+	my $a_node = $1;
+	my $a_nodeinfo = $self->{'classifiers'}->{$a_node}->{'classifyinfo'};
+	$a_freq = scalar(@{$a_nodeinfo->{'contains'}});
+    }
+    
+    if ($b =~ m/^CLASSIFY\.(.*)$/)
+    {
+	my $b_node = $1;
+	my $b_nodeinfo = $self->{'classifiers'}->{$b_node}->{'classifyinfo'};
+	$b_freq = scalar(@{$b_nodeinfo->{'contains'}});
+    }
+
+    return $b_freq <=> $a_freq;
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my @classlist =keys %{$self->{'list_mvpair'}}; # list all doc oids
+
+    my ($single_cl_ref,$multiple_cl_ref) = $self->reinit(\@classlist);
+    $self->reclassify($multiple_cl_ref);
+    $self->get_reclassify_info();
+
+    my @reclassified_classlist;
+    if ($self->{'freqsort'})
+    {
+	@reclassified_classlist 
+	    = sort { $self->frequency_cmp($a,$b) } keys %{$self->{'reclassifylist'}};
+	# supress sub-grouping by alphabet
+	map { $self->{'reclassifylist'}->{$_} = "A".$self->{'reclassifylist'}; } keys %{$self->{'reclassifylist'}};
+    }
+    else
+    {
+#	@reclassified_classlist 
+#	    = sort {$self->{'reclassifylist'}->{$a} cmp $self->{'reclassifylist'}->{$b};} keys %{$self->{'reclassifylist'}};
+
+	# alpha_numeric_cmp is slower than "cmp" but handles numbers better ...
+
+	@reclassified_classlist
+	    = sort { $self->alpha_numeric_cmp($a,$b) } keys %{$self->{'reclassifylist'}};
+
+    }
+
+    return $self->splitlist (\@reclassified_classlist);
+}
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $metaname, $thistype) = @_;
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+                        'Title'=>$title,
+                        'contains'=>[],
+			'mdtype'=>$metaname);
+
+    $classifyinfo{'thistype'} = $thistype
+        if defined $thistype && $thistype =~ /\w/;
+
+    return \%classifyinfo;
+}
+
+
+
+# splitlist takes an ordered list of classifications (@$classlistref) and 
+# splits it up into alphabetical sub-sections.
+sub splitlist {
+    my $self = shift (@_);
+    my ($classlistref) = @_;
+    my $classhash = {};
+
+    # top level
+    my @metanames = split(/\/|\|/,$self->{'metadata'});
+    my $metaname = shift(@metanames);
+
+    my $childtype = "HList";
+    $childtype = "VList" if (scalar (@$classlistref) <= $self->{'minnesting'});
+
+    my $title = $self->{'buttonname'}; # should always be defined by now.
+    my $classifyinfo;
+    if (!defined($self->{'recopt'}))
+    {
+	$classifyinfo 
+	    = $self->get_entry ($title, $childtype, $metaname, "Invisible");
+    }
+    else
+    {
+	$classifyinfo 
+	    = $self->get_entry ($title, $childtype, $metaname, "VList");
+    }
+
+    # don't need to do any splitting if there are less than 'minnesting' classifications
+    if ((scalar @$classlistref) <= $self->{'minnesting'}) {
+	foreach my $subOID (@$classlistref) {
+            if ($subOID =~ /^CLASSIFY\.(.*)$/ 
+		&& defined $self->{'classifiers'}->{$1}) 
+	    {
+                push (@{$classifyinfo->{'contains'}}, 
+		      $self->{'classifiers'}->{$1}->{'classifyinfo'});
+            } 
+	    else 
+	    {
+		$subOID =~ s/^Metavalue_(\d+)\.//;
+		my $metaname_offset = $1 -1;
+		my $oid_rec = {'OID'=>$subOID, 'offset'=>$metaname_offset};
+		push (@{$classifyinfo->{'contains'}}, $oid_rec);
+	    }
+	}
+	return $classifyinfo;
+    }
+	
+    # first split up the list into separate A-Z and 0-9 classifications
+    foreach my $classification (@$classlistref) {
+	my $title = $self->{'reclassifylist'}->{$classification};
+	$title =~ s/&(.){2,4};//g; # remove any HTML special chars
+	$title =~ s/^\W+//g; # remove leading non-word chars
+
+	# only want first character for classification
+	$title =~ m/^(.)/; # always a char, or first byte of wide char?
+	if (defined($1) && $1 ne "") {
+	    $title=$1;
+	} else {
+	    print STDERR "no first character found for \"$title\" - \"" .
+		$self->{'reclassifylist'}->{$classification} . "\"\n";
+	}
+	$title =~ tr/[a-z]/[A-Z]/;
+
+	if ($title =~ /^[0-9]$/) {$title = '0-9';}
+	elsif ($title !~ /^[A-Z]$/) {
+	    my $outhandle = $self->{'outhandle'};
+	    print $outhandle "AZCompactList: WARNING $classification has badly formatted title ($title)\n";
+	}
+	$classhash->{$title} = [] unless defined $classhash->{$title};
+	push (@{$classhash->{$title}}, $classification);
+    }
+    $classhash = $self->compactlist ($classhash);
+
+    my @tmparr = ();
+    foreach my $subsection (sort keys (%$classhash)) {
+	push (@tmparr, $subsection);
+    }
+    
+    # if there's a 0-9 section it will have been sorted to the beginning
+    # but we want it at the end
+    if ($tmparr[0] eq '0-9') {
+	shift @tmparr;
+	push (@tmparr, '0-9');
+    }
+    foreach my $subclass (@tmparr) 
+    {
+	my $tempclassify 
+	    = (scalar(@tmparr)==1) 
+		? ($self->get_entry(" ", "VList", $metaname))
+		: ($self->get_entry($subclass, "VList", $metaname));
+
+
+	foreach my $subsubOID (@{$classhash->{$subclass}}) 
+	{
+            if ($subsubOID =~ /^CLASSIFY\.(.*)$/ 
+		&& defined $self->{'classifiers'}->{$1}) 
+	    {
+		# this is a "bookshelf" node... >1 entry compacted
+                push (@{$tempclassify->{'contains'}}, 
+		      $self->{'classifiers'}->{$1}->{'classifyinfo'});
+		# set the metadata field name, for mdoffset to work
+		$self->{'classifiers'}->{$1}->{'classifyinfo'}->{'mdtype'}=
+		    $metaname;
+	    }
+	    else
+	    {
+		$subsubOID =~ s/^Metavalue_(\d+)\.//;
+		# record the offset if this metadata type has multiple values
+		my $metaname_offset = $1 -1;
+		my $oid_rec = {'OID'=>$subsubOID, 'offset'=>$metaname_offset};
+		push (@{$tempclassify->{'contains'}}, $oid_rec);
+	    }
+	}
+	push (@{$classifyinfo->{'contains'}}, $tempclassify);
+    }
+
+    return $classifyinfo;
+}
+
+sub compactlist {
+    my $self = shift (@_);
+    my ($classhashref) = @_;
+    my $compactedhash = {};
+    my @currentOIDs = ();
+    my $currentfirstletter = "";
+    my $currentlastletter = "";
+    my $lastkey = "";
+
+    # minimum and maximum documents to be displayed per page.
+    # the actual maximum will be max + (min-1).
+    # the smallest sub-section is a single letter at present
+    # so in this case there may be many times max documents
+    # displayed on a page.
+    my $min = $self->{'mincompact'}; 
+    my $max = $self->{'maxcompact'};
+
+    foreach my $subsection (sort keys %$classhashref) {
+	if ($subsection eq '0-9') {
+	    @{$compactedhash->{$subsection}} = @{$classhashref->{$subsection}};
+	    next;
+	}
+	$currentfirstletter = $subsection if $currentfirstletter eq "";
+	if ((scalar (@currentOIDs) < $min) ||
+	    ((scalar (@currentOIDs) + scalar (@{$classhashref->{$subsection}})) <= $max)) {
+	    push (@currentOIDs, @{$classhashref->{$subsection}});
+	    $currentlastletter = $subsection;
+	} else {
+
+	    if ($currentfirstletter eq $currentlastletter) {
+		@{$compactedhash->{$currentfirstletter}} = @currentOIDs;
+		$lastkey = $currentfirstletter;
+	    } else {
+		@{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
+		$lastkey = "$currentfirstletter-$currentlastletter";
+	    } 
+	    if (scalar (@{$classhashref->{$subsection}}) >= $max) {
+		$compactedhash->{$subsection} = $classhashref->{$subsection};
+		@currentOIDs = ();
+		$currentfirstletter = "";
+		$lastkey=$subsection;
+	    } else {
+		@currentOIDs = @{$classhashref->{$subsection}};
+		$currentfirstletter = $subsection;
+		$currentlastletter = $subsection;
+	    }
+	}
+    }
+
+    # add final OIDs to last sub-classification if there aren't many otherwise
+    # add final sub-classification
+
+    # don't add if there aren't any oids
+    if (! scalar (@currentOIDs)) {return $compactedhash;}
+
+    if (scalar (@currentOIDs) < $min) {
+	my ($newkey) = $lastkey =~ /^(.)/;
+	@currentOIDs = (@{$compactedhash->{$lastkey}}, @currentOIDs);
+	delete $compactedhash->{$lastkey};
+	@{$compactedhash->{"$newkey-$currentlastletter"}} = @currentOIDs;
+    } else {
+	if ($currentfirstletter eq $currentlastletter) {
+	    @{$compactedhash->{$currentfirstletter}} = @currentOIDs;
+	} else {
+	    @{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
+	} 
+    }
+
+    return $compactedhash;
+}
+
+1;
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZCompactSectionList.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZCompactSectionList.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZCompactSectionList.pm	(revision 10506)
@@ -0,0 +1,234 @@
+###########################################################################
+#
+# AZCompactSectionList.pm --
+#
+# Experimental AZCompactList with fixes to handle section-level metadata
+#
+###########################################################################
+
+package AZCompactSectionList;
+
+use AZCompactList;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @AZCompactSectionList::ISA = ('AZCompactList');
+}
+
+my $arguments = [
+		 ];
+my $options = 
+{ 	'name'     => "AZCompactSectionList",
+	'desc'     => "{AZCompactSectionList.desc}",
+	'abstract' => "no",
+	'inherits' => "yes",
+	'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new AZCompactList($classifierslist,$inputargs,$hashArgOptLists): new AZCompactList($classifierslist,$inputargs);
+
+    return bless $self, $class;
+}
+
+#
+# override reinit() & reclassify() to demonstrate possible bug fixes
+# (search for SECTIONFIX? to see lines changed from AZCompactList.pm)
+#
+sub reinit 
+{
+    my ($self,$classlist_ref) = @_;
+    
+    my %mtfreq = ();
+    my @single_classlist = ();
+    my @multiple_classlist = ();
+
+    # find out how often each metavalue occurs
+    map 
+    { 
+	my $mv;
+	foreach $mv (@{$self->{'listmetavalue'}->{$_}} )
+	{
+	    $mtfreq{$mv}++; 
+	}
+    } @$classlist_ref;
+
+    # use this information to split the list: single metavalue/repeated value
+    map
+    { 
+	my $i = 1;
+	my $metavalue;
+	foreach $metavalue (@{$self->{'listmetavalue'}->{$_}})
+	{
+	    if ($mtfreq{$metavalue} >= $self->{'mingroup'})
+	    {
+		push(@multiple_classlist,[$_,$i,$metavalue]); 
+	    } 
+	    else
+	    {
+		push(@single_classlist,[$_,$metavalue]); 
+		$metavalue =~ tr/[A-Z]/[a-z]/;
+		$self->{'reclassifylist'}->{"Metavalue_$i.$_"} = $metavalue;
+	    }
+	    $i++;
+	}
+    } @$classlist_ref;
+    
+    
+    # Setup sub-classifiers for multiple list
+
+    $self->{'classifiers'} = {};
+
+    my $pm;
+    foreach $pm ("List", "SectionList")
+    {
+	my $listname 
+	    = &util::filename_cat($ENV{'GSDLHOME'},"perllib/classify/$pm.pm");
+	if (-e $listname) { require $listname; }
+	else 
+	{ 
+	    my $outhandle = $self->{'outhandle'};
+	    print $outhandle "AZCompactList ERROR - couldn't find classifier \"$listname\"\n"; 
+	    die "\n";
+	}
+    }
+
+    # Create classifiers objects for each entry >= mingroup
+    my $metavalue;
+    foreach $metavalue (keys %mtfreq)
+    {
+	if ($mtfreq{$metavalue} >= $self->{'mingroup'})
+	{
+	    my $listclassobj;
+	    my $doclevel = $self->{'doclevel'};
+	    my $metaname  = $self->{'metaname'};
+	    my @metaname_list = split('/',$metaname);
+	    $metaname = shift(@metaname_list);
+	    if (@metaname_list==0)
+	    {
+		my @args;
+		push @args, ("-metadata", "$metaname");
+# buttonname is also used for the node's title
+		push @args, ("-buttonname", "$metavalue");
+		push @args, ("-sort", $self->{'sort'});
+
+		my $ptArgs = \@args;
+		if ($doclevel =~ m/^top(level)?/i)
+		{
+		    eval ("\$listclassobj = new List([],\$ptArgs)"); warn $@ if $@;
+		}
+		else
+		{
+		    # SECTIONFIX?
+		    #eval ("\$listclassobj = new SectionList($args)");
+		    eval ("\$listclassobj = new SectionList([],\$ptArgs)");
+		}
+	    }
+	    else
+	    {
+		$metaname = join('/',@metaname_list);
+		
+		my @args;
+		push @args, ("-metadata", "$metaname");
+# buttonname is also used for the node's title
+		push @args, ("-buttonname", "$metavalue");
+		push @args, ("-doclevel", "$doclevel");
+		push @args, "-recopt";
+
+		# SECTIONFIX?
+		#eval ("\$listclassobj = new AZCompactList($args)");
+		my $ptArgs = \@args;
+		eval ("\$listclassobj = new AZCompactList([],\$ptArgs)");
+	    }
+	    if ($@) {
+		my $outhandle = $self->{'outhandle'};
+		print $outhandle "$@";
+		die "\n";
+	    }
+	    
+	    $listclassobj->init();
+
+	    if (defined $metavalue && $metavalue =~ /\w/) 
+	    {
+		my $formatted_node = $metavalue;
+		if ($self->{'metaname'} =~ m/^Creator(:.*)?$/)
+		{
+		    &sorttools::format_string_name_en(\$formatted_node);
+		} 
+		else 
+		{
+		    &sorttools::format_string_en(\$formatted_node);
+		}
+		
+		$self->{'classifiers'}->{$metavalue} 
+		= { 'classifyobj'   => $listclassobj,
+		    'formattednode' => $formatted_node };
+	    }
+	}
+    }
+
+
+    return (\@single_classlist,\@multiple_classlist);
+}
+
+
+sub reclassify 
+{
+    my ($self,$multiple_cl_ref) = @_;
+
+    # Entries in the current classify list that are "book nodes"
+    # should be recursively classified.
+    #--
+    foreach my $dm_pair (@$multiple_cl_ref) 
+    {
+	my ($doc_OID,$mdoffset,$metavalue) = @$dm_pair;
+        my $listclassobj;
+
+	# find metavalue in list of sub-classifiers
+	my $found = 0;
+	my $node_name;
+	foreach $node_name (keys %{$self->{'classifiers'}}) 
+	{
+	    my $resafe_node_name = $node_name;
+	    $resafe_node_name =~ s/(\(|\)|\[|\]|\{|\}|\^|\$|\.|\+|\*|\?|\|)/\\$1/g;
+	    if ($metavalue =~ m/^$resafe_node_name$/i) 
+	    {
+		my ($doc_obj, $sortmeta) = @{$self->{'reclassify'}->{$doc_OID}};
+
+		# SECTIONFIX?  section must include multiple levels, e.g. '1.12'
+		#if ($doc_OID =~ m/^.*\.(\d+)$/)
+		if ($doc_OID =~ m/^[^\.]*\.([\d\.]+)$/)
+		{
+		    $self->{'classifiers'}->{$node_name}->{'classifyobj'}
+		    # SECTIONFIX? classify can't handle multi-level section
+		    #->classify($doc_obj, "Section=$1"); 
+		    ->classify_section($1, $doc_obj, $sortmeta);
+		}
+		else
+		{
+		    $self->{'classifiers'}->{$node_name}->{'classifyobj'}
+		    ->classify($doc_obj); 
+		}
+		
+		$found = 1;
+		last;
+	    }
+	}
+	
+	if (!$found)
+	{
+	    my $outhandle = $self->{'outhandle'};
+	    print $outhandle "Warning: AZCompactList::reclassify ";
+	    print $outhandle "could not find sub-node for $metavalue with doc_OID $doc_OID\n";
+	}
+    }
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZList.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZList.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZList.pm	(revision 10506)
@@ -0,0 +1,367 @@
+###########################################################################
+#
+# AZList.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# classifier plugin for sorting alphabetically
+
+package AZList;
+
+use BasClas;
+use sorttools;
+use iso639;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @AZList::ISA = ('BasClas');
+}
+
+
+my $arguments =
+    [ { 'name' => "metadata",
+	'desc' => "{AZList.metadata}",
+	'type' => "metadata",
+	'reqd' => "yes" } ,
+      { 'name' => "buttonname",
+  	'desc' => "{BasClas.buttonname}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "removeprefix",
+	'desc' => "{BasClas.removeprefix}",
+	'type' => "regexp",
+	'deft' => "",
+	'reqd' => "no" } ,
+      { 'name' => "removesuffix",
+	'desc' => "{BasClas.removesuffix}",
+	'type' => "regexp",
+	'deft' => "",
+	'reqd' => "no" } 
+      ];
+
+my $options = { 'name'     => "AZList",
+		'desc'     => "{AZList.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasClas($classifierslist,$inputargs,$hashArgOptLists): new BasClas($classifierslist,$inputargs);
+
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+
+    if (!$self->{"metadata"}) {
+	print STDERR "AZList Error: required option -metadata not supplied \n";
+	$self->print_txt_usage("");  # Use default resource bundle
+	
+	die "AZList Error: required option -metadata not supplied\n";
+    }
+        
+    # Manually set $self parameters.
+    $self->{'list'} = {};
+
+    # Transfer value from Auto Parsing to the variavle name that used in previous GreenStone.
+    my @meta_list = split(/,/, $self->{"metadata"});
+    $self->{'meta_list'} = \@meta_list;
+
+    $self->{'buttonname'} = $self->generate_title_from_metadata($self->{'metadata'}) unless ($self->{'buttonname'});
+
+    # Further setup 
+    if (defined($self->{"removeprefix"}) && $self->{"removeprefix"}) {
+	$self->{"removeprefix"} =~ s/^\^//; # don't need a leading ^
+    }
+    if (defined($self->{"removesuffix"}) && $self->{"removesuffix"}) {
+	$self->{"removesuffix"} =~ s/\$$//; # don't need a trailing $
+    }
+
+    # Clean out the unused keys
+    delete $self->{"metadata"}; # Delete this key
+
+    if($self->{"removeprefix"} eq "") {delete $self->{"removeprefix"};}
+    if($self->{"removesuffix"} eq "") {delete $self->{"removesuffix"};}
+
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    $self->{'list'} = {};
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    my $outhandle = $self->{'outhandle'};
+
+    my $metavalue;
+    my $metaname;
+    # should we extend this to use all available metadata not just the first?
+    if (!defined $self->{'meta_list'}) {
+	# just in case
+	return;
+    }
+
+    # find the first available metadata
+    foreach my $m (@{$self->{'meta_list'}}) {
+	$metavalue = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $m);
+	$metaname = $m;
+	last if defined $metavalue;
+    } 
+    
+    #if we haven't found a metavalue here, then the doc shouldn't be included
+    if (!defined $metavalue || $metavalue eq "") {
+	print $outhandle "WARNING: AZList: $doc_OID metadata is empty - not classifying\n";
+	return;
+    }
+
+    if (defined($self->{'removeprefix'}) &&
+	length($self->{'removeprefix'})) {
+	$metavalue =~ s/^$self->{'removeprefix'}//;
+    }
+    if (defined($self->{'removesuffix'}) &&
+	length($self->{'removesuffix'})) {
+	$metavalue =~ s/$self->{'removesuffix'}$//;
+    }
+    
+    $metavalue = &sorttools::format_metadata_for_sorting($metaname, $metavalue, $doc_obj);
+	
+    if (defined $self->{'list'}->{$doc_OID}) {
+	print $outhandle "WARNING: AZList::classify called multiple times for $doc_OID\n";
+    } 
+    if ($metavalue) {
+	$self->{'list'}->{$doc_OID} = $metavalue;
+    } else {
+	# the formatting has made it empty
+	my $outhandle = $self->{'outhandle'};
+	print $outhandle "WARNING: AZList: $doc_OID metadata has become empty - not classifying\n";
+    }
+    
+}
+
+sub alpha_numeric_cmp
+{
+    my ($self,$a,$b) = @_;
+
+    my $title_a = $self->{'list'}->{$a};
+    my $title_b = $self->{'list'}->{$b};
+
+    if ($title_a =~ m/^(\d+(\.\d+)?)/)
+    {
+	my $val_a = $1;
+	if ($title_b =~ m/^(\d+(\.\d+)?)/)
+	{
+	    my $val_b = $1;
+	    if ($val_a != $val_b)
+	    {
+		return ($val_a <=> $val_b);
+	    }
+	}
+    }
+    
+    return ($title_a cmp $title_b);
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my @classlist 
+	= sort { $self->alpha_numeric_cmp($a,$b) } keys %{$self->{'list'}};
+
+    return $self->splitlist (\@classlist);
+}
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $thistype) = @_;
+    
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+			'Title'=>$title,
+			'contains'=>[]);
+    $classifyinfo{'thistype'} = $thistype 
+	if defined $thistype && $thistype =~ /\w/;
+
+    return \%classifyinfo;
+}
+
+# splitlist takes an ordered list of classifications (@$classlistref) and splits it
+# up into alphabetical sub-sections.
+sub splitlist {
+    my $self = shift (@_);
+    my ($classlistref) = @_;
+    my $classhash = {};
+
+    # top level
+    my $childtype = "HList";
+    if (scalar (@$classlistref) <= 39) {$childtype = "VList";}
+    my $classifyinfo = $self->get_entry ($self->{'buttonname'}, $childtype, "Invisible");
+
+    # don't need to do any splitting if there are less than 39 (max + min -1) classifications
+    if ((scalar @$classlistref) <= 39) {
+	foreach my $subOID (@$classlistref) {
+	    push (@{$classifyinfo->{'contains'}}, {'OID'=>$subOID});
+	}
+	return $classifyinfo;
+    }
+	
+    # first split up the list into separate A-Z and 0-9 classifications
+    foreach my $classification (@$classlistref) {
+	my $title = $self->{'list'}->{$classification};
+
+	$title =~ s/^(&.{1,6};|<[^>]>|[^a-zA-Z0-9])//g; # remove any unwanted stuff
+	# only need first char for classification
+	$title =~ m/^(.)/; $title=$1;
+	$title =~ tr/[a-z]/[A-Z]/;
+	if ($title =~ /^[0-9]$/) {$title = '0-9';}
+	elsif ($title !~ /^[A-Z]$/) {
+	    my $outhandle = $self->{'outhandle'};
+	    print $outhandle "AZList: WARNING $classification has badly formatted title ($title)\n";
+	}
+	$classhash->{$title} = [] unless defined $classhash->{$title};
+	push (@{$classhash->{$title}}, $classification);
+    }
+    $classhash = $self->compactlist ($classhash);
+
+    my @tmparr = ();
+    foreach my $subsection (sort keys (%$classhash)) {
+	push (@tmparr, $subsection);
+    }
+    #if there is only one entry here, we suppress the buckets
+    if ((scalar @tmparr) == 1) {
+	$classifyinfo->{'childtype'} = "VList";
+	foreach my $OID (@{$classhash->{$tmparr[0]}}) {
+	    push (@{$classifyinfo->{'contains'}}, {'OID'=>$OID});
+	}
+	return $classifyinfo;
+    }
+    
+    # if there's a 0-9 section it will have been sorted to the beginning
+    # but we want it at the end
+    if ($tmparr[0] eq '0-9') {
+	shift @tmparr;
+	push (@tmparr, '0-9');
+    }
+
+    foreach my $subclass (@tmparr) {
+	my $tempclassify = $self->get_entry($subclass, "VList");
+	foreach my $subsubOID (@{$classhash->{$subclass}}) {
+	    push (@{$tempclassify->{'contains'}}, {'OID'=>$subsubOID});
+	}
+	push (@{$classifyinfo->{'contains'}}, $tempclassify);
+    }
+
+    return $classifyinfo;
+}
+
+sub compactlist {
+    my $self = shift (@_);
+    my ($classhashref) = @_;
+    my $compactedhash = {};
+    my @currentOIDs = ();
+    my $currentfirstletter = "";  # start of working bin
+    my $currentlastletter = "";   # end of working bin
+    my $lastkey = "";             # the name of the last completed key
+
+    # minimum and maximum documents to be displayed per page.
+    # the actual maximum will be max + (min-1).
+    # the smallest sub-section is a single letter at present
+    # so in this case there may be many times max documents
+    # displayed on a page.
+    my $min = 10; 
+    my $max = 30;
+
+    foreach my $subsection (sort keys %$classhashref) {
+	if ($subsection eq '0-9') {
+	    # leave this bin as-is... copy it straight across
+	    @{$compactedhash->{$subsection}} = @{$classhashref->{$subsection}};
+	    next;
+	}
+	$currentfirstletter = $subsection if $currentfirstletter eq "";
+	if ((scalar (@currentOIDs) < $min) ||
+	    ((scalar (@currentOIDs) + scalar (@{$classhashref->{$subsection}})) <= $max)) {
+	    # add this letter to the bin and continue
+	    push (@currentOIDs, @{$classhashref->{$subsection}});
+	    $currentlastletter = $subsection;
+	} else {
+	    # too many or too few for a separate bin
+	    if ($currentfirstletter eq $currentlastletter) {
+		@{$compactedhash->{$currentfirstletter}} = @currentOIDs;
+		$lastkey = $currentfirstletter;
+	    } else {
+		@{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
+		$lastkey = "$currentfirstletter-$currentlastletter";
+	    } 
+	    if (scalar (@{$classhashref->{$subsection}}) >= $max) {
+		# this key is now complete. Start a new one
+		$compactedhash->{$subsection} = $classhashref->{$subsection};
+		@currentOIDs = ();
+		$currentfirstletter = "";
+		$lastkey = $subsection;
+	    } else {
+		@currentOIDs = @{$classhashref->{$subsection}};
+		$currentfirstletter = $subsection;
+		$currentlastletter = $subsection;
+	    }
+	}
+    }
+
+    # add final OIDs to last sub-classification if there aren't many otherwise
+    # add final sub-classification
+    # BUG FIX: don't add anything if there are no currentOIDs (thanks to Don Gourley)
+    if (! scalar(@currentOIDs)) {return $compactedhash;}
+
+    if (scalar (@currentOIDs) < $min) {
+	my ($newkey) = $lastkey =~ /^(.)/;
+	@currentOIDs = (@{$compactedhash->{$lastkey}}, @currentOIDs);
+	delete $compactedhash->{$lastkey};
+	@{$compactedhash->{"$newkey-$currentlastletter"}} = @currentOIDs;
+    } else {
+	if ($currentfirstletter eq $currentlastletter) {
+	    @{$compactedhash->{$currentfirstletter}} = @currentOIDs;
+	}
+	else {
+	    @{$compactedhash->{"$currentfirstletter-$currentlastletter"}} =
+		@currentOIDs;
+	}
+    }
+
+    return $compactedhash;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZSectionList.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZSectionList.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AZSectionList.pm	(revision 10506)
@@ -0,0 +1,124 @@
+###########################################################################
+#
+# AZSectionList.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# classifier plugin for sorting sections alphabetically
+
+# this is very similar to AZList except it sorts by
+# section level metadata (excluding the top level)
+# instead of just top level metadata
+
+# the only change is to the classify() subroutine which 
+# must now iterate through each section, adding each
+# to the classification
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package AZSectionList;
+
+use AZList;
+use sorttools;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @AZSectionList::ISA = ('AZList');
+}
+
+my $arguments = [
+		 ];
+my $options = { 'name'     => "AZSectionList",
+		'desc'     => "{AZSectionList.desc}",
+		'abstract' => "no",
+		'inherits' => "yes" }; 
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new AZList($classifierslist,$inputargs,$hashArgOptLists): new AZList($classifierslist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    my $thissection = $doc_obj->get_next_section ($doc_obj->get_top_section());
+
+    while (defined $thissection) {
+	$self->classify_section ($thissection, $doc_obj);
+	$thissection = $doc_obj->get_next_section ($thissection);
+    }
+}
+
+sub classify_section {
+    my $self = shift (@_);
+    my ($section, $doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+
+    my $metavalue;
+    my $metaname;
+
+    if (!defined $self->{'meta_list'}) {
+	# just in case
+	return;
+    }
+
+    # find the first available metadata
+    foreach my $m (@{$self->{'meta_list'}}) {
+	$metavalue = $doc_obj->get_metadata_element($section, $m);
+	$metaname = $m;
+	last if defined $metavalue;
+    } 
+
+    # if this section doesn't contain the metadata element we're
+    # sorting by we won't include it in this classification
+
+    if (defined $metavalue && $metavalue ne "") {
+	if ($self->{'removeprefix'}) {
+	    $metavalue =~ s/^$self->{'removeprefix'}//;
+	}
+	
+	$metavalue = &sorttools::format_metadata_for_sorting($metaname, $metavalue, $doc_obj);
+	if (defined $self->{'list'}->{"$doc_OID.$section"}) {
+	    my $outhandle = $self->{'outhandle'};
+	    print $outhandle "WARNING: AZSectionList::classify called multiple times " .
+		"for $doc_OID.$section\n";
+	} 
+	$self->{'list'}->{"$doc_OID.$section"} = $metavalue;
+    }
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AllList.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AllList.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/AllList.pm	(revision 10506)
@@ -0,0 +1,85 @@
+package AllList;
+
+use BasClas;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @AllList::ISA = ('BasClas');
+}
+
+my $arguments = 
+    [
+     ];
+
+my $options = { 'name'     => "AllList",
+	        'abstract' => "no",
+	        'inherits' => "yes" };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasClas($classifierslist,$inputargs,$hashArgOptLists): new BasClas($classifierslist,$inputargs);
+    
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+
+    # Manually set $self parameters.
+    $self->{'list'} = [];
+    $self->{'buttonname'} = "All Documents";
+
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    
+    push (@{$self->{'list'}}, $doc_OID);
+
+    return;
+}
+
+sub get_classify_info {
+    my $self = shift(@_);
+    my ($no_thistype) = @_;
+
+    my %classifyinfo = ('childtype'   =>'VList',
+			'Title'       =>$self->{'buttonname'},
+			'contains'    =>[],
+			'classifyOID' =>"oai");
+    $classifyinfo{'thistype'} = 'Invisible';
+    my @list = @{$self->{'list'}};
+
+    my $seqNo = 0;
+    foreach my $OID (@list) {
+	my $hashref={};
+	$hashref->{'OID'}=$OID;
+       
+	my %tempinfo=('childtype'=>'VList',
+		      'Title'=>$self->{'buttonname'},
+		      'classifyOID' =>"oai.$seqNo",
+		      'contains'    =>[]);
+
+	push (@{$tempinfo{'contains'}}, $hashref);
+
+	push (@{$classifyinfo{'contains'}}, \%tempinfo);
+	$seqNo ++;
+    }
+
+    return \%classifyinfo;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/BasClas.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/BasClas.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/BasClas.pm	(revision 10506)
@@ -0,0 +1,323 @@
+###########################################################################
+#
+# BasClas.pm -- base class for all classifiers
+#
+# 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.
+#
+###########################################################################
+
+package BasClas;
+
+# How a classifier works.  
+#
+# For each classifier requested in the collect.cfg file, buildcol.pl creates
+# a new classifier object (a subclass of BasClas).  Later, it passes each 
+# document object to each classifier in turn for classification.
+#
+# Four primary functions are used:
+#
+# 1. "new" is called before the documents are processed to set up the
+#    classifier.
+#
+# 2. "init" is called after buildcol.pl has created the indexes etc but
+#    before the documents are classified in order that the classifier might
+#    set any variables it requires, etc.
+#
+# 3. "classify" is called once for each document object.  The classifier
+#    "classifies" each document and updates its local data accordingly.
+#
+# 4. "get_classify_info" is called after every document has been
+#    classified.  It collates the information about the documents and
+#    stores a reference to the classifier so that Greenstone can later
+#    display it.
+
+# 09/05/02 Added usage datastructure - John Thompson
+# 28/11/03 Commented out verbosity argument - John Thompson
+
+use gsprintf;
+use printusage;
+use parse2;
+
+# suppress the annoying "subroutine redefined" warning that various
+# classifiers cause under perl 5.6
+$SIG{__WARN__} = sub {warn($_[0]) unless ($_[0] =~ /Subroutine\s+\S+\sredefined/)};
+
+use strict;
+no strict 'subs'; # allow barewords (eg STDERR) as function arguments
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+my $arguments = 
+    [ { 'name' => "builddir",
+	'desc' => "{BasClas.builddir}",
+	'type' => "string",
+	'deft' => "" },
+      { 'name' => "outhandle",
+	'desc' => "{BasClas.outhandle}",
+	'type' => "string",
+	'deft' => "STDERR" },
+      { 'name' => "verbosity",
+	'desc' => "{BasClas.verbosity}",
+#	'type' => "enum",
+	'type' => "int",
+	'deft' => "2",
+	'reqd' => "no" },
+#      { 'name' => "ignore_namespace",
+#	'desc' => "{BasClas.ignore_namespace}",
+#	'type' => "flag"} 
+      ];
+
+my $options = { 'name'     => "BasClas",
+		'desc'     => "{BasClas.desc}",
+		'abstract' => "yes",
+		'inherits' => "no",
+		'args'     => $arguments };
+
+
+sub gsprintf
+{
+    return &gsprintf::gsprintf(@_);
+}
+
+
+sub print_xml_usage
+{
+    my $self = shift(@_);
+
+    # XML output is always in UTF-8
+    &gsprintf::output_strings_in_UTF8;
+
+    &PrintUsage::print_xml_header();
+    $self->print_xml();
+}
+
+
+sub print_xml
+{
+    my $self = shift(@_);
+
+    my $optionlistref = $self->{'option_list'};
+    my @optionlist = @$optionlistref;
+    my $classifieroptions = shift(@$optionlistref);
+    return if (!defined($classifieroptions));
+
+    &gsprintf(STDERR, "<ClassInfo>\n");
+    &gsprintf(STDERR, "  <Name>$classifieroptions->{'name'}</Name>\n");
+    my $desc = &gsprintf::lookup_string($classifieroptions->{'desc'});
+    $desc =~ s/</&amp;lt;/g; # doubly escaped
+    $desc =~ s/>/&amp;gt;/g;
+    &gsprintf(STDERR, "  <Desc>$desc</Desc>\n");
+    &gsprintf(STDERR, "  <Abstract>$classifieroptions->{'abstract'}</Abstract>\n");
+    &gsprintf(STDERR, "  <Inherits>$classifieroptions->{'inherits'}</Inherits>\n");
+    &gsprintf(STDERR, "  <Arguments>\n");
+    if (defined($classifieroptions->{'args'})) {
+	&PrintUsage::print_options_xml($classifieroptions->{'args'});
+    }
+
+    # Recurse up the classifier hierarchy
+    $self->print_xml();
+
+    &gsprintf(STDERR, "  </Arguments>\n");
+    &gsprintf(STDERR, "</ClassInfo>\n");
+}
+
+
+sub print_txt_usage
+{
+    my $self = shift(@_);
+
+    # Print the usage message for a classifier (recursively)
+    my $descoffset = $self->determine_description_offset(0);
+    $self->print_classifier_usage($descoffset, 1);
+}
+
+
+sub determine_description_offset
+{
+    my $self = shift(@_);
+    my $maxoffset = shift(@_);
+
+    my $optionlistref = $self->{'option_list'};
+    my @optionlist = @$optionlistref;
+    my $classifieroptions = pop(@$optionlistref);
+    return $maxoffset if (!defined($classifieroptions));
+
+    # Find the length of the longest option string of this classifier
+    my $classifierargs = $classifieroptions->{'args'};
+    if (defined($classifierargs)) {
+	my $longest = &PrintUsage::find_longest_option_string($classifierargs);
+	if ($longest > $maxoffset) {
+	    $maxoffset = $longest;
+	}
+    }
+
+    # Recurse up the classifier hierarchy
+    $maxoffset = $self->determine_description_offset($maxoffset);
+    $self->{'option_list'} = \@optionlist;
+    return $maxoffset;
+}
+
+
+sub print_classifier_usage
+{
+    my $self = shift(@_);
+    my $descoffset = shift(@_);
+    my $isleafclass = shift(@_);
+
+    my $optionlistref = $self->{'option_list'};
+    my @optionlist = @$optionlistref;
+    my $classifieroptions = shift(@$optionlistref);
+    return if (!defined($classifieroptions));
+
+    my $classifiername = $classifieroptions->{'name'};
+    my $classifierargs = $classifieroptions->{'args'};
+    my $classifierdesc = $classifieroptions->{'desc'};
+    # Produce the usage information using the data structure above
+    if ($isleafclass) {
+	if (defined($classifierdesc)) {
+	    &gsprintf(STDERR, "$classifierdesc\n\n");
+	}
+	&gsprintf(STDERR, " {common.usage}: classify $classifiername [{common.options}]\n\n");
+	
+    }
+
+    # Display the classifier options, if there are some
+    if (defined($classifierargs)) {
+	# Calculate the column offset of the option descriptions
+	my $optiondescoffset = $descoffset + 2;  # 2 spaces between options & descriptions
+
+	if ($isleafclass) {
+	    &gsprintf(STDERR, " {common.specific_options}:\n");
+	}
+	else {
+	    &gsprintf(STDERR, " {common.general_options}:\n", $classifiername);
+	}
+
+	# Display the classifier options
+	&PrintUsage::print_options_txt($classifierargs, $optiondescoffset);
+    }
+
+    # Recurse up the classifier hierarchy
+    $self->print_classifier_usage($descoffset, 0);
+    $self->{'option_list'} = \@optionlist;
+}
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$args,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+    my $classifier_name = (defined $classifierslist->[0]) ? $classifierslist->[0] : $class;
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+
+    # Manually set $self parameters.
+    my $self = {};
+    $self->{'outhandle'} = STDERR;
+    $self->{'idnum'} = -1;
+    $self->{'option_list'} = $hashArgOptLists->{"OptList"};
+    $self->{"info_only"} = 0;
+
+    # Check if gsdlinfo is in the argument list or not - if it is, don't parse 
+    # the args, just return the object.  
+    foreach my $strArg (@{$args})
+    {
+	if($strArg eq "-gsdlinfo")
+	{
+	    $self->{"info_only"} = 1;
+	    return bless $self, $class;
+	}
+    }
+
+    # general options available to all classifiers
+    if(!parse2::parse($args,$hashArgOptLists->{"ArgList"},$self))
+    {
+	#print out the text usage of this classifier. 
+	my $classTempClass = bless $self, $class;
+	&gsprintf(STDERR, "\n{BasClas.bad_general_option}\n", $classifier_name);
+	$classTempClass->print_txt_usage("");  # Use default resource bundle
+	die "\n";
+    }
+    
+    delete $self->{"info_only"};
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    $self->{'supportsmemberof'} = &supports_memberof();
+}
+
+sub set_number {
+    my $self = shift (@_);
+    my ($id)   = @_;
+    $self->{'idnum'} = $id;
+}
+
+sub get_number {
+    my $self = shift (@_);
+    return $self->{'idnum'};
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+    &gsprintf($outhandle, "BasClass::classify {common.must_be_implemented}\n");
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my $outhandle = $self->{'outhandle'};
+    &gsprintf($outhandle, "BasClass::get_classify_info {common.must_be_implemented}\n");
+}
+
+sub supports_memberof {
+    my $self = shift(@_);
+
+    return "false";
+}
+
+# previously, if a buttonname wasn't specified, we just use the metadata value,
+# but with a list of metadata, we want to do something a bit nicer so that
+# eg -metadata dc.Title,Title will end up with Title as the buttonname
+
+# current algorithm - use the first element, but strip its namespace
+sub generate_title_from_metadata {
+    
+    my $self = shift (@_);
+    my $metadata = shift (@_);
+
+    return "" unless defined $metadata && $metadata =~ /\S/;
+    
+    my @metalist = split(/,/, $metadata);
+    my $firstmeta = $metalist[0];
+    if ($firstmeta =~ /\./) {
+	$firstmeta =~ s/^\w+\.//;
+    }
+    return $firstmeta; 
+}
+
+1; 
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Browse.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Browse.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Browse.pm	(revision 10506)
@@ -0,0 +1,101 @@
+###########################################################################
+#
+# List.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package Browse;
+
+use BasClas;
+use sorttools;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @Browse::ISA = ('BasClas');
+}
+
+my $arguments = [
+		 ];
+my $options = { 'name'     => "Browse",
+		'desc'     => "{Browse.desc}",
+		'abstract' => "yes",
+		'inherits' => "yes" };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasClas($classifierslist,$inputargs,$hashArgOptLists): new BasClas($classifierslist,$inputargs);
+
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+
+    # Manually set $self parameters.
+    $self->{'collection'} = $ENV{'GSDLCOLLECTION'}; # classifier information
+    $self->{'buttonname'} = "Browse";
+
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    
+}
+
+sub classify {
+    my $self = shift (@_);
+   
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+  
+
+    # Return the information about the classifier that we'll later want to
+    # use to create macros when the Phind classifier document is displayed.
+    my %classifyinfo = ('thistype'=>'Invisible', 
+                        'Title'=>$self->{'buttonname'},
+			'contains'=>[]);
+    
+    my $collection = $self->{'collection'};
+    my $url = "library?a=br&c=collection";
+    push (@{$classifyinfo{'contains'}}, {'OID'=>$url});
+   
+    return \%classifyinfo;
+
+ 
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Collage.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Collage.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Collage.pm	(revision 10506)
@@ -0,0 +1,263 @@
+##########################################################################
+#
+# Collage.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package Collage;
+
+use BasClas;
+use sorttools;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @Collage::ISA = ('BasClas');
+}
+
+my $arguments = 
+    [ { 'name' => "buttonname",
+  	'desc' => "{Collage.buttonname}",
+	'type' => "string",
+	'deft' => "Collage",
+	'reqd' => "no" }, 
+      { 'name' => "geometry",
+  	'desc' => "{Collage.geometry}",
+	'type' => "string",
+	'deft' => "600x300",
+	'reqd' => "no" },
+      { 'name' => "verbosity",
+  	'desc' => "{BasClas.verbosity}",
+	'type' => "string",
+	'deft' => "5",
+	'reqd' => "no" },
+      { 'name' => "maxDepth",
+  	'desc' => "{Collage.maxDepth}",
+	'type' => "string",
+	'deft' => "500"},
+#      { 'name' => "maxDownloads",
+#  	'desc' => "{BasClas.maxDownloads}",
+#	'type' => "string",
+#	'deft' => "",
+#	'reqd' => "no" },
+      { 'name' => "maxDisplay",
+  	'desc' => "{Collage.maxDisplay}",
+	'type' => "string",
+	'deft' => "25",
+	'reqd' => "no" },
+      { 'name' => "imageType",
+  	'desc' => "{Collage.imageType}",
+	'type' => "string",
+	'deft' => ".jpg%%.png",
+	'reqd' => "no" },
+      { 'name' => "bgcolor",
+  	'desc' => "{Collage.bgcolor}",
+	'type' => "string",
+	'deft' => "#96c29a",
+	'reqd' => "no" },
+      { 'name' => "refreshDelay",
+  	'desc' => "{Collage.refreshDelay}",
+	'type' => "string",
+	'deft' => "1500",
+	'reqd' => "no" },
+      { 'name' => "isJava2",
+  	'desc' => "{Collage.isJava2}",
+	'type' => "string",
+	'deft' => "auto",
+	'reqd' => "no" },
+      { 'name' => "imageMustNotHave",
+  	'desc' => "{Collage.imageMustNotHave}",
+	'type' => "string",
+	'deft' => "hl=%%x=%%gt=%%gc=%%.pr",
+	'reqd' => "no" },
+      { 'name' => "caption",
+  	'desc' => "{Collage.caption}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" }
+      ];
+
+
+
+
+my $options = { 'name'     => "Collage",
+		'desc'     => "{Collage.desc}",
+		'abstract' => "no",
+		'inherits' => "Yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasClas($classifierslist,$inputargs,$hashArgOptLists): new BasClas($classifierslist,$inputargs);
+    
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+
+    # Manually set $self parameters.
+    $self->{'list'} = {};
+    $self->{'buttonname'} = 'Collage' unless ($self->{'buttonname'});
+
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    $self->{'list'} = [];
+}
+
+sub classify {
+   
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $has_image_type = 0;
+
+    my @image_type_split = split(/%/,$self->{'imageType'});
+    my @image_type_ext = map { "($_)" } @image_type_split;
+    my $image_type_re = join("|",@image_type_ext);
+    $image_type_re =~ s/\./\\\./g;
+
+    my $assoc_files = $doc_obj->{'associated_files'};
+
+    foreach my $af ( @$assoc_files ) {
+	my ($real_filename, $assoc_filename, $mime_type, $section) = @$af;
+	if ($assoc_filename =~ m/$image_type_re/) {
+	    $has_image_type = 1;
+	    last;
+	}
+    }
+
+    if ($has_image_type) {
+	my $doc_OID = $doc_obj->get_OID();
+	push (@{$self->{'list'}}, $doc_OID);
+    }
+
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+    
+    my $items_per_page = 2; 
+    my $max_items_per_page = 20;
+
+    my @list      = @{$self->{'list'}};
+
+    my $outhandle = $self->{'outhandle'};
+    my $verbosity = $self->{'verbosity'};
+
+    if ($verbosity>1) {
+	print $outhandle ("$self->{'buttonname'}\n");
+    }
+
+    my $collage_head = $self->get_entry ($self->{'buttonname'}, "Collage", "Invisible");
+    my $collage_curr = $self->get_entry("Collage","VList");
+    push (@{$collage_head->{'contains'}},$collage_curr);
+
+    my $global_c=1;
+    my $within_page_c=1;
+
+    foreach my $oid (@list) {
+	if ($within_page_c>$items_per_page) {
+	    my $title = "Items $global_c+";
+	    my $nested_node = $self->get_entry($title,"VList");
+	    push (@{$collage_curr->{'contains'}}, $nested_node);
+	    $collage_curr = $nested_node;
+
+	    $within_page_c=1;
+	    
+	    $items_per_page++ if ($items_per_page < $max_items_per_page);
+	}
+
+	push (@{$collage_curr->{'contains'}}, {'OID'=>$oid});
+	$global_c++;
+	$within_page_c++;
+    }
+   
+    return $collage_head;
+}
+
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $thistype) = @_;
+
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+			'Title'=>$title,
+			'contains'=>[]);
+
+    $classifyinfo{'thistype'} = $thistype if (defined $thistype);
+
+    if ($childtype eq "Collage") {
+	my $geometry = $self->{'geometry'};
+	my ($x_dim,$y_dim) = ($geometry =~ m/^(.*)x(.*)$/);
+	my $verbosity = $self->{'verbosity'};
+	my $maxDepth = $self->{'maxDepth'};
+#	my $maxDownloads = $self->{'maxDownloads'};
+	my $maxDisplay = $self->{'maxDisplay'};
+	my $imageType = $self->{'imageType'};
+	my $bgcolor = $self->{'bgcolor'};
+	my $refreshDelay = $self->{'refreshDelay'};
+	my $isJava2 = $self->{'isJava2'};
+	my $imageMustNotHave = $self->{'imageMustNotHave'};
+	my $caption = $self->{'caption'};
+	
+	#if (!defined($maxDownloads)) {
+	#    $maxDownloads="";
+	#}
+
+	my $parameters;
+
+	$parameters = "xdim=".$x_dim;
+	$parameters .= ";ydim=".$y_dim;
+	$parameters .= ";geometry=".$self->{'geometry'};
+	$parameters .= ";verbosity=".$self->{'verbosity'};
+	$parameters .= ";maxDepth=".$self->{'maxDepth'};
+#	$parameters .= ";maxDownloads=".$maxDownloads;
+	$parameters .= ";maxDisplay=".$self->{'maxDisplay'};
+	$parameters .= ";imageType=".$self->{'imageType'};
+	$parameters .= ";bgcolor=".$self->{'bgcolor'};
+	$parameters .= ";refreshDelay=".$self->{'refreshDelay'};
+	$parameters .= ";isJava2=".$self->{'isJava2'};
+	$parameters .= ";caption=".$self->{'caption'};
+
+#	$parameters .= ";imageMustNotHave=".$self->{'imageMustNotHave'};
+
+    
+	$classifyinfo{'parameters'} = $parameters;
+    }
+
+    return \%classifyinfo;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/DateList.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/DateList.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/DateList.pm	(revision 10506)
@@ -0,0 +1,332 @@
+###########################################################################
+#
+# DateList.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# classifier plugin for sorting by date
+
+# date is assumed to be in the form yyyymmdd
+
+# at present dates are split by year - this should change
+# jrm21 - added option "bymonth", which splits by year and month.
+
+# 23/09/03 Added some more options -kjdon.
+# these include:
+# -nogroup, which makes each year (or year+month) an individual entry in 
+# the horizontal list and prevents compaction
+# -metadata, use a different metadata for the date (instead of Date), still expects yyyymmdd format. this affects display cos greenstone displays Date metadata as dd month yyyy, whereas any other date metadata is displayed as yyyymmdd - this needs fixing
+# -sort specifies an additional metadata to use in sorting, will take affect when two docs have the same date.
+
+package DateList;
+
+use BasClas;
+use sorttools;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @DateList::ISA = ('BasClas');
+}
+
+my $arguments =
+    [ { 'name' => "metadata",
+        'desc' => "{DateList.metadata}",
+        'type' => "metadata",
+	'deft' => "Date",
+        'reqd' => "no" } ,
+      { 'name' => "sort",
+        'desc' => "{DateList.sort}",
+        'type' => "metadata",
+	'reqd' => "no" } ,
+      { 'name' => "reverse_sort",
+	'desc' => "{DateList.reverse_sort}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "bymonth",
+	'desc' => "{DateList.bymonth}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "nogroup",
+	'desc' => "{DateList.nogroup}",
+	'type' => "flag",
+	'reqd' => "no" }
+      ];
+
+my $options = { 'name'     => "DateList",
+		'desc'     => "{DateList.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasClas($classifierslist,$inputargs,$hashArgOptLists): new BasClas($classifierslist,$inputargs);
+
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+
+    # Manually set $self parameters.
+    $self->{'list'} = {};
+
+    if (!defined $self->{"metadata"} || $self->{"metadata"} eq "") {
+	$self->{'metadata'} = "Date";
+    }
+    
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    $self->{'list'} = {};
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    my $date = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), $self->{'metadata'});
+    
+    my $sort_other = "";
+    if (defined $self->{'sort'} && $self->{'sort'} ne "") {
+	$sort_other = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), $self->{'sort'});
+	$sort_other = &sorttools::format_metadata_for_sorting($self->{'sort'}, $sort_other, $doc_obj);
+    }
+    # if this document doesn't contain Date element we won't 
+    # include it in this classification
+    if (defined $date && $date =~ /\d/) {
+	if (defined $self->{'list'}->{$doc_OID}) {
+	    my $outhandle = $self->{'outhandle'};
+	    print $outhandle "WARNING: DateList::classify called multiple times for $doc_OID\n";
+	} 
+
+	$self->{'list'}->{$doc_OID} = "$date$sort_other";
+    }
+}
+
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my @classlist = sort {$self->{'list'}->{$a} cmp $self->{'list'}->{$b};} keys %{$self->{'list'}};
+    if ($self->{'reverse_sort'}) {
+	@classlist = reverse @classlist;
+    }
+
+    return $self->splitlist (\@classlist);
+}
+
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $thistype) = @_;
+    
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+			'Title'=>$title,
+			'contains'=>[],
+			'mdtype'=>$self->{'metadata'});
+    $classifyinfo{'thistype'} = $thistype 
+	if defined $thistype && $thistype =~ /\w/;
+
+    return \%classifyinfo;
+}
+
+# splitlist takes an ordered list of classifications (@$classlistref) and
+# splits it up into sub-sections by date
+sub splitlist {
+    my $self = shift (@_);
+    my ($classlistref) = @_;
+    my $classhash = {};
+
+    # top level
+    my $childtype = "HList";
+
+    if (scalar (@$classlistref) <= 39 &&
+	!$self->{'nogroup'}) {$childtype = "DateList";}
+    my $classifyinfo = $self->get_entry ("Date", $childtype, "Invisible");
+    # don't need to do any splitting if there are less than 39 (max + min -1)
+    # classifications, unless nogroup is specified
+    if ((scalar @$classlistref) <= 39 && !$self->{'nogroup'}) {
+	foreach my $subOID (@$classlistref) {
+	    push (@{$classifyinfo->{'contains'}}, {'OID'=>$subOID});
+	}
+	return $classifyinfo;
+    }
+
+
+    if ($self->{'bymonth'}) {
+	# first split up the list into separate year+month classifications
+
+	if (!$self->{'nogroup'}) { # hlist of year+month pairs
+	    # single level of classifications
+	    foreach my $classification (@$classlistref) {
+		my $date = $self->{'list'}->{$classification};
+		$date =~ s/^(\d\d\d\d)(\d\d).*$/$1&nbsp;_textmonth$2_/;
+		# sanity check if month is zero
+		if ($date =~ /00_$/) {
+		    $date =~ s/^(\d\d\d\d).*$/$1/g;
+		}
+		$classhash->{$date} = [] unless defined $classhash->{$date};
+		push (@{$classhash->{$date}}, $classification);
+	    }
+	    
+	} else { # don't group - individual years and months
+	    foreach my $classification (@$classlistref) {
+		my $date = $self->{'list'}->{$classification};
+		$date =~ s/^(\d\d\d\d)(\d\d).*$/$1&nbsp;_textmonth$2_/;
+		my ($year, $month)=($1,$2);
+		# sanity check if month is zero
+		if ($date =~ /00_$/) {
+		    $date =~ s/^(\d\d\d\d).*$/$1/g;
+		}
+		# create subclass if it doesn't already exist
+		$classhash->{$year} = () unless defined $classhash->{$year};
+		$classhash->{$year}->{$month} = []
+		    unless defined $classhash->{$year}->{$month};
+		push (@{$classhash->{$year}->{$month}}, $classification);
+	    }
+	    # create hlist of years containing hlists of months
+
+	    foreach my $subclass (sort {$a <=> $b} keys %$classhash) {
+		my $yearclassify = $self->get_entry($subclass, "HList");
+		foreach my $subsubclass (sort {$a <=> $b} 
+					 (keys %{$classhash->{$subclass}})) {
+		    my $monthname=$subsubclass;
+		    if ($monthname >= 1 && $monthname <= 12) {
+			$monthname="_textmonth" . $monthname . "_";
+		    }
+		    my $monthclassify=$self->get_entry($monthname, "DateList");
+		    push (@{$yearclassify->{'contains'}}, $monthclassify);
+		
+		    foreach my $subsubOID 
+			(@{$classhash->{$subclass}->{$subsubclass}}) {
+			    push (@{$monthclassify->{'contains'}},
+				  {'OID'=>$subsubOID});
+			}
+		}
+		push (@{$classifyinfo->{'contains'}}, $yearclassify);
+	    }
+	    return $classifyinfo;
+	} # nogroup
+    } else {
+	# not by month
+	# first split up the list into separate year classifications
+	foreach my $classification (@$classlistref) {
+	    my $date = $self->{'list'}->{$classification};
+	    $date =~ s/^(\d\d\d\d).*$/$1/;
+	    $classhash->{$date} = [] unless defined $classhash->{$date};
+	    push (@{$classhash->{$date}}, $classification);
+	}
+    }
+    
+    # only compact the list if nogroup not specified
+    if (!$self->{'nogroup'}) {
+	$classhash = $self->compactlist ($classhash);
+    }
+    foreach my $subclass (sort keys %$classhash) {
+	my $tempclassify = $self->get_entry($subclass, "DateList");
+	foreach my $subsubOID (@{$classhash->{$subclass}}) {
+	    push (@{$tempclassify->{'contains'}}, {'OID'=>$subsubOID});
+	}
+	push (@{$classifyinfo->{'contains'}}, $tempclassify);
+    }
+
+    return $classifyinfo;
+}
+
+sub compactlist {
+    my $self = shift (@_);
+    my ($classhashref) = @_;
+    my $compactedhash = {};
+    my @currentOIDs = ();
+    my $currentfirstdate = "";
+    my $currentlastdate = "";
+    my $lastkey = "";
+
+    # minimum and maximum documents to be displayed per page.
+    # the actual maximum will be max + (min-1).
+    # the smallest sub-section is a single letter at present
+    # so in this case there may be many times max documents
+    # displayed on a page.
+    my $min = 10; 
+    my $max = 30;
+    foreach my $subsection (sort keys %$classhashref) {
+	$currentfirstdate = $subsection if $currentfirstdate eq "";
+	if ((scalar (@currentOIDs) < $min) ||
+	    ((scalar (@currentOIDs) + scalar (@{$classhashref->{$subsection}})) <= $max)) {
+	    push (@currentOIDs, @{$classhashref->{$subsection}});
+	    $currentlastdate = $subsection;
+	} else {
+
+	    if ($currentfirstdate eq $currentlastdate) {
+		@{$compactedhash->{$currentfirstdate}} = @currentOIDs;
+		$lastkey = $currentfirstdate;
+	    } else {
+		@{$compactedhash->{"$currentfirstdate-$currentlastdate"}} = @currentOIDs;
+		$lastkey = "$currentfirstdate-$currentlastdate";
+	    } 
+	    if (scalar (@{$classhashref->{$subsection}}) >= $max) {
+		$compactedhash->{$subsection} = $classhashref->{$subsection};
+		@currentOIDs = ();
+		$currentfirstdate = "";
+		$lastkey = $subsection;
+	    } else {
+		@currentOIDs = @{$classhashref->{$subsection}};
+		$currentfirstdate = $subsection;
+		$currentlastdate = $subsection;
+	    }
+	}
+    }
+
+    # add final OIDs to last sub-classification if there aren't many otherwise
+    # add final sub-classification
+    if ((scalar (@currentOIDs) < $min) && (scalar (@currentOIDs) > 0)) {
+	# want every thing in previous up to the dash
+	my ($newkey) = $lastkey =~ /^([^\-]+)/;
+	@currentOIDs = (@{$compactedhash->{$lastkey}}, @currentOIDs);
+	delete $compactedhash->{$lastkey};
+	@{$compactedhash->{"$newkey-$currentlastdate"}} = @currentOIDs;	
+    } else {
+	if ($currentfirstdate eq $currentlastdate) {
+	    @{$compactedhash->{$currentfirstdate}} = @currentOIDs;
+	} else {
+	    @{$compactedhash->{"$currentfirstdate-$currentlastdate"}} = @currentOIDs;
+	} 
+    }
+
+    return $compactedhash;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/GenericList.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/GenericList.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/GenericList.pm	(revision 10506)
@@ -0,0 +1,494 @@
+###########################################################################
+#
+# GenericList.pm -- A general and flexible list classifier with most of
+#                   the abilities of AZCompactList, and better Unicode,
+#                   metadata and sorting capabilities.
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
+#
+# Copyright (C) 2005 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# TO DO: Remove punctuation from metadata values before sorting.
+#
+###########################################################################
+
+package GenericList;
+
+
+use BasClas;
+
+use strict;
+no strict 'refs';  # Allow filehandles to be variables and viceversa
+
+
+sub BEGIN {
+    @GenericList::ISA = ('BasClas');
+}
+
+
+my $arguments = 
+    [ { 'name' => "metadata",
+	'desc' => "{GenericList.metadata}",
+	'type' => "metadata",
+	'reqd' => "yes" },
+      { 'name' => "buttonname",
+  	'desc' => "{BasClas.buttonname}",
+	'type' => "string" },
+
+      # The interesting options
+      { 'name' => "always_bookshelf_last_level",
+	'desc' => "{GenericList.always_bookshelf_last_level}",
+	'type' => "flag" },
+      { 'name' => "classify_sections",
+	'desc' => "{GenericList.classify_sections}",
+	'type' => "flag" },
+      { 'name' => "partition_type_within_level",
+	'desc' => "{GenericList.partition_type_within_level}",
+	'type' => "string",
+	'deft' => "none" },
+      { 'name' => "partition_size_within_level",
+	'desc' => "{GenericList.partition_size_within_level}",
+	'type' => "string" },
+      { 'name' => "sort_leaf_nodes_using",
+	'desc' => "{GenericList.sort_leaf_nodes_using}",
+	'type' => "metadata",
+	'deft' => "Title" },
+      { 'name' => "use_hlist_for",
+	'desc' => "{GenericList.use_hlist_for}",
+	'type' => "string" } ];
+
+my $options = { 'name'     => "GenericList",
+		'desc'     => "{GenericList.desc}",
+		'abstract' => "no",
+		'inherits' => "Yes",
+		'args'     => $arguments };
+
+
+sub new
+{
+    my ($class) = shift(@_);
+    my ($classifierslist, $inputargs, $hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if (defined $arguments) { push(@{$hashArgOptLists->{"ArgList"}}, @{$arguments}); }
+    if (defined $options) { push(@{$hashArgOptLists->{"OptList"}}, $options); }
+
+    my $self = (defined $hashArgOptLists) ? new BasClas($classifierslist, $inputargs, $hashArgOptLists) : new BasClas($classifierslist, $inputargs);
+    $self->{'OIDlist'} = [];
+
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+
+    my $metadata = $self->{'metadata'};
+    my $buttonname = $self->{'buttonname'};
+    my $partition_type_within_level = $self->{'partition_type_within_level'};
+    my $partition_size_within_level = $self->{'partition_size_within_level'};
+    my $sort_leaf_nodes_using = $self->{'sort_leaf_nodes_using'};
+    my $use_hlist_for = $self->{'use_hlist_for'};
+
+    # The metadata elements to use (required)
+    # print STDERR "Creating new GenericList for $metadata...\n";
+    if (!$metadata) {
+	die "Error: No metadata fields specified for GenericList.\n";
+    }
+    my @metalist = split(/\//, $metadata);
+    $self->{'metalist'} = \@metalist;
+
+    # The classifier button name
+    if (!$buttonname) {
+	# Default: the first metadata element specified
+	my $firstmetagroupfirstelem = (split(/\;/, $metalist[0]))[0];
+	$buttonname = $self->generate_title_from_metadata($firstmetagroupfirstelem);
+    }
+    $self->{'title'} = $buttonname;
+
+    # Whether to group single items into a bookshelf (must be true for all metadata fields except the last)
+    foreach my $metagroup (@metalist) {
+	$self->{$metagroup . ".always_bookshelf"} = "t";
+    }
+    if (!$self->{'always_bookshelf_last_level'}) {
+	# Default: leave leafnodes ungrouped (equivalent to AZCompactList -mingroup 2)
+	my $lastmetagroup = $metalist[$#metalist];
+	$self->{$lastmetagroup . ".always_bookshelf"} = "f";
+    }
+
+    # Whether to use an hlist or a vlist for each level in the hierarchy
+    foreach my $metagroup (@metalist) {
+	$self->{$metagroup . ".use_hlist"} = "f";
+    }
+    foreach my $metagroup (split(/\,/, $use_hlist_for)) {
+	$self->{$metagroup . ".use_hlist"} = "t";
+    }
+
+    # How the items are grouped into partitions
+    if (!$partition_type_within_level) {
+	# Default: none
+	$partition_type_within_level = "none";
+    }
+    $self->{"partition_type_within_level"} = $partition_type_within_level;
+
+    # The number of items in each partition
+    if (!$partition_size_within_level) {
+	# Default: 20
+	foreach my $metagroup (@metalist) {
+	    $self->{$metagroup . ".partition_size_within_level"} = 20;
+	}
+    }
+    else {
+	my @partition_size_within_levellist = split(/\//, $partition_size_within_level);
+
+	# Assign values based on the partition_size_within_level parameter
+	foreach my $metagroup (@metalist) {
+	    my $partition_size_within_levelelem = shift(@partition_size_within_levellist);
+	    if (defined($partition_size_within_levelelem)) {
+		$self->{$metagroup . ".partition_size_within_level"} = $partition_size_within_levelelem;
+	    }
+	    else {
+		$self->{$metagroup . ".partition_size_within_level"} = $self->{$metalist[0] . ".partition_size_within_level"};
+	    }
+	}
+    }
+
+    # The metadata elements to use to sort the leaf nodes
+    my @sort_leaf_nodes_usingmetalist = ( "Title" );
+    if ($sort_leaf_nodes_using) {
+	@sort_leaf_nodes_usingmetalist = split(/\|/, $sort_leaf_nodes_using);
+    }
+    $self->{'sort_leaf_nodes_usingmetalist'} = \@sort_leaf_nodes_usingmetalist;
+
+    return bless $self, $class;
+}
+
+
+sub init
+{
+    # Nothing to do...
+}
+
+
+sub classify
+{
+    my $self = shift(@_);
+    my $doc_obj = shift(@_);
+
+    my $doc_OID = $doc_obj->get_OID();
+
+    if ($self->{'classify_sections'}) {
+	my $section = $doc_obj->get_next_section($doc_obj->get_top_section());
+	while (defined $section) {
+	    $self->classify_section($doc_obj, $doc_OID . ".$section", $section);
+	    $section = $doc_obj->get_next_section($section);
+	}
+    }
+    else {
+	$self->classify_section($doc_obj, $doc_OID, $doc_obj->get_top_section());
+    }
+}
+
+
+sub classify_section
+{
+    my $self = shift(@_);
+    my $doc_obj = shift(@_);
+    my $doc_OID = shift(@_);
+    my $section = shift(@_);
+
+    my @metalist = @{$self->{'metalist'}};
+
+    # Only classify the document if it has a value for one of the metadata elements in the first group
+    foreach my $firstmetagroupelem (split(/\;/, $metalist[0])) {
+	my $firstmetagroupelemvalue = $doc_obj->get_metadata_element($section, $firstmetagroupelem);
+	if (defined($firstmetagroupelemvalue) && $firstmetagroupelemvalue ne "") {
+	    push(@{$self->{'OIDlist'}}, $doc_OID);
+
+	    # Create a hash for the metadata values of each metadata element we're interested in
+	    my %metagroupsdone = ();
+	    foreach my $metagroup (@metalist, @{$self->{'sort_leaf_nodes_usingmetalist'}}) {
+		# Take care not to do a metadata group more than once
+		unless ($metagroupsdone{$metagroup}) {
+		    foreach my $metaelem (split(/\;/, $metagroup)) {
+			my @metavalues = @{$doc_obj->get_metadata($section, $metaelem)};
+			foreach my $metavalue (@metavalues) {
+			    # Strip leading and trailing whitespace
+			    $metavalue =~ s/^\s*//;
+			    $metavalue =~ s/\s*$//;
+			    push(@{$self->{$metagroup . ".list"}->{$doc_OID}}, $metavalue);
+			}
+			last if (@metavalues > 0);
+		    }
+
+		    $metagroupsdone{$metagroup} = 1;
+		}
+	    }
+
+	    last;
+	}
+    }
+}
+
+
+sub get_classify_info
+{
+    my $self = shift(@_);
+
+    # The metadata elements to classify by
+    my @metalist = @{$self->{'metalist'}};
+    my $firstmetagroup = $metalist[0];
+
+    # The OID values of the documents to include in the classification
+    my @OIDlist = @{$self->{'OIDlist'}};
+
+    # The root node of the classification hierarchy
+    my $childtype = (($self->{$firstmetagroup . ".use_hlist"} eq "t") ? "HList" : "VList");
+    my %classifyinfo = ( 'thistype' => "Invisible",
+			 'childtype' => $childtype,
+			 'Title' => $self->{'title'},
+			 'contains' => [] );
+
+    # Recursively create the classification hierarchy, one level for each metadata element
+    &add_az_list($self, \@metalist, \@OIDlist, \%classifyinfo);
+    return \%classifyinfo;
+}
+
+
+sub add_az_list
+{
+    my $self = shift(@_);
+    my @metalist = @{shift(@_)};
+    my @OIDlist = @{shift(@_)};
+    my $classifyinfo = shift(@_);
+    # print STDERR "\nAdding AZ list for " . $classifyinfo->{'Title'} . "\n";
+
+    my $metagroup = $metalist[0];
+    # print STDERR "Processing metadata group: " . $metagroup . "\n";
+    # print STDERR "Number of OID values: " . @OIDlist . "\n";
+
+    my %OIDtometavaluehash = %{$self->{$metagroup . ".list"}};
+
+    # Create a mapping from metadata value to OID
+    my %metavaluetoOIDhash = ();
+    foreach my $OID (@OIDlist) {
+	if ($OIDtometavaluehash{$OID}) {
+	    my @metavalues = @{$OIDtometavaluehash{$OID}};
+	    foreach my $metavalue (@metavalues) {
+		push(@{$metavaluetoOIDhash{$metavalue}}, $OID);
+	    }
+	}
+    }
+    # print STDERR "Number of distinct values: " . scalar(keys %metavaluetoOIDhash) . "\n";
+
+    # Partition the values (if necessary)
+    my $partition_type_within_level = $self->{"partition_type_within_level"};
+    if ($partition_type_within_level =~ /^per_letter$/i) {
+	# Generate one hlist for each letter
+	my @sortedmetavalues = sort(keys %metavaluetoOIDhash);
+	my %metavaluetoOIDsubhash = ();
+
+	my $lastpartition = &unicode::substr($sortedmetavalues[0], 0, 1);
+	foreach my $metavalue (@sortedmetavalues) {
+	    my $metavaluepartition = &unicode::substr($metavalue, 0, 1);
+
+	    # Is this the start of a new partition?
+	    if ($metavaluepartition ne $lastpartition) {
+		&add_hlist_partition($self, \@metalist, $classifyinfo, $lastpartition, \%metavaluetoOIDsubhash);
+		%metavaluetoOIDsubhash = ();
+		$lastpartition = $metavaluepartition;
+	    }
+
+	    $metavaluetoOIDsubhash{$metavalue} = $metavaluetoOIDhash{$metavalue};	    
+	}
+
+	# Don't forget to add the last partition
+	&add_hlist_partition($self, \@metalist, $classifyinfo, $lastpartition, \%metavaluetoOIDsubhash);
+
+	# The partitions are stored in an HList
+	$classifyinfo->{'childtype'} = "HList";
+    }
+
+    else {
+	# Generate hlists of a certain size
+	my $partition_size_within_level = $self->{$metagroup . ".partition_size_within_level"};
+	if ($partition_type_within_level =~ /^constant_size$/i && scalar(keys %metavaluetoOIDhash) > $partition_size_within_level) {
+	    my @sortedmetavalues = sort(keys %metavaluetoOIDhash);
+	    my $itemsdone = 0;
+	    my %metavaluetoOIDsubhash = ();
+	    my $lastpartitionend = "";
+	    my $partitionstart;
+	    foreach my $metavalue (@sortedmetavalues) {
+		$metavaluetoOIDsubhash{$metavalue} = $metavaluetoOIDhash{$metavalue};
+		$itemsdone++;
+		my $itemsinpartition = scalar(keys %metavaluetoOIDsubhash);
+
+		# Is this the start of a new partition?
+		if ($itemsinpartition == 1) {
+		    $partitionstart = &generate_partition_start($metavalue, $lastpartitionend);
+		}
+
+		# Is this the end of the partition?
+		if ($itemsinpartition == $partition_size_within_level || $itemsdone == @sortedmetavalues) {
+		    my $partitionend = &generate_partition_end($metavalue, $partitionstart);
+		    my $partitionname = $partitionstart;
+		    if ($partitionend ne $partitionstart) {
+			$partitionname = $partitionname . "-" . $partitionend;
+		    }
+
+		    &add_hlist_partition($self, \@metalist, $classifyinfo, $partitionname, \%metavaluetoOIDsubhash);
+		    %metavaluetoOIDsubhash = ();
+		    $lastpartitionend = $partitionend;
+		}
+	    }
+
+	    # The partitions are stored in an HList
+	    $classifyinfo->{'childtype'} = "HList";
+	}
+
+	# Otherwise just add all the values to a VList
+	else {
+	    &add_vlist($self, \@metalist, $classifyinfo, \%metavaluetoOIDhash);
+	}
+    }
+}
+
+
+sub unicode_length
+{
+    my $utf8string = shift(@_);
+
+    my @unicodestring = @{&unicode::utf82unicode($utf8string)};
+    return scalar(@unicodestring);
+}
+
+
+sub generate_partition_start
+{
+    my $metavalue = shift(@_);
+    my $lastpartitionend = shift(@_);
+
+    my $partitionstart = &unicode::substr($metavalue, 0, 1);
+    if ($partitionstart le $lastpartitionend) {
+	$partitionstart = &unicode::substr($metavalue, 0, 2);
+	# Give up after three characters
+	if ($partitionstart le $lastpartitionend) {
+	    $partitionstart = &unicode::substr($metavalue, 0, 3);
+	}
+    }
+
+    return $partitionstart;
+}
+
+
+sub generate_partition_end
+{
+    my $metavalue = shift(@_);
+    my $partitionstart = shift(@_);
+
+    my $partitionend = &unicode::substr($metavalue, 0, &unicode_length($partitionstart));
+    if ($partitionend gt $partitionstart) {
+	$partitionend = &unicode::substr($metavalue, 0, 1);
+	if ($partitionend le $partitionstart) {
+	    $partitionend = &unicode::substr($metavalue, 0, 2);
+	    # Give up after three characters
+	    if ($partitionend le $partitionstart) {
+		$partitionend = &unicode::substr($metavalue, 0, 3);
+	    }
+	}
+    }
+
+    return $partitionend;
+}
+
+
+sub add_hlist_partition
+{
+    my $self = shift(@_);
+    my @metalist = @{shift(@_)};
+    my $classifyinfo = shift(@_);
+    my $partitionname = shift(@_);
+    my %metavaluetoOIDhash = %{shift(@_)};
+
+    # Create an hlist partition
+    my %subclassifyinfo = ( 'Title' => $partitionname,
+			    'childtype' => "VList",
+			    'contains' => [] );
+
+    # Add the children to the hlist partition
+    &add_vlist($self, \@metalist, \%subclassifyinfo, \%metavaluetoOIDhash);
+    push(@{$classifyinfo->{'contains'}}, \%subclassifyinfo);
+}
+
+
+sub add_vlist
+{
+    my $self = shift(@_);
+    my @metalist = @{shift(@_)};
+    my $classifyinfo = shift(@_);
+    my %metavaluetoOIDhash = %{shift(@_)};
+
+    my $metagroup = shift(@metalist);
+
+    # Create an entry in the vlist for each value
+    foreach my $metavalue (sort(keys %metavaluetoOIDhash)) {
+	my @OIDlist = @{$metavaluetoOIDhash{$metavalue}};
+
+	# If there is only one item and 'always_bookshelf' is false, add the item to the list
+	if (@OIDlist == 1 && $self->{$metagroup . ".always_bookshelf"} eq "f") {
+	    push(@{$classifyinfo->{'contains'}}, { 'OID' => $OIDlist[0] });
+	}
+
+	# Otherwise create a sublist (bookshelf) for the metadata value
+	else {
+	    my %subclassifyinfo = ( 'Title' => $metavalue,
+				    'childtype' => "VList",
+				    'contains' => [] );
+
+	    # If there are metadata elements remaining, recursively apply the process
+	    if (@metalist > 0) {
+		my $nextmetagroup = $metalist[0];
+		my $childtype = (($self->{$nextmetagroup . ".use_hlist"} eq "t") ? "HList" : "VList");
+		$subclassifyinfo{'childtype'} = $childtype;
+		&add_az_list($self, \@metalist, \@OIDlist, \%subclassifyinfo);
+	    }
+	    # Otherwise just add the documents as children of this list
+	    else {
+		# Sort the leaf nodes by the metadata elements specified with -sort_leaf_nodes_using
+		my @sort_leaf_nodes_usingmetalist = @{$self->{'sort_leaf_nodes_usingmetalist'}};
+		foreach my $sort_leaf_nodes_usingmetaelem (reverse @sort_leaf_nodes_usingmetalist) {
+		    my %OIDtometavaluehash = %{$self->{$sort_leaf_nodes_usingmetaelem . ".list"}};
+		    # Force a stable sort (Perl 5.6's sort isn't stable)
+		    # !! The [0] bits aren't ideal (multiple metadata values) !! 
+		    @OIDlist = @OIDlist[ sort { $OIDtometavaluehash{$OIDlist[$a]}[0] cmp $OIDtometavaluehash{$OIDlist[$b]}[0] || $a <=> $b; } 0..$#OIDlist ];
+		}
+
+  		foreach my $OID (@OIDlist) {
+  		    push(@{$subclassifyinfo{'contains'}}, { 'OID' => $OID });
+  		}
+	    }
+
+	    # Add the sublist to the list
+	    push(@{$classifyinfo->{'contains'}}, \%subclassifyinfo);
+	}
+    }
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/HFileHierarchy.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/HFileHierarchy.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/HFileHierarchy.pm	(revision 10506)
@@ -0,0 +1,304 @@
+###########################################################################
+#
+# HFileHierarchy.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# classifier plugin for generating hierarchical classifications
+
+
+package HFileHierarchy;
+
+use BasClas;
+use util;
+use cfgread;
+use sorttools;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @HFileHierarchy::ISA = ('BasClas');
+}
+
+my $arguments =
+    [ { 'name' => "metadata",
+	'desc' => "{AZCompactList.metadata}",
+	'type' => "metadata",
+	'reqd' => "yes" },
+      { 'name' => "firstvalueonly",
+	'desc' => "{AZCompactList.firstvalueonly}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "allvalues",
+	'desc' => "{AZCompactList.allvalues}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "hfile",
+	'desc' => "{Hierarchy.hfile}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "buttonname",
+  	'desc' => "{BasClas.buttonname}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "sort",
+	'desc' => "{Hierarchy.sort}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "reverse_sort",
+	'desc' => "{Hierarchy.reverse_sort}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "hlist_at_top",
+	'desc' => "{Hierarchy.hlist_at_top}",
+	'type' => "flag",
+	'reqd' => "no" } ];
+
+my $options = 
+{ 	'name'     => "HFileHierarchy",
+	'desc'     => "{HFileHierarchy.desc}",
+	'abstract' => "yes",
+	'inherits' => "yes", 
+	'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasClas($classifierslist,$inputargs,$hashArgOptLists): new BasClas($classifierslist,$inputargs); 
+
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+
+    my $metadata = $self->{'metadata'};
+    if (!$metadata) {
+	print STDERR "$class Error: required option -metadata not supplied\n";
+	$self->print_txt_usage("");  # Use default resource bundle
+	
+	die "$class Error: required option -metadata not supplied\n";
+    }
+    
+    $self->{'buttonname'} = $self->generate_title_from_metadata($metadata) unless ($self->{'buttonname'});
+
+    #$self->{'metaname'} = $metadata;
+    my @meta_list = split(/,/, $metadata);
+    $self->{'meta_list'} = \@meta_list;
+
+    # sort = undef in this case is the same as sort=nosort
+    if ($self->{'sort'} eq "nosort") {
+	$self->{'sort'} = undef;
+    }
+
+    # sortname is handled a bit differently - kjdon
+    # undef means to sort, but use the metadata value from -metadata
+    # because there is no one metadata value to get for sorting when 
+    # we have a list of possible metadata.
+    # To get no sorting, set sortname = 'nosort'
+    # we don't need to set it to undef if its not defined do we???
+
+#    if (!$self->{'sort'}) {
+#	if (defined ($metadata)) {
+#	    $sortname = undef;
+#	} else {
+#	    $sortname = "nosort";
+#	}
+#    }
+ #   $self->{'sortname'} = $sortname;
+
+    #if (defined $self->{'sort'} && $reverse_sort) {
+#	$self->{'reverse_sort'} = 1;
+ #   }
+	
+    if ($self->{'hfile'}) {
+	my $hfile = $self->{'hfile'};
+	my $subjectfile;
+	$subjectfile = &util::filename_cat($ENV{'GSDLCOLLECTDIR'},"etc", $hfile);
+	if (!-e $subjectfile) {
+	    my $collfile = $subjectfile;
+	    $subjectfile = &util::filename_cat($ENV{'GSDLHOME'},"etc", $hfile);
+	    if (!-e $subjectfile) {
+		my $outhandle = $self->{'outhandle'};
+		print STDERR "\nHFileHierarchy Error: Can't locate subject file $hfile\n";
+		print STDERR "This file should be in $collfile or $subjectfile\n";
+		$self->print_txt_usage("");  # Use default resource bundle
+		print STDERR "\nHFileHierarchy Error: Can't locate subject file $hfile\n";
+		print STDERR "This file should be in $collfile or $subjectfile\n";
+		die "\n";
+	    }
+	}
+	$self->{'descriptorlist'} = {}; # first field in subject file
+	$self->{'locatorlist'} = {}; # second field in subject file
+	$self->{'subjectfile'} = $subjectfile;
+    }
+    
+
+   # $self->{'firstvalueonly'} = $firstvalueonly;
+   # $self->{'allvalues'} = $allvalues;
+
+    #$self->{'hlist_at_top'} = $hlist_at_top;
+
+    # Clean out the unused keys
+    delete $self->{'metadata'};
+    delete $self->{'hfile'};
+    
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+    my $subjectfile = $self->{'subjectfile'};
+    if (defined $subjectfile) {
+	# read in the subject file
+	my $list = &cfgread::read_cfg_file ($self->{'subjectfile'}, undef, '^[^#]?\S');
+	# $list is a hash that is indexed by the descriptor. The contents of this
+	# hash is a list of two items. The first item is the OID and the second item
+	# is the title
+	foreach my $descriptor (keys (%$list)) {
+	    $self->{'descriptorlist'}->{$descriptor} = $list->{$descriptor}->[0];
+	    unless (defined $self->{'locatorlist'}->{$list->{$descriptor}->[0]}) {
+		$self->{'locatorlist'}->{$list->{$descriptor}->[0]}->{'title'} = $list->{$descriptor}->[1];
+		$self->{'locatorlist'}->{$list->{$descriptor}->[0]}->{'contents'} = [];
+	    }
+	}
+    }
+}
+
+sub hfile_classify
+{
+    my $self = shift (@_);
+    my ($doc_obj,$sortmeta,$metavalues) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+
+    foreach my $metaelement (@$metavalues) {
+	if ((defined $self->{'descriptorlist'}->{$metaelement}) &&
+	    (defined $self->{'locatorlist'}->{$self->{'descriptorlist'}->{$metaelement}})) {
+	    push (@{$self->{'locatorlist'}->{$self->{'descriptorlist'}->{$metaelement}}->{'contents'}}, 
+		  [$doc_OID, $sortmeta]);
+	    my $localid = $self->{'descriptorlist'}->{$metaelement};
+	    my $classid = $self->get_number();
+
+	    $doc_obj->add_metadata($doc_obj->get_top_section(), "memberof", "CL$classid.$localid");
+	}
+    }
+}
+
+
+
+
+sub hfile_get_classify_info {
+    my $self = shift (@_);
+    
+    my ($classifyinfo) = @_;
+
+    my $list = $self->{'locatorlist'};
+
+    # sorted the keys - otherwise funny things happen - kjdon 03/01/03
+    foreach my $OID (sort keys (%$list)) {
+	my $tempinfo = $self->get_OID_entry ($OID, $classifyinfo, $list->{$OID}->{'title'}, "VList");
+	
+	if (defined $self->{'sort'}) {
+	    if ($self->{'reverse_sort'}) {
+		foreach my $subOID (sort {$b->[1] cmp $a->[1];} @{$list->{$OID}->{'contents'}}) {
+		    push (@{$tempinfo->{'contains'}}, {'OID'=>$subOID->[0]});
+		}
+	    }
+	    else {
+		foreach my $subOID (sort {$a->[1] cmp $b->[1];} @{$list->{$OID}->{'contents'}}) {
+		    push (@{$tempinfo->{'contains'}}, {'OID'=>$subOID->[0]});
+		}
+	    }
+	}
+	else {
+	    foreach my $subOID (@{$list->{$OID}->{'contents'}}) {
+		push (@{$tempinfo->{'contains'}}, {'OID'=>$subOID->[0]});
+	    }
+	}
+    }
+    
+    return $classifyinfo;
+}
+
+
+sub supports_memberof {
+    my $self = shift(@_);
+
+    return "true";
+}
+
+sub get_OID_entry {
+    my $self = shift (@_);
+    my ($OID, $classifyinfo, $title, $classifytype) = @_;
+
+    $OID = "" unless defined $OID;
+    $OID =~ s/^\.+//;
+
+    my ($headOID, $tailOID) = $OID =~ /^(\d+)(.*)$/;
+    $tailOID = "" unless defined $tailOID;
+
+    if (!defined $headOID) {
+	$classifyinfo->{'Title'} = $title;
+	$classifyinfo->{'classifytype'} = $classifytype;
+	return $classifyinfo;
+    }
+
+    $classifyinfo->{'contains'} = [] unless defined $classifyinfo->{'contains'};
+    my $offset = 0;
+    foreach my $thing (@{$classifyinfo->{'contains'}}) {
+	$offset ++ if defined $thing->{'OID'};
+    }
+
+    while (scalar(@{$classifyinfo->{'contains'}}) < ($headOID+$offset)) { 
+	push (@{$classifyinfo->{'contains'}}, $self->get_entry("", $classifytype));
+    }
+
+    return $self->get_OID_entry ($tailOID, $classifyinfo->{'contains'}->[($headOID+$offset-1)], $title, $classifytype);
+}
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $thistype) = @_;
+    my $memberof = &supports_memberof();
+    
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+			'Title'=>$title,
+			'supportsmemberof'=>$memberof,
+			'contains'=>[]);
+    $classifyinfo{'thistype'} = $thistype 
+	if defined $thistype && $thistype =~ /\w/;
+
+    return \%classifyinfo;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/HTML.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/HTML.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/HTML.pm	(revision 10506)
@@ -0,0 +1,107 @@
+###########################################################################
+#
+# HTML.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# html classifier plugin - creates an empty classification
+# that's simply a link to a web page
+
+package HTML;
+
+use BasClas;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @HTML::ISA = ('BasClas');
+}
+
+my $arguments = 
+    [ { 'name' => "url",
+	'desc' => "{HTML.url}",
+	'type' => "string",
+	'reqd' => "yes" } ,
+      { 'name' => "buttonname",
+	'desc' => "{BasClas.buttonname}",
+	'type' => "string",
+	'deft' => "Browse",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "HTML",
+		'desc'     => "{HTML.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasClas($classifierslist,$inputargs,$hashArgOptLists): new BasClas($classifierslist,$inputargs);
+
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+
+    if (!$self->{'url'}) {
+	my $outhandle = $self->{'outhandle'};
+	print $outhandle "HTML Error: required option -url not supplied\n";
+	$self->print_txt_usage("");
+	die "HTML Error: required option -url not supplied\n";
+    }
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    # we don't do anything for individual documents
+}
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my %classifyinfo = ('thistype'=>'Invisible',
+			'childtype'=>'HTML',
+			'Title'=>$self->{'buttonname'},
+			'contains'=>[]);
+
+    push (@{$classifyinfo{'contains'}}, {'OID'=>$self->{'url'}});
+
+    return \%classifyinfo;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Hierarchy.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Hierarchy.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Hierarchy.pm	(revision 10506)
@@ -0,0 +1,320 @@
+###########################################################################
+#
+# Hierarchy.pm -- classifier that enables a Hierarchy to beformed without 
+#                 the need for a hierarchy file (like HFileHierarchy). Used
+#                 to be called AutoHierarchy.  Inherits from HFileHierarchy
+#                 so can also do everything that does as well.
+#                 Created by Imene, modified by Katherine and David.
+#
+# 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.
+#
+###########################################################################
+
+# An advanced Hierarchical classifier
+# to see the options, run "perl -S classinfo.pl Hierarchy"
+
+package Hierarchy;
+
+use HFileHierarchy;
+use sorttools;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @Hierarchy::ISA = ('HFileHierarchy');
+}
+
+my $arguments = 
+    [ { 'name' => "separator",
+	'desc' => "{Hierarchy.separator}",
+	'type' => "regexp",
+	'deft' => "[\\\\\\\/|\\\\\\\|]",
+	'reqd' => "no" },
+      { 'name' => "suppresslastlevel",
+	'desc' => "{Hierarchy.suppresslastlevel}",
+	'type' => "flag",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "Hierarchy",
+		'desc'     => "{Hierarchy.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new HFileHierarchy($classifierslist,$inputargs,$hashArgOptLists): new HFileHierarchy($classifierslist,$inputargs); 
+    
+    # the hash that we use to build up the hierarchy
+    $self->{'path_hash'}= {};
+    
+    return bless $self, $class;
+}
+
+
+sub auto_classify {
+    my $self = shift (@_);
+    my ($doc_obj,$nosort,$sortmeta,$metavalues) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    
+    #Add all the metadata values to the hash
+    my $path_hash;
+    my $current_pos;
+    
+    
+    foreach my $metavalue (@$metavalues) {
+	$path_hash = $self->{'path_hash'};
+	my @chunks = split (/$self->{'separator'}/, $metavalue);
+	if ($self->{'suppresslastlevel'}) {
+	    pop(@chunks); # remove the last element from the end
+	}
+	foreach my $folderName (@chunks) 
+	{
+	    if ($folderName ne ""){ #sometimes the tokens are empty
+		$current_pos = $self->add_To_Hash($path_hash, $folderName, $nosort);
+		$path_hash = $current_pos->{'nodes'};
+	    } 
+	}
+	# now add the document, with sort meta if needed
+	if ($nosort) {
+	    push(@{$current_pos->{'docs'}}, $doc_OID);
+	} else {
+	    $current_pos->{'docs'}->{$doc_OID} = $sortmeta;
+	    
+	    #if (defined $sortmeta) {
+	#	# can you ever get the same doc twice in one classification??
+	#	$current_pos->{'docs'}->{$doc_OID} = $sortmeta;
+	#    } else {
+	#	$current_pos->{'docs'}->{$doc_OID} = $metavalue;
+	#    }
+	}
+    } # foreach metadata
+
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+
+    # are we sorting the list??
+    my $nosort = 0;
+    if (!defined $self->{'sort'}) {
+	$nosort = 1;
+    }
+    
+    my $metavalues = [];
+    # find all the metadata values
+    foreach my $m (@{$self->{'meta_list'}}) {
+	my $mvalues = $doc_obj->get_metadata($doc_obj->get_top_section(), $m);
+	next unless (@{$mvalues});
+	if ($self->{'firstvalueonly'}) {
+	    # we only want the first metadata value
+	    push (@$metavalues, $mvalues->[0]);
+	    last;
+	}
+	push (@$metavalues, @$mvalues);
+	last if (!$self->{'allvalues'}); # we don't want to try other elements
+ 	                                 # cos we have already found some 
+    } 
+    
+    return unless (@$metavalues);
+
+    #check for a sort element other than our metadata
+    my $sortmeta = undef;
+    if (!$nosort) {
+	if ($self->{'sort'} =~ /^filename$/i) {
+	    $sortmeta = $doc_obj->get_source_filename();
+	} else {
+	    $sortmeta = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $self->{'sort'});
+	    if (defined $sortmeta) {
+		$sortmeta = &sorttools::format_metadata_for_sorting($self->{'sort'}, $sortmeta, $doc_obj);
+	    }
+	}
+	$sortmeta = "" unless defined $sortmeta;
+    }
+
+    if (defined $self->{'subjectfile'}) {
+	$self->hfile_classify($doc_obj,$sortmeta,$metavalues);
+    }
+    else {
+	$self->auto_classify($doc_obj,$nosort,$sortmeta,$metavalues);
+    }
+}
+
+sub add_To_Hash {
+    my $self = shift (@_);
+    my ($myhash, $k, $nosort) = @_;
+    
+    if (!defined $myhash->{$k}){
+	$myhash->{$k}={};
+	$myhash->{$k}->{'nodes'}={};
+	if ($nosort) {
+	    $myhash->{$k}->{'docs'}=[];
+	} else {
+	    $myhash->{$k}->{'docs'} = {};
+	}
+    }
+    return $myhash->{$k}; 
+}
+
+sub print_Hash{
+    my $self = shift (@_); 
+    my ($myHash, $num_spaces) = @_;
+
+    foreach my $key (keys %{$myHash}){
+	print "\n";
+	$self->print_spaces($num_spaces);
+	print STDERR "$key*";
+	$self->print_Hash($myHash->{$key}, $num_spaces + 2);
+    }    
+}
+
+sub print_spaces{
+    my $self = shift (@_);
+    my ($num_spaces) = @_;
+    
+    for (my $i = 0; $i < $num_spaces; $i++){
+	print STDERR " ";
+    }
+}
+
+sub get_entry {
+    my $self = shift (@_);
+    my ($title, $childtype, $thistype) = @_;
+    
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>$childtype,
+			'Title'=>$title,
+			'contains'=>[],);
+    $classifyinfo{'thistype'} = $thistype 
+	if defined $thistype && $thistype =~ /\w/;
+    
+    return \%classifyinfo;
+}
+
+sub process_hash {
+    my $self = shift (@_);
+    my ($top_hash, $top_entry) = @_;   
+    my ($entry);
+    
+    my $hash = {};
+    foreach my $key (sort keys %{$top_hash}) {
+	$entry = $self->get_entry($key,"VList","VList");
+	my $has_content = 0;
+	my @doc_list;
+	# generate a sorted list of doc ids
+	if (not (defined ($self->{'sort'})) && scalar(@{$top_hash->{$key}->{'docs'}})) {
+	    @doc_list = @{$top_hash->{$key}->{'docs'}};
+	} elsif (defined ($self->{'sort'}) && (keys %{$top_hash->{$key}->{'docs'}})) {
+	    @doc_list = sort {$top_hash->{$key}->{'docs'}->{$a} 
+			      cmp $top_hash->{$key}->{'docs'}->{$b};} keys %{$top_hash->{$key}->{'docs'}};
+	    
+	}
+	# if this key has documents, add them
+	if (@doc_list) {
+	    $has_content = 1;
+	    foreach my $d (@doc_list) {
+		push (@{$entry->{'contains'}}, {'OID'=>$d});
+	    }    
+	}
+	# if this key has nodes, add them
+	if (scalar(keys %{$top_hash->{$key}->{'nodes'}})) {
+	    $has_content = 1;
+	    $self->process_hash($top_hash->{$key}->{'nodes'}, $entry); 
+	}
+	# if we have found some content, add the new entry for this key into the parent node
+	if ($has_content) {
+	    push (@{$top_entry->{'contains'}}, $entry);
+	}
+
+    }    
+}
+
+sub auto_get_classify_info {
+    my $self = shift (@_);
+    my ($no_thistype) = @_;
+    $no_thistype = 0 unless defined $no_thistype;
+
+    my ($classification);
+    my $top_h = $self->{'path_hash'};
+
+    if ($self->{'path_hash'}) {
+	if ($self->{'hlist_at_top'}) {
+	    $classification = $self->get_entry ($self->{'buttonname'}, "HList", "Invisible");
+	}
+	else {
+	    $classification = $self->get_entry ($self->{'buttonname'}, "VList", "Invisible");
+	}
+    }
+
+    $self->process_hash($top_h, $classification);
+   
+    return  $classification;
+
+}
+
+sub auto_get_classify_info
+{
+    my $self = shift (@_);
+    my ($classifyinfo) = @_;
+
+    $self->process_hash($self->{'path_hash'}, $classifyinfo);
+
+    return $classifyinfo;
+}
+
+
+sub get_classify_info {
+    my $self = shift (@_);
+
+    my ($classifyinfo);
+
+    if ($self->{'hlist_at_top'}) {
+	$classifyinfo = $self->get_entry ($self->{'buttonname'}, "HList", "Invisible");
+    }
+    else {
+	$classifyinfo = $self->get_entry ($self->{'buttonname'}, "VList", "Invisible");
+    }
+
+    if (defined $self->{'subjectfile'}) {
+	return $self->hfile_get_classify_info($classifyinfo);
+    }
+    else {
+	return $self->auto_get_classify_info($classifyinfo);
+    }
+}
+
+
+1;
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/List.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/List.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/List.pm	(revision 10506)
@@ -0,0 +1,249 @@
+###########################################################################
+#
+# List.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# simple list classifier plugin 
+# to see the options, run "perl -S classinfo.pl List"
+
+use BasClas;
+package List;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+use sorttools;
+
+sub BEGIN {
+    @List::ISA = ('BasClas');
+}
+
+my $arguments = 
+    [ { 'name' => "metadata",
+	'desc' => "{List.metadata}",
+	'type' => "metadata",
+	'reqd' => "no" },
+      { 'name' => "buttonname",
+  	'desc' => "{BasClas.buttonname}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "sort",
+	'desc' => "{List.sort}",
+	'type' => "string",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "List",
+		'desc'     => "{List.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasClas($classifierslist,$inputargs,$hashArgOptLists): new BasClas($classifierslist,$inputargs);
+
+    # Transfer value from Auto Parsing to the variable name that used in previous GreenStone.
+    my (@meta_list,$meta1);
+    if ($self->{"metadata"}) {
+	@meta_list = split(/,/, $self->{"metadata"});
+	$meta1 = $meta_list[0];
+	$self->{'meta_list'} = \@meta_list;
+    } else {
+	$meta1=undef;
+	@meta_list = undef;
+    }
+
+    if (!$self->{"buttonname"}) {
+	if (defined ($self->{'metadata'})) {
+	    $self->{"buttonname"} = $self->generate_title_from_metadata($self->{'metadata'});
+	} else {
+	    $self->{"buttonname"} = 'List';
+	}
+    }
+
+    # Further setup
+    # $self->{"sort"} is handled a bit differently - kjdon
+    # undef means to sort, but use the metadata value from -metadata
+    # because there is no one metadata value to get for sorting when 
+    # we have a list of possible metadata
+    # to get no sorting, set $self->{"sort"} = 'nosort'
+    if (!$self->{"sort"}) {
+	if (defined ($self->{"metadata"})) {
+	    $self->{"sort"} = undef;
+	} else {
+	    $self->{"sort"} = "nosort";
+	}
+    }    
+    if (defined  $self->{"sort"} &&  $self->{"sort"} eq "nosort") {
+	$self->{'list'} = [];
+    } else {
+	$self->{'list'} = {};
+    }
+        
+    # Clean out the unused keys
+    delete $self->{"metadata"}; # Delete this key
+    
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+
+    # are we sorting the list??
+    my $nosort = 0;
+    if (defined $self->{'sort'} && $self->{'sort'} eq "nosort") {
+	$nosort = 1;
+    }
+    
+    my $metavalue;
+    my $metaname;
+    if (defined $self->{'meta_list'}) {
+	my $topsection=$doc_obj->get_top_section();
+
+	# find the correct bit of metadata, if multi-valued metadata field
+	if (exists $doc_obj->{'mdoffset'}) { # set by AZCompactList
+
+	    my $mdoffset=$doc_obj->{'mdoffset'} - 1;
+	    
+	    foreach my $m (@{$self->{'meta_list'}}) {
+		my $values_listref=
+		    $doc_obj->get_metadata($topsection, $m);
+		my $array_size = scalar(@{$values_listref});
+		if ($array_size==0 || $array_size < $mdoffset+1) {
+		    $mdoffset = $mdoffset - $array_size;
+		} else {
+		    $metaname = $m;
+		    # get the correct value using the offset
+		    $metavalue=@$values_listref[$mdoffset];
+                    # use a special format for docOID...
+		    $doc_OID .= ".offset$mdoffset";
+		    last;
+		}
+	    }
+	} else {
+	    # use the first available metadata
+	    foreach my $m (@{$self->{'meta_list'}}) {
+		$metavalue = $doc_obj->
+		    get_metadata_element($topsection, $m);
+		$metaname = $m;
+		last if defined $metavalue;
+	    }
+	} 
+	# if we haven't found a metavalue, then the doc shouldn't be included
+	return unless defined $metavalue;
+    }
+    
+    # we know the doc should be included, add it now if we are not sorting
+    if ($nosort) {
+	push (@{$self->{'list'}}, $doc_OID);
+	return;
+    }
+
+    #check for a sort element other than our metadata
+    if (defined $self->{'sort'}) {
+	my $sortmeta;
+	if ($self->{'sort'} =~ /^filename$/i) {
+	    $sortmeta = $doc_obj->get_source_filename();
+	} else {
+	    $sortmeta = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $self->{'sort'});
+	    if (defined $sortmeta) {
+		$sortmeta = &sorttools::format_metadata_for_sorting($self->{'sort'}, $sortmeta, $doc_obj);
+	    }
+	}
+	$sortmeta = "" unless defined $sortmeta;
+	$self->{'list'}->{$doc_OID} = $sortmeta;
+    } else {
+	# we add to the list based on metadata value
+	# but we need to do the same formatting as for sort value
+	($metavalue) = &sorttools::format_metadata_for_sorting($metaname, $metavalue, $doc_obj);
+	$self->{'list'}->{$doc_OID} = $metavalue;
+    }
+    my $id = $self->get_number();
+    $doc_obj->add_metadata($doc_obj->get_top_section(), "memberof", "CL$id");
+}
+
+
+sub get_classify_info {
+    my $self = shift (@_);
+    my ($no_thistype) = @_;
+    $no_thistype = 0 unless defined $no_thistype;
+    my $memberof = &supports_memberof();
+
+    my @list = ();
+    if (defined $self->{'sort'} && $self->{'sort'} eq "nosort") {
+	@list = @{$self->{'list'}};
+    } else {
+	if (keys %{$self->{'list'}}) {
+	    @list = sort {$self->{'list'}->{$a} 
+			  cmp $self->{'list'}->{$b};} keys %{$self->{'list'}};
+	}	
+    }
+    # organise into classification structure
+    my %classifyinfo = ('childtype'=>'VList',
+			'Title'=>$self->{'buttonname'},
+			'contains'=>[]);
+    $classifyinfo{'thistype'} = 'Invisible' unless $no_thistype;
+    # always supports memberof
+    $classifyinfo{'supportsmemberof'} = $memberof;
+
+    foreach my $OID (@list) {
+	my $hashref={};
+	# special oid format, if using offsets (from AZCompactList)
+	if ($OID =~ s/\.offset(\d+)$//) {
+	    $hashref->{'offset'}=$1;
+	}
+	$hashref->{'OID'}=$OID;
+
+	push (@{$classifyinfo{'contains'}}, $hashref);
+    }
+
+    return \%classifyinfo;
+}
+
+sub supports_memberof {
+    my $self = shift(@_);
+
+    return "true";
+}
+
+1;
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Phind.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Phind.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/Phind.pm	(revision 10506)
@@ -0,0 +1,1503 @@
+###########################################################################
+#
+# Phind.pm -- the Phind classifier
+#
+# Copyright (C) 2000 Gordon W. Paynter
+# Copyright (C) 2000 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.
+#
+###########################################################################
+
+# The Phind clasifier plugin. 
+# Type "classinfo.pl Phind" at the command line for a summary.
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package Phind;
+
+use BasClas;
+use util;
+use ghtml;
+use unicode;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+my @removedirs = ();
+
+my %wanted_index_files = ('td'=>1,
+			  't'=>1,
+			  'ti'=>1,
+			  'tl'=>1,
+			  'tsd'=>1,
+			  'idb'=>1,
+			  'ib1'=>1,
+			  'ib2'=>1,
+			  'ib3'=>1,
+			  'i'=>1,
+			  'il'=>1,
+			  'w'=>1,
+			  'wa'=>1);
+
+sub BEGIN {
+    @Phind::ISA = ('BasClas');
+}
+
+sub END {
+    
+    # Tidy up stray files - we do this here as there's some weird problem
+    # preventing us from doing it in the get_classify_info() function (on
+    # windows at least) where the close() appears to fail on txthandle and
+    # dochandle, thus preventing us from deleting those files
+
+    foreach my $dir (@removedirs) {
+	if (-d $dir && opendir (DIR, $dir)) {
+	    my @files = readdir DIR;
+	    closedir DIR;
+	
+	    foreach my $file (@files) {
+		next if $file =~ /^\.\.?$/;
+		my ($suffix) = $file =~ /\.([^\.]+)$/;
+		if (!defined $suffix || !defined $wanted_index_files{$suffix}) {
+		    # delete it!
+		    &util::rm (&util::filename_cat ($dir, $file));
+		}
+	    }
+	}
+    }
+}
+
+my $arguments =
+    [ { 'name' => "text",
+	'desc' => "{Phind.text}",
+	'type' => "string",
+	'deft' => "section:Title,section:text",
+	'reqd' => "no" },
+      { 'name' => "title",
+	'desc' => "{Phind.title}",
+	'type' => "metadata",
+	'deft' => "Title",
+	'reqd' => "no" },
+      { 'name' => "buttonname",
+	'desc' => "{BasClas.buttonname}",
+	'type' => "string",
+	'deft' => "Phrase",
+	'reqd' => "no" },
+      { 'name' => "language",
+	'desc' => "{Phind.language}",
+	'type' => "string",
+	'deft' => "en",
+	'reqd' => "no" },
+      { 'name' => "savephrases",
+	'desc' => "{Phind.savephrases}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "suffixmode",
+	'desc' => "{Phind.suffixmode}",
+	'type' => "int",
+	'deft' => "1",
+	'range' => "0,1",
+	'reqd' => "no" },
+      { 'name' => "min_occurs",
+	'desc' => "{Phind.min_occurs}",
+	'type' => "int",
+	'deft' => "2",
+	'range' => "1,",
+	'reqd' => "no" },
+      { 'name' => "thesaurus",
+	'desc' => "{Phind.thesaurus}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "untidy",
+	'desc' => "{Phind.untidy}",
+	'type' => "flag",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "Phind",
+		'desc'     => "{Phind.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+# Phrase delimiter symbols - these should be abstracted out someplace
+
+my $colstart = "COLLECTIONSTART";
+my $colend   = "COLLECTIONEND";
+my $doclimit = "DOCUMENTLIMIT";
+my $senlimit = "SENTENCELIMIT";
+my @delimiters = ($colstart, $colend, $doclimit, $senlimit);
+
+
+# Create a new Phind browser based on collect.cfg
+
+sub new {
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasClas($classifierslist,$inputargs,$hashArgOptLists): new BasClas($classifierslist,$inputargs);
+
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+
+    # Ensure the Phind generate scripts are in place
+    my $file1 = &util::filename_cat($ENV{'GSDLHOME'}, "bin", $ENV{'GSDLOS'}, "suffix");
+    $file1 .= ".exe" if $ENV{'GSDLOS'} =~ /^windows$/;
+    my $src = &util::filename_cat($ENV{'GSDLHOME'}, "src", "phind", "generate");
+    if (!(-e $file1)) {
+	print STDERR "Phind.pm: ERROR: The Phind \"suffix\" program is not installed.\n\n";
+	exit(1);
+    }
+    
+    # Transfer value from Auto Parsing to the variable name that used in previous GreenStone.
+    $self->{"indexes"} = $self->{"text"};
+
+    # Further setup
+    $self->{'collection'} = $ENV{'GSDLCOLLECTION'}; # classifier information
+    $self->{'collectiondir'} = $ENV{'GSDLCOLLECTDIR'}; # collection directories
+    if (! defined $self->{'builddir'}) {
+	$self->{'builddir'} = &util::filename_cat($ENV{'GSDLCOLLECTDIR'}, "building");
+    } 
+    $self->{'total'} = 0;
+    
+    # Clean out the unused keys
+    delete $self->{"text"};
+
+    return bless $self, $class;
+}
+
+
+# Initialise the Phind classifier
+
+sub init {
+    my $self = shift (@_);
+
+    # ensure we have a build directory
+    my $builddir = $self->{'builddir'};
+    die unless (-e "$builddir");
+
+    # create Phind directory
+    my $phnumber = 1;
+    my $phinddir = &util::filename_cat($builddir, "phind1");
+    while (-e "$phinddir") {
+	$phnumber++;
+	$phinddir = &util::filename_cat($builddir, "phind$phnumber");
+    }
+    &util::mk_dir("$phinddir");
+    $self->{'phinddir'} = $phinddir;
+    $self->{'phindnumber'} = $phnumber;
+
+    push(@removedirs, $phinddir) unless $self->{'untidy'};
+
+    # open filehandles for documents and text
+    my $clausefile =  &util::filename_cat("$phinddir", "clauses");
+    &util::rm($clausefile) if (-e $clausefile);
+
+    my $txthandle = 'TEXT' . $phnumber;
+    open($txthandle, ">$clausefile") || die "Cannot open $clausefile: $!";
+    $self->{'txthandle'} = $txthandle;
+
+    my $docfile = &util::filename_cat("$phinddir", "docs.txt");
+    &util::rm($docfile) if (-e $docfile);
+
+    my $dochandle = 'DOC' . $phnumber;
+    open($dochandle, ">$docfile") || die "Cannot open $docfile: $!";
+    $self->{'dochandle'} = $dochandle;
+    
+}
+
+
+# Classify each document.
+#
+# Each document is passed here in turn.  The classifier extracts the 
+# text of each and stores it in the clauses file.  Document details are
+# stored in the docs.txt file. 
+
+sub classify {
+    my $self = shift (@_);
+    my $doc_obj = shift @_;
+
+    my $verbosity = $self->{'verbosity'};
+    my $top_section = $doc_obj->get_top_section();
+
+    my $titlefield = $self->{'title'};
+    
+    my $title = $doc_obj->get_metadata_element ($top_section, $titlefield);
+    if (!defined($title)) {
+	$title = "";
+	print STDERR "Phind: document has no title\n";
+    }
+    print "process: $title\n" if ($verbosity > 2);
+
+    # Only consider the file if it is in the correct language
+    my $doclanguage = $doc_obj->get_metadata_element ($top_section, "Language");
+    my $phrlanguage = $self->{'language'};
+    return if ($doclanguage && ($doclanguage !~ /$phrlanguage/i));
+    
+    # record this file
+    $self->{'total'} ++;
+    # what is $file ???
+    # print "file $self->{'total'}: $file\n" if ($self->{'$verbosity'});
+
+    # Store document details
+    my $OID = $doc_obj->get_OID();
+    $OID = "NULL" unless defined $OID;
+    my $dochandle = $self->{'dochandle'};
+    print $dochandle "<Document>\t$OID\t$title\n";
+    
+    # Store the text occuring in this object
+
+    # output the document delimiter
+    my $txthandle = $self->{'txthandle'};
+    print $txthandle "$doclimit\n";
+
+    # iterate over the required indexes and store their text
+    my $indexes = $self->{'indexes'};
+    my $text = "";
+    my ($part, $level, $field, $section, $data, $dataref);
+
+    foreach $part (split(/,/, $indexes)) {
+
+	# Each field has a level and a data element ((e.g. document:Title)
+	($level, $field) = split(/:/, $part);
+	die unless ($level && $field);
+	
+	# Extract the text from every section
+	# (In phind, document:text and section:text are equivalent)
+	if ($field eq "text") {
+	    $data = "";
+	    $section = $doc_obj->get_top_section();
+	    while (defined($section)) {
+		$data .= $doc_obj->get_text($section) . "\n";
+		$section = $doc_obj->get_next_section($section);
+	    }
+	    $text .= convert_gml_to_tokens($phrlanguage, $data) . "\n";
+	}
+	
+	# Extract a metadata field from a document
+	# (If there is more than one element of the given type, get them all.)
+	elsif ($level eq "document") {
+	    $dataref = $doc_obj->get_metadata($doc_obj->get_top_section(), $field);
+	    foreach $data (@$dataref) {
+		$text .= convert_gml_to_tokens($phrlanguage, $data) . "\n";
+	    } 
+	}
+
+	# Extract metadata from every section in a document
+	elsif ($level eq "section") {
+	    $data = "";
+	    $section = $doc_obj->get_top_section();
+	    while (defined($section)) {
+		$dataref = $doc_obj->get_metadata($section, $field);
+		$data .= join("\n", @$dataref) . "\n";
+		$section = $doc_obj->get_next_section($section);
+	    }
+	    $text .= convert_gml_to_tokens($phrlanguage, $data) . "\n";
+	} 
+	
+	# Some sort of specification which I don't understand
+	else {
+	    die "Unknown level ($level) in Phind index ($part)\n";
+	}
+	
+    }
+
+    # output the text
+    $text =~ tr/\n//s;
+    print $txthandle "$text";
+}
+
+
+# Construct the classifier from the information already gathered
+#
+# When get_classify_info is called, the clauses and docs.txt files have
+# already been constructed in the Phind directory.  This function will
+# translate them into compressed, indexed MGPP files that can be read by
+# the phindcgi script.  It will also register our classifier so that it
+# shows up in the navigation bar.
+
+sub get_classify_info {
+    my $self = shift (@_);
+    my ($gli) = @_;    
+
+    close $self->{'dochandle'};
+    close $self->{'txthandle'};
+    my $verbosity = $self->{'verbosity'};
+    my $out = $self->{'outhandle'};
+    my $phinddir = $self->{'phinddir'};
+
+    my $osextra = "";
+    if ($ENV{'GSDLOS'} !~ /^windows$/i) {
+	$osextra = " -d /";
+    }
+
+    print STDERR "</Stage>\n" if $gli;
+
+    if ($verbosity) {
+	print $out "\n*** Phind.pm generating indexes for ", $self->{'indexes'}, "\n";
+	print $out "***          in ", $self->{'phinddir'}, "\n";
+    }
+
+    print STDERR "<Stage name='Phind'>\n" if $gli;
+
+    # Construct phind indexes
+    my $suffixmode = $self->{'suffixmode'};
+    my $min_occurs = $self->{'min_occurs'};
+    my ($command, $status);
+    
+    # Generate the vocabulary, symbol statistics, and numbers file
+    # from the clauses file
+    print $out "\nExtracting vocabulary and statistics\n" if $verbosity;
+    print STDERR "<Phase name='ExtractingVocab'/>\n" if $gli;
+    &extract_vocabulary($self);
+ 
+    # Use the suffix program to generate the phind/phrases file
+    print $out "\nExtracting phrases from processed text (with suffix)\n" if $verbosity;
+    print STDERR "<Phase name='ExtractingPhrase'/>\n" if $gli;
+    &execute("suffix \"$phinddir\" $suffixmode $min_occurs $verbosity", $verbosity, $out);
+
+    # check that we generated some files. It's not necessarily an error if
+    # we didn't (execute() would have quit on error), but we can't go on.
+    my $phrasesfile=&util::filename_cat($self->{'phinddir'}, 'phrases');
+    if (! -r $phrasesfile) {
+	print STDERR "<Warning name='NoPhrasesFound'/>\n" if $gli;
+	print $out "\nNo phrases found for Phind classifier!\n";
+	return;
+    }   
+
+    # Create the phrase file and put phrase numbers in phind/phrases
+    print $out "\nSorting and renumbering phrases for input to mgpp\n" if $verbosity;
+    print STDERR "<Phase name='SortAndRenumber'/>\n" if $gli;
+    &renumber_phrases($self);
+
+    print $out "\nCreating phrase databases\n";
+    print STDERR "<Phase name='PhraseDatabases'/>\n" if $gli;
+    my $mg_input = &util::filename_cat($phinddir, "pdata.txt");
+    my $mg_stem = &util::filename_cat($phinddir, "pdata");
+
+    &execute("mgpp_passes $osextra -f \"$mg_stem\" -T1 \"$mg_input\"", $verbosity, $out);
+    &execute("mgpp_compression_dict $osextra -f \"$mg_stem\"", $verbosity, $out);
+    &execute("mgpp_passes $osextra -f \"$mg_stem\" -T2 \"$mg_input\"", $verbosity, $out);
+
+    # create the mg index of words
+    print $out "\nCreating word-level search indexes\n";
+    print STDERR "<Phase name='WordLevelIndexes'/>\n" if $gli;
+    $mg_input = &util::filename_cat($phinddir, "pword.txt");
+    $mg_stem = &util::filename_cat($phinddir, "pword");
+
+    &execute("mgpp_passes $osextra -f \"$mg_stem\" -T1 -I1 \"$mg_input\"", $verbosity, $out);
+    &execute("mgpp_compression_dict $osextra -f \"$mg_stem\"", $verbosity, $out);
+    &execute("mgpp_perf_hash_build $osextra -f \"$mg_stem\"", $verbosity, $out);
+    &execute("mgpp_passes $osextra -f \"$mg_stem\" -T2 -I2 \"$mg_input\"", $verbosity, $out);
+    &execute("mgpp_weights_build $osextra -f \"$mg_stem\"", $verbosity, $out);
+    &execute("mgpp_invf_dict $osextra -f \"$mg_stem\"", $verbosity, $out);
+
+    &execute("mgpp_stem_idx $osextra -f \"$mg_stem\" -s 1", $verbosity, $out);
+    &execute("mgpp_stem_idx $osextra -f \"$mg_stem\" -s 2", $verbosity, $out);
+    &execute("mgpp_stem_idx $osextra -f \"$mg_stem\" -s 3", $verbosity, $out);
+
+    # create the mg document information database
+    print $out "\nCreating document information databases\n";
+    print STDERR "<Phase name='DocInfoDatabases'/>\n" if $gli;
+    $mg_input = &util::filename_cat($phinddir, "docs.txt");
+    $mg_stem = &util::filename_cat($phinddir, "docs");
+
+    &execute("mgpp_passes $osextra -f \"$mg_stem\" -T1 \"$mg_input\"", $verbosity, $out);
+    &execute("mgpp_compression_dict $osextra -f \"$mg_stem\"", $verbosity, $out);
+    &execute("mgpp_passes $osextra -f \"$mg_stem\" -T2 \"$mg_input\"", $verbosity, $out);
+
+    # Return the information about the classifier that we'll later want to
+    # use to create macros when the Phind classifier document is displayed.
+    my %classifyinfo = ('thistype'=>'Invisible',
+                        'childtype'=>'Phind', 
+                        'Title'=>$self->{'buttonname'},
+                        'parameters'=>"phindnumber=$self->{'phindnumber'}",
+			'contains'=>[]);
+    
+    my $collection = $self->{'collection'};
+    my $url = "library?a=p&p=phind&c=$collection";
+    push (@{$classifyinfo{'contains'}}, {'OID'=>$url});
+   
+    return \%classifyinfo;
+}
+
+
+
+sub convert_gml_to_tokens {
+    
+    my ($language_exp, $text) = @_;
+
+    # escape any magic words... - jrm21
+    foreach my $delim (@delimiters) {
+	my $replacement=lc($delim);
+	my $num= $text=~ s/$delim/$replacement/g;
+	if (!$num) {$num=0;}
+    }
+
+    if ($language_exp =~ /en/) {
+	return &convert_gml_to_tokens_EN($text);
+    }
+
+    if ($language_exp =~ /zh/) {
+	return &convert_gml_to_tokens_ZH($text);
+    }  
+    
+    $_ = $text;
+
+    # 1. remove GML tags
+
+    # Remove everything that is in a tag
+    s/\s*<p>\s*/ PARAGRAPHBREAK /isgo;
+    s/\s*<br>\s*/ LINEBREAK /isgo;
+    s/<[^>]*>/ /sgo;
+
+    # Now we have the text, but it may contain HTML 
+    # elements coded as &gt; etc.  Remove these tags. 
+    s/&amp;/&/sgo;
+    s/&lt;/</sgo;
+    s/&gt;/>/sgo;
+    s/\s*<p>\s*/ PARAGRAPHBREAK /isgo;
+    s/\s*<br>\s*/ LINEBREAK /isgo;
+    s/<[^>]*>/ /sgo;
+
+    # replace<p> and <br> placeholders with clause break symbol (\n)
+    s/\s+/ /gso;
+    s/PARAGRAPHBREAK/\n/sgo;
+    s/LINEBREAK/\n/sgo;
+
+    
+
+
+    # 2. Split the remaining text into space-delimited tokens
+
+    # Convert any HTML special characters (like &quot;) to their UTF8 equivalent
+    s/&([^;]+);/&unicode::ascii2utf8(\&ghtml::getcharequiv($1,1))/gse;
+
+    # Split text at word boundaries
+    s/\b/ /go;
+
+    # 3. Convert the remaining text to "clause format"
+
+    # Insert newline if the end of a sentence is detected
+    # (delimter is:  "[\.\?\!]\s")
+    # s/\s*[\.\?\!]\s+/\n/go; 
+
+    # remove unnecessary punctuation and replace with clause break symbol (\n)
+    s/[^\w ]/\n/go;
+
+    # remove extraneous whitespace
+    s/ +/ /sgo;
+    s/^\s+//mgo;
+    s/\s*$/\n/mgo;
+
+    # remove lines that contain one word or less
+    s/^\S*$//mgo;
+    s/^\s*$//mgo;
+    tr/\n//s;
+
+    return $_;
+}
+
+# a chinese version
+sub convert_gml_to_tokens_ZH {
+
+    $_ = shift @_;
+
+    # Replace all whitespace with a simple space
+    s/\s+/ /gs;
+    # Remove everything that is in a tag
+    s/\s*<p>\s*/ PARAGRAPHBREAK /isg;
+    s/\s*<br>\s*/ LINEBREAK /isg;
+    s/<[^>]*>/ /sg;
+
+    # Now we have the text, but it may contain HTML 
+    # elements coded as &gt; etc.  Remove these tags. 
+    s/&lt;/</sg;
+    s/&gt;/>/sg;
+
+    s/\s+/ /sg;
+    s/\s*<p>\s*/ PARAGRAPHBREAK /isg;
+    s/\s*<br>\s*/ LINEBREAK /isg;
+    s/<[^>]*>/ /sg;
+
+    # remove &amp; and other miscellaneous markup tags
+    s/&amp;/&/sg;
+    s/&lt;/</sg;
+    s/&gt;/>/sg;
+    s/&amp;/&/sg;
+
+    # replace<p> and <br> placeholders with carriage returns
+    s/PARAGRAPHBREAK/\n/sg;
+    s/LINEBREAK/\n/sg;
+
+    
+#    print STDERR "text:$_\n";
+    return $_;
+}
+
+# A version of convert_gml_to_tokens that is fine-tuned to the English language.
+
+sub convert_gml_to_tokens_EN {
+    $_ = shift @_;
+
+    # FIRST, remove GML tags
+
+    # Replace all whitespace with a simple space
+    s/\s+/ /gs;
+
+    # Remove everything that is in a tag
+    s/\s*<p>\s*/ PARAGRAPHBREAK /isg;
+    s/\s*<br>\s*/ LINEBREAK /isg;
+    s/<[^>]*>/ /sg;
+
+    # Now we have the text, but it may contain HTML 
+    # elements coded as &gt; etc.  Remove these tags. 
+    s/&lt;/</sg;
+    s/&gt;/>/sg;
+
+    s/\s+/ /sg;
+    s/\s*<p>\s*/ PARAGRAPHBREAK /isg;
+    s/\s*<br>\s*/ LINEBREAK /isg;
+    s/<[^>]*>/ /sg;
+
+    # remove &amp; and other miscellaneous markup tags
+    s/&amp;/&/sg;
+    s/&lt;/</sg;
+    s/&gt;/>/sg;
+    s/&amp;/&/sg;
+
+    # replace<p> and <br> placeholders with carriage returns
+    s/PARAGRAPHBREAK/\n/sg;
+    s/LINEBREAK/\n/sg;
+
+
+    # Exceptional punctuation
+    # 
+    # We make special cases of some punctuation
+
+    # remove any apostrophe that indicates omitted letters 
+    s/(\w+)\'(\w*\s)/ $1$2 /g;
+
+    # remove period that appears in a person's initals
+    s/\s([A-Z])\./ $1 /g;
+
+    # replace hyphens in hypheanted words and names with a space
+    s/([A-Za-z])-\s*([A-Za-z])/$1 $2/g;
+
+    # Convert the remaining text to "clause format",
+    # This means removing all excess punctuation and garbage text,
+    # normalising valid punctuation to fullstops and commas,
+    # then putting one cluse on each line.
+
+    # Insert newline when the end of a sentence is detected
+    # (delimter is:  "[\.\?\!]\s")
+    s/\s*[\.\?\!]\s+/\n/g; 
+
+    # split numbers after four digits
+    s/(\d\d\d\d)/$1 /g;
+
+    # split words after 32 characters
+
+    # squash repeated punctuation 
+    tr/A-Za-z0-9 //cs;
+
+    # save email addresses
+    # s/\w+@\w+\.[\w\.]+/EMAIL/g;
+
+    # normalise clause breaks (mostly punctuation symbols) to commas
+    s/[^A-Za-z0-9 \n]+/ , /g;
+
+    # Remove repeated commas, and replace with newline
+    s/\s*,[, ]+/\n/g;
+
+    # remove extra whitespace
+    s/ +/ /sg;
+    s/^\s+//mg;
+    s/\s*$/\n/mg;
+
+    # remove lines that contain one word or less
+    s/^\w*$//mg;
+    s/^\s*$//mg;
+    tr/\n//s;
+
+    return $_;
+
+}
+
+
+
+# Execute a system command
+
+sub execute {
+    my ($command, $verbosity, $outhandle) = @_;
+    print $outhandle "Executing: $command\n"  if ($verbosity > 2);
+    $! = 0;
+    my $status = system($command);
+    if ($status != 0) {
+	print STDERR "Phind - Error executing '$command': $!\n";
+	exit($status);  # this causes the build to fail... 
+    }
+}
+
+
+# Generate the vocabulary, symbol statistics, and numbers file from the
+# clauses file.  This is legacy code, so is a bit messy and probably wont
+# run under windows.
+
+sub extract_vocabulary {
+    my ($self) = @_;
+    
+    my $verbosity = $self->{'verbosity'};
+    my $out = $self->{'outhandle'};
+
+    my $collectiondir = $self->{'collectiondir'};
+    my $phinddir = $self->{'phinddir'};
+
+    my $language_exp = $self->{'language'};
+
+    my ($w, $l, $line, $word);
+    
+    my ($first_delimiter, $last_delimiter,
+	$first_stopword, $last_stopword,
+	$first_extractword, $last_extractword,
+	$first_contentword, $last_contentword,
+	$phrasedelimiter);
+    
+    my $thesaurus = $self->{'thesaurus'};
+    my ($thesaurus_links, $thesaurus_terms, 
+	%thesaurus, $first_thesaurusword, $last_thesaurusword);
+
+    my %symbol;
+    my (%freq);
+
+    print $out "Calculating vocabulary\n" if ($verbosity > 1);
+
+    # Read and store the stopwords
+    my $stopdir = &util::filename_cat($ENV{'GSDLHOME'}, "etc", "packages", "phind", "stopword");
+    my $stopword_files = ();
+    my ($language, $language_dir, $file, $file_name);
+    my %stopwords;
+
+    # Examine each directory in the stopword directory
+    opendir(STOPDIR, $stopdir);
+    foreach $language (readdir STOPDIR) {
+
+	# Ignore entries that do not match the classifier's language
+	next unless ($language =~ /$language_exp/);
+	$language_dir = &util::filename_cat($stopdir, $language);
+	next unless (-d "$language_dir");
+
+	opendir(LANGDIR, $language_dir);
+	foreach $file (readdir LANGDIR) {
+
+	    # Ignore entries that are not stopword files
+	    next unless ($file =~ /sw$/);
+	    $file_name = &util::filename_cat($language_dir, $file);
+	    next unless (-f "$file_name");
+
+	    # Read the stopwords
+	    open(STOPFILE, "<$file_name");
+	    while (<STOPFILE>) {
+		s/^\s+//;
+		s/\s.*//;
+		$word = $_;
+		$l = lc($word);
+		$stopwords{$l} = $word;
+	    }
+	    close STOPFILE;
+
+	}
+	closedir LANGDIR;
+    }
+    closedir STOPDIR;
+
+    # Read thesaurus information
+    if ($thesaurus) {
+
+	# link file exists
+	$thesaurus_links = &util::filename_cat($collectiondir, "etc", "$thesaurus.lnk");
+	die "Cannot find thesaurus link file" unless (-e "$thesaurus_links");
+
+	# ensure term file exists in the correct language
+	if ($language_exp =~ /^([a-z][a-z])/) {
+	    $language = $1;
+	} else {
+	    $language = 'en';
+	}
+	$thesaurus_terms = &util::filename_cat($collectiondir, "etc", "$thesaurus.$language");
+	die "Cannot find thesaurus term file" unless (-e "$thesaurus_terms");
+	
+
+	# Read the thesaurus terms
+	open(TH, "<$thesaurus_terms");
+	while(<TH>) {
+	    s/^\d+ //;
+	    s/\(.*\)//;
+	    foreach $w (split(/\s+/, $_)) {
+		$thesaurus{lc($w)} = $w;
+	    }
+	}
+	close TH;
+    }
+
+    # Read words in the text and count occurences
+    open(TXT, "<$phinddir/clauses");
+
+    my @words;
+    while(<TXT>) {
+	$line = $_;
+	next unless ($line =~ /./);
+	
+	@words = split(/\s+/, $line);
+	foreach $w (@words) {
+	    $l = lc($w);
+	    $w = $l if ((defined $stopwords{$l}) || (defined $thesaurus{$l}));
+	    $freq{$w}++;
+	}
+	$freq{$senlimit}++;
+    }
+    
+    close TXT;
+
+    # Calculate the "best" form of each word
+    my (%bestform, %totalfreq, %bestfreq);
+
+    foreach $w (sort (keys %freq)) {
+	$l = lc($w);
+	
+	# totalfreq is the number of times a term appears in any form
+	$totalfreq{$l} += $freq{$w};
+	
+	if (defined $stopwords{$l}) {
+	    $bestform{$l} = $stopwords{$l};
+	    
+	} elsif (defined $thesaurus{$l}) {
+	    $bestform{$l} = $thesaurus{$l};
+	    
+	} elsif (!$bestform{$l} || ($freq{$w} > $bestfreq{$l})) {
+	    $bestfreq{$l} = $freq{$w};
+	    $bestform{$l} = $w;
+	}
+    }
+    undef %freq;
+    undef %bestfreq;
+    
+
+    # Assign symbol numbers to tokens
+    my $nextsymbol = 1;
+    my (@vocab);
+    
+    # Delimiters
+    $first_delimiter = 1;
+    
+    foreach $word (@delimiters) {
+
+#	$word = lc($word); # jrm21
+	$word = uc($word);
+	$bestform{$word} = $word;
+	$vocab[$nextsymbol] = $word;
+	$symbol{$word} = $nextsymbol;
+	$nextsymbol++;
+    }
+    $last_delimiter = $nextsymbol - 1;
+    # Stopwords
+    $first_stopword = $nextsymbol;
+    
+    foreach my $word (sort keys %stopwords) {
+	# don't include stopword unless it occurs in the text
+	$word = lc($word);
+	next unless ($totalfreq{$word});
+	next if ($symbol{$word});
+	
+	$vocab[$nextsymbol] = $word;
+	$symbol{$word} = $nextsymbol;
+	$nextsymbol++;
+    }
+    $last_stopword = $nextsymbol - 1;
+    $first_contentword = $nextsymbol;
+    
+    # Thesaurus terms
+    if ($thesaurus) {
+	$first_thesaurusword = $nextsymbol;
+    
+	foreach my $word (sort keys %thesaurus) {
+	    
+	    $word = lc($word);
+	    next if ($symbol{$word});
+	    $bestform{$word} = $thesaurus{$word};
+	    
+	    $vocab[$nextsymbol] = $word;
+	    $symbol{$word} = $nextsymbol;
+	    $nextsymbol++;
+	    
+	}
+	$last_thesaurusword = $nextsymbol - 1;
+    }
+
+    # Other content words
+    $first_extractword = $nextsymbol;
+    
+    foreach my $word (sort (keys %bestform)) {
+	
+	next if ($symbol{$word});
+	
+	$vocab[$nextsymbol] = $word;
+	$symbol{$word} = $nextsymbol;
+	$nextsymbol++;
+    }
+    $last_extractword = $nextsymbol - 1;
+    $last_contentword = $nextsymbol - 1;
+    
+    # Outut the words
+    print $out "Saving vocabulary in $phinddir/clauses.vocab\n" if ($verbosity > 1);
+    open(VOC, ">$phinddir/clauses.vocab");
+
+    for (my $i = 1; $i < $nextsymbol; $i++) {
+	$w = $vocab[$i];
+
+	print VOC "$bestform{$w}\n";
+	$totalfreq{$w} = 0 unless ($totalfreq{$w});
+    }
+    close VOC;
+
+
+    # Create statistics file
+    # Output statistics about the vocablary
+    print $out "Saving statistics in $phinddir/clauses.stats\n" if ($verbosity > 1);
+    &util::rm("$phinddir/clauses.stats") if (-e "$phinddir/clauses.stats");
+
+    open(STAT, ">$phinddir/clauses.stats")
+	|| die "Cannot open $phinddir/clauses.stats: $!";
+
+    print STAT "first_delimiter $first_delimiter\n";
+    print STAT "last_delimiter $last_delimiter\n";
+    print STAT "first_stopword $first_stopword\n";
+    print STAT "last_stopword $last_stopword\n";
+    if ($thesaurus) {
+	print STAT "first_thesaurusword $first_thesaurusword\n";
+	print STAT "last_thesaurusword $last_thesaurusword\n";
+    }
+    print STAT "first_extractword $first_extractword\n";
+    print STAT "last_extractword $last_extractword\n";
+    print STAT "first_contentword $first_contentword\n";
+    print STAT "last_contentword $last_contentword\n";
+    print STAT "first_symbol $first_delimiter\n";
+    print STAT "last_symbol $last_contentword\n";
+    print STAT "first_word $first_stopword\n";
+    print STAT "last_word $last_contentword\n";
+    close STAT;
+
+    undef @vocab;
+
+
+    # Create numbers file
+    # Save text as symbol numbers
+    print $out "Saving text as numbers in $phinddir/clauses.numbers\n" if ($verbosity > 1);
+    
+    open(TXT, "<$phinddir/clauses");
+    open(NUM, ">$phinddir/clauses.numbers");
+    
+##    $phrasedelimiter = $symbol{lc($senlimit)}; # jrm21
+##    print NUM "$symbol{lc($colstart)}\n"; # jrm21
+    $phrasedelimiter = $symbol{$senlimit};
+    print NUM "$symbol{$colstart}\n";
+    
+    # set up the special symbols that delimit documents and sentences
+    while(<TXT>) {
+	
+	# split sentence into a list of tokens
+	$line = $_;
+	next unless ($line =~ /./);
+	@words = split(/\s+/, $line);
+	
+	# output one token at a time
+	foreach $word (@words) {
+# don't lower-case special delimiters - jrm21
+	    if (!map {if ($word eq $_) {1} else {()}} @delimiters) {
+		$word = lc($word);
+	    }
+	    print NUM "$symbol{$word}\n";
+	}
+	
+	# output phrase delimiter
+	print NUM "$phrasedelimiter\n";
+    }
+    
+    close TXT;
+#    print NUM "$symbol{lc($colend)}\n";# jrm21
+    print NUM "$symbol{$colend}\n";
+    close NUM;
+
+    # Save thesaurus  data in one convienient file
+    if ($thesaurus) {
+
+	my $thesaurusfile = &util::filename_cat($phinddir, "$thesaurus.numbers");
+
+
+	print $out "Saving thesaurus as numbers in $thesaurusfile\n" 
+	    if ($verbosity > 1);
+
+	# Read the thesaurus terms
+	my ($num, $text, %thes_symbols);
+	
+	open(TH, "<$thesaurus_terms");
+	while(<TH>) {
+	    chomp;
+	    @words = split(/\s+/, $_);
+	    $num = shift @words;
+	    $text = "";
+
+	    # translate words into symbol numbers
+	    foreach $word (@words) {
+		$word = lc($word);
+		if ($symbol{$word}) {
+		    $text .= "s$symbol{$word} ";
+		} elsif ($verbosity) {
+		    print $out "Phind: No thesaurus symbol, ignoring \"$word\"\n";
+		}
+	    }
+	    $text =~ s/ $//;
+	    $thes_symbols{$num} = $text;
+	}
+	close TH;
+
+	# Read the thesaurus links and write the corresponding data
+	open(TH, "<$thesaurus_links");
+	open(THOUT, ">$thesaurusfile");
+
+	while(<TH>) {
+	    chomp;
+	    ($num, $text) = split(/:/, $_);
+
+	    if (defined($thes_symbols{$num})) {
+		print THOUT "$num:$thes_symbols{$num}:$text\n";
+	    } else {
+		print THOUT "$num:untranslated:$text\n";
+	    }
+	}
+	close TH;    
+	close THOUT;
+    }
+
+
+
+
+}
+
+
+# renumber_phrases
+#
+# Prepare the phrases file to be input to mgpp.  The biggest problem is
+# reconciling the phrase identifiers used by the suffix program (which
+# we'll call suffix-id numbers) with the numbers used in the thesaurus
+# (theesaurus-id) to create a ciommon set of phind id numbers (phind-id).
+# Phind-id numbers must be sorted by frequency of occurance.
+#
+# Start creating a set of phind-id numbers from the sorted suffix-id
+# numbers and (if required) the thesaurus-id numbers.  Then add any other
+# phrases occuring in the thesaurus.
+#
+# The last thing we have to do is restore the vocabulary information to the
+# phrase file so that the phrases are stored as words, not as symbol
+# numbers.
+
+# The original phrases file looks something like this:
+#   159396-1:s5175:4:1:116149-2:3:d2240,2;d2253;d2254
+#   159409-1:s5263:6:1:159410-2:6:d2122;d2128;d2129;d2130;d2215;d2380
+#   159415-1:s5267:9:1:159418-2:8:d3,2;d632;d633;d668;d1934;d2010;d2281;d2374
+#   159426-1:s5273:5:2:159429-2,115168-17:5:d252;d815;d938;d939;d2361
+
+
+sub renumber_phrases {
+    my ($self) = @_;
+
+    renumber_suffix_data($self);
+    renumber_thesaurus_data($self);
+    restore_vocabulary_data($self);
+
+}
+
+
+
+# renumber_suffix_data
+#
+# Translate phrases file to phrases.2 using phind keys instead
+# of suffix keys and sorting the expansion data.
+
+sub renumber_suffix_data {
+    my ($self) = @_;
+    
+    my $verbosity = $self->{'verbosity'};
+    my $out = $self->{'outhandle'};
+    print $out "Translate phrases: suffix-ids become phind-id's\n" 
+	if ($verbosity);
+    
+    my $phinddir = $self->{'phinddir'};
+    my $infile = &util::filename_cat($phinddir, 'phrases');
+    my $outfile = &util::filename_cat($phinddir, 'phrases.2');
+
+    # Read the phrase file.  Calculate initial set of phind-id
+    # numbers and store (suffixid -> frequency) relation.
+
+    my %suffixtophind;
+    my @totalfrequency;
+    my (@fields, $suffixid);
+    my $nextphind = 1;
+    
+    open(IN, "<$infile");
+    while(<IN>) {
+
+	chomp;
+	@fields = split(/:/, $_);
+	
+	# get next suffixid and phindid
+	$suffixid = shift @fields;
+	$suffixtophind{$suffixid} = $nextphind;
+
+	# store total frequency
+	shift @fields;
+	$totalfrequency[$nextphind] = shift @fields;
+
+	$nextphind++;
+    }
+    close IN;
+
+
+    # Translate phrases file to phrases.2.  Use phind keys (not suffix
+    # keys), sort expansion and document occurance data in order of
+    # descending frequency..
+    open(IN, "<$infile");
+    open(OUT, ">$outfile");
+    
+    my ($phindid, $text, $tf, $countexp, $expansions, $countdocs, $documents);
+    my (@documwents, @newexp, $k, $n);
+    my $linenumber = 0;
+
+    while(<IN>) {
+	
+	# read the line
+	chomp;
+	@fields = split(/:/, $_);
+	
+	# get a phrase number for this line
+	$suffixid = shift @fields;
+	die unless (defined($suffixtophind{$suffixid}));
+	$phindid = $suffixtophind{$suffixid};
+	
+	# get the symbols in the phrase
+	$text = shift @fields;
+
+	# output status information
+	$linenumber++;
+	if ($verbosity > 2) {
+	    if ($linenumber % 1000 == 0) {
+		print $out "line $linenumber:\t$phindid\t$suffixid\t($text)\n";
+	    }
+	    # what are $num and $key??
+	    #print $out "$num: $key\t($text)\n" if ($verbosity > 3);
+	}
+
+	# get the phrase frequency
+	$tf = shift @fields;
+	
+	# get the number of expansions
+	$countexp = shift @fields;
+	
+	# get the expansions, convert them into phind-id numbers, and sort them
+	$expansions = shift @fields;
+	@newexp = ();
+	foreach $k (split(/,/, $expansions)) {
+	    die "ERROR - no phindid for: $k" unless (defined($suffixtophind{$k}));
+	    $n = $suffixtophind{$k};
+	    push @newexp, $n;
+	}
+	@newexp = sort {$totalfrequency[$b] <=> $totalfrequency[$a]} @newexp;
+
+	# get the number of documents
+	$countdocs = shift @fields;
+	
+	# get the documents and sort them
+	$documents = shift @fields;
+	$documents =~ s/d//g;
+	my @documents = split(/;/, $documents);
+	@documents = sort by_doc_frequency @documents;
+
+	# output the phrase data
+ 	print OUT "$phindid:$text:$tf:$countexp:$countdocs:";
+	print OUT join(",", @newexp), ",:", join(";", @documents), ";\n";
+	
+    }
+
+    close IN;
+    close OUT;
+}
+
+
+# renumber_thesaurus_data
+#
+# Translate phrases.2 to phrases.3, adding thesaurus data if available.
+
+sub renumber_thesaurus_data {
+    my ($self) = @_;
+  
+    my $out = $self->{'outhandle'};
+    my $verbosity = $self->{'verbosity'};
+    my $thesaurus = $self->{'thesaurus'};
+
+    my $phinddir = $self->{'phinddir'};
+    my $infile = &util::filename_cat($phinddir, "phrases.2");
+    my $outfile = &util::filename_cat($phinddir, "phrases.3");
+
+
+    # If no thesaurus is defined, simply move the phrases file.
+    if (!$thesaurus) {
+	print $out "Translate phrases.2: no thesaurus data\n" 
+	    if ($verbosity);
+	&util::mv($infile, $outfile);
+	return;
+    }
+
+    print $out "Translate phrases.2: add thesaurus data\n" 
+	if ($verbosity);
+
+    # 1.
+    # Read thesaurus file and store (symbols->thesaurusid) mapping
+    my $thesaurusfile = &util::filename_cat($phinddir, "$thesaurus.numbers");
+    my %symbolstothesid;
+    my (@fields, $thesid, $symbols);
+    
+    open(TH, "<$thesaurusfile");
+
+    while (<TH>) {
+	
+	chomp;
+	@fields = split(/:/, $_);
+	
+	# get id and text
+	$thesid = shift @fields;
+	$symbols = shift @fields;
+	$symbolstothesid{$symbols} = $thesid;
+    }
+    close TH;    
+
+    # 2. 
+    # Read phrases file to find thesaurus entries that already
+    # have a phindid.  Store their phind-ids for later translation,
+    # and store their frequency for later sorting.
+    my %thesaurustophindid;
+    my %phindidtofrequency;
+    my ($phindid, $freq);
+
+    open(IN, "<$infile");
+    
+    while(<IN>) {
+	
+	chomp;
+	@fields = split(/:/, $_);
+	
+	# phindid and symbols for this line
+	$phindid = shift @fields;
+	$symbols = shift @fields;
+	$freq = shift @fields;
+
+	# do we have a thesaurus id corresponding to this phrase?
+	if (defined($symbolstothesid{$symbols})) {
+	    $thesid = $symbolstothesid{$symbols};
+	    $thesaurustophindid{$thesid} = $phindid;
+	    $phindidtofrequency{$phindid} = $freq;
+	}
+    }
+    close IN;
+  
+    undef %symbolstothesid;
+
+    # 3.
+    # Create phind-id numbers for remaining thesaurus entries,
+    # and note that their frequency is 0 for later sorting.
+    my $nextphindid = $phindid + 1;
+
+    open(TH, "<$thesaurusfile");
+    while(<TH>) {
+	
+	chomp;
+	@fields = split(/:/, $_);
+	
+	# read thesaurus-id and ensure it has a corresponding phind-id
+	$thesid = shift @fields;
+	if (!defined($thesaurustophindid{$thesid})) {
+	    $thesaurustophindid{$thesid} = $nextphindid;
+	    $phindidtofrequency{$nextphindid} = 0;
+	    $nextphindid++;
+	}
+    }
+    close TH;
+
+    # 4.
+    # Translate thesaurus file, replacing thesaurus-id numbers with 
+    # phind-id numbers.
+    my $newthesaurusfile = &util::filename_cat($phinddir, "$thesaurus.phindid");
+    my ($relations, $linkcounter, $linktext, $linktype, @linkdata);
+    my (@links, $linkid, %linkidtotype, $newrelation);
+
+    open(TH, "<$thesaurusfile");
+    open(TO, ">$newthesaurusfile");
+    while(<TH>) {
+	
+	chomp;
+	@fields = split(/:/, $_);
+	
+	# phindid and symbols for this line
+	($thesid, $symbols, $relations) = @fields;
+	
+	die unless ($thesid && $symbols);
+	die unless $thesaurustophindid{$thesid};
+	$phindid = $thesaurustophindid{$thesid};
+
+	# convert each part of the relation string to use phind-id numbers
+	# at the same time, we want to sort the list by frequency.
+	undef %linkidtotype;
+	
+	foreach $linktext (split(/;/, $relations)) {
+	    @linkdata = split(/,/, $linktext);
+	    
+	    # remember the linktype (e.g. BT, NT)
+	    $linktype = shift @linkdata;
+	    
+	    # store the type of each link
+	    foreach $thesid (@linkdata) {
+		die unless (defined($thesaurustophindid{$thesid}));
+		$linkidtotype{$thesaurustophindid{$thesid}} = $linktype;
+	    }
+	}
+
+	# sort the list of links, first by frequency, then by type.
+	@links = sort { ($phindidtofrequency{$b} <=> $phindidtofrequency{$a}) 
+                        or ($linkidtotype{$a} cmp $linkidtotype{$b}) } (keys %linkidtotype);
+	$linkcounter = (scalar @links);
+
+	# create a string describing the link information
+	$linktype = $linkidtotype{$links[0]};
+	$newrelation = $linktype;
+	foreach $linkid (@links) {
+	    if ($linkidtotype{$linkid} ne $linktype) {
+		$linktype = $linkidtotype{$linkid};
+		$newrelation .= ";" . $linktype;
+	    }
+	    $newrelation .= "," . $linkid;
+	}
+	$newrelation .= ";";
+	
+
+	# output the new line
+	print TO "$phindid:$symbols:$linkcounter:$newrelation:\n";
+    }
+    close TH;
+    close TO;
+
+    undef %thesaurustophindid;
+    undef %linkidtotype;
+    undef %phindidtofrequency;
+
+    # 5.
+    # Read thesaurus data (in phind-id format) into memory
+    my %thesaurusdata;
+
+    open(TH, "<$newthesaurusfile");
+    while(<TH>) {
+	chomp;
+	($phindid, $symbols, $linkcounter, $relations) = split(/:/, $_);
+	die unless ($phindid && $symbols);
+	$thesaurusdata{$phindid} = "$symbols:$linkcounter:$relations";
+    }
+    close TH;
+
+    # 6. 
+    # Add thesaurus data to phrases file
+    my ($text, $tf, $countexp, $expansions, $countdocs, $documents);
+    my (@documwents, @newexp, $k, $n);
+    my $linenumber = 0;
+
+    open(IN, "<$infile");
+    open(OUT, ">$outfile");
+
+    # Update existing phrases
+    while(<IN>) {
+	
+	chomp;
+	@fields = split(/:/, $_);
+		
+	# get data for this line
+	$phindid = shift @fields;
+	
+	# output the phrase data, with thesaurus information
+ 	print OUT "$phindid:", join(":", @fields);
+
+	# add thesaurus data
+	if (defined($thesaurusdata{$phindid})) {
+	    @fields = split(/:/, $thesaurusdata{$phindid});
+	    shift @fields;
+	    $linkcounter = shift @fields;
+	    $relations = shift @fields;
+
+	    print OUT ":$linkcounter:$relations";
+	    $thesaurusdata{$phindid} = "";
+	}
+	print OUT "\n";
+    }
+    close IN;
+
+    # Add phrases that aren't already in the file
+    foreach $phindid (sort numerically keys %thesaurusdata) {
+	next unless ($thesaurusdata{$phindid});
+
+	@fields = split(/:/, $thesaurusdata{$phindid});
+	$symbols = shift @fields;
+	$linkcounter = shift @fields;
+	$relations = shift @fields;
+
+	print OUT "$phindid:$symbols:0:0:0:::$linkcounter:$relations\n";
+    }
+    close OUT;
+
+}
+
+# restore_vocabulary_data
+#
+# Read phrases.3 and restore vocabulary information. Then write 
+# this data to the MGPP input files (pword.txt and pdata.txt) and
+# (if requested) to the saved phrases file.
+
+sub restore_vocabulary_data {
+    my ($self) = @_;
+ 
+    my $out = $self->{'outhandle'};
+    my $verbosity = $self->{'verbosity'};
+    print $out "Translate phrases.3: restore vocabulary\n" if ($verbosity);
+
+    my $phinddir = $self->{'phinddir'};
+    my $infile = &util::filename_cat($phinddir, 'phrases.3');
+    my $vocabfile = &util::filename_cat($phinddir, 'clauses.vocab');
+    my $datafile = &util::filename_cat($phinddir, 'pdata.txt');
+    my $wordfile = &util::filename_cat($phinddir, 'pword.txt');
+
+    my $savephrases = $self->{'savephrases'};
+
+    # 1.
+    # Read the vocabulary file
+    open(V, "<$vocabfile")
+	|| die "Cannot open $vocabfile: $!";
+    my @symbol;
+    my $i = 1;
+    while(<V>) {
+	chomp;
+	$symbol[$i++] = $_;
+    }
+    close V;
+
+    # 2. 
+    # Translate phrases.3 to MGPP input files
+    my ($key, $text, $word, $isThesaurus, $line);
+    my @fields;
+    my $linenumber = 0;
+
+    open(IN, "<$infile");
+    open(DATA, ">$datafile");
+    open(WORD, ">$wordfile");
+
+    # Save the phrases in a separate text file
+    if ($savephrases) {
+	print $out "Saving phrases in $savephrases\n" if ($verbosity);
+	open(SAVE, ">$savephrases");
+    }
+
+    while(<IN>) {
+	
+	# read the line
+	chomp;
+	$line = $_;
+	@fields = split(/:/, $line);
+	
+	# get a phrase number for this line
+	$key = shift @fields;
+	
+	# restore the text of the phrase
+	$text = shift @fields;
+	$text =~ s/s(\d+)/$symbol[$1]/g;
+	if ($text =~ / /) {
+	    $word = "";
+	} elsif ($text ne 'untranslated') {
+	    $word = $text;
+	}
+
+	# output the phrase data
+	print DATA "<Document>";
+ 	print DATA "$key:$text:", join(":", @fields), ":\n";
+	
+	# output the word index search data
+	print WORD "<Document>$word\n";
+
+	# output the phrases to a text file
+	if ($savephrases) {
+	    if ((scalar @fields) == 7) {
+		$isThesaurus = 1;
+	    } else {
+		$isThesaurus = 0;
+	    }
+	    print SAVE $fields[0], "\t", $fields[2], "\t$isThesaurus\t$text\n";
+	}
+    }
+    close IN;
+    close WORD;
+    close DATA;
+    close SAVE if ($savephrases);
+
+}
+
+
+
+# sort routines used to renumber phrases
+
+sub numerically { $a <=> $b }
+
+sub by_doc_frequency { 
+    my $fa = 1;
+    if ($a =~ /,/) {
+	$fa = $a;
+	$fa =~ s/\d+,//;
+    }
+    my $fb = 1;
+    if ($b =~ /,/) {
+	$fb = $b;
+	$fb =~ s/\d+,//;
+    }
+
+    return ($fb <=> $fa);
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/classify/SectionList.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/classify/SectionList.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/classify/SectionList.pm	(revision 10506)
@@ -0,0 +1,153 @@
+###########################################################################
+#
+# SectionList.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# Same as List classifier but includes all sections of document
+# (excluding top level) rather than just top level document 
+# itself
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package SectionList;
+
+use List;
+use sorttools;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @SectionList::ISA = ('List');
+}
+
+my $arguments = [];
+my $options = { 'name'     => "SectionList",
+		'desc'     => "{SectionList.desc}",
+		'abstract' => "no",
+		'inherits' => "yes" };
+
+
+sub new { 
+    my ($class) = shift (@_);
+    my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
+    push(@$classifierslist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new List($classifierslist,$inputargs,$hashArgOptLists): new List($classifierslist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub classify {
+    my $self = shift (@_);
+    my ($doc_obj, @options) = @_;
+    
+    # @options used by AZCompactList when is uses SectionList internally
+    # are we sorting the list??
+    my $nosort = 0;
+    if (defined $self->{'sort'} && $self->{'sort'} eq "nosort") {
+	$nosort = 1;
+    }
+
+    my $thissection = undef;
+
+    foreach my $option (@options)
+    {
+	if ($option =~ m/^section=(\d+)$/i) 
+	{
+	    $thissection = $1;
+	}
+    }
+
+    my $sortmeta = "";
+    if (!$nosort && defined $self->{'sort'}) {
+	if ($self->{'sort'} =~ /^filename$/i) {
+	    $sortmeta = $doc_obj->get_source_filename();
+	} else {
+	    $sortmeta = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $self->{'sort'});
+	    if (defined $sortmeta) {
+		$sortmeta = &sorttools::format_metadata_for_sorting($self->{'sort'}, $sortmeta, $doc_obj);
+	    }
+	}
+	$sortmeta = "" unless defined $sortmeta;
+    }
+
+    if (defined $thissection) {
+	# just classify the one section
+	$self->classify_section($thissection, $doc_obj, $sortmeta, $nosort);
+    } else    
+    {
+	$thissection = $doc_obj->get_next_section ($doc_obj->get_top_section());
+	while (defined $thissection) {
+	    $self->classify_section($thissection, $doc_obj, $sortmeta, $nosort);
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    }
+}
+
+sub classify_section {
+    my $self = shift (@_);
+    my ($section, $doc_obj, $sortmeta, $nosort) = @_;
+
+    my $doc_OID = $doc_obj->get_OID();
+    $nosort = 0 unless defined $nosort;
+    $sortmeta = "" unless defined $sortmeta;
+
+    my $metavalue;
+    my $metaname;
+    if (defined $self->{'meta_list'}) {
+	# find the first available metadata
+	foreach my $m (@{$self->{'meta_list'}}) {
+	    $metavalue = $doc_obj->get_metadata_element($section, $m);
+	    $metaname = $m;
+	    last if defined $metavalue;
+	} 
+	#if we haven't found a metavalue here, then the section shouldn't be included
+	return unless defined $metavalue;
+    }
+    
+    # we know the section should be included, add it now if we are not sorting
+    if ($nosort) {
+	push (@{$self->{'list'}}, "$doc_OID.$section");
+	return;
+    }
+    # check that it hasn't been added already
+    if (defined $self->{'list'}->{"$doc_OID.$section"}) {
+	my $outhandle = $self->{'outhandle'};
+	print $outhandle "WARNING: SectionList::classify called multiple times for $doc_OID.$section\n";
+    } 
+
+    if (defined $self->{'sort'}) {
+	# sorting on alternative metadata
+	$self->{'list'}->{"$doc_OID.$section"} = $sortmeta;
+    } else {
+	# sorting on the classification metadata
+	# do the same formatting on the meta value as for sort meta
+	$metavalue = &sorttools::format_metadata_for_sorting($metaname, $metavalue, $doc_obj);
+	$self->{'list'}->{"$doc_OID.$section"} = $metavalue;
+    }
+}
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cnseg.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cnseg.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cnseg.pm	(revision 10506)
@@ -0,0 +1,74 @@
+###########################################################################
+#
+# cnseg.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+# this package segments a chinese UTF-8 encoded Unicode
+# string into words.
+
+package cnseg;
+
+use unicode;
+
+
+# 'segment' takes a UTF-8 encoded Unicode Chinese-language
+# string and places U-200B between words -- the ZERO
+# WIDTH SPACE. Each line is treated as a separate 
+# paragraph, so lines in one paragraph should
+# be joined before using this method (normally a single
+# word might span more than one line within a paragraph).
+#
+# 'segment' is currently written in Perl, however, I (Rodger)
+# plan to use C++ (via pipes) once a more complex (and useful!)
+# algorithm is being used. Currently, each Chinese character
+# is treated as a seperate word.
+
+sub segment {
+    my ($in) = @_;
+    my ($c);
+
+    my $uniin = &unicode::utf82unicode($in);
+    my $out = [];
+
+    my $space = 1; # start doesn't need a space
+    foreach $c (@$uniin) {
+	if (($c >= 0x4e00 && $c <= 0x9fa5) ||
+	    ($c >= 0xf900 && $c <= 0xfa2d)) {
+	    # Chinese character
+	    push (@$out, 0x200b) unless $space;
+	    push (@$out, $c);
+	    push (@$out, 0x200b);
+	    $space = 1;
+
+	} else {
+	    # non-Chinese character
+	    push (@$out, $c);
+	    $space = 0;
+	}
+    }
+
+    return &unicode::unicode2utf8($out);
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/colcfg.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/colcfg.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/colcfg.pm	(revision 10506)
@@ -0,0 +1,146 @@
+###########################################################################
+#
+# colcfg.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# reads in a collection configuration file
+
+package colcfg;
+
+use cfgread;
+use strict;
+
+# the collection configuration file data is stored in the form
+#
+# {'creator'}->string
+# {'public'}->string
+# {'defaultindex'}->string
+# {'importdir'}->string
+# {'archivedir'}->string
+# {'cachedir'}->string
+# {'builddir'}->string
+# {'removeold'}->string
+# {'textcompress'}->string
+# {'buildtype'}->string
+# {'maxnumeric'}->string
+# {'separate_cjk'}->string
+# {'sections_index_document_metadata'}->string (always, unless_section_metadata_exists)
+# {'maintainer'}->array of strings
+# {'languages'}->array of strings
+# {'indexsubcollections'}->array of strings
+# {'indexes'}->array of strings
+# {'dontbuild'}->array of strings
+# {'dontgdbm'}->array of strings
+# {'mirror'}->array of strings
+# {'phind'}->array of strings
+# {'levels'}->array of strings (for mgpp eg Section, Paragraph)
+# {'searchtype'}->array of strings (for mgpp, form or plain)
+
+# {'subcollection'}->hash of key-value pairs
+
+# {'acquire'}->array of arrays of strings
+# {'plugin'}->array of arrays of strings
+# {'classify'}->array of arrays of strings
+
+# {'collectionmeta'}->hash of key->hash of param-value -used 
+# for language specification
+#    for example, collectionmeta->collectionname->default->demo
+#                                               ->mi->maori demo
+
+sub read_collect_cfg {
+    my ($filename) = @_;
+
+    return &cfgread::read_cfg_file ($filename, 
+				    q/^(creator|public|defaultindex|importdir|/ .
+					q/archivedir|cachedir|builddir|removeold|/ .
+					q/textcompress|buildtype|no_text|keepold|gzip|/ .
+					q/verbosity|remove_empty_classifications|OIDtype|/ .
+					q/groupsize|maxdocs|debug|mode|saveas|/ .
+					q/sortmeta|removesuffix|removeprefix|create_images|/ .
+					q/maxnumeric|separate_cjk|language_metadata|/ .
+					q/no_strip_html|index|sections_index_document_metadata)$/,
+				    q/(maintainer|languages|indexsubcollections|/ .
+				       q/indexes|dontbuild|dontgdbm|mirror|levels|/ .
+				       q/searchtype|searchtypes)$/,
+				    q/^(subcollection|format)$/,
+				    q/^(acquire|plugin|classify)$/,
+				    q/^(collectionmeta)$/);
+}
+
+sub write_collect_cfg {
+    my ($filename, $data) = @_;
+    
+    &cfgread::write_cfg_file($filename, $data,
+			     q/^(creator|public|defaultindex|importdir|/ .
+				 q/archivedir|cachedir|builddir|removeold|/ .
+				 q/textcompress|buildtype|no_text|keepold|gzip|/ .
+				 q/verbosity|remove_empty_classifications|OIDtype|/.
+				 q/groupsize|maxdocs|debug|mode|saveas|/ .
+				 q/sortmeta|removesuffix|removeprefix|create_images|/ .
+				 q/maxnumeric|separate_cjk|language_metadata/ .
+				 q/no_strip_html|index|sections_index_document_metadata)$/,
+			     q/^(maintainer|languages|indexsubcollections|/ .
+				 q/indexes|dontbuild|dontgdbm|mirror|levels|/.
+				 q/searchtype|searchtypes)$/,
+			     q/^(subcollection|format)$/,
+			     q/^(acquire|plugin|classify)$/,
+			     q/^(collectionmeta)$/);
+}
+
+
+# the build configuration file data is stored in the form
+#
+# {'builddate'}->string
+# {'buildtype'}->string
+# {'metadata'}->array of strings
+# {'languages'}->array of strings
+# {'numdocs'}->string
+# {'numsections'}->string
+# {'numwords'}->string
+# {'numbytes'}->string
+# {'maxnumeric'}->string
+# {'indexfields'}->array of strings
+# {'indexfieldmap'}->array of strings in the form "field->FI"
+# {'indexmap'} -> array of strings
+# {'indexlevels'} -> array of strings
+# {'textlevel'}->string
+# {'levelmap'} -> array of strings in the form "level->shortname"
+sub read_build_cfg {
+    my ($filename) = @_;
+
+    return &cfgread::read_cfg_file ($filename, 
+			    q/^(builddate|buildtype|numdocs|numsections|numwords|numbytes|maxnumeric|textlevel|indexstem)$/, 
+				    q/^(metadata|languages|indexfields|indexfieldmap|indexmap|indexlevels|levelmap)$/);
+}
+
+sub write_build_cfg {
+    my ($filename, $data) = @_;
+
+    &cfgread::write_cfg_file($filename, $data,
+	       q/^(builddate|buildtype|numdocs|numsections|numwords|numbytes|maxnumeric|textlevel|indexstem)$/, 
+	       q/^(metadata|languages|indexfieldsindexfieldmap|indexmap|indexlevels|levelmap)$/);
+}
+
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Batch.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Batch.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Batch.pm	(revision 10506)
@@ -0,0 +1,155 @@
+package MARC::Batch;
+
+=head1 NAME
+
+MARC::Batch - Perl module for handling files of MARC::Record objects
+
+=cut
+
+use strict;
+use integer;
+eval 'use warnings' if $] >= 5.006;
+
+=head1 VERSION
+
+Version 1.10
+
+    $Id$
+
+=cut
+
+use vars '$VERSION'; $VERSION = '1.10';
+
+=head1 SYNOPSIS
+
+MARC::Batch hides all the file handling of files of C<MARC::Record>s.
+C<MARC::Record> still does the file I/O, but C<MARC::Batch> handles the
+multiple-file aspects.
+
+    use MARC::Batch;
+
+    my $batch = new MARC::Batch( 'USMARC', @files );
+    while ( my $marc = $batch->next ) {
+	print $marc->subfield(245,"a"), "\n";
+    }
+
+=head1 EXPORT
+
+None.  Everything is a class method.
+
+=head1 METHODS
+
+=head2 new( $type, [@files] )
+
+Create a C<MARC::Batch> object that will process C<@files>.
+
+C<$type> must be either "USMARC" or "MicroLIF".  If you want to specify 
+"MARC::File::USMARC" or "MARC::File::MicroLIF", that's OK, too.
+
+=cut
+
+sub new {
+    my $class = shift;
+    my $type = shift;
+
+    my $marcclass = ($type =~ /^MARC::File/) ? $type : "MARC::File::$type";
+
+    eval "require $marcclass";
+    die $@ if $@;
+
+    my @files = @_;
+
+    my $self = {
+	filelist =>	[@files],
+	filestack =>	[@files],
+	filename =>	undef,
+	marcclass =>	$marcclass,
+	file =>		undef,
+    };
+
+    bless $self, $class;
+
+    return $self;
+} # new()
+
+
+=head2 next()
+
+Read the next record from the files.  If the current file is at EOF, close
+it and open the next one.
+
+=cut
+
+sub next {
+    my $self = shift;
+
+    # If we have an open file, just use it and go.
+    if ( $self->{file} ) {
+	my $rec = $self->{file}->next();
+	return $rec if $rec;
+    }
+
+    $self->{file} = undef;
+
+    # Get the next file off the stack, if there is one
+    $self->{filename} = shift @{$self->{filestack}} or return undef;
+
+    # Instantiate a filename for it
+    my $marcclass = $self->{marcclass};
+    $self->{file} = $marcclass->in( $self->{filename} ) or return undef;
+
+    return $self->{file}->next();
+}
+
+=head2 filename()
+
+Returns the currently open filename
+
+=cut
+
+sub filename {
+    my $self = shift;
+
+    return $self->{filename};
+}
+
+=head2 warnings() 
+
+Returns any warnings that have accumulated while processing a particular 
+batch file. As a side effect the warning buffer will be cleared.
+
+=cut
+
+sub warnings {
+    my $self = shift;
+    my $file = $self->{file}; 
+    return(undef) if !$file;
+    return ($file->warnings());
+}
+
+
+1;
+
+__END__
+
+=head1 RELATED MODULES
+
+L<MARC::Record>, L<MARC::Lint>
+
+=head1 TODO
+
+None yet.  Send me your ideas and needs.
+
+=head1 LICENSE
+
+This code may be distributed under the same terms as Perl itself. 
+
+Please note that these modules are not products of or supported by the
+employers of the various contributors to the code.
+
+=head1 AUTHOR
+
+Andy Lester, E<lt>marc@petdance.comE<gt> or E<lt>alester@flr.follett.comE<gt>
+
+=cut
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Field.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Field.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Field.pm	(revision 10506)
@@ -0,0 +1,487 @@
+package MARC::Field;
+
+use strict;
+use integer;
+eval 'use warnings' if $] >= 5.006;
+
+use constant SUBFIELD_INDICATOR => "\x1F";
+use constant END_OF_FIELD       => "\x1E";
+
+use vars qw( $ERROR );
+
+=head1 NAME
+
+MARC::Field - Perl extension for handling MARC fields
+
+=head1 VERSION
+
+Version 1.10
+
+    $Id$
+
+=cut
+
+use vars '$VERSION'; $VERSION = '1.10';
+
+=head1 SYNOPSIS
+
+  use MARC::Field;
+
+  my $field = 
+  	MARC::Field->new( 
+		245, '1', '0',
+			'a' => 'Raccoons and ripe corn / ',
+			'c' => 'Jim Arnosky.'
+		);
+  $field->add_subfields( "a", "1st ed." );
+
+=head1 DESCRIPTION
+
+Defines MARC fields for use in the MARC::Record module.  I suppose
+you could use them on their own, but that wouldn't be very interesting.
+
+=head1 EXPORT
+
+None by default.  Any errors are stored in C<$MARC::Field::ERROR>, which
+C<$MARC::Record> usually bubbles up to C<$MARC::Record::ERROR>.
+
+=head1 METHODS
+
+=head2 C<new(tag,indicator1,indicator2,code,data[,code,data...])>
+
+  my $record = 
+  	MARC::Field->new( 
+		245, '1', '0',
+			'a' => 'Raccoons and ripe corn / ',
+			'c' => 'Jim Arnosky.'
+		);
+
+=cut
+
+sub new($) {
+	my $class = shift;
+	$class = ref($class) || $class;
+
+	my $tagno = shift;
+	($tagno =~ /^\d\d\d$/)
+		or return _gripe( "Tag \"$tagno\" is not a valid tag number." );
+
+	my $self = bless {
+		_tag => $tagno,
+		_warnings => [],
+		}, $class;
+	
+	if ( $tagno < 10 ) { 
+		$self->{_data} = shift;
+	} else {
+		for my $indcode ( qw( _ind1 _ind2 ) ) {
+			my $indicator = shift;
+			if ( $indicator !~ /^[0-9 ]$/ ) {
+				$self->_warn( "Invalid indicator \"$indicator\" forced to blank" ) unless ($indicator eq "");
+				$indicator = " ";
+			}
+			$self->{$indcode} = $indicator;
+		} # for
+		
+		(@_ >= 2)
+			or return _gripe( "Field $tagno must have at least one subfield" );
+
+		# Normally, we go thru add_subfields(), but internally we can cheat
+		$self->{_subfields} = [@_];
+	}
+
+	return $self;
+} # new()
+
+=head2 C<clone()>
+
+Makes a copy of the field.  Note that this is not just the same as saying
+
+    my $newfield = $field;
+
+since that just makes a copy of the reference.  To get a new object, you must
+
+    my $newfield = $field->clone;
+
+=cut
+
+sub clone {
+    my $self = shift;
+
+    my $tagno = $self->tag;
+
+    my $clone = 
+	bless {
+	    _tag => $tagno,
+	    _warnings => [],
+	}, ref($self);
+
+    if ( $tagno < 10 ) {
+	$clone->{_data} = $self->{_data};
+    } else {
+	$clone->{_ind1} = $self->{_ind1};
+	$clone->{_ind2} = $self->{_ind2};
+	$clone->{_subfields} = [@{$self->{_subfields}}]; 
+    }
+
+    return $clone;
+}
+
+=head2 C<update()>
+
+Allows you to change the values of the field. You can update indicators
+and subfields like this:
+
+  $field->update( ind2 => '4', a => 'The ballad of Abe Lincoln');
+
+The amount of items modified will be returned to you as a result of the
+method call.
+
+If you want to update a field that has no indicators or subfields (000-009)
+just call update() with one argument, the string that you would like to 
+set the field to. 
+
+  $field = $record->field( '003' );
+  $field->update('IMchF');
+
+Note: when doing subfield updates be aware that C<update()> will only 
+update the first occurrence. If you need to do anything more complicated
+you need to create a new field and use C<replace_with()>. 
+
+=cut
+
+sub update {
+
+  my $self = shift;
+
+  ## tags 000 - 009 don't have indicators or subfields
+  if ( $self->tag() < 10 ) {
+    $self->{_data} = shift;
+    return(1);
+  }
+  
+  ## otherwise we need to update subfields and indicators
+  my @data = @{$self->{_subfields}}; 
+  my $changes = 0;
+
+  while ( @_ ) {
+
+    my $arg = shift;
+    my $val = shift;
+
+    ## indicator update
+    if ($arg =~ /^ind[12]$/) {
+      $self->{"_$arg"} = $val;
+      $changes++;
+    }
+    ## subfield update
+    else {
+      for (my $i=0; $i<@data; $i=$i+2) {
+	if ($data[$i] eq $arg) {
+	  $data[$i+1] = $val;
+	  $changes++;
+	  last;
+	}
+      }
+    }
+
+  }
+
+  ## synchronize our subfields 
+  $self->{_subfields} = \@data;
+  return($changes);
+
+}
+
+=head2 C<replace_with()> 
+
+Allows you to replace an existing field with a new one. You need to pass 
+C<replace()> a MARC::Field object to replace the existing field with. For 
+example:
+
+  $field = $record->field('245');
+  my $new_field = new MARC::Field('245','0','4','The ballad of Abe Lincoln.');
+  $field->replace_with($new_field);
+
+=cut 
+
+sub replace_with {
+
+  my ($self,$new) = @_;
+  ref($new) =~ /^MARC::Field$/ 
+    or return _gripe("Must pass a MARC::Field object");
+
+  %$self = %$new;
+    
+}
+
+
+=head2 C<tag()>
+
+Returns the three digit tag for the field.
+
+=cut
+
+sub tag {
+	my $self = shift;
+	return $self->{_tag};
+}
+
+=head2 C<indicator(indno)>
+
+Returns the specified indicator.  Returns C<undef> and sets 
+C<$MARC::Field::ERROR> if the I<indno> is not 1 or 2, or if 
+the tag doesn't have indicators.
+
+=cut
+
+sub indicator($) {
+	my $self = shift;
+	my $indno = shift;
+
+	($self->tag >= 10)
+		or return _gripe( "Fields below 010 do not have indicators" );
+
+	if ( $indno == 1 ) {
+		return $self->{_ind1};
+	} elsif ( $indno == 2 ) {
+		return $self->{_ind2};
+	} else {
+		return _gripe( "Indicator number must be 1 or 2" );
+	}
+}
+
+
+
+=head2 C<subfield(code)>
+
+Returns the text from the first subfield matching the subfield code.
+If no matching subfields are found, C<undef> is returned.
+
+If the tag is less than an 010, C<undef> is returned and
+C<$MARC::Field::ERROR> is set.
+
+=cut
+
+sub subfield {
+	my $self = shift;
+	my $code_wanted = shift;
+
+	($self->tag >= 10)
+		or return _gripe( "Fields below 010 do not have subfields" );
+
+	my @data = @{$self->{_subfields}};
+	while ( defined( my $code = shift @data ) ) {
+		return shift @data if ( $code eq $code_wanted );
+		shift @data;
+	}
+
+	return undef;
+}
+
+=head2 C<subfields()>
+
+Returns all the subfields in the field.  What's returned is a list of 
+lists, where the inner list is a subfield code and the subfield data. 
+
+For example, this might be the subfields from a 245 field:
+
+	[
+	  [ 'a', 'Perl in a nutshell :' ],
+	  [ 'b', 'A desktop quick reference.' ],
+	]
+
+=cut
+
+sub subfields {
+	my $self = shift;
+
+	($self->tag >= 10)
+		or return _gripe( "Fields below 010 do not have subfields" );
+
+	my @list;
+	my @data = @{$self->{_subfields}};
+	while ( defined( my $code = shift @data ) ) {
+		push( @list, [$code, shift @data] );
+	}
+	return @list;
+}
+
+sub _gripe(@) {
+	$ERROR = join( "", @_ );
+
+	warn $ERROR;
+
+	return undef;
+}
+
+=head2 C<data()>
+
+Returns the data part of the field, if the tag number is less than 10.
+
+=cut
+
+sub data($) {
+	my $self = shift;
+
+	($self->{_tag} < 10)
+		or return _gripe( "data() is only for tags less than 10" );
+		
+	my $data = shift;
+	$self->{_data} = $data if defined( $data );
+
+	return $self->{_data};
+}
+
+=head2 C<add_subfields(code,text[,code,text ...])>
+
+Adds subfields to the end of the subfield list.
+
+Returns the number of subfields added, or C<undef> if there was an error.
+
+=cut
+
+sub add_subfields(@) {
+	my $self = shift;
+
+	($self->{_tag} >= 10)
+		or return _gripe( "Subfields are only for tags >= 10" );
+
+	push( @{$self->{_subfields}}, @_ );
+	return @_/2;
+}
+
+=head2 C<as_string()>
+
+Returns a string of all subfields run together, without the tag number.
+
+=cut
+
+sub as_string() {
+	my $self = shift;
+
+	return $self->{_data} if $self->tag < 10;
+
+	my @subs;
+
+	my @subdata = @{$self->{_subfields}};
+	while ( @subdata ) {
+		my $code = shift @subdata;
+		my $text = shift @subdata;
+		push( @subs, $text );
+	} # for
+
+	return join( " ", @subs );
+}
+
+
+=head2 C<as_formatted()>
+
+Returns a pretty string for printing in a MARC dump.
+
+=cut
+
+sub as_formatted() {
+	my $self = shift;
+
+	my @lines;
+
+	if ( $self->tag < 10 ) {
+		push( @lines, sprintf( "%03d     %s", $self->{_tag}, $self->{_data} ) );
+	} else {
+		my $hanger = sprintf( "%03d %1.1s%1.1s", $self->{_tag}, $self->{_ind1}, $self->{_ind2} );
+
+		my @subdata = @{$self->{_subfields}};
+		while ( @subdata ) {
+			my $code = shift @subdata;
+			my $text = shift @subdata;
+			push( @lines, sprintf( "%-6.6s _%1.1s%s", $hanger, $code, $text ) );
+			$hanger = "";
+		} # for
+	}
+
+
+
+	return join( "\n", @lines );
+}
+
+
+=head2 C<as_usmarc()>
+
+Returns a string for putting into a USMARC file.  It's really only
+useful by C<MARC::Record::as_usmarc()>.
+
+=cut
+
+sub as_usmarc() {
+	my $self = shift;
+
+	# Tags < 010 are pretty easy
+	if ( $self->tag < 10 ) {
+		return $self->data . END_OF_FIELD;
+	} else {
+		my @subs;
+		my @subdata = @{$self->{_subfields}};
+		while ( @subdata ) {
+			push( @subs, join( "", SUBFIELD_INDICATOR, shift @subdata, shift @subdata ) );
+		} # while
+
+		return join( "", 
+			$self->indicator(1),
+			$self->indicator(2),
+			@subs,
+			END_OF_FIELD,
+			);
+	}
+}
+
+=head2 C<warnings()>
+
+Returns the warnings that were created when the record was read.
+These are things like "Invalid indicators converted to blanks".
+
+The warnings are items that you might be interested in, or might
+not.  It depends on how stringently you're checking data.  If
+you're doing some grunt data analysis, you probably don't care.
+
+=cut
+
+sub warnings() {
+	my $self = shift;
+
+	return @{$self->{_warnings}};
+}
+
+# NOTE: _warn is an object method
+sub _warn($) {
+	my $self = shift;
+
+	push( @{$self->{_warnings}}, join( "", @_ ) );
+}
+
+1;
+
+__END__
+
+=head1 SEE ALSO
+
+See the "SEE ALSO" section for L<MARC::Record>.
+
+=head1 TODO
+
+See the "TODO" section for L<MARC::Record>.
+
+=cut
+
+=head1 LICENSE
+
+This code may be distributed under the same terms as Perl itself. 
+
+Please note that these modules are not products of or supported by the
+employers of the various contributors to the code.
+
+=head1 AUTHOR
+
+Andy Lester, E<lt>marc@petdance.comE<gt> or E<lt>alester@flr.follett.comE<gt>
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/File.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/File.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/File.pm	(revision 10506)
@@ -0,0 +1,202 @@
+package MARC::File;
+
+=head1 NAME
+
+MARC::File - Base class for files of MARC records
+
+=cut
+
+use strict;
+use integer;
+eval 'use warnings' if $] >= 5.006;
+
+use vars qw( $ERROR );
+
+=head1 VERSION
+
+Version 1.10
+
+    $Id$
+
+=cut
+
+use vars '$VERSION'; $VERSION = '1.10';
+
+=head1 SYNOPSIS
+
+    use MARC::File::USMARC;
+
+    my $file = MARC::File::USMARC->in( $filename );
+    
+    while ( my $marc = $file->next() ) {
+	# Do something
+    }
+    $file->close();
+    undef $file;
+
+=head1 EXPORT
+
+None.  
+
+=head1 METHODS
+
+=head2 in()
+
+Opens a file for input.
+
+=cut
+
+sub in {
+    my $class = shift;
+    my $filename = shift;
+
+    my $self = {
+	filename => $filename,
+	_warnings => [],
+    };
+
+    bless $self, $class;
+
+    my $fh = eval { local *FH; open( FH, $filename ) or die; *FH{IO}; };
+
+    if ( $@ ) {
+	undef $self;
+	$MARC::File::ERROR = "Couldn't open $filename: $@";
+    } else {
+	$self->{fh} = $fh;
+    }
+	
+
+    return $self;
+} # new()
+
+sub out {
+    die "Not yet written";
+}
+
+=head2 next()
+
+Reads the next record from the file handle passed in. 
+
+=cut
+
+sub next {
+    my $self = shift;
+    my $rec = $self->_next();
+    return $rec ? $self->decode($rec) : undef;
+}
+
+=head2 skip()
+
+Skips over the next record in the file.  Same as C<next()>,
+without the overhead of parsing a record you're going to throw away
+anyway.
+
+Returns 1 or undef.
+
+=cut
+
+sub skip {
+    my $self = shift;
+
+    my $rec = $self->_next();
+
+    return $rec ? 1 : undef;
+}
+
+=head2 warnings()
+
+Simlilar to MARC::Record and MARC::Batch, warnings() will return any 
+warnings that have accumulated while processing this file; and as a 
+side-effect will clear the warnings buffer.
+
+=cut 
+
+sub warnings {
+    my $self = shift;
+    my @warnings = @{ $self->{_warnings} };
+    $self->{_warnings} = [];
+    return(@warnings);
+}
+
+sub close {
+    my $self = shift;
+
+    close( $self->{fh} );
+    delete $self->{fh};
+    delete $self->{filename};
+
+    return;
+}
+
+sub _unimplemented() {
+    my $self = shift;
+    my $method = shift;
+
+    warn "Method $method must be overridden";
+}
+
+sub write   { $_[0]->_unimplemented("write"); }
+sub decode  { $_[0]->_unimplemented("decode"); }
+
+# NOTE: _warn must be called as an object method
+
+sub _warn {
+    my ($self,$warning) = @_;
+    push( @{ $self->{_warnings} }, $warning );
+    return(undef);
+}
+
+# NOTE: _gripe can be called as an object method, or not.  Your choice.
+sub _gripe(@) {
+    my @parms = @_;
+    if ( @parms ) {
+	my $self = shift @parms;
+
+	if ( ref($self) =~ /^MARC::File/ ) {
+	    push( @parms, " at byte ", tell($self->{fh}) ) if $self->{fh};
+	    push( @parms, " in file ", $self->{filename} ) if $self->{filename};
+	} else {
+	    unshift( @parms, $self );
+	}
+
+	$ERROR = join( "", @parms );
+	warn $ERROR;
+    }
+
+    return(undef);
+}
+
+1;
+
+__END__
+
+=head1 RELATED MODULES
+
+L<MARC::Record>
+
+=head1 TODO
+
+=over 4
+
+=item * C<out()> method
+
+We only handle files for input right now.
+
+=back
+
+=cut
+
+=head1 LICENSE
+
+This code may be distributed under the same terms as Perl itself. 
+
+Please note that these modules are not products of or supported by the
+employers of the various contributors to the code.
+
+=head1 AUTHOR
+
+Andy Lester, E<lt>marc@petdance.comE<gt> or E<lt>alester@flr.follett.comE<gt>
+
+=cut
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/File/MicroLIF.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/File/MicroLIF.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/File/MicroLIF.pm	(revision 10506)
@@ -0,0 +1,128 @@
+package MARC::File::MicroLIF;
+
+=head1 NAME
+
+MARC::File::MicroLIF - MicroLIF-specific file handling
+
+=cut
+
+use strict;
+use integer;
+eval 'use warnings' if $] >= 5.006;
+
+use vars qw( $ERROR );
+
+=head1 VERSION
+
+Version 1.10
+
+    $Id$
+
+=cut
+
+use vars '$VERSION'; $VERSION = '1.10';
+
+use MARC::File;
+use vars qw( @ISA ); @ISA = qw( MARC::File );
+
+use MARC::Record qw( LEADER_LEN );
+
+=head1 SYNOPSIS
+
+    use MARC::File::MicroLIF;
+
+    my $file = MARC::File::MicroLIF::in( $filename );
+    
+    while ( my $marc = $file->next() ) {
+	# Do something
+    }
+    $file->close();
+    undef $file;
+
+=head1 EXPORT
+
+None.  
+
+=head1 METHODS
+
+=cut
+
+sub _next {
+    my $self = shift;
+
+    my $fh = $self->{fh};
+
+    local $/ = "`\n";
+    
+    my $lifrec = <$fh>;
+
+    return $lifrec;
+}
+
+sub decode {
+    my $text = shift;
+    $text = shift if (ref($text)||$text) =~ /^MARC::File/; # Handle being called as a method
+
+    my $marc = MARC::Record->new();
+
+    my @lines = split( /\n/, $text );
+    for my $line ( @lines ) {
+	# Ignore the file header if the calling program hasn't already dealt with it
+	next if $line =~ /^HDR/;
+
+	($line =~ s/^(\d\d\d|LDR)//) or
+	return $marc->_gripe( "Invalid tag number: ", substr( $line, 0, 3 ) );
+	my $tagno = $1;
+
+	($line =~ s/\^$//) or $marc->_warn( "Tag $tagno is missing a trailing caret." );
+
+	if ( $tagno eq "LDR" ) {
+	    $marc->leader( substr( $line, 0, LEADER_LEN ) );
+	} elsif ( $tagno < 10 ) {
+	    $marc->add_fields( $tagno, $line );
+	} else {
+	    $line =~ s/^(.)(.)//;
+	    my ($ind1,$ind2) = ($1,$2);
+	    my @subfields;
+	    my @subfield_data_pairs = split( /_(?=[a-z0-9])/, $line );
+	    shift @subfield_data_pairs; # Leading _ makes an empty pair
+	    for my $pair ( @subfield_data_pairs ) {
+		my ($subfield,$data) = (substr( $pair, 0, 1 ), substr( $pair, 1 ));
+		push( @subfields, $subfield, $data );
+	    }
+	    $marc->add_fields( $tagno, $ind1, $ind2, @subfields );
+	}
+    } # for
+
+    return $marc;
+}
+
+1;
+
+__END__
+
+=head1 TODO
+
+=over 4
+
+=item * Squawks about the final field missing a caret
+
+=back
+
+=head1 RELATED MODULES
+
+L<MARC::File>
+
+=head1 LICENSE
+
+This code may be distributed under the same terms as Perl itself. 
+
+Please note that these modules are not products of or supported by the
+employers of the various contributors to the code.
+
+=head1 AUTHOR
+
+Andy Lester, E<lt>marc@petdance.comE<gt> or E<lt>alester@flr.follett.comE<gt>
+
+=cut
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/File/USMARC.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/File/USMARC.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/File/USMARC.pm	(revision 10506)
@@ -0,0 +1,287 @@
+package MARC::File::USMARC;
+
+=head1 NAME
+
+MARC::File::USMARC - USMARC-specific file handling
+
+=cut
+
+use strict;
+use integer;
+eval 'use bytes'    if $] >= 5.006;
+eval 'use warnings' if $] >= 5.006;
+
+use vars qw( $ERROR );
+
+=head1 VERSION
+
+Version 1.10
+
+    $Id$
+
+=cut
+
+use vars '$VERSION'; $VERSION = '1.10';
+
+use MARC::File;
+use vars qw( @ISA ); @ISA = qw( MARC::File );
+
+use MARC::Record qw( LEADER_LEN );
+use constant SUBFIELD_INDICATOR	    => "\x1F";
+use constant END_OF_FIELD	    => "\x1E";
+use constant END_OF_RECORD	    => "\x1D";
+use constant DIRECTORY_ENTRY_LEN    => 12;
+
+=head1 SYNOPSIS
+
+    use MARC::File::USMARC;
+
+    my $file = MARC::File::USMARC::in( $filename );
+    
+    while ( my $marc = $file->next() ) {
+	# Do something
+    }
+    $file->close();
+    undef $file;
+
+=head1 EXPORT
+
+None.  
+
+=head1 METHODS
+
+=for internal
+
+Internal function to get the next raw record out of a file.
+
+=cut
+
+sub _next {
+    my $self = shift;
+
+    my $fh = $self->{fh};
+
+    my $reclen;
+    return undef if eof($fh);
+
+    local $/ = END_OF_RECORD;
+    my $usmarc = <$fh>;
+
+    if ( length($usmarc) < 5 ) {
+	$self->_warn( "Couldn't find record length" );
+	return $self->_next();
+    }
+
+    $reclen = substr($usmarc,0,5);
+
+    if ( $reclen !~ /^\d{5}$/ or $reclen != length($usmarc) ) {
+	$self->_warn( "Invalid record length \"$reclen\"" );
+	return $self->_next();
+    }
+
+    return $usmarc;
+}
+
+=head2 decode()
+
+Constructor for handling data from a USMARC file.  This function takes care of all
+the tag directory parsing & mangling.
+
+Any warnings or coercions can be checked in the C<warnings()> function.
+
+=cut
+
+sub decode {
+    my $text = shift;
+    $text = shift if (ref($text)||$text) =~ /^MARC::File/;
+
+    my $marc = MARC::Record->new();
+
+    # Check for an all-numeric record length
+    ($text =~ /^(\d{5})/)
+	or return $marc->_warn( "Record length \"", substr( $text, 0, 5 ), "\" is not numeric" );
+
+    my $reclen = $1;
+    ($reclen == length($text))
+	or return $marc->_gripe( "Invalid record length: Leader says $reclen bytes, but it's actually ", length( $text ) );
+
+    $marc->leader( substr( $text, 0, LEADER_LEN ) );
+    my @fields = split( END_OF_FIELD, substr( $text, LEADER_LEN ) );
+    my $dir = shift @fields or return $marc->_warn( "No directory found" );
+
+    (length($dir) % 12 == 0)
+	or return $marc->_gripe( "Invalid directory length" );
+    my $nfields = length($dir)/12;
+
+    my $finalfield = pop @fields;
+    # Check for the record terminator, and ignore it
+    ($finalfield eq END_OF_RECORD)
+    	or $marc->_gripe( "Invalid record terminator: \"$finalfield\"" );
+
+    # Walk thru the directories, and shift off the fields while we're at it
+    # Shouldn't be any non-digits anywhere in any directory entry
+    my @directory = unpack( "A3 A4 A5" x $nfields, $dir );
+    my @bad = grep /\D/, @directory;
+    if ( @bad ) { 
+	return $marc->_gripe( "Non-numeric entries in the tag directory: ", join( ", ", map { "\"$_\"" } @bad ) );
+    }
+
+    my $databytesused = 0;
+    while ( @directory ) {
+	my $tagno = shift @directory;
+	my $len = shift @directory;
+	my $offset = shift @directory;
+	my $tagdata = shift @fields;
+	warn "Specs: ", join( "|", $tagno, $len, $offset, $tagdata ), "\n" if $MARC::Record::DEBUG;
+
+	# Check directory validity
+	($tagno =~ /^\d\d\d$/)
+	    or return $marc->_gripe( "Invalid field number in directory: \"$tagno\"" );
+
+	($len == length($tagdata) + 1)
+	    or $marc->_warn( "Invalid length in the directory for tag $tagno" );
+
+	($offset == $databytesused)
+	    or $marc->_warn( "Directory offsets are out of whack" );
+	$databytesused += $len;
+
+	if ( $tagno < 10 ) {
+	    $marc->add_fields( $tagno, $tagdata )
+		or return undef; # We're relying on add_fields() having set $MARC::Record::ERROR
+	} else {
+	    my @subfields = split( SUBFIELD_INDICATOR, $tagdata );
+	    my $indicators = shift @subfields
+		or return $marc->_gripe( "No subfields found." );
+	    my ($ind1,$ind2);
+	    if ( $indicators =~ /^([0-9 ])([0-9 ])$/ ) {
+		($ind1,$ind2) = ($1,$2);
+	    } else {
+		$marc->_warn( "Invalid indicators \"$indicators\" forced to blanks\n" );
+		($ind1,$ind2) = (" "," ");
+	    }
+
+	    # Split the subfield data into subfield name and data pairs
+	    my @subfield_data = map { (substr($_,0,1),substr($_,1)) } @subfields;
+	    $marc->add_fields( $tagno, $ind1, $ind2, @subfield_data )
+		or return undef;
+	}
+    } # while
+
+    # Once we're done, there shouldn't be any fields left over: They should all have shifted off.
+    (@fields == 0)
+    	or return $marc->_gripe( "I've got leftover fields that weren't in the directory" );
+
+    return $marc;
+}
+
+=head2 update_leader()
+
+If any changes get made to the MARC record, the first 5 bytes of the
+leader (the length) will be invalid.  This function updates the 
+leader with the correct length of the record as it would be if
+written out to a file.
+
+=cut
+
+sub update_leader() {
+	my $self = shift;
+
+	my (undef,undef,$reclen,$baseaddress) = $self->_build_tag_directory();
+
+	$self->_set_leader_lengths( $reclen, $baseaddress );
+}
+
+=head2 _build_tag_directory()
+
+Function for internal use only: Builds the tag directory that gets
+put in front of the data in a MARC record.
+
+Returns two array references, and two lengths: The tag directory, and the data fields themselves,
+the length of all data (including the Leader that we expect will be added),
+and the size of the Leader and tag directory.
+
+=cut
+
+sub _build_tag_directory {
+	my $marc = shift;
+	$marc = shift if (ref($marc)||$marc) =~ /^MARC::File/;
+	die "Wanted a MARC::Record but got a ", ref($marc) unless ref($marc) eq "MARC::Record";
+
+	my @fields;
+	my @directory;
+
+	my $dataend = 0;
+	for my $field ( $marc->fields() ) {
+		# Dump data into proper format
+		my $str = $field->as_usmarc;
+		push( @fields, $str );
+
+		# Create directory entry
+		my $len = length $str;
+		my $direntry = sprintf( "%03d%04d%05d", $field->tag, $len, $dataend );
+		push( @directory, $direntry );
+		$dataend += $len;
+	}
+
+	my $baseaddress = 
+		LEADER_LEN +    # better be 24
+		( @directory * DIRECTORY_ENTRY_LEN ) +
+				# all the directory entries
+		1;           	# end-of-field marker
+
+
+	my $total = 
+		$baseaddress +	# stuff before first field
+		$dataend + 	# Length of the fields
+		1;		# End-of-record marker
+
+
+
+	return (\@fields, \@directory, $total, $baseaddress);
+}
+
+=head2 encode()
+
+Returns a string of characters suitable for writing out to a USMARC file,
+including the leader, directory and all the fields.
+
+=cut
+
+sub encode() {
+    my $marc = shift;
+    $marc = shift if (ref($marc)||$marc) =~ /^MARC::File/;
+
+    my ($fields,$directory,$reclen,$baseaddress) = _build_tag_directory($marc);
+    $marc->set_leader_lengths( $reclen, $baseaddress );
+
+    # Glomp it all together
+    return join("",$marc->leader, @$directory, END_OF_FIELD, @$fields, END_OF_RECORD);
+}
+
+1;
+
+__END__
+
+=head1 RELATED MODULES
+
+L<MARC::Record>
+
+=head1 TODO
+
+Make some sort of autodispatch so that you don't have to explicitly
+specify the MARC::File::X subclass, sort of like how DBI knows to
+use DBD::Oracle or DBD::Mysql.
+
+=head1 LICENSE
+
+This code may be distributed under the same terms as Perl itself. 
+
+Please note that these modules are not products of or supported by the
+employers of the various contributors to the code.
+
+=head1 AUTHOR
+
+Andy Lester, E<lt>marc@petdance.comE<gt> or E<lt>alester@flr.follett.comE<gt>
+
+=cut
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Lint.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Lint.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Lint.pm	(revision 10506)
@@ -0,0 +1,764 @@
+package MARC::Lint;
+
+use strict;
+use integer;
+eval 'use warnings' if $] >= 5.006;
+
+=head1 NAME
+
+MARC::Lint - Perl extension for checking validity of MARC records
+
+=head1 VERSION
+
+Version 1.10
+
+    $Id$
+
+=cut
+
+use vars '$VERSION'; $VERSION = '1.10';
+
+use MARC::Record;
+use MARC::Field;
+
+=head1 SYNOPSIS
+
+  use MARC::Record;
+  use MARC::Lint;
+
+  my $linter = new MARC::Lint;
+  my $filename = shift;
+
+  open( IN, "<", $filename ) or die "Couldn't open $filename: $!\n";
+  binmode( IN ); # for the Windows folks
+  while ( !eof(IN) ) {
+  	my $marc = MARC::Record::next_from_file( *IN );
+	die $MARC::Record::ERROR unless $marc;
+
+	$linter->check_record( $marc );
+
+
+	# Print the title tag
+	print $marc->subfield(245,"a"), "\n";
+
+	# Print the errors that were found
+	print join( "\n", $linter->warnings ), "\n";
+  } # while
+
+  close IN or die "Error closing $filename: $!\n";
+
+Given the following MARC record:
+
+	LDR 00000nam  22002538a 4500
+	100 14 _aWall, Larry.
+	110 1  _aO'Reilly & Associates.
+	245 90 _aProgramming Perl /
+               _aBig Book of Perl /
+               _cLarry Wall, Tom Christiansen & Jon Orwant.
+	250    _a3rd ed.
+	250    _a3rd ed.
+	260    _aCambridge, Mass. :
+	       _bO'Reilly,
+	       _r2000.
+	590 4  _aPersonally signed by Larry.
+	856 43 _uhttp://www.perl.com/
+
+the following errors are generated:
+
+	1XX: Only one 1XX tag is allowed, but I found 2 of them.
+	100: Indicator 2 must be blank
+	245: Indicator 1 must be 0 or 1
+	245: Subfield _a is not repeatable.
+	250: Field is not repeatable.
+	260: Subfield _r is not valid.
+	260: Must have a subfield _c.
+	590: Indicator 1 must be blank
+	856: Indicator 2 must be blank, 0, 1, 2 or 8
+
+=head1 DESCRIPTION
+
+Module for checking validity of MARC records.  99% of the users will want to do 
+something like is shown in the synopsis.  The other intrepid 1% will overload the
+C<MARC::Lint> module's methods and provide their own special field-level checking.
+
+What this means is that if you have certain requirements, such as making sure that
+all 952 tags have a certain call number in them, you can write a function that 
+checks for that, and still get all the benefits of the MARC::Lint framework.
+
+=head1 EXPORT
+
+None.  Everything is done through objects.
+
+=head1 METHODS
+
+=head2 C<new()>
+
+No parms needed.  The C<MARC::Lint> object is little more than a list of warnings 
+and a bunch of rules.
+
+=cut
+
+sub new() {
+	my $class = shift;
+	$class = ref($class) || $class;
+
+	my $self = {
+		_warnings => [],
+	};
+	bless $self, $class;
+
+	$self->_read_rules();
+
+	return $self;
+}
+
+=head2 C<warnings()>
+
+Returns a list of warnings found by C<check_record()> and its brethren.
+
+=cut
+
+sub warnings {
+	my $self = shift;
+
+	return wantarray ? @{$self->{_warnings}} : scalar @{$self->{_warnings}};
+}
+
+=head2 C<clear_warnings()>
+
+Clear the list of warnings for this linter object.  It's automatically called
+when you call C<check_record()>.
+
+=cut
+
+sub clear_warnings {
+	my $self = shift;
+
+	$self->{_warnings} = [];
+}
+
+=head2 C<warn(str[,str...])>
+
+Create a warning message, built from strings passed, like a C<print> statement.
+
+Typically, you'll leave this to C<check_record()>, but industrious programmers
+may want to do their own checking as well.
+
+=cut
+
+sub warn {
+	my $self = shift;
+
+	push( @{$self->{_warnings}}, join( "", @_ ) );
+
+	return undef;
+}
+
+=head2 C<check_record(marc)>
+
+Does all sorts of lint-like checks on the MARC record I<marc>, both on the record as a whole,
+and on the individual fields & subfields.
+
+=cut
+
+sub check_record {
+	my $self = shift;
+	my $marc = shift;
+
+	$self->clear_warnings();
+
+	(ref($marc) eq "MARC::Record")
+		or return $self->warn( "Must pass a MARC::Record object to check_record" );
+
+	if ( (my @_1xx = $marc->field( "1XX" )) > 1 ) {
+		$self->warn( "1XX: Only one 1XX tag is allowed, but I found ", scalar @_1xx, " of them." );
+	}
+
+	if ( not $marc->field( 245 ) ) {
+		$self->warn( "245: No 245 tag." );
+	}
+
+
+	my %field_seen;
+	my $rules = $self->{_rules};
+	for my $field ( $marc->fields ) {
+		my $tagno = $field->tag;
+		my $tagrules = $rules->{$tagno} or next;
+
+		if ( $tagrules->{NR} && $field_seen{$tagno} ) { 
+			$self->warn( "$tagno: Field is not repeatable." );
+		}
+
+		if ( $tagno >= 10 ) {
+			for my $ind ( 1..2 ) {
+				my $indvalue = $field->indicator($ind);
+				if ( not ($indvalue =~ $tagrules->{"ind$ind" . "_regex"}) ) {
+					$self->warn( 
+						"$tagno: Indicator $ind must be ", 
+						$tagrules->{"ind$ind" . "_desc"}, 
+						" but it's \"$indvalue\"" 
+					);
+				}
+			}
+			
+			my %sub_seen;
+			for my $subfield ( $field->subfields ) {
+				my ($code,$data) = @$subfield;
+
+				my $rule = $tagrules->{$code};
+				if ( not defined $rule ) {
+					$self->warn( "$tagno: Subfield _$code is not allowed." );
+				} elsif ( ($rule eq "NR") && $sub_seen{$code} ) {
+					$self->warn( "$tagno: Subfield _$code is not repeatable." );
+				}
+
+				if ( $data =~ /[\t\r\n]/ ) {
+					$self->warn( "$tagno: Subfield _$code has an invalid control character" );
+				}
+
+				++$sub_seen{$code};
+			}
+		}
+
+		# Check to see if a check_xxx() function exists, and call it on the field if it does
+		my $checker = "check_$tagno";
+		if ( $self->can( $checker ) ) {
+			$self->$checker( $field );
+		}
+
+		++$field_seen{$tagno};
+	} # for
+
+	return;
+}
+
+=head2 C<check_I<xxx>(field)>
+
+Various functions to check the different fields.  If the function doesn't exist, 
+then it doesn't get checked.
+
+=cut
+
+sub check_245 {
+	my $self = shift;
+	my $field = shift;
+
+	if ( not $field->subfield( "a" ) ) {
+		$self->warn( "245: Must have a subfield _a." );
+	}
+}
+
+sub check_260 {
+	my $self = shift;
+	my $field = shift;
+
+	if ( not $field->subfield( "c" ) ) {
+		$self->warn( "260: Must have a subfield _c." );
+	}
+}
+
+
+=head1 SEE ALSO
+
+Check the docs for L<MARC::Record>.  All software links are there.
+
+=head1 TODO
+
+=over 4
+
+=item * ISBN and ISSN checking
+
+We can check the 020 and 022 fields with the C<Business::ISBN> and 
+C<Business::ISSN> modules, respectively.
+
+=back
+
+=head1 LICENSE
+
+This code may be distributed under the same terms as Perl itself. 
+
+Please note that these modules are not products of or supported by the
+employers of the various contributors to the code.
+
+=head1 AUTHOR
+
+Andy Lester, E<lt>marc@petdance.comE<gt> or E<lt>alester@flr.follett.comE<gt>
+
+=cut
+
+# Used only to read the stuff from __DATA__
+sub _read_rules() {
+	my $self = shift;
+	
+	my $tell = tell(DATA);  # Stash the position so we can reset it for next time
+
+	local $/ = "";
+	while ( my $lines = <DATA> ) {
+		$lines =~ s/\s+$//;
+		my @keyvals = split( /\s+/, $lines );
+
+		my $tagno = shift @keyvals;
+		my $repeatable = shift @keyvals;
+		
+		my @tag_range = ($tagno);
+		if ( $tagno =~ /^(\d\d)X/ ) {
+			my $base = $1;
+			@tag_range = ( "${base}0" .. "${base}9" );
+		}
+
+		# Handle the ranges of tags.
+		for my $currtag ( @tag_range ) {
+			$self->_parse_tag_rules( $currtag, $repeatable, @keyvals );
+		} # for
+		# I guess I could just have multiple references to the same tag, but I'm not that worried about memory
+	} # while
+
+	seek( DATA, $tell, 0 );
+}
+
+sub _parse_tag_rules {
+	my $self = shift;
+	my $tagno = shift;
+	my $repeatable = shift;
+	my @keyvals = @_;
+
+	my $rules = ($self->{_rules}->{$tagno} ||= {});
+	$rules->{$repeatable} = $repeatable;
+
+	while ( @keyvals ) {
+		my $key = shift @keyvals;
+		my $val = shift @keyvals;
+		
+		$rules->{$key} = $val;
+
+		# Do magic for indicators
+		if ( $key =~ /^ind/ ) {
+			my $desc;
+			my $regex;
+			
+			if ( $val eq "blank" ) {
+				$desc = "blank";
+				$regex = qr/^ $/;
+			} else {
+				$desc = _nice_list($val);
+				$val =~ s/^b/ /;
+				$regex = qr/^[$val]$/;
+			}
+
+		$rules->{$key."_desc"} = $desc;
+		$rules->{$key."_regex"} = $regex;
+		} # if indicator
+	} # while
+}
+
+
+sub _nice_list($) {
+	my $str = shift;
+
+	if ( $str =~ s/(\d)-(\d)/$1 thru $2/ ) {
+		return $str;
+	}
+
+	my @digits = split( //, $str );
+	$digits[0] = "blank" if $digits[0] eq "b";
+	my $last = pop @digits;
+	return join( ", ", @digits ) . " or $last";
+}
+
+sub _ind_regex($) {
+	my $str = shift;
+
+	return qr/^ $/ if $str eq "blank";
+
+	return qr/^[$str]$/;
+}
+
+
+1;
+
+__DATA__
+010	NR
+ind1	blank
+ind2	blank
+a	NR
+z	NR
+
+016	R
+ind1	b7
+ind2	blank
+a	NR
+z	R
+2	NR
+
+020	R
+ind1	blank
+ind2	blank
+a	R
+c	R
+
+022	R
+ind1	blank
+ind2	blank
+a	NR
+
+040	NR
+ind1	blank
+ind2	blank
+a	NR
+c	NR
+d	R
+
+100	NR
+ind1	013
+ind2	blank
+a	NR
+q	NR
+b	R
+c	R
+d	NR
+e	R
+
+110	NR
+ind1	012
+ind2	blank
+a	NR
+b	R
+
+111	NR
+ind1	012
+ind2	blank
+a	NR
+n	R	
+d	NR
+c	NR
+e	R
+
+130	NR
+ind1	0-9
+ind2	blank
+a	NR
+n	R
+p	R
+h	NR
+l	NR
+k	R
+s	NR
+f	NR
+
+240	NR
+ind1	01
+ind2	0-9
+
+245	NR
+ind1	01
+ind2	0-9
+a	NR
+n	R
+p	R
+h	NR
+b	NR
+s	NR
+c	NR
+
+246	NR
+ind1	0123
+ind2	012345678
+a	NR
+h	NR
+b	NR
+n	R
+p	R
+i	NR
+f	NR
+
+250	NR
+ind1	blank
+ind2	blank
+a	NR
+b	NR
+
+260	NR
+ind1	blank
+ind2	blank
+a	R
+b	R
+c	R
+
+300	NR
+ind1	blank
+ind2	blank
+a	R
+b	NR
+c	R
+e	NR
+
+440	R
+ind1	blank
+ind2	0-9
+a	NR
+n	R
+p	R
+v	NR
+
+490	R
+ind1	01
+ind2	blank
+a	R
+v	R
+
+500	R
+ind1	blank
+ind2	blank
+a	NR
+
+504	R
+ind1	blank
+ind2	blank
+a	NR
+
+505	R
+ind1	0128
+ind2	b0
+a	NR
+g	R
+r	R
+t	R
+
+520	R
+ind1	b018
+ind2	blank
+a	R
+b	R
+
+521	R
+ind1	b012348
+ind2	blank
+a	R
+b	NR
+
+526	R
+ind1	08
+ind2	blank
+a	NR
+b	NR
+c	NR
+d	NR
+i	NR
+x	R
+z	R
+
+538	R
+ind1	blank
+ind2	blank
+a	NR
+
+546	R
+ind1	blank
+ind2	blank
+a	NR
+
+586	R
+ind1	b8
+ind2	blank
+a	NR
+
+59X	R
+ind1	blank
+ind2	blank
+a	NR
+
+600	R
+ind1	013
+ind2	012567
+a	NR
+q	NR
+b	R
+c	R
+d	NR
+t	NR
+v	R
+x	R
+y	R
+z	R
+2	NR
+
+610	R
+ind1	012
+ind2	012567
+a	NR
+b	R
+t	NR
+v	R
+x	R
+y	R
+z	R
+2	NR
+
+611	R
+ind1	012
+ind2	012567
+a	NR
+n	R
+d	NR
+c	NR
+v	R
+x	R
+y	R
+z	R
+2	NR
+
+630	R
+ind1	0-9
+ind2	012567
+a	NR
+n	R
+p	R
+l	NR
+k	R
+s	NR
+f	NR
+v	R
+x	R
+y	R
+z	R
+2	NR
+
+650	R
+ind1	blank
+ind2	012567
+a	NR
+v	R
+x	R
+y	R
+z	R
+2	NR
+
+651	R
+ind1	blank
+ind2	012567
+a	NR
+v	R
+x	R
+y	R
+z	R
+2	NR
+
+655	R
+ind1	blank
+ind2	7
+a	NR
+v	R
+x	R
+y	R
+z	R
+2	NR
+
+658	R
+ind1	blank
+ind2	blank
+a	NR
+b	R
+c	NR
+d	NR
+2	NR
+
+69X	R
+ind1	blank
+ind2	blank
+a	NR
+v	R
+x	R
+y	R
+z	R
+
+700	R
+ind1	013
+ind2	b2
+a	NR
+q	NR
+b	R
+c	R
+d	NR
+k	R
+t	NR
+e	R
+f	NR
+
+710	R
+ind1	012
+ind2	b2
+a	NR
+b	R
+e	R
+t	NR
+
+711	R
+ind1	012
+ind2	b2
+a	NR
+n	R
+d	NR
+c	NR
+t	NR
+e	R
+
+730	R
+ind1	0-9
+ind2	b2
+a	NR
+n	R
+p	R
+h	NR
+l	NR
+k	R
+s	NR
+f	NR
+
+740	R
+ind1	0-9
+ind2	b2
+a	NR
+h	NR
+n	R
+p	R
+
+
+800	R
+ind1	013
+ind2	blank
+a	NR
+q	NR
+b	NR
+c	R
+d	NR
+t	NR
+e	R
+v	NR
+
+852	R
+ind1	b01234568
+ind2	b012
+a	NR
+b	R
+h	NR
+i	R
+k	NR
+m	NR
+t	NR
+p	NR
+9	NR
+
+856	R
+ind1	b012347
+ind2	b0128
+a	R
+b	NR
+d	R
+f	R
+h	NR
+i	R
+u	R
+x	R
+z	R
+2	NR
+3	NR
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Record.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Record.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MARC/Record.pm	(revision 10506)
@@ -0,0 +1,705 @@
+package MARC::Record;
+
+=head1 NAME
+
+MARC::Record - Perl extension for handling MARC records
+
+=cut
+
+use strict;
+use integer;
+eval 'use warnings' if $] >= 5.006;
+
+use vars qw( $ERROR );
+
+use MARC::Field;
+
+=head1 VERSION
+
+Version 1.10
+
+    $Id$
+
+=cut
+
+use vars '$VERSION'; $VERSION = '1.10';
+
+use Exporter;
+use vars qw( @ISA @EXPORTS @EXPORT_OK );
+@ISA = qw( Exporter );
+@EXPORTS = qw();
+@EXPORT_OK = qw( LEADER_LEN );
+
+use vars qw( $DEBUG ); $DEBUG = 0;
+
+use constant LEADER_LEN	=> 24;
+
+=head1 DESCRIPTION
+
+Module for handling MARC records as objects.  The file-handling stuff is
+in MARC::File::*.
+
+=head1 EXPORT
+
+None.  
+
+=head1 ERROR HANDLING
+
+Any errors generated are stored in C<$MARC::Record::ERROR>. 
+Warnings are kept with the record and accessible in the C<warnings()> method. 
+
+=head1 METHODS
+
+=head2 new()
+
+Base constructor for the class.  It just returns a completely empty record.
+To get real data, you'll need to populate it with fields, or use one of
+the MARC::File::* modules to read from a file.
+
+=cut
+
+sub new {
+    my $class = shift;
+    $class = ref($class) || $class; # Handle cloning
+    my $self = {
+	_leader => ' ' x 24,
+	_fields => [],
+	_warnings => [],
+    };
+    return bless $self, $class;
+} # new()
+
+
+
+
+=head2 fields()
+
+Returns a list of all the fields in the record. The list contains 
+a MARC::Field object for each field in the record.
+
+=cut
+
+sub fields() {
+    my $self = shift;
+    return @{$self->{_fields}};
+}
+
+=head2 field(tagspec(s))
+
+Returns a list of tags that match the field specifier, or in scalar
+context, just the first matching tag.
+
+The field specifier can be a simple number (i.e. "245"), or use the "X" 
+notation of wildcarding (i.e. subject tags are "6XX").
+
+=cut
+
+my %field_regex;
+
+sub field {
+    my $self = shift;
+    my @specs = @_;
+
+    my @list = ();
+    for my $tag ( @specs ) {
+	my $regex = $field_regex{ $tag };
+
+	# Compile & stash it if necessary
+	if ( not defined $regex ) {
+	    my $pattern = $tag;
+	    $pattern =~ s/X/\\d/g;
+	    $regex = qr/^$pattern$/;
+	    $field_regex{ $tag } = $regex;
+	} # not defined
+
+	for my $maybe ( $self->fields ) {
+	    if ( $maybe->tag =~ $regex ) {
+		return $maybe unless wantarray;
+
+		push( @list, $maybe );
+	    } # if
+	} # for $maybe
+    } # for $tag
+
+    return @list;
+}
+
+=head2 subfield(tag,subfield)
+
+Shortcut method for getting just a subfield for a tag.  These are equivalent:
+
+  my $title = $marc->field(245)->subfield("a");
+  my $title = $marc->subfield(245,"a");
+
+If either the field or subfield can't be found, C<undef> is returned.
+
+=cut
+
+sub subfield($$) {
+    my $self = shift;
+    my $tag = shift;
+    my $subfield = shift;
+
+    my $field = $self->field($tag) or return undef;
+    return $field->subfield($subfield);
+} # subfield()
+
+=head2 insert_grouped_field(C<$field>)
+
+Will insert the specified MARC::Field object into the record in 'grouped
+order' and return true (1) on success, and false (undef) on failure.
+For example, if a '650' field is inserted with insert_grouped_field()
+it will be inserted at the end of the 6XX group of tags. After some discussion
+on the perl4lib list it was descided that this is ordinarily what you will 
+want. If you would like to insert at a specific point in the record you can use 
+insert_fields_after() and insert_fields_before() methods which are described 
+below. 
+
+=cut 
+
+sub insert_grouped_field {
+    my ($self,$new) = @_;
+    _all_parms_are_fields($new) or return(_gripe('Argument must be MARC::Fieldobject'));
+
+    ## try to find the end of the field group and insert it there
+    my $limit = int($new->tag() / 100);
+    my $found = 0;
+    foreach my $field ($self->fields()) {
+	if ( int($field->tag() / 100) > $limit ) {
+	    $self->insert_field_before($field,$new);
+	    $found = 1;
+	    last;
+	}
+    }
+
+    ## if we couldn't find the end of the group, then we must not have 
+    ## any tags this high yet, so just append it
+    if (!$found) {
+	$self->append_fields($new); 
+    }
+
+    return(1);
+
+}
+
+=for internal
+
+=cut
+
+sub _all_parms_are_fields {
+    for ( @_ ) {
+	return 0 unless ref($_) eq 'MARC::Field';
+    }
+    return 1;
+}
+
+=head2 append_field(C<@fields>)
+
+Appends the field specified by C<$field> to the end of the record. 
+C<@fields> need to be MARC::Field objects.
+
+    my $field = MARC::Field->new('590','','','a' => 'My local note.');
+    $record->append_field($field);
+
+Returns the number of fields appended.
+
+=cut
+
+sub append_fields {
+    my $self = shift;
+
+    _all_parms_are_fields(@_) or return(_gripe('Arguments must be MARC::Field objects'));
+
+    push(@{ $self->{_fields} }, @_); 
+    return scalar @_;
+}
+
+=head2 insert_fields_before($before_field,@new_fields)
+
+Inserts the field specified by C<$new_field> before the field C<$before_field>.
+Returns the number of fields inserted, or undef on failures.
+Both C<$before_field> and all C<@new_fields> need to be MARC::Field objects.
+
+    my $before_field = $record->field('260');
+    my $new_field = MARC::Field->new('250','','','a' => '2nd ed.');
+    $record->insert_fields_before($before_field,$new_field);
+
+=cut
+
+sub insert_fields_before {
+    my $self = shift;
+
+    _all_parms_are_fields(@_) or return(_gripe('All arguments must be MARC::Field objects'));
+    my ($before,@new) = @_;
+
+    ## find position of $before
+    my $fields = $self->{_fields};
+    my $pos = 0;
+    foreach my $f (@$fields) {
+	last if ($f == $before);
+	$pos++;
+    }
+
+    ## insert before $before 
+    if ($pos >= @$fields) {
+	return(_gripe("Couldn't find field to insert before"));
+    }
+    splice(@$fields,$pos,0,@new);
+    return scalar @new;
+
+}
+
+=head2 insert_fields_after($after_field,@new_fields)
+
+Identical to L<insert_fields_before()>, but fields are added after C<$after_field>.
+
+=cut
+
+sub insert_fields_after {
+    my $self = shift;
+
+    _all_parms_are_fields(@_) or return(_gripe('All arguments must be MARC::Field objects'));
+    my ($after,@new) = @_;
+
+    ## find position of $after
+    my $fields = $self->{_fields};
+    my $pos = 0;
+    foreach my $f (@$fields) {
+	last if ($f == $after);
+	$pos++;
+    }
+
+    ## insert after $after
+    if ($pos+1 >= @$fields) { 
+	return(_gripe("Couldn't find field to insert after"));
+    }
+    splice(@$fields,$pos+1,0,@new);
+    return scalar @new;
+}
+
+=head2 delete_field(C<$field>)
+
+Deletes a field from the record.
+
+The field must have been retrieved from the record using the 
+C<field()> method.  For example, to delete a 526 tag if it exists:
+
+    my $tag526 = $marc->field( "526" );
+    if ( $tag526 ) {
+	$marc->delete_field( $tag526 );
+    }
+
+C<delete_field()> returns the number of fields that were deleted.
+This shouldn't be 0 unless you didn't get the tag properly.
+
+=cut
+
+sub delete_field {
+    my $self = shift;
+    my $deleter = shift;
+    my $list = $self->{_fields};
+
+    my $old_count = @$list;
+    @$list = grep { $_ != $deleter } @$list;
+    return $old_count - @$list;
+}
+
+=head2 as_usmarc()
+
+This is a wrapper around C<MARC::File::USMARC::encode()> for compatibility with
+older versions of MARC::Record.
+
+=cut
+
+sub as_usmarc() {
+    my $self = shift;
+
+    require MARC::File::USMARC;
+
+    return MARC::File::USMARC::encode( $self );
+}
+
+=head2 as_formatted()
+
+Returns a pretty string for printing in a MARC dump.
+
+=cut
+
+sub as_formatted() {
+    my $self = shift;
+	    
+    my @lines = ( "LDR " . ($self->{_leader} || "") );
+    for my $field ( @{$self->{_fields}} ) {
+	    push( @lines, $field->as_formatted() );
+    }
+
+    return join( "\n", @lines );
+} # as_formatted
+
+=head2 title()
+
+Returns the title from the 245 tag.
+Note that it is a string, not a MARC::Field record.
+
+=cut
+
+sub title() {
+    my $self = shift;
+
+    my $field = $self->field(245) or return "<no 245 tag found>";
+
+    return $field->as_string;
+}
+
+=head2 author()
+
+Returns the author from the 100, 110 or 111 tag.
+Note that it is a string, not a MARC::Field record.
+
+=cut
+
+sub author() {
+    my $self = shift;
+
+    for my $tag ( qw( 100 110 111 ) ) {
+	my $field = $self->field($tag);
+	return $field->as_string() if $field;
+    }
+
+    return "<No author tag found>";
+}
+
+=head2 leader([text])
+
+Returns the leader for the record.  Sets the leader if I<text> is defined.
+No error checking is done on the validity of the leader.
+
+=cut
+
+sub leader {
+    my $self = shift;
+    my $text = shift;
+
+    if ( defined $text ) {
+    	(length($text) eq 24)
+	    or $self->_warn( "Leader must be 24 bytes long" );
+	$self->{_leader} = $text;
+    } # set the leader
+
+    return $self->{_leader};
+} # leader()
+
+=head2 set_leader_lengths( $reclen, $baseaddr )
+
+Internal function for updating the leader's length and base address.
+
+=cut
+
+sub set_leader_lengths {
+    my $self = shift;
+    my $reclen = shift;
+    my $baseaddr = shift;
+    substr($self->{_leader},0,5)  = sprintf("%05d",$reclen);
+    substr($self->{_leader},12,5) = sprintf("%05d",$baseaddr);
+}
+
+=head2 clone( [field specs] )
+
+The C<clone()> method makes a copy of an existing MARC record and returns
+the new version.  Note that you cannot just say:
+
+    my $newmarc = $oldmarc;
+
+This just makes a copy of the reference, not a new object.  You must use
+the C<clone()> method like so:
+
+    my $newmarc = $oldmarc->clone;
+
+You can also specify field specs to filter down only a 
+certain subset of fields.  For instance, if you only wanted the
+title and ISBN tags from a record, you could do this:
+
+    my $small_marc = $marc->clone( 245, '020' );
+
+The order of the fields is preserved as it was in the original record.
+
+=cut
+
+sub clone {
+    my $self = shift;
+    my @keeper_tags = @_;
+
+    my $clone = $self->new();
+    $clone->{_leader} = $self->{_leader};
+
+    my $filtered = @keeper_tags ? [$self->field( @keeper_tags )] : undef;
+
+    for my $field ( $self->fields() ) {
+        if ( !$filtered || (grep {$field==$_} @$filtered ) ) {
+	    $clone->add_fields( $field->clone );
+        }
+    }
+
+    # XXX FIX THIS $clone->update_leader();
+
+    return $clone;
+}
+
+=head2 warnings()
+
+Returns the warnings that were created when the record was read.
+These are things like "Invalid indicators converted to blanks".
+
+The warnings are items that you might be interested in, or might
+not.  It depends on how stringently you're checking data.  If
+you're doing some grunt data analysis, you probably don't care.
+
+A side effect of calling warnings() is that the warning buffer will
+be cleared.
+
+=cut
+
+sub warnings() {
+    my $self = shift;
+    my @warnings = @{$self->{_warnings}};
+    $self->{_warnings} = []; 
+    return @warnings;
+}
+
+=head2 add_fields()
+
+C<add_fields()> is now deprecated, and users are encouraged to use C<append_field()>,
+C<insert_field_after()>, and C<insert_field_before()> since they do what you want 
+probably. It is still here though, for backwards compatability.
+
+C<add_fields()> adds MARC::Field objects to the end of the list.  Returns the 
+number of fields added, or C<undef> if there was an error.
+
+There are three ways of calling C<add_fields()> to add data to the record.
+
+=over 4
+
+=item 1 Create a MARC::Field object and add it
+
+  my $author = MARC::Field->new(
+	        100, "1", " ", a => "Arnosky, Jim."
+	        );
+  $marc->add_fields( $author );
+
+=item 2 Add the data fields directly, and let C<add_fields()> take care of the objectifying.
+
+  $marc->add_fields(
+        245, "1", "0",
+                a => "Raccoons and ripe corn /",
+                c => "Jim Arnosky.",
+        	);
+
+=item 3 Same as #2 above, but pass multiple fields of data in anonymous lists
+
+  $marc->add_fields(
+	[ 250, " ", " ", a => "1st ed." ],
+	[ 650, "1", " ", a => "Raccoons." ],
+	);
+
+=back
+
+=cut
+
+sub add_fields {
+    my $self = shift;
+
+    my $nfields = 0;
+    my $fields = $self->{_fields};
+
+    while ( my $parm = shift ) {
+	# User handed us a list of data (most common possibility)
+	if ( ref($parm) eq "" ) {
+	    my $field = MARC::Field->new( $parm, @_ )
+		    or return _gripe( $MARC::Field::ERROR );
+	    push( @$fields, $field );
+	    ++$nfields;
+	    last; # Bail out, we're done eating parms
+
+	# User handed us an object.
+	} elsif ( ref($parm) eq "MARC::Field" ) {
+	    push( @$fields, $parm );
+	    ++$nfields;
+
+	# User handed us an anonymous list of parms
+	} elsif ( ref($parm) eq "ARRAY" ) {
+	    my $field = MARC::Field->new(@$parm) 
+		or return _gripe( $MARC::Field::ERROR );
+	    push( @$fields, $field );
+	    ++$nfields;
+
+	} else {
+	    return _gripe( "Unknown parm of type", ref($parm), " passed to add_fields()" );
+	} # if
+
+    } # while
+
+    return $nfields;
+}
+
+=head2 new_from_usmarc( $marcblob )
+
+This is a wrapper around C<MARC::File::USMARC::decode()> for compatibility with
+older versions of MARC::Record.
+
+=cut
+
+sub new_from_usmarc {
+    my $blob = shift;
+    $blob = shift if (ref($blob) || ($blob eq "MARC::Record"));
+
+    require MARC::File::USMARC;
+
+    return MARC::File::USMARC::decode( $blob );
+}
+
+
+# NOTE: _warn is an object method
+sub _warn {
+    my $self = shift;
+
+    push( @{$self->{_warnings}}, join( "", @_ ) );
+}
+
+
+# NOTE: _gripe is NOT an object method
+sub _gripe {
+    $ERROR = join( "", @_ );
+
+    warn $ERROR;
+
+    return undef;
+}
+
+
+1;
+
+__END__
+
+=head1 DESIGN NOTES
+
+A brief discussion of why MARC::Record is done the way it is:
+
+=over 4
+
+=item * It's built for quick prototyping
+
+One of the areas Perl excels is in allowing the programmer to 
+create easy solutions quickly.  MARC::Record is designed along
+those same lines.  You want a program to dump all the 6XX
+tags in a file?  MARC::Record is your friend.
+
+=item * It's built for extensibility
+
+Currently, I'm using MARC::Record for analyzing bibliographic
+data, but who knows what might happen in the future?  MARC::Record
+needs to be just as adept at authority data, too.
+
+=item * It's designed around accessor methods
+
+I use method calls everywhere, and I expect calling programs to do
+the same, rather than accessing internal data directly.  If you
+access an object's hash fields on your own, future releases may
+break your code.
+
+=item * It's not built for speed
+
+One of the tradeoffs in using accessor methods is some overhead
+in the method calls.  Is this slow?  I don't know, I haven't measured.
+I would suggest that if you're a cycle junkie that you use
+Benchmark.pm to check to see where your bottlenecks are, and then
+decide if MARC::Record is for you.
+
+=back
+
+=head1 RELATED MODULES
+
+L<MARC::Record>, L<MARC::Lint>
+
+=head1 SEE ALSO
+
+=over 4
+
+=item * perl4lib (L<http://www.rice.edu/perl4lib/>)
+
+A mailing list devoted to the use of Perl in libraries.
+
+=item * Library Of Congress MARC pages (L<http://www.loc.gov/marc/>)
+
+The definitive source for all things MARC.
+
+
+=item * I<Understanding MARC Bibliographic> (L<http://lcweb.loc.gov/marc/umb/>)
+
+Online version of the free booklet.  An excellent overview of the MARC format.  Essential.
+
+
+=item * Tag Of The Month (L<http://www.tagofthemonth.com/>)
+
+Follett Software Company's
+(L<http://www.fsc.follett.com/>) monthly discussion of various MARC tags.
+
+=back
+
+=head1 TODO
+
+=over 4
+
+=item * Incorporate MARC.pm in the distribution.
+
+Combine MARC.pm and MARC::* into one distribution.
+
+=item * Podify MARC.pm
+
+=item * Allow regexes across the entire tag
+
+Imagine something like this:
+
+  my @sears_headings = $marc->tag_grep( /Sears/ );
+
+(from Mike O'Regan)
+
+=item * Insert a field in an arbitrary place in the record
+
+=item * Allow deleting a field
+
+  for my $field ( $record->field( "856" ) ) {
+	$record->delete_field( $field ) unless useful($field);
+	} # for
+
+(from Anne Highsmith hismith@tamu.edu)
+
+
+=item * Modifying an existing field
+
+=back
+
+=head1 IDEAS
+
+Ideas are things that have been considered, but nobody's actually asked for.
+
+=over 4
+
+=item * Create multiple output formats.
+
+These could be ASCII, XML, or MarcMaker.
+
+=back
+
+=head1 LICENSE
+
+This code may be distributed under the same terms as Perl itself. 
+
+Please note that these modules are not products of or supported by the
+employers of the various contributors to the code.
+
+=head1 AUTHOR
+
+Andy Lester, E<lt>marc@petdance.comE<gt> or E<lt>alester@flr.follett.comE<gt>
+
+=cut
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MP3/Info.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MP3/Info.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/MP3/Info.pm	(revision 10506)
@@ -0,0 +1,1563 @@
+package MP3::Info;
+use overload;
+use strict;
+use Carp;
+use Symbol;
+
+use vars qw(
+	@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION $REVISION
+	@mp3_genres %mp3_genres @winamp_genres %winamp_genres $try_harder
+	@t_bitrate @t_sampling_freq @frequency_tbl %v1_tag_fields
+	@v1_tag_names %v2_tag_names %v2_to_v1_names $AUTOLOAD
+	@mp3_info_fields
+);
+
+@ISA = 'Exporter';
+@EXPORT = qw(
+	set_mp3tag get_mp3tag get_mp3info remove_mp3tag
+	use_winamp_genres
+);
+@EXPORT_OK = qw(@mp3_genres %mp3_genres use_mp3_utf8);
+%EXPORT_TAGS = (
+	genres	=> [qw(@mp3_genres %mp3_genres)],
+	utf8	=> [qw(use_mp3_utf8)],
+	all	=> [@EXPORT, @EXPORT_OK]
+);
+
+# $Id$
+($REVISION) = ' $Revision$ ' =~ /\$Revision:\s+([^\s]+)/;
+$VERSION = '1.02';
+
+=pod
+
+=head1 NAME
+
+MP3::Info - Manipulate / fetch info from MP3 audio files
+
+=head1 SYNOPSIS
+
+	#!perl -w
+	use MP3::Info;
+	my $file = 'Pearls_Before_Swine.mp3';
+	set_mp3tag($file, 'Pearls Before Swine', q"77's",
+		'Sticks and Stones', '1990',
+		q"(c) 1990 77's LTD.", 'rock & roll');
+
+	my $tag = get_mp3tag($file) or die "No TAG info";
+	$tag->{GENRE} = 'rock';
+	set_mp3tag($file, $tag);
+
+	my $info = get_mp3info($file);
+	printf "$file length is %d:%d\n", $info->{MM}, $info->{SS};
+
+=cut
+
+{
+	my $c = -1;
+	# set all lower-case and regular-cased versions of genres as keys
+	# with index as value of each key
+	%mp3_genres = map {($_, ++$c, lc, $c)} @mp3_genres;
+
+	# do it again for winamp genres
+	$c = -1;
+	%winamp_genres = map {($_, ++$c, lc, $c)} @winamp_genres;
+}
+
+=pod
+
+	my $mp3 = new MP3::Info $file;
+	$mp3->title('Perls Before Swine');
+	printf "$file length is %s, title is %s\n",
+		$mp3->time, $mp3->title;
+
+
+=head1 DESCRIPTION
+
+=over 4
+
+=item $mp3 = MP3::Info-E<gt>new(FILE)
+
+OOP interface to the rest of the module.  The same keys
+available via get_mp3info and get_mp3tag are available
+via the returned object (using upper case or lower case;
+but note that all-caps "VERSION" will return the module
+version, not the MP3 version).
+
+Passing a value to one of the methods will set the value
+for that tag in the MP3 file, if applicable.
+
+=cut
+
+sub new {
+	my($pack, $file) = @_;
+
+	my $info = get_mp3info($file) or return undef;
+	my $tags = get_mp3tag($file) || { map { ($_ => undef) } @v1_tag_names };
+	my %self = (
+		FILE		=> $file,
+		TRY_HARDER	=> 0
+	);
+
+	@self{@mp3_info_fields, @v1_tag_names, 'file'} = (
+		@{$info}{@mp3_info_fields},
+		@{$tags}{@v1_tag_names},
+		$file
+	);
+
+	return bless \%self, $pack;
+}
+
+sub can {
+	my $self = shift;
+	return $self->SUPER::can(@_) unless ref $self;
+	my $name = uc shift;
+	return sub { $self->$name(@_) } if exists $self->{$name};
+	return undef;
+}
+
+sub AUTOLOAD {
+	my($self) = @_;
+	(my $name = uc $AUTOLOAD) =~ s/^.*://;
+
+	if (exists $self->{$name}) {
+		my $sub = exists $v1_tag_fields{$name}
+			? sub {
+				if (defined $_[1]) {
+					$_[0]->{$name} = $_[1];
+					set_mp3tag($_[0]->{FILE}, $_[0]);
+				}
+				return $_[0]->{$name};
+			}
+			: sub {
+				return $_[0]->{$name}
+			};
+
+		no strict 'refs';
+		*{$AUTOLOAD} = $sub;
+		goto &$AUTOLOAD;
+
+	} else {
+		carp(sprintf "No method '$name' available in package %s.",
+			__PACKAGE__);
+	}
+}
+
+sub DESTROY {
+
+}
+
+
+=item use_mp3_utf8([STATUS])
+
+Tells MP3::Info to (or not) return TAG info in UTF-8.
+TRUE is 1, FALSE is 0.  Default is FALSE.
+
+Will only be able to it on if Unicode::String is available.  ID3v2
+tags will be converted to UTF-8 according to the encoding specified
+in each tag; ID3v1 tags will be assumed Latin-1 and converted
+to UTF-8.
+
+Function returns status (TRUE/FALSE).  If no argument is supplied,
+or an unaccepted argument is supplied, function merely returns status.
+
+This function is not exported by default, but may be exported
+with the C<:utf8> or C<:all> export tag.
+
+=cut
+
+my $unicode_module = eval { require Unicode::String };
+my $UNICODE = 0;
+
+sub use_mp3_utf8 {
+	my($val) = @_;
+	if ($val == 1) {
+		$UNICODE = 1 if $unicode_module;
+	} elsif ($val == 0) {
+		$UNICODE = 0;
+	}
+	return $UNICODE;
+}
+
+=pod
+
+=item use_winamp_genres()
+
+Puts WinAmp genres into C<@mp3_genres> and C<%mp3_genres>
+(adds 68 additional genres to the default list of 80).
+This is a separate function because these are non-standard
+genres, but they are included because they are widely used.
+
+You can import the data structures with one of:
+
+	use MP3::Info qw(:genres);
+	use MP3::Info qw(:DEFAULT :genres);
+	use MP3::Info qw(:all);
+
+=cut
+
+sub use_winamp_genres {
+	%mp3_genres = %winamp_genres;
+	@mp3_genres = @winamp_genres;
+	return 1;
+}
+
+=pod
+
+=item remove_mp3tag (FILE [, VERSION, BUFFER])
+
+Can remove ID3v1 or ID3v2 tags.  VERSION should be C<1> for ID3v1,
+C<2> for ID3v2, and C<ALL> for both.
+
+For ID3v1, removes last 128 bytes from file if those last 128 bytes begin
+with the text 'TAG'.  File will be 128 bytes shorter.
+
+For ID3v2, removes ID3v2 tag.  Because an ID3v2 tag is at the
+beginning of the file, we rewrite the file after removing the tag data.
+The buffer for rewriting the file is 4MB.  BUFFER (in bytes) ca
+change the buffer size.
+
+Returns the number of bytes removed, or -1 if no tag removed,
+or undef if there is an error.
+
+=cut
+
+sub remove_mp3tag {
+	my($file, $version, $buf) = @_;
+	my($fh, $return);
+
+	$buf ||= 4096*1024;  # the bigger the faster
+	$version ||= 1;
+
+	if (not (defined $file && $file ne '')) {
+		$@ = "No file specified";
+		return undef;
+	}
+
+	if (not -s $file) {
+		$@ = "File is empty";
+		return undef;
+	}
+
+	if (ref $file) { # filehandle passed
+		$fh = $file;
+	} else {
+		$fh = gensym;
+		if (not open $fh, "+< $file\0") {
+			$@ = "Can't open $file: $!";
+			return undef;
+		}
+	}
+
+	binmode $fh;
+
+	if ($version eq 1 || $version eq 'ALL') {
+		seek $fh, -128, 2;
+		my $tell = tell $fh;
+		if (<$fh> =~ /^TAG/) {
+			truncate $fh, $tell or carp "Can't truncate '$file': $!";
+			$return += 128;
+		}
+	}
+
+	if ($version eq 2 || $version eq 'ALL') {
+		my $h = _get_v2head($fh);
+		if ($h) {
+			local $\;
+			seek $fh, 0, 2;
+			my $eof = tell $fh;
+			my $off = $h->{tag_size};
+
+			while ($off < $eof) {
+				seek $fh, $off, 0;
+				read $fh, my($bytes), $buf;
+				seek $fh, $off - $h->{tag_size}, 0;
+				print $fh $bytes;
+				$off += $buf;
+			}
+
+			truncate $fh, $eof - $h->{tag_size}
+				or carp "Can't truncate '$file': $!";
+			$return += $h->{tag_size};
+		}
+	}
+
+	_close($file, $fh);
+
+	return $return || -1;
+}
+
+
+=pod
+
+=item set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM])
+
+=item set_mp3tag (FILE, $HASHREF)
+
+Adds/changes tag information in an MP3 audio file.  Will clobber
+any existing information in file.
+
+Fields are TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE.  All fields have
+a 30-byte limit, except for YEAR, which has a four-byte limit, and GENRE,
+which is one byte in the file.  The GENRE passed in the function is a
+case-insensitive text string representing a genre found in C<@mp3_genres>.
+
+Will accept either a list of values, or a hashref of the type
+returned by C<get_mp3tag>.
+
+If TRACKNUM is present (for ID3v1.1), then the COMMENT field can only be
+28 bytes.
+
+ID3v2 support may come eventually.  Note that if you set a tag on a file
+with ID3v2, the set tag will be for ID3v1[.1] only, and if you call
+C<get_mp3_tag> on the file, it will show you the (unchanged) ID3v2 tags,
+unless you specify ID3v1.
+
+=cut
+
+sub set_mp3tag {
+	my($file, $title, $artist, $album, $year, $comment, $genre, $tracknum) = @_;
+	my(%info, $oldfh, $ref, $fh);
+	local %v1_tag_fields = %v1_tag_fields;
+
+	# set each to '' if undef
+	for ($title, $artist, $album, $year, $comment, $tracknum, $genre,
+		(@info{@v1_tag_names}))
+		{$_ = defined() ? $_ : ''}
+
+	($ref) = (overload::StrVal($title) =~ /^(?:.*\=)?([^=]*)\((?:[^\(]*)\)$/)
+		if ref $title;
+	# populate data to hashref if hashref is not passed
+	if (!$ref) {
+		(@info{@v1_tag_names}) =
+			($title, $artist, $album, $year, $comment, $tracknum, $genre);
+
+	# put data from hashref into hashref if hashref is passed
+	} elsif ($ref eq 'HASH') {
+		%info = %$title;
+
+	# return otherwise
+	} else {
+		carp(<<'EOT');
+Usage: set_mp3tag (FILE, TITLE, ARTIST, ALBUM, YEAR, COMMENT, GENRE [, TRACKNUM])
+       set_mp3tag (FILE, $HASHREF)
+EOT
+		return undef;
+	}
+
+	if (not (defined $file && $file ne '')) {
+		$@ = "No file specified";
+		return undef;
+	}
+
+	if (not -s $file) {
+		$@ = "File is empty";
+		return undef;
+	}
+
+	# comment field length 28 if ID3v1.1
+	$v1_tag_fields{COMMENT} = 28 if $info{TRACKNUM};
+
+
+	# only if -w is on
+	if ($^W) {
+		# warn if fields too long
+		foreach my $field (keys %v1_tag_fields) {
+			$info{$field} = '' unless defined $info{$field};
+			if (length($info{$field}) > $v1_tag_fields{$field}) {
+				carp "Data too long for field $field: truncated to " .
+					 "$v1_tag_fields{$field}";
+			}
+		}
+
+		if ($info{GENRE}) {
+			carp "Genre `$info{GENRE}' does not exist\n"
+				unless exists $mp3_genres{$info{GENRE}};
+		}
+	}
+
+	if ($info{TRACKNUM}) {
+		$info{TRACKNUM} =~ s/^(\d+)\/(\d+)$/$1/;
+		unless ($info{TRACKNUM} =~ /^\d+$/ &&
+			$info{TRACKNUM} > 0 && $info{TRACKNUM} < 256) {
+			carp "Tracknum `$info{TRACKNUM}' must be an integer " .
+				"from 1 and 255\n" if $^W;
+			$info{TRACKNUM} = '';
+		}
+	}
+
+	if (ref $file) { # filehandle passed
+		$fh = $file;
+	} else {
+		$fh = gensym;
+		if (not open $fh, "+< $file\0") {
+			$@ = "Can't open $file: $!";
+			return undef;
+		}
+	}
+
+	binmode $fh;
+	$oldfh = select $fh;
+	seek $fh, -128, 2;
+	# go to end of file if no tag, beginning of file if tag
+	seek $fh, (<$fh> =~ /^TAG/ ? -128 : 0), 2;
+
+	# get genre value
+	$info{GENRE} = $info{GENRE} && exists $mp3_genres{$info{GENRE}} ?
+		$mp3_genres{$info{GENRE}} : 255;  # some default genre
+
+	local $\;
+	# print TAG to file
+	if ($info{TRACKNUM}) {
+		print pack "a3a30a30a30a4a28xCC", 'TAG', @info{@v1_tag_names};
+	} else {
+		print pack "a3a30a30a30a4a30C", 'TAG', @info{@v1_tag_names[0..4, 6]};
+	}
+
+	select $oldfh;
+
+	_close($file, $fh);
+
+	return 1;
+}
+
+=pod
+
+=item get_mp3tag (FILE [, VERSION, RAW_V2])
+
+Returns hash reference containing tag information in MP3 file.  The keys
+returned are the same as those supplied for C<set_mp3tag>, except in the
+case of RAW_V2 being set.
+
+If VERSION is C<1>, the information is taken from the ID3v1 tag (if present).
+If VERSION is C<2>, the information is taken from the ID3v2 tag (if present).
+If VERSION is not supplied, or is false, the ID3v1 tag is read if present, and
+then, if present, the ID3v2 tag information will override any existing ID3v1
+tag info.
+
+If RAW_V2 is C<1>, the raw ID3v2 tag data is returned, without any manipulation
+of text encoding.  The key name is the same as the frame ID (ID to name mappings
+are in the global %v2_tag_names).
+
+If RAW_V2 is C<2>, the ID3v2 tag data is returned, manipulating for Unicode if
+necessary, etc.  It also takes multiple values for a given key (such as comments)
+and puts them in an arrayref.
+
+If the ID3v2 version is older than ID3v2.2.0 or newer than ID3v2.4.0, it will
+not be read.
+
+Strings returned will be in Latin-1, unless UTF-8 is specified (L<use_mp3_utf8>),
+(unless RAW_V2 is C<1>).
+
+Also returns a TAGVERSION key, containing the ID3 version used for the returned
+data (if TAGVERSION argument is C<0>, may contain two versions).
+
+=cut
+
+sub get_mp3tag {
+	my($file, $ver, $raw_v2) = @_;
+	my($tag, $v1, $v2, $v2h, %info, @array, $fh);
+	$raw_v2 ||= 0;
+	$ver = !$ver ? 0 : ($ver == 2 || $ver == 1) ? $ver : 0;
+
+	if (not (defined $file && $file ne '')) {
+		$@ = "No file specified";
+		return undef;
+	}
+
+	if (not -s $file) {
+		$@ = "File is empty";
+		return undef;
+	}
+
+	if (ref $file) { # filehandle passed
+		$fh = $file;
+	} else {
+		$fh = gensym;
+		if (not open $fh, "< $file\0") {
+			$@ = "Can't open $file: $!";
+			return undef;
+		}
+	}
+
+	binmode $fh;
+
+	if ($ver < 2) {
+		seek $fh, -128, 2;
+		while(defined(my $line = <$fh>)) { $tag .= $line }
+
+		if ($tag =~ /^TAG/) {
+			$v1 = 1;
+			if (substr($tag, -3, 2) =~ /\000[^\000]/) {
+				(undef, @info{@v1_tag_names}) =
+					(unpack('a3a30a30a30a4a28', $tag),
+					ord(substr($tag, -2, 1)),
+					$mp3_genres[ord(substr $tag, -1)]);
+				$info{TAGVERSION} = 'ID3v1.1';
+			} else {
+				(undef, @info{@v1_tag_names[0..4, 6]}) =
+					(unpack('a3a30a30a30a4a30', $tag),
+					$mp3_genres[ord(substr $tag, -1)]);
+				$info{TAGVERSION} = 'ID3v1';
+			}
+			if ($UNICODE) {
+				for my $key (keys %info) {
+					next unless $info{$key};
+					my $u = Unicode::String::latin1($info{$key});
+					$info{$key} = $u->utf8;
+				}
+			}
+		} elsif ($ver == 1) {
+			_close($file, $fh);
+			$@ = "No ID3v1 tag found";
+			return undef;
+		}
+	}
+
+	($v2, $v2h) = _get_v2tag($fh);
+
+	unless ($v1 || $v2) {
+		_close($file, $fh);
+		$@ = "No ID3 tag found";
+		return undef;
+	}
+
+	if (($ver == 0 || $ver == 2) && $v2) {
+		if ($raw_v2 == 1 && $ver == 2) {
+			%info = %$v2;
+			$info{TAGVERSION} = $v2h->{version};
+		} else {
+			my $hash = $raw_v2 == 2 ? { map { ($_, $_) } keys %v2_tag_names } : \%v2_to_v1_names;
+			for my $id (keys %$hash) {
+				if (exists $v2->{$id}) {
+					if ($id =~ /^TCON?$/ && $v2->{$id} =~ /^.?\((\d+)\)/) {
+						$info{$hash->{$id}} = $mp3_genres[$1];
+					} else {
+						my $data1 = $v2->{$id};
+
+						# this is tricky ... if this is an arrayref,
+						# we want to only return one, so we pick the
+						# first one.  but if it is a comment, we pick
+						# the first one where the first charcter after
+						# the language is NULL and not an additional
+						# sub-comment, because that is most likely to be
+						# the user-supplied comment
+						if (ref $data1 && !$raw_v2) {
+							if ($id =~ /^COMM?$/) {
+								my($newdata) = grep /^(....\000)/, @{$data1};
+								$data1 = $newdata || $data1->[0];
+							} else {
+								$data1 = $data1->[0];
+							}
+						}
+
+						$data1 = [ $data1 ] if ! ref $data1;
+
+						for my $data (@$data1) {
+							$data =~ s/^(.)//; # strip first char (text encoding)
+							my $encoding = $1;
+							my $desc;
+							if ($id =~ /^COM[M ]?$/) {
+								$data =~ s/^(?:...)//;		# strip language
+								$data =~ s/^(.*?)\000+//;	# strip up to first NULL(s),
+												# for sub-comment
+								$desc = $1;
+							}
+
+							if ($UNICODE) {
+								if ($encoding eq "\001" || $encoding eq "\002") {  # UTF-16, UTF-16BE
+									my $u = Unicode::String::utf16($data);
+									$data = $u->utf8;
+									$data =~ s/^\xEF\xBB\xBF//;	# strip BOM
+								} elsif ($encoding eq "\000") {
+									my $u = Unicode::String::latin1($data);
+									$data = $u->utf8;
+								}
+							}
+
+							if ($raw_v2 == 2 && $desc) {
+								$data = { $desc => $data };
+							}
+
+							if ($raw_v2 == 2 && exists $info{$hash->{$id}}) {
+								if (ref $info{$hash->{$id}} eq 'ARRAY') {
+									push @{$info{$hash->{$id}}}, $data;
+								} else {
+									$info{$hash->{$id}} = [ $info{$hash->{$id}}, $data ];
+								}
+							} else {
+								$info{$hash->{$id}} = $data;
+							}
+						}
+					}
+				}
+			}
+			if ($ver == 0 && $info{TAGVERSION}) {
+				$info{TAGVERSION} .= ' / ' . $v2h->{version};
+			} else {
+				$info{TAGVERSION} = $v2h->{version};
+			}
+		}
+	}
+
+	unless ($raw_v2 && $ver == 2) {
+		foreach my $key (keys %info) {
+			if (defined $info{$key}) {
+				$info{$key} =~ s/\000+.*//g;
+				$info{$key} =~ s/\s+$//;
+			}
+		}
+
+		for (@v1_tag_names) {
+			$info{$_} = '' unless defined $info{$_};
+		}
+	}
+
+	if (keys %info && exists $info{GENRE} && ! defined $info{GENRE}) {
+		$info{GENRE} = '';
+	}
+
+	_close($file, $fh);
+
+	return keys %info ? {%info} : undef;
+}
+
+sub _get_v2tag {
+	my($fh) = @_;
+	my($off, $myseek, $myseek_22, $myseek_23, $v2, $h, $hlen, $num);
+	$h = {};
+
+	$v2 = _get_v2head($fh) or return;
+	if ($v2->{major_version} < 2) {
+		carp "This is $v2->{version}; " .
+		     "ID3v2 versions older than ID3v2.2.0 not supported\n"
+		     if $^W;
+		return;
+	}
+
+	if ($v2->{major_version} == 2) {
+		$hlen = 6;
+		$num = 3;
+	} else {
+		$hlen = 10;
+		$num = 4;
+	}
+
+	$myseek = sub {
+		seek $fh, $off, 0;
+		read $fh, my($bytes), $hlen;
+		return unless $bytes =~ /^([A-Z0-9]{$num})/
+			|| ($num == 4 && $bytes =~ /^(COM )/);  # stupid iTunes
+		my($id, $size) = ($1, $hlen);
+		my @bytes = reverse unpack "C$num", substr($bytes, $num, $num);
+		for my $i (0 .. ($num - 1)) {
+			$size += $bytes[$i] * 256 ** $i;
+		}
+		return($id, $size);
+	};
+
+	$off = $v2->{ext_header_size} + 10;
+
+	while ($off < $v2->{tag_size}) {
+		my($id, $size) = &$myseek or last;
+		seek $fh, $off + $hlen, 0;
+		read $fh, my($bytes), $size - $hlen;
+		if (exists $h->{$id}) {
+			if (ref $h->{$id} eq 'ARRAY') {
+				push @{$h->{$id}}, $bytes;
+			} else {
+				$h->{$id} = [$h->{$id}, $bytes];
+			}
+		} else {
+			$h->{$id} = $bytes;
+		}
+		$off += $size;
+	}
+
+	return($h, $v2);
+}
+
+
+=pod
+
+=item get_mp3info (FILE)
+
+Returns hash reference containing file information for MP3 file.
+This data cannot be changed.  Returned data:
+
+	VERSION		MPEG audio version (1, 2, 2.5)
+	LAYER		MPEG layer description (1, 2, 3)
+	STEREO		boolean for audio is in stereo
+
+	VBR		boolean for variable bitrate
+	BITRATE		bitrate in kbps (average for VBR files)
+	FREQUENCY	frequency in kHz
+	SIZE		bytes in audio stream
+
+	SECS		total seconds
+	MM		minutes
+	SS		leftover seconds
+	MS		leftover milliseconds
+	TIME		time in MM:SS
+
+	COPYRIGHT	boolean for audio is copyrighted
+	PADDING		boolean for MP3 frames are padded
+	MODE		channel mode (0 = stereo, 1 = joint stereo,
+			2 = dual channel, 3 = single channel)
+	FRAMES		approximate number of frames
+	FRAME_LENGTH	approximate length of a frame
+	VBR_SCALE	VBR scale from VBR header
+
+On error, returns nothing and sets C<$@>.
+
+=cut
+
+sub get_mp3info {
+	my($file) = @_;
+	my($off, $myseek, $byte, $eof, $h, $tot, $fh);
+
+	if (not (defined $file && $file ne '')) {
+		$@ = "No file specified";
+		return undef;
+	}
+
+	if (not -s $file) {
+		$@ = "File is empty";
+		return undef;
+	}
+
+	if (ref $file) { # filehandle passed
+		$fh = $file;
+	} else {
+		$fh = gensym;
+		if (not open $fh, "< $file\0") {
+			$@ = "Can't open $file: $!";
+			return undef;
+		}
+	}
+
+	$off = 0;
+	$tot = 4096;
+
+	$myseek = sub {
+		seek $fh, $off, 0;
+		read $fh, $byte, 4;
+	};
+
+	binmode $fh;
+	&$myseek;
+
+	if ($off == 0) {
+		if (my $id3v2 = _get_v2head($fh)) {
+			$tot += $off += $id3v2->{tag_size};
+			&$myseek;
+		}
+	}
+
+	$h = _get_head($byte);
+	until (_is_mp3($h)) {
+		$off++;
+		&$myseek;
+		$h = _get_head($byte);
+		if ($off > $tot && !$try_harder) {
+			_close($file, $fh);
+			$@ = "Couldn't find MP3 header (perhaps set " .
+			     '$MP3::Info::try_harder and retry)';
+			return undef;
+		}
+	}
+
+	my $vbr = _get_vbr($fh, $h, \$off);
+
+	seek $fh, 0, 2;
+	$eof = tell $fh;
+	seek $fh, -128, 2;
+	$off += 128 if <$fh> =~ /^TAG/ ? 1 : 0;
+
+	_close($file, $fh);
+
+	$h->{size} = $eof - $off;
+
+	return _get_info($h, $vbr);
+}
+
+sub _get_info {
+	my($h, $vbr) = @_;
+	my $i;
+
+	$i->{VERSION}	= $h->{IDR} == 2 ? 2 : $h->{IDR} == 3 ? 1 :
+				$h->{IDR} == 0 ? 2.5 : 0;
+	$i->{LAYER}	= 4 - $h->{layer};
+	$i->{VBR}	= defined $vbr ? 1 : 0;
+
+	$i->{COPYRIGHT}	= $h->{copyright} ? 1 : 0;
+	$i->{PADDING}	= $h->{padding_bit} ? 1 : 0;
+	$i->{STEREO}	= $h->{mode} == 3 ? 0 : 1;
+	$i->{MODE}	= $h->{mode};
+
+	$i->{SIZE}	= $vbr && $vbr->{bytes} ? $vbr->{bytes} : $h->{size};
+
+	my $mfs		= $h->{fs} / ($h->{ID} ? 144000 : 72000);
+	$i->{FRAMES}	= int($vbr && $vbr->{frames}
+				? $vbr->{frames}
+				: $i->{SIZE} / $h->{bitrate} / $mfs
+			  );
+
+	if ($vbr) {
+		$i->{VBR_SCALE}	= $vbr->{scale} if $vbr->{scale};
+		$h->{bitrate}	= $i->{SIZE} / $i->{FRAMES} * $mfs;
+		if (not $h->{bitrate}) {
+			$@ = "Couldn't determine VBR bitrate";
+			return undef;
+		}
+	}
+
+	$h->{'length'}	= ($i->{SIZE} * 8) / $h->{bitrate} / 10;
+	$i->{SECS}	= $h->{'length'} / 100;
+	$i->{MM}	= int $i->{SECS} / 60;
+	$i->{SS}	= int $i->{SECS} % 60;
+	$i->{MS}	= (($i->{SECS} - ($i->{MM} * 60) - $i->{SS}) * 1000);
+#	$i->{LF}	= ($i->{MS} / 1000) * ($i->{FRAMES} / $i->{SECS});
+#	int($i->{MS} / 100 * 75);  # is this right?
+	$i->{TIME}	= sprintf "%.2d:%.2d", @{$i}{'MM', 'SS'};
+
+	$i->{BITRATE}		= int $h->{bitrate};
+	# should we just return if ! FRAMES?
+	$i->{FRAME_LENGTH}	= int($h->{size} / $i->{FRAMES}) if $i->{FRAMES};
+	$i->{FREQUENCY}		= $frequency_tbl[3 * $h->{IDR} + $h->{sampling_freq}];
+
+	return $i;
+}
+
+sub _get_head {
+	my($byte) = @_;
+	my($bytes, $h);
+
+	$bytes = _unpack_head($byte);
+	@$h{qw(IDR ID layer protection_bit
+		bitrate_index sampling_freq padding_bit private_bit
+		mode mode_extension copyright original
+		emphasis version_index bytes)} = (
+		($bytes>>19)&3, ($bytes>>19)&1, ($bytes>>17)&3, ($bytes>>16)&1,
+		($bytes>>12)&15, ($bytes>>10)&3, ($bytes>>9)&1, ($bytes>>8)&1,
+		($bytes>>6)&3, ($bytes>>4)&3, ($bytes>>3)&1, ($bytes>>2)&1,
+		$bytes&3, ($bytes>>19)&3, $bytes
+	);
+
+	$h->{bitrate} = $t_bitrate[$h->{ID}][3 - $h->{layer}][$h->{bitrate_index}];
+	$h->{fs} = $t_sampling_freq[$h->{IDR}][$h->{sampling_freq}];
+
+	return $h;
+}
+
+sub _is_mp3 {
+	my $h = $_[0] or return undef;
+	return ! (	# all below must be false
+		 $h->{bitrate_index} == 0
+			||
+		 $h->{version_index} == 1
+			||
+		($h->{bytes} & 0xFFE00000) != 0xFFE00000
+			||
+		!$h->{fs}
+			||
+		!$h->{bitrate}
+			||
+		 $h->{bitrate_index} == 15
+			||
+		!$h->{layer}
+			||
+		 $h->{sampling_freq} == 3
+			||
+		 $h->{emphasis} == 2
+			||
+		!$h->{bitrate_index}
+			||
+		($h->{bytes} & 0xFFFF0000) == 0xFFFE0000
+			||
+		($h->{ID} == 1 && $h->{layer} == 3 && $h->{protection_bit} == 1)
+			||
+		($h->{mode_extension} != 0 && $h->{mode} != 1)
+	);
+}
+
+sub _get_vbr {
+	my($fh, $h, $roff) = @_;
+	my($off, $bytes, @bytes, $myseek, %vbr);
+
+	$off = $$roff;
+	@_ = ();	# closure confused if we don't do this
+
+	$myseek = sub {
+		my $n = $_[0] || 4;
+		seek $fh, $off, 0;
+		read $fh, $bytes, $n;
+		$off += $n;
+	};
+
+	$off += 4;
+
+	if ($h->{ID}) {	# MPEG1
+		$off += $h->{mode} == 3 ? 17 : 32;
+	} else {	# MPEG2
+		$off += $h->{mode} == 3 ? 9 : 17;
+	}
+
+	&$myseek;
+	return unless $bytes eq 'Xing';
+
+	&$myseek;
+	$vbr{flags} = _unpack_head($bytes);
+
+	if ($vbr{flags} & 1) {
+		&$myseek;
+		$vbr{frames} = _unpack_head($bytes);
+	}
+
+	if ($vbr{flags} & 2) {
+		&$myseek;
+		$vbr{bytes} = _unpack_head($bytes);
+	}
+
+	if ($vbr{flags} & 4) {
+		$myseek->(100);
+# Not used right now ...
+#		$vbr{toc} = _unpack_head($bytes);
+	}
+
+	if ($vbr{flags} & 8) { # (quality ind., 0=best 100=worst)
+		&$myseek;
+		$vbr{scale} = _unpack_head($bytes);
+	} else {
+		$vbr{scale} = -1;
+	}
+
+	$$roff = $off;
+	return \%vbr;
+}
+
+sub _get_v2head {
+	my $fh = $_[0] or return;
+	my($h, $bytes, @bytes);
+
+	# check first three bytes for 'ID3'
+	seek $fh, 0, 0;
+	read $fh, $bytes, 3;
+	return unless $bytes eq 'ID3';
+
+	# get version
+	read $fh, $bytes, 2;
+	$h->{version} = sprintf "ID3v2.%d.%d",
+		@$h{qw[major_version minor_version]} =
+			unpack 'c2', $bytes;
+
+	# get flags
+	read $fh, $bytes, 1;
+	if ($h->{major_version} == 2) {
+		@$h{qw[unsync compression]} =
+			(unpack 'b8', $bytes)[7, 6];
+		$h->{ext_header} = 0;
+		$h->{experimental} = 0;
+	} else {
+		@$h{qw[unsync ext_header experimental]} =
+			(unpack 'b8', $bytes)[7, 6, 5];
+	}
+
+	# get ID3v2 tag length from bytes 7-10
+	$h->{tag_size} = 10;	# include ID3v2 header size
+	read $fh, $bytes, 4;
+	@bytes = reverse unpack 'C4', $bytes;
+	foreach my $i (0 .. 3) {
+		# whoaaaaaa nellllllyyyyyy!
+		$h->{tag_size} += $bytes[$i] * 128 ** $i;
+	}
+
+	# get extended header size
+	$h->{ext_header_size} = 0;
+	if ($h->{ext_header}) {
+		$h->{ext_header_size} += 10;
+		read $fh, $bytes, 4;
+		@bytes = reverse unpack 'C4', $bytes;
+		for my $i (0..3) {
+			$h->{ext_header_size} += $bytes[$i] * 256 ** $i;
+		}
+	}
+
+	return $h;
+}
+
+sub _unpack_head {
+	unpack('l', pack('L', unpack('N', $_[0])));
+}
+
+sub _close {
+	my($file, $fh) = @_;
+	unless (ref $file) { # filehandle not passed
+		close $fh or carp "Problem closing '$file': $!";
+	}
+}
+
+BEGIN {
+	@mp3_genres = (
+		'Blues',
+		'Classic Rock',
+		'Country',
+		'Dance',
+		'Disco',
+		'Funk',
+		'Grunge',
+		'Hip-Hop',
+		'Jazz',
+		'Metal',
+		'New Age',
+		'Oldies',
+		'Other',
+		'Pop',
+		'R&B',
+		'Rap',
+		'Reggae',
+		'Rock',
+		'Techno',
+		'Industrial',
+		'Alternative',
+		'Ska',
+		'Death Metal',
+		'Pranks',
+		'Soundtrack',
+		'Euro-Techno',
+		'Ambient',
+		'Trip-Hop',
+		'Vocal',
+		'Jazz+Funk',
+		'Fusion',
+		'Trance',
+		'Classical',
+		'Instrumental',
+		'Acid',
+		'House',
+		'Game',
+		'Sound Clip',
+		'Gospel',
+		'Noise',
+		'AlternRock',
+		'Bass',
+		'Soul',
+		'Punk',
+		'Space',
+		'Meditative',
+		'Instrumental Pop',
+		'Instrumental Rock',
+		'Ethnic',
+		'Gothic',
+		'Darkwave',
+		'Techno-Industrial',
+		'Electronic',
+		'Pop-Folk',
+		'Eurodance',
+		'Dream',
+		'Southern Rock',
+		'Comedy',
+		'Cult',
+		'Gangsta',
+		'Top 40',
+		'Christian Rap',
+		'Pop/Funk',
+		'Jungle',
+		'Native American',
+		'Cabaret',
+		'New Wave',
+		'Psychadelic',
+		'Rave',
+		'Showtunes',
+		'Trailer',
+		'Lo-Fi',
+		'Tribal',
+		'Acid Punk',
+		'Acid Jazz',
+		'Polka',
+		'Retro',
+		'Musical',
+		'Rock & Roll',
+		'Hard Rock',
+	);
+
+	@winamp_genres = (
+		@mp3_genres,
+		'Folk',
+		'Folk-Rock',
+		'National Folk',
+		'Swing',
+		'Fast Fusion',
+		'Bebob',
+		'Latin',
+		'Revival',
+		'Celtic',
+		'Bluegrass',
+		'Avantgarde',
+		'Gothic Rock',
+		'Progressive Rock',
+		'Psychedelic Rock',
+		'Symphonic Rock',
+		'Slow Rock',
+		'Big Band',
+		'Chorus',
+		'Easy Listening',
+		'Acoustic',
+		'Humour',
+		'Speech',
+		'Chanson',
+		'Opera',
+		'Chamber Music',
+		'Sonata',
+		'Symphony',
+		'Booty Bass',
+		'Primus',
+		'Porn Groove',
+		'Satire',
+		'Slow Jam',
+		'Club',
+		'Tango',
+		'Samba',
+		'Folklore',
+		'Ballad',
+		'Power Ballad',
+		'Rhythmic Soul',
+		'Freestyle',
+		'Duet',
+		'Punk Rock',
+		'Drum Solo',
+		'Acapella',
+		'Euro-House',
+		'Dance Hall',
+		'Goa',
+		'Drum & Bass',
+		'Club-House',
+		'Hardcore',
+		'Terror',
+		'Indie',
+		'BritPop',
+		'Negerpunk',
+		'Polsk Punk',
+		'Beat',
+		'Christian Gangsta Rap',
+		'Heavy Metal',
+		'Black Metal',
+		'Crossover',
+		'Contemporary Christian',
+		'Christian Rock',
+		'Merengue',
+		'Salsa',
+		'Thrash Metal',
+		'Anime',
+		'JPop',
+		'Synthpop',
+	);
+
+	@t_bitrate = ([
+		[0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256],
+		[0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160],
+		[0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160]
+	],[
+		[0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448],
+		[0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384],
+		[0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320]
+	]);
+
+	@t_sampling_freq = (
+		[11025, 12000,  8000],
+		[undef, undef, undef],	# reserved
+		[22050, 24000, 16000],
+		[44100, 48000, 32000]
+	);
+
+	@frequency_tbl = map { $_ ? eval "${_}e-3" : 0 }
+		map { @$_ } @t_sampling_freq;
+
+	@mp3_info_fields = qw(
+		VERSION
+		LAYER
+		STEREO
+		VBR
+		BITRATE
+		FREQUENCY
+		SIZE
+		SECS
+		MM
+		SS
+		MS
+		TIME
+		COPYRIGHT
+		PADDING
+		MODE
+		FRAMES
+		FRAME_LENGTH
+		VBR_SCALE
+	);
+
+	%v1_tag_fields =
+		(TITLE => 30, ARTIST => 30, ALBUM => 30, COMMENT => 30, YEAR => 4);
+
+	@v1_tag_names = qw(TITLE ARTIST ALBUM YEAR COMMENT TRACKNUM GENRE);
+
+	%v2_to_v1_names = (
+		# v2.2 tags
+		'TT2' => 'TITLE',
+		'TP1' => 'ARTIST',
+		'TAL' => 'ALBUM',
+		'TYE' => 'YEAR',
+		'COM' => 'COMMENT',
+		'TRK' => 'TRACKNUM',
+		'TCO' => 'GENRE', # not clean mapping, but ...
+		# v2.3 tags
+		'TIT2' => 'TITLE',
+		'TPE1' => 'ARTIST',
+		'TALB' => 'ALBUM',
+		'TYER' => 'YEAR',
+		'COMM' => 'COMMENT',
+		'TRCK' => 'TRACKNUM',
+		'TCON' => 'GENRE',
+	);
+
+	%v2_tag_names = (
+		# v2.2 tags
+		'BUF' => 'Recommended buffer size',
+		'CNT' => 'Play counter',
+		'COM' => 'Comments',
+		'CRA' => 'Audio encryption',
+		'CRM' => 'Encrypted meta frame',
+		'ETC' => 'Event timing codes',
+		'EQU' => 'Equalization',
+		'GEO' => 'General encapsulated object',
+		'IPL' => 'Involved people list',
+		'LNK' => 'Linked information',
+		'MCI' => 'Music CD Identifier',
+		'MLL' => 'MPEG location lookup table',
+		'PIC' => 'Attached picture',
+		'POP' => 'Popularimeter',
+		'REV' => 'Reverb',
+		'RVA' => 'Relative volume adjustment',
+		'SLT' => 'Synchronized lyric/text',
+		'STC' => 'Synced tempo codes',
+		'TAL' => 'Album/Movie/Show title',
+		'TBP' => 'BPM (Beats Per Minute)',
+		'TCM' => 'Composer',
+		'TCO' => 'Content type',
+		'TCR' => 'Copyright message',
+		'TDA' => 'Date',
+		'TDY' => 'Playlist delay',
+		'TEN' => 'Encoded by',
+		'TFT' => 'File type',
+		'TIM' => 'Time',
+		'TKE' => 'Initial key',
+		'TLA' => 'Language(s)',
+		'TLE' => 'Length',
+		'TMT' => 'Media type',
+		'TOA' => 'Original artist(s)/performer(s)',
+		'TOF' => 'Original filename',
+		'TOL' => 'Original Lyricist(s)/text writer(s)',
+		'TOR' => 'Original release year',
+		'TOT' => 'Original album/Movie/Show title',
+		'TP1' => 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group',
+		'TP2' => 'Band/Orchestra/Accompaniment',
+		'TP3' => 'Conductor/Performer refinement',
+		'TP4' => 'Interpreted, remixed, or otherwise modified by',
+		'TPA' => 'Part of a set',
+		'TPB' => 'Publisher',
+		'TRC' => 'ISRC (International Standard Recording Code)',
+		'TRD' => 'Recording dates',
+		'TRK' => 'Track number/Position in set',
+		'TSI' => 'Size',
+		'TSS' => 'Software/hardware and settings used for encoding',
+		'TT1' => 'Content group description',
+		'TT2' => 'Title/Songname/Content description',
+		'TT3' => 'Subtitle/Description refinement',
+		'TXT' => 'Lyricist/text writer',
+		'TXX' => 'User defined text information frame',
+		'TYE' => 'Year',
+		'UFI' => 'Unique file identifier',
+		'ULT' => 'Unsychronized lyric/text transcription',
+		'WAF' => 'Official audio file webpage',
+		'WAR' => 'Official artist/performer webpage',
+		'WAS' => 'Official audio source webpage',
+		'WCM' => 'Commercial information',
+		'WCP' => 'Copyright/Legal information',
+		'WPB' => 'Publishers official webpage',
+		'WXX' => 'User defined URL link frame',
+
+		# v2.3 tags
+		'AENC' => 'Audio encryption',
+		'APIC' => 'Attached picture',
+		'COMM' => 'Comments',
+		'COMR' => 'Commercial frame',
+		'ENCR' => 'Encryption method registration',
+		'EQUA' => 'Equalization',
+		'ETCO' => 'Event timing codes',
+		'GEOB' => 'General encapsulated object',
+		'GRID' => 'Group identification registration',
+		'IPLS' => 'Involved people list',
+		'LINK' => 'Linked information',
+		'MCDI' => 'Music CD identifier',
+		'MLLT' => 'MPEG location lookup table',
+		'OWNE' => 'Ownership frame',
+		'PCNT' => 'Play counter',
+		'POPM' => 'Popularimeter',
+		'POSS' => 'Position synchronisation frame',
+		'PRIV' => 'Private frame',
+		'RBUF' => 'Recommended buffer size',
+		'RVAD' => 'Relative volume adjustment',
+		'RVRB' => 'Reverb',
+		'SYLT' => 'Synchronized lyric/text',
+		'SYTC' => 'Synchronized tempo codes',
+		'TALB' => 'Album/Movie/Show title',
+		'TBPM' => 'BPM (beats per minute)',
+		'TCOM' => 'Composer',
+		'TCON' => 'Content type',
+		'TCOP' => 'Copyright message',
+		'TDAT' => 'Date',
+		'TDLY' => 'Playlist delay',
+		'TENC' => 'Encoded by',
+		'TEXT' => 'Lyricist/Text writer',
+		'TFLT' => 'File type',
+		'TIME' => 'Time',
+		'TIT1' => 'Content group description',
+		'TIT2' => 'Title/songname/content description',
+		'TIT3' => 'Subtitle/Description refinement',
+		'TKEY' => 'Initial key',
+		'TLAN' => 'Language(s)',
+		'TLEN' => 'Length',
+		'TMED' => 'Media type',
+		'TOAL' => 'Original album/movie/show title',
+		'TOFN' => 'Original filename',
+		'TOLY' => 'Original lyricist(s)/text writer(s)',
+		'TOPE' => 'Original artist(s)/performer(s)',
+		'TORY' => 'Original release year',
+		'TOWN' => 'File owner/licensee',
+		'TPE1' => 'Lead performer(s)/Soloist(s)',
+		'TPE2' => 'Band/orchestra/accompaniment',
+		'TPE3' => 'Conductor/performer refinement',
+		'TPE4' => 'Interpreted, remixed, or otherwise modified by',
+		'TPOS' => 'Part of a set',
+		'TPUB' => 'Publisher',
+		'TRCK' => 'Track number/Position in set',
+		'TRDA' => 'Recording dates',
+		'TRSN' => 'Internet radio station name',
+		'TRSO' => 'Internet radio station owner',
+		'TSIZ' => 'Size',
+		'TSRC' => 'ISRC (international standard recording code)',
+		'TSSE' => 'Software/Hardware and settings used for encoding',
+		'TXXX' => 'User defined text information frame',
+		'TYER' => 'Year',
+		'UFID' => 'Unique file identifier',
+		'USER' => 'Terms of use',
+		'USLT' => 'Unsychronized lyric/text transcription',
+		'WCOM' => 'Commercial information',
+		'WCOP' => 'Copyright/Legal information',
+		'WOAF' => 'Official audio file webpage',
+		'WOAR' => 'Official artist/performer webpage',
+		'WOAS' => 'Official audio source webpage',
+		'WORS' => 'Official internet radio station homepage',
+		'WPAY' => 'Payment',
+		'WPUB' => 'Publishers official webpage',
+		'WXXX' => 'User defined URL link frame',
+
+		# v2.4 additional tags
+		# note that we don't restrict tags from 2.3 or 2.4,
+		'ASPI' => 'Audio seek point index',
+		'EQU2' => 'Equalisation (2)',
+		'RVA2' => 'Relative volume adjustment (2)',
+		'SEEK' => 'Seek frame',
+		'SIGN' => 'Signature frame',
+		'TDEN' => 'Encoding time',
+		'TDOR' => 'Original release time',
+		'TDRC' => 'Recording time',
+		'TDRL' => 'Release time',
+		'TDTG' => 'Tagging time',
+		'TIPL' => 'Involved people list',
+		'TMCL' => 'Musician credits list',
+		'TMOO' => 'Mood',
+		'TPRO' => 'Produced notice',
+		'TSOA' => 'Album sort order',
+		'TSOP' => 'Performer sort order',
+		'TSOT' => 'Title sort order',
+		'TSST' => 'Set subtitle',
+
+		# grrrrrrr
+		'COM ' => 'Broken iTunes comments',
+	);
+}
+
+1;
+
+__END__
+
+=pod
+
+=back
+
+=head1 TROUBLESHOOTING
+
+If you find a bug, please send me a patch (see the project page in L<"SEE ALSO">).
+If you cannot figure out why it does not work for you, please put the MP3 file in
+a place where I can get it (preferably via FTP, or HTTP, or .Mac iDisk) and send me
+mail regarding where I can get the file, with a detailed description of the problem.
+
+If I download the file, after debugging the problem I will not keep the MP3 file
+if it is not legal for me to have it.  Just let me know if it is legal for me to
+keep it or not.
+
+
+=head1 TODO
+
+=over 4
+
+=item ID3v2 Support
+
+Still need to do more for reading tags, such as using Compress::Zlib to decompress
+compressed tags.  But until I see this in use more, I won't bother.  If something
+does not work properly with reading, follow the instructions above for
+troubleshooting.
+
+ID3v2 I<writing> is coming soon.
+
+=item Get data from scalar
+
+Instead of passing a file spec or filehandle, pass the
+data itself.  Would take some work, converting the seeks, etc.
+
+=item Padding bit ?
+
+Do something with padding bit.
+
+=item Test suite
+
+Test suite could use a bit of an overhaul and update.  Patches very welcome.
+
+=over 4
+
+=item *
+
+Revamp getset.t.  Test all the various get_mp3tag args.
+
+=item *
+
+Test Unicode.
+
+=item *
+
+Test OOP API.
+
+=item *
+
+Test error handling, check more for missing files, bad MP3s, etc.
+
+=back
+
+=item Other VBR
+
+Right now, only Xing VBR is supported.
+
+=back
+
+
+=head1 THANKS
+
+Edward Allen E<lt>allenej@c51844-a.spokn1.wa.home.comE<gt>,
+Vittorio Bertola E<lt>v.bertola@vitaminic.comE<gt>,
+Michael Blakeley E<lt>mike@blakeley.comE<gt>,
+Per Bolmstedt E<lt>tomten@kol14.comE<gt>,
+Tony Bowden E<lt>tony@tmtm.comE<gt>,
+Tom Brown E<lt>thecap@usa.netE<gt>,
+Sergio Camarena E<lt>scamarena@users.sourceforge.netE<gt>,
+Chris Dawson E<lt>cdawson@webiphany.comE<gt>,
+Luke Drumm E<lt>lukedrumm@mypad.comE<gt>,
+Kyle Farrell E<lt>kyle@cantametrix.comE<gt>,
+Jeffrey Friedl E<lt>jfriedl@yahoo.comE<gt>,
+brian d foy E<lt>comdog@panix.comE<gt>,
+Ben Gertzfield E<lt>che@debian.orgE<gt>,
+Brian Goodwin E<lt>brian@fuddmain.comE<gt>,
+Todd Hanneken E<lt>thanneken@hds.harvard.eduE<gt>,
+Todd Harris E<lt>harris@cshl.orgE<gt>,
+Woodrow Hill E<lt>asim@mindspring.comE<gt>,
+Kee Hinckley E<lt>nazgul@somewhere.comE<gt>,
+Roman Hodek E<lt>Roman.Hodek@informatik.uni-erlangen.deE<gt>,
+Peter Kovacs E<lt>kovacsp@egr.uri.eduE<gt>,
+Johann Lindvall,
+Peter Marschall E<lt>peter.marschall@mayn.deE<gt>,
+Trond Michelsen E<lt>mike@crusaders.noE<gt>,
+Dave O'Neill E<lt>dave@nexus.carleton.caE<gt>,
+Christoph Oberauer E<lt>christoph.oberauer@sbg.ac.atE<gt>,
+Jake Palmer E<lt>jake.palmer@db.comE<gt>,
+Andrew Phillips E<lt>asp@wasteland.orgE<gt>,
+David Reuteler E<lt>reuteler@visi.comE<gt>,
+John Ruttenberg E<lt>rutt@chezrutt.comE<gt>,
+Matthew Sachs E<lt>matthewg@zevils.comE<gt>,
+E<lt>scfc_de@users.sf.netE<gt>,
+Hermann Schwaerzler E<lt>Hermann.Schwaerzler@uibk.ac.atE<gt>,
+Chris Sidi E<lt>sidi@angband.orgE<gt>,
+Roland Steinbach E<lt>roland@support-system.comE<gt>,
+Stuart E<lt>schneis@users.sourceforge.netE<gt>,
+Jeffery Sumler E<lt>jsumler@mediaone.netE<gt>,
+Predrag Supurovic E<lt>mpgtools@dv.co.yuE<gt>,
+Bogdan Surdu E<lt>tim@go.roE<gt>,
+E<lt>tim@tim-landscheidt.deE<gt>,
+Pass F. B. Travis E<lt>pftravis@bellsouth.netE<gt>,
+Tobias Wagener E<lt>tobias@wagener.nuE<gt>,
+Ronan Waide E<lt>waider@stepstone.ieE<gt>,
+Andy Waite E<lt>andy@mailroute.comE<gt>,
+Ken Williams E<lt>ken@forum.swarthmore.eduE<gt>,
+Meng Weng Wong E<lt>mengwong@pobox.comE<gt>.
+
+
+=head1 AUTHOR AND COPYRIGHT
+
+Chris Nandor E<lt>pudge@pobox.comE<gt>, http://pudge.net/
+
+Copyright (c) 1998-2003 Chris Nandor.  All rights reserved.  This program is
+free software; you can redistribute it and/or modify it under the terms
+of the Artistic License, distributed with Perl.
+
+
+=head1 SEE ALSO
+
+=over 4
+
+=item MP3::Info Project Page
+
+	http://projects.pudge.net/
+
+=item mp3tools
+
+	http://www.zevils.com/linux/mp3tools/
+
+=item mpgtools
+
+	http://www.dv.co.yu/mpgscript/mpgtools.htm
+	http://www.dv.co.yu/mpgscript/mpeghdr.htm
+
+=item mp3tool
+
+	http://www.dtek.chalmers.se/~d2linjo/mp3/mp3tool.html
+
+=item ID3v2
+
+	http://www.id3.org/
+
+=item Xing Variable Bitrate
+
+	http://www.xingtech.com/support/partner_developer/mp3/vbr_sdk/
+
+=item MP3Ext
+
+	http://rupert.informatik.uni-stuttgart.de/~mutschml/MP3ext/
+
+=item Xmms
+
+	http://www.xmms.org/
+
+
+=back
+
+=head1 VERSION
+
+v1.02, Sunday, March 2, 2003
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/Mail/Sendmail.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/Mail/Sendmail.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/Mail/Sendmail.pm	(revision 10506)
@@ -0,0 +1,753 @@
+package Mail::Sendmail;
+# Mail::Sendmail by Milivoj Ivkovic <mi@alma.ch>
+# see embedded POD documentation after __END__
+# or http://alma.ch/perl/mail.htm
+
+=head1 NAME
+
+Mail::Sendmail v. 0.78 - Simple platform independent mailer
+
+=cut
+
+$VERSION = '0.78';
+
+# *************** Configuration you may want to change *******************
+# You probably want to set your SMTP server here (unless you specify it in
+# every script), and leave the rest as is. See pod documentation for details
+
+%mailcfg = (
+    # List of SMTP servers:
+    'smtp'    => [],
+
+    'from'    => '', # default sender e-mail, used when no From header in mail
+
+    'mime'    => 1, # use MIME encoding by default
+
+    'retries' => 1, # number of retries on smtp connect failure
+    'delay'   => 1, # delay in seconds between retries
+
+    'tz'      => '', # only to override automatic detection
+    'port'    => 25, # change it if you always use a non-standard port
+    'debug'   => 0 # prints stuff to STDERR
+);
+
+# *******************************************************************
+
+require Exporter;
+use strict;
+use vars qw(
+            $VERSION
+            @ISA
+            @EXPORT
+            @EXPORT_OK
+            %mailcfg
+            $default_smtp_server
+            $default_smtp_port
+            $default_sender
+            $TZ
+            $use_MIME
+            $address_rx
+            $debug
+            $log
+            $error
+            $retry_delay
+            $connect_retries
+           );
+
+use Socket;
+use Time::Local; # for automatic time zone detection
+
+# use MIME::QuotedPrint if available and configured in %mailcfg
+eval("use MIME::QuotedPrint");
+$mailcfg{'mime'} &&= (!$@);
+
+@ISA        = qw(Exporter);
+@EXPORT     = qw(&sendmail);
+@EXPORT_OK  = qw(
+                 %mailcfg
+                 time_to_date
+                 $default_smtp_server
+                 $default_smtp_port
+                 $default_sender
+                 $TZ
+                 $address_rx
+                 $debug
+                 $log
+                 $error
+                );
+
+# regex for e-mail addresses where full=$1, user=$2, domain=$3
+# see pod documentation about this regex
+
+my $word_rx = '[\x21\x23-\x27\x2A-\x2B\x2D\w\x3D\x3F]+';
+my $user_rx = $word_rx         # valid chars
+             .'(?:\.' . $word_rx . ')*' # possibly more words preceded by a dot
+             ;
+my $dom_rx = '\w[-\w]*(?:\.\w[-\w]*)*'; # less valid chars in domain names
+my $ip_rx = '\[\d{1,3}(?:\.\d{1,3}){3}\]';
+
+$address_rx = '((' . $user_rx . ')\@(' . $dom_rx . '|' . $ip_rx . '))';
+; # v. 0.6
+
+sub time_to_date {
+    # convert a time() value to a date-time string according to RFC 822
+
+    my $time = $_[0] || time(); # default to now if no argument
+
+    my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+    my @wdays  = qw(Sun Mon Tue Wed Thu Fri Sat);
+
+    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)
+        = localtime($time);
+
+    $TZ ||= $mailcfg{'tz'};
+
+    if ( $TZ eq "" ) {
+        # offset in hours
+        my $offset  = sprintf "%.1f", (timegm(localtime) - time) / 3600;
+        my $minutes = sprintf "%02d", ( $offset - int($offset) ) * 60;
+        $TZ  = sprintf("%+03d", int($offset)) . $minutes;
+    }
+    return join(" ",
+                    ($wdays[$wday] . ','),
+                     $mday,
+                     $months[$mon],
+                     $year+1900,
+                     sprintf("%02d", $hour) . ":" . sprintf("%02d", $min),
+                     $TZ
+               );
+} # end sub time_to_date
+
+sub sendmail {
+    # original sendmail 1.21 by Christian Mallwitz.
+    # Modified and 'modulized' by mi@alma.ch
+
+    $error = '';
+    $log = "Mail::Sendmail v. $VERSION - "    . scalar(localtime()) . "\n";
+
+    local $_;
+    local $/ = "\015\012";
+
+    my (%mail, $k,
+        $smtp, $server, $port, $connected, $localhost,
+        $message, $fromaddr, $recip, @recipients, $to, $header,
+       );
+
+    sub fail {
+        # things to do before returning a sendmail failure
+        print STDERR @_ if $^W;
+        $error .= join(" ", @_) . "\n";
+        close S;
+        return 0;
+    }
+
+    # all config keys to lowercase, to prevent typo errors
+    foreach $k (keys %mailcfg) {
+        if ($k =~ /[A-Z]/) {
+            $mailcfg{lc($k)} = $mailcfg{$k};
+        }
+    }
+
+    # redo hash, arranging keys case etc...
+    while (@_) {
+        # arrange keys case
+        $k = ucfirst lc(shift @_);
+
+        if (!$k and $^W) {
+            warn "Received false mail hash key: \'$k\'. Did you forget to put it in quotes?\n";
+        }
+
+        $k =~ s/\s*:\s*$//o; # kill colon (and possible spaces) at end, we add it later.
+        $mail{$k} = shift @_;
+    }
+
+    $smtp = $mail{'Smtp'} || $mail{'Server'} || $default_smtp_server;
+#    unshift @{$mailcfg{'smtp'}}, $smtp if ($smtp and $mailcfg{'smtp'}->[0] ne $smtp);
+    unshift @{$mailcfg{'smtp'}}, $smtp if $smtp; # Change here to avoid undefined value
+                                                 # with our empty mailcfg{'smtp'} - Stefan
+
+    # delete non-header keys, so we don't send them later as mail headers
+    # I like this syntax, but it doesn't seem to work with AS port 5.003_07:
+    # delete @mail{'Smtp', 'Server'};
+    # so instead:
+    delete $mail{'Smtp'}; delete $mail{'Server'};
+
+    $mailcfg{'port'} = $mail{'Port'} || $default_smtp_port || $mailcfg{'port'} || 25;
+    delete $mail{'Port'};
+
+    # for backward compatibility only
+    $mailcfg{'retries'} = $connect_retries if defined($connect_retries);
+    $mailcfg{'delay'} = $retry_delay if defined($retry_delay);
+
+    {    # don't warn for undefined values below
+        local $^W = 0;
+        $message = join("", $mail{'Message'}, $mail{'Body'}, $mail{'Text'});
+    }
+
+    # delete @mail{'Message', 'Body', 'Text'};
+    delete $mail{'Message'}; delete $mail{'Body'}; delete $mail{'Text'};
+
+    # Extract 'From:' e-mail address
+
+    $fromaddr = $mail{'From'} || $default_sender || $mailcfg{'from'};
+    unless ($fromaddr =~ /$address_rx/) {
+        return fail("Bad or missing From address: \'$fromaddr\'");
+    }
+    $fromaddr = $1;
+
+    # add Date header if needed
+    $mail{Date} ||= time_to_date() ;
+    $log .= "Date: $mail{Date}\n";
+
+    # cleanup message, and encode if needed
+    $message =~ s/^\./\.\./gom;     # handle . as first character
+    $message =~ s/\r\n/\n/go;     # normalize line endings, step 1 of 2 (next step after MIME encoding)
+
+    $mail{'Mime-version'} ||= '1.0';
+    $mail{'Content-type'} ||= 'text/plain; charset="iso-8859-1"';
+
+    unless ( $mail{'Content-transfer-encoding'}
+          || $mail{'Content-type'} =~ /multipart/io )
+    {
+        if ($mailcfg{'mime'}) {
+            $mail{'Content-transfer-encoding'} = 'quoted-printable';
+            $message = encode_qp($message);
+        }
+        else {
+            $mail{'Content-transfer-encoding'} = '8bit';
+            if ($message =~ /[\x80-\xFF]/o) {
+                $error .= "MIME::QuotedPrint not present!\nSending 8bit characters, hoping it will come across OK.\n";
+                warn "MIME::QuotedPrint not present!\n",
+                     "Sending 8bit characters, hoping it will come across OK.\n"
+                     if $^W;
+            }
+        }
+    }
+
+    $message =~ s/\n/\015\012/go; # normalize line endings, step 2.
+
+    # Get recipients
+    {    # don't warn for undefined values below
+        local $^W = 0;
+        $recip = join(", ", $mail{To}, $mail{Cc}, $mail{Bcc});
+    }
+
+    delete $mail{'Bcc'};
+
+    @recipients = ();
+    while ($recip =~ /$address_rx/go) {
+        push @recipients, $1;
+    }
+    unless (@recipients) {
+        return fail("No recipient!")
+    }
+
+    # get local hostname for polite HELO
+    $localhost = (gethostbyname('localhost'))[0] || 'localhost';
+
+    foreach $server ( @{$mailcfg{'smtp'}} ) {
+        # open socket needs to be inside this foreach loop on Linux,
+        # otherwise all servers fail if 1st one fails !??! why?
+        unless ( socket S, AF_INET, SOCK_STREAM, (getprotobyname 'tcp')[2] ) {
+            return fail("socket failed ($!)")
+        }
+
+        print "- trying $server\n" if $mailcfg{'debug'} > 1;
+
+        $server =~ s/\s+//go; # remove spaces just in case of a typo
+        # extract port if server name like "mail.domain.com:2525"
+        ($server =~ s/:(.+)$//o) ? $port = $1    : $port = $mailcfg{'port'};
+        $smtp = $server; # save $server for use outside foreach loop
+
+        my $smtpaddr = inet_aton $server;
+        unless ($smtpaddr) {
+            $error .= "$server not found\n";
+            next; # next server
+        }
+
+        my $retried = 0; # reset retries for each server
+        while ( ( not $connected = connect S, pack_sockaddr_in($port, $smtpaddr) )
+            and ( $retried < $mailcfg{'retries'} )
+              ) {
+            $retried++;
+            $error .= "connect to $server failed ($!)\n";
+            print "- connect to $server failed ($!)\n" if $mailcfg{'debug'} > 1;
+            print "retrying in $mailcfg{'delay'} seconds...\n";
+            sleep $mailcfg{'delay'};
+        }
+
+        if ( $connected ) {
+            print "- connected to $server\n" if $mailcfg{'debug'} > 3;
+            last;
+        }
+        else {
+            $error .= "connect to $server failed\n";
+            print "- connect to $server failed, next server...\n" if $mailcfg{'debug'} > 1;
+            next; # next server
+        }
+    }
+
+    unless ( $connected ) {
+        return fail("connect to $smtp failed ($!) no (more) retries!")
+    };
+
+    {
+        local $^W = 0; # don't warn on undefined variables
+        # Add info to log variable
+        $log .= "Server: $smtp Port: $port\n"
+              . "From: $fromaddr\n"
+              . "Subject: $mail{Subject}\n"
+              . "To: ";
+    }
+
+    my($oldfh) = select(S); $| = 1; select($oldfh);
+
+    chomp($_ = <S>);
+    if (/^[45]/ or !$_) {
+        return fail("Connection error from $smtp on port $port ($_)")
+    }
+
+    print S "HELO $localhost\015\012";
+    chomp($_ = <S>);
+    if (/^[45]/ or !$_) {
+        return fail("HELO error ($_)")
+    }
+    
+    print S "mail from: <$fromaddr>\015\012";
+    chomp($_ = <S>);
+    if (/^[45]/ or !$_) {
+        return fail("mail From: error ($_)")
+    }
+
+    foreach $to (@recipients) {
+        if ($debug) { print STDERR "sending to: <$to>\n"; }
+        print S "rcpt to: <$to>\015\012";
+        chomp($_ = <S>);
+        if (/^[45]/ or !$_) {
+            $log .= "!Failed: $to\n    ";
+            return fail("Error sending to <$to> ($_)\n");
+        }
+        else {
+            $log .= "$to\n    ";
+        }
+    }
+
+    # start data part
+    print S "data\015\012";
+    chomp($_ = <S>);
+    if (/^[45]/ or !$_) {
+           return fail("Cannot send data ($_)");
+    }
+
+    # print headers
+    foreach $header (keys %mail) {
+        $mail{$header} =~ s/\s+$//o; # kill possible trailing garbage
+        print S "$header: ", $mail{$header}, "\015\012";
+    };
+
+    #- test diconnecting from network here, to see what happens
+    #- print STDERR "DISCONNECT NOW!\n";
+    #- sleep 4;
+    #- print STDERR "trying to continue, expecting an error... \n";
+
+    # send message body
+    print S "\015\012",
+            $message,
+            "\015\012.\015\012";
+
+    chomp($_ = <S>);
+    if (/^[45]/ or !$_) {
+           return fail("message transmission failed ($_)");
+    }
+
+    # finish
+    print S "quit\015\012";
+    $_ = <S>;
+    close S;
+
+    return 1;
+} # end sub sendmail
+
+1;
+__END__
+
+=head1 SYNOPSIS
+
+  use Mail::Sendmail;
+
+  %mail = ( To      => 'you@there.com',
+            From    => 'me@here.com',
+            Message => "This is a very short message"
+           );
+
+  sendmail(%mail) or die $Mail::Sendmail::error;
+
+  print "OK. Log says:\n", $Mail::Sendmail::log;
+
+=head1 DESCRIPTION
+
+Simple platform independent e-mail from your perl script. Only requires
+Perl 5 and a network connection.
+
+After struggling for some time with various command-line mailing programs
+which never did exactly what I wanted, I put together this Perl only
+solution.
+
+Mail::Sendmail contains mainly &sendmail, which takes a hash with the
+message to send and sends it. It is intended to be very easy to setup and
+use.
+
+=head1 INSTALLATION
+
+=over 4
+
+=item Best
+
+perl -MCPAN -e "install Mail::Sendmail"
+
+=item Traditional
+
+    perl Makefile.PL
+    make
+    make test
+    make install
+
+=item Manual
+
+Copy Sendmail.pm to Mail/ in your Perl lib directory.
+
+    (eg. c:\Perl\lib\Mail\, c:\Perl\site\lib\Mail\,
+     /usr/lib/perl5/site_perl/Mail/, ... or whatever it
+     is on your system)
+
+=item ActivePerl's PPM
+
+ppm install --location=http://alma.ch/perl/ppm Mail-Sendmail
+
+But this way you don't get a chance to have a look at other files (Changes, 
+Todo, test.pl, ...) and PPM doesn't run the test script (test.pl).
+
+=back
+
+At the top of Sendmail.pm, set your default SMTP server, unless you specify
+it with each message, or want to use the default.
+
+Install MIME::QuotedPrint. This is not required but strongly recommended.
+
+=head1 FEATURES
+
+Automatic time zone detection, Date: header, MIME quoted-printable encoding 
+(if MIME::QuotedPrint installed), all of which can be overridden.
+
+Internal Bcc: and Cc: support (even on broken servers)
+
+Allows real names in From: and To: fields
+
+Doesn't send unwanted headers, and allows you to send any header(s) you
+want
+
+Configurable retries and use of alternate servers if your mail server is
+down
+
+Good plain text error reporting
+
+=head1 LIMITATIONS
+
+Doesn't work on OpenVMS.
+
+Headers are not encoded, even if they have accented characters.
+
+Since the whole message is in memory (twice!), it's not suitable for 
+sending very big attached files.
+
+The SMTP server has to be set manually in Sendmail.pm or in your script,
+unless you have a mail server on localhost.
+
+=head1 CONFIGURATION
+
+=over 4
+
+=item Default SMTP server(s)
+
+This is probably all you want to configure. It is usually done through
+I<$mailcfg{smtp}>, which you can edit at the top of the Sendmail.pm file.
+This is a reference to a list of SMTP servers. You can also set it from
+your script:
+
+C<unshift @{$Mail::Sendmail::mailcfg{'smtp'}} , 'my.mail.server';>
+
+Alternatively, you can specify the server in the I<%mail> hash you send
+from your script, which will do the same thing:
+
+C<$mail{smtp} = 'my.mail.server';>
+
+A future version will try to set useful defaults for you during the
+Makefile.PL.
+
+=item Other configuration settings
+
+See I<%mailcfg> under L<"DETAILS"> below for other configuration options.
+
+=back
+
+=head1 DETAILS
+
+=head2 sendmail()
+
+sendmail is the only thing exported to your namespace by default
+
+C<sendmail(%mail) || print "Error sending mail: $Mail::Sendmail::error\n";>
+
+It takes a hash containing the full message, with keys for all headers,
+body, and optionally for another non-default SMTP server and/or port.
+
+It returns 1 on success or 0 on error, and rewrites
+C<$Mail::Sendmail::error> and C<$Mail::Sendmail::log>.
+
+Keys are NOT case-sensitive.
+
+The colon after headers is not necessary.
+
+The Body part key can be called 'Body', 'Message' or 'Text'. The SMTP
+server key can be called 'Smtp' or 'Server'.
+
+The following headers are added unless you specify them yourself:
+
+    Mime-version: 1.0
+    Content-type: 'text/plain; charset="iso-8859-1"'
+
+    Content-transfer-encoding: quoted-printable
+    or (if MIME::QuotedPrint not installed)
+    Content-transfer-encoding: 8bit
+
+    Date: [string returned by time_to_date()]
+
+The following are not exported by default, but you can still access them
+with their full name, or request their export on the use line like in:
+C<use Mail::Sendmail qw($address_rx time_to_date);>
+
+=head2 Mail::Sendmail::time_to_date()
+
+convert time ( as from C<time()> ) to an RFC 822 compliant string for the
+Date header. See also L<"%Mail::Sendmail::mailcfg">.
+
+=head2 $Mail::Sendmail::error
+
+When you don't run with the B<-w> flag, the module sends no errors to
+STDERR, but puts anything it has to complain about in here. You should
+probably always check if it says something.
+
+=head2 $Mail::Sendmail::log
+
+A summary that you could write to a log file after each send
+
+=head2 $Mail::Sendmail::address_rx
+
+A handy regex to recognize e-mail addresses.
+
+A correct regex for valid e-mail addresses was written by one of the judges
+in the obfuscated Perl contest... :-) It is quite big. This one is an
+attempt to a reasonable compromise, and should accept all real-world
+internet style addresses. The domain part is required and comments or
+characters that would need to be quoted are not supported.
+
+  Example:
+    $rx = $Mail::Sendmail::address_rx;
+    if (/$rx/) {
+      $address=$1;
+      $user=$2;
+      $domain=$3;
+    }
+
+=head2 %Mail::Sendmail::mailcfg
+
+This hash contains all configuration options. You normally edit it once (if
+ever) in Sendmail.pm and forget about it, but you could also access it from
+your scripts. For readability, I'll assume you have imported it.
+
+The keys are not case-sensitive: they are all converted to lowercase before
+use. Writing C<$mailcfg{Port} = 2525;> is OK: the default $mailcfg{port}
+(25) will be deleted and replaced with your new value of 2525.
+
+=over 4
+
+=item $mailcfg{smtp}
+
+C<$mailcfg{smtp} = [qw(localhost my.other.mail.server)];>
+
+This is a reference to a list of smtp servers, so if your main server is
+down, the module tries the next one. If one of your servers uses a special
+port, add it to the server name with a colon in front, to override the
+default port (like in my.special.server:2525).
+
+Default: localhost. (the previous version also had smtp.site1.csi.com which
+was an open relay, but it isn't anymore)
+
+=item $mailcfg{from}
+
+C<$mailcfg{from} = 'Mailing script me@mydomain.com';>
+
+From address used if you don't supply one in your script. Should not be of
+type 'user@localhost' since that may not be valid on the recipient's
+host.
+
+Default: undefined.
+
+=item $mailcfg{mime}
+
+C<$mailcfg{mime} = 1;>
+
+Set this to 0 if you don't want any automatic MIME encoding. You normally
+don't need this, the module should 'Do the right thing' anyway.
+
+Default: 1;
+
+=item $mailcfg{retries}
+
+C<$mailcfg{retries} = 1;>
+
+How many times should the connection to the same SMTP server be retried in
+case of a failure.
+
+Default: 1;
+
+=item $mailcfg{delay}
+
+C<$mailcfg{delay} = 1;>
+
+Number of seconds to wait between retries. This delay also happens before
+trying the next server in the list, if the retries for the current server
+have been exhausted. For CGI scripts, you want few retries and short delays
+to return with a results page before the http connection times out. For
+unattended scripts, you may want to use many retries and long delays to
+have a good chance of your mail being sent even with temporary failures on
+your network.
+
+Default: 1 (second);
+
+=item $mailcfg{tz}
+
+C<$mailcfg{tz} = '+0800';>
+
+Normally, your time zone is set automatically, from the difference between
+C<time()> and C<gmtime()>. This allows you to override automatic detection
+in cases where your system is confused (such as some Win32 systems in zones
+which do not use daylight savings time: see Microsoft KB article Q148681)
+
+Default: undefined (automatic detection at run-time).
+
+=item $mailcfg{port}
+
+C<$mailcfg{port} = 25;>
+
+Port used when none is specified in the server name.
+
+Default: 25.
+
+=item $mailcfg{debug}
+
+C<$mailcfg{debug} => 0;>
+
+Prints stuff to STDERR. Not used much, and what is printed may change
+without notice. Don't count on it.
+
+Default: 0;
+
+=back
+
+=head2 $Mail::Sendmail::VERSION
+
+The package version number (you can not import this one)
+
+=head2 Configuration variables from previous versions
+
+The following global variables were used in version 0.74 for configuration. 
+They should still work, but will not in a future version (unless you 
+complain loudly). Please use I<%mailcfg> if you need to access the 
+configuration from your scripts.
+
+=over 4
+
+=item $Mail::Sendmail::default_smtp_server
+
+=item $Mail::Sendmail::default_smtp_port
+
+=item $Mail::Sendmail::default_sender
+
+=item $Mail::Sendmail::TZ
+
+=item $Mail::Sendmail::connect_retries
+
+=item $Mail::Sendmail::retry_delay
+
+=item $Mail::Sendmail::use_MIME
+
+This one couldn't really be used in the previous version, so I just dropped it.
+It is replaced by I<$mailcfg{mime}> which works.
+
+=back
+
+=head1 ANOTHER EXAMPLE
+
+  use Mail::Sendmail;
+
+  print "Testing Mail::Sendmail version $Mail::Sendmail::VERSION\n";
+  print "Default server: $Mail::Sendmail::mailcfg{smtp}->[0]\n";
+  print "Default sender: $Mail::Sendmail::mailcfg{from}\n";
+
+  %mail = (
+      #To      => 'No to field this time, only Bcc and Cc',
+      #From    => 'not needed, use default',
+      Bcc     => 'Someone <him@there.com>, Someone else her@there.com',
+      # only addresses are extracted from Bcc, real names disregarded
+      Cc      => 'Yet someone else <xz@whatever.com>',
+      # Cc will appear in the header. (Bcc will not)
+      Subject => 'Test message',
+      'X-Mailer' => "Mail::Sendmail version $Mail::Sendmail::VERSION",
+  );
+
+
+  $mail{Smtp} = 'special_server.for-this-message-only.domain.com';
+  $mail{'X-custom'} = 'My custom additionnal header';
+  $mail{'mESSaGE : '} = "The message key looks terrible, but works.";
+  # cheat on the date:
+  $mail{Date} = Mail::Sendmail::time_to_date( time() - 86400 ),
+
+  if (sendmail %mail) { print "Mail sent OK.\n" }
+  else { print "Error sending mail: $Mail::Sendmail::error \n" }
+
+  print "\n\$Mail::Sendmail::log says:\n", $Mail::Sendmail::log;
+
+=head1 CHANGES
+
+Single-letter host names bug fixed since version 0.77. See the F<Changes> file for
+the full history.
+
+=head1 AUTHOR
+
+Milivoj Ivkovic mi@alma.ch or ivkovic@bluewin.ch
+
+=head1 NOTES
+
+MIME::QuotedPrint is used by default on every message if available. It 
+allows reliable sending of accented characters, and also takes care of 
+too long lines (which can happen in HTML mails). It is available in the 
+MIME-Base64 package at http://www.perl.com/CPAN/modules/by-module/MIME/ or 
+through PPM.
+
+Look at http://alma.ch/perl/Mail-Sendmail-FAQ.htm for additional info 
+(CGI, examples of sending attachments, HTML mail etc...)
+
+You can use it freely. (Someone complained this is too vague. So, more
+precisely: do whatever you want with it, but be warned that terrible things
+will happen to you if you use it badly, like for sending spam, claiming you
+wrote it alone, or ...?)
+
+I would appreciate a short (or long) e-mail note if you use this (and even
+if you don't, especially if you care to say why). And of course,
+bug-reports and/or suggestions are welcome.
+
+Last revision: 25.09.2000. Latest version should be available at
+http://alma.ch/perl/mail.htm , and a few days later on CPAN.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/Ogg/Vorbis/Header/PurePerl.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/Ogg/Vorbis/Header/PurePerl.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/Ogg/Vorbis/Header/PurePerl.pm	(revision 10506)
@@ -0,0 +1,674 @@
+package Ogg::Vorbis::Header::PurePerl;
+
+use 5.005;
+use strict;
+use warnings;
+
+use Fcntl qw/SEEK_END/;
+
+our $VERSION = '0.07';
+
+sub new 
+{
+    my $class = shift;
+    my $file = shift;
+
+    return load($class, $file);
+}
+
+sub load 
+{
+    my $class    = shift;
+    my $file     = shift;
+    my $from_new = shift;
+    my %data;
+    my $self;
+
+    # there must be a better way...
+    if ($class eq 'Ogg::Vorbis::Header::PurePerl')
+    {
+	$self = bless \%data, $class;
+    }
+    else
+    {
+	$self = $class;
+    }
+
+    if ($self->{'FILE_LOADED'})
+    {
+	return $self;
+    }
+
+    $self->{'FILE_LOADED'} = 1;
+
+    # check that the file exists and is readable
+    unless ( -e $file && -r _ )
+    {
+	warn "File does not exist or cannot be read.";
+	# file does not exist, can't do anything
+	return undef;
+    }
+    # open up the file
+    open FILE, $file;
+    # make sure dos-type systems can handle it...
+    binmode FILE;
+
+    $data{'filename'} = $file;
+    $data{'fileHandle'} = \*FILE;
+
+    _init(\%data);
+    _loadInfo(\%data);
+    _loadComments(\%data);
+    _calculateTrackLength(\%data);
+
+    close FILE;
+
+    return $self;
+}
+
+sub info 
+{
+    my $self = shift;
+    my $key = shift;
+
+    # if the user did not supply a key, return the entire hash
+    unless ($key)
+    {
+	return $self->{'INFO'};
+    }
+
+    # otherwise, return the value for the given key
+    return $self->{'INFO'}{lc $key};
+}
+
+sub comment_tags 
+{
+    my $self = shift;
+
+    return @{$self->{'COMMENT_KEYS'}};
+}
+
+sub comment 
+{
+    my $self = shift;
+    my $key = shift;
+
+    # if the user supplied key does not exist, return undef
+    unless($self->{'COMMENTS'}{lc $key})
+    {
+	return undef;
+    }
+
+    return @{$self->{'COMMENTS'}{lc $key}};
+}
+
+sub add_comments 
+{
+    warn "Ogg::Vorbis::Header::PurePerl add_comments() unimplemented.";
+}
+
+sub edit_comment 
+{
+    warn "Ogg::Vorbis::Header::PurePerl edit_comment() unimplemented.";
+}
+
+sub delete_comment 
+{
+    warn "Ogg::Vorbis::Header::PurePerl delete_comment() unimplemented.";
+}
+
+sub clear_comments 
+{
+    warn "Ogg::Vorbis::Header::PurePerl clear_comments() unimplemented.";
+}
+
+sub path 
+{
+    my $self = shift;
+
+    return $self->{'fileName'};
+}
+
+sub write_vorbis
+{
+    warn "Ogg::Vorbis::Header::PurePerl write_vorbis unimplemented.";
+}
+
+# "private" methods
+
+sub _init
+{
+    my $data = shift;
+    my $fh = $data->{'fileHandle'};
+    my $byteCount = 0;
+
+    # check the header to make sure this is actually an Ogg-Vorbis file
+    $byteCount = _checkHeader($data);
+
+    unless($byteCount)
+    {
+	# if it's not, we can't do anything
+	return undef;
+    }
+
+    $data->{'startInfoHeader'} = $byteCount;
+}
+
+sub _checkHeader
+{
+    my $data = shift;
+    my $fh = $data->{'fileHandle'};
+    my $buffer;
+    my $pageSegCount;
+    my $byteCount = 0; # stores how far into the file we've read,
+                       # so later reads into the file can skip right
+                       # past all of the header stuff
+
+    # check that the first four bytes are 'OggS'
+    read($fh, $buffer, 4);
+    if ($buffer ne 'OggS')
+    {
+	warn "This is not an Ogg bitstream (no OggS header).";
+	return undef;
+    }
+    $byteCount += 4;
+
+    # check the stream structure version (1 byte, should be 0x00)
+    read($fh, $buffer, 1);
+    if (ord($buffer) != 0x00)
+    {
+	warn "This is not an Ogg bitstream (invalid structure version).";
+	return undef;
+    }
+    $byteCount += 1;
+
+    # check the header type flag 
+    # This is a bitfield, so technically we should check all of the bits
+    # that could potentially be set. However, the only value this should
+    # possibly have at the beginning of a proper Ogg-Vorbis file is 0x02,
+    # so we just check for that. If it's not that, we go on anyway, but
+    # give a warning (this behavior may (should?) be modified in the future.
+    read($fh, $buffer, 1);
+    if (ord($buffer) != 0x02)
+    {
+	warn "Invalid header type flag (trying to go ahead anyway).";
+    }
+    $byteCount += 1;
+
+    # skip to the page_segments count
+    read($fh, $buffer, 20);
+    $byteCount += 20;
+    # we do nothing with this data
+
+    # read the number of page segments
+    read($fh, $buffer, 1);
+    $pageSegCount = ord($buffer);
+    $byteCount += 1;
+
+    # read $pageSegCount bytes, then throw 'em out
+    read($fh, $buffer, $pageSegCount);
+    $byteCount += $pageSegCount;
+
+    # check packet type. Should be 0x01 (for indentification header)
+    read($fh, $buffer, 1);
+    if (ord($buffer) != 0x01)
+    {
+	warn "Wrong vorbis header type, giving up.";
+	return undef;
+    }
+    $byteCount += 1;
+
+    # check that the packet identifies itself as 'vorbis'
+    read($fh, $buffer, 6);
+    if ($buffer ne 'vorbis')
+    {
+	warn "This does not appear to be a vorbis stream, giving up.";
+	return undef;
+    }
+    $byteCount += 6;
+
+    # at this point, we assume the bitstream is valid
+    return $byteCount;
+}
+
+sub _loadInfo
+{
+    my $data = shift;
+    my $start = $data->{'startInfoHeader'};
+    my $fh = $data->{'fileHandle'};
+    my $buffer;
+    my $byteCount = $start;
+    my %info;
+    
+    seek $fh, $start, 0;
+    
+    # read the vorbis version
+    read($fh, $buffer, 4);
+    $info{'version'} = _decodeInt($buffer);
+    $byteCount += 4;
+    
+    # read the number of audio channels
+    read($fh, $buffer, 1);
+    $info{'channels'} = ord($buffer);
+    $byteCount += 1;
+
+    # read the sample rate
+    read($fh, $buffer, 4);
+    $info{'rate'} = _decodeInt($buffer);
+    $byteCount += 4;
+    
+    # read the bitrate maximum
+    read($fh, $buffer, 4);
+    $info{'bitrate_upper'} = _decodeInt($buffer);
+    $byteCount += 4;
+
+    # read the bitrate nominal
+    read($fh, $buffer, 4);
+    $info{'bitrate_nominal'} = _decodeInt($buffer);
+    $byteCount += 4;
+
+    # read the bitrate minimal
+    read($fh, $buffer, 4);
+    $info{'bitrate_lower'} = _decodeInt($buffer);
+    $byteCount += 4;
+
+    # read the blocksize_0 and blocksize_1
+    read($fh, $buffer, 1);
+    # these are each 4 bit fields, whose actual value is 2 to the power
+    # of the value of the field
+    $info{'blocksize_0'} = 2 << ((ord($buffer) & 0xF0) >> 4);
+    $info{'blocksize_1'} = 2 << (ord($buffer) & 0x0F);
+    $byteCount += 1;
+
+    # read the framing_flag
+    read($fh, $buffer, 1);
+    $info{'framing_flag'} = ord($buffer);
+    $byteCount += 1;
+
+    # bitrate_window is -1 in the current version of vorbisfile
+    $info{'bitrate_window'} = -1;
+
+    $data->{'startCommentHeader'} = $byteCount;
+
+    $data->{'INFO'} = \%info;
+}
+
+sub _loadComments
+{
+    my $data = shift;
+    my $fh = $data->{'fileHandle'};
+    my $start = $data->{'startCommentHeader'};
+    my $buffer;
+    my $page_segments;
+    my $vendor_length;
+    my $user_comment_count;
+    my $byteCount = $start;
+    my %comments;
+
+    seek $fh, $start, 0;
+
+    # check that the first four bytes are 'OggS'
+    read($fh, $buffer, 4);
+    if ($buffer ne 'OggS')
+    {
+	warn "No comment header?";
+	return undef;
+    }
+    $byteCount += 4;
+
+    # skip over next ten bytes
+    read($fh, $buffer, 10);
+    $byteCount += 10;
+
+    # read the stream serial number
+    read($fh, $buffer, 4);
+    push @{$data->{'commentSerialNumber'}}, _decodeInt($buffer);
+    $byteCount += 4;
+
+    # read the page sequence number (should be 0x01)
+    read($fh, $buffer, 4);
+    if (_decodeInt($buffer) != 0x01)
+    {
+	warn "Comment header page sequence number is not 0x01: " + 
+	    _decodeInt($buffer);
+	warn "Going to keep going anyway.";
+    }
+    $byteCount += 4;
+
+    # and ignore the page checksum for now
+    read($fh, $buffer, 4);
+    $byteCount += 4;
+
+    # get the number of entries in the segment_table...
+    read($fh, $buffer, 1);
+    $page_segments = _decodeInt($buffer);
+    $byteCount += 1;
+    # then skip on past it
+    read($fh, $buffer, $page_segments);
+    $byteCount += $page_segments;
+
+    # check the header type (should be 0x03)
+    read($fh, $buffer, 1);
+    if (ord($buffer) != 0x03)
+    {
+	warn "Wrong header type: " . ord($buffer);
+    }    
+    $byteCount += 1;
+
+    # now we should see 'vorbis'
+    read($fh, $buffer, 6);
+    if ($buffer ne 'vorbis')
+    {
+	warn "Missing comment header. Should have found 'vorbis', found " .
+	    $buffer;
+    }
+    $byteCount += 6;
+
+    # get the vendor length
+    read($fh, $buffer, 4);
+    $vendor_length = _decodeInt($buffer);
+    $byteCount += 4;
+
+    # read in the vendor
+    read($fh, $buffer, $vendor_length);
+    $comments{'vendor'} = $buffer;
+    $byteCount += $vendor_length;
+
+    # read in the number of user comments
+    read($fh, $buffer, 4);
+    $user_comment_count = _decodeInt($buffer);
+    $byteCount += 4;
+
+    $data->{'COMMENT_KEYS'} = [];
+
+    # finally, read the comments
+    for (my $i = 0; $i < $user_comment_count; $i++)
+    {
+	# first read the length
+	read($fh, $buffer, 4);
+	my $comment_length = _decodeInt($buffer);
+	$byteCount += 4;
+
+	# then the comment itself
+	read($fh, $buffer, $comment_length);
+	$byteCount += $comment_length;
+
+	my ($key) = $buffer =~ /^([^=]+)/;
+	my ($value) = $buffer =~ /=(.*)$/;
+
+	push @{$comments{lc $key}}, $value;
+	push @{$data->{'COMMENT_KEYS'}}, lc $key;
+    }
+    
+    # read past the framing_bit
+    read($fh, $buffer, 1);
+    $byteCount += 1;
+
+    $data->{'INFO'}{'offset'} = $byteCount;
+
+    $data->{'COMMENTS'} = \%comments;
+}
+
+sub _calculateTrackLength
+{
+    my $data = shift;
+    my $fh = $data->{'fileHandle'};
+    my $buffer;
+    my $pageSize;
+    my $granule_position;
+
+    seek($fh,-8500,SEEK_END);  # that magic number is from vorbisfile.c
+    # in the constant CHUNKSIZE, which comes
+    # with the comment /* a shade over 8k;
+    # anyone using pages well over 8k gets
+    # what they deserve */
+
+    # we just keep looking through the headers until we get to the last one
+    # (there might be a couple of blocks here)
+    while(_findPage($fh))
+    {
+	# stream structure version - must be 0x00
+	read($fh, $buffer, 1);
+	if (ord($buffer) != 0x00)
+	{
+	    warn "Invalid stream structure version: " .
+		sprintf("%x", ord($buffer));
+	    return;
+ 	}
+
+ 	# header type flag
+ 	read($fh, $buffer, 1);
+ 	# we should check this, but for now we'll just ignore it
+
+ 	# absolute granule position - this is what we need!
+ 	read($fh, $buffer, 8);
+ 	$granule_position = _decodeInt($buffer);
+
+	# skip past stream_serial_number, page_sequence_number, and crc
+	read($fh, $buffer, 12);
+
+	# page_segments
+	read($fh, $buffer, 1);
+	my $page_segments = ord($buffer);
+
+	# reset pageSize
+	$pageSize = 0;
+	
+	# calculate approx. page size
+	for (my $i = 0; $i < $page_segments; $i++)
+	{
+	    read($fh, $buffer, 1);
+	    $pageSize += ord($buffer);
+	}
+
+	seek $fh, $pageSize, 1;
+    }
+
+    $data->{'INFO'}{'length'} = 
+	int($granule_position / $data->{'INFO'}{'rate'});
+}
+
+sub _findPage
+{
+    # search forward in the file for the 'OggS' page header
+    my $fh = shift;
+    my $char;
+    my $curStr = '';
+
+    while (read($fh, $char, 1))
+    {
+	$curStr = $char . $curStr;
+	$curStr = substr($curStr, 0, 4);
+
+	# we are actually looking for the string 'SggO' because we
+	# tack character on to our test string backwards, to make
+	# trimming it to 4 characters easier.
+	if ($curStr eq 'SggO')
+	{
+	    return 1;
+	}
+    }
+
+    return undef;
+}
+
+sub _decodeInt
+{
+    my $bytes = shift;
+    my $num = 0;
+    my @byteList = split //, $bytes;
+    my $numBytes = @byteList;
+    my $mult = 1;
+
+    for (my $i = 0; $i < $numBytes; $i ++)
+    {
+	$num += ord($byteList[$i]) * $mult;
+	$mult *= 256;
+    }
+
+    return $num;
+}
+
+sub _decodeInt5Bit
+{
+    my $byte = ord(shift);
+
+    $byte = $byte & 0xF8; # clear out the bottm 3 bits
+    $byte = $byte >> 3; # and shifted down to where it belongs
+
+    return $byte;
+}
+
+sub _decodeInt4Bit
+{
+    my $byte = ord(shift);
+
+    $byte = $byte & 0xFC; # clear out the bottm 4 bits
+    $byte = $byte >> 4; # and shifted down to where it belongs
+
+    return $byte;
+}
+
+sub _ilog
+{
+    my $x = shift;
+    my $ret = 0;
+
+    unless ($x > 0)
+    {
+	return 0;
+    }
+
+    while ($x > 0)
+    {
+	$ret++;
+	$x = $x >> 1;
+    }
+
+    return $ret;
+}
+
+1;
+__DATA__
+
+=head1 NAME
+
+Ogg::Vorbis::Header::PurePerl - An object-oriented interface to Ogg Vorbis
+information and comment fields, implemented entirely in Perl.  Intended to be 
+a drop in replacement for Ogg::Vobis::Header.
+
+Unlike Ogg::Vorbis::Header, this module will go ahead and fill in all of the
+information fields as soon as you construct the object.  In other words,
+the C<new> and C<load> constructors have identical behavior. 
+
+=head1 SYNOPSIS
+
+	use Ogg::Vorbis::Header::PurePerl;
+	my $ogg = Ogg::Vorbis::Header::PurePerl->new("song.ogg");
+	while (my ($k, $v) = each %{$ogg->info}) {
+		print "$k: $v\n";
+	}
+	foreach my $com ($ogg->comment_tags) {
+		print "$com: $_\n" foreach $ogg->comment($com);
+	}
+
+=head1 DESCRIPTION
+
+This module is intended to be a drop in replacement for Ogg::Vorbis::Header,
+implemented entirely in Perl.  It provides an object-oriented interface to
+Ogg Vorbis information and comment fields.  (NOTE: This module currently 
+supports only read operations).
+
+=head1 CONSTRUCTORS
+
+=head2 C<new ($filename)>
+
+Opens an Ogg Vorbis file, ensuring that it exists and is actually an
+Ogg Vorbis stream.  This method does not actually read any of the
+information or comment fields, and closes the file immediately. 
+
+=head2 C<load ([$filename])>
+
+Opens an Ogg Vorbis file, ensuring that it exists and is actually an
+Ogg Vorbis stream, then loads the information and comment fields.  This
+method can also be used without a filename to load the information
+and fields of an already constructed instance.
+
+=head1 INSTANCE METHODS
+
+=head2 C<info ([$key])>
+
+Returns a hashref containing information about the Ogg Vorbis file from
+the file's information header.  Hash fields are: version, channels, rate,
+bitrate_upper, bitrate_nominal, bitrate_lower, bitrate_window, and length.
+The bitrate_window value is not currently used by the vorbis codec, and 
+will always be -1.  
+
+The optional parameter, key, allows you to retrieve a single value from
+the object's hash.  Returns C<undef> if the key is not found.
+
+=head2 C<comment_tags ()>
+
+Returns an array containing the key values for the comment fields. 
+These values can then be passed to C<comment> to retrieve their values.
+
+=head2 C<comment ($key)>
+
+Returns an array of comment values associated with the given key.
+
+=head2 C<add_comments ($key, $value, [$key, $value, ...])>
+
+Unimplemented.
+
+=head2 C<edit_comment ($key, $value, [$num])>
+
+Unimplemented.
+
+=head2 C<delete_comment ($key, [$num])>
+
+Unimplemented.
+
+=head2 C<clear_comments ([@keys])>
+
+Unimplemented.
+
+=head2 C<write_vorbis ()>
+
+Unimplemented.
+
+=head2 C<path ()>
+
+Returns the path/filename of the file the object represents.
+
+=head1 NOTE
+
+This is ALPHA SOFTWARE.  It may very well be very broken.  Do not use it in
+a production environment.  You have been warned.
+
+=head1 ACKNOWLEDGEMENTS
+
+Dave Brown <cpan@dagbrown.com> made this module significantly faster
+at calculating the length of ogg files.
+
+Robert Moser II <rlmoser@earthlink.net> fixed a problem with files that
+have no comments.
+
+=head1 AUTHOR
+
+Andrew Molloy E<lt>amolloy@kaizolabs.comE<gt>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2003, Andrew Molloy.  All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.  A copy of this license is included
+with this module (LICENSE.GPL).
+
+=head1 SEE ALSO
+
+L<Ogg::Vorbis::Header>, L<Ogg::Vorbis::Decoder>
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/Win32/Shortcut.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/Win32/Shortcut.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/Win32/Shortcut.pm	(revision 10506)
@@ -0,0 +1,352 @@
+package Win32::Shortcut;
+#######################################################################
+#
+# Win32::Shortcut - Perl Module for Shell Link Interface
+# ^^^^^^^^^^^^^^^
+# This module creates an object oriented interface to the Win32
+# Shell Links (IShellLink interface).
+#
+# Version: 0.03 (07 Apr 1997)
+#
+#######################################################################
+
+require Exporter;       # to export the constants to the main:: space
+require DynaLoader;     # to dynuhlode the module.
+
+@ISA= qw( Exporter DynaLoader );
+@EXPORT = qw(
+    SW_SHOWMAXIMIZED
+    SW_SHOWMINNOACTIVE
+    SW_SHOWNORMAL
+);
+
+
+#######################################################################
+# This AUTOLOAD is used to 'autoload' constants from the constant()
+# XS function.  If a constant is not found then control is passed
+# to the AUTOLOAD in AutoLoader.
+#
+
+sub AUTOLOAD {
+    my($constname);
+    ($constname = $AUTOLOAD) =~ s/.*:://;
+    #reset $! to zero to reset any current errors.
+    local $! = 0;
+    my $val = constant($constname, @_ ? $_[0] : 0);
+    if ($! != 0) {
+
+    # [dada] This results in an ugly Autoloader error
+
+    #if ($! =~ /Invalid/) {
+    #    $AutoLoader::AUTOLOAD = $AUTOLOAD;
+    #    goto &AutoLoader::AUTOLOAD;
+    #} else {
+    
+    # [dada] ... I prefer this one :)
+
+        ($pack, $file, $line) = caller;
+        undef $pack; # [dada] and get rid of "used only once" warning...
+        die "Win32::Shortcut::$constname is not defined, used at $file line $line.";
+
+    #}
+    }
+    eval "sub $AUTOLOAD { $val }";
+    goto &$AUTOLOAD;
+}
+
+
+#######################################################################
+# STATIC OBJECT PROPERTIES
+#
+$VERSION = "0.03";
+
+#######################################################################
+# PUBLIC METHODS
+#
+
+#======== ### CLASS CONSTRUCTOR
+sub new {
+#========
+    my($class, $file) = @_;
+    my $self = {}; 
+    my $ilink = 0; 
+    my $ifile = 0;
+
+    ($ilink, $ifile) = _Instance();
+
+    if($ilink and $ifile) {
+        $self->{'ilink'} = $ilink;
+        $self->{'ifile'} = $ifile;
+        bless $self;
+        # Initialize properties
+        $self->{'File'}             = "";
+        $self->{'Path'}             = "";
+        $self->{'Arguments'}        = "";
+        $self->{'WorkingDirectory'} = "";
+        $self->{'Description'}      = "";
+        $self->{'ShowCmd'}          = 0;
+        $self->{'Hotkey'}           = 0;
+        $self->{'IconLocation'}     = "";
+        $self->{'IconNumber'}       = 0;
+
+        $self->Load($file) if $file;
+        
+    } else {
+        return undef;
+    }
+    $self;
+}  
+
+#=========
+sub Load {
+#=========
+    my($self, $file) = @_;
+    return undef unless ref($self);
+  
+    my $result = _Load($self->{'ilink'}, $self->{'ifile'}, $file);
+
+    if(defined($result)) {
+  
+        # fill the properties of $self
+        $self->{'File'} = $file;
+        $self->{'Path'} = _GetPath($self->{'ilink'}, $self->{'ifile'},0);
+        $self->{'ShortPath'} = _GetPath($self->{'ilink'}, $self->{'ifile'},1);
+        $self->{'Arguments'} = _GetArguments($self->{'ilink'}, $self->{'ifile'});
+        $self->{'WorkingDirectory'} = _GetWorkingDirectory($self->{'ilink'}, $self->{'ifile'});
+        $self->{'Description'} = _GetDescription($self->{'ilink'}, $self->{'ifile'});
+        $self->{'ShowCmd'} = _GetShowCmd($self->{'ilink'}, $self->{'ifile'});
+        $self->{'Hotkey'} = _GetHotkey($self->{'ilink'}, $self->{'ifile'});
+        ($self->{'IconLocation'},
+         $self->{'IconNumber'}) = _GetIconLocation($self->{'ilink'}, $self->{'ifile'});
+    }
+    return $result;
+}
+
+
+#========
+sub Set {
+#========
+    my($self, $path, $arguments, $dir, $description, $show, $hotkey, 
+       $iconlocation, $iconnumber) = @_;
+    return undef unless ref($self);
+
+    $self->{'Path'}             = $path;
+    $self->{'Arguments'}        = $arguments;
+    $self->{'WorkingDirectory'} = $dir;
+    $self->{'Description'}      = $description;
+    $self->{'ShowCmd'}          = $show;
+    $self->{'Hotkey'}           = $hotkey;
+    $self->{'IconLocation'}     = $iconlocation;
+    $self->{'IconNumber'}       = $iconnumber;
+    return 1;
+}
+
+
+#=========
+sub Save {
+#=========
+    my($self, $file) = @_;
+    return undef unless ref($self);
+
+    return undef if not $file and not $self->{'File'};
+    $file = $self->{'File'} if not $file;
+
+    _SetPath($self->{'ilink'}, $self->{'ifile'}, $self->{'Path'});
+    _SetArguments($self->{'ilink'}, $self->{'ifile'}, $self->{'Arguments'});
+    _SetWorkingDirectory($self->{'ilink'}, $self->{'ifile'}, $self->{'WorkingDirectory'});
+    _SetDescription($self->{'ilink'}, $self->{'ifile'}, $self->{'Description'});
+    _SetShowCmd($self->{'ilink'}, $self->{'ifile'}, $self->{'ShowCmd'});
+    _SetHotkey($self->{'ilink'}, $self->{'ifile'}, $self->{'Hotkey'});
+    _SetIconLocation($self->{'ilink'}, $self->{'ifile'},
+                     $self->{'IconLocation'}, $self->{'IconNumber'});
+
+    my $result = _Save($self->{'ilink'}, $self->{'ifile'}, $file);
+    return $result;
+}
+
+#============
+sub Resolve {
+#============
+    my($self, $flags) = @_;
+    return undef unless ref($self);
+    $flags = 1 unless defined($flags);
+    my $result = _Resolve($self->{'ilink'}, $self->{'ifile'}, $flags);
+    return $result;
+}
+
+
+#==========
+sub Close {
+#==========
+    my($self) = @_;
+    return undef unless ref($self);
+
+    my $result = _Release($self->{'ilink'}, $self->{'ifile'});
+    $self->{'released'} = 1;
+    return $result;
+}
+
+#=========
+sub Path {
+#=========
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'Path'};
+    } else {
+        $self->{'Path'} = $value;
+    }
+    return $self->{'Path'};
+}
+
+#==============
+sub ShortPath {
+#==============
+    my($self) = @_;
+    return undef unless ref($self);
+    return $self->{'ShortPath'};
+}
+
+#==============
+sub Arguments {
+#==============
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'Arguments'};
+    } else {
+        $self->{'Arguments'} = $value;
+    }
+    return $self->{'Arguments'};
+}
+
+#=====================
+sub WorkingDirectory {
+#=====================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'WorkingDirectory'};
+    } else {
+        $self->{'WorkingDirectory'} = $value;
+    }
+    return $self->{'WorkingDirectory'};
+}
+
+
+#================
+sub Description {
+#================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'Description'};
+    } else {
+        $self->{'Description'} = $value;
+    }
+    return $self->{'Description'};
+}
+
+#============
+sub ShowCmd {
+#============
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'ShowCmd'};
+    } else {
+        $self->{'ShowCmd'} = $value;
+    }
+    return $self->{'ShowCmd'};
+}
+
+#===========
+sub Hotkey {
+#===========
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'Hotkey'};
+    } else {
+        $self->{'Hotkey'} = $value;
+    }
+    return $self->{'Hotkey'};
+}
+
+#=================
+sub IconLocation {
+#=================
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'IconLocation'};
+    } else {
+        $self->{'IconLocation'} = $value;
+    }
+    return $self->{'IconLocation'};
+}
+
+#===============
+sub IconNumber {
+#===============
+    my($self, $value) = @_;
+    return undef unless ref($self);
+
+    if(not defined($value)) {
+        return $self->{'IconNumber'};
+    } else {
+        $self->{'IconNumber'} = $value;
+    }
+    return $self->{'IconNumber'};
+}
+
+#============
+sub Version {
+#============
+    # [dada] to get rid of the "used only once" warning...
+    return $VERSION;
+}
+
+
+#######################################################################
+# PRIVATE METHODS
+#
+
+#============ ### CLASS DESTRUCTOR
+sub DESTROY {
+#============
+    my($self) = @_;
+
+    if(not $self->{'released'}) {
+        _Release($self->{'ilink'}, $self->{'ifile'});
+    }
+}
+
+#======== ### PACKAGE DESTRUCTOR
+sub END { 
+#========
+    # print "Exiting...\n";
+    _Exit(); 
+}
+
+#######################################################################
+# dynamically load in the Shortcut.pll module.
+#
+
+bootstrap Win32::Shortcut;
+
+# Preloaded methods go here.
+
+#Currently Autoloading is not implemented in Perl for win32
+# Autoload methods go after __END__, and are processed by the autosplit program.
+
+1;
+__END__
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath.pm	(revision 10506)
@@ -0,0 +1,553 @@
+# $Id$
+
+package XML::XPath;
+
+use strict;
+use vars qw($VERSION $AUTOLOAD $revision);
+
+$VERSION = '1.13';
+
+$XML::XPath::Namespaces = 1;
+$XML::XPath::Debug = 0;
+
+use XML::XPath::XMLParser;
+use XML::XPath::Parser;
+use IO::File;
+
+# For testing
+#use Data::Dumper;
+#$Data::Dumper::Indent = 1;
+
+# Parameters for new()
+my @options = qw(
+        filename
+        parser
+        xml
+        ioref
+        context
+        );
+
+sub new {
+    my $proto = shift;
+    my $class = ref($proto) || $proto;
+
+    my(%args);
+    # Try to figure out what the user passed
+    if ($#_ == 0) { # passed a scalar
+        my $string = $_[0];
+        if ($string =~ m{<.*?>}s) { # it's an XML string
+            $args{'xml'} = $string;
+        } elsif (ref($string)) {    # read XML from file handle
+            $args{'ioref'} = $string;
+        } elsif ($string eq '-') {  # read XML from stdin
+            $args{'ioref'} = IO::File->new($string);
+        } else {                    # read XML from a file
+            $args{'filename'} = $string;
+        }
+    } else {        # passed a hash or hash reference
+        # just pass the parameters on to the XPath constructor
+        %args = ((ref($_[0]) eq "HASH") ? %{$_[0]} : @_);
+    }
+
+    if ($args{filename} && (!-e $args{filename} || !-r $args{filename})) {
+        die "Cannot open file '$args{filename}'";
+    }
+    my %hash = map(( "_$_" => $args{$_} ), @options);
+    $hash{path_parser} = XML::XPath::Parser->new();
+    return bless \%hash, $class;
+}
+
+sub find {
+    my $self = shift;
+    my $path = shift;
+    my $context = shift;
+    die "No path to find" unless $path;
+    
+    if (!defined $context) {
+        $context = $self->get_context;
+    }
+    if (!defined $context) {
+        # Still no context? Need to parse...
+        my $parser = XML::XPath::XMLParser->new(
+                filename => $self->get_filename,
+                xml => $self->get_xml,
+                ioref => $self->get_ioref,
+                parser => $self->get_parser,
+                );
+        $context = $parser->parse;
+        $self->set_context($context);
+#        warn "CONTEXT:\n", Data::Dumper->Dumpxs([$context], ['context']);
+    }
+    
+    my $parsed_path = $self->{path_parser}->parse($path);
+#    warn "\n\nPATH: ", $parsed_path->as_string, "\n\n";
+    
+#    warn "evaluating path\n";
+    return $parsed_path->evaluate($context);
+}
+
+# sub memsize {
+#     print STDERR @_, "\t";
+#     open(FH, '/proc/self/status');
+#     while(<FH>) {
+#         print STDERR $_ if /^VmSize/;
+#     }
+#     close FH;
+# }
+# 
+sub findnodes {
+    my $self = shift;
+    my ($path, $context) = @_;
+    
+    my $results = $self->find($path, $context);
+    
+    if ($results->isa('XML::XPath::NodeSet')) {
+        return wantarray ? $results->get_nodelist : $results;
+#        return $results->get_nodelist;
+    }
+    
+#    warn("findnodes returned a ", ref($results), " object\n") if $XML::XPath::Debug;
+    return wantarray ? () : XML::XPath::NodeSet->new();
+}
+
+sub matches {
+    my $self = shift;
+    my ($node, $path, $context) = @_;
+
+    my @nodes = $self->findnodes($path, $context);
+
+    if (grep { "$node" eq "$_" } @nodes) {
+        return 1;
+    }
+    return;
+}
+
+sub findnodes_as_string {
+    my $self = shift;
+    my ($path, $context) = @_;
+    
+    my $results = $self->find($path, $context);
+    
+    if ($results->isa('XML::XPath::NodeSet')) {
+        return join('', map { $_->toString } $results->get_nodelist);
+    }
+    elsif ($results->isa('XML::XPath::Node')) {
+        return $results->toString;
+    }
+    else {
+        return XML::XPath::Node::XMLescape($results->value);
+    }
+}
+
+sub findvalue {
+    my $self = shift;
+    my ($path, $context) = @_;
+    
+    my $results = $self->find($path, $context);
+    
+    if ($results->isa('XML::XPath::NodeSet')) {
+        return $results->to_literal;
+    }
+    
+    return $results;
+}
+
+sub exists
+{
+    my $self = shift;
+    my ($path, $context) = @_;
+    $path = '/' if (!defined $path);
+    my @nodeset = $self->findnodes($path, $context);
+    return 1 if (scalar( @nodeset ));
+    return 0;
+}
+
+sub getNodeAsXML {
+  my $self = shift;
+  my $node_path = shift;
+  $node_path = '/' if (!defined $node_path);
+  if (ref($node_path)) {
+    return $node_path->as_string();
+  } else {
+    return $self->findnodes_as_string($node_path);
+  }
+}
+
+sub getNodeText {
+  my $self = shift;
+  my $node_path = shift;
+  if (ref($node_path)) {
+    return $node_path->string_value();
+  } else {
+    return $self->findvalue($node_path);
+  }
+}
+
+sub setNodeText {
+  my $self = shift;
+  my($node_path, $new_text) = @_;
+  my $nodeset = $self->findnodes($node_path);
+  return undef if (!defined $nodeset); # could not find node
+  my @nodes = $nodeset->get_nodelist;
+  if ($#nodes < 0) {
+    if ($node_path =~ m|/@([^/]+)$|) {
+      # attribute not found, so try to create it
+      my $parent_path = $`;
+      my $attr = $1;
+      $nodeset = $self->findnodes($parent_path);
+      return undef if (!defined $nodeset); # could not find node
+      foreach my $node ($nodeset->get_nodelist) {
+        my $newnode = XML::XPath::Node::Attribute->new($attr, $new_text);
+        return undef if (!defined $newnode); # could not create new node
+        $node->appendAttribute($newnode);
+      }
+    } else {
+      return undef; # could not find node
+    }
+  }
+  foreach my $node (@nodes) {
+    if ($node->getNodeType == XML::XPath::Node::ATTRIBUTE_NODE) {
+      $node->setNodeValue($new_text);
+    } else {
+      foreach my $delnode ($node->getChildNodes()) {
+        $node->removeChild($delnode);
+      }
+      my $newnode = XML::XPath::Node::Text->new($new_text);
+      return undef if (!defined $newnode); # could not create new node
+      $node->appendChild($newnode);
+    }
+  }
+  return 1;
+}
+
+sub createNode {
+  my $self = shift;
+  my($node_path) = @_;
+  my $path_steps = $self->{path_parser}->parse($node_path);
+  my @path_steps = ();
+  foreach my $step (@{$path_steps->get_lhs()}) {
+    my $string = $step->as_string();
+    push(@path_steps, $string) if (defined $string && $string ne "");
+  }
+  my $prev_node = undef;
+  my $nodeset = undef;
+  my $nodes = undef;
+  my $p = undef;
+  my $test_path = "";
+  # Start with the deepest node, working up the path (right to left),
+  # trying to find a node that exists.
+  for ($p = $#path_steps; $p >= 0; $p--) {
+    my $path = $path_steps[$p];
+    $test_path = "(/" . join("/", @path_steps[0..$p]) . ")";
+    $nodeset = $self->findnodes($test_path);
+    return undef if (!defined $nodeset); # error looking for node
+    $nodes = $nodeset->size;
+    return undef if ($nodes > 1); # too many paths - path not specific enough
+    if ($nodes == 1) { # found a node -- need to create nodes below it
+      $prev_node = $nodeset->get_node(1);
+      last;
+    }
+  }
+  if (!defined $prev_node) {
+    my @root_nodes = $self->findnodes('/')->get_nodelist();
+    $prev_node = $root_nodes[0];
+  }
+  # We found a node that exists, or we'll start at the root.
+  # Create all lower nodes working left to right along the path.
+  for ($p++ ; $p <= $#path_steps; $p++) {
+    my $path = $path_steps[$p];
+    my $newnode = undef;
+    my($axis,$name) = ($path =~ /^(.*?)::(.*)$/);
+    if ($axis =~ /^child$/i) {
+      $newnode = XML::XPath::Node::Element->new($name);
+      return undef if (!defined $newnode); # could not create new node
+      $prev_node->appendChild($newnode);
+    } elsif ($axis =~ /^attribute$/i) {
+      $newnode = XML::XPath::Node::Attribute->new($name, "");
+      return undef if (!defined $newnode); # could not create new node
+      $prev_node->appendAttribute($newnode);
+    }
+    $prev_node = $newnode;
+  }
+  return $prev_node;
+}
+
+sub get_filename {
+    my $self = shift;
+    $self->{_filename};
+}
+
+sub set_filename {
+    my $self = shift;
+    $self->{_filename} = shift;
+}
+
+sub get_parser {
+    my $self = shift;
+    $self->{_parser};
+}
+
+sub set_parser {
+    my $self = shift;
+    $self->{_parser} = shift;
+}
+
+sub get_xml {
+    my $self = shift;
+    $self->{_xml};
+}
+
+sub set_xml {
+    my $self = shift;
+    $self->{_xml} = shift;
+}
+
+sub get_ioref {
+    my $self = shift;
+    $self->{_ioref};
+}
+
+sub set_ioref {
+    my $self = shift;
+    $self->{_ioref} = shift;
+}
+
+sub get_context {
+    my $self = shift;
+    $self->{_context};
+}
+
+sub set_context {
+    my $self = shift;
+    $self->{_context} = shift;
+}
+
+sub cleanup {
+    my $self = shift;
+    if ($XML::XPath::SafeMode) {
+        my $context = $self->get_context;
+        return unless $context;
+        $context->dispose;
+    }
+}
+
+sub set_namespace {
+    my $self = shift;
+    my ($prefix, $expanded) = @_;
+    $self->{path_parser}->set_namespace($prefix, $expanded);
+}
+
+sub clear_namespaces {
+    my $self = shift;
+    $self->{path_parser}->clear_namespaces();
+}
+
+1;
+__END__
+
+=head1 NAME
+
+XML::XPath - a set of modules for parsing and evaluating XPath statements
+
+=head1 DESCRIPTION
+
+This module aims to comply exactly to the XPath specification at
+http://www.w3.org/TR/xpath and yet allow extensions to be added in the
+form of functions. Modules such as XSLT and XPointer may need to do
+this as they support functionality beyond XPath.
+
+=head1 SYNOPSIS
+
+    use XML::XPath;
+    use XML::XPath::XMLParser;
+    
+    my $xp = XML::XPath->new(filename => 'test.xhtml');
+    
+    my $nodeset = $xp->find('/html/body/p'); # find all paragraphs
+    
+    foreach my $node ($nodeset->get_nodelist) {
+        print "FOUND\n\n", 
+            XML::XPath::XMLParser::as_string($node),
+            "\n\n";
+    }
+
+=head1 DETAILS
+
+There's an awful lot to all of this, so bear with it - if you stick it
+out it should be worth it. Please get a good understanding of XPath
+by reading the spec before asking me questions. All of the classes
+and parts herein are named to be synonimous with the names in the
+specification, so consult that if you don't understand why I'm doing
+something in the code.
+
+=head1 API
+
+The API of XML::XPath itself is extremely simple to allow you to get
+going almost immediately. The deeper API's are more complex, but you
+shouldn't have to touch most of that.
+
+=head2 new()
+
+This constructor follows the often seen named parameter method call.
+Parameters you can use are: filename, parser, xml, ioref and context.
+The filename parameter specifies an XML file to parse. The xml
+parameter specifies a string to parse, and the ioref parameter
+specifies an ioref to parse. The context option allows you to 
+specify a context node. The context node has to be in the format 
+of a node as specified in L<XML::XPath::XMLParser>. The 4 parameters
+filename, xml, ioref and context are mutually exclusive - you should
+only specify one (if you specify anything other than context, the
+context node is the root of your document).
+The parser option allows you to pass in an already prepared 
+XML::Parser object, to save you having to create more than one
+in your application (if, for example, you're doing more than just XPath).
+
+    my $xp = XML::XPath->new( context => $node );
+
+It is very much recommended that you use only 1 XPath object throughout 
+the life of your application. This is because the object (and it's sub-objects)
+maintain certain bits of state information that will be useful (such
+as XPath variables) to later calls to find(). It's also a good idea because
+you'll use less memory this way.
+
+=head2 I<nodeset> = find($path, [$context])
+
+The find function takes an XPath expression (a string) and returns either an
+XML::XPath::NodeSet object containing the nodes it found (or empty if
+no nodes matched the path), or one of XML::XPath::Literal (a string),
+XML::XPath::Number, or XML::XPath::Boolean. It should always return 
+something - and you can use ->isa() to find out what it returned. If you
+need to check how many nodes it found you should check $nodeset->size.
+See L<XML::XPath::NodeSet>. An optional second parameter of a context
+node allows you to use this method repeatedly, for example XSLT needs
+to do this.
+
+=head2 findnodes($path, [$context])
+
+Returns a list of nodes found by $path, optionally in context $context. 
+In scalar context returns an XML::XPath::NodeSet object.
+
+=head2 findnodes_as_string($path, [$context])
+
+Returns the nodes found reproduced as XML. The result is not guaranteed
+to be valid XML though.
+
+=head2 findvalue($path, [$context])
+
+Returns either a C<XML::XPath::Literal>, a C<XML::XPath::Boolean> or a
+C<XML::XPath::Number> object. If the path returns a NodeSet,
+$nodeset->to_literal is called automatically for you (and thus a
+C<XML::XPath::Literal> is returned). Note that
+for each of the objects stringification is overloaded, so you can just
+print the value found, or manipulate it in the ways you would a normal
+perl value (e.g. using regular expressions).
+
+=head2 exists($path, [$context])
+
+Returns true if the given path exists.
+
+=head2 matches($node, $path, [$context])
+
+Returns true if the node matches the path (optionally in context $context).
+
+=head2 getNodeText($path)
+
+Returns the text string for a particular XML node.  Returns a string,
+or undef if the node doesn't exist.
+
+=head2 setNodeText($path, $text)
+
+Sets the text string for a particular XML node.  The node can be an
+element or an attribute.  If the node to be set is an attribute, and
+the attribute node does not exist, it will be created automatically.
+
+=head2 createNode($path)
+
+Creates the node matching the path given.  If part of the path given, or
+all of the path do not exist, the necessary nodes will be created
+automatically.
+
+=head2 set_namespace($prefix, $uri)
+
+Sets the namespace prefix mapping to the uri.
+
+Normally in XML::XPath the prefixes in XPath node tests take their
+context from the current node. This means that foo:bar will always
+match an element <foo:bar> regardless of the namespace that the prefix
+foo is mapped to (which might even change within the document, resulting
+in unexpected results). In order to make prefixes in XPath node tests
+actually map to a real URI, you need to enable that via a call
+to the set_namespace method of your XML::XPath object.
+
+=head2 clear_namespaces()
+
+Clears all previously set namespace mappings.
+
+=head2 $XML::XPath::Namespaces
+
+Set this to 0 if you I<don't> want namespace processing to occur. This
+will make everything a little (tiny) bit faster, but you'll suffer for it,
+probably.
+
+=head1 Node Object Model
+
+See L<XML::XPath::Node>, L<XML::XPath::Node::Element>, 
+L<XML::XPath::Node::Text>, L<XML::XPath::Node::Comment>,
+L<XML::XPath::Node::Attribute>, L<XML::XPath::Node::Namespace>,
+and L<XML::XPath::Node::PI>.
+
+=head1 On Garbage Collection
+
+XPath nodes work in a special way that allows circular references, and 
+yet still lets Perl's reference counting garbage collector to clean up
+the nodes after use. This should be totally transparent to the user,
+with one caveat: B<If you free your tree before letting go of a sub-tree,
+consider that playing with fire and you may get burned>. What does this
+mean to the average user? Not much. Provided you don't free (or let go
+out of scope) either the tree you passed to XML::XPath->new, or if you
+didn't pass a tree, and passed a filename or IO-ref, then provided you
+don't let the XML::XPath object go out of scope before you let results
+of find() and its friends go out of scope, then you'll be fine. Even if
+you B<do> let the tree go out of scope before results, you'll probably
+still be fine. The only case where you may get stung is when the last
+part of your path/query is either an ancestor or parent axis. In that
+case the worst that will happen is you'll end up with a circular reference
+that won't get cleared until interpreter destruction time. You can get
+around that by explicitly calling $node->DESTROY on each of your result
+nodes, if you really need to do that.
+
+Mail me direct if that's not clear. Note that it's not doom and gloom. It's
+by no means perfect, but the worst that will happen is a long running process
+could leak memory. Most long running processes will therefore be able to
+explicitly be careful not to free the tree (or XML::XPath object) before
+freeing results. AxKit, an application that uses XML::XPath, does this and
+I didn't have to make any changes to the code - it's already sensible
+programming.
+
+If you I<really> don't want all this to happen, then set the variable
+$XML::XPath::SafeMode, and call $xp->cleanup() on the XML::XPath object
+when you're finished, or $tree->dispose() if you have a tree instead.
+
+=head1 Example
+
+Please see the test files in t/ for examples on how to use XPath.
+
+=head1 Support/Author
+
+This module is copyright 2000 AxKit.com Ltd. This is free
+software, and as such comes with NO WARRANTY. No dates are used in this
+module. You may distribute this module under the terms of either the
+Gnu GPL,  or the Artistic License (the same terms as Perl itself).
+
+For support, please subscribe to the Perl-XML mailing list at the URL 
+http://listserv.activestate.com/mailman/listinfo/perl-xml
+
+Matt Sergeant, matt@sergeant.org
+
+=head1 SEE ALSO
+
+L<XML::XPath::Literal>, L<XML::XPath::Boolean>, L<XML::XPath::Number>,
+L<XML::XPath::XMLParser>, L<XML::XPath::NodeSet>, L<XML::XPath::PerlSAX>,
+L<XML::XPath::Builder>.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Boolean.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Boolean.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Boolean.pm	(revision 10506)
@@ -0,0 +1,73 @@
+# $Id$
+
+package XML::XPath::Boolean;
+use XML::XPath::Number;
+use XML::XPath::Literal;
+use strict;
+
+use overload
+		'""' => \&value,
+		'<=>' => \&cmp;
+
+sub True {
+	my $class = shift;
+	my $val = 1;
+	bless \$val, $class;
+}
+
+sub False {
+	my $class = shift;
+	my $val = 0;
+	bless \$val, $class;
+}
+
+sub value {
+	my $self = shift;
+	$$self;
+}
+
+sub cmp {
+	my $self = shift;
+	my ($other, $swap) = @_;
+	if ($swap) {
+		return $other <=> $$self;
+	}
+	return $$self <=> $other;
+}
+
+sub to_number { XML::XPath::Number->new($_[0]->value); }
+sub to_boolean { $_[0]; }
+sub to_literal { XML::XPath::Literal->new($_[0]->value ? "true" : "false"); }
+
+sub string_value { return $_[0]->to_literal->value; }
+
+1;
+__END__
+
+=head1 NAME
+
+XML::XPath::Boolean - Boolean true/false values
+
+=head1 DESCRIPTION
+
+XML::XPath::Boolean objects implement simple boolean true/false objects.
+
+=head1 API
+
+=head2 XML::XPath::Boolean->True
+
+Creates a new Boolean object with a true value.
+
+=head2 XML::XPath::Boolean->False
+
+Creates a new Boolean object with a false value.
+
+=head2 value()
+
+Returns true or false.
+
+=head2 to_literal()
+
+Returns the string "true" or "false".
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Builder.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Builder.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Builder.pm	(revision 10506)
@@ -0,0 +1,198 @@
+# $Id$
+
+package XML::XPath::Builder;
+
+use strict;
+
+# to get array index constants
+use XML::XPath::Node;
+use XML::XPath::Node::Element;
+use XML::XPath::Node::Attribute;
+use XML::XPath::Node::Namespace;
+use XML::XPath::Node::Text;
+use XML::XPath::Node::PI;
+use XML::XPath::Node::Comment;
+
+use vars qw/$xmlns_ns $xml_ns/;
+
+$xmlns_ns = "http://www.w3.org/2000/xmlns/";
+$xml_ns = "http://www.w3.org/XML/1998/namespace";
+
+sub new {
+    my $class = shift;
+    my $self = ($#_ == 0) ? { %{ (shift) } } : { @_ };
+
+    bless $self, $class;
+}
+
+sub start_document {
+    my $self = shift;
+
+    $self->{IdNames} = {};
+    $self->{InScopeNamespaceStack} = [ { 
+            '_Default' => undef,
+            'xmlns' => $xmlns_ns,
+            'xml' => $xml_ns,
+        } ];
+    
+    $self->{NodeStack} = [ ];
+    
+    my $document = XML::XPath::Node::Element->new();
+    my $newns = XML::XPath::Node::Namespace->new('xml', $xml_ns);
+    $document->appendNamespace($newns);
+    $self->{current} = $self->{DOC_Node} = $document;
+}
+
+sub end_document {
+    my $self = shift;
+    
+    return $self->{DOC_Node};
+}
+
+sub characters {
+    my $self = shift;
+    my $sarg = shift;
+    my $text = $sarg->{Data};
+    
+    my $parent = $self->{current};
+    
+    my $last = $parent->getLastChild;
+    if ($last && $last->isTextNode) {
+        # append to previous text node
+        $last->appendText($text);
+        return;
+    }
+    
+    my $node = XML::XPath::Node::Text->new($text);
+    $parent->appendChild($node, 1);
+}
+
+sub start_element {
+    my $self = shift;
+    my $sarg = shift;
+    my $tag  = $sarg->{'Name'};
+    my $attr = $sarg->{'Attributes'};
+
+    push @{ $self->{InScopeNamespaceStack} },
+         { %{ $self->{InScopeNamespaceStack}[-1] } };
+    $self->_scan_namespaces(@_);
+    
+    my ($prefix, $namespace) = $self->_namespace($tag);
+    
+    my $node = XML::XPath::Node::Element->new($tag, $prefix);
+    
+    foreach my $name (keys %$attr) {
+	my $value = $attr->{$name};
+
+        if ($name =~ /^xmlns(:(.*))?$/) {
+            # namespace node
+            my $prefix = $2 || '#default';
+#            warn "Creating NS node: $prefix = $value\n";
+            my $newns = XML::XPath::Node::Namespace->new($prefix, $value);
+            $node->appendNamespace($newns);
+        }
+        else {
+	    my ($prefix, $namespace) = $self->_namespace($name);
+            undef $namespace unless $prefix;
+
+            my $newattr = XML::XPath::Node::Attribute->new($name, $value, $prefix);
+            $node->appendAttribute($newattr, 1);
+            if (exists($self->{IdNames}{$tag}) && ($self->{IdNames}{$tag} eq $name)) {
+    #            warn "appending Id Element: $val for ", $node->getName, "\n";
+                $self->{DOC_Node}->appendIdElement($value, $node);
+            }
+        }
+    }
+        
+    $self->{current}->appendChild($node, 1);
+    $self->{current} = $node;
+}
+
+sub end_element {
+    my $self = shift;
+    $self->{current} = $self->{current}->getParentNode;
+}
+
+sub processing_instruction {
+    my $self = shift;
+    my $pi = shift;
+    my $node = XML::XPath::Node::PI->new($pi->{Target}, $pi->{Data});
+    $self->{current}->appendChild($node, 1);
+}
+
+sub comment {
+    my $self = shift;
+    my $comment = shift;
+    my $node = XML::XPath::Node::Comment->new($comment->{Data});
+    $self->{current}->appendChild($node, 1);
+}
+
+sub _scan_namespaces {
+    my ($self, %attributes) = @_;
+
+    while (my ($attr_name, $value) = each %attributes) {
+	if ($attr_name eq 'xmlns') {
+	    $self->{InScopeNamespaceStack}[-1]{'_Default'} = $value;
+	} elsif ($attr_name =~ /^xmlns:(.*)$/) {
+	    my $prefix = $1;
+	    $self->{InScopeNamespaceStack}[-1]{$prefix} = $value;
+	}
+    }
+}
+
+sub _namespace {
+    my ($self, $name) = @_;
+
+    my ($prefix, $localname) = split(/:/, $name);
+    if (!defined($localname)) {
+	if ($prefix eq 'xmlns') {
+	    return '', undef;
+	} else {
+	    return '', $self->{InScopeNamespaceStack}[-1]{'_Default'};
+	}
+    } else {
+	return $prefix, $self->{InScopeNamespaceStack}[-1]{$prefix};
+    }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+XML::XPath::Builder - SAX handler for building an XPath tree
+
+=head1 SYNOPSIS
+
+ use AnySAXParser;
+ use XML::XPath::Builder;
+
+ $builder = XML::XPath::Builder->new();
+ $parser = AnySAXParser->new( Handler => $builder );
+
+ $root_node = $parser->parse( Source => [SOURCE] );
+
+=head1 DESCRIPTION
+
+C<XML::XPath::Builder> is a SAX handler for building an XML::XPath
+tree.
+
+C<XML::XPath::Builder> is used by creating a new instance of
+C<XML::XPath::Builder> and providing it as the Handler for a SAX
+parser.  Calling `C<parse()>' on the SAX parser will return the
+root node of the tree built from that parse.
+
+=head1 AUTHOR
+
+Ken MacLeod, <ken@bitsko.slc.ut.us>
+
+=head1 SEE ALSO
+
+perl(1), XML::XPath(3)
+
+PerlSAX.pod in libxml-perl
+
+Extensible Markup Language (XML) <http://www.w3c.org/XML>
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Expr.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Expr.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Expr.pm	(revision 10506)
@@ -0,0 +1,619 @@
+# $Id$
+
+package XML::XPath::Expr;
+use strict;
+
+sub new {
+    my $class = shift;
+    my ($pp) = @_;
+    bless { predicates => [], pp => $pp }, $class;
+}
+
+sub as_string {
+    my $self = shift;
+    local $^W; # Use of uninitialized value! grrr
+    my $string = "(" . $self->{lhs}->as_string;
+    $string .= " " . $self->{op} . " " if defined $self->{op};
+    $string .= $self->{rhs}->as_string if defined $self->{rhs};
+    $string .= ")";
+    foreach my $predicate (@{$self->{predicates}}) {
+        $string .= "[" . $predicate->as_string . "]";
+    }
+    return $string;
+}
+
+sub as_xml {
+    my $self = shift;
+    local $^W; # Use of uninitialized value! grrr
+    my $string;
+    if (defined $self->{op}) {
+        $string .= $self->op_xml();
+    }
+    else {
+        $string .= $self->{lhs}->as_xml();
+    }
+    foreach my $predicate (@{$self->{predicates}}) {
+        $string .= "<Predicate>\n" . $predicate->as_xml() . "</Predicate>\n";
+    }
+    return $string;
+}
+
+sub op_xml {
+    my $self = shift;
+    my $op = $self->{op};
+
+    my $tag;    
+    for ($op) {
+        /^or$/    && do {
+                    $tag = "Or";
+                };
+        /^and$/    && do {
+                    $tag = "And";
+                };
+        /^=$/    && do {
+                    $tag = "Equals";
+                };
+        /^!=$/    && do {
+                    $tag = "NotEquals";
+                };
+        /^<=$/    && do {
+                    $tag = "LessThanOrEquals";
+                };
+        /^>=$/    && do {
+                    $tag = "GreaterThanOrEquals";
+                };
+        /^>$/    && do {
+                    $tag = "GreaterThan";
+                };
+        /^<$/    && do {
+                    $tag = "LessThan";
+                };
+        /^\+$/    && do {
+                    $tag = "Plus";
+                };
+        /^-$/    && do {
+                    $tag = "Minus";
+                };
+        /^div$/    && do {
+                    $tag = "Div";
+                };
+        /^mod$/    && do {
+                    $tag = "Mod";
+                };
+        /^\*$/    && do {
+                    $tag = "Multiply";
+                };
+        /^\|$/    && do {
+                    $tag = "Union";
+                };
+    }
+    
+    return "<$tag>\n" . $self->{lhs}->as_xml() . $self->{rhs}->as_xml() . "</$tag>\n";
+}
+
+sub set_lhs {
+    my $self = shift;
+    $self->{lhs} = $_[0];
+}
+
+sub set_op {
+    my $self = shift;
+    $self->{op} = $_[0];
+}
+
+sub set_rhs {
+    my $self = shift;
+    $self->{rhs} = $_[0];
+}
+
+sub push_predicate {
+    my $self = shift;
+    
+    die "Only 1 predicate allowed on FilterExpr in W3C XPath 1.0"
+            if @{$self->{predicates}};
+    
+    push @{$self->{predicates}}, $_[0];
+}
+
+sub get_lhs { $_[0]->{lhs}; }
+sub get_rhs { $_[0]->{rhs}; }
+sub get_op { $_[0]->{op}; }
+
+sub evaluate {
+    my $self = shift;
+    my $node = shift;
+    
+    # If there's an op, result is result of that op.
+    # If no op, just resolve Expr
+    
+#    warn "Evaluate Expr: ", $self->as_string, "\n";
+    
+    my $results;
+    
+    if ($self->{op}) {
+        die ("No RHS of ", $self->as_string) unless $self->{rhs};
+        $results = $self->op_eval($node);
+    }
+    else {
+        $results = $self->{lhs}->evaluate($node);
+    }
+    
+    if (my @predicates = @{$self->{predicates}}) {
+        if (!$results->isa('XML::XPath::NodeSet')) {
+            die "Can't have predicates execute on object type: " . ref($results);
+        }
+        
+        # filter initial nodeset by each predicate
+        foreach my $predicate (@{$self->{predicates}}) {
+            $results = $self->filter_by_predicate($results, $predicate);
+        }
+    }
+    
+    return $results;
+}
+
+sub op_eval {
+    my $self = shift;
+    my $node = shift;
+    
+    my $op = $self->{op};
+    
+    for ($op) {
+        /^or$/    && do {
+                    return op_or($node, $self->{lhs}, $self->{rhs});
+                };
+        /^and$/    && do {
+                    return op_and($node, $self->{lhs}, $self->{rhs});
+                };
+        /^=$/    && do {
+                    return op_equals($node, $self->{lhs}, $self->{rhs});
+                };
+        /^!=$/    && do {
+                    return op_nequals($node, $self->{lhs}, $self->{rhs});
+                };
+        /^<=$/    && do {
+                    return op_le($node, $self->{lhs}, $self->{rhs});
+                };
+        /^>=$/    && do {
+                    return op_ge($node, $self->{lhs}, $self->{rhs});
+                };
+        /^>$/    && do {
+                    return op_gt($node, $self->{lhs}, $self->{rhs});
+                };
+        /^<$/    && do {
+                    return op_lt($node, $self->{lhs}, $self->{rhs});
+                };
+        /^\+$/    && do {
+                    return op_plus($node, $self->{lhs}, $self->{rhs});
+                };
+        /^-$/    && do {
+                    return op_minus($node, $self->{lhs}, $self->{rhs});
+                };
+        /^div$/    && do {
+                    return op_div($node, $self->{lhs}, $self->{rhs});
+                };
+        /^mod$/    && do {
+                    return op_mod($node, $self->{lhs}, $self->{rhs});
+                };
+        /^\*$/    && do {
+                    return op_mult($node, $self->{lhs}, $self->{rhs});
+                };
+        /^\|$/    && do {
+                    return op_union($node, $self->{lhs}, $self->{rhs});
+                };
+        
+        die "No such operator, or operator unimplemented in ", $self->as_string, "\n";
+    }
+}
+
+# Operators
+
+use XML::XPath::Boolean;
+
+sub op_or {
+    my ($node, $lhs, $rhs) = @_;
+    if($lhs->evaluate($node)->to_boolean->value) {
+        return XML::XPath::Boolean->True;
+    }
+    else {
+        return $rhs->evaluate($node)->to_boolean;
+    }
+}
+
+sub op_and {
+    my ($node, $lhs, $rhs) = @_;
+    if( ! $lhs->evaluate($node)->to_boolean->value ) {
+        return XML::XPath::Boolean->False;
+    }
+    else {
+        return $rhs->evaluate($node)->to_boolean;
+    }
+}
+
+sub op_equals {
+    my ($node, $lhs, $rhs) = @_;
+
+    my $lh_results = $lhs->evaluate($node);
+    my $rh_results = $rhs->evaluate($node);
+    
+    if ($lh_results->isa('XML::XPath::NodeSet') &&
+            $rh_results->isa('XML::XPath::NodeSet')) {
+        # True if and only if there is a node in the
+        # first set and a node in the second set such
+        # that the result of performing the comparison
+        # on the string-values of the two nodes is true.
+        foreach my $lhnode ($lh_results->get_nodelist) {
+            foreach my $rhnode ($rh_results->get_nodelist) {
+                if ($lhnode->string_value eq $rhnode->string_value) {
+                    return XML::XPath::Boolean->True;
+                }
+            }
+        }
+        return XML::XPath::Boolean->False;
+    }
+    elsif (($lh_results->isa('XML::XPath::NodeSet') ||
+            $rh_results->isa('XML::XPath::NodeSet')) &&
+            (!$lh_results->isa('XML::XPath::NodeSet') ||
+             !$rh_results->isa('XML::XPath::NodeSet'))) {
+        # (that says: one is a nodeset, and one is not a nodeset)
+        
+        my ($nodeset, $other);
+        if ($lh_results->isa('XML::XPath::NodeSet')) {
+            $nodeset = $lh_results;
+            $other = $rh_results;
+        }
+        else {
+            $nodeset = $rh_results;
+            $other = $lh_results;
+        }
+        
+        # True if and only if there is a node in the
+        # nodeset such that the result of performing
+        # the comparison on <type>(string_value($node))
+        # is true.
+        if ($other->isa('XML::XPath::Number')) {
+            foreach my $node ($nodeset->get_nodelist) {
+                if ($node->string_value == $other->value) {
+                    return XML::XPath::Boolean->True;
+                }
+            }
+        }
+        elsif ($other->isa('XML::XPath::Literal')) {
+            foreach my $node ($nodeset->get_nodelist) {
+                if ($node->string_value eq $other->value) {
+                    return XML::XPath::Boolean->True;
+                }
+            }
+        }
+        elsif ($other->isa('XML::XPath::Boolean')) {
+            if ($nodeset->to_boolean->value == $other->value) {
+                return XML::XPath::Boolean->True;
+            }
+        }
+
+        return XML::XPath::Boolean->False;
+    }
+    else { # Neither is a nodeset
+        if ($lh_results->isa('XML::XPath::Boolean') ||
+            $rh_results->isa('XML::XPath::Boolean')) {
+            # if either is a boolean
+            if ($lh_results->to_boolean->value == $rh_results->to_boolean->value) {
+                return XML::XPath::Boolean->True;
+            }
+            return XML::XPath::Boolean->False;
+        }
+        elsif ($lh_results->isa('XML::XPath::Number') ||
+                $rh_results->isa('XML::XPath::Number')) {
+            # if either is a number
+            local $^W; # 'number' might result in undef
+            if ($lh_results->to_number->value == $rh_results->to_number->value) {
+                return XML::XPath::Boolean->True;
+            }
+            return XML::XPath::Boolean->False;
+        }
+        else {
+            if ($lh_results->to_literal->value eq $rh_results->to_literal->value) {
+                return XML::XPath::Boolean->True;
+            }
+            return XML::XPath::Boolean->False;
+        }
+    }
+}
+
+sub op_nequals {
+    my ($node, $lhs, $rhs) = @_;
+    if (op_equals($node, $lhs, $rhs)->value) {
+        return XML::XPath::Boolean->False;
+    }
+    return XML::XPath::Boolean->True;
+}
+
+sub op_le {
+    my ($node, $lhs, $rhs) = @_;
+    op_gt($node, $rhs, $lhs);
+}
+
+sub op_ge {
+    my ($node, $lhs, $rhs) = @_;
+
+    my $lh_results = $lhs->evaluate($node);
+    my $rh_results = $rhs->evaluate($node);
+    
+    if ($lh_results->isa('XML::XPath::NodeSet') &&
+        $rh_results->isa('XML::XPath::NodeSet')) {
+
+        foreach my $lhnode ($lh_results->get_nodelist) {
+            foreach my $rhnode ($rh_results->get_nodelist) {
+                my $lhNum = XML::XPath::Number->new($lhnode->string_value);
+                my $rhNum = XML::XPath::Number->new($rhnode->string_value);
+                if ($lhNum->value >= $rhNum->value) {
+                    return XML::XPath::Boolean->True;
+                }
+            }
+        }
+        return XML::XPath::Boolean->False;
+    }
+    elsif (($lh_results->isa('XML::XPath::NodeSet') ||
+            $rh_results->isa('XML::XPath::NodeSet')) &&
+            (!$lh_results->isa('XML::XPath::NodeSet') ||
+             !$rh_results->isa('XML::XPath::NodeSet'))) {
+        # (that says: one is a nodeset, and one is not a nodeset)
+
+        my ($nodeset, $other);
+        my ($true, $false);
+        if ($lh_results->isa('XML::XPath::NodeSet')) {
+            $nodeset = $lh_results;
+            $other = $rh_results;
+            # we do this because unlike ==, these ops are direction dependant
+            ($false, $true) = (XML::XPath::Boolean->False, XML::XPath::Boolean->True);
+        }
+        else {
+            $nodeset = $rh_results;
+            $other = $lh_results;
+            # ditto above comment
+            ($true, $false) = (XML::XPath::Boolean->False, XML::XPath::Boolean->True);
+        }
+        
+        # True if and only if there is a node in the
+        # nodeset such that the result of performing
+        # the comparison on <type>(string_value($node))
+        # is true.
+        foreach my $node ($nodeset->get_nodelist) {
+            if ($node->to_number->value >= $other->to_number->value) {
+                return $true;
+            }
+        }
+        return $false;
+    }
+    else { # Neither is a nodeset
+        if ($lh_results->isa('XML::XPath::Boolean') ||
+            $rh_results->isa('XML::XPath::Boolean')) {
+            # if either is a boolean
+            if ($lh_results->to_boolean->to_number->value
+                    >= $rh_results->to_boolean->to_number->value) {
+                return XML::XPath::Boolean->True;
+            }
+        }
+        else {
+            if ($lh_results->to_number->value >= $rh_results->to_number->value) {
+                return XML::XPath::Boolean->True;
+            }
+        }
+        return XML::XPath::Boolean->False;
+    }
+}
+
+sub op_gt {
+    my ($node, $lhs, $rhs) = @_;
+
+    my $lh_results = $lhs->evaluate($node);
+    my $rh_results = $rhs->evaluate($node);
+    
+    if ($lh_results->isa('XML::XPath::NodeSet') &&
+        $rh_results->isa('XML::XPath::NodeSet')) {
+
+        foreach my $lhnode ($lh_results->get_nodelist) {
+            foreach my $rhnode ($rh_results->get_nodelist) {
+                my $lhNum = XML::XPath::Number->new($lhnode->string_value);
+                my $rhNum = XML::XPath::Number->new($rhnode->string_value);
+                if ($lhNum->value > $rhNum->value) {
+                    return XML::XPath::Boolean->True;
+                }
+            }
+        }
+        return XML::XPath::Boolean->False;
+    }
+    elsif (($lh_results->isa('XML::XPath::NodeSet') ||
+            $rh_results->isa('XML::XPath::NodeSet')) &&
+            (!$lh_results->isa('XML::XPath::NodeSet') ||
+             !$rh_results->isa('XML::XPath::NodeSet'))) {
+        # (that says: one is a nodeset, and one is not a nodeset)
+
+        my ($nodeset, $other);
+        my ($true, $false);
+        if ($lh_results->isa('XML::XPath::NodeSet')) {
+            $nodeset = $lh_results;
+            $other = $rh_results;
+            # we do this because unlike ==, these ops are direction dependant
+            ($false, $true) = (XML::XPath::Boolean->False, XML::XPath::Boolean->True);
+        }
+        else {
+            $nodeset = $rh_results;
+            $other = $lh_results;
+            # ditto above comment
+            ($true, $false) = (XML::XPath::Boolean->False, XML::XPath::Boolean->True);
+        }
+        
+        # True if and only if there is a node in the
+        # nodeset such that the result of performing
+        # the comparison on <type>(string_value($node))
+        # is true.
+        foreach my $node ($nodeset->get_nodelist) {
+            if ($node->to_number->value > $other->to_number->value) {
+                return $true;
+            }
+        }
+        return $false;
+    }
+    else { # Neither is a nodeset
+        if ($lh_results->isa('XML::XPath::Boolean') ||
+            $rh_results->isa('XML::XPath::Boolean')) {
+            # if either is a boolean
+            if ($lh_results->to_boolean->value > $rh_results->to_boolean->value) {
+                return XML::XPath::Boolean->True;
+            }
+        }
+        else {
+            if ($lh_results->to_number->value > $rh_results->to_number->value) {
+                return XML::XPath::Boolean->True;
+            }
+        }
+        return XML::XPath::Boolean->False;
+    }
+}
+
+sub op_lt {
+    my ($node, $lhs, $rhs) = @_;
+    op_gt($node, $rhs, $lhs);
+}
+
+sub op_plus {
+    my ($node, $lhs, $rhs) = @_;
+    my $lh_results = $lhs->evaluate($node);
+    my $rh_results = $rhs->evaluate($node);
+    
+    my $result =
+        $lh_results->to_number->value
+            +
+        $rh_results->to_number->value
+            ;
+    return XML::XPath::Number->new($result);
+}
+
+sub op_minus {
+    my ($node, $lhs, $rhs) = @_;
+    my $lh_results = $lhs->evaluate($node);
+    my $rh_results = $rhs->evaluate($node);
+    
+    my $result =
+        $lh_results->to_number->value
+            -
+        $rh_results->to_number->value
+            ;
+    return XML::XPath::Number->new($result);
+}
+
+sub op_div {
+    my ($node, $lhs, $rhs) = @_;
+    my $lh_results = $lhs->evaluate($node);
+    my $rh_results = $rhs->evaluate($node);
+
+    my $result = eval {
+        $lh_results->to_number->value
+            /
+        $rh_results->to_number->value
+            ;
+    };
+    if ($@) {
+        # assume divide by zero
+        # This is probably a terrible way to handle this! 
+        # Ah well... who wants to live forever...
+        return XML::XPath::Literal->new('Infinity');
+    }
+    return XML::XPath::Number->new($result);
+}
+
+sub op_mod {
+    my ($node, $lhs, $rhs) = @_;
+    my $lh_results = $lhs->evaluate($node);
+    my $rh_results = $rhs->evaluate($node);
+    
+    my $result =
+        $lh_results->to_number->value
+            %
+        $rh_results->to_number->value
+            ;
+    return XML::XPath::Number->new($result);
+}
+
+sub op_mult {
+    my ($node, $lhs, $rhs) = @_;
+    my $lh_results = $lhs->evaluate($node);
+    my $rh_results = $rhs->evaluate($node);
+    
+    my $result =
+        $lh_results->to_number->value
+            *
+        $rh_results->to_number->value
+            ;
+    return XML::XPath::Number->new($result);
+}
+
+sub op_union {
+    my ($node, $lhs, $rhs) = @_;
+    my $lh_result = $lhs->evaluate($node);
+    my $rh_result = $rhs->evaluate($node);
+    
+    if ($lh_result->isa('XML::XPath::NodeSet') &&
+            $rh_result->isa('XML::XPath::NodeSet')) {
+        my %found;
+        my $results = XML::XPath::NodeSet->new;
+        foreach my $lhnode ($lh_result->get_nodelist) {
+            $found{"$lhnode"}++;
+            $results->push($lhnode);
+        }
+        foreach my $rhnode ($rh_result->get_nodelist) {
+            $results->push($rhnode)
+                    unless exists $found{"$rhnode"};
+        }
+                $results->sort;
+        return $results;
+    }
+    die "Both sides of a union must be Node Sets\n";
+}
+
+sub filter_by_predicate {
+    my $self = shift;
+    my ($nodeset, $predicate) = @_;
+    
+    # See spec section 2.4, paragraphs 2 & 3:
+    # For each node in the node-set to be filtered, the predicate Expr
+    # is evaluated with that node as the context node, with the number
+    # of nodes in the node set as the context size, and with the
+    # proximity position of the node in the node set with respect to
+    # the axis as the context position.
+    
+    if (!ref($nodeset)) { # use ref because nodeset has a bool context
+        die "No nodeset!!!";
+    }
+    
+#    warn "Filter by predicate: $predicate\n";
+    
+    my $newset = XML::XPath::NodeSet->new();
+    
+    for(my $i = 1; $i <= $nodeset->size; $i++) {
+        # set context set each time 'cos a loc-path in the expr could change it
+        $self->{pp}->set_context_set($nodeset);
+        $self->{pp}->set_context_pos($i);
+        my $result = $predicate->evaluate($nodeset->get_node($i));
+        if ($result->isa('XML::XPath::Boolean')) {
+            if ($result->value) {
+                $newset->push($nodeset->get_node($i));
+            }
+        }
+        elsif ($result->isa('XML::XPath::Number')) {
+            if ($result->value == $i) {
+                $newset->push($nodeset->get_node($i));
+            }
+        }
+        else {
+            if ($result->to_boolean->value) {
+                $newset->push($nodeset->get_node($i));
+            }
+        }
+    }
+    
+    return $newset;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Function.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Function.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Function.pm	(revision 10506)
@@ -0,0 +1,392 @@
+# $Id$
+
+package XML::XPath::Function;
+use XML::XPath::Number;
+use XML::XPath::Literal;
+use XML::XPath::Boolean;
+use XML::XPath::NodeSet;
+use XML::XPath::Node::Attribute;
+use strict;
+
+sub new {
+    my $class = shift;
+    my ($pp, $name, $params) = @_;
+    bless { 
+        pp => $pp, 
+        name => $name, 
+        params => $params 
+        }, $class;
+}
+
+sub as_string {
+    my $self = shift;
+    my $string = $self->{name} . "(";
+    my $second;
+    foreach (@{$self->{params}}) {
+        $string .= "," if $second++;
+        $string .= $_->as_string;
+    }
+    $string .= ")";
+    return $string;
+}
+
+sub as_xml {
+    my $self = shift;
+    my $string = "<Function name=\"$self->{name}\"";
+    my $params = "";
+    foreach (@{$self->{params}}) {
+        $params .= "<Param>" . $_->as_string . "</Param>\n";
+    }
+    if ($params) {
+        $string .= ">\n$params</Function>\n";
+    }
+    else {
+        $string .= " />\n";
+    }
+    
+    return $string;
+}
+
+sub evaluate {
+    my $self = shift;
+    my $node = shift;
+    if ($node->isa('XML::XPath::NodeSet')) {
+        $node = $node->get_node(1);
+    }
+    my @params;
+    foreach my $param (@{$self->{params}}) {
+        my $results = $param->evaluate($node);
+        push @params, $results;
+    }
+    $self->_execute($self->{name}, $node, @params);
+}
+
+sub _execute {
+    my $self = shift;
+    my ($name, $node, @params) = @_;
+    $name =~ s/-/_/g;
+    no strict 'refs';
+    $self->$name($node, @params);
+}
+
+# All functions should return one of:
+# XML::XPath::Number
+# XML::XPath::Literal (string)
+# XML::XPath::NodeSet
+# XML::XPath::Boolean
+
+### NODESET FUNCTIONS ###
+
+sub last {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "last: function doesn't take parameters\n" if (@params);
+    return XML::XPath::Number->new($self->{pp}->get_context_size);
+}
+
+sub position {
+    my $self = shift;
+    my ($node, @params) = @_;
+    if (@params) {
+        die "position: function doesn't take parameters [ ", @params, " ]\n";
+    }
+    # return pos relative to axis direction
+    return XML::XPath::Number->new($self->{pp}->get_context_pos);
+}
+
+sub count {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "count: Parameter must be a NodeSet\n" unless $params[0]->isa('XML::XPath::NodeSet');
+    return XML::XPath::Number->new($params[0]->size);
+}
+
+sub id {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "id: Function takes 1 parameter\n" unless @params == 1;
+    my $results = XML::XPath::NodeSet->new();
+    if ($params[0]->isa('XML::XPath::NodeSet')) {
+        # result is the union of applying id() to the
+        # string value of each node in the nodeset.
+        foreach my $node ($params[0]->get_nodelist) {
+            my $string = $node->string_value;
+            $results->append($self->id($node, XML::XPath::Literal->new($string)));
+        }
+    }
+    else { # The actual id() function...
+        my $string = $self->string($node, $params[0]);
+        $_ = $string->value; # get perl scalar
+        my @ids = split; # splits $_
+        foreach my $id (@ids) {
+            if (my $found = $node->getElementById($id)) {
+                $results->push($found);
+            }
+        }
+    }
+    return $results;
+}
+
+sub local_name {
+    my $self = shift;
+    my ($node, @params) = @_;
+    if (@params > 1) {
+        die "name() function takes one or no parameters\n";
+    }
+    elsif (@params) {
+        my $nodeset = shift(@params);
+        $node = $nodeset->get_node(1);
+    }
+    
+    return XML::XPath::Literal->new($node->getLocalName);
+}
+
+sub namespace_uri {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "namespace-uri: Function not supported\n";
+}
+
+sub name {
+    my $self = shift;
+    my ($node, @params) = @_;
+    if (@params > 1) {
+        die "name() function takes one or no parameters\n";
+    }
+    elsif (@params) {
+        my $nodeset = shift(@params);
+        $node = $nodeset->get_node(1);
+    }
+    
+    return XML::XPath::Literal->new($node->getName);
+}
+
+### STRING FUNCTIONS ###
+
+sub string {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "string: Too many parameters\n" if @params > 1;
+    if (@params) {
+        return XML::XPath::Literal->new($params[0]->string_value);
+    }
+    
+    # TODO - this MUST be wrong! - not sure now. -matt
+    return XML::XPath::Literal->new($node->string_value);
+    # default to nodeset with just $node in.
+}
+
+sub concat {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "concat: Too few parameters\n" if @params < 2;
+    my $string = join('', map {$_->string_value} @params);
+    return XML::XPath::Literal->new($string);
+}
+
+sub starts_with {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "starts-with: incorrect number of params\n" unless @params == 2;
+    my ($string1, $string2) = ($params[0]->string_value, $params[1]->string_value);
+    if (substr($string1, 0, length($string2)) eq $string2) {
+        return XML::XPath::Boolean->True;
+    }
+    return XML::XPath::Boolean->False;
+}
+
+sub contains {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "starts-with: incorrect number of params\n" unless @params == 2;
+    my $value = $params[1]->string_value;
+    if ($params[0]->string_value =~ /(.*?)\Q$value\E(.*)/) {
+        # $1 and $2 stored for substring funcs below
+        # TODO: Fix this nasty implementation!
+        return XML::XPath::Boolean->True;
+    }
+    return XML::XPath::Boolean->False;
+}
+
+sub substring_before {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "starts-with: incorrect number of params\n" unless @params == 2;
+    if ($self->contains($node, @params)->value) {
+        return XML::XPath::Literal->new($1); # hope that works!
+    }
+    else {
+        return XML::XPath::Literal->new('');
+    }
+}
+
+sub substring_after {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "starts-with: incorrect number of params\n" unless @params == 2;
+    if ($self->contains($node, @params)->value) {
+        return XML::XPath::Literal->new($2);
+    }
+    else {
+        return XML::XPath::Literal->new('');
+    }
+}
+
+sub substring {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "substring: Wrong number of parameters\n" if (@params < 2 || @params > 3);
+    my ($str, $offset, $len);
+    $str = $params[0]->string_value;
+    $offset = $params[1]->value;
+    $offset--; # uses 1 based offsets
+    if (@params == 3) {
+        $len = $params[2]->value;
+    }
+    return XML::XPath::Literal->new(substr($str, $offset, $len));
+}
+
+sub string_length {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "string-length: Wrong number of params\n" if @params > 1;
+    if (@params) {
+        return XML::XPath::Number->new(length($params[0]->string_value));
+    }
+    else {
+        return XML::XPath::Number->new(
+                length($node->string_value)
+                );
+    }
+}
+
+sub normalize_space {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "normalize-space: Wrong number of params\n" if @params > 1;
+    my $str;
+    if (@params) {
+        $str = $params[0]->string_value;
+    }
+    else {
+        $str = $node->string_value;
+    }
+    $str =~ s/^\s*//;
+    $str =~ s/\s*$//;
+    $str =~ s/\s+/ /g;
+    return XML::XPath::Literal->new($str);
+}
+
+sub translate {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "translate: Wrong number of params\n" if @params != 3;
+    local $_ = $params[0]->string_value;
+    my $find = $params[1]->string_value;
+    my $repl = $params[2]->string_value;
+    eval "tr/\\Q$find\\E/\\Q$repl\\E/d, 1" or die $@;
+    return XML::XPath::Literal->new($_);
+}
+
+### BOOLEAN FUNCTIONS ###
+
+sub boolean {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "boolean: Incorrect number of parameters\n" if @params != 1;
+    return $params[0]->to_boolean;
+}
+
+sub not {
+    my $self = shift;
+    my ($node, @params) = @_;
+    $params[0] = $params[0]->to_boolean unless $params[0]->isa('XML::XPath::Boolean');
+    $params[0]->value ? XML::XPath::Boolean->False : XML::XPath::Boolean->True;
+}
+
+sub true {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "true: function takes no parameters\n" if @params > 0;
+    XML::XPath::Boolean->True;
+}
+
+sub false {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "true: function takes no parameters\n" if @params > 0;
+    XML::XPath::Boolean->False;
+}
+
+sub lang {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "lang: function takes 1 parameter\n" if @params != 1;
+    my $lang = $node->findvalue('(ancestor-or-self::*[@xml:lang]/@xml:lang)[last()]');
+    my $lclang = lc($params[0]->string_value);
+    # warn("Looking for lang($lclang) in $lang\n");
+    if (substr(lc($lang), 0, length($lclang)) eq $lclang) {
+        return XML::XPath::Boolean->True;
+    }
+    else {
+        return XML::XPath::Boolean->False;
+    }
+}
+
+### NUMBER FUNCTIONS ###
+
+sub number {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "number: Too many parameters\n" if @params > 1;
+    if (@params) {
+        if ($params[0]->isa('XML::XPath::Node')) {
+            return XML::XPath::Number->new(
+                    $params[0]->string_value
+                    );
+        }
+        return $params[0]->to_number;
+    }
+    
+    return XML::XPath::Number->new( $node->string_value );
+}
+
+sub sum {
+    my $self = shift;
+    my ($node, @params) = @_;
+    die "sum: Parameter must be a NodeSet\n" unless $params[0]->isa('XML::XPath::NodeSet');
+    my $sum = 0;
+    foreach my $node ($params[0]->get_nodelist) {
+        $sum += $self->number($node)->value;
+    }
+    return XML::XPath::Number->new($sum);
+}
+
+sub floor {
+    my $self = shift;
+    my ($node, @params) = @_;
+    require POSIX;
+    my $num = $self->number($node, @params);
+    return XML::XPath::Number->new(
+            POSIX::floor($num->value));
+}
+
+sub ceiling {
+    my $self = shift;
+    my ($node, @params) = @_;
+    require POSIX;
+    my $num = $self->number($node, @params);
+    return XML::XPath::Number->new(
+            POSIX::ceil($num->value));
+}
+
+sub round {
+    my $self = shift;
+    my ($node, @params) = @_;
+    my $num = $self->number($node, @params);
+    require POSIX;
+    return XML::XPath::Number->new(
+            POSIX::floor($num->value + 0.5)); # Yes, I know the spec says don't do this...
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Literal.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Literal.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Literal.pm	(revision 10506)
@@ -0,0 +1,99 @@
+# $Id$
+
+package XML::XPath::Literal;
+use XML::XPath::Boolean;
+use XML::XPath::Number;
+use strict;
+
+use overload 
+		'""' => \&value,
+		'cmp' => \&cmp;
+
+sub new {
+	my $class = shift;
+	my ($string) = @_;
+	
+#	$string =~ s/&quot;/"/g;
+#	$string =~ s/&apos;/'/g;
+	
+	bless \$string, $class;
+}
+
+sub as_string {
+	my $self = shift;
+	my $string = $$self;
+	$string =~ s/'/&apos;/g;
+	return "'$string'";
+}
+
+sub as_xml {
+    my $self = shift;
+    my $string = $$self;
+    return "<Literal>$string</Literal>\n";
+}
+
+sub value {
+	my $self = shift;
+	$$self;
+}
+
+sub cmp {
+	my $self = shift;
+	my ($cmp, $swap) = @_;
+	if ($swap) {
+		return $cmp cmp $$self;
+	}
+	return $$self cmp $cmp;
+}
+
+sub evaluate {
+	my $self = shift;
+	$self;
+}
+
+sub to_boolean {
+	my $self = shift;
+	return (length($$self) > 0) ? XML::XPath::Boolean->True : XML::XPath::Boolean->False;
+}
+
+sub to_number { return XML::XPath::Number->new($_[0]->value); }
+sub to_literal { return $_[0]; }
+
+sub string_value { return $_[0]->value; }
+
+1;
+__END__
+
+=head1 NAME
+
+XML::XPath::Literal - Simple string values.
+
+=head1 DESCRIPTION
+
+In XPath terms a Literal is what we know as a string.
+
+=head1 API
+
+=head2 new($string)
+
+Create a new Literal object with the value in $string. Note that &quot; and
+&apos; will be converted to " and ' respectively. That is not part of the XPath
+specification, but I consider it useful. Note though that you have to go
+to extraordinary lengths in an XML template file (be it XSLT or whatever) to
+make use of this:
+
+	<xsl:value-of select="&quot;I'm feeling &amp;quot;sad&amp;quot;&quot;"/>
+
+Which produces a Literal of:
+
+	I'm feeling "sad"
+
+=head2 value()
+
+Also overloaded as stringification, simply returns the literal string value.
+
+=head2 cmp($literal)
+
+Returns the equivalent of perl's cmp operator against the given $literal.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/LocationPath.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/LocationPath.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/LocationPath.pm	(revision 10506)
@@ -0,0 +1,61 @@
+# $Id$
+
+package XML::XPath::LocationPath;
+use XML::XPath::Root;
+use strict;
+
+sub new {
+	my $class = shift;
+	my $self = [];
+	bless $self, $class;
+}
+
+sub as_string {
+	my $self = shift;
+	my $string;
+	for (my $i = 0; $i < @$self; $i++) {
+		$string .= $self->[$i]->as_string;
+		$string .= "/" if $self->[$i+1];
+	}
+	return $string;
+}
+
+sub as_xml {
+    my $self = shift;
+    my $string = "<LocationPath>\n";
+    
+    for (my $i = 0; $i < @$self; $i++) {
+        $string .= $self->[$i]->as_xml;
+    }
+    
+    $string .= "</LocationPath>\n";
+    return $string;
+}
+
+sub set_root {
+	my $self = shift;
+	unshift @$self, XML::XPath::Root->new();
+}
+
+sub evaluate {
+	my $self = shift;
+	# context _MUST_ be a single node
+	my $context = shift;
+	die "No context" unless $context;
+	
+	# I _think_ this is how it should work :)
+	
+	my $nodeset = XML::XPath::NodeSet->new();
+	$nodeset->push($context);
+	
+	foreach my $step (@$self) {
+		# For each step
+		# evaluate the step with the nodeset
+		my $pos = 1;
+		$nodeset = $step->evaluate($nodeset);
+	}
+	
+	return $nodeset;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node.pm	(revision 10506)
@@ -0,0 +1,592 @@
+# $Id$
+
+package XML::XPath::Node;
+
+use strict;
+use vars qw(@ISA @EXPORT $AUTOLOAD %EXPORT_TAGS @EXPORT_OK);
+use Exporter;
+use Carp;
+@ISA = ('Exporter');
+
+sub UNKNOWN_NODE () {0;}
+sub ELEMENT_NODE () {1;}
+sub ATTRIBUTE_NODE () {2;}
+sub TEXT_NODE () {3;}
+sub CDATA_SECTION_NODE () {4;}
+sub ENTITY_REFERENCE_NODE () {5;}
+sub ENTITY_NODE () {6;}
+sub PROCESSING_INSTRUCTION_NODE () {7;}
+sub COMMENT_NODE () {8;}
+sub DOCUMENT_NODE () {9;}
+sub DOCUMENT_TYPE_NODE () {10;}
+sub DOCUMENT_FRAGMENT_NODE () {11;}
+sub NOTATION_NODE () {12;}
+
+# Non core DOM stuff
+sub ELEMENT_DECL_NODE () {13;}
+sub ATT_DEF_NODE () {14;}
+sub XML_DECL_NODE () {15;}
+sub ATTLIST_DECL_NODE () {16;}
+sub NAMESPACE_NODE () {17;}
+
+# per-node constants
+
+# All
+sub node_parent () { 0; }
+sub node_pos () { 1; }
+sub node_global_pos () { 2; }
+
+# Element
+sub node_prefix () { 3; }
+sub node_children () { 4; }
+sub node_name () { 5; }
+sub node_attribs () { 6; }
+sub node_namespaces () { 7; }
+sub node_ids () { 8; }
+
+# Char
+sub node_text () { 3; }
+
+# PI
+sub node_target () { 3; }
+sub node_data () { 4; }
+
+# Comment
+sub node_comment () { 3; }
+
+# Attribute
+# sub node_prefix () { 3; }
+sub node_key () { 4; }
+sub node_value () { 5; }
+
+# Namespaces
+# sub node_prefix () { 3; }
+sub node_expanded () { 4; }
+
+@EXPORT = qw(
+    UNKNOWN_NODE
+    ELEMENT_NODE
+    ATTRIBUTE_NODE
+    TEXT_NODE
+    CDATA_SECTION_NODE
+    ENTITY_REFERENCE_NODE
+    ENTITY_NODE
+    PROCESSING_INSTRUCTION_NODE
+    COMMENT_NODE
+    DOCUMENT_NODE
+    DOCUMENT_TYPE_NODE
+    DOCUMENT_FRAGMENT_NODE
+    NOTATION_NODE
+    ELEMENT_DECL_NODE
+    ATT_DEF_NODE
+    XML_DECL_NODE
+    ATTLIST_DECL_NODE
+    NAMESPACE_NODE
+    );
+
+@EXPORT_OK = qw(
+            node_parent
+            node_pos
+            node_global_pos
+            node_prefix
+            node_children
+            node_name
+            node_attribs
+            node_namespaces
+            node_text
+            node_target
+            node_data
+            node_comment
+            node_key
+            node_value
+            node_expanded
+                        node_ids
+        );
+
+%EXPORT_TAGS = (
+    'node_keys' => [
+        qw(
+            node_parent
+            node_pos
+            node_global_pos
+            node_prefix
+            node_children
+            node_name
+            node_attribs
+            node_namespaces
+            node_text
+            node_target
+            node_data
+            node_comment
+            node_key
+            node_value
+            node_expanded
+                        node_ids
+        ), @EXPORT,
+    ],
+);
+
+
+my $global_pos = 0;
+
+sub nextPos {
+    my $class = shift;
+    return $global_pos += 5;
+}
+
+sub resetPos {
+    $global_pos = 0;
+}
+
+my %DecodeDefaultEntity =
+(
+ '"' => "&quot;",
+ ">" => "&gt;",
+ "<" => "&lt;",
+ "'" => "&apos;",
+ "&" => "&amp;"
+);
+
+sub XMLescape {
+    my ($str, $default) = @_;
+    return undef unless defined $str;
+    $default ||= '';
+    
+    if ($XML::XPath::EncodeUtf8AsEntity) {
+        $str =~ s/([\xC0-\xDF].|[\xE0-\xEF]..|[\xF0-\xFF]...)|([$default])|(]]>)/
+        defined($1) ? XmlUtf8Decode ($1) : 
+        defined ($2) ? $DecodeDefaultEntity{$2} : "]]&gt;" /egsx;
+    }
+    else {
+        $str =~ s/([$default])|(]]>)/
+        defined ($1) ? $DecodeDefaultEntity{$1} : ']]&gt;' /gsex;
+    }
+
+#?? could there be references that should not be expanded?
+# e.g. should not replace &#nn; &#xAF; and &abc;
+#    $str =~ s/&(?!($ReName|#[0-9]+|#x[0-9a-fA-F]+);)/&amp;/go;
+
+    $str;
+}
+
+#
+# Opposite of XmlUtf8Decode plus it adds prefix "&#" or "&#x" and suffix ";"
+# The 2nd parameter ($hex) indicates whether the result is hex encoded or not.
+#
+sub XmlUtf8Decode
+{
+    my ($str, $hex) = @_;
+    my $len = length ($str);
+    my $n;
+
+    if ($len == 2) {
+        my @n = unpack "C2", $str;
+        $n = (($n[0] & 0x3f) << 6) + ($n[1] & 0x3f);
+    }
+    elsif ($len == 3) {
+        my @n = unpack "C3", $str;
+        $n = (($n[0] & 0x1f) << 12) + (($n[1] & 0x3f) << 6) + 
+            ($n[2] & 0x3f);
+    }
+    elsif ($len == 4) {
+        my @n = unpack "C4", $str;
+        $n = (($n[0] & 0x0f) << 18) + (($n[1] & 0x3f) << 12) + 
+            (($n[2] & 0x3f) << 6) + ($n[3] & 0x3f);
+    }
+    elsif ($len == 1) {    # just to be complete...
+        $n = ord ($str);
+    }
+    else {
+        die "bad value [$str] for XmlUtf8Decode";
+    }
+    $hex ? sprintf ("&#x%x;", $n) : "&#$n;";
+}
+
+sub new {
+    my $class = shift;
+    no strict 'refs';
+    my $impl = $class . "Impl";
+    my $this = $impl->new(@_);
+    if ($XML::XPath::SafeMode) {
+        return $this;
+    }
+    my $self = \$this;
+    return bless $self, $class;
+}
+
+sub AUTOLOAD {
+    my $method = $AUTOLOAD;
+    $method =~ s/.*:://;
+#    warn "AUTOLOAD $method!\n";
+    no strict 'refs';
+    *{$AUTOLOAD} = sub { 
+        my $self = shift;
+        my $olderror = $@; # store previous exceptions
+        my $obj = eval { $$self };
+        if ($@) {
+            if ($@ =~ /Not a SCALAR reference/) {
+                croak("No such method $method in " . ref($self));
+            }
+            croak $@;
+        }
+        if ($obj) {
+            # make sure $@ propogates if this method call was the result
+            # of losing scope because of a die().
+            if ($method =~ /^(DESTROY|del_parent_link)$/) {
+                $obj->$method(@_);
+                $@ = $olderror if $olderror;
+                return;
+            }
+            return $obj->$method(@_);
+        }
+    };
+    goto &$AUTOLOAD;
+}
+
+package XML::XPath::NodeImpl;
+
+use vars qw/@ISA $AUTOLOAD/;
+@ISA = ('XML::XPath::Node');
+
+sub new {
+    die "Virtual base method";
+}
+
+sub getNodeType {
+    my $self = shift;
+    return XML::XPath::Node::UNKNOWN_NODE;
+}
+
+sub isElementNode {}
+sub isAttributeNode {}
+sub isNamespaceNode {}
+sub isTextNode {}
+sub isProcessingInstructionNode {}
+sub isPINode {}
+sub isCommentNode {}
+
+sub getNodeValue {
+    return;
+}
+
+sub getValue {
+    shift->getNodeValue(@_);
+}
+
+sub setNodeValue {
+    return;
+}
+
+sub setValue {
+    shift->setNodeValue(@_);
+}
+
+sub getParentNode {
+    my $self = shift;
+    return $self->[XML::XPath::Node::node_parent];
+}
+
+sub getRootNode {
+    my $self = shift;
+    while (my $parent = $self->getParentNode) {
+        $self = $parent;
+    }
+    return $self;
+}
+
+sub getElementById {
+    my $self = shift;
+    my ($id) = @_;
+#    warn "getElementById: $id\n";
+    my $root = $self->getRootNode;
+    my $node = $root->[XML::XPath::Node::node_ids]{$id};
+#    warn "returning node: ", $node->getName, "\n";
+    return $node;
+}
+
+sub getName { }
+sub getData { }
+
+sub getChildNodes {
+    return wantarray ? () : [];
+}
+
+sub getChildNode {
+    return;
+}
+
+sub getAttribute {
+    return;
+}
+
+sub getAttributes {
+    return wantarray ? () : [];
+}
+
+sub getAttributeNodes {
+    shift->getAttributes(@_);
+}
+
+sub getNamespaceNodes {
+    return wantarray ? () : [];
+}
+
+sub getNamespace {
+    return;
+}
+
+sub getLocalName {
+    return;
+}
+
+sub string_value { return; }
+
+sub get_pos {
+    my $self = shift;
+    return $self->[XML::XPath::Node::node_pos];
+}
+
+sub set_pos {
+    my $self = shift;
+    $self->[XML::XPath::Node::node_pos] = shift;
+}
+
+sub get_global_pos {
+    my $self = shift;
+    return $self->[XML::XPath::Node::node_global_pos];
+}
+
+sub set_global_pos {
+    my $self = shift;
+    $self->[XML::XPath::Node::node_global_pos] = shift;
+}
+
+sub renumber {
+    my $self = shift;
+    my $search = shift;
+    my $diff = shift;
+    
+    foreach my $node ($self->findnodes($search)) {
+        $node->set_global_pos(
+                $node->get_global_pos + $diff
+                );
+    }
+}
+    
+sub insertAfter {
+    my $self = shift;
+    my $newnode = shift;
+    my $posnode = shift;
+
+    my $pos_number = eval { $posnode->[XML::XPath::Node::node_children][-1]->get_global_pos() + 1; };
+    if (!defined $pos_number) {
+        $pos_number = $posnode->get_global_pos() + 1;
+    }
+    
+    eval {
+        if ($pos_number == 
+                $posnode->findnodes(
+                    'following::node()'
+                    )->get_node(1)->get_global_pos()) {
+            $posnode->renumber('following::node()', +5);
+        }
+    };
+    
+    my $pos = $posnode->get_pos;
+    
+    $newnode->setParentNode($self);
+    splice @{$self->[XML::XPath::Node::node_children]}, $pos + 1, 0, $newnode;
+    
+    for (my $i = $pos + 1; $i < @{$self->[XML::XPath::Node::node_children]}; $i++) {
+        $self->[XML::XPath::Node::node_children][$i]->set_pos($i);
+    }
+    
+    $newnode->set_global_pos($pos_number);
+}
+
+sub insertBefore {
+    my $self = shift;
+    my $newnode = shift;
+    my $posnode = shift;
+    
+    my $pos_number = ($posnode->getPreviousSibling() || $posnode->getParentNode)->get_global_pos();
+    if ($pos_number == $posnode->get_global_pos()) {
+        $posnode->renumber('self::node() | descendant::node() | following::node()', +5);
+    }
+    
+    my $pos = $posnode->get_pos;
+    
+    $newnode->setParentNode($self);
+    splice @{$self->[XML::XPath::Node::node_children]}, $pos, 0, $newnode;
+    
+    for (my $i = $pos; $i < @{$self->[XML::XPath::Node::node_children]}; $i++) {
+        $self->[XML::XPath::Node::node_children][$i]->set_pos($i);
+    }
+    
+    $newnode->set_global_pos($pos_number);
+}
+
+sub getPreviousSibling {
+    my $self = shift;
+    my $pos = $self->[XML::XPath::Node::node_pos];
+    return unless $self->[XML::XPath::Node::node_parent];
+    return $self->[XML::XPath::Node::node_parent]->getChildNode($pos);
+}
+
+sub getNextSibling {
+    my $self = shift;
+    my $pos = $self->[XML::XPath::Node::node_pos];
+    return unless $self->[XML::XPath::Node::node_parent];
+    return $self->[XML::XPath::Node::node_parent]->getChildNode($pos + 2);
+}
+
+sub setParentNode {
+    my $self = shift;
+    my $parent = shift;
+#    warn "SetParent of ", ref($self), " to ", $parent->[XML::XPath::Node::node_name], "\n";
+    $self->[XML::XPath::Node::node_parent] = $parent;
+}
+
+sub del_parent_link {
+    my $self = shift;
+    $self->[XML::XPath::Node::node_parent] = undef;
+}
+
+sub dispose {
+    my $self = shift;
+    foreach my $kid ($self->getChildNodes) {
+        $kid->dispose;
+    }
+    foreach my $kid ($self->getAttributeNodes) {
+        $kid->dispose;
+    }
+    foreach my $kid ($self->getNamespaceNodes) {
+        $kid->dispose;
+    }
+    $self->[XML::XPath::Node::node_parent] = undef;
+}
+
+sub to_number {
+    my $num = shift->string_value;
+    return XML::XPath::Number->new($num);
+}
+
+sub find {
+    my $node = shift;
+    my ($path) = @_;
+    my $xp = XML::XPath->new(); # new is v. lightweight
+    return $xp->find($path, $node);
+}
+
+sub findvalue {
+    my $node = shift;
+    my ($path) = @_;
+    my $xp = XML::XPath->new();
+    return $xp->findvalue($path, $node);
+}
+
+sub findnodes {
+    my $node = shift;
+    my ($path) = @_;
+    my $xp = XML::XPath->new();
+    return $xp->findnodes($path, $node);
+}
+
+sub matches {
+    my $node = shift;
+    my ($path, $context) = @_;
+    my $xp = XML::XPath->new();
+    return $xp->matches($node, $path, $context);
+}
+
+sub to_sax {
+    my $self = shift;
+    unshift @_, 'Handler' if @_ == 1;
+    my %handlers = @_;
+    
+    my $doch = $handlers{DocumentHandler} || $handlers{Handler};
+    my $dtdh = $handlers{DTDHandler} || $handlers{Handler};
+    my $enth = $handlers{EntityResolver} || $handlers{Handler};
+
+    $self->_to_sax ($doch, $dtdh, $enth);
+}
+
+sub DESTROY {}
+
+use Carp;
+
+sub _to_sax {
+    carp "_to_sax not implemented in ", ref($_[0]);
+}
+
+1;
+__END__
+
+=head1 NAME
+
+XML::XPath::Node - internal representation of a node
+
+=head1 API
+
+The Node API aims to emulate DOM to some extent, however the API
+isn't quite compatible with DOM. This is to ease transition from
+XML::DOM programming to XML::XPath. Compatibility with DOM may
+arise once XML::DOM gets namespace support.
+
+=head2 new
+
+Creates a new node. See the sub-classes for parameters to pass to new().
+
+=head2 getNodeType
+
+Returns one of ELEMENT_NODE, TEXT_NODE, COMMENT_NODE, ATTRIBUTE_NODE,
+PROCESSING_INSTRUCTION_NODE or NAMESPACE_NODE. UNKNOWN_NODE is returned
+if the sub-class doesn't implement getNodeType - but that means
+something is broken! The constants are exported by default from
+XML::XPath::Node. The constants have the same numeric value as the
+XML::DOM versions.
+
+=head2 getParentNode
+
+Returns the parent of this node, or undef if this is the root node. Note
+that the root node is the root node in terms of XPath - not the root
+element node.
+
+=head2 to_sax ( $handler | %handlers )
+
+Generates sax calls to the handler or handlers. See the PerlSAX docs for
+details (not yet implemented correctly).
+
+=head1 MORE INFO
+
+See the sub-classes for the meaning of the rest of the API:
+
+=over 4
+
+=item *
+
+L<XML::XPath::Node::Element>
+
+=item *
+
+L<XML::XPath::Node::Attribute>
+
+=item *
+
+L<XML::XPath::Node::Namespace>
+
+=item *
+
+L<XML::XPath::Node::Text>
+
+=item *
+
+L<XML::XPath::Node::Comment>
+
+=item *
+
+L<XML::XPath::Node::PI>
+
+=back
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Attribute.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Attribute.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Attribute.pm	(revision 10506)
@@ -0,0 +1,135 @@
+# $Id$
+
+package XML::XPath::Node::Attribute;
+
+use strict;
+use vars qw/@ISA/;
+
+@ISA = ('XML::XPath::Node');
+
+package XML::XPath::Node::AttributeImpl;
+
+use vars qw/@ISA/;
+@ISA = ('XML::XPath::NodeImpl', 'XML::XPath::Node::Attribute');
+use XML::XPath::Node ':node_keys';
+
+sub new {
+	my $class = shift;
+	my ($key, $val, $prefix) = @_;
+	
+        my $pos = XML::XPath::Node->nextPos;
+        
+        my @vals;
+        @vals[node_global_pos, node_prefix, node_key, node_value] =
+                ($pos, $prefix, $key, $val);
+	my $self = \@vals;
+        
+	bless $self, $class;
+	
+}
+
+sub getNodeType { ATTRIBUTE_NODE }
+
+sub isAttributeNode { 1; }
+
+sub getName {
+    my $self = shift;
+    $self->[node_key];
+}
+
+sub getLocalName {
+    my $self = shift;
+    my $local = $self->[node_key];
+    $local =~ s/.*://;
+    return $local;
+}
+
+sub getNodeValue {
+    my $self = shift;
+    $self->[node_value];
+}
+
+sub getData {
+    shift->getNodeValue(@_);
+}
+
+sub setNodeValue {
+    my $self = shift;
+    $self->[node_value] = shift;
+}
+
+sub getPrefix {
+	my $self = shift;
+	$self->[node_prefix];
+}
+
+sub string_value {
+	my $self = shift;
+	return $self->[node_value];
+}
+
+sub toString {
+	my $self = shift;
+	my $string = ' ';
+# 	if ($self->[node_prefix]) {
+# 		$string .= $self->[node_prefix] . ':';
+# 	}
+	$string .= join('',
+					$self->[node_key],
+					'="',
+					XML::XPath::Node::XMLescape($self->[node_value], '"&><'),
+					'"');
+	return $string;
+}
+
+sub getNamespace {
+    my $self = shift;
+    my ($prefix) = @_;
+    $prefix ||= $self->getPrefix;
+    if (my $parent = $self->getParentNode) {
+        return $parent->getNamespace($prefix);
+    }
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Attribute - a single attribute
+
+=head1 API
+
+=head2 new ( key, value, prefix )
+
+Create a new attribute node.
+
+=head2 getName
+
+Returns the key for the attribute
+
+=head2 getLocalName
+
+As getName above, but without namespace information
+
+=head2 getNodeValue / getData
+
+Returns the value
+
+=head2 setNodeValue
+
+Sets the value of the attribute node.
+
+=head2 getPrefix
+
+Returns the prefix
+
+=head2 getNamespace
+
+Return the namespace.
+
+=head2 toString
+
+Generates key="value", encoded correctly.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Comment.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Comment.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Comment.pm	(revision 10506)
@@ -0,0 +1,91 @@
+# $Id$
+
+package XML::XPath::Node::Comment;
+
+use strict;
+use vars qw/@ISA/;
+
+@ISA = ('XML::XPath::Node');
+
+package XML::XPath::Node::CommentImpl;
+
+use vars qw/@ISA/;
+@ISA = ('XML::XPath::NodeImpl', 'XML::XPath::Node::Comment');
+use XML::XPath::Node ':node_keys';
+
+sub new {
+    my $class = shift;
+    my ($comment) = @_;
+    
+        my $pos = XML::XPath::Node->nextPos;
+        
+        my @vals;
+        @vals[node_global_pos, node_comment] =
+                ($pos, $comment);
+    my $self = \@vals;
+        
+    bless $self, $class;
+}
+
+sub getNodeType { COMMENT_NODE }
+
+sub isCommentNode { 1; }
+
+sub getNodeValue {
+    return shift->[node_comment];
+}
+
+sub getData {
+    shift->getNodeValue;
+}
+
+sub setNodeValue {
+    shift->[node_comment] = shift;
+}
+
+sub _to_sax {
+    my $self = shift;
+    my ($doch, $dtdh, $enth) = @_;
+    
+    $doch->comment( { Data => $self->getValue } );
+}
+
+sub comment_escape {
+    my $data = shift;
+    $data =~ s/--/&#45;&#45;/g;
+    return $data;
+}
+
+sub string_value {
+    my $self = shift;
+    return $self->[node_comment];
+}
+
+sub toString {
+    my $self = shift;
+    return '<!--' . comment_escape($self->[node_comment]) . '-->';
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Comment - an XML comment: <!--comment-->
+
+=head1 API
+
+=head2 new ( data )
+
+Create a new comment node.
+
+=head2 getValue / getData
+
+Returns the value in the comment
+
+=head2 toString
+
+Returns the comment with -- encoded as a numeric entity (if it
+exists in the comment text).
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Element.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Element.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Element.pm	(revision 10506)
@@ -0,0 +1,503 @@
+# $Id$
+
+package XML::XPath::Node::Element;
+
+use strict;
+use vars qw/@ISA/;
+
+@ISA = ('XML::XPath::Node');
+
+package XML::XPath::Node::ElementImpl;
+
+use vars qw/@ISA/;
+@ISA = ('XML::XPath::NodeImpl', 'XML::XPath::Node::Element');
+use XML::XPath::Node ':node_keys';
+
+sub new {
+    my $class = shift;
+    my ($tag, $prefix) = @_;
+        
+    my $pos = XML::XPath::Node->nextPos;
+
+    my @vals;
+    @vals[node_global_pos, node_prefix, node_children, node_name, node_attribs] =
+            ($pos, $prefix, [], $tag, []);
+        
+    my $self = \@vals;
+    bless $self, $class;
+}
+
+sub getNodeType { ELEMENT_NODE }
+
+sub isElementNode { 1; }
+
+sub appendChild {
+    my $self = shift;
+    my $newnode = shift;
+    if (shift) { # called from internal to XML::XPath
+#    warn "AppendChild $newnode to $self\n";
+        push @{$self->[node_children]}, $newnode;
+        $newnode->setParentNode($self);
+        $newnode->set_pos($#{$self->[node_children]});
+    }
+    else {
+        if (@{$self->[node_children]}) {
+            $self->insertAfter($newnode, $self->[node_children][-1]);
+        }
+        else {
+            my $pos_number = $self->get_global_pos() + 1;
+            
+            if (my $brother = $self->getNextSibling()) { # optimisation
+                if ($pos_number == $brother->get_global_pos()) {
+                    $self->renumber('following::node()', +5);
+                }
+            }
+            else {
+                eval {
+                    if ($pos_number == 
+                            $self->findnodes(
+                                'following::node()'
+                                )->get_node(1)->get_global_pos()) {
+                        $self->renumber('following::node()', +5);
+                    }
+                };
+            }
+            
+            push @{$self->[node_children]}, $newnode;
+            $newnode->setParentNode($self);
+            $newnode->set_pos($#{$self->[node_children]});
+            $newnode->set_global_pos($pos_number);
+        }
+    }
+}
+
+sub removeChild {
+    my $self = shift;
+    my $delnode = shift;
+    
+    my $pos = $delnode->get_pos;
+    
+#    warn "removeChild: $pos\n";
+    
+#    warn "children: ", scalar @{$self->[node_children]}, "\n";
+    
+#    my $node = $self->[node_children][$pos];
+#    warn "child at $pos is: $node\n";
+    
+    splice @{$self->[node_children]}, $pos, 1;
+    
+#    warn "children now: ", scalar @{$self->[node_children]}, "\n";
+    
+    for (my $i = $pos; $i < @{$self->[node_children]}; $i++) {
+#        warn "Changing pos of child: $i\n";
+        $self->[node_children][$i]->set_pos($i);
+    }
+    
+    $delnode->del_parent_link;
+    
+}
+
+sub appendIdElement {
+    my $self = shift;
+    my ($val, $element) = @_;
+#    warn "Adding '$val' to ID hash\n";
+    $self->[node_ids]{$val} = $element;
+}
+
+sub DESTROY {
+    my $self = shift;
+#    warn "DESTROY ELEMENT: ", $self->[node_name], "\n";
+#    warn "DESTROY ROOT\n" unless $self->[node_name];
+    
+    foreach my $kid ($self->getChildNodes) {
+        $kid && $kid->del_parent_link;
+    }
+    foreach my $attr ($self->getAttributeNodes) {
+        $attr && $attr->del_parent_link;
+    }
+    foreach my $ns ($self->getNamespaceNodes) {
+        $ns && $ns->del_parent_link;
+    }
+#     $self->[node_children] = undef;
+#     $self->[node_attribs] = undef;
+#     $self->[node_namespaces] = undef;
+}
+
+sub getName {
+    my $self = shift;
+    $self->[node_name];
+}
+
+sub getTagName {
+    shift->getName(@_);
+}
+
+sub getLocalName {
+    my $self = shift;
+    my $local = $self->[node_name];
+    $local =~ s/.*://;
+    return $local;
+}
+
+sub getChildNodes {
+    my $self = shift;
+    return wantarray ? @{$self->[node_children]} : $self->[node_children];
+}
+
+sub getChildNode {
+    my $self = shift;
+    my ($pos) = @_;
+    if ($pos < 1 || $pos > @{$self->[node_children]}) {
+        return;
+    }
+    return $self->[node_children][$pos - 1];
+}
+
+sub getFirstChild {
+    my $self = shift;
+    return unless @{$self->[node_children]};
+    return $self->[node_children][0];
+}
+
+sub getLastChild {
+    my $self = shift;
+    return unless @{$self->[node_children]};
+    return $self->[node_children][-1];
+}
+
+sub getAttributeNode {
+    my $self = shift;
+    my ($name) = @_;
+    my $attribs = $self->[node_attribs];
+    foreach my $attr (@$attribs) {
+        return $attr if $attr->getName eq $name;
+    }
+}
+
+sub getAttribute {
+    my $self = shift;
+    my $attr = $self->getAttributeNode(@_);
+    if ($attr) {
+        return $attr->getValue;
+    }
+}
+
+sub getAttributes {
+    my $self = shift;
+    if ($self->[node_attribs]) {
+        return wantarray ? @{$self->[node_attribs]} : $self->[node_attribs];
+    }
+    return wantarray ? () : [];
+}
+
+sub appendAttribute {
+    my $self = shift;
+    my $attribute = shift;
+    
+    if (shift) { # internal call
+        push @{$self->[node_attribs]}, $attribute;
+        $attribute->setParentNode($self);
+        $attribute->set_pos($#{$self->[node_attribs]});
+    }
+    else {
+        my $node_num;
+        if (@{$self->[node_attribs]}) {
+            $node_num = $self->[node_attribs][-1]->get_global_pos() + 1;
+        }
+        else {
+            $node_num = $self->get_global_pos() + 1;
+        }
+        
+        eval {
+            if (@{$self->[node_children]}) {
+                if ($node_num == $self->[node_children][-1]->get_global_pos()) {
+                    $self->renumber('descendant::node() | following::node()', +5);
+                }
+            }
+            elsif ($node_num == 
+                    $self->findnodes('following::node()')->get_node(1)->get_global_pos()) {
+                $self->renumber('following::node()', +5);
+            }
+        };
+        
+        push @{$self->[node_attribs]}, $attribute;
+        $attribute->setParentNode($self);
+        $attribute->set_pos($#{$self->[node_attribs]});
+        $attribute->set_global_pos($node_num);
+        
+    }
+}
+
+sub removeAttribute {
+    my $self = shift;
+    my $attrib = shift;
+    
+    if (!ref($attrib)) {
+        $attrib = $self->getAttributeNode($attrib);
+    }
+    
+    my $pos = $attrib->get_pos;
+    
+    splice @{$self->[node_attribs]}, $pos, 1;
+    
+    for (my $i = $pos; $i < @{$self->[node_attribs]}; $i++) {
+        $self->[node_attribs][$i]->set_pos($i);
+    }
+    
+    $attrib->del_parent_link;
+}
+
+sub setAttribute {
+    my $self = shift;
+    my ($name, $value) = @_;
+    
+    if (my $attrib = $self->getAttributeNode($name)) {
+        $attrib->setNodeValue($value);
+        return $attrib;
+    }
+    
+    my ($nsprefix) = ($name =~ /^($XML::XPath::Parser::NCName):($XML::XPath::Parser::NCName)$/o);
+    
+    if ($nsprefix && !$self->getNamespace($nsprefix)) {
+        die "No namespace matches prefix: $nsprefix";
+    }
+    
+    my $newnode = XML::XPath::Node::Attribute->new($name, $value, $nsprefix);
+    $self->appendAttribute($newnode);
+}
+
+sub setAttributeNode {
+    my $self = shift;
+    my ($node) = @_;
+    
+    if (my $attrib = $self->getAttributeNode($node->getName)) {
+        $attrib->setNodeValue($node->getValue);
+        return $attrib;
+    }
+    
+    my ($nsprefix) = ($node->getName() =~ /^($XML::XPath::Parser::NCName):($XML::XPath::Parser::NCName)$/o);
+    
+    if ($nsprefix && !$self->getNamespace($nsprefix)) {
+        die "No namespace matches prefix: $nsprefix";
+    }
+    
+    $self->appendAttribute($node);
+}
+
+sub getNamespace {
+    my $self = shift;
+    my ($prefix) = @_;
+    $prefix ||= $self->getPrefix || '#default';
+    my $namespaces = $self->[node_namespaces] || [];
+    foreach my $ns (@$namespaces) {
+        return $ns if $ns->getPrefix eq $prefix;
+    }
+    my $parent = $self->getParentNode;
+    
+    return $parent->getNamespace($prefix) if $parent;
+}
+
+sub getNamespaces {
+    my $self = shift;
+    if ($self->[node_namespaces]) {
+        return wantarray ? @{$self->[node_namespaces]} : $self->[node_namespaces];
+    }
+    return wantarray ? () : [];
+}
+
+sub getNamespaceNodes { goto &getNamespaces }
+
+sub appendNamespace {
+    my $self = shift;
+    my ($ns) = @_;
+    push @{$self->[node_namespaces]}, $ns;
+    $ns->setParentNode($self);
+    $ns->set_pos($#{$self->[node_namespaces]});
+}
+
+sub getPrefix {
+    my $self = shift;
+    $self->[node_prefix];
+}
+
+sub getExpandedName {
+    my $self = shift;
+    warn "Expanded name not implemented for ", ref($self), "\n";
+    return;
+}
+
+sub _to_sax {
+    my $self = shift;
+    my ($doch, $dtdh, $enth) = @_;
+    
+    my $tag = $self->getName;
+    my @attr;
+    
+    for my $attr ($self->getAttributes) {
+        push @attr, $attr->getName, $attr->getValue;
+    }
+    
+    my $ns = $self->getNamespace($self->[node_prefix]);
+    if ($ns) {
+        $doch->start_element( 
+                { 
+                Name => $tag,
+                Attributes => { @attr },
+                NamespaceURI => $ns->getExpanded,
+                Prefix => $ns->getPrefix,
+                LocalName => $self->getLocalName,
+                }
+            );
+    }
+    else {
+        $doch->start_element(
+                {
+                Name => $tag,
+                Attributes => { @attr },
+                }
+            );
+    }
+    
+    for my $kid ($self->getChildNodes) {
+        $kid->_to_sax($doch, $dtdh, $enth);
+    }
+    
+    if ($ns) {
+        $doch->end_element( 
+                {
+                Name => $tag,
+                NamespaceURI => $ns->getExpanded,
+                Prefix => $ns->getPrefix,
+                LocalName => $self->getLocalName
+                }
+            );
+    }
+    else {
+        $doch->end_element( { Name => $tag } );
+    }
+}
+
+sub string_value {
+    my $self = shift;
+    my $string = '';
+    foreach my $kid (@{$self->[node_children]}) {
+        if ($kid->getNodeType == ELEMENT_NODE
+                || $kid->getNodeType == TEXT_NODE) {
+            $string .= $kid->string_value;
+        }
+    }
+    return $string;
+}
+
+sub toString {
+    my $self = shift;
+    my $norecurse = shift;
+    my $string = '';
+    if (! $self->[node_name] ) {
+            # root node
+            return join('', map { $_->toString($norecurse) } @{$self->[node_children]});
+    }
+    $string .= "<" . $self->[node_name];
+    
+        $string .= join('', map { $_->toString } @{$self->[node_namespaces]});
+    
+        $string .= join('', map { $_->toString } @{$self->[node_attribs]});
+    
+    if (@{$self->[node_children]}) {
+        $string .= ">";
+
+        if (!$norecurse) {
+                        $string .= join('', map { $_->toString($norecurse) } @{$self->[node_children]});
+        }
+        
+        $string .= "</" . $self->[node_name] . ">";
+    }
+    else {
+        $string .= " />";
+    }
+    
+    return $string;
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Element - an <element>
+
+=head1 API
+
+=head2 new ( name, prefix )
+
+Create a new Element node with name "name" and prefix "prefix". The name
+be "prefix:local" if prefix is defined. I know that sounds wierd, but it
+works ;-)
+
+=head2 getName
+
+Returns the name (including "prefix:" if defined) of this element.
+
+=head2 getLocalName
+
+Returns just the local part of the name (the bit after "prefix:").
+
+=head2 getChildNodes
+
+Returns the children of this element. In list context returns a list. In
+scalar context returns an array ref.
+
+=head2 getChildNode ( pos )
+
+Returns the child at position pos.
+
+=head2 appendChild ( childnode )
+
+Appends the child node to the list of current child nodes.
+
+=head2 getAttribute ( name )
+
+Returns the attribute node with key name.
+
+=head2 getAttributes / getAttributeNodes
+
+Returns the attribute nodes. In list context returns a list. In scalar
+context returns an array ref.
+
+=head2 appendAttribute ( attrib_node)
+
+Appends the attribute node to the list of attributes (XML::XPath stores
+attributes in order).
+
+=head2 getNamespace ( prefix )
+
+Returns the namespace node by the given prefix
+
+=head2 getNamespaces / getNamespaceNodes
+
+Returns the namespace nodes. In list context returns a list. In scalar
+context returns an array ref.
+
+=head2 appendNamespace ( ns_node )
+
+Appends the namespace node to the list of namespaces.
+
+=head2 getPrefix
+
+Returns the prefix of this element
+
+=head2 getExpandedName
+
+Returns the expanded name of this element (not yet implemented right).
+
+=head2 string_value
+
+For elements, the string_value is the concatenation of all string_values
+of all text-descendants of the element node in document order.
+
+=head2 toString ( [ norecurse ] )
+
+Output (and all children) the node to a string. Doesn't process children
+if the norecurse option is a true value.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Namespace.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Namespace.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Namespace.pm	(revision 10506)
@@ -0,0 +1,99 @@
+# $Id$
+
+package XML::XPath::Node::Namespace;
+
+use strict;
+use vars qw/@ISA/;
+
+@ISA = ('XML::XPath::Node');
+
+package XML::XPath::Node::NamespaceImpl;
+
+use vars qw/@ISA/;
+@ISA = ('XML::XPath::NodeImpl', 'XML::XPath::Node::Namespace');
+use XML::XPath::Node ':node_keys';
+
+sub new {
+	my $class = shift;
+	my ($prefix, $expanded) = @_;
+	
+        my $pos = XML::XPath::Node->nextPos;
+        
+        my @vals;
+        @vals[node_global_pos, node_prefix, node_expanded] =
+                ($pos, $prefix, $expanded);
+	my $self = \@vals;
+        
+	bless $self, $class;
+}
+
+sub getNodeType { NAMESPACE_NODE }
+
+sub isNamespaceNode { 1; }
+
+sub getPrefix {
+	my $self = shift;
+	$self->[node_prefix];
+}
+
+sub getExpanded {
+	my $self = shift;
+	$self->[node_expanded];
+}
+
+sub getValue {
+	my $self = shift;
+	$self->[node_expanded];
+}
+
+sub getData {
+	my $self = shift;
+	$self->[node_expanded];
+}
+
+sub string_value {
+	my $self = shift;
+	$self->[node_expanded];
+}
+
+sub toString {
+	my $self = shift;
+	my $string = '';
+	return '' unless defined $self->[node_expanded];
+	if ($self->[node_prefix] eq '#default') {
+		$string .= ' xmlns="';
+	}
+	else {
+		$string .= ' xmlns:' . $self->[node_prefix] . '="';
+	}
+	$string .= XML::XPath::Node::XMLescape($self->[node_expanded], '"&<');
+	$string .= '"';
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Namespace - an XML namespace node
+
+=head1 API
+
+=head2 new ( prefix, expanded )
+
+Create a new namespace node, expanded is the expanded namespace URI.
+
+=head2 getPrefix
+
+Returns the prefix
+
+=head2 getExpanded
+
+Returns the expanded URI
+
+=head2 toString
+
+Returns a string that you can add to the list
+of attributes of an element: xmlns:prefix="expanded"
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/PI.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/PI.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/PI.pm	(revision 10506)
@@ -0,0 +1,81 @@
+# $Id$
+
+package XML::XPath::Node::PI;
+
+use strict;
+use vars qw/@ISA/;
+
+@ISA = ('XML::XPath::Node');
+
+package XML::XPath::Node::PIImpl;
+
+use vars qw/@ISA/;
+@ISA = ('XML::XPath::NodeImpl', 'XML::XPath::Node::PI');
+use XML::XPath::Node ':node_keys';
+
+sub new {
+	my $class = shift;
+	my ($target, $data) = @_;
+	
+        my $pos = XML::XPath::Node->nextPos;
+        
+        my @vals;
+        @vals[node_global_pos, node_target, node_data] = 
+                ($pos, $target, $data);
+	my $self = \@vals;
+	bless $self, $class;
+}
+
+sub getNodeType { PROCESSING_INSTRUCTION_NODE }
+
+sub isPINode { 1; }
+sub isProcessingInstructionNode { 1; }
+
+sub getTarget {
+	my $self = shift;
+	$self->[node_target];
+}
+
+sub getData {
+	my $self = shift;
+	$self->[node_data];
+}
+
+sub _to_sax {
+	my $self = shift;
+	my ($doch, $dtdh, $enth) = @_;
+	# PI's not supported in PerlSAX 1
+}
+
+sub string_value {
+	my $self = shift;
+	return $self->[node_data];
+}
+
+sub toString {
+	my $self = shift;
+	return "<?" . $self->[node_target] . " " . XML::XPath::Node::XMLescape($self->[node_data], ">") . "?>";
+}
+
+1;
+__END__
+
+=head1 NAME
+
+PI - an XML processing instruction node
+
+=head1 API
+
+=head2 new ( target, data )
+
+Create a new PI node.
+
+=head2 getTarget
+
+Returns the target
+
+=head2 getData
+
+Returns the data
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Text.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Text.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Node/Text.pm	(revision 10506)
@@ -0,0 +1,96 @@
+# $Id$
+
+package XML::XPath::Node::Text;
+
+use strict;
+use vars qw/@ISA/;
+
+@ISA = ('XML::XPath::Node');
+
+package XML::XPath::Node::TextImpl;
+
+use vars qw/@ISA/;
+@ISA = ('XML::XPath::NodeImpl', 'XML::XPath::Node::Text');
+use XML::XPath::Node ':node_keys';
+
+sub new {
+    my $class = shift;
+    my ($text) = @_;
+    
+        my $pos = XML::XPath::Node->nextPos;
+        
+        my @vals;
+        @vals[node_global_pos, node_text] = ($pos, $text);
+    my $self = \@vals;
+        
+    bless $self, $class;
+}
+
+sub getNodeType { TEXT_NODE }
+
+sub isTextNode { 1; }
+
+sub appendText {
+    my $self = shift;
+    my ($text) = @_;
+    $self->[node_text] .= $text;
+}
+
+sub getNodeValue {
+    my $self = shift;
+    $self->[node_text];
+}
+
+sub getData {
+    my $self = shift;
+    $self->[node_text];
+}
+
+sub setNodeValue {
+    my $self = shift;
+    $self->[node_text] = shift;
+}
+
+sub _to_sax {
+    my $self = shift;
+    my ($doch, $dtdh, $enth) = @_;
+    
+    $doch->characters( { Data => $self->getValue } );
+}
+
+sub string_value {
+    my $self = shift;
+    $self->[node_text];
+}
+
+sub toString {
+    my $self = shift;
+    XML::XPath::Node::XMLescape($self->[node_text], "<&");
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Text - an XML text node
+
+=head1 API
+
+=head2 new ( text )
+
+Create a new text node.
+
+=head2 getValue / getData
+
+Returns the text
+
+=head2 string_value
+
+Returns the text
+
+=head2 appendText ( text )
+
+Adds the given text string to this node.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/NodeSet.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/NodeSet.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/NodeSet.pm	(revision 10506)
@@ -0,0 +1,184 @@
+# $Id$
+
+package XML::XPath::NodeSet;
+use strict;
+
+use XML::XPath::Boolean;
+
+use overload 
+		'""' => \&to_literal,
+                'bool' => \&to_boolean,
+        ;
+
+sub new {
+	my $class = shift;
+	bless [], $class;
+}
+
+sub sort {
+    my $self = CORE::shift;
+    @$self = CORE::sort { $a->get_global_pos <=> $b->get_global_pos } @$self;
+    return $self;
+}
+
+sub pop {
+	my $self = CORE::shift;
+	CORE::pop @$self;
+}
+
+sub push {
+	my $self = CORE::shift;
+	my (@nodes) = @_;
+	CORE::push @$self, @nodes;
+}
+
+sub append {
+	my $self = CORE::shift;
+	my ($nodeset) = @_;
+	CORE::push @$self, $nodeset->get_nodelist;
+}
+
+sub shift {
+	my $self = CORE::shift;
+	CORE::shift @$self;
+}
+
+sub unshift {
+	my $self = CORE::shift;
+	my (@nodes) = @_;
+	CORE::unshift @$self, @nodes;
+}
+
+sub prepend {
+	my $self = CORE::shift;
+	my ($nodeset) = @_;
+	CORE::unshift @$self, $nodeset->get_nodelist;
+}
+
+sub size {
+	my $self = CORE::shift;
+	scalar @$self;
+}
+
+sub get_node { # uses array index starting at 1, not 0
+	my $self = CORE::shift;
+	my ($pos) = @_;
+	$self->[$pos - 1];
+}
+
+sub getRootNode {
+    my $self = CORE::shift;
+    return $self->[0]->getRootNode;
+}
+
+sub get_nodelist {
+	my $self = CORE::shift;
+	@$self;
+}
+
+sub to_boolean {
+	my $self = CORE::shift;
+	return (@$self > 0) ? XML::XPath::Boolean->True : XML::XPath::Boolean->False;
+}
+
+sub string_value {
+	my $self = CORE::shift;
+	return '' unless @$self;
+	return $self->[0]->string_value;
+}
+
+sub to_literal {
+	my $self = CORE::shift;
+	return XML::XPath::Literal->new(
+			join('', map { $_->string_value } @$self)
+			);
+}
+
+sub to_number {
+	my $self = CORE::shift;
+	return XML::XPath::Number->new(
+			$self->to_literal
+			);
+}
+
+1;
+__END__
+
+=head1 NAME
+
+XML::XPath::NodeSet - a list of XML document nodes
+
+=head1 DESCRIPTION
+
+An XML::XPath::NodeSet object contains an ordered list of nodes. The nodes
+each take the same format as described in L<XML::XPath::XMLParser>.
+
+=head1 SYNOPSIS
+
+	my $results = $xp->find('//someelement');
+	if (!$results->isa('XML::XPath::NodeSet')) {
+		print "Found $results\n";
+		exit;
+	}
+	foreach my $context ($results->get_nodelist) {
+		my $newresults = $xp->find('./other/element', $context);
+		...
+	}
+
+=head1 API
+
+=head2 new()
+
+You will almost never have to create a new NodeSet object, as it is all
+done for you by XPath.
+
+=head2 get_nodelist()
+
+Returns a list of nodes. See L<XML::XPath::XMLParser> for the format of
+the nodes.
+
+=head2 string_value()
+
+Returns the string-value of the first node in the list.
+See the XPath specification for what "string-value" means.
+
+=head2 to_literal()
+
+Returns the concatenation of all the string-values of all
+the nodes in the list.
+
+=head2 get_node($pos)
+
+Returns the node at $pos. The node position in XPath is based at 1, not 0.
+
+=head2 size()
+
+Returns the number of nodes in the NodeSet.
+
+=head2 pop()
+
+Equivalent to perl's pop function.
+
+=head2 push(@nodes)
+
+Equivalent to perl's push function.
+
+=head2 append($nodeset)
+
+Given a nodeset, appends the list of nodes in $nodeset to the end of the
+current list.
+
+=head2 shift()
+
+Equivalent to perl's shift function.
+
+=head2 unshift(@nodes)
+
+Equivalent to perl's unshift function.
+
+=head2 prepend($nodeset)
+
+Given a nodeset, prepends the list of nodes in $nodeset to the front of
+the current list.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Number.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Number.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Number.pm	(revision 10506)
@@ -0,0 +1,87 @@
+# $Id$
+
+package XML::XPath::Number;
+use XML::XPath::Boolean;
+use XML::XPath::Literal;
+use strict;
+
+use overload
+        '""' => \&value,
+        '0+' => \&value,
+        '<=>' => \&cmp;
+
+sub new {
+    my $class = shift;
+    my $number = shift;
+    if ($number !~ /^\s*[+-]?(\d+(\.\d*)?|\.\d+)\s*$/) {
+        $number = undef;
+    }
+    else {
+        $number =~ s/^\s*(.*)\s*$/$1/;
+    }
+    bless \$number, $class;
+}
+
+sub as_string {
+    my $self = shift;
+    defined $$self ? $$self : 'NaN';
+}
+
+sub as_xml {
+    my $self = shift;
+    return "<Number>" . (defined($$self) ? $$self : 'NaN') . "</Number>\n";
+}
+
+sub value {
+    my $self = shift;
+    $$self;
+}
+
+sub cmp {
+    my $self = shift;
+    my ($other, $swap) = @_;
+    if ($swap) {
+        return $other <=> $$self;
+    }
+    return $$self <=> $other;
+}
+
+sub evaluate {
+    my $self = shift;
+    $self;
+}
+
+sub to_boolean {
+    my $self = shift;
+    return $$self ? XML::XPath::Boolean->True : XML::XPath::Boolean->False;
+}
+
+sub to_literal { XML::XPath::Literal->new($_[0]->as_string); }
+sub to_number { $_[0]; }
+
+sub string_value { return $_[0]->value }
+
+1;
+__END__
+
+=head1 NAME
+
+XML::XPath::Number - Simple numeric values.
+
+=head1 DESCRIPTION
+
+This class holds simple numeric values. It doesn't support -0, +/- Infinity,
+or NaN, as the XPath spec says it should, but I'm not hurting anyone I don't think.
+
+=head1 API
+
+=head2 new($num)
+
+Creates a new XML::XPath::Number object, with the value in $num. Does some
+rudimentary numeric checking on $num to ensure it actually is a number.
+
+=head2 value()
+
+Also as overloaded stringification. Returns the numeric value held.
+
+=cut
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Parser.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Parser.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Parser.pm	(revision 10506)
@@ -0,0 +1,821 @@
+# $Id$
+
+package XML::XPath::Parser;
+
+use strict;
+use vars qw/
+        $NCName 
+        $QName 
+        $NCWild
+        $QNWild
+        $NUMBER_RE 
+        $NODE_TYPE 
+        $AXIS_NAME 
+        %AXES 
+        $LITERAL
+        %CACHE/;
+
+use XML::XPath::XMLParser;
+use XML::XPath::Step;
+use XML::XPath::Expr;
+use XML::XPath::Function;
+use XML::XPath::LocationPath;
+use XML::XPath::Variable;
+use XML::XPath::Literal;
+use XML::XPath::Number;
+use XML::XPath::NodeSet;
+
+# Axis name to principal node type mapping
+%AXES = (
+        'ancestor' => 'element',
+        'ancestor-or-self' => 'element',
+        'attribute' => 'attribute',
+        'namespace' => 'namespace',
+        'child' => 'element',
+        'descendant' => 'element',
+        'descendant-or-self' => 'element',
+        'following' => 'element',
+        'following-sibling' => 'element',
+        'parent' => 'element',
+        'preceding' => 'element',
+        'preceding-sibling' => 'element',
+        'self' => 'element',
+        );
+
+$NCName = '([A-Za-z_][\w\\.\\-]*)';
+$QName = "($NCName:)?$NCName";
+$NCWild = "${NCName}:\\*";
+$QNWild = "\\*";
+$NODE_TYPE = '((text|comment|processing-instruction|node)\\(\\))';
+$AXIS_NAME = '(' . join('|', keys %AXES) . ')::';
+$NUMBER_RE = '\d+(\\.\d*)?|\\.\d+';
+$LITERAL = '\\"[^\\"]*\\"|\\\'[^\\\']*\\\'';
+
+sub new {
+    my $class = shift;
+    my $self = bless {}, $class;
+    debug("New Parser being created.\n");
+    $self->{context_set} = XML::XPath::NodeSet->new();
+    $self->{context_pos} = undef; # 1 based position in array context
+    $self->{context_size} = 0; # total size of context
+    $self->clear_namespaces();
+    $self->{vars} = {};
+    $self->{direction} = 'forward';
+    $self->{cache} = {};
+    return $self;
+}
+
+sub get_var {
+    my $self = shift;
+    my $var = shift;
+    $self->{vars}->{$var};
+}
+
+sub set_var {
+    my $self = shift;
+    my $var = shift;
+    my $val = shift;
+    $self->{vars}->{$var} = $val;
+}
+
+sub set_namespace {
+    my $self = shift;
+    my ($prefix, $expanded) = @_;
+    $self->{namespaces}{$prefix} = $expanded;
+}
+
+sub clear_namespaces {
+    my $self = shift;
+    $self->{namespaces} = {};
+}
+
+sub get_namespace {
+    my $self = shift;
+    my ($prefix, $node) = @_;
+    if (my $ns = $self->{namespaces}{$prefix}) {
+        return $ns;
+    }
+    if (my $nsnode = $node->getNamespace($prefix)) {
+        return $nsnode->getValue();
+    }
+}
+
+sub get_context_set { $_[0]->{context_set}; }
+sub set_context_set { $_[0]->{context_set} = $_[1]; }
+sub get_context_pos { $_[0]->{context_pos}; }
+sub set_context_pos { $_[0]->{context_pos} = $_[1]; }
+sub get_context_size { $_[0]->{context_set}->size; }
+sub get_context_node { $_[0]->{context_set}->get_node($_[0]->{context_pos}); }
+
+sub my_sub {
+    return (caller(1))[3];
+}
+
+sub parse {
+    my $self = shift;
+    my $path = shift;
+    if ($CACHE{$path}) {
+        return $CACHE{$path};
+    }
+    my $tokens = $self->tokenize($path);
+
+    $self->{_tokpos} = 0;
+    my $tree = $self->analyze($tokens);
+    
+    if ($self->{_tokpos} < scalar(@$tokens)) {
+        # didn't manage to parse entire expression - throw an exception
+        die "Parse of expression $path failed - junk after end of expression: $tokens->[$self->{_tokpos}]";
+    }
+    
+    $CACHE{$path} = $tree;
+    
+    debug("PARSED Expr to:\n", $tree->as_string, "\n") if $XML::XPath::Debug;
+    
+    return $tree;
+}
+
+sub tokenize {
+    my $self = shift;
+    my $path = shift;
+    study $path;
+    
+    my @tokens;
+    
+    debug("Parsing: $path\n");
+    
+    # Bug: We don't allow "'@' NodeType" which is in the grammar, but I think is just plain stupid.
+
+    while($path =~ m/\G
+        \s* # ignore all whitespace
+        ( # tokens
+            $LITERAL|
+            $NUMBER_RE| # Match digits
+            \.\.| # match parent
+            \.| # match current
+            ($AXIS_NAME)?$NODE_TYPE| # match tests
+            processing-instruction|
+            \@($NCWild|$QName|$QNWild)| # match attrib
+            \$$QName| # match variable reference
+            ($AXIS_NAME)?($NCWild|$QName|$QNWild)| # match NCName,NodeType,Axis::Test
+            \!=|<=|\-|>=|\/\/|and|or|mod|div| # multi-char seps
+            [,\+=\|<>\/\(\[\]\)]| # single char seps
+            (?<!(\@|\(|\[))\*| # multiply operator rules (see xpath spec)
+            (?<!::)\*|
+            $ # match end of query
+        )
+        \s* # ignore all whitespace
+        /gcxso) {
+
+        my ($token) = ($1);
+
+        if (length($token)) {
+            debug("TOKEN: $token\n");
+            push @tokens, $token;
+        }
+        
+    }
+    
+    if (pos($path) < length($path)) {
+        my $marker = ("." x (pos($path)-1));
+        $path = substr($path, 0, pos($path) + 8) . "...";
+        $path =~ s/\n/ /g;
+        $path =~ s/\t/ /g;
+        die "Query:\n",
+            "$path\n",
+            $marker, "^^^\n",
+            "Invalid query somewhere around here (I think)\n";
+    }
+    
+    return \@tokens;
+}
+
+sub analyze {
+    my $self = shift;
+    my $tokens = shift;
+    # lexical analysis
+    
+    return Expr($self, $tokens);
+}
+
+sub match {
+    my ($self, $tokens, $match, $fatal) = @_;
+    
+    $self->{_curr_match} = '';
+    return 0 unless $self->{_tokpos} < @$tokens;
+
+    local $^W;
+    
+#    debug ("match: $match\n");
+    
+    if ($tokens->[$self->{_tokpos}] =~ /^$match$/) {
+        $self->{_curr_match} = $tokens->[$self->{_tokpos}];
+        $self->{_tokpos}++;
+        return 1;
+    }
+    else {
+        if ($fatal) {
+            die "Invalid token: ", $tokens->[$self->{_tokpos}], "\n";
+        }
+        else {
+            return 0;
+        }
+    }
+}
+
+sub Expr {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    return OrExpr($self, $tokens);
+}
+
+sub OrExpr {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my $expr = AndExpr($self, $tokens); 
+    while (match($self, $tokens, 'or')) {
+        my $or_expr = XML::XPath::Expr->new($self);
+        $or_expr->set_lhs($expr);
+        $or_expr->set_op('or');
+
+        my $rhs = AndExpr($self, $tokens);
+
+        $or_expr->set_rhs($rhs);
+        $expr = $or_expr;
+    }
+    
+    return $expr;
+}
+
+sub AndExpr {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my $expr = EqualityExpr($self, $tokens);
+    while (match($self, $tokens, 'and')) {
+        my $and_expr = XML::XPath::Expr->new($self);
+        $and_expr->set_lhs($expr);
+        $and_expr->set_op('and');
+        
+        my $rhs = EqualityExpr($self, $tokens);
+        
+        $and_expr->set_rhs($rhs);
+        $expr = $and_expr;
+    }
+    
+    return $expr;
+}
+
+sub EqualityExpr {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my $expr = RelationalExpr($self, $tokens);
+    while (match($self, $tokens, '!?=')) {
+        my $eq_expr = XML::XPath::Expr->new($self);
+        $eq_expr->set_lhs($expr);
+        $eq_expr->set_op($self->{_curr_match});
+        
+        my $rhs = RelationalExpr($self, $tokens);
+        
+        $eq_expr->set_rhs($rhs);
+        $expr = $eq_expr;
+    }
+    
+    return $expr;
+}
+
+sub RelationalExpr {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my $expr = AdditiveExpr($self, $tokens);
+    while (match($self, $tokens, '(<|>|<=|>=)')) {
+        my $rel_expr = XML::XPath::Expr->new($self);
+        $rel_expr->set_lhs($expr);
+        $rel_expr->set_op($self->{_curr_match});
+        
+        my $rhs = AdditiveExpr($self, $tokens);
+        
+        $rel_expr->set_rhs($rhs);
+        $expr = $rel_expr;
+    }
+    
+    return $expr;
+}
+
+sub AdditiveExpr {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my $expr = MultiplicativeExpr($self, $tokens);
+    while (match($self, $tokens, '[\\+\\-]')) {
+        my $add_expr = XML::XPath::Expr->new($self);
+        $add_expr->set_lhs($expr);
+        $add_expr->set_op($self->{_curr_match});
+        
+        my $rhs = MultiplicativeExpr($self, $tokens);
+        
+        $add_expr->set_rhs($rhs);
+        $expr = $add_expr;
+    }
+    
+    return $expr;
+}
+
+sub MultiplicativeExpr {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my $expr = UnaryExpr($self, $tokens);
+    while (match($self, $tokens, '(\\*|div|mod)')) {
+        my $mult_expr = XML::XPath::Expr->new($self);
+        $mult_expr->set_lhs($expr);
+        $mult_expr->set_op($self->{_curr_match});
+        
+        my $rhs = UnaryExpr($self, $tokens);
+        
+        $mult_expr->set_rhs($rhs);
+        $expr = $mult_expr;
+    }
+    
+    return $expr;
+}
+
+sub UnaryExpr {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    if (match($self, $tokens, '-')) {
+        my $expr = XML::XPath::Expr->new($self);
+        $expr->set_lhs(XML::XPath::Number->new(0));
+        $expr->set_op('-');
+        $expr->set_rhs(UnaryExpr($self, $tokens));
+        return $expr;
+    }
+    else {
+        return UnionExpr($self, $tokens);
+    }
+}
+
+sub UnionExpr {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my $expr = PathExpr($self, $tokens);
+    while (match($self, $tokens, '\\|')) {
+        my $un_expr = XML::XPath::Expr->new($self);
+        $un_expr->set_lhs($expr);
+        $un_expr->set_op('|');
+        
+        my $rhs = PathExpr($self, $tokens);
+        
+        $un_expr->set_rhs($rhs);
+        $expr = $un_expr;
+    }
+    
+    return $expr;
+}
+
+sub PathExpr {
+    my ($self, $tokens) = @_;
+
+    debug("in SUB\n");
+    
+    # PathExpr is LocationPath | FilterExpr | FilterExpr '//?' RelativeLocationPath
+    
+    # Since we are being predictive we need to find out which function to call next, then.
+        
+    # LocationPath either starts with "/", "//", ".", ".." or a proper Step.
+    
+    my $expr = XML::XPath::Expr->new($self);
+    
+    my $test = $tokens->[$self->{_tokpos}];
+    
+    # Test for AbsoluteLocationPath and AbbreviatedRelativeLocationPath
+    if ($test =~ /^(\/\/?|\.\.?)$/) {
+        # LocationPath
+        $expr->set_lhs(LocationPath($self, $tokens));
+    }
+    # Test for AxisName::...
+    elsif (is_step($self, $tokens)) {
+        $expr->set_lhs(LocationPath($self, $tokens));
+    }
+    else {
+        # Not a LocationPath
+        # Use FilterExpr instead:
+        
+        $expr = FilterExpr($self, $tokens);
+        if (match($self, $tokens, '//?')) {
+            my $loc_path = XML::XPath::LocationPath->new();
+            push @$loc_path, $expr;
+            if ($self->{_curr_match} eq '//') {
+                push @$loc_path, XML::XPath::Step->new($self, 'descendant-or-self', 
+                                        XML::XPath::Step::test_nt_node);
+            }
+            push @$loc_path, RelativeLocationPath($self, $tokens);
+            my $new_expr = XML::XPath::Expr->new($self);
+            $new_expr->set_lhs($loc_path);
+            return $new_expr;
+        }
+    }
+    
+    return $expr;
+}
+
+sub FilterExpr {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my $expr = PrimaryExpr($self, $tokens);
+    while (match($self, $tokens, '\\[')) {
+        # really PredicateExpr...
+        $expr->push_predicate(Expr($self, $tokens));
+        match($self, $tokens, '\\]', 1);
+    }
+    
+    return $expr;
+}
+
+sub PrimaryExpr {
+    my ($self, $tokens) = @_;
+
+    debug("in SUB\n");
+    
+    my $expr = XML::XPath::Expr->new($self);
+    
+    if (match($self, $tokens, $LITERAL)) {
+        # new Literal with $self->{_curr_match}...
+        $self->{_curr_match} =~ m/^(["'])(.*)\1$/;
+        $expr->set_lhs(XML::XPath::Literal->new($2));
+    }
+    elsif (match($self, $tokens, $NUMBER_RE)) {
+        # new Number with $self->{_curr_match}...
+        $expr->set_lhs(XML::XPath::Number->new($self->{_curr_match}));
+    }
+    elsif (match($self, $tokens, '\\(')) {
+        $expr->set_lhs(Expr($self, $tokens));
+        match($self, $tokens, '\\)', 1);
+    }
+    elsif (match($self, $tokens, "\\\$$QName")) {
+        # new Variable with $self->{_curr_match}...
+        $self->{_curr_match} =~ /^\$(.*)$/;
+        $expr->set_lhs(XML::XPath::Variable->new($self, $1));
+    }
+    elsif (match($self, $tokens, $QName)) {
+        # check match not Node_Type - done in lexer...
+        # new Function
+        my $func_name = $self->{_curr_match};
+        match($self, $tokens, '\\(', 1);
+        $expr->set_lhs(
+                XML::XPath::Function->new(
+                    $self,
+                    $func_name,
+                    Arguments($self, $tokens)
+                )
+            );
+        match($self, $tokens, '\\)', 1);
+    }
+    else {
+        die "Not a PrimaryExpr at ", $tokens->[$self->{_tokpos}], "\n";
+    }
+    
+    return $expr;
+}
+
+sub Arguments {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my @args;
+    
+    if($tokens->[$self->{_tokpos}] eq ')') {
+        return \@args;
+    }
+    
+    push @args, Expr($self, $tokens);
+    while (match($self, $tokens, ',')) {
+        push @args, Expr($self, $tokens);
+    }
+    
+    return \@args;
+}
+
+sub LocationPath {
+    my ($self, $tokens) = @_;
+
+    debug("in SUB\n");
+    
+    my $loc_path = XML::XPath::LocationPath->new();
+    
+    if (match($self, $tokens, '/')) {
+        # root
+        debug("SUB: Matched root\n");
+        push @$loc_path, XML::XPath::Root->new();
+        if (is_step($self, $tokens)) {
+            debug("Next is step\n");
+            push @$loc_path, RelativeLocationPath($self, $tokens);
+        }
+    }
+    elsif (match($self, $tokens, '//')) {
+        # root
+        push @$loc_path, XML::XPath::Root->new();
+        my $optimised = optimise_descendant_or_self($self, $tokens);
+        if (!$optimised) {
+            push @$loc_path, XML::XPath::Step->new($self, 'descendant-or-self',
+                                XML::XPath::Step::test_nt_node);
+            push @$loc_path, RelativeLocationPath($self, $tokens);
+        }
+        else {
+            push @$loc_path, $optimised, RelativeLocationPath($self, $tokens);
+        }
+    }
+    else {
+        push @$loc_path, RelativeLocationPath($self, $tokens);
+    }
+    
+    return $loc_path;
+}
+
+sub optimise_descendant_or_self {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my $tokpos = $self->{_tokpos};
+    
+    # // must be followed by a Step.
+    if ($tokens->[$tokpos+1] && $tokens->[$tokpos+1] eq '[') {
+        # next token is a predicate
+        return;
+    }
+    elsif ($tokens->[$tokpos] =~ /^\.\.?$/) {
+        # abbreviatedStep - can't optimise.
+        return;
+    }                                                                                              
+    else {
+        debug("Trying to optimise //\n");
+        my $step = Step($self, $tokens);
+        if ($step->{axis} ne 'child') {
+            # can't optimise axes other than child for now...
+            $self->{_tokpos} = $tokpos;
+            return;
+        }
+        $step->{axis} = 'descendant';
+        $step->{axis_method} = 'axis_descendant';
+        $self->{_tokpos}--;
+        $tokens->[$self->{_tokpos}] = '.';
+        return $step;
+    }
+}
+
+sub RelativeLocationPath {
+    my ($self, $tokens) = @_;
+    
+    debug("in SUB\n");
+    
+    my @steps;
+    
+    push @steps, Step($self, $tokens);
+    while (match($self, $tokens, '//?')) {
+        if ($self->{_curr_match} eq '//') {
+            my $optimised = optimise_descendant_or_self($self, $tokens);
+            if (!$optimised) {
+                push @steps, XML::XPath::Step->new($self, 'descendant-or-self',
+                                        XML::XPath::Step::test_nt_node);
+            }
+            else {
+                push @steps, $optimised;
+            }
+        }
+        push @steps, Step($self, $tokens);
+        if (@steps > 1 && 
+                $steps[-1]->{axis} eq 'self' && 
+                $steps[-1]->{test} == XML::XPath::Step::test_nt_node) {
+            pop @steps;
+        }
+    }
+    
+    return @steps;
+}
+
+sub Step {
+    my ($self, $tokens) = @_;
+
+    debug("in SUB\n");
+    
+    if (match($self, $tokens, '\\.')) {
+        # self::node()
+        return XML::XPath::Step->new($self, 'self', XML::XPath::Step::test_nt_node);
+    }
+    elsif (match($self, $tokens, '\\.\\.')) {
+        # parent::node()
+        return XML::XPath::Step->new($self, 'parent', XML::XPath::Step::test_nt_node);
+    }
+    else {
+        # AxisSpecifier NodeTest Predicate(s?)
+        my $token = $tokens->[$self->{_tokpos}];
+        
+        debug("SUB: Checking $token\n");
+        
+        my $step;
+        if ($token eq 'processing-instruction') {
+            $self->{_tokpos}++;
+            match($self, $tokens, '\\(', 1);
+            match($self, $tokens, $LITERAL);
+            $self->{_curr_match} =~ /^["'](.*)["']$/;
+            $step = XML::XPath::Step->new($self, 'child',
+                                    XML::XPath::Step::test_nt_pi,
+                        XML::XPath::Literal->new($1));
+            match($self, $tokens, '\\)', 1);
+        }
+        elsif ($token =~ /^\@($NCWild|$QName|$QNWild)$/o) {
+            $self->{_tokpos}++;
+                        if ($token eq '@*') {
+                            $step = XML::XPath::Step->new($self,
+                                    'attribute',
+                                    XML::XPath::Step::test_attr_any,
+                                    '*');
+                        }
+                        elsif ($token =~ /^\@($NCName):\*$/o) {
+                            $step = XML::XPath::Step->new($self,
+                                    'attribute',
+                                    XML::XPath::Step::test_attr_ncwild,
+                                    $1);
+                        }
+                        elsif ($token =~ /^\@($QName)$/o) {
+                            $step = XML::XPath::Step->new($self,
+                                    'attribute',
+                                    XML::XPath::Step::test_attr_qname,
+                                    $1);
+                        }
+        }
+        elsif ($token =~ /^($NCName):\*$/o) { # ns:*
+            $self->{_tokpos}++;
+            $step = XML::XPath::Step->new($self, 'child', 
+                                XML::XPath::Step::test_ncwild,
+                                $1);
+        }
+        elsif ($token =~ /^$QNWild$/o) { # *
+            $self->{_tokpos}++;
+            $step = XML::XPath::Step->new($self, 'child', 
+                                XML::XPath::Step::test_any,
+                                $token);
+        }
+        elsif ($token =~ /^$QName$/o) { # name:name
+            $self->{_tokpos}++;
+            $step = XML::XPath::Step->new($self, 'child', 
+                                XML::XPath::Step::test_qname,
+                                $token);
+        }
+        elsif ($token eq 'comment()') {
+                    $self->{_tokpos}++;
+            $step = XML::XPath::Step->new($self, 'child',
+                            XML::XPath::Step::test_nt_comment);
+        }
+        elsif ($token eq 'text()') {
+            $self->{_tokpos}++;
+            $step = XML::XPath::Step->new($self, 'child',
+                    XML::XPath::Step::test_nt_text);
+        }
+        elsif ($token eq 'node()') {
+            $self->{_tokpos}++;
+            $step = XML::XPath::Step->new($self, 'child',
+                    XML::XPath::Step::test_nt_node);
+        }
+        elsif ($token eq 'processing-instruction()') {
+            $self->{_tokpos}++;
+            $step = XML::XPath::Step->new($self, 'child',
+                    XML::XPath::Step::test_nt_pi);
+        }
+        elsif ($token =~ /^$AXIS_NAME($NCWild|$QName|$QNWild|$NODE_TYPE)$/o) {
+                    my $axis = $1;
+                    $self->{_tokpos}++;
+                    $token = $2;
+            if ($token eq 'processing-instruction') {
+                match($self, $tokens, '\\(', 1);
+                match($self, $tokens, $LITERAL);
+                $self->{_curr_match} =~ /^["'](.*)["']$/;
+                $step = XML::XPath::Step->new($self, $axis,
+                                        XML::XPath::Step::test_nt_pi,
+                            XML::XPath::Literal->new($1));
+                match($self, $tokens, '\\)', 1);
+            }
+            elsif ($token =~ /^($NCName):\*$/o) { # ns:*
+                $step = XML::XPath::Step->new($self, $axis, 
+                                    (($axis eq 'attribute') ? 
+                                    XML::XPath::Step::test_attr_ncwild
+                                        :
+                                    XML::XPath::Step::test_ncwild),
+                                    $1);
+            }
+            elsif ($token =~ /^$QNWild$/o) { # *
+                $step = XML::XPath::Step->new($self, $axis, 
+                                    (($axis eq 'attribute') ?
+                                    XML::XPath::Step::test_attr_any
+                                        :
+                                    XML::XPath::Step::test_any),
+                                    $token);
+            }
+            elsif ($token =~ /^$QName$/o) { # name:name
+                $step = XML::XPath::Step->new($self, $axis, 
+                                    (($axis eq 'attribute') ?
+                                    XML::XPath::Step::test_attr_qname
+                                        :
+                                    XML::XPath::Step::test_qname),
+                                    $token);
+            }
+            elsif ($token eq 'comment()') {
+                $step = XML::XPath::Step->new($self, $axis,
+                                XML::XPath::Step::test_nt_comment);
+            }
+            elsif ($token eq 'text()') {
+                $step = XML::XPath::Step->new($self, $axis,
+                        XML::XPath::Step::test_nt_text);
+            }
+            elsif ($token eq 'node()') {
+                $step = XML::XPath::Step->new($self, $axis,
+                        XML::XPath::Step::test_nt_node);
+            }
+            elsif ($token eq 'processing-instruction()') {
+                $step = XML::XPath::Step->new($self, $axis,
+                        XML::XPath::Step::test_nt_pi);
+            }
+            else {
+                die "Shouldn't get here";
+            }
+        }
+        else {
+            die "token $token doesn't match format of a 'Step'\n";
+        }
+        
+        while (match($self, $tokens, '\\[')) {
+            push @{$step->{predicates}}, Expr($self, $tokens);
+            match($self, $tokens, '\\]', 1);
+        }
+        
+        return $step;
+    }
+}
+
+sub is_step {
+    my ($self, $tokens) = @_;
+    
+    my $token = $tokens->[$self->{_tokpos}];
+    
+    return unless defined $token;
+        
+    debug("SUB: Checking if '$token' is a step\n");
+    
+        local $^W;
+        
+    if ($token eq 'processing-instruction') {
+        return 1;
+    }
+    elsif ($token =~ /^\@($NCWild|$QName|$QNWild)$/o) {
+        return 1;
+    }
+    elsif ($token =~ /^($NCWild|$QName|$QNWild)$/o && $tokens->[$self->{_tokpos}+1] ne '(') {
+        return 1;
+    }
+    elsif ($token =~ /^$NODE_TYPE$/o) {
+        return 1;
+    }
+    elsif ($token =~ /^$AXIS_NAME($NCWild|$QName|$QNWild|$NODE_TYPE)$/o) {
+        return 1;
+    }
+    
+    debug("SUB: '$token' not a step\n");
+
+    return;
+}
+
+sub debug {
+    return unless $XML::XPath::Debug;
+    
+    my ($pkg, $file, $line, $sub) = caller(1);
+    
+    $sub =~ s/^$pkg\:://;
+    
+    while (@_) {
+        my $x = shift;
+        $x =~ s/\bPKG\b/$pkg/g;
+        $x =~ s/\bLINE\b/$line/g;
+        $x =~ s/\bSUB\b/$sub/g;
+        print STDERR $x;
+    }
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/PerlSAX.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/PerlSAX.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/PerlSAX.pm	(revision 10506)
@@ -0,0 +1,166 @@
+# $Id$
+
+package XML::XPath::PerlSAX;
+use XML::XPath::XMLParser;
+use strict;
+
+sub new {
+	my $class = shift;
+	my %args = @_;
+	bless \%args, $class;
+}
+
+sub parse {
+	my $self = shift;
+
+	die "XML::XPath::PerlSAX: parser instance ($self) already parsing\n"
+		if (defined $self->{ParseOptions});
+
+	# If there's one arg and it's an array ref, assume it's a node we're parsing
+	my $args;
+	if (@_ == 1 && ref($_[0]) =~ /^(text|comment|element|namespace|attribute|pi)$/) {
+#		warn "Parsing node\n";
+		my $node = shift;
+#		warn "PARSING: $node ", XML::XPath::XMLParser::as_string($node), "\n\n";
+		$args = { Source => { Node => $node } };
+	}
+	else {
+		$args = (@_ == 1) ? shift : { @_ };
+	}
+
+	my $parse_options = { %$self, %$args };
+	$self->{ParseOptions} = $parse_options;
+
+	# ensure that we have at least one source
+	if (!defined $parse_options->{Source} ||
+		!defined $parse_options->{Source}{Node}) {
+		die "XML::XPath::PerlSAX: no source defined for parse\n";
+	}
+
+	# assign default Handler to any undefined handlers
+	if (defined $parse_options->{Handler}) {
+		$parse_options->{DocumentHandler} = $parse_options->{Handler}
+			if (!defined $parse_options->{DocumentHandler});
+	}
+
+	# ensure that we have a DocumentHandler
+	if (!defined $parse_options->{DocumentHandler}) {
+		die "XML::XPath::PerlSAX: no Handler or DocumentHandler defined for parse\n";
+	}
+
+	# cache DocumentHandler in self for callbacks
+	$self->{DocumentHandler} = $parse_options->{DocumentHandler};
+
+	if ((ref($parse_options->{Source}{Node}) eq 'element') &&
+			!($parse_options->{Source}{Node}->[node_parent])) {
+		# Got root node
+		$self->{DocumentHandler}->start_document( { } );
+		$self->parse_node($parse_options->{Source}{Node});
+		return $self->{DocumentHandler}->end_document( { } );
+	}
+	else {
+		$self->parse_node($parse_options->{Source}{Node});
+	}
+
+	# clean up parser instance
+	delete $self->{ParseOptions};
+	delete $self->{DocumentHandler};
+
+}
+
+sub parse_node {
+	my $self = shift;
+	my $node = shift;
+#	warn "parse_node $node\n";
+	if (ref($node) eq 'element' && $node->[node_parent]) {
+		# bundle up attributes
+		my @attribs;
+		foreach my $attr (@{$node->[node_attribs]}) {
+			if ($attr->[node_prefix]) {
+				push @attribs, $attr->[node_prefix] . ":" . $attr->[node_key];
+			}
+			else {
+				push @attribs, $attr->[node_key];
+			}
+			push @attribs, $attr->[node_value];
+		}
+		
+		$self->{DocumentHandler}->start_element(
+				{ Name => $node->[node_name],
+				  Attributes => \@attribs,
+				}
+			);
+		foreach my $kid (@{$node->[node_children]}) {
+			$self->parse_node($kid);
+		}
+		$self->{DocumentHandler}->end_element(
+				{
+					Name => $node->[node_name],
+				}
+			);
+	}
+	elsif (ref($node) eq 'text') {
+		$self->{DocumentHandler}->characters($node->[node_text]);
+	}
+	elsif (ref($node) eq 'comment') {
+		$self->{DocumentHandler}->comment($node->[node_comment]);
+	}
+	elsif (ref($node) eq 'pi') {
+		$self->{DocumentHandler}->processing_instruction(
+				{
+					Target => $node->[node_target],
+					Data => $node->[node_data]
+				}
+			);
+	}
+	elsif (ref($node) eq 'element') { # root node
+		# just do kids
+		foreach my $kid (@{$node->[node_children]}) {
+			$self->parse_node($kid);
+		}
+	}
+	else {
+		die "Unknown node type: '", ref($node), "' ", scalar(@$node), "\n";
+	}
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+XML::XPath::PerlSAX - A PerlSAX event generator for my wierd node structure
+
+=head1 SYNOPSIS
+
+	use XML::XPath;
+	use XML::XPath::PerlSAX;
+	use XML::DOM::PerlSAX;
+	
+	my $xp = XML::XPath->new(filename => 'test.xhtml');
+	my $paras = $xp->find('/html/body/p');
+	
+	my $handler = XML::DOM::PerlSAX->new();
+	my $generator = XML::XPath::PerlSAX->new( Handler => $handler );
+	
+	foreach my $node ($paras->get_nodelist) {
+		my $domtree = $generator->parse($node);
+		# do something with $domtree
+	}
+
+=head1 DESCRIPTION
+
+This module generates PerlSAX events to pass to a PerlSAX handler such
+as XML::DOM::PerlSAX. It operates specifically on my wierd tree format.
+
+Unfortunately SAX doesn't seem to cope with namespaces, so these are
+lost completely. I believe SAX2 is doing namespaces.
+
+=head1 Other
+
+The XML::DOM::PerlSAX handler I tried was completely broken (didn't even
+compile before I patched it a bit), so I don't know how correct this
+is or how far it will work.
+
+This software may only be distributed as part of the XML::XPath package.
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Root.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Root.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Root.pm	(revision 10506)
@@ -0,0 +1,36 @@
+# $Id$
+
+package XML::XPath::Root;
+use strict;
+use XML::XPath::XMLParser;
+use XML::XPath::NodeSet;
+
+sub new {
+	my $class = shift;
+	my $self; # actually don't need anything here - just a placeholder
+	bless \$self, $class;
+}
+
+sub as_string {
+	# do nothing
+}
+
+sub as_xml {
+    return "<Root/>\n";
+}
+
+sub evaluate {
+	my $self = shift;
+	my $nodeset = shift;
+	
+#	warn "Eval ROOT\n";
+	
+	# must only ever occur on 1 node
+	die "Can't go to root on > 1 node!" unless $nodeset->size == 1;
+	
+	my $newset = XML::XPath::NodeSet->new();
+	$newset->push($nodeset->get_node(1)->getRootNode());
+	return $newset;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Step.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Step.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Step.pm	(revision 10506)
@@ -0,0 +1,519 @@
+# $Id$
+
+package XML::XPath::Step;
+use XML::XPath::Parser;
+use XML::XPath::Node;
+use strict;
+
+# the beginnings of using XS for this file...
+# require DynaLoader;
+# use vars qw/$VERSION @ISA/;
+# $VERSION = '1.0';
+# @ISA = qw(DynaLoader);
+# 
+# bootstrap XML::XPath::Step $VERSION;
+
+sub test_qname () { 0; } # Full name
+sub test_ncwild () { 1; } # NCName:*
+sub test_any () { 2; } # *
+
+sub test_attr_qname () { 3; } # @ns:attrib
+sub test_attr_ncwild () { 4; } # @nc:*
+sub test_attr_any () { 5; } # @*
+
+sub test_nt_comment () { 6; } # comment()
+sub test_nt_text () { 7; } # text()
+sub test_nt_pi () { 8; } # processing-instruction()
+sub test_nt_node () { 9; } # node()
+
+sub new {
+    my $class = shift;
+    my ($pp, $axis, $test, $literal) = @_;
+    my $axis_method = "axis_$axis";
+    $axis_method =~ tr/-/_/;
+    my $self = {
+        pp => $pp, # the XML::XPath::Parser class
+        axis => $axis,
+        axis_method => $axis_method,
+        test => $test,
+        literal => $literal,
+        predicates => [],
+        };
+    bless $self, $class;
+}
+
+sub as_string {
+    my $self = shift;
+    my $string = $self->{axis} . "::";
+
+    my $test = $self->{test};
+        
+    if ($test == test_nt_pi) {
+        $string .= 'processing-instruction(';
+        if ($self->{literal}->value) {
+            $string .= $self->{literal}->as_string;
+        }
+        $string .= ")";
+    }
+    elsif ($test == test_nt_comment) {
+        $string .= 'comment()';
+    }
+    elsif ($test == test_nt_text) {
+        $string .= 'text()';
+    }
+    elsif ($test == test_nt_node) {
+        $string .= 'node()';
+    }
+    elsif ($test == test_ncwild || $test == test_attr_ncwild) {
+        $string .= $self->{literal} . ':*';
+    }
+    else {
+        $string .= $self->{literal};
+    }
+    
+    foreach (@{$self->{predicates}}) {
+        next unless defined $_;
+        $string .= "[" . $_->as_string . "]";
+    }
+    return $string;
+}
+
+sub as_xml {
+    my $self = shift;
+    my $string = "<Step>\n";
+    $string .= "<Axis>" . $self->{axis} . "</Axis>\n";
+    my $test = $self->{test};
+    
+    $string .= "<Test>";
+    
+    if ($test == test_nt_pi) {
+        $string .= '<processing-instruction';
+        if ($self->{literal}->value) {
+            $string .= '>';
+            $string .= $self->{literal}->as_string;
+            $string .= '</processing-instruction>';
+        }
+        else {
+            $string .= '/>';
+        }
+    }
+    elsif ($test == test_nt_comment) {
+        $string .= '<comment/>';
+    }
+    elsif ($test == test_nt_text) {
+        $string .= '<text/>';
+    }
+    elsif ($test == test_nt_node) {
+        $string .= '<node/>';
+    }
+    elsif ($test == test_ncwild || $test == test_attr_ncwild) {
+        $string .= '<namespace-prefix>' . $self->{literal} . '</namespace-prefix>';
+    }
+    else {
+        $string .= '<nametest>' . $self->{literal} . '</nametest>';
+    }
+    
+    $string .= "</Test>\n";
+    
+    foreach (@{$self->{predicates}}) {
+        next unless defined $_;
+        $string .= "<Predicate>\n" . $_->as_xml() . "</Predicate>\n";
+    }
+    
+    $string .= "</Step>\n";
+    
+    return $string;
+}
+
+sub evaluate {
+    my $self = shift;
+    my $from = shift; # context nodeset
+    
+#    warn "Step::evaluate called with ", $from->size, " length nodeset\n";
+    
+    $self->{pp}->set_context_set($from);
+    
+    my $initial_nodeset = XML::XPath::NodeSet->new();
+    
+    # See spec section 2.1, paragraphs 3,4,5:
+    # The node-set selected by the location step is the node-set
+    # that results from generating an initial node set from the
+    # axis and node-test, and then filtering that node-set by
+    # each of the predicates in turn.
+    
+    # Make each node in the nodeset be the context node, one by one
+    for(my $i = 1; $i <= $from->size; $i++) {
+        $self->{pp}->set_context_pos($i);
+        $initial_nodeset->append($self->evaluate_node($from->get_node($i)));
+    }
+    
+#    warn "Step::evaluate initial nodeset size: ", $initial_nodeset->size, "\n";
+    
+    $self->{pp}->set_context_set(undef);
+
+    $initial_nodeset->sort;
+        
+    return $initial_nodeset;
+}
+
+# Evaluate the step against a particular node
+sub evaluate_node {
+    my $self = shift;
+    my $context = shift;
+    
+#    warn "Evaluate node: $self->{axis}\n";
+    
+#    warn "Node: ", $context->[node_name], "\n";
+    
+    my $method = $self->{axis_method};
+    
+    my $results = XML::XPath::NodeSet->new();
+    no strict 'refs';
+    eval {
+        $method->($self, $context, $results);
+    };
+    if ($@) {
+        die "axis $method not implemented [$@]\n";
+    }
+    
+#    warn("results: ", join('><', map {$_->string_value} @$results), "\n");
+    # filter initial nodeset by each predicate
+    foreach my $predicate (@{$self->{predicates}}) {
+        $results = $self->filter_by_predicate($results, $predicate);
+    }
+    
+    return $results;
+}
+
+sub axis_ancestor {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    my $parent = $context->getParentNode;
+        
+    START:
+    return $results unless $parent;
+    if (node_test($self, $parent)) {
+        $results->push($parent);
+    }
+    $parent = $parent->getParentNode;
+    goto START;
+}
+
+sub axis_ancestor_or_self {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    START:
+    return $results unless $context;
+    if (node_test($self, $context)) {
+        $results->push($context);
+    }
+    $context = $context->getParentNode;
+    goto START;
+}
+
+sub axis_attribute {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    foreach my $attrib (@{$context->getAttributes}) {
+        if ($self->test_attribute($attrib)) {
+            $results->push($attrib);
+        }
+    }
+}
+
+sub axis_child {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    foreach my $node (@{$context->getChildNodes}) {
+        if (node_test($self, $node)) {
+            $results->push($node);
+        }
+    }
+}
+
+sub axis_descendant {
+    my $self = shift;
+    my ($context, $results) = @_;
+
+    my @stack = $context->getChildNodes;
+
+    while (@stack) {
+        my $node = pop @stack;
+        if (node_test($self, $node)) {
+            $results->unshift($node);
+        }
+        push @stack, $node->getChildNodes;
+    }
+}
+
+sub axis_descendant_or_self {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    my @stack = ($context);
+    
+    while (@stack) {
+        my $node = pop @stack;
+        if (node_test($self, $node)) {
+            $results->unshift($node);
+        }
+        push @stack, $node->getChildNodes;
+    }
+}
+
+sub axis_following {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    START:
+
+    my $parent = $context->getParentNode;
+    return $results unless $parent;
+        
+    while ($context = $context->getNextSibling) {
+        axis_descendant_or_self($self, $context, $results);
+    }
+
+    $context = $parent;
+    goto START;
+}
+
+sub axis_following_sibling {
+    my $self = shift;
+    my ($context, $results) = @_;
+
+    while ($context = $context->getNextSibling) {
+        if (node_test($self, $context)) {
+            $results->push($context);
+        }
+    }
+}
+
+sub axis_namespace {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    return $results unless $context->isElementNode;
+    foreach my $ns (@{$context->getNamespaces}) {
+        if ($self->test_namespace($ns)) {
+            $results->push($ns);
+        }
+    }
+}
+
+sub axis_parent {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    my $parent = $context->getParentNode;
+    return $results unless $parent;
+    if (node_test($self, $parent)) {
+        $results->push($parent);
+    }
+}
+
+sub axis_preceding {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    # all preceding nodes in document order, except ancestors
+    
+    START:
+
+    my $parent = $context->getParentNode;
+    return $results unless $parent;
+
+    while ($context = $context->getPreviousSibling) {
+        axis_descendant_or_self($self, $context, $results);
+    }
+    
+    $context = $parent;
+    goto START;
+}
+
+sub axis_preceding_sibling {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    while ($context = $context->getPreviousSibling) {
+        if (node_test($self, $context)) {
+            $results->push($context);
+        }
+    }
+}
+
+sub axis_self {
+    my $self = shift;
+    my ($context, $results) = @_;
+    
+    if (node_test($self, $context)) {
+        $results->push($context);
+    }
+}
+    
+sub node_test {
+    my $self = shift;
+    my $node = shift;
+    
+    # if node passes test, return true
+    
+    my $test = $self->{test};
+
+    return 1 if $test == test_nt_node;
+        
+    if ($test == test_any) {
+        return 1 if $node->isElementNode && defined $node->getName;
+    }
+        
+    local $^W;
+
+    if ($test == test_ncwild) {
+        return unless $node->isElementNode;
+        my $match_ns = $self->{pp}->get_namespace($self->{literal}, $node);
+        if (my $node_nsnode = $node->getNamespace()) {
+            return 1 if $match_ns eq $node_nsnode->getValue;
+        }
+    }
+    elsif ($test == test_qname) {
+        return unless $node->isElementNode;
+        if ($self->{literal} =~ /:/) {
+            my ($prefix, $name) = split(':', $self->{literal}, 2);
+            my $match_ns = $self->{pp}->get_namespace($prefix, $node);
+            if (my $node_nsnode = $node->getNamespace()) {
+#                warn "match: '$self->{literal}' match NS: '$match_ns' got NS: '", $node_nsnode->getValue, "'\n";
+                return 1 if ($match_ns eq $node_nsnode->getValue) &&
+                        ($name eq $node->getLocalName);
+            }
+        }
+        else {
+#            warn "Node test: ", $node->getName, "\n";
+            return 1 if $node->getName eq $self->{literal};
+        }
+    }
+    elsif ($test == test_nt_text) {
+        return 1 if $node->isTextNode;
+    }
+    elsif ($test == test_nt_comment) {
+        return 1 if $node->isCommentNode;
+    }
+#     elsif ($test == test_nt_pi && !$self->{literal}) {
+#         warn "Unreachable code???";
+#         return 1 if $node->isPINode;
+#     }
+    elsif ($test == test_nt_pi) {
+        return unless $node->isPINode;
+        if (my $val = $self->{literal}->value) {
+            return 1 if $node->getTarget eq $val;
+        }
+        else {
+            return 1;
+        }
+    }
+    
+    return; # fallthrough returns false
+}
+
+sub test_attribute {
+    my $self = shift;
+    my $node = shift;
+    
+#    warn "test_attrib: '$self->{test}' against: ", $node->getName, "\n";
+#    warn "node type: $node->[node_type]\n";
+    
+    my $test = $self->{test};
+    
+    return 1 if ($test == test_attr_any) || ($test == test_nt_node);
+        
+    if ($test == test_attr_ncwild) {
+        my $match_ns = $self->{pp}->get_namespace($self->{literal}, $node);
+        if (my $node_nsnode = $node->getNamespace()) {
+            return 1 if $match_ns eq $node_nsnode->getValue;
+        }
+    }
+    elsif ($test == test_attr_qname) {
+        if ($self->{literal} =~ /:/) {
+            my ($prefix, $name) = split(':', $self->{literal}, 2);
+            my $match_ns = $self->{pp}->get_namespace($prefix, $node);
+            if (my $node_nsnode = $node->getNamespace()) {
+                return 1 if ($match_ns eq $node_nsnode->getValue) &&
+                        ($name eq $node->getLocalName);
+            }
+        }
+        else {
+            return 1 if $node->getName eq $self->{literal};
+        }
+    }
+    
+    return; # fallthrough returns false
+}
+
+sub test_namespace {
+    my $self = shift;
+    my $node = shift;
+    
+    # Not sure if this is correct. The spec seems very unclear on what
+    # constitutes a namespace test... bah!
+    
+    my $test = $self->{test};
+    
+    return 1 if $test == test_any; # True for all nodes of principal type
+    
+    if ($test == test_any) {
+        return 1;
+    }
+    elsif ($self->{literal} eq $node->getExpanded) {
+        return 1;
+    }
+    
+    return;
+}
+
+sub filter_by_predicate {
+    my $self = shift;
+    my ($nodeset, $predicate) = @_;
+    
+    # See spec section 2.4, paragraphs 2 & 3:
+    # For each node in the node-set to be filtered, the predicate Expr
+    # is evaluated with that node as the context node, with the number
+    # of nodes in the node set as the context size, and with the
+    # proximity position of the node in the node set with respect to
+    # the axis as the context position.
+    
+    if (!ref($nodeset)) { # use ref because nodeset has a bool context
+        die "No nodeset!!!";
+    }
+    
+#    warn "Filter by predicate: $predicate\n";
+    
+    my $newset = XML::XPath::NodeSet->new();
+    
+    for(my $i = 1; $i <= $nodeset->size; $i++) {
+        # set context set each time 'cos a loc-path in the expr could change it
+        $self->{pp}->set_context_set($nodeset);
+        $self->{pp}->set_context_pos($i);
+        my $result = $predicate->evaluate($nodeset->get_node($i));
+        if ($result->isa('XML::XPath::Boolean')) {
+            if ($result->value) {
+                $newset->push($nodeset->get_node($i));
+            }
+        }
+        elsif ($result->isa('XML::XPath::Number')) {
+            if ($result->value == $i) {
+                $newset->push($nodeset->get_node($i));
+            }
+        }
+        else {
+            if ($result->to_boolean->value) {
+                $newset->push($nodeset->get_node($i));
+            }
+        }
+    }
+    
+    return $newset;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Twig.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Twig.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Twig.pm	(revision 10506)
@@ -0,0 +1,10940 @@
+# $Id$
+#
+# Copyright (c) 1999-2004 Michel Rodriguez
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+#
+
+# This is created in the caller's space
+BEGIN
+{ sub ::PCDATA { '#PCDATA' } 
+  sub ::CDATA  { '#CDATA'  } 
+}
+
+
+######################################################################
+package XML::Twig;
+######################################################################
+
+require 5.004;
+use strict; 
+use UNIVERSAL qw( isa ) ;
+
+use vars qw($VERSION @ISA %valid_option);
+use Carp;
+
+#start-extract twig_global
+
+# constants: element types
+use constant (PCDATA  => '#PCDATA');
+use constant (CDATA   => '#CDATA');
+use constant (PI      => '#PI');
+use constant (COMMENT => '#COMMENT');
+use constant (ENT     => '#ENT');
+
+# element classes
+use constant (ELT     => '#ELT');
+use constant (TEXT    => '#TEXT');
+
+# element properties
+use constant (ASIS    => '#ASIS');
+use constant (EMPTY   => '#EMPTY');
+
+#end-extract twig_global
+
+# used in parseurl to set the buffer size to the same size as in XML::Parser::Expat
+use constant (BUFSIZE => 32768);
+
+
+# used to store the gi's
+my %gi2index;   # gi => index
+my @index2gi;   # list of gi's
+my $SPECIAL_GI; # first non-special gi;
+my %base_ent;   # base entity character => replacement
+
+# flag, set to true if the weaken sub is available
+use vars qw( $weakrefs);
+
+#start-extract twig_global
+my $REG_NAME       = q{(?:(?:[^\W\d]|[:#])(?:[\w.-]*:)?[\w.-]*)};     # xml name
+my $REG_NAME_W     = q{(?:(?:[^\W\d_]|[:#])(?:[\w.-]*:)?[\w.-]*|\*)}; # name or wildcard (* or '')
+my $REG_REGEXP     = q{(?:/(?:[^\\/]|\\.)*/[eimsox]*)};   # regexp
+my $REG_REGEXP_EXP = q{(?:(?:[^\\/]|\\.)*)};              # content of a regexp
+my $REG_REGEXP_MOD = q{(?:[eimso]*)};                     # regexp modifiers
+my $REG_MATCH      = q{[!=]~};                            # match (or not)
+my $REG_STRING     = q{(?:"(?:[^\\"]|\\.)*"|'(?:[^\\']|\\.)*')};  # string (simple or double quoted)
+my $REG_NUMBER     = q{(?:\d+(?:\.\d*)?|\.\d+)};          # number
+my $REG_VALUE      = qq{(?:$REG_STRING|$REG_NUMBER)};     # value
+my $REG_OP         = q{=|==|!=|>|<|>=|<=|eq|ne|lt|gt|le|ge}; # op
+
+#end-extract twig_global
+
+my $parser_version;
+my( $FB_HTMLCREF, $FB_XMLCREF);
+
+
+BEGIN
+{ 
+$VERSION = '3.15';
+
+use XML::Parser;
+my $needVersion = '2.23';
+$parser_version= $XML::Parser::VERSION;
+croak "need at least XML::Parser version $needVersion" unless $parser_version >= $needVersion;
+
+if( $] >= 5.008) 
+  { eval "use Encode qw( :fallback_all)";
+    $FB_XMLCREF  = 0x0400; # Encode::FB_XMLCREF;
+    $FB_HTMLCREF = 0x0200; #Encode::FB_HTMLCREF;
+  }
+
+# test whether we can use weak references
+# set local empty signal handler to trap error messages
+{ local $SIG{__DIE__};
+  if( eval 'require Scalar::Util') { import Scalar::Util qw(weaken); $weakrefs= 1; }
+  elsif( eval 'require WeakRef')   { import WeakRef; $weakrefs= 1;                 }
+  else                             { $weakrefs= 0;                                 } 
+}
+
+import XML::Twig::Elt;
+import XML::Twig::Entity;
+import XML::Twig::Entity_list;
+
+# used to store the gi's
+# should be set for each twig really, at least when there are several
+# the init ensures that special gi's are always the same
+
+# gi => index
+# do NOT use => or the constants become quoted!
+%XML::Twig::gi2index=( PCDATA, 0, CDATA, 1, PI, 2, COMMENT, 3, ENT, 4); 
+# list of gi's
+@XML::Twig::index2gi=( PCDATA, CDATA, PI, COMMENT, ENT);
+
+# gi's under this value are special 
+$XML::Twig::SPECIAL_GI= @XML::Twig::index2gi;
+
+%XML::Twig::base_ent= ( '>' => '&gt;', '<' => '&lt;', '&' => '&amp;', "'" => '&apos;', '"' => '&quot;',);
+
+# now set some aliases
+*find_nodes           = *get_xpath;               # same as XML::XPath
+*findnodes            = *get_xpath;               # same as XML::LibXML
+*getElementsByTagName = *descendants;
+*descendants_or_self  = *descendants;             # valid in XML::Twig, not in XML::Twig::Elt
+*find_by_tag_name     = *descendants;
+*getElementById       = *elt_id;
+*getEltById           = *elt_id;
+*toString             = *sprint;
+}
+
+@ISA = qw(XML::Parser);
+
+# fake gi's used in twig_handlers and start_tag_handlers
+my $ALL    = '_all_';     # the associated function is always called
+my $DEFAULT= '_default_'; # the function is called if no other handler has been
+
+# some defaults
+my $COMMENTS_DEFAULT= 'keep';
+my $PI_DEFAULT      = 'keep';
+
+
+# handlers used in regular mode
+my %twig_handlers=( Start      => \&_twig_start, 
+                    End        => \&_twig_end, 
+                    Char       => \&_twig_char, 
+                    Entity     => \&_twig_entity, 
+                    XMLDecl    => \&_twig_xmldecl, 
+                    Doctype    => \&_twig_doctype, 
+                    Element    => \&_twig_element, 
+                    Attlist    => \&_twig_attlist, 
+                    CdataStart => \&_twig_cdatastart, 
+                    CdataEnd   => \&_twig_cdataend, 
+                    Proc       => \&_twig_pi,
+                    Comment    => \&_twig_comment,
+                    Default    => \&_twig_default,
+      );
+
+# handlers used when twig_roots is used and we are outside of the roots
+my %twig_handlers_roots=
+  ( Start      => \&_twig_start_check_roots, 
+    End        => \&_twig_end_check_roots, 
+    Doctype    => \&_twig_doctype, 
+    Char       => undef, Entity     => undef, XMLDecl    => \&_twig_xmldecl, 
+    Element    => undef, Attlist    => undef, CdataStart => undef, 
+    CdataEnd   => undef, Proc       => undef, Comment    => undef, 
+    Proc       => \&_twig_pi_check_roots,
+    Default    =>  sub {}, # hack needed for XML::Parser 2.27
+  );
+
+# handlers used when twig_roots and print_outside_roots are used and we are
+# outside of the roots
+my %twig_handlers_roots_print_2_30=
+  ( Start      => \&_twig_start_check_roots_print, 
+    End        => \&_twig_end_check_roots_print, 
+    Char       => \&_twig_print, 
+    # I have no idea why I should not be using this handler!
+    Entity     => \&_twig_print_entity, 
+    XMLDecl    => \&_twig_print,
+    Doctype   =>  \&_twig_print_doctype, # because recognized_string is broken here
+    # Element    => \&_twig_print, Attlist    => \&_twig_print, 
+    CdataStart => \&_twig_print, CdataEnd   => \&_twig_print, 
+    Proc       => \&_twig_print, Comment    => \&_twig_print, 
+    Default    => \&_twig_print_check_doctype,
+  );
+
+# handlers used when twig_roots, print_outside_roots and keep_encoding are used
+# and we are outside of the roots
+my %twig_handlers_roots_print_original_2_30=
+  ( Start      => \&_twig_start_check_roots_print_original, 
+    End        => \&_twig_end_check_roots_print_original, 
+    Char       => \&_twig_print_original, 
+    # I have no idea why I should not be using this handler!
+    #Entity     => \&_twig_print_original, 
+    ExternEnt  => \&_twig_print_entity,
+    XMLDecl    => \&_twig_print_original, 
+    Doctype    => \&_twig_print_original_doctype,  # because original_string is broken here
+    Element    => \&_twig_print_original, Attlist   => \&_twig_print_original,
+    CdataStart => \&_twig_print_original, CdataEnd  => \&_twig_print_original,
+    Proc       => \&_twig_print_original, Comment   => \&_twig_print_original,
+    Default    => \&_twig_print_original_check_doctype, 
+  );
+
+# handlers used when twig_roots and print_outside_roots are used and we are
+# outside of the roots
+my %twig_handlers_roots_print_2_27=
+  ( Start      => \&_twig_start_check_roots_print, 
+    End        => \&_twig_end_check_roots_print, 
+    Char       => \&_twig_print, 
+    # I have no idea why I should not be using this handler!
+    #Entity     => \&_twig_print, 
+    XMLDecl    => \&_twig_print, Doctype    => \&_twig_print, 
+    CdataStart => \&_twig_print, CdataEnd   => \&_twig_print, 
+    Proc       => \&_twig_print, Comment    => \&_twig_print, 
+    Default    => \&_twig_print, 
+  );
+
+# handlers used when twig_roots, print_outside_roots and keep_encoding are used
+# and we are outside of the roots
+my %twig_handlers_roots_print_original_2_27=
+  ( Start      => \&_twig_start_check_roots_print_original, 
+    End        => \&_twig_end_check_roots_print_original, 
+    Char       => \&_twig_print_original, 
+    # for some reason original_string is wrong here 
+    # this can be a problem if the doctype includes non ascii characters
+    XMLDecl    => \&_twig_print, Doctype    => \&_twig_print,
+    # I have no idea why I should not be using this handler!
+    Entity     => \&_twig_print, 
+    #Element    => undef, Attlist   => undef,
+    CdataStart => \&_twig_print_original, CdataEnd  => \&_twig_print_original,
+    Proc       => \&_twig_print_original, Comment   => \&_twig_print_original,
+    Default    => \&_twig_print_default, #  _twig_print_original does not work
+  );
+
+
+my %twig_handlers_roots_print= $parser_version > 2.27 
+                               ? %twig_handlers_roots_print_2_30 
+                               : %twig_handlers_roots_print_2_27; 
+my %twig_handlers_roots_print_original= $parser_version > 2.27 
+                               ? %twig_handlers_roots_print_original_2_30 
+                               : %twig_handlers_roots_print_original_2_27; 
+
+
+# handlers used when the finish_print method has been called
+my %twig_handlers_finish_print=
+  ( Start      => \&_twig_print, 
+    End        => \&_twig_print_end, Char       => \&_twig_print, 
+    Entity     => \&_twig_print, XMLDecl    => \&_twig_print, 
+    Doctype    => \&_twig_print, Element    => \&_twig_print, 
+    Attlist    => \&_twig_print, CdataStart => \&_twig_print, 
+    CdataEnd   => \&_twig_print, Proc       => \&_twig_print, 
+    Comment    => \&_twig_print, Default    => \&_twig_print, 
+  );
+
+# handlers used when the finish_print method has been called and the keep_encoding
+# option is used
+my %twig_handlers_finish_print_original=
+  ( Start      => \&_twig_print_original, End      => \&_twig_print_end_original, 
+    Char       => \&_twig_print_original, Entity   => \&_twig_print_original, 
+    XMLDecl    => \&_twig_print_original, Doctype  => \&_twig_print_original, 
+    Element    => \&_twig_print_original, Attlist  => \&_twig_print_original, 
+    CdataStart => \&_twig_print_original, CdataEnd => \&_twig_print_original, 
+    Proc       => \&_twig_print_original, Comment  => \&_twig_print_original, 
+    Default    => \&_twig_print_original, 
+  );
+
+# handlers used whithin ignored elements
+my %twig_handlers_ignore=
+  ( Start      => \&_twig_ignore_start, 
+    End        => \&_twig_ignore_end, 
+    Char       => undef, Entity     => undef, XMLDecl    => undef, 
+    Doctype    => undef, Element    => undef, Attlist    => undef, 
+    CdataStart => undef, CdataEnd   => undef, Proc       => undef, 
+    Comment    => undef, Default    => undef,
+  );
+
+
+# those handlers are only used if the entities are NOT to be expanded
+my %twig_noexpand_handlers= ( Default => \&_twig_default );
+
+my @saved_default_handler;
+
+my $ID= 'id'; # default value, set by the Id argument
+
+# all allowed options
+%valid_option=
+    ( # XML::Twig options
+      TwigHandlers          => 1, Id                    => 1,
+      TwigRoots             => 1, TwigPrintOutsideRoots => 1,
+      StartTagHandlers      => 1, EndTagHandlers        => 1,
+      ForceEndTagHandlersUsage => 1,
+      DoNotChainHandlers    => 1,
+      IgnoreElts            => 1,
+      CharHandler           => 1, KeepEncoding          => 1,
+      ParseStartTag         => 1, KeepAttsOrder         => 1,
+      LoadDTD               => 1, DTDHandler            => 1,
+      DoNotOutputDTD        => 1, NoProlog              => 1,
+      ExpandExternalEnts    => 1,
+      DiscardSpaces         => 1, KeepSpaces            => 1, 
+      DiscardSpacesIn       => 1, KeepSpacesIn          => 1, 
+      PrettyPrint           => 1, EmptyTags             => 1, 
+      Comments              => 1, Pi                    => 1, 
+      OutputFilter          => 1, InputFilter           => 1,
+      OutputTextFilter      => 1, 
+      OutputEncoding        => 1, 
+      EltClass              => 1,
+      MapXmlns              => 1, KeepOriginalPrefix    => 1,
+      # XML::Parser options
+      ErrorContext          => 1, ProtocolEncoding      => 1,
+      Namespaces            => 1, NoExpand              => 1,
+      Stream_Delimiter      => 1, ParseParamEnt         => 1,
+      NoLWP                 => 1, Non_Expat_Options     => 1,
+      Xmlns                 => 1,
+    );
+
+# predefined input and output filters
+use vars qw( %filter);
+%filter= ( html       => \&html_encode,
+           safe       => \&safe_encode,
+           safe_hex   => \&safe_encode_hex,
+         );
+
+sub new
+  { my ($class, %args) = @_;
+    my $handlers;
+
+    # change all nice_perlish_names into nicePerlishNames
+    %args= _normalize_args( %args);
+
+    # check options
+    unless( $args{MoreOptions})
+      { foreach my $arg (keys %args)
+        { carp "invalid option $arg" unless $valid_option{$arg}; }
+      }
+     
+    # a twig is really an XML::Parser
+    # my $self= XML::Parser->new(%args);
+    my $self;
+    $self= XML::Parser->new(%args);   
+    
+    bless $self, $class;
+
+    if( exists $args{TwigHandlers})
+      { $handlers= $args{TwigHandlers};
+        $self->setTwigHandlers( $handlers);
+        delete $args{TwigHandlers};
+      }
+
+    # take care of twig-specific arguments
+    if( exists $args{StartTagHandlers})
+      { $self->setStartTagHandlers( $args{StartTagHandlers});
+        delete $args{StartTagHandlers};
+      }
+
+    if( exists $args{DoNotChainHandlers})
+      { $self->{twig_do_not_chain_handlers}=  $args{DoNotChainHandlers}; }
+
+    if(  exists $args{IgnoreElts})
+      { $self->setIgnoreEltsHandlers( $args{IgnoreElts});
+        delete $args{IgnoreElts};
+      }
+
+    $self->{twig_elt_class}= $args{EltClass} || 'XML::Twig::Elt';
+    if( exists( $args{EltClass})) { delete $args{EltClass}; }
+
+    if( exists( $args{MapXmlns}))
+      { $self->{twig_map_xmlns}=  $args{MapXmlns};
+        $self->{Namespaces}=1;
+        delete $args{MapXmlns};
+      }
+
+    if( exists( $args{KeepOriginalPrefix}))
+      { $self->{twig_keep_original_prefix}= $args{KeepOriginalPrefix};
+        delete $args{KeepOriginalPrefix};
+      }
+
+    $self->{twig_dtd_handler}= $args{DTDHandler};
+    delete $args{DTDHandler};
+
+    if( $args{CharHandler})
+      { $self->setCharHandler( $args{CharHandler});
+        delete $args{CharHandler};
+      }
+
+    if( $args{LoadDTD})
+      { $self->{twig_read_external_dtd}= 1;
+        delete $args{LoadDTD};
+      }
+      
+    if( $args{ExpandExternalEnts})
+      { $self->set_expand_external_entities( 1);
+        $self->{twig_read_external_dtd}= 1; # implied by ExpandExternalEnts
+        delete $args{LoadDTD};
+        delete $args{ExpandExternalEnts};
+      }
+
+    # deal with TwigRoots argument, a hash of elements for which
+    # subtrees will be built (and associated handlers)
+     
+    if( $args{TwigRoots})
+      { $self->setTwigRoots( $args{TwigRoots});
+        delete $args{TwigRoots}; 
+      }
+    
+    if( $args{EndTagHandlers})
+      { unless ($self->{twig_roots} || $args{ForceEndTagHandlersUsage})
+          { croak "you should not use EndTagHandlers without TwigRoots\n",
+                  "if you want to use it anyway, normally because you have ",
+                  "a start_tag_handlers that calls 'ignore' and you want to ",
+                  "call an ent_tag_handlers at the end of the element, then ",
+                  "pass 'force_end_tag_handlers_usage => 1' as an argument ",
+                  "to new";
+          }
+                  
+        $self->setEndTagHandlers( $args{EndTagHandlers});
+        delete $args{EndTagHandlers};
+      }
+      
+    if( $args{TwigPrintOutsideRoots})
+      { croak "cannot use TwigPrintOutsideRoots without TwigRoots"
+          unless( $self->{twig_roots});
+        # if the arg is a filehandle then store it
+        if( _is_fh( $args{TwigPrintOutsideRoots}) )
+          { $self->{twig_output_fh}= $args{TwigPrintOutsideRoots}; }
+        $self->{twig_default_print}= $args{TwigPrintOutsideRoots};
+      }
+
+    if( $args{PrettyPrint})
+      { $self->set_pretty_print( $args{PrettyPrint}); }
+
+    if( $args{EmptyTags})
+      { $self->set_empty_tag_style( $args{EmptyTags}); }
+
+    # space policy
+    if( $args{KeepSpaces})
+      { croak "cannot use both keep_spaces and discard_spaces" if( $args{DiscardSpaces});
+        croak "cannot use both keep_spaces and keep_spaces_in" if( $args{KeepSpacesIn});
+        $self->{twig_keep_spaces}=1;
+        delete $args{KeepSpaces}; 
+      }
+    if( $args{DiscardSpaces})
+      { croak "cannot use both discard_spaces and keep_spaces_in" if( $args{KeepSpacesIn});
+        $self->{twig_discard_spaces}=1; 
+        delete $args{DiscardSpaces}; 
+      }
+    if( $args{KeepSpacesIn})
+      { croak "cannot use both keep_spaces_in and discard_spaces_in" if( $args{DiscardSpacesIn});
+        $self->{twig_discard_spaces}=1; 
+        $self->{twig_keep_spaces_in}={}; 
+        my @tags= @{$args{KeepSpacesIn}}; 
+        foreach my $tag (@tags) { $self->{twig_keep_spaces_in}->{$tag}=1; } 
+        delete $args{KeepSpacesIn}; 
+      }
+    if( $args{DiscardSpacesIn})
+      { $self->{twig_keep_spaces}=1; 
+        $self->{twig_discard_spaces_in}={}; 
+        my @tags= @{$args{DiscardSpacesIn}};
+        foreach my $tag (@tags) { $self->{twig_discard_spaces_in}->{$tag}=1; } 
+        delete $args{DiscardSpacesIn}; 
+      }
+    # discard spaces by default 
+    $self->{twig_discard_spaces}= 1 unless(  $self->{twig_keep_spaces});
+
+    $args{Comments}||= $COMMENTS_DEFAULT;
+    if( $args{Comments} eq 'drop')       { $self->{twig_keep_comments}= 0;    }
+    elsif( $args{Comments} eq 'keep')    { $self->{twig_keep_comments}= 1;    }
+    elsif( $args{Comments} eq 'process') { $self->{twig_process_comments}= 1; }
+    else { croak "wrong value for comments argument: '$args{Comments}' (should be 'drop', 'keep' or 'process')"; }
+    delete $args{Comments};
+
+    $args{Pi}||= $PI_DEFAULT;
+    if( $args{Pi} eq 'drop')       { $self->{twig_keep_pi}= 0;    }
+    elsif( $args{Pi} eq 'keep')    { $self->{twig_keep_pi}= 1;    }
+    elsif( $args{Pi} eq 'process') { $self->{twig_process_pi}= 1; }
+    else { croak "wrong value for pi argument: '$args{Pi}' (should be 'drop', 'keep' or 'process')"; }
+    delete $args{Pi};
+
+    if( $args{KeepEncoding})
+      { $self->{twig_keep_encoding}= $args{KeepEncoding};
+        # set it in XML::Twig::Elt so print functions know what to do
+        $self->set_keep_encoding( 1); 
+        $self->{parse_start_tag}= $args{ParseStartTag} || \&_parse_start_tag; 
+        delete $args{ParseStartTag} if defined( $args{ParseStartTag}) ;
+        delete $args{KeepEncoding};
+        $self->{NoExpand}= 1;
+      }
+    else
+      { $self->set_keep_encoding( 0);  
+        $self->{parse_start_tag}= $args{ParseStartTag} if( $args{ParseStartTag}); 
+      }
+
+    if( $args{OutputFilter})
+      { $self->set_output_filter( $args{OutputFilter}); 
+        delete $args{OutputFilter};
+      }
+    else
+      { $self->set_output_filter( 0); }
+
+    if( $args{OutputTextFilter})
+      { $self->set_output_text_filter( $args{OutputTextFilter}); 
+        delete $args{OutputTextFilter};
+      }
+    else
+      { $self->set_output_text_filter( 0); }
+
+
+    if( exists $args{KeepAttsOrder})
+      { $self->{keep_atts_order}= $args{KeepAttsOrder};
+        if( eval 'require Tie::IxHash') 
+          { import Tie::IxHash; 
+            $self->set_keep_atts_order(  $self->{keep_atts_order}); 
+          }
+        else 
+          { carp "Tie::IxHash not available, option  keep_atts_order not allowed"; }
+      }
+    else
+      { $self->set_keep_atts_order( 0); }
+
+    if( my $output_encoding= $args{OutputEncoding})
+      { $self->set_output_encoding( $output_encoding);
+        delete $args{OutputFilter};
+      }
+
+    if( $args{InputFilter})
+      { $self->set_input_filter(  $args{InputFilter}); 
+        delete  $args{InputFilter}; 
+      }
+
+    if( exists $args{Id}) { $ID= $args{Id}; delete $args{ID}; }
+
+    if( $args{NoExpand})
+      { $self->setHandlers( %twig_noexpand_handlers);
+        $self->{twig_no_expand}=1;
+      }
+
+    if( $args{NoProlog})
+      { $self->{no_prolog}= 1; 
+        delete $args{NoProlog}; 
+      }
+
+    if( $args{DoNotOutputDTD})
+      { $self->{no_dtd_output}= 1; 
+        delete $args{DoNotOutputDTD}; 
+      }
+
+    # set handlers
+    if( $self->{twig_roots})
+      { if( $self->{twig_default_print})
+          { if( $self->{twig_keep_encoding})
+              { $self->setHandlers( %twig_handlers_roots_print_original); }
+            else
+              { $self->setHandlers( %twig_handlers_roots_print);  }
+          }
+        else
+          { $self->setHandlers( %twig_handlers_roots); }
+      }
+    else
+      { $self->setHandlers( %twig_handlers); }
+
+    # XML::Parser::Expat does not like these handler to be set. So in order to 
+    # use the various sets of handlers on XML::Parser or XML::Parser::Expat
+    # objects when needed, these ones have to be set only once, here, at 
+    # XML::Parser level
+    $self->setHandlers( Init => \&_twig_init, Final => \&_twig_final);
+
+    $self->{twig_entity_list}= XML::Twig::Entity_list->new; 
+
+    $self->{twig_id}= $ID; 
+    $self->{twig_stored_spaces}='';
+
+    $self->{twig}= $self;
+    weaken( $self->{twig}) if( $weakrefs);
+
+    return $self;
+  }
+
+
+sub parseurl
+  { my $t= shift;
+    return $t->_parseurl( 0, @_);
+  }
+
+sub safe_parseurl
+  { my $t= shift;
+    return $t->_parseurl( 1, @_);
+  }
+
+# I should really add extra options to allow better configuration of the 
+# LWP::UserAgent object
+# this method forks: 
+#   - the child gets the data and copies it to the pipe,
+#   - the parent reads the stream and sends it to XML::Parser
+# the data is cut it chunks the size of the XML::Parser::Expat buffer
+# the method returns the twig and the status
+sub _parseurl
+  { my( $t, $safe, $url, $agent)= @_;
+    pipe( README, WRITEME) or croak  "cannot create connected pipes: $!";
+    if( my $pid= fork)
+      { # parent code: parse the incoming file
+        close WRITEME; # no need to write
+        my $result= $safe ? $t->safe_parse( \*README) : $t->parse( \*README);
+        close README;
+        return $@ ? 0 : $t;
+      }
+    else
+     { # child
+        close README; # no need to read
+        require LWP;  # so we can get LWP::UserAgent and HTTP::Request
+        $|=1;
+        $agent    ||= LWP::UserAgent->new;
+        my $request  = HTTP::Request->new( GET => $url);
+        # _pass_url_content is called with chunks of data the same size as
+        # the XML::Parser buffer 
+        my $response = $agent->request( $request, 
+                         sub { _pass_url_content( \*WRITEME, @_); }, BUFSIZE);
+        $response->is_success or croak "$url ", $response->message;
+        close WRITEME;
+        CORE::exit(); # CORE is there for mod_perl (which redefines exit)
+      }
+  }
+
+# get the (hopefully!) XML data from the URL and 
+sub _pass_url_content
+  { my( $fh, $data, $response, $protocol)= @_;
+    print $fh $data;
+  }
+
+sub add_options
+  { my %args= map { $_, 1 } @_;
+    %args= _normalize_args( %args);
+    foreach (keys %args) { $valid_option{$_}++; } 
+  }
+
+sub _twig_store_internal_dtd
+  { 
+    my( $p, $string)= @_;
+    my $t= $p->{twig};
+    $string= $p->original_string() if( $t->{twig_keep_encoding});
+    $t->{twig_doctype}->{internal} .= $string;
+  }
+
+sub _twig_stop_storing_internal_dtd
+  { my $p= shift;
+    if( @saved_default_handler && defined $saved_default_handler[1])
+      { $p->setHandlers( @saved_default_handler); }
+    else
+      { my $t= $p->{twig};
+        $p->setHandlers( Default => undef);
+      }
+  }
+
+
+sub _normalize_args
+  { my %normalized_args;
+    while( my $key= shift )
+      { $key= join '', map { ucfirst } split /_/, $key;
+        #$key= "Twig".$key unless( substr( $key, 0, 4) eq 'Twig');
+        $normalized_args{$key}= shift ;
+      }
+    return %normalized_args;
+  }    
+
+sub _is_fh { return unless $_[0]; return isa( $_[0], 'GLOB') || isa( $_[0], 'IO::Scalar'); }
+
+sub _set_handler
+  { my( $handlers, $path, $handler)= @_;
+
+    $handlers ||= {}; # create the handlers struct if necessary
+
+    my $prev_handler= $handlers->{handlers}->{$path} || undef;
+
+       _set_gi_handler              ( $handlers, $path, $handler, $prev_handler)
+    || _set_path_handler            ( $handlers, $path, $handler, $prev_handler)
+    || _set_subpath_handler         ( $handlers, $path, $handler, $prev_handler)
+    || _set_attribute_handler       ( $handlers, $path, $handler, $prev_handler)
+    || _set_star_att_handler        ( $handlers, $path, $handler, $prev_handler)
+    || _set_star_att_regexp_handler ( $handlers, $path, $handler, $prev_handler)
+    || _set_string_handler          ( $handlers, $path, $handler, $prev_handler)
+    || _set_attribute_regexp_handler( $handlers, $path, $handler, $prev_handler)
+    || _set_string_regexp_handler   ( $handlers, $path, $handler, $prev_handler)
+    || _set_pi_handler              ( $handlers, $path, $handler, $prev_handler)
+    || croak "unrecognized expression in handler: '$path'";
+
+
+    # this both takes care of the simple (gi) handlers and store
+    # the handler code reference for other handlers
+    $handlers->{handlers}->{$path}= $handler;
+
+    return $prev_handler;
+  }
+
+
+sub _set_gi_handler
+  { my( $handlers, $path, $handler, $prev_handler)= @_;
+    if( $path =~ m{^\s*($REG_NAME)\s*$}o )
+      { my $gi= $1;
+        $handlers->{handlers}->{gi}->{$gi}= $handler; 
+        return 1;
+      }
+    else 
+      { return 0; }
+  }
+
+sub _set_path_handler
+  { my( $handlers, $path, $handler, $prev_handler)= @_;
+    if( $path=~ m{^\s*(?:/$REG_NAME)*/($REG_NAME)\s*$}o)
+      { # a full path has been defined
+        # update the path_handlers count, knowing that
+        # either the previous or the new handler can be undef
+        $handlers->{path_handlers}->{gi}->{$1}-- if( $prev_handler);
+        if( $handler)
+         { $handlers->{path_handlers}->{gi}->{$1}++;
+           $handlers->{path_handlers}->{path}->{$path}= $handler;
+         }
+        return 1;
+      }
+    else 
+      { return 0; }
+  }
+
+sub _set_subpath_handler
+  { my( $handlers, $path, $handler, $prev_handler)= @_;
+    if( $path=~ m{^\s*(?:$REG_NAME/)+($REG_NAME)\s*$}o)
+      { # a partial path has been defined
+        # $1 is the "final" gi
+        $handlers->{subpath_handlers}->{gi}->{$1}-- if( $prev_handler);
+        if( $handler)
+         { $handlers->{subpath_handlers}->{gi}->{$1}++;
+           $handlers->{subpath_handlers}->{path}->{$path}= $handler;
+         }
+        return 1;
+      }
+    else 
+      { return 0; }
+  }
+
+sub _set_attribute_handler
+  { my( $handlers, $path, $handler, $prev_handler)= @_;
+    # check for attribute conditions
+    if( $path=~ m{^\s*($REG_NAME)          # elt
+                 \s*\[\s*\@                #    [@
+                 ($REG_NAME)\s*            #      att
+                 (?:=\s*($REG_STRING)\s*)? #           = value (optional)         
+                 \]\s*$}xo)                #                             ]  
+      { my( $gi, $att, $val)= ($1, $2, $3);
+        $val= substr( $val, 1, -1) if( defined $val); # remove the quotes
+        if( $prev_handler)
+          { # replace or remove the previous handler
+            my $i=0; # so we can splice the array if need be
+            foreach my $exp ( @{$handlers->{attcond_handlers_exp}->{$gi}})
+             { if( ($exp->{att} eq $att) && ( _eq( $exp->{val}, $val)) )
+                 { if( $handler) # just replace the handler
+                     { $exp->{handler}= $handler; }
+                   else          # remove the handler
+                     { $handlers->{attcond_handlers}->{$gi}--;
+                       splice( @{$handlers->{attcond_handlers_exp}->{$gi}}, $i, 1);
+                       last;
+                     }
+                 }
+               $i++;
+             }
+          }
+        elsif( $handler)
+          { # new handler only
+            $handlers->{attcond_handlers}->{$gi}++;
+            my $exp={att => $att, val => $val, handler => $handler};
+            $handlers->{attcond_handlers_exp}->{$gi} ||= [];
+            push @{$handlers->{attcond_handlers_exp}->{$gi}}, $exp;
+          }
+        return 1;
+      }
+    else 
+      { return 0; }
+  }
+
+
+sub _set_attribute_regexp_handler
+  { my( $handlers, $path, $handler, $prev_handler)= @_;
+    # check for attribute regexp conditions
+    if( $path=~ m{^\s*($REG_NAME)     # elt
+                 \s*\[\s*\@           #    [@
+                 ($REG_NAME)          #      att
+                 \s*=~\s*             #          =~
+                 /($REG_REGEXP_EXP)/  #             /regexp/
+                 ($REG_REGEXP_MOD)    #                     mods
+                 \s*]\s*$}gxo)        #                         ] 
+      { my( $gi, $att, $regexp, $mods)= ($1, $2, $3, $4);
+        $regexp= qr/(?$mods:$regexp)/;
+        if( $prev_handler)
+          { # replace or remove the previous handler
+            my $i=0; # so we can splice the array if need be
+            foreach my $exp ( @{$handlers->{attregexp_handlers_exp}->{$gi}})
+             { if( ($exp->{att} eq $att) && ($exp->{regexp} eq $regexp) )
+                 { if( $handler) # just replace the handler
+                     { $exp->{handler}= $handler; }
+                   else          # remove the handler
+                     { $handlers->{attregexp_handlers}->{$gi}--;
+                       splice( @{$handlers->{attregexp_handlers_exp}->{$gi}}, $i, 1);
+                       last;
+                     }
+                 }
+               $i++;
+             }
+          }
+        elsif( $handler)
+          { # new handler only
+            $handlers->{attregexp_handlers}->{$gi}++;
+            my $exp={att => $att, regexp => $regexp, handler => $handler};
+            $handlers->{attregexp_handlers_exp}->{$gi} ||= [];
+            push @{$handlers->{attregexp_handlers_exp}->{$gi}}, $exp;
+          }
+        return 1;
+      }
+    else 
+      { return 0; }
+  }
+
+sub _set_string_handler
+  { my( $handlers, $path, $handler, $prev_handler)= @_;
+    # check for string conditions
+    if( $path=~/^\s*($REG_NAME)            # elt
+                 \s*\[\s*string            #    [string
+                 \s*\(\s*($REG_NAME)?\s*\) #           (sub_elt)
+                 \s*=\s*                   #                     =
+                 ($REG_STRING)             #                       "text" (or 'text')
+                 \s*\]\s*$/ox)             #                              ] 
+      { my( $gi, $sub_elt, $text)= ($1, $2, $3);
+        $text= substr( $text, 1, -1) if( defined $text); # remove the quotes
+        if( $prev_handler)
+          { # replace or remove the previous handler
+            my $i=0; # so we can splice the array if need be
+            foreach my $exp ( @{$handlers->{text_handlers_exp}->{$gi}})
+             { if( ($exp->{text} eq $text) &&
+                   ( !$exp->{sub_elt} || ($exp->{sub_elt} eq $sub_elt) )
+                 )
+                 { if( $handler) # just replace the handler
+                     { $exp->{handler}= $handler; }
+                   else          # remove the handler
+                     { $handlers->{text_handlers}->{$gi}--;
+                       splice( @{$handlers->{text_handlers_exp}->{$gi}}, $i, 1);
+                       last;
+                     }
+                 }
+               $i++;
+             }
+          }
+        elsif( $handler)
+          { # new handler only
+            $handlers->{text_handlers}->{$gi}++;
+            my $exp={sub_elt => $sub_elt, text => $text, handler => $handler};
+            $handlers->{text_handlers_exp}->{$gi} ||= [];
+            push @{$handlers->{text_handlers_exp}->{$gi}}, $exp;
+          }
+        return 1;
+      }
+    else 
+      { return 0; 
+      }
+  }
+
+
+sub _set_string_regexp_handler
+  { my( $handlers, $path, $handler, $prev_handler)= @_;
+    # check for string regexp conditions
+    if( $path=~m{^\s*($REG_NAME)        # (elt)
+                 \s*\[\s*string         #    [string
+                 \s*\(\s*($REG_NAME?)\) #           (sub_elt)
+                 \s*=~\s*               #              =~ 
+                 /($REG_REGEXP_EXP)/    #                 /(regexp)/
+                 \s*($REG_REGEXP_MOD)?  #                         (mods)
+                 \s*\]\s*$}ox)          #                             ]   (or ')
+      { my( $gi, $sub_elt, $regexp, $mods)= ($1, $2, $3, $4);
+        $mods||="";
+        $regexp= qr/(?$mods:$regexp)/;
+        if( $prev_handler)
+          { # replace or remove the previous handler
+            my $i=0; # so we can splice the array if need be
+            foreach my $exp ( @{$handlers->{regexp_handlers_exp}->{$gi}})
+             { if( ($exp->{regexp} eq $regexp) &&
+                   ( !$exp->{sub_elt} || ($exp->{sub_elt} eq $sub_elt) )
+                 )
+                 { if( $handler) # just replace the handler
+                     { $exp->{handler}= $handler;  
+                     }
+                   else          # remove the handler
+                     { $handlers->{regexp_handlers}->{$gi}--;
+                       splice( @{$handlers->{regexp_handlers_exp}->{$gi}}, $i, 1);
+                       last;
+                     }
+                 }
+               $i++;
+             }
+          }
+        elsif( $handler)
+          { # new handler only
+            $handlers->{regexp_handlers}->{$gi}++;
+            my $exp= {sub_elt => $sub_elt, regexp => $regexp, handler => $handler};
+            $handlers->{regexp_handlers_exp}->{$gi} ||= [];
+            push @{$handlers->{regexp_handlers_exp}->{$gi}}, $exp;
+          }
+        return 1;
+      }
+    else 
+      { return 0; 
+      }
+  }
+
+
+sub _set_star_att_handler
+  { my( $handlers, $path, $handler, $prev_handler)= @_;
+    # check for *[@att="val"] or *[@att] conditions
+    if( $path=~/^(?:\s*\*)?         # * (optional)
+                 \s*\[\s*\@         #    [@
+                 ($REG_NAME)        #      att
+                 (?:\s*=\s*         #         = 
+                 ($REG_STRING))?    #           string
+                     \s*\]\s*$/ox)  #                 ]  
+      { my( $att, $val)= ($1, $2);
+        $val= substr( $val, 1, -1) if( defined $val); # remove the quotes from the string
+        if( $prev_handler)
+          { # replace or remove the previous handler
+            my $i=0; # so we can splice the array if need be
+            foreach my $exp ( @{$handlers->{att_handlers_exp}->{$att}})
+             { if( ($exp->{att} eq $att) && ( !defined( $val) || _eq( $exp->{val}, $val) ) )
+                 { if( $handler) # just replace the handler
+                     { $exp->{handler}= $handler; }
+                   else          # remove the handler
+                     { splice( @{$handlers->{att_handlers_exp}->{$att}}, $i, 1);
+                   $handlers->{att_handlers}->{$att}--;
+                       last;
+                     }
+                 }
+               $i++;
+             }
+          }
+        elsif( $handler)
+          { # new handler only
+            $handlers->{att_handlers}->{$att}++;
+            my $exp={att => $att, val => $val, handler => $handler};
+            $handlers->{att_handlers_exp}->{$att} ||= [];
+            push @{$handlers->{att_handlers_exp}->{$att}}, $exp;
+          }
+        return 1;
+      }
+    else 
+      { return 0; 
+      }
+  }
+
+sub _set_star_att_regexp_handler
+  { my( $handlers, $path, $handler, $prev_handler)= @_;
+    # check for *[@att=~ /regexp/] conditions
+    if( $path=~ m{^(?:\s*\*)?             # * (optional)
+                   \s*\[\s*\@             #  [@
+                   ($REG_NAME)            #    att
+                   \s*=~\s*               #        =~ 
+                   /($REG_REGEXP_EXP)/    #           /(regexp)/
+                   \s*($REG_REGEXP_MOD)?  #                     (mods)
+                   \s*\]\s*$}ox)          #                           ]  
+      { my( $att, $regexp, $mods)= ($1, $2, $3);
+        $mods||="";
+        $regexp= qr/(?$mods:$regexp)/;
+        if( $prev_handler)
+          { # replace or remove the previous handler
+            my $i=0; # so we can splice the array if need be
+            foreach my $exp ( @{$handlers->{att_regexp_handlers_exp}->{$att}})
+             { if( $exp->{regexp} eq $regexp)
+                 { if( $handler) # just replace the handler
+                     { $exp->{handler}= $handler;  
+                     }
+                   else          # remove the handler
+                     { splice( @{$handlers->{att_regexp_handlers_exp}->{$att}}, $i, 1);
+                   $handlers->{att_regexp_handlers}--;
+                       last;
+                     }
+                 }
+               $i++;
+             }
+          }
+        elsif( $handler)
+          { # new handler only
+            my $exp= { regexp => $regexp, handler => $handler};
+            $handlers->{regexp_handlers_exp}->{$att} ||= [];
+            push @{$handlers->{att_regexp_handlers_exp}->{$att}}, $exp;
+            $handlers->{att_regexp_handlers}++;
+          }
+        return 1;
+      }
+    else 
+      { return 0; 
+      }
+  }
+
+
+sub _set_pi_handler
+  { my( $handlers, $path, $handler, $prev_handler)= @_;
+    # PI conditions ( '?target' => \&handler or '?' => \&handler
+    #             or '#PItarget' => \&handler or '#PI' => \&handler)
+    if( $path=~ /^\s*(?:\?|#PI)\s*(?:([^\s]*)\s*)$/)
+      { my $target= $1 || '';
+        # update the path_handlers count, knowing that
+        # either the previous or the new handler can be undef
+        $handlers->{pi_handlers}->{$1}= $handler;
+        return 1;
+      }
+    else 
+      { return 0; 
+      }
+  }
+
+# just like eq except that undef values do not trigger warnings
+sub _eq
+  { my( $val1, $val2)= @_;
+    if( !defined $val1) { return !defined $val2 }
+    if( !defined $val2) { return 0; }
+    return $val1 eq $val2;
+  }
+
+sub setCharHandler
+  { my( $t, $handler)= @_;
+    $t->{twig_char_handler}= $handler;
+  }
+
+
+sub _reset_handlers
+  { my $handlers= shift;
+    delete $handlers->{handlers};
+    delete $handlers->{path_handlers};
+    delete $handlers->{subpath_handlers};
+    $handlers->{attcond_handlers_exp}=[] if( $handlers->{attcond_handlers});
+    delete $handlers->{attcond_handlers};
+  }
+  
+sub _set_handlers
+  { my $handlers= shift || return;
+    my $set_handlers= {};
+    foreach my $path (keys %{$handlers})
+      { _set_handler( $set_handlers, $path, $handlers->{$path}); }
+    return $set_handlers;
+  }
+    
+
+sub setTwigHandler
+  { my( $t, $path, $handler)= @_;
+    $t->{twig_handlers} ||={};
+    return _set_handler( $t->{twig_handlers}, $path, $handler);
+  }
+
+sub setTwigHandlers
+  { my( $t, $handlers)= @_;
+    my $previous_handlers= $t->{twig_handlers} || undef;
+    _reset_handlers( $t->{twig_handlers});
+    $t->{twig_handlers}= _set_handlers( $handlers);
+    return $previous_handlers;
+  }
+
+sub setStartTagHandler
+  { my( $t, $path, $handler)= @_;
+    $t->{twig_starttag_handlers}||={};
+    return _set_handler( $t->{twig_starttag_handlers}, $path, $handler);
+  }
+
+sub setStartTagHandlers
+  { my( $t, $handlers)= @_;
+    my $previous_handlers= $t->{twig_starttag_handlers} || undef;
+    _reset_handlers( $t->{twig_starttag_handlers});
+    $t->{twig_starttag_handlers}= _set_handlers( $handlers);
+    return $previous_handlers;
+   }
+
+sub setIgnoreEltsHandler
+  { my( $t, $path, $action)= @_;
+    $t->{twig_ignore_elts_handlers}||={};
+    return _set_handler( $t->{twig_ignore_elts_handlers}, $path, $action );
+  }
+
+sub setIgnoreEltsHandlers
+  { my( $t, $handlers)= @_;
+    my $previous_handlers= $t->{twig_ignore_elts_handlers} || undef;
+    _reset_handlers( $t->{twig_ignore_elts_handlers});
+    $t->{twig_ignore_elts_handlers}= _set_handlers( $handlers);
+    return $previous_handlers;
+   }
+
+sub setEndTagHandler
+  { my( $t, $path, $handler)= @_;
+    $t->{twig_endtag_handlers}||={};
+    return _set_handler( $t->{twig_endtag_handlers}, $path,$handler);
+  }
+
+sub setEndTagHandlers
+  { my( $t, $handlers)= @_;
+    my $previous_handlers= $t->{twig_endtag_handlers} || undef;
+    _reset_handlers( $t->{twig_endtag_handlers});
+    $t->{twig_endtag_handlers}= _set_handlers( $handlers);
+    return $previous_handlers;
+   }
+
+# a little more complex: set the twig_handlers only if a code ref is given
+sub setTwigRoots
+  { my( $t, $handlers)= @_;
+    my $previous_roots= $t->{twig_roots} || undef;
+    _reset_handlers($t->{twig_roots});
+    $t->{twig_roots}= _set_handlers( $handlers);
+    foreach my $path (keys %{$handlers})
+      { $t->{twig_handlers}||= {};
+        _set_handler( $t->{twig_handlers}, $path, $handlers->{$path})
+          if( isa( $handlers->{$path}, 'CODE')); 
+      }
+    return $previous_roots;
+  }
+
+# just store the reference to the expat object in the twig
+sub _twig_init
+  { 
+    my $p= shift;
+    my $t=$p->{twig};
+    $t->{twig_parser}= $p; 
+    weaken( $t->{twig_parser}) if( $weakrefs);
+    $t->{twig_parsing}=1;
+    # in case they had been created by a previous parse
+    delete $t->{twig_dtd};
+    delete $t->{twig_doctype};
+    delete $t->{twig_xmldecl};
+    # if needed set the output filehandle
+    $t->_set_fh_to_twig_output_fh();
+  }
+
+# uses eval to catch the parser's death
+sub safe_parse
+  { my( $t, $str)= @_;
+    eval { $t->parse( $str); } ;
+    return $@ ? 0 : $t;
+  }
+
+sub safe_parsefile
+  { my( $t, $file)= @_;
+    eval { $t->parsefile( $file); } ;
+    return $@ ? 0 : $t;
+  }
+
+
+sub _add_or_discard_stored_spaces
+  { my $t= shift;
+    my %option= @_;
+    
+    if( $t->{twig_stored_spaces} || $option{force} || $t->{twig_preserve_space})
+      { if( $t->{twig_current}->is_pcdata)
+          { $t->{twig_current}->append_pcdata($t->{twig_stored_spaces}); }
+        else
+          { my $current_gi= $t->{twig_current}->gi;
+            unless( defined( $t->{twig_space_policy}->{$current_gi}))
+              { $t->{twig_space_policy}->{$current_gi}= _space_policy( $t, $current_gi); }
+
+            if( $t->{twig_space_policy}->{$current_gi} ||  $option{force} || $t->{twig_preserve_space})
+              { _insert_pcdata( $t, $t->{twig_stored_spaces} ); }
+
+            $t->{twig_stored_spaces}='';
+          }
+      }
+  }
+
+# the default twig handlers, which build the tree
+sub _twig_start
+  { 
+    my ($p, $gi, @att)= @_;
+    my $t=$p->{twig};
+
+    # empty the stored pcdata (space stored in case they are really part of 
+    # a pcdata element) or stored it if the space policy dictades so
+    # create a pcdata element with the spaces if need be
+    _add_or_discard_stored_spaces( $t);
+    my $parent= $t->{twig_current};
+
+    # if we were parsing PCDATA then we exit the pcdata
+    if( $t->{twig_in_pcdata})
+      { $t->{twig_in_pcdata}= 0;
+        delete $parent->{'twig_current'};
+        $parent= $parent->{parent};
+      }
+
+    # if we choose to keep the encoding then we need to parse the tag
+    if( my $func = $t->{parse_start_tag})
+      { ($gi, @att)= &$func($p->original_string); }
+    
+    # filter the input data if need be  
+    if( my $filter= $t->{twig_input_filter})
+      { $gi= $filter->( $gi);
+        @att= map { $filter->($_) } @att; 
+      }
+
+    if( $t->{twig_map_xmlns}) 
+      { 
+        foreach my $new_prefix ( $p->new_ns_prefixes)
+          { my $uri= $t->parser->expand_ns_prefix( $new_prefix);
+            # replace the prefix if it is mapped
+            if( !$t->{twig_keep_original_prefix} && (my $mapped_prefix= $t->{twig_map_xmlns}->{$uri}))
+              { $new_prefix= $mapped_prefix; }
+            # now put the namespace declaration back in the element
+            if( $new_prefix eq '#default')
+              { push @att, "xmlns" =>  $uri; } 
+            else
+              { push @att, "xmlns:$new_prefix" =>  $uri; } 
+          }
+
+        if( $t->{twig_keep_original_prefix})
+          { # things become more complex: we need to find the original prefix
+            # and store both prefixes
+            my $ns_info= $t->_ns_info( $gi);
+            my $map_att;
+            if( $ns_info->{mapped_prefix})
+              { $gi= "$ns_info->{mapped_prefix}:$gi";
+                $map_att->{$ns_info->{mapped_prefix}}= $ns_info->{prefix};
+              }
+            my $att_name=1;
+            foreach( @att) 
+              { if( $att_name) 
+                  { 
+                    my $ns_info= $t->_ns_info( $_);
+                    if( $ns_info->{mapped_prefix})
+                      { $_= "$ns_info->{mapped_prefix}:$_";
+                        $map_att->{$ns_info->{mapped_prefix}}= $ns_info->{prefix};
+                      }
+                    $att_name=0; 
+                  }
+                else           
+                  {  $att_name=1; }
+              }
+            push @att, '#original_gi', $map_att if( $map_att);
+          }
+        else
+          { $gi= $t->_replace_prefix( $gi); 
+            my $att_name=1;
+            foreach( @att) 
+              { if( $att_name) { $_= $t->_replace_prefix( $_); $att_name=0; }
+                else           {  $att_name=1; }
+              }
+          }
+      }
+
+    my $elt= $t->{twig_elt_class}->new( $gi);
+    $elt->set_atts( @att);
+ 
+    delete $parent->{'twig_current'} if( $parent);
+    $t->{twig_current}= $elt;
+    $elt->{'twig_current'}=1;
+
+    if( $parent)
+      { my $prev_sibling= $parent->{last_child};
+        if( $prev_sibling) 
+          { $prev_sibling->{next_sibling}=  $elt; 
+            $elt->set_prev_sibling( $prev_sibling);
+          }
+
+        $elt->set_parent( $parent);
+        $parent->{first_child}=  $elt unless( $parent->{first_child}); 
+        $parent->set_last_child( $elt);
+      }
+    else 
+      { # processing root
+        $t->set_root( $elt);
+        # call dtd handlerif need be
+        $t->{twig_dtd_handler}->($t, $t->{twig_dtd})
+          if( defined $t->{twig_dtd_handler});
+      
+        # set this so we can catch external entities
+        # (the handler was modified during DTD processing)
+        if( $t->{twig_default_print})
+          { $p->setHandlers( Default => \&_twig_print); }
+        elsif( $t->{twig_roots})
+          { $p->setHandlers( Default => sub { return }); }
+        else
+          { $p->setHandlers( Default => \&_twig_default); }
+      }
+   
+    $elt->{empty}=  $p->recognized_string=~ m{/\s*>$}s ? 1 : 0;
+
+    $elt->{extra_data}= $t->{extra_data} if( $t->{extra_data});
+    $t->{extra_data}='';
+
+    # if the element is ID-ed then store that info
+    my $id= $elt->{'att'}->{$ID};
+    if( $id) { $t->{twig_id_list}->{$id}= $elt; 
+               weaken( $t->{twig_id_list}->{$id}) if( $weakrefs);
+             }
+
+
+    # call user handler if need be
+    if( $t->{twig_starttag_handlers})
+      { # call all appropriate handlers
+        my @handlers= _handler( $t, $t->{twig_starttag_handlers}, $gi, $elt);
+    
+        local $_= $elt;
+    
+        foreach my $handler ( @handlers)
+          { $handler->($t, $elt) || last; }
+        # call _all_ handler if needed
+        if( my $all= $t->{twig_starttag_handlers}->{handlers}->{$ALL})
+          { $all->($t, $elt); }
+      }
+
+    # check if the tag is in the list of tags to be ignored
+    if( $t->{twig_ignore_elts_handlers})
+      { my @handlers= _handler( $t, $t->{twig_ignore_elts_handlers}, $gi, $elt);
+        # only the first handler counts, it contains the action (discard/print/string)
+        if( @handlers) { my $action= shift @handlers; $t->ignore( $action); }
+      }
+
+    if( $elt->{'att'}->{'xml:space'} && (  $elt->{'att'}->{'xml:space'} eq 'preserve')) { $t->{twig_preserve_space}++; }
+
+  }
+
+# extract prefix, local_name, uri, mapped_prefix from a name
+# will only work if called from a start or end tag handler
+sub _ns_info
+  { my( $t, $name)= @_;
+    my $ns_info={};
+    my $p= $t->parser;
+    $ns_info->{uri}= $p->namespace( $name); 
+    return $ns_info unless( $ns_info->{uri});
+
+    $ns_info->{prefix}= _a_proper_ns_prefix( $p, $ns_info->{uri});
+    $ns_info->{mapped_prefix}= $t->{twig_map_xmlns}->{$ns_info->{uri}} || $ns_info->{prefix};
+
+    return $ns_info;
+  }
+    
+sub _a_proper_ns_prefix
+  { my( $p, $uri)= @_;
+    foreach my $prefix ($p->current_ns_prefixes)
+      { if( $p->expand_ns_prefix( $prefix) eq $uri)
+          { return $prefix; }
+      }
+  }
+
+
+# the default function to parse a start tag (in keep_encoding mode)
+# can be overridden with the parse_start_tag method
+# only works for 1-byte character sets
+sub _parse_start_tag
+  { my $string= shift;
+    my( $gi, @atts);
+
+    # get the gi (between < and the first space, / or > character)
+    #if( $string=~ s{^<\s*([^\s>/]*)[\s>/]*}{}s)
+    if( $string=~ s{^<\s*($REG_NAME)[\s>/]}{}s)
+      { $gi= $1; }
+    else
+      { croak "error parsing tag '$string'"; }
+    while( $string=~ s{^([^\s=]*)\s*=\s*(["'])(.*?)\2\s*}{}s)
+      { push @atts, $1, $3; }
+    return $gi, @atts;
+  }
+
+sub set_root
+  { my( $t, $elt)= @_;
+    $t->{twig_root}= $elt;
+    $elt->{twig}= $t;
+    weaken(  $elt->{twig}) if( $weakrefs);
+  }
+
+sub _twig_end($$;@)
+  { 
+    my ($p, $gi)  = @_;
+    my $t=$p->{twig};
+
+    if( $t->{twig_map_xmlns}) { $gi= $t->_replace_prefix( $gi); }
+  
+    _add_or_discard_stored_spaces( $t);
+ 
+    # the new twig_current is the parent
+    my $elt= $t->{twig_current};
+    delete $elt->{'twig_current'};
+
+    # if we were parsing PCDATA then we exit the pcdata too
+    if( $t->{twig_in_pcdata})
+      { $t->{twig_in_pcdata}= 0;
+        $elt= $elt->{parent} if($elt->{parent});
+        delete $elt->{'twig_current'};
+      }
+
+    # parent is the new current element
+    my $parent= $elt->{parent};
+    $parent->{'twig_current'}=1 if( $parent);
+    $t->{twig_current}= $parent;
+
+    $elt->{extra_data_before_end_tag}= $t->{extra_data} if( $t->{extra_data}); 
+    $t->{extra_data}='';
+
+    if( $t->{twig_handlers})
+      { # look for handlers
+        my @handlers= _handler( $t, $t->{twig_handlers}, $gi, $elt);
+
+        local $_= $elt; # so we can use $_ in the handlers
+    
+        foreach my $handler ( @handlers)
+          { $handler->($t, $elt) || last; }
+        # call _all_ handler if needed
+        if( my $all= $t->{twig_handlers}->{handlers}->{$ALL})
+          { $all->($t, $elt); }
+      }
+
+    # if twig_roots is set for the element then set appropriate handler
+    if(  $t->{twig_root_depth} and ($p->depth == $t->{twig_root_depth}) )
+      { if( $t->{twig_default_print})
+          { # select the proper fh (and store the currently selected one)
+            $t->_set_fh_to_twig_output_fh(); 
+            if( $t->{twig_keep_encoding})
+              { $p->setHandlers( %twig_handlers_roots_print_original); }
+            else
+              { $p->setHandlers( %twig_handlers_roots_print); }
+          }
+        else
+          { $p->setHandlers( %twig_handlers_roots); }
+      }
+
+    if( $elt->{'att'}->{'xml:space'} && (  $elt->{'att'}->{'xml:space'} eq 'preserve')) { $t->{twig_preserve_space}--; }
+  }
+
+# return the list of handler that can be activated for an element 
+# (either of CODE ref's or 1's for twig_roots)
+
+sub _handler
+  { my( $t, $handlers, $gi, $elt)= @_;
+
+    my @found_handlers=();
+    my $found_handler;
+
+    # warning: $elt can be either 
+    # - a regular element
+    # - a ref to the attribute hash (when called for an element 
+    #   for which the XML::Twig::Elt has not been built, outside 
+    #   of the twig_roots)
+    # - a string (case of an entity in keep_encoding mode)
+
+    # check for an attribute expression with no gi
+    if( $handlers->{att_handlers})
+      { my %att_handlers= %{$handlers->{att_handlers_exp}};
+        foreach my $att ( keys %att_handlers)
+          { my $att_val;
+            # get the attribute value
+            if( ref $elt eq 'HASH')
+              { $att_val= $elt->{$att}; }     # $elt is the atts hash
+            elsif( isa( $elt,'XML::Twig::Elt'))
+              { $att_val= $elt->{'att'}->{$att}; }  # $elt is an element
+                if( defined $att_val)
+                  { my @cond= @{$handlers->{att_handlers_exp}->{$att}};
+                    foreach my $cond (@cond)
+                      {  # 2 cases: either there is a val and the att value should be equal to it
+                         #          or there is no val (condition was gi[@att]), just for the att to be defined 
+                    if( !defined $cond->{val} || ($att_val eq $cond->{val}) )  
+                      { push @found_handlers, $cond->{handler};}
+                  }
+              }
+          }
+      }
+
+    # check for an attribute regexp expression with no gi
+    if( $handlers->{att_regexp_handlers})
+      { my %att_handlers= %{$handlers->{att_regexp_handlers_exp}};
+        foreach my $att ( keys %att_handlers)
+          { my $att_val;
+            # get the attribute value
+            if( ref $elt eq 'HASH')
+              { $att_val= $elt->{$att}; }     # $elt is the atts hash
+            elsif( isa( $elt,'XML::Twig::Elt'))
+              { $att_val= $elt->{'att'}->{$att}; }  # $elt is an element
+
+            if( defined $att_val)
+              { my @cond= @{$handlers->{att_regexp_handlers_exp}->{$att}};
+                foreach my $cond (@cond)
+                  { if( $att_val=~ $cond->{regexp})  
+                      { push @found_handlers, $cond->{handler};}
+                  }
+              }
+          }
+      }
+
+    # check for a text expression
+    if( $handlers->{text_handlers}->{$gi})
+      { my @text_handlers= @{$handlers->{text_handlers_exp}->{$gi}};
+        foreach my $exp ( @text_handlers)
+          { if (!$exp->{sub_elt})
+              { push @found_handlers, $exp->{handler}
+                  if $elt->text eq $exp->{text};
+              }
+            else
+              { foreach my $child ($elt->children($exp->{sub_elt}))
+                  { if( $child->text eq $exp->{text})
+                      { push @found_handlers, $exp->{handler};
+                        last;
+                      }
+                  }
+              }
+          }
+      }
+
+    # check for a text regexp expression
+    if( $handlers->{regexp_handlers}->{$gi})
+      { my @regexp_handlers= @{$handlers->{regexp_handlers_exp}->{$gi}};
+        foreach my $exp ( @regexp_handlers)
+          { if( !$exp->{sub_elt})
+              { push @found_handlers, $exp->{handler}
+                  if $elt->text =~ $exp->{regexp};
+              }
+            else
+              { foreach my $child ($elt->children($exp->{sub_elt}))
+                  { if( $child->text =~ $exp->{regexp})
+                      { push @found_handlers, $exp->{handler};
+                        last;
+                      }
+                  }
+              }
+          }
+      }
+
+    # check for an attribute expression
+    if( $handlers->{attcond_handlers}->{$gi})
+      { my @attcond_handlers= @{$handlers->{attcond_handlers_exp}->{$gi}};
+        foreach my $exp ( @attcond_handlers)
+          { my $att_val;
+        # get the attribute value
+        if( ref $elt eq 'HASH')
+          { $att_val= $elt->{$exp->{att}}; }    # $elt is the atts hash
+        else
+          { $att_val= $elt->{'att'}->{$exp->{att}}; }# $elt is an element
+
+        # 2 cases: either there is a val and the att value should be equal to it
+        #          or there is no val (condition was gi[@att]), just for the att to be defined 
+        if( defined $att_val && ( !defined $exp->{val} || ($att_val eq $exp->{val}) ) ) 
+              { push @found_handlers, $exp->{handler}; }
+          }
+      }
+
+    # check for an attribute regexp
+    if( $handlers->{attregexp_handlers}->{$gi})
+      { my @attregexp_handlers= @{$handlers->{attregexp_handlers_exp}->{$gi}};
+        foreach my $exp ( @attregexp_handlers)
+          { my $att_val;
+        # get the attribute value
+        if( ref $elt eq 'HASH')
+          { $att_val= $elt->{$exp->{att}}; }    # $elt is the atts hash
+        else
+          { $att_val= $elt->{'att'}->{$exp->{att}}; }# $elt is an element
+
+        if( defined $att_val && ( ($att_val=~  $exp->{regexp}) ) ) 
+              { push @found_handlers, $exp->{handler}; }
+          }
+      }
+
+    # check for a full path
+    if( defined $handlers->{path_handlers}->{gi}->{$gi})
+      { my $path= $t->path( $gi); 
+        if( defined( $found_handler= $handlers->{path_handlers}->{path}->{$path}) )
+          { push @found_handlers, $found_handler; }
+      }
+
+    # check for a partial path
+    if( $handlers->{subpath_handlers}->{gi}->{$gi})
+      { my $path= $t->path( $gi);
+        while( $path)
+          { # test each sub path
+            if( defined( $found_handler= $handlers->{subpath_handlers}->{path}->{$path}) )
+              { push @found_handlers, $found_handler; }
+             $path=~ s{^[^/]*/?}{}; # remove initial gi and /
+          }
+      }
+
+    # check for a gi (simple gi's are stored directly in the handlers field)
+    if( defined $handlers->{handlers}->{gi}->{$gi})
+      { push @found_handlers, $handlers->{handlers}->{gi}->{$gi}; }
+
+    # if no handler found call default handler if defined
+    if( !@found_handlers && defined $handlers->{handlers}->{$DEFAULT})
+      { push @found_handlers, $handlers->{handlers}->{$DEFAULT}; }
+
+    if( @found_handlers and $t->{twig_do_not_chain_handlers}) 
+      { @found_handlers= ($found_handlers[0]); }
+
+    return @found_handlers; # empty if no handler found
+
+  }
+
+
+sub _replace_prefix
+  { my( $t, $name)= @_;
+    my $p= $t->parser;
+    my $uri= $p->namespace( $name);
+    # try to get the namespace rom default if none is found (for attributes)
+    # this should probably be an option
+    if( !$uri and( $name!~/^xml/)) { $uri= $p->expand_ns_prefix( '#default'); }
+    if( $uri)
+      { if (my $mapped_prefix= $t->{twig_map_xmlns}->{$uri})
+          { return "$mapped_prefix:$name"; }
+        else
+          { my $prefix= _a_proper_ns_prefix( $p, $uri);
+            return $prefix ? "$prefix:$name" : $name; 
+          }
+      }
+    else
+      { return $name; }
+  }
+
+sub _twig_char
+  { 
+    my ($p, $string)= @_;
+    my $t=$p->{twig}; 
+
+    # if keep_encoding was set then use the original string instead of
+    # the parsed (UTF-8 converted) one
+    if( $t->{twig_keep_encoding})
+      { $string= $p->original_string(); }
+
+    if( $t->{twig_input_filter})
+      { $string= $t->{twig_input_filter}->( $string); }
+
+    if( $t->{twig_char_handler})
+      { $string= $t->{twig_char_handler}->( $string); }
+
+    my $elt= $t->{twig_current};
+
+    if(    $t->{twig_in_cdata})
+      { # text is the continuation of a previously created pcdata
+        $elt->{cdata}.=  $t->{twig_stored_spaces}.$string; } 
+    elsif( $t->{twig_in_pcdata})
+      { # text is the continuation of a previously created cdata
+        $elt->{pcdata}.=  $string; 
+      } 
+    else
+      { # text is just space, which might be discarded later
+        if( $string=~/\A\s*\Z/s)
+          { if( $t->{extra_data})
+              { # we got extra data (comment, pi), lets add the spaces to it
+                $t->{extra_data} .= $string; 
+              }
+            else
+              { # no extra data, just store the spaces
+                $t->{twig_stored_spaces}.= $string;
+              }
+          } 
+        else
+          { my $new_elt= _insert_pcdata( $t, $t->{twig_stored_spaces}.$string);
+            delete $elt->{'twig_current'};
+            $new_elt->{'twig_current'}=1;
+            $t->{twig_current}= $new_elt;
+            $t->{twig_in_pcdata}=1;
+            $new_elt->{extra_data}= $t->{extra_data} if( $t->{extra_data});
+            $t->{extra_data}='';
+          }
+      }
+  }
+
+sub _twig_cdatastart
+  { 
+    my $p= shift;
+    my $t=$p->{twig};
+
+    $t->{twig_in_cdata}=1;
+    my $cdata=  $t->{twig_elt_class}->new( '#CDATA');
+    my $twig_current= $t->{twig_current};
+
+    if( $t->{twig_in_pcdata})
+      { # create the node as a sibling of the #PCDATA
+        $cdata->set_prev_sibling( $twig_current);
+        $twig_current->{next_sibling}=  $cdata;
+        my $parent= $twig_current->{parent};
+        $cdata->set_parent( $parent);
+        $parent->set_last_child( $cdata);
+        $t->{twig_in_pcdata}=0;
+      }
+    else
+      { # we have to create a PCDATA element if we need to store spaces
+        if( $t->_space_policy($XML::Twig::index2gi[$twig_current->{'gi'}]) && $t->{twig_stored_spaces})
+          { _insert_pcdata( $t, $t->{twig_stored_spaces}); }
+        $t->{twig_stored_spaces}='';
+      
+        # create the node as a child of the current element      
+        $cdata->set_parent( $twig_current);
+        if( my $prev_sibling= $twig_current->{last_child})
+          { $cdata->set_prev_sibling( $prev_sibling);
+            $prev_sibling->{next_sibling}=  $cdata;
+          }
+        else
+          { $twig_current->{first_child}=  $cdata; }
+        $twig_current->set_last_child( $cdata);
+      
+      }
+
+    delete $twig_current->{'twig_current'};
+    $t->{twig_current}= $cdata;
+    $cdata->{'twig_current'}=1;
+  }
+
+sub _twig_cdataend
+  { 
+    my $p= shift;
+    my $t=$p->{twig};
+
+    $t->{twig_in_cdata}=0;
+
+    my $elt= $t->{twig_current};
+    delete $elt->{'twig_current'};
+    my $cdata= $elt->{cdata};
+    $elt->{cdata}=  $cdata;
+
+    if( $t->{twig_handlers})
+      { # look for handlers
+        my @handlers= _handler( $t, $t->{twig_handlers}, CDATA, $elt);
+        local $_= $elt; # so we can use $_ in the handlers
+        foreach my $handler ( @handlers) { $handler->($t, $elt) || last; }
+      }
+
+    $elt= $elt->{parent};
+    $t->{twig_current}= $elt;
+    $elt->{'twig_current'}=1;
+  }
+
+sub _twig_pi
+  { 
+    my( $p, $target, $data)= @_;
+    my $t=$p->{twig};
+    return unless( $t->{twig_process_pi} || $t->{twig_keep_pi});
+
+    if( $t->{twig_input_filter})
+      { $target = $t->{twig_input_filter}->( $target) ;
+        $data   = $t->{twig_input_filter}->( $data)   ;
+      }
+
+    my $twig_current= $t->{twig_current};    # always defined
+
+    # if pi's are to be kept then we piggiback them to the current element
+    if( $t->{twig_keep_pi})
+      {  
+        if( my $handler= $t->{twig_handlers}->{pi_handlers}->{$target})
+          { $t->{extra_data}.= $handler->( $t, $target, $data); }
+        elsif( $handler= $t->{twig_handlers}->{pi_handlers}->{''})
+          { $t->{extra_data}.= $handler->( $t, $target, $data); }
+        else
+          { if( $t->{twig_stored_spaces})
+              { $t->{extra_data}.= $t->{twig_stored_spaces};
+                $t->{twig_stored_spaces}= '';
+              }
+            # then the recognized/original string (input filtered if needed)
+            my $extra_data= $XML::Twig::Elt::keep_encoding ?  $p->recognized_string() : $p->original_string();
+            $extra_data= $t->{twig_input_filter}->( $extra_data) if( $t->{twig_input_filter});
+            $t->{extra_data}.= $extra_data;
+            return;
+          }
+
+      }
+    else
+      { # pi's are processed
+        my $pi=  $t->{twig_elt_class}->new( PI);
+        $pi->set_pi( $target, $data);
+
+        unless( $t->root)
+          {  _pi_handlers( $t, $pi, $target);
+            _add_prolog_data( $t, $pi); 
+            return;
+          }
+
+        if( $t->{twig_in_pcdata})
+          { # create the node as a sibling of the #PCDATA
+            $pi->paste_after( $twig_current);
+            $t->{twig_in_pcdata}=0;
+          }
+        else
+          { # we have to create a PCDATA element if we need to store spaces
+            if( $t->_space_policy($XML::Twig::index2gi[$twig_current->{'gi'}]) && $t->{twig_stored_spaces})
+              { _insert_pcdata( $t, $t->{twig_stored_spaces}); }
+            $t->{twig_stored_spaces}='';
+            # create the node as a child of the current element
+            $pi->paste_last_child( $twig_current);
+          }
+    
+        delete $twig_current->{'twig_current'};
+        my $parent= $pi->{parent}; 
+        $t->{twig_current}= $parent;
+        $parent->{'twig_current'}=1;
+
+        _pi_handlers( $t, $pi, $target);
+      }
+
+  }
+
+sub _pi_handlers
+  { my( $t, $pi, $target)= @_;
+    if( my $handler= $t->{twig_handlers}->{pi_handlers}->{$target})
+      { local $_= $pi; $handler->( $t, $pi); }
+    elsif( $handler= $t->{twig_handlers}->{pi_handlers}->{''})
+      { local $_= $pi; $handler->( $t, $pi); }
+  }
+
+
+sub _twig_comment
+  { 
+    my( $p, $comment_text)= @_;
+    my $t=$p->{twig};
+    return unless( $t->{twig_process_comments} || $t->{twig_keep_comments});
+
+    my $twig_current= $t->{twig_current};    # always defined
+
+    # if comments are to be kept then we piggiback them to the current element
+    if( $t->{twig_keep_comments})
+      { # first add spaces
+        if( $t->{twig_stored_spaces})
+              { $t->{extra_data}.= $t->{twig_stored_spaces};
+                $t->{twig_stored_spaces}= '';
+              }
+        # then the recognized/original string (input filtered if needed)
+        my $extra_data= $XML::Twig::Elt::keep_encoding ?  $p->recognized_string() : $p->original_string();
+        $extra_data= $t->{twig_input_filter}->( $extra_data) if( $t->{twig_input_filter});
+        $t->{extra_data}.= $extra_data;
+        return;
+      }
+
+    $comment_text= $t->{twig_input_filter}->( $comment_text) if( $t->{twig_input_filter});
+
+    my $comment=  $t->{twig_elt_class}->new( COMMENT);
+    $comment->{comment}=  $comment_text;
+
+    unless( $t->root) 
+      { _add_prolog_data( $t, $comment);
+        _comment_handler( $t, $comment);
+        return;
+      }
+
+    if( $t->{twig_in_pcdata})
+      { # create the node as a sibling of the #PCDATA
+        $comment->paste_after( $twig_current);
+        $t->{twig_in_pcdata}=0;
+      }
+    else
+      { # we have to create a PCDATA element if we need to store spaces
+        if( $t->_space_policy($XML::Twig::index2gi[$twig_current->{'gi'}]) && $t->{twig_stored_spaces})
+          { _insert_pcdata( $t, $t->{twig_stored_spaces}); }
+        $t->{twig_stored_spaces}='';
+        # create the node as a child of the current element
+        $comment->paste_last_child( $twig_current);
+
+      }
+    _comment_handler( $t, $comment);
+
+    delete $twig_current->{'twig_current'};
+
+    my $parent= $comment->{parent};
+    $t->{twig_current}= $parent;
+    $parent->{'twig_current'}=1;
+
+  }
+
+sub _comment_handler
+  { my( $t, $comment)= @_;
+    if( $t->{twig_handlers}->{handlers}->{gi}->{'#COMMENT'})
+      { # look for handlers
+        local $_= $comment;
+        my @handlers= _handler( $t, $t->{twig_handlers}, '#COMMENT', $comment);
+        foreach my $handler ( @handlers)
+          { $handler->($t, $comment) || last; }
+      }
+  }
+
+
+sub _add_prolog_data
+  { my($t, $prolog_data)= @_;
+    # comment before the first element
+    $t->{prolog_data} ||= $t->{twig_elt_class}->new( '#PROLOG_DATA');
+    # create the node as a child of the current element
+    $prolog_data->paste_last_child( $t->{prolog_data});
+  }
+  
+sub _twig_final
+  { 
+    my $p= shift;
+    my $t=$p->{twig};
+
+    # restore the selected filehandle if needed
+    $t->_set_fh_to_selected_fh();
+
+    select $t->{twig_original_selected_fh} if($t->{twig_original_selected_fh}); # probably dodgy
+
+    # tries to clean-up (probably not very well at the moment)
+    undef $p->{twig};
+    undef $t->{twig_parser};
+
+    undef $t->{twig_parsing};
+
+    return $t;
+  }
+
+sub _insert_pcdata
+  { my( $t, $string)= @_;
+    # create a new #PCDATA element
+    my $parent= $t->{twig_current};    # always defined
+    my $elt=  $t->{twig_elt_class}->new( PCDATA);
+    $elt->{pcdata}=  $string;
+    my $prev_sibling= $parent->{last_child};
+    if( $prev_sibling) 
+      { $prev_sibling->{next_sibling}=  $elt; 
+        $elt->set_prev_sibling( $prev_sibling);
+      }
+    else
+      { $parent->{first_child}=  $elt; }
+
+    $elt->set_parent( $parent);
+    $parent->set_last_child( $elt);
+    $t->{twig_stored_spaces}='';
+    return $elt;
+  }
+
+sub _space_policy
+  { my( $t, $gi)= @_;
+    my $policy;
+    $policy=0 if( $t->{twig_discard_spaces});
+    $policy=1 if( $t->{twig_keep_spaces});
+    $policy=1 if( $t->{twig_keep_spaces_in}
+               && $t->{twig_keep_spaces_in}->{$gi});
+    $policy=0 if( $t->{twig_discard_spaces_in} 
+               && $t->{twig_discard_spaces_in}->{$gi});
+    return $policy;
+  }
+
+
+sub _twig_entity($$$$$$)
+  { 
+    my( $p, $name, $val, $sysid, $pubid, $ndata)= @_;
+    my $t=$p->{twig};
+    my $ent=XML::Twig::Entity->new( $name, $val, $sysid, $pubid, $ndata);
+    $t->{twig_entity_list}->add( $ent);
+    if( $parser_version > 2.27) 
+      { # this is really ugly, but with some versions of XML::Parser the value 
+        # of the entity is not properly returned by the default handler
+        my $ent_decl= $ent->text;
+        if( $t->{twig_keep_encoding})
+          { if( defined $ent->{val} && ($ent_decl !~ /["']/))
+              { my $val=  $ent->{val};
+                $ent_decl .= $val =~ /"/ ? qq{'$val' } : qq{"$val" }; 
+              }
+				    # for my solaris box (perl 5.6.1, XML::Parser 2.31, expat?)
+            $t->{twig_doctype}->{internal}=~ s{<!ENTITY\s+$name\s+$}{substr( $ent_decl, 0, -1)}e;
+          }
+        $t->{twig_doctype}->{internal} .= $ent_decl 
+          unless( $t->{twig_doctype}->{internal}=~ m{<!ENTITY\s+$name\s+});
+      }
+  }
+
+sub _twig_xmldecl
+  { 
+    my $p= shift;
+    my $t=$p->{twig};
+    $t->{twig_xmldecl}||={};                 # could have been set by set_output_encoding
+    $t->{twig_xmldecl}->{version}= shift;
+    $t->{twig_xmldecl}->{encoding}= shift; 
+    $t->{twig_xmldecl}->{standalone}= shift;
+  }
+
+sub _twig_doctype
+  { 
+    my( $p, $name, $sysid, $pub, $internal)= @_;
+    my $t=$p->{twig};
+    $t->{twig_doctype}||= {};                   # create 
+    $t->{twig_doctype}->{name}= $name;          # always there
+    $t->{twig_doctype}->{sysid}= $sysid;        #  
+    $t->{twig_doctype}->{pub}= $pub;            #  
+
+    # now let's try to cope with XML::Parser 2.28 and above
+    if( $parser_version > 2.27)
+      { @saved_default_handler= $p->setHandlers( Default     => \&_twig_store_internal_dtd,
+                                                 Entity      => \&_twig_entity,
+                                               );
+      $p->setHandlers( DoctypeFin  => \&_twig_stop_storing_internal_dtd);
+      $t->{twig_doctype}->{internal}='';
+      }
+    else            
+      # for XML::Parser before 2.28
+      { $t->{twig_doctype}->{internal}=$internal; }
+
+    # now check if we want to get the DTD info
+    if( $t->{twig_read_external_dtd} && $sysid)
+      { # let's build a fake document with an internal DTD
+        # is this portable?
+        my $tmpfile= "twig_tmp$$";
+        open( TMP, ">$tmpfile") 
+          or croak "cannot create temp file $tmpfile: $!";
+        print TMP "<!DOCTYPE $name [\n";   # print the doctype
+        # slurp the DTD
+          { open( DTD, "<$sysid") 
+              or croak "cannot open dtd file $sysid: $!";
+            local $/= undef;
+            my $dtd= <DTD>;
+            close DTD;
+            print TMP $dtd;                 # add the dtd
+          }
+        print TMP "]>";                     # close the dtd
+        print TMP "<dummy></dummy>\n";      # XML::Parser needs an element
+
+        close TMP;
+       
+        $t->save_global_state();            # save the globals (they will be reset by the following new)  
+        my $t_dtd= XML::Twig->new;          # create a temp twig
+        $t->restore_global_state();
+        $t_dtd->parsefile( $tmpfile);       # parse it
+        $t->{twig_dtd}= $t_dtd->{twig_dtd}; # grab the dtd info
+        #$t->{twig_dtd_is_external}=1;
+        $t->{twig_entity_list}= $t_dtd->{twig_entity_list}; # grab the entity info
+
+        unlink $tmpfile;
+      }
+
+  }
+
+sub _twig_element
+  { 
+    my( $p, $name, $model)= @_;
+    my $t=$p->{twig};
+    $t->{twig_dtd}||= {};                      # may create the dtd 
+    $t->{twig_dtd}->{model}||= {};             # may create the model hash 
+    $t->{twig_dtd}->{elt_list}||= [];          # ordered list of elements 
+    push @{$t->{twig_dtd}->{elt_list}}, $name; # store the elt
+    $t->{twig_dtd}->{model}->{$name}= $model;  # store the model
+    if( ($parser_version > 2.27) && ($t->{twig_doctype}->{internal}=~ m{(^|>)\s*$}) ) 
+      { my $text= $XML::Twig::Elt::keep_encoding ? $p->original_string : $p->recognized_string; 
+        unless( $text)
+          { # this version of XML::Parser does not return the text in the *_string method
+            # we need to rebuild it
+            $text= "<!ELEMENT $name $model>";
+          }
+        $t->{twig_doctype}->{internal} .= $text;
+      }
+  }
+
+sub _twig_attlist
+  { 
+    my( $p, $el, $att, $type, $default, $fixed)= @_;
+    my $t=$p->{twig};
+    $t->{twig_dtd}||= {};                      # create dtd if need be 
+    $t->{twig_dtd}->{$el}||= {};               # create elt if need be 
+    #$t->{twig_dtd}->{$el}->{att}||= {};        # create att if need be 
+    if( ($parser_version > 2.27) && ($t->{twig_doctype}->{internal}=~ m{(^|>)\s*$}) ) 
+      { my $text= $XML::Twig::Elt::keep_encoding ? $p->original_string : $p->recognized_string; 
+        unless( $text)
+          { # this version of XML::Parser does not return the text in the *_string method
+            # we need to rebuild it
+            my $att_decl="$att $type";
+            $att_decl .= " #FIXED"   if( $fixed);
+            $att_decl .= " $default" if( $default);
+            # 2 cases: there is already an attlist on that element or not
+            if( $t->{twig_dtd}->{att}->{$el})
+              { # there is already an attlist, add to it
+                $t->{twig_doctype}->{internal}=~ s{(<!ATTLIST\s*$el )(.*?)\n?>}
+                                                  { "$1$2\n" . ' ' x length( $1) . "$att_decl\n>"}es;
+              }
+            else
+              { # create the attlist
+                 $t->{twig_doctype}->{internal}.= "<!ATTLIST $el $att_decl>"
+              }
+          }
+      }
+    $t->{twig_dtd}->{att}->{$el}->{$att}= {} ;
+    $t->{twig_dtd}->{att}->{$el}->{$att}->{type}= $type; 
+    $t->{twig_dtd}->{att}->{$el}->{$att}->{default}= $default; 
+    $t->{twig_dtd}->{att}->{$el}->{$att}->{fixed}= $fixed; 
+  }
+
+sub _twig_default
+  { 
+    my( $p, $string)= @_;
+    
+    my $t= $p->{twig};
+    
+    # process only if we have an entity
+    return unless( $string=~ m{^&([^;]*);$});
+    # the entity has to be pure pcdata, or we have a problem
+    my $ent;
+    if( $t->{twig_keep_encoding}) 
+      { _twig_char( $p, $string); 
+        $ent= substr( $string, 1, -1);
+      }
+    else
+      { $ent= _twig_insert_ent( $t, $string); 
+      }
+  }
+    
+sub _twig_insert_ent
+  { 
+    my( $t, $string)=@_;
+
+    my $twig_current= $t->{twig_current};
+
+    my $ent=  $t->{twig_elt_class}->new( '#ENT');
+    $ent->{ent}=  $string;
+
+    _add_or_discard_stored_spaces( $t, force => 0);
+    
+    if( $t->{twig_in_pcdata})
+      { # create the node as a sibling of the #PCDATA
+
+        $ent->set_prev_sibling( $twig_current);
+        $twig_current->{next_sibling}=  $ent;
+        my $parent= $twig_current->{parent};
+        $ent->set_parent( $parent);
+        $parent->set_last_child( $ent);
+        # the twig_current is now the parent
+        delete $twig_current->{'twig_current'};
+        $t->{twig_current}= $parent;
+        # we left pcdata
+        $t->{twig_in_pcdata}=0;
+      }
+    else
+      { # create the node as a child of the current element
+        $ent->set_parent( $twig_current);
+        if( my $prev_sibling= $twig_current->{last_child})
+          { $ent->set_prev_sibling( $prev_sibling);
+            $prev_sibling->{next_sibling}=  $ent;
+          }
+        else
+          { $twig_current->{first_child}=  $ent; }
+        $twig_current->set_last_child( $ent);
+      }
+
+    return $ent;
+  }
+
+sub parser
+  { return $_[0]->{twig_parser}; }
+
+# returns the declaration text (or a default one)
+sub xmldecl
+  { my $t= shift;
+    return '' unless( $t->{twig_xmldecl} || $t->{output_encoding});
+    my $decl_string;
+    my $decl= $t->{twig_xmldecl};
+    if( $decl)
+      { my $version= $decl->{version};
+        $decl_string= q{<?xml};
+        $decl_string .= qq{ version="$version"};
+
+        # encoding can either have been set (in $decl->{output_encoding})
+        # or come from the document (in $decl->{encoding})
+        if( $t->{output_encoding})
+          { my $encoding= $t->{output_encoding};
+            $decl_string .= qq{ encoding="$encoding"};
+          }
+        elsif( $decl->{encoding})
+          { my $encoding= $decl->{encoding};
+            $decl_string .= qq{ encoding="$encoding"};
+          }
+    
+        if( defined( $decl->{standalone}))
+          { $decl_string .= q{ standalone="};  
+            $decl_string .= $decl->{standalone} ? "yes" : "no";  
+            $decl_string .= q{"}; 
+          }
+      
+        $decl_string .= "?>\n";
+      }
+    else
+      { my $encoding= $t->{output_encoding};
+        $decl_string= qq{<?xml version="1.0" encoding="$encoding"?>};
+      }
+      
+    my $output_filter= XML::Twig::Elt::output_filter();
+    return $output_filter ? $output_filter->( $decl_string) : $decl_string;
+  }
+
+# returns the doctype text (or none)
+# that's the doctype just has it was in the original document
+sub doctype
+  { my $t= shift;
+    my $doctype= $t->{twig_doctype} or return '';
+    my $string= "<!DOCTYPE " . $doctype->{name};
+    $string  .= qq{ SYSTEM "$doctype->{sysid}"} if( $doctype->{sysid});
+    $string  .= qq{ PUBLIC  "$doctype->{pub}" } if( $doctype->{pub});
+    if( $doctype->{internal})
+      { # !@#$%^&* code to deal with various expat/XML::Parser versions
+        $string.= " [" unless( $doctype->{internal}=~ m{^\s*\[});
+        $string.= " " if( $doctype->{internal}=~ m{^\[});
+        $string  .= $doctype->{internal};
+        $string=~ s{\n?]?>?$}{\n]>};
+      }
+    return $string;
+  }
+
+sub set_doctype
+  { my( $t, $name, $system, $public, $internal)= @_;
+    $t->{twig_doctype}= {};
+    my $doctype= $t->{twig_doctype};
+    $doctype->{name}     = $name     if( defined $name);
+    $doctype->{sysid}    = $system   if( defined $system);
+    $doctype->{pub}      = $public   if( defined $public);
+    $doctype->{internal} = $internal if( defined $internal);
+  }
+
+# return the dtd object
+sub dtd
+  { my $t= shift;
+    return $t->{twig_dtd};
+  }
+
+# return an element model, or the list of element models
+sub model
+  { my $t= shift;
+    my $elt= shift;
+    return $t->dtd->{model}->{$elt} if( $elt);
+    return sort keys %{$t->dtd->{model}};
+  }
+
+        
+# return the entity_list object 
+sub entity_list($)
+  { my $t= shift;
+    return $t->{twig_entity_list};
+  }
+
+# return the list of entity names 
+sub entity_names($)
+  { my $t= shift;
+    return sort keys %{$t->{twig_entity_list}} ;
+  }
+
+# return the entity object 
+sub entity($$)
+  { my $t= shift;
+    my $entity_name= shift;
+    return $t->{twig_entity_list}->{$entity_name};
+  }
+
+
+sub print_prolog
+  { my $t= shift;
+    my $fh=  _is_fh($_[0])  ? shift : undef;
+    if( $fh) { print $fh $t->prolog( @_); }
+    else     { print $t->prolog( @_);     }
+  }
+
+sub prolog
+  { my $t= shift;
+    my %args= _normalize_args( @_);
+    my $prolog='';
+
+    return $prolog if( $t->{no_prolog});
+
+    my $update_dtd = $args{UpdateDTD} || '';
+
+    $prolog .= $t->xmldecl;
+    return $prolog if( defined( $t->{no_dtd_output}) or !(defined $t->{twig_doctype}));
+    my $doctype= $t->{twig_doctype};
+    if( $update_dtd)
+      { 
+        if( defined $doctype->{sysid}  )  
+          { $prolog .= "<!DOCTYPE ".$doctype->{name};
+            $prolog .= " PUBLIC  \"$doctype->{pub}\""  if( $doctype->{pub});
+            $prolog .= " SYSTEM \"$doctype->{sysid}\"" if( $doctype->{sysid} && !$doctype->{pub});
+            $prolog .= "[\n";
+            $prolog .= $t->{twig_entity_list}->text;
+            $prolog .= "]>\n";
+          }
+        else
+          { my $dtd= $t->{'twig_dtd'};
+            $prolog .= $t->dtd_text;
+          }            
+      }
+    else
+      { 
+        $prolog .= "<!DOCTYPE ". $doctype->{name}  if( $doctype->{name});
+        $prolog .= " PUBLIC \"$doctype->{pub}\""  if( $doctype->{pub});
+        $prolog .= " SYSTEM" if( $doctype->{sysid} && !$doctype->{pub});
+        $prolog .= ' "' . $doctype->{sysid} . '"'  if( $doctype->{sysid}); 
+        if( my $internal= $doctype->{internal}) 
+          { # add opening and closing brackets if not already there
+            # plus some spaces and newlines for a nice formating
+            # I test it here because I can't remember which version of
+            # XML::Parser need it or not, so this is actually quite safe
+            $internal=~ s{^\s*(\[\s*)?}{ [\n};
+            $internal=~ s{\s*(\]\s*(>\s*)?)?\s*$}{\n]>\n};
+            $prolog .=  $internal; 
+          }
+      }
+
+    # terrible hack, as I can't figure out in which case the darn prolog
+    # should get an extra >
+    $prolog=~ s/(>\s*)*$/>\n/;
+
+    my $output_filter= XML::Twig::Elt::output_filter();
+    return $output_filter ? $output_filter->( $prolog) : $prolog;
+  }
+
+sub _print_prolog_data
+  { my $t= shift;
+    my $fh=  _is_fh($_[0])  ? shift : undef;
+    if( $fh) { print $fh $t->_prolog_data( @_); }
+    else     { print $t->_prolog_data( @_);     }
+  }
+
+sub _prolog_data
+  { my $t= shift;
+    return''  unless( $t->{prolog_data});
+    my $prolog_data_text='';
+    foreach ( $t->{prolog_data}->children)
+      { $prolog_data_text .= $_->sprint . "\n"; }
+    return$ prolog_data_text;
+  }
+
+sub print
+  { my $t= shift;
+    my $fh=  _is_fh( $_[0])  ? shift : undef;
+    my %args= _normalize_args( @_);
+
+    my $old_pretty;
+    if( defined $args{PrettyPrint})
+      { $old_pretty= $t->set_pretty_print( $args{PrettyPrint}); 
+        delete $args{PrettyPrint};
+      }
+
+     my $old_empty_tag_style;
+     if( defined $args{EmptyTags})
+      { $old_empty_tag_style= $t->set_empty_tag_style( $args{EmptyTags}); 
+        delete $args{EmptyTags};
+      }
+
+    if( $fh) 
+      { $t->print_prolog( $fh, %args); 
+        $t->_print_prolog_data( $fh, %args);
+      }
+    else 
+      { $t->print_prolog( %args);
+        $t->_print_prolog_data( %args);
+      }
+
+    $t->{twig_root}->print( $fh) if( $t->{twig_root});
+    $t->set_pretty_print( $old_pretty) if( defined $old_pretty); 
+    $t->set_empty_tag_style( $old_empty_tag_style) if( defined $old_empty_tag_style); 
+  }
+
+
+sub flush
+  { my $t= shift;
+    my $fh=  _is_fh( $_[0]) ? shift : undef;
+    my $old_select= defined $fh ? select $fh : undef;
+    my $up_to= ref $_[0] ? shift : undef;
+    my %args= _normalize_args( @_);
+
+    my $old_pretty;
+    if( defined $args{PrettyPrint})
+      { $old_pretty= $t->set_pretty_print( $args{PrettyPrint}); 
+        delete $args{PrettyPrint};
+      }
+
+     my $old_empty_tag_style;
+     if( $args{EmptyTags})
+      { $old_empty_tag_style= $t->set_empty_tag_style( $args{EmptyTags}); 
+        delete $args{EmptyTags};
+      }
+
+
+    # the "real" last element processed, as _twig_end has closed it
+    my $last_elt;
+    if( $up_to)
+      { $last_elt= $up_to; }
+    elsif( $t->{twig_current})
+      { $last_elt= $t->{twig_current}->_last_child; }
+    else
+      { $last_elt= $t->{twig_root}; }
+
+    # flush the DTD unless it has ready flushed (ie root has been flushed)
+    my $elt= $t->{twig_root};
+    $t->print_prolog( %args) unless( $elt->_flushed);
+
+    while( $elt)
+      { my $next_elt; 
+        if( $last_elt && $last_elt->in( $elt))
+          { 
+            unless( $elt->_flushed) 
+              { # just output the front tag
+                print $elt->start_tag();
+                $elt->_set_flushed;
+              }
+            $next_elt= $elt->{first_child};
+          }
+        else
+          { # an element before the last one or the last one,
+            $next_elt= $elt->{next_sibling};  
+            $elt->_flush();
+            $elt->delete; 
+            last if( $last_elt && ($elt == $last_elt));
+          }
+        $elt= $next_elt;
+      }
+    select $old_select if( defined $old_select);
+    $t->set_pretty_print( $old_pretty) if( defined $old_pretty); 
+    $t->set_empty_tag_style( $old_empty_tag_style) if( defined $old_empty_tag_style); 
+  }
+
+
+# flushes up to an element
+# this method just reorders the arguments and calls flush
+sub flush_up_to
+  { my $t= shift;
+    my $up_to= shift;
+    if( _is_fh( $_[0]))
+      { my $fh=  shift;
+        $t->flush( $fh, $up_to, @_);
+      }
+    else
+      { $t->flush( $up_to, @_); }
+  }
+
+    
+# same as print except the entire document text is returned as a string
+sub sprint
+  { my $t= shift;
+    my %args= _normalize_args( @_);
+
+    my $old_pretty;
+    if( defined $args{PrettyPrint})
+      { $old_pretty= $t->set_pretty_print( $args{PrettyPrint}); 
+        delete $args{PrettyPrint};
+      }
+
+     my $old_empty_tag_style;
+     if( defined $args{EmptyTags})
+      { $old_empty_tag_style= $t->set_empty_tag_style( $args{EmptyTags}); 
+        delete $args{EmptyTags};
+      }
+      
+    my $prolog= $t->prolog( %args) || '';
+    my $prolog_data= $t->_prolog_data( %args) || '';
+    
+    my $string=  $prolog . $prolog_data . $t->{twig_root}->sprint;
+
+    $t->set_pretty_print( $old_pretty) if( defined $old_pretty); 
+    $t->set_empty_tag_style( $old_empty_tag_style) if( defined $old_empty_tag_style); 
+
+    return $string;
+  }
+    
+
+# this method discards useless elements in a tree
+# it does the same thing as a flush except it does not print it
+# the second argument is an element, the last purged element
+# (this argument is usually set through the purge_up_to method)
+sub purge
+  { my $t= shift;
+    my $up_to= shift;
+
+    # the "real" last element processed, as _twig_end has closed it
+    my $last_elt;
+    if( $up_to)
+      { $last_elt= $up_to; }
+    elsif( $t->{twig_current})
+      { $last_elt= $t->{twig_current}->_last_child; }
+    else
+      { $last_elt= $t->{twig_root}; }
+    
+    my $elt= $t->{twig_root};
+
+    while( $elt)
+      { my $next_elt; 
+        if( $last_elt && $last_elt->in( $elt))
+          { $elt->_set_flushed;
+            $next_elt= $elt->{first_child};
+          }
+        else
+          { # an element before the last one or the last one,
+            $next_elt= $elt->{next_sibling};  
+            $elt->delete; 
+            last if( $elt == $last_elt);
+          }
+        $elt= $next_elt;
+      }
+  }
+    
+# flushes up to an element. This method just calls purge
+sub purge_up_to
+  { my $t= shift;
+    my $up_to= shift;
+    $t->purge( $up_to);
+  }
+
+sub root
+  { return $_[0]->{twig_root}; }
+
+#start-extract twig_document (used to generate XML::(DOM|GDOME)::Twig)
+sub first_elt
+  { my( $t, $cond)= @_;
+    my $root= $t->root || return undef;
+    return $root if( $root->passes( $cond));
+    return $root->next_elt( $cond); 
+  }
+
+sub next_n_elt
+  { my( $t, $offset, $cond)= @_;
+    $offset -- if( $t->root->matches( $cond) );
+    return $t->root->next_n_elt( $offset, $cond);
+  }
+
+sub get_xpath
+  { my $twig= shift;
+    if( isa( $_[0], 'ARRAY'))
+      { my $elt_array= shift;
+        return _unique_elts( map { $_->get_xpath( @_) } @$elt_array);
+      }
+    else
+      { return $twig->root->get_xpath( @_); }
+  }
+
+# get a list of elts and return a sorted list of unique elts
+sub _unique_elts
+  { my @sorted= sort { $a ->cmp( $b) } @_;
+    my @unique;
+    while( my $current= shift @sorted)
+      { push @unique, $current unless( @unique && ($unique[-1] == $current)); }
+    return @unique;
+  }
+
+sub findvalue
+  { my $twig= shift;
+    if( isa( $_[0], 'ARRAY'))
+      { my $elt_array= shift;
+        return join( '', map { $_->findvalue( @_) } @$elt_array);
+      }
+    else
+      { return $twig->root->findvalue( @_); }
+  }
+
+sub set_id_seed
+  { my $t= shift;
+    XML::Twig::Elt->set_id_seed( @_);
+  }
+
+
+# return a list with just the root
+# if a condition is given then return an empty list unless the root matches
+sub children
+  { my( $t, $cond)= @_;
+    my $root= $t->root;
+    unless( $cond && !($root->passes( $cond)) )
+      { return ($root); }
+    else
+      { return (); }
+  }
+
+sub _children
+  { return ($_[0]->root); }
+
+sub descendants
+  { my( $t, $cond)= @_;
+    my $root= $t->root;
+    if( $root->passes( $cond) )
+      { return ($root, $root->descendants( $cond)); }
+    else
+      { return ( $root->descendants( $cond)); }
+  }
+
+sub simplify
+  { my $t= shift;
+    $t->root->simplify( @_);
+  }
+
+sub subs_text
+  { my $t= shift;
+    $t->root->subs_text( @_);
+  }
+
+#end-extract twig_document
+
+sub set_keep_encoding
+  { return XML::Twig::Elt::set_keep_encoding( @_); }
+
+sub set_expand_external_entities
+  { return XML::Twig::Elt::set_expand_external_entities( @_); }
+
+# WARNING: at the moment the id list is not updated reliably
+sub elt_id
+  { return $_[0]->{twig_id_list}->{$_[1]}; }
+
+# change it in ALL twigs at the moment
+sub change_gi 
+  { my( $twig, $old_gi, $new_gi)= @_;
+    my $index;
+    return unless($index= $XML::Twig::gi2index{$old_gi});
+    $XML::Twig::index2gi[$index]= $new_gi;
+    delete $XML::Twig::gi2index{$old_gi};
+    $XML::Twig::gi2index{$new_gi}= $index;
+  }
+
+
+# builds the DTD from the stored (possibly updated) data
+sub dtd_text
+  { my $t= shift;
+    my $dtd= $t->{twig_dtd};
+    my $doctype= $t->{twig_doctype} or return '';
+    my $string= "<!DOCTYPE ".$doctype->{name};
+
+    unless( $parser_version > 3.27) { $string .= " [\n"; }
+
+    foreach my $gi (@{$dtd->{elt_list}})
+      { $string.= "<!ELEMENT $gi ".$dtd->{model}->{$gi}.">\n" ;
+        if( $dtd->{att}->{$gi})
+          { my $attlist= $dtd->{att}->{$gi};
+            $string.= "<!ATTLIST $gi\n";
+            foreach my $att ( sort keys %{$attlist})
+              { $string.= "   $att $attlist->{$att}->{type} ".
+                            "$attlist->{$att}->{default}"; 
+                if( $attlist->{$att}->{fixed})
+                  { $string .= " #FIXED"};
+                $string.= "\n";
+              }
+            $string.= ">\n";
+          }
+      }
+    $string.= $t->entity_list->text if( $t->entity_list);
+    $string.= "\n]>\n";
+    return $string;
+  }
+        
+# prints the DTD from the stored (possibly updated) data
+sub dtd_print
+  { my $t= shift;
+    my $fh=  _is_fh( $_[0])  ? shift : undef;
+    if( $fh) { print $fh $t->dtd_text; }
+    else     { print $t->dtd_text; }
+  }
+
+# build the subs that call directly expat
+BEGIN
+  { my @expat_methods= qw( depth in_element within_element context
+                           current_line current_column current_byte
+                           recognized_string original_string 
+                           xpcroak xpcarp 
+                           xml_escape
+                           base current_element element_index 
+                           position_in_context);
+    foreach my $method (@expat_methods)
+      { no strict 'refs';
+        *{$method}= sub { my $t= shift;
+                          croak "calling $method after parsing is finished" 
+                                 unless( $t->{twig_parsing}); 
+                          return $t->{twig_parser}->$method(@_); 
+                        };
+      }
+  }
+
+sub path
+  { my( $t, $gi)= @_;
+    return "/" . join( "/", ($t->{twig_parser}->context, $gi));
+  }
+
+sub finish
+  { my $t= shift;
+    return $t->{twig_parser}->finish;
+  }
+
+# just finish the parse by printing the rest of the document
+sub finish_print
+  { my( $t, $fh)= @_;
+    my $old_fh;
+    unless( defined $fh)
+      { $t->_set_fh_to_twig_output_fh(); }
+    elsif( defined $fh)
+      { $old_fh= select $fh; 
+        $t->{twig_original_selected_fh}= $old_fh if( $old_fh); 
+      }
+    
+    my $p=$t->{twig_parser};
+    if( $t->{twig_keep_encoding})
+      { $p->setHandlers( %twig_handlers_finish_print); }
+    else
+      { $p->setHandlers( %twig_handlers_finish_print_original); }
+  }
+
+sub output_filter { return XML::Twig::Elt::output_filter( @_); }
+sub set_output_filter { return XML::Twig::Elt::set_output_filter( @_); }
+
+sub output_text_filter { return XML::Twig::Elt::output_text_filter( @_); }
+sub set_output_text_filter { return XML::Twig::Elt::set_output_text_filter( @_); }
+
+sub set_input_filter
+  { my( $t, $input_filter)= @_;
+    my $old_filter= $t->{twig_input_filter};
+      if( !$input_filter || isa( $input_filter, 'CODE') )
+        { $t->{twig_input_filter}= $input_filter; }
+      elsif( $input_filter eq 'latin1')
+        {  $t->{twig_input_filter}= latin1(); }
+      elsif( $filter{$input_filter})
+        {  $t->{twig_input_filter}= $filter{$input_filter}; }
+      else
+        { croak "invalid input filter: $input_filter"; }
+      
+      return $old_filter;
+    }
+
+sub set_empty_tag_style
+  { return XML::Twig::Elt::set_empty_tag_style( @_); }
+
+sub set_pretty_print
+  { return XML::Twig::Elt::set_pretty_print( @_); }
+
+sub set_quote
+  { return XML::Twig::Elt::set_quote( @_); }
+
+sub set_indent
+  { return XML::Twig::Elt::set_indent( @_); }
+
+sub set_keep_atts_order
+  { shift; return XML::Twig::Elt::set_keep_atts_order( @_); }
+
+sub keep_atts_order
+  { return XML::Twig::Elt::keep_atts_order( @_); }
+
+# save and restore package globals (the ones in XML::Twig::Elt)
+sub save_global_state
+  { my $t= shift;
+    $t->{twig_saved_state}= XML::Twig::Elt::global_state();
+  }
+
+sub restore_global_state
+  { my $t= shift;
+    XML::Twig::Elt::set_global_state( $t->{twig_saved_state});
+  }
+
+sub global_state
+  { return XML::Twig::Elt::global_state(); }
+
+sub set_global_state
+  {  return XML::Twig::Elt::set_global_state( $_[1]); }
+
+sub dispose
+  { my $t= shift;
+    $t->DESTROY;
+  }
+  
+sub DESTROY
+  { my $t= shift;
+    if( $t->{twig_root} && isa(  $t->{twig_root}, 'XML::Twig')) 
+      { $t->{twig_root}->delete } 
+
+# added to break circular references
+    undef $t->{twig};
+    undef $t->{twig_root}->{twig} if( $t->{twig_root});
+    undef $t->{twig_parser};
+    
+    $t={}; # prevents memory leaks (especially when using mod_perl)
+    undef $t;
+  }        
+
+
+#
+#  non standard handlers
+#
+
+# kludge: expat 1.95.2 calls both Default AND Doctype handlers
+# so if the default handler finds '<!DOCTYPE' then it must 
+# unset itself (_twig_print_doctype will reset it)
+sub _twig_print_check_doctype
+  { 
+    my $p= shift;
+    my $string= $p->recognized_string();
+    if( $string eq '<!DOCTYPE') 
+      { $p->setHandlers( Default => undef); 
+        $p->{twig}->{expat_1_95_2}=1; 
+      }
+    else                        
+      { print $string; }
+    
+  }
+
+#sub twig_buffer_original
+#  { my $p= shift; 
+#    my $t= $p->{twig};
+#    $t->{twig_buffered_string}= $p->original_string(); 
+#  }
+
+sub _twig_print
+  { print $_[0]->recognized_string(); }
+
+sub _twig_print_default
+  { my( $p, $string)= @_;
+    print $p->recognized_string();
+  }
+
+# recognized_string does not seem to work for entities, go figure!
+# so this handler is not used 
+sub _twig_print_entity
+  { my $p= shift; }
+
+# account for the case where the element is empty
+sub _twig_print_end
+  { my $p= shift; 
+    print $p->recognized_string();
+  }
+
+
+# kludge: expat 1.95.2 calls both Default AND Doctype handlers
+# so if the default handler finds '<!DOCTYPE' then it must 
+# unset itself (_twig_print_doctype will reset it)
+sub _twig_print_original_check_doctype
+  { 
+    my $p= shift;
+    my $string= $p->original_string();
+    if( $string eq '<!DOCTYPE') 
+      { $p->setHandlers( Default => undef); 
+        $p->{twig}->{expat_1_95_2}=1; 
+      }
+    else                        
+      { print $string; }
+    
+  }
+
+sub _twig_print_original
+  { print $_[0]->original_string(); }
+
+
+sub _twig_print_original_doctype
+  { 
+    my(  $p, $name, $sysid, $pubid, $internal)= @_;
+    if( $name)
+      { # with recent versions of XML::Parser original_string does not work,
+        # hence we need to rebuild the doctype declaration
+        my $doctype='';
+        $doctype .= qq{<!DOCTYPE $name}    if( $name);
+        $doctype .=  qq{ PUBLIC  "$pubid"}  if( $pubid);
+        $doctype .=  qq{ SYSTEM}            if( $sysid && !$pubid);
+        $doctype .=  qq{ "$sysid"}          if( $sysid); 
+        $doctype .=  qq{>} unless( $p->{twig}->{expat_1_95_2});
+        print $doctype;
+      }
+    $p->setHandlers( Default => \&_twig_print_original);
+  }
+
+sub _twig_print_doctype
+  { 
+    my(  $p, $name, $sysid, $pubid, $internal)= @_;
+    if( $name)
+      { # with recent versions of XML::Parser original_string does not work,
+        # hence we need to rebuild the doctype declaration
+        my $doctype='';
+        $doctype .= qq{<!DOCTYPE $name}    if( $name);
+        $doctype .=  qq{ PUBLIC  "$pubid"}  if( $pubid);
+        $doctype .=  qq{ SYSTEM}            if( $sysid && !$pubid);
+        $doctype .=  qq{ "$sysid"}          if( $sysid); 
+        $doctype .=  qq{>} unless( $p->{twig}->{expat_1_95_2});
+        print $doctype;
+      }
+    $p->setHandlers( Default => \&_twig_print_original);
+  }
+
+
+
+
+sub _twig_print_original_default
+  { 
+    my $p= shift;
+    print $p->original_string();
+  }
+
+# account for the case where the element is empty
+sub _twig_print_end_original
+  { my $p= shift;
+    print $p->original_string();
+  }
+
+sub _twig_start_check_roots
+  { 
+    my( $p, $gi, %att)= @_;
+    my $t= $p->{twig};
+
+    if( _handler( $t, $t->{twig_roots}, $gi, \%att))
+      { 
+        $p->setHandlers( %twig_handlers); # restore regular handlers
+        $t->{twig_root_depth}= $p->depth; 
+        _twig_start( $p, $gi, %att);
+      }
+    elsif( $p->depth == 0)
+      { _twig_start( $p, $gi, %att); }
+    elsif( $t->{twig_starttag_handlers})
+      { # look for start tag handlers
+        my @handlers= _handler( $t, $t->{twig_starttag_handlers}, $gi, \%att);
+        foreach my $handler ( @handlers)
+          { $handler->($t, $gi, %att) || last; }
+      }
+  }
+
+sub _twig_start_check_roots_print
+  { 
+    my( $p, $gi, %att)= @_;
+    my $t= $p->{twig};
+
+    if( _handler( $t, $t->{twig_roots}, $gi, \%att))
+      { $p->setHandlers( %twig_handlers); # restore regular handlers
+        $t->_set_fh_to_selected_fh();      # select the proper output fh
+        $t->{twig_root_depth}= $p->depth; 
+        _twig_start( $p, $gi, %att);
+      }
+    elsif( $p->depth == 0)
+      { if( my $fh= $t->{twig_output_fh})
+          { print $fh $p->recognized_string(); }
+        else
+          { print $p->recognized_string(); }
+      
+        _twig_start( $p, $gi, %att);
+        $t->_set_fh_to_twig_output_fh();
+      }
+    elsif( $t->{twig_starttag_handlers})
+      { # look for start tag handlers
+        my @handlers= _handler( $t, $t->{twig_starttag_handlers}, $gi, \%att);
+        my $last_handler_res;
+        $t->_set_fh_to_selected_fh() if( @handlers);     # select the proper output fh
+        foreach my $handler ( @handlers)
+          { $last_handler_res= $handler->($t, $gi, %att);
+            last unless $last_handler_res;
+          }
+        $t->_set_fh_to_twig_output_fh() if( @handlers);  # re-select the twig output fh
+        print $p->recognized_string() if( !@handlers || $last_handler_res);   
+      }
+    else
+      { print $p->recognized_string(); }  
+  }
+
+sub _twig_start_check_roots_print_original
+  { 
+    my( $p, $gi, %att)= @_;
+    my $t= $p->{twig};
+
+    if( _handler( $t, $t->{twig_roots}, $gi, \%att))
+      { $p->setHandlers( %twig_handlers); # restore regular handlers
+        $t->_set_fh_to_selected_fh();      # select the proper output fh
+        $t->{twig_root_depth}= $p->depth; 
+        _twig_start( $p, $gi, %att);
+      }
+    elsif( $p->depth == 0)
+      { if( my $fh= $t->{twig_output_fh})
+          { print $fh $p->original_string(); }
+        else
+          { print $p->original_string(); }
+
+        _twig_start( $p, $gi, %att);
+        $t->_set_fh_to_twig_output_fh();
+      }
+    elsif( $t->{twig_starttag_handlers})
+      { # look for start tag handlers
+        my @handlers= _handler( $t, $t->{twig_starttag_handlers}, $gi, \%att);
+        my $last_handler_res;
+        $t->_set_fh_to_selected_fh() if( @handlers);     # select the proper output fh
+        foreach my $handler ( @handlers)
+          { $last_handler_res= $handler->($t, $gi, %att);
+            last unless( $last_handler_res);
+          }
+        $t->_set_fh_to_twig_output_fh() if( @handlers);  # re-select the twig output fh
+        print $p->original_string() if( !@handlers || $last_handler_res);   
+      }
+    else
+      { print $p->original_string(); }
+  }
+
+sub _twig_end_check_roots
+  { 
+    my( $p, $gi)= @_;
+    my $t= $p->{twig};
+    if( $t->{twig_endtag_handlers})
+      { # look for end tag handlers
+        my @handlers= _handler( $t, $t->{twig_endtag_handlers}, $gi, {});
+        my $last_handler_res=1;
+        foreach my $handler ( @handlers)
+          { $last_handler_res= $handler->($t, $gi) || last; }
+      }
+
+    if( $p->depth == 0)
+      { _twig_end( $p, $gi); }
+  }
+
+sub _twig_end_check_roots_print
+  { 
+    my( $p, $gi, %att)= @_;
+    my $t= $p->{twig};
+    if( $t->{twig_endtag_handlers})
+      { # look for start tag handlers
+        my @handlers= _handler( $t, $t->{twig_endtag_handlers}, $gi, {});
+        my $last_handler_res=1;
+        $t->_set_fh_to_selected_fh() if( @handlers);     # select the proper output fh
+        foreach my $handler ( @handlers)
+          { $last_handler_res= $handler->($t, $gi) || last; }
+        $t->_set_fh_to_twig_output_fh() if( @handlers);  # re-select the twig output fh
+        return unless $last_handler_res;
+      }
+    print $p->recognized_string();  
+    $t->_set_fh_to_selected_fh() if( $p->depth == 0);
+    if( $p->depth == 0)
+      { _twig_end( $p, $gi);  }
+  }
+
+sub _twig_end_check_roots_print_original
+  { 
+    my( $p, $gi, %att)= @_;
+    my $t= $p->{twig};
+    if( $t->{twig_endtag_handlers})
+      { # look for start tag handlers
+        my @handlers= _handler( $t, $t->{twig_endtag_handlers}, $gi, {});
+        my $last_handler_res=1;
+        $t->_set_fh_to_selected_fh() if( @handlers);     # select the proper output fh
+        foreach my $handler ( @handlers)
+          { $last_handler_res= $handler->($t, $gi) || last; }
+        $t->_set_fh_to_twig_output_fh() if( @handlers);  # re-select the twig output fh
+        return unless $last_handler_res;
+      }
+    print $p->original_string();
+    $t->_set_fh_to_selected_fh() if( $p->depth == 0);
+    if( $p->depth == 0)
+      { _twig_end( $p, $gi);  }
+  }
+
+sub _twig_pi_check_roots
+  { my( $p, $target, $data)= @_;
+    my $t= $p->{twig};
+    if( my $handler=    $t->{twig_handlers}->{pi_handlers}->{$target}
+                     || $t->{twig_handlers}->{pi_handlers}->{''}
+      )
+      { _twig_pi( @_); }
+  }
+
+
+sub _twig_ignore_start
+  { 
+    my( $p, $gi)= @_;
+    my $t= $p->{twig};
+    return unless( $gi eq $t->{twig_ignore_gi});
+    $t->{twig_ignore_level}++;
+    my $action= $t->{twig_ignore_action};
+    if( $action eq 'print' )
+      { _twig_print_original( @_); }
+#    elsif( $action eq 'string' )
+#      { $t->{twig_buffered_string} .= $p->original_string(); }
+  }
+
+sub _twig_ignore_end
+  { 
+    my( $p, $gi)= @_;
+    my $t= $p->{twig};
+
+    my $action= $t->{twig_ignore_action};
+
+    if( $action eq 'print')
+      { _twig_print_original( $p, $gi); }
+#    elsif( $action eq 'string')
+#      { $t->{twig_buffered_string} .= $p->original_string(); }
+
+    return unless( $gi eq $t->{twig_ignore_gi});
+
+    $t->{twig_ignore_level}--;
+
+    unless( $t->{twig_ignore_level})
+      { $t->{twig_ignore_elt}->delete; 
+        $p->setHandlers( @{$t->{twig_saved_handlers}});
+        # test for handlers
+        if( $t->{twig_endtag_handlers})
+          { # look for end tag handlers
+            my @handlers= _handler( $t, $t->{twig_endtag_handlers}, $gi, {});
+            my $last_handler_res=1;
+            foreach my $handler ( @handlers)
+              { $last_handler_res= $handler->($t, $gi) || last; }
+          }
+      };
+  }
+    
+sub ignore
+  { my $t= shift;
+    my $elt;
+
+    # get the element (default: current elt)
+    if( $_[0] && isa( $_[0], 'XML::Twig::Elt'))
+      { $elt= shift; }
+    else
+      { $elt = $t->{twig_current}; }
+
+    my $action= shift || 1; 
+    $t->{twig_ignore_action}= $action;
+
+    $t->{twig_ignore_elt}= $elt;     # save it
+    $t->{twig_ignore_gi}= $XML::Twig::index2gi[$elt->{'gi'}];  # save its gi
+    $t->{twig_ignore_level}++;
+    my $p= $t->{twig_parser};
+    my @saved_handlers= $p->setHandlers( %twig_handlers_ignore); # set handlers
+    if( $action eq 'print')
+      { $p->setHandlers( Default => \&_twig_print_original); }
+#    elsif( $action eq 'string')
+#      { # not used at the moment
+#        $t->{twig_buffered_string}='';
+#        $p->setHandlers( Default => \&twig_buffer_original);
+#      }
+
+    $t->{twig_saved_handlers}= \@saved_handlers;        # save current handlers
+  }
+
+# select $t->{twig_output_fh} and store the current selected fh 
+sub _set_fh_to_twig_output_fh
+  { my $t= shift;
+    my $output_fh= $t->{twig_output_fh};
+    if( $output_fh && !$t->{twig_output_fh_selected})
+      { # there is an output fh
+        $t->{twig_selected_fh}= select(); # store the currently selected fh
+        $t->{twig_output_fh_selected}=1;
+        select $output_fh;                # select the output fh for the twig
+      }
+  }
+
+# select the fh that was stored in $t->{twig_selected_fh} 
+# (before $t->{twig_output_fh} was selected)
+sub _set_fh_to_selected_fh
+  { my $t= shift;
+    return unless( $t->{twig_output_fh});
+    my $selected_fh= $t->{twig_selected_fh};
+    $t->{twig_output_fh_selected}=0;
+    select $selected_fh;
+    return;
+  }
+  
+
+sub encoding
+  { return $_[0]->{twig_xmldecl}->{encoding} if( $_[0]->{twig_xmldecl}); }
+
+sub set_encoding
+  { my( $t, $encoding)= @_;
+    $t->{twig_xmldecl} ||={};
+    $t->set_xml_version( "1.0") unless( $t->xml_version);
+    $t->{twig_xmldecl}->{encoding}= $encoding;
+    return $t;
+  }
+
+sub output_encoding
+  { return $_[0]->{output_encoding}; }
+  
+sub set_output_encoding
+  { my( $t, $encoding)= @_;
+    $t->set_output_filter( _encoding_filter( $encoding)) if( $encoding);
+    return $t->{output_encoding}= $encoding;
+  }
+
+sub xml_version
+  { return $_[0]->{twig_xmldecl}->{version} if( $_[0]->{twig_xmldecl}); }
+
+sub set_xml_version
+  { my( $t, $version)= @_;
+    $t->{twig_xmldecl} ||={};
+    return $t->{twig_xmldecl}->{version}= $version;
+  }
+
+sub standalone
+  { return $_[0]->{twig_xmldecl}->{standalone} if( $_[0]->{twig_xmldecl}); }
+
+sub set_standalone
+  { my( $t, $standalone)= @_;
+    $t->{twig_xmldecl} ||={};
+    $t->set_xml_version( "1.0") unless( $t->xml_version);
+    return $t->{twig_xmldecl}->{standalone}= $standalone;
+  }
+
+
+# SAX methods
+
+sub toSAX1
+  { croak "cannot use toSAX1 while parsing (use flush_toSAX1)" if (defined $_[0]->{twig_parser});
+    shift(@_)->_toSAX(@_, \&XML::Twig::Elt::_start_tag_data_SAX1,
+                          \&XML::Twig::Elt::_end_tag_data_SAX1
+             ); }
+
+sub toSAX2
+  { croak "cannot use toSAX2 while parsing (use flush_toSAX2)" if (defined $_[0]->{twig_parser});
+    shift(@_)->_toSAX(@_, \&XML::Twig::Elt::_start_tag_data_SAX2,
+                          \&XML::Twig::Elt::_end_tag_data_SAX2
+             ); }
+
+
+sub _toSAX
+  { my( $t, $handler, $start_tag_data, $end_tag_data) = @_;
+
+    if( my $start_document =  $handler->can( 'start_document'))
+      { $start_document->( $handler); }
+    
+    $t->_prolog_toSAX( $handler);
+    
+    $t->root->_toSAX( $handler, $start_tag_data, $end_tag_data)  if( $t->root);
+    if( my $end_document =  $handler->can( 'end_document'))
+      { $end_document->( $handler); }
+  }
+
+
+sub flush_toSAX1
+  { shift(@_)->_flush_toSAX(@_, \&XML::Twig::Elt::_start_tag_data_SAX1,
+                               \&XML::Twig::Elt::_end_tag_data_SAX1
+             ); }
+
+sub flush_toSAX2
+  { shift(@_)->_flush_toSAX(@_, \&XML::Twig::Elt::_start_tag_data_SAX2,
+                               \&XML::Twig::Elt::_end_tag_data_SAX2
+             ); }
+
+sub _flush_toSAX
+  { my( $t, $handler, $start_tag_data, $end_tag_data, $up_to)= @_;
+
+    # the "real" last element processed, as _twig_end has closed it
+    my $last_elt;
+    if( $up_to)
+      { $last_elt= $up_to; }
+    elsif( $t->{twig_current})
+      { $last_elt= $t->{twig_current}->_last_child; }
+    else
+      { $last_elt= $t->{twig_root}; }
+
+    my $elt= $t->{twig_root};
+    unless( $elt->_flushed)
+      { # init unless already done (ie root has been flushed)
+        if( my $start_document =  $handler->can( 'start_document'))
+          { $start_document->( $handler); }
+        # flush the DTD
+        $t->_prolog_toSAX( $handler) 
+      }
+
+    while( $elt)
+      { my $next_elt; 
+        if( $last_elt && $last_elt->in( $elt))
+          { 
+            unless( $elt->_flushed) 
+              { # just output the front tag
+                if( my $start_element = $handler->can( 'start_element'))
+                 { if( my $tag_data= $start_tag_data->( $elt))
+                     { $start_element->( $handler, $tag_data); }
+                 }
+                $elt->_set_flushed;
+              }
+            $next_elt= $elt->{first_child};
+          }
+        else
+          { # an element before the last one or the last one,
+            $next_elt= $elt->{next_sibling};  
+            $elt->_toSAX( $handler, $start_tag_data, $end_tag_data);
+            $elt->delete; 
+            last if( $last_elt && ($elt == $last_elt));
+          }
+        $elt= $next_elt;
+      }
+    if( !$t->{twig_parsing}) 
+      { if( my $end_document =  $handler->can( 'end_document'))
+          { $end_document->( $handler); }
+      }
+  }
+
+
+sub _prolog_toSAX
+  { my( $t, $handler)= @_;
+    $t->_xmldecl_toSAX( $handler);
+    $t->_DTD_toSAX( $handler);
+  }
+
+sub _xmldecl_toSAX
+  { my( $t, $handler)= @_;
+    my $decl= $t->{twig_xmldecl};
+    my $data= { Version    => $decl->{version},
+                Encoding   => $decl->{encoding},
+                Standalone => $decl->{standalone},
+          };
+    if( my $xml_decl= $handler->can( 'xml_decl'))
+      { $xml_decl->( $handler, $data); }
+  }
+                
+sub _DTD_toSAX
+  { my( $t, $handler)= @_;
+    my $doctype= $t->{twig_doctype};
+    return unless( $doctype);
+    my $data= { Name     => $doctype->{name},
+                PublicId => $doctype->{pub},
+                SystemId => $doctype->{sysid},
+              };
+
+    if( my $start_dtd= $handler->can( 'start_dtd'))
+      { $start_dtd->( $handler, $data); }
+
+    # I should call code to export the internal subset here 
+    
+    if( my $end_dtd= $handler->can( 'end_dtd'))
+      { $end_dtd->( $handler); }
+  }
+
+# input/output filters
+
+sub latin1 
+  { local $SIG{__DIE__};
+    if( eval 'require Encode')
+      { import Encode; 
+        return encode_convert( 'ISO-8859-15');
+      }
+    elsif( eval 'require Text::Iconv;')
+      { 
+        return iconv_convert( 'ISO-8859-15');
+      }
+    elsif( eval 'require Unicode::Map8 && require Unicode::String;')
+      { 
+        return unicode_convert( 'ISO-8859-15'); 
+      }
+    else
+      { return \&regexp2latin1; }
+  }
+
+sub _encoding_filter
+  { 
+      { local $SIG{__DIE__};
+        my $encoding= $_[1] || $_[0];
+        if( eval 'require Encode')
+          { import Encode; 
+            my $sub= encode_convert( $encoding);
+            return $sub;
+          }
+        if( eval 'require Text::Iconv;')
+          { return iconv_convert( $encoding); }
+        elsif( eval 'require Unicode::Map8 && require Unicode::String;')
+          { return unicode_convert( $encoding); }
+        }
+    croak "Encode, Text::Iconv or Unicode::Map8 and Unicode::String need to be installed ",
+          "in order to use encoding options";
+  }
+
+# shamelessly lifted from XML::TyePYX (works only with XML::Parse 2.27)
+sub regexp2latin1
+  { my $text=shift;
+    $text=~s{([\xc0-\xc3])(.)}{ my $hi = ord($1);
+                                my $lo = ord($2);
+                                chr((($hi & 0x03) <<6) | ($lo & 0x3F))
+                              }ge;
+    return $text;
+  }
+
+
+sub html_encode
+  { require HTML::Entities;
+    return HTML::Entities::encode_entities($_[0] );
+  }
+
+sub safe_encode
+  {   my $str= shift;
+      if( $] < 5.008)
+        { $str =~ s{([\xC0-\xDF].|[\xE0-\xEF]..|[\xF0-\xFF]...)}
+                   {_XmlUtf8Decode($1)}egs; 
+        }
+      else
+        { $str= encode( ascii => $str, $FB_HTMLCREF); }
+      return $str;
+  }
+
+sub safe_encode_hex
+  {   my $str= shift;
+      if( $] < 5.008)
+        { $str =~ s{([\xC0-\xDF].|[\xE0-\xEF]..|[\xF0-\xFF]...)}
+                   {_XmlUtf8Decode($1, 1)}egs; 
+        }
+      else
+        { $str= encode( ascii => $str, $FB_XMLCREF); }
+      return $str;
+  }
+
+# this one shamelessly lifted from XML::DOM
+# does NOT work on 5.8.0
+sub _XmlUtf8Decode
+  { my ($str, $hex) = @_;
+    my $len = length ($str);
+    my $n;
+
+    if ($len == 2)
+      { my @n = unpack "C2", $str;
+        $n = (($n[0] & 0x3f) << 6) + ($n[1] & 0x3f);
+      }
+    elsif ($len == 3)
+      { my @n = unpack "C3", $str;
+        $n = (($n[0] & 0x1f) << 12) + (($n[1] & 0x3f) << 6) + ($n[2] & 0x3f);
+      }
+    elsif ($len == 4)
+      { my @n = unpack "C4", $str;
+        $n = (($n[0] & 0x0f) << 18) + (($n[1] & 0x3f) << 12) 
+           + (($n[2] & 0x3f) << 6) + ($n[3] & 0x3f);
+      }
+    elsif ($len == 1)    # just to be complete...
+      { $n = ord ($str); }
+    else
+      { croak "bad value [$str] for _XmlUtf8Decode"; }
+
+    my $char= $hex ? sprintf ("&#x%x;", $n) : "&#$n;";
+    return $char;
+}
+
+
+sub unicode_convert
+  { my $enc= $_[1] ? $_[1] : $_[0]; # so the method can be called on the twig or directly
+    require Unicode::Map8;
+    require Unicode::String;
+    import Unicode::String qw(utf8);
+    my $sub= eval q{
+            { my $cnv;
+              BEGIN {  $cnv= Unicode::Map8->new($enc) 
+                           or croak "Can't create converter to $enc";
+                    }
+              sub { return  $cnv->to8 (utf8($_[0])->ucs2); } 
+            } 
+                   };
+    unless( $sub) { croak $@; }
+    return $sub;
+  }
+
+sub iconv_convert
+  { my $enc= $_[1] ? $_[1] : $_[0]; # so the method can be called on the twig or directly
+    require Text::Iconv;
+    my $sub= eval q{
+            { my $cnv;
+              BEGIN { $cnv = Text::Iconv->new( 'utf8', $enc) 
+                           or croak "Can't create iconv converter to $enc";
+                    }
+              sub { return  $cnv->convert( $_[0]); } 
+            }       
+                   };
+    unless( $sub)
+      { if( $@=~ m{^Unsupported conversion: Invalid argument})
+          { croak "Unsupported encoding: $enc"; }
+        else
+          { croak $@; }
+      }
+
+    return $sub;
+  }
+
+sub encode_convert
+  { my $enc= $_[1] ? $_[1] : $_[0]; # so the method can be called on the twig or directly
+    my $sub=  eval qq{sub { return encode( "$enc", \$_[0]); } };
+    croak "can't create Encode-based filter: $@" unless( $sub);
+    return $sub;
+  }
+
+
+# XML::XPath compatibility
+sub getRootNode        { return $_[0]; }
+sub getParentNode      { return undef; }
+sub getChildNodes      { my @children= ($_[0]->root); return wantarray ? @children : \@children; }
+
+
+1;
+
+######################################################################
+package XML::Twig::Entity_list;
+######################################################################
+use UNIVERSAL qw( isa ) ;
+
+sub new
+  { my $class = shift;
+    my $self={};
+
+    bless $self, $class;
+    return $self;
+
+  }
+
+sub add_new_ent
+  { my $list= shift;
+    my $ent= XML::Twig::Entity->new( @_);
+    $list->add( $ent);
+  }
+
+sub add
+  { my( $list, $ent)= @_;
+    $list->{$ent->{name}}= $ent;
+  }
+
+# can be called with an entity or with an entity name
+sub delete
+  { my $list= shift;
+    if( isa( ref $_[0], 'XML::Twig::Entity'))
+      { # the second arg is an entity
+        my $ent= shift;
+        delete $list->{$ent->{name}};
+      }
+    else
+      { # the second arg was not entity, must be a string then
+        my $name= shift;
+        delete $list->{$name};
+      }
+  }
+
+sub print
+  { my ($ent_list, $fh)= @_;
+    my $old_select= defined $fh ? select $fh : undef;
+
+    foreach my $ent_name ( sort keys %{$ent_list})
+      { my $ent= $ent_list->{$ent_name};
+        # we have to test what the entity is or un-defined entities can creep in
+        $ent->print() if( isa( $ent, 'XML::Twig::Entity'));
+      }
+    select $old_select if( defined $old_select);
+  }
+
+sub text
+  { my ($ent_list)= @_;
+    return join "\n", map { $ent_list->{$_}->text} sort keys %{$ent_list};
+  }
+
+sub list
+  { my ($ent_list)= @_;
+    return map { $ent_list->{$_} } sort keys %$ent_list;
+  }
+
+1;
+
+######################################################################
+package XML::Twig::Entity;
+######################################################################
+use UNIVERSAL qw( isa ) ;
+
+sub new
+  { my( $ent, $name, $val, $sysid, $pubid, $ndata)= @_;
+
+    my $self={};
+
+    $self->{name}= $name;
+    if( $val)
+      { $self->{val}= $val; }
+    else
+      { $self->{sysid}= $sysid;
+        $self->{pubid}= $pubid;
+        $self->{ndata}= $ndata;
+      }
+    bless $self;
+    return $self;
+  }
+
+sub name  { return $_[0]->{name}; }
+sub val   { return $_[0]->{val}; }
+sub sysid { return $_[0]->{sysid}; }
+sub pubid { return $_[0]->{pubid}; }
+sub ndata { return $_[0]->{ndata}; }
+
+sub print
+  { my ($ent, $fh)= @_;
+    if( $fh) { print $fh $ent->text . "\n"; }
+    else     { print $ent->text . "\n"; }
+  }
+
+
+sub text
+  { my ($ent)= @_;
+    if( exists $ent->{'val'})
+      { if( $ent->{'val'}=~ /"/)
+          { return "<!ENTITY $ent->{'name'} '$ent->{'val'}'>"; }
+        return "<!ENTITY $ent->{'name'} \"$ent->{'val'}\">";
+      }
+    elsif( $ent->{'sysid'})
+      { my $text= "<!ENTITY $ent->{'name'} ";
+        $text .= "SYSTEM \"$ent->{'sysid'}\" " if( $ent->{'sysid'});
+        $text .= "PUBLIC \"$ent->{'pubid'}\" " if( $ent->{'pubid'});
+        $text .= "NDATA $ent->{'ndata'}"        if( $ent->{'ndata'});
+        $text .= ">";
+        return $text;
+      }
+  }
+
+                
+1;
+
+######################################################################
+package XML::Twig::Elt;
+######################################################################
+use Carp;
+use UNIVERSAL qw( isa ) ;
+
+use constant  PCDATA  => '#PCDATA'; 
+use constant  CDATA   => '#CDATA'; 
+use constant  PI      => '#PI'; 
+use constant  COMMENT => '#COMMENT'; 
+use constant  ENT     => '#ENT'; 
+
+use constant  ASIS    => '#ASIS';    # pcdata elements not to be XML-escaped
+
+use constant  ELT     => '#ELT'; 
+use constant  TEXT    => '#TEXT'; 
+use constant  EMPTY   => '#EMPTY'; 
+
+use constant CDATA_START    => "<![CDATA[";
+use constant CDATA_END      => "]]>";
+use constant PI_START       => "<?";
+use constant PI_END         => "?>";
+use constant COMMENT_START  => "<!--";
+use constant COMMENT_END    => "-->";
+
+use constant XMLNS_URI      => 'http://www.w3.org/2000/xmlns/';
+my $XMLNS_URI               = XMLNS_URI;
+
+
+BEGIN
+  { # set some aliases for methods
+    *tag           = *gi; 
+    *name          = *gi; 
+    *set_tag       = *set_gi; 
+    *set_name      = *set_gi; 
+    *find_nodes    = *get_xpath; # as in XML::DOM
+    *findnodes     = *get_xpath; # as in XML::LibXML
+    *field         = *first_child_text;
+    *trimmed_field = *first_child_trimmed_text;
+    *is_field      = *contains_only_text;
+    *is            = *passes;
+    *matches       = *passes;
+    *has_child     = *first_child;
+    *has_children  = *first_child;
+    *all_children_pass = *all_children_are;
+    *all_children_match= *all_children_are;
+    *getElementsByTagName= *descendants;
+    *find_by_tag_name= *descendants_or_self;
+  
+    *first_child_is  = *first_child_matches;
+    *last_child_is   = *last_child_matches;
+    *next_sibling_is = *next_sibling_matches;
+    *prev_sibling_is = *prev_sibling_matches;
+    *next_elt_is     = *next_elt_matches;
+    *prev_elt_is     = *prev_elt_matches;
+    *parent_is       = *parent_matches;
+    *child_is        = *child_matches;
+
+    *sort_children_by_value= *sort_children_on_value;
+
+    *has_atts= *att_nb;
+
+    # imports from XML::Twig
+    *_is_fh= *XML::Twig::_is_fh;
+
+    # XML::XPath compatibility
+    *string_value       = *text;
+    *toString           = *sprint;
+    *getName            = *gi;
+    *getRootNode        = *twig;  
+    *getNextSibling     = *_next_sibling;
+    *getPreviousSibling = *_prev_sibling;
+    *isElementNode      = *is_elt;
+    *isTextNode         = *is_text;
+    *isPI               = *is_pi;
+    *isPINode           = *is_pi;
+    *isProcessingInstructionNode= *is_pi;
+    *isComment          = *is_comment;
+    *isCommentNode      = *is_comment;
+    *getTarget          = *target;
+
+    # try using weak references
+    # test whether we can use weak references
+    { local $SIG{__DIE__};
+      if( eval 'require Scalar::Util')
+        { import Scalar::Util qw(weaken); }
+      elsif( eval 'require WeakRef')
+        { import WeakRef; }
+    }
+}
+
+ 
+# can be called as XML::Twig::Elt->new( [[$gi, $atts, [@content]])
+# - gi is an optional gi given to the element
+# - $atts is a hashref to attributes for the element
+# - @content is an optional list of text and elements that will
+#   be inserted under the element 
+sub new 
+  { my $class= shift;
+    $class= ref $class || $class;
+    my $elt  = {};
+    bless ($elt, $class);
+
+    return $elt unless @_;
+
+    # if a gi is passed then use it
+    my $gi= shift;
+    $elt->set_gi( $gi);
+
+
+    my $atts= ref $_[0] eq 'HASH' ? shift : undef;
+
+    if( $gi eq PCDATA)
+      { $elt->{pcdata}=  shift; }
+    elsif( $gi eq ENT)
+      { $elt->{ent}=  shift; }
+    elsif( $gi eq CDATA)
+      { $elt->{cdata}=  shift; }
+    elsif( $gi eq COMMENT)
+      { $elt->{comment}=  shift; }
+    elsif( $gi eq PI)
+      { $elt->set_pi( shift, shift); }
+    else
+      { # the rest of the arguments are the content of the element
+        if( @_)
+          { $elt->set_content( @_); }
+        else
+          { $elt->{empty}=  1;    }
+      }
+
+    if( $atts)
+      { # the attribute hash can be used to pass the asis status 
+        if( defined $atts->{'#ASIS'})  { $elt->set_asis(  $atts->{'#ASIS'} ); delete $atts->{'#ASIS'};  }
+        if( defined $atts->{'#EMPTY'}) { $elt->{empty}=  $atts->{'#EMPTY'}; delete $atts->{'#EMPTY'}; }
+        $elt->set_atts( $atts) if( keys %$atts);
+      }
+
+    return $elt;
+  }
+
+# this function creates an XM:::Twig::Elt from a string
+# it is quite clumsy at the moment, as it just creates a
+# new twig then returns its root
+# there might also be memory leaks there
+# additional arguments are passed to new XML::Twig
+sub parse
+  { my $class= shift;
+    my $string= shift;
+    my %args= @_;
+    my $t= XML::Twig->new(%args);
+    $t->parse( $string);
+    my $elt= $t->root;
+    # clean-up the node 
+    delete $elt->{twig};         # get rid of the twig data
+    delete $elt->{twig_current}; # better get rid of this too
+    return $elt;
+  }
+    
+
+sub set_gi 
+  { my ($elt, $gi)= @_;
+    unless( defined $XML::Twig::gi2index{$gi})
+      { # new gi, create entries in %gi2index and @index2gi
+        push  @XML::Twig::index2gi, $gi;
+        $XML::Twig::gi2index{$gi}= $#XML::Twig::index2gi;
+      }
+    $elt->{gi}= $XML::Twig::gi2index{$gi};
+    return $elt; 
+  }
+
+sub gi  { return $XML::Twig::index2gi[$_[0]->{gi}]; }
+
+sub local_name 
+  { my $elt= shift;
+    return _local_name( $XML::Twig::index2gi[$elt->{'gi'}]);
+  }
+
+sub ns_prefix
+  { my $elt= shift;
+    return _ns_prefix( $XML::Twig::index2gi[$elt->{'gi'}]);
+  }
+
+# namespace prefix for any qname (can be used for elements or attributes)
+sub _ns_prefix
+  { my $qname= shift;
+    if( $qname=~ m{^([^:]*):})
+      { return $1; }
+    else
+      { return( ''); } # should it be '' ?
+  }
+
+# local name for any qname (can be used for elements or attributes)
+sub _local_name
+  { my $qname= shift;
+    (my $local= $qname)=~ s{^[^:]*:}{};
+    return $local;
+  }
+
+BEGIN 
+  { my %DEFAULT_NS= ( xml   => "http://www.w3.org/XML/1998/namespace",
+                      xmlns => "http://www.w3.org/2000/xmlns/",
+                    );
+ 
+    #sub get_namespace
+    sub namespace
+      { my $elt= shift;
+        my $prefix= defined $_[0] ? shift() : $elt->ns_prefix;
+        my $ns_att= $prefix ? "xmlns:$prefix" : "xmlns";
+        my $expanded= $DEFAULT_NS{$prefix} || $elt->inherit_att( $ns_att) || '';
+        return $expanded;
+      }
+  }
+
+
+# return #ELT for an element and #PCDATA... for others
+sub get_type
+  { my $gi_nb= $_[0]->{gi}; # the number, not the string
+    return ELT if( $gi_nb >= $XML::Twig::SPECIAL_GI);
+    return $_[0]->gi;
+  }
+
+# return the gi if it's a "real" element, 0 otherwise
+sub is_elt
+  { return $_[0]->gi if(  $_[0]->{gi} >=  $XML::Twig::SPECIAL_GI);
+    return 0;
+  }
+
+
+sub is_pcdata
+  { my $elt= shift;
+    return (exists $elt->{'pcdata'});
+  }
+
+sub is_cdata
+  { my $elt= shift;
+    return (exists $elt->{'cdata'});
+  }
+
+sub is_pi
+  { my $elt= shift;
+    return (exists $elt->{'target'});
+  }
+
+sub is_comment
+  { my $elt= shift;
+    return (exists $elt->{'comment'});
+  }
+
+sub is_ent
+  { my $elt= shift;
+    return (exists $elt->{ent} || $elt->{ent_name});
+  }
+
+
+sub is_text
+  { my $elt= shift;
+    return (exists( $elt->{'pcdata'}) || (exists $elt->{'cdata'}));
+  }
+
+sub is_empty
+  { return $_[0]->{empty} || 0; }
+
+sub set_empty
+  { $_[0]->{empty}= defined( $_[1]) ? $_[1] : 1; return $_[0]; }
+
+sub set_not_empty
+  { delete $_[0]->{empty} if( ($_[0]->{'empty'} || 0)); return $_[0]; }
+
+
+sub set_asis
+  { my $elt=shift;
+
+    foreach my $descendant ($elt, $elt->_descendants )
+      { $descendant->{asis}= 1;
+        if( (exists $descendant->{'cdata'}))
+          { $descendant->set_gi( PCDATA);
+            $descendant->{pcdata}=  $descendant->{cdata};
+          }
+
+      }
+    return $elt;
+  }
+
+sub set_not_asis
+  { my $elt=shift;
+    foreach my $descendant ($elt, $elt->descendants)
+      { delete $descendant->{asis} if $descendant->{asis};}
+    return $elt;
+  }
+
+sub is_asis
+  { return $_[0]->{asis}; }
+
+sub closed 
+  { my $elt= shift;
+    my $t= $elt->twig || return;
+    my $curr_elt= $t->{twig_current};
+    return unless( $curr_elt);
+    return $curr_elt->in( $elt);
+  }
+
+sub set_pcdata 
+  { delete $_[0]->{empty};
+    $_[0]->{'pcdata'}= $_[1];
+    return $_[0]; 
+  }
+
+sub append_pcdata
+  { delete $_[0]->{empty};
+    $_[0]->{'pcdata'}.= $_[1];
+    return $_[0]; 
+  }
+
+sub pcdata        { return $_[0]->{pcdata}; }
+
+
+sub append_extra_data 
+  {  $_[0]->{extra_data}.= $_[1];
+     return $_[0]; 
+  }
+sub set_extra_data 
+  { $_[0]->{extra_data}= $_[1];
+    return $_[0]; 
+  }
+sub extra_data { return $_[0]->{extra_data}; }
+
+sub set_target 
+  { $_[0]->{'target'}= $_[1];
+    return $_[0]; 
+     
+  }
+sub target { return $_[0]->{target}; }
+
+sub set_data 
+  { $_[0]->{'data'}= $_[1]; 
+    return $_[0];
+  }
+sub data { return $_[0]->{data}; }
+
+sub set_pi
+  { $_[0]->{target}=  $_[1];
+    $_[0]->{data}=  $_[2];
+    return $_[0]; 
+  }
+
+sub pi_string { return PI_START . $_[0]->{target} . " " . $_[0]->{data} . PI_END; }
+
+sub set_comment    { $_[0]->{comment}= $_[1]; return $_[0]; }
+sub comment        { return $_[0]->{comment}; }
+sub comment_string { return COMMENT_START . $_[0]->{comment} . COMMENT_END; }
+
+sub set_ent  { $_[0]->{ent}= $_[1]; return $_[0]; }
+sub ent      { return $_[0]->{ent}; }
+sub ent_name { return substr( $_[0]->{ent}, 1, -1);}
+
+sub set_cdata 
+  { delete $_[0]->{empty};
+    $_[0]->{'cdata'}= $_[1]; 
+    return $_[0];
+  }
+
+sub append_cdata
+  { $_[0]->{'cdata'}.= $_[1]; 
+    return $_[0];
+  }
+sub cdata { return $_[0]->{'cdata'}; }
+sub cdata_string
+  { my $cdata= $_[0]->{cdata};
+    return defined $cdata ? CDATA_START . $cdata . CDATA_END : '';
+  }
+
+#start-extract twig_node
+sub contains_only_text
+  { my $elt= shift;
+    return 0 unless $elt->is_elt;
+    foreach my $child ($elt->children)
+      { return 0 if $child->is_elt; }
+    return $elt;
+  } 
+  
+sub contains_only
+  { my( $elt, $exp)= @_;
+    my @children= $elt->children;
+    foreach my $child (@children)
+      { return 0 unless $child->is( $exp); }
+    return @children;
+  } 
+
+sub contains_a_single
+  { my( $elt, $exp)= @_;
+    my $child= $elt->{first_child} or return 0;
+    return 0 unless $child->matches( $exp);
+    return 0 if( $child->{next_sibling});
+    return $child;
+  } 
+
+
+
+sub root 
+  { my $elt= shift;
+    while( $elt->{parent}) { $elt= $elt->{parent}; }
+    return $elt;
+  }
+#end-extract twig_node
+
+sub twig 
+  { my $elt= shift;
+    my $root= $elt->root;
+    return $root->{twig};
+  }
+
+
+#start-extract twig_node
+
+# returns undef or the element, depending on whether $elt passes $cond
+# $cond can be
+# - empty: the element passes the condition
+# - ELT ('#ELT'): the element passes the condition if it is a "real" element
+# - TEXT ('#TEXT'): the element passes if it is a CDATA or PCDATA element
+# - a string with an XPath condition (only a subset of XPath is actually
+#   supported).
+# - a regexp: the element passes if its gi matches the regexp
+# - a code ref: the element passes if the code, applied on the element,
+#   returns true
+
+my %cond_cache; # expression => coderef
+
+sub reset_cond_cache { %cond_cache=(); }
+
+{ 
+   sub _install_cond
+    { my $cond= shift;
+      my $sub;
+      my $test;
+
+      my $original_cond= $cond;
+
+      my $not= ($cond=~ s{^\s*!}{}) ? '!' : '';
+
+      if( ref $cond eq 'CODE') { return $cond; }
+    
+      if( ref $cond eq 'Regexp')
+        { $test = qq{(\$_[0]->gi=~ /$cond/)}; }
+      else
+        { # the condition is a string
+          if( $cond eq ELT)     
+            { $test = qq{\$_[0]->is_elt}; }
+          elsif( $cond eq TEXT) 
+            { $test = qq{\$_[0]->is_text}; }
+          elsif( $cond=~ m{^\s*($REG_NAME_W)\s*$}o)                  
+            { # gi
+              if( $1 ne '*')
+                { # 2 options, depending on whether the gi exists in gi2index
+                  # start optimization
+                  my $gi= $XML::Twig::gi2index{$1};
+                  if( $gi)
+                    { # the gi exists, use its index as a faster shortcut
+                      $test = qq{ \$_[0]->{gi} eq "$XML::Twig::gi2index{$1}"};
+                    }
+                  else
+                  # end optimization
+                    { # it does not exist (but might be created later), compare the strings
+                      $test = qq{ \$_[0]->gi eq "$1"}; 
+                    }
+                }
+              else
+                { $test = qq{ (1) } }
+            }
+          elsif( $cond=~ m{^\s*($REG_REGEXP)\s*$}o)
+            { # /regexp/
+              $test = qq{ \$_[0]->gi=~ $1 }; 
+            }
+          elsif( $cond=~ m{^\s*($REG_NAME_W)?\s*\[\s*(\!\s*)?\@($REG_NAME)\s*\]\s*$}o)
+            { # gi[@att]
+              my( $gi, $not, $att)= ($1, $2, $3);
+              $not||='';
+              if( $gi && ($gi ne '*'))
+                { $test = qq{    (\$_[0]->gi eq "$gi") 
+                              && $not(defined \$_[0]->{'att'}->{"$att"})
+                            };
+                }
+              else
+                { $test = qq{ $not (defined \$_[0]->{'att'}->{"$att"})}; }
+             }
+          elsif( $cond=~ m{^\s*($REG_NAME_W)?\s*  # $1
+                           \[\s*(-?)\s*(\d+)\s*\] #   [$2]
+                           \s*$}xo
+               )
+            { my( $gi, $neg, $index)= ($1, $2, $3);
+              my $siblings= $neg ? q{$_[0]->_next_siblings} : q{$_[0]->_prev_siblings};
+              if( $gi && ($gi ne '*')) 
+                { $test= qq{((\$_[0]->gi eq "$gi") && (scalar( grep { \$_->gi eq "$gi" } $siblings) + 1 == $index))}; }
+              else
+                { $test= qq{(scalar( $siblings) + 1 == $index)}; }
+            }
+          elsif( $cond=~ m{^\s*($REG_NAME_W)?\s*  # $1
+                           \[\@($REG_NAME)        #   [@$2
+                           \s*($REG_OP)\s*        #        = (or other op) $3
+                          ($REG_VALUE)            #          "$4" or '$4'
+                          \s*\]\s*$}xo)           #                       ]
+            { # gi[@att="val"]
+              my( $gi, $att, $op, $string)= ($1, $2, _op( $3), $4);
+              if( $gi && ($gi ne '*'))
+                { $test = qq{    (\$_[0]->gi eq "$gi") 
+                              && (defined \$_[0]->{'att'}->{"$att"}) 
+                              && ( \$_[0]->{'att'}->{"$att"} $op $string) 
+                            }; 
+                }
+              else
+                { $test = qq{    (defined \$_[0]->{'att'}->{"$att"}) 
+                              && ( \$_[0]->{'att'}->{"$att"} $op $string) 
+                            };
+                }
+            }
+          elsif( $cond=~ m{^\s*($REG_NAME_W)?\s*  # $1
+                           \[\@($REG_NAME)        #   [@$2
+                           \s*($REG_OP)\s*        #        = (or other op) $3
+                           ($REG_VALUE)           #          "$4" or '$4'
+                           \s*(and|or)\s*         #              and or or ($5)
+                           \@($REG_NAME)          #                  @$6
+                           \s*($REG_OP)\s*        #                      = (or other op) $7
+                           ($REG_VALUE)           #                        "$8" or '$8'
+                           \s*\]\s*$}xo)          #                       ]
+            { # gi[@att="val"]
+              my( $gi, $att1, $op1, $string1, $connector, $att2, $op2, $string2)= ($1, $2, _op( $3), $4, $5, $6, _op( $7), $8);
+              if( $gi && ($gi ne '*'))
+                { $test = qq{ (   (\$_[0]->gi eq "$gi") 
+                                and ( ( (defined \$_[0]->{'att'}->{"$att1"})  and( \$_[0]->{'att'}->{"$att1"} $op1 $string1) )
+                                        $connector 
+                                      ( (defined \$_[0]->{'att'}->{"$att2"})  and( \$_[0]->{'att'}->{"$att2"} $op2 $string2) )
+                                    )
+                              )
+                            }; 
+                }
+              else
+                { $test = qq{ ( ( (defined \$_[0]->{'att'}->{"$att1"}) and ( \$_[0]->{'att'}->{"$att1"} $op1 $string1) )
+                               $connector 
+                                ( (defined \$_[0]->{'att'}->{"$att2"})  and( \$_[0]->{'att'}->{"$att2"} $op2 $string2) )
+                              )
+                            };
+                }
+            }
+          elsif( $cond=~ m{^\s*\.([\w-]+)\s*$}o)
+            { # .class
+              my $class= $1;
+              $test = qq{(\$_[0]->in_class( "$class")) }; 
+            }
+          elsif( $cond=~ m{^\s*($REG_NAME_W)?\s*  # $1
+                           \[\@($REG_NAME)        #   [@$2
+                           \s*($REG_MATCH)\s*     #        =~ or !~ ($3)
+                           ($REG_REGEXP)          #           /$4/
+                           \s*\]\s*$}xo)          #                ]
+            { # gi[@att=~ /regexp/] or gi[@att!~/regexp/]
+              my( $gi, $att, $match, $regexp)= ($1, $2, $3, $4);
+              if( $gi && ($gi ne '*'))
+                { $test = qq{    (\$_[0]->gi eq "$gi") 
+                              && (   defined \$_[0]->{'att'}->{"$att"}) 
+                              && ( \$_[0]->{'att'}->{"$att"} $match $regexp)
+                            }; 
+                }
+              else
+                { # *[@att=~/regexp/ or *[@att!~/regexp/
+                  $test = qq{(    defined \$_[0]->{'att'}->{"$att"}) 
+                               && ( \$_[0]->{'att'}->{"$att"} $match $regexp)
+                            };
+                }
+            }
+          elsif( $cond=~ m{^\s*\@($REG_NAME)\s*$}o)
+            { # @att (or !@att)
+              my( $att)= ($1);
+              $test = qq{ (defined \$_[0]->{'att'}->{"$att"})}; 
+            }
+          elsif( $cond=~ m{^\s*                   
+                           \@($REG_NAME)        #   @$1
+                           \s*($REG_OP)\s*      #       = (or other op) $2
+                           ($REG_VALUE)         #         "$3" or '$3'
+                           \s*$}xo)                                 
+            { # @att="val"
+              my( $att, $op, $string)= ( $1, _op( $2), $3);
+              $test = qq{    (defined \$_[0]->{'att'}->{"$att"}) 
+                          && ( \$_[0]->{'att'}->{"$att"} $op $string) 
+                        };
+             }
+          elsif( $cond=~ m{^\s*                   
+                           \@($REG_NAME)        #   @$1
+                           \s*($REG_OP)\s*      #       = (or other op) $2
+                           ($REG_VALUE)         #         "$3" or '$3'
+                           \s*(and|or)\s*       #              and or or ($4)
+                           \@($REG_NAME)        #   @$5
+                           \s*($REG_OP)\s*      #       = (or other op) $6
+                           ($REG_VALUE)         #         "$7" or '$7'
+                           \s*$}xo)                                 
+            { # @att="val"
+              my( $att1, $op1, $string1, $connector, $att2, $op2, $string2 )= ( $1, _op( $2), $3, $4, $5, _op( $6), $7);
+              $test = qq{ ( (    (defined \$_[0]->{'att'}->{"$att1"}) 
+                              && ( \$_[0]->{'att'}->{"$att1"} $op1 $string1) 
+                            )
+                            $connector
+                            (    (defined \$_[0]->{'att'}->{"$att2"}) 
+                              && ( \$_[0]->{'att'}->{"$att2"} $op2 $string2) 
+                            )
+                          )
+                        };
+             }
+          elsif( $cond=~ m{^\s*
+                           \@($REG_NAME)        #   [@$1
+                           \s*(=~|!~)\s*        #        =~ or !~ ($2)
+                          ($REG_REGEXP)         #           /$3/
+                          \s*\s*$}xo)           #                ]
+            { # @att=~ /regexp/ or @att!~/regexp/
+              my( $att, $match, $regexp)= ( $2, $3, $4);
+              $test = qq{(    defined \$_[0]->{'att'}->{"$att"}) 
+                           && ( \$_[0]->{'att'}->{"$att"} $match $regexp)
+                        };
+            }
+          elsif( $cond=~ m{^\s*($REG_NAME_W)?\s*            # $1
+                           \[\s*(?:text|string)(?:\(\s*\))? #   [string()
+                           \s*($REG_OP)\s*                  #            = or other op ($2)
+                           ($REG_VALUE)                     #              "$3" or '$3'
+                           \s*\]\s*$}xo)                    #                          ]
+            { # gi[string()= "val"]
+              my ($gi, $op, $text)= ($1, _op( $2), $3);
+              if( $gi && ($gi ne '*'))
+                { $test = qq{(\$_[0]->gi eq "$gi") && ( \$_[0]->text eq $text)}; }
+              else
+                { $test = qq{ \$_[0]->text eq $text }; }
+            }
+          elsif( $cond=~ m{^\s*($REG_NAME_W)?\s*            # $1
+                           \[\s*(?:text|string)(?:\(\s*\))? #   [string()
+                           \s*($REG_MATCH)\s*               #             =~ or !~ ($2)
+                           ($REG_REGEXP)                    #               /$3/
+                           \s*\]\s*$}xo)                    #                   ]
+            { # gi[string()=~ /regexp/]
+              my( $gi, $match, $regexp)= ($1, $2, $3);
+              if( $gi && ($gi ne '*'))
+                { $test = qq{(\$_[0]->gi eq "$gi") && ( \$_[0]->text $match $regexp) }; }
+              else
+                { $test = qq{ \$_[0]->text $match $regexp }; }
+            }
+          elsif( $cond=~ m{^\s*($REG_NAME_W)?\s*            # $1
+                           \[\s*(?:text|string)\s*\(\s*     #   [string(
+                           ($REG_NAME)\s*\)                 #            $2)
+                           \s*($REG_OP)\s*                  #                = or other op $3
+                           ($REG_VALUE)                     #                  "$4" or '$4'
+                           \s*\]\s*$}xo)                    #                      ]
+            { # gi[string(gi2)= "text"]
+              my ($gi, $gi2, $op, $text)= ($1, $2, _op($3), $4);
+              $text=~ s/([{}])/\\$1/g;
+              if( $gi && ($gi ne '*'))
+                { $test = qq{    (\$_[0]->gi eq "$gi") 
+                              && ( \$_[0]->first_child( qq{$gi2\[text() $op $text]}))
+                            };
+                }
+              else
+                { $test = qq{ \$_[0]->first_child(qq{$gi2\[text() $op $text]}) } ; }
+            }
+          elsif( $cond=~ m{^\s*($REG_NAME_W)?\s*     # $1
+                           \[\s*(?:text|string)\(\s* #   [string(
+                           ($REG_NAME)\s*\)          #         $2)
+                           \s*(=~|!~)\s*             #            =~ or !~ ($3)
+                           ($REG_REGEXP)             #              /$4/
+                           \s*\]\s*$}xo)             #                  ]
+            { # gi[string(gi2)=~ /regexp/]
+              my( $gi, $gi2, $match, $regexp)= ($1, $2, $3, $4);
+              if( $gi && ($gi ne '*'))
+                { $test = qq{   (\$_[0]->gi eq "$gi") 
+                             && ( \$_[0]->field( "$gi2") $match $regexp)
+                            };
+                }
+              else
+                { $test = qq{\$_[0]->field( "$gi2") $match $regexp}; }
+            }
+          else
+            { croak "wrong condition '$original_cond'"; }
+        }
+
+      my $s= eval "sub { return \$_[0] if( $not($test)) }";
+      if( $@) 
+        { croak "wrong navigation condition $original_cond ($@);" }
+      return $s;
+    }
+
+  sub _op
+    { my $op= shift;
+      if(    $op eq '=')  { $op= 'eq'; }
+      elsif( $op eq '!=') { $op= 'ne'; }
+      return $op;
+    }
+ 
+  sub passes
+    { my( $elt, $cond)= @_;
+      return $elt unless $cond;
+      my $sub= ($cond_cache{$cond} ||= _install_cond( $cond));
+      return $sub->( $elt);
+    }
+}
+# end-extract twig_nodes
+
+sub set_parent 
+  { $_[0]->{parent}= $_[1];
+    weaken( $_[0]->{parent}) if( $XML::Twig::weakrefs);
+  }
+
+#start-extract twig_node
+sub parent
+  { my $elt= shift;
+    my $cond= shift || return $elt->{parent};
+    do { $elt= $elt->{parent} || return; } until (!$elt || $elt->passes( $cond));
+    return $elt;
+  }
+#end-extract twig_node
+
+sub set_first_child 
+  { delete $_[0]->{empty};
+    $_[0]->{'first_child'}= $_[1]; 
+  }
+
+#start-extract twig_node
+sub first_child
+  { my $elt= shift;
+    my $cond= shift || return $elt->{first_child};
+    my $child= $elt->{first_child};
+    my $test_cond= ($cond_cache{$cond} ||= _install_cond( $cond));
+    while( $child && !$test_cond->( $child)) 
+       { $child= $child->{next_sibling}; }
+    return $child;
+  }
+#end-extract twig_node
+  
+sub _first_child   { return $_[0]->{first_child};  }
+sub _last_child    { return $_[0]->{last_child};   }
+sub _next_sibling  { return $_[0]->{next_sibling}; }
+sub _prev_sibling  { return $_[0]->{prev_sibling}; }
+sub _parent        { return $_[0]->{parent};       }
+sub _next_siblings { my $elt= shift; my @siblings; while( $elt= $elt->{next_sibling}) { push @siblings, $elt; } return @siblings; }
+sub _prev_siblings { my $elt= shift; my @siblings; while( $elt= $elt->{prev_sibling}) { push @siblings, $elt; } return @siblings; }
+
+# sets a field
+# arguments $record, $cond, @content
+sub set_field
+  { my $record = shift;
+    my $cond = shift;
+    my $child= $record->first_child( $cond);
+    if( $child)
+      { $child->set_content( @_); }
+    else
+      { if( $cond=~ m{^\s*($REG_NAME)})
+          { my $gi= $1;
+            $child= $record->insert_new_elt( last_child => $gi, @_); 
+          }
+        else
+          { croak "can't create a field name from $cond"; }
+      } 
+    return $child;
+  }
+
+sub set_last_child 
+  { delete $_[0]->{empty};
+    $_[0]->{'last_child'}= $_[1];
+    weaken( $_[0]->{'last_child'}) if( $XML::Twig::weakrefs);
+  }
+
+#start-extract twig_node
+sub last_child
+  { my $elt= shift;
+    my $cond= shift || return $elt->{last_child};
+    my $test_cond= ($cond_cache{$cond} ||= _install_cond( $cond));
+    my $child= $elt->{last_child};
+    while( $child && !$test_cond->( $child) )
+      { $child= $child->{prev_sibling}; }
+    return $child
+  }
+#end-extract twig_node
+
+
+sub set_prev_sibling 
+  { $_[0]->{'prev_sibling'}= $_[1]; 
+    weaken( $_[0]->{'prev_sibling'}) if( $XML::Twig::weakrefs); 
+  }
+
+#start-extract twig_node
+sub prev_sibling
+  { my $elt= shift;
+    my $cond= shift || return $elt->{prev_sibling};
+    my $test_cond= ($cond_cache{$cond} ||= _install_cond( $cond));
+    my $sibling= $elt->{prev_sibling};
+    while( $sibling && !$test_cond->( $sibling) )
+          { $sibling= $sibling->{prev_sibling}; }
+    return $sibling;
+  }
+#end-extract twig_node
+
+sub set_next_sibling { $_[0]->{'next_sibling'}= $_[1]; }
+
+#start-extract twig_node
+sub next_sibling
+  { my $elt= shift;
+    my $cond= shift || return $elt->{next_sibling};
+    my $test_cond= ($cond_cache{$cond} ||= _install_cond( $cond));
+    my $sibling= $elt->{next_sibling};
+    while( $sibling && !$test_cond->( $sibling) )
+          { $sibling= $sibling->{next_sibling}; }
+    return $sibling;
+  }
+
+# methods dealing with the class attribute, convenient if you work with xhtml
+sub class     { my( $elt)= @_; return $elt->{'att'}->{'class'}; }
+sub set_class { my( $elt, $class)= @_; $elt->set_att( class => $class); }
+
+# adds a class to an element
+sub add_to_class
+  { my( $elt, $new_class)= @_;
+    return $elt unless $new_class;
+    my $class= $elt->class;
+    my %class= $class ? map { $_ => 1 } split /\s+/, $class : ();
+    $class{$new_class}= 1;
+    $elt->set_class( join( ' ', sort keys %class));
+  }
+
+sub att_to_class      { my( $elt, $att)= @_; $elt->set_class( $elt->{'att'}->{$att}); }
+sub add_att_to_class  { my( $elt, $att)= @_; $elt->add_to_class( $elt->{'att'}->{$att}); }
+sub move_att_to_class { my( $elt, $att)= @_; $elt->add_to_class( $elt->{'att'}->{$att});
+                        $elt->del_att( $att); 
+                      }
+sub tag_to_class      { my( $elt)= @_; $elt->set_class( $elt->tag);    }
+sub add_tag_to_class  { my( $elt)= @_; $elt->add_to_class( $elt->tag); }
+sub set_tag_class     { my( $elt, $new_tag)= @_; $elt->add_tag_to_class; $elt->set_tag( $new_tag); }
+
+sub in_class          
+  { my( $elt, $class)= @_;
+    my $elt_class= $elt->class;
+    return unless( defined $elt_class);
+    return $elt->class=~ m{(?:^|\s)\Q$class\E(?:\s|$)} ? $elt : 0;
+  }
+
+#end-extract twig_node
+
+# get or set all attributes
+sub set_atts 
+  { my $elt= shift;
+    my %atts;
+    tie %atts, 'Tie::IxHash' if( keep_atts_order());
+    if( isa( $_[0] || '', 'HASH'))
+      { while( my( $att, $value)= each %{$_[0]}) { $atts{$att}= $value; } 
+      }
+    else
+      { %atts= @_; }
+    $elt->{'att'}= \%atts;
+    return $elt;
+  }
+
+sub atts      { return $_[0]->{att};           }
+sub att_names { return sort keys %{$_[0]->{att}};   }
+sub del_atts  { $_[0]->{att}={}; return $_[0]; }
+
+# get or set a single attribute (set works for several atts)
+sub set_att 
+  { my $elt= shift;
+    
+    unless( $elt->{att})
+      { $elt->{att}={};
+        tie %{$elt->{att}}, 'Tie::IxHash' if( keep_atts_order());
+      }
+
+    while(@_) { my( $att, $val)= (shift, shift);
+                $elt->{att}->{$att}= $val;
+          }
+    return $elt;
+  }
+sub att { return $_[0]->{att}->{$_[1]}; }
+sub del_att 
+  { my $elt= shift;
+    while( @_) { delete $elt->{'att'}->{shift()}; }
+    return $elt;
+  }
+
+# delete an attribute from all descendants of an element
+sub strip_att
+  { my( $elt, $att)= @_;
+    $_->del_att( $att) foreach ($elt->descendants_or_self( qq{*[\@$att]}));
+  }
+
+sub change_att_name
+  { my( $elt, $old_name, $new_name)= @_;
+    my $value= $elt->{'att'}->{$old_name};
+    return $elt unless( defined $value);
+    $elt->del_att( $old_name)
+        ->set_att( $new_name => $value);
+    return $elt;
+  }
+
+sub set_twig_current { $_[0]->{twig_current}=1; }
+sub del_twig_current { delete $_[0]->{twig_current}; }
+
+
+# get or set the id attribute
+sub set_id 
+  { my( $elt, $id)= @_;
+    $elt->set_att($ID, $id); 
+    my $t= $elt->twig || return;
+    $elt->twig->{twig_id_list}->{$id}= $elt;
+    weaken(  $elt->twig->{twig_id_list}->{$id}) if( $XML::Twig::weakrefs);
+  }
+
+sub id { return $_[0]->{att}->{$ID}; }
+
+# methods used to add ids to elements that don't have one
+BEGIN 
+{ my $id_nb   = "0001";
+  my $id_seed = "twig_id_";
+
+  sub set_id_seed
+    { $id_seed= $_[1]; $id_nb=1; }
+
+  sub add_id
+    { my $elt= shift;
+      $elt->set_id( $id_seed . $id_nb++) unless( $elt->{'att'}->{$ID});
+    }
+
+}
+
+
+
+# delete the id attribute and remove the element from the id list
+sub del_id 
+  { my $elt= shift;
+    my $id= $elt->{'att'}->{$ID} or return;
+    my $t= $elt->twig && delete $elt->twig->{twig_id_list}->{$id};
+    delete $elt->{'att'}->{$ID}; 
+  }
+
+# return the list of children
+#start-extract twig_node
+sub children
+  { my $elt= shift;
+    my @children;
+    my $child= $elt->first_child( @_);
+    while( $child) 
+      { push @children, $child;
+        $child= $child->next_sibling( @_);
+      } 
+    return @children;
+  }
+
+sub _children
+  { my $elt= shift;
+    my @children=();
+    my $child= $elt->_first_child();
+    while( $child) 
+      { push @children, $child;
+        $child= $child->{next_sibling};
+      } 
+    return @children;
+  }
+
+sub children_copy
+  { my $elt= shift;
+    my @children;
+    my $child= $elt->first_child( @_);
+    while( $child) 
+      { push @children, $child->copy;
+        $child= $child->next_sibling( @_);
+      } 
+    return @children;
+  }
+
+
+sub children_count
+  { my $elt= shift;
+    my $cond= shift;
+    my $count=0;
+    my $child= $elt->{first_child};
+    while( $child)
+      { $count++ if( $child->passes( $cond)); 
+        $child= $child->{next_sibling};
+      }
+    return $count;
+  }
+
+sub children_text
+  { my $elt= shift;
+    return map { $_->text} $elt->children( @_);
+  }
+
+sub all_children_are
+  { my( $parent, $cond)= @_;
+    foreach my $child ($parent->children)
+      { return 0 unless( $child->passes( $cond)); }
+    return 1;
+  }
+
+
+sub ancestors
+  { my( $elt, $cond)= @_;
+    my @ancestors;
+    while( $elt->{parent})
+      { $elt= $elt->{parent};
+        push @ancestors, $elt
+          if( $elt->passes( $cond));
+      }
+    return @ancestors;
+  }
+
+sub ancestors_or_self
+  { my( $elt, $cond)= @_;
+    my @ancestors;
+    while( $elt)
+      { push @ancestors, $elt
+          if( $elt->passes( $cond));
+        $elt= $elt->{parent};
+      }
+    return @ancestors;
+  }
+
+
+sub _ancestors
+  { my( $elt, $include_self)= @_;
+    my @ancestors= $include_self ? ($elt) : ();
+    while( $elt= $elt->{parent})
+      { push @ancestors, $elt;
+      }
+    return @ancestors;
+  }
+
+
+sub inherit_att
+  { my $elt= shift;
+    my $att= shift;
+    my %tags= map { ($_, 1) } @_;
+
+    do 
+      { if(   (defined $elt->{'att'}->{$att})
+           && ( !%tags || $tags{$XML::Twig::index2gi[$elt->{'gi'}]})
+          )
+          { return $elt->{'att'}->{$att}; }
+      } while( $elt= $elt->{parent});
+    return undef;
+  }
+
+
+sub current_ns_prefixes
+  { my $elt= shift;
+    my %prefix;
+    $prefix{''}=1 if( $elt->namespace( ''));
+    while( $elt)
+      { my @ns= grep { !m{^xml} } map { m{^([^:]+):} } ($XML::Twig::index2gi[$elt->{'gi'}], $elt->att_names);
+        $prefix{$_}=1 foreach (@ns);
+        $elt= $elt->{parent};
+      }
+
+    return sort keys %prefix;
+  }
+
+# kinda counter-intuitive actually:
+# the next element is found by looking for the next open tag after from the
+# current one, which is the first child, if it exists, or the next sibling
+# or the first next sibling of an ancestor
+# optional arguments are: 
+#   - $subtree_root: a reference to an element, when the next element is not 
+#                    within $subtree_root anymore then next_elt returns undef
+#   - $gi: a gi, next_elt returns the next element of this gi
+                 
+sub next_elt
+  { my $elt= shift;
+    my $subtree_root= 0;
+    $subtree_root= shift if( defined $_[0] and (isa( $_[0], 'XML::Twig::Elt')));
+    my $cond= shift;
+    my $next_elt;
+
+    my $ind;                                                              # optimization
+    my $test_cond;
+    if( $cond)                                                            # optimization
+      { unless( defined( $ind= $XML::Twig::gi2index{$cond}) )             # optimization
+          { $test_cond= ($cond_cache{$cond} ||= _install_cond( $cond)); } # optimization
+      }                                                                   # optimization
+    
+    do
+      { if( $next_elt= $elt->{first_child})
+          { # simplest case: the elt has a child
+          }
+         elsif( $next_elt= $elt->{next_sibling}) 
+          { # no child but a next sibling (just check we stay within the subtree)
+          
+            # case where elt is subtree_root, is empty and has a sibling
+            return undef if( $subtree_root && ($elt == $subtree_root));
+            
+          }
+        else
+          { # case where the element has no child and no next sibling:
+            # get the first next sibling of an ancestor, checking subtree_root 
+          
+            # case where elt is subtree_root, is empty and has no sibling
+            return undef if( $subtree_root && ($elt == $subtree_root));
+             
+            # backtrack until we find a parent with a next sibling
+            $next_elt= $elt->{parent} || return undef;
+            until( $next_elt->{next_sibling})
+              { return undef if( $subtree_root && ($subtree_root == $next_elt));
+                $next_elt= $next_elt->{parent} || return undef;
+              }
+            return undef if( $subtree_root && ($subtree_root == $next_elt)); 
+            $next_elt= $next_elt->{next_sibling};   
+          }  
+      $elt= $next_elt;                   # just in case we need to loop
+    } until(    ! defined $elt 
+             || ! defined $cond 
+         || (defined $ind       && ($elt->{gi} eq $ind))   # optimization
+         || (defined $test_cond && ($test_cond->( $elt)))
+               );
+    
+      return $elt;
+      }
+
+# counter-intuitive too:
+# the previous element is found by looking
+# for the first open tag backwards from the current one
+# it's the last descendant of the previous sibling 
+# if it exists, otherwise it's simply the parent
+sub prev_elt
+  { my $elt= shift;
+    my $cond= shift;
+    # get prev elt
+    my $prev_elt;
+    do
+      { if( $prev_elt= $elt->{prev_sibling})
+          { while( $prev_elt->{last_child})
+              { $prev_elt= $prev_elt->{last_child}; }
+          }
+        else
+          { $prev_elt= $elt->{parent} || return; }
+        $elt= $prev_elt;     # in case we need to loop 
+      } until( $elt->passes( $cond));
+
+    return $prev_elt;
+  }
+
+
+sub next_n_elt
+  { my $elt= shift;
+    my $offset= shift;
+    foreach (1..$offset)
+      { $elt= $elt->next_elt( @_) || return undef; }
+    return $elt;
+  }
+
+# checks whether $elt is included in $ancestor, returns 1 in that case
+sub in
+  { my ($elt, $ancestor)= @_;
+    if( isa( $ancestor, 'XML::Twig::Elt'))
+      { # element
+        while( $elt= $elt->{parent}) { return $elt if( $elt ==  $ancestor); } 
+      }
+    else
+      { # condition
+        while( $elt= $elt->{parent}) { return $elt if( $elt->matches( $ancestor)); } 
+      }
+    return 0;           
+  }
+
+sub first_child_text  
+  { my $elt= shift;
+    my $dest=$elt->first_child(@_) or return '';
+    return $dest->text;
+  }
+  
+sub first_child_trimmed_text  
+  { my $elt= shift;
+    my $dest=$elt->first_child(@_) or return '';
+    return $dest->trimmed_text;
+  }
+  
+sub first_child_matches
+  { my $elt= shift;
+    my $dest= $elt->{first_child} or return undef;
+    return $dest->passes( @_);
+  }
+  
+sub last_child_text  
+  { my $elt= shift;
+    my $dest=$elt->last_child(@_) or return '';
+    return $dest->text;
+  }
+  
+sub last_child_trimmed_text  
+  { my $elt= shift;
+    my $dest=$elt->last_child(@_) or return '';
+    return $dest->trimmed_text;
+  }
+  
+sub last_child_matches
+  { my $elt= shift;
+    my $dest= $elt->{last_child} or return undef;
+    return $dest->passes( @_);
+  }
+  
+sub child_text
+  { my $elt= shift;
+    my $dest=$elt->child(@_) or return '';
+    return $dest->text;
+  }
+  
+sub child_trimmed_text
+  { my $elt= shift;
+    my $dest=$elt->child(@_) or return '';
+    return $dest->trimmed_text;
+  }
+  
+sub child_matches
+  { my $elt= shift;
+    my $nb= shift;
+    my $dest= $elt->child( $nb) or return undef;
+    return $dest->passes( @_);
+  }
+
+sub prev_sibling_text  
+  { my $elt= shift;
+    my $dest=$elt->prev_sibling(@_) or return '';
+    return $dest->text;
+  }
+  
+sub prev_sibling_trimmed_text  
+  { my $elt= shift;
+    my $dest=$elt->prev_sibling(@_) or return '';
+    return $dest->trimmed_text;
+  }
+  
+sub prev_sibling_matches
+  { my $elt= shift;
+    my $dest= $elt->{prev_sibling} or return undef;
+    return $dest->passes( @_);
+  }
+  
+sub next_sibling_text  
+  { my $elt= shift;
+    my $dest=$elt->next_sibling(@_) or return '';
+    return $dest->text;
+  }
+  
+sub next_sibling_trimmed_text  
+  { my $elt= shift;
+    my $dest=$elt->next_sibling(@_) or return '';
+    return $dest->trimmed_text;
+  }
+  
+sub next_sibling_matches
+  { my $elt= shift;
+    my $dest= $elt->{next_sibling} or return undef;
+    return $dest->passes( @_);
+  }
+  
+sub prev_elt_text  
+  { my $elt= shift;
+    my $dest=$elt->prev_elt(@_) or return '';
+    return $dest->text;
+  }
+  
+sub prev_elt_trimmed_text  
+  { my $elt= shift;
+    my $dest=$elt->prev_elt(@_) or return '';
+    return $dest->trimmed_text;
+  }
+  
+sub prev_elt_matches
+  { my $elt= shift;
+    my $dest= $elt->prev_elt or return undef;
+    return $dest->passes( @_);
+  }
+  
+sub next_elt_text  
+  { my $elt= shift;
+    my $dest=$elt->next_elt(@_) or return '';
+    return $dest->text;
+  }
+  
+sub next_elt_trimmed_text  
+  { my $elt= shift;
+    my $dest=$elt->next_elt(@_) or return '';
+    return $dest->trimmed_text;
+  }
+  
+sub next_elt_matches
+  { my $elt= shift;
+    my $dest= $elt->next_elt or return undef;
+    return $dest->passes( @_);
+  }
+  
+sub parent_text  
+  { my $elt= shift;
+    my $dest=$elt->parent(@_) or return '';
+    return $dest->text;
+  }
+  
+sub parent_trimmed_text  
+  { my $elt= shift;
+    my $dest=$elt->parent(@_) or return '';
+    return $dest->trimmed_text;
+  }
+  
+sub parent_matches
+  { my $elt= shift;
+    my $dest= $elt->{parent} or return undef;
+    return $dest->passes( @_);
+  }
+ 
+sub is_first_child
+  { my $elt= shift;
+    my $parent= $elt->{parent} or return 0;
+    my $first_child= $parent->first_child( @_) or return 0;
+    return ($first_child == $elt) ? $elt : 0;
+  }
+ 
+sub is_last_child
+  { my $elt= shift;
+    my $parent= $elt->{parent} or return 0;
+    my $last_child= $parent->last_child( @_) or return 0;
+    return ($last_child == $elt) ? $elt : 0;
+  }
+
+# returns the depth level of the element
+# if 2 parameter are used then counts the 2cd element name in the
+# ancestors list
+sub level
+  { my( $elt, $cond)= @_;
+   
+    my $level=0;
+    my $name=shift || '';
+    while( $elt= $elt->{parent}) { $level++ if( !$cond || $elt->matches( $cond)); }
+    return $level;           
+  }
+
+# checks whether $elt has an ancestor that satisfies $cond, returns the ancestor
+sub in_context
+  { my ($elt, $cond, $level)= @_;
+    $level= -1 unless( $level) ;  # $level-- will never hit 0
+
+    while( $level)
+      { $elt= $elt->{parent} or return;
+        if( $elt->matches( $cond)) { return $elt; }
+        $level--;
+      }
+  }
+
+
+sub _descendants
+  { my( $subtree_root, $include_self)= @_;
+    my @descendants= $include_self ? ($subtree_root) : ();
+
+    my $elt= $subtree_root; 
+    my $next_elt;   
+ 
+    MAIN: while( 1)  
+      { if( $next_elt= $elt->{first_child})
+          { # simplest case: the elt has a child
+          }
+        elsif( $next_elt= $elt->{next_sibling}) 
+          { # no child but a next sibling (just check we stay within the subtree)
+          
+            # case where elt is subtree_root, is empty and has a sibling
+            last MAIN if( $elt == $subtree_root);
+          }
+        else
+          { # case where the element has no child and no next sibling:
+            # get the first next sibling of an ancestor, checking subtree_root 
+                
+            # case where elt is subtree_root, is empty and has no sibling
+            last MAIN if( $elt == $subtree_root);
+               
+            # backtrack until we find a parent with a next sibling
+            $next_elt= $elt->{parent} || last;
+            until( $next_elt->{next_sibling})
+              { last MAIN if( $subtree_root == $next_elt);
+                $next_elt= $next_elt->{parent} || last MAIN;
+              }
+            last MAIN if( $subtree_root == $next_elt); 
+            $next_elt= $next_elt->{next_sibling};   
+          }  
+        $elt= $next_elt || last MAIN;
+        push @descendants, $elt;
+      }
+    return @descendants;
+  }
+
+
+sub descendants
+  { my( $subtree_root, $cond)= @_;
+    my @descendants=(); 
+    my $elt= $subtree_root;
+    
+    # this branch is pure optimisation for speed: if $cond is a gi replace it
+    # by the index of the gi and loop here 
+    # start optimization
+    my $ind;
+    if( !$cond || ( defined ( $ind= $XML::Twig::gi2index{$cond})) )
+      {
+        my $next_elt;
+
+        while( 1)  
+          { if( $next_elt= $elt->{first_child})
+                { # simplest case: the elt has a child
+                }
+             elsif( $next_elt= $elt->{next_sibling}) 
+              { # no child but a next sibling (just check we stay within the subtree)
+           
+                # case where elt is subtree_root, is empty and has a sibling
+                last if( $subtree_root && ($elt == $subtree_root));
+              }
+            else
+              { # case where the element has no child and no next sibling:
+                # get the first next sibling of an ancestor, checking subtree_root 
+                
+                # case where elt is subtree_root, is empty and has no sibling
+                last if( $subtree_root && ($elt == $subtree_root));
+               
+                # backtrack until we find a parent with a next sibling
+                $next_elt= $elt->{parent} || last undef;
+                until( $next_elt->{next_sibling})
+                  { last if( $subtree_root && ($subtree_root == $next_elt));
+                    $next_elt= $next_elt->{parent} || last;
+                  }
+                last if( $subtree_root && ($subtree_root == $next_elt)); 
+                $next_elt= $next_elt->{next_sibling};   
+              }  
+            $elt= $next_elt || last;
+            push @descendants, $elt if( !$cond || ($elt->{gi} eq $ind));
+          }
+      }
+    else
+    # end optimization
+      { # branch for a complex condition: use the regular (slow but simple) way
+        while( $elt= $elt->next_elt( $subtree_root, $cond))
+          { push @descendants, $elt; }
+      }
+    return @descendants;
+  }
+
+ 
+sub descendants_or_self
+  { my( $elt, $cond)= @_;
+    my @descendants= $elt->passes( $cond) ? ($elt) : (); 
+    push @descendants, $elt->descendants( $cond);
+    return @descendants;
+  }
+  
+sub sibling
+  { my $elt= shift;
+    my $nb= shift;
+    if( $nb > 0)
+      { foreach( 1..$nb)
+          { $elt= $elt->next_sibling( @_) or return undef; }
+      }
+    elsif( $nb < 0)
+      { foreach( 1..(-$nb))
+          { $elt= $elt->prev_sibling( @_) or return undef; }
+      }
+    else # $nb == 0
+      { return $elt->passes( $_[0]); }
+    return $elt;
+  }
+
+sub sibling_text
+  { my $elt= sibling( @_);
+    return $elt ? $elt->text : undef;
+  }
+
+
+sub child
+  { my $elt= shift;
+    my $nb= shift;
+    if( $nb >= 0)
+      { $elt= $elt->first_child( @_) or return undef;
+        foreach( 1..$nb)
+          { $elt= $elt->next_sibling( @_) or return undef; }
+      }
+    else
+      { $elt= $elt->last_child( @_) or return undef;
+        foreach( 2..(-$nb))
+          { $elt= $elt->prev_sibling( @_) or return undef; }
+      }
+    return $elt;
+  }
+
+sub prev_siblings
+  { my $elt= shift;
+    my @siblings=();
+    while( $elt= $elt->prev_sibling( @_))
+      { unshift @siblings, $elt; }
+    return @siblings;
+  }
+
+sub pos
+  { my $elt= shift;
+    return 0 if ($_[0] && !$elt->matches( @_));
+    my $pos=1;
+    $pos++ while( $elt= $elt->prev_sibling( @_));
+    return $pos;
+  }
+
+
+sub next_siblings
+  { my $elt= shift;
+    my @siblings=();
+    while( $elt= $elt->next_sibling( @_))
+      { push @siblings, $elt; }
+    return @siblings;
+  }
+
+# used by get_xpath: parses the xpath expression and generates a sub that performs the
+# search
+sub _install_xpath
+  { my( $xpath_exp, $type)= @_;
+    my $original_exp= $xpath_exp;
+    my $sub= 'my $elt= shift; my @results;';
+    
+    # grab the root if expression starts with a /
+    if( $xpath_exp=~ s{^/}{})
+      { $sub .= '@results= ($elt->twig);'; }
+    elsif( $xpath_exp=~ s{^\./}{})
+      { $sub .= '@results= ($elt);'; }
+    else
+      { $sub .= '@results= ($elt);'; }
+
+
+    while( $xpath_exp &&
+           $xpath_exp=~s{^\s*(/?)                            
+                          # the xxx=~/regexp/ is a pain as it includes /  
+                          (\s*((\*|$REG_NAME|\.)\s*)?\[\s*(string\(\s*\)|\@$REG_NAME)\s*$REG_MATCH  
+                            \s*$REG_REGEXP\s*\]\s* 
+                          # or a regular condition, with no / excepts \/
+                          |([^\\/]|\\.)*
+                          )
+                          (/|$)}{}xo)
+
+      { my $wildcard= $1;
+        my $sub_exp= $2; 
+        
+        # grab a parent
+        if( $sub_exp eq '..')
+          { croak "error in xpath expression $original_exp" if( $wildcard);
+            $sub .= '@results= map { $_->{parent}} @results;';
+          }
+    # test the element itself
+    elsif( $sub_exp=~ m{^\.(.*)$}s)
+      { $sub .= "\@results= grep { \$_->matches( q{$1}) } \@results;" }
+        # grab children
+        elsif( $sub_exp=~ m{($REG_NAME_W)?\s*                # * or a gi    ($1)
+                            (?:
+                \[\s*                             #  [
+                  (
+                (?:string\(\s*\)|\@$REG_NAME) #    regexp condition 
+                   \s*$REG_MATCH\s*$REG_REGEXP\s*  # or
+                        |[^\]]*                       #    regular condition 
+                  )
+                            \]                                #   ]
+                             )?\s*$}xs)        
+          { my $gi= $1; 
+            if( !$1 or $1 eq '*') { $gi=''; }
+            my $cond= $2; 
+            if( $cond) { $cond=~ s{^\s*}{}; $cond=~ s{\s*$}{}; }
+            my $function;
+            
+
+            # "special" conditions, that return just one element
+            if( $cond && ($cond =~ m{^((-\s*)?\d+)$}) )
+              { my $offset= $1;
+                $offset-- if( $offset > 0);
+                $function=  $wildcard ? "next_n_elt( $offset, '$gi')" 
+                                      : "child( $offset, '$gi')";
+                $sub .= "\@results= map { \$_->$function } \@results;"
+              }
+            elsif( $cond && ($cond =~ m{^last\s*\(\s*\)$}) )
+              { croak "error in xpath expression $original_exp, cant use // and last()"
+                  if( $wildcard);
+                 $sub .= "\@results= map { \$_->last_child( '$gi') } \@results;";
+              }
+            else
+              { # go down and get the children or descendants
+                unless ( defined $gi)
+                  { if( $wildcard)
+                      { $sub .= '@results= map { $_->descendants  } @results;' }
+                    else
+                      { $sub .= '@results= map { $_->children } @results;'; }
+                  }
+                else
+                  { if( $wildcard)
+                      { $sub .= "\@results= map { \$_->descendants( '$gi')  } \@results;";  }            
+                    else
+                      { $sub .= "\@results= map { \$_->children( '$gi')  } \@results;"; }
+                  } 
+                # now filter using the condition
+                if( $cond)
+                  { my $op='';
+                    my $test="";
+                    do
+                      { if( $op)
+                          { $cond=~ s{^\s*$op\s*}{};
+                            $op= lc( $op);
+                            $test .= $op;
+                          }
+                       if( $cond =~ s{^string\(\s*\)\s*=\s*($REG_STRING)\s*}{}o)  # string()="string" cond
+                          { $test .= "\$_->text eq $1"; 
+                          }
+                       elsif( $cond =~ s{^string\(\s*\)\s*($REG_MATCH)\s*($REG_REGEXP)\s*}{}o)  # string()=~/regex/ cond
+                          { my( $match, $regexp)= ($1, $2);
+                            $test .= "\$_->text $match $regexp"; 
+                          }
+                       elsif( $cond=~ s{^@($REG_NAME)\s*($REG_OP)\s*($REG_STRING|$REG_NUMBER)}{}o)  # @att="val" cond
+                          { my( $att, $oper, $val)= ($1, _op( $2), $3);
+                            $test .= qq{((defined \$_->{'att'}->{"$att"})  && (\$_->{'att'}->{"$att"} $oper $val))};
+                          }
+                       elsif( $cond =~ s{^@($REG_NAME)\s*($REG_MATCH)\s*($REG_REGEXP)\s*}{}o)  # @att=~/regex/ cond XXX
+                          { my( $att, $match, $regexp)= ($1, $2, $3);
+                            $test .= qq{((defined \$_->{'att'}->{"$att"})  && (\$_->{'att'}->{"$att"} $match $regexp))};; 
+                          }
+                       elsif( $cond=~ s{^@($REG_NAME)\s*}{}o)                      # @att cond
+                          { 
+                            $test .= qq{(defined \$_->{'att'}->{"$1"})};
+                          }
+                       elsif( $cond=~ s{^\s*(\d+)\s*}{}o)                          # positive number condition
+                          { 
+                            $test .= qq{(\$_->prev_siblings( \$_->gi) == $1)};
+                          }
+                       elsif( $cond=~ s{^\s*-\s*(\d+)\s*}{}o)                      # negative number condition
+                          { 
+                            $test .= qq{(\$_->next_siblings( \$_->gi) == $1)};
+                          }
+                       } while( ($op)=($cond=~ m{^\s*(and|or)\s*}i));
+                     croak "error in xpath expression $original_exp at $cond" if( $cond);
+                     $sub .= "\@results= grep { $test } \@results;";
+                   }
+              }
+          }
+      }
+
+    if( $xpath_exp)
+      { croak "error in xpath expression $original_exp around $xpath_exp"; }
+      
+    $sub .= "return \@results; ";
+    my $s= eval "sub { $sub }";
+    if( $@) { croak "error in xpath expression $original_exp ($@);" }
+    return( $s); 
+   }
+        
+{ # extremely elaborate caching mechanism
+  my %xpath; # xpath_expression => subroutine_code;  
+  sub get_xpath
+    { my( $elt, $xpath_exp, $offset)= @_;
+      my $sub= ($xpath{$xpath_exp} ||= _install_xpath( $xpath_exp));
+      return $sub->( $elt) unless( defined $offset); 
+      my @res= $sub->( $elt);
+      return $res[$offset];
+    }
+    1; # so the module returns 1 as this is the last BEGIN block in the file
+}
+
+
+sub findvalue
+  { my $elt= shift;
+    return join '', map { $_->text } $elt->get_xpath( @_);
+  }
+
+#end-extract twig_node
+
+
+# XML::XPath compatibility
+sub getElementById     { return $_[0]->twig->elt_id( $_[1]); }
+sub getChildNodes      { my @children= $_[0]->children; return wantarray ? @children : \@children; }
+
+sub _flushed     { return $_[0]->{flushed}; }
+sub _set_flushed { $_[0]->{flushed}=1;      }
+sub _del_flushed { delete $_[0]->{flushed}; }
+
+
+sub cut
+  { my $elt= shift;
+    my( $parent, $prev_sibling, $next_sibling, $last_elt);
+
+    # you can't cut the root, sorry
+    unless( $parent= $elt->{parent}) 
+      { return; }
+    # it we cut the current element then its parent becomes the current elt
+    if( $elt->{twig_current})
+      { my $twig_current= $elt->{parent};
+        my $t= $elt->twig;
+        $t->{twig_current}= $twig_current;
+        $twig_current->{'twig_current'}=1;
+        delete $elt->{'twig_current'};
+      }
+
+    if( $parent->{first_child} == $elt)
+      { $parent->{first_child}=  $elt->{next_sibling};
+        $parent->{empty}= 1 unless( $elt->{next_sibling});
+      }
+    $parent->set_last_child( $elt->{prev_sibling}) 
+      if( $parent->{last_child} == $elt);
+
+    if( $prev_sibling= $elt->{prev_sibling})
+      { $prev_sibling->{next_sibling}=  $elt->{next_sibling}; }
+    if( $next_sibling= $elt->{next_sibling})
+      { $next_sibling->set_prev_sibling( $elt->{prev_sibling}); }
+
+
+    $elt->set_parent( undef);
+    $elt->set_prev_sibling( undef);
+    $elt->{next_sibling}=  undef;
+
+    return $elt;
+  }
+
+sub cut_children
+  { my( $elt, $exp)= @_;
+    my @children= $elt->children( $exp);
+    foreach (@children) { $_->cut; }
+    return @children;
+  }
+
+sub erase
+  { my $elt= shift;
+    #you cannot erase the current element
+    if( $elt->{twig_current})
+      { croak "trying to erase an element before it has been completely parsed"; }
+    unless( $elt->{parent})
+      { # trying to erase the root (of a twig or of a cut/new element)
+        my @children= $elt->children;
+        unless( @children == 1)
+          { croak "can only erase an element with no parent if it has a single child"; }
+        my $child= shift @children;
+        $child->set_parent( undef);
+        my $twig= $elt->twig;
+        $twig->set_root( $child);
+      }
+    else     
+      { # normal case
+        my @children= $elt->children;
+        if( @children)
+          { # elt has children, move them up
+            if( $elt->{prev_sibling})
+              { # connect first child to previous sibling
+                $elt->{first_child}->set_prev_sibling( $elt->{prev_sibling});      
+                $elt->{prev_sibling}->set_next_sibling( $elt->{first_child}); 
+              }
+            else
+              { # elt was the first child
+                $elt->{parent}->set_first_child( $elt->{first_child});
+              }
+            if( $elt->{next_sibling})
+              { # connect last child to next sibling
+                $elt->{last_child}->set_next_sibling( $elt->{next_sibling});      
+                $elt->{next_sibling}->set_prev_sibling( $elt->{last_child}); 
+              }
+            else
+              { # elt was the last child
+                $elt->{parent}->set_last_child( $elt->{last_child});
+              }
+            # update parent for all siblings
+            foreach my $child (@children)
+              { $child->set_parent( $elt->{parent}); }
+            # elt is not referenced any more, so it will be DESTROYed
+            # so we'd better break the links to its children
+            undef $elt->{'first_child'};
+            undef $elt->{'last_child'};
+            undef $elt->{'parent'};
+            undef $elt->{'prev_sibling'};
+            undef $elt->{'next_sibling'};
+          }
+          { # elt had no child, delete it
+             $elt->delete;
+          }
+    
+        return $elt;
+      }
+
+  }
+        
+
+BEGIN
+  { my %method= ( before      => \&paste_before,
+                  after       => \&paste_after,
+                  first_child => \&paste_first_child,
+                  last_child  => \&paste_last_child,
+                  within      => \&paste_within,
+        );
+    
+    # paste elt somewhere around ref
+    # pos can be first_child (default), last_child, before, after or within
+    sub paste
+      { my $elt= shift;
+        if( $elt->{parent}) 
+          { croak "cannot paste an element that belongs to a tree"; }
+        my $pos;
+        my $ref;
+        if( ref $_[0]) 
+          { $pos= 'first_child'; 
+            croak "wrong argument order in paste, should be $_[1] first" if($_[1]); 
+          }
+        else
+          { $pos= shift; }
+
+        if( my $method= $method{$pos})
+          { unless( ref $_[0]) { croak "Destination undefined in paste"; }
+            unless( isa( $_[0], "XML::Twig::Elt"))
+              { croak "wrong argument type in paste, should be XML::Twig::Elt"; }
+            # check here so error message lists the caller file/line
+            if( !$ref->{parent} && ($method=~ m{^(before|after)}) ) { croak "cannot paste $1 root"; }
+            $elt->$method( @_); 
+          }
+        else
+          { croak "tried to paste in wrong position '$pos', allowed positions " . 
+              " are 'first_child', 'last_child', 'before', 'after' and "    .
+              "'within'";
+          }
+        return $elt;
+      }
+  
+
+    sub paste_before
+      { my( $elt, $ref)= @_;
+        my( $parent, $prev_sibling, $next_sibling );
+        unless( $ref->{parent}) { croak "cannot paste before root"; }
+        $parent= $ref->{parent};
+        $prev_sibling= $ref->{prev_sibling};
+        $next_sibling= $ref;
+
+        $elt->set_parent( $parent);
+        $parent->{first_child}=  $elt if( $parent->{first_child} == $ref);
+
+        $prev_sibling->{next_sibling}=  $elt if( $prev_sibling);
+        $elt->set_prev_sibling( $prev_sibling);
+
+        $next_sibling->set_prev_sibling( $elt);
+        $elt->{next_sibling}=  $ref;
+        return $elt;
+      }
+     
+     sub paste_after
+      { my( $elt, $ref)= @_;
+        my( $parent, $prev_sibling, $next_sibling );
+        unless( $ref->{parent}) { croak "cannot paste after root"; }
+        $parent= $ref->{parent};
+        $prev_sibling= $ref;
+        $next_sibling= $ref->{next_sibling};
+
+        $elt->set_parent( $parent);
+        $parent->set_last_child( $elt) if( $parent->{last_child}== $ref);
+
+        $prev_sibling->{next_sibling}=  $elt;
+        $elt->set_prev_sibling( $prev_sibling);
+
+        $next_sibling->set_prev_sibling( $elt) if( $next_sibling);
+        $elt->{next_sibling}=  $next_sibling;
+        return $elt;
+
+      }
+
+    sub paste_first_child
+      { my( $elt, $ref)= @_;
+        my( $parent, $prev_sibling, $next_sibling );
+        $parent= $ref;
+        $next_sibling= $ref->{first_child};
+        delete $ref->{empty};
+
+        $elt->set_parent( $parent);
+        $parent->{first_child}=  $elt;
+        $parent->set_last_child( $elt) unless( $parent->{last_child});
+
+        $elt->set_prev_sibling( undef);
+
+        $next_sibling->set_prev_sibling( $elt) if( $next_sibling);
+        $elt->{next_sibling}=  $next_sibling;
+        return $elt;
+      }
+      
+    sub paste_last_child
+      { my( $elt, $ref)= @_;
+        my( $parent, $prev_sibling, $next_sibling );
+        $parent= $ref;
+        $prev_sibling= $ref->{last_child};
+        delete $ref->{empty};
+
+        $elt->set_parent( $parent);
+        $parent->set_last_child( $elt);
+        $parent->{first_child}=  $elt unless( $parent->{first_child});
+
+        $elt->set_prev_sibling( $prev_sibling);
+        $prev_sibling->{next_sibling}=  $elt if( $prev_sibling);
+
+        $elt->{next_sibling}=  undef;
+        return $elt;
+      }
+
+    sub paste_within
+      { my( $elt, $ref, $offset)= @_;
+        my $text= $ref->is_text ? $ref : $ref->next_elt( '#TEXT', $ref);
+        my $new= $text->split_at( $offset);
+        $elt->paste_before( $new);
+        return $elt;
+      }
+  }
+
+# load an element into a structure similar to XML::Simple's
+sub simplify
+  { my $elt= shift;
+
+    # normalize option names
+    my %options= @_;
+    %options= map { my ($key, $val)= ($_, $options{$_});
+                       $key=~ s{(\w)([A-Z])}{$1_\L$2}g;
+                       $key => $val
+                     } keys %options;
+
+    # check options
+    my @allowed_options= qw( keyattr forcearray noattr content_key
+                             var var_regexp variables var_attr 
+                             erase group_tags forcecontent
+                             normalise_space normalize_space
+                   );
+    my %allowed_options= map { $_ => 1 } @allowed_options;
+    foreach my $option (keys %options)
+      { warn "invalid option $option\n" unless( $allowed_options{$option}); }
+
+    $options{normalise_space} ||= $options{normalize_space} || 0;
+    
+    $options{content_key} ||= 'content';
+    if( $options{content_key}=~ m{^-})
+      { # need to remove the - and to activate extra folding
+        $options{content_key}=~ s{^-}{};
+        $options{extra_folding}= 1;
+      }
+    else
+      { $options{extra_folding}= 0; }
+   
+    $options{forcearray} ||=0; 
+    if( isa( $options{forcearray}, 'ARRAY'))
+      { my %forcearray_tags= map { $_ => 1 } @{$options{forcearray}};
+        $options{forcearray_tags}= \%forcearray_tags;
+        $options{forcearray}= 0;
+      }
+
+    $options{erase}||= $options{group_tags}; # for compat with XML::Simple
+    if( isa( $options{erase}, 'ARRAY'))
+      { my %erase_tags= map { $_ => 1 } @{$options{erase}};
+        $options{erase}= \%erase_tags;
+      }
+
+    $options{keyattr}     ||= ['name', 'key', 'id'];
+    if( ref $options{keyattr} eq 'ARRAY')
+      { foreach my $keyattr (@{$options{keyattr}})
+          { my( $prefix, $att)= ($keyattr=~ m{^([+-])?(.*)});
+            $prefix ||= '';
+            $options{key_for_all}->{$att}= 1;
+            $options{remove_key_for_all}->{$att}=1 unless( $prefix eq '+');
+            $options{prefix_key_for_all}->{$att}=1 if( $prefix eq '-');
+          }
+      }
+    elsif( ref $options{keyattr} eq 'HASH')
+      { while( my( $elt, $keyattr)= each %{$options{keyattr}})
+         { my( $prefix, $att)= ($keyattr=~ m{^([+-])?(.*)});
+           $prefix ||='';
+           $options{key_for_elt}->{$elt}= $att;
+           $options{remove_key_for_elt}->{"$elt#$att"}=1 unless( $prefix);
+           $options{prefix_key_for_elt}->{"$elt#$att"}=1 if( $prefix eq '-');
+         }
+      }
+       
+
+    $options{var}||= $options{var_attr}; # for compat with XML::Simple
+    if( $options{var}) { $options{var_values}= {}; }
+    else               { $options{var}='';         }
+
+    if( $options{variables}) 
+      { $options{var}||= 1;
+        $options{var_values}= $options{variables};
+      }
+
+    if( $options{var_regexp} and !$options{var})
+      { warn "var option not used, var_regexp option ignored\n"; }
+    $options{var_regexp} ||= '\$\{?(\w+)\}?';
+      
+    $elt->_simplify( \%options);
+ 
+ }
+
+sub _simplify
+  { my( $elt, $options)= @_;
+
+    my $data;
+
+    my $gi= $XML::Twig::index2gi[$elt->{'gi'}];
+    my @children= $elt->children;
+    my %atts= $options->{noattr} ? () : %{$elt->atts};
+    my $nb_atts= keys %atts;
+    my $nb_children= $elt->children_count + $nb_atts;
+
+    my %nb_children;
+    foreach (@children)   { $nb_children{$_->tag}++; }
+    foreach (keys %atts)  { $nb_children{$_}++;      }
+
+    my $arrays; # tag => array where elements are stored
+
+
+    # store children
+    foreach my $child (@children)
+      { if( $child->is_text)
+          { # generate with a content key
+            my $text= $elt->_text_with_vars( $options);
+            $text= _normalize_space( $text) if( $options->{normalise_space} >= 2);
+            if(    $options->{force_content}
+                || $nb_atts 
+              )
+              { $data->{$options->{content_key}}= $text; }
+            else
+              { $data= $text; }
+          }
+        else
+          { # element with sub elements
+            my $child_gi= $XML::Twig::index2gi[$child->{'gi'}];
+
+            my $child_data= $child->_simplify( $options);
+
+            # first see if we need to simplify further the child data
+            # because of grouped tags
+            if( my $grouped_tag= $options->{group_tags}->{$child_gi})
+              { # check that the child data is a hash with a single field
+                unless(    (ref( $child_data) eq 'HASH')
+                        && (keys %$child_data == 1)
+                        && defined ( my $grouped_child_data= $child_data->{$grouped_tag})
+                      )
+                  { die "error in grouped tag $child_gi"; }
+                else
+                  { $child_data=  $grouped_child_data; }
+              }
+            # because of extra folding
+            if( $options->{extra_folding})
+              { if(    (ref( $child_data) eq 'HASH')
+                    && (keys %$child_data == 1)
+                    && defined( my $content= $child_data->{$options->{content_key}})
+                  )
+                  { $child_data= $content; }
+              }
+
+
+            if( my $keyatt= $child->_key_attr( $options))
+              { # element with key
+                my $key= $child->{'att'}->{$keyatt};
+                $key= _normalize_space( $key) if( $options->{normalise_space} >= 1);
+                $data->{$child_gi}->{$key}= $child_data;
+              }
+            elsif(      $options->{forcearray}
+                   ||   $options->{forcearray_tags}->{$child_gi}
+                   || ( $nb_children{$child_gi} > 1)
+                 )
+              { # element to store in an array
+                $data->{$child_gi} ||= [];
+                push @{$data->{$child_gi}}, $child_data;
+              }
+            else
+              { # element to store as a hash field
+                $data->{$child_gi}= $child_data;
+              }
+
+          }
+    }
+
+    # store atts
+    # TODO: deal with att that already have an element by that name
+    foreach my $att (keys %atts)
+      { # do not store if the att is a key that needs to be removed
+        if(    $options->{remove_key_for_all}->{$att}
+            || $options->{remove_key_for_elt}->{"$gi#$att"}
+          )
+          { next; }
+
+        my $att_text= _replace_vars_in_text( $atts{$att}, $options);
+        $att_text= _normalize_space( $att_text) if( $options->{normalise_space} >= 2);
+        
+        if(    $options->{prefix_key_for_all}->{$att}
+            || $options->{prefix_key_for_elt}->{"$gi#$att"}
+          )
+          { # prefix the att
+            $data->{"-$att"}= $att_text;
+          } 
+        else
+          { # normal case
+            $data->{$att}= $att_text; 
+          }
+      }
+    
+    return $data;
+  }
+
+sub _key_attr
+  { my( $elt, $options)=@_;
+    return if( $options->{noattr});
+    if( $options->{key_for_all})
+      { foreach my $att ($elt->att_names)
+          { if( $options->{key_for_all}->{$att})
+              { return $att; }
+          }
+      }
+    elsif( $options->{key_for_elt})
+      { if( my $key_for_elt= $options->{key_for_elt}->{$XML::Twig::index2gi[$elt->{'gi'}]} )
+          { return $key_for_elt if( defined( $elt->{'att'}->{$key_for_elt})); }
+      }
+    return;
+  }
+
+sub _text_with_vars
+  { my( $elt, $options)= @_;
+    my $text;
+    if( $options->{var}) 
+      { $text= _replace_vars_in_text( $elt->text, $options); 
+        $elt->_store_var( $options);
+      }
+     else
+      { $text= $elt->text; }
+    return $text;
+  }
+
+
+sub _normalize_space
+  { my $text= shift;
+    $text=~ s{\s+}{ }sg;
+    $text=~ s{^\s}{};
+    $text=~ s{\s$}{};
+    return $text;
+  }
+
+
+sub att_nb
+  { return 0 unless( my $atts= $_[0]->atts);
+    return scalar keys %$atts;
+  }
+    
+sub has_no_atts
+  { return 1 unless( my $atts= $_[0]->atts);
+    return scalar keys %$atts ? 0 : 1;
+ }
+    
+sub _replace_vars_in_text
+  { my( $text, $options)= @_;
+
+    $text=~ s{($options->{var_regexp})}
+             { if( defined( my $value= $options->{var_values}->{$2}))
+                 { $value }
+               else
+                 { warn "unknown variable $2\n";
+                   $1
+                 }
+             }gex;
+    return $text;
+  }
+
+sub _store_var
+  { my( $elt, $options)= @_;
+    if( defined (my $var_name= $elt->{'att'}->{$options->{var}}))
+       { $options->{var_values}->{$var_name}= $elt->text; 
+       }
+  }
+
+
+# split a text element at a given offset
+sub split_at
+  { my( $elt, $offset)= @_;
+    my $text_elt= $elt->is_text ? $elt : $elt->first_child( TEXT) || return '';
+    my $string= $text_elt->text; 
+    my $left_string= substr( $string, 0, $offset);
+    my $right_string= substr( $string, $offset);
+    $text_elt->{pcdata}=  $left_string;
+    my $new_elt= XML::Twig::Elt->new( $XML::Twig::index2gi[$elt->{'gi'}], $right_string);
+    $new_elt->paste( after => $elt);
+    return $new_elt;
+  }
+
+    
+# split an element or its text descendants into several, in place
+# all elements (new and untouched) are returned
+sub split    
+  { my $elt= shift;
+    my @text_chunks;
+    my @result;
+    if( $elt->is_text) { @text_chunks= ($elt); }
+    else               { @text_chunks= $elt->descendants( '#TEXT'); }
+    foreach my $text_chunk (@text_chunks)
+      { push @result, $text_chunk->_split( 1, @_); }
+    return @result;
+  }
+
+# split an element or its text descendants into several, in place
+# created elements (those which match the regexp) are returned
+sub mark
+  { my $elt= shift;
+    my @text_chunks;
+    my @result;
+    if( $elt->is_text) { @text_chunks= ($elt); }
+    else               { @text_chunks= $elt->descendants( '#TEXT'); }
+    foreach my $text_chunk (@text_chunks)
+      { push @result, $text_chunk->_split( 0, @_); }
+    return @result;
+  }
+
+# split a single text element
+# return_all defines what is returned: if it is true 
+# only returns the elements created by matches in the split regexp
+# otherwise all elements (new and untouched) are returned
+
+{ my $encode_is_loaded=0;   # so we only load Encode once in 5.8.0+
+ 
+  sub _split
+    { my $elt= shift;
+      my $return_all= shift;
+      my( $regexp, $tag, $atts)= @_;
+      my @result;                                 # the returned list of elements
+      my $text= $elt->text;
+      my $gi= $XML::Twig::index2gi[$elt->{'gi'}];
+      $tag||= $elt->parent( '#ELT')->gi;          # default: same tag as the current one
+      $atts ||= {};                               # default: no attributes
+  
+      # 2 uses: if split matches then the first substring reuses $elt
+      #         once a split has occured then the last match needs to be put in
+      #         a new element      
+      my $replaced= 0;
+
+      while( $text=~/(.*?)(?:($regexp)|$)/sg)
+        { # $1 is the pre-regexp match
+          # $2 is the string that matches the regexp (if true then the regexp 
+          #    matched, otherwise no match)
+          # $3...$n are captured by the regexp (and should be wrapped in tag)
+          if( defined $2 || $replaced)
+            { # the regexp matched this time ($2) or previously ($replaced)
+              unless( $replaced)
+                { # first match in $elt, re-use $elt for the first sub-string
+                  $elt->set_text( _utf8_ify( $1));
+                  $replaced++;                     # note that there was a match
+                  push @result, $elt if( $return_all);
+                }
+              else
+                { # match, not the first one, create a new text ($gi) element
+                  my $pre_match= _utf8_ify( $1);
+                  my $new_text= XML::Twig::Elt->new( $gi, $pre_match);
+                  $new_text->paste( 'after', $elt); # paste it after $elt
+                  $elt= $new_text;                  # $elt: element to paste after
+                  push @result, $elt if( $return_all);
+                }
+              # now deal with matches captured in the regexp
+              no strict( 'refs');                   # needed to access $3...$n
+              for( my $match_nb=3; defined $$match_nb; $match_nb++)
+                { # create new element, text is the match
+                  my %atts= %$atts; # or the same atts is used for all matches!
+                  my $match= _utf8_ify( $$match_nb);
+                  my $new_text= XML::Twig::Elt->new( $tag, \%atts, $match);
+                  $new_text->paste( 'after', $elt); # paste it after the current
+                  $elt= $new_text;                  # it becomes the current elt
+                  push @result, $elt;
+                }
+            }
+          else
+            { # the regep did not match at all, $elt is not changed
+              push @result, $elt if( $return_all);
+            }
+        } 
+      return @result; # return all elements
+   }
+
+  # evil hack needed in 5.8.0, the utf flag is not set on $<n>...
+  sub _utf8_ify
+    { my $string= shift;
+      if( $] > 5.007 and !keep_encoding()) 
+        { unless( $encode_is_loaded) { require Encode; import Encode; $encode_is_loaded++; }
+          Encode::_utf8_on( $string); # the flag should be set but is not
+        }
+      return $string;
+    }
+
+
+}
+
+{ my %replace_sub; # cache for complex expressions (expression => sub)
+
+  sub subs_text
+    { my( $elt, $regexp, $replace)= @_;
+  
+      my $replacement_string;
+      my $is_string= _is_string( $replace);
+      foreach my $text_elt ($elt->descendants_or_self( '#TEXT'))
+        { if( $is_string)
+            { my $text= $text_elt->text;
+              $text=~ s{$regexp}{ _replace_var( $replace, $1, $2, $3, $4, $5, $6, $7, $8, $9)}egx;
+              $text_elt->set_text( $text);
+           }
+          else
+            { my $replace_sub= ( $replace_sub{$replace} ||= _install_replace_sub( $replace)); 
+              my $text= $text_elt->text;
+              my $pos=0;  # used to skip text that was previously matched
+              while( my( $pre_match_string, $match_string, @var)= ($text=~ m{(.*?)($regexp)}g))
+                { my $match_start  = length( $pre_match_string);
+                  my $match        = $text_elt->split_at( $match_start + $pos);
+                  my $match_length = length( $match_string);
+                  my $post_match   = $match->split_at( $match_length);
+                  $replace_sub->( $match, @var);
+                  # merge previous text with current one
+                  my $next_sibling;
+                  if(    ($next_sibling= $text_elt->{next_sibling})
+                      && ($XML::Twig::index2gi[$text_elt->{'gi'}] eq $XML::Twig::index2gi[$next_sibling->{'gi'}])
+                    )
+                    { $text_elt->merge_text( $next_sibling); }
+                  # go to next 
+                  $text_elt= $post_match;
+                  $text= $post_match->text;
+                  # merge last text element with next one if needed,
+                  # the match will be against the non-matched text,
+                  # so $pos is used to skip the merged part
+                  my $prev_sibling;
+                  if(    ($prev_sibling=  $post_match->{prev_sibling})
+                      && ($XML::Twig::index2gi[$post_match->{'gi'}] eq $XML::Twig::index2gi[$prev_sibling->{'gi'}])
+                    )
+                    { $pos= length( $prev_sibling->text);
+                      $post_match->merge_text(  $prev_sibling);
+                    }
+                }
+            }
+        }
+      return $elt;
+    }
+
+
+  sub _is_string
+    { return ($_[0]=~ m{&e[ln]t}) ? 0: 1 }
+
+  sub _replace_var
+    { my( $string, @var)= @_;
+      unshift @var, undef;
+      $string=~ s{\$(\d)}{$var[$1]}g;
+      return $string;
+    }
+
+  sub _install_replace_sub
+    { my $replace_exp= shift;
+      my @item= split m{(&e[ln]t\s*\([^)]*\))}, $replace_exp;
+      my $sub= q{ my( $match, @var)= @_; unshift @var, undef; my $new; };
+      my( $gi, $exp);
+      foreach my $item (@item)
+        { if(    $item=~ m{^&elt\s*\(([^)]*)\)})
+            { $exp= $1;
+            }
+          elsif( $item=~ m{^&ent\s*\(\s*([^\s)]*)\s*\)})
+            { $exp= " '#ENT' => $1"; }
+          else
+            { $exp= qq{ '#PCDATA' => "$item"}; }
+          $exp=~ s{\$(\d)}{\$var[$1]}g; # replace references to matches
+          $sub.= qq{ \$new= XML::Twig::Elt->new( $exp); };
+          $sub .= q{ $new->paste( before => $match); };
+        }
+      $sub .= q{ $match->delete; };
+      #$sub=~ s/;/;\n/g;
+      my $coderef= eval "sub { $sub }";
+      if( $@) { croak( "invalid replacement expression $replace_exp: ",$@); }
+      return $coderef;
+    }
+
+  }
+
+
+sub merge_text
+  { my( $e1, $e2)= @_;
+    croak "invalid merge: can only merge 2 elements" 
+        unless( isa( $e2, 'XML::Twig::Elt'));
+    croak "invalid merge: can only merge 2 text elements" 
+        unless( $e1->is_text && $e2->is_text && ($e1->gi eq $e2->gi));
+    $e1->set_text( $e1->text . $e2->text);
+    $e2->delete;
+    return $e1;
+  }
+
+
+# recursively copy an element and returns the copy (can be huge and long)
+sub copy
+  { my $elt= shift;
+    my $copy= XML::Twig::Elt->new( $XML::Twig::index2gi[$elt->{'gi'}]);
+
+    $copy->set_extra_data( $elt->extra_data) if( $elt->extra_data);
+    $copy->set_asis                          if( $elt->is_asis);
+    if( ($elt->{'empty'} || 0)) { $copy->{empty}= 1; } # do not swap or speedup will mess up this                         
+
+    if( (exists $elt->{'pcdata'}))
+      { $copy->{pcdata}=  $elt->{pcdata}; }
+    elsif( (exists $elt->{'cdata'}))
+      { $copy->{cdata}=  $elt->{cdata}; }
+    elsif( (exists $elt->{'target'}))
+      { $copy->set_pi( $elt->{target}, $elt->{data}); }
+    elsif( (exists $elt->{'comment'}))
+      { $copy->{comment}=  $elt->{comment}; }
+    elsif( (exists $elt->{'ent'}))
+      { $copy->{ent}=  $elt->{ent}; }
+    else
+      { my @children= $elt->children;
+        if( my $atts= $elt->atts)
+          { my %atts= %{$atts}; # we want to do a real copy of the attributes
+            $copy->set_atts( \%atts);
+          }
+        foreach my $child (@children)
+          { my $child_copy= $child->copy;
+            $child_copy->paste( 'last_child', $copy);
+          }
+      }
+    return $copy;
+  }
+
+sub delete
+  { my $elt= shift;
+    $elt->cut;
+    $elt->DESTROY unless( $XML::Twig::weakrefs);
+    return undef;
+  }
+
+{ my $current_twig;
+  sub DESTROY
+    { my $elt= shift;
+
+      return if( $XML::Twig::weakrefs);
+
+      foreach( @{[$elt->children]}) { $_->XML::Twig::Elt::DESTROY; }
+      # the id reference needs to be destroyed
+      $elt->del_id if( $ID && exists $elt->{att}->{$ID});
+      undef $elt;
+    }
+}
+
+
+# to be called only from a start_tag_handler: ignores the current element
+sub ignore
+  { my $elt= shift;
+    my $t= $elt->twig;
+    $t->ignore( $elt, @_);
+  }
+
+BEGIN {
+  my $pretty=0;
+  my $quote='"';
+  my $INDENT= '  ';
+  my $empty_tag_style= 0;
+  my $keep_encoding= 0;
+  my $expand_external_entities= 0;
+  my $keep_atts_order=0;
+
+  my ($NSGMLS, $NICE, $INDENTED, $INDENTEDC, $RECORD1, $RECORD2)= (1..6);
+
+  my %pretty_print_style=
+    ( none       => 0,          # no added \n
+      nsgmls     => $NSGMLS,    # nsgmls-style, \n in tags
+      # below this line styles are UNSAFE (the generated XML can be invalid)
+      nice       => $NICE,      # \n after open/close tags except when the 
+                                # element starts with text
+      indented   => $INDENTED,  # nice plus idented
+      indented_c => $INDENTEDC, # slightly more compact than indented (closing
+                                # tags are on the same line)
+      record_c   => $RECORD1,   # for record-like data (compact)
+      record     => $RECORD2,   # for record-like data  (not so compact)
+    );
+
+  my ($HTML, $EXPAND)= (1..2);
+  my %empty_tag_style=
+    ( normal => 0,        # <tag/>
+      html   => $HTML,    # <tag />
+      xhtml  => $HTML,    # <tag />
+      expand => $EXPAND,  # <tag></tag>
+    );
+
+  my %quote_style=
+    ( double  => '"',    
+      single  => "'", 
+      # smart  => "smart", 
+    );
+
+  my $xml_space_preserve; # set when an element includes xml:space="preserve"
+
+  my $output_filter;      # filters the entire output (including < and >)
+  my $output_text_filter; # filters only the text part (tag names, attributes, pcdata)
+
+  # returns those pesky "global" variables so you can switch between twigs 
+  sub global_state
+    { return
+       { pretty                    => $pretty,
+         quote                     => $quote,
+         indent                    => $INDENT,
+         empty_tag_style           => $empty_tag_style,
+         keep_encoding             => $keep_encoding,
+         expand_external_entities  => $expand_external_entities,
+         output_filter             => $output_filter,
+         output_text_filter        => $output_text_filter,
+         keep_atts_order           => $keep_atts_order,
+        };
+    }
+
+  # restores the global variables
+  sub set_global_state
+    { my $state= shift;
+      $pretty                   = $state->{pretty};
+      $quote                    = $state->{quote};
+      $INDENT                   = $state->{indent};
+      $empty_tag_style          = $state->{empty_tag_style};
+      $keep_encoding            = $state->{keep_encoding};
+      $expand_external_entities = $state->{expand_external_entities};
+      $output_filter            = $state->{output_filter};
+      $output_text_filter       = $state->{output_text_filter};
+      $keep_atts_order          = $state->{keep_atts_order};
+    }
+
+  # set the pretty_print style (in $pretty) and returns the old one
+  # can be called from outside the package with 2 arguments (elt, style)
+  # or from inside with only one argument (style)
+  # the style can be either a string (one of the keys of %pretty_print_style
+  # or a number (presumably an old value saved)
+  sub set_pretty_print
+    { my $style= lc( defined $_[1] ? $_[1] : $_[0]); # so we cover both cases 
+      my $old_pretty= $pretty;
+      if( $style=~ /^\d+$/)
+        { croak "invalid pretty print style $style"
+        unless( $style < keys %pretty_print_style);
+        $pretty= $style;
+    }
+      else
+        { croak "invalid pretty print style '$style'"
+            unless( exists $pretty_print_style{$style});
+          $pretty= $pretty_print_style{$style};
+    }
+      return $old_pretty;
+    }
+  
+  
+  # set the empty tag style (in $empty_tag_style) and returns the old one
+  # can be called from outside the package with 2 arguments (elt, style)
+  # or from inside with only one argument (style)
+  # the style can be either a string (one of the keys of %empty_tag_style
+  # or a number (presumably an old value saved)
+  sub set_empty_tag_style
+    { my $style= lc( defined $_[1] ? $_[1] : $_[0]); # so we cover both cases 
+      my $old_style= $empty_tag_style;
+      if( $style=~ /^\d+$/)
+        { croak "invalid empty tag style $style"
+        unless( $style < keys %empty_tag_style);
+        $empty_tag_style= $style;
+    }
+      else
+        { croak "invalid empty tag style '$style'"
+            unless( exists $empty_tag_style{$style});
+          $empty_tag_style= $empty_tag_style{$style};
+    }
+      return $old_style;
+    }
+      
+  sub set_quote
+    { my $style= $_[1] || $_[0];
+      my $old_quote= $quote;
+      croak "invalid quote '$style'" unless( exists $quote_style{$style});
+      $quote= $quote_style{$style};
+      return $old_quote;
+    }
+      
+  sub set_indent
+    { my $new_value= defined $_[1] ? $_[1] : $_[0];
+      my $old_value= $INDENT;
+      $INDENT= $new_value;
+      return $old_value;
+    }
+       
+  sub set_keep_encoding
+    { my $new_value= defined $_[1] ? $_[1] : $_[0];
+      my $old_value= $keep_encoding;
+      $keep_encoding= $new_value;
+      return $old_value;
+    
+   }
+
+  sub keep_encoding { return $keep_encoding; } # so I can use elsewhere in the module
+
+  sub output_filter      { return $output_filter; }
+  sub output_text_filter { return $output_text_filter; }
+
+  sub set_output_filter
+    { my $new_value= defined $_[1] ? $_[1] : $_[0]; # can be called in object/non-object mode
+      # if called in object mode with no argument, the filter is undefined
+      if( isa( $new_value, 'XML::Twig::Elt') || isa( $new_value, 'XML::Twig')) { undef $new_value; }
+      my $old_value= $output_filter;
+      if( !$new_value || isa( $new_value, 'CODE') )
+        { $output_filter= $new_value; }
+      elsif( $new_value eq 'latin1')
+        { $output_filter= XML::Twig::latin1();
+        }
+      elsif( $XML::Twig::filter{$new_value})
+        {  $output_filter= $XML::Twig::filter{$new_value}; }
+      else
+        { croak "invalid output filter '$new_value'"; }
+      
+      return $old_value;
+    }
+       
+  sub set_output_text_filter
+    { my $new_value= defined $_[1] ? $_[1] : $_[0]; # can be called in object/non-object mode
+      # if called in object mode with no argument, the filter is undefined
+      if( isa( $new_value, 'XML::Twig::Elt') || isa( $new_value, 'XML::Twig')) { undef $new_value; }
+      my $old_value= $output_text_filter;
+      if( !$new_value || isa( $new_value, 'CODE') )
+        { $output_text_filter= $new_value; }
+      elsif( $new_value eq 'latin1')
+        { $output_text_filter= XML::Twig::latin1();
+        }
+      elsif( $XML::Twig::filter{$new_value})
+        {  $output_text_filter= $XML::Twig::filter{$new_value}; }
+      else
+        { croak "invalid output text filter '$new_value'"; }
+      
+      return $old_value;
+    }
+       
+  sub set_expand_external_entities
+    { my $new_value= defined $_[1] ? $_[1] : $_[0];
+      my $old_value= $expand_external_entities;
+      $expand_external_entities= $new_value;
+      return $old_value;
+    }
+       
+  sub set_keep_atts_order
+    { my $new_value= defined $_[1] ? $_[1] : $_[0];
+      my $old_value= $keep_atts_order;
+      $keep_atts_order= $new_value;
+      return $old_value;
+    
+   }
+
+  sub keep_atts_order { return $keep_atts_order; } # so I can use elsewhere in the module
+
+  # $elt is an element to print
+  # $pretty is an optional value, if true a \n is printed after the <
+
+  my %empty_should_be_expanded= ( script => 1);
+
+  sub start_tag
+    { my $elt= shift;
+  
+      return if( $elt->{gi}<$XML::Twig::SPECIAL_GI);
+
+      my $extra_data= $elt->{extra_data} || '';
+
+      my $gi= $XML::Twig::index2gi[$elt->{'gi'}];
+
+      my $ns_map= $elt->{'att'}->{'#original_gi'};
+      if( $ns_map) { $gi= _restore_original_prefix( $ns_map, $gi); }
+ 
+      if( $output_text_filter) { $gi= $output_text_filter->( $gi); }
+
+      my $tag="<" . $gi;
+  
+      # get the attribute and their values
+      my $att= $elt->atts;
+      if( $att)
+        { foreach my $att_name ( $keep_atts_order ?  keys %{$att} : sort keys %{$att}) 
+           { # skip private attributes (they start with #)
+             next if( (substr( $att_name, 0, 1) eq '#'));
+
+             $tag .=  $pretty==$NSGMLS ? "\n" : ' ';
+
+             my $output_att_name= $ns_map ? _restore_original_prefix( $ns_map, $att_name) : $att_name;
+             if( $output_text_filter) { $output_att_name=  $output_text_filter->( $output_att_name); }
+
+             $tag .= $output_att_name . '=' . $quote . $elt->att_xml_string( $att_name, $quote) . $quote; 
+           }
+        } 
+  
+      $tag .= "\n" if($pretty==$NSGMLS);
+
+      if( $elt->{empty})
+        { if( !$empty_tag_style)
+            { $tag .= "/>";     }
+          elsif( ($empty_tag_style eq $HTML) && ! $empty_should_be_expanded{$XML::Twig::index2gi[$elt->{'gi'}]})
+            { $tag .= " />";  }
+          else #  $empty_tag_style eq $EXPAND
+            { $tag .= "></" . $XML::Twig::index2gi[$elt->{'gi'}] .">";  }
+        }
+      else
+        { $tag .= ">"; }
+
+      if( (substr( $XML::Twig::index2gi[$elt->{'gi'}], 0, 1) eq '#')) { $tag= ''; }
+
+      unless( $pretty) { return $extra_data . $tag  }
+
+      my $prefix='';
+      my $return='';   # '' or \n is to be printed before the tag
+      my $indent=0;    # number of indents before the tag
+
+      if( $pretty==$RECORD1)
+        { my $level= $elt->level;
+          $return= "\n" if( $level < 2);
+          $indent= 1 if( $level == 1);
+        }
+
+     elsif( $pretty==$RECORD2)
+        { $return= "\n";
+          $indent= $elt->level;
+        }
+
+      elsif( $pretty==$NICE)
+        { my $parent= $elt->{parent};
+          unless( !$parent || $parent->{contains_text}) 
+            { $return= "\n"; }
+          $elt->{contains_text}= 1 if( ($parent && $parent->{contains_text})
+                                     || $elt->contains_text);
+        }
+
+      elsif( ($pretty==$INDENTED) || ($pretty==$INDENTEDC))
+        { my $parent= $elt->{parent};
+          unless( !$parent || $parent->{contains_text}) 
+            { $return= "\n"; 
+              $indent= $elt->level; 
+            }
+          $elt->{contains_text}= 1 if( ($parent && $parent->{contains_text})
+                                     || $elt->contains_text);
+        }
+
+      if( $return || $indent)
+        { # check for elements in which spaces should be kept
+          my $t= $elt->twig;
+          return $extra_data . $tag if( $xml_space_preserve);
+          if( $t && $t->{twig_keep_spaces_in})
+            { foreach my $ancestor ($elt->ancestors)
+                { return $extra_data . $tag if( $t->{twig_keep_spaces_in}->{$XML::Twig::index2gi[$ancestor->{'gi'}]}) }
+                }
+        
+              $prefix= $INDENT x $indent;
+              if( $extra_data)
+                { $extra_data=~ s{\s+$}{};
+                  $extra_data= $prefix .  $extra_data . $return;
+                }
+        }
+
+      return $return . $extra_data . $prefix . $tag;
+    }
+  
+  sub end_tag
+    { my $elt= shift;
+      return  '' if( ($elt->{gi}<$XML::Twig::SPECIAL_GI) || ($elt->{'empty'} || 0));
+      my $tag= "<";
+      $tag.= "\n" if($pretty==$NSGMLS);
+
+      my $gi= $XML::Twig::index2gi[$elt->{'gi'}];
+
+      if( my $map= $elt->{'att'}->{'#original_gi'}) { $gi= _restore_original_prefix( $map, $gi); }
+
+      if( $output_text_filter) { $gi= $output_text_filter->( $XML::Twig::index2gi[$elt->{'gi'}]); } 
+      $tag .=  "/$gi>";
+
+      $tag = ($elt->{extra_data_before_end_tag} || '') . $tag;
+
+      if( (substr( $XML::Twig::index2gi[$elt->{'gi'}], 0, 1) eq '#')) { $tag= ''; }
+
+      return $tag unless $pretty;
+
+      my $prefix='';
+      my $return=0;    # 1 if a \n is to be printed before the tag
+      my $indent=0;    # number of indents before the tag
+
+      if( $pretty==$RECORD1)
+        { $return= 1 if( $elt->level == 0);
+        }
+
+     elsif( $pretty==$RECORD2)
+        { unless( $elt->contains_text)
+            { $return= 1 ;
+              $indent= $elt->level;
+            }
+        }
+
+      elsif( $pretty==$NICE)
+        { my $parent= $elt->{parent};
+          if( (    ($parent && !$parent->{contains_text}) || !$parent )
+            && ( !$elt->{contains_text}  
+             && ($elt->{has_flushed_child} || $elt->_first_child())           
+           )
+         )
+            { $return= 1; }
+        }
+
+      elsif( $pretty==$INDENTED)
+        { my $parent= $elt->{parent};
+          if( (    ($parent && !$parent->{contains_text}) || !$parent )
+            && ( !$elt->{contains_text}  
+             && ($elt->{has_flushed_child} || $elt->_first_child())           
+           )
+         )
+            { $return= 1; 
+              $indent= $elt->level; 
+            }
+        }
+
+      if( $return || $indent)
+        { # check for elements in which spaces should be kept
+          my $t= $elt->twig;
+          return $tag if( $xml_space_preserve);
+          if( $t && $t->{twig_keep_spaces_in})
+            { foreach my $ancestor ($elt, $elt->ancestors)
+                { return $tag if( $t->{twig_keep_spaces_in}->{$XML::Twig::index2gi[$ancestor->{'gi'}]}) }
+            }
+      
+          $prefix= "\n" if( $return);
+          $prefix.= $INDENT x $indent;
+    }
+
+      # add a \n at the end of the document (after the root element)
+      $tag .= "\n" unless( $elt->{parent});
+  
+      return $prefix . $tag;
+    }
+
+  sub _restore_original_prefix
+    { my( $map, $name)= @_;
+      my $prefix= _ns_prefix( $name);
+      if( my $original_prefix= $map->{$prefix})
+        { if( $original_prefix eq '#default')
+            { $name=~ s{^$prefix:}{}; }
+          else
+            { $name=~ s{^$prefix(?=:)}{$original_prefix}; }
+        }
+      return $name;
+    }
+
+  # $elt is an element to print
+  # $fh is an optional filehandle to print to
+  # $pretty is an optional value, if true a \n is printed after the < of the
+  # opening tag
+  sub print
+    { my $elt= shift;
+  
+      my $pretty;
+      my $fh= _is_fh( $_[0]) ? shift : undef;
+      my $old_select= defined $fh ? select $fh : undef;
+      my $old_pretty= defined ($pretty= shift) ? set_pretty_print( $pretty) : undef;
+
+      $xml_space_preserve= 1 if( ($elt->inherit_att( 'xml:space') || '') eq 'preserve');
+ 
+      #$elt->_print;
+      print $elt->_sprint;
+
+      $xml_space_preserve= 0;
+    
+      select $old_select if( defined $old_select);
+      set_pretty_print( $old_pretty) if( defined $old_pretty);
+    }
+      
+  
+  # same as output but does not output the start tag if the element
+  # is marked as flushed
+  sub flush
+    { my $elt= shift;
+      $elt->twig->flush( @_);
+    }
+  
+  sub _flush
+    { my $elt= shift;
+  
+      my $pretty;
+      my $fh=  _is_fh( $_[0]) ? shift : undef;
+      my $old_select= defined $fh ? select $fh : undef;
+      my $old_pretty= defined ($pretty= shift) ? set_pretty_print( $pretty) : undef;
+
+      $xml_space_preserve= 1 if( ($elt->inherit_att( 'xml:space') || '') eq 'preserve');
+
+      $elt->__flush();
+
+      $xml_space_preserve= 0;
+
+      select $old_select if( defined $old_select);
+      set_pretty_print( $old_pretty) if( defined $old_pretty);
+    }
+
+  sub __flush
+    { my $elt= shift;
+  
+      # in case there's some comments or PI's piggybacking
+      #if( $elt->{extra_data})
+      #  { print $output_filter ? $output_filter->($elt->{extra_data}) 
+      #                         : $elt->{extra_data};
+      #  }
+
+      if( $elt->{gi} >= $XML::Twig::SPECIAL_GI)
+        { my $preserve= ($elt->{'att'}->{'xml:space'} || '') eq 'preserve';
+          $xml_space_preserve++ if $preserve;
+          unless( $elt->_flushed)
+            { print $elt->start_tag();
+            }
+      
+          # flush the children
+          my @children= $elt->children;
+          foreach my $child (@children)
+            { $child->_flush( $pretty); 
+        }
+          print $elt->end_tag;
+          $xml_space_preserve-- if $preserve;
+          # used for pretty printing
+          if( my $parent= $elt->{parent}) { $parent->{has_flushed_child}= 1; }
+        }
+      else # text or special element
+        { my $text;
+          if( (exists $elt->{'pcdata'}))     { $text= $elt->pcdata_xml_string; 
+                                     if( my $parent= $elt->{parent}) 
+                                       { $parent->{contains_text}= 1; }
+                                   }
+          elsif( (exists $elt->{'cdata'}))   { $text= $elt->cdata_string;        
+                                     if( my $parent= $elt->{parent}) 
+                                       { $parent->{contains_text}= 1; }
+                                   }
+          elsif( (exists $elt->{'target'}))      { $text= $elt->pi_string;          }
+          elsif( (exists $elt->{'comment'})) { $text= $elt->comment_string;     }
+          elsif( (exists $elt->{'ent'}))     { $text= $elt->ent_string;         }
+
+          print $output_filter ? $output_filter->( $text) : $text;
+        }
+    }
+  
+
+  sub xml_text
+    { my $elt= shift;
+      my $string='';
+
+      if( $elt->{gi} >= $XML::Twig::SPECIAL_GI)
+        { # sprint the children
+          my $child= $elt->{first_child}||'';
+          while( $child)
+            { $string.= $child->xml_text;
+              $child= $child->{next_sibling};
+            }
+        }
+      elsif( (exists $elt->{'pcdata'}))  { $string .= $output_filter ?  $output_filter->($elt->pcdata_xml_string) 
+                                                           : $elt->pcdata_xml_string; 
+                               }
+      elsif( (exists $elt->{'cdata'}))   { $string .= $output_filter ?  $output_filter->($elt->cdata_xml_string)  
+                                                           : $elt->cdata_string;      
+                               }
+      elsif( (exists $elt->{'ent'}))     { $string .= $elt->ent_string; }
+
+      return $string;
+    }
+
+
+  # same as print but except... it does not print but rather returns the string
+  # if the second parameter is set then only the content is returned, not the
+  # start and end tags of the element (but the tags of the included elements are
+  # returned)
+  sub sprint
+    { my $elt= shift;
+
+      $xml_space_preserve= 1 if( ($elt->inherit_att( 'xml:space') || '') eq 'preserve');
+
+      my $sprint= $output_filter ? $output_filter->( $elt->_sprint( @_)) : $elt->_sprint( @_);
+
+      $xml_space_preserve= 0;
+
+      return $sprint;
+
+    }
+  
+  sub _sprint
+    { my $elt= shift;
+      my $no_tag= shift || 0;
+      # in case there's some comments or PI's piggybacking
+      my $string='';
+      #if( $elt->{extra_data} && !$no_tag)
+      #  { $string= $elt->{extra_data};
+      #  }
+
+      if( $elt->{gi} >= $XML::Twig::SPECIAL_GI)
+        {
+          my $preserve= ($elt->{'att'}->{'xml:space'} || '') eq 'preserve';
+          $xml_space_preserve++ if $preserve;
+
+          $string.= $elt->start_tag unless( $no_tag);
+      
+          # sprint the children
+          my $child= $elt->{first_child}||'';
+          while( $child)
+            { $string.= $child->_sprint;
+              $child= $child->{next_sibling};
+            }
+          $string.= $elt->end_tag unless( $no_tag);
+          $xml_space_preserve-- if $preserve;
+        }
+      else
+        { $string .= $elt->{extra_data} || '';
+             if( (exists $elt->{'pcdata'}))  { $string .= $elt->pcdata_xml_string; }
+          elsif( (exists $elt->{'cdata'}))   { $string .= $elt->cdata_string;      }
+          elsif( (exists $elt->{'target'}))      { $string .= $elt->pi_string;         }
+          elsif( (exists $elt->{'comment'})) { $string .= $elt->comment_string;    }
+          elsif( (exists $elt->{'ent'}))     { $string .= $elt->ent_string;        }
+        }
+
+      return $string;
+    }
+
+  # just a shortcut to $elt->sprint( 1)
+  sub xml_string
+    { $_[0]->sprint( 1); }
+
+  sub pcdata_xml_string 
+    { my $string='';
+      if( defined( $string= $_[0]->{pcdata}) )
+        { $string=~ s/([&<])/$XML::Twig::base_ent{$1}/g
+            unless( $keep_encoding || $_[0]->{asis}); 
+        }
+      return $output_text_filter ? $output_text_filter->( $string) : $string;
+    }
+  
+  sub att_xml_string 
+    { my $elt= shift;
+      my $att= shift;
+      my $quote= shift || '"';
+      my $string='';
+      if( defined ($string= $elt->{att}->{$att}))
+        { $string=~ s/([$quote<&])/$XML::Twig::base_ent{$1}/g
+            unless( $keep_encoding); 
+        }
+      return $output_text_filter ? $output_text_filter->( $string) : $string;
+    }
+
+  sub ent_string 
+    { my $ent= shift;
+      my $ent_text= $ent->{ent};
+      my( $t, $el, $ent_string);
+      if(    $expand_external_entities
+          && ($t= $ent->twig) 
+          && ($el= $t->entity_list)
+          && ($ent_string= $el->{$ent->ent_name}->{val})
+        )
+       { return $ent_string; }
+  
+       return $ent_text; 
+    }
+
+  # returns just the text, no tags, for an element
+  sub text
+    { my $elt= shift;
+      my $string;
+  
+      if( (exists $elt->{'pcdata'}))     { return  $elt->{pcdata};   }
+      elsif( (exists $elt->{'cdata'}))   { return  $elt->{cdata};    }
+      elsif( (exists $elt->{'target'}))      { return  $elt->pi_string;}
+      elsif( (exists $elt->{'comment'})) { return  $elt->{comment};  }
+      elsif( (exists $elt->{'ent'}))     { return  $elt->{ent} ;     }
+  
+      my $child= $elt->{first_child} ||'';
+      while( $child)
+        { $string.= defined($child->text) ? $child->text : '';
+          $child= $child->{next_sibling};
+        }
+      unless( defined $string) { $string=''; }
+  
+      return $output_text_filter ? $output_text_filter->( $string) : $string;
+    }
+
+  sub trimmed_text
+    { my $elt= shift;
+      my $text= $elt->text;
+      $text=~ s{\s+}{ }sg;
+      $text=~ s{^\s*}{};
+      $text=~ s{\s*$}{};
+      return $text;
+    }
+
+  # remove cdata sections (turns them into regular pcdata) in an element 
+  sub remove_cdata 
+    { my $elt= shift;
+      foreach my $cdata ($elt->descendants_or_self( CDATA))
+        { if( $keep_encoding)
+            { my $data= $cdata->{cdata};
+              $data=~ s{([&<"'])}{$XML::Twig::base_ent{$1}}g;
+              $cdata->{pcdata}=  $data;
+            }
+          else
+            { $cdata->{pcdata}=  $cdata->{cdata}; }
+          $cdata->set_gi( PCDATA);
+          undef $cdata->{cdata};
+        }
+    }
+
+sub _is_private      { return _is_private_name( $_[0]->gi); }
+sub _is_private_name { return $_[0]=~ m{^#};                }
+
+
+} # end of block containing package globals ($pretty_print, $quotes, keep_encoding...)
+
+
+# SAX export methods
+sub toSAX1
+  { _toSAX(@_, \&_start_tag_data_SAX1, \&_end_tag_data_SAX1); }
+
+sub toSAX2
+  { _toSAX(@_, \&_start_tag_data_SAX2, \&_end_tag_data_SAX2); }
+
+sub _toSAX
+  { my( $elt, $handler, $start_tag_data, $end_tag_data)= @_;
+    if( $elt->{gi} >= $XML::Twig::SPECIAL_GI)
+      { my $data= $start_tag_data->( $elt);
+        _start_prefix_mapping( $elt, $handler, $data);
+        if( $data && (my $start_element = $handler->can( 'start_element')))
+          { $start_element->( $handler, $data) unless( $elt->_flushed); }
+      
+        foreach my $child ($elt->children)
+          { $child->_toSAX( $handler, $start_tag_data, $end_tag_data); }
+
+        if( (my $data= $end_tag_data->( $elt)) && (my $end_element = $handler->can( 'end_element')) )
+          { $end_element->( $handler, $data); }
+        _end_prefix_mapping( $elt, $handler);
+      }
+    else # text or special element
+      { if( (exists $elt->{'pcdata'}) && (my $characters= $handler->can( 'characters')))
+          { $characters->( $handler, { Data => $elt->{pcdata} });  }
+        elsif( (exists $elt->{'cdata'}))  
+          { if( my $start_cdata= $handler->can( 'start_cdata'))
+              { $start_cdata->( $handler); }
+            if( my $characters= $handler->can( 'characters'))
+              { $characters->( $handler, {Data => $elt->{cdata} });  }
+            if( my $end_cdata= $handler->can( 'end_cdata'))
+              { $end_cdata->( $handler); }
+          }
+        elsif( ((exists $elt->{'target'}))  && (my $pi= $handler->can( 'processing_instruction')))
+          { $pi->( $handler, { Target =>$elt->{target}, Data => $elt->{data} });  }
+        elsif( ((exists $elt->{'comment'}))  && (my $comment= $handler->can( 'comment')))
+          { $comment->( $handler, { Data => $elt->{comment} });  }
+        elsif( ((exists $elt->{'ent'})))
+          { 
+            if( my $se=   $handler->can( 'skipped_entity'))
+              { $se->( $handler, { Name => $elt->ent_name });  }
+            elsif( my $characters= $handler->can( 'characters'))
+              { if( defined $elt->ent_string)
+                  { $characters->( $handler, {Data => $elt->ent_string});  }
+                else
+                  { $characters->( $handler, {Data => $elt->ent_name});  }
+              }
+          }
+      
+      }
+  }
+  
+sub _start_tag_data_SAX1
+  { my( $elt)= @_;
+    my $name= $XML::Twig::index2gi[$elt->{'gi'}];
+    return if( (substr( $XML::Twig::index2gi[$elt->{'gi'}], 0, 1) eq '#'));
+    my $attributes={};
+    my $atts= $elt->atts;
+    while( my( $att, $value)= each %$atts)
+      { $attributes->{$att}= $value unless( (substr( $att, 0, 1) eq '#')); }
+    my $data= { Name => $name, Attributes => $attributes};
+    return $data;
+  }
+
+sub _end_tag_data_SAX1
+  { my( $elt)= @_;
+    return if( (substr( $XML::Twig::index2gi[$elt->{'gi'}], 0, 1) eq '#'));
+    return  { Name => $XML::Twig::index2gi[$elt->{'gi'}] };
+  } 
+  
+sub _start_tag_data_SAX2
+  { my( $elt)= @_;
+    my $data={};
+    
+    my $name= $XML::Twig::index2gi[$elt->{'gi'}];
+    return if( (substr( $XML::Twig::index2gi[$elt->{'gi'}], 0, 1) eq '#'));
+    $data->{Name}         = $name;
+    $data->{Prefix}       = $elt->ns_prefix; 
+    $data->{LocalName}    = $elt->local_name;
+    $data->{NamespaceURI} = $elt->namespace;
+
+    # save a copy of the data so we can re-use it for the end tag
+    my %sax2_data= %$data;
+    $elt->{twig_elt_SAX2_data}= \%sax2_data;
+   
+    # add the attributes
+    $data->{Attributes}= $elt->_atts_to_SAX2;
+
+    return $data;
+  }
+
+sub _atts_to_SAX2
+  { my $elt= shift;
+    my $SAX2_atts= {};
+    foreach my $att (keys %{$elt->atts})
+      { 
+        next if( (substr( $att, 0, 1) eq '#'));
+        my $SAX2_att={};
+        $SAX2_att->{Name}         = $att;
+        $SAX2_att->{Prefix}       = _ns_prefix( $att); 
+        $SAX2_att->{LocalName}    = _local_name( $att);
+        $SAX2_att->{NamespaceURI} = $elt->namespace( $SAX2_att->{Prefix});
+        $SAX2_att->{Value}        = $elt->{'att'}->{$att};
+        my $SAX2_att_name= "{$SAX2_att->{NamespaceURI}}$SAX2_att->{LocalName}";
+
+        $SAX2_atts->{$SAX2_att_name}= $SAX2_att;
+      }
+    return $SAX2_atts;
+  }
+
+sub _start_prefix_mapping
+  { my( $elt, $handler, $data)= @_;
+    if( my $start_prefix_mapping= $handler->can( 'start_prefix_mapping')
+        and my @new_prefix_mappings= grep { /^\{[^}]*\}xmlns/ || /^\{$XMLNS_URI\}/ } keys %{$data->{Attributes}}
+      )
+      { foreach my $prefix (@new_prefix_mappings)
+          { my $prefix_string= $data->{Attributes}->{$prefix}->{LocalName};
+            if( $prefix_string eq 'xmlns') { $prefix_string=''; }
+            my $prefix_data=
+              {  Prefix       => $prefix_string,
+                 NamespaceURI => $data->{Attributes}->{$prefix}->{Value}
+              };
+            $start_prefix_mapping->( $handler, $prefix_data);
+            $elt->{twig_end_prefix_mapping} ||= [];
+            push @{$elt->{twig_end_prefix_mapping}}, $prefix_string;
+          }
+      }
+  }
+
+sub _end_prefix_mapping
+  { my( $elt, $handler)= @_;
+    if( my $end_prefix_mapping= $handler->can( 'end_prefix_mapping'))
+      { foreach my $prefix (@{$elt->{twig_end_prefix_mapping}})
+          { $end_prefix_mapping->( $handler, { Prefix => $prefix} ); }
+      }
+  }
+             
+sub _end_tag_data_SAX2
+  { my( $elt)= @_;
+    return if( (substr( $XML::Twig::index2gi[$elt->{'gi'}], 0, 1) eq '#'));
+    return $elt->{twig_elt_SAX2_data};
+  } 
+
+
+
+#start-extract twig_node
+sub contains_text
+  { my $elt= shift;
+    my $child= $elt->{first_child};
+    while ($child)
+      { return 1 if( $child->is_text || (exists $child->{'ent'})); 
+        $child= $child->{next_sibling};
+      }
+    return 0;
+  }
+
+#end-extract twig_node
+
+# creates a single pcdata element containing the text as child of the element
+# options: 
+#   - force_pcdata: when set to a true value forces the text to be in a#PCDATA
+#                   even if the original element was a #CDATA
+sub set_text
+  { my( $elt, $string, %option)= @_;
+
+    if( $XML::Twig::index2gi[$elt->{'gi'}] eq PCDATA) 
+      { return $elt->{pcdata}=  $string; }
+    elsif( $XML::Twig::index2gi[$elt->{'gi'}] eq CDATA)  
+      { if( $option{force_pcdata})
+          { $elt->set_gi( PCDATA);
+            $elt->{cdata}= '';
+            return $elt->{pcdata}=  $string;
+      }
+    else
+      { return $elt->{cdata}=  $string; }
+      }
+
+    foreach my $child (@{[$elt->children]})
+      { $child->delete; }
+
+    my $pcdata= XML::Twig::Elt->new( PCDATA, $string);
+    $pcdata->paste( $elt);
+
+    delete $elt->{empty};
+
+    return $elt;
+  }
+
+# set the content of an element from a list of strings and elements
+sub set_content
+  { my $elt= shift;
+
+    return $elt unless defined $_[0];
+
+    # attributes can be given as a hash (passed by ref)
+    if( ref $_[0] eq 'HASH')
+      { my $atts= shift;
+        $elt->del_atts; # usually useless but better safe than sorry
+        $elt->set_atts( $atts);
+        return  $elt unless defined $_[0];
+      }
+
+    # check next argument for #EMPTY
+    if( !(ref $_[0]) && ($_[0] eq EMPTY) ) 
+      { $elt->{empty}= 1; return $elt; }
+
+    # case where we really want to do a set_text, the element is '#PCDATA'
+    # and we only want to add text in it
+    if( ($XML::Twig::index2gi[$elt->{'gi'}] eq PCDATA) && ($#_ == 0) && !( ref $_[0]))
+      { $elt->{pcdata}=  $_[0];
+        return $elt;
+      }
+    elsif( ($XML::Twig::index2gi[$elt->{'gi'}] eq CDATA) && ($#_ == 0) && !( ref $_[0]))
+      { $elt->{cdata}=  $_[0];
+        return $elt;
+      }
+
+    # delete the children
+    # WARNING: potential problem here if the children are used
+    # somewhere else (where?). Will be solved when I use weak refs
+    foreach my $child (@{[$elt->children]})
+      { $child->delete; }
+
+    foreach my $child (@_)
+      { if( isa( $child, 'XML::Twig::Elt'))
+          { # argument is an element
+            $child->paste( 'last_child', $elt);
+          }
+        else
+          { # argument is a string
+            if( (my $pcdata= $elt->{last_child}) && $elt->{last_child}->is_pcdata)
+              { # previous child is also pcdata: just concatenate
+                $pcdata->{pcdata}=  $pcdata->{pcdata} . $child 
+              }
+            else
+              { # previous child is not a string: creat a new pcdata element
+                $pcdata= XML::Twig::Elt->new( PCDATA, $child);
+                $pcdata->paste( 'last_child', $elt);  
+              }
+          }
+      }
+
+    delete $elt->{empty};
+
+    return $elt;
+  }
+
+# inserts an element (whose gi is given) as child of the element
+# all children of the element are now children of the new element
+# returns the new element
+sub insert
+  { my ($elt, @args)= @_;
+    # first cut the children
+    my @children= $elt->children;
+    foreach my $child (@children)
+      { $child->cut; }
+    # insert elements
+    while( my $gi= shift @args)
+      { my $new_elt= XML::Twig::Elt->new( $gi);
+        # add attributes if needed
+        if( defined( $args[0]) && ( isa( $args[0], 'HASH')) )
+          { $new_elt->set_atts( shift @args); }
+        # paste the element
+        $new_elt->paste( $elt);
+        delete $elt->{empty};
+        $elt= $new_elt;
+      }
+    # paste back the children
+    foreach my $child (@children)
+      { $child->paste( 'last_child', $elt); }
+    return $elt;
+  }
+
+# insert a new element 
+# $elt->insert_new_element( $opt_position, $gi, $opt_atts_hash, @opt_content); 
+# the element is created with the same syntax as new
+# position is the same as in paste, first_child by default
+sub insert_new_elt
+  { my $elt= shift;
+    my $position= $_[0];
+    if(     ($position eq 'before') || ($position eq 'after')
+         || ($position eq 'first_child') || ($position eq 'last_child'))
+      { shift; }
+    else
+      { $position= 'first_child'; }
+
+    my $new_elt= $elt->new( @_);
+    $new_elt->paste( $position, $elt);
+    return $new_elt;
+  }
+
+# wraps an element in elements which gi's are given as arguments
+# $elt->wrap_in( 'td', 'tr', 'table') wraps the element as a single
+# cell in a table for example
+# returns the new element
+sub wrap_in
+  { my $elt= shift;
+    while( my $gi = shift @_)
+      { my $new_elt = XML::Twig::Elt->new( $gi);
+        if( $elt->{twig_current})
+          { my $t= $elt->twig;
+            $t->{twig_current}= $new_elt;
+            delete $elt->{'twig_current'};
+            $new_elt->{'twig_current'}=1;
+          }
+
+        if( my $parent= $elt->{parent})
+          { $new_elt->set_parent( $parent); 
+            $parent->{first_child}=  $new_elt if( $parent->{first_child} == $elt);
+            $parent->set_last_child( $new_elt)  if( $parent->{last_child} == $elt);
+          }
+        else
+          { # wrapping the root
+            my $twig= $elt->twig;
+            if( $twig && $twig->root && ($twig->root eq $elt) )
+              { $twig->{twig_root}= $new_elt; }
+          }
+
+        if( my $prev_sibling= $elt->{prev_sibling})
+          { $new_elt->set_prev_sibling( $prev_sibling);
+            $prev_sibling->{next_sibling}=  $new_elt;
+          }
+
+        if( my $next_sibling= $elt->{next_sibling})
+          { $new_elt->{next_sibling}=  $next_sibling;
+            $next_sibling->set_prev_sibling( $new_elt);
+          }
+        $new_elt->{first_child}=  $elt;
+        $new_elt->set_last_child( $elt);
+
+        $elt->set_parent( $new_elt);
+        $elt->set_prev_sibling( undef);
+        $elt->{next_sibling}=  undef;
+
+        # add the attributes if the next argument is a hash ref
+        if( defined( $_[0]) && (isa( $_[0], 'HASH')) )
+          { $new_elt->set_atts( shift @_); }
+
+        $elt= $new_elt;
+      }
+      
+    return $elt;
+  }
+
+sub replace
+  { my( $elt, $ref)= @_;
+    if( my $parent= $ref->{parent})
+      { $elt->set_parent( $parent);
+        $parent->{first_child}=  $elt if( $parent->{first_child} == $ref);
+        $parent->set_last_child( $elt)  if( $parent->{last_child} == $ref);
+      }
+    if( my $prev_sibling= $ref->{prev_sibling})
+      { $elt->set_prev_sibling( $prev_sibling);
+        $prev_sibling->{next_sibling}=  $elt;
+      }
+    if( my $next_sibling= $ref->{next_sibling})
+      { $elt->{next_sibling}=  $next_sibling;
+        $next_sibling->set_prev_sibling( $elt);
+      }
+   
+    $ref->set_parent( undef);
+    $ref->set_prev_sibling( undef);
+    $ref->{next_sibling}=  undef;
+    return $ref;
+  }
+
+sub replace_with
+  { my $ref= shift;
+    my $elt= shift;
+    $elt->replace( $ref);
+    foreach my $new_elt (reverse @_)
+      { $new_elt->paste( after => $elt); }
+    return $elt;
+  }
+
+
+#start-extract twig_node
+# move an element, same syntax as paste, except the element is first cut
+sub move
+  { my $elt= shift;
+    $elt->cut;
+    $elt->paste( @_);
+    return $elt;
+  }
+#end-extract twig_node
+
+
+# adds a prefix to an element, creating a pcdata child if needed
+sub prefix
+  { my ($elt, $prefix, $option)= @_;
+    my $asis= ($option && ($option eq 'asis')) ? 1 : 0;
+    if( (exists $elt->{'pcdata'}) 
+        && (($asis && $elt->{asis}) || (!$asis && ! $elt->{asis}))
+      )
+      { $elt->{pcdata}=  $prefix . $elt->{pcdata}; }
+    elsif( $elt->{first_child} && $elt->{first_child}->is_pcdata
+        && (   ($asis && $elt->{first_child}->{asis}) 
+            || (!$asis && ! $elt->{first_child}->{asis}))
+         )
+      { $elt->{first_child}->set_pcdata( $prefix . $elt->{first_child}->pcdata); }
+    else
+      { my $new_elt= XML::Twig::Elt->new( PCDATA, $prefix);
+        $new_elt->paste( $elt);
+        $new_elt->set_asis if( $asis);
+      }
+    return $elt;
+  }
+
+# adds a suffix to an element, creating a pcdata child if needed
+sub suffix
+  { my ($elt, $suffix, $option)= @_;
+    my $asis= ($option && ($option eq 'asis')) ? 1 : 0;
+    if( (exists $elt->{'pcdata'})
+        && (($asis && $elt->{asis}) || (!$asis && ! $elt->{asis}))
+      )
+      { $elt->{pcdata}=  $elt->{pcdata} . $suffix; }
+    elsif( $elt->{last_child} && $elt->{last_child}->is_pcdata
+        && (   ($asis && $elt->{last_child}->{asis}) 
+            || (!$asis && ! $elt->{last_child}->{asis}))
+         )
+      { $elt->{last_child}->set_pcdata( $elt->{last_child}->pcdata . $suffix); }
+    else
+      { my $new_elt= XML::Twig::Elt->new( PCDATA, $suffix);
+        $new_elt->paste( 'last_child', $elt);
+        $new_elt->set_asis if( $asis);
+      }
+    return $elt;
+  }
+
+#start-extract twig_node
+# create a path to an element ('/root/.../gi)
+sub path
+  { my $elt= shift;
+    my @context= ( $elt, $elt->ancestors);
+    return "/" . join( "/", reverse map {$_->gi} @context);
+  }
+
+sub xpath
+  { my $elt= shift;
+    my $xpath;
+    foreach my $ancestor (reverse $elt->ancestors_or_self)
+      { my $gi= $XML::Twig::index2gi[$ancestor->{'gi'}];
+        $xpath.= "/$gi";
+        my $index= $ancestor->prev_siblings( $gi) + 1;
+        unless( ($index == 1) && !$ancestor->next_sibling( $gi))
+          { $xpath.= "[$index]"; }
+      }
+    return $xpath;
+  }
+
+# methods used mainly by wrap_children
+
+# return a string with the 
+# for an element <foo><elt att="val">...</elt><elt2/><elt>...</elt></foo>
+# returns '<elt att="val"><elt2><elt>'
+sub _stringify_struct
+  { my( $elt, %opt)= @_;
+    my $string;
+    my $pretty_print= XML::Twig::Elt::set_pretty_print( 'none');
+    foreach my $child ($elt->children)
+      { $child->add_id; $string .= $child->start_tag; }
+    XML::Twig::Elt::set_pretty_print( $pretty_print);
+    return $string;
+  }
+
+# wrap a series of elements in a new one
+sub _wrap_range
+  { my $elt= shift;
+    my $gi= shift;
+    my $atts= isa( $_[0], 'HASH') ? shift : undef;
+    my $range= shift; # the string with the tags to wrap
+
+    my $t= $elt->twig;
+
+    # get the tags to wrap
+    my @to_wrap;
+    while( $range=~ m{<\w+\s+[^>]*id=("[^"]*"|'[^']*')[^>]*>}g)
+      { push @to_wrap, $t->elt_id( substr( $1, 1, -1)); }
+
+    return '' unless @to_wrap;
+    
+    my $to_wrap= shift @to_wrap;
+    my %atts= %$atts;
+    my $new_elt= $to_wrap->wrap_in( $gi, \%atts);
+    $_->move( last_child => $new_elt) foreach (@to_wrap);
+
+    return '';
+  }
+    
+# wrap children matching a regexp in a new element
+sub wrap_children
+  { my( $elt, $regexp, $gi, $atts)= @_;
+
+    $atts ||={};
+
+    my $elt_as_string= $elt->_stringify_struct; # stringify the elt structure
+    $regexp=~ s{(<[^>]*>)}{_match_expr( $1)}eg; # in the regexp, replace gi's by the proper regexp 
+    $elt_as_string=~ s{($regexp)}{$elt->_wrap_range( $gi, $atts, $1)}eg; # then do the actual replace
+  
+    return $elt; 
+  }
+
+sub _match_expr
+  { my $tag= shift;
+    my( $gi, %atts)= XML::Twig::_parse_start_tag( $tag);
+    return _match_tag( $gi, %atts);
+  }
+
+
+sub _match_tag
+  { my( $elt, %atts)= @_;
+    my $string= "<$elt\\b";
+    foreach my $key (sort keys %atts)
+      { my $val= $atts{$key};
+        $val= "\Q$val\E";
+       # my $val= qq{\Q$atts{$key}\E};
+        $string.= qq{[^>]*$key=(?:"$val"|'$val')};
+      }
+    $string.=  qq{[^>]*>};
+    return "(?:$string)";
+  }
+
+sub field_to_att
+  { my( $elt, $cond, $att)= @_;
+    $att ||= $cond;
+    my $child= $elt->first_child( $cond) or return undef;
+    $elt->set_att( $att => $child->text);
+    $child->cut;
+    return $elt;
+  }
+
+sub att_to_field
+  { my( $elt, $att, $tag)= @_;
+    $tag ||= $att;
+    my $child= $elt->insert_new_elt( first_child => $tag, $elt->{'att'}->{$att});
+    $elt->del_att( $att);
+    return $elt;
+  }
+
+# sort children methods
+
+sub sort_children_on_field
+  { my $elt   = shift;
+    my $field = shift;
+    my $get_key= sub { return $_[0]->field( $field) };
+    return $elt->sort_children( $get_key, @_); 
+  }
+
+sub sort_children_on_att
+  { my $elt = shift;
+    my $att = shift;
+    my $get_key= sub { return $_[0]->{'att'}->{$att} };
+    return $elt->sort_children( $get_key, @_); 
+  }
+
+sub sort_children_on_value
+  { my $elt   = shift;
+    #my $get_key= eval qq{ sub { return \$_[0]->text } };
+    my $get_key= \&text;
+    return $elt->sort_children( $get_key, @_); 
+  }
+
+
+sub sort_children
+  { my( $elt, $get_key, %opt)=@_;
+    $opt{order} ||= 'normal';
+    $opt{type}  ||= 'alpha';
+    my( $par_a, $par_b)= ($opt{order} eq 'reverse') ? qw( b a) : qw ( a b) ;
+    my $op= ($opt{type} eq 'numeric') ? '<=>' : 'cmp' ;
+    my @children= $elt->cut_children;
+    if( $opt{type} eq 'numeric')
+      {  @children= map  { $_->[1] }
+                    sort { $a->[0] <=> $b->[0] }
+                    map  { [ $get_key->( $_), $_] } @children;
+      }
+    elsif( $opt{type} eq 'alpha')
+      {  @children= map  { $_->[1] }
+                    sort { $a->[0] cmp $b->[0] }
+                    map  { [ $get_key->( $_), $_] } @children;
+      }
+    else
+      { croak "wrong sort type '$opt{type}', should be either 'alpha' or 'numeric'"; }
+
+    @children= reverse @children if( $opt{order} eq 'reverse');
+    $elt->set_content( @children);
+  }
+
+
+# comparison methods
+
+sub before
+  { my( $a, $b)=@_;
+    if( $a->cmp( $b) == -1) { return 1; } else { return 0; }
+  }
+
+sub after
+  { my( $a, $b)=@_;
+    if( $a->cmp( $b) == 1) { return 1; } else { return 0; }
+  }
+
+sub lt
+  { my( $a, $b)=@_;
+    return 1 if( $a->cmp( $b) == -1);
+    return 0;
+  }
+
+sub le
+  { my( $a, $b)=@_;
+    return 1 unless( $a->cmp( $b) == 1);
+    return 0;
+  }
+
+sub gt
+  { my( $a, $b)=@_;
+    return 1 if( $a->cmp( $b) == 1);
+    return 0;
+  }
+
+sub ge
+  { my( $a, $b)=@_;
+    return 1 unless( $a->cmp( $b) == -1);
+    return 0;
+  }
+
+
+sub cmp
+  { my( $a, $b)=@_;
+
+    # easy cases
+    return  0 if( $a == $b);    
+    return  1 if( $a->in($b)); # a starts after b 
+    return -1 if( $b->in($a)); # a starts before b
+
+    # ancestors does not include the element itself
+    my @a_pile= ($a, $a->ancestors); 
+    my @b_pile= ($b, $b->ancestors);
+
+    # the 2 elements are not in the same twig
+    return undef unless( $a_pile[-1] == $b_pile[-1]);
+
+    # find the first non common ancestors (they are siblings)
+    my $a_anc= pop @a_pile;
+    my $b_anc= pop @b_pile;
+
+    while( $a_anc == $b_anc) 
+      { $a_anc= pop @a_pile;
+        $b_anc= pop @b_pile;
+      }
+
+    # from there move left and right and figure out the order
+    my( $a_prev, $a_next, $b_prev, $b_next)= ($a_anc, $a_anc, $b_anc, $b_anc);
+    while()
+      { $a_prev= $a_prev->{prev_sibling} || return( -1);
+        return 1 if( $a_prev == $b_next);
+        $a_next= $a_next->{next_sibling} || return( 1);
+        return -1 if( $a_next == $b_prev);
+        $b_prev= $b_prev->{prev_sibling} || return( 1);
+        return -1 if( $b_prev == $a_next);
+        $b_next= $b_next->{next_sibling} || return( -1);
+        return 1 if( $b_next == $a_prev);
+      }
+  }
+    
+#end-extract twig_node
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+XML::Twig - A perl module for processing huge XML documents in tree mode.
+
+=head1 SYNOPSIS
+
+Small documents (loaded in memory as a tree):
+
+  my $twig=XML::Twig->new();    # create the twig
+  $twig->parsefile( 'doc.xml'); # build it
+  my_process( $twig);           # use twig methods to process it 
+  $twig->print;                 # output the twig
+
+Huge documents (processed in combined stream/tree mode):
+
+  # at most one div will be loaded in memory
+  my $twig=XML::Twig->new(   
+    twig_handlers => 
+      { title   => sub { $_->set_gi( 'h2') }, # change title tags to h2
+        para    => sub { $_->set_gi( 'p')  }, # change para to p
+        hidden  => sub { $_->delete;       }, # remove hidden elements
+        list    => \&my_list_process,         # process list elements
+        div     => sub { $_[0]->flush;     }, # output and free memory
+      },
+    pretty_print => 'indented',               # output will be nicely formatted
+    empty_tags   => 'html',                   # outputs <empty_tag />
+                         );
+    $twig->flush;                             # flush the end of the document
+
+See L<XML::Twig 101|XML::Twig 101> for other ways to use the module, as a 
+filter for example
+
+Note that this documentation is intended as a reference to the module. A 
+tutorial is available at http://www.xmltwig.com/xmltwig/tutorial/index.html
+and a FAQ is at http://www.xmltwig.com/xmltwig/XML-Twig-FAQ.html
+
+=head1 DESCRIPTION
+
+This module provides a way to process XML documents. It is build on top
+of C<XML::Parser>.
+
+The module offers a tree interface to the document, while allowing you
+to output the parts of it that have been completely processed.
+
+It allows minimal resource (CPU and memory) usage by building the tree
+only for the parts of the documents that need actual processing, through the 
+use of the C<L<twig_roots|twig_roots> > and 
+C<L<twig_print_outside_roots|twig_print_outside_roots> > options. The 
+C<L<finish|finish> > and C<L<finish_print|finish_print> > methods also help 
+to increase performances.
+
+XML::Twig tries to make simple things easy so it tries its best to takes care 
+of a lot of the (usually) annoying (but sometimes necessary) features that 
+come with XML and XML::Parser.
+
+=head1 XML::Twig 101
+
+XML::Twig can be used either on "small" XML documents (that fit in memory)
+or on huge ones, by processing parts of the document and outputting or
+discarding them once they are processed.
+
+
+=head2 Loading an XML document and processing it
+
+  my $t= XML::Twig->new();
+  $t->parse( '<d><title>title</title><para>p 1</para><para>p 2</para></d>');
+  my $root= $t->root;
+  $root->set_gi( 'html');               # change doc to html
+  $title= $root->first_child( 'title'); # get the title
+  $title->set_gi( 'h1');                # turn it into h1
+  my @para= $root->children( 'para');   # get the para children
+  foreach my $para (@para)
+    { $para->set_gi( 'p'); }            # turn them into p
+  $t->print;                            # output the document
+
+Other useful methods include:
+
+L<att|att>: C<< $elt->{'att'}->{'foo'} >> return the C<foo> attribute for an 
+element,
+
+L<set_att|set_att> : C<< $elt->set_att( foo => "bar") >> sets the C<foo> 
+attribute to the C<bar> value,
+
+L<next_sibling|next_sibling>: C<< $elt->{next_sibling} >> return the next sibling
+in the document (in the example C<< $title->{next_sibling} >> is the first
+C<para>, you can also (and actually should) use 
+C<< $elt->next_sibling( 'para') >> to get it 
+
+The document can also be transformed through the use of the L<cut|cut>, 
+L<copy|copy>, L<paste|paste> and L<move|move> methods: 
+C<< $title->cut; $title->paste( after => $p); >> for example
+
+And much, much more, see L<Elt|"Elt">.
+
+=head2 Processing an XML document chunk by chunk
+
+One of the strengths of XML::Twig is that it let you work with files that do 
+not fit in memory (BTW storing an XML document in memory as a tree is quite
+memory-expensive, the expansion factor being often around 10).
+
+To do this you can define handlers, that will be called once a specific 
+element has been completely parsed. In these handlers you can access the
+element and process it as you see fit, using the navigation and the
+cut-n-paste methods, plus lots of convenient ones like C<L<prefix|prefix> >.
+Once the element is completely processed you can then C<L<flush|flush> > it, 
+which will output it and free the memory. You can also C<L<purge|purge> > it 
+if you don't need to output it (if you are just extracting some data from 
+the document for example). The handler will be called again once the next 
+relevant element has been parsed.
+
+  my $t= XML::Twig->new( twig_handlers => 
+                          { section => \&section,
+                            para   => sub { $_->set_tag( 'p');
+                          },
+                       );
+  $t->parsefile( 'doc.xml');
+  $t->flush; # don't forget to flush one last time in the end or anything
+             # after the last </section> tag will not be output 
+    
+  # the handler is called once a section is completely parsed, ie when 
+  # the end tag for section is found, it receives the twig itself and
+  # the element (including all its sub-elements) as arguments
+  sub section 
+    { my( $t, $section)= @_;      # arguments for all twig_handlers
+      $section->set_tag( 'div');  # change the tag name.4, my favourite method...
+      # let's use the attribute nb as a prefix to the title
+      my $title= $section->first_child( 'title'); # find the title
+      my $nb= $title->{'att'}->{'nb'}; # get the attribute
+      $title->prefix( "$nb - ");  # easy isn't it?
+      $section->flush;            # outputs the section and frees memory
+    }
+
+        
+There is of course more to it: you can trigger handlers on more elaborate 
+conditions than just the name of the element, C<section/title> for example.
+
+  my $t= XML::Twig->new( twig_handlers => 
+                           { 'section/title' => sub { $_->print } }
+                       )
+                  ->parsefile( 'doc.xml');
+
+Here C<< sub { $_->print } >> simply prints the current element (C<$_> is aliased
+to the element in the handler).
+
+You can also trigger a handler on a test on an attribute:
+
+  my $t= XML::Twig->new( twig_handlers => 
+                      { 'section[@level="1"]' => sub { $_->print } }
+                       );
+                  ->parsefile( 'doc.xml');
+
+You can also use C<L<start_tag_handlers|start_tag_handlers> > to process an 
+element as soon as the start tag is found. Besides C<L<prefix|prefix> > you
+can also use C<L<suffix|suffix> >, 
+
+=head2 Processing just parts of an XML document
+
+The twig_roots mode builds only the required sub-trees from the document
+Anything outside of the twig roots will just be ignored:
+
+  my $t= XML::Twig->new( 
+       # the twig will include just the root and selected titles 
+           twig_roots   => { 'section/title' => \&print_n_purge,
+                             'annex/title'   => \&print_n_purge
+           }
+                      );
+  $t->parsefile( 'doc.xml');
+  
+  sub print_n_purge 
+    { my( $t, $elt)= @_;
+      print $elt->text;    # print the text (including sub-element texts)
+      $t->purge;           # frees the memory
+    }
+
+You can use that mode when you want to process parts of a documents but are
+not interested in the rest and you don't want to pay the price, either in
+time or memory, to build the tree for the it.
+
+
+=head2 Building an XML filter
+
+You can combine the C<twig_roots> and the C<twig_print_outside_roots> options to 
+build filters, which let you modify selected elements and will output the rest 
+of the document as is.
+
+This would convert prices in $ to prices in Euro in a document:
+
+  my $t= XML::Twig->new( 
+           twig_roots   => { 'price' => \&convert, },   # process prices 
+           twig_print_outside_roots => 1,               # print the rest
+                      );
+  $t->parsefile( 'doc.xml');
+ 
+  sub convert 
+    { my( $t, $price)= @_;
+      my $currency=  $price->{'att'}->{'currency'};          # get the currency
+      if( $currency eq 'USD')
+        { $usd_price= $price->text;                     # get the price
+          # %rate is just a conversion table 
+          my $euro_price= $usd_price * $rate{usd2euro};
+          $price->set_text( $euro_price);               # set the new price
+          $price->set_att( currency => 'EUR');          # don't forget this!
+        }
+      $price->print;                                    # output the price
+    }
+
+=head2 XML::Twig and various versions of Perl, XML::Parser and expat:
+
+Before being uploaded to CPAN, XML::Twig 3.14 has been tested under the 
+following environments:
+
+=over 4
+
+=item linux-x86
+
+perl 5.6.2 to 5.9.1, expat 1.95.2 to 1.95.7, XML::Parser 2.31, 2.33 and 2.34
+perl 5.6.2, XML::Parser 2.27 (which comes with its own version of expat)
+
+=item Mac OS X (10.2)
+
+Mac OS X: same as linux-x86, plus perl 5.5.4
+
+=item Solaris
+
+perl 5.6.1, expat 1.95.2, XML::Parser 2.31
+
+=item Windows 98
+
+perl 5.6.1 (Activestate build 635), XML::Parser 2.27
+perl 5.8.2 (Activestate build 808), XML::Parser 2.34
+
+Note that with Windows 98 and Perl 5.6.1 C<nmake> may freeze while trying to copy
+the tools (xml_grep, xml_print and xml_spellcheck), so you have to answer no 
+when asked if you want to install them.
+
+=back
+
+See L<http://testers.cpan.org/search?request=dist&dist=XML-Twig> for the
+CPAN testers reports on XML::Twig
+
+XML::Twig does B<NOT> work with expat 1.95.4
+XML::Twig only works with XML::Parser 2.27 in perl 5.6.*  
+XML::Parser 2.28 does not really work
+
+When in doubt, upgrade expat, XML::Parser and Scalar::Util
+
+=head1 Simplifying XML processing
+
+=over 4
+
+=item Whitespaces
+
+Whitespaces that look non-significant are discarded, this behaviour can be 
+controlled using the C<L<keep_spaces|keep_spaces> >, 
+C<L<keep_spaces_in|keep_spaces_in> > and 
+C<L<discard_spaces_in|discard_spaces_in> > options.
+
+=item Encoding
+
+You can specify that you want the output in the same encoding as the input
+(provided you have valid XML, which means you have to specify the encoding
+either in the document or when you create the Twig object) using the 
+C<L<keep_encoding|keep_encoding> > option
+
+You can also use C<L<output_encoding>> to convert the internal UTF-8 format
+to the required encoding.
+
+=item Comments and Processing Instructions (PI)
+
+Comments and PI's can be hidden from the processing, but still appear in the
+output (they are carried by the "real" element closer to them)
+
+=item Pretty Printing
+
+XML::Twig can output the document pretty printed so it is easier to read for
+us humans.
+
+=item Surviving an untimely death
+
+XML parsers are supposed to react violently when fed improper XML. 
+XML::Parser just dies.
+
+XML::Twig provides the C<L<safe_parse|safe_parse> > and the 
+C<L<safe_parsefile|safe_parsefile> > methods which wrap the parse in an eval
+and return either the parsed twig or 0 in case of failure.
+
+=item Private attributes
+
+Attributes with a name starting with # (illegal in XML) will not be
+output, so you can safely use them to store temporary values during
+processing. Note that you can store anything in a private attribute, 
+not just text, it's just a regular Perl variable, so a reference to
+an object or a huge data structure is perfectly fine.
+
+=back
+
+=head1 CLASSES
+
+XML::Twig uses a very limited number of classes. The ones you are most likely to use
+are C<L<XML::Twig>> of course, which represents a complete XML document, including the 
+document itself (the root of the document itself is C<L<root>>), its handlers, its
+input or output filters... The other main class is C<L<XML::Twig::Elt>>, which models 
+an XML element. Element here has a very wide definition: it can be a regular element, or
+but also text, with an element C<L<tag>> of C<#PCDATA> (or C<#CDATA>), an entity (tag is
+C<#ENT>), a Processing Instruction (C<#PI>), a comment (C<#COMMENT>). 
+
+Those are the 2 commonly used classes.
+
+You might want to look the C<L<elt_class>> option if you want to subclass C<XML::Twig::Elt>.
+
+Attributes are just attached to their parent element, they are not objects per se. (Please
+use the provided methods C<L<att>> and C<L<set_att>> to access them, if you access them
+as a hash, then your code becomes implementaion de[endant and might break in the future).
+
+Other classes that are seldom used are C<L<XML::Twig::Entity_list>> and C<L<XML::Twig::Entity>>.
+
+If you use C<L<XML::Twig::XPath>> instead of C<XML::Twig>, elements are then created as
+C<L<XML::Twig::XPath::Elt>>
+
+
+=head1 METHODS
+
+=head2 XML::Twig 
+
+A twig is a subclass of XML::Parser, so all XML::Parser methods can be
+called on a twig object, including parse and parsefile.
+C<setHandlers> on the other hand cannot be used, see C<L<BUGS|BUGS> >
+
+
+=over 4
+
+=item new 
+
+This is a class method, the constructor for XML::Twig. Options are passed
+as keyword value pairs. Recognized options are the same as XML::Parser,
+plus some XML::Twig specifics.
+
+New Options:
+
+=over 4
+
+=item twig_handlers
+
+This argument replaces the corresponding XML::Parser argument. It consists
+of a hash C<{ expression => \&handler}> where expression is a 
+I<generic_attribute_condition>, I<string_condition>,
+an I<attribute_condition>,I<full_path>, a I<partial_path>, a I<gi>,
+I<_default_> or I<_all_>.
+
+The idea is to support a usefull but efficient (thus limited) subset of
+XPATH. A fuller expression set will be supported in the future, as users
+ask for more and as I manage to implement it efficiently. This will never
+encompass all of XPATH due to the streaming nature of parsing (no lookahead
+after the element end tag).
+
+A B<generic_attribute_condition> is a condition on an attribute, in the form
+C<*[@att="val"]> or C<*[@att]>, simple quotes can be used instead of double 
+quotes and the leading '*' is actually optional. No matter what the gi of the
+element is, the handler will be triggered either if the attribute has the 
+specified value or if it just exists. 
+
+A B<string_condition> is a condition on the content of an element, in the form
+C<gi[string()="foo"]>, simple quotes can be used instead of double quotes, at 
+the moment you cannot escape the quotes (this will be added as soon as I
+dig out my copy of Mastering Regular Expressions from its storage box).
+The text returned is, as per what I (and Matt Sergeant!) understood from
+the XPATH spec the concatenation of all the text in the element, excluding
+all markup. Thus to call a handler on the elementC<< <p>text <b>bold</b></p> >>
+the appropriate condition is C<p[string()="text bold"]>. Note that this is not
+exactly conformant to the XPATH spec, it just tries to mimic it while being
+still quite concise. 
+
+A extension of that notation is C<gi[string(B<child_gi>)="foo"]> where the
+handler will be called if a child of a C<gi> element has a text value of 
+C<foo>.  At the moment only direct children of the C<gi> element are checked.
+If you need to test on descendants of the element let me know. The fix is
+trivial but would slow down the checks, so I'd like to keep it the way it is.
+
+A B<regexp_condition> is a condition on the content of an element, in the form
+C<gi[string()=~ /foo/"]>. This is the same as a string condition except that
+the text of the element is matched to the regexp. The C<i>, C<m>, C<s> and C<o>
+modifiers can be used on the regexp.
+
+The C<< gi[string(B<child_gi>)=~ /foo/"] >> extension is also supported.
+
+An B<attribute_condition> is a simple condition of an attribute of the
+current element in the form C<gi[@att="val"]> (simple quotes can be used
+instead of double quotes, you can escape quotes either). 
+If several attribute_condition are true the same element all the handlers
+can be called in turn (in the order in which they were first defined).
+If the C<="val"> part is ommited ( the condition is then C<gi[@att]>) then
+the handler is triggered if the attribute actually exists for the element,
+no matter what it's value is.
+
+A B<full_path> looks like C<'/doc/section/chapter/title'>, it starts with
+a / then gives all the gi's to the element. The handler will be called if
+the path to the current element (in the input document) is exactly as
+defined by the C<full_path>.
+
+A B<partial_path> is like a full_path except it does not start with a /:
+C<'chapter/title'> for example. The handler will be called if the path to
+the element (in the input document) ends as defined in the C<partial_path>.
+
+B<WARNING>: (hopefully temporary) at the moment C<string_condition>, 
+C<regexp_condition> and C<attribute_condition> are only supported on a 
+simple gi, not on a path.
+
+A B<gi> (generic identifier) is just a tag name.
+
+#CDATA can be used to call a handler for a CDATA.
+
+A special gi B<_all_> is used to call a function for each element.
+The special gi B<_default_> is used to call a handler for each element
+that does NOT have a specific handler.
+
+The order of precedence to trigger a handler is: 
+I<generic_attribute_condition>, I<string_condition>, I<regexp_condition>, 
+I<attribute_condition>, I<full_path>, longer I<partial_path>, shorter 
+I<partial_path>, I<gi>, I<_default_> . 
+
+B<Important>: once a handler has been triggered if it returns 0 then no other
+handler is called, exept a C<_all_> handler which will be called anyway.
+
+If a handler returns a true value and other handlers apply, then the next
+applicable handler will be called. Repeat, rince, lather..; The exception
+to that rule is when the C<L<do_not_chain_handlers|do_not_chain_handlers>>
+option is set, in which case only the first handler will be called.
+
+Note that it might be a good idea to explicitely return a short true value
+(like 1) from handlers: this ensures that other applicable handlers are 
+called even if the last statement for the handler happens to evaluate to
+false. This might also speedup the code by avoiding the result of the last 
+statement of the code to be copied and passed to the code managing handlers.
+It can really pay to have 1 instead of a long string returned.
+
+When an element is CLOSED the corresponding handler is called, with 2
+arguments: the twig and the C<L</Element|/Element> >. The twig includes the 
+document tree that has been built so far, the element is the complete sub-tree
+for the element. This means that handlers for inner elements are called before
+handlers for outer elements.
+
+C<$_> is also set to the element, so it is easy to write inline handlers like
+
+  para => sub { $_->change_gi( 'p'); }
+
+Text is stored in elements where gi is #PCDATA (due to mixed content, text
+and sub-element in an element there is no way to store the text as just an
+attribute of the enclosing element).
+
+B<Warning>: if you have used purge or flush on the twig the element might not
+be complete, some of its children might have been entirely flushed or purged,
+and the start tag might even have been printed (by C<flush>) already, so changing
+its gi might not give the expected result.
+
+More generally, the I<full_path>, I<partial_path> and I<gi> expressions are
+evaluated against the input document. Which means that even if you have changed
+the gi of an element (changing the gi of a parent element from a handler for
+example) the change will not impact the expression evaluation. Attributes in
+I<attribute_condition> are different though. As the initial value of attribute
+is not stored the handler will be triggered if the B<current> attribute/value
+pair is found when the element end tag is found. Although this can be quite
+confusing it should not impact most of users, and allow others to play clever
+tricks with temporary attributes. Let me know if this is a problem for you.
+
+
+=item twig_roots
+
+This argument let's you build the tree only for those elements you are
+interested in. 
+
+  Example: my $t= XML::Twig->new( twig_roots => { title => 1, subtitle => 1});
+           $t->parsefile( file);
+           my $t= XML::Twig->new( twig_roots => { 'section/title' => 1});
+           $t->parsefile( file);
+
+
+return a twig containing a document including only C<title> and C<subtitle> 
+elements, as children of the root element.
+
+You can use I<generic_attribute_condition>, I<attribute_condition>,
+I<full_path>, I<partial_path>, I<gi>, I<_default_> and I<_all_> to 
+trigger the building of the twig. 
+I<string_condition> and I<regexp_condition> cannot be used as the content 
+of the element, and the string, have not yet been parsed when the condition
+is checked.
+
+B<WARNING>: path are checked for the document. Even if the C<twig_roots> option
+is used they will be checked against the full document tree, not the virtual
+tree created by XML::Twig
+
+
+B<WARNING>: twig_roots elements should NOT be nested, that would hopelessly
+confuse XML::Twig ;--(
+
+Note: you can set handlers (twig_handlers) using twig_roots
+  Example: my $t= XML::Twig->new( twig_roots => 
+                                   { title    => sub { $_{1]->print;}, 
+                                     subtitle => \&process_subtitle 
+                                   }
+                               );
+           $t->parsefile( file);
+ 
+
+=item twig_print_outside_roots
+
+To be used in conjunction with the C<twig_roots> argument. When set to a true 
+value this will print the document outside of the C<twig_roots> elements.
+
+ Example: my $t= XML::Twig->new( twig_roots => { title => \&number_title },
+                                twig_print_outside_roots => 1,
+                               );
+           $t->parsefile( file);
+           { my $nb;
+           sub number_title
+             { my( $twig, $title);
+               $nb++;
+               $title->prefix( "$nb "; }
+               $title->print;
+             }
+           }
+               
+
+This example prints the document outside of the title element, calls 
+C<number_title> for each C<title> element, prints it, and then resumes printing
+the document. The twig is built only for the C<title> elements. 
+
+If the value is a reference to a file handle then the document outside the
+C<twig_roots> elements will be output to this file handle:
+
+  open( OUT, ">out_file") or die "cannot open out file out_file:$!";
+  my $t= XML::Twig->new( twig_roots => { title => \&number_title },
+                         # default output to OUT
+                         twig_print_outside_roots => \*OUT, 
+                       );
+
+         { my $nb;
+           sub number_title
+             { my( $twig, $title);
+               $nb++;
+               $title->prefix( "$nb "; }
+               $title->print( \*OUT);    # you have to print to \*OUT here
+             }
+           }
+
+
+=item start_tag_handlers
+
+A hash C<{ expression => \&handler}>. Sets element handlers that are called when
+the element is open (at the end of the XML::Parser C<Start> handler). The handlers
+are called with 2 params: the twig and the element. The element is empty at 
+that point, its attributes are created though. 
+
+You can use I<generic_attribute_condition>, I<attribute_condition>,
+I<full_path>, I<partial_path>, I<gi>, I<_default_>  and I<_all_> to trigger 
+the handler. 
+
+I<string_condition> and I<regexp_condition> cannot be used as the content of 
+the element, and the string, have not yet been parsed when the condition is 
+checked.
+
+The main uses for those handlers are to change the tag name (you might have to 
+do it as soon as you find the open tag if you plan to C<flush> the twig at some
+point in the element, and to create temporary attributes that will be used
+when processing sub-element with C<twig_hanlders>. 
+
+You should also use it to change tags if you use C<flush>. If you change the tag 
+in a regular C<twig_handler> then the start tag might already have been flushed. 
+
+B<Note>: C<start_tag> handlers can be called outside of C<twig_roots> if this 
+argument is used, in this case handlers are called with the following arguments:
+C<$t> (the twig), C<$gi> (the gi of the element) and C<%att> (a hash of the 
+attributes of the element). 
+
+If the C<twig_print_outside_roots> argument is also used then the start tag
+will be printed if the last handler called returns a C<true> value, if it
+does not then the start tag will B<not> be printed (so you can print a
+modified string yourself for example);
+
+Note that you can use the L<ignore|ignore> method in C<start_tag_handlers> 
+(and only there). 
+
+=item end_tag_handlers
+
+A hash C<{ expression => \&handler}>. Sets element handlers that are called when
+the element is closed (at the end of the XML::Parser C<End> handler). The handlers
+are called with 2 params: the twig and the gi of the element. 
+
+I<twig_handlers> are called when an element is completely parsed, so why have 
+this redundant option? There is only one use for C<end_tag_handlers>: when using
+the C<twig_roots> option, to trigger a handler for an element B<outside> the roots.
+It is for example very useful to number titles in a document using nested 
+sections: 
+
+  my @no= (0);
+  my $no;
+  my $t= XML::Twig->new( 
+          start_tag_handlers => 
+           { section => sub { $no[$#no]++; $no= join '.', @no; push @no, 0; } },
+          twig_roots         => 
+           { title   => sub { $_[1]->prefix( $no); $_[1]->print; } },
+          end_tag_handlers   => { section => sub { pop @no;  } },
+          twig_print_outside_roots => 1
+                      );
+   $t->parsefile( $file);
+
+Using the C<end_tag_handlers> argument without C<twig_roots> will result in an
+error.
+
+=item do_not_chain_handlers
+
+If this option is set to a true value, then only one handler will be called for
+each element, even if several satisfy the condition
+
+Note that the C<_all_> handler will still be called regardeless
+
+=item ignore_elts
+
+This option lets you ignore elements when building the twig. This is useful 
+in cases where you cannot use C<twig_roots> to ignore elements, for example if
+the element to ignore is a sibling of elements you are interested in.
+
+Example:
+
+  my $twig= XML::Twig->new( ignore_elts => { elt => 1 });
+  $twig->parsefile( 'doc.xml');
+
+This will build the complete twig for the document, except that all C<elt> 
+elements (and their children) will be left out.
+
+
+=item char_handler
+
+A reference to a subroutine that will be called every time C<PCDATA> is found.
+
+=item elt_class
+
+The name of a class used to store elements. this class should inherit from
+C<XML::Twig::Elt> (and by default it is C<XML::Twig::Elt>). This option is used
+to subclass the element class and extend it with new methods.
+
+This option is needed because during the parsing of the XML, elements are created
+by C<XML::Twig>, without any control from the user code.
+
+=item keep_atts_order
+
+Setting this option to a true value causes the attribute hash to be tied to
+a Tie::IxHash object.
+This means that Tie::IxHash needs to be installe for this option to be 
+available. It also means that the hash keeps its order, so you will get 
+the attributes in order. This allows outputing the attributes in the same 
+order as they were in the original document.
+
+=item keep_encoding
+
+This is a (slightly?) evil option: if the XML document is not UTF-8 encoded and
+you want to keep it that way, then setting keep_encoding will use theC<Expat> 
+original_string method for character, thus keeping the original encoding, as 
+well as the original entities in the strings.
+
+See the C<t/test6.t> test file to see what results you can expect from the 
+various encoding options.
+
+B<WARNING>: if the original encoding is multi-byte then attribute parsing will
+be EXTREMELY unsafe under any Perl before 5.6, as it uses regular expressions
+which do not deal properly with multi-byte characters. You can specify an 
+alternate function to parse the start tags with the C<parse_start_tag> option 
+(see below)
+
+B<WARNING>: this option is NOT used when parsing with the non-blocking parser 
+(C<parse_start>, C<parse_more>, parse_done methods) which you probably should 
+not use with XML::Twig anyway as they are totally untested!
+
+=item output_encoding
+
+This option generates an output_filter using C<Encode>,  C<Text::Iconv> or 
+C<Unicode::Map8> and C<Unicode::Strings>, and sets the encoding in the XML
+declaration. This is the easiest way to deal with encodings, if you need 
+more sophisticated features, look at C<output_filter> below
+
+
+=item output_filter
+
+This option is used to convert the character encoding of the output document.
+It is passed either a string corresponding to a predefined filter or
+a subroutine reference. The filter will be called every time a document or 
+element is processed by the "print" functions (C<print>, C<sprint>, C<flush>). 
+
+Pre-defined filters: 
+
+=over 4 
+
+=item latin1 
+
+uses either C<Encode>, C<Text::Iconv> or C<Unicode::Map8> and C<Unicode::String>
+or a regexp (which works only with XML::Parser 2.27), in this order, to convert 
+all characters to ISO-8859-1 (aka latin1)
+
+=item html
+
+does the same conversion as C<latin1>, plus encodes entities using
+C<HTML::Entities> (oddly enough you will need to have HTML::Entities intalled 
+for it to be available). This should only be used if the tags and attribute 
+names themselves are in US-ASCII, or they will be converted and the output will
+not be valid XML any more
+
+=item safe
+
+converts the output to ASCII (US) only  plus I<character entities> (C<&#nnn;>) 
+this should be used only if the tags and attribute names themselves are in 
+US-ASCII, or they will be converted and the output will not be valid XML any 
+more
+
+=item safe_hex
+
+same as C<safe> except that the character entities are in hexa (C<&#xnnn;>)
+
+=item encode_convert ($encoding)
+
+Return a subref that can be used to convert utf8 strings to C<$encoding>).
+Uses C<Encode>.
+
+   my $conv = XML::Twig::encode_convert( 'latin1');
+   my $t = XML::Twig->new(output_filter => $conv);
+
+=item iconv_convert ($encoding)
+
+this function is used to create a filter subroutine that will be used to 
+convert the characters to the target encoding using C<Text::Iconv> (which needs
+to be installed, look at the documentation for the module and for the
+C<iconv> library to find out which encodings are available on your system)
+
+   my $conv = XML::Twig::iconv_convert( 'latin1');
+   my $t = XML::Twig->new(output_filter => $conv);
+
+=item unicode_convert ($encoding)
+
+this function is used to create a filter subroutine that will be used to 
+convert the characters to the target encoding using  C<Unicode::Strings> 
+and C<Unicode::Map8> (which need to be installed, look at the documentation 
+for the modules to find out which encodings are available on your system)
+
+   my $conv = XML::Twig::unicode_convert( 'latin1');
+   my $t = XML::Twig->new(output_filter => $conv);
+
+=back
+
+The C<text> and C<att> methods do not use the filter, so their 
+result are always in unicode.
+
+Those predeclared filters are based on subroutines that can be used
+by themselves (as C<XML::Twig::foo>). 
+
+=over 4
+
+=item html_encode ($string)
+
+Use C<HTML::Entities> to encode a utf8 string
+
+=item safe_encode ($string)
+
+Use either a regexp (perl < 5.8) or C<Encode> to encode non-ascii characters
+in the string in C<< &#<nnnn>; >> format
+
+=item safe_encode_hex ($string)
+
+Use either a regexp (perl < 5.8) or C<Encode> to encode non-ascii characters
+in the string in C<< &#x<nnnn>; >> format
+
+=item regexp2latin1 ($string)
+
+Use a regexp to encode a utf8 string into latin 1 (ISO-8859-1). Does not
+work with Perl 5.8.0!
+
+=back
+
+=item output_text_filter
+
+same as output_filter, except it doesn't apply to the brackets and quotes 
+around attribute values. This is useful for all filters that could change
+the tagging, basically anything that does not just change the encoding of
+the output. C<html>, C<safe> and C<safe_hex> are better used with this option.
+
+=item input_filter
+
+This option is similar to C<output_filter> except the filter is applied to 
+the characters before they are stored in the twig, at parsing time.
+
+=item parse_start_tag
+
+If you use the C<keep_encoding> option then this option can be used to replace
+the default parsing function. You should provide a coderef (a reference to a 
+subroutine) as the argument, this subroutine takes the original tag (given
+by XML::Parser::Expat C<original_string()> method) and returns a gi and the
+attributes in a hash (or in a list attribute_name/attribute value).
+
+=item expand_external_ents
+
+When this option is used external entities (that are defined) are expanded
+when the document is output using "print" functions such as C<L<print> >,
+C<L<sprint|sprint> >, C<L<flush|flush> > and C<L<xml_string|xml_string> >. 
+Note that in the twig the entity will be stored as an element whith a 
+gi 'C<#ENT>', the entity will not be expanded there, so you might want to 
+process the entities before outputting it. 
+
+=item load_DTD
+
+If this argument is set to a true value, C<parse> or C<parsefile> on the twig
+will load  the DTD information. This information can then be accessed through 
+the twig, in a C<DTD_handler> for example. This will load even an external DTD.
+
+Note that to do this the module will generate a temporary file in the current
+directory. If this is a problem let me know and I will add an option to
+specify an alternate directory.
+
+See L<DTD Handling|DTD Handling> for more information
+
+=item DTD_handler
+
+Set a handler that will be called once the doctype (and the DTD) have been 
+loaded, with 2 arguments, the twig and the DTD.
+
+=item no_prolog
+
+Does not output a prolog (XML declaration and DTD)
+
+=item id
+
+This optional argument gives the name of an attribute that can be used as
+an ID in the document. Elements whose ID is known can be accessed through
+the elt_id method. id defaults to 'id'.
+See C<L<BUGS|BUGS> >
+
+=item discard_spaces
+
+If this optional argument is set to a true value then spaces are discarded
+when they look non-significant: strings containing only spaces are discarded.
+This argument is set to true by default.
+
+=item keep_spaces
+
+If this optional argument is set to a true value then all spaces in the
+document are kept, and stored as C<PCDATA>.
+C<keep_spaces> and C<discard_spaces> cannot be both set.
+
+=item discard_spaces_in
+
+This argument sets C<keep_spaces> to true but will cause the twig builder to
+discard spaces in the elements listed.
+
+The syntax for using this argument is:
+ 
+  XML::Twig->new( discard_spaces_in => [ 'elt1', 'elt2']);
+
+=item keep_spaces_in
+
+This argument sets C<discard_spaces> to true but will cause the twig builder to
+keep spaces in the elements listed.
+
+The syntax for using this argument is: 
+
+  XML::Twig->new( keep_spaces_in => [ 'elt1', 'elt2']);
+
+=item pretty_print
+
+Set the pretty print method, amongst 'C<none>' (default), 'C<nsgmls>', 
+'C<nice>', 'C<indented>', 'C<indented_c>', 'C<record>' and 'C<record_c>'
+
+pretty_print formats:
+
+=over 4
+
+=item none
+
+The document is output as one ling string, with no line breaks except those 
+found within text elements
+
+=item nsgmls
+
+Line breaks are inserted in safe places: that is within tags, between a tag 
+and an attribute, between attributes and before the > at the end of a tag.
+
+This is quite ugly but better than C<none>, and it is very safe, the document 
+will still be valid (conforming to its DTD).
+
+This is how the SGML parser C<sgmls> splits documents, hence the name.
+
+=item nice
+
+This option inserts line breaks before any tag that does not contain text (so
+element with textual content are not broken as the \n is the significant).
+
+B<WARNING>: this option leaves the document well-formed but might make it
+invalid (not conformant to its DTD). If you have elements declared as
+
+  <!ELEMENT foo (#PCDATA|bar)>
+
+then a C<foo> element including a C<bar> one will be printed as
+
+  <foo>
+  <bar>bar is just pcdata</bar>
+  </foo>
+
+This is invalid, as the parser will take the line break after the C<foo> tag 
+as a sign that the element contains PCDATA, it will then die when it finds the 
+C<bar> tag. This may or may not be important for you, but be aware of it!
+
+=item indented
+
+Same as C<nice> (and with the same warning) but indents elements according to 
+their level 
+
+=item indented_c
+
+Same as C<indented> but a little more compact: the closing tags are on the 
+same line as the preceeding text
+
+=item record
+
+This is a record-oriented pretty print, that display data in records, one field 
+per line (which looks a LOT like C<indented>)
+
+=item record_c
+
+Stands for record compact, one record per line
+
+=back
+
+
+=item empty_tags
+
+Set the empty tag display style ('C<normal>', 'C<html>' or 'C<expand>').
+
+=item comments
+
+Set the way comments are processed: 'C<drop>' (default), 'C<keep>' or 
+'C<process>' 
+
+Comments processing options:
+
+=over 4
+
+=item drop
+
+drops the comments, they are not read, nor printed to the output
+
+=item keep
+
+comments are loaded and will appear on the output, they are not 
+accessible within the twig and will not interfere with processing
+though
+
+B<Bug>: comments in the middle of a text element such as 
+
+  <p>text <!-- comment --> more text --></p>
+
+are output at the end of the text:
+
+  <p>text  more text <!-- comment --></p>
+
+=item process
+
+comments are loaded in the twig and will be treated as regular elements 
+(their C<gi> is C<#COMMENT>) this can interfere with processing if you
+expect C<< $elt->{first_child} >> to be an element but find a comment there.
+Validation will not protect you from this as comments can happen anywhere.
+You can use C<< $elt->first_child( 'gi') >> (which is a good habit anyway)
+to get where you want. 
+
+Consider using C<process> if you are outputing SAX events from XML::Twig.
+
+=back
+
+=item pi
+
+Set the way processing instructions are processed: 'C<drop>', 'C<keep>' 
+(default) or 'C<process>'
+
+Note that you can also set PI handlers in the C<twig_handlers> option: 
+
+  '?'       => \&handler
+  '?target' => \&handler 2
+
+The handlers will be called with 2 parameters, the twig and the PI element if
+C<pi> is set to C<process>, and with 3, the twig, the target and the data if
+C<pi> is set to C<keep>. Of course they will not be called if C<pi> is set to 
+C<drop>.
+
+If C<pi> is set to C<keep> the handler should return a string that will be used
+as-is as the PI text (it should look like "C< <?target data?> >" or '' if you
+want to remove the PI), 
+
+Only one handler will be called, C<?target> or C<?> if no specific handler for
+that target is available.
+
+=item map_xmlns 
+
+This option is passed a hashref that maps uri's to prefixes. The prefixes in
+the document will be replaced by the ones in the map. The mapped prefixes can
+(actually have to) be used to trigger handlers, navigate or query the document.
+
+Here is an example:
+
+  my $t= XML::Twig->new( map_xmlns => {'http://www.w3.org/2000/svg' => "svg"},
+                         twig_handlers => 
+                           { 'svg:circle' => sub { $_->set_att( r => 20) } },
+                         pretty_print => 'indented', 
+                       )
+                  ->parse( '<doc xmlns:gr="http://www.w3.org/2000/svg">
+                              <gr:circle cx="10" cy="90" r="10"/>
+                           </doc>'
+                         )
+                  ->print;
+
+This will output:
+
+  <doc xmlns:svg="http://www.w3.org/2000/svg">
+     <svg:circle cx="10" cy="90" r="20"/>
+  </doc>
+
+Note that this only works when working on the entire twig. If you use C<twig_roots>
+then the namespace processing is not done. I have to keep something to do for the
+next release ;--)
+
+
+=item keep_original_prefix
+
+When used with C<L<map_xmlns>> this option will make C<XML::Twig> use the original
+namespace prefixes when outputing a document. The mapped prefix will still be used
+for triggering handlers and in navigation and query methods.
+
+  my $t= XML::Twig->new( map_xmlns => {'http://www.w3.org/2000/svg' => "svg"},
+                         twig_handlers => 
+                           { 'svg:circle' => sub { $_->set_att( r => 20) } },
+                         keep_original_prefix => 1,
+                         pretty_print => 'indented', 
+                       )
+                  ->parse( '<doc xmlns:gr="http://www.w3.org/2000/svg">
+                              <gr:circle cx="10" cy="90" r="10"/>
+                           </doc>'
+                         )
+                  ->print;
+
+This will output:
+
+  <doc xmlns:gr="http://www.w3.org/2000/svg">
+     <gr:circle cx="10" cy="90" r="20"/>
+  </doc>
+
+=back
+
+B<Note>: I _HATE_ the Java-like name of arguments used by most XML modules.
+So in pure TIMTOWTDI fashion all arguments can be written either as
+C<UglyJavaLikeName> or as C<readable_perl_name>: C<twig_print_outside_roots>
+or C<TwigPrintOutsideRoots> (or even C<twigPrintOutsideRoots> {shudder}). 
+XML::Twig normalizes them before processing them.
+
+=item parse (SOURCE [, OPT => OPT_VALUE [...]])
+
+This method is inherited from XML::Parser.
+The C<SOURCE> parameter should either be a string containing the whole XML
+document, or it should be an open C<IO::Handle>. Constructor options to
+C<XML::Parser::Expat> given as keyword-value pairs may follow theC<SOURCE> 
+parameter. These override, for this call, any options or attributes passed
+through from the XML::Parser instance.
+
+A die call is thrown if a parse error occurs. Otherwise it will return 
+the twig built by the parse. Use C<safe_parse> if you want the parsing
+to return even when an error occurs.
+
+=item parsestring
+
+This is just an alias for C<parse> for backwards compatibility.
+
+=item parsefile (FILE [, OPT => OPT_VALUE [...]])
+
+This method is inherited from XML::Parser.
+
+Open C<FILE> for reading, then call C<parse> with the open handle. The file
+is closed no matter how C<parse> returns. 
+
+A C<die> call is thrown if a parse error occurs. Otherwise it will return 
+the twig built by the parse. Use C<safe_parsefile> if you want the parsing
+to return even when an error occurs.
+
+=item parseurl ($url $optional_user_agent)
+
+Gets the data from C<$url> and parse it. Note that the data is piped to the
+parser in chunks the size of the XML::Parser::Expat buffer, so memory 
+consumption and hopefully speed are optimal.
+
+If the C<$optional_user_agent> argument is used then it is used, otherwise a
+new one is created.
+
+=item safe_parse ( SOURCE [, OPT => OPT_VALUE [...]])
+
+This method is similar to C<parse> except that it wraps the parsing in an
+C<eval> block. It returns the twig on success and 0 on failure (the twig object
+also contains the parsed twig). C<$@> contains the error message on failure.
+
+Note that the parsing still stops as soon as an error is detected, there is
+no way to keep going after an error.
+
+=item safe_parsefile (FILE [, OPT => OPT_VALUE [...]])
+
+This method is similar to C<parsefile> except that it wraps the parsing in an
+C<eval> block. It returns the twig on success and 0 on failure (the twig object
+also contains the parsed twig) . C<$@> contains the error message on failure
+
+Note that the parsing still stops as soon as an error is detected, there is
+no way to keep going after an error.
+
+=item safe_parseurl ($url $optional_user_agent)
+
+Same as C<parseurl> except that it wraps the parsing in an C<eval> block. It 
+returns the twig on success and 0 on failure (the twig object also contains
+the parsed twig) . C<$@> contains the error message on failure
+
+=item parser
+
+This method returns the C<expat> object (actually the XML::Parser::Expat object) 
+used during parsing. It is useful for example to call XML::Parser::Expat methods
+on it. To get the line of a tag for example use C<< $t->parser->current_line >>.
+
+=item setTwigHandlers ($handlers)
+
+Set the twig_handlers. C<$handlers> is a reference to a hash similar to the
+one in the C<twig_handlers> option of new. All previous handlers are unset.
+The method returns the reference to the previous handlers.
+
+=item setTwigHandler ($exp $handler)
+
+Set a single twig_handler for elements matching C<$exp>. C<$handler> is a 
+reference to a subroutine. If the handler was previously set then the reference 
+to the previous handler is returned.
+
+=item setStartTagHandlers ($handlers)
+
+Set the start_tag handlers. C<$handlers> is a reference to a hash similar to the
+one in the C<start_tag_handlers> option of new. All previous handlers are unset.
+The method returns the reference to the previous handlers.
+
+=item setStartTagHandler ($exp $handler)
+
+Set a single start_tag handlers for elements matching C<$exp>. C<$handler> is a 
+reference to a subroutine. If the handler was previously set then the reference
+to the previous handler is returned.
+
+=item setEndTagHandlers ($handlers)
+
+Set the end_tag handlers. C<$handlers> is a reference to a hash similar to the
+one in the C<end_tag_handlers> option of new. All previous handlers are unset.
+The method returns the reference to the previous handlers.
+
+=item setEndTagHandler ($exp $handler)
+
+Set a single end_tag handlers for elements matching C<$exp>. C<$handler> is a 
+reference to a subroutine. If the handler was previously set then the 
+reference to the previous handler is returned.
+
+=item setTwigRoots ($handlers)
+
+Same as using the C<L<twig_roots>> option when creating the twig
+
+=item setCharHandler ($exp $handler)
+
+Set a C<char_handler>
+
+=item setIgnoreEltsHandler ($exp)
+
+Set a C<ignore_elt> handler (elements that match C<$exp> will be ignored
+
+=item setIgnoreEltsHandlers ($exp)
+
+Set all C<ignore_elt> handlers (previous handlers are replaced)
+
+=item dtd
+
+Return the dtd (an L<XML::Twig::DTD> object) of a twig
+
+=item xmldecl
+
+Return the XML declaration for the document, or a default one if it doesn't
+have one
+
+=item doctype
+
+Return the doctype for the document
+
+=item dtd_text
+
+Return the DTD text
+
+=item dtd_print
+
+Print the DTD
+
+=item model ($tag)
+
+Return the model (in the DTD) for the element C<$tag>
+
+=item root
+
+Return the root element of a twig
+
+=item set_root ($elt)
+
+Set the root of a twig
+
+=item first_elt ($optional_condition)
+
+Return the first element matching C<$optional_condition> of a twig, if
+no condition is given then the root is returned
+
+=item elt_id        ($id)
+
+Return the element whose C<id> attribute is $id
+
+=item getEltById
+
+Same as C<L<elt_id>>
+
+=item encoding
+
+This method returns the encoding of the XML document, as defined by the 
+C<encoding> attribute in the XML declaration (ie it is C<undef> if the attribute
+is not defined)
+
+=item set_encoding
+
+This method sets the value of the C<encoding> attribute in the XML declaration. 
+Note that if the document did not have a declaration it is generated (with
+an XML version of 1.0)
+
+=item xml_version
+
+This method returns the XML version, as defined by the C<version> attribute in 
+the XML declaration (ie it is C<undef> if the attribute is not defined)
+
+=item set_xml_version
+
+This method sets the value of the C<version> attribute in the XML declaration. 
+If the declaration did not exist it is created.
+
+=item standalone
+
+This method returns the value of the C<standalone> declaration for the document
+
+=item set_standalone
+
+This method sets the value of the C<standalone> attribute in the XML 
+declaration.  Note that if the document did not have a declaration it is 
+generated (with an XML version of 1.0)
+
+=item set_output_encoding
+
+Set the C<encoding> "attribute" in the XML declaration
+
+=item set_doctype ($name, $system, $public, $internal)
+
+Set the doctype of the element. If an argument is C<undef> (or not present)
+then its former value is retained, if a false ('' or 0) value is passed then
+the former value is deleted;
+
+=item entity_list
+
+Return the entity list of a twig
+
+=item entity_names
+
+Return the list of all defined entities
+
+=item entity ($entity_name)
+
+Return the entity 
+
+=item change_gi      ($old_gi, $new_gi)
+
+Performs a (very fast) global change. All elements C<$old_gi> are now 
+C<$new_gi>.
+
+See C<L<BUGS|BUGS> >
+
+=item flush            ($optional_filehandle, $options)
+
+Flushes a twig up to (and including) the current element, then deletes
+all unnecessary elements from the tree that's kept in memory.
+C<flush> keeps track of which elements need to be open/closed, so if you
+flush from handlers you don't have to worry about anything. Just keep 
+flushing the twig every time you're done with a sub-tree and it will
+come out well-formed. After the whole parsing don't forget toC<flush> 
+one more time to print the end of the document.
+The doctype and entity declarations are also printed.
+
+flush take an optional filehandle as an argument.
+
+options: use the C<update_DTD> option if you have updated the (internal) DTD 
+and/or the entity list and you want the updated DTD to be output 
+
+The C<pretty_print> option sets the pretty printing of the document.
+
+   Example: $t->flush( Update_DTD => 1);
+            $t->flush( \*FILE, Update_DTD => 1);
+            $t->flush( \*FILE);
+
+
+=item flush_up_to ($elt, $optional_filehandle, %options)
+
+Flushes up to the C<$elt> element. This allows you to keep part of the
+tree in memory when you C<flush>.
+
+options: see flush.
+
+=item purge
+
+Does the same as a C<flush> except it does not print the twig. It just deletes
+all elements that have been completely parsed so far.
+
+=item purge_up_to ($elt)
+
+Purges up to the C<$elt> element. This allows you to keep part of the tree in 
+memory when you C<purge>.
+
+=item print            ($optional_filehandle, %options)
+
+Prints the whole document associated with the twig. To be used only AFTER the
+parse.
+ 
+options: see C<flush>.
+
+=item sprint
+
+Return the text of the whole document associated with the twig. To be used only
+AFTER the parse.
+
+options: see C<flush>.
+
+=item toSAX1 ($handler)
+
+Send SAX events for the twig to the SAX1 handler C<$handler>
+
+=item toSAX2 ($handler)
+
+Send SAX events for the twig to the SAX2 handler C<$handler>
+
+=item flush_toSAX1 ($handler)
+
+Same as flush, except that SAX events are sent to the SAX1 handler
+C<$handler> instead of the twig being printed
+
+=item flush_toSAX2 ($handler)
+
+Same as flush, except that SAX events are sent to the SAX2 handler
+C<$handler> instead of the twig being printed
+
+=item ignore
+
+This method can B<only> be called in C<start_tag_handlers>. It causes the 
+element to be skipped during the parsing: the twig is not built for this 
+element, it will not be accessible during parsing or after it. The element 
+will not take up any memory and parsing will be faster.
+
+Note that this method can also be called on an element. If the element is a 
+parent of the current element then this element will be ignored (the twig will
+not be built any more for it and what has already been built will be deleted)
+
+
+=item set_pretty_print  ($style)
+
+Set the pretty print method, amongst 'C<none>' (default), 'C<nsgmls>', 
+'C<nice>', 'C<indented>', 'C<record>' and 'C<record_c>'
+
+B<WARNING:> the pretty print style is a B<GLOBAL> variable, so once set it's
+applied to B<ALL> C<print>'s (and C<sprint>'s). Same goes if you use XML::Twig
+with C<mod_perl> . This should not be a problem as the XML that's generated 
+is valid anyway, and XML processors (as well as HTML processors, including
+browsers) should not care. Let me know if this is a big problem, but at the
+moment the performance/cleanliness trade-off clearly favors the global 
+approach.
+
+=item set_empty_tag_style  ($style)
+
+Set the empty tag display style ('C<normal>', 'C<html>' or 'C<expand>'). As 
+with C<L<set_pretty_print>> this sets a global flag.  
+
+C<normal> outputs an empty tag 'C<< <tag/> >>', C<html> adds a space 
+'C<< <tag /> >>' and C<expand> outputs 'C<< <tag></tag> >>'
+
+=item print_prolog     ($optional_filehandle, %options)
+
+Prints the prolog (XML declaration + DTD + entity declarations) of a document.
+
+options: see C<L<flush>>.
+
+=item prolog     ($optional_filehandle, %options)
+
+Return the prolog (XML declaration + DTD + entity declarations) of a document.
+
+options: see C<L<flush>>.
+
+=item finish
+
+Call Expat C<finish> method.
+Unsets all handlers (including internal ones that set context), but expat
+continues parsing to the end of the document or until it finds an error.
+It should finish up a lot faster than with the handlers set.
+
+=item finish_print
+
+Stop twig processing, flush the twig and proceed to finish printing the 
+document as fast as possible. Use this method when modifying a document and 
+the modification is done. 
+
+=item set_expand_external_entities
+
+Same as using the C<L<expand_external_ents>> option when creating the twig
+
+=item set_input_filter
+
+Same as using the C<L<input_filter>> option when creating the twig
+
+=item set_keep_atts_order
+
+Same as using the C<L<keep_atts_order>> option when creating the twig
+
+=item set_keep_encoding
+
+Same as using the C<L<keep_encoding>> option when creating the twig
+
+=item set_output_filter
+
+Same as using the C<L<output_filter>> option when creating the twig
+
+=item set_output_text_filter
+
+Same as using the C<L<output_text_filter>> option when creating the twig
+
+=item Methods inherited from XML::Parser::Expat
+
+A twig inherits all the relevant methods from XML::Parser::Expat. These 
+methods can only be used during the parsing phase (they will generate
+a fatal error otherwise).
+
+Inherited methods are:
+
+=over 4
+
+=item depth
+
+Returns the size of the context list.
+
+=item in_element
+
+Returns true if NAME is equal to the name of the innermost curâ
+rently opened element. If namespace processing is being used and
+you want to check against a name that may be in a namespace, then
+use the generate_ns_name method to create the NAME argument.
+
+=item within_element
+
+Returns the number of times the given name appears in the context
+list.  If namespace processing is being used and you want to check
+against a name that may be in a namespace, then use the generâ
+ate_ns_name method to create the NAME argument.
+
+=item context
+
+Returns a list of element names that represent open elements, with
+the last one being the innermost. Inside start and end tag hanâ
+dlers, this will be the tag of the parent element.
+
+=item current_line
+
+Returns the line number of the current position of the parse.
+
+=item current_column
+
+Returns the column number of the current position of the parse.
+
+=item current_byte
+
+Returns the current position of the parse.
+
+=item position_in_context
+
+Returns a string that shows the current parse position. LINES
+should be an integer >= 0 that represents the number of lines on
+either side of the current parse line to place into the returned
+string.
+
+=item base ([NEWBASE])
+
+Returns the current value of the base for resolving relative URIs.
+If NEWBASE is supplied, changes the base to that value.
+
+=item current_element
+
+Returns the name of the innermost currently opened element. Inside
+start or end handlers, returns the parent of the element associated
+with those tags.
+
+=item element_index
+
+Returns an integer that is the depth-first visit order of the curâ
+rent element. This will be zero outside of the root element. For
+example, this will return 1 when called from the start handler for
+the root element start tag.
+
+=item recognized_string
+
+Returns the string from the document that was recognized in order
+to call the current handler. For instance, when called from a start
+handler, it will give us the the start-tag string. The string is
+encoded in UTF-8.  This method doesn't return a meaningful string
+inside declaration handlers.
+
+=item original_string
+
+Returns the verbatim string from the document that was recognized
+in order to call the current handler. The string is in the original
+document encoding. This method doesn't return a meaningful string
+inside declaration handlers.
+
+=item xpcroak
+
+Concatenate onto the given message the current line number within
+the XML document plus the message implied by ErrorContext. Then
+croak with the formed message.
+
+=item xpcarp 
+
+Concatenate onto the given message the current line number within
+the XML document plus the message implied by ErrorContext. Then
+carp with the formed message.
+
+=item xml_escape(TEXT [, CHAR [, CHAR ...]])
+
+Returns TEXT with markup characters turned into character entities.
+Any additional characters provided as arguments are also turned
+into character references where found in TEXT.
+
+(this method is broken on some versions of expat/XML::Parser)
+
+=back
+
+=item path ($gi)
+
+Return the element context in a form similar to XPath's short
+form: 'C</root/gi1/../gi>'
+
+=item get_xpath  ( $optional_array_ref, $xpath, $optional_offset)
+
+Performs a C<get_xpath> on the document root (see <Elt|"Elt">)
+
+If the C<$optional_array_ref> argument is used the array must contain
+elements. The C<$xpath> expression is applied to each element in turn 
+and the result is union of all results. This way a first query can be
+refined in further steps.
+
+
+=item find_nodes ( $optional_array_ref, $xpath, $optional_offset)
+
+same as C<get_xpath> 
+
+=item findnodes ( $optional_array_ref, $xpath, $optional_offset)
+
+same as C<get_xpath> (similar to the XML::LibXML method)
+
+=item findvalue ( $optional_array_ref, $xpath, $optional_offset)
+
+Return the C<join> of all texts of the results of appling C<L<get_xpath>>
+to the node (similar to the XML::LibXML method)
+
+=item subs_text ($regexp, $replace)
+
+subs_text does text substitution on the whole document, similar to perl's 
+C< s///> operator.
+
+=item dispose
+
+Useful only if you don't have C<Scalar::Util> or C<WeakRef> installed.
+
+Reclaims properly the memory used by an XML::Twig object. As the object has
+circular references it never goes out of scope, so if you want to parse lots 
+of XML documents then the memory leak becomes a problem. Use
+C<< $twig->dispose >> to clear this problem.
+
+=back 
+
+
+=head2 XML::Twig::Elt
+
+=over 4
+
+=item new          ($optional_gi, $optional_atts, @optional_content)
+
+The C<gi> is optional (but then you can't have a content ), the C<$optional_atts> 
+argument is a refreference to a hash of attributes, the content can be just a 
+string or a list of strings and element. A content of 'C<#EMPTY>' creates an empty 
+element;
+
+ Examples: my $elt= XML::Twig::Elt->new();
+           my $elt= XML::Twig::Elt->new( para => { align => 'center' });  
+           my $elt= XML::Twig::Elt->new( para => { align => 'center' }, 'foo');  
+           my $elt= XML::Twig::Elt->new( br   => '#EMPTY');
+           my $elt= XML::Twig::Elt->new( 'para');
+           my $elt= XML::Twig::Elt->new( para => 'this is a para');  
+           my $elt= XML::Twig::Elt->new( para => $elt3, 'another para'); 
+
+The strings are not parsed, the element is not attached to any twig.
+
+B<WARNING>: if you rely on ID's then you will have to set the id yourself. At
+this point the element does not belong to a twig yet, so the ID attribute
+is not known so it won't be strored in the ID list.
+
+Note that C<#COMMENT>, C<#PCDATA> or C<#CDATA> are valid tag names, that will 
+create text elements.
+
+To create an element C<foo> containing a CDATA section:
+
+           my $foo= XML::Twig::Elt->new( '#CDATA' => "content of the CDATA section")
+                                  ->wrap_in( 'foo');
+
+=item parse         ($string, %args)
+
+Creates an element from an XML string. The string is actually
+parsed as a new twig, then the root of that twig is returned.
+The arguments in C<%args> are passed to the twig.
+As always if the parse fails the parser will die, so use an
+eval if you want to trap syntax errors.
+
+As obviously the element does not exist beforehand this method has to be 
+called on the class: 
+
+  my $elt= parse XML::Twig::Elt( "<a> string to parse, with <sub/>
+                                  <elements>, actually tons of </elements>
+                  h</a>");
+
+=item print         ($optional_filehandle, $optional_pretty_print_style)
+
+Prints an entire element, including the tags, optionally to a 
+C<$optional_filehandle>, optionally with a C<$pretty_print_style>.
+
+The print outputs XML data so base entities are escaped.
+
+=item sprint       ($elt, $optional_no_enclosing_tag)
+
+Return the xml string for an entire element, including the tags. 
+If the optional second argument is true then only the string inside the 
+element is returned (the start and end tag for $elt are not).
+The text is XML-escaped: base entities (& and < in text, & < and " in
+attribute values) are turned into entities.
+
+=item gi                       
+
+Return the gi of the element (the gi is the C<generic identifier> the tag
+name in SGML parlance).
+
+C<tag> and C<name> are synonyms of C<gi>.
+
+=item tag
+
+Same as C<L<gi|gi>>
+
+=item name
+
+Same as C<L<gi|gi>>
+
+=item set_gi         ($gi)
+
+Set the gi (tag) of an element
+
+=item set_tag        ($tag)
+
+Set the tag (=C<L<gi|gi>>) of an element
+
+=item set_name       ($name)
+
+Set the name (=C<L<gi|gi>>) of an element
+
+=item root 
+
+Return the root of the twig in which the element is contained.
+
+=item twig 
+
+Return the twig containing the element. 
+
+=item parent        ($optional_condition)
+
+Return the parent of the element, or the first ancestor matching the 
+C<$optional_condition>
+
+=item first_child   ($optional_condition)
+
+Return the first child of the element, or the first child matching the 
+C<$optional_condition>
+
+=item has_child ($optional_condition)
+
+Return the first child of the element, or the first child matching the 
+C<$optional_condition> (same as L<first_child>)
+
+=item has_children ($optional_condition)
+
+Return the first child of the element, or the first child matching the 
+C<$optional_condition> (same as L<first_child>)
+
+
+=item first_child_text   ($optional_condition)
+
+Return the text of the first child of the element, or the first child
+ matching the C<$optional_condition>
+If there is no first_child then returns ''. This avoids getting the
+child, checking for its existence then getting the text for trivial cases.
+
+Similar methods are available for the other navigation methods: 
+
+=over 4
+
+=item last_child_text
+
+=item prev_sibling_text
+
+=item next_sibling_text
+
+=item prev_elt_text
+
+=item next_elt_text
+
+=item child_text
+
+=item parent_text
+
+=back
+
+All this methods also exist in "trimmed" variant: 
+
+=over 4
+
+=item first_child_trimmed_text
+
+=item last_child_trimmed_text
+
+=item prev_sibling_trimmed_text
+
+=item next_sibling_trimmed_text
+
+=item prev_elt_trimmed_text
+
+=item next_elt_trimmed_text
+
+=item child_trimmed_text
+
+=item parent_trimmed_text
+
+=back
+
+=item field         ($optional_condition)
+
+Same method as C<first_child_text> with a different name
+
+=item trimmed_field         ($optional_condition)
+
+Same method as C<first_child_trimmed_text> with a different name
+
+=item set_field ($condition, $optional_atts, @list_of_elt_and_strings)
+
+Set the content of the first child of the element that matches
+C<$condition>, the rest of the arguments is tha same as for C<L<set_content>>
+
+If no child matches C<$condition> _and_ if C<$condition> is a valid
+XML element name, then a new element by that name is created and 
+inserted as the last child.
+
+=item first_child_matches   ($optional_condition)
+
+Return the element if the first child of the element (if it exists) passes
+the C<$optional_condition> C<undef> otherwise
+
+  if( $elt->first_child_matches( 'title')) ... 
+
+is equivalent to
+
+  if( $elt->{first_child} && $elt->{first_child}->passes( 'title')) 
+
+C<first_child_is> is an other name for this method
+
+Similar methods are available for the other navigation methods: 
+
+=over 4
+
+=item last_child_matches
+
+=item prev_sibling_matches
+
+=item next_sibling_matches
+
+=item prev_elt_matches
+
+=item next_elt_matches
+
+=item child_matches
+
+=item parent_matches
+
+=back
+
+=item is_first_child ($optional_condition)
+
+returns true (the element) if the element is the first child of its parent
+(optionaly that satisfies the C<$optional_condition>)
+
+=item is_last_child ($optional_condition)
+
+returns true (the element) if the element is the first child of its parent
+(optionaly that satisfies the C<$optional_condition>)
+
+=item prev_sibling  ($optional_condition)
+
+Return the previous sibling of the element, or the previous sibling matching
+C<$optional_condition>
+
+=item next_sibling  ($optional_condition)
+
+Return the next sibling of the element, or the first one matching 
+C<$optional_condition>.
+
+=item next_elt     ($optional_elt, $optional_condition)
+
+Return the next elt (optionally matching C<$optional_condition>) of the element. This 
+is defined as the next element which opens after the current element opens.
+Which usually means the first child of the element.
+Counter-intuitive as it might look this allows you to loop through the
+whole document by starting from the root.
+
+The C<$optional_elt> is the root of a subtree. When the C<next_elt> is out of the
+subtree then the method returns undef. You can then walk a sub tree with:
+
+  my $elt= $subtree_root;
+  while( $elt= $elt->next_elt( $subtree_root)
+    { # insert processing code here
+    }
+
+=item prev_elt     ($optional_condition)
+
+Return the previous elt (optionally matching C<$optional_condition>) of the
+element. This is the first element which opens before the current one.
+It is usually either the last descendant of the previous sibling or
+simply the parent
+
+=item next_n_elt   ($offset, $optional_condition)
+
+Return the C<$offset>-th element that matches the C<$optional_condition> 
+
+=item children     ($optional_condition)
+
+Return the list of children (optionally which matches C<$optional_condition>) of 
+the element. The list is in document order.
+
+=item children_count ($optional_condition)
+
+Return the number of children of the element (optionally which matches 
+C<$optional_condition>)
+
+=item children_text ($optional_condition)
+
+Return an array containing the text of children of the element (optionally 
+which matches C<$optional_condition>)
+
+=item children_copy ($optional_condition)
+
+Return a list of elements that are copies of the children of the element, 
+optionally which matches C<$optional_condition>
+
+=item descendants     ($optional_condition)
+
+Return the list of all descendants (optionally which matches 
+C<$optional_condition>) of the element. This is the equivalent of the 
+C<getElementsByTagName> of the DOM (by the way, if you are really a DOM 
+addict, you can use C<getElementsByTagName> instead)
+
+=item getElementsByTagName ($optional_condition)
+
+Same as C<L<descendants>>
+
+=item find_by_tag_name ($optional_condition)
+
+Same as C<L<descendants>>
+
+=item descendants_or_self ($optional_condition)
+
+Same as C<L<descendants>> except that the element itself is included in the list
+if it matches the C<$optional_condition> 
+
+=item ancestors    ($optional_condition)
+
+Return the list of ancestors (optionally matching C<$optional_condition>) of the 
+element.  The list is ordered from the innermost ancestor to the outtermost one
+
+NOTE: the element itself is not part of the list, in order to include it 
+you will have to use ancestors_or_self
+
+=item ancestors_or_self     ($optional_condition)
+
+Return the list of ancestors (optionally matching C<$optional_condition>) of the 
+element, including the element (if it matches the condition>).  
+The list is ordered from the innermost ancestor to the outtermost one
+
+=item passes ($condition)
+
+Return the element if it passes the C<$condition> 
+
+=item att          ($att)
+
+Return the value of attribute C<$att> or C<undef>
+
+=item set_att      ($att, $att_value)
+
+Set the attribute of the element to the given value
+
+You can actually set several attributes this way:
+
+  $elt->set_att( att1 => "val1", att2 => "val2");
+
+=item del_att      ($att)
+
+Delete the attribute for the element
+
+You can actually delete several attributes at once:
+
+  $elt->del_att( 'att1', 'att2', 'att3');
+
+=item cut
+
+Cut the element from the tree. The element still exists, it can be copied
+or pasted somewhere else, it is just not attached to the tree anymore.
+
+=item cut_children ($optional_condition)
+
+Cut all the children of the element (or all of those which satisfy the
+C<$optional_condition>).
+
+Return the list of children 
+
+=item copy        ($elt)
+
+Return a copy of the element. The copy is a "deep" copy: all sub elements of 
+the element are duplicated.
+
+=item paste       ($optional_position, $ref)
+
+Paste a (previously C<cut> or newly generated) element. Die if the element
+already belongs to a tree.
+
+The element is pasted 
+
+Example:
+
+  my $t= XML::Twig->new->parse( 'doc.xml')
+  my $toc= $t->root->new( 'toc');
+  $toc->paste( $t->root); # $toc is pasted as first child of the root 
+  foreach my $title ($t->findnodes( '/doc/section/title'))
+    { my $title_toc= $title->copy;
+      # paste $title_toc as the last child of toc
+      $title_toc->paste( last_child => $toc) 
+    }
+
+Position options:
+
+=over 4
+
+=item first_child (default)
+
+The element is pasted as the first child of C<$ref>
+
+=item last_child
+
+The element is pasted as the last child of C<$ref>
+
+=item before
+
+The element is pasted before C<$ref>, as its previous sibling.
+
+=item after
+
+The element is pasted after C<$ref>, as its next sibling.
+
+=item within
+
+In this case an extra argument, C<$offset>, should be supplied. The element
+will be pasted in the reference element (or in its first text child) at the
+given offset. To achieve this the reference element will be split at the 
+offset.
+
+=back
+
+Note that you can call directly the underlying method:
+
+=over 4
+
+=item paste_before
+
+=item paste_after
+
+=item paste_first_child
+
+=item paste_last_child
+
+=item paste_within
+
+=back
+
+=item move       ($optional_position, $ref)
+
+Move an element in the tree.
+This is just a C<cut> then a C<paste>.  The syntax is the same as C<paste>.
+
+=item replace       ($ref)
+
+Replaces an element in the tree. Sometimes it is just not possible toC<cut> 
+an element then C<paste> another in its place, so C<replace> comes in handy.
+The calling element replaces C<$ref>.
+
+=item replace_with   (@elts)
+
+Replaces the calling element with one or more elements 
+
+=item delete
+
+Cut the element and frees the memory.
+
+=item prefix       ($text, $optional_option)
+
+Add a prefix to an element. If the element is a C<PCDATA> element the text
+is added to the pcdata, if the elements first child is a C<PCDATA> then the
+text is added to it's pcdata, otherwise a new C<PCDATA> element is created 
+and pasted as the first child of the element.
+
+If the option is C<asis> then the prefix is added asis: it is created in
+a separate C<PCDATA> element with an C<asis> property. You can then write:
+
+  $elt1->prefix( '<b>', 'asis');
+
+to create a C<< <b> >> in the output of C<print>.
+
+=item suffix       ($text, $optional_option)
+
+Add a suffix to an element. If the element is a C<PCDATA> element the text
+is added to the pcdata, if the elements last child is a C<PCDATA> then the
+text is added to it's pcdata, otherwise a new PCDATA element is created 
+and pasted as the last child of the element.
+
+If the option is C<asis> then the suffix is added asis: it is created in
+a separate C<PCDATA> element with an C<asis> property. You can then write:
+
+  $elt2->suffix( '</b>', 'asis');
+
+=item simplify (%options)
+
+Return a data structure suspiciously similar to XML::Simple's. Options are
+identical to XMLin options, see XML::Simple doc for more details (or use
+DATA::dumper or YAML to dump the data structure)
+
+=over 4
+
+=item keyattr 
+
+=item forcearray 
+
+=item noattr 
+
+=item content_key
+                             
+=item variables (%var_hash)
+
+%var_hash is a hash { name => value }
+
+This option allows variables in the XML to be expanded when the file is read. (there is no facility for putting the variable names back if you regenerate XML using XMLout).
+
+A 'variable' is any text of the form ${name} (or $name) which occurs in an attribute value or in the text content of an element. If 'name' matches a key in the supplied hashref, ${name} will be replaced with the corresponding value from the hashref. If no matching key is found, the variable will not be replaced. 
+
+=item var_att ($attribute_name)
+
+This option gives the name of an attribute that will be used to create 
+variables in the XML:
+
+  <dirs>
+    <dir name="prefix">/usr/local</dir>
+    <dir name="exec_prefix">$prefix/bin</dir>
+  </dirs>
+
+use C<< var => 'name' >> to get $prefix replaced by /usr/local in the
+generated data structure  
+
+By default variables are captured by the following regexp: /$(\w+)/
+    
+=item var_regexp (regexp)
+
+This option changes the regexp used to capture variables. The variable
+name should be in $1
+
+=item group_tags ([<tag1>, <tag2>...])
+
+Option used to simplify the structure: elements listed will not be used.
+Their children will be, they will be considered children of the element
+parent.
+
+If the element is:
+
+  <config host="laptop.xmltwig.com">
+    <server>localhost</server>
+    <dirs>
+      <dir name="base">/home/mrodrigu/standards</dir>
+      <dir name="tools">$base/tools</dir>
+    </dirs>
+    <templates>
+      <template name="std_def">std_def.templ</template>
+      <template name="dummy">dummy</template>
+    </templates>
+  </config>
+
+Then callin simplify with C<< erase => [ 'dirs', 'templates'] >> makes the
+data structure be exactly as if the start and end tags for C<dirs> and
+C<templates> were not there.
+
+A YAML dump of the structure 
+
+  base: '/home/mrodrigu/standards'
+  host: laptop.xmltwig.com
+  server: localhost
+  template:
+    - std_def.templ
+    - dummy.templ
+  tools: '$base/tools'
+
+
+=back
+
+=item split_at        ($offset)
+
+Split a text (C<PCDATA> or C<CDATA>) element in 2 at C<$offset>, the original
+element now holds the first part of the string and a new element holds the
+right part. The new element is returned
+
+If the element is not a text element then the first text child of the element
+is split
+
+=item split        ( $optional_regexp, $optional_tag, $optional_attribute_ref)
+
+Split the text descendants of an element in place, the text is split using 
+the regexp, if the regexp includes () then the matched separators will be 
+wrapped in C<$optional_tag>, with C<$optional_attribute_ref> attributes
+
+if $elt is C<< <p>tati tata <b>tutu tati titi</b> tata tati tata</p> >>
+
+  $elt->split( qr/(ta)ti/, 'foo', {type => 'toto'} )
+
+will change $elt to
+
+  <p><foo type="toto">ta</foo> tata <b>tutu <foo type="toto">ta</foo>
+      titi</b> tata <foo type="toto">ta</foo> tata</p> 
+
+The regexp can be passed either as a string or as C<qr//> (perl 5.005 and 
+later), it defaults to \s+ just as the C<split> built-in (but this would be 
+quite a useless behaviour without the C<$optional_tag> parameter)
+
+C<$optional_tag> defaults to PCDATA or CDATA, depending on the initial element
+type
+
+The list of descendants is returned (including un-touched original elements 
+and newly created ones)
+
+=item mark        ( $regexp, $optional_tag, $optional_attribute_ref)
+
+This method behaves exactly as L<split|split>, except only the newly created 
+elements are returned
+
+=item wrap_children ( $regexp_string, $tag, $optional_att, $optional_value)
+
+Wrap the children of the element that match the regexp in an element C<$tag>.
+If C<$optional_att> and C<$optional_value> are passed then the new element will
+have an attribute C<$optional_att> with a value C<$optional_value>.
+
+Note that elements might get extra C<id> attributes in the process. See L<add_id>.
+Use L<strip_att> to remove unwanted id's. 
+
+Here is an example:
+
+If the element C<$elt> has the following content:
+
+  <elt>
+   <p>para 1</p>
+   <l_l1_1>list 1 item 1 para 1</l_l1_1>
+     <l_l1>list 1 item 1 para 2</l_l1>
+   <l_l1_n>list 1 item 2 para 1 (only para)</l_l1_n>
+   <l_l1_n>list 1 item 3 para 1</l_l1_n>
+     <l_l1>list 1 item 3 para 2</l_l1>
+     <l_l1>list 1 item 3 para 3</l_l1>
+   <l_l1_1>list 2 item 1 para 1</l_l1_1>
+     <l_l1>list 2 item 1 para 2</l_l1>
+   <l_l1_n>list 2 item 2 para 1 (only para)</l_l1_n>
+   <l_l1_n>list 2 item 3 para 1</l_l1_n>
+     <l_l1>list 2 item 3 para 2</l_l1>
+     <l_l1>list 2 item 3 para 3</l_l1>
+  </elt>
+
+Then the code
+
+  $elt->wrap_children( q{<l_l1_1><l_l1>*} , li => { type => "ul1" });
+  $elt->wrap_children( q{<l_l1_n><l_l1>*} , li => { type => "ul" });
+
+  $elt->wrap_children( q{<li type="ul1"><li type="ul">+}, "ul");
+  $elt->strip_att( 'id');
+  $elt->strip_att( 'type');
+  $elt->print;
+
+will output:
+
+  <elt>
+     <p>para 1</p>
+     <ul>
+       <li>
+         <l_l1_1>list 1 item 1 para 1</l_l1_1>
+         <l_l1>list 1 item 1 para 2</l_l1>
+       </li>
+       <li>
+         <l_l1_n>list 1 item 2 para 1 (only para)</l_l1_n>
+       </li>
+       <li>
+         <l_l1_n>list 1 item 3 para 1</l_l1_n>
+         <l_l1>list 1 item 3 para 2</l_l1>
+         <l_l1>list 1 item 3 para 3</l_l1>
+       </li>
+     </ul>
+     <ul>
+       <li>
+         <l_l1_1>list 2 item 1 para 1</l_l1_1>
+         <l_l1>list 2 item 1 para 2</l_l1>
+       </li>
+       <li>
+         <l_l1_n>list 2 item 2 para 1 (only para)</l_l1_n>
+       </li>
+       <li>
+         <l_l1_n>list 2 item 3 para 1</l_l1_n>
+         <l_l1>list 2 item 3 para 2</l_l1>
+         <l_l1>list 2 item 3 para 3</l_l1>
+       </li>
+     </ul>
+  </elt>
+
+=item subs_text ($regexp, $replace)
+
+subs_text does text substitution, similar to perl's C< s///> operator.
+
+C<$regexp> must be a perl regexp, created with the C<qr> operatot.
+
+C<$replace> can include C<$1, $2>... from the C<$regexp>. It can also be
+used to create element and entities, by using 
+C<< &elt( tag => { att => val }, text) >> (similar syntax as C<L<new>>) and
+C<< &ent( name) >>.
+
+Here is a rather complex example:
+
+  $elt->subs_text( qr{(?<!do not )link to (http://([^\s,]*))},
+                   'see &elt( a =>{ href => $1 }, $2)'
+                 );
+
+This will replace text like I<link to http://www.xmltwig.com> by 
+I<< see <a href="www.xmltwig.com">www.xmltwig.com</a> >>, but not
+I<do not link to...>
+
+Generating entities (here replacing spaces with &nbsp;):
+
+  $elt->subs_text( qr{ }, '&ent( "&nbsp;")');
+
+or, using a variable:
+
+  my $ent="&nbsp;";
+  $elt->subs_text( qr{ }, "&ent( '$ent')");
+
+Note that the substitution is always global, as in using the C<g> modifier
+in a perl substitution, and that it is performed on all text descendants
+of the element.
+
+=item add_id
+
+Add an id to the element.
+
+The id is an attribute (C<id> by default, see the C<id> option for XML::Twig
+C<new> to change it. Use an id starting with C<#> to get an id that's not 
+output by L<print>, L<flush> or L<sprint>) that allows you to use the
+L<elt_id> method to get the element easily.
+
+=item set_id_seed ($prefix)
+
+by default the id generated by C<L<add_id>> is C<< twig_id_<nnnn> >>, 
+C<set_id_seed> changes the prefix to C<$prefix> and resets the number
+to 1
+
+=item strip_att ($att)
+
+Remove the attribute C<$att> from all descendants of the element (including 
+the element)
+
+=item change_att_name ($old_name, $new_name)
+
+Change the name of the attribute from C<$old_name> to C<$new_name>. If there is no
+attribute C<$old_name> nothing happens.
+
+=item sort_children_on_value( %options)
+
+Sort the children of the element in place according to their text.
+All children are sorted. 
+
+Return the element, with its children sorted.
+
+
+L<%options> are
+
+  type  : numeric |  alpha     (default: alpha)
+  order : normal  |  reverse   (default: normal)
+
+Return the element, with its children sorted
+
+
+=item sort_children_on_att ($att, %options)
+
+Sort the children of the  element in place according to attribute C<$att>. 
+C<%options> are the same as for L<C<sort_children_on_value>>
+
+Return the element.
+
+
+=item sort_children_on_field ($gi, %options)
+
+Sort the children of the element in place, according to the field C<$gi> (the 
+text of the first child of the child with this gi). C<%options> are the same
+as for L<C<sort_children_on_value>>.
+
+Return the element, with its children sorted
+
+
+=item sort_children( $get_key, %options) 
+
+Sort the children of the element in place. The C<$get_key> argument is
+a reference to a function that returns the sort key when passed an element.
+
+For example:
+
+  $elt->sort_children( sub { $_[0]->{'att'}->{"nb"} + $_[0]->text }, 
+                       type => 'numeric', order => 'reverse'
+                     );
+
+=item field_to_att ($cond, $att)
+
+Turn the text of the first sub-element matched by C<$cond> into the value of 
+attribute C<$att> of the element. If C<$att> is ommited then C<$cond> is used 
+as the name of the attribute, which makes sense only if C<$cond> is a valid
+element (and attribute) name.
+
+The sub-element is then cut.
+
+=item att_to_field ($att, $gi)
+
+Take the value of attribute C<$att> and create a sub-element C<$gi> as first
+child of the element. If C<$gi> is ommited then C<$att> is used as the name of
+the sub-element. 
+
+
+=item get_xpath  ($xpath, $optional_offset)
+
+Return a list of elements satisfying the C<$xpath>. C<$xpath> is an XPATH-like 
+expression.
+
+A subset of the XPATH abbreviated syntax is covered:
+
+  gi
+  gi[1] (or any other positive number)
+  gi[last()]
+  gi[@att] (the attribute exists for the element)
+  gi[@att="val"]
+  gi[@att=~ /regexp/]
+  gi[att1="val1" and att2="val2"]
+  gi[att1="val1" or att2="val2"]
+  gi[string()="toto"] (returns gi elements which text (as per the text method) 
+                       is toto)
+  gi[string()=~/regexp/] (returns gi elements which text (as per the text 
+                          method) matches regexp)
+  expressions can start with / (search starts at the document root)
+  expressions can start with . (search starts at the current element)
+  // can be used to get all descendants instead of just direct children
+  * matches any gi
+  
+So the following examples from the 
+F<XPath recommendationL<http://www.w3.org/TR/xpath.html#path-abbrev>> work:
+
+  para selects the para element children of the context node
+  * selects all element children of the context node
+  para[1] selects the first para child of the context node
+  para[last()] selects the last para child of the context node
+  */para selects all para grandchildren of the context node
+  /doc/chapter[5]/section[2] selects the second section of the fifth chapter 
+     of the doc 
+  chapter//para selects the para element descendants of the chapter element 
+     children of the context node
+  //para selects all the para descendants of the document root and thus selects
+     all para elements in the same document as the context node
+  //olist/item selects all the item elements in the same document as the 
+     context node that have an olist parent
+  .//para selects the para element descendants of the context node
+  .. selects the parent of the context node
+  para[@type="warning"] selects all para children of the context node that have
+     a type attribute with value warning 
+  employee[@secretary and @assistant] selects all the employee children of the
+     context node that have both a secretary attribute and an assistant 
+     attribute
+
+
+The elements will be returned in the document order.
+
+If C<$optional_offset> is used then only one element will be returned, the one 
+with the appropriate offset in the list, starting at 0
+
+Quoting and interpolating variables can be a pain when the Perl syntax and the 
+XPATH syntax collide, so here are some more examples to get you started:
+
+  my $p1= "p1";
+  my $p2= "p2";
+  my @res= $t->get_xpath( "p[string( '$p1') or string( '$p2')]");
+
+  my $a= "a1";
+  my @res= $t->get_xpath( "//*[@att=\"$a\"]);
+
+  my $val= "a1";
+  my $exp= "//p[ \@att='$val']"; # you need to use \@ or you will get a warning
+  my @res= $t->get_xpath( $exp);
+
+Note that the only supported regexps delimiters are / and that you must 
+backslash all / in regexps AND in regular strings.
+
+XML::Twig does not provide natively full XPATH support, but you can use 
+XML::Twig does not provide natively full XPATH support, but you can use 
+C<L<XML::Twig::XPath>> to get C<findnodes> to use C<XML::XPath> as the
+XPath engine, with full coverage of the spec.
+
+C<L<XML::Twig::XPath>> to get C<findnodes> to use C<XML::XPath> as the
+XPath engine, with full coverage of the spec.
+
+=item find_nodes
+
+same asC<get_xpath> 
+
+=item findnodes
+
+same asC<get_xpath> 
+
+
+=item text
+
+Return a string consisting of all the C<PCDATA> and C<CDATA> in an element, 
+without any tags. The text is not XML-escaped: base entities such as C<&> 
+and C<< < >> are not escaped.
+
+=item trimmed_text
+
+Same as C<text> except that the text is trimmed: leading and trailing spaces
+are discarded, consecutive spaces are collapsed
+
+=item set_text        ($string)
+
+Set the text for the element: if the element is a C<PCDATA>, just set its
+text, otherwise cut all the children of the element and create a single
+C<PCDATA> child for it, which holds the text.
+
+=item insert         ($gi1, [$optional_atts1], $gi2, [$optional_atts2],...)
+
+For each gi in the list inserts an element C<$gi> as the only child of the 
+element.  The element gets the optional attributes inC<< $optional_atts<n>. >> 
+All children of the element are set as children of the new element.
+The upper level element is returned.
+
+  $p->insert( table => { border=> 1}, 'tr', 'td') 
+
+put C<$p> in a table with a visible border, a single C<tr> and a single C<td> 
+and return the C<table> element:
+
+  <p><table border="1"><tr><td>original content of p</td></tr></table></p>
+
+=item wrap_in        (@gi)
+
+Wrap elements C<$gi> as the successive ancestors of the element, returns the 
+new element.
+$elt->wrap_in( 'td', 'tr', 'table') wraps the element as a single cell in a 
+table for example.
+
+=item insert_new_elt ($opt_position, $gi, $opt_atts_hashref, @opt_content)
+
+Combines a C<L<new|new> > and a C<L<paste|paste> >: creates a new element using 
+C<$gi>, C<$opt_atts_hashref >and C<@opt_content> which are arguments similar 
+to those for C<new>, then paste it, using C<$opt_position> or C<'first_child'>,
+relative to C<$elt>.
+
+Return the newly created element
+
+=item erase
+
+Erase the element: the element is deleted and all of its children are
+pasted in its place.
+
+=item set_content    ( $optional_atts, @list_of_elt_and_strings)
+                     ( $optional_atts, '#EMPTY')
+
+Set the content for the element, from a list of strings and
+elements.  Cuts all the element children, then pastes the list
+elements as the children.  This method will create a C<PCDATA> element
+for any strings in the list.
+
+The C<$optional_atts> argument is the ref of a hash of attributes. If this
+argument is used then the previous attributes are deleted, otherwise they
+are left untouched. 
+
+B<WARNING>: if you rely on ID's then you will have to set the id yourself. At
+this point the element does not belong to a twig yet, so the ID attribute
+is not known so it won't be strored in the ID list.
+
+A content of 'C<#EMPTY>' creates an empty element;
+
+=item namespace ($optional_prefix)
+
+Return the URI of the namespace that C<$optional_prefix> or the element name
+belongs to. If the name doesn't belong to any namespace, C<undef> is returned.
+
+=item local_name
+
+Return the local name (without the prefix) for the element
+
+=item ns_prefix
+
+Return the namespace prefix for the element
+
+=item current_ns_prefixes
+
+Returna list of namespace prefixes valid for the element. The order of the
+prefixes in the list has no meaning. If the default namespace is currently 
+bound, '' appears in the list.
+
+
+=item inherit_att  ($att, @optional_gi_list)
+
+Return the value of an attribute inherited from parent tags. The value
+returned is found by looking for the attribute in the element then in turn
+in each of its ancestors. If the C<@optional_gi_list> is supplied only those
+ancestors whose gi is in the list will be checked. 
+
+=item all_children_are ($optional_condition)
+
+return 1 if all children of the element pass the C<$optional_condition>, 
+0 otherwise
+
+=item level       ($optional_condition)
+
+Return the depth of the element in the twig (root is 0).
+If C<$optional_condition> is given then only ancestors that match the condition are 
+counted.
+ 
+B<WARNING>: in a tree created using the C<twig_roots> option this will not return
+the level in the document tree, level 0 will be the document root, level 1 
+will be the C<twig_roots> elements. During the parsing (in a C<twig_handler>)
+you can use the C<depth> method on the twig object to get the real parsing depth.
+
+=item in           ($potential_parent)
+
+Return true if the element is in the potential_parent (C<$potential_parent> is 
+an element)
+
+=item in_context   ($cond, $optional_level)
+
+Return true if the element is included in an element which passes C<$cond>
+optionally within C<$optional_level> levels. The returned value is the 
+including element.
+
+=item pcdata
+
+Return the text of a C<PCDATA> element or C<undef> if the element is not 
+C<PCDATA>.
+
+=item pcdata_xml_string
+
+Return the text of a PCDATA element or undef if the element is not PCDATA. 
+The text is "XML-escaped" ('&' and '<' are replaced by '&amp;' and '&lt;')
+
+=item set_pcdata     ($text)
+
+Set the text of a C<PCDATA> element. 
+
+=item append_pcdata  ($text)
+
+Add the text at the end of a C<PCDATA> element.
+
+=item is_cdata
+
+Return 1 if the element is a C<CDATA> element, returns 0 otherwise.
+
+=item is_text
+
+Return 1 if the element is a C<CDATA> or C<PCDATA> element, returns 0 otherwise.
+
+=item cdata
+
+Return the text of a C<CDATA> element or C<undef> if the element is not 
+C<CDATA>.
+
+=item cdata_string
+
+Return the XML string of a C<CDATA> element, including the opening and
+closing markers.
+
+=item set_cdata     ($text)
+
+Set the text of a C<CDATA> element. 
+
+=item append_cdata  ($text)
+
+Add the text at the end of a C<CDATA> element.
+
+=item remove_cdata
+
+Turns all C<CDATA> sections in the element into regular C<PCDATA> elements. This is useful
+when converting XML to HTML, as browsers do not support CDATA sections. 
+
+=item extra_data 
+
+Return the extra_data (comments and PI's) attached to an element
+
+=item set_extra_data     ($extra_data)
+
+Set the extra_data (comments and PI's) attached to an element
+
+=item append_extra_data  ($extra_data)
+
+Append extra_data to the existing extra_data before the element (if no
+previous extra_data exists then it is created)
+
+=item set_asis
+
+Set a property of the element that causes it to be output without being XML
+escaped by the print functions: if it contains C<< a < b >> it will be output
+as such and not as C<< a &lt; b >>. This can be useful to create text elements
+that will be output as markup. Note that all C<PCDATA> descendants of the 
+element are also marked as having the property (they are the ones taht are
+actually impacted by the change).
+
+If the element is a C<CDATA> element it will also be output asis, without the
+C<CDATA> markers. The same goes for any C<CDATA> descendant of the element
+
+=item set_not_asis
+
+Unsets the C<asis> property for the element and its text descendants.
+
+=item is_asis
+
+Return the C<asis> property status of the element ( 1 or C<undef>)
+
+=item closed                   
+
+Return true if the element has been closed. Might be usefull if you are
+somewhere in the tree, during the parse, and have no idea whether a parent
+element is completely loaded or not.
+
+=item get_type
+
+Return the type of the element: 'C<#ELT>' for "real" elements, or 'C<#PCDATA>',
+'C<#CDATA>', 'C<#COMMENT>', 'C<#ENT>', 'C<#PI>'
+
+=item is_elt
+
+Return the gi if the element is a "real" element, or 0 if it is C<PCDATA>, 
+C<CDATA>...
+
+=item contains_only_text
+
+Return 1 if the element does not contain any other "real" element
+
+=item contains_only ($exp)
+
+Return the list of children if all children of the element match
+the expression C<$exp> 
+
+  if( $para->contains_only( 'tt')) { ... }
+
+=item contains_a_single ($exp)
+
+If the element contains a single child that matches the expression C<$exp>
+returns that element. Otherwise returns 0.
+
+=item is_field
+
+same as C<contains_only_text> 
+
+=item is_pcdata
+
+Return 1 if the element is a C<PCDATA> element, returns 0 otherwise.
+
+=item is_ent
+
+Return 1 if the element is an entity (an unexpanded entity) element, 
+return 0 otherwise.
+
+=item is_empty
+
+Return 1 if the element is empty, 0 otherwise
+
+=item set_empty
+
+Flags the element as empty. No further check is made, so if the element
+is actually not empty the output will be messed. The only effect of this 
+method is that the output will be C<< <gi att="value""/> >>.
+
+=item set_not_empty
+
+Flags the element as not empty. if it is actually empty then the element will
+be output as C<< <gi att="value""></gi> >>
+
+=item is_pi
+
+Return 1 if the element is a processing instruction (C<#PI>) element,
+return 0 otherwise.
+
+=item target
+
+Return the target of a processing instruction
+
+=item set_target ($target)
+
+Set the target of a processing instruction
+
+=item data
+
+Return the data part of a processing instruction
+
+=item set_data ($data)
+
+Set the data of a processing instruction
+
+=item set_pi ($target, $data)
+
+Set the target and data of a processing instruction
+
+=item pi_string
+
+Return the string form of a processing instruction
+(C<< <?target data?> >>)
+
+=item is_comment
+
+Return 1 if the element is a comment (C<#COMMENT>) element,
+return 0 otherwise.
+
+=item set_comment ($comment_text)
+
+Set the text for a comment
+
+=item comment
+
+Return the content of a comment (just the text, not the C<< <!-- >>
+and C<< --> >>)
+
+=item comment_string 
+
+Return the XML string for a comment (C<< <!-- comment --> >>)
+
+=item set_ent ($entity)
+
+Set an (non-expanded) entity (C<#ENT>). C<$entity>) is the entity
+text (C<&ent;>)
+
+=item ent
+
+Return the entity for an entity (C<#ENT>) element (C<&ent;>)
+
+=item ent_name
+
+Return the entity name for an entity (C<#ENT>) element (C<ent>)
+
+=item ent_string
+
+Return the entity, either expanded if the expanded version is available,
+or non-expanded (C<&ent;>) otherwise
+
+=item child ($offset, $optional_condition)
+
+Return the C<$offset>-th child of the element, optionally the C<$offset>-th 
+child that matches C<$optional_condition>. The children are treated as a list, so 
+C<< $elt->child( 0) >> is the first child, while C<< $elt->child( -1) >> is 
+the last child.
+
+=item child_text ($offset, $optional_condition)
+
+Return the text of a child or C<undef> if the sibling does not exist. Arguments
+are the same as child.
+
+=item last_child    ($optional_condition)
+
+Return the last child of the element, or the last child matching 
+C<$optional_condition> (ie the last of the element children matching
+the condition).
+
+=item last_child_text   ($optional_condition)
+
+Same as C<first_child_text> but for the last child.
+
+=item sibling  ($offset, $optional_condition)
+
+Return the next or previous C<$offset>-th sibling of the element, or the 
+C<$offset>-th one matching C<$optional_condition>. If C<$offset> is negative then a 
+previous sibling is returned, if $offset is positive then  a next sibling is 
+returned. C<$offset=0> returns the element if there is no condition or
+if the element matches the condition>, C<undef> otherwise.
+
+=item sibling_text ($offset, $optional_condition)
+
+Return the text of a sibling or C<undef> if the sibling does not exist. 
+Arguments are the same as C<sibling>.
+
+=item prev_siblings ($optional_condition)
+
+Return the list of previous siblings (optionaly matching C<$optional_condition>)
+for the element. The elements are ordered in document order.
+
+=item next_siblings ($optional_condition)
+
+Return the list of siblings (optionaly matching C<$optional_condition>)
+following the element. The elements are ordered in document order.
+
+=item pos ($optional_condition)
+
+Return the position of the element in the children list. The first child has a
+position of 1 (as in XPath).
+
+If the C<$optional_condition> is given then only siblings that match the condition 
+are counted. If the element itself does not match the  condition then
+0 is returned.
+
+=item atts
+
+Return a hash ref containing the element attributes
+
+=item set_atts      ({att1=>$att1_val, att2=> $att2_val... })
+
+Set the element attributes with the hash ref supplied as the argument
+
+=item del_atts
+
+Deletes all the element attributes.
+
+=item att_nb
+
+Return the number of attributes for the element
+
+=item has_atts
+
+Return true if the element has attributes (in fact return the number of
+attributes, thus being an alias to C<L<att_nb>>
+
+=item has_no_atts
+
+Return true if the element has no attributes, false (0) otherwise
+
+=item att_names
+
+return a list of the attribute names for the element
+
+=item att_xml_string ($att, $optional_quote)
+
+Return the attribute value, where '&', '<' and $quote (" by default)
+are XML-escaped
+
+if C<$optional_quote> is passed then it is used as the quote.
+
+=item set_id       ($id)
+
+Set the C<id> attribute of the element to the value.
+See C<L<elt_id|elt_id> > to change the id attribute name
+
+=item id
+
+Gets the id attribute value
+
+=item del_id       ($id)
+
+Deletes the C<id> attribute of the element and remove it from the id list
+for the document
+
+=item class
+
+Return the C<class> attribute for the element (methods on the C<class>
+attribute are quite convenient when dealing with XHTML, or plain XML that
+will eventually be displayed using CSS)
+
+=item set_class ($class)
+
+Set the C<class> attribute for the element to C<$class>
+
+=item add_to_class ($class)
+
+Add C<$class> to the element C<class> attribute: the new class is added
+only if it is not already present. Note that classes are sorted alphabetically,
+so the C<class> attribute can be changed even if the class is already there
+
+=item att_to_class ($att)
+
+Set the C<class> attribute to the value of attribute C<$att>
+
+=item add_att_to_class ($att)
+
+Add the value of attribute C<$att> to the C<class> attribute of the element
+
+=item move_att_to_class ($att)
+
+Add the value of attribute C<$att> to the C<class> attribute of the element
+and delete the attribute
+
+=item tag_to_class
+
+Set the C<class> attribute of the element to the element tag
+
+=item add_tag_to_class
+
+Add the element tag to its C<class> attribute
+
+=item set_tag_class ($new_tag)
+
+Add the element tag to its C<class> attribute and sets the tag to C<$new_tag>
+
+=item in_class ($class)
+
+Return true (C<1>) if the element is in the class C<$class> (if C<$class> is
+one of the tokens in the element C<class> attribute)
+
+=item DESTROY
+
+Frees the element from memory.
+
+=item start_tag
+
+Return the string for the start tag for the element, including 
+the C<< /> >> at the end of an empty element tag
+
+=item end_tag
+
+Return the string for the end tag of an element.  For an empty
+element, this returns the empty string ('').
+
+=item xml_string
+
+Equivalent to C<< $elt->sprint( 1) >>, returns the string for the entire 
+element, excluding the element's tags (but nested element tags are present)
+
+=item xml_text 
+
+Return the text of the element, encoded (and processed by the current 
+C<L<output_filter>> or C<L<output_encoding>> options, without any tag.
+
+=item set_pretty_print ($style)
+
+Set the pretty print method, amongst 'C<none>' (default), 'C<nsgmls>', 
+'C<nice>', 'C<indented>', 'C<record>' and 'C<record_c>'
+
+pretty_print styles:
+
+=over 4
+
+=item none
+
+the default, no C<\n> is used
+
+=item nsgmls
+
+nsgmls style, with C<\n> added within tags
+
+=item nice
+
+adds C<\n> wherever possible (NOT SAFE, can lead to invalid XML)
+
+=item indented
+
+same as C<nice> plus indents elements (NOT SAFE, can lead to invalid XML) 
+
+=item record
+
+table-oriented pretty print, one field per line 
+
+=item record_c
+
+table-oriented pretty print, more compact than C<record>, one record per line 
+
+=back
+
+=item set_empty_tag_style ($style)
+
+Set the method to output empty tags, amongst 'C<normal>' (default), 'C<html>',
+and 'C<expand>', 
+
+=item set_indent ($string)
+
+Set the indentation for the indented pretty print style (default is 2 spaces)
+
+=item set_quote ($quote)
+
+Set the quotes used for attributes. can be 'C<double>' (default) or 'C<single>'
+
+=item cmp       ($elt)
+
+  Compare the order of the 2 elements in a twig.
+
+  C<$a> is the <A>..</A> element, C<$b> is the <B>...</B> element
+  
+  document                        $a->cmp( $b)
+  <A> ... </A> ... <B>  ... </B>     -1
+  <A> ... <B>  ... </B> ... </A>     -1
+  <B> ... </B> ... <A>  ... </A>      1
+  <B> ... <A>  ... </A> ... </B>      1
+   $a == $b                           0
+   $a and $b not in the same tree   undef
+
+=item before       ($elt)
+
+Return 1 if C<$elt> starts before the element, 0 otherwise. If the 2 elements 
+are not in the same twig then return C<undef>.
+
+    if( $a->cmp( $b) == -1) { return 1; } else { return 0; }
+
+=item after       ($elt)
+
+Return 1 if $elt starts after the element, 0 otherwise. If the 2 elements 
+are not in the same twig then return C<undef>.
+
+    if( $a->cmp( $b) == -1) { return 1; } else { return 0; }
+
+=item other comparison methods
+
+=over 4
+
+=item lt
+
+=item le
+
+=item gt
+
+=item ge
+
+=back
+
+=item path
+
+Return the element context in a form similar to XPath's short
+form: 'C</root/gi1/../gi>'
+
+=item xpath
+
+Return a unique XPath expression that can be used to find the element
+again. 
+
+It looks like C</doc/sect[3]/title>: unique elements do not have an index,
+the others do.
+
+=item private methods
+
+Low-level methods on the twig:
+
+=over 4
+
+=item set_parent        ($parent)
+
+=item set_first_child   ($first_child)
+
+=item set_last_child    ($last_child)
+
+=item set_prev_sibling  ($prev_sibling)
+
+=item set_next_sibling  ($next_sibling)
+
+=item set_twig_current
+
+=item del_twig_current
+
+=item twig_current
+
+=item flush
+
+This method should NOT be used, always flush the twig, not an element.
+
+=item contains_text
+
+=back
+
+Those methods should not be used, unless of course you find some creative 
+and interesting, not to mention useful, ways to do it.
+
+=back
+
+=head2 cond
+
+Most of the navigation functions accept a condition as an optional argument
+The first element (or all elements for C<L<children|children> > or 
+C<L<ancestors|ancestors> >) that passes the condition is returned.
+
+The condition is a single step of an XPath expression using the XPath subset
+defined by C<L<get_xpath>>. Additional conditions are:
+
+The condition can be 
+
+=over 4
+
+=item #ELT
+
+return a "real" element (not a PCDATA, CDATA, comment or pi element) 
+
+=item #TEXT
+
+return a PCDATA or CDATA element
+
+=item regular expression
+
+return an element whose gi matches the regexp. The regexp has to be created 
+with C<qr//> (hence this is available only on perl 5.005 and above)
+
+=item code reference
+
+applies the code, passing the current element as argument, if the code returns
+true then the element is returned, if it returns false then the code is applied
+to the next candidate.
+
+=back
+
+=head2 XML::Twig::XPath
+
+XML::Twig implements a subset of XPath through the C<L<get_xpath>> method. 
+
+If you want to use the whole XPath power, then you can use C<XML::Twig::XPath>
+instead. In this case C<XML::Twig> uses C<XML::XPath> to execute XPath queries.
+You will of course need C<XML::XPath> installed to be able to use C<XML::Twig::XPath>.
+
+See L<XML::XPath> for more information.
+
+The methods you can use are:
+
+=over 4
+
+=item findnodes              ($path)
+
+return a list of nodes found by C<$path>.
+
+=item findnodes_as_string    ($path)
+
+return the nodes found reproduced as XML. The result is not guaranteed
+to be valid XML though.
+
+=item findvalue              ($path)
+
+return the concatenation of the text content of the result nodes
+
+=back
+
+In order for C<XML::XPath> to be used as the XPath engine the following methods
+are included in C<XML::Twig>:
+
+in XML::Twig
+
+=over 4
+
+=item getRootNode
+
+=item getParentNode
+
+=item getChildNodes 
+
+=back
+
+in XML::Twig::Elt
+
+=over 4
+
+=item string_value
+
+=item toString
+
+=item getName
+
+=item getRootNode
+
+=item getNextSibling
+
+=item getPreviousSibling
+
+=item isElementNode
+
+=item isTextNode
+
+=item isPI
+
+=item isPINode
+
+=item isProcessingInstructionNode
+
+=item isComment
+
+=item isCommentNode
+
+=item getTarget 
+
+=item getChildNodes 
+
+=item getElementById
+
+=back
+
+=head2 XML::Twig::XPath::Elt
+
+The methods you can use are the same as on C<XML::Twig::XPath> elements:
+
+=over 4
+
+=item findnodes              ($path)
+
+return a list of nodes found by C<$path>.
+
+=item findnodes_as_string    ($path)
+
+return the nodes found reproduced as XML. The result is not guaranteed
+to be valid XML though.
+
+=item findvalue              ($path)
+
+return the concatenation of the text content of the result nodes
+
+=back
+
+
+=head2 XML::Twig::Entity_list
+
+=over 4
+
+=item new
+
+Create an entity list.
+
+=item add         ($ent)
+
+Add an entity to an entity list.
+
+=item add_new_ent ($name, $val, $sysid, $pubid, $ndata)
+
+Create a new entity and add it to the entity list
+
+=item delete     ($ent or $gi).
+
+Delete an entity (defined by its name or by the Entity object)
+from the list.
+
+=item print      ($optional_filehandle)
+
+Print the entity list.
+
+=item list
+
+Return the list as an array
+
+=back
+
+
+=head2 XML::Twig::Entity
+
+=over 4
+
+=item new        ($name, $val, $sysid, $pubid, $ndata)
+
+Same arguments as the Entity handler for XML::Parser.
+
+=item print       ($optional_filehandle)
+
+Print an entity declaration.
+
+=item name 
+
+Return the name of the entity
+
+=item val  
+
+Return the value of the entity
+
+=item sysid
+
+Return the system id for the entity (for NDATA entities)
+
+=item pubid
+
+Return the public id for the entity (for NDATA entities)
+
+=item ndata
+
+Return true if the entity is an NDATA entity
+
+=item text
+
+Return the entity declaration text.
+
+=back
+
+
+=head1 EXAMPLES
+
+Additional examples (and a complete tutorial) can be found  on the
+F<XML::Twig PageL<http://www.xmltwig.com/xmltwig/>>
+
+To figure out what flush does call the following script with an
+XML file and an element name as arguments
+
+  use XML::Twig;
+
+  my ($file, $elt)= @ARGV;
+  my $t= XML::Twig->new( twig_handlers => 
+      { $elt => sub {$_[0]->flush; print "\n[flushed here]\n";} });
+  $t->parsefile( $file, ErrorContext => 2);
+  $t->flush;
+  print "\n";
+
+
+=head1 NOTES
+
+=head2 Subclassing XML::Twig
+
+Useful methods:
+
+=over 4
+
+=item elt_class
+
+In order to subclass C<XML::Twig> you will probably need to subclass also
+C<L<XML::Twig::Elt>>. Use the C<elt_class> option when you create the
+C<XML::Twig> object to get the elements created in a different class
+(which should be a subclass of C<XML::Twig::Elt>.
+
+=item add_options
+
+If you inherit C<XML::Twig> new method but want to add more options to it
+you can use this method to prevent XML::Twig to issue warnings for those
+additional options.
+
+=back
+
+=head2 DTD Handling
+
+There are 3 possibilities here.  They are:
+
+=over 4
+
+=item No DTD
+
+No doctype, no DTD information, no entity information, the world is simple...
+
+=item Internal DTD
+
+The XML document includes an internal DTD, and maybe entity declarations.
+
+If you use the load_DTD option when creating the twig the DTD information and
+the entity declarations can be accessed.
+
+The DTD and the entity declarations will be C<flush>'ed (or C<print>'ed) either
+as is (if they have not been modified) or as reconstructed (poorly, comments 
+are lost, order is not kept, due to it's content this DTD should not be viewed 
+by anyone) if they have been modified. You can also modify them directly by 
+changing the C<< $twig->{twig_doctype}->{internal} >> field (straight from 
+XML::Parser, see the C<Doctype> handler doc)
+
+=item External DTD
+
+The XML document includes a reference to an external DTD, and maybe entity 
+declarations.
+
+If you use the C<load_DTD> when creating the twig the DTD information and the 
+entity declarations can be accessed. The entity declarations will be
+C<flush>'ed (or C<print>'ed) either as is (if they have not been modified) or
+as reconstructed (badly, comments are lost, order is not kept).
+
+You can change the doctype through the C<< $twig->set_doctype >> method and 
+print the dtd through the C<< $twig->dtd_text >> or C<< $twig->dtd_print >>
+ methods.
+
+If you need to modify the entity list this is probably the easiest way to do it.
+
+=back
+
+
+=head2 Flush
+
+If you set handlers and use C<flush>, do not forget to flush the twig one
+last time AFTER the parsing, or you might be missing the end of the document.
+
+Remember that element handlers are called when the element is CLOSED, so
+if you have handlers for nested elements the inner handlers will be called
+first. It makes it for example trickier than it would seem to number nested
+clauses.
+
+
+
+=head1 BUGS
+
+=over 4
+
+=item entity handling
+
+Due to XML::Parser behaviour, non-base entities in attribute values disappear:
+C<att="val&ent;"> will be turned into C<< att => val >>, unless you use the 
+C<keep_encoding> argument to C<< XML::Twig->new >> 
+
+=item DTD handling
+
+Basically the DTD handling methods are competely bugged. No one uses them and
+it seems very difficult to get them to work in all cases, including with 
+several slightly incompatible versions of XML::Parser and of libexpat.
+
+So use XML::Twig with standalone documents, or with documents refering to an
+external DTD, but don't expect it to properly parse and even output back the
+DTD.
+
+=item memory leak
+
+If you use a lot of twigs you might find that you leak quite a lot of memory
+(about 2Ks per twig). You can use the C<L<dispose|dispose> > method to free 
+that memory after you are done.
+
+If you create elements the same thing might happen, use the C<L<delete|delete>>
+method to get rid of them.
+
+Alternatively installing the C<Scalar::Util> (or C<WeakRef>) module on a version 
+of Perl that supports it (>5.6.0) will get rid of the memory leaks automagically.
+
+=item ID list
+
+The ID list is NOT updated when ID's are modified or elements cut or
+deleted.
+
+=item change_gi
+
+This method will not function properly if you do:
+
+     $twig->change_gi( $old1, $new);
+     $twig->change_gi( $old2, $new);
+     $twig->change_gi( $new, $even_newer);
+
+=item sanity check on XML::Parser method calls
+
+XML::Twig should really prevent calls to some XML::Parser methods, especially 
+the C<setHandlers> method.
+
+=item pretty printing
+
+Pretty printing (at least using the 'C<indented>' style) is hard to get right! 
+Only elements that belong to the document will be properly indented. Printing 
+elements that do not belong to the twig makes it impossible for XML::Twig to 
+figure out their depth, and thus their indentation level.
+
+Also there is an anavoidable bug when using C<flush> and pretty printing for
+elements with mixed content that start with an embedded element:
+
+  <elt><b>b</b>toto<b>bold</b></elt>
+
+  will be output as 
+
+  <elt>
+    <b>b</b>toto<b>bold</b></elt>
+
+if you flush the twig when you find the C<< <b> >> element
+  
+
+=back
+
+=head1 Globals
+
+These are the things that can mess up calling code, especially if threaded.
+They might also cause problem under mod_perl. 
+
+=over 4
+
+=item Exported constants
+
+Whether you want them or not you get them! These are subroutines to use
+as constant when creating or testing elements
+
+  PCDATA  return '#PCDATA'
+  CDATA   return '#CDATA'
+  PI      return '#PI', I had the choice between PROC and PI :--(
+
+=item Module scoped values: constants
+
+these should cause no trouble:
+
+  %base_ent= ( '>' => '&gt;',
+               '<' => '&lt;',
+               '&' => '&amp;',
+               "'" => '&apos;',
+               '"' => '&quot;',
+             );
+  CDATA_START   = "<![CDATA[";
+  CDATA_END     = "]]>";
+  PI_START      = "<?";
+  PI_END        = "?>";
+  COMMENT_START = "<!--";
+  COMMENT_END   = "-->";
+
+pretty print styles
+
+  ( $NSGMLS, $NICE, $INDENTED, $RECORD1, $RECORD2)= (1..5);
+
+empty tag output style
+
+  ( $HTML, $EXPAND)= (1..2);
+
+=item Module scoped values: might be changed
+
+Most of these deal with pretty printing, so the worst that can
+happen is probably that XML output does not look right, but is
+still valid and processed identically by XML processors.
+
+C<$empty_tag_style> can mess up HTML bowsers though and changing C<$ID> 
+would most likely create problems.
+
+  $pretty=0;           # pretty print style
+  $quote='"';          # quote for attributes
+  $INDENT= '  ';       # indent for indented pretty print
+  $empty_tag_style= 0; # how to display empty tags
+  $ID                  # attribute used as a gi ('id' by default)
+
+=item Module scoped values: definitely changed
+
+These 2 variables are used to replace gi's by an index, thus 
+saving some space when creating a twig. If they really cause
+you too much trouble, let me know, it is probably possible to
+create either a switch or at least a version of XML::Twig that 
+does not perform this optimisation.
+
+  %gi2index;     # gi => index
+  @index2gi;     # list of gi's
+
+=back
+
+If you need to manipulate all those values, you can use the following methods on the
+XML::Twig object:
+
+=over 4
+
+=item global_state
+
+Return a hasref with all the global variables used by XML::Twig
+
+The hash has the following fields:  C<pretty>, C<quote>, C<indent>, 
+C<empty_tag_style>, C<keep_encoding>, C<expand_external_entities>, 
+C<output_filter>, C<output_text_filter>, C<keep_atts_order>
+
+=item set_global_state ($state)
+
+Set the global state, C<$state> is a hashref
+
+=item save_global_state
+
+Save the current global state
+
+=item restore_global_state
+
+Restore the previously saved (using C<Lsave_global_state>> state
+
+=back
+
+=head1 TODO 
+
+=over 4
+
+=item SAX handlers
+
+Allowing XML::Twig to work on top of any SAX parser
+
+=item multiple twigs are not well supported
+
+A number of twig features are just global at the moment. These include
+the ID list and the "gi pool" (if you use C<change_gi> then you change the gi 
+for ALL twigs).
+
+A future version will try to support this while trying not to be to
+hard on performance (at least when a single twig is used!).
+
+
+=back
+
+
+=head1 AUTHOR
+
+Michel Rodriguez <mirod@xmltwig.com>
+
+=head1 LICENSE
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+Bug reports should be sent using:
+F<RTL<http://rt.cpan.org/NoAuth/Bugs.html?Dist=XML-Twig>>
+
+Comments can be sent to mirod@xmltwig.com
+
+The XML::Twig page is at L<http://www.xmltwig.com/xmltwig/>
+It includes the development version of the module, a slightly better version 
+of the documentation, examples, a tutorial and a: 
+F<Processing XML efficiently with Perl and XML::Twig: 
+L<http://www.xmltwig.com/xmltwig/tutorial/index.html>>
+
+=head1 SEE ALSO
+
+XML::Parser,XML::Parser::Expat, Encode, Text::Iconv, Scalar::Utils
+
+
+=cut
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Variable.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Variable.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/Variable.pm	(revision 10506)
@@ -0,0 +1,43 @@
+# $Id$
+
+package XML::XPath::Variable;
+use strict;
+
+# This class does NOT contain 1 instance of a variable
+# see the XML::XPath::Parser class for the instances
+# This class simply holds the name of the var
+
+sub new {
+    my $class = shift;
+    my ($pp, $name) = @_;
+    bless { name => $name, path_parser => $pp }, $class;
+}
+
+sub as_string {
+    my $self = shift;
+    '\$' . $self->{name};
+}
+
+sub as_xml {
+    my $self = shift;
+    return "<Variable>" . $self->{name} . "</Variable>\n";
+}
+
+sub get_value {
+    my $self = shift;
+    $self->{path_parser}->get_var($self->{name});
+}
+
+sub set_value {
+    my $self = shift;
+    my ($val) = @_;
+    $self->{path_parser}->set_var($self->{name}, $val);
+}
+
+sub evaluate {
+    my $self = shift;
+    my $val = $self->get_value;
+    return $val;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/XMLParser.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/XMLParser.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/XML/XPath/XMLParser.pm	(revision 10506)
@@ -0,0 +1,385 @@
+# $Id$
+
+package XML::XPath::XMLParser;
+
+use strict;
+
+use XML::Parser;
+#use XML::XPath;
+use XML::XPath::Node;
+use XML::XPath::Node::Element;
+use XML::XPath::Node::Text;
+use XML::XPath::Node::Comment;
+use XML::XPath::Node::PI;
+use XML::XPath::Node::Attribute;
+use XML::XPath::Node::Namespace;
+
+my @options = qw(
+        filename
+        xml
+        parser
+        ioref
+        );
+
+my ($_current, $_namespaces_on);
+my %IdNames;
+
+use vars qw/$xmlns_ns $xml_ns/;
+
+$xmlns_ns = "http://www.w3.org/2000/xmlns/";
+$xml_ns = "http://www.w3.org/XML/1998/namespace";
+
+sub new {
+    my $proto = shift;
+    my $class = ref($proto) || $proto;
+    my %args = @_;
+    my %hash = map(( "_$_" => $args{$_} ), @options);
+    bless \%hash, $class;
+}
+
+sub parse {
+    my $self = shift;
+    
+    $self->{IdNames} = {};
+    $self->{InScopeNamespaceStack} = [ { 
+            '_Default' => undef,
+            'xmlns' => $xmlns_ns,
+            'xml' => $xml_ns,
+        } ];
+    
+    $self->{NodeStack} = [ ];
+    
+    $self->set_xml($_[0]) if $_[0];
+    
+    my $parser = $self->get_parser || XML::Parser->new(
+            ErrorContext => 2,
+            ParseParamEnt => 1,
+            );
+    
+    $parser->setHandlers(
+            Init => sub { $self->parse_init(@_) },
+            Char => sub { $self->parse_char(@_) },
+            Start => sub { $self->parse_start(@_) },
+            End => sub { $self->parse_end(@_) },
+            Final => sub { $self->parse_final(@_) },
+            Proc => sub { $self->parse_pi(@_) },
+            Comment => sub { $self->parse_comment(@_) },
+            Attlist => sub { $self->parse_attlist(@_) },
+            );
+    
+    my $toparse;
+    if ($toparse = $self->get_filename) {
+        return $parser->parsefile($toparse);
+    }
+    else {
+        return $parser->parse($self->get_xml || $self->get_ioref);
+    }
+}
+
+sub parsefile {
+    my $self = shift;
+    my ($filename) = @_;
+    $self->set_filename($filename);
+    $self->parse;
+}
+
+sub parse_init {
+    my $self = shift;
+    my $e = shift;
+    my $document = XML::XPath::Node::Element->new();
+    my $newns = XML::XPath::Node::Namespace->new('xml', $xml_ns);
+    $document->appendNamespace($newns);
+    $self->{current} = $self->{DOC_Node} = $document;
+}
+
+sub parse_final {
+    my $self = shift;
+    return $self->{DOC_Node};
+}
+
+sub parse_char {
+    my $self = shift;
+    my $e = shift;
+    my $text = shift;
+    
+    my $parent = $self->{current};
+    
+    my $last = $parent->getLastChild;
+    if ($last && $last->isTextNode) {
+        # append to previous text node
+        $last->appendText($text);
+        return;
+    }
+    
+    my $node = XML::XPath::Node::Text->new($text);
+    $parent->appendChild($node, 1);
+}
+
+sub parse_start {
+    my $self = shift;
+    my $e = shift;
+    my $tag = shift;
+    
+    push @{ $self->{InScopeNamespaceStack} },
+         { %{ $self->{InScopeNamespaceStack}[-1] } };
+    $self->_scan_namespaces(@_);
+    
+    my ($prefix, $namespace) = $self->_namespace($tag);
+    
+    my $node = XML::XPath::Node::Element->new($tag, $prefix);
+    
+    my @attributes;
+    for (my $ii = 0; $ii < $#_; $ii += 2) {
+	my ($name, $value) = ($_[$ii], $_[$ii+1]);
+        if ($name =~ /^xmlns(:(.*))?$/) {
+            # namespace node
+            my $prefix = $2 || '#default';
+#            warn "Creating NS node: $prefix = $value\n";
+            my $newns = XML::XPath::Node::Namespace->new($prefix, $value);
+            $node->appendNamespace($newns);
+        }
+        else {
+	    my ($prefix, $namespace) = $self->_namespace($name);
+            undef $namespace unless $prefix;
+
+            my $newattr = XML::XPath::Node::Attribute->new($name, $value, $prefix);
+            $node->appendAttribute($newattr, 1);
+            if (exists($self->{IdNames}{$tag}) && ($self->{IdNames}{$tag} eq $name)) {
+    #            warn "appending Id Element: $val for ", $node->getName, "\n";
+                $self->{DOC_Node}->appendIdElement($value, $node);
+            }
+        }
+    }
+        
+    $self->{current}->appendChild($node, 1);
+    $self->{current} = $node;
+}
+
+sub parse_end {
+    my $self = shift;
+    my $e = shift;
+    $self->{current} = $self->{current}->getParentNode;
+}
+
+sub parse_pi {
+    my $self = shift;
+    my $e = shift;
+    my ($target, $data) = @_;
+    my $node = XML::XPath::Node::PI->new($target, $data);
+    $self->{current}->appendChild($node, 1);
+}
+
+sub parse_comment {
+    my $self = shift;
+    my $e = shift;
+    my ($data) = @_;
+    my $node = XML::XPath::Node::Comment->new($data);
+    $self->{current}->appendChild($node, 1);
+}
+
+sub parse_attlist {
+    my $self = shift;
+    my $e = shift;
+    my ($elname, $attname, $type, $default, $fixed) = @_;
+    if ($type eq 'ID') {
+        $self->{IdNames}{$elname} = $attname;
+    }
+}
+
+sub _scan_namespaces {
+    my ($self, %attributes) = @_;
+
+    while (my ($attr_name, $value) = each %attributes) {
+	if ($attr_name eq 'xmlns') {
+	    $self->{InScopeNamespaceStack}[-1]{'_Default'} = $value;
+	} elsif ($attr_name =~ /^xmlns:(.*)$/) {
+	    my $prefix = $1;
+	    $self->{InScopeNamespaceStack}[-1]{$prefix} = $value;
+	}
+    }
+}
+
+sub _namespace {
+    my ($self, $name) = @_;
+
+    my ($prefix, $localname) = split(/:/, $name);
+    if (!defined($localname)) {
+	if ($prefix eq 'xmlns') {
+	    return '', undef;
+	} else {
+	    return '', $self->{InScopeNamespaceStack}[-1]{'_Default'};
+	}
+    } else {
+	return $prefix, $self->{InScopeNamespaceStack}[-1]{$prefix};
+    }
+}
+
+sub as_string {
+    my $node = shift;
+    $node->toString;
+}
+
+sub get_parser { shift->{_parser}; }
+sub get_filename { shift->{_filename}; }
+sub get_xml { shift->{_xml}; }
+sub get_ioref { shift->{_ioref}; }
+
+sub set_parser { $_[0]->{_parser} = $_[1]; }
+sub set_filename { $_[0]->{_filename} = $_[1]; }
+sub set_xml { $_[0]->{_xml} = $_[1]; }
+sub set_ioref { $_[0]->{_ioref} = $_[1]; }
+
+1;
+
+__END__
+
+=head1 NAME
+
+XML::XPath::XMLParser - The default XML parsing class that produces a node tree
+
+=head1 SYNOPSIS
+
+    my $parser = XML::XPath::XMLParser->new(
+                filename => $self->get_filename,
+                xml => $self->get_xml,
+                ioref => $self->get_ioref,
+                parser => $self->get_parser,
+            );
+    my $root_node = $parser->parse;
+
+=head1 DESCRIPTION
+
+This module generates a node tree for use as the context node for XPath processing.
+It aims to be a quick parser, nothing fancy, and yet has to store more information
+than most parsers. To achieve this I've used array refs everywhere - no hashes.
+I don't have any performance figures for the speedups achieved, so I make no
+appologies for anyone not used to using arrays instead of hashes. I think they
+make good sense here where we know the attributes of each type of node.
+
+=head1 Node Structure
+
+All nodes have the same first 2 entries in the array: node_parent
+and node_pos. The type of the node is determined using the ref() function.
+The node_parent always contains an entry for the parent of the current
+node - except for the root node which has undef in there. And node_pos is the
+position of this node in the array that it is in (think: 
+$node == $node->[node_parent]->[node_children]->[$node->[node_pos]] )
+
+Nodes are structured as follows:
+
+=head2 Root Node
+
+The root node is just an element node with no parent.
+
+    [
+      undef, # node_parent - check for undef to identify root node
+      undef, # node_pos
+      undef, # node_prefix
+      [ ... ], # node_children (see below)
+    ]
+
+=head2 Element Node
+
+    [
+      $parent, # node_parent
+      <position in current array>, # node_pos
+      'xxx', # node_prefix - namespace prefix on this element
+      [ ... ], # node_children
+      'yyy', # node_name - element tag name
+      [ ... ], # node_attribs - attributes on this element
+      [ ... ], # node_namespaces - namespaces currently in scope
+    ]
+
+=head2 Attribute Node
+
+    [
+      $parent, # node_parent - the element node
+      <position in current array>, # node_pos
+      'xxx', # node_prefix - namespace prefix on this element
+      'href', # node_key - attribute name
+      'ftp://ftp.com/', # node_value - value in the node
+    ]
+
+=head2 Namespace Nodes
+
+Each element has an associated set of namespace nodes that are currently
+in scope. Each namespace node stores a prefix and the expanded name (retrieved
+from the xmlns:prefix="..." attribute).
+
+    [
+      $parent,
+      <pos>,
+      'a', # node_prefix - the namespace as it was written as a prefix
+      'http://my.namespace.com', # node_expanded - the expanded name.
+    ]
+
+=head2 Text Nodes
+
+    [
+      $parent,
+      <pos>,
+      'This is some text' # node_text - the text in the node
+    ]
+
+=head2 Comment Nodes
+
+    [
+      $parent,
+      <pos>,
+      'This is a comment' # node_comment
+    ]
+
+=head2 Processing Instruction Nodes
+
+    [
+      $parent,
+      <pos>,
+      'target', # node_target
+      'data', # node_data
+    ]
+
+=head1 Usage
+
+If you feel the need to use this module outside of XML::XPath (for example
+you might use this module directly so that you can cache parsed trees), you
+can follow the following API:
+
+=head2 new
+
+The new method takes either no parameters, or any of the following parameters:
+
+        filename
+        xml
+        parser
+        ioref
+
+This uses the familiar hash syntax, so an example might be:
+
+    use XML::XPath::XMLParser;
+    
+    my $parser = XML::XPath::XMLParser->new(filename => 'example.xml');
+
+The parameters represent a filename, a string containing XML, an XML::Parser
+instance and an open filehandle ref respectively. You can also set or get all
+of these properties using the get_ and set_ functions that have the same
+name as the property: e.g. get_filename, set_ioref, etc.
+
+=head2 parse
+
+The parse method generally takes no parameters, however you are free to
+pass either an open filehandle reference or an XML string if you so require.
+The return value is a tree that XML::XPath can use. The parse method will
+die if there is an error in your XML, so be sure to use perl's exception
+handling mechanism (eval{};) if you want to avoid this.
+
+=head2 parsefile
+
+The parsefile method is identical to parse() except it expects a single
+parameter that is a string naming a file to open and parse. Again it
+returns a tree and also dies if there are XML errors.
+
+=head1 NOTICES
+
+This file is distributed as part of the XML::XPath module, and is copyright
+2000 Fastnet Software Ltd. Please see the documentation for the module as a
+whole for licencing information.
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/rm/Header/PurePerl.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/rm/Header/PurePerl.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/cpan/rm/Header/PurePerl.pm	(revision 10506)
@@ -0,0 +1,228 @@
+package rm::Header::PurePerl;
+
+use 5.005;
+use strict;
+use warnings;
+
+use Fcntl qw/SEEK_END/;
+
+our $VERSION = '0.07';
+
+sub new 
+{
+    my $class = shift;
+    my $file = shift;
+
+    return load($class, $file);
+}
+
+sub load 
+{
+    my $class    = shift;
+    my $file     = shift;
+    my $from_new = shift;
+    my %data;
+    my $self;
+
+    # there must be a better way...
+    if ($class eq 'rm::Header::PurePerl')
+    {
+	$self = bless \%data, $class;
+    }
+    else
+    {
+	$self = $class;
+    }
+
+    if ($self->{'FILE_LOADED'})
+    {
+	return $self;
+    }
+
+    $self->{'FILE_LOADED'} = 1;
+
+    # check that the file exists and is readable
+    unless ( -e $file && -r _ )
+    {
+	warn "File does not exist or cannot be read.";
+	# file does not exist, can't do anything
+	return undef;
+    }
+    # open up the file
+    open FILE, $file;
+    # make sure dos-type systems can handle it...
+    binmode FILE;
+
+    $data{'filename'} = $file;
+    $data{'fileHandle'} = \*FILE;
+
+    _loadInfo(\%data);
+
+    close FILE;
+
+    return $self;
+}
+
+sub info 
+{
+    my $self = shift;
+    my $key = shift;
+
+    # if the user did not supply a key, return the entire hash
+    unless ($key)
+    {
+	return $self->{'INFO'};
+    }
+
+    # otherwise, return the value for the given key
+    return $self->{'INFO'}{lc $key};
+}
+
+sub _loadInfo
+{
+    my $data = shift;
+    my $start = 0;
+    my $fh = $data->{'fileHandle'};
+    my $buffer;
+    my $byteCount = $start;
+    my %info;
+    
+    # check that the first four bytes are '.RMF'
+    read($fh, $buffer, 4);
+    if ($buffer ne '.RMF')
+    {
+	warn "No RMF header?";
+	return undef;
+    }
+
+$buffer='';
+my $char;
+
+#find the header
+my $bytes = "DATA";
+my @byteList = split //, $bytes;
+my $numBytes = @byteList;
+my $i;
+
+LINE:   while (1){
+  INNER:  for ($i = 0; $i < $numBytes; $i ++)
+    {
+  unless ( read($fh, $char, 1) ) {last LINE ;}
+	# Find out all of char
+	$buffer= $buffer.$char;  
+
+if (ord($char) !=  ord($byteList[$i]) ) 
+{last  INNER ;}
+    }
+if ($i == $numBytes) {last LINE ;} #jump out the while loop
+        }
+
+#find the tail
+ $bytes = "INDX";
+ @byteList = split //, $bytes;
+ $numBytes = @byteList;
+
+my $isrecord=0;
+LINE:  while (read($fh, $char, 1)){
+   if ($isrecord) {
+	# Find out all of char
+	$buffer= $buffer.$char;  
+   }else
+        {
+         INNER:  for ($i = 0; $i < $numBytes; $i ++)
+                     {
+                      if (ord($char) !=  ord($byteList[$i]) ) {last  INNER ;}
+                      unless ( read($fh, $char, 1) ) {last LINE ;}
+                     }
+if ($i == $numBytes) {$isrecord = 1;} #start record
+        }
+       }
+
+my @cliptype = (
+
+#add clip type here
+"Comments",
+"Keywords",
+"Category",
+"MimeType",# title
+"Lyrics",
+"Artist",
+"CD Track #",
+"Album",
+"Extension",
+"Genre",
+"Statistics",
+"PROP",
+"MDPR",
+"Target Audiences",
+"Audio Format",
+"Creation Date",
+"Modification Date",
+"Generated By",
+"Abstract",
+"Content Rating",
+"File ID",
+"CONT",
+"Audio Stream",
+"Video Stream",
+"Title"
+);
+
+for my $j ( 1 .. scalar(@cliptype) ) {
+$info{$cliptype[$j - 1]} = _loadInfor($buffer,$cliptype[$j - 1]);
+}
+
+    $data->{'INFO'} = \%info;
+}
+
+#search for the element name and value
+sub _loadInfor
+{my $data = shift;
+my $item = shift;
+
+my @byteList = split //, $data;
+my $startbyte = 0;
+
+
+my $isrecord;
+my $data2 = "";
+my $char;
+my $item2 = "";
+if ( $item eq "Title") {$item2 = $item; $item = "MimeType";}
+
+
+OUT: while(index($data, $item, $startbyte) != -1){
+$startbyte = index($data, $item, $startbyte);
+$isrecord=0;
+
+$startbyte += length($item);
+
+if(ord($byteList[$startbyte]) == 0 or ord($byteList[$startbyte]) == 0x14){
+  if ( $item eq "Album" or $item eq "Artist" or $item2 eq "Title"){
+     if ( index($data,"Name",$startbyte) != -1) {
+     $startbyte = index($data,"Name",$startbyte);
+     $startbyte += length("Name");
+     }else {next OUT;}
+}
+
+  if ($data2 ne "") {$data2 = $data2."; ";}
+
+LINE:   while (1){
+        $char = $byteList[++$startbyte];
+
+	if (ord($char) >= 32 and ord($char) <= 126)
+	{
+        $isrecord=1; #record the string started
+	$data2 = $data2.$char;  
+	}else{
+             if ( $isrecord == 1 ) {last LINE ;}# stop at the end of string
+             }
+        }# end LINE: while
+
+ }# end if 
+}# end while
+
+return $data2;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/doc.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/doc.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/doc.pm	(revision 10506)
@@ -0,0 +1,1580 @@
+###########################################################################
+#
+# doc.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistr   te it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# base class to hold documents
+
+package doc;
+eval {require bytes};
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/dynamic/lib/site_perl/5.005/i686-linux");
+}
+
+use unicode;
+use util;
+use ghtml;
+use File::stat;
+##use hashdoc;
+
+# the document type may be indexed_doc, nonindexed_doc, or
+# classification
+
+my $OIDcount = 0;
+
+sub new {
+    my $class = shift (@_);
+    my ($source_filename, $doc_type) = @_;
+
+    my $self = bless {'associated_files'=>[],
+		      'subsection_order'=>[],
+		      'next_subsection'=>1,
+		      'subsections'=>{},
+		      'metadata'=>[],
+		      'text'=>"",
+		      'OIDtype'=>"hash"}, $class;
+
+    # used to set lastmodified here, but this can screw up the HASH ids, so
+    # the docsave processor now calls set_lastmodified
+    
+    if (defined $source_filename) {
+	my $collect_dir = $ENV{'GSDLCOLLECTDIR'};
+
+	if (defined $collect_dir) {
+	    my $dirsep = &util::get_dirsep();
+	    if ($collect_dir !~ m/$dirsep$/) {
+		$collect_dir .= $dirsep;
+	    }
+
+	    $collect_dir =~ s/\\/\\\\/g; # escape DOS style file separator
+
+	    # if from within GSDLCOLLECTDIR, then remove directory prefix
+	    # so source_filename is realative to it.  This is done to aid
+	    # portability, i.e. the collection can be moved to somewhere
+	    # else on the file system and the archives directory will still
+	    # work.  This is needed, for example in the applet version of
+	    # GLI where GSDLHOME/collect on the server will be different to
+	    # the collect directory of the remove user.  Of course,
+	    # GSDLCOLLECTDIR subsequently needs to be put back on to turn
+	    # it back into a full pathname.
+
+	    if ($source_filename =~ /^$collect_dir(.*)$/) {
+		$source_filename = $1;
+	    }
+	}
+
+	$self->set_source_filename ($source_filename);
+    }
+
+    $self->set_doc_type ($doc_type) if defined $doc_type;
+
+    return $self;
+}
+# set lastmodified for OAI purposes, added by GRB, moved by kjdon
+sub set_lastmodified {
+    my $self = shift (@_);
+
+    my $source_filename = $self->get_source_filename();
+    if ((defined $self->get_metadata_element ($self->get_top_section(), "gsdldoctype")) &&
+	(defined $source_filename) && (-e $source_filename)) {
+	my $file_stat = stat($source_filename);
+	my $mtime = $file_stat->mtime;
+	$self->add_utf8_metadata($self->get_top_section(), "lastmodified", $file_stat->mtime);
+    } 
+}
+
+# clone the $self object
+sub duplicate {
+    my $self = shift (@_);
+
+    my $newobj = {};
+    
+    foreach my $k (keys %$self) {
+	$newobj->{$k} = &clone ($self->{$k});
+    }
+
+    bless $newobj, ref($self);
+    return $newobj;
+}
+
+sub clone {
+    my ($from) = @_;
+    my $type = ref ($from);
+
+    if ($type eq "HASH") {
+	my $to = {};
+	foreach my $key (keys %$from) {
+	    $to->{$key} = &clone ($from->{$key});
+	}
+	return $to;
+    } elsif ($type eq "ARRAY") {
+	my $to = [];
+	foreach my $v (@$from) {
+	    push (@$to, &clone ($v));
+	}
+	return $to;
+    } else {
+	return $from;
+    }
+}
+
+sub set_OIDtype {
+    my $self = shift (@_);
+    my ($type) = @_;
+
+    if ($type =~ /^(hash|incremental|dirname|assigned)$/) {
+	$self->{'OIDtype'} = $type;
+    } else {
+	$self->{'OIDtype'} = "hash";
+    }
+}
+
+sub set_source_filename {
+    my $self = shift (@_);
+    my ($source_filename) = @_;
+
+    $self->set_metadata_element ($self->get_top_section(), 
+				 "gsdlsourcefilename", 
+				 $source_filename);
+}
+
+sub set_converted_filename {
+    my $self = shift (@_);
+    my ($converted_filename) = @_;
+
+    $self->set_metadata_element ($self->get_top_section(), 
+				 "gsdlconvertedfilename", 
+				 $converted_filename);
+}
+
+
+# returns the source_filename as it was provided
+sub get_source_filename {
+    my $self = shift (@_);
+
+    return $self->get_metadata_element ($self->get_top_section(), "gsdlsourcefilename");
+}
+
+# returns converted filename if available else returns source filename
+sub get_filename_for_hashing {
+    my $self = shift (@_);
+
+    my $filename = $self->get_metadata_element ($self->get_top_section(), "gsdlconvertedfilename");
+
+    if (!defined $filename) {
+	$filename = $self->get_metadata_element ($self->get_top_section(), "gsdlsourcefilename");
+    }
+    return $filename;
+}
+
+sub set_doc_type {
+    my $self = shift (@_);
+    my ($doc_type) = @_;
+
+    $self->set_metadata_element ($self->get_top_section(), 
+				 "gsdldoctype", 
+				 $doc_type);
+}
+
+# returns the gsdldoctype as it was provided
+# the default of "indexed_doc" is used if no document
+# type was provided
+sub get_doc_type {
+    my $self = shift (@_);
+
+    my $doc_type = $self->get_metadata_element ($self->get_top_section(), "gsdldoctype");
+    return $doc_type if (defined $doc_type);
+    return "indexed_doc";
+}
+
+sub _escape_text {
+    my ($text) = @_;
+
+    # special characters in the gml encoding
+    $text =~ s/&/&amp;/g; # this has to be first...
+    $text =~ s/</&lt;/g;
+    $text =~ s/>/&gt;/g;
+    $text =~ s/\"/&quot;/g;
+
+    return $text;
+}
+
+sub buffer_section_xml {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section ($section);
+    return "" unless defined $section_ptr;
+
+    my $all_text = "<Section>\n";
+    $all_text .= "  <Description>\n";
+    
+    # output metadata
+    foreach my $data (@{$section_ptr->{'metadata'}}) {
+	my $escaped_value = &_escape_text($data->[1]);
+	$all_text .= '    <Metadata name="' . $data->[0] . '">' . $escaped_value . "</Metadata>\n";
+    }
+
+    $all_text .= "  </Description>\n";
+
+    # output the text
+    $all_text .= "  <Content>";
+    $all_text .= &_escape_text($section_ptr->{'text'});
+    $all_text .= "</Content>\n";
+    
+    # output all the subsections
+    foreach my $subsection (@{$section_ptr->{'subsection_order'}}) {
+	$all_text .= $self->buffer_section_xml("$section.$subsection");
+    }
+    
+    $all_text .=  "</Section>\n";
+
+    # make sure no nasty control characters have snuck through
+    # (XML::Parser will barf on anything it doesn't consider to be
+    # valid UTF-8 text, including things like \c@, \cC etc.)
+    $all_text =~ s/[\x00-\x09\x0B\x0C\x0E-\x1F]//g;
+
+    return $all_text;
+}
+
+sub buffer_txt_section_xml {
+    my $self = shift(@_);
+    my ($section) = @_;
+ 
+    my $section_ptr = $self->_lookup_section ($section);
+    
+    return "" unless defined $section_ptr;
+   
+    my $all_text = "<Section>\n";
+   
+    ##output the text
+    #$all_text .= "   <Content>";
+    $all_text .= &_escape_text($section_ptr->{'text'});
+    #$all_text .= "   </Content>\n";
+    
+   
+    #output all the subsections
+    foreach my $subsection (@{$section_ptr->{'subsection_order'}}){
+       $all_text .= $self->buffer_txt_section_xml("$section.$subsection");
+     }
+
+     $all_text .= "</Section>\n";
+
+     
+     $all_text =~ s/[\x00-\x09\x0B\x0C\x0E-\x1F]//g;
+     return $all_text;
+}
+
+sub buffer_mets_fileSection_section_xml() {
+    my $self = shift(@_);
+    my ($section,$version) = @_;
+
+    #$section="" unless defined $section;
+    
+
+    my $section_ptr=$self->_lookup_section($section);
+    return "" unless defined $section_ptr;
+ 
+
+    # output fileSection by sections
+    my $section_num ="1". $section;
+      
+    my $filePath = 'doctxt.xml';
+
+    my $opt_owner_id = "";
+    if ($version eq "fedora") {
+	$opt_owner_id = "OWNERID=\"M\"";
+    }
+
+    # output the fileSection details
+    my $all_text = '  <mets:fileGrp ID="FILEGROUP_PRELUDE' . $section_num . '">'. "\n";
+    $all_text .= "    <mets:file MIMETYPE=\"text/xml\" ID=\"FILE$section_num\" $opt_owner_id >\n";
+    $all_text .= '      <mets:FLocat LOCTYPE="URL" xlink:href="file:'.$filePath.'#xpointer(/Section[';
+    
+    my $xpath = "1".$section;
+    $xpath =~ s/\./]\/Section[/g;
+   
+    $all_text .=  $xpath;
+
+    $all_text .= ']/text())" xlink:title="Hierarchical Document Structure"/>' . "\n";
+    $all_text .= "    </mets:file>\n";
+    $all_text .= "  </mets:fileGrp>\n";
+
+
+    foreach my $subsection (@{$section_ptr->{'subsection_order'}}){
+	$all_text .= $self->buffer_mets_fileSection_section_xml("$section.$subsection",$version);
+    }
+    
+    $all_text =~ s/[\x00-\x09\x0B\x0C\x0E-\x1F]//g;
+
+    return $all_text;
+}
+
+sub buffer_mets_fileWhole_section_xml(){
+    my $self = shift(@_);
+    my ($section,$version,$working_dir) = @_;
+
+    my $section_ptr = $self-> _lookup_section($section);
+    return "" unless defined $section_ptr;
+    
+    my $all_text="" unless defined $all_txt;
+
+    my $fileID=0;
+
+    # Output the fileSection for the whole section
+    #  => get the sourcefile and associative file
+
+    my $id_root = "";
+    my $opt_owner_id = "";    
+
+    if ($version eq "fedora") {
+	$opt_owner_id = "OWNERID=\"M\"";
+    }
+    else {
+	$id_root = "default";
+    }
+
+    if ($version ne "fedora") {
+	$all_text .= "  <mets:fileGrp ID=\"$id_root\">\n";
+    }
+
+    foreach my $data (@{$section_ptr->{'metadata'}}){
+       my $escaped_value = &_escape_text($data->[1]);
+
+       if (($data->[0] eq "gsdlsourcefilename") && ($version ne "fedora")) { 
+          my ($dirPath) = $escaped_value =~ m/^(.*)[\/\\][^\/\\]*$/;
+
+          ++$fileID;	  
+          $all_text .= "    <mets:file MIMETYPE=\"text/xml\" ID=\"$id_root.$fileID\" $opt_owner_id >\n";
+        
+	  $all_text .= '      <mets:FLocat LOCTYPE="URL" xlink:href="file:'.$data->[1].'" />'."\n";
+	  
+          $all_text .= "    </mets:file>\n";
+       }
+       
+       if ($data->[0] eq "gsdlassocfile"){
+	   
+	   $escaped_value =~ m/^(.*?):(.*):(.*)$/;
+	   my $assoc_file = $1;
+	   my $mime_type  = $2;
+	   my $assoc_dir  = $3;
+	   
+	   if ($version eq "fedora") {
+	       $id_root = $assoc_file;
+	       $id_root =~ s/\//_/g;
+	       $all_text .= "  <mets:fileGrp ID=\"$id_root\">\n";
+	   }
+	   
+	   my $assfilePath = ($assoc_dir eq "") ? $assoc_file : "$assoc_dir/$assoc_file";
+	   ++$fileID;
+	   
+	   my $mime_attr   = "MIMETYPE=\"$mime_type\"";
+	   my $xlink_title = "xlink:title=\"$assoc_file\"";
+
+	   my $id_attr;
+	   my $xlink_href;
+
+	   if ($version eq "fedora") {
+	       $id_attr = "ID=\"$id_root.0\"";
+
+	       my $fedora_prefix = $ENV{'FEDORA_PREFIX'};
+	       if (!defined $fedora_prefix) {
+		   $xlink_href  = "xlink:href=\"$assfilePath\"";
+	       }
+	       else
+	       {
+		   my $gsdlhome = $ENV{'GSDLHOME'};
+		   my $gsdl_href = "$working_dir/$assfilePath";
+
+		   $gsdl_href =~ s/^$gsdlhome(\/)?//;
+		   $gsdl_href = "/gsdl/$gsdl_href";
+
+		   my $fserver = $ENV{'FEDORA_HOSTNAME'};
+		   my $fport = $ENV{'FEDORA_SERVER_PORT'};
+
+		   my $fdomain = "http://$fserver:$fport";
+		   $xlink_href  = "xlink:href=\"$fdomain$gsdl_href\"";
+	       }
+
+	       my $top_section = $self->get_top_section();
+	       my $id = $self->get_metadata_element($top_section,"Identifier");
+	   }
+	   else {
+	       $id_attr = "ID=\"$id_root.$fileID\"";
+	       $xlink_href  = "xlink:href=\"$assfilePath\"";
+	   }
+
+	   $all_text .= "    <mets:file $mime_attr $id_attr $opt_owner_id >\n";
+	   $all_text .= "      <mets:FLocat LOCTYPE=\"URL\" $xlink_href $xlink_title />\n";
+	   
+	   $all_text .= "    </mets:file>\n";
+	   
+	   if ($version eq "fedora") {
+	       $all_text .= "  </mets:fileGrp>\n";
+	   }
+	   
+       }
+   }
+    
+    if ($version ne "fedora") {
+	$all_text .= "  </mets:fileGrp>\n";
+    }         
+    
+    $all_text =~ s/[\x00-\x09\x0B\x0C\x0E-\x1F]//g;
+    
+    return $all_text;
+}
+
+sub buffer_mets_StructMapSection_section_xml(){
+    my $self = shift(@_);
+    my ($section, $order_numref) = @_;
+
+    $section="" unless defined $section;
+    
+    
+    my $section_ptr=$self->_lookup_section($section);
+    return "" unless defined $section_ptr;
+
+
+    # output fileSection by Sections
+    my $section_num ="1". $section;
+    my $dmd_num = $section_num;
+
+    ##**output the dmdSection details  
+    #if ($section_num eq "1") {
+    #	$dmd_num = "0";
+    #}
+
+    #**output the StructMap details
+ 
+    my $dmdid_attr = "DM$dmd_num";
+
+    my $all_text = "  <mets:div ID=\"DS$section_num\" TYPE=\"Section\" \n";
+    $all_text .= '      ORDER="'.$$order_numref++.'" ORDERLABEL="'. $section_num .'" '."\n";
+    $all_text .= "      LABEL=\"$section_num\" DMDID=\"$dmdid_attr\">\n";
+   
+    $all_text .= '    <mets:fptr FILEID="FILEGROUP_PRELUDE'.$section_num.'" />'. "\n";
+
+
+    foreach my $subsection (@{$section_ptr->{'subsection_order'}}){
+       $all_text .= $self->buffer_mets_StructMapSection_section_xml("$section.$subsection", $order_numref);
+    }
+    
+    $all_text .= "  </mets:div>\n";
+
+    $all_text =~ s/[\x00-\x09\x0B\x0C\x0E-\x1F]//g;
+
+    return $all_text;
+}
+
+
+sub buffer_mets_StructMapWhole_section_xml(){
+    my $self = shift(@_);
+    my ($section) = @_;
+    
+    my $section_ptr = $self-> _lookup_section($section);
+    return "" unless defined $section_ptr;
+    
+    my $all_text="" unless defined $all_txt;   
+    my $fileID=0;
+    my $order_num = 0;
+
+    $all_text .= '  <mets:div ID="DSAll" TYPE="Document" ORDER="'.$order_num.'" ORDERLABEL="All" LABEL="Whole Documemt" DMDID="DM1">' . "\n";
+  
+    #** output the StructMapSection for the whole section
+    #  get the sourcefile and associative file
+
+    foreach my $data (@{$section_ptr->{'metadata'}}){
+       my $escaped_value = &_escape_text($data->[1]);
+   
+       if ($data->[0] eq "gsdlsourcefilename") { 
+          ++$fileID;
+	  $all_text .= '    <mets:fptr FILEID="default.'.$fileID.'" />'."\n";
+       }
+       
+       if ($data->[0] eq "gsdlassocfile"){
+          ++$fileID;
+	  $all_text .= '    <mets:fptr FILEID="default.'.$fileID. '" />'. "\n";
+       }
+    }
+    $all_text .= "  </mets:div>\n";
+    
+    $all_text =~ s/[\x00-\x09\x0B\x0C\x0E-\x1F]//g;
+    
+    return $all_text;
+}
+
+
+sub buffer_mets_dmdSection_section_xml(){
+    my $self = shift(@_);
+    my ($section,$version) = @_;
+   
+    $section="" unless defined $section;
+    
+    my $section_ptr=$self->_lookup_section($section);
+    return "" unless defined $section_ptr;
+
+    # convert section number
+    my $section_num ="1". $section;
+    my $dmd_num = $section_num;
+
+    # #**output the dmdSection details  
+    # if ($section_num eq "1") {
+    #	$dmd_num = "0";
+    # }
+
+
+    my $all_text = "";
+
+    my $label_attr = "";
+    if ($version eq "fedora") {
+	$all_text .= "<mets:amdSec ID=\"DC\" >\n";
+	$all_text .= "  <mets:techMD ID=\"DC.0\">\n"; # .0 fedora version number?
+
+	$label_attr = "LABEL=\"Dublin Core Metadata\"";
+    }
+    else {
+	print STDERR "***** Check that GROUPID in dmdSec is valid!!!\n";
+	print STDERR "***** Check to see if <techMD> required\n";
+	# if it isn't allowed, go back and set $mdTag = dmdSec/amdSec
+
+	$all_text .= "<mets:dmdSec ID=\"DM$dmd_num\" GROUPID=\"$section_num\">\n";
+    }
+
+    $all_text .= "  <mets:mdWrap $label_attr MDTYPE=\"OTHER\" OTHERMDTYPE=\"gsdl3\" ID=\"gsdl$section_num\">\n";
+    $all_text .= "    <mets:xmlData>\n";
+
+    if ($version eq "fedora") {
+	my $dc_namespace = "";
+	$dc_namespace .= "xmlns:dc=\"http://purl.org/dc/elements/1.1/\"";
+	$dc_namespace .= " xmlns:oai_dc=\"http://www.openarchives.org/OAI/2.0/oai_dc/\">\n";
+
+	$all_text .= "  <oai_dc:dc $dc_namespace>\n";
+
+	$all_text .= $self->buffer_dc_section($section,"oai_dc");
+	$all_text .= "  </oai_dc:dc>\n";
+    }
+    else {
+	foreach my $data (@{$section_ptr->{'metadata'}}){
+	    my $escaped_value = &_escape_text($data->[1]);
+	    $all_text .= '      <gsdl3:Metadata name="'. $data->[0].'">'. $escaped_value. "</gsdl3:Metadata>\n";
+	    if ($data->[0] eq "dc.Title") {
+		$all_text .= '      <gsdl3:Metadata name="Title">'. $escaped_value."</gsdl3:Metadata>\n";
+	    }
+	}
+    }
+   
+    $all_text .= "    </mets:xmlData>\n";
+    $all_text .= "  </mets:mdWrap>\n";
+    
+    if ($version eq "fedora") {
+	$all_text .= "  </mets:techMD>\n";
+	$all_text .= "</mets:amdSec>\n";
+    }
+    else {
+	$all_text .= "</mets:dmdSec>\n";    
+    }
+
+
+    foreach my $subsection (@{$section_ptr->{'subsection_order'}}){
+       $all_text .= $self->buffer_mets_dmdSection_section_xml("$section.$subsection",$version);
+    }
+    
+    $all_text =~ s/[\x00-\x09\x0B\x0C\x0E-\x1F]//g;
+
+    return $all_text;
+}
+
+sub output_section {
+    my $self = shift (@_);
+    my ($handle, $section) = @_;
+
+    print $handle $self->buffer_section_xml($section);
+}
+
+#  print out DSpace dublin_core metadata section
+sub output_dspace_section {
+    my $self = shift (@_);
+    my ($handle, $section) = @_;
+
+    my $section_ptr = $self->_lookup_section ($section);
+    return "" unless defined $section_ptr;
+
+    my $all_text = "<Section>\n";
+    $all_text .= "  <Description>\n";
+    
+    # output metadata
+    foreach my $data (@{$section_ptr->{'metadata'}}) {
+	my $escaped_value = &_escape_text($data->[1]);
+	$all_text .= '    <Metadata name="' . $data->[0] . '">' . $escaped_value . "</Metadata>\n";
+    }
+
+    $all_text .= "  </Description>\n";
+    $all_text .=  "</Section>\n";
+
+    # make sure no nasty control characters have snuck through
+    # (XML::Parser will barf on anything it doesn't consider to be
+    # valid UTF-8 text, including things like \c@, \cC etc.)
+    $all_text =~ s/[\x00-\x09\x0B\x0C\x0E-\x1F]//g;
+
+    return $all_text;
+}
+
+#  print out doctxt.xml file
+sub output_txt_section {
+    my $self = shift (@_);
+    my ($handle, $section) = @_;
+
+    print $handle $self->buffer_txt_section_xml($section);
+}
+
+#  print out docmets.xml file
+sub output_mets_section {
+    my $self = shift(@_);
+    my ($handle, $section, $version, $working_dir) = @_;
+
+    # print out the dmdSection
+    print $handle $self->buffer_mets_dmdSection_section_xml($section, $version);
+
+    print $handle "<mets:fileSec>\n";
+    if ($version eq "fedora") {
+	print $handle "  <mets:fileGrp ID=\"DATASTREAMS\">\n";
+    }
+
+    # print out the fileSection by sections
+    print $handle $self->buffer_mets_fileSection_section_xml($section,$version);
+
+    # print out the whole fileSection
+    print $handle $self->buffer_mets_fileWhole_section_xml($section,$version,$working_dir); 
+
+    if ($version eq "fedora") {
+	print $handle "  </mets:fileGrp>\n";
+    }
+    print $handle "</mets:fileSec>\n";
+  
+    # print out the StructMapSection by sections
+
+    my $struct_type;
+    if ($version eq "fedora") {
+	$struct_type = "fedora:dsBindingMap";
+    }
+    else {
+	$struct_type = "Section";
+    }
+
+    if ($version ne "fedora") {
+	print $handle "<mets:structMap ID=\"Section\" TYPE=\"$struct_type\" LABEL=\"Section\">\n";
+	my $order_num=0;
+	print $handle $self->buffer_mets_StructMapSection_section_xml($section, \$order_num);
+	print $handle "</mets:structMap>\n";
+
+	print $handle '<mets:structMap ID="All" TYPE="Whole Document" LABEL="All">'."\n";
+	print $handle $self->buffer_mets_StructMapWhole_section_xml($section);
+	print $handle "</mets:structMap>\n";
+    }
+  
+}
+
+my $dc_set = { Title => 1,       
+	       Creator => 1, 
+	       Subject => 1, 
+	       Description => 1, 
+	       Publisher => 1, 
+	       Contributors => 1, 
+	       Date => 1, 
+	       Type => 1, 
+	       Format => 1, 
+	       Identifier => 1, 
+	       Source => 1, 
+	       Language => 1, 
+	       Relation => 1, 
+	       Coverage => 1, 
+	       Rights => 1};
+
+
+
+
+# Build up dublin_core metadata.  Priority given to dc.* over ex.*
+
+sub buffer_dc_section {
+    my $self = shift(@_);
+    my ($section, $version) = @_;
+    
+    # build up string of dublin core metadata
+    $section="" unless defined $section;
+    
+    my $section_ptr=$self->_lookup_section($section);
+    return "" unless defined $section_ptr;
+
+    my $explicit_dc = {};
+    my $explicit_ex = {};
+
+    my $all_text="";
+    foreach my $data (@{$section_ptr->{'metadata'}}){
+	my $escaped_value = &_escape_text($data->[1]);
+	if ($data->[0]=~ m/^dc\./) {
+	    $data->[0] =~ tr/[A-Z]/[a-z]/;
+
+	    $data->[0] =~ m/^dc\.(.*)/;
+	    my $dc_element =  $1;
+
+	    if (!defined $explicit_dc->{$dc_element}) {
+		$explicit_dc->{$dc_element} = [];
+	    }
+	    push(@{$explicit_dc->{$dc_element}},$escaped_value);
+
+	    #$all_text .= '   <dcvalue element="'. $data->[0].'" qualifier="#####">'. $escaped_value. "</dcvalue>\n";
+	    if (defined $version && ($version eq "oai_dc")) {
+		$all_text .= "   <dc:$dc_element>$escaped_value</dc:$dc_element>\n";
+	    }
+	    else {
+		$all_text .= '   <dcvalue element="'. $dc_element.'">'. $escaped_value. "</dcvalue>\n";
+	    }
+
+	} 
+	elsif (($data->[0] =~ m/^ex\./) || ($data->[0] !~ m/\./)) {
+	    $data->[0] =~ m/^(ex\.)?(.*)/;
+	    my $ex_element =  $2;
+	    my $lc_ex_element = lc($ex_element);
+
+	    if (defined $dc_set->{$ex_element}) {
+		if (!defined $explicit_ex->{$lc_ex_element}) {
+		    $explicit_ex->{$lc_ex_element} = [];
+		}
+		push(@{$explicit_ex->{$lc_ex_element}},$escaped_value);
+	    }
+	}
+    }
+
+    # go through dc_set and for any element *not* defined in explicit_dc
+    # that do exist in explicit_ex, add it in as metadata
+    foreach my $k ( keys %$dc_set ) {
+	my $lc_k = lc($k);
+
+	if (!defined $explicit_dc->{$lc_k}) {
+	    if (defined $explicit_ex->{$lc_k}) {
+
+		foreach my $v (@{$explicit_ex->{$lc_k}}) {
+		    my $dc_element    = $lc_k;
+		    my $escaped_value = $v;
+
+		    if (defined $version && ($version eq "oai_dc")) {
+			$all_text .= "   <dc:$dc_element>$escaped_value</dc:$dc_element>\n";
+		    }
+		    else {
+			$all_text .= '   <dcvalue element="'. $dc_element.'">'. $escaped_value. "</dcvalue>\n";
+		    }
+		    
+		}
+	    }
+	}
+    }
+
+    if ($all_text eq "") {
+	$all_text .= "   There is no Dublin Core metatdata in this document\n";
+    }	
+    $all_text =~ s/[\x00-\x09\x0B\x0C\x0E-\x1F]//g;
+
+    return $all_text;
+}
+
+
+# Print out dublin_core metadata
+sub output_dc_section {
+    my $self = shift(@_);
+    my ($handle, $section, $version) = @_;
+    
+    my $all_text = $self->buffer_dc_section($section,$version);
+
+    print $handle $all_text;
+}
+
+
+# look up the reference to the a particular section
+sub _lookup_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my ($num);
+    my $sectionref = $self;
+
+    while (defined $section && $section ne "") {
+	($num, $section) = $section =~ /^\.?(\d+)(.*)$/;
+	$num =~ s/^0+(\d)/$1/; # remove leading 0s
+	$section = "" unless defined $section;
+	
+	if (defined $num && defined $sectionref->{'subsections'}->{$num}) {
+	    $sectionref = $sectionref->{'subsections'}->{$num};
+	} else {
+	    return undef;
+	}
+    }
+    
+    return $sectionref;
+}
+
+# calculate OID by hashing the contents of the document
+sub _calc_OID {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    my $osexe = &util::get_os_exe();
+
+    my $hashfile_exe = &util::filename_cat($ENV{'GSDLHOME'},"bin",
+					   $ENV{'GSDLOS'},"hashfile$osexe");
+
+    my $result = "NULL";
+    
+    if (-e "$hashfile_exe") {
+#	$result = `\"$hashfile_exe\" \"$filename\"`;
+	$result = `hashfile$osexe \"$filename\"`;
+	($result) = $result =~ /:\s*([0-9a-f]+)/i;
+
+    } else {
+	print STDERR "doc::_calc_OID $hashfile_exe could not be found\n";
+    }
+    return "HASH$result";
+}
+
+# methods dealing with OID, not groups of them.
+
+# if $OID is not provided one is calculated
+sub set_OID {
+    my $self = shift (@_);
+    my ($OID) = @_;
+    
+    my $use_hash_oid = 0;
+    # if an OID wasn't provided claculate one
+    if (!defined $OID) {
+	$OID = "NULL";
+	if ($self->{'OIDtype'} eq "hash") {
+	    $use_hash_oid = 1;
+	} elsif ($self->{'OIDtype'} eq "incremental") {
+	    $OID = "D" . $OIDcount;
+	    $OIDcount ++;
+	  
+	} elsif ($self->{'OIDtype'} eq "dirname") {
+	    $OID = 'J';
+	    my $filename = $self->get_source_filename();
+	    if (defined($filename)) { # && -e $filename) {
+		$OID = &File::Basename::dirname($filename);
+		if (defined $OID) {
+		    $OID = 'J'.&File::Basename::basename($OID);
+		    $OID =~ s/\.//; #remove any periods
+		} else {
+		    print STDERR "Failed to find base for filename ($filename)...generating hash id\n";
+		    $use_hash_oid = 1;
+		}
+	    } else {
+		print STDERR "Failed to find filename, generating hash id\n";
+		$use_hash_oid = 1;
+	    }    
+	    
+	} elsif ($self->{'OIDtype'} eq "assigned") {
+	    my $identifier = $self->get_metadata_element ($self->get_top_section(), "dc.Identifier");
+	    if (defined $identifier && $identifier ne "") {
+		$OID = "D" . $self->get_metadata_element ($self->get_top_section(), "dc.Identifier");
+		$OID =~ s/\.//; #remove any periods
+	    } else {
+		# need a hash id
+		print STDERR "no dc.Identifier found, generating hash id\n";
+		$use_hash_oid = 1;
+	    }
+	    	    
+	} else {
+	    $use_hash_oid = 1;
+	}
+
+	if ($use_hash_oid) {
+	    
+	    # "hash" OID - feed file to hashfile.exe
+	    #my $filename = $self->get_source_filename();
+	    # we want to use the converted file for hashing if available
+	    # cos its quicker
+	    my $filename = $self->get_filename_for_hashing();
+
+	    # -z: don't want to hash on the file if it is zero size
+	    if (defined($filename) && -e $filename && !-z $filename) {
+		$OID = $self->_calc_OID ($filename);
+	    } else {
+		$filename = &util::get_tmp_filename();
+		if (!open (OUTFILE, ">$filename")) {
+		    print STDERR "doc::set_OID could not write to $filename\n";
+		} else {
+		    $self->output_section('OUTFILE', $self->get_top_section(), 
+					  undef, 1);
+		    close (OUTFILE);
+		}
+		$OID = $self->_calc_OID ($filename);
+		&util::rm ($filename);
+	    }
+	}
+    }
+    $self->set_metadata_element ($self->get_top_section(), "Identifier", $OID);
+}
+
+# this uses hashdoc (embedded c thingy) which is faster but still 
+# needs a little work to be suffiently stable
+sub ___set_OID {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    # if an OID wasn't provided then calculate hash value based on document
+    if (!defined $OID) 
+    {
+	my $hash_text = $self->buffer_section_gml($self->get_top_section(),
+						  undef, 1);
+	my $hash_len = length($hash_text);
+
+        $OID = &hashdoc::buffer($hash_text,$hash_len);
+    }
+
+    $self->set_metadata_element ($self->get_top_section(), "Identifier", $OID);
+}
+
+# returns the OID for this document
+sub get_OID {
+    my $self = shift (@_);
+    my $OID = $self->get_metadata_element ($self->get_top_section(), "Identifier");
+    return $OID if (defined $OID);
+    return "NULL";
+}
+
+sub delete_OID {
+    my $self = shift (@_);
+    
+    $self->set_metadata_element ($self->get_top_section(), "Identifier", "NULL");
+}
+
+
+# methods for manipulating section names
+
+# returns the name of the top-most section (the top
+# level of the document
+sub get_top_section {
+    my $self = shift (@_);
+    
+    return "";
+}
+
+# returns a section
+sub get_parent_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    $section =~ s/(^|\.)\d+$//;
+
+    return $section;
+}
+
+# returns the first child section (or the end child 
+# if there isn't any)
+sub get_begin_child {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    return "" unless defined $section_ptr;
+
+    if (defined $section_ptr->{'subsection_order'}->[0]) {
+	return "$section.$section_ptr->{'subsection_order'}->[0]";
+    }
+
+    return $self->get_end_child ($section);
+}
+
+# returns the next child of a parent section
+sub get_next_child {
+    my $self = shift (@_);
+    my ($section) = @_;
+    
+    my $parent_section = $self->get_parent_section($section);
+    my $parent_section_ptr = $self->_lookup_section($parent_section);
+    return undef unless defined $parent_section_ptr;
+
+    my ($section_num) = $section =~ /(\d+)$/;
+    return undef unless defined $section_num;
+
+    my $i = 0;
+    my $section_order = $parent_section_ptr->{'subsection_order'};
+    while ($i < scalar(@$section_order)) {
+	last if $section_order->[$i] eq $section_num;
+	$i++;
+    }
+
+    $i++; # the next child
+    if ($i < scalar(@$section_order)) {
+	return $section_order->[$i] if $parent_section eq "";
+	return "$parent_section.$section_order->[$i]";
+    }
+
+    # no more sections in this level
+    return undef;
+}
+
+# returns a reference to a list of children
+sub get_children {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    return [] unless defined $section_ptr;
+
+    my @children = @{$section_ptr->{'subsection_order'}};
+
+    map {$_ = "$section.$_"; $_ =~ s/^\.+//;} @children;
+    return \@children;
+}
+
+# returns the child section one past the last one (which
+# is coded as "0")
+sub get_end_child {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    return $section . ".0" unless $section eq "";
+    return "0";
+}
+
+# returns the next section in book order
+sub get_next_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    return undef unless defined $section;
+
+    my $section_ptr = $self->_lookup_section($section);
+    return undef unless defined $section_ptr;
+
+    # first try to find first child
+    if (defined $section_ptr->{'subsection_order'}->[0]) {
+	return $section_ptr->{'subsection_order'}->[0] if ($section eq "");
+	return "$section.$section_ptr->{'subsection_order'}->[0]";
+    }
+
+    do {
+	# try to find sibling
+	my $next_child = $self->get_next_child ($section);
+	return $next_child if (defined $next_child);
+
+	# move up one level
+	$section = $self->get_parent_section ($section);
+    } while $section =~ /\d/;
+
+    return undef;
+}
+
+sub is_leaf_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    return 1 unless defined $section_ptr;
+
+    return (scalar (@{$section_ptr->{'subsection_order'}}) == 0);
+}
+
+# methods for dealing with sections
+
+# returns the name of the inserted section
+sub insert_section {
+    my $self = shift (@_);
+    my ($before_section) = @_;
+
+    # get the child to insert before and its parent section
+    my $parent_section = "";
+    my $before_child = "0";
+    my @before_section = split (/\./, $before_section);
+    if (scalar(@before_section) > 0) {
+	$before_child = pop (@before_section);
+	$parent_section = join (".", @before_section);
+    }
+
+    my $parent_section_ptr = $self->_lookup_section($parent_section);
+    if (!defined $parent_section_ptr) {
+	print STDERR "doc::insert_section couldn't find parent section " .
+	    "$parent_section\n";
+	return;
+    }
+
+    # get the next section number
+    my $section_num = $parent_section_ptr->{'next_subsection'}++;
+
+    my $i = 0;
+    while ($i < scalar(@{$parent_section_ptr->{'subsection_order'}}) &&
+	   $parent_section_ptr->{'subsection_order'}->[$i] ne $before_child) {
+	$i++;
+    }
+    
+    # insert the section number into the order list
+    splice (@{$parent_section_ptr->{'subsection_order'}}, $i, 0, $section_num);
+
+    # add this section to the parent section
+    my $section_ptr = {'subsection_order'=>[],
+		       'next_subsection'=>1,
+		       'subsections'=>{},
+		       'metadata'=>[],
+		       'text'=>""};
+    $parent_section_ptr->{'subsections'}->{$section_num} = $section_ptr;
+
+    # work out the full section number
+    my $section = $parent_section;
+    $section .= "." unless $section eq "";
+    $section .= $section_num;
+    
+    return $section;
+}
+
+# creates a pre-named section
+sub create_named_section {
+    my $self = shift (@_);
+    my ($mastersection) = @_;
+
+    my ($num);
+    my $section = $mastersection;
+    my $sectionref = $self;
+
+    while ($section ne "") {
+	($num, $section) = $section =~ /^\.?(\d+)(.*)$/;
+	$num =~ s/^0+(\d)/$1/; # remove leading 0s
+	$section = "" unless defined $section;
+	
+	if (defined $num) {
+	    if (!defined $sectionref->{'subsections'}->{$num}) {
+		push (@{$sectionref->{'subsection_order'}}, $num);
+		$sectionref->{'subsections'}->{$num} = {'subsection_order'=>[],
+							'next_subsection'=>1,
+							'subsections'=>{},
+							'metadata'=>[],
+							'text'=>""};
+		if ($num >= $sectionref->{'next_subsection'}) {
+		    $sectionref->{'next_subsection'} = $num + 1;
+		}
+	    }
+	    $sectionref = $sectionref->{'subsections'}->{$num};
+
+	} else {
+	    print STDERR "doc::create_named_section couldn't create section ";
+	    print STDERR "$mastersection\n";
+	    last;
+	}
+    }
+}
+
+# returns a reference to a list of subsections
+sub list_subsections {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section ($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::list_subsections couldn't find section $section\n";
+	return [];
+    }
+
+    return [@{$section_ptr->{'subsection_order'}}];
+}
+
+sub delete_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+#    my $section_ptr = {'subsection_order'=>[],
+#		       'next_subsection'=>1,
+#		       'subsections'=>{},
+#		       'metadata'=>[],
+#		       'text'=>""};
+
+    # if this is the top section reset everything
+    if ($section eq "") {
+	$self->{'subsection_order'} = [];
+	$self->{'subsections'} = {};
+	$self->{'metadata'} = [];
+	$self->{'text'} = "";
+	return;
+    }
+
+    # find the parent of the section to delete
+    my $parent_section = "";
+    my $child = "0";
+    my @section = split (/\./, $section);
+    if (scalar(@section) > 0) {
+	$child = pop (@section);
+	$parent_section = join (".", @section);
+    }
+
+    my $parent_section_ptr = $self->_lookup_section($parent_section);
+    if (!defined $parent_section_ptr) {
+	print STDERR "doc::delete_section couldn't find parent section " .
+	    "$parent_section\n";
+	return;
+    }
+
+    # remove this section from the subsection_order list
+    my $i = 0;
+    while ($i < scalar (@{$parent_section_ptr->{'subsection_order'}})) {
+	if ($parent_section_ptr->{'subsection_order'}->[$i] eq $child) {
+	    splice (@{$parent_section_ptr->{'subsection_order'}}, $i, 1);
+	    last;
+	}
+	$i++;
+    }
+
+    # remove this section from the subsection hash
+    if (defined ($parent_section_ptr->{'subsections'}->{$child})) {
+	undef $parent_section_ptr->{'subsections'}->{$child};
+    }
+}
+
+#--
+# methods for dealing with metadata
+
+# set_metadata_element and get_metadata_element are for metadata
+# which should only have one value. add_meta_data and get_metadata
+# are for metadata which can have more than one value.
+
+# returns the first metadata value which matches field
+
+# This version of get metadata element works much like the one above,
+# except it allows for the namespace portion of a metadata element to
+# be ignored, thus if you are searching for dc.Title, the first piece
+# of matching metadata ending with the name Title (once any namespace
+# is removed) would be returned.
+# 28-11-2003 John Thompson
+sub get_metadata_element {
+    my $self = shift (@_);
+    my ($section, $field, $ignore_namespace) = @_;
+    my ($data);
+
+    $ignore_namespace = 0 unless defined $ignore_namespace;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::get_metadata_element couldn't find section ", $section, "\n";
+	return;
+    }
+
+    # Remove the any namespace if we are being told to ignore them
+    if($ignore_namespace) {
+	$field =~ s/^\w*\.//;
+    }
+
+    foreach $data (@{$section_ptr->{'metadata'}}) {
+
+	my $data_name = $data->[0];
+	# Remove the any namespace if we are being told to ignore them
+	if($ignore_namespace) {
+	    $data_name =~ s/^\w*\.//;
+	}
+	
+	return $data->[1] if (scalar(@$data) >= 2 && $data_name eq $field);
+    }
+	
+    return undef; # was not found
+}
+
+# returns a list of the form [value1, value2, ...]
+sub get_metadata {
+    my $self = shift (@_);
+    my ($section, $field, $ignore_namespace) = @_;
+    my ($data);
+
+    $ignore_namespace = 0 unless defined $ignore_namespace;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+        print STDERR "doc::get_metadata couldn't find section ",
+	    $section, "\n";
+        return;
+    }
+
+    # Remove the any namespace if we are being told to ignore them
+    if($ignore_namespace) {
+	$field =~ s/^\w*\.//;
+    }
+
+    my @metadata = ();
+    foreach $data (@{$section_ptr->{'metadata'}}) {
+
+	my $data_name = $data->[0];
+	# Remove the any namespace if we are being told to ignore them
+	if($ignore_namespace) {
+	    $data_name =~ s/^\w*\.//;
+	}
+
+        push (@metadata, $data->[1]) if ($data_name eq $field);
+    }
+
+    return \@metadata;
+}
+
+# returns a list of the form [[field,value],[field,value],...]
+sub get_all_metadata {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::get_all_metadata couldn't find section ", $section, "\n";
+	return;
+    }
+    
+    return $section_ptr->{'metadata'};
+}
+
+# $value is optional
+sub delete_metadata {
+    my $self = shift (@_);
+    my ($section, $field, $value) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::delete_metadata couldn't find section ", $section, "\n";
+	return;
+    }
+
+    my $i = 0;
+    while ($i < scalar (@{$section_ptr->{'metadata'}})) {
+	if (($section_ptr->{'metadata'}->[$i]->[0] eq $field) &&
+	    (!defined $value || $section_ptr->{'metadata'}->[$i]->[1] eq $value)) {
+	    splice (@{$section_ptr->{'metadata'}}, $i, 1);
+	} else {
+	    $i++;
+	}
+    }
+}
+
+sub delete_all_metadata {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::delete_all_metadata couldn't find section ", $section, "\n";
+	return;
+    }
+    
+    $section_ptr->{'metadata'} = [];
+}
+
+sub set_metadata_element {
+    my $self = shift (@_);
+    my ($section, $field, $value) = @_;
+
+    $self->set_utf8_metadata_element ($section, $field, 
+				      &unicode::ascii2utf8(\$value));
+}
+
+# set_utf8_metadata_element assumes the text has already been
+# converted to the UTF-8 encoding.
+sub set_utf8_metadata_element {
+    my $self = shift (@_);
+    my ($section, $field, $value) = @_;
+
+    $self->delete_metadata ($section, $field);
+    $self->add_utf8_metadata ($section, $field, $value);
+}
+
+
+# add_metadata assumes the text is in (extended) ascii form. For
+# text which has already been converted to the UTF-8 format use
+# add_utf8_metadata.
+sub add_metadata {
+    my $self = shift (@_);
+    my ($section, $field, $value) = @_;
+
+    $self->add_utf8_metadata ($section, $field,
+			      &unicode::ascii2utf8(\$value));
+}
+
+sub add_utf8_metadata {
+    my $self = shift (@_);
+    my ($section, $field, $value) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::add_utf8_metadata couldn't find section ", $section, "\n";
+	return;
+    }
+    if (!defined $value) {
+	print STDERR "doc::add_utf8_metadata undefined value for $field\n";
+	return;
+    }
+    if (!defined $field) {
+	print STDERR "doc::add_utf8_metadata undefined metadata type \n";
+	return;
+    }
+    
+    #print STDERR "###$field=$value\n";
+    # double check that the value is utf-8
+    if (unicode::ensure_utf8(\$value)) {
+	print STDERR "doc::add_utf8_metadata: warning: '$field' wasn't utf8\n";
+    }
+
+    push (@{$section_ptr->{'metadata'}}, [$field, $value]);
+}
+
+
+# methods for dealing with text
+
+# returns the text for a section
+sub get_text {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::get_text couldn't find section " .
+	    "$section\n";
+	return "";
+    }
+
+    return $section_ptr->{'text'};
+}
+
+# returns the (utf-8 encoded) length of the text for a section
+sub get_text_length {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::get_text_length couldn't find section " .
+	    "$section\n";
+	return 0;
+    }
+
+    return length ($section_ptr->{'text'});
+}
+
+sub delete_text {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::delete_text couldn't find section " .
+	    "$section\n";
+	return;
+    }
+
+    $section_ptr->{'text'} = "";
+}
+
+# add_text assumes the text is in (extended) ascii form. For
+# text which has been already converted to the UTF-8 format
+# use add_utf8_text.
+sub add_text {
+    my $self = shift (@_);
+    my ($section, $text) = @_;
+
+    # convert the text to UTF-8 encoded unicode characters
+    # and add the text
+    $self->add_utf8_text($section, &unicode::ascii2utf8(\$text));
+}
+
+
+# add_utf8_text assumes the text to be added has already
+# been converted to the UTF-8 encoding. For ascii text use
+# add_text
+sub add_utf8_text {
+    my $self = shift (@_);
+    my ($section, $text) = @_;
+
+    my $section_ptr = $self->_lookup_section($section);
+    if (!defined $section_ptr) {
+	print STDERR "doc::add_utf8_text couldn't find section " .
+	    "$section\n";
+	return;
+    }
+
+    $section_ptr->{'text'} .= $text;
+}
+
+
+# methods for dealing with associated files
+
+# a file is associated with a document, NOT a section.
+# if section is defined it is noted in the data structure
+# only so that files associated from a particular section
+# may be removed later (using delete_section_assoc_files)
+sub associate_file {
+    my $self = shift (@_);
+    my ($real_filename, $assoc_filename, $mime_type, $section) = @_;
+    $mime_type = &ghtml::guess_mime_type ($real_filename) unless defined $mime_type;
+
+    # remove all associated files with the same name
+    $self->delete_assoc_file ($assoc_filename);
+    
+    push (@{$self->{'associated_files'}}, 
+	  [$real_filename, $assoc_filename, $mime_type, $section]);
+}
+
+# returns a list of associated files in the form
+#   [[real_filename, assoc_filename, mimetype], ...]
+sub get_assoc_files {
+    my $self = shift (@_);
+
+    return $self->{'associated_files'};
+}
+
+sub delete_section_assoc_files {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    my $i=0;
+    while ($i < scalar (@{$self->{'associated_files'}})) {
+	if (defined $self->{'associated_files'}->[$i]->[3] &&
+	    $self->{'associated_files'}->[$i]->[3] eq $section) {
+	    splice (@{$self->{'associated_files'}}, $i, 1);
+	} else {
+	    $i++;
+	}
+    }
+}
+
+sub delete_assoc_file {
+    my $self = shift (@_);
+    my ($assoc_filename) = @_;
+
+    my $i=0;
+    while ($i < scalar (@{$self->{'associated_files'}})) {
+	if ($self->{'associated_files'}->[$i]->[1] eq $assoc_filename) {
+	    splice (@{$self->{'associated_files'}}, $i, 1);
+	} else {
+	    $i++;
+	}
+    }
+}
+
+sub reset_nextsection_ptr {
+    my $self = shift (@_);
+    my ($section) = @_;
+    
+    my $section_ptr = $self->_lookup_section($section);
+    $section_ptr->{'next_subsection'} = 1;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/docprint.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/docprint.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/docprint.pm	(revision 10506)
@@ -0,0 +1,67 @@
+###########################################################################
+#
+# docprint.pm
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# This document processor prints a document out to STDOUT
+
+
+package docprint;
+
+use arcinfo;
+use docproc;
+use util;
+
+
+sub BEGIN {
+    @docprint::ISA = ('docproc');
+}
+
+sub new {
+    my ($class) = @_;
+    my $self = new docproc ();
+
+    return bless $self, $class;
+}
+
+sub process {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    # add associated files as metadata to the document
+    my @assoc_files = ();
+    foreach my $assoc_file (@{$doc_obj->get_assoc_files()}) {
+	if (-e $assoc_file->[0]) {
+	    $doc_obj->add_metadata ($doc_obj->get_top_section(), 
+				    "gsdlassocfile", 
+				    "$assoc_file->[1]:$assoc_file->[2]");
+	}
+    }
+    
+    # output document
+    $doc_obj->output_section(STDOUT, $doc_obj->get_top_section(),
+			     undef, undef, 0);
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/docproc.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/docproc.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/docproc.pm	(revision 10506)
@@ -0,0 +1,84 @@
+###########################################################################
+#
+# docproc.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# document processors are used by the document reader plugins
+# to do some processing on some documents
+
+package docproc;
+
+sub new {
+    my ($class) = @_;
+    my $self = {};
+
+    $self->{'OIDtype'} = "hash";
+    $self->{'saveas'} = "GA";  # default
+
+    return bless $self, $class;
+}
+
+sub process {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+
+    die "docproc::process function must be implemented in sub classes\n";
+}
+
+# OIDtype may be "hash" or "incremental" or "dirname" or "assigned"
+sub set_OIDtype {
+    my $self = shift (@_);
+    my ($type) = @_;
+
+    if ($type =~ /^(hash|incremental|dirname|assigned)$/) {
+	$self->{'OIDtype'} = $type;
+    } else {
+	$self->{'OIDtype'} = "hash";
+    }
+}
+
+sub set_saveas {
+    my $self = shift (@_);
+    my ($saveas) = @_;
+
+    $self->{'saveas'} = $saveas;
+
+}
+
+sub set_saveas_version {
+    my $self = shift (@_);
+    my ($saveas_version) = @_;
+
+    $self->{'saveas_version'} = $saveas_version;
+
+}
+
+
+1;
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/docsave.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/docsave.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/docsave.pm	(revision 10506)
@@ -0,0 +1,670 @@
+###########################################################################
+#
+# docsave.pm
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# This document processor saves a document in the 
+# archives directory of a collection (as xml)
+
+use strict;
+no strict 'refs';
+
+package docsave;
+
+eval {require bytes};
+
+use arcinfo;
+use docproc;
+use util;
+
+
+sub BEGIN {
+    @docsave::ISA = ('docproc');
+}
+
+
+sub calcoutputdir 
+{
+    my ($service,$collectdir,$outhandle) = @_;
+
+    my $output_dir = undef;
+
+    if (($service eq "import") || ($service eq "unbuild")) {
+	$output_dir = &util::filename_cat ($collectdir, "archives");
+    }
+    elsif ($service eq "export") {
+	$output_dir = &util::filename_cat($collectdir, "export");
+    }
+    else {
+	print $outhandle "docsave::calcoutputdir did not recognise service ";
+	print $outhandle " '$service'. No output directory set.\n";
+    }
+
+    return $output_dir;
+}
+
+
+sub new {
+    my ($class, $collection, $info, $verbosity, 
+	$gzip, $groupsize, $outhandle, $service, $saveas) = @_;
+    my $self = new docproc ();
+    
+    my $collectdir = $ENV{'GSDLCOLLECTDIR'};
+
+    $outhandle = 'STDERR' unless (defined $outhandle);
+    $service   = "import" unless (defined $service);
+    $saveas    = "GA" unless (defined $saveas);
+    $groupsize = 1 unless (defined $groupsize);
+
+    $self->{'collection'} = $collection;
+
+    $self->{'output_info'} = $info;
+    $self->{'output_dir'} = undef;
+
+    $self->{'verbosity'} = $verbosity;
+    $self->{'gzip'} = $gzip;
+    $self->{'keepimportstructure'} = 0;
+    $self->{'groupsize'} = $groupsize;
+    $self->{'gs_count'}  = 0;
+
+    $self->{'outhandle'} = $outhandle;
+    $self->{'service'}   = $service;
+    $self->{'saveas'}    = $saveas;
+
+    $self->{'sortmeta'} = undef;
+    
+    return bless $self, $class;
+}
+
+
+
+sub setoutputdir 
+{
+    my $self = shift @_;
+    my ($output_dir) = @_;
+
+    &util::mk_all_dir ($output_dir) unless -e $output_dir;
+
+    $self->{'output_dir'} = $output_dir;
+}
+
+sub getoutputinfo 
+{
+    my $self = shift (@_);
+
+    return $self->{'output_info'};
+}
+
+sub getoutputdir 
+{
+    my $self = shift (@_);
+
+    return $self->{'output_dir'};
+}
+
+
+sub set_sortmeta {
+    my $self = shift (@_);
+    my ($sortmeta, $removeprefix, $removesuffix) = @_;
+    
+    $self->{'sortmeta'} = $sortmeta;
+    if (defined ($removeprefix) && $removeprefix ) {
+	$removeprefix =~ s/^\^//; # don't need a leading ^
+	$self->{'removeprefix'} = $removeprefix;
+    }
+    if (defined ($removesuffix) && $removesuffix) {
+	$removesuffix =~ s/\$$//; # don't need a trailing $
+	$self->{'removesuffix'} = $removesuffix;
+    }
+}
+
+sub process {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+ 
+    my $outhandle = $self->{'outhandle'};
+    my $service = $self->{'service'};
+
+    # Define the SaveAs Type
+    my $save_as = $self->{'saveas'};
+    my $collection = $self->{'collection'};
+
+    # set the lastmodified time before we write it out.
+    $doc_obj->set_lastmodified();
+
+    if ($self->{'groupsize'} > 1) {
+	$self->group_process ($doc_obj);
+	return;
+    }
+
+    my $OID = $doc_obj->get_OID();
+    $OID = "NULL" unless defined $OID;
+
+    my $top_section = $doc_obj->get_top_section();
+
+    # get document's directory
+    my $doc_dir = $self->get_doc_dir ($OID, $doc_obj->get_source_filename());
+
+    # groupsize is 1 (i.e. one document per XML file) so sortmeta 
+    # may be used
+    
+    my $output_info = $self->getoutputinfo();
+    return if (!defined $output_info);
+
+    my $output_dir = $self->getoutputdir();
+    my $working_dir = &util::filename_cat ($output_dir, $doc_dir);
+
+    # copy all the associated files, add this information as metadata
+    # to the document
+    if ($save_as eq "DSpace") {
+
+	# Genereate handle file 
+	# (Note: this section of code would benefit from being restructured)
+	my $doc_handle_file = &util::filename_cat ($working_dir, "handle");
+
+	my $env_hp = $ENV{'DSPACE_HANDLE_PREFIX'};
+	my $handle_prefix = (defined $env_hp) ? $env_hp : "123456789";
+
+	if (!open(OUTDOC_HANDLE,">$doc_handle_file")){
+	    print $outhandle "docsave::process could not write collection handle to file $doc_handle_file\n";
+	    return;
+	} 
+
+	my ($handle) = ($doc_dir =~ m/^(.*)\.dir$/);
+	print OUTDOC_HANDLE "$handle_prefix/$handle\n";
+
+	close OUTDOC_HANDLE;
+
+	# Generate contents file
+	my $doc_contents_file = &util::filename_cat ($working_dir, "contents");
+	
+	if (!open(OUTDOC_CONTENTS,">$doc_contents_file")){
+	    print $outhandle "docsave::process could not write collection contents to file $doc_contents_file\n";
+	    return;
+	} 
+	$self->process_assoc_files ($doc_obj, $doc_dir, 'docsave::OUTDOC_CONTENTS');
+
+	close OUTDOC_CONTENTS;
+
+    } else {
+	$self->process_assoc_files ($doc_obj, $doc_dir, '');
+    }
+        
+    # Save the document in the requested 'save_as' format
+
+    if ($save_as eq "GA") {
+
+	my $doc_file = &util::filename_cat ($working_dir, "doc.xml");
+
+	if (!open (OUTDOC, ">$doc_file")) {
+	    print $outhandle "docsave::process could not write to file $doc_file\n";
+	    return;
+	}
+	
+	# save this document
+	$self->output_xml_header('docsave::OUTDOC');
+	$doc_obj->output_section('docsave::OUTDOC',$top_section);
+	$self->output_xml_footer('docsave::OUTDOC');
+	
+	close OUTDOC;
+    } 
+    elsif ($save_as eq "METS") {
+	
+	my $doc_txt_file = &util::filename_cat ($working_dir,"doctxt.xml");	
+
+	if (!open(OUTDOC_TXT, ">$doc_txt_file")){
+	    print $outhandle "docsave::process could not write to file $doc_txt_file\n";
+	    return;
+	}
+	
+	$self->output_txt_xml_header('docsave::OUTDOC_TXT');
+	$doc_obj->output_txt_section('docsave::OUTDOC_TXT', $top_section);
+	$self->output_txt_xml_footer('docsave::OUTDOC_TXT');
+	
+	close OUTDOC_TXT;
+	
+	# Now save the document with metadata and text structure to docmets.xml
+	
+	my $doc_mets_file = &util::filename_cat ($working_dir, "docmets.xml");
+
+	my $doc_title = $doc_obj->get_metadata_element($top_section,"dc.Title");
+	if (!defined $doc_title) {
+	    $doc_title = $doc_obj->get_metadata_element($top_section,"Title");
+	}
+
+	if (!open(OUTDOC_METS,">$doc_mets_file")){
+	    print $outhandle "docsave::process could not write to file $doc_mets_file\n";
+	    return;
+	}
+	
+	my $saveas_version = $self->{'saveas_version'};
+	$self->output_mets_xml_header('docsave::OUTDOC_METS', $OID, $doc_title);
+	$doc_obj->output_mets_section('docsave::OUTDOC_METS',$top_section,$saveas_version,$working_dir);
+	$self->output_mets_xml_footer('docsave::OUTDOC_METS');
+	
+	close OUTDOC_METS;	
+    } 
+    elsif ($save_as eq "DSpace") {
+
+	# Generate dublin_core.xml file
+	my $doc_dc_file = &util::filename_cat ($working_dir, "dublin_core.xml");
+	
+	if (!open(OUTDOC_DC,">$doc_dc_file")){
+	    print $outhandle "docsave::process could not write dublin core to file $doc_dc_file\n";
+	    return;
+	}   
+	
+	my $saveas_version = $self->{'saveas_version'};
+
+	$self->output_dc_xml_header('docsave::OUTDOC_DC', $OID);
+	$doc_obj->output_dc_section('docsave::OUTDOC_DC',$top_section);
+	$self->output_dc_xml_footer('docsave::OUTDOC_DC');
+	
+	close OUTDOC_DC;
+    } else { # save_as isn't one of the recognised types
+	print $outhandle "docsave::process unrecognised saveas type, $save_as\n";
+	return;
+    }
+
+
+    my $short_doc_file;
+
+    if ($save_as eq "GA") {
+	$short_doc_file = util::filename_cat ($doc_dir, "doc.xml");
+    } elsif ($save_as eq "METS") {
+	$short_doc_file = &util::filename_cat ($doc_dir, "docmets.xml");
+    } elsif ($save_as eq "DSpace") {
+	$short_doc_file=&util::filename_cat ($doc_dir, "dublin_core.xml");
+    } else {
+	return;
+    }
+
+    #save for later (for close_file_output())
+    $self->{'short_doc_file'} = $short_doc_file;	
+ 
+    if ($self->{'gzip'}) {
+	my $doc_file = $self->{'gs_filename'};
+	`gzip $doc_file`;
+	$doc_file .= ".gz";
+	$short_doc_file .= ".gz";
+	if (!-e $doc_file) {
+	    print $outhandle "error while gzipping: $doc_file doesn't exist\n";
+	    return 0;
+	}
+    }
+
+    # do the sortmeta thing
+    my ($metadata);	
+    if (defined ($self->{'sortmeta'})) {
+	$metadata = $doc_obj->get_metadata_element($top_section,$self->{'sortmeta'});
+    }
+    if (defined ($metadata) && $metadata) {
+	# do remove prefix/suffix
+	if (defined($self->{'removeprefix'})) {
+	    $metadata =~ s/^$self->{'removeprefix'}//;
+	}
+	if (defined($self->{'removesuffix'})) {
+	    $metadata =~ s/$self->{'removesuffix'}$//;
+	}
+	$metadata = &sorttools::format_metadata_for_sorting($self->{'sortmeta'}, $metadata, $doc_obj);
+    }
+
+    # store reference in the output_info
+    $output_info->add_info($OID, $short_doc_file, undef, $metadata);
+}
+
+      
+sub group_process {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+    
+    my $outhandle = $self->{'outhandle'};
+
+    my $OID = $doc_obj->get_OID();
+    $OID = "NULL" unless defined $OID;
+
+    my $groupsize = $self->{'groupsize'};
+    my $gs_count = $self->{'gs_count'};
+    my $open_new_file = (($gs_count % $groupsize)==0);
+
+    # opening a new file, or document has assoicated files => directory needed
+    if (($open_new_file) || (scalar(@{$doc_obj->get_assoc_files()})>0)) {
+
+	# get document's directory
+	my $doc_dir = $self->get_doc_dir ($OID, $doc_obj->get_source_filename());
+
+	# copy all the associated files, add this information as metadata
+	# to the document
+	$self->process_assoc_files ($doc_obj, $doc_dir);
+
+
+	if ($open_new_file) {
+	    # only if opening new file
+	    my $output_dir = $self->getoutputdir();
+	    my $doc_file 
+		= &util::filename_cat ($output_dir, $doc_dir, "doc.xml");
+	    my $short_doc_file = &util::filename_cat ($doc_dir, "doc.xml");
+	    
+	    if ($gs_count>0)
+	    {
+		return if (!$self->close_file_output());
+	    }
+	    
+	    if (!open (OUTDOC, ">$doc_file")) {
+		print $outhandle "docsave::group_process could not write to file $doc_file\n";
+		return;
+	    }
+	    $self->{'gs_filename'} = $doc_file;
+	    $self->{'gs_short_filename'} = $short_doc_file;
+	    $self->{'gs_OID'} = $OID;
+
+	    $self->output_xml_header('docsave::OUTDOC');
+	}
+    }
+
+    # save this document
+    $doc_obj->output_section('docsave::OUTDOC', $doc_obj->get_top_section());
+
+    $self->{'gs_count'}++;
+}
+
+sub get_doc_dir {
+    my $self = shift (@_);
+    my ($OID, $source_filename) = @_;
+
+    my $service = $self-> {'service'};
+
+    my $working_dir  = $self->getoutputdir();
+    my $working_info = $self->getoutputinfo();
+    return if (!defined $working_info);
+
+    my $doc_info = $working_info->get_info($OID);
+    my $doc_dir = '';
+
+    if (defined $doc_info && scalar(@$doc_info) >= 1) {
+	# this OID already has an assigned directory, use the
+	# same one.
+	$doc_dir = $doc_info->[0];
+	$doc_dir =~ s/\/?((doc(mets)?)|(dublin_core))\.xml(\.gz)?$//;
+    } elsif ($self->{'keepimportstructure'}) {
+	$source_filename = &File::Basename::dirname($source_filename);
+	$source_filename =~ s/[\\\/]+/\//g;
+	$source_filename =~ s/\/$//;
+ 
+	
+	#print STDERR "Source filename: $source_filename; \nImport dir:",$ENV{'GSDLIMPORTDIR'}, "\n";
+	$doc_dir = substr($source_filename, length($ENV{'GSDLIMPORTDIR'}) + 1);
+
+    }
+    if ($doc_dir eq "") {
+	# have to get a new document directory
+
+	if (($service eq "import") || ($service eq "unbuild")) {
+	    my $doc_dir_rest = $OID;
+	    my $doc_dir_num = 0;
+
+	    do {
+		$doc_dir .= "/" if $doc_dir_num > 0;
+		if ($doc_dir_rest =~ s/^(.{1,8})//) {
+		    $doc_dir .= $1;
+		    $doc_dir_num++;
+		}
+	    } while ($doc_dir_rest ne "" && 
+		     ((-d &util::filename_cat ($working_dir, "$doc_dir.dir")) || 
+		      ($working_info->size() >= 1024 && $doc_dir_num < 2)));
+	}
+	else {
+	    # Export formats such as DSpace need the directory structure to
+	    # be flat.  This is simple to arrange (set 'doc_dir' to be the
+	    # documents OID) but breaks Windows 3.1 file system compliance.
+	    # Such a loss is not a big thing in this situation as such
+	    # systems don't run on Windows 3.1 anyway.
+
+	    $doc_dir = $OID;
+	}
+
+
+	$doc_dir .= ".dir";
+	&util::mk_all_dir (&util::filename_cat ($working_dir, $doc_dir));
+    }
+    return $doc_dir;
+}
+
+sub process_assoc_files {
+    my $self = shift (@_);
+    my ($doc_obj, $doc_dir, $handle) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+    my $service = $self->{'service'};
+    my $save_as = $self->{'saveas'};
+
+    my $output_dir = $self->getoutputdir();
+    return if (!defined $output_dir);
+
+    my $working_dir = &util::filename_cat($output_dir, $doc_dir);
+
+    my @assoc_files = ();
+    my $filename;;
+
+    my $source_filename = $doc_obj->get_source_filename();
+
+    my $collect_dir = $ENV{'GSDLCOLLECTDIR'};
+
+    if (defined $collect_dir) {
+	my $dirsep_regexp = &util::get_os_dirsep();
+
+	if ($collect_dir !~ /$dirsep_regexp$/) {
+	    $collect_dir .= &util::get_dirsep(); # ensure there is a slash at the end
+	}
+
+	# This test is never going to fail on Windows -- is this a problem?
+	if ($source_filename !~ /^$dirsep_regexp/) {
+	    $source_filename = &util::filename_cat($collect_dir, $source_filename);
+	}
+    }
+
+
+    if ($save_as eq "DSpace") {
+	my ($tail_filename) = ($source_filename =~ m/\/([^\/\\]*)$/);
+
+	print $handle "$tail_filename\n";
+
+	$filename = &util::filename_cat($working_dir, $tail_filename);
+	&util::hard_link ($source_filename, $filename);
+    }
+           
+    foreach my $assoc_file_rec (@{$doc_obj->get_assoc_files()}) {
+	my ($dir, $afile) = $assoc_file_rec->[1] =~ /^(.*?)([^\/\\]+)$/;
+	$dir = "" unless defined $dir;
+	    
+	
+	my $real_filename = $assoc_file_rec->[0];
+	# for some reasons the image associate file has / before the full path
+	$real_filename =~ s/^\\(.*)/$1/i;
+	if (-e $real_filename) {
+
+
+	    if ($save_as eq "DSpace") {
+		if ($real_filename =~ m/$source_filename$/) {
+		    next;
+		}
+		else {
+		    my $bundle = "bundle:ORIGINAL";
+
+		    if ($afile =~ m/^thumbnail\./) {
+			$bundle = "bundle:THUMBNAIL";
+		    }
+
+		    # Store the associated file to the "contents" file
+		    print $handle "$assoc_file_rec->[1]\t$bundle\n";
+		}
+	    }
+
+	    $filename = &util::filename_cat($working_dir, $afile);
+
+
+	    &util::hard_link ($real_filename, $filename);
+	    
+	    $doc_obj->add_utf8_metadata ($doc_obj->get_top_section(),
+					 "gsdlassocfile",
+					 "$afile:$assoc_file_rec->[2]:$dir");
+	    $doc_obj->set_utf8_metadata_element ($doc_obj->get_top_section(),
+						 "assocfilepath",
+						 "$doc_dir");
+	} elsif ($self->{'verbosity'} > 2) {
+	    print $outhandle "docsave::process couldn't copy the associated file " .
+		"$real_filename to $afile\n";
+	}
+    }
+}
+    
+
+sub close_file_output
+{
+    my ($self) = @_;
+    my $service =$self->{'service'};
+
+    # make sure that the handle has been opened - it won't be if we failed
+    # to import any documents...
+    if (defined(fileno(docsave::OUTDOC))) {
+	$self->output_xml_footer('docsave::OUTDOC');    
+	close OUTDOC;
+    }
+
+    my $OID = $self->{'gs_OID'};
+    my $short_doc_file;
+    # can we use 'short_doc_file' for GA too?
+    if (exists($self->{'saveas'}) && $self->{'saveas'} eq "METS") {
+	$short_doc_file=$self->{'short_doc_file'};
+    } elsif ($self->{'saveas'} eq "GA") { # "GA"
+	$short_doc_file=$self->{'gs_short_filename'};
+    } else { # "DSpace"
+    }
+    
+    if ($self->{'gzip'}) {
+	my $doc_file = $self->{'gs_filename'};
+	`gzip $doc_file`;
+	$doc_file .= ".gz";
+	$short_doc_file .= ".gz";
+	if (!-e $doc_file) {
+	    my $outhandle = $self->{'outhandle'};
+	    print $outhandle "error while gzipping: $doc_file doesn't exist\n";
+	    return 0;
+	}
+    }
+
+    # store reference in output_info
+    my $output_info = $self->getoutputinfo();
+    return 0 if (!defined $output_info);
+    $output_info->add_info($OID, $short_doc_file, undef, undef);
+
+    return 1;
+}
+
+sub output_xml_header {
+    my $self = shift (@_);
+    my ($handle) = @_;
+
+    print $handle '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . "\n";
+   
+    print $handle '<!DOCTYPE Archive SYSTEM "http://greenstone.org/dtd/Archive/1.0/Archive.dtd">' . "\n";
+    print $handle "<Archive>\n";
+}
+
+sub output_xml_footer {
+    my $self = shift (@_);
+    my ($handle) = @_;
+
+    print $handle "</Archive>\n";
+}
+
+sub output_txt_xml_header{
+    my $self = shift (@_);
+    my ($handle) = @_;
+    print $handle '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . "\n";
+    print $handle '<!DOCTYPE Archive SYSTEM "http://greenstone.org/dtd/Archive/1.0/Archive.dtd">' . "\n";
+}
+
+sub output_txt_xml_footer{
+    my $self = shift(@_);
+    my ($handle) = @_;
+    # Nothing needs to be output at present
+}
+
+sub output_mets_xml_header(){
+    my $self = shift(@_);
+    my ($handle, $OID, $doc_title) = @_;
+
+    my $version = $self->{'saveas_version'};
+
+    my $extra_attr = "";
+    if ($version eq "fedora") {	
+	my $fnamespace = $ENV{'FEDORA_PID_NAMESPACE'};
+	my $oid_namespace = (defined $fnamespace) ? $fnamespace : "test";
+
+	$extra_attr = "OBJID=\"$oid_namespace:$OID\" TYPE=\"FedoraObject\" LABEL=\"$doc_title\"";
+    }
+    else {
+	# Greenstone METS profile
+	$extra_attr = "OBJID=\"$OID:2\"";
+    }
+
+
+    print $handle '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . "\n";
+    print $handle '<mets:mets xmlns:mets="http://www.loc.gov/METS/"' . "\n";
+    print $handle '           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' . "\n";
+    print $handle '           xmlns:gsdl3="http://www.greenstone.org/namespace/gsdlmetadata/1.0/"' . "\n";
+    print $handle '           xmlns:xlink="http://www.w3.org/TR/xlink"' ."\n";
+    print $handle '           xsi:schemaLocation="http://www.loc.gov/METS/' . "\n";
+    print $handle '           http://www.loc.gov/standards/mets/mets.xsd' . "\n";
+    print $handle '           http://www.greenstone.org/namespace/gsdlmetadata/1.0/' . "\n";
+    print $handle '           http://www.greenstone.org/namespace/gsdlmetadata/1.0/gsdl_metadata.xsd"' . "\n";
+    print $handle "  $extra_attr>\n";
+
+    if ($version eq "fedora") {
+	print $handle '<mets:metsHdr RECORDSTATUS="A"/>'. "\n"; # A = active
+    }
+
+}
+
+sub output_mets_xml_footer() {
+    my $self = shift(@_);
+    my ($handle) = @_;
+    print $handle '</mets:mets>' . "\n";
+}
+
+sub output_dc_xml_header(){
+    my $self = shift(@_);
+    my ($handle, $OID) = @_;
+
+    print $handle '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' . "\n";
+#    print $handle '<!DOCTYPE Archive SYSTEM "http://greenstone.org/dtd/Archive/1.0/Archive.dtd">'."\n";
+    print $handle '<dublin_core>' . "\n";
+}
+
+sub output_dc_xml_footer() {
+    my $self = shift(@_);
+    my ($handle) = @_;
+    print $handle '</dublin_core>' . "\n";
+}
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/encodings.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/encodings.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/encodings.pm	(revision 10506)
@@ -0,0 +1,113 @@
+###########################################################################
+#
+# encodings.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001 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.
+#
+###########################################################################
+
+# Each encoding supported by the Greenstone build-time software should be
+# specified in the following hash table ($encodings).
+
+package encodings;
+
+# $encodings takes the form:
+# --> identifier --> name      --> The full display name of the encoding.
+#                --> mapfile   --> The ump file associated with the encoding
+#                --> double    --> 1 if it's a double byte encoding
+#                --> converter --> If the encoding needs a specialized conversion
+#                                  routine this is the name of that routine.
+
+$encodings::encodings = {
+    'iso_8859_1' => {'name' => 'Latin1 (western languages)', 'mapfile' => '8859_1.ump'},
+
+    'iso_8859_2' => {'name' => 'Latin2 (central and eastern european languages)',
+		     'mapfile' => '8859_2.ump'},
+
+    'iso_8859_3' => {'name' => 'Latin3', 'mapfile' => '8859_3.ump'},
+
+    'iso_8859_4' => {'name' => 'Latin4', 'mapfile' => '8859_4.ump'},
+
+    'iso_8859_5' => {'name' => 'Cyrillic', 'mapfile' => '8859_5.ump'},
+
+    'iso_8859_6' => {'name' => 'Arabic', 'mapfile' => '8859_6.ump'},
+
+    'iso_8859_7' => {'name' => 'Greek', 'mapfile' => '8859_7.ump'},
+
+    'iso_8859_8' => {'name' => 'Hebrew', 'mapfile' => '8859_8.ump'},
+
+    'iso_8859_9' => {'name' => 'Turkish', 'mapfile' => '8859_9.ump'},
+
+    'iso_8859_15' => {'name' => 'Latin15 (revised western)', 'mapfile' => '8859_15.ump'},
+
+    'windows_1250' => {'name' => 'Windows codepage 1250 (WinLatin2)',
+		       'mapfile' => 'win1250.ump'},
+
+    'windows_1251' => {'name' => 'Windows codepage 1251 (WinCyrillic)',
+		       'mapfile' => 'win1251.ump'},
+
+    'windows_1252' => {'name' => 'Windows codepage 1252 (WinLatin1)',
+		       'mapfile' => 'win1252.ump'},
+
+    'windows_1253' => {'name' => 'Windows codepage 1253 (WinGreek)', 
+		       'mapfile' => 'win1253.ump'},
+
+    'windows_1254' => {'name' => 'Windows codepage 1254 (WinTurkish)',
+		       'mapfile' => 'win1254.ump'},
+
+    'windows_1255' => {'name' => 'Windows codepage 1255 (WinHebrew)', 
+		       'mapfile' => 'win1255.ump'},
+
+    'windows_1256' => {'name' => 'Windows codepage 1256 (WinArabic)', 
+		       'mapfile' => 'win1256.ump'},
+
+    'windows_1257' => {'name' => 'Windows codepage 1257 (WinBaltic)',
+		       'mapfile' => 'win1257.ump'},
+
+    'windows_1258' => {'name' => 'Windows codepage 1258 (Vietnamese)',
+		       'mapfile' => 'win1258.ump'},
+
+    'windows_874' => {'name' => 'Windows codepage 874 (Thai)', 'mapfile' => 'win874.ump'},
+
+    'dos_437' => {'name' => 'DOS codepage 437 (US English)', 'mapfile' => 'dos437.ump'},
+
+    'dos_850' => {'name' => 'DOS codepage 850 (Latin 1)', 'mapfile' => 'dos850.ump'},
+
+    'dos_866' => {'name' => 'DOS codepage 866 (Cyrillic)', 'mapfile' => 'dos866.ump'},
+
+    'koi8_r' => {'name' => 'Cyrillic', 'mapfile' => 'koi8_r.ump'},
+
+    'koi8_u' => {'name' => 'Cyrillic (Ukrainian)', 'mapfile' => 'koi8_u.ump'},
+
+    'iscii_de' => {'name' => 'ISCII Devanagari', 'mapfile' => 'iscii_de.ump'},
+
+    'shift_jis' => {'name' => 'Japanese (Shift-JIS)', 'mapfile' => 'shiftjis.ump',
+		    'converter' => 'shiftjis2unicode'},
+
+    'euc_jp' => {'name' => 'Japanese (EUC)', 'mapfile' => 'euc_jp.ump'},
+
+    'korean' => {'name' => 'Korean (Unified Hangul Code - i.e. a superset of EUC-KR)',
+		 'mapfile' => 'uhc.ump'},
+
+    'gb' => {'name' => 'Chinese Simplified (GB)', 'mapfile' => 'gbk.ump'},
+
+    'big5' => {'name' => 'Chinese Traditional (Big5)', 'mapfile' => 'big5.ump'}
+
+};
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/expinfo.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/expinfo.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/expinfo.pm	(revision 10506)
@@ -0,0 +1,163 @@
+###########################################################################
+#
+# expinfo.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# modified by: Chi-Yu Huang
+# This module stores information about the export directory. At the moment
+# this information just consists of the file name (relative to the
+# directory the export information file is in) and its OID.
+
+# This module assumes there is a one to one correspondance between
+# a file in the export directory and an OID.
+
+
+package expinfo;
+
+sub new {
+    my ($class) = @_;
+    my $self = {'info'=>{},
+		'order'=>[]};
+
+    return bless $self, $class;
+}
+
+sub load_info {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    $self->{'info'} = {};
+ 
+    if (-e $filename) {
+	open (INFILE, $filename) || 
+	    die "expinfo::load_info couldn't read $filename\n";
+
+	my ($line, @line);
+	while (defined ($line = <INFILE>)) {
+	    $line =~ s/\cM|\cJ//g; # remove end-of-line characters
+	    @line = split ("\t", $line); # filename, 
+	    if (scalar(@line) >= 2) {
+		$self->add_info (@line);
+	    }
+	}
+	close (INFILE);
+    }
+}
+
+sub save_info {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    my ($OID, $info);
+
+    open (OUTFILE, ">$filename") || 
+	die "expinfo::save_info couldn't write $filename\n";
+
+    foreach $info (@{$self->get_OID_list()}) {
+	if (defined $info) {
+	    print OUTFILE join("\t", @$info), "\n";
+	}
+    }
+    close (OUTFILE);
+}
+
+sub delete_info {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    if (defined $self->{'info'}->{$OID}) {
+	delete $self->{'info'}->{$OID};
+	
+	my $i = 0;
+	while ($i < scalar (@{$self->{'order'}})) {
+	    if ($self->{'order'}->[$i]->[0] eq $OID) {
+		splice (@{$self->{'order'}}, $i, 1);
+		last;
+	    }
+	    $i ++;
+	}
+    }
+}
+
+sub add_info {
+    my $self = shift (@_);
+    my ($OID, $doc_file, $sortmeta) = @_;
+    $sortmeta = "" unless defined $sortmeta;
+
+    if (! defined($OID)) {
+	# only happens when no files can be processed?
+	return undef;
+    }
+    $self->delete_info ($OID);
+    $self->{'info'}->{$OID} = [$doc_file];
+    push (@{$self->{'order'}}, [$OID, $sortmeta]);
+}
+
+# returns a list of the form [[OID, doc_file], ...]
+sub get_OID_list {
+    my $self = shift (@_);
+
+    my ($OID);
+    my @list = ();
+
+    foreach $OID (sort {$a->[1] cmp $b->[1]} @{$self->{'order'}}) {
+	push (@list, [$OID->[0], $self->{'info'}->{$OID->[0]}->[0]]);
+    }
+    return \@list;
+}
+
+# returns a list of the form [[doc_file, OID], ...]
+sub get_file_list {
+    my $self = shift (@_);
+
+    my ($OID);
+    my @list = ();
+
+    foreach $OID (sort {$a->[1] cmp $b->[1]} @{$self->{'order'}}) {
+	push (@list, [$self->{'info'}->{$OID->[0]}->[0], $OID->[0]]);
+    }
+    return \@list;
+}
+
+
+# returns a list of the form [doc_file]
+sub get_info {
+    my $self = shift (@_);
+    my ($OID) = @_;
+
+    if (defined $self->{'info'}->{$OID}) {
+	return $self->{'info'}->{$OID};
+    }
+
+    return undef;
+}
+
+
+# returns the number of documents so far
+sub size {
+    my $self = shift (@_);
+    return (scalar(@{$self->{'order'}}));
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/gflock.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/gflock.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/gflock.pm	(revision 10506)
@@ -0,0 +1,54 @@
+###########################################################################
+#
+# gflock.pm - an attempt to use flock only on those platforms
+# on which it's supported (i.e. everything but Windows 95/98)
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package gflock;
+
+use Fcntl ':flock';
+
+# returns true if successful (or if OS is a form of windows other than NT)
+sub lock {
+    my ($handle) = @_;
+
+    if ($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT()) {
+	return 1;
+    } else {
+	return flock($handle, LOCK_EX);
+    }
+}
+
+# returns true if successful (or if OS is a form of windows other than NT)
+sub unlock {
+    my ($handle) = @_;
+
+    if ($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT()) {
+	return 1;
+    } else {
+	return flock($handle, LOCK_UN);
+    }
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/ghtml.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/ghtml.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/ghtml.pm	(revision 10506)
@@ -0,0 +1,305 @@
+###########################################################################
+#
+# ghtml.pm -- this used to be called html.pm but it clashed
+# with the existing html module under windows
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package ghtml;
+
+use unicode;
+
+# htmlsafe(TEXT)
+# 
+# Converts SGML meta characters in TEXT to entity references.
+# 
+sub htmlsafe
+{
+    $_[0] =~ s/&/&amp;/osg;
+    $_[0] =~ s/</&lt;/osg;
+    $_[0] =~ s/>/&gt;/osg;
+    $_[0] =~ s/\"/&quot;/osg;
+}
+
+# unescape_html(TEXT)
+# 
+# Converts HTML entities into their original form.
+# 
+sub unescape_html
+{
+    my ($html) = @_;
+
+    $html =~ s/&amp;/&/osg;
+    $html =~ s/&lt;/</osg;
+    $html =~ s/&gt;/>/osg;
+    $html =~ s/&quot;/\"/osg;
+
+    return $html;
+}
+
+# urlsafe(TEXT)
+# 
+# Converts characters not allowed in a URL to their hex representation.
+# 
+sub urlsafe
+{
+    $_[0] =~ s/[\x09\x20\x22\x3c\x3e\x5b\x5c\x5d\x5e\x60\x7b\x7c\x7d\x7e\?\=\&\+_\/]/sprintf("%%%2x", ord($&))/gse;
+}
+
+# dmsafe
+#
+# Converts characters which could make display.pl or html crack to their entity references.
+# Don't use this on dm macros as they will no longer be recognisable by dm (which
+# by the way, is the whole idea).
+# -- Rodger 12/1/98
+sub dmsafe {
+    my ($s) = $_[0];
+    $s =~ s/&/&amp;/osg; # for html
+    $s =~ s/</&lt;/osg;  # for html
+    $s =~ s/>/&gt;/osg;  # for html
+    $s =~ s/\_/&#095;/osg; # for dm (we have a convention of starting macros with _
+    $s =~ s/\"/&quot;/osg; # for html (don't want to be interpreted as a quote)
+    $s =~ s/\{/&#123;/osg; # for dm blocks
+    $s =~ s/\}/&#125;/osg; # for dm blocks
+    $s =~ s/\\/&#092;/osg; # for dm (dm removes naturally occurring backquotes)
+    return $s;
+}
+
+
+# named entry to the standard html font
+my %charnetosf = ("Agrave"=> "192",  "Aacute"=> "193",  "Acirc" => "194",  "Atilde"=> "195",
+	       "Auml"  => "196",  "Aring" => "197",  "AElig" => "198",  "Ccedil"=> "199",
+	       "Egrave"=> "200",  "Eacute"=> "201",  "Ecirc" => "202",  "Euml"  => "203",
+	       "Igrave"=> "204",  "Iacute"=> "205",  "Icirc" => "206",  "Iuml"  => "207",
+	       "ETH"   => "208",  "Ntilde"=> "209",  "Ograve"=> "210",  "Oacute"=> "211",
+	       "Ocirc" => "212",  "Otilde"=> "213",  "Ouml"  => "214",  
+	       "Oslash"=> "216",  "Ugrave"=> "217",  "Uacute"=> "218",  "Ucirc" => "219",
+	       "Uuml"  => "220",  "Yacute"=> "221",  "THORN" => "222",  "szlig" => "223",
+	       "agrave"=> "224",  "aacute"=> "225",  "acirc" => "226",  "atilde"=> "227",
+	       "auml"  => "228",  "aring" => "229",  "aelig" => "230",  "ccedil"=> "231",
+	       "egrave"=> "232",  "eacute"=> "233",  "ecirc" => "234",  "euml"  => "235",
+	       "igrave"=> "236",  "iacute"=> "237",  "icirc" => "238",  "iuml"  => "239",
+	       "eth"   => "240",  "ntilde"=> "241",  "ograve"=> "242",  "oacute"=> "243",
+	       "ocirc" => "244",  "otilde"=> "245",  "ouml"  => "246",  
+	       "oslash"=> "248",  "ugrave"=> "249",  "uacute"=> "250",  "ucirc" => "251",
+	       "uuml"  => "252",  "yacute"=> "253",  "thorn" => "254",  "yuml"  => "255");
+
+my %symnetosf = ("quot"  => "34",   "amp"   => "38",   "lt"    => "60",   "gt"    => "62",
+	      "nbsp"  => "160",  "iexcl" => "161",  "cent"  => "162",  "pound" => "163",
+	      "curren"=> "164",  "yen"   => "165",  "brvbar"=> "166",  "sect"  => "167",
+	      "uml"   => "168",  "copy"  => "169",  "ordf"  => "170",  "laquo" => "171",
+	      "not"   => "172",  "shy"   => "173",  "reg"   => "174",  "macr"  => "175",
+	      "deg"   => "176",  "plusmn"=> "177",  "sup2"  => "178",  "sup3"  => "179",
+	      "acute" => "180",  "micro" => "181",  "para"  => "182",  "middot"=> "183",
+	      "cedil" => "184",  "sup1"  => "185",  "ordm"  => "186",  "raquo" => "187",
+	      "frac14"=> "188",  "frac12"=> "189",  "frac34"=> "190",  "iquest"=> "191",
+	      "times" => "215",  "divide"=> "247");
+
+
+
+# standard font to plain text
+my %sftotxt = ("32"  => " ",  "33"  => "!",  "34"  => "\"",  "35"  => "\#",  "36"  => "\$",
+	    "37"  => "\%", "38"  => "&",  "39"  => "'",   "40"  => "(",   "41"  => ")",
+	    "42"  => "*",  "43"  => "+",  "44"  => ",",   "45"  => "-",   "46"  => ".",
+	    "47"  => "/",  "48"  => "0",  "49"  => "1",   "50"  => "2",   "51"  => "3",
+	    "52"  => "4",  "53"  => "5",  "54"  => "6",   "55"  => "7",   "56"  => "8",
+	    "57"  => "9",  "58"  => ":",  "59"  => ";",   "60"  => "<",   "61"  => "=",
+	    "62"  => ">",  "63"  => "?",  "64"  => "\@",  "65"  => "A",   "66"  => "B",
+	    "57"  => "9",  "58"  => ":",  "59"  => ";",   "61"  => "=",
+	    "63"  => "?",  "64"  => "\@", "65"  => "A",  "66"  => "B",
+	    "67"  => "C",  "68"  => "D",  "69"  => "E",   "70"  => "F",   "71"  => "G",
+	    "72"  => "H",  "73"  => "I",  "74"  => "J",   "75"  => "K",   "76"  => "L",
+	    "77"  => "M",  "78"  => "N",  "79"  => "O",   "80"  => "P",   "81"  => "Q",
+	    "82"  => "R",  "83"  => "S",  "84"  => "T",   "85"  => "U",   "86"  => "V",
+	    "87"  => "W",  "88"  => "X",  "89"  => "Y",   "90"  => "Z",   "91"  => "[",
+	    "92"  => "\\", "93"  => "]",  "94"  => "^",   "95"  => "_",   "96"  => "`",
+	    "97"  => "a",  "98"  => "b",  "99"  => "c",   "100" => "d",   "101" => "e",
+	    "102" => "f",  "103" => "g",  "104" => "h",   "105" => "i",   "106" => "j",
+	    "107" => "k",  "108" => "l",  "109" => "m",   "110" => "n",   "111" => "o",
+	    "112" => "p",  "113" => "q",  "114" => "r",   "115" => "s",   "116" => "t",
+	    "117" => "u",  "118" => "v",  "119" => "w",   "120" => "x",   "121" => "y",
+	    "122" => "z",  "123" => "{",  "124" => "|",   "125" => "}",   "126" => "~",
+	    "130" => ",",  "131" => "f",  "132" => "\"",   "133" => "...", "139" => "<",
+	    "140" => "OE", "145" => "'",  "146" => "'",   "147" => "\"",   "148" => "\"",
+	    "149" => "o",  "150" => "--", "151" => "-",   "152" => "~",   "153" => "TM",
+	    "155" => ">",  "156" => "oe", "159" => "Y",   "160" => " ",   "178" => "2",
+	    "179" => "3",  "185" => "1",  "188" => "1/4", "189" => "1/2", "190" => "3/4",
+	    "192" => "A",  "193" => "A",  "194" => "A",   "195" => "A",   "196" => "A",
+	    "197" => "A",  "198" => "AE", "199" => "C",   "200" => "E",   "201" => "E",
+	    "202" => "E",  "203" => "E",  "204" => "I",   "205" => "I",   "206" => "I",
+	    "207" => "I",  "208" => "D",  "209" => "N",   "210" => "O",   "211" => "O",
+	    "212" => "O",  "213" => "O",  "214" => "O",   "215" => "*",   "216" => "O",
+	    "217" => "U",  "218" => "U",  "219" => "U",   "220" => "U",   "221" => "Y",
+	    "223" => "ss", "224" => "a",  "225" => "a",   "226" => "a",   "227" => "a",
+	    "228" => "a",  "229" => "a",  "230" => "ae",  "231" => "c",   "232" => "e",
+	    "233" => "e",  "234" => "e",  "235" => "e",   "236" => "i",   "237" => "i",
+	    "238" => "i",  "239" => "i",  "241" => "n",   "242" => "o",   "243" => "o",
+	    "244" => "o",  "245" => "o",  "246" => "o",   "247" => "/",   "248" => "o",
+	    "249" => "u",  "250" => "u",  "251" => "u",   "252" => "u",   "253" => "y",
+	    "255" => "y",  "8218" => ",");
+
+
+# returns the character as a raw utf-8 character. It assumes that the
+# & and ; have been stripped off the string.
+sub getcharequiv {
+    my ($entity, $convertsymbols) = @_;
+
+    # a numeric entity
+    if ($entity =~ /^\#0*(\d+)/) {
+	my $code=$1;
+	# non-standard Microsoft breakage, as usual
+	if ($code < 0x9f) { # code page 1252 uses reserved bytes
+	    if ($code == 0x91) {$code=0x2018} # 145 = single left quote
+	    elsif ($code == 0x92) {$code=0x2019} # 146 = single right quote
+	    elsif ($code == 0x93) {$code=0x201c} # 147 = double left quote
+	    elsif ($code == 0x94) {$code=0x201d} # 148 = double right quote
+	    # ...
+	}
+	return &unicode::unicode2utf8([$code]);
+    }
+    
+    # a named character entity
+    if (defined $charnetosf{$entity}) {
+	return &unicode::unicode2utf8([$charnetosf{$entity}]);
+    }
+
+    # a named symbol entity
+    if ($convertsymbols && defined $symnetosf{$entity}) {
+	return &unicode::unicode2utf8([$symnetosf{$entity}]);
+    }
+
+    return "&$entity;"; # unknown character
+}
+
+# convert character entities from named equivalents to html font
+sub convertcharentities {
+    # args: the text that you want to convert
+
+    $_[0] =~ s/&([^;]+);/&getcharequiv($1,0)/gse;
+}
+
+# convert any entities from named equivalents to html font
+sub convertallentities {
+    # args: the text that you want to convert
+
+    $_[0] =~ s/&([^;]+);/&getcharequiv($1,1)/gse;
+}
+
+sub html2txt {
+    # args: the text that you want converted to ascii, 
+    # and whether to strip out sgml tags
+
+    # strip out sgml tags if needed
+    $_[0] =~ s/<[^>]*>//g if $_[1];
+
+    # convert the char entities to the standard html font
+    &convertcharentities($_[0]); 
+    
+    # convert the html character set to a plain ascii character set
+    my $pos = 0;
+    while ($pos < length($_[0])) {
+	my $charnum = ord(substr($_[0], $pos, 1));
+	if ($charnum >= 32) { # only convert characters above #32
+	    my $replacechars = " ";
+	    $replacechars = $sftotxt{$charnum} if defined $sftotxt{$charnum};
+	    substr($_[0], $pos, 1) = $replacechars;
+	    $pos += length ($replacechars);
+
+	} else {
+	    $pos ++;
+	}
+    }
+}  
+
+
+# look for mime.types (eg in /etc, or apache/conf directories), or have a look
+# at <ftp://ftp.iana.org/in-notes/iana/assignments/media-types/> for defaults.
+sub guess_mime_type {
+    my ($filename) = @_;
+
+    my ($fileext) = $filename =~ /\.(\w+)$/;
+    return "unknown" unless defined $fileext;
+
+    my %mime_type = ("ai"=>"application/postscript", "aif"=>"audio/x-aiff", 
+		     "aifc"=>"audio/x-aiff", "aiff"=>"audio/x-aiff", 
+		     "au"=>"audio/basic", "avi"=>"video/x-msvideo",
+		     "bcpio"=>"application/x-bcpio", "bin"=>"application/octet-stream", 
+		     "cdf"=>"application/x-netcdf", "class"=>"application/octet-stream", 
+		     "cpio"=>"application/x-cpio", "cpt"=>"application/mac-compactpro",
+		     "csh"=>"application/x-csh", "dcr"=>"application/x-director", 
+		     "dir"=>"application/x-director", "dms"=>"application/octet-stream", 
+		     "doc"=>"application/msword", "dvi"=>"application/x-dvi",
+		     "dxr"=>"application/x-director", "eps"=>"application/postscript", 
+		     "etx"=>"text/x-setext",
+		     "exe"=>"application/octet-stream", "gif"=>"image/gif",
+		     "gtar"=>"application/x-gtar", "hdf"=>"application/x-hdf",
+		     "hqx"=>"application/mac-binhex40", "htm"=>"text/html",
+		     "html"=>"text/html", "ice"=>"x-conference/x-cooltalk",
+		     "ief"=>"image/ief", "jpe"=>"image/jpeg",
+		     "jpeg"=>"image/jpeg", "jpg"=>"image/jpeg",
+		     "kar"=>"audio/midi", "latex"=>"application/x-latex",
+		     "lha"=>"application/octet-stream", "lzh"=>"application/octet-stream",
+		     "man"=>"application/x-troff-man", "mcf"=>"image/vasa",
+		     "me"=>"application/x-troff-me", "mid"=>"audio/midi",
+		     "midi"=>"audio/midi", "mif"=>"application/x-mif",
+		     "mov"=>"video/quicktime", "movie"=>"video/x-sgi-movie",
+		     "mp2"=>"audio/mpeg", "mpe"=>"video/mpeg",
+		     "mpeg"=>"video/mpeg", "mpg"=>"video/mpeg",
+		     "mpga"=>"audio/mpeg", "ms"=>"application/x-troff-ms",
+		     "nc"=>"application/x-netcdf", "oda"=>"application/oda",
+		     "pbm"=>"image/x-portable-bitmap", "pdb"=>"chemical/x-pdb",
+		     "pdf"=>"application/pdf", "pgm"=>"image/x-portable-graymap",
+		     "png"=>"image/png", "pnm"=>"image/x-portable-anymap",
+		     "ppm"=>"image/x-portable-pixmap",
+		     "ppt"=>"application/vnd.ms-powerpoint",
+		     "ps"=>"application/postscript", "qt"=>"video/quicktime",
+		     "ra"=>"audio/x-realaudio", "ram"=>"audio/x-pn-realaudio",
+		     "ras"=>"image/x-cmu-raster", "rgb"=>"image/x-rgb",
+		     "roff"=>"application/x-troff", "rpm"=>"audio/x-pn-realaudio-plugin",
+		     "rtf"=>"application/rtf", "rtx"=>"text/richtext",
+		     "sgm"=>"text/x-sgml", "sgml"=>"text/x-sgml",
+		     "sh"=>"application/x-sh", "shar"=>"application/x-shar",
+		     "sit"=>"application/x-stuffit", "skd"=>"application/x-koan",
+		     "skm"=>"application/x-koan", "skp"=>"application/x-koan",
+		     "skt"=>"application/x-koan", "snd"=>"audio/basic",
+		     "src"=>"application/x-wais-source", "sv4cpio"=>"application/x-sv4cpio",
+		     "sv4crc"=>"application/x-sv4crc", "t"=>"application/x-troff",
+		     "tar"=>"application/x-tar", "tcl"=>"application/x-tcl",
+		     "tex"=>"application/x-tex", "texi"=>"application/x-texinfo",
+		     "texinfo"=>"application/x-texinfo", "tif"=>"image/tiff",
+		     "tiff"=>"image/tiff", "tr"=>"application/x-troff",
+		     "tsv"=>"text/tab-separated-values", "txt"=>"text/plain",
+		     "ustar"=>"application/x-ustar", "vcd"=>"application/x-cdlink",
+		     "vrml"=>"x-world/x-vrml", "wav"=>"audio/x-wav",
+		     "wrl"=>"x-world/x-vrml", "xbm"=>"image/x-xbitmap",
+		     "xls"=>"application/vnd.ms-excel",
+		     "xpm"=>"image/x-xpixmap", "xwd"=>"image/x-xwindowdump",
+		     "xyz"=>"chemical/x-pdb", "zip"=>"application/zip");
+
+    return $mime_type{$fileext} if (defined $mime_type{$fileext});
+
+    return "unknown";
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/giget.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/giget.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/giget.pm	(revision 10506)
@@ -0,0 +1,263 @@
+
+sub readin_html 
+{
+    my ($html_fname) = @_;
+
+    open(HIN,"<$html_fname") 
+	|| die "Unable to open $html_fname: $!\n";
+    
+    my $html_text;
+    my $line;
+    while (defined ($line=<HIN>)) {
+	$html_text .= $line;
+    }
+    close(HIN);
+
+    return $html_text;
+}
+
+sub stripout_anchortags
+{
+    my ($html_text) = @_;
+
+    my @anchor_tags = ($html_text =~ m/(<a\s+.*?>)+/gs);
+
+    return @anchor_tags;
+} 
+
+
+sub print_tags
+{
+    my (@tags) = @_;
+
+    my $a;
+    foreach $a ( @tags) {
+	print "$a\n";
+    }
+}
+
+sub filter_tags
+{
+    my ($filter_text,@tags) = @_;
+
+    my @filtered_tags = ();
+
+    my $t;
+    foreach $t (@tags) {
+	if ($t =~ m/$filter_text/x) {
+	    push(@filtered_tags,$t);
+	}
+    }
+
+    return @filtered_tags;
+}
+
+sub extract_urls {
+    my (@tags) = @_;
+
+    my @urls = ();
+
+    my $t;
+    foreach $t (@tags) {
+	if ($t =~ m/href=([^ ]+)/i) {
+	    my $url = $1;
+	    $url =~ s/&amp;/&/g;
+	    push(@urls,$url);
+	}
+    }
+
+    return @urls;
+}
+
+sub get_gi_page
+{
+    my ($cgi_base,$cgi_call,$downloadto_fname) = @_;
+
+    my $full_url = "$cgi_base$cgi_call";
+    
+    if ((!-e $downloadto_fname) || (-z $downloadto_fname)) {
+	my $cmd = "wget -nv -T 10 -nc -U \"Mozilla\" -O \"$downloadto_fname\" \"$full_url\"";
+##	print STDERR "*** wget cmd:\n $cmd\n";
+
+    `$cmd`;
+    }
+
+    if (-z $downloadto_fname) { 
+	print STDERR "Warning: downloaded file 0 bytes!\n";
+    }
+}
+
+
+sub parse_gi_search_page 
+{
+    my ($ga_base,$search_term_dir,$downloaded_fname,$currpage_url) = @_;
+
+    my $nextpage_url = undef;
+
+    my @imgref_urls = ();
+
+    my $downloaded_text = readin_html($downloaded_fname);
+    if (defined $downloaded_text) {
+	my @anchor_tags = stripout_anchortags($downloaded_text);
+	
+	my @thumbimg_tags = filter_tags("imgres\\?",@anchor_tags);
+	my @nextpage_tags = filter_tags("images\\?.*?start=\\d+",@anchor_tags);
+	
+	my @thumbimg_urls = extract_urls(@thumbimg_tags);
+	my @nextpage_urls = extract_urls(@nextpage_tags);
+
+	my $curr_start = 0;
+	if ($currpage_url =~ m/start=(\d+)/) {
+	    $curr_start = $1;
+	}
+
+	my $pot_url;
+	foreach $pot_url (@nextpage_urls) {
+	
+	    my ($next_start) = ($pot_url =~ m/start=(\d+)/);
+	    if ($next_start>$curr_start) {
+		$nextpage_url = $pot_url;
+		last;
+	    }
+	}
+
+#	print "-" x 40, "\n";
+	my $c = 1;
+	my $p = 1;
+
+	foreach my $tvu (@thumbimg_urls) {
+	    my ($img_url) = ($tvu =~ m/imgurl=([^&]*)/);
+	    $img_url =~ s/%25/%/g;
+
+	    my ($imgref_url) = ($tvu =~ m/imgrefurl=([^&]*)/);
+##	    print STDERR "****imgref_url = $imgref_url\n";
+	    $imgref_url =~ s/%25/%/g;
+	    
+	    my ($img_ext) = ($img_url =~ m/\.(\w+)$/);
+	    $img_ext = lc($img_ext);
+
+	    # remove http:// if there, so later we can explicitly add it in
+	    $img_url =~ s/^http:\/\///; 
+
+	    print "Downloading image url http://$img_url\n";
+	    my $output_fname = "$search_term_dir/img_$c.$img_ext";
+
+	    get_gi_page("http://",$img_url,$output_fname);
+
+	    if (-s $output_fname == 0) {
+		unlink $output_fname;
+	    }
+	    elsif (system("identify \"$output_fname\"") > 0 ) {
+		print STDERR "**** NOT JPEG: output_fname \n";
+		unlink $output_fname;
+	    }
+	    else {
+
+		my $command = "identify \"$output_fname\" 2>&1";
+		my $result = `$command`;
+
+		my $type =   'unknown';
+		my $width =  'unknown';
+		my $height = 'unknown';
+		
+		my $image_safe = quotemeta $output_fname;
+		if ($result =~ /^$image_safe (\w+) (\d+)x(\d+)/) {
+		    $type = $1;
+		    $width = $2;
+		    $height = $3;
+		}
+
+		if (($width ne "unknown") && ($height ne "unknown")) {
+		    if (($width>200) || ($height>200)) {
+			`convert \"$output_fname\" -resize 200x200 /tmp/x.jpg`;
+			`/bin/mv /tmp/x.jpg \"$output_fname\"`;
+		    }
+		}
+		$c++;
+	    }
+
+	    push(@imgref_urls,$imgref_url);
+
+	    last if ($c==3); # Only take first 2
+
+	    $p++;
+
+	    if ($p==20) {
+		print STDERR "*** Unable to get enough images after 20 passes\n";
+		last;
+	    }
+
+
+	}
+
+	if (defined $nextpage_url) {
+	    print "Next page URL:\n";
+	    print_tags($nextpage_url);
+	}
+#	print "-" x 40, "\n";
+    }
+
+    return ($nextpage_url, \@imgref_urls);
+}
+
+sub make_search_term_safe
+{
+    my ($search_terms) = @_;
+
+    my $search_term_safe = join("+",@$search_terms);
+    $search_term_safe =~ s/\"/%22/g;
+    $search_term_safe =~ s/ /+/g;
+
+    return $search_term_safe;
+}
+
+sub gi_query_url
+{
+    my ($search_term) = @_;
+
+    my $search_term_safe = make_search_term_safe($search_term);
+
+    my $nextpage_url 
+	= "/images?as_filetype=jpg&imgc=color\&ie=UTF-8\&oe=UTF-8\&hl=en\&btnG=Google+Search";
+    $nextpage_url .= "\&q=$search_term_safe";
+
+    return $nextpage_url;
+}
+
+sub gi_url_base
+{
+    return "http://images.google.com";
+}
+
+sub giget
+{
+    my ($search_terms,$output_dir) = @_;
+    my $imgref_urls = [];
+
+    if (!-e $output_dir) {
+	mkdir($output_dir);
+    
+    }
+	
+    print STDERR "Searching Google Images for: ", join(", ",@$search_terms), "\n";
+
+    my $gi_base = gi_url_base();
+    my $nextpage_url = gi_query_url($search_terms);
+    
+    $respage_fname = "$output_dir/respage1.html";
+    get_gi_page($gi_base,$nextpage_url,$respage_fname);
+    
+    ($nextpage_url, $imgref_urls) 
+	= parse_gi_search_page($gi_base,$output_dir,
+			       $respage_fname,$nextpage_url);
+#    else {
+#	print STDERR "  Images already mirrored\n";
+#    }
+
+    print STDERR "-" x 40, "\n";
+
+    return $imgref_urls;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/gsprintf.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/gsprintf.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/gsprintf.pm	(revision 10506)
@@ -0,0 +1,239 @@
+###########################################################################
+#
+# gsprintf.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+use strict;
+no strict 'refs';
+
+package gsprintf;
+require Exporter;
+@gsprintf::ISA=qw(Exporter);
+
+use unicode;
+use util;
+
+@gsprintf::EXPORT_OK = qw'gsprintf'; # functions we can export into namespace
+
+
+# Language-specific resource bundle
+my %specialresourcebundle = ();
+our $specialoutputencoding; # our, so that it can be changed outside.
+
+# Default resource bundle
+my %defaultresourcebundle;
+my $defaultoutputencoding;
+
+# English resource bundle
+my %englishresourcebundle;
+my $englishoutputencoding;
+
+# Ignore the OutputEncoding strings in the resource bundles and output all text in UTF-8
+my $outputstringsinUTF8 = 0;
+
+
+sub gsprintf
+{
+    my ($handle, $text_string, @text_arguments) = @_;
+
+    # Return unless the required arguments were supplied
+    return unless (defined($handle) && defined($text_string));
+
+    # Look up all the strings in the dictionary
+    $text_string =~ s/(\{[^\}]+\})/&lookup_string($1)/eg;
+
+    # Resolve the string arguments using sprintf, then write out to the handle
+    print $handle sprintf($text_string, @text_arguments);
+}
+
+
+sub lookup_string
+{
+    my ($stringkey) = @_;
+    return "" unless defined $stringkey;
+    # Try the language-specific resource bundle first
+    my $utf8string = $specialresourcebundle{$stringkey};
+    my $outputencoding = $specialoutputencoding;
+
+    # Try the default resource bundle next
+    if (!defined($utf8string)) {
+	# Load the default resource bundle if it is not already loaded
+	&load_default_resource_bundle() if (!%defaultresourcebundle);
+
+	$utf8string = $defaultresourcebundle{$stringkey};
+	$outputencoding = $defaultoutputencoding;
+    }
+
+    # Try the English resource bundle last
+    if (!defined($utf8string)) {
+	# Load the English resource bundle if it is not already loaded
+	&load_english_resource_bundle() if (!%englishresourcebundle);
+
+	$utf8string = $englishresourcebundle{$stringkey};
+	$outputencoding = $englishoutputencoding;
+    }
+
+    # No matching string was found, so just return the key
+    if (!defined($utf8string)) {
+	return $stringkey;
+    }
+
+    # Return the string matching the key
+    return $utf8string if (!defined($outputencoding) || $outputstringsinUTF8
+			   || $outputencoding eq "utf8");
+
+    # If an 8-bit output encoding has been defined, encode the string appropriately
+    my $encoded=unicode::unicode2singlebyte(&unicode::utf82unicode($utf8string), $outputencoding);
+    
+    # If we successfully encoded it, return it
+    if ($encoded) { return $encoded }
+
+    # Otherwise, we can't convert to the requested encoding. return the utf8?
+    $specialoutputencoding='utf8';
+    return $utf8string;
+}
+
+
+sub load_language_specific_resource_bundle
+{
+    my $language = shift(@_);
+
+    # Read the specified resource bundle
+    my $resourcebundlehome = &util::filename_cat("$ENV{'GSDLHOME'}", "perllib");
+    my $resourcebundlename = "strings_" . $language . ".rb";
+    my $resourcebundlefile = &util::filename_cat($resourcebundlehome, $resourcebundlename);
+
+    %specialresourcebundle = &read_resource_bundle($resourcebundlefile);
+    return if (!%specialresourcebundle);
+
+    # Read the output encoding to use from the resource bundle
+    if ($ENV{'GSDLOS'} =~ /windows/) {
+	$specialoutputencoding = $specialresourcebundle{"{OutputEncoding.windows}"};
+    }
+    else {
+	# see if there is an encoding set in the appropriate locale env var
+
+	foreach my $envvar ('LC_ALL', 'LANG') {
+	    if (!exists $ENV{$envvar}) { next }
+	    my $locale=$ENV{$envvar};
+	    if ($locale !~ /^\w+\.(.+)$/) { next }
+	    my $enc=lc($1);
+	    $enc =~ s/-/_/g;
+	    if ($enc eq 'utf_8') { $enc='utf8' } # normalise to this name
+	    $specialoutputencoding = $enc;
+	    return;
+	}
+	$specialoutputencoding = $specialresourcebundle{"{OutputEncoding.unix}"};
+    }
+}
+
+
+sub load_default_resource_bundle
+{
+    # Read the default resource bundle
+    my $resourcebundlehome = &util::filename_cat("$ENV{'GSDLHOME'}", "perllib");
+    my $resourcebundlename = "strings.rb";
+    my $resourcebundlefile = &util::filename_cat($resourcebundlehome, $resourcebundlename);
+
+    %defaultresourcebundle = &read_resource_bundle($resourcebundlefile);
+    return if (!%defaultresourcebundle);
+
+    # Read the output encoding to use from the resource bundle
+    if ($ENV{'GSDLOS'} =~ /windows/) {
+	$defaultoutputencoding = $defaultresourcebundle{"{OutputEncoding.windows}"};
+    }
+    else {
+	$defaultoutputencoding = $defaultresourcebundle{"{OutputEncoding.unix}"};
+    }
+}
+
+
+sub load_english_resource_bundle
+{
+    # Ensure the English resource bundle hasn't already been loaded
+    if (%specialresourcebundle && $specialresourcebundle{"{Language.code}"} eq "en") {
+	%englishresourcebundle = %specialresourcebundle;
+	$englishoutputencoding = $specialoutputencoding;
+    }
+    if ($defaultresourcebundle{"{Language.code}"} eq "en") {
+	%englishresourcebundle = %defaultresourcebundle;
+	$englishoutputencoding = $defaultoutputencoding;
+    }
+
+    # Read the English resource bundle
+    my $resourcebundlehome = &util::filename_cat("$ENV{'GSDLHOME'}", "perllib");
+    my $resourcebundlename = "strings_en.rb";
+    my $resourcebundlefile = &util::filename_cat($resourcebundlehome, $resourcebundlename);
+
+    %englishresourcebundle = &read_resource_bundle($resourcebundlefile);
+    return if (!%englishresourcebundle);
+
+    # Read the output encoding to use from the resource bundle
+    if ($ENV{'GSDLOS'} =~ /windows/) {
+	$englishoutputencoding = $englishresourcebundle{"{OutputEncoding.windows}"};
+    }
+    else {
+	$englishoutputencoding = $englishresourcebundle{"{OutputEncoding.unix}"};
+    }
+}
+
+
+sub read_resource_bundle
+{
+    my ($resourcebundlefilepath) = shift(@_);
+
+    # Return an empty hash if the specified resource bundle could not be read
+    return () if (!open(RESOURCE_BUNDLE, "<$resourcebundlefilepath"));
+
+    # Load this resource bundle
+    my @resourcebundlelines = <RESOURCE_BUNDLE>;
+    close(RESOURCE_BUNDLE);
+
+    # Parse the resource bundle
+    my %resourcebundle = ();
+    foreach my $line (@resourcebundlelines) {
+	# Remove any trailing whitespace
+	$line =~ s/(\s*)$//;
+
+	# Ignore comments and empty lines
+	if ($line !~ /^\#/ && $line ne "") {
+	    # Parse key (everything up to the first colon)
+	    $line =~ /^([^:]+):(.+)$/;
+	    my $linekey = "{" . $1 . "}";
+	    my $linetext = $2;
+
+	    # Map key to text
+	    $resourcebundle{$linekey} = $linetext;
+	}
+    }
+
+    return %resourcebundle;
+}
+
+
+sub output_strings_in_UTF8
+{
+    $outputstringsinUTF8 = 1;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/iso639.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/iso639.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/iso639.pm	(revision 10506)
@@ -0,0 +1,339 @@
+# mapping to and from iso 639 two letter language symbols
+
+package iso639;
+
+%fromiso639 = (
+	       'aa' => 'Afar',
+	       'ab' => 'Abkhazian',
+	       'af' => 'Afrikaans',
+	       'am' => 'Amharic',
+	       'ar' => 'Arabic',
+	       'as' => 'Assamese',
+	       'ay' => 'Aymara',
+	       'az' => 'Azerbaijani',
+
+	       'ba' => 'Bashkir',
+	       'be' => 'Byelorussian',
+	       'bg' => 'Bulgarian',
+	       'bh' => 'Bihari',
+	       'bi' => 'Bislama',
+	       'bn' => 'Bengali; Bangla',
+	       'bo' => 'Tibetan',
+	       'br' => 'Breton',
+
+	       'ca' => 'Catalan',
+	       'co' => 'Corsican',
+	       'cs' => 'Czech',
+	       'cy' => 'Welsh',
+
+	       'da' => 'Danish',
+	       'de' => 'German',
+	       'dz' => 'Bhutani',
+
+	       'el' => 'Greek',
+	       'en' => 'English',
+	       'eo' => 'Esperanto',
+	       'es' => 'Spanish',
+	       'et' => 'Estonian',
+	       'eu' => 'Basque',
+
+	       'fa' => 'Persian',
+	       'fi' => 'Finnish',
+	       'fj' => 'Fiji',
+	       'fo' => 'Faroese',
+	       'fr' => 'French',
+	       'fy' => 'Frisian',
+
+	       'ga' => 'Irish',
+	       'gd' => 'Scots Gaelic',
+	       'gl' => 'Galician',
+	       'gn' => 'Guarani',
+	       'gu' => 'Gujarati',
+
+	       'ha' => 'Hausa',
+	       'he' => 'Hebrew',
+	       'hi' => 'Hindi',
+	       'hr' => 'Croatian',
+	       'hu' => 'Hungarian',
+	       'hy' => 'Armenian',
+
+	       'ia' => 'Interlingua',
+	       'id' => 'Indonesian',
+	       'ie' => 'Interlingue',
+	       'ik' => 'Inupiak',
+	       'is' => 'Icelandic',
+	       'it' => 'Italian',
+	       'iu' => 'Inuktitut',
+
+	       'ja' => 'Japanese',
+	       'jv' => 'Javanese',
+
+	       'ka' => 'Georgian',
+	       'kk' => 'Kazakh',
+	       'kl' => 'Greenlandic',
+	       'km' => 'Cambodian',
+	       'kn' => 'Kannada',
+	       'ko' => 'Korean',
+	       'ks' => 'Kashmiri',
+	       'ku' => 'Kurdish',
+	       'ky' => 'Kirghiz',
+
+	       'la' => 'Latin',
+	       'ln' => 'Lingala',
+	       'lo' => 'Laothian',
+	       'lt' => 'Lithuanian',
+	       'lv' => 'Latvian, Lettish',
+
+	       'mg' => 'Malagasy',
+	       'mi' => 'Maori',
+	       'mk' => 'Macedonian',
+	       'ml' => 'Malayalam',
+	       'mn' => 'Mongolian',
+	       'mo' => 'Moldavian',
+	       'mr' => 'Marathi',
+	       'ms' => 'Malay',
+	       'mt' => 'Maltese',
+	       'my' => 'Burmese',
+
+	       'na' => 'Nauru',
+	       'ne' => 'Nepali',
+	       'nl' => 'Dutch',
+	       'no' => 'Norwegian',
+
+	       'oc' => 'Occitan',
+	       'om' => '(Afan) Oromo',
+	       'or' => 'Oriya',
+
+	       'pa' => 'Punjabi',
+	       'pl' => 'Polish',
+	       'ps' => 'Pashto, Pushto',
+	       'pt' => 'Portuguese',
+
+	       'qu' => 'Quechua',
+	       'rm' => 'Rhaeto-Romance',
+	       'rn' => 'Kirundi',
+	       'ro' => 'Romanian',
+	       'ru' => 'Russian',
+	       'rw' => 'Kinyarwanda',
+
+	       'sa' => 'Sanskrit',
+	       'sd' => 'Sindhi',
+	       'sg' => 'Sangro',
+	       'sh' => 'Serbo-Croatian',
+	       'si' => 'Singhalese',
+	       'sk' => 'Slovak',
+	       'sl' => 'Slovenian',
+	       'sm' => 'Samoan',
+	       'sn' => 'Shona',
+	       'so' => 'Somali',
+	       'sq' => 'Albanian',
+	       'sr' => 'Serbian',
+	       'ss' => 'Siswati',
+	       'st' => 'Sesotho',
+	       'su' => 'Sudanese',
+	       'sv' => 'Swedish',
+	       'sw' => 'Swahili',
+
+	       'ta' => 'Tamil',
+	       'te' => 'Tegulu',
+	       'tg' => 'Tajik',
+	       'th' => 'Thai',
+	       'ti' => 'Tigrinya',
+	       'tk' => 'Turkmen',
+	       'tl' => 'Tagalog',
+	       'tn' => 'Setswana',
+	       'to' => 'Tonga',
+	       'tr' => 'Turkish',
+	       'ts' => 'Tsonga',
+	       'tt' => 'Tatar',
+	       'tw' => 'Twi',
+
+	       'ug' => 'Uigur',
+	       'uk' => 'Ukrainian',
+	       'ur' => 'Urdu',
+	       'uz' => 'Uzbek',
+
+	       'vi' => 'Vietnamese',
+	       'vo' => 'Volapuk',
+
+	       'wo' => 'Wolof',
+
+	       'xh' => 'Xhosa',
+
+	       'yi' => 'Yiddish',
+	       'yo' => 'Yoruba',
+
+	       'za' => 'Zhuang',
+	       'zh' => 'Chinese',
+	       'zu' => 'Zulu'
+	       );
+
+%toiso639 = (
+	     'afar' => 'aa',
+	     'abkhazian' => 'ab',
+	     'afrikaans' => 'af',
+	     'amharic' => 'am',
+	     'arabic' => 'ar',
+	     'assamese' => 'as',
+	     'aymara' => 'ay',
+	     'azerbaijani' => 'az',
+
+	     'bashkir' => 'ba',
+	     'byelorussian' => 'be',
+	     'bulgarian' => 'bg',
+	     'bihari' => 'bh',
+	     'bislama' => 'bi',
+	     'bengali' => 'bn',
+	     'bangla' => 'bn',
+	     'tibetan' => 'bo',
+	     'breton' => 'br',
+
+	     'catalan' => 'ca',
+	     'corsican' => 'co',
+	     'czech' => 'cs',
+	     'welsh' => 'cy',
+
+	     'danish' => 'da',
+	     'german' => 'de',
+	     'bhutani' => 'dz',
+
+	     'greek' => 'el',
+	     'english' => 'en',
+	     'esperanto' => 'eo',
+	     'spanish' => 'es',
+	     'estonian' => 'et',
+	     'basque' => 'eu',
+
+	     'persian' => 'fa',
+	     'finnish' => 'fi',
+	     'fiji' => 'fj',
+	     'faroese' => 'fo',
+	     'french' => 'fr',
+	     'frisian' => 'fy',
+
+	     'irish' => 'ga',
+	     'scots_gaelic' => 'gd',
+	     'galician' => 'gl',
+	     'guarani' => 'gn',
+	     'gujarati' => 'gu',
+
+	     'hausa' => 'ha',
+	     'hebrew' => 'he',
+	     'hindi' => 'hi',
+	     'croatian' => 'hr',
+	     'hungarian' => 'hu',
+	     'armenian' => 'hy',
+
+	     'interlingua' => 'ia',
+	     'indonesian' => 'id',
+	     'interlingue' => 'ie',
+	     'inupiak' => 'ik',
+	     'icelandic' => 'is',
+	     'italian' => 'it',
+	     'inuktitut' => 'iu',
+
+	     'japanese' => 'ja',
+	     'javanese' => 'jv',
+
+	     'georgian' => 'ka',
+	     'kazakh' => 'kk',
+	     'greenlandic' => 'kl',
+	     'cambodian' => 'km',
+	     'kannada' => 'kn',
+	     'korean' => 'ko',
+	     'kashmiri' => 'ks',
+	     'kurdish' => 'ku',
+	     'kirghiz' => 'ky',
+
+	     'latin' => 'la',
+	     'lingala' => 'ln',
+	     'laothian' => 'lo',
+	     'lithuanian' => 'lt',
+	     'latvian' => 'lv',
+	     'lettish' => 'lv',
+
+	     'malagasy' => 'mg',
+	     'maori' => 'mi',
+	     'macedonian' => 'mk',
+	     'malayalam' => 'ml',
+	     'mongolian' => 'mn',
+	     'moldavian' => 'mo',
+	     'marathi' => 'mr',
+	     'malay' => 'ms',
+	     'maltese' => 'mt',
+	     'burmese' => 'my',
+
+	     'nauru' => 'na',
+	     'nepali' => 'ne',
+	     'dutch' => 'nl',
+	     'norwegian' => 'no',
+
+	     'occitan' => 'oc',
+	     '(afan)_oromo' => 'om',
+	     'oriya' => 'or',
+
+	     'punjabi' => 'pa',
+	     'polish' => 'pl',
+	     'pashto' => 'ps',
+	     'pushto' => 'ps',
+	     'portuguese' => 'pt',
+
+	     'quechua' => 'qu',
+
+	     'rhaeto-romance' => 'rm',
+	     'kirundi' => 'rn',
+	     'romanian' => 'ro',
+	     'russian' => 'ru',
+	     'kinyarwanda' => 'rw',
+	     
+	     'sanskrit' => 'sa',
+	     'sindhi' => 'sd',
+	     'sangro' => 'sg',
+	     'serbo-croatian' => 'sh',
+	     'singhalese' => 'si',
+	     'slovak' => 'sk',
+	     'slovenian' => 'sl',
+	     'samoan' => 'sm',
+	     'shona' => 'sn',
+	     'somali' => 'so',
+	     'albanian' => 'sq',
+	     'serbian' => 'sr',
+	     'siswati' => 'ss',
+	     'sesotho' => 'st',
+	     'sudanese' => 'su',
+	     'swedish' => 'sv',
+	     'swahili' => 'sw',
+
+	     'tamil' => 'ta',
+	     'tegulu' => 'te',
+	     'tajik' => 'tg',
+	     'thai' => 'th',
+	     'tigrinya' => 'ti',
+	     'turkmen' => 'tk',
+	     'tagalog' => 'tl',
+	     'setswana' => 'tn',
+	     'tonga' => 'to',
+	     'turkish' => 'tr',
+	     'tsonga' => 'ts',
+	     'tatar' => 'tt',
+	     'twi' => 'tw',
+
+	     'uigur' => 'ug',
+	     'ukrainian' => 'uk',
+	     'urdu' => 'ur',
+	     'uzbek' => 'uz',
+
+	     'vietnamese' => 'vi',
+	     'volapuk' => 'vo',
+
+	     'wolof' => 'wo',
+	     
+	     'xhosa' => 'xh',
+
+	     'yiddish' => 'yi',
+	     'yoruba' => 'yo',
+
+	     'zhuang' => 'za',
+	     'chinese' => 'zh',
+	     'zul' => 'zu',
+	     );
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/lang.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/lang.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/lang.pm	(revision 10506)
@@ -0,0 +1,201 @@
+###########################################################################
+#
+# lang.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# this module translates language descriptions to and from
+# the ISO 639 standard
+
+package lang;
+
+@lang::trans = (["ab", "Abkhazian"],      ["om", "Afan Oromo"],
+	  ["om", "Oromo"],          ["aa", "Afar"],
+	  ["af", "Afrikaans"],      ["sq", "Albanian"],
+	  ["am", "Amharic"],        ["ar", "Arabic"],
+	  ["hy", "Armenian"],       ["as", "Assamese"],
+	  ["ay", "Aymara"],         ["az", "Azerbaijani"],
+
+	  ["ba", "Bashkir"],        ["eu", "Basque"],
+	  ["bn", "Bengali"],        ["bn", "Bangla"],
+	  ["dz", "Bhutani"],        ["bh", "Bihari"],
+	  ["bi", "Bislama"],        ["br", "Breton"],
+	  ["bg", "Bulgarian"],      ["my", "Burmese"],
+	  ["be", "Byelorussian"],
+
+	  ["km", "Cambodian"],      ["ca", "Catalan"],
+	  ["zh", "Chinese"],        ["co", "Corsican"],
+	  ["hr", "Croatian"],       ["cs", "Czech"],
+
+	  ["da", "Danish"],         ["nl", "Dutch"],
+
+	  ["en", "English"],        ["eo", "Esperanto"],
+	  ["et", "Estonian"],       ["fo", "Faroese"],
+	  ["fj", "Fijian"],         ["fi", "Finnish"],
+	  ["fr", "French"],         ["fy", "Frisian"],
+
+	  ["gl", "Galician"],       ["ka", "Georgian"],
+	  ["de", "German"],         ["el", "Greek"],
+	  ["kl", "Greenlandic"],    ["gn", "Guarani"],
+	  ["gu", "Gujarati"],
+
+	  ["ha", "Hausa"],          ["iw", "Hebrew"],
+	  ["hi", "Hindi"],          ["hu", "Hungarian"],
+
+	  ["is", "Icelandic"],      ["in", "Indonesian"],
+	  ["ia", "Interlingua"],    ["ie", "Interlingue"],
+	  ["ik", "Inupiak"],        ["ga", "Irish"],
+	  ["it", "Italian"],
+
+	  ["ja", "Japanese"],       ["jv", "Javanese"],
+
+	  ["kn", "Kannada"],        ["ks", "Kashmiri"],
+	  ["kk", "Kazakh"],         ["rw", "Kinyarwanda"],
+	  ["ky", "Kirghiz"],        ["rn", "Kirundi"],
+	  ["ko", "Korean"],         ["ku", "Kurdish"],
+
+	  ["lo", "Laothian"],       ["la", "Latin"],
+	  ["lv", "Latvian"],        ["lv", "Lettish"],
+	  ["ln", "Lingala"],        ["lt", "Lithuanian"],
+
+	  ["mk", "Macedonian"],     ["mg", "Malagasy"],
+	  ["ms", "Malay"],          ["ml", "Malayalam"],
+	  ["mt", "Maltese"],        ["mi", "Maori"],
+	  ["mr", "Marathi"],        ["mo", "Moldavian"],
+	  ["mn", "Mongolian"],
+
+	  ["na", "Nauru"],          ["ne", "Nepali"],
+	  ["no", "Norwegian"],
+
+	  ["oc", "Occitan"],        ["or", "Oriya"],
+
+	  ["ps", "Pashto"],         ["ps", "Pushto"],
+	  ["fa", "Persian"],        ["pl", "Polish"],
+	  ["pt", "Portuguese"],     ["pa", "Punjabi"],
+
+	  ["qu", "Quechua"],
+
+	  ["rm", "Rhaeto-Romance"], ["ro", "Romanian"],
+	  ["ru", "Russian"],
+
+	  ["sm", "Samoan"],         ["sg", "Sangho"],
+	  ["sa", "Sanskrit"],       ["gd", "Scots Gaelic"],
+	  ["sr", "Serbian"],        ["sh", "Serbo-Croatian"],
+	  ["st", "Sesotho"],        ["tn", "Setswana"],
+	  ["sn", "Shona"],          ["sd", "Sindhi"],
+	  ["si", "Singhalese"],     ["ss", "Siswati"],
+	  ["sk", "Slovak"],         ["sl", "Slovenian"],
+	  ["so", "Somali"],         ["es", "Spanish"],
+	  ["su", "Sundanese"],      ["sw", "Swahili"],
+	  ["sv", "Swedish"],
+
+	  ["tl", "Tagalog"],        ["tg", "Tajik"],
+	  ["ta", "Tamil"],          ["tt", "Tatar"],
+	  ["te", "Telugu"],         ["th", "Thai"],
+	  ["bo", "Tibetan"],        ["ti", "Tigrinya"],
+	  ["to", "Tonga"],          ["ts", "Tsonga"],
+	  ["tr", "Turkish"],        ["tk", "Turkmen"],
+	  ["tw", "Twi"],
+
+	  ["uk", "Ukrainian"],      ["ur", "Urdu"],
+	  ["uz", "Uzbek"],
+
+	  ["vi", "Vietnamese"],     ["vo", "Volapuk"],
+
+	  ["cy", "Welsh"],          ["wo", "Wolof"],
+
+	  ["xh", "Xhosa"],
+
+	  ["ji", "Yiddish"],        ["yo", "Yoruba"],
+
+	  ["zu", "Zulu"]);
+
+
+sub one_english_to_iso639 {
+    my ($english) = @_;
+    my $iso639 = "";
+
+    foreach my $lang (@lang::trans) {
+	my $code = $lang->[0];
+	my $enname = $lang->[1];
+	if ($english =~ /^\s*($code|$enname)\s*$/i) {
+	    # found the language
+	    $iso639 = $code;
+	    last;
+
+	}
+    }
+
+    return $iso639;
+}
+
+
+sub english_to_iso639 {
+    my ($englishlist) = @_;
+    my ($english);
+
+    my @englishlist = split (",", $englishlist);
+    my @iso639list = ();
+
+    foreach my $english (@englishlist) {
+	push (@iso639list, &one_english_to_iso639($english));
+    }
+
+    return join (",", @iso639list);
+}
+
+
+sub one_iso639_to_english {
+    my ($iso639) = @_;
+    my $english = "";
+
+    foreach my $lang (@lang::trans) {
+	my $code = $lang->[0];
+	my $enname = $lang->[1];
+	if ($iso639 =~ /\s*($code|$enname)\s*$/i) {
+	    # found the language
+	    $english = $enname;
+	    last;
+
+	}
+    }
+
+    return $english;
+}
+
+
+sub iso639_to_english {
+    my ($iso639list) = @_;
+    my ($iso639);
+
+    my @iso639list = split (",", $iso639list);
+    my @englishlist = ();
+
+    foreach $iso639 (@iso639list) {
+	push (@englishlist, &one_iso639_to_english($iso639));
+    }
+
+    return join (",", @englishlist);
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/lucenebuilder.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/lucenebuilder.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/lucenebuilder.pm	(revision 10506)
@@ -0,0 +1,312 @@
+###########################################################################
+#
+# lucenebuilder.pm -- perl wrapper for building index with Lucene
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package lucenebuilder;
+
+# Use same basic XML structure setup by mgppbuilder/mgppbuildproc
+
+use mgppbuilder; 
+
+sub BEGIN {
+    @lucenebuilder::ISA = ('mgppbuilder');
+}
+
+
+sub new {
+    my $class = shift(@_);
+    my ($collection, $source_dir, $build_dir, $verbosity, 
+	$maxdocs, $debug, $keepold, $allclassifications, 
+	$outhandle, $no_text, $gli) = @_;
+
+    my $self = new mgppbuilder (@_);
+    $self = bless $self, $class;
+
+    $self->{'buildtype'} = "lucene";
+
+    return $self;
+}
+
+sub default_buildproc {
+    my $self  = shift (@_);
+
+    return "lucenebuildproc";
+}
+
+# this writes a nice version of the text docs
+sub compress_text {
+
+    my $self = shift (@_);
+    my ($textindex) = @_;
+    my $outhandle = $self->{'outhandle'};
+    print STDERR "Saving the document text\n";
+    # the text directory
+    my $text_dir = &util::filename_cat($self->{'build_dir'}, "text");
+    my $build_dir = &util::filename_cat($self->{'build_dir'},"");
+    &util::mk_all_dir ($text_dir);
+
+    my $osextra = "";
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$text_dir =~ s@/@\\@g;
+    } else {
+	if ($outhandle ne "STDERR") {
+	    # so lucene_passes doesn't print to stderr if we redirect output
+	    $osextra .= " 2>/dev/null";
+	}
+    }
+	
+
+    # get any os specific stuff
+    my $scriptdir = "$ENV{'GSDLHOME'}/bin/script";
+
+    my $lucene_passes_exe = &util::filename_cat($scriptdir, "lucene_passes.pl");
+    my $full_lucene_passes_exe = $lucene_passes_exe;
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$full_lucene_passes_exe = "perl.exe -S \"$lucene_passes_exe\"";
+    }
+    my $lucene_passes_sections = "Doc";
+
+    my ($handle);
+
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$lucene_passes_exe" || 
+	    !open (PIPEOUT, "| $full_lucene_passes_exe text $lucene_passes_sections \"$build_dir\" \"dummy\"   $osextra")) {
+	    print STDERR "<FatalError name='NoRunLucenePasses'/>\n</Stage>\n" if $self->{'gli'};
+	    die "lucenebuilder::build_index - couldn't run $lucene_passes_exe\n";
+	}
+	$handle = lucenebuilder::PIPEOUT;
+    }
+    my $levels = $self->{'levels'};
+    my $gdbm_level = "document";
+    if ($levels->{'section'}) {
+	$gdbm_level = "section";
+    }
+
+    undef $levels->{'paragraph'}; # get rid of para if we had it.
+    # set up the document processr
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($textindex);
+    $self->{'buildproc'}->set_indexing_text (0);
+    $self->{'buildproc'}->set_store_text(1);
+    $self->{'buildproc'}->set_indexfieldmap ($self->{'indexfieldmap'});
+    $self->{'buildproc'}->set_levels ($levels);                       
+    $self->{'buildproc'}->set_gdbm_level ($gdbm_level);                       
+    $self->{'buildproc'}->reset();
+    &plugin::begin($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   $self->{'buildproc'}, $self->{'maxdocs'});    
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'}, 0, $self->{'gli'});
+    &plugin::end($self->{'pluginfo'});
+    close ($handle) unless $self->{'debug'};
+    close PIPEOUT;
+    $self->print_stats();
+
+    print STDERR "</Stage>\n" if $self->{'gli'};
+
+}
+
+sub build_indexes {
+    my $self = shift (@_);
+    my ($indexname) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $indexes = [];
+    if (defined $indexname && $indexname =~ /\w/) {
+	push @$indexes, $indexname;
+    } else {
+	$indexes = $self->{'collect_cfg'}->{'indexes'};
+    }
+
+    # create the mapping between the index descriptions 
+    # and their directory names (includes subcolls and langs)
+    $self->{'index_mapping'} = $self->create_index_mapping ($indexes);
+
+    # build each of the indexes
+    foreach $index (@$indexes) {
+	if ($self->want_built($index)) {
+
+	    my $idx = $self->{'index_mapping'}->{$index};
+	    foreach my $level (keys %{$self->{'levels'}}) {
+		next if $level =~ /paragraph/; # we don't do para indexing
+		my ($pindex) = $level =~ /^(.)/;
+		# should probably check that new name with level 
+		# is unique ... but currently (with doc sec and para)
+		# each has unique first letter.
+		$self->{'index_mapping'}->{$index} = $pindex.$idx;
+
+		my $llevel = $mgppbuilder::level_map{$level};
+		print $outhandle "\n*** building index $index at level $llevel in subdirectory " . 
+		    "$self->{'index_mapping'}->{$index}\n" if ($self->{'verbosity'} >= 1);
+		print STDERR "<Stage name='Index' source='$index' level=$llevel>\n" if $self->{'gli'};
+
+		$self->build_index($index,$llevel);
+	    }
+	    $self->{'index_mapping'}->{$index} = $idx;
+
+	} else {
+	    print $outhandle "\n*** ignoring index $index\n" if ($self->{'verbosity'} >= 1);
+	}
+    }
+
+    #define the final field lists
+    $self->make_final_field_list();
+}
+
+sub build_index {
+    my $self = shift (@_);
+    my ($index,$llevel) = @_;
+    my $outhandle = $self->{'outhandle'};
+    my $build_dir = $self->{'build_dir'};
+
+    # get the full index directory path and make sure it exists
+    my $indexdir = $self->{'index_mapping'}->{$index};
+    &util::mk_all_dir (&util::filename_cat($build_dir, $indexdir));
+
+    # get any os specific stuff
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $scriptdir = "$ENV{'GSDLHOME'}/bin/script";
+
+    my $exe = &util::get_os_exe ();
+    my $lucene_passes_exe = &util::filename_cat($scriptdir, "lucene_passes.pl");
+    my $full_lucene_passes_exe = $lucene_passes_exe;
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$full_lucene_passes_exe = "perl.exe -S \"$lucene_passes_exe\"";
+    }
+
+    # define the section names for lucenepasses
+    # define the section names and possibly the doc name for lucenepasses
+    my $lucene_passes_sections = $llevel;
+
+    my $opt_create_index = ($self->{'keepold'}) ? "" : "-create";
+
+    my $osextra = "";
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$build_dir =~ s@/@\\@g;
+    } else {
+	if ($outhandle ne "STDERR") {
+	    # so lucene_passes doesn't print to stderr if we redirect output
+	    $osextra .= " 2>/dev/null";
+	}
+    }
+ 
+    # get the index expression if this index belongs
+    # to a subcollection
+    my $indexexparr = [];
+    my $langarr = [];
+
+    # there may be subcollection info, and language info. 
+    my ($fields, $subcollection, $language) = split (":", $index);
+    my @subcollections = ();
+    @subcollections = split /,/, $subcollection if (defined $subcollection);
+
+    foreach $subcollection (@subcollections) {
+	if (defined ($self->{'collect_cfg'}->{'subcollection'}->{$subcollection})) {
+	    push (@$indexexparr, $self->{'collect_cfg'}->{'subcollection'}->{$subcollection});
+	} 
+    }
+    
+    # add expressions for languages if this index belongs to
+    # a language subcollection - only put languages expressions for the 
+    # ones we want in the index
+    
+    my @languages = ();
+    my $language_metadata = "Language";
+    if (defined ($self->{'collect_cfg'}->{'language_metadata'})) {
+	$language_metadata = $self->{'collect_cfg'}->{'language_metadata'};
+    }
+    @languages = split /,/, $language if (defined $language);
+    foreach my $language (@languages) {
+	my $not=0;
+	if ($language =~ s/^\!//) {
+	    $not = 1;
+	}
+	if($not) {
+	    push (@$langarr, "!$language");
+	} else {
+	    push (@$langarr, "$language");
+	}
+    }
+
+    # Build index dictionary. Uses verbatim stem method
+    print $outhandle "\n    creating index dictionary (lucene_passes -I1)\n"  if ($self->{'verbosity'} >= 1);
+    print STDERR "<Phase name='CreatingIndexDic'/>\n" if $self->{'gli'};
+    my ($handle);
+
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$lucene_passes_exe" || 
+	    !open (PIPEOUT, "| $full_lucene_passes_exe $opt_create_index index $lucene_passes_sections \"$build_dir\" \"$indexdir\"   $osextra")) {
+	    print STDERR "<FatalError name='NoRunLucenePasses'/>\n</Stage>\n" if $self->{'gli'};
+	    die "lucenebuilder::build_index - couldn't run $lucene_passes_exe\n";
+	}
+	$handle = lucenebuilder::PIPEOUT;
+    }
+	
+    my $store_levels = $self->{'levels'};
+    my $gdbm_level = "document";
+    if ($store_levels->{'section'}) {
+	$gdbm_level = "section";
+    }
+    
+    my $dom_level = "";
+    foreach my $key (keys %$store_levels) {
+	if ($mgppbuilder::level_map{$key} eq $llevel) {
+	    $dom_level = $key;
+	}
+    }
+    if ($dom_level eq "") {
+	print STDERR "Warning: unrecognized tag level $llevel\n";
+	$dom_level = "document";
+    }
+
+    my $local_levels = { $dom_level => 1 }; # work on one level at a time
+
+    # set up the document processr
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($index, $indexexparr);
+    $self->{'buildproc'}->set_index_languages ($language_metadata, $langarr) if (defined $language);
+    $self->{'buildproc'}->set_indexing_text (1);
+    $self->{'buildproc'}->set_store_text(1);
+    $self->{'buildproc'}->set_indexfieldmap ($self->{'indexfieldmap'});
+    $self->{'buildproc'}->set_levels ($local_levels);                       
+    $self->{'buildproc'}->set_gdbm_level($gdbm_level);
+    $self->{'buildproc'}->reset();
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'}, 0, $self->{'gli'});
+    close ($handle) unless $self->{'debug'};
+
+    $self->print_stats();
+
+    $self->{'buildproc'}->set_levels ($store_levels);                       
+    print STDERR "</Stage>\n" if $self->{'gli'};
+}   
+
+1;
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/lucenebuildproc.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/lucenebuildproc.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/lucenebuildproc.pm	(revision 10506)
@@ -0,0 +1,333 @@
+###########################################################################
+#
+# lucenebuildproc.pm -- perl wrapper for building index with Lucene
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package lucenebuildproc;
+
+# This document processor outputs a document
+# for lucene to process
+
+# Use same basic XML structure setup by mgppbuilder/mgppbuildproc
+
+use mgppbuildproc; 
+use ghtml;
+
+sub BEGIN {
+    @lucenebuildproc::ISA = ('mgppbuildproc');
+}
+
+
+sub new {
+    my $class = shift @_;
+    my $self = new mgppbuildproc (@_);
+
+    return bless $self, $class;
+}
+
+
+sub is_incremental_capable
+{
+    my $self = shift (@_);
+
+    # Unlike MG and MGPP, Lucene supports incremental building
+    return 1;
+}
+
+
+sub preprocess_text {
+    my $self = shift (@_);
+    my ($text, $strip_html, $para) = @_;
+
+    my ($outtext) = "";
+    if ($strip_html) { 
+	while ($text =~ /<([^>]*)>/ && $text ne "") {
+	    
+	    my $tag = $1;
+	    $outtext .= $`." "; #add everything before the matched tag
+	    $text = $'; #'everything after the matched tag
+	    if ($para && $tag =~ /^\s*p\s/i) {
+		$outtext .= $para;
+	    }
+	    elsif ($tag =~ /^pre$/) { # a pre tag
+		$text =~ /<\/pre>/; # find the closing pre tag
+		my $tmp_text = $`; #everything before the closing pre tag
+		$text = $'; #'everything after the </pre>
+		$tmp_text =~ s/[<>]//g; # remove all < and >
+		$outtext.= $tmp_text . " ";
+	    }
+	}
+    
+	$outtext .= $text; # add any remaining text
+    } #if strip_html
+    else {
+	$outtext = $text;
+    }
+    #if ($para) {
+	#$text =~ s/(<p\b)/$para$1/gi;
+	#return $text;
+    #}
+
+    # remove entities
+    $outtext =~ s/&\w{1,10};//g; 
+
+    return $outtext;
+}
+
+sub text {
+    my $self = shift (@_);
+    my ($doc_obj,$file) = @_;
+    my $handle = $self->{'output_handle'};
+    my $outhandle = $self->{'outhandle'};
+    my $indexed_doc = 1;
+
+    # only output this document if it is one to be indexed
+    return if ($doc_obj->get_doc_type() ne "indexed_doc");
+
+    # see if this document belongs to this subcollection
+    foreach my $indexexp (@{$self->{'indexexparr'}}) {
+	$indexed_doc = 0;
+	my ($field, $exp, $options) = split /\//, $indexexp;
+	if (defined ($field) && defined ($exp)) {
+	    my ($bool) = $field =~ /^(.)/;
+	    $field =~ s/^.// if $bool eq '!';
+	    if ($field =~ /^filename$/i) {
+		$field = $doc_obj->get_source_filename();
+	    } else {
+		$field = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $field);
+	    }
+	    next unless defined $field;
+	    if ($bool eq '!') {
+		if ($options =~ /^i$/i) {
+		    if ($field !~ /$exp/i) {$indexed_doc = 1; last;}
+		} else {
+		    if ($field !~ /$exp/) {$indexed_doc = 1; last;}
+		}
+	    } else {
+		if ($options =~ /^i$/i) {
+		    if ($field =~ /$exp/i) {$indexed_doc = 1; last;}
+		} else {
+		    if ($field =~ /$exp/) {$indexed_doc = 1; last;}
+		}
+	    }
+	}
+    }
+
+    # if this doc is so far in the sub collection, and we have lang info, 
+    # now we check the languages to see if it matches
+    if($indexed_doc && defined $self->{'lang_meta'}) {
+	$indexed_doc = 0;
+	my $field = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $self->{'lang_meta'});
+	if (defined $field) {
+	    foreach my $lang (@{$self->{'langarr'}}) {
+		my ($bool) = $lang =~ /^(.)/;
+		if ($bool eq '!') {
+		    $lang =~ s/^.//;
+		    if ($field !~ /$lang/) {
+			$indexed_doc = 1; last;
+		    }
+		} else {
+		    if ($field =~ /$lang/) {
+			$indexed_doc = 1; last;
+		    }
+		}
+	    }
+	} 
+    }
+
+    # this is another document
+    $self->{'num_docs'} += 1;
+
+    # get the parameters for the output
+    # split on : just in case there is subcoll and lang stuff
+    my ($fields) = split (/:/, $self->{'index'});
+
+    my $doc_level = $mgppbuildproc::level_map{'document'};
+    my $gs2ns = 'xmlns:gs2="http://www.greenstone.org/gs2"';
+
+    my $levels = $self->{'levels'};
+    my $ldoc_level = $levels->{'document'};
+    my $lsec_level = $levels->{'section'};
+    my $lpar_level = $levels->{'paragraph'};
+
+    my $docid="";
+    if ($ldoc_level) {
+	if ($self->{'gdbm_level'} eq 'document') {
+	    my $doc_sec_num = $self->{'num_docs'};	
+	    $docid = "gs2:id=\"$doc_sec_num\"";
+	} else  {
+	    # default is section level
+	    my $doc_sec_num = $self->{'num_sections'}+1;	
+	    $docid = "gs2:id=\"$doc_sec_num\"";
+	}
+    }
+    my $documenttag = "<$doc_level $gs2ns file=\"$file\" $docid >\n";
+    my $documentendtag = "\n</$doc_level>\n";
+    
+    my ($sectiontag) = "";    
+    if ($lsec_level) {
+	$sectiontag = $mgppbuildproc::level_map{'section'};
+    }
+    my ($parastarttag) = "";
+    my ($paraendtag) = "";
+    if ($self->{'levels'}->{'paragraph'}) {
+	if ($self->{'strip_html'}) {
+	    $parastarttag = "<".$mgppbuildproc::level_map{'paragraph'}.">";
+	    $paraendtag = "</".$mgppbuildproc::level_map{'paragraph'}.">";
+	} else {
+	    print $outhandle "Paragraph level can not be used with no_strip_html!. Not indexing Paragraphs.\n";
+	}
+    }
+    
+    my $doc_section = 0; # just for this document
+
+    my $text = "";
+    $text .= $documenttag;
+    # get the text for this document
+    my $section = $doc_obj->get_top_section();
+    while (defined $section) {
+	# update a few statistics
+	$doc_section++;
+	$self->{'num_sections'} += 1;
+ 
+	if ($sectiontag ne "") {
+	    my $secid = "gs2:id=\"".$self->{'num_sections'}."\"";	    
+	    $text .= "\n<$sectiontag $secid >\n";
+	}
+
+	# if we are doing subcollections, then some docs shouldn't be indexed.
+	# but we need to put the section tag placeholders in there so the 
+	# sections match up with gdbm db
+	if ($indexed_doc) {
+	    #if ($self->{'indexing_text'}) {
+	#	$text .= "$parastarttag"; # only add para tags for indexing
+		# note that we assume that metadata will not be asked for for the compressed text, so we add para tags without checking for indexing_text
+	   # }
+	    $self->{'num_bytes'} += $doc_obj->get_text_length ($section);
+	    foreach my $field (split (/,/, $fields)) {
+		# only deal with this field if it doesn't start with top or
+		# this is the first section
+		my $real_field = $field;
+		if (!($real_field =~ s/^top//) || ($doc_section == 1)) {
+		    my $new_text = ""; 
+		    my $tmp_text = "";
+		    if ($real_field eq "text") {
+			if ($self->{'indexing_text'}) { #tag the text with <Text>...</Text>, add the <Paragraph> tags and strip out html if needed
+			    $new_text .= "$parastarttag<TX index=\"1\">\n";
+			    $tmp_text .= $doc_obj->get_text ($section);
+			    if ($parastarttag =~ "") {
+				# we don't want to individually tag each paragraph if not doing para indexing
+				$tmp_text = $self->preprocess_text($tmp_text, $self->{'strip_html'}, "");
+			    } else {
+				$tmp_text = $self->preprocess_text($tmp_text, $self->{'strip_html'}, "</TX>$paraendtag$parastarttag<TX index=\"1\">");
+			    }
+			    
+			    $new_text .= "$tmp_text</TX>$paraendtag\n";
+			    #if (!defined $self->{'indexfields'}->{'TextOnly'}) {
+				#$self->{'indexfields'}->{'TextOnly'} = 1;   
+			    #}
+			}
+			else { # leave html stuff in, but escape the tags, and dont add Paragraph tags - never retrieve paras at the moment
+			    if ($self->{'store_text'}) {
+				$tmp_text .= $doc_obj->get_text ($section);
+				&ghtml::htmlsafe($tmp_text);
+				$new_text .= $tmp_text;
+			    }
+			}
+		    } else { # metadata field
+			if ($real_field eq "allfields") { #ignore
+			}
+			elsif ($real_field eq "metadata") { # insert all metadata 
+			    #except gsdl stuff
+			    my $shortname = "";
+			    my $metadata = $doc_obj->get_all_metadata ($section);
+			    foreach $pair (@$metadata) {
+				my ($mfield, $mvalue) = (@$pair);
+				# check fields here, maybe others dont want - change to use dontindex!!
+				if ($mfield ne "Identifier" 
+				    && $mfield !~ /^gsdl/ 
+				    && $mfield ne "classifytype"
+				    && $mfield ne "assocfilepath"
+				    && defined $mvalue && $mvalue ne "") {
+				    
+				    if (defined $self->{'indexfieldmap'}->{$mfield}) {
+					$shortname = $self->{'indexfieldmap'}->{$mfield};
+				    }
+				    else {
+					$shortname = $self->create_shortname($mfield);
+					$self->{'indexfieldmap'}->{$mfield} = $shortname;
+					$self->{'indexfieldmap'}->{$shortname} = 1;
+				    }	   
+				    $new_text .= "$parastarttag<$shortname index=\"1\">$mvalue</$shortname>$paraendtag\n";
+				    if (!defined $self->{'indexfields'}->{$mfield}) {
+					$self->{'indexfields'}->{$mfield} = 1;
+				    }				    
+				}
+			    }
+			    
+			}
+			else { #individual metadata specified
+			    my $shortname="";
+			    #if (!defined $self->{'indexfields'}->{$real_field}) {
+				#$self->{'indexfields'}->{$real_field} = 1;
+			    #}
+			    if (defined $self->{'indexfieldmap'}->{$real_field}) {
+				$shortname = $self->{'indexfieldmap'}->{$real_field};
+			    }
+			    else {
+				$shortname = $self->create_shortname($real_field);
+				$self->{'indexfieldmap'}->{$real_field} = $shortname;
+				$self->{'indexfieldmap'}->{$shortname} = 1;
+			    }
+			    my @section_metadata = @{$doc_obj->get_metadata ($section, $real_field)};
+			    if ($self->{'indexing_text'} && defined ($self->{'sections_index_document_metadata'})) {
+				if ($self->{'sections_index_document_metadata'} eq "always" || ( scalar(@section_metadata) == 0 && $self->{'sections_index_document_metadata'} eq "unless_section_metadata_exists")) {
+				    push (@section_metadata, @{$doc_obj->get_metadata ($doc_obj->get_top_section(), $real_field)});
+				}
+			    }
+			    foreach $item (@section_metadata) {
+				$new_text .= "$parastarttag<$shortname index=\"1\">$item</$shortname>$paraendtag\n";
+				# remove entities
+				$new_text =~ s/&\w{1,10};//g; 
+			    }
+			}
+
+		    }
+		    
+		    # filter the text
+		    $self->filter_text ($field, $new_text);
+		    $self->{'num_processed_bytes'} += length ($new_text);
+		    $text .= "$new_text";
+		}
+	    }
+	} # if (indexed_doc)
+	
+	$text .= "\n</$sectiontag>\n" if ($sectiontag ne "");
+
+	$section = $doc_obj->get_next_section($section);
+    } #while defined section
+    print $handle "$text\n$documentendtag"; 
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/mgbuilder.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/mgbuilder.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/mgbuilder.pm	(revision 10506)
@@ -0,0 +1,515 @@
+###########################################################################
+#
+# mgbuilder.pm -- MGBuilder object
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package mgbuilder;
+
+use basebuilder;
+use classify;
+use cfgread;
+use colcfg;
+use plugin;
+use util;
+use FileHandle;
+
+BEGIN {
+    @mgbuilder::ISA = ('basebuilder');
+}
+
+
+my %wanted_index_files = ('td'=>1,
+		       't'=>1,
+		       'idb'=>1,
+		       'ib1'=>1,
+		       'ib2'=>1,
+		       'ib3'=>1,
+		       'i'=>1,
+		       'ip'=>1,
+		       'tiw'=>1,
+		       'wa'=>1);
+
+my $maxdocsize = $basebuilder::maxdocsize;
+
+
+sub new {
+    my $class = shift(@_);
+
+    my ($collection, $source_dir, $build_dir, $verbosity, 
+	$maxdocs, $debug, $keepold, $remove_empty_classifications, 
+	$outhandle, $no_text, $failhandle, $gli) = @_;
+
+    my $self = new basebuilder (@_);
+    $self = bless $self, $class;
+
+    $self->{'buildtype'} = "mg";
+    return $self;
+}
+
+sub default_buildproc {
+    my $self  = shift (@_);
+
+    return "mgbuildproc";
+}
+
+sub generate_index_list {
+    my $self = shift (@_);
+
+    if (!defined($self->{'collect_cfg'}->{'indexes'})) {
+	$self->{'collect_cfg'}->{'indexes'} = [];
+    }
+    if (scalar(@{$self->{'collect_cfg'}->{'indexes'}}) == 0) {
+	# no indexes have been specified so we'll build a "dummy:text" index
+	push (@{$self->{'collect_cfg'}->{'indexes'}}, "dummy:text");	
+    }
+
+}
+
+
+sub compress_text {
+    my $self = shift (@_);
+    my ($textindex) = @_;
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $exe = &util::get_os_exe ();
+    my $mg_passes_exe = &util::filename_cat($exedir, "mg_passes$exe");
+    my $mg_compression_dict_exe = &util::filename_cat($exedir, "mg_compression_dict$exe");
+    my $outhandle = $self->{'outhandle'};
+
+    my $maxnumeric = 4;
+    if (defined($self->{'collect_cfg'}->{'maxnumeric'}) &&
+	$self->{'collect_cfg'}->{'maxnumeric'} =~ /^\d+$/) {
+	$maxnumeric = $self->{'collect_cfg'}->{'maxnumeric'};
+    }
+
+    &util::mk_all_dir (&util::filename_cat($self->{'build_dir'}, "text"));
+    my $basefilename = "text/$self->{'collection'}";
+    my $fulltextprefix = &util::filename_cat ($self->{'build_dir'}, $basefilename);
+
+    my $osextra = "";
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$fulltextprefix =~ s@/@\\@g;
+    } else {
+	$osextra = " -d /";
+    }
+
+    print $outhandle "\n*** creating the compressed text\n" if ($self->{'verbosity'} >= 1);
+    print STDERR "<Stage name='CompressText'>\n" if $self->{'gli'};
+
+    # collect the statistics for the text
+    # -b $maxdocsize sets the maximum document size to be 12 meg
+    print $outhandle "\n    collecting text statistics\n"  if ($self->{'verbosity'} >= 1);
+    print STDERR "<Phase name='CollectTextStats'/>\n" if $self->{'gli'};
+
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$mg_passes_exe" || 
+	    !open (PIPEOUT, "| mg_passes$exe -f \"$fulltextprefix\" -b $maxdocsize -T1 -M $maxnumeric $osextra")) {
+	    print STDERR "<FatalError name='NoRunMGPasses'>\n</Stage>\n" if $self->{'gli'};
+	    die "mgbuilder::compress_text - couldn't run $mg_passes_exe\n";
+	}
+	$handle = mgbuilder::PIPEOUT;
+    }
+
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($textindex);
+    $self->{'buildproc'}->set_indexing_text (0);
+
+
+    if ($self->{'no_text'}) {
+	$self->{'buildproc'}->set_store_text(0);
+    } else {
+	$self->{'buildproc'}->set_store_text(1);
+    }
+    $self->{'buildproc'}->reset();
+
+    &plugin::begin($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   $self->{'buildproc'}, $self->{'maxdocs'});
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'}, 0, $self->{'gli'});
+    &plugin::end($self->{'pluginfo'});
+    
+
+    close ($handle) unless $self->{'debug'};
+
+    $self->print_stats();
+
+    # create the compression dictionary
+    # the compression dictionary is built by assuming the stats are from a seed
+    # dictionary (-S), if a novel word is encountered it is spelled out (-H),
+    # and the resulting dictionary must be less than 5 meg with the most frequent
+    # words being put into the dictionary first (-2 -k 5120)
+    if (!$self->{'debug'}) {
+	print $outhandle "\n    creating the compression dictionary\n"  if ($self->{'verbosity'} >= 1);
+	print STDERR "<Phase name='CreatingCompress'/>\n" if $self->{'gli'};
+	if (!-e "$mg_compression_dict_exe") {
+	    die "mgbuilder::compress_text - couldn't run $mg_compression_dict_exe\n";
+	}
+	system ("mg_compression_dict$exe -f \"$fulltextprefix\" -S -H -2 -k 5120 $osextra");
+
+	# -b $maxdocsize sets the maximum document size to be 12 meg
+	if (!-e "$mg_passes_exe" || 
+	    !open ($handle, "| mg_passes$exe -f \"$fulltextprefix\" -b $maxdocsize -T2 -M $maxnumeric $osextra")) {
+	    print STDERR "<FatalError name='NoRunMGPasses'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgbuilder::compress_text - couldn't run $mg_passes_exe\n";
+	}
+    }
+    else {
+	print STDERR "<Phase name='SkipCreatingComp'/>\n" if $self->{'gli'};
+    }
+
+    $self->{'buildproc'}->reset();
+    # compress the text
+    print $outhandle "\n    compressing the text\n"  if ($self->{'verbosity'} >= 1);
+    print STDERR "<Phase name='CompressingText'/>\n" if $self->{'gli'};
+
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'}, 0, $self->{'gli'});
+
+    close ($handle) unless $self->{'debug'};
+
+    $self->print_stats();
+    print STDERR "</Stage>\n" if $self->{'gli'};
+}
+
+
+# creates directory names for each of the index descriptions
+sub create_index_mapping {
+    my $self = shift (@_);
+    my ($indexes) = @_;
+
+    my %mapping = ();
+    $mapping{'indexmaporder'} = [];
+    $mapping{'subcollectionmaporder'} = [];
+    $mapping{'languagemaporder'} = [];
+    
+    # dirnames is used to check for collisions. Start this off
+    # with the manditory directory names
+    my %dirnames = ('text'=>'text',
+		    'extra'=>'extra');
+    my %pnames = ('index' => {}, 'subcollection' => {}, 'languages' => {});
+    foreach my $index (@$indexes) {
+	my ($level, $gran, $subcollection, $languages) = split (":", $index);
+
+	# the directory name starts with the first character of the index level
+	my ($pindex) = $level =~ /^(.)/;
+
+	# next comes a processed version of the index
+	$pindex .= $self->process_field ($gran); 
+	$pindex = lc ($pindex);
+
+	# next comes a processed version of the subcollection if there is one.
+	my $psub = $self->process_field ($subcollection);
+	$psub = lc ($psub);
+
+	# next comes a processed version of the language if there is one.
+	my $plang = $self->process_field ($languages);
+	$plang = lc ($plang);
+
+	my $dirname = $pindex . $psub . $plang;
+
+	# check to be sure all index names are unique
+	while (defined ($dirnames{$dirname})) {
+	    $dirname = $self->make_unique (\%pnames, $index, \$pindex, \$psub, \$plang);
+	}
+	$mapping{$index} = $dirname;
+
+	# store the mapping orders as well as the maps
+	# also put index, subcollection and language fields into the mapping thing - 
+	# (the full index name (eg document:text:subcol:lang) is not used on
+	# the query page) -these are used for collectionmeta later on
+	if (!defined $mapping{'indexmap'}{"$level:$gran"}) {
+	    $mapping{'indexmap'}{"$level:$gran"} = $pindex;
+	    push (@{$mapping{'indexmaporder'}}, "$level:$gran");
+	    if (!defined $mapping{"$level:$gran"}) {
+		$mapping{"$level:$gran"} = $pindex;
+	    }
+	}
+	if ($psub =~ /\w/ && !defined ($mapping{'subcollectionmap'}{$subcollection})) {
+	    $mapping{'subcollectionmap'}{$subcollection} = $psub;
+	    push (@{$mapping{'subcollectionmaporder'}}, $subcollection);
+	    $mapping{$subcollection} = $psub;
+	}
+	if ($plang =~ /\w/ && !defined ($mapping{'languagemap'}{$languages})) {
+	    $mapping{'languagemap'}{$languages} = $plang;
+	    push (@{$mapping{'languagemaporder'}}, $languages);
+	    $mapping{$languages} = $plang;
+	}
+	$dirnames{$dirname} = $index;
+	$pnames{'index'}->{$pindex} = "$level:$gran";
+	$pnames{'subcollection'}->{$psub} = $subcollection;
+	$pnames{'languages'}->{$plang} = $languages;
+    }
+
+    return \%mapping;
+}
+
+
+sub make_unique {
+    my $self = shift (@_);
+    my ($namehash, $index, $indexref, $subref, $langref) = @_;
+    my ($level, $gran, $subcollection, $languages) = split (":", $index);
+
+    if ($namehash->{'index'}->{$$indexref} ne "$level:$gran") {
+	$self->get_next_version ($indexref);
+    } elsif ($namehash->{'subcollection'}->{$$subref} ne $subcollection) {
+	$self->get_next_version ($subref);
+    } elsif ($namehash->{'languages'}->{$$langref} ne $languages) {
+	$self->get_next_version ($langref);
+    }
+    return "$$indexref$$subref$$langref";
+}	
+
+sub build_index {
+    my $self = shift (@_);
+    my ($index) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    # get the full index directory path and make sure it exists
+    my $indexdir = $self->{'index_mapping'}->{$index};
+    &util::mk_all_dir (&util::filename_cat($self->{'build_dir'}, $indexdir));
+    my $fullindexprefix = &util::filename_cat ($self->{'build_dir'}, $indexdir, 
+					       $self->{'collection'});
+    my $fulltextprefix = &util::filename_cat ($self->{'build_dir'}, "text", 
+					       $self->{'collection'});
+
+    # get any os specific stuff
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $exe = &util::get_os_exe ();
+    my $mg_passes_exe = &util::filename_cat($exedir, "mg_passes$exe");
+    my $mg_perf_hash_build_exe = 
+	&util::filename_cat($exedir, "mg_perf_hash_build$exe");
+    my $mg_weights_build_exe = 
+	&util::filename_cat ($exedir, "mg_weights_build$exe");
+    my $mg_invf_dict_exe = 
+	&util::filename_cat ($exedir, "mg_invf_dict$exe");
+    my $mg_stem_idx_exe =
+	&util::filename_cat ($exedir, "mg_stem_idx$exe");
+
+    my $maxnumeric = 4;
+    if (defined($self->{'collect_cfg'}->{'maxnumeric'}) &&
+	$self->{'collect_cfg'}->{'maxnumeric'} =~ /^\d+$/) {
+	$maxnumeric = $self->{'collect_cfg'}->{'maxnumeric'};
+    }
+
+    my $osextra = "";
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$fullindexprefix =~ s@/@\\@g;
+    } else {
+	$osextra = " -d /";
+	if ($outhandle ne "STDERR") {
+	    # so mg_passes doesn't print to stderr if we redirect output
+	    $osextra .= " 2>/dev/null";
+	}
+    }
+
+    # get the index level from the index description
+    # the index will be level 2 unless we are building a
+    # paragraph level index
+    my $index_level = 2;
+    $index_level = 3 if $index =~ /^paragraph/i;
+
+    # get the index expression if this index belongs
+    # to a subcollection
+    my $indexexparr = [];
+    my $langarr = [];
+    # there may be subcollection info, and language info. 
+    my ($level, $fields, $subcollection, $language) = split (":", $index);
+    my @subcollections = ();
+    @subcollections = split /,/, $subcollection if (defined $subcollection);
+
+    foreach my $subcollection (@subcollections) {
+	if (defined ($self->{'collect_cfg'}->{'subcollection'}->{$subcollection})) {
+	    push (@$indexexparr, $self->{'collect_cfg'}->{'subcollection'}->{$subcollection});
+	} 
+    }
+    
+    # add expressions for languages if this index belongs to
+    # a language subcollection - only put languages expressions for the 
+    # ones we want in the index
+
+    my @languages = ();
+    my $language_metadata = "Language";
+    if (defined ($self->{'collect_cfg'}->{'language_metadata'})) {
+	$language_metadata = $self->{'collect_cfg'}->{'language_metadata'};
+    }
+    @languages = split /,/, $language if (defined $language);
+    foreach my $language (@languages) {
+	my $not=0;
+	if ($language =~ s/^\!//) {
+	    $not = 1;
+	}
+	if($not) {
+	    push (@$langarr, "!$language");
+	} else {
+	    push (@$langarr, "$language");
+	}
+    }
+    
+    # Build index dictionary. Uses verbatim stem method
+    print $outhandle "\n    creating index dictionary\n"  if ($self->{'verbosity'} >= 1);
+    print STDERR "<Phase name='CreatingIndexDic'/>\n" if $self->{'gli'};
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$mg_passes_exe" || 
+	    !open (PIPEOUT, "| mg_passes$exe -f \"$fullindexprefix\" -b $maxdocsize " .
+		   "-$index_level -m 32 -s 0 -G -t 10 -N1 -M $maxnumeric $osextra")) {
+	    print STDERR "<FatalError name='NoRunMGPasses'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgbuilder::build_index - couldn't run $mg_passes_exe\n";
+	}
+	$handle = mgbuilder::PIPEOUT;
+    }
+	
+    # set up the document processor
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($index, $indexexparr);
+    $self->{'buildproc'}->set_index_languages ($language_metadata, $langarr) if (defined $language);
+    $self->{'buildproc'}->set_indexing_text (1);
+    $self->{'buildproc'}->set_store_text(1);
+
+    $self->{'buildproc'}->reset();
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'},0, $self->{'gli'});
+    close ($handle) unless $self->{'debug'};
+
+    $self->print_stats();
+
+    # now we check to see if the required files have been produced - if not we quit building this index so the whole process doesn't crap out.
+    # we check on the .id file - index dictionary
+    my $dict_file = "$fullindexprefix.id";
+    if (!-e $dict_file) {
+	print $outhandle "mgbuilder::build_index - Couldn't create index $index\n";
+	$self->{'notbuilt'}->{$index}=1;
+	return;
+    }
+    if (!$self->{'debug'}) {
+	# create the perfect hash function
+	if (!-e "$mg_perf_hash_build_exe") {
+	    print STDERR "<FatalError name='NoRunMGHash'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgbuilder::build_index - couldn't run $mg_perf_hash_build_exe\n";
+	}
+	system ("mg_perf_hash_build$exe -f \"$fullindexprefix\" $osextra");
+
+	if (!-e "$mg_passes_exe" || 
+	    !open ($handle, "| mg_passes$exe -f \"$fullindexprefix\" -b $maxdocsize " .
+		   "-$index_level -c 3 -G -t 10 -N2 -M $maxnumeric $osextra")) {
+	    print STDERR "<FatalError name='NoRunMGPasses'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgbuilder::build_index - couldn't run $mg_passes_exe\n";
+	}
+    }
+    
+    # invert the text
+    print $outhandle "\n    inverting the text\n"  if ($self->{'verbosity'} >= 1);
+    print STDERR "<Phase name='InvertingText'/>\n" if $self->{'gli'};
+    $self->{'buildproc'}->reset();
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'},0, $self->{'gli'});
+
+   
+    $self->print_stats ();
+
+    if (!$self->{'debug'}) {
+
+	close ($handle);
+	
+	# create the weights file
+	print $outhandle "\n    create the weights file\n"  if ($self->{'verbosity'} >= 1);
+	print STDERR "<Phase name='CreateTheWeights'/>\n" if $self->{'gli'};
+	if (!-e "$mg_weights_build_exe") {
+	    print STDERR "<FatalError name='NoRunMGWeights'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgbuilder::build_index - couldn't run $mg_weights_build_exe\n";
+	}
+	system ("mg_weights_build$exe -f \"$fullindexprefix\" -t \"$fulltextprefix\" $osextra");
+
+	# create 'on-disk' stemmed dictionary
+	print $outhandle "\n    creating 'on-disk' stemmed dictionary\n"  if ($self->{'verbosity'} >= 1);
+	print STDERR "<Phase name='CreateStemmedDic'/>\n" if $self->{'gli'};
+	if (!-e "$mg_invf_dict_exe") {
+	    print STDERR "<FatalError name='NoRunMGInvf'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgbuilder::build_index - couldn't run $mg_invf_dict_exe\n";
+	}
+	system ("mg_invf_dict$exe -f \"$fullindexprefix\" $osextra");
+
+
+	# creates stem index files for the various stemming methods
+	print $outhandle "\n    creating stem indexes\n"  if ($self->{'verbosity'} >= 1);
+	print STDERR "<Phase name='CreatingStemIndx'/>\n" if $self->{'gli'};
+	if (!-e "$mg_stem_idx_exe") {
+	    print STDERR "<FatalError name='NoRunMGStem'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgbuilder::build_index - couldn't run $mg_stem_idx_exe\n";
+	}
+	system ("mg_stem_idx$exe -b 4096 -s1 -f \"$fullindexprefix\" $osextra");
+	system ("mg_stem_idx$exe -b 4096 -s2 -f \"$fullindexprefix\" $osextra");
+	system ("mg_stem_idx$exe -b 4096 -s3 -f \"$fullindexprefix\" $osextra");
+    
+	# remove unwanted files
+	my $tmpdir = &util::filename_cat ($self->{'build_dir'}, $indexdir);
+	opendir (DIR, $tmpdir) || die
+	    "mgbuilder::build_index - couldn't read directory $tmpdir\n";
+	foreach my $file (readdir(DIR)) {
+	    next if $file =~ /^\./;
+	    my ($suffix) = $file =~ /\.([^\.]+)$/;
+	    if (defined $suffix && !defined $wanted_index_files{$suffix}) {
+		# delete it!
+		print $outhandle "deleting $file\n" if $self->{'verbosity'} > 2;
+		&util::rm (&util::filename_cat ($tmpdir, $file));
+	    }
+	}
+	closedir (DIR);
+    }
+    print STDERR "</Stage>\n" if $self->{'gli'};
+}
+
+sub build_cfg_extra {
+   my $self = shift(@_);
+   my ($build_cfg) = @_;
+   
+    # get additional stats from mg
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $exe = &util::get_os_exe ();
+    my $mgstat_exe = &util::filename_cat($exedir, "mgstat$exe");
+    my $input_file = &util::filename_cat ("text", $self->{'collection'});
+    if (!-e "$mgstat_exe" || !open (PIPEIN, "mgstat$exe -d \"$self->{'build_dir'}\" -f \"$input_file\" |")) {
+	print $outhandle "Warning: Couldn't open pipe to $mgstat_exe to get additional stats\n";
+    } else {
+	my $line = "";
+	while (defined ($line = <PIPEIN>)) {
+	    if ($line =~ /^Words in collection \[dict\]\s+:\s+(\d+)/) {
+		($build_cfg->{'numwords'}) = $1;
+	    } elsif ($line =~ /^Documents\s+:\s+(\d+)/) {
+		($build_cfg->{'numsections'}) = $1;
+	    }
+	}
+	close PIPEIN;
+    }
+}
+
+1;
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/mgbuildproc.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/mgbuildproc.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/mgbuildproc.pm	(revision 10506)
@@ -0,0 +1,147 @@
+###########################################################################
+#
+# mgbuildproc.pm -- 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# This document processor outputs a document
+# for mg to process
+
+
+package mgbuildproc;
+
+use basebuildproc;
+
+BEGIN {
+    @mgbuildproc::ISA = ('basebuildproc');
+}
+
+sub new {
+    my $class = shift @_;
+    my $self = new basebuildproc (@_);
+    return bless $self, $class;
+}
+
+
+sub find_paragraphs {
+    $_[1] =~ s/(<p\b)/\cC$1/gi;
+}
+
+sub filter_text {
+    # $self->filter_text ($field, $new_text);
+    # don't want to do anything for this version, however,
+    # in a particular collection you might want to override
+    # this method to post-process certain fields depending on
+    # the field, or whether we are outputting it for indexing
+}
+
+sub text {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+    my $handle = $self->{'output_handle'};
+    
+    # only output this document if it is one to be indexed
+    return if ($doc_obj->get_doc_type() ne "indexed_doc");
+    
+    # see if this document belongs to this subcollection
+    my $indexed_doc = $self->is_subcollection_doc($doc_obj);
+
+    # this is another document
+    $self->{'num_docs'} += 1;
+
+    # get the parameters for the output
+    my ($level, $fields) = split (/:/, $self->{'index'});
+    $fields =~ s/\ball\b/Title,Creator,text/;
+    $fields =~ s/\btopall\b/topTitle,topCreator,toptext/;
+
+    my $doc_section = 0; # just for this document
+    my $text = "";
+    my $text_extra = "";
+
+    # get the text for this document
+    my $section = $doc_obj->get_top_section();
+    while (defined $section) {
+	# update a few statistics
+	$doc_section++;
+	$self->{'num_sections'} += 1;
+
+	if ($indexed_doc) {
+	    $self->{'num_bytes'} += $doc_obj->get_text_length ($section);
+	    foreach my $field (split (/,/, $fields)) {
+		# only deal with this field if it doesn't start with top or
+		# this is the first section
+		my $real_field = $field;
+		if (!($real_field =~ s/^top//) || ($doc_section == 1)) {
+		    my $new_text = "";
+		    if ($level eq "dummy") {
+			# a dummy index is a special case used when no
+			# indexes are specified (since there must always be
+			# at least one index or we can't retrieve the
+			# compressed text) - we add a small amount of text
+			# to these dummy indexes which will never be seen
+			# but will overcome mg's problems with building
+			# empty indexes
+			$new_text = "this is dummy text to stop mg barfing";
+			$self->{'num_processed_bytes'} += length ($new_text);
+
+		    } elsif ($real_field eq "text") {
+			$new_text = $doc_obj->get_text ($section) if $self->{'store_text'};
+			$self->{'num_processed_bytes'} += length ($new_text);
+			$new_text =~ s/[\cB\cC]//g;
+			$self->find_paragraphs($new_text);
+			
+		    } else {
+			my $first = 1;
+			my @section_metadata = @{$doc_obj->get_metadata ($section, $real_field)};
+			if ($level eq "section" && $self->{'indexing_text'} && defined ($self->{'sections_index_document_metadata'})) {
+			    if ($self->{'sections_index_document_metadata'} eq "always" || ( scalar(@section_metadata) == 0 && $self->{'sections_index_document_metadata'} eq "unless_section_metadata_exists")) {
+				push (@section_metadata, @{$doc_obj->get_metadata ($doc_obj->get_top_section(), $real_field)});
+			    }
+			}
+			foreach my $meta (@section_metadata) {
+			    $meta =~ s/[\cB\cC]//g;
+			    $self->{'num_processed_bytes'} += length ($meta);
+			    $new_text .= "\cC" unless $first;
+			    $new_text .= $meta if $self->{'store_text'};
+			    $first = 0;
+			}
+		    }
+		    
+		    # filter the text
+		    $self->filter_text ($field, $new_text);
+
+		    $text .= "$new_text\cC";
+		}
+	    }
+	}
+	
+	if ($level eq "document") { $text_extra .= "\cB"; }
+	else { $text .= "\cB"; }
+	
+	$section = $doc_obj->get_next_section($section);
+    }
+
+    print $handle "$text$text_extra";
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/mgppbuilder.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/mgppbuilder.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/mgppbuilder.pm	(revision 10506)
@@ -0,0 +1,887 @@
+###########################################################################
+#
+# mgppbuilder.pm -- MGBuilder object
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package mgppbuilder;
+
+use basebuilder;
+use classify;
+use cfgread;
+use colcfg;
+use plugin;
+use util;
+use FileHandle;
+
+sub BEGIN {
+    @mgppbuilder::ISA = ('basebuilder');
+}
+
+
+
+our %level_map = ('document'=>'Doc',
+	      'section'=>'Sec',
+	      'paragraph'=>'Para',
+	      'Doc'=>'_textdocument_',
+	      'Sec'=>'_textsection_',
+	      'Para'=>'_textparagraph_');
+
+#$doc_level = "Doc";
+#$sec_level = "Sec";
+#$para_level = "Para";
+
+our %wanted_index_files = ('td'=>1,
+		       't'=>1,
+		       'tl'=>1,
+		       'ti'=>1,
+		       'idb'=>1,
+		       'ib1'=>1,
+		       'ib2'=>1,
+		       'ib3'=>1,
+		       'i'=>1,
+		       'il'=>1,
+		       'w'=>1,
+		       'wa'=>1);
+
+# change this so a user can add their own ones in via a file or cfg
+#add AND, OR, NOT NEAR to this list - these cannot be used as field names
+#also add the level names (Doc, Sec, Para)
+our %static_indexfield_map = ('Title'=>'TI',
+			  'TI'=>1,
+			  'Subject'=>'SU',
+			  'SU'=>1,
+			  'Creator'=>'CR',
+			  'CR'=>1,
+			  'Organization'=>'ORG',
+			  'ORG'=>1,
+			  'Source'=>'SO',
+			  'SO'=>1,
+			  'Howto'=>'HT',
+			  'HT'=>1,
+			  'ItemTitle'=>'IT',
+			  'IT'=>1,
+			  'ProgNumber'=>'PN',
+			  'PN'=>1,
+			  'People'=>'PE',
+			  'PE'=>1,
+			  'Coverage'=>'CO',
+			  'CO'=>1,
+			  'allfields'=>'ZZ',
+			  'ZZ'=>1,
+			  'text'=>'TX',
+			  'TX'=>1,
+			  'AND'=>1,
+			  'OR'=>1,
+			  'NOT'=>1,
+			  'NEAR'=>1,
+			  'Doc'=>1,
+			  'Sec'=>1,
+			  'Para'=>1);
+
+my $maxdocsize = $basebuilder::maxdocsize;
+
+sub new {
+    my $class = shift(@_);
+
+    my ($collection, $source_dir, $build_dir, $verbosity, 
+	$maxdocs, $debug, $keepold, $remove_empty_classifications, 
+	$outhandle, $no_text, $failhandle, $gli) = @_;
+
+    my $self = new basebuilder (@_);
+    $self = bless $self, $class;
+
+    $self->{'indexfieldmap'} = \%static_indexfield_map;
+
+    # get the levels (Section, Paragraph) for indexing and compression
+    $self->{'levels'} = {};
+    $self->{'levelorder'} = ();
+    if (defined $self->{'collect_cfg'}->{'levels'}) {
+        foreach my $level ( @{$self->{'collect_cfg'}->{'levels'}} ){
+	    $level =~ tr/A-Z/a-z/;
+            $self->{'levels'}->{$level} = 1;
+	    push (@{$self->{'levelorder'}}, $level);
+        }
+    } else { # default to document
+	$self->{'levels'}->{'document'} = 1;
+	push (@{$self->{'levelorder'}}, 'document');
+    }
+    
+    $self->{'doc_level'} = "document";
+    if (! $self->{'levels'}->{'document'}) {
+	if ($self->{'levels'}->{'section'}) {
+	    $self->{'doc_level'} = "section";
+	} else {
+	    die "you must have either document or section level specified!!\n";
+	}
+    }
+
+    $self->{'buildtype'} = "mgpp";
+
+    return $self;
+}
+
+sub generate_index_list {
+    my $self  = shift (@_);
+    
+    # sort out the indexes
+    #indexes are specified with spaces, but we put them into one index
+    my $indexes = $self->{'collect_cfg'}->{'indexes'};
+    $self->{'collect_cfg'}->{'indexes'} = [];
+    push (@{$self->{'collect_cfg'}->{'indexes'}}, join(',', @$indexes));
+}
+
+sub default_buildproc {
+    my $self  = shift (@_);
+
+    return "mgppbuildproc";
+}
+
+sub compress_text {
+
+    my $self = shift (@_);
+    my ($textindex) = @_;
+
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+    my $exe = &util::get_os_exe ();
+    my $mgpp_passes_exe = &util::filename_cat($exedir, "mgpp_passes$exe");
+    my $mgpp_compression_dict_exe = &util::filename_cat($exedir, "mgpp_compression_dict$exe");
+    my $outhandle = $self->{'outhandle'};
+
+    &util::mk_all_dir (&util::filename_cat($self->{'build_dir'}, "text"));
+
+    my $basefilename = "text/$self->{'collection'}";
+    my $fulltextprefix = &util::filename_cat ($self->{'build_dir'}, $basefilename);
+    
+   my $osextra = "";
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$fulltextprefix =~ s@/@\\@g;
+    } 
+    else {
+	$osextra = " -d /";
+    }
+
+
+    # define the section names and possibly the doc name for mgpasses
+    # the compressor doesn't need to know about paragraphs - never want to 
+    # retrieve them
+    my $mgpp_passes_sections = "";
+    my ($doc_level) = $self->{'doc_level'};
+    $mgpp_passes_sections .= "-J " . $level_map{$doc_level} . " ";
+    foreach my $level (keys %{$self->{'levels'}}) {
+	if ($level ne $doc_level && $level ne "paragraph") {
+	    $mgpp_passes_sections .= "-K " . $level_map{$level} . " ";
+	}
+    }
+    $mgpp_passes_sections .= "-K SENT ";
+    print $outhandle "\n*** creating the compressed text\n" if ($self->{'verbosity'} >= 1);
+    print STDERR "<Stage name='CompressText'>\n" if $self->{'gli'};
+
+    # collect the statistics for the text
+    # -b $maxdocsize sets the maximum document size to be 12 meg
+    print $outhandle "\n    collecting text statistics (mgpp_passes -T1)\n"  if ($self->{'verbosity'} >= 1);
+    print STDERR "<Phase name='CollectTextStats'/>\n" if $self->{'gli'};
+
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	#print $outhandle "trying to run (compress 1) mgpp_passes$exe $mgpp_passes_sections -f \"$fulltextprefix\" -T1 $osextra\n";
+	if (!-e "$mgpp_passes_exe" || 
+	    !open (PIPEOUT, "| mgpp_passes$exe $mgpp_passes_sections -f \"$fulltextprefix\" -T1 $osextra")) {
+	    print STDERR "<FatalError name='NoRunMGPasses'>\n</Stage>\n" if $self->{'gli'};
+	    die "mgppbuilder::compress_text - couldn't run $mgpp_passes_exe\n";
+	}
+	$handle = mgppbuilder::PIPEOUT;
+    }
+
+    # gdbm_level
+    my $gdbm_level = "document";
+    if ($self->{'levels'}->{'section'}) {
+	$gdbm_level = "section";
+    }
+    
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($textindex);
+    $self->{'buildproc'}->set_indexing_text (0);
+    if ($self->{'no_text'}) {
+	$self->{'buildproc'}->set_store_text(0);
+    } else {
+	$self->{'buildproc'}->set_store_text(1);
+    }
+    $self->{'buildproc'}->set_indexfieldmap ($self->{'indexfieldmap'});
+    $self->{'buildproc'}->set_levels ($self->{'levels'});                      
+    $self->{'buildproc'}->set_gdbm_level ($gdbm_level);                       
+    $self->{'buildproc'}->reset();
+    &plugin::begin($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   $self->{'buildproc'}, $self->{'maxdocs'});
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'}, 0, $self->{'gli'});
+    &plugin::end($self->{'pluginfo'});
+    close (PIPEOUT);
+
+    close ($handle) unless $self->{'debug'};
+
+    $self->print_stats();
+
+    # create the compression dictionary
+    # the compression dictionary is built by assuming the stats are from a seed
+    # dictionary (-S), if a novel word is encountered it is spelled out (-H),
+    # and the resulting dictionary must be less than 5 meg with the most 
+    # frequent words being put into the dictionary first (-2 -k 5120)
+    # note: these options are left over from mg version
+    if (!$self->{'debug'}) {
+	print $outhandle "\n    creating the compression dictionary\n"  if ($self->{'verbosity'} >= 1);
+	print STDERR "<Phase name='CreatingCompress'/>\n" if $self->{'gli'};
+	if (!-e "$mgpp_compression_dict_exe") {
+	    print STDERR "<FatalError name='NoRunMGCompress'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgppbuilder::compress_text - couldn't run $mgpp_compression_dict_exe\n";
+	}
+	system ("mgpp_compression_dict$exe -f \"$fulltextprefix\" -S -H -2 -k 5120 $osextra");
+
+	if (!$self->{'debug'}) {
+	    #print $outhandle "trying to run (compress 2) mgpp_passes$exe $mgpp_passes_sections -f \"$fulltextprefix\" -T2 $osextra\n";
+	    if (!-e "$mgpp_passes_exe" || 
+		!open ($handle, "| mgpp_passes$exe $mgpp_passes_sections -f \"$fulltextprefix\" -T2 $osextra")) {
+		print STDERR "<FatalError name='NoRunMGPasses'/>\n</Stage>\n" if $self->{'gli'};
+		die "mgppbuilder::compress_text - couldn't run $mgpp_passes_exe\n";
+	    }
+	}
+    }
+    else {
+	print STDERR "<Phase name='SkipCreatingComp'/>\n" if $self->{'gli'};
+    }
+
+    $self->{'buildproc'}->reset();
+    # compress the text
+    print $outhandle "\n    compressing the text (mgpp_passes -T2)\n"  if ($self->{'verbosity'} >= 1);
+    print STDERR "<Phase name='CompressingText'/>\n" if $self->{'gli'};
+
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'}, 0, $self->{'gli'});
+    close ($handle) unless $self->{'debug'};
+
+    $self->print_stats();
+    print STDERR "</Stage>\n" if $self->{'gli'};
+}
+
+
+sub build_indexes_extra {
+    my $self = shift(@_);
+    #define the final field lists
+    $self->make_final_field_list();
+}    
+
+# creates directory names for each of the index descriptions
+sub create_index_mapping {
+    my $self = shift (@_);
+    my ($indexes) = @_;
+
+    my %mapping = ();
+
+    $mapping{'indexmaporder'} = [];
+    $mapping{'subcollectionmaporder'} = [];
+    $mapping{'languagemaporder'} = [];
+    
+    # dirnames is used to check for collisions. Start this off
+    # with the manditory directory names
+    my %dirnames = ('text'=>'text',
+		    'extra'=>'extra');
+    my %pnames = ('index' => {}, 'subcollection' => {}, 'languages' => {});
+
+    foreach my $index (@$indexes) {
+	my ($fields, $subcollection, $languages) = split (":", $index);
+	# the directory name starts with a processed version of index fields
+	#my ($pindex) = $self->process_field($fields);
+	#$pindex = lc ($pindex);
+	# now we only ever have one index, and its called 'idx'
+	my $pindex = 'idx';
+	
+	# next comes a processed version of the subcollection if there is one.
+	my $psub = $self->process_field ($subcollection);
+	$psub = lc ($psub);
+
+	# next comes a processed version of the language if there is one.
+	my $plang = $self->process_field ($languages);
+	$plang = lc ($plang);
+
+	my $dirname = $pindex . $psub . $plang;
+
+	# check to be sure all index names are unique
+	while (defined ($dirnames{$dirname})) {
+	    $dirname = $self->make_unique (\%pnames, $index, \$pindex, \$psub, \$plang);
+	}
+
+	$mapping{$index} = $dirname;
+
+	# store the mapping orders as well as the maps
+	# also put index, subcollection and language fields into the mapping thing - 
+	# (the full index name (eg text:subcol:lang) is not used on
+	# the query page) -these are used for collectionmeta later on
+	if (!defined $mapping{'indexmap'}{"$fields"}) {
+	    $mapping{'indexmap'}{"$fields"} = $pindex;
+	    push (@{$mapping{'indexmaporder'}}, "$fields");
+	    if (!defined $mapping{"$fields"}) {
+		$mapping{"$fields"} = $pindex;
+	    }	
+	}
+	if ($psub =~ /\w/ && !defined ($mapping{'subcollectionmap'}{$subcollection})) {
+	    $mapping{'subcollectionmap'}{$subcollection} = $psub;
+	    push (@{$mapping{'subcollectionmaporder'}}, $subcollection);
+	    $mapping{$subcollection} = $psub;
+	}
+	if ($plang =~ /\w/ && !defined ($mapping{'languagemap'}{$languages})) {
+	    $mapping{'languagemap'}{$languages} = $plang;
+	    push (@{$mapping{'languagemaporder'}}, $languages);
+	    $mapping{$languages} = $plang;
+	}
+	$dirnames{$dirname} = $index;
+	$pnames{'index'}->{$pindex} = "$fields";
+	$pnames{'subcollection'}->{$psub} = $subcollection;
+	$pnames{'languages'}->{$plang} = $languages;
+    }
+
+    return \%mapping;
+}
+
+sub make_unique {
+    my $self = shift (@_);
+    my ($namehash, $index, $indexref, $subref, $langref) = @_;
+    my ($fields, $subcollection, $languages) = split (":", $index);
+
+    if ($namehash->{'index'}->{$$indexref} ne "$fields") {
+	$self->get_next_version ($indexref);
+    } elsif ($namehash->{'subcollection'}->{$$subref} ne $subcollection) {
+	$self->get_next_version ($subref);
+    } elsif ($namehash->{'languages'}->{$$langref} ne $languages) {
+	$self->get_next_version ($langref);
+    }
+    return "$$indexref$$subref$$langref";
+}	
+
+
+sub build_index {
+    my $self = shift (@_);
+    my ($index) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    # get the full index directory path and make sure it exists
+    my $indexdir = $self->{'index_mapping'}->{$index};
+    &util::mk_all_dir (&util::filename_cat($self->{'build_dir'}, $indexdir));
+    my $fullindexprefix = &util::filename_cat ($self->{'build_dir'}, 
+					       $indexdir, 
+					       $self->{'collection'});
+    my $fulltextprefix = &util::filename_cat ($self->{'build_dir'}, "text", 
+					       $self->{'collection'});
+
+    # get any os specific stuff
+    my $exedir = "$ENV{'GSDLHOME'}/bin/$ENV{'GSDLOS'}";
+
+    my $exe = &util::get_os_exe ();
+    my $mgpp_passes_exe = &util::filename_cat($exedir, "mgpp_passes$exe");
+
+    # define the section names for mgpasses
+    # define the section names and possibly the doc name for mgpasses
+    my $mgpp_passes_sections = "";
+    my ($doc_level) = $self->{'doc_level'};
+    $mgpp_passes_sections .= "-J " . $level_map{$doc_level} ." ";
+    
+    foreach my $level (keys %{$self->{'levels'}}) {
+	if ($level ne $doc_level) {
+	    $mgpp_passes_sections .= "-K " . $level_map{$level}. " ";
+	}
+    }
+
+    my $mgpp_perf_hash_build_exe = 
+	&util::filename_cat($exedir, "mgpp_perf_hash_build$exe");
+    my $mgpp_weights_build_exe = 
+	&util::filename_cat ($exedir, "mgpp_weights_build$exe");
+    my $mgpp_invf_dict_exe = 
+	&util::filename_cat ($exedir, "mgpp_invf_dict$exe");
+    my $mgpp_stem_idx_exe =
+	&util::filename_cat ($exedir, "mgpp_stem_idx$exe");
+
+     my $osextra = "";
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$fullindexprefix =~ s@/@\\@g;
+    } else {
+	$osextra = " -d /";
+	if ($outhandle ne "STDERR") {
+	    # so mgpp_passes doesn't print to stderr if we redirect output
+	    $osextra .= " 2>/dev/null";
+	}
+    }
+ 
+    # get the index expression if this index belongs
+    # to a subcollection
+    my $indexexparr = [];
+    my $langarr = [];
+    # there may be subcollection info, and language info. 
+    my ($fields, $subcollection, $language) = split (":", $index);
+    my @subcollections = ();
+    @subcollections = split /,/, $subcollection if (defined $subcollection);
+
+    foreach $subcollection (@subcollections) {
+	if (defined ($self->{'collect_cfg'}->{'subcollection'}->{$subcollection})) {
+	    push (@$indexexparr, $self->{'collect_cfg'}->{'subcollection'}->{$subcollection});
+	} 
+    }
+    
+    # add expressions for languages if this index belongs to
+    # a language subcollection - only put languages expressions for the 
+    # ones we want in the index
+    
+    my @languages = ();
+    my $language_metadata = "Language";
+    if (defined ($self->{'collect_cfg'}->{'language_metadata'})) {
+	$language_metadata = $self->{'collect_cfg'}->{'language_metadata'};
+    }
+    @languages = split /,/, $language if (defined $language);
+    foreach my $language (@languages) {
+	my $not=0;
+	if ($language =~ s/^\!//) {
+	    $not = 1;
+	}
+	if($not) {
+	    push (@$langarr, "!$language");
+	} else {
+	    push (@$langarr, "$language");
+	}
+    }
+
+    # Build index dictionary. Uses verbatim stem method
+    print $outhandle "\n    creating index dictionary (mgpp_passes -I1)\n"  if ($self->{'verbosity'} >= 1);
+    print STDERR "<Phase name='CreatingIndexDic'/>\n" if $self->{'gli'};
+    my ($handle);
+    if ($self->{'debug'}) {
+	$handle = STDOUT;
+    } else {
+	if (!-e "$mgpp_passes_exe" || 
+	    !open (PIPEOUT, "| mgpp_passes$exe $mgpp_passes_sections -f \"$fullindexprefix\" -I1 $osextra")) {
+	    print STDERR "<FatalError name='NoRunMGPasses'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgppbuilder::build_index - couldn't run $mgpp_passes_exe\n";
+	}
+	$handle = mgppbuilder::PIPEOUT;
+    }
+	    
+    # gdbm_level
+    my $gdbm_level = "document";
+    if ($self->{'levels'}->{'section'}) {
+	$gdbm_level = "section";
+    }
+
+    # set up the document processr
+    $self->{'buildproc'}->set_output_handle ($handle);
+    $self->{'buildproc'}->set_mode ('text');
+    $self->{'buildproc'}->set_index ($index, $indexexparr);
+    $self->{'buildproc'}->set_index_languages ($language_metadata, $langarr) if (defined $language);
+    $self->{'buildproc'}->set_indexing_text (1);
+    $self->{'buildproc'}->set_store_text(1);
+    $self->{'buildproc'}->set_indexfieldmap ($self->{'indexfieldmap'});
+    $self->{'buildproc'}->set_levels ($self->{'levels'}); 
+    $self->{'buildproc'}->set_gdbm_level ($gdbm_level);   
+    
+    $self->{'buildproc'}->reset();
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'}, 0, $self->{'gli'});
+    close ($handle) unless $self->{'debug'};
+
+    $self->print_stats();
+
+    # now we check to see if the required files have been produced - if not we quit building this index so the whole process doesn't crap out.
+    # we check on the .id file - index dictionary
+    my $dict_file = "$fullindexprefix.id";
+    if (!-e $dict_file) {
+	print $outhandle "mgppbuilder::build_index - Couldn't create index $index\n";
+	print STDERR "<Warning name='NoIndex'/>\n</Stage>\n" if $self->{'gli'};
+	$self->{'notbuilt'}->{$index}=1;
+	return;
+    }
+
+    if (!$self->{'debug'}) {
+	# create the perfect hash function
+	if (!-e "$mgpp_perf_hash_build_exe") {
+	    print STDERR "<FatalError name='NoRunMGHash'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgppbuilder::build_index - couldn't run $mgpp_perf_hash_build_exe\n";
+	}
+	system ("mgpp_perf_hash_build$exe -f \"$fullindexprefix\" $osextra");
+
+	if (!-e "$mgpp_passes_exe" || 
+	    !open ($handle, "| mgpp_passes$exe $mgpp_passes_sections -f \"$fullindexprefix\" -I2 $osextra")) {
+	    print STDERR "<FatalError name='NoRunMGPasses'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgppbuilder::build_index - couldn't run $mgpp_passes_exe\n";
+	}
+    }
+    
+    # invert the text
+    print $outhandle "\n    inverting the text (mgpp_passes -I2)\n"  if ($self->{'verbosity'} >= 1);
+    print STDERR "<Phase name='InvertingText'/>\n" if $self->{'gli'};
+    $self->{'buildproc'}->reset();
+    &plugin::read ($self->{'pluginfo'}, $self->{'source_dir'}, 
+		   "", {}, $self->{'buildproc'}, $self->{'maxdocs'}, 0, $self->{'gli'});
+
+    $self->print_stats ();
+    
+    if (!$self->{'debug'}) {
+
+	close ($handle);
+	
+	# create the weights file
+	print $outhandle "\n    create the weights file\n"  if ($self->{'verbosity'} >= 1);
+	print STDERR "<Phase name='CreateTheWeights'/>\n" if $self->{'gli'};
+	if (!-e "$mgpp_weights_build_exe") {
+	    print STDERR "<FatalError name='NoRunMGWeights'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgppbuilder::build_index - couldn't run $mgpp_weights_build_exe\n";
+	}
+	system ("mgpp_weights_build$exe -f \"$fullindexprefix\" $osextra");
+
+	# create 'on-disk' stemmed dictionary
+	print $outhandle "\n    creating 'on-disk' stemmed dictionary\n"  if ($self->{'verbosity'} >= 1);
+	if (!-e "$mgpp_invf_dict_exe") {
+	    print STDERR "<FatalError name='NoRunMGInvf'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgppbuilder::build_index - couldn't run $mgpp_invf_dict_exe\n";
+	}
+	system ("mgpp_invf_dict$exe -f \"$fullindexprefix\" $osextra" );
+
+
+	# creates stem index files for the various stemming methods
+	print $outhandle "\n    creating stem indexes\n"  if ($self->{'verbosity'} >= 1);
+	print STDERR "<Phase name='CreatingStemIndx'/>\n" if $self->{'gli'};
+	if (!-e "$mgpp_stem_idx_exe") {
+	    print STDERR "<FatalError name='NoRunMGStem'/>\n</Stage>\n" if $self->{'gli'};
+	    die "mgppbuilder::build_index - couldn't run $mgpp_stem_idx_exe\n";
+	}
+	system ("mgpp_stem_idx$exe -b 4096 -s1 -f \"$fullindexprefix\" $osextra");
+	system ("mgpp_stem_idx$exe -b 4096 -s2 -f \"$fullindexprefix\" $osextra");
+	system ("mgpp_stem_idx$exe -b 4096 -s3 -f \"$fullindexprefix\" $osextra");
+	
+	# remove unwanted files
+	my $tmpdir = &util::filename_cat ($self->{'build_dir'}, $indexdir);
+	opendir (DIR, $tmpdir) || die
+	    "mgppbuilder::build_index - couldn't read directory $tmpdir\n";
+	foreach my $file (readdir(DIR)) {
+	    next if $file =~ /^\./;
+	    my ($suffix) = $file =~ /\.([^\.]+)$/;
+	    if (defined $suffix && !defined $wanted_index_files{$suffix}) {
+		# delete it!
+		print $outhandle "deleting $file\n" if $self->{'verbosity'} > 2;
+		#&util::rm (&util::filename_cat ($tmpdir, $file));
+	    }
+	}
+	closedir (DIR);
+    }
+    print STDERR "</Stage>\n" if $self->{'gli'};
+}   
+
+
+sub output_collection_meta {
+    my $self = shift(@_);
+    my ($handle) = @_;
+
+    # define the indexed field mapping if not already done so (ie if infodb called separately from build_index)
+    if (!defined $self->{'build_cfg'}) {
+	$self->read_final_field_list();
+    }
+
+    # do the collection info
+    print $handle "[collection]\n";
+    
+    # first do the collection meta stuff - everything without a dot
+    my $collmetadefined = 0;
+    my $metadata_entry;
+    if (defined $self->{'collect_cfg'}->{'collectionmeta'}) {
+	$collmetadefined = 1;
+	foreach my $cmeta (keys (%{$self->{'collect_cfg'}->{'collectionmeta'}})) {
+	    next if ($cmeta =~ /^\./); # for now, ignore ones with dots
+	    $metadata_entry = $self->create_language_db_map($cmeta, $cmeta);
+	    #write the entry to the file
+	    print $handle $metadata_entry;
+	    
+	} # foreach collmeta key
+    }
+    #add the index field macros to [collection]
+    # eg <TI>Title
+    #    <SU>Subject
+    # these now come from collection meta. if that is not defined, usses the metadata name
+    my $field_entry="";
+    my $collmeta = "";
+    foreach my $longfield (@{$self->{'build_cfg'}->{'indexfields'}}){
+	my $shortfield = $self->{'buildproc'}->{'indexfieldmap'}->{$longfield};
+	next if $shortfield eq 1;
+	
+	# we need to check if some coll meta has been defined
+	$collmeta = ".$longfield";
+	if ($collmetadefined && defined $self->{'collect_cfg'}->{'collectionmeta'}->{$collmeta}) {
+	    $metadata_entry = $self->create_language_db_map($collmeta, $shortfield);
+	    $field_entry .= $metadata_entry;
+	} else { #use the metadata names, or the text macros for allfields and textonly
+	    if ($longfield eq "allfields") {
+		$field_entry .= "<$shortfield>_query:textallfields_\n";
+	    } elsif ($longfield eq "text") {
+		$field_entry .= "<$shortfield>_query:texttextonly_\n";
+	    } else {
+		$field_entry .= "<$shortfield>$longfield\n";
+	    }
+	}
+    }
+    print $handle $field_entry;
+    
+    # now add the level names
+    my $level_entry = "";
+    foreach my $level (@{$self->{'collect_cfg'}->{'levels'}}) {
+	$collmeta = ".$level"; # based on the original specification
+	$level =~ tr/A-Z/a-z/; # make it lower case
+	my $levelid = $level_map{$level}; # find the actual value we used in the index
+	if ($collmetadefined && defined $self->{'collect_cfg'}->{'collectionmeta'}->{$collmeta}) {
+	    $metadata_entry = $self->create_language_db_map($collmeta, $levelid);
+	    $level_entry .= $metadata_entry;
+	} else {
+	    # use the default macro
+	    $level_entry .= "<$levelid>" . $level_map{$levelid} . "\n";
+	}
+    }
+    print $handle $level_entry;
+    
+    # now add subcoll meta
+    my $subcoll_entry = "";
+    my $shortname = "";
+    my $one_entry = "";
+    foreach my $subcoll (@{$self->{'index_mapping'}->{'subcollectionmaporder'}}) {
+	if (defined $self->{'collect_cfg'}->{'collectionmeta'}->{".$subcoll"}) {
+	    $shortname = $self->{'index_mapping'}->{$subcoll};
+	    $one_entry = $self->create_language_db_map(".$subcoll", $shortname);
+	    $subcoll_entry .= $one_entry;
+	} else {
+	    $subcoll_entry .= "<$shortname>$subcoll\n";
+	}
+    }
+    print $handle $subcoll_entry;
+
+    # now add language meta
+    my $lang_entry = "";
+    foreach my $lang (@{$self->{'index_mapping'}->{'languagemaporder'}}) {
+	if (defined $self->{'collect_cfg'}->{'collectionmeta'}->{".$lang"}) {
+	    $shortname = $self->{'index_mapping'}->{$lang};
+	    $one_entry = $self->create_language_db_map(".$lang", $shortname);
+	    $lang_entry .= $one_entry;
+	} else {
+	    $lang_entry .= "<$shortname>$lang\n";
+	}
+    }
+    print $handle $lang_entry;
+    # end the collection entry
+    print $handle "\n" . ('-' x 70) . "\n";        
+
+
+}
+sub create_language_db_map {
+    my $self = shift (@_);
+    my ($metaname, $mapname) = @_;
+    my $outhandle =  $self->{'outhandle'};
+    my $defaultfound=0;
+    my $first=1;
+    my $metadata_entry = "";
+    my $default="";
+    #iterate through the languages
+    foreach my $lang (keys (%{$self->{'collect_cfg'}->{'collectionmeta'}->{$metaname}})) {
+	if ($first) {
+	    $first=0;
+	    #set the default default to the first entry
+	    $default=$self->{'collect_cfg'}->{'collectionmeta'}->{$metaname}->{$lang};
+	}
+	if ($lang =~ /default/) {
+	    $defaultfound=1;
+	    #the default entry goes first
+	    $metadata_entry = "<$mapname>" .
+		$self->{'collect_cfg'}->{'collectionmeta'}->{$metaname}->{'default'} . "\n" . $metadata_entry;
+	}
+	else {
+	    my ($l) = $lang =~ /^\[l=(\w*)\]$/;
+	    if ($l) {
+		$metadata_entry .= "<$mapname:$l>" . 
+		    $self->{'collect_cfg'}->{'collectionmeta'}->{$metaname}->{$lang} . "\n";
+
+		# Use the English value as the default if no default is specified
+		if ($l =~ /en/i) {
+		    $default=$self->{'collect_cfg'}->{'collectionmeta'}->{$metaname}->{$lang};
+		}
+	    }
+	}
+    } #foreach lang
+    #if we haven't found a default, put one in
+    if (!$defaultfound) {
+	$metadata_entry = "<$mapname>$default\n" . $metadata_entry;
+    }
+    return $metadata_entry;
+    
+}
+
+# at the end of building, we have an indexfieldmap with all the mappings,
+# plus some extras, and indexmap with any indexes in it that weren't
+# specified in the index definition.  we want to make an ordered list of
+# fields that are indexed, and a list of mappings that are used. this will
+# be used for the build.cfg file, and for collection meta definition we
+# store these in a build.cfg bit
+sub make_final_field_list {
+    my $self = shift (@_);
+    
+    $self->{'build_cfg'} = {};
+    
+    # store the indexfieldmap information
+    my @indexfieldmap = ();
+    my @indexfields = ();
+    my $specifiedfields = {};
+    my @specifiedfieldorder = ();
+
+    # go through the index definition and add each thing to a map, so we
+    # can easily check if it is already specified - when doing the
+    # metadata, we print out all the individual fields, but some may
+    # already be specified in the index definition, so we dont want to add
+    # those again.
+
+    my $field;
+    foreach $field (@{$self->{'collect_cfg'}->{'indexes'}}) {
+	# remove subcoll stuff
+	my $parts = $field;
+	$parts =~ s/:.*$//;
+	my @fs = split(',', $parts);
+	foreach my $f(@fs) {
+	    if (!defined $specifiedfields->{$f}) {
+		$specifiedfields->{$f}=1;
+		push (@specifiedfieldorder, "$f");
+	    }
+	}
+    }
+    
+    #add all fields bit 
+    foreach $field (@specifiedfieldorder) {
+	if ($field eq "metadata") {
+	    foreach my $newfield (keys %{$self->{'buildproc'}->{'indexfields'}}) {
+		if (!defined $specifiedfields->{$newfield}) {
+		    push (@indexfieldmap, "$newfield\-\>$self->{'buildproc'}->{'indexfieldmap'}->{$newfield}");
+		    push (@indexfields, "$newfield");
+		}
+	    }
+
+	} elsif ($field eq 'text') {
+	    push (@indexfieldmap, "text\-\>TX");
+	    push (@indexfields, "text");
+	} elsif ($field eq 'allfields') {
+	    push (@indexfieldmap, "allfields\-\>ZZ");
+	    push (@indexfields, "allfields");
+	} else {
+	    push (@indexfieldmap, "$field\-\>$self->{'buildproc'}->{'indexfieldmap'}->{$field}");
+	    push (@indexfields, "$field");
+	    
+	}
+    }
+
+    $self->{'build_cfg'}->{'indexfieldmap'} = \@indexfieldmap;
+    $self->{'build_cfg'}->{'indexfields'} = \@indexfields;
+}
+
+
+# recreate the field list from the build.cfg file, look first in building,
+# then in index to find it. if there is no build.cfg, we can't do the field
+# list (there is unlikely to be any index anyway.)
+sub read_final_field_list {
+    my $self = shift (@_);
+    $self->{'build_cfg'} = {};
+    my @indexfieldmap = ();
+    my @indexfields = ();
+    
+    if (scalar(keys %{$self->{'buildproc'}->{'indexfieldmap'}}) == 0) {
+	# set the default mapping
+	$self->{'buildproc'}->set_indexfieldmap ($self->{'indexfieldmap'});
+    }
+    # we read the stuff in from the build.cfg file - if its there
+    my $buildconfigfile = &util::filename_cat($self->{'build_dir'}, "build.cfg");
+    
+    if (!-e $buildconfigfile) {
+	# try the index dir - but do we know where it is?? try here
+	$buildconfigfile  = &util::filename_cat($ENV{'GSDLCOLLECTDIR'}, "index", "build.cfg");
+	if (!-e $buildconfigfile) {
+	    #we cant find a config file - just ignore the field list
+	    return;
+	}
+    } 
+
+    my $buildcfg = &colcfg::read_build_cfg( $buildconfigfile);
+    my $field;
+    if (defined $buildcfg->{'indexfields'}) {
+	foreach $field (@{$buildcfg->{'indexfields'}}) {
+	    push (@indexfields, "$field");
+	}
+    }
+
+    if (defined $buildcfg->{'indexfieldmap'}) {
+	foreach $field (@{$buildcfg->{'indexfieldmap'}}) {
+	    push (@indexfieldmap, "$field");
+	    my ($f, $v) = $field =~ /^(.*)\-\>(.*)$/;
+	    $self->{'buildproc'}->{'indexfieldmap'}->{$f} = $v;
+	}
+    }	    
+
+    $self->{'build_cfg'}->{'indexfieldmap'} = \@indexfieldmap;
+    $self->{'build_cfg'}->{'indexfields'} = \@indexfields;
+}
+
+
+sub write_cfg_file {
+    my $self = shift(@_);
+    my ($build_cfg) = @_;
+
+    # write out the build information
+    &cfgread::write_cfg_file("$self->{'build_dir'}/build.cfg", $build_cfg,
+			     '^(builddate|buildtype|numdocs|numsections|numbytes|textlevel|indexstem|maxnumeric)$', 
+                             '^(indexmap|subcollectionmap|languagemap|indexfieldmap|notbuilt|indexfields|indexlevels|levelmap)$');
+
+}
+
+sub build_cfg_extra {
+    my $self = shift (@_);
+    my ($build_cfg) = @_;
+
+    $build_cfg->{'numsections'} = $self->{'buildproc'}->get_num_sections();
+    
+    # store the level info
+    my @indexlevels = ();
+    my @levelmap = ();
+    foreach my $l (@{$self->{'levelorder'}}) {
+	push (@indexlevels, $level_map{$l});
+	push (@levelmap, "$l\-\>$level_map{$l}");
+    }
+    $build_cfg->{'indexlevels'} = \@indexlevels;
+    $build_cfg->{'levelmap'} = \@levelmap;
+
+    if ($self->{'levels'}->{'section'}) {
+	$build_cfg->{'textlevel'} = $level_map{'section'};
+    } else {	
+	$build_cfg->{'textlevel'} = $level_map{'document'};
+    }
+   
+}
+
+1;
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/mgppbuildproc.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/mgppbuildproc.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/mgppbuildproc.pm	(revision 10506)
@@ -0,0 +1,338 @@
+###########################################################################
+#
+# mgppbuildproc.pm -- 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# This document processor outputs a document
+# for mgpp to process
+
+
+package mgppbuildproc;
+
+use basebuildproc;
+
+BEGIN {
+    @mgppbuildproc::ISA = ('basebuildproc');
+}
+
+#this must be the same as in mgppbuilder
+our %level_map = ('document'=>'Doc',
+		  'section'=>'Sec',
+		  'paragraph'=>'Para');
+
+sub new {
+    my $class = shift @_;
+    my $self = new basebuildproc (@_);
+
+    # use a different index specification to the default
+    $self->{'index'} = "text";
+
+    $self->{'dontindex'} = {};
+    $self->{'indexfieldmap'} = {};
+    $self->{'indexfields'} = {}; # only put in the ones that are not specified directly in the index
+    $self->{'strip_html'}=1;
+    
+    return bless $self, $class;
+}
+
+
+sub set_indexfieldmap {
+    my $self = shift (@_);
+    my ($indexmap) = @_;
+
+    $self->{'indexfieldmap'} = $indexmap;
+}
+
+sub get_indexfieldmap {
+    my $self = shift (@_);
+
+    return $self->{'indexfieldmap'};
+}
+
+sub set_levels {
+    my $self = shift (@_);
+    my ($levels) = @_;
+
+    $self->{'levels'} = $levels;
+}
+
+sub set_strip_html {
+    my $self = shift (@_);
+    my ($strip) = @_;
+    $self->{'strip_html'}=$strip;
+}
+
+
+sub get_gdbm_level {
+    my $self = shift (@_);
+    
+    #if a Section level index is not built, the gdbm file should be at doc 
+    #level not Section
+    if ($self->{'levels'}->{'section'}) {
+	return "section";
+    }
+    return "document";
+}
+
+
+#sub find_paragraphs {
+#    $_[1] =~ s/(<p\b)/<Paragraph>$1/gi;
+#}
+
+#this function strips the html tags from the doc if ($strip_html) and
+# if ($para) replaces <p> with <Paragraph> tags.
+# if both are false, the original text is returned
+#assumes that <pre> and </pre> have no spaces, and removes all < and > inside
+#these tags
+sub preprocess_text {
+    my $self = shift (@_);
+    my ($text, $strip_html, $para) = @_;
+    my ($outtext) = "";
+    if ($strip_html) { 
+	while ($text =~ /<([^>]*)>/ && $text ne "") {
+	    
+	    my $tag = $1;
+	    $outtext .= $`." "; #add everything before the matched tag
+	    $text = $'; #'everything after the matched tag
+	    if ($para && $tag =~ /^\s*p\s/i) {
+		$outtext .= $para;
+	    }
+	    elsif ($tag =~ /^pre$/) { # a pre tag
+		$text =~ /<\/pre>/; # find the closing pre tag
+		my $tmp_text = $`; #everything before the closing pre tag
+		$text = $'; #'everything after the </pre>
+		$tmp_text =~ s/[<>]//g; # remove all < and >
+		$outtext.= $tmp_text . " ";
+	    }
+	}
+    
+	$outtext .= $text; # add any remaining text
+	return $outtext;
+    } #if strip_html
+
+    #if ($para) {
+	#$text =~ s/(<p\b)/$para$1/gi;
+	#return $text;
+   # }
+    return $text;
+}
+	
+    
+
+sub filter_text {
+    # $self->filter_text ($field, $new_text);
+    # don't want to do anything for this version, however,
+    # in a particular collection you might want to override
+    # this method to post-process certain fields depending on
+    # the field, or whether we are outputting it for indexing
+}
+
+sub text {
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+    my $handle = $self->{'output_handle'};
+    my $outhandle = $self->{'outhandle'};
+
+    # only output this document if it is one to be indexed
+    return if ($doc_obj->get_doc_type() ne "indexed_doc");
+
+    my $indexed_doc = $self->is_subcollection_doc($doc_obj);
+    
+    # this is another document
+    $self->{'num_docs'} += 1;
+
+    # get the parameters for the output
+    # split on : just in case there is subcoll and lang stuff
+    my ($fields) = split (/:/, $self->{'index'});
+
+    my ($documenttag) = "";
+    my($documentendtag) = "";
+    if ($self->{'levels'}->{'document'}) {
+	$documenttag = "\n<". $level_map{'document'} . ">\n";
+	$documentendtag = "\n</". $level_map{'document'} . ">\n";
+    }
+    my ($sectiontag) = "";
+    if ($self->{'levels'}->{'section'}) {
+	$sectiontag = "\n<". $level_map{'section'} . ">\n";
+    }
+    my ($paratag) = "";
+    
+    if ($self->{'levels'}->{'paragraph'}) {
+	if ($self->{'strip_html'}) {
+	    $paratag = "<". $level_map{'paragraph'} . ">";
+	} else {
+	    print $outhandle "Paragraph level can not be used with no_strip_html!. Not indexing Paragraphs.\n";
+	}
+    }
+
+    my $doc_section = 0; # just for this document
+    
+    my $text = $documenttag;
+   
+    # get the text for this document
+    my $section = $doc_obj->get_top_section();
+    while (defined $section) {
+	# update a few statistics
+	$doc_section++;
+	$self->{'num_sections'} += 1;
+	$text .= "$sectiontag";
+
+	if ($indexed_doc) {
+	    if ($self->{'indexing_text'}) {
+		$text .= "$paratag"; # only add para tags for indexing
+		# note that we assume that metadata will not be asked for for the compressed text, so we add para tags without checking for indexing_text
+	    }
+	    $self->{'num_bytes'} += $doc_obj->get_text_length ($section);
+	    foreach my $field (split (/,/, $fields)) {
+		# only deal with this field if it doesn't start with top or
+		# this is the first section
+		my $real_field = $field;
+		if (!($real_field =~ s/^top//) || ($doc_section == 1)) {
+		    my $new_text = ""; 
+		    my $tmp_text = "";
+		    if ($real_field eq "text") {
+			if ($self->{'indexing_text'}) { #tag the text with <Text>...</Text>, add the <Paragraph> tags and strip out html if needed
+			    $new_text .= "$paratag<TX>\n";
+			    $tmp_text .= $doc_obj->get_text ($section);
+			    $tmp_text = $self->preprocess_text($tmp_text, $self->{'strip_html'}, "</TX>$paratag<TX>");
+			    
+			    $new_text .= "$tmp_text</TX>\n";
+			    #if (!defined $self->{'indexfields'}->{'TextOnly'}) {
+				#$self->{'indexfields'}->{'TextOnly'} = 1;   
+			    #}
+			}
+			else { # leave html stuff in, and dont add Paragraph tags - never retrieve paras at the moment
+			    $new_text .= $doc_obj->get_text ($section) if $self->{'store_text'};
+			}
+		    } else { # metadata field
+			if ($real_field eq "allfields") { #ignore
+			}
+			elsif ($real_field eq "metadata") { # insert all metadata 
+			    #except gsdl stuff
+			    my $shortname = "";
+			    my $metadata = $doc_obj->get_all_metadata ($section);
+			    foreach my $pair (@$metadata) {
+				my ($mfield, $mvalue) = (@$pair);
+				# check fields here, maybe others dont want - change to use dontindex!!
+				if ($mfield ne "Identifier" 
+				    && $mfield !~ /^gsdl/ 
+				    && $mfield ne "classifytype"
+				    && $mfield ne "assocfilepath"
+				    && defined $mvalue && $mvalue ne "") {
+				    
+				    if (defined $self->{'indexfieldmap'}->{$mfield}) {
+					$shortname = $self->{'indexfieldmap'}->{$mfield};
+				    }
+				    else {
+					$shortname = $self->create_shortname($mfield);
+					$self->{'indexfieldmap'}->{$mfield} = $shortname;
+					$self->{'indexfieldmap'}->{$shortname} = 1;
+				    }	   
+				    $new_text .= "$paratag<$shortname>$mvalue</$shortname>\n";
+				    if (!defined $self->{'indexfields'}->{$mfield}) {
+					$self->{'indexfields'}->{$mfield} = 1;
+				    }				    
+				}
+			    }
+			    
+			}
+			else { #individual metadata specified
+			    my $shortname="";
+			    #if (!defined $self->{'indexfields'}->{$real_field}) {
+				#$self->{'indexfields'}->{$real_field} = 1;
+			    #}
+			    if (defined $self->{'indexfieldmap'}->{$real_field}) {
+				$shortname = $self->{'indexfieldmap'}->{$real_field};
+			    }
+			    else {
+				$shortname = $self->create_shortname($real_field);
+				$self->{'indexfieldmap'}->{$real_field} = $shortname;
+				$self->{'indexfieldmap'}->{$shortname} = 1;
+			    }
+			    my @section_metadata = @{$doc_obj->get_metadata ($section, $real_field)};
+			    if ($self->{'indexing_text'} && defined ($self->{'sections_index_document_metadata'})) {
+				if ($self->{'sections_index_document_metadata'} eq "always" || ( scalar(@section_metadata) == 0 && $self->{'sections_index_document_metadata'} eq "unless_section_metadata_exists")) {
+				    push (@section_metadata, @{$doc_obj->get_metadata ($doc_obj->get_top_section(), $real_field)});
+				}
+			    }
+			    foreach my $item (@section_metadata) {
+			    #foreach my $item (@{$doc_obj->get_metadata ($section, $real_field)}) {
+				$new_text .= "$paratag<$shortname>$item</$shortname>\n";
+			    }
+			}
+
+		    }
+		    
+		    # filter the text
+		    $self->filter_text ($field, $new_text);
+
+		    $self->{'num_processed_bytes'} += length ($new_text);
+		    $text .= "$new_text";
+		}
+	    }
+	} # if (indexed_doc)
+	
+	$section = $doc_obj->get_next_section($section);
+    } #while defined section
+    print $handle "$text\n$documentendtag"; 
+    
+}
+
+#chooses the first two letters or digits for the shortname
+#now ignores non-letdig characters
+sub create_shortname {
+    my $self = shift(@_);
+    
+    my ($realname) = @_;
+    #take the first two chars
+    my $shortname;
+    if ($realname =~ /^[^\w]*(\w)[^\w]*(\w)/) {
+	$shortname = "$1$2";
+    } else {
+	# there aren't two letdig's in the field - try arbitrary combinations
+	$realname = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	$shortname = "AB";
+    }
+    $shortname =~ tr/a-z/A-Z/;
+
+    #if already used, take the first and third letdigs and so on
+    my $count = 1;
+    while (defined $self->{'indexfieldmap'}->{$shortname}) {
+	if ($realname =~ /^[^\w]*(\w)([^\w]*\w){$count}[^\w]*(\w)/) {
+	    $shortname = "$1$3";
+	    $count++;
+	    $shortname =~ tr/a-z/A-Z/;
+	
+	}
+	else {
+	    #remove up to and incl the first letdig
+	    $realname =~ s/^[^\w]*\w//;
+	    $count = 0;
+	}
+    }
+
+    return $shortname;
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/multiread.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/multiread.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/multiread.pm	(revision 10506)
@@ -0,0 +1,313 @@
+###########################################################################
+#
+# multiread.pm --
+#
+# Copyright (C) 1999 DigiLib Systems Limited, NZ
+# Copyright (C) 2005 New Zealand Digital Library project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# the multiread object will read in a number of encodings,
+# the results are always returned in the utf-8 format
+
+# encodings currently supported are
+#
+# utf8             - either utf8 or unicode (automatically detected)
+# unicode          - 2-byte UCS (does endian detection)
+#
+# plus all encodings in the "encodings" package
+
+package multiread;
+
+eval {require bytes};
+
+use unicode;
+
+sub new {
+    my ($class) = @_;
+
+    my $self = {'handle'    => "",
+		'first'     => 1,
+		'encoding'  => "utf8",
+		'bigendian' => 1};
+
+    return bless $self, $class;
+}
+
+# set_handle expects the file to be already open but
+# not read yet
+sub set_handle {
+    my $self = shift;
+    $self->{'handle'} = shift;
+    binmode( $self->{'handle'} );
+    $self->{'first'} = 1;
+    $self->{'encoding'} = "utf8";
+    $self->{'bigendian'} = 1;
+}
+
+# set_encoding should be called after set_handle
+sub set_encoding {
+    my $self = shift;
+    $self->{'encoding'} = shift;
+}
+
+sub get_encoding {
+    my $self = shift (@_);
+    return $self->{'encoding'};
+}
+
+# undef will be returned if the eof has been reached
+# the result will always be returned in utf-8
+
+sub read_unicode_char {
+    my $self = shift (@_);
+
+    # make sure we have a file handle
+    return undef if ($self->{'handle'} eq "");
+    my $handle = $self->{'handle'};
+
+    if ($self->{'encoding'} eq "utf8") {
+	# utf-8 text, how many characters we get depends 
+	# on what we find
+	my $c1 = "";
+	my $c2 = "";
+	my $c3 = "";
+
+	while (!eof ($handle)) {
+	    $c1 = ord (getc ($handle));
+
+	    if ($c1 <= 0x7f) {
+		# one byte character
+		return chr ($c1);
+
+	    } elsif ($c1 >= 0xc0 && $c1 <= 0xdf) {
+		# two byte character
+		$c2 = getc ($handle) if (!eof ($handle));
+		return chr ($c1) . $c2;
+
+	    } elsif ($c1 >= 0xe0 && $c1 <= 0xef) {
+		# three byte character
+		$c2 = getc ($handle) if (!eof ($handle));
+		$c3 = getc ($handle) if (!eof ($handle));
+		return chr ($c1) . $c2 . $c3;
+	    }
+
+	    # if we get here there was an error in the file, we should
+	    # be able to recover from it however, maybe the file is in
+	    # another encoding
+	}
+
+	return undef if (eof ($handle));
+    }
+
+    if ($self->{'encoding'} eq "unicode") {
+	# unicode text, get the next two characters
+	return undef if (eof ($handle));
+	my $c1 = ord (getc ($handle));
+	return undef if (eof ($handle));
+	my $c2 = ord (getc ($handle));
+
+	return &unicode::unicode2utf8 ([(($self->{'bigendian'}) ? ($c1*256+$c2) : ($c2*256+$c1))]);
+    }
+
+    return undef;
+}
+
+
+# undef will be returned if the eof has been reached
+# the result will always be returned in utf-8
+sub read_line {
+    my $self = shift (@_);
+
+    # make sure we have a file handle
+    return undef if ($self->{'handle'} eq "");
+
+    my $handle = $self->{'handle'};
+
+    if ($self->{'encoding'} eq "utf8") {
+	# utf-8 line
+	return <$handle>;
+    }
+
+    if ($self->{'encoding'} eq "unicode") {
+	# unicode line
+	my $c = "";
+	my ($c1, $c2) = ("", "");
+	my $out = "";
+	while (read ($handle, $c, 2) == 2) {
+	    $c1 = ord (substr ($c, 0, 1));
+	    $c2 = ord (substr ($c, 1, 1));
+	    $c = &unicode::unicode2utf8([(($self->{'bigendian'}) ? ($c1*256+$c2) : ($c2*256+$c1))]);
+	    $out .= $c;
+	    last if ($c eq "\n");
+	}
+
+	return $out if (length ($out) > 0);
+	return undef;
+    }
+
+    if ($self->{'encoding'} eq "iso_8859_1") {
+	# we'll use ascii2utf8() for this as it's faster than going
+	# through convert2unicode()
+	my $line = "";
+	if (defined ($line = <$handle>)) {
+	    return &unicode::ascii2utf8 (\$line);
+	}
+    }
+
+    # everything else uses unicode::convert2unicode
+    my $line = "";
+    if (defined ($line = <$handle>)) {
+	return &unicode::unicode2utf8 (&unicode::convert2unicode ($self->{'encoding'}, \$line));
+    }
+
+    return undef;
+}
+
+
+
+# this will look for a Byte Order Marker at the start of the file, and
+# set the encoding appropriately if there is one, returning any
+# non-marker text on the first line (or returns undef).
+sub find_unicode_bom {
+    my $self=shift;
+
+    my $non_bom_text=""; # to return if we read in 'real' text
+
+    if ($self->{'first'} == 0) { return }
+
+    # make sure we have a file handle
+    return if ($self->{'handle'} eq "");
+    my $handle = $self->{'handle'};
+
+    $self->{'first'} = 0;
+
+    my $b1 = ord(getc ($handle));
+    my $b2;
+    my $b3;
+
+    if ($b1 == 0xfe || $b1 == 0xff) {
+	$b2 = ord (getc ($handle)) if (!eof ($handle));
+	if ($b1 == 0xff && $b2 == 0xfe) {
+	    $self->{'encoding'} = "unicode";
+	    $self->{'bigendian'} = 0;
+	    return;
+	} elsif ($b1 == 0xfe && $b2 == 0xff) {
+	    $self->{'encoding'} = "unicode";
+	    $self->{'bigendian'} = 1;
+	    return;
+	} elsif ($b1 == 0xef && $b2 == 0xbb) {
+	    $b3 = ord(getc($handle));
+	    if ($b3 == 0xbf) {
+		$self->{'encoding'} = "utf8";
+		$self->{'bigendian'} = 1;
+		return;
+	    }
+	}
+    } else { # $b1 != fe or ff
+	$handle->ungetc($b1); return;
+    }
+    # if here, we have removed some chars and they aren't a BOM
+    if ($self->{'encoding'} eq "unicode") { # return the 2byte char
+	if (defined ($b3)) { # we looked at this... return it
+	    $handle->ungetc($b3);
+	}
+	return &unicode::unicode2utf8([$self->{'bigendian'}?
+				       ($b1*256+$b2) : ($b2*256+$b1)]);
+    }
+    # if here, it's utf-8
+    if ($b2 < 0x80) {
+	if (defined ($b3)) { # we grabbed this, but don't need it now
+	    $handle->ungetc($b3);
+	}
+	return ($b1 . $b2);
+    }
+    # if here, we have taken part of a multi-byte char. we need to make
+    # sure we return the entire character
+    if (defined($b3) && $b3 < 0x80) { # we have all we need
+	$handle->ungetc($b3);
+	return ($b1 . $b2);
+    }
+    my $c=$b1.$b2.$b3;
+    my $b4=$handle->getc();
+    while ($b4 > 0x7f) { # note - this will return consecutive mb utf8 chars
+	$c .= $b4;
+	$b4=$handle->getc();
+	if (eof($handle)) { last }
+    }
+    if (! eof($handle)) {
+	$handle->ungetc($b4); # this byte is an ascii byte
+    }
+    return $c;
+}
+
+
+
+# will convert entire contents of file to utf8 and append result to $outputref
+# this may be a slightly faster way to get the contents of a file than by 
+# recursively calling read_line()
+sub read_file {
+    my $self = shift (@_);
+    my ($outputref) = @_;
+
+    # make sure we have a file handle
+    return if ($self->{'handle'} eq "");
+
+    my $handle = $self->{'handle'};
+
+    # if encoding is set to utf8 or unicode, sniff to see if there is a 
+    # byte order marker
+    if ($self->{'first'} &&
+	($self->{'encoding'} eq "utf8" || $self->{'encoding'} eq 'unicode')) {
+	# this will change $self's encoding if there is a BOM
+	my $read_text = $self->find_unicode_bom();
+	$$outputref .= $read_text if (defined($read_text));
+    }
+
+    if ($self->{'encoding'} eq "utf8") {
+	undef $/;
+	$$outputref .=  <$handle>;
+	$/ = "\n";
+	return;
+    }
+
+    if ($self->{'encoding'} eq "unicode") {
+	my $line = "";
+	while (defined ($line = $self->read_line())) {
+	    $$outputref .= $line;
+	}
+	return;
+    }
+
+    if ($self->{'encoding'} eq "iso_8859_1") {
+	# we'll use ascii2utf8() for this as it's faster than going
+	# through convert2unicode()
+	undef $/;
+	my $text = <$handle>;
+	$/ = "\n";
+	$$outputref .= &unicode::ascii2utf8 (\$text);
+	return;
+    }
+
+    # everything else uses unicode::convert2unicode
+    undef $/;
+    my $text = <$handle>;
+    $/ = "\n";
+    $$outputref .= &unicode::unicode2utf8 (&unicode::convert2unicode ($self->{'encoding'}, \$text));
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/muread.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/muread.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/muread.pm	(revision 10506)
@@ -0,0 +1,151 @@
+###########################################################################
+#
+# muread.pm -- read a marked-up file
+#
+# Copyright (C) 1999 DigiLib Systems Limited, NZ
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+package muread;
+
+use unicode;
+use multiread;
+
+sub new {
+    my ($class) = @_;
+
+    my $self = {'filename'=>"",
+		'encoding'=>"",
+		'handle'=>"",
+		'reader'=>"",
+		'buffer'=>""};
+
+    return bless $self, $class;
+}
+
+# returns a new tag with a tag name and any options
+sub parse_tag {
+    my $self = shift (@_);
+    my ($orgtagtext) = @_;
+    my $tagtext = $orgtagtext;
+    my $newtag = {};
+    my $misformed = 0;
+
+#    print STDERR "parsing \"$tagtext\"\n";
+
+    # get tag name (if there is one)
+    if ($tagtext =~ /^(\w+)/) {
+	$newtag->{'_tagname'} = $1;
+	$tagtext =~ s/^(\w+)//;
+    } else {
+	print STDERR "muread::parse_tag error - no tag name found\n";
+    }
+
+    # get the tag arguments
+    while ($tagtext =~ /\S/) {
+	$tagtext =~ s/^\s+//s;
+	if ($tagtext =~ /^(\w+)\s*=\s*\"([^\"]*)\"/s) {
+	    $newtag->{$1} = (defined $2) ? $2 : "";
+	    $tagtext =~ s/^\w+\s*=\s*\"[^\"]*\"//s;
+
+	} else {
+	    if (!$misformed) {
+		print STDERR "muread::parse_tag error - miss-formed tag <$orgtagtext>\n";
+		$misformed = 1;
+	    }
+	    $tagtext =~ s/^\S+//s;
+	}
+    }
+
+    return $newtag;
+}
+
+sub read_tag_content {
+    my $self = shift (@_);
+    my ($tag) = @_;
+
+    # all tags contain a _tagname except the tag for the document
+
+    my $line = "";
+    while (1) {
+	# deal with preceeding text
+	if ($self->{'buffer'} =~ /^([^<]+)</s) {
+	    # add preceeding text
+	    $tag->{'_contains'} = [] unless defined $tag->{'_contains'};
+	    push (@{$tag->{'_contains'}}, {'_text'=>$1});
+
+	    $self->{'buffer'} =~ s/^[^<]+</</s;
+	}
+
+	if ($self->{'buffer'} =~ /^<([^>\/]+)>/s) {
+	    # add info from this tag
+	    my $tagtext = $1;
+	    my $newtag = $self->parse_tag ($tagtext);
+	    push (@{$tag->{'_contains'}}, $newtag);
+	    $self->{'buffer'} =~ s/^<[^>\/]+>//s;
+	    
+	    # deal with the contents of this tag
+	    $self->read_tag_content ($newtag);
+
+	} elsif ($self->{'buffer'} =~ /^<\/([^>\/]+)>/s) {
+	    my $tagname = $1;
+	    $self->{'buffer'} =~ s/^<\/[^>\/]+>//s;
+
+	    # check that this tag is the right tag
+	    if (!defined $tag->{'_tagname'} || $tag->{'_tagname'} ne $tagname) {
+		print STDERR "muread::read_tag_content error - mismatched tag </$tagname>, " .
+		    "expected </$tag->{'_tagname'}>\n";
+	    } else {
+		return;
+	    }
+	} elsif (defined ($line = $self->{'reader'}->read_line())) {
+	    $self->{'buffer'} .= $line;
+	} else {
+	    if ($self->{'buffer'} =~ /\S/) {
+		print STDERR "muread::read_tag_content error - can't parse text \"$self->{'buffer'}\"\n";
+	    }
+	    last;
+	}
+    }
+    
+    if (defined $tag->{'_tagname'}) {
+	print STDERR "muread::read_tag_content error - eof reached before closing " .
+	    "tag \"$tag->{'_tagname'}\" found\n";
+    }
+}
+
+sub read_file {
+    my $self = shift (@_);
+    ($self->{'handle'}, $self->{'filename'}, $self->{'encoding'}) = @_;
+    $self->{'encoding'} = "utf8" unless defined $self->{'encoding'};
+
+    my $doc = {};
+
+    # get reader set up
+    $self->{'reader'} = new multiread ();
+    $self->{'reader'}->set_handle ($self->{'handle'});
+    $self->{'reader'}->set_encoding ($self->{'encoding'});
+
+    # read in the file
+    $self->read_tag_content ($doc);
+
+    $self->{'handle'} = "";
+    return $doc;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/parsargv.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/parsargv.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/parsargv.pm	(revision 10506)
@@ -0,0 +1,238 @@
+###########################################################################
+#
+# parseargv.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package parsargv;
+# 
+# parse(ARGVREF, [SPEC, VARREF] ...)
+# 
+# Parse command line arguments.
+# 
+# ARGVREF is an array reference, usually to @ARGV.  The remaining
+# arguments are paired (SPEC, VARREF).  SPEC is a specification string
+# for a particular argument; VARREF is a variable reference that will
+# receive the argument.
+# 
+# SPEC is in one of the following forms:
+# 
+# ARG/REGEX/DEFAULT ARG is the name of command line argument.  REGEX is
+#     a regular expression that gives legal values for the argument.
+#     DEFAULT is the default value assigned to VARREF if the option does
+#     not appear on the command line.  Example
+# 
+# 
+# ARG/REGEX ARG and REGEX are as above.  Since no default is given, ARG
+#     must appear on the command line; if it doesn't, parse() returns 0.
+# 
+# ARG ARG is as above.  ARG is a boolean option.  VARREF is assigned 0 if ARG
+#     is not on the command line; 1 otherwise.
+# 
+# SPEC may start with a punctuation character, in which case this
+# character will be used instead of '/' as a delimiter.  Useful when '/'
+# is needed in the REGEX part.
+# 
+# VARREF is a reference to a scalar or an array.  If VARREF is an array
+# reference, then multiple command line options are allowed an append.  Example:
+# 
+# 	Command line: -day mon -day fri
+# 
+# 	parse(\@ARGV, "day/(mon|tue|wed|thu|fri)", \@days)
+# 
+# 	days => ('mon', 'fri')
+# 
+# Returns 0 if there was an error, nonzero otherwise.
+# 
+
+ 
+sub parse
+{
+    my $arglist = shift;
+    my ($spec, $var);
+    my %option;
+
+    my @rest = @_;
+
+
+    # if the last argument is the string "allow_extra_options" then options
+    # in \@rest without a corresponding SPEC will be ignored (i.e. the "$arg is
+    # not a valid option" error won't occur)\n";
+    my $allow_extra_options = pop @rest;
+    if (defined ($allow_extra_options)) {
+	if ($allow_extra_options eq "allow_extra_options") {
+	    $allow_extra_options = 1;
+	} else {
+	    # put it back where we got it
+	    push (@rest, $allow_extra_options);
+	    $allow_extra_options = 0;
+	}
+    } else {
+	$allow_extra_options = 0;
+    }
+
+    while (($spec, $var) = splice(@rest, 0, 2))
+        {
+	  
+	die "Variable for $spec is not a valid type."
+	    unless ref($var) eq 'SCALAR' || ref($var) eq 'ARRAY'
+	    || (ref($var) eq 'REF' && ref($$var) eq 'GLOB');
+
+	my $delimiter;
+	if ($spec !~ /^\w/)
+	{
+	    $delimiter = substr($spec, 0, 1);
+	    $spec = substr($spec, 1);
+	}
+	else
+	{
+	    $delimiter = '/';
+	}
+	my ($name, $regex, $default) = split(/$delimiter/, $spec, 3);
+	
+	
+	if ($name)
+	{   
+	    if ($default && $default !~ /$regex/)
+	    {
+		die "Default value for $name doesn't match regex ($spec).";
+	    }
+	    $option{$name} = {'name' => $name,
+			      'regex' => $regex,
+			      'default' => $default,
+			      'varref' => $var,
+			      'set' => 0};
+	}
+	else
+	{
+	    die "Invalid argument ($spec) for parsargv.";
+	}
+    }
+
+    my @argv;
+    my $arg;
+    my $parse_options = 1;
+    my $errors = 0;
+
+    while ($arg = shift(@$arglist))
+    {
+	if ($parse_options && $arg eq '--')
+	{
+	    $parse_options = 0;
+	    next;
+	}
+
+	if ($parse_options && $arg =~ /^-+\w/)
+	{
+	    $arg =~ s/^-+//;
+
+	    if (defined $option{$arg})
+	    {
+		&process_arg($option{$arg}, $arglist, \$errors);
+	    }
+	    elsif (!$allow_extra_options)
+	    {
+		print STDOUT "$arg is not a valid option.\n";
+		$errors++;
+	    }
+	}
+	else
+	{
+	    push(@argv, $arg);
+	}
+    }
+    @$arglist = @argv;
+
+    foreach $arg (keys %option)
+    {
+	if ($option{$arg}->{'set'} == 0)
+	{
+	    if (defined $option{$arg}->{'default'})
+	    {
+		&set_var($option{$arg}, $option{$arg}->{'default'});
+	    }
+	    elsif (!$option{$arg}->{'regex'})
+	    {
+		&set_var($option{$arg}, 0)
+	    }
+	    elsif (ref($option{$arg}->{'varref'}) ne 'ARRAY')
+	    {
+		print STDOUT "Missing command line argument -$arg.\n";
+		$errors++;
+	    }
+	}
+    }
+    return $errors == 0;
+}
+
+sub process_arg
+{
+    my ($option, $arglist, $errors) = @_;
+
+    if ($option->{'regex'} && @$arglist > 0 && $arglist->[0] !~ /^-+\w/)
+    {
+	if ($arglist->[0] =~ /$option->{'regex'}/)
+	{
+	    &set_var($option, shift(@$arglist));
+	}
+	else
+	{
+	    print STDOUT  "Bad value for -$option->{'name'} argument.\n";
+	    $$errors++;
+	}
+    }
+    elsif (!$option->{'regex'})
+    {
+	&set_var($option, 1);
+    }
+    else
+    {
+	print STDOUT "No value given for -$option->{'name'}.\n";
+	$$errors++;
+    }
+}
+
+sub set_var
+{
+    my ($option, $value) = @_;
+    my $type = ref($option->{'varref'});
+
+    if ($type eq 'SCALAR')
+    {
+	${$option->{'varref'}} = $value;
+    }
+    elsif ($type eq 'ARRAY')
+    {
+	push(@{$option->{'varref'}}, $value);
+    }
+    $option->{'set'} = 1;
+}
+
+1;
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/parse2.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/parse2.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/parse2.pm	(revision 10506)
@@ -0,0 +1,335 @@
+#Last: Keeping doing the processArg for handing different type of arguments
+
+#parse2(\@_,$arguments,$self )
+
+package parse2;
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+}
+
+use util;
+
+
+
+#--Local Util Functions----------------------------
+#-----------------------------------------
+# Name: transformArg
+# Parameters: 1.(Array pointer of plugin pre-defined argument list)
+# Pre-condition: Call this function and pass a array pointer of argument list.
+# Post-condition: This function will transform the array to a hash table 
+#                 with "Argument name" as its key
+# Return value: Return a hash table of plugin pre-defined argument 
+#               list with "argument name" as the key
+#-----------------------------------------
+sub transformArg
+{
+    my ($aryptSysArguList) = @_;
+    my %hashArg;
+    
+    foreach my $hashOneArg (@{$aryptSysArguList})
+    {
+	if(!(defined $hashArg{$hashOneArg->{"name"}}))
+	{
+	    $hashArg{$hashOneArg->{"name"}} = $hashOneArg;
+	}
+    }
+    return %hashArg;
+}
+
+sub checkRange
+{
+    my ($strRange,$intInputArg,$strArgName) = @_;
+    my @aryRange = split(",",$strRange);
+    if(defined $aryRange[0])
+    {
+	if($intInputArg < $aryRange[0])
+	{
+	    print STDERR " Parameter Parsing Error (Incorrect Range): when parse argument parameter for \"-$strArgName\"\n";
+	    return 0;
+	}
+	else
+	{
+	    if(scalar(@aryRange) == 2)
+	    { 
+		if($intInputArg > $aryRange[1])
+		{
+		    print STDERR " Parameter Parsing Error (Incorrect Range): when parse argument parameter for \"-$strArgName\"\n";
+		    return 0;
+		}
+	    }
+	}
+    }
+    else{ die " System error: minimum range is not defined. Possible mistyping in Argument list for $strArgName\n";}
+    return 1;
+}
+
+sub checkCharLength
+{
+    my ($intCharLength,$intInputArg,$strArgName) = @_;
+    if($intCharLength =~ m/\d/)
+    {
+	if(length($intInputArg) != $intCharLength)
+	{ 
+	    print STDERR " Parameter Parsing Error (Incorrect Char_Length): when parse argument parameter for \"-$strArgName\"\n";
+	    return 0;
+	}
+    }
+    else
+    {
+	die " System error: incorrect char_length. Possible mistyping in Argument list for $strArgName\n";
+    }
+    return 1;
+}
+#-----------------------------------------
+# Name: processArg
+# Parameters: 1.(Hash pointer of one argument)
+#             2.(Array pointer of the user given argument)
+#             3.(Hash pointer of user given arguments' values)
+# Pre-condition: Given a argument ($hashOneArg) 
+# Post-condition: System will check whether it need to get parameter 
+#                 from $aryptInputArguList or not, and also check the 
+#                 given parameter is following the argument description
+# Return value: 1 is parsing successful, 0 is failed.
+#-----------------------------------------
+sub processArg
+{
+    my ($hashOneArg,$aryptInputArguList,$hashInputArg) = @_;
+
+    # Since these two variables are going to be 
+    # used a lot, store them with some better names.
+    my $strArgName = $hashOneArg->{"name"};
+    my $strArgType = $hashOneArg->{"type"};
+
+    # If the argument type is "flag" then 
+    # set it to 1(which is "true") 
+    if($strArgType eq "flag")
+    {
+	$hashInputArg->{$strArgName} = 1;
+    }
+
+    # If the argument type is "int" then
+    # gets the next argument from $aryptInputArguList 
+    # and check whether it is a digit
+    # TODO: check its "range" and "char_length"
+    elsif($strArgType eq "int")
+    {
+	my $intInputArg = shift(@{$aryptInputArguList});
+	if ($intInputArg =~ /\d+/)
+	{
+	    $hashInputArg->{$strArgName} = $intInputArg;
+	}
+	else
+	{
+	    print STDERR " Error: occur in parse2.pm::processArg()\n Unmatched Argument: -$strArgName with type $strArgType\n";
+	    return 0;
+	}
+    }
+
+    # If the argument type is "enum" then
+    elsif($strArgType eq "enum")
+    {
+	if(defined $hashOneArg->{"list"})
+	{
+	    my $aryptList = $hashOneArg->{"list"};
+	    my $blnCheckInList = "false";
+	    my $strInputArg = shift(@{$aryptInputArguList});
+	    foreach my $hashEachItem (@$aryptList)
+	    {
+		if($strInputArg eq $hashEachItem->{"name"})
+		{
+		    $blnCheckInList = "true";
+		}
+		last if($blnCheckInList eq "true");
+	    }
+	    if($blnCheckInList ne "true")
+	    {
+		print STDERR " Error: occur in parse2.pm::processArg()\n Unknown Enum List Type: -$strArgName with parameter: $strInputArg\n";
+		return 0;
+	    } else {
+		$hashInputArg->{$strArgName} = $strInputArg;
+	    }
+	    
+	}
+	else
+	{
+	    print STDERR " Error: occur in parse2.pm::processArg(2)\n Unknown Type: -$strArgName with type $strArgType\n";
+	    return 0;
+	}
+    }
+
+    # If the argument type is "string" or "metadata" then
+    # just shift the next argument from $aryptInputArguList
+    # TODO: make sure if there is any checking required for this two types
+    elsif($strArgType eq "string" || $strArgType eq "metadata" || $strArgType eq "regexp")
+    {
+	$hashInputArg->{$strArgName}= shift(@{$aryptInputArguList});
+    }
+    
+    # Report any undefined types
+    else
+    {
+	print STDERR " Error: occur in parse2.pm::processArg(3)\n Unknown Type: -$strArgName with type $strArgType\n";
+	return 0;
+    }
+    
+    return 1;
+}
+
+#--Main Parsing Function----------------------------
+#-----------------------------------------
+# Name: parse
+# Parameters: 1.(Array pointer of the user given argument)
+#             2.(Array pointer of plugin pre-defined argument list)  
+#             3.(Self pointer, where we store all the argument value)
+# Pre-condition: Plugin gives the parameters to parse function in parse2 
+# Post-condition: Store all the default or user given values to the $self->{$ArgumentName}.
+#                 Since $self is a pointer from plugin, plugin will have every values we set.
+# Return value: 1 is parsing successful, 0 is failed.
+#-----------------------------------------
+sub parse
+{
+    # Get the user supplied arguments pointer "\@_"
+    my $aryptUserArguList = shift; 
+
+    # Check if allow extra arguments
+    my $blnAllowExtraOptions = "false";
+    
+    if(scalar(@_) == 3)
+    { 
+	my $strAllowExtraOptions = pop @_;
+	
+	if ($strAllowExtraOptions eq "allow_extra_options") 
+	{
+	    $blnAllowExtraOptions = "true";    
+	} 
+    }
+    
+    my ($aryptSysArguList,$self) = @_;
+    my %hashArg;
+    my %hashInputArg;
+    my @ExtraOption;
+
+    # Transform the system argument (predefined the code) 
+    # from array to hash table for increasing performance
+    %hashArg = &transformArg($aryptSysArguList);
+
+    # Process each User input argument and store the 
+    # information into hashInputArg
+    while (my $strOneArg = shift(@{$aryptUserArguList}))
+    {
+	# Check whether it start with a "-" sign
+	if ($strOneArg =~ /^-+\w/)
+	{
+	    # If it is start with a "-" sign then take it off
+	    $strOneArg =~ s/^-+//;
+
+	    # If the inputed argument is defined in the argument 
+	    # list from this plugin then process
+	    
+	    if(defined $hashArg{$strOneArg})
+	    {
+		#$%^
+		#print "($strOneArg) is processed\n";
+		# Process this argument and store the related 
+		# information in %hashInputArg
+		if(processArg($hashArg{$strOneArg},$aryptUserArguList,\%hashInputArg) == 0){ return 0;}
+	    }
+	    
+	    # Else check if it allows extra options, if yes 
+	    # then push it to a new array, else return fault
+	    else
+	    {
+		if($blnAllowExtraOptions eq "true")
+		{
+		    push(@ExtraOption,"-$strOneArg");
+		}
+		else
+		{
+		    print STDERR " Error: occur in parse2.pm::parse()\n Extra Arguments: $strOneArg\n";
+		    return 0;
+		}
+	    }
+	}
+	
+	# This part follow the previous parsing system. 
+	# It doesn't return error message even user
+	# gave a invalid argument.
+	else
+	{
+	    if($blnAllowExtraOptions eq "true")
+	    {
+		push(@ExtraOption,$strOneArg);
+	    }
+	    else
+	    {
+		print STDERR " Error: occur in parse2.pm::parse()\n Invalid Argument: $strOneArg\n";
+		return 0;
+	    }
+	}
+    }
+
+    # Store the extra option back 
+    # to the user given argument list.
+    @$aryptUserArguList = @ExtraOption;
+    
+    # Now we go through all the pre defined arguments, 
+    # if the user has specified the arguments then just 
+    # set to whatever they set. Otherwise use the default value
+    foreach my $hashOneArg (@{$aryptSysArguList})
+    {
+	my $strArgName = $hashOneArg->{"name"};
+	
+	# If the strArgName has defined in the %hashInputArg, 
+	# this means users has give this argument, store the 
+	# user given to self->{"$strArgName"}
+	if(defined $hashInputArg{$strArgName})
+	{
+	    if(defined $hashOneArg->{"range"})
+	    {
+		if(checkRange($hashOneArg->{"range"},$hashInputArg{$strArgName},$strArgName) == 0){ return 0;}
+	    }
+	    if(defined $hashOneArg->{"char_length"})
+	    {
+		if(checkCharLength($hashOneArg->{"char_length"},$hashInputArg{$strArgName},$strArgName) == 0){ return 0;}
+	    }
+	    $self->{"$strArgName"} = $hashInputArg{"$strArgName"};
+	}
+
+	# Else use the default value of the arguments, 
+	# if there is no default value, then it must be a flag, 
+	# then set it to 0 (which is false)
+	else
+	{
+	    if(defined $hashOneArg->{"deft"})
+	    {
+		$self->{"$strArgName"} = $hashOneArg->{"deft"};
+	    }
+	    else
+	    {
+		if($hashOneArg->{"type"} eq "flag"){ $self->{"$strArgName"} = 0;}
+		elsif($hashOneArg->{"type"} eq "string"){ $self->{"$strArgName"} = "";}
+		elsif($hashOneArg->{"type"} eq "int"){ $self->{"$strArgName"} = "";}
+		elsif($hashOneArg->{"type"} eq "enum"){ $self->{"$strArgName"} = "";}
+		elsif($hashOneArg->{"type"} eq "metadata"){ $self->{"$strArgName"} = "";}
+		else{die "other type without default value:$hashOneArg->{\"type\"}\n";}
+	    }
+	}
+	
+    }
+
+    # If allow_extra_options is set, then return the number of arguments left in the argument list.
+    if($blnAllowExtraOptions eq "true")
+    {
+	return scalar(@$aryptUserArguList);
+    }
+    else
+    {
+	return 1;
+    }
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugin.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugin.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugin.pm	(revision 10506)
@@ -0,0 +1,302 @@
+###########################################################################
+#
+# plugin.pm -- functions to handle using plugins
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package plugin;
+
+use strict; # to pick up typos and undeclared variables...
+no strict 'refs'; # ...but allow filehandles to be variables and vice versa
+
+require util;
+use gsprintf 'gsprintf';
+
+# global variables
+my $stats = {'num_processed' => 0,
+	     'num_blocked' => 0,
+	     'num_not_processed' => 0,
+	     'num_not_recognised' => 0,
+	     'num_archives' => 0
+	     };
+
+#globaloptions contains any options that should be passed to all plugins
+my ($verbosity, $outhandle, $failhandle, $globaloptions);
+
+sub load_plugins {
+    my ($plugin_list) = shift @_;
+    my $keepold;
+    ($verbosity, $outhandle, $failhandle, $globaloptions, $keepold) = @_; # globals
+    my @plugin_objects = ();
+    $keepold = 0 unless (defined $keepold && $keepold == 1);
+    $verbosity = 2 unless defined $verbosity;
+    $outhandle = 'STDERR' unless defined $outhandle;
+    $failhandle = 'STDERR' unless defined $failhandle;
+
+    map { $_ = "\"$_\""; } @$globaloptions;
+    my $globals = join (",", @$globaloptions);
+
+    foreach my $pluginoptions (@$plugin_list) {
+	my $pluginname = shift @$pluginoptions;
+	next unless defined $pluginname;
+
+	# find the plugin
+	my $colplugname = &util::filename_cat($ENV{'GSDLCOLLECTDIR'},"perllib/plugins", 
+					      "${pluginname}.pm");
+	my $mainplugname = &util::filename_cat($ENV{'GSDLHOME'},"perllib/plugins", 
+					       "${pluginname}.pm");
+	if (-e $colplugname) { require $colplugname; }
+	elsif (-e $mainplugname) { require $mainplugname; }
+	else {
+	    gsprintf($outhandle, "{plugin.could_not_find_plugin}\n",
+		     $pluginname);
+	    die "\n";
+	}
+
+	# create a plugin object
+	my ($plugobj);
+	map { $_ = "\"$_\""; } @$pluginoptions;
+	my $options = join (",", @$pluginoptions);
+	if ($globals) {
+	    if (@$pluginoptions) {
+		$options .= ",";
+	    }
+	    $options .= "$globals";
+	}
+	$options =~ s/\$/\\\$/g;
+
+	eval ("\$plugobj = new \$pluginname([],[$options])");
+	die "$@" if $@;
+	
+	# initialize plugin
+	$plugobj->init($verbosity, $outhandle, $failhandle);
+	
+	$plugobj->set_keepold($keepold);
+
+	# add this object to the list
+	push (@plugin_objects, $plugobj);
+    }
+
+    return \@plugin_objects;
+}
+
+
+sub begin {
+    my ($pluginfo, $base_dir, $processor, $maxdocs) = @_;
+   
+
+    map { $_->begin($pluginfo, $base_dir, $processor, $maxdocs); } @$pluginfo;
+}
+
+
+sub metadata_read {
+    my ($pluginfo, $base_dir, $file, $metadata, $extrametakeys, $extrametadata, $processor, $maxdocs, $gli, $aux) = @_;
+
+    $maxdocs = -1 unless defined $maxdocs && $maxdocs =~ /\d/;
+    $gli = 0 unless defined $gli;
+
+    my $rv = 0;
+    my $glifile = $file;
+    
+    $glifile =~ s/^[\/\\]+//; # file sometimes starts with a / so get rid of it
+    
+    # Announce to GLI that we are handling a file
+    print STDERR "<File n='$glifile'>\n" if $gli;
+    
+    # the .kill file is a handy (if not very elegant) way of aborting 
+    # an import.pl or buildcol.pl process
+    if (-e &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, ".kill")) {
+	gsprintf($outhandle, "{plugin.kill_file}\n");
+	die "\n";
+    }
+
+    my $had_error = 0;
+    # pass this file by each of the plugins in turn until one
+    # is found which will process it
+    # read must return:
+    # undef - could not recognise
+    # -1 - tried but error
+    # 0 - blocked
+    # anything else for successful processing
+	
+    foreach my $plugobj (@$pluginfo) {
+
+	$rv = $plugobj->metadata_read($pluginfo, $base_dir, $file, 
+			     $metadata, $extrametakeys, $extrametadata, $processor, $maxdocs, $gli, $aux);
+
+	if (defined $rv) {
+	    if ($rv == -1) {
+	        # an error has occurred
+		$had_error = 1;
+		print STDERR "<ProcessingError n='$glifile'>\n" if $gli;
+	    } else {
+        	return $rv;
+	    }
+	} # else undefined - was not recognised by the plugin
+    }
+
+    return 0;
+}
+
+sub read {
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli, $aux) = @_;
+
+    $maxdocs = -1 unless defined $maxdocs && $maxdocs =~ /\d/;
+    $total_count = 0 unless defined $total_count && $total_count =~ /\d/;
+    $gli = 0 unless defined $gli;
+
+    my $rv = 0;
+    my $glifile = $file;
+    
+    $glifile =~ s/^[\/\\]+//; # file sometimes starts with a / so get rid of it
+    
+    # Announce to GLI that we are handling a file
+    print STDERR "<File n='$glifile'>\n" if $gli;
+    
+    # the .kill file is a handy (if not very elegant) way of aborting 
+    # an import.pl or buildcol.pl process
+    if (-e &util::filename_cat ($ENV{'GSDLCOLLECTDIR'}, ".kill")) {
+	gsprintf($outhandle, "{plugin.kill_file}\n");
+	die "\n";
+    }
+
+    my $had_error = 0;
+    # pass this file by each of the plugins in turn until one
+    # is found which will process it
+    # read must return:
+    # undef - could not recognise
+    # -1 - tried but error
+    # 0 - blocked
+    # anything else for successful processing
+	
+    foreach my $plugobj (@$pluginfo) {
+
+      	$rv = $plugobj->read($pluginfo, $base_dir, $file, 
+			     $metadata, $processor, $maxdocs, $total_count, $gli, $aux);
+
+	if (defined $rv) {
+	    if ($rv == -1) {
+	        # an error has occurred
+		$had_error = 1;
+	    } else {
+        	return $rv;
+	    }
+	} # else undefined - was not recognised by the plugin
+    }
+
+    if ($had_error) {
+	# was recognised but couldn't be processed
+	if ($verbosity >= 2) {
+	    gsprintf($outhandle, "{plugin.no_plugin_could_process}\n", $file);
+	}
+	# tell the GLI that it was not processed
+	print STDERR "<NonProcessedFile n='$glifile'>\n" if $gli;
+      
+	$file =~ s/.*?([^\\\/]+)$/$1/;
+	gsprintf($failhandle, "$file: {plugin.no_plugin_could_process_this_file}\n");
+	$stats->{'num_not_processed'} ++;
+    } else {
+	# was not recognised
+	if ($verbosity >= 2) {
+	    gsprintf($outhandle, "{plugin.no_plugin_could_recognise}\n",$file);
+	}
+	# tell the GLI that it was not processed
+	print STDERR "<NonRecognisedFile n='$glifile'>\n" if $gli;
+	
+	$file =~ s/.*?([^\\\/]+)$/$1/;
+	gsprintf($failhandle, "$file: {plugin.no_plugin_could_recognise_this_file}\n");
+	$stats->{'num_not_recognised'} ++;
+    }
+    return 0;
+}
+
+# write out some general stats that the plugins have compiled - note that
+# the buildcol.pl process doesn't currently call this process so the stats
+# are only output after import.pl -
+sub write_stats {
+    my ($pluginfo, $statshandle, $faillog, $gli) = @_;
+
+    $gli = 0 unless defined $gli;
+
+    foreach my $plugobj (@$pluginfo) {
+	$plugobj->compile_stats($stats);
+    }
+
+    my $total = $stats->{'num_processed'} + $stats->{'num_blocked'} + 
+	$stats->{'num_not_processed'} + $stats->{'num_not_recognised'};
+
+    print STDERR "<ImportComplete considered='$total' processed='$stats->{'num_processed'}' blocked='$stats->{'num_blocked'}' ignored='$stats->{'num_not_recognised'}' failed='$stats->{'num_not_processed'}'>\n" if $gli;
+
+    if ($total == 1) {
+	gsprintf($statshandle, "* {plugin.one_considered}\n");
+    } else {
+	gsprintf($statshandle, "* {plugin.n_considered}\n", $total);
+    }
+    if ($stats->{'num_archives'}) {
+	if ($stats->{'num_archives'} == 1) {
+	    gsprintf($statshandle, "   ({plugin.including_archive})\n");
+	}
+	else {
+	    gsprintf($statshandle, "   ({plugin.including_archives})\n",
+		     $stats->{'num_archives'});
+	}
+    }
+    if ($stats->{'num_processed'} == 1) {
+	gsprintf($statshandle, "* {plugin.one_included}\n");
+    } else {
+	gsprintf($statshandle, "* {plugin.n_included}\n", $stats->{'num_processed'});
+    }
+    if ($stats->{'num_not_recognised'}) {
+	if ($stats->{'num_not_recognised'} == 1) {
+	    gsprintf($statshandle, "* {plugin.one_unrecognised}\n");
+	} else {
+	    gsprintf($statshandle, "* {plugin.n_unrecognised}\n",
+		     $stats->{'num_not_recognised'});
+	}
+
+    }
+    if ($stats->{'num_not_processed'}) {
+	if ($stats->{'num_not_processed'} == 1) {
+	    gsprintf($statshandle, "* {plugin.one_rejected}\n");
+	} else {
+	    gsprintf($statshandle, "* {plugin.n_rejected}\n",
+		     $stats->{'num_not_processed'});
+	}
+    }
+    if ($stats->{'num_not_processed'} || $stats->{'num_not_recognised'}) {
+	gsprintf($statshandle, " {plugin.see_faillog}\n", $faillog);
+    }
+}
+
+sub end {
+    my ($pluginfo, $processor) = @_;
+    map { $_->end($processor); } @$pluginfo;
+}
+
+sub deinit {
+    my ($pluginfo, $processor) = @_;
+   
+
+    map { $_->deinit($processor); } @$pluginfo;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ArcPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ArcPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ArcPlug.pm	(revision 10506)
@@ -0,0 +1,180 @@
+###########################################################################
+#
+# ArcPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# plugin which recurses through an archives.inf file
+# (i.e. the file generated in the archives directory
+# when an import is done), processing each file it finds 
+
+# 12-05-02 Added usage datastructure - John Thompson
+
+package ArcPlug;
+
+use util;
+use BasPlug;
+use plugin;
+use arcinfo;
+use gsprintf;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+BEGIN {
+    @ArcPlug::ISA = ('BasPlug');
+}
+
+my $arguments = [
+		 ];
+
+my $options = { 'name'     => "ArcPlug",
+		'desc'     => "{ArcPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes" };
+         
+sub gsprintf
+{
+    return &gsprintf::gsprintf(@_);
+}
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub deinit {
+    my ($self) = @_;
+
+    my $archive_info = $self->{'archive_info'};
+
+    if (defined $archive_info) {
+	my $archive_info_filename = $self->{'archive_info_filename'};
+
+       	my $file_list = $archive_info->get_file_list();
+
+	# change each file to "Been Indexed"
+
+	foreach my $subfile (@$file_list) {
+	    my $doc_oid = $subfile->[1];
+	    # why do we get this when it is not used???
+	    my $index_status = $archive_info->get_status_info($doc_oid);
+	    $archive_info->set_status_info($doc_oid,"B");
+	}
+
+	$archive_info->save_info($archive_info_filename);
+    }
+}
+
+# return 1 if this class might recurse using $pluginfo
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 1;
+}
+
+
+
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs,$total_count, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $count = 0;
+
+    # see if this has a archives information file within it
+    my $archive_info_filename = &util::filename_cat($base_dir,$file,"archives.inf");
+    $self->{'archive_info_filename'} = $archive_info_filename;
+
+    if (-e $archive_info_filename) {
+
+	# found an archives.inf file
+	&gsprintf($outhandle, "ArcPlug: {common.processing} $archive_info_filename\n") if $self->{'verbosity'} > 1;
+
+	# read in the archives information file
+	my $archive_info = new arcinfo ();
+	$self->{'archive_info'} = $archive_info;
+
+	$archive_info->load_info ($archive_info_filename);
+	
+	my $file_list = $archive_info->get_file_list();
+
+	# process each file
+	foreach my $subfile (@$file_list) {
+	    last if ($maxdocs != -1 && ($total_count + $count) >= $maxdocs);
+
+	    my $tmp = &util::filename_cat ($file, $subfile->[0]);
+	    next if $tmp eq $file;
+
+	    # Decide if file needs to be processed
+	    my $doc_oid = $subfile->[1];
+	    my $index_status = $archive_info->get_status_info($doc_oid);
+
+	    my $process_file = 0;
+	    
+	    if ($processor->get_mode() eq "infodb") {
+		$process_file = 1;
+	    }
+	    else {
+		if (!$processor->is_incremental_capable() || !$self->{'keepold'}) {
+		    $process_file = 1;
+		}
+		else {
+		    # is incremental
+
+		    # check to see if file needs to be indexed
+		    $index_status = $archive_info->get_status_info($doc_oid);
+
+		    if ($index_status eq "I") {
+			$process_file = 1;
+		    }
+		}
+	    }
+
+
+	    if ($process_file) {
+		# note: metadata is not carried on to the next level
+		$count += &plugin::read ($pluginfo, $base_dir, $tmp, {}, $processor, $maxdocs, ($total_count+$count), $gli);
+	    }
+
+	}
+
+	return $count;
+    }
+
+    # wasn't an archives directory, someone else will have to process it
+    return undef;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BNContentePlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BNContentePlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BNContentePlug.pm	(revision 10506)
@@ -0,0 +1,321 @@
+###########################################################################
+#
+# BNContentePlug.pm -- plugin for import the BN-Portugal Collection
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# BNContentePlug - 11/2004
+# 
+#
+# This plugin takes "mets.xml" and "record/NCB_***.xml: the file contain MARC details
+# about BN-Portugal ccllection. The intension is to import such a collection into GS2.
+
+package BNContentePlug;
+
+use BasPlug;
+use plugin;
+#use ghtml;
+use XMLParser;
+use XML::Parser;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @BNContentePlug::ISA = ('BasPlug');
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "string",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "only_first_doc",
+	'desc' => "{BNContentePlug.only_first_doc}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "first_inoder_ext",
+	'desc' => "{BNContentePlug.first_inorder_ext}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "first_inorder_mime",
+	'desc' => "{BNContentePlug.first_inorder_mime}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => "string",
+	'deft' => &get_default_block_exp(),
+	'reqd' => "no" }];
+
+my $options = { 'name'     => "BNContentePlug",
+		'desc'     => "{BNContentePlug.desc}",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+# Important variation to regular plugin structure.  Need to desclare
+# $self as global variable to file so XMLParser callback routines
+# can access the content of the object. 
+my ($self); 
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)(metsHTML\.xml)$^;
+}
+
+# block files
+sub get_default_block_exp {
+    my $self = shift (@_);
+    
+    # Block all files besides contents
+    #return q^(?i)(metsHTML\.xml|)$^;
+    return q^(?i)((.*?)\.(.*?))$^;
+}
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+    
+    #create XML::Parser object for parsing metsHTML.xml, NCB_???.xml files
+    my $mets_parser = new XML::Parser('Style' => 'Stream',
+				      'Handlers' => {'Doctype' => \&METS_Doctype,
+						     'Start' => \&METS_StartTag,
+						     'End' => \&METS_EndTag
+						     });
+    
+    my $marc_parser = new XML::Parser('Style' => 'Stream',
+				      'Handlers' => {'Char' => \&Char,
+						     'Doctype' => \&MARC_Doctype,
+						     'Start' => \&MARC_StartTag,
+						     'End' => \&MARC_EndTag
+						     });
+    $self->{'mets_parser'} = $mets_parser;
+    $self->{'marc_parser'} = $marc_parser;
+
+    $self->{'index_file'} = "";
+
+    return bless $self, $class;
+}
+
+sub read_marc_content {
+    my $self = shift (@_);
+    my ($marc_file) = @_;
+    
+    # parse the Marc_file: NCB_???.xml
+    eval{
+	$self->{'marc_parser'}->parsefile($marc_file);
+    };
+    
+    if ($@) {
+	die "BNContentePlug: ERROR $marc_file is not a well formed XML file ($@)\n";
+    }  
+}
+
+# Read metsHTML.xml from BN-Portugal collection 
+sub metadata_read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $extrametakeys, $extrametadata, $processor, $maxdocs, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+    
+    my $filename = &util::filename_cat($base_dir, $file);
+
+    if ($filename !~ /metsHTML\.xml$/ || !-f $filename) {
+	if ($filename =~ /\.xml$/i || $filename =~ /log\.txt$/i || $filename =~ /isbd\.html$/i) {
+	    $self->{'file_blocks'}->{$filename}=1;
+	}
+	return undef;
+    } else {
+	$self->{'file_blocks'}->{$filename}=1;	
+    }
+  
+    print $outhandle "BNContentePlug: extracting metadata from $filename\n"
+	if $self->{'verbosity'} > 1;
+   
+    my ($dir) = $filename =~ /^(.*?)[^\/\\]*$/;
+    $self->{'dir'} = $dir;
+
+    eval {
+	$self->{'mets_parser'}->parsefile($filename);
+    };
+    
+    if ($@) {
+	die "BNContentePlug: ERROR $filename is not a well formed XML file ($@)\n";
+    }
+    
+    # read NCB_???.xml to parse MARC records and save as metadata
+    my $marc_file = &util::filename_cat($dir,$self->{'marc_file'});
+    $self->read_marc_content ($marc_file);
+
+    if (defined $self->{'index_file'} && $self->{'index_file'} ne "") {
+	my $index_file = $self->{'index_file'};
+	push(@$extrametakeys,$index_file);
+	$extrametadata->{$index_file} = $self->{'saved_metadata'};
+    } else {
+	print STDERR "####Warning can't find main index file\n";
+    }
+    return 1;
+}
+
+# The BNContentePlug read() function. This function does all the right things
+# to make general options work for a given plugin. It calls the process()
+# function which does all the work specific to a plugin (like the old
+# read functions used to do). Most plugins should define their own 
+# process() function and let this read() function keep control.
+#
+# Return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+
+sub readxxx {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    my $filename = &util::filename_cat($base_dir, $file);
+    #return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+    
+    #return 0 if ($filename =~ /metsHTML\.xml$/);
+    return 0 if ($filename =~ /\.xml$/);
+    return 0 if (defined $self->{'file_blocks'}->{'filename'});
+    
+    return undef;
+}
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    return 1;
+}
+
+sub METS_Doctype {
+    my ($expat, $name, $sysid, $pubid, $internal) = @_;
+    die if ($name !~ /^metsHTML\.xml$/);
+}
+
+sub MARC_Doctype {
+    my ($expat, $name, $sysid, $pubid, $internal) = @_;
+    print STDERR "###MARC Name =$name\n";
+    #die if ($name !~ /^metsHTML\.xml$/);
+    #die if (!$name);
+}
+
+sub METS_StartTag {
+    my ($expat, $element, %attr) = @_;
+    my @file_blocks;
+    if ($element eq "dmdSec") {
+	$self->{'marc_file'} = "";
+    } elsif ($element eq "mdRef") {
+	my $marc_href = $attr{'xlink:href'};
+	$self->{'marc_file'} = $marc_href;
+    } elsif ($element eq "FLocat"){
+ 	my $assocfiles = $attr{'xlink:href'};
+ 	if ($assocfiles =~ /index\.html$/) {
+ 	    my $index_file = &util::filename_cat($self->{'dir'}, $assocfiles);
+ 	    $self->{'index_file'} = $index_file;
+ 	} else {
+	    my $link = &util::filename_cat($self->{'dir'}, $assocfiles);
+	    #$self->{'file_blocks'}->{$link} = 1;
+	}
+    }
+}
+
+sub METS_EndTag {
+    my ($expat, $element, %attr) = @_;
+}
+
+sub MARC_StartTag {
+    my ($expat, $element, %attr) = @_;
+
+    if ($element eq "record") {
+	$self->{'saved_metadata'} = {};
+    }
+    elsif ($element eq "datafield") {
+	$self->{'metaname'} = $element;
+	$self->{'datafield'} = $attr{'tag'};
+    }
+    elsif ($element eq "subfield") {
+	$self->{'subfield'} = $attr{'code'};
+	$self->{'text'} = "";
+    }
+}
+
+sub MARC_EndTag {
+    my ($expat, $element) = @_;
+
+    if ($element eq "datafield") {
+	$self->{'metaname'} = "";
+    }
+    elsif ($element eq "subfield") {
+	my $mvalue = $self->{'text'};
+	my $mname = $self->{'datafield'}."^".$self->{'subfield'};
+	#print STDERR "**** $mname = $mvalue\n";
+	
+	$mvalue =~ s/\[/&\#91;/g;
+	$mvalue =~ s/\[/&\#93;/g;
+	
+
+	if (defined $self->{'saved_metadata'}->{$mname}) {
+	    # accumulate - add value to existing value(s)
+	    if (ref ($self->{'saved_metadata'}->{$mname}) eq "ARRAY") {
+		push (@{$self->{'saved_metadata'}->{$mname}}, $mvalue);
+	    } else {
+		$self->{'saved_metadata'}->{$mname} = 
+		    [$self->{'saved_metadata'}->{$mname}, $mvalue];
+	    }
+	} else {
+	    # accumulate - add value into (currently empty) array
+	    $self->{'saved_metadata'}->{$mname} = [$mvalue];
+	}
+	# store something here 
+	$self->{'subfield'} = "";
+	$self->{'text'} = "";
+    }
+
+}
+
+
+# This Char function overrides the one in XML::Parser::Stream to overcome a
+# problem where $expat->{Text} is treated as the return value, slowing
+# things down significantly in some cases.
+sub Char {
+    use bytes;  # Necessary to prevent encoding issues with XML::Parser 2.31+
+    $_[0]->{'Text'} .= $_[1];
+    if ((defined $self->{'subfield'} && ($self->{'subfield'} ne ""))) {
+	$self->{'text'} .= $_[1];
+    }
+    return undef;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BasPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BasPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BasPlug.pm	(revision 10506)
@@ -0,0 +1,1449 @@
+###########################################################################
+#
+# BasPlug.pm -- base class for all the import plugins
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999-2005 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package BasPlug;
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+}
+
+eval {require bytes};
+
+# suppress the annoying "subroutine redefined" warning that various
+# plugins cause under perl 5.6
+$SIG{__WARN__} = sub {warn($_[0]) unless ($_[0] =~ /Subroutine\s+\S+\sredefined/)};
+
+use strict; 
+no strict 'subs';
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+use File::Basename;
+
+use Kea;
+use multiread;
+use encodings;
+use cnseg;
+use acronym;
+use textcat;
+use doc;
+eval "require diagnostics"; # some perl distros (eg mac) don't have this
+use DateExtract;
+use ghtml;
+use gsprintf 'gsprintf';
+use printusage;
+use parse2;
+
+
+use GISBasPlug;
+
+@BasPlug::ISA = ( GISBasPlug );
+
+my $unicode_list =
+    [ { 'name' => "ascii",
+	'desc' => "{BasPlug.input_encoding.ascii}" },
+      { 'name' => "utf8",
+	'desc' => "{BasPlug.input_encoding.utf8}" },
+      { 'name' => "unicode",
+	'desc' => "{BasPlug.input_encoding.unicode}" } ];
+
+my $auto_unicode_list = 
+    [ { 'name' => "auto",
+	'desc' => "{BasPlug.input_encoding.auto}" } ];
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => "regexp",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "smart_block",
+	'desc' => "{BasPlug.smart_block}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "associate_ext",
+	'desc' => "{BasPlug.associate_ext}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "input_encoding",
+	'desc' => "{BasPlug.input_encoding}",
+	'type' => "enum",
+	'list' => $auto_unicode_list,
+	'reqd' => "no" ,
+	'deft' => "auto" } ,
+      { 'name' => "default_encoding",
+	'desc' => "{BasPlug.default_encoding}",
+	'type' => "enum",
+	'list' => $unicode_list,
+	'reqd' => "no",
+        'deft' => "utf8" },
+      { 'name' => "extract_language",
+	'desc' => "{BasPlug.extract_language}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "default_language",
+	'desc' => "{BasPlug.default_language}",
+	'type' => "string",
+	'deft' => "en",
+	'reqd' => "no" },
+      { 'name' => "extract_acronyms",
+	'desc' => "{BasPlug.extract_acronyms}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "markup_acronyms",
+	'desc' => "{BasPlug.markup_acronyms}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "extract_keyphrases",
+	'desc' => "{BasPlug.extract_keyphrases}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "extract_keyphrase_options",
+	'desc' => "{BasPlug.extract_keyphrase_options}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "first",
+	'desc' => "{BasPlug.first}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "extract_email",
+	'desc' => "{BasPlug.extract_email}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "extract_historical_years",
+	'desc' => "{BasPlug.extract_historical_years}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "maximum_year",
+	'desc' => "{BasPlug.maximum_year}",
+	'type' => "int",
+	'deft' => (localtime)[5]+1900,
+	'char_length' => "4",
+	#'range' => "2,100",
+	'reqd' => "no"},
+      { 'name' => "maximum_century",
+	'desc' => "{BasPlug.maximum_century}",
+	'type' => "string",
+	'deft' => "-1",
+	'reqd' => "no" },
+      { 'name' => "no_bibliography",
+	'desc' => "{BasPlug.no_bibliography}",
+	'type' => "flag",
+	'reqd' => "no"},
+      { 'name' => "no_cover_image",
+	'desc' => "{BasPlug.no_cover_image}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "extract_keyphrases",
+	'desc' => "{BasPlug.extract_keyphrases}",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" },
+      { 'name' => "extract_keyphrase_options",
+	'desc' => "{BasPlug.extract_keyphrase_options}",
+	'type' => "string",
+	'reqd' => "no",
+	'hiddengli' => "yes" },
+      { 'name' => "separate_cjk",
+	'desc' => "{BasPlug.separate_cjk}",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" },
+      { 'name' => "smart_block",
+	'desc' => "{BasPlug.smart_block}",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" },
+      { 'name' => "new_extract_email",
+	'desc' => "",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" } ];
+
+my $gis_arguments = 
+    [ { 'name' => "extract_placenames",
+	'desc' => "{GISBasPlug.extract_placenames}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "gazetteer",
+	'desc' => "{GISBasPlug.gazetteer}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "place_list",
+	'desc' => "{GISBasPlug.place_list}",
+	'type' => "flag",
+	'reqd' => "no" } ];
+
+
+my $options = { 'name'     => "BasPlug",
+		'desc'     => "{BasPlug.desc}",
+		'abstract' => "yes",
+		'inherits' => "no",
+		'args'     => $arguments };
+
+
+sub set_keepold {
+    my $self = shift(@_);
+    my ($keepold) = @_;
+
+    $self->{'keepold'} = $keepold;
+}
+
+sub get_arguments
+{
+    my $self = shift(@_);
+    my $optionlistref = $self->{'option_list'};
+    my @optionlist = @$optionlistref;
+    my $pluginoptions = pop(@$optionlistref);
+    my $pluginarguments = $pluginoptions->{'args'};
+    return $pluginarguments;
+}
+
+
+sub print_xml_usage
+{
+    my $self = shift(@_);
+
+    # XML output is always in UTF-8
+    gsprintf::output_strings_in_UTF8;
+
+    PrintUsage::print_xml_header();
+    $self->print_xml();
+}
+
+
+sub print_xml
+{
+    my $self = shift(@_);
+
+    my $optionlistref = $self->{'option_list'};
+    my @optionlist = @$optionlistref;
+    my $pluginoptions = shift(@$optionlistref);
+    return if (!defined($pluginoptions));
+
+    gsprintf(STDERR, "<PlugInfo>\n");
+    gsprintf(STDERR, "  <Name>$pluginoptions->{'name'}</Name>\n");
+    my $desc = gsprintf::lookup_string($pluginoptions->{'desc'});
+    $desc =~ s/</&amp;lt;/g; # doubly escaped
+    $desc =~ s/>/&amp;gt;/g;
+    
+    gsprintf(STDERR, "  <Desc>$desc</Desc>\n");
+    gsprintf(STDERR, "  <Abstract>$pluginoptions->{'abstract'}</Abstract>\n");
+    gsprintf(STDERR, "  <Inherits>$pluginoptions->{'inherits'}</Inherits>\n");
+    gsprintf(STDERR, "  <Explodes>" . ($pluginoptions->{'explodes'} || "no") . "</Explodes>\n");
+    gsprintf(STDERR, "  <Arguments>\n");
+    if (defined($pluginoptions->{'args'})) {
+	&PrintUsage::print_options_xml($pluginoptions->{'args'});
+    }
+
+    # Recurse up the plugin hierarchy
+    $self->print_xml();
+
+    gsprintf(STDERR, "  </Arguments>\n");
+    gsprintf(STDERR, "</PlugInfo>\n");
+}
+
+
+sub print_txt_usage
+{
+    my $self = shift(@_);
+    # Print the usage message for a plugin (recursively)
+    my $descoffset = $self->determine_description_offset(0);
+    $self->print_plugin_usage($descoffset, 1);
+}
+
+
+sub determine_description_offset
+{
+    my $self = shift(@_);
+    my $maxoffset = shift(@_);
+
+    my $optionlistref = $self->{'option_list'};
+    my @optionlist = @$optionlistref;
+    my $pluginoptions = shift(@$optionlistref);
+    return $maxoffset if (!defined($pluginoptions));
+
+    # Find the length of the longest option string of this plugin
+    my $pluginargs = $pluginoptions->{'args'};
+    if (defined($pluginargs)) {
+	my $longest = &PrintUsage::find_longest_option_string($pluginargs);
+	if ($longest > $maxoffset) {
+	    $maxoffset = $longest;
+	}
+    }
+
+    # Recurse up the plugin hierarchy
+    $maxoffset = $self->determine_description_offset($maxoffset);
+    $self->{'option_list'} = \@optionlist;
+    return $maxoffset;
+}
+
+
+sub print_plugin_usage
+{
+    my $self = shift(@_);
+    my $descoffset = shift(@_);
+    my $isleafclass = shift(@_);
+
+    my $optionlistref = $self->{'option_list'};
+    my @optionlist = @$optionlistref;
+    my $pluginoptions = shift(@$optionlistref);
+    return if (!defined($pluginoptions));
+
+    my $pluginname = $pluginoptions->{'name'};
+    my $pluginargs = $pluginoptions->{'args'};
+    my $plugindesc = $pluginoptions->{'desc'};
+
+    # Produce the usage information using the data structure above
+    if ($isleafclass) {
+	if (defined($plugindesc)) {
+	    gsprintf(STDERR, "$plugindesc\n\n");
+	}
+	gsprintf(STDERR, " {common.usage}: plugin $pluginname [{common.options}]\n\n");
+    }
+
+    # Display the plugin options, if there are some
+    if (defined($pluginargs)) {
+	# Calculate the column offset of the option descriptions
+	my $optiondescoffset = $descoffset + 2;  # 2 spaces between options & descriptions
+
+	if ($isleafclass) {
+	    gsprintf(STDERR, " {common.specific_options}:\n");
+	}
+	else {
+	    gsprintf(STDERR, " {common.general_options}:\n", $pluginname);
+	}
+
+	# Display the plugin options
+	&PrintUsage::print_options_txt($pluginargs, $optiondescoffset);
+    }
+
+    # Recurse up the plugin hierarchy
+    $self->print_plugin_usage($descoffset, 0);
+    $self->{'option_list'} = \@optionlist;
+}
+
+
+sub new {
+    # Set Encodings to the list!!
+
+    my $e = $encodings::encodings;
+    foreach my $enc (sort {$e->{$a}->{'name'} cmp $e->{$b}->{'name'}} keys (%$e)) 
+    {
+	my $hashEncode =
+	    {'name' => $enc,
+	     'desc' => $e->{$enc}->{'name'}};
+
+	push(@{$unicode_list},$hashEncode);
+    }
+
+    push(@{$auto_unicode_list},@{$unicode_list});
+
+    # Start the BasPlug Constructor
+    my $class = shift (@_);
+    my ($pluginlist,$args,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+    my $plugin_name = (defined $pluginlist->[0]) ? $pluginlist->[0] : $class;
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    if (GISBasPlug::has_mapdata()) {
+	push(@$arguments,@$gis_arguments);
+    }
+    
+    my $self = {};
+    if(!parse2::parse($args,$hashArgOptLists->{"ArgList"},$self))
+    {
+	my $classTempClass = bless $self, $class;
+	&gsprintf(STDERR, "\n{BasPlug.bad_general_option}\n", $plugin_name);
+	$classTempClass->print_txt_usage("");  # Use default resource bundle
+	die "\n";
+    }
+
+
+    # else parsing was successful.
+
+    $self->{'plugin_type'} = $plugin_name;
+    $self->{'outhandle'} = STDERR;
+    $self->{'textcat'} = new textcat();
+    $self->{'num_processed'} = 0;
+    $self->{'num_not_processed'} = 0;
+    $self->{'num_blocked'} = 0;
+    $self->{'num_archives'} = 0;
+    $self->{'cover_image'} = 1; # cover image is on by default
+    $self->{'cover_image'} = 0 if ($self->{'no_cover_image'});
+    $self->{'file_blocks'} = {};
+    $self->{'option_list'} = $hashArgOptLists->{"OptList"};
+    
+    my $associate_ext = $self->{'associate_ext'};
+    if ((defined $associate_ext) && ($associate_ext ne "")) {
+	my @exts = split(/,/,$associate_ext);
+
+	my %associate_ext_lookup = ();
+	foreach my $e (@exts) {
+	    $associate_ext_lookup{$e} = 1;
+	}
+
+	$self->{'associate_ext_lookup'} = \%associate_ext_lookup;
+    }
+
+    $self->{'shared_fileroot'} = {};
+    $self->{'file_blocks'} = {};
+
+    if ($self->{'extract_placenames'}) {
+
+	my $outhandle = $self->{'outhandle'};
+	
+	my $places_ref 
+	    = GISBasPlug::loadGISDatabase($outhandle,$self->{'gazetteer'});
+	
+	if (!defined $places_ref) {
+	    print $outhandle "Warning: Error loading mapdata gazetteer \"$self->{'gazetteer'}\"\n";
+	    print $outhandle "         No placename extraction will take place.\n";
+	    $self->{'extract_placenames'} = undef;
+	}
+	else {
+	    $self->{'places'} = $places_ref;
+	}
+    }
+    return bless $self, $class;
+    
+}
+
+# initialize BasPlug options
+# if init() is overridden in a sub-class, remember to call BasPlug::init()
+sub init {
+    my $self = shift (@_);
+    my ($verbosity, $outhandle, $failhandle) = @_;
+
+    # verbosity is passed through from the processor
+    $self->{'verbosity'} = $verbosity;
+
+    # as are the outhandle and failhandle
+    $self->{'outhandle'} = $outhandle if defined $outhandle;
+    $self->{'failhandle'} = $failhandle;
+
+    # set process_exp and block_exp to defaults unless they were
+    # explicitly set
+
+    if ((!$self->is_recursive()) and 
+	(!defined $self->{'process_exp'}) || ($self->{'process_exp'} eq "")) {
+
+	$self->{'process_exp'} = $self->get_default_process_exp ();
+	if ($self->{'process_exp'} eq "") {
+	    warn ref($self) . " Warning: Non-recursive plugin has no process_exp\n";
+	}
+    }
+
+    if ((!defined $self->{'block_exp'}) || ($self->{'block_exp'} eq "")) {
+	$self->{'block_exp'} = $self->get_default_block_exp ();
+    }
+}
+
+sub begin {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $processor, $maxdocs) = @_;
+    $self->initialise_extractors();
+}
+
+sub end {
+    # potentially called at the end of each plugin pass 
+    # import.pl only has one plugin pass, but buildcol.pl has multiple ones
+
+    my ($self) = @_;
+    $self->finalise_extractors();
+}
+
+sub deinit {
+    # called only once, after all plugin passes have been done
+
+    my ($self) = @_;
+}
+
+# this function should be overridden to return 1
+# in recursive plugins
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 0; 
+}
+
+sub get_default_block_exp {
+    my $self = shift (@_);
+
+    return "";
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return "";
+}
+
+# default implementation is to do nothing. 
+sub store_block_files
+{
+    my $self =shift (@_);
+    my ($filename) = @_;
+    return;
+}
+
+#default implementation is to block a file with same name as this, but extension jpg or JPG, if cover_images is on.
+sub block_cover_image
+{
+    my $self =shift (@_);
+    my ($filename) = @_;
+    if ($self->{'cover_image'}) {
+	my $coverfile = $filename;
+	$coverfile =~ s/\.[^\\\/\.]+$/\.jpg/;
+	if (!-e $coverfile) {
+	    $coverfile =~ s/jpg$/JPG/;
+	} 	
+	if (-e $coverfile) {
+	    $self->{'file_blocks'}->{$coverfile} = 1;
+	}
+    }
+
+    return;
+}
+    
+sub metadata_read {
+    my $self = shift (@_);  
+    my ($pluginfo, $base_dir, $file, $metadata, $extrametakeys, $extrametadata, $processor, $maxdocs, $gli) = @_;
+    # Keep track of filenames with same root but different extensions
+    # Used to support -associate_ext
+
+    my $associate_ext = $self->{'associate_ext'};
+    if ((defined $associate_ext) && ($associate_ext ne "")) {
+
+	my ($file_prefix,$file_ext) = ($file =~ m/^(.*)\.(.*?)$/);
+	if ((defined $file_prefix) && (defined $file_ext)) {
+	    
+	    my $shared_fileroot = $self->{'shared_fileroot'};
+	    if (!defined $shared_fileroot->{$file_prefix}) {
+		my $file_prefix_rec = { 'tie_to' => undef, 'exts' => {} };
+		$shared_fileroot->{$file_prefix} = $file_prefix_rec;
+	    }
+	    
+	    my $file_prefix_rec = $shared_fileroot->{$file_prefix};
+
+	    my $process_exp = $self->{'process_exp'};
+
+	    if ($file =~ m/$self->{'process_exp'}/) {
+		# This is the document the others should be tied to
+		$file_prefix_rec->{'tie_to'} = $file_ext;
+	    }
+	    else {
+		if (defined $self->{'associate_ext_lookup'}->{$file_ext}) {
+		    $file_prefix_rec->{'exts'}->{$file_ext} = 1;
+		}
+	    }
+	}
+    }
+    
+    # now check whether we are actually processing this
+    my $filename = $file;
+    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+    if ($self->{'process_exp'} eq "" || $filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef; # can't recognise
+    }
+
+    # do smart blocking if appropriate
+    if (defined $self->{'smart_block'}) {
+	$self->block_cover_image($filename);
+	$self->store_block_files($filename);
+    }
+       
+    return 1;
+}
+
+sub tie_to_filename
+{
+    my $self = shift (@_);  
+  
+    my ($file_ext,$file_prefix_rec) = @_;
+
+    if (defined $file_prefix_rec) {
+	my $tie_to = $file_prefix_rec->{'tie_to'};
+
+	if (defined $tie_to) {
+	    if ($tie_to eq $file_ext) {
+		return 1;
+	    }
+	}
+    }
+
+    return 0;
+}
+
+sub tie_to_assoc_file
+{
+    my $self = shift (@_);    
+    my ($file_ext,$file_prefix_rec) = @_;
+
+    if (defined $file_prefix_rec) {
+	my $tie_to = $file_prefix_rec->{'tie_to'};
+	if (defined $tie_to) {
+
+	    my $exts = $file_prefix_rec->{'exts'};
+
+	    my $has_file_ext = $exts->{$file_ext};
+	    
+	    if ($has_file_ext) {
+		return 1;
+	    }
+	}
+    }
+
+    return 0;
+}
+
+
+sub associate_with
+{
+    my $self = shift (@_);    
+    my ($file, $filename, $metadata) = @_;
+
+    my $associate_ext = $self->{'associate_ext'};
+
+
+    return 0 if (!$associate_ext);
+
+    # If file, see if matches with "tie_to" doc or is one of the
+    # associated filename extensions.
+
+    my ($file_prefix,$file_ext) = ($file =~ m/^(.*)\.(.*?)$/);
+    if ((defined $file_prefix) && (defined $file_ext)) {
+
+	my $file_prefix_rec = $self->{'shared_fileroot'}->{$file_prefix};
+	
+	if ($self->tie_to_filename($file_ext,$file_prefix_rec)) {
+
+	    # Set up gsdlassocfile_tobe
+
+	    my $exts = $file_prefix_rec->{'exts'};
+		
+	    if (!defined $metadata->{'gsdlassocfile_tobe'}) {
+		$metadata->{'gsdlassocfile_tobe'} = [];
+	    }
+
+	    my $assoc_tobe = $metadata->{'gsdlassocfile_tobe'};
+			
+	    my ($full_prefix) = ($filename =~ m/^(.*)\..*?$/);
+	    foreach my $e (keys %$exts) {		
+		my $assoc_file = "$full_prefix.$e";
+		my $mime_type = ""; # let system auto detect this
+		push(@$assoc_tobe,"$assoc_file:$mime_type:"); 
+	    }
+	}
+	elsif ($self->tie_to_assoc_file($file_ext,$file_prefix_rec)) {
+	    # a form of smart block
+	    
+	    return 1;
+	}
+    }
+
+    return 0;
+}
+
+
+sub read_block {
+    my $self = shift (@_);  
+  
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+
+    my $filename = $file;
+    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+
+    if ($self->associate_with($file,$filename,$metadata)) {
+	# a form of smart block
+	$self->{'num_blocked'} ++;
+	return (0,undef); # blocked
+    }
+
+    my $smart_block = $self->{'smart_block'};
+    my $smart_block_BN = $self->{'smart_block_BN'};
+
+    if ($smart_block || $smart_block_BN) {
+	if (defined $self->{'file_blocks'}->{$filename} && $self->{'file_blocks'}->{$filename} == 1){
+	    $self->{'num_blocked'} ++;
+	    return (0,undef); # blocked
+	}
+    } elsif ($self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/) {
+	$self->{'num_blocked'} ++;
+	return (0,undef); # blocked
+    }
+    
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return (undef,undef); # can't recognise
+    }
+    
+    return (1,$filename);
+}
+
+sub read_tidy_file {
+
+    my $self = shift (@_);  
+  
+    my ($file) = @_;
+
+    $file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
+
+    return $file;
+}
+
+
+
+# The BasPlug read_into_doc_obj() function. This function does all the
+# right things to make general options work for a given plugin.  It reads in
+# a file and sets up a slew of metadata all saved in doc_obj, which
+# it then returns as part of a tuple (process_status,doc_obj)
+#
+# Much of this functionality used to reside in read, but it was broken
+# down into a supporting routine to make the code more flexible.  
+#
+# recursive plugins (e.g. RecPlug) and specialized plugins like those
+# capable of processing many documents within a single file (e.g.
+# GMLPlug) will normally want to implement their own version of
+# read_into_doc_obj()
+#
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read_into_doc_obj {
+    my $self = shift (@_);  
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    if ($self->is_recursive()) {
+	gsprintf(STDERR, "{BasPlug.read_must_be_implemented}") && die "\n";
+    }
+
+    my $outhandle   = $self->{'outhandle'};
+
+    my ($block_status,$filename) = $self->read_block(@_);    
+    return $block_status if ((!defined $block_status) || ($block_status==0));
+    $file = $self->read_tidy_file($file);
+
+    # Do encoding stuff
+    my ($language, $encoding) = $self->textcat_get_language_encoding ($filename);
+
+    # create a new document
+    my $doc_obj = new doc ($filename, "indexed_doc");
+    $doc_obj->set_OIDtype ($processor->{'OIDtype'});
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Language", $language);
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Encoding", $encoding);
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "FileSize", (-s $filename));
+
+    my ($filemeta) = $file =~ /([^\\\/]+)$/;
+    # how do we know what encoding the filename is in?
+    $doc_obj->add_metadata($doc_obj->get_top_section(), "Source", &ghtml::dmsafe($filemeta));
+    if ($self->{'cover_image'}) {
+	$self->associate_cover_image($doc_obj, $filename);
+    }
+    
+    # read in file ($text will be in utf8)
+    my $text = "";
+    $self->read_file ($filename, $encoding, $language, \$text);
+
+    if (!length ($text)) {
+	my $plugin_name = ref ($self);
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file' r='File contains no text'>\n";
+	}
+	gsprintf($outhandle, "$plugin_name: {BasPlug.file_has_no_text}\n", $filename) if $self->{'verbosity'};
+
+	my $failhandle = $self->{'failhandle'};
+	gsprintf($failhandle, "$file: " . ref($self) . ": {BasPlug.empty_file}\n");
+	# print $failhandle "$file: " . ref($self) . ": file contains no text\n";
+	$self->{'num_not_processed'} ++;
+
+	return (0,undef); # what should we return here?? error but don't want to pass it on
+    }
+   
+    # include any metadata passed in from previous plugins 
+    # note that this metadata is associated with the top level section
+
+    $self->extra_metadata ($doc_obj, $doc_obj->get_top_section(), $metadata);
+
+    # do plugin specific processing of doc_obj
+    unless (defined ($self->process (\$text, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli))) {
+	$text = '';
+	undef $text;
+	print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	return (-1,undef);
+    }
+    $text='';
+    undef $text;
+   
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata ($doc_obj);
+   
+    # add an OID
+    # see if there is a plugin-specific set_OID function...
+    if (defined ($self->can('set_OID'))) {
+	# it will need $doc_obj to set the Identifier metadata...
+	$self->set_OID($doc_obj);
+    } else {
+	# use the default set_OID() in doc.pm
+	$doc_obj->set_OID();
+    }
+    
+    return (1,$doc_obj);
+}
+
+
+# The BasPlug read() function. This function calls read_into_doc_obj()
+# to ensure all the right things to make general options work for a
+# given plugin are done. It then calls the process() function which
+# does all the work specific to a plugin (like the old read functions
+# used to do). Most plugins should define their own process() function
+# and let this read() function keep control.  
+#
+# recursive plugins (e.g. RecPlug) and specialized plugins like those
+# capable of processing many documents within a single file (e.g.
+# GMLPlug) might want to implement their own version of read(), but
+# more likely need to implement their own version of read_into_doc_obj()
+#
+# Return number of files processed, undef if can't recognise, -1 if can't
+# process
+
+sub read {
+    my $self = shift (@_);  
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my ($process_status,$doc_obj) = $self->read_into_doc_obj(@_);
+    
+    if ((defined $process_status) && ($process_status == 1)) {
+	# process the document
+	$processor->process($doc_obj);
+	
+	if(defined($self->{'places_filename'})){
+	    &util::rm($self->{'places_filename'});
+	    $self->{'places_filename'} = undef;
+	}
+	
+	$self->{'num_processed'} ++;
+	undef $doc_obj; 
+    }
+
+    # if process_status == 1, then the file has been processed.
+    return $process_status;
+
+}
+
+# returns undef if file is rejected by the plugin
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+
+    gsprintf(STDERR, "BasPlug::process {common.must_be_implemented}\n") && die "\n";
+    # die "Basplug::process function must be implemented in sub-class\n";
+
+    return undef; # never gets here
+}
+
+# uses the multiread package to read in the entire file pointed to
+# by filename and loads the resulting text into $$textref. Input text
+# may be in any of the encodings handled by multiread, output text
+# will be in utf8
+sub read_file {
+    my $self = shift (@_);
+    my ($filename, $encoding, $language, $textref) = @_;
+
+    if (!-r $filename)
+    {
+	my $outhandle = $self->{'outhandle'};
+	gsprintf($outhandle, "{BasPlug.read_denied}\n", $filename) if $self->{'verbosity'};
+	# print $outhandle "Read permission denied for $filename\n" if $self->{'verbosity'};
+	return;
+    }
+    $$textref = "";
+    if (!open (FILE, $filename)) {
+	gsprintf(STDERR, "BasPlug::read_file {BasPlug.could_not_open_for_reading} ($!)\n", $filename);
+	die "\n";
+    }
+     
+    if ($encoding eq "ascii") {
+	undef $/;
+	$$textref = <FILE>;
+	$/ = "\n";
+    } else {
+	my $reader = new multiread();
+	$reader->set_handle ('BasPlug::FILE');
+	$reader->set_encoding ($encoding);
+	$reader->read_file ($textref);
+        #Now segments chinese if the separate_cjk option is set
+	if ($self->{'separate_cjk'}) {
+	    # segment the Chinese words
+	    $$textref = &cnseg::segment($$textref);
+	}
+    }
+    close FILE;
+}
+
+# write_file -- used by ConvertToPlug, for example in post processing
+#
+sub utf8_write_file {
+    my $self = shift (@_);
+    my ($textref, $filename) = @_;
+    
+    if (!open (FILE, ">$filename")) {
+	gsprintf(STDERR, "ConvertToPlug::write_file {ConvertToPlug.could_not_open_for_writing} ($!)\n", $filename);
+	 die "\n";
+     }
+    print FILE $$textref;
+    
+    close FILE;
+}
+
+
+sub filename_based_title
+{
+    my $self = shift (@_);
+    my ($file) = @_;
+
+    my $file_derived_title = $file;
+    $file_derived_title =~ s/_/ /g;
+    $file_derived_title =~ s/\..*?$//;
+
+    return $file_derived_title;
+}
+
+
+sub title_fallback
+{
+    my $self = shift (@_);
+    my ($doc_obj,$section,$file) = @_;
+
+    if (!defined $doc_obj->get_metadata_element ($section, "Title")) {
+
+	my $file_derived_title = $self->filename_based_title($file);
+	$doc_obj->add_metadata ($section, "Title", $file_derived_title);
+    }
+}
+
+sub textcat_get_language_encoding {
+    my $self = shift (@_);
+    my ($filename) = @_;
+
+    
+    my ($language, $encoding, $extracted_encoding);
+    if ($self->{'input_encoding'} eq "auto") {
+        # use textcat to automatically work out the input encoding and language
+        ($language, $encoding) = $self->get_language_encoding ($filename);
+    } elsif ($self->{'extract_language'}) {
+        # use textcat to get language metadata
+        ($language, $extracted_encoding) = $self->get_language_encoding ($filename);
+        $encoding = $self->{'input_encoding'};
+	# don't print this message for english... english in utf8 is identical
+	# to english in iso-8859-1 (except for some punctuation). We don't have
+	# a language model for en_utf8, so textcat always says iso-8859-1!
+        if ($extracted_encoding ne $encoding && $language ne "en"
+	    && $self->{'verbosity'}) {
+	    my $plugin_name = ref ($self);
+	    my $outhandle = $self->{'outhandle'};
+	    gsprintf($outhandle, "$plugin_name: {BasPlug.wrong_encoding}\n", $filename, $encoding, $extracted_encoding);
+            # print $outhandle "$plugin_name: WARNING: $filename was read using $encoding encoding but ";
+            # print $outhandle "appears to be encoded as $extracted_encoding.\n";
+        }
+    } else {
+        $language = $self->{'default_language'};
+        $encoding = $self->{'input_encoding'};
+    }
+
+    return ($language, $encoding);
+}
+
+# Uses textcat to work out the encoding and language of the text in 
+# $filename. All html tags are removed before processing.
+# returns an array containing "language" and "encoding"
+sub get_language_encoding {
+    my $self = shift (@_);
+    my ($filename) = @_;
+    my $outhandle = $self->{'outhandle'};
+    my $unicode_format = "";
+    # read in file
+    open (FILE, $filename) || (gsprintf(STDERR, "BasPlug::get_language_encoding {BasPlug.could_not_open_for_reading} ($!)\n", $filename) && die "\n"); # die "BasPlug::get_language_encoding could not open $filename for reading ($!)\n";
+    undef $/;
+    my $text = <FILE>;
+    $/ = "\n";
+    close FILE;
+
+    # check if first few bytes have a Byte Order Marker
+    my $bom=substr($text,0,2); # check 16bit unicode
+    if ($bom eq "\xff\xfe") { # little endian 16bit unicode
+	$unicode_format="unicode";
+    } elsif ($bom eq "\xfe\xff") { # big endian 16bit unicode
+	$unicode_format="unicode";
+    } else {
+	$bom=substr($text,0,3); # check utf-8
+	if ($bom eq "\xef\xbb\xbf") { # utf-8 coded FEFF bom
+	    $unicode_format="utf8";
+#	} elsif ($bom eq "\xef\xbf\xbe") { # utf-8 coded FFFE bom. Error!?
+#	    $unicode_format="utf8";
+	}
+    }
+    
+    # VB scripting generated Word to HTML file
+    if ($text =~ /charset=(windows.*)[\"]/ig){
+	my $vbhtml_encoding = $1;
+	$vbhtml_encoding =~ s/-+/_/g;
+	$self->{'input_encoding'} = $vbhtml_encoding;
+    }
+    
+    # remove <title>stuff</title> -- as titles tend often to be in English
+    # for foreign language documents
+    $text =~ s/<title>(.|\n)*?<\/title>//i;
+
+    # remove all HTML tags
+    # XXX this doesn't match plugins derived from HTMLPlug (except ConvertTo)
+    if (ref($self) eq 'HTMLPlug' ||
+	(exists $self->{'converted_to'} && $self->{'converted_to'} eq 'HTML')){
+	$text =~ s/<[^>]*>//sg;
+    }
+
+    # get the language/encoding
+    my $results = $self->{'textcat'}->classify(\$text);
+
+    # if textcat returns 3 or less possibilities we'll use the 
+    # first one in the list - otherwise use the defaults
+    if (scalar @$results > 3) {
+	my $best_encoding="";
+	if ($unicode_format) { # in case the first had a BOM
+	    $best_encoding=$unicode_format;
+	} else {
+	    my %guessed_encodings = ();
+	    foreach my $result (@$results) {
+		$result =~ /([^\-]+)$/;
+		my $enc=$1;
+		if (!defined($guessed_encodings{$enc})) {
+		    $guessed_encodings{$enc}=0;
+		}
+		$guessed_encodings{$enc}++;
+	    }
+
+	    $guessed_encodings{""}=-1; # for default best_encoding of ""
+	    foreach my $enc (keys %guessed_encodings) {
+		if ($guessed_encodings{$enc} >
+		    $guessed_encodings{$best_encoding}){
+		    $best_encoding=$enc;
+		}
+	    }
+	}
+
+	if ($self->{'input_encoding'} ne 'auto') {
+	    if ($self->{'extract_language'} && ($self->{'verbosity'}>2)) {
+		gsprintf($outhandle,
+			 "BasPlug: {BasPlug.could_not_extract_language}\n",
+			 $filename, $self->{'default_language'});
+	    }		
+	    return ($self->{'default_language'}, $self->{'input_encoding'});
+
+	} else {
+	    if ($self->{'verbosity'}>2) {
+		gsprintf($outhandle,
+			 "BasPlug: {BasPlug.could_not_extract_language}\n",
+			 $filename, $self->{'default_language'});
+	    }
+	    return ($self->{'default_language'}, $best_encoding);
+	}
+    }
+
+    # format language/encoding
+    my ($language, $encoding) = $results->[0] =~ /^([^-]*)(?:-(.*))?$/;
+    if (!defined $language) {
+	if ($self->{'verbosity'}>2) {
+	    gsprintf($outhandle,
+		     "BasPlug: {BasPlug.could_not_extract_language}\n",
+		     $filename, $self->{'default_language'});
+	}
+	$language = $self->{'default_language'};
+    }
+    if (!defined $encoding) {
+	if ($self->{'verbosity'}>2) {
+	    gsprintf($outhandle,
+		     "BasPlug: {BasPlug.could_not_extract_encoding}\n",
+		     $filename, $self->{'default_encoding'});
+	}
+	$encoding = $self->{'default_encoding'};
+    }
+
+
+    # check for equivalents where textcat doesn't have some encodings...
+    # eg MS versions of standard encodings
+    if ($encoding =~ /^iso_8859_(\d+)/) {
+	my $iso = $1; # which variant of the iso standard?
+	# iso-8859 sets don't use chars 0x80-0x9f, windows codepages do
+	if ($text =~ /[\x80-\x9f]/) {
+	    # Western Europe
+	    if ($iso == 1 or $iso == 15) { $encoding = 'windows_1252' }
+	    elsif ($iso == 2) { $encoding = 'windows_1250' } # Central Europe
+	    elsif ($iso == 5) { $encoding = 'windows_1251' } # Cyrillic
+	    elsif ($iso == 6) { $encoding = 'windows_1256' } # Arabic
+	    elsif ($iso == 7) { $encoding = 'windows_1253' } # Greek
+	    elsif ($iso == 8) { $encoding = 'windows_1255' } # Hebrew
+	    elsif ($iso == 9) { $encoding = 'windows_1254' } # Turkish
+	}
+    }
+
+    if ($encoding !~ /^(ascii|utf8|unicode)$/ &&
+	!defined $encodings::encodings->{$encoding}) {
+	if ($self->{'verbosity'}) {
+	    gsprintf($outhandle, "BasPlug: {BasPlug.unsupported_encoding}\n",
+		     $filename, $encoding, $self->{'default_encoding'});
+	}
+	$encoding = $self->{'default_encoding'};
+    }
+
+    return ($language, $encoding);
+}
+
+# add any extra metadata that's been passed around from one
+# plugin to another.
+# extra_metadata uses add_utf8_metadata so it expects metadata values
+# to already be in utf8
+sub extra_metadata {
+    my $self = shift (@_);
+    my ($doc_obj, $cursection, $metadata) = @_;
+
+    foreach my $field (keys(%$metadata)) {
+	# $metadata->{$field} may be an array reference
+	if ($field eq "gsdlassocfile_tobe") {
+	    # 'gsdlassocfile_tobe' is artificially introduced metadata
+	    # that is used to signal that certain additional files should
+	    # be tied to this document.  Useful in situations where a
+	    # metadata pass in the plugin pipeline works out some files
+	    # need to be associated with a document, but the document hasn't
+	    # been formed yet.
+	    
+	    my $equiv_form = "";
+	    foreach my $gaf (@{$metadata->{$field}}) {
+		my ($full_filename,$mimetype) = ($gaf =~ m/^(.*):(.*):$/);
+		my ($tail_filename) = ($full_filename =~ /^.*[\/\\](.+?)$/);
+		my $filename = $full_filename;
+			      
+		$doc_obj->associate_file($full_filename,$tail_filename,$mimetype);
+		
+		my ($doc_ext) = ($tail_filename =~ m/^.*\.(.*)$/);
+		my $start_doclink = "<a href=\"_httpcollection_/index/assoc/{Or}{[parent(Top):archivedir],[archivedir]}/$tail_filename\">";
+		my $srcicon = "_icon".$doc_ext."_";
+		my $end_doclink = "</a>";
+
+		$equiv_form .= " $start_doclink\{If\}{$srcicon,$srcicon,$doc_ext\}$end_doclink";		
+	    }
+	    $doc_obj->add_utf8_metadata ($cursection, "equivlink", $equiv_form); 
+	}
+	elsif (ref ($metadata->{$field}) eq "ARRAY") {
+	    map { 
+		$doc_obj->add_utf8_metadata ($cursection, $field, $_); 
+	    } @{$metadata->{$field}};
+	} else {
+	    $doc_obj->add_utf8_metadata ($cursection, $field, $metadata->{$field}); 
+	}
+    }
+}
+
+# initialise metadata extractors
+sub initialise_extractors {
+    my $self = shift (@_);
+
+    if ($self->{'extract_acronyms'} || $self->{'markup_acronyms'}) {
+	&acronym::initialise_acronyms();
+    }
+}
+
+# finalise metadata extractors
+sub finalise_extractors {
+    my $self = shift (@_);
+
+    if ($self->{'extract_acronyms'} || $self->{'markup_acronyms'}) {
+	&acronym::finalise_acronyms();
+    }
+}
+
+# FIRSTNNN: extract the first NNN characters as metadata
+sub extract_first_NNNN_characters {
+    my $self = shift (@_);
+    my ($textref, $doc_obj, $thissection) = @_;
+    
+    foreach my $size (split /,/, $self->{'first'}) {
+	my $tmptext =  $$textref;
+	$tmptext =~ s/^\s+//;
+	$tmptext =~ s/\s+$//;
+	$tmptext =~ s/\s+/ /gs;
+	$tmptext = substr ($tmptext, 0, $size);
+	$tmptext =~ s/\s\S*$/&#8230;/;
+	$doc_obj->add_utf8_metadata ($thissection, "First$size", $tmptext);
+    }
+}
+
+sub extract_email {
+    my $self = shift (@_);
+    my ($textref, $doc_obj, $thissection) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    gsprintf($outhandle, " {BasPlug.extracting_emails}...\n")
+	if ($self->{'verbosity'} > 2);
+    
+    my @email = ($$textref =~ m/([-a-z0-9\.@+_=]+@(?:[-a-z0-9]+\.)+(?:com|org|edu|mil|int|net|[a-z][a-z]))/g);
+    @email = sort @email;
+    
+#    if($self->{"new_extract_email"} == 0)
+#    {
+#    my @email2 = ();
+#    foreach my $address (@email) 
+#   {
+#	if (!(join(" ",@email2) =~ m/(^| )$address( |$)/ )) 
+#	    {
+#		push @email2, $address;
+#		$doc_obj->add_utf8_metadata ($thissection, "emailAddress", $address);
+#		# print $outhandle "  extracting $address\n" 
+#		&gsprintf($outhandle, "  {BasPlug.extracting} $address\n")
+#		    if ($self->{'verbosity'} > 3);
+#	    }
+#	}
+#    }
+#    else
+#    {
+    my $hashExistMail = {};
+    foreach my $address (@email) {
+	if (!(defined $hashExistMail->{$address}))
+	{
+	    $hashExistMail->{$address} = 1;
+	    $doc_obj->add_utf8_metadata ($thissection, "emailAddress", $address);
+	    gsprintf($outhandle, "  {BasPlug.extracting} $address\n")
+		if ($self->{'verbosity'} > 3);
+	}
+    }
+    gsprintf($outhandle, " {BasPlug.done_email_extract}\n")
+	if ($self->{'verbosity'} > 2);
+}
+
+# extract metadata
+sub auto_extract_metadata {
+
+    my $self = shift (@_);
+    my ($doc_obj) = @_;
+    
+    if ($self->{'extract_email'}) {
+	my $thissection = $doc_obj->get_top_section();
+	while (defined $thissection) {
+	    my $text = $doc_obj->get_text($thissection);
+	    $self->extract_email (\$text, $doc_obj, $thissection) if $text =~ /./;
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    } 
+    if ($self->{'extract_placenames'}) {
+	my $thissection = $doc_obj->get_top_section();
+	while (defined $thissection) {
+	    my $text = $doc_obj->get_text($thissection);
+	    $self->extract_placenames (\$text, $doc_obj, $thissection) if $text =~ /./;
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    } 
+
+    #adding kea keyphrases
+    if ($self->{'extract_keyphrases'}) {  
+	
+	my $thissection = $doc_obj->get_top_section();
+	my $text = "";
+	my $list;
+
+	#loop through sections to gather whole doc
+	while (defined $thissection) { 
+	    my $sectiontext = $doc_obj->get_text($thissection);   
+	    $text = $text.$sectiontext;
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	} 
+       
+	if($self->{'extract_keyphrase_options'}) { #if kea options flag is set, call Kea with specified options 
+	    $list = &Kea::extract_KeyPhrases ($text, $self->{'extract_keyphrase_options'}); 
+	} else { #otherwise call Kea with no options
+	    $list = &Kea::extract_KeyPhrases ($text); 
+	}
+	 
+	if ($list){
+	    # if a list of kea keyphrases was returned (ie not empty)
+	    if ($self->{'verbosity'}) {
+		gsprintf(STDERR, "{BasPlug.keyphrases}: $list\n");
+	    }
+
+	    #add metadata to top section
+	    $thissection = $doc_obj->get_top_section(); 
+
+	    # add all key phrases as one metadata
+	    $doc_obj->add_metadata($thissection, "Keyphrases", $list);
+
+	    # add individual key phrases as multiple metadata
+	    foreach my $keyphrase (split(',', $list)) {
+	    	$keyphrase =~ s/^\s+|\s+$//g;
+		$doc_obj->add_metadata($thissection, "Keyphrase", $keyphrase);
+	    }
+	}
+    } #end of kea 
+
+    if ($self->{'first'}) {
+	my $thissection = $doc_obj->get_top_section();
+	while (defined $thissection) {
+	    my $text = $doc_obj->get_text($thissection);
+	    $self->extract_first_NNNN_characters (\$text, $doc_obj, $thissection) if $text =~ /./;
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    }   
+    
+    if ($self->{'extract_acronyms'}) {
+	my $thissection = $doc_obj->get_top_section();
+	while (defined $thissection) {
+	    my $text = $doc_obj->get_text($thissection);
+	    $self->extract_acronyms (\$text, $doc_obj, $thissection) if $text =~ /./;
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    }
+    
+    if ($self->{'markup_acronyms'}) {
+	my $thissection = $doc_obj->get_top_section();
+	while (defined $thissection) {
+	    my $text = $doc_obj->get_text($thissection);
+	    $text = $self->markup_acronyms ($text, $doc_obj, $thissection);
+	    $doc_obj->delete_text($thissection);
+	    $doc_obj->add_text($thissection, $text);
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    }
+
+    if($self->{'extract_historical_years'}) {
+	my $thissection = $doc_obj->get_top_section();
+	while (defined $thissection) {
+
+	    my $text = $doc_obj->get_text($thissection);
+	    &DateExtract::get_date_metadata($text, $doc_obj, 
+					    $thissection, 
+					    $self->{'no_bibliography'}, 
+					    $self->{'maximum_year'}, 
+					    $self->{'maximum_century'});
+	    $thissection = $doc_obj->get_next_section ($thissection);
+	}
+    }
+}
+
+# extract acronyms from a section in a document. progress is 
+# reported to outhandle based on the verbosity. both the Acronym
+# and the AcronymKWIC metadata items are created. 
+
+sub extract_acronyms {
+    my $self = shift (@_);
+    my ($textref, $doc_obj, $thissection) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    # print $outhandle " extracting acronyms ...\n" 
+    gsprintf($outhandle, " {BasPlug.extracting_acronyms}...\n")
+	if ($self->{'verbosity'} > 2);
+
+    my $acro_array =  &acronym::acronyms($textref);
+    
+    foreach my $acro (@$acro_array) {
+
+	#check that this is the first time ...
+	my $seen_before = "false";
+	my $previous_data = $doc_obj->get_metadata($thissection, "Acronym");
+	foreach my $thisAcro (@$previous_data) {
+	    if ($thisAcro eq $acro->to_string()) {
+		$seen_before = "true";
+		if ($self->{'verbosity'} >= 4) {
+		    gsprintf($outhandle, " {BasPlug.already_seen} " .
+			     $acro->to_string() . "\n");
+		}
+	    }
+	}
+
+	if ($seen_before eq "false") {
+	    #write it to the file ...
+	    $acro->write_to_file();
+
+	    #do the normal acronym
+	    $doc_obj->add_utf8_metadata($thissection, "Acronym",  $acro->to_string());
+	    gsprintf($outhandle, " {BasPlug.adding} ".$acro->to_string()."\n")
+		if ($self->{'verbosity'} > 3);
+	}
+    }
+
+    gsprintf($outhandle, " {BasPlug.done_acronym_extract}\n")
+	if ($self->{'verbosity'} > 2);
+}
+
+sub markup_acronyms {
+    my $self = shift (@_);
+    my ($text, $doc_obj, $thissection) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    gsprintf($outhandle, " {BasPlug.marking_up_acronyms}...\n")
+	if ($self->{'verbosity'} > 2);
+
+    #self is passed in to check for verbosity ...
+    $text = &acronym::markup_acronyms($text, $self);
+
+    gsprintf($outhandle, " {BasPlug.done_acronym_markup}\n")
+	if ($self->{'verbosity'} > 2);
+
+    return $text;
+}
+
+sub compile_stats {
+    my $self = shift(@_);
+    my ($stats) = @_;
+
+    $stats->{'num_processed'} += $self->{'num_processed'};
+    $stats->{'num_not_processed'} += $self->{'num_not_processed'};
+    $stats->{'num_archives'} += $self->{'num_archives'};
+
+}
+
+sub associate_cover_image {
+    my $self = shift(@_);
+    my ($doc_obj, $filename) = @_;
+
+    my $top_section=$doc_obj->get_top_section();
+
+    $filename =~ s/\.[^\\\/\.]+$/\.jpg/;
+    if (-e $filename) {
+	$doc_obj->associate_file($filename, "cover.jpg", "image/jpeg");
+	$doc_obj->add_utf8_metadata($top_section, "hascover",  1);
+    } else {
+	$filename =~ s/jpg$/JPG/;
+	if (-e $filename) {
+	    $doc_obj->associate_file($filename, "cover.jpg", "image/jpeg");
+	    $doc_obj->add_utf8_metadata($top_section, "hascover",  1);
+	}
+    }
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BibTexPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BibTexPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BibTexPlug.pm	(revision 10506)
@@ -0,0 +1,821 @@
+###########################################################################
+#
+# BibTexPlug.pm - a plugin for bibliography records in BibTex format
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright 2000 Gordon W. Paynter
+# Copyright 1999-2001 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.
+#
+###########################################################################
+
+
+# BibTexPlug reads bibliography files in BibTex format.
+#
+# by Gordon W. Paynter (gwp@cs.waikato.ac.nz), November 2000
+# Based on ReferPlug.  See ReferPlug for geneology.
+#
+# BibTexPlug creates a document object for every reference a the file.
+# It is a subclass of SplitPlug, so if there are multiple records, all
+# are read.
+#
+# Modified Dec 2001 by John McPherson:
+#  *  some modifications submitted by Sergey Yevtushenko
+#                      <sergey@intellektik.informatik.tu-darmstadt.de>
+#  *  some non-ascii char support (ie mostly Latin)
+
+
+package BibTexPlug;
+
+use SplitPlug;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+# BibTexPlug is a sub-class of BasPlug.
+sub BEGIN {
+    @BibTexPlug::ISA = ('SplitPlug');
+}
+
+my $arguments = 
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() },
+      { 'name' => "split_exp",
+	'desc' => "{SplitPlug.split_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_split_exp(),
+	'reqd' => "no" }
+      ];
+
+my $options = { 'name'     => "BibTexPlug",
+		'desc'     => "{BibTexPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'explodes' => "yes",
+		'args'     => $arguments };
+
+# This plugin processes files with the suffix ".bib"
+sub get_default_process_exp {
+    return q^(?i)\.bib$^;
+}
+
+# This plugin splits the input text at blank lines
+sub get_default_split_exp {
+    return q^\n+(?=@)^;
+}
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new SplitPlug($pluginlist,$inputargs,$hashArgOptLists): new SplitPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+
+
+# The process function reads a single bibliographic record and stores
+# it as a new document.
+
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $cursection = $doc_obj->get_top_section();
+    $self->{'key'} = "default";
+
+    # Check that we're dealing with a valid BibTex record
+    return undef unless ($$textref =~ /^@\w+\{.*\}/s);
+
+    # Ignore things we can't use
+    return 0 if ($$textref =~ /^\@String/);
+
+    # Report that we're processing the file
+    print STDERR "<Processing n='$file' p='BibTexPlug'>\n" if ($gli);
+    print $outhandle "BibTexPlug: processing $file\n"
+	if ($self->{'verbosity'}) > 1;
+
+
+    # This hash translates BibTex field names into metadata names.  The
+    # BibTex names are taken from the "Local Guide to Latex" Graeme
+    # McKinstry.  Metadata names are consistent with ReferPlug.
+
+    # The author metadata will be stored as one "Creator" entry, but will
+    # also be split up into several individual "Author" fields.
+
+    my %field = (
+		 'address', 'PublisherAddress',
+		 'author', 'Creator',
+		  
+		 'booktitle', 'Booktitle',
+		 'chapter', 'Chapter',
+		 'edition', 'Edition',
+		 'editor', 'Editor', 
+		 'institution', 'Publisher',
+		 'journal', 'Journal',
+		 'month', 'Month',
+		 'number', 'Number',
+		 'pages', 'Pages',
+		 'publisher', 'Publisher',
+		 'school', 'Publisher',
+		 'title', 'Title',
+		 'volume', 'Volume',
+		 'year', 'Year', # Can't use "Date" as this implies DDDDMMYY!
+
+		 'keywords', 'Keywords',
+		 'abstract', 'Abstract',
+		 'copyright', 'Copyright',
+		 'note', 'Note',
+		 );
+
+    # Metadata fields 
+    my %metadata;
+    my ($EntryType, $Creator, $Keywords, $text);
+
+    my $verbosity = $self->{'verbosity'};
+    $verbosity = 0 unless $verbosity;
+
+    # Make sure the text has exactly one entry per line -
+    # append line to previous if it doesn't start with "  <key> = "
+
+    my @input_lines=split(/\r?\n/, $$textref);
+    my @all_lines;
+    my $entry_line=shift @input_lines;
+    foreach my $input_line (@input_lines) {
+	if ($input_line =~ m/^\s*\w+\s*=\s*/) {
+	    # this is a new key
+	    push(@all_lines, $entry_line);
+	    $entry_line=$input_line;
+	} else {
+	    # this is a continuation of previous line
+	    $entry_line .= " " . $input_line;
+	}
+	
+    }
+    # add final line, removing trailing '}'
+    $entry_line =~ s/\}\s*$//;
+    push(@all_lines, $entry_line);
+    push(@all_lines, "}");
+
+    # Read and process each line in the bib file.
+    my ($entryname, $name, $value, $line);
+    foreach $line (@all_lines) {
+
+	# Add each line.  Most lines consist of a field identifer and
+	# then data, and we simply store them, though we treat some
+	# of the fields a bit differently.
+
+	$line =~ s/\s+/ /g;
+	$text .= "$line\n";
+
+
+	print "Processing line = $line \n" if $verbosity>=4;
+
+	# The first line is special, it contains the reference type and OID
+	if ($line =~ /\@(\w+)\W*\{\W*([\*\.\w\d:-]*)\W*$/) {
+	    $EntryType = $1;
+	    my $EntryID = (defined $2) ? $2 : "default";
+	    print "** $EntryType - \"$EntryID\" \n"
+		if ($verbosity >= 4);
+
+	    next;
+	}
+	if ($line =~ /\@/) {
+	    print $outhandle "bibtexplug: suspect line in bibtex file: $line\n"
+		if ($verbosity >= 2);
+	    print $outhandle "bibtexplug: if that's the start of a new bibtex record ammend regexp in bibtexplug::process()\n"
+		if ($verbosity >= 2);
+	}
+	
+	# otherwise, parse the metadata out of this line
+	next unless ($line =~ /^\s*(\w+)\s*=\s*(.*)/);
+	$entryname = lc($1);
+	$value = $2;
+	$value =~ s/,?\s*$//; # remove trailing comma and space
+	if ($value =~ /^"/ && $value =~ /"$/) {
+	    # remove surrounding " marks
+	    $value =~ s/^"//; $value =~ s/"$//;
+	}
+	$value = &process_latex($value);
+
+	# Add this line of metadata
+	$metadata{$entryname} .= "$value";
+	   
+    }
+
+    # Add the Entry type as metadata
+    $doc_obj->add_utf8_metadata ($cursection, "EntryType", $EntryType);
+    
+    #Add the fileformat as metadata
+    $doc_obj->add_metadata($cursection, "FileFormat", "BibTex");
+
+
+    # Add the various field as metadata
+    foreach my $entryname (keys %metadata) {
+	next unless (defined $field{$entryname});
+	next unless (defined $metadata{$entryname});	
+	
+	$name = $field{$entryname};
+	$value = $metadata{$entryname};
+
+	if ($name =~ /^Month/) {
+	    $value=expand_month($value);
+	}
+
+	# Several special operatons on metadata follow
+	
+	# Add individual keywords.
+	# The full set of keywords will be added, in due course, as "Keywords".
+	# However, we also want to add them as individual "Keyword" metadata elements.
+	if ($entryname eq "keywords") {
+	    my @keywordlist = split(/,/, $value);
+	    foreach my $k (@keywordlist) {
+		$k = lc($k); 
+		$k =~ s/\s*$//; 
+		$k =~ s/^\s*//; 
+		if ($k =~ /\w/) {
+		    $doc_obj->add_utf8_metadata ($cursection, "Keyword", $k);
+		}
+	    } 
+	}
+	
+	# Add individual authors
+	# The author metadata will be stored as one "Creator" entry, but we
+	# also want to split it into several individual "Author" fields in
+	# "Lastname, Firstnames" format so we can browse it.
+	if ($entryname eq "author") { #added also comparison with editor
+	   
+	    # take care of "et al."...
+	    my $etal='';
+	    if ($value =~ s/\s+(and\s+others|et\.?\s+al\.?)\s*$//i) {
+		$etal=' <em>et. al.</em>';
+	    }
+	    # und here for german language...
+	    # don't use brackets in pattern, else the matched bit becomes
+	    # an element in the list!
+	    my @authorlist = split(/\s+and\s+|\s+und\s+/, $value); 
+	    my @formattedlist = ();
+	    foreach $a (@authorlist) {
+		$a =~ s/\s*$//; 
+		$a =~ s/^\s*//; 
+		# Reformat and add author name
+		next if $a=~ /^\s*$/;
+		
+		# names are "First von Last", "von Last, First"
+		# or "von Last, Jr, First". See the "BibTeXing" manual, page 16
+		my $first="";
+		my $vonlast="";
+		my $jr="";
+
+		if ($a =~ /,/) {
+		    my @parts=split(/,\s*/, $a);
+		    $first = pop @parts;
+		    if (scalar(@parts) == 2) {
+			$jr = pop @parts;
+		    }
+		    $vonlast=shift @parts;
+		    if (scalar(@parts) > 0) {
+			print $outhandle "BibTexPlug: couldn't parse name $a\n";
+			# but we continue anyway...
+		    }
+		} else { # First von Last
+		    my @words = split(/ /, $a);
+		    while (scalar(@words) > 1 && $words[0] !~ /^[a-z]{2..}/) {
+			$first .= " " . shift (@words);
+		    }
+		    $first =~ s/^\s//;
+		    $vonlast = join (' ', @words); # whatever's left...
+		}
+		my $von="";
+		my $last="";
+		if ($vonlast =~ m/^[a-z]/) { # lowercase implies "von"
+		    $vonlast =~ s/^(([a-z]\w+\s+)+)//;
+		    $von = $1;
+		    if (!defined ($von)) {
+			# some non-English names do start with lowercase
+			# eg "Marie desJardins". Also we can get typos...
+			print $outhandle "BibTexPlug: couldn't parse surname $vonlast\n";
+			$von="";
+			if ($vonlast =~ /^[a-z]+$/) {
+			    # if it's all lowercase, uppercase 1st.
+			    $vonlast =~ s/^(.)/\u$1/;
+
+			}
+		    }
+		    $von =~ s/\s*$//;
+		    $last=$vonlast;
+		} else {
+		    $last=$vonlast;
+		}
+		my $wholename="$first $von $last $jr";
+		$wholename =~ s/\s+/ /g; # squeeze multiple spaces
+		$wholename =~ s/ $//;
+		push (@formattedlist, $wholename);
+		my $fullname = "$last";
+		$fullname .= " $jr" if ($jr);
+		$fullname .= ", $first";
+		$fullname .= " $von" if ($von);
+
+		# Add each name to set of Authors
+		$doc_obj->add_utf8_metadata ($cursection, "Author", $fullname);
+	    }
+
+	    # Only want at most one "and" in the Creator field
+	    if (scalar(@formattedlist) > 2) {
+		my $lastauthor=pop @formattedlist;
+		$value=join(', ', @formattedlist);
+		$value.=" and $lastauthor";
+	    } else { # 1 or 2 authors...
+		$value=join(" and ",@formattedlist);
+	    }
+	    $value.=$etal; # if there was "et al."
+	}
+
+	# Books and Journals are additionally marked for display purposes
+	if ($entryname eq "booktitle") {
+	    $doc_obj->add_utf8_metadata($cursection, "BookConfOnly", 1);
+	} elsif ($entryname eq "journal") {
+	    $doc_obj->add_utf8_metadata($cursection, "JournalsOnly", 1); 
+	}
+
+	# Add the various fields as metadata	
+	$doc_obj->add_utf8_metadata ($cursection, $name, $value); 
+    }
+
+    # for books and journals...
+    if (!exists $metadata{'title'}) {
+	my $name=$field{'title'}; # get Greenstone metadata name
+	my $value;
+	if (exists $metadata{'booktitle'}) {
+	    $value=$metadata{'booktitle'};
+	} elsif (exists $metadata{'journal'}) {
+	    $value=$metadata{'journal'};
+	}
+	if ($value) {
+	    $doc_obj->add_utf8_metadata ($cursection, $name, $value); 
+	}
+    }
+
+    # Add Date (yyyymmdd) metadata
+    if (defined ($metadata{'year'}) ) {
+	my $date=$metadata{'year'};
+	chomp $date;
+	my $month=$metadata{'month'};
+	if (defined($month)) {
+	    # month is currently 3 letter code or a range...
+	    $month = expand_month($month);
+	    # take the first month found... might not find one!
+	    $month =~ m/_textmonth(\d\d)_/;
+	    $month = $1;
+	}
+	if (!defined($month)) {
+	    $month="00";
+	}
+	$date .= "${month}00";
+	$doc_obj->add_utf8_metadata($cursection, "Date", $date); 
+}
+
+#    # Add the text in BibTex format (all fields)
+    if ($text =~ /\w/) {
+
+	$text =~ s@&@&amp;@g;
+	$text =~ s@<@&lt;@g;
+	$text =~ s@>@&gt;@g;
+	$text =~ s@\n@<br/>\n@g;
+	$text =~ s@\\@\\\\@g;
+
+	$doc_obj->add_utf8_text ($cursection, $text);
+    }
+
+    return 1;
+}
+
+
+
+
+# convert email addresses and URLs into links
+sub convert_urls_into_links{
+   my ($text) = @_;
+ 
+   $text =~ s/([\w\d\.\-]+@[\w\d\.\-]+)/<a href=\"mailto:$1\">$1<\/a>/g;
+   $text =~ s/(http:\/\/[\w\d\.\-]+[\/\w\d\.\-]*)/<a href=\"$1\">$1<\/a>/g;
+
+   return $text;
+}
+
+# Clean up whitespace and convert \n charaters to <BR> or <P>
+sub clean_up_whitespaces{
+   my ($text) = @_;
+
+   $text =~ s/%%%%%/<BR> <BR>/g;
+   $text =~ s/ +/ /g;
+   $text =~ s/\s*$//; 
+   $text =~ s/^\s*//; 
+   $text =~ s/\n/\n<BR>/g;
+   $text =~ s/<BR>\s*<BR>/<P>/g;
+
+   return $text;
+}
+
+
+sub convert_problem_characters_without_ampersand{
+    my ($text) = @_;
+    $text =~ s/</&lt;/g;
+    $text =~ s/>/&gt;/g;
+    
+    $text =~ s/\'\'/\"/g; #Latex -specific conversion
+    $text =~ s/\`\`/\"/g; #Latex -specific conversion
+
+    $text =~ s/\"/&quot;/g;
+    $text =~ s/\'/&#8217;/g;
+    $text =~ s/\`/&#8216;/g;
+
+#    $text =~ s/\+/ /g;
+#    $text =~ s/\(/ /g;
+#    $text =~ s/\)/ /g;
+
+    $text =~ s/\\/\\\\/g;
+
+#    $text =~ s/\./\\\./g;
+
+    return $text;
+}
+
+# Convert a text string into HTML.
+
+# The HTML is going to be inserted into a GML file, so we have to be
+# careful not to use symbols like ">", which occurs frequently in email
+# messages (and use &gt instead.
+
+# This function also turns URLs and email addresses into links, and
+# replaces carriage returns with <BR> tags (and multiple carriage returns
+# with <P> tags).
+
+sub text_into_html {
+    my ($text) = @_;
+
+    # Convert problem characters into HTML symbols
+    $text =~ s/&/&amp;/g;
+
+    $text = &convert_problem_characters_without_ampersand( $text );
+
+    # convert email addresses and URLs into links
+    $text = &convert_urls_into_links( $text );
+
+    $text = &clean_up_whitespaces( $text );
+
+    return $text;
+}
+
+
+sub expand_month {
+    my $text=shift;
+
+    # bibtex style files expand abbreviations for months.
+    # Entries can contain more than one month (eg ' month = jun # "-" # aug, ')
+    $text =~ s/jan/_textmonth01_/g;
+    $text =~ s/feb/_textmonth02_/g;
+    $text =~ s/mar/_textmonth03_/g;
+    $text =~ s/apr/_textmonth04_/g;
+    $text =~ s/may/_textmonth05_/g;
+    $text =~ s/jun/_textmonth06_/g;
+    $text =~ s/jul/_textmonth07_/g;
+    $text =~ s/aug/_textmonth08_/g;
+    $text =~ s/sep/_textmonth09_/g;
+    $text =~ s/oct/_textmonth10_/g;
+    $text =~ s/nov/_textmonth11_/g;
+    $text =~ s/dec/_textmonth12_/g;
+
+    return $text;
+}
+
+
+# Convert accented characters, remove { }, interprete some commands....
+# Note!! This is not comprehensive! Also assumes Latin -> Unicode!
+sub process_latex {
+    my ($text) = @_;
+      
+    # note - this is really ugly, but it works. There may be a prettier way
+    # of mapping latex accented chars to utf8, but we just brute force it here.
+    # Also, this isn't complete - not every single possible accented letter
+    # is in here yet, but most of the common ones are.
+
+    my %utf8_chars =
+	(
+	 # acutes
+	 '\'a' => chr(0xc3).chr(0xa1),
+	 '\'c' => chr(0xc4).chr(0x87),
+	 '\'e' => chr(0xc3).chr(0xa9),
+	 '\'i' => chr(0xc3).chr(0xad),
+	 '\'l' => chr(0xc3).chr(0xba),
+	 '\'n' => chr(0xc3).chr(0x84),
+	 '\'o' => chr(0xc3).chr(0xb3),
+	 '\'r' => chr(0xc5).chr(0x95),
+	 '\'s' => chr(0xc5).chr(0x9b),
+	 '\'u' => chr(0xc3).chr(0xba),
+	 '\'y' => chr(0xc3).chr(0xbd),
+	 '\'z' => chr(0xc5).chr(0xba),
+	 # graves
+	 '`a' => chr(0xc3).chr(0xa0),
+	 '`A' => chr(0xc3).chr(0x80),
+	 '`e' => chr(0xc3).chr(0xa8),
+	 '`E' => chr(0xc3).chr(0x88),
+	 '`i' => chr(0xc3).chr(0xac),
+	 '`I' => chr(0xc3).chr(0x8c),
+	 '`o' => chr(0xc3).chr(0xb2),
+	 '`O' => chr(0xc3).chr(0x92),
+	 '`u' => chr(0xc3).chr(0xb9),
+	 '`U' => chr(0xc3).chr(0x99),
+	 # circumflex
+	 '^a' => chr(0xc3).chr(0xa2),
+	 '^A' => chr(0xc3).chr(0x82),
+	 '^c' => chr(0xc4).chr(0x89),
+	 '^C' => chr(0xc4).chr(0x88),
+	 '^e' => chr(0xc3).chr(0xaa),
+	 '^E' => chr(0xc3).chr(0x8a),
+	 '^g' => chr(0xc4).chr(0x9d),
+	 '^G' => chr(0xc4).chr(0x9c),
+	 '^h' => chr(0xc4).chr(0xa5),
+	 '^H' => chr(0xc4).chr(0xa4),
+	 '^i' => chr(0xc3).chr(0xae),
+	 '^I' => chr(0xc3).chr(0x8e),
+	 '^j' => chr(0xc4).chr(0xb5),
+	 '^J' => chr(0xc4).chr(0xb4),
+	 '^o' => chr(0xc3).chr(0xb4),
+	 '^O' => chr(0xc3).chr(0x94),
+	 '^s' => chr(0xc5).chr(0x9d),
+	 '^S' => chr(0xc5).chr(0x9c),
+	 '^u' => chr(0xc3).chr(0xa2),
+	 '^U' => chr(0xc3).chr(0xbb),
+	 '^w' => chr(0xc5).chr(0xb5),
+	 '^W' => chr(0xc5).chr(0xb4),
+	 '^y' => chr(0xc5).chr(0xb7),
+	 '^Y' => chr(0xc5).chr(0xb6),
+	 
+	 # diaeresis
+	 '"a' => chr(0xc3).chr(0xa4),
+	 '"A' => chr(0xc3).chr(0x84),
+	 '"e' => chr(0xc3).chr(0xab),
+	 '"E' => chr(0xc3).chr(0x8b),
+	 '"\\\\i' => chr(0xc3).chr(0xaf),
+	 '"\\\\I' => chr(0xc3).chr(0x8f),
+	 '"o' => chr(0xc3).chr(0xb6),
+	 '"O' => chr(0xc3).chr(0x96),
+	 '"u' => chr(0xc3).chr(0xbc),
+	 '"U' => chr(0xc3).chr(0x9c),
+	 '"y' => chr(0xc3).chr(0xbf),
+	 '"Y' => chr(0xc3).chr(0xb8),
+	 # tilde
+	 '~A' => chr(0xc3).chr(0x83),
+	 '~N' => chr(0xc3).chr(0x91),
+	 '~O' => chr(0xc3).chr(0x95),
+	 '~a' => chr(0xc3).chr(0xa3),
+	 '~n' => chr(0xc3).chr(0xb1),
+	 '~o' => chr(0xc3).chr(0xb5),
+	 # caron - handled specially
+	 # double acute
+	 # ring
+	 # dot
+	 '.c' => chr(0xc4).chr(0x8b),
+	 '.C' => chr(0xc4).chr(0x8a),
+	 '.e' => chr(0xc4).chr(0x97),
+	 '.E' => chr(0xc4).chr(0x96),
+	 '.g' => chr(0xc4).chr(0xa1),
+	 '.G' => chr(0xc4).chr(0xa0),
+	 '.I' => chr(0xc4).chr(0xb0),
+	 '.z' => chr(0xc5).chr(0xbc),
+	 '.Z' => chr(0xc5).chr(0xbb),
+	 # macron
+	 '=a' => chr(0xc4).chr(0x81),
+	 '=A' => chr(0xc4).chr(0x80),
+	 '=e' => chr(0xc4).chr(0x93),
+	 '=E' => chr(0xc4).chr(0x92),
+	 '=i' => chr(0xc4).chr(0xab),
+	 '=I' => chr(0xc4).chr(0xaa),
+	 '=o' => chr(0xc4).chr(0x8d),
+	 '=O' => chr(0xc4).chr(0x8c),
+	 '=u' => chr(0xc4).chr(0xab),
+	 '=U' => chr(0xc4).chr(0xaa),
+	 
+	 # stroke - handled specially - see below
+	 
+	 # cedilla - handled specially
+	 );
+    
+# these are one letter latex commands - we make sure they're not a longer
+# command name. eg {\d} is d+stroke, so careful of \d
+    my %special_utf8_chars = 
+	(
+	 # breve
+	 'u g' => chr(0xc4).chr(0x9f),
+	 'u G' => chr(0xc4).chr(0x9e),
+	 'u i' => chr(0xc4).chr(0xad),
+	 'u I' => chr(0xc4).chr(0xac),
+	 'u o' => chr(0xc5).chr(0x8f),
+	 'u O' => chr(0xc5).chr(0x8e),
+	 'u u' => chr(0xc5).chr(0xad),
+	 'u U' => chr(0xc5).chr(0xac),
+	 # caron
+	 'v c' => chr(0xc4).chr(0x8d),
+	 'v C' => chr(0xc4).chr(0x8c),
+	 'v n' => chr(0xc5).chr(0x88),
+	 'v N' => chr(0xc5).chr(0x87),
+	 'v s' => chr(0xc5).chr(0xa1),
+	 'v S' => chr(0xc5).chr(0xa5),
+	 'v z' => chr(0xc5).chr(0xbe),
+	 'v Z' => chr(0xc5).chr(0xbd),
+	 # cedilla
+	 'c c' => chr(0xc3).chr(0xa7),
+	 'c C' => chr(0xc3).chr(0x87),
+	 'c g' => chr(0xc4).chr(0xa3),
+	 'c G' => chr(0xc4).chr(0xa2),
+	 'c k' => chr(0xc4).chr(0xb7),
+	 'c K' => chr(0xc4).chr(0xb6),
+	 'c l' => chr(0xc4).chr(0xbc),
+	 'c L' => chr(0xc4).chr(0xbb),
+	 'c n' => chr(0xc5).chr(0x86),
+	 'c N' => chr(0xc5).chr(0x85),
+	 'c r' => chr(0xc5).chr(0x97),
+	 'c R' => chr(0xc5).chr(0x96),
+	 'c s' => chr(0xc5).chr(0x9f),
+	 'c S' => chr(0xc5).chr(0x9e),
+	 'c t' => chr(0xc5).chr(0xa3),
+	 'c T' => chr(0xc5).chr(0xa2),
+	 # double acute / Hungarian accent
+	 'H O' => chr(0xc5).chr(0x90),
+	 'H o' => chr(0xc5).chr(0x91),
+	 'H U' => chr(0xc5).chr(0xb0),
+	 'H u' => chr(0xc5).chr(0xb1),
+	 
+	 # stroke 
+	 'd' => chr(0xc4).chr(0x91),
+	 'D' => chr(0xc4).chr(0x90),
+	 'h' => chr(0xc4).chr(0xa7),
+#	 'H' => chr(0xc4).chr(0xa6), # !! this normally(!!?) means Hung. umlaut
+	 'i' => chr(0xc4).chr(0xb1), # dotless lowercase i
+	 'l' => chr(0xc5).chr(0x82),
+	 'L' => chr(0xc5).chr(0x81),
+	 'o' => chr(0xc3).chr(0xb8),
+	 'O' => chr(0xc3).chr(0x98),
+	 't' => chr(0xc5).chr(0xa7),
+	 'T' => chr(0xc5).chr(0xa6),
+	 # german ss/szlig/sharp s
+	 'ss' => chr(0xc3).chr(0x9f),
+	 );
+    
+    # convert latex-style accented characters.
+
+    # remove space (if any) between \ and letter to accent (eg {\' a})
+
+    $text =~ s@(\\[`'="^~\.])\s(\w)@$1$2@g;
+
+    # remove {} around a single character (eg \'{e})
+    $text =~ s@(\\[`'="^~\.]){(\w)}@{$1$2}@g;
+
+    # \, is another way of doing cedilla \c
+    $text =~ s@\\,(.)@\\c $1@g;
+
+    # remove {} around a single character for special 1 letter commands -
+    # need to insert a space. Eg \v{s}  ->  {\v s}
+    $text =~ s@(\\[uvcH]){(\w)}@{$1 $2}@g;
+
+    # only do if the text contains a '\' character. 
+    if ($text =~ m|\\|) {
+	# "normal" accents - ie non-alpha latex tag
+	while ($text =~ m@\\([`'="^~\.])([\w])@) {
+	    my $tex="$1$2"; my $char="$2";
+	    my $replacement=$utf8_chars{$tex};
+	    if (!defined($replacement)) {
+		print STDERR "BibTexPlug: Warning: unknown latex accent \"$tex\" in \"$text\"\n";
+		$replacement=$char;
+	    }
+	    $text =~ s/\\\Q$tex/$replacement/g;
+	}
+
+        # where the following letter matters (eg "sm\o rrebr\o d", \ss{})
+        # only do the change if immediately followed by a space, }, {, or \
+	# one letter accents ( + ss)
+        while ($text =~ m@\\([DdhiLlOoTt]|ss)[{}\s\"\\]@) {
+	    my $tex=$1;
+	    my $replacement=$special_utf8_chars{$tex};
+	    if (!defined($replacement)) {
+		print STDERR "BibTexPlug: Warning: unknown latex accent \"$tex\" in \"$text\"\n";
+		$replacement=$tex;
+	    }
+	    $text =~ s/\\$tex([{}\s\"\\])/$replacement$1/g;
+
+	}
+
+	# one letter latex accent commands that affect following letter
+        while ($text =~ m@\\([uvcH]) ([\w])@) {
+          my $tex="$1 $2"; my $char="$2";
+          my $replacement=$special_utf8_chars{$tex};
+          if (!defined($replacement)) {
+	      print STDERR "BibTexPlug: Warning: unknown latex accent \"$tex\" in \"$text\"\n";
+	      $replacement=$char;
+	  }
+          $text =~ s/\\$tex/$replacement/g;
+        }
+    }
+
+    # escape html-sensitive characters
+    $text =~ s@&@&amp;@g;
+    $text =~ s@<@&lt;@g;
+    $text =~ s@>@&gt;@g;
+    $text =~ s/''/"/g; # Latex-specific
+    $text =~ s/``/"/g; # Latex-specific
+    # greenstone-specific
+    $text =~ s@\[@&\#91;@g;
+    $text =~ s@\]@&\#93;@g;
+
+    # remove latex commands
+
+    # explicitly recognised commands
+    $text =~ s@\\ldots@&hellip;@g;
+
+    # maths mode
+    $text =~ s@\$(.*?)\$@&process_latex_math($1)@ge;
+
+    # remove all other commands with optional arguments...
+    $text =~ s@\\\w+(\[.*?\])?\s*@@g;
+    # $text =~ s@\\noopsort{[^}]+\}@@g;
+    # $text =~ s@\\\w+{(([^}]*[^\\])*)}@$1@g; # all other commands
+    
+    # remove latex groupings { } (but not \{ or \} )
+    while ($text =~ s/([^\\])[\{\}]/$1/g) {;} # needed for "...}{..."
+    $text =~ s/^\{//; # remove { if first char
+    
+    # latex characters
+    # spaces - nobr space (~), opt break (\-), append ("#" - bibtex only)
+    $text =~ s/([^\\])~+/$1 /g; # non-breaking space  "~"
+    # optional break "\-"
+    if ($text =~ m/[^&]\#/) { # concat macros (bibtex) but not HTML codes
+	# the non-macro bits have quotes around them - we just remove quotes
+	$text =~ s/([^&])[\"\#]/$1/g;
+    }
+    # dashes. Convert (m|n)-dash into single dash for html.
+    $text =~ s@\-\-+@\-@g;
+
+    # quoted { } chars
+    $text =~ s@\\{@{@g;
+    $text =~ s@\\}@}@g;
+
+    # finally to protect against macro language...
+    $text =~ s@\\@\\\\@g;
+
+    return $text;
+}
+
+
+sub process_latex_math {
+    my $text = shift;
+
+    $text =~ s@\\infty@infinity@g;       # or unicode 0x221E...
+    $text =~ s@\^{(.*?)}@<sup>$1</sup>@g; # superscript
+    $text =~ s@\^([^\{])@<sup>$1</sup>@g;
+    $text =~ s@\_{(.*?)}@<sub>$1</sub>@g; # subscript
+    $text =~ s@\_([^\{])@<sub>$1</sub>@g;
+
+    # put all other command names in italics
+    $text =~ s@\\([\w]+)@<i>$1</i>@g;
+
+    return $text;
+}
+
+sub set_OID {
+    my $self = shift (@_);
+    my ($doc_obj, $id, $segment_number) = @_;
+    
+    if ( $self->{'key'} eq "default") {
+	$doc_obj->set_OID("$id\_$segment_number");
+    } else {
+	$doc_obj->set_OID($self->{'key'});
+    }
+}
+
+1;
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BookPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BookPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/BookPlug.pm	(revision 10506)
@@ -0,0 +1,248 @@
+###########################################################################
+#
+# BookPlug.pm (formally called HBSPlug) -- plugin for processing simple
+# html (or text) books
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# creates multi-level document from document containing 
+# <<TOC>> level tags. Metadata for each section is taken from any
+# other tags on the same line as the <<TOC>>. e.g. <<Title>>xxxx<</Title>>
+# sets Title metadata.
+
+# Everything else between TOC tags is treated as simple html (i.e. no 
+# processing of html links or any other HTMLPlug type stuff is done).
+
+# expects input files to have a .hb file extension by default (this can be 
+# changed by adding a -process_exp option
+
+# a file with the same name as the hb file but a .jpg extension is
+# taken as the cover image (jpg files are blocked by this plugin)
+
+# BookPlug is a simplification (and extension) of the HBPlug used
+# by the Humanity Library collections. BookPlug is faster as it expects
+# the input files to be cleaner (The input to the HDL collections
+# contains lots of excess html tags around <<TOC>> tags, uses <<I>>
+# tags to specify images, and simply takes all text between <<TOC>>
+# tags and start of text to be Title metadata). If you're marking up
+# documents to be displayed in the same way as the HDL collections,
+# use this plugin instead of HBPlug.
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package BookPlug;
+
+use BasPlug;
+use util;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @BookPlug::ISA = ('BasPlug');
+}
+
+my $arguments = 
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() },
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_block_exp() } ];
+
+my $options = { 'name'     => "BookPlug",
+		'desc'     => "{BookPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub get_default_block_exp {
+    my $self = shift (@_);
+
+    return q^\.jpg$^;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.hb$^;
+}
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    print STDERR "<Processing n='$file' p='BookPlug'>\n" if ($gli);
+    print $outhandle "BookPlug: processing $file\n" 
+	if $self->{'verbosity'} > 1;
+    
+    my $cursection = $doc_obj->get_top_section();
+
+    # Add FileFormat as the metadata
+    $doc_obj->add_metadata($doc_obj->get_top_section(),"FileFormat", "Book");
+
+    my $filename = &util::filename_cat($base_dir, $file);
+    my $absdir = $filename;
+    $absdir =~ s/[^\/\\]*$//;
+
+    # add the cover image
+    my $coverimage = $filename;
+    $coverimage =~ s/\.[^\.]*$/\.jpg/i;
+    $doc_obj->associate_file($coverimage, "cover.jpg", "image/jpeg");
+
+    my $title = "";
+
+    # remove any leading rubbish
+    $$textref =~ s/^.*?(<<TOC)/$1/ios;
+    
+    my $curtoclevel = 1;
+    my $firstsection = 1;
+    my $toccount = 0;
+    while ($$textref =~ /\w/) {
+	$$textref =~ s/^<<TOC(\d+)>>([^\n]*)\n(.*?)(<<TOC|\Z)/$4/ios;
+	my $toclevel = $1;
+	my $metadata = $2;
+	my $sectiontext = $3;
+
+	if ($toclevel == 2) {
+	    $toccount ++;
+	}
+	
+	# close any sections below the current level and
+	# create a new section (special case for the firstsection)
+	while (($curtoclevel > $toclevel) ||
+	       (!$firstsection && $curtoclevel == $toclevel)) {
+	    $cursection = $doc_obj->get_parent_section ($cursection);
+	    $curtoclevel--;
+	}
+	if ($curtoclevel+1 < $toclevel) {
+	    print $outhandle "WARNING - jump in toc levels in $filename " . 
+		"from $curtoclevel to $toclevel\n";
+	}
+	while ($curtoclevel < $toclevel) {
+	    $curtoclevel++;
+	    $cursection = 
+		$doc_obj->insert_section($doc_obj->get_end_child($cursection));
+	}
+
+	# sort out metadata
+	while ($metadata =~ s/^.*?<<([^>]*)>>(.*?)<<[^>]*>>//) {
+	    my $metakey = $1;
+	    my $metavalue = $2;
+
+	    if ($metavalue ne "" && $metakey ne "") {
+		# make sure key fits in with gsdl naming scheme 
+		$metakey =~ tr/[A-Z]/[a-z]/;
+		$metakey = ucfirst ($metakey);
+		$doc_obj->add_utf8_metadata ($cursection, $metakey, $metavalue);
+	    }
+	}
+
+	# remove header rubbish
+	$sectiontext =~ s/^.*?<body[^>]*>//ios;
+
+	# and any other unwanted tags
+	$sectiontext =~ s/<(\/p|\/html|\/body)>//isg;
+
+	# fix up the image links
+	$sectiontext =~ s/(<img[^>]*?src\s*=\s*\"?)([^\">]+)(\"?[^>]*>)/
+	    &replace_image_links($absdir, $doc_obj, $1, $2, $3)/isge;
+
+	# add the text
+	$doc_obj->add_utf8_text($cursection, $sectiontext);
+
+	$firstsection = 0;
+
+	$$textref =~ s/^\s+//s;
+    }
+
+    return 1;
+}
+
+sub replace_image_links {
+    my $self = shift (@_);
+    my ($dir, $doc_obj, $front, $link, $back) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my ($filename, $error);
+    my $foundimage = 0;
+    
+    $link =~ s/\/\///;
+    my ($imagetype) = $link =~ /([^\.]*)$/;
+    $imagetype =~ tr/[A-Z]/[a-z]/;
+    if ($imagetype eq "jpg") {$imagetype = "jpeg";}
+    if ($imagetype !~ /^(jpeg|gif|png)$/) {
+	print $outhandle "BookPlug: Warning - unknown image type ($imagetype)\n";
+    }
+    my ($imagefile) = $link =~ /([^\/]*)$/;
+    my ($imagepath) = $link =~ /^[^\/]*(.*)$/;
+
+    if (defined $imagepath && $imagepath =~ /\w/) {
+	# relative link
+	$filename = &util::filename_cat ($dir, $imagepath);
+	if (-e $filename) {
+	    $doc_obj->associate_file ($filename, $imagefile, "image/$imagetype");
+	    $foundimage = 1;
+	} else {
+	    $error = "BookPlug: Warning - couldn't find image file $imagefile in either $filename or";
+	}
+    }
+
+    if (!$foundimage) {
+	$filename = &util::filename_cat ($dir, $imagefile);
+	if (-e $filename) {
+	    $doc_obj->associate_file ($filename, $imagefile, "image/$imagetype");    
+	    $foundimage = 1;
+	} elsif (defined $error) {
+	    print $outhandle "$error $filename\n";
+	} else {
+	    print $outhandle "BookPlug: Warning - couldn't find image file $imagefile in $filename\n";
+	}
+    }
+
+    if ($foundimage) {
+	return "${front}_httpdocimg_/${imagefile}${back}";
+    } else {
+	return "";
+    }
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ConvertToPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ConvertToPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ConvertToPlug.pm	(revision 10506)
@@ -0,0 +1,463 @@
+###########################################################################
+#
+# ConvertToPlug.pm -- plugin that inherits from BasPlug
+#
+# 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 plugin is inherited by such plugins as WordPlug, PPTPlug, PSPlug, RTFPlug 
+# and PDFPlug. It facilitates the conversion of these document types to either 
+# HTML, Text or auto (allow user to choose which format to convert to).
+# It works by dynamically inheriting BasPlug and base on the plugin type in
+# secondary_plugins to devide which format to 'convert_to'. If the argument is 
+# not present, the default is to inherit auto.
+package ConvertToPlug;
+
+use BasPlug;
+use ghtml;
+use HTMLPlug;
+use TEXTPlug;
+use PagedImgPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @ConvertToPlug::ISA = ('BasPlug');
+}
+
+my $convert_to_list =
+    [ {	'name' => "auto",
+	'desc' => "{ConvertToPlug.convert_to.auto}" },
+      {	'name' => "html",
+	'desc' => "{ConvertToPlug.convert_to.html}" },
+      {	'name' => "text",
+	'desc' => "{ConvertToPlug.convert_to.text}" }
+      ];
+
+my $arguments =
+    [ { 'name' => "convert_to",
+	'desc' => "{ConvertToPlug.convert_to}",
+	'type' => "enum",
+	'reqd' => "yes",
+	'list' => $convert_to_list, 
+	'deft' => "html" },
+      { 'name' => "title_sub",
+	'desc' => "{HTMLPlug.title_sub}",
+	'type' => "string", 
+	#'type' => "regexp",
+	'deft' => "" },
+      { 'name' => "use_strings",
+	'desc' => "{ConvertToPlug.use_strings}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "extract_keyphrases",
+	'desc' => "{BasPlug.extract_keyphrases}",
+	'type' => "flag",
+	'reqd' => "no",
+	'hiddengli' => "yes" },
+      { 'name' => "extract_keyphrase_options",
+	'desc' => "{BasPlug.extract_keyphrase_options}",
+	'type' => "string",
+	'reqd' => "no",
+	'hiddengli' => "yes" } ];
+
+my $options = { 'name'     => "ConvertToPlug",
+		'desc'     => "{ConvertToPlug.desc}",
+		'abstract' => "yes",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub findType
+{
+    my ($inputargs) = @_;
+    my $convert_to_type = "html";
+    my $windows_scripting = "false";
+    for(my $intCounter = 0; $intCounter < scalar(@{$inputargs}) ; $intCounter++)
+    {
+	if($inputargs->[$intCounter] eq "-convert_to")
+	{
+	    if($inputargs->[$intCounter+1] eq "auto" || $inputargs->[$intCounter+1] =~ /pagedimg.*/i || $inputargs->[$intCounter+1] eq "text" || $inputargs->[$intCounter+1] eq "html")
+	    {
+		$convert_to_type = $inputargs->[$intCounter+1];
+	    }
+	}
+	if ($inputargs->[$intCounter] eq "-windows_scripting")
+	{
+	    $windows_scripting = "true";
+	}
+    }
+    return ($convert_to_type,$windows_scripting);
+}
+
+sub load_secondary_plugins
+{
+    my $self = shift (@_);
+    my ($class,$input_args,$hashArgOptLists) = @_;
+
+    my @convert_to_list = split(",",$self->{'convert_to'});
+    my $secondary_plugins = {};
+
+    foreach my $convert_to (@convert_to_list) {
+	# load in "convert_to" plugin package
+	my $plugin_class = $convert_to."Plug";
+	my $plugin_package = $plugin_class.".pm";
+
+	require $plugin_package;
+
+	# call its constructor with extra options that we've worked out!
+	my $arglist = $input_args->{$plugin_class};
+	my $secondary_plugin = new $plugin_class([],$arglist, $hashArgOptLists);
+	$secondary_plugins->{$plugin_class} = $secondary_plugin;
+    }
+    $self->{'secondary_plugins'} = $secondary_plugins;
+}
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+    my $classPluginName = (defined $pluginlist->[0]) ? $pluginlist->[0] : $class;
+    my ($strConvertTo,$blnWindowsScripting) = findType($inputargs);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+    
+    
+    if ($classPluginName eq "PDFPlug") {
+	if ($strConvertTo eq "text" && 
+	    $ENV{'GSDLOS'} =~ /^windows$/i) {
+	    print STDERR "Windows does not support pdf to text. PDFs will be converted to HTML instead\n";
+	    $strConvertTo = "html";
+	}
+    } elsif ($classPluginName eq "WordPlug") {
+	if ($blnWindowsScripting eq "true" && $ENV{'GSDLOS'} =~ /^windows$/i && $strConvertTo =~ /^(html|auto)$/) {
+	    # we use structured HTML, not normal html
+	    $strConvertTo = "structuredhtml";
+	} 
+    }
+    elsif ($classPluginName eq "PPTPlug") {
+	if ($blnWindowsScripting eq "true" && $ENV{'GSDLOS'} =~ /^windows$/i && $strConvertTo eq "auto") {
+	    # we use paged img
+	    $strConvertTo = "pagedimg_jpg";
+	} 
+    }
+    
+    if ($strConvertTo eq "auto") {
+	# choose html for now - should choose a format based on doc type
+	$strConvertTo = "html";
+    }
+    
+    if ($strConvertTo eq "html") {
+	$self->{'convert_to'} = "HTML";
+	$self->{'convert_to_ext'} = "html";
+    } elsif ($strConvertTo eq "text") {
+	$self->{'convert_to'} = "TEXT";
+	$self->{'convert_to_ext'} = "txt";
+    } elsif ($strConvertTo eq "structuredhtml") {
+	$self->{'convert_to'} = "StructuredHTML";
+	$self->{'convert_to_ext'} = "html";
+    } elsif ($strConvertTo =~ /^pagedimg/) {
+	$self->{'convert_to'} = "PagedImg";
+	my ($convert_to_ext) = $strConvertTo =~ /pagedimg\_(jpg|gif|png)/i;
+	$convert_to_ext = 'jpg' unless defined $convert_to_ext;
+	$self->{'convert_to_ext'} = $convert_to_ext;
+    }
+
+    return bless $self, $class;
+}
+
+
+sub init {
+    my $self = shift (@_);
+    my ($verbosity, $outhandle, $failhandle) = @_;
+
+    $self->SUPER::init($verbosity,$outhandle,$failhandle);
+
+    my $secondary_plugins =  $self->{'secondary_plugins'};
+
+    foreach my $plug_name (keys %$secondary_plugins) {
+	my $plugin = $secondary_plugins->{$plug_name};
+	$plugin->init($verbosity,$outhandle,$failhandle);
+    }
+}
+
+sub deinit {
+    # called only once, after all plugin passes have been done
+
+    my ($self) = @_;
+
+    my $secondary_plugins =  $self->{'secondary_plugins'};
+
+    foreach my $plug_name (keys %$secondary_plugins) {
+	my $plugin = $secondary_plugins->{$plug_name};
+	$plugin->deinit();
+    }
+}
+
+sub convert_post_process
+{
+    # by default do no post processing
+    return;
+}
+
+
+# Run conversion utility on the input file.  
+#
+# The conversion takes place in a collection specific 'tmp' directory so 
+# that we don't accidentally damage the input.
+#
+# The desired output type is indicated by $output_ext.  This is usually
+# something like "html" or "word", but can be "best" (or the empty string)
+# to indicate that the conversion utility should do the best it can.
+sub tmp_area_convert_file {
+    my $self = shift (@_);
+    my ($output_ext, $input_filename, $textref) = @_;
+    
+    my $outhandle = $self->{'outhandle'};
+    my $convert_to = $self->{'convert_to'};
+    my $failhandle = $self->{'failhandle'};
+    my $convert_to_ext = $self->{'convert_to_ext'};
+    
+    # softlink to collection tmp dir
+    my $tmp_dirname 
+	= &util::filename_cat($ENV{'GSDLCOLLECTDIR'}, "tmp");
+    &util::mk_dir($tmp_dirname) if (!-e $tmp_dirname);
+
+    # derive tmp filename from input filename
+    my ($tailname, $dirname, $suffix)
+	= &File::Basename::fileparse($input_filename, "\\.[^\\.]+\$");
+
+    # Remove any white space from filename -- no risk of name collision, and
+    # makes later conversion by utils simpler. Leave spaces in path...
+    # tidy up the filename with space, dot, hyphen between
+    $tailname =~ s/\s+//g; 
+    $tailname =~ s/\.+//g;
+    $tailname =~ s/\-+//g;
+    $suffix = lc($suffix);
+    my $tmp_filename = &util::filename_cat($tmp_dirname, "$tailname$suffix");
+    &util::soft_link($input_filename, $tmp_filename);
+    my $verbosity = $self->{'verbosity'};
+    if ($verbosity > 0) {
+	print $outhandle "Converting $tailname$suffix to $convert_to format\n";
+    }
+
+    my $errlog = &util::filename_cat($tmp_dirname, "err.log");
+    
+    # Execute the conversion command and get the type of the result,
+    # making sure the converter gives us the appropriate output type
+    my $output_type="";
+    if ($convert_to =~ m/PagedImg/i) {
+	$output_type = lc($convert_to)."_".lc($convert_to_ext);
+    } else {
+	$output_type = lc($convert_to);
+    }
+
+    my $cmd = "perl -S gsConvert.pl -verbose $verbosity ";
+    if (defined $self->{'convert_options'}) {
+	$cmd .= $self->{'convert_options'} . " ";
+    }
+    if ($self->{'use_strings'}) {
+      $cmd .= "-use_strings ";
+    }
+    $cmd .= "-errlog \"$errlog\" -output $output_type \"$tmp_filename\"";
+
+    $output_type = `$cmd`;
+
+    # remove symbolic link to original file
+    &util::rm($tmp_filename);
+
+    # Check STDERR here
+    chomp $output_type;
+    if ($output_type eq "fail") {
+	print $outhandle "Could not convert $tailname$suffix to $convert_to format\n";
+	print $failhandle "$tailname$suffix: " . ref($self) . " failed to convert to $convert_to\n";
+	$self->{'num_not_processed'} ++;
+	if (-s "$errlog") {
+	    open(ERRLOG, "$errlog");
+	    while (<ERRLOG>) {
+		print $outhandle "$_";
+	    }
+	    print $outhandle "\n";
+	    close ERRLOG;
+	}
+	&util::rm("$errlog") if (-e "$errlog");
+	return "";
+    }
+
+    # store the *actual* output type and return the output filename
+    # it's possible we requested conversion to html, but only to text succeeded
+    #$self->{'convert_to_ext'} = $output_type;
+    if ($output_type =~ /html/i) {
+	$self->{'converted_to'} = "HTML";
+    } elsif ($output_type =~ /te?xt/i) {
+	$self->{'converted_to'} = "TEXT";
+    } elsif ($output_type =~ /item/i){
+	$self->{'converted_to'} = "PagedImg";
+    }
+    
+    my $output_filename = $tmp_filename;
+    if ($output_type =~ /item/i) {
+	# running under windows
+	if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	    $output_filename = $tmp_dirname . "\\$tailname\\" . $tailname . ".$output_type";
+	} else {
+	    $output_filename = $tmp_dirname . "\/$tailname\/" . $tailname . ".$output_type";
+	}
+    } else {
+	$output_filename =~ s/$suffix$/.$output_type/;
+    }
+    return $output_filename;
+}
+
+
+# Override BasPlug read
+# We don't want to get language encoding stuff until after we've converted
+# our file to either TEXT or HTML or PagedImage.
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    #if ($self->is_recursive()) {
+    #   die "BasPlug::read function must be implemented in sub-class for recursive plugins\n";
+    # }
+
+    my $outhandle = $self->{'outhandle'};
+    
+    my ($block_status,$filename) = $self->read_block(@_);
+    return $block_status if ((!defined $block_status) || ($block_status==0));
+    $file = $self->read_tidy_file($file);
+    
+    my $output_ext = $self->{'convert_to_ext'};
+    my $conv_filename = "";
+    $conv_filename = $self->tmp_area_convert_file($output_ext, $filename);
+
+    if ("$conv_filename" eq "") {return 0;} # allows continue on errors
+    if (! -e "$conv_filename") {return 0;} # allows continue on errors
+    $self->{'conv_filename'} = $conv_filename;
+    $self->convert_post_process($conv_filename);
+    
+    my $secondary_plugins =  $self->{'secondary_plugins'};
+    my $num_secondary_plugins = scalar(keys %$secondary_plugins);
+
+    if ($num_secondary_plugins == 0) {
+	print $outhandle "Warning: No secondary plugin to use in conversion.  Skipping $file\n";
+	return 0; # effectively block it
+    }
+
+    my @plugin_names = keys %$secondary_plugins;
+    my $plugin_name = shift @plugin_names;
+	
+    if ($num_secondary_plugins > 1) {
+	print $outhandle "Warning: Multiple secondary plugins not supported yet!  Choosing $plugin_name\n.";
+    }
+   
+    my $secondary_plugin = $secondary_plugins->{$plugin_name};
+
+    # note: metadata is not carried on to the next level
+    my ($rv,$doc_obj) 
+	= $secondary_plugin->read_into_doc_obj ($pluginfo,"", $conv_filename, 
+						$metadata, $processor, $maxdocs, $total_count,
+						$gli);
+
+    if ((!defined $rv) || ($rv<1)) {
+	# wasn't processed
+	return $rv;
+    }
+    
+    # Override previous gsdlsourcefilename set by secondary plugin
+    my $collect_file = &util::filename_within_collection($filename);
+    my $collect_conv_file = &util::filename_within_collection($conv_filename);
+    $doc_obj->set_source_filename ($collect_file); 
+    $doc_obj->set_converted_filename($collect_conv_file);
+
+    my ($filemeta) = $file =~ /([^\\\/]+)$/;
+    $doc_obj->set_utf8_metadata_element($doc_obj->get_top_section(), "Source", &ghtml::dmsafe($filemeta));
+    $doc_obj->set_utf8_metadata_element($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+    $doc_obj->set_utf8_metadata_element($doc_obj->get_top_section(), "FileSize", (-s $filename));
+
+    # do plugin specific processing of doc_obj
+    unless (defined ($self->process(undef, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli))) {
+	print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	return -1;
+    }
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata ($doc_obj);
+    # add an OID
+    $doc_obj->set_OID();
+    # process the document
+    $processor->process($doc_obj);
+
+    $self->{'num_processed'} ++;
+
+    return 1;
+}
+
+
+# do plugin specific processing of doc_obj for doc_ext type
+sub process_type {
+    my $self = shift (@_);
+    my ($doc_ext, $base_dir, $file, $doc_obj) = @_;
+    
+    # associate original file with doc object
+    my $cursection = $doc_obj->get_top_section();
+    my $filename = &util::filename_cat($base_dir, $file);
+    $doc_obj->associate_file($filename, "doc.$doc_ext", undef, $cursection);
+
+    my $file_type;
+
+    if ($doc_ext eq "doc") {
+    	$file_type = "Word";
+    } elsif ($doc_ext eq "xls") {
+	$file_type = "Excel";
+    } elsif ($doc_ext eq "ppt") {
+	$file_type = "PPT"; 
+    } elsif ($doc_ext eq "pdf") {
+	$file_type = "PDF"; 
+    } elsif ($doc_ext eq "rtf") {
+	$file_type = "RTF";
+    } elsif ($doc_ext eq "ps") {
+	$file_type = "PS";
+    }
+
+    my $file_format = $file_type || "unknown";
+
+    # We use set instead of add here because we only want one value
+    $doc_obj->set_utf8_metadata_element($cursection, "FileFormat", $file_format);
+
+    my $doclink = "<a href=\"_httpcollection_/index/assoc/[archivedir]/doc.$doc_ext\">";
+    $doc_obj->add_utf8_metadata ($cursection, "srclink",  $doclink); 
+    $doc_obj->add_utf8_metadata ($cursection, "srcicon",  "_icon".$doc_ext."_"); 
+    $doc_obj->add_utf8_metadata ($cursection, "/srclink", "</a>"); 
+
+    return 1;
+}
+
+1;
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ConvertToRogPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ConvertToRogPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ConvertToRogPlug.pm	(revision 10506)
@@ -0,0 +1,463 @@
+###########################################################################
+#
+# ConvertToRogPlug.pm -- plugin that inherits from RogPlug
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+package ConvertToRogPlug;
+
+use BasPlug;
+use RogPlug;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @ConvertToRogPlug::ISA = ('RogPlug');
+}
+
+my $arguments = [
+		 ];
+my $options = { 'name'     => "ConvertToRogPlug",
+		'desc'     => "{ConvertToRogPlug.desc}",
+		'abstract' => "yes",
+		'inherits' => "yes" };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new RogPlug($pluginlist,$inputargs,$hashArgOptLists): new RogPlug($pluginlist,$inputargs);
+
+    $self->{'convert_to'} = "Rog";
+    $self->{'convert_to_ext'} = "rog";
+
+    return bless $self, $class;
+}
+
+
+sub begin {
+    my $self = shift (@_);
+    
+    $self->SUPER::begin(@_);
+
+    $self->{'docnum'} = 0;
+}
+
+sub end {
+    my ($self) = @_;
+
+    # nothing to do, but keep symmetric with begin function
+    $self->SUPER::end(@_);
+}
+
+
+# Run conversion utility on the input file.  
+#
+# The conversion takes place in a collection specific 'tmp' directory so 
+# that we don't accidentally damage the input.
+#
+# The desired output type is indicated by $output_ext.  This is usually
+# something like "html" or "word", but can be "best" (or the empty string)
+# to indicate that the conversion utility should do the best it can.
+
+sub tmp_area_convert_file {
+    my $self = shift (@_);
+    my ($output_ext, $input_filename, $textref) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+    my $convert_to = $self->{'convert_to'};
+    my $failhandle = $self->{'failhandle'};
+
+    # softlink to collection tmp dir
+    my $tmp_dirname 
+	= &util::filename_cat($ENV{'GSDLCOLLECTDIR'}, "tmp");
+    &util::mk_dir($tmp_dirname) if (!-e $tmp_dirname);
+
+    # derive tmp filename from input filename
+    my ($tailname, $dirname, $suffix)
+	= &File::Basename::fileparse($input_filename, "\\.[^\\.]+\$");
+
+    # Remove any white space from filename -- no risk of name collision, and
+    # makes later conversion by utils simpler. Leave spaces in path...
+    $tailname =~ s/\s+//g; 
+
+    my $tmp_filename = &util::filename_cat($tmp_dirname, "$tailname$suffix");
+
+    &util::soft_link($input_filename, $tmp_filename);
+
+    my $verbosity = $self->{'verbosity'};
+    if ($verbosity > 0) {
+	print $outhandle "Converting $tailname$suffix to $convert_to format\n";
+    }
+
+    my $errlog = &util::filename_cat($tmp_dirname, "err.log");
+    
+    # Execute the conversion command and get the type of the result,
+    # making sure the converter gives us the appropriate output type
+    my $output_type = lc($convert_to);
+    my $cmd = "perl -S gsMusicConvert.pl -verbose $verbosity -errlog \"$errlog\" -output $output_type \"$tmp_filename\"";
+    $output_type = `$cmd`;
+
+    # remove symbolic link to original file
+    &util::rm($tmp_filename);
+
+    # Check STDERR here
+    chomp $output_type;
+    if ($output_type eq "fail") {
+	print $outhandle "Could not convert $tailname$suffix to $convert_to format\n";
+	print $failhandle "$tailname$suffix: " . ref($self) . " failed to convert to $convert_to\n";
+	$self->{'num_not_processed'} ++;
+	if (-s "$errlog") {
+	    open(ERRLOG, "$errlog");
+	    while (<ERRLOG>) {
+		print $outhandle "$_";
+	    }
+	    print $outhandle "\n";
+	    close ERRLOG;
+	}
+	&util::rm("$errlog") if (-e "$errlog");
+	return "";
+    }
+
+    # store the *actual* output type and return the output filename
+    # it's possible we requested conversion to html, but only to text succeeded
+
+    $self->{'convert_to_ext'} = $output_type;
+    $self->{'converted_to'} = "Rog";
+
+    my $output_filename = $tmp_filename;
+
+    $output_filename =~ s/$suffix$//;
+
+    return $output_filename;
+}
+
+
+# Remove collection specific tmp directory and all its contents.
+
+sub cleanup_tmp_area {
+    my $self = shift (@_);
+
+    my $tmp_dirname 
+	= &util::filename_cat($ENV{'GSDLCOLLECTDIR'}, "tmp");
+    &util::rm_r($tmp_dirname);
+    &util::mk_dir($tmp_dirname);
+}
+
+
+# Exact copy of read_rog_record from RogPlug 
+# Needed for FILE in right scope
+
+sub read_rog_record
+{
+    my ($self,$file_buffer, $docnum, $seclevel) = @_;
+
+    my $next_line = $file_buffer->{'next_line'};
+
+    return 0 if (!defined $next_line);
+
+    if ($next_line eq "")
+    {
+	my $line;
+	while(defined($line=<FILE>))  
+	{
+	    $line =~ s/\r$//;
+	    $file_buffer->{'line_no'}++;
+	    next if ($line =~ m/^\#/);
+	    $next_line = $line;
+	    last;
+	}
+    }
+	    
+    if ($next_line !~ m/^song( +)\"([^\"]*)\"( +)\"([^\"]*)\"( +)(\d+)( *)$/) 
+    {
+	print STDERR "Error: Malformed Rog file: $next_line";
+	return 0;
+    }
+    else
+    {
+	# init default values
+	$file_buffer->{'song'}->{'tempo'}    = 120;
+	$file_buffer->{'song'}->{'ks_type'}  = 0;
+	$file_buffer->{'song'}->{'ks_num'}   = 0;
+	$file_buffer->{'song'}->{'metadata'} = [];
+	$file_buffer->{'song'}->{'content'}  = "";
+	
+	$file_buffer->{'song'}->{'subcol'} = $2;
+	$file_buffer->{'song'}->{'title'}  = $4;
+	$file_buffer->{'song'}->{'tval'}   = $6;
+
+	chomp($next_line);
+	my $content = $next_line;
+	if (defined $docnum) 
+	{
+	    $content.= " $docnum $seclevel";
+	}
+	$content .= "\n";
+
+	$file_buffer->{'song'}->{'content'} = $content;
+
+
+	my $line;
+	while(defined($line=<FILE>))  
+	{
+	    $line =~ s/\r$//;
+
+	    $file_buffer->{'line_no'}++;
+	    next if ($line =~ m/^\#/);
+	
+	    if ($line =~ m/^song/) 
+	    {	
+		$file_buffer->{'next_line'} = $line;
+		return 1;
+	    }
+	    elsif ($line =~ m/^tempo( +)(\d+)( *)$/) 
+	    {
+		$file_buffer->{'song'}->{'tempo'} = $2;
+		$file_buffer->{'song'}->{'content'} .= $line;
+	    } 
+	    elsif ($line =~ m/^keysig( +)(\d+)( +)(\d+)( *)$/) 
+	    {
+		$file_buffer->{'song'}->{'ks_type'} = $2;
+		$file_buffer->{'song'}->{'ks_num'}  = $4;
+		$file_buffer->{'song'}->{'content'} .= $line;	   
+	    } 
+	    elsif ($line =~ m/^timesig( +)(\d+)( +)(\d+)( *)$/) 
+	    {
+		$file_buffer->{'song'}->{'ts_numer'} = $2;
+		$file_buffer->{'song'}->{'ts_denom'} = $4;
+		$file_buffer->{'song'}->{'content'} .= $line;
+	    }
+	    elsif ($line =~ m/^metadata ([^:]*): (.*)/)
+	    {
+		push(@{$file_buffer->{'song'}->{'metadata'}},[$1,$2]);
+		$file_buffer->{'song'}->{'content'} .= $line;
+	    }
+	    else
+	    {
+		$file_buffer->{'song'}->{'content'} .= $line;
+	    }
+	}
+	
+	$file_buffer->{'next_line'} = undef;
+    }
+
+    return 1;
+}
+
+# Override RogPlug function so rog files are stored as sections (not docs)
+
+sub process_rog_record
+{
+    my ($self,$doc_obj,$cursection,$song) = @_;
+
+    $cursection = 
+	$doc_obj->insert_section($cursection);
+    $self->{'docnum'}++;
+
+    my $title = $song->{'title'};
+    my $title_safe = $title;
+    $title_safe =~ s/\'/\\\\&apos;/g;
+
+    # add metadata 
+    $doc_obj->add_metadata($cursection, "Tempo",         $song->{'tempo'}); 
+    $doc_obj->add_metadata($cursection, "KeySigType",    $song->{'ks_type'}); 
+    $doc_obj->add_metadata($cursection, "KeySigNum",     $song->{'ks_num'}); 
+    $doc_obj->add_metadata($cursection, "SubCollection", $song->{'subcol'}); 
+    $doc_obj->add_metadata($cursection, "Title",         $title); 
+    $doc_obj->add_metadata($cursection, "TitleSafe",     $title_safe); 
+    $doc_obj->add_metadata($cursection, "TVal",          $song->{'tval'}); 
+
+    foreach my $md ( @{$song->{'metadata'}} )
+    {
+	$doc_obj->add_metadata($cursection, $md->[0], $md->[1]); 
+    }
+
+    # add contents as text
+    $doc_obj->add_text($cursection,$song->{'content'});
+
+    return $cursection;
+}
+
+
+
+# Override BasPlug read
+# We don't want to get language encoding stuff until after we've converted
+# our file to Rog format
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+#    if ($self->is_recursive()) {
+#        die "BasPlug::read function must be implemented in sub-class for recursive plugins\n";
+#    }
+
+    my $outhandle = $self->{'outhandle'};
+
+    my $filename = $file;
+    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+
+    if ($self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/) {
+	$self->{'num_blocked'} ++;
+	return 0;
+    }
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+        return undef;
+    }
+    $file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
+
+    # read in file ($text will be in utf8)
+    my $text = "";
+
+    my $output_ext = $self->{'convert_to_ext'};
+    my $conv_filename = $self->tmp_area_convert_file($output_ext, $filename);
+
+    if ("$conv_filename" eq "") {return 0;} # allows continue on errors
+    $self->{'conv_filename'} = $conv_filename;
+
+
+    # create a new document
+    #my $doc_obj = new doc ($conv_filename, "indexed_doc");
+    # the original filename is used now
+    my $doc_obj = new doc ($filename, "indexed_doc");
+    # the converted filename is set separately
+    $doc_obj->set_converted_filename($conv_filename);
+
+    my $topsection = $doc_obj->get_top_section();
+    my $cursection = $topsection;
+
+    $self->{'docnum'}++;
+    my $docnum = $self->{'docnum'};
+
+    $doc_obj->set_OIDtype ($processor->{'OIDtype'});
+    my ($filemeta) = $file =~ /([^\\\/]+)$/;
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Source", &ghtml::dmsafe($filemeta));
+    if ($self->{'cover_image'}) {
+	$self->associate_cover_image($doc_obj, $filename);
+    }
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "FileSize", (-s $filename));
+
+    my $track_no = "1";
+    my $rog_filename = "$conv_filename$track_no.$output_ext";
+    while (1)
+    {
+	last unless open (FILE, $rog_filename) ;
+
+	my $file_buffer = { line_no => 0, next_line => "", song => {} };
+	
+	while ($self->read_rog_record($file_buffer, $docnum, $track_no))
+	{
+	    my $song = $file_buffer->{'song'};
+	    my $content = $song->{'content'};
+	    $content =~ s/^song\w+(.*)$/song $1 X.$track_no/;
+	    
+	    $cursection 
+		= $self->process_rog_record($doc_obj,$cursection,
+					    $file_buffer->{'song'});
+	}
+
+	close FILE;
+
+	$track_no++;
+	$rog_filename = "$conv_filename$track_no.$output_ext";
+    }
+
+    print STDERR "\n";
+
+    # include any metadata passed in from previous plugins 
+    # note that this metadata is associated with the top level section
+    $self->extra_metadata ($doc_obj, $doc_obj->get_top_section(), $metadata);
+    # do plugin specific processing of doc_obj
+    unless (defined ($self->process(\$text, $pluginfo, $base_dir, $file, $metadata, $doc_obj))) {
+	print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	return -1;
+    }
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata ($doc_obj);
+    # add an OID
+    $doc_obj->set_OID();
+
+    my $oid = $doc_obj->get_OID();
+    my $appletlink = "<a href=\"javascript:meldexout(\'$oid\','[TitleSafe]')\">";
+
+    $doc_obj->add_utf8_metadata ($topsection, "audiolink",  $appletlink); 
+    $doc_obj->add_utf8_metadata ($topsection, "audioicon",  "_iconaudio_"); 
+    $doc_obj->add_utf8_metadata ($topsection, "/audiolink", "</a>"); 
+
+    # if no title metadata defined, set it to filename minus extension
+    my $existing_title = $doc_obj->get_metadata_element($topsection,"Title");
+    if (!defined $existing_title) 
+    {
+	my $title = $doc_obj->get_metadata_element($topsection,"Source");
+	$title =~ s/\..*?$//g;
+	$doc_obj->add_utf8_metadata ($topsection, "Title", $title); 
+
+	my $title_safe = $title;
+	$title_safe =~ s/\'/\\\\&apos;/g;
+	$doc_obj->add_utf8_metadata ($topsection, "TitleSafe", $title_safe); 
+    }
+
+    # process the document
+    $processor->process($doc_obj);
+    $self->cleanup_tmp_area();
+
+    $self->{'num_processed'} ++;
+
+    return 1;
+}
+
+
+# do plugin specific processing of doc_obj for HTML type
+sub process_type {
+    my $self = shift (@_);
+    my ($doc_ext, $textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    
+    my $conv_filename = $self->{'conv_filename'};
+    my $tmp_dirname = File::Basename::dirname($conv_filename);
+    my $tmp_tailname = File::Basename::basename($conv_filename);
+    
+    my $converted_to = $self->{'converted_to'};
+    my $ret_val = 1;    
+
+#   $ret_val = &RogPlug::process($self, $textref, $pluginfo,
+#				 $tmp_dirname, $tmp_tailname,
+#				 $metadata, $doc_obj);
+
+    # associate original file with doc object
+    my $cursection = $doc_obj->get_top_section();
+    my $filename = &util::filename_cat($base_dir, $file);
+    $doc_obj->associate_file($filename, "doc.$doc_ext", undef, $cursection);
+
+    my $doclink = "<a href=\"_httpcollection_/index/assoc/[archivedir]/doc.$doc_ext\">";
+    $doc_obj->add_utf8_metadata ($cursection, "srclink",  $doclink); 
+    $doc_obj->add_utf8_metadata ($cursection, "srcicon",  "_icon".$doc_ext."_"); 
+    $doc_obj->add_utf8_metadata ($cursection, "/srclink", "</a>"); 
+    return $ret_val;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/DBPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/DBPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/DBPlug.pm	(revision 10506)
@@ -0,0 +1,354 @@
+###########################################################################
+#
+# DBPlug.pm -- plugin to import records from a database
+# 
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2003 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.
+#
+###########################################################################
+
+#
+# See <GSDLHOME>/etc/packages/example.dbi for an example config file!!
+#
+
+# Written by John McPherson for the NZDL project
+# Mar, Apr 2003
+
+package DBPlug;
+
+use strict;
+no strict 'refs'; # allow variable as a filehandle
+
+use BasPlug;
+use unicode;
+
+use DBI; # database independent stuff
+
+sub BEGIN {
+    @DBPlug::ISA = ('BasPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" }];
+
+my $options = { 'name'     => "DBPlug",
+		'desc'     => "{DBPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.dbi$^;
+}
+# we don't have a per-greenstone document process() function!
+sub process {
+
+}
+
+
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    # see if we can handle the passed file...
+    my $filename = $file;
+    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	# this plugin can't process this file type...
+        return undef;
+    }
+
+    my $outhandle = $self->{'outhandle'};
+    my $verbosity = $self->{'verbosity'};
+
+    print $outhandle "DBPlug: processing $file\n" 
+	if $self->{'verbosity'} > 1;
+    
+    # calculate the document hash, for document ids
+    my $hash="";
+
+    my $osexe = &util::get_os_exe();
+    my $hashfile_exe = &util::filename_cat($ENV{'GSDLHOME'},"bin",
+					   $ENV{'GSDLOS'},"hashfile$osexe");
+    if (-e "$hashfile_exe") {
+	$hash = `hashfile$osexe \"$filename\"`;
+	$hash =~ /:\s*([0-9a-f]+)/i;
+	$hash="HASH$1";
+    }
+
+
+    # default options - may be overridden by config file
+    my $language=undef;
+    my $encoding=undef;
+    my $dbplug_debug=0;
+    my $username='';
+    my $password='';
+
+    # these settings must be set by the config file:
+    my $db=undef;
+
+# get id of pages from "nonempty", get latest version number from "recent", and
+# then get pagename from "page" and content from "version" !
+
+    my $sql_query = undef ;
+
+    my %db_to_greenstone_fields=();
+    my %callbacks=();
+
+    # read in config file.
+    if (!open (CONF, $filename)) {
+	    print $outhandle "DBPlug: can't read $filename: $!\n";
+	    return 0;
+    }
+    my $line;
+    my $statement="";
+    my $callback="";
+    while (defined($line=<CONF>)) {
+	chomp $line;
+	$line =~ s/\s*\#.*$//mg; # remove comments
+	$statement .= $line;
+
+	if ($line =~ /^\}\s*$/ && $callback) { # ends the callback
+	    $callback .= $statement ; $statement = "";
+	    # try to check that the function is "safe"
+	    if ($callback  =~ /\b(?:system|open|pipe|readpipe|qx|kill|eval|do|use|require|exec|fork)\b/ ||
+		$callback =~ /[\`]|\|\-/) {
+		# no backticks or functions that start new processes allowed
+		print $outhandle "DBPlug: bad function in callback\n";
+		return 0;
+	    }
+	    $callback =~ s/sub (\w+?)_callback/sub/;
+	    my $fieldname=$1;
+	    eval "\$callbacks{'$fieldname'} = $callback ; 1";
+	    $callback="";
+	} elsif ($callback) {
+	    # add this line to the callback function
+	    $callback .= $statement;
+	    $statement = "";
+	} elsif ($statement =~ m/;\s*$/) { # ends with ";"
+	    # check that it is safe
+	    # assignment
+	    if ($statement =~ m~(\$\w+)\s* = \s*
+		(\d		# digits
+		 | ".*?(?<!\\)" # " up to the next " not preceded by a \
+		 | '.*?(?<!\\)' # ' up to the next ' not preceded by a \
+		)\s*;~x ||      # /x means ignore comments and whitespace in rx
+		$statement =~ m~(\%\w+)\s*=\s*(\([\w\s\"\',:=>]+\))\s*;~ ) {   
+		# evaluate the assignment, return 1 on success "
+		if (!eval "$1=$2; 1") {
+		    my $err=$@;
+		    chomp $err;
+		    $err =~ s/\.$//; # remove a trailing .
+		    print $outhandle "DBPlug: error evaluating `$statement'\n";
+		    print $outhandle " $err (in $filename)\n";
+		    return 0; # there was an error reading the config file
+		}
+	    } elsif ($statement =~ /sub \w+_callback/) {
+		# this is the start of a callback function definition
+		$callback = $statement;
+		$statement = "";
+	    } else {
+		print $outhandle "DBPlug: skipping statement `$statement'\n";
+	    }
+	    $statement = "";
+	}
+    }
+    close CONF;
+
+    if (!defined($db)) {
+	print $outhandle "DBPlug: error: $filename does not specify a db!\n";
+	return 0;
+    }
+    if (!defined($sql_query)) {
+    	print $outhandle "DBPlug: error: no SQL query specified!\n";
+	return 0;
+    }
+    # connect to database
+    my $dbhandle=DBI->connect($db, $username, $password);
+
+    if (!defined($dbhandle)) {
+	die "DBPlug: could not connect to database, exiting.\n";
+    }
+    if (defined($dbplug_debug) && $dbplug_debug==1) {
+	print $outhandle "DBPlug (debug): connected ok\n";
+    }
+
+    my $statement_hand=$dbhandle->prepare($sql_query);
+    $statement_hand->execute;
+
+    # get the array-ref for the field names and cast it to array
+    my @field_names;
+    @field_names=@{ $statement_hand->{NAME} };
+
+    foreach my $fieldname (@field_names) {
+	if (defined($db_to_greenstone_fields{$fieldname})) {
+	    if (defined($dbplug_debug) && $dbplug_debug==1) {
+		print $outhandle "DBPlug (debug): mapping db field "
+		    . "'$fieldname' to "
+			. $db_to_greenstone_fields{$fieldname} . "\n";
+	    }
+	    $fieldname=$db_to_greenstone_fields{$fieldname};
+	}
+    }
+
+#    print "DBPlug: names: " . join (", ", @field_names) . ".\n";
+    # get rows
+
+    my $count = 0;
+    my @row_array;
+
+    @row_array=$statement_hand->fetchrow_array; # fetchrow_hashref?
+    
+    while (scalar(@row_array)) {
+	if (defined($dbplug_debug) && $dbplug_debug==1) {
+	    print $outhandle "DBPlug (debug): retrieved a row from query\n";
+	}
+
+	# create a new document
+	my $doc_obj = new doc ($filename, "indexed_doc");
+	$doc_obj->set_OIDtype ($processor->{'OIDtype'});
+	my $cursection = $doc_obj->get_top_section();
+
+	# if $language not set in config file, will use BasPlug's default
+	if (defined($language)) {
+	    $doc_obj->add_utf8_metadata($cursection, "Language", $language);
+	}
+	# if $encoding not set in config file, will use BasPlug's default
+	if (defined($encoding)) {
+	    # allow some common aliases
+	    if ($encoding =~ m/^utf[-_]8$/i) {$encoding="utf8"}
+	    $encoding =~ s/-/_/g; # greenstone uses eg iso_8859_1
+	    $doc_obj->add_utf8_metadata($cursection, "Encoding", $encoding);
+	}
+	$doc_obj->add_utf8_metadata($cursection,
+				    "Source", &ghtml::dmsafe($db));
+	if ($self->{'cover_image'}) {
+	    $self->associate_cover_image($doc_obj, $filename);
+	}
+	$doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+
+	$doc_obj->add_metadata($doc_obj->get_top_section(), "FileFormat", "DB");
+
+	# include any metadata passed in from previous plugins 
+	# note that this metadata is associated with the top level section
+	$self->extra_metadata ($doc_obj, $cursection,
+			       $metadata);
+
+	# do any automatic metadata extraction
+	$self->auto_extract_metadata ($doc_obj);
+
+	my $unique_id=undef;
+
+	foreach my $fieldname (@field_names) {
+	    my $fielddata=shift @row_array;
+	    # use the specified encoding, defaulting to utf-8
+	    if (defined($encoding) && $encoding ne "ascii"
+	    	&& $encoding ne "utf8") {
+	      $fielddata=&unicode::unicode2utf8(
+	      	&unicode::convert2unicode($encoding, \$fielddata)
+					       );
+	    }
+	    # see if we have a ****_callback() function defined
+	    if (exists $callbacks{$fieldname}) {
+		my $funcptr = $callbacks{$fieldname};
+		$fielddata = &$funcptr($fielddata);
+	    }
+
+	    if ($fieldname eq "text") {
+		# add as document text
+		$fielddata=~s@<@&lt;@g;
+		$fielddata=~s@>@&gt;@g; # for xml protection...
+		$fielddata=~s@_@\\_@g; # for macro language protection...
+		$doc_obj->add_utf8_text($cursection, $fielddata);
+	    } elsif ($fieldname eq "Identifier") {
+		# use as greenstone's unique record id
+		if ($fielddata =~ /^\d+$/) {
+		    # don't allow IDs that are completely numeric
+		    $unique_id="id" . $fielddata;
+		} else {
+		    $unique_id=$fielddata;
+		}
+	    } else {
+		# add as document metadata
+		$fielddata=~s/\[/&#91;/g;
+		$fielddata=~s/\]/&#93;/g;
+		$doc_obj->add_utf8_metadata($cursection,
+					    $fieldname, $fielddata);
+
+	    }
+	}
+
+	if (!defined $unique_id) {
+	    $doc_obj->set_OID($hash . "s$count");
+	} else {
+	    # use our id from the database...
+	    $doc_obj->set_OID($unique_id);
+	}
+
+
+        # process the document
+	$processor->process($doc_obj);
+
+
+	$count++;
+
+	# get next row
+	@row_array=$statement_hand->fetchrow_array; # fetchrow_hashref?
+    } # end of row_array is not empty
+
+    # check "$sth->err" if empty array for error
+    if ($statement_hand->err) {
+	print $outhandle "DBPlug: received error: \"" .
+	    $statement_hand->errstr . "\"\n";
+    }
+
+    # clean up connection to database
+    $statement_hand->finish();
+    $dbhandle->disconnect();
+
+    # num of input files, rather than documents created?
+    $self->{'num_processed'}++;
+
+    if (defined($dbplug_debug) && $dbplug_debug==1) {
+        print $outhandle "DBPlug: imported $count DB records as documents.\n";
+    }
+    $count;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/DSpacePlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/DSpacePlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/DSpacePlug.pm	(revision 10506)
@@ -0,0 +1,408 @@
+###########################################################################
+#
+# DSpacePlug.pm -- plugin for import the collection from DSpace 
+# 
+# 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.
+#
+###########################################################################
+
+# DSpace Plug - 10/2004
+# 
+#
+# This plugin takes "contents" and dublin_core.xml file, which contain 
+# Metadata and lists of associated files for a particular document
+# and produces a document containing sections, one for each page.
+# The files should be named "contents" and "dublin_core.xml".  For each of 
+# document in DSpace, it is stored in one directory
+#
+# The format of the "contents" file is as follows:
+# 
+# File.type      bundle:ORIGINAL
+# license.txt    bundle:LICENSE
+# The format of the "dublin_core.xml" file is as follows:
+# The first line contains any metadata for the whole document
+# <dublin_core>
+# eg.
+# <dcvalue element="Title" qualifier="">Snail farming</dcvalue>
+# <dcvalue element="date" qualifier="">2004-10-15</dcvalue>
+#
+
+package DSpacePlug;
+
+use BasPlug;
+use plugin;
+#use ghtml;
+use XMLParser;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @DSpacePlug::ISA = ('BasPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "string",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "only_first_doc",
+	'desc' => "{DSpacePlug.only_first_doc}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "first_inorder_ext",
+	'desc' => "{DSpacePlug.first_inorder_ext}",
+	'type' => "string",
+	'reqd' => "no" },
+      { 'name' => "first_inorder_mime",
+	'desc' => "{DSpacePlug.first_inorder_mime}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_block_exp(),
+	'reqd' => "no" }];
+
+
+my $options = { 'name'     => "DSpacePlug",
+		'desc'     => "{DSpacePlug.desc}",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+my $primary_doc_lookup = { 'text/html' => '(?i)\.(gif|jpe?g|jpe|jpg|png|css)$' };
+
+# Important variation to regular plugin structure.  Need to declare
+# $self as global variable to file so XMLParser callback routines
+# can access the content of the object. 
+my ($self); 
+
+sub new {
+    my ($class) = shift (@_); 
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+    
+    #create XML::Parser object for parsing dublin_core.xml files
+    my $parser = new XML::Parser('Style' => 'Stream',
+				 'Handlers' => {'Char' => \&Char,
+						'Doctype' => \&Doctype
+						});
+    $self->{'parser'} = $parser;
+    $self->{'extra_blocks'} = {};
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)contents$^;
+}
+
+# want to block all files except the "contents"
+sub get_default_block_exp {
+    my $self = shift (@_);
+    
+    # Block all files besides contents
+    return q^(?i)(handle|dublin_core\.xml|\.tx?t)$^;
+}
+
+sub read_content
+{
+    my $self = shift (@_);
+    my ($dir, $only_first_doc, $first_inorder_ext, $first_inorder_mime, $mimetype_list) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my @fnamemime_list = ();
+    my @assocmime_list = ();
+
+    my $content_fname = &util::filename_cat($dir,"contents");
+
+    open(CIN,"<$content_fname") 
+	|| die "Unable to open $content_fname: $!\n";
+    
+    my $line;
+    my $pos = 0;
+
+    while (defined ($line = <CIN>)) {
+	if ($line =~ m/^(.*)\s+bundle:ORIGINAL\s*$/) {
+	    my $fname = $1;
+	    my $mtype = $mimetype_list->[$pos];
+	    my $fm_rec = { 'file' => $fname, 'mimetype' => $mtype};
+	    push(@fnamemime_list,$fm_rec);
+	    $pos++;
+	}
+    }
+    close CIN;
+
+    if ($only_first_doc){
+	my ($first_fname, @rest_fnames) = @fnamemime_list;
+	@fnamemime_list = ($first_fname);
+	@assocmime_list = @rest_fnames;
+    }
+
+    # allow user to specify the types of files (inorder)they would like to assign as
+    # a primary bitstream
+    if ($first_inorder_ext) {
+	# parse user-define file extension names
+	my @extfiles_list = split /,/, $first_inorder_ext;
+	my (@rest_fnames) = @fnamemime_list;
+	my @matched_list = ();
+	foreach my $file_ext (@extfiles_list) {
+	    $pos = 0;
+	    foreach my $allfiles (@fnamemime_list){
+		$allfiles->{'file'} =~ /^(.*)\.(.*?)$/;
+		my $allfiles_ext = $2;
+
+		if ($allfiles_ext =~ /$file_ext/) {
+		    print $outhandle "Existing file:$allfiles->{'file'} match the user-define File Extension:$file_ext\n";
+		    push (@matched_list, $allfiles);
+
+		    # delete the matched extension file from the array
+		    splice(@rest_fnames,$pos,1);
+
+		    return (\@matched_list, \@rest_fnames);
+
+		}
+		$pos++;
+	    }
+	}
+    }
+    
+    if ($first_inorder_mime) {
+	# parse user-define file mimetype
+	my @file_mime_list = split /,/, $first_inorder_mime;
+	my (@rest_fnames) = @fnamemime_list;
+	my @matched_list = ();
+	foreach my $file_mime (@file_mime_list) {
+	    $pos = 0;
+	    foreach my $allfiles (@fnamemime_list){
+		my $allfiles_mime = $allfiles->{'mimetype'};
+
+		if ($allfiles_mime =~ /$file_mime/) {
+		    print $outhandle "Existing file:$allfiles->{'file'} match the user-defined File MimeType:$file_mime\n";
+		    push (@matched_list, $allfiles);
+
+		    # delete the matched MIMEType file from the array
+		    splice(@rest_fnames,$pos,1);
+		    return (\@matched_list, \@rest_fnames);
+		}
+		$pos++;
+	    }
+	}
+    }
+    return (\@fnamemime_list, \@assocmime_list);
+}
+
+
+sub filemime_list_to_re
+{
+    my $self = shift (@_);
+    my ($fnamemime_list) = @_;
+
+    my @fname_list = map { "(".$_->{'file'}.")" } @$fnamemime_list;
+    my $fname_re = join("|",@fname_list);
+    $fname_re =~ s/\./\\\./g;
+
+    return $fname_re;
+}
+
+# Read dublin_core metadata from DSpace collection 
+sub metadata_read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $extrametakeys, $extrametadata, $processor, $maxdocs, $gli) = @_;
+
+    my $only_first_doc = $self->{'only_first_doc'};
+    my $first_inorder_ext = $self->{'first_inorder_ext'};
+    my $first_inorder_mime = $self->{'first_inorder_mime'};
+    
+    my $outhandle = $self->{'outhandle'};
+    
+    my $filename = &util::filename_cat($base_dir, $file);
+    # return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+    
+    if ($filename !~ /dublin_core\.xml$/ || !-f $filename) {
+	return undef;
+    }
+    
+    print $outhandle "DSpacePlug: extracting metadata from $file\n"
+	if $self->{'verbosity'} > 1;
+    
+    my ($dir) = $filename =~ /^(.*?)[^\/\\]*$/;
+
+    eval {
+	$self->{'parser'}->parsefile($filename);
+    };
+    
+    if ($@) {
+	die "DSpacePlug: ERROR $filename is not a well formed dublin_core.xml file ($@)\n";
+    }
+
+    my $mimetype_list = $self->{'saved_metadata'}->{'dc.Format^mimetype'};
+    my ($doc_file_mimes, $assoc_file_mimes) = $self->read_content($dir, $only_first_doc, $first_inorder_ext, 
+								  $first_inorder_mime, $mimetype_list);
+
+    my $file_re = $self->filemime_list_to_re($doc_file_mimes);
+
+    if ($only_first_doc || $first_inorder_ext || $first_inorder_mime) {	
+	foreach my $afm ( @$assoc_file_mimes ) {
+ 	    my $full_af = &util::filename_cat($dir,$afm->{'file'});
+	    $self->{'extra_blocks'}->{$full_af} = 1;
+	}
+    }
+    push(@$extrametakeys,$file_re);
+
+    if (defined $self->{'saved_metadata'}->{'dc.Format^extent'}) {
+	delete $self->{'saved_metadata'}->{'dc.Format^extent'};
+    }
+
+    if (defined $mimetype_list) {
+	delete $self->{'saved_metadata'}->{'dc.Format^mimetype'};
+
+	# Temporarily store associate file info in metadata table
+	# This will be removed in 'extra_metadata' in BasPlug and used
+	# to perform the actual file association (once the doc obj has
+	# been formed
+
+	my $main_doc = $doc_file_mimes->[0];
+	my $md_mimetype = $main_doc->{'mimetype'};
+
+	my $pd_lookup = $primary_doc_lookup->{$md_mimetype};
+
+	if (defined $pd_lookup) {
+	    my $filter_re = $pd_lookup;
+	    @$assoc_file_mimes = grep { $_->{'file'} !~ m/$filter_re/ }  @$assoc_file_mimes;
+	}
+
+	my @gsdlassocfile_tobe 
+	    = map { &util::filename_cat($dir,$_->{'file'}).":".$_->{'mimetype'}.":" } @$assoc_file_mimes;
+	$self->{'saved_metadata'}->{'gsdlassocfile_tobe'} = \@gsdlassocfile_tobe;
+
+    }
+    
+    $extrametadata->{$file_re} = $self->{'saved_metadata'};
+
+    return 1;
+}
+
+
+# The DSpacePlug read() function. This function does all the right things
+# to make general options work for a given plugin. It calls the process()
+# function which does all the work specific to a plugin (like the old
+# read functions used to do). Most plugins should define their own 
+# process() function and let this read() function keep control.
+#
+# DSpace overrides read() because there is no need to read the actual 
+# text of the file in, because the contents of the file is not text...
+#
+# Return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    # Block all files except contents
+    my $filename = &util::filename_cat($base_dir, $file);
+    return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+
+    my $assocfile = $metadata->{'assocfile'};
+
+    return 0 if (($filename =~ /dublin_core\.xml$/) || ($filename =~ /contents$/));
+    return 0 if (defined $self->{'extra_blocks'}->{$filename});
+    return undef;
+}
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    return 1;
+}
+
+sub Doctype {
+    my ($expat, $name, $sysid, $pubid, $internal) = @_;
+
+    die if ($name !~ /^dublin_core$/);
+}
+
+sub StartTag {
+    my ($expat, $element) = @_;
+    if ($element eq "dublin_core") {
+	$self->{'saved_metadata'} = {};
+    } elsif ($element eq "dcvalue") {
+	my $metaname = $_{'element'};
+	my $qualifier = $_{'qualifier'};
+	if ($metaname ne "description") {
+	    $metaname .= "^$qualifier" if ($qualifier ne "none" && $qualifier ne "");
+	    $self->{'metaname'} = "dc.\u$metaname";
+	}
+    }
+}
+
+sub EndTag {
+    my ($expat, $element) = @_;
+    
+    if ($element eq "dcvalue") {
+	$self->{'metaname'} = "";
+    }
+}
+
+sub Text {
+    if (defined ($self->{'metaname'}) && $self->{'metaname'} ne "") {
+	# $_ == Metadata content
+	my $mname = $self->{'metaname'};
+	if (defined $self->{'saved_metadata'}->{$mname}) {
+	    # accumulate - add value to existing value(s)
+	    if (ref ($self->{'saved_metadata'}->{$mname}) eq "ARRAY") {
+		push (@{$self->{'saved_metadata'}->{$mname}}, $_);
+	    } else {
+		$self->{'saved_metadata'}->{$mname} = 
+		    [$self->{'saved_metadata'}->{$mname}, $_];
+	    }
+	} else {
+	    # accumulate - add value into (currently empty) array
+	    $self->{'saved_metadata'}->{$mname} = [$_];
+	}
+
+    }
+}
+
+# This Char function overrides the one in XML::Parser::Stream to overcome a
+# problem where $expat->{Text} is treated as the return value, slowing
+# things down significantly in some cases.
+sub Char {
+    use bytes;  # Necessary to prevent encoding issues with XML::Parser 2.31+
+    $_[0]->{'Text'} .= $_[1];
+    return undef;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/EMAILPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/EMAILPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/EMAILPlug.pm	(revision 10506)
@@ -0,0 +1,1082 @@
+###########################################################################
+#
+# EMAILPlug.pm - a plugin for parsing email files
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999-2002 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+
+# EMAILPlug
+#
+# by Gordon Paynter (gwp@cs.waikato.ac.nz)
+#
+# Email plug reads email files.  These are named with a simple
+# number (i.e. as they appear in maildir folders) or with the 
+# extension .mbx (for mbox mail file format)
+#
+# Document text:
+#   The document text consists of all the text 
+#   after the first blank line in the document.
+#
+# Metadata (not Dublin Core!):
+#   $Headers      All the header content (optional, not stored by default)
+#   $Subject      Subject: header
+#   $To           To: header
+#   $From         From: header
+#   $FromName     Name of sender (where available)
+#   $FromAddr     E-mail address of sender
+#   $DateText     Date: header
+#   $Date         Date: header in GSDL format (eg: 19990924)
+#
+#   $Title	  made up of Subject, Date and Sender (for default formatting)
+#
+#
+# John McPherson - June/July 2001
+# added (basic) MIME support and quoted-printable and base64 decodings.
+# Minor fixes for names that are actually email addresses (ie <...> was lost)
+#
+# See:  * RFC 822  - ARPA Internet Text Messages
+#       * RFC 2045 - Multipurpose Internet Mail Extensions (MIME) -part1
+#       * RFC 2046 - MIME (part 2)  Media Types (and multipart messages)
+#       * RFC 2047 - MIME (part 3)  Message Header Extensions
+#       * RFC 1806 - Content Dispositions (ie inline/attachment)
+
+# 12/05/02 Added usage datastructure - John Thompson
+package EMAILPlug;
+
+use strict;
+no strict "refs"; # so we can use a variable as a filehandle for print $out
+
+
+use SplitPlug;
+use unicode;  # gs conv functions
+use gsprintf 'gsprintf'; # translations
+
+use sorttools;
+use util;
+
+sub BEGIN {
+    @EMAILPlug::ISA = ('SplitPlug');
+}
+
+
+my $arguments = 
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() },
+      { 'name' => "no_attachments",
+	'desc' => "{EMAILPlug.no_attachments}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "headers",
+	'desc' => "{EMAILPlug.headers}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "split_exp",
+	'desc' => "{EMAILPlug.split_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_split_exp() } 
+      ];
+
+my $options = { 'name'     => "EMAILPlug",
+		'desc'     => "{EMAILPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+# Create a new EMAILPlug object with which to parse a file.
+# Accomplished by creating a new BasPlug and using bless to 
+# turn it into an EMAILPlug.
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new SplitPlug($pluginlist,$inputargs,$hashArgOptLists): new SplitPlug($pluginlist,$inputargs);
+
+    $self->{'assoc_filenames'} = {}; # to save attach names so we don't clobber
+
+    # this might not actually be true at read-time, but after processing
+    # it should all be utf8.
+    $self->{'input_encoding'}="utf8";
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+    # mbx/email for mailbox file format, \d+ for maildir (each message is
+    # in a separate file, with a unique number for filename)
+    # mozilla and IE will save individual mbx format files with a ".eml" ext.
+    return q@([\\/]\d+|\.(mbx|email|eml))$@;
+}
+
+# This plugin splits the mbox mail files at lines starting with From<sp>
+# It is supposed to be "\n\nFrom ", but this isn't always used.
+# add \d{4} so that the line ends in a year (in case the text has an
+# unescaped "From " at the start of a line).
+sub get_default_split_exp {
+    return q^\nFrom .*\d{4}\n^;
+    
+}
+
+
+# do plugin specific processing of doc_obj
+sub process {
+
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    # Check that we're dealing with a valid mail file
+    # mbox message files start with "From "
+    # maildir messages usually start with Return-Path and Delivered-To
+    # mh is very similar to maildir
+    my $startoffile=substr($$textref,0,256);
+    if (($startoffile !~ /^(From )/) &&
+	($startoffile !~ /^(From|To|Envelope.*|Received|Return-Path|Date|Subject|Content\-.*|MIME-Version|Forwarded):/im)) {
+	return undef;
+    }
+
+
+    print STDERR "<Processing n='$file' p='EMAILPlug'>\n" if ($gli);
+
+    gsprintf($outhandle, "EMAILPlug: {common.processing} $file\n")
+	if $self->{'verbosity'} > 1;
+
+    my $cursection = $doc_obj->get_top_section();
+
+    #
+    # Parse the document's text and extract metadata
+    #
+
+    # Protect backslashes
+    $$textref =~ s@\\@\\\\@g;
+
+    # Separate header from body of message
+    my $Headers = $$textref;
+    $Headers =~ s/\r?\n\r?\n(.*)$//s;
+    $$textref = $1;
+    $Headers .= "\n";
+    
+    # Unfold headers - see rfc822
+    $Headers =~ s/\r?\n[\t\ ]+/ /gs;
+    # Extract basic metadata from header
+    my @headers = ("From", "To", "Subject", "Date");
+    my %raw;
+    foreach my $name (@headers) {
+	$raw{$name} = "No $name value";
+    }
+
+    # Get a default encoding for the header - RFC says should be ascii...
+    my $default_header_encoding="iso_8859_1";
+
+    # We don't know what character set is the user's default...
+    # We could use textcat to guess... for now we'll look at mime content-type
+#    if ($Headers =~ /([[:^ascii:]])/) {
+#    }
+    if ($Headers =~ /^Content\-type:.*charset=\"?([a-z0-9\-_]+)/mi) {
+	$default_header_encoding=$1;
+	$default_header_encoding =~ s@\-@_@g;
+	$default_header_encoding =~ tr/A-Z/a-z/;
+    }
+
+
+    # Examine each line of the headers
+    my ($line, $name, $value);
+    my @parts;
+    foreach $line (split(/\n/, $Headers)) {
+	
+	# Ignore lines with no content or which begin with whitespace
+	next unless ($line =~ /:/);
+	next if ($line =~ /^\s/);
+
+	# Find out what metadata is on this line
+	@parts = split(/:/, $line);
+	$name = shift @parts;
+        # get fieldname in canonical form - first cap, then lower case.
+	$name =~ tr/A-Z/a-z/;
+        # uppercase the first character according to the current locale
+	$name=~s/(.+)/\u$1/;
+	next unless $name;
+	next unless ($raw{$name});
+
+	# Find the value of that metadata
+	$value = join(":", @parts);
+	$value =~ s/^\s+//;
+	$value =~ s/\s+$//;
+	# decode headers if stored using =?<charset>?[BQ]?<data>?= (rfc2047)
+	if ($value =~ /=\?.*\?[BbQq]\?.*\?=/) {
+	    my $original_value=$value;
+	    my $encoded=$value;
+	    $value="";
+	    # we should ignore spaces between consecutive encoded-texts
+	    $encoded =~ s@\?=\s+=\?@\?==\?@g;
+	    while ($encoded =~ s/(.*?)=\?([^\?]*)\?([bq])\?([^\?]+)\?=//i) {
+		my ($charset, $encoding, $data)=($2,$3,$4);
+		my ($decoded_data);
+		$value.="$1"; # any leading chars
+		$data=~s/^\s*//; $data=~s/\s*$//; # strip whitespace from ends
+		chomp $data;
+		$encoding =~ tr/BQ/bq/;
+		if ($encoding eq "q") { # quoted printable
+		    $data =~ s/_/\ /g;  # from rfc2047 (sec 4.2.2)
+		    $decoded_data=qp_decode($data);
+		    # qp_decode adds \n, which is default for body text
+		    chomp($decoded_data);
+		} else { # base 64
+		    $decoded_data=base64_decode($data);
+		}
+		$self->convert2unicode($charset, \$decoded_data);
+		$value .= $decoded_data;
+	      } # end of while loop
+	    
+	    # get any trailing characters
+	    $self->convert2unicode($default_header_encoding, \$encoded);
+	    $value.=$encoded;
+
+	    if ($value =~ /^\s*$/) { # we couldn't extract anything...
+	      $self->convert2unicode($default_header_encoding,
+				     \$original_value);
+	      $value=$original_value;
+	    }
+        } # end of if =?...?=
+
+        # In the absense of other charset information, assume the
+        # header is the default (usually "iso_8859_1") and convert to unicode.
+        else {
+	    $self->convert2unicode($default_header_encoding, \$value);
+	}
+	
+	# Store the metadata
+	$value =~ s@_@\\_@g; # protect against GS macro language
+	$raw{$name} = $value;
+    }
+
+    # Extract the name and e-mail address from the From metadata
+    my $frommeta = $raw{"From"};
+    my $fromnamemeta;
+    my $fromaddrmeta;
+
+    $frommeta =~ s/\s*$//;  # Remove trailing space, if any
+
+    if ($frommeta =~ m/(.+)\s*<(.+)>/) {
+	$fromnamemeta=$1;
+	$fromaddrmeta=$2;
+    } elsif ($frommeta =~ m/(.+@.+)\s+\((.*)\)/) {
+	$fromnamemeta=$2;
+	$fromaddrmeta=$1;
+    } 
+    if (!defined($fromaddrmeta)) {
+	$fromaddrmeta=$frommeta;
+    }
+    $fromaddrmeta=~s/<//; $fromaddrmeta=~s/>//;
+    # minor attempt to prevent spam-bots from harvesting addresses...
+    $fromaddrmeta=~s/@/&#64;/;
+
+    $doc_obj->add_utf8_metadata ($cursection, "FromAddr", $fromaddrmeta);
+
+    if (defined($fromnamemeta) && $fromnamemeta) { # must be > 0 long
+	$fromnamemeta =~ s/\"//g;  # remove quotes
+	$fromnamemeta =~ s/\s+$//; # remove trailing whitespace
+    }
+    else {
+	$fromnamemeta = $fromaddrmeta;
+    }
+    # if name is an address
+    $fromnamemeta =~ s/<//g; $fromnamemeta =~ s/>//g;
+    $fromnamemeta=~s/@/&#64\;/;
+    $doc_obj->add_utf8_metadata ($cursection, "FromName", $fromnamemeta);
+
+    $raw{"From"}=$frommeta;
+
+    # Process Date information
+    if ($raw{"Date"} !~ /No Date/) {
+	$raw{"DateText"} = $raw{"Date"};
+	
+	# Convert the date text to internal date format
+	$value = $raw{"Date"};
+	my ($day, $month, $year) = $value =~ /(\d?\d)\s([A-Z][a-z][a-z])\s(\d\d\d?\d?)/;
+	# make some assumptions about the year formatting...
+	# some (old) software thinks 2001 is 101, some think 2001 is 01
+	if ($year < 20) { $year += 2000; } # assume not really 1920...
+	elsif ($year < 150) { $year += 1900; } # assume not really 2150...
+	$raw{"Date"} = &sorttools::format_date($day, $month, $year);
+	
+    } else {
+	# We have not extracted a date
+	$raw{"DateText"} = "Unknown.";
+	$raw{"Date"} = "19000000";
+    }
+
+    # Add extracted metadata to document object
+    foreach my $name (keys %raw) {
+	$value = $raw{$name};
+	if ($value) {
+	    # assume subject, etc headers have no special HTML meaning.
+	    $value = &text_into_html($value);
+	    # escape [] so it isn't re-interpreted as metadata
+	    $value =~ s/\[/&#91;/g; $value =~ s/\]/&#93;/g;
+	} else {
+	    $value = "No $name field";
+	}
+	$doc_obj->add_utf8_metadata ($cursection, $name, $value);
+    }
+
+
+    # extract a message ID from the headers, if there is one, and we'll use
+    # that as the greenstone doc ID. Having a predictable ID means we can
+    # link to other messages, eg from In-Reply-To or References headers...
+    if ($Headers =~ m@^Message-ID:(.+)$@mi) {
+	my $id=escape_msg_id($1);
+	$doc_obj->{'msgid'}=$id;
+    }
+    # link to another message, if this is a reply
+    if ($Headers =~ m@^In-Reply-To:(.+)$@mi) {
+	my $id=escape_msg_id($1);
+	$doc_obj->add_utf8_metadata ($cursection, 'InReplyTo', $id);
+    } elsif ($Headers =~ m@^References:.*\s([^\s]+)$@mi) {
+	# References can have multiple, get the last one
+	my $id=escape_msg_id($1);
+	# not necessarily in-reply-to, but same thread...
+	$doc_obj->add_utf8_metadata ($cursection, 'InReplyTo', $id);
+    }
+
+
+
+    my $mimetype="text/plain";
+    my $mimeinfo="";
+    my $charset = $default_header_encoding;
+    # Do MIME and encoding stuff. Allow \s in mimeinfo in case there is
+    # more than one parameter given to Content-type.
+    # eg: Content-type: text/plain; charset="us-ascii"; format="flowed"
+    if ($Headers =~ m@^content\-type:\s*([\w\.\-/]+)\s*(\;\s*.+)?\s*$@mi)
+	{
+	    $mimetype=$1;
+	    $mimetype =~ tr/[A-Z]/[a-z]/;
+
+	    if ($mimetype eq "text") { # for pre-RFC2045 messages (c. 1996)
+		$mimetype = "text/plain";
+	    }
+
+	    $mimeinfo=$2;
+	    if (!defined $mimeinfo) {
+		$mimeinfo="";
+	    } else { # strip leading and trailing stuff
+		$mimeinfo =~ s/^\;\s*//;
+		$mimeinfo =~ s/\s*$//;
+	    }
+	    if ($mimeinfo =~ /charset=\"([^\"]+)\"/i) {
+	      $charset = $1;
+	    }
+	}
+
+    my $transfer_encoding="7bit";
+    if ($Headers =~ /^content-transfer-encoding:\s*([^\s]+)\s*$/mi) {
+	$transfer_encoding=$1;
+    }
+
+    if ($mimetype eq "text/html") {
+	$$textref= $self->text_from_part($$textref, $Headers);
+    } elsif ($mimetype ne "text/plain") {
+	$self->{'doc_obj'} = $doc_obj; # in case we need to associate files...
+	$$textref=$self->text_from_mime_message($mimetype,$mimeinfo,$$textref);
+    } else { # mimetype eq text/plain
+
+	if ($transfer_encoding =~ /quoted\-printable/) {
+	    $$textref=qp_decode($$textref);
+	} elsif ($transfer_encoding =~ /base64/) {
+	    $$textref=base64_decode($$textref);
+	}
+	$self->convert2unicode($charset, $textref);
+
+	$$textref = &text_into_html($$textref);
+	$$textref =~ s@_@\\_@g; # protect against GS macro language
+
+    }
+
+    
+    if ($self->{'headers'} && $self->{'headers'} == 1) {
+	# Add "All headers" metadata
+	$Headers = &text_into_html($Headers);
+
+	$Headers = "No headers" unless ($Headers =~ /\w/);
+	$Headers =~ s/@/&#64\;/g;
+	# escape [] so it isn't re-interpreted as metadata
+	$Headers =~ s/\[/&#91;/g; $Headers =~ s/\]/&#93;/g;
+	$self->convert2unicode($charset, \$Headers);
+
+	$Headers =~ s@_@\\_@g; # protect against GS macro language
+	$doc_obj->add_utf8_metadata ($cursection, "Headers", $Headers);
+    }
+
+
+    # Add Title metadata
+    my $Title = text_into_html($raw{'Subject'});
+    $Title .= "<br>From: " . text_into_html($fromnamemeta);
+    $Title .= "<br>Date: " . text_into_html($raw{'DateText'});
+    $Title =~ s/\[/&#91;/g; $Title =~ s/\]/&#93;/g;
+
+    $doc_obj->add_utf8_metadata ($cursection, "Title", $Title);
+	
+    # Add FileFormat metadata
+    $doc_obj->add_metadata($cursection, "FileFormat", "EMAIL");
+
+    # Add text to document object
+    $$textref = "No message" unless ($$textref =~ /\w/);
+
+    $doc_obj->add_utf8_text($cursection, $$textref);
+
+    return 1;
+}
+
+
+# Convert a text string into HTML.
+#
+# The HTML is going to be inserted into a GML file, so 
+# we have to be careful not to use symbols like ">",
+# which ocurs frequently in email messages (and use
+# &gt instead.
+#
+# This function also turns links and email addresses into hyperlinks,
+# and replaces carriage returns with <BR> tags (and multiple carriage
+# returns with <P> tags).
+
+
+sub text_into_html {
+    my ($text) = @_;
+
+    # Convert problem characters into HTML symbols
+    $text =~ s/&/&amp;/g;
+    $text =~ s/</&lt;/g;
+    $text =~ s/>/&gt;/g;
+    $text =~ s/\"/&quot;/g;
+
+    # convert email addresses and URIs into links
+# don't markup email addresses for now
+#    $text =~ s/([\w\d\.\-]+@[\w\d\.\-]+)/<a href=\"mailto:$1\">$1<\/a>/g;
+
+    # try to munge email addresses a little bit...
+    $text =~ s/@/&#64;/;
+    # assume hostnames are \.\w\- only, then might have a trailing '/.*'
+    # assume URI doesn't finish with a '.'
+    $text =~ s@((http|ftp|https)://[\w\-]+(\.[\w\-]+)*/?((&amp;|\.)?[\w\?\=\-_/~]+)*(\#[\w\.\-_]*)?)@<a href=\"$1\">$1<\/a>@g;
+
+
+    # Clean up whitespace and convert \n charaters to <BR> or <P>
+    $text =~ s/ +/ /g;
+    $text =~ s/\s*$//g; 
+    $text =~ s/^\s*//g;
+    $text =~ s/\n/\n<br>/g;
+    $text =~ s/<br>\s*<br>/<p>/gi;
+
+    return $text;
+}
+
+
+
+
+#Process a MIME message.
+# the textref we are given DOES NOT include the header.
+sub text_from_mime_message {
+    my $self = shift(@_);
+    my ($mimetype,$mimeinfo,$text)=(@_);
+    my $outhandle=$self->{'outhandle'};
+    # Check for multiparts - $mimeinfo will be a boundary
+    if ($mimetype =~ /multipart/) {
+	my $boundary="";
+	if ($mimeinfo =~ m@boundary=(\"[^\"]+\"|[^\s]+)\s*$@im) {
+	    $boundary=$1;
+	    if ($boundary =~ m@^\"@) {
+		$boundary =~ s@^\"@@; $boundary =~ s@\"$@@;
+	    }
+	} else {
+	    print $outhandle "EMAILPlug: (warning) couldn't parse MIME boundary\n";
+	}
+	# parts start with "--$boundary"
+	# message ends with "--$boundary--"
+	# RFC says boundary is <70 chars, [A-Za-z'()+_,-./:=?], so escape any
+	# that perl might want to interpolate. Also allows spaces...
+	$boundary=~s/\\/\\\\/g;
+	$boundary=~s/([\?\+\.\(\)\:\/\'])/\\$1/g;
+	my @message_parts = split("\r?\n\-\-$boundary", "\n$text");
+	# remove first "part" and last "part" (final --)
+	shift @message_parts;
+	my $last=pop @message_parts;
+	# if our boundaries are a bit dodgy and we only found 1 part...
+	if (!defined($last)) {$last="";}
+	# make sure it is only -- and whitespace
+	if ($last !~ /^\-\-\s*$/ms) {
+	    print $outhandle "EMAILPlug: (warning) last part of MIME message isn't empty\n";
+	}
+	foreach my $message_part (@message_parts) {
+	    # remove the leading newline left from split.
+	    $message_part=~s/^\r?\n//;
+	}
+	if ($mimetype eq "multipart/alternative") {
+	    # check for an HTML version first, then TEXT, otherwise use first.
+	    my $part_text="";
+	    foreach my $message_part (@message_parts) {
+		if ($message_part =~ m@\s*content\-type:\s*text/html@mis)
+		{
+		    # Use the HTML version
+		    $part_text= $self->text_from_part($message_part);
+		    $mimetype="text/html";
+		    last;
+		}
+	    }
+	    if ($part_text eq "") { # try getting a text part instead
+		foreach my $message_part (@message_parts) {
+		    if ($message_part =~ m@^content\-type:\s*text/plain@mis)
+		    {
+			# Use the plain version
+			$part_text= $self->text_from_part($message_part);
+			if ($part_text =~/[^\s]/) {
+			    $part_text = text_into_html($part_text);
+			}
+			$mimetype="text/plain";
+			last;
+		    }
+		}
+	    }
+	    if ($part_text eq "") { #use first part (no html/text part found)
+		$part_text = $self->text_from_part(shift @message_parts);
+		$part_text = text_into_html($part_text);
+	    }
+	    if ($part_text eq "") { # we couldn't get anything!!!
+		# or it was an empty message...
+		# do nothing...
+		gsprintf($outhandle, "{BasPlug.empty_file} - empty body?\n");
+	    } else {
+		$text = $part_text;
+	    }
+	} elsif ($mimetype =~ m@multipart/(mixed|digest|related|signed)@) {
+	    $text = "";
+	    # signed is for PGP/GPG messages... the last part is a hash
+	    if ($mimetype =~ m@multipart/signed@) {
+		pop @message_parts;
+	    }
+	    my $is_first_part=1;
+	    foreach my $message_part (@message_parts) {
+		if ($is_first_part && $text ne "") {$is_first_part=0;}
+
+		if ($mimetype eq "multipart/digest") {
+		    # default type - RTFRFC!! Set if not already set
+		    $message_part =~ m@^(.*)\n\r?\n@s;
+		    my $part_header=$1;
+		    if ($part_header !~ m@^content-type@mi) {
+			$message_part="Content-type: message/rfc822\n"
+			    . $message_part; # prepend default type
+		    }
+		}
+
+		$text .= $self->process_multipart_part($message_part,
+						       $is_first_part);
+	    } # foreach message part.
+	} else {
+	    # we can't handle this multipart type (not mixed or alternative)
+	    # the RFC also mentions "parallel".
+	}
+    } # end of ($mimetype =~ multipart)
+    elsif ($mimetype =~ m@message/rfc822@) {
+	my $msg_header = $text;
+	$msg_header =~ s/\r?\n\r?\n(.*)$//s;
+	$text = $1;
+
+	if ($msg_header =~ /^content\-type:\s*([\w\.\-\/]+)\s*\;?\s*(.+?)\s*$/mi)
+	{
+	    $mimetype=$1;
+	    $mimeinfo=$2;
+	    $mimetype =~ tr/[A-Z]/[a-z]/;
+
+	    my $msg_text;
+	    if ($mimetype =~ m@multipart/@) {
+		$msg_text = text_from_mime_message($self, $mimetype, $mimeinfo,
+						   $text);
+	    } else {
+		$msg_text=$self->text_from_part($text,$msg_header);
+	    }
+
+	    my $brief_header=text_into_html(get_brief_headers($msg_header));
+	    $text= "\n<b>&lt;&lt;attached message&gt;&gt;</b><br>";
+	    $text.= "<table><tr><td width=\"5%\"> </td>\n";
+	    $text.="<td>" . $brief_header . "\n</p>" . $msg_text 
+		. "</td></tr></table>";
+	}
+    } else {
+	# we don't do any processing of the content.
+    }
+
+    return $text;
+}
+
+
+
+# used for turning a message id into a more friendly string for greenstone
+sub escape_msg_id {
+#msgid
+    my $id=shift;
+    chomp $id; $id =~ s!\s!!g; # remove spaces
+    $id =~ s![<>\[\]]!!g; # remove [ ] < and >
+    $id =~ s![_&]!-!g; # replace symbols that might cause problems
+    $id =~ s!@!-!g; # replace @ symbol, to avoid spambots
+    return $id;
+}
+
+
+
+sub process_multipart_part {
+    my $self = shift;
+    my $message_part = shift;
+    my $is_first_part = shift;
+
+    my $return_text="";
+    my $part_header=$message_part;
+    my $part_body;
+    if ($message_part=~ /^\s*\n/) {
+	# no header... use defaults
+	$part_body=$message_part;
+	$part_header="Content-type: text/plain; charset=us-ascii";
+    } elsif ($part_header=~s/\r?\n\r?\n(.*)$//s) {
+	$part_body=$1;
+    } else {
+	# something's gone wrong...
+	$part_header="";
+	$part_body=$message_part;
+    }
+    
+    $part_header =~ s/\r?\n[\t\ ]+/ /gs; #unfold
+    my $part_content_type="";
+    my $part_content_info="";
+
+    if ($part_header =~ m@^content\-type:\s*([\w\.\-/]+)\s*(\;.*)?$@mi) {
+	$part_content_type=$1; $part_content_type =~ tr/A-Z/a-z/;
+	$part_content_info=$2;
+	if (!defined($part_content_info)) {
+	    $part_content_info="";
+	} else {
+	    $part_content_info =~ s/^\;\s*//;
+	    $part_content_info =~ s/\s*$//;
+	}
+    }
+    my $filename="";
+    if ($part_header =~ m@name=\"?([^\"\n]+)\"?@mis) {
+	$filename=$1;
+	$filename =~ s@\r?\s*$@@; # remove trailing space, if any
+    }
+    
+    # disposition - either inline or attachment.
+    # NOT CURRENTLY USED - we display all text types instead...
+    # $part_header =~ /^content\-disposition:\s*([\w+])/mis;
+    
+    # add <<attachment>> to each part except the first...
+    if (!$is_first_part) {
+	$return_text.="\n<p><hr><strong>&lt;&lt;attachment&gt;&gt;";
+	# add part info header
+	my $header_text="<br>Type: $part_content_type<br>\n";
+	if ($filename ne "") {
+	    $header_text.="Filename: $filename\n";
+	}
+	$header_text =~ s@_@\\_@g;
+	$return_text.=$header_text . "</strong></p>\n<p>\n";
+    }
+
+    if ($part_content_type =~ m@text/@)
+    {
+	my $part_text= $self->text_from_part($message_part);
+	if ($part_content_type !~ m@text/(ht|x)ml@) {
+	    $part_text = text_into_html($part_text);
+	}
+	if ($part_text eq "") {
+	    $part_text = ' ';
+	}
+	$return_text .= $part_text;
+    } elsif ($part_content_type =~ m@message/rfc822@) {
+	# This is a forwarded message
+	my $message_part_headers=$part_body;
+	$message_part_headers=~s/\r?\n\r?\n(.*)$//s;
+	my $message_part_body=$1;
+	$message_part_headers =~ s/\r?\n[\t\ ]+/ /gs; #unfold
+	
+	my $rfc822_formatted_body=""; # put result in here
+	if ($message_part_headers =~
+	    /^content\-type:\s*([\w\.\-\/]+)\s*(\;.*)?$/ims)
+	{
+	    # The message header uses MIME flags
+	    my $message_content_type=$1;
+	    my $message_content_info=$2;
+	    if (!defined($message_content_info)) {
+		$message_content_info="";
+	    } else {
+		$message_content_info =~ s/^\;\s*//;
+		$message_content_info =~ s/\s*$//;
+	    }
+	    $message_content_type =~ tr/A-Z/a-z/;
+	    if ($message_content_type =~ /multipart/) {
+		$rfc822_formatted_body=
+		    $self->text_from_mime_message($message_content_type,
+						  $message_content_info,
+						  $message_part_body);
+	    } else {
+		$message_part_body=$self->text_from_part($part_body,
+							$message_part_headers);
+		$rfc822_formatted_body=text_into_html($message_part_body);
+	    }
+	} else {
+	    # message doesn't use MIME flags
+	    $rfc822_formatted_body=text_into_html($message_part_body);
+	    $rfc822_formatted_body =~ s@_@\\_@g;
+	}
+	# Add the returned text to the output
+	# don't put all the headers...
+#	$message_part_headers =~ s/^(X\-.*|received|message\-id|return\-path):.*\n//img;
+	my $brief_headers=get_brief_headers($message_part_headers);
+	$return_text.=text_into_html($brief_headers);
+	$return_text.="</p><p>\n";
+	$return_text.=$rfc822_formatted_body;
+	$return_text.="</p>\n";
+	# end of message/rfc822
+    } elsif ($part_content_type =~ /multipart/) { 
+	# recurse again
+	
+	my $tmptext= $self->text_from_mime_message($part_content_type,
+						   $part_content_info,
+						   $part_body);
+	$return_text.=$tmptext;
+    } else {
+	# this part isn't text/* or another message...
+	if ($is_first_part) {
+	    # this is the first part of a multipart, or only part!
+	    $return_text="\n<p><hr><strong>&lt;&lt;attachment&gt;&gt;";
+	    # add part info header
+	    my $header_text="<br>Type: $part_content_type<br>\n";
+	    $header_text.="Filename: $filename</strong></p>\n<p>\n";
+	    $header_text =~ s@_@\\_@g;
+	    $return_text.=$header_text;
+	}
+	
+	# save attachment by default
+	if (!$self->{'no_attachments'}
+	    && $filename ne "") { # this part has a file...
+	    my $encoding="8bit";
+	    if ($part_header =~
+		/^content-transfer-encoding:\s*(\w+)/mi ) {
+		$encoding=$1; $encoding =~ tr/A-Z/a-z/;
+	    }
+	    my $tmpdir=$ENV{'GSDLHOME'} . "/tmp";
+	    my $save_filename=$filename;
+	    
+	    # make sure we don't clobber files with same name;
+	    # need to keep state between .mbx files
+	    my $assoc_files=$self->{'assoc_filenames'};
+	    if ($assoc_files->{$filename}) { # it's been set...
+		$assoc_files->{$filename}++;
+		$filename =~ m/(.+)\.(\w+)$/;
+		my ($filestem, $ext)=($1,$2);
+		$save_filename="${filestem}_"
+		    . $assoc_files->{$filename} . ".$ext";
+	    } else { # first file with this name
+		$assoc_files->{$filename}=1;
+	    }
+	    open (SAVE, ">$tmpdir/$save_filename") ||
+		warn "EMAILPlug: Can't save attachment as $tmpdir/$save_filename: $!";
+	    my $part_text = $message_part;
+	    $part_text =~ s/(.*?)\r?\n\r?\n//s; # remove header
+	    if ($encoding eq "base64") {
+		print SAVE base64_decode($part_text);
+	    } elsif ($encoding eq "quoted-printable") {
+		print SAVE qp_decode($part_text);
+	    } else { # 7bit, 8bit, binary, etc...
+		print SAVE $part_text;
+	    }
+	    close SAVE;
+	    my $doc_obj=$self->{'doc_obj'};
+	    $doc_obj->associate_file("$tmpdir/$save_filename",
+				     "$save_filename",
+				     $part_content_type # mimetype
+				     );
+	    # clean up tmp area...
+	    # Can't do this as it hasn't been copied/linked yet!!!
+#			&util::rm("$tmpdir/$save_filename");
+	    my $outhandle=$self->{'outhandle'};
+	    print $outhandle "EMAILPlug: saving attachment \"$filename\"\n"; #
+	    
+	    # be nice if "download" was a translatable macro :(
+	    $return_text .="<a href=\"_httpdocimg_/$save_filename\">download</a>";
+	} # end of save attachment
+    } # end of !text/message part
+
+
+    return $return_text;
+}
+
+
+# Return only the "important" headers from a set of message headers
+sub get_brief_headers {
+    my $msg_header = shift;
+    my $brief_header = "";
+
+    # Order matters!
+    if ($msg_header =~ /^(From:.*)$/im) {$brief_header.="$1\n";}
+    if ($msg_header =~ /^(To:.*)$/im) {$brief_header.="$1\n";}
+    if ($msg_header =~ /^(Cc:.*)$/im) {$brief_header.="$1\n";}
+    if ($msg_header =~ /^(Subject:.*)$/im) {$brief_header.="$1\n";}
+    if ($msg_header =~ /^(Date:.*)$/im) {$brief_header.="$1\n";}
+
+    return $brief_header;
+}
+
+
+# Process a MIME part. Return "" if we can't decode it.
+# should only be called for parts with type "text/*" ?
+# Either pass the entire mime part (including the part's header),
+# or pass the mime part's text and optionally the part's header.
+sub text_from_part {
+    my $self = shift;
+    my $text = shift || '';
+    my $part_header = shift;
+
+    my $type="text/plain"; # default, overridden from part header
+    my $charset="ascii"; # default, overridden from part header
+
+    if (! $part_header) { # no header argument was given. check the body
+	$part_header = $text;
+	# check for empty part header (leading blank line)
+	if ($text =~ /^\s*\r?\n/) {
+	    $part_header="Content-type: text/plain; charset=us-ascii";
+	} else {
+	    $part_header =~ s/\r?\n\r?\n(.*)$//s;
+	    $text=$1; if (!defined($text)) {$text="";}
+	}
+	$part_header =~ s/\r?\n[\t ]+/ /gs; #unfold
+    }
+
+    if ($part_header =~
+	/content\-type:\s*([\w\.\-\/]+).*?charset=\"?([^\;\"\s]+)\"?/is) {
+	$type=$1;
+	$charset=$2;
+    }
+    my $encoding="";
+    if ($part_header =~ /^content\-transfer\-encoding:\s*([^\s]+)/mis) {
+	$encoding=$1; $encoding=~tr/A-Z/a-z/;
+    }
+    # Content-Transfer-Encoding is per-part
+    if ($encoding ne "") {
+	if ($encoding =~ /quoted\-printable/) {
+	    $text=qp_decode($text);
+	} elsif ($encoding =~ /base64/) {
+	    $text=base64_decode($text);
+	} elsif ($encoding !~ /[78]bit/) { # leave 7/8 bit as is.
+	    # rfc2045 also allows binary, which we ignore (for now).
+	    my $outhandle=$self->{'outhandle'};
+	    print $outhandle "EMAILPlug: unknown transfer encoding: $encoding\n";
+	    return "";
+	}
+    }
+    if ($type eq "text/html") {
+	# only get stuff between <body> tags, or <html> tags.
+	$text =~ s@^.*<html[^>]*>@@is;
+	$text =~ s@</html>.*$@@is;
+	$text =~ s/^.*?<body[^>]*>//si;
+	$text =~ s/<\/body>.*$//si;
+    }
+    elsif ($type eq "text/xml") {
+	$text=~s/</&lt;/g;$text=~s/>/&gt;/g;
+	$text="<pre>\n$text\n</pre>\n";
+    }
+    # convert to unicode
+    $self->convert2unicode($charset, \$text);
+    
+    $text =~ s@_@\\_@g; # protect against GS macro language
+    return $text;
+}
+
+
+
+
+# decode quoted-printable text
+sub qp_decode {
+    my $text=shift;
+
+    # if a line ends with "=\s*", it is a soft line break, otherwise
+    # keep in any newline characters.
+
+    $text =~ s/=\s*\r?\n//mg;
+    $text =~ s/=([0-9A-Fa-f]{2})/chr (hex "0x$1")/eg;
+    return $text;
+}
+
+# decode base64 text. This is fairly slow (since it's interpreted perl rather
+# than compiled XS stuff like in the ::MIME modules, but this is more portable
+# for us at least).
+# see rfc2045 for description, but basically, bits 7 and 8 are set to zero;
+# 4 bytes of encoded text become 3 bytes of binary - remove 2 highest bits
+# from each encoded byte.
+
+
+sub base64_decode {
+    my $enc_text = shift;
+# A=>0, B=>1, ..., '+'=>62, '/'=>63
+# also '=' is used for padding at the end, but we remove it anyway.
+    my $mimechars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+# map each MIME char into it's value, for more efficient lookup.
+    my %index;
+    map { $index{$_} = index ($mimechars, $_) } (split ('', $mimechars));
+# remove all non-base64 chars. eval to get variable in transliteration...
+# also remove '=' - we'll assume (!!) that there are no errors in the encoding
+    eval "\$enc_text =~ tr|$mimechars||cd";
+    my $decoded="";
+    while (length ($enc_text)>3)
+    { 
+	my $fourchars=substr($enc_text,0,4,"");
+	my @chars=(split '',$fourchars);
+	$decoded.=chr( $index{$chars[0]}        << 2 | $index{$chars[1]} >> 4);
+	$decoded.=chr( ($index{$chars[1]} & 15) << 4 | $index{$chars[2]} >> 2);
+	$decoded.=chr( ($index{$chars[2]} & 3 ) << 6 |  $index{$chars[3]});
+    } 
+# if there are any input chars left, there are either
+# 2 encoded bytes (-> 1 raw byte) left or 3 encoded (-> 2 raw) bytes left.
+    my @chars=(split '',$enc_text);
+    if (length($enc_text)) {
+	$decoded.=chr($index{$chars[0]} << 2 | (int $index{$chars[1]} >> 4));
+    } 
+    if (length($enc_text)==3) {
+	$decoded.=chr( ($index{$chars[1]} & 15) << 4 | $index{$chars[2]} >> 2);
+    }
+    return $decoded;
+}
+
+sub convert2unicode {
+  my $self = shift(@_);
+  my ($charset, $textref) = @_;
+
+  if (!$$textref) {
+      # nothing to do!
+      return;
+  }
+
+  # first get our character encoding name in the right form.
+  $charset = "iso_8859_1" unless defined $charset;
+  $charset =~ tr/A-Z/a-z/; # lowercase
+  $charset =~ s/\-/_/g;
+  if ($charset =~ /gb_?2312/) { $charset="gb" }
+  # assumes EUC-KR, not ISO-2022 !?
+  $charset =~ s/^ks_c_5601_1987/korean/;
+  if ($charset eq 'utf_8') {$charset='utf8'}
+
+  my $outhandle = $self->{'outhandle'};
+
+  if ($charset eq "utf8") {
+      # no conversion needed, but lets check that it's valid utf8
+      # see utf-8 manpage for valid ranges
+      $$textref =~ m/^/g; # to set \G
+      my $badbytesfound=0;
+      while ($$textref =~ m!\G.*?([\x80-\xff]+)!sg) {
+	  my $highbytes=$1;
+	  my $highbyteslength=length($highbytes);
+	  # replace any non utf8 complaint bytes
+	  $highbytes =~ /^/g; # set pos()
+	  while ($highbytes =~
+		 m!\G (?: [\xc0-\xdf][\x80-\xbf] | # 2 byte utf-8
+		       [\xe0-\xef][\x80-\xbf]{2} | # 3 byte
+		       [\xf0-\xf7][\x80-\xbf]{3} | # 4 byte
+		       [\xf8-\xfb][\x80-\xbf]{4} | # 5 byte
+		       [\xfc-\xfd][\x80-\xbf]{5}   # 6 byte
+		       )*([\x80-\xff])? !xg
+		 ) {
+	      my $badbyte=$1;
+	      if (!defined $badbyte) {next} # hit end of string
+	      my $pos=pos($highbytes);
+	      substr($highbytes, $pos-1, 1, "\xc2\x80");
+	      # update the position to continue searching (for \G)
+	      pos($highbytes) = $pos+1; # set to just after the \x80
+	      $badbytesfound=1;
+	  }
+	  if ($badbytesfound==1) {
+	      # claims to be utf8, but it isn't!
+	      print $outhandle "EMAILPlug: Headers claim utf-8 but bad bytes "
+		  . "detected and removed.\n";
+
+	      my $replength=length($highbytes);
+	      my $textpos=pos($$textref);
+	      # replace bad bytes with good bytes
+	      substr( $$textref, $textpos-$replength,
+		      $replength, $highbytes);
+	      # update the position to continue searching (for \G)
+	      pos($$textref)=$textpos+($replength-$highbyteslength);
+	  }
+      }
+      return;
+  }
+
+  # It appears that we can't always trust ascii text so we'll treat it
+  # as iso-8859-1 (letting characters above 0x80 through without
+  # converting them to utf-8 will result in invalid XML documents
+  # which can't be parsed at build time).
+  $charset = "iso_8859_1" if ($charset eq "us_ascii" || $charset eq "ascii");
+
+  if ($charset eq "iso_8859_1") {
+      # test if the mailer lied, and it has win1252 chars in it...
+      # 1252 has characters between 0x80 and 0x9f, 8859-1 doesn't
+      if ($$textref =~ m/[\x80-\x9f]/) {
+	  print $outhandle "EMAILPlug: Headers claim ISO charset but MS ";
+	  print $outhandle "codepage 1252 detected.\n";
+	  $charset = "windows_1252";
+      }
+  }
+  my $utf8_text=&unicode::unicode2utf8(&unicode::convert2unicode($charset,$textref));
+
+  if ($utf8_text ne "") {
+      $$textref=$utf8_text;
+  } else {
+      # we didn't get any text... unsupported encoding perhaps? Or it is
+      # empty anyway. We'll try to continue, assuming 8859-1. We could strip
+      # characters out here if this causes problems...
+      my $outhandle=$self->{'outhandle'};
+      print $outhandle "EMAILPlug: falling back to iso-8859-1\n";
+      $$textref=&unicode::unicode2utf8(&unicode::convert2unicode("iso_8859_1",$textref));
+
+  }
+}
+
+
+sub set_OID {
+    my $self = shift (@_);
+    my ($doc_obj, $id, $segment_number) = @_;
+    
+    if ( exists $doc_obj->{'msgid'} ) {
+	$doc_obj->set_OID($doc_obj->{'msgid'});
+    } else {
+	$doc_obj->set_OID("$id\_$segment_number");
+    }
+}
+
+
+# Perl packages have to return true if they are run.
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ExcelPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ExcelPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ExcelPlug.pm	(revision 10506)
@@ -0,0 +1,110 @@
+###########################################################################
+#
+# ExcelPlug.pm -- plugin for importing Microsoft Excel files.
+#  (currently only versions 95 and 97)
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2002 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 ExcelPlug;
+
+use ConvertToPlug;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @ExcelPlug::ISA = ('ConvertToPlug');
+}
+
+my $arguments = 
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() }
+      ];
+
+my $options = { 'name'     => "ExcelPlug",
+		'desc'     => "{ExcelPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+    
+    my $self = (defined $hashArgOptLists)? new ConvertToPlug($pluginlist,$inputargs,$hashArgOptLists): new ConvertToPlug($pluginlist,$inputargs);
+
+    my $secondary_plugin_options = $self->{'secondary_plugin_options'};
+    if (!defined $secondary_plugin_options->{'HTMLPlug'}) {
+	$secondary_plugin_options->{'HTMLPlug'} = [];
+    }
+    my $html_options = $secondary_plugin_options->{'HTMLPlug'};
+    
+    #$self->{'input_encoding'} = "utf8";
+    #$self->{'extract_language'} = 1;
+    push(@$html_options, "-input_encoding", "utf8");
+    push(@$html_options,"-extract_language");
+    $self = bless $self, $class;
+    
+    $self->load_secondary_plugins($class,$secondary_plugin_options,$hashArgOptLists);
+    return bless $self;    
+}
+
+sub convert_post_process
+{
+    my $self = shift (@_);
+    my ($conv_filename) = @_;
+    
+    my $outhandle=$self->{'outhandle'};
+    
+    my ($language, $encoding) = $self->textcat_get_language_encoding ($conv_filename);
+    
+    # read in file ($text will be in utf8)
+    my $text = "";
+    $self->read_file ($conv_filename, $encoding, $language, \$text);
+    
+    # turn any high bytes that aren't valid utf-8 into utf-8.
+    #unicode::ensure_utf8(\$text);
+    
+    # Write it out again!
+    #$self->utf8_write_file (\$text, $conv_filename);
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+    return q^(?i)\.xls$^;
+}
+    
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+
+    return $self->process_type("xls",$base_dir,$file,$doc_obj);
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/FOXPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/FOXPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/FOXPlug.pm	(revision 10506)
@@ -0,0 +1,295 @@
+###########################################################################
+#
+# FOXPlug.pm
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# plugin to process a Foxbase dbt file. This plugin provides the basic
+# functionality to read in the dbt and dbf files and process each record.
+# This general plugin should be overridden for a particular database to process
+# the appropriate fields in the file.
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package FOXPlug;
+
+use BasPlug;
+use util;
+use doc;
+use unicode;
+use cnseg;
+# use gb;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+
+sub BEGIN {
+    @FOXPlug::ISA = ('BasPlug');
+}
+
+my $arguments = [
+		 ];
+
+my $options = { 'name'     => "FOXPlug",
+		'desc'     => "{FOXPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes" };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 0; # this is not a recursive plugin
+}
+
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    my $fullname = &util::filename_cat ($base_dir, $file);
+
+    # dbt files are processed at the same time as dbf files
+    return 0 if ($fullname =~ /\.dbt$/i);
+
+    # see if this is a foxbase database
+    return undef unless (-f $fullname && $fullname =~ /\.dbf$/i);
+
+    my ($parent_dir) = $fullname =~ /^(.*)\/[^\/]+\.dbf$/i;
+
+    # open the file
+    if (!open (FOXBASEIN, $fullname)) {
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file' r='Could not read $fullname'>\n";
+	}
+	print STDERR "FOXPlug::read - couldn't read $fullname\n";
+	return -1; # error in processing
+    }
+
+    print STDERR "<Processing n='$file' p='FOXPlug'>\n" if ($gli);
+    
+    print STDERR "FOXPlug: processing $file\n";
+
+    # read in the database header
+    my ($temp, %dbf);
+    
+    # read in information about dbt file
+    if (read (FOXBASEIN, $temp, 32) < 32) {
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file' r='EOF while reading database header'>\n";
+	}
+	print STDERR "FOXPlug::read - eof while reading database header\n";
+	close (FOXBASEIN);
+	return -1;
+    }
+    
+    # unpack the header
+    ($dbf{'hasdbt'},
+     $dbf{'modyear'}, $dbf{'modmonth'}, $dbf{'modday'},
+     $dbf{'numrecords'}, $dbf{'headerlen'}, 
+     $dbf{'recordlen'}) = unpack ("CCCCVvv", $temp);
+    
+    # process hasdbt
+    if ($dbf{'hasdbt'} == 131) {
+	$dbf{'hasdbt'} = 1;
+    } elsif ($dbf{'hasdbt'} == 3 || $dbf{'hasdbt'} == 48) {
+	$dbf{'hasdbt'} = 0;
+    } else {
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file' r='Does not seem to be a Foxbase file'>\n";
+	}
+	print STDERR "FOXPlug:read - $fullname doesn't seem to be a Foxbase file\n";
+	return -1;
+    }
+
+    # read in the field description
+    $dbf{'numfields'} = 0;
+    $dbf{'fieldinfo'} = [];
+    while (read (FOXBASEIN, $temp, 1) > 0) {
+	last if ($temp eq "\x0d");
+	last if (read (FOXBASEIN, $temp, 31, 1) < 31);
+
+	my %field = ();
+	$field{'name'} = $self->extracttext($temp, 11);
+	($field{'type'}, $field{'pos'}, $field{'len'}, $field{'dp'}) 
+	    = unpack ("x11a1VCC", $temp);
+
+	push (@{$dbf{'fieldinfo'}}, \%field);
+
+	$dbf{'numfields'} ++;
+    }
+
+    # open the dbt file if we need to
+    my $dbtfullname = $fullname;
+    if ($fullname =~ /f$/) {
+	$dbtfullname =~ s/f$/t/;
+    } else {
+	$dbtfullname =~ s/F$/T/;
+    }
+    if ($dbf{'hasdbt'} && !open (DBTIN, $dbtfullname)) {
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file' r='Could not read $dbtfullname'>\n";
+	}
+	print STDERR "FOXPlug::read - couldn't read $dbtfullname\n";
+	close (FOXBASEIN);
+	return -1;
+    }
+
+    # read in and process each record in the database
+    my $numrecords = 0;
+    while (($numrecords < $dbf{'numrecords'}) && 
+	   (read (FOXBASEIN, $temp, $dbf{'recordlen'}) == $dbf{'recordlen'})) {
+
+	# create a new record
+	my $record = [];
+	
+	foreach my $field (@{$dbf{'fieldinfo'}}) {
+	    my $fieldvalue = "";
+	    
+	    if ($field->{'type'} eq "M" && $dbf{'hasdbt'}) {
+		# a memo field, look up this field in the dbt file
+		my $seekpos = substr ($temp, $field->{'pos'}, $field->{'len'});
+
+		$seekpos =~ s/^\s*//;
+		$seekpos = 0 unless $seekpos =~ /^\d+$/;
+		
+		$seekpos = $seekpos * 512;
+
+		if ($seekpos == 0) {
+		    # there is no memo field
+
+		} elsif (seek (DBTIN, $seekpos, 0)) {
+		    while (read (DBTIN, $fieldvalue, 512, length($fieldvalue)) > 0) {
+			last if ($fieldvalue =~ /\cZ/);
+		    }
+
+		    # remove everything after the control-Z
+		    substr($fieldvalue, index($fieldvalue, "\cZ")) = "";
+
+		} else {
+		    print STDERR "\nERROR - seek (to $seekpos) failed\n";
+		}
+
+	    } else {
+		# a normal field
+		$fieldvalue = substr ($temp, $field->{'pos'}, $field->{'len'});
+	    }
+
+	    push (@$record, {%$field, 'value'=>$fieldvalue});
+	}
+
+	# process this record
+	$self->process_record ($pluginfo, $base_dir, $file, $metadata, $processor, 
+			       $numrecords, $record);
+	
+	# finished another record...
+	$numrecords++;
+    }
+
+    # close the dbt file if we need to
+    if ($dbf{'hasdbt'}) {
+	close (DBTIN);
+    }
+
+    # close the dbf file
+    close (FOXBASEIN);
+
+    # finished processing
+    return 1;
+}
+
+
+# will extract a string from some larger string, making it
+# conform to a number of constraints
+sub extracttext {
+    my $self = shift (@_);
+    my ($text, $maxlen, $offset, $stopstr) = @_;
+    $offset = 0 unless defined $offset;
+    $stopstr = "\x00" unless defined $stopstr;
+    
+    # decide where the string finishes
+    my $end = index ($text, $stopstr, $offset);
+    $end = length ($text) if $end < 0;
+    $end = $offset+$maxlen if (defined $maxlen) && ($end-$offset > $maxlen);
+    
+    return "" if ($end <= $offset);
+    return substr ($text, $offset, $end-$offset);
+}
+
+
+# process_record should be overriden for a particular type
+# of database. This default version outputs an html document
+# containing all the fields in the record as a table.
+# It also assumes that the text is in utf-8.
+sub process_record {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $numrecords, $record) = @_;
+
+    # create a new document
+    my $doc_obj = new doc ($file, "indexed_doc");
+    $doc_obj->set_OIDtype ($processor->{'OIDtype'});
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+    my $section = $doc_obj->get_top_section();
+
+    $doc_obj->add_metadata($section, "FileFormat", "FOX");
+    $doc_obj->add_metadata($section, "FileSize",   (-s $file));
+
+    # start of document
+    $doc_obj->add_utf8_text($section, "<table>\n");
+
+    # add each field
+    foreach my $field (@$record) {
+	if (defined ($field->{'name'}) && defined ($field->{'value'})) {
+	    $doc_obj->add_utf8_text($section, "  <tr>\n");
+	    $doc_obj->add_utf8_text($section, "    <td>$field->{'name'}</td>\n");
+	    $doc_obj->add_utf8_text($section, "    <td>$field->{'value'}</td>\n");
+	    $doc_obj->add_utf8_text($section, "  </tr>\n");
+	}
+    }
+
+    # end of document
+    $doc_obj->add_utf8_text($section, "</table>\n");
+
+    # add an object id
+    $doc_obj->set_OID();
+
+    # process the document
+    $processor->process($doc_obj);
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/FavouritesPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/FavouritesPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/FavouritesPlug.pm	(revision 10506)
@@ -0,0 +1,113 @@
+###########################################################################
+#
+# FavouritesPlug.pm -- Plugin for Internet Explorer Favourites files
+#                      By Stephen De Gabrielle
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2005 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+# hacked together by Stephen De Gabrielle from various plugins 
+# especially SRCPlug by John McPherson Nov 2000
+
+package FavouritesPlug;
+
+use BasPlug;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @FavouritesPlug::ISA = ('BasPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "FavouritesPlug",
+		'desc'     => "FavouritesPlug imports Internet Explorer style Favourites. Favourites are often found in the \"C:\\Documents and Settings\\[your username]\\Favorites\" folder on your computer, but can also be made by dragging a bookmark or location from your browser (any) to the desktop.",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift(@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+
+sub get_default_process_exp
+{
+    # URL is extension for single bookmarks under windows.
+    return q^(?i)\.URL$^;
+}
+
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $section = $doc_obj->get_top_section();
+    print STDERR "<Processing n='$file' p='FavouritesPlug'>\n" if ($gli);
+    print $outhandle "FavouritesPlug: processing $file\n" if $self->{'verbosity'} > 1;
+
+    # don't want mg to turn escape chars into actual values
+    $$textref =~ s/\\/\\\\/g;
+
+    # use filename (minus the .url extension) as the title
+    my $title = $file;
+    $title =~ s/.url$//i;
+    $doc_obj->add_utf8_metadata($section, "Title", $title);
+
+    # get the URL from the file
+    my ($url) = ($$textref =~ m/^URL=(http.+)/mg);
+    $doc_obj->add_metadata($section, "URL", $url);
+
+    # Add srclink metadata for an automatic link to the webpage
+    $doc_obj->add_utf8_metadata($section, "srclink", "<a href=\"$url\">");
+    $doc_obj->add_utf8_metadata($section, "srcicon", "_iconworld_");
+    $doc_obj->add_utf8_metadata($section, "/srclink", "</a>");
+
+    # Tidy up the favourite text to look a bit nicer
+    $$textref =~ s/^\\n/<p>/g;
+    $$textref =~ s/\[/<p><strong>/g;
+    $$textref =~ s/\]/<\/strong><p>/g;
+    $$textref =~ s/^Modified=(.+)$/<strong>Modified<\/strong>$1<p>/g;
+    $doc_obj->add_utf8_text($section, "$$textref");
+
+    $doc_obj->add_metadata($section, "FileFormat", "Favourite");
+    return 1;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/GAPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/GAPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/GAPlug.pm	(revision 10506)
@@ -0,0 +1,197 @@
+###########################################################################
+#
+# GAPlug.pm
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001 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.
+#
+###########################################################################
+
+# Processes GreenstoneArchive XML documents. Note that this plugin does no
+# syntax checking (though the XML::Parser module tests for
+# well-formedness). It's assumed that the GreenstoneArchive files conform
+# to their DTD.
+
+package GAPlug;
+
+use XMLPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @GAPlug::ISA = ('XMLPlug');
+}
+
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)doc\.xml$^;
+}
+
+my $arguments = [
+		 ];
+
+my $options = { 'name'     => "GAPlug",
+		'desc'     => "{GAPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes" };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new XMLPlug($pluginlist,$inputargs,$hashArgOptLists): new XMLPlug($pluginlist,$inputargs);
+
+    $self->{'section'} = "";
+    $self->{'section_level'} = 0;
+    $self->{'metadata_name'} = "";
+    $self->{'metadata_value'} = "";
+    $self->{'content'} = "";
+   
+    return bless $self, $class;
+}
+
+sub xml_start_document {
+}
+
+sub xml_end_document {
+}
+
+sub xml_doctype {
+    my $self = shift(@_);
+
+    my ($expat, $name, $sysid, $pubid, $internal) = @_;
+
+    # allow the short-lived and badly named "GreenstoneArchive" files to be processed
+    # as well as the "Archive" files which should now be created by import.pl
+    die "" if ($name !~ /^(Greenstone)?Archive$/);
+
+    my $outhandle = $self->{'outhandle'};
+    print $outhandle "GAPlug: processing $self->{'file'}\n" if $self->{'verbosity'} > 1;
+    print STDERR "<Processing n='$self->{'file'}' p='GAPlug'>\n" if $self->{'gli'};
+
+}
+
+
+sub xml_start_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+
+    $self->{'element'} = $element;
+    if ($element eq "Section") {
+	if ($self->{'section_level'} == 0) {
+	    $self->open_document();
+       	} else {
+	    my $doc_obj = $self->{'doc_obj'};
+	    $self->{'section'} = 
+		$doc_obj->insert_section($doc_obj->get_end_child($self->{'section'}));
+	}
+	
+	$self->{'section_level'} ++;
+    }
+    elsif ($element eq "Metadata") {
+	$self->{'metadata_name'} = $_{'name'};
+    }
+}
+
+sub xml_end_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+
+    if ($element eq "Section") {
+	$self->{'section_level'} --;
+	$self->{'section'} = $self->{'doc_obj'}->get_parent_section ($self->{'section'});
+	$self->close_document() if $self->{'section_level'} == 0;
+    }
+    elsif ($element eq "Metadata") {
+	$self->{'doc_obj'}->add_utf8_metadata($self->{'section'}, $self->{'metadata_name'},$self->{'metadata_value'});
+	$self->{'metadata_name'} = "";
+	$self->{'metadata_value'} = "";
+    }
+    elsif ($element eq "Content" && $self->{'content'} ne "") {
+	$self->{'doc_obj'}->add_utf8_text($self->{'section'}, $self->{'content'});
+	$self->{'content'} = "";
+    }
+    
+    $self->{'element'} = "";
+}
+
+sub xml_text {
+    my $self = shift(@_);
+    my ($expat) = @_;
+
+    if ($self->{'element'} eq "Metadata") {
+	$self->{'metadata_value'} .= $_;
+    }
+    elsif ($self->{'element'} eq "Content") {
+	$self->{'content'} .= $_;
+    }
+}
+
+sub open_document {
+    my $self = shift(@_);
+
+    # create a new document
+    $self->{'doc_obj'} = new doc ();
+    $self->{'section'} = "";
+}
+
+sub close_document {
+    my $self = shift(@_);
+    
+    # add the associated files
+    my $assoc_files = 
+	$self->{'doc_obj'}->get_metadata($self->{'doc_obj'}->get_top_section(), "gsdlassocfile");
+
+    # for when "assocfilepath" isn't the same directory that doc.xml is in...
+    my $assoc_filepath_list= $self->{'doc_obj'}->get_metadata($self->{'doc_obj'}->get_top_section(), "assocfilepath");
+
+    my $assoc_filepath=shift (@$assoc_filepath_list);
+    if (defined ($assoc_filepath)) {
+	# make absolute rather than relative...
+	$self->{'filename'} =~ m@^(.*[\\/]archives)@;
+	$assoc_filepath = "$1/$assoc_filepath/";
+    } else {
+	$assoc_filepath = $self->{'filename'};
+	$assoc_filepath =~ s/[^\\\/]*$//;
+    }
+
+    foreach my $assoc_file_info (@$assoc_files) {
+	my ($assoc_file, $mime_type, $dir) = split (":", $assoc_file_info);
+	my $real_dir = &util::filename_cat($assoc_filepath, $assoc_file),
+	my $assoc_dir = (defined $dir && $dir ne "") 
+	    ? &util::filename_cat($dir, $assoc_file) : $assoc_file;
+	$self->{'doc_obj'}->associate_file($real_dir, $assoc_dir, $mime_type);
+    }
+    $self->{'doc_obj'}->delete_metadata($self->{'doc_obj'}->get_top_section(), "gsdlassocfile");
+
+    # process the document
+    $self->{'processor'}->process($self->{'doc_obj'}, $self->{'file'});
+}
+
+
+1;
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/GISBasPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/GISBasPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/GISBasPlug.pm	(revision 10506)
@@ -0,0 +1,300 @@
+###########################################################################
+#
+# GISBasPlug.pm -- base class to enhance plugins with GIS capabilities
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package GISBasPlug;
+
+use util;
+use locale;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+#field categories in DataBase files
+#$LAT = 3;
+#$LONG = 4;
+my $FC = 9;
+my $DSG = 10;
+#$CC1 = 12;
+my $FULL_NAME = 22;
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+}
+
+
+use BasPlug; # uses BasPlug, but is not inherited
+
+
+my $options = { 'name'     => "GISBasPlug",
+		'desc'     => "{GISBasPlug.desc}",
+		'abstract' => "yes",
+		'inherits' => "no" };
+
+
+sub new {
+    my $class = shift (@_);
+    my $plugin_name = shift (@_);
+
+    my $self = {};
+    $self->{'plugin_type'} = "GISBasPlug";
+
+    $self->{'option_list'} = [ $options ];
+
+    return bless $self, $class;
+}
+
+sub init {
+}
+
+sub print_xml_usage
+{
+    BasPlug::print_xml_usage(@_);
+}
+
+sub print_xml
+{
+    BasPlug::print_xml(@_);
+}
+
+sub print_txt_usage
+{
+   BasPlug::print_txt_usage(@_);
+}
+
+sub set_keepold
+{
+    BasPlug::set_keepold(@_);
+}
+
+sub has_mapdata
+{
+    my $db_dir = &util::filename_cat($ENV{'GSDLHOME'}, "lamp", "data");
+    return ( -d $db_dir );
+}
+
+
+#returns a hash table of names from database files (specified in collect.cfg). 
+sub loadGISDatabase {
+    my ($outhandle,$datasets) = @_;
+    my @dbase = map{$_ = $_ . ".txt";} split(/,/, $datasets);
+    if(scalar(@dbase)==0) { #default is to include all databases
+	@dbase=("UK.txt", "NZ.txt", "NF.txt", "CA.txt", "AS.txt", "GM.txt", "BE.txt", "IN.txt", "JA.txt", "USA.txt");
+    }
+    my $counter=0;
+    my %places = ();
+    my @cats = ();	
+    while($counter <= $#dbase){ #loop through all the databases
+	my $folder = $dbase[$counter];
+	$folder =~ s/(.*?)\.txt/$1/;
+####		my $dbName = &util::filename_cat($ENV{'GSDLHOME'}, "etc", "mapdata", "data", $folder, $dbase[$counter]);
+	my $dbName = &util::filename_cat($ENV{'GSDLHOME'}, "lamp", "data", $folder, $dbase[$counter]);
+	if (!open(FILEIN, "<$dbName")) {
+	    print $outhandle "Unable to open database $dbName: $!\n";
+	    return undef;
+	}
+	
+	my $line = <FILEIN>; #database category details.
+	my @catdetails = split("\t", $line);
+	
+	while ( defined($line = <FILEIN>)){ #stores all place names in file as keys in hash array %places
+	    @cats = split("\t", $line);
+	    if( #eliminating "bad" place names without missing real ones
+		($cats[$FC] eq "A" && !($cats[$DSG] =~ /ADMD|ADM2|PRSH/))
+		||($cats[$FC] eq "P" && ($cats[$DSG] =~ /PPLA|PPLC|PPLS/)) 
+		||($cats[$FC] eq "H" && ($cats[$DSG] =~ /BAY|LK/)) 
+		||($cats[$FC] eq "L" && !($cats[$DSG] =~ /LCTY|RGN/)) 
+		||($cats[$FC] eq "T" && ($cats[$DSG] =~ /CAPE|ISL|GRGE/))
+		||($dbase[$counter] eq "USA.txt" && ($cats[$DSG] =~ /ppl|island/))
+		){$places{$cats[$FULL_NAME]} = [@cats];}
+			@cats = ();	
+	}	
+	close(FILEIN);
+	$counter++;	
+    }	
+    return \%places;
+}
+
+#returns a unique hash array of all the places found in a document, along with coordinates, description and country data
+sub getPlaces {
+    my $self = shift @_;
+
+    my ($textref, $places) = @_;
+	my %tempPlaces = ();	
+	
+	foreach my $plc (%$places){ #search for an occurrence of each place in the text
+		if($$textref =~ m/(\W)$plc(\W)/){
+			$tempPlaces{$plc} = $places->{$plc};
+		}
+	}
+	#make sure each place is only there once
+	my %uniquePlaces = ();
+	foreach my $p (keys %tempPlaces) {	
+		if(!defined($uniquePlaces{$p})){
+			$uniquePlaces{$p} = $tempPlaces{$p};
+		}
+	}
+	return \%uniquePlaces;
+}
+
+
+
+
+#returns a lowercase version of the place, with no spaces
+sub placename_to_anchorname {
+	my ($placename) = @_;
+	my $p_tag = lc($placename);
+	$p_tag =~ s/\s+//g;
+	return $p_tag;
+}
+
+#takes a place from the text and wraps an anchor tag, a hyperlink tag and an image tag around it
+sub anchor_wrapper {
+	my ($p, $p_counter_ref, $path) = @_;
+	my $image = "/gsdlgis/gisimages/nextplace.gif";
+	my $endTag = "</a>";
+	my $hrefTag = "<a href=";
+	$$p_counter_ref++;
+	my $next = $$p_counter_ref + 1;
+	my $p_tag = placename_to_anchorname($p);
+	my $place_anchor = "<a name=\"" . $p_tag . $$p_counter_ref . "\">" . $endTag; 
+	my $popup_anchor = $hrefTag . "'" . $path . "'>" . $p . $endTag;
+	my $image_anchor = $hrefTag . "#" . $p_tag . $next . "><img src=\"" . $image . "\" name=\"img" . $p_tag . $$p_counter_ref . "\" border=\"0\">" . $endTag;
+	return $place_anchor . $popup_anchor . $image_anchor;
+}
+
+#takes dangerous place names and checks if they are part of another placename or not.
+sub place_name_check {
+	my ($pre, $preSpace, $p, $postSpace, $post, $p_counter_ref, $path, $y) = @_;
+	if($pre =~ /$y/ || $post =~ /$y/) {return $pre . $preSpace . $p . $postSpace . $post;}
+	$pre = $pre . $preSpace;
+	$post = $postSpace . $post;
+	return $pre . &anchor_wrapper("", $p, "", $p_counter_ref, $path) . $post;
+}
+
+sub extract_placenames {
+    my $self = shift (@_);
+    my ($textref, $doc_obj, $thissection) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $GSDLHOME = $ENV{'GSDLHOME'};
+    #field categories in DataBase file for extract_placenames.
+    my $LAT = 3;
+    my $LONG = 4;
+    my $CC1 = 12;
+
+    
+    &gsprintf($outhandle, " {BasPlug.extracting_placenames}...\n")
+	if ($self->{'verbosity'} > 2);
+
+    #get all the places found in the document	
+    my $uniquePlaces = $self->getPlaces($textref, $self->{'places'});
+       
+    #finds 'dangerous' placenames (eg York and New York). Dangerous because program will find "York" within "New York"  
+    my %danger = ();    
+    foreach my $x (keys %$uniquePlaces){
+	foreach my $y (keys %$uniquePlaces){
+		if(($y =~ m/ /) && ($y =~ m/$x/) && ($y ne $x)){
+			$y =~ s/($x\s)|(\s$x)//;
+			$danger{$x} = $y;
+		}
+	}
+    }  
+      
+    #creates a list of clickable placenames at top of page, linked to first occurrence of name, and reads them into a file 
+    my $tempfname = $doc_obj;
+    $tempfname =~ s/.*\(0x(.*)\)/$1/;
+    my $names = "";
+    my $filename = "tmpfile" . $tempfname;
+    my $tempfile = &util::filename_cat($GSDLHOME, "tmp", $filename);
+    open(FOUT, ">$tempfile") || die "Unable to create a temp file: $!";	
+    foreach my $name (sort (keys %$uniquePlaces)){
+	if(!defined($danger{$name})){
+		my $name_tag = placename_to_anchorname($name);
+		print FOUT "$name\t" . $uniquePlaces->{$name}->[$LONG] . "\t" . $uniquePlaces->{$name}->[$LAT] . "\n";
+		if($self->{'place_list'}) {$names = $names . "<a href=\"#" . $name_tag . "1\">" . $name . "</a>" . "\n";}
+	}
+    }
+    close(FOUT);
+    $doc_obj->associate_file($tempfile, "places.txt", "text/plain");
+    $self->{'places_filename'} = $tempfile;
+    my %countries = ();
+    
+    foreach my $p (keys %$uniquePlaces){
+	my $place = $p;
+	$place =~ s/\s+|\n+|\r+|\t+/(\\s+)/g;
+	my $cap_place = uc($place);	
+	my $long = $uniquePlaces->{$p}->[$LONG];
+	my $lat = $uniquePlaces->{$p}->[$LAT];
+	my $country = $uniquePlaces->{$p}->[$CC1];
+	my $path = "javascript:popUp(\"$long\",\"$lat\",\"$p\",\"$country\")";
+	my $p_counter = 0;
+	
+	if(!defined($danger{$p})){	
+		#adds html tags to each place name
+		$$textref =~ s/\b($place|$cap_place)\b/&anchor_wrapper($1,\$p_counter,$path)/sge;
+	} 
+	#else {
+	#$y = $danger{$p};
+	#$$textref =~ s/(\w+)(\s+?)($place|$cap_place)(\s+?)(\w+)/&place_name_check($1,$2,$3,$4,$5,\$p_counter,$path, $y)/sge;  
+	#}
+	
+	#edits the last place's image, and removes image if place only occurres once.
+	my $p_tag = placename_to_anchorname($p);
+	$p_counter++;
+	$$textref =~ s/#$p_tag$p_counter(><img src="\/gsdl\/images\/)nextplace.gif/#${p_tag}1$1firstplace.gif/;
+	$$textref =~ s/<img src="\/gsdl\/images\/firstplace.gif" name="img$p_tag(1)" border="0">//;
+	
+	#this line removes apostrophes from placenames (they break the javascript function)
+	$$textref =~ s/(javascript:popUp.*?)(\w)'(\w)/$1$2$3/g;
+		
+	#for displaying map of document, count num of places from each country
+	if(defined($countries{$country})){$countries{$country}++;}
+	else{$countries{$country} = 1;}
+
+	#adds placename to metadata
+	$doc_obj->add_utf8_metadata ($thissection, "Placename", $p);	
+	&gsprintf($outhandle, "  {BasPlug.extracting} $p\n")
+		if ($self->{'verbosity'} > 3); 
+    }
+    #finding the country that most places are from, in order to display map of the document
+    my $max = 0;
+    my $CNTRY = "";
+    foreach my $c_key (keys %countries){
+	if($countries{$c_key} > $max){
+		$max = $countries{$c_key};
+		$CNTRY = $c_key;
+	}
+    }
+    #allows user to view map with all places from the document on it
+####    my $places_filename = &util::filename_cat($GSDLHOME, "collect", "_cgiargc_", "index", "assoc", "_thisOID_", "places.txt");
+    my $places_filename = &util::filename_cat("collect", "_cgiargc_", "index", "assoc", "_thisOID_", "places.txt");
+    my $docmap = "<a href='javascript:popUp(\"$CNTRY\",\"$places_filename\")'>View map for this document<\/a><br><br>\n";
+    $$textref = $docmap . $names . "<br>" . $$textref;
+    
+    $doc_obj->delete_text($thissection);
+    $doc_obj->add_utf8_text($thissection, $$textref);
+    &gsprintf($outhandle, " {BasPlug.done_places_extract}\n")
+	if ($self->{'verbosity'} > 2);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/GMLPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/GMLPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/GMLPlug.pm	(revision 10506)
@@ -0,0 +1,254 @@
+###########################################################################
+#
+# GMLPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# plugin which processes a GML format document
+# assumes that gml tags are all in lower-case.
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package GMLPlug;
+
+use BasPlug;
+use util;
+use doc;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @GMLPlug::ISA = ('BasPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' =>  &get_default_process_exp() } 
+    ];
+
+my $options = { 'name'     => "GMLPlug",
+		'desc'     => "{GMLPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args' => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.gml?$^;
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $filename = $file;
+    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+
+    return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+    $file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
+
+    print STDERR "<Processing n='$file' p='GMLPlug'>\n" if ($gli);
+    print $outhandle "GMLPlug: processing $file\n";
+
+    my $parent_dir = $file;
+    $parent_dir =~ s/[^\\\/]*$//;
+    $parent_dir = &util::filename_cat ($base_dir, $parent_dir);
+
+    if (!open (INFILE, $filename)) {
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file' r='Could not read $filename'>\n";
+	}
+	print $outhandle "GMLPlug::read - couldn't read $filename\n";
+	return -1;
+    }
+
+    undef $/;
+    my $gml = <INFILE>;
+    $/ = "\n";
+    close (INFILE);
+    
+    my @gml_sections = split("</gsdlsection>",$gml);
+    $gml = shift(@gml_sections);
+
+    my $no_docs = 0;
+
+    while (1) {
+	# create a new document
+	my $doc_obj = new doc ();
+	my $section = $doc_obj->get_top_section();
+
+	# process the document
+	my $firstsection = 1;
+	while (1) {
+	    my ($tags, $text) = ("", "");
+
+	    my @indenting_sections = split("<gsdlsection", $gml);
+	    shift(@indenting_sections); # skips over xml header if present
+
+	    foreach $gml (@indenting_sections) {
+
+		if ($gml =~ /^\s*([^>]*)>(.*)$/so) {
+		    $tags = $1 if defined $1;
+		    $text = &GMLPlug::_unescape_text($2);
+
+		} else {
+		    print $outhandle "GMLPlug::read - error in file $filename\n";
+		    print $outhandle "text: \"$gml\"\n";
+		    last;
+		}
+
+		# create the section (unless this is the first section)
+		if ($firstsection) {
+ 		    $firstsection = 0;
+#		    $tags =~ /gsdlsourcefilename\s*=\s*(?:\"([^\"]*)\")/o;
+#		    $src_filename = $2 || $3;
+
+		} else {
+
+		    $tags =~ s/gsdlnum\s*=\s*\"?(\d+)\"?//o;
+		    if (defined $1) {
+			$section .= ".$1";
+			$doc_obj->create_named_section($section);
+		    } else {
+			$section = $doc_obj->insert_section($doc_obj->get_end_child($section));
+		    }
+		}
+	    
+		# add the metadata
+		# could be stored as either attributes or ....
+		while ((defined $tags) && ($tags =~ s/^\s*(\S+)=\"([^\"]*)\"//o)) {
+		    $doc_obj->add_utf8_metadata($section, $1, &GMLPlug::_unescape_text($2)) 
+			if (defined $1 and defined $2);
+
+		}
+		
+		# ... or tags (xml compliant)
+		if ($text =~ m/^\s*<metadata>/)
+		{
+		    my ($metadata, $tagname, $tagvalue);
+		    ($metadata,$text) 
+			= ($text =~ m/\s*<metadata>\s*(<.*)\s*<\/metadata>(.*)$/s);
+
+		    # note: \1 refers to 1st match within regexp, so we can
+		    # handle the unescaped text here...
+		    while ((defined $metadata) 
+			   && ($metadata =~ s/<(.*?)>(.*?)<\/\1>//s))
+		    {
+			if (defined $1 && defined $2) 
+			{
+			    $tagname = $1;
+			    $tagvalue = $2;
+			    
+			    # if tagname begins with '/' it will be escaped
+			    $tagname =~ s/^&\#47;/\//;
+			    
+			    $doc_obj->add_utf8_metadata($section, $tagname, &GMLPlug::_unescape_text($tagvalue)); 
+			}
+		    }
+		}
+
+		# add the text
+
+		$doc_obj->add_utf8_text($section, $text) 
+		    if ((defined $text) && ($text ne ""));		
+	    }
+
+	    $gml = shift(@gml_sections); # get next bit of data
+	    last unless defined $gml;
+ 	    last if $section eq ""; # back to top level again (more than one document in gml file)
+	    $section = $doc_obj->get_parent_section ($section);
+	} # while (1) section level
+	
+	# add the FileFormat as the metadata
+	$doc_obj->add_metadata($doc_obj->get_top_section(), "FileFormat", "GML");
+
+	# add the associated files
+	my $assoc_files = $doc_obj->get_metadata($doc_obj->get_top_section(), "gsdlassocfile");
+	my ($assoc_file_info);
+	
+	foreach $assoc_file_info (@$assoc_files) 
+	{
+	    my ($assoc_file, $mime_type, $dir) = split (":", $assoc_file_info);
+	    my $real_dir = &util::filename_cat($parent_dir, $assoc_file),
+	    my $assoc_dir = (defined $dir && $dir ne "") 
+		? &util::filename_cat($dir, $assoc_file) : $assoc_file;
+	    $doc_obj->associate_file($real_dir, $assoc_dir, $mime_type);
+	    
+	}
+	$doc_obj->delete_metadata($doc_obj->get_top_section(), "gsdlassocfile");
+
+	# add metadata passed in from elsewhere
+	$self->extra_metadata ($doc_obj, $doc_obj->get_top_section(), $metadata);
+	
+	# do any automatic metadata extraction
+	$self->auto_extract_metadata ($doc_obj);
+
+	# assume the document has an OID already
+
+	# process the document
+	$processor->process($doc_obj, $file);
+	
+	$no_docs++;
+	last if ($maxdocs > -1 && ($total_count+$no_docs) >= $maxdocs);
+	last unless defined $gml && $gml =~ /\w/;
+    } # while(1) document level
+    
+    return $no_docs; # no of docs processed
+}
+
+sub _unescape_text {
+    my ($text) = @_;
+
+    # special characters in the gml encoding
+    $text =~ s/&lt;/</g;
+    $text =~ s/&gt;/>/g;
+    $text =~ s/&quot;/\"/g;
+    $text =~ s/&amp;/&/g; # this has to be last...
+
+    return $text;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/HBPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/HBPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/HBPlug.pm	(revision 10506)
@@ -0,0 +1,358 @@
+###########################################################################
+#
+# HBPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# plugin which processes an HTML book directory
+
+# This plugin is used by the Humanity Library collections and does not handle
+# input encodings other than ascii or extended ascii
+
+# this code is kind of ugly and could no doubt be made to run faster, by leaving
+# it in this state I hope to encourage people to make their collections use
+# HBSPlug instead ;-)
+
+# Use HBSPlug if creating a new collection and marking up files like the
+# Humanity Library collections. HBSPlug accepts all input encodings but
+# expects the marked up files to be cleaner than those used by the
+# Humanity Library collections
+
+package HBPlug;
+
+use ghtml;
+use BasPlug;
+use unicode;
+use util;
+use doc;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @HBPlug::ISA = ('BasPlug');
+}
+
+my $arguments = 
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() }
+      ];
+
+my $options = { 'name'     => "HBPlug",
+		'desc'     => "{HBPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+    my ($verbosity, $outhandle) = @_;
+
+    $self->BasPlug::init($verbosity, $outhandle);
+    $self->{'input_encoding'} = "iso_8859_1";
+
+    # this plugin only handles ascii encodings
+    if ($self->{'input_encoding'} !~ /^(iso_8859_1|ascii)$/) {
+	die "ERROR: HBPlug can handle only iso_8859_1 or ascii encodings.\n" .
+	    $self->{'input_encoding'} . " is not an acceptable input_encoding value\n";
+    } 
+}
+
+# this is included only to prevent warnings being printed out 
+# from BasPlug::init. The process_exp is not used by this plugin
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return "This plugin does not use a process_exp\n";
+}
+
+
+sub HB_read_html_file {
+    my $self = shift (@_);
+    my ($htmlfile, $text) = @_;
+
+    # load in the file
+    if (!open (FILE, $htmlfile)) {
+	my $outhandle = $self->{'outhandle'};
+	print $outhandle "ERROR - could not open $htmlfile\n";
+	return;
+    }
+
+    my $foundbody = 0;
+    $self->HB_gettext (\$foundbody, $text, "FILE");
+    close FILE;
+
+    # just in case there was no <body> tag
+    if (!$foundbody) {
+	$foundbody = 1;
+	open (FILE, $htmlfile) || return;
+	$self->HB_gettext (\$foundbody, $text, "FILE");	
+	close FILE;
+    }
+    # text is in utf8
+}
+
+# converts the text to utf8, as ghtml does that for &eacute; etc.
+sub HB_gettext {
+    my $self = shift (@_);
+    my ($foundbody, $text, $handle) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $line = "";
+    while (defined ($line = <$handle>)) {
+	# look for body tag
+	if (!$$foundbody) {
+	    if ($line =~ s/^.*<body[^>]*>//i) {
+		$$foundbody = 1;
+	    } else {
+		next;
+	    }
+	}
+	
+	# check for symbol fonts
+	if ($line =~ /<font [^>]*?face\s*=\s*\"?(\w+)\"?/i) {
+	    my $font = $1;
+	    print $outhandle "HBPlug::HB_gettext - warning removed font $font\n" 
+		if ($font !~ /^arial$/i);
+	}
+
+	$line =~ s/<\/p>//ig;   # remove </p> tags
+	$line =~ s/<\/?(body|html|font)\b[^>]*>//ig; # remove any unwanted tags
+
+	$$text .= $line;
+    }
+    #
+    if ($self->{'input_encoding'} eq "iso_8859_1") {
+	# convert to utf-8
+	$$text=&unicode::unicode2utf8(&unicode::convert2unicode("iso_8859_1", $text));
+    }
+    # convert any alphanumeric character entities to their utf-8
+    # equivalent for indexing purposes
+    &ghtml::convertcharentities ($$text);
+
+    $$text =~ s/\s+/ /g; # remove \n's
+}
+
+sub HB_clean_section {
+    my $self = shift (@_);
+    my ($section) = @_;
+
+    # remove tags without a starting tag from the section
+    my ($tag, $tagstart);
+    while ($section =~ /<\/([^>]{1,10})>/) {
+	$tag = $1;
+	$tagstart = index($section, "<$tag");
+	last if (($tagstart >= 0) && ($tagstart < index($section, "<\/$tag")));
+	$section =~ s/<\/$tag>//;
+    }
+    
+    # remove extra paragraph tags
+    while ($section =~ s/<p\b[^>]*>\s*<p\b/<p/ig) {}
+    
+    # remove extra stuff at the end of the section
+    while ($section =~ s/(<u>|<i>|<b>|<p\b[^>]*>|&nbsp;|\s)$//i) {}
+    
+    # add a newline at the beginning of each paragraph
+    $section =~ s/(.)\s*<p\b/$1\n\n<p/gi;
+    
+    # add a newline every 80 characters at a word boundary
+    # Note: this regular expression puts a line feed before
+    # the last word in each section, even when it is not
+    # needed.
+    $section =~ s/(.{1,80})\s/$1\n/g;
+    
+    # fix up the image links
+    $section =~ s/<img[^>]*?src=\"?([^\">]+)\"?[^>]*>/
+	<center><img src=\"_httpdocimg_\/$1\"><\/center><br>/ig;
+    $section =~ s/&lt;&lt;I&gt;&gt;\s*([^\.]+\.(png|jpg|gif))/
+	<center><img src=\"_httpdocimg_\/$1\"><\/center><br>/ig;
+
+    return $section;
+}
+
+
+sub shorten {
+    my $self = shift (@_);
+    my ($text) = @_;
+
+    return "\"$text\"" if (length($text) < 100);
+
+    return "\"" . substr ($text, 0, 50) . "\" ... \"" . 
+	substr ($text, length($text)-50) . "\"";
+}
+
+# if input_encoding is ascii we can call add_utf8_metadata
+# directly but if it's iso_8859_1 (the default) we need to call
+# add_metadata so that the ascii2utf8 conversion is done first
+# this should speed things up a little if processing an ascii only
+# document with input_encoding set to ascii
+sub HB_add_metadata {
+    my $self = shift (@_);
+    my ($doc_obj, $cursection, $field, $value) = @_;
+
+# All text should now be in utf-8
+#    if ($self->{'input_encoding'} eq "ascii") {
+    $doc_obj->add_utf8_metadata ($cursection, $field, $value);
+#    } else {
+#	$doc_obj->add_metadata ($cursection, $field, $value);
+#    }
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    # get the html filename and see if this is an HTML Book...
+    my $jobnumber = $file;
+    if ($file =~ /[\\\/]/) {
+	($jobnumber) = $file =~ /[\\\/]([^\\\/]+)$/;
+    }
+    return undef unless defined $jobnumber;
+    my $htmlfile = &util::filename_cat($base_dir, $file, "$jobnumber.htm");
+    return undef unless -e $htmlfile;
+
+    print STDERR "<Processing n='$file' p='HBPlug'>\n" if ($gli);
+    print $outhandle "HBPlug: processing $file\n";
+
+    # read in the file and do basic html cleaning (removing header etc)
+    my $html = "";
+    $self->HB_read_html_file ($htmlfile, \$html);
+    # html is in utf8
+
+    # create a new document
+    my $doc_obj = new doc ($file, "indexed_doc");
+    $doc_obj->set_OIDtype ($processor->{'OIDtype'});
+
+    # copy the book cover if it exists
+    my $bookcover = &util::filename_cat($base_dir, $file, "$jobnumber.jpg");
+    $doc_obj->associate_file($bookcover, "cover.jpg", "image/jpeg");
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "FileFormat", "HB");
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "FileSize", (-s $htmlfile));
+
+    my $cursection = $doc_obj->get_top_section();
+    
+    # add metadata for top level of document
+    foreach my $field (keys(%$metadata)) {
+	# $metadata->{$field} may be an array reference
+	if (ref ($metadata->{$field}) eq "ARRAY") {
+	    map { 
+		$self->HB_add_metadata ($doc_obj, $cursection, $field, $_); 
+	    } @{$metadata->{$field}};
+	} else {
+	    $self->HB_add_metadata ($doc_obj, $cursection, $field, $metadata->{$field}); 
+	}
+    }
+
+    # process the file one section at a time
+    my $curtoclevel = 1;
+    my $firstsection = 1;
+    while (length ($html) > 0) {
+	if ($html =~ s/^.*?(?:<p\b[^>]*>)?((<b>|<i>|<u>|\s)*)&lt;&lt;TOC(\d+)&gt;&gt;\s*(.*?)<p\b/<p/i) {
+	    my $toclevel = $3;
+	    my $title = $4;
+	    my $sectiontext = "";
+	    if ($html =~ s/^(.*?)((?:<p\b[^>]*>)?((<b>|<i>|<u>|\s)*)&lt;&lt;TOC\d+&gt;&gt;)/$2/i) {
+		$sectiontext = $1;
+	    } else {
+		$sectiontext = $html;
+		$html = "";
+	    }
+
+	    # remove tags and extra spaces from the title
+	    $title =~ s/<\/?[^>]+>//g;
+	    $title =~ s/^\s+|\s+$//g;
+
+	    # close any sections below the current level and
+	    # create a new section (special case for the firstsection)
+	    while (($curtoclevel > $toclevel) ||
+		   (!$firstsection && $curtoclevel == $toclevel)) {
+		$cursection = $doc_obj->get_parent_section ($cursection);
+		$curtoclevel--;
+	    }
+	    if ($curtoclevel+1 < $toclevel) {
+		print $outhandle "WARNING - jump in toc levels in $htmlfile " . 
+		    "from $curtoclevel to $toclevel\n";
+	    }
+	    while ($curtoclevel < $toclevel) {
+		$curtoclevel++;
+		$cursection = 
+		    $doc_obj->insert_section($doc_obj->get_end_child($cursection));
+	    }
+
+	    # add the metadata to this section
+	    $self->HB_add_metadata ($doc_obj, $cursection, "Title", $title);
+
+	    # clean up the section html
+	    $sectiontext = $self->HB_clean_section($sectiontext);
+
+	    # associate any files
+	    map { $doc_obj->associate_file(&util::filename_cat ($base_dir, $file, $1), $1)
+		      if /_httpdocimg_\/([^\"]+)\"/; 0; }
+	         split (/(_httpdocimg_\/[^\"]+\")/, $sectiontext);
+
+	    # add the text for this section
+# All read text should now be in utf-8
+#	    if ($self->{'input_encoding'} eq "ascii") {
+	    $doc_obj->add_utf8_text ($cursection, $sectiontext);
+#	    } else {
+#		$doc_obj->add_text ($cursection, $sectiontext);
+#	    }
+	} else {
+	    print $outhandle "WARNING - leftover text\n" , $self->shorten($html), 
+	    "\nin $htmlfile\n";
+	    last;
+	}
+	$firstsection = 0;
+    }
+
+    # add a OID
+    $doc_obj->set_OID ();
+
+    # process the document
+    $processor->process($doc_obj, &util::filename_cat($file, "$jobnumber.htm"));
+        
+    return 1; # processed the file
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/HTMLPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/HTMLPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/HTMLPlug.pm	(revision 10506)
@@ -0,0 +1,991 @@
+###########################################################################
+#
+# HTMLPlug.pm -- basic html plugin
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# 
+# Note that this plugin handles frames only in a very simple way
+# i.e. each frame is treated as a separate document. This means
+# search results will contain links to individual frames rather
+# than linking to the top level frameset.
+# There may also be some problems caused by the _parent target
+# (it's removed by this plugin)
+#
+
+package HTMLPlug;
+
+use BasPlug;
+use ghtml;
+use unicode;
+use util;
+use XMLParser;
+
+sub BEGIN {
+    @HTMLPlug::ISA = ('BasPlug');
+}
+
+use strict; # every perl program should have this!
+no strict 'refs'; # make an exception so we can use variables as filehandles
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' =>  &get_default_process_exp() },
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => 'regexp',
+	'deft' =>  &get_default_block_exp() },
+      { 'name' => "nolinks",
+	'desc' => "{HTMLPlug.nolinks}",
+	'type' => "flag" },
+      { 'name' => "keep_head",
+	'desc' => "{HTMLPlug.keep_head}",
+	'type' => "flag" },
+      { 'name' => "no_metadata",
+	'desc' => "{HTMLPlug.no_metadata}",
+	'type' => "flag" },
+      { 'name' => "metadata_fields",
+	'desc' => "{HTMLPlug.metadata_fields}",
+	'type' => "string",
+	'deft' => "Title" },
+      { 'name' => "hunt_creator_metadata",
+	'desc' => "{HTMLPlug.hunt_creator_metadata}",
+	'type' => "flag" },
+      { 'name' => "file_is_url",
+	'desc' => "{HTMLPlug.file_is_url}",
+	'type' => "flag" },
+      { 'name' => "assoc_files",
+	'desc' => "{HTMLPlug.assoc_files}",
+	'type' => "regexp",
+	'deft' => &get_default_block_exp() },
+      { 'name' => "rename_assoc_files",
+	'desc' => "{HTMLPlug.rename_assoc_files}",
+	'type' => "flag" },
+      { 'name' => "title_sub",
+	'desc' => "{HTMLPlug.title_sub}",
+	'type' => "string", 
+	'deft' => "" },
+      { 'name' => "description_tags",
+	'desc' => "{HTMLPlug.description_tags}",
+	'type' => "flag" },
+      # retain this for backward compatibility (w3mir option was replaced by
+      # file_is_url)
+      { 'name' => "w3mir",
+#	'desc' => "{HTMLPlug.w3mir}",
+	'type' => "flag",
+	'hiddengli' => "yes"},
+      { 'name' => "no_strip_metadata_html",
+	'desc' => "{HTMLPlug.no_strip_metadata_html}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no"},
+      { 'name' => "sectionalise_using_h_tags",
+	'desc' => "{HTMLPlug.sectionalise_using_h_tags}",
+	'type' => "flag" }
+      ];
+
+my $options = { 'name'     => "HTMLPlug",
+		'desc'     => "{HTMLPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+    
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+   
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+    
+    if ($self->{'w3mir'}) {
+	$self->{'file_is_url'} = 1;
+    }
+    $self->{'aux_files'} = {};
+    $self->{'dir_num'} = 0;
+    $self->{'file_num'} = 0;
+    
+    return bless $self, $class;
+}
+
+# may want to use (?i)\.(gif|jpe?g|jpe|png|css|js(?:@.*)?)$
+# if have eg <script language="javascript" src="img/lib.js@123">
+sub get_default_block_exp {
+    my $self = shift (@_);
+    
+    return q^(?i)\.(gif|jpe?g|jpe|jpg|png|css)$^;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+    
+    # the last option is an attempt to encode the concept of an html query ...
+    return q^(?i)(\.html?|\.shtml|\.shm|\.asp|\.php\d?|\.cgi|.+\?.+=.*)$^;
+}
+
+sub store_block_files
+{
+    my $self =shift (@_);
+    my ($filename) = @_;
+    my $html_fname = $filename;
+    my @file_blocks;
+    
+    my ($language, $encoding) = $self->textcat_get_language_encoding ($filename);
+
+    # read in file ($text will be in utf8)
+    my $text = "";
+    $self->read_file ($filename, $encoding, $language, \$text);
+    my $textref = \$text;
+    my $opencom = '(?:<!--|&lt;!(?:&mdash;|&#151;|--))';
+    my $closecom = '(?:-->|(?:&mdash;|&#151;|--)&gt;)';
+    $$textref =~ s/$opencom(.*?)$closecom//gs;
+
+    my $attval = "\\\"[^\\\"]+\\\"|[^\\s>]+";
+    my @img_matches = ($$textref =~ m/<img[^>]*?src\s*=\s*($attval)[^>]*>/igs);
+    my @usemap_matches = ($$textref =~ m/<img[^>]*?usemap\s*=\s*($attval)[^>]*>/igs);
+    my @link_matches = ($$textref =~ m/<link[^>]*?href\s*=\s*($attval)[^>]*>/igs);
+    my @embed_matches = ($$textref =~ m/<embed[^>]*?src\s*=\s*($attval)[^>]*>/igs);
+    my @tabbg_matches = ($$textref =~ m/<(?:table|tr|td)[^>]*?background\s*=\s*($attval)[^>]*>/igs);
+
+    foreach my $link (@img_matches, @usemap_matches, @link_matches, @embed_matches, @tabbg_matches) {
+
+	# remove quotes from link at start and end if necessary
+	if ($link=~/^\"/) {
+	    $link=~s/^\"//;
+	    $link=~s/\"$//;
+	}
+
+	$link =~ s/\#.*$//s; # remove any anchor names, e.g. foo.html#name becomes foo.html
+
+	if ($link !~ m@^/@ && $link !~ m/^([A-Z]:?)\\/) {
+	    # Turn relative file path into full path
+	    my $dirname = &File::Basename::dirname($filename);
+	    $link = &util::filename_cat($dirname, $link);
+	}
+	$link = $self->eval_dir_dots($link);
+	
+	$self->{'file_blocks'}->{$link} = 1;
+    }
+}
+
+  
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    print STDERR "<Processing n='$file' p='HTMLPlug'>\n" if ($gli);
+
+    print $outhandle "HTMLPlug: processing $file\n"
+	if $self->{'verbosity'} > 1;
+
+    if ($ENV{'GSDLOS'} =~ /^windows/i) {
+      # this makes life so much easier... perl can cope with unix-style '/'s.
+      $base_dir =~ s@(\\)+@/@g;
+      $file =~ s@(\\)+@/@g; 
+    }
+    
+    # reset per-doc stuff...
+    $self->{'aux_files'} = {};
+    $self->{'dir_num'} = 0;
+    $self->{'file_num'} = 0;
+
+    # process an HTML file where sections are divided by headings tags (H1, H2 ...)
+    # you can also include metadata in the format (X can be any number)
+    # <hX>Title<!--gsdl-metadata
+    #	<Metadata name="name1">value1</Metadata>
+    #	...
+    #	<Metadata name="nameN">valueN</Metadata>
+    #--></hX>
+    if ($self->{'sectionalise_using_h_tags'}) {
+	# description_tags should allways be activated because we convert headings to description tags
+	$self->{'description_tags'} = 1;
+
+	my $arrSections = [];
+	$$textref =~ s/<h([0-9]+)[^>]*>(.*?)<\/h[0-9]+>/$self->process_heading($1, $2, $arrSections, $file)/isge;
+
+	if (scalar(@$arrSections)) {
+	    my $strMetadata = $self->update_section_data($arrSections, -1);
+	    if (length($strMetadata)) {
+		$strMetadata = '<!--' . $strMetadata . "\n-->\n</body>";
+		$$textref =~ s/<\/body>/$strMetadata/ig;
+	    }
+	}
+    }
+
+    my $cursection = $doc_obj->get_top_section();
+
+    $self->extract_metadata ($textref, $metadata, $doc_obj, $cursection)
+	unless $self->{'no_metadata'} || $self->{'description_tags'};
+
+    # Store URL for page as metadata - this can be used for an
+    # altavista style search interface. The URL won't be valid
+    # unless the file structure contains the domain name (i.e.
+    # like when w3mir is used to download a website).
+
+    # URL metadata (even invalid ones) are used to support internal
+    # links, so even if 'file_is_url' is off, still need to store info
+
+    my $web_url = "http://$file";
+    $doc_obj->add_metadata($cursection, "URL", $web_url);
+
+    if ($self->{'file_is_url'}) {
+	$doc_obj->add_metadata($cursection, "weblink", "<a href=\"$web_url\">");
+	$doc_obj->add_metadata($cursection, "webicon", "_iconworld_");
+	$doc_obj->add_metadata($cursection, "/weblink", "</a>");
+    }
+
+    if ($self->{'description_tags'}) {
+	# remove the html header - note that doing this here means any
+	# sections defined within the header will be lost (so all <Section>
+	# tags must appear within the body of the HTML)
+	my ($head_keep) = ($$textref =~ m/^(.*?)<body[^>]*>/is);
+
+	$$textref =~ s/^.*?<body[^>]*>//is;
+	$$textref =~ s/(<\/body[^>]*>|<\/html[^>]*>)//isg;
+
+	my $opencom = '(?:<!--|&lt;!(?:&mdash;|&#151;|--))';
+	my $closecom = '(?:-->|(?:&mdash;|&#151;|--)&gt;)';
+
+	my $lt = '(?:<|&lt;)';
+	my $gt = '(?:>|&gt;)';
+	my $quot = '(?:"|&quot;|&rdquo;|&ldquo;)';
+
+	my $dont_strip = '';
+	if ($self->{'no_strip_metadata_html'}) {
+	    ($dont_strip = $self->{'no_strip_metadata_html'}) =~ s{,}{|}g;
+	}
+
+	my $found_something = 0; my $top = 1;
+	while ($$textref =~ s/^(.*?)$opencom(.*?)$closecom//s) {
+	    my $text = $1;
+	    my $comment = $2;
+	    if (defined $text) {
+		# text before a comment - note that getting to here
+		# doesn't necessarily mean there are Section tags in
+		# the document
+		$self->process_section(\$text, $base_dir, $file, $doc_obj, $cursection);
+	    }
+	    while ($comment =~ s/$lt(.*?)$gt//s) {
+		my $tag = $1;
+		if ($tag eq "Section") {
+		    $found_something = 1;
+		    $cursection = $doc_obj->insert_section($doc_obj->get_end_child($cursection)) unless $top;
+		    $top = 0;
+		} elsif ($tag eq "/Section") {
+		    $found_something = 1;
+		    $cursection = $doc_obj->get_parent_section ($cursection);
+		} elsif ($tag =~ /^Metadata name=$quot(.*?)$quot/s) {
+		    my $metaname = $1;
+		    my $accumulate = $tag =~ /mode=${quot}accumulate${quot}/ ? 1 : 0;
+		    $comment =~ s/^(.*?)$lt\/Metadata$gt//s;
+		    my $metavalue = $1;
+		    $metavalue =~ s/^\s+//;
+		    $metavalue =~ s/\s+$//;
+                    # assume that no metadata value intentionally includes
+                    # carriage returns or HTML tags (if they're there they
+                    # were probably introduced when converting to HTML from
+                    # some other format).
+		    # actually some people want to have html tags in their
+		    # metadata.
+		    $metavalue =~ s/[\cJ\cM]/ /sg;
+		    $metavalue =~ s/<[^>]+>//sg
+			unless $dont_strip && ($dont_strip eq 'all' || $metaname =~ /^($dont_strip)$/);
+		    $metavalue =~ s/\s+/ /sg;
+		    if ($accumulate) {
+			$doc_obj->add_utf8_metadata($cursection, $metaname, $metavalue);
+		    } else {
+			$doc_obj->set_utf8_metadata_element($cursection, $metaname, $metavalue);	
+		    }
+		} elsif ($tag eq "Description" || $tag eq "/Description") {
+		    # do nothing with containing Description tags
+		} else {
+		    # simple HTML tag (probably created by the conversion
+		    # to HTML from some other format) - we'll ignore it and
+		    # hope for the best ;-)
+		}
+	    }
+	}
+	if ($cursection ne "") {
+	    print $outhandle "HTMLPlug: WARNING: $file contains unmatched <Section></Section> tags\n";
+	}
+
+	$$textref =~ s/^.*?<body[^>]*>//is;
+	$$textref =~ s/(<\/body[^>]*>|<\/html[^>]*>)//isg;
+	if ($$textref =~ /\S/) {
+	    if (!$found_something) {
+		if ($self->{'verbosity'} > 2) {
+		    print $outhandle "HTMLPlug: WARNING: $file appears to contain no Section tags so\n";
+		    print $outhandle "          will be processed as a single section document\n";
+		}
+
+		# go ahead and process single-section document
+		$self->process_section($textref, $base_dir, $file, $doc_obj, $cursection);
+
+		# if document contains no Section tags we'll go ahead
+		# and extract metadata (this won't have been done
+		# above as the -description_tags option prevents it)
+		my $complete_text = $head_keep.$doc_obj->get_text($cursection);
+		$self->extract_metadata (\$complete_text, $metadata, $doc_obj, $cursection) 
+		    unless $self->{'no_metadata'};
+
+	    } else {
+		print $outhandle "HTMLPlug: WARNING: $file contains the following text outside\n";
+		print $outhandle "          of the final closing </Section> tag. This text will\n";
+		print $outhandle "          be ignored.";
+
+		my ($text);
+		if (length($$textref) > 30) {
+		    $text = substr($$textref, 0, 30) . "...";
+		} else {
+		    $text = $$textref;
+		}
+		$text =~ s/\n/ /isg;
+		print $outhandle " ($text)\n";
+	    }
+	} elsif (!$found_something) {
+
+	    if ($self->{'verbosity'} > 2) {
+		# may get to here if document contained no valid Section
+		# tags but did contain some comments. The text will have
+		# been processed already but we should print the warning
+		# as above and extract metadata
+		print $outhandle "HTMLPlug: WARNING: $file appears to contain no Section tags and\n";
+		print $outhandle "          is blank or empty.  Metadata will be assigned if present.\n";
+	    }
+
+	    my $complete_text = $head_keep.$doc_obj->get_text($cursection);
+	    $self->extract_metadata (\$complete_text, $metadata, $doc_obj, $cursection) 
+		unless $self->{'no_metadata'};
+	}
+	
+    } else {
+
+	# remove header and footer
+	if (!$self->{'keep_head'} || $self->{'description_tags'}) {
+	    $$textref =~ s/^.*?<body[^>]*>//is;
+	    $$textref =~ s/(<\/body[^>]*>|<\/html[^>]*>)//isg;
+	}
+
+	# single section document
+	$self->process_section($textref, $base_dir, $file, $doc_obj, $cursection);
+    }
+    return 1;
+}
+
+
+sub process_heading
+{
+    my ($self, $nHeadNo, $strHeadingText, $arrSections, $file) = @_;
+    $strHeadingText = '' if (!defined($strHeadingText));
+
+    my $strMetadata = $self->update_section_data($arrSections, int($nHeadNo));
+
+    my $strSecMetadata = '';
+    while ($strHeadingText =~ s/<!--gsdl-metadata(.*?)-->//is)
+    {
+	$strSecMetadata .= $1;
+    }
+
+    $strHeadingText =~ s/^\s+//g;
+    $strHeadingText =~ s/\s+$//g;
+    $strSecMetadata =~ s/^\s+//g;
+    $strSecMetadata =~ s/\s+$//g;
+
+    $strMetadata .= "\n<Section>\n\t<Description>\n\t\t<Metadata name=\"Title\">" . $strHeadingText . "</Metadata>\n";
+
+    if (length($strSecMetadata)) {
+	$strMetadata .= "\t\t" . $strSecMetadata . "\n";
+    }
+
+    $strMetadata .= "\t</Description>\n";
+
+    return "<!--" . $strMetadata . "-->";
+}
+
+
+sub update_section_data
+{
+    my ($self, $arrSections, $nCurTocNo) = @_;
+    my ($strBuffer, $nLast, $nSections) = ('', 0, scalar(@$arrSections));
+
+    if ($nSections == 0) {
+	push @$arrSections, $nCurTocNo;
+	return $strBuffer;
+    }
+    $nLast = $arrSections->[$nSections - 1];
+    if ($nCurTocNo > $nLast) {
+	push @$arrSections, $nCurTocNo;
+	return $strBuffer;
+    }
+    for(my $i = $nSections - 1; $i >= 0; $i--) {
+	if ($nCurTocNo <= $arrSections->[$i]) {
+	    $strBuffer .= "\n</Section>";
+	    pop @$arrSections;
+	}
+    }
+    push @$arrSections, $nCurTocNo;
+    return $strBuffer;
+}
+
+
+# note that process_section may be called multiple times for a single
+# section (relying on the fact that add_utf8_text appends the text to any
+# that may exist already).
+sub process_section {
+    my $self = shift (@_);
+    my ($textref, $base_dir, $file, $doc_obj, $cursection) = @_;
+    # trap links
+    if (!$self->{'nolinks'}) {
+
+	# usemap="./#index" not handled correctly => change to "#index"
+	$$textref =~ s/(<img[^>]*?usemap\s*=\s*\"?)([^\">\s]+)(\"?[^>]*>)/
+	    $self->replace_usemap_links($1, $2, $3)/isge;
+
+	$$textref =~ s/(<(?:a|area|frame|link|script)\s+[^>]*?\s*(?:href|src)\s*=\s*\"?)([^\">\s]+)(\"?[^>]*>)/
+	    $self->replace_href_links ($1, $2, $3, $base_dir, $file, $doc_obj, $cursection)/isge;
+    }
+
+    # trap images
+
+    # allow spaces if inside quotes - jrm21
+    $$textref =~ s/(<(?:img|embed|table|tr|td)[^>]*?(?:src|background)\s*=\s*)(\"[^\"]+\"|[^\s>]+)([^>]*>)/
+	$self->replace_images ($1, $2, $3, $base_dir, $file, $doc_obj, $cursection)/isge;
+
+    # add text to document object
+    # turn \ into \\ so that the rest of greenstone doesn't think there
+    # is an escape code following. (Macro parsing loses them...)
+    $$textref =~ s/\\/\\\\/go;
+    
+    $doc_obj->add_utf8_text($cursection, $$textref);
+}
+
+sub replace_images {
+    my $self = shift (@_);
+    my ($front, $link, $back, $base_dir, 
+	$file, $doc_obj, $section) = @_;
+
+    # remove quotes from link at start and end if necessary
+    if ($link=~/^\"/) {
+	$link=~s/^\"//;$link=~s/\"$//;
+	$front.='"';
+	$back="\"$back";
+    }
+
+    $link =~ s/\n/ /g;
+
+    # Hack to overcome Windows wv 0.7.1 bug that causes embedded images to be broken
+    # If the Word file path has spaces in it, wv messes up and you end up with
+    #   absolute paths for the images, and without the "file://" prefix
+    # So check for this special case and massage the data to be correct
+    if ($ENV{'GSDLOS'} =~ /^windows/i && $self->{'plugin_type'} eq "WordPlug" && $link =~ /^[A-Za-z]\:\\/) {
+	$link =~ s/^.*\\([^\\]+)$/$1/;
+    }
+
+    my ($href, $hash_part, $rl) = $self->format_link ($link, $base_dir, $file);
+
+    my $img_file =  $self->add_file ($href, $rl, $hash_part, $base_dir, $doc_obj, $section);
+
+    my $anchor_name = $img_file;
+    $anchor_name =~ s/^.*\///;
+    $anchor_name = "<a name=\"$anchor_name\">";
+
+    return $front . $img_file . $back . $anchor_name;
+}
+
+sub replace_href_links {
+    my $self = shift (@_);
+    my ($front, $link, $back, $base_dir, $file, $doc_obj, $section) = @_;
+
+    # attempt to sort out targets - frames are not handled 
+    # well in this plugin and some cases will screw things
+    # up - e.g. the _parent target (so we'll just remove 
+    # them all ;-)
+    $front =~ s/(target=\"?)_top(\"?)/$1_gsdltop_$2/is;
+    $back =~ s/(target=\"?)_top(\"?)/$1_gsdltop_$2/is;
+    $front =~ s/target=\"?_parent\"?//is;
+    $back =~ s/target=\"?_parent\"?//is;
+
+    return $front . $link . $back if $link =~ /^\#/s;
+    $link =~ s/\n/ /g;
+
+    my ($href, $hash_part, $rl) = $self->format_link ($link, $base_dir, $file);
+    # href may use '\'s where '/'s should be on Windows
+    $href =~ s/\\/\//g;
+
+    my ($filename) = $href =~ /^(?:.*?):(?:\/\/)?(.*)/;
+    
+
+    ##### leave all these links alone (they won't be picked up by intermediate 
+    ##### pages). I think that's safest when dealing with frames, targets etc.
+    ##### (at least until I think of a better way to do it). Problems occur with
+    ##### mailto links from within small frames, the intermediate page is displayed
+    ##### within that frame and can't be seen. There is still potential for this to
+    ##### happen even with html pages - the solution seems to be to somehow tell
+    ##### the browser from the server side to display the page being sent (i.e. 
+    ##### the intermediate page) in the top level window - I'm not sure if that's 
+    ##### possible - the following line should probably be deleted if that can be done
+    return $front . $link . $back if $href =~ /^(mailto|news|gopher|nntp|telnet|javascript):/is;
+
+
+    if (($rl == 0) || ($filename =~ /$self->{'process_exp'}/) || 
+	($href =~ /\/$/) || ($href =~ /^(mailto|news|gopher|nntp|telnet|javascript):/i)) {
+	&ghtml::urlsafe ($href);
+	return $front . "_httpextlink_&rl=" . $rl . "&href=" . $href . $hash_part . $back;
+    } else {
+	# link is to some other type of file (eg image) so we'll
+	# need to associate that file
+	return $front . $self->add_file ($href, $rl, $hash_part, $base_dir, $doc_obj, $section) . $back;
+    }
+}
+
+sub add_file {
+    my $self = shift (@_);
+    my ($href, $rl, $hash_part, $base_dir, $doc_obj, $section) = @_;
+    my ($newname);
+
+    my $filename = $href;
+    if ($base_dir eq "") {
+	# remove http:/ thereby leaving one slash at the start
+	$filename =~ s/^[^:]*:\///;
+    }
+    else {
+	# remove http://
+	$filename =~ s/^[^:]*:\/\///;
+    }
+
+    $filename = &util::filename_cat($base_dir, $filename);
+       
+    # Replace %20's in URL with a space if required. Note that the filename
+    # may include the %20 in some situations
+    if ($filename =~ /\%20/) {
+	if (!-e $filename) {
+	    $filename =~ s/\%20/ /g;
+	}
+    }
+
+    my ($ext) = $filename =~ /(\.[^\.]*)$/;
+
+    if ($rl == 0) {
+	if ((!defined $ext) || ($ext !~ /$self->{'assoc_files'}/)) {
+	    return "_httpextlink_&rl=0&el=prompt&href=" . $href . $hash_part;
+	}
+	else {
+	    return "_httpextlink_&rl=0&el=direct&href=" . $href . $hash_part;
+	}
+    }
+
+    if ((!defined $ext) || ($ext !~ /$self->{'assoc_files'}/)) {
+	return "_httpextlink_&rl=" . $rl . "&href=" . $href . $hash_part;
+    }
+    if ($self->{'rename_assoc_files'}) {
+	if (defined $self->{'aux_files'}->{$href}) {
+	    $newname = $self->{'aux_files'}->{$href}->{'dir_num'} . "/" .
+		$self->{'aux_files'}->{$href}->{'file_num'} . $ext;
+	} else {
+	    $newname = $self->{'dir_num'} . "/" . $self->{'file_num'} . $ext;
+	    $self->{'aux_files'}->{$href} = {'dir_num' => $self->{'dir_num'}, 'file_num' => $self->{'file_num'}};
+	    $self->inc_filecount ();
+	}
+	$doc_obj->associate_file($filename, $newname, undef, $section);
+	return "_httpdocimg_/$newname";
+    } else {
+	($newname) = $filename =~ /([^\/\\]*)$/;
+	$doc_obj->associate_file($filename, $newname, undef, $section);
+	return "_httpdocimg_/$newname";
+    }
+}
+
+
+sub format_link {
+    my $self = shift (@_);
+    my ($link, $base_dir, $file) = @_;
+
+    my ($before_hash, $hash_part) = $link =~ /^([^\#]*)(\#?.*)$/;
+    
+    $hash_part = "" if !defined $hash_part;
+    if (!defined $before_hash || $before_hash !~ /[\w\.\/]/) {
+	my $outhandle = $self->{'outhandle'};
+	print $outhandle "HTMLPlug: ERROR - badly formatted tag ignored ($link)\n"
+	    if $self->{'verbosity'};
+	return ($link, "", 0);
+    }
+
+    if ($before_hash =~ s@^((?:http|ftp|file)://)@@i) {
+	my $type = $1;
+
+	if ($link =~ /^(http|ftp):/i) {
+	    # Turn url (using /) into file name (possibly using \ on windows)
+	    my @http_dir_split = split('/', $before_hash);
+	    $before_hash = &util::filename_cat(@http_dir_split);
+	}
+
+	$before_hash = $self->eval_dir_dots($before_hash);
+					 
+	my $linkfilename = &util::filename_cat ($base_dir, $before_hash);
+	
+	my $rl = 0;
+	$rl = 1 if (-e $linkfilename);
+
+	# make sure there's a slash on the end if it's a directory
+	if ($before_hash !~ /\/$/) {
+	    $before_hash .= "/" if (-d $linkfilename);
+	}
+
+	return ($type . $before_hash, $hash_part, $rl);
+    
+    } elsif ($link !~ /^(mailto|news|gopher|nntp|telnet|javascript):/i) {
+	if ($before_hash =~ s@^/@@ || $before_hash =~ /\\/) {
+
+	    # the first directory will be the domain name if file_is_url
+	    # to generate archives, otherwise we'll assume all files are
+	    # from the same site and base_dir is the root
+
+	    if ($self->{'file_is_url'}) {
+		my @dirs = split /[\/\\]/, $file;
+		my $domname = shift (@dirs);
+		$before_hash = &util::filename_cat($domname, $before_hash);
+		$before_hash =~ s@\\@/@g; # for windows
+	    }
+	    else
+	    {
+		# see if link shares directory with source document
+		# => turn into relative link if this is so!
+		
+		if ($ENV{'GSDLOS'} =~ /^windows/i) {
+		    # too difficult doing a pattern match with embedded '\'s...
+		    my $win_before_hash=$before_hash;
+		    $win_before_hash =~ s@(\\)+@/@g;
+		    # $base_dir is already similarly "converted" on windows.
+		    if ($win_before_hash =~ s@^$base_dir/@@o) {
+		      # if this is true, we removed a prefix
+		      $before_hash=$win_before_hash;
+		    }
+		}
+		else {
+		    # before_hash has lost leading slash by this point,
+		    # -> add back in prior to substitution with $base_dir
+		    $before_hash = "/$before_hash"; 
+
+		    $before_hash = &util::filename_cat("",$before_hash);
+		    $before_hash =~ s@^$base_dir/@@;
+		}
+	    }
+	} else {
+	    # Turn relative file path into full path
+	    my $dirname = &File::Basename::dirname($file);
+	    $before_hash = &util::filename_cat($dirname, $before_hash);
+	    $before_hash = $self->eval_dir_dots($before_hash);
+	}
+
+	my $linkfilename = &util::filename_cat ($base_dir, $before_hash); 
+	# make sure there's a slash on the end if it's a directory
+	if ($before_hash !~ /\/$/) {
+	    $before_hash .= "/" if (-d $linkfilename);
+	}
+	return ("http://" . $before_hash, $hash_part, 1);
+    } else {
+	# mailto, news, nntp, telnet, javascript or gopher link
+	return ($before_hash, "", 0);
+    }
+}
+
+sub extract_first_NNNN_characters {
+    my $self = shift (@_);
+    my ($textref, $doc_obj, $thissection) = @_;
+    
+    foreach my $size (split /,/, $self->{'first'}) {
+	my $tmptext =  $$textref;
+	# skip to the body
+	$tmptext =~ s/.*<body[^>]*>//i;
+	# remove javascript
+	$tmptext =~ s@<script.*?</script>@ @sig;
+	$tmptext =~ s/<[^>]*>/ /g;
+	$tmptext =~ s/&nbsp;/ /g;
+	$tmptext =~ s/^\s+//;
+	$tmptext =~ s/\s+$//;
+	$tmptext =~ s/\s+/ /gs;
+	$tmptext = &unicode::substr ($tmptext, 0, $size);
+	$tmptext =~ s/\s\S*$/&#8230;/; # adds an ellipse (...)
+	$doc_obj->add_utf8_metadata ($thissection, "First$size", $tmptext);
+    }
+}
+
+
+sub extract_metadata {
+    my $self = shift (@_);
+    my ($textref, $metadata, $doc_obj, $section) = @_;
+    my $outhandle = $self->{'outhandle'};
+    # if we don't want metadata, we may as well not be here ...
+    return if (!defined $self->{'metadata_fields'});
+
+    # metadata fields to extract/save. 'key' is the (lowercase) name of the
+    # html meta, 'value' is the metadata name for greenstone to use
+    my %find_fields = ();
+
+    my %creator_fields = (); # short-cut for lookups
+
+
+    foreach my $field (split /,/, $self->{'metadata_fields'}) {
+	# support tag<tagname>
+	if ($field =~ /^(.*?)<(.*?)>$/) {
+	    # "$2" is the user's preferred gs metadata name
+	    $find_fields{lc($1)}=$2; # lc = lowercase
+	} else { # no <tagname> for mapping
+	    # "$field" is the user's preferred gs metadata name
+	    $find_fields{lc($field)}=$field; # lc = lowercase
+	}
+    }
+
+    if (defined $self->{'hunt_creator_metadata'} &&
+	$self->{'hunt_creator_metadata'} == 1 ) {
+	my @extra_fields =
+	    (
+	     'author',
+	     'author.email',
+	     'creator',
+	     'dc.creator',
+	     'dc.creator.corporatename',
+	     );
+
+	# add the creator_metadata fields to search for
+	foreach my $field (@extra_fields) {
+	    $creator_fields{$field}=0; # add to lookup hash
+	}
+    }
+
+
+    # find the header in the html file, which has the meta tags
+    $$textref =~ m@<head>(.*?)</head>@si;
+
+    my $html_header=$1;
+    # go through every <meta... tag defined in the html and see if it is
+    # one of the tags we want to match.
+
+    # special case for title - we want to remember if its been found
+    my $found_title = 0;
+    # this assumes that ">" won't appear. (I don't think it's allowed to...)
+    $html_header =~ /^/; # match the start of the string, for \G assertion
+ 
+    while ($html_header =~ m/\G.*?<meta(.*?)>/sig) {
+	my $metatag=$1;
+	my ($tag, $value);
+
+	# find the tag name
+	$metatag =~ /(?:name|http-equiv)\s*=\s*([\"\'])?(.*?)\1/is;
+	$tag=$2;
+	# in case they're not using " or ', but they should...
+	if (! $tag) {
+	    $metatag =~ /(?:name|http-equiv)\s*=\s*([^\s\>]+)/is;
+	    $tag=$1;
+	}
+
+	if (!defined $tag) {
+	    print $outhandle "HTMLPlug: can't find NAME in \"$metatag\"\n";
+	    next;
+	}
+
+	# don't need to assign this field if it was passed in from a previous 
+	# (recursive) plugin
+	if (defined $metadata->{$tag}) {next}
+
+	# find the tag content
+	$metatag =~ /content\s*=\s*([\"\'])?(.*?)\1/is;
+	$value=$2;
+	if (! $value) {
+	    $metatag =~ /(?:name|http-equiv)\s*=\s*([^\s\>]+)/is;
+	    $value=$1;
+	}
+	if (!defined $value) {
+	    print $outhandle "HTMLPlug: can't find VALUE in \"$metatag\"\n";
+	    next;
+	}
+
+	# clean up and add
+	$value =~ s/\s+/ /gs;
+	chomp($value); # remove trailing \n, if any
+	if (exists $creator_fields{lc($tag)}) {
+	    # map this value onto greenstone's "Creator" metadata
+	    $tag='Creator';
+	} elsif (!exists $find_fields{lc($tag)}) {
+	    next; # don't want this tag
+	} else {
+	    # get the user's preferred capitalisation
+	    $tag = $find_fields{lc($tag)};
+	}
+	if (lc($tag) eq "title") {
+	    $found_title = 1;
+	}
+	print $outhandle " extracted \"$tag\" metadata \"$value\"\n" 
+	    if ($self->{'verbosity'} > 2);
+	$doc_obj->add_utf8_metadata($section, $tag, $value);
+
+    }
+    
+    # TITLE: extract the document title
+    if (exists $find_fields{'title'} && !$found_title) {
+	# we want a title, and didn't find one in the meta tags
+	# see if there's a <title> tag
+	my $title;
+	my $from = ""; # for debugging output only
+	if ($html_header =~ /<title[^>]*>([^<]+)<\/title[^>]*>/is) {
+	    $title = $1;
+	    $from = "<title> tags";
+	}
+
+	if (!defined $title) {
+	    $from = "first 100 chars";
+	    # if no title use first 100 or so characters
+	    $title = $$textref;
+	    $title =~ s/^\xFE\xFF//; # Remove unicode byte order mark	    
+	    $title =~ s/^.*?<body>//si;
+	    # ignore javascript!
+	    $title =~ s@<script.*?</script>@ @sig;
+	    $title =~ s/<\/([^>]+)><\1>//g; # (eg) </b><b> - no space
+	    $title =~ s/<[^>]*>/ /g; # remove all HTML tags
+	    $title = substr ($title, 0, 100);
+	    $title =~ s/\s\S*$/.../;
+	}
+	$title =~ s/<[^>]*>/ /g; # remove html tags
+	$title =~ s/&nbsp;/ /g;
+	$title =~ s/(?:&nbsp;|\xc2\xa0)/ /g; # utf-8 for nbsp...
+	$title =~ s/\s+/ /gs; # collapse multiple spaces
+	$title =~ s/^\s*//;   # remove leading spaces
+	$title =~ s/\s*$//;   # remove trailing spaces
+
+	$title =~ s/^$self->{'title_sub'}// if ($self->{'title_sub'});
+	$title =~ s/^\s+//s; # in case title_sub introduced any...
+	$doc_obj->add_utf8_metadata ($section, 'Title', $title);
+	print $outhandle " extracted Title metadata \"$title\" from $from\n" 
+	    if ($self->{'verbosity'} > 2);
+    } 
+    
+    # add FileFormat metadata
+    $doc_obj->add_metadata($section,"FileFormat", "HTML");
+
+    # Special, for metadata names such as tagH1 - extracts
+    # the text between the first <H1> and </H1> tags into "H1" metadata.
+
+    foreach my $field (keys %find_fields) {
+	if ($field !~ /^tag([a-z0-9]+)$/i) {next}
+	my $tag = $1;
+	if ($$textref =~ m@<$tag[^>]*>(.*?)</$tag[^>]*>@g) {
+	    my $content = $1;
+	    $content =~ s/&nbsp;/ /g;
+	    $content =~ s/<[^>]*>/ /g;
+	    $content =~ s/^\s+//;
+	    $content =~ s/\s+$//;
+	    $content =~ s/\s+/ /gs;
+	    if ($content) {
+		$tag=$find_fields{"tag$tag"}; # get the user's capitalisation
+		$tag =~ s/^tag//i;
+		$doc_obj->add_utf8_metadata ($section, $tag, $content);
+		print $outhandle " extracted \"$tag\" metadata \"$content\"\n" 
+		    if ($self->{'verbosity'} > 2);
+	    }
+	}
+    }    
+}
+
+
+# evaluate any "../" to next directory up
+# evaluate any "./" as here
+sub eval_dir_dots {
+    my $self = shift (@_);
+    my ($filename) = @_;
+    my $dirsep_os = &util::get_os_dirsep();
+    my @dirsep = split(/$dirsep_os/,$filename);
+
+    my @eval_dirs = ();
+    foreach my $d (@dirsep) {
+	if ($d eq "..") {
+	    pop(@eval_dirs);
+	    
+	} elsif ($d eq ".") {
+	    # do nothing!
+
+	} else {
+	    push(@eval_dirs,$d);
+	}
+    }
+
+    # Need to fiddle with number of elements in @eval_dirs if the
+    # first one is the empty string.  This is because of a
+    # modification to util::filename_cat that supresses the addition
+    # of a leading '/' character (or \ if windows) (intended to help
+    # filename cat with relative paths) if the first entry in the
+    # array is the empty string.  Making the array start with *two*
+    # empty strings is a way to defeat this "smart" option.
+    #
+    if (scalar(@eval_dirs) > 0) {
+	if ($eval_dirs[0] eq ""){
+	    unshift(@eval_dirs,"");
+	}
+    }
+    return &util::filename_cat(@eval_dirs);
+}
+
+sub replace_usemap_links {
+    my $self = shift (@_);
+    my ($front, $link, $back) = @_;
+
+    $link =~ s/^\.\///;
+    return $front . $link . $back;
+}
+
+sub inc_filecount {
+    my $self = shift (@_);
+
+    if ($self->{'file_num'} == 1000) {
+	$self->{'dir_num'} ++;
+	$self->{'file_num'} = 0;
+    } else {
+	$self->{'file_num'} ++;
+    }
+}
+
+
+# Extend the BasPlug read_file so that strings like &eacute; are
+# converted to UTF8 internally.  
+#
+# We don't convert &lt; or &gt; or &amp; or &quot; in case
+# they interfere with the GML files
+
+sub read_file {
+    my ($self, $filename, $encoding, $language, $textref) = @_;
+
+    &BasPlug::read_file($self, $filename, $encoding, $language, $textref);
+
+    # Convert entities to their UTF8 equivalents
+    $$textref =~ s/&(lt|gt|amp|quot|nbsp);/&z$1;/go;
+    $$textref =~ s/&([^;]+);/&ghtml::getcharequiv($1,1)/gseo;
+    $$textref =~ s/&z(lt|gt|amp|quot|nbsp);/&$1;/go;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ISISPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ISISPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ISISPlug.pm	(revision 10506)
@@ -0,0 +1,288 @@
+###########################################################################
+#
+# ISISPlug.pm -- A plugin for CDS/ISIS databases
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright 1999-2004 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 ISISPlug;
+
+
+use multiread;
+use SplitPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+# ISISPlug is a sub-class of SplitPlug.
+sub BEGIN {
+    @ISISPlug::ISA = ('SplitPlug');
+}
+
+
+my $arguments = 
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() },
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_block_exp() },
+      { 'name' => "split_exp",
+	'desc' => "{SplitPlug.split_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_split_exp() },
+
+      # The interesting options
+      { 'name' => "entry_separator",
+	'desc' => "{ISISPlug.entry_separator}",
+	'type' => "string",
+	'reqd' => "no",
+	'deft' => "<br>" },
+      { 'name' => "subfield_separator",
+	'desc' => "{ISISPlug.subfield_separator}",
+	'type' => "string",
+	'reqd' => "no",
+	'deft' => ", " }
+      ];
+
+my $options = { 'name'     => "ISISPlug",
+		'desc'     => "{ISISPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'explodes' => "yes",
+		'args'     => $arguments };
+
+
+# This plugin processes files with the suffix ".mst"
+sub get_default_process_exp {
+    return q^(?i)(\.mst)$^;
+}
+
+
+# This plugin blocks files with the suffix ".fdt" and ".xrf"
+sub get_default_block_exp {
+    return q^(?i)(\.fdt|\.xrf)$^;
+}
+
+    
+# This plugin splits the input text at the "----------" lines
+sub get_default_split_exp {
+    return q^\r?\n----------\r?\n^;
+}
+
+
+sub new
+{
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new SplitPlug($pluginlist,$inputargs,$hashArgOptLists): new SplitPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+
+sub read_file
+{
+    my $self = shift (@_);
+    my ($filename, $encoding, $language, $textref) = @_;
+
+    my ($databasename) = ($filename =~ /(.*)\.mst$/i);
+
+    # Check the associated .fdt and .xrf files exist
+    # These files must have a lowercase extension for the IsisGdl program to work
+    # Bailing out because of this is kind of crappy but it is only an issue on Unix
+    my $fdtfilename = $databasename . ".fdt";
+    if (! -e $fdtfilename) {
+	die "Error: Could not find ISIS FDT file $fdtfilename.\n";
+    }
+    my $xrffilename = $databasename . ".xrf";
+    if (! -e $xrffilename) {
+	die "Error: Could not find ISIS XRF file $xrffilename.\n";
+    }
+
+    # The text to split is exported from the database by the IsisGdl program
+    open(FILE, "IsisGdl \"$filename\" |");
+
+    my $reader = new multiread();
+    $reader->set_handle('ISISPlug::FILE');
+    $reader->set_encoding($encoding);
+    $reader->read_file($textref);
+
+    close(FILE);
+
+    # Parse the associated ISIS database Field Definition Table file (.fdt)
+    my %fdtmapping = &parse_field_definition_table($fdtfilename);
+
+    # Map the tag numbers to tag names, using the FDT mapping
+    $$textref =~ s/\r?\ntag=(\d+) /\ntag=$fdtmapping{$1}{'title'} /g;
+
+    # Remove the line at the start so it is split and processed properly
+    $$textref =~ s/^----------\n//;
+}
+
+
+sub process
+{
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $cursection = $doc_obj->get_top_section();
+    my $subfield_separator = $self->{'subfield_separator'};
+    my $entry_separator = $self->{'entry_separator'};
+
+    # Report that we're processing the file
+    print STDERR "<Processing n='$file' p='ISISPlug'>\n" if ($gli);
+    print $outhandle "IsisPlug: processing $file\n"
+	if ($self->{'verbosity'}) > 1;
+
+    # Process each line of the ISIS record, one at a time
+    foreach my $line (split(/\n/, $$textref)) {
+	$line =~ /^tag=(.*) data=(.+)$/;
+	my $rawtagname = $1;
+	my $rawtagdata = $2;
+	# print STDERR "Raw tag: $rawtagname, Raw data: $rawtagdata\n";
+	next if ($rawtagname eq "");
+
+	# Metadata field names: title case, then remove spaces
+	my $tagname = "";
+	foreach my $word (split(/\s+/, $rawtagname)) {
+	    substr($word, 0, 1) =~ tr/a-z/A-Z/;
+	    $tagname .= $word;
+	}
+
+	# Make sure there is nothing bad in the tag names
+	$tagname =~ s/&//g;
+
+	# Handle each piece of metadata ('%' separated)
+	my $completetagvalue = "";
+	foreach my $rawtagvalue (split(/%/, $rawtagdata)) {
+	    $completetagvalue .= $entry_separator unless ($completetagvalue eq "");
+
+	    # Metadata field values: take care with subfields
+	    my $completeentryvalue = "";
+	    while ($rawtagvalue ne "") {
+		# If there is a subfield specifier, parse it off
+		my $subfieldname = "";
+		if ($rawtagvalue =~ s/^\^// && $rawtagvalue =~ s/([a-z])//) {
+		    $subfieldname = "^$1";
+		}
+
+		# Parse the metadata value off
+		$rawtagvalue =~ s/^([^\^]*)//;
+		my $metadatafieldname = $tagname . $subfieldname;
+		my $metadatafieldvalue = $1;
+		
+		# Handle Keywords specially
+		if ($metadatafieldname eq "Keywords") {
+		    my $keywordmetadatavalue = $metadatafieldvalue;
+		    my $keywordlist = "";
+		    while ($keywordmetadatavalue =~ s/\<(.+?)\>//) {
+			my $keyword = $1;
+			$doc_obj->add_utf8_metadata($cursection, $metadatafieldname, $keyword); 
+			$keywordlist .= ", " unless ($keywordlist eq "");
+			$keywordlist .= $keyword;
+		    }
+
+		    $metadatafieldvalue = $keywordlist;
+		}
+
+		# Escape any '<' and '>' characters so they appear correctly in the final collection
+		$metadatafieldvalue =~ s/\</&lt;/g;
+		$metadatafieldvalue =~ s/\>/&gt;/g;
+
+		# We have already added Keywords metadata above
+		unless ($metadatafieldname eq "Keywords") {
+		    $doc_obj->add_utf8_metadata($cursection, $metadatafieldname, $metadatafieldvalue); 
+		}
+
+		$completeentryvalue .= $subfield_separator unless ($completeentryvalue eq "");
+		$completeentryvalue .= $metadatafieldvalue;
+	    }
+
+	    $completetagvalue .= $completeentryvalue;
+	}
+
+	$doc_obj->add_utf8_metadata($cursection, $tagname . "^all", $completetagvalue); 
+    }
+
+    # Add the full record as the document text
+    $$textref =~ s/\</&lt;/g;
+    $$textref =~ s/\>/&gt;/g;
+    $doc_obj->add_utf8_text($cursection, $$textref);
+
+    # Add FileFormat metadata
+    $doc_obj->add_utf8_metadata($cursection, "FileFormat", "CDS/ISIS");
+
+    # Record was processed successfully (and there was no document obtained)
+    return 1;
+}
+
+
+sub parse_field_definition_table
+{
+    my $fdtfilename = shift(@_);
+
+    my %fdtmapping = ();
+
+    open(FDT_FILE, "<$fdtfilename") || die "Error: Could not open file $fdtfilename.\n";
+
+    my $amongstdefinitions = 0;
+    foreach my $fdtfileline (<FDT_FILE>) {
+	$fdtfileline =~ s/(\s*)$//;  # Remove any nasty spaces at the end of the lines
+
+	if ($amongstdefinitions) {
+	    my $fieldtitle     = substr($fdtfileline,  0, 30);
+	    my $fieldsubfields = substr($fdtfileline, 30, 20);
+	    my $fieldspecs     = substr($fdtfileline, 50);
+
+	    # Remove extra spaces
+	    $fieldtitle =~ s/(\s*)$//;
+	    $fieldsubfields =~ s/(\s*)$//;
+
+	    # Map from tag number to metadata field title and subfields
+	    my $fieldtag = (split(/ /, $fieldspecs))[0];
+	    $fdtmapping{$fieldtag} = { 'title' => $fieldtitle,
+				       'subfields' => $fieldsubfields };
+	}
+	elsif ($fdtfileline eq "***") {
+	    $amongstdefinitions = 1;
+	}
+    }
+
+    close(FDT_FILE);
+
+    return %fdtmapping;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ImagePlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ImagePlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ImagePlug.pm	(revision 10506)
@@ -0,0 +1,473 @@
+###########################################################################
+#
+# ImagePlug.pm -- simple text plugin
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package ImagePlug;
+
+use BasPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @ImagePlug::ISA = ('BasPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "noscaleup",
+	'desc' => "{ImagePlug.noscaleup}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "thumbnailsize",
+	'desc' => "{ImagePlug.thumbnailsize}",
+	'type' => "int",
+	'deft' => "100",
+	'range' => "1,",
+	'reqd' => "no" },
+      { 'name' => "thumbnailtype",
+	'desc' => "{ImagePlug.thumbnailtype}",
+	'type' => "string",
+	'deft' => "gif",
+	'reqd' => "no" },
+      { 'name' => "screenviewsize",
+	'desc' => "{ImagePlug.screenviewsize}",
+	'type' => "int",
+	'deft' => "0",
+	'range' => "1,",
+	'reqd' => "no" },
+      { 'name' => "screenviewtype",
+	'desc' => "{ImagePlug.screenviewtype}",
+	'type' => "string",
+	'deft' => "jpg",
+	'reqd' => "no" },
+      { 'name' => "converttotype",
+	'desc' => "{ImagePlug.converttotype}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "minimumsize",
+	'desc' => "{ImagePlug.minimumsize}",
+	'type' => "int",
+	'deft' => "100",
+	'range' => "1,",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "ImagePlug",
+		'desc'     => "{ImagePlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    # Check that ImageMagick is installed and available on the path (except for Windows 95/98)
+    if (!($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT())) {
+	my $result = `identify 2>&1`;
+	if ($? == -1 || $? == 256) {  # Linux and Windows return different values for "program not found"
+	    $self->{'imagemagick_not_installed'} = 1;
+	}
+    }
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)(\.jpe?g|\.gif|\.png|\.bmp|\.xbm|\.tif?f)$^; 
+}
+
+# this makes no sense for images
+sub block_cover_image
+{
+    my $self =shift (@_);
+    my ($filename) = @_;
+
+    return;
+}
+# Create the thumbnail and screenview images, and discover the Image's
+# size, width, and height using the convert utility.
+
+sub run_convert {
+    my $self = shift (@_);
+    my $filename = shift (@_);   # filename with full path
+    my $file = shift (@_);       # filename without path
+    my $doc_obj = shift (@_);
+    my $section = $doc_obj->get_top_section();
+    
+    my $verbosity = $self->{'verbosity'};
+    my $outhandle = $self->{'outhandle'};
+
+    # check the filename is okay
+    return 0 if ($file eq "" || $filename eq "");
+
+#    Code now extended to quote filenames in 'convert' commnads
+#    Allows spaces in filenames, but note needs spaces to be escaped in URL as well
+#    if ($filename =~ m/ /) {
+#	print $outhandle "ImagePlug: \"$filename\" contains a space. choking.\n";
+#	return undef;
+#    }
+
+    my $minimumsize = $self->{'minimumsize'};
+    if (defined $minimumsize && (-s $filename < $minimumsize)) {
+        print $outhandle "ImagePlug: \"$filename\" too small, skipping\n"
+	    if ($verbosity > 1);
+    }
+
+
+    # Convert the image to a new type (if required).
+    my $converttotype = $self->{'converttotype'};
+    my $originalfilename = "";  # only set if we do a conversion
+    my $type = "unknown";
+
+
+    if ($converttotype ne "" && $filename =~ m/$converttotype$/) {
+
+	$originalfilename = $filename;
+	$filename = &util::get_tmp_filename() . ".$converttotype";
+	$self->{'tmp_filename'} = $filename;
+
+	my $command = "convert -interlace plane -verbose \"$originalfilename\" \"$filename\"";
+	print $outhandle "$command\n" if ($verbosity > 2);
+	my $result = '';
+	$result = `$command`;
+	print $outhandle "RESULT = $result\n" if ($verbosity > 2);
+
+	$type = $converttotype;
+    }
+    
+
+    # Add the image metadata
+    my $url = $file;
+    $url =~ s/ /%20/g;
+
+    $doc_obj->add_metadata ($section, "Image", $url);
+
+    # Also want to set filename as 'Source' metadata to be
+    # consistent with other plugins
+    $doc_obj->add_metadata ($section, "Source", $url);
+
+    my ($image_type, $image_width, $image_height, $image_size) 
+	= &identify($filename, $outhandle, $verbosity);
+
+    if ($image_type ne " ") {
+	$type = $image_type;
+    }
+    
+    $doc_obj->add_metadata ($section, "FileFormat", $type);
+    $doc_obj->add_metadata ($section, "FileSize",   $image_size);
+
+    $doc_obj->add_metadata ($section, "ImageType",   $image_type);
+    $doc_obj->add_metadata ($section, "ImageWidth",  $image_width);
+    $doc_obj->add_metadata ($section, "ImageHeight", $image_height);
+    $doc_obj->add_metadata ($section, "ImageSize",   $image_size);
+
+    $doc_obj->add_metadata ($section, "srclink", 
+			    "<a href=\"_httpcollection_/index/assoc/[assocfilepath]/[Image]\">");
+    $doc_obj->add_metadata ($section, "/srclink", "</a>");
+
+    $doc_obj->add_metadata ($section, "srcicon", "<img src=\"_httpcollection_/index/assoc/[assocfilepath]/[Image]\" width=100>");
+
+    
+    # Add the image as an associated file
+    $doc_obj->associate_file($filename,$file,"image/$type",$section);
+
+
+    # Make the thumbnail image
+    my $thumbnailsize = $self->{'thumbnailsize'} || 100;
+    my $thumbnailtype = $self->{'thumbnailtype'} || 'gif';
+	
+    my $thumbnailfile = &util::get_tmp_filename() . ".$thumbnailtype";
+    $self->{'tmp_filename2'} = $thumbnailfile;
+
+    # Generate the thumbnail with convert
+    my $command = "convert -interlace plane -verbose -geometry $thumbnailsize" 
+	. "x$thumbnailsize \"$filename\" \"$thumbnailfile\"";
+    print $outhandle "THUMBNAIL: $command\n" if ($verbosity > 2);
+    my $result = '';
+    $result = `$command 2>&1` ;
+    print $outhandle "THUMB RESULT: $result\n" if ($verbosity > 2);
+
+    # Add the thumbnail as an associated file ...
+    if (-e "$thumbnailfile") { 
+	$doc_obj->associate_file("$thumbnailfile", "thumbnail.$thumbnailtype", 
+				 "image/$thumbnailtype",$section);
+	$doc_obj->add_metadata ($section, "ThumbType", $thumbnailtype);
+	$doc_obj->add_metadata ($section, "Thumb", "thumbnail.$thumbnailtype");
+
+	$doc_obj->add_metadata ($section, "thumbicon", "<img src=\"_httpcollection_/index/assoc/[assocfilepath]/[Thumb]\" width=[ThumbWidth] height=[ThumbHeight]>");
+    }
+
+    # Extract Thumnail metadata from convert output
+    if ($result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) {
+	$doc_obj->add_metadata ($section, "ThumbWidth", $1);
+	$doc_obj->add_metadata ($section, "ThumbHeight", $2);
+    }
+
+    # Make a screen-sized version of the picture if requested
+    if ($self->{'screenviewsize'}) {
+
+	# To do: if the actual image smaller than the screenview size,
+	# we should use the original !
+
+	my $screenviewsize = $self->{'screenviewsize'};
+	my $screenviewtype = $self->{'screenviewtype'} || 'jpeg';
+	my $screenviewfilename = &util::get_tmp_filename() . ".$screenviewtype";
+	$self->{'tmp_filename3'} = $screenviewfilename;
+
+	# make the screenview image
+	my $command = "convert -interlace plane -verbose -geometry $screenviewsize" 
+	    . "x$screenviewsize \"$filename\" \"$screenviewfilename\"";
+	print $outhandle "$command\n" if ($verbosity > 2);
+	my $result = "";
+	$result = `$command  2>&1` ;
+	print $outhandle "$result\n" if ($verbosity > 3);
+
+	# get screenview dimensions, size and type
+        if ($result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) {
+	    $doc_obj->add_metadata ($section, "ScreenWidth", $1);
+	    $doc_obj->add_metadata ($section, "ScreenHeight", $2);
+	}
+	else {
+	    $doc_obj->add_metadata ($section, "ScreenWidth", $image_width);
+	    $doc_obj->add_metadata ($section, "ScreenHeight", $image_height);
+	}
+
+	#add the screenview as an associated file ...
+	if (-e "$screenviewfilename") { 
+	    $doc_obj->associate_file("$screenviewfilename", "screenview.$screenviewtype",
+				     "image/$screenviewtype",$section);
+	    $doc_obj->add_metadata ($section, "ScreenType", $screenviewtype);
+	    $doc_obj->add_metadata ($section, "Screen", "screenview.$screenviewtype");
+
+	    $doc_obj->add_metadata ($section, "screenicon", "<img src=\"_httpcollection_/index/assoc/[assocfilepath]/[Screen]\" width=[ScreenWidth] height=[ScreenHeight]>");
+	} else {
+	    print $outhandle "ImagePlug: couldn't find \"$screenviewfilename\"\n";
+	}
+    }
+
+    return $type;
+
+
+}
+
+
+
+# Discover the characteristics of an image file with the ImageMagick
+# "identify" command.
+
+sub identify { 
+    my ($image, $outhandle, $verbosity) = @_;
+
+    # Use the ImageMagick "identify" command to get the file specs
+    my $command = "identify \"$image\" 2>&1";
+    print $outhandle "$command\n" if ($verbosity > 2);
+    my $result = '';
+    $result = `$command`;
+    print $outhandle "$result\n" if ($verbosity > 3);
+
+    # Read the type, width, and height
+    my $type =   'unknown';
+    my $width =  'unknown';
+    my $height = 'unknown';
+
+    my $image_safe = quotemeta $image;
+    if ($result =~ /^$image_safe (\w+) (\d+)x(\d+)/) {
+	$type = $1;
+	$width = $2;
+	$height = $3;
+    }
+
+    # Read the size
+    my $size = "unknown";
+    if ($result =~ m/^.* ([0-9]+)b/) {
+	$size = $1;
+    }
+    elsif ($result =~ m/^.* ([0-9]+)(\.([0-9]+))?kb?/) {
+	$size = 1024 * $1;
+	if (defined($2)) {
+	    $size = $size + (1024 * $2);
+	    # Truncate size (it isn't going to be very accurate anyway)
+	    $size = int($size);
+	}
+    }
+
+    print $outhandle "file: $image:\t $type, $width, $height, $size\n" 
+	if ($verbosity > 2);
+
+    # Return the specs
+    return ($type, $width, $height, $size);
+}
+
+
+# The ImagePlug read() function. This function does all the right things
+# to make general options work for a given plugin. It calls the process()
+# function which does all the work specific to a plugin (like the old
+# read functions used to do). Most plugins should define their own 
+# process() function and let this read() function keep control.
+#
+# ImagePlug overrides read() because there is no need to read the actual 
+# text of the file in, because the contents of the file is not text...
+#
+# Return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+
+    my $filename = &util::filename_cat($base_dir, $file);
+    return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+
+    print STDERR "<Processing n='$file' p='ImagePlug'>\n" if ($gli);
+    print $outhandle "ImagePlug processing $file\n"
+	    if $self->{'verbosity'} > 1;
+
+    # None of this works very well on Windows 95/98...
+    if ($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT()) {
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file' r='Windows 95/98 not supported'>\n";
+	}
+	print $outhandle "ImagePlug: Windows 95/98 not supported\n";
+	return -1;
+    }
+
+    # None of this is going to work very well without ImageMagick...
+    if ($self->{'imagemagick_not_installed'}) {
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file' r='ImageMagick not installed'>\n";
+	}
+	print $outhandle "ImagePlug: ImageMagick not installed\n";
+	return -1;
+    }
+
+    #if there's a leading directory name, eat it...
+    $file =~ s/^.*[\/\\]//;
+    
+    # create a new document
+    my $doc_obj = new doc ($filename, "indexed_doc");
+    $doc_obj->set_OIDtype ($processor->{'OIDtype'});    
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+
+    #run convert to get the thumbnail and extract size and type info
+    my $result = run_convert($self, $filename, $file, $doc_obj);
+    
+    if (!defined $result)
+    {
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file'>\n";
+	}
+	print $outhandle "ImagePlug: couldn't process \"$filename\"\n";
+	return -1; # error during processing
+    }
+
+    #create an empty text string so we don't break downstream plugins 
+    my $text = &gsprintf::lookup_string("{BasPlug.dummy_text}");
+    # include any metadata passed in from previous plugins 
+    # note that this metadata is associated with the top level section
+    my $section = $doc_obj->get_top_section();
+    $self->extra_metadata ($doc_obj, $section, $metadata);
+
+    # do plugin specific processing of doc_obj
+    unless (defined ($self->process(\$text, $pluginfo, $base_dir, $file, $metadata, $doc_obj))) {
+	print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	return -1;
+    }
+
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata ($doc_obj);
+
+    # if we haven't found any Title so far, assign one
+    # this was shifted to here from inside read()
+    $self->title_fallback($doc_obj,$section,$file);
+    # add an OID
+    $doc_obj->set_OID();
+    $doc_obj->add_text($section, $text);
+
+    # process the document
+    $processor->process($doc_obj);
+
+    # clean up temporary files - we do this here instead of in  
+    # run_convert becuase associated files aren't actually copied 
+    # until after process has been run.
+    if (defined $self->{'tmp_filename'} && 
+	-e $self->{'tmp_filename'}) {
+      &util::rm($self->{'tmp_filename'})
+    }
+    if (defined $self->{'tmp_filename2'} && 
+	-e $self->{'tmp_filename2'}) {
+      &util::rm($self->{'tmp_filename2'})
+    }
+    if (defined $self->{'tmp_filename3'} && 
+	-e $self->{'tmp_filename3'}) {
+      &util::rm($self->{'tmp_filename3'})
+    }
+
+    $self->{'num_processed'}++;
+
+    return 1;
+}
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    return 1;
+}
+
+1;
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/IndexPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/IndexPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/IndexPlug.pm	(revision 10506)
@@ -0,0 +1,160 @@
+###########################################################################
+#
+# IndexPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# This recursive plugin processes an index.txt file. 
+# The index.txt file should contain the list of files to be
+# included in the collection followed by any extra metadata to
+# be associated with each file.
+
+# The index.txt file should be formatted as follows:
+# The first line may be a key (beginning with key:)
+# to name the metadata fields
+# (e.g. key: Subject Organization Date) 
+# The following lines will contain a filename followed 
+# by the value that metadata entry is to be set to.
+# (e.g. 'irma/iw097e 3.2 unesco 1993' will associate the
+# metadata Subject=3.2, Organization=unesco, and Date=1993
+# with the file irma/iw097e if the above key line was used)
+
+# Note that if any of the metadata fields use the Hierarchy
+# classifier plugin then the value they're set to should
+# correspond to the first field (the descriptor) in the
+# appropriate classification file.
+
+# Metadata values may be named separately using a tag 
+# (e.g. <Subject>3.2) and this will override any name 
+# given to them by the key line.
+# If there's no key line any unnamed metadata value will be
+# named 'Subject'.
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package IndexPlug;
+
+use plugin;
+use BasPlug;
+use doc;
+use util;
+use cfgread;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @IndexPlug::ISA = ('BasPlug');
+}
+
+my $arguments = [
+		 ];
+
+my $options = { 'name'     => "IndexPlug",
+		'desc'     => "{IndexPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes" };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+# return 1 if this class might recurse using $pluginfo
+sub is_recursive {
+    my $self = shift (@_);
+    
+    return 1;
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $indexfile = &util::filename_cat($base_dir, $file, "index.txt");
+    if (!-f $indexfile) {
+	# not a directory containing an index file
+	return undef;
+    }
+
+    # found an index.txt file
+    print STDERR "<Processing n='$file' p='IndexPlug'>\n" if ($gli);
+    print $outhandle "IndexPlug: processing $indexfile\n";
+
+    # read in the index.txt
+    my $list = &cfgread::read_cfg_file ($indexfile, undef, '^[^#]\w');
+    my @fields = ();
+    # see if there's a 'key:' line
+    if (defined $list->{'key:'}) {
+	@fields = @{$list->{'key:'}};
+    }
+
+    my $index_base_dir = &util::filename_cat($base_dir, $file);
+
+    # process each document
+    my $count = 0;
+    foreach my $docfile (keys (%$list)) {
+	last if ($maxdocs != -1 && ($total_count + $count) >= $maxdocs);
+	$metadata = {}; # at present we can do this as metadata
+	                # will always be empty when it arrives
+	                # at this plugin - this might cause 
+	                # problems if things change though
+
+	# note that $list->{$docfile} is an array reference
+	if ($docfile !~ /key:/i) {
+	    my $i = 0;
+	    for ($i = 0; $i < scalar (@{$list->{$docfile}}); $i ++) {
+		if ($list->{$docfile}->[$i] =~ /^<([^>]+)>(.+)$/) {
+		    unless (defined ($metadata->{$1})) {
+			$metadata->{$1} = [];
+		    } 
+		    push (@{$metadata->{$1}}, $2);
+		} elsif (scalar @fields >= $i) {
+		    unless (defined ($metadata->{$fields[$i]})) {
+			$metadata->{$fields[$i]} = [];
+		    } 
+		    push (@{$metadata->{$fields[$i]}}, $list->{$docfile}->[$i]);
+		} else {
+		    $metadata->{'Subject'} = $list->{$docfile};
+		}
+	    }
+	    $count += &plugin::read ($pluginfo, $index_base_dir, $docfile, $metadata, $processor, $maxdocs, ($total_count +$count), $gli);
+	}
+    }
+
+    return $count; # was processed
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/LaTeXPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/LaTeXPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/LaTeXPlug.pm	(revision 10506)
@@ -0,0 +1,755 @@
+###########################################################################
+#
+# LaTeXPlug.pm
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Written by John McPherson
+# Copyright (C) 2004 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.
+#
+###########################################################################
+
+# todo:
+#  \includegraphics
+#  parse/remove tex \if ... macros
+
+package LaTeXPlug;
+
+# System complains about $arguments if the strict is set
+use strict;
+no strict 'refs'; # so we can print to a handle named by a variable
+
+# greenstone packages
+use BasPlug;
+use unicode;
+use util;
+
+my $arguments = [
+		 ];
+my $options={ 'name' => 'LaTeXPlug',
+	      'desc' => '{LaTeXPlug.desc}',
+	      'abstract' => 'no',
+	      'inherits' => 'yes' };
+sub BEGIN {
+    @LaTeXPlug::ISA = ('BasPlug');
+}
+
+sub print_usage {
+    print STDERR "\n  usage: plugin LaTeXPlug [options]\n\n";
+}
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    $self->{'aux_files'} = {};
+    $self->{'dir_num'} = 0;
+    $self->{'file_num'} = 0;
+    return bless $self, $class;
+}
+
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+    return q^\.tex$^;
+}
+
+sub get_default_block_exp {
+    # assume any .eps files are part of the latex stuff
+    return '\.(?:eps)$';
+}
+
+
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+
+    my $start=substr($$textref, 0, 200); # first 200 bytes
+
+    if ($start !~ m~\\ (?:documentclass | documentstyle | input | section 
+			| chapter | contents | begin) ~x) {
+	# this doesn't look like latex...
+	return undef;
+    }
+    my $outhandle = $self->{'outhandle'};
+    if ($gli) {
+	print STDERR "<Processing n='$file' p='LaTeXPlug'>\n";
+    } elsif ($self->{'verbosity'} > 1) {
+	print $outhandle "LaTeXPlug: processing $file\n" 
+    }
+    my $cursection = $doc_obj->get_top_section();
+
+    ###### clean up text ######
+    $$textref =~ s/\r$//mg;  # remove dos ^M
+    $$textref =~ s/%.*$//mg; # remove comments
+
+    # convert to utf-8 if not already - assume non ascii => iso-8859-1/latin
+
+    $$textref =~ s@(?<=[[:ascii:]])\xA0+@\xc2\xa0@g; # latin nonbreaking space
+    # check that both sides are ascii, so we don't screw up utf-8 chars
+    $$textref =~ s@ (?<=[[:ascii:]])([\x80-\xff])(?=[[:ascii:]]) @
+	unicode::ascii2utf8($1) @egx; # takes "extended ascii" (ie latin)
+
+
+    ###### find metadata ######
+
+    ## FileFormat metadata ##
+    $doc_obj->add_metadata($cursection, "FileFormat", "LaTeX");
+
+    ### title metadata ###
+    $$textref =~ m@\\title\s*{(.*?)}@s;
+    my $title = $1;
+    if (!$title) {
+	# no title tag. look for a chapter/section heading
+	$$textref =~ m@\\(?:chapter|section)\s*{(.*?)}@s; # will get 1st match
+	$title = $1;
+    }
+    if (!$title) {
+	# no chapter/section heading tags either... use filename
+	$title = $file;
+	$title =~ s/\.tex$//i;
+	$title =~ s/[-_.]/ /g; # turn punctuation into spaces
+    }
+    if ($title) {
+	$title =~ s@\\\\@ @g; # embedded newlines
+	$title = $self->process_latex($title); # no "-html" for title eg in browser
+	$doc_obj->add_utf8_metadata($cursection, "Title", $title);
+    }
+
+    ### creator/individual author metadata ###
+    $$textref =~ m@\\author\s*{((?:{.*?}|.*?)+)}\s*$@sm;
+    my $authors=$1;
+    if ($authors) {
+	# take care of "et al."...
+	$authors =~ s/(\s+et\.?\s+al\.?)\s*$//;
+	my $etal=$1;
+	$etal="" if (!defined ($etal));
+
+	my @authorlist=parse_authors($self, $authors);
+
+	foreach my $author (@authorlist) {
+	    # Add each name to set of Authors
+	    $doc_obj->add_utf8_metadata ($cursection, "Author", $author);
+	}
+
+	# Only want at most one "and" in the Creator field
+	my $creator_str="";
+	if (scalar(@authorlist) > 2) {
+	    my $lastauthor=pop @authorlist;
+	    $creator_str=join(', ', @authorlist);
+	    $creator_str.=" and $lastauthor";
+	} else { # 1 or 2 authors...
+	    $creator_str=join(" and ",@authorlist);
+	}
+	$creator_str.=$etal; # if there was "et al."
+    	$doc_obj->add_utf8_metadata($cursection, "Creator", $creator_str);
+    }
+    ### end of author metadata ###
+
+    ###### process latex for the main text ######
+    $$textref =~ s/^.*?\\begin{document}//s;
+    $$textref =~ s/\\end{document}.*?$//s;
+    $$textref = $self->process_latex("-html",$$textref);
+    $doc_obj->add_utf8_text($cursection, $$textref);
+
+    return 1;
+}
+
+
+# returns a list of author names
+sub parse_authors {
+    my $self=shift;
+    my $authors=shift;
+
+    my $outhandle=$self->{'outhandle'};
+
+    $authors =~ s/\n/ /g; # remove newlines
+	
+    # some people do this for affiliation footnote/dagger
+    $authors =~ s@\$.*?\$@@g; # remove maths from author :(
+
+    # und here for german language...
+    # don't use brackets in pattern, else the matched bit becomes
+    # an element in the list!
+    my @authorlist = split(/\s+and\s+|\s+und\s+/, $authors);
+    my @formattedlist = ();
+    foreach my $author (@authorlist) {
+	$author =~ s/\s*$//; 
+	$author =~ s/^\s*//; 
+	# Reformat and add author name
+	next if $author=~ /^\s*$/;
+
+	# names are "First von Last", "von Last, First"
+	# or "von Last, Jr, First". See the "BibTeXing" manual, page 16
+	my $first="";
+	my $vonlast="";
+	my $jr="";
+	    
+	if ($author =~ /,/) {
+	    my @parts=split(/,\s*/, $author);
+	    $first = pop @parts;
+	    if (scalar(@parts) == 2) {
+		$jr = pop @parts;
+	    }
+	    $vonlast=shift @parts;
+	    if (scalar(@parts) > 0) {
+		print $outhandle $self->{'plugin_type'} .
+		    ": couldn't parse name $author\n";
+		# but we continue anyway...
+	    }
+	} else { # First von Last
+	    my @words = split(/ /, $author);
+	    while (scalar(@words) > 1 && $words[0] !~ /^[a-z]{2..}/) {
+		$first .= " " . shift (@words);
+	    }
+	    $first =~ s/^\s//;
+	    $vonlast = join (' ', @words); # whatever's left...
+	}
+	my $von="";
+	my $last="";
+	if ($vonlast =~ m/^[a-z]/) { # lowercase implies "von"
+	    $vonlast =~ s/^(([a-z]\w+\s+)+)//;
+	    $von = $1;
+	    if (!defined ($von)) {
+		# some non-English names do start with lowercase
+		# eg "Marie desJardins". Also we can get typos...
+		print $outhandle "BibTexPlug: couldn't parse surname $vonlast\n";
+		$von="";
+		if ($vonlast =~ /^[a-z]+$/) {
+		    # if it's all lowercase, uppercase 1st.
+		    $vonlast =~ s/^(.)/\u$1/;
+		}
+	    }
+	    $von =~ s/\s*$//;
+	    $last=$vonlast;
+	} else {
+	    $last=$vonlast;
+	}
+	my $wholename="$first $von $last $jr";
+	$wholename =~ s/ $//; $wholename =~ s/\s+/ /g;
+#	my $fullname = "$last";
+#	$fullname .= " $jr" if ($jr);
+#	$fullname .= ", $first";
+#	$fullname .= " $von" if ($von);
+	push (@formattedlist, $wholename);
+    }
+    return @formattedlist;
+}
+
+
+## following functions based on bibtex plugin ##
+# not actually used at the moment, but might be useful in future?
+sub expand_month {
+    my $text=shift;
+
+    # bibtex style files expand abbreviations for months.
+    # Entries can contain more than one month (eg ' month = jun # "-" # aug, ')
+    $text =~ s/jan/_textmonth01_/g;
+    $text =~ s/feb/_textmonth02_/g;
+    $text =~ s/mar/_textmonth03_/g;
+    $text =~ s/apr/_textmonth04_/g;
+    $text =~ s/may/_textmonth05_/g;
+    $text =~ s/jun/_textmonth06_/g;
+    $text =~ s/jul/_textmonth07_/g;
+    $text =~ s/aug/_textmonth08_/g;
+    $text =~ s/sep/_textmonth09_/g;
+    $text =~ s/oct/_textmonth10_/g;
+    $text =~ s/nov/_textmonth11_/g;
+    $text =~ s/dec/_textmonth12_/g;
+
+    return $text;
+}
+
+
+# If you want basic html formatting (eg \emph -> <em>, \bf, etc), give "-html"
+# as the first argument to this function.
+#
+# Convert accented characters, remove { }, interprete some commands....
+# Note!! This is not comprehensive! Also assumes Latin -> Unicode!
+
+# Also, it sucks quite a bit for complicated/nested commands since it doesn't
+# match { with the corresponding }, only the nearest }
+
+sub process_latex {
+    my $self=shift;
+    my $text=shift;
+
+    my $outhandle=$self->{'outhandle'};
+
+    my $html_markup=0;
+    if ($text =~ /^\-html/) {
+	$html_markup=1;
+	$text=shift;
+    }
+
+    if (! $text) {
+	return $text;
+    }
+    # escape html-sensitive characters
+    $text =~ s@&@&amp;@g;
+    $text =~ s@<@&lt;@g;
+    $text =~ s@>@&gt;@g;
+ 
+    # do this before accents, since \= means something different in tabbing
+    # also \> is a tab stop too, and \\ is newline
+    sub do_tabbing {
+	my $tabbing=shift;
+	$tabbing =~ s!^.*\\kill\s*$!!mg; # \kill sets tab stops, kills line
+	$tabbing =~ s~\\(?:=|&gt;)~\xc2\xa0~g; # replace with nbsp
+	$tabbing =~ s~[\\][\\](?:\[.*?\])?\s*$~<br/>~mg;
+	return "<br/>" . $tabbing . "<br/>\n";
+    }
+    $text =~ s@\\begin{tabbing}(.*?)\\end{tabbing}@do_tabbing($1)@ges;
+    sub do_tabular {
+	my $tabular=shift;
+	$tabular =~ s~(?<!\\)\s*&amp;\s*~</td><td>~g;
+	$tabular =~ s~[\\][\\]\s*~</td></tr>\n <tr><td>~g;
+	$tabular =~ s~\\hline~~g; # for now...
+	$tabular =~ s~<td>\s*\\multicolumn{(\d+)}{.*?}~<td colspan="$1">~g;
+	return "<table border=\"1\">\n <tr><td>"
+	    . $tabular . "</td></tr></table>\n";
+    }
+    $text =~ s@\\begin{tabular}(?:\[.*?\])?{.*?}(.*?)\\end{tabular} @
+    		do_tabular($1)  @xges;
+
+    $text =~ s@[\\][\\]\s*\n@ @g; # fold lines ending with \\
+
+    # process maths mode before accents... things like \, mean different!
+    # maths mode
+    $text =~ s@\$\$(.*?)\$\$ 
+	@ process_latex_math($html_markup,$1)
+	@xsge; # multi-line maths: $$ .... $$
+
+    $text =~ s@([^\\])\$(.*?[^\\])\$
+	@$1.process_latex_math($html_markup,$2)@xsge;
+
+
+    # is this an amstext environment, or just custom for that input file?
+    $text =~ s@\\begin{(algorithm)}(.*?)\\end{\1}@remove_equals($2)@ges;
+
+    # convert latex-style accented characters.
+    $self->latex_accents_to_utf8(\$text);
+
+    # replace quotes with utf-8
+
+    $text =~ s/``/\xe2\xc0\x9c/g; # Latex-specific, left-dbl quote (&ldquo;)
+    $text =~ s/''/\xe2\xc0\x9d/g; # Latex-specific, right-dbl quote (&rdquo;)
+    $text =~ s/`/\xe2\xc0\x98/g; # single left quote
+    $text =~ s/'/\xe2\xc0\x99/g; # single right quote
+
+    ###### remove/replace latex commands ######
+    ### commands that expand to something that gets displayed ###
+    $text =~ s~\\ldots~&hellip;~g;
+    $text =~ s~\\hrule~<hr/>\n~g;
+    $text =~ s~\\maketitle~ ~;
+    ### space commands ###
+    $text =~ s~\\[vh]skip\s+\S+~~g;
+    $text =~ s~\\vspace\*?{.*?}~<div>&nbsp;</div>~g; # vertical space
+    $text =~ s~\\\w+skip~ ~g; # \smallskip \medskip \bigskip \baselineskip etc
+    $text =~ s~\\noindent\b~~g;
+    # newpage, etc
+    $text =~ s~\\(?:clearemptydoublepage|newpage)~~g;
+    ### counters, contents, environments, labels, etc ###
+    $text =~ s~\\(?:addcontentsline){.*?}{.*?}{.*}~~g;
+    $text =~ s~\s*\\begin{itemize}\s*~\n<ul>\n~g;
+    $text =~ s~\s*\\end{itemize}\s*~</li></ul>\n~g;
+    $text =~ s~\s*\\begin{enumerate}\s*~<ol>\n~g;
+    $text =~ s~\s*\\end{enumerate}\s*~</li></ol>\n~g;
+    if ($text =~ s~\s*\\item~</li>\n<li>~g) {
+	# (count for first list item)
+	$text =~ s~<([ou])l>\s*</li>\s*~<$1l>~g;
+    }
+    $text =~ s~\\(?:label|begin|end){.*?}\s*\n?~ ~g; # remove tag and contents
+    $text =~ s~\\(?:tableofcontents|listoffigures)~ ~g;
+    ### font sizes/styles ###
+    $text =~ s~\\(?:tiny|small|footnotesize|normalsize|large|Large|huge|Huge)\b~~g;
+
+    if ($html_markup) {
+	$text =~ s~\\section\*?{([^\}]+)}\s*\n?~<H1>$1</H1>\n~g;
+	$text =~ s~\\subsection\*?{(.*?)}\s*\n?~<H2>$1</H2>\n~g;
+	$text =~ s~{\\tt\s*(.*?)}~<tt>$1</tt>~g;
+	$text =~ s~\\(?:texttt|tt|ttseries)\s*{(.*?)}~<tt>$1</tt>~g;
+	$text =~ s~\\emph{(.*?)}~<em>$1</em>~g;
+	$text =~ s~{\\(?:em|it)\s*(.*?)}~<em>$1</em>~g;
+	$text =~ s~{\\(?:bf|bfseries)\s*(.*?)}~<strong>$1</strong>~g;
+	$text =~ s~\\(?:textbf|bf|bfseries)\s*{(.*?)}~<strong>$1</strong>~g;
+    } else {
+	# remove tags for text-only
+	$text =~ s~\\(?:textbf|bf|bfseries|em|emph|tt|rm|texttt)\b~ ~g;
+    }
+    $text =~ s ~ {\\sc\s+(.*?)} ~
+		{<span style="font-variant:\ small-caps">$1</span>} ~gx;
+    # ignore these font tags (if there are any left)
+    # sf is sans-serif
+    $text =~ s~\\(?:mdseries|textmd|bfseries|textbf|sffamily|sf|sc)\b~ ~;
+    #### end font-related stuff ####
+
+    ### remove all other commands with optional arguments... ###
+    # don't remove commands without { }....
+    # $text =~ s~\\\w+(\[.*?\])?\s*~~g;
+    # $text =~ s~\\noopsort{[^}]+\}~~g;
+    # verbatim
+    $text =~ s~\\verb(.)(.*?)\1~verb_text($1)~ge;
+    # remove tags, keep contents for \tag[optional]{contents}
+    while ($text =~ s~\\\w+(\[.*?\])?{([^}]+)}~$2 ~g) {;} # all other commands
+    
+    # remove latex groupings { } (but not \{ or \} )
+    while ($text =~ s/([^\\])[\{\}]/$1/g) {;} # needed for "...}{..."
+    $text =~ s/^\{//; # remove { if first char
+
+    # latex characters
+    # spaces - nobr space (~), opt break (\-), append ("#" - bibtex only)
+    $text =~ s/([^\\])~+/$1 /g; # non-breaking space  "~"
+    # optional break "\-"
+    if ($text =~ m/[^&]\#/) { # concat macros (bibtex) but not HTML codes
+	# the non-macro bits have quotes around them - we just remove quotes
+	# XXX bibtex and latex differ here (for the '#' char)...
+	$text =~ s/([^&])[\"\#]/$1/g;
+    }
+    # dashes. Convert (m|n)-dash into single dash for html.
+    $text =~ s~\-\-+~\-~g;
+
+    # quoted { } chars
+    $text =~ s~\\{~{~g;
+    $text =~ s~\\}~}~g;
+
+    # spaces
+    $text =~ s~\\ ~ ~g;
+
+    # finally to protect against macro language...
+    # greenstone-specific
+    $text =~ s~\[~&\#91;~g;
+    $text =~ s~\]~&\#93;~g;
+    $text =~ s~(?<!\\)([\\_])~\\$1~g;
+
+    if ($html_markup) {
+	$text =~ s~\n{2,}~\n</p>\n<p>~g;
+	return "<p>$text</p>";
+    }
+
+    return $text;
+}
+
+# only used by process_latex for \verb....
+sub verb_text {
+    my $verbatim=shift;
+    $verbatim =~ s/([{}_])/\\$1/g;
+    return $verbatim;
+}
+# only used by process_latex_math
+# returns a unicode char if applicable, otherwise ascii
+sub math_fraction {
+    my $num=$1;
+    my $denom=$2;
+
+    if ($num==1 && $denom==2) {return chr(0xc2).chr(0xbd)}
+    if ($num==1 && $denom==4) {return chr(0xc2).chr(0xbc)}
+    if ($num==3 && $denom==4) {return chr(0xc2).chr(0xbe)}
+    return "$num/$denom";
+}
+
+sub process_latex_math {
+
+    my $text = pop; # if given one or two args, this is the last one...
+    my $html_markup=pop; # if given two args, this is the first one else undef
+
+    $text =~ s~\\,~ ~g; # forces a space?
+    $text =~ s~\\infty~infinity~g;             # or unicode 0x221E...
+
+# use this one when more things can read 3-byte utf8 values like this!
+#    $text =~ s~\\cup\b~\xe2\xc8\xaa~g; # union operator - unicode 0x222a
+    $text =~ s~\\cup\b~ U ~g;
+
+    $text =~ s~\\frac\s*{(.+?)}{(.+?)}~math_fraction($1,$2)~ge;
+
+    if ($html_markup) {
+	$text =~ s~\^{(.*?)}~<sup>$1</sup>~g;  # a^b superscript
+	$text =~ s~\^([^\{])~<sup>$1</sup>~g;
+	$text =~ s~\_{(.*?)}~<sub>$1</sub>~g;  # a_b subscript
+	$text =~ s~\_([^\{])~<sub>$1</sub>~g;
+	
+	$text =~ s~\\ldots~&hellip;~g;         # use html named entity for now
+
+	# put all other command names in italics for now
+	$text =~ s~\\([\w]+)~<i>$1</i> ~g;
+    }
+
+    # special cases, for some input files
+    if ($text =~ m~^\\\w+$~) {
+	$text="{" . $text . "}";
+    }
+
+    return $text;
+}
+
+
+
+sub latex_accents_to_utf8 {
+
+    # note - this is really ugly, but it works. There may be a prettier way
+    # of mapping latex accented chars to utf8, but we just brute force it here.
+    # Also, this isn't complete - not every single possible accented letter
+    # is in here yet, but most of the common ones are.
+
+    my %utf8_chars =
+	(
+	 # acutes
+	 '\'a' => chr(0xc3).chr(0xa1),
+	 '\'c' => chr(0xc4).chr(0x87),
+	 '\'e' => chr(0xc3).chr(0xa9),
+	 '\'i' => chr(0xc3).chr(0xad),
+	 '\'l' => chr(0xc3).chr(0xba),
+	 '\'n' => chr(0xc3).chr(0x84),
+	 '\'o' => chr(0xc3).chr(0xb3),
+	 '\'r' => chr(0xc5).chr(0x95),
+	 '\'s' => chr(0xc5).chr(0x9b),
+	 '\'u' => chr(0xc3).chr(0xba),
+	 '\'y' => chr(0xc3).chr(0xbd),
+	 '\'z' => chr(0xc5).chr(0xba),
+	 # graves
+	 '`a' => chr(0xc3).chr(0xa0),
+	 '`A' => chr(0xc3).chr(0x80),
+	 '`e' => chr(0xc3).chr(0xa8),
+	 '`E' => chr(0xc3).chr(0x88),
+	 '`i' => chr(0xc3).chr(0xac),
+	 '`I' => chr(0xc3).chr(0x8c),
+	 '`o' => chr(0xc3).chr(0xb2),
+	 '`O' => chr(0xc3).chr(0x92),
+	 '`u' => chr(0xc3).chr(0xb9),
+	 '`U' => chr(0xc3).chr(0x99),
+	 # circumflex
+	 '^a' => chr(0xc3).chr(0xa2),
+	 '^A' => chr(0xc3).chr(0x82),
+	 '^c' => chr(0xc4).chr(0x89),
+	 '^C' => chr(0xc4).chr(0x88),
+	 '^e' => chr(0xc3).chr(0xaa),
+	 '^E' => chr(0xc3).chr(0x8a),
+	 '^g' => chr(0xc4).chr(0x9d),
+	 '^G' => chr(0xc4).chr(0x9c),
+	 '^h' => chr(0xc4).chr(0xa5),
+	 '^H' => chr(0xc4).chr(0xa4),
+	 '^i' => chr(0xc3).chr(0xae),
+	 '^I' => chr(0xc3).chr(0x8e),
+	 '^j' => chr(0xc4).chr(0xb5),
+	 '^J' => chr(0xc4).chr(0xb4),
+	 '^o' => chr(0xc3).chr(0xb4),
+	 '^O' => chr(0xc3).chr(0x94),
+	 '^s' => chr(0xc5).chr(0x9d),
+	 '^S' => chr(0xc5).chr(0x9c),
+	 '^u' => chr(0xc3).chr(0xa2),
+	 '^U' => chr(0xc3).chr(0xbb),
+	 '^w' => chr(0xc5).chr(0xb5),
+	 '^W' => chr(0xc5).chr(0xb4),
+	 '^y' => chr(0xc5).chr(0xb7),
+	 '^Y' => chr(0xc5).chr(0xb6),
+	 
+	 # diaeresis
+	 '"a' => chr(0xc3).chr(0xa4),
+	 '"A' => chr(0xc3).chr(0x84),
+	 '"e' => chr(0xc3).chr(0xab),
+	 '"E' => chr(0xc3).chr(0x8b),
+	 '"i' => chr(0xc3).chr(0xaf),
+	 '"I' => chr(0xc3).chr(0x8f),
+	 '"\\\\i' => chr(0xc3).chr(0xaf),
+	 '"\\\\I' => chr(0xc3).chr(0x8f),
+	 '"o' => chr(0xc3).chr(0xb6),
+	 '"O' => chr(0xc3).chr(0x96),
+	 '"u' => chr(0xc3).chr(0xbc),
+	 '"U' => chr(0xc3).chr(0x9c),
+	 '"y' => chr(0xc3).chr(0xbf),
+	 '"Y' => chr(0xc3).chr(0xb8),
+	 # tilde
+	 '~A' => chr(0xc3).chr(0x83),
+	 '~N' => chr(0xc3).chr(0x91),
+	 '~O' => chr(0xc3).chr(0x95),
+	 '~a' => chr(0xc3).chr(0xa3),
+	 '~n' => chr(0xc3).chr(0xb1),
+	 '~o' => chr(0xc3).chr(0xb5),
+	 # caron - handled specially
+	 # double acute
+	 # ring
+	 # dot
+	 '.c' => chr(0xc4).chr(0x8b),
+	 '.C' => chr(0xc4).chr(0x8a),
+	 '.e' => chr(0xc4).chr(0x97),
+	 '.E' => chr(0xc4).chr(0x96),
+	 '.g' => chr(0xc4).chr(0xa1),
+	 '.G' => chr(0xc4).chr(0xa0),
+	 '.I' => chr(0xc4).chr(0xb0),
+	 '.z' => chr(0xc5).chr(0xbc),
+	 '.Z' => chr(0xc5).chr(0xbb),
+	 # macron
+	 '=a' => chr(0xc4).chr(0x81),
+	 '=A' => chr(0xc4).chr(0x80),
+	 '=e' => chr(0xc4).chr(0x93),
+	 '=E' => chr(0xc4).chr(0x92),
+	 '=i' => chr(0xc4).chr(0xab),
+	 '=I' => chr(0xc4).chr(0xaa),
+	 '=o' => chr(0xc4).chr(0x8d),
+	 '=O' => chr(0xc4).chr(0x8c),
+	 '=u' => chr(0xc4).chr(0xab),
+	 '=U' => chr(0xc4).chr(0xaa),
+	 
+	 # stroke - handled specially - see below
+	 
+	 # cedilla - handled specially
+	 );
+    
+# these are one letter latex commands - we make sure they're not a longer
+# command name. eg {\d} is d+stroke, so careful of \d
+    my %special_utf8_chars = 
+	(
+	 # breve
+	 'u g' => chr(0xc4).chr(0x9f),
+	 'u G' => chr(0xc4).chr(0x9e),
+	 'u i' => chr(0xc4).chr(0xad),
+	 'u I' => chr(0xc4).chr(0xac),
+	 'u o' => chr(0xc5).chr(0x8f),
+	 'u O' => chr(0xc5).chr(0x8e),
+	 'u u' => chr(0xc5).chr(0xad),
+	 'u U' => chr(0xc5).chr(0xac),
+	 'u z' => chr(0xc5).chr(0xbe), # !!! no such char, but common mistake
+	 'u Z' => chr(0xc5).chr(0xbd), # used instead of v Z !!!
+	 # caron
+	 'v c' => chr(0xc4).chr(0x8d),
+	 'v C' => chr(0xc4).chr(0x8c),
+	 'v n' => chr(0xc5).chr(0x88),
+	 'v N' => chr(0xc5).chr(0x87),
+	 'v s' => chr(0xc5).chr(0xa1),
+	 'v S' => chr(0xc5).chr(0xa5),
+	 'v z' => chr(0xc5).chr(0xbe),
+	 'v Z' => chr(0xc5).chr(0xbd),
+	 # cedilla
+	 'c c' => chr(0xc3).chr(0xa7),
+	 'c C' => chr(0xc3).chr(0x87),
+	 'c g' => chr(0xc4).chr(0xa3),
+	 'c G' => chr(0xc4).chr(0xa2),
+	 'c k' => chr(0xc4).chr(0xb7),
+	 'c K' => chr(0xc4).chr(0xb6),
+	 'c l' => chr(0xc4).chr(0xbc),
+	 'c L' => chr(0xc4).chr(0xbb),
+	 'c n' => chr(0xc5).chr(0x86),
+	 'c N' => chr(0xc5).chr(0x85),
+	 'c r' => chr(0xc5).chr(0x97),
+	 'c R' => chr(0xc5).chr(0x96),
+	 'c s' => chr(0xc5).chr(0x9f),
+	 'c S' => chr(0xc5).chr(0x9e),
+	 'c t' => chr(0xc5).chr(0xa3),
+	 'c T' => chr(0xc5).chr(0xa2),
+	 # double acute / Hungarian accent
+	 'H O' => chr(0xc5).chr(0x90),
+	 'H o' => chr(0xc5).chr(0x91),
+	 'H U' => chr(0xc5).chr(0xb0),
+	 'H u' => chr(0xc5).chr(0xb1),
+	 
+	 # stroke 
+	 'd' => chr(0xc4).chr(0x91),
+	 'D' => chr(0xc4).chr(0x90),
+	 'h' => chr(0xc4).chr(0xa7),
+#	 'H' => chr(0xc4).chr(0xa6), # !! this normally(!!?) means Hung. umlaut
+	 'i' => chr(0xc4).chr(0xb1), # dotless lowercase i
+	 'l' => chr(0xc5).chr(0x82),
+	 'L' => chr(0xc5).chr(0x81),
+	 'o' => chr(0xc3).chr(0xb8),
+	 'O' => chr(0xc3).chr(0x98),
+	 't' => chr(0xc5).chr(0xa7),
+	 'T' => chr(0xc5).chr(0xa6),
+
+         # other special chars
+         'ss' => chr(0xc3).chr(0x9f), # german ss/szlig/sharp s
+         'aa' =>,chr(0xc3).chr(0xa5), # scandanavian/latin a with ring
+	 );
+
+    my $self=shift;
+    my $textref=shift;
+
+    my $outhandle=$self->{'outhandle'};
+    my $text=$$textref;
+    
+    # remove space (if any) between \ and letter to accent (eg {\' a})
+    $text =~ s!(\\[`'="^~\.])\s(\w)\b!$1$2!g;   # for emacs indenting... `]);
+
+    # remove {} around a single character (eg \'{e})
+    $text =~ s!(\\[`'="^~\.]){(\w)}!{$1$2}!g;  # for emacs indenting... `]);
+
+    ## only in bibtex... not in latex proper?!
+    ### \, is another way of doing cedilla \c
+    ##$text =~ s~\\,(.)~\\c $1~g;
+
+    # remove {} around a single character for special 1 letter commands -
+    # need to insert a space. Eg \v{s}  ->  {\v s}
+    $text =~ s~(\\[uvcH]){(\w)}~{$1 $2}~g;
+
+    # only do if the text contains a '\' character. 
+    if ($text =~ m|\\|) {
+	# "normal" accents - ie non-alpha latex tag
+	# xxx used to have ([\w]\b)@ (for word boundary)
+	while ($text =~ m/\\([`'="^~\.])([\w])/) {      # for emacs `])){
+	    my $tex="$1$2"; my $char="$2";
+	    my $replacement=$utf8_chars{$tex};
+	    if (!defined($replacement)) {
+		$text =~ m~(.{20}\\\Q$tex\E.{20})~s;
+		print $outhandle . $self->{'plugin_type'} .
+		    ": Warning: unknown latex accent \"$tex\""
+		    . " in \"$1\"\n";
+		$replacement=$char;
+	    }
+	    $text =~ s/\\\Q$tex/$replacement/g;
+	}
+
+        # where the following letter matters (eg "sm\o rrebr\o d", \ss{})
+        # only do the change if immediately followed by a space, }, {, or \
+	# one letter accents ( + ss / aa)
+        while ($text =~ m~\\([DdhiLlOoTt]|ss|aa)[{}\s\"\\]~) {
+	    my $tex=$1;
+	    my $replacement=$special_utf8_chars{$tex};
+	    if (!defined($replacement)) {
+		$text =~ m~(.{20}\\\Q$tex\E.{20})~s;
+		print $outhandle $self->{'plugin_type'} .
+		    ": Warning: unknown latex accent \"$tex\""
+		    . " in \"$1\"\n";
+		$replacement=$tex;
+	    }
+	    ($text =~ s/{\\$tex}/$replacement/g) or
+		$text =~ s/\\$tex([{}\s\"\\])/$replacement$1/g;
+
+	}
+
+	# one letter latex accent commands that affect following letter
+        while ($text =~ m~\\([uvcH]) ([\w])~) {
+          my $tex="$1 $2"; my $char="$2";
+          my $replacement=$special_utf8_chars{$tex};
+          if (!defined($replacement)) {
+	      $text =~ m~(.{20}\\\Q$tex\E.{20})~s;
+	      print  $outhandle $self->{'plugin_type'} .
+		  ": Warning: unknown latex accent \"$tex\""
+		  . " in \"$1\"\n";
+	      $replacement=$char;
+	  }
+          $text =~ s/\\$tex/$replacement/g;
+        }
+    }
+    $textref=\$text;
+}
+
+
+# modules must return true
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MACROPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MACROPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MACROPlug.pm	(revision 10506)
@@ -0,0 +1,536 @@
+###########################################################################
+#
+# MACROPlug plugin - to process .dm files for language translation
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package MACROPlug;
+
+use BasPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @MACROPlug::ISA = ('BasPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "MACROPlug",
+		'desc'     => "{MACROPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub load_language_table
+{
+    my $lang_table = {};
+
+    my $lang_fname = util::filename_cat($ENV{'GSDLHOME'},"tmp","lang",
+					"package_forms","languages.log");
+    open (LANGFILE, "<$lang_fname") 
+	|| die ("Unable to open $lang_fname: $!\n");
+
+    my $full_name;
+    my $abbr_name;
+
+    while (defined ($full_name=<LANGFILE>)) {
+	chomp($full_name);
+	
+	$abbr_name = <LANGFILE>;
+	chomp($abbr_name);
+
+	$lang_table->{$full_name} = $abbr_name;
+
+	my $fourchar_name = substr($full_name,0,4);
+	if (!defined $lang_table->{$fourchar_name}) {
+	    $lang_table->{$fourchar_name} = $abbr_name;
+	}
+	else {
+	    print STDERR "Warning: Clash on four character abbreviation for language $fourchar_name\n";
+	}
+    }
+
+    close LANGFILE;
+
+    return $lang_table;
+}
+
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    # $self->{'lang_abbr'} = load_language_table();
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.dm$^;
+}
+
+
+sub read {
+    my $self = shift (@_);  
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+
+    my $lang_table = $self->{'lang_abbr'};
+    my $fn = $file;
+    $fn =~ s/.*\/(.*)\..*/$1/;
+    $fn =~ s/\d+$//; # remove any digits from end of filename
+
+    my $filename = $file;
+    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+
+    if ((!-d $filename) && ($file !~ m/doc.xml$/) && (!defined $lang_table->{$fn})) {
+	print $outhandle "MACROPlug: blocking $file\n" 
+	    if $self->{'verbosity'} > 2;
+	$self->{'num_blocked'} ++;
+	return 0;
+    }
+
+    return $self->SUPER::read(@_);
+}
+
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    print STDERR "<Processing n='$file' p='MACROPlug'>\n" if ($gli);
+    print $outhandle "MACROPlug: processing $file\n" 
+	if $self->{'verbosity'} > 1;
+   
+    my $thissection = $doc_obj->get_top_section();
+
+    $self->extract_macronames (\$textref, $doc_obj, $thissection, $file);
+    # we need to escape the escape character, or else mg will convert into
+    # eg literal newlines, instead of leaving the text as '\n'
+    
+    
+    my ($filemeta) = $file =~ /([^\\\/]+)$/;
+    $doc_obj->add_utf8_metadata($thissection, "Title", &ghtml::dmsafe($filemeta));
+    
+    # FileFormat metadata
+    $doc_obj->add_metadata($thissection, "FileFormat", "MACRO");
+    $doc_obj->add_metadata($thissection, "FileSize", (-s $file));
+
+    return 1;
+}
+
+
+sub extract_macronames {
+
+    my $self = shift(@_);
+
+    my ($textref, $doc_obj, $thissection, $file) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    print $outhandle " extracting macronames ...\n"
+	if ($self->{'verbosity'}>3);
+    
+    my @textarray = split ("\n", $$$textref)
+	if ($self->{'verbosity'}>3);
+
+    my $macro_text = "";
+    my $image_macro = "false";
+    my $norm_macro = "false";
+    my $currpackage = "";
+    
+    #print STDERR "FILE@@@@@ $file\n";
+
+    #foreach my $ta (@textarray) {
+	
+    for (my $k = 0; $k < scalar(@textarray); $k++) {
+	
+	my $ta = $textarray[$k];
+
+        #print STDERR "$ta\n" if ($file =~ m/port/);
+
+	if ($ta =~ m/^package /) {
+	    $currpackage = $ta;
+	    chomp($currpackage);
+	    $currpackage =~ s/^package //;
+	}
+	
+	
+	elsif ($image_macro eq "true") {
+	    unless ($ta =~ m/\S+/) {
+		$image_macro = "false";
+		
+		$macro_text =~ s/\_/\\_/osg; # for dm (we have a convention of starting macros with _
+	    
+		#print STDERR "$macro_text\n\n" if ($file =~ m/spanish/);
+
+		$doc_obj->add_utf8_text($thissection, $macro_text);
+
+		my @names = split(/\s*\#\#\s*/, $macro_text);
+		
+		my ($title) = $names[1];
+		
+		if (length($title) > 100) {
+		    $title = substr ($title, 0, 100) . "...";
+		}
+
+		$title =~ s/</\&lt;/g;
+		$title =~ s/>/\&gt;/g;
+		
+		#print STDERR "$title\n" if ($file =~ m/port/);
+
+		$doc_obj->add_utf8_metadata ($thissection, "SecTitle", $title);
+		$macro_text = "";
+	    }
+	    $ta .= "<br>";
+	    $macro_text .= $ta;
+	    
+	}
+
+	elsif ($norm_macro eq "true") {
+
+	    $macro_text .= $ta;
+
+	    if ($ta =~ m/\}\s*(\#.*)*\Z/) {
+		
+		$norm_macro = "false";
+		
+		$macro_text =~ s/\A(_\w+_)\s//;
+		
+		#print STDERR "$macro_text\n" if($file =~ m/spanish/i);
+
+		$doc_obj->add_utf8_text($thissection, $macro_text);
+		
+		my ($title) = $macro_text;
+		
+		$title =~ s/\_/\\_/osg;
+		$title =~ s/\{//;
+		$title =~ s/\}\s*(\#.*)*\Z//;
+		$title =~ s/\<br\>|\<p\>/\n/osg;
+		$title =~ s/\n/ /osg;
+		$title =~ s/</\&lt;/g;
+		$title =~ s/>/\&gt;/g;
+
+		$title =~ s/\(/\\\(/g;
+		$title =~ s/\)/\\\)/g;
+		
+		if (length($title) > 100) {
+		    $title = substr ($title, 0, 100) . "...";
+		}
+		#print STDERR "$title\n\n\n" if($file =~ m/spanish/i);
+
+		$doc_obj->add_utf8_metadata ($thissection, "SecTitle", $title);
+		$macro_text = "";
+	    }
+	    
+	}
+	elsif(($ta =~ m/\A(_\w+_)\s*/) && ($image_macro eq "false")) {
+	    
+	    my $new_macro = $1;
+	    
+	    my $new_cursection = $doc_obj->get_next_child($thissection);
+	    $thissection = $doc_obj->insert_section("");
+	    
+	    $new_macro =~ s/\_/\\_/osg;
+	    
+	    $new_macro = $currpackage . "::" . $new_macro;
+	    
+	    #print STDERR "$new_macro\n" if ($file =~ m/spanish/);
+
+	    $doc_obj->add_utf8_metadata ($thissection, "Macroname", $new_macro);
+	    
+	    $macro_text = $ta;
+	    
+	    if ($ta =~ m/\}\s*(\#.*)*\Z/) {
+		
+		$macro_text =~ s/\A(_\w+_)\s//;
+		$macro_text =~ s/\n/ /osg;
+		
+		#print STDERR "$macro_text\n" if($file =~ m/spanish/i);
+
+		$doc_obj->add_utf8_text($thissection, $macro_text);
+		
+		my ($title) = $macro_text;
+		$title =~ s/\{//;
+		$title =~ s/\}\s*(\#.*)*\Z//;
+		$title =~ s/\<br\>|\<p\>/\n/osg;
+		$title =~ s/\n/ /osg;
+		$title =~ s/</\&lt;/g;
+		$title =~ s/>/\&gt;/g;
+		
+		if (length($title) > 100) {
+		    $title = substr ($title, 0, 100) . "...";
+		}
+		#print STDERR "$title\n\n\n" if($file =~ m/spanish/i);
+
+		$doc_obj->add_utf8_metadata ($thissection, "SecTitle", $title);
+	    }
+	    else {
+		$norm_macro = "true";
+	    }
+	
+	    $macro_text = "";
+	    $macro_text .= $ta;
+	}
+	
+	#line in format ## "sometext" ## macro ## macroname ##
+	elsif ($ta =~ m/^\#\# .*/) {
+	    my $macroname = $ta;
+	    $image_macro = "true";
+	    $macro_text = "";
+
+	    #NEED S.T LIKE THIS TO PICK UP HOARY ONES OVER 2 LINES
+	    unless ($macroname =~ m/^\#\# .*\#\#/) {		
+		$macroname = $ta;
+		chomp($macroname);
+		$macro_text .= $macroname;
+		$ta .= $textarray[++$k];
+		$macroname .= $ta;
+	    }
+
+	    my @names = split(/\s*\#\#\s*/, $macroname);
+	    $macroname = $names[(scalar @names) - 1];
+	    my $key = $currpackage . "::" . $macroname; # key to the hash and the database
+
+	    my $new_cursection = $doc_obj->get_next_child($thissection);
+	    $thissection = $doc_obj->insert_section("");
+	    
+	    #print STDERR "$key \n" if ($file =~ m/(port)|(chin)|(engl)/);
+
+	    $doc_obj->add_utf8_metadata ($thissection, "Macroname", $key);
+	    
+	    $macro_text = $ta . "<br>";
+	    
+	}
+    }
+   
+    print $outhandle "done extracting macros\n"
+	if ($self->{'verbosity'}>3);
+
+}
+
+
+sub get_language_encoding_old {
+    my $self = shift (@_);
+    my ($filename) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    # read in file
+    open (FILE, $filename) || die "BasPlug::get_language_encoding could not open $filename for reading ($!)\n";
+    undef $/;
+    my $text = <FILE>;
+    $/ = "\n";
+    close FILE;
+
+    # remove <title>stuff</title> -- as titles tend often to be in English
+    # for foreign language documents
+    $text =~ s/<title>.*?<\/title>//i;
+
+    # remove all HTML tags
+    $text =~ s/<[^>]*>//sg;
+    my $results = [];
+
+    # get the language/encoding
+    $results = $self->{'textcat'}->classify(\$text);
+
+    foreach my $r (@$results) {
+	print $outhandle "Results: $r\n";
+	
+    }
+   
+    # if textcat returns 3 or less possibilities we'll use the 
+    # first one in the list - otherwise use the defaults
+    if (scalar @$results > 3) {
+	                            
+        my $lang_fname = util::filename_cat($ENV{'GSDLHOME'},"tmp","lang","package_forms",
+					    "languages.log");
+	open (LANGFILE, "<$lang_fname") or die ("Unable to open $lang_fname: $!\n");
+
+	while (<LANGFILE>) {
+	    
+	    my $line = $_;
+	    chomp($line);
+
+	    my $fn = $filename;
+	    $fn =~ s/.*\/(.*)\..*/$1/;
+
+
+	    if ($line eq $fn) {
+		print $outhandle "BINGO $line $fn\n";
+		$line = <LANGFILE>;
+		chomp($line);
+		print $outhandle "language code is $line\n";
+
+		foreach my $r (@$results) {
+		    print $outhandle "MY1 $r\n";
+
+		    my $roar = $& if($r =~ m/../);
+
+		    if ($roar eq $line) {
+			print $outhandle "WE HAVE A WINNER $r\n";
+		    }
+		}
+
+
+	    }
+	    else {
+		$line = <LANGFILE>;
+	    }
+	}
+
+	close LANGFILE;
+
+	if ($self->{'input_encoding'} ne 'auto') {
+	    if ($self->{'extract_language'} && $self->{'verbosity'}) {
+		print $outhandle "BasPlug: WARNING: language could not be extracted from $filename - ";
+		print $outhandle "defaulting to $self->{'default_language'}\n";
+	    }		
+	    return ($self->{'default_language'}, $self->{'input_encoding'});
+
+	} else {
+	    if ($self->{'verbosity'}) {
+		print $outhandle "BASPlug: WARNING: language/encoding could not be extracted from $filename - ";
+		print $outhandle "defaulting to $self->{'default_language'}/$self->{'default_encoding'}\n";
+	    }
+	    return ($self->{'default_language'}, $self->{'default_encoding'});
+	}
+    }
+    
+
+    # format language/encoding
+    my ($language, $encoding) = $results->[0] =~ /^([^-]*)(?:-(.*))?$/;
+    if (!defined $language) {
+	if ($self->{'verbosity'}) {
+	    print $outhandle "BasPlug: WARNING: language could not be extracted from $filename - ";
+	    print $outhandle "defaulting to $self->{'default_language'}\n";
+	}
+	$language = $self->{'default_language'};
+    }
+    if (!defined $encoding) {
+	if ($self->{'verbosity'}) {
+	    print $outhandle "BasPlug: WARNING: encoding could not be extracted from $filename - ";
+	    print $outhandle "defaulting to $self->{'default_encoding'}\n";
+	}
+	$encoding = $self->{'default_encoding'};
+    }
+
+    if ($encoding !~ /^(ascii|utf8|unicode)$/ &&
+	!defined $encodings::encodings->{$encoding}) {
+	if ($self->{'verbosity'}) {
+	    print $outhandle "BasPlug: WARNING: $filename appears to be encoded in an unsupported encoding ($encoding) - ";
+	    print $outhandle "using $self->{'default_encoding'}\n";
+	}
+	$encoding = $self->{'default_encoding'};
+    }
+
+    print STDERR "**** forcing encoding to be utf8\n";
+    $encoding = "utf8";
+
+    print STDERR "**** forcing language to be first two letters\n";
+    my $lfname = $filename;
+    $lfname =~ s/^.*\///;
+    $language = substr($lfname,0,2);
+
+    print $outhandle "RETURNING VALUES $language $encoding\n";
+
+    return ($language, $encoding);
+}
+
+
+sub find_language {
+    my ($self,$fn) = @_;
+
+    my $lang_table = $self->{'lang_abbr'};
+
+    if (!defined $lang_table->{$fn}) {
+
+	# try and find it with shorter string name
+	
+	my $try_len = length($fn);
+
+	while ($try_len>=4) {
+	    my $try_fn = substr($fn,0,$try_len);
+
+	    if (defined $lang_table->{$try_fn}) {
+		$fn = $try_fn;
+		last;
+	    }
+	    $try_len--;
+	}
+    }
+
+    return $fn;
+}
+
+
+sub get_language_encoding {
+    my $self = shift (@_);
+    my ($filename) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $fn = $filename;
+    $fn =~ s/.*\/(.*)\..*/$1/;
+    $fn =~ s/\d+$//; # remove any digits from end of filename
+
+    my $language;
+    my $encoding = "utf8";
+
+    ## my $lang_lookup = $self->find_language($fn);
+
+    my $lang_table = $self->{'lang_abbr'};
+
+    if (!defined $lang_table->{$fn}) {
+
+	print $outhandle "Warning: Macro file name $filename not in list of languages.\n";
+	print $outhandle "         Using default language.\n";
+	$language = $self->{'default_language'};
+    }
+    else {
+	$language = $lang_table->{$fn};
+    }
+
+    ## print $outhandle "Storing $filename as $language $encoding\n";
+
+    return ($language, $encoding);
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MARCPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MARCPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MARCPlug.pm	(revision 10506)
@@ -0,0 +1,311 @@
+###########################################################################
+#
+# MARCPlug.pm -- basic MARC plugin
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2002 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 MARCPlug;
+
+use SplitPlug;
+
+use unicode;
+use util;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @MARCPlug::ISA = ('SplitPlug');
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+}
+
+my $arguments = 
+    [ { 'name' => "metadata_mapping",
+	'desc' => "{MARCPlug.metadata_mapping}",
+	'type' => "string",
+	'deft' => "marctodc.txt",
+	'reqd' => "no" },
+      { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() },
+      { 'name' => "split_exp",
+	'desc' => "{SplitPlug.split_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_split_exp() } 
+      ];
+
+my $options = { 'name'     => "MARCPlug",
+		'desc'     => "{MARCPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "Yes",
+		'explodes' => "yes",
+		'args'     => $arguments };
+
+require MARC::Record;  
+require MARC::Batch;  
+#use MARC::Record;  
+#use MARC::Batch;
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new SplitPlug($pluginlist,$inputargs,$hashArgOptLists): new SplitPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+    my ($verbosity, $outhandle, $failhandle) = @_;
+
+    my @metadata_mapping = ();
+
+    # read in the metadata mapping file
+    my $mm_file =
+	&util::filename_cat( $ENV{'GSDLHOME'}, "etc", $self->{'metadata_mapping'} );
+
+    if (!-e $mm_file)
+    {
+
+	my $msg = "MARCPlug ERROR: Can't locate mapping file \"" .
+	    $self->{'metadata_mapping'} . "\".\n    This file should be at $mm_file\n" .
+		"    No marc files can be processed.\n";
+
+	print $outhandle $msg;
+	print $failhandle $msg;
+	$self->{'metadata_mapping'} = undef;
+	# We pick up the error in process() if there is no $mm_file
+	# If we exit here, then pluginfo.pl will exit too!
+    }
+    elsif (open(MMIN, "<$mm_file"))
+    {
+	my $l=1;
+	my $line;
+	while (defined($line=<MMIN>))
+	{
+	    chomp $line;
+	    if ($line =~ m/^(\d+)\s*->\s*(\w+)$/)
+	    {
+		my $marc_info = $1;
+		my $gsdl_info = $2;
+		my $mapping = { 'marc' => $marc_info, 'gsdl' => $gsdl_info };
+		push(@metadata_mapping,$mapping);
+	    }
+	    elsif ($line !~ m/^\#/       # allow comments (# in first column)
+		   && $line !~ m/^\s*$/) # allow blank lines
+	    {
+		print $outhandle "Parse error on line $l of $mm_file:\n";
+		print $outhandle "  \"$line\"\n";
+	    }
+	    $l++
+	}
+	close(MMIN);
+    }
+    else
+    {
+	print STDERR "Unable to open $mm_file: $!\n";
+    }
+
+    $self->{'metadata_mapping'} = \@metadata_mapping;
+
+    $self->SUPER::init(@_);
+}
+    
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)(\.marc)$^;
+}
+
+
+sub get_default_split_exp {
+    # \r\n for msdos eol, \n for unix
+    return q^\r?\n\s*\r?\n^;
+}
+
+
+
+# The bulk of this function is based on read_line in multiread.pm
+# Unable to use read_line original because it expects to get its input
+# from a file.  Here the line to be converted is passed in as a string
+
+sub to_utf8
+{
+    my $self = shift (@_);
+    my ($encoding, $line) = @_;
+
+    if ($encoding eq "iso_8859_1") {
+	# we'll use ascii2utf8() for this as it's faster than going
+	# through convert2unicode()
+	return &unicode::ascii2utf8 (\$line);
+    }
+
+    # everything else uses unicode::convert2unicode
+    return &unicode::unicode2utf8 (&unicode::convert2unicode ($encoding, \$line));
+}
+
+
+sub read_file {
+    my $self = shift (@_);
+    my ($filename, $encoding, $language, $textref) = @_;
+
+    $self->{'readfile_encoding'}->{$filename} = $encoding;
+
+    my @marc_entries = ();
+
+    if (!-r $filename)
+    {
+	my $outhandle = $self->{'outhandle'};
+	print $outhandle "Read permission denied for $filename\n" if $self->{'verbosity'};
+	return;
+    }
+
+    my $batch = new MARC::Batch( 'USMARC', $filename );
+    while ( my $marc = $batch->next ) 
+    {
+	push(@marc_entries,$marc);
+	$$textref .= $marc->as_formatted();
+	$$textref .= "\n\n"; # for SplitPlug - see default_split_exp above...
+    }
+
+    $self->{'marc_entries'}->{$filename} = \@marc_entries;
+}
+
+
+
+# do plugin specific processing of doc_obj
+# This gets done for each record found by SplitPlug in marc files.
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+    my $filename = &util::filename_cat($base_dir, $file);
+
+    if (! defined($self->{'metadata_mapping'}))
+    {
+	print $outhandle "MARCPlug: no metadata file! Can't process $file\n";
+	return undef;
+    }
+
+    print STDERR "<Processing n='$file' p='MARCPlug'>\n" if ($gli);
+    print $outhandle "MARCPlug: processing $file\n"
+	if $self->{'verbosity'} > 1;
+
+    my $cursection = $doc_obj->get_top_section();
+
+    # Add fileFormat as the metadata
+    $doc_obj->add_metadata($cursection, "FileFormat", "MARC");
+    
+    my $marc_entries = $self->{'marc_entries'}->{$filename};
+    my $marc = shift(@$marc_entries);
+
+    my $encoding = $self->{'readfile_encoding'}->{$filename};
+    $self->extract_metadata ($marc, $metadata, $encoding, $doc_obj, $cursection);
+
+    # add spaces after the sub-field markers, for word boundaries
+    $$textref =~ s/^(.{6} _\w)/$1 /gm;
+
+    # add text to document object
+    $$textref =~ s/</&lt;/g;
+    $$textref =~ s/>/&gt;/g;
+
+    $$textref = $self->to_utf8($encoding,$$textref);
+
+    print $outhandle "  Adding Marc Record:\n",substr($$textref,0,40), " ...\n"
+	if $self->{'verbosity'} > 2;
+
+    # line wrapping
+    $$textref = &wrap_text_in_columns($$textref, 64);
+    $$textref = "<pre>\n" . $$textref . "</pre>\n"; # HTML formatting...
+
+    $doc_obj->add_utf8_text($cursection, $$textref);
+
+    return 1;
+}
+
+sub wrap_text_in_columns
+{
+    my ($text, $columnwidth) = @_;
+    my $newtext = "";
+    my $linelength = 0;
+    
+    # Break the text into words, and display one at a time
+    my @words = split(/ /, $text);
+
+    foreach my $word (@words) {
+	# If printing this word would exceed the column end, start a new line
+	if (($linelength + length($word)) >= $columnwidth) {
+	    $newtext .= "\n";
+	    $linelength = 0;
+	}
+	
+	# Write the word
+	$newtext .= " $word";
+	if ($word =~ /\n/) {
+	    $linelength = 0;
+	} else {
+	    $linelength = $linelength + length(" $word");
+	}
+    }
+
+    $newtext .= "\n";
+    return $newtext;
+}
+
+
+sub extract_metadata 
+{
+    my $self = shift (@_);
+    my ($marc, $metadata, $encoding, $doc_obj, $section) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    my $metadata_mapping = $self->{'metadata_mapping'};
+    my $mm;
+    foreach $mm ( @$metadata_mapping )
+    {
+	my $marc_field = $mm->{'marc'};
+	my @metavalues = $marc->field($marc_field);
+
+	if (scalar(@metavalues)>0)
+	{
+	    my $metaname = $mm->{'gsdl'};
+	    my $metavalue;
+	    foreach $metavalue ( @metavalues )
+	    {
+		my $metavalue_str = $self->to_utf8($encoding,$metavalue->as_string());
+		$doc_obj->add_utf8_metadata ($section, $metaname, $metavalue_str);
+	    }
+	}
+    }
+}
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/METSPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/METSPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/METSPlug.pm	(revision 10506)
@@ -0,0 +1,320 @@
+###########################################################################
+#
+# METSPlug.pm
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001 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.
+#
+###########################################################################
+
+# Processes GreenstoneArchive METS documents. Note that this plugin does no
+# syntax checking (though the XML::Parser module tests for
+# well-formedness). It's assumed that the GreenstoneArchive files conform
+# to their DTD.
+
+# 28/07/04 Modified to METSPlug - CHI-YU HUANG
+
+package METSPlug;
+
+use ghtml;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+use XMLPlug;
+use XML::XPath;
+use XML::XPath::XMLParser;
+
+sub BEGIN {
+    @METSPlug::ISA = ('XMLPlug');
+}
+
+my $arguments = [
+		 ];
+my $options = { 'name'     => "METSPlug",
+		'desc'     => "{METSPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes" };
+
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)docmets\.xml$^;
+}
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new XMLPlug($pluginlist,$inputargs,$hashArgOptLists): new XMLPlug($pluginlist,$inputargs);
+
+    $self->{'section'} = "";
+    $self->{'section_level'} = 0;
+    $self->{'metadata_name'} = "";
+    $self->{'metadata_value'} = "";
+    $self->{'content'} = "";
+
+    return bless $self, $class;
+}
+
+sub xml_start_document {
+    my $self = shift (@_);
+    my ($expat, $element) =  @_;
+
+    $self->{'section'} = "";
+    $self->{'section_level'} = 0;
+    $self->{'metadata_name'} = "";
+    $self->{'metadata_value'} = "";
+    $self->{'content'} = "";
+
+    #**defined a dmdSection Table
+    $self->{'dmdSec_table'}={};
+
+    #**defined a fileSection Table
+    $self->{'fileSec_table'}={};
+
+    #***open doctxt.xml and read the data in 
+    my $filename = $self->{'filename'};
+    
+    $filename =~ s/docmets.xml$/doctxt.xml/;
+   
+    if (!open (FILEIN,"<$filename")){
+   	print STDERR "Warning: unable to open the $filename\n";
+	$self->{'xmltxt'} = "";
+    }
+    else {
+	my $xml_text = "";
+	while (defined (my $line = <FILEIN>)) {
+	    if ($line !~ m/^<!DOCTYPE.*>/) {
+		$xml_text .= $line;
+	    }
+	}
+        my $xml_parser = XML::XPath->new (xml=> $xml_text);
+	#my $xml_tree = $xml_parser->parse ($xml_text);
+
+	#eval {$self->{'parser_text'}->parse};
+	$self->{'parsed_xml'} = $xml_parser;
+    }
+    my $outhandle = $self->{'outhandle'};
+    print $outhandle "METSPlug: processing $self->{'file'}\n" if $self->{'verbosity'} > 1;
+    print STDERR "<Processing n='$self->{'file'}' p='METSPlug'>\n" if ($self->{'gli'});
+
+}
+
+sub xml_end_document {
+}
+
+sub xml_doctype {
+}
+
+sub xml_start_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+
+    $self->{'element'} = $element;
+
+    #**deal with dmdSection
+    if ($element eq "mets:dmdSec" || $element eq "gsdl3:Metadata"){    
+	$self->xml_dmd_start_tag (@_);
+    } elsif ($element eq "mets:file") {
+	$_{'ID'} =~ m/FILE(.*)/;
+	$self->{'file_Id'} = $1;
+    } elsif ($element eq "mets:FLocat"){
+	#***deal with fileSection
+	$self->xml_fileloc_start_tag (@_);
+    } elsif ($element eq "mets:div"){
+	#***deal with StrucMap Section
+	$self->xml_strucMap_start_tag (@_);
+    }
+}
+
+sub xml_dmd_start_tag {
+    my $self = shift (@_);
+    my ($expat, $element) = @_;
+
+    if ($element eq "mets:dmdSec"){
+  	my ($section_num) = ($_{'ID'} =~ m/DM(.*)/);
+	$self->{'dmdSec_table'}->{"$section_num"}=[];
+	$self->{'dmdSec_table'}->{'section_num'}=$section_num;
+    } elsif ($element eq "gsdl3:Metadata") {
+	$self->{'metadata_name'} = $_{'name'};
+    }
+}
+
+sub xml_fileloc_start_tag {
+    my $self = shift (@_);
+    my ($expat, $element) = @_;
+
+    my $xlink = $_{'xlink:href'};
+    #my ($section_num) = ($_{'ID'} =~ m/^FLOCAT(.*)$/);
+    my $section_num = $self->{'file_Id'};
+
+    return if (!defined $section_num); 
+    #**return if the section_num is not defined or not deal with the whole section (ID="default.*")
+    
+    $self->{'fileSec_table'}->{"$section_num"}=[];
+    $self->{'fileSec_table'}->{'section_num'}=$section_num;
+    
+    my ($filename,$xpath_expr)=($xlink =~ m/^file:(.*)\#xpointer\((.*)\)$/);
+    
+    my $nodeset = $self->{'parsed_xml'}->findnodes ($xpath_expr);
+    my $node_size= $nodeset->size;
+    
+    if ($node_size==0) {
+	print STDERR "Warning: no text associated with XPATH $xpath_expr\n";
+    }
+    else {
+	foreach my $node ($nodeset->get_nodelist) {
+	    my $xml_content = XML::XPath::XMLParser::as_string($node);
+	    my $unescaped_xml_content = &ghtml::unescape_html($xml_content);
+
+	    my $section_content={'section_content'=> $unescaped_xml_content};
+	    
+	    my $content_list = $self->{'fileSec_table'}->{"$section_num"};
+	    push (@$content_list, $section_content);
+	}
+    }
+}
+
+sub xml_strucMap_start_tag {
+    my $self = shift (@_);
+    my ($expat, $element) = @_;
+
+
+    my ($section_num) = ($_{'ID'} =~ m/DS(.*)/);
+
+    if ($_{'ID'} ne "DSAll"){
+	if ($self->{'section_level'}==0) {
+	    $self->open_document();
+	} else {
+	    my $doc_obj = $self->{'doc_obj'};
+	    $self->{'section'}=
+		$doc_obj->insert_section($doc_obj->get_end_child($self->{'section'}));
+	}
+	$self->{'section_level'}++;
+	
+	#***Add metadata from dmdSection
+	my $md_list = $self->{'dmdSec_table'}->{"$section_num"};
+	
+	foreach my $md_pair (@$md_list){
+	    my $metadata_name = $md_pair->{'metadata_name'};
+	    my $metadata_value = $md_pair->{'metadata_value'};
+	    $self->{'doc_obj'}->add_utf8_metadata($self->{'section'}, $metadata_name, $metadata_value);
+	}
+	
+	#*** Add content from fileSection
+	my $content_list = $self->{'fileSec_table'}->{"$section_num"};
+	
+	foreach my $section_content (@$content_list){
+	    my $content = $section_content->{'section_content'};
+	    $self->{'doc_obj'}->add_utf8_text($self->{'section'},$content);
+	}
+    }
+}
+
+sub xml_end_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+
+    if ($element eq "gsdl3:Metadata") {
+	my $section_num = $self->{'dmdSec_table'}->{'section_num'};
+	my $metadata_name=$self->{'metadata_name'};
+	my $metadata_value=$self->{'metadata_value'};
+
+	my $md_pair={'metadata_name' => $metadata_name,
+		     'metadata_value'=> $metadata_value};
+
+	my $md_list = $self->{'dmdSec_table'}->{"$section_num"};
+
+	push(@$md_list,$md_pair);
+      
+	$self->{'metadata_name'} = "";
+	$self->{'metadata_value'} = "";
+    } elsif ($element eq "mets:file"){
+	$self->{'file_id'} = "";
+    }
+    
+    
+    #*** StrucMap Section
+    if ($element eq "mets:div") {
+	$self->{'section_level'}--;
+	$self->{'section'} = $self->{'doc_obj'}->get_parent_section($self->{'section'});
+	$self->close_document() if $self->{'section_level'}==0;
+    }
+    $self->{'element'} = "";
+}
+
+sub xml_text {
+    my $self = shift(@_);
+    my ($expat) = @_; 
+
+    if ($self->{'element'} eq "gsdl3:Metadata") {
+   	$self->{'metadata_value'} .= $_;
+    }
+}
+
+sub open_document {
+    my $self = shift(@_);
+
+    # create a new document
+    $self->{'doc_obj'} = new doc ();
+    $self->{'section'} = "";
+}
+
+sub close_document {
+    my $self = shift(@_);
+    
+    # add the associated files
+    my $assoc_files = 
+	$self->{'doc_obj'}->get_metadata($self->{'doc_obj'}->get_top_section(), "gsdlassocfile");
+
+    # for when "assocfilepath" isn't the same directory that doc.xml is in...
+    my $assoc_filepath_list= $self->{'doc_obj'}->get_metadata($self->{'doc_obj'}->get_top_section(), "assocfilepath");
+
+    my $assoc_filepath=shift (@$assoc_filepath_list);
+    if (defined ($assoc_filepath)) {
+	# make absolute rather than relative...
+	$self->{'filename'} =~ m@^(.*[\\/]archives)@;
+	$assoc_filepath = "$1/$assoc_filepath/";
+    } else {
+	$assoc_filepath = $self->{'filename'};
+	$assoc_filepath =~ s/[^\\\/]*$//;
+    }
+
+    foreach my $assoc_file_info (@$assoc_files) {
+	my ($assoc_file, $mime_type, $dir) = split (":", $assoc_file_info);
+	my $real_dir = &util::filename_cat($assoc_filepath, $assoc_file),
+	my $assoc_dir = (defined $dir && $dir ne "") 
+	    ? &util::filename_cat($dir, $assoc_file) : $assoc_file;
+	$self->{'doc_obj'}->associate_file($real_dir, $assoc_dir, $mime_type);
+    }
+    $self->{'doc_obj'}->delete_metadata($self->{'doc_obj'}->get_top_section(), "gsdlassocfile");
+
+    # process the document
+    $self->{'processor'}->process($self->{'doc_obj'}, $self->{'file'});
+}
+
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MP3Plug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MP3Plug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MP3Plug.pm	(revision 10506)
@@ -0,0 +1,396 @@
+###########################################################################
+#
+# MP3Plug.pm -- Plugin for MP3 files (MPEG audio layer 3).
+#
+# A component of the Greenstone digital library software from the New
+# Zealand Digital Library Project at the University of Waikato, New
+# Zealand.
+#
+# Copyright (C) 2001 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 MP3Plug;
+
+use UnknownPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+use MP3::Info;
+
+require giget;
+
+sub BEGIN {
+    @MP3Plug::ISA = ('UnknownPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "string",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "assoc_images",
+        'desc' => "{MP3Plug.assoc_images}",
+        'type' => "flag",
+        'deft' => "",
+        'reqd' => "no" },
+      { 'name' => "applet_metadata",
+	'desc' => "{MP3Plug.applet_metadata}",
+	'type' => "flag",
+	'deft' => "" },
+      { 'name' => "metadata_fields",
+	'desc' => "{MP3Plug.metadata_fields}",
+	'type' => "string",
+	'deft' => "Title,Artist,Genre" } ];
+
+my $options = { 'name'     => "MP3Plug",
+		'desc'     => "{MP3Plug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new UnknownPlug($pluginlist,$inputargs,$hashArgOptLists): new UnknownPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    return q^(?i)\.mp3$^;
+}
+
+sub gen_mp3applet {
+
+    my ($mp3_filename) = @_;
+
+    my $applet_html = '
+<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
+        WIDTH = "59"
+        HEIGHT = "32"
+        codebase="http://java.sun.com/products/plugin/1.3/jinstall-13-win32.cab#Version=1,3,0,0">
+<PARAM NAME = CODE VALUE = "javazoom.jlGui.TinyPlayer" >
+<PARAM NAME = ARCHIVE VALUE = "_httpcollection_/tinyplayer.jar,_httpcollection_/jl10.jar" >
+<PARAM NAME="type" VALUE="application/x-java-applet;version=1.3">
+<PARAM NAME="scriptable" VALUE="false">
+<PARAM NAME = "skin" VALUE ="_httpcollection_/skins/Digitalized">
+<PARAM NAME = "autoplay" VALUE ="yes">
+<PARAM NAME = "bgcolor" VALUE ="638182">
+<PARAM NAME = "audioURL" VALUE ="MP3FILENAME">
+<COMMENT>
+<EMBED type="application/x-java-applet;version=1.3"
+       CODE = "javazoom.jlGui.TinyPlayer"
+       ARCHIVE = "_httpcollection_/tinyplayer.jar,_httpcollection_/jl10.jar"
+       WIDTH = "59"
+       HEIGHT = "32"
+       skin = "_httpcollection_/skins/Digitalized"
+       autoplay = "yes"
+       bgcolor = "638182"
+       audioURL = "MP3FILENAME"
+       scriptable=false
+       pluginspage="http://java.sun.com/products/plugin/1.3/plugin-install.html">
+<NOEMBED>
+</COMMENT>
+</NOEMBED></EMBED>
+</OBJECT>
+';
+
+    $applet_html =~ s/MP3FILENAME/$mp3_filename/g;
+
+    return $applet_html;
+}
+
+
+
+# Associate the mp3 file with the new document
+
+sub associate_mp3_file {
+    my $self = shift (@_);
+    my $filename = shift (@_);   # filename with full path
+    my $file = shift (@_);       # filename without path
+    my $doc_obj = shift (@_);
+    
+    my $verbosity = $self->{'verbosity'};
+    my $outhandle = $self->{'outhandle'};
+
+    # check the filename is okay
+    return 0 if ($file eq "" || $filename eq "");
+
+    # Add the file metadata
+    my $assoc_url = $file;
+#    $assoc_url =~ s/ /%20/g; # probably need to do more escaping than this!!
+    $assoc_url =~ s/ /_/g; # workaround for now
+    my $dst_file = $file;
+    $dst_file =~ s/ /_/g;
+
+    # Add the file as an associated file ...
+    my $section = $doc_obj->get_top_section();
+    my $mime_type = $self->{'mime_type'} || "audio/mp3";
+    my $assoc_field = $self->{'assoc_field'} || "mp3";
+    my $assoc_name = $file;
+    $assoc_name =~ s/\.mp3$//;
+
+    $doc_obj->associate_file($filename, $dst_file, $mime_type, $section);
+    $doc_obj->add_metadata ($section, "Source", $file);
+    $doc_obj->add_metadata ($section, $assoc_field, $assoc_name);
+    $doc_obj->add_metadata ($section, "srcurl", $assoc_url);
+
+    my $mp3_info = get_mp3info($filename);
+    my $mp3_tags = get_mp3tag($filename);
+
+    my $metadata_fields = $self->{'metadata_fields'};
+
+    if ($metadata_fields eq "*") {
+	# Locate all info and tag metadata
+
+	foreach my $ki ( keys %$mp3_info ) {
+	    my $mp3_metavalue = $mp3_info->{$ki};
+
+	    if ($mp3_metavalue !~ m/^\s*$/s) {
+		my $mp3_metaname = "mp3:".lc($ki);
+		$doc_obj->add_metadata ($section, $mp3_metaname, $mp3_metavalue);
+	    }
+	}
+
+	foreach my $kt ( keys %$mp3_tags ) {
+	    my $mp3_metavalue = $mp3_tags->{$kt};
+	    
+	    if ($mp3_metavalue !~ m/^\s*$/s) {
+		my $kt_len = length($kt);
+		my $kt_initial_cap = uc(substr($kt,0,1)).lc(substr($kt,1,$kt_len-1));
+		my $mp3_metaname = "mp3:".$kt_initial_cap;
+		
+		$doc_obj->add_metadata ($section, $mp3_metaname, $mp3_metavalue);
+	    }
+	}
+    }
+    else {
+
+	# Restrict metadata to that specifically given
+	foreach my $field (split /,/, $metadata_fields) {
+
+	    # check info
+	    if (defined $mp3_info->{$field}) {
+
+		my $mp3i_metavalue = $mp3_info->{$field};
+		
+		if ($mp3i_metavalue !~ m/^\s*$/s) {
+		    my $mp3i_metaname = "mp3:".lc($field);
+		    $doc_obj->add_metadata ($section, $mp3i_metaname, $mp3i_metavalue);
+		}
+	    }
+
+	    # check tags
+	    if (defined $mp3_tags->{uc($field)}) {
+
+		my $mp3t_metavalue = $mp3_tags->{uc($field)};
+		
+		if ($mp3t_metavalue !~ m/^\s*$/s) {
+		    my $mp3t_metaname = "mp3:".$field;
+		    
+		    $doc_obj->add_metadata ($section, $mp3t_metaname, $mp3t_metavalue);
+		}
+	    }
+	    
+	}
+    }
+
+    $doc_obj->add_metadata ($section, "FileFormat", "MP3");
+    
+    $doc_obj->add_metadata ($section, "srclink", 
+			    "<a href=\"_httpcollection_/index/assoc/[assocfilepath]/[srcurl]\">");
+    $doc_obj->add_metadata ($section, "srcicon", "<img src=\"_httpimg_/mp3icon.gif\">");
+    $doc_obj->add_metadata ($section, "/srclink", "</a>");
+
+    my $applet_metadata = $self->{'applet_metadata'};
+    if (defined $applet_metadata && $applet_metadata ) {
+	my $applet_html 
+	    = gen_mp3applet("_httpcollection_/index/assoc/[assocfilepath]/[srcurl]");
+	$doc_obj->add_metadata ($section, "mp3applet", $applet_html);
+    }
+
+    my $assoc_images = $self->{'assoc_images'};
+    if (defined $assoc_images && $assoc_images) {
+	my @search_terms = ();
+
+	my $title  = $mp3_tags->{'TITLE'};
+	my $artist = $mp3_tags->{'ARTIST'};
+
+	if (defined $title && $title ne "") {
+
+	    push(@search_terms,$title);
+
+	    if (defined $artist && $artist ne "") {
+		push(@search_terms,$artist);
+	    }
+	}
+	else {
+	    push(@search_terms,$assoc_name);
+	}
+
+	push(@search_terms,"song");
+
+	my $output_dir = $filename;
+	$output_dir =~ s/\.\w+$//;
+
+	my ($imgref_urls) = giget(\@search_terms,$output_dir);
+
+	my $gi_base = gi_url_base();
+	my $gi_query_url = gi_query_url(\@search_terms);
+
+	$doc_obj->add_metadata ($section, "giquery", "<a href=\"$gi_base$gi_query_url\" target=giwindow>");
+	$doc_obj->add_metadata ($section, "/giquery", "</a>");
+
+	for (my $i=1; $i<=2; $i++) {
+	    my $img_filename = "$output_dir/img_$i.jpg";
+	    my $dst_file = "img_$i.jpg";
+
+	    if (-e $img_filename) {
+		$doc_obj->associate_file($img_filename, $dst_file, "image/jpeg", $section);
+
+		my $srcurl = "src=\"_httpcollection_/index/assoc/[assocfilepath]/$dst_file\"";
+
+		$doc_obj->add_metadata ($section, "img$i", 
+					"<img $srcurl>");
+		$doc_obj->add_metadata ($section, "smallimg$i", 
+					"<img $srcurl width=100>");
+
+		my $imgref_url = $imgref_urls->[$i-1];
+
+		$doc_obj->add_metadata ($section, "imgref$i", "<a href=\"$imgref_url\" target=giwindow>");
+		$doc_obj->add_metadata ($section, "/imgref$i", "</a>");
+	    }
+
+	}
+
+
+    }
+
+    return 1;
+}
+
+
+
+# The MP3Plug read() function is based on UnknownPlug read().  This
+# function does all the right things to make general options work for
+# a given plugin. 
+
+my $mp3_doc_count = 0; ## is this used anywhere now !!???
+
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+
+    # Make sure we're processing the correct file
+    my $filename = &util::filename_cat($base_dir, $file);
+    return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+    print STDERR "<Processing n='$file' p='MP3Plug'>\n" if ($gli);
+    print $outhandle "MP3Plug processing \"$filename\"\n"
+	    if $self->{'verbosity'} > 1;
+
+    #if there's a leading directory name, eat it...
+    $file =~ s/^.*[\/\\]//;
+    
+    # create a new document
+    my $doc_obj = new doc ($filename, "indexed_doc");
+    $mp3_doc_count++;
+    
+##    $doc_obj->set_OIDtype ($processor->{'OIDtype'});    
+    $doc_obj->set_OIDtype ("incremental");    # this is done to avoid hashing content of file
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "FileSize", (-s $filename));
+
+    # associate the file with the document
+    if (associate_mp3_file($self, $filename, $file, $doc_obj) != 1)
+    {
+	print "MP3Plug: couldn't process \"$filename\"\n";
+	return 0;
+    }
+
+    #create an empty text string so we don't break downstream plugins 
+    my $text = &gsprintf::lookup_string("{BasPlug.dummy_text}");
+    $text .= "[img1]<br>";
+    $text .= "[img2]<br>";
+
+    # include any metadata passed in from previous plugins 
+    my $section = $doc_obj->get_top_section();
+    $self->extra_metadata ($doc_obj, $section, $metadata);
+
+    $self->title_fallback($doc_obj,$section,$file);
+
+    # do plugin specific processing of doc_obj
+    return undef unless defined ($self->process (\$text, $pluginfo, $base_dir, 
+						 $file, $metadata, $doc_obj));
+
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata ($doc_obj);
+
+    # add an OID
+    $doc_obj->set_OID();
+    $doc_obj->add_text($section, $text);
+
+    # process the document
+    $processor->process($doc_obj);
+
+    $self->{'num_processed'} ++;
+    return 1;
+}
+
+
+sub title_fallback
+{
+    my $self = shift (@_);
+    my ($doc_obj,$section,$file) = @_;
+
+    if (!defined $doc_obj->get_metadata_element ($section, "Title")) {
+	my $mp3_title = $doc_obj->get_metadata_element ($section, "mp3:Title");
+	if (defined $mp3_title) {
+	    $doc_obj->add_metadata ($section, "Title", $mp3_title);
+	}
+	else {
+	    &BasPlug::title_fallback($self, $doc_obj, $section, $file);
+	}
+    }
+}
+
+
+1;
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MetadataPass.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MetadataPass.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/MetadataPass.pm	(revision 10506)
@@ -0,0 +1,158 @@
+###########################################################################
+#
+# MetadataPass.pm -- class to enhance plugins with generic metadata capabilities
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package MetadataPass;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+use BasPlug; # uses BasPlug, but is not inherited
+
+
+my $options = { 'name'     => "MetadataPass",
+		'desc'     => "{MetadataPass.desc}",
+		'abstract' => "yes",
+		'inherits' => "no" };
+
+
+sub new {
+    my $class = shift (@_);
+    my $plugin_name = shift (@_);
+
+    my $self = {};
+    $self->{'plugin_type'} = "MetadataPass";
+
+    $self->{'option_list'} = [ $options ];
+
+    return bless $self, $class;
+}
+
+sub init {
+}
+
+sub print_xml_usage
+{
+    BasPlug::print_xml_usage(@_);
+}
+
+sub print_xml
+{
+    BasPlug::print_xml(@_);
+}
+
+sub set_keepold
+{
+    BasPlug::set_keepold(@_);
+}
+
+sub reset_saved_metadata {
+    my $self = shift(@_);
+
+    $self->{'saved_metadata'} = {};
+}
+
+
+sub get_saved_metadata {
+    my $self = shift(@_);
+    
+    return $self->{'saved_metadata'};
+}
+
+sub open_prettyprint_metadata_table
+{
+    my $self = shift(@_);
+
+    my $att   = "width=100% cellspacing=2";
+    my $style = "style=\'border-bottom: 4px solid #000080\'";
+
+    $self->{'ppmd_table'} = "\n<table $att $style>";
+}
+
+sub add_prettyprint_metadata_line 
+{
+    my $self = shift(@_);
+    my ($metaname, $metavalue_utf8) = @_;
+
+    $metavalue_utf8 = &util::hyperlink_text($metavalue_utf8);
+
+    $self->{'ppmd_table'} .= "  <tr bgcolor=#b5d3cd>\n";
+    $self->{'ppmd_table'} .= "    <td width=30%>\n";
+    $self->{'ppmd_table'} .= "      $metaname\n";
+    $self->{'ppmd_table'} .= "    </td>\n";
+    $self->{'ppmd_table'} .= "    <td>\n";
+    $self->{'ppmd_table'} .= "      $metavalue_utf8\n";
+    $self->{'ppmd_table'} .= "    </td>\n";
+    $self->{'ppmd_table'} .= "  </tr>\n";
+
+}
+
+sub close_prettyprint_metadata_table
+{
+    my $self = shift(@_);
+    $self->{'ppmd_table'} .= "</table>\n";
+
+    $self->set_filere_metadata("prettymd",$self->{'ppmd_table'});
+    $self->{'ppmd_table'} = undef;
+}
+
+sub set_filere_metadata
+{
+    my $self = shift(@_);
+    my ($full_mname,$md_content) = @_;
+
+    if (defined $self->{'saved_metadata'}->{$full_mname}) {
+	# accumulate - add value to existing value(s)
+	if (ref ($self->{'saved_metadata'}->{$full_mname}) eq "ARRAY") {
+	    push (@{$self->{'saved_metadata'}->{$full_mname}}, $md_content);
+	} else {
+	    $self->{'saved_metadata'}->{$full_mname} = 
+		[$self->{'saved_metadata'}->{$full_mname}, $md_content];
+	}
+    } else {
+	# accumulate - add value into (currently empty) array
+	$self->{'saved_metadata'}->{$full_mname} = [$md_content];
+    }
+}
+
+
+sub get_filere_metadata
+{
+    my $self = shift(@_);
+    my ($full_mname) = @_;
+
+    return $self->{'saved_metadata'}->{$full_mname};
+}
+
+sub get_filere_metadata_head
+{
+    my $self = shift(@_);
+    my ($full_mname) = @_;
+    
+    return $self->{'saved_metadata'}->{$full_mname}->[0];
+}
+
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/NULPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/NULPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/NULPlug.pm	(revision 10506)
@@ -0,0 +1,165 @@
+###########################################################################
+#
+# NULPlug.pm -- Plugin for dummy (.nul) files
+#
+# A component of the Greenstone digital library software from the New
+# Zealand Digital Library Project at the University of Waikato, New
+# Zealand.
+#
+# Copyright (C) 2005 Katherine Don
+# Copyright (C) 2005 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# NULPlug - a plugin for dummy files
+
+# This is a simple Plugin for importing dummy files, along with
+# their metadata.  A fictional document will
+# be created for every such file, and the metadata added to it.
+
+# This is used mainly for the null files resulting from exploding metadata
+# databases
+
+package NULPlug;
+
+use BasPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @NULPlug::ISA = ('BasPlug');
+}
+
+my $arguments = [
+		 ];
+
+my $options = { 'name'     => "NULPlug",
+		'desc'     => "{NULPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes" };
+	#	'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+    
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    return '(?i)\.nul$';
+}
+
+# The NULPlug read() function. This function does all the right
+# things to make general options work for a given plugin.  NULPlug
+# overrides read() because there is no need to read the actual text of
+# the file in, because the contents of the file is not text...
+#
+#
+# Return number of files processed, undef if can't process 
+#
+# Note that $base_dir might be "" and that $file might include directories
+
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+
+    # Make sure we're processing the correct file
+    my $filename = &util::filename_cat($base_dir, $file);
+    return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+    print STDERR "<Processing n='$file' p='NULPlug'>\n" if ($gli);
+    print $outhandle "NULPlug processing \"$filename\"\n"
+	    if $self->{'verbosity'} > 1;
+
+    #if there's a leading directory name, eat it...
+    $file =~ s/^.*[\/\\]//;
+    
+    # create a new document
+    my $doc_obj = new doc ($filename, "indexed_doc");
+    $doc_obj->set_OIDtype ($processor->{'OIDtype'});    
+    #$doc_obj->set_OIDtype ("incremental");
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+    $doc_obj->add_metadata($doc_obj->get_top_section(), "Source", &ghtml::dmsafe($file)); # set the filename as Source metadata to be consistent with other plugins
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "FileSize", (-s $filename));
+
+    #create an empty text string so we don't break downstream plugins 
+    my $text = &gsprintf::lookup_string("{BasPlug.dummy_text}");
+    
+    # include any metadata passed in from previous plugins 
+    my $section = $doc_obj->get_top_section();
+    $self->extra_metadata ($doc_obj, $section, $metadata);
+    
+    $self->title_fallback($doc_obj,$section,$file);
+    
+    # do plugin specific processing of doc_obj
+    unless (defined ($self->process(\$text, $pluginfo, $base_dir, $file, $metadata, $doc_obj))) {
+	print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	return -1;
+    }
+
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata ($doc_obj);
+
+    # add an OID
+    $doc_obj->set_OID();
+    $doc_obj->add_text($section, $text);
+    
+    # process the document
+    $processor->process($doc_obj);
+
+    $self->{'num_processed'} ++;
+    return 1;
+}
+
+
+# NULPlug processing of doc_obj.  In practice we don't need to do
+# anything here because the read function takes care of everything.
+
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    return 1;
+}
+
+
+1;
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/OAIPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/OAIPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/OAIPlug.pm	(revision 10506)
@@ -0,0 +1,375 @@
+###########################################################################
+#
+# OAIPlug.pm -- basic Open Archives Initiative (OAI) plugin
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package OAIPlug;
+
+use BasPlug;
+use unicode;
+use util;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+use XMLPlug;
+
+sub BEGIN {
+    @OAIPlug::ISA = ('XMLPlug');
+}
+
+
+my $arguments = 
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() },
+      ];
+
+my $options = { 'name'     => "OAIPlug",
+		'desc'     => "{OAIPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new XMLPlug($pluginlist,$inputargs,$hashArgOptLists): new XMLPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)(\.oai)$^;
+}
+
+sub xml_start_document {
+    my $self = shift (@_);
+    $self->{'in_metadata_node'} = 0;
+    $self->{'rawxml'} = "";
+}
+
+sub xml_end_document {
+}
+
+sub xml_doctype {
+    my $self = shift(@_);
+
+    my ($expat, $name, $sysid, $pubid, $internal) = @_;
+
+    # allow the short-lived and badly named "GreenstoneArchive" files to be processed
+    # as well as the "Archive" files which should now be created by import.pl
+    die "" if ($name !~ /^OAI-PMH$/);
+
+    my $outhandle = $self->{'outhandle'};
+    print $outhandle "OAIPlug: processing $self->{'file'}\n" if $self->{'verbosity'} > 1;
+    print STDERR "<Processing n='$self->{'file'}' p='OAIPlug'>\n" if $self->{'gli'};
+
+}
+
+
+sub xml_start_tag {
+    my $self = shift(@_);
+    my ($expat,$element) = @_;
+
+    my %attr_hash = %_;
+
+    my $attr = "";
+    map { $attr .= " $_=$attr_hash{$_}"; } keys %attr_hash;
+
+    $self->{'rawxml'} .= "<$element$attr>";
+
+    if ($element eq "metadata") {
+	$self->{'in_metadata_node'} = 1;
+	$self->{'metadata_xml'} = "";
+    }
+
+    if ($self->{'in_metadata_node'}) {
+	$self->{'metadata_xml'} .= "<$element$attr>";
+    }
+}
+
+sub xml_end_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+
+    $self->{'rawxml'} .= "</$element>";
+
+    if ($self->{'in_metadata_node'}) {
+	$self->{'metadata_xml'} .= "</$element>";
+    }
+
+    if ($element eq "metadata") {
+	my $textref = \$self->{'metadata_xml'};
+	my $metadata = $self->{'metadata'};
+	$self->extract_oai_metadata($textref,$metadata);
+
+	$self->{'in_metadata_node'} = 0;	
+    }
+
+
+}
+
+sub xml_text {
+    my $self = shift(@_);
+    my ($expat) = @_;
+
+    $self->{'rawxml'} .= $_;
+
+    if ($self->{'in_metadata_node'}) {
+	$self->{'metadata_xml'} .= $_;
+    }
+}
+
+
+
+
+sub read {
+    my $self = shift (@_);  
+  
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+
+    my $filename = $file;
+    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+
+    return 0 if ((-d $filename) && ($filename =~ m/srcdocs$/));
+
+    if ($self->SUPER::read(@_)) {
+
+	# Do encoding stuff
+	my ($language, $encoding) = $self->textcat_get_language_encoding ($filename);
+	
+	my $url_array = $metadata->{'URL'};
+	my $num_urls = (defined $url_array) ? scalar(@$url_array) : 0;
+	
+	my $srcdoc_exists = 0;
+	my $srcdoc_pos = 0;
+	my $filename_dir = &util::filename_head($filename);
+	
+	for (my $i=0; $i<$num_urls; $i++) {
+	    
+	    if ($url_array->[$i] !~ m/^(http|ftp):/) {
+		
+		my $src_filename = &util::filename_cat($filename_dir, $url_array->[$i]);
+		
+		if (-e $src_filename) {
+		    $srcdoc_pos = $i;
+		    $srcdoc_exists = 1;
+		}
+	    }
+	}
+	
+	if ($srcdoc_exists)
+	{
+	    print $outhandle "OAIPlug: passing metadata on to $url_array->[0]\n"
+		if ($self->{'verbosity'}>1);
+	    
+	    
+	    # Make pretty print metadata table stick with src filename
+	    my $ppmd_table = $self->{'ppmd_table'};
+	    $metadata->{'prettymd'} = [ $ppmd_table ];
+	    $self->{'ppmd_table'} = undef;
+	    
+	    return &plugin::read ($pluginfo, $filename_dir, $url_array->[0],
+				  $metadata, $processor, $maxdocs, $total_count, $gli);
+	}
+	else
+	{
+	    # create a new document
+	    my $doc_obj = new doc ($filename, "indexed_doc");
+	    my $top_section = $doc_obj->get_top_section;
+	    my $plugin_type = $self->{'plugin_type'};
+	    
+	    $doc_obj->add_utf8_metadata($top_section, "Language", $language);
+	    $doc_obj->add_utf8_metadata($top_section, "Encoding", $encoding);
+	    $doc_obj->add_utf8_metadata($top_section, "Plugin", $plugin_type);
+	    $doc_obj->add_metadata($top_section, "FileFormat", "OAI");
+	    $doc_obj->add_metadata($top_section, "FileSize", (-s $filename));
+	    
+	    # include any metadata passed in from previous plugins 
+	    # note that this metadata is associated with the top level section
+	    $self->extra_metadata ($doc_obj, $doc_obj->get_top_section(), $metadata);
+	    
+	    # do plugin specific processing of doc_obj
+	    my $textref = \$self->{'rawxml'};
+	    unless (defined ($self->process($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj))) {
+		print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+		return -1;
+	    }
+	    
+	    # do any automatic metadata extraction
+	    $self->auto_extract_metadata ($doc_obj);
+	    
+	    # add an OID
+	    $doc_obj->set_OID();
+	    
+	    my $ppmd_table = $self->{'ppmd_table'};
+	    $doc_obj->add_utf8_metadata($top_section,"prettymd",$ppmd_table);
+	    $self->{'ppmd_table'} = undef;
+	    
+	    # process the document
+	    $processor->process($doc_obj);
+	    
+	    $self->{'num_processed'} ++;
+	    
+	    return 1; # processed the file
+	}
+    }
+    else {
+	return undef;
+    }
+}
+
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    print STDERR "<Processing n='$file' p='OAIPlug'>\n" if ($gli);
+    print $outhandle "OAIPlug: processing $file\n"
+	if $self->{'verbosity'} > 1;
+
+    my $cursection = $doc_obj->get_top_section();
+
+##    $self->extract_metadata ($textref, $metadata, $doc_obj, $cursection);
+
+    # add text to document object
+
+#    $$textref =~ s/<(.*?)>/$1 /g;
+    $$textref =~ s/</&lt;/g;
+    $$textref =~ s/>/&gt;/g;
+
+##    print STDERR "*** adding text: $$textref\n";
+    
+    $doc_obj->add_utf8_text($cursection, $$textref);
+
+    return 1;
+}
+
+
+# Improvement is to merge this with newer version in MetadataPass
+
+sub open_prettyprint_metadata_table
+{
+    my $self = shift(@_);
+
+    my $att   = "width=100% cellspacing=2";
+    my $style = "style=\'border-bottom: 4px solid #000080\'";
+
+    $self->{'ppmd_table'} = "\n<table $att $style>";
+}
+
+sub add_prettyprint_metadata_line 
+{
+    my $self = shift(@_);
+    my ($metaname, $metavalue_utf8) = @_;
+
+    $metavalue_utf8 =~ s/hdl\.handle\.net/mcgonagall.cs.waikato.ac.nz:8080\/dspace\/handle/;
+    $metavalue_utf8 = &util::hyperlink_text($metavalue_utf8);
+
+    $self->{'ppmd_table'} .= "  <tr bgcolor=#b5d3cd>\n";
+    $self->{'ppmd_table'} .= "    <td width=30%>\n";
+    $self->{'ppmd_table'} .= "      $metaname\n";
+    $self->{'ppmd_table'} .= "    </td>\n";
+    $self->{'ppmd_table'} .= "    <td>\n";
+    $self->{'ppmd_table'} .= "      $metavalue_utf8\n";
+    $self->{'ppmd_table'} .= "    </td>\n";
+    $self->{'ppmd_table'} .= "  </tr>\n";
+
+}
+
+sub close_prettyprint_metadata_table
+{
+    my $self = shift(@_);
+
+    $self->{'ppmd_table'} .= "</table>\n";
+}
+
+
+
+
+sub extract_oai_metadata {
+    my $self = shift (@_);
+    my ($textref, $metadata) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    # Only handles DC metadata
+
+    $self->open_prettyprint_metadata_table();
+
+    if ($$textref =~ m/<metadata\s*>(.*?)<\/metadata\s*>/s)
+    {
+	my $metadata_text = $1;
+	$metadata_text =~ s/^.*?<(oai_dc:)?dc.*?>(.*?)<\/(oai_dc:)?dc>.*?/$2/s;
+
+	while ($metadata_text =~ m/<(.*?)>(.*?)<\/(.*?)>(.*)/s)
+	{
+	    # if URL given for document as identifier metadata, store it ...
+	    # $doc_obj->add_utf8_metadata($cursection, "URL", $web_url);
+
+	    my $metaname = $1;
+	    my $metavalue = $2;
+	    $metadata_text = $4;
+	    
+	    $metaname =~ s/^(dc:)?(.)/\u$2/;
+
+	    if ($metaname eq "Identifier")
+	    {
+		# name clashes with GSDL reserved metadata name for hash id
+		$metaname = "URL";
+	    }
+
+	    if (defined $metadata->{$metaname})
+	    {
+		push(@{$metadata->{$metaname}},$metavalue);
+
+	    }
+	    else
+	    {
+		$metadata->{$metaname} = [ $metavalue ];
+	    }
+
+	    $self->add_prettyprint_metadata_line($metaname, $metavalue);
+	    
+	}
+    }
+
+    $self->close_prettyprint_metadata_table();
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/OggVorbisPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/OggVorbisPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/OggVorbisPlug.pm	(revision 10506)
@@ -0,0 +1,178 @@
+###########################################################################
+#
+# OggVorbisPlug.pm -- A plugin for Ogg Vorbis audio files
+#
+# Original code by Christy Kuo
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright 1999-2004 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 OggVorbisPlug;
+
+
+use UnknownPlug;
+use Ogg::Vorbis::Header::PurePerl;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @OggVorbisPlug::ISA = ('UnknownPlug');
+}
+
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "string",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "add_technical_metadata",
+	'desc' => "{OggVorbisPlug.add_technical_metadata}",
+	'type' => "flag",
+	'deft' => "" } ];
+
+my $options = { 'name'     => "OggVorbisPlug",
+		'desc'     => "{OggVorbisPlug.desc}",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+# This plugin processes exported Ogg Vorbis files with the suffix ".ogg"
+sub get_default_process_exp
+{
+    return q^(?i)(\.ogg)$^;
+}
+
+
+sub new
+{
+    my ($class) = shift(@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+    
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+    
+    my $self = (defined $hashArgOptLists)? new UnknownPlug($pluginlist,$inputargs,$hashArgOptLists): new UnknownPlug($pluginlist,$inputargs);
+    
+    return bless $self, $class;
+}
+
+
+sub read
+{
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+
+    # filename is the full pathname of the file
+    my $filename = &util::filename_cat($base_dir, $file);
+    return 0 if $self->{block_exp} ne "" && $filename =~ /$self->{'block_exp'}/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+
+    # Report that we're processing the file
+    print STDERR "<Processing n='$file' p='OggVorbisPlug'>\n" if ($gli);
+    print $outhandle "OggVorbisPlug: processing $file\n"
+  	if ($self->{'verbosity'}) > 1;
+    
+    # file is just the name of the file (need to get rid off any leading directory names)
+    $file =~ s/^.*[\/\\]//;
+
+    # create a new index document
+    my $doc_obj = new doc ($filename, "indexed_doc");
+    $doc_obj->set_OIDtype ("incremental");    # this is done to avoid hashing content of file
+    my $section = $doc_obj->get_top_section();
+    
+    # replace spaces in filename with %20 in url for metadata entry
+    my $url = $file;
+    $url =~ s/ /%20/g;
+    # Source (filename) to be consistent with other plugins
+    $doc_obj->add_metadata ($section, "Source", $url);
+
+    # Extract metadata
+    my $ogg = Ogg::Vorbis::Header::PurePerl->new($filename);
+
+    # Comments added to the file
+    foreach my $key ($ogg->comment_tags())
+    {
+	# Convert key to title case
+	my $keytc = uc(substr($key, 0, 1)) . substr($key, 1, length($key));
+	foreach my $value ($ogg->comment($key))
+	{
+	    if (defined $value && $value ne "") {
+		$doc_obj->add_metadata($section, $keytc, $value);
+	    }
+	}
+    }
+
+    # Technical data (optional)
+    if ($self->{'add_technical_metadata'}) {
+	foreach my $key (keys %{$ogg->info})
+	{
+	    # Convert key to title case
+	    my $keytc = uc(substr($key, 0, 1)) . substr($key, 1, length($key));
+	    my $value = $ogg->info->{$key};
+	    if (defined $value && $value ne "") {
+		$doc_obj->add_metadata($section, $keytc, $value);
+	    }
+	}
+    }
+
+    # srclink
+    $doc_obj->add_metadata ($section, "FileFormat", "OggVorbis");
+    $doc_obj->add_metadata ($section, "srclink", "<a href=\"_httpcollection_/index/assoc/[assocfilepath]/[Source]\">");
+    $doc_obj->add_metadata ($section, "/srclink", "</a>");
+    # srcicon (need to include "ogg.png" in the greenstone images directory
+    $doc_obj->add_metadata ($section, "srcicon", "<img src=\"_httpprefix_/images/ogg.png\" title=\"Download\" border=0>");
+
+    # Add the actual file as an associated file
+    $doc_obj->associate_file($filename, $file, "VORBIS", $section);
+
+    # Create an empty text string so we don't break downstream plugins 
+    my $text = &gsprintf::lookup_string("{BasPlug.dummy_text}");
+
+    # include any metadata passed in from previous plugins
+    $self->extra_metadata ($doc_obj, $section, $metadata);
+
+    # do plugin specific processing of doc_obj
+    return undef unless defined ($self->process (\$text, $pluginfo, $base_dir, $file, $metadata, $doc_obj));
+
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata($doc_obj);
+
+    # add an OID
+    $doc_obj->set_OID();
+    $doc_obj->add_text($section, $text);
+
+    # process the document
+    $processor->process($doc_obj);
+
+    $self->{'num_processed'}++;
+    return 1;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PDFPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PDFPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PDFPlug.pm	(revision 10506)
@@ -0,0 +1,311 @@
+###########################################################################
+#
+# PDFPlug.pm -- reasonably with-it pdf plugin
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999-2001 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 PDFPlug;
+
+use ConvertToPlug;
+use unicode;
+use strict;
+no strict 'refs'; # so we can use a var for filehandles (eg STDERR)
+
+sub BEGIN {
+    @PDFPlug::ISA = ('ConvertToPlug');
+}
+
+my $convert_to_list =
+    [ {	'name' => "auto",
+	'desc' => "{ConvertToPlug.convert_to.auto}" },
+      {	'name' => "html",
+	'desc' => "{ConvertToPlug.convert_to.html}" },
+      {	'name' => "text",
+	'desc' => "{ConvertToPlug.convert_to.text}" },
+      { 'name' => "pagedimg_jpg",
+	'desc' => "{ConvertToPlug.convert_to.pagedimg_jpg}"},
+      { 'name' => "pagedimg_gif",
+	'desc' => "{ConvertToPlug.convert_to.pagedimg_gif}"},
+      { 'name' => "pagedimg_png",
+	'desc' => "{ConvertToPlug.convert_to.pagedimg_png}"}, 
+      ];
+
+
+my $arguments = 
+      [
+       { 'name' => "convert_to",
+	'desc' => "{ConvertToPlug.convert_to}",
+	'type' => "enum",
+	'reqd' => "yes",
+	'list' => $convert_to_list, 
+	'deft' => "html" },	 
+       { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_block_exp() },
+      { 'name' => "noimages",
+	'desc' => "{PDFPlug.noimages}",
+	'type' => "flag" },
+      { 'name' => "allowimagesonly",
+	'desc' => "{PDFPlug.allowimagesonly}",
+	'type' => "flag" },
+      { 'name' => "complex",
+	'desc' => "{PDFPlug.complex}",
+	'type' => "flag" },
+      { 'name' => "nohidden",
+	'desc' => "{PDFPlug.nohidden}",
+	'type' => "flag" },
+      { 'name' => "zoom",
+	'desc' => "{PDFPlug.zoom}",
+	'deft' => "2",
+	'range' => "1,3", # actually the range is 0.5-3 
+	'type' => "int" },
+      { 'name' => "use_sections",
+	'desc' => "{PDFPlug.use_sections}",
+	'type' => "flag" } ];
+
+my $options = { 'name'     => "PDFPlug",
+		'desc'     => "{PDFPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    push(@$inputargs,"-title_sub");
+    push(@$inputargs,'^(Page\s+\d+)?(\s*1\s+)?');
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my @arg_array = @$inputargs;
+    my $self = (defined $hashArgOptLists)? new ConvertToPlug($pluginlist,$inputargs,$hashArgOptLists): new ConvertToPlug($pluginlist,$inputargs);
+    
+    # these are passed through to gsConvert.pl by ConvertToPlug.pm
+    my $zoom = $self->{"zoom"};
+    $self->{'convert_options'} = "-pdf_zoom $zoom";
+    $self->{'convert_options'} .= " -pdf_complex" if $self->{"complex"};
+    $self->{'convert_options'} .= " -pdf_nohidden" if $self->{"nohidden"};
+    $self->{'convert_options'} .= " -pdf_ignore_images" if $self->{"noimages"};
+    $self->{'convert_options'} .= " -pdf_allow_images_only" if $self->{"allowimagesonly"};
+
+    my $secondary_plugin_options = $self->{'secondary_plugin_options'};
+
+    if (!defined $secondary_plugin_options->{'HTMLPlug'}) {
+	$secondary_plugin_options->{'HTMLPlug'} = [];
+    }
+    if (!defined $secondary_plugin_options->{'TEXTPlug'}) {
+	$secondary_plugin_options->{'TEXTPlug'} = [];
+    }
+    if (defined $self->{'convert_to'} && $self->{'convert_to'} =~ /pagedimg.*/i) {
+	if (!defined $secondary_plugin_options->{'PagedImgPlug'}){
+	    $secondary_plugin_options->{'PagedImgPlug'} = [];
+	    my $pagedimg_options = $secondary_plugin_options->{'PagedImgPlug'}; 
+	    push(@$pagedimg_options, "-title_sub", '^(Page\s+\d+)?(\s*1\s+)?');
+	}
+    }
+    my $html_options = $secondary_plugin_options->{'HTMLPlug'};
+    my $text_options = $secondary_plugin_options->{'TEXTPlug'};
+   
+    if ($self->{'input_encoding'} eq "auto") {
+	# pdftohtml will always produce html files encoded as utf-8
+	# => restrict primary PDFPlug and secondary HTML plugin to use 
+	# utf8 and extract language.
+	$self->{'input_encoding'} = "utf8";
+	$self->{'extract_language'} = 1;
+
+	push(@$html_options,"-input_encoding", "utf8");
+	push(@$html_options,"-extract_language");
+    }
+
+    # Instruct HTMLPlug (when eventually accessed through read_into_doc_obj) 
+    # to extract these metadata fields from the HEAD META fields
+    push(@$html_options,"-metadata_fields","Title,GENERATOR,date,author<Creator>");
+    
+    if ($self->{'use_sections'}) {
+	$self->{'description_tags'} = 1;
+	push(@$html_options,"-description_tags");
+    }
+
+    # following title_sub removes "Page 1" added by pdftohtml, and a leading
+    # "1", which is often the page number at the top of the page. Bad Luck
+    # if your document title actually starts with "1 " - is there a better way?
+    push(@$html_options , "-title_sub", '^(Page\s+\d+)?(\s*1\s+)?');
+    push(@$text_options , "-title_sub", '^(Page\s+\d+)?(\s*1\s+)?');
+ 
+    $self = bless $self, $class;
+    $self->load_secondary_plugins($class,$secondary_plugin_options,$hashArgOptLists);
+    return $self;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.pdf$^;
+}
+
+# so we don't inherit HTMLPlug's block exp...
+sub get_default_block_exp {
+    return "";
+}
+    
+sub convert_post_process
+{
+    my $self = shift (@_);
+    my ($conv_filename) = @_;
+
+    my $outhandle=$self->{'outhandle'};
+
+    my ($language, $encoding) = $self->textcat_get_language_encoding ($conv_filename);
+
+    # read in file ($text will be in utf8)
+    my $text = "";
+    $self->read_file ($conv_filename, $encoding, $language, \$text);
+
+    # Calculate number of pages based on <a ...> tags (we have a <a name=1> etc
+    # for each page).  Metadata based on this calculation not set until process()
+    # 
+    # Note: this is done even if we are not breaking to document into pages as it might
+    # be useful to give an indication of document length in browser through setting
+    # num_pages as metadata.
+    my @pages = ($text =~ /\<[Aa] name=\"?\w+\"?>/ig);
+    my $num_pages = scalar(@pages);
+    $self->{'num_pages'} = $num_pages;
+
+    if ($self->{'use_sections'}
+	&& $self->{'converted_to'} eq "HTML") {
+
+	print $outhandle "PDFPlug: Calculating sections...\n";
+
+	# we have "<a name=1></a>" etc for each page
+	# it may be <A name=
+	my @sections = split('<[Aa] name=', $text);
+
+	my $top_section = "";
+
+	if (scalar (@sections) == 1) { #only one section - no split!
+	    print $outhandle "PDFPlug: warning - no sections found\n";
+	} else {
+	    $top_section .= shift @sections; # keep HTML header etc as top_section
+	}
+
+	# handle first section specially for title? Or all use first 100...
+	
+	my $title = $sections[0];
+	$title =~ s/^\"?\w+\"?>//; # specific for pdftohtml...
+	$title =~ s/<\/([^>]+)><\1>//g; # (eg) </b><b> - no space
+	$title =~ s/<[^>]*>/ /g;
+	$title =~ s/(?:&nbsp;|\xc2\xa0)/ /g; # utf-8 for nbsp...
+	$title =~ s/^\s+//s;
+	$title =~ s/\s+$//;
+	$title =~ s/\s+/ /gs;
+	$title =~ s/^$self->{'title_sub'}// if ($self->{'title_sub'});
+	$title =~ s/^\s+//s; # in case title_sub introduced any...
+	$title = substr ($title, 0, 100);
+	$title =~ s/\s\S*$/.../;
+
+
+	if (scalar (@sections) == 1) { # no sections found
+	    $top_section .= $sections[0];
+	    @sections=();
+	} else {
+	    $top_section .= "<!--<Section>\n<Metadata name=\"Title\">$title</Metadata>\n-->\n <!--</Section>-->\n";
+	}
+
+	# add metadata per section...
+	foreach my $section (@sections) {
+	    # section names are not always just digits, may be like "outline"
+	    $section =~ s@^\"?(\w+)\"?></a>@@; # leftover from split expression...
+
+	    $title = $1; # Greenstone does magic if sections are titled digits
+	    if (! defined($title) ) {
+		print STDERR "no title: $section\n";
+		$title = " "; # get rid of the undefined warning in next line
+	    }
+	    my $newsection = "<!-- from PDFPlug -->\n<!-- <Section>\n";
+	    $newsection .= "<Metadata name=\"Title\">" . $title
+		. "</Metadata>\n--><p>\n";
+	    $newsection .= $section;
+	    $newsection .= "<!--</Section>-->\n";
+	    $section = $newsection;
+	}
+
+	$text=join('', ($top_section, @sections));
+    }
+
+    # turn any high bytes that aren't valid utf-8 into utf-8.
+    unicode::ensure_utf8(\$text);
+
+    # Write it out again!
+    $self->utf8_write_file (\$text, $conv_filename);
+}
+
+
+# do plugin specific processing of doc_obj for HTML type
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+
+    my $result = $self->process_type("pdf",$base_dir,$file,$doc_obj);
+
+    # fix up the extracted date metadata to be in Greenstone date format,
+    # and fix the capitalisation of 'date'
+    my $cursection = $doc_obj->get_top_section();
+
+    foreach my $datemeta (@{$doc_obj->get_metadata($cursection, "date")}) {
+	$doc_obj->delete_metadata($cursection, "date", $datemeta);
+
+	# We're just interested in the date bit, not the time
+	# some pdf creators (eg "Acrobat 5.0 Scan Plug-in for Windows")
+	# set a /CreationDate, and set /ModDate to 000000000. pdftohtml
+	# extracts the ModDate, so it is 0...
+	$datemeta =~ /(\d+)-(\d+)-(\d+)/;
+	my ($year, $month, $day) = ($1,$2,$3);
+	if (defined($year) && defined($month) && defined($day)) {
+	    if ($year == 0) {next}
+	    if ($year < 100) {$year += 1900} # just to be safe
+	    if ($month =~ /^\d$/) {$month="0$month"} # single digit
+	    if ($day =~ /^\d$/) {$day="0$day"} # single digit
+	    my $date="$year$month$day";
+	    $doc_obj->add_utf8_metadata($cursection, "Date", $date);
+	}
+    }
+
+    $doc_obj->add_utf8_metadata($cursection, "NumPages", $self->{'num_pages'});
+    
+    if ($self->{'use_sections'} && $self->{'converted_to'} eq "HTML") {
+	# we explicitly make it a paged document, cos greenstone won't get it
+	# right if any section has an empty title, or one with letters in it
+	$doc_obj->set_utf8_metadata_element ($cursection, "gsdlthistype", "Paged");
+    }
+
+    return $result;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PPTPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PPTPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PPTPlug.pm	(revision 10506)
@@ -0,0 +1,166 @@
+###########################################################################
+#
+# PPTPlug.pm -- plugin for importing Microsoft PowerPoint files.
+#  (currently only versions 95 and 97)
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2002 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 PPTPlug;
+
+use ConvertToPlug;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @PPTPlug::ISA = ('ConvertToPlug');
+}
+
+my $convert_to_list =
+    [ {	'name' => "auto",
+	'desc' => "{ConvertToPlug.convert_to.auto}" },
+      {	'name' => "html",
+	'desc' => "{ConvertToPlug.convert_to.html}" },
+      {	'name' => "text",
+	'desc' => "{ConvertToPlug.convert_to.text}" },
+      { 'name' => "pagedimg_jpg",
+	'desc' => "{ConvertToPlug.convert_to.pagedimg_jpg}" },
+      { 'name' => "pagedimg_gif",
+	'desc' => "{ConvertToPlug.convert_to.pagedimg_gif}" },
+      { 'name' => "pagedimg_png",
+	'desc' => "{ConvertToPlug.convert_to.pagedimg_png}" }
+      ];
+
+my $arguments = 
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp()}
+      ];
+
+my $options = { 'name'     => "PPTPlug",
+		'desc'     => "{PPTPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "Yes",
+	        'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if ($ENV{'GSDLOS'} =~ m/^windows$/i) {
+	my $ws_arg =[{ 'name' => "convert_to",
+		       'desc' => "{ConvertToPlug.convert_to}",
+		       'type' => "enum",
+		       'reqd' => "yes",
+		       'list' => $convert_to_list, 
+		       'deft' => "html" },
+		     { 'name' => "windows_scripting",
+		       'desc' => "{PPTPlug.windows_scripting}",
+		       'type' => "flag",
+		       'reqd' => "no" }
+		     ];
+	push(@$arguments,@$ws_arg);
+    }
+    
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+
+    my @arg_array = @$inputargs;
+    my $self = (defined $hashArgOptLists)? new ConvertToPlug($pluginlist,$inputargs,$hashArgOptLists): new ConvertToPlug($pluginlist,$inputargs);
+ 
+    # ppthtml outputs utf-8 already.
+    #these are passed through to gsConvert.pl by ConvertToPlug.pm
+    $self->{'convert_options'} = "-windows_scripting" if $self->{'windows_scripting'};
+    my $secondary_plugin_options = $self->{'secondary_plugin_options'};
+
+    if ($self->{'windows_scripting'} && ($self->{'convert_to'} eq "PagedImg")) {
+	$secondary_plugin_options->{'PagedImgPlug'} = [];
+    } else {
+	$secondary_plugin_options->{'HTMLPlug'} = [];
+    }
+    my $html_options = $secondary_plugin_options->{'HTMLPlug'};
+    my $pageimg_options = $secondary_plugin_options->{'PagedImgPlug'};
+
+    if ($self->{'input_encoding'} eq "auto") {
+	$self->{'input_encoding'} = "utf8";
+	$self->{'extract_language'} = 1;
+	if (defined $secondary_plugin_options->{'HTMLPlug'}){
+	    push(@$html_options,"-input_encoding", "utf8");
+	    push(@$html_options,"-extract_language");
+
+	    # Instruct HTMLPlug (when eventually accessed through read_into_doc_obj) 
+	    # to extract these metadata fields from the HEAD META fields
+	    push(@$html_options,"-metadata_fields","Title,GENERATOR,date,author<Creator>");
+	} 
+	if (defined $secondary_plugin_options->{'PagedImgPlug'}){
+	    push(@$pageimg_options,"-input_encoding", "utf8");
+	    push(@$pageimg_options,"-extract_language");
+	}
+    }
+
+    $self = bless $self, $class;
+
+    $self->load_secondary_plugins($class,$secondary_plugin_options,$hashArgOptLists);
+    return $self;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+    return q^(?i)\.ppt$^;
+}
+
+sub get_file_type {
+    my $self = shift (@_);
+    my $file_type = "PPT";
+    return $file_type;
+}
+
+sub convert_post_process
+{
+    my $self = shift (@_);
+    my ($conv_filename) = @_;
+
+    my $outhandle=$self->{'outhandle'};
+    my ($language, $encoding) = $self->textcat_get_language_encoding ($conv_filename);
+    # read in file ($text will be in utf8)
+    my $text = "";
+    $self->read_file ($conv_filename, $encoding, $language, \$text);
+ 
+    # turn any high bytes that aren't valid utf-8 into utf-8.
+    unicode::ensure_utf8(\$text);
+    # Write it out again!
+    $self->utf8_write_file (\$text, $conv_filename);
+}
+
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+
+    return $self->process_type("ppt",$base_dir,$file,$doc_obj);
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PSPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PSPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PSPlug.pm	(revision 10506)
@@ -0,0 +1,225 @@
+###########################################################################
+#
+# PSPlug.pm -- this might look VERY similar to the PDF plugin...
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package PSPlug;
+
+use ConvertToPlug;
+use sorttools;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @PSPlug::ISA = ('ConvertToPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => 'regexp',
+	'deft' => &get_default_block_exp() },
+      { 'name' => "extract_date",
+	'desc' => "{PSPlug.extract_date}",
+	'type' => "flag" },
+      { 'name' => "extract_pages",
+	'desc' => "{PSPlug.extract_pages}",
+	'type' => "flag" },
+      { 'name' => "extract_title",
+	'desc' => "{PSPlug.extract_title}",
+	'type' => "flag" } ];
+
+my $options = { 'name'     => "PSPlug",
+		'desc'     => "{PSPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    push(@$inputargs,"-convert_to");
+    push(@$inputargs,"text");
+    push(@$inputargs,"-title_sub");
+    push(@$inputargs,'^(Page\s+\d+)?(\s*1\s+)?');
+    
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+    
+    my $self = (defined $hashArgOptLists)? new ConvertToPlug($pluginlist,$inputargs,$hashArgOptLists): new ConvertToPlug($pluginlist,$inputargs);
+
+    my $secondary_plugin_options = $self->{'secondary_plugin_options'};
+    if (!defined $secondary_plugin_options->{'TEXTPlug'}) {
+	$secondary_plugin_options->{'TEXTPlug'} = [];
+    }
+
+    my $text_options = $secondary_plugin_options->{'TEXTPlug'};
+   
+    # following title_sub removes "Page 1" added by ps2ascii, and a leading
+    # "1", which is often the page number at the top of the page. Bad Luck
+    # if your document title actually starts with "1 " - is there a better way?
+    #$self->{'input_encoding'} = "utf8";
+    #$self->{'extract_language'} = 1;
+    push(@$text_options, "-input_encoding", "utf8");
+    push(@$text_options,"-extract_language");
+    push(@$text_options , "-title_sub", '^(Page\s+\d+)?(\s*1\s+)?');
+
+    $self = bless $self, $class;
+
+    $self->load_secondary_plugins($class,$secondary_plugin_options, $hashArgOptLists);
+
+    return $self;
+}
+
+
+sub get_default_block_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.(eps)$^;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.ps$^;
+}
+
+sub convert_post_process
+{
+    my $self = shift (@_);
+    my ($conv_filename) = @_;
+    
+    my $outhandle=$self->{'outhandle'};
+    
+    my ($language, $encoding) = $self->textcat_get_language_encoding ($conv_filename);
+    
+    # read in file ($text will be in utf8)
+    my $text = "";
+    $self->read_file ($conv_filename, $encoding, $language, \$text);
+    
+    # turn any high bytes that aren't valid utf-8 into utf-8.
+    unicode::ensure_utf8(\$text);
+    
+    # Write it out again!
+    $self->utf8_write_file (\$text, $conv_filename);
+}
+
+sub extract_metadata_from_postscript {
+    my $self = shift (@_);
+
+    my ($filename,$doc) = @_;
+
+    my $section = $doc->get_top_section();
+
+    my $title_found = 0;
+    my $pages_found = 0;
+    my $date_found = 0;
+
+    print STDERR "PSPlug: extracting PostScript metadata from \"$filename\"\n" 
+	if $self->{'verbosity'} > 1;
+
+    open(INPUT, "<$filename");
+    my $date;
+
+    while(my $line =<INPUT>) {
+	if ($self->{'extract_title'} && !$title_found) {
+	    foreach my $word ($line =~ m|Title: ([-A-Za-z0-9@/\/\(\):,. ]*)|g) {
+		my $new_word = $word; 
+		$new_word =~ s/\(Untitled\)//i;
+		$new_word =~ s/\(Microsoft Word\)//i;
+		$new_word =~ s/Microsoft Word//i;
+		$new_word =~ s/^\(//i;
+		$new_word =~ s/\)$//i;
+		$new_word =~ s/^ - //i;
+		if ($new_word ne "") {
+		    $doc->add_utf8_metadata($section, "Title", $new_word );
+		    $title_found = 1;
+		}
+	    }
+	}
+	if ($self->{'extract_date'} && !$date_found) {
+            foreach my $word ($line =~ m/(Creation[-A-Za-z0-9@\/\(\):,. ]*)/g) {
+                if ($word =~ m/ ([A-Za-z][A-Za-z][A-Za-z]) ([0-9 ][0-9])  ?[0-9: ]+ ([0-9]{4})/) {
+                    $date = &sorttools::format_date($2,$1,$3);
+		    if (defined $date) {
+			$doc->add_utf8_metadata($section, "Date", $date );
+		    }
+                }
+                if ($word =~ m/D:([0-9]{4})([0-9]{2})([0-9]{2})[0-9]{6}\)/) {
+                    $date = &sorttools::format_date($3,$2,$1);
+		    if (defined $date) {
+			$doc->add_utf8_metadata($section, "Date", $date );
+		    }
+                }
+                if ($word =~ m/CreationDate: ([0-9]{4}) ([A-Za-z][A-Za-z][A-Za-z]) ([0-9 ][0-9]) [0-9:]*/) {
+                    $date = &sorttools::format_date($3,$2,$1);
+		    if (defined $date) {
+			$doc->add_utf8_metadata($section, "Date", $date );
+		    }
+                }
+		$date_found = 1;
+            }
+	}
+	if ($self->{'extract_pages'} && !$pages_found) {
+	    foreach my $word ($line =~ m/(Pages: [0-9]*)/g) {
+                my $digits = $word;
+                $digits =~ s/[^0-9]//g;
+		if ($digits ne "" && $digits ne "0") {
+		    $doc->add_utf8_metadata($section, "Pages", $digits );
+		    $pages_found = 1;
+		}
+            }
+	}
+    }
+}
+
+# do plugin specific processing of doc_obj for HTML type
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+
+#    my $outhandle = $self->{'outhandle'};
+
+#    print $outhandle "PSPlug: passing $file on to $self->{'converted_to'}Plug\n" 
+#	if $self->{'verbosity'} > 1;
+#    print STDERR "<Processing n='$file' p='PSPlug'>\n" if ($gli);
+
+    my $filename = &util::filename_cat($base_dir,$file);
+    $self->extract_metadata_from_postscript($filename, $doc_obj);
+
+    return $self->process_type("ps",$base_dir,$file,$doc_obj);
+}
+
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PagedImgPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PagedImgPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/PagedImgPlug.pm	(revision 10506)
@@ -0,0 +1,936 @@
+###########################################################################
+#
+# PagedImgPlug.pm -- plugin for sets of images and OCR text that
+#  make up a document
+# 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.
+#
+###########################################################################
+
+# PagedImgPlug
+# processes sequences of images, with optional OCR text
+#
+# This plugin takes *.item files, which contain metadata and lists of image 
+# files, and produces a document containing sections, one for each page.
+# The files should be named something.item, then you can have more than one 
+# book in a directory. You will need to create these files, one for each
+# document/book.
+#
+#There are two formats for the item files: a plain text format, and an xml 
+#format. You can use either format, and can have both formats in the same 
+#collection if you like. If you use the plain format, you must not start the 
+#file off with <PagedDocument>
+
+#### PLAIN FORMAT
+# The format of the xxx.item file is as follows:
+# The first lines contain any metadata for the whole document
+# <metadata-name>metadata-value
+# eg.
+# <Title>Snail farming
+# <Date>19230102
+# Then comes a list of pages, one page per line, each line has the format
+#
+# pagenum:imagefile:textfile:r
+#
+# page num and imagefile are required. pagenum is used for the Title 
+# of the section, and in the display is shown as page <pagenum>. 
+# imagefile is the image for the page. textfile is an optional text 
+# file containing the OCR (or any) text for the page - this gets added 
+# as the text for the section. r is optional, and signals that the image 
+# should be rotated 180deg. Eg use this if the image has been made upside down.
+# So an example item file looks like:
+# <Title>Snail farming
+# <Date>19960403
+# 1:p1.gif:p1.txt:
+# 2:p2.gif::
+# 3:p3.gif:p3.txt:
+# 3b:p3b.gif:p3b.txt:r
+# The second page has no text, the fourth page is a back page, and 
+# should be rotated.
+# 
+
+#### XML FORMAT
+# The xml format looks like the following
+#<PagedDocument>
+#<Metadata name="Title">The Title of the entire document</Metadata>
+#<Page pagenum="1" imgfile="xxx.jpg" txtfile="yyy.jpg">
+#<Metadata name="Title">The Title of this page</Metadata>
+#</Page>
+#... more pages
+#</PagedDocument>
+#PagedDocument contains a list of Pages, Metadata and PageGroups. Any metadata 
+#that is not inside another tag will belong to the document.
+#Each Page has a pagenum (not used at the moment), an imgfile and/or a txtfile.
+#These are both optional - if neither is used, the section will have no content.
+#Pages can also have metadata associated with them.
+#PageGroups can be introduced at any point - they can contain Metadata and Pages and other PageGroups. They are used to introduce hierarchical structure into the document.
+#For example
+#<PagedDocument>
+#<PageGroup>
+#<Page>
+#<Page>
+#</PageGroup>
+#<Page>
+#</PagedDocument>
+#would generate a structure like
+#X
+#--X
+#  --X
+#  --X
+#--X
+#PageGroup tags can also have imgfile/textfile metadata if you like - this way they get some content themselves.
+
+#Currently the XML structure doesn't work very well with the paged document type, unless you use numerical Titles for each section.
+#There is still a bit of work to do on this format:
+#* enable other text file types, eg html, pdf etc
+#* make the document paging work properly
+#* add pagenum as Title unless a Title is present?
+
+# All the supplemetary image amd text files should be in the same folder as 
+# the .item file.
+#
+# To display the images instead of the document text, you can use [srcicon] 
+# in the DocumentText format statement.
+# For example, 
+#
+# format DocumentText "<center><table width=_pagewidth_><tr><td>[srcicon]</td></tr></table></center>"
+#
+# To have it create thumbnail size images, use the '-thumbnail' option.
+# To have it create medium size images for display, use the '-screenview'
+# option. As usual, running 
+# 'perl -S pluginfo.pl PagedImgPlug' will list all the options.
+
+# If you want the resulting documents to be presented with a table of 
+# contents, use '-documenttype hierarchy', otherwise they will have 
+# next and previous arrows, and a goto page X box. 
+
+# If you have used -screenview, you can also use [screenicon] in the format
+# statement to display the smaller image.  Here is an example  that switches 
+# between the two: 
+#
+# format DocumentText "<center><table width=_pagewidth_><tr><td>{If}{_cgiargp_ eq full,<a href='_httpdocument_&d=_cgiargd_&p=small'>Switch to small version.</a>,<a href='_httpdocument_&d=_cgiargd_&p=full'>Switch to fullsize version</a>}</td></tr><tr><td>{If}{_cgiargp_ eq full,<a href='_httpdocument_&d=_cgiargd_&p=small' title='Switch to small version'>[srcicon]</a>,<a href='_httpdocument_&d=_cgiargd_&p=full' title='Switch to fullsize version'>[screenicon]</a>}</td></tr></table></center>"
+#
+# Additional metadata can be added into the .item files, alternatively you can 
+# use normal metadata.xml files, with the name of the xxx.item file as the 
+# FileName (only for document level metadata).
+
+package PagedImgPlug;
+
+use XMLPlug;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @PagedImgPlug::ISA = ('XMLPlug');
+}
+
+my $type_list =
+    [ { 'name' => "paged",
+        'desc' => "{PagedImgPlug.documenttype.paged}" },
+      { 'name' => "hierarchy",
+        'desc' => "{PagedImgPlug.documenttype.hierarchy}" } ];
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "string",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => "string",
+	'deft' => &get_default_block_exp(),
+	'reqd' => "no" },
+      { 'name' => "title_sub",
+	'desc' => "{HTMLPlug.title_sub}",
+	'type' => "string", 
+	'deft' => "" },
+      { 'name' => "noscaleup",
+	'desc' => "{ImagePlug.noscaleup}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "thumbnail",
+	'desc' => "{PagedImgPlug.thumbnail}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "thumbnailsize",
+	'desc' => "{ImagePlug.thumbnailsize}",
+	'type' => "int",
+	'deft' => "100",
+	'range' => "1,",
+	'reqd' => "no" },
+      { 'name' => "thumbnailtype",
+	'desc' => "{ImagePlug.thumbnailtype}",
+	'type' => "string",
+	'deft' => "gif",
+	'reqd' => "no" },
+      { 'name' => "screenview",
+	'desc' => "{PagedImgPlug.screenview}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "screenviewsize",
+	'desc' => "{PagedImgPlug.screenviewsize}",
+	'type' => "int",
+        'deft' => "500",
+        'range' => "1,",
+	'reqd' => "no" },
+      { 'name' => "screenviewtype",
+	'desc' => "{PagedImgPlug.screenviewtype}",
+	'type' => "string",
+	'deft' => "jpg",
+	'reqd' => "no" },
+      { 'name' => "converttotype",
+	'desc' => "{ImagePlug.converttotype}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "minimumsize",
+	'desc' => "{ImagePlug.minimumsize}",
+	'type' => "int",
+	'deft' => "100",
+	'range' => "1,",
+	'reqd' => "no" },
+      { 'name' => "headerpage",
+	'desc' => "{PagedImgPlug.headerpage}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "documenttype",
+	'desc' => "{PagedImgPlug.documenttype}",
+	'type' => "enum",
+	'list' => $type_list,
+	'deft' => "paged",
+	'reqd' => "no" } ];
+
+
+my $options = { 'name'     => "PagedImgPlug",
+		'desc'     => "{PagedImgPlug.desc}",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+    
+    my $self = (defined $hashArgOptLists)? new XMLPlug($pluginlist,$inputargs,$hashArgOptLists): new XMLPlug($pluginlist,$inputargs);
+    
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^\.item$^;
+}
+
+# want to block everything except the .item ones 
+# but instead we will block images and txt files
+sub get_default_block_exp {
+    my $self = shift (@_);
+    
+    return q^(?i)(\.jpe?g|\.gif|\.png|\.tif?f|\.te?xt|~)$^
+}
+
+# Create the thumbnail and screenview images, and discover the Image's
+# size, width, and height using the convert utility.
+sub process_image {
+    my $self = shift (@_);
+    my $filename = shift (@_); # filename with full path
+    my $srcfile = shift (@_); # filename without path
+    my $doc_obj = shift (@_);
+    my $section = shift (@_); #the current section
+    my $rotate = shift (@_); # whether to rotate the image or not
+    $rotate = 0 unless defined $rotate;
+    
+    my $top=0;
+    if ($section eq $doc_obj->get_top_section()) {
+	$top=1;
+    }
+    my $verbosity = $self->{'verbosity'};
+    my $outhandle = $self->{'outhandle'};
+
+    # check the filename is okay
+    return 0 if ($srcfile eq "" || $filename eq "");
+    
+    my $minimumsize = $self->{'minimumsize'};
+    if (defined $minimumsize && (-s $filename < $minimumsize)) {
+        print $outhandle "PagedImgPlug: \"$filename\" too small, skipping\n"
+	    if ($verbosity > 1);
+    }
+
+    # Convert the image to a new type (if required), and rotate if required.
+    my $converttotype = $self->{'converttotype'};
+    my $originalfilename = "";  # only set if we do a conversion
+    my $type = "unknown";
+    my $converted = 0;
+    my $rotated=0;
+
+    if ($converttotype ne "" && $filename !~ /$converttotype$/) {
+	$converted=1;
+	$originalfilename = $filename;
+	my $filehead = &util::get_tmp_filename();
+	$filename = $filehead . ".$converttotype";
+	my $n = 1;
+	while (-e $filename) {
+	    $filename = "$filehead$n\.$converttotype";
+	    $n++;
+	}
+	$self->{'tmp_filename1'} = $filename;
+
+	my $rotate_option = "";
+	if ($rotate eq "r") {
+	    $rotate_option = "-rotate 180 ";
+	}
+	
+	my $command = "convert -verbose \"$originalfilename\" $rotate_option \"$filename\"";
+	print $outhandle "CONVERT: $command\n" if ($verbosity > 2);
+	my $result = '';
+	$result = `$command`;
+	print $outhandle "CONVERT RESULT = $result\n" if ($verbosity > 2);
+
+	$type = $converttotype;
+    } elsif ($rotate eq "r") {
+	$rotated=1;
+	$originalfilename = $filename;
+	$filename  = &util::get_tmp_filename();
+	
+	my $command = "convert \"$originalfilename\" -rotate 180 \"$filename\"";
+	print $outhandle "ROTATE: $command\n" if ($verbosity > 2);
+	my $result = '';
+	$result = `$command`;
+	print $outhandle "ROTATE RESULT = $result\n" if ($verbosity > 2);
+	
+    } 
+    
+
+    # Add the image metadata
+    my $file; # the new file name
+    my $id = $srcfile;
+    $id =~ s/\.([^\.]*)$//;  # the new file name without an extension
+    if ($converted) {
+	# we have converted the image
+	# add on the new extension
+	$file .= "$id.$converttotype";
+    } else {
+	$file = $srcfile;
+    }
+    
+    my $url =$file; # the new file name prepared for a url
+    my $srcurl = $srcfile;
+    $url =~ s/ /%20/g;
+    $srcurl =~ s/ /%20/g;
+    
+    $doc_obj->add_metadata ($section, "Image", $url);
+
+    # Also want to set filename as 'Source' metadata to be
+    # consistent with other plugins
+    $doc_obj->add_metadata ($section, "Source", $srcurl);
+
+    my ($image_type, $image_width, $image_height, $image_size) 
+	= &identify($filename, $outhandle, $verbosity);
+
+    $doc_obj->add_metadata ($section, "ImageType",   $image_type);
+    $doc_obj->add_metadata ($section, "ImageWidth",  $image_width);
+    $doc_obj->add_metadata ($section, "ImageHeight", $image_height);
+    $doc_obj->add_metadata ($section, "ImageSize",   $image_size);
+    $doc_obj->add_metadata ($section, "FileFormat", "PagedImg");
+    
+    if ($type eq "unknown" && $image_type) {
+	$type = $image_type;
+    }
+
+    if ($top) {
+	$doc_obj->add_metadata ($section, "srclink", 
+				"<a href=\"_httpcollection_/index/assoc/[assocfilepath]/[Image]\">");
+	$doc_obj->add_metadata ($section, "srcicon", "<img src=\"_httpcollection_/index/assoc/[assocfilepath]/[Image]\">");
+
+    } else {
+	$doc_obj->add_metadata ($section, "srclink", 
+				"<a href=\"_httpcollection_/index/assoc/[parent(Top):assocfilepath]/[Image]\">");
+	$doc_obj->add_metadata ($section, "srcicon", "<img src=\"_httpcollection_/index/assoc/[parent(Top):assocfilepath]/[Image]\">");
+
+    }
+    $doc_obj->add_metadata ($section, "/srclink", "</a>");
+
+
+    # Add the image as an associated file
+    $doc_obj->associate_file($filename,$file,"image/$type",$section);
+    print $outhandle "associating file $filename as name $file\n" if ($verbosity > 2);
+
+    if ($self->{'thumbnail'}) {
+	# Make the thumbnail image
+	my $thumbnailsize = $self->{'thumbnailsize'} || 100;
+	my $thumbnailtype = $self->{'thumbnailtype'} || 'gif';
+	
+	my $filehead = &util::get_tmp_filename();
+	my $thumbnailfile = $filehead . ".$thumbnailtype";
+	my $n=1;
+	while (-e $thumbnailfile) {
+	    $thumbnailfile = $filehead . $n . ".$thumbnailtype";
+	    $n++;
+	}
+	
+	$self->{'tmp_filename2'} = $thumbnailfile;
+	
+	# Generate the thumbnail with convert
+	my $command = "convert  -verbose -geometry $thumbnailsize" 
+	    . "x$thumbnailsize \"$filename\" \"$thumbnailfile\"";
+	print $outhandle "THUMBNAIL: $command\n" if ($verbosity > 2);
+	my $result = '';
+	$result = `$command 2>&1` ;
+	print $outhandle "THUMB RESULT: $result\n" if ($verbosity > 2);
+	
+	# Add the thumbnail as an associated file ...
+	if (-e "$thumbnailfile") { 
+	    $doc_obj->associate_file("$thumbnailfile", $id."thumb.$thumbnailtype", "image/$thumbnailtype",$section);
+	    $doc_obj->add_metadata ($section, "ThumbType", $thumbnailtype);
+	    $doc_obj->add_metadata ($section, "Thumb", $id."thumb.$thumbnailtype");
+	    if ($top) {
+		$doc_obj->add_metadata ($section, "thumbicon", "<img src=\"_httpcollection_/index/assoc/[assocfilepath]/[Thumb]\" width=[ThumbWidth] height=[ThumbHeight]>");
+	    } else {
+		$doc_obj->add_metadata ($section, "thumbicon", "<img src=\"_httpcollection_/index/assoc/[parent(Top):assocfilepath]/[Thumb]\" width=[ThumbWidth] height=[ThumbHeight]>");
+	    }
+	}
+	
+	# Extract Thumnail metadata from convert output
+	if ($result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) {
+	    $doc_obj->add_metadata ($section, "ThumbWidth", $1);
+	    $doc_obj->add_metadata ($section, "ThumbHeight", $2);
+	}
+    }
+    # Make a screen-sized version of the picture if requested
+    if ($self->{'screenview'}) {
+	
+	# To do: if the actual image is smaller than the screenview size,
+	# we should use the original !
+
+	my $screenviewsize = $self->{'screenviewsize'} || 500;
+	my $screenviewtype = $self->{'screenviewtype'} || 'jpeg';
+	my $filehead = &util::get_tmp_filename();
+	my $screenviewfilename = $filehead . ".$screenviewtype";
+	my $n=1;
+	while (-e $screenviewfilename) {
+	    $screenviewfilename = "$filehead$n\.$screenviewtype";
+	    $n++;
+	}
+	$self->{'tmp_filename3'} = $screenviewfilename;
+
+	# make the screenview image
+	my $command = "convert  -verbose -geometry $screenviewsize" 
+	    . "x$screenviewsize \"$filename\" \"$screenviewfilename\"";
+	print $outhandle "SCREENVIEW: $command\n" if ($verbosity > 2);
+	my $result = "";
+	$result = `$command  2>&1` ;
+	print $outhandle "SCREENVIEW RESULT: $result\n" if ($verbosity > 3);
+
+	# get screenview dimensions, size and type
+        if ($result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) {
+	    $doc_obj->add_metadata ($section, "ScreenWidth", $1);
+	    $doc_obj->add_metadata ($section, "ScreenHeight", $2);
+	}elsif ($result =~ m/([0-9]+)x([0-9]+)/) {
+	    #if the image hasn't changed size,  the previous regex doesn't match
+	    $doc_obj->add_metadata ($section, "ScreenWidth", $1);
+	    $doc_obj->add_metadata ($section, "ScreenHeight", $2);
+	}
+    
+	#add the screenview as an associated file ...
+	if (-e "$screenviewfilename") { 
+	    $doc_obj->associate_file("$screenviewfilename", $id."sv.$screenviewtype",
+				     "image/$screenviewtype",$section);
+	    print $outhandle "associating screen file $screenviewfilename as name $id sv.$screenviewtype\n" if ($verbosity > 2);
+	    
+	    $doc_obj->add_metadata ($section, "ScreenType", $screenviewtype);
+	    $doc_obj->add_metadata ($section, "Screen", $id."sv.$screenviewtype");
+
+	    if ($top) {
+		$doc_obj->add_metadata ($section, "screenicon", "<img src=\"_httpcollection_/index/assoc/[assocfilepath]/[Screen]\" width=[ScreenWidth] height=[ScreenHeight]>");
+	    } else {
+		$doc_obj->add_metadata ($section, "screenicon", "<img src=\"_httpcollection_/index/assoc/[parent(Top):assocfilepath]/[Screen]\" width=[ScreenWidth] height=[ScreenHeight]>");
+
+	    }
+	} else {
+	    print $outhandle "PagedImgPlug: couldn't find \"$screenviewfilename\"\n";
+	}
+    }
+
+    return $type;
+
+
+}
+
+
+
+# Discover the characteristics of an image file with the ImageMagick
+# "identify" command.
+
+sub identify { 
+    my ($image, $outhandle, $verbosity) = @_;
+
+    # Use the ImageMagick "identify" command to get the file specs
+    my $command = "identify \"$image\" 2>&1";
+    print $outhandle "$command\n" if ($verbosity > 2);
+    my $result = '';
+    $result = `$command`;
+    print $outhandle "$result\n" if ($verbosity > 3);
+
+    # Read the type, width, and height
+    my $type =   'unknown';
+    my $width =  'unknown';
+    my $height = 'unknown';
+
+    my $image_safe = quotemeta $image;
+    if ($result =~ /^$image_safe (\w+) (\d+)x(\d+)/) {
+	$type = $1;
+	$width = $2;
+	$height = $3;
+    }
+	
+    # Read the size
+    my $size = "unknown";
+    if ($result =~ m/^.* ([0-9]+)b/) {
+	$size = $1;
+    } elsif ($result =~ m/^.* ([0-9]+)kb/) {
+	$size = 1024 * $1;
+    }
+
+    print $outhandle "file: $image:\t $type, $width, $height, $size\n" 
+	if ($verbosity > 3);
+
+    # Return the specs
+    return ($type, $width, $height, $size);
+}
+
+
+# The PagedImgPlug read() function. This function does all the right things
+# to make general options work for a given plugin. It calls the process()
+# function which does all the work specific to a plugin (like the old
+# read functions used to do). Most plugins should define their own 
+# process() function and let this read() function keep control.
+#
+# PagedImgPlug overrides read() because there is no need to read the actual 
+# text of the file in, because the contents of the file is not text...
+#
+# Return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+
+sub read_into_doc_obj {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    my $outhandle   = $self->{'outhandle'};
+    my $smart_block = $self->{'smart_block'};
+    
+    my $filename = &util::filename_cat($base_dir, $file);
+    
+    if ($self->associate_with($file,$filename,$metadata)) {
+	# a form of smart block
+	$self->{'num_blocked'} ++;
+	return 0; # blocked
+    }
+    
+    if ($smart_block) {
+	if (defined $self->{'file_blocks'}->{$filename} && $self->{'file_blocks'}->{$filename} == 1){
+	    $self->{'num_blocked'} ++;
+	    return 0; # blocked
+	}
+    } elsif ($self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/) {
+	$self->{'num_blocked'} ++;
+	return 0; # blocked
+    }
+    
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+    
+    print $outhandle "PagedImgPlug processing \"$filename\"\n"
+	if $self->{'verbosity'} > 1;
+    print STDERR "<Processing n='$file' p='PagedImgPlug'>\n" if ($gli);
+    
+    # here we need to decide if we have an old text .item file, or a new xml 
+    # .item file - for now the test is if the first non-empty line is 
+    # <PagedDocument> then its xml
+    my $xml_version = 0;
+    open (ITEMFILE, $filename) || die "couldn't open $filename\n";
+    
+    my $backup_filename = "backup.item";
+    open (BACKUP,">$backup_filename")|| die "couldn't write to $backup_filename\n";
+    my $line = "";
+    my $num = 0;
+    $line = <ITEMFILE>;
+    while ($line !~ /\w/) {
+	$line = <ITEMFILE>;
+    }
+    chomp $line;
+    if ($line =~ /<PagedDocument/) {
+	$xml_version = 1;
+    }
+    close ITEMFILE;
+    open (ITEMFILE, $filename) || die "couldn't open $filename\n";
+    #Tidy up the item file some metadata title contains \vt-vertical tab
+    while ($line = <ITEMFILE>) {
+	$line =~ s/\x0B+//ig;
+	$line =~ s/&/&amp;/g;
+	print BACKUP ($line);
+    }
+    close ITEMFILE;
+    close BACKUP;
+    &File::Copy::copy ($backup_filename, $filename);
+    &util::rm($backup_filename);
+    #print STDERR "xml version = $xml_version\n";
+    my $doc_obj;
+    if ($xml_version) {
+	$file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
+	$self->{'file'} = $file;
+	$self->{'filename'} = $filename;
+	$self->{'processor'} = $processor;
+	$self->{'metadata'} = $metadata;
+	$self->{'gli'} = $gli;
+	eval {
+	    $@ = "";
+	    my $xslt = $self->{'xslt'};
+	    if (defined $xslt && ($xslt ne "")) {
+		# perform xslt
+		my $transformed_xml = $self->apply_xslt($xslt,$filename);
+		
+		# feed transformed file (now in memory as string) into XML parser
+		#$self->{'parser'}->parse($transformed_xml);
+		$self->parse_string($transformed_xml);
+	    }
+	    else {
+		#$self->{'parser'}->parsefile($filename);
+		$self->parse_file($filename);
+	    }
+	};
+	
+	
+	
+	if ($@) {
+	    
+	    # parsefile may either croak somewhere in XML::Parser (e.g. because
+	    # the document is not well formed) or die somewhere in XMLPlug or a
+	    # derived plugin (e.g. because we're attempting to process a
+	    # document whose DOCTYPE is not meant for this plugin). For the
+	    # first case we'll print a warning and continue, for the second
+	    # we'll just continue quietly
+	    
+	    print STDERR "**** XML Parse Error is: $@\n";
+	    
+	    my ($msg) = $@ =~ /Carp::croak\(\'(.*?)\'\)/;
+	    if (defined $msg) {	
+		my $outhandle = $self->{'outhandle'};
+		my $plugin_name = ref ($self);
+		print $outhandle "$plugin_name failed to process $file ($msg)\n";
+	    }
+
+	    # reset ourself for the next document
+	    $self->{'section_level'}=0;
+	    print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	    return -1; # error during processing
+	}
+	$doc_obj = $self->{'doc_obj'};
+    } else {
+	my ($dir);
+	($dir, $file) = $filename =~ /^(.*?)([^\/\\]*)$/;
+
+	#process the .item file
+	$doc_obj = $self->process_item($filename, $dir, $file, $processor);
+	
+    }
+    
+    if ($self->{'cover_image'}) {
+	$self->associate_cover_image($doc_obj, $filename);
+    }
+
+    # include any metadata passed in from previous plugins 
+    # note that this metadata is associated with the top level section
+    my $section = $doc_obj->get_top_section();
+    $self->extra_metadata ($doc_obj, $section, $metadata);
+    #my $text="";
+    # do plugin specific processing of doc_obj
+    #unless (defined ($self->process(\$text, $pluginfo, $base_dir, $file, $metadata, $doc_obj))) {
+	#print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	#return -1;
+    #}
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata ($doc_obj);
+
+    $self->{'num_processed'}++;
+    return (1,$doc_obj);
+}
+
+sub read
+{
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my ($process_status,$doc_obj) = $self->read_into_doc_obj(@_);
+
+    if ((defined $process_status) && ($process_status == 1)) {
+	# process the document
+	$processor->process($doc_obj);
+
+	#if(defined($self->{'places_filename'})){
+	#    &util::rm($self->{'places_filename'});
+	#    $self->{'places_filename'} = undef;
+	#}
+	#$self->{'num_processed'} ++;
+	undef $doc_obj; 
+    }
+    
+    # clean up temporary files - we do this here instead of in  
+    # process_image becuase associated files aren't actually copied 
+    # until after process has been run.
+    if (defined $self->{'tmp_filename1'} && 
+	-e $self->{'tmp_filename1'}) {
+	&util::rm($self->{'tmp_filename1'})
+    }
+    if (defined $self->{'tmp_filename2'} && 
+	-e $self->{'tmp_filename2'}) {
+	&util::rm($self->{'tmp_filename2'})
+    }
+    if (defined $self->{'tmp_filename3'} && 
+	-e $self->{'tmp_filename3'}) {
+      &util::rm($self->{'tmp_filename3'})
+    }
+    # if process_status == 1, then the file has been processed.
+    return $process_status;
+}
+
+sub xml_start_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+    $self->{'element'} = $element;
+    
+    my $doc_obj = $self->{'doc_obj'};
+    if ($element eq "PagedDocument") {
+	$self->{'current_section'} = $doc_obj->get_top_section();
+    } elsif ($element eq "PageGroup" || $element eq "Page") {
+	# create a new section as a child
+	$self->{'current_section'} = $doc_obj->insert_section($doc_obj->get_end_child($self->{'current_section'}));
+	$self->{'num_pages'}++;
+	# assign pagenum as  what??
+	my $pagenum = $_{'pagenum'}; #TODO!!
+	$doc_obj->set_utf8_metadata_element($self->{'current_section'}, 'PageNum', $pagenum);
+	my ($imgfile) = $_{'imgfile'};
+	if (defined $imgfile) {
+	    $self->process_image($self->{'base_dir'}.$imgfile, $imgfile, $doc_obj, $self->{'current_section'});
+	}
+	my ($txtfile) = $_{'txtfile'};
+	if (defined($txtfile)&& $txtfile ne "") {
+	    $self->process_text ($self->{'base_dir'}.$txtfile, $txtfile, $doc_obj, $self->{'current_section'});
+	} else {
+	    # otherwise add in some dummy text 
+	    $doc_obj->add_text($self->{'current_section'}, &gsprintf::lookup_string("{BasPlug.dummy_text}"));
+	}
+    } elsif ($element eq "Metadata") {
+	$self->{'metadata_name'} = $_{'name'};
+    }
+}
+
+sub xml_end_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+    
+    my $doc_obj = $self->{'doc_obj'};
+    if ($element eq "Page" || $element eq "PageGroup") {
+	# if Title hasn't been assigned, set PageNum as Title
+	if (!defined $doc_obj->get_metadata_element ($self->{'current_section'}, "Title") && defined $doc_obj->get_metadata_element ($self->{'current_section'}, "PageNum" )) {
+	    $doc_obj->add_utf8_metadata ($self->{'current_section'}, "Title", $doc_obj->get_metadata_element ($self->{'current_section'}, "PageNum" ));
+	}
+	# move the current section back to the parent
+	$self->{'current_section'} = $doc_obj->get_parent_section($self->{'current_section'});
+    } elsif ($element eq "Metadata") {
+	
+	$doc_obj->add_utf8_metadata ($self->{'current_section'}, $self->{'metadata_name'}, $self->{'metadata_value'});
+	$self->{'metadata_name'} = "";
+	$self->{'metadata_value'} = "";
+
+    }
+    # otherwise we ignore the end tag
+}
+
+
+sub xml_text {
+    my $self = shift(@_);
+    my ($expat) = @_; 
+
+    if ($self->{'element'} eq "Metadata") {
+   	$self->{'metadata_value'} .= $_;
+    }
+}
+
+sub xml_doctype {
+}
+
+sub open_document {
+    my $self = shift(@_);
+    
+    # create a new document
+    $self->{'doc_obj'} = new doc ($self->{'filename'}, "indexed_doc");
+    my $doc_obj = $self->{'doc_obj'};
+    $doc_obj->set_OIDtype ($self->{'processor'}->{'OIDtype'});
+    my ($dir, $file) = $self->{'filename'} =~ /^(.*?)([^\/\\]*)$/;
+    $self->{'base_dir'} = $dir;
+    $self->{'num_pages'} = 0;
+    my $topsection = $doc_obj->get_top_section();
+    if ($self->{'documenttype'} eq 'paged') {
+	# set the gsdlthistype metadata to Paged - this ensures this document will
+	# be treated as a Paged doc, even if Titles are not numeric
+    
+	$doc_obj->set_utf8_metadata_element ($topsection, "gsdlthistype", "Paged");
+    } else {
+	$doc_obj->set_utf8_metadata_element ($topsection, "gsdlthistype", "Hierarchy");
+    }
+
+    $doc_obj->add_metadata ($topsection, "Source", $file);
+    if ($self->{'headerpage'}) {
+	$doc_obj->add_text($topsection, &gsprintf::lookup_string("{BasPlug.dummy_text}"));
+    }
+
+}
+
+sub close_document {
+    my $self = shift(@_);
+    my $doc_obj = $self->{'doc_obj'};
+        
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+    $doc_obj->add_metadata($doc_obj->get_top_section(), "FileFormat", "PagedImg");
+    
+    # add numpages metadata
+    $doc_obj->set_utf8_metadata_element ($doc_obj->get_top_section(), 'NumPages', $self->{'num_pages'});
+
+    # add an OID
+    $doc_obj->set_OID();
+    
+}
+
+sub process_item {
+    my $self = shift (@_);
+    my ($filename, $dir, $file, $processor) = @_;
+
+    my $doc_obj = new doc ($filename, "indexed_doc");
+    my $topsection = $doc_obj->get_top_section();
+
+    if ($self->{'documenttype'} eq 'paged') {
+	# set the gsdlthistype metadata to Paged - this ensures this document will
+	# be treated as a Paged doc, even if Titles are not numeric
+	$doc_obj->set_utf8_metadata_element ($topsection, "gsdlthistype", "Paged");
+    } else {
+	$doc_obj->set_utf8_metadata_element ($topsection, "gsdlthistype", "Hierarchy");
+    }
+
+    $doc_obj->add_metadata ($topsection, "Source", $file);
+
+    open (ITEMFILE, $filename) || die "couldn't open $filename\n";
+    my $line = "";
+    my $num = 0;
+    while (defined ($line = <ITEMFILE>)) {
+	next unless $line =~ /\w/;
+	chomp $line;
+	if ($line =~ /^<([^>]*)>(.*?)\s*$/) {
+	    $doc_obj->set_utf8_metadata_element ($topsection, $1, $2);
+	    #$meta->{$1} = $2;
+	} else {
+	    $num++;
+	    # line should be like page:imagefilename:textfilename:r - the r is optional -> means rotate the image 180 deg
+	    $line =~ s/^\s+//; #remove space at the front
+	    $line =~ s/\s+$//; #remove space at the end
+	    my ($pagenum, $imgname, $txtname, $rotate) = split /:/, $line;
+	    
+	    # create a new section for each image file
+	    my $cursection = $doc_obj->insert_section($doc_obj->get_end_child($topsection));
+	    # the page number becomes the Title
+	    $doc_obj->set_utf8_metadata_element($cursection, 'Title', $pagenum);
+	    # process the image for this page
+	    my $result = $self->process_image($dir.$imgname, $imgname, $doc_obj, $cursection, $rotate);
+	    
+	    if (!defined $result)
+	    {
+		print "PagedImgPlug: couldn't process image \"$dir.$imgname\" for item \"$filename\"\n";
+	    }
+	    
+	    # process the text file if one is there
+	    if (defined $txtname && $txtname ne "") {
+		$result = undef;
+		$result = $self->process_text ($dir.$txtname, $txtname, $doc_obj, $cursection);
+		if (!defined $result) {
+		    print "PagedImgPlug: couldn't process text file \"$dir.$txtname\" for item \"$filename\"\n";
+		}
+	    } else {
+		# otherwise add in some dummy text 
+		$doc_obj->add_text($cursection, &gsprintf::lookup_string("{BasPlug.dummy_text}"));
+	    }
+	}
+    }
+    
+    close ITEMFILE;
+
+    # if we want a header page, we need to add some text into the top section, otherwise this section will become invisible
+    if ($self->{'headerpage'}) {
+	$doc_obj->add_text($topsection, &gsprintf::lookup_string("{BasPlug.dummy_text}"));
+    }
+    $file =~ s/\.item//i;
+    $doc_obj->set_OID ();
+    # add numpages metadata
+    $doc_obj->set_utf8_metadata_element ($topsection, 'NumPages', "$num");
+    return $doc_obj;
+}
+
+sub process_text {
+    my $self = shift (@_);
+    my ($fullpath, $file, $doc_obj, $cursection) = @_;
+
+    # Do encoding stuff
+    my ($language, $encoding) = $self->textcat_get_language_encoding ($fullpath);
+
+    my $text="";
+    &BasPlug::read_file($self, $fullpath, $encoding, $language, \$text);
+    if (!length ($text)) {
+        my $plugin_name = ref ($self);
+        print "PagedImgPlug: ERROR: $fullpath contains no text\n" if $self->{'verbosity'};
+        return 0;
+    }
+
+    # we need to escape the escape character, or else mg will convert into
+    # eg literal newlines, instead of leaving the text as '\n'
+    $text =~ s/\\/\\\\/g; # macro language
+    $text =~ s/_/\\_/g; # macro language
+    $text =~ s/</&lt;/g;
+    $text =~ s/>/&gt;/g;
+ 
+    # insert preformat tags and add text to document object
+    $doc_obj->add_utf8_text($cursection, "<pre>\n$text\n</pre>");
+    
+    return 1;
+}
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    return 1;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ProCitePlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ProCitePlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ProCitePlug.pm	(revision 10506)
@@ -0,0 +1,241 @@
+###########################################################################
+#
+# ProCitePlug.pm -- A plugin for (exported) ProCite databases
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright 1999-2004 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 ProCitePlug;
+
+
+use multiread;
+use SplitPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+# ProCitePlug is a sub-class of SplitPlug
+sub BEGIN {
+    @ProCitePlug::ISA = ('SplitPlug');
+}
+
+
+my $arguments = 
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() },
+      { 'name' => "split_exp",
+	'desc' => "{SplitPlug.split_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_split_exp(),
+	'reqd' => "no" }
+      ];
+
+my $options = { 'name'     => "ProCitePlug",
+		'desc'     => "{ProCitePlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+# This plugin processes exported ProCite files with the suffix ".txt"
+sub get_default_process_exp
+{
+    return q^(?i)(\.txt)$^;
+}
+
+
+# This plugin splits the input text at every line
+sub get_default_split_exp
+{
+    return q^\n^;
+}
+
+
+sub new
+{
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new SplitPlug($pluginlist,$inputargs,$hashArgOptLists): new SplitPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+
+my %crazy_workform_mapping =
+    ( "A", "Book, Long Form",
+      "B", "Book, Short Form",
+      "C", "Journal, Long Form",
+      "D", "Journal, Short Form",
+      "E", "Report",
+      "F", "Newspaper",
+      "G", "Dissertation",
+      "H", "Trade Catalog",
+      "I", "Letter (Correspondence)",
+      "J", "Manuscript",
+      "K", "Conference Proceedings",
+      "L", "Map",
+      "M", "Music Score",
+      "N", "Sound Recording",
+      "O", "Motion Picture",
+      "P", "Audiovisual Material",
+      "Q", "Video Recording",
+      "R", "Art Work",
+      "S", "Computer Program",
+      "T", "Data File" );
+
+
+sub read_file
+{
+    my $self = shift (@_);
+    my ($filename, $encoding, $language, $textref) = @_;
+
+    # Store the workform definitions for this file
+    my %workform_definitions = ();
+
+    # Read the contents of the file into $textref
+    open(PROCITE_FILE, "<$filename");
+    my $reader = new multiread();
+    $reader->set_handle ('ProCitePlug::PROCITE_FILE');
+    $reader->set_encoding ($encoding);
+    $reader->read_file ($textref);
+    close(PROCITE_FILE);
+
+    # Read the workform definitions at the start of the file
+    while ($$textref =~ /^\<Workform Definition\>/) {
+	# Remove the workform definition line so it is not processed later as a record
+	$$textref =~ s/^\<Workform Definition\>(.*)\n//;
+	my $workform_definition = $1;
+
+	# Parse the workform definitions and store them for later
+	$workform_definition =~ s/^\"([^\"]*)\",//;
+	my $workform_name = $1;
+
+	my @workform_values;
+	while ($workform_definition !~ /^$/) {
+	    $workform_definition =~ s/^\"([^\"]*)\",?//;
+	    my $workform_field = $1;
+	    push(@workform_values, $workform_field);
+	}
+
+	# Remember this workform definition for when we're reading the records
+	$workform_definitions{$workform_name} = \@workform_values;
+    }
+
+    $self->{'workform_definitions'}->{$filename} = \%workform_definitions;
+}
+
+
+sub process
+{
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+    my $filename = &util::filename_cat($base_dir, $file);
+    my $cursection = $doc_obj->get_top_section();
+    # Report that we're processing the file
+    print STDERR "<Processing n='$file' p='ProCitePlug'>\n" if ($gli);
+    print $outhandle "ProCitePlug: processing $file\n"
+  	if ($self->{'verbosity'}) > 1;
+
+    # Build up an HTML view of the record for easy display at run-time
+    my $html_record = "";
+
+    # Read the record's workform indicator and record number
+    $$textref =~ s/^\"([^\"]*)\",\"([^\"]*)\",//;
+    my $workform_indicator = $1;
+    my $recordnum = $2;
+
+    # If necessary, map the workform indicator into something useful
+    if ($crazy_workform_mapping{$workform_indicator}) {
+	$workform_indicator = $crazy_workform_mapping{$workform_indicator};
+    }
+
+    # Check we know about the workform of this record
+    my %workform_definitions = %{$self->{'workform_definitions'}->{$filename}};
+    if (!$workform_definitions{$workform_indicator}) {
+	print STDERR "Unknown workform!\n";
+	return 0;
+    }
+
+    # Store the full record as the document text
+    $doc_obj->add_utf8_text($cursection, $$textref);
+
+    # Store workform and record number as metadata
+    $doc_obj->add_utf8_metadata($cursection, "pc.Workform", $workform_indicator);
+    $doc_obj->add_utf8_metadata($cursection, "pc.RecordNumber", $recordnum);
+    
+    # Store FileFormat metadata
+    $doc_obj->add_metadata($cursection, "FileFormat", "ProCite");
+
+    $html_record .= "<tr><td valign=top><b>Record Number: </b></td><td valign=top>$recordnum</td></tr>";
+
+    my @workform_values = @{$workform_definitions{$workform_indicator}};
+
+    # Read each field (surrounded by quotes) of the record
+    my $fieldnum = 0;
+    while ($$textref !~ /^$/) {
+	$$textref =~ s/^\"([^\"]*)\",?//;
+	my $field_value_raw = $1;
+
+	# Add non-empty metadata values to the document
+	unless ($field_value_raw eq "") {
+	    # Add the display name of the metadata field for format statement convenience
+	    my $field_name = $workform_values[$fieldnum];
+	    unless ($field_name eq "---") {
+		my $meta_name = "pc.Field" . ($fieldnum + 1) . "Name";
+		$doc_obj->add_utf8_metadata($cursection, $meta_name, $field_name);
+	    }
+
+	    $html_record .= "<tr><td valign=top><b>$field_name: </b></td><td valign=top>";
+
+	    # Multiple metadata values are separated with "//"
+	    foreach my $field_value (split(/\/\//, $field_value_raw)) {
+		my $meta_name = "pc.Field" . ($fieldnum + 1) . "Value";
+		$doc_obj->add_utf8_metadata($cursection, $meta_name, $field_value);
+
+		$html_record .= $field_value . "<br>";
+	    }
+
+	    $html_record .= "</td></tr>";
+	}
+
+	$fieldnum++;
+    }
+
+    # Store HTML view of record as metadata
+    $doc_obj->add_utf8_metadata($cursection, "HTMLDisplay", $html_record);
+
+    # Record was processed successfully
+    return 1;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RTFPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RTFPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RTFPlug.pm	(revision 10506)
@@ -0,0 +1,97 @@
+###########################################################################
+#
+# RTFPlug.pm -- plugin for importing Rich Text Format files.
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001 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.
+#
+###########################################################################
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package RTFPlug;
+
+use ConvertToPlug;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @RTFPlug::ISA = ('ConvertToPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "RTFPlug",
+		'desc'     => "{RTFPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+ 
+    my $self = (defined $hashArgOptLists)? new ConvertToPlug($pluginlist,$inputargs,$hashArgOptLists): new ConvertToPlug($pluginlist,$inputargs);
+
+    my $secondary_plugin_options = $self->{'secondary_plugin_options'};
+    if (!defined $secondary_plugin_options->{'TEXTPlug'}) {
+	$secondary_plugin_options->{'TEXTPlug'} = [];
+    }
+    if (!defined $secondary_plugin_options->{'HTMLPlug'}) {
+	$secondary_plugin_options->{'HTMLPlug'} = [];
+    }
+    my $text_options = $secondary_plugin_options->{'TEXTPlug'};
+    my $html_options = $secondary_plugin_options->{'HTMLPlug'};
+    
+    #$self->{'input_encoding'} = "utf8";
+    #$self->{'extract_language'} = 1;
+    push(@$text_options, "-input_encoding", "utf8");
+    push(@$text_options,"-extract_language");
+    
+
+    $self = bless $self, $class;
+
+    $self->load_secondary_plugins($class,$secondary_plugin_options, $hashArgOptLists);
+
+    return $self;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+    return q^(?i)\.rtf$^;
+}
+    
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+
+    return $self->process_type("rtf",$base_dir,$file,$doc_obj);
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RealMediaPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RealMediaPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RealMediaPlug.pm	(revision 10506)
@@ -0,0 +1,152 @@
+###########################################################################
+#
+# RealMediaPlug.pm -- Extract metadata from Real Media files
+#
+# Original code by Xin Gao
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2005 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package RealMediaPlug;
+
+
+use UnknownPlug;
+use rm::Header::PurePerl;
+
+use strict;
+no strict 'refs'; # make an exception so we can use variables as filehandles
+
+
+sub BEGIN {
+    @RealMediaPlug::ISA = ('UnknownPlug');
+}
+
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "RealMediaPlug",
+		'desc'     => "{RealMediaPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+# This plugin processes Real Media files with the suffixes ".rm" and ".rmvb"
+sub get_default_process_exp
+{
+    return q^(?i)(\.rm|rmvb)$^;
+}
+
+
+sub new
+{
+    my ($class) = shift(@_);
+    my ($pluginlist, $inputargs, $hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if (defined $arguments) { push(@{$hashArgOptLists->{"ArgList"}}, @{$arguments}); }
+    if (defined $options) { push(@{$hashArgOptLists->{"OptList"}}, $options); }
+
+    my $self = (defined $hashArgOptLists) ? new UnknownPlug($pluginlist, $inputargs, $hashArgOptLists) : new UnknownPlug($pluginlist, $inputargs);
+    
+    return bless $self, $class;
+}
+
+
+# do plugin specific processing of doc_obj
+sub read
+{
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+
+    # filename is the full pathname of the file
+    my $filename = &util::filename_cat($base_dir, $file);
+    return 0 if $self->{block_exp} ne "" && $filename =~ /$self->{'block_exp'}/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+
+    # Report that we're processing the file
+    print STDERR "<Processing n='$file' p='RealMediaPlug'>\n" if ($gli);
+    print $outhandle "RealMediaPlug: processing $file\n"
+  	if ($self->{'verbosity'}) > 1;
+
+    # create a new index document
+    my $doc_obj = new doc ($filename, "indexed_doc");
+    $doc_obj->set_OIDtype ("incremental");    # this is done to avoid hashing content of file
+    my $top_section = $doc_obj->get_top_section();
+
+    # replace spaces in filename with %20 in url for metadata entry
+    my $url = $file;
+    $url =~ s/ /%20/g;
+    # Source (filename) to be consistent with other plugins
+    $doc_obj->add_metadata($top_section, "Source", $url);
+
+    my $text = "";
+    my $real_media = rm::Header::PurePerl->new($filename);
+    foreach my $key (keys %{$real_media->info})
+    {
+	my $value = $real_media->info->{$key};
+	$doc_obj->add_metadata($top_section, $key, $value);
+	$text .= "$key: $value\n";
+    }
+
+    $doc_obj->add_utf8_text($top_section, "<pre>\n$text\n</pre>");
+
+    # srclink
+    $doc_obj->add_metadata($top_section, "FileFormat", "RealMedia");
+    $doc_obj->add_metadata($top_section, "srclink", "<a href=\"_httpcollection_/index/assoc/[assocfilepath]/[Source]\">");
+    $doc_obj->add_metadata($top_section, "/srclink", "</a>");
+    # srcicon (need to include "irmvideo.gif" in the greenstone images directory
+    $doc_obj->add_metadata($top_section, "srcicon", "<img src=\"_httpprefix_/images/irmvideo.gif\" title=\"Download\" border=0>");
+
+    # Add the actual file as an associated file
+    $doc_obj->associate_file($filename, $file, "RealMedia", $top_section);
+
+    # include any metadata passed in from previous plugins
+    my $section = $doc_obj->get_top_section();
+    $self->extra_metadata ($doc_obj, $section, $metadata);
+
+    # do plugin specific processing of doc_obj
+    return undef unless defined ($self->process (\$text, $pluginfo, $base_dir, $file, $metadata, $doc_obj));
+
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata($doc_obj);
+
+    # add an OID
+    $doc_obj->set_OID();
+
+    # process the document
+    $processor->process($doc_obj);
+
+    $self->{'num_processed'}++;
+    return 1;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RecPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RecPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RecPlug.pm	(revision 10506)
@@ -0,0 +1,666 @@
+###########################################################################
+#
+# RecPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# RecPlug is a plugin which recurses through directories processing
+# each file it finds.
+
+# RecPlug has one option: use_metadata_files.  When this is set, it will
+# check each directory for an XML file called "metadata.xml" that specifies
+# metadata for the files (and subdirectories) in the directory.
+#
+# Here's an example of a metadata file that uses three FileSet structures
+# (ignore the # characters):
+
+#<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+#<!DOCTYPE DirectoryMetadata SYSTEM "http://greenstone.org/dtd/DirectoryMetadata/1.0/DirectoryMetadata.dtd">
+#<DirectoryMetadata>
+#  <FileSet>
+#    <FileName>nugget.*</FileName>
+#    <Description>
+#      <Metadata name="Title">Nugget Point, The Catlins</Metadata>
+#      <Metadata name="Place" mode="accumulate">Nugget Point</Metadata>
+#    </Description>
+#  </FileSet>
+#  <FileSet>
+#    <FileName>nugget-point-1.jpg</FileName>
+#    <Description>
+#      <Metadata name="Title">Nugget Point Lighthouse, The Catlins</Metadata>
+#      <Metadata name="Subject">Lighthouse</Metadata>
+#    </Description>
+#  </FileSet>
+#  <FileSet>
+#    <FileName>kaka-point-dir</FileName>
+#    <Description>
+#      <Metadata name="Title">Kaka Point, The Catlins</Metadata>
+#    </Description>
+#  </FileSet>
+#</DirectoryMetadata>
+
+# Metadata elements are read and applied to files in the order they appear
+# in the file.
+#
+# The FileName element describes the subfiles in the directory that the
+# metadata applies to as a perl regular expression (a FileSet group may
+# contain multiple FileName elements). So, <FileName>nugget.*</FileName>
+# indicates that the metadata records in the following Description block
+# apply to every subfile that starts with "nugget".  For these files, a
+# Title metadata element is set, overriding any old value that the Title
+# might have had.
+#
+# Occasionally, we want to have multiple metadata values applied to a
+# document; in this case we use the "mode=accumulate" attribute of the
+# particular Metadata element.  In the second metadata element of the first
+# FileSet above, the "Place" metadata is accumulating, and may therefore be
+# given several values.  If we wanted to override these values and use a
+# single metadata element again, we could set the mode attribute to
+# "override" instead.  Remember: every element is assumed to be in override
+# mode unless you specify otherwise, so if you want to accumulate metadata
+# for some field, every occurance must have "mode=accumulate" specified.
+#
+# The second FileSet element above applies to a specific file, called
+# nugget-point-1.jpg.  This element overrides the Title metadata set in the
+# first FileSet, and adds a "Subject" metadata field.
+#
+# The third and final FileSet sets metadata for a subdirectory rather than
+# a file.  The metadata specified (a Title) will be passed into the
+# subdirectory and applied to every file that occurs in the subdirectory
+# (and to every subsubdirectory and its contents, and so on) unless the
+# metadata is explictly overridden later in the import.
+
+
+
+package RecPlug;
+
+use BasPlug;
+use plugin;
+use util;
+
+use File::Basename;
+use strict;
+no strict 'refs';
+
+BEGIN {
+    @RecPlug::ISA = ('BasPlug');
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+}
+
+use XMLParser;
+
+my $arguments =
+    [ { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_block_exp(),
+	'reqd' => "no" },
+      { 'name' => "use_metadata_files",
+	'desc' => "{RecPlug.use_metadata_files}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "recheck_directories",
+	'desc' => "{RecPlug.recheck_directories}",
+	'type' => "flag",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "RecPlug",
+		'desc'     => "{RecPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+my ($self);
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+    if ($self->{'use_metadata_files'}) {
+	# create XML::Parser object for parsing metadata.xml files
+	my $parser = new XML::Parser('Style' => 'Stream',
+				     'Handlers' => {'Char' => \&Char,
+						    'Doctype' => \&Doctype
+						    });
+
+	$self->{'parser'} = $parser;
+	$self->{'in_filename'} = 0;
+    }
+    
+    $self->{'subdir_extrametakeys'} = {};
+
+    return bless $self, $class;
+}
+
+sub begin {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $processor, $maxdocs) = @_;
+
+    my $proc_package_name = ref $processor;
+
+    if ($proc_package_name !~ /buildproc$/) {
+
+	# Only lookup timestamp info for import.pl
+
+	my $output_dir = $processor->getoutputdir();
+	my $archives_inf = &util::filename_cat($output_dir,"archives.inf");
+    
+	if ( -e $archives_inf ) {
+	    $self->{'inf_timestamp'} = -M $archives_inf;
+	}
+    }
+
+    $self->SUPER::begin($pluginfo, $base_dir, $processor, $maxdocs);
+}
+
+
+# return 1 if this class might recurse using $pluginfo
+sub is_recursive {
+    my $self = shift (@_);
+    
+    return 1;
+}
+
+sub get_default_block_exp {
+    my $self = shift (@_);
+    
+    return 'CVS';
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+
+# This function passes around metadata hash structures.  Metadata hash
+# structures are hashes that map from a (scalar) key (the metadata element
+# name) to either a scalar metadata value or a reference to an array of
+# such values.
+
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $in_metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    
+    my $outhandle = $self->{'outhandle'};
+    my $verbosity = $self->{'verbosity'};
+    my $read_metadata_files = $self->{'use_metadata_files'};
+
+    # Calculate the directory name and ensure it is a directory and
+    # that it is not explicitly blocked.
+    my $dirname = $file;
+    $dirname = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+    return undef unless (-d $dirname);
+    return 0 if ($self->{'block_exp'} ne "" && $dirname =~ /$self->{'block_exp'}/);
+
+    # check to make sure we're not reading the archives or index directory
+    my $gsdlhome = quotemeta($ENV{'GSDLHOME'});
+    if ($dirname =~ m/^$gsdlhome\/.*?\/import.*?\/(archives|index)$/) {
+	print $outhandle "RecPlug: $dirname appears to be a reference to a Greenstone collection, skipping.\n";
+        return 0;
+    }
+    
+    # check to see we haven't got a cyclic path...
+    if ($dirname =~ m%(/.*){,41}%) {
+	print $outhandle "RecPlug: $dirname is 40 directories deep, is this a recursive path? if not increase constant in RecPlug.pm.\n";
+	return 0;
+    }
+    
+    # check to see we haven't got a cyclic path...
+    if ($dirname =~ m%.*?import/(.+?)/import/\1.*%) {
+	print $outhandle "RecPlug: $dirname appears to be in a recursive loop...\n";
+	return 0;
+    }
+    
+    if (($verbosity > 2) && ((scalar keys %$in_metadata) > 0)) {
+        print $outhandle "RecPlug: metadata passed in: ", 
+	join(", ", keys %$in_metadata), "\n";
+    }
+    
+    # Recur over directory contents.
+    my (@dir, $subfile);
+    my $count = 0;
+    
+    print $outhandle "RecPlug: getting directory $dirname\n" if ($verbosity);
+    
+    # find all the files in the directory
+    if (!opendir (DIR, $dirname)) {
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file' r='Could not read directory $dirname'>\n";
+	}
+	print $outhandle "RecPlug: WARNING - couldn't read directory $dirname\n";
+	return -1; # error in processing
+    }
+    @dir = readdir (DIR);
+    closedir (DIR);
+
+    # Re-order the files in the list so any directories ending with .all are moved to the end
+    for (my $i = scalar(@dir) - 1; $i >= 0; $i--) {
+	if (-d &util::filename_cat($dirname, $dir[$i]) && $dir[$i] =~ /\.all$/) {
+	    push(@dir, splice(@dir, $i, 1));
+	}
+    }
+
+    # read XML metadata files (if supplied)
+    my $additionalmetadata = 0;      # is there extra metadata available?
+    my %extrametadata;               # maps from filespec to extra metadata keys
+    my @extrametakeys;               # keys of %extrametadata in order read
+
+    my $dirsepre = &util::get_re_dirsep();
+    my $dirsep    = &util::get_dirsep();
+    my $local_dirname = $dirname;
+    $local_dirname =~ s/^$base_dir($dirsepre)//;
+    $local_dirname .= $dirsep;
+
+    if (defined $self->{'subdir_extrametakeys'}->{$local_dirname}) {
+	my $extrakeys = $self->{'subdir_extrametakeys'}->{$local_dirname};
+	foreach my $ek (@$extrakeys) {
+	    my $extrakeys_re  = $ek->{'re'};
+	    my $extrakeys_md  = $ek->{'md'};
+	    push(@extrametakeys,$extrakeys_re);
+	    $extrametadata{$extrakeys_re} = $extrakeys_md;
+	}
+	delete($self->{'subdir_extrametakeys'}->{$local_dirname});
+    }
+
+    if ($read_metadata_files) {
+	#read the directory "metadata.xml" file
+	my $metadatafile = &util::filename_cat ($dirname, 'metadata.xml');
+	if (-e $metadatafile) {
+	    print $outhandle "RecPlug: found metadata in $metadatafile\n" 
+		if ($verbosity);
+	    $self->read_metadata_xml_file($metadatafile, \%extrametadata, \@extrametakeys);
+	    $additionalmetadata = 1;
+	}
+    }
+    
+    # apply metadata pass for each of the files in the directory
+    my $out_metadata; 
+    my $num_files = scalar(@dir);
+    for (my $i = 0; $i < scalar(@dir); $i++) {
+	my $subfile = $dir[$i];
+	my $this_file_base_dir = $base_dir;
+	last if ($maxdocs != -1 && $count >= $maxdocs);
+	next if ($subfile =~ m/^\.\.?$/);
+	#next if ($read_metadata_files && $subfile =~ /metadata\.xml$/);
+
+	# Recursively read each $subfile
+	print $outhandle "RecPlug metadata recurring: $subfile\n" if ($verbosity > 2);
+	
+	$count += &plugin::metadata_read ($pluginfo, $this_file_base_dir,
+					  &util::filename_cat($file, $subfile),
+					  $out_metadata, \@extrametakeys, \%extrametadata,
+					  $processor, $maxdocs, $gli);
+	$additionalmetadata = 1;
+    }
+   
+    # filter out any extrametakeys that mention subdirectories and store
+    # for later use (i.e. when that sub-directory is being processed)
+
+    foreach my $ek (@extrametakeys) {
+	my ($subdir_re,$extrakey_dir) = &File::Basename::fileparse($ek);
+	$extrakey_dir =~ s/\\\./\./g; # remove RE syntax
+
+	my $dirsep_re = &util::get_re_dirsep();
+
+	if ($ek =~ m/$dirsep_re/) { # specifies at least one directory
+	    my $md = $extrametadata{$ek};
+
+	    my $subdir_extrametakeys = $self->{'subdir_extrametakeys'};
+
+	    my $subdir_rec = { 're' => $subdir_re, 'md' => $md };
+	    push(@{$subdir_extrametakeys->{$extrakey_dir}},$subdir_rec);
+	}
+    }
+    
+    # import each of the files in the directory
+    $count=0;
+    for (my $i = 0; $i <= scalar(@dir); $i++) {
+	# When every file in the directory has been done, pause for a moment (figuratively!)
+	# If the -recheck_directories argument hasn't been provided, stop now (default)
+	# Otherwise, re-read the contents of the directory to check for new files
+	#   Any new files are added to the @dir list and are processed as normal
+	#   This is necessary when documents to be indexed are specified in bibliographic DBs
+	#   These files are copied/downloaded and stored in a new folder at import time
+	if ($i == $num_files) {
+	    last unless $self->{'recheck_directories'};
+
+	    # Re-read the files in the directory to see if there are any new files
+	    last if (!opendir (DIR, $dirname));
+	    my @dirnow = readdir (DIR);
+	    closedir (DIR);
+
+	    # We're only interested if there are more files than there were before
+	    last if (scalar(@dirnow) <= scalar(@dir));
+
+	    # Any new files are added to the end of @dir to get processed by the loop
+	    my $j;
+	    foreach my $subfilenow (@dirnow) {
+		for ($j = 0; $j < $num_files; $j++) {
+		    last if ($subfilenow eq $dir[$j]);
+		}
+		if ($j == $num_files) {
+		    # New file
+		    push(@dir, $subfilenow);
+		}
+	    }
+	    # When the new files have been processed, check again
+	    $num_files = scalar(@dir);
+	}
+
+	my $subfile = $dir[$i];
+	my $this_file_base_dir = $base_dir;
+	last if ($maxdocs != -1 && ($count + $total_count) >= $maxdocs);
+	next if ($subfile =~ /^\.\.?$/);
+	next if ($read_metadata_files && $subfile =~ /metadata\.xml$/);
+
+	# Follow Windows shortcuts
+	if ($subfile =~ /(?i)\.lnk$/ && $ENV{'GSDLOS'} =~ /^windows$/i) {
+	    require Win32::Shortcut;
+	    my $shortcut = new Win32::Shortcut(&util::filename_cat($dirname, $subfile));
+	    if ($shortcut) {
+		# The file to be processed is now the target of the shortcut
+		$this_file_base_dir = "";
+		$file = "";
+		$subfile = $shortcut->Path;
+	    }
+	}
+
+	# check for a symlink pointing back to a leading directory
+	if (-d "$dirname/$subfile" && -l "$dirname/$subfile") {
+	    # readlink gives a "fatal error" on systems that don't implement
+	    # symlinks. This assumes the the -l test above would fail on those.
+	    my $linkdest=readlink "$dirname/$subfile";
+	    if (!defined ($linkdest)) {
+		# system error - file not found?
+		warn "RecPlug: symlink problem - $!";
+	    } else {
+		# see if link points to current or a parent directory
+		if ($linkdest =~ m@^[\./\\]+$@ ||
+		    index($dirname, $linkdest) != -1) {
+		    warn "RecPlug: Ignoring recursive symlink ($dirname/$subfile -> $linkdest)\n";
+		    next;
+		    ;
+		}
+	    }
+	}
+
+	print $outhandle "RecPlug: preparing metadata for $subfile\n" if ($verbosity > 2);
+
+	# Make a copy of $in_metadata to pass to $subfile
+	$out_metadata = {};
+	&combine_metadata_structures($out_metadata, $in_metadata);
+
+	# Next add metadata read in XML files (if it is supplied)
+	if ($additionalmetadata == 1) {
+	    
+	    my ($filespec, $mdref);
+	    foreach $filespec (@extrametakeys) {
+		if ($subfile =~ /^$filespec$/) {
+		    print $outhandle "File \"$subfile\" matches filespec \"$filespec\"\n" 
+			if ($verbosity > 2);
+		    $mdref = $extrametadata{$filespec};
+		    &combine_metadata_structures($out_metadata, $mdref);
+		}
+	    }
+	}
+
+
+	my $file_subfile = &util::filename_cat($file, $subfile);
+	my $filename_subfile 
+	    = &util::filename_cat($this_file_base_dir,$file_subfile);
+	if (defined $self->{'inf_timestamp'}) {
+	    my $inf_timestamp = $self->{'inf_timestamp'};
+
+	    if (! -d $filename_subfile) {
+		my $filename_timestamp = -M $filename_subfile;
+		if ($filename_timestamp > $inf_timestamp) {
+		    # filename has been around for longer than inf
+#####		    print $outhandle "**** Skipping $subfile\n";
+		    next;
+		}
+	    }
+	}
+
+	# Recursively read each $subfile
+	print $outhandle "RecPlug recurring: $subfile\n" if ($verbosity > 2);
+	
+	$count += &plugin::read ($pluginfo, $this_file_base_dir,
+				 $file_subfile,
+				 $out_metadata, $processor, $maxdocs, ($total_count + $count), $gli);
+    }
+
+    return $count;
+}
+
+
+
+# Read a manually-constructed metadata file and store the data
+# it contains in the $metadataref structure.
+#
+# (metadataref is a reference to a hash whose keys are filenames
+# and whose values are metadata hash structures.)  
+
+sub read_metadata_xml_file {
+    my $self = shift(@_);
+    my ($filename, $metadataref, $metakeysref) = @_;
+    $self->{'metadataref'} = $metadataref;
+    $self->{'metakeysref'} = $metakeysref;
+    
+    eval {
+	$self->{'parser'}->parsefile($filename);
+    };
+
+    if ($@) {
+	die "RecPlug: ERROR $filename is not a well formed metadata.xml file ($@)\n";
+    }
+}
+
+sub Doctype {
+    my ($expat, $name, $sysid, $pubid, $internal) = @_;
+
+    # allow the short-lived and badly named "GreenstoneDirectoryMetadata" files 
+    # to be processed as well as the "DirectoryMetadata" files which should now
+    # be created by import.pl
+    die if ($name !~ /^(Greenstone)?DirectoryMetadata$/);
+}
+
+sub StartTag {
+    my ($expat, $element) = @_;
+
+    if ($element eq "FileSet") {
+	$self->{'saved_targets'} = [];
+	$self->{'saved_metadata'} = {};
+    }
+    elsif ($element eq "FileName") {
+	$self->{'in_filename'} = 1;
+    }
+    elsif ($element eq "Metadata") {
+	$self->{'metadata_name'} = $_{'name'};
+	if ((defined $_{'mode'}) && ($_{'mode'} eq "accumulate")) {
+	    $self->{'metadata_accumulate'} = 1;
+	} else {
+	    $self->{'metadata_accumulate'} = 0;
+	}
+    }
+}
+
+sub EndTag {
+    my ($expat, $element) = @_;
+
+    if ($element eq "FileSet") {
+	push (@{$self->{'metakeysref'}}, @{$self->{'saved_targets'}});
+	foreach my $target (@{$self->{'saved_targets'}}) {
+	    my $file_metadata = $self->{'metadataref'}->{$target};
+	    my $saved_metadata = $self->{'saved_metadata'};
+	    if (!defined $file_metadata) {
+		$self->{'metadataref'}->{$target} = $saved_metadata;
+	    }
+	    else {
+		$self->combine_metadata_structures($file_metadata,$saved_metadata);
+	    }
+	}
+    }
+    elsif ($element eq "FileName") {
+	$self->{'in_filename'} = 0;
+    }
+    elsif ($element eq "Metadata") {
+	$self->{'metadata_name'} = "";
+    }
+
+}
+
+sub store_saved_metadata
+{
+    my $self = shift(@_);
+    my ($mname,$mvalue,$md_accumulate) = @_;
+
+    if (defined $self->{'saved_metadata'}->{$mname}) {
+	if ($md_accumulate) {
+	    # accumulate mode - add value to existing value(s)
+	    if (ref ($self->{'saved_metadata'}->{$mname}) eq "ARRAY") {
+		push (@{$self->{'saved_metadata'}->{$mname}}, $mvalue);
+	    } else {
+		$self->{'saved_metadata'}->{$mname} = 
+		    [$self->{'saved_metadata'}->{$mname}, $mvalue];
+	    }
+	} else {
+	    # override mode
+	    $self->{'saved_metadata'}->{$mname} = $mvalue;
+	}
+    } else {
+	if ($md_accumulate) {
+	    # accumulate mode - add value into (currently empty) array
+	    $self->{'saved_metadata'}->{$mname} = [$mvalue];
+	} else {
+	    # override mode
+	    $self->{'saved_metadata'}->{$mname} = $mvalue;
+	}
+    }
+}
+
+
+sub Text {
+
+    if ($self->{'in_filename'}) {
+	# $_ == FileName content
+	push (@{$self->{'saved_targets'}}, $_);
+    }
+    elsif (defined ($self->{'metadata_name'}) && $self->{'metadata_name'} ne "") {
+	# $_ == Metadata content
+	my $mname = $self->{'metadata_name'};
+	my $mvalue = $_;
+	my $md_accumulate = $self->{'metadata_accumulate'};
+	$self->store_saved_metadata($mname,$mvalue,$md_accumulate);
+    }
+}
+
+# This Char function overrides the one in XML::Parser::Stream to overcome a
+# problem where $expat->{Text} is treated as the return value, slowing
+# things down significantly in some cases.
+sub Char {
+    use bytes;  # Necessary to prevent encoding issues with XML::Parser 2.31+
+    $_[0]->{'Text'} .= $_[1];
+    return undef;
+}
+
+# Combine two metadata structures.  Given two references to metadata
+# element structures, add every field of the second ($mdref2) to the first
+# ($mdref1).  
+#
+# Afterwards $mdref1 will be updated, and $mdref2 will be unchanged.
+#
+# We have to be careful about the way we merge metadata when one metadata
+# structure is in "override" mode and one is in "merge" mode.  In fact, we
+# use the mode from the second structure, $mdref2, because it is generally
+# defined later (lower in the directory structure) and is therefore more
+# "local" to the document concerned.
+#
+# Another issue is the use of references to pass metadata around.  If we
+# simply copy one metadata structure reference to another, then we're
+# effectively just copyinga pointer, and changes to the new referene
+# will affect the old (copied) one also.  This also applies to ARRAY
+# references used as metadata element values (hence the "clonedata"
+# function below).
+
+sub combine_metadata_structures { 
+    my ($mdref1, $mdref2) = @_;
+    my ($key, $value1, $value2);
+
+    foreach $key (keys %$mdref2) {
+
+	$value1 = $mdref1->{$key};
+	$value2 = $mdref2->{$key};
+	
+	# If there is no existing value for this metadata field in 
+	# $mdref1, so we simply copy the value from $mdref2 over.
+	if (!defined $value1) {
+	    $mdref1->{$key} = &clonedata($value2);
+	} 
+	# Otherwise we have to add the new values to the existing ones.
+	# If the second structure is accumulated, then acculate all the
+	# values into the first structure
+	elsif ((ref $value2) eq "ARRAY") {
+	    # If the first metadata element is a scalar we have to 
+	    # convert it into an array before we add anything more.
+	    if ((ref $value1) ne 'ARRAY') {
+		$mdref1->{$key} = [$value1];
+		$value1 = $mdref1->{$key};
+	    }
+	    # Now add the value(s) from the second array to the first
+	    $value2 = &clonedata($value2);
+	    push @$value1, @$value2;
+	} 
+	# Finally, If the second structure is not an array erference, we
+	# know it is in override mode, so override the first structure.
+	else {
+	    $mdref1->{$key} = &clonedata($value2);
+	}
+    }
+}
+
+
+# Make a "cloned" copy of a metadata value.  
+# This is trivial for a simple scalar value,
+# but not for an array reference.
+
+sub clonedata {
+    my ($value) = @_;
+    my $result;
+
+    if ((ref $value) eq 'ARRAY') {
+	$result = [];
+	foreach my $item (@$value) {
+	    push @$result, $item;
+	}
+    } else {
+	$result = $value;
+    }
+    return $result;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ReferPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ReferPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ReferPlug.pm	(revision 10506)
@@ -0,0 +1,313 @@
+###########################################################################
+#
+# ReferPlug.pm - a plugin for bibliography records in Refer format
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright 2000 Gordon W. Paynter
+# Copyright 1999-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.
+#
+###########################################################################
+
+# ReferPlug reads bibliography files in Refer format.
+#
+# by Gordon W. Paynter (gwp@cs.waikato.ac.nz), November 2000
+#
+# Loosely based on hcibib2Plug by Steve Jones (stevej@cs.waikato.ac.nz).
+# Which was based on EMAILPlug by Gordon Paynter (gwp@cs.waikato.ac.nz).
+# Which was based on old versions of HTMLplug and HCIBIBPlugby by Stefan
+# Boddie and others -- it's hard to tell what came from where, now.
+#
+#
+# ReferPlug creates a document object for every reference in the file.
+# It is a subclass of SplitPlug, so if there are multiple records, all
+# are read.
+#
+# Document text:
+#   The document text consists of the reference in Refer format
+#
+# Metadata:
+#	$Creator	%A	Author name
+#	$Title		%T	Title of article of book
+#	$Journal	%J	Title of Journal
+#	$Booktitle	%B	Title of book containing the publication
+#	$Report		%R	Type of Report, paper or thesis
+#	$Volume		%V	Volume Number of Journal
+#	$Number		%N	Number of Journal within Volume
+#	$Editor		%E	Editor name
+#	$Pages		%P	Page Number of article
+#	$Publisher	%I	Name of Publisher
+#	$Publisheraddr	%C	Publisher's address
+#	$Date		%D	Date of publication
+#	$Keywords	%K	Keywords associated with publication 
+#	$Abstract	%X	Abstract of publication
+#	$Copyright	%*	Copyright information for the article
+#
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package ReferPlug;
+
+use SplitPlug;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+# ReferPlug is a sub-class of BasPlug.
+sub BEGIN {
+    @ReferPlug::ISA = ('SplitPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "split_exp",
+	'desc' => "{SplitPlug.split_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_split_exp() } 
+      ];
+
+my $options = { 'name'     => "ReferPlug",
+		'desc'     => "{ReferPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+# This plugin processes files with the suffix ".bib"
+sub get_default_process_exp {
+    return q^(?i)\.bib$^;
+}
+
+# This plugin splits the input text at blank lines
+sub get_default_split_exp {
+    return q^\n\s*\n^;
+}
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new SplitPlug($pluginlist,$inputargs,$hashArgOptLists): new SplitPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+# The process function reads a single bibliogrphic record and stores
+# it as a new document.
+
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    # Check that we're dealing with a valid Refer file
+    return undef unless ($$textref =~ /^\s*%/);
+
+    my $cursection = $doc_obj->get_top_section();
+    # Report that we're processing the file
+    print STDERR "<Processing n='$file' p='ReferPlug'>\n" if ($gli);
+    print $outhandle "ReferPlug: processing $file\n"
+	if ($self->{'verbosity'}) > 1;
+
+    my %field = ('H', 'Header',
+		 'A', 'Creator',
+		 'T', 'Title',
+		 'J', 'Journal',
+		 'B', 'Booktitle',
+		 'R', 'Report',
+		 'V', 'Volume',
+		 'N', 'Number',
+		 'E', 'Editor',
+		 'P', 'Pages',
+		 'I', 'Publisher',
+		 'C', 'PublisherAddress',
+		 'D', 'Date',
+		 'O', 'OtherInformation',
+		 'K', 'Keywords',
+		 'X', 'Abstract',
+		 '*', 'Copyright');
+
+    # Metadata fields 
+    my %metadata;
+    my ($id, $Creator, $Keywords, $text);
+    my @lines = split(/\n+/, $$textref);
+
+    
+    # Read and process each line in the bib file.
+    # Each file consists of a set of metadata items, one to each line
+    # with the Refer key followed by a space then the associated data
+    foreach my $line (@lines) {
+	
+	# Add each line.  Most lines consist of a field identifer and
+	# then data, and we simply store them, though we treat some
+	# of the fields a bit differently.
+
+	$line =~ s/\s+/ /g;
+	$text .= "$line\n";
+	# $ReferFormat .= "$line\n"; # what is this???
+	
+	next unless ($line =~ /^%[A-Z\*]/);
+	$id = substr($line,1,1);
+	$line =~ s/^%. //;
+   	
+	# Add individual authors in "Lastname, Firstname" format.
+	# (The full set of authors will be added below as "Creator".)
+	if ($id eq "A") {
+
+	    # Reformat and add author name
+	    my @words = split(/ /, $line);
+	    my $lastname = pop @words;
+	    my $firstname = join(" ",  @words);
+	    my $fullname = $lastname . ", " . $firstname;
+	    
+	    # Add each name to set of Authors
+	    if ($fullname =~ /\w/) {
+		$fullname = &text_into_html($fullname);
+		$doc_obj->add_metadata ($cursection, "Author", $fullname);
+	    }
+	}
+	# Add FileFormat as the metadata
+	$doc_obj->add_metadata($cursection,"FileFormat","Refer");
+
+	# Add individual keywords.
+	# (The full set of authors will be added below as "Keywords".)
+	if ($id eq "K") {
+	    my @keywordlist = split(/,/, $line);
+	    foreach my $k (@keywordlist) {
+		$k = lc($k);
+		$k =~ s/\s*$//; 
+		$k =~ s/^\s*//; 
+		if ($k =~ /\w/) {
+		    $k = &text_into_html($k);
+		    $doc_obj->add_metadata ($cursection, "Keyword", $k);
+		}
+	    } 
+	}
+	
+	# Add this line of metadata
+	$metadata{$id} .= "$line\n";
+    }
+
+
+
+    # Add the various field as metadata
+    my ($f, $name, $value);
+    foreach $f (keys %metadata) {
+	
+	next unless (defined $field{$f});
+	next unless (defined $metadata{$f});	
+
+	$name = $field{$f};
+	$value = $metadata{$f};
+
+	# Add the various field as metadata	
+	
+	# The Creator metadata is found by concatenating authors.
+	if ($f eq "A") {
+
+	    my @authorlist = split(/\n/, $value);
+	    my $lastauthor = pop @authorlist;
+	    my $Creator = "";
+	    if (scalar @authorlist) {
+		$Creator = join(", ", @authorlist) . "and $lastauthor";
+	    } else {
+		$Creator = $lastauthor;
+	    }
+
+	    if ($Creator =~ /\w/) {
+		$Creator = &text_into_html($Creator);
+		$doc_obj->add_metadata ($cursection, "Creator", $Creator);
+	    }
+	}
+
+	# The rest are added in a standard way
+	else {
+	    $value = &text_into_html($value);
+	    $doc_obj->add_metadata ($cursection, $name, $value);
+	}
+
+	# Books and Journals are additionally marked for display purposes
+	if ($f eq "B") {
+	    $doc_obj->add_metadata($cursection, "BookConfOnly", 1);
+	} elsif ($f eq "J") {
+	    $doc_obj->add_metadata($cursection, "JournalsOnly", 1); 
+	}
+
+
+    }
+
+    # Add the text in refer format(all fields)
+    if ($text =~ /\w/) {
+	$text = &text_into_html($text);
+	$doc_obj->add_text ($cursection, $text);
+    }
+
+    return 1; # processed the file
+}
+
+1;
+#
+# Convert a text string into HTML.
+#
+# The HTML is going to be inserted into a GML file, so 
+# we have to be careful not to use symbols like ">",
+# which ocurs frequently in email messages (and use
+# &gt instead.
+#
+# This function also turns links and email addresses into hyperlinks,
+# and replaces carriage returns with <BR> tags (and multiple carriage
+# returns with <P> tags).
+#
+
+sub text_into_html {
+    my ($text) = @_;
+
+
+    # Convert problem charaters into HTML symbols
+    $text =~ s/&/&amp;/g;
+    $text =~ s/</&lt;/g;
+    $text =~ s/>/&gt;/g;
+    $text =~ s/\"/&quot;/g;
+    $text =~ s/\'/ /g;
+    $text =~ s/\+/ /g;
+    $text =~ s/\(/ /g;
+    $text =~ s/\)/ /g;
+
+    # convert email addresses and URLs into links
+    $text =~ s/([\w\d\.\-]+@[\w\d\.\-]+)/<a href=\"mailto:$1\">$1<\/a>/g;
+    $text =~ s/(http:\/\/[\w\d\.\-]+[\/\w\d\.\-]*)/<a href=\"$1">$1<\/a>/g;
+
+    # Clean up whitespace and convert \n charaters to <BR> or <P>
+    $text =~ s/ +/ /g;
+    $text =~ s/\s*$//; 
+    $text =~ s/^\s*//; 
+    $text =~ s/\n/\n<BR>/g;
+    $text =~ s/<BR>\s*<BR>/<P>/g;
+
+    return $text;
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RogPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RogPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/RogPlug.pm	(revision 10506)
@@ -0,0 +1,288 @@
+###########################################################################
+#
+# RogPlug.pm -- simple text plugin
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# creates simple single-level document from .rog or .mdb files 
+
+package RogPlug;
+
+use BasPlug;
+use sorttools;
+use doc; 
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @RogPlug::ISA = ('BasPlug');
+}
+
+my $arguments = 
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'reqd' => "no",
+	'deft' => &get_default_process_exp() },
+      ];
+
+my $options = { 'name'     => "RogPlug",
+		'desc'     => "{RogPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "Yes",
+		'args' => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 0; # this is not a recursive plugin
+}
+
+
+# This plugin processes files with the suffix ".mdb" or ".rog"
+sub get_default_process_exp {
+    return q^(?i)\.(mdb|rog)$^;
+}
+
+sub read_rog_record
+{
+    my ($self,$file_buffer, $seclevel) = @_;
+
+    my $next_line = $file_buffer->{'next_line'};
+
+    return 0 if (!defined $next_line);
+
+    if ($next_line eq "")
+    {
+	my $line;
+	while(defined($line=<FILE>))  
+	{
+	    $line =~ s/\r$//;
+	    $file_buffer->{'line_no'}++;
+	    next if ($line =~ m/^\#/);
+	    $next_line = $line;
+	    last;
+	}
+    }
+	    
+    if ($next_line !~ m/^song( +)\"([^\"]*)\"( +)\"([^\"]*)\"( +)(\d+)( *)$/) 
+    {
+	print STDERR "Error: Malformed Rog file: $next_line";
+	return 0;
+    }
+    else
+    {
+	# init default values
+	$file_buffer->{'song'}->{'tempo'}    = 120;
+	$file_buffer->{'song'}->{'ks_type'}  = 0;
+	$file_buffer->{'song'}->{'ks_num'}   = 0;
+	$file_buffer->{'song'}->{'metadata'} = [];
+	$file_buffer->{'song'}->{'content'}  = "";
+	
+	$file_buffer->{'song'}->{'subcol'} = $2;
+	$file_buffer->{'song'}->{'title'}  = $4;
+	$file_buffer->{'song'}->{'tval'}   = $6;
+
+	chomp($next_line);
+	my $content = $next_line;
+	if (defined $seclevel) 
+	{
+	    $content.= " $seclevel";
+	}
+	$content .= "\n";
+
+	$file_buffer->{'song'}->{'content'} = $content;
+
+
+	my $line;
+	while(defined($line=<FILE>))  
+	{
+	    $line =~ s/\r$//;
+
+	    $file_buffer->{'line_no'}++;
+	    next if ($line =~ m/^\#/);
+	
+	    if ($line =~ m/^song/) 
+	    {	
+		$file_buffer->{'next_line'} = $line;
+		return 1;
+	    }
+	    elsif ($line =~ m/^tempo( +)(\d+)( *)$/) 
+	    {
+		$file_buffer->{'song'}->{'tempo'} = $2;
+		$file_buffer->{'song'}->{'content'} .= $line;
+	    } 
+	    elsif ($line =~ m/^keysig( +)(\d+)( +)(\d+)( *)$/) 
+	    {
+		$file_buffer->{'song'}->{'ks_type'} = $2;
+		$file_buffer->{'song'}->{'ks_num'}  = $4;
+		$file_buffer->{'song'}->{'content'} .= $line;	   
+	    } 
+	    elsif ($line =~ m/^timesig( +)(\d+)( +)(\d+)( *)$/) 
+	    {
+		$file_buffer->{'song'}->{'ts_numer'} = $2;
+		$file_buffer->{'song'}->{'ts_denom'} = $4;
+		$file_buffer->{'song'}->{'content'} .= $line;
+	    }
+	    elsif ($line =~ m/^metadata ([^:]*): (.*)/)
+	    {
+		push(@{$file_buffer->{'song'}->{'metadata'}},[$1,$2]);
+		$file_buffer->{'song'}->{'content'} .= $line;
+	    }
+	    else
+	    {
+		$file_buffer->{'song'}->{'content'} .= $line;
+	    }
+	}
+	
+	$file_buffer->{'next_line'} = undef;
+    }
+
+    return 1;
+}
+
+sub process_rog_record
+{
+    my ($self,$file,$metadata,$song,$processor) = @_;
+
+    # create a new document
+    my $doc_obj = new doc ($file, "indexed_doc");
+    my $cursection = $doc_obj->get_top_section();
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+
+    my $title = $song->{'title'};
+    my $title_safe = $title;
+    $title_safe =~ s/\'/\\\\&apos;/g;
+
+    # add metadata 
+    $doc_obj->add_metadata($cursection, "Tempo",         $song->{'tempo'}); 
+    $doc_obj->add_metadata($cursection, "KeySigType",    $song->{'ks_type'}); 
+    $doc_obj->add_metadata($cursection, "KeySigNum",     $song->{'ks_num'}); 
+    $doc_obj->add_metadata($cursection, "SubCollection", $song->{'subcol'}); 
+    $doc_obj->add_metadata($cursection, "Title",         $title); 
+    $doc_obj->add_metadata($cursection, "TitleSafe",     $title_safe); 
+    $doc_obj->add_metadata($cursection, "TVal",          $song->{'tval'}); 
+    $doc_obj->add_metadata($cursection, "FileFormat",    "Rog");
+    $doc_obj->add_metadata($cursection, "FileSize",      (-s $file));
+
+    foreach my $md ( @{$song->{'metadata'}} )
+    {
+	$doc_obj->add_metadata($cursection, $md->[0], $md->[1]); 
+    }
+
+    # add contents as text
+    $doc_obj->add_text($cursection,$song->{'content'});
+
+    $self->extra_metadata($doc_obj,$cursection, $metadata);
+    
+    # add OID
+    $doc_obj->set_OID ();
+
+    my $oid = $doc_obj->get_OID();
+    my $appletlink = "<a href=\"javascript:meldexout(\'$oid\','[TitleSafe]')\">";
+
+    $doc_obj->add_utf8_metadata ($cursection, "audiolink",  $appletlink); 
+    $doc_obj->add_utf8_metadata ($cursection, "audioicon",  "_iconaudio_"); 
+    $doc_obj->add_utf8_metadata ($cursection, "/audiolink", "</a>"); 
+
+    # process the document
+    $processor->process($doc_obj);
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my $filename = &util::filename_cat($base_dir, $file);
+
+    return undef unless ($filename =~ /\.((rog|mdb)(\.gz)?)$/i && (-e $filename));
+
+    my $gz = (defined $3) ? 1: 0;
+
+    	print STDERR "<Processing n='$file' p='RogPlug'>\n" if ($gli);
+    print STDERR "RogPlug: processing $filename\n" if $processor->{'verbosity'};
+    
+    if ($gz) {
+	open (FILE, "zcat $filename |") 
+	    || die "RogPlug::read - zcat can't open $filename\n";
+    } else {
+	open (FILE, $filename) 
+	    || die "RogPlug::read - can't open $filename\n";
+    }
+
+    my $doc_count = 0;
+    my $dot_count = 0;
+    my $file_buffer = { line_no => 0, next_line => "", song => {} };
+
+    while ($self->read_rog_record($file_buffer))
+    {
+	$self->process_rog_record($file,$metadata,$file_buffer->{'song'},$processor);
+	$doc_count++;
+
+	last if ($maxdocs !=-1 && ($total_count+$doc_count) >= $maxdocs);
+	
+	if (($doc_count % 10) == 0)
+	{
+	    print STDERR ".";
+	    $dot_count++;
+	    print STDERR "\n" if (($dot_count % 80) == 0);
+	}
+    }
+
+    close FILE;
+
+    print STDERR "\n";
+
+    $self->{'num_processed'} = $doc_count;
+
+    return 1; # processed the file
+}
+
+1;
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/SRCPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/SRCPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/SRCPlug.pm	(revision 10506)
@@ -0,0 +1,249 @@
+###########################################################################
+#
+# SRCPlug.pm -- source code plugin
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+# John McPherson Nov 2000
+# originally based on TEXTPlug
+
+# filename is currently used for Title ( optionally minus some prefix )
+
+# Current languages:
+#   text: READMEs/Makefiles
+#   C/C++   (currently extracts #include statements and C++ class decls)
+#   Perl    (currently only done as text)
+#   Shell   (currently only done as text)
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package SRCPlug;
+
+use BasPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @SRCPlug::ISA = ('BasPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" } ,
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_block_exp(),
+	'reqd' => "no" },
+      { 'name' => "remove_prefix",
+	'desc' => "{SRCPlug.remove_prefix}",
+	'type' => "regexp",
+	'deft' => "^.*[/\\]",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "SRCPlug",
+		'desc'     => "{SRCPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub get_default_block_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.(o|obj|a|so|dll)$^;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+#    return q^(?i)\.te?xt$^;
+    return q^(Makefile.*|README.*|(?i)\.(c|cc|cpp|C|h|hpp|pl|pm|sh))$^;
+}
+
+
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    	print STDERR "<Processing n='$file' p='SRCPlug'>\n" if ($gli);
+    print $outhandle "SRCPlug: processing $file\n" 
+	if $self->{'verbosity'} > 1;
+    
+    my $cursection = $doc_obj->get_top_section();
+
+    my $filetype="text";  # Makefiles, READMEs, ...
+    if ($file =~ /\.(cc|h|cpp|C)$/) {$filetype="C++";} # assume all .h files...
+    elsif ($file =~ /\.c$/)         {$filetype="C";}
+    elsif ($file =~ /\.p(l|m)$/)    {$filetype="perl";}
+    elsif ($file =~ /\.sh$/)        {$filetype="sh";}
+
+    # modify '<' and '>' for GML... (even though inside <pre> tags!!)
+    $$textref =~ s/</&lt;/g;
+    $$textref =~ s/>/&gt;/g;
+    $$textref =~ s/_/&#95;/g;
+    # try _escape_text($text) from doc.pm....
+
+    # don't want mg to turn escape chars into actual values
+    $$textref =~ s/\\/\\\\/g;
+
+    # use filename (minus any prefix) as the title.
+    my $title;
+    if ($self->{'remove_prefix' ne ""}) {
+	($title = $file) =~ s/^$self->{'remove_prefix'}//;
+    } else {
+	($title = $file) =~ s@^.*[/\\]@@; # remove pathname by default
+    }
+    $doc_obj->add_utf8_metadata ($cursection, "Title", $title);
+    $doc_obj->add_metadata ($cursection, "FileFormat", "SRC");
+
+    # remove the gsdl prefix from the filename
+    my $relative_filename=$file;
+    $relative_filename =~ s@^.*?gsdl[/\\]@@;
+    $doc_obj->add_utf8_metadata ($cursection, "filename", $relative_filename);
+
+    # class information from .h and .cc and .C and .cpp files
+    if ($filetype eq "C++") 
+    {
+	process_c_plus_plus($textref,$pluginfo, $base_dir, 
+				   $file, $metadata, $doc_obj);
+    } elsif ($filetype eq "C")
+    {
+	get_includes_metadata($textref, $doc_obj);
+    }
+
+
+     # default operation...
+     # insert preformat tags and add text to document object
+    $doc_obj->add_utf8_text($cursection, "<pre>\n$$textref\n</pre>");
+    
+    return 1;
+}
+
+
+
+
+sub get_includes_metadata {
+    my ($textref, $doc_obj) = @_;
+    
+    my $topsection = $doc_obj->get_top_section();
+
+    # Get '#include' directives for metadata
+    if ($$textref !~ /\#\s*include\b/) {
+	return;
+    }
+
+    my @includes =
+	($$textref =~ m/^\s*\#\s*include\s*(?:\"|&lt;)(.*?)(?:\"|&gt;)/mg);
+    
+    my $incs_done_ref=$doc_obj->get_metadata($topsection, "includes");
+    my @incs_done;
+    if (defined($incs_done_ref)) {
+	@incs_done=@$incs_done_ref;
+    } else {
+	@incs_done=();
+    }
+
+    foreach my $inc (@includes) {
+	# add entries, but only if they don't already exist
+	if (!join('', map {$_ eq "$inc"?1:""} @incs_done)) {
+	    push @incs_done, $inc;
+	    $doc_obj->add_utf8_metadata($topsection, "includes", $inc);
+	}
+    }
+}
+
+
+
+sub process_c_plus_plus {
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+
+    my $topsection = $doc_obj->get_top_section();
+
+
+    # Check for include metadata
+    get_includes_metadata($textref, $doc_obj);
+
+
+
+    # Get class declarations (but not forward declarations...) as metadata
+    if ($$textref =~ /\bclass\b/ ) {
+	my $classnames=$$textref;
+	
+	# remove commented lines
+	$classnames =~ s@/\*.*?\*/@@sg;
+	$classnames =~ s@//.*$@@mg;
+	while ($classnames =~ /\bclass\b/) {
+
+	    # delete all lines up to the next "class"
+	    while ($classnames !~ /^[^\n]*\bclass\b[^\n]*\n/)
+	    {$classnames =~ s/.*\n//;}
+	    
+#	    $classnames =~ s/^([^c][^l])*(.)?$//mg; # delete unneccessary lines
+
+	    # get the line including the next "class" and remove it from
+	    # our tmp text.
+	    $classnames =~ s/^(.*\bclass\b.*)$//m;
+
+	    # don't index if merely a reference/fwd decl. of another class
+	    if ($1 !~ /(friend\Wclass)|(class\W\w+\W?\;)|(\/\/.*class)/) {
+		# $1 is still the whole line - eg:
+		# "class StaffSystem: public BaseStaffSystem"
+		my $wholeline=$1;
+		my $classname=$1;
+		$classname =~ s/.*class\W(\w+).*/$1/;
+		my $classes=$doc_obj->get_metadata($topsection, "class");
+		foreach my $elem (@$classes) {
+		    if ("$elem" eq "$classname") {goto class_done;}
+		}
+		$doc_obj->add_utf8_metadata($topsection, "class", $classname);
+	      class_done:
+		$doc_obj->add_utf8_metadata($topsection, "classdecl", $wholeline);
+	    }
+	}
+    } # end of "class"
+
+    return 1;
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/SplitPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/SplitPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/SplitPlug.pm	(revision 10506)
@@ -0,0 +1,284 @@
+###########################################################################
+#
+# SplitPlug.pm - a plugin for splitting input files into segments that
+#                will then be individually processed.
+#
+#
+# Copyright 2000 Gordon W. Paynter (gwp@cs.waikato.ac.nz)
+# 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.
+#
+###########################################################################
+
+
+# SplitPlug is a plugin for splitting input files into segments that will
+# then be individually processed.  
+
+# This plugin should not be called directly.  Instead, if you need to
+# process input files that contain several documents, you should write a
+# plugin with a process function that will handle one of those documents
+# and have it inherit from SplitPlug.  See ReferPlug for an example.
+
+
+package SplitPlug;
+
+use BasPlug;
+use gsprintf 'gsprintf';
+use util;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+# SplitPlug is a sub-class of BasPlug.
+sub BEGIN {
+    @SplitPlug::ISA = ('BasPlug');
+}
+
+
+my $arguments =
+    [ { 'name' => "split_exp",
+	'desc' => "{SplitPlug.split_exp}",
+	'type' => "regexp",
+	#'deft' => &get_default_split_exp(),
+	'deft' => "",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "SplitPlug",
+		'desc'     => "{SplitPlug.desc}",
+		'abstract' => "yes",
+		'inherits' => "yes",
+	        'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    $self->{'textcat_store'} = {};
+    $self->{'metapass_srcdoc'} = {}; # which segments have valid metadata_srcdoc
+    return bless $self, $class;
+}
+
+sub init {
+    my $self = shift (@_);
+    my ($verbosity, $outhandle, $failhandle) = @_;
+
+    $self->BasPlug::init($verbosity, $outhandle, $failhandle);
+
+    if ((!defined $self->{'process_exp'}) || ($self->{'process_exp'} eq "")) {
+
+	$self->{'process_exp'} = $self->get_default_process_exp ();
+	if ($self->{'process_exp'} eq "") {
+	    warn ref($self) . " Warning: Non-recursive plugin has no process_exp\n";
+	}
+    }
+
+
+    # set split_exp to default unless explicitly set
+    if (!$self->{'split_exp'}) {
+	$self->{'split_exp'} = $self->get_default_split_exp ();
+    }
+
+}
+
+# This plugin recurs over the segments it finds
+sub is_recursive {
+    return 1;
+}
+
+# By default, we split the input text at blank lines
+sub get_default_split_exp {
+    return q^\n\s*\n^;
+}
+
+sub metadata_read {
+    my $self = shift (@_);  
+    my ($pluginfo, $base_dir, $file, $metadata, $extrametakeys, $extrametadata, $processor, $maxdocs, $gli) = @_;
+
+    my $matched = $self->SUPER::metadata_read($pluginfo, $base_dir, $file, 
+					      $metadata, $extrametakeys, 
+					      $extrametadata, $processor, 
+					      $maxdocs, $gli);
+    my $split_matched = undef;
+
+    if ($matched) {
+
+	my $outhandle = $self->{'outhandle'};
+	my $filename = &util::filename_cat($base_dir, $file);
+
+	my $plugin_name = ref ($self);
+	$file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
+
+	$self->{'metapass_srcdoc'}->{$file} = {};
+
+	# Do encoding stuff
+	my ($language, $encoding) = $self->textcat_get_language_encoding ($filename);
+	my $le_rec = { 'language' => $language, 'encoding' => $encoding };
+	$self->{'textcat_store'}->{$file} = $le_rec;
+
+	# Read in file ($text will be in utf8)
+	my $text = "";
+	$self->read_file ($filename, $encoding, $language, \$text);
+
+	if ($text !~ /\w/) {
+	    gsprintf($outhandle, "$plugin_name: {BasPlug.file_has_no_text}\n",
+		     $file)
+		if $self->{'verbosity'};
+	    
+	    my $failhandle = $self->{'failhandle'};
+	    print $failhandle "$file: " . ref($self) . ": file contains no text\n";
+	    $self->{'num_not_processed'} ++;
+
+	    $self->{'textcat_store'}->{$file} = undef;
+
+	    return 0; 
+	}
+    
+    
+	# Split the text into several smaller segments
+	my $split_exp = $self->{'split_exp'};
+	my @segments = split(/$split_exp/, $text);
+	print $outhandle "SplitPlug found " . (scalar @segments) . " documents in $filename\n" 
+	    if $self->{'verbosity'};
+	
+	$self->{'split_segments'}->{$file} = \@segments;
+	$split_matched = scalar(@segments);
+    }
+    
+    return $split_matched;
+}
+
+
+
+# The read function opens a file and splits it into parts. 
+# Each part is sent to the process function
+#
+# Returns: Number of document objects created (or undef if it fails)
+
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+    my $verbosity = $self->{'verbosity'};
+
+    # Figure out the exact filename of this file (and maybe block it)
+    my $filename = &util::filename_cat($base_dir, $file);
+    my $block_exp = $self->{'block_exp'};
+    return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+    $file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
+
+    my $le_rec = $self->{'textcat_store'}->{$file};
+    if (!defined $le_rec) {
+	# means no text was found;
+	return 0; # not processed but no point in passing it on
+    }
+
+    my $language = $le_rec->{'language'};
+    my $encoding = $le_rec->{'encoding'};
+    $self->{'textcat_store'}->{$file} = undef;
+
+    my $segments = $self->{'split_segments'}->{$file};
+    $self->{'split_segments'}->{$file} = undef;
+
+    # Process each segment in turn
+    my ($count, $segment, $segtext, $status, $id);
+    $segment = 0;
+    $count = 0;
+    foreach $segtext (@$segments) {
+	$segment++;
+
+	if (defined $self->{'metapass_srcdoc'}->{$file}->{$segment}) {
+	    # metadata is attached to a srcdoc
+	    next;
+	}
+
+	# create a new document
+	my $doc_obj = new doc ($filename, "indexed_doc");
+	$doc_obj->set_OIDtype ($processor->{'OIDtype'});
+	$doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Language", $language);
+	$doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Encoding", $encoding);
+	my ($filemeta) = $file =~ /([^\\\/]+)$/;
+	$doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Source", &ghtml::dmsafe($filemeta));
+	$doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "SourceSegment", "$segment");
+	if ($self->{'cover_image'}) {
+	  $self->associate_cover_image($doc_obj, $filename);
+	}
+	$doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+	#$doc_obj->add_metadata($doc_obj->get_top_section(), "FileFormat", "Split");
+
+	# Calculate a "base" document ID.
+	if (!defined $id) {
+	    $doc_obj->set_OID();
+	    $id = $doc_obj->get_OID();
+	}
+    
+	# include any metadata passed in from previous plugins 
+	# note that this metadata is associated with the top level section
+	$self->extra_metadata ($doc_obj, $doc_obj->get_top_section(), $metadata);
+
+	# do plugin specific processing of doc_obj
+	print $outhandle "segment $segment - " if ($self->{'verbosity'});
+	$status = $self->process (\$segtext, $pluginfo, $base_dir, $file, $metadata, $doc_obj);
+	if (!defined $status) {
+	    print $outhandle "WARNING - no plugin could process segment $segment of $file\n" 
+		if ($verbosity >= 2);
+	    next;
+	}
+	# If the plugin returned 0, it threw away this part
+	if ($status == 0) {
+	    next;
+	}
+	$count += $status;
+
+	# do any automatic metadata extraction
+	$self->auto_extract_metadata ($doc_obj);
+
+	# add an OID
+	$self->set_OID($doc_obj, $id, $segment);
+
+	# process the document
+	$processor->process($doc_obj);
+
+	$self->{'num_processed'} ++;
+    }
+
+    delete $self->{'metapass_srcdoc'}->{$file};
+
+    # Return number of document objects produced
+    return $count; 
+}
+
+sub set_OID {
+    my $self = shift (@_);
+    my ($doc_obj, $id, $segment_number) = @_;
+    
+    $doc_obj->set_OID($id . "s" . $segment_number);
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/StructuredHTMLPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/StructuredHTMLPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/StructuredHTMLPlug.pm	(revision 10506)
@@ -0,0 +1,419 @@
+###########################################################################
+#
+# StructuredHTMLPlug.pm -- html plugin with extra facilities for teasing out 
+# hierarchical structure (such as h1, h2, h3, or user-defined tags) in an 
+# HTML document
+#
+# 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 plugin is to process an HTML file where sections are divided by 
+# user-defined headings tags. As it is difficult to predict what user's definition
+# this plugin allows to detect the user-defined titles up to three levels (level1, level2, level3...)
+# as well as allows to get rid of user-defined Table of Content (TOC)...
+# format:e.g. level1 (Abstract_title|ChapterTitle|Referencing Heading) level2(SectionHeading)...
+
+package StructuredHTMLPlug;
+
+use HTMLPlug;
+use ImagePlug;
+
+#use strict; # every perl program should have this!
+#no strict 'refs'; # make an exception so we can use variables as filehandles
+
+sub BEGIN {
+    @StructuredHTMLPlug::ISA = ('HTMLPlug');
+}
+
+my $arguments = [];
+
+my $options = { 'name'     => "StructuredHTMLPlug",
+		'desc'     => "{StructuredHTMLPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+    
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+    
+    my $self = (defined $hashArgOptLists)? new HTMLPlug($pluginlist,$inputargs,$hashArgOptLists): new HTMLPlug($pluginlist,$inputargs);
+    
+    return bless $self, $class;
+}
+
+sub read {
+    my $self = shift (@_);  
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $gli) = @_;
+
+    my $filename = $file;
+    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+
+    if ($filename =~ m/\.html?$/) {
+	my $poss_doc_filename = $filename;
+	$poss_doc_filename =~ s/\.html?$/.doc/;
+
+	if (-e $poss_doc_filename) {
+	    # this file has already been processed by Word plugin
+	    return 0;
+	}
+    }
+    return $self->SUPER::read(@_);
+}
+
+sub process {
+    my $self = shift (@_);
+    #my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    print $outhandle "StructuredHTMLPlug: processing $file\n"
+        if $self->{'verbosity'} > 1;
+    my @head_and_body = split(/<body/i,$$textref);
+    my $head = shift(@head_and_body);
+    my $body_text = join("<body", @head_and_body);
+    
+    if (defined $self->{'extracted_word_metadata_fields'} && $self->{'extracted_word_metadata_fields'}=~ /\S/) {
+	my @doc_properties = split(/<xml>/i,$head);
+	my $doc_heading = shift(@doc_properties);
+	my $rest_doc_properties = join(" ", @doc_properties);
+	my @extracted_metadata = split(/<\/xml>/i, $rest_doc_properties);
+	my $extracted_metadata = shift (@extracted_metadata);
+	$self->extract_metadata($extracted_metadata, $metadata, $doc_obj);
+    }
+    
+    # If delete_toc is enables, it means to get rid of toc and tof contents.
+    # get rid of TOC and TOF sections and their title
+    if ($self->{'delete_toc'} == 1){
+	#line-height:150%;mso-ansi-language:FR'>Contents<o:p></o:p></span></b></p>
+	# get rid of Table of Contents title and Table of Figures 
+	# these two lines don't work - how can we do this properlly??
+	#$body_text =~ s/<p[^>]*><b><span[^>]*>(Table of Content.|Content.)<o:p><\/o:p><\/span><\/b><\/p>//isg;
+	#$body_text =~ s/<p[^>]*><b><span[^>]*>(Table of Figure.|Figure.)<o:p><\/o:p><\/span><\/b><\/p>//isg;
+	if (defined $self->{'toc_header'}&& $self->{'toc_header'} =~ /\S/){
+	    $body_text =~ s/<p class=(($self->{'toc_header'})[^>]*)>(.+?)<\/p>//isg;
+	}
+	if (defined $self->{'tof_header'}&& $self->{'tof_header'}=~ /\S/) {
+	    $body_text =~ s/<p class=(($self->{'tof_header'})[^>]*)>(.+?)<\/p>//isg;
+	}
+    }
+
+    if (defined $self->{'title_header'} && $self->{'title_header'}=~ /\S/){
+	$self->{'title_header'} =~ s/^(\()(.*)(\))/$2/is;
+	$body_text =~ s/<p class=(($self->{'title_header'})[^>]*)>(.+?)<\/p>/<p class=$1><title>$3<\/title><\/p>/isg;
+    }
+
+    if (defined $self->{'level1_header'} && $self->{'level1_header'}=~ /\S/ ){
+     	$self->{'level1_header'} =~ s/^\((.*)\)/$1/i;
+	$body_text =~ s/<p class=(($self->{'level1_header'})[^>]*)>(.+?)<\/p>/<p class=$1><h1>$3<\/h1><\/p>/ig;
+    }
+    
+    if (defined $self->{'level2_header'} && $self->{'level2_header'}=~ /\S/){
+	$self->{'level2_header'} =~ s/^\((.*)\)/$1/i;
+	$body_text =~ s/<p class=(($self->{'level2_header'})[^>]*)>(.+?)<\/p>/<p class=$1><h2>$3<\/h2><\/p>/ig;
+    }
+    
+    if (defined $self->{'level3_header'} && $self->{'level3_header'}=~ /\S/ ){
+	$self->{'level3_header'} =~ s/^\((.*)\)/$1/is;
+	$body_text =~ s/<p class=(($self->{'level3_header'})[^>]*)>(.+?)<\/p>/<p class=$1><h3>$3<\/h3><\/p>/isg;
+    }
+    # Tidy up extra new lines
+    $body_text =~ s/(<p[^>]*><span[^>]*><o:p>&nbsp;<\/o:p><\/span><\/p>)//isg;
+    $body_text =~ s/(<p[^>]*><o:p>&nbsp;<\/o:p><\/p>)//isg;
+    
+    my $body = "<body".$body_text;
+    
+    my $section_text = $head;
+    $section_text .= "<!--\n<Section>\n-->\n";
+    
+    # split HTML text on <h1>, <h2> etc tags
+    my @h_split = split(/<h/i,$body);
+    
+    my $hnum = 0;
+
+    my $sectionh1 = 0;
+    $section_text .= shift(@h_split);
+    
+    my $hc;
+    foreach $hc ( @h_split )
+    {
+	if ($hc =~ m/^([1-3])\s*.*?>(.*)$/s)
+	{
+	    my $new_hnum = $1;
+	    my $hc_after = $2;
+	    
+	    if ($hc_after =~ m/^(.*?)<\/h$new_hnum>/is)
+	    {
+		my $h_text = $1;
+		$hc =~ s/^(\&nbsp\;)+/\&nbsp\;/g;
+		# boil HTML down to some interesting text
+		$h_text =~ s/^[1-3]>//;
+		$h_text =~ s/<\/?.*?>//sg;
+		$h_text =~ s/\s+/ /sg;
+		$h_text =~ s/^\s$//s;
+		$h_text =~ s/(&nbsp;)+\W*/&nbsp;/sg;
+		
+		if ($h_text =~ m/\w+/)
+		{
+		    if ($new_hnum > $hnum)
+		    {
+			# increase section nesting
+			$hnum++;
+			while ($hnum < $new_hnum)
+			{
+			    my $spacing = "  " x $hnum;
+			    $section_text .= "<!--\n";
+			    $section_text .= $spacing."<Section>\n";
+			    $section_text .= "-->\n";
+			    $hnum++;
+			}
+		    }
+		    else # ($new_hnum <= $hnum)
+		    {
+			# descrease section nesting
+			while ($hnum >= $new_hnum)
+			{
+			    my $spacing = "  " x $hnum;
+			    $section_text .= "<!--\n";
+			    $section_text .= $spacing."</Section>\n";
+			    $section_text .= "-->\n";
+			    $hnum--;
+			}
+			$hnum++;
+		    }
+
+		    my $spacing = "  " x $hnum;		    
+		    $section_text .= "<!--\n";
+		    $section_text .= $spacing."<Section>\n";
+		    $section_text .= $spacing."  <Description>\n";
+		    $section_text .= $spacing."    <Metadata name=\"Title\">$h_text</Metadata>";
+		    $section_text .= $spacing."  </Description>\n";
+		    $section_text .= "-->\n";
+		    
+		    print $outhandle $spacing."$h_text\n"
+			if $self->{'verbosity'} > 2;
+		    
+		    $sectionh1++ if ($hnum==1);
+		}
+	    }
+	    else {
+###		print STDERR "***** hc = <h$hc\n\n";
+		
+	    }
+	    $section_text .= "<h$hc";
+	}
+	else
+	{
+	    $section_text .= "<h$hc";
+	}
+    }
+
+    while ($hnum >= 1)
+    {
+	my $spacing = "  " x $hnum;
+	$section_text .= "<!--\n";
+	$section_text .= $spacing."</Section>\n";
+	$section_text .= "-->\n";
+	$hnum--;
+    }
+
+    $section_text .= "<!--\n</Section>\n-->\n";
+
+    $$textref = $section_text;
+    
+    # should be textref not testref???
+    #$$testref =~ s/<h(\d+)>(.*?)<\/h$1>/<Section><Metadata name=\"Title\">$1<\/Metadata></Section><h$1><\/h$1>/gi;
+    
+    if ($sectionh1>0)
+    {
+	print $outhandle "  Located section headings ..."
+	    if $self->{'verbosity'} > 1;
+    }
+    print $outhandle "  Passing on the HTMLPlug\n"
+	if $self->{'verbosity'} > 1;
+    
+    $$textref =~ s/<!\[if !vml\]>/<![if vml]>/g;
+    
+    $$textref =~ s/(&nbsp;)+/&nbsp;/sg;    
+    
+    ## $$textref =~ s/<o:p>&nbsp;<\/o:p>//g; # used with VML to space figures?
+    
+    $self->SUPER::process(@_);
+    
+    # associate original file with doc object
+    my $cursection = $doc_obj->get_top_section();
+    my $filename = &util::filename_cat($base_dir, $file);
+    if (-e $filename)
+    {
+	print $outhandle "  Adding associated Word document\n"
+	    if $self->{'verbosity'} > 1;
+	
+	$doc_obj->associate_file($filename, "doc.doc", undef, $cursection);
+	
+	my $doclink = "<a href=_httpcollection_/index/assoc/[archivedir]/doc.doc>";
+	$doc_obj->add_utf8_metadata ($cursection, "srclink",  $doclink);
+	$doc_obj->add_utf8_metadata ($cursection, "srcicon",  "_icondoc_");
+	$doc_obj->add_utf8_metadata ($cursection, "/srclink", "</a>");
+
+	my $file_size = -s $filename;
+	if ($file_size>1024)
+	{
+	    my $fs_kbytes = sprintf("%d",$file_size/1024);
+	    $doc_obj->add_utf8_metadata ($cursection, "filesize", "$fs_kbytes Kb");
+	}
+	else
+	{
+	    $doc_obj->add_utf8_metadata ($cursection, "filesize", "$file_size bytes");
+	}
+
+	if ($file_size > 200000)
+	{
+	    $doc_obj->add_utf8_metadata ($cursection, "fswarning", "1");
+	}
+    }
+}
+
+
+sub resize_if_necessary
+{
+    my ($self,$front,$back,$base_dir,$href) = @_;
+    
+    # dig out width and height of image, if there
+    my $img_attributes = "$front back";
+    my ($img_width)  = ($img_attributes =~ m/\s+width=\"?(\d+)\"?/i);
+    my ($img_height) = ($img_attributes =~ m/\s+height=\"?(\d+)\"?/i);
+    
+    # derive local filename for image based on its URL
+    my $img_filename = $href;
+    $img_filename =~ s/^[^:]*:\/\///;
+    $img_filename = &util::filename_cat($base_dir, $img_filename);
+    
+    # Replace %20's in URL with a space if required. Note that the filename
+    # may include the %20 in some situations
+    if ($img_filename =~ /\%20/) {
+	if (!-e $img_filename) {
+	    $img_filename =~ s/\%20/ /g;
+	}
+    }
+    if ((-e $img_filename) && (defined $img_width) && (defined $img_height)) {
+	# get image info on width and height
+	
+	my $outhandle = $self->{'outhandle'};
+	my $verbosity = $self->{'verbosity'};
+
+	my ($image_type, $actual_width, $actual_height, $image_size) 
+	    = &ImagePlug::identify($img_filename, $outhandle, $verbosity);
+	
+	#print STDERR "**** $actual_width x $actual_height";
+	#print STDERR " (requested: $img_width x $img_height)\n";
+
+	if (($img_width < $actual_width) || ($img_height < $actual_height)) {
+	    print $outhandle "Resizing $img_filename\n" if ($verbosity > 0);
+	    
+	    # derive new image name based on current image
+	    my ($tailname, $dirname, $suffix)
+		= &File::Basename::fileparse($input_filename, "\\.[^\\.]+\$");
+	    
+	    my $resized_filename 
+		= &util::filename_cat($dirname, $tailname."_resized".$suffix);
+	    
+	    #print STDERR "**** suffix = $suffix\n";
+	    
+	    # Generate smaller image with convert
+	    my $newsize = "$img_widthx$image_height";
+	    my $command = "convert -interlace plane -verbose "
+		."-geometry $newsize \"img_$filename\" \"$resized_filename\"";
+	    print $outhandle "ImageResize: $command\n" if ($verbosity > 2);
+	    my $result = '';
+	    print $outhandle "ImageResize result: $result\n" if ($verbosity > 2);
+	}
+    }
+    return $href;
+}
+
+sub replace_images {
+    my $self = shift (@_);
+    my ($front, $link, $back, $base_dir, 
+	$file, $doc_obj, $section) = @_;
+    # remove quotes from link at start and end if necessary
+    if ($link=~/^\"/) {
+	$link=~s/^\"//;$link=~s/\"$//;
+	$front.='"';
+	$back="\"$back";
+    }
+    
+    $link =~ s/\n/ /g;
+    
+    my ($href, $hash_part, $rl) = $self->format_link ($link, $base_dir, $file);
+    
+##    $href = $self->resize_if_necessary($front,$back,$base_dir,$href);
+    
+    my $middle = $self->add_file ($href, $rl, $hash_part, $base_dir, $doc_obj, $section);
+    
+    return $front . $middle . $back;
+}
+
+sub extract_metadata 
+{
+    my $self = shift (@_);
+    my ($textref, $metadata, $doc_obj) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    # metadata fields to extract/save. 'key' is the (lowercase) name of the
+    # html meta, 'value' is the metadata name for greenstone to use
+    my %find_fields = ();
+    my ($tag,$value);
+
+    my $orig_field = "";
+    foreach my $field (split /,/, $self->{'extracted_word_metadata_fields'}) {
+	# support tag<tagname>
+	if ($field =~ /^(.*?)<(.*?)>$/) {
+	    # "$2" is the user's preferred gs metadata name
+	    $find_fields{lc($1)}=$2; # lc = lowercase
+	    $orig_field = $1;
+	} else { # no <tagname> for mapping
+	    # "$field" is the user's preferred gs metadata name
+	    $find_fields{lc($field)}=$field; # lc = lowercase
+	    $orig_field = $field;
+	}
+	if ($textref =~ m/<o:$orig_field>(.*)<\/o:$orig_field>/i){
+	    $tag = $orig_field;
+	    $value = $1;
+	    if (!defined $value || !defined $tag){
+		print $outhandle "StructuredHTMLPlug: can't find VALUE in \"$tag\"\n";
+		next;
+	    } else {
+		# clean up and add
+		chomp($value); # remove trailing \n, if any
+		$tag = $find_fields{lc($tag)};
+		print $outhandle " extracted \"$tag\" metadata \"$value\"\n" 
+		    if ($self->{'verbosity'} > 2);
+		$doc_obj->add_utf8_metadata($doc_obj->get_top_section(), $tag, $value);
+	    }
+	}
+    }
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/TEXTPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/TEXTPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/TEXTPlug.pm	(revision 10506)
@@ -0,0 +1,137 @@
+###########################################################################
+#
+# TEXTPlug.pm -- simple text plugin
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# creates simple single-level document. Adds Title metadata 
+# of first line of text (up to 100 characters long).
+
+# 12/05/02 Added usage datastructure - John Thompson
+
+package TEXTPlug;
+
+use BasPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @TEXTPlug::ISA = ('BasPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" } ,
+      { 'name' => "title_sub",
+	'desc' => "{TEXTPlug.title_sub}",
+	'type' => "regexp",
+	'deft' => "",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "TEXTPlug",
+		'desc'     => "{TEXTPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.te?xt$^;
+}
+
+# do plugin specific processing of doc_obj
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    print STDERR "<Processing n='$file' p='TEXTPlug'>\n" if ($gli);
+    print $outhandle "TEXTPlug: processing $file\n" 
+	if $self->{'verbosity'} > 1;
+    
+    my $cursection = $doc_obj->get_top_section();
+    # get title metadata
+    # (don't need to get title if it has been passed
+    # in from another plugin)
+    if (!defined $metadata->{'Title'}) {
+	my ($title) = $$textref;
+	$title =~ /^\s+/s;
+	if (defined $self->{'title_sub'} &&
+           $self->{'title_sub'}) {$title =~ s/$self->{'title_sub'}//;}
+	$title =~ /^\s*([^\n]*)/s; $title=$1;
+	if (length($title) > 100) {
+	    $title = substr ($title, 0, 100) . "...";
+	}
+        $title =~ s/\[/&#91;/g;
+        $title =~ s/\[/&#93;/g;
+        $title =~ s/\</&#60;/g;
+        $title =~ s/\>/&#62;/g;
+	$doc_obj->add_utf8_metadata ($cursection, "Title", $title);
+    }
+    # Add FileFormat metadata
+    $doc_obj->add_metadata($cursection, "FileFormat", "TEXT");
+    
+
+    # we need to escape the escape character, or else mg will convert into
+    # eg literal newlines, instead of leaving the text as '\n'
+    $$textref =~ s/\\/\\\\/g; # macro language
+    $$textref =~ s/_/\\_/g; # macro language
+    $$textref =~ s/</&lt;/g;
+    $$textref =~ s/>/&gt;/g;
+
+    # insert preformat tags and add text to document object
+    $doc_obj->add_utf8_text($cursection, "<pre>\n$$textref\n</pre>");
+
+    return 1;
+}
+
+1;
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/UnknownPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/UnknownPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/UnknownPlug.pm	(revision 10506)
@@ -0,0 +1,256 @@
+###########################################################################
+#
+# UnknownPlug.pm -- Plugin for files you know about but Greenstone doesn't
+#
+# A component of the Greenstone digital library software from the New
+# Zealand Digital Library Project at the University of Waikato, New
+# Zealand.
+#
+# Copyright (C) 2001 Gordon W. Paynter
+# Copyright (C) 2001 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.
+#
+###########################################################################
+
+# UnknownPlug - a plugin for unknown files
+
+# This is a simple Plugin for importing files in formats that
+# Greenstone doesn't know anything about.  A fictional document will
+# be created for every such file, and the file itself will be passed
+# to Greenstone as the "associated file" of the document.
+
+# Here's an example where it is useful: I have a collection of
+# pictures that include a couple of quicktime movie files with names
+# like DCP_0163.MOV.  Rather than write a new plugin for quicktime
+# movies, I add this line to the collection configuration file:
+
+# plugin UnknownPlug -process_exp "*.MOV" -assoc_field "movie"
+
+# A document is created for each movie, with the associated movie
+# file's name in the "movie" metadata field.  In the collection's
+# format strings, I use the {If} macro to output different text for
+# each type of file, like this:
+
+# {If}{[movie],<HTML for displaying movie>}{If}{[Image],<HTML for displaying image>}
+
+# You can also add extra metadata, such as the Title, Subject, and
+# Duration, with metadata.xml files and RecPlug.  (If you want to use
+# UnknownPlug with more than one type of file, you will have to add
+# some sort of distinguishing metadata in this way.)
+
+
+
+package UnknownPlug;
+
+use BasPlug;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @UnknownPlug::ISA = ('BasPlug');
+}
+
+my $arguments =
+    [ { 'name' => "assoc_field",
+	'desc' => "{UnknownPlug.assoc_field}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "file_format",
+	'desc' => "{UnknownPlug.file_format}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "mime_type",
+	'desc' => "{UnknownPlug.mime_type}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "process_extension",
+	'desc' => "{UnknownPlug.process_extension}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "UnknownPlug",
+		'desc'     => "{UnknownPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    # "-process_extension" is a simpler alternative to -process_exp for non-regexp people
+    if (!$self->{'process_exp'} && $self->{'process_extension'}) {
+	$self->{'process_exp'} = "\\." . $self->{'process_extension'} . "\$";
+    }
+
+    return bless $self, $class;
+}
+
+sub get_default_process_exp {
+    return '';
+}
+
+
+# Associate the unknown file with the new document
+
+sub associate_unknown_file {
+    my $self = shift (@_);
+    my $filename = shift (@_);   # filename with full path
+    my $file = shift (@_);       # filename without path
+    my $doc_obj = shift (@_);
+    
+    my $verbosity = $self->{'verbosity'};
+    my $outhandle = $self->{'outhandle'};
+
+    # check the filename is okay
+    return 0 if ($file eq "" || $filename eq "");
+
+    # Add the image metadata
+    my $url = $file;
+    $url =~ s/ /%20/g;
+
+    # Add the file as an associated file ...
+    my $section = $doc_obj->get_top_section();
+    my $file_format = $self->{'file_format'} || "unknown";
+    my $mime_type = $self->{'mime_type'} || "unknown/unknown";
+    my $assoc_field = $self->{'assoc_field'} || "unknown_file";
+
+    $doc_obj->associate_file($filename, $file, $mime_type, $section);
+    $doc_obj->add_metadata ($section, "FileFormat", $file_format);
+    $doc_obj->add_metadata ($section, $assoc_field, $file);
+    
+    $doc_obj->add_metadata ($section, "srclink", 
+			    "<a href=\"_httpcollection_/index/assoc/[assocfilepath]/[$assoc_field]\">");
+    $doc_obj->add_metadata ($section, "srcicon", "_iconunknown_");
+    $doc_obj->add_metadata ($section, "/srclink", "</a>");
+    
+    return 1;
+}
+
+
+
+# The UnknownPlug read() function. This function does all the right
+# things to make general options work for a given plugin.  UnknownPlug
+# overrides read() because there is no need to read the actual text of
+# the file in, because the contents of the file is not text...
+#
+#
+# Return number of files processed, undef if can't process 
+#
+# Note that $base_dir might be "" and that $file might include directories
+
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my $outhandle = $self->{'outhandle'};
+
+    # Make sure we're processing the correct file
+    my $filename = &util::filename_cat($base_dir, $file);
+    return 0 if $self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/;
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+    print STDERR "<Processing n='$file' p='UnknownPlug'>\n" if ($gli);
+    print $outhandle "UnknownPlug processing \"$filename\"\n"
+	    if $self->{'verbosity'} > 1;
+
+    #if there's a leading directory name, eat it...
+    $file =~ s/^.*[\/\\]//;
+    
+    # create a new document
+    my $doc_obj = new doc ($filename, "indexed_doc");
+    $doc_obj->set_OIDtype ($processor->{'OIDtype'});    
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+    $doc_obj->add_metadata($doc_obj->get_top_section(), "Source", &ghtml::dmsafe($file)); # set the filename as Source metadata to be consistent with other plugins
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "FileSize", (-s $filename));
+
+    # associate the file with the document
+    if (associate_unknown_file($self, $filename, $file, $doc_obj) != 1)
+    {
+	if ($gli) {
+	    print STDERR "<ProcessingError n='$file'>\n";
+	}
+	print $outhandle "UnknownPlug: couldn't process \"$filename\"\n";
+	return -1; # error during processing
+    }
+
+    #create an empty text string so we don't break downstream plugins 
+    my $text = &gsprintf::lookup_string("{BasPlug.dummy_text}");
+
+    # include any metadata passed in from previous plugins 
+    my $section = $doc_obj->get_top_section();
+    $self->extra_metadata ($doc_obj, $section, $metadata);
+
+    $self->title_fallback($doc_obj,$section,$file);
+
+    # do plugin specific processing of doc_obj
+    unless (defined ($self->process(\$text, $pluginfo, $base_dir, $file, $metadata, $doc_obj))) {
+	print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	return -1;
+    }
+
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata ($doc_obj);
+
+    # add an OID
+    $doc_obj->set_OID();
+    $doc_obj->add_text($section, $text);
+
+    # process the document
+    $processor->process($doc_obj);
+
+    $self->{'num_processed'} ++;
+    return 1;
+}
+
+
+# UnknownPlug processing of doc_obj.  In practice we don't need to do
+# anything here because the read function takes care of everything.
+
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    my $outhandle = $self->{'outhandle'};
+    
+    return 1;
+}
+
+
+1;
+
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/W3ImgPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/W3ImgPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/W3ImgPlug.pm	(revision 10506)
@@ -0,0 +1,1068 @@
+###########################################################################
+#
+# W3ImgPlug.pm -- Context-based image indexing plugin for HTML documents
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001 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.
+#
+###########################################################################
+
+# DESCRIPTION:
+#
+#  Extracts images and associated text and metadata from
+#  web pages as individual documents for indexing. Thumbnails
+#  are created from each image for browsing purposes.
+#
+#  Options are available for configuring the aggressiveness of the
+#  associated text extraction mechanisms. A higher level of
+#  aggressiveness will extract more text and consequently
+#  may mean lower accuracy (precision); however, it may also 
+#  retrieve more of the relevant images from the collection (recall). 
+#  Lower levels of aggressiveness maybe result in slightly faster
+#  collection builds at the import stage.
+#
+#  W3ImgPlug is a subclass of HTMLPlug (i.e. it will index pages also 
+#  if required). It can be used in place of HTMLPlug to index both
+#  pages and their images.
+#
+# REQUIREMENTS:
+#   
+#  The ImageMagick image manipulation is used to create
+#  thumbnails and extract some image metadata. (Available 
+#  from http://www.imagemagick.org/)
+#
+#  Unix:
+#    Many Linux distributions contain ImageMagick.
+#
+#  Windows:
+#    ImageMagick can be downloaded from the website above.
+#    Make sure the system path includes the ImageMagick binaries
+#    before using W3ImgPlug.
+#
+#    NOTE: NT/2000/XP contain a filesystem utility 'convert.exe' 
+#    with the same name as the image conversion utility. The
+#    ImageMagick FAQ recommends renaming the filesystem
+#    utility (e.g. to 'fsconvert.exe') to avoid this clash.
+#
+# USAGE:  
+#
+#  An image document consists of metadata elements:
+#
+#   OriginalFilename, FilePath, Filename, FileExt, FileSize,
+#   Width, Height, URL, PageURL, ThumbURL, CacheURL, CachePageURL
+#   ImageText, PageTitle
+#
+#  Most of these are only useful in format strings (e.g. ThumbURL, 
+#  Filename, URL, PageURL, CachePageURL). 
+#
+#  ImageText, as the name suggests contains the indexable text.
+#  (unless using the -document_text plugin option)
+#
+#  Since image documents are made up of metadata elements 
+#  alone, format strings are needed to display them properly. 
+#  NOTE: The receptionist will only display results (e.g. thumbnails)
+#  in 4 columns if the format string begins with "<td><table>".
+#
+#  The example below takes the user to the image within the
+#  source HTML document rather than using a format string
+#  on DocumentText to display the image document itself.
+#
+#  Example collect.cfg:
+#
+#   ...
+#
+#   indexes document:ImageText document:text
+#   defaultindex document:ImageText
+#  
+#   collectionmeta .document:ImageText "images"
+#   collectionmeta .document:text "documents"
+#
+#   ...
+#
+#   plugin W3ImgPlug -index_pages -aggressiveness 6
+#
+#   ...
+#  
+#   format SearchVList '<td>{If}{[Title],[link][icon]&nbsp;[Title][[/link],
+#    <table><tr><td align="center"><a href="[CachePageURL]">
+#    <img src="[ThumbURL]"></a></td></tr><tr><td align="center">
+#    <a href="[CachePageURL]"><font size="-1">[OriginalFilename]</font></a>
+#    <br>[Width]x[Height]</td></tr></table>}</td>'
+#
+#   ...
+#
+ 
+package W3ImgPlug;
+
+use HTMLPlug;
+use ghtml;
+use unicode;
+use util;
+use strict; # 'subs';
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @W3ImgPlug::ISA = qw( HTMLPlug );
+}
+
+my $aggressiveness_list = 
+    [ { 'name' => "1",
+	'desc' => "{W3ImgPlug.aggressiveness.1}" },
+      { 'name' => "2",
+	'desc' => "{W3ImgPlug.aggressiveness.2}" },
+      { 'name' => "3",
+	'desc' => "{W3ImgPlug.aggressiveness.3}" },
+      { 'name' => "4",
+	'desc' => "{W3ImgPlug.aggressiveness.4}" },
+      { 'name' => "5",
+	'desc' => "{W3ImgPlug.aggressiveness.5}" },
+      { 'name' => "6",
+	'desc' => "{W3ImgPlug.aggressiveness.6}" },
+      { 'name' => "7",
+	'desc' => "{W3ImgPlug.aggressiveness.7}" },
+      { 'name' => "8",
+	'desc' => "{W3ImgPlug.aggressiveness.8}" },
+      { 'name' => "9",
+	'desc' => "{W3ImgPlug.aggressiveness.9}" } ];
+
+my $arguments =
+    [ { 'name' => "aggressiveness",
+	'desc' => "{W3ImgPlug.aggressiveness}",
+	'type' => "int",
+	'list' => $aggressiveness_list,
+	'deft' => "3",
+	'reqd' => "no" },
+      { 'name' => "index_pages",
+	'desc' => "{W3ImgPlug.index_pages}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "no_cache_images",
+	'desc' => "{W3ImgPlug.no_cache_images}",
+	'type' => "flag",
+	'reqd' => "no" },
+      { 'name' => "min_size",
+	'desc' => "{W3ImgPlug.min_size}",
+	'type' => "int",
+	'deft' => "2000",
+	'reqd' => "no" },
+      { 'name' => "min_width",
+	'desc' => "{W3ImgPlug.min_width}",
+	'type' => "int",
+	'deft' => "50",
+	'reqd' => "no" },
+      { 'name' => "min_height",
+	'desc' => "{W3ImgPlug.min_height}",
+	'type' => "int",
+	'deft' => "50",
+	'reqd' => "no" },
+      { 'name' => "thumb_size",
+	'desc' => "{W3ImgPlug.thumb_size}",
+	'type' => "int",
+	'deft' => "100",
+	'reqd' => "no" },
+      { 'name' => "convert_params",
+	'desc' => "{W3ImgPlug.convert_params}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+      { 'name' => "min_near_text",
+	'desc' => "{W3ImgPlug.min_near_text}",
+	'type' => "int",
+	'deft' => "10",
+	'reqd' => "no" },
+      { 'name' => "max_near_text",
+	'desc' => "{W3ImgPlug.max_near_text}",
+	'type' => "int",
+	'deft' => "400",
+	'reqd' => "no" },
+      { 'name' => "smallpage_threshold",
+	'desc' => "{W3ImgPlug.smallpage_threshold}",
+	'type' => "int",
+	'deft' => "2048",
+	'reqd' => "no" },
+      { 'name' => "textrefs_threshold",
+	'desc' => "{W3ImgPlug.textrefs_threshold}",
+	'type' => "int",
+	'deft' => "2",
+	'reqd' => "no" },
+      { 'name' => "caption_length",
+	'desc' => "{W3ImgPlug.caption_length}",
+	'type' => "int",
+	'deft' => "80",
+	'reqd' => "no" },
+      { 'name' => "neartext_length",
+	'desc' => "{W3ImgPlug.neartext_length}",
+	'type' => "int",
+	'deft' => "300",
+	'reqd' => "no" },
+      { 'name' => "document_text",
+	'desc' => "{W3ImgPlug.document_text}",
+	'type' => "flag",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "W3ImgPlug",
+		'desc'     => "{W3ImgPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new HTMLPlug($pluginlist,$inputargs,$hashArgOptLists): new HTMLPlug($pluginlist,$inputargs);
+
+    # init class variables
+    $self->{'textref'} = undef; # init by read_file fn
+    $self->{'htdoc_obj'} = undef; # init by process fn
+    $self->{'htpath'} = undef; # init by process fn
+    $self->{'hturl'} = undef; # init by process fn
+    $self->{'plaintext'} = undef; # HTML stripped version - only init if needed by raw_neartext sub
+    $self->{'smallpage'} = 0; # set by process fn
+    $self->{'images_indexed'} = undef; # num of images indexed - if 1 or 2 then we know page is small
+    $self->{'initialised'} = undef; # flag (see set_extraction_options())
+
+    return bless $self, $class;
+}
+
+# if indexing pages, let HTMLPlug do it's stuff
+# image extraction done through read()
+sub process {
+    my ($self, $textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
+    $self->{'imglist'} = ();
+    if ( $self->{'index_pages'} ) {
+	my $ok = $self->SUPER::process($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj);
+	if ( ! $ok ) { return $ok }
+	$self->{'htdoc_obj'} = $doc_obj;
+    }
+    # else use URL for referencing
+    #if ( $file =~ /(.*)[\/\\]/ ) { $self->{'htpath'} = $1; } else { $self->{'htpath'} = $file; }
+
+    $self->{'htpath'} = $base_dir if (-d $base_dir);
+    if ( $file =~ /(.*)[\/\\]/ ) { $self->{'htpath'} .= "/$1"; }
+    $self->{'htpath'} =~ s/\\/\//g;  # replace \ with /
+
+    $self->{'hturl'} = "http://$file";
+    $self->{'hturl'} =~ s/\\/\//g; # for windows
+    ($self->{'filename'}) = $file =~ /.*[\/\\](.*)/;
+    ($self->{'base_path'}) = $file =~ /(.*)[\/\\]/i;
+    if ( ( -s "$base_dir/$file") <= $self->{'smallpage_threshold'} ) {
+	$self->{'smallpage'} = 1;
+    } else { $self->{'smallpage'} = 0; }
+
+    if ( defined($self->{'initialised'}) ) { return 1; }
+    else {
+	$self->{'initialised'} = $self->set_extraction_options($base_dir =~ /^(.*?)\/import/i);
+	return $self->{'initialised'};
+    }
+}
+
+# get complex configuration options from configuration files
+# -- $GSDLCOLLECTION/etc/W3ImgPlug.cfg (tag sets for aggr 2+)
+# -- $GSDLHOME/etc/packages/phind/stopword/en/brown.sw (stopwords for aggr 5+)
+
+# If there's no W3ImgPlug.cfg file we'll use the following default values
+my $defaultcfg = '
+<delimitertagset>
+  <setname>Caption</setname>
+  <taggroup>font</taggroup>
+  <taggroup>tt</taggroup>
+  <taggroup>small</taggroup>
+  <taggroup>b</taggroup>
+  <taggroup>i</taggroup>
+  <taggroup>u</taggroup>
+  <taggroup>em</taggroup>
+  <taggroup>td</taggroup>
+  <taggroup>li</taggroup>
+  <taggroup>a</taggroup>
+  <taggroup>p</taggroup>
+  <taggroup>tr</taggroup>
+  <taggroup>center</taggroup>
+  <taggroup>div</taggroup>
+  <taggroup>caption</taggroup>
+  <taggroup>br</taggroup>
+  <taggroup>ul</taggroup>
+  <taggroup>ol</taggroup>
+  <taggroup>table</taggroup>
+  <taggroup>hr</taggroup>
+</delimitertagset>
+
+<delimitertagset>
+  <setname>Neartext</setname>
+  <taggroup>tr|hr|table|h\d|img|body</taggroup>
+  <taggroup>td|tr|hr|table|h\d|img|body</taggroup>
+  <taggroup>p|br|td|tr|hr|table|h\d|img|body</taggroup>
+  <taggroup>font|p|i|b|em|img</taggroup>
+</delimitertagset>
+';
+
+sub set_extraction_options() {
+    my ($self, $collpath) = @_;
+    my ($filepath);
+
+    print {$self->{'outhandle'}} "W3ImgPlug: Initialising\n"
+	if $self->{'verbosity'} > 1;
+    # etc/W3ImgPlug.cfg (XML)
+    # tag sets for captions and neartext
+    if ( $self->{'aggressiveness'} > 1 && $self->{'aggressiveness'} != 9 ) {
+	$self->{'delims'} = [];
+	$self->{'cdelims'} = [];
+	my ($cfg, @tagsets, $tagset, $type, @delims);
+
+	$filepath = "$collpath/etc/W3ImgPlug.cfg";
+	if ( open CFG, "<$filepath" ) {
+	    while (<CFG>) { $cfg .= $_ }
+	    close CFG;
+	} else {
+	    $cfg = $defaultcfg;
+	}
+
+	(@tagsets) = 
+	    $cfg =~ /<delimitertagset>(.*?)<\/delimitertagset>/igs;
+	foreach $tagset ( @tagsets ) {
+	    ($type) = $tagset =~ /<setname>(.*?)<\/setname>/i;
+	    if ( lc($type) eq "caption" ) {
+		(@{$self->{'cdelims'}}) = $tagset =~ /<taggroup>(.*?)<\/taggroup>/igs;
+	    }
+	    elsif ( lc($type) eq "neartext" ) {
+		(@{$self->{'delims'}}) = $tagset =~ /<taggroup>(.*?)<\/taggroup>/igs;
+	    }
+	}
+
+	# output a warning if there seem to be no delimiters
+	if ( scalar(@{$self->{'cdelims'}} == 0)) {
+	    print {$self->{'outhandle'}} "W3ImgPlug: Warning: no caption delimiters found in $filepath\n";
+	}
+	if ( scalar(@{$self->{'delims'}} == 0)) {
+	    print {$self->{'outhandle'}} "W3ImgPlug: Warning: no neartext delimiters found in $filepath\n";
+	}
+    }
+    
+    # get stop words for textual reference extraction
+    # TODO: warnings scroll off. Would be best to output them again at end of import
+    if ( $self->{'aggressiveness'} >=5 && $self->{'aggressiveness'} != 9 ) {
+	$self->{'stopwords'} = ();
+	$filepath = &util::filename_cat($ENV{'GSDLHOME'}, "etc", "packages", "phind", "stopword", "en", "brown.sw");
+	if ( open STOPWORDS, "<$filepath" ) {
+	    while ( <STOPWORDS> ) {
+		chomp;
+		$self->{'stopwords'}{$_} = 1;
+	    }
+	    close STOPWORDS;
+	} else {
+	    print {$self->{'outhandle'}} "W3ImgPlug: Warning: couldn't open stopwords file at $filepath ($!)\n";
+	}
+	
+    }
+
+    if ( $self->{'neartext_length'} > $self->{'max_near_text'} ) {
+	$self->{'max_near_text'} = $self->{'neartext_length'} * 1.33;
+	print {$self->{'outhandle'}} "W3ImgPlug: Warning: adjusted max_text to $self->{'max_near_text'}\n";
+    } 
+    if ( $self->{'caption_length'} > $self->{'max_near_text'} ) {
+	$self->{'max_near_text'} = $self->{'caption_length'} * 1.33;
+	print {$self->{'outhandle'}} "W3ImgPlug: Warning: adjusted max_text to $self->{'max_near_text'}\n";
+    }
+
+    return 1;
+}
+
+# return number of files processed, undef if can't recognise, -1 if 
+# cant process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my ($self, $pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = (@_);
+    my ($doc_obj, $section, $filepath, $imgtag, $pos, $context, $numdocs, $tndir, $imgs);
+    # forward normal read (runs HTMLPlug if index_pages T)
+    my $ok =  $self->SUPER::read($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli); 
+    if ( ! $ok ) { return $ok } # what is this returning??
+
+    my $outhandle = $self->{'outhandle'};
+    my $textref = $self->{'textref'};
+    my $htdoc_obj = $self->{'htdoc_obj'};
+    $numdocs = 0;
+    $base_dir =~ /(.*)\/.*/;
+    $tndir = "$1/archives/thumbnails"; # TODO: this path shouldn't be hardcoded?
+    &util::mk_all_dir($tndir) unless -e "$tndir"; 
+
+    $imgs = \%{$self->{'imglist'}};
+    my $nimgs = $self->get_img_list($textref);
+    $self->{'images_indexed'} = $nimgs;
+    if ( $nimgs > 0 ) {
+	my @fplist = (sort { $imgs->{$a}{'pos'} <=> $imgs->{$b}{'pos'} } keys %{$imgs});
+	my $i = 0;
+	foreach $filepath ( @fplist ) {
+	    $pos = $imgs->{$filepath}{'pos'}; 
+	    $context = substr ($$textref, $pos - 50, $pos + 50); # grab context (quicker)
+	    ($imgtag) = ($context =~ /(<(?:img|a|body)\s[^>]*$filepath[^>]*>)/is );
+	    if (! defined($imgtag)) { $imgtag = $filepath }
+	    print $outhandle "W3ImgPlug: extracting $filepath\n"
+		if ( $self->{'verbosity'} > 1 );
+	    $doc_obj = new doc ("", "indexed_doc");
+	    $section = $doc_obj->get_top_section();
+	    my $prevpos = ( $i == 0 ? 0 : $imgs->{$fplist[$i - 1]}{'pos'});
+	    my $nextpos = ( $i >= ($nimgs -1) ? -1 : $imgs->{$fplist[$i + 1]}{'pos'} );
+
+	    $self->extract_image_info($imgtag, $filepath, $textref, $doc_obj, $section, $tndir, $prevpos, $nextpos);
+            $processor->process($doc_obj);
+	    $numdocs++;
+	    $i++;
+	}
+	return $numdocs;
+    } else {
+	print $outhandle "W3ImgPlug: No images from $file indexed\n"
+	    if ( $self->{'verbosity'} > 2 );
+	return 1;
+    }
+    
+}
+
+# for every valid image tag
+# 1. extract related text and image metadata
+# 2. add this as document meta-data
+# 3. add assoc image(s) as files
+#
+sub extract_image_info {
+    my $self = shift (@_);
+    my ($tag, $id, $textref, $doc_obj, $section, $tndir, $prevpos, $nextpos) = (@_);
+    my ($filename, $orig_fp, $fn, $ext, $reltext, $relreltext, $crcid, $imgs,
+	$thumbfp, $pagetitle, $alttext,	$filepath, $aggr);
+    $aggr = $self->{'aggressiveness'};
+    $imgs = \%{$self->{'imglist'}};
+    $filepath = $imgs->{$id}{'relpath'}; 
+    ($filename) = $filepath =~ /([^\/\\]+)$/s;
+    ($orig_fp) = "$self->{'base_path'}/$filepath"; 
+    $orig_fp =~ tr/+/ /;
+    $orig_fp =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # translate %2E to space, etc
+    $orig_fp =~ s/\\/\//g;
+    $filepath = "$self->{'htpath'}/$filepath";
+    my ($onlyfn) = $filename =~ /([^\\\/]*)$/;
+    ($fn, $ext) = $onlyfn =~ /(.*)\.(.*)/;
+    $fn = lc $fn; $ext = lc $ext;
+    ($reltext) = "<tr><td>GifComment</td><td>" . `identify $filepath -ping -format "%c"` . "</td></tr>\n"
+        if ($ext eq "gif");
+    $reltext .= "<tr><td>FilePath</td><td>$orig_fp</td></tr>\n";
+
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$crcid = "$fn.$ext." . $self->{'next_crcid'}++;
+    } else { ($crcid) = `cksum $filepath` =~ /^(\d+)/; }
+    $thumbfp = "$tndir/tn_$crcid.jpg";
+    `convert -flatten -filter Hanning $self->{'convert_params'} -geometry "$self->{'thumb_size'}x$self->{'thumb_size'}>" $filepath $thumbfp` unless -e $thumbfp;
+    if ( ! (-e $thumbfp) ) {
+	print STDERR "W3ImgPlug: 'convert' failed. Check ImageMagicK binaries are installed and working correctly\n"; return 0; 
+    }
+    
+    # shove in full text (tag stripped or unstripped) if settings require it
+    if ( $aggr == 10) {
+	$reltext = "<tr><td>AllPage</td><td>" . $$textref . "</td><tr>\n";   # level 10 (all text, verbatim)
+    } else {
+	$pagetitle = $self->get_meta_value("title", $textref);
+	($alttext) = $tag =~ /\salt\s*=\s*(?:\"|\')(.+?)(?:\"|\')/is;
+	if ( defined($alttext) && length($alttext) > 1) {
+	    $reltext .= "<tr><td>ALTtext</td><td>$alttext</td></tr>\n"; }
+	$reltext .= "<tr><td>SplitCapitalisation</td><td>" . 
+	    $self->split_filepath($orig_fp) . "</td></tr>\n";
+
+	# get caption/tag based near text (if appropriate)
+	if ( $aggr > 1 ) {
+	    if ( $aggr >= 2 ) {
+		$reltext .= 
+		    $self->extract_caption_text($tag, $textref, $prevpos, $imgs->{$id}{'pos'}, $nextpos);
+		$relreltext = $reltext;
+	    } 
+	    # repeat the filepath, alt-text, caption, etc
+	    if ( $aggr == 8 ) {
+		$reltext .= $relreltext; 
+	    }
+	    if ( $aggr >= 3 ) {
+		$reltext .= 
+		    $self->extract_near_text($tag, $textref, $prevpos, $imgs->{$id}{'pos'}, $nextpos);
+	    }
+	
+	    # get page metadata (if appropriate)
+	    if ( $aggr >= 6 || ( $aggr >= 2 && 
+						     ( $self->{'images_indexed'} < 2 || 
+						       ($self->{'smallpage'} == 1 && $self->{'images_indexed'} < 6 )))) {	
+		$reltext .= $self->get_page_metadata($textref);
+	    }
+	    # textual references
+	    if ( $aggr  == 5 || $aggr >= 7) {
+		if ( length($relreltext) > ($self->{'caption_length'} * 2) )  {
+		    $reltext .= $self->get_textrefs($relreltext, $textref, $prevpos, $imgs->{$id}{'pos'}, $nextpos); }
+		else {
+		    $reltext .= $self->get_textrefs($reltext, $textref, $prevpos, $imgs->{$id}{'pos'}, $nextpos); 
+		}
+	    }
+	} # aggr > 1
+    } # aggr != 10
+    
+    $doc_obj->set_OID($crcid); 
+    $doc_obj->associate_file($thumbfp, "$fn.thumb.jpg", undef, $section);
+    $doc_obj->add_metadata($section, "OriginalFilename", $filename);
+    $doc_obj->add_metadata($section, "FilePath", $orig_fp);
+    $doc_obj->add_metadata($section, "Filename", $fn);
+    $doc_obj->add_metadata($section, "FileExt", $ext);
+    $doc_obj->add_metadata($section, "FileSize", $imgs->{$id}{'filesize'});
+    $doc_obj->add_metadata($section, "Width", $imgs->{$id}{'width'});
+    $doc_obj->add_metadata($section, "Height", $imgs->{$id}{'height'});
+    $doc_obj->add_metadata($section, "URL", "http://$orig_fp");
+    $doc_obj->add_metadata($section, "PageURL", $self->{'hturl'});
+    $doc_obj->add_metadata($section, "PageTitle", $pagetitle);
+    $doc_obj->add_metadata($section, "ThumbURL", 
+			   "_httpcollection_/index/assoc/[archivedir]/$fn.thumb.jpg");
+    $doc_obj->add_metadata($section, "FileFormat", "W3Img");
+
+    if ( $self->{'document_text'} ) {
+	$doc_obj->add_utf8_text($section, "<table border=1>\n$reltext</table>");
+    } else {
+	$doc_obj->add_metadata($section, "ImageText", "<table border=1>\n$reltext</table>\n");
+    }
+    
+    if ( $self->{'index_pages'} ) {
+	my ($cache_url) = "_httpdoc_&d=" . $self->{'htdoc_obj'}->get_OID();
+	if ( $imgs->{$id}{'anchored'} ) {
+	    my $a_name = $id;
+	    $a_name =~ s/[\/\\\:\&]/_/g;
+	    $cache_url .=  "#gsdl_$a_name" ;
+	}
+	$doc_obj->add_utf8_metadata($section, "CachePageURL", $cache_url);
+    }
+    if ( ! $self->{'no_cache_images'} ) {
+	$onlyfn = lc $onlyfn;
+	$doc_obj->associate_file($filepath, $onlyfn, undef, $section);
+	$doc_obj->add_utf8_metadata($section, "CacheURL", 
+			       "_httpcollection_/index/assoc/[archivedir]/$onlyfn");
+    }
+    return 1;
+}
+
+sub get_page_metadata {
+    my ($self, $textref) = (@_);
+    my (@rval);
+    $rval[0] = $self->get_meta_value("title", $textref);
+    $rval[1] = $self->get_meta_value("keywords", $textref);
+    $rval[2] = $self->get_meta_value("description", $textref);
+    $rval[3] = $self->{'filename'};
+
+    return wantarray ? @rval : "<tr><td>PageMeta</td><td>@rval</td></tr>\n" ;
+}
+
+# turns LargeCatFish into Large,Cat,Fish so MG sees the separate words
+sub split_filepath {
+    my ($self, $filepath) = (@_);
+    my (@words) = $filepath =~ /([A-Z][a-z]+)/g; 
+    return join(',', @words);
+}
+
+# finds and extracts sentences
+# that seem to be on the same topic
+# as other related text (correlations)
+# and textual references (e.g. in figure 3 ...)
+sub get_textrefs {
+    my ($self, $reltext, $textref, $prevpos, $pos, $nextpos) = (@_);
+    my ($maxtext, $mintext, $startpos, $context_size, $context);
+
+    my (@relwords, @refwords, %sentences, @pagemeta);
+
+    # extract larger context
+    $maxtext = $self->{'max_near_text'};
+    $startpos = $pos - ($maxtext * 4);
+    $context_size = $maxtext*10;
+    if ($startpos < $prevpos ) { $startpos = $prevpos }
+    if ($nextpos != -1 && $context_size > ( $nextpos - $startpos )) { $context_size = ($nextpos - $startpos) }
+    $context = substr ( $$textref, $startpos, $context_size );
+    $context =~ s/<.*?>//gs;
+    $context =~ s/^.*>(.*)/$1/gs;
+    $context =~ s/(.*)<.*$/$1/gs;
+
+    # get page meta-data (if not already included)
+    if ( $self->{'aggressiveness'} == 5 && ! $self->{'smallpage'} ) {
+	@pagemeta = $self->get_page_metadata($textref);
+	foreach my $value ( @pagemeta ) {
+	    $context .= "$value."; # make each into psuedo-sentence
+	}
+    }
+
+    # TODO: this list is not exhaustive
+    @refwords = ( '(?:is|are)? ?(?:show(?:s|n)|demonstrate(?:d|s)|explains|features) (?:in|by|below|above|here)', 
+		  '(?:see)? (?:figure|table)? (?:below|above)');    
+
+    # extract general references
+    foreach my $rw ( @refwords ) {
+	while ( $context =~ /[\.\?\!\,](.*?$rw\W.*?[\.\?\!\,])/ig ) {
+	    my $sentence = $1;
+	    $sentence =~ s/\s+/ /g;
+	    $sentences{$sentence}+=2;
+	}
+    }
+    # extract specific (figure, table) references by number
+    my ($fignum) = $context =~ /[\.\?\!].*?(?:figure|table)s?[\-\_\ \.](\d+\w*)\W.*?[\.\?\!]/ig;
+    if ( $fignum ) {
+	foreach my $rw ( @refwords ) {
+	    while ( $context =~ /[\.\?\!](.*?(figure|table)[\-\_\ \.]$fignum\W.*?[\.\?\!])/ig ) {
+		my $sentence = $1;
+		$sentence =~ s/\s+/ /g;
+		$sentences{$sentence}+=4;
+	    }
+	}
+    }
+
+    # sentences with occurances of important words
+    @relwords = $reltext =~ /([a-zA-Z]{4,})/g; # take out small words
+    foreach my $word ( @relwords ) {
+	if ( $self->{'stopwords'}{$word} ) { next } # skip stop words
+	while ( $context =~ /([^\.\?\!]*?$word\W.*?[\.\?\!])/ig ) {
+	    my $sentence = $1;
+	    $sentence =~ s/\s+/ /g;
+	    $sentences{$sentence}++;
+	}
+    }
+    foreach my $sentence ( keys %sentences ) {
+	if ($sentences{$sentence} < $self->{'textrefs_threshold'}) {
+	    delete $sentences{$sentence};
+	}
+    }
+    my ($rval) = join "<br>\n", (keys %sentences);
+    if ( $rval && length($rval) > 5 ) {
+	return ( "<tr><td>TextualReferences</td><td>" . $rval . "</td></tr>\n") }
+    else { return "" }
+}
+
+# handles caption extraction
+# calling the extractor with different
+# tags and choosing the best candidate caption
+sub extract_caption_text {
+    my ($self, $tag, $textref, $prevpos, $pos, $nextpos) = (@_);
+    my (@neartext, $len, $hdelim, $mintext, $goodlen,
+	$startpos, $context, $context_size);
+    
+    $mintext = $self->{'min_near_text'};
+    $goodlen = $self->{'caption_length'};
+
+    # extract a context to extract near text from (faster)
+    $context_size = $self->{'max_near_text'}*3;
+    $startpos = $pos - ($context_size / 2);
+    if ($startpos < $prevpos ) { $startpos = $prevpos }
+    if ($nextpos != -1 && $context_size > ( $nextpos - $startpos )) 
+    { $context_size = ($nextpos - $startpos) }
+
+    $context = substr ( $$textref, $startpos, $context_size );
+    $context =~ s/<!--.*?-->//gs;
+    $context =~ s/^.*-->(.*)/$1/gs;
+    $context =~ s/(.*)<!--.*$/$1/gs;
+
+    # try stepping through markup delimiter sets
+    # and selecting the best one
+    foreach $hdelim ( @{ $self->{'cdelims'} } ) {
+	@neartext = $self->extract_caption($tag, $hdelim, \$context);
+	$len = length(join("", @neartext));
+	last if ($len >= $mintext && $len <= $goodlen);
+    }
+    # reject if well over reasonable length
+    if ( $len > $goodlen ) {
+	@neartext = [];
+    }
+    $neartext[0] = " " if (! defined $neartext[0]);
+    $neartext[1] = " " if (! defined $neartext[1]);
+    return "<tr><td>Caption</td><td>" . (join ",",  @neartext) . "</td></tr>\n"; # TODO: the | is for testing purposes
+} # end extract_caption_text
+
+# the previous section header often gives a bit
+# of context to the section that the image is
+# in (invariably the header is before/above the image)
+# so extract the text of the closest header above the image
+#
+# this fn just gets all the headers above the image, within the context window
+sub get_prev_header {
+    my ($self, $pos, $textref) = (@_);
+    my ($rhtext);
+    while ( $$textref =~ /<h\d>(.*?)<\/h\d>/sig ) {
+	# only headers before image
+	if ((pos $$textref) < $pos) {
+	    $rhtext .= "$1, ";
+	}
+    } 
+    if ( $rhtext ) { return "Header($rhtext)" }
+    else { return "" }
+}
+
+# not the most robust tag stripping 
+# regexps (see perl.com FAQ) but good enough
+#
+# used by caption & tag-based near text algorithms
+sub strip_tags {
+    my ( $self, $value ) = @_;
+    if ( ! defined($value) ) { $value = "" } # handle nulls
+    else {
+	$value =~ s/<.*?>//gs; # strip all html tags
+	$value =~ s/\s+/\ /g; # remove extra whitespace
+	$value =~ s/\&\w+\;//g; # remove &nbsp; etc
+    }
+    return $value;
+}
+
+# uses the given tag(s) to identify
+# the caption near to the image
+# (below, above or both below and above)
+sub extract_caption {
+    my ($self, $tag, $bound_tag, $contextref) = (@_);
+    my (@nt, $n, $etag, $gotcap);
+    return ("", "") if ( ! ($$contextref =~ /\Q$tag/) );
+
+    $nt[0] = $`;
+    $nt[1] = $';
+    $gotcap = 0;
+
+    # look before the image for a boundary tag
+    ($etag, $nt[0]) = $nt[0] =~ /<($bound_tag)[\s]?.*?>(.*?)$/is;
+    # if bound_tag too far from the image, then prob not caption
+    # (note: have to allow for tags, so multiply by 3
+    if ( $etag && length($nt[0]) < ($self->{'caption_length'} * 3) ) { 
+	if ( $nt[0] =~ /<\/$etag>/si ) {
+	    # the whole caption is above the image: <tag>text</tag><img>
+	    ($nt[0]) =~ /<(?:$etag)[\s]?.*?>(.*?)<\/$etag>/is;
+	    $nt[0] = $self->strip_tags($nt[0]);
+	    if ( length($nt[0]) > $self->{'min_near_text'} ) { 
+		$gotcap = 1;
+		$nt[1] = ""; 
+	    }
+
+	} elsif ( $nt[1] =~ /<\/$etag>/si) {
+	    # the caption tag covers image: <tag>text?<img>text?</tag>
+	    ($nt[1]) = $nt[1] =~ /(.*?)<\/$etag>/si;
+	    $nt[0] = $self->strip_tags($nt[0] . $nt[1]);
+	    if ( length($nt[0]) > $self->{'min_near_text'} ) { 
+		$gotcap = 2;
+		$nt[1] = "";
+	    }
+	}
+    }
+    # else try below the image
+    if ( ! $gotcap ) { 
+	# the caption is after the image: <img><tag>text</tag>
+	($etag, $nt[1]) = $nt[1] =~ /^.*?<($bound_tag)[\s]?.*?>(.*)/is;
+	if ( $etag && $nt[1] =~ /<\/$etag>/s) {
+	    ($nt[1]) = $nt[1] =~ /(.*?)<\/$etag>/si;
+	    $gotcap = 3;
+	    $nt[0] = "";
+	    $nt[1] = $self->strip_tags($nt[1]);
+	} 
+    }
+    if ( ! $gotcap ) { $nt[0] = $nt[1] = "" }
+    else {
+	# strip part-tags
+	$nt[0] =~ s/^.*>//s;
+	$nt[1] =~ s/<.*$//s;
+    }
+    my ($type);
+    if ( $gotcap == 0 ) { return ("nocaption", "") }
+    elsif ( $gotcap == 1 ) { $type = "captionabove:" }
+    elsif ( $gotcap == 2 ) { $type = "captioncovering:" }
+    elsif ( $gotcap == 3 ) { $type = "captionbelow:" }
+    return ($type, $nt[0], $nt[1]);
+}
+
+# tag-based near text
+# 
+# tries different tag sets
+# and chooses the best one
+sub extract_near_text {
+    my ($self, $tag, $textref, $prevpos, $pos, $nextpos) = (@_);
+    my (@neartext, $len, $hdelim, $maxtext, $mintext, $goodlen,
+	@bestlen, @best, $startpos, $context, $context_size,
+	$dist, $bdist, $best1, $i, $nt);
+    $bestlen[0] = $bestlen[1] = 0; $bestlen[2] = $bdist = 999999;
+    $best[0] = $best[1] = $best[2] = "";
+    $maxtext = $self->{'max_near_text'};
+    $mintext = $self->{'min_near_text'};
+    $goodlen = $self->{'neartext_length'}; 
+
+    # extract a context to extract near text from (faster)
+    $context_size = $maxtext*4;
+    $startpos = $pos - ($context_size / 2);
+    if ($startpos < $prevpos ) { $startpos = $prevpos }
+    if ($nextpos != -1 && $context_size > ( $nextpos - $startpos )) 
+    { $context_size = ($nextpos - $startpos) }
+    $context = substr ( $$textref, $startpos, $context_size );
+    $context =~ s/<!--.*?-->//gs;
+    $context =~ s/^.*-->(.*)/$1/gs;
+    $context =~ s/(.*)<!--.*$/$1/gs;
+
+    # try stepping through markup delimiter sets
+    # and selecting the best one
+    foreach $hdelim ( @{ $self->{'delims'} } ) {
+	@neartext = $self->extract_tagged_neartext($tag, $hdelim, \$context);
+	$nt = join("", @neartext);
+	$len = length($nt);
+	# Priorities:
+	# 1. Greater than mintext 
+	# 2. Less than maxtext 
+	# 3. Closest to goodlen
+	if ( $len <= $goodlen && $len > $bestlen[0] ) {
+	    $bestlen[0] = $len;
+	    $best[0] = $hdelim;
+	} elsif ( $len >= $maxtext && $len < $bestlen[2] ) {
+	    $bestlen[2] = $len;
+	    $best[2] = $hdelim;
+	} elsif ( $len >= $bestlen[0] && $len <= $bestlen[2] ) {
+	    $dist = abs($goodlen - $len);
+	    if ( $dist < $bdist ) {
+		$bestlen[1] = $len;
+		$best[1] = $hdelim;
+		$bdist = $dist;
+	    }
+	}
+    }
+    $best1 = 2;
+    foreach $i ( 0..2 ) {
+	if ( $bestlen[$i] == 999999 ) { $bestlen[$i] = 0 }
+	$dist = abs($goodlen - $bestlen[$i]);
+	if ( $bestlen[$i] > $mintext && $dist <= $bdist ) {
+	    $best1 = $i;
+	    $bdist = $dist;
+	}
+    }
+    @neartext = $self->extract_tagged_neartext($tag, $best[$best1], \$context);
+    if ( $bestlen[$best1] > $maxtext ) {
+	# truncate on word boundary if too much text
+	my $hmax = $maxtext / 2;
+	($neartext[0]) = $neartext[0] =~ /([^\s]*.{1,$hmax})$/s;
+	($neartext[1]) = $neartext[1] =~ /^(.{1,$hmax}[^\s]*)/s;
+    } elsif ( $bestlen[$best1] < $mintext ) {
+	# use plain text extraction if tags failed (e.g. usable tag outside context)
+	print {$self->{'outhandle'}} "W3ImgPlug: Fallback to plain-text extraction for $tag\n" 
+	    if $self->{'verbosity'} > 2;
+	$neartext[0] = "<tr><td>RawNeartext</td><td>" . $self->extract_raw_neartext($tag, $textref) . "</td></tr>";
+	$neartext[1] = "";
+    }
+    # get previous header if available
+    $neartext[0] .= "<br>\n" . 
+	$self->get_prev_header($pos, \$context) if ( $self->{'aggressiveness'} >= 4 );
+    $neartext[0] = " " if (! defined $neartext[0]);
+    $neartext[1] = " " if (! defined $neartext[1]);
+
+    return "<tr><td>NearText</td><td>" . (join "|",  @neartext) . "</td></tr>\n"; # TODO: the | is for testing purposes
+} # end extract_near_text
+
+# actually captures tag-based
+# near-text given a tag set
+sub extract_tagged_neartext {
+    my ($self, $tag, $bound_tag, $textref) = (@_);
+    return "" if ( ! ($$textref =~ /\Q$tag/) );
+    my (@nt, $delim, $pre_tag, $n);
+    $nt[0] = $`;
+    $nt[1] = $';
+
+    # get text after previous image tag
+    $nt[0] =~ s/.*<($bound_tag)[^>]*>(.*)/$2/is; # get rid of preceding text
+    if (defined($1)) { $delim = $1 }    
+    $pre_tag = $bound_tag;
+
+    if (defined($delim)) {
+	# we want to try and use the end tag of the previous delimiter
+	# (put it on the front of the list)
+	$pre_tag =~ s/(^|\|)($delim)($|\|)//i; # take it out
+	$pre_tag =~ s/\|\|/\|/i; # replace || with |
+	$pre_tag = $delim . "|" . $pre_tag; # put it on the front
+    }
+    
+    # get text before next image tag
+    $nt[1] =~ s/<\/?(?:$pre_tag)[^>]*>.*//is; # get rid of stuff after first delimiter
+
+    # process related text
+    for $n (0..1) {
+	if ( defined($nt[$n]) ) {
+	    $nt[$n] =~ s/<.*?>//gs; # strip all html tags
+	    $nt[$n] =~ s/\s+/\ /gs; # remove extra whitespace
+	    $nt[$n] =~ s/\&\w+\;//sg; # remove &nbsp; etc
+	    # strip part-tags
+	    if ( $n == 0 ) { $nt[0] =~ s/^.*>//s }
+	    if ( $n == 1 ) { $nt[1] =~ s/<.*$//s }
+	} else { $nt[$n] = ""; } # handle nulls
+    }
+    return @nt;
+}
+
+# this function is fall-back
+# if tags aren't suitable.
+#
+# extracts a fixed length of characters
+# either side of image tag (on word boundary)
+sub extract_raw_neartext {
+    my ($self, $tag, $textref) = (@_);
+    my ($rawtext, $startpos, $fp);
+    my $imgs = \%{$self->{'imglist'}};
+    ($fp) = $tag =~ /([\w\\\/]+\.(?:gif|jpe?g|png))/is;
+    if (! $fp) { return " " };
+    # if the cached, plain-text version isn't there, then create it
+    $self->init_plaintext($textref) unless defined($self->{'plaintext'});
+
+    # take the closest maxtext/2 characters 
+    # either side of the tag (by word boundary)
+    return "" if ( ! exists $imgs->{$fp}{'rawpos'} );
+    $startpos = $imgs->{$fp}{'rawpos'} - (($self->{'max_near_text'} / 2) + 20);
+    if ( $startpos < 0 ) { $startpos = 0 }
+    $rawtext = substr $self->{'plaintext'}, $startpos, $self->{'max_near_text'} + 20;
+    $rawtext =~ s/\s\s/ /g;
+
+    return $rawtext;
+}
+
+# init plaintext variable for HTML-stripped version 
+# (for full text index/raw assoc text extraction)
+sub init_plaintext {
+    my ($self, $textref) = (@_);
+    my ($page, $fp);
+    my $imgs = \%{$self->{'imglist'}};
+    $page = $$textref; # make a copy of original
+
+    # strip tags around image filenames so they don't get zapped
+    $page =~ s/<\w+\s+.*?([\w\/\\]+\.(?:gif|jpe?g|png))[^>]*>/\"$1\"/gsi;
+    $page =~ s/<.*?>//gs;
+    $page =~ s/&nbsp;/ /gs;
+    $page =~ s/&amp;/&/gs; #TODO: more &zzz; replacements (except &lt;, $gt;)
+
+    # get positions and strip images
+    while ( $page =~ /([^\s\'\"]+\.(jpe?g|gif|png))/ig ) {
+	$fp = $1;
+	if ( $imgs->{$fp}{'exists'} ) {
+	    $imgs->{$fp}{'rawpos'} = pos $page;
+	}
+	$page =~ s/\"$fp\"//gs;
+    }
+    $self->{'plaintext'} = $page;
+}
+
+# finds and filters images based on size 
+# (dimensions, height, filesize) and existence
+#
+# looks for image filenames (.jpg, .gif, etc)
+# and checks for existence on disk 
+# (hence supports most JavaScript images)
+sub get_img_list {
+    my $self = shift (@_);
+    my ($textref) = (@_);
+    my ($filepath, $relpath, $abspath, $pos, $num, $width, $height, $filesize);
+    my $imgs = \%{$self->{'imglist'}};
+    while ( $$textref =~ /([^\s\'\"]+\.(jpe?g|gif|png))/ig ) {
+	$filepath = $1;
+	$pos = pos $$textref;
+	next if ( $imgs->{$filepath}{'relpath'} );
+        $relpath = $filepath;
+	$relpath =~ s/^http\:\/\///; # remove http:// in case we have mirrored it
+	$relpath =~ s/\\/\//g;  # replace \ with /
+	$relpath =~ s/^\.\///s; # make "./filepath" into "filepath"
+	$imgs->{$filepath}{'relpath'} = $relpath;
+	$abspath = "$self->{'htpath'}/$relpath";
+
+	if (! -e $abspath) { next }
+
+	# can't modify real filepath var because it
+	# then can't be located in the page for tag recognition later
+	($width, $height) = 
+	    `identify $abspath -ping -format "%wx%h"` =~ /^(\d*)x(\d*)$/m;
+	if (! ($width && $height)) { 
+	    print STDERR "W3ImgPlug: ($abspath) 'identify' failed. Check ImageMagicK binaries are installed and working correctly\n"; next;
+	}
+	$filesize = (-s $abspath);
+	if ( $filesize >= $self->{'min_size'} 
+	    && ( $width >= $self->{'min_width'} ) 
+	    && ( $height >= $self->{'min_height'} ) ) {
+	    
+	   $imgs->{$filepath}{'exists'} = 1;
+	   $imgs->{$filepath}{'pos'} = $pos;
+	   $imgs->{$filepath}{'width'} = $width;
+	   $imgs->{$filepath}{'height'} = $height;
+	   $imgs->{$filepath}{'filesize'} = $filesize;
+       } else {
+	   print {$self->{'outhandle'}} "W3ImgPlug: skipping $self->{'base_path'}/$relpath: $filesize, $width x $height\n" 
+	       if $self->{'verbosity'} > 2;
+       }
+    }
+    $num = 0;
+    foreach my $i ( keys %{$imgs} ) {
+	if ( $imgs->{$i}{'pos'} ) {
+	    $num++;
+	} else { delete $imgs->{$i} }
+    }
+    return $num;
+}
+
+# make the text available to the read function
+# by making it an object variable
+sub read_file {
+    my ($self, $filename, $encoding, $language, $textref) = @_;
+    $self->SUPER::read_file($filename, $encoding, $language, $textref);
+
+    # if HTMLplug has run through, then it will
+    # have replaced references so we have to 
+    # make a copy of the text before processing
+    if ( $self->{'index_pages'} ) {
+	$self->{'text'} = $$textref;
+	$self->{'textref'} = \($self->{'text'});
+    } else {
+	$self->{'textref'} = $textref;
+    }
+    $self->{'plaintext'} = undef;
+}
+
+# HTMLPlug only extracts meta-data if it is specified in plugin options
+# hence a special function to do it here
+sub get_meta_value {
+    my ($self, $name, $textref) = @_;
+    my ($value);
+    $name = lc $name;
+    if ($name eq "title") {
+	($value) = $$textref =~ /<title>(.*?)<\/title>/is
+    } else {
+	my $qm = "(?:\"|\')";
+	($value) = $$textref =~ /<meta name\s*=\s*$qm?$name$qm?\s+content\s*=\s*$qm?(.*?)$qm?\s*>/is
+    }
+    $value = "" unless $value;
+    return $value;
+}
+
+# make filename an anchor reference
+# so we can go straight to the image
+# within the cached version of the source page
+# (augment's HTMLPlug sub)
+sub replace_images {
+    my $self = shift (@_);
+    my ($front, $link, $back, $base_dir, 
+	$file, $doc_obj, $section) = @_;
+    $link =~ s/\"//g;
+    my ($a_name) = $link;
+    $a_name =~ s/[\/\\\:\&]/_/g;
+    # keep a list so we don't repeat the same anchor
+    if ( ! $self->{'imglist'}{$link}{'anchored'} ) {
+	$front = "<a name=\"gsdl_$a_name\">$front";
+	$back = "$back</a>";
+	$self->{'imglist'}{$link}{'anchored'} = 1;
+    }
+    return $self->SUPER::replace_images($front, $link, $back, $base_dir, 
+				     $file, $doc_obj, $section);
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/WordPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/WordPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/WordPlug.pm	(revision 10506)
@@ -0,0 +1,230 @@
+###########################################################################
+#
+# WordPlug.pm -- plugin for importing Microsoft Word documents
+# 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.
+#
+###########################################################################
+# 12/05/02 Added usage datastructure - John Thompson
+
+package WordPlug;
+
+use ConvertToPlug;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @WordPlug::ISA = ('ConvertToPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" }
+      ];
+
+my $options = { 'name'     => "WordPlug",
+		'desc'     => "{WordPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if ($ENV{'GSDLOS'} =~ m/^windows$/i) {
+	my $ws_arg = [ { 'name' => "windows_scripting",
+			 'desc' => "{WordPlug.windows_scripting}",
+			 'type' => "flag",
+		         'reqd' => "no" },
+		       { 'name' => "delete_toc",
+			 'desc' => "{WordPlug.delete_toc}",
+			 'type' => "flag",
+			 'reqd' => "no"},
+		       { 'name' => "level1_header",
+			 'desc' => "{WordPlug.level1_header}",
+			 'type' => "regexp",
+			 'reqd' => "no",
+			 'deft' => "" },
+		       { 'name' => "level2_header",
+			 'desc' => "{WordPlug.level2_header}",
+			 'type' => "regexp",
+			 'reqd' => "no",
+			 'deft' => "" },
+		       { 'name' => "level3_header",
+			 'desc' => "{WordPlug.level3_header}",
+			 'type' => "regexp",
+			 'reqd' => "no",
+			 'deft' => "" },
+		       { 'name' => "title_header",
+			 'desc' => "{WordPlug.title_header}",
+			 'type' => "regexp",
+			 'reqd' => "no",
+			 'deft' => "" },
+		       { 'name' => "toc_header",
+			 'desc' => "{WordPlug.toc_header}",
+			 'type' => "regexp",
+			 'reqd' => "no",
+			 'deft' => "" },
+		       { 'name' => "tof_header",
+			 'desc' => "{WordPlug.tof_header}",
+			 'type' => "regexp",
+			 'reqd' => "no",
+			 'deft' => "" },
+		       { 'name' => "extracted_word_metadata_fields",
+			 'type' => "string",
+			 'deft' => "Title"}];
+	
+	push(@$arguments,@$ws_arg);
+    }
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new ConvertToPlug($pluginlist,$inputargs,$hashArgOptLists): new ConvertToPlug($pluginlist,$inputargs);
+
+    #this is passed through to gsConvert.pl by ConvertToPlug.pm
+    $self->{'convert_options'} = "-windows_scripting" if $self->{'windows_scripting'};
+
+    my $secondary_plugin_options = $self->{'secondary_plugin_options'};
+    if (defined $self->{'windows_scripting'}) { 
+	if (!defined $secondary_plugin_options->{'StructuredHTMLPlug'}){
+	    $secondary_plugin_options->{'StructuredHTMLPlug'} = [];
+	    my $structhtml_options = $secondary_plugin_options->{'StructuredHTMLPlug'};
+	    if ($self->{'input_encoding'} eq "auto") {
+		$self->{'input_encoding'} = "utf8";
+		$self->{'extract_language'} = 1;
+		push(@$structhtml_options,"-input_encoding", "utf8");
+		push(@$structhtml_options,"-extract_language");
+	    }
+				
+	    # Instruct HTMLPlug (when eventually accessed through read_into_doc_obj)
+	    # to extract these metadata fields from the HEAD META fields
+	    push (@$structhtml_options,"-metadata_fields","Title,GENERATOR,date,author<Creator>");
+	    push (@$structhtml_options , "-title_sub", '^(Page\s+\d+)?(\s*1\s+)?');
+	    push (@$structhtml_options, "-description_tags") if $self->{'windows_scripting'};
+	    push (@$structhtml_options, "-delete_toc") if $self->{'delete_toc'};
+	    push (@$structhtml_options, "-toc_header", $self->{'toc_header'}) if $self->{'toc_header'};
+	    push (@$structhtml_options, "-tof_header", $self->{'tof_header'}) if $self->{'tof_header'};
+	    push (@$structhtml_options, "-title_header", $self->{'title_header'}) if $self->{'title_header'};
+	    push (@$structhtml_options, "-level1_header", $self->{'level1_header'}) if $self->{'level1_header'};
+	    push (@$structhtml_options, "-level2_header", $self->{'level2_header'})if $self->{'level2_header'};
+	    push (@$structhtml_options, "-level3_header", $self->{'level3_header'}) if $self->{'level3_header'};
+	    push (@$structhtml_options, "-extracted_word_metadata_fields", $self->{'extracted_word_metadata_fields'}) if $self->{'extracted_word_metadata_fields'};
+	}
+    }
+    if (!defined $secondary_plugin_options->{'HTMLPlug'}) {
+	$secondary_plugin_options->{'HTMLPlug'} = [];
+    }
+    if (!defined $secondary_plugin_options->{'TEXTPlug'}) {
+	$secondary_plugin_options->{'TEXTPlug'} = [];
+    }
+
+    my $html_options = $secondary_plugin_options->{'HTMLPlug'};
+    my $text_options = $secondary_plugin_options->{'TextPlug'};
+    
+    # wvWare will always produce html files encoded as utf-8
+    if ($self->{'input_encoding'} eq "auto") {
+	$self->{'input_encoding'} = "utf8";
+	$self->{'extract_language'} = 1;
+	push(@$html_options,"-input_encoding", "utf8");
+	push(@$html_options,"-extract_language");
+    }
+
+    # Instruct HTMLPlug (when eventually accessed through read_into_doc_obj)
+    # to extract these metadata fields from the HEAD META fields
+    push(@$html_options,"-metadata_fields","Title,GENERATOR,date,author<Creator>");
+    push(@$html_options , "-title_sub", '^(Page\s+\d+)?(\s*1\s+)?');
+       
+    $self = bless $self, $class;
+    $self->load_secondary_plugins($class,$secondary_plugin_options,$hashArgOptLists);
+
+    return bless $self;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.(doc|dot)$^;
+}
+
+sub convert_post_process
+{
+    my $self = shift (@_);
+    my ($conv_filename) = @_;
+
+    my $outhandle=$self->{'outhandle'};
+     
+    my ($language, $encoding) = $self->textcat_get_language_encoding ($conv_filename);
+
+    # read in file ($text will be in utf8)
+    my $text = "";
+    $self->read_file ($conv_filename, $encoding, $language, \$text);
+
+    # turn any high bytes that aren't valid utf-8 into utf-8.
+    #unicode::ensure_utf8(\$text);
+    
+    # Write it out again!
+    #$self->utf8_write_file (\$text, $conv_filename);
+}
+
+sub get_file_type {
+    my $self = shift (@_);
+    my $file_type = "Word";
+    return $file_type;
+}
+
+# Modified to cache HTML files for efficieny reasons rather
+# than delete all.  HTML is modified not to use IE's VML.
+# VML uses WML files, so these can be deleted.
+sub cleanup_tmp_area {
+    my ($self) = @_;
+    if (defined $self->{'files_dir'}) {
+	my $html_files_dir = $self->{'files_dir'};
+
+	if (opendir(DIN,$html_files_dir)) {
+	    my @wmz_files = grep( /\.wmz$/, readdir(DIN));
+	    foreach my $f (@wmz_files) {
+		my $full_f = &util::filename_cat($html_files_dir,$f);
+		&util::rm($full_f);
+	    }
+	    closedir(DIN);
+	}
+	else {
+	    # if HTML file has no supporting images, then no _files dir made
+	    # => do nothing
+	}
+    }
+}
+
+# do plugin specific processing of doc_obj for HTML type
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+
+    return $self->process_type("doc", $base_dir, $file, $doc_obj);
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/XMLPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/XMLPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/XMLPlug.pm	(revision 10506)
@@ -0,0 +1,360 @@
+###########################################################################
+#
+# XMLPlug.pm -- base class for XML plugins
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001 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 XMLPlug;
+
+use BasPlug;
+use doc;
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+sub BEGIN {
+    @XMLPlug::ISA = ('BasPlug');
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+}
+
+use XMLParser;
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "xslt",
+	'desc' => "{XMLPlug.xslt}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "XMLPlug",
+		'desc'     => "{XMLPlug.desc}",
+		'abstract' => "yes",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+
+our ($self);
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+    
+    # $self is global for use within subroutines called by XML::Parser
+    $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    my $parser = new XML::Parser('Style' => 'Stream',
+				 'Handlers' => {'Char' => \&Char,
+						'XMLDecl' => \&XMLDecl,
+						'Entity' => \&Entity,
+						'Doctype' => \&Doctype,
+						'Default' => \&Default
+						});  
+    $self->{'parser'} = $parser;
+
+    return bless $self, $class;
+}
+
+sub apply_xslt
+{
+    my $self = shift @_;
+    my ($xslt,$filename) = @_;
+    
+    my $outhandle = $self->{'outhandle'};
+
+    my $xslt_filename = $xslt;
+
+    if (! -e $xslt_filename) {
+	# Look in main site directory
+	my $gsdlhome = $ENV{'GSDLHOME'};
+	$xslt_filename = &util::filename_cat($gsdlhome,$xslt);
+    }
+
+    if (! -e $xslt_filename) {
+	# Look in collection directory
+	my $coldir = $ENV{'COLLECTDIR'};
+	$xslt_filename = &util::filename_cat($coldir,$xslt);
+    }
+
+    if (! -e $xslt_filename) {
+	print $outhandle "Warning: Unable to find XSLT $xslt\n";
+	if (open(XMLIN,"<$filename")) {
+
+	    my $untransformed_xml = "";
+	    while (defined (my $line = <XMLIN>)) {
+
+		$untransformed_xml .= $line;
+	    }
+	    close(XMLIN);
+	    
+	    return $untransformed_xml;
+	}
+	else {
+	    print $outhandle "Error: Unable to open file $filename\n";
+	    print $outhandle "       $!\n";
+	    return "";
+	}
+	
+    }
+
+    my $bin_java = &util::filename_cat($ENV{'GSDLHOME'},"bin","java");
+    my $jar_filename = &util::filename_cat($bin_java,"xalan.jar");
+    my $xslt_base_cmd = "java -jar $jar_filename";
+    my $xslt_cmd = "$xslt_base_cmd -IN \"$filename\" -XSL \"$xslt_filename\"";
+
+    my $transformed_xml = "";
+
+    if (open(XSLT_IN,"$xslt_cmd |")) {
+	while (defined (my $line = <XSLT_IN>)) {
+
+	    $transformed_xml .= $line;
+	}
+	close(XSLT_IN);
+    }
+    else {
+	print $outhandle "Error: Unable to run command $xslt_cmd\n";
+	print $outhandle "       $!\n";
+    }
+
+    return $transformed_xml;
+
+}
+
+
+sub read {
+    # $self must be global to work with XML callback routines.
+    $self = shift (@_);  
+  
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    my $filename = $file;
+    $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+
+    if ($self->{'block_exp'} ne "" && $filename =~ /$self->{'block_exp'}/) {
+	$self->{'num_blocked'} ++;
+	return 0;
+    }
+    if ($filename !~ /$self->{'process_exp'}/ || !-f $filename) {
+	return undef;
+    }
+
+    $file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
+    $self->{'file'} = $file;
+    $self->{'filename'} = $filename;
+    $self->{'processor'} = $processor;
+    $self->{'metadata'} = $metadata;
+    $self->{'gli'} = $gli;
+
+    eval {
+	my $xslt = $self->{'xslt'};
+	if (defined $xslt && ($xslt ne "")) {
+	    # perform xslt
+	    my $transformed_xml = $self->apply_xslt($xslt,$filename);
+
+	    # feed transformed file (now in memory as string) into XML parser
+	    $self->{'parser'}->parse($transformed_xml);
+	}
+	else {
+	    $self->{'parser'}->parsefile($filename);
+	}
+    };
+  
+    if ($@) {
+
+	# parsefile may either croak somewhere in XML::Parser (e.g. because
+	# the document is not well formed) or die somewhere in XMLPlug or a
+	# derived plugin (e.g. because we're attempting to process a
+	# document whose DOCTYPE is not meant for this plugin). For the
+	# first case we'll print a warning and continue, for the second
+	# we'll just continue quietly
+
+	print STDERR "**** Error is: $@\n";
+
+	my ($msg) = $@ =~ /Carp::croak\(\'(.*?)\'\)/;
+	if (defined $msg) {	
+	    my $outhandle = $self->{'outhandle'};
+	    my $plugin_name = ref ($self);
+	    print $outhandle "$plugin_name failed to process $file ($msg)\n";
+	}
+
+	# reset ourself for the next document
+	$self->{'section_level'}=0;
+	print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	return -1; # error during processing
+    }
+
+    return 1; # processed the file
+}
+
+# the following two methods are for if you want to do the parsing from a
+# plugin that inherits from this. it seems that you can't call the parse 
+# methods directly. WHY???
+sub parse_file {
+    $self = shift (@_); 
+    my ($filename) = @_;
+    $self->{'parser'}->parsefile($filename);
+}
+
+sub parse_string {
+    $self = shift (@_); 
+    my ($xml_string) = @_;
+    $self->{'parser'}->parse($xml_string);
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.xml$^;
+}
+
+sub StartDocument {$self->xml_start_document(@_);}
+sub XMLDecl {$self->xml_xmldecl(@_);}
+sub Entity {$self->xml_entity(@_);}
+sub Doctype {$self->xml_doctype(@_);}
+sub StartTag {$self->xml_start_tag(@_);}
+sub EndTag {$self->xml_end_tag(@_);}
+sub Text {$self->xml_text(@_);}
+sub PI {$self->xml_pi(@_);}
+sub EndDocument {$self->xml_end_document(@_);}
+sub Default {$self->xml_default(@_);}
+
+# This Char function overrides the one in XML::Parser::Stream to overcome a
+# problem where $expat->{Text} is treated as the return value, slowing
+# things down significantly in some cases.
+sub Char {
+    use bytes;  # Necessary to prevent encoding issues with XML::Parser 2.31+
+    $_[0]->{'Text'} .= $_[1];
+    return undef;
+}
+
+# Called at the beginning of the XML document.
+sub xml_start_document {
+    my $self = shift(@_);
+    my ($expat) = @_;
+
+    $self->open_document();
+}
+
+# Called for XML declarations
+sub xml_xmldecl {
+    my $self = shift(@_);
+    my ($expat, $version, $encoding, $standalone) = @_;
+}
+
+# Called for XML entities
+sub xml_entity {
+  my $self = shift(@_);
+  my ($expat, $name, $val, $sysid, $pubid, $ndata) = @_;
+}
+
+# Called for DOCTYPE declarations - use die to bail out if this doctype
+# is not meant for this plugin
+sub xml_doctype {
+    my $self = shift(@_);
+    my ($expat, $name, $sysid, $pubid, $internal) = @_;
+    die "XMLPlug Cannot process XML document with DOCTYPE of $name";
+}
+
+# Called for every start tag. The $_ variable will contain a copy of the
+# tag and the %_ variable will contain the element's attributes.
+sub xml_start_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+}
+
+# Called for every end tag. The $_ variable will contain a copy of the tag.
+sub xml_end_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+}
+
+# Called just before start or end tags with accumulated non-markup text in
+# the $_ variable.
+sub xml_text {
+    my $self = shift(@_);
+    my ($expat) = @_;
+}
+
+# Called for processing instructions. The $_ variable will contain a copy
+# of the pi.
+sub xml_pi {
+    my $self = shift(@_);
+    my ($expat, $target, $data) = @_;
+}
+
+# Called at the end of the XML document.
+sub xml_end_document {
+    my $self = shift(@_);
+    my ($expat) = @_;
+
+    $self->close_document();
+}
+
+# Called for any characters not handled by the above functions.
+sub xml_default {
+    my $self = shift(@_);
+    my ($expat, $text) = @_;
+}
+
+sub open_document {
+    my $self = shift(@_);
+
+    # create a new document
+    $self->{'doc_obj'} = new doc ($self->{'filename'}, "indexed_doc");
+    $self->{'doc_obj'}->set_OIDtype ($self->{'processor'}->{'OIDtype'});
+}
+
+sub close_document {
+    my $self = shift(@_);
+    my $doc_obj = $self->{'doc_obj'};
+    # include any metadata passed in from previous plugins 
+    # note that this metadata is associated with the top level section
+    $self->extra_metadata ($doc_obj, 
+			   $doc_obj->get_top_section(), 
+			   $self->{'metadata'});
+   
+    # do any automatic metadata extraction
+    $self->auto_extract_metadata ($doc_obj);
+   
+    # add an OID
+    $doc_obj->set_OID();
+    
+    $doc_obj->add_utf8_metadata($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+    $doc_obj->add_metadata($doc_obj->get_top_section(), "FileFormat", "XML");
+
+    # process the document
+    $self->{'processor'}->process($doc_obj);
+    
+    $self->{'num_processed'} ++;
+}
+
+1;
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ZIPPlug.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ZIPPlug.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/plugins/ZIPPlug.pm	(revision 10506)
@@ -0,0 +1,208 @@
+###########################################################################
+#
+# ZIPPlug.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# plugin which handles compressed and/or archived input formats
+#
+# currently handled formats and file extensions are:
+# 
+# gzip (.gz, .z, .tgz, .taz)
+# bzip (.bz)
+# bzip2 (.bz2)
+# zip (.zip .jar)
+# tar (.tar)
+#
+# this plugin relies on the following utilities being present 
+# (if trying to process the corresponding formats)
+#
+# gunzip (for gzip)
+# bunzip (for bzip)
+# bunzip2 
+# unzip (for zip)
+# tar (for tar) 
+
+
+package ZIPPlug;
+
+use BasPlug;
+use plugin;
+use util;
+use Cwd;
+
+use strict;
+no strict 'refs'; # allow filehandles to be variables and viceversa
+
+BEGIN {
+    @ZIPPlug::ISA = ('BasPlug');
+}
+
+my $arguments =
+    [ { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "string",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" } ];
+
+my $options = { 'name'     => "ZIPPlug",
+		'desc'     => "{ZIPPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+sub new {
+
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my $self = (defined $hashArgOptLists)? new BasPlug($pluginlist,$inputargs,$hashArgOptLists): new BasPlug($pluginlist,$inputargs);
+
+    # BasPlug is explicitly set not to set process_exp if recursive plugin
+    # Not sure of this reasoning.  Want it to be set in ZIPPlug, so explicitly
+    # pass it in as default value
+    
+    ## do we need this???? --kjdon
+    if (!$self->{'process_exp'}) {
+	$self->{'process_exp'} = get_default_process_exp();
+    }
+
+    return bless $self, $class;
+}
+
+# this is a recursive plugin
+sub is_recursive {
+    my $self = shift (@_);
+
+    return 1;
+}
+
+sub get_default_process_exp {
+    return q^(?i)\.(gz|tgz|z|taz|bz|bz2|zip|jar|tar)$^;
+}
+
+# return number of files processed, undef if can't process
+# Note that $base_dir might be "" and that $file might 
+# include directories
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+    my $outhandle = $self->{'outhandle'};
+
+    if ($file =~ /$self->{'process_exp'}/) {
+
+	my $filename = $file;
+	$filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
+	if (!-e $filename) {
+	    print $outhandle "ZIPPLug: WARNING: $filename does not exist\n";
+	    return undef;
+	}
+	
+	my ($file_only) = $file =~ /([^\\\/]*)$/;
+	my $tmpdir = &util::get_tmp_filename ();
+	&util::mk_all_dir ($tmpdir);
+
+	print $outhandle "ZIPPlug: extracting $file_only to $tmpdir\n"
+	    if $self->{'verbosity'} > 1;
+
+	# save current working directory
+	my $cwd = cwd();
+	chdir ($tmpdir) || die "Unable to change to $tmpdir";
+	&util::cp ($filename, $tmpdir);
+	
+	if ($file =~ /\.bz$/i) {
+	    $self->bunzip ($file_only);
+	} elsif ($file =~ /\.bz2$/i) {
+	    $self->bunzip2 ($file_only);
+	} elsif ($file =~ /\.(zip|jar)$/i) {
+	    $self->unzip ($file_only);
+	} elsif ($file =~ /\.tar$/i) {
+	    $self->untar ($file_only);
+	} else {
+	    $self->gunzip ($file_only);
+	}
+
+	chdir ($cwd) || die "Unable to change back to $cwd";
+
+	my $numdocs = &plugin::read ($pluginfo, "", $tmpdir, $metadata, $processor, $maxdocs, $total_count, $gli);
+	&util::rm_r ($tmpdir);
+
+	$self->{'num_archives'} ++;
+
+	return $numdocs;
+
+    } else {
+	return undef;
+    }
+}
+
+sub bunzip {
+    my $self = shift (@_);
+    my ($file) = @_;
+
+    if (system ("bunzip $file")!=0)
+    {
+	&util::rm ($file);
+    }
+}
+
+sub bunzip2 {
+    my $self = shift (@_);
+    my ($file) = @_;
+
+    if (system ("bunzip2 $file")!=0)
+    {
+	&util::rm ($file);
+    }
+}
+
+sub unzip {
+    my $self = shift (@_);
+    my ($file) = @_;
+
+    system ("unzip $file");
+    &util::rm ($file) if -e $file;
+}
+
+sub untar {
+    my $self = shift (@_);
+    my ($file) = @_;
+
+    system ("tar xf $file");
+    &util::rm ($file) if -e $file;
+}
+
+sub gunzip {
+    my $self = shift (@_);
+    my ($file) = @_;
+
+    if (system ("gunzip $file")!=0)
+    {
+	&util::rm ($file);
+    };
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/printusage.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/printusage.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/printusage.pm	(revision 10506)
@@ -0,0 +1,333 @@
+###########################################################################
+#
+# printusage.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+package PrintUsage;
+
+
+use gsprintf;
+use strict;
+no strict 'subs'; # allow barewords (eg STDERR) as function arguments
+
+
+sub gsprintf
+{
+    return &gsprintf::gsprintf(@_);
+}
+
+
+sub print_xml_usage
+{
+    my $options = shift(@_);
+
+    # XML output is always in UTF-8
+    &gsprintf::output_strings_in_UTF8;
+
+    &print_xml_header();
+
+    &gsprintf(STDERR, "<Info>\n");
+    &gsprintf(STDERR, "  <Name>$options->{'name'}</Name>\n");
+    &gsprintf(STDERR, "  <Desc>$options->{'desc'}</Desc>\n");
+    &gsprintf(STDERR, "  <Arguments>\n");
+    if (defined($options->{'args'})) {
+	&print_options_xml($options->{'args'});
+    }
+    &gsprintf(STDERR, "  </Arguments>\n");
+    &gsprintf(STDERR, "</Info>\n");
+}
+
+
+sub print_xml_header
+{
+    &gsprintf(STDERR, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+    &gsprintf(STDERR, "<!DOCTYPE Info [\n");
+    &gsprintf(STDERR, "  <!ELEMENT Info      (Name, Desc, Arguments)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT Arguments (Option*)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT Option    (Name, Desc, Type, Required, Range, Default?, List?)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT Name      (#PCDATA)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT Desc      (#PCDATA)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT Type      (#PCDATA)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT Required  (#PCDATA)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT Range     (#PCDATA)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT Default   (#PCDATA)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT List      (Value*)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT Value     (Name, Desc?)>\n");
+    &gsprintf(STDERR, "  <!ELEMENT HiddenGLI (#PCDATA)>\n");
+    &gsprintf(STDERR, "]>\n\n");
+}
+
+
+sub print_options_xml
+{
+    my $options = shift(@_);
+
+    foreach my $option (@$options) {
+	my $optionname = $option->{'name'};
+	my $optiondesc = &gsprintf::lookup_string($option->{'desc'});
+
+	# Escape '<' and '>' characters
+	$optiondesc =~ s/</&amp;lt;/g; # doubly escaped
+	$optiondesc =~ s/>/&amp;gt;/g;
+
+	# Display option name, description and type
+	&gsprintf(STDERR, "    <Option>\n");
+	&gsprintf(STDERR, "      <Name>$optionname</Name>\n");
+	&gsprintf(STDERR, "      <Desc>$optiondesc</Desc>\n");
+	&gsprintf(STDERR, "      <Type>$option->{'type'}</Type>\n");
+
+	# If the option has a required field, display this
+	if (defined($option->{'reqd'})) {
+	    &gsprintf(STDERR, "      <Required>$option->{'reqd'}</Required>\n");
+	}
+
+	# If the option has a charactor length field, display this
+	if (defined($option->{'char_length'})) {
+	    &gsprintf(STDERR, "      <CharactorLength>$option->{'char_length'}</CharactorLength>\n");
+	}
+
+	# If the option has a range field, display this
+	if (defined($option->{'range'})) {
+	    &gsprintf(STDERR, "      <Range>$option->{'range'}</Range>\n");
+	}
+
+	# If the option has a list of possible values, display these
+	if (defined $option->{'list'}) {
+	    &gsprintf(STDERR, "      <List>\n");
+	    my $optionvalueslist = $option->{'list'};
+	    foreach my $optionvalue (@$optionvalueslist) {
+		&gsprintf(STDERR, "        <Value>\n");
+		&gsprintf(STDERR, "          <Name>$optionvalue->{'name'}</Name>\n");
+		if (defined $optionvalue->{'desc'}) {
+		    my $optionvaluedesc = &gsprintf::lookup_string($optionvalue->{'desc'});
+
+		    # Escape '<' and '>' characters
+		    $optionvaluedesc =~ s/</&amp;lt;/g; #doubly escaped
+		    $optionvaluedesc =~ s/>/&amp;gt;/g;
+
+		    &gsprintf(STDERR, "          <Desc>$optionvaluedesc</Desc>\n");
+		}
+		&gsprintf(STDERR, "        </Value>\n");
+	    }
+
+#	    # Special case for 'input_encoding'
+#	    if ($optionname =~ m/^input_encoding$/i) {
+#		my $e = $encodings::encodings;
+#		foreach my $enc (sort {$e->{$a}->{'name'} cmp $e->{$b}->{'name'}} keys (%$e)) {
+#		    &gsprintf(STDERR, "        <Value>\n");
+#		    &gsprintf(STDERR, "          <Name>$enc</Name>\n");
+#		    &gsprintf(STDERR, "          <Desc>$e->{$enc}->{'name'}</Desc>\n");
+#		    &gsprintf(STDERR, "        </Value>\n");
+#		}
+#	    }
+
+	    &gsprintf(STDERR, "      </List>\n");
+	}
+
+	# Show the default value for the option, if there is one
+	if (defined $option->{'deft'}) {
+	    my $optiondeftvalue = $option->{'deft'};
+
+	    # Escape '<' and '>' characters
+	    $optiondeftvalue =~ s/</&amp;lt;/g; #doubly escaped
+	    $optiondeftvalue =~ s/>/&amp;gt;/g;
+
+	    &gsprintf(STDERR, "      <Default>$optiondeftvalue</Default>\n");
+	}
+
+	# If the option is noted as being hidden in GLI, add that to the printout
+	if (defined($option->{'hiddengli'})) {
+	    &gsprintf(STDERR, "      <HiddenGLI>$option->{'hiddengli'}</HiddenGLI>\n");
+	}
+	# If the argument is not hidden then print out the lowest detail mode it is visible in
+	if (defined($option->{'modegli'})) {
+	    &gsprintf(STDERR, "      <ModeGLI>$option->{'modegli'}</ModeGLI>\n");
+	}
+
+	&gsprintf(STDERR, "    </Option>\n");
+    }
+}
+
+
+sub print_txt_usage
+{
+    my $options = shift(@_);
+    my $params = shift(@_);
+    my $programdesc = shift(@_);
+
+    my $programname = $options->{'name'};
+    my $programargs = $options->{'args'};
+
+    # Find the length of the longest option string
+    my $descoffset = 0;
+    if (defined($programargs)) {
+	$descoffset = &find_longest_option_string($programargs);
+    }
+
+    # Produce the usage information using the data structure above
+    if ($programdesc) {
+	&gsprintf(STDERR, $programname . ": $options->{'desc'}\n\n");
+    }
+    &gsprintf(STDERR, " {common.usage}: $programname $params\n\n");
+
+    # Display the program options, if there are some
+    if (defined($programargs)) {
+	# Calculate the column offset of the option descriptions
+	my $optiondescoffset = $descoffset + 2;  # 2 spaces between options & descriptions
+
+	&gsprintf(STDERR, " {common.options}:\n");
+
+	# Display the program options
+	&print_options_txt($programargs, $optiondescoffset);
+    }
+}
+
+
+sub print_options_txt
+{
+    my $options = shift(@_);
+    my $optiondescoffset = shift(@_);
+
+    foreach my $option (@$options) {
+	# Display option name
+	my $optionname = $option->{'name'};
+	&gsprintf(STDERR, "  -$optionname");
+	my $optionstringlength = length("  -$optionname");
+
+	# Display option type, if the option is not a flag
+	my $optiontype = $option->{'type'};
+	if ($optiontype ne "flag") {
+	    &gsprintf(STDERR, " <$optiontype>");
+	    $optionstringlength = $optionstringlength + length(" <$optiontype>");
+	}
+
+	# Display the option description
+	my $optiondesc = &gsprintf::lookup_string($option->{'desc'});
+	my $optionreqd = $option->{'reqd'};
+	if (defined($optionreqd) && $optionreqd eq "yes") {
+	    $optiondesc = "(" . &gsprintf::lookup_string("{PrintUsage.required}") . ") " . $optiondesc;
+	}
+	&display_text_in_column($optiondesc, $optiondescoffset, $optionstringlength, 80);
+
+	# Show the default value for the option, if there is one
+	my $optiondefault = $option->{'deft'};
+	if (defined($optiondefault)) {
+	    &gsprintf(STDERR, " " x $optiondescoffset);
+	    &gsprintf(STDERR, "{PrintUsage.default}: $optiondefault\n");
+	}
+
+	# If the option has a list of possible values, display these
+	my $optionvalueslist = $option->{'list'};
+	if (defined($optionvalueslist)) {
+	    &gsprintf(STDERR, "\n");
+	    foreach my $optionvalue (@$optionvalueslist) {
+		my $optionvaluename = $optionvalue->{'name'};
+		&gsprintf(STDERR, " " x $optiondescoffset);
+		&gsprintf(STDERR, "$optionvaluename:");
+
+		my $optionvaluedesc = &gsprintf::lookup_string($optionvalue->{'desc'});
+		&display_text_in_column($optionvaluedesc, $optiondescoffset + 2,
+					$optiondescoffset + length($optionvaluename), 80);
+	    }
+	}
+
+#	# Special case for 'input_encoding'
+#	if ($optionname =~ m/^input_encoding$/i) {
+#	    my $e = $encodings::encodings;
+#	    foreach my $enc (sort {$e->{$a}->{'name'} cmp $e->{$b}->{'name'}} keys (%$e)) {
+#		&gsprintf(STDERR, " " x $optiondescoffset);
+#		&gsprintf(STDERR, "$enc:");
+#
+#		my $encodingdesc = $e->{$enc}->{'name'};
+#		&display_text_in_column($encodingdesc, $optiondescoffset + 2,
+#					$optiondescoffset + length("$enc:"), 80);
+#	    }
+#	}
+
+	# Add a blank line to separate options
+	&gsprintf(STDERR, "\n");
+    }
+}
+
+
+sub display_text_in_column
+{
+    my ($text, $columnbeg, $firstlineoffset, $columnend) = @_;
+
+    # Spaces are put *before* words, so treat the column beginning as 1 smaller than it is
+    $columnbeg = $columnbeg - 1;
+
+    # Add some padding (if needed) for the first line
+    my $linelength = $columnbeg;
+    if ($firstlineoffset < $columnbeg) {
+	&gsprintf(STDERR, " " x ($columnbeg - $firstlineoffset));
+    }
+    else {
+	$linelength = $firstlineoffset;
+    }
+
+    # Break the text into words, and display one at a time
+    my @words = split(/ /, $text);
+
+    foreach my $word (@words) {
+	# If printing this word would exceed the column end, start a new line
+	if (($linelength + length($word)) >= $columnend) {
+	    &gsprintf(STDERR, "\n");
+	    &gsprintf(STDERR, " " x $columnbeg);
+	    $linelength = $columnbeg;
+	}
+
+	# Write the word
+	&gsprintf(STDERR, " $word");
+	$linelength = $linelength + length(" $word");
+    }
+
+    &gsprintf(STDERR, "\n");
+}
+
+
+sub find_longest_option_string
+{
+    my $options = shift(@_);
+
+    my $maxlength = 0;
+    foreach my $option (@$options) {
+	my $optionname = $option->{'name'};
+	my $optiontype = $option->{'type'};
+
+	my $optionlength = length("  -$optionname");
+	if ($optiontype ne "flag") {
+	    $optionlength = $optionlength + length(" <$optiontype>");
+	}
+
+	# Remember the longest
+	if ($optionlength > $maxlength) {
+	    $maxlength = $optionlength;
+	}
+    }
+    return $maxlength;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/remproc.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/remproc.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/remproc.pm	(revision 10506)
@@ -0,0 +1,59 @@
+###########################################################################
+#
+# remproc.pm -- document processor used to cache all documents in memory
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package remproc;
+
+use classify;
+use doc;
+use docproc;
+
+BEGIN {
+    @remproc::ISA = ('docproc');
+}
+
+
+sub new {
+    my ($class) = @_;
+    my $self = {'docs'=>[]};
+
+    return bless $self, $class;
+}
+
+sub process {
+    my $self = shift (@_);
+    my ($doc_obj, $filename) = @_;
+
+    push (@{$self->{'docs'}}, {'doc_obj'=>$doc_obj,
+			       'filename'=>$filename});
+}
+
+sub get_doc_list {
+    my $self = shift (@_);
+
+    return $self->{'docs'};
+}
+
+1;
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/scriptutil.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/scriptutil.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/scriptutil.pm	(revision 10506)
@@ -0,0 +1,62 @@
+###########################################################################
+#
+# scriptutil.pm -- various useful utilities for the scripts
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package scriptutil;
+no strict 'subs'; # allow barewords (eg STDERR) as function arguments
+no strict 'refs'; # ...but allow filehandles to be variables and vice versa
+
+use gsprintf 'gsprintf';
+
+# returns $removeold, $keepold
+sub check_removeold_and_keepold {
+
+    my ($removeold, $keepold, $dir, $collectcfg) = @_;
+
+    if ($keepold && $removeold) {
+	gsprintf(STDERR, "{scripts.both_old_options}\n", $dir);
+	sleep(3); #just in case
+	return (1,0); 
+	
+    } 
+
+    if (!$keepold && !$removeold) {
+	# we only look at config file options if we dont have these on the command line
+	if (defined $collectcfg->{'removeold'} && $collectcfg->{'removeold'} =~ /^true$/i ) {
+	    $removeold = 1;
+	} elsif (defined $collectcfg->{'keepold'} && $collectcfg->{'keepold'} =~ /^true$/i) {
+	    $keepold = 1;
+	}
+    }
+    if (!$keepold && !$removeold) {
+	gsprintf(STDERR, "{scripts.no_old_options} \n", $dir);
+	sleep(3); #just in case
+	return (1,0);
+    }
+    
+    return ($removeold, $keepold);
+
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/sorttools.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/sorttools.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/sorttools.pm	(revision 10506)
@@ -0,0 +1,195 @@
+###########################################################################
+#
+# sorttools.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# various subroutines to format strings
+# for sorting
+
+package sorttools;
+
+# moved here from BasClas so import can share it
+sub format_metadata_for_sorting {
+    my ($metaname, $metavalue, $doc_obj) = @_;
+    if (!defined $metaname || $metaname !~ /\S/ || ! defined $metavalue || $metavalue !~ /\S/) {
+	return "";
+    }
+
+    if ($metaname eq "Language") {
+	$metavalue = $iso639::fromiso639{$metavalue};
+	return $metavalue;
+    } 
+    
+    my $lang;
+    if (defined $doc_obj) {
+	$lang = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), 'Language');
+    }
+    $lang = 'en' unless defined $lang;
+    
+    # is this metadata likely to be a name?
+    my $function_name="format_string_name_$lang";
+    if ($metaname =~ /^(?:\w+\.)?(?:Creator|Author|Editor)(?::.*)?$/
+	&& exists &$function_name) {
+	no strict 'refs';
+	&$function_name(\$metavalue);
+    } else {
+	$function_name="format_string_$lang";
+	if (exists &$function_name) {
+	    no strict 'refs';
+	    &$function_name(\$metavalue);
+	}
+    }
+    
+    return $metavalue;
+}
+
+### language-specific sorting functions (called by format_metadata_for_sorting)
+
+## format_string_$lang() converts to lowercase (where appropriate), and
+# removes punctuation, articles from the start of string, etc
+## format_string_name_$lang() converts to lowercase, puts the surname first,
+# removes punctuation, etc
+
+sub format_string_en {
+    my $stringref = shift;
+    $$stringref = lc($$stringref);
+    $$stringref =~ s/&[^\;]+\;//g; # html entities
+    $$stringref =~ s/^\s*(the|a|an)\b//; # articles
+    $$stringref =~ s/[^[:alnum:]]//g;
+    $$stringref =~ s/\s+/ /g;
+    $$stringref =~ s/^\s+//;
+    $$stringref =~ s/\s+$//;
+}
+
+sub format_string_name_en {
+    my ($stringref) = @_;
+
+    $$stringref =~ tr/A-Z/a-z/;
+    $$stringref =~ s/&\S+;//g;
+
+    my $comma_format = ($$stringref =~ m/^.+,.+$/);
+    $$stringref =~ s/[[:punct:]]//g;
+    $$stringref =~ s/\s+/ /g;
+    $$stringref =~ s/^\s+//;
+    $$stringref =~ s/\s+$//;
+
+    
+    if (!$comma_format) {
+	# No commas in name => name in 'firstname surname' format
+	# need to sort by surname
+	my @names = split / /, $$stringref;
+	my $surname = pop @names;
+	while (scalar @names && $surname =~ /^(jnr|snr)$/i) {
+	    $surname = pop @names;
+	}
+	$$stringref = $surname . " " . $$stringref;
+    }
+}
+
+
+sub format_string_fr {
+    my $stringref = shift;
+
+    $$stringref = lc($$stringref);
+    $$stringref =~ s/&[^\;]+\;//g; # html entities
+    $$stringref =~ s/[^[:alpha:]]//g;
+    $$stringref =~ s/^\s*(les?|la|une?)\b//; # articles
+    $$stringref =~ s/\s+/ /g;
+    $$stringref =~ s/^\s+//;
+    $$stringref =~ s/\s+$//;
+}
+
+sub format_string_es {
+    my $stringref = shift;
+
+    $$stringref = lc($$stringref);
+    $$stringref =~ s/&[^\;]+\;//g; # html entities
+    $$stringref =~ s/[^[:alpha:]]//g;
+    $$stringref =~ s/^\s*(la|el)\b//; # articles
+    $$stringref =~ s/\s+/ /g;
+    $$stringref =~ s/^\s+//;
+    $$stringref =~ s/\s+$//;
+}
+
+### end of language-specific functions
+
+# takes arguments of day, month, year and converts to
+# date of form yyyymmdd. month may be full (e.g. "January"),
+# abbreviated (e.g. "Jan"), or a number (1-12). Years like "86" 
+# will be assumed to be "1986".
+sub format_date {
+    my ($day, $month, $year) = @_;
+
+    my %months = ('january' => '01', 'jan' => '01', 'february' => '02', 'feb' => '02',
+		  'march' => '03', 'mar' => '03', 'april' => '04', 'apr' => '04',
+		  'may' => '05', 'june' => '06', 'jun' => '06', 'july' => '07', 
+		  'jul' => '07', 'august' => '08', 'aug' => '08', 'september' => '09', 
+		  'sep' => '09', 'october' => '10', 'oct' => '10', 'november' => '11', 
+		  'nov' => '11', 'december' => '12', 'dec' => '12');
+
+    $month =~ tr/A-Z/a-z/;
+    
+    if ($day < 1) { 
+	print STDERR "sorttools::format_date WARNING day $day out of range\n";
+	$day = "01";
+    } elsif ($day > 31) {
+	print STDERR "sorttools::format_date WARNING day $day out of range\n";
+	$day = "31";
+    }
+
+    $day = "0$day" if (length($day) == 1);
+
+    if ($month =~ /^\d\d?$/) {
+	if ($month < 1) {
+	    print STDERR "sorttools::format_date WARNING month $month out of range\n";
+	    $month = "01";
+	} elsif ($month > 12) {
+	    print STDERR "sorttools::format_date WARNING month $month out of range\n";
+	    $month = "12";
+	}
+	if ($month =~ /^\d$/) {
+	    $month = "0" . $month;
+	}
+    } elsif (!defined $months{$month}) {
+	print STDERR "sorttools::format_date WARNING month $month out of range\n";
+	$month = "01";
+    } else {
+	$month = $months{$month};
+    }
+    
+    if ($year !~ /^\d\d\d\d$/) {
+	if ($year !~ /^\d\d$/) {
+	    my $newyear = 1900 + $year;
+	    print STDERR "sorttools::format_date WARNING year $year assumed to be $newyear\n";
+	    $year=$newyear;
+	} else {
+	    print STDERR "sorttools::format_date WARNING year $year out of range - reset to 1900\n";
+	    $year = "1900";
+	}
+    }
+
+    return "$year$month$day";
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/strings.rb
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/strings.rb	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/strings.rb	(revision 10506)
@@ -0,0 +1,929 @@
+#
+# Resource bundle description
+#
+
+Language.code:en
+Language.name:English
+
+OutputEncoding.unix:iso_8859_1
+OutputEncoding.windows:iso_8859_1
+
+
+#
+# Common output messages
+#
+
+common.cannot_create_file:ERROR: Can't create file %s
+
+common.cannot_find_cfg_file:ERROR: Can't find the configuration file %s
+
+common.cannot_open:ERROR: Can't open %s
+
+common.cannot_open_fail_log:ERROR: Can't open fail log %s
+
+common.cannot_open_output_file:ERROR: Can't open output file %s
+
+common.cannot_read:ERROR: Can't read %s
+
+common.cannot_read_file:ERROR: Can't read file %s
+
+common.general_options:general options (for %s)
+
+common.must_be_implemented:function must be implemented in sub-class
+
+common.options:options
+
+common.processing:processing
+
+common.specific_options:specific options
+
+common.usage:Usage
+
+
+#
+# Script option descriptions and output messages
+#
+
+scripts.language:Language to display option descriptions in (eg. 'en_US' specifies American English). Requires translations of the option descriptions to exist in the perllib/strings_language-code.rb file.
+
+scripts.xml:Produces the information in an XML form, without 'pretty' comments but with much more detail.
+
+scripts.listall:Lists all items known about.
+
+scripts.both_old_options:WARNING: Both -removeold and -keepold were specified, defaulting to -removeold. Current contents of %s directory will be deleted.
+
+scripts.no_old_options:WARNING: Neither -removeold or -keepold were specified, defaulting to -removeold. Current contents of %s directory will be deleted.
+
+# -- buildcol.pl --
+
+buildcol.archivedir:Where the archives live.
+
+buildcol.builddir:Where to put the built indexes.
+
+buildcol.cachedir:Collection will be temporarily built here before being copied to the build directory.
+
+buildcol.cannot_open_cfg_file:WARNING: Can't open config file for updating: %s
+
+buildcol.collectdir:Collection directory.
+
+buildcol.copying_back_cached_build:Copying back the cached build
+
+buildcol.create_images:Attempt to create default images for new collection. This relies on the Gimp being installed along with relevant perl modules to allow scripting from perl.
+
+buildcol.debug:Print output to STDOUT.
+
+buildcol.desc:PERL script used to build a greenstone collection from GML documents.
+
+buildcol.faillog:Fail log filename. This log receives the filenames of any files which fail to be processed.
+
+buildcol.index:Index to build (will build all in config file if not set).
+
+buildcol.keepold:Will not destroy the current contents of the building directory.
+
+buildcol.maxdocs:Maximum number of documents to build.
+
+buildcol.mode:The parts of the building process to carry out.
+buildcol.mode.all:Do everything.
+buildcol.mode.build_index:Just index the text.
+buildcol.mode.compress_text:Just compress the text.
+buildcol.mode.infodb:Just build the metadata database.
+
+buildcol.no_default_images:Default images will not be generated.
+
+buildcol.no_image_script:WARNING: Image making script could not be found: %s
+
+buildcol.no_strip_html:Do not strip the html tags from the indexed text (only used for mgpp collections).
+
+buildcol.no_text:Don't store compressed text. This option is useful for minimizing the size of the built indexes if you intend always to display the original documents at run time (i.e. you won't be able to retrieve the compressed text version).
+
+buildcol.sections_index_document_metadata:Index document level metadata at section level
+buildcol.sections_index_document_metadata.never:Don't index any document metadata at section level.
+buildcol.sections_index_document_metadata.always:Add all specified document level metadata even if section level metadata of that name exists.
+buildcol.sections_index_document_metadata.unless_section_metadata_exists:Only add document level metadata if no section level metadata of that name exists.
+
+buildcol.out:Filename or handle to print output status to.
+
+buildcol.params:[options] collection-name
+
+buildcol.remove_empty_classifications:Hide empty classifiers and classification nodes (those that contain no documents).
+
+buildcol.removeold:Will remove the old contents of the building directory.
+
+buildcol.unlinked_col_images:Collection images may not be linked correctly.
+
+buildcol.unknown_mode:Unknown mode: %s
+
+buildcol.updating_archive_cache:Updating archive cache
+
+buildcol.verbosity:Controls the quantity of output. 0=none, 3=lots.
+
+
+# -- classinfo.pl --
+
+classinfo.collect:Giving a collection name will make classinfo.pl look in collect/collection-name/perllib/classify first. If the classifier is not found there it will look in the general perllib/classify directory.
+
+classinfo.desc:Prints information about a classifier.
+
+classinfo.general_options:General options are inherited from parent classes of the classifier.
+
+classinfo.info:info
+
+classinfo.no_classifier_name:ERROR: You must provide a classifier name.
+
+classinfo.option_types:Classifiers may take two types of options
+
+classinfo.params:[options] classifier-name
+
+classinfo.passing_options:Options may be passed to any classifier by including them in your collect.cfg configuration file.
+
+classinfo.specific_options:Specific options are defined within the classifier itself, and are available only to this particular classifier.
+
+# -- explode_metadata_database.pl --
+explode.desc:Explode a metadata database
+
+explode.document_field:The metadata element specifying the file name of documents to obtain and include in the collection.
+
+explode.document_prefix:A prefix for the document locations (for use with the document_field option).
+
+explode.document_suffix:A suffix for the document locations (for use with the document_field option).
+
+explode.encoding:Encoding to use when reading in the database file
+explode.filename_field:Field to use for filenames for the generated null files (if no document_field or that field is empty)
+explode.metadata_set:Metadata set (namespace) to export all metadata as
+explode.plugin: Plugin to use for exploding
+explode.params: [options] filename
+# -- exportcol.pl --
+
+exportcol.out:Filename or handle to print output status to.
+exportcol.cddir:The name of the directory that the CD contents are exported to.
+exportcol.cdname:The name of the CD-ROM -- this is what will appear in the start menu once the CD-ROM is installed.
+exportcol.desc:PERL script used to export one or more collections to a Windows CD-ROM. 
+exportcol.params:[options] collection-name1 collection-name2 ...
+exportcol.coll_not_found:Ignoring invalid collection %s: collection not found at %s.
+exportcol.coll_dirs_not_found:Ignoring invalid collection %s: one of the following directories not found:
+exportcol.fail:exportcol.pl failed:
+exportcol.no_valid_colls:No valid collections specified to export.
+exportcol.couldnt_create_dir:Could not create directory %s.
+exportcol.couldnt_create_file:Could not create %s.
+exportcol.instructions:To create a self-installing Windows CD-ROM, write the contents of this folder out to a CD-ROM.
+exportcol.non_exist_files:One or more of the following necessary files and directories does not exist:
+exportcol.success:exportcol.pl succeeded:
+exportcol.output_dir:The exported collections (%s) are in %s.
+exportcol.nonetscape:Do not bundle netscape with exported CD-ROM.
+exportcol.export_coll_not_installed:The Export to CD-ROM functionality has not been installed.
+
+# -- import.pl --
+
+import.archivedir:Where the converted material ends up.
+
+import.cannot_open_stats_file:WARNING: Couldn't open stats file %s.
+
+import.cannot_open_fail_log:ERROR: Couldn't open fail log %s
+
+import.cannot_sort:WARNING: import.pl cannot sort documents when groupsize > 1. sortmeta option will be ignored.
+
+import.collectdir:Collection directory.
+
+import.complete:Import complete
+
+import.debug:Print imported text to STDOUT.
+
+import.desc:PERL script used to import files into a GML format ready for building.
+
+import.faillog:Fail log filename. This log receives the filenames of any files which fail to be processed.
+
+import.groupsize:Number of import documents to group into one XML file.
+
+import.gzip:Use gzip to compress resulting xml documents (don't forget to include ZIPPlug in your plugin list when building from compressed documents).
+
+import.importdir:Where the original material lives.
+
+import.keepold:Will not destroy the current contents of the archives directory.
+
+import.maxdocs:Maximum number of documents to import.
+
+import.no_plugins_loaded:ERROR: No plugins loaded.
+
+import.OIDtype:The method to use when generating unique identifiers for each document.
+import.OIDtype.hash:Hashes the contents of the file. Document identifier will be the same every time the collection is imported.
+
+import.OIDtype.incremental:A simple document count that is significantly faster than "hash". It is not guaranteed to always assign the same identifier to a given document though and does not allow further documents to be added to existing xml archives.
+
+import.OIDtype.assigned:Uses 'D' plus the value of dc.Identifier as the document identifier. dc.Identifiers should be unique. If no dc.Identifier is assigned to the document, a hash id will be used instead.
+
+import.OIDtype.dirname:Uses 'J' plus the parent directory name as the identifier. This relies on there being only one document per directory, and all directory names being unique. E.g. import/b13as/h15ef/page.html will get an identifier of Jh15ef.
+
+import.saveas:This is to decide the archives format to be generated. The default setting is to GA.
+
+import.saveas.GA:Will generate Greenstone Archive format.
+
+import.saveas.METS:Will generate METS format.
+
+import.out:Filename or handle to print output status to.
+
+import.params:[options] collection-name
+
+import.removeold:Will remove the old contents of the archives directory.
+
+import.removing_archives:Removing current contents of the archives directory...
+
+import.removing_tmpdir:Removing contents of the collection "tmp" directory...
+
+import.sortmeta:Sort documents alphabetically by metadata for building. Search results for boolean queries will be displayed in this order. This will be disabled if groupsize > 1.
+
+import.statsfile:Filename or handle to print import statistics to.
+
+import.stats_backup:Will print stats to STDERR instead.
+
+import.verbosity:Controls the quantity of output. 0=none, 3=lots.
+
+
+# -- export.pl --
+
+export.exportdir:Where the export material ends up.
+
+export.cannot_open_stats_file:WARNING: Couldn't open stats file %s.
+
+export.cannot_open_fail_log:ERROR: Couldn't open fail log %s
+
+export.cannot_sort:WARNING: export.pl cannot sort documents when groupsize > 1. sortmeta option will be ignored.
+
+export.collectdir:Collection directory.
+
+export.complete:Export complete
+
+export.debug:Print exported text to STDOUT.
+
+export.desc:PERL script used to export files in a Greenstone collection to another format.
+
+export.faillog:Fail log filename. This log receives the filenames of any files which fail to be processed. (Default: collectdir/collect/collname/etc/fail.log)
+
+export.groupsize:Number of documents to group into one XML file.
+
+export.gzip:Use gzip to compress resulting xml documents (don't forget to include ZIPPlug in your plugin list when building from compressed documents).
+
+export.importdir:Where the original material lives.
+
+export.keepold:Will not destroy the current contents of the export directory. 
+
+export.maxdocs:Maximum number of documents to export.
+
+export.no_plugins_loaded:ERROR: No plugins loaded.
+
+export.OIDtype:The method to use when generating unique identifiers for each document.
+export.OIDtype.hash:Hashes the contents of the file. Document identifier will be the same every time the collection is imported.
+export.OIDtype.incremental:A simple document count that is significantly faster than "hash". It is not guaranteed to always assign the same identifier to a given document though and does not allow further documents to be added to existing xml archives.
+
+export.saveas:Format to export documents as.
+
+export.saveas.DSpace:DSpace Archive format.
+
+export.saveas.METS:METS format using the Greenstone profile.
+
+export.out:Filename or handle to print output status to.
+
+export.params:[options] collection-name1, collection-name2...
+
+export.removeold:Will remove the old contents of the export directory. 
+
+export.removing_export:Removing current contents of the export directory...
+
+export.sortmeta:Sort documents alphabetically by metadata for building. This will be disabled if groupsize > 1.
+
+export.statsfile:Filename or handle to print export statistics to.
+
+export.stats_backup:Will print stats to STDERR instead.
+
+export.verbosity:Controls the quantity of output. 0=none, 3=lots.
+
+
+# -- mkcol.pl --
+
+mkcol.about:The about text for the collection.
+
+mkcol.bad_name_cvs:ERROR: No collection can be named CVS as this may interfere with directories created by the CVS versioning system.
+
+mkcol.bad_name_modelcol:ERROR: No collection can be named modelcol as this is the name of the model collection.
+
+mkcol.cannot_find_modelcol:ERROR: Cannot find the model collection %s
+
+mkcol.col_already_exists:ERROR: This collection already exists.
+
+mkcol.collectdir:Directory where new collection will be created.
+
+mkcol.creating_col:Creating the collection %s
+
+mkcol.creator:The collection creator's e-mail address.
+
+mkcol.creator_undefined:ERROR: The creator was not defined. This variable is needed to recognise duplicate collection names.
+
+mkcol.desc:PERL script used to create the directory structure for a new Greenstone collection.
+
+mkcol.doing_replacements:doing replacements for %s
+
+mkcol.long_colname:ERROR: The collection name must be less than 8 characters so compatibility with earlier filesystems can be maintained.
+
+mkcol.maintainer:The collection maintainer's email address (if different from the creator).
+
+mkcol.no_collectdir:ERROR: The collect dir doesn't exist: %s
+
+mkcol.no_colname:ERROR: No collection name was specified.
+
+mkcol.optionfile:Get options from file, useful on systems where long command lines may cause problems.
+
+mkcol.params:[options] collection-name
+
+mkcol.plugin:Perl plugin module to use (there may be multiple plugin entries).
+
+mkcol.public:If this collection has anonymous access (true/false).
+
+mkcol.quiet:Operate quietly.
+
+mkcol.success:The new collection was created successfully at %s
+
+mkcol.title:The title of the collection.
+
+mkcol.win31compat:Whether or not the named collection directory must conform to Windows 3.1 file conventions or not (i.e. 8 characters long).
+
+# -- pluginfo.pl --
+
+pluginfo.collect:Giving a collection name will make pluginfo.pl look in collect/collection-name/perllib/plugins first. If the plugin is not found there it will look in the general perllib/plugins directory.
+
+pluginfo.desc:Prints information about a plugin.
+
+pluginfo.general_options:General options are inherited from parent classes of the plugin.
+
+pluginfo.info:info
+
+pluginfo.no_plugin_name:ERROR: You must provide a plugin name.
+
+pluginfo.option_types:Plugins may take two types of options
+
+pluginfo.params:[options] plugin-name
+
+pluginfo.passing_options:Options may be passed to any plugin by including them in your collect.cfg configuration file.
+
+pluginfo.specific_options:Specific options are defined within the plugin itself, and are available only to this particular plugin.
+
+
+#
+# Classifier option descriptions
+#
+
+AZCompactList.allvalues:Use all metadata values found.
+
+AZCompactList.desc:Classifier plugin for sorting alphabetically
+
+AZCompactList.doclevel:Level to process document at.
+AZCompactList.doclevel.top:Whole document.
+AZCompactList.doclevel.section:By sections.
+
+AZCompactList.firstvalueonly:Use only the first metadata value found.
+
+AZCompactList.freqsort:Sort by node frequency rather than alpha-numeric.
+
+AZCompactList.maxcompact:Maximum number of documents to be displayed per page.
+
+AZCompactList.metadata:A single Metadata field, or a comma separated list of Metadata fields, used for classification. If a list is specified, the first metadata type that has values will be used. May be used in conjunction with the -firstvalueonly and -allvalues flags, to select only the first value, or all metadata values from the list.
+
+AZCompactList.mincompact:Minimum number of documents to be displayed per page.
+
+AZCompactList.mingroup:The smallest value that will cause a group in the hierarchy to form.
+
+AZCompactList.minnesting:The smallest value that will cause a list to be converted into a nested list.
+
+AZCompactList.recopt:Used in nested metadata such as -metadata Year/Organisation.
+AZCompactList.sort:Metadata field to sort the leaf nodes by. 
+
+AZCompactSectionList.desc:Variation on AZCompactList that classifies sections rather than documents. Entries are sorted by section-level metadata.
+
+AZList.desc:Classifier plugin for sorting alphabetically
+
+AZList.metadata:A single Metadata field or a comma separated list of Metadata fields used for classification. Following the order indicated by the list, the first field that contains a Metadata value will be used. List will be sorted by this element.
+
+AZSectionList.desc:Classifier plugin for sorting alphabetically. This is very similar to AZList except it sorts by section level metadata (excluding the top level) instead of just top level metadata. The only change is to the classify() subroutine which must now iterate through each section, adding each to the classification.
+
+BasClas.bad_general_option:The %s classifier uses an incorrect general option (general options are those available to all classifiers). Check your collect.cfg configuration file.
+
+BasClas.builddir:Where to put the built indexes.
+
+BasClas.buttonname:The label for the classifier screen and button in navigation bar. The default is the metadata element specified with -metadata.
+
+BasClas.desc:Base class for all the classifiers.
+
+BasClas.outhandle:The file handle to write output to.
+
+BasClas.removeprefix:A prefix to ignore in metadata values when sorting.
+
+BasClas.removesuffix:A suffix to ignore in metadata values when sorting.
+
+BasClas.verbosity:Controls the quantity of output. 0=none, 3=lots.
+
+Browse.desc:.
+
+DateList.bymonth:Classify by year and month instead of only year.
+
+DateList.desc:Classifier plugin for sorting by date. By default, sorts by 'Date' metadata. Date is assumed to be in the form yyyymmdd.
+
+DateList.metadata:The metadata that contains the dates to classify by. The format is expected to be yyyymmdd.
+
+DateList.reverse_sort:Sort the documents in reverse chronological order (newest first).
+
+DateList.nogroup:Make each year an individual entry in the horizontal list, instead of spanning years with few entries. (This can also be used with the -bymonth option to make each month a separate entry instead of merging).
+
+DateList.sort:An extra metadata field to sort by in the case where two documents have the same date.
+
+GenericList.always_bookshelf_last_level:Create a bookshelf icon even if there is only one item in each group at the leaf nodes.
+GenericList.classify_sections:Classify sections instead of documents.
+GenericList.desc:A general and flexible list classifier with most of the abilities of AZCompactList, but with better Unicode, metadata and sorting capabilities.
+GenericList.metadata:Metadata fields used for classification. Use '/' to separate the levels in the hierarchy and ';' to separate metadata fields within each level.
+GenericList.partition_size_within_level:The number of items in each partition (only applies when partition_type_within_level is set to 'constant_size').
+GenericList.partition_type_within_level:The type of partitioning done: either 'per_letter', 'constant_size', or 'none'.
+GenericList.sort_leaf_nodes_using:Metadata fields used for sorting the leaf nodes. Use '|' to separate the metadata groups to stable sort and ';' to separate metadata fields within each group.
+GenericList.use_hlist_for:Metadata fields to use a hlist rather than a vlist. Use ',' to separate the metadata groups and ';' to separate the metadata fields within each group.
+
+HFileHierarchy.desc:Classifier plugin for generating hierarchical classifications based on a supplementary structure file.
+
+Hierarchy.desc:Classifier plugin for generating a hierarchical classification. This may be based on structured metadata, or may use a supplementary structure file (use the -hfile option).
+
+Hierarchy.hfile:Use the specified classification structure file.
+
+Hierarchy.hlist_at_top:Display the first level of the classification horizontally.
+
+Hierarchy.reverse_sort:Sort leaf nodes in reverse order (use with -sort).
+
+Hierarchy.separator:Regular expression used for the separator, if using structured metadata.
+
+Hierarchy.sort:Metadata field to sort leaf nodes by. Leaves will not be sorted if not specified.
+
+Hierarchy.suppresslastlevel:Ignore the final part of the metadata value. This is useful for metadata where each value is unique, such as file paths.
+
+HTML.desc:Creates an empty classification that's simply a link to a web page.
+
+HTML.url:The url of the web page to link to.
+
+List.desc:Simple list classifier plugin. 
+
+List.metadata:A single Metadata field or a comma separated list of Metadata fields used for classification. Following the order indicated by the list, the first field that contains a Metadata value will be used. List will be sorted by this element, unless -sort is used. If no metadata is specified, then all documents will be included in the list, otherwise only documents that contain a metadata value will be included.
+
+List.sort:Metadata field to sort by. Use '-sort nosort' for no sorting. 
+
+Phind.desc:The Phind clasifier plugin.
+
+Phind.language:Language or languages to use building hierarchy. Languages are identified by two-letter country codes like en (English), es (Spanish), and fr (French). Language is a regular expression, so 'en|fr' (English or French) and '..' (match any language) are valid.
+
+Phind.min_occurs:The minimum number of times a phrase must appear in the text to be included in the phrase hierarchy.
+
+Phind.savephrases:If set, the phrase infomation will be stored in the given file as text. It is probably a good idea to use an absolute path.
+
+Phind.suffixmode:The smode parameter to the phrase extraction program. A value of 0 means that stopwords are ignored, and of 1 means that stopwords are used.
+
+Phind.text:The text used to build the phrase hierarchy.
+
+Phind.thesaurus:Name of a thesaurus stored in Phind format in the collection's etc directory.
+
+Phind.title:The metadata field used to describe each document.
+
+Phind.untidy:Don't remove working files.
+
+SectionList.desc:Same as List classifier but includes all sections of document (excluding top level) rather than just top level document itself.
+
+Collage.desc:The Collage classifier plugin.
+
+Collage.geometry:The dimensions of the Collage canvas. For a canvas 600 pixels wide by 400 pixels high, for example, specify geometry as 600x400
+
+Collage.maxDepth:Images for collaging are drawn from mirroring the underlying browse classifier. This controls the maximum depth of the mirroring process.
+
+Collage.maxDisplay:The maximum number of images to show in the collage at any one time.
+
+Collage.imageType:Used to control, by expressing file name extensions, which file types are used in the collage.  A list of file name extensions is separated by the percent (%%) symbol.
+
+Collage.bgcolor:The background color of the collage canvas, specified in hexadecimal form (for example #008000 results in a forest green background).
+
+Collage.buttonname:The label for the classifier screen and button in navigation bar.
+
+Collage.refreshDelay:Rate, in milliseconds, that the collage canvas is refreshed.
+
+Collage.isJava2:Used to control which run-time classes of Java are used. More advanced version of Java (i.e. Java 1.2 onwards) include more sophisticated support for controlling transparency in images, this flag helps control what happens, however the built-in Java runtime for some browsers is version 1.1.  The applet is designed to, by default, auto-detect which version of Java the browser is running and act accordingly.
+
+Collage.imageMustNotHave:Used to suppress images that should not appear in the collage, such as image buttons that make up the navigation bar.
+
+Collage.caption:Optional captions to display below the collage canvas.
+
+#
+# Plugin option descriptions
+#
+
+ArcPlug.desc:Plugin which recurses through an archives.inf file (i.e. the file generated in the archives directory when an import is done), processing each file it finds.
+
+BasPlug.adding:adding
+
+BasPlug.already_seen:already seen
+
+BasPlug.bad_general_option:The %s plugin uses an incorrect general option (general options are those available to all plugins). Check your collect.cfg configuration file.
+
+BasPlug.block_exp:Files matching this regular expression will be blocked from being passed to any later plugins in the list. This has no real effect other than to prevent lots of warning messages about input files you don't care about. Each plugin might have a default block_exp. e.g. by default HTMLPlug blocks any files with .gif, .jpg, .jpeg, .png or .css file extensions.
+
+BasPlug.associate_ext:Causes files with the same root filename as the document being processed by the plugin AND a filename extension from the comma separated list provided by this argument to be associated with the document being processed rather than handled as a separate list.
+
+BasPlug.could_not_extract_encoding:WARNING: encoding could not be extracted from %s - defaulting to %s
+
+BasPlug.could_not_extract_language:WARNING: language could not be extracted from %s - defaulting to %s
+
+BasPlug.could_not_open_for_reading:could not open %s for reading
+
+BasPlug.no_cover_image:Do not look for a prefix.jpg file (where prefix is the same prefix as the file being processed) and associate it as a cover image.
+
+BasPlug.default_encoding:Use this encoding if -input_encoding is set to 'auto' and the text categorization algorithm fails to extract the encoding or extracts an encoding unsupported by Greenstone. This option can take the same values as -input_encoding.
+
+BasPlug.default_language:If Greenstone fails to work out what language a document is the 'Language' metadata element will be set to this value. The default is 'en' (ISO 639 language symbols are used: en = English). Note that if -input_encoding is not set to 'auto' and -extract_language is not set, all documents will have their 'Language' metadata set to this value.
+
+BasPlug.desc:Base class for all the import plugins.
+
+BasPlug.done_acronym_extract:done extracting acronyms.
+
+BasPlug.done_acronym_markup:done acronym markup.
+
+BasPlug.done_email_extract:done extracting e-mail addresses.
+
+BasPlug.dummy_text:This document has no text.
+
+BasPlug.empty_file:file contains no text
+
+BasPlug.extract_acronyms:Extract acronyms from within text and set as metadata.
+
+BasPlug.extract_email:Extract email addresses as metadata.
+
+BasPlug.extract_historical_years:Extract time-period information from historical documents.  This is stored as metadata with the document. There is a search interface for this metadata, which you can include in your collection by adding the statement, "format QueryInterface DateSearch" to your collection configuration file.
+
+BasPlug.extract_language:Identify the language of each document and set 'Language' metadata. Note that this will be done automatically if -input_encoding is 'auto'.
+
+BasPlug.extracting:extracting
+
+BasPlug.extracting_acronyms:extracting acronyms
+
+BasPlug.extract_keyphrases:Extract keyphrases automatically with Kea (default settings).
+
+BasPlug.extract_keyphrase_options:Options for keyphrase extraction with Kea. For example: mALIWEB - use ALIWEB extraction model; n5 - extract 5 keyphrase;, eGBK - use GBK encoding.
+
+BasPlug.extracting_emails:extracting e-mail addresses
+
+BasPlug.file_has_no_text:ERROR: %s contains no text
+
+BasPlug.first:Comma separated list of first sizes to extract from the text into a metadata field. The field is called 'FirstNNN'.
+
+BasPlug.input_encoding:The encoding of the source documents. Documents will be converted from these encodings and stored internally as utf8.
+BasPlug.input_encoding.ascii:Plain 7 bit ascii. This may be a bit faster than using iso_8859_1. Beware of using this on a collection of documents that may contain characters outside the plain 7 bit ascii set though (e.g. German or French documents containing accents), use iso_8859_1 instead.
+BasPlug.input_encoding.auto:Use text categorization algorithm to automatically identify the encoding of each source document. This will be slower than explicitly setting the encoding but will work where more than one encoding is used within the same collection.
+
+BasPlug.input_encoding.unicode:Just unicode.
+
+BasPlug.input_encoding.utf8:Either utf8 or unicode -- automatically detected.
+
+BasPlug.keyphrases:keyphrases
+
+BasPlug.marking_up_acronyms:marking up acronyms
+
+BasPlug.markup_acronyms:Add acronym metadata into document text.
+
+BasPlug.maximum_century:The maximum named century to be extracted as historical metadata (e.g. 14 will extract all references up to the 14th century).
+
+BasPlug.maximum_year:The maximum historical date to be used as metadata (in a Common Era date, such as 1950).
+
+BasPlug.must_be_implemented:BasPlug::read function must be implemented in sub-class for recursive plugins
+
+BasPlug.no_bibliography:Do not try to block bibliographic dates when extracting historical dates.
+
+BasPlug.process_exp:A perl regular expression to match against filenames. Matching filenames will be processed by this plugin. For example, using '(?i).html?\$' matches all documents ending in .htm or .html (case-insensitive).
+
+BasPlug.read_denied:Read permission denied for %s
+
+BasPlug.separate_cjk:Insert spaces between Chinese/Japanese/Korean characters to make each character a word. Use if text is not segmented.
+
+BasPlug.smart_block:Block files in a smarter way than just looking at filenames.
+
+BasPlug.stems:stems
+
+BasPlug.unsupported_encoding:WARNING: %s appears to be encoded in an unsupported encoding (%s) - using %s
+
+BasPlug.wrong_encoding:WARNING: %s was read using %s encoding but appears to be encoded as %s.
+
+BibTexPlug.desc:BibTexPlug reads bibliography files in BibTex format. BibTexPlug creates a document object for every reference in the file. It is a subclass of SplitPlug, so if there are multiple records, all are read.
+
+BookPlug.desc:Creates multi-level document from document containing <<TOC>> level tags. Metadata for each section is taken from any other tags on the same line as the <<TOC>>. e.g. <<Title>>xxxx<</Title>> sets Title metadata. Everything else between TOC tags is treated as simple html (i.e. no processing of html links or any other HTMLPlug type stuff is done). Expects input files to have a .hb file extension by default (this can be changed by adding a -process_exp option a file with the same name as the hb file but a .jpg extension is taken as the cover image (jpg files are blocked by this plugin). BookPlug is a simplification (and extension) of the HBPlug used by the Humanity Library collections. BookPlug is faster as it expects the input files to be cleaner (The input to the HDL collections contains lots of excess html tags around <<TOC>> tags, uses <<I>> tags to specify images, and simply takes all text between <<TOC>> tags and start of text to be Title metadata). If you're marking up documents to be displayed in the same way as the HDL collections, use this plugin instead of HBPlug.
+
+BRSPlug.desc: BRSPlug deals with the BBC collections. There are three BBC collections we deliver, which are National Sound Archive (nsa), British Film Institute (bfi), and BBC Other (bbcother) (everything does not fit into one of the first two). Four options are provided which are all-build all collections, nsa-build the NSA collections, bfi-build the BFI collections, bbcother-build the OTHER collections.
+
+ConvertToPlug.convert_to:Plugin converts to TEXT or HTML or various types of Image (e.g. JPEG, GIF, PNG).
+ConvertToPlug.convert_to.auto:Automatically select the format converted too.  Format chosen depends on input document type, for example Word will automatically be converted to HTML, whereas PowerPoint will be converted to Greenstone's PagedImage format.
+ConvertToPlug.convert_to.html:HTML format.
+ConvertToPlug.convert_to.text:Plain text format.
+ConvertToPlug.convert_to.pagedimg_jpg:JPEG format.
+ConvertToPlug.convert_to.pagedimg_gif:GIF format.
+ConvertToPlug.convert_to.pagedimg_png:PNG format. 
+
+ConvertToPlug.desc:The plugin is inherited by such plugins as WordPlug and PDFPlug. It facilitates the conversion of these document types to either HTML or TEXT by setting up variable that instruct ConvertToBasPlug how to work. It works by dynamically inheriting HTMLPlug or TEXTPlug based on the plugin argument 'convert_to'. If the argument is not present, the default is to inherit HTMLPlug.
+
+ConvertToPlug.use_strings:If set, a simple strings function will be called to extract text if the conversion utility fails.
+
+ConvertToRogPlug.desc:A plugin that inherits from RogPlug.
+
+DBPlug.desc:Uses records from a database as documents.
+
+DBPlug.title_sub:Substitution expression to modify string stored as Title. Used by, for example, PSPlug to remove "Page 1" etc from text used as the title.
+
+DSpacePlug.desc:DSpacePlug reads the DSpace Export collection and its dublin_core metadata file, and convert to GSII compilance format.	
+DSpacePlug.first_inorder_ext: This is used to identify the primary stream of DSpace collection document. With this option, the system will treat the defined ext types of document in sequence to look for the possible primary stream. 
+DSpacePlug.first_inorder_mime:This is used to identify the primary data stream of DSpace collection document.With this option, the system will treat the defined mime types of document in sequence to look for the possible primary stream. 
+DSpacePlug.only_first_doc:This is used to identify the primary data stream of DSpace collection document.With this option, the system will treat the first document in dublic_core metadata file as the possible primary stream. 
+
+EMAILPlug.desc:Email plug reads email files.  These are named with a simple number (i.e. as they appear in maildir folders) or with the extension .mbx (for mbox mail file format).\nDocument text: The document text consists of all the text after the first blank line in the document.\nMetadata (not Dublin Core!):\n\t\$Headers      All the header content (optional, not stored by default)\n\t\$Subject      Subject: header\n\t\$To           To: header\n\t\$From         From: header\n\t\$FromName     Name of sender (where available)\n\t\$FromAddr     E-mail address of sender\n\t\$DateText     Date: header\n\t\$Date         Date: header in GSDL format (eg: 19990924)
+
+EMAILPlug.no_attachments:Do not save message attachments.
+
+EMAILPlug.headers:Store email headers as "Headers" metadata.
+
+EMAILPlug.split_exp:A perl regular expression used to split files containing many messages into individual documents.
+
+ExcelPlug.desc:A plugin for importing Microsoft Excel files.
+
+FOXPlug.desc:Plugin to process a Foxbase dbt file. This plugin provides the basic functionality to read in the dbt and dbf files and process each record. This general plugin should be overridden for a particular database to process the appropriate fields in the file.
+
+GAPlug.desc:Processes GreenstoneArchive XML documents. Note that this plugin does no syntax checking (though the XML::Parser module tests for well-formedness). It's assumed that the GreenstoneArchive files conform to their DTD.
+
+GISBasPlug.extract_placenames:Extract placenames from within text and set as metadata. Requires GIS extension to Greenstone.
+
+GISBasPlug.gazetteer:Gazetteer to use to extract placenames from within text and set as metadata. Requires GIS extension to Greenstone.
+
+GISBasPlug.place_list:When extracting placements, include list of placenames at start of the document. Requires GIS extension to Greenstone.
+
+GMLPlug.desc:Plugin which processes a GML format document assumes that gml tags are all in lower-case.
+
+HBPlug.desc:Plugin which processes an HTML book directory. This plugin is used by the Humanity Library collections and does not handle input encodings other than ascii or extended ascii. This code is kind of ugly and could no doubt be made to run faster, by leaving it in this state I hope to encourage people to make their collections use HBSPlug instead ;-)\n\nUse HBSPlug if creating a new collection and marking up files like the Humanity Library collections. HBSPlug accepts all input encodings but expects the marked up files to be cleaner than those used by the Humanity Library collections
+
+HTMLPlug.assoc_files:Perl regular expression of file extensions to associate with html documents.
+
+HTMLPlug.desc:This plugin processes HTML files
+
+HTMLPlug.description_tags:Split document into sub-sections where <Section> tags occur. Note that by setting this option you implicitly set -no_metadata, as all metadata should be included within the <Section> tags. Also, '-keep_head' will have no effect when this option is set.
+
+HTMLPlug.file_is_url:Set if input filenames make up url of original source documents e.g. if a web mirroring tool was used to create the import directory structure.
+
+HTMLPlug.hunt_creator_metadata:Find as much metadata as possible on authorship and place it in the 'Creator' field. Requires the -metadata_fields flag.
+
+HTMLPlug.keep_head:Don't remove headers from html files.
+
+HTMLPlug.metadata_fields:Comma separated list of metadata fields to attempt to extract. Use 'tag<tagname>' to have the contents of the first <tagname> pair put in a metadata element called 'tagname'. Capitalise this as you want the metadata capitalised in Greenstone, since the tag extraction is case insensitive.
+
+HTMLPlug.no_metadata:Don't attempt to extract any metadata from files.
+
+HTMLPlug.no_strip_metadata_html:Comma separated list of metadata names, or 'all'. Used with -description_tags, it prevents stripping of HTML tags from the values for the specified metadata.
+
+HTMLPlug.nolinks:Don't make any attempt to trap links (setting this flag may improve speed of building/importing but any relative links within documents will be broken).
+
+HTMLPlug.rename_assoc_files:Renames files associated with documents (e.g. images). Also creates much shallower directory structure (useful when creating collections to go on cd-rom).
+
+HTMLPlug.sectionalise_using_h_tags:Automatically create a sectioned document using h1, h2, ... hX tags.
+
+HTMLPlug.title_sub:Substitution expression to modify string stored as Title. Used by, for example, PDFPlug to remove "Page 1", etc from text used as the title.
+
+ImagePlug.converttotype:Convert main image to format 's'.
+
+ImagePlug.desc:This plugin processes images, adding basic metadata
+
+ImagePlug.minimumsize:Ignore images smaller than n bytes.
+
+ImagePlug.noscaleup:Don't scale up small images when making thumbnails.
+
+ImagePlug.screenviewsize:If set, makes an image of size n for screen display and sets Screen, ScreenSize, ScreenWidth and ScreenHeight metadata.  By default it is not set.
+
+ImagePlug.screenviewtype:If -screenviewsize is set, this sets the screen display image type.
+
+ImagePlug.thumbnailsize:Make thumbnails of size nxn.
+
+ImagePlug.thumbnailtype:Make thumbnails in format 's'.
+
+IndexPlug.desc:This recursive plugin processes an index.txt file. The index.txt file should contain the list of files to be included in the collection followed by any extra metadata to be associated with each file.\n\nThe index.txt file should be formatted as follows: The first line may be a key (beginning with key:) to name the metadata fields (e.g. key: Subject Organization Date). The following lines will contain a filename followed by the value that metadata entry is to be set to. (e.g. 'irma/iw097e 3.2 unesco 1993' will associate the metadata Subject=3.2, Organization=unesco, and Date=1993 with the file irma/iw097e if the above key line was used)\n\nNote that if any of the metadata fields use the Hierarchy classifier plugin then the value they're set to should correspond to the first field (the descriptor) in the appropriate classification file.\n\nMetadata values may be named separately using a tag (e.g. <Subject>3.2) and this will override any name given to them by the key line. If there's no key line any unnamed metadata value will be named 'Subject'.
+
+ISISPlug.desc:This plugin processes CDS/ISIS databases. For each CDS/ISIS database processed, three files must exist in the collection's import folder: the Master file (.mst), the Field Definition Table (.fdt), and the Cross-Reference File (.xrf).
+
+ISISPlug.subfield_separator:The string used to separate subfields in CDS/ISIS database records.
+
+ISISPlug.entry_separator:The string used to separate multiple values for single metadata fields in CDS/ISIS database records.
+
+LaTeXPlug.desc:Plugin for LaTeX documents.
+
+MACROPlug.desc:Creates simple single-level document. Adds Title metadata of first line of text (up to 100 characters long).
+
+MARCPlug.desc:Basic MARC plugin.
+
+MARCPlug.metadata_mapping:Name of file that includes mapping details from MARC values to Greenstone metadata names. Defaults to 'marctodc.txt' found in the site's etc directory.
+
+MetadataPass.desc:On-the-side base class to BasPlug that supports metadata plugins utilise metadata_read pass of import.pl
+GISBasPlug.desc: On-the-side base class to BasPlug that supports GIS capabilities
+
+NULPlug.desc:Dummy (.nul) file plugin. Used with the files produced by exploding metadata database files.
+
+OAIPlug.desc:Basic Open Archives Initiate (OAI) plugin.
+
+OggVorbisPlug.add_technical_metadata:Add technical (eg. bitrate) metadata.
+
+OggVorbisPlug.desc:A plugin for importing Ogg Vorbis audio files.
+
+PagedImgPlug.desc:Plugin for documents made up of a sequence of images, with optional OCR text for each image.
+
+PagedImgPlug.documenttype:Set the document type (used for display)
+PagedImgPlug.documenttype.paged:Paged documents have next and previous arrows and a 'go to page X' box
+PagedImgPlug.documenttype.hierarchy:Hierarchical documents have a table of contents
+
+PagedImgPlug.headerpage:Add a top level header page (that contains no image) to each document.
+
+PagedImgPlug.screenview:Produce a screenview image for each image, and set Screen, ScreenSize, ScreenWidth and ScreenHeight metadata.
+
+PagedImgPlug.screenviewsize:Make screenview images of size nxn.
+
+PagedImgPlug.screenviewtype:Make screenview images in format 's'.
+
+PagedImgPlug.thumbnail:Produce a thumbnail for each image
+
+PDFPlug.allowimagesonly:Allow PDF files with no extractable text. Avoids the need to have -complex set. Only useful with convert_to html.
+PDFPlug.complex:Create more complex output. With this option set the output html will look much more like the original PDF file. For this to function properly you Ghostscript installed (for *nix gs should be on your path while for windows you must have gswin32c.exe on your path).
+
+PDFPlug.desc:Reasonably with-it pdf plugin.
+
+PDFPlug.nohidden:Prevent pdftohtml from attempting to extract hidden text. This is only useful if the -complex option is also set.
+
+PDFPlug.noimages:Don't attempt to extract images from PDF.
+
+PDFPlug.use_sections:Create a separate section for each page of the PDF file.
+
+PDFPlug.zoom:The factor by which to zoom the PDF for output (this is only useful if -complex is set).
+
+PPTPlug.desc:A plugin for importing Microsoft PowerPoint files.
+
+PPTPlug.windows_scripting:Use MicroSoft Windows scripting technology (Visual Basic for Applications) to get PPT to convert document to various image types (e.g. JPEG,PNG,GIF) rather than rely on the open source package ppttohtml. 
+
+PSPlug.desc:This is a \"poor man's\" ps to text converter. If you are serious, consider using the PRESCRIPT package, which is available for download at http://www.nzdl.org/html/software.html
+
+PSPlug.extract_date:Extract date from PS header.
+
+PSPlug.extract_pages:Extract pages from PS header.
+
+PSPlug.extract_title:Extract title from PS header.
+
+RealMediaPlug.desc:A plugin for processing Real Media files.
+
+RecPlug.desc:RecPlug is a plugin which recurses through directories processing each file it finds.
+
+RecPlug.recheck_directories:After the files in an import directory have been processed, re-read the directory to discover any new files created.
+
+RecPlug.use_metadata_files:Read metadata from metadata XML files.
+
+ReferPlug.desc:ReferPlug reads bibliography files in Refer format.
+
+ReferPlug.longdesc:ReferPlug reads bibliography files in Refer format.\nBy Gordon W. Paynter (gwp\@cs.waikato.ac.nz), November 2000\n\nLoosely based on hcibib2Plug by Steve Jones (stevej\@cs.waikato.ac.nz). Which was based on EMAILPlug by Gordon Paynter (gwp\@cs.waikato.ac.nz). Which was based on old versions of HTMLplug and HCIBIBPlugby by Stefan Boddie and others -- it's hard to tell what came from where, now.\n\nReferPlug creates a document object for every reference in the file. It is a subclass of SplitPlug, so if there are multiple records, all are read.\n\nDocument text:\n\tThe document text consists of the reference in Refer format.\nMetadata:\n\t\$Creator	\%A	Author name\n\t\$Title		\%T	Title of article of book\n\t\$Journal	\%J	Title of Journal\n\t\$Booktitle	\%B	Title of book containing the publication\n\t\$Report		\%R	Type of Report, paper or thesis\n\t\$Volume		\%V	Volume Number of Journal\n\t\$Number		\%N	Number of Journal within Volume\n\t\$Editor		\%E	Editor name\n\t\$Pages		\%P	Page Number of article\n\t\$Publisher	\%I	Name of Publisher\n\t\$Publisheraddr	\%C	Publisher's address\n\t\$Date		\%D	Date of publication\n\t\$Keywords	\%K	Keywords associated with publication\n\t\$Abstract	\%X	Abstract of publication\n\t\$Copyright\t\%*	Copyright information for the article
+
+RogPlug.desc:Creates simple single-level documents from .rog or .mdb files.
+
+RTFPlug.desc:Plugin for importing Rich Text Format files.
+
+SRCPlug.desc:Filename is currently used for Title ( optionally minus some prefix ). Current languages:\ntext: READMEs/Makefiles\nC/C++   (currently extracts #include statements and C++ class decls)\nPerl    (currently only done as text)\nShell   (currently only done as text)
+
+SRCPlug.remove_prefix:Remove this leading pattern from the filename (eg -remove_prefix /tmp/XX/src/). The default is to remove the whole path from the filename.
+
+SplitPlug.desc:SplitPlug is a plugin for splitting input files into segments that will then be individually processed. This plugin should not be called directly.  Instead, if you need to process input files that contain several documents, you should write a plugin with a process function that will handle one of those documents and have it inherit from SplitPlug.  See ReferPlug for an example.
+
+SplitPlug.split_exp:A perl regular expression to split input files into segments.
+
+TEXTPlug.desc:Creates simple single-level document. Adds Title metadata of first line of text (up to 100 characters long).
+
+TEXTPlug.title_sub:Substitution expression to modify string stored as Title. Used by, for example, PSPlug to remove "Page 1" etc from text used as the title.
+
+UnknownPlug.assoc_field:Name of the metadata field that will hold the associated file's name.
+
+UnknownPlug.desc:This is a simple Plugin for importing files in formats that Greenstone doesn't know anything about.  A fictional document will be created for every such file, and the file itself will be passed to Greenstone as the \"associated file\" of the document.
+
+UnknownPlug.file_format:Type of the file (e.g. MPEG, MIDI, ...)
+
+UnknownPlug.mime_type:Mime type of the file (e.g. image/gif).
+
+UnknownPlug.process_extension:Process files with this file extension. This option is an alternative to process_exp that is simpler to use but less flexible.
+
+MP3Plug.desc:Plugin for processing MP3 files.
+
+MP3Plug.assoc_images:Use google image search to locate images related to MP3 file based on ID3 Title and Artist metadata.
+
+MP3Plug.assoc_images:Used to store [applet] metadata for each document that contains the necessary HTML for an MP3 audio player applet to play that file.
+
+MP3Plug.metadata_fields:Comma separated list of metadata fields to extract (assuming present) in an MP3 file. Use \"*\" to extract all the fields.
+
+W3ImgPlug.aggressiveness:Range of related text extraction techniques to use.
+W3ImgPlug.aggressiveness.1:Filename, path, ALT text only.
+W3ImgPlug.aggressiveness.2:All of 1, plus caption where available.
+W3ImgPlug.aggressiveness.3:All of 2, plus near paragraphs where available.
+W3ImgPlug.aggressiveness.4:All of 3, plus previous headers (<h1>, <h2>...) where available.
+W3ImgPlug.aggressiveness.5:All of 4, plus textual references where available.
+W3ImgPlug.aggressiveness.6:All of 4, plus page metatags (title, keywords, etc).
+W3ImgPlug.aggressiveness.7:All of 6, 5 and 4 combined.
+W3ImgPlug.aggressiveness.8:All of 7, plus repeat caption, filename, etc (raise ranking of more relevant results).
+W3ImgPlug.aggressiveness.9:All of 1, plus full text of source page.
+
+W3ImgPlug.caption_length:Maximum length of captions (in characters).
+
+W3ImgPlug.convert_params:Additional parameters for ImageMagicK convert on thumbnail creation. For example, '-raise' will give a three dimensional effect to thumbnail images.
+
+W3ImgPlug.desc:A plugin for extracting images and associated text from webpages.
+
+W3ImgPlug.document_text:Add image text as document:text (otherwise IndexedText metadata field).
+
+W3ImgPlug.index_pages:Index the pages along with the images. Otherwise reference the pages at the source URL.
+
+W3ImgPlug.max_near_text:Maximum characters near images to extract.
+
+W3ImgPlug.min_height:Pixels. Skip images shorter than this.
+
+W3ImgPlug.min_near_text:Minimum characters of near text or caption to extract.
+
+W3ImgPlug.min_size:Bytes. Skip images smaller than this.
+
+W3ImgPlug.min_width:Pixels. Skip images narrower than this.
+
+W3ImgPlug.neartext_length:Target length of near text (in characters).
+
+W3ImgPlug.no_cache_images:Don't cache images (point to URL of original).
+
+W3ImgPlug.smallpage_threshold:Images on pages smaller than this (bytes) will have the page (title, keywords, etc) meta-data added.
+
+W3ImgPlug.textrefs_threshold:Threshold for textual references. Lower values mean the algorithm is less strict.
+
+W3ImgPlug.thumb_size:Max thumbnail size. Both width and height.
+
+WordPlug.desc:A plugin for importing Microsoft Word documents.
+
+WordPlug.windows_scripting:Use MicroSoft Windows scripting technology (Visual Basic for Applications) to get Word to convert document to HTML rather than rely on the open source package WvWare.  Causes Word application to open on screen if not already running.
+
+WordPlug.delete_toc:Remove the "Table of Contents" and "List of Tables" from the converted HTML file. 
+
+WordPlug.title_header:set up the possible user-defined style for the title_header.
+
+WordPlug.level1_header:possible user-defined styles for the level1 header in the HTML document (equivalent to <h1>).
+
+WordPlug.level2_header:possible user-defined styles for the level2 header in the HTML document (equivalent to <h2>).
+
+WordPlug.level3_header:possible user-defined styles for the level3 header in the HTML document (equivalent <h3>).
+
+WordPlug.toc_header:possible user-defined header styles for the TOC.
+
+WordPlug.tof_header:possible user-defined header styles for the TOF
+
+WordPlug.extracted_word_metadata: This is to retrieve metadata from the HTML document converted by VB scripting. It allows users to define comma separated list of metadata fields to attempt to extract. Use 'tag<tagname>' to have the contents of the first <tagname> pair put in a metadata element called 'tagname'. Capitalise this as you want the metadata capitalised in Greenstone, since the tag extraction is case insensitive
+
+XMLPlug.desc:Base class for XML plugins.
+
+XMLPlug.xslt:Transform a matching input document with the XSLT in the named file.  A relative filename is assumed to be in the collection's file area, for instance etc/mods2dc.xsl.
+ZIPPlug.desc:Plugin which handles compressed and/or archived input formats currently handled formats and file extensions are:\ngzip (.gz, .z, .tgz, .taz)\nbzip (.bz)\nbzip2 (.bz2)\nzip (.zip .jar)\ntar (.tar)\n\nThis plugin relies on the following utilities being present (if trying to process the corresponding formats):\ngunzip (for gzip)\nbunzip (for bzip)\nbunzip2 \nunzip (for zip)\ntar (for tar)
+
+
+#
+# Perl module strings
+#
+
+classify.could_not_find_classifier:ERROR: Could not find classifier \"%s\"
+
+plugin.could_not_find_plugin:ERROR: Could not find plugin \"%s\"
+
+plugin.including_archive:including the contents of 1 ZIP/TAR archive
+
+plugin.including_archives:including the contents of %d ZIP/TAR archives
+
+plugin.kill_file:Process killed by .kill file
+
+plugin.n_considered:%d documents were considered for processing
+
+plugin.n_included:%d were processed and included in the collection
+
+plugin.n_rejected:%d were rejected
+
+plugin.n_unrecognised:%d were unrecognised
+
+plugin.no_plugin_could_process:WARNING: No plugin could process %s
+
+plugin.no_plugin_could_recognise:WARNING: No plugin could recognise %s
+
+plugin.no_plugin_could_process_this_file:no plugin could process this file
+
+plugin.no_plugin_could_recognise_this_file:no plugin could recognise this file
+
+plugin.one_considered:1 document was considered for processing
+
+plugin.one_included:1 was processed and included in the collection
+
+plugin.one_rejected:1 was rejected
+
+plugin.one_unrecognised:1 was unrecognised
+
+plugin.see_faillog:See %s for a list of unrecognised and/or rejected documents
+
+PrintUsage.default:Default
+
+PrintUsage.required:REQUIRED
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/strings_es.rb
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/strings_es.rb	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/strings_es.rb	(revision 10506)
@@ -0,0 +1,1275 @@
+#
+# Resource bundle description
+#
+
+Language.code:es
+
+Language.name:EspaÃ±ol
+
+
+OutputEncoding.unix:iso_8859_1
+
+OutputEncoding.windows:iso_8859_1
+
+
+
+#
+# Common output messages
+#
+
+common.cannot_create_file:ERROR: no puede crear archivo %s
+
+
+common.cannot_find_cfg_file:ERROR: no puede encontrar el archivo de configuraciÃ³n %s
+
+
+common.cannot_open:ERROR: no puede abrir %s
+
+
+common.cannot_open_fail_log:ERROR: no puede abrir el fail log %s
+
+
+common.cannot_open_output_file:ERROR: no puede abrir el archivo del rendimiento output %s
+
+
+common.cannot_read:ERROR: no puede leer %s
+
+
+common.cannot_read_file:ERROR: no puede leer el archivo %s
+
+
+common.general_options:las opciones generales (para % s)
+
+
+common.must_be_implemented:la funciÃ³n debe implementarse en clase-subalterno
+
+
+common.options:opciones
+
+
+common.processing:procesando
+
+
+common.specific_options:opciones especÃ­ficas
+
+
+common.usage:uso
+
+
+
+#
+# Script option descriptions and output messages
+#
+
+scripts.language:El idioma para desplegar las descripciones de la opciÃ³n en ('en_US' especifica inglÃ©s americano). Requiere las traducciones de las descripciones de la opciÃ³n existente en el archivo de perllib/strings_language-code.rb.
+
+
+scripts.xml:Produce la informaciÃ³n en un formato XML, sin comentarios 'elegantes' pero con mucho mÃ¡s detalle.
+
+
+scripts.listall:Listar todos los Ã­tems conocidos.
+
+
+
+# -- buildcol.pl --
+
+buildcol.archivedir:Donde los archivos residen.
+
+
+buildcol.builddir:DÃ³nde poner los Ã­ndices construidos.
+
+
+buildcol.cachedir:La colecciÃ³n se construirÃ¡ aquÃ­ temporalmente antes de copiarse al directorio construido.
+
+
+buildcol.cannot_open_cfg_file:ADVERTENCIA: no puede abrir los archivos config a efecto de poner al dÃ­a: %s
+
+
+buildcol.collectdir:El directorio de colecciÃ³n. 
+
+
+buildcol.copying_back_cached_build:Copiando la figura anteriormente construida
+
+
+buildcol.create_images:Intente crear las imÃ¡genes predefinidas para la nueva colecciÃ³n. Esto confÃ­a en el Gimp instalÃ¡ndose a lo largo con los mÃ³dulos perl pertinentes que permitan el scripting del perl.
+
+
+buildcol.debug:Imprima el output a STDOUT.
+
+
+buildcol.desc:La escritura de PERL construÃ­a una colecciÃ³n del greenstone de los documentos GML.
+
+
+buildcol.faillog:Falla en el archivo de login. Este log recibe los nombres de archivos de cualquier archivo que haya fallado al ser procesado.
+
+
+buildcol.index:Indice para construir (construirÃ¡ todos los archivos en el config si no estÃ¡ determinado).
+
+
+buildcol.keepold:No destruirÃ¡ los volÃºmenes actuales del directorio construido.
+
+
+buildcol.maxdocs:El nÃºmero mÃ¡ximo de documentos para construir.
+
+
+buildcol.mode:Las partes del proceso construido para llevar a cabo.
+
+buildcol.mode.all:Realizar todo.
+
+buildcol.mode.build_index:Simplemente ponga en un Ã­ndice el texto.
+
+buildcol.mode.compress_text:Simplemente comprima el texto.
+
+buildcol.mode.infodb:Simplemente construya la base de datos del metadata.
+
+
+buildcol.no_default_images:No se generarÃ¡n las imÃ¡genes predefinidas.
+
+
+buildcol.no_image_script:ADVIRTIENDO: Imagen que hace la escritura no encontrada: %s
+
+
+buildcol.no_strip_html:No despoje las etiquetas html del texto puesto en un Ã­ndice (sÃ³lo utilice para las colecciones del mgpp).
+
+
+buildcol.no_text:No guarde el texto comprimido. Esta opciÃ³n es Ãºtil para minimizar el tamaÃ±o de los Ã­ndices construidos si usted siempre piensa desplegar los documentos originales en momento que estÃ¡ utilizando el programa (es decir usted no podrÃ¡ recuperar la versiÃ³n del texto comprimido).
+
+
+buildcol.out:Nombre de archivo o palanca para imprimir el estado del rendimiento a.
+
+
+buildcol.params:[las opciones] collection-name
+
+
+buildcol.remove_empty_classifications:Ocultar los clasificadores y los nodos de clasificaciÃ³n vacÃ­os (aquellos que no contienen documentos).
+
+
+buildcol.unlinked_col_images:No pueden unirse las imÃ¡genes de la colecciÃ³n de manera correcta.
+
+
+buildcol.unknown_mode:Modo desconocido: %s
+
+
+buildcol.updating_archive_cache:El archivo poniendo al dÃ­a actualizando
+
+
+buildcol.verbosity:Los mandos la cantidad de rendimiento. El 0=ninguno, 3=muchos.
+
+
+
+# -- classinfo.pl --
+
+classinfo.collect:Dar un nombre de la colecciÃ³n harÃ¡n que classinfo.pl aparezca primero clasifique en el collect/collection-name/perllib/classify. Si el clasificador no se encuentra allÃ­ buscarÃ¡ en el directorio general perllib/classify.
+
+
+classinfo.desc:Imprime la informaciÃ³n de las impresiones sobre un clasificador.
+
+
+classinfo.general_options:Se heredan las opciones generales de las clases paternales del clasificador.
+
+
+classinfo.info:info
+
+
+classinfo.no_classifier_name:ERROR: Usted debe proporcionar un nombre del clasificador.
+
+
+classinfo.option_types:Los clasificadores pueden tomar dos tipos de opciones
+
+
+classinfo.params:[opciones] nombre-clasificador
+
+
+classinfo.passing_options:Las opciones pueden pasarse a cualquier clasificador incluyÃ©ndolos en su archivo de configuraciÃ³n collect.cfg.
+
+
+classinfo.specific_options:Se definen las opciones especÃ­ficas dentro del propio clasificador, y sÃ³lo estÃ¡ disponible a este clasificador particular.
+
+
+# -- explode_metadata_database.pl --
+explode.desc:Explotar una base de datos de metadatos.
+
+explode.document_field:El elemento de los meta-datos que especifica los nombres de archivo de los documentos a obtener e incluir en la colecciÃ³n.
+
+
+explode.document_prefix:Un prefijo para las ubicaciones de los documentos (para usar con la opciÃ³n document_field).
+
+
+explode.document_suffix:Un sufijo para las ubicaciones de los documentos (para usar con la opciÃ³n document_field).
+
+
+explode.encoding:CodificaciÃ³n a utilizar al leer el archivo de la base de datos
+explode.filename_field:Campo a utilizar para los nombres de los archivos nulos generados (si no existe document_field o ese campo estÃ¡ vacÃ­o)
+explode.metadata_set:Conjunto de metadatos (espacio de nombres) para exportar todos los metadatos
+explode.plugin:Plugin a utilizar para explotar
+explode.params:[opciones] nombre de archivo
+# -- exportcol.pl --
+
+exportcol.out:Nombre del archivo o identificador para imprimir el estado de los resultados. 
+
+exportcol.cdname:El nombre del CD-ROM. Esto es lo que aparecerÃ¡ en el menÃº de inicio una vez que el CD-ROM se haya instalado.
+
+exportcol.desc:GuiÃ³n PERL usado para exportar una o mÃ¡s colecciones a un CD-ROM para Windows. 
+
+exportcol.params:[opciones] nombre de la colecciÃ³n 1 nombre de la colecciÃ³n 2 ...
+
+exportcol.coll_not_found:El %s de la colecciÃ³n no es vÃ¡lido: la colecciÃ³n no se encontrÃ³ en %s.
+
+exportcol.coll_dirs_not_found:El %s de la colecciÃ³n no es vÃ¡lido: no se pudo encontrar uno de los siguientes directorios: 
+
+exportcol.fail:exportcol.pl no se pudo ejecutar:
+
+exportcol.no_valid_colls:Las colecciones especificadas no son vÃ¡lidas y por lo tanto no se pueden exportar.
+
+exportcol.couldnt_create_dir:No se pudo crear el directorio %s.
+
+exportcol.couldnt_create_file:No se pudo crear %s.
+
+exportcol.instructions:Para crear un CD-ROM en Windows que se podrÃ¡ instalar automÃ¡ticamente, grabe el contenido de esta carpeta en un CD-ROM.
+
+exportcol.non_exist_files:Uno o mÃ¡s de los siguientes archivos y directorios no existe:
+
+exportcol.success:exportcol.pl se ejecutÃ³ con Ã©xito:
+
+exportcol.output_dir:Las colecciones que se exportaron (%s) se encuentran en %s
+
+exportcol.nonetscape:No adjuntar netscape al CD-ROM exportado.
+exportcol.export_coll_not_installed:La funcionalidad de 'Exportar a un CD-ROM' no ha estado instalada.
+
+
+# -- import.pl --
+
+import.archivedir:Lugar donde los materiales convertidos finalizan.
+
+
+import.cannot_open_stats_file:ADVIRTIENDO: No podrÃ­a abrir el archivos stats %s.
+
+
+import.cannot_open_fail_log:ERROR: No se pudo abrir el registro %s
+
+
+import.cannot_sort:ADVIRTIENDO: import.pl no puede ordenar los documentos cuando el tamaÃ±o del grupo > 1. la opciÃ³n sortmeta se ignorarÃ¡.
+
+
+import.collectdir:El directorio de la colecciÃ³n.
+
+
+import.complete:La importaciÃ³n ha sido completada
+
+
+import.debug:La impresiÃ³n importÃ³ el texto a STDOUT.
+
+
+import.desc:La escritura de PERL utilizada para importar los archivos en un formato de GML listo para utilizar.
+
+
+import.faillog:FallÃ³ log el nombre del archivo . Este log recibe los nombres de archivo de cualquier archivo que haya fallado al ser procesado.
+
+
+import.groupsize:El nÃºmero de documentos de importaciÃ³n para agruparse en un archivo de XML.
+
+
+import.gzip:Use el gzip para comprimir documentos xml (no se olvide de incluir ZIPPlug en su lista plugin al construir de los documentos comprimidos).
+
+
+import.importdir:Donde el material original reside.
+
+
+import.keepold:No destruirÃ¡ los volÃºmenes actuales del directorio de los archivos (el valor predeterminado).
+
+
+import.maxdocs:El nÃºmero mÃ¡ximo de documentos para importar.
+
+
+import.no_plugins_loaded:ERROR: NingÃºn plugins ha sido cargado.
+
+
+import.OIDtype:El mÃ©todo a utilizar al generar los Ãºnicos identificadores para cada documento.
+
+import.OIDtype.hash:Conjuga los volÃºmenes del archivo. El identificador del documento serÃ¡ el mismo cada vez que la colecciÃ³n es importada.
+
+
+import.OIDtype.incremental:Una cuenta del documento simple que es significativamente mÃ¡s rÃ¡pido que hash. No se garantiza siempre asignar el mismo identificador a un documento dado aunque y no permite agregar los documentos extensos a los archivos xml existentes.
+
+
+import.OIDtype.assigned:Utiliza 'D' mÃ¡s el valor de dc.Identifier como el identificador del documento. Los dc.Identifiers deben ser Ãºnicos. Si al documento no se le ha asignado un dc.Identifier, se procede a utilizar una identificaciÃ³n generada por hash.
+
+import.OIDtype.dirname:Utiliza como identificador 'J' mÃ¡s el nombre del directorio padre. Se parte de la base de que sÃ³lo existe un documento por directorio y que todos los nombres de directorio son Ãºnicos. Por ejemplo: import/b13as/h15ef/page.html producirÃ¡ Jh15ef como identificador.
+
+
+import.saveas:Establece el fomato de archivo a generar. La preselecciÃ³n es GA.
+
+
+import.saveas.GA:GenerarÃ¡ formato de archivo Greenstone.
+
+
+import.saveas.METS:GenerarÃ¡ formato METS:
+
+
+import.out:Nombre de archivo o maneja para imprimir el estado del rendimiento.
+
+
+import.params:[opciones] colecciÃ³n-nombre
+
+
+import.removeold:EliminarÃ¡ los volÃºmenes antiguos del directorio de los archivos--utilice con cuidado.
+
+
+import.removing_archives:Los volÃºmenes actuales eliminados del directorio de los archivos...
+
+
+import.sortmeta:Ordena documentos alfabÃ©ticamente por metadatos para la construcciÃ³n. Los resultados de las bÃºsquedas booleanas se mostrarÃ¡n con este orden. Se desactivarÃ¡ si groupsize > 1.
+
+
+import.statsfile:Nombre de archivo o habilidad para imprimir las estadÃ­sticas de importaciÃ³n.
+
+
+import.stats_backup:ImprimirÃ¡ el stats en lugar de STDERR.
+
+
+import.verbosity:Controla la cantidad de output rendimiento. El 0=ninguno, 3=muchos.
+
+
+
+# -- export.pl --
+
+export.exportdir:LocalizaciÃ³n final del material exportado.
+
+
+export.cannot_open_stats_file:ATENCIÃN:No se puede abrir el archivo de estadÃ­sticas %s.
+
+
+export.cannot_open_fail_log:ERROR: No se puede abrir el registro de errores %s
+
+
+export.cannot_sort:ATENCIÃN: export.pl no puede ordenar los documentos cuando groupsize>1. Se ignorarÃ¡ la opciÃ³n sortmeta.
+
+
+export.collectdir:Directorio de la colecciÃ³n
+
+
+export.complete:ExportaciÃ³n completa
+
+
+export.debug:Imprimir el texto exportado a STDOUT.
+
+
+export.desc:Script PERL usado para importar archivos al formato GML preparado para la construcciÃ³n.
+
+
+export.faillog:Nombre de archivo del registro de fallos. Este registro contiene el nombre de cualquier archivo que falle al ser procesado.
+
+
+export.groupsize:NÃºmero de documentos importados a agrupar en un archivo XML.
+
+
+export.gzip:Use gzip para comprimir los documentos xml resultantes (no olvide incluir ZIPPlug en su lista de plugins cuando construya desde documentos comprimidos).
+
+
+export.importdir:LocalizaciÃ³n del material original.
+
+
+export.keepold:No destruirÃ¡ el contenido actual del directorio export (predefinido).
+
+
+export.maxdocs:NÃºmero mÃ¡ximo de documentos a importar.
+
+
+export.no_plugins_loaded:ERROR: no se han cargado plugins.
+
+
+export.OIDtype:MÃ©todo usado cuando se generan identificadores Ãºnicos para cada documento.
+
+export.OIDtype.hash:Marca el contenido del archivo. El identificador del documento serÃ¡ el mismo cada vez que se importe la colecciÃ³n.
+
+export.OIDtype.incremental:Contador simple de documentos bastante mÃ¡s rÃ¡pido que "hash". No se garantiza que siempre asigne el mismo identificador a un documento dado, y no permite que se aÃ±adan nuevos documentos a archivos xml ya existentes.
+
+
+export.saveas:Sirve para decidir el formato de exportaciÃ³n a generar. La selecciÃ³n previa es METS.
+
+
+export.saveas.DSpace:GenerarÃ¡ formato de archivo Dspace.
+
+
+export.saveas.METS:GenerarÃ¡ formato METS.
+
+
+export.out:archivo o dispositivo en el que imprimir el estado de salida.
+
+
+export.params:[options] nombre de colecciÃ³n
+
+
+export.removeold:BorrarÃ¡ los contenidos previos del directorio export -- usar con cuidado.
+
+
+export.removing_export:Borrando los contenidos actuales del directorio exportâŠ
+
+
+export.sortmeta:Ordenar los documentos alfabÃ©ticamente por metadatos para construir. Se desactivarÃ¡ si groupsize > 1.
+
+
+export.statsfile:archivo o dispositivo en el que imprimiar las estadÃ­sticas de exportaciÃ³n.
+
+
+export.stats_backup:ImrprimirÃ¡ las estadÃ­sticas en STDERR en su lugar.
+
+
+export.verbosity:Controla la cantidad de salida. 0=nada, 3=mucha.
+
+
+
+# -- mkcol.pl --
+
+mkcol.about:Sobre el texto para la colecciÃ³n.
+
+
+mkcol.bad_name_cvs:ERROR: Ninguna colecciÃ³n puede nombrarse CVS puesto que puede interferir con directorios creados por la versiÃ³n del sistema CVS.
+
+
+mkcol.bad_name_modelcol:ERROR: Ninguna colecciÃ³n puede nombrarse modelcol puesto que este es el nombre de la colecciÃ³n model
+
+
+mkcol.cannot_find_modelcol:ERROR: Ninguna colecciÃ³n puede nombrarse el modelcol puesto que este es el nombre del ejemplo de colecciÃ³n %s
+
+
+mkcol.col_already_exists:ERROR: Esta colecciÃ³n ya existe.
+
+
+mkcol.collectdir:Directorio dÃ³nde la nueva colecciÃ³n serÃ¡ creada.
+
+
+mkcol.creating_col:Creando la colecciÃ³n %s
+
+
+mkcol.creator:La direcciÃ³n de correo electrÃ³nico del creador de la colecciÃ³n.
+
+
+mkcol.creator_undefined:ERROR: El creador no fue definido. Esta variable se necesita reconocer los nombres duplicados de la colecciÃ³n.
+
+
+mkcol.desc:La escritura de PERL utilizada para crear la estructura del directorio para una nueva colecciÃ³n de Greenstone.
+
+
+mkcol.doing_replacements:realizando reemplazos %s
+
+
+mkcol.long_colname:ERROR: El nombre de la colecciÃ³n debe estar menor de 8 caracteres para que la compatibilidad con el sistema de archivo anterior pueda mantenerse.
+
+
+mkcol.maintainer:La direcciÃ³n del correo electrÃ³nico de la persona que proporciona mantenimiento a la colecciÃ³n (si es diferente a la del creador).
+
+
+mkcol.no_collectdir:ERROR: El dir del coleccionador no existe: %s
+
+
+mkcol.no_colname:ERROR: NingÃºn nombre de la colecciÃ³n fue especificado.
+
+
+mkcol.optionfile:Reciba las opciones del archivo, Ãºtil en sistemas donde las lÃ­neas de orden largas pueden causar problemas.
+
+
+mkcol.params:[opciones] colecciÃ³n-nombre
+
+
+mkcol.plugin:El mÃ³dulo Perl plugin para usar (puede haber entradas mÃºltiples plugin).
+
+
+mkcol.public:Si esta colecciÃ³n tiene acceso anÃ³nimo (verdadero/falso).
+
+
+mkcol.quiet:Opere de manera silenciosa
+
+
+mkcol.success:La nueva colecciÃ³n se creada exitosamente a %s
+
+
+mkcol.title:El tÃ­tulo de la colecciÃ³n.
+
+
+mkcol.win31compat:Establece si el directorio de la colecciÃ³n indicada debe ser conforme a las convenciones de archivo de Windows 3.1 (ej.: longitud de 8 caracteres).
+
+
+# -- pluginfo.pl --
+
+pluginfo.collect:Al dar un nombre a la colecciÃ³n realizarÃ¡ que un pluginfo.pl revise primero en el collect/collection-name/perllib/plugins. Si el plugin general no se encuentra allÃ­ que aparecerÃ¡ en el directorio del perllib/plugins.
+
+
+pluginfo.desc:Imprime informaciÃ³n sobre un plugin.
+
+
+pluginfo.general_options:Se toman las opciones generales de las clases paternal inicial del plugin.
+
+
+pluginfo.info:info
+
+
+pluginfo.no_plugin_name:ERROR: Usted debe proporcionar un nombre plug.
+
+
+pluginfo.option_types:Plugins podrÃ¡n tomar dos tipos de opciones
+
+
+pluginfo.params:[opciones] el nombre-plugin
+
+
+pluginfo.passing_options:Pueden pasarse las opciones a cualquier plugin incluyÃ©ndolos en su archivo de configuraciÃ³n collect.cfg.
+
+
+pluginfo.specific_options:Se definen las opciones especÃ­ficas dentro del propio plugin, y sÃ³lo estÃ¡n disponibles en este plugin en particular.
+
+
+
+#
+# Classifier option descriptions
+#
+
+AZCompactList.allvalues:Utilizar todos los valores de meta-datos encontrados
+
+
+AZCompactList.desc:Plugin para clasificar por orden alfabÃ©tica
+
+
+AZCompactList.doclevel:Nivel para procesar el documento a
+
+AZCompactList.doclevel.top:Documento completo
+
+AZCompactList.doclevel.section:Por secciones
+
+
+AZCompactList.firstvalueonly:Utilizar Ãºnicamente el primer valor de meta-datos encontrado.
+
+
+AZCompactList.freqsort:Clasificar por la frecuencia del nodo en lugar de alfa-numÃ©rico.
+
+
+AZCompactList.maxcompact:NÃºmero mÃ¡ximo de documentos que serÃ¡n desplegados por pÃ¡gina.
+
+
+AZCompactList.metadata:Un solo campo de Meta-datos, o una lista de campos de Meta-datos separada por comas, utilizados para clasificaciÃ³n. Si se especifica una lista, serÃ¡ utilizado el primer tipo de meta-datos que tenga valores. Puede utilizarse al tiempo con las banderas -firstvalueonly y -allvalues, para seleccionar Ãºnicamente el primer valor o todos los valores de la lista.
+
+
+AZCompactList.mincompact:NÃºmero mÃ­nimo de documentos que serÃ¡n desplegados por pÃ¡gina.
+
+
+AZCompactList.mingroup:El valor mÃ¡s pequeÃ±o que causarÃ¡ un grupo en formato jerÃ¡rquico
+
+
+AZCompactList.minnesting:El valor mÃ¡s pequeÃ±o que causarÃ¡ una lista a ser convertida en una lista anidada.
+
+
+AZCompactList.recopt:Usado en metadatos anidados como -metadato AÃ±o/OrganizaciÃ³n.
+
+AZCompactList.sort:Campo de metadatos por medio del cual ordenar los nodos anidados.
+
+
+AZCompactSectionList.desc:VariaciÃ³n de AZCompactList que clasifica secciones en vez de documentos. Las entradas se ordenan por medio de metadatos a nivel de secciÃ³n.
+
+
+AZList.desc:El plugin clasificador alfabÃ©tico.
+
+
+AZList.metadata:Un solo campo de Metadatos o una lista de campos de Metadatos separados por una coma y usados con fines de clasificaciÃ³n. Siguiendo el orden indicado por la lista, se utilizarÃ¡ el primer campo que contiene un valor. La lista se ordenarÃ¡ de acuerdo a este elemento.
+
+
+AZSectionList.desc:El plugin del clasificador para ordenar de manera alfabÃ©tica. Esto es muy similar a AZList excepto que clasifica por secciones el nivel del metadata (excluyendo el nivel superior) en lugar de sÃ³lo el nivel superior del metadata. El Ãºnico cambio es a la subrutina de clasificaciÃ³n () que debe repetir ahora a travÃ©s de cada secciÃ³n, agregando cada uno a la clasificaciÃ³n.
+
+
+BasClas.bad_general_option:El clasificador de porcentajes (%s) utiliza una opciÃ³n general incorrecta (las opciones generales estÃ¡n disponibles a todos los clasificadores). Revise su archivo de configuraciÃ³n collect.cfg.
+
+
+BasClas.builddir:En dÃ³nde poner los Ã­ndices construidos.
+
+
+BasClas.buttonname:Etiqueta para clasificador de pantalla y botÃ³n en la barra de navegaciÃ³n.
+
+
+BasClas.desc:Clase base para todos los clasificadores.
+
+
+BasClas.outhandle:El archivo para escribir el output (o salida) para.
+
+
+BasClas.removeprefix:Un prefijo que al clasificar se debe ignorar en los valores de los metadatos.
+
+BasClas.removesuffix:Un sufijo que al clasificar se debe ignorar en los valores de los metadatos.
+
+BasClas.verbosity:Controla la cantidad de (output) rendimiento. 0=ninguno, 3=muchos.
+
+
+Browse.desc:.
+
+
+DateList.bymonth:Clasificar por aÃ±o y mes en vez de sÃ³lo aÃ±o.
+
+
+DateList.desc:El plugin clasificador ordenador por fecha. El metadata por defaul clasifica por 'Fecha'. Se asume que la fecha estÃ¡ en el formulario aaaammdd
+
+
+DateList.metadata:El metadata que contiene las fechas para clasificar. Se espera que el formato sea el aaaammdd. (aÃ±o, mes, dÃ­a)
+
+
+DateList.reverse_sort:Ordenar los documentos en orden cronolÃ³gico inverso (el mÃ¡s nuevo al comienzo).
+
+
+DateList.nogroup:Haga de cada aÃ±o una entrada individual en la lista horizontal, en vez de extender los aÃ±os con pocas entradas. (Esto tambiÃ©n se puede usar con la opciÃ³n -bymonth para hacer que cada mes tenga una entrada separada en vez de combinarlas).
+
+
+DateList.sort:Un campo de metadata extra para ordenar por en el caso dÃ³nde dos documentos tienen la misma fecha.
+
+
+HFileHierarchy.desc:Plugin clasificador para generar clasificaciones jerÃ¡rquicas basadas en una estructura existente en un archivo suplementario.
+
+
+Hierarchy.hfile:Archivo de clasificaciÃ³n de estructura.
+
+
+Hierarchy.hlist_at_top:Despliega el primer nivel de clasificaciÃ³n horizontalmente
+
+Hierarchy.reverse_sort:Ordenar hojas de nodos en orden inverso (usar con -sort).
+
+Hierarchy.sort:Campo de Metadata para clasificar. Use '-sort nosort' para no clasificar.
+
+
+Hierarchy.separator:ExpresiÃ³n regular utilizada por el separador
+
+
+Hierarchy.suppresslastlevel:Ignorar la parte final del valor del metadato. Es Ãºtil para metadatos en los cuales cada valor es Ãºnico, como en la rutas de archivos.
+
+
+HTML.desc:Crea una clasificaciÃ³n vacÃ­a que simplemente es un link a una pÃ¡gina web.
+
+
+HTML.url:El url de la pÃ¡gina web para unirse a.
+
+
+List.desc:El plugin clasificador de lista simple.
+
+
+List.metadata:Un solo campo de Metadatos o una lista de campos de Metadatos separados por una coma y usados con fines de clasificaciÃ³n. Siguiendo el orden indicado por la lista, se utilizarÃ¡ el primer campo que contiene un valor. La lista se ordenarÃ¡ por este elemento, a menos que estÃ© utilizando otro clasificador.
+
+
+List.sort:Campo de Metadata a partir del cual se harÃ¡ la ordenaciÃ³n. Use '-sort nosort' para no clasificar.
+
+
+Phind.desc:Plugin clasificador Phind.
+
+
+Phind.language:Idioma o idiomas utilizados para construir una jerarquÃ­a. Los idiomas son identificados por un cÃ³digo de paÃ­s de dos letras: en (inglÃ©s), es (espaÃ±ol), y fr (francÃ©s). El lenguaje es una expresiÃ³n normal, de modo que 'en|fr' (inglÃ©s o francÃ©s) y '.. ' (iguala cualquier idioma) son vÃ¡lidos.
+
+
+Phind.min_occurs:MÃ­nimo nÃºmero de veces que debe aparecer una frase en el texto para que sea incluida en la jerarquÃ­a de frases.
+
+
+Phind.savephrases:Si estÃ¡ determinado, la informaciÃ³n de la frase se guardarÃ¡ en el archivo como texto. Probablemente es una buena idea para utilizar una ruta absoluto.
+
+
+Phind.suffixmode:El parÃ¡metro smode para el programa de extracciÃ³n de frase. Un valor de 0 significa que los stopwords serÃ¡n ignorados, y 1 significa que los stopwords serÃ¡n utilizadas.
+
+
+Phind.text:El texto utilizado para construir la jerarquÃ­a de la frase.
+
+
+Phind.thesaurus:El nombre de un thesaurus guardado en formato Phind en el directorio etc de la colecciÃ³n.
+
+
+Phind.title:El campo del metadata para describir cada documento.
+
+
+Phind.untidy:No elimine los archivos activos.
+
+
+SectionList.desc:Igual que el clasificador de la lista pero incluye todas las secciones del documento (excluyendo el nivel superior) y no sÃ³lo el propio documento del nivel superior.
+
+Collage.buttonname:Etiqueta para clasificador de pantalla y botÃ³n en la barra de navegaciÃ³n.
+
+
+Collage.desc:El plugin clasificador del collage.
+
+
+Collage.geometry:Las dimensiones del lienzo del collage. Para un lienzo de 600 pixels de ancho y 400 pixels de alto, por ejemplo, especifique la geometrÃ­a como 600x400
+
+
+Collage.maxDepth:Las imÃ¡genes para el collage se dibujan mediante un espejo del clasificador de navegaciÃ³n subyacente. Esto controla la profundidad mÃ¡xima del proceso de espejo.
+
+
+Collage.maxDisplay:El mÃ¡ximo nÃºmero de imÃ¡genes a mostrar en el collage en cualquier momento.
+
+
+Collage.imageType:Utilizado para controlar, empleando las extensiones del nombre de archivo, cuales tipos de archivo se utilizan en el collage. Una lista de las extensiones del nombre de archivo se separa con el sÃ­mbolo (%%).
+
+
+Collage.bgcolor:El color de fondo del lienzo del collage, especificado en hexadecimal (por ejemplo, #008000 produce un fondo verde bosque).
+
+
+Collage.refreshDelay:Rata, en milisegundos, de refresco del lienzo del collage.
+
+
+Collage.isJava2:Utilizado para controlar cuales clases del run-time de Java se usan. Las versiones mÃ¡s avanzadas de Java (desde Java 1.2 en adelante) incluyen un soporte mas sofisticado para controlar la transparencia de las imÃ¡genes. Esta bandera ayuda a controlar los que pasa, sin embargo, el run-time de Java integrado con algunos navegadores es versiÃ³n 1.1. El applet estÃ¡ disÃ±ado, por defecto, para auto-detectar cual versiÃ³n de Java estÃ¡ utilizando el navegador y actuar en conformidad.
+
+
+Collage.imageMustNotHave:Utilizado para suprimir las imÃ¡genes que no deben aparecer en el collage, tales como las imÃ¡genes de los botones que forman la barra de navegaciÃ³n.
+
+
+Collage.caption:TÃ­tulos opcionales para desplegar bajo el lienzo del collage.
+
+
+#
+# Plugin option descriptions
+#
+
+ArcPlug.desc:Plugin que reproduce a travÃ©s de un archivo de archivos.inf file (es decir el archivo generado en el directorio de archivos cuando realiza una importaciÃ³n), procesando cada archivo que encuentra.
+
+
+BasPlug.adding:agregando
+
+
+BasPlug.already_seen:ya ha sido visto
+
+
+BasPlug.bad_general_option:El % del plugin utiliza una opciÃ³n general incorrecta (las opciones generales estÃ¡n disponibles a todos los plugins). Revise su archivo de configuraciÃ³n collect.cfg.
+
+
+BasPlug.block_exp:Los archivos que sean igual a esta expresiÃ³n regular serÃ¡n bloqueados al pasarse a cualquier plugins posterior en el listado. Esto no tiene otro efecto real de manera que previene muchos mensajes de alerta sobre los archivos input que a usted no le interesen. Cada plugin podrÃ­a tener un block_exp predefinido, por ejemplo por defaul HTMLPlug bloquea cualquier archivo gif. jpg. jpeg. png o los archivos css.
+
+
+BasPlug.associate_ext:Hace que los archivos cuyos nombres contienen la misma parte inicial que el documento procesado por el plugin Y una extensiÃ³n que figura en la lista separada por comas que provee este argumento, sean asociados con el documento que se estÃ¡ procesando en vez de ser manejados como una lista separada.
+
+BasPlug.could_not_extract_encoding:ALERTA: codificando no podrÃ­an extraerse de % s - predefiniendo a % s
+
+
+BasPlug.could_not_extract_language:ALERTA: el idioma no podrÃ­a extraerse de % s - predefiniendo a % s
+
+
+BasPlug.could_not_open_for_reading:no podrÃ¡ abrir % s ni leerlos
+
+
+BasPlug.no_cover_image:No buscar un archivo prefix.jpg (en el cual prefix es el mismo prefix que el del archivo que estÃ¡ siendo procesado) y asociarlo como imagen de portada.
+
+
+BasPlug.default_encoding:Utilice esta codificaciÃ³n si -input_encoding estÃ¡ puesto en âautoâ y el algoritmo de categorizaciÃ³n de texto no puede extraer el cÃ³digo o extrae un cÃ³digo que Greenstone no soporte. Esta opciÃ³n puede tomar los mismos valores que -input_encoding.
+
+
+BasPlug.default_language:Si Greenstone no identifica el idioma del documento el elemento del metadata serÃ¡ colocado a este valor. El valor predeterminado es el 'en' (ISO 639 los sÃ­mbolos del idioma son: el en = inglÃ©s). Nota que si - el input_encoding no estÃ¡ en 'automÃ¡tico' y - el extract_language no estÃ¡ programado, todos los documentos tendrÃ¡n su 'Idioma' el metadata estÃ¡ programado a este valor.
+
+
+BasPlug.desc:La clase base para todos los plugins de importaciÃ³n.
+
+
+BasPlug.done_acronym_extract:terminÃ³ de extraer las siglas.
+
+
+BasPlug.done_acronym_markup:TerminÃ³ el marcado de sigla (o acrÃ³nimo).
+
+
+BasPlug.done_email_extract:terminÃ³ de extraer las direcciones electrÃ³nicas.
+
+
+BasPlug.dummy_text:Este documento no tiene contenido.
+
+
+BasPlug.empty_file:el archivo no contiene ningÃºn texto
+
+
+BasPlug.extract_acronyms:Extrae las siglas desde dentro el texto y las coloca como metadata.
+
+
+BasPlug.extract_email:Extrae direcciones de correo electrÃ³nico como metadata.
+
+
+BasPlug.extract_historical_years:Extrae informaciÃ³n periÃ³dica de documentos histÃ³ricos. Esto se guarda como documento de metadata. Existe un interfaz de bÃºsqueda para este metadata que usted puede incluir en su colecciÃ³n agregando la frase, âformat QueryInterface DateSearchâ a su archivo de configuraciÃ³n colectivo.
+
+
+BasPlug.extract_language:Identifica el idioma de cada documento y establece el 'Idioma' del metadata. Note que esto se harÃ¡ automÃ¡ticamente si - el input_encoding esta en 'automÃ¡tico'.
+
+
+BasPlug.extracting:extrayendo
+
+
+BasPlug.extracting_acronyms:extrayendo siglas
+
+
+BasPlug.extract_keyphrases:Extraer automÃ¡ticamente frases clave con Kea (opciones por defecto).
+
+BasPlug.extract_keyphrase_options:Opciones para extracciÃ³n de frases clave con Kea. Por ejemplo: mALIWEB - utilizar el modelo de extracciÃ³n ALIWEB; n5 - extraer 5 frases clave;, eGBK - utilizar codificaciÃ³n GBK.
+
+BasPlug.extracting_emails:extrayendo direcciones electrÃ³nicas	
+
+
+BasPlug.file_has_no_text:ERROR: % s no contiene texto alguno
+
+
+BasPlug.first:La coma separa el listado de primeros tamaÃ±os para extraer del texto en un campo del metadata. El campo se llama 'FirstNNN'.
+
+
+BasPlug.input_encoding:La codificaciÃ³n de los documentos de la fuente. Los documentos se convertirÃ¡n de estas codificaciones y se guardarÃ¡n internamente como utf8.
+
+BasPlug.input_encoding.ascii:Conjunto de 7 bits ascii simples. Ãste puede resultar mÃ¡s rÃ¡pido que usando el iso_8859_1. Tenga cuidado con usar esto en una colecciÃ³n de documentos que pueden contener caracteres fuera de los 7 ascii simples (por ejemplo documentos en AlemÃ¡n o FrancÃ©s que contengan acentos), mejor utilice el iso_8859_1.
+
+BasPlug.input_encoding.auto:Use el algoritmo de categorizaciÃ³n de texto para identificar la codificaciÃ³n de cada fuente de documento automÃ¡ticamente. Esto serÃ¡ mÃ¡s lento que poniendo la codificaciÃ³n explÃ­citamente pero trabajarÃ¡ en donde mÃ¡s de una codificaciÃ³n se use dentro de la misma colecciÃ³n.
+
+BasPlug.input_encoding.unicode:SÃ³lo unicode.
+
+BasPlug.input_encoding.utf8:Ya sea Utf8 o unicodeâdetectada automÃ¡ticamente
+
+
+BasPlug.keyphrases:frases clave
+
+
+BasPlug.marking_up_acronyms:marcando siglas
+
+
+BasPlug.markup_acronyms:Agregue el metadato de sigla en el texto del documento.
+
+
+BasPlug.maximum_century:El mÃ¡ximo siglo a que se hace referencia que serÃ¡ extraÃ­do como metadata histÃ³rico (por ejemplo 14 extraerÃ¡ todas las referencias hasta el siglo14).
+
+
+BasPlug.maximum_year:La fecha histÃ³rica mÃ¡xima a ser usada como metadata (en una fecha referida a un periÃ³do comÃºn, como 1950).
+
+
+BasPlug.must_be_implemented:La funciÃ³n de BasPlug::read deberÃ¡ ser implementada en la subclase para los plugins recursivos
+
+
+BasPlug.no_bibliography:No intente bloquear las fechas bibliogrÃ¡ficas al extraer las fechas histÃ³ricas.
+
+
+BasPlug.process_exp:La expresiÃ³n perl regular para igualar contra nombres de archivos. Para igualar nombres de archivo se procesarÃ¡n por este plugin. Por ejemplo, usando '(? i). html? \ $' aparecerÃ¡n todos los documentos con terminaciÃ³n. htm o el .html (caso-insensible).
+
+
+BasPlug.read_denied:Lea permiso negado para % s
+
+
+BasPlug.smart_block:Ablocar los archivos en una forma mÃ¡s inteligente que simplemente examinando sus nombres.
+
+BasPlug.stems:tallos (inicios, bases)
+
+
+BasPlug.unsupported_encoding:ALERTA: % s aparece para ser codificado en un cÃ³digo sin apoyo (% s) â usando % s
+
+
+BasPlug.wrong_encoding:ALERTA: %s fue leÃ­do utilizando la codificaciÃ³n %s pero parece haber sido codificado como % s.
+
+
+BibTexPlug.desc:BibTexPlug lee los archivos de bibliografÃ­a en el formato de BibTex. BibTexPlug crea un objeto del documento para cada referencia en el archivo. Es una subclase de SplitPlug, por lo que si hay archivos mÃºltiples, todos se leen.
+
+
+BookPlug.desc:Crea documentos multi-nivel a partir de documentos que contengan etiquetas de nivel <<TOC>>. El meta-dato para cada secciÃ³n se toma de cualquier otra etiqueta que estÃ© en la misma lÃ­nea que el << TOC >>, por ejemplo, <<Title>> xxxx <</Title>> establece el meta-dato Title. Todo lo demÃ¡s que aparezca entre las etiquetas TOC se tratarÃ¡ como html simple (es decir, no se establece ningÃºn proceso de vÃ­nculos html o cualquier otro tipo HTMLPlug). Espera que los archivos de entrada por defecto tengan una extensiÃ³n .hb (esto puede cambiarse agregando una opciÃ³n -process_exp), un archivo con el mismo nombre que el archivo hb pero con una extensiÃ³n .jpg se toma como la imagen de la portada (los archivos jpg son bloqueados por este plugin). BookPlug es una simplificaciÃ³n (y extensiÃ³n) del HBPlug utilizado por las colecciones de la Biblioteca de la Humanidad. BookPlug es mÃ¡s rÃ¡pido en tanto que  espera la entrada de archivos mÃ¡s limpios (La entrada a las colecciones de HDL contiene muchas etiquetas html adicionales alrededor de etiquetas << TOC >>, utiliza etiquetas << I >> para especificar las imÃ¡genes, y simplemente toma como meta-datos del TÃ­tulo todo el texto entre las etiquetas << TOC >> y el inicio del texto). Si usted estÃ¡ colocando mark-up en documentos para que sean desplegados de la misma manera que las colecciones HDL, use este plugin en lugar de HBPlug.
+
+
+ConvertToPlug.convert_to:Plugin convierte a TEXTO o HTML.
+
+ConvertToPlug.convert_to.html:Formato HTML
+
+ConvertToPlug.convert_to.text:Formato texto simple.
+
+
+ConvertToPlug.desc:El plugin se hereda por dichos plugins como WordPlug y PDFPlug. Facilita la conversiÃ³n de Ã©stos tipos de documentos ya sea HTML o TEXTO variable que le dice a ConvertToBasPlug cÃ³mo trabajar. Funciona heredando HTMLPlug o TEXTPlug dinÃ¡micamente basado en el argumento del plugin 'convert_to'. Si el argumento no estÃ¡ presente, el valor predeterminado es heredar HTMLPlug.
+
+
+ConvertToPlug.use_strings:Si estÃ¡ definido, una funciÃ³n de cadenas simple serÃ¡ llamada para extraer el texto si la conversiÃ³n de utilidad falla.
+
+
+ConvertToRogPlug.desc:Un plugin que hereda de RogPlug.
+
+
+DBPlug.desc:Usa de archivos desde una base de datos como documentos.
+
+
+DBPlug.title_sub:La substituciÃ³n de la expresiÃ³n para modificar cordÃ³n guardado como TÃ­tulo. Por ejemplo, utilizado por PSPlug para quitar PÃ¡gina 1 etc de texto usado como tÃ­tulo.
+
+
+EMAILPlug.desc:El lector del correo electrÃ³nico lee los archivos electrÃ³nicos.  Ãstos se nombran con un nÃºmero simple (es decir cuando ellos aparecen en las carpetas del maildir) o con la extensiÃ³n. mbx (para el mbox mande por correo el formato del archivo). el texto del \nDocument text: El texto del documento consiste en todo el texto despuÃ©s de la primera lÃ­nea en blanco en el documento. el \nMetadata (not DublÃ­n Core!):\n\t\$Headers Todo el contenido del Asunto content (opcional, no se almacenan si no se indica)\n\t\$Subject:  header\n\t\$To A: el header\n\t\$From De: los header\n\t\$FromName Nombran al remitente (donde los available)\n\t\$FromAddr Mandan electrÃ³nicamente a la direcciÃ³n de Fecha del sender\n\t\$DateText: los header\n\t\$Date Fecha: el tÃ­tulo en GSDL estructura (ejemplo: 19990924)
+
+
+EMAILPlug.no_attachments:No guarde los anexos del mensaje.
+
+
+EMAILPlug.headers:Almacenar encabezados de email como metadatos "Headers".
+
+
+EMAILPlug.split_exp:Un expresiÃ³n perl regular se utiliza para separar archivos que contengan muchos mensajes en documentos individuales.
+
+
+ExcelPlug.desc:Un plugin para importador los archivos de Microsoft Excel.
+
+
+FOXPlug.desc:Plugin para procesar un archivo Foxbase dbt. Este plugin proporciona la funcionalidad bÃ¡sica para leer los archivos dbt y dbf y procesa cada registro. Este plugin generales debe doblemente leÃ­do para una base de datos particular para procesar los campos apropiados en el archivo.
+
+
+GAPlug.desc:Procesa los documentos XML del GreenstoneArchive. Note que este plugin no realiza ninguna sintaxis verificativa (aunque el mÃ³dulo de XML::Parser prueba para buen-formateo). Se asume que los archivos de GreenstoneArchive conforman a su DTD.
+
+
+GISBasPlug.extract_placenames:Extraer del texto nombres de lugares y establecerlos como metadata. Requiere extensiÃ³n de Greenstone a GIS.
+
+GISBasPlug.gazetteer:Mirar para extrarer del texto nombres de lugares y establecerlos como metadata. Requiere extensiÃ³n de Greenstone a GIS.
+
+GISBasPlug.place_list:Al extractar ubicaciones, incluya la lista de nombres de lugares al comienzo del documento. Requiere extensiÃ³n de Greenstone a GIS.
+
+GMLPlug.desc:Plugin que procesa un formato en documento GML asume que las etiquetas gml estÃ¡n todos escritas en letras minÃºsculas.
+
+
+HBPlug.desc: Plugin que procesa un directorio de libro HTML. Este plugin se usa por las colecciones de la Biblioteca de Humanidades y no se ocupa de codificaciones de la entrada mas que de ascii o el ascii extendido. Este cÃ³digo es algo pesado y podrÃ­a hacerse correr mÃ¡s rÃ¡pidamente indudablemente, dejÃ¡ndolo en este estado espero animar a las personas para hagan sus colecciones utilizando el HBSPlug en cambio ;-)\n\nUse utilice HBSPlug si estÃ¡ creando una nueva colecciÃ³n y marcando a los archivos como las colecciones de la Biblioteca de Humanidades. HBSPlug acepta todas las codificaciones de entrada pero espera los archivos marcados sean mas limpios que aquellos usados por las colecciones de la Biblioteca de Humanidades
+
+
+HTMLPlug.assoc_files:ExpresiÃ³n Perl normal de las extensiones de archivo para asociar con documentos html.
+
+
+HTMLPlug.desc:Este plugin procesa archivos HTML
+
+
+HTMLPlug.description_tags:Divide el documento en las sub-secciones dÃ³nde aparecen las etiquetas de <SecciÃ³n>. Note que al utilizar esta opciÃ³n usted implÃ­citamente fija -no_metadata, cuando todos los metadata deben ser incluidos dentro de las etiquetas <SecciÃ³n>. TambiÃ©n, '-keep_head' no surtirÃ¡ efecto cuando esta opciÃ³n estÃ¡ definida.
+
+
+HTMLPlug.file_is_url:Utilice y ponga si los nombres de los archivos de la entrada constituyen el url de los documentos fuente originales, por ejemplo si una herramienta para espejos web fuera utilizada para crear la estructura del directorio de importaciÃ³n.
+
+
+HTMLPlug.hunt_creator_metadata:Localiza tantos metadatos como sea posible en autor y los coloca en el campo 'Creator'. Requiere la bandera de -metadata_fields (campos de metadata)
+
+
+HTMLPlug.keep_head:No elimine los tÃ­tulos de los archivos html.
+
+
+HTMLPlug.metadata_fields:Listado de campos de metadata separado por coma para intentar extraer. Use 'tag<tagname>' para tener los contenidos del primer par <tagname> en un elemento del metadata llamado 'tagname' (nombre de etiqueta). Ponga en mayÃºsculas esto si desea el metadata en mayÃºsculas en Greenstone, ya que la extracciÃ³n de la etiqueta no tiene la sensibilidad para hacerlo.
+
+
+HTMLPlug.no_metadata:No intente extraer metadata de los archivos.
+
+
+HTMLPlug.no_strip_metadata_html:Lista de nombres de metadatos separados por comas o 'all'. Utilizado con -description_tags, evita la supresiÃ³n de las etiquetas HTML de los valores de los metadatos especificados.
+
+
+HTMLPlug.nolinks:No se esfuerce por tomar links (poniendo esta bandera puede mejorar la velocidad para crear/importar pero cualquier link relativo dentro de los documentos se romperÃ¡).
+
+
+HTMLPlug.rename_assoc_files:Renombra archivos asociados con documentos (por ejemplo imÃ¡genes). TambiÃ©n crea mucha estructura de directorios de poco peso (Ãºtil al crear las colecciones cd-rom).
+
+
+HTMLPlug.title_sub:ExpresiÃ³n sustituta para modificar una cadena almacenada como TÃ­tulo. Usada, por ejemplo, en PDFPlug para eliminar "PÃ¡gina 1", etc de un texto usado como tÃ­tulo.
+
+
+ImagePlug.converttotype:Convertir la imagen principal al formato 's'.
+
+
+ImagePlug.desc:Este plugin procesa las imÃ¡genes, agregando el metadata bÃ¡sico
+
+
+ImagePlug.minimumsize:Ignore las imÃ¡genes menores que n bytes.
+
+
+ImagePlug.noscaleup:No sobreponga las imÃ¡genes pequeÃ±as al hacer thumbnails .
+
+
+ImagePlug.screenviewsize:Si estÃ¡ fijo, hace un imagen de tamaÃ±o n para el despliegue de la pantalla y fija el metadato de Pantalla, ScreenSize, (tamaÃ±o de pantalla) ScreenWidth (ancho de Pantalla) y ScreenHeight (altura de pantalla). No estÃ¡ predeterminado por defaul.
+
+
+ImagePlug.screenviewtype:Si - el screenviewsize (tamaÃ±o de lector de pantalla) estÃ¡ establecido, Ã©ste coloca el despliegue de imagen.
+
+
+ImagePlug.thumbnailsize:Realiza iconos pequeÃ±os tamaÃ±o nxn.
+
+
+ImagePlug.thumbnailtype:Realiza iconos pequeÃ±os en el formato 's'.
+
+
+IndexPlug.desc:Este plugin recursivo procesa un archivo index.txt. El archivo index.txt debe contener la lista de archivos que deberÃ¡n ser incluidos en la colecciÃ³n, seguida por cualesquiera meta-datos extras a ser asociados con cada archivo.\n\n El archivo index.txt debe estructurarse de la siguiente manera: La primera lÃ­nea puede ser una llave (empezando con key:)  para nombrar los archivos de meta-datos (por ejemplo, key: Asunto OrganizaciÃ³n Fecha). Las lÃ­neas siguientes contendrÃ¡n un nombre de archivo seguido por el valor que se asignarÃ¡ a la entrada del meta-dato. (por ejemplo, 'irma/iw097e 3.2 unesco 1993' asociarÃ¡ el meta-dato Asunto=3.2, OrganizaciÃ³n=unesco, y Fecha=1993 con el archivo irma/iw097e si se utilizÃ³ la lÃ­nea anterior)\n\n Note que si cualquiera de los campos de los meta-datos utiliza el plugin de clasificador de JerarquÃ­a, entonces el valor de ellos debe corresponder al primer campo (el descriptor) en el archivo de la clasificaciÃ³n apropiado.\n\nLos valores de los Meta-datos pueden nombrarse utilizando una etiqueta de manera separada (por ejemplo <Asunto>3.2) y esto prevalecerÃ¡ sobre cualquier nombre que se les haya asignado en la lÃ­nea que contiene la "key". Si no hay ninguna lÃ­nea que contenga una "key", cualquier valor sin nombre de los meta-datos se denominarÃ¡ 'Asunto'.
+
+
+ISISPlug.desc:Este plugin procesa las bases de datos CDS/ISIS. Por cada base de datos CDS/ISIS procesada deberÃ¡n existir tres archivos en la carpeta de importaciÃ³n de la colecciÃ³n: el archivo Maestro (.mst), la Tabla de DefiniciÃ³n de Campos (.fdt) y el Archivo de Referencias Cruzadas (.xrf)
+
+
+ISISPlug.subfield_separator:La cadena de caracteres que se usa para separar subcampos en los registros de la base de datos CDS/ISIS.
+
+
+ISISPlug.entry_separator:La cadena de caracteres que se usa para separar mÃºltiples valores en los campos de metadatos de los registros de la base de datos CDS/ISIS.
+
+
+LaTeXPlug.desc:Plugin para documentos LaTeX.
+
+
+MACROPlug.desc:Crea el documento simple-nivelado. Agrega TÃ­tulo de metadata en primera lÃ­nea de texto (hasta 100 caracteres).
+
+
+MARCPlug.desc:Plugin MARC bÃ¡sico.
+
+
+MARCPlug.metadata_mapping:Nombre de archivo que incluye la cartografÃ­a detallada de valores MARC para los nombres de los metadatos de Greenstone. Predetermina a 'marctodc.txt' encontrado en el directorio etc del sitio.
+
+
+MetadataPass.desc:Clase base paralela a BasPlug que soporta plugins de metadata y usa el paso metadata_read de import.pl
+
+GISBasPlug.desc:Clase base paralela a BasPlug que soporta capacidades de GIS
+
+NULPlug.desc:Plugin de archivo postizo (.nul). Utilizado con los archivos producidos al explotar los archivos de la base de datos de metadatos.
+
+OAIPlug.desc:Plugin Inicio de Archivos Abiertos BÃ¡sicos (OAI)
+
+
+OggVorbisPlug.add_technical_metadata:AÃ±adir metadatos tÃ©cnicos (ej. bitrate)
+
+
+OggVorbisPlug.desc:Plugin para importar archivos de audio Ogg Vorbis.
+
+
+PagedImgPlug.desc:El plugin para documentos consiste de secuencias de imÃ¡genes, con texto opcional de OCR para cada imagen.
+
+
+PagedImgPlug.documenttype:Establecer el tipo de documento (usado para despliegue)
+
+PagedImgPlug.documenttype.paged:Los documentos paginados tienen flechas "siguiente" y "anterior", asÃ­ como una opciÃ³n para "ir a la pÃ¡gina X"
+
+PagedImgPlug.documenttype.hierarchy:Los documentos jerÃ¡rquicos tienen una tabla de contenido
+
+
+PagedImgPlug.headerpage:AÃ±adir una cabecera de pÃ¡gina de nivel principal (que no contenga imagen) a cada documento.
+
+
+PagedImgPlug.screenview:Producir una imagen "screenview"  para cada imagen, asÃ­ como metadatos Screen, ScreenSize, ScreenWidth y ScreenHeight.
+
+
+PagedImgPlug.screenviewsize:Producir imÃ¡genes "screenview" de tamaÃ±o nxn.
+
+
+PagedImgPlug.screenviewtype:Producir imÃ¡genes "screenview" en formato 's'.
+
+
+PagedImgPlug.thumbnail:Producir una vista en miniatura de cada imagen
+
+
+PDFPlug.complex:Crea un output mÃ¡s complejo. Con esta opciÃ³n fijada los html resultantes se parecerÃ¡n mucho mÃ¡s al archivo PDF original. Para el apropiado funcionamiento Ghostscript instalado (para *nix gs deben estar en su trazado mientras que para windows se debe tener gswin32c.exe).
+
+
+PDFPlug.desc:Razonablemente con un plugin pdf.
+
+
+PDFPlug.nohidden:Prevenga al pdftohtml de intentar extraer texto oculto. Esto sÃ³lo es Ãºtil si la opciÃ³n -complex estÃ¡ determinada.
+
+
+PDFPlug.noimages:No intente extraer las imÃ¡genes de PDF.
+
+
+PDFPlug.use_sections:Cree una secciÃ³n separada para cada pÃ¡gina del archivo de PDF.
+
+
+PDFPlug.zoom:El factor por el cual se hace acercamiento al PDF para la salida (esto sÃ³lo es Ãºtil si el -complex esta determinado).
+
+
+PPTPlug.desc:Un plugin para importar archivos de PowerPoint Microsoft.
+
+
+PSPlug.desc:Este es un ps \"poor manâs\" para convertidor de texto. Si si plan es serio, considere utilizar el paquete PRESCRIPT, para bajarlo lo podrÃ¡ encontrar en http://www.nzdl.org/html/software.html
+
+
+PSPlug.extract_date:Extrae la fecha del encabezado de PS.
+
+
+PSPlug.extract_pages:Extrae las pÃ¡ginas del encabezado de PS.
+
+
+PSPlug.extract_title:Extrae el encabezado de PS inicial.
+
+
+RecPlug.desc:RecPlug es un plugin que recorre a travÃ©s de directorios procesando cada archivo encontrado.
+
+
+RecPlug.recheck_directories:DespuÃ©s de procesar los archivos en un directorio de importaciÃ³n, vuelva a leer el directorio para descubrir los nuevos archivos creados.
+
+
+RecPlug.use_metadata_files:Lea el metadato archivos de XML metadata.
+
+
+ReferPlug.desc:ReferPlug lee archivos bibliogrÃ¡ficos en formato Refer.
+
+
+ReferPlug.longdesc:ReferPlug lee archivos bibliogrÃ¡ficos en formato Refer.\nBy Gordon W. Paynter (gwp\@cs.waikato.ac.nz), Noviembre 2000\n\nLoosely basado en el hcibib2Plug por Steve Jones (stevej\@cs.waikato.ac.nz). Que a su vez estaba basado en EMAILPlug por Gordon Paynter (gwp\@cs.waikato.ac.nz). Basado en las versiones anteriores de HTMLplug y HCIBIBPlugby por Stefan Boddie y otros--es difÃ­cil decir quÃ© viene de dÃ³nde, ahora .\n\nReferPlug crea un objeto del documento para cada referencia en el archivo. Es una subclase de SplitPlug, por lo que si hay archivos mÃºltiples, todos se leen .\n\nDocument text:\n\t El texto del documento consiste en la referencia en Refer format .\nMetadata:\n\t\$Creator \% A Autor name\n\t\$Title del Autor \% T Titulo de artÃ­culo de book\n\t\$Journal \%J Titulo de Journal\n\t\$Booktitle \%B Titulo de libro que contiene publicaciÃ³n publication\n\t\$Report \%R Tipo de Informe, ponencia o tesis thesis\n\t\$Volume \%V NÃºmero de Volumen Journal\n\t\$Number \%N NÃºmero de Revista dentro de volumen Volume\n\t\$Editor \%E Nombre del Editor name\n\t\$Pages \%P NÃºmero de hojas en artÃ­culo de article\n\t\$Publisher \%I Nombre de editor Publisher\n\t\$Publisheraddr \% address\n\t\$Fecha de PublicaciÃ³n C \% D fecha de publicaciÃ³n publication\n\t\$Keywords \% las Palabras claves de la publicaciÃ³n\n\t\$Abstract \%X Abstract de la publicaciÃ³n\n\t\$Copyright\t \% * informaciÃ³n de derechos de propiedad literaria para el artÃ­culo
+
+
+RogPlug.desc:Crea los documentos simples single-level (de nivel Ãºnico) a partir de archivos .rog o .mdb.
+
+
+RTFPlug.desc:Plugin para importar archivos de Formato Rich Text.
+
+
+SRCPlug.desc:Nombre de Archivo utilizado actualmente para TÃ­tulo (opcionalmente menos algÃºn prefijo). Languages actuales:\ntextl: READMEs/Makefiles\nC/C++ (actualmente los extractos #incluye las declaraciones y clase C++ decls)\nPerl (actualmente sÃ³lo elaborado como texto)\nShell (actualmente sÃ³lo elaborado como texto)
+
+
+SRCPlug.remove_prefix:Elimine este modelo principal del nombre del archivo (eg - remove_prefix /tmp/XX/src/). El valor predeterminado es eliminar la ruta completa del nombre del archivo.
+
+
+SplitPlug.desc:SplitPlug es un plugin para los archivos de entrada que divide en segmentos que se procesarÃ¡n de manera individual. Este plugin no debe llamarse de manera directa.  En cambio, si usted necesita procesar archivos input que contienen varios documentos, debe escribir un plugin con una funciÃ³n de proceso que manejarÃ¡ uno de esos documentos habiÃ©ndolo tomado de SplitPlug. Vea ReferPlug para un ejemplo.
+
+
+SplitPlug.split_exp:La expresiÃ³n perl regular para separar la entrada de archivos en segmentos.
+
+
+TEXTPlug.desc:Crea un documento simple de nivel Ãºnico (single-level). Agrega el metadato TÃ­tulo de la primera lÃ­nea de texto (hasta 100 caracteres).
+
+
+TEXTPlug.title_sub:ExpresiÃ³n de substituciÃ³n para modificar la cadena guardada como TÃ­tulo. Por ejemplo, PSPlug para eliminar "PÃ¡gina 1" etc del texto utilizado como tÃ­tulo.
+
+
+UnknownPlug.assoc_field:El nombre del campo del metadata que sostendrÃ¡ el nombre del archivo asociado.
+
+
+UnknownPlug.desc:Ãste es un Plugin simple para los archivos importados en los formatos que Greenstone no tiene. Un documento de ficciÃ³n serÃ¡ creado para cada uno de esos archivos, y el propio archivo se pasarÃ¡ a Greenstone como archivo asociado \âassociated file\â del documento.
+
+
+UnknownPlug.file_format:Tipo de archivo (ej: MPEG, MIDI, âŠ)
+
+
+UnknownPlug.mime_type:Tipo mime del archivo (por ejemplo image/gif).
+
+
+UnknownPlug.process_extension:Procesar archivos con esta extensiÃ³n de archivo. Esta oopciÃ³n es una alternativa a process_exp mÃ¡s sencilla de usar pero menos flexible.
+
+
+MP3Plug.desc:Plugin para procesar archivos MP3.
+
+
+MP3Plug.assoc_images:Use google image search to locate images related to MP3 file based on ID3 Title and Artist metadata.
+
+MP3Plug.assoc_images:Usado para almacenar [applet] metadatos para cada documento que contiene el HTML necesario para que un applet de audio MP3 pueda reproducir ese archivo.
+
+
+MP3Plug.metadata_fields:Lista de campos de metadatos separados por comas, a extraer (asumiendo los existentes) de un archivo MP3. Use \"*\" para extraer todos los campos.
+
+
+W3ImgPlug.aggressiveness:El rango de tÃ©cnicas de extracciÃ³n de textos relacionados a utilizar.
+
+W3ImgPlug.aggressiveness.1:Nombre de Archivo, ruta, ALT sÃ³lo texto.
+
+W3ImgPlug.aggressiveness.2:Todos de 1, mÃ¡s el subtÃ­tulo si hubiese disponible.
+
+W3ImgPlug.aggressiveness.3:Todos de 2, mÃ¡s los pÃ¡rrafos disponibles.
+
+W3ImgPlug.aggressiveness.4:Todos de 3, mÃ¡s los encabezados anteriores (<h1>, <h2>...) disponibles.
+
+W3ImgPlug.aggressiveness.5:Todos de 4, mÃ¡s las referencias textuales disponibles.
+
+W3ImgPlug.aggressiveness.6:Todos de 4, mÃ¡s la metaetiqueta de la pÃ¡gina (tÃ­tulo, las palabras clave, etc).
+
+W3ImgPlug.aggressiveness.7:Todos de 6, 5 y 4 combinados.
+
+W3ImgPlug.aggressiveness.8:Todos de 7, mÃ¡s la repeticiÃ³n de subtÃ­tulo, el nombre del archivo, etc (la clasificaciÃ³n jerÃ¡rquica de resultados mÃ¡s relevantes).
+
+W3ImgPlug.aggressiveness.9:Todos de 1, mÃ¡s el texto completo de la pÃ¡gina fuente.
+
+
+W3ImgPlug.caption_length:La longitud mÃ¡xima de subtÃ­tulos (en caracteres).
+
+
+W3ImgPlug.convert_params:ParÃ¡metros adicionales para la que ImageMagicK convierta el Ã­cono. Por ejemplo, '-raise' darÃ¡ un efecto tridimensional a las imÃ¡genes en miniatura.
+
+
+W3ImgPlug.desc:Plugin para extraer imÃ¡genes y el texto asociado de pÃ¡ginas web.
+
+
+W3ImgPlug.document_text:Agrega el texto de imagen como document:text (por otra parte los metadata de IndexedText se presentan).
+
+
+W3ImgPlug.index_pages:Indice las pÃ¡ginas junto con las imÃ¡genes. Por otra parte referencia las pÃ¡ginas a la fuente URL.
+
+
+W3ImgPlug.max_near_text:Caracteres mÃ¡ximos cerca de las imÃ¡genes a extraer.
+
+
+W3ImgPlug.min_height:Pixeles. Salta las imÃ¡genes mÃ¡s pequeÃ±as que Ã©sta.
+
+
+W3ImgPlug.min_near_text:Caracteres mÃ­nimos cerca del texto o subtitulo para extraer.
+
+
+W3ImgPlug.min_size:Bytes. Brinca las imÃ¡genes mÃ¡s pequeÃ±as que estas.
+
+
+W3ImgPlug.min_width:Pixeles. Salta imÃ¡genes mas breves que Ã©sta.
+
+
+W3ImgPlug.neartext_length:Longitud designada del texto mas cercano (en caracteres)
+
+
+W3ImgPlug.no_cache_images:No esconda las imÃ¡genes (apunte al URL original).
+
+
+W3ImgPlug.smallpage_threshold:ImÃ¡genes en las pÃ¡ginas mÃ¡s pequeÃ±as que esto (los bytes) tendrÃ¡n la pÃ¡gina (el tÃ­tulo, las palabras claves, etc) con meta-datos agregados.
+
+
+W3ImgPlug.textrefs_threshold:El umbral para las referencias textuales. Los valores mÃ¡s bajos significan que el algoritmo es menos estricto.
+
+
+W3ImgPlug.thumb_size:Max el tamaÃ±o en miniatura. Ambos ancho y altura.
+
+
+WordPlug.desc:Plugin importador para los documentos de Microsoft Word.
+
+
+XMLPlug.desc:La clase base para plugins XML.
+
+
+ZIPPlug.desc:Plugin que se ocupa de los formatos comprimidos y/o archivados de entrada los formatos actualmente manejados y las extensiones de archivo son are:\ngzip de (.gz. z. el tgz. taz)\nbzip (.bz)\nbzip2 (.bz2)\nzip (.zip. .jar)\ntar\n\n Este plugin confÃ­a en las utilerÃ­as siguientes que estÃ¡n presentes (si estÃ¡ intentando procesar formatos correspondientes) :\ngunzip (para gzip)\nbunzip (para bzip)\nbunzip2 \nunzip (para zip)\ntar (para tar)
+
+
+
+#
+# Perl module strings
+#
+
+classify.could_not_find_classifier:ERROR: no encontrÃ³ el clasificador \â% s\â
+
+
+plugin.could_not_find_plugin:ERROR: No podrÃ¡ encontrar el plugin \"% s\"
+
+
+plugin.including_archive:inclusive los volÃºmenes de 1 archivo de ZIP/TAR
+
+
+plugin.including_archives:inclusive los volÃºmenes de %d los archivos de ZIP/TAR
+
+
+plugin.kill_file:Proceso finiquitados por el archivo .kill
+
+
+plugin.n_considered:%d de los documentos fueron considerados a efecto de ser procesados
+
+
+plugin.n_included:%d se procesaron e incluidos en la colecciÃ³n
+
+
+plugin.n_rejected:%d rechazados
+
+
+plugin.n_unrecognised:%d no fueron reconocidos
+
+
+plugin.no_plugin_could_process:ADVIRTIENDO: NingÃºn plugin podrÃ¡ ser procesado %s
+
+
+plugin.no_plugin_could_recognise:ATENCIÃN: NingÃºn plugin pudo reconocer %s
+
+
+plugin.no_plugin_could_process_this_file:ningÃºn plugin podrÃ¡ procesar este archivo
+
+
+plugin.no_plugin_could_recognise_this_file:ningÃºn plugin pudo reconocer este archivo
+
+
+plugin.one_considered:1 documento fue considerado a efecto de ser procesado
+
+
+plugin.one_included:1 fue procesado e incluido en la colecciÃ³n
+
+
+plugin.one_rejected:1 fue rechazado
+
+
+plugin.one_unrecognised:1 no fue reconocido
+
+
+plugin.see_faillog:Vea en %s una lista de documentos no reconocidos y/o rechazados
+
+
+PrintUsage.default:Valor predeterminado (default)
+
+
+PrintUsage.required:REQUERIDO
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/strings_fr.rb
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/strings_fr.rb	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/strings_fr.rb	(revision 10506)
@@ -0,0 +1,1269 @@
+#
+# Resource bundle description
+#
+
+Language.code:fr
+
+Language.name:FranÃ§ais
+
+
+OutputEncoding.unix:iso_8859_1
+
+OutputEncoding.windows:iso_8859_1
+
+
+
+#
+# Common output messages
+#
+
+common.cannot_create_file:ERREUR: impossible de crÃ©er le fichier %s
+
+
+common.cannot_find_cfg_file:ERREUR: fichier de configuration introuvable %s
+
+
+common.cannot_open:ERREUR: impossible d'ouvrir %s
+
+
+common.cannot_open_fail_log:ERREUR: Impossible d'ouvrir le log d'Ã©chec %s
+
+
+common.cannot_open_output_file:ERREUR: impossible d'ouvrir le fichier output %s
+
+
+common.cannot_read:ERREUR: impossible de lire %s
+
+
+common.cannot_read_file:ERREUR: impossible de lire le fichier %s
+
+
+common.general_options:options gÃ©nÃ©rales (pour %s)
+
+
+common.must_be_implemented:fonction doit Ãªtre implÃ©mentÃ©e dans sous-classe
+
+
+common.options:options
+
+
+common.processing:traitement
+
+
+common.specific_options:options spÃ©cifiques
+
+
+common.usage:utilisation
+
+
+
+#
+# Script option descriptions and output messages
+#
+
+scripts.language:Langue dans laquelle les descriptions d'option sont affichÃ©es (ex. 'en_US' spÃ©cifie l'anglais amÃ©ricain). NÃ©cessite des traductions des descriptions d'options qui sont prÃ©sentes dans le fichier perllib/strings_language-code.rb.
+
+
+scripts.xml:Produit l'information sous forme XML, sans 'jolis' commentaires mais avec beaucoup plus de dÃ©tails.
+
+
+scripts.listall:Liste tous les Ã©lÃ©ments connus.
+
+
+
+# -- buildcol.pl --
+
+buildcol.archivedir:LÃ  oÃ¹ se trouvent les archives.
+
+
+buildcol.builddir:LÃ  oÃ¹ mettre les indexes construits.
+
+
+buildcol.cachedir:La collection sera temporairement construite ici avant d'Ãªtre copiÃ©e dans le le rÃ©pertoire de construction.
+
+
+buildcol.cannot_open_cfg_file:ATTENTION: Impossible d'ouvrir le fichier de configuration pour mise Ã  jour: %s
+
+
+buildcol.collectdir:RÃ©pertoire de la collection.
+
+
+buildcol.copying_back_cached_build:Recopie de la construction mise en cache
+
+
+buildcol.create_images:Tente de crÃ©er des images par dÃ©faut pour la nouvelle collection. Cela dÃ©pend de l'installation de Gimp en mÃªme temps que les modules qui vont avec pour permettre l'Ã©criture de scripts Ã  partir de perl.
+
+
+buildcol.debug:Imprimer la sortie sur STDOUT.
+
+
+buildcol.desc:Script PERL utilisÃ© pour bÃ¢tir une collection Greenstone Ã  pertir de documents GML.
+
+
+buildcol.faillog:Nom de fichier log d'Ã©chec. Ce fichier log reÃ§oit les noms de fichiers de tous les fichiers qu'on n'a pas pu traiter.
+
+
+buildcol.index:Index Ã  construire (va construire toust dans le fichier de configuration si pas dÃ©fini).
+
+
+buildcol.keepold:Ne dÃ©truira pas les contenus actuels du rÃ©pertoire de construction.
+
+
+buildcol.maxdocs:Nombre maximum de documents Ã  construire.
+
+
+buildcol.mode:Les parties du processus de construction Ã  mener.
+
+buildcol.mode.all:Tout faire.
+
+buildcol.mode.build_index:Indexer le texte uniquement.
+
+buildcol.mode.compress_text:Compresser le texte uniquement.
+
+buildcol.mode.infodb:Construire la base de donnÃ©es des mÃ©ta-donnÃ©es uniquement.
+
+
+buildcol.no_default_images:Des images par dÃ©faut ne seront gÃ©nÃ©rÃ©es.
+
+
+buildcol.no_image_script:ATTENTION: script de fabrication d'images introuvable: %s
+
+
+buildcol.no_strip_html:Ne pas enlever les balises html du texte indexÃ© (utilisÃ© seulement pour les collections mgpp).
+
+
+buildcol.no_text:Ne pas stocker de texte compressÃ©. Cette option est utile pour la rÃ©duction de la taille des indexes incorporÃ©s si vous voulez toujours afficher les documents originaux en temps voulu (c'est Ã  dire que vous ne pouvez pas retrouver la version du texte compressÃ©).
+
+
+buildcol.out:Nom de fichier ou de contrÃŽle vers lequel envoyer le statut de sortie.
+
+
+buildcol.params:[options] nom de collection
+
+
+buildcol.remove_empty_classifications:Cacher les nÅuds de classeurs et classification (ceux qui sont vides, sans documents)
+
+
+buildcol.unlinked_col_images:Les images de la collection peuvent ne pas Ãªtre correctement Ãªtre liÃ©es.
+
+
+buildcol.unknown_mode:Mode inconnu: %s
+
+
+buildcol.updating_archive_cache:Mise Ã  jour du cache d'archive
+
+
+buildcol.verbosity:ContrÃŽle la quantitÃ© de sortie. 0=aucun, 3= beaucoup.
+
+
+
+# -- classinfo.pl --
+
+classinfo.collect:En donnant un nom Ã  la collection fera que classinfo.pl va regarder d'abord dans collect/nom-de-collection/perlib/classify. Si le classificateur n'est pas trouvÃ©, il va alors chercher dans le rÃ©pertoire gÃ©nÃ©ral perlib/classify.
+
+
+classinfo.desc:Impime l'information sur un classificateur.
+
+
+classinfo.general_options:Options gÃ©nÃ©rales hÃ©ritÃ©es de classes parentes du classificateur.
+
+
+classinfo.info:info
+
+
+classinfo.no_classifier_name:ERREUR: Vous devez donner un nom de classificateur.
+
+
+classinfo.option_types:Les classificateurs peuvent prendre deux types d'options
+
+
+classinfo.params:[options] nom de classificateur
+
+
+classinfo.passing_options:Les options peuvent Ãªtre passÃ©es Ã  tout classificateur en les intÃ©grant au fichier de configuration de votre collection collect.cfg.
+
+
+classinfo.specific_options:Les options spÃ©cifiques sont dÃ©finies dans le classificateur lui mÃªme, et sont disponibles seulement pour ce classificateur particulier.
+
+
+# -- explode_metadata_database.pl --
+explode.desc:Ãclater la base de donnÃ©es mÃ©ta-donnÃ©es.
+
+explode.document_field:L'Ã©lÃ©ment de metadata indiquant le nom de fichier des documents Ã  obtenir et inclure dans la collection.
+
+
+explode.document_prefix:PrÃ©fixe pour localiser les documents (s'utilise avec l'option "document_field").
+
+
+explode.document_suffix:Suffixe pour localiser les documents (s'utilise avec l'option "document_field").
+
+
+explode.encoding:Encodage Ã  utiliser lors de la lecture de la base de donnÃ©es
+explode.filename_field:Champ Ã  utiliser pour les noms de fichier factices (null) gÃ©nÃ©rÃ©s (si pas de document_field ou ce champ est vide)
+explode.metadata_set:Jeu mÃ©ta-donnÃ©es (espace nom) pour exporter toutes les mÃ©ta-donnÃ©es comme
+explode.plugin:Plugin Ã  utiliser pour Ã©clater
+explode.params:[options] nom de fichier
+# -- exportcol.pl --
+
+exportcol.out:Nom de fichier ou de contrÃŽle vers lequel envoyer le statut de sortie.
+
+exportcol.cdname:Le nom du CD-ROM -- c'est ce qui va apparaÃ®tre dans le menu de dÃ©marrage une fois que le CD-ROM est installÃ©.
+
+exportcol.desc:Script PERL utilisÃ© pour exporter une ou plusieurs collections vers un CD-ROM Windows.
+
+exportcol.params:[options] nom de collection1 nom de collection 2âŠ
+
+exportcol.coll_not_found:Collection non valide %s ignorÃ©e: collection introuvable Ã  %s.
+
+exportcol.coll_dirs_not_found:Collection non valide %s ignorÃ©e: l'un des rÃ©pertoires suivants n'a pas Ã©tÃ© trouvÃ©:
+
+exportcol.fail:echec de export.pl:
+
+exportcol.no_valid_colls:Pas de collection valide spÃ©cifiÃ©e pour exportation
+
+exportcol.couldnt_create_dir:N'a pas pu crÃ©er rÃ©pertoire %s.
+
+exportcol.couldnt_create_file:N'a pas pu crÃ©er %s.
+
+exportcol.instructions:Pour crÃ©er un CD-ROM d'auto-installation pour Windows, Ã©crire les contenus de ce fichier dans un CD-ROM.
+
+exportcol.non_exist_files:Un ou plusieurs des fichiers et rÃ©pertoires nÃ©cessaires suivants n'existent pas:
+
+exportcol.success:succÃšs de export.pl:
+
+exportcol.output_dir:Les collections exportÃ©es (%s) sont dans %s.
+
+exportcol.nonetscape:Ne mettez pas netscape sur le CD-ROM
+exportcol.export_coll_not_installed:La fonctionnalitÃ© de 'Exporter vers CD-Rom' n'a pas Ã©tÃ© installÃ©e.
+
+
+# -- import.pl --
+
+import.archivedir:LÃ  oÃ¹ finissent le matÃ©riau converti.
+
+
+import.cannot_open_stats_file:ATTENTION: impossible d'ouvrir le fichier stats %s.
+
+
+import.cannot_open_fail_log:Erreur: N'a pas pu ouvrir le journal des Ã©checs %s
+
+
+import.cannot_sort:ATTENTION: le plugin d'importation ne peut pas trier les documents si groupsize > 1. L'option sortmeta sera ignorÃ©e.
+
+
+import.collectdir:RÃ©pertoire de la collection.
+
+
+import.complete:Fin de l'importation.
+
+
+import.debug:Imprimer le texte importÃ© vers STDOUT.
+
+
+import.desc:Script PERL utilisÃ© pour importer les fichiers dans le formÃ¹at GML prÃªt pour la construction.
+
+
+import.faillog:Nom de fichier du log d'Ã©chec. Ce log reÃ§oit les noms de fichier de tous les fichiers qui n'ont pas pu Ãªtre traitÃ©s
+
+
+import.groupsize:Nombre de documents importÃ©s Ã  regrouper dans un fichier XML.
+
+
+import.gzip:Utiliser gzip pour compresser les documents xml de sortie (ne pas oublier d'intÃ©grer ZIPPLug dans votre liste de plugins en construisant Ã  partir de documents compressÃ©s.
+
+
+import.importdir:lÃ  oÃ¹ se trouve le matÃ©riau original.
+
+
+import.keepold:Ne dÃ©truira pas les contenus actuels du rÃ©pertoire des archives (par dÃ©faut).
+
+
+import.maxdocs:Nombre maximum de documents Ã  importer.
+
+
+import.no_plugins_loaded:ERREUR: plugins non chargÃ©s
+
+
+import.OIDtype:La mÃ©thode Ã  utiliser pour produire des identificateurs uniques pour chaque document
+
+import.OIDtype.hash:Hache les contenus du fichier. L'identificateur du document sera le mÃªme Ã  chaque fois que la collection est importÃ©e.
+
+
+import.OIDtype.incremental:Un compteur de document simple beaucoup plus rapide que ''hash". Ce n'est pas garanti de toujours assigner le mÃªme identificateur Ã  un document donnÃ© et ne permet pas l'addition d'aures documents dans des archives xml existants.
+
+
+import.OIDtype.assigned:Utilise 'D' plus la valeur de ds.Idendifier comme identificateur de document. Dc.Identifier doit Ãªtre unique. Si aucun dc.Idenfier n'est associÃ© au document, un id calculÃ© sera utilisÃ©.
+
+import.OIDtype.dirname:Utilise 'J' plus le nom du rÃ©pertoire parent comme identificateur. Cela suppose qu'il y a juste un document par rÃ©pertoire, et que tous les noms de rÃ©pertoire sont uniques.C.a.d. import/b13as/h15ef/page.html obtiendra l'identificateur Jh15ef.
+"
+	
+source::plugin.one_unrecognised	"1 was unrecognised
+
+
+import.saveas:Format Ã  gÃ©nÃ©rer pour l'exportation. L'option par dÃ©faut est GA.
+
+
+import.saveas.GA:Va gÃ©nÃ©rer le format archive Greenstone.
+
+
+import.saveas.METS:Va gÃ©nÃ©rer le format METS
+
+
+import.out:Nom de fichier ou contrÃŽle vers lequel envoyer le statut.
+
+
+import.params:[options] nom de collection
+
+
+import.removeold:Va supprimer les anciens contenus du rÃ©pertoire d'archives -- Ã  utiliser avec prudence.
+
+
+import.removing_archives:Suppression des contenus du rÃ©pertoire d'archivesâŠ
+
+
+import.sortmeta:Trier les documents par ordre alphabÃ©tique et par mÃ©ta-donnÃ©e pour la construction. Ceci sera dÃ©sactivÃ© si groupsize > 1.
+
+
+import.statsfile:Nom de fichier ou contrÃŽle vers lequel envoyer les statistiques d'importation.
+
+
+import.stats_backup:Va plutÃŽt imprimer les stats vers STDERR.
+
+
+import.verbosity:ContrÃŽle la quantitÃ© de sortie. 0=aucun, 3=beaucoup.
+
+
+
+# -- export.pl --
+
+export.exportdir:Ou le matÃ©riel exportÃ© se termine
+
+
+export.cannot_open_stats_file:ATTENTION: Impossible d'ouvrir le fichier stats %s
+
+
+export.cannot_open_fail_log:ERREUR: Impossible d'ouvrir la log des Ã©checs %s
+
+
+export.cannot_sort:ATTENTION: export.pl ne peut trier les documents lorsque groupsize>1. L'option sortmeta sera ignorÃ©e.
+
+
+export.collectdir:RÃ©pertoire collection.
+
+
+export.complete:Exportation terminÃ©e
+
+
+export.debug:Imprimer le texte exportÃ© sur STDOUT.
+
+
+export.desc:Les scripts PERL utilisÃ©s pour importer des fichier dans un format GML sont prÃªts pour la construction
+
+
+export.faillog:Nom de fichier de la log des Ã©checs. Cette log reÃ§oit les noms de fichier de tous les fichiers qui n'ont pu Ãªtre traitÃ©.
+
+
+export.groupsize:Nombre de documents importÃ©s Ã  grouper dans un fichier XML.
+
+
+export.gzip:Utiliser gzip pour compresser les documents xml rÃ©sultats (Noubliez pas d'insÃ©rer ZIPPlug dans votre liste de plugins lorsque vous construisez Ã  partir de documents comprÃ©ssÃ©s.
+
+
+export.importdir:La ou le matÃ©riel original rÃ©side.
+
+
+export.keepold:Ne dÃ©truira pas les contenus du rÃ©pertoire "export" (par dÃ©faut) 
+
+
+export.maxdocs:Nombre maximum de documents Ã  importer.
+
+
+export.no_plugins_loaded:ERREUR: Pas de plugins chargÃ©s.
+
+
+export.OIDtype:MÃ©thode Ã  utiliser pour gÃ©nÃ©rer un identificateur unique pour chaque document.
+
+export.OIDtype.hash:Calculer une valeur ("hash") Ã  partir du contenu du fichier. L'idendificateur document restera le mÃªme Ã  chaque fois que la collection est importÃ©e. 
+
+export.OIDtype.incremental:Un comptage simple des documents plus rapdide que la mÃ©thode "hash". Cette mÃ©thode ne garantit pas d'affecter toujours le mÃªme identificateur Ã  un document donnÃ© et ne permet donc pas d'ajouter d'autres documents Ã  des archives xml existantes.
+
+
+export.saveas:Format Ã  gÃ©nÃ©rer pour l'exportation. L'option par dÃ©faut est METS.
+
+
+export.saveas.DSpace:Va gÃ©nÃ©rer le format archive DSPACE
+
+
+export.saveas.METS:Va gÃ©nÃ©rer le format METS
+
+
+export.out:Nom de fichier ou sortie pour imprimer l'Ã©tat.
+
+
+export.params:[options] nom-collection
+
+
+export.removeold:EnlÃ©vera le contenu du rÃ©pertoire "export" -- Ã  utiliser avec prÃ©caution.
+
+
+export.removing_export:Suppression des contenus du rÃ©pertoire exportâŠ
+
+
+export.sortmeta:Trier les documents en ordre alphabÃ©tique des mÃ©ta-donnÃ©es pour la construction. DÃ©sactivÃ© si groupsize > 1.
+
+
+export.statsfile:Nom de fichier ou sortie pour imprimer les statistiques d'exportation.
+
+
+export.stats_backup:Va imprimer les stats sur STDERR
+
+
+export.verbosity:ContrÃŽle du volume de sortie. 0=aucun, 3=beaucoup.
+
+
+
+# -- mkcol.pl --
+
+mkcol.about:Le texte Ã  propos pour la collection.
+
+
+mkcol.bad_name_cvs:ERREUR: Aucune collection ne peut Ãªtre nommÃ©e CVS car cela pourrait interfÃ©rer avec des rÃ©pertoires de gestion de version de CVS.
+
+
+mkcol.bad_name_modelcol:ERREUR: Aucune collection ne peut Ãªtre nommÃ©e modelcol puisque c'est le nom de la collection modÃšle.
+
+
+mkcol.cannot_find_modelcol:ERREUR: impossible de trouver la collection modÃšle %s
+
+
+mkcol.col_already_exists:ERREUR: Cette collection existe dÃ©jÃ .
+
+
+mkcol.collectdir:Le rÃ©pertoire dans lequel la nouvelle collection va Ãªtre crÃ©Ã©e.
+
+
+mkcol.creating_col:CrÃ©ation de la collection %s
+
+
+mkcol.creator:L'adresse e-mail du crÃ©ateur de la collection.
+
+
+mkcol.creator_undefined:ERREUR: Le crÃ©ateur n'a pas Ã©tÃ© dÃ©fini. Cette variable est nÃ©cesaire pour reconnaÃ®tre les noms de collection dupliquÃ©s.
+
+
+mkcol.desc:Script PERL utilisÃ© pour crÃ©er la structure de rÃ©pertoire pour une nouvelle collection Greenstone.
+
+
+mkcol.doing_replacements:en train d'effectuer des remplacements pour %s
+
+
+mkcol.long_colname:ERREUR: Le nom de collection doit Ãªtre de moins de 8 caractÃšres afin de maintenir la compatibilitÃ© avec des sytÃšmes prÃ©cÃ©dents.
+
+
+mkcol.maintainer:L'adresse e-mail du maintenancier de la collection (si diffÃ©rent du crÃ©ateur).
+
+
+mkcol.no_collectdir:ERREUR: Le rÃ©pertoire de la collection n'existe pas: %s
+
+
+mkcol.no_colname:ERREUR: Aucun nom de collection n'a Ã©tÃ© spÃ©cifiÃ©.
+
+
+mkcol.optionfile:Prendre des options Ã  partir du fichier, utile dans des systÃšmes oÃ¹ des longues lignes de commandes peuvent poser des problÃšmes.
+
+
+mkcol.params:[option] nom de collection
+
+
+mkcol.plugin:Module plugin Perl Ã  utiliser (il peut y avoir plusieurs entrÃ©es de plugins).
+
+
+mkcol.public:Si cette collection a des accÃšs anonymes (vrai/faux).
+
+
+mkcol.quiet:Fonctionne en silence.
+
+
+mkcol.success:La nouvelle collection a Ã©tÃ© crÃ©e avec succÃšs Ã  %s
+
+
+mkcol.title:Le titre de la collection
+
+
+mkcol.win31compat:Est-ce que les noms de rÃ©pertoires doivent suivre le modÃšle Windows 3.1 ou non (c.a.d. 8 caractÃšres max).
+
+
+# -- pluginfo.pl --
+
+pluginfo.collect:L'attribution d'un nom de colection fera que pluginfo.pl va rechercher d'abord dans collect/nom_de_collection/perllib/plugins. Si le plugin n'y est pas trouvÃ© il va alors chercher dans le rÃ©pertoire gÃ©nÃ©ral de logiciels/perlib.
+
+
+pluginfo.desc:Imprime l'information concernant un plugin.
+
+
+pluginfo.general_options:Les options gÃ©nÃ©rales sont hÃ©ritÃ©es des classes parentes du plugin.
+
+
+pluginfo.info:info
+
+
+pluginfo.no_plugin_name:ERREUR: Vous devez donner un nom de plugin.
+
+
+pluginfo.option_types:Les plugins peuvent prendre deux types d'options.
+
+
+pluginfo.params:[options] nom de plugin
+
+
+pluginfo.passing_options:Des options peuvent Ãªtre passÃ©es Ã  tous les plugins en les intÃ©grant dans votre fichier de configuration collect.cfg.
+
+
+pluginfo.specific_options:Les options spÃ©cifiques sont dÃ©finies au sein du plugin mÃªme, et sont disponibles uniquement pour ce plugin particulier.
+
+
+
+#
+# Classifier option descriptions
+#
+
+AZCompactList.allvalues:Utiliser toutes les valeurs de mÃ©ta-donnÃ©es trouvÃ©es.
+
+AZCompactList.desc:Plugin de classification pour tri par ordre alphabÃ©tique
+
+
+AZCompactList.doclevel:Niveau oÃ¹ le document est traitÃ©.
+
+AZCompactList.doclevel.top:Tout le document.
+
+AZCompactList.doclevel.section:Par sections.
+
+
+AZCompactList.firstvalueonly:Utiliser uniquement la premiÃšre valeure de mÃ©ta-donnÃ©e trouvÃ©e
+
+
+AZCompactList.freqsort:Classer par frÃ©quence nodale plutÃŽt que de maniÃšre alpha-numÃ©rique.
+
+
+AZCompactList.maxcompact:Nombre maximum de documents Ã  afficher par page.
+
+
+AZCompactList.metadata:Champ de mÃ©ta-donnÃ©e, ou liste de champs  de mÃ©ta-donnÃ©e sÃ©parÃ©s par des virgules, utilisÃ© pour la classification. Si une liste est spÃ©cifiiÃ©e, le premier type de mÃ©ta-donnÃ©e qui a une valeure sera utilisÃ©. Peut Ãªtre aussi utilisÃ© avec les options -firstvalueonly et -allvalues, pour sÃ©lectioner uniquement la premiÃšre valeur, ou toutes les valeurs de mÃ©ta-donnÃ©es de la liste.
+
+
+AZCompactList.mincompact:Nombre minimum de documents Ã  afficher par page.
+
+
+AZCompactList.mingroup:Valeur minimale qui va causer la formation d'un groupe dans la hierarchie.
+
+
+AZCompactList.minnesting:La valeur minimale qui va entraÃ®ner la conversion d'une liste en liste emboÃ®tÃ©e.
+
+
+AZCompactList.recopt:UtilisÃ© dans des mÃ©ta-donnÃ©es imbriquÃ©es tel que AnnÃ©e/Organisation
+
+AZCompactList.sort:Champ de mÃ©ta-donnÃ©e Ã  partir duquel les nÅuds fils seront triÃ©s.
+
+
+AZCompactSectionList.desc:Variation sur AZCompactList qui classifie des sections plutÃŽt que des documents. Les entrÃ©es sont triÃ©es par mÃ©ta-donnÃ©es de niveau section.
+
+
+AZList.desc:Plugin de classification pour le tri par ordre alphabÃ©tique
+
+
+AZList.metadata:Un champ de mÃ©ta-donnÃ©e unique ou une liste de champs de mÃ©ta-donnÃ©e sÃ©parÃ©s par des virgules utilisÃ© pour classification. En suivant l'ordre indiquÃ© par la liste, le premier champ qui contient  une valeur de mÃ©ta-donnÃ©e sera utilisÃ©. La liste sera triÃ©e suivant cet Ã©lÃ©ment.
+
+
+AZSectionList.desc:Plugin de classification pour classer par ordre alphabÃ©tique. Ceci est trÃšs similaire Ã  AZList sauf qu'il classe par niveau de mÃ©ta-donnÃ©es (en excluant le sommet) au lieu de ne considÃ©rer que les seules mÃ©ta-donnÃ©es des niveaux supÃ©rieurs. Le seul changement est au niveau sous-programme classify () qui doit procÃ©der Ã  une itÃ©ration Ã  travers chaque section, ajoutant chacune d'elle Ã  la classification.
+
+
+BasClas.bad_general_option:Le classificateur %s utilise une option gÃ©nÃ©rale incorrecte (les options gÃ©nÃ©rales sont celles qui sont disponibles pour tous les classificateurs). VÃ©rifiez votre fichier de configuration collect.cfg.
+
+
+BasClas.builddir:Endroit oÃ¹ les indexes construits vont Ãªtre mis.
+
+
+BasClas.buttonname:Le label pour l'Ã©cran et le bouton dans la barre de navigation du classificateur.
+
+
+BasClas.desc:Classe de base pour tous les classificateurs.
+
+
+BasClas.outhandle:Le fichier qui va recevoir les rÃ©sultats.
+
+
+BasClas.removeprefix:PrÃ©fixe Ã  ignorer dans les valeurs de mÃ©ta-donnÃ©es lors du tri. 
+
+BasClas.removesuffix:Suffixe Ã  ignorer dans les valeurs de mÃ©ta-donnÃ©es lors du tri.
+
+BasClas.verbosity:ContrÃŽle la quantitÃ© d'Ã©lÃ©ments produits. 0=aucun, 3=beaucoup.
+
+
+Browse.desc:.
+
+
+DateList.bymonth:Classifier par annÃ©e et par mois plutÃŽt que par annÃ©e seulement.
+
+
+DateList.desc:Plugin de classification utilisÃ© pour trier par date. Par dÃ©faut, trie suivant la mÃ©ta-donnÃ©e 'Date'. La date doit Ãªtre sous la forme yyyymmdd (aaaammjj).
+
+
+DateList.metadata:Le mÃ©ta-donnÃ©e contient qui contient les dates dont on se sert pour classissifier. Le format doit Ãªtre yyyymmdd (aaaammjj).
+
+
+DateList.reverse_sort:Trier les documents par ordre chronologique inverse (plus rÃ©cent en premier).
+
+
+DateList.nogroup:Faire de chaque annÃ©e une entrÃ©e individuelle dans la liste horizontale plutÃŽt que d'utiliser quelques entrÃ©es pour plusieurs annÃ©es
+
+
+DateList.sort:Champ de mÃ©ta-donnÃ©e supplÃ©mentaire pour le tri au oÃ¹ deux documents ont la mÃªme date.
+
+HFileHierarchy.desc:Plugin pour gÃ©nÃ©rer des classifications hiÃ©rarchiques basÃ© sur un fichier structurel supplÃ©mentaire.
+
+Hierarchy.hfile:Le fichier de structure de classificateur.
+
+Hierarchy.hlist_at_top:Affiche horizontalement le premier niveau de la classification.
+
+Hierarchy.reverse_sort:Trier les nÅuds feuilles en ordre inverse (utiliser avec -sort).
+
+Hierarchy.separator:Expression rÃ©guliÃšre utilisÃ©e pour le sÃ©parateur
+
+Hierarchy.sort:Champ de mÃ©ta-donnÃ©e suivant lequel trier. Utiliser '-sort nosort' pour dÃ©sactiver le tri.
+
+Hierarchy.suppresslastlevel:Ignorer la partie finale de la valeur de mÃ©ta-donnÃ©e. C'est particuliÃšrement utile pour des mÃ©ta-donnÃ©es dont chaque valeur est unique, telles que les chemins de fichiers.
+
+
+HTML.desc:CrÃ©e une classification vide qui qui est tout simplement un lien vers une page web.
+
+
+HTML.url:L'url de la page web de destination.
+
+
+List.desc:Plugin de classificateur de liste simple.
+
+
+List.metadata:Un champ de mÃ©ta-donnÃ©e unique ou une liste de champs de mÃ©ta-donnÃ©e sÃ©parÃ©s par des virgules utilisÃ© pour classification. En suivant l'ordre indiquÃ© par la liste, le premier champ qui contient  une valeur de mÃ©ta-donnÃ©e sera utilisÃ©. La liste va Ãªtre triÃ©Ã©e suivant cet Ã©lÃ©ment, Ã  moins que -sort soit utilisÃ©.
+
+
+List.sort:Champ de mÃ©ta-donnÃ©e suivant lequel trier. Utiliser '-sort nosort' pour dÃ©sactiver le tri.
+
+
+Phind.desc:Le plugin du classificateur Phind.
+
+
+Phind.language:Langue ou langues Ã  utiliser pour la construction d'une hiÃ©rarchie. Les langues sont identifiÃ©es par des codes de pays Ã  deux lettres comme en (anglais), es (espagnole), fr (franÃ§ais). Langue est une expression ordinaire, donc 'en|fr' (anglais ou franÃ§ais) et '..' (toute langue) sont valides.
+
+
+Phind.min_occurs:Le nombre minimum de fois qu'une phrase doit apparaÃ®tre dans le texte pour faire partie de la hiÃ©rarchie des phrases.
+
+
+Phind.savephrases:Lorsque dÃ©finie, l'information d'expression sera stockÃ©e comme texte dans le fichier spÃ©cifiÃ©. C'est probablement une bonne idÃ©e d'utiliser une chemin absolu.
+
+
+Phind.suffixmode:Le paramÃštre smode du programme d'extraction d'expression. Une valeur 0 signifie que les mots d'arrÃªt sont ignorÃ©s et 1 signifie que les mots d'arrÃªts sont utilisÃ©s.
+
+
+Phind.text:Le texte utilisÃ© pour construire la hierarchie d'expression.
+
+
+Phind.thesaurus:Nom d'un thÃ©saurus stockÃ© au format Phind dans le repertoire etc de la collection.
+
+
+Phind.title:Le champ de mÃ©ta-donnÃ©e utilisÃ© pour dÃ©crire chaque document.
+
+
+Phind.untidy:Ne pas supprimer les fichiers actifs.
+
+
+SectionList.desc:Comme le classificateur List, mais inclut toutes les sections du document (Ã  l'exception du niveau supÃ©rieur) plutÃŽt que le document de niveau supÃ©rieur seulement.
+
+Collage.buttonname:Le label pour l'Ã©cran et le bouton dans la barre de navigation du classificateur.
+
+Collage.desc:Le plugin du classeur de collage
+
+
+Collage.geometry:Les dimensions du fond de Collage.  Pour un fond de 600 pixels de large et 400 pixels de haut par example, indiquez la gÃ©omÃ©trie comme 600x400
+
+
+Collage.maxDepth:Les images pour le collage sont obtenues en reflÃ©tant ("mirroring") le classeur utilisÃ©. Ceci commande la profondeur maximum du processus de reflÃ©t ("mirroring").
+
+
+Collage.maxDisplay:Le nombre maximum d'images Ã  montrer dans le collage n'importe quand.
+
+
+Collage.imageType:UtilisÃ© pour contrÃŽler, en spÃ©cifiant les extensions de nom de fichier, quels types de fichier sont untilisÃ©s pour le collage. Une liste de noms de fichier est sÃ©parÃ©e par le caractÃšre pourcent (%%).
+
+Collage.bgcolor:La couleur d'arriÃšre plan de la toile de fond, indiquÃ©e sous forme hexadÃ©cimale (par exemple #008000 a comme consÃ©quence un arriÃšre plan vert forÃªt).
+
+
+Collage.refreshDelay:Taux, en millisecondes, de rafraichissement du fond de collage.
+
+
+Collage.isJava2:UtilisÃ© pour contrÃŽler l'utilisation des classes "Java runtime".  Les versions plus rÃ©centes de Java (c.-Ã -d. supÃ©rieures Ã  Java 1.2) incluent des fonctions plus avancÃ©es pour contrÃŽler la transparence des images, qui permettent un contrÃŽle plus fin, toutefois le "Java runtime"   intÃ©grÃ© dans certain navigateurs  est la version 1,1.  L'applet est conÃ§u pour dÃ©tecter automatiquement la version du "Java runtime" utilisÃ©e par le navigateur et rÃ©agir en consÃ©quence.
+
+
+Collage.imageMustNotHave:UtilisÃ© pour supprimer les images qui ne devraient pas apparaÃ®tre dans le collage, telles que les images des boutons qui composent la barre de navigation.
+
+
+Collage.caption:Sous-titres facultatifs Ã  afficher au-dessous de la toile de fond.
+
+
+#
+# Plugin option descriptions
+#
+
+ArcPlug.desc:Plugin rÃ©cursif Ã  travers un fichier archives.inf (ex: le fichier gÃ©nÃ©rÃ© par l'index des archives lorsqu'une importation est faite), traitant chaque fichier trouvÃ©.
+
+
+BasPlug.adding:ajout
+
+
+BasPlug.already_seen:dÃ©jÃ  vu
+
+
+BasPlug.bad_general_option:Le plugin %s utilise une option gÃ©nÃ©rale incomplÃšte (les options gÃ©nÃ©rales sont celles qui sont disponibles pour tous les plugins). VÃ©rifiez votre fichier de configuration collect.cfg.
+
+
+BasPlug.block_exp:Les fichiers qui correspondent Ã  cette expression ordinaire ne pourront pas Ãªtre passÃ©s Ã  d'autres plugins dans la liste. Cela n'a pas d'autres vÃ©ritables effets que d'empÃªcher qu'il y ait plusieurs messages d'avertissements concernant des fichiers d'entrÃ©e dont vous n'aurez pas Ã  vous soucier. Chaque plugin pourrait avoir un bloc_exp par dÃ©faut, p.ex: par dÃ©faut HTMLPlug bloque tout fichier avec les extensions de fichiers .gif, .,jpg, ,.jpeg, .png ou .css.
+
+
+BasPlug.associate_ext:Modifie les fichiers ayant le  mÃªme nom de fichier racine que le document traitÃ© par le plugin ET une extension de fichier provenant de la liste d'arguments sÃ©parÃ©s par une virgule  donnÃ© par cet argument pour les associer au document traitÃ© plutÃŽt que manipulÃ© comme une liste sÃ©parÃ©e
+
+BasPlug.could_not_extract_encoding:ATTENTION: encodage n'a pas pu Ãªtre extrait de %s - utilisation de %s par dÃ©faut
+
+
+BasPlug.could_not_extract_language:ATTENTION: langue n'a pas pu Ãªtre extraite de %s - utilisation de %s par dÃ©faut
+
+
+BasPlug.could_not_open_for_reading:impossible d'ouvrir %s pour lecture
+
+
+BasPlug.no_cover_image:Ne pas rechercher un fichier prÃ©fix.jpg ( prÃ©fix Ã©tant le mÃªme prÃ©fix que le fichier traitÃ©) et considÃ©rer le comme image de couverture.
+
+
+BasPlug.default_encoding:Utiliser cet encodage si -input_ encoding est placÃ© Ã  'auto' et l'algorithme de catÃ©gorisation de texte ne rÃ©ussit pas Ã  extraire l'encodage ou lorsqu'il extrait un encodage non supportÃ© par Greenstone. Cette option peut prendre la mÃªme valeur que -input_ encoding.
+
+
+BasPlug.default_language:Si Greenstone ne rÃ©ussit pas Ã  identifier la langue du document l'Ã©lÃ©ment de mÃ©ta-donnÃ©e 'Langue' sera portÃ© Ã  cette valeur. Le dÃ©faut est 'en' (les symboles de langue ISO 639 sont utilisÃ©s: en= anglais). Notez que si -imput_encoding n'est pas mis Ã  'auto' et -extract_language n'est pas dÃ©fini, tous les documents auront leurs mÃ©ta-donnÃ©es 'Langue' portÃ©es Ã  cette valeur.
+
+
+BasPlug.desc:Classe de base pour tous les plugins d'importation.
+
+
+BasPlug.done_acronym_extract:extraction des acronymes terminÃ©e.
+
+
+BasPlug.done_acronym_markup:marquage des acronymes terminÃ©.
+
+
+BasPlug.done_email_extract:extraction des adresses e-mail terminÃ©e.
+
+
+BasPlug.dummy_text:Ce document n'a pas de texte.
+
+
+BasPlug.empty_file:le fichier ne contient aucun texte
+
+
+BasPlug.extract_acronyms:Extraire les acronymes du texte et les dÃ©finir comme mÃ©ta-donnÃ©es.
+
+
+BasPlug.extract_email:Extraire les adresses e-mail comme mÃ©ta-donnÃ©es.
+
+
+BasPlug.extract_historical_years:Extraire des documents historiques l'information sur les pÃ©riodes. Ceci est stockÃ© comme mÃ©ta-donnÃ©e avec le document. Il y a une interface de recherche pour cette mÃ©ta-donnÃ©e que vous pouvez inclure dans votre collection en ajoutant la formule ''format QueryInterface DateSearch'' au fichier de configuration de votre collection.
+
+
+BasPlug.extract_language:Identifier la langue de chaque document et dÃ©finir la mÃ©ta-donnÃ©e 'Langue'. Notez que cela se fera automatiquement si -imput_encoding est Ã  'auto'.
+
+
+BasPlug.extracting:Extraction
+
+
+BasPlug.extracting_acronyms:extraction d'acronymes
+
+
+BasPlug.extract_keyphrases:Extraction automatique des phrases clÃ©s avec Kea (par dÃ©faut).
+
+BasPlug.extract_keyphrase_options:Options pour l'extraction phrase clÃ© avec Kea. Par exemple: mALIWEB - utilise ALIWEB modÃšle d'extraction; n5 - extraire 5 phrases clÃ©; eGBK - utiliser l'encodage GBK
+
+BasPlug.extracting_emails:extraction d'adresses e-mail
+
+
+BasPlug.file_has_no_text:ERREUR: %s ne contient pas de texte
+
+
+BasPlug.first:Liste des premiÃšres tailles sÃ©parrÃ©es par une virgule Ã  extraire du texte vers le champ de mÃ©ta-donnÃ©e. Ce champ est appelÃ© 'FirstNNN'.
+
+
+BasPlug.input_encoding:Encodage des documents sources. Les documents vont Ãªtre convertis de ces encodages et stoquÃ©s en interne au format utf8.
+
+BasPlug.input_encoding.ascii:ASCII 7 bits pur. Ceci peut Ãªtre plus rapide que d'utiliser iso_8859_1. Veillez Ã  ne pas utiliser ceci sur une collection de documents ayant des caractÃšres non compris dans ASCCI 7 bits pur (ex: les documents franÃ§ais et allemands qui ont des accents). Utiliser iso_8859_1 dans ce cas.
+
+BasPlug.input_encoding.auto:Utilisez un algorithme de catÃ©gorisation de texte pour identifier automatiquement le codage de chaque document source, cela sera plus lent que l'opÃ©ration consistant Ã  mettre explicitement le codage mais est efficace lorsqu'il y a plusieurs codes dans une mÃªme collection.
+
+BasPlug.input_encoding.unicode:Unicode seulement.
+
+BasPlug.input_encoding.utf8:Utf8 ou unicode -- dÃ©tectÃ© automatique
+
+
+BasPlug.keyphrases:expressions clÃ©s
+
+
+BasPlug.marking_up_acronyms:acronymes de marquage
+
+
+BasPlug.markup_acronyms:Ajouter des mÃ©ta-data d'acromyme au texte du document
+
+
+BasPlug.maximum_century:Le siÃšcle le plus citÃ© Ã  extraire comme mÃ©ta-donnÃ©e historique (ex: 14 va extraire toutes les rÃ©fÃ©rences jusqu'au 14 Ãšme siÃšcle).
+
+
+BasPlug.maximum_year:La date historique la plus Ã©levÃ©e Ã  utiliser comme mÃ©ta-donnÃ©e (dans une Ãšre commune, comme 1950).
+
+
+BasPlug.must_be_implemented:BasPlug: :la fonction de lecture doit Ãªtre exÃ©cutÃ©e dans une sous-classe pour les plugins rÃ©cursifs
+
+
+BasPlug.no_bibliography:Ne cherchez pas Ã  bloquer les dates bibliographiques lors de l'extraction de dates historiques.
+
+
+BasPlug.process_exp:Une expression de Perl Ã  faire correspondre Ã  des noms de fichiers. La correspondance avec les noms de fichiers sera traitÃ©e avec ce plugin. Par exemple, l'usage de '(?i).html?\$' fait correspondre tous les documents se terminant par .htm ou .html (indÃ©pendemment de la casse).
+
+
+BasPlug.read_denied:Permission de lecture refusÃ©e pour %s
+
+
+BasPlug.smart_block:Bloquer les fichiers d'une faÃ§on plus flexible qu'en regardant le nom du fichier.
+
+BasPlug.stems:troncs
+
+
+BasPlug.unsupported_encoding:ATTENTION: %s semble encodÃ© dans un encodage non supportÃ© (%s) - utilisant %
+
+
+BasPlug.wrong_encoding:ATTENTION: %s a Ã©tÃ© lu en utilisant l'encodage %s mais semble avoir Ã©tÃ© encodÃ© comme %s
+
+
+BibTexPlug.desc:BibTexPlug lit les fichiers bibliographiques dans le format BibTex. BibTexPlug crÃ©e un objet document pour chaque rÃ©fÃ©rence dans le fichier. C'est une sous-classe de SplitPlug, donc s'il y a plusieurs Ã©lÃ©ments, ils sont tous lus.
+
+
+BookPlug.desc:CrÃ©e un document Ã  niveaux multiples Ã  partir d'un document contenant les balises de niveau <<TOC>>. Les mÃ©ta-donnÃ©es pour chaque section sont extraites Ã  partir des autres balises se trouvant sur la mÃªme ligne que <<TOC>>. Par exemple, <<Title>>xxxx<</Title>> dÃ©finit une mÃ©ta-donnÃ©e de titre. Tout le reste entre des balises TOC est traitÃ© comme du simple html (c.-Ã -d. qu'aucun lien html ou tout autre Ã©lÃ©ment de type HTMLPlug n'est traitÃ©). Les fichiers d'entrÃ©e sont supposÃ©s avoir l'extension .hb par dÃ©faut (cela peut Ãªtre changÃ© en ajoutant une option -processus_exp de mÃªme que le fichier hb mais une extension .jpg est prise comme image de couverture (les fichiers jpg sont bloquÃ©s par ce plugin). BookPlug est une simplification (et une extension) de HPPlug utilisÃ© par Humanity Library Collections. BookPlug est plus rapide et il s'attend Ã  ce que les fichiers d'entrÃ©e soient  propres (l'entrÃ©e aux collections HDL contient un nombre excessif de balises html autour de <<TOC>>, et utilise des balises <<I>> pour spÃ©cifier les images, et prend tout simplement tout le texte compris entre les balises <<TOC>> et le dÃ©but du texte comme Ã©tant la mÃ©ta-donnÃ©e de titre). Si vous dÃ©sirez baliser un document pour qu'il soit affichÃ© de la mÃªme maniÃšre que les collections HDL, utilisez ce plugin au lieu de HBPlug.
+
+
+ConvertToPlug.convert_to:Ce plugin convertit vers du TEXT ou HTML
+
+ConvertToPlug.convert_to.html:Format HTML
+
+ConvertToPlug.convert_to.text:Format de texte simple
+
+
+ConvertToPlug.desc:Ce plugin est hÃ©ritÃ© par des plugins comme WORDPlug et PDFPlug. Il facilite la conversion de ces types de documents en HTML ou Text en dÃ©finissant une variable qui instruit ConvertTBasPlug comme procÃ©der. Il fonctionne en hÃ©ritant de maniÃšre dynamique HTMLPlug ou TextPlug, basÃ© sur un argument plugin 'convert to' Si l'argument n'est pas prÃ©sent, HTMLPlug est hÃ©ritÃ© par dÃ©faut.
+
+
+ConvertToPlug.use_strings:Si dÃ©fini, une simple fonction de chaÃ®ne sera appelÃ©e pour extraire le texte si l'utilitaire de conversion Ã©choue.
+
+
+ConvertToRogPlug.desc:Un plugiciel qui hÃ©rite de RogPlug.
+
+
+DBPlug.desc:Utilise des enregistrements d'une base de donnÃ©es comme documents.
+
+
+DBPlug.title_sub:Expression de substitution pour modifier une chaÃ®ne enregistrÃ©e titre. UtilisÃ©e, par exemple, par PSPlug pour supprimer ''Page1'' etc du texte utilisÃ© comme titre.
+
+
+EMAILPlug.desc:Email plug lit les fichiers email. Ceux-ci sont nommÃ©s simplement avec un numÃ©ro (c'est-Ã -dire comme ils apparaissent dans les dossiers maildir) ou avec l'extension .mbx (pour format de fichier courrier mbox).\n Texte de document: Le texte de document est composÃ© de tous le texte situÃ© aprÃšs la premiÃšre ligne vide du document.\nMÃ©ta-donnÃ©es (pas Dublin Core!):\n\t\$Headers  Tout le contenu de l'en-tÃªte (optionel, n'est pas emmagasinÃ© par defaut)\n\t\$Subject   Objet: header\n\t\$To    A: header\n\t\$From   De: header/n/t/$FromName    Nom de l'expÃ©diteur (si disponible)\n\t\$FromAddr    Adresse Ã©lectronique de l'expÃ©diteur\n\t\$DateText     Date: header\n\t\$Date   Date: en-tÃªte au format GSDL (ex 19990924)
+
+
+EMAILPlug.no_attachments:Ne pas sauvegarder fichiers attachÃ©s aux messages.
+
+
+EMAILPlug.headers:Emmagasine les titres des email comme "Headers" dans les mÃ©ta-donnÃ©es.
+
+
+EMAILPlug.split_exp:Une expression ordinaire perl utilisÃ©e pour scinder les fichiers contenant plusieurs messages en documents sÃ©parÃ©s.
+
+
+ExcelPlug.desc:Un Plugin pour importer des fichiers Microsoft Excel.
+
+
+FOXPlug.desc:Plugin pour traiter un fichier Foxbase dbt. Ce plugin fournit une fonctionnalitÃ© de base pour lire dans les fichiers dbt et dbf et traiter chaque enregistrement. Ce plugin gÃ©nÃ©ral devrait Ãªtre remplacÃ© pour une base de donnÃ©es particuliÃšre afin de traiter les champs appropriÃ©s.
+
+
+GAPlug.desc:Traite les documents XML de GreenstoneArchive. Notez que ce plugin ne corrige pas la syntaxe (bien que le module XML: :Parser vÃ©rifie l'exactitude de la forme). Il est supposÃ© que les fichiers GreenstoneArchive sont conformes Ã  leur DTD.
+
+
+GISBasPlug.extract_placenames:Extrait le nom des emplacements du texte et les considÃ©rer comme mÃ©ta-donnÃ©es. NÃ©cessite l'installation d'une extension GIS Ã  Greenstone.
+
+GISBasPlug.gazetteer:Atlas Ã  utiliser pour extraire le nom des emplacements du texte et les considÃ©rer comme mÃ©ta-donnÃ©es. NÃ©cessite l'installation d'une extension GIS Ã  Greenstone.
+
+GISBasPlug.place_list:Lors de l'extraction des emplacements, contient la liste des noms d'emplacements au dÃ©but du document. NÃ©cessite l'installation d'une extension GIS Ã  Greenstone.
+
+GMLPlug.desc:Plugin qui traite un document au format GML suppose que toutes les balises GML sont en minuscule.
+
+
+HBPlug.desc:Plugin qui traite un rÃ©pertoire de livres en HTML. Ce plugin est utilisÃ© par les collections Humanity Library et ne traite pas d' encodages d'entrÃ©e autres ascii et ascii Ã©tendu. Ce code n'est pas du tout joli et on pourrait le rendre plus rapide. En le laissant tel quel, j'espÃšre encourager les gens Ã  Ã  construire leurs collections en utilisant plutÃŽt HBSPlug ;-) \n\n Utilisez HBSPlug pour crÃ©er une nouvelle collection et pour marquer des fichiers comme les collections Humanity Library Collections. HBSPlug accepte tous les encodages d'entrÃ©e mais exige que les fichiers marquÃ©s soient plus propres que ceux utilisÃ©s par les collections Human Library.
+
+
+HTMLPlug.assoc_files:Expression perl d'extensions de fichiers Ã  associer avec des documents html.
+
+
+HTMLPlug.desc:Ce plugin traite les fichiers HTML
+
+
+HTMLPlug.description_tags:Divise le document en sous-sections oÃ¹ apparaissent des balises <Section>. Notez qu'en dÃ©finissant cette option, vous dÃ©finissez de faÃ§on implicite -no_metadata puisque toutes les mÃ©ta-donnÃ©es doivent Ãªtre incluses entre les signes <Sections>. '-keep_head' n'aura non plus aucun effet si cette option est dÃ©finie.
+
+
+HTMLPlug.file_is_url:DÃ©fini si les noms de fichiers d'entrÃ©e constituent l'url des documents source d'origine, p.ex. si un outil de "mirroring" a Ã©tÃ© utilisÃ© pour crÃ©er la structure du rÃ©pertoire d'importation.
+
+
+HTMLPlug.hunt_creator_metadata:Trouver autant de mÃ©ta-donnÃ©es possibles sur l'auteur et les placer dans le champ 'Creator'. NÃ©cessite le drapeau -metadata_fields.
+
+
+HTMLPlug.keep_head:Ne pas supprimer les en-tÃªtes des fichiers html.
+
+
+HTMLPlug.metadata_fields:Liste de champs de mÃ©ta-donnÃ©es sÃ©parÃ©s par des virgules Ã  essayer Ã  extraire. Utiliser balise 'tag<nom_balise>' pour obtenir le contenu de la premiÃšre paire de <nom_balise> placÃ©e dans un Ã©lÃ©ment de mÃ©ta-donnÃ©e 'tagname'. Mettre en majuscules si vous voulez les mÃ©ta-donnÃ©es en en lettres majuscules dans Greenstone, car l'extraction des balises ne tient pas compte de la casse.
+
+
+HTMLPlug.no_metadata:Ne cherchez pas Ã  extraire des mÃ©tadata des fichiers.
+
+
+HTMLPlug.no_strip_metadata_html:Liste de noms de mÃ©ta-donnÃ©es sÃ©parÃ©es par des virgules, ou 'all'. UtilisÃ© avec -description_tags, cela Ã©vite d'Ã©liminer les balises HTML des valeurs pour les mÃ©ta-donnÃ©es spÃ©cifiÃ©es.
+
+HTMLPlug.nolinks:Ne pas essayer de piÃ©ger les liens (la dÃ©finition de ce drapeau peut amÃ©liorer la vitesse de construction/importation mais tout lien relatif dans le document sera brisÃ©).
+
+
+HTMLPlug.rename_assoc_files:Renomme les fichiers associÃ©s aux documents (ex. les images). CrÃ©e aussi une structure de rÃ©pertoire beaucoup plus petite (utile pour la crÃ©ation de collections sur cd-rom).
+
+
+HTMLPlug.title_sub:Expression de substitution pour modifier la chaine enregistrÃ©e comme titre. UtilisÃ© par exemple par PDFPlug pour supprimer ''Page 1'', etc du texte utilisÃ© comme titre.
+
+
+ImagePlug.converttotype:Convertit lâimage pricipale en une format 's'.
+
+
+ImagePlug.desc:Ce plugin traite les images, en ajoutant des mÃ©ta-donnÃ©es de base
+
+
+ImagePlug.minimumsize:Ignorer les images de moins de n octets.
+
+
+ImagePlug.noscaleup:Ne pas rÃ©Ã©chelonner les petites images en crÃ©ant des vignettes.
+
+
+ImagePlug.screenviewsize:Si dÃ©fini, crÃ©e une image de taille n pour l'affichage Ã  l'Ã©cran et dÃ©finit les mÃ©ta-donnÃ©es Screen, ScreenSize, ScreenWidth et ScreenHeigth. N'est pas dÃ©fini par dÃ©faut.
+
+
+ImagePlug.screenviewtype:Si -screenviewsize est dÃ©fini, ceci dÃ©finit le type d'mage d'affichage.
+
+
+ImagePlug.thumbnailsize:CrÃ©e des vignettes de taille nxn.
+
+
+ImagePlug.thumbnailtype:CrÃ©e des vignettes au format 's'.
+
+
+IndexPlug.desc:Ce plugin rÃ©cursif traite un fichier index.txt. Le fichier index.txt doit contenir la liste des fichiers Ã  inclure dans la collection, suivie par toute mÃ©ta-donnÃ©e supplÃ©mentaire Ã  associer Ã  chaque fichier\n\nLe fichier index.txt doit Ãªtre formatÃ© comme suit: la premiÃšre ligne peut Ãªtre une clÃ© (commenÃ§ant par key:) pour nommer les champs de mÃ©ta-donnÃ©e (ex. key: Subject Organization Date). Les lignes suivantes contiennent un nom de fichier suivi de la valeur de la mÃ©ta-donnÃ©e (ex 'irma/iwo097e 3.2 unesco 93â va associer les mÃ©ta-donnÃ©es Subject= 3.2, Organization=unesco, et Date=1993 avec le fichier irma/iwo097e si la ligne de clÃ© ci dessus a Ã©tÃ© utilisÃ©e)\n\nNotez que si l'un des champs de mÃ©ta-donnÃ©e utilise le plugin de classification de HiÃ©rarchie, alors sa valeur doit correspondre au premier champ (le descripteur) dans le fichier de classification appropriÃ©.\n\nLes valeurs de mÃ©ta-donnÃ©e peuvent Ãªtre nommÃ©es sÃ©parÃ©ment en utilisant une balise (ex. >Sujet<3.2) et cela va remplacer tout nom qui leur a Ã©tÃ© attribuÃ© par la ligne de clÃ©. S'il n'y a pas de ligne de clÃ©, toute valeur de  mÃ©ta-donnÃ©e sans nom sera nommÃ©e 'Subject'.
+
+
+ISISPlug.desc:Ce plugin traite les bases de donnÃ©es CDS/ISIS. Pour chaque base de donnÃ©es CDS/ISIS traitÃ©e, il doit y avoir trois fichiers dans le dossier d'importation de la collection: le Fichier de Base (.mst), le Tableau de DÃ©finition de Champ (.fdt), et le Fichier de RÃ©fÃ©rences croisÃ©es (.xrf).
+
+
+ISISPlug.subfield_separator:La chaÃ®ne utilisÃ©e pour sÃ©parer les sous champs dans les enregistrements de bases de donnÃ©es CDS/ISIS.
+
+
+ISISPlug.entry_separator:La chaÃ®ne utilisÃ©e pour sÃ©parer les valeurs multiples des champs de mÃ©ta-donnÃ©es individuelles dans les enregistrements de base de donnÃ©es CDS/ISIS.
+
+
+LaTeXPlug.desc:Plugin pour documents  LaTeX .
+
+
+MACROPlug.desc:CrÃ©e un document simple Ã  un seul niveau. Ajoute une mÃ©ta-donnÃ©e de Titre de la premiÃšre ligne de texte (jusqu'Ã  100 caratÃšres).
+
+
+MARCPlug.desc:Plugin MARC de base.
+
+
+MARCPlug.metadata_mapping:Nom de fichier qui inclut des dÃ©tails de de correspondance de valeurs MARC vers les noms de mÃ©ta-donnÃ©es Greenstone. Le dÃ©faut est 'marctdoc.txt' trouvÃ© dans rÃ©pertoire etc du site.
+
+
+MetadataPass.desc:Classe de base Ã  BasPlug qui permet l'utilisation des plugins mÃ©ta-donnÃ©e, utilise la passe metadata_read de import.pl
+
+# -- Missing translation: GISBasPlug.desc
+
+NULPlug.desc:Fichier plugin factice (.nul). UtilisÃ© avec les fichiers gÃ©nÃ©rÃ©s lors de l'Ã©clatement des bases de donnÃ©es mÃ©ta-donnÃ©es.
+
+OAIPlug.desc:Plugin Basic Open Archives Initiate (OAI)
+
+
+OggVorbisPlug.add_technical_metadata:Ajouter des mÃ©ta-donnÃ©es techniques (c.a.d. bitrate)
+
+
+OggVorbisPlug.desc:Un plugin pour importer des fichiers audio Ogg Vorbis.
+
+
+PagedImgPlug.desc:Ajouter Plugin pour les documents construits a partir d'une chaine d'images, avec l'option texte OCR pour chaque image.
+
+
+PagedImgPlug.documenttype:Met le type de document (utilisÃ© pour le display)
+
+PagedImgPlug.documenttype.paged:Les documents avec pages numÃ©rotÃ©es ont des flÃšches qui indiquent la prochaine et la derniÃšre page, ainsi qu'une boite permettant d'aller directement la page X
+
+PagedImgPlug.documenttype.hierarchy:Les documents hiÃ©rarchiques ont une table de contenu.
+
+
+PagedImgPlug.headerpage:Ajouter une page d'entÃªte au niveau supÃ©rieur( sans image) Ã  chaque document.
+
+
+PagedImgPlug.screenview:Produit une vue Ã©cran pour chaque image, et programme les mÃ©ta-donnÃ©es de Screen, ScreenSize, ScreenWidth et ScreenHeight.
+
+
+PagedImgPlug.screenviewsize:CrÃ©e des images vue-Ã©cran de taille nxn.
+
+
+PagedImgPlug.screenviewtype:CrÃ©e des images vue-Ã©cran en format 's'.
+
+
+PagedImgPlug.thumbnail:CrÃ©e une vignette pour chaque image
+
+
+PDFPlug.complex:CrÃ©e une sortie plus complexe. Avec la dÃ©finition de cette option, la sortie html va beaucoup plus ressembler au fichier PDF original. Pour que cela fonctionne correctement, il faut que Ghostscript soit installÃ© (pour *nix, gs doit Ãªtre dans la dÃ©finition de chemins, pendant que pour windows, vous devez avoir gswin32c.exe sur votre chemin).
+
+
+PDFPlug.desc:Plugin pdf "reasonably with-it"
+
+
+PDFPlug.nohidden:EmpÃªche pdftohtml de chercher Ã  extraire du texte cachÃ©. Cela n'est utile que si l'option -complex est Ã©galement dÃ©finie.
+
+
+PDFPlug.noimages:Ne pas chercher Ã  extraire des images de PDF.
+
+
+PDFPlug.use_sections:CreÃ©e une section sÃ©parÃ©e pour chaque page du fichier PDF.
+
+
+PDFPlug.zoom:Le facteur avec lequel zoomer PDF pour la sortie (ceci n'est utile que si -comlex est dÃ©fini).
+
+
+PPTPlug.desc:Un plugin pour importer des fichiers Microsoft PowerPoint.
+
+
+PSPlug.desc:Ceci est un convertisseur de texte ps \''bon marchÃ©\''. Si vous Ãªtes sÃ©rieux, pensez Ã  utiliser le paquetage PRESCRIT, qui est disponible pour tÃ©lÃ©chargement Ã  http://www.nzdl/software.html
+
+
+PSPlug.extract_date:Extrait date de l'en-tÃªte PS.
+
+
+PSPlug.extract_pages:Extrait pages de l'en-tÃªte PS.
+
+
+PSPlug.extract_title:Extrait titre de l'entÃªte PS.
+
+
+RecPlug.desc:RecPlug est un plugin rÃ©cursif Ã  travers les rÃ©pertoires, traitant chaque fichier trouvÃ©.
+
+
+RecPlug.recheck_directories:Une fois le traitement terminÃ© des fichiers dans un rÃ©pertoire d'importation, vÃ©rifiez le rÃ©pertoire pour dÃ©couvrir les nouveaux fichiers crÃ©Ã©s.
+
+
+RecPlug.use_metadata_files:Lit les mÃ©ta-donnÃ©es Ã  partir de fichiers XML.
+
+
+ReferPlug.desc:ReferPlug lit les fichiers de bibliographie au format Refer.
+
+
+ReferPlug.longdesc:ReferPlug lit les fichiers de bibliographie au format Refer.\nPar Gordon W. Paynter (gwp\@cs.waikato.ac.nz), Novembre 2000\n\n BasÃ© approximativement sur hcibib2Plug de Steve Jones (stevej\@cs.waikato.ac.nz) qui Ã©tait basÃ© sur EmailPlug de Gordon Paynter (gwp\@cs.waikato.ac.nz), qui Ã©tait basÃ© sur d'anciennes versions de HTMLPlug et HCIBIBPlug de Stefan Boddie et autres ... il est actuellement difficile de dire quoi vient de quoi\n\nReferPlug crÃ©e un objet document pour chaque rÃ©fÃ©rence dans le fichier. C'est une sous-classe de SplitPlug, donc s'il y a plusieurs enregistrements, ils sont tous lus.\n\nLe texte du document constituÃ© de la rÃ©fÃ©rence au format Refer.\nMeta-donnÃ©es::\n\t\$Creator \%A Nom de l'auteur\n\t\$Title  \%T Titre d'article du livre\n\t\$Journal \%J Titre de la revue\n\t\$Booktitle \%B Titre du livre contenant la publication\n\t\$Report  \%R Type de rapport, article ou thÃšse\n\t\$Volume  \%V NumÃ©ro de volume de la revue\n\t\$Number  \%N Nombre de revues dans le volume\n\t\$Editor  \%E Editor name\n\t\$Pages  \%P Page Number of article\n\t\$Publisher \%I Name of Publisher\n\t\$Publisheraddr \%C Adresse de l'Ã©diteur\n\t\$Date  \%D Date de publication\n\t\$Keywords \%K Mots-clÃ©s associÃ©s Ã  la publication\n\t\$Abstract \%X Abstract de la publication\n\t\$Copyright\t\%* Information de droits d'auteur pour l'article
+
+
+RogPlug.desc:CrÃ©e des documents Ã  un seul niveau Ã  partir de fichiers .rog ou .mdb.
+
+
+RTFPlug.desc:Plugin pour l'importation de fichiers Rich Text Format.
+
+
+SRCPlug.desc:Le nom du fichier est prÃ©sentement utilisÃ© pour Titre (optionnellement moins un certain prÃ©fixe). Languages actuels:\ntext:READMEs/Makefiles\nC/C++ (extrait actuellement les dÃ©clarations #include et les dÃ©clarations de classe C++)\n Perl (pour le moment, effectuÃ© uniquement comme texte)\nShell (pour le moment, effectuÃ© uniquement comme texte)
+
+
+SRCPlug.remove_prefix:Enlever cette chaine de dÃ©but du nom de fichier (ex.: -remove_prefix /tmp/XX/src). Par dÃ©faut, le chemin complet est supprimÃ© du nom de fichier.
+
+
+SplitPlug.desc:SplitPlug est un plugin pour Ã©clater des fichiers d'entrÃ© en en segments qui vont Ãªtre traitÃ©s individuellement. Ce plugin ne doit pas Ãªtre invoquÃ© directement. Si vous voulez traiter des fichiers d'entrÃ©e qui contiennent plusieurs documents, vous devez plutÃŽt Ã©crire un plugin avec une fonction de traitement qui va traiter un de ces documents et hÃ©riter de SplitPlug. Voir ReferPlug en guise d'exemple.
+
+
+SplitPlug.split_exp:Une expression ordinaire Perl pour Ã©clater les fichiers d'entrÃ©e en segments.
+
+
+TEXTPlug.desc:CrÃ©e un document Ã  niveau unique. Ajoute une mÃ©ta-donnÃ©e de Titre de premiÃšre ligne de texte (jusqu'Ã  100 caractÃšres).
+
+
+TEXTPlug.title_sub:Expression de substitution pour modifier la chaine stockÃ©e comme Titre. UtilisÃ©e par exemple par PSPlug pour supprimer ''Page 1'' etc du texte utilisÃ© comme titre.
+
+
+UnknownPlug.assoc_field:Nom du champ de mÃ©ta-donnÃ©e qui va contenir le nom de fichier associÃ©.
+
+
+UnknownPlug.desc:Ceci est un plugin simple d'importation de fichiers aux formats inconnus de Greenstone. Un document fictif va Ãªtre crÃ©Ã© pour chacun de ses fichiers et le fichier lui mÃªme va Ãªtre passÃ© Ã  Greenstone comme \"fichier associÃ©\" du document.
+
+
+UnknownPlug.file_format:Type Mime du fichier (ex. image/gif).
+
+
+UnknownPlug.mime_type:Type Mime du fichier (c.a.d. image/gif).
+
+
+UnknownPlug.process_extension:Traiter les fichiers avec cette extension. Cette option est une alternative Ã  process_exp qui est plus simple Ã  utiliser mais moins flexible.
+
+
+MP3Plug.desc:Plugin pour le traitement des fichiers MP3.
+
+
+MP3Plug.assoc_images:Use google image search to locate images related to MP3 file based on ID3 Title and Artist metadata.
+
+MP3Plug.assoc_images:UtilisÃ© pour enregistrer [applet] des mÃ©ta-donnÃ©es pour chaque document qui contient le code HTML d'un applet MP3 audio player pour jouer ce fichier.
+
+
+MP3Plug.metadata_fields:Liste de champs mÃ©ta-donnÃ©es sÃ©parÃ©s par des virgules pour extraction dans un fichier MP3 (supposÃ© prÃ©sent) . Utiliser \"*\" pour extraire tous les champs.
+
+
+W3ImgPlug.aggressiveness:SÃ©rie de techniques d'extraction de textes du mÃªme type Ã  utiliser.
+
+W3ImgPlug.aggressiveness.1:Nom de fichier, chemin, texte ALT seulement.
+
+W3ImgPlug.aggressiveness.2:Tout de 1, plus lÃ©gende ou image s'il y a lieu.
+
+W3ImgPlug.aggressiveness.3:Tout de 2, plus paragraphes proches si disponibles.
+
+W3ImgPlug.aggressiveness.4:Tout de 3, plus en-tÃªtes prÃ©cÃ©dents (<h1>,<h2>,,,) si disponibles.
+
+W3ImgPlug.aggressiveness.5:Tout de 4, plus les rÃ©fÃ©rences textuelles si disponibles.
+
+W3ImgPlug.aggressiveness.6:Tout de 4, plus page de mÃ©ta-balises (titre, mots clÃ©s, etc).
+
+W3ImgPlug.aggressiveness.7:Tout de 6, 5 et 4 combinÃ©s.
+
+W3ImgPlug.aggressiveness.8:Tout de 7, plus lÃ©gende de rÃ©pÃ©tition, nom de fichier, etc (Ã©lever le rang des rÃ©sultats les plus pertinents).
+
+W3ImgPlug.aggressiveness.9:Tout de 1, plus texte complet de la page source.
+
+
+W3ImgPlug.caption_length:Longueur maximum des lÃ©gendes (en caractÃšres).
+
+
+W3ImgPlug.convert_params:ParamÃštres additionnels de conversion d'ImageMagick pour la crÃ©ation de vignettes. Par exemple, '-raise' va donner un effet tridimensionnel aux vignettes.
+
+
+W3ImgPlug.desc:Un plugin pour extraire des images et le texte associÃ© Ã  partir de pages web.
+
+
+W3ImgPlug.document_text:Ajoute un texte d'image comme document:text (autrement champ de mÃ©ta-donnÃ©e IndexedText).
+
+
+W3ImgPlug.index_pages:Indexe les pages en mÃªme temps que les images. Ou alors rÃ©fÃ©rencie les pages Ã  la source URL.
+
+
+W3ImgPlug.max_near_text:Nombre maximum de caractÃšres prÃšs des images Ã  extraire.
+
+
+W3ImgPlug.min_height:Pixels. Sauter les images plus courtes que ceci.
+
+
+W3ImgPlug.min_near_text:Nombre minimum de caractÃšres prÃšs du texte ou de la lÃ©gende Ã  extraire.
+
+
+W3ImgPlug.min_size:Bytes. Sauter les images plus petites que ceci.
+
+
+W3ImgPlug.min_width:Pixels. Sauter les images plus petites que ceci.
+
+
+W3ImgPlug.neartext_length:Longueur cible du texte proche (en caractÃšres).
+
+
+W3ImgPlug.no_cache_images:Ne pas mettre les images en cache (pointer vers URL de l'original).
+
+
+W3ImgPlug.smallpage_threshold:Les images sur les pages plus petites que ceci (bytes) auront les mÃ©ta-donnÃ©es de la page (titre, mots clÃ©s, etc) ajoutÃ©es.
+
+
+W3ImgPlug.textrefs_threshold:Seuil de rÃ©fÃ©rences textuelles. Des valeurs plus faibles indiquent que l'algorithme est moins strict.
+
+
+W3ImgPlug.thumb_size:Taille maximale de vignette. Largeur comme hauteur.
+
+
+WordPlug.desc:Un plugin pour des documents Microsoft Word.
+
+
+XMLPlug.desc:Classe de base pour les plugins XML.
+
+
+ZIPPlug.desc:Plugin qui traite les formats d'entrÃ©e compressÃ©s et/ou les formats d'entrÃ©e archivÃ©s actuellement traitÃ©s et les extensions de fichiers sont:\ngzip (.gz, .z, .tgz, .taz)\nbzip (.bz)\nbzip2 (.bz2)\nzip (.zip .jar)\ntar (.tar)\n\n. Ce plugin dÃ©pend de la prÃ©sence des utilaires suivants (lorsqu'il essaie de traiter les formats correspondants):\ngunzip (pour gzip)\nbunzip (pour bzip)\nbunzip2 \nunzip (pour zip)\ntar (pour tar)
+
+
+
+#
+# Perl module strings
+#
+
+classify.could_not_find_classifier:ERREUR: Classificateur \''%s\'' introuvable
+
+
+plugin.could_not_find_plugin:ERREUR: impossible de trouver le plugin /''%s''
+
+
+plugin.including_archive:intÃ©gration des contenus d'une archive ZIP/TAR
+
+
+plugin.including_archives:intÃ©gration des contenus de %d archives ZIP/TAR
+
+
+plugin.kill_file:Processus tuÃ© par le fichier .kill
+
+
+plugin.n_considered:%d documents ont Ã©tÃ© pris en compte pour traitement
+
+
+plugin.n_included:%d ont Ã©tÃ© traitÃ©s et intÃ©grÃ©s dans la collection
+
+
+plugin.n_rejected:%d ont Ã©tÃ© rejetÃ©s
+
+
+plugin.n_unrecognised:%d n'ont pas Ã©tÃ© reconnus
+
+
+plugin.no_plugin_could_process:ATTENTION: Aucun plugin n'a pu traiter %s
+
+
+plugin.no_plugin_could_recognise:ATTENTION: Aucun plugin n'a pu reconnaÃ®tre %s
+
+
+plugin.no_plugin_could_process_this_file:aucun plugin n'a pu traiter ce fichier
+
+
+plugin.no_plugin_could_recognise_this_file:Aucun plugin n'a pu reconnaÃ®tre ce fichier
+
+
+plugin.one_considered:1 document a Ã©tÃ© pris en compte pour traitement
+
+
+plugin.one_included:1 a Ã©tÃ© traitÃ© et intÃ©grÃ© dans la collection
+
+
+plugin.one_rejected:1 a Ã©tÃ© rejetÃ©
+
+
+plugin.one_unrecognised:1 n'a pas Ã©tÃ© reconnu
+
+
+plugin.see_faillog:Voir %s pour une liste des documents rejetÃ©s
+
+
+PrintUsage.default:DÃ©faut
+
+
+PrintUsage.required:REQUIS
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/strings_ru.rb
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/strings_ru.rb	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/strings_ru.rb	(revision 10506)
@@ -0,0 +1,1557 @@
+#
+# Resource bundle description
+#
+
+Language.code:ru
+
+Language.name:Russian
+
+
+OutputEncoding.unix:koi8_r
+
+OutputEncoding.windows:dos_850
+
+
+
+#
+# Common output messages
+#
+
+common.cannot_create_file:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÑÐŸÐ·ÐŽÐ°ÑÑ ÑÐ°Ð¹Ð» %s
+
+
+common.cannot_find_cfg_file:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐœÐ°Ð¹ÑÐž ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» %s
+
+
+common.cannot_open:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐŸÑÐºÑÑÑÑ %s
+
+
+common.cannot_open_fail_log:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐŸÑÐºÑÑÑÑ ÑÐµÐ³ÐžÑÑÑÐ°ÑÐžÐŸÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» %s
+
+
+common.cannot_open_output_file:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐŸÑÐºÑÑÑÑ Ð²ÑÑ
+ÐŸÐŽÐœÐŸÐ¹ ÑÐ°Ð¹Ð» %s.
+
+
+common.cannot_read:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÑÐžÑÐ°ÑÑ %s
+
+
+common.cannot_read_file:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ Ð¿ÑÐŸÑÐµÑÑÑ ÑÐ°Ð¹Ð» %s
+
+
+common.general_options:ÐŸÐ±ÑÐžÐµ Ð²Ð°ÑÐžÐ°ÐœÑÑ (ÐŽÐ»Ñ %s)
+
+
+common.must_be_implemented:ÑÑÐœÐºÑÐžÑ ÐŽÐŸÐ»Ð¶ÐœÐ° Ð±ÑÑÑ ÐŸÑÑÑÐµÑÑÐ²Ð»ÐµÐœÐ° Ð² Ð¿ÐŸÐŽÐºÐ»Ð°ÑÑÐµ
+
+
+common.options:ÐŸÐ¿ÑÐžÐž
+
+
+common.processing:ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐ°
+
+
+common.specific_options:ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐžÐµ ÐŸÐ¿ÑÐžÐž
+
+
+common.usage:ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµ
+
+
+
+#
+# Script option descriptions and output messages
+#
+
+scripts.language:Ð¯Ð·ÑÐº ÐŽÐ»Ñ ÐŸÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ ÐŸÐ¿ÐžÑÐ°ÐœÐžÐ¹ ÐŸÐ¿ÑÐžÐ¹ Ð² (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, 'en_US' ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÐµÑ Ð°ÐŒÐµÑÐžÐºÐ°ÐœÑÐºÐžÐ¹ Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐžÐ¹ ÑÐ·ÑÐº). Ð¢ÑÐµÐ±ÑÐµÑ Ð¿ÐµÑÐµÐ²ÐŸÐŽÐŸÐ² ÐŸÐ¿ÐžÑÐ°ÐœÐžÐ¹ ÐŸÐ¿ÑÐžÐ¹ ÐŽÐ»Ñ Ð¿ÑÐžÑÑÑÑÑÐ²ÐžÑ Ð² ÑÐ°Ð¹Ð»Ðµ perllib/strings_language-code.rb.
+
+
+scripts.xml:ÐÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ Ð² ÑÐŸÑÐŒÐ°ÑÐµ XML Ð±ÐµÐ· 'ÑÐžÐŒÐ¿Ð°ÑÐžÑÐœÑÑ
+' ÐºÐŸÐŒÐŒÐµÐœÑÐ°ÑÐžÐµÐ², ÐœÐŸ Ñ ÐœÐ°ÐŒÐœÐŸÐ³ÐŸ Ð±ÐŸÐ»ÑÑÐžÐŒ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸÐŒ ÐŽÐµÑÐ°Ð»ÐµÐ¹.
+
+
+scripts.listall:Ð¡Ð¿ÐžÑÐŸÐº Ð²ÑÐµÑ
+ ÐžÐ·Ð²ÐµÑÑÐœÑÑ
+ ÐµÐŽÐžÐœÐžÑ.
+
+
+
+# -- buildcol.pl --
+
+buildcol.archivedir:ÐÐŽÐµ ÐœÐ°Ñ
+ÐŸÐŽÑÑÑÑ Ð°ÑÑ
+ÐžÐ²Ñ.
+
+
+buildcol.builddir:ÐÐŽÐµ Ð¿ÐŸÐŒÐµÑÑÐžÑÑ ÑÐŸÐ·ÐŽÐ°ÐœÐœÑÐµ ÐžÐœÐŽÐµÐºÑÑ.
+
+
+buildcol.cachedir:ÐÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±ÑÐŽÐµÑ Ð²ÑÐµÐŒÐµÐœÐœÐŸ ÑÐŸÐ·ÐŽÐ°ÐœÐ° Ð·ÐŽÐµÑÑ, Ð¿ÐµÑÐµÐŽ ÑÐµÐŒ ÐºÐ°Ðº Ð±ÑÐŽÐµÑ ÑÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐ° Ð² ÑÐŸÐ·ÐŽÐ°ÐœÐœÑÑ ÐŽÐžÑÐµÐºÑÐŸÑÐžÑ.
+
+
+buildcol.cannot_open_cfg_file:ÐÐ ÐÐÐ£ÐÐ ÐÐÐÐÐÐÐ: ÐÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» ÐœÐµ ÐŒÐŸÐ¶ÐµÑ ÐŸÑÐºÑÑÑÑ ÐŽÐ»Ñ ÐŸÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÑ: %s
+
+
+buildcol.collectdir:ÐÐžÑÐµÐºÑÐŸÑÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+
+buildcol.copying_back_cached_build:ÐÐ±ÑÐ°ÑÐœÐŸÐµ ÐºÐŸÐ¿ÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐºÑÑÐžÑÐŸÐ²Ð°ÐœÐœÐŸÐ¹ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ.
+
+
+buildcol.create_images:ÐÐŸÐ¿ÑÑÐºÐ° ÑÐŸÐ·ÐŽÐ°ÑÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ ÐŽÐ»Ñ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. ÐÐœÐ° ÐŸÑÐœÐŸÐ²Ð°ÐœÐ° ÐœÐ° Gimp, ÐºÐŸÑÐŸÑÑÐ¹ ÐžÐœÑÑÐ°Ð»Ð»ÐžÑÑÐµÑÑÑ ÐœÐ°ÑÑÐŽÑ Ñ Ð¿ÐŸÐŽÑ
+ÐŸÐŽÑÑÐžÐŒÐž ÐŒÐŸÐŽÑÐ»ÑÐŒÐž perl, ÑÑÐŸÐ±Ñ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÐžÑÑ ÐœÐ°Ð¿ÐžÑÐ°ÐœÐžÐµ ÑÐºÑÐžÐ¿ÑÐŸÐ² ÐŸÑ perl.
+
+
+buildcol.debug:ÐÐ°Ð¿ÐžÑÐ°ÑÑ Ð¿ÑÐŸÐŽÑÐºÑÐžÑ Ð² STDOUT.
+
+
+buildcol.desc:Ð¡ÐºÑÐžÐ¿Ñ PERL, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÐ¹ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Greenstone ÐžÐ· ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² GML.
+
+
+buildcol.faillog:ÐÐµÑÐŽÐ°ÑÐœÐ°Ñ ÑÐµÐ³ÐžÑÑÑÐ°ÑÐžÑ ÐžÐŒÐµÐœÐž ÑÐ°Ð¹Ð»Ð°. Ð­ÑÐŸÑ Ð¶ÑÑÐœÐ°Ð» ÑÐµÐ³ÐžÑÑÑÐ°ÑÐžÑ Ð¿ÐŸÐ»ÑÑÐžÐ» ÐžÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÐŸÐ² ÐžÐ· Ð»ÑÐ±ÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐœÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÐœÑ
+
+
+buildcol.index:ÐÐœÐŽÐµÐºÑ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ( Ð²ÑÐµ Ð±ÑÐŽÐµÑ ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÑÑÑÑ Ð² ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÐŸÐŒ ÑÐ°Ð¹Ð»Ðµ, ÐµÑÐ»Ðž ÐŸÐœ ÐœÐµ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ).
+
+
+buildcol.keepold:ÐÐµ Ð±ÑÐŽÐµÑ ÑÐœÐžÑÑÐŸÐ¶Ð°ÑÑ ÑÐµÐºÑÑÐµÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ ÑÐŸÐ·ÐŽÐ°Ð²Ð°ÐµÐŒÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž.
+
+
+buildcol.maxdocs:ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÑÐžÑÐ»ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ.
+
+
+buildcol.mode:Ð§Ð°ÑÑÐž Ð¿ÑÐŸÑÐµÑÑÐ° Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÐºÐŸÑÐŸÑÑÐµ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ Ð²ÑÐ¿ÐŸÐ»ÐœÐžÑÑ.
+
+buildcol.mode.all:ÐÐµÐ»Ð°ÑÑ Ð²ÑÐµ.
+
+buildcol.mode.build_index:Ð¢ÐŸÐ»ÑÐºÐŸ ÐžÐœÐŽÐµÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÑÐµÐºÑÑ.
+
+buildcol.mode.compress_text:Ð¢ÐŸÐ»ÑÐºÐŸ ÑÐ¶Ð°ÑÑ ÑÐµÐºÑÑ.
+
+buildcol.mode.infodb:Ð¢ÐŸÐ»ÑÐºÐŸ ÑÐŸÐ·ÐŽÐ°ÑÑ Ð±Ð°Ð·Ñ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.
+
+
+buildcol.no_default_images:ÐÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ ÐœÐµ Ð±ÑÐŽÑÑ ÑÐŸÐ·ÐŽÐ°ÐœÑ.
+
+
+buildcol.no_image_script:ÐÐ ÐÐÐ£ÐÐ ÐÐÐÐÐÐÐ: Ð¡ÐºÑÐžÐ¿Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ ÐœÐµ ÐŒÐŸÐ³ Ð±ÑÑÑ ÐœÐ°Ð¹ÐŽÐµÐœ: %s
+
+
+buildcol.no_strip_html:ÐÐµ ÑÐŽÐ°Ð»ÑÑÑ ÑÑÐ³Ðž HTML ÐžÐ· ÐžÐœÐŽÐµÐºÑÐžÑÐŸÐ²Ð°ÐœÐœÐŸÐ³ÐŸ ÑÐµÐºÑÑÐ° (ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐŽÐ»Ñ mgpp ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹).
+
+
+buildcol.no_text:ÐÐµ Ñ
+ÑÐ°ÐœÐžÑÑ ÑÐ¶Ð°ÑÑÐ¹ ÑÐµÐºÑÑ. Ð­ÑÐŸÑ ÐŸÐ¿ÑÐžÑ Ð¿ÐŸÐ»ÐµÐ·ÐœÐ° ÐŽÐ»Ñ ÐŒÐžÐœÐžÐŒÐžÐ·Ð°ÑÐžÐž ÑÐ°Ð·ÐŒÐµÑÐ° Ð¿ÐŸÑÑÑÐŸÐµÐœÐœÑÑ
+ ÐžÐœÐŽÐµÐºÑÐŸÐ², ÐµÑÐ»Ðž ÐÑ ÐœÐ°ÐŒÐµÑÐµÐ²Ð°ÐµÑÐµÑÑ Ð²ÑÐµÐ³ÐŽÐ° Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÑÑ ÐŸÑÐžÐ³ÐžÐœÐ°Ð»Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° Ð² ÑÐµÐºÑÑÐµÐµ Ð²ÑÐµÐŒÑ (ÑÐŸ ÐµÑÑÑ ÐÑ ÐœÐµ Ð±ÑÐŽÐµÑÐµ ÑÐ¿ÐŸÑÐŸÐ±ÐœÑ Ð²ÐŸÑÑÑÐ°ÐœÐŸÐ²ÐžÑÑ ÑÐ¶Ð°ÑÑÑ Ð²ÐµÑÑÐžÑ ÑÐµÐºÑÑÐ°).
+
+
+buildcol.out:ÐÐŒÑ ÑÐ°Ð¹Ð»Ð° ÐžÐ»Ðž ÐžÐœÐŽÐµÐºÑ ÐŽÐ»Ñ Ð¿ÐµÑÐ°ÑÐž ÑÑÐ°ÑÑÑÐ° Ð¿ÑÐŸÐŽÑÐºÑÐžÐž Ð².
+
+
+buildcol.params:[Ð²Ð°ÑÐžÐ°ÐœÑÑ] ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+
+
+buildcol.remove_empty_classifications:Ð¡ÐºÑÑÑÑ ÐœÐµÐ·Ð°Ð¿ÐŸÐ»ÐœÐµÐœÐœÑÐµ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ Ðž ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÑÐµ ÑÐ·Ð»Ñ (Ð±ÐµÐ· ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²).
+
+
+buildcol.unlinked_col_images:ÐÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐœÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÑÐ²ÑÐ·Ð°ÐœÑ Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸ.
+
+
+buildcol.unknown_mode:ÐÐµÐžÐ·Ð²ÐµÑÑÐœÑÐ¹ ÑÐ¿ÐŸÑÐŸÐ±: %s
+
+
+buildcol.updating_archive_cache:ÐÐ±ÐœÐŸÐ²Ð»ÐµÐœÐžÐµ ÐºÑÑÐ° Ð°ÑÑ
+ÐžÐ²Ð°
+
+
+buildcol.verbosity:Ð£Ð¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸÐŒ Ð¿ÑÐŸÐŽÑÐºÑÐžÐž. 0=ÐœÐžÑÐµÐ³ÐŸ, 3=Ð±ÐŸÐ»ÑÑÐŸÐµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸ.
+
+
+
+# -- classinfo.pl --
+
+classinfo.collect:ÐÑÐž Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÐµÐœÐžÐž ÐžÐŒÐµÐœÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐœÐ°ÐŽÐŸ Ð±ÑÐŽÐµÑ Ð¿ÑÐµÐ¶ÐŽÐµ Ð²ÑÐµÐ³ÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ classinfo.pl Ð² collect/collection-name/perllib/classify. ÐÑÐ»Ðž ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ ÑÐ°ÐŒ ÐœÐµ ÐœÐ°Ð¹ÐŽÐµÐœ, ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐŸ Ð±ÑÐŽÐµÑ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ ÐŸÐ±ÑÑÑ ÐŽÐžÑÐµÐºÑÐŸÑÐžÑ perllib/classify.
+
+
+classinfo.desc:ÐÐ°Ð¿ÐžÑÐ°ÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐµ.
+
+
+classinfo.general_options:ÐÐ±ÑÐžÐµ ÐŸÐ¿ÑÐžÐž ÑÐœÐ°ÑÐ»ÐµÐŽÐŸÐ²Ð°ÐœÑ ÐŸÑ ÑÐŸÐŽÐžÑÐµÐ»ÑÑÐºÐžÑ
+ ÐºÐ»Ð°ÑÑÐŸÐ² ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°.
+
+
+classinfo.info:ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ
+
+
+classinfo.no_classifier_name:ÐÐšÐÐÐÐ: ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÑÐµÐŽÐŸÑÑÐ°Ð²ÐžÑÑ ÐžÐŒÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°.
+
+
+classinfo.option_types:ÐÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ ÐŒÐŸÐ³ÑÑ ÐžÐŒÐµÑÑ ÐŽÐ²Ð° ÑÐžÐ¿Ð° ÐŸÐ¿ÑÐžÐ¹.
+
+
+classinfo.params:[Ð²Ð°ÑÐžÐ°ÐœÑÑ] ÐžÐŒÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°
+
+
+classinfo.passing_options:ÐÐ¿ÑÐžÐž ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ Ð¿ÐµÑÐµÐŽÐ°ÐœÑ Ð»ÑÐ±ÐŸÐŒÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ Ð²ÐºÐ»ÑÑÐµÐœÐžÐµÐŒ ÐžÑ
+ Ð² ÐÐ°Ñ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» collect.cfg.
+
+
+classinfo.specific_options:ÐÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÐµ ÐŸÐ¿ÑÐžÐž ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÑ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÑÐ°ÐŒÐŸÐ³ÐŸ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° Ðž ÐŽÐŸÑÑÑÐ¿ÐœÑ ÑÐŸÐ»ÑÐºÐŸ ÑÑÐŸÐŒÑ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐŸÐŒÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ.
+
+
+# -- explode_metadata_database.pl --
+explode.desc:Ð Ð°ÑÑÐžÑÐžÑÑ Ð±Ð°Ð·Ñ ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+Ñ
+
+explode.document_field: Ð­Ð»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÑÑÐžÐ¹ ÐžÐŒÑ ÑÐ°Ð¹Ð»Ð° ÐŽÐ»Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ Ð±ÑÐŽÑÑ Ð¿ÐŸÐ»ÑÑÐµÐœÑ Ðž Ð²ÐºÐ»ÑÑÐµÐœÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ.
+
+
+explode.document_prefix: ÐÑÐžÑÑÐ°Ð²ÐºÐ° ÐŽÐ»Ñ ÐŒÐµÑÑÐŸÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐžÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° (ÐŽÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ Ñ ÐŸÐ¿ÑÐžÐµÐ¹ document_field).
+
+
+explode.document_suffix:Ð¡ÑÑÑÐžÐºÑ ÐŽÐ»Ñ ÐŒÐµÑÑÐŸÐ¿ÐŸÐ»ÐŸÐ¶ÐµÐœÐžÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° (ÐŽÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ Ñ ÐŸÐ¿ÑÐžÐµÐ¹ document_field).
+
+
+explode.encoding:ÐÐŸÐŽÐžÑÐŸÐ²ÐºÐ° ÐŽÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ Ð¿ÑÐž ÑÑÐµÐœÐžÐž ÑÐ°Ð¹Ð»ÐŸÐ² Ð² Ð±Ð°Ð·Ðµ ÐŽÐ°ÐœÐœÑÑ
+
+
+explode.filename_field:ÐÐŸÐ»Ðµ Ñ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑÐŒÐž ÑÐ°Ð¹Ð»ÐŸÐ², ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÐŒÐž Ð¿ÑÐž ÑÐŸÐ·ÐŽÐ°ÐœÐžÐž ÐœÑÐ»ÐµÐ²ÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² (ÐµÑÐ»Ðž ÐœÐµÑ document_field ÐžÐ»Ðž ÑÑÐŸ Ð¿ÐŸÐ»Ðµ Ð¿ÑÑÑÐŸ)
+explode.metadata_set:ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐœÐ°Ð±ÐŸÑÐ° ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ Ð²ÑÐµÑ
+ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+
+explode.plugin:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ Ð¿ÑÐž ÑÐ°ÑÑÐžÑÐµÐœÐžÐž
+explode.params: [ÐŸÐ¿ÑÐžÐž] ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÑÐ°Ð¹Ð»Ð°
+
+# -- exportcol.pl --
+
+exportcol.out:ÐÐŒÑ ÑÐ°Ð¹Ð»Ð° ÐžÐ»Ðž ÐžÐœÐŽÐµÐºÑ ÐŽÐ»Ñ Ð¿ÐµÑÐ°ÑÐž ÑÑÐ°ÑÑÑÐ° Ð¿ÑÐŸÐŽÑÐºÑÐžÐž Ð².
+
+exportcol.cdname:ÐÐŒÑ CD-ROM - ÑÑÐŸ ÑÐŸ, ÑÑÐŸ Ð¿ÐŸÑÐ²ÐžÑÑÑ Ð² ÑÑÐ°ÑÑÐŸÐ²ÐŸÐŒ ÐŒÐµÐœÑ, ÐºÐ°Ðº ÑÐŸÐ»ÑÐºÐŸ CD-ROM ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ.
+
+exportcol.desc:Ð¡ÐºÑÐžÐ¿Ñ PERL ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°Ð»ÑÑ ÐŽÐ»Ñ ÑÐºÑÐ¿ÐŸÑÑÐ° ÐŸÐŽÐœÐŸÐ¹ ÐžÐ»Ðž Ð±ÐŸÐ»ÐµÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹ Ð² Windows CD-ROM. 
+
+exportcol.params:[ÐŸÐ¿ÑÐžÐž] ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ-ÐžÐŒÑ1 ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ-ÐžÐŒÑ2...
+
+exportcol.coll_not_found:ÐÐµ Ð¿ÑÐžÐœÐžÐŒÐ°ÑÑ Ð²ÐŸ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ ÐœÐµÐŽÐµÐ¹ÑÑÐ²ÐžÑÐµÐ»ÑÐœÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ %s:ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµ ÐœÐ°Ð¹ÐŽÐµÐœÐ° Ð² %s.
+
+exportcol.coll_dirs_not_found:ÐÐµ Ð¿ÑÐžÐœÐžÐŒÐ°ÑÑ Ð²ÐŸ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ ÐœÐµÐŽÐµÐ¹ÑÑÐ²ÐžÑÐµÐ»ÑÐœÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ %s: ÐŸÐŽÐœÐ° ÐžÐ· ÑÐ»ÐµÐŽÑÑÑÐžÑ
+ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐ¹ ÐœÐµ ÐœÐ°Ð¹ÐŽÐµÐœÐ°.
+
+exportcol.fail:exportcol.pl ÐœÐµ ÑÐŽÐ°Ð»ÑÑ:
+
+exportcol.no_valid_colls:ÐÐžÐºÐ°ÐºÐžÑ
+ Ð¿ÑÐžÐ³ÐŸÐŽÐœÑÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÑ
+ ÐŽÐ»Ñ ÑÐºÑÐ¿ÐŸÑÑÐ°.
+
+exportcol.couldnt_create_dir:ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÑÐŸÐ·ÐŽÐ°ÑÑ ÐŽÐžÑÐµÐºÑÐŸÑÐžÑ %s.
+
+exportcol.couldnt_create_file:ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÑÐŸÐ·ÐŽÐ°ÑÑ %s.
+
+exportcol.instructions:Ð§ÑÐŸÐ±Ñ ÑÐŸÐ·ÐŽÐ°ÑÑ ÑÐ°ÐŒÐŸÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÑÑÐžÐ¹ÑÑ CD-ROM ÐŽÐ»Ñ Windows, Ð·Ð°Ð¿ÐžÑÐžÑÐµ ÐœÐ° CD-ROM ÑÐŸÐŽÐµÑÐ¶ÐžÐŒÐŸÐµ ÑÑÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐž.
+
+exportcol.non_exist_files:ÐÐŽÐžÐœ ÐžÐ»Ðž Ð±ÐŸÐ»ÐµÐµ ÐžÐ· ÑÐ»ÐµÐŽÑÑÑÐžÑ
+ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² Ðž ÐŽÐžÑÐµÐºÑÐŸÑÐžÐ¹ ÐœÐµ ÑÑÑÐµÑÑÐ²ÑÐµÑ:
+
+exportcol.success:exportcol.pl ÑÐ»ÐµÐŽÐŸÐ²Ð°Ð²ÑÐžÐ¹:
+
+exportcol.output_dir:Ð­ÐºÑÐ¿ÐŸÑÑÐžÑÑÐµÐŒÑÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž (%s) ÐœÐ°Ñ
+ÐŸÐŽÑÑÑÑ Ð² %s.
+
+exportcol.nonetscape:ÐÐµ Ð²ÐºÐ»ÑÑÐ°ÑÑ Netscape ÐœÐ° ÑÐºÑÐ¿ÐŸÑÑÐžÑÑÐµÐŒÑÐ¹ CD-ROM.
+exportcol.export_coll_not_installed:Ð€ÑÐœÐºÑÐžÐŸÐœÐ°Ð»ÑÐœÑÐµ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÐž âÐ­ÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ Ð² CD-ROMâ ÐœÐµ Ð±ÑÐ»Ðž ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ.
+
+
+# -- import.pl --
+
+import.archivedir:ÐÐŽÐµ Ð·Ð°ÐºÐ°ÐœÑÐžÐ²Ð°ÐµÑÑÑ ÐºÐŸÐœÐ²ÐµÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ ÐŒÐ°ÑÐµÑÐžÐ°Ð» Ð·Ð°ÐºÐ°ÐœÑÐžÐ²Ð°ÐµÑÑÑ.
+
+
+import.cannot_open_stats_file:ÐÐ ÐÐÐ£ÐÐ ÐÐÐÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐŸÑÐºÑÑÑÑ ÑÐ°Ð¹Ð» ÑÐŸÑÑÐŸÑÐœÐžÑ %s.
+
+
+import.cannot_open_fail_log:ÐÐšÐÐÐÐ: Ð ÐµÐ³ÐžÑÑÑÐ°ÑÐžÐŸÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» ÐœÐµ ÐŒÐŸÐ³ Ð±ÑÑÑ ÐŸÑÐºÑÑÑ %s
+
+
+import.cannot_sort:ÐÐ ÐÐÐ£ÐÐ ÐÐÐÐÐÐÐ: import.pl ÐœÐµ ÐŒÐŸÐ¶ÐµÑ ÑÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ, ÐºÐŸÐ³ÐŽÐ° ÑÐ°Ð·ÐŒÐµÑ Ð³ÑÑÐ¿Ð¿Ñ> 1. sortmeta ÐÐ¿ÑÐžÑ ÐŒÐµÑÐ°ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž Ð±ÑÐŽÐµÑ ÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÑÑÑÑ.
+
+
+import.collectdir:ÐÐžÑÐµÐºÑÐŸÑÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+
+import.complete:ÐÐŒÐ¿ÐŸÑÑ Ð·Ð°Ð²ÐµÑÑÐµÐœ
+
+
+import.debug:ÐÐ°Ð¿ÐžÑÐ°ÑÑ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ ÑÐµÐºÑÑ Ð² STDOUT.
+
+
+import.desc:Ð¡ÐºÑÐžÐ¿Ñ PERL, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÐ¹ ÐŽÐ»Ñ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ ÑÐ°Ð¹Ð»ÐŸÐ² Ð² ÑÐŸÑÐŒÐ°Ñ GML, Ð³ÐŸÑÐŸÐ² ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ.
+
+
+import.faillog:ÐÐµÑÐŽÐ°ÑÐœÐ°Ñ ÑÐµÐ³ÐžÑÑÑÐ°ÑÐžÑ ÐžÐŒÐµÐœÐž ÑÐ°Ð¹Ð»Ð°. Ð­ÑÐŸÑ Ð¶ÑÑÐœÐ°Ð» ÑÐµÐ³ÐžÑÑÑÐ°ÑÐžÐž Ð¿ÐŸÐ»ÑÑÐ°ÐµÑ ÐžÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»Ð° Ð»ÑÐ±ÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐœÐµ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÐœÑ.
+
+
+import.groupsize:Ð§ÐžÑÐ»ÐŸ ÐžÐŒÐ¿ÐŸÑÑÐžÑÑÐµÐŒÑÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² ÐŽÐ»Ñ Ð³ÑÑÐ¿Ð¿ÐžÑÐŸÐ²ÐºÐž Ð² ÐŸÐŽÐžÐœ XML ÑÐ°Ð¹Ð».
+
+
+import.gzip:ÐÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ gzip ÐŽÐ»Ñ ÑÐ¶Ð°ÑÐžÑ ÑÐµÐ·ÑÐ»ÑÑÐžÑÑÑÑÐžÑ
+ xml ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² (ÐœÐµ Ð·Ð°Ð±ÑÐŽÑÑÐµ Ð²ÐºÐ»ÑÑÐžÑÑ ZIPPlug Ð² ÐÐ°Ñ ÑÐ¿ÐžÑÐŸÐº Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ², ÐºÐŸÐ³ÐŽÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÐŸÐ·ÐŽÐ°ÐµÑÑÑ ÐžÐ· ÑÐ¶Ð°ÑÑÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²).
+
+
+import.importdir:ÐÐŽÐµ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ ÐžÑÑ
+ÐŸÐŽÐœÑÐ¹ ÐŒÐ°ÑÐµÑÐžÐ°Ð».
+
+
+import.keepold:ÐÐµ Ð±ÑÐŽÐµÑ ÑÐœÐžÑÑÐŸÐ¶Ð°ÑÑ ÑÐµÐºÑÑÐµÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ Ð°ÑÑ
+ÐžÐ²ÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž (Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ).
+
+
+import.maxdocs:ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÑÐžÑÐ»ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² ÐŽÐ»Ñ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ.
+
+
+import.no_plugins_loaded:ÐÐšÐÐÐÐ: ÐÐžÐºÐ°ÐºÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÑ ÐœÐµ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÑ.
+
+
+import.OIDtype:ÐÐµÑÐŸÐŽ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð¿ÑÐž Ð³ÐµÐœÐµÑÐžÑÐŸÐ²Ð°ÐœÐžÐž ÑÐœÐžÐºÐ°Ð»ÑÐœÑÑ
+ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ² ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°.
+
+import.OIDtype.hash:Ð¥ÐµÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐ°Ð¹Ð»Ð°. ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° Ð±ÑÐŽÐµÑ ÑÐµÐŒ Ð¶Ðµ ÑÐ°ÐŒÑÐŒ ÐºÐ°Ð¶ÐŽÑÐ¹ ÑÐ°Ð·, ÐºÐŸÐ³ÐŽÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐŒÐ¿ÐŸÑÑÐžÑÑÐµÑÑÑ.
+
+
+import.OIDtype.incremental:ÐÑÐŸÑÑÐŸÐ¹ Ð¿ÐŸÐŽÑÑÐµÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐºÐŸÑÐŸÑÑÐ¹ ÑÐ²Ð»ÑÐµÑÑÑ Ð·ÐœÐ°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð±ÐŸÐ»ÐµÐµ Ð±ÑÑÑÑÑÐŒ, ÑÐµÐŒ "Ñ
+ÐµÑÐžÑÐŸÐ²Ð°ÐœÐžÐµ". Ð­ÑÐŸ ÐœÐµ Ð³Ð°ÑÐ°ÐœÑÐžÑÑÑÑ ÑÐŸÐ³ÐŸ, ÑÑÐŸ Ð²ÑÐµÐ³ÐŽÐ° Ð±ÑÐŽÐµÑ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœ ÑÐŸÑ Ð¶Ðµ ÑÐ°ÐŒÑÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ Ðº ÐŽÐ°ÐœÐœÐŸÐŒÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ, Ñ
+ÐŸÑÑ Ðž ÐœÐµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ Ð¿ÐŸÑÐ»ÐµÐŽÑÑÑÐžÐŒ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒ Ð±ÑÑÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐœÑÐŒÐž Ðº ÑÑÑÐµÑÑÐ²ÑÑÑÐžÐŒ  xml Ð°ÑÑ
+ÐžÐ²Ð°ÐŒ.
+
+
+import.OIDtype.assigned:ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑ 'D' Ð¿Ð»ÑÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ð² Ð¿ÐŸÐ»Ðµ dc.Identifier Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°. ÐÐŸÐ»Ðµ dc.Identifiers ÐŽÐŸÐ»Ð¶ÐœÐŸ Ð±ÑÑÑ ÐŸÐŽÐœÐŸÐ·ÐœÐ°ÑÐœÑÐŒ. ÐÑÐ»Ðž dc.Identifier ÐœÐµ Ð·Ð°Ð¿ÐŸÐ»ÐœÐµÐœÐŸ ÐŽÐ»Ñ ÐŽÐ°ÐœÐœÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°, Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ Ð·Ð°ÐŒÐµÐœÑ Ð±ÑÐŽÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°Ðœ hash id.
+
+import.OIDtype.dirname:ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑ 'J' Ð¿Ð»ÑÑ ÑÐŸÐŽÐžÑÐµÐ»ÑÑÐºÑÑ Ð¿Ð°Ð¿ÐºÑ as the identifier. ÐÐ»Ñ ÑÑÐŸÐ³ÐŸ Ð² ÐºÐ°Ð¶ÐŽÐŸÐ¹ Ð¿Ð°Ð¿ÐºÐµ ÐŽÐŸÐ»Ð¶ÐµÐœ Ð±ÑÑÑ ÑÐŸÐ»ÑÐºÐŸ ÐŸÐŽÐžÐœ ÑÐ°Ð¹Ð», Ð° ÐµÐµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐŽÐŸÐ»Ð¶ÐœÐŸ Ð±ÑÑÑ ÐŸÐŽÐœÐŸÐ·ÐœÐ°ÑÐœÑÐŒ. E.g. import/b13as/h15ef/page.html Ð¿ÐŸÐ»ÑÑÐžÑ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ Jh15ef.
+
+
+import.saveas:Ð ÐºÐ°ÐºÐŸÐŒ ÑÐŸÑÐŒÐ°ÑÐµ Ð³ÐµÐœÐµÑÐžÑÐŸÐ²Ð°ÑÑ Ð°ÑÑ
+ÐžÐ². ÐÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ GA.
+
+
+import.saveas.GA:ÐÐµÐœÐµÑÐžÑÑÐµÑ ÑÐŸÑÐŒÐ°Ñ Greenstone Archive.
+
+
+import.saveas.METS:ÐÐµÐœÐµÑÐžÑÑÐµÑ ÑÐŸÑÐŒÐ°Ñ METS.
+
+
+import.out:ÐÐŒÑ ÑÐ°Ð¹Ð»Ð° ÐžÐ»Ðž ÐžÐœÐŽÐµÐºÑ ÐŽÐ»Ñ Ð·Ð°Ð¿ÐžÑÐž Ð²ÑÑ
+ÐŸÐŽÐœÐŸÐ³ÐŸ ÑÑÐ°ÑÑÑÐ° Ð².
+
+
+import.params:[ÐŸÐ¿ÑÐžÐž] ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+
+
+import.removeold:Ð£ÐŽÐ°Ð»ÐžÑ ÑÑÐ°ÑÐŸÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ Ð°ÑÑ
+ÐžÐ²ÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž - ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ñ ÐŸÑÑÐŸÑÐŸÐ¶ÐœÐŸÑÑÑÑ.
+
+
+import.removing_archives:Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÑÐµÐºÑÑÐµÐ³ÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ Ð°ÑÑ
+ÐžÐ²ÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž...
+
+
+import.sortmeta:Ð¡ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ð² Ð°Ð»ÑÐ°Ð²ÐžÑÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð ÐµÐ·ÑÐ»ÑÑÐ°ÑÑ Ð¿ÐŸÐžÑÐºÐ° Ð±ÑÐ»ÐµÐ²ÑÑ
+ Ð·Ð°Ð¿ÑÐŸÑÐŸÐ² Ð±ÑÐŽÑÑ Ð²ÑÐŽÐ°ÐœÑ Ð² ÑÑÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ. Ð­ÑÐŸ Ð±ÑÐŽÐµÑ Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÐœÐŸ, ÐµÑÐ»Ðž ÑÐ°Ð·ÐŒÐµÑ Ð³ÑÑÐ¿Ð¿Ñ> 1.
+
+
+import.statsfile:ÐÐŒÑ ÑÐ°Ð¹Ð»Ð° ÐžÐ»Ðž ÐžÐœÐŽÐµÐºÑ ÐŽÐ»Ñ Ð·Ð°Ð¿ÐžÑÐž ÑÑÐ°ÑÐžÑÑÐžÐºÐž ÐžÐŒÐ¿ÐŸÑÑÐ° Ð².
+
+
+import.stats_backup:ÐÐŒÐµÑÑÐŸ ÑÑÐŸÐ³ÐŸ Ð±ÑÐŽÐµÑ Ð·Ð°Ð¿ÐžÑÑÐ²Ð°ÑÑ stats Ð² STDERR.
+
+
+import.verbosity:Ð£Ð¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸÐŒ Ð¿ÑÐŸÐŽÑÐºÑÐžÐž. 0=ÐœÐžÑÐµÐ³ÐŸ, 3=Ð±ÐŸÐ»ÑÑÐŸÐµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸ.
+
+
+
+# -- export.pl --
+
+export.exportdir:ÐÐŽÐµ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ ÐŒÐ°ÑÐµÑÐžÐ°Ð».
+
+
+export.cannot_open_stats_file:ÐÐÐÐÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐŸÑÐºÑÑÑÑ ÑÐ°Ð¹Ð» ÑÑÐ°ÑÑ %s
+
+
+export.cannot_open_fail_log:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐŸÑÐºÑÑÑÑ ÑÐ°Ð¹Ð» Ð»ÐŸÐ³ %s
+
+
+export.cannot_sort:ÐÐÐÐÐÐÐÐ: export.pl ÐœÐµ ÐŒÐŸÐ¶ÐµÑ ÑÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ, ÐµÑÐ»Ðž ÑÐ°Ð·ÐŒÐµÑ Ð³ÑÑÐ¿Ð¿Ñ > 1. ÐÐµÑÐ°-ÐŸÐ¿ÑÐžÑ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÑ Ð±ÑÐŽÐµÑ Ð¿ÑÐŸÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÐœÐ°.
+
+
+export.collectdir:ÐÐžÑÐµÐºÑÐŸÑÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+
+export.complete:Ð­ÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐµ ÐŸÐºÐŸÐœÑÐµÐœÐœÐŸ.
+
+
+export.debug:ÐÑÐ²ÐµÑÑÐž ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ ÑÐµÐºÑÑ ÐœÐ° ÑÐºÑÐ°Ðœ.
+
+
+export.desc:PERL ÑÐºÑÐžÐ¿Ñ ÐŽÐ»Ñ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ ÑÐ°Ð¹Ð»ÐŸÐ² Ð² ÑÐŸÑÐŒÐ°Ñ GML Ð³ÐŸÑÐŸÐ² ÐŽÐ»Ñ ÐºÐŸÐœÑÑÑÑÐºÑÐžÐž.
+
+
+export.faillog:ÐÐµÑÐŽÐ°Ð»ÐŸÑÑ Ð·Ð°Ð¿ÐžÑÐ°ÑÑ Ð² Ð»ÐŸÐ³ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÑÐ°Ð¹Ð»Ð°. Ð­ÑÐŸÑ Ð»ÐŸÐ³ Ð·Ð°Ð¿ÐžÑÑÐ²Ð°ÐµÑ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÑÐ°Ð¹Ð»ÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐœÐµ ÑÐŒÐŸÐ³Ð»Ðž Ð±ÑÑÑ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÐœÐœÑ.
+
+
+export.groupsize:Ð§ÐžÑÐ»ÐŸ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÑÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² ÐŽÐ»Ñ Ð³ÑÑÐ¿Ð¿ÐžÑÐŸÐ²ÐºÐž Ð² ÐŸÐŽÐœÐŸÐŒ XML ÑÐ°Ð¹Ð»Ðµ.
+
+
+export.gzip:ÐÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÑ gzip ÐŽÐ»Ñ ÐºÐŸÐŒÐ¿ÑÐžÐŒÐžÑÐŸÐ²Ð°ÐœÐžÑ ÑÐµÐ·ÑÐ»ÑÑÐžÑÑÑÑÐžÑ
+ xml ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² (ÐœÐµ Ð·Ð°Ð±ÑÐŽÑÑÐµ Ð²ÐºÐ»ÑÑÐžÑÑ ZIPPlug Ð² ÑÐ¿ÐžÑÐŸÐº Ð²Ð°ÑÐžÑ
+ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ² Ð¿ÑÐž ÐºÐŸÐœÑÑÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐž ÐžÐ· ÐºÐŸÐŒÐ¿ÑÐžÐŒÐžÑÐŸÐ²Ð°ÐœÐžÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²).
+
+
+export.importdir:ÐÐŽÐµ ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ ÐžÑÑ
+ÐŸÐŽÐœÑÐ¹ ÐŒÐ°ÑÐµÑÐžÐ°Ð».
+
+
+export.keepold:ÐÐµ ÑÐœÐžÑÑÐŸÐ¶ÐžÑ ÐœÐ°ÑÑÐŸÑÑÐµÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž (Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ).
+
+
+export.maxdocs:ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÑÐžÑÐ»ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², Ð¿ÑÐµÐŽÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÑ
+ ÐŽÐ»Ñ ÐžÐŒÐ¿ÐŸÑÑÐ°. 
+
+
+export.no_plugins_loaded:ÐÐšÐÐÐÐ: ÐÐµÑ Ð·Ð°Ð³ÑÑÐ¶ÐµÐœÐœÑÑ
+ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ².
+
+
+export.OIDtype:ÐÐµÑÐŸÐŽ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÐ¹ Ð¿ÑÐž Ð³ÐµÐœÐµÑÐžÑÐŸÐ²Ð°ÐœÐžÐž ÐŸÐŽÐœÐŸÐ·ÐœÐ°ÑÐœÑÑ
+ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ² ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°.
+
+export.OIDtype.hash:Ð¡ÐŸÑ
+ÑÐ°ÐœÑÐµÑ Ð² ÐŸÐ¿ÐµÑÐ°ÑÐžÐŸÐœÐœÐŸÐ¹ Ð¿Ð°ÐŒÑÑÐž ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ ÑÐ°Ð¹Ð»Ð°. ÐÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÐŸÑÑÐ°ÐµÑÑÑ ÑÐµÐŒ Ð¶Ðµ Ð¿ÑÐž ÐºÐ°Ð¶ÐŽÐŸÐŒ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+export.OIDtype.incremental:ÐÑÐŸÑÑÐŸÐ¹ ÑÐ¿ÐŸÑÐŸÐ± Ð¿ÐŸÐŽÑÑÐžÑÑÐ²Ð°ÐœÐžÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐœÐ°ÐŒÐœÐŸÐ³ÐŸ Ð±ÑÑÑÑÐµÐµ, ÑÐµÐŒ "hash". ÐÐŽÐœÐ°ÐºÐŸ, ÐŸÐœ ÐœÐµ Ð³Ð°ÑÐ°ÐœÑÐžÑÐµÑ, ÑÑÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑ ÐºÐ°Ð¶ÐŽÑÐ¹ ÑÐ°Ð· Ð¿ÐŸÐ»ÑÑÐžÑ ÑÐŸÑ Ð¶Ðµ ÑÐ°ÐŒÑÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ, Ðž ÐœÐµ Ð¿ÐŸÐ·Ð²ÐŸÐ»ÑÐµÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÑÑÑ ÐœÐŸÐ²ÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ðº ÑÑÑÐµÑÑÐ²ÑÑÑÐµÐŒÑ xml Ð°ÑÑ
+ÐžÐ²Ñ.
+
+
+export.saveas:Ð ÐºÐ°ÐºÐŸÐŒ ÑÐŸÑÐŒÐ°ÑÐµ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ. ÐÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ METS.
+
+
+export.saveas.DSpace:ÐÐµÐœÐµÑÐžÑÑÐµÑ ÑÐŸÑÐŒÐ°Ñ DSpace Archive.
+
+
+export.saveas.METS:ÐÐµÐœÐµÑÐžÑÑÐµÑ ÑÐŸÑÐŒÐ°Ñ METS.
+
+
+export.out:ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ ÑÐ°Ð¹Ð»Ð° ÐžÐ»Ðž ÐµÐ³ÐŸ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ, Ð² ÐºÐŸÑÐŸÑÑÐ¹ Ð±ÑÐŽÐµÑ Ð·Ð°Ð¿ÐžÑÐ°Ðœ ÑÑÐ°ÑÑÑ Ð²ÑÐ²ÐŸÐŽÐ°.
+
+
+export.params:[ÐŸÐ¿ÑÐžÐž] ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+
+
+export.removeold:Ð£ÐŽÐ°Ð»ÐžÑ ÑÑÐ°ÑÐŸÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž -- ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ ÐŸÑÑÐŸÑÐŸÐ¶ÐœÐŸ.
+
+
+export.removing_export:Ð£ÐŽÐ°Ð»ÐµÐœÐžÐµ ÐœÐ°ÑÑÐŸÑÑÐµÐ³ÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ ÑÐºÑÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž...
+
+
+export.sortmeta:Ð¡ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ð² Ð°Ð»ÑÐ°Ð²ÐžÑÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµÐŒ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž. Ð­ÑÐŸ Ð±ÑÐŽÐµÑ Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÐœÐŸ, ÐµÑÐ»Ðž ÑÐ°Ð·ÐŒÐµÑ Ð³ÑÑÐ¿Ð¿Ñ> 1.
+
+
+export.statsfile:ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ ÑÐ°Ð¹Ð»Ð° ÐžÐ»Ðž ÐµÐ³ÐŸ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐŸÑ, Ð² ÐºÐŸÑÐŸÑÑÐ¹ Ð±ÑÐŽÑÑ Ð·Ð°Ð¿ÐžÑÐ°ÐœÑ ÑÑÐ°ÑÐžÑÑÐžÐºÐž ÑÐºÑÐ¿ÐŸÑÑÐ°.
+
+
+export.stats_backup:ÐÐ·Ð°ÐŒÐµÐœ Ð²ÑÐ²ÐŸÐŽÐžÑ ÐœÐ° STDERR (Ð¿ÑÐŸÑÐŸÐºÐŸÐ» ÐŸÑÐžÐ±ÐŸÐº).
+
+
+export.verbosity:ÐÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÑ ÐºÐŸÐ»Ð»ÐžÑÐµÑÑÐ²ÐŸ Ð²ÑÐ²ÐŸÐŽÐ°.  0=ÐœÐžÑÐµÐ³ÐŸ, 3=ÐŒÐœÐŸÐ³ÐŸ.
+
+
+
+# -- mkcol.pl --
+
+mkcol.about:Ð ÑÐµÐºÑÑÐµ ÐŽÐ»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+
+mkcol.bad_name_cvs:ÐÐšÐÐÐÐ: ÐÐžÐºÐ°ÐºÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐœÐ°Ð·Ð²Ð°ÐœÐ° CVS, Ð¿ÐŸÑÐºÐŸÐ»ÑÐºÑ ÑÑÐŸ ÐŒÐŸÐ¶ÐµÑ ÐœÐ°Ð»ÐŸÐ¶ÐžÑÑÑÑ ÐœÐ° ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž, ÑÐŸÐ·ÐŽÐ°ÐœÐœÑÐµ Ð²ÐµÑÑÐžÐµÐ¹ CVS ÑÐžÑÑÐµÐŒÑ.
+
+
+mkcol.bad_name_modelcol:ÐÐšÐÐÐÐ: ÐÐžÐºÐ°ÐºÐ°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐœÐµ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐœÐ°Ð·Ð²Ð°ÐœÐ° modelcol, Ð¿ÐŸÑÐºÐŸÐ»ÑÐºÑ ÑÑÐŸ ÐžÐŒÑ ÐŒÐŸÐŽÐµÐ»ÑÐœÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+
+mkcol.cannot_find_modelcol:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐœÐ°Ð¹ÑÐž ÐŒÐŸÐŽÐµÐ»ÑÐœÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ %s
+
+
+mkcol.col_already_exists:ÐÐšÐÐÐÐ: Ð­ÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÑÐ¶Ðµ ÑÑÑÐµÑÑÐ²ÑÐµÑ.
+
+
+mkcol.collectdir:ÐÐžÑÐµÐºÑÐŸÑÐžÑ, Ð³ÐŽÐµ ÐœÐŸÐ²Ð°Ñ ÐºÐŸÐ»ÐµÐºÑÐžÑ Ð±ÑÐŽÐµÑ ÑÐŸÐ·ÐŽÐ°ÐœÐ°.
+
+
+mkcol.creating_col:Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž %s
+
+
+mkcol.creator:ÐÐŽÑÐµÑ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ ÑÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+
+mkcol.creator_undefined:ÐÐšÐÐÐÐ: ÑÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ ÐœÐµ Ð±ÑÐ» ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœ. Ð­ÑÐ° Ð¿ÐµÑÐµÐŒÐµÐœÐœÐ°Ñ ÐœÐµÐŸÐ±Ñ
+ÐŸÐŽÐžÐŒÐ°, ÑÑÐŸÐ±Ñ ÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°ÑÑ ÐŽÑÐ±Ð»ÐžÐºÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+
+mkcol.desc:Ð¡ÐºÑÐžÐ¿Ñ PERL, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÐ¹ ÐŽÐ»Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÑÑÑÑÐºÑÑÑÑ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž ÐŽÐ»Ñ ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Greenstone.
+
+
+mkcol.doing_replacements:Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐžÐµ Ð·Ð°ÐŒÐµÐœ ÐŽÐ»Ñ %s
+
+
+mkcol.long_colname:ÐÐšÐÐÐÐ: ÐÐŒÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŽÐŸÐ»Ð¶ÐœÐŸ ÑÐŸÐŽÐµÑÐ¶Ð°ÑÑ ÐŒÐµÐœÐµÐµ 8 Ð·ÐœÐ°ÐºÐŸÐ², ÑÑÐŸÐ±Ñ Ð±ÑÑÑ ÑÐŸÐ²ÐŒÐµÑÑÐžÐŒÑÐŒ  Ñ Ð±ÐŸÐ»ÐµÐµ ÑÐ°ÐœÐœÐžÐŒÐž ÑÐ°Ð¹Ð»ÐŸÐ²ÑÐŒÐž ÑÐžÑÑÐµÐŒÐ°ÐŒÐž Ðž ÐžÐŒÐµÑÑ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÑ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÐž.
+
+
+mkcol.maintainer:ÐÐŽÑÐµÑ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ Ð»ÐžÑÐ°, Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÑÑÐµÐ³ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ (ÐµÑÐ»Ðž ÐŸÐœ ÐŸÑÐ»ÐžÑÐ°ÐµÑÑÑ ÐŸÑ ÑÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ).
+
+
+mkcol.no_collectdir:ÐÐšÐÐÐÐ: ÐÐžÑÐµÐºÑÐŸÑÐžÑ collect ÐœÐµ ÑÑÑÐµÑÑÐ²ÑÐµÑ: %s
+
+
+mkcol.no_colname:ÐÐšÐÐÐÐ: ÐÐžÐºÐ°ÐºÐŸÐ³ÐŸ ÐžÐŒÐµÐœÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐœÐµ Ð±ÑÐ»ÐŸ Ð·Ð°ÐŽÐ°ÐœÐŸ.
+
+
+mkcol.optionfile:ÐÐŸÐ»ÑÑÐžÑÑ ÐŸÐ¿ÑÐžÐž ÑÐ°Ð¹Ð»Ð°, Ð¿ÐŸÐ»ÐµÐ·ÐœÐŸÐ³ÐŸ ÐŽÐ»Ñ ÑÐžÑÑÐµÐŒ, Ð³ÐŽÐµ ÐŽÐ»ÐžÐœÐœÑÐµ ÐºÐŸÐŒÐ°ÐœÐŽÐœÑÐµ ÑÑÑÐŸÐºÐž ÐŒÐŸÐ³ÑÑ Ð²ÑÐ·ÑÐ²Ð°ÑÑ Ð¿ÑÐŸÐ±Ð»ÐµÐŒÑ.
+
+
+mkcol.params:[ÐŸÐ¿ÑÐžÐž] ÐžÐŒÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž
+
+
+mkcol.plugin:ÐÐŸÐŽÑÐ»Ñ Ð¿Ð»Ð°Ð³ÐžÐœÐ° Perl ÐŽÐ»Ñ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ (Ð·ÐŽÐµÑÑ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐŒÐœÐŸÐ³ÐŸÐºÑÐ°ÑÐœÑÐµ Ð²Ñ
+ÐŸÐ¶ÐŽÐµÐœÐžÑ Ð¿Ð»Ð°Ð³ÐžÐœÐ°).
+
+
+mkcol.public:ÐÑÐ»Ðž ÑÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ ÐžÐŒÐµÐµÑ Ð°ÐœÐŸÐœÐžÐŒÐœÑÐ¹  ÐŽÐŸÑÑÑÐ¿ (Ð²ÐµÑÐœÑÐ¹/Ð»ÐŸÐ¶ÐœÑÐ¹).
+
+
+mkcol.quiet:Ð Ð°Ð±ÐŸÑÐ°ÑÑ ÑÐ¿ÐŸÐºÐŸÐ¹ÐœÐŸ.
+
+
+mkcol.success:ÐÐŸÐ²Ð°Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ Ð±ÑÐ»Ð° ÑÐŸÐ·ÐŽÐ°ÐœÐ° ÑÑÐ¿ÐµÑÐœÐŸ Ð² %s
+
+
+mkcol.title:ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+
+mkcol.win31compat:Ð£ÑÐžÑÑÐ²Ð°ÑÑ Ð»Ðž ÐºÐŸÐœÐ²ÐµÐœÑÐžÐž Windows 3.1, Ð¿ÑÐž Ð²ÑÐ±ÐŸÑÐµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ ÐŽÐ»Ñ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐœÐµ Ð±ÐŸÐ»ÐµÐµ 8 Ð·ÐœÐ°ÐºÐŸÐ²).
+
+
+# -- pluginfo.pl --
+
+pluginfo.collect:ÐÑÐµÐŽÐŸÑÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐžÐŒÐµÐœÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ð±ÑÐŽÐµÑ Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐŸ Ð¿ÑÐž Ð¿ÑÐŸÑÐŒÐŸÑÑÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ² Ð¿ÑÐµÐ¶ÐŽÐµ Ð²ÑÐµÐ³ÐŸ  Ð² collect/collection-name/perllib/plugins.  ÐÑÐ»Ðž Ð¿Ð»Ð°Ð³ÐžÐœ ÑÐ°ÐŒ ÐœÐµ ÐœÐ°Ð¹ÐŽÐµÐœ, ÑÐŸ ÐœÐ°ÐŽÐŸ Ð±ÑÐŽÐµÑ Ð¿ÑÐŸÑÐŒÐŸÑÑÐµÑÑ Ð² ÐŸÐ±ÑÐµÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž perllib/plugins.
+
+
+pluginfo.desc:ÐÐ°Ð¿ÐžÑÐ°ÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ Ð¿Ð»Ð°Ð³ÐžÐœÐ°Ñ
+.
+
+
+pluginfo.general_options:ÐÐ±ÑÐžÐµ ÐŸÐ¿ÑÐžÐž, ÑÐœÐ°ÑÐ»ÐµÐŽÐŸÐ²Ð°ÐœÐœÑÐµ ÐŸÑ ÑÐŸÐŽÐžÑÐµÐ»ÑÑÐºÐžÑ
+ ÐºÐ»Ð°ÑÑÐŸÐ² Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ².
+
+
+pluginfo.info:ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ
+
+
+pluginfo.no_plugin_name:ÐÐšÐÐÐÐ: ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ Ð·Ð°ÐŽÐ°ÑÑ ÐžÐŒÑ Ð¿Ð»Ð°Ð³ÐžÐœÐ°.
+
+
+pluginfo.option_types:ÐÐ»Ð°Ð³ÐžÐœÑ ÐŒÐŸÐ³ÑÑ ÐžÐŒÐµÑÑ ÐŽÐ²Ð° ÑÐžÐ¿Ð° ÐŸÐ¿ÑÐžÐ¹.
+
+
+pluginfo.params:[ÐŸÐ¿ÑÐžÐž] ÐžÐŒÑ Ð¿Ð»Ð°Ð³ÐžÐœÐ°
+
+
+pluginfo.passing_options:ÐÐ¿ÑÐžÐž ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ Ð¿ÐµÑÐµÐŽÐ°ÐœÑ Ð»ÑÐ±ÑÐŒ Ð¿Ð»Ð°Ð³ÐžÐœÐ°ÐŒ Ð²ÐºÐ»ÑÑÐµÐœÐžÐµÐŒ ÐžÑ
+ Ð² ÐÐ°Ñ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» collect.cfg.
+
+
+pluginfo.specific_options:Ð¡Ð¿ÐµÑÐžÑÐžÑÐµÑÐºÐžÐµ ÐŸÐ¿ÑÐžÐž ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÑ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÑÐ°ÐŒÐžÑ
+ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ² Ðž ÐŽÐŸÑÑÑÐ¿ÐœÑ ÑÐŸÐ»ÑÐºÐŸ ÑÑÐŸÐŒÑ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐŸÐŒÑ Ð¿Ð»Ð°Ð³ÐžÐœÑ.
+
+
+
+#
+# Classifier option descriptions
+#
+
+AZCompactList.allvalues:ÐÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð²ÑÐµ ÐœÐ°Ð¹ÐŽÐµÐœÐœÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+.
+
+AZCompactList.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° ÐŽÐ»Ñ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž Ð² Ð°Ð»ÑÐ°Ð²ÐžÑÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ
+
+
+AZCompactList.doclevel:Ð£ÑÐŸÐ²ÐµÐœÑ ÐŽÐ»Ñ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° Ð².
+
+AZCompactList.doclevel.top:ÐŠÐµÐ»ÑÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ.
+
+AZCompactList.doclevel.section:Ð Ð°Ð·ÐŽÐµÐ»Ð°ÐŒÐž.
+
+
+AZCompactList.firstvalueonly:ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ ÑÐŸÐ»ÑÐºÐŸ Ð¿ÐµÑÐ²ÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.
+
+
+AZCompactList.freqsort:Ð¡ÐŸÑÑÐžÑÐŸÐ²Ð°ÑÑ Ð¿ÐŸ ÑÐ°ÑÑÐŸÑÐµ ÑÐ·Ð»Ð°, Ð° ÐœÐµ Ð² Ð°Ð»ÑÐ°Ð²ÐžÑÐœÐŸ-ÑÐžÑÑÐŸÐ²ÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ.
+
+
+AZCompactList.maxcompact:ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÑÐžÑÐ»ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ Ð±ÑÐŽÑÑ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÑ ÐœÐ° ÑÑÑÐ°ÐœÐžÑÐµ.
+
+
+AZCompactList.metadata:ÐÐŽÐžÐœÑÑÐ²ÐµÐœÐœÐŸÐµ Ð¿ÐŸÐ»Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐžÐ»Ðž Ð·Ð°Ð¿ÑÑÐ°Ñ ÑÐ°Ð·ÐŽÐµÐ»ÐžÑÐµÐ»Ñ Ð¿ÐŸÐ»ÐµÐ¹ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž. ÐÑÐ»Ðž ÑÐ¿ÐžÑÐŸÐº ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœ, Ð±ÑÐŽÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ Ð¿ÐµÑÐ²ÑÐ¹ ÑÐžÐ¿ ÐŒÐµÑÐ°Ð»ÐŽÐ°ÐœÐœÑÑ
+, ÐºÐŸÑÐŸÑÑÐ¹ ÐŸÐ±Ð»Ð°ÐŽÐ°ÐµÑ Ð·ÐœÐ°ÑÐµÐœÐžÑÐŒÐž. ÐÐŸÐ¶ÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ Ð² ÑÐŸÐµÐŽÐžÐœÐµÐœÐžÐž Ñ -firstvalueonly Ðž ÑÐ»Ð°Ð³Ð°ÐŒÐž -allvalues, ÐŽÐ»Ñ Ð²ÑÐ±ÐŸÑÐ° ÑÐŸÐ»ÑÐºÐŸ Ð¿ÐµÑÐ²ÐŸÐ³ÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÑ, ÐžÐ»Ðž Ð²ÑÐµÑ
+ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐžÐ· ÑÐ¿ÐžÑÐºÐ°.
+
+
+AZCompactList.mincompact:ÐÐžÐœÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÑÐžÑÐ»ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ Ð±ÑÐŽÑÑ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÑ ÐœÐ° ÑÑÑÐ°ÐœÐžÑÐµ.
+
+
+AZCompactList.mingroup:ÐÐ°ÐžÐŒÐµÐœÑÑÐ°Ñ ÑÐžÑÐ»ÐŸ, ÐºÐŸÑÐŸÑÐŸÐµ Ð²ÑÐ·ÑÐ²Ð°ÐµÑ ÑÐŸÑÐŒÐžÑÐŸÐ²Ð°ÐœÐžÐµ Ð³ÑÑÐ¿Ð¿ Ð² ÐžÐµÑÐ°ÑÑ
+ÐžÑÐµÑÐºÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ.
+
+
+AZCompactList.minnesting:ÐÐ°ÐžÐŒÐµÐœÑÑÐµÐµ ÑÐžÑÐ»ÐŸ, ÐºÐŸÑÐŸÑÐŸÐµ Ð²ÑÐ·ÐŸÐ²ÐµÑ Ð¿ÑÐµÐŸÐ±ÑÐ°Ð·ÐŸÐ²Ð°ÐœÐžÐµ ÑÐ¿ÐžÑÐºÐ° Ð²ÐŸ Ð²Ð»ÐŸÐ¶ÐµÐœÐœÑÐ¹ ÑÐ¿ÐžÑÐŸÐº.
+
+
+AZCompactList.recopt:ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÐ¹ Ð²ÐŸ Ð²Ð»ÐŸÐ¶ÐµÐœÐœÑÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÑÐžÐ¿Ð° -ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐÐŸÐŽÐ°/ÐÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÐž.
+
+AZCompactList.sort:ÐÐŸÐ»Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž ÐŽÐŸÑÐµÑÐœÐžÑ
+ ÑÐ·Ð»ÐŸÐ² Ñ Ð¿ÐŸÐŒÐŸÑÑÑ
+
+
+AZCompactSectionList.desc:ÐÐ°ÑÐžÐ°ÑÐžÐž Ð² AZCompactList, ÐºÐŸÑÐŸÑÑÐ¹ ÐºÐ»Ð°ÑÑÐžÑÐžÑÐžÑÑÐµÑ ÑÐ°Ð·ÐŽÐµÐ»Ñ, Ð° ÐœÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ. ÐÑ
+ÐŸÐ¶ÐŽÐµÐœÐžÑ ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÑ Ð¿ÐŸ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒ ÑÑÐŸÐ²ÐœÑ ÑÐ°Ð·ÐŽÐµÐ»Ð°.
+
+
+AZList.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° ÐŽÐ»Ñ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž Ð² Ð°Ð»ÑÐ°Ð²ÐžÑÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ
+
+
+AZList.metadata:ÐÐŽÐžÐœÑÑÐ²ÐµÐœÐœÐŸÐµ Ð¿ÐŸÐ»Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐžÐ»Ðž ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐœÑÐ¹ Ð·Ð°Ð¿ÑÑÐŸÐ¹ ÑÐ¿ÐžÑÐŸÐº Ð¿ÐŸÐ»ÐµÐ¹ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÑ
+ ÐŽÐ»Ñ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž. Ð¡Ð»ÐµÐŽÑÑ Ð¿ÐŸÑÑÐŽÐºÑ, ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐœÐŸÐŒÑ Ð² ÑÐ¿ÐžÑÐºÐµ, Ð¿ÐµÑÐ²ÐŸÐµ Ð¿ÐŸÐ»Ðµ, ÐºÐŸÑÐŸÑÐŸÐµ ÑÐŸÐŽÐµÑÐ¶ÐžÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, Ð±ÑÐŽÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ. Ð¡Ð¿ÐžÑÐŸÐº Ð±ÑÐŽÐµÑ ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°Ðœ Ð¿ÐŸ ÑÑÐŸÐŒÑ ÑÐ»ÐµÐŒÐµÐœÑÑ.
+
+
+AZSectionList.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° ÐŽÐ»Ñ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž Ð² Ð°Ð»ÑÐ°Ð²ÐžÑÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ. ÐÐœ ÐŸÑÐµÐœÑ Ð¿ÐŸÑ
+ÐŸÐ¶ ÐœÐ° AZList, Ð·Ð° ÐžÑÐºÐ»ÑÑÐµÐœÐžÐµÐŒ ÑÐŸÐ³ÐŸ, ÑÑÐŸ ÐŸÐœ ÑÐŸÑÑÐžÑÑÐµÑ Ð¿ÐŸ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒ ÑÑÐŸÐ²ÐœÑ ÑÐ°Ð·ÐŽÐµÐ»Ð° (ÐžÑÐºÐ»ÑÑÐ°Ñ Ð²ÐµÑÑ
+ÐœÐžÐ¹ ÑÑÐŸÐ²ÐµÐœÑ) Ð²ÐŒÐµÑÑÐŸ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž ÑÐŸÐ»ÑÐºÐŸ  Ð¿ÐŸ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒ Ð²ÐµÑÑ
+ÐœÐµÐ³ÐŸ ÑÑÐŸÐ²ÐœÑ. ÐÐŽÐžÐœÑÑÐ²ÐµÐœÐœÐŸÐµ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÐµ ÐŸÑÐœÐŸÑÐžÑÑÑ Ðº Ð¿ÐŸÐŽÐ¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐµ  () ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž, ÐºÐŸÑÐŸÑÐ°Ñ  ÑÐµÐ¿ÐµÑÑ ÐŽÐŸÐ»Ð¶ÐœÐ° Ð¿ÑÐŸÐ²ÐŸÐŽÐžÑÑ ÐžÑÐµÑÐ°ÑÐžÑ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÑÐ°Ð·ÐŽÐµÐ»Ð°, ÐŽÐŸÐ±Ð°Ð²Ð»ÑÑ ÐºÐ°Ð¶ÐŽÑÐ¹ Ð² ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÑ.
+
+
+BasClas.bad_general_option:ÐÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ %s  ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑ ÐœÐµÐºÐŸÑÑÐµÐºÑÐœÑÑ ÐŸÐ±ÑÑÑ ÐŸÐ¿ÑÐžÑ (ÐŸÐ±ÑÐžÐµ ÐŸÐ¿ÑÐžÐž  - ÑÑÐŸ ÑÐ°ÐºÐžÐµ, ÐºÐŸÑÐŸÑÑÐµ ÐŽÐŸÑÑÑÐ¿ÐœÑ ÐŽÐ»Ñ Ð²ÑÐµÑ
+ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ²). ÐÑÐŸÐ²ÐµÑÑÑÐµ ÐÐ°Ñ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» collect.cfg.
+
+
+BasClas.builddir:ÐÐŽÐµ Ð¿ÐŸÐŒÐµÑÑÐžÑÑ Ð¿ÐŸÑÑÑÐŸÐµÐœÐœÑÐµ ÐžÐœÐŽÐµÐºÑÑ.
+
+
+BasClas.buttonname:Ð¯ÑÐ»ÑÐº ÐŽÐ»Ñ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° Ð¿ÐŸÐºÐ°Ð·Ð° ÐœÐ° ÑÐºÑÐ°ÐœÐµ Ðž ÐºÐœÐŸÐ¿ÐºÐ° Ð² ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÐŸÐœÐœÐŸÐ¹ Ð»ÐžÐœÐµÐ¹ÐºÐµ.
+
+
+BasClas.desc:ÐÑÐœÐŸÐ²ÐœÐŸÐ¹ ÐºÐ»Ð°ÑÑ ÐŽÐ»Ñ Ð²ÑÐµÑ
+ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ².
+
+
+BasClas.outhandle:ÐÐœÐŽÐµÐºÑÐœÑÐ¹ ÑÐ°Ð¹Ð» ÐŽÐ»Ñ ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐ°.
+
+
+BasClas.removeprefix:ÐÑÐµÑÐžÐºÑ, Ñ ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ ÐœÐ°ÑÐžÐœÐ°ÑÑÑÑ ÐŽÐ°ÐœÐœÑÐµ ÐŽÐ»Ñ ÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÐœÐžÑ Ð¿ÑÐž ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž.
+
+BasClas.removesuffix:Ð¡ÑÑÑÐžÐºÑ, Ñ ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ ÐœÐ°ÑÐžÐœÐ°ÑÑÑÑ ÐŽÐ°ÐœÐœÑÐµ ÐŽÐ»Ñ ÐžÐ³ÐœÐŸÑÐžÑÐŸÐ²Ð°ÐœÐžÑ Ð¿ÑÐž ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž.
+
+BasClas.verbosity:Ð£Ð¿ÑÐ°Ð²Ð»ÐµÐœÐžÐµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸÐŒ Ð¿ÑÐŸÐŽÑÐºÑÐžÐž. 0=ÐŸÑÑÑÑÑÑÐ²ÐžÐµ, 3=Ð±ÐŸÐ»ÑÑÐžÐµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²Ð°.
+
+
+Browse.desc:.
+
+
+DateList.bymonth:ÐÐ»Ð°ÑÑÐžÑÐžÑÐžÑÐŸÐ²Ð°ÑÑ Ð¿ÐŸ Ð³ÐŸÐŽÑ Ðž ÐŒÐµÑÑÑÑ Ð²ÐŒÐµÑÑÐŸ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž ÑÐŸÐ»ÑÐºÐŸ Ð¿ÐŸ Ð³ÐŸÐŽÑ
+
+
+DateList.desc:ÐÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐŸÐœÐœÑÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž Ð¿ÐŸ ÐŽÐ°ÑÐ°ÐŒ. ÐÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐ° Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑÑÑ Ð¿ÐŸ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒ 'ÐÐ°ÑÐ°'. ÐÑÐžÐœÑÑÐŸ, ÑÑÐŸ ÐŽÐ°ÑÐ° ÐŽÐŸÐ»Ð¶ÐœÐ° ÐžÐŒÐµÑÑ Ð²ÐžÐŽ Ð³Ð³Ð³Ð³ÐŒÐŒÐŽÐŽ.
+
+
+DateList.metadata:ÐÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ, ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ ÐŽÐ°ÑÑ Ñ ÑÐµÐ»ÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž. ÐÑÐµÐŽÐ¿ÐŸÐ»Ð°Ð³Ð°ÐµÑÑÑ, ÑÑÐŸ ÑÐŸÑÐŒÐ°Ñ Ð±ÑÐŽÐµÑ Ð³Ð³Ð³Ð³ÐŒÐŒÐŽÐŽ.
+
+
+DateList.reverse_sort:Ð¡ÐŸÑÑÐžÑÐŸÐ²ÐºÐ° ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Ð² ÐŸÐ±ÑÐ°ÑÐœÐŸÐŒ Ñ
+ÑÐŸÐœÐŸÐ»ÐŸÐ³ÐžÑÐµÑÐºÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ (ÐœÐŸÐ²ÐµÐ¹ÑÐžÐ¹ Ð²ÐœÐ°ÑÐ°Ð»Ðµ).
+
+
+DateList.nogroup:Ð¡ÐŽÐµÐ»Ð°ÑÑ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ Ð³ÐŸÐŽÐ° ÐžÐœÐŽÐžÐ²ÐžÐŽÑÐ°Ð»ÑÐœÑÐ¹ Ð²Ñ
+ÐŸÐŽ Ð² Ð³ÐŸÑÐžÐ·ÐŸÐœÑÐ°Ð»ÑÐœÐŸÐŒ ÑÐ¿ÐžÑÐºÐµ, Ð²ÐŒÐµÑÑÐŸ ÑÐŸÐ³ÐŸ, ÑÑÐŸÐ±Ñ ÐŸÑ
+Ð²Ð°ÑÐžÑÑ Ð³ÐŸÐŽÑ ÐœÐµÑÐºÐŸÐ»ÑÐºÐžÐŒÐž Ð²Ñ
+ÐŸÐŽÐ°ÐŒÐž. (Ð­ÑÐŸ ÐŒÐŸÐ¶ÐµÑ ÑÐ°ÐºÐ¶Ðµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ ÐŽÐ»Ñ ÐŽÐ²ÑÑ
+ÐŒÐµÑÑÑÐœÐŸÐ¹ ÐŸÐ¿ÑÐžÐž, ÐŽÐµÐ»Ð°Ñ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐŒÐµÑÑÑÐ° ÐŸÑÐŽÐµÐ»ÑÐœÑÐ¹ Ð²Ñ
+ÐŸÐŽ Ð²ÐŒÐµÑÑÐŸ ÐŸÐ±ÑÐµÐŽÐžÐœÐµÐœÐŸÐ³ÐŸ).
+
+
+DateList.sort:ÐÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐŸÐµ Ð¿ÐŸÐ»Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž Ð² ÑÐ»ÑÑÐ°Ðµ, ÐºÐŸÐ³ÐŽÐ° ÐŽÐ²Ð° ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÐžÐŒÐµÑÑ ÐŸÐŽÐœÑ Ðž ÑÑ Ð¶Ðµ  ÐŽÐ°ÑÑ.
+
+
+HFileHierarchy.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° ÐŽÐ»Ñ Ð³ÐµÐœÐµÑÐžÑÐŸÐ²Ð°ÐœÐžÑ ÐžÐµÑÐ°ÑÑ
+ÐžÑÐµÑÐºÐžÑ
+ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐ¹, Ð¿ÐŸÑÑÑÐŸÐµÐœÐœÑÑ
+ ÐœÐ° ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÐŸÐŒ ÑÐ°Ð¹Ð»Ðµ ÑÐŸ ÑÑÑÑÐºÑÑÑÐŸÐ¹.
+
+Hierarchy.hfile:Ð¡ÑÑÑÐºÑÑÑÐ° ÑÐ°Ð¹Ð»Ð° ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž.
+
+Hierarchy.hlist_at_top:ÐÐŸÐºÐ°Ð·Ð°ÑÑ Ð¿ÐµÑÐ²ÑÐ¹ ÑÑÐŸÐ²ÐµÐœÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž Ð³ÐŸÑÐžÐ·ÐŸÐœÑÐ°Ð»ÑÐœÐŸ.
+
+Hierarchy.reverse_sort:Ð¡ÐŸÑÑÐžÑÐŸÐ²ÐºÐ° Ð»ÐžÑÑÑÐµÐ² ÐŽÐµÑÐµÐ²Ð° (ÐºÐŸÐœÑÐµÐ²ÑÑ
+ Ð²ÐµÑÑÐžÐœ) Ð² ÐŸÐ±ÑÐ°ÑÐœÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ (ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ Ñ -sort).
+
+Hierarchy.separator:Ð ÐµÐ³ÑÐ»ÑÑÐœÐŸÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐœÐŸÐµ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÑÐ°Ð·ÐŽÐµÐ»ÐžÑÐµÐ»Ñ.
+
+
+Hierarchy.sort:ÐÐŸÐ»Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž. ÐÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ'-sort nosort', ÐµÑÐ»Ðž ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐ° ÐœÐµ ÐœÑÐ¶ÐœÐ°.
+
+Hierarchy.suppresslastlevel:ÐÐ³ÐœÐŸÑÐžÑÑÐ¹ÑÐµ Ð¿ÐŸÑÐ»ÐµÐŽÐœÑÑ ÑÐ°ÑÑÑ Ð² Ð·ÐœÐ°ÑÐµÐœÐžÐž ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+. Ð­ÑÐŸ Ð¿ÐŸÐ»ÐµÐ·ÐœÐŸ ÐŽÐ»Ñ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+, Ð² ÐºÐŸÑÐŸÑÑÑ
+ ÐºÐ°Ð¶ÐŽÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŸÐŽÐžÐœÐ°ÐºÐŸÐ²ÐŸ, ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, Ð²ÐµÑÐ²Ñ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž.
+
+HTML.desc:Ð¡ÐŸÐ·ÐŽÐ°ÐµÑ Ð¿ÑÑÑÑÑ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÑ, ÐºÐŸÑÐŸÑÐ°Ñ ÑÐ²Ð»ÑÐµÑÑÑ Ð¿ÑÐŸÑÑÐŸ ÑÑÑÐ»ÐºÐŸÐ¹ ÐœÐ° Ð²ÐµÐ±-ÑÑÑÐ°ÐœÐžÑÑ.
+
+
+HTML.url:URL Ð²ÐµÐ±-ÑÑÑÐ°ÐœÐžÑÑ ÐŽÐ»Ñ ÑÐ²ÑÐ·Ðž Ñ.
+
+
+List.desc:ÐÑÐŸÑÑÐŸÐ¹ ÑÐ¿ÐžÑÐŸÐº Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ² ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž.
+
+
+List.metadata:ÐÐŽÐžÐœÑÑÐ²ÐµÐœÐœÐŸÐµ Ð¿ÐŸÐ»Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐžÐ»Ðž ÑÐ°Ð·ÐŽÐµÐ»ÐµÐœÐœÑÐ¹ Ð·Ð°Ð¿ÑÑÐŸÐ¹ ÑÐ¿ÐžÑÐŸÐº Ð¿ÐŸÐ»ÐµÐ¹ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÑ
+ ÐŽÐ»Ñ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž. Ð¡Ð»ÐµÐŽÑÑ Ð¿ÐŸÑÑÐŽÐºÑ, ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐµÐœÐœÐŸÐŒÑ Ð² ÑÐ¿ÐžÑÐºÐµ, Ð¿ÐµÑÐ²ÐŸÐµ Ð¿ÐŸÐ»Ðµ, ÐºÐŸÑÐŸÑÐŸÐµ ÑÐŸÐŽÐµÑÐ¶ÐžÑ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, Ð±ÑÐŽÐµÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑÑÑ. Ð¡Ð¿ÐžÑÐŸÐº Ð±ÑÐŽÐµÑ ÐŸÑÑÐŸÑÑÐžÑÐŸÐ²Ð°Ðœ ÑÑÐžÐŒ ÑÐ»ÐµÐŒÐµÐœÑÐŸÐŒ, ÐµÑÐ»Ðž ÐœÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ -sort.
+
+
+List.sort:ÐÐŸÐ»Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐ»Ñ ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐž. ÐÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ'-sort nosort', ÐµÑÐ»Ðž ÑÐŸÑÑÐžÑÐŸÐ²ÐºÐ° ÐœÐµ ÐœÑÐ¶ÐœÐ°.
+
+
+Phind.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐºÐ»Ð°ÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° Phind.
+
+
+Phind.language:Ð¯Ð·ÑÐº ÐžÐ»Ðž ÑÐ·ÑÐºÐž, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÐµ ÐŽÐ»Ñ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ ÐžÐµÑÐ°ÑÑ
+ÐžÐž. Ð¯Ð·ÑÐºÐž ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐ°ÑÑÑÑ ÐŽÐ²ÑÑ
+Ð±ÑÐºÐ²ÐµÐœÐœÑÐŒÐž ÐºÐŸÐŽÐ°ÐŒÐž ÑÑÑÐ°Ðœ, Ðº Ð¿ÑÐžÐŒÐµÑÑ, en (Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐžÐ¹ ÑÐ·ÑÐº), es (ÐžÑÐ¿Ð°ÐœÑÐºÐžÐ¹ ÑÐ·ÑÐº) Ðž fr (ÑÑÐ°ÐœÑÑÐ·ÑÐºÐžÐ¹ ÑÐ·ÑÐº). Ð¯Ð·ÑÐº ÑÐ²Ð»ÑÐµÑÑÑ Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÑÐŒ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµÐŒ, ÑÐ°Ðº 'en|fr' (Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐžÐ¹ ÐžÐ»Ðž ÑÑÐ°ÐœÑÑÐ·ÑÐºÐžÐ¹ ÑÐ·ÑÐº) Ðž '..' (ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÐŸ, Ð»ÑÐ±ÐŸÐ¹ ÑÐ·ÑÐº) Ð¿ÑÐžÐ³ÐŸÐŽÐœÑ.
+
+
+Phind.min_occurs:ÐÐžÐœÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÑÐžÑÐ»ÐŸ ÐŸÐ±ÐŸÐ·ÐœÐ°ÑÐ°ÑÑÐµÐµ, ÑÐºÐŸÐ»ÐºÐŸ ÑÐ°Ð· ÑÑÐ°Ð·Ð° ÐŽÐŸÐ»Ð¶ÐœÐ° Ð²ÑÑÑÐµÑÐžÑÑÑÑ Ð² ÑÐµÐºÑÑÐµ, ÑÑÐŸÐ±Ñ Ð±ÑÑÑ Ð²ÐºÐ»ÑÑÐµÐœÐœÐŸÐ¹ Ð²ÐŸ ÑÑÐ°Ð·ÐŸÐ²ÑÑ ÐžÐµÑÐ°ÑÑ
+ÐžÑ.
+
+
+Phind.savephrases:ÐÑÐ»Ðž ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐŸ, ÑÐŸ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÐŸÐœÐœÐ°Ñ ÑÑÐ°Ð·Ð° Ð±ÑÐŽÐµÑ Ñ
+ÑÐ°ÐœÐžÑÑÑÑ Ð² Ð·Ð°ÐŽÐ°ÐœÐœÐŸÐŒ ÑÐ°Ð¹Ð»Ðµ ÐºÐ°Ðº ÑÐµÐºÑÑ. Ð­ÑÐŸ  Ð²ÐµÑÐŸÑÑÐœÐŸ Ñ
+ÐŸÑÐŸÑÐ°Ñ ÐžÐŽÐµÑ - ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ð°Ð±ÑÐŸÐ»ÑÑÐœÑÐ¹ Ð¿ÑÑÑ ÐŽÐŸÑÑÑÐ¿Ð°.
+
+
+Phind.suffixmode:Smode Ð¿Ð°ÑÐ°ÐŒÐµÑÑ Ðº Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐµ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÑ ÑÑÐ°Ð·Ñ. ÐÐœÐ°ÑÐµÐœÐžÐµ 0 ÐŸÐ·ÐœÐ°ÑÐ°ÐµÑ, ÑÑÐŸ ÑÑÐŸÐ¿-ÑÐ»ÐŸÐ²Ð° ÐžÐ³ÐœÐŸÑÐžÑÑÑÑÑÑ, Ð° 1  -  ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ.
+
+
+Phind.text:Ð¢ÐµÐºÑÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÐ¹ ÐŽÐ»Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÐžÐµÑÐ°ÑÑ
+ÐžÐž ÑÑÐ°Ð·.
+
+
+Phind.thesaurus:ÐÐŒÑ ÑÐµÐ·Ð°ÑÑÑÑÐ°, Ñ
+ÑÐ°ÐœÑÑÐµÐ³ÐŸÑÑ Ð² Phind-ÑÐŸÑÐŒÐ°ÑÐµ Ð² ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž Ñ.ÐŽ.
+
+
+Phind.title:ÐÐŸÐ»Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐŸÐµ ÐŽÐ»Ñ ÐŸÐ¿ÐžÑÐ°ÐœÐžÑ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°.
+
+
+Phind.untidy:ÐÐµ ÑÐŽÐ°Ð»ÑÑÑ ÑÐ°Ð±ÐŸÑÐžÐµ ÑÐ°Ð¹Ð»Ñ.
+
+
+SectionList.desc:Ð¢ÐŸ Ð¶Ðµ ÑÐ°ÐŒÐŸÐµ, ÑÑÐŸ Ðž ÑÐ¿ÐžÑÐŸÐº ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐŸÐ², ÐœÐŸ Ð²ÐºÐ»ÑÑÐ°ÐµÑ Ð²ÑÐµ ÑÐ°Ð·ÐŽÐµÐ»Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° (ÐžÑÐºÐ»ÑÑÐ°Ñ Ð²ÑÑÑÐžÐ¹ ÑÑÐŸÐ²ÐµÐœÑ), Ð° ÐœÐµ ÑÐŸÐ»ÑÐºÐŸ Ð²ÑÑÑÐžÐ¹ ÑÑÐŸÐ²ÐµÐœÑ ÑÐ°ÐŒÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°.
+
+Collage.buttonname:Ð¯ÑÐ»ÑÐº ÐŽÐ»Ñ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ° Ð¿ÐŸÐºÐ°Ð·Ð° ÐœÐ° ÑÐºÑÐ°ÐœÐµ Ðž ÐºÐœÐŸÐ¿ÐºÐ° Ð² ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÐŸÐœÐœÐŸÐ¹ Ð»ÐžÐœÐµÐ¹ÐºÐµ.
+
+Collage.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ ÐºÐŸÐ»Ð»Ð°Ð¶Ð°.
+
+
+Collage.geometry:ÐÐ·ÐŒÐµÑÐµÐœÐžÑ ÑÐ°Ð·ÐŒÐµÑÐ° ÐºÐŸÐ»Ð»Ð°Ð¶Ð°. ÐÐ»Ñ ÐºÐŸÐ»Ð»Ð°Ð¶Ð° Ð² 600 Ð¿ÐžÐºÑÐµÐ»ÐµÐ¹ ÑÐžÑÐžÐœÐŸÐ¹ Ðž 400 Ð¿ÐžÐºÑÐµÐ»ÐµÐ¹ Ð²ÑÑÐŸÑÐŸÐ¹, ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐŸÐ¿ÑÐµÐŽÐµÐ»ÑÑÑ Ð³ÐµÐŸÐŒÐµÑÑÐžÑ ÐºÐ°Ðº 600x400
+
+
+Collage.maxDepth:ÐÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ ÐŽÐ»Ñ ÐºÐŸÐ»Ð»Ð°Ð¶Ð° Ð¿ÑÐŸÑÐžÑÐŸÐ²Ð°ÐœÑ ÐŸÑ Ð·ÐµÑÐºÐ°Ð»ÐžÑÐŸÐ²Ð°ÐœÐžÑ Ðº ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÑ Ð±ÑÐ°ÑÐ·ÐµÑÐ°. Ð­ÑÐŸ ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÑÐµÑ ÐŒÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÑÑ Ð³Ð»ÑÐ±ÐžÐœÑ Ð¿ÑÐŸÑÐµÑÑÐ° Ð·ÐµÑÐºÐ°Ð»ÐžÑÐŸÐ²Ð°ÐœÐžÑ.
+
+
+Collage.maxDisplay:ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÑÐžÑÐ»ÐŸ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐ¹ Ð¿ÐŸÐºÐ°Ð·ÑÐ²Ð°ÐµÐŒÑÑ
+ ÐŸÐŽÐœÐŸÐ²ÑÐµÐŒÐµÐœÐœÐŸ Ð² ÐºÐŸÐ»Ð»Ð°Ð¶Ðµ.
+
+
+Collage.imageType: ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ, ÑÑÐŸÐ±Ñ ÑÐ¿ÑÐ°Ð²Ð»ÑÑÑ, Ð²ÑÑÐ°Ð¶Ð°Ñ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ ÐžÐŒÐµÐœÐž ÑÐ°Ð¹Ð»Ð°, ÑÐµÑ
+ ÑÐžÐ¿ÐŸÐ² ÑÐ°Ð¹Ð»ÐŸÐ² ÐºÐŸÑÐŸÑÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ Ð² ÐºÐŸÐ»Ð»Ð°Ð¶Ðµ. Ð¡Ð¿ÐžÑÐŸÐº ÑÐ°ÑÑÐžÑÐµÐœÐžÐ¹ ÐžÐŒÐµÐœ ÑÐ°Ð¹Ð»ÐŸÐ² ÐŸÑÐŽÐµÐ»ÐµÐœ ÑÐžÐŒÐ²ÐŸÐ»ÐŸÐŒ Ð¿ÑÐŸÑÐµÐœÑÐ° (%%).
+
+
+Collage.bgcolor:ÐŠÐ²ÐµÑ ÑÐŸÐœÐ° Ñ
+ÐŸÐ»ÑÑÐ° ÐºÐŸÐ»Ð»Ð°Ð¶Ð°, ÑÐºÐ°Ð·Ð°ÐœÐœÐŸÐ³ÐŸ Ð² ÑÐµÑÑÐœÐ°ÐŽÑÐ°ÑÐžÑÐžÑÐœÐŸÐ¹ ÑÐŸÑÐŒÐµ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ #008000 ÑÐµÐ·ÑÐ»ÑÑÐ°Ñ: ÑÐµÐŒÐœÐŸ-Ð·ÐµÐ»ÐµÐœÑÐ¹ ÑÐŸÐœ).
+
+
+Collage.refreshDelay:ÐÐŸÑÐŒÐ°, Ð² ÐŒÐžÐ»Ð»ÐžÑÐµÐºÑÐœÐŽÐ°Ñ
+, Ñ ÐºÐŸÑÐŸÑÐŸÐ¹ ÐŸÐ±ÐœÐŸÐ²Ð»ÑÐµÑÑÑ ÐºÐŸÐ»Ð»Ð°Ð¶.
+
+
+Collage.isJava2:ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ, ÑÑÐŸÐ±Ñ ÑÐ¿ÑÐ°Ð²Ð»ÑÑÑ, ÐœÐµÐºÐŸÑÐŸÑÑÐŒÐž  ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÐžÐŒÐžÑÑ ÐºÐ»Ð°ÑÑÐ°ÐŒÐž-Ð²ÑÐ¿ÐŸÐ»ÐœÐµÐœÐžÑ Java. ÐÐŸÐ»ÐµÐµ Ð¿ÑÐŸÐŽÐ²ÐžÐœÑÑÐ°Ñ Ð²ÐµÑÑÐžÑ Java (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ: Java 1.2 Ðž ÐŽÐ°Ð»ÐµÐµ) Ð²ÐºÐ»ÑÑÐ°ÐµÑ Ð±ÐŸÐ»ÐµÐµ ÐžÑÐºÑÑÐµÐœÐœÑÑ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐºÑ ÐŽÐ»Ñ ÑÐ¿ÑÐ°Ð²Ð»ÐµÐœÐžÑ Ð¿ÑÐŸÐ·ÑÐ°ÑÐœÐŸÑÑÑÑ Ð² ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑÑ
+, ÑÑÐŸ Ð¿ÐŸÐŒÐŸÐ³Ð°ÐµÑ ÐºÐŸÐœÑÑÐŸÐ»ÐžÑÐŸÐ²Ð°ÑÑ ÑÑÐŸ ÑÐ»ÑÑÐ°ÐµÑÑÑ Ñ ÑÐ»Ð°Ð³ÐŸÐŒ, ÐŸÐŽÐœÐ°ÐºÐŸ Ð²ÑÑÑÐŸÐµÐœÐœÐ°Ñ Ð²ÐµÑÑÐžÑ Java ÐŽÐ»Ñ ÐœÐµÐºÐŸÑÐŸÑÑÑ
+ Ð±ÑÐ°ÑÐ·ÐµÑÐŸÐ² - Ð²ÐµÑÑÐžÑ 1.1. ÐÐ¿Ð¿Ð»ÐµÑ ÑÐ°Ð·ÑÐ°Ð±ÐŸÑÐ°Ðœ ÑÐ°Ðº, ÑÑÐŸÐ±Ñ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ,  ÐŸÐ±ÐœÐ°ÑÑÐ¶ÐžÐ²Ð°Ð»ÑÑ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž, ÐŽÐ»Ñ ÑÐŸÐ¹ Ð²ÐµÑÑÐžÐž Java ÐºÐŸÑÐŸÑÐŸÐ¹ ÐŸÐ±Ð»Ð°ÐŽÐ°ÐµÑ Ð±ÑÐ°ÑÐ·ÐµÑ Ð¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÐµÐ»Ñ, ÑÑÐŸ Ð·Ð°ÑÑÐ°Ð²Ð»ÑÐµÑ Ð²ÑÐ¿ÐŸÐ»ÐœÑÑÑÑÑ Ðž ÐŽÐµÐ¹ÑÑÐ²ÐŸÐ²Ð°ÑÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐµÐœÐœÐŸ.
+
+
+Collage.imageMustNotHave:ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÑÐ¶Ð°ÑÐžÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐ¹, ÐºÐŸÑÐŸÑÑÐµ ÐœÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð¿ÐŸÑÐ²ÐžÑÑÑÑ Ð² ÐºÐŸÐ»Ð»Ð°Ð¶Ðµ, ÑÐžÐ¿Ð° ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐ¹ ÐºÐœÐŸÐ¿ÐŸÑÐµÐº, ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÑÑÐ°Ð²Ð»ÑÑÑ ÐœÐ°Ð²ÐžÐ³Ð°ÑÐžÐŸÐœÐœÑÑ Ð¿Ð°ÐœÐµÐ»Ñ.
+
+
+Collage.caption:ÐÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÑÐµ Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž, Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÑ ÐœÐžÐ¶Ðµ ÐºÐŸÐ»Ð»Ð°Ð¶Ð°. 
+
+
+#
+# Plugin option descriptions
+#
+
+ArcPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ, ÐºÐŸÑÐŸÑÑÐ¹ Ð¿ÐŸÐ²ÑÐŸÑÑÐµÑÑÑ Ð² ÑÐ°Ð¹Ð»Ðµ archives.inf (ÑÐŸ ÐµÑÑÑ ÑÐ°Ð¹Ð», Ð³ÐµÐœÐµÑÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ Ð² Ð°ÑÑ
+ÐžÐ²ÐœÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž, ÐºÐŸÐ³ÐŽÐ°  Ð²ÑÐ¿ÐŸÐ»ÐœÑÐ»ÑÑ ÐžÐŒÐ¿ÐŸÑÑ ), ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°Ñ ÐºÐ°Ð¶ÐŽÑÐ¹ ÐœÐ°Ð¹ÐŽÐµÐœÐœÑÐ¹ ÑÐ°Ð¹Ð».
+
+
+BasPlug.adding:ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµ
+
+
+BasPlug.already_seen:ÑÐ¶Ðµ Ð·Ð°ÐŒÐµÑÐµÐœÐœÑÐ¹
+
+
+BasPlug.bad_general_option:ÐÐ»Ð°Ð³ÐžÐœ %s ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑ ÐœÐµÐºÐŸÑÑÐµÐºÑÐœÑÑ ÐŸÐ±ÑÑÑ ÐŸÐ¿ÑÐžÑ (ÐŸÐ±ÑÐžÐµ ÐŸÐ¿ÑÐžÐž -  ÑÑÐŸ ÑÐµ, ÐºÐŸÑÐŸÑÑÐµ ÐŽÐŸÑÑÑÐ¿ÐœÑ Ð²ÑÐµÐŒ Ð¿Ð»Ð°Ð³ÐžÐœÐ°ÐŒ). ÐÑÐŸÐ²ÐµÑÑÑÐµ Ð²Ð°Ñ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÑÐ¹ ÑÐ°Ð¹Ð» collect.cfg.
+
+
+BasPlug.block_exp:Ð€Ð°Ð¹Ð»Ñ, ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐžÐµ ÑÑÐŸÐŒÑ Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸÐŒÑ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÑ, Ð±ÑÐŽÑÑ Ð·Ð°Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÐœÑ ÐŸÑ ÑÐŸÐ³ÐŸ, ÑÑÐŸÐ±Ñ Ð±ÑÑÑ Ð¿ÐµÑÐµÐŽÐ°ÐœÐœÑÐŒÐž Ð»ÑÐ±ÐŸÐŒÑ ÐŽÐ°Ð»ÑÐœÐµÐ¹ÑÐµÐŒÑ Ð¿Ð»Ð°Ð³ÐžÐœÑ Ð² ÑÐ¿ÐžÑÐºÐµ. Ð­ÑÐŸ ÐœÐµ ÐžÐŒÐµÐµÑ ÐœÐžÐºÐ°ÐºÐŸÐ³ÐŸ ÐŽÑÑÐ³ÐŸÐ³ÐŸ ÑÐµÐ°Ð»ÑÐœÐŸÐ³ÐŸ ÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐžÑ, ÑÐµÐŒ Ð¿ÑÐµÐŽÐŸÑÐ²ÑÐ°ÑÐžÑÑ Ð±ÐŸÐ»ÑÑÐŸÐµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸ Ð¿ÑÐµÐŽÑÐ¿ÑÐµÐ¶ÐŽÐ°ÑÑÐžÑ
+ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐ¹ ÐŸ Ð²Ñ
+ÐŸÐŽÐœÑÑ
+ ÑÐ°Ð¹Ð»Ð°Ñ
+, ÐºÐŸÑÐŸÑÑÐŒ ÐÑ ÐœÐµ ÑÐŽÐµÐ»ÑÐµÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÑ. ÐÐ°Ð¶ÐŽÑÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŒÐŸÐ³ Ð±Ñ ÐžÐŒÐµÑÑ Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ block_exp., ÐºÐ°Ðº ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, HTMLPlug  Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ Ð±Ð»ÐŸÐºÐžÑÑÐµÑ Ð»ÑÐ±ÑÐµ ÑÐ°Ð¹Ð»Ñ Ñ  ÑÐ°ÑÑÐžÑÐµÐœÐžÐµÐŒ .gif, .jpg, .jpeg, .png ÐžÐ»Ðž .css. 
+
+
+BasPlug.associate_ext:ÐÑÐ·ÑÐ²Ð°ÐµÑ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÑ ÑÐ°Ð¹Ð»ÐŸÐ² Ñ ÑÐµÐŒ Ð¶Ðµ ÐºÐŸÑÐœÐµÐ²ÑÐŒ ÐºÐ°ÑÐ°Ð»ÐŸÐ³ÐŸÐŒ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐŒ  AND Ð°ÑÑÐŸÑÐžÐžÑÑÐµÑ Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒÐž ÑÐ¿ÐžÑÐŸÐº ÑÐ°ÑÑÐžÑÐµÐœÐžÑ ÑÐ°Ð¹Ð»ÐŸÐ², Ð¿ÐµÑÐµÑÐžÑÐ»ÐµÐœÐœÑÑ
+ ÑÐµÑÐµÐ· Ð·Ð°Ð¿ÑÑÑÑ, Ð¿ÐµÑÐµÐŽÐ°Ð²Ð°ÐµÐŒÑÐ¹ Ð·ÐŽÐµÑÑ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ Ð°ÑÐ³ÑÐŒÐµÐœÑÐ°.
+
+
+BasPlug.could_not_extract_encoding:ÐÐ ÐÐÐ£ÐÐ ÐÐÐÐÐÐÐ: ÐºÐŸÐŽÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐœÐµ ÑÐŒÐŸÐ³Ð»ÐŸ Ð±ÑÑÑ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐŸ ÐžÐ· %s - Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ Ðº %s
+
+
+BasPlug.could_not_extract_language:ÐÐ ÐÐÐ£ÐÐ ÐÐÐÐÐÐÐ: ÑÐ·ÑÐº ÐœÐµ ÑÐŒÐŸÐ³ Ð±ÑÑÑ ÐžÐ·Ð²Ð»ÐµÑÐµÐœ ÐžÐ· %s - Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ Ðº %s
+
+
+BasPlug.could_not_open_for_reading:ÐœÐµ ÑÐŒÐŸÐ³ ÐŸÑÐºÑÑÑÑ %s ÐŽÐ»Ñ ÑÑÐµÐœÐžÑ
+
+
+BasPlug.no_cover_image:ÐÐµ ÐŸÐ±ÑÐ°ÑÐ°Ð¹ÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÑ ÐœÐ° ÑÐ°Ð¹Ð» prefix.jpg (Ð³ÐŽÐµ prefix - ÑÑÐŸ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÐŒÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð°). Ð­ÑÐŸ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ ÐŸÐ±Ð»ÐŸÐ¶ÐºÐž.
+
+
+BasPlug.default_encoding:ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÑÑÐŸ ÐºÐŸÐŽÐžÑÐŸÐ²Ð°ÐœÐžÐµ, ÐµÑÐ»Ðž -input_encoding ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ ÐœÐ° 'Ð°Ð²ÑÐŸ', Ð° Ð°Ð»Ð³ÐŸÑÐžÑÐŒ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž ÑÐµÐºÑÑÐ° ÐœÐµ Ð² ÑÐŸÑÑÐŸÑÐœÐžÐž ÐžÐ·Ð²Ð»ÐµÑÑ Ð·Ð°ÐºÐŸÐŽÐžÑÐŸÐ²Ð°ÐœÐœÑÐµ ÐžÐ»Ðž ÐžÐ·Ð²Ð»ÐµÐºÐ°ÐµÑ Ð·Ð°ÐºÐŸÐŽÐžÑÐŸÐ²Ð°ÐœÐœÑÐµ, ÐœÐŸ ÐœÐµÐ¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÐµÐŒÑÐµ Greenstone. Ð­ÑÐ° ÐŸÐ¿ÑÐžÑ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÐ°ÑÑ ÑÐµ Ð¶Ðµ ÑÐ°ÐŒÑÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ, ÐºÐ°Ðº Ðž -input_encoding.
+
+
+BasPlug.default_language:ÐÑÐ»Ðž Greenstone ÐœÐµ Ð² ÑÐŸÑÑÐŸÑÐœÐžÐž ÑÐµÑÐžÑÑ, ÐºÐ°ÐºÐžÐŒ ÑÐ²Ð»ÑÐµÑÑÑ ÑÐ·ÑÐº ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°, ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ 'Ð¯Ð·ÑÐº' Ð±ÑÐŽÐµÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ ÐœÐ° ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ. ÐÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ -  ÑÑÐŸ 'en' (ÐÐ¡Ð ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑ 639 ÑÐžÐŒÐ²ÐŸÐ»ÐŸÐ² ÑÐ·ÑÐºÐ°: en = Ð°ÐœÐ³Ð»ÐžÐ¹ÑÐºÐžÐ¹ ÑÐ·ÑÐº). ÐÐ±ÑÐ°ÑÐžÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ, ÑÑÐŸ ÐµÑÐ»Ðž -input_encoding ÐœÐµ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ ÐœÐ° 'Ð°Ð²ÑÐŸ', Ðž -extract_language ÐœÐµ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ, Ð²ÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ Ð±ÑÐŽÑÑ ÐžÐŒÐµÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÑ
+ 'Ð¯Ð·ÑÐºÐ°' ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐœÑÐŒÐž ÐœÐ° ÑÑÐŸ Ð·ÐœÐ°ÑÐµÐœÐžÐµ.
+
+
+BasPlug.desc:ÐÑÐœÐŸÐ²ÐœÐŸÐ¹ ÐºÐ»Ð°ÑÑ ÐŽÐ»Ñ Ð²ÑÐµÐ³ÐŸ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ² ÐžÐŒÐ¿ÐŸÑÑÐ°.
+
+
+BasPlug.done_acronym_extract:ÐÑÐŸÐžÐ·Ð²ÐµÐŽÐµÐœÐŸ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ Ð°ÐºÑÐŸÐœÐžÐŒÐŸÐ².
+
+
+BasPlug.done_acronym_markup:ÐÑÐ¿ÐŸÐ»ÐœÐµÐœÐ° Ð¿ÐŸÐŒÐµÑÐºÐ° Ð°ÐºÑÐŸÐœÐžÐŒÐ°.
+
+
+BasPlug.done_email_extract:ÐÑÐ¿ÐŸÐ»ÐœÐµÐœÐŸ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ Ð°ÐŽÑÐµÑÐŸÐ² ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ.
+
+
+BasPlug.dummy_text:ÐÐ°ÐœÐœÑÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ ÐœÐµ ÐžÐŒÐµÐµÑ ÑÐµÐºÑÑÐ°.
+
+
+BasPlug.empty_file:ÑÐ°Ð¹Ð» ÐœÐµ ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÐœÐžÐºÐ°ÐºÐŸÐ³ÐŸ ÑÐµÐºÑÑÐ°
+
+
+BasPlug.extract_acronyms:ÐÐºÑÐŸÐœÐžÐŒÑ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÑ ÐžÐ· ÑÐµÐºÑÑÐ° Ðž ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ  Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.
+
+
+BasPlug.extract_email:ÐÐ·Ð²Ð»ÐµÑÑ Ð°ÐŽÑÐµÑÐ° ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+.
+
+
+BasPlug.extract_historical_years:ÐÐ·Ð²Ð»ÐµÑÑ ÐžÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸ Ð²ÑÐµÐŒÐµÐœÐœÐŸÐŒ Ð¿ÐµÑÐžÐŸÐŽÐµ ÐžÐ· ÐžÑÑÐŸÑÐžÑÐµÑÐºÐžÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ². ÐÐœÐ° Ñ
+ÑÐ°ÐœÐžÑÑÑ Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐŒ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐŒÐµÐµÑÑÑ ÐžÐœÑÐµÑÑÐµÐ¹Ñ Ð¿ÐŸÐžÑÐºÐ° ÐŽÐ»Ñ ÑÑÐžÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐºÐŸÑÐŸÑÑÐ¹ ÐÑ ÐŒÐŸÐ¶ÐµÑÐµ Ð²ÐºÐ»ÑÑÐžÑÑ Ð² ÐÐ°ÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÐŽÐŸÐ±Ð°Ð²Ð»ÑÑ ÐŸÐ¿ÐµÑÐ°ÑÐŸÑ"format QueryInterface DateSearch" Ðº ÐÐ°ÑÐµÐŒÑ ÐºÐŸÐœÑÐžÐ³ÑÑÐ°ÑÐžÐŸÐœÐœÐŸÐŒÑ ÑÐ°Ð¹Ð»Ñ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+
+BasPlug.extract_language:ÐÐŽÐµÐœÑÐžÑÐžÑÐžÑÑÐ¹ÑÐµ ÑÐ·ÑÐº ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ 'Ð¯Ð·ÑÐº' . ÐÐ±ÑÐ°ÑÐžÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ, ÑÑÐŸ ÑÑÐŸ Ð±ÑÐŽÐµÑ ÑÐŽÐµÐ»Ð°ÐœÐŸ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž, ÐµÑÐ»Ðž -input_encoding ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ ÐœÐ° 'Ð°Ð²ÑÐŸ'.
+
+
+BasPlug.extracting:ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ
+
+
+BasPlug.extracting_acronyms:ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ Ð°ÐºÑÐŸÐœÐžÐŒÐŸÐ²
+
+
+BasPlug.extract_keyphrases:ÐÐ·Ð²Ð»ÐµÑÑ ÐºÐ»ÑÑÐµÐ²ÑÐµ ÑÑÐ°Ð·Ñ  Ñ Ð¿ÐŸÐŒÐŸÑÑÑ Kea (ÐŸÐ¿ÑÐžÐž Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ)
+
+BasPlug.extract_keyphrase_options:ÐÐ¿ÑÐžÐž ÐŽÐ»Ñ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÑ ÐºÐ»ÑÑÐµÐ²ÑÑ
+ ÑÑÐ°Ð· Ñ Ð¿ÐŸÐŒÐŸÑÑÑ Kea. ÐÐ°Ð¿ÑÐžÐŒÐµÑ, mALIWEB - ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ ÐŒÐŸÐŽÐµÐ»Ñ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÑ ALIWEB; n5 - ÐžÐ·Ð²Ð»ÐµÐºÐ°Ð¹ Ð¿ÐŸ 5 ÐºÐ»ÑÑÐµÐ²ÑÑ
+ ÑÐ»ÐŸÐ² ÐžÐ· ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°; eGBK - ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ ÐºÐŸÐŽÐžÑÐŸÐ²ÐºÑ GBK.
+
+BasPlug.extracting_emails:ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ Ð°ÐŽÑÐµÑÐŸÐ² ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ
+
+
+BasPlug.file_has_no_text:ÐÐšÐÐÐÐ: %s ÐœÐµ ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÐœÐžÐºÐ°ÐºÐŸÐ³ÐŸ ÑÐµÐºÑÑÐ°
+
+
+BasPlug.first:ÐÑÐŽÐµÐ»ÐµÐœÐœÑÐ¹ Ð·Ð°Ð¿ÑÑÐŸÐ¹ ÑÐ¿ÐžÑÐŸÐº Ð¿ÐµÑÐ²ÑÑ
+ Ð²ÐµÐ»ÐžÑÐžÐœ ÐŽÐ»Ñ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÑ ÐžÐ· ÑÐµÐºÑÑÐ° Ð² Ð¿ÐŸÐ»Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+. ÐÐŸÐ»Ðµ ÐœÐ°Ð·Ð²Ð°ÐœÐŸ 'FirstNNN'.
+
+
+BasPlug.input_encoding:ÐÐŸÐŽÐžÑÐŸÐ²Ð°ÐœÐžÐµ ÐžÑÑ
+ÐŸÐŽÐœÑÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ². ÐÐŸÐºÑÐŒÐµÐœÑÑ Ð±ÑÐŽÑÑ ÐºÐŸÐœÐ²ÐµÑÑÐžÑÐŸÐ²Ð°ÐœÑ ÐžÐ· ÑÑÐžÑ
+ ÑÐžÑÑÐŸÐ²Ð°ÐœÐžÐ¹ Ðž Ñ
+ÑÐ°ÐœÐžÑÑÑÑ Ð²ÐœÑÑÑÐž ÑÐžÑÑÐµÐŒÑ Ð² Ð²ÐžÐŽÐµ utf8.
+
+BasPlug.input_encoding.ascii:ÐÑÐŸÑÑÐŸÐ¹ 7-Ð±ÐžÑÐœÑÐ¹ ascii. ÐÐœ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐœÐµÐŒÐœÐŸÐ³ÐŸ Ð±ÑÑÑÑÐµÐµ, ÑÐµÐŒ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµ iso_8859_1. ÐÑÑÐµÑÐµÐ³Ð°Ð¹ÑÐµÑÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÑ ÑÑÐŸÐ³ÐŸ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐŒÐŸÐ³ÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÑÑ ÑÐžÐŒÐ²ÐŸÐ»Ñ Ð²ÐœÐµ Ð¿ÑÐŸÑÑÑÑ
+ 7-Ð±ÐžÑÐœÑÑ
+ ÐœÐ°Ð±ÐŸÑÐŸÐ² ascii (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐœÐµÐŒÐµÑÐºÐžÐµ ÐžÐ»Ðž ÑÑÐ°ÐœÑÑÐ·ÑÐºÐžÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ Ð·ÐœÐ°ÐºÐž ÑÐŽÐ°ÑÐµÐœÐžÑ), ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ Ð²ÐŒÐµÑÑÐŸ ÑÑÐŸÐ³ÐŸ iso_8859_1.
+
+BasPlug.input_encoding.auto:ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ Ð°Ð»Ð³ÐŸÑÐžÑÐŒ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž ÑÐµÐºÑÑÐ° ÐŽÐ»Ñ Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐŸÐ¹ ÐžÐŽÐµÐœÑÐžÑÐžÐºÐ°ÑÐžÐž ÐºÐŸÐŽÐžÑÐŸÐ²Ð°ÐœÐžÑ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐžÑÑ
+ÐŸÐŽÐœÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°. Ð­ÑÐŸ Ð±ÑÐŽÐµÑ ÐŒÐµÐŽÐ»ÐµÐœÐœÐµÐµ, ÑÐµÐŒ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐžÑÑÐŸÐ²Ð°ÐœÐžÑ Ð² ÑÐ²ÐœÐŸÐŒ Ð²ÐžÐŽÐµ, ÐœÐŸ Ð±ÑÐŽÐµÑ ÑÐ°Ð±ÐŸÑÐ°ÑÑ ÑÐ°ÐŒ, Ð³ÐŽÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ Ð±ÐŸÐ»ÑÑÐµ ÑÐµÐŒ ÐŸÐŽÐžÐœ Ð²ÐžÐŽ ÑÐžÑÑÐŸÐ²Ð°ÐœÐžÑ  Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÑÐŸÐ¹ Ð¶Ðµ ÑÐ°ÐŒÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž.
+
+BasPlug.input_encoding.unicode:Ð¢ÐŸÐ»ÑÐºÐŸ ÑÐœÐžÐºÐŸÐŽ.
+
+BasPlug.input_encoding.utf8:ÐÐ»Ðž utf8, ÐžÐ»Ðž ÑÐœÐžÐºÐŸÐŽ - Ð°Ð²ÑÐŸÐŒÐ°ÑÐžÑÐµÑÐºÐž ÐŸÐ±ÐœÐ°ÑÑÐ¶ÐµÐœÐœÑÐµ.
+
+
+BasPlug.keyphrases:ÐÐ»ÑÑÐµÐ²ÑÐµ ÑÑÐ°Ð·Ñ
+
+
+BasPlug.marking_up_acronyms:Ð¿ÐŸÐŒÐµÑÐºÐ° Ð°ÐºÑÐŸÐœÐžÐŒÐŸÐ²
+
+
+BasPlug.markup_acronyms:ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð°ÐºÑÐŸÐœÐžÐŒÐ° Ð² ÑÐµÐºÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°.
+
+
+BasPlug.maximum_century:ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐœÐ°Ð·Ð²Ð°ÐœÐœÐŸÐ³ÐŸ ÑÑÐŸÐ»ÐµÑÐžÑ, ÐºÐŸÑÐŸÑÐŸÐµ Ð±ÑÐŽÐµÑ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐŸ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÐžÑÑÐŸÑÐžÑÐµÑÐºÐžÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, 14 ÐžÐ·Ð²Ð»ÐµÑÐµÑ Ð²ÑÐµ ÑÑÑÐ»ÐºÐž, ÐŸÑÐœÐŸÑÑÑÐžÐµÑÑ Ðº 14-ÐŸÐŒÑ ÑÑÐŸÐ»ÐµÑÐžÑ).
+
+
+BasPlug.maximum_year:ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐ°Ñ ÐžÑÑÐŸÑÐžÑÐµÑÐºÐ°Ñ ÐŽÐ°ÑÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐœÐ°Ñ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ (ÐŽÐ°ÑÐ° ÑÑÑ, ÑÐžÐ¿Ð° 1950).
+
+
+BasPlug.must_be_implemented:BasPlug::ÑÐžÑÐ°ÐµÐŒÐ°Ñ ÑÑÐœÐºÑÐžÑ, ÐºÐŸÑÐŸÑÐ°Ñ ÐŽÐŸÐ»Ð¶ÐœÐ° Ð±ÑÑÑ ÑÐµÐ°Ð»ÐžÐ·ÐŸÐ²Ð°ÐœÐ° Ð² Ð¿ÐŸÐŽÐºÐ»Ð°ÑÑÐµ ÐŽÐ»Ñ ÑÐµÐºÑÑÑÐžÐ²ÐœÑÑ
+ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ².
+
+
+BasPlug.no_bibliography:ÐÐµ Ð¿ÑÐŸÐ±ÑÐ¹ÑÐµ Ð±Ð»ÐŸÐºÐžÑÐŸÐ²Ð°ÑÑ Ð±ÐžÐ±Ð»ÐžÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÐµ ÐŽÐ°ÑÑ Ð¿ÑÐž ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÐž ÐžÑÑÐŸÑÐžÑÐµÑÐºÐžÑ
+ ÐŽÐ°Ñ.
+
+
+BasPlug.process_exp:ÐÐ±ÑÑÐœÐŸÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ Perl ÐŽÐ»Ñ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÑ  ÐžÐŒÐµÐœÐ°ÐŒ ÑÐ°Ð¹Ð»Ð°. Ð¡ÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐžÐµ ÐžÐŒÐµÐœÐ°ÐŒ ÑÐ°Ð¹Ð»Ð° Ð±ÑÐŽÐµÑ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÐœÐŸ ÑÑÐžÐŒ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐŒ. ÐÐ°Ð¿ÑÐžÐŒÐµÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµ '(?i).html?\$' ÑÐŸÑÐ²ÐµÑÑÑÐ²ÑÐµÑ Ð²ÑÐµÐŒ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒ, Ð·Ð°ÐºÐ°ÐœÑÐžÐ²Ð°ÑÑÐžÐŒÑÑ ÐœÐ° .htm ÐžÐ»Ðž .html (Ð±ÐµÐ· ÑÐ°Ð·Ð»ÐžÑÐµÐœÐžÑ Ð·Ð°Ð³Ð»Ð°Ð²ÐœÑÑ
+ Ðž ÑÑÑÐŸÑÐœÑÑ
+ Ð±ÑÐºÐ²).
+
+
+BasPlug.read_denied:Ð Ð°Ð·ÑÐµÑÐµÐœÐžÐµ ÑÑÐµÐœÐžÑ,  ÐŸÑÐºÐ»ÐŸÐœÐµÐœÐœÐŸÐµ ÐŽÐ»Ñ %s
+
+
+BasPlug.smart_block:ÐÐ»ÐŸÐºÐžÑÐŸÐ²ÐºÐ° ÑÐ°Ð¹Ð»ÐŸÐ² ÑÐ»ÑÑÑÐµÐœÐœÑÐŒ ÐŒÐµÑÐŸÐŽÐŸÐŒ, Ð²ÐŒÐµÑÑÐŸ Ð¿ÑÐŸÑÑÐŸÐ³ÐŸ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ° ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ ÑÐ°Ð¹Ð»ÐŸÐ².
+
+BasPlug.stems:ÑÑÐµÐ±Ð»Ðž
+
+
+BasPlug.unsupported_encoding:ÐÐ ÐÐÐ£ÐÐ ÐÐÐÐÐÐÐ: %s Ð¿ÐŸÑÐ²Ð»ÑÐµÑÑÑ, ÑÑÐŸÐ±Ñ Ð±ÑÑÑ Ð·Ð°ÐºÐŸÐŽÐžÑÐŸÐ²Ð°ÐœÐœÑÐŒ Ð² ÐœÐµÐ¿ÐŸÐŽÐŽÐµÑÐ¶Ð°ÐœÐœÐŸÐŒ ÑÐžÑÑÐŸÐ²Ð°ÐœÐžÐž (%s) - ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ %s
+
+
+BasPlug.wrong_encoding:ÐÐ ÐÐÐ£ÐÐ ÐÐÐÐÐÐÐ: %s ÑÐžÑÐ°Ð»ÐŸÑÑ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ %s ÑÐžÑÑÐŸÐ²Ð°ÐœÐžÐµ, ÐœÐŸ  Ð¿ÐŸÑÐ²Ð»ÑÐ»ÐŸÑÑ ÐºÐŸÐŽÐžÑÐŸÐ²Ð°ÐœÐœÑÐŒ ÐºÐ°Ðº %s.
+
+
+BibTexPlug.desc:BibTexPlug ÑÐžÑÐ°ÐµÑ Ð±ÐžÐ±Ð»ÐžÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÐµ ÑÐ°Ð¹Ð»Ñ Ð² ÑÐŸÑÐŒÐ°ÑÐµ BibTex. BibTexPlug ÑÐŸÐ·ÐŽÐ°ÐµÑ ÐŸÐ±ÑÐ°Ð· ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ¹ ÑÑÑÐ»ÐºÐž Ð² ÑÐ°Ð¹Ð»Ðµ. Ð­ÑÐŸ - Ð¿ÐŸÐŽÐºÐ»Ð°ÑÑ SplitPlug, ÑÐ°Ðº ÑÑÐŸ ÐµÑÐ»Ðž ÐžÐŒÐµÑÑÑÑ ÐŒÐœÐŸÐ¶ÐµÑÑÐ²ÐµÐœÐœÑÐµ Ð·Ð°Ð¿ÐžÑÐž, ÑÐŸ Ð²ÑÐµ ÐŸÐœÐž ÑÐžÑÐ°ÑÑÑÑ.
+
+
+BookPlug.desc:Ð¡ÐŸÐ·ÐŽÐ°ÐµÑÑÑ ÐŒÐœÐŸÐ³ÐŸÑÑÐŸÐ²ÐœÐµÐ²ÑÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ ÐžÐ· ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐµÐ³ÐŸ ÑÑÐ³Ðž ÑÑÐŸÐ²ÐœÑ <<TOC>>. ÐÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ  ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÑÐ°Ð·ÐŽÐµÐ»Ð° Ð²Ð·ÑÑÑ ÐžÐ· Ð»ÑÐ±ÐŸÐ³ÐŸ ÐŽÑÑÐ³ÐŸÐ³ÐŸ ÑÑÐ³Ð° Ð² ÑÐŸÐ¹ Ð¶Ðµ ÑÐ°ÐŒÐŸÐ¹ ÑÑÑÐŸÐºÐµ, ÐºÐ°Ðº Ðž <<TOC>>. ÐÐ°Ð¿ÑÐžÐŒÐµÑ, <<Title>>xxxx<</Title>>  ÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÐµÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ. ÐÑÐµ ÐŸÑÑÐ°Ð»ÑÐœÐŸÐµ ÐŒÐµÐ¶ÐŽÑ ÑÑÐ³Ð°ÐŒÐž ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÑÑÑ ÐºÐ°Ðº Ð¿ÑÐŸÑÑÐŸÐ¹ html (ÑÐŸ ÐµÑÑÑ ÐœÐžÐºÐ°ÐºÐŸÐ¹ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐž ÑÐ²ÑÐ·ÐµÐ¹ html ÐžÐ»Ðž Ð»ÑÐ±ÑÑ
+ ÐŽÑÑÐ³ÐžÑ
+ Ð²ÐžÐŽÐŸÐ² HTMLPlug  ÐœÐµ Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐŽÐžÑÑÑ). ÐÐ¶ÐžÐŽÐ°ÐµÑÑÑ, ÑÑÐŸ Ð²Ñ
+ÐŸÐŽÐœÑÐµ ÑÐ°Ð¹Ð»Ñ ÐžÐŒÐµÑÑ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ .hb Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ. Ð­ÑÐŸ ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐžÐ·ÐŒÐµÐœÐµÐœÐŸ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÐµÐŒ ÐŸÐ¿ÑÐžÐž -process_exp Ðº  ÑÐ°Ð¹Ð»Ñ Ñ ÑÐµÐŒ Ð¶Ðµ ÑÐ°ÐŒÑÐŒ ÐžÐŒÐµÐœÐµÐŒ, ÑÑÐŸ Ðž hb ÑÐ°Ð¹Ð», ÐœÐŸ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ .jpg Ð²Ð·ÑÑÐŸ ÐŽÐ»Ñ ÐŸÐ±Ð»ÐŸÐ¶ÐºÐž ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ (jpg ÑÐ°Ð¹Ð»Ñ Ð±Ð»ÐŸÐºÐžÑÑÑÑÑÑ ÑÑÐžÐŒ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐŒ). BookPlug ÑÐ²Ð»ÑÐµÑÑÑ ÑÐ¿ÑÐŸÑÐµÐœÐžÐµÐŒ (Ðž ÑÐ°ÑÑÐžÑÐµÐœÐžÐµÐŒ) HBPlug, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐŸÐ³ÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒÐž ÐÑÐŒÐ°ÐœÐžÑÐ°ÑÐœÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž. BookPlug ÑÐ²Ð»ÑÐµÑÑÑ Ð±ÐŸÐ»ÐµÐµ Ð±ÑÑÑÑÑÐŒ, Ð¿ÐŸÑÐºÐŸÐ»ÑÐºÑ Ð¿ÑÐµÐŽÐ¿ÐŸÐ»Ð°Ð³Ð°ÐµÑÑÑ, ÑÑÐŸ Ð²Ñ
+ÐŸÐŽÐœÑÐµ ÑÐ°Ð¹Ð»Ñ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ Ð±ÐŸÐ»ÐµÐµ ÑÐžÑÑÑÐŒÐž (Ð²Ñ
+ÐŸÐŽ Ðº HDL ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒ ÑÐŸÐŽÐµÑÐ¶ÐžÑ ÐŒÐœÐŸÐ¶ÐµÑÑÐ²ÐŸ ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÑÑ
+ ÑÑÐ³ÐŸÐ² html Ð²ÐŸÐºÑÑÐ³  ÑÑÐ³ÐŸÐ² <<TOC>>, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÑÑÐ³Ðž <<I>>, ÑÑÐŸÐ±Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐžÑÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ, Ðž Ð¿ÑÐŸÑÑÐŸ Ð±ÐµÑÑÑ Ð²ÐµÑÑ ÑÐµÐºÑÑ ÐŒÐµÐ¶ÐŽÑ ÑÑÐ³Ð°ÐŒÐž <<TOC>>, Ð° ÐœÐ°ÑÐ°Ð»ÐŸÐŒ ÑÐµÐºÑÑÐ° ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐÐ°Ð·Ð²Ð°ÐœÐžÑ). ÐÑÐ»Ðž ÐÑ Ð¿ÐŸÐŒÐµÑÐ°ÐµÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ, ÐºÐŸÑÐŸÑÑÐµ Ð±ÑÐŽÑÑ Ð¿ÐŸÐºÐ°Ð·Ð°ÐœÑ ÑÐµÐŒ Ð¶Ðµ ÑÐ°ÐŒÑÐŒ ÑÐ¿ÐŸÑÐŸÐ±ÐŸÐŒ, ÑÑÐŸ Ðž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ HDL, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ ÑÑÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœ Ð²ÐŒÐµÑÑÐŸ HBPlug.
+
+
+ConvertToPlug.convert_to:ÐÐ»Ð°Ð³ÐžÐœ ÐºÐŸÐœÐ²ÐµÑÑÐžÑÑÐµÑ Ðº Ð¢ÐÐÐ¡Ð¢Ð£ ÐžÐ»Ðž HTML.
+
+ConvertToPlug.convert_to.html:Ð€ÐŸÑÐŒÐ°Ñ HTML.
+
+ConvertToPlug.convert_to.text:Ð€ÐŸÑÐŒÐ°Ñ Ð¿ÑÐŸÑÑÐŸÐ³ÐŸ ÑÐµÐºÑÑÐ°.
+
+
+ConvertToPlug.desc:The plugin is inherited by such plugins as WordPlug and PDFPlug. It facilitates the conversion of these document types to either HTML or TEXT by setting up variable that instruct ConvertToBasPlug how to work. It works by dynamically inheriting HTMLPlug or TEXTPlug based on the plugin argument 'convert_to'.  If the argument is not present, the default is to inherit  .
+
+
+ConvertToPlug.use_strings:ÐÑÐ»Ðž ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐŸ, ÑÐŸ Ð¿ÑÐŸÑÑÐ°Ñ  ÑÑÑÐŸÐºÐŸÐ²Ð°Ñ ÑÑÐœÐºÑÐžÑ Ð±ÑÐŽÐµÑ Ð²ÑÐ·ÑÐ²Ð°ÑÑÑÑ ÐŽÐ»Ñ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÑ ÑÐµÐºÑÑÐ°, ÐµÑÐ»Ðž ÑÑÐžÐ»ÐžÑÐ° ÐºÐŸÐœÐ²ÐµÑÑÐžÐž ÐœÐµ ÑÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÑ.
+
+
+ConvertToRogPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ, ÐºÐŸÑÐŸÑÑÐ¹ ÐœÐ°ÑÐ»ÐµÐŽÑÐµÑ RogPlug.
+
+
+DBPlug.desc:ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑ Ð·Ð°Ð¿ÐžÑÐž ÐžÐ· Ð±Ð°Ð·Ñ ÐŽÐ°ÐœÐœÑÑ
+  ÐºÐ°Ðº ÐŽÐŸÐºÑÐŒÐµÐœÑÑ.
+
+
+DBPlug.title_sub:ÐÑÑÐ°Ð¶ÐµÐœÐžÐµ Ð·Ð°ÐŒÐµÐœÑ, ÑÑÐŸÐ±Ñ ÐžÐ·ÐŒÐµÐœÐžÑÑ ÑÑÑÐŸÐºÑ, ÑÐŸÑ
+ÑÐ°ÐœÐµÐœÐœÑÑ ÐºÐ°Ðº ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ. ÐÑÐžÐŒÐµÐœÑÐµÑÑÑ, ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐŒ PSPlug, ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ "Ð¡ÑÑÐ°ÐœÐžÑÑ 1" Ðž Ñ.ÐŽ ÐžÐ· ÑÐµÐºÑÑÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐŸÐ³ÐŸ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ.
+
+
+EMAILPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ Email ÑÐžÑÐ°ÐµÑ ÑÐ°Ð¹Ð»Ñ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ. ÐÐœÐž ÐžÐŒÐµÐœÑÑÑÑÑ Ð¿ÑÐŸÑÑÑÐŒÐž ÐœÐŸÐŒÐµÑÐ°ÐŒÐž (Ñ.Ðµ.Ð² ÑÐŸÐŒ Ð¿ÐŸÑÑÐŽÐºÐµ,ÐºÐ°Ðº ÐŸÐœÐž Ð¿ÐŸÑÐ²Ð»ÑÑÑÑÑ Ð² Ð¿Ð°Ð¿ÐºÐ°Ñ
+ Ð¿ÐŸÑÑÐŸÐ²ÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž) ÐžÐ»Ðž Ñ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµÐŒ .mbx (ÑÐŸÑÐŒÐ°Ñ ÑÐ°Ð¹Ð»Ð° ÐŽÐ»Ñ Ð¿ÐžÑÐµÐŒ mbox).\nÐ¢ÐµÐºÑÑ ÐŽÐŸÐŸÐºÑÐŒÐµÐœÑÐ°: Ð¢ÐµÐºÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÑÐŸÑÑÐŸÐžÑ ÐžÐ· Ð²ÑÐµÐ³ÐŸ ÑÐµÐºÑÑÐ° Ð¿ÐŸÑÐ»Ðµ Ð¿ÐµÑÐ²ÐŸÐ¹ Ð¿ÑÑÑÐŸÐ¹ ÑÑÑÐŸÐºÐž Ð² ÐŽÐŸÐºÑÐŒÐµÐœÑÐµ.\nÐÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ (ÐœÐµ Dublin Core!):\n\t\$Headers ÐÑÐµ ÑÑÐŸ ÑÐŸÐŽÐµÑÐ¶ÐžÑ Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐŸÐº (ÐœÐµÐŸÐ±ÑÐ·Ð°ÑÐµÐ»ÑÐœÐŸ, Ð¿ÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ ÐœÐµ ÑÐŸÑ
+ÑÐ°ÐœÑÐµÑÑÑ)\n\t\$Subject ÐÑÐµÐŽÐŒÐµÑ: Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐŸÐº\n\t\$To  ÐÐŸÐŒÑ:Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐŸÐº\n\t\$From ÐºÐŸÐ³ÐŸ   ÐÑ ÐºÐŸÐ³ÐŸ: Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐŸÐº\n\t\$FromName ÐŸÑ ÐºÐŸÐ³ÐŸ  ÐÐŒÑ ÐŸÑÐ¿ÑÐ°Ð²ÐžÑÐµÐ»Ñ(ÐºÐŸÐ³ÐŽÐŽÐ° ÐŸÐœÐŸ ÐžÐŒÐµÐµÑÑÑ Ð² ÐœÐ°Ð»ÐžÑÐžÐž)\n\t\$FromAddr ÐŸÑ ÐºÐŸÐ³ÐŸ  Ð°ÐŽÑÐµÑ ÑÐ»ÐµÐºÑÑÐŸÐœÐœÐŸÐ¹ Ð¿ÐŸÑÑÑ ÐŸÑÐ¿ÑÐ°Ð²ÐžÑÐµÐ»Ñ\n\t\$DateText ÐŽÐ°ÑÑ  ÐÐ°ÑÐ°: Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐŸÐº\n\t\$Date   ÐÐ°ÑÐ°: Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐŸÐº Ð² ÑÐŸÑÐŒÐ°ÑÐµ ÑÐžÑÑÐŸÐ²ÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž Greenstone (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ: 19990924)
+
+
+EMAILPlug.no_attachments:ÐÐµ ÑÐŸÑ
+ÑÐ°ÐœÑÑÑ Ð¿ÑÐžÐ»ÐŸÐ¶ÐµÐœÐžÑ ÑÐŸÐŸÐ±ÑÐµÐœÐžÑ.
+
+
+EMAILPlug.headers:Ð¡ÐŸÑ
+ÑÐ°ÐœÑÑÑ Ð¿ÐŸÑÑÐŸÐ²ÑÐµ Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž ÐºÐ°Ðº ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ "Headers"
+
+
+EMAILPlug.split_exp:ÐÐ±ÑÑÐœÐŸÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ  perl ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÑÐ°ÑÑÐµÐ¿Ð»ÐµÐœÐžÑ ÑÐ°Ð¹Ð»ÐŸÐ², ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐžÑ
+ ÐžÐŒÐµÐ»ÐŸ ÐŸÐ±ÑÐºÐœÐŸÐ²ÐµÐœÐžÐµ ÑÐ°ÑÐºÐ°Ð»ÑÐ²Ð°ÑÑ ÑÐ°Ð¹Ð»Ñ, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐžÐµ ÐŒÐœÐŸÐ³ÐŸ ÑÐŸÐŸÐ±ÑÐµÐœÐžÐ¹ Ð² ÐžÐœÐŽÐžÐ²ÐžÐŽÑÐ°Ð»ÑÐœÑÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°Ñ
+.
+
+
+ExcelPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐžÐŒÐ¿ÐŸÑÑÐ° ÑÐ°Ð¹Ð»Ð° Microsoft Excel.
+
+
+FOXPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐž ÑÐ°Ð¹Ð»Ð° Foxbase dbt. Ð­ÑÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŸÐ±ÐµÑÐ¿ÐµÑÐžÐ²Ð°ÐµÑ ÐŸÑÐœÐŸÐ²ÐœÑÐµ ÑÑÐœÐºÑÐžÐŸÐœÐ°Ð»ÑÐœÑÐµ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÐž ÑÑÐµÐœÐžÑ dbt Ðž dbf ÑÐ°Ð¹Ð»ÐŸÐ² Ðž ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐž ÐºÐ°Ð¶ÐŽÐŸÐ¹ Ð·Ð°Ð¿ÐžÑÐž. Ð­ÑÐŸÑ ÐŸÐ±ÑÐžÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŽÐŸÐ»Ð¶ÐµÐœ Ð±ÑÑÑ Ð·Ð°ÐŒÐµÑÐµÐœ ÐŽÐ»Ñ ÑÐ¿ÐµÑÐžÑÐžÑÐµÑÐºÐŸÐ¹ Ð±Ð°Ð·Ñ ÐŽÐ°ÐœÐœÑÑ
+, ÑÑÐŸÐ±Ñ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÑÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐžÐµ Ð¿ÐŸÐ»Ñ Ð² ÑÐ°Ð¹Ð»Ðµ.
+
+
+GAPlug.desc:ÐÐ±ÑÐ°Ð±ÐŸÑÐºÐ° XML ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Ð°ÑÑ
+ÐžÐ²Ð° Greenstone. ÐÐ±ÑÐ°ÑÐžÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ, ÑÑÐŸ ÑÑÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœ ÐœÐµ ÐŽÐµÐ»Ð°ÐµÑ ÐœÐžÐºÐ°ÐºÐŸÐ¹ Ð¿ÑÐŸÐ²ÐµÑÐºÐž ÑÐžÐœÑÐ°ÐºÑÐžÑÐ° (Ñ
+ÐŸÑÑ  Ð°ÐœÐ°Ð»ÐžÐ·ÐžÑÑÑÑÐžÐ¹ ÐŒÐŸÐŽÑÐ»Ñ XML::   Ð¿ÑÐŸÐ²ÐµÑÑÐµÑ Ð¿ÑÐ°Ð²ÐžÐ»ÑÐœÐŸÑÑÑ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ). ÐÑÐµÐŽÐ¿ÐŸÐ»Ð°Ð³Ð°ÐµÑÑÑ, ÑÑÐŸ ÑÐ°Ð¹Ð»Ñ Ð°ÑÑ
+ÐžÐ²Ð° Greenstone ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑ ÐžÑ
+ DTD .
+
+
+GISBasPlug.extract_placenames:Ð Ð°ÑÐ¿ÐŸÐ·ÐœÐŸÐ²Ð°ÑÑ Ð³ÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÐµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ Ð² ÑÐµÐºÑÑÐµ Ðž Ð²ÐºÐ»ÑÑÐžÑÑ ÐžÑ
+ Ð² ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ. Ð¢ÑÐµÐ±ÑÐµÑ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ ÐÐÐ¡ Ð² ÐÑÐžÐœÑÑÐŸÑÐœ.
+
+GISBasPlug.gazetteer:ÐÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÐ¹ ÑÐ¿ÑÐ°Ð²ÐŸÑÐœÐžÐº ÐŽÐ»Ñ ÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°ÐœÐžÑ Ð³ÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÑ
+ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ Ð² ÑÐµÐºÑÑÐµ Ðž ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐžÑ ÐžÑ
+ Ð² ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+. Ð¢ÑÐµÐ±ÑÐµÑ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ ÐÐÐ¡ Ð² ÐÑÐžÐœÑÑÐŸÑÐœ.
+
+GISBasPlug.place_list:ÐÑÐž ÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°ÐœÐžÐž Ð³ÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÑ
+ ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹, Ð¿Ð»Ð°Ð³ÐžÐœ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÐžÑ
+ ÑÐ¿ÐžÑÐŸÐº Ð² ÐœÐ°ÑÐ°Ð»ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°. Ð¢ÑÐµÐ±ÑÐµÑ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµ ÐÐÐ¡ Ð² ÐÑÐžÐœÑÑÐŸÑÐœ.
+
+GMLPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ, ÐºÐŸÑÐŸÑÑÐ¹ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÑ ÐŽÐŸÐºÑÐŒÐµÐœÑ ÑÐŸÑÐŒÐ°ÑÐ° GML, Ð¿ÑÐµÐŽÐ¿ÐŸÐ»Ð°Ð³Ð°Ñ, ÑÑÐŸ Ð²ÑÐµ ÑÑÐ³Ðž gml Ð² ÑÑÑÐŸÑÐœÑÑ
+ Ð±ÑÐºÐ²Ð°Ñ
+.
+
+
+HBPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ, ÐºÐŸÑÐŸÑÑÐ¹ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÑ HTML ÐºÐœÐžÐ¶ÐœÑÑ ÐŽÐžÑÐµÐºÑÐŸÑÐžÑ. Ð­ÑÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒÐž ÐÑÐŒÐ°ÐœÐžÑÐ°ÑÐœÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž Ðž ÐœÐµ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÑ ÐŽÑÑÐ³ÐžÐµ Ð²Ñ
+ÐŸÐŽÐœÑÐµ ÑÐžÑÑÐŸÐ²Ð°ÐœÐžÑ, ÐºÑÐŸÐŒÐµ ascii ÐžÐ»Ðž Ñ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµÐŒ ascii. Ð­ÑÐ° Ð¿ÑÐŸÐ³ÑÐ°ÐŒÐŒÐ° ÑÐ²Ð»ÑÐµÑÑÑ Ð»ÑÑÑÐµÐ¹ ÐžÐ· Ñ
+ÑÐŽÑÐžÑ
+ Ðž ÐŒÐŸÐ³Ð»Ð° Ð±Ñ Ð±ÐµÐ· ÑÐŸÐŒÐœÐµÐœÐžÑ ÐŽÐŸÑÐ°Ð±ÐŸÑÐ°ÐœÐ° ÑÐ°Ðº, ÑÑÐŸÐ±Ñ Ð·Ð°Ð³ÑÑÐ¶Ð°ÑÑÑÑ Ð±ÑÑÑÑÐµÐµ. ÐÑÑÐ°Ð²Ð»ÑÑ ÐµÐµ Ð² ÑÑÐŸÐŒ ÑÐŸÑÑÐŸÑÐœÐžÐž, Ñ ÐœÐ°ÐŽÐµÑÑÑ Ð¿ÐŸÐŸÑÑÐžÑÑ Ð»ÑÐŽÐµÐ¹ ÐŽÐµÐ»Ð°ÑÑ ÐžÑ
+ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ Ð²ÐŒÐµÑÑÐŸ ÑÑÐŸÐ³ÐŸ Ð¿Ð»Ð°Ð³ÐžÐœ HBSPlug. ;-)\n\n ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ HBSPlug Ð¿ÑÐž ÑÐŸÐ·ÐŽÐ°ÐœÐžÐž ÐœÐŸÐ²ÐŸÐ¹ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž Ðž Ð¿ÐŸÐŒÐµÑÐµÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ², Ð¿ÐŸÐŽÐŸÐ±ÐœÐŸ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒ ÐÑÐŒÐ°ÐœÐžÑÐ°ÑÐœÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž. HBSPlug Ð¿ÑÐžÐœÐžÐŒÐ°ÐµÑ Ð²ÑÐµ Ð²Ñ
+ÐŸÐŽÐœÑÐµ ÐºÐŸÐŽÐžÑÐŸÐ²Ð°ÐœÐžÑ, ÐœÐŸ ÐŸÐ¶ÐžÐŽÐ°ÐµÑ, ÑÑÐŸ Ð¿ÐŸÐŒÐµÑÐµÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ Ð±ÑÐŽÑÑ Ð±ÐŸÐ»ÐµÐµ ÑÐžÑÑÑÐŒÐž, ÑÐµÐŒ ÑÐµ, ÑÑÐŸ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑÑÑÑ ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑÐŒÐž ÐÑÐŒÐ°ÐœÐžÑÐ°ÑÐœÐŸÐ¹ Ð±ÐžÐ±Ð»ÐžÐŸÑÐµÐºÐž.
+
+
+HTMLPlug.assoc_files:ÐÐ±ÑÑÐœÐŸÐµ Perl Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ ÑÐ°Ð¹Ð»Ð° ÑÐ°ÑÑÐžÑÐµÐœÐžÐ¹ ÐŽÐ»Ñ ÑÐ²ÑÐ·Ðž Ñ  html -ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒÐž.
+
+
+HTMLPlug.desc:Ð­ÑÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÑ ÑÐ°Ð¹Ð»Ñ HTML
+
+
+HTMLPlug.description_tags:Ð Ð°Ð·Ð±ÐžÐµÐœÐžÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÐœÐ° Ð¿ÐŸÐŽÑÐ°Ð·ÐŽÐµÐ»Ñ, Ð³ÐŽÐµ ÐžÐŒÐµÑÑÑÑ ÑÑÐ³Ðž <Ð Ð°Ð·ÐŽÐµÐ»>. ÐÐ±ÑÐ°ÑÐžÑÐµ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ, ÑÑÐŸ Ð¿ÑÐž ÑÑÑÐ°ÐœÐŸÐ²ÐºÐµ ÑÑÐŸÐ¹ ÐŸÐ¿ÑÐžÐž, ÐÑ ÐœÐµÑÐ²ÐœÐŸ ÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÐµÑÐµ -no_metadata (ÐœÐžÐºÐ°ÐºÐžÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+), Ð¿ÐŸÑÐºÐŸÐ»ÑÐºÑ Ð²ÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ Ð²ÐºÐ»ÑÑÐµÐœÑ Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÑÑÐ³ÐŸÐ² <Ð Ð°Ð·ÐŽÐµÐ»>. ÐÑÐŸÐŒÐµ ÑÐŸÐ³ÐŸ '-keep_head' ÐœÐµ Ð±ÑÐŽÐµÑ ÐžÐŒÐµÑÑ ÐœÐžÐºÐ°ÐºÐŸÐ³ÐŸ ÐŽÐµÐ¹ÑÑÐ²ÐžÑ, ÐºÐŸÐ³ÐŽÐ° ÑÑÐ° ÐŸÐ¿ÑÐžÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐ°.
+
+
+HTMLPlug.file_is_url:Ð£ÑÑÐ°ÐœÐŸÐ²ÐžÑÑ, ÐµÑÐ»Ðž Ð²Ñ
+ÐŸÐŽÐœÑÐµ ÐžÐŒÐµÐœÐ° ÑÐ°Ð¹Ð»ÐŸÐ² ÑÐŸÐŽÐµÑÐ¶Ð°Ñ URL Ð¿ÐµÑÐ²ÐŸÐœÐ°ÑÐ°Ð»ÑÐœÑÑ
+ ÐžÑÑ
+ÐŸÐŽÐœÑÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐµÑÐ»Ðž ÑÑÐµÐŽÑÑÐ²Ð° Ð²ÐµÐ±-Ð·ÐµÑÐºÐ°Ð»Ð° ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°Ð»ÐžÑÑ ÐŽÐ»Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐžÑ ÑÑÑÑÐºÑÑÑÑ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž ÐžÐŒÐ¿ÐŸÑÑÐ°.
+
+
+HTMLPlug.hunt_creator_metadata:ÐÐ°Ð¹ÑÐž ÐœÐ°ÑÐºÐŸÐ»ÑÐºÐŸ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ Ð±ÐŸÐ»ÑÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð² Ð°Ð²ÑÐŸÑÑÑÐ²Ðµ Ðž ÑÐ°Ð·ÐŒÐµÑÑÐžÑÑ ÐžÑ
+ Ð² Ð¿ÐŸÐ»Ðµ 'CÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ'. Ð¢ÑÐµÐ±ÑÐµÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐ»Ð°Ð³Ð° ÐœÐ° -metadata_fields (ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð¿ÐŸÐ»ÐµÐ¹).
+
+
+HTMLPlug.keep_head:ÐÐµ ÑÐŽÐ°Ð»ÑÑÑ Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž ÐžÐ· html-ÑÐ°Ð¹Ð»ÐŸÐ².
+
+
+HTMLPlug.metadata_fields:ÐÐ°Ð¿ÑÑÐ°Ñ ÐŸÑÐŽÐµÐ»ÑÐµÑ ÑÐ¿ÐžÑÐŸÐº Ð¿ÐŸÐ»ÐµÐ¹ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÑÑÐŸÐ±Ñ Ð¿ÐŸÐ¿ÑÑÐ°ÑÑÑÑ  ÐœÐ°ÑÐ°ÑÑ ÑÐºÑÑÑÐ°ÐºÑÐžÑ. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ'ÑÑÐ³ <tagname>', ÑÑÐŸÐ±Ñ Ð¿ÐŸÐ»ÑÑÐžÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÐµ Ð¿ÐµÑÐ²ÐŸÐ¹  Ð¿Ð°ÑÑ <tagname>, Ð²ÑÑÐ°Ð²Ð»ÐµÐœÐœÐŸÐ¹ Ð² ÑÐ»ÐµÐŒÐµÐœÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐœÐ°Ð·ÑÐ²Ð°ÐµÐŒÑÐ¹ 'tagname'. ÐÐ°ÐŒÐµÐœÐžÑÐµ Ð·ÐŽÐµÑÑ ÑÑÑÐŸÑÐœÑÐµ Ð±ÑÐºÐ²Ñ Ð·Ð°Ð³Ð»Ð°Ð²ÐœÑÐŒÐž, ÐµÑÐ»Ðž ÐÑ Ñ
+ÐŸÑÐžÑÐµ, ÑÑÐŸÐ±Ñ ÑÑÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Ð±ÑÐ»Ðž Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÑ Ð² Greenstone Ð·Ð°Ð³Ð»Ð°Ð²ÐœÑÐŒÐž Ð±ÑÐºÐ²Ð°ÐŒÐž, ÑÐ°Ðº ÐºÐ°Ðº ÑÐºÑÑÑÐ°ÐºÑÐžÑ ÑÑÐ³ÐŸÐ² ÑÐ²Ð»ÑÐµÑÑÑ ÐŒÐ°Ð»ÐŸÑÑÐ²ÑÑÐ²ÐžÑÐµÐ»ÑÐœÑÐŒ ÐŽÐµÐ¹ÑÑÐ²ÐžÐµÐŒ.
+
+
+HTMLPlug.no_metadata:ÐÐµ Ð¿ÑÑÐ°Ð¹ÑÐµÑÑ ÐžÐ·Ð²Ð»ÐµÐºÐ°ÑÑ Ð»ÑÐ±ÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ².
+
+
+HTMLPlug.no_strip_metadata_html:Ð¡Ð¿ÐžÑÐŸÐº ÐœÐ°Ð·Ð²Ð°ÐœÐžÐ¹ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+, Ð¿ÐµÑÐµÑÐžÑÐ»ÐµÐœÐœÑÑ
+ ÑÐµÑÐµÐ· Ð·Ð°Ð¿ÑÑÑÑ, ÐžÐ»Ðž 'all' (Ð²ÑÐµ). ÐÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÑÑ Ñ -description_tags, ÑÑÐŸ Ð¿ÑÐµÐŽÐŸÑÐ²ÑÐ°ÑÐ°ÐµÑ ÑÐŽÐ°Ð»ÐµÐœÐžÐµ HTML ÑÐ°Ð³ÐŸÐ² ÐžÐ· Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+.
+
+HTMLPlug.nolinks:ÐÐµ ÐŽÐµÐ»Ð°Ð¹ÑÐµ ÐœÐžÐºÐ°ÐºÐžÑ
+ Ð¿ÐŸÐ¿ÑÑÐŸÐº  ÑÐ»Ð°Ð²Ð»ÐžÐ²Ð°ÑÑ Ð»ÐžÐœÐºÐž (ÑÑÑÐ°ÐœÐŸÐ²ÐºÐ° ÑÐ°ÐºÐŸÐ³ÐŸ ÑÐ»Ð°Ð³Ð° ÐŒÐŸÐ¶ÐµÑ ÑÐ»ÑÑÑÐžÑÑ ÑÐºÐŸÑÐŸÑÑÑ Ð¿ÐŸÑÑÑÐŸÐµÐœÐžÑ/ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ, ÐœÐŸ Ð»ÑÐ±ÑÐµ ÐŸÑÐœÐŸÑÐžÑÐµÐ»ÑÐœÑÐµ ÑÐ²ÑÐ·Ðž Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Ð±ÑÐŽÑÑ ÐœÐ°ÑÑÑÐµÐœÑ).
+
+
+HTMLPlug.rename_assoc_files:ÐÐµÑÐµÐžÐŒÐµÐœÐŸÐ²ÑÐ²Ð°ÐµÑ ÑÐ°Ð¹Ð»Ñ, ÑÐ²ÑÐ·Ð°ÐœÐœÑÐµ Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°ÐŒÐž (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑÐŒÐž). Ð¢Ð°ÐºÐ¶Ðµ ÑÐŸÐ·ÐŽÐ°ÐµÑ ÐœÐ°ÐŒÐœÐŸÐ³ÐŸ Ð±ÐŸÐ»ÐµÐµ ÐŒÐµÐ»ÐºÑÑ ÑÑÑÑÐºÑÑÑÑ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž (Ð¿ÐŸÐ»ÐµÐ·ÐœÐŸ Ð¿ÑÐž ÑÐŸÐ·ÐŽÐ°ÐœÐžÐž ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐ¹, ÐºÐŸÑÐŸÑÑÐµ Ð±ÑÐŽÑÑ Ð¿ÐµÑÐµÐœÐµÑÐµÐœÑ ÐœÐ° CD-ROM).
+
+
+HTMLPlug.title_sub:ÐÑÑÐ°Ð¶ÐµÐœÐžÐµ Ð·Ð°ÐŒÐµÐœÑ ÐŽÐ»Ñ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ ÑÑÑÐŸÐºÐž, Ñ
+ÑÐ°ÐœÑÑÐµÐ¹ÑÑ ÐºÐ°Ðº ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ.ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ, ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐŒ PDFPlug, ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ "Ð¡ÑÑÐ°ÐœÐžÑÑ 1 ", Ðž Ñ.ÐŽ ÐžÐ· ÑÐµÐºÑÑÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐŸÐ³ÐŸ ÐºÐ°Ðº ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ.
+
+
+ImagePlug.converttotype:ÐÑÐµÐŸÐ±ÑÐ°Ð·ÐŸÐ²Ð°ÑÑ Ð³Ð»Ð°Ð²ÐœÐŸÐµ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ Ðº ÑÐŸÑÐŒÐ°ÑÑ 's'
+
+
+ImagePlug.desc:Ð­ÑÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ, ÐŽÐŸÐ±Ð°Ð²Ð»ÑÑ Ð±Ð°Ð·ÐŸÐ²ÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ
+
+
+ImagePlug.minimumsize:ÐÐµ Ð¿ÑÐžÐœÐžÐŒÐ°ÑÑ Ð²ÐŸ Ð²ÐœÐžÐŒÐ°ÐœÐžÐµ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ, ÐŒÐµÐœÑÑÐžÐµ, ÑÐµÐŒ n Ð±Ð°Ð¹Ñ.
+
+
+ImagePlug.noscaleup:ÐÐµ ÑÐ²ÐµÐ»ÐžÑÐžÐ²Ð°ÑÑ ÐŒÐ°Ð»ÐµÐœÑÐºÐžÐµ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ Ð¿ÑÐž ÑÐŒÐµÐœÑÑÐµÐœÐžÑÑ
+.
+
+
+ImagePlug.screenviewsize:ÐÑÐ»Ðž ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐŸ, ÐŽÐµÐ»Ð°ÐµÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ ÑÐ°Ð·ÐŒÐµÑÐŸÐŒ n ÐŽÐ»Ñ Ð¿ÐŸÐºÐ°Ð·Ð° ÑÐºÑÐ°ÐœÐ° Ðž ÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÐµÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ, Ð Ð°Ð·ÐŒÐµÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ, ÐšÐžÑÐžÐœÐ° ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ Ðž ÐÑÑÐŸÑÐ° ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ.ÐÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ ÐŸÐœÐŸ ÐœÐµ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐŸ.
+
+
+ImagePlug.screenviewtype:ÐÑÐ»Ðž  -screenviewsize ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ,  ÑÐŸ ÑÑÐŸ ÑÑÑÐ°ÐœÐ°Ð²Ð»ÐžÐ²Ð°ÐµÑ ÑÐžÐ¿ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ ÐŽÐ»Ñ  Ð¿ÐŸÐºÐ°Ð·Ð° ÐœÐ° ÑÐºÑÐ°ÐœÐµ.
+
+
+ImagePlug.thumbnailsize:ÐÑÐ¿ÐŸÐ»ÐœÐžÑÑ ÑÐŒÐµÐœÑÑÐµÐœÐžÐµ ÑÐ°Ð·ÐŒÐµÑÐ° nxn.
+
+
+ImagePlug.thumbnailtype:ÐÑÐ¿ÐŸÐ»ÐœÐžÑÑ ÑÐŒÐµÐœÑÑÐµÐœÐžÐµ Ð² ÑÐŸÑÐŒÐ°ÑÐµ 's'.
+
+
+IndexPlug.desc:Ð­ÑÐŸÑ ÑÐµÐºÑÑÑÐžÐ²ÐœÑÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÑ ÑÐ°Ð¹Ð» index.txt. Ð€Ð°Ð¹Ð» index.txt ÐŽÐŸÐ»Ð¶ÐµÐœ ÑÐŸÐŽÐµÑÐ¶Ð°ÑÑ ÑÐ¿ÐžÑÐŸÐº ÑÐ°Ð¹Ð»ÐŸÐ², ÐºÐŸÑÐŸÑÑÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ Ð²ÐºÐ»ÑÑÐµÐœÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ, ÑÐŸÐ¿ÑÐŸÐ²ÐŸÐ¶ÐŽÐ°ÐµÐŒÑÐ¹ Ð»ÑÐ±ÑÐŒÐž ÐŽÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÑÐŒÐž ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐŒÐž, ÑÐ²ÑÐ·Ð°ÐœÐœÑÐŒÐž Ñ ÐºÐ°Ð¶ÐŽÑÐŒ ÑÐ°Ð¹Ð»ÐŸÐŒ \n\n Ð€Ð°Ð¹Ð» index.txt ÐŽÐŸÐ»Ð¶ÐµÐœ Ð±ÑÑÑ ÑÐŸÑÐŒÐ°ÑÐžÑÐŸÐ²Ð°Ðœ ÑÐ»ÐµÐŽÑÑÑÐžÐŒ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ: Ð¿ÐµÑÐ²Ð°Ñ ÑÑÑÐŸÐºÐ° ÐŒÐŸÐ¶ÐµÑ Ð±ÑÑÑ ÐºÐ»ÑÑÐŸÐŒ (ÐœÐ°ÑÐžÐœÐ°Ñ Ñ ÐºÐ»ÑÑÐ°:), ÑÑÐŸÐ±Ñ ÐœÐ°Ð·Ð²Ð°ÑÑ Ð¿ÐŸÐ»Ñ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐºÐ»ÑÑ: ÐÑÐµÐŽÐŒÐµÑ, ÐÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ, ÐÐ°ÑÐ°). Ð¡Ð»ÐµÐŽÑÑÑÐžÐµ ÑÑÑÐŸÐºÐž Ð±ÑÐŽÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°ÑÑ ÐžÐŒÑ ÑÐ°Ð¹Ð»Ð°, Ð·Ð°ÑÐµÐŒ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÐµÑ
+ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð²Ñ
+ÐŸÐŽÐ°, ÐºÐŸÑÐŸÑÑÐµ ÐŽÐŸÐ»Ð¶ÐœÑ Ð±ÑÑÑ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ. (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, 'irma/iw097e 3.2 unesco 1993' ÑÐ²ÑÐ¶ÐµÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐÑÐµÐŽÐŒÐµÑ=3.2, ÐÑÐ³Ð°ÐœÐžÐ·Ð°ÑÐžÑ=unesco, Ðž ÐÐ°ÑÐ°=1993 Ñ ÑÐ°Ð¹Ð»ÐŸÐŒ irma/iw097e, ÐµÑÐ»Ðž Ð²ÑÑÐµÑÐ¿ÐŸÐŒÑÐœÑÑÐ°Ñ ÑÑÑÐŸÐºÐ° ÐºÐ»ÑÑÐ° ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐ°). \n\nÐÐ°ÐŒÐµÑÑÑÐµ, ÑÑÐŸ ÐµÑÐ»Ðž Ð»ÑÐ±ÐŸÐµ ÐžÐ· Ð¿ÐŸÐ»ÐµÐ¹ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑ Ð¿Ð»Ð°Ð³ÐžÐœ ÐžÐµÑÐ°ÑÑ
+ÐžÑÐµÑÐºÐŸÐ³ÐŸ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑÐ°, ÐºÐŸÐ³ÐŽÐ° ÐžÑ
+ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÑ , ÐŸÐœ ÐŽÐŸÐ»Ð¶ÐµÐœ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÐŸÐ²Ð°ÑÑ Ð¿ÐµÑÐ²ÐŸÐŒÑ Ð¿ÐŸÐ»Ñ (ÐŽÐµÑÐºÑÐžÐ¿ÑÐŸÑ) Ð² ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐµÐŒ ÑÐ°Ð¹Ð»Ðµ ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐžÐž. \n\nÐÐœÐ°ÑÐµÐœÐžÑ  ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ ÐŒÐŸÐ³ÑÑ Ð±ÑÑÑ ÐœÐ°Ð·Ð²Ð°ÐœÑ ÐŸÑÐŽÐµÐ»ÑÐœÐŸ, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÑ ÑÑÐ³ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ,>ÐÑÐµÐŽÐŒÐµÑ<3.2) Ðž ÑÑÐŸ Ð·Ð°ÐŒÐµÐœÐžÑ Ð»ÑÐ±ÐŸÐµ ÐžÐŒÑ, Ð¿ÑÐžÑÐ²ÐŸÐµÐœÐœÐŸÐµ ÐžÐŒ ÐºÐ»ÑÑÐµÐ²ÐŸÐ¹ ÑÑÑÐŸÐºÐŸÐ¹. ÐÑÐ»Ðž ÐºÐ»ÑÑÐµÐ²Ð°Ñ ÑÑÑÐŸÐºÐ° ÐŸÑÑÑÑÑÑÐ²ÑÐµÑ, Ð»ÑÐ±ÐŸÐµ ÐœÐµÐœÐ°Ð·Ð²Ð°ÐœÐœÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð±ÑÐŽÐµÑ ÐœÐ°Ð·Ð²Ð°ÐœÐŸ 'ÐÑÐµÐŽÐŒÐµÑ'.
+
+
+ISISPlug.desc:Ð­ÑÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÑ Ð±Ð°Ð·Ñ ÐŽÐ°ÐœÐœÑÑ
+ CDS/ISIS. ÐÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ¹ ÑÐ°ÐºÐŸÐ¹ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÐœÐœÐŸÐ¹ Ð±Ð°Ð·Ñ ÐŽÐ°ÐœÐœÑÑ
+ ÐŽÐŸÐ»Ð¶ÐœÑ ÑÑÑÐµÑÑÐ²ÐŸÐ²Ð°ÑÑ ÑÑÐž ÑÐ°Ð¹Ð»Ð° Ð² Ð¿Ð°Ð¿ÐºÐµ ÐžÐŒÐ¿ÐŸÑÑÐ° ÐºÐŸÐ»Ð»ÐµÐºÑÐžÐž: ÐŸÑÐœÐŸÐ²ÐœÐŸÐ¹ ÑÐ°Ð¹Ð» (.mst), ÑÐ°Ð±Ð»ÐžÑÐ° ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐžÑ Ð¿ÐŸÐ»ÐµÐ¹ (.fdt), Ðž ÑÐ°Ð¹Ð» Ð¿ÐµÑÐµÐºÑÐµÑÑÐœÑÑ
+ ÑÑÑÐ»ÐŸÐº (.xrf).
+
+
+ISISPlug.subfield_separator:Ð¡ÑÑÐŸÐºÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐ°Ñ ÐŽÐ»Ñ ÐŸÑÐŽÐµÐ»ÐµÐœÐžÑ Ð¿ÐŸÐŽÐ¿ÐŸÐ»ÐµÐ¹  Ð² Ð·Ð°Ð¿ÐžÑÑÑ
+ Ð±Ð°Ð·Ñ ÐŽÐ°ÐœÐœÑÑ
+ CDS/ISIS.
+
+
+ISISPlug.entry_separator:Ð¡ÑÑÐŸÐºÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐ°Ñ ÐŽÐ»Ñ ÐŸÑÐŽÐµÐ»ÐµÐœÐžÑ ÐŒÐœÐŸÐ¶ÐµÑÑÐ²ÐµÐœÐœÑÑ
+ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ ÐŽÐ»Ñ ÐŸÑÐŽÐµÐ»ÑÐœÑÑ
+ Ð¿ÐŸÐ»ÐµÐ¹ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Ð² Ð·Ð°Ð¿ÐžÑÑÑ
+ Ð±Ð°Ð·Ñ ÐŽÐ°ÐœÐœÑÑ
+ CDS/ISIS.
+
+
+LaTeXPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² LaTeX. 
+
+
+MACROPlug.desc:Ð¡ÐŸÐ·ÐŽÐ°ÐµÑ Ð¿ÑÐŸÑÑÐŸÐ¹ ÐŸÐŽÐœÐŸ-ÑÑÐŸÐ²ÐœÐµÐ²ÑÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ. ÐÐŸÐ±Ð°Ð²Ð»ÑÐµÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐÐ°Ð·Ð²Ð°ÐœÐžÑ ÐžÐ· Ð¿ÐµÑÐ²ÐŸÐ¹ ÑÑÑÐŸÐºÐž ÑÐµÐºÑÑÐ° (ÐŽÐŸ 100 Ð·ÐœÐ°ÐºÐŸÐ² ÐŽÐ»ÐžÐœÐŸÐ¹).
+
+
+MARCPlug.desc:ÐÑÐœÐŸÐ²ÐœÐŸÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ  MARC.
+
+
+MARCPlug.metadata_mapping:ÐÐŒÑ ÑÐ°Ð¹Ð»Ð°, ÐºÐŸÑÐŸÑÐŸÐµ Ð²ÐºÐ»ÑÑÐ°ÐµÑ ÐŽÐµÑÐ°Ð»Ðž ÐŸÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ Ð·ÐœÐ°ÑÐµÐœÐžÐ¹ ÐžÐ· MARC Ð² ÐžÐŒÐµÐœÐ° ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ Greenstone. ÐÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ 'marctodc.txt' ÐœÐ°Ñ
+ÐŸÐŽÐžÑÑÑ Ð²  ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž ÑÐ°Ð¹ÑÐŸÐ².
+
+
+MetadataPass.desc:ÐÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÑÐ¹ ÐºÐ»Ð°ÑÑ Ðº BasPlug, ÐºÐŸÑÐŸÑÑÐ¹ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÐµÑ Ð¿Ð°ÑÐ°ÐŒÐµÑÑ Ð¿Ð»Ð°Ð³ÐžÐœÐ° ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+ metadata_read Ð² import.pl
+
+GISBasPlug.desc:ÐÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÑÐ¹ ÐºÐ»Ð°ÑÑ Ðº BasPlug, ÐºÐŸÑÐŸÑÑÐ¹ Ð¿ÐŸÐŽÐŽÐµÑÐ¶ÐžÐ²Ð°ÐµÑ Ð²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸÑÑÐž ÐÐµÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÑ
+ ÐÐœÑÐŸÑÐŒÐ°ÑÐžÐŸÐœÑÑ
+ Ð¡ÐžÑÑÐµÐŒ (ÐÐÐ¡)
+
+NULPlug.desc:Ð¥ÐŸÐ»ÐŸÑÑÐŸÐµ Ð·ÐœÐ°ÑÐµÐœÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÐ° ÐŽÐ»Ñ ÑÐ°Ð¹Ð»Ð° (.nul). ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ Ñ ÑÐ°Ð¹Ð»Ð°ÐŒÐž, ÑÐŸÐ·ÐŽÐ°ÐœÐœÑÐŒÐž Ð¿ÑÐž ÑÐ°ÑÑÐžÑÐµÐœÐžÐž Ð±Ð°Ð·Ñ ÐŽÐ°ÐœÐœÑÐ¹ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐŒÐž ÑÐ°Ð¹Ð»ÐŸÐ².
+
+OAIPlug.desc:ÐÑÐœÐŸÐ²ÐœÐŸÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ ÐžÑÑ
+ÐŸÐŽÐœÑÑ
+ ÐŸÑÐºÑÑÑÑÑ
+ Ð°ÑÑ
+ÐžÐ²ÐŸÐ² (OAI).
+
+
+OggVorbisPlug.add_technical_metadata:ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐµÑ
+ÐœÐžÑÐµÑÐºÐžÐµ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÑÐºÐŸÑÐŸÑÑÑ Ð¿ÐµÑÐµÐŽÐ°ÑÐž).
+
+
+OggVorbisPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ Ð·Ð²ÑÐºÐŸÐ²ÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² Ogg Vorbis.
+
+
+PagedImgPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÑÐŸÑÑÐ°Ð²Ð»ÐµÐœÐœÑÑ
+ ÐžÐ· Ð¿ÐŸÑÐ»ÐµÐŽÐŸÐ²Ð°ÑÐµÐ»ÑÐœÐŸÑÑÐž ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐ¹, Ñ ÐœÐµÐŸÐ±ÑÐ·Ð°ÑÐµÐ»ÑÐœÑÐŒ ÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°ÐœÐœÑÐŒ ÑÐµÐºÑÑÐŸÐŒ Ðº ÐºÐ°Ð¶ÐŽÐŸÐŒÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ.
+
+
+PagedImgPlug.documenttype:Ð£ÑÑÐ°ÐœÐŸÐ²ÐžÑÐµ ÑÐžÐ¿ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° (ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ Ð¿ÑÐŸÑÐŒÐŸÑÑÐ°).
+
+PagedImgPlug.documenttype.paged:Ð¡ÑÑÐ°ÐœÐžÑÐœÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ ÑÑÑÐµÐ»ÐºÐž 'Ð¡Ð»ÐµÐŽÑÑÑÐ°Ñ' Ðž 'ÐÑÐµÐŽÑÐŽÑÑÐ°Ñ' Ðž ÐºÐœÐŸÐ¿ÐºÑ 'ÐÐµÑÐµÐ¹ÑÐž Ðº ÑÑÑÐ°ÐœÐžÑÐµ X'.
+
+PagedImgPlug.documenttype.hierarchy:ÐÐµÑÐ°ÑÑ
+ÐžÑÐµÑÐºÐžÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ ÐŸÐ³Ð»Ð°Ð²Ð»ÐµÐœÐžÐµ.
+
+
+PagedImgPlug.headerpage:ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° Ð·Ð°Ð³Ð»Ð°Ð²ÐœÑÑ ÑÑÑÐ°ÐœÐžÑÐºÑ (Ð±ÐµÐ· ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ).
+
+
+PagedImgPlug.screenview:Ð¡ÐŸÐ·ÐŽÐ°Ð¹ÑÐµ ÑÐºÑÐ°ÐœÐœÐŸÐµ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ, Ðž ÑÑÑÐ°ÐœÐŸÐ²ÐžÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ Screen (ÑÐºÑÐ°Ðœ), ScreenSize (ÑÐ°Ð·ÐŒÐµÑ ÑÐºÑÐ°ÐœÐ°), ScreenWidth (ÑÐžÑÐžÐœÐ° ÑÐºÑÐ°ÐœÐ°) Ðž ScreenHeight (Ð²ÑÑÐŸÑÐ° ÑÐºÑÐ°ÐœÐ°).
+
+
+PagedImgPlug.screenviewsize:Ð¡ÐŸÐ·ÐŽÐ°Ð¹ÑÐµ ÑÐºÑÐ°ÐœÐœÑÐµ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ ÑÐ°Ð·ÐŒÐµÑÐ° nxn.
+
+
+PagedImgPlug.screenviewtype:Ð¡ÐŸÐ·ÐŽÐ°Ð¹ÑÐµ ÑÐºÑÐ°ÐœÐœÑÐµ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ Ð² ÑÐŸÑÐŒÐ°ÑÐµ 's'.
+
+
+PagedImgPlug.thumbnail:Ð¡ÐŸÐ·ÐŽÐ°Ð¹ÑÐµ ÐžÐºÐŸÐœÐºÑ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ.
+
+
+PDFPlug.complex:Ð¡ÐŸÐ·ÐŽÐ°ÐµÑ Ð±ÐŸÐ»ÐµÐµ ÑÐ»ÐŸÐ¶ÐœÑÑ Ð¿ÑÐŸÐŽÑÐºÑÐžÑ. Ð¡ ÑÑÐŸÐ¹ ÐŸÐ¿ÑÐžÐµÐ¹ ÑÑÑÐ°ÐœÐŸÐ²ÐŸÐº Ð¿ÑÐŸÐŽÑÐºÑÐžÑ Ð² ÑÐŸÑÐŒÐ°ÑÐµ HTML Ð±ÑÐŽÐµÑ Ð²ÑÐ³Ð»ÑÐŽÐµÑÑ Ð·ÐœÐ°ÑÐžÑÐµÐ»ÑÐœÐŸ Ð±ÐŸÐ»ÐµÐµ Ð¿ÐŸÑ
+ÐŸÐ¶ÐµÐ¹ ÐœÐ° ÐŸÑÐžÐ³ÐžÐœÐ°Ð»ÑÐœÑÐ¹ PDF-ÑÐ°Ð¹Ð». ÐÐ»Ñ ÑÐŸÐ³ÐŸ, ÑÑÐŸÐ±Ñ ÑÑÐœÐºÑÐžÐŸÐœÐžÑÐŸÐ²Ð°ÑÑ ÐŽÐŸÐ»Ð¶ÐœÑÐŒ ÐŸÐ±ÑÐ°Ð·ÐŸÐŒ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ Ghostscript (ÐŽÐ»Ñ *nix gs ÐŽÐŸÐ»Ð¶ÐµÐœ Ð±ÑÑÑ ÐœÐ° Ð²Ð°ÑÐµÐŒ Ð¿ÑÑÐž ÐŽÐŸÑÑÑÐ¿Ð°, Ð² ÑÐŸ Ð²ÑÐµÐŒÑ ÐºÐ°Ðº ÐŽÐ»Ñ Windows Ñ ÐÐ°Ñ ÐŽÐŸÐ»Ð¶ÐµÐœ Ð±ÑÑÑ gswin32c.exe ÐœÐ° Ð¿ÑÑÐž ÐŽÐŸÑÑÑÐ¿Ð°).
+
+
+PDFPlug.desc:ÐÑÐžÐµÐŒÐ»ÐµÐŒÑÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ with-it pdf.
+
+
+PDFPlug.nohidden:ÐÑÐµÐ¿ÑÑÑÑÐ²ÑÐµÑ Ð¿ÐŸÐ¿ÑÑÐºÐ°ÐŒ pdftohtml ÐžÐ·Ð²Ð»ÐµÑÑ ÑÐºÑÑÑÑÐ¹ ÑÐµÐºÑÑ. Ð­ÑÐŸ Ð¿ÐŸÐ»ÐµÐ·ÐœÐŸ ÑÐŸÐ»ÑÐºÐŸ, ÐµÑÐ»Ðž ÐŸÐ¿ÑÐžÑ  -complex ÑÐ°ÐºÐ¶Ðµ ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœÐ°.
+
+
+PDFPlug.noimages:ÐÐµ Ð¿ÑÑÐ°Ð¹ÑÐµÑÑ ÐžÐ·Ð²Ð»ÐµÐºÐ°ÑÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ ÐžÐ· PDF.
+
+
+PDFPlug.use_sections:Ð¡ÐŸÐ·ÐŽÐ°ÑÑ ÐŸÑÐŽÐµÐ»ÑÐœÑÐ¹ ÑÐ°Ð·ÐŽÐµÐ» ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ¹ ÑÑÑÐ°ÐœÐžÑÑ PDF-ÑÐ°Ð¹Ð»Ð°.
+
+
+PDFPlug.zoom:Ð€Ð°ÐºÑÐŸÑ, c Ð¿ÐŸÐŒÐŸÑÑÑ ÐºÐŸÑÐŸÑÐŸÐ³ÐŸ ÐžÐ·ÐŒÐµÐœÑÐµÑÑÑ ÐŒÐ°ÑÑÑÐ°Ð± ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ PDF (ÑÑÐŸ Ð¿ÐŸÐ»ÐµÐ·ÐœÐŸ ÑÐŸÐ»ÑÐºÐŸ, ÐµÑÐ»Ðž   ÑÑÑÐ°ÐœÐŸÐ²Ð»ÐµÐœ -complex).
+
+
+PPTPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐžÐŒÐ¿ÐŸÑÑÐ° ÑÐ°Ð¹Ð»ÐŸÐ² Microsoft PowerPoint.
+
+
+PSPlug.desc:Ð­ÑÐŸ - Ð¿ÐŸÑÑÑÐºÑÐžÐ¿ÑÑÐŒ \"Ð±ÐµÐŽÐœÑÐµ Ð»ÑÐŽÐž\" ÐŽÐ»Ñ ÑÐµÐºÑÑÐŸÐ²ÐŸÐ³ÐŸ ÐºÐŸÐœÐ²ÐµÑÑÐµÑÐ°.. ÐÑÐ»Ðž ÑÐµÑÑÐµÐ·ÐœÐŸ, ÑÐ°ÑÑÐŒÐŸÑÑÐžÑÐµ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÐŸÐ²Ð°ÐœÐžÐµ Ð¿Ð°ÐºÐµÑÐ° PRESCRIPT, ÐºÐŸÑÐŸÑÑÐ¹ ÐŽÐŸÑÑÑÐ¿ÐµÐœ ÐŽÐ»Ñ Ð·Ð°Ð³ÑÑÐ·ÐºÐž Ñ http://www.nzdl.org/html/software.html
+
+
+PSPlug.extract_date:ÐÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ ÐŽÐ°ÑÑ ÐžÐ· Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐ° PS.
+
+
+PSPlug.extract_pages:ÐÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ ÑÑÑÐ°ÐœÐžÑ ÐžÐ· Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐ° PS.
+
+
+PSPlug.extract_title:ÐÐ·Ð²Ð»ÐµÑÐµÐœÐžÐµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ ÐžÐ· Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐ° PS.
+
+
+RecPlug.desc:RecPlug - ÑÑÐŸ Ð¿Ð»Ð°Ð³ÐžÐœ, ÐºÐŸÑÐŸÑÑÐ¹ Ð¿ÐŸÐ²ÑÐŸÑÑÐµÑÑÑ Ð² ÐºÐ°Ð¶ÐŽÐŸÐ¹ ÐŽÐžÑÐµÐºÑÐŸÑÐžÐž, ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°Ñ ÐºÐ°Ð¶ÐŽÑÐ¹ ÑÐ°Ð¹Ð», ÐºÐŸÑÐŸÑÑÐ¹ ÐŸÐœ ÐœÐ°Ñ
+ÐŸÐŽÐžÑ.
+
+
+RecPlug.recheck_directories:ÐÐŸÑÐ»Ðµ ÑÐŸÐ³ÐŸ, ÐºÐ°Ðº ÑÐ°Ð¹Ð»Ñ Ð² Ð¿Ð°Ð¿ÐºÐµ ÐžÐŒÐ¿ÐŸÑÑÐ° Ð±ÑÐ»Ðž ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÐœÑ, Ð¿Ð°Ð¿ÐºÐ° Ð¿ÐŸÐ²ÑÐŸÑÐœÐŸ Ð¿ÑÐŸÑÐžÑÑÐ²Ð°ÐµÑÑÑ, ÑÑÐŸÐ±Ñ ÐŸÐ±ÐœÐ°ÑÑÐ¶ÐžÑÑ Ð»ÑÐ±ÑÐµ Ð²ÐœÐŸÐ²Ñ ÑÐŸÐ·ÐŽÐ°ÐœÐœÑÐµ ÑÐ°Ð¹Ð»Ñ.
+
+
+RecPlug.use_metadata_files:Ð§ÐžÑÐ°ÑÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐžÐ· ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ XML-ÑÐ°Ð¹Ð»ÐŸÐ².
+
+
+ReferPlug.desc:ReferPlug ÑÐžÑÐ°ÐµÑ Ð±ÐžÐ±Ð»ÐžÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÐµ ÑÐ°Ð¹Ð»Ñ Ð² ÑÐµÑÐµÑÐ°ÑÐžÐ²ÐœÐŸÐŒ ÑÐŸÑÐŒÐ°ÑÐµ.
+
+
+ReferPlug.longdesc:ReferPlug ÑÐžÑÐ°ÐµÑ Ð±ÐžÐ±Ð»ÐžÐŸÐ³ÑÐ°ÑÐžÑÐµÑÐºÐžÐµ ÑÐ°Ð¹Ð»Ñ Ð² ÑÐµÑÐµÑÐ°ÑÐžÐ²ÐœÐŸÐŒ ÑÐŸÑÐŒÐ°ÑÐµ. \nÐÐŸÑÐŽÐŸÐœ Ð.ÐÑÐ¹ÐœÑÐµÑ (gwp\@cs.waikato.ac.nz), ÐœÐŸÑÐ±ÑÑ 2000 Ð³.\n\nÐ¡Ð²ÐŸÐ±ÐŸÐŽÐœÐŸ ÐŸÑÐœÐŸÐ²Ð°ÐœÐœÑÐ¹ ÐœÐ° hcibib2Plug Ð¡ÑÐžÐ²ÐŸÐŒ ÐÐ¶ÐŸÑÐœÑÐŸÐŒ (stevej\@cs.waikato.ac.nz). ÐÐŸÑÐŸÑÑÐ¹ Ð±Ð°Ð·ÐžÑÐŸÐ²Ð°Ð»ÑÑ ÐœÐ° EMAILPlug ÐÐŸÑÐŽÐŸÐœÐ° ÐÑÐ¹ÐœÑÐµÑÐ° (gwp\@cs.waikato.ac.nz). ÐÐŸÑÐŸÑÑÐ¹ Ð±Ð°Ð·ÐžÑÐŸÐ²Ð°Ð»ÑÑ ÐœÐ° ÑÑÐ°ÑÑÑ
+ Ð²ÐµÑÑÐžÑÑ
+ HTMLplug Ðž HCIBIBPlugby ÐšÑÐµÑÐ°ÐœÐ° ÐÐŸÐŽÐŽÐž, Ð° ÐŽÑÑÐ³ÐžÐµ -  ÑÐµÐ¿ÐµÑÑ ÑÑÑÐŽÐœÐŸ ÑÐºÐ°Ð·Ð°ÑÑ, ÑÑÐŸ ÐŸÑÐºÑÐŽÐ° Ð²Ð·ÑÐ»ÐŸÑÑ.\n\nReferPlug ÑÐŸÐ·ÐŽÐ°ÐµÑ ÐŸÑÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ¹ ÑÑÑÐ»ÐºÐž Ð² ÑÐ°Ð¹Ð»Ðµ. ÐÐœ ÑÐ²Ð»ÑÐµÑÑÑ Ð¿ÐŸÐŽÐºÐ»Ð°ÑÑÐŸÐŒ SplitPlug, ÑÐ°Ðº ÑÑÐŸ, ÐµÑÐ»Ðž ÐµÑÑÑ ÐŒÐœÐŸÐ³ÐŸÐºÑÐ°ÑÐœÑÐµ Ð·Ð°Ð¿ÐžÑÐž, ÑÐŸ Ð²ÑÐµ ÐŸÐœÐžÑÐžÑÐ°ÑÑÑÑ. \n\n ÐÐŸÐºÑÐŒÐµÐœÑ, ÑÐµÐºÑÑ:\n\tÐ¢ÐµÐºÑÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ° ÑÐŸÑÑÐŸÐžÑ ÐžÐ· ÑÑÑÐ»ÐºÐž Ð² ÑÐµÑÐµÑÐ°ÑÐžÐ²ÐœÐŸÐŒ ÑÐŸÑÐŒÐ°ÑÐµ.\nÐÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ:\n\t\$Ð¡ÐŸÐ·ÐŽÐ°ÑÐµÐ»Ñ\%A ÐÐŒÑ Ð°Ð²ÑÐŸÑÐ°\n\t\$ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ \%T ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ ÑÑÐ°ÑÑÐž ÐžÐ· ÐºÐœÐžÐ³Ðž\n\t\$ÐÑÑÐœÐ°Ð» \%J ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ Ð¶ÑÑÐœÐ°Ð»Ð°\n\t\$ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐºÐœÐžÐ³Ðž \%B ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ ÐºÐœÐžÐ³Ðž, ÑÐŸÐŽÐµÑÐ¶Ð°ÑÐµÐ¹ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÑ\n\t\$Ð¡ÐŸÐŸÐ±ÑÐµÐœÐžÐµ \%R Ð¢ÐžÐ¿ ÑÐŸÐŸÐ±ÑÐµÐœÐžÑ, ÑÑÐ°ÑÑÑ ÐžÐ»Ðž ÑÐµÐ·ÐžÑÑ\n\t\$Ð¢ÐŸÐŒ \%V ÐÐŸÐŒÐµÑ ÑÐŸÐŒÐ° Ð¶ÑÑÐœÐ°Ð»Ð°\n\t\$ÐÐŸÐŒÐµÑ \%N ÐÐŸÐŒÐµÑ Ð¶ÑÑÐœÐ°Ð»Ð° Ð² Ð¿ÑÐµÐŽÐµÐ»Ð°Ñ
+ ÑÐŸÐŒÐ°\n\t\$Ð ÐµÐŽÐ°ÐºÑÐŸÑ \%E ÐÐŒÑ ÑÐµÐŽÐ°ÐºÑÐŸÑÐ°\n\t\$Ð¡ÑÑÐ°ÐœÐžÑÑ \%P ÐÐŸÐŒÐµÑ ÑÑÑÐ°ÐœÐžÑÑ ÑÑÐ°ÑÑÐž\n\t\$ÐÐ·ÐŽÐ°ÑÐµÐ»Ñ \%I ÐÐŒÑÐžÐ·ÐŽÐ°ÑÐµÐ»Ñ\n\t\$ÐÐŽÑÐµÑ ÐžÐ·ÐŽÐ°ÑÐµÐ»Ñ \%C Ð°ÐŽÑÐµÑ\n\t\$ÐÐ°ÑÐ° \%D ÐÐ°ÑÐ° Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž\n\t\$ÐÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð° \%K ÐÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð°, ÑÐ²ÑÐ·Ð°ÐœÐœÑÐµ Ñ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐµÐ¹\n\t\$Ð ÐµÐ·ÑÐŒÐµ \%X Ð ÐµÐ·ÑÐŒÐµ Ð¿ÑÐ±Ð»ÐžÐºÐ°ÑÐžÐž\n\t\$ÐÐŸÐ¿ÐžÑÐ°Ð¹Ñ t\%* ÐÐœÑÐŸÑÐŒÐ°ÑÐžÑ ÐŸÐ± Ð°Ð²ÑÐŸÑÑÐºÐŸÐŒ Ð¿ÑÐ°Ð²Ðµ ÐœÐ° ÑÑÐ°ÑÑÑ.
+
+
+RogPlug.desc:Ð¡ÐŸÐ·ÐŽÐ°ÐµÑ Ð¿ÑÐŸÑÑÑÐµ ÐŸÐŽÐœÐŸ-ÑÑÐŸÐ²ÐœÐµÐ²ÑÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÑ ÐžÐ· ÑÐ°Ð¹Ð»ÐŸÐ² .rog ÐžÐ»Ðž .mdb.
+
+
+RTFPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ ÑÐ°Ð¹Ð»ÐŸÐ² RTF.
+
+
+SRCPlug.desc:ÐÐŒÑ ÑÐ°Ð¹Ð»Ð° Ð² ÐœÐ°ÑÑÐŸÑÑÐµÐµ Ð²ÑÐµÐŒÑ ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ ÐŽÐ»Ñ ÐÐ°Ð·Ð²Ð°ÐœÐžÑ (Ð¿ÑÐŸÐžÐ·Ð²ÐŸÐ»ÑÐœÐŸ Ð²ÑÐ±ÑÐ°ÐœÐœÐŸÐµ ÐŒÐžÐœÑÑ ÐœÐµÐºÐŸÑÐŸÑÑÑ Ð¿ÑÐžÑÑÐ°Ð²ÐºÑ). Ð¢ÐµÐºÑÑÐžÐµ ÑÐ·ÑÐºÐž:\nÑÐµÐºÑÑ:READMEs/Ð¡ÐŸÐ·ÐŽÐ°ÐœÐžÐµÑÐ°Ð¹Ð»ÐŸÐ²\nC/C ++ (Ð² ÐœÐ°ÑÑÐŸÑÑÐµÐµ Ð²ÑÐµÐŒÑ ÐžÐ·Ð²Ð»ÐµÐºÐ°ÐµÑ #Ð²ÐºÐ»ÑÑÐµÐœÐœÑÐµ ÐŸÐ¿ÐµÑÐ°ÑÐŸÑÑ Ðž decls ÐºÐ»Ð°ÑÑÐ° C ++ ) \nPerl (Ð² ÐœÐ°ÑÑÐŸÑÑÐµÐµ Ð²ÑÐµÐŒÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐœÑÐ¹ ÑÐŸÐ»ÑÐºÐŸ Ð² Ð²ÐžÐŽÐµ ÑÐµÐºÑÑÐ°) \nÐÐ±ÐŸÐ»ÐŸÑÐºÐ° (Ð² ÐœÐ°ÑÑÐŸÑÑÐµÐµ Ð²ÑÐµÐŒÑ Ð¿ÑÐµÐŽÑÑÐ°Ð²Ð»ÐµÐœÐœÐ°Ñ ÑÐŸÐ»ÑÐºÐŸ Ð² Ð²ÐžÐŽÐµ ÑÐµÐºÑÑÐ°).
+
+
+SRCPlug.remove_prefix:Ð£ÐŽÐ°Ð»ÐžÑÑ ÑÑÐŸÑ Ð²ÐµÐŽÑÑÐžÐ¹ ÐŸÐ±ÑÐ°Ð·ÐµÑ ÐžÐ· ÐžÐŒÐµÐœÐž ÑÐ°Ð¹Ð»Ð° (eg-remove_prefix/tmp/xx/src/). ÐÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ ÐŽÐŸÐ»Ð¶ÐµÐœ Ð²ÐµÑÑ Ð¿ÑÑÑ ÐŽÐŸÑÑÑÐ¿Ð° ÐŸÑ ÐžÐŒÐµÐœÐž ÑÐ°Ð¹Ð»Ð°.
+
+
+SplitPlug.desc:SplitPlug - ÑÑÐŸ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ Ð²Ñ
+ÐŸÐŽÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÐœÐ° ÑÐµÐ³ÐŒÐµÐœÑÑ, ÐºÐŸÑÐŸÑÑÐµ Ð±ÑÐŽÑÑ Ð¿ÐŸÑÐŸÐŒ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÑÑÑÑ Ð¿ÐŸ ÐŸÑÐŽÐµÐ»ÑÐœÐŸÑÑÐž.Ð­ÑÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœ ÐœÐµÐ»ÑÐ·Ñ Ð²ÑÐ·Ð²Ð°ÑÑ ÐœÐµÐ¿ÐŸÑÑÐµÐŽÑÑÐ²ÐµÐœÐœÐŸ. ÐÐŒÐµÑÑÐŸ ÑÑÐŸÐ³ÐŸ, ÐµÑÐ»Ðž ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÑÑ Ð²Ñ
+ÐŸÐŽÐœÑÐµ ÑÐ°Ð¹Ð»Ñ, ÐºÐŸÑÐŸÑÑÐµ ÑÐŸÐŽÐµÑÐ¶Ð°Ñ ÐœÐµÑÐºÐŸÐ»ÑÐºÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐÑ ÐŽÐŸÐ»Ð¶ÐœÑ ÐœÐ°Ð¿ÐžÑÐ°ÑÑ Ð¿Ð»Ð°Ð³ÐžÐœ Ñ ÑÑÐœÐºÑÐžÐµÐ¹ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐž, ÐºÐŸÑÐŸÑÑÐ¹ Ð±ÑÐŽÐµÑ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÑÑ ÐŸÐŽÐžÐœ ÐžÐ· ÑÑÐžÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ², ÐœÐ°ÑÐ»ÐµÐŽÑÑ ÐµÐ³ÐŸ ÐžÐ· SplitPlug. Ð¡ÐŒ. ReferPlug ÐŽÐ»Ñ Ð¿ÑÐžÐŒÐµÑÐ°.
+
+
+SplitPlug.split_exp:ÐÑÐ°Ð²ÐžÐ»ÑÐœÐŸÐµ Ð²ÑÑÐ°Ð¶ÐµÐœÐžÐµ perl ÐŽÐ»Ñ ÑÐ°Ð·Ð±ÐžÐµÐœÐžÑ Ð²Ñ
+ÐŸÐŽÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ² ÐœÐ° ÑÐ°ÑÑÐž.
+
+
+TEXTPlug.desc:Ð¡ÐŸÐ·ÐŽÐ°ÐµÑ Ð¿ÑÐŸÑÑÐŸÐ¹ ÐŸÐŽÐœÐŸ-ÑÑÐŸÐ²ÐœÐµÐ²ÑÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ. ÐÐŸÐ±Ð°Ð²Ð»ÑÐµÑ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÐÐ°Ð·Ð²Ð°ÐœÐžÑ ÐžÐ· Ð¿ÐµÑÐ²ÐŸÐ¹ ÑÑÑÐŸÐºÐž ÑÐµÐºÑÑÐ° (ÐŽÐ»ÐžÐœÐŸÐ¹ ÐŽÐŸ 100 Ð·ÐœÐ°ÐºÐŸÐ².
+
+
+TEXTPlug.title_sub:ÐÑÑÐ°Ð¶ÐµÐœÐžÐµ Ð·Ð°ÐŒÐµÐœÑ ÐŽÐ»Ñ ÐžÐ·ÐŒÐµÐœÐµÐœÐžÑ ÑÑÑÐŸÐºÐž, Ñ
+ÑÐ°ÐœÑÑÐµÐ¹ÑÑ ÐºÐ°Ðº ÐÐ°Ð·Ð²Ð°ÐœÐžÐµ. ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÑÑÑ, ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, PSPlug, ÑÑÐŸÐ±Ñ ÑÐŽÐ°Ð»ÐžÑÑ "Ð¡ÑÑÐ°ÐœÐžÑÑ 1" Ðž Ñ.ÐŽ ÐžÐ· ÑÐµÐºÑÑÐ°, ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÐŸÐ³ÐŸ Ð² ÐºÐ°ÑÐµÑÑÐ²Ðµ ÐœÐ°Ð·Ð²Ð°ÐœÐžÑ.
+
+
+UnknownPlug.assoc_field:ÐÐŒÑ Ð¿ÐŸÐ»Ñ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+, ÐºÐŸÑÐŸÑÐŸÐµ Ð±ÑÐŽÐµÑ ÐŽÐµÑÐ¶Ð°ÑÑ ÐžÐŒÐµÐœÐ° Ð°ÑÑÐŸÑÐžÐžÑÐŸÐ²Ð°ÐœÐœÑÑ
+ ÑÐ°Ð¹Ð»ÐŸÐ².
+
+
+UnknownPlug.desc:Ð­ÑÐŸ Ð¿ÑÐŸÑÑÐŸÐ¹ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ ÑÐ°Ð¹Ð»ÐŸÐ² Ð² ÑÐŸÑÐŒÐ°ÑÐ°Ñ
+, ÐœÐµÐžÐ·Ð²ÐµÑÑÐœÑÑ
+ ÐŽÐ»Ñ Greenstone.  ÐÑÐŒÑÑÐ»ÐµÐœÐœÑÐ¹ ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð±ÑÐŽÐµÑ ÑÐŸÐ·ÐŽÐ°Ðœ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÑÐ°ÐºÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð°, Ðž ÑÐ°ÐŒ ÑÐ°Ð¹Ð» Ð±ÑÐŽÐµÑ Ð¿ÐµÑÐµÐŽÐ°Ðœ Ð² Greenstone ÐºÐ°Ðº \"Ð°ÑÑÐŸÑÐžÐžÑÐŸÐ²Ð°ÐœÐœÑÐ¹ ÑÐ°Ð¹Ð»\" ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°.
+
+
+UnknownPlug.file_format:Ð¢ÐžÐ¿ ÑÐ°Ð¹Ð»Ð° (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, MPEG, MIDI, ...).
+
+
+UnknownPlug.mime_type:Ð¢ÐžÐ¿ ÑÐ°Ð¹Ð»Ð°  mime (ÐœÐ°Ð¿ÑÐžÐŒÐµÑ, ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐµ/gif).
+
+
+UnknownPlug.process_extension:ÐÐ±ÑÐ°Ð±ÐŸÑÐºÐ° ÑÐ°Ð¹Ð»ÐŸÐ² Ñ ÐŸÐ¿ÑÐµÐŽÐµÐ»ÐµÐœÐœÑÐŒ ÑÐ°ÑÑÐžÑÐµÐœÐžÐµÐŒ. Ð­ÑÐ° ÐŸÐ¿ÑÐžÑ - Ð°Ð»ÑÑÐµÑÐœÐ°ÑÐžÐ²Ð° Ðº process_exp, ÐºÐŸÑÐŸÑÐ°Ñ Ð¿ÑÐŸÑÐµ, ÐœÐŸ ÐŒÐµÐœÐµÐµ Ð¿ÑÐžÑÐ¿ÐŸÑÐ°Ð±Ð»ÐžÐ²Ð°ÐµÐŒÐ°Ñ.
+
+
+MP3Plug.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐž MP3 ÑÐ°Ð¹Ð»ÐŸÐ².
+
+
+MP3Plug.assoc_images:Use google image search to locate images related to MP3 file based on ID3 Title and Artist metadata.
+
+MP3Plug.assoc_images:ÐÑÐ¿ÐŸÐ»ÑÐ·Ð°Ð²Ð°ÐœÐœÐŸ ÐŽÐ»Ñ ÑÐŸÐ³ÐŸ, ÑÑÐŸÐ±Ñ Ñ
+ÑÐ°ÐœÐžÑÑ [Ð°Ð¿Ð¿Ð»ÐµÑ] ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÐµ ÐŽÐ»Ñ ÐºÐ°Ð¶ÐŽÐŸÐ³ÐŸ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°, Ð² ÐºÐŸÑÐŸÑÑÑ
+ Ð·Ð°Ð¿ÐžÑÐ°Ðœ HTML ÐŽÐ»Ñ Ð¿ÑÐŸÐžÐ³ÑÑÐ²Ð°ÐœÐžÑ ÑÑÐŸÐ³ÐŸ ÑÐ°Ð¹Ð»Ð° Ð² MP3 Ð¿ÑÐŸÐžÐ³ÑÑÐ²Ð°ÑÐµÐ»Ðµ.
+
+
+MP3Plug.metadata_fields:Ð¡Ð¿ÐžÑÐŸÐº Ð¿ÐŸÐ»ÐµÐ¹ ÐŒÐµÑÐ°-ÐŽÐ°ÐœÐœÑÑ
+, Ð¿ÐµÑÐµÑÐžÑÐ»ÐµÐœÐœÑÑ
+ ÑÐµÑÐµÐ· Ð·Ð°Ð¿ÑÑÑÑ, ÐºÐŸÑÐŸÑÑÐµ Ð¿ÑÐµÐŽÐœÐ°Ð·ÐœÐ°ÑÐµÐœÑ ÐŽÐ»Ñ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÑ ÐžÐ· MP3 ÑÐ°Ð¹Ð»Ð° (ÐµÑÐ»Ðž ÐŽÐŸÑÑÑÐ¿ÐµÐœ). ÐÑÐ¿ÐŸÐ»ÑÐ·ÑÐ¹ÑÐµ \"*\" ÐŽÐ»Ñ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÑ Ð²ÑÐµÑ
+ Ð¿ÐŸÐ»ÐµÐ¹.
+
+
+W3ImgPlug.aggressiveness:Ð Ð°ÐœÐ³ ÑÐ²ÑÐ·Ð°ÐœÐœÑÑ
+ ÐŒÐµÑÐŸÐŽÐŸÐ², ÐžÑÐ¿ÐŸÐ»ÑÐ·ÑÐµÐŒÑÑ
+ ÐŽÐ»Ñ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÑ ÑÐµÐºÑÑÐ°.
+
+W3ImgPlug.aggressiveness.1:ÐÐŒÑ ÑÐ°Ð¹Ð»Ð°, Ð¿ÑÑÑ, ÐŒÐŸÐŽÐžÑÐžÐºÐ°ÑÐžÑ (ALT) ÑÐŸÐ»ÑÐºÐŸ ÑÐµÐºÑÑÐ°.
+
+W3ImgPlug.aggressiveness.2:ÐÑÐµ ÐžÐ· 1 Ð¿Ð»ÑÑ Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐŸÐº, Ð³ÐŽÐµ ÑÑÐŸ ÐŽÐŸÑÑÑÐ¿ÐœÐŸ.
+
+W3ImgPlug.aggressiveness.3:ÐÑÐµ  ÐžÐ· 2 Ð¿Ð»ÑÑ Ð±Ð»ÐžÐ¶Ð°Ð¹ÑÐžÐµ Ð¿Ð°ÑÐ°Ð³ÑÐ°ÑÑ, Ð³ÐŽÐµ ÑÑÐŸ ÐŽÐŸÑÑÑÐ¿ÐœÐŸ.
+
+W3ImgPlug.aggressiveness.4:ÐÑÐµ ÐžÐ· 3 Ð¿Ð»ÑÑ Ð¿ÑÐµÐŽÑÐŽÑÑÐžÐµ Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐž (<h1>, <h2> ...), Ð³ÐŽÐµ ÑÑÐŸ ÐŽÐŸÑÑÑÐ¿ÐœÐŸ.
+
+W3ImgPlug.aggressiveness.5:ÐÑÐµ ÐžÐ· 4 Ð¿Ð»ÑÑ ÑÐµÐºÑÑÐŸÐ²ÑÐµ ÑÑÑÐ»ÐºÐž, Ð³ÐŽÐµ ÑÑÐŸ ÐŽÐŸÑÑÑÐ¿ÐœÐŸ.
+
+W3ImgPlug.aggressiveness.6:ÐÑÐµ ÐžÐ· 4 Ð¿Ð»ÑÑ ÑÑÑÐ°ÐœÐžÑÐ° ÐŒÐµÑÐ°ÑÑÐ³ÐŸÐ² (ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ, ÐºÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð° Ðž Ñ.ÐŽ).
+
+W3ImgPlug.aggressiveness.7:ÐÑÐµ  ÐžÐ· ÐŸÐ±ÑÐµÐŽÐžÐœÐµÐœÐœÑÑ
+ 6, 5 Ðž 4.
+
+W3ImgPlug.aggressiveness.8:ÐÑÐµ ÐžÐ· 7 Ð¿Ð»ÑÑ Ð¿ÐŸÐ²ÑÐŸÑÐµÐœÐžÐµ Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐ°, ÐžÐŒÐµÐœÐž ÑÐ°Ð¹Ð»Ð° Ðž Ñ.ÐŽ ( Ð¿ÐŸÐ²ÑÑÐµÐœÐžÐµ ÑÐ°ÐœÐ³Ð° Ð±ÐŸÐ»ÐµÐµ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐžÑ
+ ÑÐµÐ·ÑÐ»ÑÑÐ°ÑÐŸÐ²).
+
+W3ImgPlug.aggressiveness.9:ÐÑÐµ ÐžÐ· 1 Ð¿Ð»ÑÑ Ð¿ÐŸÐ»ÐœÑÐ¹ ÑÐµÐºÑÑ ÐžÑÑ
+ÐŸÐŽÐœÐŸÐ¹ ÑÑÑÐ°ÐœÐžÑÑ.
+
+
+W3ImgPlug.caption_length:ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐ°Ñ ÐŽÐ»ÐžÐœÐ° Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐŸÐ² (Ð² Ð·ÐœÐ°ÐºÐ°Ñ
+).
+
+
+W3ImgPlug.convert_params: ÐÐŸÐ¿ÐŸÐ»ÐœÐžÑÐµÐ»ÑÐœÑÐµ Ð¿Ð°ÑÐ°ÐŒÐµÑÑÑ ÐŽÐ»Ñ ImageMagicK ÐºÐŸÐœÐ²ÐµÑÑÐžÑÑÑÑ ÑÐŒÐµÐœÑÑÐµÐœÐœÑÐµ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ. ÐÐ°Ð¿ÑÐžÐŒÐµÑ, '-Ð¿ÐŸÐ²ÑÑÐµÐœÐžÐµ' ÐŽÐ°ÑÑ ÑÑÐµÑ
+ÐŒÐµÑÐœÑÐ¹ Ð²ÐžÐŽ ÑÐŒÐµÐœÑÑÐµÐœÐœÑÐŒ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑÐŒ.
+
+
+W3ImgPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐžÐ·Ð²Ð»ÐµÑÐµÐœÐžÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐ¹ Ðž ÑÐ²ÑÐ·Ð°ÐœÐœÐŸÐ³ÐŸ ÑÐµÐºÑÑÐ° ÐžÐ· Ð²ÐµÐ±-ÑÑÑÐ°ÐœÐžÑ.
+
+
+W3ImgPlug.document_text:ÐÐŸÐ±Ð°Ð²ÐžÑÑ ÑÐµÐºÑÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ Ð² Ð²ÐžÐŽÐµ ÐŽÐŸÐºÑÐŒÐµÐœÑÐ°:ÑÐµÐºÑÑ (ÐžÐœÐ°ÑÐµ, Ð¿ÐŸÐ»Ðµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÑ
+ IndexedText).
+
+
+W3ImgPlug.index_pages:ÐÐœÐŽÐµÐºÑÐžÑÐŸÐ²Ð°ÑÑ ÑÑÑÐ°ÐœÐžÑÑ ÐœÐ°ÑÑÐŽÑ Ñ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑÐŒÐž. ÐÐœÐ°ÑÐµ, ÑÐŸÑÐ»Ð°ÑÑÑÑ ÐœÐ° ÑÑÑÐ°ÐœÐžÑÑ Ð² ÐžÑÑ
+ÐŸÐŽÐœÐŸÐŒ URL.
+
+
+W3ImgPlug.max_near_text:ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸ Ð·ÐœÐ°ÐºÐŸÐ² Ñ ÐžÐ·Ð²Ð»ÐµÐºÐ°ÐµÐŒÑÑ
+ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐ¹.
+
+
+W3ImgPlug.min_height:ÐÐžÐºÑÐµÐ»Ñ. ÐÑÐŸÐ¿ÑÑÑÐžÑÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ, ÐŒÐµÐœÑÑÐžÐµ, ÑÐµÐŒ ÑÑÐŸ.
+
+
+W3ImgPlug.min_near_text:ÐÐžÐœÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÐºÐŸÐ»ÐžÑÐµÑÑÐ²ÐŸ Ð·ÐœÐ°ÐºÐŸÐ² Ñ ÐžÐ·Ð²Ð»ÐµÐºÐ°ÐµÐŒÐŸÐ³ÐŸ ÑÐµÐºÑÑÐ° ÐžÐ»Ðž Ð·Ð°Ð³ÐŸÐ»ÐŸÐ²ÐºÐ°.
+
+
+W3ImgPlug.min_size:ÐÐ°Ð¹ÑÑ. ÐÑÐŸÐ¿ÑÑÑÐžÑÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ, ÐŒÐµÐœÑÑÐžÐµ, ÑÐµÐŒ ÑÑÐŸ.
+
+
+W3ImgPlug.min_width:ÐÐžÐºÑÐµÐ»Ñ. ÐÑÐŸÐ¿ÑÑÑÐžÑÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ, Ð±ÐŸÐ»ÐµÐµ ÑÐ·ÐºÐžÐµ, ÑÐµÐŒ ÑÑÐŸ.
+
+
+W3ImgPlug.neartext_length:ÐÐ»ÐžÐœÐ° Ð°ÐŽÑÐµÑÐ° Ñ ÑÐµÐºÑÑÐ° (Ð² Ð·ÐœÐ°ÐºÐ°Ñ
+).
+
+
+W3ImgPlug.no_cache_images:ÐÐµ ÐŽÐµÐ»Ð°ÑÑ ÐºÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ ÐžÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÐ¹ (ÑÐºÐ°Ð·Ð°ÑÑ URL ÐŸÑÐžÐ³ÐžÐœÐ°Ð»Ð°).
+
+
+W3ImgPlug.smallpage_threshold:ÐÐ·ÐŸÐ±ÑÐ°Ð¶ÐµÐœÐžÑ ÐœÐ° ÑÑÑÐ°ÐœÐžÑÐ°Ñ
+, ÐŒÐµÐœÑÑÐžÑ
+ ÑÐµÐŒ ÑÑÐ° ( Ð² Ð±Ð°Ð¹ÑÐ°Ñ
+), Ð±ÑÐŽÑÑ ÐžÐŒÐµÑÑ ÐŽÐŸÐ±Ð°Ð²Ð»ÐµÐœÐœÑÐµ ÐŒÐµÑÐ°ÐŽÐ°ÐœÐœÑÐµ ÑÑÑÐ°ÐœÐžÑÑ (ÐœÐ°Ð·Ð²Ð°ÐœÐžÐµ, ÐºÐ»ÑÑÐµÐ²ÑÐµ ÑÐ»ÐŸÐ²Ð° Ðž Ñ.ÐŽ).
+
+
+W3ImgPlug.textrefs_threshold:ÐÐŸÑÐŸÐ³ ÐŽÐ»Ñ ÑÐµÐºÑÑÐŸÐ²ÑÑ
+ ÑÑÑÐ»ÐŸÐº. ÐÐŸÐ»ÐµÐµ ÐœÐžÐ·ÐºÐžÐµ Ð·ÐœÐ°ÑÐµÐœÐžÑ Ð¿ÐŸÐŽÑÐ°Ð·ÑÐŒÐµÐ²Ð°ÑÑ, ÑÑÐŸ Ð°Ð»Ð³ÐŸÑÐžÑÐŒ ÐŒÐµÐœÐµÐµ ÑÑÑÐŸÐ³.
+
+
+W3ImgPlug.thumb_size:ÐÐ°ÐºÑÐžÐŒÐ°Ð»ÑÐœÐŸÐµ ÑÐŒÐµÐœÑÑÐµÐœÐžÐµ ÑÐ°Ð·ÐŒÐµÑÐ° - Ðž ÑÐžÑÐžÐœÑ, Ðž Ð²ÑÑÐŸÑÑ.
+
+
+WordPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ ÐŽÐ»Ñ ÐžÐŒÐ¿ÐŸÑÑÐžÑÐŸÐ²Ð°ÐœÐžÑ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ² Microsoft Word.
+
+
+XMLPlug.desc:ÐÑÐœÐŸÐ²ÐœÐŸÐ¹ ÐºÐ»Ð°ÑÑ Ð¿Ð»Ð°Ð³ÐžÐœÐŸÐ² XML.
+
+
+ZIPPlug.desc:ÐÐ»Ð°Ð³ÐžÐœ, ÐºÐŸÑÐŸÑÑÐ¹ ÐŸÐ±ÑÐ°Ð±Ð°ÑÑÐ²Ð°ÐµÑ ÑÐ¶Ð°ÑÑÐµ Ðž/ÐžÐ»Ðž Ð°ÑÑ
+ÐžÐ²ÐžÑÐŸÐ²Ð°ÐœÐœÑÐµ Ð²Ñ
+ÐŸÐŽÐœÑÐµ ÑÐŸÑÐŒÐ°ÑÑ, ÑÐµÐºÑÑÐžÐµ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÐœÐœÑÐµ ÑÐŸÑÐŒÐ°ÑÑ Ðž ÑÐ°Ð¹Ð»Ñ Ñ ÑÐ°ÑÑÐžÑÐµÐœÐžÑÐŒÐž:\ngzip (.gz, .z, .tgz, .taz)\nbzip (.bz)\nbzip2 (.bz2)\nzip (.zip .jar)\ntar (.tar)\n\n Ð­ÑÐŸÑ Ð¿Ð»Ð°Ð³ÐžÐœ ÐŸÐ¿ÐžÑÐ°ÐµÑÑÑ ÐœÐ° ÑÐ»ÐµÐŽÑÑÑÐžÐµ Ð¿ÑÐžÑÑÑÑÑÐ²ÑÑÑÐžÐµ ÑÑÐžÐ»ÐžÑÑ (ÐµÑÐ»Ðž Ð¿ÑÑÐ°ÑÑÑÑ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÑÑ ÑÐŸÐŸÑÐ²ÐµÑÑÑÐ²ÑÑÑÐžÐµ ÑÐŸÑÐŒÐ°ÑÑ):\ngunzip (ÐŽÐ»Ñ gzip)\nbunzip (ÐŽÐ»Ñ bzip)\nbunzip2 \nunzip (ÐŽÐ»Ñzip)\ntar (ÐŽÐ»Ñ tar).
+
+
+
+#
+# Perl module strings
+#
+
+classify.could_not_find_classifier:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐœÐ°Ð¹ÑÐž ÐºÐ»Ð°ÑÑÐžÑÐžÐºÐ°ÑÐŸÑ \"%s\"
+
+
+plugin.could_not_find_plugin:ÐÐšÐÐÐÐ: ÐÐµÐ²ÐŸÐ·ÐŒÐŸÐ¶ÐœÐŸ ÐœÐ°Ð¹ÑÐž Ð¿Ð»Ð°Ð³ÐžÐœ \"%s\"
+
+
+plugin.including_archive:Ð²ÐºÐ»ÑÑÐµÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ 1 Ð°ÑÑ
+ÐžÐ²Ð° ZIP/TAR. 
+
+
+plugin.including_archives:Ð²ÐºÐ»ÑÑÐµÐœÐžÐµ ÑÐŸÐŽÐµÑÐ¶Ð°ÐœÐžÑ  Ð°ÑÑ
+ÐžÐ²ÐŸÐ² %d ZIP/TAR 
+
+
+plugin.kill_file:ÐÐ±ÑÐ°Ð±ÐŸÑÐºÐ°, ÑÐœÐžÑÑÐŸÐ¶ÐµÐœÐœÐ°Ñ ÑÐ°Ð¹Ð»ÐŸÐŒ .kill.
+
+
+plugin.n_considered:%d ÐŽÐŸÐºÑÐŒÐµÐœÑÑ, Ð¿ÑÐµÐŽÐœÐ°Ð·ÐœÐ°ÑÐµÐœÐœÑÐµ ÐŽÐ»Ñ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐž
+
+
+plugin.n_included:%d Ð±ÑÐ»Ðž ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÐœÑ Ðž Ð²ÐºÐ»ÑÑÐµÐœÑ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ
+
+
+plugin.n_rejected:%d Ð±ÑÐ»Ðž ÐŸÑÐºÐ»ÐŸÐœÐµÐœÑ
+
+
+plugin.n_unrecognised:%d Ð·ÐŽÐµÑÑ ÐœÐµÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°ÐœÐŸ
+
+
+plugin.no_plugin_could_process:ÐÐ ÐÐÐ£ÐÐ ÐÐÐÐÐÐÐ: ÐÐžÐºÐ°ÐºÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÑ ÐœÐµ ÑÐŒÐŸÐ³Ð»Ðž ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÑÑ %s
+
+
+plugin.no_plugin_could_recognise:ÐÐÐÐÐÐÐÐ: ÐÐµÑ Ð¿Ð»Ð°Ð³ÐžÐœÐ° ÐºÐŸÑÐŸÑÑÐ¹ ÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°ÐµÑ %s
+
+
+plugin.no_plugin_could_process_this_file:ÐœÐžÐºÐ°ÐºÐžÐµ Ð¿Ð»Ð°Ð³ÐžÐœÑ ÐœÐµ ÑÐŒÐŸÐ³Ð»Ðž  ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°ÑÑ ÑÑÐŸÑ ÑÐ°Ð¹Ð»
+
+
+plugin.no_plugin_could_recognise_this_file:ÐœÐµÑ Ð¿Ð»Ð°Ð³ÐžÐœÐ° ÐºÐŸÑÐŸÑÑÐ¹ ÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°ÐµÑ ÑÑÐŸÑ ÑÐ°Ð¹Ð»
+
+
+plugin.one_considered:1 ÐŽÐŸÐºÑÐŒÐµÐœÑ Ð¿ÑÐµÐŽÐœÐ°Ð·ÐœÐ°ÑÐ°Ð»ÑÑ ÐŽÐ»Ñ ÐŸÐ±ÑÐ°Ð±ÐŸÑÐºÐž
+
+
+plugin.one_included:1 Ð±ÑÐ» ÐŸÐ±ÑÐ°Ð±ÐŸÑÐ°Ðœ Ðž Ð²ÐºÐ»ÑÑÐµÐœ Ð² ÐºÐŸÐ»Ð»ÐµÐºÑÐžÑ
+
+
+plugin.one_rejected:1 Ð±ÑÐ» ÐŸÑÐºÐ»ÐŸÐœÐµÐœ
+
+
+plugin.one_unrecognised:1 Ð±ÑÐ» ÐœÐµ ÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°Ðœ
+
+plugin.see_faillog:Ð¡ÐŒ. %s ÐŽÐ»Ñ ÑÐ¿ÐžÑÐºÐ° ÐœÐµÑÐ°ÑÐ¿ÐŸÐ·ÐœÐ°ÐœÐœÑÑ
+  Ðž/ÐžÐ»Ðž ÐŸÑÐºÐ»ÐŸÐœÐµÐœÐœÑÑ
+ ÐŽÐŸÐºÑÐŒÐµÐœÑÐŸÐ²
+
+
+PrintUsage.default:ÐÐŸ ÑÐŒÐŸÐ»ÑÐ°ÐœÐžÑ
+
+
+PrintUsage.required:Ð¢Ð ÐÐÐ£ÐÐÐ«Ð
+
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/textcat.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/textcat.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/textcat.pm	(revision 10506)
@@ -0,0 +1,149 @@
+###########################################################################
+#
+# textcat.pm -- Identify the language of a piece of text
+#
+#
+# This file is based on TextCat version 1.08 by Gertjan van Noord
+# Copyright (C) 1997 Gertjan van Noord (vannoord@let.rug.nl)
+# TextCat is available from: http://odur.let.rug.nl/~vannoord/TextCat 
+#
+# It was modified by Gordon Paynter (gwp@cs.waikato.ac.nz) and turned
+# into a package for use in Greenstone digital library system.  Most of
+# the modifications consist of commenting out or deleting functionality
+# I don't need.  
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package textcat;
+
+# OPTIONS
+my $model_dir = $ENV{'GSDLHOME'} . "/perllib/textcat";
+
+my $opt_f = 1;                # Ngrams which occur <= this number of times are removed
+my $opt_t = 400;              # topmost number of ngrams that should be used
+my $opt_u = 1.05;             # how much worse result must be before it is ignored
+
+my $non_word_characters = '0-9\s';
+
+sub new {
+    my $class = shift (@_);
+    my $self = {};
+
+    # open directory to find which languages are supported
+    opendir DIR, "$model_dir" or die "directory $model_dir: $!\n";
+    my @languages = sort(grep { s/\.lm// && -r "$model_dir/$_.lm" } readdir(DIR));
+    closedir DIR;
+    @languages or die "sorry, can't read any language models from $model_dir\n" .
+	"language models must reside in files with .lm ending\n";
+
+    # load model and count for each language.
+    foreach my $language (@languages) {
+	my %ngram=();
+	my $rang=1;
+	open(LM, "$model_dir/$language.lm") || die "cannot open $language.lm: $!\n";
+	while (<LM>) {
+	    chomp;
+	    # only use lines starting with appropriate character. Others are ignored.
+	    if (/^[^$non_word_characters]+/o) {
+		$self->{'ngrams'}->{$language}->{$&} = $rang++;
+	    } 
+	}
+	close(LM);
+    }
+
+    $self->{'languages'} = \@languages;
+    return bless $self, $class;
+}
+
+
+
+# CLASSIFICATION
+#
+# What language is a text string?
+#   Input:  text string
+#   Output: array of language names
+
+sub classify {
+    my ($self, $inputref)=@_;
+    my %results = ();
+    my $maxp = $opt_t;
+
+    # create ngrams for input.
+    my $unknown = $self->create_lm($inputref);
+
+    foreach my $language (@{$self->{'languages'}}) {
+    
+	# compare language model with input ngrams list
+	my ($i,$p)=(0,0);
+	while ($i < scalar (@$unknown)) {
+	    if (defined ($self->{'ngrams'}->{$language}->{$unknown->[$i]})) {
+		$p=$p+abs($self->{'ngrams'}->{$language}->{$unknown->[$i]}-$i);
+	    } else { 
+		$p=$p+$maxp; 
+	    }
+	    ++$i;
+	}
+	$results{$language} = $p;
+    }
+
+    my @results = sort { $results{$a} <=> $results{$b} } keys %results;
+    my $a = $results{$results[0]};
+  
+    my @answers=(shift(@results));
+    while (@results && $results{$results[0]} < ($opt_u *$a)) {
+	@answers=(@answers,shift(@results));
+    }
+
+    return \@answers;
+}
+
+sub create_lm {
+    # $ngram contains reference to the hash we build
+    # then add the ngrams found in each word in the hash
+    my ($self, $textref) = @_;  
+    
+    my $ngram = {};
+
+    foreach my $word (split(/[$non_word_characters]+/, $$textref)) {
+	$word = "_" . $word . "_";
+	my $len = length($word);
+	my $flen=$len;
+	my $i;
+
+	for ($i=0; $i<$flen; $i++) {
+	    $ngram->{substr($word,$i,5)}++ if $len > 4;
+	    $ngram->{substr($word,$i,4)}++ if $len > 3;
+	    $ngram->{substr($word,$i,3)}++ if $len > 2;
+	    $ngram->{substr($word,$i,2)}++ if $len > 1;
+	    $ngram->{substr($word,$i,1)}++;
+	    $len--;
+	}
+    }
+
+    map { if ($ngram->{$_} <= $opt_f) { delete $ngram->{$_}; }
+      } keys %$ngram;
+  
+    # sort the ngrams, and spit out the $opt_t frequent ones.
+    # adding  `or $a cmp $b' in the sort block makes sorting five
+    # times slower..., although it would be somewhat nicer (unique result)
+    my @sorted = sort { $ngram->{$b} <=> $ngram->{$a} } keys %$ngram;
+    splice(@sorted,$opt_t) if (@sorted > $opt_t); 
+    return \@sorted;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/unbuildutil.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/unbuildutil.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/unbuildutil.pm	(revision 10506)
@@ -0,0 +1,48 @@
+###########################################################################
+#
+# unbuildutil.pm -- common methods for the two unbuilding scripts
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package unbuildutil;
+
+sub read_gdbm {
+    my ($filename, $infodb) = @_;
+
+    open (PIPEIN, "db2txt \"$filename\" |") || die "couldn't open pipe from db2txt\n";
+    my $line = ""; my $key = ""; my $value = "";
+    while (defined ($line = <PIPEIN>)) {
+	if ($line =~ /^\[([^\]]+)\]$/) {
+	    $key = $1;
+	} elsif ($line =~ /^-{70}$/) {
+	    $infodb->{$key} = $value;
+	    #print STDERR "adding key $key, value $value\n";
+	    $value = "";
+	    $key = "";
+	} else {
+	    $value .= $line;
+	}
+    }
+    close PIPEIN;
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/unicode.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/unicode.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/unicode.pm	(revision 10506)
@@ -0,0 +1,568 @@
+###########################################################################
+#
+# unicode.pm --
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999-2004 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+# useful functions for dealing with Unicode
+
+# Unicode strings are stored as arrays of scalars as perl 
+# lacks characters are 8-bit (currently)
+
+package unicode;
+
+eval {require bytes};
+
+use encodings;
+use util;
+
+# ascii2unicode takes an (extended) ascii string (ISO-8859-1)
+# and returns a unicode array.
+sub ascii2unicode {
+    my ($in) = @_;
+    my $out = [];
+
+    my $i = 0;
+    my $len = length($in);
+    while ($i < $len) {
+	push (@$out, ord(substr ($in, $i, 1)));	
+	$i++;
+    }
+
+    return $out;
+}
+
+# ascii2utf8 takes a reference to an (extended) ascii string and returns a
+# UTF-8 encoded string. This is just a faster version of
+# "&unicode2utf8(&ascii2unicode($str));"
+# "Extended ascii" really means "iso_8859_1"
+sub ascii2utf8 {
+    my ($in) = @_;
+    my $out = "";
+
+    if (!defined($in)|| !defined($$in)) {
+	return $out;
+    }
+
+    my ($c);
+    my $i = 0;
+    my $len = length($$in);
+    while ($i < $len) {
+	$c = ord (substr ($$in, $i, 1));
+	if ($c < 0x80) {
+	    # ascii character
+	    $out .= chr ($c);
+
+	} else {
+	    # extended ascii character
+	    $out .= chr (0xc0 + (($c >> 6) & 0x1f));
+	    $out .= chr (0x80 + ($c & 0x3f));
+	}
+	$i++;
+    }
+
+    return $out;
+}
+
+# unicode2utf8 takes a unicode array as input and encodes it
+# using utf-8
+sub unicode2utf8 {
+    my ($in) = @_;
+    my $out = "";
+    
+    foreach my $num (@$in) {
+	next unless defined $num;
+	if ($num < 0x80) {
+	    $out .= chr ($num);
+
+	} elsif ($num < 0x800) {
+	    $out .= chr (0xc0 + (($num >> 6) & 0x1f));
+	    $out .= chr (0x80 + ($num & 0x3f));
+
+	} elsif ($num < 0xFFFF) {
+	    $out .= chr (0xe0 + (($num >> 12) & 0xf));
+	    $out .= chr (0x80 + (($num >> 6) & 0x3f));
+	    $out .= chr (0x80 + ($num & 0x3f));
+
+	} else {
+	    # error, don't encode anything
+	    die;
+	}
+    }
+    return $out;
+}
+
+# utf82unicode takes a utf-8 string and produces a unicode
+# array
+sub utf82unicode {
+    my ($in) = @_;
+    my $out = [];
+
+    my $i = 0;
+    my ($c1, $c2, $c3);
+    my $len = length($in);
+    while ($i < $len) {
+	if (($c1 = ord(substr ($in, $i, 1))) < 0x80) {
+	    # normal ascii character
+	    push (@$out, $c1);
+
+	} elsif ($c1 < 0xc0) {
+	    # error, was expecting the first byte of an
+	    # encoded character. Do nothing.
+
+	} elsif ($c1 < 0xe0 && $i+1 < $len) {
+	    # an encoded character with two bytes
+	    $c2 = ord (substr ($in, $i+1, 1));
+	    if ($c2 >= 0x80 && $c2 < 0xc0) {
+		# everything looks ok
+		push (@$out, ((($c1 & 0x1f) << 6) +
+		      ($c2 & 0x3f)));
+		$i++; # gobbled an extra byte
+	    }
+
+	} elsif ($c1 < 0xf0 && $i+2 < $len) {
+	    # an encoded character with three bytes
+	    $c2 = ord (substr ($in, $i+1, 1));
+	    $c3 = ord (substr ($in, $i+2, 1));
+	    if ($c2 >= 0x80 && $c2 < 0xc0 &&
+		$c3 >= 0x80 && $c3 < 0xc0) {
+		# everything looks ok
+		push (@$out, ((($c1 & 0xf) << 12) +
+		      (($c2 & 0x3f) << 6) +
+		      ($c3 & 0x3f)));
+
+		$i += 2; # gobbled an extra two bytes
+	    }
+
+	} else {
+	    # error, only decode Unicode characters not full UCS.
+	    # Do nothing.
+	}
+
+	$i++;
+    }
+
+    return $out;
+}
+
+# unicode2ucs2 takes a unicode array and produces a UCS-2
+# unicode string (every two bytes forms a unicode character)
+sub unicode2ucs2 {
+    my ($in) = @_;
+    my $out = "";
+
+    foreach my $num (@$in) {
+	$out .= chr (($num & 0xff00) >> 8);
+	$out .= chr ($num & 0xff);
+    }
+
+    return $out;
+}
+
+# ucs22unicode takes a UCS-2 string and produces a unicode array
+sub ucs22unicode {
+    my ($in) = @_;
+    my $out = [];
+
+    my $i = 0;
+    my $len = length ($in);
+    while ($i+1 < $len) {
+	push (@$out, ord (substr($in, $i, 1)) << 8 +
+	      ord (substr($in, $i+1, 1)));
+
+	$i ++;
+    }
+
+    return $out;
+}
+
+# takes a reference to a string and returns a reference to a unicode array
+sub convert2unicode {
+    my ($encoding, $textref) = @_;
+
+    if (!defined $encodings::encodings->{$encoding}) {
+	print STDERR "unicode::convert2unicode: ERROR: Unsupported encoding ($encoding)\n";
+	return [];
+    }
+
+    my $encodename = "$encoding-unicode";
+    my $enc_info = $encodings::encodings->{$encoding};
+    my $mapfile = &util::filename_cat($ENV{'GSDLHOME'}, "mappings",
+				      "to_uc", $enc_info->{'mapfile'});
+    if (!&loadmapencoding ($encodename, $mapfile)) {
+	print STDERR "unicode: ERROR - could not load encoding $encodename\n";
+	return [];
+    }
+    
+    if (defined $enc_info->{'converter'}) {
+	my $converter = $enc_info->{'converter'};
+	return &$converter ($encodename, $textref);
+    }
+
+    if ($unicode::translations{$encodename}->{'count'} == 1) {
+	return &singlebyte2unicode ($encodename, $textref);
+    } else {
+	return &doublebyte2unicode ($encodename, $textref);
+    }
+}
+
+# singlebyte2unicode converts simple 8 bit encodings where characters below
+# 0x80 are normal ascii characters and the rest are decoded using the
+# appropriate mapping files.
+#
+# Examples of encodings that may be converted using singlebyte2unicode are
+# the iso-8859 and windows-125* series.
+sub singlebyte2unicode {
+    my ($encodename, $textref) = @_;
+
+    my @outtext = ();
+    my $len = length($$textref);
+    my ($c);
+    my $i = 0;
+
+    while ($i < $len) {
+	if (($c = ord(substr($$textref, $i, 1))) < 0x80) {
+	    # normal ascii character
+	    push (@outtext, $c);
+	} else {
+	    $c = &transchar ($encodename, $c);
+	    # put a black square if cannot translate
+	    $c = 0x25A1 if $c == 0;
+	    push (@outtext, $c);
+	}
+	$i ++;
+    }
+    return \@outtext;
+}
+
+# doublebyte2unicode converts simple two byte encodings where characters
+# below code point 0x80 are single-byte characters and the rest are
+# double-byte characters.
+#
+# Examples of encodings that may be converted using doublebyte2unicode are
+# CJK encodings like GB encoded Chinese and UHC Korean.
+#
+# Note that no error checking is performed to make sure that the input text
+# is valid for the given encoding.
+#
+# Also, encodings that may contain characters of more than two bytes are
+# not supported (any EUC encoded text may in theory contain 3-byte
+# characters but in practice only one and two byte characters are used).
+sub doublebyte2unicode {
+    my ($encodename, $textref) = @_;    
+    
+    my @outtext = ();
+    my $len = length($$textref);
+    my ($c1, $c2);
+    my $i = 0;
+
+    while ($i < $len) {
+	if (($c1 = ord(substr($$textref, $i, 1))) >= 0x80) {
+	    if ($i+1 < $len) {
+		# double-byte character
+		$c2 = ord(substr($$textref, $i+1, 1));
+		my $c = &transchar ($encodename, ($c1 << 8) | $c2);
+		# put a black square if cannot translate
+		$c = 0x25A1 if $c == 0;
+		push (@outtext, $c);
+		$i += 2;
+		
+	    } else {
+		# error
+		print STDERR "unicode: ERROR missing second half of double-byte character\n";
+		$i++;
+	    }
+	    
+	} else {
+	    # single-byte character
+	    push (@outtext, $c1);
+	    $i++;
+	}
+    }
+    return \@outtext;
+}
+
+# Shift-JIS to unicode
+# We can't use doublebyte2unicode for Shift-JIS because it uses some
+# single-byte characters above code point 0x80 (i.e. half-width katakana
+# characters in the range 0xA1-0xDF)
+sub shiftjis2unicode {
+    my ($encodename, $textref) = @_;
+    
+    my @outtext = ();
+    my $len = length($$textref);
+    my ($c1, $c2);
+    my $i = 0;
+
+    while ($i < $len) {
+	$c1 = ord(substr($$textref, $i, 1));
+
+	if (($c1 >= 0xA1 && $c1 <= 0xDF) || $c1 == 0x5c || $c1 == 0x7E) {
+	    # Single-byte half-width katakana character or
+	    # JIS Roman yen or overline characters
+	    my $c = &transchar ($encodename, $c1);
+	    # - put a black square if cannot translate
+	    $c = 0x25A1 if $c == 0;
+	    push (@outtext, $c);
+	    $i++;
+
+	} elsif ($c1 < 0x80) {
+	    # ASCII
+	    push (@outtext, $c1);
+	    $i ++;
+
+	} elsif ($c1 < 0xEF) {
+	    if ($i+1 < $len) {
+		$c2 = ord(substr($$textref, $i+1, 1));
+		if (($c2 >= 0x40 && $c2 <= 0x7E) || ($c2 >= 0x80 && $c2 <= 0xFC)) {
+		    # Double-byte shift-jis character
+		    my $c = &transchar ($encodename, ($c1 << 8) | $c2);
+		    # put a black square if cannot translate
+		    $c = 0x25A1 if $c == 0;
+		    push (@outtext, $c);
+		} else {
+		    # error
+		    print STDERR "unicode: ERROR Invalid Shift-JIS character\n";
+		}
+		$i += 2;
+	    } else {
+		# error
+		print STDERR "unicode: ERROR missing second half of Shift-JIS character\n";
+		$i ++;
+	    }
+	} else {
+	    # error
+	    print STDERR "unicode: ERROR Invalid Shift-JIS character\n";
+	    $i ++;
+	}
+    }
+    return \@outtext;
+}
+
+sub transchar {
+    my ($encoding, $from) = @_;
+    my $high = ($from / 256) % 256;
+    my $low = $from % 256;
+
+    return 0 unless defined $unicode::translations{$encoding};
+
+    my $block = $unicode::translations{$encoding}->{'map'};
+
+    if (ref ($block->[$high]) ne "ARRAY") {
+	return 0;
+    }
+    return $block->[$high]->[$low];
+}
+
+# %translations is of the form:
+#
+# encodings{encodingname-encodingname}->{'map'}->blocktranslation
+# blocktranslation->[[0-255],[256-511], ..., [65280-65535]]
+#
+# Any of the top translation blocks can point to an undefined
+# value. This data structure aims to allow fast translation and 
+# efficient storage.
+%unicode::translations = ();
+
+# @array256 is used for initialisation, there must be
+# a better way...
+# What about this?: @array256 = (0) x 256;
+@unicode::array256 = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+	     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+
+# returns 1 if successful, 0 if unsuccessful
+sub loadmapencoding {
+    my ($encoding, $mapfile) = @_;
+    
+    # check to see if the encoding has already been loaded
+    return 1 if (defined $unicode::translations{$encoding});
+
+    if (! -r $mapfile || -d $mapfile) {
+	return 0;
+    }
+    return 0 unless open (MAPFILE, $mapfile);
+    binmode (MAPFILE);
+
+    $unicode::translations{$encoding} = {'map' => [@unicode::array256], 'count' => 0};
+    my $block = $unicode::translations{$encoding};
+
+    my ($in,$i,$j);
+    while (1) {
+	my $ret=read(MAPFILE, $in, 1);
+	if (!defined($ret)) { # error
+	    print STDERR "unicode.pm: error reading mapfile: $!\n";
+	    last;
+	}
+	if ($ret != 1) { last }
+	$i = unpack ("C", $in);
+	$block->{'map'}->[$i] = [@unicode::array256];
+	for ($j=0; $j<256 && read(MAPFILE, $in, 2)==2; $j++) {
+	    my ($n1, $n2) = unpack ("CC", $in);
+	    $block->{'map'}->[$i]->[$j] = ($n1*256) + $n2;
+	}
+	$block->{'count'} ++;
+    }
+
+    close (MAPFILE);
+}
+
+# unicode2singlebyte converts unicode to simple 8 bit encodings where
+# characters below 0x80 are normal ascii characters and the rest are encoded
+# using the appropriate mapping files.
+#
+# Examples of encodings that may be converted using unicode2singlebyte are
+# the iso-8859 and windows-125* series, KOI8-R (Russian), and the Kazakh encoding.
+sub unicode2singlebyte {
+    my ($uniref, $encoding) = @_;
+
+    my $outtext = "";
+    my $encodename = "unicode-$encoding";
+
+    if (!exists $encodings::encodings->{$encoding}) {
+	print STDERR "unicode.pm: ERROR - unsupported encoding "
+	    . "'$encoding' requested\n";
+	return "";
+    }
+
+    my $enc_info = $encodings::encodings->{$encoding};
+    my $mapfile = &util::filename_cat($ENV{'GSDLHOME'}, "mappings",
+				      "from_uc", $enc_info->{'mapfile'});
+    if (!&loadmapencoding ($encodename, $mapfile)) {
+	print STDERR "unicode: ERROR - could not load encoding $encodename\n";
+	return "";
+    }
+    
+    foreach my $c (@$uniref) {
+	if ($c < 0x80) {
+	    # normal ascii character
+	    $outtext .= chr($c);
+	} else {
+	    # extended ascii character
+	    $c = &transchar ($encodename, $c);
+
+	    # put a question mark if cannot translate
+	    if ($c == 0) {
+		$outtext .= "?";
+	    } else {
+		$outtext .= chr($c);
+	    }
+	}
+    }
+    return $outtext;
+}
+
+
+# this makes sure that the referenced input string is utf8 encoded, and
+# will change/remove bytes that aren't.
+# returns 0 if the text was already utf8, or 1 if text modified to become utf8
+sub ensure_utf8 {
+    my $stringref=shift;
+
+    if (!defined($stringref) || ref($stringref) ne 'SCALAR') {
+	return $stringref;
+    }
+
+    my $value=$$stringref;
+
+    my $non_utf8_found = 0;
+    $value =~ m/^/g; # to set \G
+    while ($value =~ m!\G.*?([\x80-\xff]+)!sg) {
+	my $highbytes=$1;
+	my $highbyteslength=length($highbytes);
+	# make sure this block of high bytes is utf-8
+	$highbytes =~ /^/g; # set pos()
+	my $byte_replaced = 0;
+	while ($highbytes =~
+		m!\G (?: [\xc0-\xdf][\x80-\xbf]   | # 2 byte utf-8
+			[\xe0-\xef][\x80-\xbf]{2} | # 3 byte
+			[\xf0-\xf7][\x80-\xbf]{3} | # 4 byte
+			[\xf8-\xfb][\x80-\xbf]{4} | # 5 byte
+			[\xfc-\xfd][\x80-\xbf]{5} | # 6 byte
+			)*([\x80-\xff])? !xg
+		) {
+	    # this highbyte is "out-of-place" for valid utf-8
+	    my $badbyte=$1;
+	    if (!defined $badbyte) {next} # hit end of string
+	    my $pos=pos($highbytes);
+	    # replace bad byte. assume iso-8859-1 -> utf-8
+	    # ascii2utf8 does "extended ascii"... ie iso-8859-1
+	    my $replacement=&unicode::ascii2utf8(\$badbyte);
+	    substr($highbytes, $pos-1, 1, $replacement);
+	    # update the position to continue searching (for \G)
+	    pos($highbytes) = $pos+length($replacement)-1;
+	    $byte_replaced = 1;
+	}
+	if ($byte_replaced) {
+	    # replace this block of high bytes in the $value
+	    $non_utf8_found = 1;
+	    my $replength=length($highbytes); # we've changed the length
+	    my $textpos=pos($value); # pos at end of last match
+	    # replace bad bytes with good bytes
+	    substr($value, $textpos-$highbyteslength,
+			    $highbyteslength, $highbytes);
+	    # update the position to continue searching (for \G)
+	    pos($value)=$textpos+($replength-$highbyteslength)+1;
+	}
+    }
+
+    $$stringref = $value;
+    return $non_utf8_found;
+}
+
+
+sub substr
+{
+    my ($utf8_string, $offset, $length) = @_;
+
+    my @unicode_string = @{&utf82unicode($utf8_string)};
+    my $unicode_string_length = scalar(@unicode_string);
+
+    my $substr_start = $offset;
+    if ($substr_start >= $unicode_string_length) {
+	return "";
+    }
+
+    my $substr_end = $offset + $length - 1;
+    if ($substr_end >= $unicode_string_length) {
+	$substr_end = $unicode_string_length - 1;
+    }
+
+    my @unicode_substring = @unicode_string[$substr_start..$substr_end];
+    return &unicode2utf8(\@unicode_substring);
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/util.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/util.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/util.pm	(revision 10506)
@@ -0,0 +1,708 @@
+###########################################################################
+#
+# util.pm -- various useful utilities
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+package util;
+
+use File::Copy;
+use File::Basename;
+
+
+# removes files (but not directories)
+sub rm {
+    my (@files) = @_;
+    my @filefiles = ();
+
+    # make sure the files we want to delete exist 
+    # and are regular files
+    foreach my $file (@files) {
+	if (!-e $file) {
+	    print STDERR "util::rm $file does not exist\n";
+	} elsif ((!-f $file) && (!-l $file)) {
+	    print STDERR "util::rm $file is not a regular (or symbolic) file\n";
+	} else {
+	    push (@filefiles, $file);
+	}
+    }
+    
+    # remove the files
+    my $numremoved = unlink @filefiles;
+
+    # check to make sure all of them were removed
+    if ($numremoved != scalar(@filefiles)) {
+	print STDERR "util::rm Not all files were removed\n";
+    }
+}
+
+
+
+# recursive removal
+sub filtered_rm_r {
+    my ($files,$file_accept_re,$file_reject_re) = @_;
+
+    my @files_array = (ref $files eq "ARRAY") ? @$files : ($files);
+
+    # recursively remove the files
+    foreach my $file (@files_array) {
+	$file =~ s/[\/\\]+$//; # remove trailing slashes
+	
+	if (!-e $file) {
+	    print STDERR "util::filtered_rm_r $file does not exist\n";
+
+	} elsif ((-d $file) && (!-l $file)) { # don't recurse down symbolic link
+	    # get the contents of this directory
+	    if (!opendir (INDIR, $file)) {
+		print STDERR "util::filtered_rm_r could not open directory $file\n";
+	    } else {
+		my @filedir = grep (!/^\.\.?$/, readdir (INDIR));
+		closedir (INDIR);
+				
+		# remove all the files in this directory
+		map {$_="$file/$_";} @filedir;
+		&filtered_rm_r (\@filedir,$file_accept_re,$file_reject_re);
+
+		if (!defined $file_accept_re && !defined $file_reject_re) {
+		    # remove this directory
+		    if (!rmdir $file) {
+			print STDERR "util::filtered_rm_r couldn't remove directory $file\n";
+		    }
+		}
+	    }
+	} else {
+	    next if (defined $file_reject_re && ($file =~ m/$file_reject_re/));
+
+	    if ((!defined $file_accept_re) || ($file =~ m/$file_accept_re/)) {
+		# remove this file	
+		&rm ($file);
+	    }
+	}
+    }
+}
+
+
+# recursive removal
+sub rm_r {
+    my (@files) = @_;
+    
+    # use the more general (but reterospectively written function
+    # filtered_rm_r function()
+
+    filtered_rm_r(\@files,undef,undef); # no accept or reject expressions
+}
+
+
+
+
+# moves a file or a group of files
+sub mv {
+    my $dest = pop (@_);
+    my (@srcfiles) = @_;
+
+    # remove trailing slashes from source and destination files
+    $dest =~ s/[\\\/]+$//;
+    map {$_ =~ s/[\\\/]+$//;} @srcfiles;
+
+    # a few sanity checks
+    if (scalar (@srcfiles) == 0) {
+	print STDERR "util::mv no destination directory given\n";
+	return;
+    } elsif ((scalar (@srcfiles) > 1) && (!-d $dest)) {
+	print STDERR "util::mv if multiple source files are given the ".
+	    "destination must be a directory\n";
+	return;
+    }
+
+    # move the files
+    foreach my $file (@srcfiles) {
+	my $tempdest = $dest;
+	if (-d $tempdest) {
+	    my ($filename) = $file =~ /([^\\\/]+)$/;
+	    $tempdest .= "/$filename";
+	}
+	if (!-e $file) {
+	    print STDERR "util::mv $file does not exist\n";
+	} else {
+	    rename ($file, $tempdest);
+	}
+    }
+}
+
+
+# copies a file or a group of files
+sub cp {
+    my $dest = pop (@_);
+    my (@srcfiles) = @_;
+
+    # remove trailing slashes from source and destination files
+    $dest =~ s/[\\\/]+$//;
+    map {$_ =~ s/[\\\/]+$//;} @srcfiles;
+
+    # a few sanity checks
+    if (scalar (@srcfiles) == 0) {
+	print STDERR "util::cp no destination directory given\n";
+	return;
+    } elsif ((scalar (@srcfiles) > 1) && (!-d $dest)) {
+	print STDERR "util::cp if multiple source files are given the ".
+	    "destination must be a directory\n";
+	return;
+    }
+
+    # copy the files
+    foreach my $file (@srcfiles) {
+	my $tempdest = $dest;
+	if (-d $tempdest) {
+	    my ($filename) = $file =~ /([^\\\/]+)$/;
+	    $tempdest .= "/$filename";
+	}
+	if (!-e $file) {
+	    print STDERR "util::cp $file does not exist\n";
+	} elsif (!-f $file) {
+	    print STDERR "util::cp $file is not a plain file\n";
+	} else {
+	    &File::Copy::copy ($file, $tempdest);
+	}
+    }
+}
+
+
+
+# recursively copies a file or group of files
+# syntax: cp_r (sourcefiles, destination directory)
+# destination must be a directory - to copy one file to
+# another use cp instead
+sub cp_r {
+    my $dest = pop (@_);
+    my (@srcfiles) = @_;
+
+    # a few sanity checks
+    if (scalar (@srcfiles) == 0) {
+	print STDERR "util::cp_r no destination directory given\n";
+	return;
+    } elsif (-f $dest) {
+	print STDERR "util::cp_r destination must be a directory\n";
+	return;
+    }
+    
+    # create destination directory if it doesn't exist already
+    if (! -d $dest) {
+	my $store_umask = umask(0002);
+	mkdir ($dest, 0777);
+	umask($store_umask);
+    } 
+
+    # copy the files
+    foreach my $file (@srcfiles) {
+
+	if (!-e $file) {
+	    print STDERR "util::cp_r $file does not exist\n";
+
+	} elsif (-d $file) {
+	    # make the new directory
+	    my ($filename) = $file =~ /([^\\\/]*)$/;
+	    $dest = &util::filename_cat ($dest, $filename);
+	    my $store_umask = umask(0002);
+	    mkdir ($dest, 0777);
+	    umask($store_umask);
+
+	    # get the contents of this directory
+	    if (!opendir (INDIR, $file)) {
+		print STDERR "util::cp_r could not open directory $file\n";
+	    } else {
+		my @filedir = readdir (INDIR);
+		closedir (INDIR);
+		foreach my $f (@filedir) {
+		    next if $f =~ /^\.\.?$/;
+		    # copy all the files in this directory
+		    my $ff = &util::filename_cat ($file, $f); 
+		    &cp_r ($ff, $dest);
+		}
+	    }
+
+	} else {
+	    &cp($file, $dest);
+	}
+    }
+}
+
+
+sub mk_dir {
+    my ($dir) = @_;
+
+    my $store_umask = umask(0002);
+    my $mkdir_ok = mkdir ($dir, 0777);
+    umask($store_umask);
+    
+    if (!$mkdir_ok) 
+    {
+	print STDERR "util::mk_dir could not create directory $dir\n";
+	return;
+    }
+}
+
+# in case anyone cares - I did some testing (using perls Benchmark module)
+# on this subroutine against File::Path::mkpath (). mk_all_dir() is apparently
+# slightly faster (surprisingly) - Stefan.
+sub mk_all_dir {
+    my ($dir) = @_;
+
+    # use / for the directory separator, remove duplicate and
+    # trailing slashes
+    $dir=~s/[\\\/]+/\//g; 
+    $dir=~s/[\\\/]+$//;
+
+    # make sure the cache directory exists
+    my $dirsofar = "";
+    my $first = 1;
+    foreach my $dirname (split ("/", $dir)) {
+	$dirsofar .= "/" unless $first;
+	$first = 0;
+
+	$dirsofar .= $dirname;
+
+	next if $dirname =~ /^(|[a-z]:)$/i;
+	if (!-e $dirsofar)
+	    {
+		my $store_umask = umask(0002);
+		my $mkdir_ok = mkdir ($dirsofar, 0777);
+		umask($store_umask);
+		if (!$mkdir_ok)
+		{
+		    print STDERR "util::mk_all_dir could not create directory $dirsofar\n";
+		    return;
+		}
+	    }
+    }
+}
+
+# make hard link to file if supported by OS, otherwise copy the file
+sub hard_link {
+    my ($src, $dest) = @_;
+
+    # remove trailing slashes from source and destination files
+    $src =~ s/[\\\/]+$//;
+    $dest =~ s/[\\\/]+$//;
+
+    # a few sanity checks
+    if (-e $dest) {
+	# destination file already exists
+	return;
+    }
+    elsif (!-e $src) {
+	print STDERR "util::hard_link source file $src does not exist\n";
+	return 1;
+    }
+    elsif (-d $src) {
+	print STDERR "util::hard_link source $src is a directory\n";
+	return 1;
+    }
+
+    my $dest_dir = &File::Basename::dirname($dest);
+    mk_all_dir($dest_dir) if (!-e $dest_dir);
+
+    # link not supported on windows 9x
+    if (($ENV{'GSDLOS'} =~ /^windows$/i) && (Win32::FsType() !~ /^ntfs$/i)) {
+	&File::Copy::copy ($src, $dest);
+
+    } elsif (!link($src, $dest)) {
+	print STDERR "util::hard_link: unable to create hard link. ";
+	print STDERR " Attempting to copy file: $src -> $dest\n";
+	&File::Copy::copy ($src, $dest);
+    }
+    return 0;
+}
+
+# make soft link to file if supported by OS, otherwise copy file
+sub soft_link {
+    my ($src, $dest) = @_;
+
+    # remove trailing slashes from source and destination files
+    $src =~ s/[\\\/]+$//;
+    $dest =~ s/[\\\/]+$//;
+
+    # a few sanity checks
+    if (!-e $src) {
+	print STDERR "util::soft_link source file $src does not exist\n";
+	return 0;
+    }
+
+    my $dest_dir = &File::Basename::dirname($dest);
+    mk_all_dir($dest_dir) if (!-e $dest_dir);
+
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	# symlink not supported on windows
+	&File::Copy::copy ($src, $dest);
+
+    } elsif (!eval {symlink($src, $dest)}) {
+	print STDERR "util::soft_link: unable to create soft link.\n";
+	return 0;
+    }
+
+    return 1;
+}
+
+
+
+
+# updates a copy of a directory in some other part of the filesystem
+# verbosity settings are: 0=low, 1=normal, 2=high
+# both $fromdir and $todir should be absolute paths
+sub cachedir {
+    my ($fromdir, $todir, $verbosity) = @_;
+    $verbosity = 1 unless defined $verbosity;
+
+    # use / for the directory separator, remove duplicate and
+    # trailing slashes
+    $fromdir=~s/[\\\/]+/\//g; 
+    $fromdir=~s/[\\\/]+$//;
+    $todir=~s/[\\\/]+/\//g; 
+    $todir=~s/[\\\/]+$//;
+
+    &mk_all_dir ($todir);
+
+    # get the directories in ascending order
+    if (!opendir (FROMDIR, $fromdir)) {
+	print STDERR "util::cachedir could not read directory $fromdir\n";
+	return;
+    }
+    my @fromdir = grep (!/^\.\.?$/, sort(readdir (FROMDIR)));
+    closedir (FROMDIR);
+
+    if (!opendir (TODIR, $todir)) {
+	print STDERR "util::cacedir could not read directory $todir\n";
+	return;
+    }
+    my @todir = grep (!/^\.\.?$/, sort(readdir (TODIR)));
+    closedir (TODIR);
+
+    my $fromi = 0;
+    my $toi = 0;
+		    
+    while ($fromi < scalar(@fromdir) || $toi < scalar(@todir)) {
+#	print "fromi: $fromi toi: $toi\n";
+
+	# see if we should delete a file/directory
+	# this should happen if the file/directory
+	# is not in the from list or if its a different
+	# size, or has an older timestamp
+	if ($toi < scalar(@todir)) {
+	    if (($fromi >= scalar(@fromdir)) ||
+		($todir[$toi] lt $fromdir[$fromi] || 
+		 ($todir[$toi] eq $fromdir[$fromi] && 
+		  &differentfiles("$fromdir/$fromdir[$fromi]","$todir/$todir[$toi]",
+				  $verbosity)))) {
+
+		# the files are different
+		&rm_r("$todir/$todir[$toi]");
+		splice(@todir, $toi, 1); # $toi stays the same
+
+	    } elsif ($todir[$toi] eq $fromdir[$fromi]) {
+		# the files are the same
+		# if it is a directory, check its contents
+		if (-d "$todir/$todir[$toi]") {
+		    &cachedir ("$fromdir/$fromdir[$fromi]",
+			       "$todir/$todir[$toi]", $verbosity);
+		}
+
+		$toi++;
+		$fromi++;
+		next;
+	    }
+	}
+  
+	# see if we should insert a file/directory
+	# we should insert a file/directory if there
+	# is no tofiles left or if the tofile does not exist
+	if ($fromi < scalar(@fromdir) && ($toi >= scalar(@todir) || 
+					  $todir[$toi] gt $fromdir[$fromi])) {
+	    &cp_r ("$fromdir/$fromdir[$fromi]", "$todir/$fromdir[$fromi]");
+	    splice (@todir, $toi, 0, $fromdir[$fromi]);
+
+	    $toi++;
+	    $fromi++;
+	}
+    }
+}
+
+# this function returns -1 if either file is not found
+# assumes that $file1 and $file2 are absolute file names or
+# in the current directory
+# $file2 is allowed to be newer than $file1
+sub differentfiles {
+    my ($file1, $file2, $verbosity) = @_;
+    $verbosity = 1 unless defined $verbosity;
+
+    $file1 =~ s/\/+$//;
+    $file2 =~ s/\/+$//;
+    
+    my ($file1name) = $file1 =~ /\/([^\/]*)$/;
+    my ($file2name) = $file2 =~ /\/([^\/]*)$/;
+
+    return -1 unless (-e $file1 && -e $file2);
+    if ($file1name ne $file2name) {
+	print STDERR "filenames are not the same\n" if ($verbosity >= 2);
+	return 1;
+    }
+
+    my @file1stat = stat ($file1);
+    my @file2stat = stat ($file2);
+
+    if (-d $file1) {
+	if (! -d $file2) {
+	    print STDERR "one file is a directory\n" if ($verbosity >= 2);
+	    return 1;
+	}
+	return 0;
+    }
+
+    # both must be regular files
+    unless (-f $file1 && -f $file2) {
+	print STDERR "one file is not a regular file\n" if ($verbosity >= 2);
+	return 1;
+    }
+
+    # the size of the files must be the same
+    if ($file1stat[7] != $file2stat[7]) {
+	print STDERR "different sized files\n" if ($verbosity >= 2);
+	return 1;
+    }
+
+    # the second file cannot be older than the first
+    if ($file1stat[9] > $file2stat[9]) {
+	print STDERR "file is older\n" if ($verbosity >= 2);
+	return 1;
+    }
+
+    return 0;
+}
+
+
+sub get_tmp_filename {
+    my $tmpdir = filename_cat($ENV{'GSDLHOME'}, "tmp");
+    &mk_all_dir ($tmpdir) unless -e $tmpdir;
+
+    my $count = 1000;
+    my $rand = int(rand $count);
+    while (-e &filename_cat($tmpdir, "F$rand")) {
+	$rand = int(rand $count);
+	$count++;
+    }
+
+    return filename_cat($tmpdir, "F$rand");
+}
+
+
+sub filename_cat {
+    my $first_file = shift(@_);
+    my (@filenames) = @_;
+
+    # Check for empty first filename
+    if ($first_file =~ /\S/) {
+	unshift(@filenames, $first_file);
+    }
+
+    my $filename = join("/", @filenames);
+
+    # remove duplicate slashes and remove the last slash
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$filename =~ s/[\\\/]+/\\/g;
+    } else {
+	$filename =~ s/[\/]+/\//g; 
+	# DB: want a filename abc\de.html to remain like this
+    }
+    $filename =~ s/[\\\/]$//;
+
+    return $filename;
+}
+
+
+sub envvar_prepend {
+    my ($var,$val) = @_;
+
+    my $current_val = $ENV{$var};
+    
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$ENV{$var} .= "$val;$current_val";
+    }
+    else {
+	$ENV{$var} .= "$val:$current_val";
+    }
+}
+
+sub envvar_append {
+    my ($var,$val) = @_;
+
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$ENV{$var} .= ";$val";
+    }
+    else {
+	$ENV{$var} .= ":$val";
+    }
+}
+
+
+# returns the path of a file without the filename -- ie. the directory the file is in
+sub filename_head {
+    my $filename = shift(@_);
+
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$filename =~ s/[^\\\\]*$//;
+    }
+    else {
+	$filename =~ s/[^\\\/]*$//;
+    }
+
+    return $filename;
+}
+
+
+# returns 1 if filename1 and filename2 point to the same
+# file or directory
+sub filenames_equal {
+    my ($filename1, $filename2) = @_;
+
+    # use filename_cat to clean up trailing slashes and 
+    # multiple slashes
+    $filename1 = filename_cat ($filename1);
+    $filename2 = filename_cat ($filename2);
+
+    # filenames not case sensitive on windows
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	$filename1 =~ tr/[A-Z]/[a-z]/;
+	$filename2 =~ tr/[A-Z]/[a-z]/;
+    }
+    return 1 if $filename1 eq $filename2;
+    return 0;
+}
+
+sub filename_within_collection
+{
+    my ($filename) = @_;
+
+    my $collect_dir = $ENV{'GSDLCOLLECTDIR'};
+    
+    if (defined $collect_dir) {
+	my $dirsep = &util::get_dirsep();
+	if ($collect_dir !~ m/$dirsep$/) {
+	    $collect_dir .= $dirsep;
+	}
+	
+	$collect_dir =~ s/\\/\\\\/g; # escape DOS style file separator
+	
+	if ($filename =~ /^$collect_dir(.*)$/) {
+	    $filename = $1;
+	}
+    }
+    
+    return $filename;
+}
+
+
+sub get_dirsep {
+
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	return "\\";
+    } else {
+	return "\/";
+    }
+}
+
+sub get_os_dirsep {
+
+    if ($ENV{'GSDLOS'} =~ /^windows$/i) {
+	return "\\\\";
+    } else {
+	return "\\\/";
+    }
+}
+
+sub get_re_dirsep {
+
+    return "\\\\|\\\/";
+}
+
+
+# if this is running on windows we want binaries to end in
+# .exe, otherwise they don't have to end in any extension
+sub get_os_exe {
+    return ".exe" if $ENV{'GSDLOS'} =~ /^windows$/i;
+    return "";
+}
+
+
+# test to see whether this is a big or little endian machine
+sub is_little_endian {
+    return (ord(substr(pack("s",1), 0, 1)) == 1);
+}
+
+
+# will return the collection name if successful, "" otherwise
+sub use_collection {
+    my ($collection, $collectdir) = @_;
+
+    if (!defined $collectdir || $collectdir eq "") {
+	$collectdir = &filename_cat ($ENV{'GSDLHOME'}, "collect");
+    }
+
+    # get and check the collection
+    if (!defined($collection) || $collection eq "") {
+	if (defined $ENV{'GSDLCOLLECTION'}) {
+	    $collection = $ENV{'GSDLCOLLECTION'};
+	} else {
+	    print STDOUT "No collection specified\n";
+	    return "";
+	}
+    }
+    
+    if ($collection eq "modelcol") {
+	print STDOUT "You can't use modelcol.\n";
+	return "";
+    }
+
+    # make sure the environment variables GSDLCOLLECTION and GSDLCOLLECTDIR
+    # are defined
+    $ENV{'GSDLCOLLECTION'} = $collection unless defined $ENV{'GSDLCOLLECTION'};
+    $ENV{'GSDLCOLLECTDIR'} = &filename_cat ($collectdir, $collection);
+
+    # make sure this collection exists
+    if (!-e $ENV{'GSDLCOLLECTDIR'}) {
+	print STDOUT "Invalid collection ($collection).\n";
+	return "";
+    }
+
+    # everything is ready to go
+    return $collection;
+}
+
+sub hyperlink_text
+{
+    my ($text) = @_;
+    
+    $text =~ s/(http:\/\/[^\s]+)/<a href=\"$1\">$1<\/a>/mg;
+    $text =~ s/(^|\s+)(www\.(\w|\.)+)/<a href=\"http:\/\/$2\">$2<\/a>/mg;
+
+    return $text;
+}
+
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/perllib/webpageutil.pm
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/perllib/webpageutil.pm	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/perllib/webpageutil.pm	(revision 10506)
@@ -0,0 +1,24 @@
+package webpageutil;
+
+use ghtml;
+
+sub error_location
+{
+    my ($args,$text) = @_;
+
+    &ghtml::urlsafe($text);
+    my $mess_url = "$args->{'httpbuild'}&bca=mess&head=_headerror_";
+    print "Location: $mess_url&mess=$text\n\n";
+}
+
+sub status_location
+{
+    my ($args,$text,$tmpname,$bc1finished) = @_;
+
+    &ghtml::urlsafe($text);    
+    my $mess_url = "$args->{'httpbuild'}&bca=buildstatus";
+    $mess_url .= "&bc1tmpfilename=$tmpname&bc1finished=$bc1finished";
+    print "Location: $mess_url&mess=$text\n\n";
+}
+
+1;
Index: /tags/gsdl-2_61-distribution/gsdl/setup.bash
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/setup.bash	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/setup.bash	(revision 10506)
@@ -0,0 +1,183 @@
+# 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.
+gsdllang=""
+# encoding inputs and outputs
+gsdltoenc=""
+gsdlfromenc=""
+
+# see if the shell has any language environment variables set
+# see locale(7) manpage for this ordering.
+if test ! -z "$LC_ALL" ; then
+  gsdllang="$LC_ALL"
+elif test ! -z "$LANG"; then
+  gsdllang="$LANG"
+fi
+
+
+# note... all our output strings have the charset hard-coded, but
+# people may be using a different encoding in their terminal. LANG
+# strings look like "en_NZ.UTF-8".
+
+# Determine the requested output encoding
+case $gsdllang in
+  *.*)
+    gsdltoenc=`echo $gsdllang | sed 's/.*\.//'`
+    ;;
+esac
+
+# Our french and spanish strings are currently in iso-8859-1 encoding.
+case $gsdllang in
+  fr*|FR*)
+    gsdllang=fr
+    gsdlfromenc="iso-8859-1"
+  ;;
+  es*|ES*)
+    gsdllang=es
+    gsdlfromenc="iso-8859-1"
+  ;;
+  ru*|RU*)
+    gsdllang=ru
+    gsdlfromenc="koi8r"
+  ;;
+  *) # default
+    gsdllang=en
+    gsdlfromenc="iso-8859-1"
+  ;;
+esac  
+
+# "iconv" is the program for converting text between encodings.
+gsdliconv=`which iconv 2>/dev/null`
+if test $? -ne 0 || test ! -x "$gsdliconv" || test -z "$gsdlfromenc" || test -z "$gsdltoenc"; then
+# we can't convert encodings from some reason
+  gsdliconv="cat"
+else
+# add the encodings
+  gsdliconv="$gsdliconv -f $gsdlfromenc -t $gsdltoenc"
+fi
+
+# make sure we are sourced, and not run
+
+if test "$0" != "`echo $0 | sed s/setup\.bash//`" ; then
+# if $0 contains "setup.bash" 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
+  case "$gsdllang" in
+ "es")
+eval $gsdliconv <<EOF
+      Error: Asegúrese de compilar este guión, no de ejecutarlo. P. ej.:
+         $ source setup.bash
+      o
+         $ . ./setup.bash
+      no
+         $ ./setup.bash
+EOF
+  ;;
+  "fr")
+eval $gsdliconv <<EOF
+      Erreur: Assurez-vous de "sourcer" le script, plutôt que de l'exécuter. Ex:
+         $ source setup.bash
+      ou
+         $ . ./setup.bash
+      pas
+         $ ./setup.bash
+EOF
+  ;;
+  "ru")
+eval $gsdliconv <<EOF
+      ïÛÉÂËÁ: õÄÏÓÔÏ×ÅÒØÔÅÓØ × ÉÓÔÏÞÎÉËÅ ÜÔÏÇÏ ÓËÒÉÐÔÁ. îÅ ÉÓÐÏÌÎÑÊÔÅ ÅÇÏ.
+      îÁÐÒÉÍÅÒ:
+         $ source setup.bash
+      ÉÌÉ
+         $ . ./setup.bash
+      ÎÅÔ
+         $ ./setup.bash
+EOF
+  ;;
+  *)
+eval $gsdliconv <<EOF
+	Error: Make sure you source this script, not execute it. Eg:
+		$ source setup.bash
+	or
+		$ . ./setup.bash
+	not
+		$ ./setup.bash
+EOF
+  ;;
+  esac
+elif test -n "$GSDLHOME" ; then
+  case "$gsdllang" in
+  "es")
+    echo '¡Su ambiente ya está listo para Greenstone!' | eval $gsdliconv
+  ;;
+  "fr")
+    echo 'Votre environnement est déjà préparé pour Greenstone!' | eval $gsdliconv
+ ;;
+  "ru")
+    echo '÷ÁÛÅ ÏËÒÕÖÅÎÉÅ ÕÖÅ ÎÁÓÔÒÏÅÎÏ ÄÌÑ Greenstone!' | eval $gsdliconv
+  ;;
+  *)
+    echo 'Your environment is already set up for Greenstone!'
+  ;;
+  esac
+elif test ! -f setup.bash ; then
+  case "$gsdllang" in
+    "es")
+eval $gsdliconv <<EOF
+Usted debe compilar el guión desde el interior del directorio de inicio
+de Greenstone.
+EOF
+  ;;
+  "fr")
+echo 'Vous devez trouver la source du script dans le répertoire de base de Greenstone' | eval $gsdliconv
+  ;;
+  "ru")
+eval $gsdliconv <<EOF
+÷ÁÍ ÎÅÏÂÈÏÄÉÍ ÉÓÔÏÞÎÉË ÓËÒÉÐÔÁ ÉÚ ÂÁÚÏ×ÏÊ ÄÉÒÅËÔÏÒÉÉ Greenstone
+EOF
+  ;;
+  *)
+    echo 'You must source the script from within the Greenstone home directory'
+  ;;
+  esac
+else
+  GSDLHOME=`pwd`
+  export GSDLHOME
+  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
+
+  PATH=$PATH:$GSDLHOME/bin/script:$GSDLHOME/bin/$GSDLOS
+  export PATH
+  MANPATH=$MANPATH:$GSDLHOME/packages/mg/man
+  export MANPATH
+  case "$gsdllang" in
+    "es")
+      echo 'Su ambiente ha sido configurado para correr los programas Greenstone.' | eval $gsdliconv
+    ;;
+    "fr")
+      echo 'Votre environnement a été configuére avec succès pour exécuter Greenstone' | eval $gsdliconv
+    ;;
+    "ru")
+eval $gsdliconv <<EOF
+÷ÁÛÅ ÏËÒÕÖÅÎÉÅ ÂÙÌÏ ÕÓÐÅÛÎÏ ÎÁÓÔÒÏÅÎÏ, ÞÔÏÂÙ ÕÓÔÁÎÏ×ÉÔØ Greenstone
+EOF
+    ;;
+    *)
+      echo 'Your environment has successfully been set up to run Greenstone'
+    ;;
+  esac
+fi
+unset gsdl_not_sourced
+unset gsdliconv
+unset gsdlfromenc
+unset gsdltoenc
Index: /tags/gsdl-2_61-distribution/gsdl/setup.csh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/setup.csh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/setup.csh	(revision 10506)
@@ -0,0 +1,18 @@
+setenv GSDLLANG en
+setenv GSDLHOME `pwd`
+setenv GSDLOS `uname -s | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+setenv PATH $PATH\:$GSDLHOME/bin/script\:$GSDLHOME/bin/$GSDLOS
+if ($?MANPATH) then
+  setenv MANPATH $MANPATH\:$GSDLHOME/packages/mg/man
+else
+  setenv MANPATH $GSDLHOME/packages/mg/man
+endif
+if ("$GSDLLANG" == "es") then
+  echo "Su ambiente ha sido configurado para correr los programas Greenstone."
+else if ("$GSDLLANG" == "fr") then
+  echo "Votre environnement a été configuére avec succès pour exécuter Greenstone"
+else if ("$GSDLLANG" == "ru") then
+  echo "÷ÁÛÅ ÏËÒÕÖÅÎÉÅ ÂÙÌÏ ÕÓÐÅÛÎÏ ÎÁÓÔÒÏÅÎÏ, ÞÔÏÂÙ ÕÓÔÁÎÏ×ÉÔØ Greenstone"
+else
+  echo "Your environment has successfully been set up to run Greenstone"
+endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/checkis/checkis.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/checkis/checkis.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/checkis/checkis.cpp	(revision 10506)
@@ -0,0 +1,68 @@
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+
+int __stdcall WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, LPSTR CmdLineStr, int /*CmdShow*/) {
+  HKEY hk1, hk2, hk3, hk4, hk5, lk;
+  char command[2048];
+  command[0] = '\0';
+  
+  // try to find the command to start the library
+  if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE", &hk1) == ERROR_SUCCESS) {
+    if (RegOpenKey(hk1, "Waikato University", &hk2) == ERROR_SUCCESS) {
+      if (RegOpenKey(hk2, "sjnew", &hk3) == ERROR_SUCCESS) {
+	if (RegOpenKey(hk3, "1", &hk4) == ERROR_SUCCESS) {
+	  if (RegOpenKey(hk4, "2.26.000", &hk5) == ERROR_SUCCESS) {
+
+	    if (RegOpenKey(hk3, "2.26.000", &lk) == ERROR_SUCCESS) {
+	    
+	      // look for the command to start the browser
+	      DWORD dwIndex = 0;
+	      char key[256];
+	      key[0] = '\0';
+	      DWORD keysize = 256;
+	      DWORD type;
+	      DWORD comsize = 2048;
+	      while (RegEnumValue(lk, dwIndex, key, &keysize, NULL, &type, 
+				  (unsigned char *)command, &comsize) == ERROR_SUCCESS) {
+		// see if this is the right key (yes, this should always be library, NOT
+		// the name of the executable
+		if (strcmp (key, "library") == 0) break;
+		else command[0] = '\0';
+	      
+		// prepare for next iteration
+		++dwIndex;
+		keysize = 256;
+		comsize = 2048;
+	      }
+	      RegCloseKey(lk);
+	    }
+	    RegCloseKey(hk5);
+	  }	   
+ 	  RegCloseKey(hk4);
+	}
+	RegCloseKey(hk3);
+      }
+      RegCloseKey(hk2);
+    }
+    RegCloseKey(hk1);
+  }
+  
+  if (strlen (command) == 0) { 
+    // not installed, try to run the setup program
+    WinExec ("setup.exe", SW_SHOW);
+  } else { 
+    // installed ask the user whether they want to run the library now
+    if (MessageBox (NULL, 
+		    "Would you like to view the School Journal Collection?",
+		    "Greenstone Digital Library",
+		    MB_YESNO) == IDYES) {
+      WinExec (command, SW_SHOW);
+    }
+  }
+  
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/checkis/checkis_cd.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/checkis/checkis_cd.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/checkis/checkis_cd.cpp	(revision 10506)
@@ -0,0 +1,32 @@
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+
+int __stdcall WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, LPSTR CmdLineStr, int /*CmdShow*/) {
+  HKEY hk1, hk2, hk3, hk4;
+  BOOL found = FALSE;
+  
+  // try to find the command to start the library
+  if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE", &hk1) == ERROR_SUCCESS) {
+    if (RegOpenKey(hk1, "New Zealand Digital Library Project", &hk2) == ERROR_SUCCESS) {
+      if (RegOpenKey(hk2, "Greenstone Digital Library Software", &hk3) == ERROR_SUCCESS) {
+	if (RegOpenKey(hk3, "2.37.000", &hk4) == ERROR_SUCCESS) {
+	  found = TRUE;
+ 	  RegCloseKey(hk4);
+	}
+	RegCloseKey(hk3);
+      }
+      RegCloseKey(hk2);
+    }
+    RegCloseKey(hk1);
+  }
+  
+  if (!found) { 
+    // not installed, try to run the setup program
+    WinExec ("setup.exe", SW_SHOW);
+  }
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/GCC.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/GCC.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/GCC.mak	(revision 10506)
@@ -0,0 +1,73 @@
+###########################################################################
+#
+# gcc win32 makefile -- src/colservr
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+AR = ar
+RANLIB = ranlib
+CC = g++
+DELETE = del
+
+o = .o
+/ = \\
+
+CPPFLAGS = -g -Wall
+DEFS = -D__WIN32__ -DGSDL_USE_IOS_H -DHAVE_CONFIG_H
+
+INCLUDES = -I"..$/..$/lib" -I"..$/recpt" -I"..$/..$/packages$/mg" \
+	   -I"..$/..$/packages$/mg$/lib" -I"..$/..$/packages$/mg$/src$/text" \
+           -I"..$/..$/packages$/wingdbm"
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c $o
+.c$o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp $o
+.cpp$o:
+	$(COMPILE) $< 
+
+HEADERS = mgq.h mgsearch.h querycache.h queryinfo.h collectserver.h \
+          colservrconfig.h maptools.h filter.h source.h browsefilter.h \
+          queryfilter.h mggdbmsource.h phrasesearch.h phrasequeryfilter.h
+
+SOURCES = mgq.c mgsearch.cpp querycache.cpp queryinfo.cpp collectserver.cpp \
+          colservrconfig.cpp maptools.cpp filter.cpp source.cpp \
+          browsefilter.cpp queryfilter.cpp mggdbmsource.cpp phrasesearch.cpp \
+          phrasequeryfilter.cpp
+
+OBJECTS = mgq$o mgsearch$o querycache$o queryinfo$o collectserver$o \
+          colservrconfig$o maptools$o filter$o source$o browsefilter$o \
+          queryfilter$o mggdbmsource$o phrasesearch$o phrasequeryfilter$o
+
+all : $(OBJECTS)
+
+clean:
+	$(DELETE) *$o
+
+install:
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/Makefile.in	(revision 10506)
@@ -0,0 +1,190 @@
+###########################################################################
+#
+# Makefile -- src/colservr
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+AR = ar
+CC = @CC@
+CXX = @CXX@
+CFLAGS = @CFLAGS@
+CXXFLAGS = @CXXFLAGS@
+MCFLAGS = @CFLAGS@ -Wall -Wunused
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DGSDLSERVER @DEFS@
+
+USE_FASTCGI = @USE_FASTCGI@
+USE_MGPP = @USE_MGPP@
+ifneq ($(USE_FASTCGI), 1)
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM @DEFS@
+
+CGI_INCLUDES = 
+else
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DUSE_FASTCGI @DEFS@
+
+CGI_INCLUDES = -I../../packages/fcgi/include 
+endif
+
+ifneq ($(USE_MGPP), 1)
+MG_INCLUDES = -I../../packages/mg  -I../../packages/mg/lib \
+		-I../../packages/mg/src/text
+MG_HEADERS = mgq.h mgsearch.h mgqueryfilter.h 
+
+MG_SOURCES = mgq.c mgsearch.cpp mgqueryfilter.cpp 
+
+MG_OBJECTS = mgq.o mgsearch.o mgqueryfilter.o 
+MGPP_OBJECTS = mgppsearch.o mgppqueryfilter.o
+
+else
+MG_INCLUDES = -I../mgpp/text -I../mgpp/lib 
+
+MG_HEADERS = mgppsearch.h mgppqueryfilter.h
+
+MG_SOURCES = mgppsearch.cpp mgppqueryfilter.cpp
+
+MG_OBJECTS = mgppsearch.o mgppqueryfilter.o
+
+endif
+
+LC_INCLUDES = -I../../packages/expat/include
+LC_HEADERS  = lucenesearch.h   lucenequeryfilter.h   lucenegdbmsource.h \
+	      expat_resultset.h expat_document.h
+
+LC_SOURCES  = lucenesearch.cpp lucenequeryfilter.cpp lucenegdbmsource.cpp \
+	      expat_resultset.cpp expat_document.cpp
+
+LC_OBJECTS  = lucenesearch.o   lucenequeryfilter.o   lucenegdbmsource.o \
+	      expat_resultset.o expat_document.o
+
+INCLUDES = -I. -I../.. -I../../lib -I../recpt \
+		$(CGI_INCLUDES) $(MG_INCLUDES) $(LC_INCLUDES) @GDBM_INCLUDE@
+MICO_DIR = @MICO_DIR@
+ifeq ($(MICO_DIR), default)
+MICO_INC = -I../../packages/mico/include
+MICO_PATH = ../../bin/linux/
+else
+ifeq ($(MICO_DIR), yes)
+MICO_INC =
+MICO_PATH =
+else
+MICO_INC = -I$(MICO_DIR)
+MICO_PATH =
+endif
+endif
+MINCLUDES = -I. -I../../lib -I../recpt  -I../mgpp/text $(MICO_INC)
+
+USE_CORBA = @USE_CORBA@
+USE_Z3950 = @USE_Z3950@
+
+RANLIB = @RANLIB@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+GSDLOS = @gsdlos@
+
+
+COMPILE = $(CC) -c $(CFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CXX) $(LDFLAGS) -o $@
+
+CXXCOMPILE = $(CXX) -c $(CXXFLAGS) $(DEFS) $(INCLUDES)
+CXXLINK = $(CXX) $(LDFLAGS) -o $@
+
+MCOMPILE = $(MICO_PATH)mico-c++ -x c++ $(MCFLAGS) $(DEFS) $(MINCLUDES) -c
+MLINK = $(MICO_PATH)mico-ld $(LDFLAGS) -lmico2.2.7 -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CXXCOMPILE) $< 
+
+.SUFFIXES: .mpp .o
+.mpp.o:
+	$(MCOMPILE) $<
+
+ifneq ($(USE_CORBA), 0)
+CORBAHEADERS = \
+  corbaServer.h
+CORBASOURCES = \
+  corbaServer.mpp
+CORBAOBJECTS = \
+  corbaServer.o ../../lib/corbaiface_skel.o
+else
+CORBAHEADERS = 
+CORBASOURCES = 
+CORBAOBJECTS = 
+endif
+
+ifeq ($(USE_Z3950), 1)
+INCLUDES += -I../../packages/yaz/include -I../../packages/d2m
+Z3950HEADERS = 
+Z3950SOURCES = z3950parser.cpp z3950explain.cpp z3950_to_gsdl.cpp \
+	       z3950server.cpp read-grs.cpp
+Z3950OBJECTS = z3950parser.o   z3950explain.o   z3950_to_gsdl.o   \
+	       z3950server.o   read-grs.o
+else
+Z3950HEADERS = 
+Z3950SOURCES = 
+Z3950OBJECTS = 
+endif
+
+# following objects need both mg and mgpp stuff - jrm21
+MG_MGPP_OBJECTS=collectset.o
+
+HEADERS = search.h querycache.h queryinfo.h collectserver.h collectset.h \
+          colservrconfig.h maptools.h filter.h source.h browsefilter.h \
+          queryfilter.h mggdbmsource.h gdbmsource.h \
+	  phrasesearch.h phrasequeryfilter.h \
+	  $(MG_HEADERS) $(LC_HEADERS) $(CORBAHEADERS)
+
+SOURCES = search.cpp querycache.cpp queryinfo.cpp collectserver.cpp \
+          colservrconfig.cpp maptools.cpp filter.cpp source.cpp \
+          browsefilter.cpp queryfilter.cpp mggdbmsource.cpp gdbmsource.cpp \
+	  phrasesearch.cpp phrasequeryfilter.cpp collectset.cpp \
+	  $(MG_SOURCES) $(LC_SOURCES) $(CORBASOURCES)
+
+OBJECTS = search.o querycache.o queryinfo.o collectserver.o \
+          colservrconfig.o maptools.o filter.o source.o browsefilter.o \
+          queryfilter.o mggdbmsource.o gdbmsource.o \
+	  phrasesearch.o phrasequeryfilter.o \
+	  $(MG_MGPP_OBJECTS) $(MG_OBJECTS) $(LC_OBJECTS) $(CORBAOBJECTS) 
+
+all : $(OBJECTS)
+	$(MAKE) USE_MGPP=1 $(MGPP_OBJECTS) $(Z3950OBJECTS)
+
+distclean:
+	rm -f $(OBJECTS) Makefile mgppsearch.o mgppqueryfilter.o
+clean:
+	rm -f $(OBJECTS) mgppsearch.o mgppqueryfilter.o
+
+install:
+
+# needs IndexData.h from mgpp...
+$(MG_MGPP_OBJECTS): %.o : %.cpp
+	$(CXXCOMPILE) -I../mgpp/text -I../mgpp/lib -o $@ $<
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CXXFLAGS) -- $(SOURCES)
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/browsefilter.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/browsefilter.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/browsefilter.cpp	(revision 10506)
@@ -0,0 +1,308 @@
+/**********************************************************************
+ *
+ * browsefilter.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "browsefilter.h"
+#include "fileutil.h"
+#include "gsdltools.h"
+
+
+browsefilterclass::browsefilterclass () {
+  gdbmptr = NULL;
+
+  // -- onePerQuery StartResults   integer
+  FilterOption_t filtopt;
+  filtopt.name = "StartResults";
+  filtopt.type = FilterOption_t::integert;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "1";
+  filtopt.validValues.push_back("1");
+  filtopt.validValues.push_back("10000");
+  filterOptions["StartResults"] = filtopt;
+
+  // -- onePerQuery EndResults     integer
+  filtopt.clear();
+  filtopt.name = "EndResults";
+  filtopt.type = FilterOption_t::integert;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "-1";
+  filtopt.validValues.push_back("-1");
+  filtopt.validValues.push_back("10000");
+  filterOptions["EndResults"] = filtopt;
+
+  // -- onePerQuery ParentNode     string ("" will return the browsing available)
+  filtopt.clear();
+  filtopt.name = "ParentNode";
+  filtopt.type = FilterOption_t::stringt;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "";
+  filterOptions["ParentNode"] = filtopt;
+}
+
+browsefilterclass::~browsefilterclass () {
+}
+
+void browsefilterclass::configure (const text_t &key, const text_tarray &cfgline) {
+  filterclass::configure (key, cfgline);
+  if (key == "indexstem") {
+    indexstem = cfgline[0];
+  }
+}
+
+bool browsefilterclass::init (ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  if (!filterclass::init(logout)) return false;
+
+  if (indexstem.empty()) {
+    indexstem = collection;
+  }
+  // get the filename for the database and make sure it exists
+  gdbm_filename = filename_cat(gdbmhome, "collect", collection, "index", "text", indexstem);
+
+  if (littleEndian()) gdbm_filename += ".ldb";
+  else gdbm_filename += ".bdb";
+
+  if (!file_exists(gdbm_filename)) {
+    logout << text_t2ascii
+	   << "warning: gdbm database \"" //****
+	   << gdbm_filename << "\" does not exist\n\n";
+    //    return false; //****
+  }
+
+  return true;
+}
+
+void browsefilterclass::filter (const FilterRequest_t &request,
+				FilterResponse_t &response,
+				comerror_t &err, ostream &logout) {
+  int numDocs = 0;
+  outconvertclass text_t2ascii;
+
+  response.clear ();
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: browsefilter contains a null gdbmclass\n\n";
+    err = configurationError;
+    return;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return;
+  }
+
+  // get the browse parameters
+  int startresults = filterOptions["StartResults"].defaultValue.getint();
+  int endresults = filterOptions["EndResults"].defaultValue.getint();
+  text_t parentnode = filterOptions["ParentNode"].defaultValue;
+  OptionValue_tarray::const_iterator options_here = request.filterOptions.begin();
+  OptionValue_tarray::const_iterator options_end = request.filterOptions.end();
+  while (options_here != options_end) {
+    if ((*options_here).name == "StartResults") 
+      startresults = (*options_here).value.getint();
+    else if ((*options_here).name == "EndResults")
+      endresults = (*options_here).value.getint();
+    else if ((*options_here).name == "ParentNode")
+      parentnode = (*options_here).value;
+    else {
+      logout << text_t2ascii
+	     << "warning: unknown browsefilter option \""
+	     << (*options_here).name
+	     << "\" ignored.\n\n";
+    }
+
+    ++options_here;
+  }
+
+  infodbclass info;
+
+  // translate any ".fc", ".pr" etc. stuff in the parentnode
+  parentnode = gdbmptr->translate_OID (parentnode, info);
+
+  // adjust topmost browsing node
+  if (parentnode.empty()) parentnode = "browse";
+
+  // get the node
+  if ((request.filterResultOptions & FROID) ||
+      (request.filterResultOptions & FRmetadata)) {
+    if (!gdbmptr->getinfo(parentnode, info)) {
+      // didn't find the node
+      logout << text_t2ascii
+	     << "warning: lookup for node \"" << parentnode 
+	     << "\" failed for browsefilter.\n\n";
+    } else {
+      // found the node
+
+      // replace " with the parent node name and split the contains string
+      // into the result set
+      text_tarray resultset;
+      text_t tmptext;
+      text_t &contains = info["contains"];
+      text_t::iterator contains_here = contains.begin();
+      text_t::iterator contains_end = contains.end();
+      while (contains_here != contains_end) {
+	if (*contains_here == '"') tmptext += parentnode;
+	else if (*contains_here == ';') {
+	  if (!tmptext.empty()) resultset.push_back (tmptext);
+	  tmptext.clear();
+	} else tmptext.push_back(*contains_here);
+	
+	++contains_here;
+      }
+      // insert the last result in the set
+      if (!tmptext.empty()) resultset.push_back (tmptext);
+
+      text_tarray offset_resultset;
+      text_t &md_type = info["mdtype"];
+      if (!md_type.empty())
+	{
+	  text_t &md_offset = info["mdoffset"];
+	  if (!md_offset.empty())
+	    {
+	      text_t offsettext;
+
+	      text_t::iterator offset_here = md_offset.begin();
+	      text_t::iterator offset_end = md_offset.end();
+	      while (offset_here != offset_end) 
+		{
+		  if (*offset_here == ';')
+		    {
+		      if (offsettext.empty())
+			{
+			  offset_resultset.push_back ("0");
+			}
+		      else
+			{
+			  offset_resultset.push_back (offsettext);
+			}
+		      offsettext.clear();
+		    } 
+		  else 
+		    {
+		      offsettext.push_back(*offset_here);
+		    }
+		  
+		  ++offset_here;
+		}
+	      // insert the last result in the set
+	      if (offsettext.empty())
+		{
+		  offset_resultset.push_back ("0");
+		}
+	      else
+		{
+		  offset_resultset.push_back (offsettext);
+		}
+	    }
+	  else
+	    {
+	      // add 0 offset for each 'contains' entry
+	      text_tarray::iterator result_here = resultset.begin();
+	      text_tarray::iterator result_end = resultset.end();
+	      while (result_here != result_end) {
+		offset_resultset.push_back("0");
+		++result_here;
+	      }
+	    }
+
+	  // do an intersection with the input set
+	  if (!request.docSet.empty()) {
+
+	    text_tarray intersect_resultset;
+	    text_tarray intersect_offset_resultset;
+	    
+	    text_tarray::const_iterator resultset_here = resultset.begin();
+	    text_tarray::const_iterator resultset_end = resultset.end();
+	    text_tarray::const_iterator offset_resultset_here = offset_resultset.begin();
+	    
+	    while (resultset_here != resultset_end) {
+	      if (in_set (request.docSet, *resultset_here))
+		{
+		  intersect_resultset.push_back (*resultset_here);
+		  intersect_offset_resultset.push_back (*offset_resultset_here);
+		}
+	      ++resultset_here;
+	      ++offset_resultset_here;
+	    }
+	    resultset = intersect_resultset;
+	    offset_resultset = intersect_offset_resultset;
+	  }
+	}
+      else
+	{
+	  // do an intersection with the input set
+	  if (!request.docSet.empty()) {
+	    intersect (resultset, request.docSet);
+	  }
+
+	  // add 0 offset for each 'contains' entry
+	  text_tarray::iterator result_here = resultset.begin();
+	  text_tarray::iterator result_end = resultset.end();
+	  while (result_here != result_end) {
+	    offset_resultset.push_back("0");
+	    ++result_here;
+	  }
+	}
+
+      // create the response
+      numDocs = resultset.size();
+      int resultnum = 1;
+      ResultDocInfo_t resultdoc;
+      text_tarray::iterator result_here = resultset.begin();
+      text_tarray::iterator result_end = resultset.end();
+      text_tarray::iterator offset_result_here = offset_resultset.begin();
+
+      while (result_here != result_end) {
+	// if endresults is -1 get all results
+	if ((endresults != -1) && (resultnum > endresults)) break;
+	if (resultnum >= startresults) {
+	  resultdoc.OID = (*result_here);
+	  if (!md_type.empty())
+	    {
+	      resultdoc.classifier_metadata_type = md_type;
+	      resultdoc.classifier_metadata_offset = offset_result_here->getint();
+	    }
+	  response.docInfo.push_back(resultdoc);
+	}
+
+	++resultnum;
+	++result_here;
+	if (!md_type.empty()) ++offset_result_here;
+      }
+    }
+  }
+
+  response.numDocs = numDocs;
+  response.isApprox = Exact;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/browsefilter.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/browsefilter.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/browsefilter.h	(revision 10506)
@@ -0,0 +1,64 @@
+/**********************************************************************
+ *
+ * browsefilter.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef BROWSEFILTER_H
+#define BROWSEFILTER_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+#include "filter.h"
+#include "infodbclass.h"
+
+
+class browsefilterclass : public filterclass {
+protected:
+  text_t gdbm_filename;
+  text_t indexstem;
+  gdbmclass *gdbmptr;
+
+public:
+  browsefilterclass ();
+  virtual ~browsefilterclass ();
+
+  // configure should be called once for each configuration line
+  // default configures the default filter options
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  // the gdbmptr remains the responsability of the calling code and
+  // should be destroyed after this browsefilter is destroyed
+  void set_gdbmptr (gdbmclass *thegdbmptr) {gdbmptr = thegdbmptr;}
+
+  bool init (ostream &logout);
+  text_t get_filter_name () {return "BrowseFilter";}
+  void filter (const FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout);
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectserver.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectserver.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectserver.cpp	(revision 10506)
@@ -0,0 +1,497 @@
+
+/**********************************************************************
+ *
+ * collectserver.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "collectserver.h"
+#include "infodbclass.h"
+#include "OIDtools.h"
+#include <assert.h>
+#include "display.h"
+
+
+collectserver::collectserver () {
+  configinfo.collection = "null";
+}
+
+collectserver::~collectserver () {
+
+  // clean up the sources
+  sourcelistclass::iterator source_here = sources.begin();
+  sourcelistclass::iterator source_end = sources.end();
+  while (source_here != source_end) {
+    if ((*source_here).s != NULL)
+      delete (*source_here).s;
+    ++source_here;
+  }
+  sources.clear();
+
+  // clean up the filters
+  filtermapclass::iterator filter_here = filters.begin();
+  filtermapclass::iterator filter_end = filters.end();
+  while (filter_here != filter_end) {
+    if ((*filter_here).second.f != NULL) 
+      delete (*filter_here).second.f;
+    ++filter_here;
+  }
+  filters.clear();
+}
+
+// configure should be called for each line in the
+// configuration files to configure the collection server and everything
+// it contains. The configuration should take place just before initialisation.
+void collectserver::configure (const text_t &key, const text_tarray &cfgline) {
+  if (cfgline.size() >= 1) {
+    const text_t &value = cfgline[0];
+    if (key == "gsdlhome") configinfo.gsdlhome = value;
+    else if (key == "gdbmhome") configinfo.gdbmhome = value;
+    else if (key == "collection") {
+      configinfo.collection = value;
+      collectinfo.shortInfo.name = value;
+    } else if (key == "collectdir") configinfo.collectdir = value;
+    else if (key == "host") collectinfo.shortInfo.host = value;
+    else if (key == "port") collectinfo.shortInfo.port = value.getint();
+    else if (key == "public") {
+      if (value == "true") collectinfo.isPublic = true;
+      else collectinfo.isPublic = false;
+    } else if (key == "beta") {
+      if (value == "true") collectinfo.isBeta = true;
+      else collectinfo.isBeta = false;
+    } else if ((key == "ccscols") || (key == "supercollection")) collectinfo.ccsCols = cfgline;
+    else if (key == "builddate") collectinfo.buildDate = value.getint();
+    else if (key == "languages") collectinfo.languages = cfgline;
+    else if (key == "numdocs") collectinfo.numDocs = value.getint();
+    else if (key == "numsections") collectinfo.numSections = value.getint();
+    else if (key == "numwords") collectinfo.numWords = value.getint();
+    else if (key == "numbytes") collectinfo.numBytes = value.getint();
+    else if (key == "collectionmeta") {
+      text_t params;
+      if (cfgline.size() == 3) {
+	// get the params for later
+	text_t::const_iterator first=cfgline[1].begin()+1;
+	text_t::const_iterator last=cfgline[1].end()-1;
+	params=substr(first, last);
+      }
+      
+      text_t meta_name = cfgline[0];
+      if (*(meta_name.begin())=='.') {
+	// a .xxx collectionmeta. strip off the . and
+	// look it up in the indexmap to get the actual value
+	
+	text_t name = substr(cfgline[0].begin()+1,cfgline[0].end());
+	text_t new_name;
+	if (indexmap.from2to(name, new_name)) {
+	  meta_name = new_name;
+	} 
+      } else {
+	// add them to collectionmeta
+	text_tmap lang_map = collectinfo.collectionmeta[cfgline[0]];
+	if (cfgline.size() == 2) {
+	  lang_map[g_EmptyText] = cfgline[1];
+	} else if (cfgline.size() == 3 ) {
+	  // get the lang out of params
+	  paramhashtype params_hash;
+	  splitparams(params, params_hash);
+	  
+	  text_t lang = params_hash["l"];
+	  lang_map[lang] = cfgline[2];
+	  if (lang_map[g_EmptyText].empty()) {
+	    // want the first one as the default if no default specified
+	    lang_map[g_EmptyText] = cfgline[2];
+	  }
+	}
+	collectinfo.collectionmeta[cfgline[0]] = lang_map;
+	
+      }
+      
+      // add all collectionmeta to macro list
+      if (cfgline.size() == 2) // no params for this macro
+	collectinfo.collection_macros
+	  .insert( make_pair(meta_name, make_pair(g_EmptyText,cfgline[1])) );
+      else if (cfgline.size() == 3) {// has params
+	// can we somehow add this is with no params if there is not already 
+	// a no params entry??
+	collectinfo.collection_macros
+	  .insert( make_pair(meta_name, make_pair(params,cfgline[2])) );
+      }
+    }
+    else if (key == "collectionmacro") {
+      text_t nobrackets;
+      // add all to macro list
+      if (cfgline.size() == 2) // no params for this macro
+	collectinfo.collection_macros
+	  .insert( make_pair(cfgline[0], make_pair(g_EmptyText,cfgline[1])) );
+      else if (cfgline.size() == 3) {// has params
+	// strip [ ] brackets from params
+	text_t::const_iterator first=cfgline[1].begin()+1;
+	text_t::const_iterator last=cfgline[1].end()-1;
+	nobrackets=substr(first, last);
+	collectinfo.collection_macros
+	  .insert( make_pair(cfgline[0], make_pair(nobrackets,cfgline[2])) );
+      }
+    } else if (key == "format" && cfgline.size() == 2)
+      collectinfo.format[cfgline[0]] = cfgline[1];
+    else if (key == "building" && cfgline.size() == 2)
+      collectinfo.building[cfgline[0]] = cfgline[1];
+    else if (key == "httpdomain") collectinfo.httpdomain = value;
+    else if (key == "httpprefix") collectinfo.httpprefix = value;
+    else if (key == "receptionist") collectinfo.receptionist = value;
+    else if (key == "buildtype") collectinfo.buildType = value;
+    else if (key == "searchtype") { // means buildtype is mgpp
+      if (collectinfo.buildType.empty()) {
+	collectinfo.buildType = "mgpp";
+      }
+      collectinfo.searchTypes = cfgline;
+    }
+    else if (key == "separate_cjk") {
+      if (value == "true") collectinfo.isSegmented = true;
+      else collectinfo.isSegmented = false;
+    }
+    // What have we set in our collect.cfg file :  document or collection ?
+    else if (key == "authenticate") collectinfo.authenticate = value;
+
+    // What have we set for our group list
+    else if (key == "auth_group")
+       {
+	  // use the joinchar helper function from
+	  // text_t.h, it takes in the whole cfgline
+	  // array and a separator aka a comma in our
+	  // case and returns a sting separated by a
+	  // comma like this:
+	  //
+	  //   Rene,Kolla,Crystal,Stefan,Aly,Ian
+	  
+	  joinchar(cfgline,',',collectinfo.auth_group);
+	  
+	  //outconvertclass t;
+	  //cerr << t << collectinfo.auth_group << "\n";
+       }
+
+    // store all the mappings for use when collection meta is read later
+    // (build.cfg read before collect.cfg)
+    else if (key == "indexmap" || key == "indexfieldmap" || key == "subcollectionmap" || key == "languagemap" || key == "levelmap") {
+      indexmap.importmap (cfgline, true);
+      
+    } 
+    // In the map the key-value pair contain the same
+    // data i.e key == data, if key is 2 then data is 2
+    
+    // What have we set for our public_documents ACL
+    else if (key == "public_documents")
+       {
+	  text_tarray::const_iterator begin = cfgline.begin();
+	  text_tarray::const_iterator end = cfgline.end();
+	  while(begin != end)
+	     {
+		// key = data i.e if key is 2 then data is 2
+		// collectinfo.public_documents[*begin] is the key
+		// *begin is the data value
+
+		collectinfo.public_documents[*begin] = *begin;
+		++begin;
+	     }
+       }
+    
+    // What have we set for our private_documents ACL
+    else if (key == "private_documents")
+       {
+	  text_tarray::const_iterator begin = cfgline.begin();
+	  text_tarray::const_iterator end = cfgline.end();
+	  while(begin != end)
+	     {
+		// key = data i.e if key is 2 then data is 2
+		// collectinfo.public_documents[*begin] is the key
+		// *begin is the data value
+		
+		collectinfo.private_documents[*begin] = *begin;
+		++begin;
+	     }
+       }
+  }
+  
+  // configure the filters
+  filtermapclass::iterator filter_here = filters.begin();
+  filtermapclass::iterator filter_end = filters.end();
+  while (filter_here != filter_end) {
+    assert ((*filter_here).second.f != NULL);
+    if ((*filter_here).second.f != NULL) 
+      (*filter_here).second.f->configure(key, cfgline);
+
+    ++filter_here;
+  }
+
+  // configure the sources
+  sourcelistclass::iterator source_here = sources.begin();
+  sourcelistclass::iterator source_end = sources.end();
+  while (source_here != source_end) {
+    assert ((*source_here).s != NULL);
+    if ((*source_here).s != NULL)
+      (*source_here).s->configure(key, cfgline);
+    
+    ++source_here;
+  }
+}
+
+
+void collectserver::configure (const text_t &key, const text_t &value) {
+  text_tarray cfgline;
+  cfgline.push_back (value);
+  configure(key, cfgline);
+}
+
+void collectserver::ping (bool &wasSuccess, comerror_t &error, ostream &logout) {
+  // if we've not been properly configured, then it is a foregone
+  // conclusion that we cannot be active
+  if (this->configinfo.collection == "null")
+    {
+      wasSuccess = false;
+    }
+  // if no build date exists, then the collection was probably not built;
+  // ditto if the number of documents is zero, then something is pretty
+  // wrong
+  else if (this->collectinfo.buildDate == 0 ||
+      this->collectinfo.numDocs == 0)
+    {
+      wasSuccess =  false;
+    }
+  // it is probably okay
+  else
+    wasSuccess = true;
+}
+
+
+bool collectserver::init (ostream &logout) {
+  // delete the indexmap
+  indexmap.clear();
+
+  // init the filters
+  filtermapclass::iterator filter_here = filters.begin();
+  filtermapclass::iterator filter_end = filters.end();
+  while (filter_here != filter_end) {
+    assert ((*filter_here).second.f != NULL);
+    if (((*filter_here).second.f != NULL) &&
+	!(*filter_here).second.f->init(logout)) return false;
+    
+    ++filter_here;
+  }
+
+  // init the sources
+  sourcelistclass::iterator source_here = sources.begin();
+  sourcelistclass::iterator source_end = sources.end();
+  while (source_here != source_end) {
+    assert ((*source_here).s != NULL);
+    if (((*source_here).s != NULL) &&
+	!(*source_here).s->init(logout)) return false;
+    
+    ++source_here;
+  }
+
+  return true;
+}
+
+
+void collectserver::get_collectinfo (ColInfoResponse_t &reponse,
+		      comerror_t &err, ostream &/*logout*/) {
+  reponse = collectinfo; 
+  err = noError;
+}
+
+void collectserver::get_filterinfo (InfoFiltersResponse_t &response,
+				    comerror_t &err, ostream &/*logout*/) {
+  response.clear ();
+
+  // get a list of filter names
+  filtermapclass::iterator filter_here = filters.begin();
+  filtermapclass::iterator filter_end = filters.end();
+  while (filter_here != filter_end) {
+    response.filterNames.insert ((*filter_here).first);
+    ++filter_here;
+  }
+
+  err = noError;
+}
+
+void collectserver::get_filteroptions (const InfoFilterOptionsRequest_t &request,
+				       InfoFilterOptionsResponse_t &response, 
+				       comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  filterclass *thisfilter = filters.getfilter(request.filterName);
+  if (thisfilter != NULL) {
+    thisfilter->get_filteroptions (response, err, logout);
+  } else {
+    response.clear ();
+    err = protocolError;
+    logout << text_t2ascii << "Protocol Error: filter options requested for non-existent\n"
+	   << "filter \"" << request.filterName << "\".\n\n";
+  }
+}
+
+void collectserver::filter (FilterRequest_t &request,
+			    FilterResponse_t &response,
+			    comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  // translate any ".fc", ".pr" etc. stuff in the docSet
+  text_t translatedOID;
+  text_tarray translatedOIDs;
+  text_tarray::iterator doc_here = request.docSet.begin();
+  text_tarray::iterator doc_end = request.docSet.end();
+  while (doc_here != doc_end) {
+    if (needs_translating (*doc_here)) {
+      sourcelistclass::iterator source_here = sources.begin();
+      sourcelistclass::iterator source_end = sources.end();
+      while (source_here != source_end) {
+	assert ((*source_here).s != NULL);
+	if (((*source_here).s != NULL) &&
+	    ((*source_here).s->translate_OID (*doc_here, translatedOID, err, logout))) {
+	  if (err != noError) return;
+	  break;
+	}
+	++source_here;
+      }
+      translatedOIDs.push_back (translatedOID);
+    } else {
+      translatedOIDs.push_back (*doc_here);
+    }
+    ++doc_here;
+  }
+  request.docSet = translatedOIDs;
+
+  response.clear();
+
+  filterclass *thisfilter = filters.getfilter(request.filterName);
+  if (thisfilter != NULL) {
+    // filter the data
+    thisfilter->filter (request, response, err, logout);
+    if (err != noError) return;
+    // fill in the metadata for each of the OIDs (if it is requested)
+    if (request.filterResultOptions & FRmetadata) {
+      bool processed = false;
+      ResultDocInfo_tarray::iterator resultdoc_here = response.docInfo.begin();
+      ResultDocInfo_tarray::iterator resultdoc_end = response.docInfo.end();
+      while (resultdoc_here != resultdoc_end) {
+	// try each of the sources in turn
+	sourcelistclass::iterator source_here = sources.begin();
+	sourcelistclass::iterator source_end = sources.end();
+	while (source_here != source_end) {
+	  assert ((*source_here).s != NULL);
+	  if (((*source_here).s != NULL) &&
+	      ((*source_here).s->get_metadata(request.requestParams, request.refParams,
+					      request.getParents, request.fields, 
+					      (*resultdoc_here).OID, (*resultdoc_here).metadata, 
+					      err, logout))) {
+	    if (err != noError) return;
+	    processed = true;
+	    break;
+	  }
+	  ++source_here;
+	}
+	if (!processed) {
+	  err = protocolError;
+	  return;
+	}
+	++resultdoc_here;
+      }
+    }
+    
+  } else {
+    response.clear ();
+    err = protocolError;
+    logout << text_t2ascii << "Protocol Error: filter options requested for non-existent\n"
+	   << "filter \"" << request.filterName << "\".\n\n";
+  }
+  
+  err = noError;
+}
+
+void collectserver::get_document (const DocumentRequest_t &request,
+				  DocumentResponse_t &response,
+				  comerror_t &err, ostream &logout) {
+
+  sourcelistclass::iterator source_here = sources.begin();
+  sourcelistclass::iterator source_end = sources.end();
+  while (source_here != source_end) {
+    assert ((*source_here).s != NULL);
+    if (((*source_here).s != NULL) &&
+	((*source_here).s->get_document (request.OID, response.doc, err, logout))) {
+      if (err != noError) return;
+      break;
+    }
+    ++source_here;
+  }
+}
+
+void collectserver::is_searchable (bool &issearchable, comerror_t &err,
+				   ostream &logout) {
+
+  sourcelistclass::iterator source_here = sources.begin();
+  sourcelistclass::iterator source_end = sources.end();
+  while (source_here != source_end) {
+    assert ((*source_here).s != NULL);
+    if (((*source_here).s != NULL) &&
+	((*source_here).s->is_searchable (issearchable, err, logout))) {
+      if (err != noError) return;
+      break;
+    }
+    ++source_here;
+  }
+}
+
+
+bool operator==(const collectserverptr &x, const collectserverptr &y) {
+  return (x.c == y.c);
+}
+
+bool operator<(const collectserverptr &x, const collectserverptr &y) {
+  return (x.c < y.c);
+}
+
+
+// thecollectserver remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void collectservermapclass::addcollectserver (collectserver *thecollectserver) {
+  // can't add a null collection server
+  assert (thecollectserver != NULL);
+  if (thecollectserver == NULL) return;
+  
+  // can't add an collection server with no collection name
+  assert (!(thecollectserver->get_collection_name()).empty());
+  if ((thecollectserver->get_collection_name()).empty()) return;
+
+  collectserverptr cptr;
+  cptr.c = thecollectserver;
+  collectserverptrs[thecollectserver->get_collection_name()] = cptr;
+}
+
+// getcollectserver will return NULL if the collectserver could not be found
+collectserver *collectservermapclass::getcollectserver (const text_t &collection) {
+  // can't find a collection with no name
+  if (collection.empty()) return NULL;
+
+  iterator here = collectserverptrs.find (collection);
+  if (here == collectserverptrs.end()) return NULL;
+  
+  return (*here).second.c;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectserver.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectserver.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectserver.h	(revision 10506)
@@ -0,0 +1,198 @@
+/**********************************************************************
+ *
+ * collectserver.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef COLLECTSERVER_H
+#define COLLECTSERVER_H
+
+// Library header files
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+#include "filter.h"
+#include "source.h"
+#include "cfgread.h"
+#include "cnfgable.h" 
+#include "maptools.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+struct colservrconf {
+  text_t gsdlhome;
+  text_t gdbmhome;
+  text_t collection;
+  text_t collectdir;
+};
+
+
+class collectserver : public configurable {
+protected:
+  colservrconf configinfo;
+  ColInfoResponse_t collectinfo;
+
+  filtermapclass filters;
+  sourcelistclass sources;
+
+  // some stuff to remember while we are configuring
+  stringmap indexmap;
+
+public:
+  collectserver ();
+  virtual ~collectserver ();
+
+  // add_filter makes another filter available to the collection server
+  // the filter remains the property of the calling code and that
+  // code should destroy the filter after the collection server has been
+  // destroyed.
+  void add_filter (filterclass *thefilter) {filters.addfilter(thefilter);}
+  filtermapclass *get_filtermap_ptr () {return &filters;}
+
+  // add_source makes another source available to the collection server
+  // the source remains the property of the calling code and that
+  // code should destroy the source after the collection server has been
+  // destroyed.
+  void add_source (sourceclass *thesource) {sources.addsource(thesource);}
+  sourcelistclass *get_sourcelist_ptr () {return &sources;}
+
+  // configure should be called for each line in the
+  // configuration files to configure the collection server and everything
+  // it contains. The configuration should take place just before initialisation.
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+  void configure (const text_t &key, const text_t &value);
+  const colservrconf &get_configinfo () {return configinfo;}
+  text_t get_collection_name () {return configinfo.collection;}
+
+  // ping indicates whether the collection has appropriate data structures
+  // to be active or not
+  void ping(bool &wasSuccess, comerror_t &err, ostream &logout);
+
+  // init should be called after the collection name has been set and
+  // all initialisation is done. init returns true if the initialisation
+  // was successful, if false is returned then no other functions
+  // should be called (without producing meaningless output).
+  virtual bool init (ostream &logout);
+
+  void get_collectinfo (ColInfoResponse_t &reponse,
+			comerror_t &err, ostream &logout);
+
+  virtual void get_filterinfo (InfoFiltersResponse_t &response,
+			       comerror_t &err, ostream &logout);
+
+  virtual void get_filteroptions (const InfoFilterOptionsRequest_t &request,
+				  InfoFilterOptionsResponse_t &response, 
+				  comerror_t &err, ostream &logout);
+
+  virtual void filter (FilterRequest_t &request,
+		       FilterResponse_t &response,
+		       comerror_t &err, ostream &logout);
+
+
+  virtual void get_document (const DocumentRequest_t &request,
+			     DocumentResponse_t &response,
+			     comerror_t &err, ostream &logout);
+
+  virtual void is_searchable (bool &issearchable, comerror_t &err,
+			      ostream &logout);
+
+};
+
+
+// The collectserverptr function does not 'own' the collectserver. The
+// collectserver should be deleted by the code which created it.
+class collectserverptr {
+public:
+  collectserver *c;
+
+  collectserverptr () {c=NULL;}
+  ~collectserverptr () {}
+};
+
+bool operator==(const collectserverptr &x, const collectserverptr &y);
+bool operator<(const collectserverptr &x, const collectserverptr &y);
+
+typedef map<text_t, collectserverptr, lttext_t> collectserverptrmap;
+
+// contains a list of collectservers indexed by their name
+class collectservermapclass {
+protected:
+  collectserverptrmap collectserverptrs;
+
+public:
+  // type support for collectserverptrmap
+  typedef collectserverptrmap::iterator iterator;
+  typedef collectserverptrmap::const_iterator const_iterator;
+  typedef collectserverptrmap::reference reference;
+  typedef collectserverptrmap::const_reference const_reference;
+  typedef collectserverptrmap::size_type size_type;
+
+  typedef collectserverptrmap::difference_type difference_type;
+  typedef collectserverptrmap::const_reverse_iterator const_reverse_iterator;
+  typedef collectserverptrmap::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return collectserverptrs.begin();}
+  const_iterator begin () const {return collectserverptrs.begin();}
+  iterator end () {return collectserverptrs.end();}
+  const_iterator end () const {return collectserverptrs.end();}
+
+  void erase(iterator pos) {collectserverptrs.erase(pos);}
+  void erase(iterator first, iterator last) {collectserverptrs.erase(first, last);}
+  collectservermapclass &operator=(const collectservermapclass &x) 
+    {collectserverptrs=x.collectserverptrs;return *this;}
+
+  bool empty () const {return collectserverptrs.empty();}
+  size_type size() const {return collectserverptrs.size();}
+
+
+  // added functionality
+  void clear () {collectserverptrs.erase(collectserverptrs.begin(),collectserverptrs.end());}
+
+  // thecollectserver remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addcollectserver (collectserver *thecollectserver);
+
+  // getcollectserver will return NULL if the collectserver could not be found
+  collectserver *getcollectserver (const text_t &collection);
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectset.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectset.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectset.cpp	(revision 10506)
@@ -0,0 +1,489 @@
+/**********************************************************************
+ *
+ * collectset.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#include "collectserver.h"
+#include "filter.h"
+#include "browsefilter.h"
+#include "queryfilter.h"
+#include "infodbclass.h"
+#include "mgqueryfilter.h"
+#include "mgppqueryfilter.h"
+#include "mggdbmsource.h"
+#include "lucenequeryfilter.h"
+#include "lucenegdbmsource.h"
+
+#include "fileutil.h"
+#include <assert.h>
+
+#include "colservrconfig.h"
+#include "recptconfig.h"
+#include "fileutil.h"
+#include "collectset.h"
+
+collectset::collectset (text_t &gsdlhome) {
+
+  text_tarray collections;
+  text_t      collectdir;
+
+  // get gsdlhome (if we fail the error will be picked up later -- in
+  // cgiwrapper)
+  if (site_cfg_read (gsdlhome, httpdomain, httpprefix)) {
+    if (!gsdlhome.empty() && directory_exists(gsdlhome)) {
+      collectdir = filename_cat (gsdlhome, "collect");
+      if (read_dir (collectdir, collections)) {
+    
+	text_tarray::const_iterator thiscol = collections.begin();
+	text_tarray::const_iterator endcol = collections.end();
+
+	while (thiscol != endcol) {
+	  // ignore the modelcol
+	  if (*thiscol == "modelcol") {
+	    ++thiscol;
+	    continue;
+	  }
+
+	  // read config file to see if built with mg, mgpp, or lucene
+	  text_t buildtype = "mg"; // mg is default
+	  text_tarray cfgline;
+	  text_t key;
+	  text_t filename = filename_cat(collectdir, *thiscol, "index" , "build.cfg");
+	  ifstream confin(filename.getcstr());
+
+	  if (confin) {
+	    while (read_cfg_line(confin, cfgline) >= 0) {
+	      if (cfgline.size() ==2 ) {
+		key = cfgline[0];
+		cfgline.erase(cfgline.begin());
+		if (key =="buildtype") {
+		  buildtype = cfgline[0];
+		  break;
+		}
+	      }
+	    }
+	  }
+	  
+	  confin.close();
+
+	  // this memory is created but never destroyed
+	  // we're also not doing any error checking to make sure we didn't
+	  // run out of memory
+	  collectserver *cserver = new collectserver();
+	  gdbmclass *gdbmhandler = new gdbmclass();
+    
+	  // add a null filter
+	  filterclass *filter = new filterclass ();
+	  cserver->add_filter (filter);
+	  
+	  // add a browse filter
+	  browsefilterclass *browsefilter = new browsefilterclass();
+	  browsefilter->set_gdbmptr (gdbmhandler);
+	  cserver->add_filter (browsefilter);
+	  
+	  if (buildtype == "mg") {
+	    mgsearch = new mgsearchclass();
+	    
+	    // add a query filter
+	    mgqueryfilterclass *queryfilter = new mgqueryfilterclass();
+	    queryfilter->set_gdbmptr (gdbmhandler);
+	    queryfilter->set_textsearchptr (mgsearch);
+	    cserver->add_filter (queryfilter);
+	    
+	    // add a mg and gdbm source
+	    mggdbmsourceclass *mggdbmsource = new mggdbmsourceclass ();
+	    mggdbmsource->set_gdbmptr (gdbmhandler);
+	    mggdbmsource->set_textsearchptr (mgsearch);
+	    cserver->add_source (mggdbmsource);
+
+	  } else if (buildtype == "mgpp") {
+	    
+	    mgppsearch = new mgppsearchclass();
+	    	    
+	    // add a query filter
+	    mgppqueryfilterclass *queryfilter = new mgppqueryfilterclass();
+	    queryfilter->set_gdbmptr (gdbmhandler);
+	    queryfilter->set_textsearchptr (mgppsearch);
+	    cserver->add_filter (queryfilter);
+	    
+	    // add a mg and gdbm source
+	    mggdbmsourceclass *mggdbmsource = new mggdbmsourceclass ();
+	    mggdbmsource->set_gdbmptr (gdbmhandler);
+	    mggdbmsource->set_textsearchptr (mgppsearch);
+	    cserver->add_source (mggdbmsource);   
+	  } else if (buildtype == "lucene") {
+	    lucenesearch = new lucenesearchclass();
+	    
+	    // add a query filter
+	    lucenequeryfilterclass *queryfilter = new lucenequeryfilterclass();
+	    queryfilter->set_gdbmptr (gdbmhandler);
+	    queryfilter->set_textsearchptr (lucenesearch);
+	    cserver->add_filter (queryfilter);
+	    
+	    // add a lucene and gdbm source
+	    lucenegdbmsourceclass *lucenegdbmsource = new lucenegdbmsourceclass ();
+	    lucenegdbmsource->set_gdbmptr (gdbmhandler);
+	    lucenegdbmsource->set_textsearchptr (lucenesearch);
+	    cserver->add_source (lucenegdbmsource);   
+  }
+
+
+	  // inform collection server and everything it contains about its
+	  // collection name
+	  cserver->configure ("collection", *thiscol);
+	  // AZIZ: added on 10/10/00
+	  //       the cserver object does not have a reference to gsdlhome
+	  cserver->configure ("gsdlhome", gsdlhome);
+    
+	  // GRB: removed    proto.add_collectserver (cserver);
+	  // GRB: added to build our own cservers list
+	  cservers.addcollectserver (cserver);
+
+	  ++thiscol;
+	}
+      }
+    }
+  }
+}
+
+collectset::~collectset () {
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+
+  while (here != end) {
+    if ((*here).second.c != NULL) {
+      delete (*here).second.c;
+    }
+    ++here;
+  }
+  cservers.clear();
+}
+
+bool collectset::init (ostream &logout) {
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+
+  while (here != end) {
+    assert ((*here).second.c != NULL);
+    if ((*here).second.c != NULL) {
+      const colservrconf &configinfo = (*here).second.c->get_configinfo ();
+
+      // configure this collection server
+
+      // note that we read build.cfg before collect.cfg so that the indexmaps
+      // are available to decode defaultindex, defaultsubcollection, and
+      // defaultlanguage
+      if (!build_cfg_read (*((*here).second.c), configinfo.gsdlhome,
+			   configinfo.collection)) {
+	outconvertclass text_t2ascii;
+	logout << text_t2ascii 
+	       << "Warning: couldn't read build.cfg file for collection \"" //****
+	       << configinfo.collection << "\", gsdlhome=\""
+	       << configinfo.gsdlhome << "\"\n";
+	++here;
+	continue;
+      }
+
+      if (!collect_cfg_read (*((*here).second.c), configinfo.gsdlhome,
+			     configinfo.collection)) {
+	outconvertclass text_t2ascii;
+	logout << text_t2ascii 
+	       << "Warning: couldn't read collect.cfg file for collection \""
+	       << configinfo.collection << "\", gsdlhome=\"" 
+	       << configinfo.gsdlhome << "\"\n";
+	++here;
+	continue;
+      }
+
+      if (!(*here).second.c->init (logout)) return false;
+
+      (*here).second.c->configure("httpdomain",httpdomain);
+      (*here).second.c->configure("httpprefix",httpprefix);
+    }
+    ++here;
+  }
+
+  return true;
+}
+
+collectservermapclass collectset::servers()
+{ return cservers;
+}
+
+
+void collectset::add_all_collections(const text_t &gsdlhome) {
+
+  text_tarray collections;
+  text_t collectdir = filename_cat(gsdlhome, "collect");
+  if (read_dir(collectdir, collections)) {
+
+    text_tarray::const_iterator thiscol = collections.begin();
+    text_tarray::const_iterator endcol = collections.end();
+
+    while (thiscol != endcol) {
+    
+      // ignore the modelcol
+      if (*thiscol == "modelcol") {
+	++thiscol;
+	continue;
+      }
+    
+      // create collection server and add to null protocol
+      this->add_collection (*thiscol, gsdlhome);
+    
+      ++thiscol;
+    }
+  }
+}
+
+// add_collection sets up the collectionserver and calls
+// add_collectserver
+void collectset::add_collection (const text_t &collection, 
+				 const text_t &gsdlhome) {
+
+  // if an old collection server exists for this collection we should
+  // delete it first
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+  while (here != end) {
+    if ((*here).second.c != NULL && (*here).first == collection) {
+      delete (*here).second.c;
+      cservers.erase (here);
+      break;
+    }
+    ++here;
+  }
+      
+  // read config file to see if built with mg, mgpp, or lucene
+  // -- we can rely on the collection (and therefore the build.cfg)
+  // being here since this is the null protocol - a nicer way to 
+  // do this would be preferable though - Stefan.
+  text_t buildtype = "mg"; // mg is default
+
+  text_tarray cfgline;
+  text_t key;
+  text_t build_cfg = filename_cat(gsdlhome, "collect", collection, "index", "build.cfg");
+  char *build_cfgc = build_cfg.getcstr();
+  ifstream confin(build_cfgc);
+
+  if (confin) {
+    while (read_cfg_line(confin, cfgline) >= 0) {
+      if (cfgline.size() == 2) {
+	key = cfgline[0];
+	cfgline.erase(cfgline.begin());
+	if (key == "buildtype") {
+	  buildtype = cfgline[0];
+	  break;
+	}
+      }
+    }
+    confin.close();
+  }
+  delete []build_cfgc;
+
+  collectserver *cserver = new collectserver();
+  gdbmclass *gdbmhandler = new gdbmclass();
+
+  // add a null filter
+  filterclass *filter = new filterclass ();
+  cserver->add_filter (filter);
+      
+  // add a browse filter
+  browsefilterclass *browsefilter = new browsefilterclass();
+  browsefilter->set_gdbmptr (gdbmhandler);
+
+  cserver->add_filter (browsefilter);  
+ 
+  if (buildtype == "mg") {
+    mgsearch = new mgsearchclass();
+ 
+    // add a query filter
+    mgqueryfilterclass *queryfilter = new mgqueryfilterclass();
+    queryfilter->set_gdbmptr (gdbmhandler);
+    queryfilter->set_textsearchptr (mgsearch);
+    cserver->add_filter (queryfilter);
+    
+    // add a mg and gdbm source
+    mggdbmsourceclass *mggdbmsource = new mggdbmsourceclass ();
+    mggdbmsource->set_gdbmptr (gdbmhandler);
+    mggdbmsource->set_textsearchptr (mgsearch);
+    cserver->add_source (mggdbmsource);
+
+  } else if (buildtype == "mgpp") {
+      
+    mgppsearch = new mgppsearchclass();
+
+    // add a query filter
+    mgppqueryfilterclass *queryfilter = new mgppqueryfilterclass();
+    queryfilter->set_gdbmptr (gdbmhandler);
+    queryfilter->set_textsearchptr (mgppsearch);
+    cserver->add_filter (queryfilter);
+      
+    // add a mg and gdbm source
+    mggdbmsourceclass *mggdbmsource = new mggdbmsourceclass ();
+    mggdbmsource->set_gdbmptr (gdbmhandler);
+    mggdbmsource->set_textsearchptr (mgppsearch);
+    cserver->add_source (mggdbmsource);
+
+  } else if (buildtype == "lucene") {
+    lucenesearch = new lucenesearchclass();
+
+    // add a query filter
+    lucenequeryfilterclass *queryfilter = new lucenequeryfilterclass();
+    queryfilter->set_gdbmptr (gdbmhandler);
+    queryfilter->set_textsearchptr (lucenesearch);
+    cserver->add_filter (queryfilter);
+      
+    // add a lucene and gdbm source
+    lucenegdbmsourceclass *lucenegdbmsource = new lucenegdbmsourceclass ();
+    lucenegdbmsource->set_gdbmptr (gdbmhandler);
+    lucenegdbmsource->set_textsearchptr (lucenesearch);
+    cserver->add_source (lucenegdbmsource);
+  }
+
+  // inform collection server and everything it contains about its
+  // collection name
+  cserver->configure ("collection", collection);
+  cserver->configure ("gsdlhome", gsdlhome);
+
+  /* Removed from add_collection 24/11/2000; already done elsewhere in collectset.  
+  // configure receptionist's collectinfo structure 
+  text_tarray colinfo;
+  colinfo.push_back (collection);
+  colinfo.push_back (gsdlhome);
+  colinfo.push_back (gdbmhome);
+  */
+  cservers.addcollectserver (cserver);
+}
+
+void collectset::remove_all_collections () {
+
+  // first unload any cached mg databases
+  if (mgsearch != NULL) {
+    mgsearch->unload_database();
+  }
+
+  // now delete the collection server objects
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+
+  while (here != end) {
+    if ((*here).second.c != NULL) {
+      delete (*here).second.c;
+    }
+    ++here;
+  }
+  cservers.clear();
+}
+
+
+// remove_collection deletes the collection server of collection.
+// This only needs to be called if a collectionserver is to be
+// removed while the library is running. The destructor function
+// cleans up all collectservers when the program exits.
+void collectset::remove_collection (const text_t &collection, ostream &logout) {
+
+  // do nothing if no collection server exists for this collection 
+  if (cservers.getcollectserver(collection) == NULL) return;
+
+  // first unload any cached mg databases - we may need to do something
+  // similar to this for mgpp and lucene too
+  if (mgsearch != NULL) {
+    mgsearch->unload_database();
+  }
+
+  // now delete the collection server object
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+
+  while (here != end) {
+    if ((*here).second.c != NULL && (*here).first == collection) {
+      delete (*here).second.c;
+      cservers.erase (here);
+      return;
+    }
+    ++here;
+  }
+  outconvertclass text_t2ascii;
+  logout << text_t2ascii << "nullproto::remove_collection: failed to remove collectserver for "
+	 << collection << "\n";
+}
+
+void collectset::configure(const text_t &key, const text_tarray &cfgline)
+{
+  if (key == "collection" || key == "collectdir") return;
+
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+
+  while (here != end) {
+    assert ((*here).second.c != NULL);
+    if ((*here).second.c != NULL) {
+      if (key == "collectinfo") {
+	if ((*here).first == cfgline[0]) {
+	  (*here).second.c->configure ("gsdlhome", cfgline[1]);
+	  (*here).second.c->configure ("gdbmhome", cfgline[2]);
+	}
+      } else {
+	(*here).second.c->configure (key, cfgline);
+      }
+    }
+
+    ++here;
+  }
+}
+
+void collectset::getCollectionList (text_tarray &collist) 
+{
+  collist.erase(collist.begin(),collist.end());
+
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+  while (here != end) {
+    assert ((*here).second.c != NULL);
+    if ((*here).second.c != NULL) {
+      collist.push_back ((*here).second.c->get_collection_name());
+    }
+    ++here;
+  }
+}
+
+void collectset::setReceptionistServers(receptionist &recpt, text_t &gsdlhome)
+{ 
+  collectservermapclass::iterator here = cservers.begin();
+  collectservermapclass::iterator end = cservers.end();
+  while (here != end) {
+    assert ((*here).second.c != NULL);
+
+    text_tarray colinfo;
+    colinfo.push_back((*here).second.c->get_collection_name());
+    colinfo.push_back(gsdlhome);
+    colinfo.push_back(gsdlhome);
+    recpt.configure("collectinfo", colinfo);
+
+    ++here;
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectset.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectset.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/collectset.h	(revision 10506)
@@ -0,0 +1,67 @@
+/************************************************************
+ * 
+ * Collection set
+ *
+ ************************************************************/
+
+#ifndef COLLECTSET_H
+#define COLLECTSET_H
+
+#include "collectserver.h"
+#include "cnfgable.h"
+#include "receptionist.h"
+#include "mgsearch.h"
+#include "mgppsearch.h"
+#include "lucenesearch.h"
+
+class collectset : public configurable
+{
+ protected:
+  collectservermapclass cservers;
+  mgsearchclass         *mgsearch;
+  mgppsearchclass       *mgppsearch;
+  lucenesearchclass     *lucenesearch;
+  int                   noofservers;
+  text_t                httpdomain;
+  text_t                httpprefix;
+
+ public:
+  collectset(text_t &gsdlhome);
+  // this constructor is used by the local library
+  collectset() {}
+
+  ~collectset();
+
+  // initialise the collections
+  bool init(ostream &logout);
+
+  // configure all the servers as supplied
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  // Add/remove collections
+  void add_all_collections (const text_t &gsdlhome);
+  void remove_all_collections ();
+
+  void remove_collection (const text_t &collection, ostream &logout);
+  void add_collection (const text_t &collection, 
+		       const text_t &gsdlhome);
+
+  // return the total number of servers in the set
+  int size();
+
+  void getCollectionList(text_tarray &collist);
+
+  // return the component map
+  collectservermapclass servers();
+
+  // configure a receptionist with the list of servers
+  void setReceptionistServers(receptionist &recpt, text_t &gsdlhome);
+
+  // return an individual collection server
+  collectserver *getCollectServer(const text_t &collection)
+    {
+      return cservers.getcollectserver(collection);
+    }
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/colservrconfig.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/colservrconfig.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/colservrconfig.cpp	(revision 10506)
@@ -0,0 +1,144 @@
+/**********************************************************************
+ *
+ * colservrconfig.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+/*
+   $Log$
+   Revision 1.5  2005/04/11 21:08:04  kjdon
+   delete -> delete [] change submitted by Emanuel Dejanu
+
+   Revision 1.4  2001/01/25 18:26:44  cs025
+   Included CORBA branch for first time
+
+   Revision 1.2.2.1  2000/04/04 15:02:31  cs025
+   Corba first commit
+
+   Revision 1.2  1999/09/07 04:57:20  sjboddie
+   added gpl notice
+
+   Revision 1.1  1999/02/21 22:32:55  rjmcnab
+
+   Initial revision.
+
+ */
+
+
+#include "colservrconfig.h"
+#include "fileutil.h"
+#include "cfgread.h"
+
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace/std/iostream>
+#  include <ospace/std/fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+// collect_cfg_read reads collect.cfg returning true on success.
+bool collect_cfg_read (collectserver &cserver, const text_t &gsdlhome,
+		       const text_t &collection) {
+  text_t filename = filename_cat (gsdlhome, "collect");
+  filename = filename_cat (filename, collection);
+  filename = filename_cat (filename, "etc");
+  filename = filename_cat (filename, "collect.cfg");
+  if (!file_exists (filename)) {
+    filename = filename_cat (gsdlhome, "etc");
+    filename = filename_cat (filename, "collect.cfg");
+    if (!file_exists (filename)) return false;
+  }
+
+  return cserver.read_configfile(filename);
+  /*
+  // read in the collection configuration file
+  text_t key;
+  text_tarray cfgline;
+  char *cstr = filename.getcstr();
+  ifstream confin (cstr);
+  delete []cstr;
+
+  if (confin) {
+    while (read_cfg_line(confin, cfgline) >= 0) {
+      if (cfgline.size () >= 2) {
+	key = cfgline[0];
+	cfgline.erase(cfgline.begin());
+
+	// configure the collection server
+	cserver.configure (key, cfgline);
+      }
+    }
+    confin.close ();
+    return true;
+  }
+  return false;
+  */
+}
+
+
+// build_cfg_read reads build.cfg and returns true on success.
+bool build_cfg_read (collectserver &cserver, const text_t &gsdlhome,
+		     const text_t &collection) {
+  text_t filename = filename_cat (gsdlhome, "collect");
+  filename = filename_cat (filename, collection);
+  filename = filename_cat (filename, "index");
+
+  filename = filename_cat (filename, "build.cfg");
+  if (!file_exists (filename)) {
+    filename = filename_cat (gsdlhome, "index");
+    filename = filename_cat (filename, "build.cfg");
+    if (!file_exists (filename)) return false;
+  }
+
+  return cserver.read_configfile(filename);
+
+  /*
+  // read in the build configuration file
+  text_t key;
+  text_tarray cfgline;
+  char *cstr = filename.getcstr();
+  ifstream confin (cstr);
+  delete []cstr;
+
+  if (confin) {
+    while (read_cfg_line(confin, cfgline) >= 0) {
+      if (cfgline.size () >= 2) {
+	key = cfgline[0];
+	cfgline.erase(cfgline.begin());
+
+	// configure the collection server
+	cserver.configure (key, cfgline);
+      }
+    }
+    confin.close ();
+    return true;
+  }
+  return false;
+  */
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/colservrconfig.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/colservrconfig.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/colservrconfig.h	(revision 10506)
@@ -0,0 +1,45 @@
+/**********************************************************************
+ *
+ * colservrconfig.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef COLSERVRCONFIG_H
+#define COLSERVRCONFIG_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "collectserver.h"
+
+
+// collect_cfg_read reads collect.cfg returning true on success.
+bool collect_cfg_read (collectserver &cserver, const text_t &gsdlhome,
+		       const text_t &collection);
+
+// build_cfg_read reads build.cfg and returns true on success.
+bool build_cfg_read (collectserver &cserver, const text_t &gsdlhome,
+		     const text_t &collection);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/corbaServer.mpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/corbaServer.mpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/corbaServer.mpp	(revision 10506)
@@ -0,0 +1,489 @@
+// Standard headers
+#include <iostream.h>
+#include <fstream.h>
+
+// protocol headers
+#include "corbaiface.h"
+using namespace gsdlInterface;
+
+#include "corbaconv_text_t.h"
+
+// library headers
+#include "fileutil.h"
+//#include "gsdlhome.h"
+
+// greenstone headers
+#include "comtypes.h"
+#include "recptproto.h"
+#include "nullproto.h"
+
+// local headers
+#include "corbatext_t.h"
+
+void corbatext_setToCorbaArray(text_tset set, corbatext_tset *cset);
+void corbatext_corbaArrayToSet(corbatext_tset cset, text_tset *set);
+void corbatext_mapToCorbaMap(text_tmap map, corbatext_tmap *tm);
+void corbaresponse_resultDocInfoToCorba(ResultDocInfo_tarray docinfo, corbaResultDocInfo_array &corbainfo);
+
+void corbaresponse_termInfoToCorba(TermInfo_tarray terminfo, corbaTermInfo_array &corbainfo) {
+  TermInfo_tarray::iterator here = terminfo.begin();
+  TermInfo_tarray::iterator end  = terminfo.end();
+  unsigned int i;
+	
+  i = 0;
+
+  while (here != end) 
+    {
+      corbainfo.length(i+1);
+      
+      corbainfo[i].frequency = here->freq;
+      corbaconv_text_t::getCorbatext(here->term,corbainfo[i].term);
+      corbatext_arrayToCorbaArray(here->matchTerms, &corbainfo[i].matchTerms);
+
+      i ++;
+      here ++;
+    }
+  cout << "Terminfo " << i << endl;
+}
+
+void corbatext_optionValueArrayToC(corbaOptionValue_array corba, OptionValue_tarray &array)
+{
+  unsigned int i = 0;
+  OptionValue_t option;
+
+  for (i = 0; i < corba.length(); i ++)
+    {
+      corbaconv_text_t::setCorbatext(option.name,corba[i].name);
+      corbaconv_text_t::setCorbatext(option.value,corba[i].value);
+
+      // cout << corbatext_string(corba[i].name) << "?" << option
+
+      array.push_back(option);
+    }
+}
+
+class corbaServer : virtual public corbaiface_skel
+{
+private:
+  text_tarray collections;
+  recptproto *protocol;
+  text_t      gsdlhome;
+
+  void openLogfile(text_t extension, ofstream &out)
+  {
+    char *cfilename;
+    text_t filename;
+
+    filename = filename_cat(gsdlhome, extension);
+    cfilename = filename.getcstr();
+
+    out.open(cfilename);
+    delete cfilename;
+  }
+
+public:
+  corbaServer(recptproto *protocol, text_t home)
+  { 
+    text_t dirname;
+    char * cdirname;
+
+    cout << "CorbaServer: gsdlhome = " << home << endl;
+
+    this->gsdlhome = home;
+    cout << gsdlhome.getcstr() << endl;
+    dirname = filename_cat(gsdlhome, "/collect");
+    cdirname = dirname.getcstr();
+    if (!read_dir (cdirname, collections)) {
+      cout << "Unable to read the gsdl directory; terminating" << endl;
+      exit (1);
+    }
+    delete cdirname;
+
+    cout << "Constructing set list server" << endl;
+    this->protocol = protocol;
+
+  }
+  
+  CORBA::Boolean initialise(corbaComError &err) 
+  {
+      ofstream      logout;
+      int           reply;
+      comerror_t    error = noError;
+
+      this->openLogfile("/etc/corbaout.txt", logout);
+      reply = protocol->init(error, logout);
+      logout.close();
+      return (reply != 0 ? 1 : 0);
+    }
+
+  void configure(const corbatext_t &corbaKey, const corbatext_tarray &corbaCfgline,corbaComError &err)
+    {
+      text_t        key;
+      text_tarray   cfgline;
+      comerror_t    error = noError;
+
+      corbaconv_text_t::setCorbatext(key,corbaKey);
+      corbatext_corbaArrayToArray(corbaCfgline, &cfgline);
+
+
+      // ****
+      cout << "Recieved " << key << " = ";
+      for (int unsigned i=0; i<cfgline.size(); i++)
+	{
+	  cout << cfgline[i] << " ";
+	}
+      cout << endl;
+
+      // DB // ****
+      if (key=="gsdlhome")
+	{  
+	  text_tarray cfgline;
+	  cfgline.push_back (gsdlhome);
+	  cout << "Changing gsdlhome to " << gsdlhome << endl;
+	  protocol->configure(key, cfgline, error);
+	}
+      else if (key=="httpdomain")
+	{
+	  // Only let gsdlhome through !!!! // ****
+	  cout << "Supressing httpdomain" << endl;
+	}
+      else if (key=="httpprefix")
+	{
+	  cout << "Supressing httpprefix" << endl;
+	}
+      else
+	{ 
+	  protocol->configure(key, cfgline,error);
+	}
+    }
+
+  void hasCollection(const corbatext_t &corbaCollect, CORBA::Boolean &has,
+                     corbaComError &error) {
+    // do nowt!
+    corbaconv_text_t *cct;
+    bool    _has;
+    comerror_t err = noError;
+    ofstream logout;
+
+    this->openLogfile("/etc/corbaout.txt", logout);
+
+    cct = new corbaconv_text_t(corbaCollect);
+
+    cout << "Collection: " << cct->getcstr() << endl;
+
+    protocol->has_collection(*cct, _has, err, logout); // 'cct' typecast to text_t
+    if (_has)
+      { 
+	has = 1;
+      }
+    else
+      {
+	has = 0;
+      }
+
+    // cout << "  " << has << endl;
+
+    delete cct;
+
+    error = corbaNoError;
+    logout.close();
+  }
+
+  void ping(const struct corbatext_t &corbaCollect, CORBA::Boolean &wasSuccess, corbaComError &corbaError)
+  { 
+    text_t collection;
+    bool   success;
+    comerror_t error = noError;
+    ofstream logout;
+
+    this->openLogfile("/etc/corbaout.txt", logout);
+
+    corbaconv_text_t::setCorbatext(collection,corbaCollect);
+    protocol->ping(collection, success, error, logout);
+
+    corbaError = (corbaComError) error;
+    wasSuccess = (CORBA::Boolean) success;
+    logout.close();
+  }
+
+  void filter(const struct corbatext_t &corbaCollect,
+	      const struct corbaFilterRequest &corbaRequest,
+	      struct corbaFilterResponse &corbaResponse,
+	      corbaComError &corbaError)
+  {
+    // variables for action
+    FilterRequest_t request;
+    FilterResponse_t response;
+    comerror_t       error = noError;
+    text_t           collection;
+    ofstream         logout;
+
+    this->openLogfile("/etc/corbaout.txt", logout);
+
+    // copy collection id
+    corbaconv_text_t::setCorbatext(collection,corbaCollect);
+
+    // copy request values
+    corbaconv_text_t::setCorbatext(request.filterName,corbaRequest.filter);
+    corbatext_optionValueArrayToC(corbaRequest.filterOptions, request.filterOptions);
+    corbatext_corbaArrayToArray(corbaRequest.docSet, &request.docSet);
+    request.filterResultOptions = corbaRequest.filterResultOptions;
+    corbaconv_text_t::setCorbatext(request.requestParams,corbaRequest.requestParams);
+    corbaconv_text_t::setCorbatext(request.refParams,corbaRequest.refParams);
+    corbatext_corbaArrayToSet(corbaRequest.fields, &request.fields);
+    request.getParents = corbaRequest.getParents;
+
+    protocol->filter(collection, request, response, error, logout);
+
+    // copy response values
+    corbaResponse.numDocs = response.numDocs;
+    corbaResponse.isApprox = (::gsdlInterface::corbaIsApprox) response.isApprox;
+    corbaresponse_termInfoToCorba(response.termInfo, corbaResponse.termInfo);
+    corbaresponse_resultDocInfoToCorba(response.docInfo, corbaResponse.docInfo);
+
+    // tidy up variables
+    logout.close();
+    corbaError = (corbaComError) error;
+    cout << "Filter prepared" << corbaResponse.docInfo.length() << "," << corbaResponse.numDocs << endl;
+  }
+
+  void getCollectInfo(const struct corbatext_t &corbaCollect,
+                      corbaColInfoResponse &corbaResponse,
+                      corbaComError &corbaError)
+  {
+    ColInfoResponse_t response;
+    comerror_t       error = noError;
+    text_t           collection;
+    ofstream logout;
+
+    this->openLogfile("/etc/corbaout.txt", logout);
+
+    corbaconv_text_t::setCorbatext(collection,corbaCollect);
+    protocol->get_collectinfo(collection, response, error, logout);
+
+    cout << "IsPublic  = " << ((response.isPublic)?"True":"False") << endl;
+    cout << "IsBeta    = " << ((response.isBeta)  ?"True":"False") << endl;
+    cout << "BuildDate = " << response.buildDate << endl;
+    cout << "NumDocs   = " << response.numDocs << endl;
+    cout << "NumBytes  = " << response.numBytes << endl;
+    cout << "NumWords  = " << response.numWords << endl;
+
+    corbaResponse.isPublic  = response.isPublic;
+    corbaResponse.isBeta    = response.isBeta;
+    corbaResponse.buildDate = response.buildDate;
+    corbatext_arrayToCorbaArray(response.languages, &corbaResponse.languages);
+    corbatext_arrayToCorbaArray(response.ccsCols, &corbaResponse.ccsCols);
+    corbaResponse.numDocs   = response.numDocs;
+    corbaResponse.numBytes  = response.numBytes;
+    corbaResponse.numWords  = response.numWords;
+
+    corbatext_mapToCorbaMap(response.collectionmeta, &corbaResponse.collectionMeta);
+    corbatext_mapToCorbaMap(response.format, &corbaResponse.format);
+    corbatext_mapToCorbaMap(response.building, &corbaResponse.building);
+    corbaconv_text_t::getCorbatext(response.httpdomain,corbaResponse.httpdomain);
+
+    corbaconv_text_t::getCorbatext(response.httpprefix,corbaResponse.httpprefix);
+    corbaconv_text_t::getCorbatext(response.receptionist,corbaResponse.receptionist);
+
+    /* text_tmap::iterator f_here = response.format.begin();
+    text_tmap::iterator f_end = response.format.end();
+    while (f_here!=f_end)
+    {
+      cout << "**** format: " << f_here->first << " = " << f_here->second << endl;
+      f_here++;
+    } 
+    */ // ****
+
+    logout.close();
+    corbaError = (corbaComError) error;
+  }
+
+  void getFilterOptions(const struct corbatext_t &corbaCollect,
+			const struct corbatext_t &corbaFilterName,
+			struct corbaFilterOptionsResponse &corbaResponse,
+			enum corbaComError &corbaError)
+  {   
+    text_t collection;
+    InfoFilterOptionsRequest_t request;
+    InfoFilterOptionsResponse_t response;
+    comerror_t error = noError;
+    unsigned int i;
+    ofstream logout;
+
+    this->openLogfile("/etc/corbaout.txt", logout);
+
+    corbaconv_text_t::setCorbatext(collection,corbaCollect);
+    corbaconv_text_t::setCorbatext(request.filterName,corbaFilterName);
+    protocol->get_filteroptions(collection, request, response, error, logout);
+
+    // decode filters back into corba format
+    FilterOption_tmap::iterator here = response.filterOptions.begin();
+    FilterOption_tmap::iterator end = response.filterOptions.end();
+    i = 0;
+    while (here != end)
+      {
+	// set array for name/options to be one bigger
+	corbaResponse.names.length(i+1);
+	corbaResponse.options.length(i+1);
+
+	// get left-hand side of map
+	corbaconv_text_t::getCorbatext((*here).first,corbaResponse.names[i]);
+	
+	// get right-hand side of map
+	corbaconv_text_t::getCorbatext((*here).second.name,corbaResponse.options[i].name);
+	corbaResponse.options[i].type = 
+	  (::gsdlInterface::corbaFilterType)(*here).second.type;
+	corbaResponse.options[i].repeatable = 
+	  (::gsdlInterface::corbaFilterRepeatable)(*here).second.repeatable;
+	corbaconv_text_t::getCorbatext((*here).second.defaultValue,corbaResponse.options[i].defaultValue);
+	corbatext_arrayToCorbaArray((*here).second.validValues, &corbaResponse.options[i].validValues);
+
+	// take next iterators
+	i++;
+	here ++;
+      }
+
+    logout.close();
+    corbaError = (corbaComError) error;
+  }
+
+  void getFilterInfo(const struct corbatext_t &corbaCollect, 
+		     corbatext_tarray &filterNames, 
+		     enum corbaComError &corbaError)
+  { text_tarray ta;
+    comerror_t error = noError;
+    text_t collection;    
+    InfoFiltersResponse_t response;
+    ofstream logout;
+
+    this->openLogfile("/etc/corbaout.txt", logout);
+
+    corbaconv_text_t::setCorbatext(collection,corbaCollect);
+    cout << collection.getcstr() << endl;
+			    
+    protocol->get_filterinfo(collection, response, error, logout);
+    corbatext_setToCorbaArray(response.filterNames, &filterNames);
+
+    corbaError = (corbaComError) error;
+    logout.close();
+  }
+  
+  void getDocument(const struct corbatext_t &corbaCollection, struct corbaDocRequest &corbaRequest, 
+		   struct corbaDocResponse &corbaResponse,  enum corbaComError &corbaError)
+  { DocumentRequest_t request;
+    DocumentResponse_t response;
+    comerror_t         error = noError;
+    text_t             collection;
+    ofstream logout;
+
+    this->openLogfile("/etc/corbaout.txt", logout);
+
+    // set up request
+    corbaconv_text_t::setCorbatext(collection,corbaCollection);
+    corbaconv_text_t::setCorbatext(request.OID,corbaRequest.OID);
+    corbaconv_text_t::setCorbatext(request.docType,corbaRequest.docType);
+    corbaconv_text_t::setCorbatext(request.docFormat,corbaRequest.docFormat);
+
+    // do actual get document
+    protocol->get_document(collection, request, response, error, logout);
+    corbaconv_text_t::getCorbatext(response.doc,corbaResponse.doc);
+
+    // decode response
+    corbaError = (corbaComError) error;
+
+    logout.close();
+  }
+
+  void collectionList(corbatext_tarray &corbalist, corbaComError &error)
+  {
+    /* stringSeq *reply;
+    unsigned int i;
+    char *istring; */
+
+    text_tarray collist;
+    comerror_t  err;
+    ofstream logout;
+
+    cout << "Received collection list request" << endl;
+
+    this->openLogfile("/etc/corbaout.txt", logout);
+
+    protocol->get_collection_list(collist, err, logout);
+
+    /*    reply = new stringSeq(collections.size());
+    
+    (*reply).length(collections.size());
+    for (i = 0; i < collections.size(); i ++)
+      {
+	istring = collections[i].getcstr();
+	(*reply)[i] = CORBA::string_dup(istring);
+	delete istring;
+      }
+    
+    return reply;
+    */
+
+    corbatext_arrayToCorbaArray(collist, &corbalist);
+    cout << "Replying " << collist.size() << ": " << endl;
+
+    for (int unsigned i = 0; i < collist.size(); i ++)
+      {
+	cout << collist[i];
+	if (i<collist.size()-1) cout << ", ";
+      }
+    cout << endl;
+
+    logout.close();
+    // CORBA::string_dup(_listString);
+  }
+};
+
+int main (int argc, char *argv[])
+{
+  nullproto protocol;
+  collectset *cservers;
+  text_t     gsdlhome;
+
+  cservers = new collectset(gsdlhome);
+  protocol.set_collectset(cservers);
+
+  cout << "Started Corba ..." << endl;
+
+  // ORB initialization
+  CORBA::ORB_var orb = CORBA::ORB_init( argc, argv, "mico-local-orb" );
+  CORBA::BOA_var boa = orb->BOA_init( argc, argv, "mico-local-boa" );
+
+  cout << "Initialised ORB and BOA" << endl;
+
+  corbaServer* server = new corbaServer(&protocol, gsdlhome);
+
+  cout << "Initialised server" << endl;
+
+  CORBA::String_var ref = orb->object_to_string( server );
+
+  cout << "Mapped Corba object to string" << endl;
+
+  // write id to "naming service"
+  ofstream out ("/tmp/localcorba.objid");
+	if (out.is_open()) {
+		out << ref << endl;
+		if (out.fail() || out.bad()) {
+			cout << "Failed " << endl;
+		}
+		out.close ();
+	}
+	else {
+		cout << "Unable to write string to file /tmp/localcorba.objid" << endl;
+		cout << "Please check the file permissions/ownership" << endl;
+		return 0;
+	}
+  cout << "Corba string is " << ref << endl;
+
+  // indicate readiness and run
+  boa->impl_is_ready( CORBA::ImplementationDef::_nil() );
+  orb->run ();
+  CORBA::release( server );
+  return 0;
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_document.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_document.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_document.cpp	(revision 10506)
@@ -0,0 +1,104 @@
+
+#include <stdio.h>
+#include <string.h>
+#include <expat.h>
+#include "gsdlunicode.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+using namespace std;
+#endif
+
+#include "queryinfo.h"
+
+#include "expat_document.h"
+
+#include "text_t.h"
+#include "fileutil.h"
+#include "expat_resultset.h"
+
+struct resultpack {
+  text_t *current_text;
+  text_t *section_num;
+  text_t *section_level;
+  bool store_text;
+};
+
+static void XMLCALL 
+startElement(void *userData, const char *name, const char **attributes)
+{
+  resultpack * rpack_ptr = (resultpack*)userData;
+  text_t element_name = (char*)name;
+  if (element_name == *(rpack_ptr->section_level)) {
+    text_t id_att = (char *)get_attribute(attributes,"gs2:id");
+    if (id_att == *(rpack_ptr->section_num)) {
+      rpack_ptr->store_text = true;
+    }
+    
+  }
+}
+
+static void XMLCALL
+endElement(void *userData, const char *name)
+{
+  resultpack * rpack_ptr = (resultpack*)userData;
+  text_t element_name = (char*)name;
+  if (element_name == *(rpack_ptr->section_level)) {
+    if (rpack_ptr->store_text == true) {
+      // we have finished now, can we quit this??
+      rpack_ptr->store_text = false;
+    }
+  }
+  
+}
+
+static void XMLCALL
+characterData(void *userData, const char * text, int len) {
+  resultpack * rpack_ptr = (resultpack*)userData;
+  if  (rpack_ptr->store_text) {
+    rpack_ptr->current_text->appendcarr(text, len);
+  }
+}
+
+
+int expat_document(const text_t &filename, const text_t &sec_level, const text_t &sec_num, text_t & doc_content)
+{
+  text_t current_text;
+  current_text.clear();
+  text_t section_num = sec_num;
+  text_t section_level = sec_level;
+
+  resultpack rpack = { &current_text, &section_num, &section_level, false};
+  //cerr << "sec num = "<<sec_num<<", sec level="<<sec_level<<", filename="<<filename<<endl;
+  text_t doc_text;
+  read_file(filename, doc_text);
+
+  char* c_doc_text = doc_text.getcstr();
+  XML_Parser parser = XML_ParserCreate(NULL);
+  
+  XML_SetUserData(parser, &rpack);
+  XML_SetElementHandler(parser, startElement, endElement);
+  XML_SetCharacterDataHandler(parser, characterData);
+  int return_status = 0;
+  const int parse_status 
+    = XML_Parse(parser, c_doc_text, strlen(c_doc_text), XML_TRUE);
+  
+  if (parse_status == XML_STATUS_ERROR) {
+    fprintf(stderr,
+	    "%s at line %d\n",
+	    XML_ErrorString(XML_GetErrorCode(parser)),
+	    XML_GetCurrentLineNumber(parser));
+    return_status = 1;
+  }
+  
+  XML_ParserFree(parser);
+  free(c_doc_text);
+  doc_content = to_uni(current_text);  // Vital for non-ASCII documents
+  return return_status;
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_document.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_document.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_document.h	(revision 10506)
@@ -0,0 +1,9 @@
+#ifndef gs_expat_document_h
+#define gs_expat_document_h
+
+class text_t;
+
+int expat_document(const text_t &filename, const text_t & section_level,
+		   const text_t &section_num, text_t & doc_content);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_resultset.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_resultset.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_resultset.cpp	(revision 10506)
@@ -0,0 +1,118 @@
+
+#include <stdio.h>
+#include <string.h>
+#include <expat.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+using namespace std;
+#endif
+
+#include "text_t.h"
+#include "queryinfo.h"
+
+struct queryresultpack {
+  queryresultsclass* queryresult_ptr;
+  int match_count;
+};
+
+char* get_attribute(const char** attr, char* att_name)
+{
+  char* att_val = NULL;
+
+  for (int i = 0; attr[i]; i += 2) {
+    if (strcmp(attr[i],att_name)==0) {
+      att_val = strdup(attr[i+1]);
+    }
+  }
+
+  return att_val;
+}
+
+static void XMLCALL 
+startElement(void *userData, const char *name, const char **attributes)
+{
+  queryresultpack* qrpack_ptr = (queryresultpack*)userData;
+  queryresultsclass* queryresult_ptr = qrpack_ptr->queryresult_ptr;
+
+  text_t element_name = (char*)name;
+
+  if (element_name=="MatchingDocsInfo") {
+    char* num_match_docs_str = get_attribute(attributes,"num");
+    if (num_match_docs_str != NULL) {
+      int num_match_docs = atoi(num_match_docs_str);
+
+      queryresult_ptr->docs_matched = num_match_docs;
+      free(num_match_docs_str);
+    }
+    else {
+            queryresult_ptr->docs_matched = 0;
+    }
+
+  }
+
+
+  if (element_name=="Match") {
+
+    char* id = get_attribute(attributes,"id");
+    if (id!=NULL) {
+      int id_num = atoi(id);
+    
+      docresultclass doc;
+      doc.clear();
+      doc.docnum = id_num;
+      doc.docweight = qrpack_ptr->match_count;
+      queryresult_ptr->docs.docset[doc.docnum] = doc;
+      queryresult_ptr->docs.docorder.push_back(doc.docnum);
+      ++qrpack_ptr->match_count;
+
+      free(id);
+    }
+    
+  }
+}
+
+static void XMLCALL
+endElement(void *userData, const char *name)
+{
+  // no need to do anything
+}
+
+
+
+
+int expat_resultset(text_t& xml_text, queryresultsclass& queryresult)
+{
+  queryresult.clear();
+  queryresultpack qrpack = { &queryresult, 0 };
+
+  char * xml_text_cstr = xml_text.getcstr();
+  
+  cerr << "**** xml_text = " << xml_text.getcstr() << endl;
+  
+  XML_Parser parser = XML_ParserCreate(NULL);
+  
+  XML_SetUserData(parser, &qrpack);
+  XML_SetElementHandler(parser, startElement, endElement);
+  
+  int return_status = 0;
+  const int parse_status 
+    = XML_Parse(parser, xml_text_cstr, strlen(xml_text_cstr), XML_TRUE);
+  
+  if (parse_status == XML_STATUS_ERROR) {
+    fprintf(stderr,
+	    "%s at line %d\n",
+	    XML_ErrorString(XML_GetErrorCode(parser)),
+	    XML_GetCurrentLineNumber(parser));
+    return_status = 1;
+  }
+  
+  XML_ParserFree(parser);
+  free(xml_text_cstr);
+  
+  return return_status;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_resultset.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_resultset.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/expat_resultset.h	(revision 10506)
@@ -0,0 +1,11 @@
+#ifndef gs_expat_resultset_h
+#define gs_expat_resultset_h
+
+class text_t;
+class queryresultsclass;
+
+char* get_attribute(const char** attr, char* att_name);
+int expat_resultset(text_t& xml_text, queryresultsclass& queryresult);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/filter.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/filter.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/filter.cpp	(revision 10506)
@@ -0,0 +1,310 @@
+/**********************************************************************
+ *
+ * filter.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "filter.h"
+#include "fileutil.h"
+#include <assert.h>
+
+
+// default constructor does nothing
+filterclass::filterclass () {
+}
+
+// default destructor does nothing
+filterclass::~filterclass () {
+}
+
+// configure should be called once for each configuration line
+// default configures the default filter options
+void filterclass::configure (const text_t &key, const text_tarray &cfgline) {
+  if (cfgline.size() >= 1) {
+    const text_t &value = cfgline[0];
+
+    if (key == "collection") collection = value;
+    else if (key == "collectdir") collectdir = value;
+    else if (key == "gsdlhome") gsdlhome = value;
+    else if (key == "gdbmhome") gdbmhome = value;
+    else if ((key == "filteroptdefault") && (cfgline.size() == 2)) {
+      // see if this filter has an option with this name
+      FilterOption_tmap::iterator thisfilteroption = 
+	filterOptions.find(cfgline[0]);
+      if (thisfilteroption != filterOptions.end())
+	(*thisfilteroption).second.defaultValue = cfgline[1];
+    }
+  }
+}
+
+// init should be called after all the configuration is done but
+// before any other methods are called
+// default checks all the filter option defaults
+bool filterclass::init (ostream &/*logout*/) {
+  // check all the filter defaults
+  FilterOption_tmap::iterator filteroption_here = filterOptions.begin();
+  FilterOption_tmap::iterator filteroption_end = filterOptions.end();
+  while (filteroption_here != filteroption_end) {
+    (*filteroption_here).second.check_defaultValue ();
+    
+    ++filteroption_here;
+  }
+
+  if (gdbmhome.empty()) gdbmhome = gsdlhome;
+  
+  // get the collection directory name
+  if (collectdir.empty()) {
+    collectdir = filename_cat (gsdlhome, "collect", collection);
+  }
+  
+  return true;
+}
+
+// returns the name of this filter
+// default returns "NullFilter"
+text_t filterclass::get_filter_name () {
+  return "NullFilter";
+}
+
+// returns the current filter options
+void filterclass::get_filteroptions (InfoFilterOptionsResponse_t &response,
+				     comerror_t &err, ostream &/*logout*/) {
+  response.clear();
+  response.filterOptions = filterOptions;
+  err = noError;
+}
+
+// default returns nothing
+void filterclass::filter (const FilterRequest_t &request,
+			  FilterResponse_t &response,
+			  comerror_t &err, ostream &/*logout*/) {
+  ResultDocInfo_t resultdoc;
+
+  response.clear();
+
+  if ((request.filterResultOptions & FROID) ||
+      (request.filterResultOptions & FRmetadata)) {
+    // copy the OIDs from the request to the response
+    text_tarray::const_iterator here = request.docSet.begin();
+    text_tarray::const_iterator end = request.docSet.end();
+    while (here != end) {
+      resultdoc.OID = (*here);
+      response.docInfo.push_back(resultdoc);
+
+      ++here;
+    }
+  }
+
+  response.numDocs = response.docInfo.size();
+  response.isApprox = Exact;
+  err = noError;
+}
+
+
+bool operator==(const filterptr &x, const filterptr &y) {
+  return (x.f == y.f);
+}
+
+bool operator<(const filterptr &x, const filterptr &y) {
+  return (x.f < y.f);
+}
+
+
+// thefilter remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void filtermapclass::addfilter (filterclass *thefilter) {
+  // can't add a null filter
+  assert (thefilter != NULL);
+  if (thefilter == NULL) return;
+  
+  // can't add an filter with no name
+  assert (!(thefilter->get_filter_name()).empty());
+  if ((thefilter->get_filter_name()).empty()) return;
+
+  filterptr fptr;
+  fptr.f = thefilter;
+  filterptrs[thefilter->get_filter_name()] = fptr;
+}
+
+// getfilter will return NULL if the filter could not be found
+filterclass *filtermapclass::getfilter (const text_t &key) {
+  // can't find an filter with no name
+  assert (!key.empty());
+  if (key.empty()) return NULL;
+
+  iterator here = filterptrs.find (key);
+  if (here == filterptrs.end()) return NULL;
+  
+  return (*here).second.f;
+}
+
+
+
+
+// some useful functions for dealing with document sets
+
+// returns -1 if t1 is a child of t2
+// returns 0  if t1 and t2 are not parent-child related
+// returns 1  if t1 is a parent of t2
+int child_compare (const text_t &t1, const text_t &t2) {
+  text_t::const_iterator t1_here = t1.begin();
+  text_t::const_iterator t1_end = t1.end();
+  text_t::const_iterator t2_here = t2.begin();
+  text_t::const_iterator t2_end = t2.end();
+
+  while ((t1_here != t1_end) && (t2_here != t2_end)) {
+    if (*t1_here != *t2_here) return 0; // unrelated
+    ++t1_here;
+    ++t2_here;
+  }
+
+  if ((t1_here == t1_end) && (t2_here == t2_end)) return 0; // equal
+  if (t1_here != t1_end) {
+    if (*t1_here == '.') return -1; // t1 is child
+    else return 0; // unrelated
+  }
+
+  if (t2_here != t2_end) {
+    if (*t2_here == '.') return 1; // t2 is child
+    else return 0; // unrelated
+  }
+
+  return 0; // shouldn't get here...
+}
+
+// intersect places the result in set1
+void intersect (text_tset &set1, const text_tset &set2) {
+  text_tset resultset;
+  int childcomp = 0;
+
+  text_tset::const_iterator set1_here = set1.begin();
+  text_tset::const_iterator set1_end = set1.end();
+  text_tset::const_iterator set2_here = set2.begin();
+  text_tset::const_iterator set2_end = set2.end();
+  while ((set1_here != set1_end) && (set2_here != set2_end)) {
+    if (*set1_here == *set2_here) {
+      // equal
+      resultset.insert (*set1_here);
+      ++set1_here;
+      ++set2_here;
+
+    } else if ((childcomp=child_compare(*set1_here, *set2_here)) != 0) {
+      if (childcomp < 0) {
+	// set1_here is child
+	resultset.insert (*set1_here);
+	++set1_here;
+      } else {
+	// set2_here is child
+	resultset.insert (*set2_here);
+	++set2_here;
+      }
+
+    } else if (*set1_here < *set2_here) {
+      // set1 is less
+      ++set1_here;
+
+    } else {
+      // set2 is less
+      ++set2_here;
+    }
+  }
+
+  set1 = resultset;
+}
+
+void intersect (text_tarray &set1, const text_tset &set2) {
+  text_tarray resultset;
+
+  text_tarray::const_iterator set1_here = set1.begin();
+  text_tarray::const_iterator set1_end = set1.end();
+
+  while (set1_here != set1_end) {
+    if (in_set (set2, *set1_here))
+      resultset.push_back (*set1_here);
+    ++set1_here;
+  }
+  set1 = resultset;
+}
+
+void intersect (text_tarray &set1, const text_tarray &set2) {
+  text_tarray resultset;
+
+  text_tarray::const_iterator set1_here = set1.begin();
+  text_tarray::const_iterator set1_end = set1.end();
+
+  while (set1_here != set1_end) {
+    if (in_set (set2, *set1_here))
+      resultset.push_back (*set1_here);
+    ++set1_here;
+  }
+  set1 = resultset;
+}
+
+// tests to see if el is in set
+bool in_set (const text_tset &set1, const text_t &el) {
+  text_t::const_iterator here = el.begin();
+  text_t::const_iterator end = el.end();
+  text_t tryel, tryel_add;
+  bool first = true;
+
+  // the element is in the set if any of its parents are
+  // in the set
+  do {
+    // get next possible element to try
+    here = getdelimitstr (here, end, '.', tryel_add);
+    if (!first) tryel += ".";
+    first = false;
+    tryel += tryel_add;
+
+    // see if this element is in the set
+    if (set1.find(tryel) != set1.end()) return true;
+  } while (here != end);
+
+  return false;
+}
+
+bool in_set (const text_tarray &set1, const text_t &el) {
+  text_t::const_iterator here = el.begin();
+  text_t::const_iterator end = el.end();
+  text_t tryel, tryel_add;
+  bool first = true;
+
+  // the element is in the set if any of its parents are
+  // in the set
+  do {
+    // get next possible element to try
+    here = getdelimitstr (here, end, '.', tryel_add);
+    if (!first) tryel += ".";
+    first = false;
+    tryel += tryel_add;
+
+    // see if this element is in the set
+    text_tarray::const_iterator h = set1.begin();
+    text_tarray::const_iterator e = set1.end();
+    while (h != e) {
+      if (*h == tryel) return true;
+      ++h;
+    }
+  } while (here != end);
+
+  return false;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/filter.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/filter.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/filter.h	(revision 10506)
@@ -0,0 +1,141 @@
+/**********************************************************************
+ *
+ * filter.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef FILTER_H
+#define FILTER_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+
+
+class filterclass {
+protected:
+  text_t gsdlhome;
+  text_t gdbmhome;
+  text_t collection;
+  text_t collectdir;
+
+  FilterOption_tmap filterOptions;
+
+public:
+  filterclass ();
+  virtual ~filterclass ();
+
+  // configure should be called once for each configuration line
+  // default configures the default filter options
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  // init should be called after all the configuration is done but
+  // before any other methods are called
+  // default checks all the filter option defaults
+  virtual bool init (ostream &logout);
+
+  // returns the name of this filter
+  virtual text_t get_filter_name ();
+
+  // returns the current filter options
+  virtual void get_filteroptions (InfoFilterOptionsResponse_t &response,
+				  comerror_t &err, ostream &logout);
+
+  virtual void filter (const FilterRequest_t &request,
+		       FilterResponse_t &response,
+		       comerror_t &err, ostream &logout);
+};
+
+
+// The filterptr class does not 'own' the filter. The 
+// filter should be deleted by the code which created it.
+class filterptr {
+public:
+  filterclass *f;
+
+  filterptr () {f=NULL;}
+  ~filterptr () {}
+};
+
+bool operator==(const filterptr &x, const filterptr &y);
+bool operator<(const filterptr &x, const filterptr &y);
+
+
+typedef map<text_t, filterptr, lttext_t> filterptrmap;
+
+// contains a list of filters indexed by their name
+class filtermapclass {
+protected:
+  filterptrmap filterptrs;
+
+public:
+  // type support for filterptrmap
+  typedef filterptrmap::iterator iterator;
+  typedef filterptrmap::const_iterator const_iterator;
+  typedef filterptrmap::reference reference;
+  typedef filterptrmap::const_reference const_reference;
+  typedef filterptrmap::size_type size_type;
+
+  typedef filterptrmap::difference_type difference_type;
+  typedef filterptrmap::const_reverse_iterator const_reverse_iterator;
+  typedef filterptrmap::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return filterptrs.begin();}
+  const_iterator begin () const {return filterptrs.begin();}
+  iterator end () {return filterptrs.end();}
+  const_iterator end () const {return filterptrs.end();}
+
+  void erase(iterator pos) {filterptrs.erase(pos);}
+  void erase(iterator first, iterator last) {filterptrs.erase(first, last);}
+  filtermapclass &operator=(const filtermapclass &x) {filterptrs=x.filterptrs;return *this;}
+
+  bool empty () const {return filterptrs.empty();}
+  size_type size() const {return filterptrs.size();}
+
+
+  // added functionality
+  void clear () {filterptrs.erase(filterptrs.begin(),filterptrs.end());}
+
+  // thefilter remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addfilter (filterclass *thefilter);
+
+  // getfilter will return NULL if the filter could not be found
+  filterclass *getfilter (const text_t &key);
+};
+
+
+
+// some useful functions for dealing with document sets
+
+// intersect places the result in set1
+void intersect (text_tset &set1, const text_tset &set2);
+void intersect (text_tarray &set1, const text_tset &set2);
+void intersect (text_tarray &set1, const text_tarray &set2);
+
+// tests to see if el is in set
+bool in_set (const text_tset &set1, const text_t &el);
+bool in_set (const text_tarray &set1, const text_t &el);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/gdbmsource.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/gdbmsource.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/gdbmsource.cpp	(revision 10506)
@@ -0,0 +1,381 @@
+/**********************************************************************
+ *
+ * gdbmsource.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gdbmsource.h"
+#include "fileutil.h"
+#include "OIDtools.h"
+#include "gsdltools.h"
+
+
+gdbmsourceclass::gdbmsourceclass () {
+  gdbmptr = NULL;
+  textsearchptr = NULL;
+  classname = "gdbmsource";
+}
+
+gdbmsourceclass::~gdbmsourceclass () {
+  if (gdbmptr != NULL) delete gdbmptr;
+  if (textsearchptr != NULL) delete textsearchptr;
+}
+
+void gdbmsourceclass::configure (const text_t &key, const text_tarray &cfgline) {
+  if (cfgline.size() >= 1) {
+    const text_t &value = cfgline[0];
+
+    if (key == "collection") collection = value;
+    else if (key == "collectdir") collectdir = value;
+    else if (key == "gsdlhome") gsdlhome = value;
+    else if (key == "gdbmhome") gdbmhome = value;
+  }
+
+  if (key == "indexmap") {
+    indexmap.importmap (cfgline);
+
+  } else if (key == "defaultindex") {
+    indexmap.from2to (cfgline[0], defaultindex);
+
+  } else if (key == "subcollectionmap") {
+    subcollectionmap.importmap (cfgline);
+
+  } else if (key == "defaultsubcollection") {
+    subcollectionmap.from2to (cfgline[0], defaultsubcollection);
+
+  } else if (key == "languagemap") {
+    languagemap.importmap (cfgline);
+
+  } else if (key == "defaultlanguage") {
+    languagemap.from2to (cfgline[0], defaultlanguage);
+  } else if (key == "indexstem") {
+    indexstem = cfgline[0];
+  }
+  
+}
+
+bool gdbmsourceclass::init (ostream &logout) {
+  outconvertclass text_t2ascii;
+  
+  if (gdbmhome.empty()) gdbmhome = gsdlhome;
+
+  if (!sourceclass::init (logout)) return false;
+
+  if (defaultindex.empty()) {
+    // use first index in map as default if no default is set explicitly
+    text_tarray toarray;
+    indexmap.gettoarray(toarray);
+    if (toarray.size()) {
+      defaultindex = toarray[0];
+    }
+  }
+
+  if (defaultsubcollection.empty()) {
+    // use first subcollection in map as default if no default is set explicitly
+    text_tarray toarray;
+    subcollectionmap.gettoarray(toarray);
+    if (toarray.size()) {
+      defaultsubcollection = toarray[0];
+    }
+  }
+
+  if (defaultlanguage.empty()) {
+    // use first language in map as default if no default is set explicitly
+    text_tarray toarray;
+    languagemap.gettoarray(toarray);
+    if (toarray.size()) {
+      defaultlanguage = toarray[0];
+    }
+  }
+  
+  // get the collection directory name
+  if (collectdir.empty()) {
+    collectdir = filename_cat (gsdlhome, "collect", collection);
+  }
+  
+  // get the filename for the database and make sure it exists
+  if (indexstem.empty()) {
+    indexstem = collection;
+  }
+  gdbm_filename = filename_cat(gdbmhome, "collect", collection, "index", "text", indexstem);
+  if (littleEndian()) gdbm_filename += ".ldb";
+  else gdbm_filename += ".bdb";
+
+  if (!file_exists(gdbm_filename)) {
+    logout << text_t2ascii
+	   << "warning: gdbm database \"" //****
+	   << gdbm_filename << "\" does not exist\n\n";
+    // return false; //****
+  }
+  
+  return true;
+}
+
+bool gdbmsourceclass::translate_OID (const text_t &OIDin, text_t &OIDout, 
+				       comerror_t &err, ostream &logout) {
+
+  outconvertclass text_t2ascii;
+
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: " << classname << " contains a null gdbmclass\n\n";
+    err = configurationError;
+    return true;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return true;
+  }
+
+  infodbclass info;
+  OIDout = gdbmptr->translate_OID (OIDin, info);
+  return true;
+}
+
+bool gdbmsourceclass::get_metadata (const text_t &/*requestParams*/, const text_t &/*refParams*/, 
+				      bool getParents, const text_tset &fields, 
+				      const text_t &OID, MetadataInfo_tmap &metadata, 
+				      comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  metadata.erase(metadata.begin(), metadata.end());
+
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: " << classname <<" contains a null gdbmclass\n\n";
+    err = configurationError;
+    return true;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return true;
+  }
+
+  // get the metadata - if getParents is set we need to get 
+  // info for all parents of OID as well as OID
+  vector<infodbclass> info_array;
+  text_tarray OIDs;
+  if (getParents) get_parents_array (OID, OIDs);
+  OIDs.push_back (OID);
+
+  text_tarray::const_iterator this_OID = OIDs.begin();
+  text_tarray::const_iterator end_OID = OIDs.end();
+
+  while (this_OID != end_OID) {
+    infodbclass info;
+    if (!gdbmptr->getinfo(*this_OID, info)) return false;
+
+    // adjust the metadata
+    text_t &contains = info["contains"];
+    if (contains.empty()) info["haschildren"] = 0;
+    else info["haschildren"] = 1;
+    //contains.clear();
+
+    info_array.push_back(info);
+    ++this_OID;
+  }
+
+  // if fields set is empty we want to get all available metadata
+  text_tset tfields = fields;
+  if (tfields.empty() && !info_array.empty()) {
+    infodbclass::iterator t_info = info_array[0].begin(); 
+    infodbclass::iterator e_info = info_array[0].end(); 
+    while (t_info != e_info) {
+      if ((*t_info).first != "contains")
+	tfields.insert ((*t_info).first);
+      ++t_info;
+    }
+    tfields.insert ("hasnext");
+    tfields.insert ("hasprevious");
+  }
+    
+  // collect together the metadata
+  bool donenextprevtest = false;
+  bool hasnext=false, hasprevious=false;
+  MetadataInfo_t this_metadata;
+  text_tarray *pos_metadata;
+  text_tset::const_iterator fields_here = tfields.begin();
+  text_tset::const_iterator fields_end = tfields.end();
+
+  while (fields_here != fields_end) {
+    this_metadata.clear();
+    this_metadata.isRef = false;
+
+    vector<infodbclass>::reverse_iterator this_info = info_array.rbegin(); 
+    vector<infodbclass>::reverse_iterator end_info = info_array.rend(); 
+    MetadataInfo_t *tmetaptr = &this_metadata;
+    while (this_info != end_info) {
+
+      pos_metadata = (*this_info).getmultinfo(*fields_here);
+      if ((*fields_here == "hasnext" || *fields_here == "hasprevious")) {
+	
+	// collect metadata
+	if (!donenextprevtest) {
+	  donenextprevtest = true;
+	  
+	  // cache parent contents array
+	  text_t thisparent = get_parent (OID);
+	  if (!thisparent.empty()) {
+	    if (thisparent != parentOID) {
+	      parentOID = thisparent;
+	      parentcontents.erase(parentcontents.begin(), parentcontents.end());
+	      if (gdbmptr->getinfo(parentOID, parentinfo)) {
+		text_t &parentinfocontains = parentinfo["contains"];
+		if (!parentinfocontains.empty())
+		  splitchar (parentinfocontains.begin(), parentinfocontains.end(), 
+			     ';', parentcontents);
+	      }
+	    }
+	    
+	    // do tests
+	    text_tarray::const_iterator parentcontents_here = parentcontents.begin();
+	    text_tarray::const_iterator parentcontents_end = parentcontents.end();
+	    text_t shrunk_OID = OID;
+	    shrink_parent (shrunk_OID);
+	    while (parentcontents_here != parentcontents_end) {
+	      if (*parentcontents_here == shrunk_OID) {
+		if (parentcontents_here == parentcontents.begin()) hasprevious = false;
+		else hasprevious = true;
+		
+		++parentcontents_here;
+		
+		if (parentcontents_here == parentcontents.end()) hasnext = false;
+		else hasnext = true;
+		
+		break;
+	      }  
+	      
+	      ++parentcontents_here;
+	    }
+	 
+	    // fill in metadata
+	    if ((*fields_here == "hasnext" && hasnext) ||
+		(*fields_here == "hasprevious" && hasprevious))
+	      tmetaptr->values.push_back("1");
+	    else
+	      tmetaptr->values.push_back("0");
+	  } else
+	    tmetaptr->values.push_back("0");
+	}
+      }
+      //else if (pos_metadata != NULL && *fields_here != "contains") {
+      else if (pos_metadata != NULL) {
+	tmetaptr->values = *pos_metadata;
+      }
+      else
+	tmetaptr->values.push_back("");
+
+      ++this_info;
+      if (this_info != end_info) {
+	tmetaptr->parent = new MetadataInfo_t();
+	tmetaptr = tmetaptr->parent;
+      }
+    }
+    metadata[*fields_here] = this_metadata;
+    ++fields_here;
+  }
+  return true;
+}
+
+
+bool gdbmsourceclass::get_document (const text_t &OID, text_t &doc, 
+				      comerror_t &err, ostream &logout) {
+
+  outconvertclass text_t2ascii;
+
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: " << classname << " contains a null gdbmclass\n\n";
+    err = configurationError;
+    return true;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return true;
+  }
+
+  text_t tOID = OID;
+  if (needs_translating (OID)) 
+    translate_OID (OID, tOID, err, logout);
+  infodbclass info;
+  if (!gdbmptr->getinfo(tOID, info)) return false;
+  
+  if (info["hastxt"].getint() == 1) {
+    int docnum = info["docnum"].getint();
+    
+    // set the collection directory
+    textsearchptr->setcollectdir (collectdir);
+    
+    // get the text
+    textsearchptr->docTargetDocument(defaultindex, defaultsubcollection,
+				   defaultlanguage, collection, docnum, doc);
+  }
+  return true;
+}
+
+bool gdbmsourceclass::is_searchable(bool &issearchable, comerror_t &err, ostream &logout) {
+  err = noError;
+  issearchable = false;
+
+  text_tarray fromarray;
+  indexmap.getfromarray(fromarray);
+  if (fromarray.size() == 0) {
+    return true;
+  } else if (fromarray.size() == 1) {
+    if (fromarray[0] == "dummy:text") {
+      // always return true - issearchable is false here though
+      return true;
+    }
+  }
+  issearchable = true;
+  return true;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/gdbmsource.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/gdbmsource.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/gdbmsource.h	(revision 10506)
@@ -0,0 +1,95 @@
+/**********************************************************************
+ *
+ * gdbmsource.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef GDBMSOURCE_H
+#define GDBMSOURCE_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+#include "infodbclass.h"
+#include "maptools.h"
+#include "search.h"
+#include "source.h"
+
+
+class gdbmsourceclass : public sourceclass {
+protected:
+  text_t gsdlhome;
+  text_t gdbmhome;
+  text_t collection;
+  text_t collectdir;
+  
+  // these maps are only needed to convert the default indexes
+  stringmap indexmap;
+  stringmap subcollectionmap;
+  stringmap languagemap;
+
+  text_t defaultindex;
+  text_t defaultsubcollection;
+  text_t defaultlanguage;
+
+  text_t indexstem;
+
+  text_t parentOID;
+  infodbclass parentinfo;
+  text_tarray parentcontents;
+
+  text_t gdbm_filename;
+  gdbmclass *gdbmptr;
+  
+  searchclass *textsearchptr;
+
+public:
+  gdbmsourceclass ();
+  virtual ~gdbmsourceclass ();
+
+  // the gdbmptr remains the responsability of the calling code
+  void set_gdbmptr (gdbmclass *thegdbmptr) {gdbmptr=thegdbmptr;}
+
+  // the textsearchptr remains the responsability of the calling code
+  void set_textsearchptr (searchclass *thetextsearchptr) {textsearchptr=thetextsearchptr;}
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+  bool init (ostream &logout);
+  bool translate_OID (const text_t &OIDin, text_t &OIDout, 
+		      comerror_t &err, ostream &logout);
+  bool get_metadata (const text_t &requestParams, const text_t &refParams, 
+		     bool getParents, const text_tset &fields, 
+		     const text_t &OID, MetadataInfo_tmap &metadata, 
+		     comerror_t &err, ostream &logout);
+  bool get_document (const text_t &OID, text_t &doc, 
+		     comerror_t &err, ostream &logout);
+  bool is_searchable(bool &issearchable, comerror_t &err, ostream &logout);
+
+ protected:
+  text_t classname;
+
+};
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenegdbmsource.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenegdbmsource.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenegdbmsource.cpp	(revision 10506)
@@ -0,0 +1,90 @@
+/**********************************************************************
+ *
+ * lucenegdbmsource.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "lucenegdbmsource.h"
+#include "fileutil.h"
+#include "OIDtools.h"
+#include "expat_document.h"
+#include "lucenesearch.h"
+
+lucenegdbmsourceclass::lucenegdbmsourceclass () 
+  : gdbmsourceclass()
+{
+  classname = "lucenegdbmsource";
+}
+
+lucenegdbmsourceclass::~lucenegdbmsourceclass () {
+}
+
+bool lucenegdbmsourceclass::get_document (const text_t &OID, text_t &doc, 
+				      comerror_t &err, ostream &logout) {
+
+  outconvertclass text_t2ascii;
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: lucenegdbmsource contains a null gdbmclass\n\n";
+    err = configurationError;
+    return true;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return true;
+  }
+
+  text_t tOID = OID;
+  if (needs_translating (OID)) 
+    translate_OID (OID, tOID, err, logout);
+  infodbclass info;
+  if (!gdbmptr->getinfo(tOID, info)) return false;
+  
+  if (info["hastxt"].getint() == 0) { // there is no text for this section
+    return false; // true??
+  }
+  int docnum = info["docnum"].getint();
+
+  // get the parent id
+  text_t parent_OID;
+  get_top(tOID, parent_OID);
+  
+  // locate the parent info ingdbm db
+  if (!gdbmptr->getinfo(parent_OID, info)) return false;
+  
+  text_t archive_dir = info["assocfilepath"];
+  text_t full_path_to_doc = filename_cat(collectdir, "index", "text", archive_dir, "doc.xml");
+  
+  doc.clear();
+  expat_document(full_path_to_doc, ((lucenesearchclass*)textsearchptr)->gdbm_level, text_t(docnum), doc);
+  return true;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenegdbmsource.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenegdbmsource.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenegdbmsource.h	(revision 10506)
@@ -0,0 +1,51 @@
+/**********************************************************************
+ *
+ * lucenegdbmsource.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef LUCENEGDBMSOURCE_H
+#define LUCENEGDBMSOURCE_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+#include "infodbclass.h"
+#include "maptools.h"
+#include "search.h"
+#include "gdbmsource.h"
+
+
+class lucenegdbmsourceclass : public gdbmsourceclass {
+public:
+  lucenegdbmsourceclass ();
+  virtual ~lucenegdbmsourceclass ();
+
+  bool get_document (const text_t &OID, text_t &doc, 
+		     comerror_t &err, ostream &logout);
+
+};
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenequeryfilter.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenequeryfilter.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenequeryfilter.cpp	(revision 10506)
@@ -0,0 +1,379 @@
+/**********************************************************************
+ *
+ * lucenequeryfilter.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+
+#include "lucenequeryfilter.h"
+#include "fileutil.h"
+#include <assert.h>
+#include "lucenesearch.h"
+
+/////////////////////////////////
+// functions for queryfilterclass
+/////////////////////////////////
+
+
+lucenequeryfilterclass::lucenequeryfilterclass () 
+  : queryfilterclass() {
+
+  
+  FilterOption_t filtopt;
+  
+  // -- onePerTerm  Level          enumerated
+  // likely to be Doc, Sec, Para, but we dont assume anything now
+  filtopt.clear();
+  filtopt.name = "Level";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filterOptions["Level"] = filtopt;
+
+  // --  IndexField, enumerated, used to list available fields
+  filtopt.clear();
+  filtopt.name = "IndexField";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "";
+  filterOptions["IndexField"] = filtopt;
+
+}
+
+lucenequeryfilterclass::~lucenequeryfilterclass () {
+}
+
+
+//whether a query is a full text browse
+bool lucenequeryfilterclass::full_text_browse (int filterRequestOptions) {
+  return (filterRequestOptions & FRfullTextBrowse);
+}
+
+void lucenequeryfilterclass::configure (const text_t &key, const text_tarray &cfgline) {
+  queryfilterclass::configure(key, cfgline);
+
+  if (key == "indexfieldmap") {
+    indexfieldmap.importmap (cfgline);
+    
+    // update the list of indexes in the filter information
+    text_tarray options;
+    indexfieldmap.gettoarray (options);
+
+    text_tarray::const_iterator here = options.begin();
+    text_tarray::const_iterator end = options.end();
+    bool start = true;
+    while (here !=end) {
+      if (!(*here).empty()) {
+	filterOptions["IndexField"].validValues.push_back(*here);
+	if (start) {
+	  filterOptions["IndexField"].defaultValue = *here;
+	  start = false;
+	}
+      }
+      ++here;
+    }
+  } else if (key == "indexlevels") {
+    text_tarray::const_iterator here = cfgline.begin();
+    text_tarray::const_iterator end = cfgline.end();
+    bool first=true;
+    while (here != end) {
+      if (!(*here).empty()) {
+	if (first) {
+	  first = false;
+	  // the default is the first value
+	  filterOptions["Level"].defaultValue = *here;
+	}
+	filterOptions["Level"].validValues.push_back(*here);
+      }
+      ++here;
+    }
+  } else if (key == "textlevel") {
+      ((lucenesearchclass *)textsearchptr)->set_gdbm_level( cfgline[0]);
+  }
+  
+}
+
+
+void lucenequeryfilterclass::filter(const FilterRequest_t &request,
+				  FilterResponse_t &response,
+				  comerror_t &err, ostream &logout) {  
+
+  outconvertclass text_t2ascii;
+
+  response.clear ();
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: queryfilter contains a null gdbmclass\n\n";
+    err = configurationError;
+    return;
+  }
+  if (textsearchptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: queryfilter contains a null textsearchclass (lucene)\n\n";
+    err = configurationError;
+    return;
+  }
+  if (full_text_browse(request.filterResultOptions)) {
+    browsefilter(request, response, err, logout);
+    return;
+  }
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return;
+  }
+
+
+  // get the query parameters
+  int startresults, endresults;
+  text_t phrasematch; // not used here any more
+  vector<queryparamclass> queryfilterparams;
+  parse_query_params (request, queryfilterparams, startresults, 
+		      endresults, phrasematch, logout);  
+ 
+   
+  // do query
+  queryresultsclass queryresults;
+  do_multi_query (request, queryfilterparams, queryresults, err, logout);
+  if (err != noError) return;
+  // assemble document results
+  if (need_matching_docs (request.filterResultOptions)) {
+    
+    int resultnum = 1;
+    ResultDocInfo_t resultdoc;
+    text_t trans_OID;
+    vector<int>::iterator docorder_here = queryresults.docs.docorder.begin();
+    vector<int>::iterator docorder_end = queryresults.docs.docorder.end();
+
+    if (endresults == -1) endresults = MAXNUMDOCS;
+    while (docorder_here != docorder_end) {
+      if (resultnum > endresults) break;
+      
+      // translate the document number
+      if (!translate(gdbmptr, *docorder_here, trans_OID)) {
+	logout << text_t2ascii
+	       << "warning: could not translate lucene document number \""
+	       << *docorder_here << "\" to OID.\n\n";
+	
+      } else {
+	docresultmap::iterator docset_here = queryresults.docs.docset.find (*docorder_here);
+
+	// see if there is a result for this number,
+	// if it is in the request set (or the request set is empty)
+	if (docset_here != queryresults.docs.docset.end() &&
+	    (request.docSet.empty() || in_set(request.docSet, trans_OID))) {
+	  if (resultnum >= startresults) {
+	    // add this document
+	    resultdoc.OID = trans_OID;
+	    resultdoc.result_num = resultnum;
+	    resultdoc.ranking = (int)((*docset_here).second.docweight * 10000.0 + 0.5);
+
+	    response.docInfo.push_back (resultdoc);
+	  }
+	  
+	  ++resultnum;
+	}
+      } // else
+      
+      ++docorder_here;
+    }
+  } // if need matching docs
+
+  // assemble the term results
+  if (need_term_info(request.filterResultOptions)) {
+    // note: the terms have already been sorted and uniqued - ?? have they??
+
+    TermInfo_t terminfo;
+    bool terms_first = true;
+
+    termfreqclassarray::iterator terms_here = queryresults.terms.begin();
+    termfreqclassarray::iterator terms_end = queryresults.terms.end();
+
+    while (terms_here != terms_end) {
+      terminfo.clear();
+      terminfo.term = (*terms_here).termstr;
+      terminfo.freq = (*terms_here).termfreq;
+
+      // this bit gets the matchTerms ie the equivalent (stem/casefold) terms
+      if (terms_first) {
+	text_tset::iterator termvariants_here = queryresults.termvariants.begin();
+	text_tset::iterator termvariants_end = queryresults.termvariants.end();
+	while (termvariants_here != termvariants_end) {
+	  terminfo.matchTerms.push_back (*termvariants_here);
+	  ++termvariants_here;
+	}
+      }
+      terms_first = false;
+      
+      response.termInfo.push_back (terminfo);
+
+      ++terms_here;
+    }
+  }
+
+  response.numDocs = queryresults.docs_matched;
+  response.isApprox = queryresults.is_approx;
+}
+
+void lucenequeryfilterclass::browsefilter(const FilterRequest_t &request,
+					FilterResponse_t &response,
+					comerror_t &err, ostream &logout) {  
+
+  outconvertclass text_t2ascii;
+
+  // get the query parameters
+  int startresults, endresults;
+  text_t phrasematch; // not used here any more, just have it so can use
+                      // parse_query_params function
+  
+  vector<queryparamclass> queryfilterparams;
+  parse_query_params (request, queryfilterparams, startresults, 
+		      endresults, phrasematch, logout);  
+
+    vector<queryparamclass>::const_iterator query_here = queryfilterparams.begin();
+   
+  // do query
+  queryresultsclass queryresults;
+  queryresults.clear();
+  
+  int numDocs = endresults-startresults;
+  textsearchptr->setcollectdir (collectdir);
+
+  if (!((lucenesearchclass*)textsearchptr)->browse_search((*query_here), startresults, numDocs, queryresults)) {
+    // most likely a system problem
+    logout << text_t2ascii
+	   << "system problem: could not do full text browse with lucene for index \""
+	   << (*query_here).index << (*query_here).subcollection
+	   << (*query_here).language << "\".\n\n";
+    err = systemProblem;
+    return;
+  }
+
+  // assemble the term results
+  TermInfo_t terminfo;
+  
+  termfreqclassarray::iterator terms_here = queryresults.terms.begin();
+  termfreqclassarray::iterator terms_end = queryresults.terms.end();
+
+  while (terms_here != terms_end) {
+    terminfo.clear();
+    terminfo.term = (*terms_here).termstr;
+    terminfo.freq = (*terms_here).termfreq;
+    
+    response.termInfo.push_back (terminfo);
+
+    ++terms_here;
+  }
+  
+
+}
+
+// lucenesearchptr and gdbmptr are assumed to be valid
+void lucenequeryfilterclass::do_multi_query (const FilterRequest_t &request,
+					   const vector<queryparamclass> &query_params,
+					   queryresultsclass &multiresults,
+					   comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  err = noError;
+  textsearchptr->setcollectdir (collectdir);
+  multiresults.clear();
+  
+  vector<queryparamclass>::const_iterator query_here = query_params.begin();
+  vector<queryparamclass>::const_iterator query_end = query_params.end();
+  while (query_here != query_end) {
+    queryresultsclass thisqueryresults;
+    if (!textsearchptr->search((*query_here), thisqueryresults)) {
+      // most likely a system problem
+      logout << text_t2ascii
+	     << "system problem: could not do search with lucene for index \""
+	     << (*query_here).index << (*query_here).level 
+	     << (*query_here).subcollection
+	     << (*query_here).language << "\".\n\n";
+      err = systemProblem;
+      return;
+    }
+
+    // check for syntax error
+    if (thisqueryresults.syntax_error==true) {
+      logout << text_t2ascii
+	     << "syntax problem: invalid query string \""
+	     << (*query_here).querystring<<"\".\n";
+      err = syntaxError;
+      return;
+    }
+    // combine the results
+    if (need_matching_docs (request.filterResultOptions)) {
+            
+      if (query_params.size() == 1) {
+	multiresults.docs = thisqueryresults.docs; // just one set of results
+	multiresults.docs_matched = thisqueryresults.docs_matched;
+	multiresults.is_approx = thisqueryresults.is_approx;
+	
+      } else {
+	if ((*query_here).combinequery == "and") {
+	  multiresults.docs.combine_and (thisqueryresults.docs);
+	} else if ((*query_here).combinequery == "or") {
+	  multiresults.docs.combine_or (thisqueryresults.docs);
+	} else if ((*query_here).combinequery == "not") {
+	  multiresults.docs.combine_not (thisqueryresults.docs);
+	}
+	multiresults.docs_matched = multiresults.docs.docset.size();
+	multiresults.is_approx = Exact;
+      }
+    }
+
+    // combine the term information 
+    if (need_term_info (request.filterResultOptions)) {
+      // append the terms
+      multiresults.orgterms.insert(multiresults.orgterms.end(),
+				   thisqueryresults.orgterms.begin(),
+				   thisqueryresults.orgterms.end());
+
+      
+      // add the term variants - 
+      text_tset::iterator termvar_here = thisqueryresults.termvariants.begin();
+      text_tset::iterator termvar_end = thisqueryresults.termvariants.end();
+      while (termvar_here != termvar_end) {
+	multiresults.termvariants.insert(*termvar_here);
+	++termvar_here;
+      }
+    }
+   
+    ++query_here;
+  }
+
+  // sort and unique the query terms
+  multiresults.sortuniqqueryterms ();
+}
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenequeryfilter.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenequeryfilter.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenequeryfilter.h	(revision 10506)
@@ -0,0 +1,67 @@
+/**********************************************************************
+ *
+ * lucenequeryfilter.h -- new queryfilter to use lucene 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef LUCENEQUERYFILTER_H
+#define LUCENEQUERYFILTER_H
+
+#include "queryfilter.h"
+
+class lucenequeryfilterclass : public queryfilterclass {
+protected:
+
+  stringmap indexfieldmap;
+  bool full_text_browse (int filterRequestOptions);
+
+  // mgsearchptr and gdbmptr are assumed to be valid
+  void do_multi_query (const FilterRequest_t &request,
+		       const vector<queryparamclass> &query_params,
+		       queryresultsclass &multiresults,
+		       comerror_t &err, ostream &logout);
+
+
+public:
+  lucenequeryfilterclass ();
+  virtual ~lucenequeryfilterclass ();
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  void filter (const FilterRequest_t &request,
+		       FilterResponse_t &response,
+		       comerror_t &err, ostream &logout);
+  
+  void browsefilter(const FilterRequest_t &request,
+		    FilterResponse_t &response,
+		    comerror_t &err, ostream &logout);  
+
+
+};
+
+#endif
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenesearch.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenesearch.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenesearch.cpp	(revision 10506)
@@ -0,0 +1,349 @@
+/**********************************************************************
+ *
+ * lucenesearch.cpp -- 
+ * Copyright (C) 1999-2002  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.
+ *
+ *********************************************************************/
+
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#include <stdio.h>
+#include <time.h>
+
+#include "gsdlconf.h"
+#include "gsdltools.h"
+#include "lucenesearch.h"
+#include "fileutil.h"
+#include "queryinfo.h"
+#include "gsdlunicode.h"
+
+#include "expat_resultset.h"
+
+
+text_t lucenesearchclass::getindexsuffix(const queryparamclass &qp) {
+  text_t indexsuffix = "index";
+  // get the first char of the level to be the start of the index name
+  text_t suffix = substr(qp.level.begin(), qp.level.begin()+1);
+  lc(suffix);
+  text_t ind = qp.index;
+  text_t sub = qp.subcollection;
+  text_t lang = qp.language;
+   
+  // collection name not added for Lucene
+  indexsuffix = filename_cat(indexsuffix, suffix +ind + sub + lang);
+  return indexsuffix;
+
+}
+
+////////////////////
+// lucenesearch class //
+////////////////////
+
+lucenesearchclass::lucenesearchclass ()
+  : searchclass() {
+
+  gdbm_level = "Doc";
+}
+
+lucenesearchclass::~lucenesearchclass () 
+{
+  if (cache != NULL) 
+    {
+      delete cache;
+      cache = NULL;
+    }
+}
+
+void lucenesearchclass::set_gdbm_level(const text_t &level) {
+  gdbm_level = level;
+  
+}
+
+
+bool lucenesearchclass::search(const queryparamclass &queryparams, 
+			       queryresultsclass &queryresult) {
+ 
+#ifdef __WIN32__
+  char basepath[]="";
+#else
+  char basepath[] = "/";
+#endif
+ 
+  cerr << "**** in lucene search" << endl;
+
+  char *indexname = (filename_cat(collectdir, getindexsuffix(queryparams))).getcstr(); 
+
+  // set default stem method from values originally set on prefs page
+  int defaultStemMethod = 0;
+  if (queryparams.casefolding) {
+    defaultStemMethod |= 1;
+  }
+  if (queryparams.stemming) {
+    defaultStemMethod |= 2;
+  }
+  
+  // set default Boolean combiner from all/some setting
+  // if match_mode == 1, ie all, default=1 ie AND
+  // if match_mode == 0, ie some, default=0, ie OR
+  int defaultBoolCombine = 0;
+  if (queryparams.match_mode){
+    defaultBoolCombine = 1;
+  }
+
+  text_t utf8querystring = to_utf8(queryparams.querystring);
+  cerr << "**** query string = " << utf8querystring << endl;
+
+  text_t escaped_utf8querystring = "";
+  text_t::const_iterator here = utf8querystring.begin();
+  while (here != utf8querystring.end()) {
+    if (*here == '"') escaped_utf8querystring.push_back('\\');
+    escaped_utf8querystring.push_back(*here);
+    here++;
+  }
+  cerr << "**** escaped query string = " << escaped_utf8querystring << endl;
+  cerr << "***** index name = " << indexname << endl;
+
+  text_t cmd = filename_cat(getenv("GSDLHOME"), "bin", "script", "lucene_query.pl");
+  cmd += (text_t)" \""+indexname + (text_t)"\" \"" + escaped_utf8querystring + (text_t)"\""; 
+  cerr << "Lucene command: " << cmd << endl;
+ 
+  text_t xml_text = "";
+
+#ifdef __WIN32__
+  //FILE *PIN = _popen(cmd.getcstr(), "r"); // didn't seem to work
+  cmd = (text_t)"perl -S "+cmd;
+  // we write the result to a file
+  clock_t this_time = clock();
+  text_t filename = "luc";
+  filename.append(this_time);
+  filename.append(".txt");
+ 
+  text_t out_file = filename_cat(collectdir, filename);
+  cmd += (text_t)" \""+out_file+ (text_t)"\"";
+  int rv = gsdl_system(cmd, true, cerr);
+  if (rv != 0) {
+    cerr << "tried to run command \""<<cmd<<"\", but it failed\n";
+  } else {
+    read_file(out_file, xml_text);
+    remove(out_file.getcstr()); // now delete it
+  }
+#else
+  FILE *PIN = popen(cmd.getcstr(), "r");
+
+  if (PIN==NULL) {
+    perror("PIPE");
+    cerr << "Error: unable to open pipe to " << cmd << endl;
+    
+    return false;
+  }
+  while (!feof(PIN)) {
+    char buffer[256];
+    int num_bytes = fread(buffer,1,256,PIN);
+    xml_text.appendcarr(buffer,num_bytes);
+  }
+
+#endif
+  expat_resultset(xml_text,queryresult);
+  
+#ifdef __WIN32__
+  //  _pclose(PIN);
+#else
+  pclose(PIN);
+#endif
+
+  return true;
+}
+  /*
+  // use default query info settings - change to reflect user preferences??
+  QueryInfo queryInfo;
+  
+  SetCStr (queryInfo.docLevel, (queryparams.level.getcstr())); 
+  queryInfo.maxDocs = (unsigned long)queryparams.maxdocs;
+  queryInfo.sortByRank = (queryparams.search_type == 1);
+  queryInfo.exactWeights = false;
+  queryInfo.needRankInfo = true; // used for overall term freq as well as ranking
+  queryInfo.needTermFreqs = true;
+  
+  ExtQueryResult queryResult;
+  
+  UCArray queryArray;
+  // greenstone gives us the query encoded in unicode. We want utf8.
+  char* utf8querystring=to_utf8(queryparams.querystring).getcstr();
+  SetCStr(queryArray, utf8querystring);
+  delete utf8querystring;
+
+  UCArray level;
+  UCArrayClear(level);
+  
+  //set the level for results
+  SetCStr(level, gdbm_level.getcstr());
+
+  
+  // do the query
+  // LuceneQuery(*indexData, queryInfo, queryTree, queryResult, level); // ****
+  
+ 
+  // convert ExtQueryResult to queryresultclass
+  
+  queryresult.docs_matched = (int)queryResult.docs.size();
+
+  if (queryresult.docs_matched == (int)queryResult.actualNumDocs) {
+    queryresult.is_approx = Exact; 
+  }
+  else if (queryresult.docs_matched < (int)queryResult.actualNumDocs) {
+    queryresult.is_approx = MoreThan;
+  }
+  else {
+    queryresult.is_approx = Approximate;
+  }
+
+  docresultclass doc;
+  for (int i=0; i<(int)queryResult.docs.size(); ++i) {
+    doc.clear();
+    doc.docnum = (int)queryResult.levels[i];
+    doc.docweight = queryResult.ranks[i];
+    queryresult.docs.docset[doc.docnum] = doc;
+    queryresult.docs.docorder.push_back(doc.docnum);
+
+  }
+
+  // term info
+  termfreqclass term;
+  for (int k=0; k<(int)queryResult.termFreqs.size(); ++k) {
+    term.clear();
+    char* termfreq_cstr=GetCStr(queryResult.termFreqs[k].term);
+    term.termstr = to_uni(termfreq_cstr);
+    delete termfreq_cstr;
+    term.termstemstr = term.termstr;
+    // we don't set term.utf8equivterms ?? - jrm21
+    term.termfreq = queryResult.termFreqs[k].termFreq;
+    queryresult.terms.push_back(term);
+    queryresult.orgterms.push_back(term); // should this change??
+    
+    for (int j=0; j<(int)queryResult.termFreqs[k].equivTerms.size(); ++j) {
+      char* equivterm_cstr=GetCStr(queryResult.termFreqs[k].equivTerms[j]);
+      queryresult.termvariants.insert(to_uni(equivterm_cstr));
+      delete equivterm_cstr;
+    }
+
+  }
+  // clean up
+  delete indexname;
+  return true;
+  */
+
+
+bool lucenesearchclass::browse_search(const queryparamclass &queryparams, 
+				      int start, int numDocs,
+				      queryresultsclass &queryresult) {
+
+  cerr << "**** Not sure what this function does!" << endl;
+
+  /*
+#ifdef __WIN32__
+  char basepath[]="";
+#else
+  char basepath[] = "/";
+#endif
+
+  char *indexname = (filename_cat(collectdir, getindexsuffix(queryparams))).getcstr();
+ 
+  UCArray level;
+  UCArrayClear(level);
+  
+  //browse always at top level
+  SetCStr(level, "Doc"); // this name may change.
+
+  
+  BrowseQueryNode browseNode;
+  browseNode.startPosition = start;
+  browseNode.numTerms = numDocs;
+
+  BrowseQueryResult browseResult;
+  
+
+  UCArrayClear(browseNode.term);
+  // greenstone gives us the query encoded in unicode. We want utf8.
+  char* utf8querystring=to_utf8(queryparams.querystring).getcstr();
+  SetCStr(browseNode.term, utf8querystring);
+  delete utf8querystring;
+
+  // do the actual query
+  // LuceneBrowseQuery(*indexData, level, browseNode, browseResult); // ****
+
+  // load results into term info
+  termfreqclass term;
+  for (int i=0; i<(int)browseResult.termFreqs.size(); ++i) {
+    term.clear();
+    char* term_cstr = GetCStr(browseResult.termFreqs[i].term);
+    term.termstr = to_uni(term_cstr);
+    delete term_cstr;
+    term.termstemstr = term.termstr;
+    term.termfreq = browseResult.termFreqs[i].termFreq;
+    queryresult.terms.push_back(term);
+    queryresult.orgterms.push_back(term);
+
+  }
+  // clean up
+  delete indexname;
+
+  return true;
+
+  */
+
+  return false;
+}
+
+// the document text for 'docnum' is placed in 'output'
+// docTargetDocument returns 'true' if it was able to
+// try to get a document
+// collection is needed to see if an index from the 
+// collection is loaded. THe default index bits are just there cos
+// the mg version needs them
+
+bool lucenesearchclass::docTargetDocument(const text_t &/*defaultindex*/,
+					const text_t &/*defaultsubcollection*/,
+					const text_t &/*defaultlanguage*/,
+					const text_t &collection,
+					int docnum,
+					text_t &output) {
+
+  // we now get the document directly by lucenegdbmsource, so don't use this 
+  // method
+  return false;
+}
+
+// used to clear any cached databases for persistent versions of 
+// Greenstone like the Windows local library
+void lucenesearchclass::unload_database () {
+}
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenesearch.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenesearch.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/lucenesearch.h	(revision 10506)
@@ -0,0 +1,89 @@
+/**********************************************************************
+ *
+ * lucenesearch.h -- implementation of search class for lucene
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * 
+ *
+ *********************************************************************/
+
+
+#ifndef LUCENESEARCH_H
+#define LUCENESEARCH_H
+
+#include "search.h"
+
+class lucenesearchclass : public searchclass {
+public:
+  lucenesearchclass ();
+  virtual ~lucenesearchclass ();
+
+  virtual text_t get_textindex_type() {return "lucene";}
+
+  // the search results are returned in queryresults
+  // search returns 'true' if it was able to do a search
+  virtual bool search(const queryparamclass &queryparams, 
+		      queryresultsclass &queryresults);
+  
+  // this returns a list of terms in queryresults - no document info is returned
+  // returns a list of numTerms terms, starting from the query string term (in queryparams)
+  // + start. used for full text browsing
+  virtual bool browse_search(const queryparamclass &queryparams, int start, int numTerms,
+			     queryresultsclass &queryresults);
+
+  // the document text for 'docnum' is placed in 'output'
+  // docTargetDocument returns 'true' if it was able to
+  // try to get a document
+  // collection is needed to see if an index from the 
+  // collection is loaded. If no index has been loaded
+  // defaultindex is needed to load one
+  virtual bool docTargetDocument(const text_t &defaultindex,
+			 const text_t &defaultsubcollection,
+			 const text_t &defaultlanguage,
+			 const text_t &collection,
+			 int docnum,
+			 text_t &output);
+
+  /*  // same as docTargetDocument except the document is returned
+  // in its raw form. UDoc remains the property of mg and may
+  // be destroyed on the next call to mg.
+  // not implemented for lucene
+  virtual bool mgdocument (const text_t &defaultindex,
+		   const text_t &defaultsubcollection,
+		   const text_t &defaultlanguage,
+		   const text_t &collection,
+		   int docnum,
+		   char *&UDoc, int &ULen);
+  */
+  void set_gdbm_level(const text_t &level);
+
+  // used to clear any cached databases for persistent versions of 
+  // Greenstone like the Windows local library
+  void unload_database ();
+
+  text_t gdbm_level; // the default level used for retrieval, and in the gdbm file 
+ protected:
+  text_t getindexsuffix(const queryparamclass &qp);
+};
+
+
+#endif
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/maptools.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/maptools.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/maptools.cpp	(revision 10506)
@@ -0,0 +1,183 @@
+/**********************************************************************
+ *
+ * maptools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "maptools.h"
+
+
+
+void stringmap::clear () {
+  fromorder.erase (fromorder.begin(), fromorder.end());
+  mapfrom.erase (mapfrom.begin(), mapfrom.end());
+}
+
+void stringmap::importmap (const text_tarray &maparray) {
+  importmap(maparray, false);
+}
+
+void stringmap::importmap (const text_tarray &maparray, bool keepold) {
+  if (!keepold) {
+    clear ();
+  }
+  
+  text_tarray::const_iterator here = maparray.begin();
+  text_tarray::const_iterator end = maparray.end();
+  text_t from;
+  text_t to;
+
+  while (here != end) {
+    splitmapentry (*here, from, to);
+    fromorder.push_back (from);
+    mapfrom[from] = to;
+    ++here;
+  }
+}
+
+void stringmap::exportmap (text_tarray &maparray) const {
+  maparray.erase (maparray.begin(), maparray.end());
+
+  text_tarray::const_iterator here = fromorder.begin();
+  text_tarray::const_iterator end = fromorder.end();
+  text_tmap::const_iterator toptr;
+  text_t tempmap;
+
+  while (here != end) {
+    toptr = mapfrom.find (*here);
+    if (toptr != mapfrom.end()) {
+      joinmapentry ((*toptr).first, (*toptr).second, tempmap);
+      maparray.push_back (tempmap);
+    }
+
+    ++here;
+  }
+}
+
+void stringmap::getfromarray (text_tarray &fromarray) const {
+  fromarray = fromorder;
+}
+
+void stringmap::gettoarray (text_tarray &toarray) const {
+  toarray.erase(toarray.begin(), toarray.end());
+
+  text_tarray::const_iterator here = fromorder.begin();
+  text_tarray::const_iterator end = fromorder.end();
+  text_tmap::const_iterator toptr;
+
+  while (here != end) {
+    toptr = mapfrom.find (*here);
+    if (toptr != mapfrom.end()) {
+      toarray.push_back((*toptr).second);
+    }
+    ++here;
+  }
+}
+
+bool stringmap::fromexists (const text_t &from) const {
+  return (mapfrom.find (from) != mapfrom.end ());
+}
+
+bool stringmap::toexists (const text_t &to) const {
+  text_tarray::const_iterator here = fromorder.begin();
+  text_tarray::const_iterator end = fromorder.end();
+  text_tmap::const_iterator toptr;
+
+  while (here != end) {
+    toptr = mapfrom.find (*here);
+    if (toptr != mapfrom.end() && (*toptr).second == to) return true;
+    ++here;
+  }
+  
+  // it was not found
+  return false;
+}
+
+bool stringmap::from2to (const text_t &from, text_t &to) const {
+  text_tmap::const_iterator toptr = mapfrom.find (from);
+  if (toptr == mapfrom.end()) {
+    to.clear();
+    return false;
+  }
+
+  to = (*toptr).second;
+  return true;
+}
+
+bool stringmap::to2from (const text_t &to, text_t &from) const {
+  text_tarray::const_iterator here = fromorder.begin();
+  text_tarray::const_iterator end = fromorder.end();
+  text_tmap::const_iterator toptr;
+
+  while (here != end) {
+    toptr = mapfrom.find (*here);
+    if (toptr != mapfrom.end() && (*toptr).second == to) {
+      from = (*toptr).first;
+      return true;
+    }
+    ++here;
+  }
+  
+  // it was not found
+  from.clear();
+  return false;
+}
+
+
+
+void splitmapentry (const text_t &mapentry, text_t &from, text_t &to) {
+  from.clear ();
+  to.clear();
+
+  text_t::const_iterator here = mapentry.begin();
+  text_t::const_iterator end = mapentry.end();
+
+  // get the "from" part of the map
+  while (here != end) {
+    if (*here == '-') {
+      ++here;
+      if (here != end && *here == '>') {
+	++here;
+	break; // found "->"
+      }
+
+      // didn't find "->"
+      from.push_back('-');
+
+    } else {
+      from.push_back(*here);
+      ++here;
+    }
+  }
+
+  // get the "to" part of the map
+  while (here != end) {
+    to.push_back(*here);
+    ++here;
+  }
+}
+
+void joinmapentry (const text_t &from, const text_t &to, text_t &mapentry) {
+  mapentry = from;
+  mapentry += "->";
+  mapentry += to;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/maptools.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/maptools.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/maptools.h	(revision 10506)
@@ -0,0 +1,66 @@
+/**********************************************************************
+ *
+ * maptools.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef MAPTOOLS_H
+#define MAPTOOLS_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+// stringmap is a mapping which remembers the original order 
+// of the map, but is very fast to look up.
+class stringmap {
+protected:
+  text_tarray fromorder;
+  text_tmap mapfrom;
+
+public:
+  void clear ();
+
+  void importmap (const text_tarray &maparray);
+  void importmap (const text_tarray &maparray, bool keepold);
+  void exportmap (text_tarray &maparray) const;
+
+  void getfromarray (text_tarray &fromarray) const;
+  void gettoarray (text_tarray &toarray) const;
+  
+  bool fromexists (const text_t &from) const;
+  bool toexists (const text_t &to) const;
+
+  // from2to and to2from return false if the key (the "from"
+  // field or the "to" field) cannot be found
+  bool from2to (const text_t &from, text_t &to) const;
+  bool to2from (const text_t &to, text_t &from) const;
+};
+
+
+// a few useful functions used by stringmap
+void splitmapentry (const text_t &mapentry, text_t &from, text_t &to);
+void joinmapentry (const text_t &from, const text_t &to, text_t &mapentry);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mggdbmsource.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mggdbmsource.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mggdbmsource.cpp	(revision 10506)
@@ -0,0 +1,37 @@
+/**********************************************************************
+ *
+ * mggdbmsource.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "mggdbmsource.h"
+
+mggdbmsourceclass::mggdbmsourceclass () 
+  : gdbmsourceclass()
+{
+  classname = "mggdbsource";
+}
+
+mggdbmsourceclass::~mggdbmsourceclass () 
+{
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mggdbmsource.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mggdbmsource.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mggdbmsource.h	(revision 10506)
@@ -0,0 +1,48 @@
+/**********************************************************************
+ *
+ * mggdbmsource.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef MGGDBMSOURCE_H
+#define MGGDBMSOURCE_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+#include "infodbclass.h"
+#include "maptools.h"
+#include "search.h"
+#include "gdbmsource.h"
+
+
+class mggdbmsourceclass : public gdbmsourceclass {
+public:
+  mggdbmsourceclass ();
+  virtual ~mggdbmsourceclass ();
+
+};
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppqueryfilter.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppqueryfilter.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppqueryfilter.cpp	(revision 10506)
@@ -0,0 +1,384 @@
+/**********************************************************************
+ *
+ * queryfilter.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+
+#include "mgppqueryfilter.h"
+#include "fileutil.h"
+#include <assert.h>
+#include "mgppsearch.h"
+
+/////////////////////////////////
+// functions for queryfilterclass
+/////////////////////////////////
+
+
+mgppqueryfilterclass::mgppqueryfilterclass () 
+  : queryfilterclass() {
+
+  
+  FilterOption_t filtopt;
+  
+  // -- onePerTerm  Level          enumerated
+  // likely to be Doc, Sec, Para, but we dont assume anything now
+  filtopt.clear();
+  filtopt.name = "Level";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filterOptions["Level"] = filtopt;
+
+  // --  IndexField, enumerated, used to list available fields
+  filtopt.clear();
+  filtopt.name = "IndexField";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "";
+  filterOptions["IndexField"] = filtopt;
+
+}
+
+mgppqueryfilterclass::~mgppqueryfilterclass () {
+}
+
+
+//whether a query is a full text browse
+bool mgppqueryfilterclass::full_text_browse (int filterRequestOptions) {
+  return (filterRequestOptions & FRfullTextBrowse);
+}
+
+void mgppqueryfilterclass::configure (const text_t &key, const text_tarray &cfgline) {
+  queryfilterclass::configure(key, cfgline);
+
+  if (key == "indexfieldmap") {
+    indexfieldmap.importmap (cfgline);
+    
+    // update the list of indexes in the filter information
+    text_tarray options;
+    indexfieldmap.gettoarray (options);
+    filterOptions["IndexField"].validValues.erase(filterOptions["IndexField"].validValues.begin(), filterOptions["IndexField"].validValues.end());
+    text_tarray::const_iterator here = options.begin();
+    text_tarray::const_iterator end = options.end();
+    bool start = true;
+    while (here !=end) {
+      if (!(*here).empty()) {
+	filterOptions["IndexField"].validValues.push_back(*here);
+	if (start) {
+	  filterOptions["IndexField"].defaultValue = *here;
+	  start = false;
+	}
+      }
+      ++here;
+    }
+    
+  } else if (key == "indexlevels") {
+    text_tarray::const_iterator here = cfgline.begin();
+    text_tarray::const_iterator end = cfgline.end();
+    bool first=true;
+    filterOptions["Level"].validValues.erase(filterOptions["Level"].validValues.begin(), filterOptions["Level"].validValues.end());
+    while (here != end) {
+      if (!(*here).empty()) {
+	if (first) {
+	  first = false;
+	  // the default is the first value
+	  filterOptions["Level"].defaultValue = *here;
+	}
+	filterOptions["Level"].validValues.push_back(*here);
+      }
+      ++here;
+    }
+  } else if (key == "textlevel") {
+      ((mgppsearchclass *)textsearchptr)->set_gdbm_level( cfgline[0]);
+  } else if (key == "indexstem") {
+    ((mgppsearchclass *)textsearchptr)->set_indexstem (cfgline[0]);
+  }
+  
+}
+
+
+void mgppqueryfilterclass::filter(const FilterRequest_t &request,
+				  FilterResponse_t &response,
+				  comerror_t &err, ostream &logout) {  
+
+
+  outconvertclass text_t2ascii;
+
+  response.clear ();
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: queryfilter contains a null gdbmclass\n\n";
+    err = configurationError;
+    return;
+  }
+  if (textsearchptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: queryfilter contains a null textsearchclass for mgpp\n\n";
+    err = configurationError;
+    return;
+  }
+  if (full_text_browse(request.filterResultOptions)) {
+    browsefilter(request, response, err, logout);
+    return;
+  }
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return;
+  }
+
+
+  // get the query parameters
+  int startresults, endresults;
+  text_t phrasematch; // not used here any more
+  vector<queryparamclass> queryfilterparams;
+  parse_query_params (request, queryfilterparams, startresults, 
+		      endresults, phrasematch, logout);  
+ 
+   
+  // do query
+  queryresultsclass queryresults;
+  do_multi_query (request, queryfilterparams, queryresults, err, logout);
+  if (err != noError) return;
+  // assemble document results
+  if (need_matching_docs (request.filterResultOptions)) {
+    
+    int resultnum = 1;
+    ResultDocInfo_t resultdoc;
+    text_t trans_OID;
+    vector<int>::iterator docorder_here = queryresults.docs.docorder.begin();
+    vector<int>::iterator docorder_end = queryresults.docs.docorder.end();
+
+    if (endresults == -1) endresults = MAXNUMDOCS;
+    while (docorder_here != docorder_end) {
+      if (resultnum > endresults) break;
+      
+      // translate the document number
+      if (!translate(gdbmptr, *docorder_here, trans_OID)) {
+	logout << text_t2ascii
+	       << "warning: could not translate mgpp document number \""
+	       << *docorder_here << "\"to OID.\n\n";
+	
+      } else {
+	docresultmap::iterator docset_here = queryresults.docs.docset.find (*docorder_here);
+
+	// see if there is a result for this number,
+	// if it is in the request set (or the request set is empty)
+	if (docset_here != queryresults.docs.docset.end() &&
+	    (request.docSet.empty() || in_set(request.docSet, trans_OID))) {
+	  if (resultnum >= startresults) {
+	    // add this document
+	    resultdoc.OID = trans_OID;
+	    resultdoc.result_num = resultnum;
+	    resultdoc.ranking = (int)((*docset_here).second.docweight * 10000.0 + 0.5);
+
+	    response.docInfo.push_back (resultdoc);
+	  }
+	  
+	  ++resultnum;
+	}
+      } // else
+      
+      ++docorder_here;
+    }
+  } // if need matching docs
+
+  // assemble the term results
+  if (need_term_info(request.filterResultOptions)) {
+    // note: the terms have already been sorted and uniqued - ?? have they??
+
+    TermInfo_t terminfo;
+    bool terms_first = true;
+
+    termfreqclassarray::iterator terms_here = queryresults.terms.begin();
+    termfreqclassarray::iterator terms_end = queryresults.terms.end();
+
+    while (terms_here != terms_end) {
+      terminfo.clear();
+      terminfo.term = (*terms_here).termstr;
+      terminfo.freq = (*terms_here).termfreq;
+
+      // this bit gets the matchTerms ie the equivalent (stem/casefold) terms
+      if (terms_first) {
+	text_tset::iterator termvariants_here = queryresults.termvariants.begin();
+	text_tset::iterator termvariants_end = queryresults.termvariants.end();
+	while (termvariants_here != termvariants_end) {
+	  terminfo.matchTerms.push_back (*termvariants_here);
+	  ++termvariants_here;
+	}
+      }
+      terms_first = false;
+      
+      response.termInfo.push_back (terminfo);
+
+      ++terms_here;
+    }
+  }
+
+  response.numDocs = queryresults.docs_matched;
+  response.isApprox = queryresults.is_approx;
+}
+
+void mgppqueryfilterclass::browsefilter(const FilterRequest_t &request,
+					FilterResponse_t &response,
+					comerror_t &err, ostream &logout) {  
+
+  outconvertclass text_t2ascii;
+
+  // get the query parameters
+  int startresults, endresults;
+  text_t phrasematch; // not used here any more, just have it so can use
+                      // parse_query_params function
+  
+  vector<queryparamclass> queryfilterparams;
+  parse_query_params (request, queryfilterparams, startresults, 
+		      endresults, phrasematch, logout);  
+
+    vector<queryparamclass>::const_iterator query_here = queryfilterparams.begin();
+   
+  // do query
+  queryresultsclass queryresults;
+  queryresults.clear();
+  
+  int numDocs = endresults-startresults;
+  textsearchptr->setcollectdir (collectdir);
+
+  if (!((mgppsearchclass*)textsearchptr)->browse_search((*query_here), startresults, numDocs, queryresults)) {
+    // most likely a system problem
+    logout << text_t2ascii
+	   << "system problem: could not do full text browse with mgpp for index \""
+	   << (*query_here).index << (*query_here).subcollection
+	   << (*query_here).language << "\".\n\n";
+    err = systemProblem;
+    return;
+  }
+
+  // assemble the term results
+  TermInfo_t terminfo;
+  
+  termfreqclassarray::iterator terms_here = queryresults.terms.begin();
+  termfreqclassarray::iterator terms_end = queryresults.terms.end();
+
+  while (terms_here != terms_end) {
+    terminfo.clear();
+    terminfo.term = (*terms_here).termstr;
+    terminfo.freq = (*terms_here).termfreq;
+    
+    response.termInfo.push_back (terminfo);
+
+    ++terms_here;
+  }
+  
+
+}
+
+// mgppsearchptr and gdbmptr are assumed to be valid
+void mgppqueryfilterclass::do_multi_query (const FilterRequest_t &request,
+					   const vector<queryparamclass> &query_params,
+					   queryresultsclass &multiresults,
+					   comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  err = noError;
+  textsearchptr->setcollectdir (collectdir);
+  multiresults.clear();
+  
+  vector<queryparamclass>::const_iterator query_here = query_params.begin();
+  vector<queryparamclass>::const_iterator query_end = query_params.end();
+  while (query_here != query_end) {
+    queryresultsclass thisqueryresults;
+    text_t indx((*query_here).index);
+    if (!textsearchptr->search((*query_here), thisqueryresults)) {
+      // most likely a system problem
+      logout << text_t2ascii
+	     << "system problem: could not do search with mgpp for index \""
+	     << (*query_here).index << (*query_here).subcollection
+	     << (*query_here).language << "\".\n\n";
+      err = systemProblem;
+      return;
+    }
+
+    // check for syntax error
+    if (thisqueryresults.syntax_error==true) {
+      logout << text_t2ascii
+	     << "syntax problem: invalid query string \""
+	     << (*query_here).querystring<<"\".\n";
+      err = syntaxError;
+      return;
+    }
+    // combine the results
+    if (need_matching_docs (request.filterResultOptions)) {
+            
+      if (query_params.size() == 1) {
+	multiresults.docs = thisqueryresults.docs; // just one set of results
+	multiresults.docs_matched = thisqueryresults.docs_matched;
+	multiresults.is_approx = thisqueryresults.is_approx;
+	
+      } else {
+	if ((*query_here).combinequery == "and") {
+	  multiresults.docs.combine_and (thisqueryresults.docs);
+	} else if ((*query_here).combinequery == "or") {
+	  multiresults.docs.combine_or (thisqueryresults.docs);
+	} else if ((*query_here).combinequery == "not") {
+	  multiresults.docs.combine_not (thisqueryresults.docs);
+	}
+	multiresults.docs_matched = multiresults.docs.docset.size();
+	multiresults.is_approx = Exact;
+      }
+    }
+
+    // combine the term information 
+    if (need_term_info (request.filterResultOptions)) {
+      // append the terms
+      multiresults.orgterms.insert(multiresults.orgterms.end(),
+				   thisqueryresults.orgterms.begin(),
+				   thisqueryresults.orgterms.end());
+
+      
+      // add the term variants - 
+      text_tset::iterator termvar_here = thisqueryresults.termvariants.begin();
+      text_tset::iterator termvar_end = thisqueryresults.termvariants.end();
+      while (termvar_here != termvar_end) {
+	multiresults.termvariants.insert(*termvar_here);
+	++termvar_here;
+      }
+    }
+   
+    ++query_here;
+  }
+
+  // sort and unique the query terms
+  multiresults.sortuniqqueryterms ();
+}
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppqueryfilter.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppqueryfilter.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppqueryfilter.h	(revision 10506)
@@ -0,0 +1,67 @@
+/**********************************************************************
+ *
+ * mgppqueryfilter.h -- new queryfilter to use mgpp 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef MGPPQUERYFILTER_H
+#define MGPPQUERYFILTER_H
+
+#include "queryfilter.h"
+
+class mgppqueryfilterclass : public queryfilterclass {
+protected:
+
+  stringmap indexfieldmap;
+  bool full_text_browse (int filterRequestOptions);
+
+  // mgsearchptr and gdbmptr are assumed to be valid
+  void do_multi_query (const FilterRequest_t &request,
+		       const vector<queryparamclass> &query_params,
+		       queryresultsclass &multiresults,
+		       comerror_t &err, ostream &logout);
+
+
+public:
+  mgppqueryfilterclass ();
+  virtual ~mgppqueryfilterclass ();
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  void filter (const FilterRequest_t &request,
+		       FilterResponse_t &response,
+		       comerror_t &err, ostream &logout);
+  
+  void browsefilter(const FilterRequest_t &request,
+		    FilterResponse_t &response,
+		    comerror_t &err, ostream &logout);  
+
+
+};
+
+#endif
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppsearch.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppsearch.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppsearch.cpp	(revision 10506)
@@ -0,0 +1,340 @@
+/**********************************************************************
+ *
+ * mgppsearch.cpp -- 
+ * Copyright (C) 1999-2002  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#include "gsdlconf.h"
+#include "mgppsearch.h"
+#include "fileutil.h"
+#include "GSDLQueryParser.h"
+#include "MGQuery.h"
+#include "TextGet.h"
+#include "queryinfo.h"
+#include "gsdlunicode.h"
+
+
+text_t mgppsearchclass::getindexsuffix(const queryparamclass &qp) {
+  return getindexsuffix(qp.collection, qp.index+qp.subcollection+qp.language);
+
+}
+
+text_t mgppsearchclass::getindexsuffix (const text_t &collection, 
+			      const text_t &index) {
+
+  text_t indexsuffix = "index";  
+  indexsuffix = filename_cat (indexsuffix, index);
+  if (indexstem.empty()) {
+    // no index stem, use the coll name
+    indexsuffix = filename_cat (indexsuffix, collection);
+  } else {
+    indexsuffix = filename_cat (indexsuffix, indexstem);
+  }
+  return indexsuffix;
+}
+
+////////////////////
+// mgppsearch class //
+////////////////////
+
+mgppsearchclass::mgppsearchclass ()
+  : searchclass() {
+
+  gdbm_level = "Doc";
+  indexData = NULL;
+}
+
+mgppsearchclass::~mgppsearchclass () 
+{
+  if (cache != NULL) 
+    {
+      delete cache;
+      cache = NULL;
+    }
+
+  if (indexData !=NULL) {
+    indexData->UnloadData();
+    delete indexData;
+    indexData = NULL;
+  }
+  
+}
+
+void mgppsearchclass::set_gdbm_level(const text_t &level) {
+  gdbm_level = level;
+  
+}
+void mgppsearchclass::set_indexstem(const text_t &stem) {
+  indexstem = stem;
+  
+}
+
+
+bool mgppsearchclass::search(const queryparamclass &queryparams, 
+			     queryresultsclass &queryresult) {
+ 
+#ifdef __WIN32__
+  char basepath[]="";
+#else
+  char basepath[] = "/";
+#endif
+ 
+  char *indexname = (filename_cat(collectdir, getindexsuffix(queryparams))).getcstr(); 
+
+ // load index data
+  if (indexData == NULL) {
+    indexData = new IndexData();
+  }
+  if (!indexData->LoadData (basepath, indexname)) {
+    cerr<<"couldn't load index data\n"<<endl;
+    return false;
+  }
+
+  // set default stem method from values originally set on prefs page
+  int defaultStemMethod = 0;
+  if (queryparams.casefolding) {
+    defaultStemMethod |= 1;
+  }
+  if (queryparams.stemming) {
+    defaultStemMethod |= 2;
+  }
+  
+  // set default Boolean combiner from all/some setting
+  // if match_mode == 1, ie all, default=1 ie AND
+  // if match_mode == 0, ie some, default=0, ie OR
+  int defaultBoolCombine = 0;
+  if (queryparams.match_mode){
+    defaultBoolCombine = 1;
+  }
+
+  // use default query info settings - change to reflect user preferences??
+  QueryInfo queryInfo;
+  
+  SetCStr (queryInfo.docLevel, (queryparams.level.getcstr())); 
+  queryInfo.maxDocs = (unsigned long)queryparams.maxdocs;
+  queryInfo.sortByRank = (queryparams.search_type == 1);
+  queryInfo.exactWeights = false;
+  queryInfo.needRankInfo = true; // used for overall term freq as well as ranking
+  queryInfo.needTermFreqs = true;
+  
+  ExtQueryResult queryResult;
+  
+  UCArray queryArray;
+  // greenstone gives us the query encoded in unicode. We want utf8.
+  char* utf8querystring=to_utf8(queryparams.querystring).getcstr();
+  SetCStr(queryArray, utf8querystring);
+  delete []utf8querystring;
+
+  // create the mgpp query tree
+  QueryNode *queryTree = NULL;
+  queryTree = ParseQuery(queryArray, defaultBoolCombine, defaultStemMethod);
+  if (queryTree == NULL) { // syntax error
+    queryresult.syntax_error = true;
+    return true; // should we return true or false?
+  }
+  UCArray level;
+  UCArrayClear(level);
+  
+  //set the level for results
+  SetCStr(level, gdbm_level.getcstr());
+
+  
+  // do the query
+  MGQuery(*indexData, queryInfo, queryTree, queryResult, level);
+  
+ 
+  // convert ExtQueryResult to queryresultclass
+  
+  queryresult.docs_matched = (int)queryResult.docs.size();
+
+  if (queryresult.docs_matched == (int)queryResult.actualNumDocs) {
+    queryresult.is_approx = Exact; 
+  }
+  else if (queryresult.docs_matched < (int)queryResult.actualNumDocs) {
+    queryresult.is_approx = MoreThan;
+  }
+  else {
+    queryresult.is_approx = Approximate;
+  }
+
+  docresultclass doc;
+  for (int i=0; i<(int)queryResult.docs.size(); ++i) {
+    doc.clear();
+    doc.docnum = (int)queryResult.levels[i];
+    doc.docweight = queryResult.ranks[i];
+    queryresult.docs.docset[doc.docnum] = doc;
+    queryresult.docs.docorder.push_back(doc.docnum);
+
+  }
+
+  // term info
+  termfreqclass term;
+  for (int k=0; k<(int)queryResult.termFreqs.size(); ++k) {
+    term.clear();
+    char* termfreq_cstr=GetCStr(queryResult.termFreqs[k].term);
+    term.termstr = to_uni(termfreq_cstr);
+    delete []termfreq_cstr;
+    term.termstemstr = term.termstr;
+    // we don't set term.utf8equivterms ?? - jrm21
+    term.termfreq = queryResult.termFreqs[k].termFreq;
+    queryresult.terms.push_back(term);
+    queryresult.orgterms.push_back(term); // should this change??
+    
+    for (int j=0; j<(int)queryResult.termFreqs[k].equivTerms.size(); ++j) {
+      char* equivterm_cstr=GetCStr(queryResult.termFreqs[k].equivTerms[j]);
+      queryresult.termvariants.insert(to_uni(equivterm_cstr));
+      delete []equivterm_cstr;
+    }
+
+  }
+  // clean up
+  delete []indexname;
+  return true;
+
+}
+
+
+bool mgppsearchclass::browse_search(const queryparamclass &queryparams, int start, int numDocs,
+				    queryresultsclass &queryresult) {
+
+#ifdef __WIN32__
+  char basepath[]="";
+#else
+  char basepath[] = "/";
+#endif
+
+  char *indexname = (filename_cat(collectdir, getindexsuffix(queryparams))).getcstr();
+ 
+  if (indexData == NULL) {
+    indexData = new IndexData();
+  }
+  if (!indexData->LoadData (basepath, indexname)) {
+    cerr<<"couldn't load index data\n"<<endl;
+    return false;
+  }
+
+  UCArray level;
+  UCArrayClear(level);
+  
+  //browse always at top level
+  SetCStr(level, "Doc"); // this name may change.
+  
+
+  BrowseQueryNode browseNode;
+  browseNode.startPosition = start;
+  browseNode.numTerms = numDocs;
+
+  BrowseQueryResult browseResult;
+
+  UCArrayClear(browseNode.term);
+  // greenstone gives us the query encoded in unicode. We want utf8.
+  char* utf8querystring=to_utf8(queryparams.querystring).getcstr();
+  SetCStr(browseNode.term, utf8querystring);
+  delete []utf8querystring;
+
+  // do the actual query
+  MGBrowseQuery(*indexData, level, browseNode, browseResult);
+
+  // load results into term info
+  termfreqclass term;
+  for (int i=0; i<(int)browseResult.termFreqs.size(); ++i) {
+    term.clear();
+    char* term_cstr = GetCStr(browseResult.termFreqs[i].term);
+    term.termstr = to_uni(term_cstr);
+    delete []term_cstr;
+    term.termstemstr = term.termstr;
+    term.termfreq = browseResult.termFreqs[i].termFreq;
+    queryresult.terms.push_back(term);
+    queryresult.orgterms.push_back(term);
+
+  }
+  // clean up
+  delete []indexname;
+
+  return true;
+}
+
+// the document text for 'docnum' is placed in 'output'
+// docTargetDocument returns 'true' if it was able to
+// try to get a document
+// collection is needed to see if an index from the 
+// collection is loaded. THe default index bits are just there cos
+// the mg version needs them
+
+bool mgppsearchclass::docTargetDocument(const text_t &/*defaultindex*/,
+					const text_t &/*defaultsubcollection*/,
+					const text_t &/*defaultlanguage*/,
+					const text_t &collection,
+					int docnum,
+					text_t &output) {
+  
+#ifdef __WIN32__
+  char basepath[]="";
+#else
+  char basepath[] = "/";
+#endif
+  char *textname = (filename_cat(collectdir, getindexsuffix(collection, "text"))).getcstr();
+ 
+  TextData textdata;
+  if(!textdata.LoadData(basepath, textname)) {
+    cout<<"couldn't load text data\n"<<endl;
+    return false;
+  }
+  UCArray doctext;
+  UCArray level;
+  SetCStr(level, gdbm_level.getcstr());
+  if (!GetDocText(textdata, level, (unsigned long)docnum, doctext)) {
+    cout<<"couldn't retrieve document text\n";
+    return false;
+  }
+
+  // convert UCArray to text_t
+  output.clear();
+  char* doctext_cstr = GetCStr(doctext);
+  output = to_uni(doctext_cstr); // convert from utf-8 to unicode
+  delete []doctext_cstr;
+
+  // here need to remove the <Document>, <Section>, <Paragraph> tags
+
+  
+  //clean up
+  textdata.UnloadData ();
+  delete []textname;
+
+  return true;
+
+}
+
+// used to clear any cached databases for persistent versions of 
+// Greenstone like the Windows local library
+void mgppsearchclass::unload_database () {
+
+  if (indexData !=NULL) {
+    indexData->UnloadData();
+  }
+}
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppsearch.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppsearch.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgppsearch.h	(revision 10506)
@@ -0,0 +1,99 @@
+/**********************************************************************
+ *
+ * mgppsearch.h -- implementation of search class for mgpp
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * 
+ *
+ *********************************************************************/
+
+
+#ifndef MGPPSEARCH_H
+#define MGPPSEARCH_H
+
+#include "search.h"
+#include "IndexData.h"
+
+class mgppsearchclass : public searchclass {
+public:
+  mgppsearchclass ();
+  virtual ~mgppsearchclass ();
+
+  virtual text_t get_textindex_type() {return "mgpp";}
+
+  // the search results are returned in queryresults
+  // search returns 'true' if it was able to do a search
+  virtual bool search(const queryparamclass &queryparams, 
+	      queryresultsclass &queryresults);
+  
+  // this returns a list of terms in queryresults - no document info is returned
+  // returns a list of numTerms terms, starting from the query string term (in queryparams)
+  // + start. used for full text browsing
+  virtual bool browse_search(const queryparamclass &queryparams, int start, int numTerms,
+			     queryresultsclass &queryresults);
+
+  // the document text for 'docnum' is placed in 'output'
+  // docTargetDocument returns 'true' if it was able to
+  // try to get a document
+  // collection is needed to see if an index from the 
+  // collection is loaded. If no index has been loaded
+  // defaultindex is needed to load one
+  virtual bool docTargetDocument(const text_t &defaultindex,
+			 const text_t &defaultsubcollection,
+			 const text_t &defaultlanguage,
+			 const text_t &collection,
+			 int docnum,
+			 text_t &output);
+
+  /*  // same as docTargetDocument except the document is returned
+  // in its raw form. UDoc remains the property of mg and may
+  // be destroyed on the next call to mg.
+  // not implemented for mgpp
+  virtual bool mgdocument (const text_t &defaultindex,
+		   const text_t &defaultsubcollection,
+		   const text_t &defaultlanguage,
+		   const text_t &collection,
+		   int docnum,
+		   char *&UDoc, int &ULen);
+  */
+  
+  void set_gdbm_level(const text_t &level);
+  
+  void set_indexstem(const text_t &indexstem);
+
+  // used to clear any cached databases for persistent versions of 
+  // Greenstone like the Windows local library
+  void unload_database ();
+ protected:
+  
+  text_t gdbm_level; // the default level used for retrieval, and in the gdbm file 
+  text_t indexstem; // the stem of the index file names
+  IndexData *indexData; // the index data structure needed for MGQuery - keep
+  // as a cache
+  
+  text_t getindexsuffix(const queryparamclass &qp);
+  text_t getindexsuffix (const text_t &collection, const text_t &index);
+
+};
+
+
+#endif
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgq.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgq.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgq.c	(revision 10506)
@@ -0,0 +1,731 @@
+/**********************************************************************
+ *
+ * mgq.c -- cut-dowm version of mgquery
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "mgq.h"
+
+
+#include <stdio.h>
+#include <string.h>
+/* #include <io.h> */
+#include <fcntl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  
+#include "sysfuncs.h"
+  
+#include "messages.h"
+#include "memlib.h"
+  
+#include "invf.h"
+#include "text.h"
+#include "lists.h"
+#include "backend.h"
+#include "environment.h"
+#include "globals.h"
+#include "mg_errors.h"
+#include "commands.h"
+#include "text_get.h"
+#include "term_lists.h"
+#include "local_strings.h"
+
+#include "words.h"
+#include "stemmer.h"
+#include "stem_search.h"
+  
+#ifdef __cplusplus
+}
+#endif
+
+
+#include "mgq.h"
+
+/* get a reasonable database cache size */
+#ifndef MAXNUMDATABASEINFO
+#  ifdef GSDLSERVER
+#    define MAXNUMDATABASEINFO 10
+#  else
+#    define MAXNUMDATABASEINFO 2
+#  endif
+#endif
+
+#define MAXCOLLECTIONLEN  16
+#define MAXMGDIRLEN       256
+#define MAXGENSUFFIXLEN   256
+#define MAXTEXTSUFFIXLEN  256
+
+typedef struct DatabaseInfo {
+  int accessnum; /* -1 = invalid record */
+  char collection[MAXCOLLECTIONLEN];
+  char mgdir[MAXMGDIRLEN];
+  char gensuffix[MAXGENSUFFIXLEN];
+  char textsuffix[MAXTEXTSUFFIXLEN];
+  query_data *qd;
+} DatabaseInfo;
+
+
+/* globals needed by some vague part of mg... */
+FILE *OutFile = NULL, *InFile = NULL;
+int OutPipe = 0, InPipe = 0;
+int Quitting = 0;
+
+/* globals needed to handle loading of databases */
+static int cur_cachenum = -1;
+
+/* globals needed by the database cache */
+static DatabaseInfo dbcache[MAXNUMDATABASEINFO];
+static int cache_nextaccessnum = 0;
+static int cache_numloaded = 0;
+
+
+
+#if defined(PARADOCNUM) ||  defined(NZDL)
+static int GetDocNumFromParaNum(query_data *qd, int paranum) {
+  int Documents = qd->td->cth.num_of_docs;
+  int *Paragraph = qd->paragraph;
+  int low = 1, high = Documents;
+  int mid = (low+high)/2;
+
+  while ((mid = (low+high)/2) >=1 && mid <= Documents)
+    {
+      if (paranum > Paragraph[mid])
+        low = mid+1;
+      else if (paranum <= Paragraph[mid-1])
+        high = mid-1;
+      else
+        return mid;
+    }
+  FatalError(1, "Bad paragraph number.\n");
+  return 0;
+}
+
+static int GetParaNumFromDocNum(query_data *qd, int docnum) {
+  int Documents = qd->td->cth.num_of_docs;
+  int *Paragraph = qd->paragraph;
+
+  if (docnum > 0 && docnum <= Documents)
+    return Paragraph[docnum-1]+1;
+  return 0;
+}
+#endif
+
+
+/*****************************************************************************/
+
+static void MGQError(char *emsg)
+{
+  fprintf(stderr,"Fatal error: %s\n", emsg);
+  exit(1);
+}
+
+static int ProcessDocs (query_data * qd, int skip, int howmany, 
+			enum result_kinds kind, 
+			int (*sender)(char *,int,int,float,void *), void *ptr) {
+  int max_buf = 0, output_failure = 0;
+  int DocCount = 0;
+  int need_text = (kind == result_docs);
+
+  /* skip the requested number of documents */
+  while (skip > 0) {
+    if (!NextDoc(qd)) return 0;
+    skip--;
+  }
+
+  /* find out the maximum size for the text buffer */
+  if (need_text) max_buf = atoi (GetDefEnv ("buffer", "1048576"));
+
+  /* process each document */
+  do {
+    u_char *UDoc = NULL;
+    unsigned long ULen=0;
+
+#if defined(PARADOCNUM) ||  defined(NZDL)
+    /* adjust the document number for paragraph level result_docs */
+    /* this is a bit of a hack ... */
+    if (kind==result_docs && qd->id->ifh.InvfLevel == 3 &&
+	qd->DL != NULL && (int)qd->doc_pos < (int)qd->DL->num)
+      qd->DL->DE[qd->doc_pos].DocNum = GetParaNumFromDocNum(qd, qd->DL->DE[qd->doc_pos].DocNum);
+#endif
+    
+    if (need_text) {
+      /* load the compressed text */
+      if (LoadCompressedText (qd, max_buf))
+	MGQError("Unable to load compressed text(memory?).");
+
+      /* uncompress the loaded text */
+      UDoc = GetDocText (qd, &ULen);
+      if (UDoc == NULL) MGQError("UDoc is unexpectedly NULL");
+    }
+      
+    if (UDoc != NULL  ||  kind == result_docnums) {
+      int docnum = GetDocNum(qd);
+#if defined(PARADOCNUM) ||  defined(NZDL)
+      if (qd->id->ifh.InvfLevel == 3) docnum = GetDocNumFromParaNum(qd, docnum);
+#endif
+      switch (kind) {
+      case result_docnums:
+	if (sender != NULL)
+	  output_failure = (*sender)("",0,docnum,GetDocWeight(qd),ptr);
+	break;
+      case result_docs:
+	if (sender != NULL)
+	  output_failure = (*sender)((char *)UDoc,ULen,docnum,GetDocWeight(qd),ptr);
+	break;
+      default:
+	break;
+      }
+    }
+    DocCount++;
+      
+  } while (NextDoc (qd) && output_failure == 0 && --howmany > 0);
+  
+  /*  if (need_text) FreeTextBuffer (qd);*/
+  
+  return (DocCount);
+}
+
+
+static void send_query_term_freqs(QueryTermList *qtl,
+				  int (*sender)(char *,int,int,float,void *), void *ptr)
+{
+  int i = 0;
+  for (i = 0; i < qtl->num; i++)
+    if (sender != NULL) {
+      /*      word = word2str(qtl->QTE[i].Term); 
+	      (* sender)(word, strlen(word), qtl->QTE[i].Count, (float)0.0, ptr); */
+      (* sender)((char *)(qtl->QTE[i].Term+1), qtl->QTE[i].Term[0], 
+		 qtl->QTE[i].Count, (float)0.0, ptr);
+    }
+}
+
+
+static void send_terms (TermList * qtl, 
+			int (*sender)(char *,int,int,float,void *), void *ptr)
+{
+  int i = 0;
+  if (sender == NULL) return;
+  for (i = 0; i < qtl->num; i++)
+    {
+      /*      word = word2str(qtl->TE[i].Word);
+	      (* sender)(word, strlen(word), qtl->TE[i].Count, (float)0.0, ptr);*/
+      (* sender)((char *)(qtl->TE[i].Word+1), qtl->TE[i].Word[0], 
+		 qtl->TE[i].Count, (float)0.0, ptr);
+    }
+}
+
+
+/* MoreDocs () */
+/* Displays all documents in list  DocList. */
+/* Documents are fetched, then decompressed and displayed according to the */
+/* format implied in  FormString(). */
+
+static void
+MoreDocs (query_data * qd, enum result_kinds kind, 
+	  int skip, int howmany,
+	  int (*sender)(char *,int,int,float,void *), void *ptr)
+{
+  qd->num_of_ans = qd->DL->num;
+  switch (kind) {
+  case result_docs:
+  case result_docnums:
+    if (qd->num_of_ans > 0)
+      ProcessDocs (qd, skip, howmany, kind, sender, ptr);
+    break;
+  case result_termfreqs:
+    send_query_term_freqs(qd->QTL, sender, ptr);
+    break;
+  case result_terms:
+    send_terms(qd->TL, sender, ptr);
+    break;
+  }
+}
+
+
+
+
+
+
+/******************************************
+ * functions to handle the database cache *
+ ******************************************/
+
+/* init_dbcache should be called at the start of each */
+/* function which deals with the database cache */
+static void init_dbcache (void) {
+  static int dbcacheinited = 0;
+  int i = 0;
+
+  if (dbcacheinited) return;
+
+  cache_numloaded = 0;
+
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    dbcache[i].accessnum = -1;
+    dbcache[i].collection[0] = '\0';
+    dbcache[i].mgdir[0] = '\0';
+    dbcache[i].gensuffix[0] = '\0';
+    dbcache[i].textsuffix[0] = '\0';
+    dbcache[i].qd = NULL;
+  }
+
+  dbcacheinited = 1;
+}
+
+/* returns the next cache access number and increments it */
+static int get_next_accessnum (void) {
+  return cache_nextaccessnum++;
+}
+
+/* get_free_dbcache returns the cache number which */
+/* was used the longest time ago */
+/* init_dbcache should be called before this function */
+static int get_free_dbcache (void) {
+  int i = 0;
+  int minaccessnum = cache_nextaccessnum; /* the current max */
+  int minpos = 0;
+
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    if (dbcache[i].accessnum < minaccessnum) {
+      minaccessnum = dbcache[i].accessnum;
+      minpos = i;
+    }
+  }
+  
+  return minpos;
+}
+
+/* search_collect will search for an index which */
+/* belongs to a certain collection It returns -1 if none could be found. */
+/* init_dbcache should be called before this function */
+static int search_collect (char *collection) {
+  int i = 0;
+
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    if ((dbcache[i].accessnum >= 0) &&
+	(dbcache[i].qd != NULL) &&
+	(strcmp (collection, dbcache[i].collection) == 0)
+	/* && (dbcache[i].qd->id->ifh.InvfLevel == 2)*/
+	) {
+      dbcache[i].accessnum = get_next_accessnum ();
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+/* search_gensuffix will search for an index which */
+/* has a certain gensuffix. It returns -1 if none could be found. */
+/* init_dbcache should be called before this function */
+static int search_gensuffix (char *gensuffix) {
+  int i = 0;
+
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    if ((dbcache[i].accessnum >= 0) &&
+	(dbcache[i].qd != NULL) &&
+	(strcmp (gensuffix, dbcache[i].gensuffix) == 0)) {
+      dbcache[i].accessnum = get_next_accessnum ();
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+/* unload_database will unload a certain entry within */
+/* the database cache, clearing it for furture use. */
+static void unload_database (int i) {
+  /* check to see if it contains anything */
+  if (dbcache[i].accessnum < 0 || dbcache[i].qd == NULL) 
+    return;
+
+  /* unload all the query information  */
+  FinishQuerySystem(dbcache[i].qd);
+  
+  /* reset all the db info */
+  dbcache[i].accessnum = -1;
+  dbcache[i].collection[0] = '\0';
+  dbcache[i].mgdir[0] = '\0';
+  dbcache[i].gensuffix[0] = '\0';
+  dbcache[i].textsuffix[0] = '\0';
+  dbcache[i].qd = NULL;
+
+  cache_numloaded--;
+  if (cache_numloaded < 0) cache_numloaded = 0;
+}
+
+/* cache_database will store the information about */
+/* a database in the database cache. */
+static void cache_database (int i, char *collection, char *mgdir, char *gensuffix,
+			    char *textsuffix, query_data *qd) {
+  /* make sure this entry has been unloaded first */
+  if (dbcache[i].accessnum >= 0 && dbcache[i].qd != NULL) 
+    unload_database (i);
+
+  /* store the db info */
+  dbcache[i].accessnum = get_next_accessnum ();
+  strcpy (dbcache[i].collection, collection);
+  strcpy (dbcache[i].mgdir, mgdir);
+  strcpy (dbcache[i].gensuffix, gensuffix);
+  strcpy (dbcache[i].textsuffix, textsuffix);
+  dbcache[i].qd = qd;
+
+  cache_numloaded++;
+}
+
+static void make_current (int i) {
+  /* see if it is the current index */
+  if (i == cur_cachenum) return;
+ 
+  /* unload the old index */
+  if (cur_cachenum >= 0) UninitEnv ();
+  cur_cachenum = -1;
+
+  /* make sure the new one is ok */
+  if (i < 0 || dbcache[i].accessnum < 0 || dbcache[i].qd == NULL)
+    return;
+
+  /* load the new one */
+
+  /* Initialise the environment with default values */
+  InitEnv ();
+  
+  SetEnv("mgdir",dbcache[i].mgdir,NULL);
+  SetEnv("mgname",dbcache[i].gensuffix,NULL);
+  SetEnv("textname",dbcache[i].textsuffix,NULL);
+  
+  PushEnv ();
+  
+  cur_cachenum = i;
+}
+
+
+
+/********************
+ * public functions *
+ ********************/
+
+int mgq_ask(char *line)
+{
+  query_data *qd = (query_data *)NULL;
+  char QueryType = QUERY_BOOLEAN;
+  char OutputType = QUERY_DOCNUMS;
+  char *LinePtr = (char *)NULL;
+
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL) return 0;
+  
+  ResetFileStats (qd);
+  qd->max_mem_in_use = qd->mem_in_use = 0;
+  qd->tot_hops_taken += qd->hops_taken;
+  qd->tot_num_of_ptrs += qd->num_of_ptrs;
+  qd->tot_num_of_accum += qd->num_of_accum;
+  qd->tot_num_of_terms += qd->num_of_terms;
+  qd->tot_num_of_ans += qd->num_of_ans;
+  qd->tot_text_idx_lookups += qd->text_idx_lookups;
+  qd->hops_taken = qd->num_of_ptrs = 0;
+  qd->num_of_accum = qd->num_of_ans = qd->num_of_terms = 0;
+  qd->text_idx_lookups = 0;
+  
+  LinePtr = ProcessCommands (line, qd);
+  if (CommandsErrorStr) {
+    fprintf (stderr, "%s\n", CommandsErrorStr);
+    return 0;
+  }
+  if (*LinePtr == '\0') return 1;
+  
+  FreeQueryDocs (qd);
+  
+  QueryType = get_query_type ();
+  OutputType = get_output_type ();
+  /* No point in hiliting words on a docnum query */
+  if (OutputType == OUTPUT_HILITE && QueryType == QUERY_DOCNUMS)
+    OutputType = OUTPUT_TEXT;
+  
+  switch (QueryType)
+    {
+    case QUERY_BOOLEAN:
+      {
+	char *maxdocs = (char *)NULL;
+	BooleanQueryInfo bqi;
+	maxdocs = GetDefEnv ("maxdocs", "all");
+	bqi.MaxDocsToRetrieve = strcmp (maxdocs, "all") ? atoi (maxdocs) : -1;
+        if (qd->sd->sdh.indexed)
+	  BooleanQuery (qd, line, &bqi, (BooleanEnv (GetEnv ("casefold"), 0) |
+					 (BooleanEnv (GetEnv ("stem"), 0) << 1)));
+	else
+	  BooleanQuery (qd, line, &bqi, qd->sd->sdh.stem_method);
+	/*	if (qd->sd->sdh.indexed) BooleanQuery (qd, line, &bqi, 3);
+	else BooleanQuery (qd, line, &bqi, qd->sd->sdh.stem_method); */
+	break;
+      }
+    case QUERY_APPROX:
+    case QUERY_RANKED:
+      {
+	char *maxdocs = (char *)NULL;
+	char *maxterms = (char *)NULL;
+	char *maxaccum = (char *)NULL;
+	RankedQueryInfo rqi;
+	maxdocs = GetDefEnv ("maxdocs", "all");
+	maxterms = GetDefEnv ("max_terms", "all");
+	maxaccum = GetDefEnv ("max_accumulators", "all");
+	rqi.Sort = BooleanEnv (GetEnv ("sorted_terms"), 0);
+	rqi.QueryFreqs = BooleanEnv (GetEnv ("qfreq"), 1);
+	rqi.Exact = QueryType == QUERY_RANKED;
+	rqi.MaxDocsToRetrieve = strcmp (maxdocs, "all") ? atoi (maxdocs) : -1;
+	rqi.MaxTerms = strcmp (maxterms, "all") ? atoi (maxterms) : -1;
+	rqi.MaxParasToRetrieve = rqi.MaxDocsToRetrieve;
+	if (qd->id->ifh.InvfLevel == 3 && GetEnv ("maxparas"))
+	  rqi.MaxParasToRetrieve = atoi (GetEnv ("maxparas"));
+	rqi.AccumMethod = toupper (*GetDefEnv ("accumulator_method", "A"));
+	rqi.MaxAccums = strcmp (maxaccum, "all") ? atoi (maxaccum) : -1;
+	rqi.HashTblSize = IntEnv (GetEnv ("hash_tbl_size"), 1000);
+	rqi.StopAtMaxAccum = BooleanEnv (GetEnv ("stop_at_max_accum"), 0);
+	rqi.skip_dump = GetEnv ("skip_dump");
+	RankedQuery (qd, line, &rqi);
+	break;
+      }
+    case QUERY_DOCNUMS:
+      {
+	DocnumsQuery (qd, line);
+	break;
+      }
+    }
+
+  return 1;
+}
+
+int mgq_numdocs(void)
+{
+  query_data *qd = NULL;
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL) return 0;
+
+  if (qd->DL) return qd->DL->num;
+  else return 0;
+}
+
+int mgq_numterms(void)
+{
+  query_data *qd = NULL;
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL) return 0;
+
+  if (qd->QTL) return qd->QTL->num;
+  else return 0;
+}
+
+int mgq_results(enum result_kinds kind,int skip,int howmany, int (*sender)(char *, int, int, float, void *), void *ptr)
+{
+  query_data *qd = NULL;
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL) return 0;
+
+  if (qd->DL) {
+    qd->doc_pos = 0;
+    MoreDocs(qd, kind, skip, howmany, sender, ptr);
+  }
+  return 0;
+}
+
+/* get all the terms that match wordstem using the current stemmer and */
+/* stemming method. The callback is the same style used by mgq_results */
+int mgq_equivterms (unsigned char *wordstem, int (*sender)(char *, int, int, float, void *),
+		    void *ptr) {
+  int stem_method = 0;
+  query_data *qd = NULL;
+  TermList *equivterms = NULL;  /* used for equivalent terms */
+
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL || wordstem == NULL || sender == NULL) return 0;
+
+  if (qd->sd->sdh.indexed) {
+    stem_method = BooleanEnv(GetEnv("casefold"),0) | (BooleanEnv(GetEnv("stem"),0) << 1);
+  } else {
+    stem_method = qd->sd->sdh.stem_method;
+  }
+
+  /* make the term list */
+  equivterms = MakeTermList (0);
+  
+  /* expand out this word */
+  if (FindWords (qd->sd, wordstem, stem_method, &equivterms) > 0) {
+    int i;
+    for (i=0; i < equivterms->num; i++) {
+      (* sender)((char *)(equivterms->TE[i].Word+1), equivterms->TE[i].Word[0], 
+		 equivterms->TE[i].Count, (float)0.0, ptr);
+    }
+  }
+
+  /* free the term list */
+  if (equivterms != NULL) FreeTermList (&equivterms);
+
+  return 0;
+}
+
+/* gets the total number of documents retrieved. If this is not available */
+/* it will set total_retrieved to 0 (even when it obviously isn't) */
+int mgq_docsretrieved (int *total_retrieved, int *is_approx) {
+  query_data *qd = NULL;
+
+  if (cur_cachenum == -1) return 0;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL || total_retrieved == NULL || is_approx == NULL) return 0;
+
+  /* set default values */
+  *total_retrieved = 0;
+  *is_approx = 0;
+
+  if (qd->DL == NULL) return 0;
+
+  *total_retrieved = qd->DL->total_retrieved;
+  *is_approx = qd->DL->is_approx;
+
+  return 0;
+}
+
+
+/* use mgq_getmaxstemlen to determine the length of the word stems to pass */
+/* to mgq_stemword */
+int mgq_getmaxstemlen () {
+  return MAXSTEMLEN;
+}
+
+/* note: the stemming method and the stemmer come from the last query */
+/* "word" should be at least maxstemlen+1 long and it is a string that */
+/* starts with the string length */
+void mgq_stemword (unsigned char *word) {
+  int stem_method = 0;
+  query_data *qd = NULL;
+
+  if (cur_cachenum == -1) return;
+  qd = dbcache[cur_cachenum].qd;
+  if (qd == NULL || word == NULL) return;
+
+  if (qd->sd->sdh.indexed) {
+    stem_method = BooleanEnv(GetEnv("casefold"),0) | (BooleanEnv(GetEnv("stem"),0) << 1);
+  } else {
+    stem_method = qd->sd->sdh.stem_method;
+  }
+
+  stemmer (stem_method, qd->sd->sdh.stemmer_num, word);
+}
+
+
+
+int is_dbcache_full (void) {
+  init_dbcache ();
+  if (cache_numloaded >= MAXNUMDATABASEINFO) return 1;
+  return 0;
+}
+
+int load_database (char *collection, char *mgdir, 
+		   char *gensuffix, char *textsuffix) {
+  int i = 0;
+  query_data *qd = NULL;
+  /*  FILE *deb = NULL; */
+  init_dbcache ();
+
+  /* print out some debug information */
+/*  deb = fopen ("/home/rjmcnab/gsdl/etc/deb.txt", "a");
+  fprintf (deb, "\ncache_nextaccessnum: %i\n", cache_nextaccessnum);
+  fprintf (deb, "cache_numloaded: %i\n", cache_numloaded);
+  fprintf (deb, "cur_cachenum: %i\n", cur_cachenum);
+  fprintf (deb, "MAXNUMDATABASEINFO: %i\n\n", MAXNUMDATABASEINFO);
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    fprintf (deb, "Entry %i\n", i);
+    fprintf (deb, "  accessnum: %i\n", dbcache[i].accessnum);
+    fprintf (deb, "  collection: %s\n", dbcache[i].collection);
+    fprintf (deb, "  mgdir: %s\n", dbcache[i].mgdir);
+    fprintf (deb, "  gensuffix: %s\n", dbcache[i].gensuffix);
+    fprintf (deb, "  textsuffix: %s\n", dbcache[i].textsuffix);
+    fprintf (deb, "  qd: %x\n", (int)(dbcache[i].qd));
+  }
+  fclose (deb); */
+
+  /* search for the index */
+  i = search_gensuffix (gensuffix);
+  if (i >= 0) {
+    make_current (i);
+    return 1;
+  }
+
+  /* if there was a current database then the */
+  /* environment needs uninitialising */
+  make_current (-1);
+
+  /* get a free cache number */
+  i = get_free_dbcache ();
+  unload_database (i);
+
+  /* load the index */
+  qd = InitQuerySystem (mgdir, gensuffix, textsuffix, NULL);
+  if (qd == NULL) return 0;
+
+  /* cache this index */
+  cache_database (i, collection, mgdir, gensuffix, textsuffix, qd);
+
+  /* make this index current */
+  make_current (i);
+
+  return 1;
+}
+
+/* load_text_database tries to make an index of the */
+/* specified collection current */
+int load_text_database (char *collection) {
+  int i = 0;
+  init_dbcache ();
+
+  /* search for the index */
+  i = search_collect (collection);
+
+  /* return if none were found */
+  if (i < 0) return 0;
+  
+  /* make this index current */
+  make_current (i);
+  return 1;
+}
+
+void close_all_databases (void) {
+  int i = 0;
+  init_dbcache ();
+  
+  /* unload all active databases */
+  for (i=0; i<MAXNUMDATABASEINFO; i++) {
+    unload_database (i);
+  }
+
+  /* if there was a current database then the */
+  /* environment needs uninitialising */
+  make_current (-1);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgq.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgq.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgq.h	(revision 10506)
@@ -0,0 +1,78 @@
+/**********************************************************************
+ *
+ * mgq.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef MGQ_H
+#define MGQ_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  
+enum result_kinds {
+  result_docs,      /* Return the documents found in last search */
+  result_docnums,   /* Return document id numbers and weights */
+  result_termfreqs, /* Return terms and frequencies */
+  result_terms      /* Return matching query terms */
+};
+
+int mgq_ask(char *line);
+int mgq_results(enum result_kinds kind, int skip, int howmany,
+		int (*sender)(char *, int, int, float, void *), void *ptr);
+int mgq_numdocs(void);
+int mgq_numterms(void);
+
+/* get all the terms that match wordstem using the current stemmer and */
+/* stemming method. The callback is the same style used by mgq_results */
+int mgq_equivterms (unsigned char *wordstem, int (*sender)(char *, int, int, float, void *),
+		    void *ptr);
+
+/* gets the total number of documents retrieved. If this is not available */
+/* it will set total_retrieved to 0 (even when it obviously isn't) */
+int mgq_docsretrieved (int *total_retrieved, int *is_approx);
+  
+/* use mgq_getmaxstemlen to determine the length of the word stems to pass */
+/* to mgq_stemword */
+int mgq_getmaxstemlen ();
+
+/* note: the stemming method and the stemmer come from the last query */
+/* "word" should be at least maxstemlen+1 long and it is a string that */
+/* starts with the string length */
+void mgq_stemword (unsigned char *word);
+
+  
+int is_dbcache_full (void);
+int load_database (char *collection, char *mgdir, char *gensuffix, char *textsuffix);
+int load_text_database (char *collection);
+void close_all_databases (void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgqueryfilter.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgqueryfilter.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgqueryfilter.cpp	(revision 10506)
@@ -0,0 +1,532 @@
+/**********************************************************************
+ *
+ * mgqueryfilter.cpp -- implementation of queryfilter for old mg 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "mgqueryfilter.h"
+#include "fileutil.h"
+#include "phrasesearch.h"
+#include <assert.h>
+#include "mgsearch.h"
+
+///////////////////////////////
+// methods for resultsorderer_t
+///////////////////////////////
+
+resultsorderer_t::resultsorderer_t() {
+  clear ();
+}
+
+void resultsorderer_t::clear() {
+  compare_phrase_match = false;
+  compare_terms_match = false;
+  compare_doc_weight = true;
+
+  docset = NULL;
+}
+
+bool resultsorderer_t::operator()(const int &t1, const int &t2) const {
+  if (docset == NULL) return t1>t2;
+
+  docresultmap::iterator t1_here = docset->find(t1);
+  docresultmap::iterator t2_here = docset->find(t2);
+  docresultmap::iterator end = docset->end();
+
+  // sort all the document numbers not in the document set to
+  // the end of the list
+  if (t1_here == end) {
+    if (t2_here == end) return t1>t2;
+    else return true;
+  } else if (t2_here == end) return false;
+  
+  if (compare_phrase_match) {
+    if ((*t1_here).second.num_phrase_match > (*t2_here).second.num_phrase_match) return true;
+    if ((*t1_here).second.num_phrase_match < (*t2_here).second.num_phrase_match) return false;
+  }
+
+  if (compare_terms_match) {
+    if ((*t1_here).second.num_query_terms_matched > (*t2_here).second.num_query_terms_matched) return true;
+    if ((*t1_here).second.num_query_terms_matched < (*t2_here).second.num_query_terms_matched) return false;
+  }
+
+  if (compare_doc_weight) {
+    if ((*t1_here).second.docweight > (*t2_here).second.docweight) return true;
+    if ((*t1_here).second.docweight < (*t2_here).second.docweight) return false;
+  }
+
+  return t1>t2;
+}
+
+
+
+
+/////////////////////////////////
+// functions for mgqueryfilterclass
+/////////////////////////////////
+
+
+void mgqueryfilterclass::configure (const text_t &key, const text_tarray &cfgline) {
+  queryfilterclass::configure (key, cfgline);
+
+  if (key == "maxnumeric") {
+    maxnumeric = cfgline[0].getint();
+  }
+  else if (key == "indexstem") {
+    ((mgsearchclass *)textsearchptr)->set_indexstem (cfgline[0]);
+  }
+  
+}
+
+// loads up phrases data structure with any phrases (that's the quoted bits)
+// occuring in the querystring
+void mgqueryfilterclass::get_phrase_terms (const text_t &querystring, 
+					 const termfreqclassarray &orgterms,
+					 vector<termfreqclassarray> &phrases) {
+
+  text_t::const_iterator here = querystring.begin();
+  text_t::const_iterator end = querystring.end();
+
+  termfreqclassarray tmpterms;
+
+  int termcount = 0;
+  bool foundquote = false;
+  bool foundbreak = false;
+  bool start = true;
+  while (here != end) {
+    if (*here == '\"') {
+      if (foundquote) {
+	if (!foundbreak && !start) {
+	  tmpterms.push_back (orgterms[termcount]);
+	  ++termcount;
+	}
+	if (tmpterms.size() > 1) {
+	  phrases.push_back (tmpterms);
+	  tmpterms.erase (tmpterms.begin(), tmpterms.end());
+	}
+	foundquote = false;
+	foundbreak = true;
+      } else foundquote = true;
+    } else if (!is_unicode_letdig(*here)) {
+      // found a break between terms
+      if (!foundbreak && !start) {
+	if (foundquote)
+	  tmpterms.push_back (orgterms[termcount]);
+	++termcount;
+      }
+      foundbreak = true;
+    } else {
+      start = false;
+      foundbreak = false;
+    }      
+    ++here;
+  }
+}
+
+// do aditional query processing
+void mgqueryfilterclass::post_process (const queryparamclass &queryparams, 
+				     queryresultsclass &queryresults) {
+
+  // post-process the results if needed
+  if (queryresults.orgterms.size() > 1 && !queryresults.docs.docset.empty()) {
+
+    // get the terms between quotes (if any)
+    vector<termfreqclassarray> phrases;
+    get_phrase_terms (queryparams.querystring, queryresults.orgterms, phrases);
+
+    num_phrases = phrases.size();
+    if (num_phrases > 0) {
+
+      // get the long version of the index
+      text_t longindex;
+      indexmap.to2from (queryparams.index, longindex);
+      
+      vector<termfreqclassarray>::const_iterator this_phrase = phrases.begin();
+      vector<termfreqclassarray>::const_iterator end_phrase = phrases.end();
+
+      while (this_phrase != end_phrase) {
+
+	// process each of the matched documents
+	docresultmap::iterator docs_here = queryresults.docs.docset.begin();
+	docresultmap::iterator docs_end = queryresults.docs.docset.end();
+	while (docs_here != docs_end) {
+	  if (OID_phrase_search (*((mgsearchclass*)textsearchptr), *gdbmptr, queryparams.index,
+				 queryparams.subcollection, queryparams.language, 
+				 longindex, queryparams.collection, *this_phrase,
+				 (*docs_here).second.docnum)) {
+	    ++docs_here->second.num_phrase_match;
+	  }
+	
+	  ++docs_here;
+	}
+	++this_phrase;
+      }
+    }
+  }
+}
+
+
+// do query that might involve multiple sub queries
+// mgsearchptr and gdbmptr are assumed to be valid
+void mgqueryfilterclass::do_multi_query (const FilterRequest_t &request,
+				       const vector<queryparamclass> &query_params,
+				       queryresultsclass &multiresults,
+				       comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  err = noError;
+  textsearchptr->setcollectdir (collectdir);
+  multiresults.clear();
+  
+  vector<queryparamclass>::const_iterator query_here = query_params.begin();
+  vector<queryparamclass>::const_iterator query_end = query_params.end();
+  while (query_here != query_end) {
+    queryresultsclass thisqueryresults;
+
+    if (!textsearchptr->search(*query_here, thisqueryresults)) {
+      // most likely a system problem
+      logout << text_t2ascii
+	     << "system problem: could not do search with mg for index \""
+	     << (*query_here).index << (*query_here).subcollection
+	     << (*query_here).language << "\".\n\n";
+      err = systemProblem;
+      return;
+    }
+
+    // combine the results
+    if (need_matching_docs (request.filterResultOptions)) {
+      // post-process the results if needed
+      if (!thisqueryresults.postprocessed && thisqueryresults.orgterms.size() > 1 &&
+	  !thisqueryresults.docs.docset.empty()) {
+	post_process (*query_here, thisqueryresults);
+	thisqueryresults.postprocessed = true;
+	multiresults.postprocessed = true;
+      } else {
+	num_phrases = 0;
+      }
+      
+      if (query_params.size() == 1) {
+	multiresults.docs = thisqueryresults.docs; // just one set of results
+	multiresults.docs_matched = thisqueryresults.docs_matched;
+	multiresults.is_approx = thisqueryresults.is_approx;
+	
+      } else {
+	if ((*query_here).combinequery == "and") {
+	  multiresults.docs.combine_and (thisqueryresults.docs);
+	} else if ((*query_here).combinequery == "or") {
+	  multiresults.docs.combine_or (thisqueryresults.docs);
+	} else if ((*query_here).combinequery == "not") {
+	  multiresults.docs.combine_not (thisqueryresults.docs);
+	}
+	multiresults.docs_matched = multiresults.docs.docset.size();
+	multiresults.is_approx = Exact;
+      }
+    }
+
+    // combine the term information 
+    if (need_term_info (request.filterResultOptions)) {
+      // append the terms
+      multiresults.orgterms.insert(multiresults.orgterms.end(),
+				   thisqueryresults.orgterms.begin(),
+				   thisqueryresults.orgterms.end());
+
+      // add the term variants
+      text_tset::iterator termvar_here = thisqueryresults.termvariants.begin();
+      text_tset::iterator termvar_end = thisqueryresults.termvariants.end();
+      while (termvar_here != termvar_end) {
+	multiresults.termvariants.insert(*termvar_here);
+	++termvar_here;
+      }
+    }
+   
+    ++query_here;
+  }
+
+  // sort and unique the query terms
+  multiresults.sortuniqqueryterms ();
+}
+
+
+void mgqueryfilterclass::sort_doc_results (const FilterRequest_t &/*request*/,
+					 docresultsclass &docs) {
+  resultsorderer_t resultsorderer;
+  resultsorderer.compare_phrase_match = true;
+  resultsorderer.docset = &(docs.docset);
+
+  // first get a list of document numbers
+  docs.docnum_order();
+
+  sort (docs.docorder.begin(), docs.docorder.end(), resultsorderer);
+}
+
+
+
+mgqueryfilterclass::mgqueryfilterclass () 
+  :queryfilterclass() {
+
+  num_phrases = 0;
+  maxnumeric = 4;
+}
+
+mgqueryfilterclass::~mgqueryfilterclass () {
+}
+
+void mgqueryfilterclass::filter (const FilterRequest_t &request,
+			       FilterResponse_t &response,
+			       comerror_t &err, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  response.clear ();
+  err = noError;
+  if (gdbmptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: mgqueryfilter contains a null gdbmclass\n\n";
+    err = configurationError;
+    return;
+  }
+  if (textsearchptr == NULL) {
+    // most likely a configuration problem
+    logout << text_t2ascii 
+	   << "configuration error: mgqueryfilter contains a null textsearchclass (mg)\n\n";
+    err = configurationError;
+    return;
+  }
+
+  // open the database
+  gdbmptr->setlogout(&logout);
+  if (!gdbmptr->opendatabase (gdbm_filename, GDBM_READER, 100, false)) {
+    // most likely a system problem (we have already checked that the
+    // gdbm database exists)
+    logout << text_t2ascii
+	   << "system problem: open on gdbm database \""
+	   << gdbm_filename << "\" failed\n\n";
+    err = systemProblem;
+    return;
+  }
+
+  // get the query parameters
+  int startresults = filterOptions["StartResults"].defaultValue.getint();
+  int endresults = filterOptions["EndResults"].defaultValue.getint();
+  text_t phrasematch = filterOptions["PhraseMatch"].defaultValue;
+
+  vector<queryparamclass> queryfilterparams;
+  parse_query_params (request, queryfilterparams, startresults, 
+		      endresults, phrasematch, logout);
+  // do any mg specific diddling with query parameters that may be required
+  mg_parse_query_params (request, queryfilterparams, startresults, 
+			 endresults, phrasematch, logout);
+
+
+  // do query
+  queryresultsclass queryresults;
+  do_multi_query (request, queryfilterparams, queryresults, err, logout);
+  if (err != noError) return;
+  
+  // assemble document results
+  if (need_matching_docs (request.filterResultOptions)) {
+    // sort the query results
+    // only want to sort the docs if we have done a ranked search or there were phrases
+    if (num_phrases > 0 || (request.filterResultOptions & FRranking)) {
+      sort_doc_results (request, queryresults.docs);
+    }
+    int resultnum = 1;
+    ResultDocInfo_t resultdoc;
+    text_t trans_OID;
+    vector<int>::iterator docorder_here = queryresults.docs.docorder.begin();
+    vector<int>::iterator docorder_end = queryresults.docs.docorder.end();
+
+    // documents containing matching phrases will be sorted to the top so
+    // we can break out once we're past those that match the PhraseMatch
+    // option -- "all_phrases" = return only those documents containing all
+    //	                     phrases in query string
+    //           "some_phrases" = return only those documents containing 
+    //                            at least 1 of the phrases in the document
+    //           "all_docs" = return all documents regardless
+    if (num_phrases > 0) {
+      int numdocs = 0;
+      while (docorder_here != docorder_end) {
+	docresultmap::iterator docset_here = queryresults.docs.docset.find (*docorder_here);
+	
+	if (((phrasematch == "all_phrases") && ((*docset_here).second.num_phrase_match < num_phrases)) ||
+	    ((phrasematch == "some_phrases") && ((*docset_here).second.num_phrase_match < 1))) {
+	  queryresults.docs_matched = numdocs;
+	  break;
+	}
+	++numdocs;
+	++docorder_here;
+      }
+    }
+
+    if (endresults == -1) endresults = MAXNUMDOCS;
+    docorder_here = queryresults.docs.docorder.begin();
+    while (docorder_here != docorder_end) {
+      if (resultnum > endresults || resultnum > queryresults.docs_matched) break;
+      
+      // translate the document number
+      if (!translate(gdbmptr, *docorder_here, trans_OID)) {
+	logout << text_t2ascii
+	       << "warning: could not translate mg document number \""
+	       << *docorder_here << "\"to OID.\n\n";
+	
+      } else {
+	docresultmap::iterator docset_here = queryresults.docs.docset.find (*docorder_here);
+
+	// see if there is a result for this number,
+	// if it is in the request set (or the request set is empty)
+	if (docset_here != queryresults.docs.docset.end() &&
+	    (request.docSet.empty() || in_set(request.docSet, trans_OID))) {
+	  if (resultnum >= startresults) {
+	    // add this document
+	    resultdoc.OID = trans_OID;
+	    resultdoc.result_num = resultnum;
+	    resultdoc.ranking = (int)((*docset_here).second.docweight * 10000.0 + 0.5);
+
+	    // these next two are not available on all versions of mg
+	    resultdoc.num_terms_matched = (*docset_here).second.num_query_terms_matched; 
+	    resultdoc.num_phrase_match = (*docset_here).second.num_phrase_match;
+	    
+	    response.docInfo.push_back (resultdoc);
+	  }
+	  
+	  ++resultnum;
+	}
+      }
+      
+      ++docorder_here;
+    }
+  }
+
+  // assemble the term results
+  if (need_term_info(request.filterResultOptions)) {
+    // note: the terms have already been sorted and uniqued
+
+    TermInfo_t terminfo;
+    bool terms_first = true;
+    termfreqclassarray::iterator terms_here = queryresults.terms.begin();
+    termfreqclassarray::iterator terms_end = queryresults.terms.end();
+
+    while (terms_here != terms_end) {
+      terminfo.clear();
+      terminfo.term = (*terms_here).termstr;
+      terminfo.freq = (*terms_here).termfreq;
+      if (terms_first) {
+	text_tset::iterator termvariants_here = queryresults.termvariants.begin();
+	text_tset::iterator termvariants_end = queryresults.termvariants.end();
+	while (termvariants_here != termvariants_end) {
+	  terminfo.matchTerms.push_back (*termvariants_here);
+	  ++termvariants_here;
+	}
+      }
+      terms_first = false;
+
+      response.termInfo.push_back (terminfo);
+
+      ++terms_here;
+    }
+  }
+
+  response.numDocs = queryresults.docs_matched;
+  response.isApprox = queryresults.is_approx;
+}
+
+void mgqueryfilterclass::mg_parse_query_params (const FilterRequest_t &/*request*/,
+						vector<queryparamclass> &query_params,
+						int &/*startresults*/, int &/*endresults*/,
+						text_t &/*phrasematch*/, ostream &/*logout*/) {
+
+  //  outconvertclass text_t2ascii;
+  
+  vector<queryparamclass>::iterator query_here = query_params.begin();
+  vector<queryparamclass>::iterator query_end = query_params.end();
+  while (query_here != query_end) {
+
+    // set maxnumeric
+    (*query_here).maxnumeric = maxnumeric;
+
+    // if we're doing a phrase search we want to maximise hits by making it
+    // a boolean search on the index with the finest granularity - we'll
+    // also set maxdocs to "all" (realizing that this will cause searches
+    // like "and the" on a large collection to take a very very long time).
+
+    // we're deciding it's a phrase search based on if the querystring 
+    // contains at least 2 double quotes (not very scientific but 
+    // then neither is the rest of the mg phrase searching functionality :-)
+    if (countchar ((*query_here).querystring.begin(), (*query_here).querystring.end(), '"') > 1) {
+      (*query_here).search_type = 0;
+
+      // set maxdocs to "all"
+      (*query_here).maxdocs = -1;
+
+      // Get the long version of the index and test to see if any indexes with
+      // finer granularity exist. Indexes must be the same type (i.e. same metadata
+      // or "text").
+      text_t longindex; text_tarray splitindex;
+      indexmap.to2from ((*query_here).index, longindex);
+      splitchar (longindex.begin(), longindex.end(), ':', splitindex);
+      text_t &granularity = splitindex[0];
+      text_t &indextype = splitindex[1];
+      bool found = false;
+      // currently supported granularity options are "document", "section" and "paragraph"
+      if (granularity == "document" || granularity == "section") {
+	text_t shortindex;
+	if (indexmap.fromexists ("paragraph:" + indextype)) {
+	  indexmap.from2to ("paragraph:" + indextype, shortindex);
+	  (*query_here).index = shortindex;
+	  found = true;
+	}
+	if (!found && granularity == "document" && indexmap.fromexists ("section:" + indextype)) {
+	  indexmap.from2to ("section:" + indextype, shortindex);
+	  (*query_here).index = shortindex;
+	}
+      }
+    }
+
+#ifdef GSDL_BBC_COLLECTION
+    // This is a special hack for the BBC collection's ProgNumber and zzabn
+    // indexes (they're built this way to prevent mg_perf_hash_build from
+    // dying at build time)
+
+    // if we're searching the ProgNumber index we want to
+    // remove all non-alphanumeric characters from the query string
+    text_t longindex; text_tarray splitindex;
+    indexmap.to2from ((*query_here).index, longindex);
+    splitchar (longindex.begin(), longindex.end(), ':', splitindex);
+    text_t &indextype = splitindex[1];
+    if (indextype == "ProgNumber") {
+      text_t new_querystring;
+      text_t::const_iterator here = (*query_here).querystring.begin();
+      text_t::const_iterator end = (*query_here).querystring.end();
+      while (here != end) {
+        if ((*here >= 'a' && *here <= 'z') || (*here >= 'A' && *here <= 'Z') ||
+            (*here >= '0' && *here <= '9')) {
+          new_querystring.push_back (*here);
+        }
+        ++here;
+      }
+      (*query_here).querystring = new_querystring;
+    }
+#endif
+    ++query_here;
+  }
+}
+    
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgqueryfilter.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgqueryfilter.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgqueryfilter.h	(revision 10506)
@@ -0,0 +1,92 @@
+/**********************************************************************
+ *
+ * mgqueryfilter.h -- queryfilter for old mg
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef MGQUERYFILTER_H
+#define MGQUERYFILTER_H
+
+#include "queryfilter.h"
+
+// resultsorderer_t is used to sort the query results
+struct resultsorderer_t {
+  bool compare_phrase_match;
+  bool compare_terms_match;
+  bool compare_doc_weight;
+  docresultmap *docset;
+
+  resultsorderer_t();
+  void clear();
+  bool operator()(const int &t1, const int &t2) const;
+};
+
+
+
+class mgqueryfilterclass : public queryfilterclass {
+protected:
+  
+  int num_phrases;
+
+  int maxnumeric;
+
+  void get_phrase_terms (const text_t &querystring, 
+			 const termfreqclassarray &orgterms,
+			 vector<termfreqclassarray> &phrases);
+
+  // do aditional query processing
+  virtual void post_process (const queryparamclass &queryparams,
+			     queryresultsclass &queryresults);
+
+  // do query that might involve multiple sub queries
+  // mgsearchptr and gdbmptr are assumed to be valid
+  void do_multi_query (const FilterRequest_t &request,
+		       const vector<queryparamclass> &query_params,
+		       queryresultsclass &multiresults,
+		       comerror_t &err, ostream &logout);
+
+  virtual void sort_doc_results (const FilterRequest_t &request,
+				 docresultsclass &docs);
+
+  virtual void mg_parse_query_params (const FilterRequest_t &request,
+				      vector<queryparamclass> &query_params,
+				      int &startresults, int &endresults,
+				      text_t &phrasematch, ostream &logout);
+
+  
+public:
+  mgqueryfilterclass ();
+  virtual ~mgqueryfilterclass ();
+
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  void filter (const FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout);
+};
+
+
+#endif
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgsearch.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgsearch.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgsearch.cpp	(revision 10506)
@@ -0,0 +1,572 @@
+/**********************************************************************
+ *
+ * mgsearch.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdlconf.h"
+#include "mgsearch.h"
+#include "fileutil.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#if defined(__WIN32__)
+// gdbm stuff
+#  include "autoconf.h"
+#  include "systems.h"
+#  include "gdbmconst.h"
+#  include "gdbm.h"
+#else
+#  include <gdbm.h>
+#endif
+
+  
+#include <assert.h>
+
+#include "mgq.h"
+// #include "locateinfo.h"
+#include "gsdlunicode.h"
+#include "unitool.h"
+
+
+/////////////
+// globals //
+/////////////
+
+static char *tempdoc = NULL;
+static int templen = 0;
+
+
+//////////////////////
+// useful functions //
+//////////////////////
+
+
+// input and output are in utf8
+text_t mgsearch_stemword (const text_t &word) {
+  // allocate working stem space
+  int maxstemlen = mgq_getmaxstemlen ();
+  unsigned char *word_stem = new unsigned char [maxstemlen + 2];
+  if (word_stem == NULL) return "";
+
+  // copy word to word_stem
+  int len = 0;
+  text_t::const_iterator here = word.begin();
+  text_t::const_iterator end = word.end();
+  while (len < maxstemlen && here != end) {
+    word_stem[len+1] = (unsigned char)(*here);
+    ++len; ++here;
+  }
+  word_stem[len+1] = '\0';
+  word_stem[0] = len;
+
+  mgq_stemword (word_stem);
+
+  // copy word_stem back to tempstr
+  text_t tempstr;
+  tempstr.setcarr((char *)(&word_stem[1]), word_stem[0]);
+
+  delete [] word_stem;
+  
+  return tempstr;
+}
+
+
+
+////////////////////////
+// callback functions //
+////////////////////////
+
+// This routine is called for each document found in a search
+// it assumes that cache_num is set up correctly to point to
+// a suitable result cache
+int ourquerycallback(char * /*UDoc*/, int /*ULen*/, int DocNum, 
+		     float Weight, void *info) {
+
+  
+  queryresultsclass *queryresults = (queryresultsclass * )info;
+
+  // append this entry to the document results
+  docresultclass docresult;
+  docresult.docnum = DocNum;
+  docresult.num_query_terms_matched = (int)(Weight/100.0); // will always be 0 on some versions of mg...
+  docresult.docweight = Weight - docresult.num_query_terms_matched*100;
+  
+  queryresults->docs.docset[DocNum] = docresult;
+  queryresults->docs.docorder.push_back(DocNum);
+  
+  return 0;
+}
+
+int termequivcallback(char *Word, int ULen,  int /*Freq*/, 
+		      float /*Weight*/,  void *info) {
+  text_tset *equivterms = (text_tset *)info;
+  if (equivterms == NULL) return 0;
+
+  text_t thisterm;
+  thisterm.setcarr(Word, ULen);
+
+  equivterms->insert(thisterm);
+  
+  return 0;
+}
+
+
+void mgsearch_equivterms (const text_t &word, text_tset &equivterms) {
+  // allocate working stem space
+  int maxstemlen = mgq_getmaxstemlen ();
+  unsigned char *word_stem = new unsigned char [maxstemlen + 2];
+  if (word_stem == NULL) return;
+
+  // copy word to word_stem
+  int len = 0;
+  text_t::const_iterator here = word.begin();
+  text_t::const_iterator end = word.end();
+  while (len < maxstemlen && here != end) {
+    word_stem[len+1] = (unsigned char)(*here);
+    ++len; ++here;
+  }
+  word_stem[len+1] = '\0';
+  word_stem[0] = len;
+
+  // get the equivalent terms
+  mgq_equivterms (word_stem, termequivcallback, (void *)(&equivterms));
+  
+  delete [] word_stem;
+
+  return;
+}
+
+  text_tset utf8equivterms; // kept as utf8 string for fast matching
+
+
+// This callback is called once for each term in the query
+int termfreqcallback(char *Word, int ULen,  int Freq, 
+		     float /*Weight*/,  void *info) {
+  queryresultsclass *queryresults = (queryresultsclass *)info;
+  if (queryresults == NULL) return 0;
+
+  text_t term;
+  term.setcarr(Word, ULen);
+  termfreqclass termfreq;
+
+  termfreq.termstr = to_uni(term);
+  text_t utf8termstem = mgsearch_stemword (term);
+  termfreq.termstemstr = to_uni (utf8termstem);
+
+  mgsearch_equivterms (utf8termstem, termfreq.utf8equivterms);
+  
+  termfreq.termfreq = Freq;
+  queryresults->orgterms.push_back(termfreq);
+  
+  return 0;
+}
+
+// this callback is called once for each variation of each term
+int termvariantscallback(char *Word, int ULen, int /*Freq*/,
+			 float /*Weight*/, void *info) {
+
+  text_t term;
+  term.setcarr(Word, ULen);
+  queryresultsclass *queryresults = (queryresultsclass *)info;
+  queryresults->termvariants.insert(to_uni(term));
+
+  return 0;
+}
+
+// This callback is for getting document text
+int doctextcallback(char *Doc, int ULen,  int /*Freq*/, 
+		    float /*Weight*/,  void * /*info*/) {
+  tempdoc = Doc;
+  templen = ULen;
+  
+  return 0;
+}
+
+
+text_t mgsearchclass::getindexsuffix (const text_t &collection, 
+			      const text_t &index) {
+
+  text_t indexsuffix = "index";  
+  indexsuffix = filename_cat (indexsuffix, index);
+  if (indexstem.empty()) {
+    // no index stem, use the coll name
+    indexsuffix = filename_cat (indexsuffix, collection);
+  } else {
+    indexsuffix = filename_cat (indexsuffix, indexstem);
+  }
+  return indexsuffix;
+}
+
+
+
+
+////////////////////
+// mgsearch class //
+////////////////////
+
+mgsearchclass::mgsearchclass ()
+  : searchclass() {
+ 
+}
+
+mgsearchclass::~mgsearchclass () 
+{
+  if (cache != NULL) 
+    {
+      delete cache;
+      cache = NULL;
+    }
+}
+
+void mgsearchclass::set_indexstem(const text_t &stem) {
+  indexstem = stem;
+  
+}
+
+// you only need to use this function before doing any stemming
+// casefolding and stemming will be set if values for them are
+// provided (0 or 1).
+// makeindexcurrent returns true if it was able to load the database
+bool mgsearchclass::makeindexcurrent (const text_t &index,
+				      const text_t &subcollection,
+				      const text_t &language,
+				      const text_t &collection,
+				      int casefolding,
+				      int stemming) {
+  bool databaseloaded = true;
+
+  // get the names of the collection, index and text suffixes
+  char *ccollection = collection.getcstr();
+  assert (ccollection != NULL);
+  char *idxsuffix = (getindexsuffix (collection, (index+subcollection+language))).getcstr();
+  assert (idxsuffix != NULL);
+  char *txtsuffix = (getindexsuffix (collection, "text")).getcstr();
+  assert (txtsuffix != NULL);
+#ifdef __WIN32__
+  char *ccollectdir = (collectdir+"\\").getcstr(); assert (ccollectdir != NULL);
+#else
+  char *ccollectdir = collectdir.getcstr(); assert (ccollectdir != NULL);
+#endif
+
+  if (load_database(ccollection, ccollectdir, idxsuffix, txtsuffix)) {
+    if (casefolding == 0) mgq_ask(".set casefold off");
+    else if (casefolding > 0) mgq_ask(".set casefold on");
+    if (stemming == 0) mgq_ask(".set stem off");
+    else if (stemming > 0) mgq_ask(".set stem on");
+    
+  } else databaseloaded = false;
+
+  // free up the c strings
+  delete []ccollection;
+  delete []idxsuffix;
+  delete []txtsuffix;
+  delete []ccollectdir;
+
+  return databaseloaded;
+}
+
+
+// stem word uses the values set in the last call to makeindexcurrent
+// to stem the word. It is assumed that word is in unicode
+text_t mgsearchclass::stemword (const text_t &word) {
+  return to_uni (mgsearch_stemword (to_utf8 (word)));
+}
+
+text_t mgsearchclass::stemword (text_t::const_iterator here, text_t::const_iterator end) {
+  return to_uni (mgsearch_stemword (to_utf8 (here, end)));
+}
+
+/**
+ * search directs the whole execution of the search; a number of other
+ * functions in this class are called as a result, and precondition
+ * checks are also made
+ */
+bool mgsearchclass::search(const queryparamclass &queryparams, 
+			   queryresultsclass &queryresults) {
+  //  assert (cache != NULL);
+
+  // clear any previous results
+  queryresults.clear();
+  // first check the cache
+  if (cache != NULL) {
+    if (cache->find(queryparams, queryresults)) return true;
+  }
+  // make sure there is a query to be processed
+  if (!has_unicode_letdig(queryparams.querystring)) return true;
+
+  if (makeindexcurrent (queryparams.index, queryparams.subcollection,
+			queryparams.language, queryparams.collection)) {
+    // initialise the form of results
+    setsearchmode (queryparams);
+
+    // execute the query
+    submitquery (queryparams);
+
+    // retrieve the results
+    getresults (queryparams, queryresults);
+    return true;
+  }
+
+  return false;
+}
+
+/* accumulator_method has been changed to use array rather than list.
+list appears to be broken somewhat - for some ranked queries, it returned 
+fewer results than it should have (eg 45 instead of 50). The three other
+methods (array, splay_tree, hash_table) all return the same number of 
+documents, in the same order, with the same ranks. list returns what 
+appears to be the same documents (but less of them), but with different ranks,
+and in a different order. Minimal time tests dont show any speed improvement
+of list over array (maybe because its broken??).  [02/2001, kjm18]
+
+... [sjboddie, also 02/2001] turns out that changing the accumulator_method
+introduced a more serious bug than it fixed (i.e. occasionally when doing a
+ranked search for a very common word you get no results at all). I've
+changed it back to list for now, one day we should play with other
+accumulator_methods but for now I don't have time and don't want to risk
+introducing bugs (better the devil you know ;)
+*/
+void mgsearchclass::setsearchmode (const queryparamclass &queryparams)
+{
+  mgq_ask(".set expert true");
+  mgq_ask(".set sorted_terms true");
+  mgq_ask(".set accumulator_method list");
+  mgq_ask(".set max_accumulators 500000");
+  mgq_ask(".set maxparas 500000");
+  mgq_ask(".set verbatim true");
+  mgq_ask(".unset skip_dump");
+  mgq_ask(".set mode docnums");
+
+  switch (queryparams.search_type) 
+    {
+    case 0: mgq_ask(".set query boolean");  break;
+    case 1:  mgq_ask(".set query ranked"); break;
+    }
+  switch (queryparams.casefolding) 
+    {
+    case 1: mgq_ask(".set casefold on");  break;
+    case 0: mgq_ask(".set casefold off"); break;
+    }
+  switch (queryparams.stemming) 
+    {
+    case 1: mgq_ask(".set stem on");  break;
+    case 0: mgq_ask(".set stem off"); break;
+    }
+  mgq_ask(".set heads_length 150");
+  
+  if (queryparams.maxdocs == -1) {
+    mgq_ask(".set maxdocs all");
+  } else {
+    char maxdocstr[32];
+    sprintf(maxdocstr, ".set maxdocs %i", queryparams.maxdocs);
+    mgq_ask(maxdocstr);
+  }
+
+  char maxnumericstr[32];
+  sprintf(maxnumericstr, ".set maxnumeric %i", queryparams.maxnumeric);
+  mgq_ask(maxnumericstr);
+  
+}
+
+/**
+ * submitquery constructs the query string (into UTF8 encoding)
+ * and submits it using mgq_ask to the mg search engine.  Most
+ * of the processing will be done inside Greenstone
+ */
+void mgsearchclass::submitquery (const queryparamclass &queryparams)
+{
+  // sort out the query string; copy it, remove all special characters
+  // and then convert it to a string in UTF8 format
+  text_t ttquerystring = queryparams.querystring;
+  filterquery (ttquerystring);
+  char *querystring = to_utf8(ttquerystring).getcstr();
+
+  // submit the query
+  mgq_ask(querystring);
+
+  // destroy the temporary character array
+  delete []querystring;
+}
+
+/**
+ * getrults is called to retrieve the required data on the docs
+ * which responded to the query submitted in submitquery above.
+ *
+ * It calls the local mgquery (mgq) interface to MG several times,
+ * to obtain the document numbers, term frequencies, term variants
+ * etc.  All processing of the query will be done by Greenstone
+ * thereafter
+ */
+void mgsearchclass::getresults (const queryparamclass &queryparams,
+				queryresultsclass &queryresults) {
+  // get the configuration for the maximum number of documents to
+  // retrieve
+  int howmany = queryparams.maxdocs;
+  if (howmany == -1) howmany = MAXNUMDOCS;
+  mgq_results(result_docnums, 0, howmany, 
+	      ourquerycallback, (void *)(&queryresults));
+  
+  // get the term frequencies
+  mgq_results(result_termfreqs, 0, MAXNUMTERMS, 
+	      termfreqcallback, (void *)(&queryresults));
+  queryresults.sortuniqqueryterms();
+
+  // get term variants 
+  mgq_results(result_terms, 0, MAXNUMTERMS,
+              termvariantscallback, (void *)(&queryresults));
+
+  // get the number of documents retrieved
+  int total_retrieved = 0, is_approx = 0;
+  mgq_docsretrieved (&total_retrieved, &is_approx);
+
+  if (total_retrieved == 0) {
+    // not available (or really was zero)
+    queryresults.docs_matched = queryresults.docs.docset.size();
+    if ((queryparams.maxdocs == -1) ||
+	(queryresults.docs_matched < queryparams.maxdocs))
+      queryresults.is_approx = Exact;
+    else
+      queryresults.is_approx = MoreThan;
+  } else {
+    queryresults.docs_matched = total_retrieved;
+    if (is_approx) queryresults.is_approx = Approximate;
+    else queryresults.is_approx = Exact;
+  }
+}
+
+/**
+ * Tidies the given querystring, removing special characters
+ */
+void mgsearchclass::filterquery (text_t &ttquerystring) {
+  text_t::iterator ithere = ttquerystring.begin ();
+  text_t::iterator itend = ttquerystring.end ();
+  
+  // remove all non alphanumeric characters (except
+  // boolean operators
+  while (ithere != itend) {
+    if ((!is_unicode_letdig(*ithere)) && (*ithere != '!') &&
+	(*ithere != '&') && (*ithere != '|') && (*ithere != '(') &&
+	(*ithere != ')')) (*ithere) = ' ';
+    ++ithere;
+  }
+}
+
+
+// the document text for 'docnum' is placed in 'output'
+// docTargetDocument returns 'true' if it was able to
+// try to get a document
+// collection is needed to see if an index from the 
+// collection is loaded. If no index has been loaded
+// defaultindex is needed to load one
+bool mgsearchclass::docTargetDocument(const text_t &defaultindex,
+				      const text_t &defaultsubcollection,
+				      const text_t &defaultlanguage,
+				      const text_t &collection,
+				      int docnum,
+				      text_t &output) {
+  output.clear();
+
+  // get the mg version of the document
+  char *mgdoc = NULL;
+  int doclen = 0;
+  if (!mgdocument (defaultindex, defaultsubcollection, defaultlanguage,
+		   collection, docnum, mgdoc, doclen)) return false;
+  if (mgdoc == NULL) return false;
+
+  // replace all control-Cs with spaces
+  char *mgdoc_here = mgdoc;
+  char *mgdoc_end = mgdoc + doclen;
+  while (mgdoc_here < mgdoc_end) {
+    if (*mgdoc_here == '\x3') *mgdoc_here = ' ';
+    ++mgdoc_here;
+  }
+
+  // convert this document to unicode
+  utf8inconvertclass inconvert;
+  convertclass::status_t status;
+  inconvert.reset ();
+  inconvert.setinput (mgdoc, doclen);
+  inconvert.convert (output, status);
+
+  return true;
+}
+
+
+bool mgsearchclass::mgdocument (const text_t &defaultindex, 
+				const text_t &defaultsubcollection,
+				const text_t &defaultlanguage,
+				const text_t &collection,
+				int docnum,
+				char *&UDoc, int &ULen) {
+  int databaseloaded = 0;
+
+  UDoc = NULL; ULen = 0;
+  
+  // see if we can make an appropriate database current
+//    char *ccollection = collection.getcstr();
+//    assert (ccollection != NULL);
+//    databaseloaded = load_text_database (ccollection);
+//    delete []ccollection;
+  
+  // try and load the database
+//    if (!databaseloaded)
+  databaseloaded = makeindexcurrent (defaultindex, defaultsubcollection,
+				     defaultlanguage, collection);
+  
+  if (databaseloaded) {
+    // retrieve the document from mg
+    char docstr[32];
+    sprintf(docstr, "%i", docnum);
+    
+    mgq_ask(".set mode text");
+    mgq_ask(".set query docnums");
+    mgq_ask(docstr);
+
+    tempdoc = NULL;
+    templen = 0;
+    mgq_results (result_docs, 0, 1, doctextcallback, (void *)NULL);
+    UDoc = tempdoc;
+    ULen = templen;
+  }
+
+  return (bool)databaseloaded;
+}
+
+// unload_database simply calls mgq's close_all_databases function to clear
+// any cached databases - this is useful when attempting to completely
+// remove all trace of a collectionserver at runtime (when using a
+// persistent version of Greenstone like the windows local library)
+void mgsearchclass::unload_database () {
+  close_all_databases();
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgsearch.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgsearch.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/mgsearch.h	(revision 10506)
@@ -0,0 +1,101 @@
+/**********************************************************************
+ *
+ * mgsearch.h --  implementation of search for old versions of mg
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef MGSEARCH_H
+#define MGSEARCH_H
+
+
+#include "search.h"
+
+class mgsearchclass : public searchclass {
+public:
+  mgsearchclass ();
+  virtual ~mgsearchclass ();
+
+  virtual text_t get_textindex_type() {return "mg";}
+
+  // you only need to use this function before doing any stemming
+  // casefolding and stemming will be set if values for them are
+  // provided (0 or 1).
+  // makeindexcurrent returns true if it was able to load the database
+  bool makeindexcurrent (const text_t &index, const text_t &subcollection,
+			 const text_t &language, const text_t &collection,
+			 int casefolding = -1, int stemming = -1);
+
+  // stem word uses the values set in the last call to makeindexcurrent
+  // to stem the word. It is assumed that word is in unicode
+  text_t stemword (const text_t &word);
+  text_t stemword (text_t::const_iterator here, text_t::const_iterator end);
+  
+  // the search results are returned in queryresults
+  // search returns 'true' if it was able to do a search
+  bool search(const queryparamclass &queryparams, 
+	      queryresultsclass &queryresults);
+  
+  // the document text for 'docnum' is placed in 'output'
+  // docTargetDocument returns 'true' if it was able to
+  // try to get a document
+  // collection is needed to see if an index from the 
+  // collection is loaded. If no index has been loaded
+  // defaultindex is needed to load one
+  bool docTargetDocument(const text_t &defaultindex,
+			 const text_t &defaultsubcollection,
+			 const text_t &defaultlanguage,
+			 const text_t &collection,
+			 int docnum,
+			 text_t &output);
+
+  // same as docTargetDocument except the document is returned
+  // in its raw form. UDoc remains the property of mg and may
+  // be destroyed on the next call to mg.
+  bool mgdocument (const text_t &defaultindex,
+		   const text_t &defaultsubcollection,
+		   const text_t &defaultlanguage,
+		   const text_t &collection,
+		   int docnum,
+		   char *&UDoc, int &ULen);
+
+  // unload_database simply calls mgq's close_all_databases function to
+  // clear any cached databases - this is useful when attempting to
+  // completely remove all trace of a collectionserver at runtime (when
+  // using a persistent version of Greenstone like the windows local
+  // library)
+  void unload_database ();
+
+  void set_indexstem(const text_t &indexstem);
+
+protected:
+
+  text_t indexstem; // the stem of the index files - defaults to the collectionname
+  void setsearchmode (const queryparamclass &queryparams);
+  void submitquery (const queryparamclass &queryparams);
+  void getresults (const queryparamclass &queryparams, queryresultsclass &queryresults);
+  text_t getindexsuffix (const text_t &collection, const text_t &index);
+  virtual void filterquery (text_t &ttquerystring);
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasequeryfilter.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasequeryfilter.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasequeryfilter.cpp	(revision 10506)
@@ -0,0 +1,84 @@
+/**********************************************************************
+ *
+ * phrasequeryfilter.cpp -- 
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "phrasequeryfilter.h"
+#include "queryinfo.h"
+
+#include "phrasesearch.h"
+
+
+
+// do aditional query processing
+void phrasequeryfilterclass::post_process (const queryparamclass &queryparams,
+					   queryresultsclass &queryresults) {
+  bool results_shrunk = false;
+
+  // post-process the results if needed
+  if (queryresults.orgterms.size() > 1 && !queryresults.docs.docset.empty()) {
+    // get the long version of the index
+    text_t longindex;
+    indexmap.to2from (queryparams.index, longindex);
+      
+    // process each of the matched documents
+    docresultmap::iterator docs_here = queryresults.docs.docset.begin();
+    docresultmap::iterator docs_end = queryresults.docs.docset.end();
+    while (docs_here != docs_end) {
+      if ((*docs_here).second.num_query_terms_matched == queryresults.orgterms.size() &&
+	  OID_phrase_search (*(mgsearchclass *)textsearchptr, *gdbmptr, queryparams.index,
+			     queryparams.subcollection, queryparams.language, 
+			     longindex, queryparams.collection, queryresults.orgterms,
+			     (*docs_here).second.docnum)) {
+	++docs_here->second.num_phrase_match;
+	++docs_here;
+
+      } else {
+	docresultmap::iterator this_doc_here = docs_here;
+	++docs_here;
+	if (queryparams.match_mode == 1) {
+	  // need to delete this element, there was no exact match
+	  queryresults.docs.docset.erase(this_doc_here);
+	  results_shrunk = true;
+	}
+      }
+    }
+  }
+
+  if (results_shrunk) queryresults.docs_matched = queryresults.docs.docset.size();
+}
+
+
+void phrasequeryfilterclass::sort_doc_results (const FilterRequest_t &/*request*/,
+					 docresultsclass &docs) {
+  resultsorderer_t resultsorderer;
+  resultsorderer.compare_phrase_match = true;
+  resultsorderer.compare_terms_match = true;
+  resultsorderer.compare_doc_weight = true;
+  resultsorderer.docset = &(docs.docset);
+
+  // first get a list of document numbers
+  docs.docnum_order();
+
+  sort (docs.docorder.begin(), docs.docorder.end(), resultsorderer);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasequeryfilter.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasequeryfilter.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasequeryfilter.h	(revision 10506)
@@ -0,0 +1,43 @@
+/**********************************************************************
+ *
+ * phrasequeryfilter.h -- 
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef PHRASEQUERYFILTER_H
+#define PHRASEQUERYFILTER_H
+
+#include "mgqueryfilter.h"
+
+
+class phrasequeryfilterclass : public mgqueryfilterclass {
+protected:
+  void post_process (const queryparamclass &queryparams,
+		     queryresultsclass &queryresults);
+  void sort_doc_results (const FilterRequest_t &request,
+			 docresultsclass &docs);
+public:
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasesearch.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasesearch.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasesearch.cpp	(revision 10506)
@@ -0,0 +1,259 @@
+/**********************************************************************
+ *
+ * phrasesearch.cpp -- tools to search for a phrase in a larger text
+ * Copyright (C) 1999  DigiLib Systems Limited
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "phrasesearch.h"
+#include "gsdlunicode.h"
+
+inline unsigned char *parse_nonword_word (unsigned char *here, unsigned char *end,
+					  text_t &word) {
+  int c_len = 0;
+  unsigned short c = 0;
+
+  word.clear();
+
+  // parse non word
+  while (here <= end) {
+    c_len = parse_utf8_char (here, end, &c);
+    if (c == '(') {
+      // found a note, look for '}'
+      while (here <= end && c != ')') {
+	c_len = parse_utf8_char (here, end, &c);
+	here += c_len;
+      }
+    }
+    if (c == '{') {
+      // found a composite character, look for '}'
+      while (here <= end && c != '}') {
+	c_len = parse_utf8_char (here, end, &c);
+	here += c_len;
+      }
+    }
+    if (is_unicode_letdig(c)) {
+      while (c_len > 0) {
+	// this is in a word
+	word.push_back(*here);
+	++here; --c_len;
+      }
+      break;
+    }
+    here += c_len;
+  }
+
+  // parse word
+  while (here <= end) {
+    c_len = parse_utf8_char (here, end, &c);
+    if (!is_unicode_letdig(c)) {
+      here += c_len;  // it is ok to skip a nonword character
+      break;
+    }
+    while (c_len > 0) {
+      word.push_back(*here);
+      ++here; --c_len;
+    }
+  }
+
+  return here;
+}
+
+static void get_all_docnums (gdbmclass &gdbm, text_t OID, vector<int> &docnum_list) {
+
+  infodbclass OID_info;
+  
+  // get OID
+  if (!gdbm.getinfo (OID, OID_info)) return;
+  if (OID_info["hastxt"] == "1" && !OID_info["docnum"].empty()) {
+    docnum_list.push_back (OID_info["docnum"].getint());
+  }
+
+  // get contents set
+  if (OID_info["contains"].empty()) return;
+  text_tarray contains; text_t tmptext;
+  text_t::iterator contains_here = OID_info["contains"].begin();
+  text_t::iterator contains_end = OID_info["contains"].end();
+  while (contains_here != contains_end) {
+    if (*contains_here == '"') tmptext += OID;
+    else if (*contains_here == ';') {
+      if (!tmptext.empty()) contains.push_back (tmptext);
+      tmptext.clear();
+    } else tmptext.push_back(*contains_here);
+    ++contains_here;
+  }
+  if (!tmptext.empty()) contains.push_back (tmptext);
+
+  text_tarray::const_iterator here = contains.begin();
+  text_tarray::const_iterator end = contains.end();
+  while (here != end) {
+    get_all_docnums (gdbm, *here, docnum_list);
+    ++here;
+  }
+}
+
+bool doc_phrase_search (unsigned char *doc, int doclen,
+			const termfreqclassarray &phrase) {
+  // note: this uses the most braindead search routine :-)
+  // however its not so bad as there shouldn't be many partial
+  // matches
+
+  // a null phrase matches anything
+  if (phrase.empty()) return true;
+
+  // if there is nothing then there can't be a match
+  if (doc == NULL || doclen == 0) return false;
+  
+  text_t doc_word;
+  doc_word.reserve (16);
+
+  bool first = true;
+
+  unsigned char *doc_here = doc;
+  unsigned char *doc_herefirstword = doc;
+  unsigned char *doc_end = doc+doclen-1; // unitool conventions :-/
+
+  while (doc_here <= doc_end) {
+    first = true;
+
+    // there will be at least one member of phrase (see above)
+    termfreqclassarray::const_iterator phrase_here = phrase.begin();
+    termfreqclassarray::const_iterator phrase_end = phrase.end();
+    do {
+      // get the next non-word ... and ignore it, then get the next word
+      doc_here = parse_nonword_word (doc_here, doc_end, doc_word);
+      if (first) {doc_herefirstword = doc_here; first = false;}
+
+      // break if this word is not the next in the phrase
+      if ((*phrase_here).utf8equivterms.find (doc_word) ==
+	  (*phrase_here).utf8equivterms.end()) break;
+
+      ++phrase_here;
+    } while (doc_here <= doc_end && phrase_here != phrase_end);
+
+    // see if we found a phrase
+    if (phrase_here == phrase_end) return true;
+    
+    doc_here = doc_herefirstword; // set the counter back
+  }
+
+  return false;
+}
+
+// looks for the stemmed phrase in the metadata or text associated with
+// an OID. This function has not been coded with all situations in mind
+bool OID_phrase_search (mgsearchclass &mgsearch,
+			gdbmclass &gdbm,
+			const text_t &index,
+			const text_t &subcollection,
+			const text_t &language,
+			const text_t &longindex,
+			const text_t &collection,
+			const termfreqclassarray &phrase,
+			int docnum) {
+
+  // get OID
+  infodbclass docnum_info;
+  if (!gdbm.getinfo (docnum, docnum_info)) return false;
+  text_t &OID = docnum_info["section"];
+  if (OID.empty()) return false;
+
+  // disect the long index to find out where the text should come from
+  text_t gran, type;
+  text_t::const_iterator longindex_here = longindex.begin();
+  text_t::const_iterator longindex_end = longindex.end();
+  longindex_here = getdelimitstr (longindex_here, longindex_end, ':', gran);
+  longindex_here = getdelimitstr (longindex_here, longindex_end, ':', type);
+
+  if (gran.empty()) return false;
+  
+  // note that we're treating indexes of type 'all' (i.e. text,Title,Creator)
+  // or other composite indexes that contain "text" as if they were simply 'text' indexes
+  if ((type == "text") || (type == "all") || (findword(type.begin(),type.end(),"text") != type.end())) {
+    char *doc = NULL;
+    int doclen = 0;
+  
+    // get text from mg.
+    if (gran == "document") {
+
+      // if this is a document level index (which should only happen if
+      // there are no matching indexes with a finer granularity -- see
+      // mgqueryfilterclass::mg_parse_query_params) then we must do the
+      // phrase search on the entire document (i.e. all the sections)
+      // -- this is going to make a slow process even slower
+      vector<int> docnum_list; text_t fulldoc;
+      get_all_docnums (gdbm, OID, docnum_list);
+      vector<int>::const_iterator this_docnum = docnum_list.begin();
+      vector<int>::const_iterator end_docnum = docnum_list.end();
+      while (this_docnum != end_docnum) {
+	if (mgsearch.mgdocument (index, subcollection, language, collection,
+				 *this_docnum, doc, doclen)) {
+	  fulldoc.appendcstr (doc);
+	}
+	++this_docnum;
+      }
+      doc = fulldoc.getcstr();
+      doclen = fulldoc.size();
+      bool rv = doc_phrase_search ((unsigned char *)doc, doclen, phrase);
+      delete []doc;
+      return rv;
+
+    } else {
+
+      if (!mgsearch.mgdocument (index, subcollection, language, collection,
+				docnum, doc, doclen)) return false;
+      return doc_phrase_search ((unsigned char *)doc, doclen, phrase);
+    } 
+  }
+
+  char *metadata = NULL;
+  text_t::size_type metadata_len = 0;
+  infodbclass OID_info;
+  
+  // get field
+  if (!gdbm.getinfo (OID, OID_info)) return false;
+
+  bool result = false;
+
+  // need to look through all the metadata values in the index
+  text_tarray keys;
+  splitchar(type.begin(), type.end(), ',', keys);
+
+  text_tarray::const_iterator keyhere = keys.begin();
+  text_tarray::const_iterator keyend = keys.end();
+  while (keyhere != keyend) {
+    text_tarray *tarr_ptr = OID_info.getmultinfo (*keyhere);
+    if (tarr_ptr != NULL ) {
+      text_tarray::const_iterator subvalue_here = (*tarr_ptr).begin();
+      text_tarray::const_iterator subvalue_end = (*tarr_ptr).end();
+      while (subvalue_here != subvalue_end) {
+	metadata = (to_utf8(*subvalue_here)).getcarr(metadata_len);
+	result = doc_phrase_search ((unsigned char *)metadata, metadata_len, phrase);
+	delete [] metadata;
+	
+	if (result) return true;
+	++subvalue_here;
+      }
+    }
+    ++keyhere;
+  }
+  return result;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasesearch.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasesearch.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/phrasesearch.h	(revision 10506)
@@ -0,0 +1,50 @@
+/**********************************************************************
+ *
+ * phrasesearch.h -- tools to search for a phrase in a larger text
+ * Copyright (C) 1999  DigiLib Systems Limited
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef PHRASESEARCH_H
+#define PHRASESEARCH_H
+
+
+#include "text_t.h"
+#include "unitool.h"
+#include "mgsearch.h"
+#include "infodbclass.h"
+
+
+// looks for the phrase in the metadata or text associated with
+// a document number. This function has not been coded with all
+// situations in mind and expects mgsearch and gdbm set up ready to go
+bool OID_phrase_search (mgsearchclass &mgsearch,
+			gdbmclass &gdbm,
+			const text_t &index,
+			const text_t &subcollection,
+			const text_t &language,
+			const text_t &longindex,
+			const text_t &collection,
+			const termfreqclassarray &phrase,
+			int docnum);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/querycache.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/querycache.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/querycache.cpp	(revision 10506)
@@ -0,0 +1,104 @@
+/**********************************************************************
+ *
+ * querycache.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "querycache.h"
+
+
+
+
+resultcacheel::resultcacheel () 
+{
+  accessnum = -1;
+}
+
+
+
+querycache::querycache (int themaxcachesize)
+{
+  if (themaxcachesize < 1) themaxcachesize = 1;
+  
+  resultcache = new resultcacheel[themaxcachesize];
+
+  maxcachesize = themaxcachesize;
+  nextaccessnum = 1;
+}
+
+querycache::~querycache ()
+{
+  delete [] resultcache;
+}
+
+// returns true if the query was found in the cache
+// if the query was found then queryresults contains
+// the results
+bool querycache::find (const queryparamclass &queryparams, 
+		       queryresultsclass &queryresults)
+{
+  int i;
+
+  for (i=0; i < maxcachesize; ++i)
+    {
+      if (resultcache[i].queryparameters == queryparams)
+	{
+	  queryresults = resultcache[i].queryresults;
+	  resultcache[i].accessnum = getnextaccessnum ();
+	  return true;
+	}
+    }
+
+  return false;
+}
+
+
+void querycache::cache (const queryparamclass &queryparams,
+	  const queryresultsclass &queryresults)
+{
+  int i = getfreecachenum();
+  resultcache[i].queryparameters = queryparams;
+  resultcache[i].queryresults = queryresults;
+  resultcache[i].accessnum = getnextaccessnum ();
+}
+
+int querycache::getnextaccessnum ()
+{
+  return nextaccessnum++;
+}
+
+int querycache::getfreecachenum ()
+{
+  int i;
+  int minaccessnum = 0;
+  int minaccessi = 0;
+  
+  for (i=0; i < maxcachesize; ++i)
+    {
+      if (resultcache[i].accessnum < minaccessnum) {
+	minaccessnum = resultcache[i].accessnum;
+	minaccessi = i;
+      }
+    }
+
+  return minaccessi;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/querycache.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/querycache.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/querycache.h	(revision 10506)
@@ -0,0 +1,70 @@
+/**********************************************************************
+ *
+ * querycache.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef QUERYCACHE_H
+#define QUERYCACHE_H
+
+
+#include "text_t.h"
+#include "queryinfo.h"
+
+class resultcacheel
+{
+public:
+  resultcacheel ();
+
+  int accessnum;
+  queryparamclass queryparameters;
+  queryresultsclass queryresults;
+};
+
+
+class querycache {
+public:
+  querycache (int themaxcachesize);
+  ~querycache ();
+
+  // returns true if the query was found in the cache
+  // if the query was found then queryresults contains
+  // the results
+  bool find (const queryparamclass &queryparams, 
+	     queryresultsclass &queryresults);
+
+  void cache (const queryparamclass &queryparams,
+	    const queryresultsclass &queryresults);
+
+protected:
+  resultcacheel *resultcache;
+
+  int maxcachesize;
+  int nextaccessnum;
+  
+  int getnextaccessnum ();
+  int getfreecachenum ();
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryfilter.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryfilter.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryfilter.cpp	(revision 10506)
@@ -0,0 +1,388 @@
+/**********************************************************************
+ *
+ * queryfilter.cpp -- base class for queryfilters
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "queryfilter.h"
+#include "fileutil.h"
+#include "gsdltools.h"
+#include <assert.h>
+
+
+// translate will return true if successful
+bool queryfilterclass::translate (gdbmclass *gdbmptr, int docnum, text_t &trans_OID) {
+  infodbclass info;
+
+  trans_OID.clear();
+
+  // get the info
+  if (gdbmptr == NULL) return false;
+  if (!gdbmptr->getinfo(docnum, info)) return false;
+
+  // translate
+  if (info["section"].empty()) return false;
+
+  trans_OID = info["section"];
+  return true;
+}
+
+
+// whether document results are needed
+bool queryfilterclass::need_matching_docs (int filterResultOptions) {
+  return ((filterResultOptions & FROID) || (filterResultOptions & FRranking) ||
+	  (filterResultOptions & FRmetadata));
+}
+
+// whether term information is needed
+bool queryfilterclass::need_term_info (int filterResultOptions) {
+  return ((filterResultOptions & FRtermFreq) || (filterResultOptions & FRmatchTerms));
+}
+
+/////////////////////////////////
+// functions for queryfilterclass
+/////////////////////////////////
+
+// get the query parameters
+void queryfilterclass::parse_query_params (const FilterRequest_t &request,
+					   vector<queryparamclass> &query_params,
+					   int &startresults, int &endresults,
+					   text_t &phrasematch, ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  // set defaults for the return parameters
+  query_params.erase(query_params.begin(), query_params.end());
+  startresults = filterOptions["StartResults"].defaultValue.getint();
+  endresults = filterOptions["EndResults"].defaultValue.getint();
+  phrasematch = filterOptions["PhraseMatch"].defaultValue;
+
+  // set defaults for query parameters
+  queryparamclass query;
+  query.combinequery = "or"; // first one must be "or"
+  query.collection = collection;
+  query.index = filterOptions["Index"].defaultValue;
+  query.subcollection = filterOptions["Subcollection"].defaultValue;
+  query.language = filterOptions["Language"].defaultValue;
+  query.querystring.clear();
+  query.search_type = (filterOptions["QueryType"].defaultValue == "ranked");
+  query.match_mode = (filterOptions["MatchMode"].defaultValue == "all");
+  query.casefolding = (filterOptions["Casefold"].defaultValue == "true");
+  query.stemming = (filterOptions["Stem"].defaultValue == "true");
+  query.maxdocs = filterOptions["Maxdocs"].defaultValue.getint();
+  query.level = filterOptions["Level"].defaultValue;
+  OptionValue_tarray::const_iterator options_here = request.filterOptions.begin();
+  OptionValue_tarray::const_iterator options_end = request.filterOptions.end();
+  while (options_here != options_end) {
+    if ((*options_here).name == "CombineQuery") {
+      // add this query
+      
+      // "all", needed when combining queries where the document results are needed
+      if (need_matching_docs (request.filterResultOptions)) query.maxdocs = -1; 
+      query_params.push_back (query);
+
+      // start on next query
+      query.clear();
+      query.combinequery = (*options_here).value;
+
+      // set defaults for query parameters
+      query.collection = collection;
+      query.index = filterOptions["Index"].defaultValue;
+      query.subcollection = filterOptions["Subcollection"].defaultValue;
+      query.language = filterOptions["Language"].defaultValue;
+      query.querystring.clear();
+      query.search_type = (filterOptions["QueryType"].defaultValue == "ranked");
+      query.match_mode = (filterOptions["MatchMode"].defaultValue == "all");
+      query.casefolding = (filterOptions["Casefold"].defaultValue == "true");
+      query.stemming = (filterOptions["Stem"].defaultValue == "true");
+      query.level = filterOptions["Level"].defaultValue;
+      // "all", needed when combining queries where the document results are needed
+      if (need_matching_docs (request.filterResultOptions)) query.maxdocs = -1; 
+      else query.maxdocs = filterOptions["Maxdocs"].defaultValue.getint();
+      
+    } else if ((*options_here).name == "StartResults") {
+      startresults = (*options_here).value.getint();
+    } else if ((*options_here).name == "EndResults") {
+      endresults = (*options_here).value.getint();
+    } else if ((*options_here).name == "QueryType") {
+      query.search_type = ((*options_here).value == "ranked");
+    } else if ((*options_here).name == "MatchMode") {
+      query.match_mode = ((*options_here).value == "all");
+      if (query.match_mode == 1) query.maxdocs = -1;
+    } else if ((*options_here).name == "Term") {
+      query.querystring = (*options_here).value;
+    } else if ((*options_here).name == "Casefold") {
+      query.casefolding = ((*options_here).value == "true");
+    } else if ((*options_here).name == "Stem") {
+      query.stemming = ((*options_here).value == "true");
+    } else if ((*options_here).name == "Index"&& (*options_here).value !="") {
+      query.index = (*options_here).value;
+    } else if ((*options_here).name == "Subcollection") {
+      query.subcollection = (*options_here).value;
+    } else if ((*options_here).name == "Language") {
+      query.language = (*options_here).value;
+    } else if ((*options_here).name == "Maxdocs") {
+      query.maxdocs = (*options_here).value.getint();
+    } else if ((*options_here).name == "PhraseMatch") {
+      phrasematch = (*options_here).value;
+    } else if ((*options_here).name == "Level") {
+      query.level = (*options_here).value;
+    } else {
+      logout << text_t2ascii
+	     << "warning: unknown queryfilter option \""
+	     << (*options_here).name
+	     << "\" ignored.\n\n";
+    }
+
+    ++options_here;
+  }
+
+  // add the last query
+  query_params.push_back (query);
+}
+
+
+
+
+queryfilterclass::queryfilterclass () {
+  gdbmptr = NULL;
+  textsearchptr = NULL;
+
+  FilterOption_t filtopt;
+  filtopt.name = "CombineQuery";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "and";
+  filtopt.validValues.push_back("and");
+  filtopt.validValues.push_back("or");
+  filtopt.validValues.push_back("not");
+  filterOptions["CombineQuery"] = filtopt;
+
+  // -- onePerQuery StartResults   integer
+  filtopt.clear();
+  filtopt.name = "StartResults";
+  filtopt.type = FilterOption_t::integert;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "1";
+  filtopt.validValues.push_back("1");
+  filtopt.validValues.push_back("1000");
+  filterOptions["StartResults"] = filtopt;
+
+  // -- onePerQuery EndResults     integer
+  filtopt.clear();
+  filtopt.name = "EndResults";
+  filtopt.type = FilterOption_t::integert;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "10";
+  filtopt.validValues.push_back("-1");
+  filtopt.validValues.push_back("1000");
+  filterOptions["EndResults"] = filtopt;
+
+  // -- onePerQuery QueryType      enumerated (boolean, ranked)
+  filtopt.clear();
+  filtopt.name = "QueryType";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "ranked";
+  filtopt.validValues.push_back("boolean");
+  filtopt.validValues.push_back("ranked");
+  filterOptions["QueryType"] = filtopt;
+
+  // -- onePerQuery MatchMode      enumerated (some, all)
+  filtopt.clear();
+  filtopt.name = "MatchMode";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "some";
+  filtopt.validValues.push_back("some");
+  filtopt.validValues.push_back("all");
+  filterOptions["MatchMode"] = filtopt;
+
+  // -- onePerTerm  Term           string ???
+  filtopt.clear();
+  filtopt.name = "Term";
+  filtopt.type = FilterOption_t::stringt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "";
+  filterOptions["Term"] = filtopt;
+
+  // -- onePerTerm  Casefold       boolean
+  filtopt.clear();
+  filtopt.name = "Casefold";
+  filtopt.type = FilterOption_t::booleant;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "true";
+  filtopt.validValues.push_back("false");
+  filtopt.validValues.push_back("true");
+  filterOptions["Casefold"] = filtopt;
+
+  // -- onePerTerm  Stem           boolean
+  filtopt.clear();
+  filtopt.name = "Stem";
+  filtopt.type = FilterOption_t::booleant;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "false";
+  filtopt.validValues.push_back("false");
+  filtopt.validValues.push_back("true");
+  filterOptions["Stem"] = filtopt;
+
+  // -- onePerTerm  Index          enumerated
+  filtopt.clear();
+  filtopt.name = "Index";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "";
+  filterOptions["Index"] = filtopt;
+
+  // -- onePerTerm  Subcollection  enumerated
+  filtopt.clear();
+  filtopt.name = "Subcollection";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "";
+  filterOptions["Subcollection"] = filtopt;
+
+  // -- onePerTerm  Language  enumerated
+  filtopt.clear();
+  filtopt.name = "Language";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerTerm;
+  filtopt.defaultValue = "";
+  filterOptions["Language"] = filtopt;
+
+  // -- onePerQuery  Maxdocs  integer
+  filtopt.clear();
+  filtopt.name = "Maxdocs";
+  filtopt.type = FilterOption_t::integert;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "200";
+  filtopt.validValues.push_back("-1");
+  filtopt.validValues.push_back("1000");
+  filterOptions["Maxdocs"] = filtopt;
+
+  // -- onePerQuery  PhraseMatch  enumerated
+  filtopt.clear();
+  filtopt.name = "PhraseMatch";
+  filtopt.type = FilterOption_t::enumeratedt;
+  filtopt.repeatable = FilterOption_t::onePerQuery;
+  filtopt.defaultValue = "some_phrases";
+  filtopt.validValues.push_back ("all_phrases");
+  filtopt.validValues.push_back ("some_phrases");
+  filtopt.validValues.push_back ("all_docs");
+  filterOptions["PhraseMatch"] = filtopt;
+}
+
+queryfilterclass::~queryfilterclass () {
+  // don't delete gdbmptr or mgsearchptr here, they'll 
+  // be cleaned up by mggdbmsource
+}
+
+void queryfilterclass::configure (const text_t &key, const text_tarray &cfgline) {
+  filterclass::configure (key, cfgline);
+
+  if (key == "indexmap") {
+    indexmap.importmap (cfgline);
+    
+    // update the list of indexes in the filter information
+    text_tarray options;
+    indexmap.gettoarray (options);
+    filterOptions["Index"].validValues = options;
+
+  } else if (key == "defaultindex") {
+    indexmap.from2to (cfgline[0], filterOptions["Index"].defaultValue);
+
+  } else if (key == "subcollectionmap") {
+    subcollectionmap.importmap (cfgline);
+
+    // update the list of subcollections in the filter information
+    text_tarray options;
+    subcollectionmap.gettoarray (options);
+    filterOptions["Subcollection"].validValues = options;
+
+  } else if (key == "defaultsubcollection") {
+    subcollectionmap.from2to (cfgline[0], filterOptions["Subcollection"].defaultValue);
+
+  } else if (key == "languagemap") {
+    languagemap.importmap (cfgline);
+
+    // update the list of languages in the filter information
+    text_tarray options;
+    languagemap.gettoarray (options);
+    filterOptions["Language"].validValues = options;
+
+  } else if (key == "defaultlanguage") {
+    languagemap.from2to (cfgline[0], filterOptions["Language"].defaultValue);
+  } else if (key == "indexstem") {
+    indexstem = cfgline[0];
+  }
+}
+
+bool queryfilterclass::init (ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  if (!filterclass::init(logout)) return false;
+
+  if (filterOptions["Index"].defaultValue.empty()) {
+    // use first index in map as default if no default is set explicitly
+    text_tarray fromarray;
+    indexmap.getfromarray(fromarray);
+    if (fromarray.size()) {
+      filterOptions["Index"].defaultValue = fromarray[0];
+    }
+  }
+
+  if (filterOptions["Subcollection"].defaultValue.empty()) {
+    // use first subcollection in map as default if no default is set explicitly
+    text_tarray fromarray;
+    subcollectionmap.getfromarray(fromarray);
+    if (fromarray.size()) {
+      filterOptions["Subcollection"].defaultValue = fromarray[0];
+    }
+  }
+
+  if (filterOptions["Language"].defaultValue.empty()) {
+    // use first language in map as default if no default is set explicitly
+    text_tarray fromarray;
+    languagemap.getfromarray(fromarray);
+    if (fromarray.size()) {
+      filterOptions["Language"].defaultValue = fromarray[0];
+    }
+  }
+
+  // get the filename for the database and make sure it exists
+  if (indexstem.empty()) {
+    indexstem = collection;
+  }
+  gdbm_filename = filename_cat(gdbmhome, "collect", collection, "index", "text", indexstem);
+
+  if (littleEndian()) gdbm_filename += ".ldb";
+  else gdbm_filename += ".bdb";
+
+  if (!file_exists(gdbm_filename)) {
+    logout << text_t2ascii
+	   << "warning: gdbm database \"" //****
+	   << gdbm_filename << "\" does not exist\n\n";
+    //return false; //****
+  }
+
+  return true;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryfilter.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryfilter.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryfilter.h	(revision 10506)
@@ -0,0 +1,98 @@
+/**********************************************************************
+ *
+ * queryfilter.h -- abstract base class for queryfilters
+ *          mgqueryfilter, mgppqueryfilter and lucenequeryfilter 
+ *          implement this
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef QUERYFILTER_H
+#define QUERYFILTER_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+#include "filter.h"
+#include "infodbclass.h"
+#include "maptools.h"
+#include "search.h"
+#include "queryinfo.h"
+
+
+class queryfilterclass : public filterclass {
+protected:
+
+  stringmap indexmap;
+  stringmap subcollectionmap;
+  stringmap languagemap;
+
+  text_t gdbm_filename;
+  text_t indexstem;
+  gdbmclass *gdbmptr;
+  
+  searchclass *textsearchptr;
+  
+   // get the query parameters
+  void parse_query_params (const FilterRequest_t &request,
+			   vector<queryparamclass> &query_params,
+			   int &startresults, int &endresults,
+			   text_t &phrasematch, ostream &logout);
+
+  // do query that might involve multiple sub queries
+  // textsearchptr and gdbmptr are assumed to be valid
+  virtual void do_multi_query (const FilterRequest_t &request,
+		       const vector<queryparamclass> &query_params,
+		       queryresultsclass &multiresults,
+		       comerror_t &err, ostream &logout)=0;
+
+public:
+  queryfilterclass ();
+  virtual ~queryfilterclass ();
+
+  // the gdbmptr remains the responsability of the calling code
+  void set_gdbmptr (gdbmclass *thegdbmptr) {gdbmptr=thegdbmptr;}
+
+  // the testsearchptr remains the responsability of the calling code
+  void set_textsearchptr (searchclass *thetextsearchptr) {textsearchptr=thetextsearchptr;}
+
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+  bool init (ostream &logout);
+
+  text_t get_filter_name () {return "QueryFilter";}
+  bool translate(gdbmclass *gdbmptr, int docnum, text_t &trans_OID);
+  bool need_matching_docs (int filterResultOptions);
+  bool need_term_info (int filterResultOptions);
+
+
+  virtual void filter (const FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout)=0;
+
+
+
+};
+
+
+#endif
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryinfo.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryinfo.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryinfo.cpp	(revision 10506)
@@ -0,0 +1,402 @@
+/**********************************************************************
+ *
+ * queryinfo.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "queryinfo.h"
+
+
+// query parameters
+
+queryparamclass::queryparamclass () {
+  clear ();
+}
+
+void queryparamclass::clear () {
+  combinequery.clear();
+  collection.clear();
+  index.clear();
+  subcollection.clear();
+  language.clear();
+  level.clear();
+  querystring.clear();
+  search_type = 0; // 0 = boolean, 1 = ranked
+  match_mode = 0; // 0 = some, 1 = all
+  casefolding = 0;
+  stemming = 0;
+  maxdocs = -1;    // all
+  maxnumeric = 4;  // must default to the same value as mg_passes
+}
+
+
+queryparamclass &queryparamclass::operator=(const queryparamclass &q) {
+  combinequery = q.combinequery;
+  collection = q.collection;
+  index = q.index;
+  subcollection = q.subcollection;
+  language = q.language;
+  level = q.level;
+  querystring = q.querystring;
+  search_type = q.search_type;
+  match_mode = q.match_mode;
+  casefolding = q.casefolding;
+  stemming = q.stemming;
+  maxdocs = q.maxdocs;
+  maxnumeric = q.maxnumeric;
+
+  return *this;
+}
+
+
+bool operator==(const queryparamclass &x, const queryparamclass &y) {
+  return ((x.combinequery == y.combinequery) &&
+	  (x.collection == y.collection) &&
+	  (x.index == y.index) &&
+	  (x.subcollection == y.subcollection) &&
+	  (x.language == y.language) &&
+	  (x.level == y.level) &&
+	  (x.querystring == y.querystring) &&
+	  (x.search_type == y.search_type) &&
+	  (x.match_mode == y.match_mode) &&
+	  (x.casefolding == y.casefolding) &&
+	  (x.stemming == y.stemming) &&
+	  (x.maxdocs == y.maxdocs) &&
+	  (x.maxnumeric == y.maxnumeric));
+}
+
+bool operator!=(const queryparamclass &x, const queryparamclass &y) {
+  return !(x == y);
+}
+
+
+ostream &operator<< (ostream &outs, queryparamclass &q) {
+  outconvertclass text_t2ascii;
+
+  outs << "*** queryparamclass\n";
+  outs << text_t2ascii << " combinequery = \"" << q.combinequery << "\"\n";
+  outs << text_t2ascii << " collection = \"" << q.collection << "\"\n";
+  outs << text_t2ascii << " index = \"" << q.index << "\"\n";
+  outs << text_t2ascii << " level = \"" << q.level << "\"\n";
+  outs << text_t2ascii << " subcollection = \"" << q.subcollection << "\"\n";
+  outs << text_t2ascii << " language = \"" << q.language << "\"\n";
+  outs << text_t2ascii << " querystring = \"" << q.querystring << "\"\n";
+  outs << " search_type = \"" << q.search_type << "\"\n";
+  outs << " match_mode = \"" << q.match_mode << "\"\n";
+  outs << " casefolding = \"" << q.casefolding << "\"\n";
+  outs << " stemming = \"" << q.stemming << "\"\n";
+  outs << " maxdocs = \"" << q.maxdocs << "\"\n";
+  outs << " maxnumeric = \"" << q.maxnumeric << "\"\n";
+  outs << "\n";
+
+  return outs;
+}
+
+
+
+
+// term frequencies
+
+termfreqclass::termfreqclass () {
+  clear();
+}
+
+void termfreqclass::clear() {
+  termstr.clear();
+  termstemstr.clear();
+  utf8equivterms.erase(utf8equivterms.begin(), utf8equivterms.end());
+  termfreq = 0;
+}
+
+termfreqclass &termfreqclass::operator=(const termfreqclass &t)  {
+  termstr = t.termstr;
+  termstemstr = t.termstemstr;
+  utf8equivterms = t.utf8equivterms;
+  termfreq = t.termfreq;
+
+  return *this;
+}
+	
+bool operator==(const termfreqclass &x, const termfreqclass &y) {
+  return ((x.termstr == y.termstr) &&
+	  (x.termstemstr == y.termstemstr) &&
+	  (x.termfreq == y.termfreq));
+}
+
+bool operator!=(const termfreqclass &x, const termfreqclass &y) {
+  return !(x == y);
+}
+
+// ordered by termfreq and then by termstr
+bool operator<(const termfreqclass &x, const termfreqclass &y) {
+  return ((x.termfreq < y.termfreq) ||
+	  ((x.termfreq == y.termfreq) && (x.termstemstr < y.termstemstr)) ||
+	  ((x.termfreq == y.termfreq) && (x.termstemstr == y.termstemstr) && (x.termstr < y.termstr)));
+}
+
+bool operator>(const termfreqclass &x, const termfreqclass &y) {
+  return ((x.termfreq > y.termfreq) ||
+	  ((x.termfreq == y.termfreq) && (x.termstemstr > y.termstemstr)) ||
+	  ((x.termfreq == y.termfreq) && (x.termstemstr == y.termstemstr) && (x.termstr > y.termstr)));
+}
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, termfreqclass &t) {
+  outconvertclass text_t2ascii;
+
+  outs << text_t2ascii << " t:\"" << t.termstr << "\"";
+  outs << text_t2ascii << " s:\"" << t.termstemstr << "\"";
+  outs << " f:" << t.termfreq << "\n";
+
+  return outs;
+}
+
+
+
+// one query result
+
+docresultclass::docresultclass() {
+  clear ();
+}
+
+void docresultclass::clear () {
+  docnum=-1;
+  docweight=0.0;
+  num_query_terms_matched=0;
+  num_phrase_match=0;
+}
+
+// merges two result classes relating to a single docnum
+docresultclass &docresultclass::combine(const docresultclass &d) {
+  docweight += d.docweight; // budget!
+  num_query_terms_matched += d.num_query_terms_matched;
+  num_phrase_match += d.num_phrase_match;
+
+  return *this;
+}
+
+docresultclass &docresultclass::operator=(const docresultclass &d) {
+  docnum = d.docnum;
+  docweight = d.docweight;
+  num_query_terms_matched = d.num_query_terms_matched;
+  num_phrase_match = d.num_phrase_match;
+
+  return *this;
+}
+
+
+bool operator==(const docresultclass &x, const docresultclass &y) {
+  return ((x.docnum == y.docnum) && (x.docweight == y.docweight) &&
+	  (x.num_query_terms_matched == y.num_query_terms_matched) &&
+	  (x.num_phrase_match == y.num_phrase_match));
+}
+
+bool operator<(const docresultclass &x, const docresultclass &y) {
+  return ((x.docnum < y.docnum) ||
+	  ((x.docnum == y.docnum) &&
+	   ((x.docweight < y.docweight) ||
+	    ((x.docweight == y.docweight) &&
+	     ((x.num_query_terms_matched < y.num_query_terms_matched) ||
+	      ((x.num_query_terms_matched == y.num_query_terms_matched) &&
+	       ((x.num_phrase_match < y.num_phrase_match))))))));
+}
+
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, docresultclass &a) {
+  outs << " d:" << a.docnum << " w:" << a.docweight << "\n";
+  return outs;
+}
+
+
+
+// many document results
+
+docresultsclass::docresultsclass () {
+  clear ();
+}
+
+void docresultsclass::clear () {
+  docset.erase(docset.begin(), docset.end());
+  docorder.erase(docorder.begin(), docorder.end());
+}
+
+void docresultsclass::docnum_order() {
+  docorder.erase(docorder.begin(), docorder.end());
+  
+  docresultmap::iterator here = docset.begin();
+  docresultmap::iterator end = docset.end();
+  while (here != end) {
+    docorder.push_back ((*here).first);
+    ++here;
+  }
+}
+
+void docresultsclass::combine_and (const docresultsclass &d) {
+  docorder.erase(docorder.begin(), docorder.end());
+
+  // put the resulting set in tempresults
+  docresultmap tempresults;
+  
+  docresultmap::const_iterator d_here = d.docset.begin();
+  docresultmap::const_iterator d_end = d.docset.end();
+  docresultmap::iterator found = docset.end();
+  while (d_here != d_end) {
+    found = docset.find((*d_here).first);
+    if (found != docset.end()) {
+      (*found).second.combine ((*d_here).second);
+      tempresults[(*found).first] = (*found).second;
+    }
+    ++d_here;
+  }
+
+  // then copy it back to docset
+  docset = tempresults;
+}
+
+void docresultsclass::combine_or (const docresultsclass &d) {
+  docorder.erase(docorder.begin(), docorder.end());
+    
+  docresultmap::const_iterator d_here = d.docset.begin();
+  docresultmap::const_iterator d_end = d.docset.end();
+  docresultmap::iterator found = docset.end();
+  while (d_here != d_end) {
+    found = docset.find((*d_here).first);
+    if (found != docset.end()) {
+      (*found).second.combine ((*d_here).second);
+    } else {
+      docset[(*d_here).first] = (*d_here).second;
+    }
+    ++d_here;
+  }
+}
+
+void docresultsclass::combine_not (const docresultsclass &d) {
+  docorder.erase(docorder.begin(), docorder.end());
+
+ docresultmap::const_iterator d_here = d.docset.begin();
+ docresultmap::const_iterator d_end = d.docset.end();
+ docresultmap::iterator found = docset.end();
+ while (d_here != d_end) {
+   found = docset.find((*d_here).first);
+   if (found != docset.end()) docset.erase (found);
+   ++d_here;
+ }
+}
+
+docresultsclass &docresultsclass::operator=(const docresultsclass &d) {
+  docset = d.docset;
+  docorder = d.docorder;
+
+  return *this;
+}
+
+
+
+
+// query results
+
+void queryresultsclass::clear () {
+  docs_matched = 0;
+  is_approx = Exact;
+  syntax_error = false;
+  postprocessed = false;
+
+  docs.clear();
+  orgterms.erase(orgterms.begin(),orgterms.end());
+  terms.erase(terms.begin(),terms.end());
+}
+
+queryresultsclass &queryresultsclass::operator=(const queryresultsclass &q) {
+  docs_matched = q.docs_matched;
+  is_approx = q.is_approx;
+  syntax_error = q.syntax_error;
+  postprocessed = q.postprocessed;
+
+  docs = q.docs;
+  terms = q.terms;
+  termvariants = q.termvariants;
+
+  return *this;
+}
+
+void queryresultsclass::sortuniqqueryterms() {
+  termfreqclassarray tempterms = orgterms;
+  text_tset seenterms;
+  terms.erase(terms.begin(), terms.end());
+
+  // sort the terms to get the frequencies in ascending order
+  sort (tempterms.begin(), tempterms.end());
+
+  // insert first occurance of each term (maximum)
+  termfreqclassarray::reverse_iterator here = tempterms.rbegin();
+  termfreqclassarray::reverse_iterator end = tempterms.rend();
+  while (here != end) {
+    if (seenterms.find((*here).termstr) == seenterms.end()) {
+      // the termstemstr and utf8equivterms might be different for
+      // different occurances of the term
+      (*here).termstemstr.clear();
+      (*here).utf8equivterms.erase((*here).utf8equivterms.begin(),
+				   (*here).utf8equivterms.end());
+      terms.push_back(*here);
+      seenterms.insert((*here).termstr);
+    }
+    ++here;
+  }
+
+  // now re-sort in ascending order
+  sort (terms.begin(), terms.end());
+}
+
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, queryresultsclass &q) {
+  outs << "*** queryresultsclass\n";
+  outs << "docs\n";
+
+  docresultmap::iterator docshere = q.docs.docset.begin();
+  docresultmap::iterator docsend = q.docs.docset.end();
+  while (docshere != docsend) {
+    outs << (*docshere).second;
+    ++docshere;
+  }
+
+  outs << "orgterms\n";
+  termfreqclassarray::iterator orgtermshere = q.orgterms.begin();
+  termfreqclassarray::iterator orgtermsend = q.orgterms.end();
+  while (orgtermshere != orgtermsend) {
+    outs << (*orgtermshere);
+    ++orgtermshere;
+  }
+
+  outs << "terms\n";
+  termfreqclassarray::iterator termshere = q.terms.begin();
+  termfreqclassarray::iterator termsend = q.terms.end();
+  while (termshere != termsend) {
+    outs << (*termshere);
+    ++termshere;
+  }
+
+  outs << "\n";
+
+  return outs;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryinfo.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryinfo.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/queryinfo.h	(revision 10506)
@@ -0,0 +1,188 @@
+/**********************************************************************
+ *
+ * queryinfo.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef QUERYINFO_H
+#define QUERYINFO_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#  include <ospace\std\algorithm>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#  if defined(GSDL_USE_ALGO_H)
+#    include <algo.h>
+#  else
+#    include <algorithm.h>
+#  endif
+#else
+#  include <vector>
+#  include <algorithm>
+#endif
+
+// query parameters
+
+struct queryparamclass {
+  text_t combinequery;
+  text_t collection;
+
+  // search_index = index+subcollection+language
+  text_t index;
+  text_t subcollection;
+  text_t language;
+  text_t level; // for new mg stuff
+  text_t querystring;
+  int search_type; // 0 = boolean, 1 = ranked
+  int match_mode; // 0 = some, 1 = all
+  int casefolding;
+  int stemming;
+  int maxdocs;
+  int maxnumeric;
+
+  queryparamclass ();
+  void clear ();
+  queryparamclass &operator=(const queryparamclass &q);
+};
+
+bool operator==(const queryparamclass &x, const queryparamclass &y);
+bool operator!=(const queryparamclass &x, const queryparamclass &y);
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, queryparamclass &q);
+
+
+
+// term frequencies
+
+struct termfreqclass {
+  text_t termstr;
+  text_t termstemstr;
+  text_tset utf8equivterms; // kept as utf8 string for fast matching
+  unsigned int termfreq;
+
+  termfreqclass ();
+  void clear();
+  termfreqclass &operator=(const termfreqclass &t);
+};
+
+typedef vector<termfreqclass> termfreqclassarray;
+
+bool operator==(const termfreqclass &x, const termfreqclass &y);
+bool operator!=(const termfreqclass &x, const termfreqclass &y);
+bool operator<(const termfreqclass &x, const termfreqclass &y);
+bool operator>(const termfreqclass &x, const termfreqclass &y);
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, termfreqclass &q);
+
+
+
+// one query result
+
+struct docresultclass {
+  int docnum;
+  float docweight;
+  unsigned int num_query_terms_matched;  // not available on all versions of mg
+  int num_phrase_match;                  // not available on all versions of mg
+
+  docresultclass();
+  ~docresultclass() {}
+  void clear ();
+  
+  // merges two result classes relating to a single docnum
+  docresultclass &combine(const docresultclass &d);
+
+  docresultclass &operator=(const docresultclass &d);
+};
+
+bool operator==(const docresultclass &x, const docresultclass &y);
+bool operator<(const docresultclass &x, const docresultclass &y);
+
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, docresultclass &a);
+
+
+struct ltint {
+  bool operator()(const int &t1, const int &t2) const
+  { return t1 < t2; }
+};
+
+typedef map<int, docresultclass, ltint> docresultmap;
+
+
+
+// many document results
+
+struct docresultsclass {
+  docresultmap docset;
+  vector<int> docorder;
+
+  docresultsclass ();
+  void clear ();
+  void docnum_order();
+
+  void combine_and (const docresultsclass &d);
+  void combine_or (const docresultsclass &d);
+  void combine_not (const docresultsclass &d);
+  
+  docresultsclass &operator=(const docresultsclass &d);
+};
+
+
+
+
+// query results
+
+struct queryresultsclass {
+  queryresultsclass () {clear();}
+
+  int docs_matched; // not available on all versions of mg
+  isapprox is_approx;
+  //  bool is_approx;   // not available on all versions of mg
+  bool syntax_error; // whether the query string was invalid
+  bool postprocessed; // whether this record has been post-processed
+  
+  docresultsclass docs;
+  termfreqclassarray orgterms; // terms before they are sorted and uniqued
+  termfreqclassarray terms;
+  text_tset termvariants;
+  
+  void clear ();
+  queryresultsclass &operator=(const queryresultsclass &q);
+  
+  void sortuniqqueryterms();
+};
+
+// stream output for debugging purposes
+ostream &operator<< (ostream &outs, queryresultsclass &q);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/read-grs.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/read-grs.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/read-grs.cpp	(revision 10506)
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1995-1999, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log$
+ * Revision 1.1  2005/05/23 04:06:20  davidb
+ *
+ * Introduction of Z39.50 Server code for Greenstone.  Based on the work of
+ * Chris Martin (2001 approx).  Updated to work with newer version of YAZ
+ * library.
+ *
+ * Revision 1.5  1999/11/30 13:47:12  adam
+ * Improved installation. Moved header files to include/yaz.
+ *
+ * Revision 1.4  1999/08/27 09:40:32  adam
+ * Renamed logf function to yaz_log. Removed VC++ project files.
+ *
+ * Revision 1.3  1999/03/31 11:18:25  adam
+ * Implemented odr_strdup. Added Reference ID to backend server API.
+ *
+ * Revision 1.2  1998/02/11 11:53:36  adam
+ * Changed code so that it compiles as C++.
+ *
+ * Revision 1.1  1997/09/01 08:55:53  adam
+ * New windows NT/95 port using MSV5.0. Test server ztest now in
+ * separate directory. When using NT, this test server may operate
+ * as an NT service. Note that the service.[ch] should be part of
+ * generic, but it isn't yet.
+ *
+ * Revision 1.1  1995/08/17 12:45:23  quinn
+ * Fixed minor problems with GRS-1. Added support in c&s.
+ *
+ *
+ */
+
+/*
+ * Little toy-thing to read a GRS-1 record from a file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include <yaz/proto.h>
+#include <yaz/log.h>
+
+#define GRS_MAX_FIELDS 50
+
+Z_GenericRecord *read_grs1(FILE *f, ODR o)
+{
+    char line[512], *buf;
+    int type, ivalue;
+    char value[512];
+    Z_GenericRecord *r = 0;
+
+    for (;;)
+    {
+	Z_TaggedElement *t;
+	Z_ElementData *c;
+
+	while (fgets(buf = line, 512, f))
+	{
+	    while (*buf && isspace(*buf))
+		buf++;
+	    if (!*buf || *buf == '#')
+		continue;
+	    break;
+	}
+	if (*buf == '}')
+	    return r;
+	if (sscanf(buf, "(%d,%[^)])", &type, value) != 2)
+	{
+	    yaz_log(LOG_WARN, "Bad data in '%s'", buf);
+	    return 0;
+	}
+	if (!type && *value == '0')
+	    return r;
+	if (!(buf = strchr(buf, ')')))
+	    return 0;
+	buf++;
+	while (*buf && isspace(*buf))
+	    buf++;
+	if (!*buf)
+	    return 0;
+	if (!r)
+	{
+	    r = (Z_GenericRecord *)odr_malloc(o, sizeof(*r));
+	    r->elements = (Z_TaggedElement **)
+                odr_malloc(o, sizeof(Z_TaggedElement*) * GRS_MAX_FIELDS);
+	    r->num_elements = 0;
+	}
+	r->elements[r->num_elements] = t = (Z_TaggedElement *)
+            odr_malloc(o, sizeof(Z_TaggedElement));
+	t->tagType = (int *)odr_malloc(o, sizeof(int));
+	*t->tagType = type;
+	t->tagValue = (Z_StringOrNumeric *)
+            odr_malloc(o, sizeof(Z_StringOrNumeric));
+	if ((ivalue = atoi(value)))
+	{
+	    t->tagValue->which = Z_StringOrNumeric_numeric;
+	    t->tagValue->u.numeric = (int *)odr_malloc(o, sizeof(int));
+	    *t->tagValue->u.numeric = ivalue;
+	}
+	else
+	{
+	    t->tagValue->which = Z_StringOrNumeric_string;
+	    t->tagValue->u.string = (char *)odr_malloc(o, strlen(value)+1);
+	    strcpy(t->tagValue->u.string, value);
+	}
+	t->tagOccurrence = 0;
+	t->metaData = 0;
+	t->appliedVariant = 0;
+	t->content = c = (Z_ElementData *)odr_malloc(o, sizeof(Z_ElementData));
+	if (*buf == '{')
+	{
+	    c->which = Z_ElementData_subtree;
+	    c->u.subtree = read_grs1(f, o);
+	}
+	else
+	{
+	    c->which = Z_ElementData_string;
+	    buf[strlen(buf)-1] = '\0';
+	    c->u.string = odr_strdup(o, buf);
+	}
+	r->num_elements++;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/search.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/search.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/search.cpp	(revision 10506)
@@ -0,0 +1,53 @@
+/**********************************************************************
+ *
+ * search.cpp -- abstract search class for mg
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "search.h"
+
+////////////////////
+// search class //
+////////////////////
+
+searchclass::searchclass ()
+{
+  cache = new querycache (RESULTCACHESIZE);
+ 
+}
+
+searchclass::~searchclass () 
+{
+  if (cache != NULL) 
+    {
+      delete cache;
+      cache = NULL;
+    }
+}
+
+
+void searchclass::setcollectdir (const text_t &thecollectdir)
+{
+  collectdir = thecollectdir;
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/search.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/search.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/search.h	(revision 10506)
@@ -0,0 +1,80 @@
+/**********************************************************************
+ *
+ * search.h -- abstract search class for mg systems
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef SEARCH_H
+#define SEARCH_H
+
+#include "text_t.h"
+#include "querycache.h"
+
+#define RESULTCACHESIZE 10
+#define MAXNUMDOCS      1000000
+#define MAXNUMTERMS     100
+
+class searchclass {
+public:
+  searchclass ();
+  virtual ~searchclass ();
+
+  // in subclass, should be over-rided to return "mg" or "mgpp"
+  virtual text_t get_textindex_type()=0;
+  // the index directory must be set before any searching
+  // is done
+  virtual void setcollectdir (const text_t &thecollectdir);
+  
+  // the search results are returned in queryresults
+  // search returns 'true' if it was able to do a search
+   virtual bool search(const queryparamclass &queryparams, 
+	      queryresultsclass &queryresults)=0;
+  
+  // the document text for 'docnum' is placed in 'output'
+  // docTargetDocument returns 'true' if it was able to
+  // try to get a document
+  // collection is needed to see if an index from the 
+  // collection is loaded. If no index has been loaded
+  // defaultindex is needed to load one
+  virtual bool docTargetDocument(const text_t &defaultindex,
+			 const text_t &defaultsubcollection,
+			 const text_t &defaultlanguage,
+			 const text_t &collection,
+			 int docnum,
+			 text_t &output)=0;
+
+  // unload_database clears any cached databases - 
+  // this is useful when attempting to
+  // completely remove all trace of a collectionserver at runtime (when
+  // using a persistent version of Greenstone like the windows local
+  // library)
+  virtual void unload_database ()=0;
+
+protected:
+  querycache *cache;
+  text_t collectdir; // the collection directory
+
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/source.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/source.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/source.cpp	(revision 10506)
@@ -0,0 +1,109 @@
+/**********************************************************************
+ *
+ * source.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "source.h"
+#include <assert.h>
+
+
+// default constructor does nothing
+sourceclass::sourceclass () {
+}
+
+// default destructor does nothing
+sourceclass::~sourceclass () {
+}
+
+// configure should be called once for each configuration line
+// default does nothing
+void sourceclass::configure (const text_t &/*key*/, const text_tarray &/*cfgline*/) {
+}
+
+// init should be called after all the configuration is done but
+// before any other methods are called
+// default does nothing
+bool sourceclass::init (ostream &/*logout*/) {
+  return true;
+}
+
+
+// translate_OID translates OIDs using ".pr", ."fc" etc.
+bool sourceclass::translate_OID (const text_t &/*OIDin*/, text_t &/*OIDout*/, 
+				 comerror_t &err, ostream &/*logout*/) {
+  err = noError;
+
+  return false;
+}
+
+
+// get_metadata fills out the metadata if possible, if it is not responsable
+// for the given OID then it will return false.
+bool sourceclass::get_metadata (const text_t &/*requestParams*/, const text_t &/*refParams*/, 
+				bool /*getParents*/, const text_tset &/*fields*/, 
+				const text_t &/*OID*/, MetadataInfo_tmap &metadata, 
+				comerror_t &err, ostream &/*logout*/) {
+  metadata.erase(metadata.begin(), metadata.end());
+  err = noError;
+
+  return false;
+}
+
+bool sourceclass::get_document (const text_t &/*OID*/, text_t &/*doc*/, 
+				comerror_t &err, ostream &/*logout*/) {
+  err = noError;
+
+  return false;
+}
+
+bool sourceclass::is_searchable(bool &issearchable, comerror_t &err, ostream &logout) {
+
+  // currently defaults to claiming the collection is searchable!!
+  issearchable = true;
+
+  err = noError;
+  
+  return false;
+}
+
+bool operator==(const sourceptr &x, const sourceptr &y) {
+  return (x.s == y.s);
+}
+
+bool operator<(const sourceptr &x, const sourceptr &y) {
+  return (x.s < y.s);
+}
+
+
+// thesource remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void sourcelistclass::addsource (sourceclass *thesource) {
+  // can't add a source that doesn't exist
+  assert (thesource != NULL);
+  if (thesource == NULL) return;
+
+  sourceptr sp;
+  sp.s = thesource;
+
+  sourceptrs.push_back(sp);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/source.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/source.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/source.h	(revision 10506)
@@ -0,0 +1,122 @@
+/**********************************************************************
+ *
+ * source.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef SOURCE_H
+#define SOURCE_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+
+
+class sourceclass {
+public:
+  sourceclass ();
+  virtual ~sourceclass ();
+
+  // configure should be called once for each configuration line
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  // init should be called after all the configuration is done but
+  // before any other methods are called
+  virtual bool init (ostream &logout);
+
+  // translate_OID translates OIDs using ".pr", ."fc" etc.
+  virtual bool translate_OID (const text_t &OIDin, text_t &OIDout, 
+			      comerror_t &err, ostream &logout);
+
+  // get_metadata fills out the metadata if possible, if it is not responsable
+  // for the given OID then it will return false.
+  virtual bool get_metadata (const text_t &requestParams, const text_t &refParams, 
+			     bool getParents, const text_tset &fields,
+			     const text_t &OID, MetadataInfo_tmap &metadata, 
+			     comerror_t &err, ostream &logout);
+
+  virtual bool get_document (const text_t &OID, text_t &doc, 
+			     comerror_t &err, ostream &logout);
+
+  virtual bool is_searchable(bool &issearchable, comerror_t &err, ostream &logout);
+};
+
+
+// The sourceptr class does not 'own' the source. The 
+// source should be deleted by the code which created it.
+class sourceptr {
+public:
+  sourceclass *s;
+
+  sourceptr () {s=NULL;}
+  ~sourceptr () {}
+};
+
+bool operator==(const sourceptr &x, const sourceptr &y);
+bool operator<(const sourceptr &x, const sourceptr &y);
+
+typedef vector<sourceptr> sourceptrlist;
+
+// contains a list of sources
+class sourcelistclass {
+protected:
+  sourceptrlist sourceptrs;
+
+public:
+  // type support for sourcelistclass
+  typedef sourceptrlist::iterator iterator;
+  typedef sourceptrlist::const_iterator const_iterator;
+  typedef sourceptrlist::reference reference;
+  typedef sourceptrlist::const_reference const_reference;
+  typedef sourceptrlist::size_type size_type;
+
+  typedef sourceptrlist::difference_type difference_type;
+  typedef sourceptrlist::const_reverse_iterator const_reverse_iterator;
+  typedef sourceptrlist::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return sourceptrs.begin();}
+  const_iterator begin () const {return sourceptrs.begin();}
+  iterator end () {return sourceptrs.end();}
+  const_iterator end () const {return sourceptrs.end();}
+
+  void erase(iterator pos) {sourceptrs.erase(pos);}
+  void erase(iterator first, iterator last) {sourceptrs.erase(first, last);}
+  sourcelistclass &operator=(const sourcelistclass &x) 
+    {sourceptrs=x.sourceptrs;return *this;}
+
+  bool empty () const {return sourceptrs.empty();}
+  size_type size() const {return sourceptrs.size();}
+
+
+  // added functionality
+  void clear () {sourceptrs.erase(sourceptrs.begin(),sourceptrs.end());}
+
+  // thesource remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addsource (sourceclass *thesource);
+};
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/win32.mak	(revision 10506)
@@ -0,0 +1,127 @@
+###########################################################################
+#
+# win32 makefile -- src/colservr
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..\..
+USE_STLPORT = 0
+DLL = 0
+DLLDEBUG = 0
+USE_Z3950=0
+STLPATH = "$(GSDLHOME)\packages\windows\stlport\stlport"
+
+AR = lib
+CC = cl
+
+CPPFLAGS = -GX
+!IF $(DLL)
+CPPFLAGS = $(CPPFLAGS) -MD
+!ELSE
+!IF ($(DLLDEBUG))
+CPPFLAGS = $(CPPFLAGS) -MDd
+!ENDIF
+!ENDIF
+
+LDFLAGS =
+DEFS = -D__WIN32__ -DHAVE_CONFIG_H -DPARADOCNUM -D_LITTLE_ENDIAN -DSHORT_SUFFIX -DXML_STATIC
+INCLUDES = -I"$(GSDLHOME)" -I"$(GSDLHOME)\lib" -I"$(GSDLHOME)\src\colservr" \
+	   -I"$(GSDLHOME)\src\recpt" -I"$(GSDLHOME)\packages\mg" \
+	   -I"$(GSDLHOME)\packages\mg\lib" -I"$(GSDLHOME)\packages\mg\src\text" \
+	   -I"$(GSDLHOME)\packages\windows\gdbm\gdbm" \
+           -I"$(GSDLHOME)\src\mgpp\lib" -I"$(GSDLHOME)\src\mgpp\text" \
+           -I"$(GSDLHOME)\packages\windows\expat"
+
+!IF $(USE_STLPORT)
+DEFS=$(DEFS) -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = $(INCLUDES) -I$(STLPATH)
+!ENDIF
+
+LIBS =
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $< 
+
+!IF $(USE_Z3950)
+INCLUDES = $(INCLUDES) -I"$(GSDLHOME)\packages\yaz\yaz-2.1.4\include" -I"$(GSDLHOME)\packages\d2m"
+Z3950HEADERS = 
+Z3950SOURCES = z3950parser.cpp z3950explain.cpp z3950_to_gsdl.cpp \
+	       z3950server.cpp read-grs.cpp
+Z3950OBJECTS = z3950parser.obj   z3950explain.obj   z3950_to_gsdl.obj   \
+	       z3950server.obj   read-grs.obj
+Z3950LIB = gsdlz3950.lib
+!ELSE
+Z3950HEADERS = 
+Z3950SOURCES = 
+Z3950OBJECTS = 
+Z3950LIB =
+!ENDIF
+
+HEADERS = mgq.h search.h mgsearch.h querycache.h queryinfo.h collectserver.h \
+          colservrconfig.h maptools.h filter.h source.h browsefilter.h \
+          queryfilter.h mgqueryfilter.h mggdbmsource.h phrasesearch.h \
+          phrasequeryfilter.h collectset.h mgppsearch.h mgppqueryfilter.h \
+          lucenegdbmsource.h lucenequeryfilter.h lucenesearch.h \
+          expat_resultset.h expat_document.h gdbmsource.h
+
+SOURCES = mgq.c search.cpp mgsearch.cpp querycache.cpp queryinfo.cpp \
+	  collectserver.cpp colservrconfig.cpp maptools.cpp filter.cpp \
+	  source.cpp browsefilter.cpp queryfilter.cpp mgqueryfilter.cpp \
+	  mggdbmsource.cpp phrasesearch.cpp phrasequeryfilter.cpp \
+          collectset.cpp mgppsearch.cpp mgppqueryfilter.cpp \
+          lucenegdbmsource.cpp lucenequeryfilter.cpp lucenesearch.cpp \
+          expat_resultset.cpp expat_document.cpp gdbmsource.cpp
+
+OBJECTS = mgq.obj search.obj mgsearch.obj querycache.obj queryinfo.obj \
+	  collectserver.obj colservrconfig.obj maptools.obj filter.obj \
+	  source.obj browsefilter.obj queryfilter.obj mgqueryfilter.obj \
+	  mggdbmsource.obj phrasesearch.obj phrasequeryfilter.obj \
+          collectset.obj mgppsearch.obj mgppqueryfilter.obj \
+          lucenegdbmsource.obj lucenequeryfilter.obj lucenesearch.obj \
+          expat_resultset.obj expat_document.obj gdbmsource.obj 
+	
+
+all : gsdlcolservr.lib $(Z3950LIB)
+
+gsdlcolservr.lib : $(OBJECTS) 
+	if EXIST gsdlcolservr.lib del gsdlcolservr.lib
+	$(AR) /out:gsdlcolservr.lib $(OBJECTS)
+
+gsdlz3950.lib : $(Z3950OBJECTS)
+	if EXIST gsdlz3950.lib del gsdlz3950.lib
+	$(AR) /out:gsdlz3950.lib $(Z3950OBJECTS)
+clean:
+	del *.obj
+	del gsdlcolservr.lib
+	del gsdlz3950.lib
+
+install:
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950_to_gsdl.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950_to_gsdl.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950_to_gsdl.cpp	(revision 10506)
@@ -0,0 +1,335 @@
+/**********************************************************************
+ *
+ * z3950_to_gsdl.cpp --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "z3950parser.h"
+#include "z3950server.h"
+#include "z3950_to_gsdl.h"
+
+// converts a char* to uppercase, I wouldn't be
+// writing this if I could find an existing
+// function to do it
+void toUpperString(char *&text)
+{
+  for (int i = 0; text[i] != '\0'; i++) {
+    text[i] = toupper(text[i]);
+  }
+}
+
+
+text_t gsdlCollection::getName() 
+{
+  return name;
+}
+
+bool gsdlCollection::z3950Capeable() const
+{
+  return z3950ready;
+}
+
+
+bool gsdlCollection::bib1_to_dc_mapping(text_t& filename)
+{
+    ifstream inFile;
+    int input_Bib1;
+    text_t input_DCES;
+    text_t input_Short;
+
+    char* filename_cstr = filename.getcstr();
+    inFile.open(filename_cstr, ios::in);
+    delete [] filename_cstr;
+
+    if (!inFile) {
+      return false;
+    }
+
+    const int BUFFERSIZE = 1024;
+    char buffer[BUFFERSIZE];
+
+    // read in pairs of values (mappings from Bib-1 to DCES)
+    while (!inFile.eof()) {
+      char input_DCES_tmp[BUFFERSIZE];
+
+      inFile.getline(buffer, BUFFERSIZE, '\n');
+      if (buffer[0] == '#') {
+	// ignore comments (# ...)
+	continue;
+      }
+
+      sscanf(buffer,"%d %s",&input_Bib1, input_DCES_tmp);
+
+      input_DCES = input_DCES_tmp;
+
+      Bib1_to_DCES[input_Bib1] = input_DCES;
+
+      if (z3950_verbosity_>2) {
+	cerr << "(" << input_Bib1 << "/" << input_DCES << ") ";
+      }
+    }
+
+    if (z3950_verbosity_>2) {
+      cerr << endl;
+    }
+    inFile.close();
+
+    return true;
+}
+
+
+bool gsdlCollection::dc_to_short_mapping(text_t& filename, 
+					 text_t& collectionName) 
+{
+    ifstream inFileBuild;
+    text_t input_DCES;
+    text_t input_Short;
+  
+    char* filename_cstr = filename.getcstr();
+    inFileBuild.open(filename_cstr, ios::in);
+    delete [] filename_cstr;
+
+    if (!inFileBuild) {
+      if (z3950_verbosity_>2) {
+	cerr << "Warning: Unable to open: " << filename << endl;
+	cerr << "         Collection " << collectionName << " might not be built" << endl;
+      }
+      return false;
+    }
+
+    const int BUFFERSIZE = 1024;
+    char buffer[BUFFERSIZE];
+
+    // find the indexfieldmap line
+    do {
+      inFileBuild >> buffer;
+      if (inFileBuild.eof()) {
+	if (z3950_verbosity_>1) {
+	  cerr << "Warning: Did not find indexfieldmap in build.cfg for " 
+	       << collectionName << endl;
+	}
+	return false;
+      }
+    } while (strcmp(buffer, "indexfieldmap") != 0);
+
+    // at this stage, buffer contains "indexfieldmap",
+    // if the file didn't contain it, would have returned above
+    inFileBuild >> buffer;
+    while (strstr(buffer, "->") != NULL) {
+      // buffer contains a DCES->Short mapping
+      input_DCES.clear();
+      input_Short.clear();
+
+      // copy in DCES
+      int i;
+      for (i = 0; buffer[i] != '-'; i++) {
+	input_DCES.appendcarr(&(buffer[i]), 1);
+      }
+
+      // skip over "->"
+      i+=2;
+
+      // copy in Short
+      for (; isalpha(buffer[i]); i++) {
+	input_Short.appendcarr(&(buffer[i]), 1);
+      }
+
+      // add to map
+      DCES_to_Short[input_DCES] = input_Short;
+
+      if (z3950_verbosity_>1) {
+	cerr << "<" << input_DCES << "/" << input_Short << "> ";
+      }
+
+      inFileBuild >> buffer;
+    }
+
+    inFileBuild.close();
+
+    if (z3950_verbosity_>1) {
+      cerr << endl;
+    }
+
+    return true;
+}    
+
+
+
+
+  // converts a Bib1 field number to a short index name,
+  // returns true if a mapping existed, false otherwise
+bool gsdlCollection::getFieldArg(int Bib1, text_t &Short) 
+{
+    if (Bib1_to_DCES.count(Bib1) < 1) return false;
+    if (DCES_to_Short.count(Bib1_to_DCES[Bib1]) < 1) return false;
+    Short = DCES_to_Short[Bib1_to_DCES[Bib1]];
+    return true;
+}
+  
+gsdlCollection::~gsdlCollection(void) 
+{
+    //cerr << "gsdlCollection destructor called" << endl;
+}
+
+gsdlCollection::gsdlCollection(void) 
+{
+    //cerr << "gsdlCollection void constructor called" << endl;
+}
+ 
+gsdlCollection::gsdlCollection(text_t collectionName, text_t gsdlhome) 
+{
+
+    //char *filename_cstr;
+    //ifstream inFile;
+    //int inFileSize = 0;
+    z3950ready = true;
+
+    // int input_Bib1;
+    //text_t input_DCES;
+    //text_t input_Short;
+
+    name = collectionName;
+
+    // read in the cfg file for Bib1_to_DCES
+    text_t col_filename = gsdlhome;
+    col_filename.appendcstr("/collect/");
+    col_filename.append(collectionName);
+    col_filename.appendcstr("/etc/bib1_to_dces.cfg");
+
+    if (!bib1_to_dc_mapping(col_filename)) {
+      text_t site_filename = gsdlhome;
+      site_filename.appendcstr("/etc/bib1_to_dces.cfg");
+
+      if (!bib1_to_dc_mapping(site_filename)) {
+	cerr << "Unable to find bib1->dublin core mapping for " 
+	     << collectionName << endl;
+	cerr << "Looked for:\n  " << col_filename << "\n  " 
+	     << site_filename << endl;
+	z3950ready = false;
+	return;
+      }
+    }
+
+    // read in the cfg file for mapping Dublin Core to Short (internal name)
+    text_t build_filename = gsdlhome;
+    build_filename.appendcstr("/collect/");
+    build_filename.append(collectionName);
+    build_filename.appendcstr("/index/build.cfg");
+
+    if (!dc_to_short_mapping(build_filename,collectionName)) {
+      // explicitly check for error (in case in future more work is done after
+      // this
+      z3950ready = false;
+      return;
+    }
+
+}
+
+
+void z3950Server::openLogfile(text_t extension, ofstream &out)
+{
+    char *cfilename;
+    text_t filename;
+
+    filename = filename_cat(gsdlhome, extension);
+    cfilename = filename.getcstr();
+
+    out.open(cfilename);
+    delete cfilename;
+}
+
+z3950Server::z3950Server(nullproto *protocol, text_t home)
+{ 
+
+    text_t dirname;
+    char * cdirname;
+
+    cerr << "Z3950Server: gsdlhome = " << home << endl;
+
+    this->gsdlhome = home;
+    cerr << gsdlhome.getcstr() << endl;
+    dirname = filename_cat(gsdlhome, "/collect");
+    cdirname = dirname.getcstr();
+    if (!read_dir (cdirname, collections)) exit (1);
+    delete cdirname;
+
+    cerr << "Constructing set list server" << endl;
+    this->protocol = protocol;
+
+    // initialise Yaz stuff for z39.50 server 
+}
+  
+bool z3950Server::initialise() 
+{
+      ofstream      logout;
+      int           reply;
+      comerror_t    error = noError;
+
+      this->openLogfile("/etc/z3950out.txt", logout);
+      reply = protocol->init(error, logout);
+      logout.close();
+      return (reply != 0 ? 1 : 0);
+}
+
+void z3950Server::configure(const text_t &key, const text_tarray &cfgline, 
+			    comerror_t &err)
+{
+      err = noError;
+
+      // ****
+      cerr << "Recieved " << key << " = ";
+      for (int unsigned i=0; i<cfgline.size(); i++)
+	{
+	  cout << cfgline[i] << " ";
+	}
+      cout << endl;
+
+      // DB // ****
+      if (key=="gsdlhome")
+	{  
+	  text_tarray cfgline;
+	  cfgline.push_back (gsdlhome);
+	  cerr << "Changing gsdlhome to " << gsdlhome << endl;
+	  protocol->configure(key, cfgline, err);
+	}
+      else if (key=="httpdomain")
+	{
+	  // Only let gsdlhome through !!!! // ****
+	  cerr << "Supressing httpdomain" << endl;
+	}
+      else if (key=="httpprefix")
+	{
+	  cerr << "Supressing httpprefix" << endl;
+	}
+      else
+	{ 
+	  protocol->configure(key, cfgline,err);
+	}
+}
+
+int z3950Server::run_z3950( int argc, char **argv ) 
+{
+
+    const int statserv_var =  statserv_main(argc, argv, bend_init, bend_close);
+    cerr << "statserv_main returns: " << statserv_var << endl;
+    return statserv_var;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950_to_gsdl.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950_to_gsdl.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950_to_gsdl.h	(revision 10506)
@@ -0,0 +1,88 @@
+/**********************************************************************
+ *
+ * z3950_to_gsdl.h --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef Z3950_TO_GSDL_H
+#define Z3950_TO_GSDL_H
+
+
+void toUpperString(char *&text);
+
+class gsdlCollection
+{
+ public:
+  gsdlCollection(); 
+  gsdlCollection(text_t collectionName, text_t gsdlhome);
+  ~gsdlCollection(void);
+
+  bool z3950Capeable() const;
+
+  // converts a Bib1 field number to a short index name,
+  // returns true if a mapping existed, false otherwise
+  bool getFieldArg(int Bib1, text_t &Short);
+
+  text_t getName(); // returns the name of the collection in short form
+  
+ protected:
+
+
+  bool bib1_to_dc_mapping(text_t& filename);
+  bool dc_to_short_mapping(text_t& filename, text_t& collectionName);
+
+ protected:
+  text_t name;
+  map<int, text_t>    Bib1_to_DCES;  // Bib-1 to DC metadata names
+  map<text_t, text_t> DCES_to_Short; // DC to short (2-3 letter) internal name
+
+  bool z3950ready; // is the collection Z39.50-ready ?
+                   // (i.e. does it have the cfg files for mappings)
+
+
+};
+
+class z3950Server 
+{
+protected:
+  text_tarray collections;
+  recptproto *protocol;
+  text_t      gsdlhome;
+
+  // save particular YAZ variables ...
+
+  void openLogfile(text_t extension, ofstream &out);
+
+
+public:
+  //z3950Server(recptproto *protocol, text_t home);
+  z3950Server(nullproto *protocol, text_t home);
+  
+  bool initialise();
+
+  void configure(const text_t &key, const text_tarray &cfgline, comerror_t &err);
+
+  int run_z3950( int argc, char **argv );
+
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950explain.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950explain.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950explain.cpp	(revision 10506)
@@ -0,0 +1,204 @@
+/**********************************************************************
+ *
+ * z3950explain.cpp --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "z3950explain.h"
+
+void getExplainInfo(bend_search_rr *rr, FilterResponse_t &response, comerror_t &err)
+{
+  text_t GSQuery = ZQueryToGSQuery(rr);
+  char *GSQuery_char = GSQuery.getcstr(); 
+
+  int i;
+  if (strstr(GSQuery_char, "TargetInfo") != NULL) {
+    // should be one only
+    // real-life example:
+    /*
+      62
+      explain-category targetInfo
+      date-of-info Sep 22, 1999
+      language eng
+    */
+    ResultDocInfo_t docinfo;
+    docinfo.metadata["explain-category"].values.push_back("TargetInfo");
+    docinfo.metadata["name"].values.push_back("Greenstone");
+    docinfo.metadata["namedResultSets"].values.push_back("false");
+    docinfo.metadata["multipleDBsearch"].values.push_back("true");
+    docinfo.metadata["language"].values.push_back("eng");
+    response.docInfo.push_back(docinfo);
+    response.numDocs++;
+  }
+  if (strstr(GSQuery_char, "DatabaseInfo") != NULL) {
+    // should be one per collection
+    // real-life example:
+    /*
+      3
+      dbnum 0
+      explain-category DatabaseInfo
+      database-name.1 0
+      title Z39.50 EXPLAIN DB
+      database-name.2 ir-explain-1
+      date-of-info Sep 22, 1999
+      language eng
+      dbpath /usr/wald/z39.50root/explain
+      dbname explain
+    */
+    ResultDocInfo_t docinfo;
+    docinfo.metadata["explain-category"].values.push_back("DatabaseInfo");
+    docinfo.metadata["database-name"].values.push_back("IR-Explain-1");
+    docinfo.metadata["title"].values.push_back("Z39.50 EXPLAIN DB");
+    docinfo.metadata["language"].values.push_back("eng");
+    docinfo.metadata["dbname"].values.push_back("explain");
+    response.docInfo.push_back(docinfo);
+    response.numDocs++;
+    // now get the info for each collection
+    text_tarray collectlist;
+    Protocol->get_collection_list(collectlist, err, cerr);
+    text_tarray::iterator COLHERE = collectlist.begin();
+    text_tarray::iterator COLEND = collectlist.end();
+    while (COLHERE != COLEND) {
+      // don't include information for non-active collections
+      bool collection_active;
+      Protocol->ping(*COLHERE, collection_active, err, cerr);
+      if (collection_active != true) {
+	COLHERE++;
+	continue;
+      }
+      ColInfoResponse_t collectinfo;
+      Protocol->get_collectinfo(*COLHERE, collectinfo, err, cerr);
+      docinfo.clear();
+      docinfo.metadata["name"].values.push_back(collectinfo.shortInfo.name);
+      docinfo.metadata["host"].values.push_back(collectinfo.shortInfo.host);
+      if (collectinfo.isPublic) {
+	docinfo.metadata["isPublic"].values.push_back("true");
+      } else {
+	docinfo.metadata["isPublic"].values.push_back("false");
+      }
+      if (collectinfo.isBeta) {
+	docinfo.metadata["isBeta"].values.push_back("true");
+      } else {
+	docinfo.metadata["isBeta"].values.push_back("false");
+      }
+      docinfo.metadata["buildDate"].values.push_back(collectinfo.buildDate);
+      text_tarray::iterator TEXTT_HERE = collectinfo.ccsCols.begin();
+      text_tarray::iterator TEXTT_END = collectinfo.ccsCols.end();
+      for (i = 1; TEXTT_HERE != TEXTT_END; i++, TEXTT_HERE++) {
+	text_t tmp = "ccsCols.";
+	tmp.appendint(i);
+	docinfo.metadata[tmp].values.push_back(*TEXTT_HERE);
+      }
+      TEXTT_HERE = collectinfo.languages.begin();
+      TEXTT_END = collectinfo.languages.end();
+      for (i = 1; TEXTT_HERE != TEXTT_END; i++, TEXTT_HERE++) {
+	text_t tmp = "languages.";
+	tmp.appendint(i);
+	docinfo.metadata[tmp].values.push_back(*TEXTT_HERE);
+      }
+      docinfo.metadata["numDocs"].values.push_back(collectinfo.numDocs);
+      docinfo.metadata["numSections"].values.push_back(collectinfo.numSections);
+      docinfo.metadata["numWords"].values.push_back(collectinfo.numWords);
+      docinfo.metadata["numBytes"].values.push_back(collectinfo.numBytes);
+
+      collectionmeta_map::iterator COLLMETA_MAP_HERE = collectinfo.collectionmeta.begin();
+      collectionmeta_map::iterator COLLMETA_MAP_END = collectinfo.collectionmeta.end();
+      for (i = 1; COLLMETA_MAP_HERE != COLLMETA_MAP_END; i++, COLLMETA_MAP_HERE++) {
+	text_t tmp = "collectionmeta.";
+	tmp.appendint(i);
+	text_t tmp2 = COLLMETA_MAP_HERE->first;
+	tmp2.appendcstr(" -> ");
+	tmp2.append(COLLMETA_MAP_HERE->second[g_EmptyText]);
+	docinfo.metadata[tmp].values.push_back(tmp2);
+      }
+      text_tmap::iterator TEXTT_MAP_HERE;
+      text_tmap::iterator TEXTT_MAP_END;
+      // uncomment if you want to include this in the explain record,
+      // it's a bit messy to include by default
+      /*
+      TEXTT_MAP_HERE = collectinfo.format.begin();
+      TEXTT_MAP_END = collectinfo.format.end();
+      for (i = 1; TEXTT_MAP_HERE != TEXTT_MAP_END; i++, TEXTT_MAP_HERE++) {
+	text_t tmp = "format.";
+	tmp.appendint(i);
+	text_t tmp2 = TEXTT_MAP_HERE->first;
+	tmp2.appendcstr(" -> ");
+	tmp2.append(TEXTT_MAP_HERE->second);
+	docinfo.metadata[tmp].values.push_back(tmp2);
+      }
+      */
+      TEXTT_MAP_HERE = collectinfo.building.begin();
+      TEXTT_MAP_END = collectinfo.building.end();
+      for (i = 1; TEXTT_MAP_HERE != TEXTT_MAP_END; i++, TEXTT_MAP_HERE++) {
+	text_t tmp = "building.";
+	tmp.appendint(i);
+	text_t tmp2 = TEXTT_MAP_HERE->first;
+	tmp2.appendcstr(" -> ");
+	tmp2.append(TEXTT_MAP_HERE->second);
+	docinfo.metadata[tmp].values.push_back(tmp2);
+      }
+      docinfo.metadata["receptionist"].values.push_back(collectinfo.receptionist);
+      docinfo.metadata["buildType"].values.push_back(collectinfo.buildType);
+      response.docInfo.push_back(docinfo);
+      response.numDocs++;
+      COLHERE++;
+    }
+  }
+  if (strstr(GSQuery_char, "SchemaInfo") != NULL) {
+    // should be one per collection
+    // real-life example:
+    /*
+      10
+      dbnum 1
+      explain-category schemaInfo
+      database-name.1 1
+      database-name.2 books
+      database-name.3 default
+      database-name.4 cat
+      date-of-info Sep 22, 1999
+      language eng
+      schema.1 1.2.840.10003.13.1000.3.1
+      dbpath /usr/wald/z39.50root/books
+      dbname books
+     */
+  }
+  if (strstr(GSQuery_char, "AttributeSetInfo") != NULL) {
+    // should be one per collection
+    // real-life example:
+    /*
+      9
+      dbnum 1
+      explain-category AttributeSetInfo
+      database-name.1 1
+      database-name.2 books
+      database-name.3 default
+      database-name.4 cat
+      date-of-info Sep 22, 1999
+      language eng
+      attribute-set.1 1.2.840.10003.13.1000.3.1
+      dbpath /usr/wald/z39.50root/books
+      dbname books
+    */
+  }
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950explain.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950explain.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950explain.h	(revision 10506)
@@ -0,0 +1,35 @@
+/**********************************************************************
+ *
+ * z3950proto.h --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef Z3950EXPLAIN_H
+#define Z3950EXPLAIN_H
+
+
+#include "z3950parser.h"
+
+void getExplainInfo(bend_search_rr *rr, FilterResponse_t &response, comerror_t &err);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950parser.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950parser.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950parser.cpp	(revision 10506)
@@ -0,0 +1,373 @@
+
+#include "z3950parser.h"
+
+void Z_AttributeList_parse(bend_search_rr *rr, Z_AttributeList *Z, text_t &GSQuery)
+{
+  /*
+    struct Z_AttributeList {
+    int num_attributes;
+    Z_AttributeElement **attributes;
+    };
+  */
+
+  /*
+    struct Z_AttributeElement {
+    Z_AttributeSetId *attributeSet; // OPT
+    int *attributeType;
+    int which;
+    union {
+    int *numeric;
+    Z_ComplexAttribute *complex;
+    #define Z_AttributeValue_numeric 1
+    #define Z_AttributeValue_complex 2
+    } value;
+    };
+  */
+
+  
+
+}
+
+void Z_Term_parse(bend_search_rr *rr, Z_Term *Z, text_t &GSQuery)
+{
+  /*
+    struct Z_Term {
+    int which;
+    union {
+    Odr_oct *general;
+    int *numeric;
+    Z_InternationalString *characterString;
+    Odr_oid *oid;
+    char *dateTime;
+    Z_External *external;
+    Z_IntUnit *integerAndUnit;
+    Odr_null *null;
+    #define Z_Term_general 1
+    #define Z_Term_numeric 2
+    #define Z_Term_characterString 3
+    #define Z_Term_oid 4
+    #define Z_Term_dateTime 5
+    #define Z_Term_external 6
+    #define Z_Term_integerAndUnit 7
+    #define Z_Term_null 8
+    } u;
+    };
+  */
+
+  char *term;
+
+  switch(Z->which){
+  case Z_Term_general: {
+    // must copy no more than len bytes from buf, or else previous query terms may be included
+    int buflen = Z->u.general->len;
+    term = new char[buflen+1];
+    memset(term, '\0', buflen+1);
+    strncpy(term, (const char*)(Z->u.general->buf), buflen);
+    GSQuery += term;
+    break; }
+  case Z_Term_numeric:
+    GSQuery += *(Z->u.numeric); // int*
+    break;
+  case Z_Term_characterString:
+    GSQuery += Z->u.characterString; // what is this type?
+    break;
+  case Z_Term_oid:
+    GSQuery += *(Z->u.oid); // int*
+    break;
+  case Z_Term_dateTime:
+    GSQuery += Z->u.dateTime; // char*
+    break;
+  case Z_Term_external:
+    GSQuery += " "; // ignore this for now
+    break;
+  case Z_Term_integerAndUnit:
+    GSQuery += " "; // ignore this for now
+    break;
+  case Z_Term_null:
+    GSQuery += " "; // void
+    break;
+  default:
+    cerr << "Error in Z_Term_parse" << endl;
+    exit(1);
+  }
+}
+
+void Z_ProximityOperator_parse(bend_search_rr *rr, Z_ProximityOperator *Z, text_t &GSQuery)
+{
+  /*
+    struct Z_ProximityOperator {
+    bool_t *exclusion; // OPT
+    int *distance;
+    bool_t *ordered;
+    #define Z_ProximityOperator_Prox_lessThan 1
+    #define Z_ProximityOperator_Prox_lessThanOrEqual 2
+    #define Z_ProximityOperator_Prox_equal 3
+    #define Z_ProximityOperator_Prox_greaterThanOrEqual 4
+    #define Z_ProximityOperator_Prox_greaterThan 5
+    #define Z_ProximityOperator_Prox_notEqual 6
+    int *relationType;
+    int which;
+    union {
+    Z_ProxUnit *known;
+    int *zprivate;
+    #define Z_ProximityOperator_known 1
+    #define Z_ProximityOperator_private 2
+    } u;
+    };
+    
+    #define Z_ProxUnit_character 1
+    #define Z_ProxUnit_word 2
+    #define Z_ProxUnit_sentence 3
+    #define Z_ProxUnit_paragraph 4
+    #define Z_ProxUnit_section 5
+    #define Z_ProxUnit_chapter 6
+    #define Z_ProxUnit_document 7
+    #define Z_ProxUnit_element 8
+    #define Z_ProxUnit_subelement 9
+    #define Z_ProxUnit_elementType 10
+    #define Z_ProxUnit_byte 11
+  */
+
+  // Greenstone (actually mgpp) supports proximity, but only 
+  // to n words either side.
+  // A more complete implementation of proximity can be added
+  // by parsing the other fields in Z_ProximityOperator.
+  // Note: this only works properly with MGPP collections
+  
+  GSQuery += " NEAR"; 
+  GSQuery += *(Z->distance);
+  GSQuery += " ";
+}
+
+void Z_Operator_parse(bend_search_rr *rr, Z_Operator *Z, text_t &GSQuery)
+{
+  /*
+    struct Z_Operator {
+    int which;
+    union {
+    Odr_null *and;
+    Odr_null *or;
+    Odr_null *and_not;
+    Z_ProximityOperator *prox;
+    #define Z_Operator_and 1
+    #define Z_Operator_or 2
+    #define Z_Operator_and_not 3
+    #define Z_Operator_prox 4
+    } u;
+    };
+  */
+  
+  switch(Z->which){
+  case Z_Operator_and:
+    GSQuery += " & ";
+    break;
+  case Z_Operator_or:
+    GSQuery += " | ";
+    break;
+  case Z_Operator_and_not:
+    GSQuery += " ! ";
+    break;
+  case Z_Operator_prox:
+    Z_ProximityOperator_parse(rr, Z->u.prox, GSQuery);
+    break;
+  default:
+    cerr << "Error in Z_Operator_parse" << endl;
+    exit(1);
+  }
+}
+
+void Z_Operand_parse(bend_search_rr *rr, Z_Operand *Z, text_t &GSQuery)
+{
+    /*
+      struct Z_Operand {
+      int which;
+      union {
+      Z_AttributesPlusTerm *attributesPlusTerm;
+      Z_ResultSetId *resultSetId;
+      Z_ResultSetPlusAttributes *resultAttr;
+      #define Z_Operand_APT 1
+      #define Z_Operand_resultSetId 2
+      #define Z_Operand_resultAttr 3
+      } u;
+      };
+    */
+  
+  switch(Z->which) {
+  case Z_Operand_APT: {
+    /*
+      struct Z_AttributesPlusTerm {
+      Z_AttributeList *attributes;
+      Z_Term *term;
+      };
+    */
+    
+    /*
+      struct Z_AttributeList {
+      int num_attributes;
+      Z_AttributeElement **attributes;
+      };
+    */
+    
+    /*
+      struct Z_AttributeElement {
+      Z_AttributeSetId *attributeSet; // OPT
+      int *attributeType;
+      int which;
+      union {
+      int *numeric;
+      Z_ComplexAttribute *complex;
+      #define Z_AttributeValue_numeric 1
+      #define Z_AttributeValue_complex 2
+      } value;
+      };
+    */
+    
+    char *term;
+    
+    if (Z->u.attributesPlusTerm->attributes->num_attributes > 0) {
+      int Bib1_relation = *(Z->u.attributesPlusTerm->attributes->attributes[0]->attributeType);
+      int Bib1_use = *(Z->u.attributesPlusTerm->attributes->attributes[0]->value.numeric);
+
+      // if use value is 1010 ("Body of text"), is not a fielded search
+      if (Bib1_use == 1010) {
+	// if relation value is 6 ("not"), add a "not" to GSQuery
+	if (Bib1_relation == 6) {
+	  GSQuery += "! ";
+	}
+	Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
+      }
+      // for other use values, is a fielded search
+      else {
+	text_t Short;
+	// only add [ ]: if the index exists in the collection,
+	// note: only the index names in the first collection of a
+	// multi-collection search are used at the moment
+	if ((Collection_map[rr->basenames[0]]).getFieldArg(Bib1_use, Short)) {
+	  GSQuery += "[";
+	  cerr << "Supressing square brackets for the moment!\n";
+
+	  Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
+	  GSQuery += "]";
+	  GSQuery += ":";
+	  GSQuery += Short;
+	}
+	// if it doesn't, add it as an unfielded search term
+	else {
+	  cerr << "[" << rr->basenames[0] << "]: failed to find index" << endl;
+	  Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
+	}
+      }
+    }
+    else {
+      Z_Term_parse(rr, Z->u.attributesPlusTerm->term, GSQuery);
+    }
+    break;
+  }
+  case Z_Operand_resultSetId: {
+    GSQuery += "(";
+    GSQuery += Resultsets[Z->u.resultSetId];
+    GSQuery += ")";
+    break; 
+  }
+  case Z_Operand_resultAttr:
+    GSQuery += " "; // ignore this for now
+    break;
+  default:
+    cerr << "Error in Z_Operand_parse" << endl;
+    exit(1);
+  } 
+}
+
+void Z_RPNStructure_parse(bend_search_rr *rr, Z_RPNStructure *Z, text_t &GSQuery)
+{
+  /*
+    struct Z_RPNStructure {
+    int which;
+    union {
+    Z_Operand *simple;
+    Z_Complex *complex;
+    #define Z_RPNStructure_simple 1
+    #define Z_RPNStructure_complex 2
+    } u;
+    };
+  */
+
+  switch(Z->which){
+  case Z_RPNStructure_simple:
+    Z_Operand_parse(rr, Z->u.simple, GSQuery);
+    break;
+  case Z_RPNStructure_complex:
+    GSQuery += "(";
+    Z_RPNStructure_parse(rr, Z->u.complex->s1, GSQuery);
+    Z_Operator_parse(rr, Z->u.complex->roperator, GSQuery);
+    Z_RPNStructure_parse(rr, Z->u.complex->s2, GSQuery);
+    GSQuery += ")";
+    break;
+  default:
+    cerr << "Error in Z_RPNStructure_parse" << endl;
+    exit(1);
+  }
+}
+
+text_t ZQueryToGSQuery(bend_search_rr *rr)
+{
+  text_t GSQuery;
+
+  switch(rr->query->which){
+  case Z_Query_type_0:
+    cerr << "querytype = 0" << endl;
+    // this is a void*, pretend it's a Greenstone-type query
+    GSQuery += (char*)(rr->query->u.type_0);
+    break;
+  case Z_Query_type_1: {
+    cerr << "querytype = 1" << endl;
+    /*
+      struct Z_RPNQuery {
+      Z_AttributeSetId *attributeSetId;
+      Z_RPNStructure *RPNStructure;
+      };
+    */
+    // parse attributeSetId
+    cerr << "attributeSetId = ";
+    int c, d = 0;
+    do {
+      c = rr->query->u.type_1->attributeSetId[d];
+      cerr << c;
+      d++;
+    } while (c >= 0);
+    cerr << endl;
+
+    Z_RPNStructure_parse(rr, rr->query->u.type_1->RPNStructure, GSQuery);
+    break; }
+  case Z_Query_type_2: {
+    cerr << "querytype = 2" << endl;
+    // this is just a buf (unsigned char*), pretend it's a Greenstone-type query
+    GSQuery += (char*)(rr->query->u.type_2->buf);
+    break; }
+  case Z_Query_type_100: {
+    cerr << "querytype = 100" << endl;
+     // this is just a buf (unsigned char*), pretend it's a Greenstone-type query
+    GSQuery += (char*)(rr->query->u.type_100->buf);
+    break; }
+  case Z_Query_type_101: {
+    cerr << "querytype = 101" << endl;
+    // check: is this really the same as a type 1 query?
+    Z_RPNStructure_parse(rr, rr->query->u.type_101->RPNStructure, GSQuery);
+    break; }
+  case Z_Query_type_102: {
+    cerr << "querytype = 102" << endl;
+     // this is just a buf (unsigned char*), pretend it's a Greenstone-type query
+    GSQuery += (char*)(rr->query->u.type_102->buf);
+    break; }
+  default: {
+    cerr << "Error in ZQueryToGSQuery" << endl;
+    exit(1); }
+  }
+
+  // override GSQuery (test code)
+  //GSQuery = "[the]:TX";
+
+  cerr << "GSQuery = `" << GSQuery << "'" << endl;
+  return GSQuery;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950parser.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950parser.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950parser.h	(revision 10506)
@@ -0,0 +1,77 @@
+/**********************************************************************
+ *
+ * z3950parser.h -- convert Z39.50's RPN query syntax into Greenstone
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef Z3950PARSER_H
+#define Z3950PARSER_H
+
+// YAZ headers
+extern "C" {
+#include <yaz/backend.h>
+#include <yaz/log.h>
+#ifdef ASN_COMPILED
+#include <yaz/ill.h>
+#endif
+}
+
+#include <string>
+#include <list>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+
+// Greenstone headers
+#include "fileutil.h"
+#include "comtypes.h"
+#include "recptproto.h"
+#include "nullproto.h"
+#include "z3950_to_gsdl.h"
+
+extern text_t gsdlhome;
+extern list<FilterResponse_t> Response_tlist;
+extern list<text_t> Response_tlist_colnames;
+extern list<int> Response_tlist_sizes;
+extern z3950Server *Server;
+extern collectset *Cservers;
+extern nullproto *Protocol;
+extern map<text_t, gsdlCollection> Collection_map;
+extern map<text_t, text_t> Resultsets;
+
+void Z_AttributeList_parse(bend_search_rr *rr, Z_AttributeList *Z, text_t &GSQuery);
+
+void Z_Term_parse(bend_search_rr *rr, Z_Term *Z, text_t &GSQuery);
+
+void Z_ProximityOperator_parse(bend_search_rr *rr, Z_ProximityOperator *Z, text_t &GSQuery);
+
+void Z_Operator_parse(bend_search_rr *rr, Z_Operator *Z, text_t &GSQuery);
+
+void Z_Operand_parse(bend_search_rr *rr, Z_Operand *Z, text_t &GSQuery);
+
+void Z_RPNStructure_parse(bend_search_rr *rr, Z_RPNStructure *Z, text_t &GSQuery);
+
+text_t ZQueryToGSQuery(bend_search_rr *rr);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950server.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950server.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950server.cpp	(revision 10506)
@@ -0,0 +1,955 @@
+
+// YAZ headers
+#include <yaz/backend.h>
+#include <yaz/log.h>
+#ifdef ASN_COMPILED
+#include <yaz/ill.h>
+#endif
+
+
+// Standard headers
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#  include <ospace\std\fstream>
+#  include <ospace\std\sstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#  include <strstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#  include <sstream>
+#endif
+
+#include <string>
+#include <list>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+
+// Greenstone headers
+#include "fileutil.h"
+#include "comtypes.h"
+#include "recptproto.h"
+#include "nullproto.h"
+
+
+// Z39.50 server headers
+#include "z3950parser.h"
+#include "z3950explain.h"
+
+#include "z3950server.h"
+
+// Dublin Core -> MARC (d2m) headers and source files
+#include "d2m4gs.h"
+
+// these globals are local to each thread,
+// one Z39.50 connection = one thread.
+text_t gsdlhome; // this is specified externally when Greenstone is installed
+list<FilterResponse_t> Response_tlist; // list of response sets
+list<text_t> Response_tlist_colnames;  // collection names for the above
+list<int> Response_tlist_sizes;        // sizes (number of records) for the above
+z3950Server *Server   = NULL;
+collectset  *Cservers = NULL;
+nullproto   *Protocol = NULL;
+
+map<text_t, gsdlCollection> Collection_map; // info and tools for collections
+map<text_t, text_t> Resultsets;             // mapping from ResultSetId to GSQuery 
+
+int z3950_verbosity_ = 3;
+
+// *** initialize things here ***
+bend_initresult *bend_init(bend_initrequest *q)
+{
+  // *** called when client connects to the server ***
+  if (z3950_verbosity_ > 1) {
+    cerr << "Entering bend_init" << endl;
+  }
+
+  Protocol = new nullproto();  
+  Cservers = new collectset(gsdlhome);
+  Protocol->set_collectset(Cservers);
+  
+  cerr << "Starting Z39.50 Server ..." << endl;
+  
+  Server = new z3950Server(Protocol, gsdlhome);
+  cerr << "Server constructed" << endl;
+  
+  const bool status = Server->initialise();
+  cerr << "Initialised server: return status = " << status << endl;
+  
+  text_tarray collist;
+  comerror_t err;
+  Protocol->get_collection_list( collist, err, cout );
+
+  // display the list of available Greenstone collections
+  text_tarray::iterator cols_here=collist.begin();
+  text_tarray::iterator cols_end=collist.end();
+  while (cols_here != cols_end) {
+    gsdlCollection tmpcol(*cols_here, gsdlhome);
+    
+    Collection_map[*cols_here] = tmpcol;
+    
+    if (tmpcol.z3950Capeable()) {
+      cerr << "  " << tmpcol.getName() << "\tis Z39.50 capable" << endl;
+    }
+    cols_here++;
+  }
+
+    
+  bend_initresult *r = (bend_initresult *) odr_malloc (q->stream, sizeof(*r));
+  //static char *dummy = "Hej fister"; // what's this for?
+  
+  r->errcode = 0;
+  r->errstring = 0;
+  r->handle = Protocol;
+  q->bend_sort = ztest_sort;       /* register sort handler */
+  q->bend_search = ztest_search;   /* register search handler */
+  q->bend_present = ztest_present; /* register present handle */
+  q->bend_esrequest = ztest_esrequest;
+  q->bend_delete = ztest_delete;
+  q->bend_fetch = ztest_fetch;
+  q->bend_scan = ztest_scan;
+
+  return r;
+}
+
+// *** perform query, get number of hits ***
+int ztest_search (void *handle, bend_search_rr *rr)
+{
+  // *** called when client issues a "find" command
+  if (z3950_verbosity_>1) {
+    cerr << "Entering ztest_search" << endl;
+  }
+
+  Response_tlist.clear();
+  Response_tlist_colnames.clear();
+  Response_tlist_sizes.clear();
+ 
+  comerror_t err;
+  FilterRequest_t request;
+
+  request.filterName = "QueryFilter";
+  request.filterResultOptions = FROID | FRtermFreq | FRmetadata;  
+
+  OptionValue_t option;
+
+  // how many results to get. grouping all results together into
+  // one set instead of breaking up into "pages". 
+  // note: see if Z39.50 has a concept of pages.
+  option.name = "StartResults";
+  option.value = "1";
+  request.filterOptions.push_back (option);
+  option.name = "EndResults";
+  option.value = MAXHITS;
+  request.filterOptions.push_back (option);
+  option.name = "Maxdocs";
+  option.value = MAXHITS;
+  request.filterOptions.push_back (option);
+
+  text_t GSQuery = ZQueryToGSQuery(rr);
+  option.name = "Term";
+  option.value = GSQuery;
+  request.filterOptions.push_back (option);
+  Resultsets[Resultsets.size()+1] = GSQuery;
+
+  option.name = "QueryType";
+  option.value = "boolean";
+  request.filterOptions.push_back (option);
+
+  option.name = "MatchMode";
+  option.value = "all";
+  request.filterOptions.push_back (option);
+
+  option.name = "Casefold";
+  option.value = "true";
+  request.filterOptions.push_back (option);
+
+  option.name = "Stem";
+  option.value = "false";
+  request.filterOptions.push_back (option);
+
+  // MG queries don't need this, MGPP queries do.
+  // doesn't do any harm to include it anyway.
+  // note: not all collections have document-level granularity...
+  option.name = "Level";
+  option.value = "Doc";
+  request.filterOptions.push_back (option);
+
+  // Z39.50 supports the searching of multiple databases
+  rr->hits = 0;
+  for (int i = 0; i < rr->num_bases; i++) {
+    FilterResponse_t response;
+    cerr << "Searching basename = " << rr->basenames[i] << endl;
+    // intercept Explain requests
+    if (strcmp(rr->basenames[i], "IR-Explain-1")==0) {
+      //ColInfoResponse_t collectinfo;
+      //Protocol->get_collectinfo("csbib", collectinfo, err, cerr);
+      //response.numDocs = 1;
+      //ResultDocInfo_t docinfo;
+      //docinfo.metadata["foo"].values.push_back("bar");
+      getExplainInfo(rr, response, err);
+      //response.docInfo.push_back(docinfo);
+    } else {
+      cerr << "calling filter..." << endl;
+      Protocol->filter(rr->basenames[i], request, response, err, cerr);
+      cerr << "returned from filter." << endl;
+      if (response.numDocs > MAXHITS) {
+	response.numDocs = MAXHITS;
+      }
+    }
+    rr->hits += response.numDocs;
+    Response_tlist.push_back(response);
+    text_t basename = rr->basenames[i];
+    Response_tlist_colnames.push_back(basename);
+    Response_tlist_sizes.push_back(response.numDocs);
+    cerr << "search complete." << endl;
+  }    
+
+  if (rr->hits > MAXHITS) rr->hits = MAXHITS;
+  return 0;
+}
+
+// *** extra code for showing results, not needed ***
+int ztest_present (void *handle, bend_present_rr *rr)
+{
+  // *** called when client issues a "show" command, 1st of 5
+  if (z3950_verbosity_>1) {
+    cerr << "entering ztest_present" << endl;
+  }
+  return 0;
+}
+
+int ztest_esrequest (void *handle, bend_esrequest_rr *rr)
+{
+
+    if (z3950_verbosity_>1) {
+      cerr << "Entering ztest_esrequest" << endl;
+    }
+    yaz_log(LOG_LOG, "function: %d", *rr->esr->function);
+    if (rr->esr->packageName)
+    	yaz_log(LOG_LOG, "packagename: %s", rr->esr->packageName);
+    yaz_log(LOG_LOG, "Waitaction: %d", *rr->esr->waitAction);
+
+    if (!rr->esr->taskSpecificParameters)
+    {
+        yaz_log (LOG_WARN, "No task specific parameters");
+    }
+    else if (rr->esr->taskSpecificParameters->which == Z_External_itemOrder)
+    {
+    	Z_ItemOrder *it = rr->esr->taskSpecificParameters->u.itemOrder;
+	yaz_log (LOG_LOG, "Received ItemOrder");
+	switch (it->which)
+	{
+#ifdef ASN_COMPILED
+	case Z_IOItemOrder_esRequest:
+#else
+	case Z_ItemOrder_esRequest:
+#endif
+	{
+	    Z_IORequest *ir = it->u.esRequest;
+	    Z_IOOriginPartToKeep *k = ir->toKeep;
+	    Z_IOOriginPartNotToKeep *n = ir->notToKeep;
+	    
+	    if (k && k->contact)
+	    {
+	        if (k->contact->name)
+		    yaz_log(LOG_LOG, "contact name %s", k->contact->name);
+		if (k->contact->phone)
+		    yaz_log(LOG_LOG, "contact phone %s", k->contact->phone);
+		if (k->contact->email)
+		    yaz_log(LOG_LOG, "contact email %s", k->contact->email);
+	    }
+	    if (k->addlBilling)
+	    {
+	        yaz_log(LOG_LOG, "Billing info (not shown)");
+	    }
+	    
+	    if (n->resultSetItem)
+	    {
+	        yaz_log(LOG_LOG, "resultsetItem");
+		yaz_log(LOG_LOG, "setId: %s", n->resultSetItem->resultSetId);
+		yaz_log(LOG_LOG, "item: %d", *n->resultSetItem->item);
+	    }
+#ifdef ASN_COMPILED
+	    if (n->itemRequest)
+	    {
+		Z_External *r = (Z_External*) n->itemRequest;
+		ILL_ItemRequest *item_req = 0;
+		ILL_Request *ill_req = 0;
+		if (r->direct_reference)
+		{
+		    oident *ent = oid_getentbyoid(r->direct_reference);
+		    if (ent)
+			yaz_log(LOG_LOG, "OID %s", ent->desc);
+		    if (ent && ent->value == VAL_ISO_ILL_1)
+		    {
+			yaz_log (LOG_LOG, "ItemRequest");
+			if (r->which == ODR_EXTERNAL_single)
+			{
+			    odr_setbuf(rr->decode,
+				       (char*)(r->u.single_ASN1_type->buf),
+				       r->u.single_ASN1_type->len, 0);
+			    
+			    if (!ill_ItemRequest (rr->decode, &item_req, 0, 0))
+			    {
+				yaz_log (LOG_LOG,
+                                    "Couldn't decode ItemRequest %s near %d",
+                                       odr_errmsg(odr_geterror(rr->decode)),
+                                       odr_offset(rr->decode));
+                                yaz_log(LOG_LOG, "PDU dump:");
+                                odr_dumpBER(yaz_log_file(),
+                                     (const char*)(r->u.single_ASN1_type->buf),
+                                     r->u.single_ASN1_type->len);
+                            }
+			    if (rr->print)
+			    {
+				ill_ItemRequest (rr->print, &item_req, 0,
+                                    "ItemRequest");
+				odr_reset (rr->print);
+ 			    }
+			}
+			if (!item_req && r->which == ODR_EXTERNAL_single)
+			{
+			    yaz_log (LOG_LOG, "ILLRequest");
+			    odr_setbuf(rr->decode,
+				       (char*)(r->u.single_ASN1_type->buf),
+				       r->u.single_ASN1_type->len, 0);
+			    
+			    if (!ill_Request (rr->decode, &ill_req, 0, 0))
+			    {
+				yaz_log (LOG_LOG,
+                                    "Couldn't decode ILLRequest %s near %d",
+                                       odr_errmsg(odr_geterror(rr->decode)),
+                                       odr_offset(rr->decode));
+                                yaz_log(LOG_LOG, "PDU dump:");
+                                odr_dumpBER(yaz_log_file(),
+                                     (const char*)(r->u.single_ASN1_type->buf),
+                                     r->u.single_ASN1_type->len);
+                            }
+			    if (rr->print)
+                            {
+				ill_Request (rr->print, &ill_req, 0,
+                                    "ILLRequest");
+				odr_reset (rr->print);
+			    }
+			}
+		    }
+		}
+		if (item_req)
+		{
+		    yaz_log (LOG_LOG, "ILL protocol version = %d",
+			     *item_req->protocol_version_num);
+		}
+	    }
+#endif
+	}
+	break;
+	}
+    }
+    else if (rr->esr->taskSpecificParameters->which == Z_External_update)
+    {
+    	Z_IUUpdate *up = rr->esr->taskSpecificParameters->u.update;
+	yaz_log (LOG_LOG, "Received DB Update");
+	if (up->which == Z_IUUpdate_esRequest)
+	{
+	    Z_IUUpdateEsRequest *esRequest = up->u.esRequest;
+	    Z_IUOriginPartToKeep *toKeep = esRequest->toKeep;
+	    Z_IUSuppliedRecords *notToKeep = esRequest->notToKeep;
+	    
+	    yaz_log (LOG_LOG, "action");
+	    if (toKeep->action)
+	    {
+		switch (*toKeep->action)
+		{
+		case Z_IUOriginPartToKeep_recordInsert:
+		    yaz_log (LOG_LOG, " recordInsert");
+		    break;
+		case Z_IUOriginPartToKeep_recordReplace:
+		    yaz_log (LOG_LOG, " recordUpdate");
+		    break;
+		case Z_IUOriginPartToKeep_recordDelete:
+		    yaz_log (LOG_LOG, " recordDelete");
+		    break;
+		case Z_IUOriginPartToKeep_elementUpdate:
+		    yaz_log (LOG_LOG, " elementUpdate");
+		    break;
+		case Z_IUOriginPartToKeep_specialUpdate:
+		    yaz_log (LOG_LOG, " specialUpdate");
+		    break;
+		default:
+		    yaz_log (LOG_LOG, " unknown (%d)", *toKeep->action);
+		}
+	    }
+	    if (toKeep->databaseName)
+	    {
+		yaz_log (LOG_LOG, "database: %s", toKeep->databaseName);
+		if (!strcmp(toKeep->databaseName, "fault"))
+		{
+		    rr->errcode = 109;
+		    rr->errstring = toKeep->databaseName;
+		}
+		if (!strcmp(toKeep->databaseName, "accept"))
+		    rr->errcode = -1;
+	    }
+	    if (notToKeep)
+	    {
+		int i;
+		for (i = 0; i < notToKeep->num; i++)
+		{
+		    Z_External *rec = notToKeep->elements[i]->record;
+
+		    if (rec->direct_reference)
+		    {
+			struct oident *oident;
+			oident = oid_getentbyoid(rec->direct_reference);
+			if (oident)
+			    yaz_log (LOG_LOG, "record %d type %s", i,
+				     oident->desc);
+		    }
+		    switch (rec->which)
+		    {
+		    case Z_External_sutrs:
+			if (rec->u.octet_aligned->len > 170)
+			    yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
+				     rec->u.sutrs->len,
+				     rec->u.sutrs->buf);
+			else
+			    yaz_log (LOG_LOG, "%d bytes:\n%s",
+				     rec->u.sutrs->len,
+				     rec->u.sutrs->buf);
+                        break;
+		    case Z_External_octet        :
+			if (rec->u.octet_aligned->len > 170)
+			    yaz_log (LOG_LOG, "%d bytes:\n%.168s ...",
+				     rec->u.octet_aligned->len,
+				     rec->u.octet_aligned->buf);
+			else
+			    yaz_log (LOG_LOG, "%d bytes\n%s",
+				     rec->u.octet_aligned->len,
+				     rec->u.octet_aligned->buf);
+		    }
+		}
+	    }
+	}
+    }
+    else
+    {
+        yaz_log (LOG_WARN, "Unknown Extended Service(%d)",
+		 rr->esr->taskSpecificParameters->which);
+	
+    }
+    return 0;
+}
+
+int ztest_delete (void *handle, bend_delete_rr *rr)
+{
+  // *** called when client issues a "delete" command
+  if (z3950_verbosity_>1) {
+    cerr << "Entering ztest_delete" << endl;
+  }
+  if (rr->num_setnames == 1 && !strcmp (rr->setnames[0], "1"))
+    rr->delete_status = Z_DeleteStatus_success;
+  else
+    rr->delete_status = Z_DeleteStatus_resultSetDidNotExist;
+  return 0;
+}
+
+// *** do we want to sort the results? ***
+/* Our sort handler really doesn't sort... */
+int ztest_sort (void *handle, bend_sort_rr *rr)
+{
+  if (z3950_verbosity_>1) {
+    cerr << "entering ztest_sort" << endl;
+  }
+  rr->errcode = 0;
+  rr->sort_status = Z_SortStatus_success;
+  return 0;
+}
+
+static int atoin (const char *buf, int n)
+{
+  // *** called when client issues a "show" command, 5th of 5
+  // *** NOT called if the "show" command has an invalid argument
+    if (z3950_verbosity_>1) {
+      cerr << "Entering atoin" << endl;
+    }
+    int val = 0;
+    while (--n >= 0)
+    {
+        if (isdigit(*buf))
+            val = val*10 + (*buf - '0');
+        buf++;
+    }
+    return val;
+}
+
+// *** don't think we want this ***
+static Z_GenericRecord *dummy_grs_record (int num, ODR o)
+{
+  if (z3950_verbosity_>1) {
+    cerr << "Entering dummy_grs_record" << endl;
+  }
+
+  FILE *f = fopen("dummy-grs", "r");
+  char line[512];
+  Z_GenericRecord *r = 0;
+  int n;
+  
+  if (!f)
+    return 0;
+  while (fgets(line, 512, f))
+    if (*line == '#' && sscanf(line, "#%d", &n) == 1 && n == num)
+      {
+	r = read_grs1(f, o);
+	break;
+      }
+  fclose(f);
+  return r;
+}
+
+bool get_sutrs_record (int recnum, text_t &MetadataResult, text_t &CollectionName)
+{
+  if (z3950_verbosity_>1) {
+    cerr << "Entering get_sutrs_record" << endl;
+  }
+  int total_records = 0;
+
+  list<FilterResponse_t>::iterator RESPONSE_here = Response_tlist.begin();
+  list<FilterResponse_t>::iterator RESPONSE_end = Response_tlist.end();
+  list<text_t>::iterator RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
+  list<text_t>::iterator RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
+  list<int>::iterator RESPONSE_SIZES_here = Response_tlist_sizes.begin();
+  list<int>::iterator RESPONSE_SIZES_end = Response_tlist_sizes.end();
+
+  RESPONSE_here = Response_tlist.begin();
+  RESPONSE_end = Response_tlist.end();
+  while (RESPONSE_here != RESPONSE_end) {
+    total_records += (*RESPONSE_here).numDocs;
+    RESPONSE_here++;
+  }
+
+  // check that the index is within bounds
+  if (recnum < 1 || recnum > total_records) {
+    cerr << "get_sutrs_record failed" << endl;
+    return false; // failed
+  } else {
+    FilterResponse_t response;
+    // iterate through Response_tlist to find the right response
+    RESPONSE_here = Response_tlist.begin();
+    RESPONSE_end = Response_tlist.end();
+    RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
+    RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
+    RESPONSE_SIZES_here = Response_tlist_sizes.begin();
+    RESPONSE_SIZES_end = Response_tlist_sizes.end();
+    int n = 0;
+
+    while (RESPONSE_here != RESPONSE_end) {
+      n += *RESPONSE_SIZES_here;
+      if (n >= recnum) {
+	response = *RESPONSE_here;
+	CollectionName = *RESPONSE_COLNAMES_here;
+	recnum = *RESPONSE_SIZES_here - (n - recnum);
+	break;
+      }
+      // these should all have the same number of elements,
+      // so only need to check that one is within bounds.
+      // may want to combine these into a larger data structure later.
+      RESPONSE_here++;
+      RESPONSE_COLNAMES_here++;
+      RESPONSE_SIZES_here++;
+    }
+
+    // locate the desired record in the response 
+   
+    MetadataInfo_tmap::iterator METAFIELD_here = response.docInfo[recnum-1].metadata.begin();
+    MetadataInfo_tmap::iterator METAFIELD_end = response.docInfo[recnum-1].metadata.end();
+
+    while (METAFIELD_here!=METAFIELD_end) {
+      text_tarray::iterator METAVALUE_here = METAFIELD_here->second.values.begin();
+      text_tarray::iterator METAVALUE_end = METAFIELD_here->second.values.end();
+      while (METAVALUE_here!=METAVALUE_end) {
+	// construct a text_t containing the record:
+	// there are multiple metadata fields,
+	// each field can have multiple values.
+	/*
+	// don't include fields starting with a lowercase letter,
+	// these are system fields.
+	// later: include these anyway, since Explain fields start with lowercase letters
+	if (METAFIELD_here->first[0] >= 'A' &&
+	    METAFIELD_here->first[0] <= 'Z') {
+	*/
+	  MetadataResult += METAFIELD_here->first; // field name
+	  MetadataResult += " ";
+	  MetadataResult += *METAVALUE_here; // field contents
+	  MetadataResult += "\n";
+	  //}
+	METAVALUE_here++;
+      }
+      METAFIELD_here++;
+    }
+    return true; // succeeded
+  }
+}
+
+bool get_marc_record (int recnum, list<metatag*> &Metatag_list, text_t &CollectionName)
+{
+  if (z3950_verbosity_>1) {
+    cerr << "Entering get_marc_record" << endl;
+  }
+  int total_records = 0;
+
+  list<FilterResponse_t>::iterator RESPONSE_here = Response_tlist.begin();
+  list<FilterResponse_t>::iterator RESPONSE_end = Response_tlist.end();
+  list<text_t>::iterator RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
+  list<text_t>::iterator RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
+  list<int>::iterator RESPONSE_SIZES_here = Response_tlist_sizes.begin();
+  list<int>::iterator RESPONSE_SIZES_end = Response_tlist_sizes.end();
+
+  RESPONSE_here = Response_tlist.begin();
+  RESPONSE_end = Response_tlist.end();
+  while (RESPONSE_here != RESPONSE_end) {
+    total_records += (*RESPONSE_here).numDocs;
+    RESPONSE_here++;
+  }
+
+  // check that the index is within bounds
+  if (recnum < 1 || recnum > total_records) {
+    cerr << "get_marc_record failed" << endl;
+    return false; // failed
+  } else {
+    FilterResponse_t response;
+    // iterate through Response_tlist to find the right response
+    RESPONSE_here = Response_tlist.begin();
+    RESPONSE_end = Response_tlist.end();
+    RESPONSE_COLNAMES_here = Response_tlist_colnames.begin();
+    RESPONSE_COLNAMES_end = Response_tlist_colnames.end();
+    RESPONSE_SIZES_here = Response_tlist_sizes.begin();
+    RESPONSE_SIZES_end = Response_tlist_sizes.end();
+    int n = 0;
+    while (RESPONSE_here != RESPONSE_end) {
+      n += *RESPONSE_SIZES_here;
+      if (n >= recnum) {
+	response = *RESPONSE_here;
+	CollectionName = *RESPONSE_COLNAMES_here;
+	recnum = *RESPONSE_SIZES_here - (n - recnum);
+	break;
+      }
+      // these should all have the same number of elements,
+      // so only need to check that one is within bounds.
+      // may want to combine these into a larger data structure later.
+      RESPONSE_here++;
+      RESPONSE_COLNAMES_here++;
+      RESPONSE_SIZES_here++;
+    }
+
+    // locate the desired record in the response
+    
+    MetadataInfo_tmap::iterator METAFIELD_here = response.docInfo[recnum-1].metadata.begin();
+    MetadataInfo_tmap::iterator METAFIELD_end = response.docInfo[recnum-1].metadata.end();
+    
+    while (METAFIELD_here!=METAFIELD_end) {
+      text_tarray::iterator METAVALUE_here = METAFIELD_here->second.values.begin();
+      text_tarray::iterator METAVALUE_end = METAFIELD_here->second.values.end();
+      while (METAVALUE_here!=METAVALUE_end) {
+	if (METAFIELD_here->first[0] >= 'A' &&
+	    METAFIELD_here->first[0] <= 'Z') {
+	  metatag *tmptag = new metatag();
+	  tmptag->name = METAFIELD_here->first.getcstr();
+	  tmptag->type = "";
+	  tmptag->scheme = "";
+	  tmptag->value = (*METAVALUE_here).getcstr();
+	  Metatag_list.push_back(tmptag);
+	}
+	METAVALUE_here++;
+      }
+      METAFIELD_here++;
+    }
+    return true; // succeeded
+  }
+}
+
+// *** implement this ***
+int ztest_fetch(void *handle, bend_fetch_rr *r)
+{
+  // *** called when client issues a "show" command, 2nd of 5
+    if (z3950_verbosity_>1) {
+      cerr << "Entering ztest_fetch" << endl;
+    }
+    char *cp;
+    r->errstring = 0;
+    r->last_in_set = 0;
+    r->basename = "DUMMY"; // this is set below
+    r->output_format = r->request_format;
+
+    // *** use this until found a good way of mapping Greenstone
+    // *** metadata fields to USMARC fields
+    if (r->request_format == VAL_SUTRS)
+    {
+      // copies record into r, errcode will be 13 if fails
+      text_t MetadataResult;
+      text_t CollectionName;
+      if (!get_sutrs_record(r->number, MetadataResult, CollectionName)) {
+	r->errcode = 13;
+	return 0;
+      } else {			
+	r->len = MetadataResult.size();
+	r->record = (char*) odr_malloc(r->stream, r->len+1);
+	char *tmptxt = MetadataResult.getcstr();
+	strcpy(r->record, tmptxt);
+	delete tmptxt;
+	r->basename = (char*) odr_malloc(r->stream, CollectionName.size()+1);
+	tmptxt = CollectionName.getcstr();
+	strcpy(r->basename, tmptxt);
+	delete tmptxt;
+      }
+    }
+    // *** do we want to use this format? ***
+    else if (r->request_format == VAL_GRS1)
+    {
+      // bail out, since we don't support grs (yet?)
+      r->errcode = 107; // "Query type not supported"
+      return 0;
+      
+    } 
+    // assume that here on in is some sort of MARC format
+    else {
+      marcrec *mrec = new marcrec;
+
+      mrec = (marcrec*) malloc(sizeof(*mrec));
+      
+      mrec->marcline = (char*) malloc(100000);
+      mrec->partitle = (char*) malloc(10000);
+      mrec->subtitle = (char*) malloc(10000);
+      mrec->year     = (char*) malloc(1000);
+      mrec->url      = (char*) malloc(1000);
+      mrec->fmat     = (char*) malloc(1000);
+      mrec->s008     = (char*) malloc(41);
+      
+      mrec->ncreators = 0;
+      mrec->ntitles   = 0;
+      *mrec->marcline = 0;
+      *mrec->subtitle = 0;
+      *mrec->partitle = 0;
+      *mrec->year     = 0;
+      *mrec->url      = 0;
+      *mrec->fmat     = 0;
+      strcpy(mrec->s008, "                                        ");
+
+      text_t CollectionName;
+      list<metatag*> Metatag_list;
+
+      if (!get_marc_record(r->number, Metatag_list, CollectionName)) {
+	r->errcode = 13;
+	return 0;
+      } else {
+	list<metatag*>::iterator METATAG_here = Metatag_list.begin();
+	list<metatag*>::iterator METATAG_end = Metatag_list.end();
+	while (METATAG_here != METATAG_end) {
+	  usMARC(*METATAG_here, mrec);
+	  METATAG_here++;
+	}
+
+	// set the date in the marc record to the current date
+	char today[32];
+	time_t d;
+	struct tm *time_struct;
+	//putenv("TZ=NFT-1DFT");
+	d = time(NULL);
+	time_struct = localtime(&d);
+	strftime(today, 16, "%y%m%d", time_struct);
+	put008(mrec->s008, today, F008_DATE_ENTERED);
+	put008(mrec->s008, "s", F008_TYPE_OF_DATE);
+
+	// to do: make this safer + more efficient
+	cp = new char[1000000];
+	char *cp2 = new char[1000000];
+	
+	switch(r->request_format) {
+	case VAL_DANMARC: {
+	  MARCtidy(mrec, cp, DANMARC);
+	  r->output_format = VAL_DANMARC;
+	  break; }
+	case VAL_FINMARC: {
+	  MARCtidy(mrec, cp, FINMARC);
+	  r->output_format = VAL_FINMARC;
+	  break; }
+	// YAZ doesn't know about ISMARC
+	/*
+	case VAL_ISMARC: {
+	  put008(mrec->s008, "k", F008_FORM_OF_PUBLICATION);
+	  MARCtidy(mrec, cp, ISMARC);
+	  r->output_format = VAL_ISMARC;
+	  break; }
+	*/
+	case VAL_NORMARC: {
+	  MARCtidy(mrec, cp, NORMARC);
+	  r->output_format = VAL_NORMARC;
+	  break; }
+	case VAL_SWEMARC: {
+	  MARCtidy(mrec, cp, SWEMARC);
+	  r->output_format = VAL_SWEMARC;
+	  break; }
+	default: {
+	  MARCtidy(mrec, cp, USMARC);
+	  r->output_format = VAL_USMARC;
+	  break; }
+	}
+	
+	sprintf(cp2, "%s", (char*) MARC2709(cp, 0, 6, 'n', 'm', ' '));
+	r->len = strlen(cp2);
+	r->record = (char*) odr_malloc(r->stream, r->len+1);
+	strcpy(r->record, cp2);     
+	r->basename = (char*) odr_malloc(r->stream, CollectionName.size()+1);
+	char *tmptxt;
+	tmptxt = CollectionName.getcstr();
+	strcpy(r->basename, tmptxt);
+	delete tmptxt;
+	delete cp2;      
+	cerr << "dumping record:`" << cp << "'" << endl;
+	delete cp;
+      }
+    }
+
+    r->errcode = 0;
+    return 0;
+}
+
+/*
+ * silly dummy-scan what reads words from a file.
+ */
+int ztest_scan(void *handle, bend_scan_rr *q)
+{
+  // *** called when client issues a "scan" command
+  if (z3950_verbosity_>1) {
+    cerr << "Entering ztest_scan" << endl;
+  }
+    
+  // bail out, since we don't support scan (yet?)
+  q->errcode = 107; // "Query type not supported"
+  return 0;
+
+    static FILE *f = 0;
+    static struct scan_entry list[200];
+    static char entries[200][80];
+    int hits[200];
+    char term[80], *p;
+    int i, pos;
+    int term_position_req = q->term_position;
+    int num_entries_req = q->num_entries;
+
+    q->errcode = 0;
+    q->errstring = 0;
+    q->entries = list;
+    q->status = BEND_SCAN_SUCCESS;
+    if (!f && !(f = fopen("dummy-words", "r")))
+    {
+	perror("dummy-words");
+	exit(1);
+    }
+    if (q->term->term->which != Z_Term_general)
+    {
+    	q->errcode = 229; /* unsupported term type */
+	return 0;
+    }
+    if (*q->step_size != 0)
+    {
+	q->errcode = 205; /*Only zero step size supported for Scan */
+	return 0;
+    }
+    if (q->term->term->u.general->len >= 80)
+    {
+    	q->errcode = 11; /* term too long */
+	return 0;
+    }
+    if (q->num_entries > 200)
+    {
+    	q->errcode = 31;
+	return 0;
+    }
+    memcpy(term, q->term->term->u.general->buf, q->term->term->u.general->len);
+    term[q->term->term->u.general->len] = '\0';
+    for (p = term; *p; p++)
+    	if (islower(*p))
+	    *p = toupper(*p);
+
+    fseek(f, 0, SEEK_SET);
+    q->num_entries = 0;
+
+    for (i = 0, pos = 0; fscanf(f, " %79[^:]:%d", entries[pos], &hits[pos]) == 2;
+	i++, pos < 199 ? pos++ : (pos = 0))
+    {
+    	if (!q->num_entries && strcmp(entries[pos], term) >= 0) /* s-point fnd */
+	{
+	    if ((q->term_position = term_position_req) > i + 1)
+	    {
+	    	q->term_position = i + 1;
+		q->status = BEND_SCAN_PARTIAL;
+	    }
+	    for (; q->num_entries < q->term_position; q->num_entries++)
+	    {
+	    	int po;
+
+		po = pos - q->term_position + q->num_entries+1; /* find pos */
+		if (po < 0)
+		    po += 200;
+
+		if (!strcmp (term, "SD") && q->num_entries == 2)
+		{
+		    list[q->num_entries].term = entries[pos];
+		    list[q->num_entries].occurrences = -1;
+		    list[q->num_entries].errcode = 233;
+		    list[q->num_entries].errstring = "SD for Scan Term";
+		}
+		else
+		{
+		    list[q->num_entries].term = entries[po];
+		    list[q->num_entries].occurrences = hits[po];
+		}
+	    }
+	}
+	else if (q->num_entries)
+	{
+	    list[q->num_entries].term = entries[pos];
+	    list[q->num_entries].occurrences = hits[pos];
+	    q->num_entries++;
+	}
+	if (q->num_entries >= num_entries_req)
+	    break;
+    }
+    if (feof(f))
+    	q->status = BEND_SCAN_PARTIAL;
+    return 0;
+}
+
+
+
+void bend_close(void *handle)
+{
+  if (z3950_verbosity_>1) {
+    cerr << "Entering bend_close" << endl;
+  }
+  delete Server;
+  delete Cservers;
+  delete Protocol;
+  if (z3950_verbosity_>1) {
+    cerr << "heap cleaned up, exiting bend_close" << endl;
+  }
+  return;
+}
+
+int main (int argc, char *argv[])
+{
+  
+  const int statserv_var =  statserv_main(argc, argv, bend_init, bend_close);
+  cerr << "statserv_main returns: " << statserv_var << endl;
+  return statserv_var;
+  
+  return 0;
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950server.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950server.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/colservr/z3950server.h	(revision 10506)
@@ -0,0 +1,71 @@
+/**********************************************************************
+ *
+ * z3950server.h --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef Z3950SERVER_H
+#define Z3950ESRVER_H
+
+#include <string>
+#include <list>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+
+// Greenstone headers
+#include "fileutil.h"
+
+// the maximum number of hits allowed
+#define MAXHITS 10000
+
+// These globals are local to each thread: one Z39.50 connection = one thread.
+
+extern text_t gsdlhome; // this is specified externally when Greenstone is installed
+extern list<FilterResponse_t> Response_tlist; // list of response sets
+extern list<text_t> Response_tlist_colnames;  // collection names for the above
+extern list<int> Response_tlist_sizes;        // sizes (number of records) for the above
+extern z3950Server *Server;
+extern collectset *Cservers;
+extern nullproto *Protocol;
+extern map<text_t, gsdlCollection> Collection_map; // info and tools for collections
+extern map<text_t, text_t> Resultsets;             // mapping from ResultSetId to GSQuery 
+
+extern int z3950_verbosity_;
+
+bend_initresult *bend_init(bend_initrequest *q);
+void bend_close(void *handle);
+
+Z_GenericRecord *read_grs1(FILE *f, ODR o);
+
+int ztest_search (void *handle, bend_search_rr *rr);
+int ztest_sort (void *handle, bend_sort_rr *rr);
+int ztest_present (void *handle, bend_present_rr *rr);
+int ztest_esrequest (void *handle, bend_esrequest_rr *rr);
+int ztest_delete (void *handle, bend_delete_rr *rr);
+int ztest_fetch(void *handle, bend_fetch_rr *r);
+int ztest_scan(void *handle, bend_scan_rr *q);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/db2txt/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/db2txt/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/db2txt/Makefile.in	(revision 10506)
@@ -0,0 +1,87 @@
+###########################################################################
+#
+# Makefile -- Makefile for db2txt
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 Rodger McNab, Stefan Boddie
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)Makefile.in	1.3 16 Mar 1994
+#
+###########################################################################
+
+ 
+AR = ar
+CC = @CC@
+CPP = @CXX@
+CCFLAGS = -Wall @CFLAGS@ 
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INCLUDES = -I../../lib @GDBM_INCLUDE@
+LDFLAGS = @LDFLAGS@
+DPLIBS = 
+LIBS = @GDBM_LIBPATH@ -lgdbm @LIBS@
+GSDLOS = @gsdlos@
+INSTALL = @INSTALL@
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CCFLAGS)
+CPPCOMPILE = $(CPP) -c $(DEFS) $(INCLUDES) $(CCFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+CPPLINK = $(CPP) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CPPCOMPILE) $< 
+ 
+
+HEADERS = 
+
+SOURCES = db2txt.cpp
+
+OBJECTS = db2txt.o
+
+EXEC    = db2txt
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	$(INSTALL) -d ../../bin/$(GSDLOS)
+	$(INSTALL) -m 755 -s $(EXEC) ../../bin/$(GSDLOS)
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC)
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+DB2TXT_OBJS = db2txt.o
+
+db2txt: $(DB2TXT_OBJS) $(DPLIBS)
+	$(CPPLINK) $(DB2TXT_OBJS) $(LIBS) 
Index: /tags/gsdl-2_61-distribution/gsdl/src/db2txt/db2txt.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/db2txt/db2txt.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/db2txt/db2txt.cpp	(revision 10506)
@@ -0,0 +1,99 @@
+/**********************************************************************
+ *
+ * db2txt.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifdef __WIN32__
+#include "autoconf.h"
+#include "systems.h"
+#include "gdbmconst.h"
+#include "gdbm.h"
+
+#else
+#include <gdbm.h>
+#endif
+
+#include "gsdlconf.h"
+#include <stdlib.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#include <iostream.h>
+#else
+#include <iostream>
+#endif
+
+// use the standard namespace
+#if !defined (GSDL_NAMESPACE_BROKEN)
+#if defined(GSDL_USE_OBJECTSPACE)
+using namespace ospace::std;
+#else
+using namespace std;
+#endif
+#endif
+
+void print_usage (char *program_name) {
+  cerr << "usage: " << program_name << " database-name\n\n";
+}
+
+
+int main (int argc, char *argv[]) {
+  int block_size = 0, i;
+  GDBM_FILE dbf;
+  datum key, value;
+      
+  // sanity check
+  if (argc != 2) {
+    print_usage (argv[0]);
+    exit (0);
+  }
+  
+  // open the database
+#ifdef __WIN32__
+  dbf = gdbm_open (argv[1], block_size, GDBM_READER, 00664, NULL, 0);
+#else
+  dbf = gdbm_open  (argv[1], block_size, GDBM_READER, 00664, NULL);
+#endif
+  if (dbf == NULL) {
+    cerr << "couldn't create " << argv[1] << "\n";
+    exit (0);
+  }
+
+  key = gdbm_firstkey (dbf);
+  while (key.dptr != NULL) {
+    cout << "[";
+    for (i = 0; i < key.dsize; ++i)
+      cout << key.dptr[i];
+    cout << "]\n";
+    value = gdbm_fetch (dbf, key);
+    for (i = 0; i < value.dsize; ++i)
+      cout << value.dptr[i];
+    cout << "\n----------------------------------------------------------------------\n";
+    key = gdbm_nextkey (dbf, key);
+    delete value.dptr;
+  }
+  
+  gdbm_close (dbf);
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/db2txt/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/db2txt/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/db2txt/win32.mak	(revision 10506)
@@ -0,0 +1,78 @@
+###########################################################################
+#
+# win32 makefile -- db2txt
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..\..
+USE_STLPORT = 0
+STLPATH = "$(GSDLHOME)\packages\windows\stlport\stlport"
+
+AR = lib
+CC = cl
+CPPFLAGS = 
+LDFLAGS =
+
+DEFS = -D__WIN32__ -DHAVE_CONFIG_H
+INCLUDES = -I"$(GSDLHOME)\src\db2txt" -I"$(GSDLHOME)\lib" -I"$(GSDLHOME)\packages\mg\lib" \
+	   -I"$(GSDLHOME)\packages\windows\gdbm\gdbm"
+!IF $(USE_STLPORT)
+DEFS=$(DEFS) -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = $(INCLUDES) -I$(STLPATH)
+!ENDIF
+
+LIBS = "$(GSDLHOME)\packages\mg\lib\unitool.obj" "$(GSDLHOME)\lib\gsdllib.lib" \
+       "$(GSDLHOME)\packages\windows\gdbm\gdbm\gdbm.lib"
+
+COMPILE = $(CC) -c -GX $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $<
+
+ANSI2KNR = 
+o = .obj
+e = .exe
+
+HEADERS = 
+
+SOURCES = db2txt.cpp
+
+OBJECTS = db2txt$o
+
+EXEC = db2txt$e
+
+all : $(EXEC)
+
+install: $(EXEC)
+	if NOT EXIST "$(GSDLHOME)\bin\windows" mkdir "$(GSDLHOME)\bin\windows"
+	copy $(EXEC) "$(GSDLHOME)\bin\windows"
+
+clean:
+	del *$o
+	del $(EXEC)
+
+db2txt$e: $(OBJECTS) $(LIBS)
+	  $(LINK) $(OBJECTS) $(LIBS)
Index: /tags/gsdl-2_61-distribution/gsdl/src/getpw/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/getpw/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/getpw/Makefile.in	(revision 10506)
@@ -0,0 +1,83 @@
+###########################################################################
+#
+# Makefile -- Makefile for getpw
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+ 
+AR = ar
+CC = @CC@
+CFLAGS = @CFLAGS@
+CXX = @CXX@
+CXXFLAGS = @CXXFLAGS@ 
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+# need to include config.h
+INCLUDES = -I../.. -I../../lib
+LDFLAGS = @LDFLAGS@
+DPLIBS = 
+LIBS = @LIBS@
+GSDLOS = @gsdlos@
+INSTALL = @INSTALL@
+ 
+LINK = $(CXX) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(CC) -c $(DEFS) $(INCLUDES) $(CFLAGS) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CXX) -c $(DEFS) $(INCLUDES) $(CXXFLAGS) $< 
+
+HEADERS = 
+
+SOURCES = getpw.cpp
+
+OBJECTS = getpw.o
+
+EXEC    = getpw
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	$(INSTALL) -d ../../bin/$(GSDLOS)
+	$(INSTALL) -m 755 -s $(EXEC) ../../bin/$(GSDLOS)
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC)
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+GETPW_OBJS = getpw.o
+
+getpw: $(GETPW_OBJS) $(DPLIBS)
+	$(LINK) $(GETPW_OBJS) $(LIBS) 
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/getpw/getpw.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/getpw/getpw.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/getpw/getpw.cpp	(revision 10506)
@@ -0,0 +1,93 @@
+/**********************************************************************
+ *
+ * getpw.cpp -- 
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the 
+ * University of Waikato, New Zealand.
+ *
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **********************************************************************/
+
+#define _XOPEN_SOURCE 1
+/* following is for solaris */
+#define _XOPEN_SOURCE_EXTENDED 1
+
+#include "gsdlconf.h"
+
+// use the standard namespace
+#if !defined (GSDL_NAMESPACE_BROKEN)
+#if defined(GSDL_USE_OBJECTSPACE)
+using namespace ospace::std;
+#else
+using namespace std;
+#endif
+#endif
+
+
+// include crypt
+#if defined(__WIN32__)
+#include "crypt.h"
+#else
+
+#include "config.h"
+#if defined(HAVE_CRYPT_H)
+#include <crypt.h>
+#endif
+
+#if defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+/* we are probably in trouble if we have neither crypt.h or unistd.h,
+   but for now we'll do nothing about it... */
+
+#endif  /* not WIN32 */
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#include <string.h>
+#include <pwd.h>
+
+int main (int argc, char *argv[]) {
+
+  char c[10];
+  while (1) {
+    char *a = getpass("Enter password:");
+    int len = strlen (a);
+    if (len < 3 || len > 8) {
+      cerr << "Password must be between 3 and 8 characters long. Try again\n";
+      continue;
+    }
+    strcpy (c, a);
+    char *b = getpass("Re-enter password:");  
+    if ((strcmp (c, b)) == 0) break;
+    else cerr << "Passwords didn't match. Try again.\n";
+  }
+
+  char *salt = "Tp";
+  char *pw = crypt (c, salt);
+
+  cout << pw << "\n";
+  
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/hashfile/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/hashfile/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/hashfile/Makefile.in	(revision 10506)
@@ -0,0 +1,83 @@
+###########################################################################
+#
+# Makefile -- Makefile for hashfile
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 Rodger McNab, Stefan Boddie
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)Makefile.in	1.3 16 Mar 1994
+#
+###########################################################################
+
+ 
+AR = ar
+CXX = @CXX@
+CXXFLAGS = @CXXFLAGS@
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INCLUDES = -I../../lib
+LDFLAGS = @LDFLAGS@
+LIBS = ../../lib/gsdllib.a
+GSDLOS = @gsdlos@
+INSTALL = @INSTALL@
+ 
+COMPILE = $(CXX) -c $(DEFS) $(INCLUDES) $(CCFLAGS)
+LINK = $(CXX) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(COMPILE) $< 
+ 
+
+HEADERS = 
+
+SOURCES = hashfile.cpp
+
+OBJECTS = hashfile.o
+
+EXEC    = hashfile
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	$(INSTALL) -d ../../bin/$(GSDLOS)
+	$(INSTALL) -m 755 -s $(EXEC) ../../bin/$(GSDLOS)
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC)
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+HASHFILE_OBJS = hashfile.o
+
+hashfile: $(HASHFILE_OBJS) $(LIBS)
+	$(LINK) $(HASHFILE_OBJS) $(LIBS) 
Index: /tags/gsdl-2_61-distribution/gsdl/src/hashfile/hashfile.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/hashfile/hashfile.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/hashfile/hashfile.cpp	(revision 10506)
@@ -0,0 +1,263 @@
+/**********************************************************************
+ *
+ * hashfile.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include <stdio.h>
+
+#define MAXNUMLEN  100   // bytes
+
+
+// The number class is used to store very long unsigned integers.
+// The least significant of each number is stored first. Numbers can 
+// be no longer than MAXNUMLEN bytes long. A number with length=0
+// is considered to be equal to 0. There should be no extra zeros
+// at the front of the number.
+
+struct number {
+  unsigned int len;
+  unsigned char num[MAXNUMLEN];
+
+  number () {len = 0;}
+};
+
+
+// evaluates a = a + b
+// a and b can be the same number
+void my_inc (number &a, number &b) {
+  unsigned int carry = 0;
+  unsigned int num = 0;
+  unsigned int i = 0;
+
+  while ((carry || (i < a.len) || (i < b.len)) && (i < MAXNUMLEN)) {
+    num = carry;
+    if (i < a.len) num += a.num[i];
+    if (i < b.len) num += b.num[i];
+
+    if (num >= 256) {
+      num -= 256; // assumes that each number in the list < 256
+      carry = 1;
+    } else {
+      carry = 0;
+    }
+    a.num[i] = (unsigned char)num;
+
+    ++i;
+  }
+
+  a.len = i;
+}
+
+
+// evaluates a = a - b if a >= b
+// returns true if the subtraction was possible
+int my_ifpos_dec (number &a, number &b) {
+  int carry = 0;
+  int num = 0;
+  int i = 0;
+  unsigned int len = 0; // the last non-zero digit
+
+  // make sure a >= b
+  if (b.len > a.len) return 0;
+  if (b.len == a.len) {
+    i = a.len - 1;
+    while (i >= 0) {
+      if (a.num[i] > b.num[i]) break;
+      if (a.num[i] < b.num[i]) return 0;
+      --i;
+    }
+  }
+
+  unsigned int j = 0;
+  len = 0;
+  while ((j < a.len) || (j < b.len)) {
+    num = -carry;
+    if (j < a.len) num += a.num[j];
+    if (j < b.len) num -= b.num[j];
+
+    if (num < 0) {
+      num += 256; // assumes each number in the list < 256
+      carry = 1;
+    } else {
+      carry = 0;
+    }
+
+    a.num[j] = (unsigned char) num;
+    
+    ++j;
+    if (num != 0) len = j;
+  }
+
+  a.len = len;
+
+  if (carry) {
+    // panic, this should NOT happen
+    fprintf (stderr, "panic: error in my_ifpos_dec\n");
+  }
+
+  return 1;
+}
+
+
+char *my_convert_num (number &a) {
+  char *result = new char[(a.len*2)+1];
+  int i,len;
+  char convert[16] = {'0','1','2','3','4','5','6','7',
+		      '8','9','a','b','c','d','e','f'};
+
+  // zero might be a special case
+  if (a.len == 0) {
+    result[0] = '0';
+    result[1] = '\0';
+    return result;
+  }
+
+  for (i=a.len-1, len=0; i >= 0; --i) {
+    result[len++] = convert[a.num[i]/16];
+    result[len++] = convert[a.num[i]%16];
+  }
+  result[len] = '\0';
+
+  return result;
+}
+
+
+
+// create a hash string from the contents of a file.
+//
+// The file is treated as a large base 256 number (each char is a digit),
+// and the hash value is the remainder when this number is divided by a
+// very large prime.
+//
+// PROBLEM: This is a flawed hash function because the rightmost (highest)
+// value in remainder is more likely to be a "1" than it is to be any other
+// number.  
+//
+// EVIDENCE: About 50% of the files in any GSDL directory have a hash code
+// that starts with 01* which implies (based on the my_convert_num function)
+// that the rightmost "digit" of the remainder = z such that (z % 16 = 0)
+// and (z / 16 = 1) which means (z = 1).
+//
+// MAJOR REASON: suppose our prime number was 19.  Then, if we have a 
+// reasonably random distribution of numbers for which we are going to 
+// calculate (N % 19), we expect to get a roughly uniform distribution
+// of remainders where the possible values are 0, 1, 2, 3... 18.  The
+// problem is that 9 out of the 19 possible values (10,11... 18) start
+// with the digit 1.  Thus our hascode will start with "01".
+//
+// ANOTHER PROBLEM: Characters in the file are read one at a time; after each 
+// one is read it is prepended to the remainder, then the remainder is
+// recalculated on the string thus far seen.  I am sure the math here 
+// is wrong - if I try calculating (111 mod 7) by the same algorithm, it
+// simply does nor work.
+//
+// ANOTHER POSSIBLE PROLEM: Each character from the file is read into 
+// remainder at the most significant end, and when that character
+// is a zero you get a number like "01" which would be considered 
+// larger than a number like "8" because it is longer (two  digits
+// instead of 1).  
+//
+// These comments added by Gordon Paynter (gwp@cs.waikato.ac.nz) in
+// June 2000.  I didn't write any code, however.
+
+char *hashfile (char *filename) {
+  FILE *infile = (FILE *)NULL;
+  int i;
+
+  number primepow[8];
+  number pow;
+  number remainder;
+  unsigned char c;
+
+  // our prime number (618970019642690137449562111)
+  pow.num[0] = 255;  pow.num[1] = 255;
+  pow.num[2] = 255;  pow.num[3] = 255;
+  pow.num[4] = 255;  pow.num[5] = 255;
+  pow.num[6] = 255;  pow.num[7] = 255;
+  pow.num[8] = 255;  pow.num[9] = 255;
+  pow.num[10] = 255; pow.num[11] = 1;
+  pow.len = 12;
+
+  // calculate 8 multiples of the prime number.
+  // These are used to find the remainder using only subtraction operations
+  for (i=0; i<8; ++i) {
+    primepow[i] = pow;
+    my_inc (pow, pow);
+  }
+
+  // The "remainder" after division by the prime.  Our result.
+  remainder.len = 0;
+
+  // open the file
+  infile = fopen (filename, "rb");
+  if (infile == NULL) {
+    return (char *)NULL;
+  }
+  c = (unsigned char)fgetc(infile);
+  
+  while (!feof (infile)) {
+
+    // make sure the remainder has not grown too large
+    if (remainder.len == MAXNUMLEN-1) {
+      fprintf (stderr, "ERROR - number overflow\n");
+      return (char *)NULL;
+    }
+
+    // remainder = remainder * 256 + c
+    for (i=remainder.len; i>0; --i) {
+      remainder.num[i] = remainder.num[i-1];
+    }
+    remainder.num[0] = c;
+    if (remainder.len > 0 || c != 0) remainder.len = remainder.len+1;
+    
+    // remainder = (remainder % large-prime-number)
+    for (i=7; i>=0; --i) {
+      my_ifpos_dec (remainder, primepow[i]);
+    }
+
+    // read a new character from the file
+    c = (unsigned char)fgetc(infile);
+  }
+
+  fclose (infile);
+
+  return my_convert_num (remainder);
+}
+
+
+int main (int argc, char *argv[]) {
+  int i;
+  char *result;
+
+  for (i = 1; i < argc; ++i) {
+    result = hashfile (argv[i]);
+    if (result == NULL) {
+      printf ("ERROR - could not process %s\n", argv[i]);
+    } else {
+      printf ("%s: %s\n", argv[i], result);
+      delete [] result;
+    }
+  }
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/hashfile/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/hashfile/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/hashfile/win32.mak	(revision 10506)
@@ -0,0 +1,69 @@
+###########################################################################
+#
+# win32 makefile -- hashfile
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+ 
+GSDLHOME = ..\..
+
+AR = lib
+CC = cl
+CPPFLAGS = 
+DEFS = -DHAVE_CONFIG_H -D__WIN32__
+INCLUDES = -I"$(GSDLHOME)\src\hashfile"
+LIBS =
+
+COMPILE = $(CC) -c -GX $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $<
+
+ANSI2KNR = 
+o = .obj
+e = .exe
+ 
+HEADERS = 
+
+SOURCES = hashfile.cpp
+
+OBJECTS = hashfile$o
+
+EXEC = hashfile$e
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	if NOT EXIST "$(GSDLHOME)\bin\windows" mkdir "$(GSDLHOME)\bin\windows"
+	copy $(EXEC) "$(GSDLHOME)\bin\windows"
+
+clean:
+	del *$o
+	del $(EXEC)
+
+HASHFILE_OBJS = hashfile$o
+
+hashfile$e: $(HASHFILE_OBJS) $(LIBS)
+	    $(LINK) $(HASHFILE_OBJS) $(LIBS)
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/CURL.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/CURL.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/CURL.java	(revision 10506)
@@ -0,0 +1,660 @@
+package org.nzdl.gsdl.GsdlCollageApplet;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/** Examines html pages and extracts all the images and links */
+public class CURL {
+
+    private boolean url_valid = true;
+    private InputStream input = null;
+    private int peek_value = -1;
+    private String buffer = "";
+    private URL url = null;
+    private Vector href_links = null;
+    private Vector src_links = null;
+    private Vector link_links = null;
+    private Vector background_links = null;
+
+    /** Starts processing the given url for images and links
+     *  @param url_str The url to examine */
+    public CURL(String url_str) {
+	href_links = new Vector();
+	src_links = new Vector();
+	link_links = new Vector();
+	background_links = new Vector();
+
+	try {
+	    url = new URL(url_str);
+	    input = url.openStream();
+	} 
+	catch (MalformedURLException e) {
+	    url_valid = false;
+	} 
+	catch (IOException e) {
+	    url_valid = false;
+	}
+    }
+
+    /** Checks that a valid connection to the url has been made */
+    public boolean connected_ok()
+    {
+	return url_valid;
+    }
+
+    /** Gets any href links from this url
+     *  @return Vector of href links */
+    public Vector getHrefLinks() {
+	return href_links;
+    }
+    /** Gets any source links from this url
+     *  @return Vector of source links */
+    public Vector getSrcLinks() {
+	return src_links;
+    }
+    /** Gets any other links from this url
+     *  @return Vector of other links */
+    public Vector getLinkLinks() {
+	return link_links;
+    }
+    /** Gets any background links from this url
+     *  @return Vector of background links */
+    public Vector getBackgroundLinks() {
+	return background_links;
+    }
+    
+    /** Gets the url currently being processed */
+    public URL getURL() {
+	return url;
+    }
+    /** Checks that the content of the url is in html */
+    public boolean isHTML() {
+	String content_type = guessContentType(url.toString());
+
+	if(content_type.startsWith("text/html")) {
+	    return true;
+	}
+	return false;
+    }
+    
+    /** Reads a value from the buffer
+     *  @return Value read if successful and -1 if not */
+    public int read() {
+	int value = -1;
+	if(isHTML()) {
+	    if(buffer.length() == 0) {
+		refill();
+	    }
+	    if(buffer.length() != 0) {
+		value = getBuffer();
+	    }
+	} else {
+	    value = getRaw();
+	}
+	return value;
+    }
+    /** Reads the entire URL */
+    public void readAll() {
+	int value;
+	while((value = read()) != -1) {
+	}
+    }
+    
+    // Gets the head of the buffered buffer.
+    private int getBuffer() {
+	if(buffer.length() > 0) {
+	    int value = buffer.charAt(0);
+	    buffer = buffer.substring(1, buffer.length());
+	    return value;
+	} else {
+	    System.err.println("Called getRaw on an empty string");
+	    return -1;
+	}
+    }
+    // Gets the head of the raw buffer.
+    private int getRaw() {
+	int value = -1;
+	if(peek_value != -1) {
+	    value = peek_value;
+	    peek_value = -1;
+	} 
+	else {
+	    try {
+		value = input.read();
+	    } catch (Exception e) {
+		e.printStackTrace();
+	    }
+	}
+	return value;
+    }
+    
+    private int peekRaw() {
+	if(peek_value == -1) {
+	    peek_value = getRaw();
+	}
+	return peek_value;
+    }
+    
+    // Refills the buffered buffer with the next tag or non-tag block
+    // The tag is checked for urls. Note a tag is taken to be < .. > or
+    // < .. < so comments are supported, but comment blocks are still
+    // scanned.
+    private void refill() {
+	int value = getRaw();
+	if(value != -1) {
+	    if(value == '<') {
+		//System.err.println("Parsing a tag starting " + (char)value);
+		// Add opening < to buffer
+		setBuffer(value);
+		String tag = "";
+		value = getRaw();
+		while(value != -1 && peekRaw() != '<' && value != '>') {
+		    //System.err.println("Read a " + (char)value);
+		    tag = tag + (char) value;
+		    value = getRaw();
+		}
+		//System.err.println("Read a " + (char)value);
+		//tag = smartLower(tag);
+		tag = findURL(tag);
+		buffer = buffer + tag;
+		// Add closing > to buffer
+		setBuffer(value);
+		//System.err.println("Finished tag");
+	    } else {
+		//System.err.println("Parsing content");
+		//System.err.println("Value = " + value + " = '" + (char)value + "'");
+		while(value != -1 && value != '<') {
+		    //System.err.println("Read a '" + (char)value + "'");
+		    setBuffer(value);
+		    value = getRaw();
+		}
+		// If we've accidently read the '<' push it back in the stream by
+		// setting peek_value to value. Since the peek_value will be returned
+		// on the next read this has the desired effect.
+		if(value == '<') {
+		    peek_value = value;
+		}
+		//System.err.println("Read " + buffer);
+		//System.err.println("Finished Content");
+	    }
+	}
+    }
+    
+    // Sets the tail of the buffered buffer.
+    private void setBuffer(int value) {
+	buffer = buffer + (char) value;
+    }
+    
+    private String smartLower(String tag) {
+	boolean lower = true;
+	String new_tag = "";
+	for(int i = 0; i < tag.length(); i++) {
+				// Disable case lowering for value tags (bound by "")
+	    if (tag.charAt(i) == '"') {
+		if(lower) {
+		    lower = false;
+		} else {
+		    lower = true;
+		}
+	    }
+				// Lower everything else
+	    if(lower) {
+		new_tag = new_tag + Character.toLowerCase(tag.charAt(i));
+	    } else {
+		new_tag = new_tag + tag.charAt(i);
+	    }
+	}
+	return new_tag;
+    }
+    
+    private final static int GROUND           = 0;
+    private final static int COMMENT          = 5;
+    private final static int COMMENT_DASH     = 6;
+    private final static int COMMENT_FINAL    = 7;
+    private final static int H                = 11;
+    private final static int HR               = 12;
+    private final static int HRE              = 13;
+    private final static int HREF             = 14;
+    private final static int HREF_EQUAL       = 15;
+    private final static int HREF_Q           = 16;
+    private final static int HREF_NQ          = 17;
+    private final static int HREF_FINAL       = 18;
+    private final static int S                = 23;
+    private final static int SR               = 24;
+    private final static int SRC              = 25;
+    private final static int SRC_EQUAL        = 26;
+    private final static int SRC_Q            = 27;
+    private final static int SRC_NQ           = 28;
+    private final static int SRC_FINAL        = 29;
+    private final static int L                = 67;
+    private final static int LI               = 68;
+    private final static int LIN              = 69;
+    private final static int LINK             = 70;
+    private final static int LINK_QUOTE       = 72;
+    private final static int LINK_H           = 73;
+    private final static int LINK_HR          = 74;
+    private final static int LINK_HRE         = 75;
+    private final static int LINK_HREF        = 76;
+    private final static int LINK_EQUAL       = 77;
+    private final static int LINK_Q           = 78;
+    private final static int LINK_NQ          = 79;
+    private final static int LINK_FINAL       = 80;
+    private final static int B                = 85;
+    private final static int BA               = 86;
+    private final static int BAC              = 87;
+    private final static int BACK             = 88;
+    private final static int BACKG            = 89;
+    private final static int BACKGR           = 90;
+    private final static int BACKGRO          = 91;
+    private final static int BACKGROU         = 92;
+    private final static int BACKGROUN        = 93;
+    private final static int BACKGROUND       = 94;
+    private final static int BACKGROUND_EQUAL = 95;
+    private final static int BACKGROUND_Q     = 96;
+    private final static int BACKGROUND_NQ    = 97;
+    private final static int BACKGROUND_FINAL = 98;
+    private final static int FINAL            = 99;
+    
+    // Run the finite-state machine on a buffer-load.
+    private String findURL(String tail) {
+	int state = GROUND;
+	String head = "";
+	String url_str = "";
+	// Sift through the tag for urls
+	while(tail.length() > 0 && state != BACKGROUND_FINAL && state != COMMENT_FINAL && state != HREF_FINAL && state != LINK_FINAL && state != SRC_FINAL) {
+	    char ch = tail.charAt(0);
+	    String sch = "" + ch;
+	    sch = sch.toLowerCase();
+	    char lch = sch.charAt(0);
+	    tail = tail.substring(1);
+	    switch (state) {
+		// Initial state.
+	    case GROUND:
+		switch (lch) {
+		case '!': state = COMMENT; break;
+		case 'B': case 'b': state = B; break;
+		case 'H': case 'h': state = H; break;
+		case 'L': case 'l': state = L; break;
+		case 'S': case 's': state = S; break;
+		}
+		head = head + ch;
+		break;
+		// A possible comment
+	    case COMMENT:
+		switch(lch) {
+		case '-': state = COMMENT_DASH; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case COMMENT_DASH:
+		switch(lch) {
+		case '-': state = COMMENT_FINAL; break; // skip comments
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+		// A possible href
+	    case H:
+		switch(lch) {
+		case 'R': case 'r': state = HR; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case HR:
+		switch(lch) {
+		case 'E': case 'e': state = HRE; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case HRE:
+		switch(lch) {
+		case 'F': case 'f': state = HREF; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case HREF:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r': break; // Skip blanks
+		case '=': state = HREF_EQUAL; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case HREF_EQUAL:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r': break; // Skip blanks
+		case '\'': case '\"': state = HREF_Q; break;
+		default: state = HREF_NQ; break;
+		}
+		if(state == HREF_NQ) {
+		    url_str = url_str + ch;
+		} else {
+		    head = head + ch;
+		}
+		break;
+	    case HREF_NQ:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r':
+		    state = HREF_FINAL;
+		    tail = ch + tail;
+		    break;
+		default: url_str = url_str + ch; break;
+		}
+		break;
+	    case HREF_Q:
+		switch(lch) {
+		case '\'': case '\"':
+		    state = HREF_FINAL;
+		    tail = ch + tail;
+		    break;
+		default: url_str = url_str + ch; break;
+		}
+		break;
+		// A possible src
+	    case S:
+		switch(lch) {
+		case 'R': case 'r': state = SR; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case SR:
+		switch(lch) {
+		case 'C': case 'c': state = SRC; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case SRC:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r': break; // Skip blanks
+		case '=': state = SRC_EQUAL; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case SRC_EQUAL:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r': break; // Skip spaces
+		case '\'': case '\"': state = SRC_Q; break;
+		default: state = SRC_NQ; break;
+		}
+		if(state == SRC_NQ) {
+		    url_str = url_str + ch;
+		} else {
+		    head = head + ch;
+		}
+		break;
+	    case SRC_NQ:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r':
+		    state = SRC_FINAL;
+		    tail = ch + tail;
+		    break;
+		default: url_str = url_str + ch; break;
+		}
+		break;
+	    case SRC_Q:
+		switch(lch) {
+		case '\'': case '\"':
+		    state = SRC_FINAL;
+		    tail = ch + tail;
+		    break;
+		default: url_str = url_str + ch; break;
+		}
+		break;
+		// A possible link-src combo
+	    case L:
+		switch(lch) {
+		case 'I': case 'i': state = LI; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case LI:
+		switch(lch) {
+		case 'N': case 'n': state = LIN; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case LIN:
+		switch(lch) {
+		case 'K': case 'k': state = LINK; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case LINK:
+		switch(lch) {
+		case 'H': case 'h': state = LINK_H; break;
+		default: state = LINK; break;
+		}
+		head = head + ch;
+		break;
+	    case LINK_H:
+		switch(lch) {
+		case 'R': case 'r': state = LINK_HR; break;
+		default: state = LINK; break;
+		}
+		head = head + ch;
+		break;
+	    case LINK_HR:
+		switch(lch) {
+		case 'E': case 'e': state = LINK_HRE; break;
+		default: state = LINK; break;
+		}
+		head = head + ch;
+		break;
+	    case LINK_HRE:
+		switch(lch) {
+		case 'F': case 'f': state = LINK_HREF; break;
+		default: state = LINK; break;
+		}
+		head = head + ch;
+		break;
+	    case LINK_HREF:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r': break; // Skip blanks
+		case '=': state = LINK_EQUAL; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case LINK_EQUAL:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r': break; // Skip blanks
+		case '\'': case '\"': state = LINK_Q; break;
+		default: state = LINK_NQ; break;
+		}
+		if(state == LINK_NQ) {
+		    url_str = url_str + ch;
+		} else {
+		    head = head + ch;
+		}
+		break;
+	    case LINK_NQ:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r':
+		    state = LINK_FINAL;
+		    tail = ch + tail;
+		    break;
+		default: url_str = url_str + ch; break;
+		}
+		break;
+	    case LINK_Q:
+		switch(lch) {
+		case '\'': case '\"':
+		    state = LINK_FINAL;
+		    tail = ch + tail;
+		    break;
+		default: url_str = url_str + ch; break;
+		}
+		break;
+		// A possible background
+	    case B:
+		switch(lch) {
+		case 'A': case 'a': state = BA; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case BA:
+		switch(lch) {
+		case 'C': case 'c': state = BAC; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case BAC:
+		switch(lch) {
+		case 'K': case 'k': state = BACK; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case BACK:
+		switch(lch) {
+		case 'G': case 'g': state = BACKG; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case BACKG:
+		switch(lch) {
+		case 'R': case 'r': state = BACKGR; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case BACKGR:
+		switch(lch) {
+		case 'O': case 'o': state = BACKGRO; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case BACKGRO:
+		switch(lch) {
+		case 'U': case 'u': state = BACKGROU; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case BACKGROU:
+		switch(lch) {
+		case 'N': case 'n': state = BACKGROUN; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case BACKGROUN:
+		switch(lch) {
+		case 'D': case 'd': state = BACKGROUND; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case BACKGROUND:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r': break; // Skip blanks
+		case '=': state = BACKGROUND_EQUAL; break;
+		default: state = GROUND; break;
+		}
+		head = head + ch;
+		break;
+	    case BACKGROUND_EQUAL:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r': break; // Skip blanks
+		case '\'': case '\"': state = BACKGROUND_Q; break;
+		default: state = BACKGROUND_NQ; break;
+		}
+		if(state == BACKGROUND_NQ) {
+		    url_str = url_str + ch;
+		} else {
+		    head = head + ch;
+		}
+		break;
+	    case BACKGROUND_NQ:
+		switch(lch) {
+		case ' ': case '\t': case '\n': case '\r':
+		    state = BACKGROUND_FINAL;
+		    tail = ch + tail;
+		    break;
+		default: url_str = url_str + ch; break;
+		}
+		break;
+	    case BACKGROUND_Q:
+		switch(lch) {
+		case '\'': case '\"':
+		    state = BACKGROUND_FINAL;
+		    tail = ch + tail;
+		    break;
+		default: url_str = url_str + ch; break;
+		}
+		break;
+	    }
+	}
+
+	if(state == HREF_FINAL ) {
+	    try {
+		URL new_url = new URL(url, url_str);
+		href_links.addElement(new_url);
+	    }
+	    catch (Exception e) {
+		e.printStackTrace();
+	    }
+        }
+
+	if(state == SRC_FINAL ) {
+	    try {
+		URL new_url = new URL(url, url_str);
+		src_links.addElement(new_url);
+	    }
+	    catch (Exception e) {
+		e.printStackTrace();
+	    }
+        }
+
+	if(state == LINK_FINAL ) {
+	    try {
+		URL new_url = new URL(url, url_str);
+		link_links.addElement(new_url);
+	    }
+	    catch (Exception e) {
+		e.printStackTrace();
+	    }
+        }
+
+	if(state == BACKGROUND_FINAL ) {
+	    try {
+		URL new_url = new URL(url, url_str);
+		background_links.addElement(new_url);
+	    }
+	    catch (Exception e) {
+		e.printStackTrace();
+	    }
+        }
+
+	return head + url + tail;
+    }
+    
+    static private String guessContentType(String text) {
+	if(text.endsWith("/")) {
+	    return "text/html";
+	} else if (text.endsWith(".html")) {
+	    return "text/html";
+	} else if (text.endsWith(".htm")) {
+	    return "text/html";
+	} else if (text.indexOf("?")>0) {
+	    return "text/html";
+	}
+	return "image/jpeg";
+    }
+    
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/CollageImage.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/CollageImage.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/CollageImage.java	(revision 10506)
@@ -0,0 +1,160 @@
+package org.nzdl.gsdl.GsdlCollageApplet;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.io.*;
+
+/** 
+ *  @author Katrina Edgar
+ *  @author David Bainbridge
+ *
+ *  Data Structure to store an image once it is displayed in the applet.
+ *  This structure remembers the images graphical representation, source url,
+ *  name, width, height, position on the screen and whether or not it has
+ *  previously been displayed. It provides methods to set the dimensions and
+ *  position of the image. It also provides access methods to the translated
+ *  x and y co-ordinates of the image */
+public class CollageImage {
+
+    /** Graphical representation of the image */
+    Image image_        = null;
+    /** Source url of the image */
+    String from_url_    = null;
+    /** Name of the image */
+    String name_        = null;
+    /** Width of the image */
+    int image_x_dim_    = 0;
+    /** Height of the image */
+    int image_y_dim_    = 0;
+    /** Indicates whether or not the image has been drawn on the applet previously */
+    boolean fresh       = true;
+
+    /** Reflects the translation of the image from the origin to its position on the screen */
+    AffineTransform af_ = null;
+    /** Left x co-ordinate */
+    protected int xl_ = 0;
+    /** Top y co-ordinate */
+    protected int yt_ = 0;
+    /** Right x co-ordinate */
+    protected int xr_ = 0;
+    /** Bottom y co-ordinate */
+    protected int yb_ = 0;
+
+    /** Constructs an CollageImage from the three specified parameters
+     *
+     *  @param image The graphical representation of the image
+     *  @param from_url The source url for the image
+     *  @param name The file name of the image */
+    public CollageImage(Image image, String from_url, String name)
+    {
+	image_    = image;
+	from_url_ = from_url;
+	name_     = name;
+    }
+
+    /** Sets the width and height of the image
+     *
+     *  @param x_dim The new width of the image
+     *  @param y_dim The new height of the image */
+    public void setDimensions(int x_dim, int y_dim)
+    {
+	image_x_dim_ = x_dim;
+	image_y_dim_ = y_dim;
+    }
+
+    /** Sets the translation for the image from the origin
+     *  And regenerate the image as the scaled version
+     *
+     *  @param af The AffineTransform translation that has been calculated */
+    public void setAffineTransform(MyAffineTransform af, boolean is_java2_)
+    {	
+	image_x_dim_ = (int) (image_x_dim_ * af.scaleX);
+	image_y_dim_ = (int) (image_y_dim_ * af.scaleY);
+	image_ = image_.getScaledInstance(image_x_dim_, image_y_dim_, Image.SCALE_DEFAULT);
+	
+	if (is_java2_) {
+	    af_ = new AffineTransform();
+	    af_.translate(af.translateX, af.translateY);
+	    af_.scale(1.0, 1.0);
+	
+	    calculate_rect();
+	}
+	else {
+	    double trans_x = af.translateX;
+	    double trans_y = af.translateY;
+	    
+	    xl_ = Math.round((float)trans_x);
+	    xr_ = Math.round((float)(trans_x + image_x_dim_)) -1;
+	    yt_ = Math.round((float)trans_y);
+	    yb_ = Math.round((float)(trans_y + image_y_dim_)) -1; 
+	}
+    }
+
+    public void expand () {
+	
+	// still expands a little too fast... how to fix this?
+	magnify(new Rectangle((int) (xl_ + (image_x_dim_ * 0.000001)),
+			      (int) (yt_ + (image_y_dim_ * 0.000001)),
+			      (int) (image_x_dim_ * 0.999998),
+			      (int) (image_y_dim_ * 0.999998)));
+	
+    }
+    
+    public void magnify(Rectangle border) {
+	
+	double magX = image_x_dim_/(double)border.width;
+	double magY = image_y_dim_/(double)border.height;
+	int x = border.x + border.width/2;
+	int y = border.y + border.height/2;
+	paintImage(x,y,magX, magY);
+    }
+    
+    public void paintImage(int magCenterX, int magCenterY, double magX, double magY){
+	
+	try {
+	    //Point2D mgp = null;
+	    //mgp = af_.inverseTransform((new Point(magCenterX, magCenterY)),(Point)mgp);
+	    //double x = (mgp.getX()*magX)-mgp.getX();
+	    //double y = (mgp.getY()*magY)-mgp.getY();
+	    //scale(-x,-y, magX, magY);
+	}catch (Exception e) {System.out.println(e); }
+    }
+    
+    public void scale(double magOffsetX, double magOffsetY, double magX, double magY){
+	
+	af_.translate(magOffsetX,magOffsetY);
+	af_.scale(magX, magY);
+    }
+    
+    /** Calculates the new image co-ordinates after translation has occurred */
+    protected void calculate_rect()
+    {
+	double trans_x = af_.getTranslateX();
+	double trans_y = af_.getTranslateY();
+
+	xl_ = Math.round((float)trans_x);
+	xr_ = Math.round((float)(trans_x + image_x_dim_)) -1;
+	yt_ = Math.round((float)trans_y);
+	yb_ = Math.round((float)(trans_y + image_y_dim_)) -1; 
+    }
+
+    /** Determines whether a given co-ordinate is inside this image
+     *
+     *  @param x The x co-ordinate
+     *  @param y The y co-ordinate */
+    public boolean inside(int x, int y)
+    {
+	return ((x>=xl_) && (x<=xr_)) && ((y>=yt_) && (y<=yb_));
+    }
+
+    /** Gets the width of the translated image */
+    public double getX() {
+	return af_.getTranslateX();
+    }
+
+    /** Gets the height of the translated image */
+    public double getY() {
+	return af_.getTranslateY();
+    }
+}	
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/Display.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/Display.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/Display.java	(revision 10506)
@@ -0,0 +1,44 @@
+package org.nzdl.gsdl.GsdlCollageApplet;
+
+import java.applet.*;
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.geom.*;
+import java.util.*;
+
+/** 
+ *  @author Katrina Edgar */
+public class Display extends Thread {
+
+    GsdlCollageApplet app_ = null;
+
+     public Display(GsdlCollageApplet app) {
+	super("Display");
+	app_ = app;
+	
+    }
+
+
+    /** Runs display thread by repeatedly calling the next frame,
+     *  waiting for a specified delay period between calls */
+    public void run() {
+	try {
+
+	    System.err.println("Started display thread.");
+
+	    Thread curr_thread = Thread.currentThread();
+	    
+	    while (curr_thread == this) {
+		app_.repaint();
+		// can't make it zero or it hogs the whole processor
+		Thread.sleep(100);
+		curr_thread = Thread.currentThread();
+	    }
+
+	    System.err.println("Stopped display thread.");
+	    
+	} catch (Exception e) {
+	    e.printStackTrace();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/DisplayImages.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/DisplayImages.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/DisplayImages.java	(revision 10506)
@@ -0,0 +1,764 @@
+package org.nzdl.gsdl.GsdlCollageApplet;
+
+import java.applet.*;
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.geom.*;
+import java.util.*;
+
+/** 
+ *  @author Katrina Edgar
+ *  @author David Bainbridge
+ *
+ *  Retrieves images from the download thread, determines an appropriate position
+ *  for these images onscreen ensuring maximum whitespace coverage and minimal overlap
+ *  when possible. Draws images using advanced image processing techniques when applicable,
+ *  such as fading the edges of an image and discolouring backgrounds. Also re-uses images
+ *  from those that have previously been displayed, or are aging onscreen, in order to
+ *  to create movement when no new images have been downloaded. */
+public class DisplayImages extends Thread {
+
+    /** Decrements the alpha value between adjacent rows on the edge of an image<br>
+     *  Used to fade the edges faster than the rest of the image <br>
+     *  Only used when java2 parameter is true and advanced image processing
+     *  techniques may be applied */
+    static final int FADEVALUE = 3;
+    /** Defines the number of shades of white used to colour the backgrounds of white images <br>
+     *  These colours are used because when several white images appear in the collage
+     *  simultaneously it is difficult to distinguish their edges<br>
+     *  Only used when java2 parameter is true and advanced image processing
+     *  techniques may be applied */
+    static final int NO_OF_COLORS = 7;
+
+    /** Will fire a removal operation when 4 images in the collage overlap a single area */
+    static final int NO_IMAGES_OF_OVERLAP = 4;
+    
+    /** To determine if there are several images overlapped, can remove the
+     *  layers underneath to save time in repainting */
+    boolean overlap = false;
+
+    /** Refers to download thread */
+    DownloadImages download_images_ = null;
+
+    /** Refers to applet */
+    GsdlCollageApplet app_ = null;
+
+    /** Applets width on screen */
+    public static int app_x_dim_  = 0;
+
+    /** Applets height on screen */
+    public static int app_y_dim_  = 0;
+    
+    /** Background colour of the applet screen */
+    protected Color bgcolor_        = null;
+
+    /** Indicates whether java2 functionality should be used <br>
+     *  If true will allow advanced image processing techniques to occur, 
+     *  such as fading and colouring using pixel manipulation <br>
+     *  If false, images will maintain an alpha value of 1 (appear solid), 
+     *  newer images will simply be pasted on top of existing images <br> */
+    protected boolean is_java2_     = false;
+
+    /** Holds images currently on display in the applet */
+    protected Vector inuse_    = null;
+
+    /** Holds previously displayed images for re-use */
+    protected Vector notinuse_ = null;
+   
+    protected Image    screen_buffer_    = null;
+    protected Graphics screen_graphic_   = null;
+    protected Image    finished_buffer_  = null;
+    protected Graphics finished_graphic_ = null;
+
+    /** Used to determine where to place new images on the applet to optimize
+     *  whitespace coverage <br>
+     *  A co-ordinate in the applet has a value of zero if it is whitespace,
+     *  one if it is covered by one image, two if it is covered by two images,
+     *  and so on. New images will be placed such that they cover the largest
+     *  area of whitespace (zero valued co-ordinates) */
+    public static int [] [] used_space = null;
+    
+    /** Defines the shades of white used to colour the backgrounds of white images <br>
+     *  These colours are used because when several white images appear in the collage
+     *  simultaneously it is difficult to distinguish their edges<br>
+     *  Only used when java2 parameter is true and advanced image processing
+     *  techniques may be applied */
+    int colorMask [] = {0xF8FFFF, 0xFFF8FF, 0xFFFFF8, 0xF8F8FF, 0xFFF8F8, 0xF8FFF8, 0xFAFAFA};
+
+    /**
+     *  Starts the display images thread. Initialises variables using parameters and
+     *  static values. Creates the blank applet screen, initialises the used space
+     *  2D array to indicate that there are no images onscreen
+     *
+     *  @param app the applet to display the images on
+     *  @param download_images thread from which to retrieve downloaded images
+     *  @param is_java2 whether advanced image processing techniques should be used
+     *  @param bgcolor the background colour of the applet screen */
+    public DisplayImages(GsdlCollageApplet app, 
+			 DownloadImages download_images, boolean is_java2, Color bgcolor)
+    {
+	super("DisplayImages");
+
+	// parameters saved locally
+	app_             = app;
+	download_images_ = download_images;
+	is_java2_        = is_java2;
+	bgcolor_         = bgcolor;
+
+	inuse_    = new Vector();
+	notinuse_ = new Vector();
+
+	// sets width and height
+	if (is_java2_)
+	{
+	    app_x_dim_  = app_.getWidth();
+	    app_y_dim_  = app_.getHeight();
+	}
+	else
+	{
+	    app_x_dim_  = 645;
+	    app_y_dim_  = 780;
+	}
+
+	// creates initial screen
+	screen_buffer_ = app_.createImage(app_x_dim_, app_y_dim_); 
+	screen_graphic_ = screen_buffer_.getGraphics();
+	screen_graphic_.setColor(bgcolor_);
+	screen_graphic_.fillRect(0,0,app_x_dim_,app_y_dim_);
+	
+	finished_buffer_  = app_.createImage(app_x_dim_, app_y_dim_);
+	finished_graphic_ = finished_buffer_.getGraphics();
+    
+	// initialises used space array to indicate an empty screen
+	used_space = new int [app_x_dim_][app_y_dim_];	
+	for (int n=0; n < app_x_dim_; n++)
+	    for (int m=0; m < app_y_dim_; m++)
+		used_space[n][m] = 0;
+
+    }
+
+    /** Determines what the user has clicked on in the applet, either an image or whitespace
+     *  @param x the x co-ordinate of the mouse
+     *  @param y the y co-ordinate of the mouse
+     *  @return the image that the user has clicked on or null if the user has clicked whitespace */
+ 
+   public synchronized CollageImage clickedOnImage(int x, int y)
+    {
+	if (app_.verbosity() > 1)
+	{
+	    System.err.print("Checking for clicked on image: ("+x+","+y+")");
+	}
+
+	int no_images = inuse_.size() - 1;
+	// checks from last image down, as last images place will be at the top of the collage
+	for (int i= no_images; i >= 0; i--)
+	{
+	    CollageImage collage_image = (CollageImage)inuse_.elementAt(i);
+	    if (collage_image.inside(x,y))
+	    {
+		return collage_image;
+	    }
+	}
+	// no image at these co-ordinates, just whitespace
+	return null;
+    }
+
+    /** Generates the images onscreen.
+     *  Loops through the vector of currently displayed images and draws each one in turn.
+     *  If the image is being drawn for the first time, its position will be determined
+     *  and its alpha channel set as solid prior to drawing. <br>
+     *  Drawing of the image will depend on whether or not java2 is enabled. If so then
+     *  the image will be processed so that fading occurs with age, so that the edges 
+     *  fade faster than the rest of the image and so that white images are slightly 
+     *  discoloured to allow distinction. If java2 is not enabled, new images will simply
+     *  be pasted on top of existing images without any special effects occuring<br>
+     *  This function also deletes old images. If java2 is enabled then images are deleted
+     *  once they have faded to a suitably low alpha value. If java2 is not enabled then
+     *  images will be removed once there are greater than 25 images onscreen, to ensure
+     *  the applet cannot be overloaded. */
+    public synchronized void display_collage() 
+    {
+	// get the number of images currently in the collage
+	final int no_images = inuse_.size();
+
+	// if there is nothing new to add
+	if (no_images==0) return;
+	
+	
+	// otherwise need to re-generate images
+	if (app_.verbosity() > 3)
+	{
+	    System.err.print("Regenerating images:");
+	}
+	
+	// get each image currently onscreen inturn
+	for (int i=0; i<no_images; i++)
+	{
+	    CollageImage collage_image = (CollageImage)inuse_.elementAt(i);
+
+	    Image image = collage_image.image_;
+	    // images x and y dimensions
+	    int image_x_dim = image.getWidth(app_);
+	    int image_y_dim = image.getHeight(app_);
+
+	    int status = app_.checkImage(image,app_);
+
+	    if ((image_x_dim>0) && (image_y_dim>0))
+	    {
+		// the first time the image is painted, determine its position and size
+		if (collage_image.fresh == true)
+		    {
+			// first time => randomly place doc
+			collage_image.setDimensions(image_x_dim,image_y_dim);
+			
+			// places and sizes the image
+			MyAffineTransform af = new MyAffineTransform(image_x_dim,image_y_dim);
+			
+			// sets location & size of collage image
+			collage_image.setAffineTransform(af, is_java2_);
+			
+			if (is_java2_) {
+			    collage_image.image_ 
+				= restoreAlpha(collage_image.image_, 0, 0, 
+					       collage_image.image_x_dim_, collage_image.image_y_dim_); 
+			}
+			
+			
+		    }
+		
+		// advanced image processing may be used
+		if (is_java2_)
+		{
+		    // conducts fading and colouring of image
+		    Image img = handlepixels(collage_image.image_, 0, 0, collage_image.image_x_dim_, 
+					     collage_image.image_y_dim_, i, collage_image.fresh ); 
+		    collage_image.image_ = img;
+		   
+		}
+		if (collage_image.fresh) {
+		    collage_image.fresh = false;
+		}
+		   
+	    }
+	    else {
+		if (app_.verbosity()>=3) {
+		    System.err.println("  Image ["+i+"] not ready yet!");
+		}
+	    }
+	    //finished_graphic_.drawImage(screen_buffer_,0,0,app_);
+	
+	}	
+	
+	// draws the finished image onscreen
+	finished_graphic_.drawImage(screen_buffer_,0,0,app_);
+	remove_old_images();
+    }
+
+    /** loops through removing oldest images and reduces number of images if excessive overlap is occuring */
+    synchronized void remove_old_images() {
+
+	// loops through removing oldest images that have almost faded completely
+	// and restricting the size of a simple collage to 25 images
+	int i=0;
+	while (i<inuse_.size())
+	{
+	    CollageImage collage_image = (CollageImage)inuse_.elementAt(i);
+	    
+	    // if we remove when images have faded too much
+	    if (is_java2_) {
+		if (checkFaded(collage_image.image_, 0, 0, collage_image.image_x_dim_, collage_image.image_y_dim_) || overlap)
+		    {
+			overlap = false;
+
+			CollageImage removed_image = (CollageImage)inuse_.elementAt(i);
+			inuse_.removeElementAt(i);
+
+			// restores alpha channel to represent a solid image
+			Image img = restoreAlpha(removed_image.image_, 0, 0, removed_image.image_x_dim_, removed_image.image_y_dim_); 
+			
+			// indicates space for this image is no longer used
+			for (int n = removed_image.xl_; n < (removed_image.xl_ + removed_image.image_x_dim_); n++)
+			    for (int m = removed_image.yt_; m < (removed_image.yt_ + removed_image.image_y_dim_); m++)
+				if(used_space[n][m] != 0) {
+				    used_space[n][m]--;
+				    if (used_space[n][m] > NO_IMAGES_OF_OVERLAP)
+					overlap = true;
+				}
+
+			// sets the image as fresh and adds it to the vector of images previously seen
+			removed_image.image_ = img;
+			removed_image.fresh = true;
+			notinuse_.addElement(removed_image);
+		    }
+		else {
+		    i++;
+		}
+	    }
+	    // if we remove to prevent too many images being displayed simultaneously
+	    else {
+		if (inuse_.size() > 25 || overlap) {
+		    overlap = false;
+
+		    CollageImage removed_image = (CollageImage)inuse_.elementAt(i);
+		    inuse_.removeElementAt(i);
+
+		    // indicates space for this image is no longer used
+		    for (int n = removed_image.xl_; n < (removed_image.xl_ + removed_image.image_x_dim_); n++)
+			for (int m = removed_image.yt_; m < (removed_image.yt_ + removed_image.image_y_dim_); m++)
+			    if(used_space[n][m] != 0) {
+				used_space[n][m]--;
+				if (used_space[n][m] > NO_IMAGES_OF_OVERLAP)
+				    overlap = true;
+			    }
+		    
+		    // sets the image as fresh and adds it to the vector of images previously seen
+		    removed_image.fresh = true;
+		    notinuse_.addElement(removed_image);
+		}
+		else {
+		    i++;
+		}
+	    }
+	}
+
+    }
+
+    /** Alters the images currently on display in the applet <br>
+     *  Changes are prioritised in the following way:
+     *  1. If there are images that have been downloaded and are yet to be displayed 
+     *  they will be added to the list of images in use. <br>
+     *  2. Otherwise if there are images that have previously been displayed but
+     *  are not currently on the applet screen, re-use one of these images. <br>
+     *  3. Otherwise if there are any images on screen at all, take the oldest and
+     *  repaint it as the newest. <br>
+     *  Then the collage is asked to display and repaint with the new image set. */
+
+    synchronized void next_frame()
+    {
+	double random = Math.random();
+	
+	// if there is a new image in the downloaded vector
+	if (download_images_.size()>0)
+	{
+	    int position = (int) ((download_images_.size() - 1) * random);
+
+	    // get the image and its associated url (and remove from download area)
+	    DownloadImages.ImageUrlTriple iutriple = download_images_.retrieve(position);
+	    Image image     = iutriple.image();
+	    String from_url = iutriple.url();
+	    String img_name = iutriple.name();
+
+	    // prepare the image for collaging
+	    // app_.prepareImage(image,app_);
+	    CollageImage collage_image = new CollageImage(image,from_url,img_name);
+	    
+	    // add it to the vector of images currently in use
+	    inuse_.addElement(collage_image);	    
+	    
+	    if (app_.verbosity()>=1)
+	    {
+		System.err.println("Adding in a newly downloaded image");
+		if (app_.verbosity()>=2)
+		    {
+			System.err.println("  name="+img_name+", url="+from_url);
+		    }
+
+	    }
+	}
+	// use an image that has already been displayed but is no longer in the collage
+	else if (notinuse_.size()>0)
+	{
+	    int position = (int) ((notinuse_.size() - 1) * random);
+	    Image image;
+
+	    CollageImage collage_image = (CollageImage)notinuse_.elementAt(position);
+	    notinuse_.removeElementAt(position);
+	    inuse_.addElement(collage_image);
+
+	    if (app_.verbosity()>3)
+	    {
+		System.err.println("Re-using an image not on screen");
+	    }
+	}
+	// otherwise repaint the first image as the last image
+	else if (inuse_.size() > 0){
+	    CollageImage removed_image = (CollageImage)inuse_.elementAt(0);
+	    
+	    // empty the picture from the grid
+	    for (int n = removed_image.xl_; n < (removed_image.xl_ + removed_image.image_x_dim_); n++)
+		for (int m = removed_image.yt_; m < (removed_image.yt_ + removed_image.image_y_dim_); m++)
+		    used_space[n][m]--;
+	    
+	    // reset the alpha and add it
+	    removed_image.fresh = true;
+	    
+	    if (is_java2_) {
+		removed_image.image_ = restoreAlpha(removed_image.image_, 0, 0, 
+						    removed_image.image_x_dim_, removed_image.image_y_dim_); 
+	    }
+	    
+	    notinuse_.addElement(removed_image);
+	    inuse_.removeElementAt(0);
+	    
+	    if (app_.verbosity()>=4){
+		System.err.println("Removing oldest image");
+	    }
+	}
+	else{
+	    if (app_.verbosity()>=4)
+		System.err.println("No images in download area");
+	}
+	
+	display_collage();
+    }
+    
+    /** Adjusts the colour and alpha value of an individual pixel <br>
+     *  If the image is being drawn for the first time, the RGB values are
+     *  extracted. If the pixel is close to white (RGB > 250) then an offwhite
+     *  colour is applied to this pixel.
+     *  This is done because when several white images appear in the collage
+     *  simultaneously it is difficult to distinguish their edges. <br>
+     *  This function also fades the alpha value of the pixel as the image ages.
+     *  The alpha value is more heavily decremented as pixels get closer to the
+     *  edge of the image
+     *
+     *  @param pixel the pixel to manipulate
+     *  @param p the position of the image in collage (representative of age)
+     *  @param fresh indicates whether or not the image is being drawn for the first time
+     *  @param edge indicates whether or not this pixel is near the edge of the image
+     *  @param fade the amount by which to fade this pixel
+     *  @return the adjusted pixel as an int */
+    public int handlesinglepixel(int pixel, int p, boolean fresh, boolean edge, int fade) {
+	
+	int newpixel = 0;
+
+        //changes the colour of the picture, only when first drawn
+	//and only if the pixel is close to white
+	if (fresh) {
+	    
+	    int red   = (pixel >> 16) & 0xff;
+	    int green = (pixel >>  8) & 0xff;
+	    int blue  = (pixel      ) & 0xff;
+	    
+	    if (red >= 250 && green >= 250 && blue >= 250) {
+		
+		int c = colorMask[((int) (p%NO_OF_COLORS))];
+
+		red = (c >> 16) & 0xff;
+		green = (c >> 8) & 0xff;
+		blue  = (c) & 0xff;
+	    }
+
+	    newpixel |= (red << 16) & 0x00ff0000;
+	    newpixel |= (green << 8) & 0x0000ff00;
+	    newpixel |= blue & 0x000000ff;
+	}
+
+	else {
+	    newpixel |= pixel & 0x00ffffff;
+	}
+
+	int alpha = (pixel >> 24) & 0xff;
+
+	if (edge) {
+	    // fade the edges more...
+	    alpha = fade;
+	}
+	else if (alpha > 10 && !fresh) {
+	    alpha -= 10;
+	}
+
+	newpixel |= (alpha << 24) & 0xff000000;
+	
+	return (newpixel);
+    }
+    
+    /** Fades and colours the image on a pixel-by-pixel basis <br>
+     *  First it grabs the pixels of the entire image and stores them in a 2D array.
+     *  Then a bound is calculated to indicate the point from which edge
+     *  fading should occur. The position of the bound will change in proportion
+     *  to the age of the image so that older images have a larger faded edge.
+     *  The area within the bounds, that forms the center of the image, is processed
+     *  first and faded by a standard alpha value. Then each edge of the image
+     *  is processed separately, creating a gradient fade from the true edge to the
+     *  position of the bound. <br>
+     *  The faded pixel array is then turned into a new image a returned.
+     *
+     *  @param img the image that requires processing
+     *  @param x the x co-ordinate of the image
+     *  @param y the y co-ordinate of the image
+     *  @param w the width of the image
+     *  @param h the height of the image
+     *  @param p the position of the image in the applet (indicates age)
+     *  @param fresh whether the image is being processed for the first time */
+
+    public synchronized Image handlepixels(Image img, int x, int y, int w, int h, int p, boolean fresh) {
+	
+	// declare an array to hold the pixels
+	int[] pixels = new int[w * h];
+
+	// get the pixels of the image into the pixels array
+	PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
+	try {
+	    pg.grabPixels();
+	
+	} catch (InterruptedException e) {
+	    System.err.println("interrupted waiting for pixels!");
+	    return img;
+	}
+	// check for any failures
+	if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
+	    System.err.println("image fetch aborted or errored");
+	    return img;
+	}
+
+	// calculates the bound from which fading should begin
+	double bound = (inuse_.size() - p) * 0.01;
+	if (w > h)
+	    bound *= w;
+	else
+	    bound *= h;
+	int upperboundheight = h - (int) bound;
+	int upperboundwidth = w - (int) bound;
+	int lowerbound = (int) bound;
+
+	// loop through every pixel in the picture and handle it
+	for (int j = lowerbound; j < upperboundheight; j++) {
+	    for (int i = lowerbound; i < upperboundwidth; i++) {
+		// width and height: x+i y+j
+		pixels[j * w + i] = handlesinglepixel(pixels[j * w + i], p, fresh, false, 255);
+	    }
+	}
+
+	int fade = 0;
+	int fader = 0;
+	int corealpha = (pixels[(h/2) * w + (w/2)] >> 24) & 0xff;
+	
+	// top edge
+	for (int n = lowerbound; n >= 0; n--) {
+	    fader = corealpha - fade;
+	    if (fader < 0)
+		fader = 0;
+	    
+	    for (int m = 0; m < w; m++)
+		pixels[n * w + m] = handlesinglepixel(pixels[n * w + m], p, fresh, true, fader);
+	    
+	    fade+= FADEVALUE;
+	}
+
+	// bottom edge
+	fade = 0;
+	for (int n = upperboundheight; n < h; n++) {
+	    fader = corealpha - fade;
+	    if (fader < 0)
+		fader = 0;
+	    for (int m = 0; m < w; m++)
+		pixels[n * w + m] = handlesinglepixel(pixels[n * w + m], p, fresh, true, fader);
+	    
+	    fade += FADEVALUE;
+	}
+
+	// left edge
+	fade = 0;
+	for (int n = lowerbound; n >= 0; n--) {
+	    fader = corealpha - fade;
+	    if (fader < 0)
+		fader = 0;
+	    for (int m = 0; m < h; m++) {
+		if ( m < lowerbound && n > m);
+		else if ( m > upperboundheight && n > (h - m));
+		else 
+		    pixels[m * w + n] = handlesinglepixel(pixels[m * w + n], p, fresh, true, fader);
+	    }
+	    fade += FADEVALUE;    
+	}
+	
+	// right edge
+	fade = 0;
+	for (int n = upperboundwidth; n < w; n++) {
+	    fader = corealpha - fade;
+	    if (fader < 0)
+		fader = 0;
+	    for (int m = 0; m < h; m++) {
+		if ( m < lowerbound && (w - n) > m);
+		else if ( m > upperboundheight && (w - n) > (h - m));
+		else 
+		    pixels[m * w + n] = handlesinglepixel(pixels[m * w + n], p, fresh, true, fader);
+	    }
+	    
+	    fade += FADEVALUE;
+	}
+   
+	// set the pixels of the whole picture to the pixels array
+	pg.setPixels(0, 0, w, h, pg.getColorModel(), pixels, 0, w);
+
+	// create the new image and return it
+	return( app_.createImage(new MemoryImageSource(w, h, pixels, 0, w)) );
+    
+    }
+
+    /** Resets the alpha channel of an image so that it appears solid
+     *
+     *  @param img the image to restore
+     *  @param x the x co-ordinate of the image
+     *  @param y the y co-ordinate of the image
+     *  @param w the width of the image
+     *  @param h the height of the image */
+    public Image restoreAlpha(Image img, int x, int y, int w, int h) {
+	
+	// declare an array to hold the pixels
+	int[] pixels = new int[w * h];
+
+	// get the pixels of the image into the pixels array
+	PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
+	try {
+	    pg.grabPixels();
+	
+	} catch (InterruptedException e) {
+	    System.err.println("interrupted waiting for pixels!");
+	    return img;
+	}
+	// check for any failures
+	if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
+	    System.err.println("image fetch aborted or errored");
+	    return img;
+	}
+
+	// loop through every pixel in the picture and handle it
+	for (int j = 0; j < h; j++) {
+	    for (int i = 0; i < w; i++) {
+		pixels[j * w + i] |= (255 << 24) & 0xff000000;
+	    }
+	}
+
+	// set the pixels of the whole picture to the pixels array
+	pg.setPixels(0, 0, w, h, pg.getColorModel(), pixels, 0, w);
+
+	// create the new image and return it
+	return( app_.createImage(new MemoryImageSource(w, h, pixels, 0, w)) );
+    
+    }
+
+    /** Checks whether an image has faded to the point where it must be removed
+     *  from the collage.
+     *
+     *  @param img the image to restore
+     *  @param x the x co-ordinate of the image
+     *  @param y the y co-ordinate of the image
+     *  @param w the width of the image
+     *  @param h the height of the image */
+    public boolean checkFaded (Image img, int x, int y, int w, int h) {
+
+	 if (w == 0 || h == 0) 
+	     return false;
+	
+	// declare an array to hold the pixels
+	int[] pixels = new int[w * h];
+
+	// get the pixels of the image into the pixels array
+	PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
+	try {
+	    pg.grabPixels();
+	
+	} catch (InterruptedException e) {
+	    System.err.println("interrupted waiting for pixels!");
+	    return false;
+	}
+	// check for any failures
+	if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
+	    System.err.println("image fetch aborted or errored");
+	    return false;
+	}
+
+	// get the alpha value of the middle pixel of the image
+	int corealpha = (pixels[(h/2) * w + (w/2)] >> 24) & 0xff;
+	
+	if (corealpha < 50)
+	    return true;
+
+	return false;
+	
+    }
+
+    /** Paints the applet on the screen */
+    public synchronized void paint(Graphics g)
+    {
+	screen_graphic_.setColor(bgcolor_);
+	screen_graphic_.fillRect(0,0,app_x_dim_,app_y_dim_);
+	
+	int n = inuse_.size();
+	
+	// get each image currently onscreen inturn
+	for (int i=0; i < n; i++)
+	    {
+		CollageImage collage_image = (CollageImage)inuse_.elementAt(i);
+		// don't paint new images yet
+		if (collage_image.fresh) {
+		    if (app_.verbosity()>3) {
+			System.err.println("doing nothing... image " + i + " of "+n+ " images in use is fresh.");
+		    }
+		}
+
+		// advanced image processing may be used
+		//		else if (is_java2_) {
+		else if (false) {
+			// the alphacomposite controls the blending of these two images.
+			Graphics2D sg2d = (Graphics2D)screen_graphic_;
+			//sg2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
+			sg2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
+					      RenderingHints.VALUE_ANTIALIAS_ON); 
+			collage_image.expand();
+			sg2d.drawImage(collage_image.image_, collage_image.af_, app_);
+		    }
+		// simple image collage
+		else
+		    {
+			// add the image to the collage
+			screen_graphic_.drawImage(collage_image.image_, 
+						  collage_image.xl_, collage_image.yt_,
+						  collage_image.xr_, collage_image.yb_,
+						  0,0,collage_image.image_x_dim_-1,
+						  collage_image.image_y_dim_-1,  app_);
+	   
+		    }
+		
+		
+	    }
+	
+        
+	finished_graphic_.drawImage(screen_buffer_,0,0,app_);
+	
+	if (finished_buffer_ != null)
+	    {
+		g.drawImage(finished_buffer_, 0, 0, app_);
+	    }
+    }
+
+    /** Runs display thread by repeatedly calling the next frame,
+     *  waiting for a specified delay period between calls */
+    public void run() 
+    {
+	try {
+
+	    System.err.println("Running display thread");
+
+	    Thread curr_thread = Thread.currentThread();
+	    
+	    //long tm = System.currentTimeMillis();
+	
+	    while (curr_thread == this) {
+		next_frame();
+		//tm += app_.refreshDelay();
+		//Thread.sleep(Math.max(0, tm - System.currentTimeMillis()));
+		Thread.sleep(app_.refreshDelay());
+		//Thread.sleep(2);
+		curr_thread = Thread.currentThread();
+	    }
+
+	    System.err.println("Display thread finished");
+	    
+	} catch (Exception e) {
+	    e.printStackTrace();
+	}
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/DownloadImages.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/DownloadImages.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/DownloadImages.java	(revision 10506)
@@ -0,0 +1,118 @@
+package org.nzdl.gsdl.GsdlCollageApplet;
+
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/** 
+ *  @author Katrina Edgar
+ *  @author David Bainbridge
+ *
+ *  Stores images that are downloaded but have not yet been displayed
+ *  in the applet. Provides methods to add to and remove from this list
+ *  and check it's size. It uses an inner class to store the data for these
+ *  images, comprising of three parts: the image itself, it's source url
+ *  and the name of the image */
+public class DownloadImages {
+
+    /** Data structure to store an image that has been downloaded and is
+     *  waiting to be used. */
+    public class ImageUrlTriple {
+
+	Image image_;
+	String url_;
+	String name_;
+
+	/** Constructs a downloaded image structure from the given parameters
+	 *  @param image the graphical image
+	 *  @param url the source url for this image
+	 *  @param name the name of the image file */
+	public ImageUrlTriple (Image image, String url, String name)
+	{
+	    image_ = image;
+	    url_ = url;
+	    name_ = name;
+	}
+
+	Image image() {
+	    return image_;
+	}
+
+	String url() {
+	    return url_;
+	}
+
+	String name() {
+	    return name_;
+	}
+
+    }
+
+    /** The amount of output to produce to the screen */
+    int verbosity_       = 0;
+    /** Holds the images that have been downloaded and are waiting to be used */
+    Vector image_array_  = null;
+
+    /** Initialises an empty vector to store downloaded images in and sets
+     *  the verbosity for this class */
+    public DownloadImages(int verbosity)
+    {
+	verbosity_ = verbosity;
+	image_array_ = new Vector();
+    }
+
+    /** Get the number of images currently downloaded and waiting for use
+     *  @return the number of images currently downloaded */
+    public synchronized int size()
+    {
+	return image_array_.size();
+    }
+
+   //   /** Get the image from the specified position in the array of downloaded images
+//       *  @return an ImageUrlTriple containing the image, url and image name */
+//      public synchronized ImageUrlTriple get(int pos)
+//      {
+//  	return (ImageUrlTriple)image_array_.get(pos);
+//      }
+
+    /** Push a new image into the vector of downloaded images
+     *  @param image the graphical image to add
+     *  @param url the source url of the image
+     *  @param name the name of the image to add */
+    public synchronized void push(Image image, String url, String name)
+    {
+	ImageUrlTriple iutriple = new ImageUrlTriple(image,url,name);
+
+	image_array_.addElement(iutriple);
+    }
+
+    /** Remove the image from the specified position in the array of downloaded images
+     *  @return an ImageUrlTriple containing the image, url and image name */
+    public synchronized ImageUrlTriple retrieve(int pos)
+    {
+	if (image_array_.size() == 0)
+	    return null;
+
+	if (pos >= (image_array_.size() - 1))
+	    pos = 0;
+
+	ImageUrlTriple u = (ImageUrlTriple) image_array_.elementAt(pos);
+	image_array_.removeElementAt(pos);
+	return u;
+    }
+
+    /** gets the oldest downloaded image, checks that the downloaded images are
+     *  not empty.
+     *  @return an ImageUrlTriple containing the image, url and image name */
+    public synchronized ImageUrlTriple shift()
+    {	
+	if (image_array_.size()==0) {
+	    return null;
+	}
+
+	ImageUrlTriple u = (ImageUrlTriple) image_array_.elementAt(0);
+	image_array_.removeElementAt(0);
+	return u;
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/DownloadUrls.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/DownloadUrls.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/DownloadUrls.java	(revision 10506)
@@ -0,0 +1,525 @@
+package org.nzdl.gsdl.GsdlCollageApplet;
+
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+// import javax.swing.ImageIcon; //****
+
+
+/** 
+ *  @author Katrina Edgar
+ *  @author David Bainbridge
+ *
+ *  Controls retrieval of images from the specified starting url. Follows appropriate
+ *  links from this starting point, traversing in a tree-like state through several other
+ *  pages. Filters images and links based on specified parameters. Also controls the quantity
+ *  of downloading that occurs by restricting the number of downloaded images that are yet to
+ *  be displayed to 10, and the total number of downloads allowed is also restricted by
+ *  the applet application (to prevent downloading occuring infinitely). */
+
+public class DownloadUrls extends Thread {
+
+    /** Refers to applet */
+    GsdlCollageApplet app_          = null;
+    /** Refers to download thread */
+    DownloadImages download_images_ = null;
+
+    /** The address from which the application should start looking for images */
+    String starting_url_  = null;
+
+    /** CHRIS - Holds the contents of the collection's assoc directory */
+    //    File[] assocDir_ = null;
+
+    /** Restricts links followed from the starting url to links that contain this string */
+    String href_musthave_ = null;
+    /** Restricts links followed from the starting url to links that do not contain this string. 
+     *  Also prevents image names from containing this string */
+    String image_mustnothave_ = null;
+    /** Ignore images whose names begin with this string */
+    String image_ignore_  = null;
+    /** Restricts the types of images included in the collage, for example jpg, gif, etc. */
+    String image_type_ = null;
+
+    /** A static delay used when attempting to download more images into a full downloading buffer */
+    final int delay_       = 1000;
+    /** The maximum number of images to have downloaded and not yet displayed */ 
+    final int buffer_size_ = 10;
+
+    /** Used in cases where the image maps to a url outside of it's original location.
+     *  When used with Greenstone the collage images will refer to documents in the collections
+     *  from which the images are sourced. When used individually, the images may be saved into
+     *  a user directory and the pages they reference may be external hyperlinks. */
+    Hashtable external_links_ = null;
+
+    /** Records all urls which have already been examined */
+    Hashtable visited_url_  = null;
+    /** Determines whether there are still pages to examine and images to download */
+    boolean thread_running_ = true;
+
+    int verbosity_;
+
+    /** Constructor to initialise a download thread from which images are found, 
+     *  saves parameters into local variables for use within the class.
+     *
+     *  @param app reference to the applet
+     *  @param download_images class which stores the images retrieved in triplets
+     *  @param starting_url the url from which the search for images should begin
+     *  @param href_musthave restricts links to only those containing this string
+     *  @param image_mustnothave restricts links and image names to only those that don't contain this string
+     *  @param image_ignore restricts the beginning of image names
+     *  @param image_type restricts the type of images included in the collage to those named */
+    public DownloadUrls(GsdlCollageApplet app, 
+			DownloadImages download_images, String starting_url, 
+			String href_musthave, String image_mustnothave, 
+			String image_ignore, String image_type, int verbosity)
+    {
+	super("DownloadUrls");
+	app_             = app;
+	download_images_ = download_images;
+
+	starting_url_  = starting_url;
+	href_musthave_ = href_musthave;
+	image_mustnothave_ = image_mustnothave;
+	image_ignore_  = image_ignore;
+	image_type_    = image_type;
+	
+	verbosity_ = verbosity;
+    }
+
+    
+
+    /** Determines whether or not a url has already been examined
+     *
+     *  @param url_string the url to check
+     *  @return true if the url has been visited, false if not */
+    public boolean already_visited(String url_string)
+    {
+	int hash_pos = url_string.indexOf("#");
+	if (hash_pos>0)
+	 {
+	     // strip off #anchor reference
+	     url_string = url_string.substring(0,hash_pos);
+	 }
+
+	// if the url has been visited before, return true
+	if (visited_url_.containsKey(url_string))
+	{
+	    if (verbosity_ > 3)
+		{
+		    System.err.println("Visited " + url_string + " before!");
+		}
+	    return true;
+	}
+	
+	visited_url_.put(url_string,"visited");
+
+	return false;
+    }
+
+    /** Restricts the type of images that can be included in the collage
+     *
+     * @param url_string the url to check
+     * @return true if the image is of a specified type, false if not */
+    public boolean image_file_extension(String url_string)
+    {
+	// lower case comparisons
+	String url_lstring = url_string.toLowerCase();
+
+	if (image_type_ == null)
+	    return true;
+
+	String tmp = image_type_;
+	String original_image_type_ = image_type_;
+
+	while (image_type_ != null && image_type_.indexOf("%") >= 0) {
+	    
+	    tmp = image_type_.substring(0, image_type_.indexOf("%"));
+	    if (image_type_.length() > image_type_.indexOf("%") + 1)
+		image_type_ = image_type_.substring(image_type_.indexOf("%") + 1, image_type_.length());
+	    else
+		image_type_ = null;
+
+	    if (url_lstring.endsWith(tmp)) {
+		image_type_ = original_image_type_;
+		return true;
+	    }
+	}
+
+	if (image_type_ != null && url_lstring.endsWith(image_type_)) {
+		image_type_ = original_image_type_;
+		return true;
+	}
+
+	image_type_ = original_image_type_;
+	return false;
+    }
+
+    /** Restricts images to only those that satisfy several specified conditions
+     *  regarding the content of the image name and url.
+     *
+     *  @param url_string the url to check
+     *  @return true if the image is satisfactory, false if not */
+    public boolean filter_image(String url_string)
+    {
+	if (image_ignore_==null || !url_string.startsWith(image_ignore_))
+	{
+	    if (!already_visited(url_string))
+	    {
+		if (image_mustnothave_ != null) {
+		    
+		    String tmp = image_mustnothave_;
+		    String original_image_mustnothave_ = image_mustnothave_;
+
+		    while (image_mustnothave_ != null && image_mustnothave_.indexOf("%") >= 0) {
+	    
+			tmp = image_mustnothave_.substring(0, image_mustnothave_.indexOf("%"));
+			if (image_mustnothave_.length() > image_mustnothave_.indexOf("%") + 1)
+			    image_mustnothave_ = image_mustnothave_.substring(image_mustnothave_.indexOf("%") + 1, 
+									      image_mustnothave_.length());
+			else
+			    image_mustnothave_ = null;
+			
+			if (url_string.indexOf(tmp) >= 0) {
+			    image_mustnothave_ = original_image_mustnothave_;
+			    return false;
+			}
+		    }
+
+		    if (image_mustnothave_ != null && url_string.indexOf(image_mustnothave_) >= 0) {
+			image_mustnothave_ = original_image_mustnothave_;
+			return false;
+		    }
+
+		    if (verbosity_ > 2) {
+			System.err.println("src url = "+ url_string);
+		    }
+		    
+		    image_mustnothave_ = original_image_mustnothave_;
+		    return true;
+		}
+	    }
+	}
+
+	return false;
+    }
+
+    /** Restricts links to only those that satisfy several specified conditions
+     *  regarding the address of the link.
+     *
+     *  @param url_string the url to check
+     *  @param new_url_string the url from which this link was found
+     *  @param depth the number of links followed on this path
+     *  @return true if the image is satisfactory, false if not */
+    public boolean filter_href(String url_string, String new_url_string, int depth)
+    {
+	boolean has_href = false;
+	String tmp = href_musthave_;
+	String original_href_musthave_ = href_musthave_;
+
+	// checks that it does contain this content
+	if (href_musthave_ !=  null) {
+
+	    while (href_musthave_ != null && href_musthave_.indexOf("%") >= 0) {
+		
+		tmp = href_musthave_.substring(0, href_musthave_.indexOf("%"));
+		if (href_musthave_.length() > href_musthave_.indexOf("%") + 1)
+		    href_musthave_ = href_musthave_.substring(href_musthave_.indexOf("%") + 1, href_musthave_.length());
+		else
+		    href_musthave_ = null;
+		
+		if (url_string.indexOf(tmp) >= 0)
+		    has_href = true;
+	    }
+	    
+	    if (href_musthave_ != null && url_string.indexOf(href_musthave_) >= 0)
+		has_href = true;
+
+	    href_musthave_ = original_href_musthave_;
+	}
+
+	tmp = image_mustnothave_;
+	String original_image_mustnothave_ = image_mustnothave_;
+
+	// checks that it doesn't contain this content
+	if (image_mustnothave_ != null) {
+
+	    while (image_mustnothave_ != null && image_mustnothave_.indexOf("%") >= 0) {
+		
+		tmp = image_mustnothave_.substring(0, image_mustnothave_.indexOf("%"));
+		if (image_mustnothave_.length() > image_mustnothave_.indexOf("%") + 1)
+		    image_mustnothave_ = image_mustnothave_.substring(image_mustnothave_.indexOf("%") + 1, image_mustnothave_.length());
+		else
+		    image_mustnothave_ = null;
+		
+		if (url_string.indexOf(tmp) >= 0)
+		    has_href = false;
+	    }
+	    if (image_mustnothave_ != null && url_string.indexOf(image_mustnothave_) >= 0)
+		has_href = false;
+	  
+	    image_mustnothave_ = original_image_mustnothave_;
+	}
+
+	// return true if the link is valid and false if not
+	if (href_musthave_==null || has_href)
+	{
+	    // might be another URL
+	    if (depth < app_.maxDepth())
+	    {
+		if (!new_url_string.startsWith(url_string))
+		{
+		    return true;
+		}
+	    }
+	}
+	return false;
+    }
+
+    /** Adds an image to the stored downloaded images as a triplet.
+     *  Ensures that the number of images downloaded but not displayed at
+     *  any one time is controlled by using a buffer. If the buffer is
+     *  full this function will wait until space becomes available before
+     *  continuing. It also restricts the
+     *  total number of images to download as specified by the applet.
+     *
+     *  @param url the image to download
+     *  @param from_url the url that this image was sourced from
+     *  @param img_name the name of the image */
+    public void add_image(URL url, String from_url, String img_name)
+    {
+	try {
+
+	    boolean had_to_wait = false;
+
+	    // ensure that we don't download too many images
+	    while (download_images_.size() >= buffer_size_)
+	    {
+		had_to_wait = true;
+		Thread.sleep(delay_);
+	    }
+	    
+	    // get the image from the url
+	    if (verbosity_>=2) {
+		System.err.println("  Downloading image URL: " + url.toString());
+	    }
+
+	    //ImageIcon image_icon = new ImageIcon(url);
+	    // Image image = image_icon.getImage();
+
+	    // Image image = Toolkit.getDefaultToolkit().createImage(url);
+	    // Image image = app_.getImage(url);
+	    Image image = Toolkit.getDefaultToolkit().getImage(url);
+
+	    //System.err.println("###DownloadingED image URL: " + url.toString());
+
+	    boolean status = app_.prepareImage(image,app_);
+	    //System.err.println(" Prepare Image status = " + status);
+
+	    Thread.sleep(100);
+
+	    // push image onto the downloaded images
+	    /* System.err.println("*** Pushing: name="+img_name
+			       +" dimensions = "+image_icon.getIconWidth()+"x"+image_icon.getIconHeight());
+	    //			       +" dimensions = "+image.getWidth(app_)+"x"+image.getHeight(app_));
+	    */
+
+	    download_images_.push(image,from_url, img_name);
+	    
+	    // if have completed the maximum number of downloads for the
+	    // application then stop
+	    if (download_images_.size() == app_.maxDownloads()) {
+		stop();
+	    }
+	    
+	}
+	catch (Exception e) {
+	    thread_running_ = false;
+	    stop();
+	    e.printStackTrace();
+	}
+    }
+
+    /** Connects to the starting url and looks for all images and links from this
+     *  original page. Image links are processed first, so that any images found can be
+     *  downloaded immediately and placed on the applet. Secondly, the links to other
+     *  pages are recursively processed by this function and treated as a starting url
+     *
+     *  @param new_url the url from which to start searching for images and links
+     *  @param depth the number of links that have been followed on this path */
+    public void rec_add_images(String new_url, int depth)
+    {
+	System.err.println("Parsing url = " + new_url);
+	
+	if (already_visited(new_url)) return;
+
+	// check if there is a scenario where external hyperlinks are being used
+	externalLinks();
+	String img_name = new String();
+
+	// connect to the url
+	CURL curl = new CURL(new_url);
+	if (curl.connected_ok())
+	{
+	    if (verbosity_ >= 1) {
+		System.err.print("Connected OK ... ");
+	    }
+
+	    // read the page
+	    curl.readAll();
+	    if (verbosity_ >= 1) {
+		System.err.println("URL read.");
+	    }
+
+	    // get all the <code><img src=</code> links into a vector
+	    Vector src_links = curl.getSrcLinks();
+	    
+	    if (verbosity_ >= 2) {
+		System.err.println("  Got src links... there are " + src_links.size() + " of them.");
+	    }
+	    // process each of the image links according to the parameters given.
+	    for (int i = 0; i < src_links.size(); i++) 
+	    {
+		URL url = (URL)src_links.elementAt(i);
+		String url_string  = url.toString();
+
+		if (verbosity_ >= 3) {
+		    System.err.println("    Unfiltered: src_link[" + i + "] = " + url_string);
+		}
+
+		if (image_file_extension(url_string))
+		    {
+			if (filter_image(url_string))
+			    {
+				img_name = url_string.substring(url_string.lastIndexOf("/") + 1, url_string.length());
+
+				if (verbosity_ >= 2) {
+				    System.err.println("    Filtered: src_link[" + i + "] = " + url_string);
+				}
+
+				if ((external_links_ != null) && (!external_links_.isEmpty())) {
+				    String ext = (String) external_links_.get(img_name);
+				    
+				    if (ext != null) 
+					add_image(url, ext, img_name);
+				    else
+					add_image(url, new_url, img_name);
+				}
+				else {
+				    add_image(url, new_url, img_name);
+				}
+			    }
+		    }
+		
+	    }
+
+	    // get all the <code><a href=</code> links into a vector
+	    Vector href_links = curl.getHrefLinks();
+	    
+	    // process each of the href links according to the parameters given.
+	    for (int i = 0; i < href_links.size(); i++) 
+		{
+		    URL url = (URL)href_links.elementAt(i);
+		    String url_string  = url.toString();
+		    
+		    if (image_file_extension(url_string))
+			{
+			    if (filter_image(url_string))
+				{
+				    img_name = url_string.substring(url_string.lastIndexOf("/") + 1, url_string.length());
+
+				    if ((external_links_ != null) && (!external_links_.isEmpty())) {
+					String ext = (String) external_links_.get(img_name);
+
+					if (ext != null) 
+					    add_image(url, ext, img_name);
+					else
+					    add_image(url, new_url, img_name);
+				    }
+				    else {
+					add_image(url, url_string, img_name);
+				    }
+				}
+			}
+		    else
+			{
+			    if (filter_href(url_string,new_url,depth))
+				{
+				    rec_add_images(url_string,depth+1);
+				    
+				}
+			}
+		}
+	}
+   
+	else {
+	    System.err.println("Unable able to download "+new_url);
+	}
+    }
+
+    
+    /** Used in cases where the image maps to a url outside of it's original location.
+     *  When used with Greenstone the collage images will refer to documents in the collections
+     *  from which the images are sourced. When used individually, the images may be saved into
+     *  a user directory and the pages they reference may be external hyperlinks. 
+     *  This function reads that external links file and creates a hash map of the image to
+     *  its external hyperlink. If the file does not exist the download thread will continue
+     *  and assume the first case, that links are internal. */
+    public void externalLinks() {
+
+	try {
+
+	    if (starting_url_.indexOf("gsdl") >= 0) {
+		external_links_ = null;
+		return;
+	    }
+	    
+	    // open a url to the file written
+	    URL u = new URL(starting_url_ + "externallinks");
+
+	    BufferedReader r = new BufferedReader(new InputStreamReader(u.openStream()));
+	    
+	    external_links_ = new Hashtable();
+
+	    String l = r.readLine();
+	    // split the line of the space, first part is the image, second part the link
+	    while (l != null) {
+
+		String tmp1 = new String();
+		String tmp2 = new String();
+
+		if (l.indexOf(" ") >= 0) {
+		    
+		    tmp1 = l.substring(0, l.indexOf(" "));
+		    if (l.length() > l.indexOf(" ") + 1)
+			tmp2 = l.substring(l.indexOf(" ") + 1, l.length());
+		    else
+			tmp2 = null;
+		    
+		    if (tmp2 != null) {
+			external_links_.put(tmp1, tmp2);
+			//System.err.println(tmp1 + " " + tmp2);
+		    }
+		}
+		l = r.readLine();
+	    }
+		
+		r.close();
+
+	} catch (Exception e) {
+	    e.printStackTrace();
+	    return;
+	}
+    }
+
+    /** Controls the download thread */
+    public void run () 
+    {
+	System.err.println("Starting download thread.");
+	visited_url_ = new Hashtable();
+	rec_add_images(starting_url_,1);
+
+	System.err.println("Download thread finished.");
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/GsdlCollageApplet.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/GsdlCollageApplet.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/GsdlCollageApplet.java	(revision 10506)
@@ -0,0 +1,338 @@
+package org.nzdl.gsdl.GsdlCollageApplet;
+
+import java.applet.*;
+import java.awt.*;
+import java.net.*;
+
+/**
+ * 
+ *  @author Katrina Edgar
+ *  @author David Bainbridge
+ *
+ * Main class for the GsdlCollageApplet<br>
+ * Processes the parameters passed through the Applet<br>
+ * Builds an appropriate starting url from these parameters<br>
+ * Creates a storage class for downloaded images<br>
+ * Starts thread to download images and their associated url<br>
+ * Starts thread to display downloaded images on the applet screen<br>
+ */
+ 
+public class GsdlCollageApplet extends Applet {
+
+
+    /** Amount of error checking output produced <br>
+     *  Ranges from 0 - no output to 3 - maximum output */ 
+    protected int verbosity_     = 0;
+    /** Indicates whether java2 functionality should be used <br>
+     *  If true will allow advanced image processing techniques to occur, 
+     *  such as fading and colouring using pixel manipulation <br>
+     *  If false, images will maintain an alpha value of 1 (appear solid), 
+     *  newer images will simply be pasted on top of existing images <br> */
+    protected boolean isJava2_  = true;
+    /** Number of nested links to follow When used with greenstone,
+     *  controls to which level of the document links will be followed For
+     *  example a maximum depth of 1 will mean only the top page of a
+     *  document will be examined, while a depth of 2 will include sections
+     *  within this document, 3 includes sections within sections, and so
+     *  on */
+    protected int maxDepth_     = 3;
+
+    /** Maximum number of images to display on the canvas */
+    protected int maxDisplay_ = 25;
+
+    /** Maximum number of downloaded images to store <br> Prevents applet
+     *  from using excessive amounts of bandwidth by downloading too many
+     *  images simulataneously*/
+    protected int maxDownloads_ = Integer.MAX_VALUE;
+
+    /** Types of images permitted in the collage, for example gif, jpg,
+     * png... */
+    protected String imageType_ = ".jpg%.png";
+
+    /** Caption of the collage */
+    protected String caption_ = "";
+
+    /** Background color of applet screen */
+    protected Color bgcolor_ = new Color(150, 193, 155);
+
+    /** Time lapse between repainting of the applet */
+    protected int refreshDelay_ = 1500;
+    
+    /** Stores an image and url pair and provides associated methods */
+    protected DownloadImages download_images_ = null;
+    /** Downloads images from a starting url, recursively follows nested
+     * links */
+    protected DownloadUrls download_thread_   = null;
+    /** Image processing and placement on applet screen */
+    protected DisplayImages display_thread_   = null;
+
+    protected Display display_ = null;
+
+    /** Gets verbosity */
+    public int verbosity()    { return verbosity_; }
+    /** Gets maximum depth for nested links */
+    public int maxDepth()     { return maxDepth_; }
+
+    /** Gets maximum number of images to display */
+    public int maxDisplay() { return maxDisplay_;}
+
+    /** Gets maximum number of images to store during downloading */
+    public int maxDownloads() { return maxDownloads_; }
+    /** Gets the refresh delay used between repaint */
+    public int refreshDelay() { return refreshDelay_; }
+
+    /** Gets parameters from the applet code and stores locally.
+     * Forms a starting url for image retrieval to begin from.
+     * The starting url is formed either by:
+     *  * Using the image_url parameter as provided, which is assumed to 
+     *     be a complete url
+     *  * If this parameter does not exist, the assumption is that the 
+     *     collage is being incorporated with the Greenstone Digital Library 
+     *     Software. The starting url is formed by concatenating
+     *     the gwcgi, collection and classifier parameters as provided.
+     * Then starts downloading and displaying images */
+    public void init() 
+    {	    
+	if (verbosity_ >= 4) { 
+	    System.err.println("Attempting to retrieve parameters...");
+	}
+
+	// gets the parameters specified
+	String verbosity_param      = getParameter("verbosity");
+	String is_java2_param       = getParameter("isJava2");
+	String max_depth_param      = getParameter("maxDepth");
+	String max_downloads_param  = getParameter("maxDownloads");
+	String max_display_param    = getParameter("maxDisplay");
+	String refresh_delay_param  = getParameter("refreshDelay");
+	String image_type_param     = getParameter("imageType");
+	String bgcolor_param        = getParameter("bgcolor");
+	String caption_param        = getParameter("caption");
+
+	// Check it isn't null
+	if ((verbosity_param!=null) && (!verbosity_param.startsWith("_"))) {
+	    verbosity_  = Integer.parseInt(verbosity_param);
+	}
+	else {
+	    verbosity_ = 1;
+	}
+
+	if (verbosity_ >= 4) { 
+	    System.err.println("Got parameters.");
+	}
+
+	if (caption_param != null && !caption_param.startsWith("_")) {
+	    caption_ = caption_param;
+	}
+	else {
+	    if (verbosity_ >= 4) { 
+		System.err.println("No Caption: setting to a space.");
+	    }
+	    caption_ = " ";
+	}
+
+	if ((bgcolor_param != null) && (!bgcolor_param.startsWith("_"))) {
+	    if (bgcolor_param.startsWith("#")) {
+		bgcolor_ = Color.decode(bgcolor_param);   
+	    }
+	    else {
+		String [] c = bgcolor_param.split(",");
+		if (c.length == 3)
+		    bgcolor_ = new Color(Integer.parseInt(c[0]), Integer.parseInt(c[1]), Integer.parseInt(c[2]));
+	    }
+	    if (verbosity_ >= 4){ 
+		System.err.println("Set BG to be " + bgcolor_.toString());
+	    }
+	}
+	else {
+	    if (verbosity_ >= 4) { 
+		System.err.println("No BG: setting to NZDL green.");
+	    }	   
+	    bgcolor_ = new Color(150, 193, 155);
+	}
+
+	if ((image_type_param != null) && (!image_type_param.startsWith("_"))) {
+	    imageType_ = image_type_param;
+	}
+
+	if ((is_java2_param == null) || (is_java2_param.equals("auto")) || (is_java2_param.startsWith("_"))) {
+	    String version = System.getProperty("java.version");
+	    version = version.substring(0, version.lastIndexOf("."));
+	    System.err.println("VERSION: " + version);
+	    float ver = (new Float(version)).floatValue();
+	    isJava2_ = (ver >= 1.2) ? true : false;
+	}
+	else {
+	    isJava2_ = (is_java2_param.equals("true")) ? true : false;
+	}
+
+	if ((max_depth_param != null) && (!max_depth_param.startsWith("_"))) {
+	    // System.err.println("maxDepth = " + max_depth_param);
+	    maxDepth_ = Integer.parseInt(max_depth_param);
+	}
+
+	if ((max_downloads_param!=null) && (!max_downloads_param.startsWith("_"))) {
+	    maxDownloads_ = Integer.parseInt(max_downloads_param);
+	}
+
+	if ((max_display_param!=null) && (!max_display_param.startsWith("_"))) {
+	    maxDisplay_ = Integer.parseInt(max_display_param);
+	}
+
+	if ((refresh_delay_param!=null) && (!refresh_delay_param.startsWith("_"))) {
+	    refreshDelay_ = Integer.parseInt(refresh_delay_param);
+	}
+
+	String image_url  = getParameter("imageURL"); 
+	String image_ignore  = getParameter("imageIgnorePrefix"); 
+	String href_musthave  = getParameter("hrefMustHave"); 
+	String image_mustnothave = getParameter("imageMustNotHave");
+
+	// builds starting url when incorporated with Greenstone
+	if (image_url==null)
+	{
+	    String gwcgi_param  = getParameter("gwcgi");
+	    gwcgi_param = tidy_URL(gwcgi_param, true);
+	
+	    String collection_param  = getParameter("collection");
+	    String classifier_param  = getParameter("classifier");
+
+	    image_url = gwcgi_param + "a=d";
+	    image_url += "&c=" + collection_param;
+	    image_url += "&cl=" + classifier_param;
+	}
+	
+	// creates a class to store the image and it's associated url
+	download_images_ = new DownloadImages(verbosity_);
+	// starts the download image thread with the starting url
+	download_thread_ = new DownloadUrls(this, download_images_, 
+					    image_url, href_musthave, image_mustnothave, 
+					    image_ignore, imageType_, verbosity_);
+	// starts the display image thread with the currently downloaded images
+	display_thread_ = new DisplayImages(this,download_images_, isJava2_, bgcolor_);
+	display_ = new Display(this);
+    }
+
+    /** Goes to the url associated with the image that is clicked on screen<br>
+     *  Displays the url containing the image in a new window */
+    public boolean mouseDown(Event event, int x, int y)
+    {
+	// determines which image was clicked on
+	CollageImage cimage = display_thread_.clickedOnImage(x,y);
+	// if they were clicking on an image (as opposed to background)
+	if (cimage != null)
+	{
+	    System.err.println("Click on image: from url = " + cimage.from_url_);
+	    try {
+		// displays the associated url in a new window
+		URL from_url = new URL(cimage.from_url_  + "#" + cimage.name_);
+		getAppletContext().showDocument(from_url,"gsdlDoc");
+	    } 
+	    catch (MalformedURLException e) {
+		e.printStackTrace();
+	    }
+
+	}
+        return true;
+    }
+    
+    /** Start threads for downloading and displaying images */
+    public void start() 
+    {
+	download_thread_.start();
+	display_thread_.start();
+	display_.start();
+    }
+
+    /** Stops threads for downloading and displaying images */
+    public void stop() 
+    {
+	download_thread_.stop();
+	display_thread_.stop();
+	display_.stop();
+
+	download_thread_ = null;
+	display_thread_ = null;
+	display_ = null;
+    }
+
+    /** Destroys threads for downloading and displaying images */
+    public void destroyed() 
+    {
+	download_thread_ = null;
+	display_thread_ = null;
+	display_ = null;
+    }
+
+    /** Repaints the applet */
+    public void update(Graphics g) 
+    { 
+	// System.err.println("Update called");
+	paint(g); 
+    } 
+        
+    /** Repaints the applet using the paint method of the thread that is
+     * currently displaying images */
+    public void paint(Graphics g) {
+	if (display_thread_!=null)
+	{
+	    //display_thread_.display_collage();
+	    display_thread_.paint(g);
+	}
+	else
+	{
+	    System.err.println("Applet still trying to paint!!");
+	}
+    }
+
+
+    
+    /** Ensures 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;
+    }
+
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/Makefile
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/Makefile	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/Makefile	(revision 10506)
@@ -0,0 +1,17 @@
+
+
+
+CLASSES = CURL.class CollageImage.class Display.class DisplayImages.class \
+          DownloadImages.class DownloadUrls.class GsdlCollageApplet.class \
+          MyAffineTransform.class
+
+all: GsdlCollageApplet.jar
+
+clean:
+	rm -f $(CLASSES) GsdlCollageApplet.jar
+
+GsdlCollageApplet.jar: $(CLASSES)
+	jar cf GsdlCollageApplet.jar org
+
+%.class : %.java
+	javac -d . -classpath ../../../.. $<
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/MyAffineTransform.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/MyAffineTransform.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/GsdlCollageApplet/MyAffineTransform.java	(revision 10506)
@@ -0,0 +1,154 @@
+package org.nzdl.gsdl.GsdlCollageApplet;
+
+public class MyAffineTransform {
+
+    public double scaleX = 0;
+    public double scaleY = 0;
+    public double translateX = 0;
+    public double translateY = 0;
+    public boolean overlap = false;
+
+    public MyAffineTransform (int image_x_dim, int image_y_dim) {
+
+	random_set_pos(image_x_dim, image_y_dim);
+    }
+
+    /** The amount to adjust the size of an image so that it fits into the applet screen
+     *  @param image_x_dim the width of the image to scale
+     *  @param image_y_dim the height of the image to scale
+     *  @return a value by which to scale the image to ensure it will fit in the applet */
+    private double scaleFactor (int image_x_dim, int image_y_dim) {
+
+	double scale_factor = 1.0;
+
+	// three quarters of the application width & height
+	int tol_app_x_dim = 3*DisplayImages.app_x_dim_/4;
+	int tol_app_y_dim = 3*DisplayImages.app_y_dim_/4;
+
+	// if the image is too big, calculate a fraction
+	// by which to reduce the image
+	if (image_x_dim>tol_app_x_dim)
+	{
+	    scale_factor = image_x_dim/tol_app_x_dim + 1;
+	}
+
+	if (image_y_dim>tol_app_y_dim)
+	{
+	    int y_scale_factor = image_y_dim/tol_app_y_dim + 1;
+	    // take the biggest of the two as the same fraction must
+	    // be applied to both the x and y values to keep the image
+	    // in proportion
+	    if (y_scale_factor>scale_factor)
+	    {
+		scale_factor = y_scale_factor;
+	    }
+	}
+
+	return scale_factor;
+    }
+
+    /** Determines the placement of new images on the applet screen <br>
+     *  First the image is scaled, then the function loops until a satisfactory
+     *  image position is found. This is done by randomly selecting an x and y
+     *  co-ordinate for the image, then determining how much whitespace will be
+     *  covered if the image were to be placed at this position in the collage.
+     *  The standards for loop termination are as follows:<br>
+     *  1. On any occasion a whitespace coverage of greater than 70% will result 
+     *  in the loop being terminated.<br>
+     *  2. After three times through the loop, a whitespace coverage of 50% will
+     *  also allow the loop to terminate (a less stringent condition). <br>
+     *  3. After seven times through, the loop will terminate and the best
+     *  position will be used by default.<br>
+     *  This function also updates the used space array after image position has been selected.
+     *  
+     *  @param image_x_dim the width of the image
+     *  @param image_y_dim the height of the image
+     *  @return a transform operation by which to move the image from the origin */
+    protected void random_set_pos(int image_x_dim, int image_y_dim) 
+    {
+
+	double scale_factor = scaleFactor(image_x_dim, image_y_dim);
+
+	// scale the image (will be 1 and therefore no change as a default)
+	image_x_dim/=scale_factor;
+	image_y_dim/=scale_factor;
+	
+	// initialise variables required to determine image placement
+	int image_x_pos = 0;
+	int image_y_pos = 0;
+	int best_x = 0;
+	int best_y = 0;
+	double best_clear = 0;
+	double clear = 100;
+	int stoploop = 0;
+	
+	do {
+	    // increment the loop counter
+	    stoploop++;
+
+	    // the number of positions that the image could occupy on the x axis
+	    int safe_x_dim = DisplayImages.app_x_dim_ - image_x_dim;
+	    double rx = Math.random();
+	    // randomly pick an x co-ordinate for the image
+	    image_x_pos= ((int)(rx*safe_x_dim));
+	    
+	    // same process as for the x co-ordinate
+	    // ensuring the y co-ordinate will fit on the screen
+	    int safe_y_dim = DisplayImages.app_y_dim_ - image_y_dim;
+	    double ry = Math.random();
+	    // randomly pick a y co-ordinate for the image
+	    image_y_pos= ((int)(ry*safe_y_dim));
+	    
+	    double whitespace = 0;
+	    double space = 0;
+	    
+	    // determine how much whitespace the image will cover if placed in the
+	    // current position and how much overlap will occur
+	    for (int n = image_x_pos; n < (image_x_pos + image_x_dim); n++) {
+		for (int m = image_y_pos; m < (image_y_pos + image_y_dim); m++) {
+		    if (DisplayImages.used_space[n][m] == 0)
+			whitespace++;
+		    space++;
+		}
+	    }
+	    
+	    // divide the amount of whitespace covered by the amount of overlap
+	    clear = whitespace/space;
+	    // if this value is better than previous calculations, save these co-ordinates
+	    if (clear > best_clear) {
+		best_x = image_x_pos;
+		best_y = image_y_pos;
+		best_clear = clear;
+	    }
+
+	    if ((image_x_dim > (DisplayImages.app_x_dim_ / 2)) || (image_y_dim > (DisplayImages.app_y_dim_ / 2)))
+		break;
+
+	} while ((clear < 0.70 || (stoploop > 3 && clear < 0.50)) && stoploop < 7);
+	    
+	// if we only terminated because we went through so many times,
+	// then we set the position to the best value possible
+	if (stoploop == 7) {
+	    image_x_pos = best_x;
+	    image_y_pos = best_y;
+	}
+
+	// indicate that the space where the image is to be placed is now used
+	for (int n = image_x_pos; n < (image_x_pos + image_x_dim); n++)
+	    for (int m = image_y_pos; m < (image_y_pos + image_y_dim); m++) {
+		DisplayImages.used_space[n][m]++;
+		if (DisplayImages.used_space[n][m] > DisplayImages.NO_IMAGES_OF_OVERLAP)
+		    overlap = true;
+	    }
+	
+	translateX = image_x_pos;
+	translateY = image_y_pos;
+	
+	// scale the image appropriately
+	scaleX = 1.0/scale_factor;
+	scaleY = 1.0/scale_factor;
+	
+	return;
+    }
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/GS2LuceneIndexer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/GS2LuceneIndexer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/GS2LuceneIndexer.java	(revision 10506)
@@ -0,0 +1,103 @@
+/**
+ *
+ * class for indexing XML generated by lucenebuildproc.pm
+ * @author  kjdon@cs.waikato.ac.nz
+ * @author  davidb@cs.waikato.ac.nz
+ * @version 
+ */
+
+
+import java.io.*;
+import java.util.Vector;
+
+public class GS2LuceneIndexer {
+
+    public static void main (String args[]) throws Exception 
+    { 
+
+	int verbosity = 1;
+	boolean create = false;
+
+	Vector filtered_args = new Vector();
+
+	int argc = args.length;
+	int i = 0;
+	while (i<argc) {
+	    if (args[i].startsWith("-")) {
+
+		// -create causes build to be incremental
+		if (args[i].equals("-create")) {
+		    create = true;
+		}
+
+		// -verbosity [num]
+		else if (args[i].equals("-verbosity")) {
+		    i++;
+		    if (i<argc) {
+			verbosity = Integer.parseInt(args[i]);
+		    }
+		}
+		else {
+		    System.out.println("Unrecognised option: " + args[i]);
+		}
+	    }
+	    else {
+		filtered_args.add((Object)args[i]);
+	    }
+	    i++;
+	}
+
+	if (filtered_args.size() != 3) {
+	    System.out.println("Usage: java GS2LuceneIndexer [-create|-verbosity [num]] doc-tag-level building_dir index");
+	    return;
+	}
+ 
+	String doc_tag_level     = (String)filtered_args.get(0);
+	String building_dirname  = (String)filtered_args.get(1);
+	String index_dirname     = (String)filtered_args.get(2);
+
+	String import_dirname = building_dirname + File.separator + "text";
+
+	File import_dir   = new File(import_dirname);
+	File building_dir = new File(building_dirname);
+
+	if (!import_dir.exists()) {
+	    System.out.println("Couldn't find import directory: "+import_dirname);
+	    return;
+	}
+
+	File idx_dir = new File(building_dir.getPath()+File.separator+index_dirname+File.separator);
+	idx_dir.mkdir();
+	
+	// Set up indexer
+	IndexXML indexer = new IndexXML(doc_tag_level,idx_dir, create);
+	indexer.init();	
+
+	// Read from stdin the files to process
+	try {
+	    InputStreamReader isr = new InputStreamReader(System.in, "UTF-8");
+	    BufferedReader brin = new BufferedReader(isr);
+
+	    StringBuffer xml_text = new StringBuffer(1024);
+	    String line = null;
+	    while ((line = brin.readLine()) != null) {
+		xml_text.append(line);
+		if (line.startsWith("</Doc>")) {
+		    indexer.indexFile(xml_text.toString());
+		    xml_text = new StringBuffer(1024);
+		}
+		//File xml_file = new File(import_dir + File.separator + line);
+		//indexer.indexFile(xml_file); // ****
+	    }
+
+	    brin.close();
+	    isr.close();
+
+	} catch (IOException e) {
+	    System.err.println("Error: unable to read from stdin");
+	    e.printStackTrace();
+	}
+
+	indexer.finish();
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/GS2LuceneQuery.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/GS2LuceneQuery.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/GS2LuceneQuery.java	(revision 10506)
@@ -0,0 +1,82 @@
+/*
+ * search.java
+ *
+ * Created on 25 February 2003, 02:25
+ */
+
+
+/**
+ *
+ * @author  kjdon@cs.waikato.ac.nz
+ * @author  davidb@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 GS2LuceneQuery  {
+
+    public static void main (String args[]) {
+	
+	if (args.length == 0) {
+	    System.out.println("Usage: GS2LuceneQuery <index directory>");
+	    return;
+	}
+        try {
+	    Searcher searcher = new IndexSearcher(args[0]);
+	    Analyzer analyzer = new StandardAnalyzer();
+
+	    BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
+	    while (true) {
+		String line = in.readLine();
+		
+		if (line == null) {
+		    break;
+		}
+
+		if (line.length() == -1)
+		    break;
+		
+
+		// Term term = new Term("TX",line);
+		// Query query = new TermQuery(term);
+
+		System.err.println("**** query = " + line);
+
+		Query query = QueryParser.parse(line, "TX", analyzer);
+		
+		Hits hits = searcher.search(query);
+		System.out.println("<ResultSet>");
+		System.out.println("  <QueryString>" + query.toString("TX")+"</QueryString>");
+		System.out.println("  <MatchingDocsInfo num=\""+hits.length()+"\"/>");
+				
+		for (int i=0; i< hits.length(); i++) {
+		    Document doc = hits.doc(i);
+		    String node_id= doc.get("nodeID");
+		    System.out.println("  <Match id=\""+node_id+"\"/>");
+		}
+		System.out.println("</ResultSet>");
+		
+	    }
+	    
+	    searcher.close();
+	}
+	catch (Exception e) {
+	    System.out.println(" caught a " + e.getClass() +
+			       "\n with message: " + e.getMessage());
+        }
+    }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/IndexXML.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/IndexXML.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/IndexXML.java	(revision 10506)
@@ -0,0 +1,48 @@
+
+/**
+ *
+ * @author  kjdon@cs.waikato.ac.nz
+ * @author  davidb@cs.waikato.ac.nz
+ * @version 
+ */
+
+import java.io.File;
+
+public class IndexXML extends Object {
+
+    String doc_tag_level_ = null;
+    File out_dir_         = null;
+    Indexer indexer_      = null;
+    boolean create_index_ = false;
+
+    public IndexXML(String doc_tag_level, File out_dir, boolean create)
+    {
+	doc_tag_level_ = doc_tag_level;
+	out_dir_ = out_dir;
+	create_index_ = create;
+    }
+
+    public void init() 
+    {
+	indexer_ = new Indexer(doc_tag_level_, out_dir_, create_index_);
+    }
+
+    public void finish() 
+    {
+	indexer_.finish();
+    }
+
+    public void indexFile(File file) 
+    {
+	String name = file.getName();
+	name = name.substring(0, name.lastIndexOf('.'));
+	System.out.println("Indexing "+file.getPath()+" with id "+name);
+	indexer_.index(name, file);
+    }    
+
+    public void indexFile(String xml_text) 
+    {
+	indexer_.index(xml_text);
+    }    
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/Indexer.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/Indexer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/Indexer.java	(revision 10506)
@@ -0,0 +1,247 @@
+
+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.XMLReader;
+
+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.index.IndexWriter;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+
+import java.util.Stack;
+import java.io.FileInputStream;
+import java.io.File;
+import java.io.StringReader;
+import java.net.URL;
+
+
+
+public class Indexer extends DefaultHandler 
+{
+    IndexWriter writer_   = null;
+    SAXParser sax_parser_ = null;
+    String doc_tag_level_ = null;
+
+    Stack stack_ = null;
+    String path_ = "";
+
+    Document current_doc_ = null;
+    String current_node_ = "";
+    String indexable_current_node_ = "";
+    String current_contents_ = "";
+
+    protected String file_id_ = null;
+
+    /** pass in true if want to create a new index, false if want to use the existing one */
+    public Indexer (String doc_tag_level, File index_dir, boolean create) 
+    {
+	doc_tag_level_ = doc_tag_level;
+
+	try {
+	    stack_ = new Stack();
+	    SAXParserFactory sax_factory = SAXParserFactory.newInstance();
+	    sax_parser_ = sax_factory.newSAXParser();
+
+	    XMLReader reader = sax_parser_.getXMLReader(); 
+	    reader.setFeature("http://xml.org/sax/features/validation", false);
+
+	    writer_ = new IndexWriter(index_dir.getPath(), new StandardAnalyzer(), create);
+	    if (create) {
+		writer_.optimize();
+	    }
+
+	} catch (Exception e) {
+	    // do nothing!
+	}
+    }
+
+    /** index one document */
+    public void index (String file_id, File file) 
+    {
+	file_id_ = file_id;
+	path_ = "";
+	String base_path = file.getPath();
+	base_path = base_path.substring(0, base_path.lastIndexOf(File.separatorChar));
+
+	try {	    
+            sax_parser_.parse(new InputSource(new FileInputStream(file)), this);
+        }
+        catch (Exception e) {
+	    println("parse error:");
+            e.printStackTrace();
+	}
+    }
+
+    /** index one document stored as string*/
+    public void index (String xml_text) 
+    {
+	file_id_ = "<xml doc on stdin>";
+	path_ = "";
+
+	try {
+            sax_parser_.parse(new InputSource(new StringReader(xml_text)), this);
+        }
+        catch (Exception e) {
+	    println("parse error:");
+            e.printStackTrace();
+	}
+    }
+    
+    public void finish() 
+    {
+	/** optimise the index */
+	try {
+	    writer_.optimize();
+	    writer_.close();
+	} 
+	catch (Exception e) {
+	}
+    }
+
+    protected void print(String s) 
+    { 
+	System.out.print(s); 
+    }
+
+    protected void println(String s) 
+    { 
+	System.out.println(s); 
+    }
+
+    public void startDocument() throws SAXException 
+    {
+        println("Starting to index " + file_id_);
+        print("[");
+    }
+
+    public void endDocument() throws SAXException 
+    {
+        println("]");
+        println("... indexing finished.");
+    }
+
+    public void startElement(String uri, String localName, String qName, Attributes atts) 
+	throws SAXException 
+    {
+	path_ = appendPathLink(path_, qName, atts);
+
+	if (qName.equals(doc_tag_level_)) {
+	    pushOnStack(); // start new doc
+	    current_node_ = qName;
+	    String node_id = atts.getValue("gs2:id");
+
+	    print(" " + qName + ": " + node_id );
+	    current_doc_.add(Field.UnIndexed("nodeID", node_id));
+	}
+
+	if (XMLTagInfo.isIndexable(atts)) {
+	    indexable_current_node_ = qName;	
+	}
+	else {
+	    indexable_current_node_ = "";
+	}
+
+    }
+    public void endElement(String uri, String localName, String qName) throws SAXException 
+    {
+	if (qName.equals(indexable_current_node_)) {
+	    current_doc_.add(Field.UnStored(qName, current_contents_));
+	    current_contents_ = "";
+	}
+
+	if (qName.equals(doc_tag_level_)) {
+	    try {
+		writer_.addDocument(current_doc_);
+	    } 
+	    catch (java.io.IOException e) {
+		e.printStackTrace();
+	    }
+	    popOffStack(); // end document
+	}
+	
+	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("gs2:id");
+	    if (id != null) {
+		path +=  "[@gs2:id='"+id+"']";
+	    }
+	    else {
+		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_ = "";
+	}
+    }
+
+
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/Makefile
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/Makefile	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/Makefile	(revision 10506)
@@ -0,0 +1,24 @@
+
+
+#CLASSPATH = ./lib/lucene-1.4.jar:./lib/soap.jar:./lib/xercesImpl.jar:./lib/xalan.jar:./lib/xml-apis.jar
+CLASSPATH = classes
+
+
+compile:
+	javac -classpath $(CLASSPATH):. -d classes *.java
+
+jar:
+	jar cvf LuceneWrap.jar -C classes .
+
+install:
+	install LuceneWrap.jar ../../../../../../bin/java/.
+
+build:
+	java -classpath $(CLASSPATH):. BuildXMLColl `pwd` test
+
+search:
+	java -classpath $(CLASSPATH):. Search `pwd`/collect/test/building/idx
+
+clean:
+	/bin/rm -f classes/*.class
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/XMLTagInfo.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/XMLTagInfo.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/LuceneWrap/XMLTagInfo.java	(revision 10506)
@@ -0,0 +1,33 @@
+/** XMLTagInfo
+ * contains any methods that are specific to what kind of XML you are working on
+ */
+
+import org.xml.sax.Attributes;
+
+public class XMLTagInfo {
+
+    public static boolean isDocumentLevel(Attributes atts) 
+    {
+	boolean is_doc_level = false;
+	String id = atts.getValue("gs2:id");
+	if (id!=null) {
+	    is_doc_level = true;
+	}
+	return is_doc_level;
+    }
+
+    public static boolean isIndexable(Attributes atts) 
+    {
+	boolean is_indexable = false;
+
+	String index = atts.getValue("index");
+	if (index!=null) {
+	    if (index.equals("1")) {
+		is_indexable = true;
+	    }
+	}
+	return is_indexable;
+    }
+
+    
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/Makefile
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/Makefile	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/Makefile	(revision 10506)
@@ -0,0 +1,18 @@
+
+
+
+CLASSES = Phind.class ResultCanvas.class ResultItemDocument.class \
+          ResultTitle.class PhindTitle.class ResultDisplay.class \
+          ResultItemLink.class ResultBox.class ResultItem.class \
+          ResultItemPhrase.class PhindTitle.class URLUTF8Encoder.class
+
+all: Phind.jar
+
+clean:
+	rm -f $(CLASSES) Phind.jar
+
+Phind.jar: $(CLASSES)
+	jar cf Phind.jar org
+
+%.class : %.java
+	javac -target 1.1 -d . -classpath ../../../.. $<
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/Phind.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/Phind.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/Phind.java	(revision 10506)
@@ -0,0 +1,1119 @@
+/**********************************************************************
+ *
+ * Phind.java -- the 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.
+ *
+ *********************************************************************/
+
+
+/*********************************************************************
+
+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.nzdl.gsdl.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;
+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.net.URL;
+import java.net.URLConnection;
+import java.io.DataInputStream;
+import java.io.InputStream;
+
+import java.net.Socket;
+//import java.net.SocketTimeoutException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+import java.util.Vector;
+import java.util.Date;
+
+import org.nzdl.gsdl.Phind.URLUTF8Encoder;
+
+public class Phind extends java.applet.Applet {
+    
+    // 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 serach 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.
+
+    /** We're adding a timeout to the loop used to read the result from the
+     *  server - partially because of the 'fails to return anything' death
+     *  spiral - but also because its a good idea anyway. Why DataInputStream
+     *  doesn't have a TimeOutException, given its most often used to get data
+     *  from a URL, I don't know. Lets default it to 60 seconds.
+     *  DLConsulting 12-07-2004
+     */
+    private int timeout = 60;
+
+    public String getAppletInfo() {
+	return "Phind by Gordon Paynter (paynter@cs.waikato.ac.nz). Copyright 1997-2000.";
+    }
+
+
+    public void init() {
+
+	mode = initMode;
+	
+        System.out.println("Java vendor: " + System.getProperty("java.vendor"));
+        System.out.println("Java version: " + System.getProperty("java.version"));
+
+	// 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) {
+	    searchForWord(getSearchTerm());
+	} else if (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;
+    }
+
+
+    // Search for a word 
+    //
+    // Called on two occasions:
+    //   when the "Search" Button is pressed, or
+    //   to perform an "initial search"
+    void searchForWord(String searchWord) {
+
+	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.resize(result.display.size());
+		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.resize(result.display.size());
+		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 + "pxml=1&c=" + collection + "&pc=" + classifier;
+
+	if (keyKnown) {
+	  query = query + "&ppnum=" + word;
+	} else {
+	  query = query + "&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("sending query: " + query);
+	/** Start timeout counter.
+	 *  DLConsulting 12-07-2004
+	 */
+	int time = 0;
+	try {
+	    URL phindcgi = new URL(query);
+            //            DataInputStream in = new DataInputStream(phindcgi.openStream());
+
+            URLConnection conn = phindcgi.openConnection();
+            DataInputStream in = new DataInputStream(conn.getInputStream());
+
+	    byte[] buffer;
+	    int availableBytes = 0;
+
+	    
+	    while (!area.finished) {
+		// Lovely old method, which would work just fine if Sun supported their own API and made
+		// in.available() work.
+
+		/*
+		availableBytes = in.available();
+		if (availableBytes == 0) {
+		    // if i had threads i'd do a wait here for 1 second
+		    /** Ah-ha but we do have threads here - at least one thread 
+		     *  anyway! Note that we want to prevent interrupted 
+		     *  exceptions flinging us out of the read loop.
+		     *  We also check that the time count hasn't reached out
+		     *  timeout threshold yet. If so, make use of the nifty
+		     *  execption handling.
+		     *  DLConsulting 12-07-2004
+		     *  Start...
+		     
+                    System.err.println("No bytes available");
+		    if(time >= timeout) {
+			throw new InterruptedIOException(
+			    "No data recieved in " + time + 
+			    " seconds. Connection timed-out.");
+		    }
+		    try {
+			Thread.sleep(1000);
+		    }
+		    catch(InterruptedException exception) {
+			System.err.println("Unexpected InterruptedException. Non-fatal.");
+			exception.printStackTrace();
+		    }
+		    time++;
+		    /** ...End 
+		} else {
+                    System.err.println("Preparing to read " + availableBytes + " bytes");
+		    buffer = new byte[availableBytes];
+		    in.read(buffer);
+                    System.err.println("Done reading");
+		    area.parseBytes(buffer);
+		}
+		*/
+
+		// New - and hopefully safer - method.
+
+		// Create a new SafeReader, and then wait while it reads
+		// we can watch for timeouts as necessary
+		int timeout = 0;
+		SafeReader reader = new SafeReader(in);
+		reader.start();
+		while(!reader.isComplete()) {
+		    // Wait timeout time.
+		    try {
+			Thread.sleep(1000);
+		    }
+		    catch(InterruptedException exception) {
+			System.err.println("test.init(): Unexpected InterruptedException. Non-fatal.");
+			exception.printStackTrace();
+		    }
+		    // Then see if the readers read anything
+		    if(reader.poll() == 0) {
+			timeout++;
+			// Have we reached timeout?
+			if(timeout > reader.getTimeout()) {
+			    // Nothing been read. Kill the reader
+			    reader.interrupt();
+			    // And throw a hissy fit
+			    throw new InterruptedIOException("No data recieved in " + reader.getTimeout() + 
+							     " seconds. Connection timed-out.");
+			}
+			// Otherwise, wait a little longer.
+		    }
+		    // Otherwise we can continue waiting and polling
+		}
+		// Process the buffer
+		System.err.println("Done reading");
+		area.parseBytes(reader.getBuffer());
+            }
+	    
+	    in.close();
+	} catch (Exception e) {
+	    System.err.println( "Error sending query to phindcgi: " + e);
+	}
+	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 no protocol and host
+	    URL document = getDocumentBase();
+	    String protocol = document.getProtocol();
+	    String host = document.getHost();
+	    String port = "";
+	    if (document.getPort()!=-1) {
+		port = ":" + document.getPort();
+	    }
+	    address = protocol + "://" + host + port + address;
+	} else {
+	    // this URL is relative to the directory the document is in
+	    URL document = getDocumentBase();
+	    String protocol = document.getProtocol();
+	    String host = document.getHost();
+	    String directory = document.getFile();
+	    int end = directory.lastIndexOf('/');
+	    String port = "";
+	    if (document.getPort() != -1) {
+		port = ":" + document.getPort();
+	    }
+	    directory = directory.substring(0, end + 1);
+	    address = protocol + "://" + host + port + directory + address;
+	}
+
+	// if the URL is a cgi script, make sure it has a "?" in it,
+	// 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 phind CGI script
+	phindcgi_address = parameterValue("phindcgi");
+	phindcgi_address = tidy_URL(phindcgi_address, true);
+	System.out.println("Phind phindcgi: " + phindcgi_address);
+
+	// Where is the Greenstone library
+	library_address = parameterValue("library");
+	library_address = tidy_URL(library_address, true);
+	System.out.println("Phind library: " + library_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);
+
+	/** How long should the read loop wait before timing out?
+	 *  DLConsulting 12-07-2004
+	 */
+	timeout = parameterValue("timeout", 60);
+    }
+
+    // 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);
+	    p1.add(searchButton);
+	    
+	    Label tempLabel = new Label("  for");
+	    tempLabel.setFont(boldFont);
+	    p1.add(tempLabel);
+	    
+	    wordField = new TextField(12);
+	    wordField.setFont(boldFont);
+	    p1.add(wordField);
+	    
+	    Label temp2 = new Label("          ");
+	    p1.add(temp2);
+	    
+	    prevButton = new Button("Previous");
+	    prevButton.setFont(boldFont);
+	    prevButton.disable();
+	    
+	    p1.add(prevButton);
+	    
+	    nextButton = new Button("  Next  ");
+	    nextButton.setFont(boldFont);
+	    nextButton.disable();
+	    p1.add(nextButton);
+	    
+	}
+    }
+    
+    // Button and field functionality
+    
+    // Enable and disable the word field
+    void enableSearchButton() {
+	if (showControlPanel) {
+	    searchButton.enable();
+	}
+    }
+    void disableSearchButton() {
+	if (showControlPanel) {
+	    searchButton.disable();
+	}
+    }
+
+    // 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.enable();
+		} else {
+		    prevButton.disable();
+		}
+	    }
+	    
+	    c = lastDisplay.current;
+	    if (c.getClass().getName().endsWith("ResultBox")) {
+		if (((ResultBox) c).nextBoxExists()) {
+		    nextButton.enable();
+		} else {
+		    nextButton.disable();
+		}
+	    }
+	}
+    }
+
+    // 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.resize(b.display.size());
+		    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.resize(b.display.size());
+		    b.paintAll(b.getGraphics());
+		    b = b.next;
+		}
+	    }
+	}
+	enablePreviousAndNext();
+    }
+
+    public class SafeReader 
+	extends Thread {
+	// Has the reader finished reading?
+	private boolean complete;
+	// The buffer in where the data read is stored
+	private byte[] buffer;
+	// The stream this reader reads from
+	private DataInputStream in;
+	// If the bytes_read hasn't changed in this time, then stop this thread
+	// and timeout
+	private int timeout; 
+	// The current buffer size
+	private int buffer_current_size;
+	// The maximum buffer size
+	private int buffer_max_size;
+	// The number of bytes read through this reader since the last poll
+	private int bytes_read;
+
+	/** Default constructor 
+	 *  @param in the DataInputStream to read from
+	 */
+	public SafeReader(DataInputStream in) {
+	    complete = false;
+	    buffer_current_size = 0;
+	    buffer_max_size = 16;
+	    buffer = new byte[buffer_max_size]; // Default size
+	    timeout = 60; // Sixty seconds
+	    bytes_read = 0;
+	    
+	    this.in = in;
+	}
+
+	/** Construct a new SafeReader
+	 *  @param in the DataInputStream to read from
+	 *  @param timeout how long this thread should wait when reading data
+	 */
+	public SafeReader(DataInputStream in, int timeout) {
+	    this(in);
+	    this.timeout = timeout;
+	}
+
+	/** Retrieve the current buffer
+	 *  @return a byte[] buffer trimmed to the appropriate size
+	 */
+	public byte[] getBuffer() {
+	    byte[] final_buffer = new byte[buffer_current_size];
+	    System.arraycopy(buffer, 0, final_buffer, 0, buffer_current_size);
+	    return final_buffer;
+	}
+
+	/** Retrieve the current timeout
+	 *  @return the timeout as an int
+	 */
+	public int getTimeout() {
+	    return timeout;
+	}
+
+	/** See whether the reader has finished reading
+	 *  @return true if the read is complete (-1 bytes read!) or false otherwise
+	 */
+	public synchronized boolean isComplete() {
+	    return complete;
+	}
+
+	/** Poll the reader to determine if it has read any bytes recently
+	 *  @return the number of bytes read
+	 */
+	public long poll() {
+	    // Maybe should test if complete - but its only one second right?
+	    long result = bytes_read;
+	    bytes_read = 0;
+	    return result;
+	}
+
+	/** Try to read bytes from the input stream. Note the caller is responsible for closing the datainputstream
+	 */
+	public void run() {
+	    try {
+		int i = 0;
+		byte[] read_buffer = new byte[8];
+		while ((i = in.read(read_buffer)) != -1) {
+		    // Check our storage buffer is big enough
+		    if(buffer_max_size - (buffer_current_size + i) <= 0) {
+			// Double the size
+			buffer_max_size = 2 * buffer_max_size;
+			byte[] new_buffer = new byte[buffer_max_size];
+			System.arraycopy(buffer, 0, new_buffer, 0, buffer_current_size);
+			buffer = new_buffer;
+		    }
+		    // Then copy in the read buffer
+		    System.arraycopy(read_buffer, 0, buffer, buffer_current_size, i);
+		    buffer_current_size += i;
+		    bytes_read += i;
+		}
+		setComplete(true);
+	    }
+	    catch(IOException exception) {
+		System.err.println("SafeReader.run(): Unexpected IOException. Fatal.");
+		exception.printStackTrace();
+	    }
+	}
+
+	/** Set the complete boolean to the desired state, synchronized to avoid race with isComplete()
+	 *  @param value the desired state
+	 */
+	private synchronized void setComplete(boolean value) {
+	    complete = value;
+	}
+    }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/PhindTitle.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/PhindTitle.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/PhindTitle.java	(revision 10506)
@@ -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.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 = size();
+
+	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: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultBox.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultBox.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultBox.java	(revision 10506)
@@ -0,0 +1,774 @@
+/**********************************************************************
+ *
+ * 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.nzdl.gsdl.Phind;
+
+import java.awt.Panel;
+import java.awt.BorderLayout;
+import java.awt.Scrollbar;
+
+import java.awt.Label;
+import java.awt.Event;
+
+import java.net.*;
+import java.applet.*;
+
+import java.util.Vector;
+
+
+public class ResultBox extends Panel {
+    
+    // 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();
+	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.setLineIncrement(1);
+	    s.setPageIncrement(1);
+	    s.disable();
+	}
+    }
+
+    // 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 boolean handleEvent(Event 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();
+	    return true;
+	} else {
+	    return super.handleEvent(event);
+	}
+    }    
+
+
+    // a new section of the byte stream is read
+    void parseBytes(byte[] bytes) {
+	mode = loadingMode;
+
+	// update the buffer that holds the bytes read
+	String input;
+	try {
+	    input = new String(bytes, new String("UTF8"));
+	} catch (Exception e) {
+	    System.err.println(e);
+	    input = "";
+	}
+	buffer = buffer.concat(input);
+
+	// Parse each line until there are no more lines to parse
+	while(parseLine());
+
+	if (finished) {
+	    c.updateMarkers();
+	    buffer = "";
+	} else {
+	    // We haven't finished, give some feedback about progress
+	    setStatus("Connected to host, " + c.numberOfItems + " results read");
+	}
+    }
+
+    // Parse a line of XML
+    //
+    // This isn't necessarily real XML.  We assume every tag begins and
+    // ends on one line.  We read one line out of the buffer at a time,
+    // then "add" them to the box with the addLine method.
+    //
+    // Return true if there is a another line here to parse, otherwise false.
+
+    boolean parseLine() {
+
+        // System.out.print("parseLine " + "(length " + buffer.length() + ")");
+	String item;
+	int eol = buffer.indexOf((int) '\n');
+
+	// If there are no carriage returns, the line is incomplete
+	if (eol == -1) {
+	    return false;
+	}
+
+	// The </phinddata> tag concludes the dataset
+	else if (buffer.startsWith("</phinddata>")) {
+	    mode = finishedMode;
+	    finished = true;
+	    return false;
+	}
+	
+	// The <expansion> tag
+	else if (buffer.startsWith("<expansion ")) {
+	    item = buffer.substring(0, eol);
+	    buffer = buffer.substring(eol + 1);
+	    addExpansionTag(item);
+	    return true;
+	}
+ 
+	// The <document> tag
+	else if (buffer.startsWith("<document ")) {
+	    item = buffer.substring(0, eol);
+	    buffer = buffer.substring(eol + 1);
+	    addDocumentTag(item);
+	    return true;
+	}
+ 
+	// The <thesaurus> tag
+	else if (buffer.startsWith("<thesaurus ")) {
+	    item = buffer.substring(0, eol);
+	    buffer = buffer.substring(eol + 1);
+	    addThesaurusTag(item);
+	    return true;
+	}
+ 
+	// The <phinddata> tag introduces the dataset
+	else if (buffer.startsWith("<phinddata ")) {
+	    item = buffer.substring(0, eol);
+	    buffer = buffer.substring(eol + 1);
+	    addPhinddataTag(item);
+	    return true;
+	}
+
+	// The <phinderror> tag contains an error message
+	else if (buffer.startsWith("<phinderror")) {
+	    item = buffer.substring(0, eol);
+	    System.out.println("phind reported an error: " + item);
+	    buffer = buffer.substring(eol + 1);
+	    return true;
+	}
+ 
+	// Ignore the piece we've read
+	item = buffer.substring(0, eol);
+	// System.out.println("discarding: " + item);
+	buffer = buffer.substring(eol + 1);
+	return true;
+    }
+    
+
+
+    // Add a phinddata tag
+    //
+    // Given a string containing an XML phinddata tag of the form:
+    //   <phinddata id="35" text="FOREST" df="797" ef="134">
+    // Read the expansion information from the tag
+    //
+    // Return true if successful, otherwise false.
+
+    boolean addPhinddataTag( String line ) {
+
+	// System.out.println( "addExpansionListTag: " + line);
+
+	String idStr = "", text = "", tfStr = "", efStr = "", dfStr = "", lfStr = "";
+	int tf = 0, ef = 0, df = 0, lf = 0;
+
+	// Break the tag down into its component parts
+	int nextSplit;
+       	while (line.length() > 0) {
+	    line = line.trim();
+
+	    // Read the phrase identifier
+	    if (line.startsWith("id")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    idStr = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("addExpansionListTag: error parsing: " + line);
+ 		}
+	    } 
+	    
+	    // Read the total frequency
+	    else if (line.startsWith("tf")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    tfStr = line.substring(0, nextSplit);
+		    tf = Integer.valueOf(tfStr).intValue();
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("addExpansionListTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the text of the phrase
+	    else if (line.startsWith("text")) {
+		line = line.substring(6);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    text = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("addExpansionListTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the expansion frequency
+	    else if (line.startsWith("ef")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    efStr = line.substring(0, nextSplit);
+		    ef = Integer.valueOf(efStr).intValue();
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("addExpansionListTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the document frequency
+	    else if (line.startsWith("df")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    dfStr = line.substring(0, nextSplit);
+		    df = Integer.valueOf(dfStr).intValue();
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("addExpansionListTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the thesaurus link frequency
+	    else if (line.startsWith("lf")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    lfStr = line.substring(0, nextSplit);
+		    lf = Integer.valueOf(lfStr).intValue();
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("addExpansionListTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read and ignore some other tag
+	    else {
+		nextSplit = line.indexOf((int) ' ');
+		if (nextSplit >= 1) {
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    line = "";
+		}
+	    }
+	}
+
+	// Add the data to the ResultBox
+	searchKey = idStr;
+	searchPhrase = text;
+	numberOfOccurances = tf;
+	numberOfExpansions = ef;
+	numberOfDocuments = df;
+	numberOfThesaurusLinks = lf;
+	return true;
+    }
+
+
+    // Add an expansion tag
+    //
+    // Given a string containing an XML expansin tag of the form:
+    //   <expansion num="3" id="8421" prefix="PEOPLE and" suffix="" tf="3" df="3"/>
+    //   <expansion num="4" id="8696" prefix="" suffix="products" tf="3" df="3"/>
+    // Create a new ResultItemPhrase for display
+    //
+    // Return true if successful, otherwise false.
+
+    boolean addExpansionTag( String line ) {
+
+	// System.out.println( "addExpansionTag: " + line + " (" + expansionsRetrieved + ")");
+
+	String numStr = "", idStr = "", tfStr = "", dfStr = "", 
+	    prefix = "", body = "", suffix = "";
+
+	body = searchPhrase;
+
+	// Break the tag down into its component parts
+	line = line.substring(11);
+	int nextSplit;
+       	while (line.length() > 0) {
+	    line = line.trim();
+
+	    // Read the expansion number
+	    if (line.startsWith("num")) {
+		line = line.substring(5);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    numStr = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the phrase ID
+	    else if (line.startsWith("id")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    idStr = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the prefix of the phrase
+	    else if (line.startsWith("prefix")) {
+		line = line.substring(8);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 0) {
+		    prefix = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the suffix of the phrase
+	    else if (line.startsWith("suffix")) {
+		line = line.substring(8);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 0) {
+		    suffix = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the frequency
+	    else if (line.startsWith("tf")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    tfStr = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the document frequency
+	    else if (line.startsWith("df")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    dfStr = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read some other tag
+	    else {
+		nextSplit = line.indexOf((int) ' ');
+		if (nextSplit >= 1) {
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    line = "";
+		}
+	    }
+	}
+	
+	// Create a new ResultItem and add it to the display
+	ResultItemPhrase ri = new ResultItemPhrase(idStr, tfStr, dfStr, prefix, body, suffix);
+	
+	if (c.addResultItem(ri)) {
+	    expansionsRetrieved++;
+	    return true;
+	}
+	
+	return false;
+    }
+
+
+    // Add an document tag
+    //
+    // Given a string containing an XML document tag of the form:
+    //   <document num="2" hash="HASH424e64b811fdad933be69c" freq="1" title="CONTENTS"/>
+    //   <document num="3" hash="HASH01f08efd8752ad54ca0a99cf" freq="1" title="Tree mixtures"/>
+    //
+    // Create a new ResultItemDocument for display
+    //
+    // Return true if successful, otherwise false.
+
+    boolean addDocumentTag( String line ) {
+
+	// System.out.println( "addDocumentTag: " + line + " (" + documentsRetrieved + ")");
+	
+	String num = "", hash = "", freq = "", title = "";
+	line = line.substring(9);
+	
+	// Break the tag down into its component parts
+	int nextSplit;
+       	while (line.length() > 0) {
+	    line = line.trim();
+
+	    // Read the expansion number
+	    if (line.startsWith("num")) {
+		line = line.substring(5);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    num = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addDocumentTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the document OID hash
+	    else if (line.startsWith("hash")) {
+		line = line.substring(6);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    hash = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addDocumentTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the document frequency
+	    else if (line.startsWith("freq")) {
+		line = line.substring(6);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    freq = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addDocumentTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the title
+	    else if (line.startsWith("title")) {
+		line = line.substring(7);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    title = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addDocumentTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read some other tag or close the string off
+	    else {
+		nextSplit = line.indexOf((int) ' ');
+		if (nextSplit >= 1) {
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    line = "";
+		}
+	    }
+	}
+	
+	// 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 a string containing an XML document tag of the form:
+    //
+    // <thesaurus num="3" id="36506" tf="0" df="0" type="RT" text="ANGLOPHONE AFRICA"/>
+    // <thesaurus num="4" id="28724" tf="0" df="0" type="RT" text="FRANCOPHONE AFRICA"/>
+    //
+    // Create a new ResultItemLink for display
+    //
+    // Return true if successful, otherwise false.
+
+    boolean addThesaurusTag( String line ) {
+    
+	// System.out.println( "addThesaurusTag: " + line + " (" + thesaurusLinksRetrieved + ")");
+
+	String num = "", id = "", tf = "", df = "", type = "", text = "";
+	line = line.substring(10);
+
+	// Break the tag down into its component parts
+	int nextSplit;
+       	while (line.length() > 0) {
+	    line = line.trim();
+
+	    // Read the expansion number
+	    if (line.startsWith("num")) {
+		line = line.substring(5);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    num = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addThesaurusTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the phrase ID
+	    else if (line.startsWith("id")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    id = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addThesaurusTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the phrase link type
+	    else if (line.startsWith("type")) {
+		line = line.substring(6);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    type = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addThesaurusTag: error parsing: " + line);
+ 		}
+	    } 
+
+
+	    // Read the phrase text
+	    else if (line.startsWith("text")) {
+		line = line.substring(6);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    text = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addThesaurusTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the frequency
+	    else if (line.startsWith("tf")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    tf = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
+ 		}
+	    } 
+
+	    // Read the document frequency
+	    else if (line.startsWith("df")) {
+		line = line.substring(4);
+		nextSplit = line.indexOf((int) '"');
+		if (nextSplit >= 1) {
+		    df = line.substring(0, nextSplit);
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
+ 		}
+	    } 
+
+
+	    // Read some other tag or close the string off
+	    else {
+		nextSplit = line.indexOf((int) ' ');
+		if (nextSplit >= 1) {
+		    line = line.substring(nextSplit + 1);
+		} else {
+		    line = "";
+		}
+	    }
+	}
+	
+	// Create a new ResultItem and add it to the display
+	ResultItemLink ri = new ResultItemLink(id, text, type, tf, df);
+
+	if (c.addResultItem(ri)) {
+	    thesaurusLinksRetrieved++;
+	    return true;
+	}
+	
+	return false;
+    }
+}
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultCanvas.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultCanvas.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultCanvas.java	(revision 10506)
@@ -0,0 +1,557 @@
+/**********************************************************************
+ *
+ * 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.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.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;
+	}
+
+    }
+
+    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() ");
+
+	// 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();
+	Dimension canvasSize = size();
+
+	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);
+	}
+    }
+
+    // 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 handleEvent(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&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&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();
+	    }
+	}
+	return true;
+    }    
+  
+}
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultDisplay.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultDisplay.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultDisplay.java	(revision 10506)
@@ -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.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: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItem.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItem.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItem.java	(revision 10506)
@@ -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.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: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItemDocument.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItemDocument.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItemDocument.java	(revision 10506)
@@ -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.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: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItemLink.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItemLink.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItemLink.java	(revision 10506)
@@ -0,0 +1,86 @@
+/**********************************************************************
+ *
+ * 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.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: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItemPhrase.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItemPhrase.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultItemPhrase.java	(revision 10506)
@@ -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;
+
+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: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultTitle.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultTitle.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/ResultTitle.java	(revision 10506)
@@ -0,0 +1,163 @@
+/**********************************************************************
+ *
+ * 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;
+
+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();
+    Dimension d = size();
+    d.height = phind.fontSize + 10;
+    //setSize(d);
+    resize(d);
+    
+  }
+
+  public void update(Graphics g) {
+    paint(g);
+  }
+
+  public void paint(Graphics g) {
+
+    // calculate the canvas size, margins, and spacing
+    Dimension canvasSize = size();
+    
+    g.setFont(plain);
+    int margin = g.getFontMetrics().stringWidth(" 8888 ");
+    int y = phind.fontSize + 5;
+
+    int rightMargin = canvas.size().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: /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/URLUTF8Encoder.java
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/URLUTF8Encoder.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/java/org/nzdl/gsdl/Phind/URLUTF8Encoder.java	(revision 10506)
@@ -0,0 +1,159 @@
+/**********************************************************************
+ *
+ *
+ * URLUTF8Encoder.java -- encode UTF8 String into a URL form
+ *
+ * W3C® SOFTWARE NOTICE AND LICENSE
+ *
+ * Copyright © 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 ©
+ *      [$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;
+
+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: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/COPYING
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/COPYING	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/COPYING	(revision 10506)
@@ -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: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/Makefile.in	(revision 10506)
@@ -0,0 +1,113 @@
+# Main Makefile for GNU tar.
+# Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+ 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+ 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ 
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+@SET_MAKE@
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+ 
+
+CC = @CC@
+CPP = @CXX@
+CFLAGS = @CFLAGS@ -ansi
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@  
+TOUCH = echo timestamp >
+ 
+bindir = $(exec_prefix)/bin
+infodir = $(prefix)/info
+libexecdir = $(exec_prefix)/libexec
+ 
+MDEFINES = 
+#CC='$(CC)' CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS)' LIBS='$(LIBS)' \
+#prefix='$(prefix)' exec_prefix='$(exec_prefix)' \
+#bindir='$(bindir)' libexecdir='$(libexecdir)' \
+#infodir='$(infodir)' infodir='$(infodir)' libexecdir='$(libexecdir)'
+
+SUBDIRS = lib text
+
+
+.SUFFIXES:
+
+all install uninstall execinstall execuninstall maninstall manuninstall:
+#config.h
+	for subdir in $(SUBDIRS); do \
+	  echo making $@ in $$subdir; \
+	  (cd $$subdir && $(MAKE) $(MDEFINES) $@) || exit 1; \
+	done
+
+# Have not written any texinfo files for the documentation yet
+#info dvi:
+#	cd doc && $(MAKE) $@
+
+mostlyclean: mostlyclean-recursive mostlyclean-local
+
+clean: clean-recursive clean-local
+
+# toplevel Makefile does our subdirs already (jrm21)
+#distclean: distclean-recursive distclean-local
+#	rm config.status
+distclean:
+
+maintainer-clean: maintainer-clean-recursive maintainer-clean-local
+	rm config.status
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	for subdir in $(SUBDIRS); do \
+	  target=`echo $@ | sed 's/-recursive//'`; \
+	  echo making $$target in $$subdir; \
+	  (cd $$subdir && $(MAKE) $$target) || exit 1; \
+	done
+
+mostlyclean-local:
+
+clean-local: mostlyclean-local
+
+distclean-local: clean-local
+	rm -f Makefile config.cache config.h config.log stamp-h
+
+maintainer-clean-local: distclean-local
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+distdir = $(PACKAGE)-$(VERSION)
+
+distname = $(distdir)
+
+DISTFILES = \
+INSTALL.mg INSTALL README README.port COPYING MODIFICATIONS about_mg.html \
+Makefile.in acconfig.h aclocal.m4 configure.in install-sh mkinstalldirs \
+config.guess config.sub \
+config.h.in configure stamp-h.in
+
+#-----------------------------------------------------------------
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/acconfig.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/acconfig.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/acconfig.h	(revision 10506)
@@ -0,0 +1,41 @@
+/* Special definitions for mg, processed by autoheader.
+   Created by [TS:Aug/95] 
+   by grepping for AC_DEFINE on configure.in and using the appropriate defs 
+   of acconfig.h used by GNU tar.
+*/
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define if `union wait' is the type of the first arg to wait functions.  */
+#undef HAVE_UNION_WAIT
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Define to 1 if GNU readline should be used. */
+#undef WITH_GNU_READLINE
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define to 1 to override the automatic selection of "long long" */
+#undef DISABLE_LONG_LONG
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/aclocal.m4
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/aclocal.m4	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/aclocal.m4	(revision 10506)
@@ -0,0 +1,225 @@
+# Local additions to Autoconf macros.
+# Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+# François Pinard <pinard@iro.umontreal.ca>, 1992.
+
+# [TS:Aug/95] - chopped out the NLS stuff which I don't support
+
+## ------------------------------- ##
+## Check for function prototypes.  ##
+## ------------------------------- ##
+
+AC_DEFUN(fp_C_PROTOTYPES,
+[AC_REQUIRE([fp_PROG_CC_STDC])
+AC_MSG_CHECKING([for function prototypes])
+if test "$ac_cv_prog_cc_stdc" != no; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(PROTOTYPES)
+  U= ANSI2KNR=
+else
+  AC_MSG_RESULT(no)
+  U=_ ANSI2KNR=ansi2knr
+fi
+AC_SUBST(U)dnl
+AC_SUBST(ANSI2KNR)dnl
+])
+
+## ----------------------------------------- ##
+## ANSIfy the C compiler whenever possible.  ##
+## ----------------------------------------- ##
+
+# @defmac AC_PROG_CC_STDC
+# @maindex PROG_CC_STDC
+# @ovindex CC
+# If the C compiler in not in ANSI C mode by default, try to add an option
+# to output variable @code{CC} to make it so.  This macro tries various
+# options that select ANSI C on some system or another.  It considers the
+# compiler to be in ANSI C mode if it defines @code{__STDC__} to 1 and
+# handles function prototypes correctly.
+#
+# If you use this macro, you should check after calling it whether the C
+# compiler has been set to accept ANSI C; if not, the shell variable
+# @code{ac_cv_prog_cc_stdc} is set to @samp{no}.  If you wrote your source
+# code in ANSI C, you can make an un-ANSIfied copy of it by using the
+# program @code{ansi2knr}, which comes with Ghostscript.
+# @end defmac
+
+AC_DEFUN(fp_PROG_CC_STDC,
+[AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
+AC_CACHE_VAL(ac_cv_prog_cc_stdc,
+[ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  AC_TRY_COMPILE(
+[#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+], [int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};],
+[ac_cv_prog_cc_stdc="$ac_arg"; break])
+done
+CFLAGS="$ac_save_CFLAGS"
+])
+AC_MSG_RESULT($ac_cv_prog_cc_stdc)
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+])
+
+## --------------------------------------------------------- ##
+## Use AC_PROG_INSTALL, supplementing it with INSTALL_SCRIPT ##
+## substitution.					     ##
+## --------------------------------------------------------- ##
+
+AC_DEFUN(fp_PROG_INSTALL,
+[AC_PROG_INSTALL
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL} -m 755'
+AC_SUBST(INSTALL_SCRIPT)dnl
+])
+
+## ----------------------------------- ##
+## Check if --with-dmalloc was given.  ##
+## ----------------------------------- ##
+
+# I just checked, and GNU rx seems to work fine with a slightly
+# modified GNU m4.  So, I put out the test below in my aclocal.m4,
+# and will try to use it in my things.  The idea is to distribute
+# rx.[hc] and regex.[hc] together, for a while.  The WITH_REGEX symbol
+# (which should also be documented in acconfig.h) is used to decide
+# which of regex.h or rx.h should be included in the application.
+#
+# If `./configure --with-regex' is given, the package will use
+# the older regex.  Else, a check is made to see if rx is already
+# installed, as with newer Linux'es.  If not found, the package will
+# use the rx from the distribution.  If found, the package will use
+# the system's rx which, on Linux at least, will result in a smaller
+# executable file.
+
+AC_DEFUN(fp_WITH_DMALLOC,
+[AC_MSG_CHECKING(if malloc debugging is wanted)
+AC_ARG_WITH(dmalloc,
+[  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz],
+[if test "$withval" = yes; then
+  AC_MSG_RESULT(yes)
+  AC_DEFINE(WITH_DMALLOC)
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  AC_MSG_RESULT(no)
+fi], [AC_MSG_RESULT(no)])
+])
+
+## --------------------------------- ##
+## Check if --with-regex was given.  ##
+## --------------------------------- ##
+
+AC_DEFUN(fp_WITH_REGEX,
+[AC_MSG_CHECKING(which of rx or regex is wanted)
+AC_ARG_WITH(regex,
+[  --with-regex            use older regex in lieu of GNU rx for matching],
+[if test "$withval" = yes; then
+  ac_with_regex=1
+  AC_MSG_RESULT(regex)
+  AC_DEFINE(WITH_REGEX)
+  LIBOBJS="$LIBOBJS regex.o"
+fi])
+if test -z "$ac_with_regex"; then
+  AC_MSG_RESULT(rx)
+  AC_CHECK_FUNC(re_rx_search, , 
+   [AC_CHECK_SIZEOF(unsigned char *, unsigned char *)  
+    if test "$ac_cv_sizeof_unsigned_char_p" = 8
+    then
+      AC_MSG_WARN(I'm forcing you to use regex because I can't 
+        find a local rx library and the one included with this 
+        distribution doesn't work on 64-bit machines like yours)
+      [LIBOBJS="$LIBOBJS regex.o"]
+    else
+      [LIBOBJS="$LIBOBJS rx.o"]
+    fi]
+  )
+fi
+AC_SUBST(LIBOBJS)dnl
+])
+
+
+## --------------------------------------- ##
+## Check if --with-gnu-readline was given. ##
+## --------------------------------------- ##
+
+AC_DEFUN(fp_WITH_GNU_READLINE,
+[AC_MSG_CHECKING(whether GNU readline requested)
+  AC_ARG_WITH(gnu_readline,
+    [  --with-gnu-readline     compile with GNU readline support],
+    [if test "$withval" = yes; then
+      AC_MSG_RESULT(yes)
+      ac_with_gnu_readline=1
+    else
+      AC_MSG_RESULT(no)
+    fi],
+    AC_MSG_RESULT(no))
+
+  if test -n "$ac_with_gnu_readline"; then
+    AC_CHECK_HEADER(readline/readline.h, ac_mg_readline_header_found=1,
+	AC_MSG_WARN(Can't find GNU readline headers; configuring without \
+GNU readline support))
+    if test -n "$ac_mg_readline_header_found"; then
+      # first check whether we can find the readline library itself
+      AC_CHECK_LIB(readline, main, 
+        [ac_mg_readline_lib_found=1
+         AC_DEFINE(WITH_GNU_READLINE)
+         LIBS="$LIBS -lreadline"],
+        AC_MSG_WARN(Can't find GNU readline library; configuring without \
+GNU readline support))
+      if test -n "$ac_mg_readline_lib_found"; then
+        # on some systems, readline needs curses.  It is difficult to 
+        #  determine whether this is necessary on the current system,
+        #  since other undefined symbols can be turned up by an
+        #  AC_CHECK_LIB(readline, readline) test that are actually defined
+	#  by mg itself (e.g. xmalloc, xrealloc).  So, if we find libcurses,
+	#  we just bung it on and hope for the best.
+	AC_CHECK_LIB(curses, main,
+	  LIBS="$LIBS -lcurses")
+      fi
+    fi
+  fi
+])	
+
+
+
+#AC_DEFUN(fp_WITH_GNU_READLINE,
+#[AC_MSG_CHECKING(whether GNU readline requested)
+#  AC_ARG_WITH(gnu-readline,
+#    [  --with-gnu-readline   compile with GNU readline support],
+#    [if test "$withval" = yes; then
+#      AC_MSG_RESULT(yes)
+#      ac_with_gnu_readline=1
+#    else
+#      AC_MSG_RESULT(no)
+#    fi],
+#    AC_MSG_RESULT(no))
+#  if test -n "$ac_with_gnu_readline"; then
+#    AC_CHECK_LIB(readline, main, 
+#      AC_CHECK_HEADER(readline/readline.h,
+#	[AC_DEFINE(WITH_GNU_READLINE)
+## curses required on some systems (DEC OSF/1), but not on others (GNU/Linux,
+##  Solaris 2.6).  Forcing its inclusion is unsophisticated; if it causes 
+##  any actual problems on any UNIX platforms, let the maintainer know.
+#	LIBS="$LIBS -lreadline -lcurses"],
+#        AC_MSG_WARN(Can't find GNU readline headers: configuring \
+#without GNU readline support)
+#      ),
+#      AC_MSG_WARN(Can't find GNU readline library: configuring \
+#without GNU readline support)
+#    )
+#  fi 
+#])
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/config.guess
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/config.guess	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/config.guess	(revision 10506)
@@ -0,0 +1,470 @@
+#!/bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    alpha:OSF1:V*:*)
+	# After 1.2, OSF1 uses "V1.3" for uname -r.
+	echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^V//'`
+	exit 0 ;;
+    alpha:OSF1:*:*)
+	# 1.2 uses "1.2" for uname -r.
+	echo alpha-dec-osf${UNAME_RELEASE}
+        exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit 0;;
+    Pyramid*:OSx*:*:*)
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit 0 ;;
+    sun4*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:*:*)
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit 0 ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    mips:*:5*:RISCos)
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit 0 ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit 0 ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit 0 ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    AViiON:dgux:*:*)
+	if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+	     -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	fi
+ 	exit 0 ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit 0 ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit 0 ;;
+    *:IRIX:*:*)
+	echo mips-sgi-irix${UNAME_RELEASE}
+	exit 0 ;;
+    i[34]86:AIX:*:*)
+	echo i386-ibm-aix
+	exit 0 ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		sed 's/^		//' << EOF >dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+		rm -f dummy.c dummy
+		echo rs6000-ibm-aix3.2.5
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit 0 ;;
+    *:AIX:*:4)
+	if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if grep bos410 /usr/include/stdio.h >/dev/null 2>&1; then
+		IBM_REV=4.1
+	elif grep bos411 /usr/include/stdio.h >/dev/null 2>&1; then
+		IBM_REV=4.1.1
+	else
+		IBM_REV=4.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit 0 ;;
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit 0 ;;
+    9000/[3478]??:HP-UX:*:*)
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/7?? | 9000/8?7 ) HP_ARCH=hppa1.1 ;;
+	    9000/8?? )            HP_ARCH=hppa1.0 ;;
+	esac
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    3050*:HI-UX:*:*)
+	sed 's/^	//' << EOF >dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+	rm -f dummy.c dummy
+	echo unknown-hitachi-hiuxwe2
+	exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?7:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit 0 ;;
+    hp7??:OSF1:*:* | hp8?7:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit 0 ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*X-MP:UNICOS:*:*)
+	echo xmp-cray-unicos
+        exit 0 ;;
+    CRAY*Y-MP:UNICOS:*:*)
+	echo ymp-cray-unicos
+        exit 0 ;;
+    CRAY-2:UNICOS:*:*)
+	echo cray2-cray-unicos
+        exit 0 ;;
+    hp3[0-9][05]:NetBSD:*:*)
+	echo m68k-hp-netbsd${UNAME_RELEASE}
+	exit 0 ;;
+    i[34]86:BSD/386:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:FreeBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit 0 ;;
+    *:NetBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+	exit 0 ;;
+    *:GNU:*:*)
+	echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit 0 ;;
+    *:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux
+	exit 0 ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+    i[34]86:DYNIX/ptx:4*:*)
+	echo i386-sequent-sysv4
+	exit 0 ;;
+    i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+	else
+		echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit 0 ;;
+    i[34]86:*:3.2:*)
+	if /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+		echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
+	elif test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-unknown-isc$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-unknown-sysv32
+	fi
+	exit 0 ;;
+    Intel:Mach:3*:*)
+	echo i386-unknown-mach3
+	exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit 0 ;;
+    M680[234]0:*:R3V[567]*:*)
+	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
+        uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4.3 && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m680[234]0:LynxOS:2.2*:*)
+	echo m68k-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit 0 ;;
+    i[34]86:LynxOS:2.2*:*)
+	echo i386-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    TSUNAMI:LynxOS:2.2*:*)
+	echo sparc-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    rs6000:LynxOS:2.2*:*)
+	echo rs6000-lynx-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >dummy.c <<EOF
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+  printf ("m68k-sony-newsos\n"); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  printf ("%s-next-nextstep%s\n", __ARCHITECTURE__,  version==2 ? "2" : "3");
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-unknown-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+  printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+  printf ("vax-dec-bsd\n"); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
+rm -f dummy.c dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit 0 ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit 0 ;;
+    c34*)
+	echo c34-convex-bsd
+	exit 0 ;;
+    c38*)
+	echo c38-convex-bsd
+	exit 0 ;;
+    c4*)
+	echo c4-convex-bsd
+	exit 0 ;;
+    esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/config.h.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/config.h.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/config.h.in	(revision 10506)
@@ -0,0 +1,183 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if using alloca.c.  */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+   This function is required for alloca.c support on those systems.  */
+#undef CRAY_STACKSEG_END
+
+/* Define if you have alloca, as a function or macro.  */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix).  */
+#undef HAVE_ALLOCA_H
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function.  */
+#undef HAVE_VPRINTF
+
+/* Define if on MINIX.  */
+#undef _MINIX
+
+/* Define to `long' if <sys/types.h> doesn't define.  */
+#undef off_t
+
+/* Define if the system does not provide POSIX.1 features except
+   with this defined.  */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work.  */
+#undef _POSIX_SOURCE
+
+/* Define as the return type of signal handlers (int or void).  */
+#undef RETSIGTYPE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+   direction of stack growth for your system; otherwise it will be
+   automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>.  */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if your <sys/time.h> declares struct tm.  */
+#undef TM_IN_SYS_TIME
+
+/* Define to the name of the distribution.  */
+#undef PACKAGE
+
+/* Define to the version of the distribution.  */
+#undef VERSION
+
+/* Define to 1 if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define to 1 if ANSI function prototypes are usable.  */
+#undef PROTOTYPES
+
+ 
+/* Define to 1 for better use of the debugging malloc library.  See
+   site ftp.antaire.com in antaire/src, file dmalloc/dmalloc.tar.gz.  */
+#undef WITH_DMALLOC
+
+ 
+/* Define to 1 if GNU regex should be used instead of GNU rx.  */
+#undef WITH_REGEX
+
+/* Define to 1 if GNU readline should be used. */
+#undef WITH_GNU_READLINE
+
+/* Some braindead header files do not have the requ'd function declarations */
+#undef HAVE_FGETC_DECL
+#undef HAVE_FREAD_DECL
+
+/* See if have this field in the prstatus_t structure */
+/* It stores the size of the process heap */
+#undef HAVE_PR_BRKSIZE
+
+/* Define to 1 to override the automatic selection of "long long" */
+#undef DISABLE_LONG_LONG
+
+/* The number of bytes in a unsigned char *.  */
+#undef SIZEOF_UNSIGNED_CHAR_P
+
+/* Define if you have the ftime function.  */
+#undef HAVE_FTIME
+
+/* Define if you have the ftruncate function.  */
+#undef HAVE_FTRUNCATE
+
+/* Define if you have the getpagesize function.  */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the mallinfo function.  */
+#undef HAVE_MALLINFO
+
+/* Define if you have the select function.  */
+#undef HAVE_SELECT
+
+/* Define if you have the setbuffer function.  */
+#undef HAVE_SETBUFFER
+
+/* Define if you have the strcasecmp function.  */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strftime function.  */
+#undef HAVE_STRFTIME
+
+/* Define if you have the strstr function.  */
+#undef HAVE_STRSTR
+
+/* Define if you have the strtol function.  */
+#undef HAVE_STRTOL
+
+/* Define if you have the times function.  */
+#undef HAVE_TIMES
+
+/* Define if you have the valloc function.  */
+#undef HAVE_VALLOC
+
+/* Define if you have the <dirent.h> header file.  */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <fcntl.h> header file.  */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file.  */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <memory.h> header file.  */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <ndir.h> header file.  */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <string.h> header file.  */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file.  */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/ndir.h> header file.  */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/procfs.h> header file.  */
+#undef HAVE_SYS_PROCFS_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the m library (-lm).  */
+#undef HAVE_LIBM
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/config.sub
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/config.sub	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/config.sub	(revision 10506)
@@ -0,0 +1,793 @@
+#!/bin/sh
+# Configuration validation subroutine script, version 1.1.
+#   Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can. 
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+# First pass through any local machine types.
+case $1 in
+	*local*)
+		echo $1
+		exit 0
+		;;
+	*)
+	;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS (if any).
+basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+if [ $basic_machine != $1 ]
+then os=`echo $1 | sed 's/.*-/-/'`
+else os=; fi
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp )
+		os=
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+		;;
+	-lynx)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	tahoe | i[345]86 | i860 | m68k | m68000 | m88k | ns32k | arm | pyramid \
+		| tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
+		| alpha | we32k | ns16k | clipper | sparclite | i370 | sh \
+		| powerpc | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
+		| pdp11 | mips64el | mips64orion | mips64orionel )
+		basic_machine=$basic_machine-unknown
+		;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	vax-* | tahoe-* | i[345]86-* | i860-* | m68k-* | m68000-* | m88k-* \
+	      | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
+	      | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+	      | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
+	      | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
+	      | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
+	      | pdp11-* | sh-* | powerpc-* | sparc64-* | mips64-* | mipsel-* \
+	      | mips64el-* | mips64orion-* | mips64orionel-* )
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-cbm
+		;;
+	amigados)
+		basic_machine=m68k-cbm
+		os=-amigados
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-cbm
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	cray2)
+		basic_machine=cray2-cray
+		os=-unicos
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i[345]86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv32
+		;;
+	i[345]86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv4
+		;;
+	i[345]86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-sysv
+		;;
+	i[345]86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+		os=-solaris2
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+        pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pentium-*)
+		# We will change tis to say i586 once there has been
+		# time for various packages to start to recognize that.
+		basic_machine=i486-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	xmp)
+		basic_machine=xmp-cray
+		os=-unicos
+		;;
+        xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	mips)
+		basic_machine=mips-mips
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sparc)
+		basic_machine=sparc-sun
+		;;
+        cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative must end in a *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[345]* \
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
+	      | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
+	      | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \
+	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+	      | -ptx* | -coff* | -winnt*)
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	*-acorn)
+		os=-riscix1.2
+		;;
+        pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigados
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+        *-gould)
+		os=-sysv
+		;;
+        *-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+        *-sgi)
+		os=-irix
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-lynxos*)
+				vendor=lynx
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/configure
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/configure	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/configure	(revision 10506)
@@ -0,0 +1,3380 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+  --with-dmalloc          use dmalloc, as in
+                          ftp://ftp.letters.com/src/dmalloc/dmalloc.tar.gz"
+ac_help="$ac_help
+  --with-regex            use older regex in lieu of GNU rx for matching"
+ac_help="$ac_help
+  --with-gnu-readline     compile with GNU readline support"
+ac_help="$ac_help
+  --enable-override-longlong
+                          overide use of long long with GCC"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=text/MGQuery.cpp
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+
+PACKAGE=mgpp
+VERSION=1.3
+
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+
+for ac_prog in $CCC c++ g++ gcc CC cxx cc++ cl
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:575: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CXX="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CXX="$ac_cv_prog_CXX"
+if test -n "$CXX"; then
+  echo "$ac_t""$CXX" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$CXX" && break
+done
+test -n "$CXX" || CXX="gcc"
+
+
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:607: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5
+
+ac_ext=C
+# CXXFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='${CXX-g++} -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cxx_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 618 "configure"
+#include "confdefs.h"
+
+int main(){return(0);}
+EOF
+if { (eval echo configure:623: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cxx_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cxx_cross=no
+  else
+    ac_cv_prog_cxx_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cxx_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cxx_works" 1>&6
+if test $ac_cv_prog_cxx_works = no; then
+  { echo "configure: error: installation or configuration problem: C++ compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:649: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cxx_cross" 1>&6
+cross_compiling=$ac_cv_prog_cxx_cross
+
+echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
+echo "configure:654: checking whether we are using GNU C++" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.C <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:663: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gxx=yes
+else
+  ac_cv_prog_gxx=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gxx" 1>&6
+
+if test $ac_cv_prog_gxx = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+
+ac_test_CXXFLAGS="${CXXFLAGS+set}"
+ac_save_CXXFLAGS="$CXXFLAGS"
+CXXFLAGS=
+echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
+echo "configure:682: checking whether ${CXX-g++} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.cc
+if test -z "`${CXX-g++} -g -c conftest.cc 2>&1`"; then
+  ac_cv_prog_cxx_g=yes
+else
+  ac_cv_prog_cxx_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cxx_g" 1>&6
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS="$ac_save_CXXFLAGS"
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:718: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_AWK="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+  echo "$ac_t""$AWK" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
+done
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:752: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_YACC="$ac_prog"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+  echo "$ac_t""$YACC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:785: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:815: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:866: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:898: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 909 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:914: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:940: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:945: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:954: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:973: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1035: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1088: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+  rm -f conftestdata
+  ac_cv_prog_LN_S="ln -s"
+else
+  ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+  echo "$ac_t""yes" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1109: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1138: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1167: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1182 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1188: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1199 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1205: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1216 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1222: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for AIX""... $ac_c" 1>&6
+echo "configure:1247: checking for AIX" >&5
+cat > conftest.$ac_ext <<EOF
+#line 1249 "configure"
+#include "confdefs.h"
+#ifdef _AIX
+  yes
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "yes" >/dev/null 2>&1; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
+#define _ALL_SOURCE 1
+EOF
+
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+fi
+rm -f conftest*
+
+
+echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
+echo "configure:1271: checking for POSIXized ISC" >&5
+if test -d /etc/conf/kconfig.d &&
+  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
+then
+  echo "$ac_t""yes" 1>&6
+  ISC=yes # If later tests want to check for ISC.
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  if test "$GCC" = yes; then
+    CC="$CC -posix"
+  else
+    CC="$CC -Xp"
+  fi
+else
+  echo "$ac_t""no" 1>&6
+  ISC=
+fi
+
+ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
+echo "configure:1293: checking for minix/config.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1298 "configure"
+#include "confdefs.h"
+#include <minix/config.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1303: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  MINIX=yes
+else
+  echo "$ac_t""no" 1>&6
+MINIX=
+fi
+
+if test "$MINIX" = yes; then
+  cat >> confdefs.h <<\EOF
+#define _POSIX_SOURCE 1
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _POSIX_1_SOURCE 2
+EOF
+
+  cat >> confdefs.h <<\EOF
+#define _MINIX 1
+EOF
+
+fi
+
+echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6
+echo "configure:1341: checking for ${CC-cc} option to accept ANSI C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CFLAGS="$CFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX			-Aa -D_HPUX_SOURCE
+# SVR4			-Xc
+for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" -Xc
+do
+  CFLAGS="$ac_save_CFLAGS $ac_arg"
+  cat > conftest.$ac_ext <<EOF
+#line 1357 "configure"
+#include "confdefs.h"
+#if !defined(__STDC__) || __STDC__ != 1
+choke me
+#endif	
+
+int main() {
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+; return 0; }
+EOF
+if { (eval echo configure:1369: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_prog_cc_stdc="$ac_arg"; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+CFLAGS="$ac_save_CFLAGS"
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_stdc" 1>&6
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno) ;;
+  *) CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+
+echo $ac_n "checking for function prototypes""... $ac_c" 1>&6
+echo "configure:1390: checking for function prototypes" >&5
+if test "$ac_cv_prog_cc_stdc" != no; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define PROTOTYPES 1
+EOF
+
+  U= ANSI2KNR=
+else
+  echo "$ac_t""no" 1>&6
+  U=_ ANSI2KNR=ansi2knr
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1404: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1409 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1458: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1479: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1484 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1492: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1509 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1527 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1548 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1559: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:1583: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1588 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_off_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+  cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1616: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1621 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1649: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1654 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1663: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_header_time=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+  cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1684: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1689 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1697: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_tm=time.h
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+  cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+cat > conftest.$ac_ext <<EOF
+#line 1720 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+int main() {
+ FILE *rubbish = popen("yes", "r"); 
+; return 0; }
+EOF
+if { (eval echo configure:1728: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'
+fi
+rm -f conftest*
+fi
+
+
+echo $ac_n "checking for main in -lm""... $ac_c" 1>&6
+echo "configure:1741: checking for main in -lm" >&5
+ac_lib_var=`echo m'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lm  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1749 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:1756: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo m | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lm $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+ac_header_dirent=no
+for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6
+echo "configure:1789: checking for $ac_hdr that defines DIR" >&5
+if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1794 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <$ac_hdr>
+int main() {
+DIR *dirp = 0;
+; return 0; }
+EOF
+if { (eval echo configure:1802: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_dirent_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ ac_header_dirent=$ac_hdr; break
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix.
+if test $ac_header_dirent = dirent.h; then
+echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6
+echo "configure:1827: checking for opendir in -ldir" >&5
+ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-ldir  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1835 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1846: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -ldir"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+else
+echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6
+echo "configure:1868: checking for opendir in -lx" >&5
+ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lx  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1876 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char opendir();
+
+int main() {
+opendir()
+; return 0; }
+EOF
+if { (eval echo configure:1887: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lx"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1910: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1915 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1923: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1940 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1958 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1979 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1990: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h limits.h sys/time.h unistd.h string.h memory.h sys/procfs.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:2017: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2022 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2027: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+cat > conftest.$ac_ext <<EOF
+#line 2054 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fread" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FREAD_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 2069 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "fgetc" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_FGETC_DECL 1
+EOF
+
+fi
+rm -f conftest*
+
+cat > conftest.$ac_ext <<EOF
+#line 2084 "configure"
+#include "confdefs.h"
+#include <sys/procfs.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "pr_brksize" >/dev/null 2>&1; then
+  rm -rf conftest*
+  cat >> confdefs.h <<\EOF
+#define HAVE_PR_BRKSIZE 1
+EOF
+
+fi
+rm -f conftest*
+
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+echo "configure:2102: checking for working alloca.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2107 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:2114: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_header_alloca_h=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+echo "configure:2135: checking for alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2140 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+#  define alloca _alloca
+# else
+#  if HAVE_ALLOCA_H
+#   include <alloca.h>
+#  else
+#   ifdef _AIX
+ #pragma alloca
+#   else
+#    ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+int main() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:2168: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  ac_cv_func_alloca_works=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_func_alloca_works=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
+if test $ac_cv_func_alloca_works = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca_works = no; then
+  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+  # that cause trouble.  Some versions do not even contain alloca or
+  # contain a buggy version.  If you still want to use their alloca,
+  # use ar to extract alloca.o from them instead of compiling alloca.c.
+  ALLOCA=alloca.${ac_objext}
+  cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+echo "configure:2200: checking whether alloca needs Cray hooks" >&5
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2205 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "webecray" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_os_cray=yes
+else
+  rm -rf conftest*
+  ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+  echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2230: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2235 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2258: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+  break
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+echo "configure:2285: checking stack direction for C alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_c_stack_direction=0
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2293 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+  static char *addr = 0;
+  auto char dummy;
+  if (addr == 0)
+    {
+      addr = &dummy;
+      return find_stack_direction ();
+    }
+  else
+    return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+  exit (find_stack_direction() < 0);
+}
+EOF
+if { (eval echo configure:2312: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_c_stack_direction=1
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_c_stack_direction=-1
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:2335: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <<EOF
+#line 2341 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <<EOF
+#line 2359 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
+echo "configure:2381: checking return type of signal handlers" >&5
+if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2386 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+#undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int main() {
+int i;
+; return 0; }
+EOF
+if { (eval echo configure:2403: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_type_signal=void
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_type_signal=int
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_type_signal" 1>&6
+cat >> confdefs.h <<EOF
+#define RETSIGTYPE $ac_cv_type_signal
+EOF
+
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:2422: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2427 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2450: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:2474: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2479 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2502: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+for ac_func in ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize strerror
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2529: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2534 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2557: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_func in ftruncate strstr strcasecmp
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2584: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2589 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2612: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}"
+fi
+done
+
+
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+echo $ac_n "checking for HP-UX needing gmalloc""... $ac_c" 1>&6
+echo "configure:2643: checking for HP-UX needing gmalloc" >&5
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  echo "$ac_t""yes" 1>&6
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  cat >> confdefs.h <<\EOF
+#define HAVE_VALLOC 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+  for ac_func in valloc
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:2656: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2661 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2684: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+fi
+
+echo $ac_n "checking if malloc debugging is wanted""... $ac_c" 1>&6
+echo "configure:2711: checking if malloc debugging is wanted" >&5
+# Check whether --with-dmalloc or --without-dmalloc was given.
+if test "${with_dmalloc+set}" = set; then
+  withval="$with_dmalloc"
+  if test "$withval" = yes; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_DMALLOC 1
+EOF
+
+  LIBS="$LIBS -ldmalloc"
+  LDFLAGS="$LDFLAGS -g"
+else
+  echo "$ac_t""no" 1>&6
+fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+echo $ac_n "checking which of rx or regex is wanted""... $ac_c" 1>&6
+echo "configure:2732: checking which of rx or regex is wanted" >&5
+# Check whether --with-regex or --without-regex was given.
+if test "${with_regex+set}" = set; then
+  withval="$with_regex"
+  if test "$withval" = yes; then
+  ac_with_regex=1
+  echo "$ac_t""regex" 1>&6
+  cat >> confdefs.h <<\EOF
+#define WITH_REGEX 1
+EOF
+
+  LIBOBJS="$LIBOBJS regex.o"
+fi
+fi
+
+if test -z "$ac_with_regex"; then
+  echo "$ac_t""rx" 1>&6
+  echo $ac_n "checking for re_rx_search""... $ac_c" 1>&6
+echo "configure:2750: checking for re_rx_search" >&5
+if eval "test \"`echo '$''{'ac_cv_func_re_rx_search'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2755 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char re_rx_search(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char re_rx_search();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_re_rx_search) || defined (__stub___re_rx_search)
+choke me
+#else
+re_rx_search();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:2778: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_re_rx_search=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'re_rx_search`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  :
+else
+  echo "$ac_t""no" 1>&6
+echo $ac_n "checking size of unsigned char *""... $ac_c" 1>&6
+echo "configure:2796: checking size of unsigned char *" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_char_p'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_sizeof_unsigned_char_p=unsigned char *
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2804 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(unsigned char *));
+  exit(0);
+}
+EOF
+if { (eval echo configure:2815: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_unsigned_char_p=`cat conftestval`
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_sizeof_unsigned_char_p=0
+fi
+rm -fr conftest*
+fi
+
+fi
+echo "$ac_t""$ac_cv_sizeof_unsigned_char_p" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_UNSIGNED_CHAR_P $ac_cv_sizeof_unsigned_char_p
+EOF
+
+  
+    if test "$ac_cv_sizeof_unsigned_char_p" = 8
+    then
+      echo "configure: warning: I'm forcing you to use regex because I can't 
+        find a local rx library and the one included with this 
+        distribution doesn't work on 64-bit machines like yours" 1>&2
+      LIBOBJS="$LIBOBJS regex.o"
+    else
+      LIBOBJS="$LIBOBJS rx.o"
+    fi
+  
+fi
+
+fi
+
+echo $ac_n "checking whether GNU readline requested""... $ac_c" 1>&6
+echo "configure:2849: checking whether GNU readline requested" >&5
+  # Check whether --with-gnu_readline or --without-gnu_readline was given.
+if test "${with_gnu_readline+set}" = set; then
+  withval="$with_gnu_readline"
+  if test "$withval" = yes; then
+      echo "$ac_t""yes" 1>&6
+      ac_with_gnu_readline=1
+    else
+      echo "$ac_t""no" 1>&6
+    fi
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+  if test -n "$ac_with_gnu_readline"; then
+    ac_safe=`echo "readline/readline.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for readline/readline.h""... $ac_c" 1>&6
+echo "configure:2867: checking for readline/readline.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 2872 "configure"
+#include "confdefs.h"
+#include <readline/readline.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:2877: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  ac_mg_readline_header_found=1
+else
+  echo "$ac_t""no" 1>&6
+echo "configure: warning: Can't find GNU readline headers; configuring without \
+GNU readline support" 1>&2
+fi
+
+    if test -n "$ac_mg_readline_header_found"; then
+      # first check whether we can find the readline library itself
+      echo $ac_n "checking for main in -lreadline""... $ac_c" 1>&6
+echo "configure:2903: checking for main in -lreadline" >&5
+ac_lib_var=`echo readline'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lreadline  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2911 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2918: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  ac_mg_readline_lib_found=1
+         cat >> confdefs.h <<\EOF
+#define WITH_GNU_READLINE 1
+EOF
+
+         LIBS="$LIBS -lreadline"
+else
+  echo "$ac_t""no" 1>&6
+echo "configure: warning: Can't find GNU readline library; configuring without \
+GNU readline support" 1>&2
+fi
+
+      if test -n "$ac_mg_readline_lib_found"; then
+        # on some systems, readline needs curses.  It is difficult to 
+        #  determine whether this is necessary on the current system,
+        #  since other undefined symbols can be turned up by an
+        #  AC_CHECK_LIB(readline, readline) test that are actually defined
+	#  by mg itself (e.g. xmalloc, xrealloc).  So, if we find libcurses,
+	#  we just bung it on and hope for the best.
+	echo $ac_n "checking for main in -lcurses""... $ac_c" 1>&6
+echo "configure:2953: checking for main in -lcurses" >&5
+ac_lib_var=`echo curses'_'main | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lcurses  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2961 "configure"
+#include "confdefs.h"
+
+int main() {
+main()
+; return 0; }
+EOF
+if { (eval echo configure:2968: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  LIBS="$LIBS -lcurses"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+      fi
+    fi
+  fi
+
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+# see if the user wants to override use of long long
+# Check whether --enable-override-longlong or --disable-override-longlong was given.
+if test "${enable_override_longlong+set}" = set; then
+  enableval="$enable_override_longlong"
+  cat >> confdefs.h <<\EOF
+#define DISABLE_LONG_LONG 1
+EOF
+
+fi
+
+
+# ---------------------------------------------------------------------------
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile text/Makefile lib/Makefile  config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@CXX@%$CXX%g
+s%@AWK@%$AWK%g
+s%@YACC@%$YACC%g
+s%@CC@%$CC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@LN_S@%$LN_S%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@RANLIB@%$RANLIB%g
+s%@CPP@%$CPP%g
+s%@U@%$U%g
+s%@ANSI2KNR@%$ANSI2KNR%g
+s%@ALLOCA@%$ALLOCA%g
+s%@LIBOBJS@%$LIBOBJS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile text/Makefile lib/Makefile "}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ 	]*\)#\([ 	]*define[ 	][ 	]*\)'
+ac_dB='\([ 	][ 	]*\)[^ 	]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_uB='\([ 	]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ 	]*\)#\([ 	]*\)undef\([ 	][ 	]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+  CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  echo creating $ac_file
+
+  rm -f conftest.frag conftest.in conftest.out
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h.  And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ 	]*#[ 	]*undef[ 	][ 	]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+  ac_lines=`grep -c . conftest.vals`
+  # grep -c gives empty output for an empty file on some AIX systems.
+  if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+  # Write a limited-size here document to conftest.frag.
+  echo '  cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+  echo 'CEOF
+  sed -f conftest.frag conftest.in > conftest.out
+  rm -f conftest.in
+  mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+  rm -f conftest.vals
+  mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+  rm -f conftest.frag conftest.h
+  echo "/* $ac_file.  Generated automatically by configure.  */" > conftest.h
+  cat conftest.in >> conftest.h
+  rm -f conftest.in
+  if cmp -s $ac_file conftest.h 2>/dev/null; then
+    echo "$ac_file is unchanged"
+    rm -f conftest.h
+  else
+    # Remove last slash and all that follows it.  Not all systems have dirname.
+      ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+      if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+      # The file is in a subdirectory.
+      test ! -d "$ac_dir" && mkdir "$ac_dir"
+    fi
+    rm -f $ac_file
+    mv conftest.h $ac_file
+  fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/configure.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/configure.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/configure.in	(revision 10506)
@@ -0,0 +1,105 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(text/MGQuery.cpp)
+AC_CONFIG_HEADER(config.h)
+AC_ARG_PROGRAM
+
+dnl
+PACKAGE=mgpp
+VERSION=1.3
+
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
+AC_SUBST(PACKAGE)
+AC_SUBST(VERSION)
+
+dnl Checks for programs.
+AC_PROG_CXX
+AC_PROG_AWK
+AC_PROG_YACC
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_RANLIB
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_AIX
+AC_ISC_POSIX
+AC_MINIX
+fp_C_PROTOTYPES
+AC_C_CONST
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl --- This should be in the stdc checking -----------------
+if test "$ac_cv_prog_cc_stdc" = '-Xc'; then
+dnl The Pyramids running SMP_DC.OSx on MIPS r3000 chips with
+dnl /usr/opt/cc3.11/bin/cc treat -Xc as full ANSI mode - no POSIX or
+dnl XOPEN extensions (like popen).
+dnl Unfortunately -D_{XOPEN,POSIX}_SOURCE can't provide all that mg
+dnl needs. So drop back to -Xa
+AC_TRY_COMPILE(
+[#include <stdio.h>
+], [ FILE *rubbish = popen("yes", "r"); ],,
+[CC="`echo $CC | sed 's/-Xc/-Xa/'`"    ac_cv_prog_cc_stdc='-Xa'])
+fi
+dnl ----------------------
+
+
+dnl Checks for libraries.
+dnl Replace `main' with a function in -lm:
+AC_CHECK_LIB(m, main)
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h sys/time.h unistd.h string.h memory.h sys/procfs.h)
+AC_EGREP_HEADER(fread, stdio.h, AC_DEFINE(HAVE_FREAD_DECL))
+AC_EGREP_HEADER(fgetc, stdio.h, AC_DEFINE(HAVE_FGETC_DECL))
+AC_EGREP_HEADER(pr_brksize, sys/procfs.h, AC_DEFINE(HAVE_PR_BRKSIZE))
+
+dnl Checks for library functions.
+AC_FUNC_ALLOCA
+AC_PROG_GCC_TRADITIONAL
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(ftime select strftime strtol getrusage times mallinfo setbuffer getpagesize strerror)
+AC_REPLACE_FUNCS(ftruncate strstr strcasecmp)
+
+
+# *** Custom checking (based on GNU tar configure.in) ***
+# ---------------------------------------------------------------------------
+AC_MSG_CHECKING(for HP-UX needing gmalloc)
+if test "`(uname -s) 2> /dev/null`" = 'HP-UX'; then
+  AC_MSG_RESULT(yes)
+  LIBOBJS="$LIBOBJS gmalloc.o"
+  AC_DEFINE(HAVE_VALLOC)
+else
+  AC_MSG_RESULT(no)
+  AC_CHECK_FUNCS(valloc)
+fi
+
+fp_WITH_DMALLOC
+fp_WITH_REGEX
+fp_WITH_GNU_READLINE
+
+# ---------------------------------------------------------------------------
+if test "$ac_cv_func_alloca" = 'no'; then
+dnl    support functions for alloca.c
+  LIBOBJS="$LIBOBJS xmalloc.o error.o"
+fi
+
+
+# ---------------------------------------------------------------------------
+# see if the user wants to override use of long long
+AC_ARG_ENABLE(override-longlong,
+[  --enable-override-longlong
+                          overide use of long long with GCC],
+  AC_DEFINE(DISABLE_LONG_LONG))
+
+# ---------------------------------------------------------------------------
+
+AC_OUTPUT([Makefile text/Makefile lib/Makefile ], 
+[test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h])
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/install-sh
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/install-sh	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/install-sh	(revision 10506)
@@ -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: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/Makefile.in	(revision 10506)
@@ -0,0 +1,155 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the general purpose library
+# Copyright (C) 1994  Neil Sharman; (C) 1995 Tim Shimmin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)Makefile.in	1.3 16 Mar 1994
+#
+###########################################################################
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+ 
+SHELL = /bin/sh
+srcdir = @srcdir@
+subdir = lib
+VPATH = @srcdir@
+ 
+AR = ar
+CC = @CC@
+CXX = @CXX@
+ifneq ($(NZDL), 1)
+CFLAGS = @CFLAGS@ -ansi
+else 
+CFLAGS = @CFLAGS@ -ansi -DSILENT
+endif
+CXXFLAGS = @CXXFLAGS@
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+
+prefix = @prefix@
+datadir = $(prefix)/share
+localedir = $(datadir)/locale
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES)  $(CFLAGS)
+CXXCOMPILE = $(CXX) -c $(DEFS) $(INCLUDES) $(CXXFLAGS)
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CXXCOMPILE) -D__cplusplus $<
+
+ANSI2KNR = @ANSI2KNR@
+o = .@U@o
+ 
+.SUFFIXES: ._c ._o
+.c._c:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $@
+._c._o:
+	@echo $(COMPILE) $<
+	@rm -f _$*.c
+	@ln $< _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+.c._o:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $*._c
+	@echo $(COMPILE) $*._c
+	@rm -f _$*.c
+	@ln $*._c _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+
+# want toplevel config.h, not local one
+INCLUDES = -I../../.. -I$(srcdir)
+ 
+HEADERS = \
+    bitio_m_random.h   local_strings.h    lovinstem.h \
+    bitio_m_stdio.h    memlib.h           netorder.h \
+    bitio_gen.h        mgheap.h           messages.h \
+    bitio_m.h          huffman.h  \
+    bitio_m_mem.h      perf_hash.h \
+    bitio_m_mems.h      \
+    pathmax.h          getpagesize.h      sysfuncs.h         bitio_m_abstract.h  \
+    random.h           simplefrenchstem.h unitool.h	     longlong.h \
+    non_ansi.h
+
+
+SOURCES = \
+    mgheap.cpp         \
+    huffman.cpp       messages.cpp \
+    bitio_gen.cpp     perf_hash.cpp \
+    local_strings.cpp lovinstem.cpp \
+    bitio_m_mem.cpp   bitio_m_stdio.cpp bitio_m_mems.cpp \
+    alloca.c          xmalloc.c         strstr.cpp \
+    ftruncate.cpp     strcasecmp.cpp    random.cpp \
+    simplefrenchstem.cpp                unitool.cpp       bitio_m_random.cpp \
+    bitio_m_abstract.cpp
+# memlib.cpp removed
+
+OBJECTS =  mgheap$o   \
+    huffman$o         messages$o \
+    bitio_gen$o       perf_hash$o \
+     local_strings$o   lovinstem$o \
+    bitio_m_mem$o     bitio_m_stdio$o   bitio_m_mems$o \
+    xmalloc$o         bitio_m_random$o  bitio_m_abstract$o \
+     random$o          simplefrenchstem$o \
+    unitool$o
+
+DISTFILES = Makefile.in $(HEADERS) $(SOURCES)
+
+all : libmg.a
+
+libmg.a : $(OBJECTS)
+	rm -f libmg.a
+	$(AR) cru libmg.a $(OBJECTS)
+	$(RANLIB) libmg.a
+
+install: 
+installdirs:
+uninstall:
+execinstall:
+execuninstall:
+maninstall:
+manuninstall:
+ 
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $$file $(distdir) 2> /dev/null \
+	  || cp -p $$file $(distdir); \
+	done
+
+mostlyclean:
+	rm -f *.o *_.o
+ 
+clean: mostlyclean
+	rm -f libmg.a
+ 
+distclean: clean
+	rm -f Makefile
+ 
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+# breaks make distclean (jrm21)
+#Makefile: Makefile.in ../../../config.status
+#	cd ../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+ 
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/WIN32.MAK
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/WIN32.MAK	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/WIN32.MAK	(revision 10506)
@@ -0,0 +1,108 @@
+###########################################################################
+#
+# win32 makefile -- mgpp\text
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..\..\..
+USE_STLPORT = 0
+DLL = 0
+DLLDEBUG = 0
+STLPATH = "$(GSDLHOME)\packages\windows\stlport\stlport"
+
+CC = cl
+
+CPPFLAGS = -GX
+!IF $(DLL)
+CPPFLAGS = $(CPPFLAGS) -MD
+!ELSE
+!IF ($(DLLDEBUG))
+CPPFLAGS = $(CPPFLAGS) -MDd
+!ENDIF
+!ENDIF
+
+DEFS = -DSHORT_SUFFIX -DSILENT -DHAVE_CONFIG_H -D__WIN32__
+INCLUDES = -I"$(GSDLHOME)"
+!IF $(USE_STLPORT)
+DEFS = $(DEFS) -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = $(INCLUDES) -I$(STLPATH)
+!ENDIF
+
+LDFLAGS =
+
+LIBS = 
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .c .obj .cpp
+.c.obj:
+	$(COMPILE) $<
+.cpp.obj:
+	$(COMPILE) $<
+
+o = .obj
+
+HEADERS = \
+    bitio_m_random.h   local_strings.h    lovinstem.h \
+    bitio_m_stdio.h    memlib.h           netorder.h \
+    bitio_gen.h        mgheap.h           messages.h \
+    bitio_m.h          huffman.h  \
+    bitio_m_mem.h      perf_hash.h \
+    bitio_m_mems.h     getopt_old.h \
+    pathmax.h          getpagesize.h      sysfuncs.h         bitio_m_abstract.h  \
+    random.h           simplefrenchstem.h unitool.h	     longlong.h \
+    non_ansi.h
+
+SOURCES = \
+    mgheap.cpp         \
+    huffman.cpp       messages.cpp \
+    bitio_gen.cpp     perf_hash.cpp \
+    local_strings.cpp lovinstem.cpp \
+    bitio_m_mem.cpp   bitio_m_stdio.cpp bitio_m_mems.cpp \
+    alloca.c          xmalloc.c         strstr.cpp \
+    ftruncate.cpp     strcasecmp.cpp    random.cpp \
+    simplefrenchstem.cpp                unitool.cpp       bitio_m_random.cpp \
+    bitio_m_abstract.cpp getopt_old.c
+
+OBJECTS =  mgheap$o   \
+    huffman$o         messages$o \
+    bitio_gen$o       perf_hash$o \
+     local_strings$o   lovinstem$o \
+    bitio_m_mem$o     bitio_m_stdio$o   bitio_m_mems$o \
+    xmalloc$o         bitio_m_random$o  bitio_m_abstract$o \
+     random$o          simplefrenchstem$o \
+    unitool$o  win32in$o getopt_old$o
+
+all : libmg.lib
+
+libmg.lib: $(OBJECTS)
+	if EXIST libmg.lib del libmg.lib
+	lib /out:libmg.lib $(OBJECTS)
+
+clean:
+	del *$o 
+	del libmg.lib
+
+install:
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/alloca.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/alloca.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/alloca.c	(revision 10506)
@@ -0,0 +1,496 @@
+/* alloca.c -- allocate automatically reclaimed memory
+   (Mostly) portable public-domain implementation -- D A Gwyn
+
+   This implementation of the PWB library alloca function,
+   which is used to allocate space off the run-time stack so
+   that it is automatically reclaimed upon procedure exit,
+   was inspired by discussions with J. Q. Johnson of Cornell.
+   J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+   There are some preprocessor constants that can
+   be defined when compiling for your specific system, for
+   improved efficiency; however, the defaults should be okay.
+
+   The general concept of this implementation is to keep
+   track of all alloca-allocated blocks, and reclaim any
+   that are found to be deeper in the stack than the current
+   invocation.  This heuristic does not reclaim storage as
+   soon as it becomes invalid, but it will do so eventually.
+
+   As a special case, alloca(0) reclaims storage without
+   allocating any.  It is a good idea to use alloca(0) in
+   your main control loop, etc. to force garbage collection.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#ifdef emacs
+#include "blockinput.h"
+#endif
+
+/* If compiling with GCC 2, this file's not needed.  */
+#if !defined (__GNUC__) || __GNUC__ < 2
+
+/* If someone has defined alloca as a macro,
+   there must be some other way alloca is supposed to work.  */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+   -- this is for usg, in which emacs must undefine static
+   in order to make unexec workable
+   */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+   provide an "address metric" ADDRESS_FUNCTION macro.  */
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#define	NULL	0
+
+/* Different portions of Emacs need to call different versions of
+   malloc.  The Emacs executable needs alloca to call xmalloc, because
+   ordinary malloc isn't protected from input signals.  On the other
+   hand, the utilities in lib-src need alloca to call malloc; some of
+   them are very simple, and don't have an xmalloc routine.
+
+   Non-Emacs programs expect this to call use xmalloc.
+
+   Callers below should use malloc.  */
+
+#ifndef emacs
+#define malloc xmalloc
+#endif
+extern pointer malloc ();
+
+/* Define STACK_DIRECTION if you know the direction of stack
+   growth for your system; otherwise it will be automatically
+   deduced at run-time.
+
+   STACK_DIRECTION > 0 => grows toward higher addresses
+   STACK_DIRECTION < 0 => grows toward lower addresses
+   STACK_DIRECTION = 0 => direction of growth unknown  */
+
+#ifndef STACK_DIRECTION
+#define	STACK_DIRECTION	0	/* Direction unknown.  */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define	STACK_DIR	STACK_DIRECTION	/* Known at compile-time.  */
+
+#else /* STACK_DIRECTION == 0; need run-time code.  */
+
+static int stack_dir;		/* 1 or -1 once known.  */
+#define	STACK_DIR	stack_dir
+
+static void
+find_stack_direction ()
+{
+  static char *addr = NULL;	/* Address of first `dummy', once known.  */
+  auto char dummy;		/* To get stack address.  */
+
+  if (addr == NULL)
+    {				/* Initial entry.  */
+      addr = ADDRESS_FUNCTION (dummy);
+
+      find_stack_direction ();	/* Recurse once.  */
+    }
+  else
+    {
+      /* Second entry.  */
+      if (ADDRESS_FUNCTION (dummy) > addr)
+	stack_dir = 1;		/* Stack grew upward.  */
+      else
+	stack_dir = -1;		/* Stack grew downward.  */
+    }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+   (a) chain together all alloca'ed blocks;
+   (b) keep track of stack depth.
+
+   It is very important that sizeof(header) agree with malloc
+   alignment chunk size.  The following default should work okay.  */
+
+#ifndef	ALIGN_SIZE
+#define	ALIGN_SIZE	sizeof(double)
+#endif
+
+typedef union hdr
+{
+  char align[ALIGN_SIZE];	/* To force sizeof(header).  */
+  struct
+    {
+      union hdr *next;		/* For chaining headers.  */
+      char *deep;		/* For stack depth measure.  */
+    } h;
+} header;
+
+static header *last_alloca_header = NULL;	/* -> last alloca header.  */
+
+/* Return a pointer to at least SIZE bytes of storage,
+   which will be automatically reclaimed upon exit from
+   the procedure that called alloca.  Originally, this space
+   was supposed to be taken from the current stack frame of the
+   caller, but that method cannot be made to work for some
+   implementations of C, for example under Gould's UTX/32.  */
+
+pointer
+alloca (size)
+     unsigned size;
+{
+  auto char probe;		/* Probes stack depth: */
+  register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+  if (STACK_DIR == 0)		/* Unknown growth direction.  */
+    find_stack_direction ();
+#endif
+
+  /* Reclaim garbage, defined as all alloca'd storage that
+     was allocated from deeper in the stack than currently. */
+
+  {
+    register header *hp;	/* Traverses linked list.  */
+
+#ifdef emacs
+    BLOCK_INPUT;
+#endif
+
+    for (hp = last_alloca_header; hp != NULL;)
+      if ((STACK_DIR > 0 && hp->h.deep > depth)
+	  || (STACK_DIR < 0 && hp->h.deep < depth))
+	{
+	  register header *np = hp->h.next;
+
+	  free ((pointer) hp);	/* Collect garbage.  */
+
+	  hp = np;		/* -> next header.  */
+	}
+      else
+	break;			/* Rest are not deeper.  */
+
+    last_alloca_header = hp;	/* -> last valid storage.  */
+
+#ifdef emacs
+    UNBLOCK_INPUT;
+#endif
+  }
+
+  if (size == 0)
+    return NULL;		/* No allocation required.  */
+
+  /* Allocate combined header + user data storage.  */
+
+  {
+    register pointer new = malloc (sizeof (header) + size);
+    /* Address of header.  */
+
+    ((header *) new)->h.next = last_alloca_header;
+    ((header *) new)->h.deep = depth;
+
+    last_alloca_header = (header *) new;
+
+    /* User storage begins just after header.  */
+
+    return (pointer) ((char *) new + sizeof (header));
+  }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+  {
+    long shgrow:32;		/* Number of times stack has grown.  */
+    long shaseg:32;		/* Size of increments to stack.  */
+    long shhwm:32;		/* High water mark of stack.  */
+    long shsize:32;		/* Current size of stack (all segments).  */
+  };
+
+/* The stack segment linkage control information occurs at
+   the high-address end of a stack segment.  (The stack
+   grows from low addresses to high addresses.)  The initial
+   part of the stack segment linkage control information is
+   0200 (octal) words.  This provides for register storage
+   for the routine which overflows the stack.  */
+
+struct stack_segment_linkage
+  {
+    long ss[0200];		/* 0200 overflow words.  */
+    long sssize:32;		/* Number of words in this segment.  */
+    long ssbase:32;		/* Offset to stack base.  */
+    long:32;
+    long sspseg:32;		/* Offset to linkage control of previous
+				   segment of stack.  */
+    long:32;
+    long sstcpt:32;		/* Pointer to task common address block.  */
+    long sscsnm;		/* Private control structure number for
+				   microtasking.  */
+    long ssusr1;		/* Reserved for user.  */
+    long ssusr2;		/* Reserved for user.  */
+    long sstpid;		/* Process ID for pid based multi-tasking.  */
+    long ssgvup;		/* Pointer to multitasking thread giveup.  */
+    long sscray[7];		/* Reserved for Cray Research.  */
+    long ssa0;
+    long ssa1;
+    long ssa2;
+    long ssa3;
+    long ssa4;
+    long ssa5;
+    long ssa6;
+    long ssa7;
+    long sss0;
+    long sss1;
+    long sss2;
+    long sss3;
+    long sss4;
+    long sss5;
+    long sss6;
+    long sss7;
+  };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+   returned by the STKSTAT library routine.  */
+struct stk_stat
+  {
+    long now;			/* Current total stack size.  */
+    long maxc;			/* Amount of contiguous space which would
+				   be required to satisfy the maximum
+				   stack demand to date.  */
+    long high_water;		/* Stack high-water mark.  */
+    long overflows;		/* Number of stack overflow ($STKOFEN) calls.  */
+    long hits;			/* Number of internal buffer hits.  */
+    long extends;		/* Number of block extensions.  */
+    long stko_mallocs;		/* Block allocations by $STKOFEN.  */
+    long underflows;		/* Number of stack underflow calls ($STKRETN).  */
+    long stko_free;		/* Number of deallocations by $STKRETN.  */
+    long stkm_free;		/* Number of deallocations by $STKMRET.  */
+    long segments;		/* Current number of stack segments.  */
+    long maxs;			/* Maximum number of stack segments so far.  */
+    long pad_size;		/* Stack pad size.  */
+    long current_address;	/* Current stack segment address.  */
+    long current_size;		/* Current stack segment size.  This
+				   number is actually corrupted by STKSTAT to
+				   include the fifteen word trailer area.  */
+    long initial_address;	/* Address of initial segment.  */
+    long initial_size;		/* Size of initial segment.  */
+  };
+
+/* The following structure describes the data structure which trails
+   any stack segment.  I think that the description in 'asdef' is
+   out of date.  I only describe the parts that I am sure about.  */
+
+struct stk_trailer
+  {
+    long this_address;		/* Address of this block.  */
+    long this_size;		/* Size of this block (does not include
+				   this trailer).  */
+    long unknown2;
+    long unknown3;
+    long link;			/* Address of trailer block of previous
+				   segment.  */
+    long unknown5;
+    long unknown6;
+    long unknown7;
+    long unknown8;
+    long unknown9;
+    long unknown10;
+    long unknown11;
+    long unknown12;
+    long unknown13;
+    long unknown14;
+  };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+   I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+  struct stk_stat status;
+  struct stk_trailer *trailer;
+  long *block, size;
+  long result = 0;
+
+  /* We want to iterate through all of the segments.  The first
+     step is to get the stack status structure.  We could do this
+     more quickly and more directly, perhaps, by referencing the
+     $LM00 common block, but I know that this works.  */
+
+  STKSTAT (&status);
+
+  /* Set up the iteration.  */
+
+  trailer = (struct stk_trailer *) (status.current_address
+				    + status.current_size
+				    - 15);
+
+  /* There must be at least one stack segment.  Therefore it is
+     a fatal error if "trailer" is null.  */
+
+  if (trailer == 0)
+    abort ();
+
+  /* Discard segments that do not contain our argument address.  */
+
+  while (trailer != 0)
+    {
+      block = (long *) trailer->this_address;
+      size = trailer->this_size;
+      if (block == 0 || size == 0)
+	abort ();
+      trailer = (struct stk_trailer *) trailer->link;
+      if ((block <= address) && (address < (block + size)))
+	break;
+    }
+
+  /* Set the result to the offset in this segment and add the sizes
+     of all predecessor segments.  */
+
+  result = address - block;
+
+  if (trailer == 0)
+    {
+      return result;
+    }
+
+  do
+    {
+      if (trailer->this_size <= 0)
+	abort ();
+      result += trailer->this_size;
+      trailer = (struct stk_trailer *) trailer->link;
+    }
+  while (trailer != 0);
+
+  /* We are done.  Note that if you present a bogus address (one
+     not in any segment), you will get a different number back, formed
+     from subtracting the address of the first block.  This is probably
+     not what you want.  */
+
+  return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+   Determine the number of the cell within the stack,
+   given the address of the cell.  The purpose of this
+   routine is to linearize, in some sense, stack addresses
+   for alloca.  */
+
+static long
+i00afunc (long address)
+{
+  long stkl = 0;
+
+  long size, pseg, this_segment, stack;
+  long result = 0;
+
+  struct stack_segment_linkage *ssptr;
+
+  /* Register B67 contains the address of the end of the
+     current stack segment.  If you (as a subprogram) store
+     your registers on the stack and find that you are past
+     the contents of B67, you have overflowed the segment.
+
+     B67 also points to the stack segment linkage control
+     area, which is what we are really interested in.  */
+
+  stkl = CRAY_STACKSEG_END ();
+  ssptr = (struct stack_segment_linkage *) stkl;
+
+  /* If one subtracts 'size' from the end of the segment,
+     one has the address of the first word of the segment.
+
+     If this is not the first segment, 'pseg' will be
+     nonzero.  */
+
+  pseg = ssptr->sspseg;
+  size = ssptr->sssize;
+
+  this_segment = stkl - size;
+
+  /* It is possible that calling this routine itself caused
+     a stack overflow.  Discard stack segments which do not
+     contain the target address.  */
+
+  while (!(this_segment <= address && address <= stkl))
+    {
+#ifdef DEBUG_I00AFUNC
+      fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+      if (pseg == 0)
+	break;
+      stkl = stkl - pseg;
+      ssptr = (struct stack_segment_linkage *) stkl;
+      size = ssptr->sssize;
+      pseg = ssptr->sspseg;
+      this_segment = stkl - size;
+    }
+
+  result = address - this_segment;
+
+  /* If you subtract pseg from the current end of the stack,
+     you get the address of the previous stack segment's end.
+     This seems a little convoluted to me, but I'll bet you save
+     a cycle somewhere.  */
+
+  while (pseg != 0)
+    {
+#ifdef DEBUG_I00AFUNC
+      fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+      stkl = stkl - pseg;
+      ssptr = (struct stack_segment_linkage *) stkl;
+      size = ssptr->sssize;
+      pseg = ssptr->sspseg;
+      result += size;
+    }
+  return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
+#endif /* not GCC version 2 */
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_gen.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_gen.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_gen.cpp	(revision 10506)
@@ -0,0 +1,134 @@
+/**************************************************************************
+ *
+ * bitio_gen.c -- General supoport routines for bitio
+ * Copyright (C) 1994  Neil Sharman and Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "bitio_m_abstract.h"
+
+int fprintf (FILE *, const char *,...);
+
+unsigned long 
+BIO_Unary_Length (unsigned long val)
+{
+  register unsigned long num;
+  num = bitio_buffer::unary_length(val);
+  //  UNARY_LENGTH (val, num);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Binary_Length (unsigned long val, unsigned long b)
+{
+  register unsigned long num;
+  num = bitio_buffer::binary_length (val, b);
+  return (num);
+}
+
+
+unsigned long BIO_Gamma_Length (unsigned long val) {
+  register unsigned long num;
+  num = bitio_buffer::gamma_length(val);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Delta_Length (unsigned long val)
+{
+  register unsigned long num;
+  num = bitio_buffer::delta_length(val);
+  return (num);
+}
+
+
+unsigned long 
+BIO_Elias_Length (unsigned long val, unsigned long b, double s)
+{
+  register unsigned long num;
+  num = bitio_buffer::elias_length(val, b, s);
+  return (num);
+}
+
+unsigned long 
+BIO_Bblock_Length (unsigned long val, unsigned long b)
+{
+  register unsigned long num;
+  num = bitio_buffer::bblock_length (val, b);
+  return (num);
+}
+
+
+int 
+BIO_Bblock_Init (int N, int p)
+{
+  int b;
+  b = (int) (0.5 + 0.6931471 * N / p);
+  return (b ? b : 1);
+}
+
+
+int 
+BIO_Bblock_Init_W (int N, int p)
+{
+  int logb;
+  logb = bitio_buffer::floor_log2 ((N - p) / p);
+  return (logb < 0 ? 1 : (1 << logb));
+}
+
+int 
+BIO_Bblock_Bound_b (int N, int p, int b)
+{
+  int clogb;
+  clogb = bitio_buffer::ceil_log2 (b);
+  return (p * (1 + clogb) + (N - p * ((1 << clogb) - b + 1)) / b);
+}
+
+int 
+BIO_Bblock_Bound (int N, int p)
+{
+  int b;
+  b = BIO_Bblock_Init_W (N, p);
+  return (BIO_Bblock_Bound_b (N, p, b));
+}
+
+/* adjustment is a hack to overcome inaccuracies in floating point,
+   where (int)(ln4/ln2) can equal 1, not 2. */
+int 
+BIO_Gamma_Bound (int N, int p)
+{
+  return ((int) (p * (2 * log2 (((double) N * 1.0001) / p) + 1)));
+}
+
+int 
+floorlog_2 (int b)
+{
+  int logb;
+  logb = bitio_buffer::floor_log2 (b);
+  return logb;
+}
+
+int 
+ceillog_2 (int b)
+{
+  int logb;
+  logb = bitio_buffer::ceil_log2 (b);
+  return logb;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_gen.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_gen.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_gen.h	(revision 10506)
@@ -0,0 +1,61 @@
+/**************************************************************************
+ *
+ * bitio_gen.h -- General supoport routines for bitio
+ * Copyright (C) 1994  Neil Sharman and Alistair Moffat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************
+ *
+ *  This file contains function definitions for doing general bitio operations.
+ *
+ *  This file defines functions for calculation the length in bits of a number
+ *  coded unary, binary, delta, gamma, elias, and  bblock coding. It defines 
+ *  routines for calculating the parameter and bounds for bblock coding. 
+ *  Routines for calculating ceil and floor lg are also defined.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_GEN
+#define H_BITIO_GEN
+
+unsigned long BIO_Unary_Length (unsigned long val);
+
+unsigned long BIO_Binary_Length (unsigned long val, unsigned long b);
+
+unsigned long BIO_Gamma_Length (unsigned long val);
+
+unsigned long BIO_Delta_Length (unsigned long val);
+
+unsigned long BIO_Elias_Length (unsigned long val, unsigned long b, double s);
+
+unsigned long BIO_Bblock_Length (unsigned long val, unsigned long b);
+
+int BIO_Bblock_Init (int N, int p);
+
+int BIO_Bblock_Init_W (int N, int p);
+
+int BIO_Bblock_Bound_b (int N, int p, int b);
+
+int BIO_Bblock_Bound (int N, int p);
+
+int BIO_Gamma_Bound (int N, int p);
+
+int floorlog_2 (int b);
+
+int ceillog_2 (int b);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_abstract.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_abstract.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_abstract.cpp	(revision 10506)
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "bitio_m_abstract.h"
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_abstract.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_abstract.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_abstract.h	(revision 10506)
@@ -0,0 +1,340 @@
+#ifndef H_BITIO_ABSTRACT
+#define H_BITIO_ABSTRACT
+
+class bitio_buffer {
+public:
+  virtual int bit() = 0;
+  virtual void encodeBit(int bit) = 0;
+  virtual void seek(unsigned long topos) = 0;
+  
+  static inline void check_positive(char *type, unsigned long x) {
+    if (x <= 0) {
+      fprintf(stderr, "Error: Cannot %s encode %lu\n", type, x);
+      exit(1);
+    }
+  }
+
+  static inline int floor_log2(unsigned long x) {
+    unsigned long  _B_x = x;
+    int reply;
+    
+    reply = -1;
+    while (_B_x != 0) {
+      _B_x >>= 1;
+      ++reply;
+    }
+    return reply;
+  }
+  
+  static inline int ceil_log2(unsigned long x) {
+    register int _B_x;
+    unsigned long reply;
+    
+    _B_x = x - 1;
+    reply = 0;
+    while (_B_x != 0) {
+      _B_x >>= 1;
+      ++reply;
+    }
+    return reply;
+  }
+
+  inline unsigned long unary_decode(unsigned long *count) {
+    unsigned long x;
+    
+    x = 1;
+    while (!this->bit()) ++x;
+    if (count != NULL) {
+      *count += x;
+    }
+    return x;
+  }
+
+  inline void unary_encode(unsigned long x, unsigned long *count) {
+    register unsigned long _B_x = x;
+    check_positive("unary", _B_x);
+    if (count != NULL) {
+      *count += _B_x;
+    }
+    while(--_B_x) 
+      encodeBit(0);
+    encodeBit(1);
+  }
+
+
+  inline unsigned long binary_decode(unsigned long b, unsigned long *count) {
+    register unsigned long _B_x = 0;
+    register unsigned long _B_b = b;
+    register int _B_i, _B_logofb, _B_thresh;
+    register unsigned long reply;
+    
+    if (_B_b != 1) {					
+      _B_logofb = ceil_log2(_B_b);
+      _B_thresh = (1<<_B_logofb) - _B_b;
+      --_B_logofb;
+      
+      if (count != NULL) {
+	*count += _B_logofb;
+      }
+      
+      for (_B_i=0; _B_i < _B_logofb; ++_B_i) {
+	_B_x += _B_x + this->bit();
+      }
+
+      if ((int)_B_x >= _B_thresh) {
+	_B_x += _B_x + this->bit();
+	_B_x -= _B_thresh;
+	if (count != NULL) {
+	  *count = *count + 1;
+	}
+      }
+      reply = _B_x+1;
+      
+    } else reply = 1;
+    
+    return reply;
+  }
+
+  inline void binary_encode(unsigned long x, unsigned long b, unsigned long *count) {
+    register unsigned long _B_x = (x);
+    register unsigned long _B_b = (b);
+    register int _B_nbits, _B_logofb, _B_thresh;
+    
+    check_positive("binary", _B_x);
+    _B_logofb = ceil_log2(_B_b);
+    
+    _B_thresh = (1<<_B_logofb) - _B_b;
+    if ((int)(--_B_x) < _B_thresh) _B_nbits = _B_logofb-1;
+    else {
+      _B_nbits = _B_logofb;
+      _B_x += _B_thresh;
+    }
+    if (count != NULL) {
+      *count += _B_nbits;
+    }
+    while (--_B_nbits>=0)
+      encodeBit((_B_x>>_B_nbits) & 0x1);
+  }
+
+  inline unsigned long bblock_decode(unsigned long b, unsigned long *count) {
+    register unsigned long _B_x1, _B_xx = 0;
+    register unsigned long _B_bb = (b);
+    register int _B_xdivb;
+    
+    _B_xdivb = this->unary_decode(count);
+    --_B_xdivb;				       
+    while (_B_xdivb--) {
+      _B_xx += _B_bb;
+    }
+    _B_x1 = this->binary_decode(_B_bb, count);
+    return (_B_xx + _B_x1);
+  }
+  
+  inline void bblock_encode(unsigned long x, unsigned long b, unsigned long *count) {
+    register unsigned long _B_xx = (x);
+    register unsigned long _B_bb = (b);
+    register int _B_xdivb = 0;
+    check_positive("bblock", _B_xx);
+    --_B_xx;
+    while (_B_xx >= _B_bb) {
+      ++_B_xdivb;
+      _B_xx -= _B_bb;
+    }
+    unary_encode(_B_xdivb+1, count);
+    binary_encode(_B_xx+1, _B_bb, count);
+  }
+
+  inline unsigned long elias_decode(unsigned long b, double s, unsigned long *count) {
+    register unsigned long _B_xx;
+    register unsigned long _B_b = b;
+    register double _B_s = s;
+    register int _B_lower=1, _B_upper=1;
+    register int _B_k;
+    register double _B_pow=1.0;
+    
+    _B_k = this->unary_decode(count);
+    --_B_k;
+    while (_B_k--) {
+      _B_lower = _B_upper+1;
+      _B_pow *= _B_s;
+      _B_upper += (int) (_B_b*_B_pow);
+    }
+    _B_xx = this->binary_decode(_B_upper-_B_lower+1, count);
+    --_B_xx;
+    check_positive("gamma", _B_xx+_B_lower);
+    return _B_xx+_B_lower;
+  }
+  
+  inline void elias_encode(unsigned long x, unsigned long b, double s, unsigned long *count) {
+    register unsigned long _B_xx = x;
+    register unsigned long _B_b = b;
+    register double _B_s = s;
+    register int _B_lower=1, _B_upper=1;
+    register int _B_k=0;
+    register double _B_pow=1.0;
+    
+    check_positive("elias", _B_xx);
+    
+    while ((int)_B_xx>_B_upper) {
+      ++_B_k;
+      _B_lower = _B_upper+1;
+      _B_pow *= _B_s;
+      _B_upper += (int) (_B_b*_B_pow);
+    }
+    unary_encode(_B_k+1, count);
+    binary_encode(_B_xx-_B_lower+1, _B_upper-_B_lower+1, count);
+  }
+  
+  inline unsigned long gamma_decode(unsigned long *count) {
+    register unsigned long _B_xx = 1;
+    register int _B_nbits = 0;
+    
+    while(!this->bit()) ++_B_nbits;
+    if (count != NULL) {
+      *count += _B_nbits*2+1;
+    }
+    while (_B_nbits-- > 0)
+      _B_xx += _B_xx + this->bit();
+    return _B_xx;
+  }
+
+  inline void gamma_encode(unsigned long x, unsigned long *count) {
+    register unsigned long _B_xx = x;
+    register int _B_logofb;
+    register int _B_nbits;
+    
+    check_positive("gamma", _B_xx);
+    _B_logofb = floor_log2(_B_xx);
+    _B_nbits = _B_logofb+1;
+    
+    if (count != NULL) { 
+      *count += _B_logofb*2+1;
+    }
+    while(_B_logofb--) encodeBit(0);
+    while (--_B_nbits>=0) encodeBit((_B_xx>>_B_nbits) & 0x1);
+  }
+  
+  inline unsigned long delta_decode(unsigned long *count) {
+    register unsigned long _B_xxx;
+    register int _B_logx;
+    _B_logx = gamma_decode(count);
+    --_B_logx;
+    _B_xxx = binary_decode(1<<_B_logx, count); 
+    --_B_xxx;
+    return (_B_xxx + (1<<_B_logx));
+  }
+
+  inline void delta_encode(unsigned long x, unsigned long *count) {
+    register unsigned long _B_xxx = x;
+    register int _B_logx;
+    _B_logx = floor_log2(_B_xxx);
+    gamma_encode(_B_logx+1, count);
+    binary_encode(_B_xxx+1, 1<<_B_logx, count);
+  }
+
+  inline unsigned long huff_decode(unsigned long *mcodes, unsigned long **values,
+				   unsigned long *count = NULL) {
+    register unsigned long *__min_code = mcodes;
+    register unsigned long *__mclen    = mcodes;
+    register unsigned long **__values  = values;
+    register unsigned long __code = 0;
+    do {
+      __code += __code + bit();
+      if (count != NULL) ++(*count);
+    } while (__code < *++__mclen);
+    
+    return __values[__mclen - __min_code][__code - *__mclen];
+  }
+
+  inline void huff_encode(unsigned long x, unsigned long *codes, char *lens,
+			  unsigned long *count = NULL) {
+    register int __i;
+    register int __clen = lens[x];
+    register unsigned long __code = codes[x];
+    for (__i=__clen-1; __i>=0; --__i) {
+      encodeBit((__code >> __i) & 1);
+    }
+    if (count != NULL) {
+      *count += lens[x];
+    }
+  }
+
+  static inline unsigned long unary_length(unsigned long x) {
+    check_positive("unary", x);
+    return x;
+  }
+
+  static inline int binary_length(unsigned long x, unsigned long b) {
+    register unsigned long _B_x = (x);
+    register unsigned long _B_b = (b);
+    register int _B_nbits, _B_logofb, _B_thresh;
+    
+    check_positive("binary", _B_x);
+    _B_logofb = ceil_log2(_B_b);
+    _B_thresh = (1<<_B_logofb) - _B_b;
+    if ((int)(--_B_x) < _B_thresh) _B_nbits = _B_logofb-1;
+    else _B_nbits = _B_logofb;
+    return _B_nbits;
+  }
+
+  static inline unsigned long bblock_length(unsigned long x, unsigned long b) {
+    register unsigned long _B_bcount, count, _B_xx = (x);
+    register unsigned long _B_bb = (b);
+    register int _B_xdivb = 0;
+    
+    check_positive("bblock", _B_xx);
+    --_B_xx;
+    while (_B_xx >= _B_bb) {
+      ++_B_xdivb;
+      _B_xx -= _B_bb;
+    }
+    count = unary_length(_B_xdivb+1);
+    _B_bcount = binary_length(_B_xx+1, _B_bb);
+    count += _B_bcount;
+    return count;
+  }
+  
+  static inline unsigned long elias_length(unsigned long x, unsigned long b, 
+					   double s) {
+    register unsigned long _B_xx = x;
+    register unsigned long _B_b = b;
+    register double _B_s = s;
+    register int _B_lower=1, _B_upper=1;
+    register int _B_k=0, _B_ecount;
+    register double _B_pow=1.0;
+    register unsigned long count;
+    check_positive("gamma", _B_xx);
+    
+    while ((int)(_B_xx)>_B_upper) {
+      ++_B_k;
+      _B_lower = _B_upper+1;
+      _B_pow *= _B_s;
+      _B_upper += (int) (_B_b*_B_pow);
+    }
+    count = unary_length(_B_k+1);
+    _B_ecount = binary_length(_B_xx-_B_lower+1, _B_upper-_B_lower+1);
+    count += _B_ecount;
+    return count;
+  }
+  
+  static inline unsigned long gamma_length(unsigned long x) {
+    register unsigned long _B_xx = x;
+    register int _B_logofb;
+    check_positive("gamma", _B_xx);
+    _B_logofb = floor_log2(_B_xx);
+    return _B_logofb*2+1;
+  }
+
+  static inline unsigned long delta_length(unsigned long x) {
+    register unsigned long _B_xxx = x;
+    register int _B_logx, _B_dcount;
+    register unsigned long count;
+    _B_logx = floor_log2 (_B_xxx);
+    count = gamma_length(_B_logx+1);
+    _B_dcount = binary_length (_B_xxx+1, 1<<_B_logx);
+    count += _B_dcount;
+    return count;
+  }
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mem.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mem.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mem.cpp	(revision 10506)
@@ -0,0 +1,128 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "bitio_m_abstract.h"
+#include "bitio_m_mem.h"
+
+mem_bitio_buffer::mem_bitio_buffer() {
+}
+
+mem_bitio_buffer::mem_bitio_buffer(unsigned char *readbuffer, int size) { 
+  pos       = readbuffer;
+  base      = readbuffer;
+  remaining = size;
+  buffer    = 0;
+  btg       = 0;
+}
+
+
+void mem_bitio_buffer::error() {
+  fprintf (stderr, "Unexpected EOF in \"%s\" on line %d\n", __FILE__, __LINE__);
+  exit(1);
+}
+
+void mem_bitio_buffer::encodeStart() {
+  btg = sizeof(buffer) * 8;
+}
+
+
+void mem_bitio_buffer::seek(unsigned long toPos) { 
+  register long _newPos;
+  do {
+    _newPos = toPos;
+    
+    pos    = base + (_newPos >> 3);
+    buffer = *pos++;
+    btg    = 8 - (_newPos & 0x07);
+  } while (0);
+}
+
+long mem_bitio_buffer::addff(long b) {
+  do {
+    if (btg == 0) {
+      if (remaining != 0) {
+	buffer = *pos++;
+	--remaining;
+      } else {
+	buffer = 0xff;
+      }
+      btg = sizeof(buffer) * 8;
+    }
+    b = b + b + ((buffer >> --btg) & 1);
+  } while(0);
+
+  return b;
+}
+
+long mem_bitio_buffer::add00(long b) {
+  do {
+    if (btg == 0) {
+      if (remaining != 0) {
+	buffer = *pos++;
+	--remaining;
+      } else {
+	buffer = 0x00;
+      }
+      btg = sizeof(buffer) * 8;
+    }
+    b = b + b + ((buffer >> --btg) & 1);
+  } while(0);
+  
+  return b;
+}
+
+int mem_bitio_buffer::bit() {
+  if (btg == 0) {
+
+    if (remaining == 0) { 
+      this->error();
+      return 0;
+
+    } else {
+      buffer = *pos++;
+      --remaining;
+      btg = sizeof(buffer) * 8;
+    }
+    
+  }
+  return ((buffer >> --btg) & 0x01);
+}
+
+void mem_bitio_buffer::encodeBit(int b) {
+  --btg;
+  if (b) buffer |= (1 << btg);
+  
+  if (btg == 0) {
+    if (remaining) {
+      *pos++ = buffer;
+      --remaining;
+    }
+    buffer = 0;
+    btg = sizeof(buffer)*8;
+  }
+}
+
+void mem_bitio_buffer::flush() {
+  if (btg != sizeof(buffer)*8) {
+    if (remaining) {
+      *pos++ = buffer;
+      --remaining;
+    }
+  }
+  btg = sizeof(buffer)*8;
+}
+
+void mem_bitio_buffer::done() {
+  // do nothing
+}
+
+int mem_bitio_buffer::encodeLength() {
+  return pos - base;
+}
+
+int mem_bitio_buffer::encodeVerify() {
+  return (remaining != 0);
+}
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mem.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mem.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mem.h	(revision 10506)
@@ -0,0 +1,104 @@
+/**************************************************************************
+ *
+ * bitio_m_mem.h -- Macros for bitio to memory
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are faster than the ones in "mems" files. But 
+ *  with these routines you cannot mix reads and writes on the array of chars,
+ *  or multiple write, at the same time and guarantee them to work, also you 
+ *  cannot seek to a point and do a write. The decode routine can detect when
+ *  you run off the end of the array and will produce an approate error 
+ *  message, and the encode routine will stop when it gets to the end of the 
+ *  character array. 
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_MEM
+#define H_BITIO_M_MEM
+
+#include "bitio_m_abstract.h"
+
+
+class mem_bitio_buffer : public bitio_buffer {
+protected:
+  unsigned char *pos;
+  unsigned char *base;
+  int            remaining;
+  unsigned char  buffer;
+  unsigned char  btg;
+  
+public:
+  mem_bitio_buffer ();
+  mem_bitio_buffer (unsigned char *buffer, int size);
+  void seek (unsigned long topos);
+  void error ();
+  long add00 (long b);
+  long addff (long b);
+  int  bit ();
+  void done ();
+
+  void encodeStart ();
+  void encodeBit (int bit);
+  void encodeDone () { flush(); }
+  int  encodeVerify ();
+  int  encodeLength ();
+  void flush ();
+};
+
+
+/*
+#define ENCODE_START(p,r)						\
+  {									\
+    mem_bitio_buffer buffer(p, r);                                     \
+    buffer.encodeStart();
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    mem_bitio_buffer buffer;                                           \
+    buffer.unpause(b);
+
+#define ENCODE_PAUSE(b)	buffer.pause(&b);}
+
+#define ENCODE_FLUSH buffer.flush()
+
+#define ENCODE_DONE buffer.flush();}
+
+
+#define DECODE_START(p,r)						\
+  {	                                                                \
+    mem_bitio_buffer buffer(p,r);
+
+#define DECODE_CONTINUE(b)						\
+  {	                                                                \
+    mem_bitio_buffer buffer;                                           \
+    buffer.unpause(b);
+
+#define DECODE_ADD_FF(b) b = buffer.addff(b)
+
+#define DECODE_ADD_00(b) b = buffer.add00(b)
+
+#define DECODE_BIT buffer.bit()
+
+#define DECODE_DONE buffer.done();}
+
+#define DECODE_PAUSE(b) buffer.pause(&b);}
+*/
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mems.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mems.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mems.cpp	(revision 10506)
@@ -0,0 +1,89 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "bitio_m_abstract.h"
+#include "bitio_m_mems.h"
+
+/**
+ * Create decoding "stream"/"file"
+ */
+mems_bitio_buffer::mems_bitio_buffer()
+{
+}
+
+mems_bitio_buffer::mems_bitio_buffer(unsigned char *readbuffer, long _pos)
+{ 
+  base = readbuffer;
+  pos  = _pos;
+}
+
+void mems_bitio_buffer::encodeStart()
+{
+  // Do nothing
+}
+
+
+void mems_bitio_buffer::error()
+{
+  fprintf(stderr, "Unexpected EOF in \"%s\" on line %d\n", __FILE__, __LINE__);
+  exit(1);
+}
+
+
+void mems_bitio_buffer::seek(unsigned long toPos)
+{ 
+  pos = toPos;
+}
+
+unsigned long mems_bitio_buffer::position()
+{
+  return pos;
+}
+
+long mems_bitio_buffer::addff(long b)
+{
+  do
+    {
+      b = b + b + (base[pos>>3] & (0x80 >> (pos & 0x07)) != 0);
+      ++pos;
+    }
+  while(0);
+
+  return b;
+}
+
+long mems_bitio_buffer::add00(long b)
+{
+  return addff(b);
+}
+
+int mems_bitio_buffer::bit()
+{
+  ++pos;
+  return ((base[(pos-1)>>3] & (0x80 >> ((pos-1) & 0x07))) != 0);
+}
+
+void mems_bitio_buffer::encodeBit(int bit)
+{
+  if (bit)
+    base[pos>>3] |= 0x80 >> (pos & 0x07);
+  else
+    base[pos>>3] &= 0xff7f >> (pos & 0x07);
+  ++pos;
+}
+
+void mems_bitio_buffer::flush()
+{
+  // do nothing
+}
+
+void mems_bitio_buffer::done()
+{
+  // do nothing
+}
+
+void mems_bitio_buffer::encodeDone()
+{
+  flush();
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mems.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mems.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_mems.h	(revision 10506)
@@ -0,0 +1,100 @@
+/**************************************************************************
+ *
+ * bitio_m_mems.h -- Macros for bitio to memory (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are slower than the ones in "mem" files. but 
+ *  with these routines you can mix reads and writes, or multiple writes,  on
+ *  the array of chars at the same time and guarantee them to work, also you 
+ *  can seek to a point and do a write. The decode and encode macros cannot 
+ *  detect when the end off the character is reached and just continue 
+ *  processing.
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_MEMS
+#define H_BITIO_M_MEMS
+
+#include "bitio_m_abstract.h"
+
+
+class mems_bitio_buffer : public bitio_buffer {
+protected:
+  unsigned char *base;
+  unsigned long  pos;
+  
+public:
+  mems_bitio_buffer();
+  mems_bitio_buffer(unsigned char *readbuffer, long _pos);
+  void seek(unsigned long topos);
+  void error();
+  long add00(long b);
+  long addff(long b);
+  int  bit();
+  //  int  bitOffset();
+  void done();
+
+  unsigned long position();
+
+  void encodeStart();
+  void encodeBit(int b);
+  void encodeDone();
+  void flush();
+};
+
+
+/*#define ENCODE_START(b,p)						\
+  {									\
+    mems_bitio_buffer buffer(b, p);
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    mems_bitio_buffer buffer;                                          \
+    buffer.unpause(b);
+
+#define ENCODE_PAUSE(b)	buffer.pause(&b);}
+
+#define ENCODE_FLUSH buffer.flush();
+
+
+#define ENCODE_DONE buffer.encodeDone();}
+
+
+#define DECODE_START(b,p)						\
+  {		                                                        \
+    mems_bitio_buffer buffer(b, p);
+
+#define DECODE_CONTINUE(b)						\
+  {									\
+    mems_bitio_buffer buffer;                                          \
+    buffer.unpause(b);
+
+#define DECODE_ADD_FF(b) b = buffer.addff(b);
+
+#define DECODE_ADD_00(b) b = buffer.add00(b);
+
+#define DECODE_BIT buffer.bit()
+
+#define DECODE_DONE buffer.done();}
+
+#define DECODE_PAUSE(b) buffer.pause(&b);}
+*/
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_random.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_random.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_random.cpp	(revision 10506)
@@ -0,0 +1,218 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "longlong.h"
+#include "sysfuncs.h"
+#include "memlib.h"
+
+#include "bitio_m_abstract.h"
+#include "bitio_m_random.h"
+
+random_bitio_buffer::random_bitio_buffer(FILE *f, unsigned long length)
+{
+  buffer = NULL;
+  attachFile (f, length);
+}
+
+random_bitio_buffer::~random_bitio_buffer() {
+  if (buffer != NULL) delete []buffer;
+}
+
+void random_bitio_buffer::attachFile (FILE *f, unsigned long length) {
+  // delete the old buffer
+  if (buffer != NULL) {
+    delete []buffer;
+    buffer = NULL;
+  }
+
+  // reset all the values
+  file   = f;
+  pos    = 0;
+  base   = 0;
+  used   = 0;
+  len    = length - 1;
+  shift  = 0;
+
+  // make sure the length is a power of 2
+  while (len != 0) {
+    ++shift;
+    len = len >> 1;
+  }
+  len = 1 << shift;
+
+  // allocate a new buffer
+  buffer = new u_char[len];
+
+  // fill up the buffer
+  if (file != NULL) {
+    fseek(file, 0, 0);
+    fread(buffer, 1, len, file);
+  }
+}
+
+random_bitio_buffer &random_bitio_buffer::operator= (const random_bitio_buffer &_rbb) {
+  // delete the old buffer
+  if (buffer != NULL) {
+    delete []buffer;
+    buffer = NULL;
+  }
+
+  file = _rbb.file;
+
+  base = _rbb.base;
+  used = _rbb.used;
+  pos = _rbb.pos;
+  len = _rbb.len;
+  shift = _rbb.shift;
+
+  // copy the buffer
+  buffer = new u_char [len];
+  //  memcpy (buffer, _rbb.buffer, len);
+memcpy (buffer, _rbb.buffer, len);
+  
+  return (*this);
+}
+
+void random_bitio_buffer::error() {
+}
+
+void random_bitio_buffer::writeRead()
+{
+  if (used)
+    {
+      fseek(file, base, 0);
+      fwrite(buffer, 1, len, file);
+    }
+  //  else
+  //    {
+      base += len;
+      fseek(file, base, 0);
+      fread(buffer, 1, len, file);
+      pos = 0;
+      used = 0;
+  //    }
+}
+
+void random_bitio_buffer::encodeBit(int bit)
+{
+  do
+    {
+      if (bit != 0)
+	{
+	  buffer[pos >> 3] |= 0x80 >> (pos & 0x07);
+	}
+      else
+	{
+	  buffer[pos >> 3] &= 0xff7f >> (pos & 0x07);
+	}
+      used = 1;
+      ++pos;
+
+      if ((pos >> 3) >= len)
+	{
+	  writeRead();
+	}
+    }
+  while (0);
+}
+
+void random_bitio_buffer::flush()
+{
+  if (used != 0)
+    {
+      fseek(file, base, 0);
+      fwrite(buffer, 1, len, file);
+      used = 0;
+    }
+}
+
+void random_bitio_buffer::encodeDone()
+{
+  flush();
+  if (buffer != NULL) {
+    delete []buffer;
+    buffer = NULL;
+  }
+}
+
+unsigned long random_bitio_buffer::tell()
+{
+  return ((base << 3) + pos);
+}
+
+void random_bitio_buffer::seek(unsigned long toPos)
+{
+  if (((toPos >> 3) >= base) && (((toPos+7) >> 3) < (base + len)))
+    {
+      pos = toPos - (base << 3);
+    }
+  else
+    {
+      flush();
+      base = toPos >> 3;
+      base = (toPos >> (shift + 3)) << shift;
+      fseek(file, base, 0);
+      fread(buffer, 1, len, file);
+      pos = toPos & 0x07;
+      pos = toPos & ((8 << shift) - 1);
+    }
+}
+
+int random_bitio_buffer::bit()
+{
+  //  fprintf(stderr, "Bit in");
+  ++pos;
+  if (((pos - 1) >> 3) >= len)
+    {
+      writeRead();
+      pos = 1;
+    }
+  return (buffer[(pos - 1) >> 3] & (0x80 >> ((pos - 1) & 0x07))) != 0;
+}
+
+long random_bitio_buffer::addff(long b)
+{
+  return b + b + bit();
+}
+
+long random_bitio_buffer::add00(long b)
+{
+  return addff(b);
+}
+
+int random_bitio_buffer::bitOffset()
+{
+  return 0;
+}
+
+void random_bitio_buffer::done()
+{
+  encodeDone();
+}
+
+
+#ifdef USE_LONG_LONG
+void random_bitio_buffer::seek_LL(mg_ullong toPos)
+{
+  if (((toPos >> 3) >= (mg_ullong) base) &&
+      (((toPos + 7) >> 3) < (mg_ullong) (base + len)))
+    {
+      pos = (long) (toPos - (mg_ullong) (base << 3));
+    }
+  else
+    {
+      flush();
+      base = (long) ((toPos >> (shift + 3)) << shift);
+
+      fseek(file, base, 0);
+      fread(buffer, 1, len, file);
+      pos = (long) (toPos & ((8 << shift) - 1));
+    }
+}
+
+mg_ullong random_bitio_buffer::tell_LL()
+{
+  return (((mg_ullong) base) << 3ull) + pos;
+}
+#endif
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_random.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_random.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_random.h	(revision 10506)
@@ -0,0 +1,127 @@
+/**************************************************************************
+ *
+ * bitio_m_random.h -- Macros for bitio to a file (random access)
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on an array 
+ *  of chars. These routines are slower than the ones in "mem" files. but 
+ *  with these routines you can mix reads and writes, or multiple writes,  on
+ *  the array of chars at the same time and guarantee them to work, also you 
+ *  can seek to a point and do a write. The decode and encode macros cannot 
+ *  detect when the end off the character is reached and just continue 
+ *  processing.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_RANDOM
+#define H_BITIO_M_RANDOM
+
+#include "longlong.h"
+#include "bitio_m_abstract.h"
+
+
+class random_bitio_buffer : public bitio_buffer { 
+public:
+  FILE *file;
+  unsigned char *buffer;
+  unsigned long  base;
+  unsigned long  used;
+  unsigned long  pos;
+  unsigned long  len;
+  unsigned long  shift;
+  void writeRead();
+
+  random_bitio_buffer(FILE *f = 0,
+		      unsigned long length = 8*1024);
+  virtual ~random_bitio_buffer();
+  
+  void attachFile (FILE *f, unsigned long length);
+
+  random_bitio_buffer &operator= (const random_bitio_buffer &_rbb);
+  
+  void encodeDone();
+  void encodeBit(int b);
+  void flush();
+  unsigned long tell();
+
+  void seek(unsigned long topos);
+  void error();
+  long add00(long b);
+  long addff(long b);
+  int  bit();
+  int  bitOffset();
+  void done();
+
+#ifdef USE_LONG_LONG
+  // extras for longlong.h
+  void seek_LL(mg_ullong pos);
+  mg_ullong tell_LL();
+#endif
+};
+
+
+/*#define ENCODE_START(f,l)						\
+  {									\
+    random_bitio_buffer buffer(f, l);
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    random_bitio_buffer buffer;                                               \
+    buffer.unpause(b);
+
+#define SEEK fprintf(stderr, "Seek to %d\n",buffer.base)
+#define READ fprintf(stderr, "Read of %d\n",buffer.len)
+#define WRITE fprintf(stderr, "Write of %d\n",buffer.used)
+
+#define WRITE_READ buffer.writeRead()
+
+#define ENCODE_PAUSE(b)	buffer.pause(&b);}
+
+#define ENCODE_FLUSH buffer.flush();
+
+#define ENCODE_DONE buffer.done();}							
+
+#define DECODE_START(f,l) \
+  {									\
+    random_bitio_buffer buffer(f, l);
+
+#define DECODE_CONTINUE(b) \
+  {									\
+    random_bitio_buffer buffer;                                               \
+    buffer.unpause(b);
+
+#define DECODE_BIT buffer.bit()
+
+#define DECODE_ADD_FF(b) b = buffer.addff(b)
+
+#define DECODE_ADD_00(b) b = buffer.add00(b)
+
+#define DECODE_DONE buffer.done();}
+
+#define DECODE_PAUSE(b)	buffer.pause(&b);}
+
+#define ENCODE_TELL buffer.tell()
+
+#define DECODE_TELL buffer.tell()
+*/
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_stdio.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_stdio.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_stdio.cpp	(revision 10506)
@@ -0,0 +1,125 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "bitio_m_stdio.h"
+
+stdio_bitio_buffer::stdio_bitio_buffer(FILE *f) {
+  attachFile (f);
+}
+
+void stdio_bitio_buffer::attachFile (FILE *f) {
+  file = f;
+  buffer = 0;
+  btg = 0;
+  bytesWritten = 0;
+}
+
+void stdio_bitio_buffer::encodeStart() {
+  btg = sizeof(buffer) * 8;
+}
+
+void stdio_bitio_buffer::error() {
+  fprintf(stderr, "Unexpected EOF in \"%s\" on line %d", __FILE__, __LINE__);
+  exit(1);
+}
+
+void stdio_bitio_buffer::seek (unsigned long byte, unsigned char bit) {
+  if (fseek (file, byte, SEEK_SET) != 0) return;
+  buffer = getc(file);
+  btg = bit;
+  bytesWritten = 0;
+}
+
+void stdio_bitio_buffer::seek(unsigned long topos) {
+  if (fseek(file, topos >> 3, SEEK_SET) != 0) return;
+  buffer = getc(file);
+  btg = 8 - (topos & 0x07);
+  bytesWritten = 0;
+}
+
+long stdio_bitio_buffer::addff(long b)
+{
+  if (!btg)
+    {
+      register int val;
+      val = getc(file);
+      if (val == EOF)
+	{
+	  buffer = 0x0ff;
+	}
+      else
+	{
+	  buffer = val;
+	}
+      btg = sizeof(buffer) * 8;
+    }
+  b = b + b + ((buffer >> --btg) & 0x01);
+
+  return b;
+}
+
+long stdio_bitio_buffer::add00(long b)
+{
+  if (!btg)
+    {
+      register int val;
+      val = getc(file);
+      if (val == EOF)
+	{
+	  buffer = 0xff;
+	}
+      else
+	{
+	  buffer = val;
+	}
+      btg = sizeof(buffer) * 8;
+    }
+  b = b + b + ((buffer >> --btg) & 0x01);
+  
+  return b;
+}
+
+void stdio_bitio_buffer::encodeBit(int b)
+{
+  --btg;
+  if (b != 0)
+    buffer |= (1 << btg);
+
+  if (btg == 0)
+    {
+      putc(buffer, file);
+      bytesWritten += sizeof (buffer);
+      buffer = 0;
+      btg = sizeof(buffer)*8;
+    }
+}
+
+int stdio_bitio_buffer::bit()
+{
+  if (btg == 0)
+    {
+      buffer = getc(file);
+      if (feof(file))
+	{
+	  error();
+	  return 0;
+	}
+      else
+	{
+	  btg = sizeof(buffer) * 8;
+	}
+    }
+  return ((buffer >> --btg) & 0x01);
+}
+
+void stdio_bitio_buffer::done() {
+  // no tidying required
+}
+
+void stdio_bitio_buffer::encodeDone() {
+  if (btg != sizeof(buffer) * 8) {
+    putc(buffer, file);
+    bytesWritten += sizeof (buffer);
+  }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_stdio.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_stdio.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/bitio_m_stdio.h	(revision 10506)
@@ -0,0 +1,101 @@
+/**************************************************************************
+ *
+ * bitio_m_stdio.h -- Macros for bitio to a file
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************
+ *
+ *  This file contains macros for doing bitwise input and output on a FILE*.
+ *  With these routines you cannot mix reads and writes on the FILE,
+ *  or multiple writes, at the same time and guarantee them to work, also you 
+ *  cannot seek to a point and do a write. The decode routine can detect when
+ *  you run off the end of the file and will produce an approate error message.
+ *
+ *
+ **************************************************************************/
+
+#ifndef H_BITIO_M_STDIO
+#define H_BITIO_M_STDIO
+
+#include "bitio_m_abstract.h"
+
+
+class stdio_bitio_buffer : public bitio_buffer {
+protected:
+  FILE *file;
+  unsigned char buffer;
+  unsigned char btg;
+  unsigned long bytesWritten;
+  
+public:
+  stdio_bitio_buffer (FILE *f = NULL);
+
+  void attachFile (FILE *f);
+
+  unsigned char GetBtg () { return btg; }
+  unsigned long GetBytesWritten () { return bytesWritten; }
+  
+  void seek (unsigned long byte, unsigned char bit);
+  void seek (unsigned long topos);
+  void error();
+  long add00(long b);
+  long addff(long b);
+  int  bit();
+  int  bitOffset() { return btg; }
+  void done();
+
+  void encodeStart();
+  void encodeBit(int bit);
+  void encodeDone();
+};
+
+
+/*#define ENCODE_START(f)							\
+  {									\
+    stdio_bitio_buffer buffer(f);                                       \
+    buffer.encodeStart();
+
+#define ENCODE_CONTINUE(b)						\
+  {									\
+    stdio_bitio_buffer buffer;                                          \
+    buffer.unpause(b);
+
+#define ENCODE_PAUSE(b) buffer.pause(&b);}
+
+#define ENCODE_DONE buffer.encodeDone();}
+
+#define DECODE_START(f)							\
+  {		                                                        \
+    stdio_bitio_buffer buffer(f);
+
+#define DECODE_CONTINUE(b)						\
+  {									\
+    stdio_bitio_buffer buffer;                                          \
+     buffer.unpause(b);
+
+#define DECODE_ADD_FF(b) b = buffer.addff(b)
+
+#define DECODE_ADD_00(b) b = buffer.add00(b)
+
+#define DECODE_BIT buffer.bit()
+
+#define DECODE_DONE buffer.done();}
+
+#define DECODE_PAUSE(b) buffer.pause(&b);}
+*/
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/ftruncate.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/ftruncate.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/ftruncate.cpp	(revision 10506)
@@ -0,0 +1,99 @@
+/* ftruncate emulations that work on some System V's.
+   This file is in the public domain.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef F_CHSIZE
+
+int
+ftruncate (int fd, off_t length)
+{
+  return fcntl (fd, F_CHSIZE, length);
+}
+
+#else /* not F_CHSIZE */
+#ifdef F_FREESP
+
+/* By William Kucharski <kucharsk@netcom.com>.  */
+
+#include <sys/stat.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+int
+ftruncate (int fd, off_t length)
+{
+  struct flock fl;
+  struct stat filebuf;
+
+  if (fstat (fd, &filebuf) < 0)
+    return -1;
+
+  if (filebuf.st_size < length)
+    {
+      /* Extend file length. */
+      if (lseek (fd, (length - 1), SEEK_SET) < 0)
+	return -1;
+
+      /* Write a "0" byte. */
+      if (write (fd, "", 1) != 1)
+	return -1;
+    }
+  else
+    {
+
+      /* Truncate length. */
+
+      fl.l_whence = 0;
+      fl.l_len = 0;
+      fl.l_start = length;
+      fl.l_type = F_WRLCK;	/* write lock on file space */
+
+      /* This relies on the *undocumented* F_FREESP argument to fcntl,
+	 which truncates the file so that it ends at the position
+	 indicated by fl.l_start.  Will minor miracles never cease?  */
+
+      if (fcntl (fd, F_FREESP, &fl) < 0)
+	return -1;
+    }
+
+  return 0;
+}
+
+#else /* not F_CHSIZE nor F_FREESP */
+#ifdef HAVE_CHSIZE
+
+int
+ftruncate (int fd, off_t length)
+{
+  return chsize (fd, length);
+}
+
+#else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+int
+ftruncate (int fd, off_t length)
+{
+  errno = EIO;
+  return -1;
+}
+
+#endif /* not HAVE_CHSIZE */
+#endif /* not F_FREESP */
+#endif /* not F_CHSIZE */
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/getopt_old.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/getopt_old.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/getopt_old.c	(revision 10506)
@@ -0,0 +1,748 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+   Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+
+#if !__STDC__ && !defined(const) && IN_GCC
+#define const
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#endif /* GNU C library.  */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+/* jrm21 - GSDL: getopt.h -> getopt_old.h */
+#include "getopt_old.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+  {
+    REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+  }
+ordering;
+
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define	my_index	strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif /* GNU C library.  */
+
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* Determine how to handle the ordering of options and nonoptions.  */
+
+      if (optstring[0] == '-')
+	{
+	  ordering = RETURN_IN_ORDER;
+	  ++optstring;
+	}
+      else if (optstring[0] == '+')
+	{
+	  ordering = REQUIRE_ORDER;
+	  ++optstring;
+	}
+      else if (getenv ("POSIXLY_CORRECT") != NULL)
+	ordering = REQUIRE_ORDER;
+      else
+	ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Now skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc
+		 && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+		 && (longopts == NULL
+		     || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+	    )
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* Special ARGV-element `--' means premature end of options.
+         Skip it like a null option,
+         then exchange with previous non-options as if it were an option,
+         then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+         and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return EOF;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+         either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+	  && (longopts == NULL
+	      || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+	)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return EOF;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+         Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+	   && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+	  || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+      ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound;
+
+      while (*s && *s != '=')
+	s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+	   p++, option_index++)
+	if (!strncmp (p->name, nextchar, s - nextchar))
+	  {
+	    if (s - nextchar == strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, "%s: option `%s' is ambiguous\n",
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*s)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+	         allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = s + 1;
+	      else
+		{
+		  if (opterr)
+		    {
+		      if (argv[optind - 1][1] == '-')
+			/* --option */
+			fprintf (stderr,
+			    "%s: option `--%s' doesn't allow an argument\n",
+				 argv[0], pfound->name);
+		      else
+			/* +option or -option */
+			fprintf (stderr,
+			    "%s: option `%c%s' doesn't allow an argument\n",
+				 argv[0], argv[optind - 1][0], pfound->name);
+		    }
+		  nextchar += strlen (nextchar);
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr, "%s: option `%s' requires an argument\n",
+			     argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+         or the option starts with '--' or is not a valid short
+         option, then it's an error.
+         Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+	  || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, "%s: unrecognized option `--%s'\n",
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+#if 0
+	    if (c < 040 || c >= 0177)
+	      fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+		       argv[0], c);
+	    else
+	      fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+	    /* 1003.2 specifies the format of this message.  */
+	    fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+	  }
+	optopt = c;
+	return '?';
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = 0;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+#if 0
+		    fprintf (stderr, "%s: option `-%c' requires an argument\n",
+			     argv[0], c);
+#else
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr, "%s: option requires an argument -- %c\n",
+			     argv[0], c);
+#endif
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+	         increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/getopt_old.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/getopt_old.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/getopt_old.h	(revision 10506)
@@ -0,0 +1,134 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the
+   Free Software Foundation; either version 2, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef HAVE_DECL_GETOPT
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+  extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+  extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+  extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+  extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument          (or 0) if the option does not take an argument,
+   required_argument    (or 1) if the option requires an argument,
+   optional_argument    (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+  struct option
+    {
+#if	__STDC__
+      const char *name;
+#else
+      char *name;
+#endif
+      /* has_arg can't be an enum because some compilers complain about
+         type mismatches in all the code that assumes it is an int.  */
+      int has_arg;
+      int *flag;
+      int val;
+    };
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+  extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else				/* not __GNU_LIBRARY__ */
+  int getopt (int, char * const *, const char *);
+#endif				/* not __GNU_LIBRARY__ */
+  extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+			  const struct option *longopts, int *longind);
+  extern int getopt_long_only (int argc, char *const *argv,
+			       const char *shortopts,
+			       const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+  extern int _getopt_internal (int argc, char *const *argv,
+			       const char *shortopts,
+			       const struct option *longopts, int *longind,
+			       int long_only);
+#else				/* not __STDC__ */
+  extern int getopt ();
+  extern int getopt_long ();
+  extern int getopt_long_only ();
+
+  extern int _getopt_internal ();
+#endif				/* not __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif				/* _GETOPT_H */
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/getpagesize.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/getpagesize.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/getpagesize.h	(revision 10506)
@@ -0,0 +1,38 @@
+/* Emulate getpagesize on systems that lack it.  */
+
+#ifndef HAVE_GETPAGESIZE
+
+#ifdef VMS
+#define getpagesize() 512
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef _SC_PAGESIZE
+#define getpagesize() sysconf(_SC_PAGESIZE)
+#else
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifndef __WIN32__
+#include <sys/param.h>
+#endif
+
+#ifdef EXEC_PAGESIZE
+#define getpagesize() EXEC_PAGESIZE
+#else
+#ifdef NBPG
+#define getpagesize() NBPG * CLSIZE
+#ifndef CLSIZE
+#define CLSIZE 1
+#endif /* no CLSIZE */
+#else /* no NBPG */
+#ifdef NBPC
+#define getpagesize() NBPC
+#endif /* NBPC */
+#endif /* no NBPG */
+#endif /* no EXEC_PAGESIZE */
+#endif /* no _SC_PAGESIZE */
+
+#endif /* not HAVE_GETPAGESIZE */
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/gmalloc.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/gmalloc.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/gmalloc.c	(revision 10506)
@@ -0,0 +1,1318 @@
+/* DO NOT EDIT THIS FILE -- it is automagically generated.  -*- C -*- */
+
+#define _MALLOC_INTERNAL
+
+/* The malloc headers and source files from the C library follow here.  */
+
+/* Declarations for `malloc' and friends.
+   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef _MALLOC_H
+
+#define _MALLOC_H	1
+
+#ifdef _MALLOC_INTERNAL
+
+#ifdef	HAVE_CONFIG_H
+#include <sysfuncs.h>
+#endif
+
+#if	defined(_LIBC) || defined(STDC_HEADERS) || defined(USG)
+#include <string.h>
+#else
+#ifndef memset
+#define	memset(s, zero, n)	bzero ((s), (n))
+#endif
+#ifndef memcpy
+#define	memcpy(d, s, n)		bcopy ((s), (d), (n))
+#endif
+#endif
+
+#if	defined(__GNU_LIBRARY__) || __STDC__
+#include <limits.h>
+#else
+#define	CHAR_BIT	8
+#endif
+
+#ifdef	HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#endif	/* _MALLOC_INTERNAL.  */
+
+
+#ifdef	__cplusplus
+extern "C"
+{
+#endif
+
+#if defined (__cplusplus) || __STDC__
+#undef	__P
+#define	__P(args)	args
+#undef	__ptr_t
+#define	__ptr_t		void *
+#else /* Not C++ or ANSI C.  */
+#undef	__P
+#define	__P(args)	()
+#undef	const
+#define	const
+#undef	__ptr_t
+#define	__ptr_t		char *
+#endif /* C++ or ANSI C.  */
+
+#if	__STDC__
+#include <stddef.h>
+#else
+#undef	size_t
+#define	size_t		unsigned int
+#undef	ptrdiff_t
+#define	ptrdiff_t	int
+#endif
+
+#ifndef	NULL
+#define	NULL	0
+#endif
+
+
+/* Allocate SIZE bytes of memory.  */
+extern __ptr_t malloc __P ((size_t __size));
+/* Re-allocate the previously allocated block
+   in __ptr_t, making the new block SIZE bytes long.  */
+extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size));
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0.  */
+extern __ptr_t calloc __P ((size_t __nmemb, size_t __size));
+/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
+extern void free __P ((__ptr_t __ptr));
+
+/* Allocate SIZE bytes allocated to ALIGNMENT bytes.  */
+extern __ptr_t memalign __P ((size_t __alignment, size_t __size));
+
+/* Allocate SIZE bytes on a page boundary.  */
+extern __ptr_t valloc __P ((size_t __size));
+
+
+#ifdef _MALLOC_INTERNAL
+
+/* The allocator divides the heap into blocks of fixed size; large
+   requests receive one or more whole blocks, and small requests
+   receive a fragment of a block.  Fragment sizes are powers of two,
+   and all fragments of a block are the same size.  When all the
+   fragments in a block have been freed, the block itself is freed.  */
+#define INT_BIT		(CHAR_BIT * sizeof(int))
+#define BLOCKLOG	(INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE	(1 << BLOCKLOG)
+#define BLOCKIFY(SIZE)	(((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+
+/* Determine the amount of memory spanned by the initial heap table
+   (not an absolute limit).  */
+#define HEAP		(INT_BIT > 16 ? 4194304 : 65536)
+
+/* Number of contiguous free blocks allowed to build up at the end of
+   memory before they will be returned to the system.  */
+#define FINAL_FREE_BLOCKS	8
+
+/* Data structure giving per-block information.  */
+typedef union
+  {
+    /* Heap information for a busy block.  */
+    struct
+      {
+	/* Zero for a large block, or positive giving the
+	   logarithm to the base two of the fragment size.  */
+	int type;
+	union
+	  {
+	    struct
+	      {
+		size_t nfree;	/* Free fragments in a fragmented block.  */
+		size_t first;	/* First free fragment of the block.  */
+	      } frag;
+	    /* Size (in blocks) of a large cluster.  */
+	    size_t size;
+	  } info;
+      } busy;
+    /* Heap information for a free block
+       (that may be the first of a free cluster).  */
+    struct
+      {
+	size_t size;		/* Size (in blocks) of a free cluster.  */
+	size_t next;		/* Index of next free cluster.  */
+	size_t prev;		/* Index of previous free cluster.  */
+      } free;
+  } malloc_info;
+
+/* Pointer to first block of the heap.  */
+extern char *_heapbase;
+
+/* Table indexed by block number giving per-block information.  */
+extern malloc_info *_heapinfo;
+
+/* Address to block number and vice versa.  */
+#define BLOCK(A)	(((char *) (A) - _heapbase) / BLOCKSIZE + 1)
+#define ADDRESS(B)	((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase))
+
+/* Current search index for the heap table.  */
+extern size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+extern size_t _heaplimit;
+
+/* Doubly linked lists of free fragments.  */
+struct list
+  {
+    struct list *next;
+    struct list *prev;
+  };
+
+/* Free list headers for each fragment size.  */
+extern struct list _fraghead[];
+
+/* List of blocks allocated with `memalign' (or `valloc').  */
+struct alignlist
+  {
+    struct alignlist *next;
+    __ptr_t aligned;		/* The address that memaligned returned.  */
+    __ptr_t exact;		/* The address that malloc returned.  */
+  };
+extern struct alignlist *_aligned_blocks;
+
+/* Instrumentation.  */
+extern size_t _chunks_used;
+extern size_t _bytes_used;
+extern size_t _chunks_free;
+extern size_t _bytes_free;
+
+/* Internal version of `free' used in `morecore' (malloc.c). */
+extern void _free_internal __P ((__ptr_t __ptr));
+
+#endif /* _MALLOC_INTERNAL.  */
+
+/* Underlying allocation function; successive calls should
+   return contiguous pieces of memory.  */
+extern __ptr_t (*__morecore) __P ((ptrdiff_t __size));
+
+/* Default value of `__morecore'.  */
+extern __ptr_t __default_morecore __P ((ptrdiff_t __size));
+
+/* If not NULL, this function is called after each time
+   `__morecore' is called to increase the data size.  */
+extern void (*__after_morecore_hook) __P ((void));
+
+/* Nonzero if `malloc' has been called and done its initialization.  */
+extern int __malloc_initialized;
+
+/* Hooks for debugging versions.  */
+extern void (*__free_hook) __P ((__ptr_t __ptr));
+extern __ptr_t (*__malloc_hook) __P ((size_t __size));
+extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Return values for `mprobe': these are the kinds of inconsistencies that
+   `mcheck' enables detection of.  */
+enum mcheck_status
+  {
+    MCHECK_DISABLED = -1,	/* Consistency checking is not turned on.  */
+    MCHECK_OK,			/* Block is fine.  */
+    MCHECK_FREE,		/* Block freed twice.  */
+    MCHECK_HEAD,		/* Memory before the block was clobbered.  */
+    MCHECK_TAIL			/* Memory after the block was clobbered.  */
+  };
+
+/* Activate a standard collection of debugging hooks.  This must be called
+   before `malloc' is ever called.  ABORTFUNC is called with an error code
+   (see enum above) when an inconsistency is detected.  If ABORTFUNC is
+   null, the standard function prints on stderr and then calls `abort'.  */
+extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status))));
+
+/* Check for aberrations in a particular malloc'd block.  You must have
+   called `mcheck' already.  These are the same checks that `mcheck' does
+   when you free or reallocate a block.  */
+extern enum mcheck_status mprobe __P ((__ptr_t __ptr));
+
+/* Activate a standard collection of tracing hooks.  */
+extern void mtrace __P ((void));
+
+/* Statistics available to the user.  */
+struct mstats
+  {
+    size_t bytes_total;		/* Total size of the heap. */
+    size_t chunks_used;		/* Chunks allocated by the user. */
+    size_t bytes_used;		/* Byte total of user-allocated chunks. */
+    size_t chunks_free;		/* Chunks in the free list. */
+    size_t bytes_free;		/* Byte total of chunks in the free list. */
+  };
+
+/* Pick up the current statistics. */
+extern struct mstats mstats __P ((void));
+
+/* Call WARNFUN with a warning message when memory usage is high.  */
+extern void memory_warnings __P ((__ptr_t __start,
+				  void (*__warnfun) __P ((const char *))));
+
+
+/* Relocating allocator.  */
+
+/* Allocate SIZE bytes, and store the address in *HANDLEPTR.  */
+extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size));
+
+/* Free the storage allocated in HANDLEPTR.  */
+extern void r_alloc_free __P ((__ptr_t *__handleptr));
+
+/* Adjust the block at HANDLEPTR to be SIZE bytes long.  */
+extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size));
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* malloc.h  */
+/* Allocate memory on a page boundary.
+   Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#if defined (__GNU_LIBRARY__) || defined (_LIBC)
+#include <stddef.h>
+#include <sys/cdefs.h>
+extern size_t __getpagesize __P ((void));
+#else
+#include "getpagesize.h"
+#define	 __getpagesize()	getpagesize()
+#endif
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+static size_t pagesize;
+
+__ptr_t
+valloc (size)
+     size_t size;
+{
+  if (pagesize == 0)
+    pagesize = __getpagesize ();
+
+  return memalign (pagesize, size);
+}
+/* Memory allocator `malloc'.
+   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* How to really get more memory.  */
+__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore;
+
+/* Debugging hook for `malloc'.  */
+__ptr_t (*__malloc_hook) __P ((size_t __size));
+
+/* Pointer to the base of the first block.  */
+char *_heapbase;
+
+/* Block information table.  Allocated with align/__free (not malloc/free).  */
+malloc_info *_heapinfo;
+
+/* Number of info entries.  */
+static size_t heapsize;
+
+/* Search index in the info table.  */
+size_t _heapindex;
+
+/* Limit of valid info table indices.  */
+size_t _heaplimit;
+
+/* Free lists for each fragment size.  */
+struct list _fraghead[BLOCKLOG];
+
+/* Instrumentation.  */
+size_t _chunks_used;
+size_t _bytes_used;
+size_t _chunks_free;
+size_t _bytes_free;
+
+/* Are you experienced?  */
+int __malloc_initialized;
+
+void (*__after_morecore_hook) __P ((void));
+
+/* Aligned allocation.  */
+static __ptr_t align __P ((size_t));
+static __ptr_t
+align (size)
+     size_t size;
+{
+  __ptr_t result;
+  unsigned long int adj;
+
+  result = (*__morecore) (size);
+  adj = (unsigned long int) ((unsigned long int) ((char *) result -
+						  (char *) NULL)) % BLOCKSIZE;
+  if (adj != 0)
+    {
+      adj = BLOCKSIZE - adj;
+      (void) (*__morecore) (adj);
+      result = (char *) result + adj;
+    }
+
+  if (__after_morecore_hook)
+    (*__after_morecore_hook) ();
+
+  return result;
+}
+
+/* Set everything up and remember that we have.  */
+static int initialize __P ((void));
+static int
+initialize ()
+{
+  heapsize = HEAP / BLOCKSIZE;
+  _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info));
+  if (_heapinfo == NULL)
+    return 0;
+  memset (_heapinfo, 0, heapsize * sizeof (malloc_info));
+  _heapinfo[0].free.size = 0;
+  _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
+  _heapindex = 0;
+  _heapbase = (char *) _heapinfo;
+
+  /* Account for the _heapinfo block itself in the statistics.  */
+  _bytes_used = heapsize * sizeof (malloc_info);
+  _chunks_used = 1;
+
+  __malloc_initialized = 1;
+  return 1;
+}
+
+/* Get neatly aligned memory, initializing or
+   growing the heap info table as necessary. */
+static __ptr_t morecore __P ((size_t));
+static __ptr_t
+morecore (size)
+     size_t size;
+{
+  __ptr_t result;
+  malloc_info *newinfo, *oldinfo;
+  size_t newsize;
+
+  result = align (size);
+  if (result == NULL)
+    return NULL;
+
+  /* Check if we need to grow the info table.  */
+  if ((size_t) BLOCK ((char *) result + size) > heapsize)
+    {
+      newsize = heapsize;
+      while ((size_t) BLOCK ((char *) result + size) > newsize)
+	newsize *= 2;
+      newinfo = (malloc_info *) align (newsize * sizeof (malloc_info));
+      if (newinfo == NULL)
+	{
+	  (*__morecore) (-size);
+	  return NULL;
+	}
+      memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info));
+      memset (&newinfo[heapsize], 0,
+	      (newsize - heapsize) * sizeof (malloc_info));
+      oldinfo = _heapinfo;
+      newinfo[BLOCK (oldinfo)].busy.type = 0;
+      newinfo[BLOCK (oldinfo)].busy.info.size
+	= BLOCKIFY (heapsize * sizeof (malloc_info));
+      _heapinfo = newinfo;
+      /* Account for the _heapinfo block itself in the statistics.  */
+      _bytes_used += newsize * sizeof (malloc_info);
+      ++_chunks_used;
+      _free_internal (oldinfo);
+      heapsize = newsize;
+    }
+
+  _heaplimit = BLOCK ((char *) result + size);
+  return result;
+}
+
+/* Allocate memory from the heap.  */
+__ptr_t
+malloc (size)
+     size_t size;
+{
+  __ptr_t result;
+  size_t block, blocks, lastblocks, start;
+  register size_t i;
+  struct list *next;
+
+  /* ANSI C allows `malloc (0)' to either return NULL, or to return a
+     valid address you can realloc and free (though not dereference).
+
+     It turns out that some extant code (sunrpc, at least Ultrix's version)
+     expects `malloc (0)' to return non-NULL and breaks otherwise.
+     Be compatible.  */
+
+#if	0
+  if (size == 0)
+    return NULL;
+#endif
+
+  if (__malloc_hook != NULL)
+    return (*__malloc_hook) (size);
+
+  if (!__malloc_initialized)
+    if (!initialize ())
+      return NULL;
+
+  if (size < sizeof (struct list))
+      size = sizeof (struct list);
+
+#ifdef SUNOS_LOCALTIME_BUG
+  if (size < 16)
+    size = 16;
+#endif
+
+  /* Determine the allocation policy based on the request size.  */
+  if (size <= BLOCKSIZE / 2)
+    {
+      /* Small allocation to receive a fragment of a block.
+	 Determine the logarithm to base two of the fragment size. */
+      register size_t log = 1;
+      --size;
+      while ((size /= 2) != 0)
+	++log;
+
+      /* Look in the fragment lists for a
+	 free fragment of the desired size. */
+      next = _fraghead[log].next;
+      if (next != NULL)
+	{
+	  /* There are free fragments of this size.
+	     Pop a fragment out of the fragment list and return it.
+	     Update the block's nfree and first counters. */
+	  result = (__ptr_t) next;
+	  next->prev->next = next->next;
+	  if (next->next != NULL)
+	    next->next->prev = next->prev;
+	  block = BLOCK (result);
+	  if (--_heapinfo[block].busy.info.frag.nfree != 0)
+	    _heapinfo[block].busy.info.frag.first = (unsigned long int)
+	      ((unsigned long int) ((char *) next->next - (char *) NULL)
+	       % BLOCKSIZE) >> log;
+
+	  /* Update the statistics.  */
+	  ++_chunks_used;
+	  _bytes_used += 1 << log;
+	  --_chunks_free;
+	  _bytes_free -= 1 << log;
+	}
+      else
+	{
+	  /* No free fragments of the desired size, so get a new block
+	     and break it into fragments, returning the first.  */
+	  result = malloc (BLOCKSIZE);
+	  if (result == NULL)
+	    return NULL;
+
+	  /* Link all fragments but the first into the free list.  */
+	  for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
+	    {
+	      next = (struct list *) ((char *) result + (i << log));
+	      next->next = _fraghead[log].next;
+	      next->prev = &_fraghead[log];
+	      next->prev->next = next;
+	      if (next->next != NULL)
+		next->next->prev = next;
+	    }
+
+	  /* Initialize the nfree and first counters for this block.  */
+	  block = BLOCK (result);
+	  _heapinfo[block].busy.type = log;
+	  _heapinfo[block].busy.info.frag.nfree = i - 1;
+	  _heapinfo[block].busy.info.frag.first = i - 1;
+
+	  _chunks_free += (BLOCKSIZE >> log) - 1;
+	  _bytes_free += BLOCKSIZE - (1 << log);
+	  _bytes_used -= BLOCKSIZE - (1 << log);
+	}
+    }
+  else
+    {
+      /* Large allocation to receive one or more blocks.
+	 Search the free list in a circle starting at the last place visited.
+	 If we loop completely around without finding a large enough
+	 space we will have to get more memory from the system.  */
+      blocks = BLOCKIFY (size);
+      start = block = _heapindex;
+      while (_heapinfo[block].free.size < blocks)
+	{
+	  block = _heapinfo[block].free.next;
+	  if (block == start)
+	    {
+	      /* Need to get more from the system.  Check to see if
+		 the new core will be contiguous with the final free
+		 block; if so we don't need to get as much.  */
+	      block = _heapinfo[0].free.prev;
+	      lastblocks = _heapinfo[block].free.size;
+	      if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
+		  (*__morecore) (0) == ADDRESS (block + lastblocks) &&
+		  (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL)
+		{
+ 		  /* Which block we are extending (the `final free
+ 		     block' referred to above) might have changed, if
+ 		     it got combined with a freed info table.  */
+ 		  block = _heapinfo[0].free.prev;
+  		  _heapinfo[block].free.size += (blocks - lastblocks);
+		  _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
+		  continue;
+		}
+	      result = morecore (blocks * BLOCKSIZE);
+	      if (result == NULL)
+		return NULL;
+	      block = BLOCK (result);
+	      _heapinfo[block].busy.type = 0;
+	      _heapinfo[block].busy.info.size = blocks;
+	      ++_chunks_used;
+	      _bytes_used += blocks * BLOCKSIZE;
+	      return result;
+	    }
+	}
+
+      /* At this point we have found a suitable free list entry.
+	 Figure out how to remove what we need from the list. */
+      result = ADDRESS (block);
+      if (_heapinfo[block].free.size > blocks)
+	{
+	  /* The block we found has a bit left over,
+	     so relink the tail end back into the free list. */
+	  _heapinfo[block + blocks].free.size
+	    = _heapinfo[block].free.size - blocks;
+	  _heapinfo[block + blocks].free.next
+	    = _heapinfo[block].free.next;
+	  _heapinfo[block + blocks].free.prev
+	    = _heapinfo[block].free.prev;
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapindex = block + blocks;
+	}
+      else
+	{
+	  /* The block exactly matches our requirements,
+	     so just remove it from the list. */
+	  _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapinfo[block].free.prev;
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapindex = _heapinfo[block].free.next;
+	  --_chunks_free;
+	}
+
+      _heapinfo[block].busy.type = 0;
+      _heapinfo[block].busy.info.size = blocks;
+      ++_chunks_used;
+      _bytes_used += blocks * BLOCKSIZE;
+      _bytes_free -= blocks * BLOCKSIZE;
+    }
+
+  return result;
+}
+
+
+#ifndef _LIBC
+
+/* On some ANSI C systems, some libc functions call _malloc, _free
+   and _realloc.  Make them use the GNU functions.  */
+
+__ptr_t
+_malloc (size)
+     size_t size;
+{
+  return malloc (size);
+}
+
+void
+_free (ptr)
+     __ptr_t ptr;
+{
+  free (ptr);
+}
+
+__ptr_t
+_realloc (ptr, size)
+     __ptr_t ptr;
+     size_t size;
+{
+  return realloc (ptr, size);
+}
+
+#endif
+/* Free a block of memory allocated by `malloc'.
+   Copyright 1990, 1991, 1992 Free Software Foundation
+		  Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* Debugging hook for free.  */
+void (*__free_hook) __P ((__ptr_t __ptr));
+
+/* List of blocks allocated by memalign.  */
+struct alignlist *_aligned_blocks = NULL;
+
+/* Return memory to the heap.
+   Like `free' but don't call a __free_hook if there is one.  */
+void
+_free_internal (ptr)
+     __ptr_t ptr;
+{
+  int type;
+  size_t block, blocks;
+  register size_t i;
+  struct list *prev, *next;
+
+  block = BLOCK (ptr);
+
+  type = _heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Get as many statistics as early as we can.  */
+      --_chunks_used;
+      _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
+      _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;
+
+      /* Find the free cluster previous to this one in the free list.
+	 Start searching at the last block referenced; this may benefit
+	 programs with locality of allocation.  */
+      i = _heapindex;
+      if (i > block)
+	while (i > block)
+	  i = _heapinfo[i].free.prev;
+      else
+	{
+	  do
+	    i = _heapinfo[i].free.next;
+	  while (i > 0 && i < block);
+	  i = _heapinfo[i].free.prev;
+	}
+
+      /* Determine how to link this block into the free list.  */
+      if (block == i + _heapinfo[i].free.size)
+	{
+	  /* Coalesce this block with its predecessor.  */
+	  _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
+	  block = i;
+	}
+      else
+	{
+	  /* Really link this block back into the free list.  */
+	  _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
+	  _heapinfo[block].free.next = _heapinfo[i].free.next;
+	  _heapinfo[block].free.prev = i;
+	  _heapinfo[i].free.next = block;
+	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
+	  ++_chunks_free;
+	}
+
+      /* Now that the block is linked in, see if we can coalesce it
+	 with its successor (by deleting its successor from the list
+	 and adding in its size).  */
+      if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
+	{
+	  _heapinfo[block].free.size
+	    += _heapinfo[_heapinfo[block].free.next].free.size;
+	  _heapinfo[block].free.next
+	    = _heapinfo[_heapinfo[block].free.next].free.next;
+	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
+	  --_chunks_free;
+	}
+
+      /* Now see if we can return stuff to the system.  */
+      blocks = _heapinfo[block].free.size;
+      if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
+	  && (*__morecore) (0) == ADDRESS (block + blocks))
+	{
+	  register size_t bytes = blocks * BLOCKSIZE;
+	  _heaplimit -= blocks;
+	  (*__morecore) (-bytes);
+	  _heapinfo[_heapinfo[block].free.prev].free.next
+	    = _heapinfo[block].free.next;
+	  _heapinfo[_heapinfo[block].free.next].free.prev
+	    = _heapinfo[block].free.prev;
+	  block = _heapinfo[block].free.prev;
+	  --_chunks_free;
+	  _bytes_free -= bytes;
+	}
+
+      /* Set the next search to begin at this block.  */
+      _heapindex = block;
+      break;
+
+    default:
+      /* Do some of the statistics.  */
+      --_chunks_used;
+      _bytes_used -= 1 << type;
+      ++_chunks_free;
+      _bytes_free += 1 << type;
+
+      /* Get the address of the first free fragment in this block.  */
+      prev = (struct list *) ((char *) ADDRESS (block) +
+			   (_heapinfo[block].busy.info.frag.first << type));
+
+      if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
+	{
+	  /* If all fragments of this block are free, remove them
+	     from the fragment list and free the whole block.  */
+	  next = prev;
+	  for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
+	    next = next->next;
+	  prev->prev->next = next;
+	  if (next != NULL)
+	    next->prev = prev->prev;
+	  _heapinfo[block].busy.type = 0;
+	  _heapinfo[block].busy.info.size = 1;
+
+	  /* Keep the statistics accurate.  */
+	  ++_chunks_used;
+	  _bytes_used += BLOCKSIZE;
+	  _chunks_free -= BLOCKSIZE >> type;
+	  _bytes_free -= BLOCKSIZE;
+
+	  free (ADDRESS (block));
+	}
+      else if (_heapinfo[block].busy.info.frag.nfree != 0)
+	{
+	  /* If some fragments of this block are free, link this
+	     fragment into the fragment list after the first free
+	     fragment of this block. */
+	  next = (struct list *) ptr;
+	  next->next = prev->next;
+	  next->prev = prev;
+	  prev->next = next;
+	  if (next->next != NULL)
+	    next->next->prev = next;
+	  ++_heapinfo[block].busy.info.frag.nfree;
+	}
+      else
+	{
+	  /* No fragments of this block are free, so link this
+	     fragment into the fragment list and announce that
+	     it is the first free fragment of this block. */
+	  prev = (struct list *) ptr;
+	  _heapinfo[block].busy.info.frag.nfree = 1;
+	  _heapinfo[block].busy.info.frag.first = (unsigned long int)
+	    ((unsigned long int) ((char *) ptr - (char *) NULL)
+	     % BLOCKSIZE >> type);
+	  prev->next = _fraghead[type].next;
+	  prev->prev = &_fraghead[type];
+	  prev->prev->next = prev;
+	  if (prev->next != NULL)
+	    prev->next->prev = prev;
+	}
+      break;
+    }
+}
+
+/* Return memory to the heap.  */
+void
+free (ptr)
+     __ptr_t ptr;
+{
+  register struct alignlist *l;
+
+  if (ptr == NULL)
+    return;
+
+  for (l = _aligned_blocks; l != NULL; l = l->next)
+    if (l->aligned == ptr)
+      {
+	l->aligned = NULL;	/* Mark the slot in the list as free.  */
+	ptr = l->exact;
+	break;
+      }
+
+  if (__free_hook != NULL)
+    (*__free_hook) (ptr);
+  else
+    _free_internal (ptr);
+}
+/* Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#ifdef _LIBC
+
+#include <ansidecl.h>
+#include <gnu-stabs.h>
+
+#undef	cfree
+
+function_alias(cfree, free, void, (ptr),
+	       DEFUN(cfree, (ptr), PTR ptr))
+
+#else
+
+void
+cfree (ptr)
+     __ptr_t ptr;
+{
+  free (ptr);
+}
+
+#endif
+/* Change the size of a block allocated by `malloc'.
+   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+		     Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#if  (defined (MEMMOVE_MISSING) || \
+      !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG))
+
+/* Snarfed directly from Emacs src/dispnew.c:
+   XXX Should use system bcopy if it handles overlap.  */
+#ifndef emacs
+
+/* Like bcopy except never gets confused by overlap.  */
+
+static void
+safe_bcopy (from, to, size)
+     char *from, *to;
+     int size;
+{
+  if (size <= 0 || from == to)
+    return;
+
+  /* If the source and destination don't overlap, then bcopy can
+     handle it.  If they do overlap, but the destination is lower in
+     memory than the source, we'll assume bcopy can handle that.  */
+  if (to < from || from + size <= to)
+    bcopy (from, to, size);
+
+  /* Otherwise, we'll copy from the end.  */
+  else
+    {
+      register char *endf = from + size;
+      register char *endt = to + size;
+
+      /* If TO - FROM is large, then we should break the copy into
+	 nonoverlapping chunks of TO - FROM bytes each.  However, if
+	 TO - FROM is small, then the bcopy function call overhead
+	 makes this not worth it.  The crossover point could be about
+	 anywhere.  Since I don't think the obvious copy loop is too
+	 bad, I'm trying to err in its favor.  */
+      if (to - from < 64)
+	{
+	  do
+	    *--endt = *--endf;
+	  while (endf != from);
+	}
+      else
+	{
+	  for (;;)
+	    {
+	      endt -= (to - from);
+	      endf -= (to - from);
+
+	      if (endt < to)
+		break;
+
+	      bcopy (endf, endt, to - from);
+	    }
+
+	  /* If SIZE wasn't a multiple of TO - FROM, there will be a
+	     little left over.  The amount left over is
+	     (endt + (to - from)) - to, which is endt - from.  */
+	  bcopy (from, to, endt - from);
+	}
+    }
+}     
+#endif	/* Not emacs.  */
+
+#define memmove(to, from, size) safe_bcopy ((from), (to), (size))
+
+#endif
+
+
+#define min(A, B) ((A) < (B) ? (A) : (B))
+
+/* Debugging hook for realloc.  */
+__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
+
+/* Resize the given region to the new size, returning a pointer
+   to the (possibly moved) region.  This is optimized for speed;
+   some benchmarks seem to indicate that greater compactness is
+   achieved by unconditionally allocating and copying to a
+   new region.  This module has incestuous knowledge of the
+   internals of both free and malloc. */
+__ptr_t
+realloc (ptr, size)
+     __ptr_t ptr;
+     size_t size;
+{
+  __ptr_t result;
+  int type;
+  size_t block, blocks, oldlimit;
+
+  if (size == 0)
+    {
+      free (ptr);
+      return malloc (0);
+    }
+  else if (ptr == NULL)
+    return malloc (size);
+
+  if (__realloc_hook != NULL)
+    return (*__realloc_hook) (ptr, size);
+
+  block = BLOCK (ptr);
+
+  type = _heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Maybe reallocate a large block to a small fragment.  */
+      if (size <= BLOCKSIZE / 2)
+	{
+	  result = malloc (size);
+	  if (result != NULL)
+	    {
+	      memcpy (result, ptr, size);
+	      _free_internal (ptr);
+	      return result;
+	    }
+	}
+
+      /* The new size is a large allocation as well;
+	 see if we can hold it in place. */
+      blocks = BLOCKIFY (size);
+      if (blocks < _heapinfo[block].busy.info.size)
+	{
+	  /* The new size is smaller; return
+	     excess memory to the free list. */
+	  _heapinfo[block + blocks].busy.type = 0;
+	  _heapinfo[block + blocks].busy.info.size
+	    = _heapinfo[block].busy.info.size - blocks;
+	  _heapinfo[block].busy.info.size = blocks;
+	  /* We have just created a new chunk by splitting a chunk in two.
+	     Now we will free this chunk; increment the statistics counter
+	     so it doesn't become wrong when _free_internal decrements it.  */
+	  ++_chunks_used;
+	  _free_internal (ADDRESS (block + blocks));
+	  result = ptr;
+	}
+      else if (blocks == _heapinfo[block].busy.info.size)
+	/* No size change necessary.  */
+	result = ptr;
+      else
+	{
+	  /* Won't fit, so allocate a new region that will.
+	     Free the old region first in case there is sufficient
+	     adjacent free space to grow without moving. */
+	  blocks = _heapinfo[block].busy.info.size;
+	  /* Prevent free from actually returning memory to the system.  */
+	  oldlimit = _heaplimit;
+	  _heaplimit = 0;
+	  _free_internal (ptr);
+	  _heaplimit = oldlimit;
+	  result = malloc (size);
+	  if (result == NULL)
+	    {
+	      /* Now we're really in trouble.  We have to unfree
+		 the thing we just freed.  Unfortunately it might
+		 have been coalesced with its neighbors.  */
+	      if (_heapindex == block)
+	        (void) malloc (blocks * BLOCKSIZE);
+	      else
+		{
+		  __ptr_t previous = malloc ((block - _heapindex) * BLOCKSIZE);
+		  (void) malloc (blocks * BLOCKSIZE);
+		  _free_internal (previous);
+		}
+	      return NULL;
+	    }
+	  if (ptr != result)
+	    memmove (result, ptr, blocks * BLOCKSIZE);
+	}
+      break;
+
+    default:
+      /* Old size is a fragment; type is logarithm
+	 to base two of the fragment size.  */
+      if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type))
+	/* The new size is the same kind of fragment.  */
+	result = ptr;
+      else
+	{
+	  /* The new size is different; allocate a new space,
+	     and copy the lesser of the new size and the old. */
+	  result = malloc (size);
+	  if (result == NULL)
+	    return NULL;
+	  memcpy (result, ptr, min (size, (size_t) 1 << type));
+	  free (ptr);
+	}
+      break;
+    }
+
+  return result;
+}
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+/* Allocate an array of NMEMB elements each SIZE bytes long.
+   The entire array is initialized to zeros.  */
+__ptr_t
+calloc (nmemb, size)
+     register size_t nmemb;
+     register size_t size;
+{
+  register __ptr_t result = malloc (nmemb * size);
+
+  if (result != NULL)
+    (void) memset (result, 0, nmemb * size);
+
+  return result;
+}
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU C Library; see the file COPYING.  If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define	_MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+#ifndef	__GNU_LIBRARY__
+#define	__sbrk	sbrk
+#endif
+
+#ifdef __GNU_LIBRARY__
+/* It is best not to declare this and cast its result on foreign operating
+   systems with potentially hostile include files.  */
+extern __ptr_t __sbrk __P ((int increment));
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Allocate INCREMENT more bytes of data space,
+   and return the start of data space, or NULL on errors.
+   If INCREMENT is negative, shrink data space.  */
+__ptr_t
+__default_morecore (increment)
+     ptrdiff_t increment;
+{
+  __ptr_t result = (__ptr_t) __sbrk ((int) increment);
+  if (result == (__ptr_t) -1)
+    return NULL;
+  return result;
+}
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef	_MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#endif
+
+__ptr_t
+memalign (alignment, size)
+     size_t alignment;
+     size_t size;
+{
+  __ptr_t result;
+  unsigned long int adj;
+
+  size = ((size + alignment - 1) / alignment) * alignment;
+
+  result = malloc (size);
+  if (result == NULL)
+    return NULL;
+  adj = (unsigned long int) ((unsigned long int) ((char *) result -
+						  (char *) NULL)) % alignment;
+  if (adj != 0)
+    {
+      struct alignlist *l;
+      for (l = _aligned_blocks; l != NULL; l = l->next)
+	if (l->aligned == NULL)
+	  /* This slot is free.  Use it.  */
+	  break;
+      if (l == NULL)
+	{
+	  l = (struct alignlist *) malloc (sizeof (struct alignlist));
+	  if (l == NULL)
+	    {
+	      free (result);
+	      return NULL;
+	    }
+	  l->next = _aligned_blocks;
+	  _aligned_blocks = l;
+	}
+      l->exact = result;
+      result = l->aligned = (char *) result + alignment - adj;
+    }
+
+  return result;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/huffman.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/huffman.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/huffman.cpp	(revision 10506)
@@ -0,0 +1,385 @@
+/**************************************************************************
+ *
+ * huffman.c -- Huffman coding functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "huffman.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+/* ->data on success,  
+   NULL on error 
+ */
+huff_data *
+Generate_Huffman_Data (int num, long *freqs, huff_data * data,
+		       u_long * mem)
+{
+  int HNum, i, count;
+  unsigned long *heap;
+  huff_data *hd = data;
+  if (!hd)
+    {
+      if (!(hd = new huff_data))
+	goto error0;
+    }
+  if (!(heap = new unsigned long[num * 2]))
+    goto error1;
+  if (!(hd->clens = new char[num]))
+      goto error2;
+  hd->num_codes = num;
+  if (mem)
+    {
+      if (hd != data)
+	*mem += sizeof (huff_data);
+      *mem += num * sizeof (char);
+    }
+  memcpy (&heap[num], freqs, num * sizeof (*heap));
+  memset (heap, '\0', num * sizeof (*heap));
+
+  /* Initialise the pointers to the leaves */
+  for (count = i = 0; i < num; ++i)
+    if (heap[num + i])
+      heap[count++] = num + i;
+
+  /* Reorganise the pointers so that it is a heap */
+  HNum = count;
+  for (i = HNum / 2; i > 0; --i)
+    {
+      register int curr, child;
+      curr = i;
+      child = curr * 2;
+      while (child <= HNum)
+	{
+	  if (child < HNum && heap[heap[child]] < heap[heap[child - 1]])
+	    ++child;
+	  if (heap[heap[curr - 1]] > heap[heap[child - 1]])
+	    {
+	      register u_long temp;
+	      temp = heap[child - 1];
+	      heap[child - 1] = heap[curr - 1];
+	      heap[curr - 1] = temp;
+	      curr = child;
+	      child = 2 * curr;
+	    }
+	  else
+	    break;
+	}
+    }
+
+
+  /* Form the huffman tree */
+  while (HNum > 1)
+    {
+      int pos[2];
+
+      for (i = 0; i < 2; ++i)
+	{
+	  register int curr, child;
+	  pos[i] = heap[0];
+	  heap[0] = heap[--HNum];
+	  curr = 1;
+	  child = 2;
+	  while (child <= HNum)
+	    {
+	      if (child < HNum &&
+		  heap[heap[child]] < heap[heap[child - 1]])
+		++child;
+	      if (heap[heap[curr - 1]] > heap[heap[child - 1]])
+		{
+		  register int temp;
+		  temp = heap[child - 1];
+		  heap[child - 1] = heap[curr - 1];
+		  heap[curr - 1] = temp;
+		  curr = child;
+		  child = 2 * curr;
+		}
+	      else
+		break;
+	    }
+	}
+
+      heap[HNum + 1] = heap[pos[0]] + heap[pos[1]];
+      heap[pos[0]] = heap[pos[1]] = HNum + 1;
+
+      heap[HNum] = HNum + 1;
+
+      {
+	register int parent, curr;
+	++HNum;
+	curr = HNum;
+	parent = curr >> 1;
+	while (parent && heap[heap[parent - 1]] > heap[heap[curr - 1]])
+	  {
+	    register int temp;
+	    temp = heap[parent - 1];
+	    heap[parent - 1] = heap[curr - 1];
+	    heap[curr - 1] = temp;
+	    curr = parent;
+	    parent = curr >> 1;
+	  }
+      }
+    }
+
+
+  /* Calculate the code lens */
+  heap[0] = -1UL;
+  heap[1] = 0;
+  for (i = 2; i < num * 2; ++i)
+    heap[i] = heap[heap[i]] + 1;
+
+  /* zero the lencount's array */
+  memset (hd->lencount, '\0', sizeof (hd->lencount));
+  hd->maxcodelen = 0;
+  hd->mincodelen = 100;
+
+  /* Set the code length of each leaf in the huffman tree */
+  for (i = 0; i < num; ++i)
+    {
+      register u_long codelen = heap[i + num];
+      hd->clens[i] = (char) codelen;
+      if (!codelen)
+	continue;
+      if (codelen > hd->maxcodelen)
+	hd->maxcodelen = codelen;
+      if (codelen < hd->mincodelen)
+	hd->mincodelen = codelen;
+      ++hd->lencount[codelen];
+    }
+
+
+  if (hd->maxcodelen == 0 && hd->mincodelen == 100)
+    {
+      hd->num_codes = 0;
+    }
+  else
+    {
+      /* Calculate the current codes for each different code length */
+      hd->min_code[hd->maxcodelen] = 0;
+      for (i = hd->maxcodelen - 1; i>=0; --i)
+	hd->min_code[i] = (hd->min_code[i + 1] + hd->lencount[i + 1]) >> 1;
+    }
+  delete []heap;
+  return (hd);
+
+error2:
+  delete []heap;
+error1:
+  if (!data)
+    delete hd;
+error0:
+  return (NULL);
+
+}
+
+unsigned long *
+Generate_Huffman_Codes (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *codes;
+  unsigned long mc[MAX_HUFFCODE_LEN + 1];
+
+  if (!data)
+    return (NULL);
+  if (!(codes = new unsigned long[data->num_codes]))
+    return (NULL);
+  if (mem)
+    *mem += data->num_codes * sizeof (*codes);
+  memcpy (mc, data->min_code, sizeof (mc));
+  for (i = 0; i < data->num_codes; ++i)
+    if (data->clens[i])
+      codes[i] = mc[(int) (data->clens[i])]++;
+
+  return (codes);
+}
+
+
+unsigned long **
+Generate_Huffman_Vals (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *fcode[MAX_HUFFCODE_LEN + 1];
+  unsigned long **values;
+  unsigned long *vals;
+
+  if (!data)
+    return (NULL);
+  if (!(vals = new unsigned long[data->num_codes]))
+    return (NULL);
+  if (!(values = new unsigned long *[MAX_HUFFCODE_LEN + 1]))
+    {
+      delete []vals;
+      return (NULL);
+    }
+
+  memset (values, '\0', (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *));
+
+  if (mem)
+    *mem += data->num_codes * sizeof (*vals) +
+      (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+  fcode[0] = values[0] = &vals[0];
+  for (i = 1; i <= data->maxcodelen; ++i)
+    fcode[i] = values[i] = &vals[(values[i - 1] - vals) + data->lencount[i - 1]];
+
+  for (i = 0; i < data->num_codes; ++i)
+    if (data->clens[i])
+      *fcode[(int) (data->clens[i])]++ = i;
+  return (values);
+}
+
+
+
+double 
+Calculate_Huffman_Size (int num, long *freqs, long *counts)
+{
+  double size = 0;
+  huff_data hd;
+  int i;
+  if (!Generate_Huffman_Data (num, freqs, &hd, NULL))
+    return -1;
+  for (i = 0; i < num; ++i)
+    size += counts[i] * hd.clens[i];
+  delete []hd.clens;
+  return size;
+}
+
+
+
+int 
+Write_Huffman_Data (FILE * f, huff_data * hd)
+{
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONSI(hd->num_codes);
+  HTONSI(hd->mincodelen);
+  HTONSI(hd->maxcodelen);
+
+  if (fwrite (&hd->num_codes, sizeof (hd->num_codes), 1, f) != 1)
+    return -1;
+
+  if (fwrite (&hd->mincodelen, sizeof (hd->mincodelen), 1, f) != 1)
+    return -1;
+
+  if (fwrite (&hd->maxcodelen, sizeof (hd->maxcodelen), 1, f) != 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(hd->num_codes);
+  NTOHSI(hd->mincodelen);
+  NTOHSI(hd->maxcodelen);
+
+  if (hd->num_codes)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int i;
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; ++i)
+	HTONSI(hd->lencount[i]);
+      for (i = 0; i < hd->maxcodelen + 1; ++i)
+	HTONUL(hd->min_code[i]);
+
+      if (fwrite (hd->lencount + hd->mincodelen, sizeof (*hd->lencount),
+		  hd->maxcodelen - hd->mincodelen + 1, f) !=
+	  hd->maxcodelen - hd->mincodelen + 1)
+	return -1;
+
+      if (fwrite (hd->min_code, sizeof (*hd->min_code), hd->maxcodelen + 1, f) !=
+	  hd->maxcodelen + 1)
+	return -1;
+
+      if (fwrite (hd->clens, sizeof (*hd->clens), hd->num_codes, f) != hd->num_codes)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; ++i)
+	NTOHSI(hd->lencount[i]);
+      for (i = 0; i < hd->maxcodelen + 1; ++i)
+	NTOHUL(hd->min_code[i]);
+    }
+  return 0;
+}
+
+
+
+int Read_Huffman_Data (FILE * f, huff_data * hd, u_long * mem, u_long * disk) {
+  if (fread (&hd->num_codes, sizeof (hd->num_codes), 1, f) != 1)
+    return -1;
+
+  if (fread (&hd->mincodelen, sizeof (hd->mincodelen), 1, f) != 1)
+    return -1;
+
+  if (fread (&hd->maxcodelen, sizeof (hd->maxcodelen), 1, f) != 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(hd->num_codes);
+  NTOHSI(hd->mincodelen);
+  NTOHSI(hd->maxcodelen);
+
+  if (disk)
+    (*disk) += sizeof (hd->num_codes) + sizeof (hd->mincodelen) +
+      sizeof (hd->maxcodelen);
+
+  hd->clens = NULL;
+
+  if (hd->num_codes)
+    {
+      int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+      memset (hd->lencount, '\0', sizeof (hd->lencount));
+      if (fread (hd->lencount + hd->mincodelen, sizeof (*hd->lencount),
+	      hd->maxcodelen - hd->mincodelen + 1, f) !=
+	  hd->maxcodelen - hd->mincodelen + 1)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = hd->mincodelen; i < hd->maxcodelen + 1; ++i)
+	NTOHSI(hd->lencount[i]);
+
+      if (disk)
+	(*disk) += sizeof (*hd->lencount) * (hd->maxcodelen - hd->mincodelen + 1);
+
+      memset (hd->min_code, '\0', sizeof (hd->min_code));
+
+      if (fread (hd->min_code, sizeof (*hd->min_code), hd->maxcodelen + 1, f) !=
+	  hd->maxcodelen + 1)
+	return -1;
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (i = 0; i < hd->maxcodelen + 1; ++i)
+	NTOHUL(hd->min_code[i]);
+
+      if (disk)
+	(*disk) += sizeof (*hd->min_code) * (hd->maxcodelen + 1);
+
+      if (!(hd->clens = new char[hd->num_codes]))
+	return -1;
+
+
+      if (fread (hd->clens, sizeof (*hd->clens), hd->num_codes, f) != hd->num_codes)
+	return -1;
+
+      if (disk)
+	(*disk) += sizeof (*hd->clens) * hd->num_codes;
+    }
+
+  if (mem)
+    *mem += sizeof (*hd->clens) * hd->num_codes;
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/huffman.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/huffman.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/huffman.h	(revision 10506)
@@ -0,0 +1,57 @@
+/**************************************************************************
+ *
+ * huffman.h -- Huffman coding functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef H_HUFFMAN
+#define H_HUFFMAN
+
+#include "sysfuncs.h"
+#include "bitio_m_abstract.h"
+
+#define MAX_HUFFCODE_LEN 31
+
+struct huff_data {
+  int num_codes;
+  int mincodelen;
+  int maxcodelen;
+  int lencount[MAX_HUFFCODE_LEN + 1];
+  unsigned long min_code[MAX_HUFFCODE_LEN + 1];
+  char *clens;
+};
+
+
+huff_data *Generate_Huffman_Data (int num, long *freqs, huff_data * data,
+				  u_long * mem);
+
+unsigned long *Generate_Huffman_Codes (huff_data * data, u_long * mem);
+
+unsigned long **Generate_Huffman_Vals (huff_data * data, u_long * mem);
+
+int Write_Huffman_Data (FILE * f, huff_data * hd);
+
+int Read_Huffman_Data (FILE * f, huff_data * hd, u_long * mem, u_long * disk);
+
+/* Calculate the number of bits required to code the data with the
+   specified frequencies. Normally freqs and counts should point to
+   the same array. */
+double Calculate_Huffman_Size (int num, long *freqs, long *counts);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/local_strings.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/local_strings.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/local_strings.cpp	(revision 10506)
@@ -0,0 +1,411 @@
+/**************************************************************************
+ *
+ * local_strings -- provides some extra string routines
+ * Copyright (C) 1994  Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "local_strings.h"
+#include "memlib.h"
+
+/* =========================================================================
+ * Function: arg_atoi
+ * Description: 
+ *      Converts an ascii string to an integer
+ *      but allows a scale string immediately following.
+ *      i.e. "10Mb" or "20Kb" or "40Megabytes"
+ *      There must be no gap between the last digit and the scale.
+ *      Only the fist letter is significant.
+ *      K = Kilo
+ *      M = Mega
+ *      G = Giga
+ * Input: 
+ *      string of form: xxxxxxK or xxxxxxxM or xxxxxxxG
+ *      where x is a digit
+ * Output: 
+ *      a scaled integer
+ * ========================================================================= */
+
+#define KILO 	1024
+#define MEGA	1024*1024
+#define GIGA	1024*1024*1024
+
+int 
+arg_atoi (char *str)
+{
+  char *str_ptr = str;
+  char ch = '\0';
+  long scale = 1;
+
+  /* find any scale letter immediately after digits */
+  ch = *str_ptr;
+  while (!isalpha (ch) && (ch != '\0'))
+    ch = *str_ptr++;
+
+  /* replace scale letter by end-of-string character */
+  *str_ptr = '\0';
+
+  /* set scale appropriately */
+  switch (ch)
+    {
+    case 'K':
+      scale = KILO;
+      break;
+    case 'M':
+      scale = MEGA;
+      break;
+    case 'G':
+      scale = GIGA;
+      break;
+    default:
+      scale = 1;
+      break;
+    }
+
+  return (atoi (str) * scale);
+
+}
+
+/* ===============================================================================
+ * Function: compare
+ * Description: Compare two strings. 
+ * Input: Two binary strings, first byte of string indicates length. 
+ * Output: Like standard strcmp.
+ *      = 0 if s1 = s2
+ *      < 0 if s1 < s2
+ *      > 0 if s1 > s2
+ * =============================================================================== */
+int 
+compare (u_char * s1, u_char * s2)
+{
+  int l1 = *s1, l2 = *s2;
+  int l = (l1 < l2) ? l1 : l2;
+
+  while (l--)
+    if (*++s1 != *++s2)
+      return (*s1 - *s2);
+  return (l1 - l2);
+
+}
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char casecharmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+/* ===============================================================================
+ * Function: casecompare   [RPAP - Jan 97: Stem Index Change]
+ * Description: Compare two strings in dictionary order
+ * Input: Two binary strings, first byte of string indicates length. 
+ * Output:
+ *      = 0 if s1 = s2
+ *      < 0 if s1 < s2
+ *      > 0 if s1 > s2
+ * =============================================================================== */
+int 
+casecompare (u_char * s1, u_char * s2)
+{
+  int l1 = *s1, l2 = *s2;
+  int l = (l1 < l2) ? l1 : l2;
+  int pos = 0;
+  register int diff = 0;
+
+  while (l--)
+    if ((diff = casecharmap[*++s1] - casecharmap[*++s2]) != 0)
+      return (diff);
+    else if ((diff = *s1 - *s2) != 0)
+      if (!pos)
+	pos = diff;
+
+  return ((l1 - l2) ? (l1 - l2) : (pos));
+
+}
+
+/* =========================================================================
+ * Function: copy_string
+ * Description: 
+ *      Copies a string with the len in 1st byte
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+u_char *
+copy_string (u_char * src_str)
+{
+  u_char *copy = new u_char(src_str[0] + 1);
+
+  if (!copy)
+    return NULL;
+
+  memcpy (copy, src_str, src_str[0] + 1);
+  return copy;
+
+}
+
+
+/* ===============================================================================
+ * Function: prefixlen
+ * Description: Returns length of common prefix string between s1 and s2.
+ * Input: two binary strings
+ * Output: prefix length
+ * =============================================================================== */
+int 
+prefixlen (u_char * s1, u_char * s2)
+{
+  int l = (*s1 < *s2) ? *s1 : *s2;
+  int i = 0;
+
+  while (i < l && *++s1 == *++s2)
+    ++i;
+  return (i);
+}
+
+
+/* ===============================================================================
+ * Function: char2str
+ * Description: 
+ *      Ensures that non-printable characters are converted to a string
+ *      which is printable i.e. it indentifies the character.
+ *      e.g. carriage-return = "\n".
+ * Input: character (may be non-printable)
+ * Output: pointer to static string
+ * =============================================================================== */
+
+char *
+char2str (u_char c)
+{
+  static char buf[10];
+  switch (c)
+    {
+    case '\n':
+      sprintf (buf, "\\n");
+      break;
+    case '\b':
+      sprintf (buf, "\\b");
+      break;
+    case '\f':
+      sprintf (buf, "\\f");
+      break;
+    case '\t':
+      sprintf (buf, "\\t");
+      break;
+    default:
+	if (c >= ' ' && c <= 126)
+	switch (c)
+	  {
+	  case '\\':
+	    sprintf (buf, "\\\\");
+	    break;
+	  case '\"':
+	    sprintf (buf, "\\\"");
+	    break;
+	  case '\'':
+	    sprintf (buf, "\\\'");
+	    break;
+	  default:
+	    buf[0] = c;
+	    buf[1] = '\0';
+	    break;
+	  }
+      else
+	sprintf (buf, "\\x%02x", c);
+      break;
+    }
+  return buf;
+}
+
+/* ===============================================================================
+ * Function: word2str
+ * Description: 
+ *      Converts a string with possible non-printable characters into a string
+ *      consisting entirely of printable characters.
+ * Input: string, length stored in first byte
+ * Output: pointer to static string
+ * =============================================================================== */
+
+char *
+word2str (u_char * s)
+{
+  static char buf[1024];
+  char *p = buf;
+  int i, len = (int) *s++;
+
+  memset (buf, '\0', sizeof(buf));
+  for (i = 0; i < len; ++i)
+    {
+      strcpy (p, char2str (s[i]));
+      p = strchr (p, '\0');
+    }
+  return buf;
+}
+
+
+/* =========================================================================
+ * Function: de_escape_string
+ * Description: 
+ *      Turn a string containing \ escapes into real characters
+ *      Note this destroys the string s in the process
+ * Input: string to de-escape 
+ * Output: the de-escaped string
+ * ========================================================================= */
+char *
+de_escape_string (char *s)
+{
+  char *org = s;
+  char *d = s;
+  while (*s)
+    {
+      if (*s == '\\')
+	{
+	  ++s;
+	  switch (*s++)
+	    {
+	    case '\0':
+	      *d++ = '\\';
+	      --s;
+	      break;
+	    case '\\':
+	      *d++ = '\\';
+	      break;
+	    case 'b':
+	      *d++ = '\b';
+	      break;
+	    case 'f':
+	      *d++ = '\f';
+	      break;
+	    case 'n':
+	      *d++ = '\n';
+	      break;
+	    case 'r':
+	      *d++ = '\r';
+	      break;
+	    case 't':
+	      *d++ = '\r';
+	      break;
+	    case '\"':
+	      *d++ = '\"';
+	      break;
+	    case '\'':
+	      *d++ = '\'';
+	      break;
+	    case 'x':
+	      {
+		int num = 0;
+		if (isxdigit (*s))
+		  {
+		    char ch = toupper (*s++);
+		    num = ch <= '9' ? ch - '0' : ch - 'A' + 10;
+		  }
+		if (isxdigit (*s))
+		  {
+		    char ch = toupper (*s++);
+		    num = (num << 4) + (ch <= '9' ? ch - '0' : ch - 'A' + 10);
+		  }
+		*d++ = num;
+		break;
+	      }
+	    case '0':
+	    case '1':
+	    case '2':
+	    case '3':
+	    case '4':
+	    case '5':
+	    case '6':
+	    case '7':
+	      {
+		int num = *(s - 1) - '0';
+		if (*s >= '0' && *s <= '7')
+		  num = (num << 3) + *s++ - '0';
+		if (*s >= '0' && *s <= '7')
+		  num = (num << 3) + *s++ - '0';
+		*d++ = num;
+		break;
+	      }
+	    }
+	}
+      else
+	*d++ = *s++;
+    }
+  *d = '\0';
+  return (org);
+}
+
+/* =========================================================================
+ * Function: str255_to_string 
+ * Description: 
+ * Input: 
+ * Output: 
+ * ========================================================================= */
+
+char *
+str255_to_string (u_char * str255, char *str)
+{
+  static char buf[256];
+  char *str_base = NULL;
+  int len = *str255++;
+  int i = 0;
+
+  /* if haven't been given a str to write to then use local buffer */
+  if (!str)
+    str = &(buf[0]);
+
+  str_base = str;
+  for (i = 0; i < len; ++i)
+    {
+      *str++ = *str255++;
+    }
+  *str = '\0';
+
+  return str_base;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/local_strings.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/local_strings.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/local_strings.h	(revision 10506)
@@ -0,0 +1,79 @@
+/**************************************************************************
+ *
+ * local_strings.h -- string routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef LOCAL_STRINGS_H
+#define LOCAL_STRINGS_H
+
+#include "sysfuncs.h"
+
+class mgString
+{
+  u_char *data;
+ public:
+  inline int length()
+    {
+      return data[0];
+    }
+  inline u_char *rawdata()
+    {
+      return data;
+    }
+  inline void read(u_char **base)
+    {
+      unsigned int copy, suff;
+      
+      copy  = **base;
+      *base = *base + 1;
+      suff  = **base;
+      *base = *base + 1;
+      memcpy( (data + copy + 1), *base, suff);
+      *data = copy + suff;
+      *base += suff;
+    }
+  inline void read(FILE *dict)
+    {
+      unsigned int copy, suff;
+      copy = fgetc(dict);
+      suff = fgetc(dict);
+      fread(data + copy + 1, sizeof(u_char), suff, dict);
+      *data = copy + suff;
+    }
+  inline static void readString(u_char **base, u_char *prev)
+    {
+      ((mgString *) &prev)->read(base);
+    }
+  inline static void readString(FILE *dict, u_char *prev)
+    { 
+      ((mgString *) &prev)->read(dict);
+    }
+};
+
+int arg_atoi (char *str);
+int compare (u_char * s1, u_char * s2);
+int casecompare (u_char * s1, u_char * s2);   /* [RPAP - Jan 97: Stem Index Change] */
+u_char *copy_string (u_char * src_str);
+char *str255_to_string (u_char * str255, char *str);
+int prefixlen (u_char * s1, u_char * s2);
+char *char2str (u_char c);
+char *word2str (u_char * s);
+char *de_escape_string (char *s);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/longlong.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/longlong.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/longlong.h	(revision 10506)
@@ -0,0 +1,85 @@
+/**************************************************************************
+ *
+ * longlong.h -- Use of GCC's long long integer types
+ * Copyright (C) 1999 Tim A.H. Bell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef H_LONGLONG
+#define H_LONGLONG
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__
+#  include <WIN32cfg.h>
+# else
+#  include <config.h>
+# endif
+#endif
+
+/*
+  Use GCC's "long long" integer types for certain variables, to avoid
+  overflowing 32 bit integers.
+
+  Other files affected:
+  
+    lib:
+        bitio_random.c
+        bitio_random.h
+	
+    src/text:
+        ivf.pass1.c
+        ivf.pass2.c
+        build.h
+        mg_passes.c
+        text.h
+    
+*/
+
+/*#define TESTING_OVERFLOW*/
+
+#ifdef TESTING_OVERFLOW
+
+/* Test the overflow detection by using tiny (16-bit) types */
+typedef unsigned short int mg_ullong;
+typedef short int mg_llong;
+
+#define ULL_FS "u"
+#define LL_FS "d"
+
+#elif defined __GNUC__ && ! defined DISABLE_LONG_LONG
+
+/* We're using GCC, so it's okay to use "long long" (64-bit) types */
+#define USE_LONG_LONG
+
+typedef unsigned long long int mg_ullong;
+typedef long long int mg_llong;
+
+#define ULL_FS "llu"
+#define LL_FS "lld"
+
+#else
+
+/* Not using GCC, so fall back on plain "long" (32-bit) types */
+typedef unsigned long int mg_ullong;
+typedef long int mg_llong;
+
+#define ULL_FS "lu"
+#define LL_FS "ld"
+
+#endif /* __GNUC__ */
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/lovinstem.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/lovinstem.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/lovinstem.cpp	(revision 10506)
@@ -0,0 +1,1172 @@
+/**************************************************************************
+ *
+ * lovinstem.c -- Stemming code
+ * Copyright (C) 1994  Linh Huynh (linh@kbs.citri.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+
+/*****************************************************************************
+ *
+ *   Transformational Rules used in Recoding Stem Terminations
+ *
+ *   Parameter in functions:
+ *       ch : the second last character of the old ending
+ *            (after removing one of double consonants) 
+ *
+ ****************************************************************************/
+
+
+/************ Conditional rules associated with transformations **************/
+
+/*static int aio ();
+static int s ();
+static int pt ();
+static int m ();
+static int n ();*/
+
+static int 
+aio (char ch)			/* Rule number 9     */
+{
+  return ((ch != 'a') && (ch != 'i') && (ch != 'o'));
+}
+
+static int 
+s (char ch)				/* Rule Number 24    */
+{
+  return (ch != 's');
+}
+
+static int 
+pt (char ch)				/* Rule number 28    */
+{
+  return ((ch != 'p') && (ch != 't'));
+}
+
+static int 
+m (char ch)				/* Rule number 30    */
+{
+  return (ch != 'm');
+}
+
+static int 
+n (char ch)				/* Rule number 32    */
+{
+  return (ch != 'n');
+}
+
+
+/**************************************************************************
+ *
+ *  Context-sensitive rules associated with certain endings.
+ *
+ *  The notations of the rules are the same as in Lovins' paper
+ *  except that rule A is replaced by a NULL in the data structure.
+ *
+ *  Function parameters:
+ *      - stem_length: possible stem length
+ *      - end        : pointer points to the end of the possible stem.
+ *
+ *************************************************************************/
+
+
+/********* Context-sensitive rule function declarations ******************/
+
+/*static int B ();
+static int C ();
+static int D ();
+static int E ();
+static int F ();
+static int G ();
+static int H ();
+static int I ();
+static int J ();
+static int K ();
+static int L ();
+static int M ();
+static int N ();
+static int O ();
+static int P ();
+static int Q ();
+static int R ();
+static int S ();
+static int T ();
+static int U ();
+static int V ();
+static int W ();
+static int X ();
+static int Y ();
+static int Z ();
+static int AA ();
+static int BB ();
+static int CC ();
+*/
+static int 
+B (int stem_length, char *end)
+{
+  return (stem_length >= 3);
+}
+
+static int 
+C (int stem_length, char *end)
+{
+  return (stem_length >= 4);
+}
+
+static int 
+D (int stem_length, char *end)
+{
+  return (stem_length >= 5);
+}
+
+static int 
+E (int stem_length, char *end)
+
+     
+{
+  return (*end != 'e');
+}
+
+static int 
+F (int stem_length, char *end)
+     
+     
+{
+  return ((stem_length >= 3) && (*end != 'e'));
+}
+
+static int 
+G (int stem_length, char *end)
+     
+     
+{
+  return ((stem_length >= 3) && (*end == 'f'));
+}
+
+static int 
+H (int stem_length, char *end)
+     
+     
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+  return ((p1 == 't') || ((p1 == 'l') && (p2 == 'l')));
+}
+
+static int 
+I (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'o') && (p1 != 'e'));
+}
+
+static int 
+J (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'a') && (p1 != 'e'));
+}
+
+static int 
+K (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((stem_length >= 3) &&
+	  ((p1 == 'l') || (p1 == 'i') ||
+	   ((p1 == 'e') && (*(end - 2) == 'u'))));
+}
+
+static int 
+L (int stem_length, char *end)
+     
+     
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+  if (p1 == 's')
+    return (p2 == 'o');
+  else
+    return ((p1 != 'u') && (p1 != 'x'));
+}
+
+static int 
+M (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((p1 != 'a') && (p1 != 'c') &&
+	  (p1 != 'e') && (p1 != 'm'));
+}
+
+static int 
+N (int stem_length, char *end)
+     
+     
+{
+  if (stem_length >= 3)
+    {
+      if (*(end - 2) == 's')
+	return (stem_length >= 4);
+      else
+	return 1;
+    }
+  else
+    return 0;
+}
+
+static int 
+O (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((p1 == 'l') || (p1 == 'i'));
+}
+
+static int 
+P (int stem_length, char *end)
+     
+     
+{
+  return (*end != 'c');
+}
+
+static int 
+Q (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+
+  return ((stem_length >= 3) && (p1 != 'l') && (p1 != 'n'));
+}
+
+static int 
+R (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+  return ((p1 == 'n') || (p1 == 'r'));
+}
+
+static int 
+S (int stem_length, char *end)
+     
+     
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 't')
+    return (p2 != 't');
+  else
+    return ((p1 == 'r') && (p2 == 'd'));
+}
+
+static int 
+T (int stem_length, char *end)
+     
+     
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 't')
+    return (p2 != 'o');
+  else
+    return (p1 == 's');
+}
+
+static int 
+U (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+
+  return ((p1 == 'l') || (p1 == 'm') ||
+	  (p1 == 'n') || (p1 == 'r'));
+}
+
+static int 
+V (int stem_length, char *end)
+     
+     
+{
+  return (*end == 'c');
+}
+
+static int 
+W (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+
+  return ((p1 != 's') && (p1 != 'u'));
+}
+
+static int 
+X (int stem_length, char *end)
+     
+     
+{
+  char p1;
+  p1 = *end;
+
+  if (p1 == 'e')
+    return ((stem_length >= 3) && (*(end - 2) == 'u'));
+  else
+    return ((p1 == 'l') || (p1 == 'i'));
+}
+
+static int 
+Y (int stem_length, char *end)
+     
+     
+{
+  return ((*end == 'n') && (*(end - 1) == 'i'));
+}
+
+static int 
+Z (int stem_length, char *end)
+     
+     
+{
+  return (*end != 'f');
+}
+
+static int 
+AA (int stem_length, char *end)
+     
+     
+{
+  char p1, p2;
+  p1 = *end;
+  p2 = *(end - 1);
+
+  if (p1 == 'h')
+    return ((p2 == 'p') || (p2 == 't'));
+  else if (p1 == 'r')
+    return ((p2 == 'e') || (p2 == 'o'));
+  else if (p1 == 's')
+    return (p2 == 'e');
+  else
+    return ((p1 == 'd') || (p1 == 'f') ||
+	    (p1 == 'l') || (p1 == 't'));
+}
+
+static int 
+BB (int stem_length, char *end)
+     
+     
+{
+  if (stem_length >= 3)
+    {
+      if (stem_length >= 4)
+	return (strncmp (end - 3, "ryst", 4) != 0);
+      else
+	return (strncmp (end - 2, "met", 3) != 0);
+    }
+  else
+    return 0;
+}
+
+static int 
+CC (int stem_length, char *end)
+     
+     
+{
+  return (*end == 'l');
+}
+
+/**************************************************************************/
+
+#define MIN_STEM_LENGTH 2
+#define MAX_ENDING_SIZE 11
+#define PREDEFINED_SIZE (MAX_ENDING_SIZE + MIN_STEM_LENGTH)
+#define EOS     '\0'
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAX_STEM_LENGTH 255
+
+static char *remove_ending (char *word, int w_len);
+static void recode_stem (char *stem_end);
+
+/* =========================================================================
+ * Function: stem
+ * Description: 
+ *      Implemetation of the Lovins' stemming algorithm described in
+ *      J.B. Lovins, "Development of a Stemming Algorithm",
+ *      Mechanical Translation and Computational Linguistics, Vol 11,1968.
+ * Input: a word string with the length in the first byte
+ * Output: the stemmed word
+ * ========================================================================= */
+
+void
+lovinstem (u_char * word)
+{
+  char *word_start;		/* points to first letter of word */
+  char *stem_end;		/* points to last character of stem portion */
+  int old_length;		/* length of word */
+  int new_length;		/* length after stemming */
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  u_char copy[MAX_STEM_LENGTH + 2];
+  memcpy (copy, word, *word + 1);
+
+  old_length = *copy; /* [RPAP - Jan 97: Stem Index Change] */
+
+  /* The word must be at least MIN_STEM_LENGTH characters long. */
+  if (old_length <= MIN_STEM_LENGTH)
+    return;
+
+  word_start = (char *) copy + 1;	/* jump over length byte */ /* [RPAP - Jan 97: Stem Index Change] */
+  copy[old_length + 1] = '\0';	/* null terminate string */ /* [RPAP - Jan 97: Stem Index Change] */
+
+  stem_end = remove_ending (word_start, old_length);
+  recode_stem (stem_end);
+
+  /* fix up new length */
+  /* have to use strlen because have no other way of telling length */
+  new_length = strlen (word_start);
+  *copy = new_length;  /* [RPAP - Jan 97: Stem Index Change] */
+
+  /* [RPAP - Jan 97: Stem Index Change] */
+  memcpy (word, copy, *copy + 1);
+
+}				/*stem_complex */
+
+/* =========================================================================
+
+ *   Data structure for recoding and the method for recoding the stem. 
+ *
+ * ========================================================================= */
+
+typedef struct
+{
+  char *old_end;		/* old ending */
+  char *new_end;		/* new ending */
+  char old_offset;		/* length of the old ending - 1 */
+  int (*cond) (char);	        /* condition rule */
+  char end_group;		/* signal the end of the group */
+}
+Recode_Rules;
+
+/*  
+   Stem terminations are divided into groups having the same last
+   character
+ */
+
+static Recode_Rules Rules[] =
+{
+  "uad", "uas", 2, NULL, 0,
+  "vad", "vas", 2, NULL, 0,
+  "cid", "cis", 2, NULL, 0,
+  "lid", "lis", 2, NULL, 0,
+  "erid", "eris", 3, NULL, 0,
+  "pand", "pans", 3, NULL, 0,
+  "end", "ens", 2, s, 0,
+  "end", "ens", 2, m, 0,
+  "ond", "ons", 2, NULL, 0,
+  "lud", "lus", 2, NULL, 0,
+  "rud", "rus", 2, NULL, 1,
+
+  "ul", "l", 1, aio, 1,
+
+  "istr", "ister", 3, NULL, 0,
+  "metr", "meter", 3, NULL, 0,
+  "her", "hes", 2, pt, 1,
+
+  "urs", "ur", 2, NULL, 1,
+
+  "uct", "uc", 2, NULL, 0,
+  "umpt", "um", 3, NULL, 0,
+  "rpt", "rb", 2, NULL, 0,
+  "mit", "mis", 2, NULL, 0,
+  "ert", "ers", 2, NULL, 0,
+  "et", "es", 1, n, 0,
+  "yt", "ys", 1, NULL, 1,
+
+  "iev", "ief", 2, NULL, 0,
+  "olv", "olut", 2, NULL, 1,
+
+  "bex", "bic", 2, NULL, 0,
+  "dex", "dic", 2, NULL, 0,
+  "pex", "pic", 2, NULL, 0,
+  "tex", "tic", 2, NULL, 0,
+  "ax", "ac", 1, NULL, 0,
+  "ex", "ec", 1, NULL, 0,
+  "ix", "ic", 1, NULL, 0,
+  "lux", "luc", 2, NULL, 1,
+
+  "yz", "ys", 1, NULL, 1
+};
+
+typedef struct last
+  {
+    char c;			/* The last character */
+    struct last *left;		/* used in balanced   */
+    struct last *right;		/* binary tree        */
+    Recode_Rules *pt;		/* location of approriate group */
+  }
+Last_Char_Node;
+
+/*------------
+       s
+     /   \
+    l     x
+   / \   / \
+  d   r t   z
+         \
+          v
+---------------*/
+static Last_Char_Node pr[] =
+{
+  'd', NULL, NULL, Rules,
+  'l', pr, pr + 2, Rules + 11,
+  'r', NULL, NULL, Rules + 12,
+  's', pr + 1, pr + 6, Rules + 15,
+  't', NULL, pr + 5, Rules + 16,
+  'v', NULL, NULL, Rules + 23,
+  'x', pr + 4, pr + 7, Rules + 25,
+  'z', NULL, NULL, Rules + 33,
+};
+
+
+/*****************************************************************************
+ *
+ *  Recode the stem according to the transformation rules.
+ *
+ *****************************************************************************/
+
+static void
+recode_stem (char *stem_end)
+{
+  static Last_Char_Node *root = pr + 3;
+  Last_Char_Node *p_last = root;
+  Recode_Rules *rule;		/* points to the transformation list */
+  char *h,			/* points to start of possible ending */
+    ch,				/* last character of the old ending  */
+    ch2;
+
+  h = stem_end - 1;
+  ch = *stem_end;
+  if (*h == ch)			/* Check for double consonant        */
+    {
+      if (strchr ("bdglmnprst", ch) != NULL)
+	{
+	  *stem_end = EOS;
+	  stem_end = h;
+	}
+    }
+
+  do				/* Check for the last character       */
+    {
+      ch2 = p_last->c;
+      if (ch == ch2)
+	break;
+      else if (ch > ch2)
+	p_last = p_last->right;
+      else
+	p_last = p_last->left;
+    }
+  while (p_last != NULL);
+
+  if (p_last != NULL)		/* Check for the rest of suffix list */
+    {
+      rule = p_last->pt;
+      for (;;)
+	{
+	  h = stem_end - rule->old_offset;
+	  if (strcmp (h, rule->old_end) == 0)
+	    {
+	      if (!rule->cond || (*rule->cond) (*(h - 1)))
+		{
+		  (void) strcpy (h, rule->new_end);
+		  break;
+		}
+	    }
+	  if (rule->end_group)
+	    break;
+	  ++rule;
+	}
+    }
+}
+
+/* ======================================================================
+
+ *    List of endings and the method to remove the ending 
+ *
+ * ======================================================================*/
+
+/************ Data structures for list of endings  ********************/
+
+typedef struct
+{
+  char *ending;			/* old ending                */
+  int (*cond) (int length, char *end);		/* conditional rule          */
+  signed char left_offset;	/* used to find the siblings */
+  signed char right_offset;	/* in balanced binary tree   */
+}
+Ending_List;
+
+/*
+   The original list of endings is re-organised into groups having
+   the same length and the same first character.
+ */
+
+static Ending_List List[] =
+{
+  "a", NULL, 0, 0,
+
+  "ae", NULL, 0, 0,
+  "al", BB, -1, 2,
+  "ar", X, 0, 0,
+  "as", B, -1, 0,
+
+  "acy", NULL, 0, 1,
+  "age", B, 0, 0,
+  "aic", NULL, -2, 1,
+  "als", BB, 0, 0,
+  "ant", B, -2, 2,
+  "ars", O, 0, 0,
+  "ary", F, -1, 2,
+  "ata", NULL, 0, 0,
+  "ate", NULL, -1, 0,
+
+  "able", NULL, 0, 1,
+  "ably", NULL, 0, 0,
+  "ages", B, -2, 2,
+  "ally", B, 0, 0,
+  "ance", B, -1, 1,
+  "ancy", B, 0, 0,
+  "ants", B, -4, 4,
+  "aric", NULL, 0, 0,
+  "arly", K, -1, 1,
+  "ated", I, 0, 0,
+  "ates", NULL, -2, 2,
+  "atic", B, 0, 0,
+  "ator", NULL, -1, 0,
+
+  "acies", NULL, 0, 0,
+  "acity", NULL, -1, 1,
+  "aging", B, 0, 0,
+  "aical", NULL, -2, 2,
+  "alist", NULL, 0, 0,
+  "alism", B, -1, 0,
+  "ality", NULL, -3, 3,
+  "alize", NULL, 0, 1,
+  "allic", BB, 0, 0,
+  "anced", B, -2, 2,
+  "ances", B, 0, 0,
+  "antic", C, -1, 0,
+  "arial", NULL, -6, 6,
+  "aries", NULL, 0, 1,
+  "arily", NULL, 0, 0,
+  "arity", B, -2, 2,
+  "arize", NULL, 0, 0,
+  "aroid", NULL, -1, 0,
+  "ately", NULL, -3, 3,
+  "ating", I, 0, 1,
+  "ation", B, 0, 0,
+  "ative", NULL, -2, 2,
+  "ators", NULL, 0, 0,
+  "atory", NULL, -1, 1,
+  "ature", E, 0, 0,
+
+  "aceous", NULL, 0, 1,
+  "acious", B, 0, 0,
+  "action", G, -2, 2,
+  "alness", NULL, 0, 0,
+  "ancial", NULL, -1, 1,
+  "ancies", NULL, 0, 0,
+  "ancing", B, -4, 4,
+  "ariser", NULL, 0, 0,
+  "arized", NULL, -1, 1,
+  "arizer", NULL, 0, 0,
+  "atable", NULL, -2, 2,
+  "ations", B, 0, 0,
+  "atives", NULL, -1, 0,
+
+  "ability", NULL, 0, 1,
+  "aically", NULL, 0, 0,
+  "alistic", B, -2, 2,
+  "alities", NULL, 0, 0,
+  "ariness", E, -1, 0,
+  "aristic", NULL, -3, 3,
+  "arizing", NULL, 0, 1,
+  "ateness", NULL, 0, 0,
+  "atingly", NULL, -2, 2,
+  "ational", B, 0, 0,
+  "atively", NULL, -1, 1,
+  "ativism", NULL, 0, 0,
+
+  "ableness", NULL, 0, 1,
+  "arizable", NULL, 0, 0,
+
+  "allically", C, 0, 0,
+  "antaneous", NULL, -1, 1,
+  "antiality", NULL, 0, 0,
+  "arisation", NULL, -2, 2,
+  "arization", NULL, 0, 0,
+  "ationally", B, -1, 1,
+  "ativeness", NULL, 0, 0,
+
+  "antialness", NULL, 0, 0,
+  "arisations", NULL, -1, 1,
+  "arizations", NULL, 0, 0,
+
+  "alistically", B, 0, 1,
+  "arizability", NULL, 0, 0,
+
+  "e", NULL, 0, 0,
+
+  "ed", E, 0, 0,
+  "en", F, -1, 1,
+  "es", E, 0, 0,
+
+  "eal", Y, 0, 0,
+  "ear", Y, -1, 1,
+  "ely", E, 0, 0,
+  "ene", E, -2, 2,
+  "ent", C, 0, 0,
+  "ery", E, -1, 1,
+  "ese", NULL, 0, 0,
+
+  "ealy", Y, 0, 1,
+  "edly", E, 0, 0,
+  "eful", NULL, -2, 1,
+  "eity", NULL, 0, 0,
+  "ence", NULL, -2, 2,
+  "ency", NULL, 0, 0,
+  "ened", E, -1, 2,
+  "enly", E, 0, 0,
+  "eous", NULL, -1, 0,
+
+  "early", Y, 0, 1,
+  "ehood", NULL, 0, 0,
+  "eless", NULL, -2, 2,
+  "elity", NULL, 0, 0,
+  "ement", NULL, -1, 0,
+  "enced", NULL, -3, 3,
+  "ences", NULL, 0, 1,
+  "eness", E, 0, 0,
+  "ening", E, -2, 2,
+  "ental", NULL, 0, 0,
+  "ented", C, -1, 1,
+  "ently", NULL, 0, 0,
+
+  "eature", Z, 0, 0,
+  "efully", NULL, -1, 1,
+  "encies", NULL, 0, 0,
+  "encing", NULL, -2, 2,
+  "ential", NULL, 0, 0,
+  "enting", C, -1, 1,
+  "entist", NULL, 0, 1,
+  "eously", NULL, 0, 0,
+
+  "elihood", E, 0, 1,
+  "encible", NULL, 0, 0,
+  "entally", NULL, -2, 2,
+  "entials", NULL, 0, 0,
+  "entiate", NULL, -1, 1,
+  "entness", NULL, 0, 0,
+
+  "entation", NULL, 0, 0,
+  "entially", NULL, -1, 1,
+  "eousness", NULL, 0, 0,
+
+  "eableness", E, 0, 1,
+  "entations", NULL, 0, 0,
+  "entiality", NULL, -2, 2,
+  "entialize", NULL, 0, 0,
+  "entiation", NULL, -1, 0,
+
+  "entialness", NULL, 0, 0,
+
+  "ful", NULL, 0, 0,
+
+  "fully", NULL, 0, 0,
+
+  "fulness", NULL, 0, 0,
+
+  "hood", NULL, 0, 0,
+
+  "i", NULL, 0, 0,
+
+  "ia", NULL, 0, 0,
+  "ic", NULL, -1, 1,
+  "is", NULL, 0, 0,
+
+  "ial", NULL, 0, 0,
+  "ian", NULL, -1, 1,
+  "ics", NULL, 0, 1,
+  "ide", L, 0, 0,
+  "ied", NULL, -3, 3,
+  "ier", NULL, 0, 0,
+  "ies", P, -1, 0,
+  "ily", NULL, -1, 1,
+  "ine", M, 0, 0,
+  "ing", N, -5, 5,
+  "ion", Q, 0, 0,
+  "ish", C, -1, 1,
+  "ism", B, 0, 1,
+  "ist", NULL, 0, 0,
+  "ite", AA, -3, 3,
+  "ity", NULL, 0, 0,
+  "ium", NULL, -1, 0,
+  "ive", NULL, -1, 1,
+  "ize", F, 0, 0,
+
+  "ials", NULL, 0, 0,
+  "ians", NULL, -1, 0,
+  "ible", NULL, -1, 1,
+  "ibly", NULL, 0, 0,
+  "ical", NULL, -2, 2,
+  "ides", L, 0, 0,
+  "iers", NULL, -1, 1,
+  "iful", NULL, 0, 0,
+  "ines", M, -4, 4,
+  "ings", N, 0, 0,
+  "ions", B, -1, 1,
+  "ious", NULL, 0, 0,
+  "isms", B, -2, 2,
+  "ists", NULL, 0, 0,
+  "itic", H, -1, 1,
+  "ized", F, 0, 1,
+  "izer", F, 0, 0,
+
+  "ially", NULL, 0, 0,
+  "icant", NULL, -1, 1,
+  "ician", NULL, 0, 0,
+  "icide", NULL, -2, 2,
+  "icism", NULL, 0, 0,
+  "icist", NULL, -1, 0,
+  "icity", NULL, -3, 3,
+  "idine", I, 0, 1,
+  "iedly", NULL, 0, 0,
+  "ihood", NULL, -2, 2,
+  "inate", NULL, 0, 0,
+  "iness", NULL, -1, 0,
+  "ingly", B, -6, 6,
+  "inism", J, 0, 1,
+  "inity", CC, 0, 0,
+  "ional", NULL, -2, 2,
+  "ioned", NULL, 0, 0,
+  "ished", NULL, -1, 0,
+  "istic", NULL, -3, 3,
+  "ities", NULL, 0, 1,
+  "itous", NULL, 0, 0,
+  "ively", NULL, -2, 2,
+  "ivity", NULL, 0, 0,
+  "izers", F, -1, 1,
+  "izing", F, 0, 0,
+
+  "ialist", NULL, 0, 0,
+  "iality", NULL, -1, 1,
+  "ialize", NULL, 0, 0,
+  "ically", NULL, -2, 2,
+  "icance", NULL, 0, 0,
+  "icians", NULL, -1, 1,
+  "icists", NULL, 0, 0,
+  "ifully", NULL, -4, 4,
+  "ionals", NULL, 0, 0,
+  "ionate", D, -1, 1,
+  "ioning", NULL, 0, 0,
+  "ionist", NULL, -2, 2,
+  "iously", NULL, 0, 0,
+  "istics", NULL, -1, 1,
+  "izable", E, 0, 0,
+
+  "ibility", NULL, 0, 0,
+  "icalism", NULL, -1, 1,
+  "icalist", NULL, 0, 1,
+  "icality", NULL, 0, 0,
+  "icalize", NULL, -3, 3,
+  "ication", G, 0, 0,
+  "icianry", NULL, -1, 0,
+  "ination", NULL, -1, 1,
+  "ingness", NULL, 0, 0,
+  "ionally", NULL, -5, 5,
+  "isation", NULL, 0, 0,
+  "ishness", NULL, -1, 1,
+  "istical", NULL, 0, 1,
+  "iteness", NULL, 0, 0,
+  "iveness", NULL, -3, 3,
+  "ivistic", NULL, 0, 0,
+  "ivities", NULL, -1, 0,
+  "ization", F, -1, 1,
+  "izement", NULL, 0, 0,
+
+  "ibleness", NULL, 0, 0,
+  "icalness", NULL, -1, 1,
+  "ionalism", NULL, 0, 0,
+  "ionality", NULL, -2, 2,
+  "ionalize", NULL, 0, 0,
+  "iousness", NULL, -1, 1,
+  "izations", NULL, 0, 0,
+
+  "ionalness", NULL, 0, 1,
+  "istically", NULL, 0, 0,
+  "itousness", NULL, -2, 2,
+  "izability", NULL, 0, 0,
+  "izational", NULL, -1, 0,
+
+  "izationally", B, 0, 0,
+
+  "ly", B, 0, 0,
+
+  "less", NULL, 0, 1,
+  "lily", NULL, 0, 0,
+
+  "lessly", NULL, 0, 0,
+
+  "lessness", NULL, 0, 0,
+
+  "ness", NULL, 0, 0,
+
+  "nesses", NULL, 0, 0,
+
+  "o", NULL, 0, 0,
+
+  "on", S, 0, 1,
+  "or", T, 0, 0,
+
+  "oid", NULL, 0, 0,
+  "one", R, -1, 1,
+  "ous", NULL, 0, 0,
+
+  "ogen", NULL, 0, 0,
+
+  "oidal", NULL, 0, 0,
+  "oides", NULL, -1, 2,
+  "otide", NULL, 0, 0,
+  "ously", NULL, -1, 0,
+
+  "oidism", NULL, 0, 0,
+
+  "oidally", NULL, 0, 1,
+  "ousness", NULL, 0, 0,
+
+  "s", W, 0, 0,
+
+  "s'", NULL, 0, 0,
+
+  "um", U, 0, 1,
+  "us", V, 0, 0,
+
+  "ward", NULL, 0, 1,
+  "wise", NULL, 0, 0,
+
+  "y", B, 0, 0,
+
+  "yl", R, 0, 0,
+
+  "ying", B, 0, 1,
+  "yish", NULL, 0, 0,
+
+  "'s", NULL, 0, 0,
+};
+
+typedef struct node
+  {
+    char c;			/* First character  */
+    struct node *left;		/* used in balanced */
+    struct node *right;		/* binary tree      */
+    Ending_List *ptr[11];	/* the approriate location */
+  }
+First_Char_Node;
+
+static First_Char_Node First[] =
+{
+  '\'', NULL, NULL,
+  {NULL,
+   List + 293, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'a', First, NULL,
+  {List,
+   List + 2, List + 9, List + 20, List + 39, List + 58,
+   List + 70, List + 77, List + 82, List + 87, List + 89},
+
+  'e', First + 1, First + 4,
+  {List + 91,
+   List + 93, List + 98, List + 106, List + 116, List + 126,
+   List + 133, List + 138, List + 142, List + 145, NULL},
+
+  'f', NULL, NULL,
+  {NULL,
+   NULL, List + 146, NULL, List + 147, NULL,
+   List + 148, NULL, NULL, NULL, NULL},
+
+  'h', First + 3, First + 5,
+  {NULL,
+   NULL, NULL, List + 149, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'i', NULL, NULL,
+  {List + 150,
+   List + 152, List + 163, List + 181, List + 202, List + 222,
+   List + 239, List + 252, List + 258, NULL, List + 261},
+
+  'l', First + 2, First + 10,
+  {NULL,
+   List + 262, NULL, List + 263, NULL, List + 265,
+   NULL, List + 266, NULL, NULL, NULL},
+
+  'n', NULL, NULL,
+  {NULL,
+   NULL, NULL, List + 267, NULL, List + 268,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'o', First + 7, First + 9,
+  {List + 269,
+   List + 270, List + 273, List + 275, List + 277, List + 280,
+   List + 281, NULL, NULL, NULL, NULL},
+
+  's', NULL, NULL,
+  {List + 283,
+   List + 284, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'u', First + 8, First + 12,
+  {NULL,
+   List + 285, NULL, NULL, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'w', NULL, NULL,
+  {NULL,
+   NULL, NULL, List + 287, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+
+  'y', First + 11, NULL,
+  {List + 289,
+   List + 290, NULL, List + 291, NULL, NULL,
+   NULL, NULL, NULL, NULL, NULL},
+};
+
+
+/******************************************************************************
+ *
+ *  Look for a match in the suffix list.
+ *  Return the pointer to the end of the new stem if there is a match.
+ *  Otherwise, return the pointer to the end of the original word.
+ *
+ *  Method:
+ *      * Search for the first character in the suffix list.
+ *      * If there is match, search for the rest of the suffix list.
+ *         
+ *****************************************************************************/
+
+static char *
+remove_ending (char *word, int w_len)
+{
+  static First_Char_Node *root = First + 6;	/* the root of binary tree is 'l' */
+  First_Char_Node *p_first;	/* Points to the first character      */
+  /* of the possible suffix             */
+  Ending_List *p_list;		/* Points to the List of Endings      */
+  char *suffix_start,		/* Points to start of possible suffix */
+   *stem_end,			/* Points to the end of possible stem */
+    ch1, ch2;
+  int s_len,			/* Possible stem length               */
+    e_offset,			/* Offset from the end to the start of */
+  /* possible suffix                    */
+    not_done = 1, cmp;
+
+  stem_end = word + w_len - 1;
+  if (w_len > PREDEFINED_SIZE)	/* find the start of suffix   */
+    suffix_start = word + w_len - MAX_ENDING_SIZE;
+  else
+    suffix_start = word + MIN_STEM_LENGTH;
+
+  ch1 = *suffix_start;
+  do				/* Search for the first character     */
+    {
+      p_first = root;
+      do
+	{
+	  ch2 = p_first->c;
+	  if (ch1 == ch2)
+	    break;
+	  else if (ch1 > ch2)
+	    p_first = p_first->right;
+	  else
+	    p_first = p_first->left;
+	}
+      while (p_first != NULL);
+
+      if (p_first != NULL)	/* Search for the rest */
+	{
+	  e_offset = stem_end - suffix_start;
+	  if ((p_list = p_first->ptr[e_offset]) != NULL)
+	    {
+	      for (;;)		/* no need to compare the first char  */
+		{
+		  cmp = strcmp (suffix_start + 1, p_list->ending + 1);
+		  if (cmp > 0)
+		    if (p_list->right_offset)
+		      p_list += p_list->right_offset;
+		    else
+		      break;
+		  else if (cmp < 0)
+		    if (p_list->left_offset)
+		      p_list += p_list->left_offset;
+		    else
+		      break;
+		  else
+		    {
+		      s_len = suffix_start - word;
+		      if (!p_list->cond ||
+			  (*p_list->cond) (s_len, suffix_start - 1))
+			{
+			  *suffix_start = EOS;
+			  stem_end = suffix_start - 1;
+			  not_done = 0;
+			}
+		      break;
+		    }
+		}
+	    }
+	}
+      ++suffix_start;
+    }
+  while (not_done && ((ch1 = *suffix_start) != EOS));
+  return (stem_end);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/lovinstem.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/lovinstem.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/lovinstem.h	(revision 10506)
@@ -0,0 +1,28 @@
+/**************************************************************************
+ *
+ * lovinstem.h -- Lovins' stemmer header
+ * Copyright (C) 1994  Linh Huynh, 
+ *                     (glued into library by tes@kbs.citri.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef LOVINSTEM_H
+#define LOVINSTEM_H
+
+void lovinstem (unsigned char *word);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/memlib.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/memlib.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/memlib.cpp	(revision 10506)
@@ -0,0 +1,41 @@
+/**************************************************************************
+ *
+ * memlib.c -- Malloc wrappers
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+/* Defined as strdup is not an ANSI function */
+char *
+my_strdup(const char *str)
+{
+  char *ret_str = new char[strlen(str)+1];
+  if (ret_str) return strcpy(ret_str, str);
+  else return (char*) 0;
+}
+
+
+Malloc_func Xmalloc = malloc;
+
+Realloc_func Xrealloc = realloc;
+
+Free_func Xfree = free;
+
+Strdup_func Xstrdup = my_strdup;
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/memlib.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/memlib.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/memlib.h	(revision 10506)
@@ -0,0 +1,55 @@
+/**************************************************************************
+ *
+ * memlib.h -- Malloc wrappers
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef H_MEMLIB
+#define H_MEMLIB
+
+/* changed default behaviour - we now assume std memory. - john mcp. */
+/* #ifdef STD_MEM */
+#if !defined(NOT_STD_MEM)
+#include <string.h>
+#define Xmalloc malloc
+#define Xrealloc realloc
+#define Xfree free
+
+#if defined (__WIN32__)
+# define Xstrdup _strdup
+#else
+# define Xstrdup strdup
+#endif
+
+#else
+
+
+#include "sysfuncs.h"
+
+typedef void *(*Malloc_func) (size_t);
+typedef void *(*Realloc_func) (void *, size_t);
+typedef void (*Free_func) (void *);
+typedef char *(*Strdup_func) (const char *);
+
+extern Malloc_func Xmalloc;
+extern Realloc_func Xrealloc;
+extern Free_func Xfree;
+extern Strdup_func Xstrdup;
+#endif
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/messages.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/messages.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/messages.cpp	(revision 10506)
@@ -0,0 +1,75 @@
+/**************************************************************************
+ *
+ * messages.c -- Message and error functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include <stdarg.h>
+#include "messages.h"
+
+char *msg_prefix = "";
+
+
+void VOLATILE 
+FatalError (int ExitCode, const char *fmt,...)
+{
+  char buf[1024];
+  char *s, *pfx;
+  va_list args;
+  va_start (args, fmt);
+  vsprintf (buf, fmt, args);
+  s = strrchr (buf, '\n');
+  if (!s || *(s + 1) != '\0')
+    strcat (buf, "\n");
+  pfx = strrchr (msg_prefix, '/');
+  pfx = pfx ? pfx + 1 : msg_prefix;
+  fprintf (stderr, "%s%s%s", pfx, *pfx ? " : " : "", buf);
+  exit (ExitCode);
+}
+
+
+
+/*
+ * This function writes messages to stderr. Due to the fact that I can't 
+ * guarantee that the fprintf call is monatomic I have to implement a 
+ * semaphore system.
+ */
+void 
+Message (const char *fmt,...)
+{
+  char buf[1024];
+  char *s, *pfx;
+  va_list args;
+
+#ifdef SILENT
+  return; /* stop those messages!!!! */
+#endif  
+
+  va_start (args, fmt);
+  vsprintf (buf, fmt, args);
+  s = strrchr (buf, '\n');
+  if (!s || *(s + 1) != '\0')
+    strcat (buf, "\n");
+
+  pfx = strrchr (msg_prefix, '/');
+  pfx = pfx ? pfx + 1 : msg_prefix;
+  fprintf (stderr, "%s%s%s", pfx, *pfx ? " : " : "", buf);
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/messages.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/messages.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/messages.h	(revision 10506)
@@ -0,0 +1,49 @@
+/**************************************************************************
+ *
+ * messages.h -- Message and error functions
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef H_MESSAGES
+#define H_MESSAGES
+
+#ifdef __GNUC__
+#define VOLATILE volatile
+#else
+#define VOLATILE
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+extern char *msg_prefix;
+
+void VOLATILE FatalError (int ExitCode, const char *fmt,...);
+void Message (const char *fmt,...);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/mgheap.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/mgheap.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/mgheap.cpp	(revision 10506)
@@ -0,0 +1,148 @@
+/**************************************************************************
+ *
+ * mgheap.c -- Heap routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "mgheap.h"
+
+#define SWAP(s, a, b) 						\
+do {								\
+     register int __i;						\
+     register char *__a = (a), *__b = (b);			\
+     for (__i = (s); __i; --__i)				\
+       {							\
+         register char __t = *__a;				\
+	 *__a++ = *__b; *__b++ = __t;				\
+       }							\
+} while(0)
+
+
+
+#define COPY(s, dst, src) 					\
+do {								\
+     register int __i;						\
+     register char *__dst = (dst), *__src = (src);		\
+     for (__i = (s); __i; --__i)				\
+       *__dst++ = *__src++;					\
+} while(0)
+
+
+
+static void 
+heap_heapify (void *heap, int size, int num, int curr, heap_comp hc)
+{
+  register int child = curr * 2;
+  while (child <= num)
+    {
+      if (child < num && hc ((char *) heap + child * size,
+			     (char *) heap + child * size - size) < 0)
+	++child;
+      if (hc ((char *) heap + (curr - 1) * size, (char *) heap + (child - 1) * size) > 0)
+	{
+	  SWAP (size, (char *) heap + (curr - 1) * size,
+		(char *) heap + (child - 1) * size);
+	  curr = child;
+	  child = child * 2;
+	}
+      else
+	break;
+    }
+}
+
+static void 
+heap_pullup (void *heap, int size, int num, heap_comp hc)
+{
+  register int curr = num;
+  register int parent = curr >> 1;
+  while (parent &&
+	 hc ((char *) heap + (curr - 1) * size, (char *) heap + (parent - 1) * size) < 0)
+    {
+      SWAP (size, (char *) heap + (curr - 1) * size,
+	    (char *) heap + (parent - 1) * size);
+      curr = parent;
+      parent = curr >> 1;
+    }
+}
+
+/************************************************************************
+ *
+ * NOTE: If you choose to change the comparison function the first thing 
+ *       you do after changing the function is call heap_build.
+ *
+ */
+void 
+heap_build (void *heap, int size, int num, heap_comp hc)
+{
+  register int i;
+  for (i = num / 2; i > 0; --i)
+    heap_heapify (heap, size, num, i, hc);
+}
+
+
+
+/****************************************************
+ *
+ * NOTE : The heap must be built before heap_sort is called. 
+ *        This has the effect of reversing the order of the array.
+ *		e.g. if your comparison function is designed to pull the
+ *                   biggest thing off the heap first then the result of
+ *		     sorting with this function will be to put the bigest
+ *                   thing at the end of the array.
+ *
+ */
+void 
+heap_sort (void *heap, int size, int num, heap_comp hc)
+{
+  register int i;
+  for (i = num; i > 1; --i)
+    {
+      SWAP (size, (char *) heap, (char *) heap + (i - 1) * size);
+      heap_heapify (heap, size, i - 1, 1, hc);
+    }
+}
+
+
+void 
+heap_deletehead (void *heap, int size, int *num, heap_comp hc)
+{
+  --(*num);
+  SWAP (size, (char *) heap, (char *) heap + *num * size);
+  heap_heapify (heap, size, *num, 1, hc);
+}
+
+
+void 
+heap_changedhead (void *heap, int size, int num, heap_comp hc)
+{
+  heap_heapify (heap, size, num, 1, hc);
+}
+
+
+/***********************************************************************
+ *
+ * This assumes that the item has been added to the end of the
+ * array that is the heap. But that num has not been changed. 
+ *
+ */
+void 
+heap_additem (void *heap, int size, int *num, heap_comp hc)
+{
+  ++(*num);
+  heap_pullup (heap, size, *num, hc);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/mgheap.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/mgheap.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/mgheap.h	(revision 10506)
@@ -0,0 +1,82 @@
+/**************************************************************************
+ *
+ * mgheap.h -- Heap routines
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+/* Care should be taken when using these routines as NO error checking is
+ * done.
+ */
+
+
+
+/* The heap comparison routine should return 
+ * <0 : If a should be before b
+ *  0 : If a and b are equal
+ * >0 : If a should be after b
+ */
+typedef int (*heap_comp) (void *a, void *b);
+
+
+/************************************************************************
+ *
+ * NOTE: If you choose to change the comparison function the first thing 
+ *       you do after changing the function is call heap_build.
+ *
+ */
+void heap_build (void *heap, int size, int num, heap_comp hc);
+
+
+
+/************************************************************************
+ *
+ * NOTE : The heap must be built before heap_sort is called.
+ *        This has the effect of reversing the order of the array.
+ *		e.g. if your comparison function is designed to pull the
+ *                   biggest thing off the heap first then the result of
+ *		     sorting with this function will be to put the bigest
+ *                   thing at the end of the array.
+ *
+ */
+void heap_sort (void *heap, int size, int num, heap_comp hc);
+
+/***********************************************************************
+ *
+ * NOTE: After deleting the head the heap will be one item shorter.
+ *       The deleted item will be placed at the end of the heap.
+ *
+ */
+void heap_deletehead (void *heap, int size, int *num, heap_comp hc);
+
+
+/***********************************************************************
+ *
+ * If you change the "value" of the root node of the heap then you
+ * should call this to re-pritorize the heap.
+ *
+ */
+void heap_changedhead (void *heap, int size, int num, heap_comp hc);
+
+
+/***********************************************************************
+ *
+ * This assumes that the item has been added to the end of the
+ * array that is the heap. But that num has not been changed. 
+ *
+ */
+void heap_additem (void *heap, int size, int *num, heap_comp hc);
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/netorder.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/netorder.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/netorder.h	(revision 10506)
@@ -0,0 +1,189 @@
+#ifndef NETORDER_H
+#define NETORDER_H
+
+#include "sysfuncs.h"
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+#include "win32in.h"
+#else
+# include <netinet/in.h>
+#endif
+
+#if defined (_BIG_ENDIAN) || (defined (BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || (defined (__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN)
+# ifndef _BIG_ENDIAN
+#  define _BIG_ENDIAN
+# endif
+#endif
+
+#if defined (_LITTLE_ENDIAN) || (defined (BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || (defined (__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN)
+# ifndef _LITTLE_ENDIAN
+#  define _LITTLE_ENDIAN
+# endif
+#endif
+
+#ifdef _LITTLE_ENDIAN
+
+/* double */
+#define HTOND(d)                                                              \
+        do {                                                                  \
+             unsigned long tmph, tmpl;                                        \
+	     memcpy ((void *) &tmph, (const void *) &d, sizeof(double) >> 1); \
+	     memcpy ((void *) &tmpl, (const void *) ((unsigned int) &d + (sizeof(double) >> 1)), sizeof (double) >> 1);   \
+	     tmph = htonl (tmph);                                             \
+	     tmpl = htonl (tmpl);                                             \
+	     memcpy ( (void *) &d, (const void *) &tmpl, sizeof (double) >> 1);                           \
+	     memcpy ((void *) ((unsigned int) &d + (sizeof(double) >> 1)), (const void *) &tmph, sizeof (double) >> 1);   \
+	}while(0)
+#define NTOHD(d)                                                              \
+        do {                                                                  \
+             unsigned long tmph, tmpl;                                        \
+	     memcpy ((void *) &tmph, (const void *) &d, sizeof(double) >> 1); \
+	     memcpy ((void *) &tmpl, (const void *) ((int) &d + (sizeof(double) >> 1)), sizeof (double) >> 1);   \
+	     tmph = ntohl (tmph);                                             \
+	     tmpl = ntohl (tmpl);                                             \
+	     memcpy((void *) &d, (const void *) &tmpl, sizeof (double) >> 1); \
+	     memcpy ((void *) ((int) &d + (sizeof(double) >> 1)), (const void *) &tmph, sizeof (double) >> 1);   \
+        }while(0)
+#define HTOND2(hd, nd)                                                        \
+        do {                                                                  \
+             unsigned long tmph, tmpl;                                        \
+	     memcpy ((void *) &tmph, (const void *) &hd, sizeof(double) >> 1);\
+	     memcpy ((void *) &tmpl, (const void *) ((unsigned int) &hd + (sizeof(double) >> 1)), sizeof (double) >> 1);  \
+	     tmph = htonl (tmph);                                             \
+	     tmpl = htonl (tmpl);                                             \
+	     memcpy((void *) &nd, (const void *) &tmpl, sizeof (double) >> 1);\
+	     memcpy ((void *) ((unsigned int) &nd + (sizeof(double) >> 1)), (void *) &tmph, sizeof (double) >> 1);  \
+	}while(0)
+#define NTOHD2(nd, hd)                                                        \
+        do {                                                                  \
+             unsigned long tmph, tmpl;                                        \
+	     memcpy ((void *) &nd, (void *) &tmph, sizeof(double) >> 1);      \
+	     memcpy ((void *) &tmpl, (const void *) &nd + (sizeof(double) >> 1), sizeof (double) >> 1);  \
+	     tmph = ntohl (tmph);                                             \
+	     tmpl = ntohl (tmpl);                                             \
+	     memcpy((void *) &hd, (const void *) &tmpl, sizeof (double) >> 1);\
+	     memcpy ((void *) &hd + (sizeof(double) >> 1), (const void *) &tmph, sizeof (double) >> 1);  \
+        }while(0)
+
+/* float */
+#define HTONF(f)                                                              \
+        do {                                                                  \
+             unsigned long tmp;                                               \
+             memcpy ((void *) &tmp, (const void *) &(f), sizeof (float));     \
+             HTONUL (tmp);                                                    \
+	     memcpy ((void *) &(f), (const void *) &tmp, sizeof (float));     \
+	}while(0)
+#define NTOHF(f)                                                              \
+        do {                                                                  \
+             unsigned long tmp;                                               \
+             memcpy ((void *) &tmp, (const void *) &(f), sizeof (float));     \
+	     NTOHUL (tmp);                                                    \
+	     memcpy ((void *) &(f), (const void *) &tmp, sizeof (float));     \
+	}while(0)
+#define HTONF2(hf, nf)                                                        \
+        do {                                                                  \
+             unsigned long tmp;                                               \
+             memcpy ((void *) &tmp, (const void *) &(hf), sizeof (float));    \
+             HTONUL (tmp);                                                    \
+	     memcpy ((void *) &(nf), (const void *) &tmp, sizeof (float));    \
+	}while(0)
+#define NTOHF2(nf, hf)                                                        \
+        do {                                                                  \
+             unsigned long tmp;                                               \
+             memcpy ((void *) &tmp, (const void *) &(nf), sizeof (float));    \
+	     NTOHUL (tmp);                                                    \
+	     memcpy ((void *) &(hf), (const void *) &tmp, sizeof (float));    \
+	}while(0)
+
+/* pointers */
+#define HTONP(p)          ((p) = (void *) htonl ((unsigned long) p))
+#define NTOHP(p)          ((p) = (void *) ntohl ((unsigned long) p))
+#define HTONP2(hp, np)    ((np) = (void *) htonl ((unsigned long) hp))
+#define NTOHP2(np, hp)    ((hp) = (void *) ntohl ((unsigned long) np))
+
+/* unsigned long */
+#define HTONUL(l)         ((l) = htonl((l)))
+#define NTOHUL(l)         ((l) = ntohl((l)))
+#define HTONUL2(hl, nl)   ((nl) = htonl ((hl)))
+#define NTOHUL2(nl, hl)   ((hl) = ntohl ((nl)))
+
+/* signed long */
+#define HTONSL(l)         ((l) = (long) htonl ((unsigned long) (l)))
+#define NTOHSL(l)         ((l) = (long) ntohl ((unsigned long) (l)))
+#define HTONSL2(hl, nl)   ((nl) = (long) htonl ((unsigned long) (hl)))
+#define NTOHSL2(nl, hl)   ((hl) = (long) ntohl ((unsigned long) (nl)))
+
+/* unsigned int */
+#define HTONUI(i)         ((i) = (unsigned int) htonl ((unsigned long) (i)))
+#define NTOHUI(i)         ((i) = (unsigned int) ntohl ((unsigned long) (i)))
+#define HTONUI2(hi, ni)   ((ni) = (unsigned int) htonl ((unsigned long) (hi)))
+#define NTOHUI2(ni, hi)   ((hi) = (unsigned int) ntohl ((unsigned long) (ni)))
+
+/* signed int */
+#define HTONSI(i)         ((i) = (int) htonl ((unsigned long) (i)))
+#define NTOHSI(i)         ((i) = (int) ntohl ((unsigned long) (i)))
+#define HTONSI2(hi, ni)   ((ni) = (int) htonl ((unsigned long) (hi)))
+#define NTOHSI2(ni, hi)   ((hi) = (int) ntohl ((unsigned long) (ni)))
+
+/* unsigned short */
+#define HTONUS(s)         ((s) = htons((s)))
+#define NTOHUS(s)         ((s) = ntohs((s)))
+#define HTONUS2(hs, ns)   ((ns) = htons((hs)))
+#define NTOHUS2(ns, hs)   ((hs) = ntohs((ns)))
+
+#else   /* _BIG_ENDIAN */
+
+/* double */
+#define HTOND(d)          (d)
+#define NTOHD(d)          (d)
+#define HTOND2(hd, nd)    ((hd) = (nd))
+#define NTOHD2(nd, hd)    ((nd) = (hd))
+
+/* float */
+#define HTONF(f)          (f)
+#define NTOHF(f)          (f)
+#define HTONF2(hf, nf)    ((nf) = (hf))
+#define NTOHF2(nf, hf)    ((hf) = (nf))
+
+/* pointers */
+#define HTONP(p)          (p)
+#define NTOHP(p)          (p)
+#define HTONP2(hp, np)    ((np) = (hp))
+#define NTOHP2(np, hp)    ((hp) = (np))
+
+/* unsigned long */
+#define HTONUL(l)         (l)
+#define NTOHUL(l)         (l)
+#define HTONUL2(hl, nl)   ((nl) = (hl))
+#define NTOHUL2(nl, hl)   ((hl) = (nl))
+
+/* signed long */
+#define HTONSL(l)         (l)
+#define NTOHSL(l)         (l)
+#define HTONSL2(hl, nl)   ((nl) = (hl))
+#define NTOHSL2(nl, hl)   ((hl) = (nl))
+
+/* unsigned int */
+#define HTONUI(i)         (i)
+#define NTOHUI(i)         (i)
+#define HTONUI2(hi, ni)   ((ni) = (hi))
+#define NTOHUI2(ni, hi)   ((hi) = (ni))
+
+/* signed int */
+#define HTONSI(i)         (i)
+#define NTOHSI(i)         (i)
+#define HTONSI2(hi, ni)   ((ni) = (hi))
+#define NTOHSI2(ni, hi)   ((hi) = (ni))
+
+/* unsigned short */
+#define HTONUS(s)         (s)
+#define NTOHUS(s)         (s)
+#define HTONUS2(hs, ns)   ((ns) = (hs))
+#define NTOHUS2(ns, hs)   ((hs) = (ns))
+
+
+
+#endif
+
+#endif /* netorder.h */
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/non_ansi.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/non_ansi.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/non_ansi.h	(revision 10506)
@@ -0,0 +1,24 @@
+#if !defined(_NON_ANSI_H)
+#define _NON_ANSI_H 1
+
+#include "config.h" 
+# if !defined(__STDC__)
+
+#include <stdlib.h>  /* for FILE def */
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+int fileno(FILE *);
+int ftruncate(int, long);
+int pclose(FILE *);
+FILE *popen(const char *command, const char *type);
+int getpagesize();
+int strcasecmp(const char *, const char *);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* !defined STDC, ... */
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/pathmax.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/pathmax.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/pathmax.h	(revision 10506)
@@ -0,0 +1,53 @@
+/* Define PATH_MAX somehow.  Requires sys/types.h.
+   Copyright (C) 1992 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _PATHMAX_H
+#define _PATHMAX_H
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
+   PATH_MAX but might cause redefinition warnings when sys/param.h is
+   later included (as on MORE/BSD 4.3).  */
+#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__))
+#include <limits.h>
+#endif
+
+#ifndef _POSIX_PATH_MAX
+#define _POSIX_PATH_MAX 255
+#endif
+
+#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
+#define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
+#endif
+
+/* Don't include sys/param.h if it already has been.  */
+#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN)
+#include <sys/param.h>
+#endif
+
+#if !defined(PATH_MAX) && defined(MAXPATHLEN)
+#define PATH_MAX MAXPATHLEN
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX _POSIX_PATH_MAX
+#endif
+
+#endif /* _PATHMAX_H */
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/perf_hash.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/perf_hash.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/perf_hash.cpp	(revision 10506)
@@ -0,0 +1,1074 @@
+/**************************************************************************
+ *
+ * perf_hash.c -- Perfect hashing functions
+ * Copyright (C) 1992  Bohdan S. Majewski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************
+ *
+ * 1994 Neil Sharman
+ *      Small modifications were made to the interface so that it fitted in
+ *      with mg.
+ *
+ **************************************************************************/
+
+#define STRUCT
+
+#include <time.h>  /* for call to time () in SEED_RANDOM() */
+#include "sysfuncs.h"
+
+#include "local_strings.h"
+#include "memlib.h"
+#include "messages.h"
+#include "perf_hash.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#define FALSE 0
+#define TRUE  1
+
+#define STATIC 0
+
+/* Random Number stuff */
+
+long irandm (long is[2]);  /* from random.c */
+
+static long seed[] = {0, 0};
+#define RANDOM() irandm(seed)
+#define SEED_RANDOM(the_seed) do{ seed[0] = the_seed; }while(0)
+
+/* Max number of keys - must be a power of 2 minus 1 */
+static int MAX_M;
+
+
+static int MAX_CH;
+
+
+/* the width of the mapping tables  */
+static int MAX_L;
+
+
+
+#define c     1.23
+static int MAX_N;
+
+
+
+
+static u_char *translate;
+
+#define MEMBER 0
+#define ERASED 1
+
+
+
+/* direction constants for the edge oriented 3-graph representation */
+#define A              0
+#define B        (MAX_M)
+#define C          (2*B)
+
+/* NODEa, NODEb, NODEc, FIRST and NEXT are used to represent a 3-graph */
+static int *NODEa, *NODEb, *NODEc;
+static int *FIRST;
+static int *NEXT;
+
+
+#define norm(e) ((e) % MAX_M)
+/* in general should be ((e) % MAX_M) but MAX_M = 2^k - 1 */
+
+
+static char *mk;		/* for marking edges/vertices as removed */
+static int *g;			/* array g defines a minimal perfect hash function */
+
+
+
+/* stack of edges, created during the independency */
+/* test, used in the assignment step               */
+static struct
+  {
+    int sp;
+    int *st;
+  }
+S;
+#define push(s, e) s.st[s.sp++] = (e)
+#define pop(s, e)  e = s.st[--s.sp]
+
+#ifndef STRUCT
+static long **tb0, **tb1, **tb2;
+#else
+struct tb_entry **tb;
+#endif
+
+
+static int 
+unique (int v)
+{				/* checks if vertex v belongs to only one edge */
+  return (FIRST[v] != 0 && NEXT[FIRST[v]] == 0) ? FIRST[v] : 0;
+}				/*unique */
+
+
+
+
+
+
+
+
+static void 
+_delete (int v, int e)
+{				/* deletes edge e from list of v */
+
+  int b;
+
+  b = FIRST[v];
+  assert (norm (b) != 0);
+  if (norm (b) == e)
+    FIRST[v] = NEXT[FIRST[v]];
+  else
+    {
+      while (norm (NEXT[b]) != e)
+	{
+	  b = NEXT[b];
+	  assert (norm (b) != 0);
+	}
+      NEXT[b] = NEXT[NEXT[b]];
+    }
+}				/*delete */
+
+
+
+
+
+
+#if 0
+/* recursively removes the edges of a 3-graph which have at least */
+/* one unique vertex. The removed edges are placed on stack S     */
+static void 
+ph_remove (int e, int v)
+{
+  int b;
+  mk[e] = ERASED;
+  push (S, e);
+
+  if (NODEa[e] != v)
+    _delete (NODEa[e], e);
+  if (NODEb[e] != v)
+    _delete (NODEb[e], e);
+  if (NODEc[e] != v)
+    _delete (NODEc[e], e);
+
+  if (NODEa[e] != v && mk[b = norm (unique (NODEa[e]))] == MEMBER)
+    ph_remove (b, NODEa[e]);
+  if (NODEb[e] != v && mk[b = norm (unique (NODEb[e]))] == MEMBER)
+    ph_remove (b, NODEb[e]);
+  if (NODEc[e] != v && mk[b = norm (unique (NODEc[e]))] == MEMBER)
+    ph_remove (b, NODEc[e]);
+}
+#else
+
+
+static int StackPos, StackMax;
+static struct Stack
+  {
+    int e, v, m;
+  }
+ *Stack = NULL;
+
+#define StackAdd(_e, _v, _m)						\
+  do {									\
+    if (StackPos == StackMax)						\
+      {									\
+        StackMax <<= 1;							\
+	if (!(Stack = (struct Stack *)Xrealloc(Stack, sizeof(*Stack) * StackMax)))	\
+	  return(-1);							\
+      }									\
+    Stack[StackPos].e = (_e);						\
+    Stack[StackPos].v = (_v);						\
+    Stack[StackPos++].m = (_m);						\
+  } while(0)
+
+
+static int 
+ph_remove (int e, int v)
+{
+  if (!Stack)
+    {
+      StackMax = 256;
+      if (!(Stack = (struct Stack *) Xmalloc (sizeof (*Stack) * StackMax)))
+	return (-1);
+      StackPos = 0;
+    }
+  Stack[StackPos].e = e;
+  Stack[StackPos].v = v;
+  Stack[StackPos].m = 0;
+  ++StackPos;
+  while (StackPos)
+    {
+      int m, b;
+      --StackPos;
+      e = Stack[StackPos].e;
+      v = Stack[StackPos].v;
+      m = Stack[StackPos].m;
+
+
+      switch (m)
+	{
+	case 0:
+	  {
+	    mk[e] = ERASED;
+	    push (S, e);
+
+	    if (NODEa[e] != v)
+	      _delete (NODEa[e], e);
+	    if (NODEb[e] != v)
+	      _delete (NODEb[e], e);
+	    if (NODEc[e] != v)
+	      _delete (NODEc[e], e);
+
+	    if (NODEa[e] != v && mk[b = norm (unique (NODEa[e]))] == MEMBER)
+	      {
+		Stack[StackPos++].m = 1;
+		StackAdd (b, NODEa[e], 0);
+		break;
+	      }
+	  }
+	case 1:
+	  {
+	    if (NODEb[e] != v && mk[b = norm (unique (NODEb[e]))] == MEMBER)
+	      {
+		Stack[StackPos++].m = 2;
+		StackAdd (b, NODEb[e], 0);
+		break;
+	      }
+	  }
+	case 2:
+	  if (NODEc[e] != v && mk[b = norm (unique (NODEc[e]))] == MEMBER)
+	    StackAdd (b, NODEc[e], 0);
+	}
+    }
+  return (0);
+}
+#endif
+
+
+
+
+
+/* returns TRUE if and only if set of edges created in the tree_builder */
+/* procedure form a 3-graph with independent edges. Edges of a 3-graph  */
+/* are independent iff repeated deletion of edges containing vertices   */
+/* of degree 1 results in a graph with no edges in it.                  */
+static int 
+acyclic (int m, int n)
+{
+
+  int v, e;
+  /* build list of edges for each node */
+  for (v = 1; v <= n; FIRST[v++] = 0);
+  for (e = 1; e <= m; ++e)
+    {
+      NEXT[A + e] = FIRST[NODEa[e]];
+      FIRST[NODEa[e]] = A + e;
+      NEXT[B + e] = FIRST[NODEb[e]];
+      FIRST[NODEb[e]] = B + e;
+      NEXT[C + e] = FIRST[NODEc[e]];
+      FIRST[NODEc[e]] = C + e;
+
+      /* mark edge e as belonging to the hypergraph */
+      mk[e] = MEMBER;
+    }
+
+
+  S.sp = 0;			/* empty the stack */
+  mk[0] = ERASED;		/* a sentinel for the test below */
+  for (v = 1; v <= n; ++v)
+    {
+      if (mk[e = norm (unique (v))] == MEMBER)
+	ph_remove (e, v);
+    }
+
+  /* check if any edges were left in the graph */
+  return S.sp == m;
+}				/*acyclic */
+
+
+
+
+
+
+
+
+/* repeatedly maps words into edges of a 3-graph until the edges */
+/* are independent.                                              */
+static int 
+tree_builder (int num, u_char ** keys, int *n)
+{
+
+  int e, k = 0;
+  int i, j;
+  u_char *w;
+
+  do
+    {
+      *n = (int) (num * c + 1);
+      /* initialize tables of random integers */
+      for (i = 0; i < MAX_CH; ++i)
+	for (j = 0; j < MAX_L; ++j)
+	  {
+#ifndef STRUCT
+	    tb0[i][j] = RANDOM () % *n;
+	    tb1[i][j] = RANDOM () % *n;
+	    tb2[i][j] = RANDOM () % *n;
+#else
+	    struct tb_entry *tbp = &tb[i][j];
+	    tbp->tb0 = RANDOM () % *n;
+	    tbp->tb1 = RANDOM () % *n;
+	    tbp->tb2 = RANDOM () % *n;
+#endif
+	  }
+
+      /* compute an edge (NODEa[e], NODEb[e], NODEc[e]) for each word */
+      for (e = 1; e <= num; ++e)
+	{
+	  /*generate an edge corresponding to the ith word */
+	  int x = 0, y = 0, z = 0, l;
+	  w = keys[e - 1];
+
+	  l = *w++;
+	  j = (l - 1) % MAX_L;
+
+	  do
+	    {
+#ifndef STRUCT
+	      x += tb0[translate[*w]][j];
+	      y += tb1[translate[*w]][j];
+	      z += tb2[translate[*w]][j];
+#else
+	      struct tb_entry *tbp = &tb[translate[*w]][j];
+	      x += tbp->tb0;
+	      y += tbp->tb1;
+	      z += tbp->tb2;
+#endif
+	      if (++j >= MAX_L)
+		j = 0;
+	      ++w;
+	    }
+	  while (--l);
+	  x = (x % *n) + 1;
+	  y = (y % *n) + 1;
+	  z = (z % *n) + 1;
+	  if (y == x && ++y > *n)
+	    y = 1;
+	  if (z == x && ++z > *n)
+	    z = 1;
+	  if (z == y)
+	    {
+	      if (++z > *n)
+		z = 1;
+	      if (z == x && ++z > *n)
+		z = 1;
+	    }
+
+	  NODEa[e] = x;
+	  NODEb[e] = y;
+	  NODEc[e] = z;
+	}
+      if (++k > 50)		/* make sure we will not wait for ever */
+	FatalError (1, "Unable to generate the perfect hash function. "
+		    "This is probably because there aren't enough words");
+    }
+  while (!acyclic (num, *n));
+  return k;
+}				/*tree_builder */
+
+
+
+
+
+
+
+
+
+/* calculates values of the g function/array so that i-th word is */
+/* placed at the (i-1)st position of a hash table.                */
+static void 
+assign (int n)
+{
+
+  int v, w = 0, e;
+
+  /* mark all the vertices of the 3-graph as unassigned */
+  for (v = 1; v <= n; mk[v++] = FALSE);
+
+  while (S.sp > 0)
+    {
+      int _xor = 0;
+      pop (S, e);
+      v = NODEa[e];
+      if (mk[v])
+	_xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      v = NODEb[e];
+      if (mk[v])
+	_xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      v = NODEc[e];
+      if (mk[v])
+	_xor ^= g[v];
+      else
+	{
+	  g[w = v] = 0;
+	  mk[v] = TRUE;
+	}
+      g[w] = (e - 1) ^ _xor;
+    }
+}				/*assign */
+
+
+
+
+
+
+
+
+
+/*check returns 0 if no error in mphf is detected, else returns error code */
+static int 
+check (int m)
+{
+
+  int e, err_code = 0;
+
+  /*for each word compute its place in hash table and check if correct */
+  for (e = 1; e <= m; ++e)
+    {
+      if ((e - 1) != (g[NODEa[e]] ^ g[NODEb[e]] ^ g[NODEc[e]]))
+	{
+	  (void) fprintf (stderr, "Error for %dth word detected.\n", e);
+	  err_code = e;
+	}
+    }
+  return err_code;
+}				/*check */
+
+
+
+
+
+
+
+#if 0
+void 
+outputh (int m, int n)
+{
+
+  int i, j, w = (int) ceil (log10 ((double) n + 1.0)) + 1;
+
+#if 0
+  char *PRG =
+  "int h(char *s)\n"
+  "{\n"
+  "  int u, v, w, i;\n"
+  "i = (strlen(s) - 1) % _HXL;\n"
+  "  u = v = w = 0;\n"
+  "  while(*s)\n"
+  "    {\n"
+  "      u += mt1[(*s) - _HFC][i];\n"
+  "      v += mt2[(*s) - _HFC][i];\n"
+  "      w += mt3[(*s++) - _HFC][i];\n"
+  "      if(++i >= _HXL) i = 0;\n"
+  "    }\n"
+  "  u %= _HFN; v %= _HFN; w %= _HFN;\n"
+  "  if(u == v && ++v >= _HFN) v = 0;\n"
+  "  if(w == u && ++w >= _HFN) w = 0;\n"
+  "  if(w == v && ++w >= _HFN) w = 0;\n"
+  "  if(w == u && ++w >= _HFN) w = 0;\n"
+  "  return (g[u] ^ g[v] ^ g[w]) % _HFM;\n"
+  "};\n\n";
+#endif
+
+  char *PRG =
+  "int h(char *s)\n"
+  "{\n"
+  "  int u, v, w, i;\n"
+  "  i = (strlen(s) - 1) % _HXL;\n"
+  "  u = v = w = 0;\n"
+  "  while(*s)\n"
+  "    {\n"
+  "      if((u += mt1[(*s) - _HFC][i]) >= _HFN) u -= _HFN;\n"
+  "      if((v += mt2[(*s) - _HFC][i]) >= _HFN) v -= _HFN;\n"
+  "      if((w += mt3[(*s++) - _HFC][i]) >= _HFN) w -= _HFN;\n"
+  "      if(++i >= _HXL) i = 0;\n"
+  "    }\n"
+  "  if(u == v && ++v >= _HFN) v = 0;\n"
+  "  if(w == v) \n"
+  "    {\n"
+  "      if(++w >= _HFN) w = 0;\n"
+  "      if(w == u && ++w >= _HFN) w = 0;\n"
+  "    }\n"
+  "  else\n"
+  "    if(w == u)\n"
+  "      {\n"
+  "	     if(++w >= _HFN) w = 0;\n"
+  "	     if(w == v && ++w >= _HFN) w = 0;\n"
+  "      }\n"
+  "  return ((g[u] ^ g[v] ^ g[w]) > _HFM)? 0 : (g[u] ^ g[v] ^ g[w]);\n"
+  "}\n\n";
+
+  printf ("#define _HFN %d\n#define _HFC %d\n", n, fc);
+  printf ("#define _HFM %d\n#define _HXL %d\n", m, MAX_L);
+  printf ("#define _HFA %d\n\nstatic int g[_HFN] = {\n", lc - fc + 1);
+  for (i = 1; i < n; ++i)
+    {
+      if (i % 8 == 0)
+	putchar ('\n');
+      printf ("%5d, ", g[i]);
+    }
+  printf ("%5d};\n\n", g[n]);
+
+  printf ("static int mt1[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; ++j)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; ++i)
+	printf ("%*d,", w, tb0[j][i]);
+      printf ("%*d},\n", w, tb0[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; ++i)
+    printf ("%*d,", w, tb0[lc][i]);
+  printf ("%*d}\n", w, tb0[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("static int mt2[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; ++j)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; ++i)
+	printf ("%*d,", w, tb1[j][i]);
+      printf ("%*d},\n", w, tb1[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; ++i)
+    printf ("%*d,", w, tb1[lc][i]);
+  printf ("%*d}\n", w, tb1[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("static int mt3[_HFA][_HXL] = {\n");
+  for (j = fc; j < lc; ++j)
+    {
+      printf ("{");
+      for (i = 0; i < MAX_L - 1; ++i)
+	printf ("%*d,", w, tb2[j][i]);
+      printf ("%*d},\n", w, tb2[j][MAX_L - 1]);
+    }
+  printf ("{");
+  for (i = 0; i < MAX_L - 1; ++i)
+    printf ("%*d,", w, tb2[lc][i]);
+  printf ("%*d}\n", w, tb2[lc][MAX_L - 1]);
+  printf ("};\n\n");
+
+  printf ("%s", PRG);
+}				/*outputh */
+#endif
+
+
+
+
+
+
+
+static void 
+make_trans_func (int num, u_char ** keys)
+{
+  int i, j;
+
+  memset (translate, '\0', sizeof (translate));
+
+  MAX_L = 1;
+  for (i = 0; i < num; ++i)
+    {
+      unsigned len = keys[i][0];
+      u_char *s = keys[i] + 1;
+      for (; len; --len, ++s)
+	translate[*s] = 1;
+      if (i)
+	{
+	  int l;
+	  l = prefixlen (keys[i - 1], keys[i]);
+	  if (l + 1 > MAX_L)
+	    MAX_L = l + 1;
+	}
+    }
+  j = 0;
+  for (i = 0; i < 256; ++i)
+    if (translate[i])
+      translate[i] = j++;
+  MAX_CH = j;
+}
+
+
+static void 
+temp_free (void)
+{
+  if (NODEa)
+    Xfree (NODEa);
+  if (NODEb)
+    Xfree (NODEb);
+  if (NODEc)
+    Xfree (NODEc);
+  if (FIRST)
+    Xfree (FIRST);
+  if (NEXT)
+    Xfree (NEXT);
+  if (S.st)
+    Xfree (S.st);
+  if (mk)
+    Xfree (mk);
+}
+
+static void 
+all_free (void)
+{
+  int i;
+  temp_free ();
+  if (translate)
+    Xfree (translate);
+  if (g)
+    Xfree (g);
+#ifndef STRUCT
+  for (i = 0; i < MAX_CH; ++i)
+    {
+      if (tb0 && tb0[i])
+	Xfree (tb0[i]);
+      if (tb1 && tb1[i])
+	Xfree (tb1[i]);
+      if (tb2 && tb2[i])
+	Xfree (tb2[i]);
+    }
+  if (tb0)
+    Xfree (tb0);
+  if (tb1)
+    Xfree (tb1);
+  if (tb2)
+    Xfree (tb2);
+#else
+  for (i = 0; i < MAX_CH; ++i)
+    if (tb && tb[i])
+      Xfree (tb[i]);
+  if (tb)
+    Xfree (tb);
+#endif
+}
+
+static int 
+allocate_memory (void)
+{
+  int i, ok = 1;
+  NODEa = (int *) Xmalloc (sizeof (int) * (MAX_M + 1));
+  NODEb = (int *)Xmalloc (sizeof (int) * (MAX_M + 1));
+  NODEc = (int *)Xmalloc (sizeof (int) * (MAX_M + 1));
+  FIRST = (int *)Xmalloc (sizeof (int) * (MAX_N + 1));
+  NEXT = (int *)Xmalloc (sizeof (int) * (MAX_M + 1) * 3);
+  S.st = (int *)Xmalloc (sizeof (int) * MAX_M);
+  mk = (char *)Xmalloc (sizeof (char) * (MAX_N + 1));
+  g = (int *)Xmalloc (sizeof (int) * (MAX_N + 1));
+#ifndef STRUCT
+  tb0 = Xmalloc (sizeof (int *) * MAX_CH);
+  tb1 = Xmalloc (sizeof (int *) * MAX_CH);
+  tb2 = Xmalloc (sizeof (int *) * MAX_CH);
+  for (i = 0; i < MAX_CH; ++i)
+    {
+      if (tb0)
+	if (!(tb0[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+      if (tb1)
+	if (!(tb1[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+      if (tb2)
+	if (!(tb2[i] = Xmalloc (sizeof (long) * MAX_L)))
+	    ok = 0;
+    }
+
+  if (!(NODEa && NODEb && NODEc && FIRST && NEXT && S.st && mk && g &&
+	tb0 && tb1 && tb2 && ok))
+    {
+      all_free ();
+      return (-1);
+    }
+#else
+  tb = (tb_entry **)Xmalloc (sizeof (struct tb_entry *) * MAX_CH);
+  for (i = 0; i < MAX_CH; ++i)
+    if (tb)
+      if (!(tb[i] = (tb_entry *)Xmalloc (sizeof (struct tb_entry) * MAX_L)))
+	  ok = 0;
+
+  if (!(NODEa && NODEb && NODEc && FIRST && NEXT && S.st && mk && g &&
+	tb && ok))
+    {
+      all_free ();
+      return (-1);
+    }
+#endif
+  return (0);
+}
+
+
+perf_hash_data *
+gen_hash_func (int num, u_char ** keys, int r)
+{
+  int n;
+  perf_hash_data *phd;
+  translate = (u_char *)Xmalloc (sizeof (u_char) * 256);
+  memset(translate, '\0', sizeof (u_char) * 256);  /* [RPAP - Feb 97: WIN32 Port] */
+  make_trans_func (num, keys);
+
+  if (r <= 0)
+    SEED_RANDOM ((long) time ((time_t *) NULL));
+  else
+    SEED_RANDOM (r);
+
+  MAX_M = num + 1;
+
+  MAX_N = MAX_M + MAX_M / 4;
+
+  if (allocate_memory () == -1)
+    return (NULL);
+
+  /* construct an "acyclic" hypergraph */
+  tree_builder (num, keys, &n);
+  /* compute function g */
+  assign (n);
+
+  if (check (num) != 0)
+    FatalError (1, "An error has been detected in the mphf.");
+  temp_free ();
+
+  if (!(phd = (perf_hash_data *)Xmalloc (sizeof (perf_hash_data))))
+    return (NULL);
+
+  memcpy ((void *) g, (const void *) &g[1], n * sizeof (int));
+
+  phd->MAX_L = MAX_L;
+  phd->MAX_N = n;
+  phd->MAX_M = num;
+  phd->MAX_CH = MAX_CH;
+  phd->translate = translate;
+  phd->g = g;
+#ifndef STRUCT
+  phd->tb0 = tb0;
+  phd->tb1 = tb1;
+  phd->tb2 = tb2;
+#else
+  phd->tb = tb;
+#endif
+  return (phd);
+}
+
+int 
+write_perf_hash_data (FILE * f, perf_hash_data * phd)
+{
+  int tot, i;
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONSI(phd->MAX_L);
+  HTONSI(phd->MAX_N);
+  HTONSI(phd->MAX_M);
+  HTONSI(phd->MAX_CH);
+
+  tot = fwrite ((char *) &phd->MAX_L, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_N, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_M, sizeof (int), 1, f) * sizeof (int);
+  tot += fwrite ((char *) &phd->MAX_CH, sizeof (int), 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(phd->MAX_L);
+  NTOHSI(phd->MAX_N);
+  NTOHSI(phd->MAX_M);
+  NTOHSI(phd->MAX_CH);
+
+  tot += fwrite ((char *) phd->translate, sizeof (u_char), 256, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; ++i)
+    HTONSI(phd->g[i]);
+
+  tot += fwrite ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; ++i)
+    NTOHSI(phd->g[i]);
+
+#ifndef STRUCT
+  for (i = 0; i < phd->MAX_CH; ++i)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int j;
+      for (j = 0; j < phd->MAX_L; ++j)
+	{
+	  HTONSI(phd->tb0[i][j]);
+	  HTONSI(phd->tb1[i][j]);
+	  HTONSI(phd->tb2[i][j]);
+	}
+
+      tot += fwrite ((char *) phd->tb0[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fwrite ((char *) phd->tb1[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fwrite ((char *) phd->tb2[i], sizeof (int), phd->MAX_L, f) *
+        sizeof (int);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; ++j)
+	{
+	  NTOHSI(phd->tb0[i][j]);
+	  NTOHSI(phd->tb1[i][j]);
+	  NTOHSI(phd->tb2[i][j]);
+	}
+    }
+#else
+  for (i = 0; i < phd->MAX_CH; ++i)
+    {
+      /* [RPAP - Jan 97: Endian Ordering] */
+      int j;
+      for (j = 0; j < phd->MAX_L; ++j)
+	{
+	  HTONSL(phd->tb[i][j].tb0);
+	  HTONSL(phd->tb[i][j].tb1);
+	  HTONSL(phd->tb[i][j].tb2);
+	}
+
+      tot += fwrite ((char *) phd->tb[i], sizeof (struct tb_entry), phd->MAX_L, f) *
+	sizeof (struct tb_entry);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; ++j)
+	{
+	  NTOHSL(phd->tb[i][j].tb0);
+	  NTOHSL(phd->tb[i][j].tb1);
+	  NTOHSL(phd->tb[i][j].tb2);
+	}
+    }
+#endif
+  return (tot);
+}
+
+
+perf_hash_data *
+read_perf_hash_data (FILE * f)
+{
+  perf_hash_data *phd;
+  int i, tot, ok = 1;
+  if (!(phd = (perf_hash_data *)Xmalloc (sizeof (perf_hash_data))))
+    return (NULL);
+  tot = fread ((char *) &phd->MAX_L, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_N, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_M, sizeof (int), 1, f) * sizeof (int);
+  tot += fread ((char *) &phd->MAX_CH, sizeof (int), 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHSI(phd->MAX_L);
+  NTOHSI(phd->MAX_N);
+  NTOHSI(phd->MAX_M);
+  NTOHSI(phd->MAX_CH);
+
+  if (tot != 4 * sizeof (int))
+      return (NULL);
+  phd->translate = (u_char *)Xmalloc (sizeof (u_char) * 256);
+  phd->g = (int *)Xmalloc (sizeof (int) * (phd->MAX_N + 1));
+#ifndef STRUCT
+  phd->tb0 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  phd->tb1 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  phd->tb2 = Xmalloc (sizeof (int *) * phd->MAX_CH);
+  for (i = 0; i < phd->MAX_CH; ++i)
+    {
+      if (phd->tb0)
+	if (!(phd->tb0[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+      if (phd->tb1)
+	if (!(phd->tb1[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+      if (phd->tb2)
+	if (!(phd->tb2[i] = Xmalloc (sizeof (long) * phd->MAX_L)))
+	    ok = 0;
+    }
+  if (!(phd->translate && phd->g && phd->tb0 && phd->tb1 && phd->tb2 && ok))
+    {
+      if (phd->translate)
+	Xfree (phd->translate);
+      if (phd->g)
+	Xfree (phd->g);
+      for (i = 0; i < MAX_CH; ++i)
+	{
+	  if (phd->tb0 && phd->tb0[i])
+	    Xfree (phd->tb0[i]);
+	  if (phd->tb1 && phd->tb1[i])
+	    Xfree (phd->tb1[i]);
+	  if (phd->tb2 && phd->tb2[i])
+	    Xfree (phd->tb2[i]);
+	}
+      if (phd->tb0)
+	Xfree (phd->tb0);
+      if (phd->tb1)
+	Xfree (phd->tb1);
+      if (phd->tb2)
+	Xfree (phd->tb2);
+      Xfree (phd);
+      return (NULL);
+    }
+  tot += fread ((char *) phd->translate, sizeof (u_char), 256, f);
+  tot += fread ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; ++i)
+    NTOHSI(phd->g[i]);
+
+  for (i = 0; i < phd->MAX_CH; ++i)
+    {
+      int j;
+
+      tot += fread ((char *) phd->tb0[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fread ((char *) phd->tb1[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+      tot += fread ((char *) phd->tb2[i], sizeof (long), phd->MAX_L, f) *
+        sizeof (int);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; ++j)
+	{
+	  NTOHSI(phd->tb0[i][j]);
+	  NTOHSI(phd->tb1[i][j]);
+	  NTOHSI(phd->tb2[i][j]);
+	}
+    }
+#else
+  phd->tb = (struct tb_entry **)Xmalloc (sizeof (struct tb_entry *) * phd->MAX_CH);
+  for (i = 0; i < phd->MAX_CH; ++i)
+    if (phd->tb)
+      if (!(phd->tb[i] = (struct tb_entry *)Xmalloc (sizeof (struct tb_entry) * phd->MAX_L)))
+	  ok = 0;
+  if (!(phd->translate && phd->g && phd->tb && ok))
+    {
+      if (phd->translate)
+	Xfree (phd->translate);
+      if (phd->g)
+	Xfree (phd->g);
+      for (i = 0; i < MAX_CH; ++i)
+	if (phd->tb && phd->tb[i])
+	  Xfree (phd->tb[i]);
+      if (phd->tb)
+	Xfree (phd->tb);
+      Xfree (phd);
+      return (NULL);
+    }
+  tot += fread ((char *) phd->translate, sizeof (u_char), 256, f);
+  tot += fread ((char *) phd->g, sizeof (int), phd->MAX_N + 1, f) * sizeof (int);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = 0; i < phd->MAX_N + 1; ++i)
+    NTOHSI(phd->g[i]);
+
+  for (i = 0; i < phd->MAX_CH; ++i)
+    {
+      int j;
+
+      tot += fread ((char *) phd->tb[i], sizeof (struct tb_entry), phd->MAX_L, f) *
+	sizeof (struct tb_entry);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      for (j = 0; j < phd->MAX_L; ++j)
+	{
+	  NTOHSL(phd->tb[i][j].tb0);
+	  NTOHSL(phd->tb[i][j].tb1);
+	  NTOHSL(phd->tb[i][j].tb2);
+	}
+    }
+#endif
+  return (phd);
+}
+
+void 
+free_perf_hash (perf_hash_data * phd)
+{
+  int i;
+  if (phd->translate)
+    Xfree (phd->translate);
+  if (phd->g)
+    Xfree (phd->g);
+  for (i = 0; i < phd->MAX_CH; ++i)
+    if (phd->tb && phd->tb[i])
+      Xfree (phd->tb[i]);
+  if (phd->tb)
+    Xfree (phd->tb);
+  Xfree (phd);
+}
+
+
+int 
+perf_hash (perf_hash_data * phd, u_char * s)
+{
+  int u, v, w, i, l;
+  l = *s++;
+  i = (l - 1) % phd->MAX_L;
+  u = v = w = 0;
+  while (l)
+    {
+#ifndef STRUCT
+      if ((u += phd->tb0[phd->translate[*s]][i]) >= phd->MAX_N)
+	u -= phd->MAX_N;
+      if ((v += phd->tb1[phd->translate[*s]][i]) >= phd->MAX_N)
+	v -= phd->MAX_N;
+      if ((w += phd->tb2[phd->translate[*s]][i]) >= phd->MAX_N)
+	w -= phd->MAX_N;
+#else
+      struct tb_entry *tbp = &phd->tb[phd->translate[*s]][i];
+      if ((u += tbp->tb0) >= phd->MAX_N)
+	u -= phd->MAX_N;
+      if ((v += tbp->tb1) >= phd->MAX_N)
+	v -= phd->MAX_N;
+      if ((w += tbp->tb2) >= phd->MAX_N)
+	w -= phd->MAX_N;
+#endif
+      if (++i >= phd->MAX_L)
+	i = 0;
+      --l;
+      ++s;
+    }
+  if (u == v && ++v >= phd->MAX_N)
+    v = 0;
+  if (w == v)
+    {
+      if (++w >= phd->MAX_N)
+	w = 0;
+      if (w == u && ++w >= phd->MAX_N)
+	w = 0;
+    }
+  else if (w == u)
+    {
+      if (++w >= phd->MAX_N)
+	w = 0;
+      if (w == v && ++w >= phd->MAX_N)
+	w = 0;
+    }
+  return ((phd->g[u] ^ phd->g[v] ^ phd->g[w]) > phd->MAX_M) ? 0 :
+    (phd->g[u] ^ phd->g[v] ^ phd->g[w]);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/perf_hash.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/perf_hash.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/perf_hash.h	(revision 10506)
@@ -0,0 +1,52 @@
+/**************************************************************************
+ *
+ * perf_hash.h -- Perfect hashing functions
+ * Copyright (C) 1994  Bohdan S. Majewski and Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef H_PERF_HASH
+#define H_PERF_HASH
+
+struct tb_entry
+  {
+    long tb0, tb1, tb2;
+  };
+
+typedef struct
+  {
+    int MAX_L;
+    int MAX_N;
+    int MAX_M;
+    int MAX_CH;
+    u_char *translate;
+    int *g;
+    struct tb_entry **tb;
+  }
+perf_hash_data;
+
+perf_hash_data *gen_hash_func (int num, u_char ** keys, int r);
+
+int perf_hash (perf_hash_data * phd, u_char * s);
+
+int write_perf_hash_data (FILE * f, perf_hash_data * phd);
+
+void free_perf_hash (perf_hash_data * phd);
+
+perf_hash_data *read_perf_hash_data (FILE * f);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/random.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/random.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/random.cpp	(revision 10506)
@@ -0,0 +1,211 @@
+/**************************************************************************
+ *
+ * random.c -- pseudo random number generator
+ * Copyright (C) 1994  Chris Wallace (csw@bruce.cs.monash.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+/*
+ *	A random number generator called as a function by
+ *	random (iseed)	or	irandm (iseed)
+ *	The parameter should be a pointer to a 2-element long vector.
+ *	The first function returns a double uniform in 0 .. 1.
+ *	The second returns a long integer uniform in 0 .. 2**31-1
+ *	Both update iseed[] in exactly the same way.
+ *	iseed[] must be a 2-element integer vector.
+ *	The initial value of the second element may be anything.
+ *
+ *	The period of the random sequence is 2**32 * (2**32-1)
+ *	The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
+ */
+
+#define MASK ((long) 593970775)
+/*	or in hex, 23674657	*/
+
+#define SCALE ((double) 1.0 / (1024.0 * 1024.0 * 1024.0 * 2.0))
+/*	i.e. 2 to power -31	*/
+
+static long mt [128] =   {
+      902906369,
+     2030498053,
+     -473499623,
+     1640834941,
+      723406961,
+     1993558325,
+     -257162999,
+    -1627724755,
+      913952737,
+      278845029,
+     1327502073,
+    -1261253155,
+      981676113,
+    -1785280363,
+     1700077033,
+      366908557,
+    -1514479167,
+     -682799163,
+      141955545,
+     -830150595,
+      317871153,
+     1542036469,
+     -946413879,
+    -1950779155,
+      985397153,
+      626515237,
+      530871481,
+      783087261,
+    -1512358895,
+     1031357269,
+    -2007710807,
+    -1652747955,
+    -1867214463,
+      928251525,
+     1243003801,
+    -2132510467,
+     1874683889,
+     -717013323,
+      218254473,
+    -1628774995,
+    -2064896159,
+       69678053,
+      281568889,
+    -2104168611,
+     -165128239,
+     1536495125,
+      -39650967,
+      546594317,
+     -725987007,
+     1392966981,
+     1044706649,
+      687331773,
+    -2051306575,
+     1544302965,
+     -758494647,
+    -1243934099,
+      -75073759,
+      293132965,
+    -1935153095,
+      118929437,
+      807830417,
+    -1416222507,
+    -1550074071,
+      -84903219,
+     1355292929,
+     -380482555,
+    -1818444007,
+     -204797315,
+      170442609,
+    -1636797387,
+      868931593,
+     -623503571,
+     1711722209,
+      381210981,
+     -161547783,
+     -272740131,
+    -1450066095,
+     2116588437,
+     1100682473,
+      358442893,
+    -1529216831,
+     2116152005,
+     -776333095,
+     1265240893,
+     -482278607,
+     1067190005,
+      333444553,
+       86502381,
+      753481377,
+       39000101,
+     1779014585,
+      219658653,
+     -920253679,
+     2029538901,
+     1207761577,
+    -1515772851,
+     -236195711,
+      442620293,
+      423166617,
+    -1763648515,
+     -398436623,
+    -1749358155,
+     -538598519,
+     -652439379,
+      430550625,
+    -1481396507,
+     2093206905,
+    -1934691747,
+     -962631983,
+     1454463253,
+    -1877118871,
+     -291917555,
+    -1711673279,
+      201201733,
+     -474645415,
+      -96764739,
+    -1587365199,
+     1945705589,
+     1303896393,
+     1744831853,
+      381957665,
+     2135332261,
+      -55996615,
+    -1190135011,
+     1790562961,
+    -1493191723,
+      475559465,
+          69069
+		};
+
+double 
+random (long is [2])
+{
+	long it, leh, nit;
+
+	it = is [0];
+	leh = is [1];
+	if (it <= 0)	
+		it = (it + it) ^ MASK;
+	else
+		it = it + it;
+	nit = it - 1;
+/*	to ensure all-ones pattern omitted    */
+	leh = leh * mt[nit & 127] + nit;
+	is [0] = it;    is [1] = leh;
+	if (leh < 0) leh = ~leh;
+	return (SCALE * ((long) (leh | 1)));
+}
+
+
+
+long 
+irandm (long is [2])
+{
+	long it, leh, nit;
+
+	it = is [0];
+	leh = is [1];
+	if (it <= 0)	
+		it = (it + it) ^ MASK;
+	else
+		it = it + it;
+	nit = it - 1;
+/*	to ensure all-ones pattern omitted    */
+	leh = leh * mt[nit & 127] + nit;
+	is [0] = it;    is [1] = leh;
+	if (leh < 0) leh = ~leh;
+	return (leh);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/random.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/random.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/random.h	(revision 10506)
@@ -0,0 +1,42 @@
+/**************************************************************************
+ *
+ * random.h -- pseudo random number generator
+ * Copyright (C) 1994  Chris Wallace (csw@bruce.cs.monash.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+/*
+ *	A random number generator called as a function by
+ *	random (iseed)	or	irandm (iseed)
+ *	The parameter should be a pointer to a 2-element long vector.
+ *	The first function returns a double uniform in 0 .. 1.
+ *	The second returns a long integer uniform in 0 .. 2**31-1
+ *	Both update iseed[] in exactly the same way.
+ *	iseed[] must be a 2-element integer vector.
+ *	The initial value of the second element may be anything.
+ *
+ *	The period of the random sequence is 2**32 * (2**32-1)
+ *	The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
+ */
+
+double random (long is [2]);
+long irandm (long is [2]);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/simplefrenchstem.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/simplefrenchstem.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/simplefrenchstem.cpp	(revision 10506)
@@ -0,0 +1,70 @@
+/**************************************************************************
+ *
+ * simplefrenchstem.c -- a simple french stemmer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "simplefrenchstem.h"
+#include "unitool.h"
+
+
+/* =========================================================================
+ * Function: simplefrenchstem
+ * Description: a simple french stemmer
+ * Input: a word string with the length in the first byte
+ * Output: the stemmed word
+ * ========================================================================= */
+
+void simplefrenchstem (unsigned char *word) {      
+  unsigned short out[256]; /* temp space */
+  unsigned short *wordstart; /* points to first letter of word */
+  int last;                  /* last points to the last character */
+
+  /* decode */
+  utf8_word_to_unicode (word, out, 255);
+  wordstart = out + 1;
+  last = out[0]-1;
+  
+
+  if (last > 4) {
+    if (wordstart[last]=='x') {
+      if (wordstart[last-1]=='u' && wordstart[last-2]=='a') {
+	wordstart[last-1]='l';
+      }
+      --last;
+
+    } else {
+      if (last>=0 && wordstart[last]=='s') --last;
+      if (last>=0 && wordstart[last]=='r') --last;
+      if (last>=0 && wordstart[last]=='e') --last;
+
+      /* letter with accent e + ' -- there are two possible encodings  */
+      if (last>=0 && wordstart[last]==0xe9) { 
+	--last;
+      } else if (last>=1 && wordstart[last-1]=='e' && wordstart[last]==0x301) {
+	last -= 2; 
+      }
+
+      if (last >= 1 && wordstart[last]==wordstart[last-1]) --last;
+    }  /* end else */
+
+    out[0] = (unsigned char)(last+1);
+  } /* end if (len > 4) */
+
+  /* re-code, make sure the result is not longer than the input */
+  unicode_to_utf8_word (out, word, word[0]+1);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/simplefrenchstem.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/simplefrenchstem.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/simplefrenchstem.h	(revision 10506)
@@ -0,0 +1,26 @@
+/**************************************************************************
+ *
+ * simplefrenchstem.h -- a simple french stemmer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef SIMPLEFRENCHSTEM_H
+#define SIMPLEFRENCHSTEM_H
+
+void simplefrenchstem (unsigned char *word);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/strcasecmp.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/strcasecmp.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/strcasecmp.cpp	(revision 10506)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific written prior permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strcasecmp.c	5.5 (Berkeley) 11/24/87";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char charmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+int
+strcasecmp(char *s1, char *s2)
+{
+    register unsigned char u1, u2;
+
+    for (;;) {
+	u1 = (unsigned char) *s1++;
+	u2 = (unsigned char) *s2++;
+	if (charmap[u1] != charmap[u2]) {
+	    return charmap[u1] - charmap[u2];
+	}
+	if (u1 == '\0') {
+	    return 0;
+	}
+    }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/strstr.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/strstr.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/strstr.cpp	(revision 10506)
@@ -0,0 +1,42 @@
+/* strstr.c -- return the offset of one string within another
+   Copyright (C) 1989, 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Written by Mike Rendell <michael@cs.mun.ca>.  */
+
+/* Return the starting address of string S2 in S1;
+   return 0 if it is not found. */
+
+char *
+strstr (char *s1, char *s2)
+{
+  int i;
+  char *p1;
+  char *p2;
+  char *s = s1;
+
+  for (p2 = s2, i = 0; *s; p2 = s2, ++i, ++s)
+    {
+      for (p1 = s; *p1 && *p2 && *p1 == *p2; ++p1, ++p2)
+	;
+      if (!*p2)
+	break;
+    }
+  if (!*p2)
+    return s1 + i;
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/sysfuncs.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/sysfuncs.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/sysfuncs.cpp	(revision 10506)
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+void *bcopy(void *s, void *d, int n)
+{ return memcpy(d, s, n);
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/sysfuncs.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/sysfuncs.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/sysfuncs.h	(revision 10506)
@@ -0,0 +1,388 @@
+/* System dependent definitions for GNU tar.
+   Copyright (C) 1994 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * [TS:Aug/95]
+ * Based on code from system.h file in GNU's tar package 
+ *
+ */
+
+#ifndef SYSFUNCS_H
+#define SYSFUNCS_H
+
+#include <sys/stat.h>
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__
+#  include <WIN32cfg.h>
+# else
+#  include <config.h>
+# endif
+#endif
+
+/* Declare alloca.  AIX requires this to be the first thing in the file.  */
+
+#ifdef __GNUC__
+#ifndef alloca
+#define alloca __builtin_alloca
+#endif
+#else
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+#pragma alloca
+#else
+#ifndef alloca
+char *alloca ();
+#endif
+#endif
+#endif
+#endif
+
+#include <sys/types.h>
+
+/* ------------------------------------------------- */
+/* [TS:Aug/95]
+ * Some extra include files that mg needs
+ */
+#include <stdlib.h>
+#include <math.h>
+
+#ifndef log2
+# ifndef M_LN2
+#  define M_LN2 0.69314718055994530942
+# endif
+# define log2(x) (log(x)/M_LN2)
+#endif
+
+
+#ifndef HAVE_SETBUFFER
+#ifdef __CYGWIN__ 
+/* Cygwin has setbuffer in stdio.h, but can't link against it!! */
+#include <stdio.h>
+#endif
+# define setbuffer(f, b, s)  setvbuf(f, b, _IOFBF, s)
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#if defined(__MSDOS__)  && !defined(__WIN32__)
+# define SHORT_SUFFIX 1
+#endif
+
+
+
+#include <assert.h>
+
+/* ------------------------------------------------- */
+
+/* Declare a generic pointer type.  */
+#if __STDC__ || defined(__TURBOC__)
+#define voidstar void *
+#else
+#define voidstar char *
+#endif
+
+/* Declare ISASCII.  */
+
+#include <ctype.h>
+
+#if STDC_HEADERS
+#define ISASCII(Char) 1
+#else
+#ifdef isascii
+#define ISASCII(Char) isascii (Char)
+#else
+#if HAVE_ISASCII
+#define ISASCII(Char) isascii (Char)
+#else
+#define ISASCII(Char) 1
+#endif
+#endif
+#endif
+
+
+/* ------------------------------------------------- */
+/* [TS:Aug/95] 
+ * The following is copied from GNU Autoconf.Info (1.1)   
+ * It sets up the approriate string and memory functions.
+ */
+
+#if STDC_HEADERS || HAVE_STRING_H
+#include <string.h>
+   /* An ANSI string.h and pre-ANSI memory.h might conflict */
+#if !STDC_HEADERS && HAVE_MEMORY_H
+#include <memory.h>
+#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
+#ifndef index
+/*#define index strchr 
+ *
+ * this is stuffing up our code so its commented out */
+#endif
+#ifndef rindex
+#define rindex strrchr
+#endif
+
+#ifdef __cplusplus /* compiling for C++ */
+#include <stdlib.h>
+#ifndef __bcopy
+inline void *bcopy(void *s, void *d, int n)
+{ return memcpy(d, s, n);
+}
+#define __bcopy 1
+#endif
+#ifndef __bcmp
+inline int bcmp(void *s1, void *s2, int n)
+{ return memcmp(s1, s2, n);
+}
+#define __bcmp 1
+#endif
+#ifndef __bzero
+inline void bzero(void *m, int n)
+{ memset(m, 0, n);
+}
+#define __bzero 1
+#endif
+#else              /* compiling for C */
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy((d), (s), (n))
+#endif
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n) memset((s), 0, (n))
+#endif
+#endif
+
+#else /* not STDC_HEADERS and not HAVE_STRING_H */
+#include <strings.h>
+   /* memory.h and strings.h conflict on some systems */
+#endif
+/* ------------------------------------------------- */
+
+
+/* Declare errno.  */
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+/* Declare open parameters.  */
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#else
+#include <sys/file.h>
+#endif
+
+#ifndef	O_BINARY
+#define O_BINARY 0
+#endif
+#ifndef O_CREAT
+#define O_CREAT 0
+#endif
+#ifndef	O_NDELAY
+#define O_NDELAY 0
+#endif
+#ifndef	O_RDONLY
+#define O_RDONLY 0
+#endif
+#ifndef O_RDWR
+#define O_RDWR 2
+#endif
+
+/* Declare file status routines and bits.  */
+
+#ifdef STAT_MACROS_BROKEN
+#undef S_ISBLK
+#undef S_ISCHR
+#undef S_ISDIR
+#undef S_ISFIFO
+#undef S_ISLNK
+#undef S_ISMPB
+#undef S_ISMPC
+#undef S_ISNWK
+#undef S_ISREG
+#undef S_ISSOCK
+#endif
+
+/* On MSDOS, there are missing things from <sys/stat.h>.  */
+#ifdef __MSDOS__
+#define S_ISUID 0
+#define S_ISGID 0
+#define S_ISVTX 0
+#endif
+
+#ifndef S_ISREG			/* POSIX.1 stat stuff missing */
+#define mode_t unsigned short
+#endif
+#if !defined(S_ISBLK) && defined(S_IFBLK)
+#define S_ISBLK(Mode) (((Mode) & S_IFMT) == S_IFBLK)
+#endif
+#if !defined(S_ISCHR) && defined(S_IFCHR)
+#define S_ISCHR(Mode) (((Mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(Mode) (((Mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG) && defined(S_IFREG)
+#define S_ISREG(Mode) (((Mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISFIFO) && defined(S_IFIFO)
+#define S_ISFIFO(Mode) (((Mode) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(Mode) (((Mode) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK) && defined(S_IFSOCK)
+#define S_ISSOCK(Mode) (((Mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISMPB) && defined(S_IFMPB)	/* V7 */
+#define S_ISMPB(Mode) (((Mode) & S_IFMT) == S_IFMPB)
+#define S_ISMPC(Mode) (((Mode) & S_IFMT) == S_IFMPC)
+#endif
+#if !defined(S_ISNWK) && defined(S_IFNWK)	/* HP/UX */
+#define S_ISNWK(Mode) (((Mode) & S_IFMT) == S_IFNWK)
+#endif
+
+#if !defined(S_ISCTG) && defined(S_IFCTG)	/* contiguous file */
+#define S_ISCTG(Mode) (((Mode) & S_IFMT) == S_IFCTG)
+#endif
+#if !defined(S_ISVTX)
+#define S_ISVTX 0001000
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#if !defined(_POSIX_SOURCE) && !defined(__WIN32__)
+#include <sys/param.h>
+#endif
+
+/* Include <unistd.h> before any preprocessor test of _POSIX_VERSION.  */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+/* Declare standard functions.  */
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+voidstar malloc ();
+voidstar realloc ();
+char *getenv ();
+#endif
+
+#include <stdio.h>
+
+#ifndef _POSIX_VERSION
+#ifdef __MSDOS__
+#include <io.h>
+#else
+off_t lseek ();
+#endif
+#endif
+
+#ifndef __WIN32__
+#include <pathmax.h>
+#endif
+
+/* Until getoptold function is declared in getopt.h, we need this here for
+   struct option.  */
+/*#include <getopt.h>*/
+
+#ifdef WITH_DMALLOC
+#undef HAVE_VALLOC
+#define DMALLOC_FUNC_CHECK
+#include <dmalloc.h>
+#endif
+
+/* Prototypes for external functions.  */
+
+#ifndef __P
+#if PROTOTYPES
+#define __P(Args) Args
+#else
+#define __P(Args) ()
+#endif
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+/*** setlocale is ansi and posix...(jrm21)
+#if !HAVE_SETLOCALE
+#define setlocale(Category, Locale)
+#endif
+***/
+
+#if ENABLE_NLS
+#include <libintl.h>
+#define _(Text) gettext (Text)
+#else
+#define textdomain(Domain)
+#define _(Text) Text
+#endif
+
+/* Library modules.  */
+
+#ifdef HAVE_VPRINTF
+void error __P ((int, int, const char *,...));
+#else
+void error ();
+#endif
+
+#ifndef HAVE_STRSTR
+char *strstr __P ((const char *, const char *));
+#endif
+
+/* [RB/TS:Oct/95] commented out. Used by lib/gmalloc.c - but it defines it anyway ???
+ *#ifndef HAVE_VALLOC
+ *#define valloc(Size) malloc (Size)
+ *#endif
+ */
+
+voidstar xmalloc __P ((size_t));
+voidstar xrealloc __P ((voidstar, size_t));
+char *xstrdup __P ((const char *));
+
+/* [TS:Aug/95] 
+ * These were required by files which referred 
+ * to these as function pointers. 
+ * e.g. huffman.c - fread,  mgfelics.c - fgetc
+ */
+#ifndef HAVE_FREAD_DECL
+extern size_t   fread __P ((void *, size_t, size_t, FILE *));
+#endif
+#ifndef HAVE_FGETC_DECL
+extern int      fgetc __P ((FILE *));
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifndef u_long
+# define u_long unsigned long
+#endif
+#ifndef u_char
+# define u_char unsigned char
+#endif
+
+
+#endif /* SYSFUNCS_H */
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/unitool.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/unitool.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/unitool.cpp	(revision 10506)
@@ -0,0 +1,1756 @@
+#include "unitool.h"
+#include "sysfuncs.h"
+
+
+/* unicode_cat_data is a combination of the letter, digit, and
+ * space information in a form that is quick to look up.
+ * The information about each byte is stored in two bits
+ *
+ * 00 - neither letter, digit or space
+ * 01 - letter
+ * 10 - space
+ * 11 - digit
+ *
+ * You can test for letter | space by looking at the right
+ * column
+ */
+unsigned long *unicode_cat_data=NULL;
+
+
+typedef struct unidecompose {
+  unsigned short ch;
+  unsigned short str[3];
+} unidecompose;
+
+typedef struct unirelate {
+  unsigned short ch1;
+  unsigned short ch2;
+} unirelate;
+
+typedef struct unirange {
+  unsigned short first;
+  unsigned short last;
+} unirange;
+
+
+
+/* This decomposition data only includes canonical decompositional
+ * characters.  Any unused bytes are set to 0x0. */
+
+#define NUM_DECOMPOSE_INFO 1269
+static const unidecompose decompose_info[NUM_DECOMPOSE_INFO] = {
+  {0xC0,0x41,0x300,0x0}, {0xC1,0x41,0x301,0x0}, {0xC2,0x41,0x302,0x0}, 
+  {0xC3,0x41,0x303,0x0}, {0xC4,0x41,0x308,0x0}, {0xC5,0x41,0x30A,0x0}, 
+  {0xC7,0x43,0x327,0x0}, {0xC8,0x45,0x300,0x0}, {0xC9,0x45,0x301,0x0}, 
+  {0xCA,0x45,0x302,0x0}, {0xCB,0x45,0x308,0x0}, {0xCC,0x49,0x300,0x0}, 
+  {0xCD,0x49,0x301,0x0}, {0xCE,0x49,0x302,0x0}, {0xCF,0x49,0x308,0x0}, 
+  {0xD1,0x4E,0x303,0x0}, {0xD2,0x4F,0x300,0x0}, {0xD3,0x4F,0x301,0x0}, 
+  {0xD4,0x4F,0x302,0x0}, {0xD5,0x4F,0x303,0x0}, {0xD6,0x4F,0x308,0x0}, 
+  {0xD9,0x55,0x300,0x0}, {0xDA,0x55,0x301,0x0}, {0xDB,0x55,0x302,0x0}, 
+  {0xDC,0x55,0x308,0x0}, {0xDD,0x59,0x301,0x0}, {0xE0,0x61,0x300,0x0}, 
+  {0xE1,0x61,0x301,0x0}, {0xE2,0x61,0x302,0x0}, {0xE3,0x61,0x303,0x0}, 
+  {0xE4,0x61,0x308,0x0}, {0xE5,0x61,0x30A,0x0}, {0xE7,0x63,0x327,0x0}, 
+  {0xE8,0x65,0x300,0x0}, {0xE9,0x65,0x301,0x0}, {0xEA,0x65,0x302,0x0}, 
+  {0xEB,0x65,0x308,0x0}, {0xEC,0x69,0x300,0x0}, {0xED,0x69,0x301,0x0}, 
+  {0xEE,0x69,0x302,0x0}, {0xEF,0x69,0x308,0x0}, {0xF1,0x6E,0x303,0x0}, 
+  {0xF2,0x6F,0x300,0x0}, {0xF3,0x6F,0x301,0x0}, {0xF4,0x6F,0x302,0x0}, 
+  {0xF5,0x6F,0x303,0x0}, {0xF6,0x6F,0x308,0x0}, {0xF9,0x75,0x300,0x0}, 
+  {0xFA,0x75,0x301,0x0}, {0xFB,0x75,0x302,0x0}, {0xFC,0x75,0x308,0x0}, 
+  {0xFD,0x79,0x301,0x0}, {0xFF,0x79,0x308,0x0}, {0x100,0x41,0x304,0x0}, 
+  {0x101,0x61,0x304,0x0}, {0x102,0x41,0x306,0x0}, {0x103,0x61,0x306,0x0}, 
+  {0x104,0x41,0x328,0x0}, {0x105,0x61,0x328,0x0}, {0x106,0x43,0x301,0x0}, 
+  {0x107,0x63,0x301,0x0}, {0x108,0x43,0x302,0x0}, {0x109,0x63,0x302,0x0}, 
+  {0x10A,0x43,0x307,0x0}, {0x10B,0x63,0x307,0x0}, {0x10C,0x43,0x30C,0x0}, 
+  {0x10D,0x63,0x30C,0x0}, {0x10E,0x44,0x30C,0x0}, {0x10F,0x64,0x30C,0x0}, 
+  {0x112,0x45,0x304,0x0}, {0x113,0x65,0x304,0x0}, {0x114,0x45,0x306,0x0}, 
+  {0x115,0x65,0x306,0x0}, {0x116,0x45,0x307,0x0}, {0x117,0x65,0x307,0x0}, 
+  {0x118,0x45,0x328,0x0}, {0x119,0x65,0x328,0x0}, {0x11A,0x45,0x30C,0x0}, 
+  {0x11B,0x65,0x30C,0x0}, {0x11C,0x47,0x302,0x0}, {0x11D,0x67,0x302,0x0}, 
+  {0x11E,0x47,0x306,0x0}, {0x11F,0x67,0x306,0x0}, {0x120,0x47,0x307,0x0}, 
+  {0x121,0x67,0x307,0x0}, {0x122,0x47,0x327,0x0}, {0x123,0x67,0x327,0x0}, 
+  {0x124,0x48,0x302,0x0}, {0x125,0x68,0x302,0x0}, {0x128,0x49,0x303,0x0}, 
+  {0x129,0x69,0x303,0x0}, {0x12A,0x49,0x304,0x0}, {0x12B,0x69,0x304,0x0}, 
+  {0x12C,0x49,0x306,0x0}, {0x12D,0x69,0x306,0x0}, {0x12E,0x49,0x328,0x0}, 
+  {0x12F,0x69,0x328,0x0}, {0x130,0x49,0x307,0x0}, {0x134,0x4A,0x302,0x0}, 
+  {0x135,0x6A,0x302,0x0}, {0x136,0x4B,0x327,0x0}, {0x137,0x6B,0x327,0x0}, 
+  {0x139,0x4C,0x301,0x0}, {0x13A,0x6C,0x301,0x0}, {0x13B,0x4C,0x327,0x0}, 
+  {0x13C,0x6C,0x327,0x0}, {0x13D,0x4C,0x30C,0x0}, {0x13E,0x6C,0x30C,0x0}, 
+  {0x143,0x4E,0x301,0x0}, {0x144,0x6E,0x301,0x0}, {0x145,0x4E,0x327,0x0}, 
+  {0x146,0x6E,0x327,0x0}, {0x147,0x4E,0x30C,0x0}, {0x148,0x6E,0x30C,0x0}, 
+  {0x14C,0x4F,0x304,0x0}, {0x14D,0x6F,0x304,0x0}, {0x14E,0x4F,0x306,0x0}, 
+  {0x14F,0x6F,0x306,0x0}, {0x150,0x4F,0x30B,0x0}, {0x151,0x6F,0x30B,0x0}, 
+  {0x154,0x52,0x301,0x0}, {0x155,0x72,0x301,0x0}, {0x156,0x52,0x327,0x0}, 
+  {0x157,0x72,0x327,0x0}, {0x158,0x52,0x30C,0x0}, {0x159,0x72,0x30C,0x0}, 
+  {0x15A,0x53,0x301,0x0}, {0x15B,0x73,0x301,0x0}, {0x15C,0x53,0x302,0x0}, 
+  {0x15D,0x73,0x302,0x0}, {0x15E,0x53,0x327,0x0}, {0x15F,0x73,0x327,0x0}, 
+  {0x160,0x53,0x30C,0x0}, {0x161,0x73,0x30C,0x0}, {0x162,0x54,0x327,0x0}, 
+  {0x163,0x74,0x327,0x0}, {0x164,0x54,0x30C,0x0}, {0x165,0x74,0x30C,0x0}, 
+  {0x168,0x55,0x303,0x0}, {0x169,0x75,0x303,0x0}, {0x16A,0x55,0x304,0x0}, 
+  {0x16B,0x75,0x304,0x0}, {0x16C,0x55,0x306,0x0}, {0x16D,0x75,0x306,0x0}, 
+  {0x16E,0x55,0x30A,0x0}, {0x16F,0x75,0x30A,0x0}, {0x170,0x55,0x30B,0x0}, 
+  {0x171,0x75,0x30B,0x0}, {0x172,0x55,0x328,0x0}, {0x173,0x75,0x328,0x0}, 
+  {0x174,0x57,0x302,0x0}, {0x175,0x77,0x302,0x0}, {0x176,0x59,0x302,0x0}, 
+  {0x177,0x79,0x302,0x0}, {0x178,0x59,0x308,0x0}, {0x179,0x5A,0x301,0x0}, 
+  {0x17A,0x7A,0x301,0x0}, {0x17B,0x5A,0x307,0x0}, {0x17C,0x7A,0x307,0x0}, 
+  {0x17D,0x5A,0x30C,0x0}, {0x17E,0x7A,0x30C,0x0}, {0x1A0,0x4F,0x31B,0x0}, 
+  {0x1A1,0x6F,0x31B,0x0}, {0x1AF,0x55,0x31B,0x0}, {0x1B0,0x75,0x31B,0x0}, 
+  {0x1CD,0x41,0x30C,0x0}, {0x1CE,0x61,0x30C,0x0}, {0x1CF,0x49,0x30C,0x0}, 
+  {0x1D0,0x69,0x30C,0x0}, {0x1D1,0x4F,0x30C,0x0}, {0x1D2,0x6F,0x30C,0x0}, 
+  {0x1D3,0x55,0x30C,0x0}, {0x1D4,0x75,0x30C,0x0}, {0x1D5,0xDC,0x304,0x0}, 
+  {0x1D6,0xFC,0x304,0x0}, {0x1D7,0xDC,0x301,0x0}, {0x1D8,0xFC,0x301,0x0}, 
+  {0x1D9,0xDC,0x30C,0x0}, {0x1DA,0xFC,0x30C,0x0}, {0x1DB,0xDC,0x300,0x0}, 
+  {0x1DC,0xFC,0x300,0x0}, {0x1DE,0xC4,0x304,0x0}, {0x1DF,0xE4,0x304,0x0}, 
+  {0x1E0,0x41,0x307,0x304}, {0x1E1,0x61,0x307,0x304}, {0x1E2,0xC6,0x304,0x0}, 
+  {0x1E3,0xE6,0x304,0x0}, {0x1E6,0x47,0x30C,0x0}, {0x1E7,0x67,0x30C,0x0}, 
+  {0x1E8,0x4B,0x30C,0x0}, {0x1E9,0x6B,0x30C,0x0}, {0x1EA,0x4F,0x328,0x0}, 
+  {0x1EB,0x6F,0x328,0x0}, {0x1EC,0x1EA,0x304,0x0}, {0x1ED,0x1EB,0x304,0x0}, 
+  {0x1EE,0x1B7,0x30C,0x0}, {0x1EF,0x292,0x30C,0x0}, {0x1F0,0x6A,0x30C,0x0}, 
+  {0x1F4,0x47,0x301,0x0}, {0x1F5,0x67,0x301,0x0}, {0x1FA,0xC5,0x301,0x0}, 
+  {0x1FB,0xE5,0x301,0x0}, {0x1FC,0xC6,0x301,0x0}, {0x1FD,0xE6,0x301,0x0}, 
+  {0x1FE,0xD8,0x301,0x0}, {0x1FF,0xF8,0x301,0x0}, {0x200,0x41,0x30F,0x0}, 
+  {0x201,0x61,0x30F,0x0}, {0x202,0x41,0x311,0x0}, {0x203,0x61,0x311,0x0}, 
+  {0x204,0x45,0x30F,0x0}, {0x205,0x65,0x30F,0x0}, {0x206,0x45,0x311,0x0}, 
+  {0x207,0x65,0x311,0x0}, {0x208,0x49,0x30F,0x0}, {0x209,0x69,0x30F,0x0}, 
+  {0x20A,0x49,0x311,0x0}, {0x20B,0x69,0x311,0x0}, {0x20C,0x4F,0x30F,0x0}, 
+  {0x20D,0x6F,0x30F,0x0}, {0x20E,0x4F,0x311,0x0}, {0x20F,0x6F,0x311,0x0}, 
+  {0x210,0x52,0x30F,0x0}, {0x211,0x72,0x30F,0x0}, {0x212,0x52,0x311,0x0}, 
+  {0x213,0x72,0x311,0x0}, {0x214,0x55,0x30F,0x0}, {0x215,0x75,0x30F,0x0}, 
+  {0x216,0x55,0x311,0x0}, {0x217,0x75,0x311,0x0}, {0x310,0x306,0x307,0x0}, 
+  {0x340,0x300,0x0,0x0}, {0x341,0x301,0x0,0x0}, {0x343,0x313,0x0,0x0}, 
+  {0x344,0x308,0x30D,0x0}, {0x374,0x2B9,0x0,0x0}, {0x37E,0x3B,0x0,0x0}, 
+  {0x385,0xA8,0x30D,0x0}, {0x386,0x391,0x30D,0x0}, {0x387,0xB7,0x0,0x0}, 
+  {0x388,0x395,0x30D,0x0}, {0x389,0x397,0x30D,0x0}, {0x38A,0x399,0x30D,0x0}, 
+  {0x38C,0x39F,0x30D,0x0}, {0x38E,0x3A5,0x30D,0x0}, {0x38F,0x3A9,0x30D,0x0}, 
+  {0x390,0x3B9,0x344,0x0}, {0x3AA,0x399,0x308,0x0}, {0x3AB,0x3A5,0x308,0x0}, 
+  {0x3AC,0x3B1,0x30D,0x0}, {0x3AD,0x3B5,0x30D,0x0}, {0x3AE,0x3B7,0x30D,0x0}, 
+  {0x3AF,0x3B9,0x30D,0x0}, {0x3B0,0x3C5,0x344,0x0}, {0x3CA,0x3B9,0x308,0x0}, 
+  {0x3CB,0x3C5,0x308,0x0}, {0x3CC,0x3BF,0x30D,0x0}, {0x3CD,0x3C5,0x30D,0x0}, 
+  {0x3CE,0x3C9,0x30D,0x0}, {0x3D3,0x3D2,0x30D,0x0}, {0x3D4,0x3D2,0x308,0x0}, 
+  {0x401,0x415,0x308,0x0}, {0x403,0x413,0x301,0x0}, {0x407,0x406,0x308,0x0}, 
+  {0x40C,0x41A,0x301,0x0}, {0x40E,0x423,0x306,0x0}, {0x419,0x418,0x306,0x0}, 
+  {0x439,0x438,0x306,0x0}, {0x451,0x435,0x308,0x0}, {0x453,0x433,0x301,0x0}, 
+  {0x457,0x456,0x308,0x0}, {0x45C,0x43A,0x301,0x0}, {0x45E,0x443,0x306,0x0}, 
+  {0x476,0x474,0x30F,0x0}, {0x477,0x475,0x30F,0x0}, {0x4C1,0x416,0x306,0x0}, 
+  {0x4C2,0x436,0x306,0x0}, {0x4D0,0x410,0x306,0x0}, {0x4D1,0x430,0x306,0x0}, 
+  {0x4D2,0x410,0x308,0x0}, {0x4D3,0x430,0x308,0x0}, {0x4D6,0x415,0x306,0x0}, 
+  {0x4D7,0x435,0x306,0x0}, {0x4DA,0x4D8,0x308,0x0}, {0x4DB,0x4D9,0x308,0x0}, 
+  {0x4DC,0x416,0x308,0x0}, {0x4DD,0x436,0x308,0x0}, {0x4DE,0x417,0x308,0x0}, 
+  {0x4DF,0x437,0x308,0x0}, {0x4E2,0x418,0x304,0x0}, {0x4E3,0x438,0x304,0x0}, 
+  {0x4E4,0x418,0x308,0x0}, {0x4E5,0x438,0x308,0x0}, {0x4E6,0x41E,0x308,0x0}, 
+  {0x4E7,0x43E,0x308,0x0}, {0x4EA,0x4E8,0x308,0x0}, {0x4EB,0x4E9,0x308,0x0}, 
+  {0x4EE,0x423,0x304,0x0}, {0x4EF,0x443,0x304,0x0}, {0x4F0,0x423,0x308,0x0}, 
+  {0x4F1,0x443,0x308,0x0}, {0x4F2,0x423,0x30B,0x0}, {0x4F3,0x443,0x30B,0x0}, 
+  {0x4F4,0x427,0x308,0x0}, {0x4F5,0x447,0x308,0x0}, {0x4F8,0x42B,0x308,0x0}, 
+  {0x4F9,0x44B,0x308,0x0}, {0x929,0x928,0x93C,0x0}, {0x931,0x930,0x93C,0x0}, 
+  {0x934,0x933,0x93C,0x0}, {0x958,0x915,0x93C,0x0}, {0x959,0x916,0x93C,0x0}, 
+  {0x95A,0x917,0x93C,0x0}, {0x95B,0x91C,0x93C,0x0}, {0x95C,0x921,0x93C,0x0}, 
+  {0x95D,0x922,0x93C,0x0}, {0x95E,0x92B,0x93C,0x0}, {0x95F,0x92F,0x93C,0x0}, 
+  {0x9B0,0x9AC,0x9BC,0x0}, {0x9CB,0x9C7,0x9BE,0x0}, {0x9CC,0x9C7,0x9D7,0x0}, 
+  {0x9DC,0x9A1,0x9BC,0x0}, {0x9DD,0x9A2,0x9BC,0x0}, {0x9DF,0x9AF,0x9BC,0x0}, 
+  {0xA59,0xA16,0xA3C,0x0}, {0xA5A,0xA17,0xA3C,0x0}, {0xA5B,0xA1C,0xA3C,0x0}, 
+  {0xA5C,0xA21,0xA3C,0x0}, {0xA5E,0xA2B,0xA3C,0x0}, {0xB48,0xB47,0xB56,0x0}, 
+  {0xB4B,0xB47,0xB3E,0x0}, {0xB4C,0xB47,0xB57,0x0}, {0xB5C,0xB21,0xB3C,0x0}, 
+  {0xB5D,0xB22,0xB3C,0x0}, {0xB5F,0xB2F,0xB3C,0x0}, {0xB94,0xB92,0xBD7,0x0}, 
+  {0xBCA,0xBC6,0xBBE,0x0}, {0xBCB,0xBC7,0xBBE,0x0}, {0xBCC,0xBC6,0xBD7,0x0}, 
+  {0xC48,0xC46,0xC56,0x0}, {0xCC0,0xCBF,0xCD5,0x0}, {0xCC7,0xCC6,0xCD5,0x0}, 
+  {0xCC8,0xCC6,0xCD6,0x0}, {0xCCA,0xCC6,0xCC2,0x0}, {0xCCB,0xCC6,0xCC2,0xCD5}, 
+  {0xD4A,0xD46,0xD3E,0x0}, {0xD4B,0xD47,0xD3E,0x0}, {0xD4C,0xD46,0xD57,0x0}, 
+  {0xE33,0xE4D,0xE32,0x0}, {0xEB3,0xECD,0xEB2,0x0}, {0xF43,0xF42,0xFB7,0x0}, 
+  {0xF4D,0xF4C,0xFB7,0x0}, {0xF52,0xF51,0xFB7,0x0}, {0xF57,0xF56,0xFB7,0x0}, 
+  {0xF5C,0xF5B,0xFB7,0x0}, {0xF69,0xF40,0xFB5,0x0}, {0xF73,0xF72,0xF71,0x0}, 
+  {0xF75,0xF71,0xF74,0x0}, {0xF76,0xFB2,0xF80,0x0}, {0xF77,0xF76,0xF71,0x0}, 
+  {0xF78,0xFB3,0xF80,0x0}, {0xF79,0xF78,0xF71,0x0}, {0xF81,0xF80,0xF71,0x0}, 
+  {0xF93,0xF92,0xFB7,0x0}, {0xF9D,0xF9C,0xFB7,0x0}, {0xFA2,0xFA1,0xFB7,0x0}, 
+  {0xFA7,0xFA6,0xFB7,0x0}, {0xFAC,0xFAB,0xFB7,0x0}, {0xFB9,0xF90,0xFB5,0x0}, 
+  {0x1E00,0x41,0x325,0x0}, {0x1E01,0x61,0x325,0x0}, {0x1E02,0x42,0x307,0x0}, 
+  {0x1E03,0x62,0x307,0x0}, {0x1E04,0x42,0x323,0x0}, {0x1E05,0x62,0x323,0x0}, 
+  {0x1E06,0x42,0x331,0x0}, {0x1E07,0x62,0x331,0x0}, {0x1E08,0xC7,0x301,0x0}, 
+  {0x1E09,0xE7,0x301,0x0}, {0x1E0A,0x44,0x307,0x0}, {0x1E0B,0x64,0x307,0x0}, 
+  {0x1E0C,0x44,0x323,0x0}, {0x1E0D,0x64,0x323,0x0}, {0x1E0E,0x44,0x331,0x0}, 
+  {0x1E0F,0x64,0x331,0x0}, {0x1E10,0x44,0x327,0x0}, {0x1E11,0x64,0x327,0x0}, 
+  {0x1E12,0x44,0x32D,0x0}, {0x1E13,0x64,0x32D,0x0}, {0x1E14,0x112,0x300,0x0}, 
+  {0x1E15,0x113,0x300,0x0}, {0x1E16,0x112,0x301,0x0}, {0x1E17,0x113,0x301,0x0}, 
+  {0x1E18,0x45,0x32D,0x0}, {0x1E19,0x65,0x32D,0x0}, {0x1E1A,0x45,0x330,0x0}, 
+  {0x1E1B,0x65,0x330,0x0}, {0x1E1C,0x114,0x327,0x0}, {0x1E1D,0x115,0x327,0x0}, 
+  {0x1E1E,0x46,0x307,0x0}, {0x1E1F,0x66,0x307,0x0}, {0x1E20,0x47,0x304,0x0}, 
+  {0x1E21,0x67,0x304,0x0}, {0x1E22,0x48,0x307,0x0}, {0x1E23,0x68,0x307,0x0}, 
+  {0x1E24,0x48,0x323,0x0}, {0x1E25,0x68,0x323,0x0}, {0x1E26,0x48,0x308,0x0}, 
+  {0x1E27,0x68,0x308,0x0}, {0x1E28,0x48,0x327,0x0}, {0x1E29,0x68,0x327,0x0}, 
+  {0x1E2A,0x48,0x32E,0x0}, {0x1E2B,0x68,0x32E,0x0}, {0x1E2C,0x49,0x330,0x0}, 
+  {0x1E2D,0x69,0x330,0x0}, {0x1E2E,0xCF,0x301,0x0}, {0x1E2F,0xEF,0x301,0x0}, 
+  {0x1E30,0x4B,0x301,0x0}, {0x1E31,0x6B,0x301,0x0}, {0x1E32,0x4B,0x323,0x0}, 
+  {0x1E33,0x6B,0x323,0x0}, {0x1E34,0x4B,0x331,0x0}, {0x1E35,0x6B,0x331,0x0}, 
+  {0x1E36,0x4C,0x323,0x0}, {0x1E37,0x6C,0x323,0x0}, {0x1E38,0x1E36,0x304,0x0}, 
+  {0x1E39,0x1E37,0x304,0x0}, {0x1E3A,0x4C,0x331,0x0}, {0x1E3B,0x6C,0x331,0x0}, 
+  {0x1E3C,0x4C,0x32D,0x0}, {0x1E3D,0x6C,0x32D,0x0}, {0x1E3E,0x4D,0x301,0x0}, 
+  {0x1E3F,0x6D,0x301,0x0}, {0x1E40,0x4D,0x307,0x0}, {0x1E41,0x6D,0x307,0x0}, 
+  {0x1E42,0x4D,0x323,0x0}, {0x1E43,0x6D,0x323,0x0}, {0x1E44,0x4E,0x307,0x0}, 
+  {0x1E45,0x6E,0x307,0x0}, {0x1E46,0x4E,0x323,0x0}, {0x1E47,0x6E,0x323,0x0}, 
+  {0x1E48,0x4E,0x331,0x0}, {0x1E49,0x6E,0x331,0x0}, {0x1E4A,0x4E,0x32D,0x0}, 
+  {0x1E4B,0x6E,0x32D,0x0}, {0x1E4C,0xD5,0x301,0x0}, {0x1E4D,0xF5,0x301,0x0}, 
+  {0x1E4E,0xD5,0x308,0x0}, {0x1E4F,0xF5,0x308,0x0}, {0x1E50,0x14C,0x300,0x0}, 
+  {0x1E51,0x14D,0x300,0x0}, {0x1E52,0x14C,0x301,0x0}, {0x1E53,0x14D,0x301,0x0}, 
+  {0x1E54,0x50,0x301,0x0}, {0x1E55,0x70,0x301,0x0}, {0x1E56,0x50,0x307,0x0}, 
+  {0x1E57,0x70,0x307,0x0}, {0x1E58,0x52,0x307,0x0}, {0x1E59,0x72,0x307,0x0}, 
+  {0x1E5A,0x52,0x323,0x0}, {0x1E5B,0x72,0x323,0x0}, {0x1E5C,0x1E5A,0x304,0x0}, 
+  {0x1E5D,0x1E5B,0x304,0x0}, {0x1E5E,0x52,0x331,0x0}, {0x1E5F,0x72,0x331,0x0}, 
+  {0x1E60,0x53,0x307,0x0}, {0x1E61,0x73,0x307,0x0}, {0x1E62,0x53,0x323,0x0}, 
+  {0x1E63,0x73,0x323,0x0}, {0x1E64,0x15A,0x307,0x0}, {0x1E65,0x15B,0x307,0x0}, 
+  {0x1E66,0x160,0x307,0x0}, {0x1E67,0x161,0x307,0x0}, {0x1E68,0x1E62,0x307,0x0}, 
+  {0x1E69,0x1E63,0x307,0x0}, {0x1E6A,0x54,0x307,0x0}, {0x1E6B,0x74,0x307,0x0}, 
+  {0x1E6C,0x54,0x323,0x0}, {0x1E6D,0x74,0x323,0x0}, {0x1E6E,0x54,0x331,0x0}, 
+  {0x1E6F,0x74,0x331,0x0}, {0x1E70,0x54,0x32D,0x0}, {0x1E71,0x74,0x32D,0x0}, 
+  {0x1E72,0x55,0x324,0x0}, {0x1E73,0x75,0x324,0x0}, {0x1E74,0x55,0x330,0x0}, 
+  {0x1E75,0x75,0x330,0x0}, {0x1E76,0x55,0x32D,0x0}, {0x1E77,0x75,0x32D,0x0}, 
+  {0x1E78,0x168,0x301,0x0}, {0x1E79,0x169,0x301,0x0}, {0x1E7A,0x16A,0x308,0x0}, 
+  {0x1E7B,0x16B,0x308,0x0}, {0x1E7C,0x56,0x303,0x0}, {0x1E7D,0x76,0x303,0x0}, 
+  {0x1E7E,0x56,0x323,0x0}, {0x1E7F,0x76,0x323,0x0}, {0x1E80,0x57,0x300,0x0}, 
+  {0x1E81,0x77,0x300,0x0}, {0x1E82,0x57,0x301,0x0}, {0x1E83,0x77,0x301,0x0}, 
+  {0x1E84,0x57,0x308,0x0}, {0x1E85,0x77,0x308,0x0}, {0x1E86,0x57,0x307,0x0}, 
+  {0x1E87,0x77,0x307,0x0}, {0x1E88,0x57,0x323,0x0}, {0x1E89,0x77,0x323,0x0}, 
+  {0x1E8A,0x58,0x307,0x0}, {0x1E8B,0x78,0x307,0x0}, {0x1E8C,0x58,0x308,0x0}, 
+  {0x1E8D,0x78,0x308,0x0}, {0x1E8E,0x59,0x307,0x0}, {0x1E8F,0x79,0x307,0x0}, 
+  {0x1E90,0x5A,0x302,0x0}, {0x1E91,0x7A,0x302,0x0}, {0x1E92,0x5A,0x323,0x0}, 
+  {0x1E93,0x7A,0x323,0x0}, {0x1E94,0x5A,0x331,0x0}, {0x1E95,0x7A,0x331,0x0}, 
+  {0x1E96,0x68,0x331,0x0}, {0x1E97,0x74,0x308,0x0}, {0x1E98,0x77,0x30A,0x0}, 
+  {0x1E99,0x79,0x30A,0x0}, {0x1E9B,0x17F,0x307,0x0}, {0x1EA0,0x41,0x323,0x0}, 
+  {0x1EA1,0x61,0x323,0x0}, {0x1EA2,0x41,0x309,0x0}, {0x1EA3,0x61,0x309,0x0}, 
+  {0x1EA4,0xC2,0x301,0x0}, {0x1EA5,0xE2,0x301,0x0}, {0x1EA6,0xC2,0x300,0x0}, 
+  {0x1EA7,0xE2,0x300,0x0}, {0x1EA8,0xC2,0x309,0x0}, {0x1EA9,0xE2,0x309,0x0}, 
+  {0x1EAA,0xC2,0x303,0x0}, {0x1EAB,0xE2,0x303,0x0}, {0x1EAC,0xC2,0x323,0x0}, 
+  {0x1EAD,0xE2,0x323,0x0}, {0x1EAE,0x102,0x301,0x0}, {0x1EAF,0x103,0x301,0x0}, 
+  {0x1EB0,0x102,0x300,0x0}, {0x1EB1,0x103,0x300,0x0}, {0x1EB2,0x102,0x309,0x0}, 
+  {0x1EB3,0x103,0x309,0x0}, {0x1EB4,0x102,0x303,0x0}, {0x1EB5,0x103,0x303,0x0}, 
+  {0x1EB6,0x102,0x323,0x0}, {0x1EB7,0x103,0x323,0x0}, {0x1EB8,0x45,0x323,0x0}, 
+  {0x1EB9,0x65,0x323,0x0}, {0x1EBA,0x45,0x309,0x0}, {0x1EBB,0x65,0x309,0x0}, 
+  {0x1EBC,0x45,0x303,0x0}, {0x1EBD,0x65,0x303,0x0}, {0x1EBE,0xCA,0x301,0x0}, 
+  {0x1EBF,0xEA,0x301,0x0}, {0x1EC0,0xCA,0x300,0x0}, {0x1EC1,0xEA,0x300,0x0}, 
+  {0x1EC2,0xCA,0x309,0x0}, {0x1EC3,0xEA,0x309,0x0}, {0x1EC4,0xCA,0x303,0x0}, 
+  {0x1EC5,0xEA,0x303,0x0}, {0x1EC6,0xCA,0x323,0x0}, {0x1EC7,0xEA,0x323,0x0}, 
+  {0x1EC8,0x49,0x309,0x0}, {0x1EC9,0x69,0x309,0x0}, {0x1ECA,0x49,0x323,0x0}, 
+  {0x1ECB,0x69,0x323,0x0}, {0x1ECC,0x4F,0x323,0x0}, {0x1ECD,0x6F,0x323,0x0}, 
+  {0x1ECE,0x4F,0x309,0x0}, {0x1ECF,0x6F,0x309,0x0}, {0x1ED0,0xD4,0x301,0x0}, 
+  {0x1ED1,0xF4,0x301,0x0}, {0x1ED2,0xD4,0x300,0x0}, {0x1ED3,0xF4,0x300,0x0}, 
+  {0x1ED4,0xD4,0x309,0x0}, {0x1ED5,0xF4,0x309,0x0}, {0x1ED6,0xD4,0x303,0x0}, 
+  {0x1ED7,0xF4,0x303,0x0}, {0x1ED8,0xD4,0x323,0x0}, {0x1ED9,0xF4,0x323,0x0}, 
+  {0x1EDA,0x1A0,0x301,0x0}, {0x1EDB,0x1A1,0x301,0x0}, {0x1EDC,0x1A0,0x300,0x0}, 
+  {0x1EDD,0x1A1,0x300,0x0}, {0x1EDE,0x1A0,0x309,0x0}, {0x1EDF,0x1A1,0x309,0x0}, 
+  {0x1EE0,0x1A0,0x303,0x0}, {0x1EE1,0x1A1,0x303,0x0}, {0x1EE2,0x1A0,0x323,0x0}, 
+  {0x1EE3,0x1A1,0x323,0x0}, {0x1EE4,0x55,0x323,0x0}, {0x1EE5,0x75,0x323,0x0}, 
+  {0x1EE6,0x55,0x309,0x0}, {0x1EE7,0x75,0x309,0x0}, {0x1EE8,0x1AF,0x301,0x0}, 
+  {0x1EE9,0x1B0,0x301,0x0}, {0x1EEA,0x1AF,0x300,0x0}, {0x1EEB,0x1B0,0x300,0x0}, 
+  {0x1EEC,0x1AF,0x309,0x0}, {0x1EED,0x1B0,0x309,0x0}, {0x1EEE,0x1AF,0x303,0x0}, 
+  {0x1EEF,0x1B0,0x303,0x0}, {0x1EF0,0x1AF,0x323,0x0}, {0x1EF1,0x1B0,0x323,0x0}, 
+  {0x1EF2,0x59,0x300,0x0}, {0x1EF3,0x79,0x300,0x0}, {0x1EF4,0x59,0x323,0x0}, 
+  {0x1EF5,0x79,0x323,0x0}, {0x1EF6,0x59,0x309,0x0}, {0x1EF7,0x79,0x309,0x0}, 
+  {0x1EF8,0x59,0x303,0x0}, {0x1EF9,0x79,0x303,0x0}, {0x1F00,0x3B1,0x313,0x0}, 
+  {0x1F01,0x3B1,0x314,0x0}, {0x1F02,0x1F00,0x300,0x0}, {0x1F03,0x1F01,0x300,0x0}, 
+  {0x1F04,0x1F00,0x301,0x0}, {0x1F05,0x1F01,0x301,0x0}, {0x1F06,0x1F00,0x342,0x0}, 
+  {0x1F07,0x1F01,0x342,0x0}, {0x1F08,0x391,0x313,0x0}, {0x1F09,0x391,0x314,0x0}, 
+  {0x1F0A,0x1F08,0x300,0x0}, {0x1F0B,0x1F09,0x300,0x0}, {0x1F0C,0x1F08,0x301,0x0}, 
+  {0x1F0D,0x1F09,0x301,0x0}, {0x1F0E,0x1F08,0x342,0x0}, {0x1F0F,0x1F09,0x342,0x0}, 
+  {0x1F10,0x3B5,0x313,0x0}, {0x1F11,0x3B5,0x314,0x0}, {0x1F12,0x1F10,0x300,0x0}, 
+  {0x1F13,0x1F11,0x300,0x0}, {0x1F14,0x1F10,0x301,0x0}, {0x1F15,0x1F11,0x301,0x0}, 
+  {0x1F18,0x395,0x313,0x0}, {0x1F19,0x395,0x314,0x0}, {0x1F1A,0x1F18,0x300,0x0}, 
+  {0x1F1B,0x1F19,0x300,0x0}, {0x1F1C,0x1F18,0x301,0x0}, {0x1F1D,0x1F19,0x301,0x0}, 
+  {0x1F20,0x3B7,0x313,0x0}, {0x1F21,0x3B7,0x314,0x0}, {0x1F22,0x1F20,0x300,0x0}, 
+  {0x1F23,0x1F21,0x300,0x0}, {0x1F24,0x1F20,0x301,0x0}, {0x1F25,0x1F21,0x301,0x0}, 
+  {0x1F26,0x1F20,0x342,0x0}, {0x1F27,0x1F21,0x342,0x0}, {0x1F28,0x397,0x313,0x0}, 
+  {0x1F29,0x397,0x314,0x0}, {0x1F2A,0x1F28,0x300,0x0}, {0x1F2B,0x1F29,0x300,0x0}, 
+  {0x1F2C,0x1F28,0x301,0x0}, {0x1F2D,0x1F29,0x301,0x0}, {0x1F2E,0x1F28,0x342,0x0}, 
+  {0x1F2F,0x1F29,0x342,0x0}, {0x1F30,0x3B9,0x313,0x0}, {0x1F31,0x3B9,0x314,0x0}, 
+  {0x1F32,0x1F30,0x300,0x0}, {0x1F33,0x1F31,0x300,0x0}, {0x1F34,0x1F30,0x301,0x0}, 
+  {0x1F35,0x1F31,0x301,0x0}, {0x1F36,0x1F30,0x342,0x0}, {0x1F37,0x1F31,0x342,0x0}, 
+  {0x1F38,0x399,0x313,0x0}, {0x1F39,0x399,0x314,0x0}, {0x1F3A,0x1F38,0x300,0x0}, 
+  {0x1F3B,0x1F39,0x300,0x0}, {0x1F3C,0x1F38,0x301,0x0}, {0x1F3D,0x1F39,0x301,0x0}, 
+  {0x1F3E,0x1F38,0x342,0x0}, {0x1F3F,0x1F39,0x342,0x0}, {0x1F40,0x3BF,0x313,0x0}, 
+  {0x1F41,0x3BF,0x314,0x0}, {0x1F42,0x1F40,0x300,0x0}, {0x1F43,0x1F41,0x300,0x0}, 
+  {0x1F44,0x1F40,0x301,0x0}, {0x1F45,0x1F41,0x301,0x0}, {0x1F48,0x39F,0x313,0x0}, 
+  {0x1F49,0x39F,0x314,0x0}, {0x1F4A,0x1F48,0x300,0x0}, {0x1F4B,0x1F49,0x300,0x0}, 
+  {0x1F4C,0x1F48,0x301,0x0}, {0x1F4D,0x1F49,0x301,0x0}, {0x1F50,0x3C5,0x313,0x0}, 
+  {0x1F51,0x3C5,0x314,0x0}, {0x1F52,0x1F50,0x300,0x0}, {0x1F53,0x1F51,0x300,0x0}, 
+  {0x1F54,0x1F50,0x301,0x0}, {0x1F55,0x1F51,0x301,0x0}, {0x1F56,0x1F50,0x342,0x0}, 
+  {0x1F57,0x1F51,0x342,0x0}, {0x1F59,0x3A5,0x314,0x0}, {0x1F5B,0x1F59,0x300,0x0}, 
+  {0x1F5D,0x1F59,0x301,0x0}, {0x1F5F,0x1F59,0x342,0x0}, {0x1F60,0x3C9,0x313,0x0}, 
+  {0x1F61,0x3C9,0x314,0x0}, {0x1F62,0x1F60,0x300,0x0}, {0x1F63,0x1F61,0x300,0x0}, 
+  {0x1F64,0x1F60,0x301,0x0}, {0x1F65,0x1F61,0x301,0x0}, {0x1F66,0x1F60,0x342,0x0}, 
+  {0x1F67,0x1F61,0x342,0x0}, {0x1F68,0x3A9,0x313,0x0}, {0x1F69,0x3A9,0x314,0x0}, 
+  {0x1F6A,0x1F68,0x300,0x0}, {0x1F6B,0x1F69,0x300,0x0}, {0x1F6C,0x1F68,0x301,0x0}, 
+  {0x1F6D,0x1F69,0x301,0x0}, {0x1F6E,0x1F68,0x342,0x0}, {0x1F6F,0x1F69,0x342,0x0}, 
+  {0x1F70,0x3B1,0x300,0x0}, {0x1F71,0x3B1,0x301,0x0}, {0x1F72,0x3B5,0x300,0x0}, 
+  {0x1F73,0x3B5,0x301,0x0}, {0x1F74,0x3B7,0x300,0x0}, {0x1F75,0x3B7,0x301,0x0}, 
+  {0x1F76,0x3B9,0x300,0x0}, {0x1F77,0x3B9,0x301,0x0}, {0x1F78,0x3BF,0x300,0x0}, 
+  {0x1F79,0x3BF,0x301,0x0}, {0x1F7A,0x3C5,0x300,0x0}, {0x1F7B,0x3C5,0x301,0x0}, 
+  {0x1F7C,0x3C9,0x300,0x0}, {0x1F7D,0x3C9,0x301,0x0}, {0x1F80,0x1F00,0x345,0x0}, 
+  {0x1F81,0x1F01,0x345,0x0}, {0x1F82,0x1F02,0x345,0x0}, {0x1F83,0x1F03,0x345,0x0}, 
+  {0x1F84,0x1F04,0x345,0x0}, {0x1F85,0x1F05,0x345,0x0}, {0x1F86,0x1F06,0x345,0x0}, 
+  {0x1F87,0x1F07,0x345,0x0}, {0x1F88,0x1F08,0x345,0x0}, {0x1F89,0x1F09,0x345,0x0}, 
+  {0x1F8A,0x1F0A,0x345,0x0}, {0x1F8B,0x1F0B,0x345,0x0}, {0x1F8C,0x1F0C,0x345,0x0}, 
+  {0x1F8D,0x1F0D,0x345,0x0}, {0x1F8E,0x1F0E,0x345,0x0}, {0x1F8F,0x1F0F,0x345,0x0}, 
+  {0x1F90,0x1F20,0x345,0x0}, {0x1F91,0x1F21,0x345,0x0}, {0x1F92,0x1F22,0x345,0x0}, 
+  {0x1F93,0x1F23,0x345,0x0}, {0x1F94,0x1F24,0x345,0x0}, {0x1F95,0x1F25,0x345,0x0}, 
+  {0x1F96,0x1F26,0x345,0x0}, {0x1F97,0x1F27,0x345,0x0}, {0x1F98,0x1F28,0x345,0x0}, 
+  {0x1F99,0x1F29,0x345,0x0}, {0x1F9A,0x1F2A,0x345,0x0}, {0x1F9B,0x1F2B,0x345,0x0}, 
+  {0x1F9C,0x1F2C,0x345,0x0}, {0x1F9D,0x1F2D,0x345,0x0}, {0x1F9E,0x1F2E,0x345,0x0}, 
+  {0x1F9F,0x1F2F,0x345,0x0}, {0x1FA0,0x1F60,0x345,0x0}, {0x1FA1,0x1F61,0x345,0x0}, 
+  {0x1FA2,0x1F62,0x345,0x0}, {0x1FA3,0x1F63,0x345,0x0}, {0x1FA4,0x1F64,0x345,0x0}, 
+  {0x1FA5,0x1F65,0x345,0x0}, {0x1FA6,0x1F66,0x345,0x0}, {0x1FA7,0x1F67,0x345,0x0}, 
+  {0x1FA8,0x1F68,0x345,0x0}, {0x1FA9,0x1F69,0x345,0x0}, {0x1FAA,0x1F6A,0x345,0x0}, 
+  {0x1FAB,0x1F6B,0x345,0x0}, {0x1FAC,0x1F6C,0x345,0x0}, {0x1FAD,0x1F6D,0x345,0x0}, 
+  {0x1FAE,0x1F6E,0x345,0x0}, {0x1FAF,0x1F6F,0x345,0x0}, {0x1FB0,0x3B1,0x306,0x0}, 
+  {0x1FB1,0x3B1,0x304,0x0}, {0x1FB2,0x1F70,0x345,0x0}, {0x1FB3,0x3B1,0x345,0x0}, 
+  {0x1FB4,0x1F71,0x345,0x0}, {0x1FB6,0x3B1,0x342,0x0}, {0x1FB7,0x1FB6,0x345,0x0}, 
+  {0x1FB8,0x391,0x306,0x0}, {0x1FB9,0x391,0x304,0x0}, {0x1FBA,0x391,0x300,0x0}, 
+  {0x1FBB,0x391,0x301,0x0}, {0x1FBC,0x391,0x345,0x0}, {0x1FBE,0x3B9,0x0,0x0}, 
+  {0x1FC1,0xA8,0x342,0x0}, {0x1FC2,0x1F74,0x345,0x0}, {0x1FC3,0x3B7,0x345,0x0}, 
+  {0x1FC4,0x1F75,0x345,0x0}, {0x1FC6,0x3B7,0x342,0x0}, {0x1FC7,0x1FC6,0x345,0x0}, 
+  {0x1FC8,0x395,0x300,0x0}, {0x1FC9,0x395,0x301,0x0}, {0x1FCA,0x397,0x300,0x0}, 
+  {0x1FCB,0x397,0x301,0x0}, {0x1FCC,0x397,0x345,0x0}, {0x1FCD,0x1FBF,0x300,0x0}, 
+  {0x1FCE,0x1FBF,0x301,0x0}, {0x1FCF,0x1FBF,0x342,0x0}, {0x1FD0,0x3B9,0x306,0x0}, 
+  {0x1FD1,0x3B9,0x304,0x0}, {0x1FD2,0x3CA,0x300,0x0}, {0x1FD3,0x3CA,0x301,0x0}, 
+  {0x1FD6,0x3B9,0x342,0x0}, {0x1FD7,0x3CA,0x342,0x0}, {0x1FD8,0x399,0x306,0x0}, 
+  {0x1FD9,0x399,0x304,0x0}, {0x1FDA,0x399,0x300,0x0}, {0x1FDB,0x399,0x301,0x0}, 
+  {0x1FDD,0x1FFE,0x300,0x0}, {0x1FDE,0x1FFE,0x301,0x0}, {0x1FDF,0x1FFE,0x342,0x0}, 
+  {0x1FE0,0x3C5,0x306,0x0}, {0x1FE1,0x3C5,0x304,0x0}, {0x1FE2,0x3CB,0x300,0x0}, 
+  {0x1FE3,0x3CB,0x301,0x0}, {0x1FE4,0x3C1,0x313,0x0}, {0x1FE5,0x3C1,0x314,0x0}, 
+  {0x1FE6,0x3C5,0x342,0x0}, {0x1FE7,0x3CB,0x342,0x0}, {0x1FE8,0x3A5,0x306,0x0}, 
+  {0x1FE9,0x3A5,0x304,0x0}, {0x1FEA,0x3A5,0x300,0x0}, {0x1FEB,0x3A5,0x301,0x0}, 
+  {0x1FEC,0x3A1,0x314,0x0}, {0x1FED,0xA8,0x300,0x0}, {0x1FEE,0xA8,0x301,0x0}, 
+  {0x1FEF,0x60,0x0,0x0}, {0x1FF2,0x1F7C,0x345,0x0}, {0x1FF3,0x3C9,0x345,0x0}, 
+  {0x1FF4,0x1F79,0x345,0x0}, {0x1FF6,0x3C9,0x342,0x0}, {0x1FF7,0x1FF6,0x345,0x0}, 
+  {0x1FF8,0x39F,0x300,0x0}, {0x1FF9,0x39F,0x301,0x0}, {0x1FFA,0x3A9,0x300,0x0}, 
+  {0x1FFB,0x3A9,0x301,0x0}, {0x1FFC,0x3A9,0x345,0x0}, {0x1FFD,0xB4,0x0,0x0}, 
+  {0x2000,0x2002,0x0,0x0}, {0x2001,0x2003,0x0,0x0}, {0x2126,0x3A9,0x0,0x0}, 
+  {0x212A,0x4B,0x0,0x0}, {0x212B,0xC5,0x0,0x0}, {0x2204,0x2203,0x338,0x0}, 
+  {0x2209,0x2208,0x338,0x0}, {0x220C,0x220B,0x338,0x0}, {0x2224,0x2223,0x338,0x0}, 
+  {0x2226,0x2225,0x338,0x0}, {0x2241,0x7E,0x338,0x0}, {0x2244,0x2243,0x338,0x0}, 
+  {0x2247,0x2245,0x338,0x0}, {0x2249,0x2248,0x338,0x0}, {0x2260,0x3D,0x338,0x0}, 
+  {0x2262,0x2261,0x338,0x0}, {0x226D,0x224D,0x338,0x0}, {0x226E,0x3C,0x338,0x0}, 
+  {0x226F,0x3E,0x338,0x0}, {0x2270,0x2264,0x338,0x0}, {0x2271,0x2265,0x338,0x0}, 
+  {0x2274,0x2272,0x338,0x0}, {0x2275,0x2273,0x338,0x0}, {0x2278,0x2276,0x338,0x0}, 
+  {0x2279,0x2277,0x338,0x0}, {0x2280,0x227A,0x338,0x0}, {0x2281,0x227B,0x338,0x0}, 
+  {0x2284,0x2282,0x338,0x0}, {0x2285,0x2283,0x338,0x0}, {0x2288,0x2286,0x338,0x0}, 
+  {0x2289,0x2287,0x338,0x0}, {0x22AC,0x22A2,0x338,0x0}, {0x22AD,0x22A8,0x338,0x0}, 
+  {0x22AE,0x22A9,0x338,0x0}, {0x22AF,0x22AB,0x338,0x0}, {0x22E0,0x227C,0x338,0x0}, 
+  {0x22E1,0x227D,0x338,0x0}, {0x22E2,0x2291,0x338,0x0}, {0x22E3,0x2292,0x338,0x0}, 
+  {0x22EA,0x22B2,0x338,0x0}, {0x22EB,0x22B3,0x338,0x0}, {0x22EC,0x22B4,0x338,0x0}, 
+  {0x22ED,0x22B5,0x338,0x0}, {0x2329,0x3008,0x0,0x0}, {0x232A,0x3009,0x0,0x0}, 
+  {0x304C,0x304B,0x3099,0x0}, {0x304E,0x304D,0x3099,0x0}, {0x3050,0x304F,0x3099,0x0}, 
+  {0x3052,0x3051,0x3099,0x0}, {0x3054,0x3053,0x3099,0x0}, {0x3056,0x3055,0x3099,0x0}, 
+  {0x3058,0x3057,0x3099,0x0}, {0x305A,0x3059,0x3099,0x0}, {0x305C,0x305B,0x3099,0x0}, 
+  {0x305E,0x305D,0x3099,0x0}, {0x3060,0x305F,0x3099,0x0}, {0x3062,0x3061,0x3099,0x0}, 
+  {0x3065,0x3064,0x3099,0x0}, {0x3067,0x3066,0x3099,0x0}, {0x3069,0x3068,0x3099,0x0}, 
+  {0x3070,0x306F,0x3099,0x0}, {0x3071,0x306F,0x309A,0x0}, {0x3073,0x3072,0x3099,0x0}, 
+  {0x3074,0x3072,0x309A,0x0}, {0x3076,0x3075,0x3099,0x0}, {0x3077,0x3075,0x309A,0x0}, 
+  {0x3079,0x3078,0x3099,0x0}, {0x307A,0x3078,0x309A,0x0}, {0x307C,0x307B,0x3099,0x0}, 
+  {0x307D,0x307B,0x309A,0x0}, {0x3094,0x3046,0x3099,0x0}, {0x309E,0x309D,0x3099,0x0}, 
+  {0x30AC,0x30AB,0x3099,0x0}, {0x30AE,0x30AD,0x3099,0x0}, {0x30B0,0x30AF,0x3099,0x0}, 
+  {0x30B2,0x30B1,0x3099,0x0}, {0x30B4,0x30B3,0x3099,0x0}, {0x30B6,0x30B5,0x3099,0x0}, 
+  {0x30B8,0x30B7,0x3099,0x0}, {0x30BA,0x30B9,0x3099,0x0}, {0x30BC,0x30BB,0x3099,0x0}, 
+  {0x30BE,0x30BD,0x3099,0x0}, {0x30C0,0x30BF,0x3099,0x0}, {0x30C2,0x30C1,0x3099,0x0}, 
+  {0x30C5,0x30C4,0x3099,0x0}, {0x30C7,0x30C6,0x3099,0x0}, {0x30C9,0x30C8,0x3099,0x0}, 
+  {0x30D0,0x30CF,0x3099,0x0}, {0x30D1,0x30CF,0x309A,0x0}, {0x30D3,0x30D2,0x3099,0x0}, 
+  {0x30D4,0x30D2,0x309A,0x0}, {0x30D6,0x30D5,0x3099,0x0}, {0x30D7,0x30D5,0x309A,0x0}, 
+  {0x30D9,0x30D8,0x3099,0x0}, {0x30DA,0x30D8,0x309A,0x0}, {0x30DC,0x30DB,0x3099,0x0}, 
+  {0x30DD,0x30DB,0x309A,0x0}, {0x30F4,0x30A6,0x3099,0x0}, {0x30F7,0x30EF,0x3099,0x0}, 
+  {0x30F8,0x30F0,0x3099,0x0}, {0x30F9,0x30F1,0x3099,0x0}, {0x30FA,0x30F2,0x3099,0x0}, 
+  {0x30FE,0x30FD,0x3099,0x0}, {0xF900,0x8C48,0x0,0x0}, {0xF901,0x66F4,0x0,0x0}, 
+  {0xF902,0x8ECA,0x0,0x0}, {0xF903,0x8CC8,0x0,0x0}, {0xF904,0x6ED1,0x0,0x0}, 
+  {0xF905,0x4E32,0x0,0x0}, {0xF906,0x53E5,0x0,0x0}, {0xF907,0x9F9C,0x0,0x0}, 
+  {0xF908,0x9F9C,0x0,0x0}, {0xF909,0x5951,0x0,0x0}, {0xF90A,0x91D1,0x0,0x0}, 
+  {0xF90B,0x5587,0x0,0x0}, {0xF90C,0x5948,0x0,0x0}, {0xF90D,0x61F6,0x0,0x0}, 
+  {0xF90E,0x7669,0x0,0x0}, {0xF90F,0x7F85,0x0,0x0}, {0xF910,0x863F,0x0,0x0}, 
+  {0xF911,0x87BA,0x0,0x0}, {0xF912,0x88F8,0x0,0x0}, {0xF913,0x908F,0x0,0x0}, 
+  {0xF914,0x6A02,0x0,0x0}, {0xF915,0x6D1B,0x0,0x0}, {0xF916,0x70D9,0x0,0x0}, 
+  {0xF917,0x73DE,0x0,0x0}, {0xF918,0x843D,0x0,0x0}, {0xF919,0x916A,0x0,0x0}, 
+  {0xF91A,0x99F1,0x0,0x0}, {0xF91B,0x4E82,0x0,0x0}, {0xF91C,0x5375,0x0,0x0}, 
+  {0xF91D,0x6B04,0x0,0x0}, {0xF91E,0x721B,0x0,0x0}, {0xF91F,0x862D,0x0,0x0}, 
+  {0xF920,0x9E1E,0x0,0x0}, {0xF921,0x5D50,0x0,0x0}, {0xF922,0x6FEB,0x0,0x0}, 
+  {0xF923,0x85CD,0x0,0x0}, {0xF924,0x8964,0x0,0x0}, {0xF925,0x62C9,0x0,0x0}, 
+  {0xF926,0x81D8,0x0,0x0}, {0xF927,0x881F,0x0,0x0}, {0xF928,0x5ECA,0x0,0x0}, 
+  {0xF929,0x6717,0x0,0x0}, {0xF92A,0x6D6A,0x0,0x0}, {0xF92B,0x72FC,0x0,0x0}, 
+  {0xF92C,0x90CE,0x0,0x0}, {0xF92D,0x4F86,0x0,0x0}, {0xF92E,0x51B7,0x0,0x0}, 
+  {0xF92F,0x52DE,0x0,0x0}, {0xF930,0x64C4,0x0,0x0}, {0xF931,0x6AD3,0x0,0x0}, 
+  {0xF932,0x7210,0x0,0x0}, {0xF933,0x76E7,0x0,0x0}, {0xF934,0x8001,0x0,0x0}, 
+  {0xF935,0x8606,0x0,0x0}, {0xF936,0x865C,0x0,0x0}, {0xF937,0x8DEF,0x0,0x0}, 
+  {0xF938,0x9732,0x0,0x0}, {0xF939,0x9B6F,0x0,0x0}, {0xF93A,0x9DFA,0x0,0x0}, 
+  {0xF93B,0x788C,0x0,0x0}, {0xF93C,0x797F,0x0,0x0}, {0xF93D,0x7DA0,0x0,0x0}, 
+  {0xF93E,0x83C9,0x0,0x0}, {0xF93F,0x9304,0x0,0x0}, {0xF940,0x9E7F,0x0,0x0}, 
+  {0xF941,0x8AD6,0x0,0x0}, {0xF942,0x58DF,0x0,0x0}, {0xF943,0x5F04,0x0,0x0}, 
+  {0xF944,0x7C60,0x0,0x0}, {0xF945,0x807E,0x0,0x0}, {0xF946,0x7262,0x0,0x0}, 
+  {0xF947,0x78CA,0x0,0x0}, {0xF948,0x8CC2,0x0,0x0}, {0xF949,0x96F7,0x0,0x0}, 
+  {0xF94A,0x58D8,0x0,0x0}, {0xF94B,0x5C62,0x0,0x0}, {0xF94C,0x6A13,0x0,0x0}, 
+  {0xF94D,0x6DDA,0x0,0x0}, {0xF94E,0x6F0F,0x0,0x0}, {0xF94F,0x7D2F,0x0,0x0}, 
+  {0xF950,0x7E37,0x0,0x0}, {0xF951,0x96FB,0x0,0x0}, {0xF952,0x52D2,0x0,0x0}, 
+  {0xF953,0x808B,0x0,0x0}, {0xF954,0x51DC,0x0,0x0}, {0xF955,0x51CC,0x0,0x0}, 
+  {0xF956,0x7A1C,0x0,0x0}, {0xF957,0x7DBE,0x0,0x0}, {0xF958,0x83F1,0x0,0x0}, 
+  {0xF959,0x9675,0x0,0x0}, {0xF95A,0x8B80,0x0,0x0}, {0xF95B,0x62CF,0x0,0x0}, 
+  {0xF95C,0x6A02,0x0,0x0}, {0xF95D,0x8AFE,0x0,0x0}, {0xF95E,0x4E39,0x0,0x0}, 
+  {0xF95F,0x5BE7,0x0,0x0}, {0xF960,0x6012,0x0,0x0}, {0xF961,0x7387,0x0,0x0}, 
+  {0xF962,0x7570,0x0,0x0}, {0xF963,0x5317,0x0,0x0}, {0xF964,0x78FB,0x0,0x0}, 
+  {0xF965,0x4FBF,0x0,0x0}, {0xF966,0x5FA9,0x0,0x0}, {0xF967,0x4E0D,0x0,0x0}, 
+  {0xF968,0x6CCC,0x0,0x0}, {0xF969,0x6578,0x0,0x0}, {0xF96A,0x7D22,0x0,0x0}, 
+  {0xF96B,0x53C3,0x0,0x0}, {0xF96C,0x585E,0x0,0x0}, {0xF96D,0x7701,0x0,0x0}, 
+  {0xF96E,0x8449,0x0,0x0}, {0xF96F,0x8AAA,0x0,0x0}, {0xF970,0x6BBA,0x0,0x0}, 
+  {0xF971,0x8FB0,0x0,0x0}, {0xF972,0x6C88,0x0,0x0}, {0xF973,0x62FE,0x0,0x0}, 
+  {0xF974,0x82E5,0x0,0x0}, {0xF975,0x63A0,0x0,0x0}, {0xF976,0x7565,0x0,0x0}, 
+  {0xF977,0x4EAE,0x0,0x0}, {0xF978,0x5169,0x0,0x0}, {0xF979,0x51C9,0x0,0x0}, 
+  {0xF97A,0x6881,0x0,0x0}, {0xF97B,0x7CE7,0x0,0x0}, {0xF97C,0x826F,0x0,0x0}, 
+  {0xF97D,0x8AD2,0x0,0x0}, {0xF97E,0x91CF,0x0,0x0}, {0xF97F,0x52F5,0x0,0x0}, 
+  {0xF980,0x5442,0x0,0x0}, {0xF981,0x5973,0x0,0x0}, {0xF982,0x5EEC,0x0,0x0}, 
+  {0xF983,0x65C5,0x0,0x0}, {0xF984,0x6FFE,0x0,0x0}, {0xF985,0x792A,0x0,0x0}, 
+  {0xF986,0x95AD,0x0,0x0}, {0xF987,0x9A6A,0x0,0x0}, {0xF988,0x9E97,0x0,0x0}, 
+  {0xF989,0x9ECE,0x0,0x0}, {0xF98A,0x529B,0x0,0x0}, {0xF98B,0x66C6,0x0,0x0}, 
+  {0xF98C,0x6B77,0x0,0x0}, {0xF98D,0x8F62,0x0,0x0}, {0xF98E,0x5E74,0x0,0x0}, 
+  {0xF98F,0x6190,0x0,0x0}, {0xF990,0x6200,0x0,0x0}, {0xF991,0x649A,0x0,0x0}, 
+  {0xF992,0x6F23,0x0,0x0}, {0xF993,0x7149,0x0,0x0}, {0xF994,0x7489,0x0,0x0}, 
+  {0xF995,0x79CA,0x0,0x0}, {0xF996,0x7DF4,0x0,0x0}, {0xF997,0x806F,0x0,0x0}, 
+  {0xF998,0x8F26,0x0,0x0}, {0xF999,0x84EE,0x0,0x0}, {0xF99A,0x9023,0x0,0x0}, 
+  {0xF99B,0x934A,0x0,0x0}, {0xF99C,0x5217,0x0,0x0}, {0xF99D,0x52A3,0x0,0x0}, 
+  {0xF99E,0x54BD,0x0,0x0}, {0xF99F,0x70C8,0x0,0x0}, {0xF9A0,0x88C2,0x0,0x0}, 
+  {0xF9A1,0x8AAA,0x0,0x0}, {0xF9A2,0x5EC9,0x0,0x0}, {0xF9A3,0x5FF5,0x0,0x0}, 
+  {0xF9A4,0x637B,0x0,0x0}, {0xF9A5,0x6BAE,0x0,0x0}, {0xF9A6,0x7C3E,0x0,0x0}, 
+  {0xF9A7,0x7375,0x0,0x0}, {0xF9A8,0x4EE4,0x0,0x0}, {0xF9A9,0x56F9,0x0,0x0}, 
+  {0xF9AA,0x5BE7,0x0,0x0}, {0xF9AB,0x5DBA,0x0,0x0}, {0xF9AC,0x601C,0x0,0x0}, 
+  {0xF9AD,0x73B2,0x0,0x0}, {0xF9AE,0x7469,0x0,0x0}, {0xF9AF,0x7F9A,0x0,0x0}, 
+  {0xF9B0,0x8046,0x0,0x0}, {0xF9B1,0x9234,0x0,0x0}, {0xF9B2,0x96F6,0x0,0x0}, 
+  {0xF9B3,0x9748,0x0,0x0}, {0xF9B4,0x9818,0x0,0x0}, {0xF9B5,0x4F8B,0x0,0x0}, 
+  {0xF9B6,0x79AE,0x0,0x0}, {0xF9B7,0x91B4,0x0,0x0}, {0xF9B8,0x96B8,0x0,0x0}, 
+  {0xF9B9,0x60E1,0x0,0x0}, {0xF9BA,0x4E86,0x0,0x0}, {0xF9BB,0x50DA,0x0,0x0}, 
+  {0xF9BC,0x5BEE,0x0,0x0}, {0xF9BD,0x5C3F,0x0,0x0}, {0xF9BE,0x6599,0x0,0x0}, 
+  {0xF9BF,0x6A02,0x0,0x0}, {0xF9C0,0x71CE,0x0,0x0}, {0xF9C1,0x7642,0x0,0x0}, 
+  {0xF9C2,0x84FC,0x0,0x0}, {0xF9C3,0x907C,0x0,0x0}, {0xF9C4,0x9F8D,0x0,0x0}, 
+  {0xF9C5,0x6688,0x0,0x0}, {0xF9C6,0x962E,0x0,0x0}, {0xF9C7,0x5289,0x0,0x0}, 
+  {0xF9C8,0x677B,0x0,0x0}, {0xF9C9,0x67F3,0x0,0x0}, {0xF9CA,0x6D41,0x0,0x0}, 
+  {0xF9CB,0x6E9C,0x0,0x0}, {0xF9CC,0x7409,0x0,0x0}, {0xF9CD,0x7559,0x0,0x0}, 
+  {0xF9CE,0x786B,0x0,0x0}, {0xF9CF,0x7D10,0x0,0x0}, {0xF9D0,0x985E,0x0,0x0}, 
+  {0xF9D1,0x516D,0x0,0x0}, {0xF9D2,0x622E,0x0,0x0}, {0xF9D3,0x9678,0x0,0x0}, 
+  {0xF9D4,0x502B,0x0,0x0}, {0xF9D5,0x5D19,0x0,0x0}, {0xF9D6,0x6DEA,0x0,0x0}, 
+  {0xF9D7,0x8F2A,0x0,0x0}, {0xF9D8,0x5F8B,0x0,0x0}, {0xF9D9,0x6144,0x0,0x0}, 
+  {0xF9DA,0x6817,0x0,0x0}, {0xF9DB,0x7387,0x0,0x0}, {0xF9DC,0x9686,0x0,0x0}, 
+  {0xF9DD,0x5229,0x0,0x0}, {0xF9DE,0x540F,0x0,0x0}, {0xF9DF,0x5C65,0x0,0x0}, 
+  {0xF9E0,0x6613,0x0,0x0}, {0xF9E1,0x674E,0x0,0x0}, {0xF9E2,0x68A8,0x0,0x0}, 
+  {0xF9E3,0x6CE5,0x0,0x0}, {0xF9E4,0x7406,0x0,0x0}, {0xF9E5,0x75E2,0x0,0x0}, 
+  {0xF9E6,0x7F79,0x0,0x0}, {0xF9E7,0x88CF,0x0,0x0}, {0xF9E8,0x88E1,0x0,0x0}, 
+  {0xF9E9,0x91CC,0x0,0x0}, {0xF9EA,0x96E2,0x0,0x0}, {0xF9EB,0x533F,0x0,0x0}, 
+  {0xF9EC,0x6EBA,0x0,0x0}, {0xF9ED,0x541D,0x0,0x0}, {0xF9EE,0x71D0,0x0,0x0}, 
+  {0xF9EF,0x7498,0x0,0x0}, {0xF9F0,0x85FA,0x0,0x0}, {0xF9F1,0x96A3,0x0,0x0}, 
+  {0xF9F2,0x9C57,0x0,0x0}, {0xF9F3,0x9E9F,0x0,0x0}, {0xF9F4,0x6797,0x0,0x0}, 
+  {0xF9F5,0x6DCB,0x0,0x0}, {0xF9F6,0x81E8,0x0,0x0}, {0xF9F7,0x7ACB,0x0,0x0}, 
+  {0xF9F8,0x7B20,0x0,0x0}, {0xF9F9,0x7C92,0x0,0x0}, {0xF9FA,0x72C0,0x0,0x0}, 
+  {0xF9FB,0x7099,0x0,0x0}, {0xF9FC,0x8B58,0x0,0x0}, {0xF9FD,0x4EC0,0x0,0x0}, 
+  {0xF9FE,0x8336,0x0,0x0}, {0xF9FF,0x523A,0x0,0x0}, {0xFA00,0x5207,0x0,0x0}, 
+  {0xFA01,0x5EA6,0x0,0x0}, {0xFA02,0x62D3,0x0,0x0}, {0xFA03,0x7CD6,0x0,0x0}, 
+  {0xFA04,0x5B85,0x0,0x0}, {0xFA05,0x6D1E,0x0,0x0}, {0xFA06,0x66B4,0x0,0x0}, 
+  {0xFA07,0x8F3B,0x0,0x0}, {0xFA08,0x884C,0x0,0x0}, {0xFA09,0x964D,0x0,0x0}, 
+  {0xFA0A,0x898B,0x0,0x0}, {0xFA0B,0x5ED3,0x0,0x0}, {0xFA0C,0x5140,0x0,0x0}, 
+  {0xFA0D,0x55C0,0x0,0x0}, {0xFA10,0x585A,0x0,0x0}, {0xFA12,0x6674,0x0,0x0}, 
+  {0xFA15,0x51DE,0x0,0x0}, {0xFA16,0x732A,0x0,0x0}, {0xFA17,0x76CA,0x0,0x0}, 
+  {0xFA18,0x793C,0x0,0x0}, {0xFA19,0x795E,0x0,0x0}, {0xFA1A,0x7965,0x0,0x0}, 
+  {0xFA1B,0x798F,0x0,0x0}, {0xFA1C,0x9756,0x0,0x0}, {0xFA1D,0x7CBE,0x0,0x0}, 
+  {0xFA1E,0x7FBD,0x0,0x0}, {0xFA20,0x8612,0x0,0x0}, {0xFA22,0x8AF8,0x0,0x0}, 
+  {0xFA25,0x9038,0x0,0x0}, {0xFA26,0x90FD,0x0,0x0}, {0xFA2A,0x98EF,0x0,0x0}, 
+  {0xFA2B,0x98FC,0x0,0x0}, {0xFA2C,0x9928,0x0,0x0}, {0xFA2D,0x9DB4,0x0,0x0}, 
+  {0xFB1F,0x5F2,0x5B7,0x0}, {0xFB2A,0x5E9,0x5C1,0x0}, {0xFB2B,0x5E9,0x5C2,0x0}, 
+  {0xFB2C,0x5E9,0x5BC,0x5C1}, {0xFB2D,0x5E9,0x5BC,0x5C2}, {0xFB2E,0x5D0,0x5B7,0x0}, 
+  {0xFB2F,0x5D0,0x5B8,0x0}, {0xFB30,0x5D0,0x5BC,0x0}, {0xFB31,0x5D1,0x5BC,0x0}, 
+  {0xFB32,0x5D2,0x5BC,0x0}, {0xFB33,0x5D3,0x5BC,0x0}, {0xFB34,0x5D4,0x5BC,0x0}, 
+  {0xFB35,0x5D5,0x5BC,0x0}, {0xFB36,0x5D6,0x5BC,0x0}, {0xFB38,0x5D8,0x5BC,0x0}, 
+  {0xFB39,0x5D9,0x5BC,0x0}, {0xFB3A,0x5DA,0x5BC,0x0}, {0xFB3B,0x5DB,0x5BC,0x0}, 
+  {0xFB3C,0x5DC,0x5BC,0x0}, {0xFB3E,0x5DE,0x5BC,0x0}, {0xFB40,0x5E0,0x5BC,0x0}, 
+  {0xFB41,0x5E1,0x5BC,0x0}, {0xFB43,0x5E3,0x5BC,0x0}, {0xFB44,0x5E4,0x5BC,0x0}, 
+  {0xFB46,0x5E6,0x5BC,0x0}, {0xFB47,0x5E7,0x5BC,0x0}, {0xFB48,0x5E8,0x5BC,0x0}, 
+  {0xFB49,0x5E9,0x5BC,0x0}, {0xFB4A,0x5EA,0x5BC,0x0}, {0xFB4B,0x5D5,0x5B9,0x0}, 
+  {0xFB4C,0x5D1,0x5BF,0x0}, {0xFB4D,0x5DB,0x5BF,0x0}, {0xFB4E,0x5E4,0x5BF,0x0} 
+};
+
+
+/* All upper-case translations are included here */
+
+#define NUM_TOUPPER_INFO 677
+static const unirelate toupper_info[NUM_TOUPPER_INFO] = {
+  {0x61,0x41}, {0x62,0x42}, {0x63,0x43}, {0x64,0x44}, {0x65,0x45}, 
+  {0x66,0x46}, {0x67,0x47}, {0x68,0x48}, {0x69,0x49}, {0x6A,0x4A}, 
+  {0x6B,0x4B}, {0x6C,0x4C}, {0x6D,0x4D}, {0x6E,0x4E}, {0x6F,0x4F}, 
+  {0x70,0x50}, {0x71,0x51}, {0x72,0x52}, {0x73,0x53}, {0x74,0x54}, 
+  {0x75,0x55}, {0x76,0x56}, {0x77,0x57}, {0x78,0x58}, {0x79,0x59}, 
+  {0x7A,0x5A}, {0xE0,0xC0}, {0xE1,0xC1}, {0xE2,0xC2}, {0xE3,0xC3}, 
+  {0xE4,0xC4}, {0xE5,0xC5}, {0xE6,0xC6}, {0xE7,0xC7}, {0xE8,0xC8}, 
+  {0xE9,0xC9}, {0xEA,0xCA}, {0xEB,0xCB}, {0xEC,0xCC}, {0xED,0xCD}, 
+  {0xEE,0xCE}, {0xEF,0xCF}, {0xF0,0xD0}, {0xF1,0xD1}, {0xF2,0xD2}, 
+  {0xF3,0xD3}, {0xF4,0xD4}, {0xF5,0xD5}, {0xF6,0xD6}, {0xF8,0xD8}, 
+  {0xF9,0xD9}, {0xFA,0xDA}, {0xFB,0xDB}, {0xFC,0xDC}, {0xFD,0xDD}, 
+  {0xFE,0xDE}, {0xFF,0x178}, {0x101,0x100}, {0x103,0x102}, {0x105,0x104}, 
+  {0x107,0x106}, {0x109,0x108}, {0x10B,0x10A}, {0x10D,0x10C}, {0x10F,0x10E}, 
+  {0x111,0x110}, {0x113,0x112}, {0x115,0x114}, {0x117,0x116}, {0x119,0x118}, 
+  {0x11B,0x11A}, {0x11D,0x11C}, {0x11F,0x11E}, {0x121,0x120}, {0x123,0x122}, 
+  {0x125,0x124}, {0x127,0x126}, {0x129,0x128}, {0x12B,0x12A}, {0x12D,0x12C}, 
+  {0x12F,0x12E}, {0x131,0x49}, {0x133,0x132}, {0x135,0x134}, {0x137,0x136}, 
+  {0x13A,0x139}, {0x13C,0x13B}, {0x13E,0x13D}, {0x140,0x13F}, {0x142,0x141}, 
+  {0x144,0x143}, {0x146,0x145}, {0x148,0x147}, {0x14B,0x14A}, {0x14D,0x14C}, 
+  {0x14F,0x14E}, {0x151,0x150}, {0x153,0x152}, {0x155,0x154}, {0x157,0x156}, 
+  {0x159,0x158}, {0x15B,0x15A}, {0x15D,0x15C}, {0x15F,0x15E}, {0x161,0x160}, 
+  {0x163,0x162}, {0x165,0x164}, {0x167,0x166}, {0x169,0x168}, {0x16B,0x16A}, 
+  {0x16D,0x16C}, {0x16F,0x16E}, {0x171,0x170}, {0x173,0x172}, {0x175,0x174}, 
+  {0x177,0x176}, {0x17A,0x179}, {0x17C,0x17B}, {0x17E,0x17D}, {0x17F,0x53}, 
+  {0x183,0x182}, {0x185,0x184}, {0x188,0x187}, {0x18C,0x18B}, {0x192,0x191}, 
+  {0x199,0x198}, {0x1A1,0x1A0}, {0x1A3,0x1A2}, {0x1A5,0x1A4}, {0x1A8,0x1A7}, 
+  {0x1AD,0x1AC}, {0x1B0,0x1AF}, {0x1B4,0x1B3}, {0x1B6,0x1B5}, {0x1B9,0x1B8}, 
+  {0x1BD,0x1BC}, {0x1C5,0x1C4}, {0x1C6,0x1C4}, {0x1C8,0x1C7}, {0x1C9,0x1C7}, 
+  {0x1CB,0x1CA}, {0x1CC,0x1CA}, {0x1CE,0x1CD}, {0x1D0,0x1CF}, {0x1D2,0x1D1}, 
+  {0x1D4,0x1D3}, {0x1D6,0x1D5}, {0x1D8,0x1D7}, {0x1DA,0x1D9}, {0x1DC,0x1DB}, 
+  {0x1DD,0x18E}, {0x1DF,0x1DE}, {0x1E1,0x1E0}, {0x1E3,0x1E2}, {0x1E5,0x1E4}, 
+  {0x1E7,0x1E6}, {0x1E9,0x1E8}, {0x1EB,0x1EA}, {0x1ED,0x1EC}, {0x1EF,0x1EE}, 
+  {0x1F2,0x1F1}, {0x1F3,0x1F1}, {0x1F5,0x1F4}, {0x1FB,0x1FA}, {0x1FD,0x1FC}, 
+  {0x1FF,0x1FE}, {0x201,0x200}, {0x203,0x202}, {0x205,0x204}, {0x207,0x206}, 
+  {0x209,0x208}, {0x20B,0x20A}, {0x20D,0x20C}, {0x20F,0x20E}, {0x211,0x210}, 
+  {0x213,0x212}, {0x215,0x214}, {0x217,0x216}, {0x253,0x181}, {0x254,0x186}, 
+  {0x256,0x189}, {0x257,0x18A}, {0x259,0x18F}, {0x25B,0x190}, {0x260,0x193}, 
+  {0x263,0x194}, {0x268,0x197}, {0x269,0x196}, {0x26F,0x19C}, {0x272,0x19D}, 
+  {0x275,0x19F}, {0x283,0x1A9}, {0x288,0x1AE}, {0x28A,0x1B1}, {0x28B,0x1B2}, 
+  {0x292,0x1B7}, {0x3AC,0x386}, {0x3AD,0x388}, {0x3AE,0x389}, {0x3AF,0x38A}, 
+  {0x3B1,0x391}, {0x3B2,0x392}, {0x3B3,0x393}, {0x3B4,0x394}, {0x3B5,0x395}, 
+  {0x3B6,0x396}, {0x3B7,0x397}, {0x3B8,0x398}, {0x3B9,0x399}, {0x3BA,0x39A}, 
+  {0x3BB,0x39B}, {0x3BC,0x39C}, {0x3BD,0x39D}, {0x3BE,0x39E}, {0x3BF,0x39F}, 
+  {0x3C0,0x3A0}, {0x3C1,0x3A1}, {0x3C2,0x3A3}, {0x3C3,0x3A3}, {0x3C4,0x3A4}, 
+  {0x3C5,0x3A5}, {0x3C6,0x3A6}, {0x3C7,0x3A7}, {0x3C8,0x3A8}, {0x3C9,0x3A9}, 
+  {0x3CA,0x3AA}, {0x3CB,0x3AB}, {0x3CC,0x38C}, {0x3CD,0x38E}, {0x3CE,0x38F}, 
+  {0x3D0,0x392}, {0x3D1,0x398}, {0x3D5,0x3A6}, {0x3D6,0x3A0}, {0x3E3,0x3E2}, 
+  {0x3E5,0x3E4}, {0x3E7,0x3E6}, {0x3E9,0x3E8}, {0x3EB,0x3EA}, {0x3ED,0x3EC}, 
+  {0x3EF,0x3EE}, {0x3F0,0x39A}, {0x3F1,0x3A1}, {0x3F2,0x3A3}, {0x430,0x410}, 
+  {0x431,0x411}, {0x432,0x412}, {0x433,0x413}, {0x434,0x414}, {0x435,0x415}, 
+  {0x436,0x416}, {0x437,0x417}, {0x438,0x418}, {0x439,0x419}, {0x43A,0x41A}, 
+  {0x43B,0x41B}, {0x43C,0x41C}, {0x43D,0x41D}, {0x43E,0x41E}, {0x43F,0x41F}, 
+  {0x440,0x420}, {0x441,0x421}, {0x442,0x422}, {0x443,0x423}, {0x444,0x424}, 
+  {0x445,0x425}, {0x446,0x426}, {0x447,0x427}, {0x448,0x428}, {0x449,0x429}, 
+  {0x44A,0x42A}, {0x44B,0x42B}, {0x44C,0x42C}, {0x44D,0x42D}, {0x44E,0x42E}, 
+  {0x44F,0x42F}, {0x451,0x401}, {0x452,0x402}, {0x453,0x403}, {0x454,0x404}, 
+  {0x455,0x405}, {0x456,0x406}, {0x457,0x407}, {0x458,0x408}, {0x459,0x409}, 
+  {0x45A,0x40A}, {0x45B,0x40B}, {0x45C,0x40C}, {0x45E,0x40E}, {0x45F,0x40F}, 
+  {0x461,0x460}, {0x463,0x462}, {0x465,0x464}, {0x467,0x466}, {0x469,0x468}, 
+  {0x46B,0x46A}, {0x46D,0x46C}, {0x46F,0x46E}, {0x471,0x470}, {0x473,0x472}, 
+  {0x475,0x474}, {0x477,0x476}, {0x479,0x478}, {0x47B,0x47A}, {0x47D,0x47C}, 
+  {0x47F,0x47E}, {0x481,0x480}, {0x491,0x490}, {0x493,0x492}, {0x495,0x494}, 
+  {0x497,0x496}, {0x499,0x498}, {0x49B,0x49A}, {0x49D,0x49C}, {0x49F,0x49E}, 
+  {0x4A1,0x4A0}, {0x4A3,0x4A2}, {0x4A5,0x4A4}, {0x4A7,0x4A6}, {0x4A9,0x4A8}, 
+  {0x4AB,0x4AA}, {0x4AD,0x4AC}, {0x4AF,0x4AE}, {0x4B1,0x4B0}, {0x4B3,0x4B2}, 
+  {0x4B5,0x4B4}, {0x4B7,0x4B6}, {0x4B9,0x4B8}, {0x4BB,0x4BA}, {0x4BD,0x4BC}, 
+  {0x4BF,0x4BE}, {0x4C2,0x4C1}, {0x4C4,0x4C3}, {0x4C8,0x4C7}, {0x4CC,0x4CB}, 
+  {0x4D1,0x4D0}, {0x4D3,0x4D2}, {0x4D5,0x4D4}, {0x4D7,0x4D6}, {0x4D9,0x4D8}, 
+  {0x4DB,0x4DA}, {0x4DD,0x4DC}, {0x4DF,0x4DE}, {0x4E1,0x4E0}, {0x4E3,0x4E2}, 
+  {0x4E5,0x4E4}, {0x4E7,0x4E6}, {0x4E9,0x4E8}, {0x4EB,0x4EA}, {0x4EF,0x4EE}, 
+  {0x4F1,0x4F0}, {0x4F3,0x4F2}, {0x4F5,0x4F4}, {0x4F9,0x4F8}, {0x561,0x531}, 
+  {0x562,0x532}, {0x563,0x533}, {0x564,0x534}, {0x565,0x535}, {0x566,0x536}, 
+  {0x567,0x537}, {0x568,0x538}, {0x569,0x539}, {0x56A,0x53A}, {0x56B,0x53B}, 
+  {0x56C,0x53C}, {0x56D,0x53D}, {0x56E,0x53E}, {0x56F,0x53F}, {0x570,0x540}, 
+  {0x571,0x541}, {0x572,0x542}, {0x573,0x543}, {0x574,0x544}, {0x575,0x545}, 
+  {0x576,0x546}, {0x577,0x547}, {0x578,0x548}, {0x579,0x549}, {0x57A,0x54A}, 
+  {0x57B,0x54B}, {0x57C,0x54C}, {0x57D,0x54D}, {0x57E,0x54E}, {0x57F,0x54F}, 
+  {0x580,0x550}, {0x581,0x551}, {0x582,0x552}, {0x583,0x553}, {0x584,0x554}, 
+  {0x585,0x555}, {0x586,0x556}, {0x1E01,0x1E00}, {0x1E03,0x1E02}, {0x1E05,0x1E04}, 
+  {0x1E07,0x1E06}, {0x1E09,0x1E08}, {0x1E0B,0x1E0A}, {0x1E0D,0x1E0C}, {0x1E0F,0x1E0E}, 
+  {0x1E11,0x1E10}, {0x1E13,0x1E12}, {0x1E15,0x1E14}, {0x1E17,0x1E16}, {0x1E19,0x1E18}, 
+  {0x1E1B,0x1E1A}, {0x1E1D,0x1E1C}, {0x1E1F,0x1E1E}, {0x1E21,0x1E20}, {0x1E23,0x1E22}, 
+  {0x1E25,0x1E24}, {0x1E27,0x1E26}, {0x1E29,0x1E28}, {0x1E2B,0x1E2A}, {0x1E2D,0x1E2C}, 
+  {0x1E2F,0x1E2E}, {0x1E31,0x1E30}, {0x1E33,0x1E32}, {0x1E35,0x1E34}, {0x1E37,0x1E36}, 
+  {0x1E39,0x1E38}, {0x1E3B,0x1E3A}, {0x1E3D,0x1E3C}, {0x1E3F,0x1E3E}, {0x1E41,0x1E40}, 
+  {0x1E43,0x1E42}, {0x1E45,0x1E44}, {0x1E47,0x1E46}, {0x1E49,0x1E48}, {0x1E4B,0x1E4A}, 
+  {0x1E4D,0x1E4C}, {0x1E4F,0x1E4E}, {0x1E51,0x1E50}, {0x1E53,0x1E52}, {0x1E55,0x1E54}, 
+  {0x1E57,0x1E56}, {0x1E59,0x1E58}, {0x1E5B,0x1E5A}, {0x1E5D,0x1E5C}, {0x1E5F,0x1E5E}, 
+  {0x1E61,0x1E60}, {0x1E63,0x1E62}, {0x1E65,0x1E64}, {0x1E67,0x1E66}, {0x1E69,0x1E68}, 
+  {0x1E6B,0x1E6A}, {0x1E6D,0x1E6C}, {0x1E6F,0x1E6E}, {0x1E71,0x1E70}, {0x1E73,0x1E72}, 
+  {0x1E75,0x1E74}, {0x1E77,0x1E76}, {0x1E79,0x1E78}, {0x1E7B,0x1E7A}, {0x1E7D,0x1E7C}, 
+  {0x1E7F,0x1E7E}, {0x1E81,0x1E80}, {0x1E83,0x1E82}, {0x1E85,0x1E84}, {0x1E87,0x1E86}, 
+  {0x1E89,0x1E88}, {0x1E8B,0x1E8A}, {0x1E8D,0x1E8C}, {0x1E8F,0x1E8E}, {0x1E91,0x1E90}, 
+  {0x1E93,0x1E92}, {0x1E95,0x1E94}, {0x1E9B,0x1E60}, {0x1EA1,0x1EA0}, {0x1EA3,0x1EA2}, 
+  {0x1EA5,0x1EA4}, {0x1EA7,0x1EA6}, {0x1EA9,0x1EA8}, {0x1EAB,0x1EAA}, {0x1EAD,0x1EAC}, 
+  {0x1EAF,0x1EAE}, {0x1EB1,0x1EB0}, {0x1EB3,0x1EB2}, {0x1EB5,0x1EB4}, {0x1EB7,0x1EB6}, 
+  {0x1EB9,0x1EB8}, {0x1EBB,0x1EBA}, {0x1EBD,0x1EBC}, {0x1EBF,0x1EBE}, {0x1EC1,0x1EC0}, 
+  {0x1EC3,0x1EC2}, {0x1EC5,0x1EC4}, {0x1EC7,0x1EC6}, {0x1EC9,0x1EC8}, {0x1ECB,0x1ECA}, 
+  {0x1ECD,0x1ECC}, {0x1ECF,0x1ECE}, {0x1ED1,0x1ED0}, {0x1ED3,0x1ED2}, {0x1ED5,0x1ED4}, 
+  {0x1ED7,0x1ED6}, {0x1ED9,0x1ED8}, {0x1EDB,0x1EDA}, {0x1EDD,0x1EDC}, {0x1EDF,0x1EDE}, 
+  {0x1EE1,0x1EE0}, {0x1EE3,0x1EE2}, {0x1EE5,0x1EE4}, {0x1EE7,0x1EE6}, {0x1EE9,0x1EE8}, 
+  {0x1EEB,0x1EEA}, {0x1EED,0x1EEC}, {0x1EEF,0x1EEE}, {0x1EF1,0x1EF0}, {0x1EF3,0x1EF2}, 
+  {0x1EF5,0x1EF4}, {0x1EF7,0x1EF6}, {0x1EF9,0x1EF8}, {0x1F00,0x1F08}, {0x1F01,0x1F09}, 
+  {0x1F02,0x1F0A}, {0x1F03,0x1F0B}, {0x1F04,0x1F0C}, {0x1F05,0x1F0D}, {0x1F06,0x1F0E}, 
+  {0x1F07,0x1F0F}, {0x1F10,0x1F18}, {0x1F11,0x1F19}, {0x1F12,0x1F1A}, {0x1F13,0x1F1B}, 
+  {0x1F14,0x1F1C}, {0x1F15,0x1F1D}, {0x1F20,0x1F28}, {0x1F21,0x1F29}, {0x1F22,0x1F2A}, 
+  {0x1F23,0x1F2B}, {0x1F24,0x1F2C}, {0x1F25,0x1F2D}, {0x1F26,0x1F2E}, {0x1F27,0x1F2F}, 
+  {0x1F30,0x1F38}, {0x1F31,0x1F39}, {0x1F32,0x1F3A}, {0x1F33,0x1F3B}, {0x1F34,0x1F3C}, 
+  {0x1F35,0x1F3D}, {0x1F36,0x1F3E}, {0x1F37,0x1F3F}, {0x1F40,0x1F48}, {0x1F41,0x1F49}, 
+  {0x1F42,0x1F4A}, {0x1F43,0x1F4B}, {0x1F44,0x1F4C}, {0x1F45,0x1F4D}, {0x1F51,0x1F59}, 
+  {0x1F53,0x1F5B}, {0x1F55,0x1F5D}, {0x1F57,0x1F5F}, {0x1F60,0x1F68}, {0x1F61,0x1F69}, 
+  {0x1F62,0x1F6A}, {0x1F63,0x1F6B}, {0x1F64,0x1F6C}, {0x1F65,0x1F6D}, {0x1F66,0x1F6E}, 
+  {0x1F67,0x1F6F}, {0x1F70,0x1FBA}, {0x1F71,0x1FBB}, {0x1F72,0x1FC8}, {0x1F73,0x1FC9}, 
+  {0x1F74,0x1FCA}, {0x1F75,0x1FCB}, {0x1F76,0x1FDA}, {0x1F77,0x1FDB}, {0x1F78,0x1FF8}, 
+  {0x1F79,0x1FF9}, {0x1F7A,0x1FEA}, {0x1F7B,0x1FEB}, {0x1F7C,0x1FFA}, {0x1F7D,0x1FFB}, 
+  {0x1F80,0x1F88}, {0x1F81,0x1F89}, {0x1F82,0x1F8A}, {0x1F83,0x1F8B}, {0x1F84,0x1F8C}, 
+  {0x1F85,0x1F8D}, {0x1F86,0x1F8E}, {0x1F87,0x1F8F}, {0x1F90,0x1F98}, {0x1F91,0x1F99}, 
+  {0x1F92,0x1F9A}, {0x1F93,0x1F9B}, {0x1F94,0x1F9C}, {0x1F95,0x1F9D}, {0x1F96,0x1F9E}, 
+  {0x1F97,0x1F9F}, {0x1FA0,0x1FA8}, {0x1FA1,0x1FA9}, {0x1FA2,0x1FAA}, {0x1FA3,0x1FAB}, 
+  {0x1FA4,0x1FAC}, {0x1FA5,0x1FAD}, {0x1FA6,0x1FAE}, {0x1FA7,0x1FAF}, {0x1FB0,0x1FB8}, 
+  {0x1FB1,0x1FB9}, {0x1FB3,0x1FBC}, {0x1FC3,0x1FCC}, {0x1FD0,0x1FD8}, {0x1FD1,0x1FD9}, 
+  {0x1FE0,0x1FE8}, {0x1FE1,0x1FE9}, {0x1FE5,0x1FEC}, {0x1FF3,0x1FFC}, {0x2170,0x2160}, 
+  {0x2171,0x2161}, {0x2172,0x2162}, {0x2173,0x2163}, {0x2174,0x2164}, {0x2175,0x2165}, 
+  {0x2176,0x2166}, {0x2177,0x2167}, {0x2178,0x2168}, {0x2179,0x2169}, {0x217A,0x216A}, 
+  {0x217B,0x216B}, {0x217C,0x216C}, {0x217D,0x216D}, {0x217E,0x216E}, {0x217F,0x216F}, 
+  {0x24D0,0x24B6}, {0x24D1,0x24B7}, {0x24D2,0x24B8}, {0x24D3,0x24B9}, {0x24D4,0x24BA}, 
+  {0x24D5,0x24BB}, {0x24D6,0x24BC}, {0x24D7,0x24BD}, {0x24D8,0x24BE}, {0x24D9,0x24BF}, 
+  {0x24DA,0x24C0}, {0x24DB,0x24C1}, {0x24DC,0x24C2}, {0x24DD,0x24C3}, {0x24DE,0x24C4}, 
+  {0x24DF,0x24C5}, {0x24E0,0x24C6}, {0x24E1,0x24C7}, {0x24E2,0x24C8}, {0x24E3,0x24C9}, 
+  {0x24E4,0x24CA}, {0x24E5,0x24CB}, {0x24E6,0x24CC}, {0x24E7,0x24CD}, {0x24E8,0x24CE}, 
+  {0x24E9,0x24CF}, {0xFF41,0xFF21}, {0xFF42,0xFF22}, {0xFF43,0xFF23}, {0xFF44,0xFF24}, 
+  {0xFF45,0xFF25}, {0xFF46,0xFF26}, {0xFF47,0xFF27}, {0xFF48,0xFF28}, {0xFF49,0xFF29}, 
+  {0xFF4A,0xFF2A}, {0xFF4B,0xFF2B}, {0xFF4C,0xFF2C}, {0xFF4D,0xFF2D}, {0xFF4E,0xFF2E}, 
+  {0xFF4F,0xFF2F}, {0xFF50,0xFF30}, {0xFF51,0xFF31}, {0xFF52,0xFF32}, {0xFF53,0xFF33}, 
+  {0xFF54,0xFF34}, {0xFF55,0xFF35}, {0xFF56,0xFF36}, {0xFF57,0xFF37}, {0xFF58,0xFF38}, 
+  {0xFF59,0xFF39}, {0xFF5A,0xFF3A} 
+};
+
+
+
+/* All lower-case translations are included here */
+
+#define NUM_TOLOWER_INFO 705
+static const unirelate tolower_info[NUM_TOLOWER_INFO] = {
+  {0x41,0x61}, {0x42,0x62}, {0x43,0x63}, {0x44,0x64}, {0x45,0x65}, 
+  {0x46,0x66}, {0x47,0x67}, {0x48,0x68}, {0x49,0x69}, {0x4A,0x6A}, 
+  {0x4B,0x6B}, {0x4C,0x6C}, {0x4D,0x6D}, {0x4E,0x6E}, {0x4F,0x6F}, 
+  {0x50,0x70}, {0x51,0x71}, {0x52,0x72}, {0x53,0x73}, {0x54,0x74}, 
+  {0x55,0x75}, {0x56,0x76}, {0x57,0x77}, {0x58,0x78}, {0x59,0x79}, 
+  {0x5A,0x7A}, {0xC0,0xE0}, {0xC1,0xE1}, {0xC2,0xE2}, {0xC3,0xE3}, 
+  {0xC4,0xE4}, {0xC5,0xE5}, {0xC6,0xE6}, {0xC7,0xE7}, {0xC8,0xE8}, 
+  {0xC9,0xE9}, {0xCA,0xEA}, {0xCB,0xEB}, {0xCC,0xEC}, {0xCD,0xED}, 
+  {0xCE,0xEE}, {0xCF,0xEF}, {0xD0,0xF0}, {0xD1,0xF1}, {0xD2,0xF2}, 
+  {0xD3,0xF3}, {0xD4,0xF4}, {0xD5,0xF5}, {0xD6,0xF6}, {0xD8,0xF8}, 
+  {0xD9,0xF9}, {0xDA,0xFA}, {0xDB,0xFB}, {0xDC,0xFC}, {0xDD,0xFD}, 
+  {0xDE,0xFE}, {0x100,0x101}, {0x102,0x103}, {0x104,0x105}, {0x106,0x107}, 
+  {0x108,0x109}, {0x10A,0x10B}, {0x10C,0x10D}, {0x10E,0x10F}, {0x110,0x111}, 
+  {0x112,0x113}, {0x114,0x115}, {0x116,0x117}, {0x118,0x119}, {0x11A,0x11B}, 
+  {0x11C,0x11D}, {0x11E,0x11F}, {0x120,0x121}, {0x122,0x123}, {0x124,0x125}, 
+  {0x126,0x127}, {0x128,0x129}, {0x12A,0x12B}, {0x12C,0x12D}, {0x12E,0x12F}, 
+  {0x130,0x69}, {0x132,0x133}, {0x134,0x135}, {0x136,0x137}, {0x139,0x13A}, 
+  {0x13B,0x13C}, {0x13D,0x13E}, {0x13F,0x140}, {0x141,0x142}, {0x143,0x144}, 
+  {0x145,0x146}, {0x147,0x148}, {0x14A,0x14B}, {0x14C,0x14D}, {0x14E,0x14F}, 
+  {0x150,0x151}, {0x152,0x153}, {0x154,0x155}, {0x156,0x157}, {0x158,0x159}, 
+  {0x15A,0x15B}, {0x15C,0x15D}, {0x15E,0x15F}, {0x160,0x161}, {0x162,0x163}, 
+  {0x164,0x165}, {0x166,0x167}, {0x168,0x169}, {0x16A,0x16B}, {0x16C,0x16D}, 
+  {0x16E,0x16F}, {0x170,0x171}, {0x172,0x173}, {0x174,0x175}, {0x176,0x177}, 
+  {0x178,0xFF}, {0x179,0x17A}, {0x17B,0x17C}, {0x17D,0x17E}, {0x181,0x253}, 
+  {0x182,0x183}, {0x184,0x185}, {0x186,0x254}, {0x187,0x188}, {0x189,0x256}, 
+  {0x18A,0x257}, {0x18B,0x18C}, {0x18E,0x1DD}, {0x18F,0x259}, {0x190,0x25B}, 
+  {0x191,0x192}, {0x193,0x260}, {0x194,0x263}, {0x196,0x269}, {0x197,0x268}, 
+  {0x198,0x199}, {0x19C,0x26F}, {0x19D,0x272}, {0x19F,0x275}, {0x1A0,0x1A1}, 
+  {0x1A2,0x1A3}, {0x1A4,0x1A5}, {0x1A7,0x1A8}, {0x1A9,0x283}, {0x1AC,0x1AD}, 
+  {0x1AE,0x288}, {0x1AF,0x1B0}, {0x1B1,0x28A}, {0x1B2,0x28B}, {0x1B3,0x1B4}, 
+  {0x1B5,0x1B6}, {0x1B7,0x292}, {0x1B8,0x1B9}, {0x1BC,0x1BD}, {0x1C4,0x1C6}, 
+  {0x1C5,0x1C6}, {0x1C7,0x1C9}, {0x1C8,0x1C9}, {0x1CA,0x1CC}, {0x1CB,0x1CC}, 
+  {0x1CD,0x1CE}, {0x1CF,0x1D0}, {0x1D1,0x1D2}, {0x1D3,0x1D4}, {0x1D5,0x1D6}, 
+  {0x1D7,0x1D8}, {0x1D9,0x1DA}, {0x1DB,0x1DC}, {0x1DE,0x1DF}, {0x1E0,0x1E1}, 
+  {0x1E2,0x1E3}, {0x1E4,0x1E5}, {0x1E6,0x1E7}, {0x1E8,0x1E9}, {0x1EA,0x1EB}, 
+  {0x1EC,0x1ED}, {0x1EE,0x1EF}, {0x1F1,0x1F3}, {0x1F2,0x1F3}, {0x1F4,0x1F5}, 
+  {0x1FA,0x1FB}, {0x1FC,0x1FD}, {0x1FE,0x1FF}, {0x200,0x201}, {0x202,0x203}, 
+  {0x204,0x205}, {0x206,0x207}, {0x208,0x209}, {0x20A,0x20B}, {0x20C,0x20D}, 
+  {0x20E,0x20F}, {0x210,0x211}, {0x212,0x213}, {0x214,0x215}, {0x216,0x217}, 
+  {0x386,0x3AC}, {0x388,0x3AD}, {0x389,0x3AE}, {0x38A,0x3AF}, {0x38C,0x3CC}, 
+  {0x38E,0x3CD}, {0x38F,0x3CE}, {0x391,0x3B1}, {0x392,0x3B2}, {0x393,0x3B3}, 
+  {0x394,0x3B4}, {0x395,0x3B5}, {0x396,0x3B6}, {0x397,0x3B7}, {0x398,0x3B8}, 
+  {0x399,0x3B9}, {0x39A,0x3BA}, {0x39B,0x3BB}, {0x39C,0x3BC}, {0x39D,0x3BD}, 
+  {0x39E,0x3BE}, {0x39F,0x3BF}, {0x3A0,0x3C0}, {0x3A1,0x3C1}, {0x3A3,0x3C3}, 
+  {0x3A4,0x3C4}, {0x3A5,0x3C5}, {0x3A6,0x3C6}, {0x3A7,0x3C7}, {0x3A8,0x3C8}, 
+  {0x3A9,0x3C9}, {0x3AA,0x3CA}, {0x3AB,0x3CB}, {0x3E2,0x3E3}, {0x3E4,0x3E5}, 
+  {0x3E6,0x3E7}, {0x3E8,0x3E9}, {0x3EA,0x3EB}, {0x3EC,0x3ED}, {0x3EE,0x3EF}, 
+  {0x401,0x451}, {0x402,0x452}, {0x403,0x453}, {0x404,0x454}, {0x405,0x455}, 
+  {0x406,0x456}, {0x407,0x457}, {0x408,0x458}, {0x409,0x459}, {0x40A,0x45A}, 
+  {0x40B,0x45B}, {0x40C,0x45C}, {0x40E,0x45E}, {0x40F,0x45F}, {0x410,0x430}, 
+  {0x411,0x431}, {0x412,0x432}, {0x413,0x433}, {0x414,0x434}, {0x415,0x435}, 
+  {0x416,0x436}, {0x417,0x437}, {0x418,0x438}, {0x419,0x439}, {0x41A,0x43A}, 
+  {0x41B,0x43B}, {0x41C,0x43C}, {0x41D,0x43D}, {0x41E,0x43E}, {0x41F,0x43F}, 
+  {0x420,0x440}, {0x421,0x441}, {0x422,0x442}, {0x423,0x443}, {0x424,0x444}, 
+  {0x425,0x445}, {0x426,0x446}, {0x427,0x447}, {0x428,0x448}, {0x429,0x449}, 
+  {0x42A,0x44A}, {0x42B,0x44B}, {0x42C,0x44C}, {0x42D,0x44D}, {0x42E,0x44E}, 
+  {0x42F,0x44F}, {0x460,0x461}, {0x462,0x463}, {0x464,0x465}, {0x466,0x467}, 
+  {0x468,0x469}, {0x46A,0x46B}, {0x46C,0x46D}, {0x46E,0x46F}, {0x470,0x471}, 
+  {0x472,0x473}, {0x474,0x475}, {0x476,0x477}, {0x478,0x479}, {0x47A,0x47B}, 
+  {0x47C,0x47D}, {0x47E,0x47F}, {0x480,0x481}, {0x490,0x491}, {0x492,0x493}, 
+  {0x494,0x495}, {0x496,0x497}, {0x498,0x499}, {0x49A,0x49B}, {0x49C,0x49D}, 
+  {0x49E,0x49F}, {0x4A0,0x4A1}, {0x4A2,0x4A3}, {0x4A4,0x4A5}, {0x4A6,0x4A7}, 
+  {0x4A8,0x4A9}, {0x4AA,0x4AB}, {0x4AC,0x4AD}, {0x4AE,0x4AF}, {0x4B0,0x4B1}, 
+  {0x4B2,0x4B3}, {0x4B4,0x4B5}, {0x4B6,0x4B7}, {0x4B8,0x4B9}, {0x4BA,0x4BB}, 
+  {0x4BC,0x4BD}, {0x4BE,0x4BF}, {0x4C1,0x4C2}, {0x4C3,0x4C4}, {0x4C7,0x4C8}, 
+  {0x4CB,0x4CC}, {0x4D0,0x4D1}, {0x4D2,0x4D3}, {0x4D4,0x4D5}, {0x4D6,0x4D7}, 
+  {0x4D8,0x4D9}, {0x4DA,0x4DB}, {0x4DC,0x4DD}, {0x4DE,0x4DF}, {0x4E0,0x4E1}, 
+  {0x4E2,0x4E3}, {0x4E4,0x4E5}, {0x4E6,0x4E7}, {0x4E8,0x4E9}, {0x4EA,0x4EB}, 
+  {0x4EE,0x4EF}, {0x4F0,0x4F1}, {0x4F2,0x4F3}, {0x4F4,0x4F5}, {0x4F8,0x4F9}, 
+  {0x531,0x561}, {0x532,0x562}, {0x533,0x563}, {0x534,0x564}, {0x535,0x565}, 
+  {0x536,0x566}, {0x537,0x567}, {0x538,0x568}, {0x539,0x569}, {0x53A,0x56A}, 
+  {0x53B,0x56B}, {0x53C,0x56C}, {0x53D,0x56D}, {0x53E,0x56E}, {0x53F,0x56F}, 
+  {0x540,0x570}, {0x541,0x571}, {0x542,0x572}, {0x543,0x573}, {0x544,0x574}, 
+  {0x545,0x575}, {0x546,0x576}, {0x547,0x577}, {0x548,0x578}, {0x549,0x579}, 
+  {0x54A,0x57A}, {0x54B,0x57B}, {0x54C,0x57C}, {0x54D,0x57D}, {0x54E,0x57E}, 
+  {0x54F,0x57F}, {0x550,0x580}, {0x551,0x581}, {0x552,0x582}, {0x553,0x583}, 
+  {0x554,0x584}, {0x555,0x585}, {0x556,0x586}, {0x10A0,0x10D0}, {0x10A1,0x10D1}, 
+  {0x10A2,0x10D2}, {0x10A3,0x10D3}, {0x10A4,0x10D4}, {0x10A5,0x10D5}, {0x10A6,0x10D6}, 
+  {0x10A7,0x10D7}, {0x10A8,0x10D8}, {0x10A9,0x10D9}, {0x10AA,0x10DA}, {0x10AB,0x10DB}, 
+  {0x10AC,0x10DC}, {0x10AD,0x10DD}, {0x10AE,0x10DE}, {0x10AF,0x10DF}, {0x10B0,0x10E0}, 
+  {0x10B1,0x10E1}, {0x10B2,0x10E2}, {0x10B3,0x10E3}, {0x10B4,0x10E4}, {0x10B5,0x10E5}, 
+  {0x10B6,0x10E6}, {0x10B7,0x10E7}, {0x10B8,0x10E8}, {0x10B9,0x10E9}, {0x10BA,0x10EA}, 
+  {0x10BB,0x10EB}, {0x10BC,0x10EC}, {0x10BD,0x10ED}, {0x10BE,0x10EE}, {0x10BF,0x10EF}, 
+  {0x10C0,0x10F0}, {0x10C1,0x10F1}, {0x10C2,0x10F2}, {0x10C3,0x10F3}, {0x10C4,0x10F4}, 
+  {0x10C5,0x10F5}, {0x1E00,0x1E01}, {0x1E02,0x1E03}, {0x1E04,0x1E05}, {0x1E06,0x1E07}, 
+  {0x1E08,0x1E09}, {0x1E0A,0x1E0B}, {0x1E0C,0x1E0D}, {0x1E0E,0x1E0F}, {0x1E10,0x1E11}, 
+  {0x1E12,0x1E13}, {0x1E14,0x1E15}, {0x1E16,0x1E17}, {0x1E18,0x1E19}, {0x1E1A,0x1E1B}, 
+  {0x1E1C,0x1E1D}, {0x1E1E,0x1E1F}, {0x1E20,0x1E21}, {0x1E22,0x1E23}, {0x1E24,0x1E25}, 
+  {0x1E26,0x1E27}, {0x1E28,0x1E29}, {0x1E2A,0x1E2B}, {0x1E2C,0x1E2D}, {0x1E2E,0x1E2F}, 
+  {0x1E30,0x1E31}, {0x1E32,0x1E33}, {0x1E34,0x1E35}, {0x1E36,0x1E37}, {0x1E38,0x1E39}, 
+  {0x1E3A,0x1E3B}, {0x1E3C,0x1E3D}, {0x1E3E,0x1E3F}, {0x1E40,0x1E41}, {0x1E42,0x1E43}, 
+  {0x1E44,0x1E45}, {0x1E46,0x1E47}, {0x1E48,0x1E49}, {0x1E4A,0x1E4B}, {0x1E4C,0x1E4D}, 
+  {0x1E4E,0x1E4F}, {0x1E50,0x1E51}, {0x1E52,0x1E53}, {0x1E54,0x1E55}, {0x1E56,0x1E57}, 
+  {0x1E58,0x1E59}, {0x1E5A,0x1E5B}, {0x1E5C,0x1E5D}, {0x1E5E,0x1E5F}, {0x1E60,0x1E61}, 
+  {0x1E62,0x1E63}, {0x1E64,0x1E65}, {0x1E66,0x1E67}, {0x1E68,0x1E69}, {0x1E6A,0x1E6B}, 
+  {0x1E6C,0x1E6D}, {0x1E6E,0x1E6F}, {0x1E70,0x1E71}, {0x1E72,0x1E73}, {0x1E74,0x1E75}, 
+  {0x1E76,0x1E77}, {0x1E78,0x1E79}, {0x1E7A,0x1E7B}, {0x1E7C,0x1E7D}, {0x1E7E,0x1E7F}, 
+  {0x1E80,0x1E81}, {0x1E82,0x1E83}, {0x1E84,0x1E85}, {0x1E86,0x1E87}, {0x1E88,0x1E89}, 
+  {0x1E8A,0x1E8B}, {0x1E8C,0x1E8D}, {0x1E8E,0x1E8F}, {0x1E90,0x1E91}, {0x1E92,0x1E93}, 
+  {0x1E94,0x1E95}, {0x1EA0,0x1EA1}, {0x1EA2,0x1EA3}, {0x1EA4,0x1EA5}, {0x1EA6,0x1EA7}, 
+  {0x1EA8,0x1EA9}, {0x1EAA,0x1EAB}, {0x1EAC,0x1EAD}, {0x1EAE,0x1EAF}, {0x1EB0,0x1EB1}, 
+  {0x1EB2,0x1EB3}, {0x1EB4,0x1EB5}, {0x1EB6,0x1EB7}, {0x1EB8,0x1EB9}, {0x1EBA,0x1EBB}, 
+  {0x1EBC,0x1EBD}, {0x1EBE,0x1EBF}, {0x1EC0,0x1EC1}, {0x1EC2,0x1EC3}, {0x1EC4,0x1EC5}, 
+  {0x1EC6,0x1EC7}, {0x1EC8,0x1EC9}, {0x1ECA,0x1ECB}, {0x1ECC,0x1ECD}, {0x1ECE,0x1ECF}, 
+  {0x1ED0,0x1ED1}, {0x1ED2,0x1ED3}, {0x1ED4,0x1ED5}, {0x1ED6,0x1ED7}, {0x1ED8,0x1ED9}, 
+  {0x1EDA,0x1EDB}, {0x1EDC,0x1EDD}, {0x1EDE,0x1EDF}, {0x1EE0,0x1EE1}, {0x1EE2,0x1EE3}, 
+  {0x1EE4,0x1EE5}, {0x1EE6,0x1EE7}, {0x1EE8,0x1EE9}, {0x1EEA,0x1EEB}, {0x1EEC,0x1EED}, 
+  {0x1EEE,0x1EEF}, {0x1EF0,0x1EF1}, {0x1EF2,0x1EF3}, {0x1EF4,0x1EF5}, {0x1EF6,0x1EF7}, 
+  {0x1EF8,0x1EF9}, {0x1F08,0x1F00}, {0x1F09,0x1F01}, {0x1F0A,0x1F02}, {0x1F0B,0x1F03}, 
+  {0x1F0C,0x1F04}, {0x1F0D,0x1F05}, {0x1F0E,0x1F06}, {0x1F0F,0x1F07}, {0x1F18,0x1F10}, 
+  {0x1F19,0x1F11}, {0x1F1A,0x1F12}, {0x1F1B,0x1F13}, {0x1F1C,0x1F14}, {0x1F1D,0x1F15}, 
+  {0x1F28,0x1F20}, {0x1F29,0x1F21}, {0x1F2A,0x1F22}, {0x1F2B,0x1F23}, {0x1F2C,0x1F24}, 
+  {0x1F2D,0x1F25}, {0x1F2E,0x1F26}, {0x1F2F,0x1F27}, {0x1F38,0x1F30}, {0x1F39,0x1F31}, 
+  {0x1F3A,0x1F32}, {0x1F3B,0x1F33}, {0x1F3C,0x1F34}, {0x1F3D,0x1F35}, {0x1F3E,0x1F36}, 
+  {0x1F3F,0x1F37}, {0x1F48,0x1F40}, {0x1F49,0x1F41}, {0x1F4A,0x1F42}, {0x1F4B,0x1F43}, 
+  {0x1F4C,0x1F44}, {0x1F4D,0x1F45}, {0x1F59,0x1F51}, {0x1F5B,0x1F53}, {0x1F5D,0x1F55}, 
+  {0x1F5F,0x1F57}, {0x1F68,0x1F60}, {0x1F69,0x1F61}, {0x1F6A,0x1F62}, {0x1F6B,0x1F63}, 
+  {0x1F6C,0x1F64}, {0x1F6D,0x1F65}, {0x1F6E,0x1F66}, {0x1F6F,0x1F67}, {0x1F88,0x1F80}, 
+  {0x1F89,0x1F81}, {0x1F8A,0x1F82}, {0x1F8B,0x1F83}, {0x1F8C,0x1F84}, {0x1F8D,0x1F85}, 
+  {0x1F8E,0x1F86}, {0x1F8F,0x1F87}, {0x1F98,0x1F90}, {0x1F99,0x1F91}, {0x1F9A,0x1F92}, 
+  {0x1F9B,0x1F93}, {0x1F9C,0x1F94}, {0x1F9D,0x1F95}, {0x1F9E,0x1F96}, {0x1F9F,0x1F97}, 
+  {0x1FA8,0x1FA0}, {0x1FA9,0x1FA1}, {0x1FAA,0x1FA2}, {0x1FAB,0x1FA3}, {0x1FAC,0x1FA4}, 
+  {0x1FAD,0x1FA5}, {0x1FAE,0x1FA6}, {0x1FAF,0x1FA7}, {0x1FB8,0x1FB0}, {0x1FB9,0x1FB1}, 
+  {0x1FBA,0x1F70}, {0x1FBB,0x1F71}, {0x1FBC,0x1FB3}, {0x1FC8,0x1F72}, {0x1FC9,0x1F73}, 
+  {0x1FCA,0x1F74}, {0x1FCB,0x1F75}, {0x1FCC,0x1FC3}, {0x1FD8,0x1FD0}, {0x1FD9,0x1FD1}, 
+  {0x1FDA,0x1F76}, {0x1FDB,0x1F77}, {0x1FE8,0x1FE0}, {0x1FE9,0x1FE1}, {0x1FEA,0x1F7A}, 
+  {0x1FEB,0x1F7B}, {0x1FEC,0x1FE5}, {0x1FF8,0x1F78}, {0x1FF9,0x1F79}, {0x1FFA,0x1F7C}, 
+  {0x1FFB,0x1F7D}, {0x1FFC,0x1FF3}, {0x2160,0x2170}, {0x2161,0x2171}, {0x2162,0x2172}, 
+  {0x2163,0x2173}, {0x2164,0x2174}, {0x2165,0x2175}, {0x2166,0x2176}, {0x2167,0x2177}, 
+  {0x2168,0x2178}, {0x2169,0x2179}, {0x216A,0x217A}, {0x216B,0x217B}, {0x216C,0x217C}, 
+  {0x216D,0x217D}, {0x216E,0x217E}, {0x216F,0x217F}, {0x24B6,0x24D0}, {0x24B7,0x24D1}, 
+  {0x24B8,0x24D2}, {0x24B9,0x24D3}, {0x24BA,0x24D4}, {0x24BB,0x24D5}, {0x24BC,0x24D6}, 
+  {0x24BD,0x24D7}, {0x24BE,0x24D8}, {0x24BF,0x24D9}, {0x24C0,0x24DA}, {0x24C1,0x24DB}, 
+  {0x24C2,0x24DC}, {0x24C3,0x24DD}, {0x24C4,0x24DE}, {0x24C5,0x24DF}, {0x24C6,0x24E0}, 
+  {0x24C7,0x24E1}, {0x24C8,0x24E2}, {0x24C9,0x24E3}, {0x24CA,0x24E4}, {0x24CB,0x24E5}, 
+  {0x24CC,0x24E6}, {0x24CD,0x24E7}, {0x24CE,0x24E8}, {0x24CF,0x24E9}, {0xFF21,0xFF41}, 
+  {0xFF22,0xFF42}, {0xFF23,0xFF43}, {0xFF24,0xFF44}, {0xFF25,0xFF45}, {0xFF26,0xFF46}, 
+  {0xFF27,0xFF47}, {0xFF28,0xFF48}, {0xFF29,0xFF49}, {0xFF2A,0xFF4A}, {0xFF2B,0xFF4B}, 
+  {0xFF2C,0xFF4C}, {0xFF2D,0xFF4D}, {0xFF2E,0xFF4E}, {0xFF2F,0xFF4F}, {0xFF30,0xFF50}, 
+  {0xFF31,0xFF51}, {0xFF32,0xFF52}, {0xFF33,0xFF53}, {0xFF34,0xFF54}, {0xFF35,0xFF55}, 
+  {0xFF36,0xFF56}, {0xFF37,0xFF57}, {0xFF38,0xFF58}, {0xFF39,0xFF59}, {0xFF3A,0xFF5A}
+};
+
+
+
+#define NUM_TOSIMPLIFIED_INFO 2145
+static const unirelate tosimplified_info[NUM_TOSIMPLIFIED_INFO] = {
+  {0x4E48,0x9EBD}, {0x4E82,0x4E71}, {0x4E9E,0x4E9A}, {0x4F47,0x4F2B}, {0x4F59,0x9980}, 
+  {0x4F86,0x6765}, {0x4F96,0x4ED1}, {0x4FE0,0x4FA0}, {0x5000,0x4F25}, {0x5006,0x4FE9}, 
+  {0x5009,0x4ED3}, {0x500B,0x4E2A}, {0x5011,0x4EEC}, {0x502B,0x4F26}, {0x5049,0x4F1F}, 
+  {0x5074,0x4FA7}, {0x5075,0x4FA6}, {0x5096,0x4F27}, {0x5098,0x4F1E}, {0x5099,0x5907}, 
+  {0x50AD,0x4F63}, {0x50B3,0x4F20}, {0x50B4,0x4F1B}, {0x50B5,0x503A}, {0x50B7,0x4F24}, 
+  {0x50BE,0x503E}, {0x50C2,0x507B}, {0x50C5,0x4EC5}, {0x50C9,0x4F65}, {0x50D1,0x4FA8}, 
+  {0x50D5,0x4EC6}, {0x50DE,0x4F2A}, {0x50E5,0x4FA5}, {0x50E8,0x507E}, {0x50F9,0x4EF7}, 
+  {0x5100,0x4EEA}, {0x5102,0x4FAC}, {0x5104,0x4EBF}, {0x5108,0x4FA9}, {0x5109,0x4FED}, 
+  {0x5110,0x50A7}, {0x5114,0x4FE6}, {0x5115,0x4FAA}, {0x511F,0x507F}, {0x512A,0x4F18}, 
+  {0x5132,0x50A8}, {0x5137,0x4FEA}, {0x513A,0x50A9}, {0x513B,0x50A5}, {0x513C,0x4FE8}, 
+  {0x5152,0x513F}, {0x5169,0x4E24}, {0x51C8,0x51C0}, {0x51CD,0x51BB}, {0x51F1,0x51EF}, 
+  {0x5244,0x522D}, {0x5247,0x5219}, {0x525B,0x521A}, {0x526E,0x5250}, {0x5274,0x5240}, 
+  {0x5275,0x521B}, {0x5283,0x5212}, {0x5287,0x5267}, {0x5289,0x5218}, {0x528A,0x523D}, 
+  {0x528C,0x523F}, {0x528D,0x5251}, {0x5291,0x5242}, {0x52C1,0x52B2}, {0x52D5,0x52A8}, 
+  {0x52D9,0x52A1}, {0x52DB,0x52CB}, {0x52DD,0x80DC}, {0x52DE,0x52B3}, {0x52E2,0x52BF}, 
+  {0x52F1,0x52A2}, {0x52F5,0x52B1}, {0x52F8,0x529D}, {0x532D,0x5326}, {0x532F,0x6C47}, 
+  {0x5331,0x532E}, {0x5340,0x533A}, {0x5354,0x534F}, {0x5399,0x538D}, {0x53A0,0x5395}, 
+  {0x53AD,0x538C}, {0x53B2,0x5389}, {0x53B4,0x53A3}, {0x53C3,0x53C2}, {0x53E2,0x4E1B}, 
+  {0x540E,0x5F8C}, {0x54BC,0x5459}, {0x54E1,0x5458}, {0x5504,0x5457}, {0x554F,0x95EE}, 
+  {0x5553,0x542F}, {0x555E,0x54D1}, {0x559A,0x5524}, {0x55AA,0x4E27}, {0x55AC,0x4E54}, 
+  {0x55AE,0x5355}, {0x55B2,0x54DF}, {0x55C6,0x545B}, {0x55C7,0x556C}, {0x55CE,0x5417}, 
+  {0x55DA,0x545C}, {0x55E9,0x5522}, {0x55F6,0x54D4}, {0x5606,0x53F9}, {0x560D,0x55BD}, 
+  {0x5614,0x5455}, {0x5616,0x5567}, {0x5617,0x5C1D}, {0x561C,0x551B}, {0x5629,0x54D7}, 
+  {0x562E,0x5520}, {0x562F,0x5578}, {0x5630,0x53FD}, {0x5635,0x54D3}, {0x5638,0x5452}, 
+  {0x565D,0x549D}, {0x5660,0x54D2}, {0x5665,0x54DD}, {0x5666,0x54D5}, {0x566F,0x55F3}, 
+  {0x5672,0x54D9}, {0x5674,0x55B7}, {0x5678,0x5428}, {0x5680,0x549B}, {0x5687,0x5413}, 
+  {0x568C,0x54DC}, {0x5695,0x565C}, {0x5699,0x556E}, {0x56A6,0x5456}, {0x56A8,0x5499}, 
+  {0x56B3,0x55BE}, {0x56B4,0x4E25}, {0x56B6,0x5624}, {0x56C0,0x556D}, {0x56C1,0x55EB}, 
+  {0x56C2,0x56A3}, {0x56C5,0x5181}, {0x56C8,0x5453}, {0x56D1,0x5631}, {0x5707,0x56F5}, 
+  {0x570B,0x56FD}, {0x570D,0x56F4}, {0x5712,0x56ED}, {0x5713,0x5706}, {0x5716,0x56FE}, 
+  {0x5718,0x56E2}, {0x57E1,0x57AD}, {0x57F7,0x6267}, {0x5805,0x575A}, {0x580A,0x57A9}, 
+  {0x5816,0x57B4}, {0x581D,0x57DA}, {0x582F,0x5C27}, {0x5831,0x62A5}, {0x5834,0x573A}, 
+  {0x584A,0x5757}, {0x584B,0x8314}, {0x584F,0x57B2}, {0x5852,0x57D8}, {0x5857,0x6D82}, 
+  {0x5862,0x575E}, {0x5864,0x57D9}, {0x5875,0x5C18}, {0x5879,0x5811}, {0x588A,0x57AB}, 
+  {0x589C,0x5760}, {0x58AE,0x5815}, {0x58B3,0x575F}, {0x58BB,0x5899}, {0x58BE,0x57A6}, 
+  {0x58C7,0x575B}, {0x58D3,0x538B}, {0x58D8,0x5792}, {0x58D9,0x5739}, {0x58DA,0x5786}, 
+  {0x58DE,0x574F}, {0x58DF,0x5784}, {0x58E0,0x5785}, {0x58E2,0x575C}, {0x58E9,0x575D}, 
+  {0x58EF,0x58EE}, {0x58FA,0x58F6}, {0x58FD,0x5BFF}, {0x5922,0x68A6}, {0x593E,0x5939}, 
+  {0x5950,0x5942}, {0x5969,0x5941}, {0x596A,0x593A}, {0x596C,0x5956}, {0x596E,0x594B}, 
+  {0x599D,0x5986}, {0x5A41,0x5A04}, {0x5A66,0x5987}, {0x5A6D,0x5A05}, {0x5AA7,0x5A32}, 
+  {0x5ABD,0x5988}, {0x5AD7,0x59AA}, {0x5AF5,0x59A9}, {0x5AFB,0x5A34}, {0x5B00,0x59AB}, 
+  {0x5B08,0x5A06}, {0x5B0B,0x5A75}, {0x5B0C,0x5A07}, {0x5B19,0x5AF1}, {0x5B21,0x5AD2}, 
+  {0x5B2A,0x5AD4}, {0x5B30,0x5A74}, {0x5B38,0x5A76}, {0x5B4C,0x5A08}, {0x5B6B,0x5B59}, 
+  {0x5B78,0x5B66}, {0x5B7F,0x5B6A}, {0x5BE2,0x5BDD}, {0x5BE6,0x5B9E}, {0x5BE7,0x5B81}, 
+  {0x5BE9,0x5BA1}, {0x5BEB,0x5199}, {0x5BEC,0x5BBD}, {0x5BF5,0x5BA0}, {0x5BF6,0x5B9D}, 
+  {0x5C07,0x5C06}, {0x5C08,0x4E13}, {0x5C0B,0x5BFB}, {0x5C0D,0x5BF9}, {0x5C0E,0x5BFC}, 
+  {0x5C37,0x5C34}, {0x5C62,0x5C61}, {0x5C64,0x5C42}, {0x5C68,0x5C66}, {0x5C6C,0x5C5E}, 
+  {0x5CA1,0x5188}, {0x5CF4,0x5C98}, {0x5CF6,0x5C9B}, {0x5CFD,0x5CE1}, {0x5D0D,0x5D03}, 
+  {0x5D17,0x5C97}, {0x5D22,0x5CE5}, {0x5D2C,0x5CBD}, {0x5D50,0x5C9A}, {0x5D81,0x5D5D}, 
+  {0x5D84,0x5D2D}, {0x5D87,0x5C96}, {0x5D97,0x5D02}, {0x5DA0,0x5CE4}, {0x5DA7,0x5CC4}, 
+  {0x5DB8,0x5D58}, {0x5DBA,0x5CAD}, {0x5DBC,0x5C7F}, {0x5DCB,0x5CBF}, {0x5DD2,0x5CE6}, 
+  {0x5DD4,0x5DC5}, {0x5DF0,0x5DEF}, {0x5E25,0x5E05}, {0x5E2B,0x5E08}, {0x5E33,0x5E10}, 
+  {0x5E36,0x5E26}, {0x5E40,0x5E27}, {0x5E43,0x5E0F}, {0x5E57,0x5E3C}, {0x5E58,0x5E3B}, 
+  {0x5E5F,0x5E1C}, {0x5E63,0x5E01}, {0x5E6B,0x5E2E}, {0x5E6C,0x5E31}, {0x5E79,0x5E72}, 
+  {0x5E7E,0x51E0}, {0x5EAB,0x5E93}, {0x5EDF,0x5E99}, {0x5EE0,0x5382}, {0x5EE1,0x5E91}, 
+  {0x5EE2,0x5E9F}, {0x5EE3,0x5E7F}, {0x5EEC,0x5E90}, {0x5EF3,0x5385}, {0x5F33,0x5F2A}, 
+  {0x5F35,0x5F20}, {0x5F48,0x5F39}, {0x5F4C,0x5F25}, {0x5F4E,0x5F2F}, {0x5F8C,0x540E}, 
+  {0x5F91,0x5F84}, {0x5F9E,0x4ECE}, {0x5FA0,0x5F95}, {0x5FA9,0x590D}, {0x5FB9,0x5F7B}, 
+  {0x60B5,0x6005}, {0x60B6,0x95F7}, {0x60E1,0x6076}, {0x60F1,0x607C}, {0x60F2,0x607D}, 
+  {0x60FB,0x607B}, {0x611B,0x7231}, {0x611C,0x60EC}, {0x6134,0x6006}, {0x6137,0x607A}, 
+  {0x613E,0x5FFE}, {0x614B,0x6001}, {0x6158,0x60E8}, {0x615A,0x60ED}, {0x615F,0x6078}, 
+  {0x6163,0x60EF}, {0x6164,0x60AB}, {0x616A,0x6004}, {0x616B,0x6002}, {0x616E,0x8651}, 
+  {0x6173,0x60AD}, {0x6176,0x5E86}, {0x6182,0x5FE7}, {0x618A,0x60EB}, {0x6190,0x601C}, 
+  {0x6191,0x51ED}, {0x6192,0x6126}, {0x619A,0x60EE}, {0x61A4,0x6124}, {0x61AB,0x60AF}, 
+  {0x61AE,0x6003}, {0x61B2,0x5BAA}, {0x61B6,0x5FC6}, {0x61C7,0x6073}, {0x61C9,0x5E94}, 
+  {0x61CC,0x603F}, {0x61DF,0x603C}, {0x61E3,0x61D1}, {0x61E8,0x6079}, {0x61F2,0x60E9}, 
+  {0x61F6,0x61D2}, {0x61F7,0x6000}, {0x61F8,0x60AC}, {0x61FA,0x5FCF}, {0x61FC,0x60E7}, 
+  {0x61FE,0x6151}, {0x6200,0x604B}, {0x6207,0x6206}, {0x6214,0x620B}, {0x6227,0x6217}, 
+  {0x6229,0x622C}, {0x6230,0x6218}, {0x6232,0x620F}, {0x633E,0x631F}, {0x6368,0x820D}, 
+  {0x636B,0x626A}, {0x6383,0x626B}, {0x6384,0x62A1}, {0x6399,0x6323}, {0x63C0,0x62E3}, 
+  {0x63DA,0x626C}, {0x63DB,0x6362}, {0x63EE,0x6325}, {0x640D,0x635F}, {0x6417,0x6363}, 
+  {0x6436,0x62A2}, {0x6451,0x63B4}, {0x645C,0x63BC}, {0x645F,0x6402}, {0x646F,0x631A}, 
+  {0x6473,0x62A0}, {0x6476,0x629F}, {0x647B,0x63BA}, {0x6488,0x635E}, {0x6493,0x6320}, 
+  {0x649F,0x6322}, {0x64A3,0x63B8}, {0x64A5,0x62E8}, {0x64AB,0x629A}, {0x64B2,0x6251}, 
+  {0x64B3,0x63FF}, {0x64BB,0x631E}, {0x64BE,0x631D}, {0x64BF,0x6361}, {0x64C1,0x62E5}, 
+  {0x64C4,0x63B3}, {0x64C7,0x62E9}, {0x64CA,0x51FB}, {0x64CB,0x6321}, {0x64D4,0x62C5}, 
+  {0x64DA,0x636E}, {0x64E0,0x6324}, {0x64EC,0x62DF}, {0x64EF,0x6448}, {0x64F0,0x62E7}, 
+  {0x64F1,0x6401}, {0x64F2,0x63B7}, {0x64F4,0x6269}, {0x64F7,0x64B7}, {0x64FA,0x6446}, 
+  {0x64FB,0x64DE}, {0x64FC,0x64B8}, {0x64FE,0x6270}, {0x6504,0x6445}, {0x6506,0x64B5}, 
+  {0x650F,0x62E2}, {0x6514,0x62E6}, {0x6516,0x6484}, {0x6519,0x6400}, {0x651B,0x64BA}, 
+  {0x651D,0x6444}, {0x6522,0x6512}, {0x6523,0x631B}, {0x6524,0x644A}, {0x652A,0x6405}, 
+  {0x652C,0x63FD}, {0x6557,0x8D25}, {0x6575,0x654C}, {0x6578,0x6570}, {0x6582,0x655B}, 
+  {0x6583,0x6BD9}, {0x6595,0x6593}, {0x65AC,0x65A9}, {0x65B7,0x65AD}, {0x6642,0x65F6}, 
+  {0x6649,0x664B}, {0x665D,0x663C}, {0x6688,0x6655}, {0x6689,0x6656}, {0x66A2,0x7545}, 
+  {0x66AB,0x6682}, {0x66C4,0x6654}, {0x66C7,0x6619}, {0x66C9,0x6653}, {0x66D6,0x66A7}, 
+  {0x66E0,0x65F7}, {0x66EC,0x6652}, {0x66F8,0x4E66}, {0x6703,0x4F1A}, {0x6727,0x80E7}, 
+  {0x6771,0x4E1C}, {0x6898,0x67A7}, {0x689D,0x6761}, {0x689F,0x67AD}, {0x68C4,0x5F03}, 
+  {0x68D6,0x67A8}, {0x68D7,0x67A3}, {0x68DF,0x680B}, {0x68E7,0x6808}, {0x68F2,0x6816}, 
+  {0x690F,0x6860}, {0x694A,0x6768}, {0x6953,0x67AB}, {0x6968,0x6862}, {0x696D,0x4E1A}, 
+  {0x6975,0x6781}, {0x69AA,0x6769}, {0x69AE,0x8363}, {0x69BF,0x6864}, {0x69CB,0x6784}, 
+  {0x69CD,0x67AA}, {0x69E7,0x6920}, {0x69F3,0x6868}, {0x6A01,0x6869}, {0x6A02,0x4E50}, 
+  {0x6A05,0x679E}, {0x6A13,0x697C}, {0x6A19,0x6807}, {0x6A1E,0x67A2}, {0x6A23,0x6837}, 
+  {0x6A38,0x6734}, {0x6A39,0x6811}, {0x6A3A,0x6866}, {0x6A48,0x6861}, {0x6A4B,0x6865}, 
+  {0x6A5F,0x673A}, {0x6A62,0x692D}, {0x6A89,0x67FD}, {0x6A94,0x6863}, {0x6A9C,0x6867}, 
+  {0x6AA2,0x68C0}, {0x6AA3,0x6A2F}, {0x6AB3,0x69DF}, {0x6AB8,0x67E0}, {0x6ABB,0x69DB}, 
+  {0x6AC3,0x67DC}, {0x6AD3,0x6A79}, {0x6ADA,0x6988}, {0x6ADB,0x6809}, {0x6ADD,0x691F}, 
+  {0x6ADE,0x6A7C}, {0x6ADF,0x680E}, {0x6AE7,0x69E0}, {0x6AE8,0x680C}, {0x6AEA,0x67A5}, 
+  {0x6AEC,0x6987}, {0x6AF3,0x680A}, {0x6AF8,0x6989}, {0x6AFB,0x6A31}, {0x6B04,0x680F}, 
+  {0x6B0A,0x6743}, {0x6B0F,0x6924}, {0x6B12,0x683E}, {0x6B16,0x6984}, {0x6B1E,0x68C2}, 
+  {0x6B3D,0x94A6}, {0x6B50,0x6B27}, {0x6B5F,0x6B24}, {0x6B61,0x6B22}, {0x6B72,0x5C81}, 
+  {0x6B77,0x5386}, {0x6B78,0x5F52}, {0x6B98,0x6B8B}, {0x6B9E,0x6B92}, {0x6BA4,0x6B87}, 
+  {0x6BAB,0x6B9A}, {0x6BAE,0x6B93}, {0x6BAF,0x6BA1}, {0x6BB2,0x6B7C}, {0x6BBA,0x6740}, 
+  {0x6BBB,0x58F3}, {0x6BC6,0x6BB4}, {0x6BFF,0x6BF5}, {0x6C08,0x6BE1}, {0x6C0C,0x6C07}, 
+  {0x6C23,0x6C14}, {0x6C2B,0x6C22}, {0x6C2C,0x6C29}, {0x6D79,0x6D43}, {0x6D87,0x6CFE}, 
+  {0x6DEA,0x6CA6}, {0x6DF5,0x6E0A}, {0x6DF6,0x6D9E}, {0x6DFA,0x6D45}, {0x6E19,0x6DA3}, 
+  {0x6E26,0x6DA1}, {0x6E2C,0x6D4B}, {0x6E3E,0x6D51}, {0x6E5E,0x6D48}, {0x6E6F,0x6C64}, 
+  {0x6E96,0x51C6}, {0x6E9D,0x6C9F}, {0x6EC4,0x6CA7}, {0x6EC5,0x706D}, {0x6ECC,0x6DA4}, 
+  {0x6ECE,0x8365}, {0x6EEC,0x6CAA}, {0x6EEF,0x6EDE}, {0x6EF2,0x6E17}, {0x6EF7,0x5364}, 
+  {0x6EF8,0x6D52}, {0x6EFF,0x6EE1}, {0x6F01,0x6E14}, {0x6F1A,0x6CA4}, {0x6F22,0x6C49}, 
+  {0x6F23,0x6D9F}, {0x6F2C,0x6E0D}, {0x6F32,0x6DA8}, {0x6F38,0x6E10}, {0x6F3F,0x6D46}, 
+  {0x6F41,0x988D}, {0x6F51,0x6CFC}, {0x6F54,0x6D01}, {0x6F59,0x6CA9}, {0x6F5B,0x6F5C}, 
+  {0x6F64,0x6DA6}, {0x6F6F,0x6D54}, {0x6F70,0x6E83}, {0x6F77,0x6ED7}, {0x6F7F,0x6DA0}, 
+  {0x6F80,0x6DA9}, {0x6F86,0x6D47}, {0x6F87,0x6D9D}, {0x6F97,0x6DA7}, {0x6FA0,0x6E11}, 
+  {0x6FA4,0x6CFD}, {0x6FA9,0x6CF6}, {0x6FAE,0x6D4D}, {0x6FB1,0x6DC0}, {0x6FC1,0x6D4A}, 
+  {0x6FC3,0x6D53}, {0x6FD5,0x6E7F}, {0x6FD8,0x6CDE}, {0x6FDF,0x6D4E}, {0x6FE4,0x6D9B}, 
+  {0x6FEB,0x6EE5}, {0x6FF0,0x6F4D}, {0x6FF1,0x6EE8}, {0x6FFA,0x6E85}, {0x6FFC,0x6CFA}, 
+  {0x6FFE,0x6EE4}, {0x7005,0x6EE2}, {0x7006,0x6E0E}, {0x7009,0x6CFB}, {0x700B,0x6E16}, 
+  {0x700F,0x6D4F}, {0x7015,0x6FD2}, {0x7018,0x6CF8}, {0x701D,0x6CA5}, {0x701F,0x6F47}, 
+  {0x7020,0x6F46}, {0x7027,0x6CF7}, {0x7028,0x6FD1}, {0x7032,0x6F4B}, {0x703E,0x6F9C}, 
+  {0x7043,0x6CA3}, {0x7044,0x6EE0}, {0x7051,0x6D12}, {0x7055,0x6F13}, {0x7058,0x6EE9}, 
+  {0x705D,0x704F}, {0x7063,0x6E7E}, {0x7064,0x6EE6}, {0x7067,0x6EDF}, {0x70CF,0x4E4C}, 
+  {0x70F4,0x70C3}, {0x7121,0x65E0}, {0x7149,0x70BC}, {0x7152,0x709C}, {0x7162,0x8315}, 
+  {0x7165,0x7115}, {0x7169,0x70E6}, {0x716C,0x7080}, {0x7192,0x8367}, {0x7197,0x709D}, 
+  {0x71B1,0x70ED}, {0x71BE,0x70BD}, {0x71C1,0x70E8}, {0x71C8,0x706F}, {0x71D2,0x70E7}, 
+  {0x71D9,0x70EB}, {0x71DC,0x7116}, {0x71DF,0x8425}, {0x71E6,0x707F}, {0x71ED,0x70DB}, 
+  {0x71F4,0x70E9}, {0x71FC,0x70EC}, {0x71FE,0x7118}, {0x720D,0x70C1}, {0x7210,0x7089}, 
+  {0x721B,0x70C2}, {0x722D,0x4E89}, {0x7232,0x4E3A}, {0x723A,0x7237}, {0x723E,0x5C14}, 
+  {0x7258,0x724D}, {0x727D,0x7275}, {0x7296,0x8366}, {0x72A2,0x728A}, {0x72A7,0x727A}, 
+  {0x72C0,0x72B6}, {0x72F9,0x72ED}, {0x72FD,0x72C8}, {0x7319,0x72F0}, {0x7336,0x72B9}, 
+  {0x733B,0x72F2}, {0x7341,0x72B8}, {0x7344,0x72F1}, {0x7345,0x72EE}, {0x7368,0x72EC}, 
+  {0x736A,0x72EF}, {0x736B,0x7303}, {0x7370,0x72DE}, {0x7372,0x83B7}, {0x7375,0x730E}, 
+  {0x7377,0x72B7}, {0x7378,0x517D}, {0x737A,0x736D}, {0x737B,0x732E}, {0x737C,0x7315}, 
+  {0x7380,0x7321}, {0x73FE,0x73B0}, {0x743F,0x73F2}, {0x744B,0x73AE}, {0x7463,0x7410}, 
+  {0x7469,0x83B9}, {0x746A,0x739B}, {0x7489,0x740F}, {0x74A3,0x7391}, {0x74A6,0x7477}, 
+  {0x74B0,0x73AF}, {0x74BD,0x73BA}, {0x74CA,0x743C}, {0x74CF,0x73D1}, {0x74D4,0x748E}, 
+  {0x74DA,0x74D2}, {0x750C,0x74EF}, {0x7523,0x4EA7}, {0x755D,0x4EA9}, {0x7562,0x6BD5}, 
+  {0x756B,0x753B}, {0x7576,0x5F53}, {0x7587,0x7574}, {0x758A,0x53E0}, {0x75D9,0x75C9}, 
+  {0x7602,0x75D6}, {0x760B,0x75AF}, {0x760D,0x75A1}, {0x7613,0x75EA}, {0x761E,0x7617}, 
+  {0x7621,0x75AE}, {0x7627,0x759F}, {0x763B,0x7618}, {0x7642,0x7597}, {0x7646,0x75E8}, 
+  {0x7647,0x75EB}, {0x7649,0x7605}, {0x7658,0x75A0}, {0x765F,0x762A}, {0x7662,0x75D2}, 
+  {0x7664,0x7596}, {0x7665,0x75C7}, {0x7667,0x75AC}, {0x7669,0x765E}, {0x766C,0x7663}, 
+  {0x766D,0x763F}, {0x766E,0x763E}, {0x7670,0x75C8}, {0x7671,0x762B}, {0x7672,0x766B}, 
+  {0x767C,0x53D1}, {0x769A,0x7691}, {0x76B8,0x76B2}, {0x76BA,0x76B1}, {0x76DE,0x76CF}, 
+  {0x76E1,0x5C3D}, {0x76E3,0x76D1}, {0x76E4,0x76D8}, {0x76E7,0x5362}, {0x775C,0x7741}, 
+  {0x775E,0x7750}, {0x7798,0x770D}, {0x779E,0x7792}, {0x77BC,0x7751}, {0x77DA,0x77A9}, 
+  {0x77EF,0x77EB}, {0x7864,0x7856}, {0x7868,0x7817}, {0x786F,0x781A}, {0x78A9,0x7855}, 
+  {0x78AD,0x7800}, {0x78B8,0x781C}, {0x78BA,0x786E}, {0x78BC,0x7801}, {0x78DA,0x7816}, 
+  {0x78E3,0x789C}, {0x78E7,0x789B}, {0x78EF,0x77F6}, {0x78FD,0x7857}, {0x790E,0x7840}, 
+  {0x7919,0x788D}, {0x7926,0x77FF}, {0x792A,0x783A}, {0x792B,0x783E}, {0x792C,0x77FE}, 
+  {0x7931,0x783B}, {0x798D,0x7978}, {0x798E,0x796F}, {0x79AA,0x7985}, {0x79AE,0x793C}, 
+  {0x79B0,0x7962}, {0x79B1,0x7977}, {0x7A2E,0x79CD}, {0x7A31,0x79F0}, {0x7A4C,0x7A23}, 
+  {0x7A4D,0x79EF}, {0x7A4E,0x9896}, {0x7A61,0x7A51}, {0x7A62,0x79FD}, {0x7A69,0x7A33}, 
+  {0x7AA9,0x7A9D}, {0x7AAA,0x6D3C}, {0x7AAE,0x7A77}, {0x7AB6,0x7AAD}, {0x7ABA,0x7AA5}, 
+  {0x7AC4,0x7A9C}, {0x7AC5,0x7A8D}, {0x7AC7,0x7AA6}, {0x7AC8,0x7076}, {0x7ACA,0x7A83}, 
+  {0x7AEA,0x7AD6}, {0x7AF6,0x7ADE}, {0x7B46,0x7B14}, {0x7B67,0x7B15}, {0x7B8B,0x7B3A}, 
+  {0x7B8F,0x7B5D}, {0x7BC0,0x8282}, {0x7BC4,0x8303}, {0x7BC9,0x7B51}, {0x7BCB,0x7BA7}, 
+  {0x7BE4,0x7B03}, {0x7BE9,0x7B5B}, {0x7BF3,0x7B5A}, {0x7C00,0x7BA6}, {0x7C0D,0x7BD3}, 
+  {0x7C1E,0x7BAA}, {0x7C21,0x7B80}, {0x7C23,0x7BD1}, {0x7C2B,0x7BAB}, {0x7C3D,0x7B7E}, 
+  {0x7C3E,0x5E18}, {0x7C43,0x7BEE}, {0x7C4C,0x7B79}, {0x7C5C,0x7BA8}, {0x7C5F,0x7C41}, 
+  {0x7C60,0x7B3C}, {0x7C69,0x7B3E}, {0x7C6A,0x7C16}, {0x7C6C,0x7BF1}, {0x7C6E,0x7BA9}, 
+  {0x7CDD,0x7CC1}, {0x7CDE,0x7CAA}, {0x7CE7,0x7CAE}, {0x7CF2,0x7C9D}, {0x7CF4,0x7C74}, 
+  {0x7CF6,0x7C9C}, {0x7CF9,0x7E9F}, {0x7CFE,0x7EA0}, {0x7D00,0x7EAA}, {0x7D02,0x7EA3}, 
+  {0x7D04,0x7EA6}, {0x7D05,0x7EA2}, {0x7D06,0x7EA1}, {0x7D07,0x7EA5}, {0x7D08,0x7EA8}, 
+  {0x7D09,0x7EAB}, {0x7D0B,0x7EB9}, {0x7D0D,0x7EB3}, {0x7D10,0x7EBD}, {0x7D13,0x7EBE}, 
+  {0x7D14,0x7EAF}, {0x7D15,0x7EB0}, {0x7D17,0x7EB1}, {0x7D19,0x7EB8}, {0x7D1A,0x7EA7}, 
+  {0x7D1B,0x7EB7}, {0x7D1C,0x7EAD}, {0x7D21,0x7EBA}, {0x7D30,0x7EC6}, {0x7D31,0x7EC2}, 
+  {0x7D32,0x7EC1}, {0x7D33,0x7EC5}, {0x7D39,0x7ECD}, {0x7D3A,0x7EC0}, {0x7D3C,0x7ECB}, 
+  {0x7D3F,0x7ED0}, {0x7D40,0x7ECC}, {0x7D42,0x7EC8}, {0x7D44,0x7EC4}, {0x7D46,0x7ECA}, 
+  {0x7D4E,0x7ED7}, {0x7D50,0x7ED3}, {0x7D5D,0x7ED4}, {0x7D5E,0x7EDE}, {0x7D61,0x7EDC}, 
+  {0x7D62,0x7EDA}, {0x7D66,0x7ED9}, {0x7D68,0x7ED2}, {0x7D71,0x7EDF}, {0x7D72,0x4E1D}, 
+  {0x7D73,0x7EDB}, {0x7D76,0x7EDD}, {0x7D79,0x7EE2}, {0x7D81,0x7ED1}, {0x7D83,0x7EE1}, 
+  {0x7D86,0x7EE0}, {0x7D88,0x7EE8}, {0x7D89,0x7EE3}, {0x7D8F,0x7EE5}, {0x7D93,0x7ECF}, 
+  {0x7D9C,0x7EFC}, {0x7D9E,0x7F0D}, {0x7DA2,0x7EF8}, {0x7DA3,0x7EFB}, {0x7DAB,0x7EBF}, 
+  {0x7DAC,0x7EF6}, {0x7DAD,0x7EF4}, {0x7DB0,0x7EFE}, {0x7DB1,0x7EB2}, {0x7DB2,0x7F51}, 
+  {0x7DB3,0x7EF7}, {0x7DB4,0x7F00}, {0x7DB8,0x7EB6}, {0x7DB9,0x7EFA}, {0x7DBA,0x7EEE}, 
+  {0x7DBB,0x7EFD}, {0x7DBD,0x7EF0}, {0x7DBE,0x7EEB}, {0x7DBF,0x7EF5}, {0x7DC4,0x7EF2}, 
+  {0x7DC7,0x7F01}, {0x7DCA,0x7D27}, {0x7DCB,0x7EEF}, {0x7DD1,0x7EFF}, {0x7DD2,0x7EEA}, 
+  {0x7DD4,0x7EF1}, {0x7DD7,0x7F03}, {0x7DD8,0x7F04}, {0x7DD9,0x7F02}, {0x7DDD,0x7F09}, 
+  {0x7DDE,0x7F0E}, {0x7DE0,0x7F14}, {0x7DE1,0x7F17}, {0x7DE3,0x7F18}, {0x7DE6,0x7F0C}, 
+  {0x7DE8,0x7F16}, {0x7DE9,0x7F13}, {0x7DEC,0x7F05}, {0x7DEF,0x7EAC}, {0x7DF1,0x7F11}, 
+  {0x7DF2,0x7F08}, {0x7DF4,0x7EC3}, {0x7DF6,0x7F0F}, {0x7DF9,0x7F07}, {0x7E08,0x8426}, 
+  {0x7E09,0x7F19}, {0x7E0A,0x7F22}, {0x7E0B,0x7F12}, {0x7E10,0x7EC9}, {0x7E11,0x7F23}, 
+  {0x7E1B,0x7F1A}, {0x7E1D,0x7F1C}, {0x7E1E,0x7F1F}, {0x7E1F,0x7F1B}, {0x7E23,0x53BF}, 
+  {0x7E27,0x7EE6}, {0x7E2B,0x7F1D}, {0x7E2D,0x7F21}, {0x7E2E,0x7F29}, {0x7E31,0x7EB5}, 
+  {0x7E32,0x7F27}, {0x7E35,0x7F26}, {0x7E36,0x7D77}, {0x7E37,0x7F15}, {0x7E39,0x7F25}, 
+  {0x7E3D,0x603B}, {0x7E3E,0x7EE9}, {0x7E45,0x7F2B}, {0x7E46,0x7F2A}, {0x7E52,0x7F2F}, 
+  {0x7E54,0x7EC7}, {0x7E55,0x7F2E}, {0x7E5A,0x7F2D}, {0x7E5E,0x7ED5}, {0x7E62,0x7F0B}, 
+  {0x7E69,0x7EF3}, {0x7E6A,0x7ED8}, {0x7E6D,0x8327}, {0x7E6E,0x7F30}, {0x7E6F,0x7F33}, 
+  {0x7E70,0x7F32}, {0x7E73,0x7F34}, {0x7E79,0x7ECE}, {0x7E7C,0x7EE7}, {0x7E7D,0x7F24}, 
+  {0x7E7E,0x7F31}, {0x7E88,0x7F2C}, {0x7E8A,0x7EA9}, {0x7E8C,0x7EED}, {0x7E8F,0x7F20}, 
+  {0x7E93,0x7F28}, {0x7E96,0x7EA4}, {0x7E98,0x7F35}, {0x7E9C,0x7F06}, {0x7F4C,0x7F42}, 
+  {0x7F70,0x7F5A}, {0x7F77,0x7F62}, {0x7F85,0x7F57}, {0x7F86,0x7F74}, {0x7F88,0x7F81}, 
+  {0x7FA5,0x7F9F}, {0x7FA9,0x4E49}, {0x7FD2,0x4E60}, {0x7FF9,0x7FD8}, {0x802C,0x8027}, 
+  {0x802E,0x8022}, {0x8056,0x5723}, {0x805E,0x95FB}, {0x806F,0x8054}, {0x8070,0x806A}, 
+  {0x8072,0x58F0}, {0x8073,0x8038}, {0x8075,0x8069}, {0x8076,0x8042}, {0x8077,0x804C}, 
+  {0x8079,0x804D}, {0x807D,0x542C}, {0x807E,0x804B}, {0x8085,0x8083}, {0x8105,0x80C1}, 
+  {0x811B,0x80EB}, {0x8139,0x80C0}, {0x814E,0x80BE}, {0x8156,0x80E8}, {0x8161,0x8136}, 
+  {0x8166,0x8111}, {0x816B,0x80BF}, {0x8178,0x80A0}, {0x819A,0x80A4}, {0x81A0,0x80F6}, 
+  {0x81A9,0x817B}, {0x81BD,0x80C6}, {0x81BE,0x810D}, {0x81BF,0x8113}, {0x81C9,0x8138}, 
+  {0x81CD,0x8110}, {0x81CF,0x8191}, {0x81D8,0x814A}, {0x81DA,0x80EA}, {0x81DF,0x810F}, 
+  {0x81E0,0x8114}, {0x81E8,0x4E34}, {0x81FA,0x53F0}, {0x8207,0x4E0E}, {0x8208,0x5174}, 
+  {0x8209,0x4E3E}, {0x820A,0x65E7}, {0x8259,0x8231}, {0x8264,0x8223}, {0x8266,0x8230}, 
+  {0x826B,0x823B}, {0x8271,0x8270}, {0x8277,0x8273}, {0x82BB,0x520D}, {0x82E7,0x82CE}, 
+  {0x838A,0x5E84}, {0x8396,0x830E}, {0x83A2,0x835A}, {0x83A7,0x82CB}, {0x83EF,0x534E}, 
+  {0x8407,0x82CC}, {0x840A,0x83B1}, {0x842C,0x4E07}, {0x8435,0x83B4}, {0x8449,0x53F6}, 
+  {0x8452,0x836D}, {0x8464,0x836E}, {0x8466,0x82C7}, {0x8477,0x8364}, {0x8493,0x83BC}, 
+  {0x8494,0x83B3}, {0x84BC,0x82CD}, {0x84C0,0x836A}, {0x84CB,0x76D6}, {0x84EE,0x83B2}, 
+  {0x84EF,0x82C1}, {0x84FD,0x835C}, {0x851E,0x848C}, {0x8523,0x848B}, {0x8526,0x8311}, 
+  {0x852D,0x836B}, {0x8541,0x8368}, {0x8546,0x8487}, {0x854E,0x835E}, {0x8552,0x836C}, 
+  {0x8553,0x82B8}, {0x8555,0x83B8}, {0x8558,0x835B}, {0x8562,0x8489}, {0x8569,0x8361}, 
+  {0x856A,0x829C}, {0x856D,0x8427}, {0x8577,0x84E3}, {0x8588,0x835F}, {0x858A,0x84DF}, 
+  {0x858C,0x8297}, {0x8594,0x8537}, {0x859F,0x83B6}, {0x85A6,0x8350}, {0x85A9,0x8428}, 
+  {0x85BA,0x8360}, {0x85CD,0x84DD}, {0x85CE,0x8369}, {0x85DD,0x827A}, {0x85E5,0x836F}, 
+  {0x85EA,0x85AE}, {0x85F4,0x8574}, {0x85F6,0x82C8}, {0x85F9,0x853C}, {0x85FA,0x853A}, 
+  {0x8604,0x8572}, {0x8606,0x82A6}, {0x8607,0x82CF}, {0x860B,0x82F9}, {0x861A,0x85D3}, 
+  {0x861E,0x8539}, {0x8622,0x830F}, {0x862D,0x5170}, {0x863A,0x84E0}, {0x863F,0x841D}, 
+  {0x8655,0x5904}, {0x865C,0x864F}, {0x865F,0x53F7}, {0x8667,0x4E8F}, {0x86FA,0x86F1}, 
+  {0x8706,0x86AC}, {0x8755,0x8680}, {0x8766,0x867E}, {0x8778,0x8717}, {0x8784,0x86F3}, 
+  {0x879E,0x8682}, {0x87A2,0x8424}, {0x87BB,0x877C}, {0x87C4,0x86F0}, {0x87C8,0x8748}, 
+  {0x87CE,0x87A8}, {0x87E3,0x866E}, {0x87EC,0x8749}, {0x87EF,0x86F2}, {0x87F2,0x866B}, 
+  {0x87F6,0x86CF}, {0x87FB,0x8681}, {0x8805,0x8747}, {0x8806,0x867F}, {0x8810,0x86F4}, 
+  {0x8811,0x877E}, {0x881F,0x8721}, {0x8823,0x86CE}, {0x8831,0x86CA}, {0x8836,0x8695}, 
+  {0x883B,0x86EE}, {0x8846,0x4F17}, {0x8853,0x672F}, {0x885B,0x536B}, {0x885D,0x51B2}, 
+  {0x8879,0x53EA}, {0x88CA,0x8885}, {0x88CF,0x91CC}, {0x88DC,0x8865}, {0x88DD,0x88C5}, 
+  {0x8932,0x88E4}, {0x8933,0x88E2}, {0x8938,0x891B}, {0x893B,0x4EB5}, {0x8947,0x88E5}, 
+  {0x8956,0x8884}, {0x895D,0x88E3}, {0x8960,0x88C6}, {0x8964,0x8934}, {0x896A,0x889C}, 
+  {0x896F,0x886C}, {0x8972,0x88AD}, {0x898B,0x89C1}, {0x898F,0x89C4}, {0x8993,0x89C5}, 
+  {0x8996,0x89C6}, {0x8998,0x89C7}, {0x89A1,0x89CB}, {0x89A6,0x89CE}, {0x89AA,0x4EB2}, 
+  {0x89AC,0x89CA}, {0x89AF,0x89CF}, {0x89B2,0x89D0}, {0x89B7,0x89D1}, {0x89BA,0x89C9}, 
+  {0x89BD,0x89C8}, {0x89BF,0x89CC}, {0x89C0,0x89C2}, {0x89F4,0x89DE}, {0x89F6,0x89EF}, 
+  {0x89F8,0x89E6}, {0x8A01,0x8BA0}, {0x8A02,0x8BA2}, {0x8A03,0x8BA3}, {0x8A08,0x8BA1}, 
+  {0x8A0A,0x8BAF}, {0x8A0C,0x8BA7}, {0x8A0E,0x8BA8}, {0x8A10,0x8BA6}, {0x8A13,0x8BAD}, 
+  {0x8A15,0x8BAA}, {0x8A16,0x8BAB}, {0x8A18,0x8BB0}, {0x8A1B,0x8BB9}, {0x8A1D,0x8BB6}, 
+  {0x8A1F,0x8BBC}, {0x8A23,0x8BC0}, {0x8A25,0x8BB7}, {0x8A2A,0x8BBF}, {0x8A2D,0x8BBE}, 
+  {0x8A31,0x8BB8}, {0x8A34,0x8BC9}, {0x8A36,0x8BC3}, {0x8A3A,0x8BCA}, {0x8A41,0x8BC2}, 
+  {0x8A46,0x8BCB}, {0x8A4E,0x8BB5}, {0x8A50,0x8BC8}, {0x8A52,0x8BD2}, {0x8A54,0x8BCF}, 
+  {0x8A55,0x8BC4}, {0x8A58,0x8BCE}, {0x8A5B,0x8BC5}, {0x8A5E,0x8BCD}, {0x8A61,0x8BE9}, 
+  {0x8A62,0x8BE2}, {0x8A63,0x8BE3}, {0x8A66,0x8BD5}, {0x8A69,0x8BD7}, {0x8A6B,0x8BE7}, 
+  {0x8A6C,0x8BDF}, {0x8A6D,0x8BE1}, {0x8A6E,0x8BE0}, {0x8A70,0x8BD8}, {0x8A71,0x8BDD}, 
+  {0x8A72,0x8BE5}, {0x8A73,0x8BE6}, {0x8A75,0x8BDC}, {0x8A7C,0x8BD9}, {0x8A7F,0x8BD6}, 
+  {0x8A84,0x8BD4}, {0x8A85,0x8BDB}, {0x8A86,0x8BD3}, {0x8A87,0x5938}, {0x8A8D,0x8BA4}, 
+  {0x8A91,0x8BF3}, {0x8A92,0x8BF6}, {0x8A95,0x8BDE}, {0x8A98,0x8BF1}, {0x8A9A,0x8BEE}, 
+  {0x8A9E,0x8BED}, {0x8AA0,0x8BDA}, {0x8AA1,0x8BEB}, {0x8AA3,0x8BEC}, {0x8AA4,0x8BEF}, 
+  {0x8AA5,0x8BF0}, {0x8AA6,0x8BF5}, {0x8AA8,0x8BF2}, {0x8AAC,0x8BF4}, {0x8AB0,0x8C01}, 
+  {0x8AB2,0x8BFE}, {0x8AB6,0x8C07}, {0x8AB9,0x8BFD}, {0x8ABC,0x8C0A}, {0x8ABF,0x8C03}, 
+  {0x8AC2,0x8C04}, {0x8AC4,0x8C06}, {0x8AC7,0x8C08}, {0x8AC9,0x8BFF}, {0x8ACB,0x8BF7}, 
+  {0x8ACD,0x8BE4}, {0x8ACF,0x8BF9}, {0x8AD1,0x8BFC}, {0x8AD2,0x8C05}, {0x8AD6,0x8BBA}, 
+  {0x8AD7,0x8C02}, {0x8ADB,0x8C00}, {0x8ADC,0x8C0D}, {0x8ADE,0x8C1D}, {0x8AE2,0x8BE8}, 
+  {0x8AE4,0x8C14}, {0x8AE6,0x8C1B}, {0x8AE7,0x8C10}, {0x8AEB,0x8C0F}, {0x8AED,0x8C15}, 
+  {0x8AEE,0x8C18}, {0x8AF1,0x8BB3}, {0x8AF3,0x8C19}, {0x8AF6,0x8C0C}, {0x8AF7,0x8BBD}, 
+  {0x8AF8,0x8BF8}, {0x8AFA,0x8C1A}, {0x8AFC,0x8C16}, {0x8AFE,0x8BFA}, {0x8B00,0x8C0B}, 
+  {0x8B01,0x8C12}, {0x8B02,0x8C13}, {0x8B04,0x8A8A}, {0x8B05,0x8BCC}, {0x8B0A,0x8C0E}, 
+  {0x8B0E,0x8C1C}, {0x8B10,0x8C27}, {0x8B14,0x8C11}, {0x8B16,0x8C21}, {0x8B17,0x8C24}, 
+  {0x8B19,0x8C26}, {0x8B1A,0x8C25}, {0x8B1B,0x8BB2}, {0x8B1D,0x8C22}, {0x8B21,0x8C23}, 
+  {0x8B28,0x8C1F}, {0x8B2B,0x8C2A}, {0x8B2C,0x8C2C}, {0x8B2D,0x8C2B}, {0x8B33,0x8BB4}, 
+  {0x8B39,0x8C28}, {0x8B3E,0x8C29}, {0x8B49,0x8BC1}, {0x8B4E,0x8C32}, {0x8B4F,0x8BA5}, 
+  {0x8B56,0x8C2E}, {0x8B58,0x8BC6}, {0x8B59,0x8C2F}, {0x8B5A,0x8C2D}, {0x8B5C,0x8C31}, 
+  {0x8B6B,0x8C35}, {0x8B6F,0x8BD1}, {0x8B70,0x8BAE}, {0x8B74,0x8C34}, {0x8B77,0x62A4}, 
+  {0x8B7D,0x8A89}, {0x8B80,0x8BFB}, {0x8B8A,0x53D8}, {0x8B8E,0x96E0}, {0x8B92,0x8C17}, 
+  {0x8B93,0x8BA9}, {0x8B95,0x8C30}, {0x8B96,0x8C36}, {0x8B9C,0x8C20}, {0x8B9E,0x8C33}, 
+  {0x8C48,0x5C82}, {0x8C50,0x4E30}, {0x8C9D,0x8D1D}, {0x8C9E,0x8D1E}, {0x8CA0,0x8D1F}, 
+  {0x8CA1,0x8D22}, {0x8CA2,0x8D21}, {0x8CA7,0x8D2B}, {0x8CA8,0x8D27}, {0x8CA9,0x8D29}, 
+  {0x8CAA,0x8D2A}, {0x8CAB,0x8D2F}, {0x8CAC,0x8D23}, {0x8CAF,0x8D2E}, {0x8CB0,0x8D33}, 
+  {0x8CB2,0x8D40}, {0x8CB3,0x8D30}, {0x8CB4,0x8D35}, {0x8CB6,0x8D2C}, {0x8CB7,0x4E70}, 
+  {0x8CB8,0x8D37}, {0x8CBA,0x8D36}, {0x8CBB,0x8D39}, {0x8CBC,0x8D34}, {0x8CBD,0x8D3B}, 
+  {0x8CBF,0x8D38}, {0x8CC0,0x8D3A}, {0x8CC1,0x8D32}, {0x8CC2,0x8D42}, {0x8CC3,0x8D41}, 
+  {0x8CC4,0x8D3F}, {0x8CC5,0x8D45}, {0x8CC7,0x8D44}, {0x8CC8,0x8D3E}, {0x8CCA,0x8D3C}, 
+  {0x8CD1,0x8D48}, {0x8CD2,0x8D4A}, {0x8CD3,0x5BBE}, {0x8CD5,0x8D47}, {0x8CDA,0x8D49}, 
+  {0x8CDC,0x8D50}, {0x8CDE,0x8D4F}, {0x8CE0,0x8D54}, {0x8CE1,0x8D53}, {0x8CE2,0x8D24}, 
+  {0x8CE3,0x5356}, {0x8CE4,0x8D31}, {0x8CE6,0x8D4B}, {0x8CE7,0x8D55}, {0x8CEA,0x8D28}, 
+  {0x8CEB,0x8D4D}, {0x8CEC,0x8D26}, {0x8CED,0x8D4C}, {0x8CF4,0x8D56}, {0x8CFA,0x8D5A}, 
+  {0x8CFB,0x8D59}, {0x8CFC,0x8D2D}, {0x8CFD,0x8D5B}, {0x8CFE,0x8D5C}, {0x8D04,0x8D3D}, 
+  {0x8D05,0x8D58}, {0x8D08,0x8D60}, {0x8D0A,0x8D5E}, {0x8D0B,0x8D5D}, {0x8D0D,0x8D61}, 
+  {0x8D0F,0x8D62}, {0x8D10,0x8D46}, {0x8D16,0x8D4E}, {0x8D1B,0x8D63}, {0x8D1C,0x8D43}, 
+  {0x8D95,0x8D76}, {0x8D99,0x8D75}, {0x8DA8,0x8D8B}, {0x8DB2,0x8DB1}, {0x8E10,0x8DF5}, 
+  {0x8E34,0x8E0A}, {0x8E4C,0x8DC4}, {0x8E55,0x8DF8}, {0x8E63,0x8E52}, {0x8E7A,0x8DF7}, 
+  {0x8E89,0x8DB8}, {0x8E8A,0x8E0C}, {0x8E8B,0x8DFB}, {0x8E8D,0x8DC3}, {0x8E91,0x8E2F}, 
+  {0x8E92,0x8DDE}, {0x8E93,0x8E2C}, {0x8E9A,0x8DF9}, {0x8EA1,0x8E51}, {0x8EA5,0x8E7F}, 
+  {0x8EA6,0x8E9C}, {0x8EAA,0x8E8F}, {0x8EC0,0x8EAF}, {0x8ECA,0x8F66}, {0x8ECB,0x8F67}, 
+  {0x8ECC,0x8F68}, {0x8ECD,0x519B}, {0x8ED2,0x8F69}, {0x8ED4,0x8F6B}, {0x8EDB,0x8F6D}, 
+  {0x8EDF,0x8F6F}, {0x8EE4,0x8F77}, {0x8EEB,0x8F78}, {0x8EF2,0x8F71}, {0x8EF8,0x8F74}, 
+  {0x8EF9,0x8F75}, {0x8EFA,0x8F7A}, {0x8EFB,0x8F72}, {0x8EFC,0x8F76}, {0x8EFE,0x8F7C}, 
+  {0x8F03,0x8F83}, {0x8F05,0x8F82}, {0x8F07,0x8F81}, {0x8F09,0x8F7D}, {0x8F0A,0x8F7E}, 
+  {0x8F12,0x8F84}, {0x8F14,0x8F85}, {0x8F15,0x8F7B}, {0x8F1B,0x8F86}, {0x8F1C,0x8F8E}, 
+  {0x8F1D,0x8F89}, {0x8F1E,0x8F8B}, {0x8F1F,0x8F8D}, {0x8F25,0x8F8A}, {0x8F26,0x8F87}, 
+  {0x8F29,0x8F88}, {0x8F2A,0x8F6E}, {0x8F2F,0x8F91}, {0x8F33,0x8F8F}, {0x8F38,0x8F93}, 
+  {0x8F3B,0x8F90}, {0x8F3E,0x8F97}, {0x8F3F,0x8206}, {0x8F42,0x6BC2}, {0x8F44,0x8F96}, 
+  {0x8F45,0x8F95}, {0x8F46,0x8F98}, {0x8F49,0x8F6C}, {0x8F4D,0x8F99}, {0x8F4E,0x8F7F}, 
+  {0x8F54,0x8F9A}, {0x8F5F,0x8F70}, {0x8F61,0x8F94}, {0x8F62,0x8F79}, {0x8F64,0x8F73}, 
+  {0x8FA6,0x529E}, {0x8FAD,0x8F9E}, {0x8FAE,0x8FAB}, {0x8FAF,0x8FA9}, {0x8FB2,0x519C}, 
+  {0x9015,0x8FF3}, {0x9019,0x8FD9}, {0x9023,0x8FDE}, {0x9032,0x8FDB}, {0x904B,0x8FD0}, 
+  {0x904E,0x8FC7}, {0x9054,0x8FBE}, {0x9055,0x8FDD}, {0x905C,0x900A}, {0x905E,0x9012}, 
+  {0x9060,0x8FDC}, {0x9069,0x9002}, {0x9072,0x8FDF}, {0x9077,0x8FC1}, {0x9078,0x9009}, 
+  {0x907A,0x9057}, {0x907C,0x8FBD}, {0x9081,0x8FC8}, {0x9084,0x8FD8}, {0x9087,0x8FE9}, 
+  {0x908A,0x8FB9}, {0x908F,0x903B}, {0x9090,0x9026}, {0x90DF,0x90CF}, {0x90F5,0x90AE}, 
+  {0x9106,0x90D3}, {0x9109,0x4E61}, {0x9112,0x90B9}, {0x9114,0x90AC}, {0x9116,0x90E7}, 
+  {0x9127,0x9093}, {0x912D,0x90D1}, {0x9130,0x90BB}, {0x9132,0x90F8}, {0x9134,0x90BA}, 
+  {0x9136,0x90D0}, {0x913A,0x909D}, {0x9148,0x90E6}, {0x9196,0x915D}, {0x919C,0x4E11}, 
+  {0x91AB,0x533B}, {0x91AC,0x9171}, {0x91C0,0x917F}, {0x91C1,0x8845}, {0x91C3,0x917E}, 
+  {0x91C5,0x917D}, {0x91CB,0x91CA}, {0x91D2,0x9485}, {0x91D3,0x9486}, {0x91D4,0x9487}, 
+  {0x91D5,0x948C}, {0x91D7,0x948A}, {0x91D8,0x9489}, {0x91D9,0x948B}, {0x91DD,0x9488}, 
+  {0x91E3,0x9493}, {0x91E4,0x9490}, {0x91E7,0x948F}, {0x91E9,0x9492}, {0x91F5,0x9497}, 
+  {0x91F7,0x948D}, {0x91F9,0x9495}, {0x91FA,0x948E}, {0x9200,0x94AF}, {0x9201,0x94AB}, 
+  {0x9204,0x94AD}, {0x9208,0x949A}, {0x9209,0x94A0}, {0x920D,0x949D}, {0x920E,0x94A9}, 
+  {0x9210,0x94A4}, {0x9211,0x94A3}, {0x9214,0x949E}, {0x9215,0x94AE}, {0x921E,0x94A7}, 
+  {0x9223,0x9499}, {0x9225,0x94AC}, {0x9226,0x949B}, {0x9227,0x94AA}, {0x922E,0x94CC}, 
+  {0x9230,0x94C8}, {0x9233,0x94B6}, {0x9234,0x94C3}, {0x9237,0x94B4}, {0x9238,0x94B9}, 
+  {0x9239,0x94CD}, {0x923A,0x94B0}, {0x923D,0x94B8}, {0x923E,0x94C0}, {0x923F,0x94BF}, 
+  {0x9240,0x94BE}, {0x9245,0x949C}, {0x9248,0x94CA}, {0x9249,0x94C9}, {0x924D,0x94CB}, 
+  {0x9251,0x94C2}, {0x9255,0x94B7}, {0x9257,0x94B3}, {0x925A,0x94C6}, {0x925B,0x94C5}, 
+  {0x925E,0x94BA}, {0x9262,0x94B5}, {0x9266,0x94B2}, {0x926C,0x94BC}, {0x926D,0x94BD}, 
+  {0x9278,0x94F0}, {0x927A,0x94D2}, {0x927B,0x94EC}, {0x927F,0x94EA}, {0x9280,0x94F6}, 
+  {0x9283,0x94F3}, {0x9285,0x94DC}, {0x9291,0x94E3}, {0x9293,0x94E8}, {0x9296,0x94E2}, 
+  {0x9298,0x94ED}, {0x929A,0x94EB}, {0x929C,0x8854}, {0x92A0,0x94D1}, {0x92A3,0x94F7}, 
+  {0x92A5,0x94F1}, {0x92A6,0x94DF}, {0x92A8,0x94F5}, {0x92A9,0x94E5}, {0x92AA,0x94D5}, 
+  {0x92AB,0x94EF}, {0x92AC,0x94D0}, {0x92B1,0x94DE}, {0x92B7,0x9500}, {0x92B9,0x9508}, 
+  {0x92BB,0x9511}, {0x92BC,0x9509}, {0x92C1,0x94DD}, {0x92C3,0x9512}, {0x92C5,0x950C}, 
+  {0x92C7,0x94A1}, {0x92CC,0x94E4}, {0x92CF,0x94D7}, {0x92D2,0x950B}, {0x92DD,0x950A}, 
+  {0x92DF,0x9513}, {0x92E3,0x94D8}, {0x92E4,0x9504}, {0x92E5,0x9503}, {0x92E6,0x9514}, 
+  {0x92E8,0x9507}, {0x92EA,0x94FA}, {0x92ED,0x9510}, {0x92EE,0x94D6}, {0x92EF,0x9506}, 
+  {0x92F0,0x9502}, {0x92F1,0x94FD}, {0x92F6,0x950D}, {0x92F8,0x952F}, {0x92FC,0x94A2}, 
+  {0x9301,0x951E}, {0x9306,0x9516}, {0x9307,0x952B}, {0x9308,0x9529}, {0x9310,0x9525}, 
+  {0x9312,0x9515}, {0x9315,0x951F}, {0x9318,0x9524}, {0x9319,0x9531}, {0x931A,0x94EE}, 
+  {0x931B,0x951B}, {0x931F,0x952C}, {0x9320,0x952D}, {0x9322,0x94B1}, {0x9326,0x9526}, 
+  {0x9328,0x951A}, {0x932B,0x9521}, {0x932E,0x9522}, {0x932F,0x9519}, {0x9332,0x5F55}, 
+  {0x9333,0x9530}, {0x9338,0x94FC}, {0x9340,0x951D}, {0x9341,0x9528}, {0x9343,0x952A}, 
+  {0x9346,0x9494}, {0x9347,0x9534}, {0x934B,0x9505}, {0x934D,0x9540}, {0x9354,0x9537}, 
+  {0x9358,0x94E1}, {0x935B,0x953B}, {0x9364,0x9538}, {0x9365,0x9532}, {0x9369,0x9518}, 
+  {0x936C,0x9539}, {0x9370,0x953E}, {0x9375,0x952E}, {0x9376,0x9536}, {0x937A,0x9517}, 
+  {0x937E,0x953A}, {0x9382,0x9541}, {0x9384,0x953F}, {0x9387,0x9545}, {0x938A,0x9551}, 
+  {0x9396,0x9501}, {0x9398,0x9549}, {0x93A2,0x94A8}, {0x93A3,0x84E5}, {0x93A6,0x954F}, 
+  {0x93A7,0x94E0}, {0x93A9,0x94E9}, {0x93AA,0x953C}, {0x93AC,0x9550}, {0x93AE,0x9547}, 
+  {0x93B0,0x9552}, {0x93B3,0x954D}, {0x93B5,0x9553}, {0x93B8,0x954C}, {0x93BF,0x954E}, 
+  {0x93C3,0x955E}, {0x93C7,0x955F}, {0x93C8,0x94FE}, {0x93CC,0x9546}, {0x93CD,0x9559}, 
+  {0x93D1,0x955D}, {0x93D7,0x94FF}, {0x93D8,0x9535}, {0x93DC,0x9557}, {0x93DD,0x9558}, 
+  {0x93DE,0x955B}, {0x93DF,0x94F2}, {0x93E1,0x955C}, {0x93E2,0x9556}, {0x93E4,0x9542}, 
+  {0x93E8,0x933E}, {0x93F5,0x94E7}, {0x93F7,0x9564}, {0x93F9,0x956A}, {0x9403,0x94D9}, 
+  {0x940B,0x94F4}, {0x9410,0x9563}, {0x9412,0x94F9}, {0x9413,0x9566}, {0x9414,0x9561}, 
+  {0x9418,0x949F}, {0x9419,0x956B}, {0x941D,0x9562}, {0x9420,0x9568}, {0x9426,0x950E}, 
+  {0x9427,0x950F}, {0x9428,0x9544}, {0x942E,0x9570}, {0x9432,0x956F}, {0x9433,0x956D}, 
+  {0x9435,0x94C1}, {0x9438,0x94CE}, {0x943A,0x94DB}, {0x943F,0x9571}, {0x9444,0x94F8}, 
+  {0x944A,0x956C}, {0x944C,0x9554}, {0x9452,0x9274}, {0x9454,0x9572}, {0x9460,0x94C4}, 
+  {0x9463,0x9573}, {0x9465,0x9565}, {0x946D,0x9567}, {0x9470,0x94A5}, {0x9472,0x9576}, 
+  {0x9477,0x954A}, {0x9479,0x9569}, {0x947C,0x9523}, {0x947D,0x94BB}, {0x947E,0x92AE}, 
+  {0x947F,0x51FF}, {0x9577,0x957F}, {0x9580,0x95E8}, {0x9582,0x95E9}, {0x9583,0x95EA}, 
+  {0x9586,0x95EB}, {0x9589,0x95ED}, {0x958B,0x5F00}, {0x958C,0x95F6}, {0x958E,0x95F3}, 
+  {0x958F,0x95F0}, {0x9591,0x95F2}, {0x9593,0x95F4}, {0x9594,0x95F5}, {0x9598,0x95F8}, 
+  {0x95A1,0x9602}, {0x95A3,0x9601}, {0x95A5,0x9600}, {0x95A8,0x95FA}, {0x95A9,0x95FD}, 
+  {0x95AB,0x9603}, {0x95AC,0x9606}, {0x95AD,0x95FE}, {0x95B2,0x9605}, {0x95B6,0x960A}, 
+  {0x95B9,0x9609}, {0x95BB,0x960E}, {0x95BC,0x960F}, {0x95BD,0x960D}, {0x95BE,0x9608}, 
+  {0x95BF,0x960C}, {0x95C3,0x9612}, {0x95C8,0x95F1}, {0x95CA,0x9614}, {0x95CB,0x9615}, 
+  {0x95CC,0x9611}, {0x95D0,0x9617}, {0x95D4,0x9616}, {0x95D5,0x9619}, {0x95D6,0x95EF}, 
+  {0x95DC,0x5173}, {0x95DE,0x961A}, {0x95E1,0x9610}, {0x95E5,0x95FC}, {0x9658,0x9649}, 
+  {0x965D,0x9655}, {0x9663,0x9635}, {0x9670,0x9634}, {0x9673,0x9648}, {0x9678,0x9646}, 
+  {0x967D,0x9633}, {0x9689,0x9667}, {0x968A,0x961F}, {0x968E,0x9636}, {0x9695,0x9668}, 
+  {0x969B,0x9645}, {0x96A8,0x968F}, {0x96AA,0x9669}, {0x96B1,0x9690}, {0x96B4,0x9647}, 
+  {0x96B8,0x96B6}, {0x96D6,0x867D}, {0x96D9,0x53CC}, {0x96DB,0x96CF}, {0x96DC,0x6742}, 
+  {0x96E2,0x79BB}, {0x96E3,0x96BE}, {0x96F2,0x4E91}, {0x96FB,0x7535}, {0x9727,0x96FE}, 
+  {0x973D,0x9701}, {0x9742,0x96F3}, {0x9744,0x972D}, {0x9748,0x7075}, {0x975A,0x9753}, 
+  {0x975C,0x9759}, {0x9768,0x9765}, {0x978F,0x5DE9}, {0x97BD,0x9792}, {0x97C3,0x9791}, 
+  {0x97C9,0x97AF}, {0x97CB,0x97E6}, {0x97CC,0x97E7}, {0x97D3,0x97E9}, {0x97D9,0x97EA}, 
+  {0x97DC,0x97EC}, {0x97DE,0x97EB}, {0x97FF,0x54CD}, {0x9801,0x9875}, {0x9802,0x9876}, 
+  {0x9803,0x9877}, {0x9805,0x9879}, {0x9806,0x987A}, {0x9807,0x9878}, {0x9808,0x987B}, 
+  {0x980A,0x987C}, {0x980C,0x9882}, {0x980E,0x9880}, {0x980F,0x9883}, {0x9810,0x9884}, 
+  {0x9811,0x987D}, {0x9812,0x9881}, {0x9813,0x987F}, {0x9817,0x9887}, {0x9818,0x9886}, 
+  {0x981C,0x988C}, {0x9821,0x9889}, {0x9824,0x9890}, {0x9826,0x988F}, {0x982D,0x5934}, 
+  {0x9830,0x988A}, {0x9837,0x9894}, {0x9838,0x9888}, {0x983B,0x9891}, {0x983D,0x9893}, 
+  {0x9846,0x9897}, {0x984C,0x9898}, {0x984D,0x989D}, {0x984E,0x989A}, {0x9853,0x989B}, 
+  {0x9854,0x989C}, {0x9858,0x613F}, {0x9859,0x98A1}, {0x985B,0x98A0}, {0x985E,0x7C7B}, 
+  {0x9862,0x989F}, {0x9865,0x98A2}, {0x9867,0x987E}, {0x986B,0x98A4}, {0x986C,0x98A5}, 
+  {0x986F,0x663E}, {0x9870,0x98A6}, {0x9871,0x9885}, {0x9873,0x989E}, {0x9874,0x98A7}, 
+  {0x98A8,0x98CE}, {0x98AE,0x98D1}, {0x98AF,0x98D2}, {0x98B6,0x98D3}, {0x98BC,0x98D5}, 
+  {0x98C4,0x98D8}, {0x98C6,0x98D9}, {0x98C8,0x98DA}, {0x98DB,0x98DE}, {0x98E0,0x9963}, 
+  {0x98E9,0x9968}, {0x98EA,0x996A}, {0x98EB,0x996B}, {0x98ED,0x996C}, {0x98EF,0x996D}, 
+  {0x98F2,0x996E}, {0x98F4,0x9974}, {0x98FC,0x9972}, {0x98FD,0x9971}, {0x98FE,0x9970}, 
+  {0x9903,0x997A}, {0x9905,0x997C}, {0x9909,0x9977}, {0x990A,0x517B}, {0x990C,0x9975}, 
+  {0x9911,0x997D}, {0x9912,0x9981}, {0x9913,0x997F}, {0x9918,0x4F59}, {0x991B,0x9984}, 
+  {0x991E,0x996F}, {0x9921,0x9985}, {0x9928,0x9986}, {0x9933,0x9967}, {0x9937,0x9987}, 
+  {0x993C,0x9969}, {0x993E,0x998F}, {0x993F,0x998A}, {0x9943,0x998D}, {0x9945,0x9992}, 
+  {0x9948,0x9990}, {0x9949,0x9991}, {0x994A,0x9993}, {0x994B,0x9988}, {0x994C,0x9994}, 
+  {0x9951,0x9965}, {0x9952,0x9976}, {0x9957,0x98E8}, {0x995C,0x990D}, {0x995E,0x998B}, 
+  {0x9962,0x9995}, {0x99AC,0x9A6C}, {0x99AD,0x9A6D}, {0x99AE,0x51AF}, {0x99B1,0x9A6E}, 
+  {0x99B3,0x9A70}, {0x99B4,0x9A6F}, {0x99C1,0x9A73}, {0x99D0,0x9A7B}, {0x99D1,0x9A7D}, 
+  {0x99D2,0x9A79}, {0x99D4,0x9A75}, {0x99D5,0x9A7E}, {0x99D8,0x9A80}, {0x99D9,0x9A78}, 
+  {0x99DB,0x9A76}, {0x99DD,0x9A7C}, {0x99DF,0x9A77}, {0x99E1,0x9A82}, {0x99E2,0x9A88}, 
+  {0x99ED,0x9A87}, {0x99F1,0x9A86}, {0x99FF,0x9A8F}, {0x9A01,0x9A8B}, {0x9A05,0x9A93}, 
+  {0x9A0D,0x9A92}, {0x9A0E,0x9A91}, {0x9A0F,0x9A90}, {0x9A16,0x9A9B}, {0x9A19,0x9A97}, 
+  {0x9A2B,0x9A9E}, {0x9A2D,0x9A98}, {0x9A2E,0x9A9D}, {0x9A30,0x817E}, {0x9A36,0x9A7A}, 
+  {0x9A37,0x9A9A}, {0x9A38,0x9A9F}, {0x9A3E,0x9AA1}, {0x9A40,0x84E6}, {0x9A41,0x9A9C}, 
+  {0x9A42,0x9A96}, {0x9A43,0x9AA0}, {0x9A44,0x9AA2}, {0x9A45,0x9A71}, {0x9A4A,0x9A85}, 
+  {0x9A4D,0x9A81}, {0x9A4F,0x9AA3}, {0x9A55,0x9A84}, {0x9A57,0x9A8C}, {0x9A5A,0x60CA}, 
+  {0x9A5B,0x9A7F}, {0x9A5F,0x9AA4}, {0x9A62,0x9A74}, {0x9A64,0x9AA7}, {0x9A65,0x9AA5}, 
+  {0x9A6A,0x9A8A}, {0x9AAF,0x80AE}, {0x9ACF,0x9AC5}, {0x9AD4,0x4F53}, {0x9AD5,0x9ACC}, 
+  {0x9AD6,0x9ACB}, {0x9B06,0x677E}, {0x9B22,0x9B13}, {0x9B25,0x6597}, {0x9B27,0x95F9}, 
+  {0x9B29,0x960B}, {0x9B2E,0x9604}, {0x9B31,0x90C1}, {0x9B4E,0x9B49}, {0x9B58,0x9B47}, 
+  {0x9B5A,0x9C7C}, {0x9B6F,0x9C81}, {0x9B74,0x9C82}, {0x9B77,0x9C7F}, {0x9B81,0x9C85}, 
+  {0x9B83,0x9C86}, {0x9B8E,0x9C87}, {0x9B90,0x9C90}, {0x9B91,0x9C8D}, {0x9B92,0x9C8B}, 
+  {0x9B9A,0x9C92}, {0x9B9D,0x9C9E}, {0x9B9E,0x9C95}, {0x9BAA,0x9C94}, {0x9BAB,0x9C9B}, 
+  {0x9BAD,0x9C91}, {0x9BAE,0x9C9C}, {0x9BC0,0x9CA7}, {0x9BC1,0x9CA0}, {0x9BC7,0x9CA9}, 
+  {0x9BC9,0x9CA4}, {0x9BCA,0x9CA8}, {0x9BD4,0x9CBB}, {0x9BD6,0x9CAD}, {0x9BDB,0x9CB7}, 
+  {0x9BDD,0x9CB4}, {0x9BE1,0x9CB1}, {0x9BE2,0x9CB5}, {0x9BE4,0x9CB2}, {0x9BE7,0x9CB3}, 
+  {0x9BE8,0x9CB8}, {0x9BEA,0x9CAE}, {0x9BEB,0x9CB0}, {0x9BF0,0x9CB6}, {0x9BF4,0x9CBA}, 
+  {0x9BFD,0x9CAB}, {0x9BFF,0x9CCA}, {0x9C08,0x9CBD}, {0x9C09,0x9CC7}, {0x9C0D,0x9CC5}, 
+  {0x9C10,0x9CC4}, {0x9C12,0x9CC6}, {0x9C13,0x9CC3}, {0x9C20,0x9CCB}, {0x9C23,0x9CA5}, 
+  {0x9C25,0x9CCF}, {0x9C28,0x9CCE}, {0x9C29,0x9CD0}, {0x9C2D,0x9CCD}, {0x9C31,0x9CA2}, 
+  {0x9C32,0x9CCC}, {0x9C33,0x9CD3}, {0x9C35,0x9CD8}, {0x9C37,0x9CA6}, {0x9C39,0x9CA3}, 
+  {0x9C3B,0x9CD7}, {0x9C3E,0x9CD4}, {0x9C45,0x9CD9}, {0x9C48,0x9CD5}, {0x9C49,0x9CD6}, 
+  {0x9C52,0x9CDF}, {0x9C54,0x9CDD}, {0x9C56,0x9CDC}, {0x9C57,0x9CDE}, {0x9C58,0x9C9F}, 
+  {0x9C5D,0x9CBC}, {0x9C5F,0x9C8E}, {0x9C67,0x9CE2}, {0x9C6D,0x9C9A}, {0x9C78,0x9C88}, 
+  {0x9C7A,0x9CA1}, {0x9CE5,0x9E1F}, {0x9CE9,0x9E20}, {0x9CEC,0x51EB}, {0x9CF3,0x51E4}, 
+  {0x9CF4,0x9E23}, {0x9CF6,0x9E22}, {0x9D06,0x9E29}, {0x9D07,0x9E28}, {0x9D09,0x9E26}, 
+  {0x9D15,0x9E35}, {0x9D1B,0x9E33}, {0x9D1D,0x9E32}, {0x9D1F,0x9E31}, {0x9D23,0x9E2A}, 
+  {0x9D26,0x9E2F}, {0x9D28,0x9E2D}, {0x9D2F,0x9E38}, {0x9D30,0x9E39}, {0x9D3B,0x9E3F}, 
+  {0x9D3F,0x9E3D}, {0x9D42,0x9E3A}, {0x9D51,0x9E43}, {0x9D52,0x9E46}, {0x9D53,0x9E41}, 
+  {0x9D5C,0x9E48}, {0x9D5D,0x9E45}, {0x9D60,0x9E44}, {0x9D61,0x9E49}, {0x9D6A,0x9E4C}, 
+  {0x9D6C,0x9E4F}, {0x9D6F,0x9E4E}, {0x9D72,0x9E4A}, {0x9D87,0x9E2B}, {0x9D89,0x9E51}, 
+  {0x9D93,0x9E4B}, {0x9D98,0x9E55}, {0x9D9A,0x9E57}, {0x9DA5,0x9E5B}, {0x9DA9,0x9E5C}, 
+  {0x9DAF,0x83BA}, {0x9DB4,0x9E64}, {0x9DBB,0x9E58}, {0x9DBC,0x9E63}, {0x9DC0,0x9E5A}, 
+  {0x9DC2,0x9E5E}, {0x9DC4,0x9E21}, {0x9DD3,0x9E67}, {0x9DD7,0x9E25}, {0x9DD9,0x9E37}, 
+  {0x9DDA,0x9E68}, {0x9DE5,0x9E36}, {0x9DE6,0x9E6A}, {0x9DEF,0x9E69}, {0x9DF2,0x9E6B}, 
+  {0x9DF3,0x9E47}, {0x9DF8,0x9E6C}, {0x9DF9,0x9E70}, {0x9DFA,0x9E6D}, {0x9E0C,0x9E71}, 
+  {0x9E15,0x9E2C}, {0x9E1A,0x9E66}, {0x9E1B,0x9E73}, {0x9E1D,0x9E42}, {0x9E1E,0x9E3E}, 
+  {0x9E7A,0x9E7E}, {0x9E7C,0x7877}, {0x9E7D,0x76D0}, {0x9E97,0x4E3D}, {0x9EA5,0x9EA6}, 
+  {0x9EA9,0x9EB8}, {0x9EBD,0x4E48}, {0x9ECC,0x9EC9}, {0x9EDE,0x70B9}, {0x9EE8,0x515A}, 
+  {0x9EF2,0x9EEA}, {0x9EF7,0x9EE9}, {0x9EFD,0x9EFE}, {0x9EFF,0x9F0B}, {0x9F09,0x9F0D}, 
+  {0x9F4A,0x9F50}, {0x9F4B,0x658B}, {0x9F4F,0x9F51}, {0x9F52,0x9F7F}, {0x9F54,0x9F80}, 
+  {0x9F59,0x9F85}, {0x9F5C,0x9F87}, {0x9F5F,0x9F83}, {0x9F60,0x9F86}, {0x9F61,0x9F84}, 
+  {0x9F66,0x9F88}, {0x9F6A,0x9F8A}, {0x9F6C,0x9F89}, {0x9F72,0x9F8B}, {0x9F77,0x9F8C}, 
+  {0x9F8D,0x9F99}, {0x9F90,0x5E9E}, {0x9F94,0x9F9A}, {0x9F95,0x9F9B}, {0x9F9C,0x9F9F}
+};
+
+
+
+/* the letters correspond to unicode characters which
+ * have Lu, Ll, Lt, Lm, Lo, Mn, Mc, or Me in their
+ * GENERAL CATEGORY */
+
+#define NUM_LETTER_INFO 274
+static const unirange letter_info[NUM_LETTER_INFO] = {
+  {0x41,0x5a}, {0x61,0x7a}, {0xaa,0xaa}, {0xb5,0xb5}, 
+  {0xba,0xba}, {0xc0,0xd6}, {0xd8,0xf6}, {0xf8,0x1f5}, 
+  {0x1fa,0x217}, {0x250,0x2a8}, {0x2b0,0x2b8}, {0x2bb,0x2c1}, 
+  {0x2d0,0x2d1}, {0x2e0,0x2e4}, {0x300,0x345}, {0x360,0x361}, 
+  {0x37a,0x37a}, {0x386,0x386}, {0x388,0x38a}, {0x38c,0x38c}, 
+  {0x38e,0x3a1}, {0x3a3,0x3ce}, {0x3d0,0x3d6}, {0x3da,0x3da}, 
+  {0x3dc,0x3dc}, {0x3de,0x3de}, {0x3e0,0x3e0}, {0x3e2,0x3f3}, 
+  {0x401,0x40c}, {0x40e,0x44f}, {0x451,0x45c}, {0x45e,0x481}, 
+  {0x483,0x486}, {0x490,0x4c4}, {0x4c7,0x4c8}, {0x4cb,0x4cc}, 
+  {0x4d0,0x4eb}, {0x4ee,0x4f5}, {0x4f8,0x4f9}, {0x531,0x556}, 
+  {0x559,0x559}, {0x561,0x587}, {0x591,0x5a1}, {0x5a3,0x5b9}, 
+  {0x5bb,0x5bd}, {0x5bf,0x5bf}, {0x5c1,0x5c2}, {0x5c4,0x5c4}, 
+  {0x5d0,0x5ea}, {0x5f0,0x5f2}, {0x621,0x63a}, {0x640,0x652}, 
+  {0x670,0x6b7}, {0x6ba,0x6be}, {0x6c0,0x6ce}, {0x6d0,0x6d3}, 
+  {0x6d5,0x6e8}, {0x6ea,0x6ed}, {0x901,0x903}, {0x905,0x939}, 
+  {0x93c,0x94d}, {0x951,0x954}, {0x958,0x963}, {0x981,0x983}, 
+  {0x985,0x98c}, {0x98f,0x990}, {0x993,0x9a8}, {0x9aa,0x9b0}, 
+  {0x9b2,0x9b2}, {0x9b6,0x9b9}, {0x9bc,0x9bc}, {0x9be,0x9c4}, 
+  {0x9c7,0x9c8}, {0x9cb,0x9cd}, {0x9d7,0x9d7}, {0x9dc,0x9dd}, 
+  {0x9df,0x9e3}, {0x9f0,0x9f1}, {0xa02,0xa02}, {0xa05,0xa0a}, 
+  {0xa0f,0xa10}, {0xa13,0xa28}, {0xa2a,0xa30}, {0xa32,0xa33}, 
+  {0xa35,0xa36}, {0xa38,0xa39}, {0xa3c,0xa3c}, {0xa3e,0xa42}, 
+  {0xa47,0xa48}, {0xa4b,0xa4d}, {0xa59,0xa5c}, {0xa5e,0xa5e}, 
+  {0xa70,0xa74}, {0xa81,0xa83}, {0xa85,0xa8b}, {0xa8d,0xa8d}, 
+  {0xa8f,0xa91}, {0xa93,0xaa8}, {0xaaa,0xab0}, {0xab2,0xab3}, 
+  {0xab5,0xab9}, {0xabc,0xac5}, {0xac7,0xac9}, {0xacb,0xacd}, 
+  {0xae0,0xae0}, {0xb01,0xb03}, {0xb05,0xb0c}, {0xb0f,0xb10}, 
+  {0xb13,0xb28}, {0xb2a,0xb30}, {0xb32,0xb33}, {0xb36,0xb39}, 
+  {0xb3c,0xb43}, {0xb47,0xb48}, {0xb4b,0xb4d}, {0xb56,0xb57}, 
+  {0xb5c,0xb5d}, {0xb5f,0xb61}, {0xb82,0xb83}, {0xb85,0xb8a}, 
+  {0xb8e,0xb90}, {0xb92,0xb95}, {0xb99,0xb9a}, {0xb9c,0xb9c}, 
+  {0xb9e,0xb9f}, {0xba3,0xba4}, {0xba8,0xbaa}, {0xbae,0xbb5}, 
+  {0xbb7,0xbb9}, {0xbbe,0xbc2}, {0xbc6,0xbc8}, {0xbca,0xbcd}, 
+  {0xbd7,0xbd7}, {0xc01,0xc03}, {0xc05,0xc0c}, {0xc0e,0xc10}, 
+  {0xc12,0xc28}, {0xc2a,0xc33}, {0xc35,0xc39}, {0xc3e,0xc44}, 
+  {0xc46,0xc48}, {0xc4a,0xc4d}, {0xc55,0xc56}, {0xc60,0xc61}, 
+  {0xc82,0xc83}, {0xc85,0xc8c}, {0xc8e,0xc90}, {0xc92,0xca8}, 
+  {0xcaa,0xcb3}, {0xcb5,0xcb9}, {0xcbe,0xcc4}, {0xcc6,0xcc8}, 
+  {0xcca,0xccd}, {0xcd5,0xcd6}, {0xcde,0xcde}, {0xce0,0xce1}, 
+  {0xd02,0xd03}, {0xd05,0xd0c}, {0xd0e,0xd10}, {0xd12,0xd28}, 
+  {0xd2a,0xd39}, {0xd3e,0xd43}, {0xd46,0xd48}, {0xd4a,0xd4d}, 
+  {0xd57,0xd57}, {0xd60,0xd61}, {0xe01,0xe2e}, {0xe30,0xe3a}, 
+  {0xe40,0xe4e}, {0xe81,0xe82}, {0xe84,0xe84}, {0xe87,0xe88}, 
+  {0xe8a,0xe8a}, {0xe8d,0xe8d}, {0xe94,0xe97}, {0xe99,0xe9f}, 
+  {0xea1,0xea3}, {0xea5,0xea5}, {0xea7,0xea7}, {0xeaa,0xeab}, 
+  {0xead,0xeae}, {0xeb0,0xeb9}, {0xebb,0xebd}, {0xec0,0xec4}, 
+  {0xec6,0xec6}, {0xec8,0xecd}, {0xedc,0xedd}, {0xf18,0xf19}, 
+  {0xf35,0xf35}, {0xf37,0xf37}, {0xf39,0xf39}, {0xf40,0xf47}, 
+  {0xf49,0xf69}, {0xf71,0xf84}, {0xf86,0xf87}, {0xf90,0xf95}, 
+  {0xf97,0xf97}, {0xf99,0xfad}, {0xfb1,0xfb7}, {0xfb9,0xfb9}, 
+  {0x10a0,0x10c5}, {0x10d0,0x10f6}, {0x1100,0x1159}, {0x115f,0x11a2}, 
+  {0x11a8,0x11f9}, {0x1e00,0x1e9b}, {0x1ea0,0x1ef9}, {0x1f00,0x1f15}, 
+  {0x1f18,0x1f1d}, {0x1f20,0x1f45}, {0x1f48,0x1f4d}, {0x1f50,0x1f57}, 
+  {0x1f59,0x1f59}, {0x1f5b,0x1f5b}, {0x1f5d,0x1f5d}, {0x1f5f,0x1f7d}, 
+  {0x1f80,0x1fb4}, {0x1fb6,0x1fbc}, {0x1fbe,0x1fbe}, {0x1fc2,0x1fc4}, 
+  {0x1fc6,0x1fcc}, {0x1fd0,0x1fd3}, {0x1fd6,0x1fdb}, {0x1fe0,0x1fec}, 
+  {0x1ff2,0x1ff4}, {0x1ff6,0x1ffc}, {0x207f,0x207f}, {0x20d0,0x20e1}, 
+  {0x2102,0x2102}, {0x2107,0x2107}, {0x210a,0x2113}, {0x2115,0x2115}, 
+  {0x2118,0x211d}, {0x2124,0x2124}, {0x2126,0x2126}, {0x2128,0x2128}, 
+  {0x212a,0x2131}, {0x2133,0x2138}, {0x3005,0x3005}, {0x302a,0x302f}, 
+  {0x3031,0x3035}, {0x3041,0x3094}, {0x3099,0x309e}, {0x30a1,0x30fa}, 
+  {0x30fc,0x30fe}, {0x3105,0x312c}, {0x3131,0x318e}, {0x4e00,0x9fa5}, 
+  {0xac00,0xd7a3}, {0xf900,0xfa2d}, {0xfb00,0xfb06}, {0xfb13,0xfb17}, 
+  {0xfb1e,0xfb28}, {0xfb2a,0xfb36}, {0xfb38,0xfb3c}, {0xfb3e,0xfb3e}, 
+  {0xfb40,0xfb41}, {0xfb43,0xfb44}, {0xfb46,0xfbb1}, {0xfbd3,0xfd3d}, 
+  {0xfd50,0xfd8f}, {0xfd92,0xfdc7}, {0xfdf0,0xfdfb}, {0xfe20,0xfe23}, 
+  {0xfe70,0xfe72}, {0xfe74,0xfe74}, {0xfe76,0xfefc}, {0xff21,0xff3a}, 
+  {0xff41,0xff5a}, {0xff66,0xffbe}, {0xffc2,0xffc7}, {0xffca,0xffcf}, 
+  {0xffd2,0xffd7}, {0xffda,0xffdc}
+};
+
+
+/* the digits correspond to unicode characters which
+ * have Nd in their GENERAL CATEGORY */
+
+#define NUM_DIGIT_INFO 16
+static const unirange digit_info[NUM_DIGIT_INFO] = {
+  {0x30,0x39}, {0x660,0x669}, {0x6f0,0x6f9}, {0x966,0x96f}, 
+  {0x9e6,0x9ef}, {0xa66,0xa6f}, {0xae6,0xaef}, {0xb66,0xb6f}, 
+  {0xbe7,0xbef}, {0xc66,0xc6f}, {0xce6,0xcef}, {0xd66,0xd6f}, 
+  {0xe50,0xe59}, {0xed0,0xed9}, {0xf20,0xf29}, {0xff10,0xff19}
+};
+
+
+/* the spaces correspond to unicode characters which
+ * have Zs, Zl, or Zp in their GENERAL CATEGORY */
+
+#define NUM_SPACE_INFO 5
+static const unirange space_info[NUM_SPACE_INFO] = {
+  {0x20,0x20}, {0xa0,0xa0}, {0x2000,0x200b}, {0x2028,0x2029}, 
+  {0x3000,0x3000}
+};
+
+
+
+/* parse_utf8_char parses the next utf-8 character, placing its
+ * unicode equivalent in *value. The length of the utf-8 character
+ * is returned */
+int parse_utf8_char(const unsigned char *here,
+		    const unsigned char *end,
+		    unsigned short *value) {
+  unsigned short c1;
+  unsigned short c2;
+  unsigned short c3;
+  
+  *value = 0; /* will be the value for illegal characters */
+  
+  if (here <= end) {
+    c1 = (unsigned short)(*here);
+    
+    if (c1 <= 0x7f) {
+      /* found a one-byte character */
+      *value = c1;
+      return 1;
+      
+    } else if (c1 >= 0xc0 && c1 <= 0xdf && here+1 <= end &&
+	       (c2=(unsigned short)(*(here+1))) >= 0x80) {
+      /* found a two-byte character */
+      *value = ((c1 & 0x1f) << 6) + (c2 & 0x3f);
+      return 2;
+      
+    } else if (c1 >= 0xe0 && c1 <= 0xef && here+2 <= end &&
+	       (c2=(unsigned int)(*(here+1))) >= 0x80 &&
+	       (c3=(unsigned int)(*(here+2))) >= 0x80) {
+      /* found a three-byte character */
+      *value = ((c1 & 0xf) << 12) + ((c2 & 0x3f) << 6) +
+	(c3 & 0x3f);
+      return 3;
+      
+    } else {
+      /* error in encoding, return the length as 1 */
+      return 1;
+    }
+  }
+
+  /* end of string */
+  return 0;
+}
+
+
+/* output_utf8_char encodes a unicode character as a UTF-8 character.
+ * The length of the encoding is returned. If the string was not
+ * long enough to encode the character 0 is returned. */
+int output_utf8_char (unsigned short value,
+		      unsigned char *here,
+		      unsigned char *end) {
+  int len = (int)(end - here + 1); /* end is the last character */
+  if (value < 0x80) {
+    /* will be encoded in one byte */
+    if (len >= 1) {
+      *here = (unsigned char)value;
+      return 1;
+    }
+
+  } else if (value < 0x800) {
+    /* will be encoded in two bytes */
+    if (len >= 2) {
+      *here++ = 0xc0 | (unsigned char)((value >> 6) & 0x1f);
+      *here = 0x80 | (unsigned char)(value & 0x3f);
+
+      return 2;
+    }
+
+  } else {
+    /* will be encoded in three bytes */
+    if (len >= 3) {
+      *here++ = 0xe0 | (unsigned char)((value >> 12) & 0xf);
+      *here++ = 0x80 | (unsigned char)((value >> 6) & 0x3f);
+      *here = 0x80 | (unsigned char)(value & 0x3f);
+      return 3;
+    }
+  }
+
+  return 0;
+}
+
+
+static int lookup_decompose_table (unsigned short value) {
+  int first = 0;
+  int last = NUM_DECOMPOSE_INFO;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < decompose_info[here].ch) {
+      last = here;
+    } else if (value > decompose_info[here].ch) {
+      first = here+1;
+    } else {
+      return here;
+    }
+  }
+
+  return -1;
+}
+
+/* decompose_str will decompose a unicode string into its canonical
+ * equivalents. NULL is returned if the input array was not 
+ * large enough to contain the fully decomposed string (the array
+ * will be in a correct, but partially decomposed state). The input 
+ * must be null-terminated. */
+unsigned short *decompose_str (unsigned short *input,
+			       int max_output_len) {
+  int curpos = 0;
+  int curlen = unicode_strlen (input);
+  int tablepos = 0;
+  int leninc;
+  int i;
+
+  while (input[curpos] != 0) {
+    tablepos = lookup_decompose_table (input[curpos]);
+    if (tablepos >= 0) {
+      /* found a decomposition */
+      leninc = unicode_strnlen (decompose_info[tablepos].str, 3)-1;
+      if (curlen+leninc < max_output_len) {
+	/* enough space for this decomposition */
+
+	if (leninc > 1) {
+	  /* we have to shift the array along */
+	  for (i=curlen-1; i>=curpos; --i) {
+	    input[i+leninc] = input[i];
+	  }
+	  input[curlen+leninc] = 0;
+	  curlen += leninc;
+	}
+
+	/* decompose the character */
+	for (i=0; i<=leninc; ++i) {
+	  input[curpos+i] = decompose_info[tablepos].str[i];
+	}
+
+	/* note: curpos is not incremented because the decomposed */
+	/*       characters might need decomposing */
+
+      } else {
+	/* no space left in string */
+	return NULL;
+      }
+
+    } else {
+      /* the character cannot be decomposed */
+      ++curpos;
+    }
+  }
+
+  return input;
+}
+
+
+
+/* unicode_cat_data is a combination of the letter, digit, and
+ * space information in a form that is quick to look up.
+ * The information about each byte is stored in two bits
+ *
+ * 00 - neither letter, digit or space
+ * 01 - letter
+ * 10 - space
+ * 11 - digit
+ *
+ * You can test for letter | space by looking at the right
+ * column
+ */
+/*unsigned long *unicode_cat_data;*/
+
+void create_unicat_data () {
+  int i=0;
+  int min_start=0;
+  int min_end=0;
+  register unsigned long min_value=0; /* filling the whole byte */
+  
+  const unirange *letter_here = letter_info;
+  const unirange *letter_end = letter_info+NUM_LETTER_INFO;
+  const unirange *digit_here = digit_info;
+  const unirange *digit_end = digit_info+NUM_DIGIT_INFO;
+  const unirange *space_here = space_info;
+  const unirange *space_end = space_info+NUM_SPACE_INFO;
+
+  if (unicode_cat_data != NULL) return;
+  unicode_cat_data = (unsigned long *) malloc (0x10000/4);
+  if (unicode_cat_data == NULL) return;
+  
+  while (i <= 0xffff) {
+    /* decide what to fill with next */
+    min_start = i;
+    min_end = 0xffff;
+    min_value = 0; /* 00 */
+    
+    while (letter_here < letter_end && letter_here->last < i) ++letter_here;
+    if (letter_here < letter_end && letter_here->last <= min_end) {
+      min_start = letter_here->first;
+      min_end = letter_here->last;
+      min_value = 0x55555555; /* 01 */
+    }
+    
+    while (digit_here < digit_end && digit_here->last < i) ++digit_here;
+    if (digit_here < digit_end && digit_here->last <= min_end) {
+      min_start = digit_here->first;
+      min_end = digit_here->last;
+      min_value = 0xffffffff; /* 11 */
+    }
+    
+    while (space_here < space_end && space_here->last < i) ++space_here;
+    if (space_here < space_end && space_here->last <= min_end) {
+      min_start = space_here->first;
+      min_end = space_here->last;
+      min_value = 0xaaaaaaaa; /* 10 */
+    }
+
+    if (min_start < i) min_start = i;
+    else if (min_start > i) {
+      min_end = min_start-1;
+      min_start = i;
+      min_value = 0; /* 00 */
+    }
+
+    /* fill the entries from min_start to min_end with min_value */
+    while (i <= min_end) {
+      /* special version for common case */
+      if (i % 16 == 0) {
+	unicode_cat_data[i/16] = min_value; /* doesn't matter if too long */
+	i += 16;
+	if (i > min_end) {
+	  i = min_end+1;
+	  break;
+	}
+	
+      } else {
+	register unsigned long mask = 3 << ((i % 16) * 2);
+	unicode_cat_data[i/16] = (unicode_cat_data[i/16] & (~mask)) |
+				  (min_value & mask);
+	++i;
+      }
+    }
+  }
+}
+
+/* does a binary search on a range table */
+static int in_unirange (const unirange *info, int num_info,
+			unsigned short value) {
+  int first = 0;
+  int last = num_info;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < info[here].first) {
+      last = here;
+    } else if (value > info[here].last) {
+      first = here+1;
+    } else {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+
+
+/* tests to see whether 'value' is a valid Unicode letter */
+int is_unicode_letter (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(letter_info, NUM_LETTER_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x1);
+}
+
+/* tests to see whether 'value' is a valid Unicode digit */
+int is_unicode_digit (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(digit_info, NUM_DIGIT_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x3);
+}
+
+/* tests to see whether 'value' is a valid Unicode letter or 
+ * digit */
+int is_unicode_letdig (unsigned short value) {
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return (in_unirange(letter_info, NUM_LETTER_INFO, value) ||
+	    in_unirange(digit_info, NUM_DIGIT_INFO, value));
+    
+  }
+
+  return ((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x1);
+}
+
+/* tests to see whether 'value' is a valid space
+ * The test includes both "C" spaces and "Unicode" spaces, i.e. 
+ * form-feed, newline, carriage return, horizontal tab,
+ * vertical tab, and the Zs, Zl, and Zp Unicode categorizations */
+int is_unicode_space (unsigned short value) {
+  if (value < 0x80) return isspace (value);
+  if (unicode_cat_data == NULL) create_unicat_data ();
+  if (unicode_cat_data == NULL) {
+    /* use old method */
+    return in_unirange(space_info, NUM_SPACE_INFO, value);
+  }
+
+  return (((unicode_cat_data[value/16] >> ((value%16)*2)) & 0x3) == 0x2);
+}
+
+/* returns the length of the unicode string */
+int unicode_strlen (const unsigned short *str) {
+  int len = 0;
+
+  /* keep going till you find the null-terminator */
+  while (*str != 0) {
+    ++len;
+    ++str;
+  }
+
+  return len;
+}
+
+/* returns the length of the unicode string, up to a maximum */
+int unicode_strnlen (const unsigned short *str, int max_length) {
+  int len = 0;
+
+  /* keep going till you find the null-terminator */
+  while (*str != 0 && len < max_length ) {
+    ++len;
+    ++str;
+  }
+
+  return len;
+}
+
+
+/* Does a binary search on a relate table, returns -1 if it is not
+ * found. */
+static int search_unirelate (const unirelate *info, int num_info,
+			     unsigned short value) {
+  int first = 0;
+  int last = num_info;
+  int here;
+
+  while (first < last) {
+    here = (last-first)/2 + first;
+    if (value < info[here].ch1) {
+      last = here;
+    } else if (value > info[here].ch1) {
+      first = here+1;
+    } else {
+      return here;
+    }
+  }
+
+  return -1;
+}
+
+
+/* returns the upper-case equivalent of value */
+unsigned short unicode_toupper (unsigned short value) {
+  int related = search_unirelate (toupper_info, NUM_TOUPPER_INFO, value);
+  if (related >= 0) {
+    value = toupper_info[related].ch2;
+  }
+  return value;
+}
+
+/* returns the lower-case equivalent of value */
+unsigned short unicode_tolower (unsigned short value) {
+  int related = search_unirelate (tolower_info, NUM_TOLOWER_INFO, value);
+  if (related >= 0) {
+    value = tolower_info[related].ch2;
+  }
+  return value;
+}
+
+/* returns the simplified Chinese character equivalent of 
+ * another Chinese character */
+unsigned short unicode_tosimplified (unsigned short value) {
+  int related = search_unirelate (tosimplified_info, NUM_TOSIMPLIFIED_INFO, value);
+  if (related >= 0) {
+    value = tosimplified_info[related].ch2;
+  }
+  return value;
+}
+
+
+/* converts a utf-8 word (string with length stored in the first byte
+ * to a Unicode array. To handle all situations the output buffer should
+ * be 256 unsigned shorts long. The output will also have the length as
+ * the first entry. */
+unsigned short *utf8_word_to_unicode (const unsigned char *input,
+				      unsigned short *output,
+				      int max_output_length) {
+  int inlen = *input;
+  const unsigned char *inhere = input+1;
+  const unsigned char *inend = &inhere[inlen-1];
+  unsigned short c;
+  int clen;
+  
+  int outlen = 0;
+  unsigned short *outhere = output+1;
+  
+  while (inhere <= inend && inlen < max_output_length-1) {
+    /* decode the character */
+    clen = parse_utf8_char (inhere, inend, &c);
+    inhere += clen;
+
+    if (clen > 0) {
+      /* store the character */
+      *outhere = c;
+      ++outhere;
+      ++outlen;
+    }
+  }
+
+  output[0] = outlen;
+  return output;
+}
+
+
+/* converts a unicode word buffer (with the length stored in the
+ * entry) to a utf8 encoded word output (with the length stored in
+ * the first byte. Only 255 bytes (not characters) can be stored 
+ * in the output. */
+unsigned char *unicode_to_utf8_word (const unsigned short *input,
+				     unsigned char *output,
+				     int max_output_length) {
+  int inlen = *input;
+  const unsigned short *word = input + 1;
+  int in_i = 0;
+  int clen;
+
+  int outlen = 0;
+  unsigned char *outhere = output+1;
+  unsigned char *outend = output+max_output_length;
+
+  while (in_i < inlen) {
+    if ((clen=output_utf8_char(word[in_i], outhere, outend)) == 0) {
+      /* ran out of space to encode the character */
+      break;
+    }
+
+    outhere += clen;
+    outlen += clen;
+    ++in_i;
+  }
+
+  output[0] = outlen;
+
+  return output;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/unitool.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/unitool.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/unitool.h	(revision 10506)
@@ -0,0 +1,88 @@
+#ifndef UNITOOL_H
+#define UNITOOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* This module is based on Unicode 2.1 */
+
+
+/* parse_utf8_char parses the next utf-8 character, placing its
+ * unicode equivalent in *value. The length of the utf-8 character
+ * is returned. end is the address of the last character. */
+int parse_utf8_char (const unsigned char *here,
+		     const unsigned char *end,
+		     unsigned short *value);
+
+/* output_utf8_char encodes a unicode character as a UTF-8 character.
+ * The length of the encoding is returned. If the string was not
+ * long enough to encode the character 0 is returned. end is the
+ * address of the last character */
+int output_utf8_char (unsigned short value,
+		      unsigned char *here,
+		      unsigned char *end);
+
+/* decompose_str will decompose a unicode string into its canonical
+ * equivalents. NULL is returned if the input array was not 
+ * large enough to contain the fully decomposed string (the array
+ * will be in a correct, but partially decomposed state). The input 
+ * must be null-terminated. */
+unsigned short *decompose_str (unsigned short *input,
+			       int max_output_len);
+
+/* tests to see whether 'value' is a valid Unicode letter */
+int is_unicode_letter (unsigned short value);
+
+/* tests to see whether 'value' is a valid Unicode digit */
+int is_unicode_digit (unsigned short value);
+
+/* tests to see whether 'value' is a valid Unicode letter or 
+ * digit */
+int is_unicode_letdig (unsigned short value);
+
+/* tests to see whether 'value' is a valid space
+ * The test includes both "C" spaces and "Unicode" spaces, i.e. 
+ * form-feed, newline, carriage return, horizontal tab,
+ * vertical tab, and the Zs, Zl, and Zp Unicode categorizations */
+int is_unicode_space (unsigned short value);
+
+/* returns the length of the unicode string */
+int unicode_strlen (const unsigned short *str);
+
+/* returns the length of the unicode string, up to a maximum */
+int unicode_strnlen (const unsigned short *str, int max_length);
+
+/* returns the upper-case equivalent of value */
+unsigned short unicode_toupper (unsigned short value);
+
+/* returns the lower-case equivalent of value */
+unsigned short unicode_tolower (unsigned short value);
+
+/* returns the simplified Chinese character equivalent of 
+ * another Chinese character */
+unsigned short unicode_tosimplified (unsigned short value);
+
+
+/* converts a utf-8 word (string with length stored in the first byte
+ * to a Unicode array. To handle all situations the output buffer should
+ * be 256 unsigned shorts long. The output will also have the length as
+ * the first entry. */
+unsigned short *utf8_word_to_unicode (const unsigned char *input,
+				      unsigned short *output,
+				      int max_output_length);
+
+/* converts a unicode word buffer (with the length stored in the
+ * entry) to a utf8 encoded word output (with the length stored in
+ * the first byte. Only 255 bytes (not characters) can be stored 
+ * in the output. */
+unsigned char *unicode_to_utf8_word (const unsigned short *input,
+				     unsigned char *output,
+				     int max_output_length);
+
+#ifdef __cplusplus
+	   }
+#endif
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/win32in.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/win32in.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/win32in.c	(revision 10506)
@@ -0,0 +1,85 @@
+/* This module provides an equivalent of <netinet/in.h> on  */
+/* unix systems. */
+#include "win32in.h"
+
+unsigned long htonl(unsigned long x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) |
+		((x << 8) & 0x00FF0000) | ((x << 24) & 0xFF000000);
+#endif
+
+	return x;
+}
+
+mg_ullong ntohll(mg_ullong x)
+{
+#if defined (LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = 
+	  ((x >> 56) & 0x00000000000000FF) | ((x >> 40) & 0x000000000000FF00) |
+	  ((x >> 24) & 0x0000000000FF0000) | ((x >> 8)  & 0x00000000FF000000) |
+	  ((x << 8)  & 0x000000FF00000000) | ((x << 24) & 0x0000FF0000000000) |
+		((x << 40) & 0x00FF000000000000) | ((x << 56) & 0xFF00000000000000);
+#endif
+  return x;
+}
+
+unsigned long ntohl(unsigned long x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 24) & 0x000000FF) | ((x >> 8) & 0x0000FF00) |
+		((x << 8) & 0x00FF0000) | ((x << 24) & 0xFF000000);
+#endif
+	return x;
+}
+
+unsigned short htons(unsigned short x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 8) & 0x00FF) | ((x << 8) & 0xFF00);
+#endif
+	return x;
+}
+
+unsigned short ntohs(unsigned short x) {
+#if defined (LITTLE_ENDIAN) || defined (_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN)
+	x = ((x >> 8) & 0x00FF) | ((x << 8) & 0xFF00);
+#endif
+	return x;
+}
+
+/* just to test stuff
+#include <stdio.h>
+
+main () {
+	long x;
+	short sx;
+
+	x = 0x000000FF;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0x0000FF00;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0x00FF0000;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n",(int)x);
+
+	x = 0xFF000000;
+	printf ("before %i, ",(int)x);
+	x = htonl (x);
+	printf ("after %i\n\n",(int)x);
+
+	sx = 0x00FF;
+	printf ("before %i, ",(int)sx);
+	sx = htons (sx);
+	printf ("after %i\n",(int)sx);
+
+	sx = 0xFF00;
+	printf ("before %i, ",(int)sx);
+	sx = htons (sx);
+	printf ("after %i\n",(int)sx);
+}
+*/
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/win32in.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/win32in.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/win32in.h	(revision 10506)
@@ -0,0 +1,20 @@
+/* This module provides an equivalent of <netinet/in.h> on  */
+/* unix systems. */
+#ifdef __WIN32__
+#define _LITTLE_ENDIAN
+#endif
+
+#include "longlong.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned long htonl(unsigned long x);
+unsigned long ntohl(unsigned long x);
+mg_ullong ntohll(mg_ullong x);
+unsigned short htons(unsigned short x);
+unsigned short ntohs(unsigned short x);
+
+#ifdef __cplusplus
+}
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/xmalloc.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/xmalloc.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/lib/xmalloc.c	(revision 10506)
@@ -0,0 +1,111 @@
+/* xmalloc.c -- malloc with out of memory checking
+   Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# ifdef __WIN32__  /* [RPAP - Feb 97: WIN32 Port] */
+#  include <win32cfg.h>
+# else
+#  include <sysfuncs.h>
+# endif
+#endif
+
+#if __STDC__
+#define VOID void
+#else
+#define VOID char
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS
+#include <stdlib.h>
+#else
+VOID *malloc ();
+VOID *realloc ();
+void free ();
+#endif
+
+/* This is for other GNU distributions with internationalized messages.
+   The GNU C Library itself does not yet support such messages.  */
+#if HAVE_LIBINTL_H
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* Exit value when the requested amount of memory is not available.
+   The caller may set it to some other value.  */
+int xmalloc_exit_failure = EXIT_FAILURE;
+
+#if defined(__WIN32__)
+void error (int, int, const char *, ...);
+#else
+#if __STDC__ && (HAVE_VPRINTF || HAVE_DOPRNT)
+void error (int, int, const char *, ...);
+#else
+void error (int, int, char *, char *, char *, char *, char *, char *, char *, char *, char *);
+#endif
+#endif
+
+static VOID *
+fixup_null_alloc (n)
+     size_t n;
+{
+  VOID *p;
+
+  p = 0;
+  if (n == 0)
+    p = malloc ((size_t) 1);
+  if (p == 0)
+    error (xmalloc_exit_failure, 0, gettext ("Memory exhausted"));
+  return p;
+}
+
+/* Allocate N bytes of memory dynamically, with error checking.  */
+
+VOID *
+xmalloc (n)
+     size_t n;
+{
+  VOID *p;
+
+  p = malloc (n);
+  if (p == 0)
+    p = fixup_null_alloc (n);
+  return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+   with error checking.
+   If P is NULL, run xmalloc.  */
+
+VOID *
+xrealloc (p, n)
+     VOID *p;
+     size_t n;
+{
+  if (p == 0)
+    return xmalloc (n);
+  p = realloc (p, n);
+  if (p == 0)
+    p = fixup_null_alloc (n);
+  return p;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/mkinstalldirs
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/mkinstalldirs	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/mkinstalldirs	(revision 10506)
@@ -0,0 +1,32 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Last modified: 1994-03-25
+# Public domain
+
+errstatus=0
+
+for file in ${1+"$@"} ; do 
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d in ${1+"$@"} ; do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp" 1>&2
+        mkdir "$pathcomp" || errstatus=$?
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/stamp-h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/stamp-h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/stamp-h	(revision 10506)
@@ -0,0 +1,1 @@
+timestamp
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/stamp-h.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/stamp-h.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/stamp-h.in	(revision 10506)
@@ -0,0 +1,1 @@
+timestamp
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FIvfLevelInfo.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FIvfLevelInfo.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FIvfLevelInfo.cpp	(revision 10506)
@@ -0,0 +1,129 @@
+/**************************************************************************
+ *
+ * FIvfLevelInfo.cpp -- File functions for document levels
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "FIvfLevelInfo.h"
+
+
+IvfLevelInfo::IvfLevelInfo () {
+  Clear();
+}
+
+void IvfLevelInfo::Clear () {
+  levelTag.erase (levelTag.begin(), levelTag.end());
+  numEntries = 0;
+  approxWeightsDiskPtr = 0;
+  exactWeightsDiskPtr = 0;
+  workInLevel = false;
+}
+
+bool IvfLevelInfo::Read (FILE *f) {
+  workInLevel = false;
+  return (ReadUCArray (f, levelTag) &&
+	  ReadUL (f, numEntries) &&
+	  ReadUL (f, approxWeightsDiskPtr) &&
+	  ReadUL (f, exactWeightsDiskPtr));
+}
+
+bool IvfLevelInfo::Write (FILE *f) const {
+  return (WriteUCArray (f, levelTag) &&
+	  WriteUL (f, numEntries) &&
+	  WriteUL (f, approxWeightsDiskPtr) &&
+	  WriteUL (f, exactWeightsDiskPtr));
+}
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const IvfLevelInfo &l) {
+  s << "  Tag: \"" << l.levelTag << "\"\n"
+    << "  numEntries: " << l.numEntries << "\n"
+    << "  approxWeightsDiskPtr: " << l.approxWeightsDiskPtr << "\n"
+    << "  exactWeightsDiskPtr: " << l.exactWeightsDiskPtr << "\n"
+    << "  workInLevel: " << ((l.workInLevel) ? "true" : "false") << "\n\n";
+  
+  return s;
+}
+
+
+
+FIvfLevel::FIvfLevel () {
+  Clear ();
+}
+
+void FIvfLevel::Clear () {
+  docTag.erase (docTag.begin(), docTag.end());
+  indexLevel.erase (indexLevel.begin(), indexLevel.end());
+  levelInfo.erase (levelInfo.begin(), levelInfo.end());
+}
+
+bool FIvfLevel::Read (FILE *f) {
+  if (!ReadUCArray (f, docTag) ||
+      !ReadUCArray (f, indexLevel))
+    return false;
+  
+  // read in the array size
+  unsigned long arrSize = 0;
+  if (!ReadVarLenUL (f, arrSize)) return false;
+  
+  IvfLevelInfo thisLevel;
+  while (arrSize > 0) {
+    // read and insert the next level information
+    if (!thisLevel.Read (f)) return false;
+    levelInfo[thisLevel.levelTag] = thisLevel;
+    
+    --arrSize;
+  }
+
+  return true;
+}
+
+bool FIvfLevel::Write (FILE *f) const {
+  if (!WriteUCArray (f, docTag) ||
+      !WriteUCArray (f, indexLevel))
+    return false;
+  
+  // write out the array size
+  if (!WriteVarLenUL (f, levelInfo.size())) return false;
+
+  // write out each level info
+  IvfLevelInfoMap::const_iterator here = levelInfo.begin();
+  IvfLevelInfoMap::const_iterator end = levelInfo.end();
+  while (here != end) {
+    if (!(*here).second.Write (f)) return false;
+    
+    ++here;
+  }
+
+  return true;
+}
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const FIvfLevel &l) {
+  s << "docTag: \"" << l.docTag << "\"\n"
+    << "indexLevel: \"" << l.indexLevel << "\"\n";
+  
+  IvfLevelInfoMap::const_iterator here = l.levelInfo.begin ();
+  IvfLevelInfoMap::const_iterator end = l.levelInfo.end ();
+  while (here != end) {
+    s << (*here).second;
+    ++here;
+  }
+  
+  return s;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FIvfLevelInfo.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FIvfLevelInfo.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FIvfLevelInfo.h	(revision 10506)
@@ -0,0 +1,77 @@
+/**************************************************************************
+ *
+ * FIvfLevelInfo.h -- File functions for document levels
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef FIVFLEVELINFO_H
+#define FIVFLEVELINFO_H
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+#include <stdio.h>
+#include "UCArray.h"
+
+
+class IvfLevelInfo {
+public:
+  UCArray levelTag;
+  unsigned long numEntries; // N for level
+  unsigned long approxWeightsDiskPtr;
+  unsigned long exactWeightsDiskPtr;
+  bool workInLevel;  // this is just a working variable,
+                     // it is not saved or read from the file
+  
+  IvfLevelInfo ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const IvfLevelInfo &l);
+
+
+typedef map<UCArray, IvfLevelInfo, LTUCArray> IvfLevelInfoMap;
+
+
+class FIvfLevel {
+public:
+  UCArray docTag;
+  UCArray indexLevel;    // empty for word level index
+  IvfLevelInfoMap levelInfo;
+  
+  FIvfLevel ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const FIvfLevel &l);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FText.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FText.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FText.cpp	(revision 10506)
@@ -0,0 +1,249 @@
+/**************************************************************************
+ *
+ * FText.cpp -- File structures for text compression
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "FText.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+BitAddr::BitAddr () {
+  Clear ();  
+}
+
+void BitAddr::Clear () {
+  byte = 0;
+  bit = 0;
+}
+
+bool BitAddr::Read (FILE *f) {
+  return (ReadUL (f, byte) && ReadUC (f, bit));
+}
+
+bool BitAddr::Write (FILE *f) const {
+  return (WriteUL (f, byte) && WriteUC (f, bit));
+}
+
+#define BITADDRLEN (sizeof(unsigned long) + sizeof(unsigned char))
+
+  
+TextLevelInfo::TextLevelInfo () {
+  Clear();
+}
+
+void TextLevelInfo::Clear () {
+  levelTag.erase (levelTag.begin(), levelTag.end());
+  textIdxPtr = 0;
+  numEntries = 0;
+}
+
+bool TextLevelInfo::Read (FILE *f) {
+  return (ReadUCArray (f, levelTag) &&
+	  ReadUL (f, textIdxPtr) &&
+	  ReadUL (f, numEntries));
+}
+
+bool TextLevelInfo::Write (FILE *f) const {
+  return (WriteUCArray (f, levelTag) &&
+	  WriteUL (f, textIdxPtr) &&
+	  WriteUL (f, numEntries));
+}
+
+ostream &operator<<(ostream &s, const TextLevelInfo &l) {
+  s << "  Tag: \"" << l.levelTag << "\"\n"
+    << "  textIdxPtr: " << l.textIdxPtr << "\n"
+    << "  numEntries: " << l.numEntries << "\n\n";
+  
+  return s;
+}
+
+
+FTextLevel::FTextLevel () {
+  Clear();
+}
+
+void FTextLevel::Clear () {
+  levelInfo.erase (levelInfo.begin(), levelInfo.end());
+}
+
+bool FTextLevel::Read (FILE *f) {
+  // read in the array size
+  unsigned long arrSize = 0;
+  if (!ReadVarLenUL (f, arrSize)) return false;
+
+  TextLevelInfo thisLevel;
+  while (arrSize > 0) {
+    // read and insert the next level information
+    if (!thisLevel.Read (f)) return false;
+    levelInfo[thisLevel.levelTag] = thisLevel;
+    
+    --arrSize;
+  }
+
+  return true;
+}
+
+bool FTextLevel::Write (FILE *f) const {
+  // write out the array size
+  if (!WriteVarLenUL (f, levelInfo.size())) return false;
+
+  // write out each level info
+  TextLevelInfoMap::const_iterator here = levelInfo.begin();
+  TextLevelInfoMap::const_iterator end = levelInfo.end();
+  while (here != end) {
+    if (!(*here).second.Write (f)) return false;
+    
+    ++here;
+  }
+
+  return true;
+}
+
+ostream &operator<<(ostream &s, const FTextLevel &l) {
+  TextLevelInfoMap::const_iterator here = l.levelInfo.begin ();
+  TextLevelInfoMap::const_iterator end = l.levelInfo.end ();
+  while (here != end) {
+    s << (*here).second;
+    ++here;
+  }
+  
+  return s;
+}
+
+
+TextIdx::TextIdx () {
+  Clear ();
+}
+
+void TextIdx::Clear () {
+  start.Clear();
+  end.Clear();
+  which = 0;
+}
+
+#define TEXTIDXLEN (BITADDRLEN*2 + sizeof(char))
+
+bool TextIdx::Read (FILE *f, const TextLevelInfo &levelInfo,
+		    unsigned long docNum) {
+  if (!SeekTextIdx (f, levelInfo, docNum)) return false;
+  return Read (f);
+}
+
+bool TextIdx::Read (FILE *f) {
+  return (start.Read (f) && end.Read (f) && ReadUC (f, which));
+}
+
+bool TextIdx::Write (FILE *f) const {
+  return (start.Write (f) && end.Write (f) && WriteUC (f, which));
+}
+
+ostream &operator<<(ostream &s, const TextIdx &t) {
+  s << "start byte: " << t.start.byte << "\n";
+  s << "start bit:  " << (int)t.start.bit << "\n";
+  s << "end byte:   " << t.end.byte << "\n";
+  s << "end bit:    " << (int)t.end.bit << "\n";
+  s << "which:      " << (int)t.which << "\n\n";
+  
+  return s;
+}
+
+
+bool SeekTextIdx (FILE *f, const TextLevelInfo &levelInfo,
+		  unsigned long docNum) {
+  if (docNum == 0 || docNum > levelInfo.numEntries) return false;
+  
+  unsigned long seekPos = levelInfo.textIdxPtr + (docNum-1) * TEXTIDXLEN;
+  if (fseek (f, seekPos, SEEK_SET) != 0) return false;
+  
+  return true;
+}
+
+
+bool ReadTextIdxArray (FILE *f, TextIdxArray &a, unsigned long arrSize) {
+  // clear the array
+  a.erase (a.begin(), a.end());
+
+  // read in each element
+  TextIdx idx;
+  while (arrSize > 0) {
+    if (!idx.Read(f)) return false;
+    a.push_back (idx);
+    --arrSize;
+  }
+
+  return true;
+}
+
+bool WriteTextIdxArray (FILE *f, const TextIdxArray &a) {
+  TextIdxArray::const_iterator here = a.begin();
+  TextIdxArray::const_iterator end = a.end();
+  while (here != end) {
+    if (!(*here).Write(f)) return false;
+    ++here;
+  }
+  
+  return true;
+}
+
+
+CompressTextInfo::CompressTextInfo () {
+  Clear();
+}
+
+void CompressTextInfo::Clear () {
+  ResetStart();
+  docPtrs.erase (docPtrs.begin(), docPtrs.end());
+}
+
+void CompressTextInfo::ResetStart () {
+  inDoc = false;
+  start.Clear();
+  which = 0;
+}
+  
+void CompressTextInfo::SetStart (unsigned long startPos,
+				 unsigned char startBit,
+				 unsigned char startWhich) {
+  // place an imaginary end tag if needed
+  // note: the document tag always needs a closing tag
+  if (inDoc) SetEnd (startPos, startBit);
+
+  // remember start of level
+  inDoc = true;
+  start.byte = startPos;
+  start.bit = startBit;
+  which = startWhich;
+}
+
+void CompressTextInfo::SetEnd (unsigned long endPos,
+			       unsigned char endBit) {
+  if (inDoc) {
+    // add completed entry to list of ptrs
+    TextIdx textIdx;
+    textIdx.start = start;
+    textIdx.end.byte = endPos;
+    textIdx.end.bit = endBit;
+    textIdx.which = which;
+    docPtrs.push_back (textIdx);
+    
+    // reset this entry
+    ResetStart();
+  }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FText.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FText.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FText.h	(revision 10506)
@@ -0,0 +1,150 @@
+/**************************************************************************
+ *
+ * FText.h -- File structures for text compression
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef FTEXT_H
+#define FTEXT_H
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+#include <stdio.h>
+#include "UCArray.h"
+
+
+// holds a bit address
+class BitAddr {
+public:
+  unsigned long byte;
+  unsigned char bit;
+
+  BitAddr ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+
+class TextLevelInfo {
+public:
+  UCArray levelTag;
+  unsigned long textIdxPtr;
+  unsigned long numEntries;
+
+  TextLevelInfo ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const TextLevelInfo &l);
+
+
+typedef map<UCArray, TextLevelInfo, LTUCArray> TextLevelInfoMap;
+
+
+class FTextLevel {
+public:
+  TextLevelInfoMap levelInfo;
+  
+  FTextLevel ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const FTextLevel &l);
+
+
+// the text.idx file points into the compressed text
+class TextIdx {
+public:
+  BitAddr start;       // the first bit of the compressed text
+  BitAddr end;         // the first bit past the end of the text
+  unsigned char which; // 0 = non-word, 1 = word
+  
+  TextIdx ();
+  void Clear ();
+
+  // does a seek and reads the appropriate record
+  bool Read (FILE *f, const TextLevelInfo &levelInfo,
+	     unsigned long docNum);
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// stream output for debugging purposes
+ostream &operator<<(ostream &s, const TextIdx &t);
+
+
+// note: document numbers start at 1
+
+bool SeekTextIdx (FILE *f, const TextLevelInfo &levelInfo,
+		  unsigned long docNum);
+
+
+// used to store the pointers while compressing the text
+typedef vector<TextIdx> TextIdxArray;
+
+bool ReadTextIdxArray (FILE *f, TextIdxArray &a, unsigned long arrSize);
+bool WriteTextIdxArray (FILE *f, const TextIdxArray &a);
+
+
+// used to store information about a level while compressing the text
+class CompressTextInfo {
+public:
+  bool inDoc;
+  BitAddr start;
+  unsigned char which;
+  TextIdxArray docPtrs;
+
+  CompressTextInfo ();
+  void Clear ();
+
+  // clears inDoc, start, and which (not the docPtrs)
+  void ResetStart ();
+  
+  // set the start of a level (closing off the last opening
+  // tag if needed)
+  void SetStart (unsigned long startPos,
+		 unsigned char startBit,
+		 unsigned char startWhich);
+
+  // if in a document, it will set the end, add the document to the
+  // list of document ptrs, and then call ResetStart
+  void SetEnd (unsigned long endPos,
+	       unsigned char endBit);
+};
+
+typedef map<UCArray, CompressTextInfo, LTUCArray> CompressTextInfoMap;
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FileBuf.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FileBuf.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FileBuf.cpp	(revision 10506)
@@ -0,0 +1,50 @@
+/**************************************************************************
+ *
+ * FileBuf.cpp -- File buffer
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "FileBuf.h"
+#include "sysfuncs.h"
+
+#ifdef __WIN32__
+# include <io.h>
+# define read _read
+#endif
+
+bool FileBuf::NextBuf () {
+  if (fd < 0) return false;
+  int numbytes = read (fd, buf, FILEBUFSIZE);
+  if (numbytes < 0) numbytes = 0;
+  
+  here = buf;
+  end = here + numbytes;
+
+  return (numbytes > 0);
+}
+
+FileBuf::FileBuf () {
+  here = end = buf;
+  fd = -1;
+}
+
+void FileBuf::SetFD (int _fd) {
+  here = end = buf;
+  fd = _fd;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FileBuf.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FileBuf.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FileBuf.h	(revision 10506)
@@ -0,0 +1,73 @@
+/**************************************************************************
+ *
+ * FileBuf.h -- File buffer
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef FILEBUF_H
+#define FILEBUF_H
+
+#define FILEBUFSIZE 65536
+
+// some elderly windows compilers need to include <vector> (or something
+// similar) here so that they know what a "bool" is
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#else
+#  include <vector>
+#endif
+
+
+class FileBuf {
+protected:
+  unsigned char buf[FILEBUFSIZE];
+  unsigned char *here;
+  unsigned char *end;
+
+  int fd;
+
+  // gets a new buffer if need be, returns true if
+  // more could be got. if true is returned the caller
+  // can assume that here != end
+  bool NextBuf ();
+  
+public:
+  FileBuf ();
+
+  void SetFD (int _fd);
+
+  inline bool Get (unsigned char &c) {
+    if (here != end || NextBuf()) { c = *here++; return true; }
+    return false;
+  }
+  
+  inline bool Peek (unsigned char &c) {
+    if (here != end || NextBuf()) { c = *here; return true; }
+    return false;
+  }
+
+  inline bool Next () {
+    if (here != end || NextBuf()) { ++here; return true; }
+    return false;
+  }
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FragLevelConvert.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FragLevelConvert.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FragLevelConvert.cpp	(revision 10506)
@@ -0,0 +1,105 @@
+/**************************************************************************
+ *
+ * FragLevelConvert.cpp -- converting between fragment and document numbers
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "FragLevelConvert.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+
+
+FragLevelConvert::FragLevelConvert () {
+  numFrags = 0;
+  numLevelDocs = 0;
+}
+
+bool FragLevelConvert::Read (FILE *invfFile,
+			     unsigned long levelPtr,
+			     unsigned long _numFrags,
+			     unsigned long _numLevelDocs) {
+  levelStarts.erase (levelStarts.begin(), levelStarts.end());
+  numFrags = _numFrags;
+  numLevelDocs = _numLevelDocs;
+
+  // seek to the appropriate place in the inverted file
+  fseek (invfFile, levelPtr, SEEK_SET);
+
+  stdio_bitio_buffer buffer(invfFile);
+  
+  unsigned long pTag = numLevelDocs*2;
+  unsigned long B = BIO_Bblock_Init (numFrags+pTag, pTag);
+  unsigned long fragNum = 0;
+  unsigned long i;
+  for (i=0; i<numLevelDocs; ++i) {
+    unsigned long delta = buffer.bblock_decode (B, NULL)-1;
+    fragNum += delta;
+
+    levelStarts.push_back (fragNum);
+
+    // ignore end, assume every fragment is in a level
+    delta = buffer.bblock_decode (B, NULL)-1;
+    fragNum += delta;
+  }
+
+  // fragNum would be the starting fragment of the next document
+  // if there was one
+  levelStarts.push_back (fragNum);
+  
+  if (fragNum != _numFrags) {
+    cerr << "last frag num:"<<fragNum<<" != num frags:"<<_numFrags<<endl;
+  } 
+  buffer.done();
+
+  return true;
+}
+
+bool FragLevelConvert::FragToLevel (unsigned long fragNum,
+				    unsigned long &levelDocNum) const {
+  // do binary search for something containing this fragment number
+  unsigned long low = 1, high = numLevelDocs;
+  unsigned long mid;
+
+  while ((mid = (low+high)/2) >= 1 && low <= high) {
+    if (fragNum > levelStarts[mid]) low = mid+1;
+    else if (fragNum <= levelStarts[mid-1]) high = mid-1;
+    else {
+      levelDocNum = mid;
+      return true;
+    }
+  }
+  return false;
+}
+
+
+bool FragLevelConvert::LevelToLevel (FragLevelConvert sectionLevelConvert,
+		 unsigned long levelNum, unsigned long &DocNum) {
+  
+  if (levelNum==1) {
+    DocNum=1;
+    return true;
+  }
+  unsigned long levelfragnum = sectionLevelConvert.levelStarts[levelNum-1]+1;
+
+  if (FragToLevel(levelfragnum, DocNum)) {
+    return true;
+  } 
+  return false;
+  
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FragLevelConvert.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FragLevelConvert.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/FragLevelConvert.h	(revision 10506)
@@ -0,0 +1,70 @@
+/**************************************************************************
+ *
+ * FragLevelConvert.h -- converting between fragment and document numbers
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef FRAGLEVELCONVERT_H
+#define FRAGLEVELCONVERT_H
+
+#include <stdio.h>
+#include "UCArray.h"
+
+
+/*Notes about levelStarts (kjm18) - this is my interpretation of
+whats going on, feel free to correct this if its wrong.
+
+say you have 5 docs, consisting of fragments:
+1:  1-55
+2: 56-83
+3: 84-106
+4: 107-152
+5: 153-211
+
+then levelStarts would have the values
+0  1  2   3   4   5 
+0  55 83 106 152 211
+
+*/
+class FragLevelConvert {
+protected:
+  // note fragment start is one before before real start
+  vector<unsigned long> levelStarts;
+  unsigned long numFrags;
+  unsigned long numLevelDocs;
+  
+public:
+  FragLevelConvert ();
+
+  bool Read (FILE *invfFile, unsigned long levelPtr,
+	     unsigned long _numFrags, unsigned long _numLevelDocs);
+
+  bool FragToLevel (unsigned long fragNum, unsigned long &levelDocNum) const;
+
+  // this function converts from one level number to another
+  // the FragLevelConvert thats calling the method should be loaded with
+  // the level that you want to convert to, while the sectionLevelConvert
+  // should be loaded with the level converting from.
+  // level Num has the old level, DocNum will be returned with the new
+  // coresponding level
+  bool LevelToLevel (FragLevelConvert sectionLevelConvert,
+		   unsigned long levelNum, unsigned long &DocNum);
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryLex.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryLex.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryLex.cpp	(revision 10506)
@@ -0,0 +1,275 @@
+/**************************************************************************
+ *
+ * GSDLQueryLex.cpp -- Lexical analyser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "GSDLQueryLex.h"
+#include "unitool.h"
+#include "words.h"
+
+inline void AddNChar (UCArray::const_iterator &here,
+		      UCArray &text,
+		      int len) {
+  if (text.capacity() < text.size() + len + 1) {
+    text.reserve(text.size() + len + 1);
+  }
+  while (len > 0) {
+    text.push_back (*here++);
+    --len;
+  }
+}
+
+static bool ParseInteger (UCArray::const_iterator &here,
+			  UCArray::const_iterator end,
+			  LexEl &el) {
+  el.Clear();
+
+  // this version of end is used in unitool
+  //  UCArray::const_iterator endMinus1 = end-1;
+  const unsigned char* endMinus1 = &(*end)-1;
+
+  int charLen;
+  unsigned short c; // one character lookahead
+  charLen = parse_utf8_char (&*here, endMinus1, &c);
+
+  // check for positive or negative
+  bool neg = false;
+  if (c == '+') {
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (&*here, endMinus1, &c);
+  } else if (c == '-') {
+    neg = true;
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (&*here, endMinus1, &c);
+  }
+
+  // read in number part
+  int numeric=0;
+  el.num = 0;
+  el.lexType = IntegerE;
+  /* stop integers at 4 digits */
+  while (c >= '0' && c <= '9'&& ++numeric<=MAXNUMERIC) {
+    el.num = el.num*10 + c - '0';
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (&*here, endMinus1, &c);
+  }
+
+  if (neg) el.num *= -1;
+
+  return (!el.text.empty());
+}
+
+static bool ParsePotentialInteger(UCArray::const_iterator &here,
+				  UCArray::const_iterator end,
+				  LexEl &el) {
+  el.Clear();
+
+  // this version of end is used in unitool
+  //UCArray::const_iterator endMinus1 = end-1;
+  const unsigned char* endMinus1 = &(*end)-1;
+
+  int charLen=0;
+  int length=0;
+  unsigned short c; // one character lookahead
+  charLen = parse_utf8_char (&*here, endMinus1, &c);
+
+  // read in number part
+  int numeric=0;
+  el.num = 0;
+  el.lexType = IntegerE;
+  /* stop integers at 4 digits */
+  while (c >= '0' && c <= '9'&& ++numeric<=MAXNUMERIC) {
+    el.num = el.num*10 + c - '0';
+    AddNChar (here, el.text, charLen);
+    length += charLen;
+    charLen = parse_utf8_char (&*here, endMinus1, &c);
+  }
+  // check the next character -if it is a letter, then have a term, not an integer
+  if (!is_unicode_letter(c)) {
+    // this was just an integer
+    return (!el.text.empty());
+  }
+  // else its a term
+  el.lexType = TermE;
+  el.num = 0;
+  /* this bit taken from ParseIndexWord in words.h*/
+  while (length+charLen<=MAXSTEMLEN && charLen > 0 &&
+	 (is_unicode_letter(c) || (is_unicode_digit(c) &&
+				   ++numeric <= MAXNUMERIC))) {
+    AddNChar (here, el.text, charLen);
+    length += charLen;
+    charLen = parse_utf8_char (&*here, endMinus1, &c);
+  }
+
+  return (!el.text.empty());
+}
+static bool ParseTerm (UCArray::const_iterator &here,
+		       UCArray::const_iterator end,
+		       UCArray &text) {
+  //UCArray::const_iterator endMinus1 = end-1;
+  const unsigned char* endMinus1 = &(*end)-1;
+  const unsigned char* new_here = ParseIndexWord (&*here, endMinus1, text);
+  here += (new_here - &*here); // advance iterator by number of chars advanced
+  return !text.empty();
+}
+
+
+bool ParseLexEl (UCArray::const_iterator &here,
+		 UCArray::const_iterator end,
+		 LexEl &el) {
+  el.Clear();
+
+  // strange things can happen if here == end == 0
+  if (here == end) return false;
+  
+  // this version of end is used in unitool
+  //UCArray::const_iterator endMinus1 = end-1;
+  const unsigned char* endMinus1 = &(*end)-1;
+
+  // ignore all white space
+  int charLen;
+  unsigned short c; // one character lookahead
+  charLen = parse_utf8_char (&*here, endMinus1, &c);
+  while (here != end && is_unicode_space (c)) {
+    here += charLen;
+    charLen = parse_utf8_char (&*here, endMinus1, &c);
+  }
+  if (here == end) return false;
+
+  if (c == '(') {
+    el.lexType = OpenBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == ')') {
+    el.lexType = CloseBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+
+  } else if (c =='[') {
+    el.lexType = OpenSquareBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+  
+  } else if (c ==']') {
+    el.lexType = CloseSquareBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+  
+  } else if (c == '\"') {
+    el.lexType = QuoteE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '/') {
+    el.lexType = TermWeightE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '#') {
+    el.lexType = StemMethodE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '*') {
+    el.lexType = StarE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '^') {
+    el.lexType = RangeE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '@') {
+    el.lexType = AtE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == ':') {
+    el.lexType = TagE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c=='&') {
+    el.lexType = AndOpE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '|') {
+    el.lexType = OrOpE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '!') {
+    el.lexType = NotOpE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '+' || c == '-' ) {
+    return  ParseInteger (here, end, el);
+  }
+
+  else if (c >= '0' && c <= '9') {
+    return ParsePotentialInteger (here, end, el);
+  }
+
+  // assume it is a term of some sort
+  if (!ParseTerm (here, end, el.text))  {
+    // parse term returns false if it hasn't parsed anything that is a term
+    // here should be the same as it was before 
+    el.lexType = UnknownE;
+    AddNChar (here, el.text, charLen);
+    return true;
+  }
+  //return false;
+
+  //UCArray AND; SetCStr (AND, "AND");
+  //if (el.text == AND) {
+  if (UCArrayCStrEquals(el.text, "AND")) {
+    el.lexType = AndOpE;
+    return true;
+  }
+  //UCArray OR; SetCStr (OR, "OR");
+  //if (el.text == OR) {
+  if (UCArrayCStrEquals(el.text, "OR")) {
+    el.lexType = OrOpE;
+    return true;
+  }
+  //UCArray NOT; SetCStr (NOT, "NOT");
+  //if (el.text == NOT) {
+  if (UCArrayCStrEquals(el.text, "NOT")) {
+    el.lexType = NotOpE;
+    return true;
+  }
+  UCArray NEAR; SetCStr (NEAR, "NEAR", 4);
+  if (PrefixLen(el.text, NEAR)==4) {
+    el.lexType = NearOpE;
+    return true;
+  }
+  UCArray WITHIN; SetCStr (WITHIN, "WITHIN", 6);
+  if (PrefixLen(el.text, WITHIN)==6) {
+    el.lexType = WithinOpE;
+    return true;
+  }
+  
+  el.lexType = TermE;
+  return true;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryLex.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryLex.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryLex.h	(revision 10506)
@@ -0,0 +1,64 @@
+/**************************************************************************
+ *
+ * GSDLQueryLex.h -- Lexical analyser for a simple query language, for GSDL
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef GSDLQUERYLEX_H
+#define GSDLQUERYLEX_H
+
+#include "UCArray.h"
+
+
+// note: white space is ignored
+enum LexType {NoTypeE, OpenBracketE, CloseBracketE, TermE, AndOpE, OrOpE,
+	      NotOpE, NearOpE, WithinOpE, QuoteE, IntegerE, TermWeightE, 
+	      StemMethodE, RangeE, AtE, TagE, OpenSquareBracketE, 
+	      CloseSquareBracketE, StarE, UnknownE};
+
+struct LexEl {
+  LexType lexType;
+  UCArray text;
+  int num; // for IntegerE
+
+  void Clear () {
+    lexType = NoTypeE;
+    UCArrayClear (text);
+    num = 0;
+  }
+  LexEl () { Clear (); }
+};
+
+
+// returns true if another lexical element could be parsed.
+bool ParseLexEl (UCArray::const_iterator &here,
+		 UCArray::const_iterator end,
+		 LexEl &el);
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryParser.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryParser.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryParser.cpp	(revision 10506)
@@ -0,0 +1,515 @@
+/**************************************************************************
+ *
+ * QueryParser.cpp -- Query parser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "GSDLQueryParser.h"
+#include "GSDLQueryLex.h"
+
+
+static QueryNode *ParseExpression (UCArray::const_iterator &here,
+				   UCArray::const_iterator end, 
+				   int defaultBoolCombine,
+				   int defaultStemMethod);
+
+static QueryNode *AndAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  AndQueryNode *andNode = new AndQueryNode;
+  andNode->leftNode = t1;
+  andNode->rightNode = t2;
+  return andNode;
+}
+
+static QueryNode *OrAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  OrQueryNode *orNode = new OrQueryNode;
+  orNode->leftNode = t1;
+  orNode->rightNode = t2;
+  return orNode;
+}
+
+static QueryNode *NotAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  NotQueryNode *notNode = new NotQueryNode;
+  notNode->queryNode = t1;
+  notNode->notNode = t2;
+  return notNode;
+}
+
+// expects the opening bracket to have already been parsed
+// and discarded
+static QueryNode *ParseBracketExpression (UCArray::const_iterator &here,
+					  UCArray::const_iterator end, 
+					  int defaultBoolCombine,
+					  int defaultStemMethod) {
+  // get everything in the expression
+  QueryNode *curTree = ParseExpression (here, end, defaultBoolCombine,
+					defaultStemMethod);
+  
+  // gobble up tokens until a closing bracket is found
+  // or the end of the string
+  LexEl el;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == CloseBracketE) break;
+  }
+
+  return curTree;
+}
+
+static int ParseInt (UCArray::const_iterator &here,
+		     UCArray::const_iterator end) {
+  LexEl el;
+  UCArray::const_iterator oldHere = here;
+  if (ParseLexEl (here, end, el) && el.lexType == IntegerE)
+    return el.num;
+  
+  here = oldHere; // not an integer
+  return 0;
+}
+
+// default is within 20 words
+static void SetRangeValues (TermNode &termNode,
+			    UCArray &nearby,
+			    bool reverse) {
+  UCArray NEARBY; SetCStr(NEARBY, "NEAR", 4);
+  UCArray WITHIN; SetCStr(WITHIN, "WITHIN", 6);
+  
+  if (nearby == NEARBY) { // no modifier
+    termNode.startRange = (NEAR_DEFAULT+1)*-1;
+    termNode.endRange = NEAR_DEFAULT;
+
+  } else if (nearby == WITHIN) { // no modifier
+    if (reverse) {
+      termNode.startRange = (NEAR_DEFAULT+1)*-1;
+      termNode.endRange = -1;
+    } else {
+      termNode.startRange = NEAR_DEFAULT;
+      termNode.endRange = 0;
+    }
+  }
+  else { // extract number
+    UCArray::const_iterator here;
+    bool within = false;
+    if (PrefixLen(nearby, WITHIN)==6) {
+      within=true;
+      here = nearby.begin()+6;
+    } else {
+      here = nearby.begin()+4;
+    }
+    UCArray::const_iterator end = nearby.end();
+    int size=0;
+    while (here != end) {
+      size = size*10 + (*here-'0');
+      ++here;
+    }
+    if (within) {
+      if (reverse) {
+	termNode.startRange = size;
+	termNode.endRange = 0;
+      } else {
+	termNode.startRange = -1 * (size+1);
+	termNode.endRange = -1;
+      }
+    } else {
+      termNode.startRange = -1 * (size+1);
+      termNode.endRange = size;
+    }
+  }
+}
+
+static unsigned long GetStemMethod(LexEl &el, int defaultStemMethod) {
+  // here expect el to contain some of c,s,i,u
+  // stem method 0 = c,u  00
+  // stem method 1 = i,u  01  - default for DL
+  // stem method 2 = c, s  10
+  // stem method 3 = i,s  11
+
+  unsigned long stem = (unsigned long)defaultStemMethod;
+      
+  UCArray::const_iterator here = el.text.begin();
+  UCArray::const_iterator end = el.text.end();
+
+  unsigned char c1 = *here; 
+  if (!(c1 == 'c'|| c1 == 'i' || c1 == 'u' || c1 == 's')) 
+    return 4; // incorrect format
+  
+  ++here;
+  unsigned char c2 = 'a';
+  if (here !=end) {
+    c2 = *here;
+    if (!(c2 == 'c'|| c2 == 'i' || c2 == 'u' || c2 == 's')) 
+      return 4; // incorrect format
+  }
+  
+  if (c1 == 'i'|| c2=='i') stem |= 1; // set bit 0 to 1
+  if (c1 == 'c' || c2 == 'c') stem &=0xe; //set bit 0 to 0
+  if (c1 == 's'|| c2 == 's') stem |= 2; // set bit 1 to 1
+  if (c1 == 'u' || c2 =='u') stem &=0xd; // set bit 1 to 0
+  return stem;
+}
+  
+
+static void ParseTermModifiers (UCArray::const_iterator &here,
+				UCArray::const_iterator end,
+				TermNode &termNode,
+				int defaultStemMethod) {
+ 
+  termNode.stemMethod = defaultStemMethod;
+  bool partial_match = false;
+  LexEl el;
+  UCArray::const_iterator oldHere = here;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TermWeightE) {
+      termNode.termWeight = ParseInt (here, end);
+      
+    } else if (el.lexType == StemMethodE) {
+      oldHere = here;
+      LexEl stem;
+      if (ParseLexEl (here, end, stem) && stem.lexType == TermE) {
+	termNode.stemMethod = GetStemMethod(stem, defaultStemMethod);
+	if (termNode.stemMethod == 4) { // error so backtrack
+	  here = oldHere;
+	  termNode.stemMethod = (unsigned long)defaultStemMethod;
+	} 
+      }else here = oldHere; //ignore - wrong syntax
+
+    } else if (el.lexType == RangeE) {
+      termNode.startRange = ParseInt (here, end);
+      termNode.endRange = ParseInt (here, end);
+      
+    } else if (el.lexType == AtE) {
+      termNode.startRange = termNode.endRange = ParseInt (here, end);
+    } else if (el.lexType == StarE) {
+      partial_match = true;
+    } else {
+      // no term modifiers
+      here = oldHere;
+      break;
+    }
+    
+    if (partial_match) {
+      termNode.stemMethod |= 4; // set bit 2 to 1
+      termNode.stemMethod &=0xd; // set bit 1 to 0 // we dont have stemming on if doing partial matching.
+    }
+    oldHere = here;
+  }  
+}
+
+static void ParseProxModifiers (UCArray::const_iterator &here,
+				UCArray::const_iterator end,
+				ProxMatchQueryNode *proxNode) {
+  // so far only have one - the tag stuff
+  LexEl el;
+  UCArray::const_iterator oldHere = here;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TagE) {
+      oldHere = here; // don't backtrack past here
+      if (ParseLexEl (here, end, el) && el.lexType == TermE) {
+	proxNode->tagNodePtr = new TagNode;
+	proxNode->tagNodePtr->tagName = el.text;
+	
+      }
+      else { // error in tag
+	here = oldHere;
+      }
+    } // TagE
+    // add in other cases here
+    else {
+      // no modifiers
+      here = oldHere;
+      break;
+    }
+    oldHere = here;
+  }//while
+
+
+}
+
+// expects starting brackets to have been parsed
+// sets error to true if something has gone wrong
+static ProxMatchQueryNode *ParseSquareBrackets(UCArray::const_iterator &here,
+				UCArray::const_iterator end,
+				/*ProxMatchQueryNode *proxNode,*/
+				int defaultStemMethod,
+				bool & error) {
+
+  ProxMatchQueryNode *proxNode = new ProxMatchQueryNode;
+  LexEl el;
+  bool phrase=false;
+  bool first=true;
+  bool prox = false;
+  UCArray near_string;
+  while (ParseLexEl (here, end, el)) {
+    // cant have AND, OR, NOT in square brackets, so assume they are words
+    if (el.lexType == TermE || el.lexType == IntegerE || el.lexType == AndOpE || el.lexType == OrOpE || el.lexType == NotOpE) {
+      TermNode termNode;
+      termNode.term = el.text;
+      ParseTermModifiers (here, end, termNode, defaultStemMethod);
+      if (phrase) {
+        if (first) first=false;
+        else {
+          termNode.startRange = -2;
+          termNode.endRange = -1;
+        }
+      } else if (prox) {
+	SetRangeValues(termNode, near_string, false);
+	prox = false;
+      }
+      proxNode->terms.push_back(termNode);
+    }
+    else if (el.lexType == CloseSquareBracketE) {
+      break;
+    }
+    else if (el.lexType == QuoteE) {
+      // phrase inside square brackets
+      if (phrase) { // end of phrase
+	phrase=false;
+	first = true;
+      } else {
+	phrase=true; // start of phrase
+      }
+    } else if (el.lexType == NearOpE || el.lexType == WithinOpE) {
+      if (phrase) {
+	// cant have proximity  op in a phrase - just assume its an actual word
+	TermNode termNode;
+	termNode.term = el.text;
+	ParseTermModifiers (here, end, termNode, defaultStemMethod);
+	proxNode->terms.push_back(termNode);
+      } else {
+	// its a NEAR or within op
+	prox = true;
+	near_string = el.text;
+      }
+	  
+    } 
+    else if (el.lexType == UnknownE) {
+      // just ignore it 
+    }
+    else {
+      //error - we set the proxNode to NULL,
+      cerr <<"GSDLQueryParser: bad syntax inside []\n";
+      error = true;
+      return NULL;
+    }
+  } // while
+  return proxNode;
+}
+// expects the starting quote to have been parsed
+// and discarded
+// now phrases use the case and stem preference options
+// ie can search for a phrase ignoring case
+static void ParsePhrase (UCArray::const_iterator &here,
+			 UCArray::const_iterator end,
+			 ProxMatchQueryNode &proxNode, 
+			 int defaultStemMethod,
+			 bool &error) {
+  LexEl el;
+  bool first = true;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TermE || el.lexType == IntegerE) {
+      TermNode termNode;
+      termNode.term = el.text;
+      //termNode.stemMethod = defaultStemMethod;
+      ParseTermModifiers (here, end, termNode, defaultStemMethod);
+      if (first) {
+	first = false;
+      }
+      else {
+	termNode.startRange = -2;
+	termNode.endRange = -1;
+      }
+      proxNode.terms.push_back (termNode);
+      
+    } else if (el.lexType == QuoteE) {
+      break;
+      
+    } else if (el.lexType == UnknownE) {
+      // just ignore it
+    } else {
+      // error 
+      error = true;
+      return;
+    }
+  }
+}
+
+static QueryNode *ParseTerm (UCArray::const_iterator &here,
+			     UCArray::const_iterator end,
+			     int defaultBoolCombine,
+			     int defaultStemMethod) {
+  LexEl el;
+
+  UCArray::const_iterator oldHere = here;
+  if (!ParseLexEl (here, end, el)) return NULL;
+
+  if (el.lexType == OpenBracketE)
+    return ParseBracketExpression (here, end, defaultBoolCombine,
+				   defaultStemMethod);
+
+  ProxMatchQueryNode *proxNode = new ProxMatchQueryNode;
+
+  if (el.lexType == TermE || el.lexType == IntegerE) {
+    TermNode termNode;
+    termNode.term = el.text;
+    ParseTermModifiers (here, end, termNode, defaultStemMethod);
+    oldHere = here;  // dont backtrack past here
+    if (ParseLexEl(here, end, el) && (el.lexType == NearOpE || el.lexType == WithinOpE )) {
+	delete proxNode;
+	oldHere = here;
+      // this is calling ParseTerm again, but only a subset of the things accepted by ParseTerm are appropriate here. add in some hacks to avoid segmentation faults - kjdon, 04/2003
+      
+      // if the next element is a '(' have a syntax error, return NULL 
+      LexEl temp_el;
+      if (ParseLexEl(here, end, temp_el) && temp_el.lexType == OpenBracketE) {
+	cerr << "GSDLQueryParser: NEAR/WITHIN cannot be followed by a '('\n";
+	return NULL;
+      }
+      here = oldHere; // else backtrack
+	
+      proxNode = (ProxMatchQueryNode *)ParseTerm(here, end, defaultBoolCombine,
+						 defaultStemMethod);
+      SetRangeValues(termNode, el.text, true);
+      proxNode->terms.push_back (termNode);
+      return proxNode;
+      
+    } else {
+      here = oldHere; // backtrack
+      proxNode->terms.push_back (termNode);
+      ParseProxModifiers(here, end, proxNode);
+      return proxNode;
+    }
+  } else if (el.lexType == QuoteE) {
+    bool error = false;
+    ParsePhrase (here, end, *proxNode, defaultStemMethod, error);
+    if (error) {
+      delete proxNode;
+      return NULL;
+    }
+    return proxNode;
+  }
+  else if (el.lexType == OpenSquareBracketE) {
+    bool error = false;
+    proxNode = ParseSquareBrackets (here, end, /*proxNode, */defaultStemMethod, error);
+    if (error) {
+      delete proxNode;
+      return NULL;
+    }
+    ParseProxModifiers (here, end, proxNode);
+    return proxNode;
+  }
+
+  // not a term
+  here = oldHere;
+  delete proxNode;
+  return NULL;
+}
+
+
+static QueryNode *ParseExpression (UCArray::const_iterator &here,
+				   UCArray::const_iterator end,
+				   int defaultBoolCombine,
+				   int defaultStemMethod) {
+  LexEl el;
+  QueryNode *curTree = NULL;
+  UCArray::const_iterator oldHere = here;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == CloseBracketE) {
+      // parsebracketexpression is waiting for the last bracket, so put it back
+      here = oldHere;
+      break;
+      
+    } else if (el.lexType == OpenSquareBracketE ||
+	       el.lexType == OpenBracketE ||
+	       el.lexType == TermE ||
+	       el.lexType == QuoteE ||
+	       el.lexType == IntegerE ) { 
+      
+      // some type of term, back track and parse it
+      here = oldHere;
+
+      //  parse the term
+      QueryNode * newTerm = ParseTerm (here, end, defaultBoolCombine, 
+				       defaultStemMethod);
+      if (newTerm == NULL) {
+	delete curTree;
+	return NULL;
+      }
+
+      // if default==1, AND, else if==0, OR
+      if (defaultBoolCombine) {
+	curTree = AndAdd (curTree, newTerm);
+      }
+      else {
+	curTree = OrAdd (curTree, newTerm); 
+      }
+      
+    } else if (el.lexType == AndOpE) {
+      QueryNode * newTerm = ParseTerm (here, end, defaultBoolCombine,
+				       defaultStemMethod);
+      if (newTerm == NULL) {
+	delete curTree;
+	return NULL;
+      }
+      curTree = AndAdd (curTree, newTerm);
+      
+    } else if (el.lexType == OrOpE) {
+      QueryNode * newTerm = ParseTerm (here, end, defaultBoolCombine,
+				       defaultStemMethod);
+      if (newTerm == NULL) {
+	delete curTree;
+	return NULL;
+      }
+      curTree = OrAdd (curTree, newTerm);
+      
+    } else if (el.lexType == NotOpE) {
+      QueryNode * newTerm = ParseTerm (here, end, defaultBoolCombine,
+				       defaultStemMethod);
+      if (newTerm == NULL) {
+	delete curTree;
+	return NULL;
+      }
+      curTree = NotAdd (curTree, newTerm); 
+      
+    } else if (el.lexType == UnknownE) {
+      // just ignore it 
+    } else {
+
+      // syntax error, return NUll
+      delete curTree;
+      return NULL;
+    }
+
+    oldHere = here;
+  }
+
+  return curTree;
+}
+
+QueryNode *ParseQuery (const UCArray &queryStr, int defaultBoolCombine,
+		       int defaultStemMethod) {
+  UCArray::const_iterator here = queryStr.begin();
+  UCArray::const_iterator end = queryStr.end();
+  return ParseExpression (here, end, defaultBoolCombine, defaultStemMethod);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryParser.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryParser.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/GSDLQueryParser.h	(revision 10506)
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * QueryParser.h -- Query parser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef GSDLQUERYPARSER_H
+#define GSDLQUERYPARSER_H
+
+#include "UCArray.h"
+#include "MGQuery.h"
+
+#define NEAR_DEFAULT 20
+
+// returns NULL if the query could not be parsed
+// defaultBoolCOmbine determines if individual terms are combined using
+// AND or OR in the absence of specified operators.
+// defaultStemMethod used to set stemming and casefolding for terms where
+// its not set explicitly in the query string. THe defaultStemMethod value
+// should be set using the values from the preferences page
+QueryNode *ParseQuery (const UCArray &queryStr, int defaultBoolCombine,
+		       int defaultStemMethod);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/IndexData.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/IndexData.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/IndexData.cpp	(revision 10506)
@@ -0,0 +1,207 @@
+/**************************************************************************
+ *
+ * IndexData.cpp -- Information needed for querying
+ * Copyright (C) 1999 Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "IndexData.h"
+#include "string.h"
+#include "mg_files.h"
+
+IndexData::IndexData () {
+  basePath[0] = '\0';
+  filename[0] = '\0';
+
+  dictFile = NULL;
+
+  stem1File = NULL;
+  stem2File = NULL;
+  stem3File = NULL;
+
+  invfFile = NULL;
+
+  approxWeightsFile = NULL;
+  exactWeightsFile = NULL;
+
+  curLevelNum = 0;
+}
+
+IndexData::~IndexData () {
+  UnloadData ();
+}
+
+bool IndexData::LoadData (const char *_basePath, const char *_filename) {
+  if (_filename[0] == '\0') return false;
+  
+  // make sure this data has not already been loaded
+  if (strcmp (_basePath, basePath) == 0 &&
+      strcmp (_filename, filename) == 0) return true;
+  
+  // make sure there is nothing else loaded
+  UnloadData ();
+
+  strcpy (basePath, _basePath);
+  strcpy (filename, _filename);
+
+  set_basepath (basePath);
+
+  // load in the level information
+  FILE *ivfLevelFile;
+  ivfLevelFile = open_file (filename, INVF_LEVEL_SUFFIX, "rb",
+			    MAGIC_INVF_LEVELS, MG_ABORT);
+  levels.Read (ivfLevelFile);
+  fclose (ivfLevelFile);
+
+  // blocked dictionary
+  dictFile = open_file (filename, INVF_DICT_BLOCKED_SUFFIX, "rb",
+			MAGIC_STEM, MG_ABORT);
+  if (!bdh.Read (dictFile)) { UnloadData (); return false; }
+
+  fseek (dictFile, bdh.wblk_idx_start, SEEK_SET);
+  if (!ReadBlockIdx (dictFile, biWords)) { UnloadData (); return false; }
+
+  fseek (dictFile, bdh.tblk_idx_start, SEEK_SET);
+  if (!ReadBlockIdx (dictFile, biTags)) { UnloadData (); return false; }
+
+  // blocked stem index 1
+  stem1File = open_file (filename, INVF_DICT_BLOCKED_1_SUFFIX,
+			 "rb", MAGIC_STEM_1, MG_ABORT);
+  if (!sih1.Read (stem1File)) { UnloadData (); return false; }
+
+  fseek (stem1File, sih1.block_idx_start, SEEK_SET);
+  if (!ReadBlockIdx (stem1File, sii1)) { UnloadData (); return false; }
+  
+  // blocked stem index 2
+  stem2File = open_file (filename, INVF_DICT_BLOCKED_2_SUFFIX,
+			 "rb", MAGIC_STEM_2, MG_ABORT);
+  if (!sih2.Read (stem2File)) { UnloadData (); return false; }
+
+  fseek (stem2File, sih2.block_idx_start, SEEK_SET);
+  if (!ReadBlockIdx (stem2File, sii2)) { UnloadData (); return false; }
+  
+  // blocked stem index 3
+  stem3File = open_file (filename, INVF_DICT_BLOCKED_3_SUFFIX,
+			 "rb", MAGIC_STEM_3, MG_ABORT);
+  if (!sih3.Read (stem3File)) { UnloadData (); return false; }
+
+  fseek (stem3File, sih3.block_idx_start, SEEK_SET);
+  if (!ReadBlockIdx (stem3File, sii3)) { UnloadData (); return false; }
+
+  // inverted file
+  invfFile = open_file (filename, INVF_SUFFIX, "rb",
+			MAGIC_INVF, MG_ABORT);
+  ifh.Read (invfFile);
+
+  // weights
+  approxWeightsFile = open_file (filename, APPROX_WEIGHTS_SUFFIX, "rb",
+				 MAGIC_WGHT_APPROX, MG_ABORT);
+  exactWeightsFile = open_file (filename, WEIGHTS_SUFFIX, "rb",
+				MAGIC_WGHT, MG_ABORT);
+
+  return true;
+}
+
+bool IndexData::UnloadData () {
+  basePath[0] = '\0';
+  filename[0] = '\0';
+
+  if (dictFile != NULL) {
+    fclose (dictFile); dictFile = NULL;
+  }
+
+  if (stem1File != NULL) {
+    fclose (stem1File); stem1File = NULL;
+  }
+  if (stem2File != NULL) {
+    fclose (stem2File); stem2File = NULL;
+  }
+  if (stem3File != NULL) {
+    fclose (stem3File); stem3File = NULL;
+  }
+
+  if (invfFile != NULL) {
+    fclose (invfFile); invfFile = NULL;
+  }
+
+  if (approxWeightsFile != NULL) {
+    fclose (approxWeightsFile); approxWeightsFile = NULL;
+  }
+  if (exactWeightsFile != NULL) {
+    fclose (exactWeightsFile); exactWeightsFile = NULL;
+  }
+
+  UnloadLevel();
+  
+  return true;
+}
+
+
+bool IndexData::LoadLevel (const UCArray &level) {
+  // make sure this level is not already loaded
+  if (level == curLevel) return true;
+
+  // unload any levels currently loaded
+  UnloadLevel();
+
+  // make sure the required files are open
+  if (dictFile == NULL || invfFile == NULL ||
+      approxWeightsFile == NULL || exactWeightsFile == NULL)
+    return false;
+  
+  // read in the information from the dictionary
+  block_dict_el tagEl;
+  unsigned long tagElNum;
+  if (!SearchBlockDictEl (dictFile, biTags, bdh.entries_per_tblk,
+			  bdh.tag_dict_size, level, tagEl, tagElNum))
+    return false;
+
+  // read in the level conversion information
+  if (!levelConverter.Read (invfFile, tagEl.invf_ptr,
+			    bdh.num_frags, tagEl.frag_occur))
+    return false;
+
+  // read in the approximate weights
+  if (!weightData.Read (approxWeightsFile,
+			levels.levelInfo[level].approxWeightsDiskPtr,
+			levels.levelInfo[level].numEntries))
+    return false;
+  
+  // find the level number
+  curLevelNum = 0;
+  IvfLevelInfoMap::const_iterator levelHere, levelEnd;
+  for (levelHere=levels.levelInfo.begin(), levelEnd=levels.levelInfo.end();
+       levelHere!=levelEnd && (*levelHere).first != level; ++levelHere)
+    ++curLevelNum;
+
+  // make sure we found the level
+  if (levelHere == levelEnd) return false;
+
+  curLevel = level;
+
+  return true;
+}
+
+bool IndexData::UnloadLevel () {
+  curLevel.erase (curLevel.begin(), curLevel.end());
+  curLevelNum = 0;
+  
+  weightData.Free ();
+    
+  return true;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/IndexData.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/IndexData.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/IndexData.h	(revision 10506)
@@ -0,0 +1,82 @@
+/**************************************************************************
+ *
+ * IndexData.h -- Information needed for querying
+ * Copyright (C) 1999 Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef INDEXDATA_H
+#define INDEXDATA_H
+
+#include <stdio.h>
+#include "invf.h"
+#include "FIvfLevelInfo.h"
+#include "FragLevelConvert.h"
+#include "Weights.h"
+
+
+class IndexData {
+public:
+  // general information
+  char basePath[FILENAME_MAX];
+  char filename[FILENAME_MAX];
+  FIvfLevel levels;
+  
+  // blocked dictionary
+  FILE *dictFile;
+  block_dict_header bdh;
+  block_idx biWords;
+  block_idx biTags;
+
+  // stem indexes
+  FILE *stem1File;
+  FILE *stem2File;
+  FILE *stem3File;
+  stem_idx_header sih1;
+  stem_idx_header sih2;
+  stem_idx_header sih3;
+  block_idx sii1;
+  block_idx sii2;
+  block_idx sii3;
+
+  // inverted file
+  FILE *invfFile;
+  invf_file_header ifh;
+
+  // weights
+  FILE *approxWeightsFile;
+  FILE *exactWeightsFile;
+
+  // level specific information
+  UCArray curLevel; // last level that was loaded
+  unsigned long curLevelNum;
+  FragLevelConvert levelConverter;
+  ApproxWeightsData weightData;
+  
+  IndexData ();
+  ~IndexData ();
+
+  // LoadData will only load the data if it has not been loaded before
+  bool LoadData (const char *_basePath, const char *_filename);
+  bool UnloadData ();
+
+  bool LoadLevel (const UCArray &level);
+  bool UnloadLevel ();
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/MGQuery.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/MGQuery.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/MGQuery.cpp	(revision 10506)
@@ -0,0 +1,760 @@
+/**************************************************************************
+ *
+ * MGQuery.cpp -- Query related functions
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "MGQuery.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include "Terms.h"
+#include "QueryResultsSort.h"
+#include <assert.h>
+
+
+void PrintIndent (ostream &s, int indent) {
+  while (indent-- > 0) s << " ";
+}
+
+
+void PrintIndentText (ostream &s, char *text, int indent) {
+  PrintIndent (s, indent);
+  s << text;
+}
+
+void PrintNode (ostream &s, QueryNode *node, int indent) {
+  if (node == NULL) {
+    PrintIndentText (s, "NULL\n", indent);
+  } else {
+    node->Print (s, indent+2);
+  }
+}
+
+  
+
+QueryNode::QueryNode () {
+}
+
+QueryNode::~QueryNode () {
+}
+
+void QueryNode::Calculate (IndexData &/*indexData*/,
+			   const QueryInfo &/*queryInfo*/,
+			   QueryResult &result) const {
+  result.Clear();
+}
+
+void QueryNode::Free () {
+}
+
+void QueryNode::Print (ostream &/*s*/, int /*indent*/) const {
+}
+
+
+
+AndQueryNode::AndQueryNode () {
+  leftNode = NULL;
+  rightNode = NULL;
+}
+
+AndQueryNode::~AndQueryNode () {
+  Free ();
+}
+
+void AndQueryNode::Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+			      QueryResult &result) const {
+  result.Clear();
+
+  // an And between nothing and something is nothing...
+  if (leftNode == NULL || rightNode == NULL) return;
+  
+  // calculate the result from the left tree and the result
+  // from the right tree
+  QueryResult rightResult;
+  leftNode->Calculate (indexData, queryInfo, result);
+  rightNode->Calculate (indexData, queryInfo, rightResult);
+
+  // merge the results, this can be done in place as the results
+  // will always shrink with an And
+
+  bool haveAccum = (queryInfo.sortByRank || queryInfo.needRankInfo);
+  if (haveAccum && (result.ranks.size() != result.docs.size() ||
+		    rightResult.ranks.size() != rightResult.docs.size())) {
+    // shouldn't ever get here
+    haveAccum = false;
+    assert (0);
+  }
+
+  // combine document numbers and corresponding ranks
+  unsigned long leftI = 0;
+  unsigned long rightI = 0;
+  unsigned long outI = 0;
+  while (leftI < result.docs.size() &&
+	 rightI < rightResult.docs.size()) {
+    if (result.docs[leftI] < rightResult.docs[rightI]) {
+      ++leftI;
+    } else if (result.docs[leftI] > rightResult.docs[rightI]) {
+      ++rightI;
+    } else {
+      // the documents are equal
+      result.docs[outI] = result.docs[leftI];
+      if (haveAccum)
+	result.ranks[outI] = result.ranks[leftI] + rightResult.ranks[rightI];
+      ++leftI;
+      ++rightI;
+      ++outI;
+    }
+  }
+
+  // erase unused document numbers and ranks
+  result.docs.erase(result.docs.begin()+outI, result.docs.end());
+  if (haveAccum)
+    result.ranks.erase(result.ranks.begin()+outI, result.ranks.end());
+    
+  // combine term frequency information
+  if (queryInfo.needTermFreqs)
+    result.termFreqs.insert (result.termFreqs.end(),
+			     rightResult.termFreqs.begin(),
+			     rightResult.termFreqs.end());
+}
+
+void AndQueryNode::Free () {
+  if (leftNode != NULL) {
+    delete leftNode;
+    leftNode = NULL;
+  }
+  if (rightNode != NULL) {
+    delete rightNode;
+    rightNode = NULL;
+  }
+}
+
+void AndQueryNode::Print (ostream &s, int indent) const {
+  PrintIndentText (s, "leftNode:\n", indent);
+  PrintNode (s, leftNode, indent+2);
+  PrintIndentText (s, "AND\n", indent);
+  PrintIndentText (s, "rightNode:\n", indent);
+  PrintNode (s, rightNode, indent+2);
+}
+
+
+OrQueryNode::OrQueryNode () {
+  leftNode = NULL;
+  rightNode = NULL;
+}
+
+OrQueryNode::~OrQueryNode () {
+  Free ();
+}
+
+void OrQueryNode::Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+			      QueryResult &result) const {
+  result.Clear();
+  
+  // calculate the result from the left tree and the result
+  // from the right tree
+  QueryResult leftResult;
+  QueryResult rightResult;
+  if (leftNode != NULL)
+    leftNode->Calculate (indexData, queryInfo, leftResult);
+  if (rightNode != NULL)
+    rightNode->Calculate (indexData, queryInfo, rightResult);
+
+  // merge the results
+  
+  bool haveAccum = (queryInfo.sortByRank || queryInfo.needRankInfo);
+  if (haveAccum && (leftResult.ranks.size() != leftResult.docs.size() ||
+		    rightResult.ranks.size() != rightResult.docs.size())) {
+    // shouldn't ever get here
+    haveAccum = false;
+    assert (0);
+  }
+
+  // combine document numbers and corresponding ranks
+  unsigned long leftSize = leftResult.docs.size();
+  unsigned long rightSize = rightResult.docs.size();
+  unsigned long leftI = 0;
+  unsigned long rightI = 0;
+  unsigned long leftDocNum = 0;
+  unsigned long rightDocNum = 0;
+  while (leftI < leftSize || rightI < rightSize) {
+    // check leftI
+    if (leftI < leftResult.docs.size())
+      leftDocNum = leftResult.docs[leftI];
+    else leftDocNum = ULONG_MAX;
+    
+    // check rightI
+    if (rightI < rightResult.docs.size())
+      rightDocNum = rightResult.docs[rightI];
+    else rightDocNum = ULONG_MAX;
+    
+    // combine
+    if (leftDocNum < rightDocNum) {
+      result.docs.push_back (leftDocNum);
+      if (haveAccum)
+	result.ranks.push_back (leftResult.ranks[leftI]);
+      ++leftI;
+      
+    } else if (leftDocNum > rightDocNum) {
+      result.docs.push_back (rightDocNum);
+      if (haveAccum)
+	result.ranks.push_back (rightResult.ranks[rightI]);
+      ++rightI;
+      
+    } else { // equal
+      result.docs.push_back (leftDocNum);
+      if (haveAccum)
+	result.ranks.push_back (leftResult.ranks[leftI] +
+				rightResult.ranks[rightI]);
+      ++leftI;
+      ++rightI;
+    }
+  }
+
+  // combine term frequency information
+  if (queryInfo.needTermFreqs) {
+    result.termFreqs.insert (result.termFreqs.end(),
+			     leftResult.termFreqs.begin(),
+			     leftResult.termFreqs.end());
+    result.termFreqs.insert (result.termFreqs.end(),
+			     rightResult.termFreqs.begin(),
+			     rightResult.termFreqs.end());
+  }
+}
+
+void OrQueryNode::Free () {
+  if (leftNode != NULL) {
+    delete leftNode;
+    leftNode = NULL;
+  }
+  if (rightNode != NULL) {
+    delete rightNode;
+    rightNode = NULL;
+  }
+}
+
+void OrQueryNode::Print (ostream &s, int indent) const {
+  PrintIndentText (s, "leftNode:\n", indent);
+  PrintNode (s, leftNode, indent+2);
+  PrintIndentText (s, "OR\n", indent);
+  PrintIndentText (s, "rightNode:\n", indent);
+  PrintNode (s, rightNode, indent+2);
+}
+
+
+
+NotQueryNode::NotQueryNode () {
+  queryNode = NULL;
+  notNode = NULL;
+}
+
+NotQueryNode::~NotQueryNode () {
+  Free ();
+}
+
+void NotQueryNode::Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+			      QueryResult &result) const {
+  result.Clear();
+
+  // check for nothing
+  if (queryNode == NULL) return;
+  if (notNode == NULL) {
+    queryNode->Calculate (indexData, queryInfo, result);
+    return;
+  }
+  
+  // calculate the result from the query tree and the result
+  // from the not tree
+  QueryResult notResult;
+  queryNode->Calculate (indexData, queryInfo, result);
+  notNode->Calculate (indexData, queryInfo, notResult);
+
+  // merge the results, this can be done in place as the results
+  // will always shrink with a Not
+
+  bool haveAccum = (queryInfo.sortByRank || queryInfo.needRankInfo);
+  if (haveAccum && (result.ranks.size() != result.docs.size() ||
+		    notResult.ranks.size() != notResult.docs.size())) {
+    // shouldn't ever get here
+    haveAccum = false;
+    assert (0);
+  }
+
+  // combine document numbers and corresponding ranks
+  unsigned long queryI = 0;
+  unsigned long notI = 0;
+  unsigned long outI = 0;
+  while (queryI < result.docs.size() &&
+	 notI < notResult.docs.size()) {
+    if (result.docs[queryI] < notResult.docs[notI]) {
+      // found a document not in the notResults
+      result.docs[outI] = result.docs[queryI];
+      if (haveAccum)
+	result.ranks[outI] = result.ranks[queryI];
+      ++queryI;
+      ++outI;
+    } else if (result.docs[queryI] > notResult.docs[notI]) {
+      ++notI;
+    } else {
+      // the documents are equal, ignore both
+      ++queryI;
+      ++notI;
+    }
+  }
+
+  // erase unused document numbers and ranks
+  result.docs.erase(result.docs.begin()+outI, result.docs.end());
+  if (haveAccum)
+    result.ranks.erase(result.ranks.begin()+outI, result.ranks.end());
+  
+  // combine term frequency information
+  if (queryInfo.needTermFreqs)
+    result.termFreqs.insert (result.termFreqs.end(),
+			     notResult.termFreqs.begin(),
+			     notResult.termFreqs.end());
+}
+
+void NotQueryNode::Free () {
+  if (queryNode != NULL) {
+    delete queryNode;
+    queryNode = NULL;
+  }
+  if (notNode != NULL) {
+    delete notNode;
+    notNode = NULL;
+  }
+}
+
+void NotQueryNode::Print (ostream &s, int indent) const {
+  PrintIndentText (s, "queryNode:\n", indent);
+  PrintNode (s, queryNode, indent+2);
+  PrintIndentText (s, "NOT\n", indent);
+  PrintIndentText (s, "notNode:\n", indent);
+  PrintNode (s, notNode, indent+2);
+}
+
+
+void TagNode::Clear () {
+  UCArrayClear (tagName);
+}
+
+void TagNode::Calculate (IndexData &indexData,
+			 FragRangeArray &fragRange) const {
+  fragRange.erase (fragRange.begin(), fragRange.end());
+  if (tagName.empty()) return;
+
+  // get information about this tag
+  block_dict_el tagEl;
+  unsigned long tagElNum;
+  if (!SearchBlockDictEl (indexData.dictFile, indexData.biTags,
+			  indexData.bdh.entries_per_tblk,
+			  indexData.bdh.tag_dict_size,
+			  tagName, tagEl, tagElNum))
+    return;
+
+  // seek to the appropriate place in the inverted file
+  fseek (indexData.invfFile, tagEl.invf_ptr, SEEK_SET);
+
+  stdio_bitio_buffer buffer(indexData.invfFile);
+  
+  unsigned long pTag = tagEl.frag_occur*2;
+  unsigned long B = BIO_Bblock_Init (indexData.bdh.num_frags+pTag, pTag);
+  unsigned long fragNum = 0;
+  unsigned long i;
+  FragRange thisFrag;
+  for (i=0; i<tagEl.frag_occur; ++i) {
+    // get start
+    unsigned long delta = buffer.bblock_decode (B, NULL)-1;
+    fragNum += delta;
+
+    thisFrag.rangeStart = fragNum;
+
+    // get end
+    delta = buffer.bblock_decode (B, NULL)-1;
+    fragNum += delta;
+
+    thisFrag.rangeEnd = fragNum;
+    fragRange.push_back (thisFrag);
+  }
+
+  buffer.done();
+}
+
+void TagNode::Free () {
+  Clear ();
+}
+
+void TagNode::Print (ostream &s, int indent) const {
+  PrintIndent (s, indent);
+  s << "TAG: \"" << tagName << "\"\n";
+}
+
+
+void TermNode::Clear () {
+  UCArrayClear (term);
+  termWeight = 1;
+  stemMethod = 0;
+  startRange = NO_TERM_RANGE_START;
+  endRange = NO_TERM_RANGE_END;
+}
+
+TermNode::TermNode () {
+  Clear ();
+}
+
+void TermNode::Calculate (IndexData &indexData,
+			  bool needFragFreqs,
+			  FragRangeArray *fragLimits,
+			  FragData &fragData,
+			  UCArrayVector &equivTerms) const {
+  fragData.Clear ();
+  equivTerms.erase(equivTerms.begin(), equivTerms.end());
+
+  // get a list of term numbers
+  vector<unsigned long> equivNums;
+  FindWordNumbers (indexData, term, stemMethod, equivNums);
+
+  // get the information for each word and merge it with
+  // previous results
+  FragData tempFragData1;
+  FragData tempFragData2;
+  UCArray equivWord;
+  vector<unsigned long>::iterator here = equivNums.begin();
+  vector<unsigned long>::iterator end = equivNums.end();
+  while (here != end) {
+    // get the information for this word
+    ReadTermFragData (indexData, needFragFreqs, *here,
+		      tempFragData1, fragLimits, equivWord);
+    equivTerms.push_back(equivWord);
+    // combine with last results
+    tempFragData2 = fragData;
+    CombineFragData (needFragFreqs, tempFragData1, tempFragData2, fragData);
+    
+    ++here;
+  }
+}
+
+void TermNode::Free () {
+  Clear ();
+}
+
+void TermNode::Print (ostream &s, int indent) const {
+  PrintIndent (s, indent);
+  s << "TERM: \"" << term << "\"\n";
+  PrintIndent (s, indent+2);
+  s << "termWeight: " << termWeight << "\n";
+  PrintIndent (s, indent+2);
+  s << "stemMethod: " << stemMethod << "\n";
+  PrintIndent (s, indent+2);
+  s << "startRange: " << startRange << "\n";
+  PrintIndent (s, indent+2);
+  s << "endRange: " << endRange << "\n";
+}
+
+
+ProxMatchQueryNode::ProxMatchQueryNode () {
+  tagNodePtr = NULL;
+}
+
+ProxMatchQueryNode::~ProxMatchQueryNode () {
+  Free ();
+}
+
+void ProxMatchQueryNode::Calculate (IndexData &indexData,
+				    const QueryInfo &queryInfo,
+				    QueryResult &result) const {
+  result.Clear ();
+
+  bool needFragFreqs = (queryInfo.sortByRank || queryInfo.needRankInfo);
+
+  // read in the tag if needed
+  FragRangeArray fragLimits;
+  FragRangeArray *fragLimitsPtr = NULL;
+  if (tagNodePtr == NULL && terms.size() > 1) {
+    // multiple terms must be compared relative to some tag
+    // otherwise phrase matches could span documents
+    TagNode tempTagNode;
+    tempTagNode.tagName = indexData.curLevel;
+    tempTagNode.Calculate (indexData, fragLimits);
+    fragLimitsPtr = &fragLimits;
+    
+  } else if (tagNodePtr != NULL) {
+    (*tagNodePtr).Calculate (indexData, fragLimits);
+    fragLimitsPtr = &fragLimits;
+  }
+
+  UCArray tagOrLevel = indexData.curLevel;
+  if (tagNodePtr != NULL) tagOrLevel = (*tagNodePtr).tagName;
+
+  // read in the first term
+  FragData termData;
+  UCArrayVector equivTerms;
+  TermNodeArray::const_iterator termHere=terms.begin(), termEnd = terms.end();
+  if (termHere != termEnd) {
+    (*termHere).Calculate (indexData, needFragFreqs, fragLimitsPtr, 
+			   termData, equivTerms);
+
+    // convert initial fragment information
+    FragsToQueryResult (indexData,
+			queryInfo,
+			termData,
+			tagOrLevel,
+			(*termHere).term,
+			(*termHere).stemMethod,
+			(*termHere).termWeight,
+			equivTerms,
+			result);
+  
+    ++termHere;
+
+    if (termHere == termEnd) return; // nothing more to do
+  }
+
+  // read and combine the rest of the terms
+  FragData comTermData;
+  while (termHere != termEnd) {
+    (*termHere).Calculate (indexData, needFragFreqs,
+			   fragLimitsPtr, comTermData, equivTerms);
+
+    AndFragsToQueryResult (indexData,
+			   queryInfo,
+			   comTermData,
+			   tagOrLevel,
+			   (*termHere).term,
+			   (*termHere).stemMethod,
+			   (*termHere).termWeight,
+			   equivTerms,
+			   result);
+    
+    AndCombineFragData (needFragFreqs, termData, comTermData,
+			(*termHere).startRange,
+			(*termHere).endRange,
+			fragLimitsPtr);
+    ++termHere;
+  }
+
+  // remove unwanted document numbers
+  RemoveUnwantedResults (indexData,
+			 queryInfo,
+			 termData,
+			 result);
+}
+
+void ProxMatchQueryNode::Free () {
+  if (tagNodePtr != NULL) {
+    delete tagNodePtr;
+    tagNodePtr = NULL;
+  }
+  terms.erase (terms.begin(), terms.end());
+}
+
+void ProxMatchQueryNode::Print (ostream &s, int indent) const {
+  PrintIndentText (s, "PROXMATCH\n", indent);
+  if (tagNodePtr != NULL) tagNodePtr->Print (s, indent+2);
+  
+  TermNodeArray::const_iterator here = terms.begin();
+  TermNodeArray::const_iterator end = terms.end();
+  while (here != end) {
+    (*here).Print (s, indent+2);
+    ++here;
+  }
+}
+
+
+void BrowseQueryNode::Clear () {
+  UCArrayClear(term);
+}
+
+void BrowseQueryNode::Calculate (IndexData &indexData, BrowseQueryResult &result) const {
+
+  unsigned long number=0;
+  FindNearestWordNumber(indexData, term, number);
+  if (number + startPosition > 0 ) {
+    number = number+startPosition;
+  }
+  else {
+    number = 1;
+  }
+
+  GetTermList (indexData, number, numTerms, result.termFreqs);
+
+}
+
+
+
+void BrowseQueryNode::Free () {
+  Clear();
+}
+
+
+void BrowseQueryNode::Print (ostream &s, int indent) const {
+  PrintIndentText(s, "BROWSEQUERYNODE\n", indent);
+  PrintIndent (s, indent+2);
+  s << "TERM:"<<term<<"\n";
+  PrintIndent (s, indent+2);
+  s << "Start position: "<< startPosition<<", Num terms: "<< numTerms<<"\n";
+
+
+}
+
+
+
+void MGQuery (IndexData &indexData,
+	      const QueryInfo &queryInfo,
+	      const QueryNode *queryTree,
+	      QueryResult &result) {
+  result.Clear ();
+
+  // make sure level is current
+  if (!indexData.LoadLevel (queryInfo.docLevel)) {
+    return;
+  }
+  // do query
+  if (queryTree == NULL) return;
+  
+  (*queryTree).Calculate (indexData, queryInfo, result);
+
+  // make weights into ranks if needed
+  unsigned long i;
+  if (queryInfo.sortByRank || queryInfo.needRankInfo) {
+    for (i=0; i<result.ranks.size(); ++i) {
+      result.ranks[i] /=
+	indexData.weightData.GetLowerApproxDocWeight (result.docs[i]);
+    }
+  }
+  
+  unsigned long resultsSize = queryInfo.maxDocs;
+  if (resultsSize == 0 || resultsSize > result.docs.size())
+    resultsSize = result.docs.size();
+
+  result.actualNumDocs = result.docs.size(); // the total number of docs 
+                                   //returned, before pruning based on maxDocs
+
+  // sort results by rank if needed
+  GTRank gtRank;
+  if (queryInfo.sortByRank) {
+    // need in ascending order for SelectAddHeap
+    MakeHeap (result.docs.begin(), result.ranks.begin(),
+	      resultsSize, gtRank);
+    SelectAddHeap (result.docs.begin(), result.ranks.begin(), resultsSize,
+		   result.docs.begin()+resultsSize,
+		   result.ranks.begin()+resultsSize,
+		   (unsigned long) result.ranks.size()-resultsSize,
+		   gtRank);
+
+    // sort into descending order
+    SortHeap (result.docs.begin(), result.ranks.begin(), resultsSize, gtRank);
+  }
+  
+  // get exact weights if needed
+  if (queryInfo.exactWeights &&
+      (queryInfo.sortByRank || queryInfo.needRankInfo)) {
+    unsigned long exactDiskPtr =
+      indexData.levels.levelInfo[indexData.curLevel].exactWeightsDiskPtr;
+    
+    for (i=0; i<resultsSize; ++i) {
+      result.ranks[i] =  result.ranks[i] *
+	indexData.weightData.GetLowerApproxDocWeight (result.docs[i]) /
+	GetExactDocWeight (indexData.exactWeightsFile, exactDiskPtr,
+			   result.docs[i]);
+    }
+
+    // re-sort top candidates based on exact weights
+    if (queryInfo.sortByRank) {
+      MakeHeap (result.docs.begin(), result.ranks.begin(),
+		resultsSize, gtRank);
+      SortHeap (result.docs.begin(), result.ranks.begin(),
+		resultsSize, gtRank);
+    }
+  }
+
+  // get rid of unwanted ranking results
+  if (result.ranks.empty()) {
+    // do nothing
+  } else if (!queryInfo.needRankInfo) {
+    result.ranks.erase(result.ranks.begin(), result.ranks.end());
+  } else {
+    result.ranks.erase(result.ranks.begin()+resultsSize, result.ranks.end());
+  }
+
+  // remove extra docs that are unwanted
+  result.docs.erase(result.docs.begin()+resultsSize, result.docs.end());
+}
+
+// new MGQuery to retrieve doc and section nums
+// this will return doc nums for the level queried at (set in queryInfo)
+// in QueryResult.docs and if a second level is specified, 
+// it will return corresponding docnums for that level in QueryResult.levels
+// If there is no level specified, or that level is invalid, the query
+// level is used
+void MGQuery (IndexData &indexData,
+	      const QueryInfo &queryInfo,
+	      const QueryNode *queryTree,
+	      ExtQueryResult &realresult, UCArray &level) {
+  realresult.Clear ();
+  QueryResult result; // temp result
+
+  // do the normal query
+  MGQuery (indexData, queryInfo, queryTree, result);
+
+  // now that have the final result stuff, convert to ExtQueryResult,
+  // add in level nums if needed
+
+  realresult.docs = result.docs;
+  realresult.ranks = result.ranks;
+  realresult.termFreqs = result.termFreqs;
+  realresult.actualNumDocs = result.actualNumDocs;
+
+  if (queryInfo.docLevel == level || level.empty()) {
+    realresult.levels = result.docs;
+    return;
+  }
+
+  // else need to convert from queryInfo.docLevel to level
+
+  // the original level info
+  FragLevelConvert sectionLevelConverter = indexData.levelConverter;
+
+  // the new level info
+  if (!indexData.LoadLevel(level)) {
+    realresult.levels = result.docs;
+    return;
+  }
+  
+  unsigned long DocNum = 0;
+  
+  for (unsigned long i=0; i<realresult.docs.size(); ++i) {
+
+    // do an if ! here????
+    indexData.levelConverter.LevelToLevel(sectionLevelConverter, realresult.docs[i], DocNum);
+    realresult.levels.push_back(DocNum);
+  }
+  
+}
+
+
+
+// new function for full text browsing, 
+void MGBrowseQuery (IndexData &indexData, UCArray &level,
+		  const BrowseQueryNode &node,
+		  BrowseQueryResult &result) {
+
+  indexData.LoadLevel(level);
+  node.Calculate(indexData, result); 
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/MGQuery.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/MGQuery.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/MGQuery.h	(revision 10506)
@@ -0,0 +1,197 @@
+/**************************************************************************
+ *
+ * MGQuery.h -- Query related functions
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef MGQUERY_H
+#define MGQUERY_H
+
+#include "IndexData.h"
+#include <limits.h>
+#include "Terms.h"
+
+// forms base for defining and calculating the boolean
+// part of a query
+class QueryNode {
+public:
+  QueryNode ();
+  virtual ~QueryNode ();
+
+  virtual void Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+			  QueryResult &result) const;
+  virtual void Free ();
+  virtual void Print (ostream &s, int indent=0) const;
+};
+
+
+
+void PrintIndent (ostream &s, int indent);
+void PrintIndentText (ostream &s, char *text, int indent);
+void PrintNode (ostream &s, QueryNode *node, int indent=0);
+
+
+
+// basic boolean nodes
+
+class AndQueryNode : public QueryNode {
+public:
+  QueryNode *leftNode;
+  QueryNode *rightNode;
+  
+  AndQueryNode ();
+  ~AndQueryNode ();
+
+  void Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+		  QueryResult &result) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+class OrQueryNode : public QueryNode {
+public:
+  QueryNode *leftNode;
+  QueryNode *rightNode;
+  
+  OrQueryNode ();
+  ~OrQueryNode ();
+
+  void Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+		  QueryResult &result) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+class NotQueryNode : public QueryNode {
+public:
+  QueryNode *queryNode;
+  QueryNode *notNode;
+  
+  NotQueryNode ();
+  ~NotQueryNode ();
+
+  void Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+		  QueryResult &result) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+
+
+class TagNode {
+public:
+  UCArray tagName;
+
+  void Clear ();
+  TagNode () { Clear (); }
+
+  void Calculate (IndexData &indexData, FragRangeArray &fragRange) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+
+#define NO_TERM_RANGE_START (LONG_MIN/2)
+#define NO_TERM_RANGE_END   (LONG_MAX/2)
+
+/* NOTE: range stuff - the range values are for the previous term relative
+to the current term. So if searching for the phrase "the cat", 'the' doesn't 
+need range limits, but 'cat' has a range of -2 to -1. ie, if have found 'cat'
+then 'the' has to be at position between -2 and -1 relative to 'cat'.
+"the cat" could also be searched for by 'cat' with no range limits, then 'the' with range 0 to 1.
+range values are relative to the gaps between words:
+   x   y   z   X   a   b   c
+    -3   -2  -1  0   1   2   3
+
+ */
+class TermNode {
+public:
+  UCArray term;
+  unsigned long termWeight;
+  unsigned long stemMethod;
+  signed long startRange; // range relative to last term
+  signed long endRange;
+  
+  void Clear ();
+  TermNode ();
+
+  // fragLimits can be NULL if not neede
+  void Calculate (IndexData &indexData,
+		  bool needFragFreqs,
+		  FragRangeArray *fragLimits,
+		  FragData &fragData,
+		  UCArrayVector &equivTerms) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+typedef vector<TermNode> TermNodeArray;
+
+
+class ProxMatchQueryNode : public QueryNode {
+public:
+  TagNode *tagNodePtr; // optional field
+  TermNodeArray terms;
+  
+  ProxMatchQueryNode ();
+  ~ProxMatchQueryNode ();
+
+  void Calculate (IndexData &indexData, const QueryInfo &queryInfo,
+		  QueryResult &result) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+};
+
+class BrowseQueryNode :public QueryNode {
+ public:
+  UCArray term;
+  signed long startPosition;
+  unsigned long numTerms;
+
+  void Clear();
+  BrowseQueryNode () { Clear(); }
+  //  ~BrowseQueryNode ();
+
+  void Calculate (IndexData &indexData, BrowseQueryResult &result) const;
+  void Free ();
+  void Print (ostream &s, int indent=0) const;
+
+
+
+
+};
+
+void MGQuery (IndexData &indexData,
+	      const QueryInfo &queryInfo,
+	      const QueryNode *queryTree,
+	      QueryResult &result);
+
+// this function for retrieving results with both section doc nums
+// and Document docnums
+void MGQuery (IndexData &indexData,
+	      const QueryInfo &queryInfo,
+	      const QueryNode *queryTree,
+	      ExtQueryResult &result, UCArray &level);
+
+
+// new function for full text browsing, 
+void MGBrowseQuery (IndexData &indexData, UCArray &level,
+		  const BrowseQueryNode &node,
+		  BrowseQueryResult &result);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Makefile.in	(revision 10506)
@@ -0,0 +1,316 @@
+###########################################################################
+#
+# Makefile.in -- Makefile for the MG system
+# Copyright (C) 1994  Neil Sharman;  1995 Tim Shimmin
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)Makefile.in	1.10 22 Mar 1994
+#
+###########################################################################
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+SHELL = /bin/sh
+VPATH = @srcdir@
+exec_prefix = @exec_prefix@
+prefix = @prefix@
+srcdir = @srcdir@
+subdir = text
+top_srcdir = @top_srcdir@
+transform = @program_transform_name@
+
+AR = ar
+CC = @CC@
+CXX = @CXX@
+CFLAGS = @CFLAGS@ -ansi -DSILENT -DSHORT_SUFFIX
+CXXFLAGS = @CXXFLAGS@ -DSILENT -DSHORT_SUFFIX
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBS = ../lib/libmg.a -lstdc++ @LIBS@
+TOUCH = echo timestamp >
+AWK = @AWK@
+
+##########################################
+# George Buchanan - August 1999
+# 
+# compiling with make NZDL=1 to ensure that 
+# the NZDL compile mode is used - this has been changed to the default - kjm18
+#
+##########################################
+GSDLOS = @gsdlos@
+
+bindir = $(top_srcdir)/bin/$(GSDLOS)
+datadir = $(prefix)/share
+libexecdir = $(exec_prefix)/libexec
+localedir = $(datadir)/locale
+mandir = $(prefix)/man/man1
+
+COMPILE = $(CC) -c $(DEFS) $(TREC_MODE) $(READLINE) $(INCLUDES) $(CFLAGS)
+CXXCOMPILE = $(CXX) -c $(DEFS) $(TREC_MODE) $(READLINE) $(INCLUDES) $(CXXFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CXXCOMPILE) $<
+
+
+ANSI2KNR = @ANSI2KNR@
+o = .@U@o
+
+.SUFFIXES: ._c ._o
+.c._c:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $@
+._c._o:
+	@echo $(COMPILE) $<
+	@rm -f _$*.c
+	@ln $< _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+.c._o:
+	./ansi2knr $< > $*.tmp && mv $*.tmp $*._c
+	@echo $(COMPILE) $*._c
+	@rm -f _$*.c
+	@ln $*._c _$*.c && $(COMPILE) _$*.c && mv _$*.o $@ && rm _$*.c
+
+# want toplevel config.h, not local mg one
+INCLUDES = -I../../.. -I../lib -I.
+
+#############################################################################
+#
+# Uncomment (and possibly edit) the following lines if you wish
+# to use the GNU readline library for the input in mgquery
+# 
+#READLINE = -DGNU_READLINE -I/opt/gnu/include/readline -L/opt/gnu/lib
+#READLINE_LIBS = -lreadline -ltermcap
+#
+#
+#############################################################################
+
+SOURCES = \
+  FIvfLevelInfo.cpp        ivf.pass1.cpp            mgpp_invf_dump.cpp       \
+  FText.cpp                ivf.pass2.cpp            mgpp_passes.cpp          \
+  FileBuf.cpp              locallib.cpp             mgpp_perf_hash_build.cpp \
+  FragLevelConvert.cpp     mg.special.cpp           mgpp_stem_idx.cpp        \
+  IndexData.cpp            mgpp_compression_dict.cpp  mgpp_weights_build.cpp   \
+  TagInfo.cpp              mgpp_decompress_text.cpp   stemmer.cpp            \
+  TextEl.cpp               mg_errors.cpp            text.cpp               \
+  TextGet.cpp              mgpp_fast_comp_dict.cpp    text.pass1.cpp         \
+  UCArray.cpp              mg_files.cpp             text.pass2.cpp         \
+  comp_dict.cpp            mgpp_invf_dict.cpp         words.cpp              \
+  invf.cpp                 mgpp_invf_dict_dump.cpp    Weights.cpp            \
+  MGQuery.cpp              Terms.cpp                QueryTester.cpp        \
+  QueryLex.cpp             QueryParser.cpp         \
+  GSDLQueryLex.cpp	   GSDLQueryParser.cpp      Queryer.cpp
+
+
+HEADERS = \
+  FIvfLevelInfo.h     TextEl.h            hash.h              stemmer.h  \
+  FText.h             TextGet.h           invf.h              text.h     \
+  FileBuf.h           UCArray.h           locallib.h          words.h    \
+  FragLevelConvert.h  WordData.h          mg.h                           \
+  IndexData.h         build.h             mg_errors.h                    \
+  TagInfo.h           comp_dict.h         mg_files.h          Weights.h  \
+  MGQuery.h           Terms.h             QueryLex.h          QueryParser.h \
+  GSDLQueryLex.h	GSDLQueryParser.h
+
+
+MISC          = Makefile.in 
+
+ALLFILES      =	$(SOURCES) $(HEADERS) $(MISC) $(MAN)
+
+DISTFILES     = $(ALLFILES) 
+
+EXEC          = mgpp_passes mgpp_decompress_text mgpp_perf_hash_build \
+                mgpp_invf_dump mgpp_weights_build mgpp_invf_dict mgpp_stem_idx \
+                mgpp_invf_dict_dump mgpp_compression_dict mgpp_fast_comp_dict \
+                QueryTester Queryer
+
+MAN           =  mgpp_weights_build.1  mgpp_invf_dict.1 \
+                 mgpp_passes.1 mgpp_perf_hash_build.1 \
+                 mgpp_compression_dict.1  mgpp_fast_comp_dict.1 \
+                 mgpp_stem_idx.1
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+all:	$(EXEC) libtextin.a
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CXXFLAGS) $(CFLAGS) -- $(SOURCES)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+
+PASSES_OBJS = \
+	mgpp_passes$o text.pass1$o comp_dict$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o \
+	words$o invf$o FileBuf$o TextEl$o UCArray$o TagInfo$o \
+        FText$o text$o FIvfLevelInfo$o
+
+mgpp_passes: $(PASSES_OBJS)
+	$(LINK) $(PASSES_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+QUERYER_OBJS = Queryer$o mg_files$o mg_errors$o locallib$o invf$o UCArray$o \
+               FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+               IndexData$o stemmer$o Weights$o TextGet$o text$o FText$o \
+               GSDLQueryParser$o GSDLQueryLex$o words$o
+
+Queryer: $(QUERYER_OBJS)
+	$(LINK) $(QUERYER_OBJS) $(LIBS)
+
+QUERY_TESTER_OBJS = QueryTester$o mg_files$o invf$o UCArray$o \
+                    FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+                    IndexData$o stemmer$o Weights$o
+
+QueryTester: $(QUERY_TESTER_OBJS)
+	$(LINK) $(QUERY_TESTER_OBJS) $(LIBS)
+
+WEIGHTS_BUILD_OBJS = mgpp_weights_build$o mg_files$o invf$o UCArray$o \
+                     FIvfLevelInfo$o FragLevelConvert$o
+
+mgpp_weights_build: $(WEIGHTS_BUILD_OBJS)
+	$(LINK) $(WEIGHTS_BUILD_OBJS) $(LIBS)
+
+COMP_DICT_OBJS = mgpp_compression_dict$o mg_files$o locallib$o
+
+mgpp_compression_dict: $(COMP_DICT_OBJS)
+	$(LINK) $(COMP_DICT_OBJS) $(LIBS)
+
+FAST_COMP_OBJS = mgpp_fast_comp_dict$o mg_files$o locallib$o
+
+mgpp_fast_comp_dict: $(FAST_COMP_OBJS)
+	$(LINK) $(FAST_COMP_OBJS) $(LIBS)
+
+INVF_DUMP_OBJS = mgpp_invf_dump$o locallib$o mg_files$o invf$o UCArray$o
+
+mgpp_invf_dump: $(INVF_DUMP_OBJS)
+	$(LINK) $(INVF_DUMP_OBJS) $(LIBS)
+
+INVF_DICT_OBJS = mgpp_invf_dict$o mg_files$o invf$o UCArray$o
+
+mgpp_invf_dict: $(INVF_DICT_OBJS)
+	$(LINK) $(INVF_DICT_OBJS) $(LIBS)
+
+INVF_DICT_DUMP_OBJS = mgpp_invf_dict_dump$o mg_files$o invf$o UCArray$o
+
+mgpp_invf_dict_dump: $(INVF_DICT_DUMP_OBJS)
+	$(LINK) $(INVF_DICT_DUMP_OBJS) $(LIBS)
+
+PERF_HASH_OBJS = mgpp_perf_hash_build$o mg_files$o invf$o UCArray$o
+
+mgpp_perf_hash_build: $(PERF_HASH_OBJS)
+	$(LINK) $(PERF_HASH_OBJS) $(LIBS)
+
+STEM_IDX_OBJS = mgpp_stem_idx$o mg_files$o stemmer$o \
+                invf$o UCArray$o
+
+mgpp_stem_idx: $(STEM_IDX_OBJS)
+	$(LINK) $(STEM_IDX_OBJS) $(LIBS)
+
+DECOMPRESS_TEXT_OBJS = \
+                mgpp_decompress_text$o mg_files$o mg_errors$o \
+                locallib$o text$o UCArray$o TextGet$o FText$o
+
+mgpp_decompress_text: $(DECOMPRESS_TEXT_OBJS)
+	$(LINK) $(DECOMPRESS_TEXT_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+ansi2knr: ansi2knr.o
+	$(LINK) ansi2knr.o $(LIBS)
+
+install: execinstall
+uninstall: execuninstall
+
+execinstall: $(EXEC)
+	for name in $(EXEC); do \
+	  $(INSTALL_PROGRAM) $$name \
+	  $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+execuninstall:
+	for name in $(EXEC); do \
+	 rm -f $(bindir)/`echo $$name | sed '$(transform)'`; \
+	done
+
+maninstall: $(MAN)
+	$(top_srcdir)/mkinstalldirs $(mandir); \
+	for f in $(MAN); do \
+	  $(INSTALL_DATA) $$f $(mandir)/$$f ;\
+	done
+
+manuninstall: $(MAN)
+	for f in $(MAN); do \
+	  rm -f $(mandir)/$$f ;\
+	done
+
+#mg_errors$o removed from LIB_OBJS to avoid conflict with mg's libtextin.a
+LIB_OBJS = mg_files$o  mg_errors$o locallib$o invf$o UCArray$o \
+           FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+           IndexData$o stemmer$o Weights$o TextGet$o text$o FText$o \
+           GSDLQueryParser$o GSDLQueryLex$o words$o
+
+libtextin.a: $(LIB_OBJS)
+	rm -f libtextin.a
+	$(AR) cru libtextin.a $(LIB_OBJS)
+	$(RANLIB) libtextin.a
+
+
+mostlyclean:
+	rm -f *$o _*.c _*.o *._c *._o core core.*
+
+clean: mostlyclean
+	rm -f $(EXEC) libtextin.a
+
+distclean: clean
+	rm -f ansi2knr
+	rm -f Makefile
+
+maintainer-clean: distclean
+	@echo "This command is intended only for maintainers to use;"
+	@echo "rebuilding the deleted files may require special tools."
+
+dist: $(DISTFILES)
+	for file in $(DISTFILES); do \
+	  ln $(srcdir)/$$file $(distdir) 2> /dev/null \
+	  || cp -p $(srcdir)/$$file $(distdir); \
+	done
+
+movclean:
+	for file in $(SOURCES); do \
+          test = $$file; \
+          echo $("test.c"##*.c); \
+        done 
+
+# jrm21
+#Makefile: Makefile.in ../../../config.status
+#	cd ../../.. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exc
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryLex.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryLex.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryLex.cpp	(revision 10506)
@@ -0,0 +1,175 @@
+/**************************************************************************
+ *
+ * QueryLex.cpp -- Lexical analyser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "QueryLex.h"
+#include "unitool.h"
+#include "words.h"
+
+inline void AddNChar (UCArray::const_iterator &here,
+		      UCArray &text,
+		      int len) {
+  if (text.capacity() < text.size() + len + 1) {
+    text.reserve(text.size + len + 1);
+  }
+  while (len > 0) {
+    text.push_back (*here++);
+    --len;
+  }
+}
+
+static bool ParseInteger (UCArray::const_iterator &here,
+			  UCArray::const_iterator end,
+			  LexEl &el) {
+  el.Clear();
+
+  // this version of end is used in unitool
+  UCArray::const_iterator endMinus1 = end-1;
+
+  int charLen;
+  unsigned short c; // one character lookahead
+  charLen = parse_utf8_char (here, endMinus1, &c);
+
+  // check for positive or negative
+  bool neg = false;
+  if (c == '+') {
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  } else if (c == '-') {
+    neg = true;
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  }
+
+  // read in number part
+  el.num = 0;
+  el.lexType = IntegerE;
+  while (c >= '0' && c <= '9') {
+    el.num = el.num*10 + c - '0';
+    AddNChar (here, el.text, charLen);
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  }
+
+  if (neg) el.num *= -1;
+
+  return (!el.text.empty());
+}
+
+static bool ParseTerm (UCArray::const_iterator &here,
+		       UCArray::const_iterator end,
+		       UCArray &text) {
+  UCArray::const_iterator endMinus1 = end-1;
+  here = ParseIndexWord (here, endMinus1, text);
+  return !text.empty();
+}
+
+
+bool ParseLexEl (UCArray::const_iterator &here,
+		 UCArray::const_iterator end,
+		 LexEl &el) {
+  el.Clear();
+
+  // strange things can happen if here == end == 0
+  if (here == end) return false;
+  
+  // this version of end is used in unitool
+  UCArray::const_iterator endMinus1 = end-1;
+  
+  // ignore all white space
+  int charLen;
+  unsigned short c; // one character lookahead
+  charLen = parse_utf8_char (here, endMinus1, &c);
+  while (here != end && is_unicode_space (c)) {
+    here += charLen;
+    charLen = parse_utf8_char (here, endMinus1, &c);
+  }
+  if (here == end) return false;
+
+  if (c == '(') {
+    el.lexType = OpenBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == ')') {
+    el.lexType = CloseBracketE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '\"') {
+    el.lexType = QuoteE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '#') {
+    el.lexType = TermWeightE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '$') {
+    el.lexType = StemMethodE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '^') {
+    el.lexType = RangeE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '@') {
+    el.lexType = AtE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == ':') {
+    el.lexType = TagE;
+    AddNChar (here, el.text, charLen);
+    return true;
+    
+  } else if (c == '+' || c == '-' ||
+	     (c >= '0' && c <= '9')) {
+    return ParseInteger (here, end, el);
+  }
+
+  // assume it is a term of some sort
+  if (!ParseTerm (here, end, el.text)) return false;
+
+  //UCArray AND; SetCStr (AND, "AND");
+  //if (el.text == AND) {
+  if (UCArrayCStrEquals(el.text, "AND")) {  
+    el.lexType = AndOpE;
+    return true;
+  }
+  //UCArray OR; SetCStr (OR, "OR");
+  //if (el.text == OR) {
+  if (UCArrayCStrEquals(el.text, "OR")) {
+    el.lexType = OrOpE;
+    return true;
+  }
+  //UCArray NOT; SetCStr (NOT, "NOT");
+  //if (el.text == NOT) {
+  if (UCArrayCStrEquals(el.text, "NOT")) {
+    el.lexType = NotOpE;
+    return true;
+  }
+
+  el.lexType = TermE;
+  return true;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryLex.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryLex.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryLex.h	(revision 10506)
@@ -0,0 +1,53 @@
+/**************************************************************************
+ *
+ * QueryLex.h -- Lexical analyser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef QUERYLEX_H
+#define QUERYLEX_H
+
+#include "UCArray.h"
+
+
+// note: white space is ignored
+enum LexType {NoTypeE, OpenBracketE, CloseBracketE, TermE, AndOpE, OrOpE,
+	      NotOpE, QuoteE, IntegerE, TermWeightE, StemMethodE,
+	      RangeE, AtE, TagE};
+
+struct LexEl {
+  LexType lexType;
+  UCArray text;
+  int num; // for IntegerE
+
+  void Clear () {
+    lexType = NoTypeE;
+    UCArrayClear (text);
+    num = 0;
+  }
+  LexEl () { Clear (); }
+};
+
+
+// returns true if another lexical element could be parsed.
+bool ParseLexEl (UCArray::const_iterator &here,
+		 UCArray::const_iterator end,
+		 LexEl &el);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryParser.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryParser.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryParser.cpp	(revision 10506)
@@ -0,0 +1,219 @@
+/**************************************************************************
+ *
+ * QueryParser.cpp -- Query parser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "QueryParser.h"
+#include "QueryLex.h"
+
+
+static QueryNode *ParseExpression (UCArray::const_iterator &here,
+				   UCArray::const_iterator end);
+
+static QueryNode *AndAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  AndQueryNode *andNode = new AndQueryNode;
+  andNode->leftNode = t1;
+  andNode->rightNode = t2;
+  return andNode;
+}
+
+static QueryNode *OrAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  OrQueryNode *orNode = new OrQueryNode;
+  orNode->leftNode = t1;
+  orNode->rightNode = t2;
+  return orNode;
+}
+
+static QueryNode *NotAdd (QueryNode *t1, QueryNode *t2) {
+  if (t1 == NULL) return t2;
+  if (t2 == NULL) return t1;
+
+  NotQueryNode *notNode = new NotQueryNode;
+  notNode->queryNode = t1;
+  notNode->notNode = t2;
+  return notNode;
+}
+
+// expects the opening bracket to have already been parsed
+// and discarded
+static QueryNode *ParseBracketExpression (UCArray::const_iterator &here,
+					  UCArray::const_iterator end) {
+  // get everything in the expression
+  QueryNode *curTree = ParseExpression (here, end);
+  
+  // gobble up tokens until a closing bracket is found
+  // or the end of the string
+  LexEl el;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == CloseBracketE) break;
+  }
+
+  return curTree;
+}
+
+static int ParseInt (UCArray::const_iterator &here,
+		     UCArray::const_iterator end) {
+  LexEl el;
+  UCArray::const_iterator oldHere = here;
+  if (ParseLexEl (here, end, el) && el.lexType == IntegerE)
+    return el.num;
+  
+  here = oldHere; // not an integer
+  return 0;
+}
+
+
+static void ParseTermModifiers (UCArray::const_iterator &here,
+				UCArray::const_iterator end,
+				TermNode &termNode) {
+  LexEl el;
+  UCArray::const_iterator oldHere = here;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TermWeightE) {
+      termNode.termWeight = ParseInt (here, end);
+      
+    } else if (el.lexType == StemMethodE) {
+      termNode.stemMethod = ParseInt (here, end);
+      
+    } else if (el.lexType == RangeE) {
+      termNode.startRange = ParseInt (here, end);
+      termNode.endRange = ParseInt (here, end);
+      
+    } else if (el.lexType == AtE) {
+      termNode.startRange = termNode.endRange = ParseInt (here, end);
+      
+    } else {
+      // no term modifiers
+      here = oldHere;
+      break;
+    }
+    
+    oldHere = here;
+  }  
+}
+
+// expects the starting quote to have been parsed
+// and discarded
+static void ParsePhrase (UCArray::const_iterator &here,
+			 UCArray::const_iterator end,
+			 ProxMatchQueryNode &proxNode) {
+  LexEl el;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == TermE || el.lexType == IntegerE) {
+      TermNode termNode;
+      termNode.term = el.text;
+      ParseTermModifiers (here, end, termNode);
+      proxNode.terms.push_back (termNode);
+      
+    } else if (el.lexType == QuoteE) {
+      break;
+      
+    } else {
+      // error
+      break;
+    }
+  }
+}
+
+static QueryNode *ParseTerm (UCArray::const_iterator &here,
+			     UCArray::const_iterator end) {
+  LexEl el;
+
+  UCArray::const_iterator oldHere = here;
+  if (!ParseLexEl (here, end, el)) return NULL;
+
+  if (el.lexType == OpenBracketE)
+    return ParseBracketExpression (here, end);
+
+  ProxMatchQueryNode *proxNode = new ProxMatchQueryNode;
+
+  // check for a tag
+  if (el.lexType == TagE) {
+    oldHere = here; // don't backtrack past here
+    if (!ParseLexEl (here, end, el)) return NULL;
+    if (el.lexType == TermE) {
+      proxNode->tagNodePtr = new TagNode;
+      proxNode->tagNodePtr->tagName = el.text;
+      if (!ParseLexEl (here, end, el)) return NULL;
+    }
+  }
+  
+  if (el.lexType == TermE || el.lexType == IntegerE) {
+    TermNode termNode;
+    termNode.term = el.text;
+    ParseTermModifiers (here, end, termNode);
+    proxNode->terms.push_back (termNode);
+    return proxNode;
+    
+  } else if (el.lexType == QuoteE) {
+    ParsePhrase (here, end, *proxNode);
+    return proxNode;
+  }
+
+  // not a term
+  here = oldHere;
+  delete proxNode;
+  return NULL;
+}
+
+
+static QueryNode *ParseExpression (UCArray::const_iterator &here,
+				   UCArray::const_iterator end) {
+  LexEl el;
+  QueryNode *curTree = NULL;
+
+  UCArray::const_iterator oldHere = here;
+  while (ParseLexEl (here, end, el)) {
+    if (el.lexType == OpenBracketE ||
+	el.lexType == TermE ||
+	el.lexType == QuoteE ||
+	el.lexType == IntegerE ||
+	el.lexType == TagE) {
+      // some type of term, back track and parse it
+      here = oldHere;
+      curTree = OrAdd (curTree, ParseTerm (here, end));
+      
+    } else if (el.lexType == AndOpE) {
+      curTree = AndAdd (curTree, ParseTerm (here, end));
+      
+    } else if (el.lexType == OrOpE) {
+      curTree = OrAdd (curTree, ParseTerm (here, end));
+      
+    } else if (el.lexType == NotOpE) {
+      curTree = NotAdd (curTree, ParseTerm (here, end));
+      
+    } else break;
+    
+    oldHere = here;
+  }
+
+  return curTree;
+}
+
+QueryNode *ParseQuery (const UCArray &queryStr) {
+  UCArray::const_iterator here = queryStr.begin();
+  UCArray::const_iterator end = queryStr.end();
+  return ParseExpression (here, end);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryParser.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryParser.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryParser.h	(revision 10506)
@@ -0,0 +1,31 @@
+/**************************************************************************
+ *
+ * QueryParser.h -- Query parser for a simple query language
+ * Copyright (C) 2000  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef QUERYPARSER_H
+#define QUERYPARSER_H
+
+#include "UCArray.h"
+#include "MGQuery.h"
+
+// returns NULL if the query could not be parsed
+QueryNode *ParseQuery (const UCArray &queryStr);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryResultsSort.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryResultsSort.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryResultsSort.h	(revision 10506)
@@ -0,0 +1,140 @@
+/**************************************************************************
+ *
+ * QueryResultsSort.h -- Functions to sort query results and parallel data
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef QUERYRESULTSSORT_H
+#define QUERYRESULTSSORT_H
+
+#include "Terms.h"
+
+
+struct LTRank {
+  bool operator()(const float &f1, const float &f2) const
+    { return (f1 < f2); }
+};
+
+struct GTRank {
+  bool operator()(const float &f1, const float &f2) const
+    { return (f1 > f2); }
+};
+
+
+
+// assumes the rank vector is the same size as the document
+// number vector. assumes the value to be pushed is in
+// docNumHeap + heapSize - 1 and rankHeap + heapSize - 1
+// topIndex can be set
+template <class RandomAccessIterator, class Compare>
+void PushHeap (DocNumArray::iterator docNumHeap,
+	       RandomAccessIterator parallelHeap,
+	       unsigned long heapSize,
+	       const Compare &comp) {
+  unsigned long holeIndex = heapSize-1;
+  unsigned long parent = (holeIndex - 1) / 2;
+  while (holeIndex > 0 && comp (*(parallelHeap+parent),
+				*(parallelHeap+holeIndex))) {
+    swap (*(parallelHeap+holeIndex), *(parallelHeap+parent));
+    swap (*(docNumHeap+holeIndex), *(docNumHeap+parent));
+    holeIndex = parent;
+    parent = (holeIndex - 1) / 2;
+  }
+}
+
+// AdjustHeap is used to add a element to a heap after one
+// element in the heap has been replaced with a new one
+template <class RandomAccessIterator, class Compare>
+void AdjustHeap (DocNumArray::iterator docNumHeap,
+		     RandomAccessIterator parallelHeap,
+		     unsigned long holeIndex,
+		     unsigned long heapSize,
+		     const Compare &comp) {
+  unsigned long secondChild = 2 * holeIndex + 2;
+  while (secondChild < heapSize) {
+    if (comp(*(parallelHeap + secondChild),
+	     *(parallelHeap + (secondChild - 1))))
+      --secondChild;
+    swap (*(parallelHeap+holeIndex), *(parallelHeap+secondChild));
+    swap (*(docNumHeap+holeIndex), *(docNumHeap+secondChild));
+    holeIndex = secondChild;
+    secondChild = 2 * secondChild + 2;
+  }
+  if (secondChild == heapSize) {
+    swap (*(parallelHeap+holeIndex), *(parallelHeap+(secondChild-1)));
+    swap (*(docNumHeap+holeIndex), *(docNumHeap+(secondChild-1)));
+    holeIndex = secondChild - 1;
+  }
+  PushHeap (docNumHeap, parallelHeap, holeIndex+1, comp);
+}
+
+template <class RandomAccessIterator, class Compare>
+void PopHeap (DocNumArray::iterator docNumHeap,
+	      RandomAccessIterator parallelHeap,
+	      unsigned long heapSize,
+	      const Compare &comp) {
+  swap (*(parallelHeap), *(parallelHeap+heapSize-1));
+  swap (*(docNumHeap), *(docNumHeap+heapSize-1));
+  AdjustHeap (docNumHeap, parallelHeap, (unsigned long)0, heapSize-1, comp);
+}
+
+template <class RandomAccessIterator, class Compare>
+void MakeHeap (DocNumArray::iterator docNumHeap,
+	       RandomAccessIterator parallelHeap,
+	       unsigned long size,
+	       const Compare &comp) {
+  if (size < 2) return;
+  
+  unsigned long i = 0;
+  for (i=1; i<=size; ++i)
+    PushHeap (docNumHeap, parallelHeap, i, comp);
+}
+
+ 
+template <class RandomAccessIterator, class Compare>
+void SortHeap (DocNumArray::iterator docNumHeap,
+	       RandomAccessIterator parallelHeap,
+	       unsigned long size,
+	       const Compare &comp) {
+  if (size < 2) return;
+
+  unsigned long i;
+  for (i=size; i>1; --i)
+    PopHeap (docNumHeap, parallelHeap, i, comp);
+}
+
+// uses the heap to get the top "size" elements
+template <class RandomAccessIterator, class Compare>
+void SelectAddHeap (DocNumArray::iterator docNumHeap,
+		    RandomAccessIterator parallelHeap,
+		    unsigned long heapSize,
+		    DocNumArray::iterator docNumAdd,
+		    RandomAccessIterator parallelAdd,
+		    unsigned long addSize,
+		    const Compare &comp) {
+  unsigned long i;
+  for (i=0; i<addSize; ++i) {
+    if (comp(*(parallelAdd+i), *(parallelHeap))) {
+      swap (*(docNumHeap), *(docNumAdd+i));
+      swap (*(parallelHeap), *(parallelAdd+i));
+      AdjustHeap (docNumHeap, parallelHeap, (unsigned long)0, heapSize, comp);
+    }
+  }
+}
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryTester.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryTester.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/QueryTester.cpp	(revision 10506)
@@ -0,0 +1,447 @@
+/**************************************************************************
+ *
+ * QueryTester.cpp -- 
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "MGQuery.h"
+
+
+class SetQueryNode : public QueryNode {
+public:
+  QueryResult queryResult;
+  
+  SetQueryNode () {}
+  ~SetQueryNode () {}
+
+  void Calculate (IndexData &/*indexData*/, const QueryInfo &queryInfo,
+		  QueryResult &result) const {
+    result = queryResult;
+    if (!queryInfo.sortByRank && !queryInfo.needRankInfo)
+      result.ranks.erase (result.ranks.begin(), result.ranks.end());
+    if (!queryInfo.needTermFreqs)
+      result.termFreqs.erase (result.termFreqs.begin(),
+			      result.termFreqs.end());
+  }
+  void Free () { queryResult.Clear(); }
+};
+
+
+bool Test1 () {
+  AndQueryNode andNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  RankArray &rankSet1 = setNode1->queryResult.ranks;
+  docSet1.push_back (1);  rankSet1.push_back (0.1f);
+  docSet1.push_back (10); rankSet1.push_back (0.2f);
+  docSet1.push_back (15); rankSet1.push_back (0.2f);
+  docSet1.push_back (18); rankSet1.push_back (0.4f);
+  docSet1.push_back (19); rankSet1.push_back (0.5f);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  RankArray &rankSet2 = setNode2->queryResult.ranks;
+  docSet2.push_back (2);  rankSet2.push_back (0.1f);
+  docSet2.push_back (11); rankSet2.push_back (0.2f);
+  docSet2.push_back (12); rankSet2.push_back (0.3f);
+  docSet2.push_back (13); rankSet2.push_back (0.4f);
+  docSet2.push_back (14); rankSet2.push_back (0.5f);
+  docSet2.push_back (15); rankSet2.push_back (0.6f);
+  docSet2.push_back (16); rankSet2.push_back (0.7f);
+  docSet2.push_back (17); rankSet2.push_back (0.8f);
+  docSet2.push_back (19); rankSet2.push_back (0.9f);
+  docSet2.push_back (20); rankSet2.push_back (0.1f);
+  docSet2.push_back (21); rankSet2.push_back (0.2f);
+
+  cout << "\n" << setNode1->queryResult << "AND\n\n"
+       << setNode2->queryResult;
+  
+
+  andNode.leftNode = setNode1;
+  andNode.rightNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = true;
+  queryInfo.needRankInfo = true;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  andNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  RankArray &rcRankSet = resultCompare.ranks;
+  rcDocSet.push_back (15);  rcRankSet.push_back (0.2+0.6);
+  rcDocSet.push_back (19);  rcRankSet.push_back (1.4);
+
+  if (!(result == resultCompare)) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+bool Test1b () {
+  AndQueryNode andNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  docSet1.push_back (1); 
+  docSet1.push_back (10);
+  docSet1.push_back (15);
+  docSet1.push_back (18);
+  docSet1.push_back (19);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  docSet2.push_back (2); 
+  docSet2.push_back (11);
+  docSet2.push_back (12);
+  docSet2.push_back (13);
+  docSet2.push_back (14);
+  docSet2.push_back (15);
+  docSet2.push_back (16);
+  docSet2.push_back (17);
+  docSet2.push_back (19);
+  docSet2.push_back (20);
+  docSet2.push_back (21);
+
+  cout << "\n" << setNode1->queryResult << "AND\n\n"
+       << setNode2->queryResult;
+  
+
+  andNode.leftNode = setNode1;
+  andNode.rightNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = false;
+  queryInfo.needRankInfo = false;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  andNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  rcDocSet.push_back (15); 
+  rcDocSet.push_back (19); 
+
+  if (!(result == resultCompare)) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+bool Test2 () {
+  OrQueryNode orNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  RankArray &rankSet1 = setNode1->queryResult.ranks;
+  docSet1.push_back (1);  rankSet1.push_back (0.1f);
+  docSet1.push_back (10); rankSet1.push_back (0.2f);
+  docSet1.push_back (15); rankSet1.push_back (0.2f);
+  docSet1.push_back (18); rankSet1.push_back (0.4f);
+  docSet1.push_back (19); rankSet1.push_back (0.5f);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  RankArray &rankSet2 = setNode2->queryResult.ranks;
+  docSet2.push_back (2);  rankSet2.push_back (0.1f);
+  docSet2.push_back (11); rankSet2.push_back (0.2f);
+  docSet2.push_back (12); rankSet2.push_back (0.3f);
+  docSet2.push_back (13); rankSet2.push_back (0.4f);
+  docSet2.push_back (14); rankSet2.push_back (0.5f);
+  docSet2.push_back (15); rankSet2.push_back (0.6f);
+  docSet2.push_back (16); rankSet2.push_back (0.7f);
+  docSet2.push_back (17); rankSet2.push_back (0.8f);
+  docSet2.push_back (19); rankSet2.push_back (0.9f);
+  docSet2.push_back (20); rankSet2.push_back (0.1f);
+  docSet2.push_back (21); rankSet2.push_back (0.2f);
+
+  cout << "\n" << setNode1->queryResult << "OR\n\n"
+       << setNode2->queryResult;
+  
+
+  orNode.leftNode = setNode1;
+  orNode.rightNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = true;
+  queryInfo.needRankInfo = true;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  orNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  RankArray &rcRankSet = resultCompare.ranks;
+  rcDocSet.push_back (1);  rcRankSet.push_back (0.1f);
+  rcDocSet.push_back (2);  rcRankSet.push_back (0.1f);
+  rcDocSet.push_back (10); rcRankSet.push_back (0.2f);
+  rcDocSet.push_back (11); rcRankSet.push_back (0.2f);
+  rcDocSet.push_back (12); rcRankSet.push_back (0.3f);
+  rcDocSet.push_back (13); rcRankSet.push_back (0.4f);
+  rcDocSet.push_back (14); rcRankSet.push_back (0.5f);
+  rcDocSet.push_back (15); rcRankSet.push_back (0.2f+0.6f);
+  rcDocSet.push_back (16); rcRankSet.push_back (0.7f);
+  rcDocSet.push_back (17); rcRankSet.push_back (0.8f);
+  rcDocSet.push_back (18); rcRankSet.push_back (0.4f);
+  rcDocSet.push_back (19); rcRankSet.push_back (0.9f+0.5f);
+  rcDocSet.push_back (20); rcRankSet.push_back (0.1f);
+  rcDocSet.push_back (21); rcRankSet.push_back (0.2f);
+  
+
+  if (!(result == resultCompare)) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+bool Test2b () {
+  OrQueryNode orNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  docSet1.push_back (1); 
+  docSet1.push_back (10);
+  docSet1.push_back (15);
+  docSet1.push_back (18);
+  docSet1.push_back (19);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  docSet2.push_back (2);
+  docSet2.push_back (11);
+  docSet2.push_back (12);
+  docSet2.push_back (13);
+  docSet2.push_back (14);
+  docSet2.push_back (15);
+  docSet2.push_back (16);
+  docSet2.push_back (17);
+  docSet2.push_back (19);
+  docSet2.push_back (20);
+  docSet2.push_back (21);
+
+  cout << "\n" << setNode1->queryResult << "OR\n\n"
+       << setNode2->queryResult;
+  
+
+  orNode.leftNode = setNode1;
+  orNode.rightNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = false;
+  queryInfo.needRankInfo = false;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  orNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  rcDocSet.push_back (1);
+  rcDocSet.push_back (2); 
+  rcDocSet.push_back (10);
+  rcDocSet.push_back (11);
+  rcDocSet.push_back (12);
+  rcDocSet.push_back (13);
+  rcDocSet.push_back (14);
+  rcDocSet.push_back (15);
+  rcDocSet.push_back (16);
+  rcDocSet.push_back (17);
+  rcDocSet.push_back (18);
+  rcDocSet.push_back (19);
+  rcDocSet.push_back (20);
+  rcDocSet.push_back (21);
+  
+
+  if (!(result == resultCompare)) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+bool Test3 () {
+  NotQueryNode notNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  RankArray &rankSet1 = setNode1->queryResult.ranks;
+  docSet1.push_back (1);  rankSet1.push_back (0.1f);
+  docSet1.push_back (10); rankSet1.push_back (0.2f);
+  docSet1.push_back (15); rankSet1.push_back (0.2f);
+  docSet1.push_back (18); rankSet1.push_back (0.4f);
+  docSet1.push_back (19); rankSet1.push_back (0.5f);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  RankArray &rankSet2 = setNode2->queryResult.ranks;
+  docSet2.push_back (2);  rankSet2.push_back (0.1f);
+  docSet2.push_back (11); rankSet2.push_back (0.2f);
+  docSet2.push_back (12); rankSet2.push_back (0.3f);
+  docSet2.push_back (13); rankSet2.push_back (0.4f);
+  docSet2.push_back (14); rankSet2.push_back (0.5f);
+  docSet2.push_back (15); rankSet2.push_back (0.6f);
+  docSet2.push_back (16); rankSet2.push_back (0.7f);
+  docSet2.push_back (17); rankSet2.push_back (0.8f);
+  docSet2.push_back (19); rankSet2.push_back (0.9f);
+  docSet2.push_back (20); rankSet2.push_back (0.1f);
+  docSet2.push_back (21); rankSet2.push_back (0.2f);
+
+  cout << "\n" << setNode1->queryResult << "NOT\n\n"
+       << setNode2->queryResult;
+  
+
+  notNode.queryNode = setNode1;
+  notNode.notNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = true;
+  queryInfo.needRankInfo = true;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  notNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  RankArray &rcRankSet = resultCompare.ranks;
+  rcDocSet.push_back (1);  rcRankSet.push_back (0.1);
+  rcDocSet.push_back (10); rcRankSet.push_back (0.2);
+  rcDocSet.push_back (18); rcRankSet.push_back (0.4);
+  
+
+  if (!(result == resultCompare)) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+bool Test3b () {
+  NotQueryNode notNode;
+
+  SetQueryNode *setNode1 = new SetQueryNode;
+  DocNumArray &docSet1 = setNode1->queryResult.docs;
+  docSet1.push_back (1); 
+  docSet1.push_back (10);
+  docSet1.push_back (15);
+  docSet1.push_back (18);
+  docSet1.push_back (19);
+
+  SetQueryNode *setNode2 = new SetQueryNode;
+  DocNumArray &docSet2 = setNode2->queryResult.docs;
+  docSet2.push_back (2); 
+  docSet2.push_back (11);
+  docSet2.push_back (12);
+  docSet2.push_back (13);
+  docSet2.push_back (14);
+  docSet2.push_back (15);
+  docSet2.push_back (16);
+  docSet2.push_back (17);
+  docSet2.push_back (19);
+  docSet2.push_back (20);
+  docSet2.push_back (21);
+
+  cout << "\n" << setNode1->queryResult << "NOT\n\n"
+       << setNode2->queryResult;
+  
+
+  notNode.queryNode = setNode1;
+  notNode.notNode = setNode2;
+
+  IndexData indexData; // this will not be used anywhere
+  QueryInfo queryInfo;
+  queryInfo.maxDocs = 0;
+  queryInfo.sortByRank = false;
+  queryInfo.needRankInfo = false;
+  queryInfo.needTermFreqs = true;
+  
+  QueryResult result;
+
+  notNode.Calculate(indexData, queryInfo, result);
+
+  cout << "EQUALS\n\n" << result << "\n";
+
+  QueryResult resultCompare;
+  DocNumArray &rcDocSet = resultCompare.docs;
+  rcDocSet.push_back (1); 
+  rcDocSet.push_back (10);
+  rcDocSet.push_back (18);
+  
+
+  if (!(result == resultCompare)) {
+    cout << "Test failed!!!\n";
+    cout << resultCompare;
+    return false;
+  }
+
+  return true;
+}
+
+
+int main () {
+  if (!Test1 () ||
+      !Test2 () ||
+      !Test2b () ||
+      !Test3 () ||
+      !Test3b ()) return 1;
+  
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Queryer.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Queryer.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Queryer.cpp	(revision 10506)
@@ -0,0 +1,271 @@
+/**************************************************************************
+ *
+ * Queryer.cpp -- simple interactive query program
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+/* getopt is in posix.2, so cygwin should have it in unistd, but doesn't */
+#if defined (__WIN32__) || defined (__CYGWIN__)
+# include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "MGQuery.h"
+#include "TextGet.h"
+
+#include "messages.h"
+#include "mg_files.h"
+
+#include "GSDLQueryParser.h"
+
+void printHelp() {
+
+  cout << "commands available are:\n"
+       << "\t.q\t\tquit\n"
+       << "\t.h\t\tprint the help message\n"
+       << "\t.i\t\tchange the search level (enter the new level at the prompt)\n"
+       << "\t.l\t\tchange the result level ( \"\"   \"\"  )\n"
+       << "\t.b\t\tfull text browse (enter a word or fragment at the prompt)\n"
+       << "\t.r0/.r1\t\tranking off/on\n"
+       << "\t.t0/.t1\t\tquery type some/all\n"
+       << "\t.c0/.c1\t\tcasefolding off/on\n"
+       << "\t.s0/.s1\t\tstemming off/on\n"
+       << "\t.o0/.o1\t\tshort output off/on\n\n"
+       << "\t.p\t\tprint a document (enter the docnum at the prompt)\n"
+       << "otherwise just enter a query\n\n";
+
+}
+
+int main (int argc, char **argv) {
+  int ch;
+  char *textfilename = "";
+  char *indexfilename = "";
+  char *basePath = "";
+  
+  opterr = 0;
+  msg_prefix = argv[0];
+  
+  // process the command line arguments
+  while ((ch = getopt (argc, argv, "f:t:d:h")) != -1) {
+    switch (ch) {
+    case 'f':		/* input file */
+      indexfilename = optarg;
+      break;
+    case 't':
+      textfilename = optarg;
+      break;
+    case 'd':
+      basePath = optarg;
+      set_basepath (basePath);
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-h] [-d directory] -f indexname -t textname\n", argv[0]);
+      exit (1);
+    }
+  }
+
+  if (textfilename[0] == '\0' || indexfilename[0] == '\0') {
+    FatalError (1, "Index and text file names must be specified with -f and -t \n");
+  }
+  
+  // init the text system
+    TextData textData;
+  if (!textData.LoadData (basePath, textfilename)) {
+    FatalError (1, "Couldn't load text information for \"%s\"", textfilename);
+  }
+  
+  // init the query system
+  IndexData indexData;
+  if (!indexData.LoadData (basePath, indexfilename)) {
+    FatalError (1, "Couldn't load index information for \"%s\"", indexfilename);
+  }
+
+  // debug output
+  cerr << "num docs: "<<indexData.bdh.num_docs       
+       << "\nnum frags: "<<indexData.bdh.num_frags
+       << "\nnum words: "<<indexData.bdh.num_words
+       << "\ntotal bytes: "<<indexData.bdh.total_bytes
+       << "\nindex string bytes: "<<indexData.bdh.index_string_bytes
+       << "\nnum levels: "<<indexData.bdh.num_levels<<endl;
+  
+  // do querying
+  QueryInfo queryInfo;
+  SetCStr (queryInfo.docLevel, "Document", 8);
+  queryInfo.maxDocs = 50;
+  queryInfo.sortByRank = true;
+  queryInfo.exactWeights = false;
+  queryInfo.needRankInfo = true;
+  queryInfo.needTermFreqs = true;
+  
+  ExtQueryResult queryResult;
+  char query[2048];
+  UCArray queryArray;
+  QueryNode *queryTree = NULL;
+
+
+  UCArray docLevel;
+  SetCStr(docLevel, "Document", 8);
+
+  UCArray level;
+  UCArrayClear(level);
+  //SetCStr(level, "");
+   
+  int defaultStemMethod = 0; // uncasefolded, unstemmed
+  int defaultBoolCombine = 0; // OR
+  bool shortOutput = false;
+  BrowseQueryNode browseNode;
+  browseNode.startPosition = -10;
+  browseNode.numTerms = 40;
+
+  BrowseQueryResult browseResult;
+
+  while (true) {
+    cout << "> ";
+    cin.getline(query, 2048, '\n');
+    SetCStr (queryArray, query, strlen(query));
+
+    // check for commands
+    if (queryArray.size() >= 2 && queryArray[0] == '.') {
+      if (queryArray[1] == 'q') break;  // quit
+
+      if (queryArray[1] == 'h') { // help
+	printHelp();
+      } else if (queryArray[1] == 'i') {
+	cout << "current index="<< queryInfo.docLevel << "\nchange to index:";
+	cin >> query;
+	UCArrayClear(queryInfo.docLevel);
+	SetCStr(queryInfo.docLevel, query, strlen(query));
+	cout << "index set to " << queryInfo.docLevel <<"\n";
+	cin.getline(query, 2048, '\n');
+      } else if (queryArray[1] == 'l') {
+	cout << "current level="<< level << "\nchange to level:";
+	cin >> query;
+	UCArrayClear(level);
+	SetCStr(level, query, strlen(query));
+	cout << "level set to " << level <<"\n";
+	cin.getline(query, 2048, '\n');
+      }
+
+
+      else if (queryArray[1] == 'p') {
+	// print
+	UCArray docText;
+	unsigned long docNum = 0;
+	cin >> docNum;
+	cin.getline(query, 2048, '\n'); // eat up return
+	
+	if (!GetDocText (textData, queryInfo.docLevel, docNum, docText)) {
+	  FatalError (1, "Error while trying to get document %u", docNum);
+	}
+	
+	cout << docText << "\n";
+      }
+      else if (queryArray[1] == 't') { // query type - all/some
+	if (queryArray[2] == '1') defaultBoolCombine = 1;
+	else if (queryArray[2] == '0') defaultBoolCombine = 0;
+	else {
+	  cout << "Error: please enter .t0 (some) or .t1 (all)\n";
+	}
+      }
+      else if (queryArray[1] == 'r') { // ranking - on/off
+	if (queryArray[2] == '1') queryInfo.sortByRank = true;
+	else if (queryArray[2] == '0') queryInfo.sortByRank = false;
+	else {
+	  cout << "Error: please enter .r0 (non-ranked) or .r1 (ranked)\n";
+	}
+      }
+      else if (queryArray[1] == 'c') { // casefolding - on/off
+	if (queryArray[2] == '1') defaultStemMethod |= 1;
+	else if (queryArray[2] == '0') defaultStemMethod &= 0xe;
+	else {
+	  cout << "Error: please enter .c0 (case sensitive) or .c1 (casefolded)\n";
+	}
+      }
+      else if (queryArray[1] == 's') { // stemming - on/off
+	if (queryArray[2] == '1') defaultStemMethod |=2;
+	else if (queryArray[2] == '0') defaultStemMethod &=0xd;
+	else {
+	  cout << "Error: please enter .s0 (unstemmed) or .s1 (stemmed)\n";
+	}
+      }      
+      else if (queryArray[1] == 'o') { // output - short/long
+	if (queryArray[2] == '1') shortOutput = true;
+	else if (queryArray[2] == '0') shortOutput = false;
+	else {
+	  cout << "Error: please enter .o0 (long output) or .o1 (short output)\n";
+	}
+      }
+      else if (queryArray[1] == 'b') {
+	// full text browse
+	cout<<"enter a few letters to start browsing from:";
+	cin>>query;
+	UCArrayClear(browseNode.term);
+	SetCStr(browseNode.term, query, strlen(query));
+	cin.getline(query, 2048, '\n'); // get rest of line
+
+	// print the query
+	PrintNode (cout, &browseNode);
+
+	MGBrowseQuery(indexData, docLevel, browseNode, browseResult);
+	cout << browseResult;
+	cout << "\n";
+
+      }
+      else { // bad option
+	cout << "bad command\n\n";
+	printHelp();
+      }
+    } // if a .x query
+    else {
+      // regular query
+      queryTree = ParseQuery (queryArray, defaultBoolCombine, defaultStemMethod);
+      if (queryTree == NULL) {
+	cout << "invalid syntax\n";
+      } else {
+	// print the query
+	PrintNode (cout, queryTree);
+	
+	MGQuery (indexData, queryInfo, queryTree, queryResult, level);
+	if (shortOutput) {
+	  queryResult.printShort(cout);
+	  cout << "\n";
+	} else {
+	  cout << queryResult;
+	  cout << "\n";
+	}
+	// delete the query
+	delete queryTree;
+	queryTree = NULL;
+      }
+    }
+  }
+
+
+  // clean up, everybody clean up
+    textData.UnloadData ();
+  indexData.UnloadData ();
+
+  return (0);
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TagInfo.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TagInfo.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TagInfo.cpp	(revision 10506)
@@ -0,0 +1,74 @@
+/**************************************************************************
+ *
+ * TagInfo.cpp -- 
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "TagInfo.h"
+
+
+void TagInfo::SetDocTag (const char *cStr) {
+  SetCStr (docTag, cStr, strlen(cStr));
+}
+
+void TagInfo::SetIndexLevel (const char *cStr) {
+  SetCStr (indexLevel, cStr, strlen(cStr));
+}
+void TagInfo::AddLevelTag (const char *cStr) {
+  // convert the string
+  UCArray cArr;
+  SetCStr (cArr, cStr, strlen(cStr));
+
+  // insert the tag
+  levelTags.insert (cArr);
+}
+
+
+TagInfo::TagInfo () {
+  Clear ();
+}
+
+void TagInfo::Clear () {
+  docTag.erase (docTag.begin(), docTag.end());
+  indexLevel.erase (indexLevel.begin(), indexLevel.end());
+  levelTags.erase (levelTags.begin(), levelTags.end());
+}
+
+ostream &operator<<(ostream &s, const TagInfo &t) {
+  // output docTag
+  s << "docTag: \"" << t.docTag << "\"\n";
+
+  // output indexLevel
+  s << "indexLevel: \"" << t.indexLevel << "\"\n";
+
+  // output levelTags
+  s << "levelTags: ";
+
+  UCArraySet::const_iterator here = t.levelTags.begin();
+  UCArraySet::const_iterator end = t.levelTags.end();
+  while (here != end) {
+    s << "\"" << (*here) << "\"";
+    ++here;
+    if (here != end) s << ", ";
+  }
+
+  s << "\n";
+  
+  return s;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TagInfo.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TagInfo.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TagInfo.h	(revision 10506)
@@ -0,0 +1,46 @@
+/**************************************************************************
+ *
+ * TagInfo.h -- 
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef TAGINFO_H
+#define TAGINFO_H
+
+#include "UCArray.h"
+
+
+class TagInfo {
+public:
+  UCArray docTag;
+  UCArray indexLevel;    // empty for word level index
+  UCArraySet levelTags;
+
+  void SetDocTag (const char *cStr);
+  void SetIndexLevel (const char *cStr);
+  void AddLevelTag (const char *cStr);
+  
+  TagInfo ();
+  void Clear ();
+};
+
+// stream operator to print TagInfo
+ostream &operator<<(ostream &s, const TagInfo &t);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Terms.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Terms.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Terms.cpp	(revision 10506)
@@ -0,0 +1,797 @@
+/**************************************************************************
+ *
+ * Terms.cpp -- Query related functions
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "Terms.h"
+#include "words.h"
+#include "stemmer.h"
+#include "bitio_gen.h"
+#include "bitio_m_stdio.h"
+
+void QueryInfo::Clear () {
+  UCArrayClear (docLevel);
+  maxDocs = 0;
+  sortByRank = true;
+  exactWeights = false;
+  needRankInfo = false;
+  needTermFreqs = false;
+}
+
+
+
+void TermFreqData::Clear () {
+  UCArrayClear (tag);
+  UCArrayClear (term);
+  equivTerms.erase(equivTerms.begin(), equivTerms.end());
+  stemMethod = 0;
+  matchDocs = 0;
+  termFreq = 0;
+}
+
+ostream &operator<< (ostream &s, const TermFreqData &t) {
+  s << "<" << t.tag << ">\"" << t.term << "\"stem("
+    << t.stemMethod << ")equiv terms(";
+  
+  unsigned long i;
+  for (i=0; i<t.equivTerms.size(); ++i) {
+    s << t.equivTerms[i] << ", ";
+  }
+  s <<")docs(" << t.matchDocs << ")"
+    << "count("<<t.termFreq<<")";
+  return s;
+}
+
+bool operator== (const TermFreqData &t1, const TermFreqData &t2) {
+  return ((t1.tag == t2.tag) &&
+	  (t1.term == t2.term) &&
+	  (t1.stemMethod == t2.stemMethod) &&
+	  (t1.equivTerms == t2.equivTerms) &&
+	  (t1.matchDocs == t2.matchDocs) &&
+	  (t1.termFreq == t2.termFreq));
+}
+
+
+void QueryResult::Clear () {
+  docs.erase (docs.begin(), docs.end());
+  ranks.erase (ranks.begin(), ranks.end());
+  termFreqs.erase (termFreqs.begin(), termFreqs.end());
+  actualNumDocs = 0;
+}
+
+QueryResult::QueryResult () {
+  Clear ();
+}
+
+void QueryResult::printShort(ostream &s) {
+
+  s << "termFreqs: ";
+  for (unsigned long i=0; i<termFreqs.size(); ++i)
+    s << termFreqs[i] << ", ";
+  
+  s << "\nactual number of docs found: " << actualNumDocs;
+  s << "\n\n";
+
+}
+
+
+ostream &operator<< (ostream &s, const QueryResult &r) {
+  s << "docs: ";
+  unsigned long i;
+  for (i=0; i<r.docs.size(); ++i)
+    s << r.docs[i] << ", ";
+  
+  s << "\nranks: ";
+  for (i=0; i<r.ranks.size(); ++i)
+    s << r.ranks[i] << ", ";
+
+  s << "\ntermFreqs: ";
+  for (i=0; i<r.termFreqs.size(); ++i)
+    s << r.termFreqs[i] << ", ";
+
+  s << "\nactual number of docs found: " << r.actualNumDocs;
+  s << "\n\n";
+
+  return s;
+}
+
+
+bool operator== (const QueryResult &r1, const QueryResult &r2) {
+  return ((r1.docs == r2.docs) &&
+	  (r1.ranks == r2.ranks) &&
+	  (r1.termFreqs == r2.termFreqs) &&
+	  (r1.actualNumDocs == r2.actualNumDocs));
+}
+
+//---------------------------------------------------
+// new ExtQueryResult stuff
+void ExtQueryResult::Clear () {
+  docs.erase (docs.begin(), docs.end());
+  levels.erase (levels.begin(), levels.end());
+  ranks.erase (ranks.begin(), ranks.end());
+  termFreqs.erase (termFreqs.begin(), termFreqs.end());
+  actualNumDocs = 0;
+}
+
+ExtQueryResult::ExtQueryResult () {
+  Clear ();
+}
+
+ostream &operator<< (ostream &s, const ExtQueryResult &r) {
+  s << "docs: ";
+  unsigned long i;
+  for (i=0; i<r.docs.size(); ++i)
+    s << r.docs[i] << ", ";
+
+  s << "\nlevels: ";
+  for (i=0; i<r.levels.size(); ++i)
+    s << r.levels[i] << ", ";
+
+  
+  s << "\nranks: ";
+  for (i=0; i<r.ranks.size(); ++i)
+    s << r.ranks[i] << ", ";
+
+  s << "\ntermFreqs: ";
+  for (i=0; i<r.termFreqs.size(); ++i)
+    s << r.termFreqs[i] << ", ";
+  s << "\nactual number of docs found: " << r.actualNumDocs;
+  s << "\n\n";
+
+  return s;
+}
+
+
+bool operator== (const ExtQueryResult &r1, const ExtQueryResult &r2) {
+  return ((r1.docs == r2.docs) &&
+	  (r1.levels == r2.levels) &&
+	  (r1.ranks == r2.ranks) &&
+	  (r1.termFreqs == r2.termFreqs) &&
+	  (r1.actualNumDocs == r2.actualNumDocs));
+}
+
+//-------------------------------------------------------
+// new BrowseQueryResult stuff
+void BrowseQueryResult::Clear () {
+  termFreqs.erase (termFreqs.begin(), termFreqs.end());
+}
+
+BrowseQueryResult::BrowseQueryResult () {
+  Clear ();
+}
+
+
+
+ostream &operator<< (ostream &s, const BrowseQueryResult &r) {
+  s << "terms: ";
+  unsigned long i;
+  for (i=0; i<r.termFreqs.size(); ++i)
+    s << r.termFreqs[i] << ", ";
+    s << "\n\n";
+  return s;
+}
+
+
+bool operator== (const BrowseQueryResult &r1, const BrowseQueryResult &r2) {
+  return ((r1.termFreqs == r2.termFreqs));
+	 
+}
+
+
+
+
+//--------------------------------------
+void FragData::Clear () {
+  matchDocs = 0;
+  fragNums.erase (fragNums.begin(), fragNums.end());
+  fragFreqs.erase (fragFreqs.begin(), fragFreqs.end());
+}
+
+
+void FindWordNumbers (IndexData &indexData,
+		      const UCArray &term,
+		      unsigned long stemMethod,
+		      vector<unsigned long> &equivWords) {
+  equivWords.erase (equivWords.begin(), equivWords.end());
+  
+  if (stemMethod == 0 || stemMethod==4 || stemMethod==5) {
+    // don't need to stem the word,
+    // find the word number(s) for this term
+    unsigned long wordElNum = 0;
+    unsigned long numLevels = indexData.bdh.num_levels;
+    word_block_dict_el wordDictEl;
+    wordDictEl.SetNumLevels (numLevels);
+    if (stemMethod ==0) {
+      if (SearchWordBlockDictEl (indexData.dictFile, indexData.biWords,
+				 indexData.bdh.entries_per_wblk,
+				 indexData.bdh.word_dict_size,
+				 numLevels, term, wordDictEl, wordElNum))
+	equivWords.push_back (wordElNum);
+      
+      return;
+    } else {
+      // partial matching,
+      PartialMatchSearchWordBlockDictEl (indexData.dictFile, indexData.biWords, indexData.bdh.entries_per_wblk, indexData.bdh.word_dict_size, numLevels, term, wordDictEl, equivWords, (stemMethod==5?true:false) );
+      return;
+    }
+  }
+		      
+  // need to stem this word and find it in the blocked stem index
+  
+  unsigned char  mgWord[MAXSTEMLEN + 1];
+  UCArray stemTerm;
+  unsigned long stemmerNum = 0;
+  if (stemMethod == 1) stemmerNum = indexData.sih1.stemmer_num;
+  else if (stemMethod == 2) stemmerNum = indexData.sih2.stemmer_num;
+  else if (stemMethod == 3) stemmerNum = indexData.sih3.stemmer_num;
+   
+  // convert the word to an "mg word"
+  mgWord[0] = term.size();
+  memcpy ((char *)&mgWord[1], &(term[0]), term.size());
+  
+  // stem the word
+  stemmer (stemMethod, stemmerNum, mgWord);
+
+  // convert the result back to a UCArray
+  stemTerm.insert (stemTerm.end(), &mgWord[1], &mgWord[1] + mgWord[0]);
+
+  // need to look up this term in the appropriate dictionary
+  stem_block_dict_el stemDictEl;
+  unsigned long stemElNum;
+  bool result = false;
+  if (stemMethod == 1) {
+    result = SearchStemBlockDictEl (indexData.stem1File,
+			   indexData.sii1,
+			   indexData.sih1.entries_per_block,
+			   indexData.sih1.dict_size,
+			   stemTerm,
+			   stemDictEl,
+			   stemElNum);
+
+  } else if (stemMethod == 2) {
+    result = SearchStemBlockDictEl (indexData.stem2File,
+			   indexData.sii2,
+			   indexData.sih2.entries_per_block,
+			   indexData.sih2.dict_size,
+			   stemTerm,
+			   stemDictEl,
+			   stemElNum);
+
+  } else if (stemMethod == 3) {
+    result = SearchStemBlockDictEl (indexData.stem3File,
+			   indexData.sii3,
+			   indexData.sih3.entries_per_block,
+			   indexData.sih3.dict_size,
+			   stemTerm,
+			   stemDictEl,
+			   stemElNum);
+  }
+
+  if (result) {
+    equivWords = stemDictEl.equivWords;  
+  }
+}
+
+
+
+void ReadTermFragData (IndexData &indexData,
+		       bool needFragFreqs,
+		       unsigned long termNum,
+		       FragData &fragData,
+		       FragRangeArray *fragLimits,
+		       UCArray & termWord) {
+  fragData.Clear();
+
+  // look up the word in the dictionary
+  unsigned long numLevels = indexData.bdh.num_levels;
+  word_block_dict_el wordDictEl;
+  wordDictEl.SetNumLevels (numLevels);
+  if (!SearchWordBlockDictElNum (indexData.dictFile,
+				 indexData.biWords,
+				 indexData.bdh.entries_per_wblk,
+				 indexData.bdh.word_dict_size,
+				 numLevels,
+				 termNum, wordDictEl))
+    return; // nothing more to do
+
+  fragData.matchDocs = wordDictEl.levelFreqs[indexData.curLevelNum];
+  termWord = wordDictEl.el;
+  // seek to the appropriate place in the inverted file
+  fseek (indexData.invfFile, wordDictEl.invf_ptr, SEEK_SET);
+  stdio_bitio_buffer buffer (indexData.invfFile);
+    
+  unsigned long B = BIO_Bblock_Init (indexData.bdh.num_frags,
+				     wordDictEl.frag_occur);
+  unsigned long fragNum = 0;
+  unsigned long termFreq = 0;
+
+  unsigned long fragLimitI = 0;
+  unsigned long i;
+  for (i=0; i<wordDictEl.frag_occur; ++i) {
+    fragNum += buffer.bblock_decode (B, NULL);
+    if (!indexData.ifh.word_level_index) termFreq = buffer.gamma_decode (NULL);
+    else termFreq = 1;
+
+    // get the right fragment range
+    if (fragLimits != NULL) {
+      while (fragLimitI+1 < (*fragLimits).size() &&
+	     fragNum > (*fragLimits)[fragLimitI+1].rangeStart) {
+	++fragLimitI;
+      }
+    }
+
+    // add the entry if it is within the limits
+    if ((fragLimits == NULL) ||
+	(fragLimitI < (*fragLimits).size() &&
+	 fragNum > (*fragLimits)[fragLimitI].rangeStart &&
+	 fragNum <= (*fragLimits)[fragLimitI].rangeEnd)) {
+      fragData.fragNums.push_back (fragNum);
+      if (needFragFreqs)
+	fragData.fragFreqs.push_back (termFreq);
+    }
+  }
+
+  buffer.done();
+}
+
+
+void CombineFragData (bool needFragFreqs,
+		      const FragData &f1,
+		      const FragData &f2,
+		      FragData &outFragData) {
+  outFragData.Clear();
+
+  // the new number of matching documents is the maximum
+  // of the two input matching number of documents -- it
+  // is assumed that these are at the same document level
+  outFragData.matchDocs = (f1.matchDocs > f2.matchDocs) ?
+    f1.matchDocs : f2.matchDocs;
+
+  // do or
+  unsigned long f1I = 0, f1Size = f1.fragNums.size();
+  unsigned long f2I = 0, f2Size = f2.fragNums.size();
+  while (f1I < f1Size || f2I < f2Size) {
+    if (f2I < f2Size &&
+	(f1I >= f1Size ||
+	 f1.fragNums[f1I] > f2.fragNums[f2I])) {
+      // output f2I
+      outFragData.fragNums.push_back (f2.fragNums[f2I]);
+      if (needFragFreqs)
+	outFragData.fragFreqs.push_back (f2.fragFreqs[f2I]);
+      ++f2I;
+      
+    } else if (f1I < f1Size &&
+	       (f2I >= f2Size ||
+		f1.fragNums[f1I] < f2.fragNums[f2I])) {
+      // output f1I
+      outFragData.fragNums.push_back (f1.fragNums[f1I]);
+      if (needFragFreqs)
+	outFragData.fragFreqs.push_back (f1.fragFreqs[f1I]);
+      ++f1I;
+      
+    } else {
+      // must be equal combine f1I and f2I
+      outFragData.fragNums.push_back (f1.fragNums[f1I]);
+      if (needFragFreqs)
+	outFragData.fragFreqs.push_back (f1.fragFreqs[f1I]+f2.fragFreqs[f2I]);
+      ++f1I;
+      ++f2I;
+    }
+  }
+}
+
+
+void AndCombineFragData (bool needFragFreqs,
+			 FragData &fragData,
+			 const FragData &comFragData,
+			 signed long startRange,
+			 signed long endRange,
+			 const FragRangeArray *fragLimits) {
+  // sanity check on range
+  if (startRange > endRange) {
+    signed long temp = endRange;
+    endRange = startRange;
+    startRange = temp;
+  }
+
+  // get min matchdocs
+  if (comFragData.matchDocs < fragData.matchDocs)
+    fragData.matchDocs = comFragData.matchDocs;
+  
+  unsigned long fragDataI = 0;
+  unsigned long fragDataSize = fragData.fragNums.size();
+  unsigned long comFragDataI = 0;
+  unsigned long comFragDataSize = comFragData.fragNums.size();
+  unsigned long fragLimitI = 0;
+  unsigned long fragLimitSize = (fragLimits==NULL) ? 0 : (*fragLimits).size();
+  unsigned long outI = 0;
+
+  while (fragDataI < fragDataSize &&
+	 comFragDataI < comFragDataSize) {
+    signed long fragNum = (signed long)fragData.fragNums[fragDataI];
+    signed long comFragNum = (signed long)comFragData.fragNums[comFragDataI];
+    
+    // go to the right fragment limit (for the com frag)
+    if (fragLimits != NULL) {
+      while (fragLimitI+1 < fragLimitSize &&
+	     comFragNum > (signed long)(*fragLimits)[fragLimitI+1].rangeStart) {
+	++fragLimitI;
+      }
+    }
+
+    if (fragNum <= comFragNum+startRange ||
+	(fragLimits!=NULL &&
+	 fragNum<=(signed long)(*fragLimits)[fragLimitI].rangeStart)) {
+      ++fragDataI;
+      
+    } else if (fragNum > comFragNum+endRange ||
+	       (fragLimits!=NULL &&
+		fragNum>(signed long)(*fragLimits)[fragLimitI].rangeEnd)) {
+      ++comFragDataI;
+      
+    } else {
+      // equal and within tag
+      fragData.fragNums[outI] = comFragNum;
+      if (needFragFreqs) {
+	fragData.fragFreqs[outI] =
+	  (fragData.fragFreqs[fragDataI] < comFragData.fragFreqs[comFragDataI]) ?
+	  fragData.fragFreqs[fragDataI] : comFragData.fragFreqs[comFragDataI];
+      }
+      ++fragDataI;
+      ++comFragDataI;
+      ++outI;
+    }
+  }
+
+  // erase unused part of fragData
+  fragData.fragNums.erase (fragData.fragNums.begin()+outI,
+			   fragData.fragNums.end());
+  if (needFragFreqs)
+    fragData.fragFreqs.erase (fragData.fragFreqs.begin()+outI,
+			      fragData.fragFreqs.end());
+  else
+    fragData.fragFreqs.erase (fragData.fragFreqs.begin(),
+			      fragData.fragFreqs.end());
+}
+
+
+void FragsToQueryResult (IndexData &indexData,
+			 const QueryInfo &queryInfo,
+			 const FragData &termData,
+			 const UCArray &tag,
+			 const UCArray &term,
+			 unsigned long stemMethod,
+			 unsigned long termWeight,
+			 UCArrayVector &equivTerms,
+			 QueryResult &result) {
+  bool needRanks = (queryInfo.sortByRank || queryInfo.needRankInfo);
+  
+  result.Clear();
+
+  // log (N / ft)
+  unsigned long N = indexData.levels.levelInfo[indexData.curLevel].numEntries;
+  float wordLog = log((double)N / (double)termData.matchDocs);
+
+  // Wqt = fqt * log (N / ft)
+  // note: terms are allowed to have a weight of zero so
+  // they can be excluded from the ranking
+  float Wqt = termWeight * wordLog;
+
+  // Wdt = fdt * log (N / ft)
+  float Wdt;
+  
+  unsigned long termDataI = 0;
+  unsigned long termDataSize = termData.fragNums.size();
+  unsigned long levelDocNum = 0;
+  
+  unsigned long termDocFreq = 0;
+  unsigned long lastLevelDocNum = 0;
+  unsigned long overallwordfreq = 0;
+  
+  while (termDataI < termDataSize) {
+    if (indexData.levelConverter.FragToLevel (termData.fragNums[termDataI],
+					      levelDocNum)) {
+      if (levelDocNum != lastLevelDocNum) {
+	if (lastLevelDocNum > 0) {
+	  // add this doc information
+	  if (needRanks) {
+	    Wdt = termDocFreq * wordLog;
+	    result.ranks.push_back (Wqt * Wdt);
+	  }
+	  result.docs.push_back (lastLevelDocNum);
+	}
+	
+	lastLevelDocNum = levelDocNum;
+	termDocFreq = 0;
+      }
+
+      if (needRanks){
+	termDocFreq += termData.fragFreqs[termDataI];
+	overallwordfreq += termData.fragFreqs[termDataI];
+      }
+    }
+    ++termDataI;
+  }
+
+  if (lastLevelDocNum > 0) {
+    // add the last document information
+    if (needRanks) {
+      Wdt = termDocFreq * wordLog;
+      result.ranks.push_back (Wqt * Wdt);
+    }
+    result.docs.push_back (lastLevelDocNum);
+  }
+
+  // add the term frequency information
+  if (queryInfo.needTermFreqs) {
+    TermFreqData termFreqData;
+    termFreqData.tag = tag;
+    termFreqData.term = term;
+    termFreqData.stemMethod = stemMethod;
+    termFreqData.equivTerms = equivTerms;
+    termFreqData.matchDocs = termData.matchDocs;
+    termFreqData.termFreq = overallwordfreq; // will be zero if needRankInfo 
+                                              //not true
+    result.termFreqs.push_back (termFreqData);
+  }
+}
+
+void AndFragsToQueryResult (IndexData &indexData,
+			    const QueryInfo &queryInfo,
+			    const FragData &termData,
+			    const UCArray &tag,
+			    const UCArray &term,
+			    unsigned long stemMethod,
+			    unsigned long termWeight,
+			    UCArrayVector &equivTerms,
+			    QueryResult &result) {
+  bool needRanks = (queryInfo.sortByRank || queryInfo.needRankInfo);
+  
+  // log (N / ft)
+  float wordLog =
+    log((double)indexData.levels.levelInfo[indexData.curLevel].numEntries/
+	(double)termData.matchDocs);
+
+  // Wqt = fqt * log (N / ft)
+  // note: terms are allowed to have a weight of zero so
+  // they can be excluded from the ranking
+  float Wqt = termWeight * wordLog;
+
+  // Wdt = fdt * log (N / ft)
+  float Wdt;
+  
+  unsigned long termDataI = 0;
+  unsigned long termDataSize = termData.fragNums.size();
+  unsigned long levelDocNum = 0;
+  
+  unsigned long termDocFreq = 0;
+  unsigned long lastLevelDocNum = 0;
+  unsigned long overallwordfreq = 0;
+  unsigned long resultI = 0;
+  unsigned long resultSize = result.docs.size();
+  unsigned long resultOutI = 0;
+  
+  
+  while (termDataI < termDataSize) {
+    if (indexData.levelConverter.FragToLevel (termData.fragNums[termDataI],
+					      levelDocNum)) {
+      if (levelDocNum != lastLevelDocNum) {
+	if (lastLevelDocNum > 0) {
+	  // add this doc information
+	  Wdt = termDocFreq * wordLog;
+	  
+	  // find this document number
+	  while (resultI < resultSize &&
+		 result.docs[resultI] < lastLevelDocNum)
+	    ++resultI;
+	  
+	  // store the result
+	  if (resultI < resultSize && result.docs[resultI] == lastLevelDocNum) {
+	    result.docs[resultOutI] = lastLevelDocNum;
+	    if (needRanks)
+	      result.ranks[resultOutI] = result.ranks[resultI] + Wqt * Wdt;
+	    ++resultI;
+	    ++resultOutI;
+	  }
+	}
+	
+	lastLevelDocNum = levelDocNum;
+	termDocFreq = 0;
+      }
+
+      if (needRanks)
+	termDocFreq += termData.fragFreqs[termDataI];
+     overallwordfreq += termData.fragFreqs[termDataI]; 
+    }
+    
+    ++termDataI;
+  } // while
+
+  if (lastLevelDocNum > 0) {
+    // add the last document information
+    Wdt = termDocFreq * wordLog;
+
+    // find this document number
+    while (resultI < resultSize &&
+	   result.docs[resultI] < lastLevelDocNum)
+      ++resultI;
+    
+    // store the result
+    if (resultI < resultSize && result.docs[resultI] == lastLevelDocNum) {
+      result.docs[resultOutI] = lastLevelDocNum;
+      if (needRanks)
+	result.ranks[resultOutI] = result.ranks[resultI] + Wqt * Wdt;
+      ++resultI;
+      ++resultOutI;
+    }
+  }
+
+  // remove unneeded entries
+  result.docs.erase (result.docs.begin()+resultOutI, result.docs.end());
+  if (needRanks)
+    result.ranks.erase (result.ranks.begin()+resultOutI, result.ranks.end());
+  else
+    result.ranks.erase (result.ranks.begin(), result.ranks.end());
+  
+  // add the term frequency information
+  if (queryInfo.needTermFreqs) {
+    TermFreqData termFreqData;
+    termFreqData.tag = tag;
+    termFreqData.term = term;
+    termFreqData.stemMethod = stemMethod;
+    termFreqData.equivTerms = equivTerms;
+    termFreqData.matchDocs = termData.matchDocs;
+    termFreqData.termFreq = overallwordfreq;
+    result.termFreqs.push_back (termFreqData);
+  }
+}
+
+
+void RemoveUnwantedResults (IndexData &indexData,
+			    const QueryInfo &queryInfo,
+			    const FragData &termData,
+			    QueryResult &result) {
+  bool needRanks = (queryInfo.sortByRank || queryInfo.needRankInfo);
+
+  unsigned long termDataI = 0;
+  unsigned long termDataSize = termData.fragNums.size();
+  unsigned long levelDocNum = 0;
+  
+  unsigned long lastLevelDocNum = 0;
+
+  unsigned long resultI = 0;
+  unsigned long resultSize = result.docs.size();
+  unsigned long resultOutI = 0;
+  
+  while (termDataI < termDataSize) {
+    if (indexData.levelConverter.FragToLevel (termData.fragNums[termDataI],
+					      levelDocNum)) {
+      if (levelDocNum != lastLevelDocNum) {
+	if (lastLevelDocNum > 0) {
+	  // find this document number
+	  while (resultI < resultSize &&
+		 result.docs[resultI] < lastLevelDocNum)
+	    ++resultI;
+	  
+	  // store the result
+	  if (resultI < resultSize && result.docs[resultI] == lastLevelDocNum) {
+	    result.docs[resultOutI] = lastLevelDocNum;
+	    if (needRanks)
+	      result.ranks[resultOutI] = result.ranks[resultI];
+	    ++resultI;
+	    ++resultOutI;
+	  }
+	}
+	
+	lastLevelDocNum = levelDocNum;
+      }
+    }
+    
+    ++termDataI;
+  }
+
+  if (lastLevelDocNum > 0) {
+    // find this document number
+    while (resultI < resultSize &&
+	   result.docs[resultI] < lastLevelDocNum)
+      ++resultI;
+    
+    // store the result
+    if (resultI < resultSize && result.docs[resultI] == lastLevelDocNum) {
+      result.docs[resultOutI] = lastLevelDocNum;
+      if (needRanks) 
+	result.ranks[resultOutI] = result.ranks[resultI];
+      ++resultI;
+      ++resultOutI;
+    }
+  }
+
+  // remove unneeded entries
+  result.docs.erase (result.docs.begin()+resultOutI, result.docs.end());
+  if (needRanks)
+    result.ranks.erase (result.ranks.begin()+resultOutI, result.ranks.end());
+  else
+    result.ranks.erase (result.ranks.begin(), result.ranks.end());
+}
+
+
+
+//--------------------------------------------------------------
+// functions to support full text browse
+
+void FindNearestWordNumber (IndexData &indexData,
+			    const UCArray &term,
+			    unsigned long &number) {
+
+    // find the word number for this term
+    unsigned long wordElNum = 0;
+    unsigned long numLevels = indexData.bdh.num_levels;
+    word_block_dict_el wordDictEl;
+    wordDictEl.SetNumLevels (numLevels);
+    if (NearestSearchWordBlockDictEl (indexData.dictFile, indexData.biWords,
+				      indexData.bdh.entries_per_wblk,
+				      indexData.bdh.word_dict_size,
+				      numLevels, term, wordDictEl, wordElNum))
+      number = wordElNum;
+
+}
+
+void GetTermList(IndexData &indexData,
+		 unsigned long startTerm,
+		 unsigned long numTerms,
+		 TermFreqArray &terms) {
+
+  word_block_dict_el_array wordBlocks; // = new word_block_dict_el_array();
+  TermFreqData termdata;
+
+  terms.erase(terms.begin(), terms.end());
+
+  SearchWordBlockDictElNumRange (indexData.dictFile, indexData.biWords,
+				 indexData.bdh.entries_per_wblk,
+				 indexData.bdh.word_dict_size,
+				 indexData.bdh.num_levels, startTerm,
+				 numTerms, wordBlocks);
+
+  word_block_dict_el_array::iterator here = wordBlocks.begin();
+  word_block_dict_el_array::iterator end = wordBlocks.end();
+
+  while (here != end) {
+    termdata.Clear();
+    termdata.term = (*here).el;
+    termdata.termFreq = (*here).freq;
+    terms.push_back(termdata);
+    ++here;
+  }
+
+}
+
+void GetTermList(IndexData &indexData,
+		 unsigned long startTerm,
+		 unsigned long numTerms,
+		 UCArrayVector &terms) {
+
+  
+  
+  SearchWordBlockDictElNumRange (indexData.dictFile, indexData.biWords,
+				 indexData.bdh.entries_per_wblk,
+				 indexData.bdh.word_dict_size,
+				 indexData.bdh.num_levels, startTerm,
+				 numTerms, terms);
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Terms.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Terms.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Terms.h	(revision 10506)
@@ -0,0 +1,215 @@
+/**************************************************************************
+ *
+ * Terms.h -- Query related functions
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef TERMS_H
+#define TERMS_H
+
+#include "IndexData.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+class QueryInfo {
+public:
+  // general query information
+  UCArray docLevel;
+  unsigned long maxDocs; // 0 = all
+  bool sortByRank;
+  bool exactWeights;
+
+  // information need to return
+  bool needRankInfo;
+  bool needTermFreqs;
+
+  void Clear ();
+  QueryInfo () { Clear (); }
+};
+
+
+class TermFreqData {
+public:
+  UCArray tag;  // level tag or query tag
+  UCArray term; // unstemmed term
+  int stemMethod;
+  UCArrayVector equivTerms; // the stemmed and casefolded variants of the term
+  unsigned long matchDocs; // tf for level - num levels
+			   // containing this term
+  unsigned long termFreq;  // overall term freq - num words that
+				// are this term
+  void Clear ();
+  TermFreqData () { Clear (); }
+};
+
+ostream &operator<< (ostream &s, const TermFreqData &t);
+bool operator== (const TermFreqData &t1, const TermFreqData &t2);
+
+typedef vector<TermFreqData> TermFreqArray;
+
+
+typedef vector<float> RankArray;
+typedef vector<unsigned long> DocNumArray;
+
+class QueryResult {
+public:
+  DocNumArray docs;
+  RankArray ranks; // used for accumulators during query
+  
+  TermFreqArray termFreqs;
+
+  unsigned long actualNumDocs;
+  void Clear ();
+  QueryResult ();
+  void printShort(ostream &s);
+};
+
+ostream &operator<< (ostream &s, const QueryResult &r);
+bool operator== (const QueryResult &r1, const QueryResult &r2);
+
+typedef vector<unsigned long> FragNumArray;
+typedef vector<unsigned long> FragFreqArray;
+
+class FragData {
+public:
+  unsigned long matchDocs;    // ft for level
+  FragNumArray fragNums;
+  FragFreqArray fragFreqs;
+
+  void Clear ();
+  FragData () { Clear (); }
+};
+
+
+class FragRange {
+public:
+  unsigned long rangeStart;
+  unsigned long rangeEnd;
+
+  void Clear () { rangeStart = rangeEnd = 0; }
+  FragRange () { Clear (); }
+};
+
+typedef vector<FragRange> FragRangeArray;
+
+
+
+void FindWordNumbers (IndexData &indexData,
+		      const UCArray &term,
+		      unsigned long stemMethod,
+		      vector<unsigned long> &equivWords);
+
+void ReadTermFragData (IndexData &indexData,
+		       bool needFragFreqs,
+		       unsigned long termNum,
+		       FragData &fragData,
+		       FragRangeArray *fragLimits,
+		       UCArray &termWord);
+
+void CombineFragData (bool needFragFreqs,
+		      const FragData &f1,
+		      const FragData &f2,
+		      FragData &outFragData);
+
+// output will be in fragData (as this is an and operation)
+void AndCombineFragData (bool needFragFreqs,
+			 FragData &fragData,
+			 const FragData &comFragData,
+			 signed long startRange,
+			 signed long endRange,
+			 const FragRangeArray *fragLimits);
+
+void FragsToQueryResult (IndexData &indexData,
+			 const QueryInfo &queryInfo,
+			 const FragData &termData,
+			 const UCArray &tag,
+			 const UCArray &term,
+			 unsigned long stemMethod,
+			 unsigned long termWeight,
+			 UCArrayVector &equivTerms,
+			 QueryResult &result);
+
+void AndFragsToQueryResult (IndexData &indexData,
+			    const QueryInfo &queryInfo,
+			    const FragData &termData,
+			    const UCArray &tag,
+			    const UCArray &term,
+			    unsigned long stemMethod,
+			    unsigned long termWeight,
+			    UCArrayVector &equivTerms,
+			    QueryResult &result);
+
+void RemoveUnwantedResults (IndexData &indexData,
+			    const QueryInfo &queryInfo,
+			    const FragData &termData,
+			    QueryResult &result);
+
+//-----------------------------------------------------------------
+// new QueryResult class to handle retrieval of doc and level nums.
+// Use this class with extended version of MGQuery
+
+class ExtQueryResult : public QueryResult {
+public:
+  DocNumArray levels; // used for returning a different granularity, eg
+  // search sections but return Document numbers, or search Documents, 
+  // return Section numbers.
+ 
+  void Clear ();
+  ExtQueryResult ();
+};
+
+ostream &operator<< (ostream &s, const ExtQueryResult &r);
+bool operator== (const ExtQueryResult &r1, const ExtQueryResult &r2);
+
+//------------------------------------------------------------
+// new functions to handle full text browse
+
+class BrowseQueryResult {
+ public:
+  TermFreqArray termFreqs;
+  void Clear();
+  BrowseQueryResult ();
+
+};
+
+
+ostream &operator<< (ostream &s, const BrowseQueryResult &r);
+bool operator== (const BrowseQueryResult &r1, const BrowseQueryResult &r2);
+
+void FindNearestWordNumber (IndexData &indexData,
+			    const UCArray &term,
+			    unsigned long &number);
+
+void GetTermList(IndexData &indexData,
+		 unsigned long startTerm,
+		 unsigned long numTerms,
+		 TermFreqArray &terms);
+
+void GetTermList (IndexData &indexData,
+		 unsigned long startTerm,
+		 unsigned long numTerms,
+		 UCArrayVector &terms);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextEl.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextEl.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextEl.cpp	(revision 10506)
@@ -0,0 +1,211 @@
+/**************************************************************************
+ *
+ * TextEl.cpp -- Data structures for parsed documents
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "TextEl.h"
+#include "ctype.h"
+
+#define REC_TERM   '\002'
+#define PARA_TERM  '\003'
+
+
+void TextEl::Clear () {
+  elType = TextE;
+  tagName.erase (tagName.begin(), tagName.end());
+  text.erase (text.begin(), text.end());
+}
+
+
+static bool ReadTextTag (FileBuf &buf, TextEl &el) {
+  // we must have some sort of tag
+  unsigned char c;
+  if (!buf.Peek(c)) return false;
+  
+  // get the '<'
+  if (c != '<') return false;
+  el.text.push_back (c);
+  if (!buf.Next() || !buf.Peek (c)) return false;
+  
+  // see if we have a '/'
+  if (c == '/') {
+    // we have a closing tag
+    el.text.push_back (c);
+    if (!buf.Next() || !buf.Peek (c)) return false;
+    el.elType = CloseTagE;
+  } else {
+    // we have an opening tag
+    el.elType = OpenTagE;
+  }
+
+  // get the tag name
+  while (isalnum(c)) {
+    el.text.push_back (c);
+    el.tagName.push_back (c);
+    if (!buf.Next() || !buf.Peek (c)) return false;
+  }
+  
+  // get everything up to the closing '>'
+  while (c != '>') {
+    el.text.push_back (c);
+    if (!buf.Next() || !buf.Peek (c)) return false;
+  }
+
+  // get the closing '>'
+  el.text.push_back (c);
+  buf.Next();
+
+  // if there is no tag name then make this a text element
+  if (el.tagName.empty()) el.elType = TextE;
+  
+  return true;
+}
+
+static void ToggleParaTag (TextEl &el, bool &compatInPara) {
+  SetCStr (el.tagName, "Paragraph", 9);
+  el.text.erase (el.text.begin(), el.text.end());
+  if (compatInPara) {
+    el.elType = CloseTagE;
+    el.text.push_back (PARA_TERM);
+  } else el.elType = OpenTagE;
+  compatInPara = !compatInPara;
+}
+
+static void SetRecTag (TextEl &el, TextElType elType) {
+  el.elType = elType;
+  SetCStr (el.tagName, "Document", 8);
+  el.text.erase (el.text.begin(), el.text.end());
+  if (elType == CloseTagE)
+    el.text.push_back (REC_TERM);
+}
+
+
+bool ReadTextEl (FileBuf &buf, TextEl &el,
+		 bool compatMode, bool &compatInPara) {
+  el.Clear();
+
+  unsigned char c;
+  if (!buf.Peek (c)) return false;
+
+  if (compatMode) {
+    if (c == PARA_TERM) {
+      ToggleParaTag (el, compatInPara);
+      if (!compatInPara) buf.Next();
+      return true;
+    }
+    if (c == REC_TERM) {
+      if (compatInPara) {
+	// need to close this paragraph
+	ToggleParaTag (el, compatInPara);
+	return true;
+      }
+      // can close this document
+      buf.Next();
+      SetRecTag (el, CloseTagE);
+      return true;
+    }
+    if (!compatInPara) {
+      // need to open a paragraph
+      ToggleParaTag (el, compatInPara);
+      return true;
+    }
+  }
+  
+  // see if we have some sort of tag
+  if (c == '<') return ReadTextTag (buf, el);
+
+  // read in a text element
+  el.elType = TextE;
+  while (c != '<' && !(compatMode && (c == PARA_TERM || c == REC_TERM))) {
+    el.text.push_back (c);
+    if (!buf.Next() || !buf.Peek (c)) break;
+  }
+
+  return true;
+}
+
+static void AddTextEl (TextElArray &doc, unsigned long &docLen,
+		       const TextEl &el) {
+  doc.push_back (el);
+  docLen += el.text.size();
+
+//    cout << "elType:  " << el.elType << "\n";
+//    cout << "tagName: " << el.tagName << "\n";
+//    cout << "text:    \"" << el.text << "\"\n\n";
+}
+
+
+bool ReadDoc (FileBuf &buf, const UCArray &docTag,
+	      TextElArray &doc, unsigned long &docLen,
+	      bool compatMode) {
+  bool compatInPara = false;
+  bool foundDocEl = false;
+  TextEl el;
+  
+  doc.erase (doc.begin(), doc.end());
+  docLen = 0;
+
+  if (compatMode) {
+    // add <Document><Paragraph>
+    SetRecTag (el, OpenTagE);
+    AddTextEl (doc, docLen, el);
+    ToggleParaTag (el, compatInPara);
+    AddTextEl (doc, docLen, el);
+    
+  } else {
+    // look for an opening docTag
+    do {
+      if (!ReadTextEl (buf, el, compatMode, compatInPara)) return false;
+    } while (el.elType != OpenTagE || el.tagName != docTag);
+    
+    AddTextEl (doc, docLen, el);
+  }
+
+  
+  // get all elements until the closing docTag
+  while (ReadTextEl (buf, el, compatMode, compatInPara)) {
+    foundDocEl = true;
+    AddTextEl (doc, docLen, el);
+    if (el.elType == CloseTagE && el.tagName == docTag)
+      return true;
+  }
+
+  
+  if (compatMode) {
+    if (!foundDocEl) { // end of text
+      doc.erase (doc.begin(), doc.end());
+      return false;
+    }
+
+    // if we got here then the eof was encountered before
+    // the closing document tag
+    if (compatInPara) {
+      // need to close this paragraph
+      ToggleParaTag (el, compatInPara);
+      AddTextEl (doc, docLen, el);
+    }
+    // close this document
+    SetRecTag (el, CloseTagE);
+    AddTextEl (doc, docLen, el);
+  }
+  
+  return true;
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextEl.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextEl.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextEl.h	(revision 10506)
@@ -0,0 +1,62 @@
+/**************************************************************************
+ *
+ * TextEl.h -- Data structures for parsed documents
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef TEXTEL_H
+#define TEXTEL_H
+
+#include "UCArray.h"
+#include "FileBuf.h"
+
+
+enum TextElType {OpenTagE, CloseTagE, TextE};
+
+class TextEl {
+protected:
+  bool ReadTextTag (FileBuf &buf, TextEl &el);
+public:
+  TextElType elType;
+  UCArray tagName;
+  UCArray text; // complete text, including tag
+
+  TextEl () { Clear (); }
+  void Clear ();
+};
+
+
+typedef vector<TextEl> TextElArray;
+
+
+// compatMode parses documents similar to "old mg" -- ie with
+// C-b between documents and C-c between paragraphs
+
+// returns true if a text element could be read
+bool ReadTextEl (FileBuf &buf, TextEl &el,
+		 bool compatMode, bool &compatInPara);
+
+// looks for an opening docTag and reads all text elements up
+// to a corresponding closing docTag. note that this does not
+// hierarchically parse the document so you can't nest documents.
+// returns true if a document could be found
+bool ReadDoc (FileBuf &buf, const UCArray &docTag,
+	      TextElArray &doc, unsigned long &docLen,
+	      bool compatMode=false);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextGet.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextGet.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextGet.cpp	(revision 10506)
@@ -0,0 +1,685 @@
+/**************************************************************************
+ *
+ * TextGet.cpp -- Decompressing the text
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+// is important to be first, so we escape the truncation warning on VC++
+#include "TextGet.h"
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+#include "mg_files.h"
+#include "netorder.h"
+#include "mg_errors.h"
+#include "locallib.h"
+#include "words.h"
+#include "local_strings.h"
+#include "bitio_m_stdio.h"
+
+typedef enum huff_type {lengths, chars};
+
+
+static auxiliary_dict *LoadAuxDict (compression_dict &cd, FILE *text_aux_dict) {
+  auxiliary_dict *ad;
+  int i;
+
+  if (!(ad = new auxiliary_dict))
+    {
+      mg_errno = MG_NOMEM;
+      return (NULL);
+    }
+
+  memset (ad, '\0', sizeof (*ad));
+
+  for (i = 0; i <= 1; ++i)
+    {
+      int j;
+      u_char *pos;
+
+      fread (&ad->afh[i], sizeof (aux_frags_header), 1, text_aux_dict);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(ad->afh[i].num_frags);
+      NTOHUL(ad->afh[i].mem_for_frags);
+
+      if (!(ad->word_data[i] = new u_char[ad->afh[i].mem_for_frags]))
+	{
+	  mg_errno = MG_NOMEM;
+	  delete ad;
+	  return (NULL);
+	}
+      if (!(ad->words[i] = new u_char* [ad->afh[i].num_frags]))
+	{
+	  mg_errno = MG_NOMEM;
+	  delete ad;
+	  return (NULL);
+	}
+
+      fread (ad->word_data[i], ad->afh[i].mem_for_frags, sizeof (u_char),
+	     text_aux_dict);
+
+      pos = ad->word_data[i];
+      for (j = 0; j < (int)ad->afh[i].num_frags; ++j)
+	{
+	  ad->words[i][j] = pos;
+	  pos += *pos + 1;
+	}
+      if (cd.cdh.novel_method == MG_NOVEL_HYBRID)
+	{
+	  int num;
+	  num = 1;
+	  ad->blk_start[i][0] = 0;
+	  ad->blk_end[i][0] = cd.cdh.num_words[i] - 1;
+	  while (num < 33)
+	    {
+	      ad->blk_start[i][num] = ad->blk_end[i][num - 1] + 1;
+	      ad->blk_end[i][num] = ad->blk_start[i][num] +
+		(ad->blk_end[i][num - 1] - ad->blk_start[i][num - 1]) * 2;
+	      ++num;
+	    }
+	}
+    }
+  return (ad);
+}
+
+
+static u_char ***ReadInWords (FILE *dict, compression_dict &cd,
+			      comp_frags_header *cfh, u_char **escape) {
+  int i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+  int num_set[MAX_HUFFCODE_LEN + 1];
+  u_char *next_word[MAX_HUFFCODE_LEN + 1];
+  u_char **vals;
+  u_char ***values;
+  u_char word[MAXWORDLEN + 1];
+  u_char last_word[MAX_HUFFCODE_LEN + 1][MAXWORDLEN + 1];
+
+  lookback = cd.cdh.lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; ++i) {
+    ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+    mem_reqd += cfh->huff_words_size[i];
+  }
+
+  if (!(vals = new u_char* [ptrs_reqd]))
+    return (NULL);
+
+  if (!(values = new u_char** [MAX_HUFFCODE_LEN + 1]))
+    return (NULL);
+
+  if (!(next_word[0] = new u_char[mem_reqd])) 
+    return (NULL);
+
+  cd.MemForCompDict += ptrs_reqd * sizeof (*vals) +
+    (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **) +
+    mem_reqd;
+
+  values[0] = vals;
+  values[0][0] = next_word[0];
+  for (i = 1; i <= cfh->hd.maxcodelen; ++i)
+    {
+      int next_start = (values[i - 1] - vals) +
+      ((cfh->hd.lencount[i - 1] + ((1 << lookback) - 1)) >> lookback);
+      values[i] = &vals[next_start];
+      next_word[i] = next_word[i - 1] + cfh->huff_words_size[i - 1];
+      values[i][0] = next_word[i];
+    }
+
+  memset (num_set, '\0', sizeof (num_set));
+
+  for (i = 0; i < cfh->hd.num_codes; ++i)
+    {
+      register int val, copy;
+      register int len = cfh->hd.clens[i];
+      val = getc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      fread (word + copy + 1, sizeof (u_char), val, dict);
+      *word = val + copy;
+
+      if ((num_set[len] & ((1 << lookback) - 1)) == 0)
+	{
+	  values[len][num_set[len] >> lookback] = next_word[len];
+	  memcpy (next_word[len], word, *word + 1);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    *escape = next_word[len];
+	  next_word[len] += *word + 1;
+	}
+      else
+	{
+	  copy = prefixlen (last_word[len], word);
+	  memcpy (next_word[len] + 1, word + copy + 1, *word - copy);
+	  *next_word[len] = (copy << 4) + (*word - copy);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    *escape = next_word[len];
+	  next_word[len] += (*word - copy) + 1;
+	}
+      memcpy (last_word[len], word, *word + 1);
+      ++num_set[len];
+    }
+  if (cfh->hd.clens)
+    delete []cfh->hd.clens;
+  cfh->hd.clens = NULL;
+  return values;
+}
+
+static int Load_Comp_HuffData(compression_dict &cd, int which, FILE *dict, 
+			      huff_type type) {
+  huff_data * hd;
+  u_long **   vals;
+
+  if (!(hd = new huff_data))
+    return 1;
+  cd.MemForCompDict += sizeof (huff_data);
+  if (Read_Huffman_Data (dict, hd, &cd.MemForCompDict, NULL) == -1)
+    return 2;
+  if (!(vals = Generate_Huffman_Vals (hd, &cd.MemForCompDict)))
+    return 3;
+  if (hd->clens)
+    delete []hd->clens;
+  hd->clens = NULL;
+  if (type == chars)
+    {
+      cd.chars_huff[which] = hd;
+      cd.chars_vals[which] = vals;
+    }
+  else
+    {
+      cd.lens_huff[which] = hd;
+      cd.lens_vals[which] = vals;
+    }
+
+  return 0;
+}
+
+static int Load_Comp_FragsHeader(compression_dict &cd, int which, int getEscape,
+				 FILE *dict) {
+  if (!(cd.cfh[which] = new comp_frags_header))
+    return 1;
+  cd.MemForCompDict += sizeof (*cd.cfh[which]);
+  if (Read_cfh (dict, cd.cfh[which], &cd.MemForCompDict, NULL) == -1)
+    return 2;
+
+  if (!(cd.values[which] = ReadInWords (dict, cd, cd.cfh[which],
+					getEscape == 0 ? NULL : &cd.escape[which])))
+    return 3;
+  
+  return 0;
+}
+
+static bool LoadSlowCompDict (FILE *dict, FILE *aux_dict, compression_dict &cd) {
+  if (dict == NULL) return false;
+
+  int which;
+
+  memset (&cd, '\0', sizeof (compression_dict));
+
+  cd.MemForCompDict = sizeof (compression_dict);
+
+  if (Read_cdh (dict, &cd.cdh, &cd.MemForCompDict, NULL) == -1)
+    return false;
+
+  for (which = 0; which < 2; ++which)
+    switch (cd.cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  if (Load_Comp_FragsHeader(cd, which, 0, dict) != 0)
+	    return false;
+	  cd.escape[which] = NULL;
+
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (cd.cdh.num_words[which])
+	    {
+	      if (Load_Comp_FragsHeader(cd, which, 1, dict) != 0)
+		return false;
+	    }
+
+	  if (Load_Comp_HuffData(cd, which, dict, chars) != 0)
+	    return false;
+
+	  if (Load_Comp_HuffData(cd, which, dict, lengths) != 0)
+	    return false;
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (cd.cdh.num_words[which])
+	    {
+	      if (Load_Comp_FragsHeader(cd, which, 1, dict) != 0)
+		return false;
+	    }
+	  switch (cd.cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      if (Load_Comp_HuffData(cd, which, dict, chars) != 0)
+		return false;
+
+	      if (Load_Comp_HuffData(cd, which, dict, lengths) != 0)
+		return false;
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    }
+	  break;
+	}
+      }
+
+  if (cd.cdh.novel_method == MG_NOVEL_DELTA ||
+      cd.cdh.novel_method == MG_NOVEL_HYBRID)
+    {
+      if (!aux_dict)
+	{
+	  mg_errno = MG_NOFILE;
+	  cd.Clear();
+	  return false;
+	}
+
+      if (!(cd.ad = LoadAuxDict (cd, aux_dict)))
+	{
+	  cd.Clear();
+	  return false;
+	}
+    }
+
+  mg_errno = MG_NOERROR;
+
+  cd.fast_loaded = 0;
+  
+  return true;
+}
+
+
+
+#define WORDNO(p, base) ((((char*)(p))-((char*)(base)))/sizeof(u_char*))
+#define IS_FIXUP(p) ((fixup[WORDNO(p,cd)/8] & (1<<(WORDNO(p,cd) & 7))) != 0)
+
+// fast loading really needs to be totally re-writen. "Unloading" the
+// text data will currently cause a crash because memory is being
+// deleted multiple times (and probably a zillion other reasons).
+static bool LoadFastCompDict (FILE *text_fast_comp_dict, compression_dict &_cd) {
+  if (text_fast_comp_dict == NULL) return false;
+  
+  u_long *p, *end;
+  u_char *fixup;
+  u_long mem;
+  u_long fixup_mem;
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  fread (&mem, sizeof (mem), 1, text_fast_comp_dict);
+  NTOHUL(mem);  /* [RPAP - Jan 97: Endian Ordering] */
+  fread (&fixup_mem, sizeof (fixup_mem), 1, text_fast_comp_dict);
+  NTOHUL(fixup_mem);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  compression_dict *cd;
+  if (!(cd = (compression_dict *)malloc (mem))) {
+    mg_errno = MG_NOMEM;
+    return false;
+  }
+
+  end = (u_long *) (((u_char *) cd) + mem);
+  fread (cd, sizeof (u_char), mem, text_fast_comp_dict);
+
+  if (!(fixup = new u_char[fixup_mem]))
+    {
+      mg_errno = MG_NOMEM;
+      return false;
+    }
+
+  fread (fixup, fixup_mem, sizeof (u_char), text_fast_comp_dict);
+
+  for (p = (u_long *) cd; (u_long) p < (u_long) end; ++p)
+    if (IS_FIXUP (p))
+      {
+	NTOHUL(*p);  /* [RPAP - Jan 97: Endian Ordering] */
+	*p = *p + (u_long) cd;
+      }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  /* cdh */
+  NTOHUL(cd->cdh.dict_type);
+  NTOHUL(cd->cdh.novel_method);
+  for (i = 0; i < TEXT_PARAMS; ++i)
+    NTOHUL(cd->cdh.params[i]);
+  NTOHUL(cd->cdh.num_words[0]);
+  NTOHUL(cd->cdh.num_words[1]);
+  NTOHUL(cd->cdh.num_word_chars[0]);
+  NTOHUL(cd->cdh.num_word_chars[1]);
+  NTOHUL(cd->cdh.lookback);
+  /* cfh */
+  for (i = 0; i <= 1; ++i)
+    {
+      int j;
+
+      NTOHSI(cd->cfh[i]->hd.num_codes);
+      NTOHSI(cd->cfh[i]->hd.mincodelen);
+      NTOHSI(cd->cfh[i]->hd.maxcodelen);
+      for (j = 0; j < MAX_HUFFCODE_LEN + 1; ++j)
+	{
+	  NTOHSI(cd->cfh[i]->hd.lencount[j]);
+	  NTOHUL(cd->cfh[i]->hd.min_code[j]);
+	}
+      NTOHUL(cd->cfh[i]->uncompressed_size);
+      for (j = 0; j < MAX_HUFFCODE_LEN + 1; ++j)
+	NTOHUL(cd->cfh[i]->huff_words_size[j]);
+    }
+  NTOHUL(cd->MemForCompDict);
+  /* ad */
+  if (cd->cdh.novel_method == MG_NOVEL_DELTA ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID)
+    for (i = 0; i <= 1; ++i)
+      {
+	int j;
+	
+	NTOHUL(cd->ad->afh[i].num_frags);
+	NTOHUL(cd->ad->afh[i].mem_for_frags);
+	for (j = 0; j < 33; ++j)
+	  {
+	    NTOHSI(cd->ad->blk_start[i][j]);
+	    NTOHSI(cd->ad->blk_end[i][j]);
+	  }
+      }
+  NTOHSI(cd->fast_loaded);
+
+  delete []fixup;
+
+  // the whole fast comp dict is a bit of a hack so I don't
+  // feel too bad about the next line :-) -- Rodger.
+  _cd = *cd;
+  
+  return true;
+}
+
+
+static bool LoadCompDict (FILE *compDictFile,
+			  FILE *auxDictFile,
+			  FILE *fastCompDictFile,
+			  compression_dict &cd) {
+  // see if we have a fast loading compression dictionary
+  if (fastCompDictFile != NULL)
+    return LoadFastCompDict (fastCompDictFile, cd);
+  
+  // slow compression dictionary
+  return LoadSlowCompDict (compDictFile, auxDictFile, cd);
+}
+
+
+// try to open the dictionary files and load the dictionary
+static bool OpenLoadCompDict (char *textname, compression_dict &cd) {
+  FILE *compDictFile = NULL;
+  FILE *auxDictFile = NULL;
+  FILE *fastCompDictFile = NULL;
+
+  fastCompDictFile = open_file (textname, TEXT_DICT_FAST_SUFFIX,
+				"rb", MAGIC_FAST_DICT, MG_CONTINUE);
+  
+  if (fastCompDictFile == NULL) {
+    compDictFile = open_file (textname, TEXT_DICT_SUFFIX,
+			      "rb", MAGIC_DICT, MG_MESSAGE);
+    auxDictFile =  open_file (textname, TEXT_DICT_AUX_SUFFIX,
+			      "rb", MAGIC_AUX_DICT, MG_CONTINUE);
+  }
+  
+  bool res = LoadCompDict (compDictFile, auxDictFile, fastCompDictFile, cd);
+
+  if (compDictFile != NULL) fclose (compDictFile);
+  if (auxDictFile != NULL) fclose (auxDictFile);
+  if (fastCompDictFile != NULL) fclose (fastCompDictFile);
+  
+  return res;
+}
+
+static bool LoadLevels (char *textname, FTextLevel &levels) {
+  FILE *levelFile = NULL;
+
+  // open the text level file
+  levelFile = open_file (textname, TEXT_LEVEL_SUFFIX,
+			 "rb", MAGIC_TEXT_LEVELS, MG_CONTINUE);
+  if (levelFile == NULL) return false;
+
+  // seek to the appropriate place and read the level information
+  bool res = ((fseek (levelFile, sizeof (u_long), SEEK_SET) == 0) &&
+	      levels.Read (levelFile));
+
+  // close the file
+  fclose (levelFile);
+  
+  return res;
+}
+
+
+TextData::TextData () {
+  // put file pointers in known state first
+  textFile = NULL;
+  textIdxFile = NULL;
+  Clear ();
+}
+
+void TextData::Clear () {
+  cd.Clear(); 
+  textFile = NULL;
+  textIdxFile = NULL;
+  cth.Clear();
+  levels.Clear();
+}
+
+bool TextData::LoadData (char *basepath, char *textname) {
+  
+  if (textname[0] == '\0') return false;
+  
+  // set the basepath
+  set_basepath(basepath);
+  
+  // load the compression dictionary
+  if (!OpenLoadCompDict (textname, cd)) return false;
+
+  // open the compressed text and text index file
+  textFile = open_file (textname, TEXT_SUFFIX, "rb", MAGIC_TEXT, MG_CONTINUE);
+  if (textFile == NULL) return false;
+
+  textIdxFile = open_file (textname, TEXT_IDX_SUFFIX, "rb", MAGIC_TEXI, MG_CONTINUE);
+  if (textIdxFile == NULL) return false;
+
+  // read in the compressed text header
+  if ((fseek (textFile, sizeof (u_long), SEEK_SET) != 0) || !cth.Read (textFile))
+    return false;
+
+  // read in the level information
+  if (!LoadLevels (textname, levels)) return false;
+  
+  return true;
+}
+
+bool TextData::UnloadData () {
+  // close any open files
+  if (textFile != NULL) {
+    fclose (textFile);
+    textFile = NULL;
+  }
+  if (textIdxFile != NULL) {
+    fclose (textIdxFile);
+    textIdxFile = NULL;
+  }
+
+  // do general clear
+  Clear ();
+  
+  return true;  
+}
+
+
+bool GetDocIdx (TextData &td, const UCArray &docLevel,
+		unsigned long docNum, TextIdx &docIdx) {
+  // make sure the text index file was opened successfully
+  if (td.textIdxFile == NULL) return false;
+
+  // read in the index
+  TextLevelInfo &levelInfo = td.levels.levelInfo[docLevel];
+  if (!docIdx.Read (td.textIdxFile, levelInfo, docNum)) return false;
+  
+  return true;
+}
+
+
+
+
+#define MY_HUFF_DECODE(len, code, mcodes)				\
+  do {									\
+    register unsigned long *__min_code = (mcodes);			\
+    register unsigned long *__mclen = __min_code;			\
+    register unsigned long __code = 0;					\
+    do									\
+      {									\
+        __code += __code + buffer.bit();	                  	\
+      }									\
+    while (__code < *++__mclen);					\
+    (len) = __mclen - __min_code;					\
+    (code) = __code - *__mclen;						\
+  } while(0);
+
+
+bool GetDocText (TextData &td, const UCArray &docLevel,
+		 unsigned long docNum, UCArray &docText) {
+  // erase the current text
+  docText.erase (docText.begin(), docText.end());
+
+  // look up the information about this document
+  TextIdx docIdx;
+  if (!GetDocIdx (td, docLevel, docNum, docIdx)) return false;
+
+  // do seek to appropriate position
+  stdio_bitio_buffer buffer (td.textFile);
+  buffer.seek (docIdx.start.byte, docIdx.start.bit);
+  
+  // decompress the document
+  compression_dict &cd = td.cd;
+  auxiliary_dict *ad = cd.ad;
+  int which = docIdx.which;
+  unsigned long num_bits = (docIdx.end.byte*8+(8-docIdx.end.bit)) -
+    (docIdx.start.byte*8+(8-docIdx.start.bit));
+  unsigned long bits = 0;
+
+  if (docText.capacity() < docText.size() + num_bits + 1) {
+    docText.reserve(docText.size() + num_bits + 1);
+  }
+  // keep decoding bits until enough bits have been decoded
+  while (bits < num_bits) {
+    register unsigned code, len;
+    register int r;
+    register u_char *t, *b = NULL;
+    u_char word[MAXWORDLEN + 1];
+    
+    if (cd.cfh[which]) {
+      MY_HUFF_DECODE (len, code, cd.cfh[which]->hd.min_code);
+      bits += len;
+      
+      r = code & ((1 << cd.cdh.lookback) - 1);
+      t = cd.values[which][len][code >> cd.cdh.lookback];
+      
+      /* step through from base pointer */
+      b = word + 1;
+      while (r--) {
+	register int copy = *t >> 4;
+	memcpy (word + copy + 1, t + 1, *t & 0xf);
+	word[0] = copy + (*t & 0xf);
+	t += ((*t) & 0xf) + 1;
+      }
+    } else t = NULL;
+    
+    if (t == cd.escape[which]) {
+      switch (cd.cdh.novel_method) {
+      case MG_NOVEL_HUFFMAN_CHARS:
+	{
+	  int len, i;
+	  int c;
+	  len = buffer.huff_decode(cd.lens_huff[which]->min_code,
+				   cd.lens_vals[which], &bits);
+	  for (i = 0; i < len; ++i) {
+	    c = buffer.huff_decode(cd.chars_huff[which]->min_code,
+				   cd.chars_vals[which], &bits);
+	    docText.push_back (c);
+	  }
+	}
+	break;
+      case MG_NOVEL_DELTA:
+      case MG_NOVEL_HYBRID:
+	{
+	  int idx = 0, len;
+	  u_char *base;
+	  switch (cd.cdh.novel_method)
+	    {
+	    case MG_NOVEL_DELTA:
+	      {
+		idx = buffer.delta_decode (&bits);
+		--idx;
+	      }
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      {
+		int k;
+		k = buffer.gamma_decode (&bits);
+		--k;
+		idx = buffer.binary_decode(ad->blk_end[which][k] -
+					   ad->blk_start[which][k] + 1, 
+					   &bits);
+		idx += ad->blk_start[which][k] - 1;
+	      }
+	      break;
+	    }
+	  base = ad->words[which][idx];
+	  len = *base++;
+	  for (; len; --len)
+	    {
+	      docText.push_back (*base++);
+	    }
+	}
+	break;
+      }
+    }
+    else
+      {
+	/* copy over the matching prefix */
+	r = (*t >> 4);
+	while (r--) {
+	  docText.push_back (*b++);
+	}
+	
+	/* and the stored suffix */
+	r = ((*t) & 0xf);
+	while (r--) {
+	  docText.push_back (*++t);
+	}
+      }
+    which = !which;
+  }
+  
+  buffer.done();
+  
+  return true;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextGet.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextGet.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/TextGet.h	(revision 10506)
@@ -0,0 +1,58 @@
+/**************************************************************************
+ *
+ * TextGet.h -- Decompressing the text
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef TEXTGET_H
+#define TEXTGET_H
+
+#include "text.h"
+#include "FText.h"
+
+
+class TextData {
+public:
+  compression_dict cd;
+  FILE *textFile;
+  FILE *textIdxFile;
+  compressed_text_header cth;
+  FTextLevel levels;
+
+  TextData ();
+  void Clear ();
+
+  // loads compression dictionary, the compressed text header,
+  // and all level informaiton
+  bool LoadData (char *basepath, char *textname);
+  bool UnloadData ();
+};
+
+
+// note: document numbers start at 1
+
+// get information about where a document starts and finishes
+bool GetDocIdx (TextData &td, const UCArray &docLevel,
+		unsigned long docNum, TextIdx &docIdx);
+
+
+// decompress a document's text
+bool GetDocText (TextData &td, const UCArray &docLevel,
+		 unsigned long docNum, UCArray &docText);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/UCArray.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/UCArray.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/UCArray.cpp	(revision 10506)
@@ -0,0 +1,360 @@
+/**************************************************************************
+ *
+ * UCArray.cpp -- vector based string class
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "UCArray.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+void SetCStr (UCArray &text, const char *cStr) {
+  text.erase(text.begin(), text.end());
+  
+  while (*cStr != '\0') {
+    text.push_back (*cStr);
+    ++cStr;
+  }
+}
+
+void SetCStr (UCArray &text, const char *cStr, size_t nSizeHint) {
+  text.erase(text.begin(), text.end());
+
+  // reserve the needed space in advance
+  if (text.capacity() < nSizeHint + 1) {
+    text.reserve(nSizeHint + 1);
+  }
+  while (*cStr != '\0') {
+    text.push_back (*cStr);
+    ++cStr;
+  }
+}
+
+char * GetCStr(const UCArray& text) {
+
+  char *cstr = new char[text.size()+1];
+  UCArray::const_iterator here = text.begin();
+  UCArray::const_iterator end = text.end();
+
+  int i = 0;
+  while (here != end) {
+    cstr[i] = text[i];
+    ++here; ++i;
+  }
+  cstr[i]='\0';
+  return cstr;
+}
+
+bool UCArrayCStrEquals(const UCArray &text, const unsigned char *cStr)
+{
+  if ((cStr == NULL || *cStr == '\0') && text.empty()) return true;
+  UCArray::const_iterator thisUC = text.begin();
+  UCArray::const_iterator endUC = text.end();
+  while (thisUC != endUC && *cStr != '\0') {
+    if (*thisUC != *cStr) return false;
+    ++cStr; ++thisUC;
+  }
+  if (thisUC == endUC && *cStr == '\0') return true;
+  return false;
+}
+
+ostream &operator<<(ostream &s, const UCArray &a) {
+  UCArray::const_iterator here = a.begin();
+  UCArray::const_iterator end = a.end();
+  while (here != end) {
+    s << *here;
+    ++here;
+  }
+
+  return s;
+}
+
+
+bool ReadVarLenUL (FILE *f, unsigned long &n) {
+  register unsigned long temp = 0;
+  register unsigned int bitPos = 0;
+  unsigned char b = 0;
+
+  do {
+    b = fgetc (f);
+    if (feof(f)) return false;
+    temp |= (b & 0x7f) << bitPos;
+    bitPos += 7;
+  } while (b >= 0x80 && bitPos < 32);
+
+  n = temp;
+  
+  return true;
+}
+
+bool WriteVarLenUL (FILE *f, unsigned long n) {
+  register unsigned long temp = n;
+  register unsigned char b = 0;
+  do {
+    b = static_cast<unsigned char> (temp & 0x7f);
+    if (temp >= 0x80) b |= 0x80;
+    fputc (b, f);
+    if (ferror (f) != 0) return false;
+  } while ((temp = temp >> 7) > 0);
+  
+  return true;
+}
+
+
+bool ReadUL (FILE *f, unsigned long &n) {
+  if (fread (&n, sizeof (unsigned long), 1, f) <= 0) return false;
+  NTOHUL (n);
+  return true;
+}
+
+
+bool WriteUL (FILE *f, unsigned long n) {
+  HTONUL (n);
+  return (fwrite (&n, sizeof (unsigned long), 1, f) > 0);
+}
+
+bool ReadF (FILE *f, float &n) {
+  if (fread (&n, sizeof (float), 1, f) <= 0) return false;
+  NTOHF(n);
+  return true;
+}
+
+bool WriteF (FILE *f, float n) {
+  HTONF(n);
+  return (fwrite (&n, sizeof (float), 1, f) > 0);
+}
+
+bool ReadD (FILE *f, double &n) {
+  if (fread (&n, sizeof (double), 1, f) <= 0) return false;
+  NTOHD(n);
+  return true;
+}
+
+bool WriteD (FILE *f, double n) {
+  HTOND(n);
+  return (fwrite (&n, sizeof (double), 1, f) > 0);
+}
+
+bool ReadUCArray (FILE *f, UCArray &a) {
+  // clear the array in preparation
+  a.erase (a.begin(), a.end());
+
+  // read in the array size
+  unsigned long arraySize = 0;
+  if (!ReadVarLenUL (f, arraySize)) return false;
+
+  // reserve the needed space in advance
+  if (a.capacity() < arraySize + 1) {
+    a.reserve(arraySize + 1);
+  }
+
+  // read in the array
+  unsigned char b = 0;
+  while (arraySize > 0) {
+    b = fgetc (f);
+    if (feof(f)) return false;
+    a.push_back (b);
+    
+    --arraySize;
+  }
+  
+  return true;
+}
+
+bool WriteUCArray (FILE *f, const UCArray &a) {
+  // write out the array size
+  if (!WriteVarLenUL (f, a.size())) return false;
+
+  UCArray::const_iterator here = a.begin();
+  UCArray::const_iterator end = a.end();
+  while (here != end) {
+    fputc (*here, f);
+    if (ferror (f) != 0) return false;
+    
+    ++here;
+  }
+  
+  return true;
+}
+
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static unsigned char casecharmap[] = {
+	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
+	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
+	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
+	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
+	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
+	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
+	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
+	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
+	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
+	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
+	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
+	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
+	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
+	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
+};
+
+
+int DictCompare (const UCArray &a1, const UCArray &a2) {
+  unsigned int l1 = a1.size();
+  unsigned int l2 = a2.size();
+  unsigned int l = (l1 < l2) ? l1 : l2;
+  int pos = 0;
+  register int diff = 0;
+
+  UCArray::const_iterator a1Here = a1.begin();
+  UCArray::const_iterator a2Here = a2.begin();
+  
+  while (l--) {
+    if ((diff = casecharmap[*a1Here] - casecharmap[*a2Here]) != 0)
+      return diff;
+    if (pos == 0 && (diff = *a1Here - *a2Here) != 0)
+      pos = diff;
+
+    ++a1Here;
+    ++a2Here;
+  }
+
+  return ((l1 - l2) ? (l1 - l2) : (pos));
+}
+
+// does the first string start with the second?
+bool StartsWith (const UCArray &a1, const UCArray &a2) {
+  unsigned int l1 = a1.size();
+  unsigned int l2 = a2.size();
+  if (l2 > l1) {
+    // if the prefix is longer than the string, it can't start with it
+    return false; 
+  }
+  unsigned int l =l2;
+  UCArray::const_iterator a1Here = a1.begin();
+  UCArray::const_iterator a2Here = a2.begin();
+  
+  while (l--) {
+    if ((*a1Here != *a2Here))
+      return false;
+    ++a1Here;
+    ++a2Here;
+  }
+  return true; // we have successfully matched the whole way
+    
+}
+
+// does the first string start with the second, ignoring case?
+bool StartsWithCasefold(const UCArray &a1, const UCArray &a2) {
+  unsigned int l1 = a1.size();
+  unsigned int l2 = a2.size();
+  if (l2 > l1) {
+    // if the prefix is longer than the string, it can't start with it
+    return false; 
+  }
+  unsigned int l =l2;
+  UCArray::const_iterator a1Here = a1.begin();
+  UCArray::const_iterator a2Here = a2.begin();
+  
+  while (l--) {
+    if (casecharmap[*a1Here] != casecharmap[*a2Here]) 
+      return false;
+    ++a1Here;
+    ++a2Here;
+  }
+  return true; // we have successfully matched the whole way
+    
+}
+
+
+unsigned long PrefixLen (const UCArray &a1, const UCArray &a2) {
+  unsigned long l = (a1.size() < a2.size()) ? a1.size() : a2.size();
+  unsigned long i = 0;
+
+  UCArray::const_iterator a1Here = a1.begin();
+  UCArray::const_iterator a2Here = a2.begin();
+
+  while (i < l && *a1Here == *a2Here) {
+    ++i; ++a1Here; ++a2Here;
+  }
+  
+  return i;
+}
+
+bool WritePreSufStr (FILE *f, const UCArray *prev, const UCArray &a) {
+  unsigned char preLen;
+  unsigned char sufLen;
+  
+  if (prev != NULL) preLen = PrefixLen (*prev, a);
+  else preLen = 0;
+  sufLen = a.size() - preLen;
+
+  // output the prefix length, suffix length, and the suffix
+  fputc (preLen, f);
+  if (ferror(f) != 0) return false;
+  fputc (sufLen, f);
+  if (ferror(f) != 0) return false;
+  char* tmp=GetCStr(a);
+  int ret=(fwrite (tmp+preLen, sizeof (char), sufLen, f) == sufLen);
+  delete []tmp;
+  return (ret != 0);
+}
+
+// a also used for prev
+bool ReadPreSufStr (FILE *f, UCArray &a) {
+  unsigned char preLen = 0;
+  unsigned char sufLen = 0;
+
+  preLen = fgetc(f);
+  sufLen = fgetc(f);
+
+  if (a.size() > preLen) a.erase (a.begin()+preLen, a.end());
+
+  // reserve the needed space in advance
+  if (a.capacity() < a.size() + sufLen + 1) {
+    a.reserve(a.size() + sufLen + 1);
+  }
+
+  while (sufLen > 0) {
+    unsigned char c = fgetc (f);
+    a.push_back (c);
+    --sufLen;
+  }
+
+  return true;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/UCArray.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/UCArray.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/UCArray.h	(revision 10506)
@@ -0,0 +1,131 @@
+/**************************************************************************
+ *
+ * UCArray.h -- vector based string class
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef UCARRAY_H
+#define UCARRAY_H
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+#pragma warning(disable:4786)
+#endif
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if !defined (GSDL_NAMESPACE_BROKEN) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+using namespace std;
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#  include <ospace\std\set>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#  include <set.h>
+#else
+#  include <vector>
+#  include <set>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#include <stdio.h>
+
+
+typedef vector<unsigned char> UCArray;
+
+// functions to manipulate UCArrays
+void SetCStr (UCArray &text, const char *cStr);
+// same as SetCStr but first tries to allocate nSizeHint space (only if needed)
+void SetCStr (UCArray &text, const char *cStr, size_t nSizeHint);
+char * GetCStr(const UCArray& text);
+inline void UCArrayClear (UCArray &a) {
+  a.erase (a.begin(), a.end());
+}
+bool UCArrayCStrEquals(const UCArray &text, const unsigned char *cStr);
+inline bool UCArrayCStrEquals(const UCArray &text, const char *cStr) { return UCArrayCStrEquals(text, (const unsigned char *)cStr); }
+
+// stream operator to print UCArray
+ostream &operator<<(ostream &s, const UCArray &a);
+
+// used for reading and writing unsigned characters
+inline bool ReadUC (FILE *f, unsigned char &c) {
+  return (fread (&c, sizeof (unsigned char), 1, f) == 1);
+}
+inline bool WriteUC (FILE *f, unsigned char c) {
+  return (fwrite (&c, sizeof (unsigned char), 1, f) == 1);
+}
+
+// used for reading and writing variable length unsigned longs
+bool ReadVarLenUL (FILE *f, unsigned long &n);
+bool WriteVarLenUL (FILE *f, unsigned long n);
+
+// used for reading and writing unsigned longs
+bool ReadUL (FILE *f, unsigned long &n);
+bool WriteUL (FILE *f, unsigned long n);
+
+// used for reading and writing floats
+bool ReadF (FILE *f, float &n);
+bool WriteF (FILE *f, float n);
+
+// used for reading and writing doubles
+bool ReadD (FILE *f, double &n);
+bool WriteD (FILE *f, double n);
+
+// used for reading and writing arrays to files
+bool ReadUCArray (FILE *f, UCArray &a);
+bool WriteUCArray (FILE *f, const UCArray &a);
+
+
+// compares the two strings in dictionary order
+int DictCompare (const UCArray &a1, const UCArray &a2);
+
+// does the first string start with the second?
+bool StartsWith(const UCArray &a1, const UCArray &a2);
+// does the first string start with the second, ignoring case?
+bool StartsWithCasefold(const UCArray &a1, const UCArray &a2);
+
+struct LTUCArray {
+  bool operator()(const UCArray &a1, const UCArray &a2) const
+    { return (a1 < a2); }
+};
+
+struct DictLTUCArray {
+  bool operator() (const UCArray &a1, const UCArray &a2) const
+    { return (DictCompare (a1, a2) < 0); }
+};
+
+
+typedef set<UCArray, LTUCArray> UCArraySet;
+typedef vector<UCArray> UCArrayVector;
+
+unsigned long PrefixLen (const UCArray &a1, const UCArray &a2);
+
+// prev == NULL if no previous string
+bool WritePreSufStr (FILE *f, const UCArray *prev, const UCArray &a);
+bool ReadPreSufStr (FILE *f, UCArray &a); // a also used for prev
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/WIN32.MAK
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/WIN32.MAK	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/WIN32.MAK	(revision 10506)
@@ -0,0 +1,202 @@
+###########################################################################
+#
+# win32 makefile -- mgpp\text
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..\..\..
+USE_STLPORT = 0
+DLL = 0
+DLLDEBUG = 0
+STLPATH = "$(GSDLHOME)\packages\windows\stlport\stlport"
+
+CC = cl
+
+CPPFLAGS = -GX
+!IF $(DLL)
+CPPFLAGS = $(CPPFLAGS) -MD
+!ELSE
+!IF ($(DLLDEBUG))
+CPPFLAGS = $(CPPFLAGS) -MDd
+!ENDIF
+!ENDIF
+
+DEFS = -DSHORT_SUFFIX -DSILENT -DHAVE_CONFIG_H -D__WIN32__ -D__STDC__ -D__GNU_LIBRARY__ -D__MSDOS__
+INCLUDES = -I"$(GSDLHOME)\src\mgpp\lib" -I"$(GSDLHOME)"
+!IF $(USE_STLPORT)
+DEFS = $(DEFS) -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = $(INCLUDES) -I$(STLPATH)
+!ENDIF
+
+LDFLAGS =
+
+LIBS = "$(GSDLHOME)\src\mgpp\lib\libmg.lib"
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .c .obj .cpp
+.c.obj:
+	$(COMPILE) $<
+.cpp.obj:
+	$(COMPILE) $<
+
+o = .obj
+e = .exe
+
+SOURCES = \
+  FIvfLevelInfo.cpp        ivf.pass1.cpp            mgpp_invf_dump.cpp       \
+  FText.cpp                ivf.pass2.cpp            mgpp_passes.cpp          \
+  FileBuf.cpp              locallib.cpp             mgpp_perf_hash_build.cpp \
+  FragLevelConvert.cpp     mg.special.cpp           mgpp_stem_idx.cpp        \
+  IndexData.cpp            mgpp_compression_dict.cpp  mgpp_weights_build.cpp   \
+  TagInfo.cpp              mgpp_decompress_text.cpp   stemmer.cpp            \
+  TextEl.cpp               mg_errors.cpp            text.cpp               \
+  TextGet.cpp              mgpp_fast_comp_dict.cpp    text.pass1.cpp         \
+  UCArray.cpp              mg_files.cpp             text.pass2.cpp         \
+  comp_dict.cpp            mgpp_invf_dict.cpp         words.cpp              \
+  invf.cpp                 mgpp_invf_dict_dump.cpp    Weights.cpp            \
+  MGQuery.cpp              Terms.cpp                QueryTester.cpp        \
+  QueryLex.cpp             QueryParser.cpp         \
+  GSDLQueryLex.cpp	   GSDLQueryParser.cpp      Queryer.cpp
+
+
+HEADERS = \
+  FIvfLevelInfo.h     TextEl.h            hash.h              stemmer.h  \
+  FText.h             TextGet.h           invf.h              text.h     \
+  FileBuf.h           UCArray.h           locallib.h          words.h    \
+  FragLevelConvert.h  WordData.h          mg.h                           \
+  IndexData.h         build.h             mg_errors.h                    \
+  TagInfo.h           comp_dict.h         mg_files.h          Weights.h  \
+  MGQuery.h           Terms.h             QueryLex.h          QueryParser.h \
+  GSDLQueryLex.h	GSDLQueryParser.h
+
+EXEC          = mgpp_passes$e mgpp_decompress_text$e mgpp_perf_hash_build$e \
+                mgpp_invf_dump$e mgpp_weights_build$e mgpp_invf_dict$e mgpp_stem_idx$e \
+                mgpp_invf_dict_dump$e mgpp_compression_dict$e mgpp_fast_comp_dict$e \
+                QueryTester$e Queryer$e
+
+all:    $(EXEC) libtextin.lib
+
+PASSES_OBJS = \
+	mgpp_passes$o text.pass1$o comp_dict$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o \
+	words$o invf$o FileBuf$o TextEl$o UCArray$o TagInfo$o \
+        FText$o text$o FIvfLevelInfo$o
+
+mgpp_passes$e: $(PASSES_OBJS)
+	$(LINK) $(PASSES_OBJS) $(LIBS)
+
+
+QUERYER_OBJS = Queryer$o mg_files$o mg_errors$o locallib$o invf$o UCArray$o \
+               FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+               IndexData$o stemmer$o Weights$o TextGet$o text$o FText$o \
+               GSDLQueryParser$o GSDLQueryLex$o words$o
+
+Queryer$e: $(QUERYER_OBJS)
+	$(LINK) $(QUERYER_OBJS) $(LIBS)
+
+QUERY_TESTER_OBJS = QueryTester$o mg_files$o invf$o UCArray$o \
+                    FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+                    IndexData$o stemmer$o Weights$o
+
+QueryTester$e: $(QUERY_TESTER_OBJS)
+	$(LINK) $(QUERY_TESTER_OBJS) $(LIBS)
+
+WEIGHTS_BUILD_OBJS = mgpp_weights_build$o mg_files$o invf$o UCArray$o \
+                     FIvfLevelInfo$o FragLevelConvert$o
+
+mgpp_weights_build$e: $(WEIGHTS_BUILD_OBJS)
+	$(LINK) $(WEIGHTS_BUILD_OBJS) $(LIBS)
+
+COMP_DICT_OBJS = mgpp_compression_dict$o mg_files$o locallib$o
+
+mgpp_compression_dict$e: $(COMP_DICT_OBJS)
+	$(LINK) $(COMP_DICT_OBJS) $(LIBS)
+
+FAST_COMP_OBJS = mgpp_fast_comp_dict$o mg_files$o locallib$o
+
+mgpp_fast_comp_dict$e: $(FAST_COMP_OBJS)
+	$(LINK) $(FAST_COMP_OBJS) $(LIBS)
+
+INVF_DUMP_OBJS = mgpp_invf_dump$o locallib$o mg_files$o invf$o UCArray$o
+
+mgpp_invf_dump$e: $(INVF_DUMP_OBJS)
+	$(LINK) $(INVF_DUMP_OBJS) $(LIBS)
+
+INVF_DICT_OBJS = mgpp_invf_dict$o mg_files$o invf$o UCArray$o
+
+mgpp_invf_dict$e: $(INVF_DICT_OBJS)
+	$(LINK) $(INVF_DICT_OBJS) $(LIBS)
+
+INVF_DICT_DUMP_OBJS = mgpp_invf_dict_dump$o mg_files$o invf$o UCArray$o
+
+mgpp_invf_dict_dump$e: $(INVF_DICT_DUMP_OBJS)
+	$(LINK) $(INVF_DICT_DUMP_OBJS) $(LIBS)
+
+PERF_HASH_OBJS = mgpp_perf_hash_build$o mg_files$o invf$o UCArray$o
+
+mgpp_perf_hash_build$e: $(PERF_HASH_OBJS)
+	$(LINK) $(PERF_HASH_OBJS) $(LIBS)
+
+STEM_IDX_OBJS = mgpp_stem_idx$o mg_files$o stemmer$o \
+                invf$o UCArray$o
+
+mgpp_stem_idx$e: $(STEM_IDX_OBJS)
+	$(LINK) $(STEM_IDX_OBJS) $(LIBS)
+
+DECOMPRESS_TEXT_OBJS = \
+                mgpp_decompress_text$o mg_files$o mg_errors$o \
+                locallib$o text$o UCArray$o TextGet$o FText$o
+
+mgpp_decompress_text$e: $(DECOMPRESS_TEXT_OBJS)
+	$(LINK) $(DECOMPRESS_TEXT_OBJS) $(LIBS)
+
+
+PASS_OBJS = \
+	words$o mgpass$o text.pass1$o comp_dict$o stemmer$o \
+	text.pass2$o locallib$o \
+	ivf.pass1$o ivf.pass2$o mg.special$o mg_files$o
+mgpass$e: $(PASS_OBJS)
+	$(LINK) $(PASS_OBJS) $(LIBS)
+
+install: 
+	if NOT EXIST "$(GSDLHOME)\bin\windows" mkdir "$(GSDLHOME)\bin\windows"
+	for %%i in ($(EXEC)) do \
+	  copy %%i "$(GSDLHOME)\bin\windows"
+
+LIB_OBJS = mg_files$o  mg_errors$o locallib$o invf$o UCArray$o \
+           FIvfLevelInfo$o FragLevelConvert$o Terms$o MGQuery$o \
+           IndexData$o stemmer$o Weights$o TextGet$o text$o FText$o \
+           GSDLQueryParser$o GSDLQueryLex$o words$o
+
+libtextin.lib: $(LIB_OBJS)
+	if EXIST libtextin.lib del libtextin.lib
+	lib /out:libtextin.lib $(LIB_OBJS)
+
+clean:
+	del *$o 
+	del $(EXEC)
+	del libtextin.lib
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Weights.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Weights.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Weights.cpp	(revision 10506)
@@ -0,0 +1,126 @@
+/**************************************************************************
+ *
+ * Weights.cpp -- Dealing with document weights
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "UCArray.h"
+#include "Weights.h"
+#include "sysfuncs.h"
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+
+ApproxWeightsData::ApproxWeightsData () {
+  weightBuf = NULL;
+  table = NULL;
+  Free();
+}
+
+ApproxWeightsData::~ApproxWeightsData () {
+  Free ();
+}
+
+void ApproxWeightsData::Free () {
+  bits = 0;
+  mask = 0;
+  L = 0.0;
+  B = 0.0;
+  numLevelDocs = 0;
+  if (weightBuf != NULL) {
+    delete [] weightBuf;
+    weightBuf = NULL;
+  }
+  if (table != NULL) {
+    delete [] table;
+    table = NULL;
+  }
+}
+
+bool ApproxWeightsData::Read (FILE *approxWeightsFile, unsigned long diskPtr,
+			      unsigned long _numLevelDocs) {
+  Free ();
+  
+  // go to the appropriate place in the weights file
+  fseek (approxWeightsFile, diskPtr, SEEK_SET);
+
+  // read in approx weights parameters
+  ReadUC (approxWeightsFile, bits);
+  ReadD (approxWeightsFile, L);
+  ReadD (approxWeightsFile, B);
+
+  mask = (bits == 32) ? 0xffffffff : (1 << bits) - 1;
+  numLevelDocs = _numLevelDocs;
+
+  // allocate buffer for the weights
+  unsigned long arrSize = (bits*numLevelDocs+sizeof(unsigned long)-1) / 32;
+  weightBuf = new unsigned long[arrSize];
+
+  // read in the weights
+  unsigned long i;
+  for (i=0; i<arrSize; ++i) {
+    ReadUL (approxWeightsFile, weightBuf[i]);
+  }
+
+  // create precomputed table of values if it will be small enough
+  // (if not small enough table == NULL
+  if (bits <= 12) {
+    unsigned long i, tableSize = (1 << bits);
+    table = new float[tableSize];
+    table[0] = L;
+    for (i = 1; i < tableSize; ++i)
+      table[i] = table[i - 1] * B;
+  }
+
+  return true;
+}
+
+float ApproxWeightsData::GetLowerApproxDocWeight (unsigned long levelDocNum) {
+  // sanity check
+  if (bits == 0 || weightBuf == NULL) return 1.0;
+
+  register unsigned long c, pos;
+  register unsigned long *dw;
+
+  // get the compressed version of the weight
+  pos = levelDocNum * bits;
+  dw = &weightBuf[pos / MAXBITS];
+  pos &= (MAXBITS - 1);
+  c = *dw >> pos;
+  if (pos + bits > MAXBITS)
+    c |= *(dw + 1) << (MAXBITS - pos);
+  c &= mask;
+
+  // decompress the weight
+  if (table != NULL) return table[c];
+  return (L * pow (B, (double) c));
+}
+
+
+
+float GetExactDocWeight (FILE *exactWeightsFile, unsigned long diskPtr,
+			 unsigned long levelDocNum) {
+  // go to the appropriate place in the weights file
+  fseek (exactWeightsFile, diskPtr+sizeof(float)*levelDocNum, SEEK_SET);
+
+  // read in the exact weight
+  float weight;
+  ReadF (exactWeightsFile, weight);
+  
+  return weight;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Weights.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Weights.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/Weights.h	(revision 10506)
@@ -0,0 +1,56 @@
+/**************************************************************************
+ *
+ * Weights.h -- Dealing with document weights
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef WEIGHTS_H
+#define WEIGHTS_H
+
+#include <stdio.h>
+
+
+class ApproxWeightsData {
+public:
+  unsigned char bits;
+  unsigned long mask;
+  double L;
+  double B;
+  unsigned long numLevelDocs;
+  unsigned long *weightBuf;
+  float *table;   // precomputed translation table
+  
+  ApproxWeightsData ();
+  ~ApproxWeightsData ();
+
+  void Free (); // frees any allocated memory
+  
+  bool Read (FILE *approxWeightsFile, unsigned long diskPtr,
+	     unsigned long _numLevelDocs);
+
+  float GetLowerApproxDocWeight (unsigned long levelDocNum);
+};
+
+
+// diskPtr points to the start of the exact document weights
+// for this level
+float GetExactDocWeight (FILE *exactWeightsFile, unsigned long diskPtr,
+			 unsigned long levelDocNum);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/WordData.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/WordData.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/WordData.h	(revision 10506)
@@ -0,0 +1,47 @@
+/**************************************************************************
+ *
+ * WordData.h -- 
+ * Copyright (C) 1999  NZDL
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+class WordData
+{
+
+ public:
+  unsigned long docCount;
+  unsigned long wordCount;
+
+  inline void read(FILE *f)
+    {
+      fread((char *) &docCount, sizeof(docCount), 1, f);
+      fread((char *) &wordCount, sizeof(wordCount), 1, f);
+
+      NTOHUL(docCount);
+      NTOHUL(wordCount);
+    }
+
+  inline unsigned long documents()
+    {
+      return docCount;
+    }
+
+  inline int words()
+    {
+      return wordCount;
+    }
+};
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/build.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/build.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/build.h	(revision 10506)
@@ -0,0 +1,86 @@
+/**************************************************************************
+ *
+ * build.h -- Global information for the passes of mg_passes
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+
+#ifndef H_BUILD
+#define H_BUILD
+
+#include "longlong.h"
+
+#include "TextEl.h"
+#include "TagInfo.h"
+
+
+int init_special (const TagInfo &tagInfo, char *file_name);
+int init_text_1 (const TagInfo &tagInfo, char *file_name);
+int init_text_2 (const TagInfo &tagInfo, char *file_name);
+int init_ivf_1 (const TagInfo &tagInfo, char *file_name);
+int init_ivf_2 (const TagInfo &tagInfo, char *file_name);
+/*
+ * file_name  IN      The name of the dictionary file
+ * 
+ * returns      COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot read file
+ */
+
+
+
+
+
+int process_special (const TagInfo &tagInfo, const TextElArray &doc);
+int process_text_1 (const TagInfo &tagInfo, const TextElArray &doc);
+int process_text_2 (const TagInfo &tagInfo, const TextElArray &doc);
+int process_ivf_1 (const TagInfo &tagInfo, const TextElArray &doc);
+int process_ivf_2 (const TagInfo &tagInfo, const TextElArray &doc);
+/*
+ * returns      COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot read file
+ *
+ * The calling routine is responsible for ensuring that s_out is long 
+ * enough.
+ */
+
+
+
+
+
+int done_special (const TagInfo &tagInfo, char *filename);
+int done_text_1 (const TagInfo &tagInfo, char *filename);
+int done_text_2 (const TagInfo &tagInfo, char *filename);
+int done_ivf_1 (const TagInfo &tagInfo, char *filename);
+int done_ivf_2 (const TagInfo &tagInfo, char *filename);
+/*
+ * returns    COMPALLOK for all ok,
+ *              COMPERROR for any error.  e.g. cannot write file
+ */
+
+
+
+
+extern unsigned long invf_buffer_size;
+/*
+ * The amount of memory to allocate to the invertion buffer.
+ */
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/comp_dict.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/comp_dict.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/comp_dict.cpp	(revision 10506)
@@ -0,0 +1,229 @@
+/**************************************************************************
+ *
+ * comp_dict.cpp -- Functions for loading the compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "huffman.h"
+#include "local_strings.h"
+#include "memlib.h"
+#include "messages.h"
+
+#include "mg.h"
+#include "hash.h"
+#include "text.h"
+#include "comp_dict.h"
+#include "locallib.h"
+#include "mg_files.h"
+
+compression_dict_header cdh;
+compressed_text_header cth;
+comp_frags_header cfh[2];
+
+dict_hash_table *ht[2];
+
+huff_data char_huff[2];
+huff_data lens_huff[2];
+u_long *char_codes[2], *lens_codes[2];
+u_long Words_disk = 0;
+u_long Chars_disk = 0;
+
+
+static dict_hash_table *
+ReadInWords (FILE * dict, comp_frags_header * cfh,
+	     int esc)
+{
+  int i;
+  u_char *allwords, *prev = NULL;
+  dict_hash_table *ht;
+  u_char **words;
+  u_long ht_size;
+
+  ht_size = prime (cfh->hd.num_codes * HASH_RATIO);
+  if (!(ht = (dict_hash_table *) Xmalloc (sizeof (dict_hash_table) +
+		                            (ht_size - 1) * sizeof (ht->table[0]))))
+    {
+      Message ("no memory for hash_table\n");
+      return NULL;
+    }
+
+  ht->size = ht_size;
+  ht->hd = &cfh->hd;
+
+  if (!(ht->codes = Generate_Huffman_Codes (&cfh->hd, NULL)))
+    {
+      Message ("no memory for huffman codes\n");
+      return NULL;
+    }
+
+  if (!(ht->words = (u_char **) Xmalloc (sizeof (u_char *) * cfh->hd.num_codes)))
+    {
+      Message ("no memory for word pointers\n");
+      return NULL;
+    }
+  words = ht->words;
+
+  memset (ht->table, '\0', ht_size * sizeof (ht->table[0]));
+
+  if (!(allwords = (u_char *) Xmalloc (sizeof (u_char) * cfh->uncompressed_size)))
+    {
+      Message ("no memory for words\n");
+      return NULL;
+    }
+
+  for (i = 0; i < cfh->hd.num_codes; ++i, ++words)
+    {
+      register int val, copy;
+      val = fgetc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      *words = allwords;
+
+      memcpy (allwords + 1, prev + 1, copy);
+      fread (allwords + copy + 1, sizeof (u_char), val, dict);
+      *allwords = val + copy;
+
+      Words_disk += val + 1;
+
+      /* insert into the hash table */
+      if (i < cfh->hd.num_codes - esc)
+	{
+	  register u_char **wptr;
+	  register unsigned long tsize = ht->size;
+	  register unsigned long hashval, step;
+
+	  HASH (hashval, step, allwords, tsize);
+
+	  wptr = ht->table[hashval];
+	  for (; wptr;)
+	    {
+	      hashval += step;
+	      if (hashval >= tsize)
+		hashval -= tsize;
+	      wptr = ht->table[hashval];
+	    }
+	  ht->table[hashval] = words;
+	}
+      prev = allwords;
+      allwords += *allwords + 1;
+    }
+  return ht;
+}
+
+inline int LoadWords(FILE *dict, int which)
+{
+  if (Read_cfh (dict, &cfh[which], NULL, &Words_disk) == -1)
+    return 1;
+  
+  if (!(ht[which] = ReadInWords (dict, &cfh[which], 0)))
+    return 1;
+
+  return 0;
+}
+
+inline int LoadHuffmanCodes(FILE *dict, int which)
+{
+  if (Read_Huffman_Data (dict, &char_huff[which], NULL,
+			 &Chars_disk) == -1)
+    return 1;
+  if (!(char_codes[which] =
+	Generate_Huffman_Codes (&char_huff[which], NULL)))
+    return 2;
+  if (Read_Huffman_Data (dict, &lens_huff[which], NULL,
+			 &Chars_disk) == -1)
+    return 3;
+  if (!(lens_codes[which] =
+	Generate_Huffman_Codes (&lens_huff[which], NULL)))
+    return 4;
+
+  return 0;
+}
+
+int 
+LoadCompressionDictionary (char *dict_file_name)
+{
+  FILE *dict;
+  int which;
+  if (!(dict = open_named_file (dict_file_name, "rb", MAGIC_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    return COMPERROR;
+
+  Words_disk = sizeof (u_long);
+
+  if (Read_cdh (dict, &cdh, NULL, &Words_disk) == -1)
+    goto error;
+
+  for (which = 0; which < 2; ++which)
+    switch (cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  if (LoadWords(dict, which) != 0)
+	    goto error;
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    {
+	      if (LoadWords(dict, which) != 0)
+		goto error;
+	    }
+	  else
+	    ht[which] = NULL;
+	  if (LoadHuffmanCodes(dict, which) != 0)
+	    goto error;
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (cdh.num_words[which])
+	    {
+	      if (LoadWords(dict, which) != 0)
+		goto error;
+	    }
+	  else
+	    ht[which] = NULL;
+	  switch (cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      if (LoadHuffmanCodes(dict, which) != 0)
+		goto error;
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    default:
+	      FatalError (1, "Bad novel method");
+	    }
+	}
+	break;
+      default:
+	FatalError (1, "Bad dictionary kind\n");
+      }
+
+  return (COMPALLOK);
+
+
+error:
+  fclose (dict);
+  return (COMPERROR);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/comp_dict.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/comp_dict.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/comp_dict.h	(revision 10506)
@@ -0,0 +1,48 @@
+/**************************************************************************
+ *
+ * comp_dict.h -- Functions for loading the compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define HASH_RATIO 2
+
+typedef struct dict_hash_table
+  {
+    u_long size;
+    huff_data *hd;
+    u_long *codes;
+    u_char **words;
+    u_char **table[1];
+  }
+dict_hash_table;
+
+extern compression_dict_header cdh;
+extern compressed_text_header cth;
+extern comp_frags_header cfh[2];
+
+extern dict_hash_table *ht[2];
+
+extern huff_data char_huff[2];
+extern huff_data lens_huff[2];
+extern u_long *char_codes[2], *lens_codes[2];
+extern u_long Words_disk;
+extern u_long Chars_disk;
+
+
+
+int LoadCompressionDictionary (char *dict_file_name);
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/hash.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/hash.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/hash.h	(revision 10506)
@@ -0,0 +1,39 @@
+/**************************************************************************
+ *
+ * hash.h -- Hash function
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef H_HASH
+#define H_HASH
+
+#define HASH(h, step, wd, tablesize)			\
+	do {						\
+		register u_char *p=wd;			\
+		register long len = *p++;		\
+		register unsigned long hval;		\
+		if (len>25) len = 25;			\
+		for (hval=0; len; --len)		\
+		  hval = (hval << 5) - hval + *p++;	\
+		step = hval % (tablesize - 2) + 1;	\
+		h = hval % tablesize;			\
+	} while (0)
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/invf.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/invf.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/invf.cpp	(revision 10506)
@@ -0,0 +1,914 @@
+/**************************************************************************
+ *
+ * invf.cpp -- Data structures for inverted files
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "invf.h"
+#include "UCArray.h"
+
+
+invf_dict_header::invf_dict_header () {
+  Clear();
+}
+
+invf_dict_header::~invf_dict_header () {
+}
+
+void invf_dict_header::Clear() {
+  lookback = 0;
+  word_dict_start = 0;
+  word_dict_size = 0;
+  tag_dict_start = 0;
+  tag_dict_size = 0;
+  num_docs = 0;
+  num_frags = 0;
+  num_words = 0;
+  total_bytes = 0;
+  index_string_bytes = 0;
+  num_levels = 0;
+}
+
+bool invf_dict_header::Read (FILE *f) {
+  return (ReadUL (f, lookback) &&
+	  ReadUL (f, word_dict_start) &&
+	  ReadUL (f, word_dict_size) &&
+	  ReadUL (f, tag_dict_start) &&
+	  ReadUL (f, tag_dict_size) &&
+	  ReadUL (f, num_docs) &&
+	  ReadUL (f, num_frags) &&
+	  ReadUL (f, num_words) &&
+	  ReadUL (f, total_bytes) &&
+	  ReadUL (f, index_string_bytes) &&
+	  ReadUL (f, num_levels));
+}
+
+bool invf_dict_header::Write (FILE *f) const {
+  return (WriteUL (f, lookback) &&
+	  WriteUL (f, word_dict_start) &&
+	  WriteUL (f, word_dict_size) &&
+	  WriteUL (f, tag_dict_start) &&
+	  WriteUL (f, tag_dict_size) &&
+	  WriteUL (f, num_docs) &&
+	  WriteUL (f, num_frags) &&
+	  WriteUL (f, num_words) &&
+	  WriteUL (f, total_bytes) &&
+	  WriteUL (f, index_string_bytes) &&
+	  WriteUL (f, num_levels));
+}
+
+
+
+void dict_el::Clear () {
+  el.erase (el.begin(), el.end());
+  frag_occur = 0;
+  freq = 0;
+}
+
+bool dict_el::Read (FILE *f) {
+  return (ReadPreSufStr (f, el) &&
+	  ReadUL (f, frag_occur) &&
+	  ReadUL (f, freq));
+}
+
+bool dict_el::Write (FILE *f, const UCArray *lastEl) const {
+  return (WritePreSufStr (f, lastEl, el) &&
+	  WriteUL (f, frag_occur) &&
+	  WriteUL (f, freq));
+}
+
+
+void word_dict_el::Clear () {
+  dict_el::Clear();
+  if (levelFreqs != NULL) delete [] levelFreqs;
+  levelFreqs = NULL;
+}
+
+word_dict_el::~word_dict_el () {
+  if (levelFreqs != NULL) delete [] levelFreqs;
+}
+
+void word_dict_el::SetNumLevels (unsigned long numLevels) {
+  if (levelFreqs != NULL) delete [] levelFreqs;
+  levelFreqs = new unsigned long [numLevels];
+}
+  
+bool word_dict_el::Read (FILE *f, unsigned long numLevels) {
+  if (!dict_el::Read (f)) return false;
+
+  if (levelFreqs == NULL) return false;
+  
+  unsigned long i;
+  for (i=0; i<numLevels; ++i) {
+    if (!ReadUL (f, levelFreqs[i])) return false;
+  }
+
+  return true;
+}
+
+bool word_dict_el::Write (FILE *f, const UCArray *lastEl,
+			  unsigned long numLevels) const {
+  if (!dict_el::Write (f, lastEl)) return false;
+
+  if (levelFreqs == NULL) return false;
+
+  unsigned long i;
+  for (i=0; i<numLevels; ++i) {
+    if (!WriteUL (f, levelFreqs[i])) return false;
+  }
+
+  return true;
+}
+
+
+
+block_dict_header::block_dict_header () {
+  Clear();
+}
+
+void block_dict_header::Clear () {
+  invf_dict_header::Clear();
+
+  entries_per_wblk = 0;
+  num_wblks = 0;
+  max_wblk_size = 0;
+  wblk_start = 0;
+  wblk_idx_start = 0;
+  
+  entries_per_tblk = 0;
+  num_tblks = 0;
+  max_tblk_size = 0;
+  tblk_start = 0;
+  tblk_idx_start = 0;
+}
+
+bool block_dict_header::Read (FILE *f) {
+  return (invf_dict_header::Read (f) &&
+
+	  ReadUL (f, entries_per_wblk) &&
+	  ReadUL (f, num_wblks) &&
+	  ReadUL (f, max_wblk_size) &&
+	  ReadUL (f, wblk_start) &&
+	  ReadUL (f, wblk_idx_start) &&
+  
+	  ReadUL (f, entries_per_tblk) &&
+	  ReadUL (f, num_tblks) &&
+	  ReadUL (f, max_tblk_size) &&
+	  ReadUL (f, tblk_start) &&
+	  ReadUL (f, tblk_idx_start));
+}
+
+bool block_dict_header::Write (FILE *f) const {
+  return (invf_dict_header::Write (f) &&
+
+	  WriteUL (f, entries_per_wblk) &&
+	  WriteUL (f, num_wblks) &&
+	  WriteUL (f, max_wblk_size) &&
+	  WriteUL (f, wblk_start) &&
+	  WriteUL (f, wblk_idx_start) &&
+  
+	  WriteUL (f, entries_per_tblk) &&
+	  WriteUL (f, num_tblks) &&
+	  WriteUL (f, max_tblk_size) &&
+	  WriteUL (f, tblk_start) &&
+	  WriteUL (f, tblk_idx_start));
+}
+
+
+
+
+
+void block_dict_el::Clear () {
+  el.erase (el.begin(), el.end());
+  frag_occur = 0;
+  freq = 0;
+  invf_ptr = 0;
+}
+
+bool block_dict_el::Read (FILE *f) {
+  return (ReadPreSufStr (f, el) &&
+	  ReadUL (f, frag_occur) &&
+	  ReadUL (f, freq) &&
+	  ReadUL (f, invf_ptr));
+}
+
+bool block_dict_el::Write (FILE *f, const UCArray *lastEl) const {
+  return (WritePreSufStr (f, lastEl, el) &&
+	  WriteUL (f, frag_occur) &&
+	  WriteUL (f, freq) &&
+	  WriteUL (f, invf_ptr));
+}
+
+
+
+
+
+void word_block_dict_el::Clear () {
+  block_dict_el::Clear();
+  if (levelFreqs != NULL) delete [] levelFreqs;
+  levelFreqs = NULL;
+}
+
+word_block_dict_el::~word_block_dict_el () {
+  if (levelFreqs != NULL) delete [] levelFreqs;
+}
+
+void word_block_dict_el::SetNumLevels (unsigned long numLevels) {
+  if (levelFreqs != NULL) delete [] levelFreqs;
+  levelFreqs = new unsigned long [numLevels];
+}
+
+bool word_block_dict_el::Read (FILE *f, unsigned long numLevels) {
+  if (!block_dict_el::Read (f)) return false;
+  
+  if (levelFreqs == NULL) return false;
+  
+  unsigned long i;
+  for (i=0; i<numLevels; ++i) {
+    if (!ReadUL (f, levelFreqs[i])) return false;
+  }
+
+  return true;
+}
+
+bool word_block_dict_el::Write (FILE *f, const UCArray *lastEl,
+				unsigned long numLevels) const {
+  if (!block_dict_el::Write (f, lastEl)) return false;
+  
+  if (levelFreqs == NULL) return false;
+  
+  unsigned long i;
+  for (i=0; i<numLevels; ++i) {
+    if (!WriteUL (f, levelFreqs[i])) return false;
+  }
+  
+  return true;
+}
+
+
+
+
+block_idx_info::block_idx_info () {
+  Clear ();
+}
+
+void block_idx_info::Clear () {
+  el.erase (el.begin(), el.end());
+  block_ptr = 0;
+}
+
+bool block_idx_info::Read (FILE *f) {
+  return (ReadUCArray (f, el) &&
+	  ReadUL (f, block_ptr));
+}
+
+bool block_idx_info::Write (FILE *f) const {
+  return (WriteUCArray (f, el) &&
+	  WriteUL (f, block_ptr));
+}
+
+
+bool ReadBlockIdx (FILE *f, block_idx &blockIdx) {
+  blockIdx.erase (blockIdx.begin(), blockIdx.end());
+  
+  // read in the array size
+  unsigned long arraySize = 0;
+  if (!ReadVarLenUL (f, arraySize)) return false;
+  
+  // read in the array
+  block_idx_info bi;
+  while (arraySize > 0) {
+    if (!bi.Read (f)) return false;
+    blockIdx.push_back (bi);
+    
+    --arraySize;
+  }
+  
+  return true;
+}
+
+bool WriteBlockIdx (FILE *f, const block_idx &blockIdx) {
+  // write out the array size
+  if (!WriteVarLenUL (f, blockIdx.size())) return false;
+
+  block_idx::const_iterator here = blockIdx.begin();
+  block_idx::const_iterator end = blockIdx.end();
+  while (here != end) {
+    if (!(*here).Write (f)) return false;
+    ++here;
+  }
+
+  return true;
+}
+
+
+
+
+stem_idx_header::stem_idx_header () {
+  Clear ();
+}
+
+void stem_idx_header::Clear () {
+  lookback = 0;
+  dict_size = 0;
+
+  entries_per_block = 0;
+  num_blocks = 0;
+  max_block_size = 0;
+  blocks_start = 0;
+  block_idx_start = 0;
+  
+  stemmer_num = 0;
+  stem_method = 0;
+}
+
+bool stem_idx_header::Read (FILE *f) {
+  return (ReadUL (f, lookback) &&
+	  ReadUL (f, dict_size) &&
+	  
+	  ReadUL (f, entries_per_block) &&
+	  ReadUL (f, num_blocks) &&
+	  ReadUL (f, max_block_size) &&
+	  ReadUL (f, blocks_start) &&
+	  ReadUL (f, block_idx_start) &&
+	  
+	  ReadUL (f, stemmer_num) &&
+	  ReadUL (f, stem_method));
+}
+
+bool stem_idx_header::Write (FILE *f) const {
+  return (WriteUL (f, lookback) &&
+	  WriteUL (f, dict_size) &&
+	  
+	  WriteUL (f, entries_per_block) &&
+	  WriteUL (f, num_blocks) &&
+	  WriteUL (f, max_block_size) &&
+	  WriteUL (f, blocks_start) &&
+	  WriteUL (f, block_idx_start) &&
+	  
+	  WriteUL (f, stemmer_num) &&
+	  WriteUL (f, stem_method));
+}
+
+
+
+stem_block_dict_el::stem_block_dict_el () {
+  Clear ();
+}
+
+void stem_block_dict_el::Clear () {
+  el.erase (el.begin(), el.end());
+  equivWords.erase (equivWords.begin(), equivWords.end());
+}
+
+bool stem_block_dict_el::Read (FILE *f) {
+  equivWords.erase (equivWords.begin(), equivWords.end());
+  
+  if (!ReadPreSufStr (f, el)) return false;
+  
+  // read in the array size
+  unsigned long arraySize = 0;
+  if (!ReadVarLenUL (f, arraySize)) return false;
+  
+  // read in the array
+  unsigned long wordNum;
+  while (arraySize > 0) {
+    if (!ReadUL (f, wordNum)) return false;
+    equivWords.push_back (wordNum);
+    
+    --arraySize;
+  }
+  
+  return true;
+}
+
+bool stem_block_dict_el::Write (FILE *f, const UCArray *lastEl) const {
+  if (!WritePreSufStr (f, lastEl, el)) return false;
+
+  // write out the array size
+  if (!WriteVarLenUL (f, equivWords.size())) return false;
+
+  vector<unsigned long>::const_iterator here = equivWords.begin();
+  vector<unsigned long>::const_iterator end = equivWords.end();
+  while (here != end) {
+    if (!WriteUL (f, (*here))) return false;
+    ++here;
+  }
+
+  return true;
+}
+
+
+
+
+invf_file_header::invf_file_header () {
+  Clear ();
+}
+
+void invf_file_header::Clear () {
+  no_of_words = 0;
+  no_of_tags = 0;
+  skip_mode = SKIP_MODE_NO_SKIPS;
+  word_level_index = 0;
+  
+  int i;
+  for (i=0; i<16; ++i) params[i] = 0;
+}
+  
+bool invf_file_header::Read (FILE *f) {
+  if (!ReadUL (f, no_of_words) ||
+      !ReadUL (f, no_of_tags) ||
+      !ReadUL (f, skip_mode) ||
+      !ReadUL (f, word_level_index)) return false;
+
+  int i;
+  for (i=0; i<16; ++i) {
+    if (!ReadUL (f, params[i])) return false;
+  }
+
+  return true;
+}
+
+bool invf_file_header::Write (FILE *f) const {
+  if (!WriteUL (f, no_of_words) ||
+      !WriteUL (f, no_of_tags) ||
+      !WriteUL (f, skip_mode) ||
+      !WriteUL (f, word_level_index)) return false;
+
+  int i;
+  for (i=0; i<16; ++i) {
+    if (!WriteUL (f, params[i])) return false;
+  }
+
+  return true;
+}
+
+
+
+
+
+bool SearchElNum (const block_idx &bIdx,
+		  unsigned long entriesPerBlock,
+		  unsigned long elNum,
+		  unsigned long &blockIdxNum,
+		  unsigned long &blockStartElNum) {
+  blockIdxNum = 0;
+  blockStartElNum = 0;
+
+  // make sure the element number isn't out of range
+  if (elNum > bIdx.size()*entriesPerBlock) return false;
+
+  blockIdxNum = elNum / entriesPerBlock;
+  blockStartElNum = blockIdxNum * entriesPerBlock;
+  
+  return true;
+}
+
+bool SearchEl (const block_idx &bIdx,
+	       unsigned long entriesPerBlock,
+	       const UCArray &el,
+	       unsigned long &blockIdxNum,
+	       unsigned long &blockStartElNum) {
+  blockIdxNum = 0;
+  blockStartElNum = 0;
+
+  unsigned long begin = 0;
+  unsigned long bIdxEnd = bIdx.size();
+  unsigned long end = bIdxEnd;
+  unsigned long mid;
+  while (begin < end) {
+    mid = (begin+end)/2;
+    if (DictCompare (el, bIdx[mid].el) < 0) {
+      end = mid;
+    } else if (mid+1 < bIdxEnd &&
+	       DictCompare (el, bIdx[mid+1].el) >= 0) {
+      begin = mid+1;
+    } else {
+      blockIdxNum = mid;
+      blockStartElNum = blockIdxNum * entriesPerBlock;
+      return true;
+    }
+  }
+  
+  return false;
+}
+
+
+
+// use the block dictionary functions for tag entries, and word block dict
+// functions for word entries.
+
+
+bool SearchBlockDictElNum (FILE *dictFile,
+			   const block_idx &bIdx,
+			   unsigned long entriesPerBlock,
+			   unsigned long dictSize,
+			   unsigned long elNum,
+			   block_dict_el &dictEl) {
+  UCArrayClear (dictEl.el);
+  if (elNum >= dictSize) return false;
+
+  // find the block that contains the element
+  unsigned long blockIdxNum, curElNum;
+  if (!SearchElNum (bIdx, entriesPerBlock, elNum,
+		    blockIdxNum, curElNum))
+    return false;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  do {
+    dictEl.Read (dictFile);
+  } while (curElNum++ < elNum);
+
+  return true;
+}
+
+bool SearchBlockDictEl (FILE *dictFile,
+			const block_idx &bIdx,
+			unsigned long entriesPerBlock,
+			unsigned long dictSize,
+			const UCArray &el,
+			block_dict_el &dictEl,
+			unsigned long &elNum) {
+  UCArrayClear (dictEl.el);
+
+  // find the block that contains the element
+  unsigned long blockIdxNum;
+  if (!SearchEl (bIdx, entriesPerBlock, el,
+		 blockIdxNum, elNum))
+    return false;
+
+  unsigned long blockEndElNum = elNum + entriesPerBlock;
+  if (blockEndElNum > dictSize) blockEndElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  while (elNum < blockEndElNum) {
+    dictEl.Read (dictFile);
+    int res = DictCompare (dictEl.el, el);
+    if (res == 0) return true; // found it
+    else if (res > 0) break; // not here
+    
+    ++elNum;
+  }
+
+  return false;
+}
+
+
+
+
+bool SearchWordBlockDictElNum (FILE *dictFile,
+			       const block_idx &bIdx,
+			       unsigned long entriesPerBlock,
+			       unsigned long dictSize,
+			       unsigned long numLevels,
+			       unsigned long elNum,
+			       word_block_dict_el &dictEl) {
+  UCArrayClear (dictEl.el);
+  if (elNum >= dictSize) return false;
+
+  // find the block that contains the element
+  unsigned long blockIdxNum, curElNum;
+  if (!SearchElNum (bIdx, entriesPerBlock, elNum,
+		    blockIdxNum, curElNum))
+    return false;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  do {
+    dictEl.Read (dictFile, numLevels);
+  } while (curElNum++ < elNum);
+
+  return true;
+}
+
+bool SearchWordBlockDictEl (FILE *dictFile,
+			    const block_idx &bIdx,
+			    unsigned long entriesPerBlock,
+			    unsigned long dictSize,
+			    unsigned long numLevels,
+			    const UCArray &el,
+			    word_block_dict_el &dictEl,
+			    unsigned long &elNum) {
+  UCArrayClear (dictEl.el);
+
+  // find the block that contains the element
+  unsigned long blockIdxNum;
+  if (!SearchEl (bIdx, entriesPerBlock, el,
+		 blockIdxNum, elNum))
+    return false;
+
+  unsigned long blockEndElNum = elNum + entriesPerBlock;
+  if (blockEndElNum > dictSize) blockEndElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  while (elNum < blockEndElNum) {
+    dictEl.Read (dictFile, numLevels);
+    int res = DictCompare (dictEl.el, el);
+    if (res == 0) return true; // found it
+    else if (res > 0) break; // not here
+    
+    ++elNum;
+  }
+
+  return false;
+}
+
+
+
+
+bool SearchStemBlockDictElNum (FILE *dictFile,
+			       const block_idx &bIdx,
+			       unsigned long entriesPerBlock,
+			       unsigned long dictSize,
+			       unsigned long elNum,
+			       stem_block_dict_el &dictEl) {
+  UCArrayClear (dictEl.el);
+  if (elNum >= dictSize) return false;
+
+  // find the block that contains the element
+  unsigned long blockIdxNum, curElNum;
+  if (!SearchElNum (bIdx, entriesPerBlock, elNum,
+		    blockIdxNum, curElNum))
+    return false;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  do {
+    dictEl.Read (dictFile);
+  } while (curElNum++ < elNum);
+
+  return true;
+}
+
+bool SearchStemBlockDictEl (FILE *dictFile,
+			    const block_idx &bIdx,
+			    unsigned long entriesPerBlock,
+			    unsigned long dictSize,
+			    const UCArray &el,
+			    stem_block_dict_el &dictEl,
+			    unsigned long &elNum) {
+  UCArrayClear (dictEl.el);
+
+  // find the block that contains the element
+  unsigned long blockIdxNum;
+  if (!SearchEl (bIdx, entriesPerBlock, el,
+		 blockIdxNum, elNum))
+    return false;
+
+  unsigned long blockEndElNum = elNum + entriesPerBlock;
+  if (blockEndElNum > dictSize) blockEndElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  while (elNum < blockEndElNum) {
+    dictEl.Read (dictFile);
+    int res = DictCompare (dictEl.el, el);
+    if (res == 0) return true; // found it
+    else if (res > 0) break; // not here
+    
+    ++elNum;
+  }
+
+  return false;
+}
+
+// ------------------------------------------
+// functions for partial term matching
+// ie find all words that start with xxx
+bool PartialMatchSearchWordBlockDictEl (FILE *dictFile,
+				 const block_idx &bIdx,
+				 unsigned long entriesPerBlock,
+				 unsigned long dictSize,
+				 unsigned long numLevels,
+				 const UCArray &el,
+				 word_block_dict_el &dictEl,
+				 vector<unsigned long> &elNumList,
+				 bool casefold) {
+
+  UCArrayClear (dictEl.el);
+  elNumList.erase (elNumList.begin(), elNumList.end());
+  unsigned long elNum;
+  // find the block that contains the element
+  unsigned long blockIdxNum;
+  // will this work??
+  if (!SearchEl (bIdx, entriesPerBlock, el,
+		 blockIdxNum, elNum)) {
+    return false;
+  }
+  unsigned long blockEndElNum = elNum + entriesPerBlock;
+  if (blockEndElNum > dictSize) blockEndElNum = dictSize;
+  
+  bool still_looking = true;
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  // test each element
+  while (elNum < blockEndElNum) {
+    dictEl.Read (dictFile, numLevels);
+    if (StartsWithCasefold(dictEl.el, el)) {
+      if (casefold || StartsWith(dictEl.el, el)) {
+	elNumList.push_back(elNum);
+      }
+      still_looking=false; // we have found one now, so stop the next time we don't have a match
+    } else if (!still_looking) {
+      // we have found a match previously, and now this doesn't match
+      return true;
+    } // else keep looking
+    
+    ++elNum;
+  }
+  // if we get here, we are either still searching for the first
+  // case, or we are collecting terms.
+  if (still_looking) {
+    //we haven't found a match yet, just check the next element,
+    dictEl.Read (dictFile, numLevels);
+    if (!StartsWithCasefold(dictEl.el, el)) {
+      // the first element of the next block is not a match, so there are no matches
+      return false;
+    } else {
+      if (casefold || StartsWith(dictEl.el, el)) {
+	elNumList.push_back(elNum);
+	++elNum;
+      } 
+
+    }
+  }
+  // just keep accumulating matches until there are no more
+  dictEl.Read (dictFile, numLevels);
+  while (StartsWithCasefold(dictEl.el, el)) {
+    if (casefold || StartsWith(dictEl.el, el)) {
+      elNumList.push_back(elNum);
+    }
+    ++elNum;
+    dictEl.Read (dictFile, numLevels);
+  }
+  return true;
+  
+}
+
+
+//----------------------------------------------------------------
+// functions for full text browse
+
+bool NearestSearchWordBlockDictEl (FILE *dictFile,
+				   const block_idx &bIdx,
+				   unsigned long entriesPerBlock,
+				   unsigned long dictSize,
+				   unsigned long numLevels,
+				   const UCArray &el,
+				   word_block_dict_el &dictEl,
+				   unsigned long &elNum) {
+
+  UCArrayClear (dictEl.el);
+
+  // find the block that contains the element
+  unsigned long blockIdxNum;
+  if (!SearchEl (bIdx, entriesPerBlock, el,
+		 blockIdxNum, elNum))
+    return false;
+
+  unsigned long blockEndElNum = elNum + entriesPerBlock;
+  if (blockEndElNum > dictSize) blockEndElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  while (elNum < blockEndElNum) {
+    dictEl.Read (dictFile, numLevels);
+    int res = DictCompare (el, dictEl.el); // look for the first word that is
+                                     // greater or equal to the el
+    if (res <= 0) {
+      return true; // found one
+   } 
+    
+    ++elNum;
+  }
+  // it must be the last term
+  return true;
+
+
+}
+
+
+bool SearchWordBlockDictElNumRange (FILE *dictFile,
+				    const block_idx &bIdx,
+				    unsigned long entriesPerBlock,
+				    unsigned long dictSize,
+				    unsigned long numLevels,
+				    unsigned long elNum,
+				    unsigned long numWords,
+				    UCArrayVector &terms) {
+
+  word_block_dict_el dictEl;  
+  dictEl.SetNumLevels (numLevels);
+  UCArrayClear(dictEl.el);
+
+  terms.erase(terms.begin(), terms.end());
+
+  if (elNum >= dictSize) return false;
+  
+  // find the block that contains the element
+  unsigned long blockIdxNum, curElNum;
+  if (!SearchElNum (bIdx, entriesPerBlock, elNum,
+		    blockIdxNum, curElNum))
+    return false;
+
+  unsigned long lastElNum = elNum + numWords - 1;
+  if (lastElNum > dictSize) lastElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  
+  // get the first term
+  do {
+    dictEl.Read (dictFile, numLevels);
+  } while (curElNum++ < elNum);
+
+  terms.push_back(dictEl.el);
+  while (curElNum <= lastElNum ) {
+    dictEl.Read(dictFile, numLevels);
+    terms.push_back(dictEl.el);
+    ++curElNum;
+  }
+  
+
+  return true;
+}
+
+// NOte: before each addition of dictEl to the array, the level freqs array
+// is deleted, as this was causing problems - generating a seg fault, I think if
+// the vector had to be reallocated or something.
+// setNumLevels has to be called each time before a read, now, to set up the level
+//freqs array. this is necessary.
+bool SearchWordBlockDictElNumRange (FILE *dictFile,
+				    const block_idx &bIdx,
+				    unsigned long entriesPerBlock,
+				    unsigned long dictSize,
+				    unsigned long numLevels,
+				    unsigned long elNum,
+				    unsigned long numWords,
+				    word_block_dict_el_array &terms) {
+
+  word_block_dict_el dictEl;
+  dictEl.SetNumLevels (numLevels);
+  UCArrayClear(dictEl.el);
+
+  block_dict_el elem;
+  terms.erase(terms.begin(), terms.end());
+
+  if (elNum >= dictSize) return false;
+  
+  // find the block that contains the element
+  unsigned long blockIdxNum, curElNum;
+  if (!SearchElNum (bIdx, entriesPerBlock, elNum,
+		    blockIdxNum, curElNum))
+    return false;
+
+  unsigned long lastElNum = elNum + numWords - 1;
+  if (lastElNum > dictSize) lastElNum = dictSize;
+
+  // look for the block
+  fseek (dictFile, bIdx[blockIdxNum].block_ptr, SEEK_SET);
+  // get the first term
+  do {
+    dictEl.Read (dictFile, numLevels);
+  } while (curElNum++ < elNum);
+
+  dictEl.levelFreqs = NULL;
+  terms.push_back(dictEl);
+
+  while (curElNum <= lastElNum ) { 
+    dictEl.SetNumLevels(numLevels);
+    dictEl.Read(dictFile, numLevels);
+    dictEl.levelFreqs = NULL;
+    terms.push_back(dictEl);
+    ++curElNum;
+  }
+
+  return true;
+}
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/invf.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/invf.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/invf.h	(revision 10506)
@@ -0,0 +1,353 @@
+/**************************************************************************
+ *
+ * invf.h -- Data structures for inverted files
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ **************************************************************************/
+
+
+#ifndef H_INVF
+#define H_INVF
+
+#include <stdio.h>
+
+#include "UCArray.h"
+
+// NOTE: This does not include the magic number
+// header info for .invf.dict file
+struct invf_dict_header {
+  unsigned long lookback;
+  unsigned long word_dict_start;
+  unsigned long word_dict_size;
+  unsigned long tag_dict_start;
+  unsigned long tag_dict_size;
+  unsigned long num_docs;
+  unsigned long num_frags;
+  unsigned long num_words;
+  unsigned long total_bytes;
+  unsigned long index_string_bytes;
+  unsigned long num_levels;
+
+  invf_dict_header ();
+  virtual ~invf_dict_header ();
+  virtual void Clear();
+
+  virtual bool Read (FILE *f);
+  virtual bool Write (FILE *f) const;
+};
+
+
+struct dict_el {
+  UCArray el; // word or tag
+  unsigned long frag_occur;
+  unsigned long freq;
+
+  virtual void Clear ();
+  dict_el () { Clear (); }
+  virtual ~dict_el () { }
+
+  // Read assumes that the last word is in el
+  bool Read (FILE *f);
+  bool Write (FILE *f, const UCArray *lastEl) const;
+};
+
+
+struct word_dict_el : public dict_el {
+  unsigned long *levelFreqs;
+
+  void Clear ();
+  word_dict_el () { levelFreqs = NULL; Clear (); }
+  ~word_dict_el ();
+
+  void SetNumLevels (unsigned long numLevels);
+
+  // SetNumLevels should be called before either
+  // reading or writing using Read and Write
+  
+  // Read assumes that the last word is in el
+  bool Read (FILE *f, unsigned long numLevels);
+  bool Write (FILE *f, const UCArray *lastEl,
+	      unsigned long numLevels) const;
+};
+
+
+// wblk = word block
+// tblk = tag block
+// this version of the blocked dictionary uses a fixed number
+// of entries per block, not a fixed block size
+// info for .invf.dict.blocked file
+// blocked dict has a heap of blocks, some for words, some for tags
+// and an index into each set of blocks. The index has pointers to
+// the first entry in each block. Can do a binary search on the index
+// to find out which block an elemnet is in
+struct block_dict_header : public invf_dict_header {
+  // note: word_dict_start and tag_dict_start are undefined
+  // for blocked dictionaries
+
+  unsigned long entries_per_wblk; // word blocks
+  unsigned long num_wblks;
+  unsigned long max_wblk_size;
+  unsigned long wblk_start;
+  unsigned long wblk_idx_start;
+  
+  unsigned long entries_per_tblk; // tag blocks
+  unsigned long num_tblks;
+  unsigned long max_tblk_size;
+  unsigned long tblk_start;
+  unsigned long tblk_idx_start;
+  
+  block_dict_header ();
+  void Clear ();
+  
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+
+struct block_dict_el {
+  UCArray el; // word or tag
+  unsigned long frag_occur; // # entries in invf file - if have a
+  // word level index, this is the same as freq, otherwise, its the number
+  // of fragments containing this word
+  unsigned long freq; // # of times this word occurs
+  unsigned long invf_ptr; // pointer into inverted file
+
+  virtual void Clear ();
+  block_dict_el () { Clear (); }
+  virtual ~block_dict_el () { }
+
+  // Read assumes that the last word is in el
+  // set lastEl = NULL when no lookback is wanted (eg
+  // for the start of a block
+  bool Read (FILE *f);
+  bool Write (FILE *f, const UCArray *lastEl) const;
+};
+
+struct word_block_dict_el : public block_dict_el {
+  unsigned long *levelFreqs; // freq of the word at each level
+
+  void Clear ();
+  word_block_dict_el () { levelFreqs = NULL; Clear (); }
+  ~word_block_dict_el ();
+
+  void SetNumLevels (unsigned long numLevels);
+
+  // SetNumLevels should be called before either
+  // reading or writing using Read and Write
+  
+  // Read assumes that the last word is in el
+  bool Read (FILE *f, unsigned long numLevels);
+  bool Write (FILE *f, const UCArray *lastEl,
+	      unsigned long numLevels) const;
+};
+
+typedef vector<word_block_dict_el> word_block_dict_el_array;
+
+struct block_idx_info {
+  UCArray el;
+  unsigned long block_ptr;
+
+  block_idx_info ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+// used for an index into the word and tag blocks
+typedef vector<block_idx_info> block_idx;
+
+bool ReadBlockIdx (FILE *f, block_idx &blockIdx);
+bool WriteBlockIdx (FILE *f, const block_idx &blockIdx);
+
+
+
+struct stem_idx_header {
+  unsigned long lookback;
+  unsigned long dict_size;
+
+  unsigned long entries_per_block;
+  unsigned long num_blocks;
+  unsigned long max_block_size;
+  unsigned long blocks_start;
+  unsigned long block_idx_start;
+  
+  unsigned long stemmer_num;
+  unsigned long stem_method;
+
+  stem_idx_header ();
+  void Clear ();
+
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+struct stem_block_dict_el {
+  UCArray el; // word or tag
+  vector<unsigned long> equivWords;
+  
+  stem_block_dict_el ();
+  void Clear ();
+
+  // Read assumes that the last word is in el
+  // set lastEl = NULL when no lookback is wanted (eg
+  // for the start of a block
+  bool Read (FILE *f);
+  bool Write (FILE *f, const UCArray *lastEl) const;
+};
+
+
+
+#define SKIP_MODE_NO_SKIPS 0
+
+// invf file - has a list of frags for each word, but the word is not 
+//  stored in the invf file - the dictionaries store the words, along
+// with num entries, and a pointer into invf file
+struct invf_file_header {
+  unsigned long no_of_words;
+  unsigned long no_of_tags;
+  unsigned long skip_mode;
+  unsigned long word_level_index; // 1 if word level index
+  unsigned long params[16];
+
+  invf_file_header ();
+  void Clear ();
+  
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+
+
+
+
+
+// the search functions returns true if a block that could
+// satisfy the request is found. these functions assume that
+// the block index is sorted by DictCompare (or DictLTUCArray)
+bool SearchElNum (const block_idx &bIdx,
+		  unsigned long entriesPerBlock,
+		  unsigned long elNum,
+		  unsigned long &blockIdxNum,
+		  unsigned long &blockStartElNum);
+bool SearchEl (const block_idx &bIdx,
+	       unsigned long entriesPerBlock,
+	       const UCArray &el,
+	       unsigned long &blockIdxNum,
+	       unsigned long &blockStartElNum);
+
+
+// The next six functions use SearchElNum and SearchEl
+// for a particular type of dictionary (Block, WordBlock, or StemBlock)
+// and then look up the entry
+bool SearchBlockDictElNum (FILE *dictFile,
+			   const block_idx &bIdx,
+			   unsigned long entriesPerBlock,
+			   unsigned long dictSize,
+			   unsigned long elNum,
+			   block_dict_el &dictEl);
+bool SearchBlockDictEl (FILE *dictFile,
+			const block_idx &bIdx,
+			unsigned long entriesPerBlock,
+			unsigned long dictSize,
+			const UCArray &el,
+			block_dict_el &dictEl,
+			unsigned long &elNum);
+
+// assumes the numLevels has been set for dictEl
+bool SearchWordBlockDictElNum (FILE *dictFile,
+			       const block_idx &bIdx,
+			       unsigned long entriesPerBlock,
+			       unsigned long dictSize,
+			       unsigned long numLevels,
+			       unsigned long elNum,
+			       word_block_dict_el &dictEl);
+bool SearchWordBlockDictEl (FILE *dictFile,
+			    const block_idx &bIdx,
+			    unsigned long entriesPerBlock,
+			    unsigned long dictSize,
+			    unsigned long numLevels,
+			    const UCArray &el,
+			    word_block_dict_el &dictEl,
+			    unsigned long &elNum);
+
+bool SearchStemBlockDictElNum (FILE *dictFile,
+			       const block_idx &bIdx,
+			       unsigned long entriesPerBlock,
+			       unsigned long dictSize,
+			       unsigned long elNum,
+			       stem_block_dict_el &dictEl);
+bool SearchStemBlockDictEl (FILE *dictFile,
+			    const block_idx &bIdx,
+			    unsigned long entriesPerBlock,
+			    unsigned long dictSize,
+			    const UCArray &el,
+			    stem_block_dict_el &dictEl,
+			    unsigned long &elNum);
+
+//-----------------------------------------------------
+// New functions for partial matching
+// returns a list of word numbers from the main block index whose
+// words start with el.
+bool PartialMatchSearchWordBlockDictEl (FILE *dictFile,
+				 const block_idx &bIdx,
+				 unsigned long entriesPerBlock,
+				 unsigned long dictSize,
+				 unsigned long numLevels,
+				 const UCArray &el,
+				 word_block_dict_el &dictEl,
+				 vector<unsigned long> &elNumList,
+				 bool casefold); 
+
+//----------------------------------------------------------
+
+// new functions for full text browse
+
+bool NearestSearchWordBlockDictEl (FILE *dictFile,
+			    const block_idx &bIdx,
+			    unsigned long entriesPerBlock,
+			    unsigned long dictSize,
+			    unsigned long numLevels,
+			    const UCArray &el,
+			    word_block_dict_el &dictEl,
+			    unsigned long &elNum);
+
+// returns a list of word_block_dict_el, with no levelfreqs
+bool SearchWordBlockDictElNumRange (FILE *dictFile,
+				    const block_idx &bIdx,
+				    unsigned long entriesPerBlock,
+				    unsigned long dictSize,
+				    unsigned long numLevels,
+				    unsigned long elNum,
+				    unsigned long numWords,
+				    word_block_dict_el_array &terms);
+				    
+// just returns a list of terms
+bool SearchWordBlockDictElNumRange (FILE *dictFile,
+				    const block_idx &bIdx,
+				    unsigned long entriesPerBlock,
+				    unsigned long dictSize,
+				    unsigned long numLevels,
+				    unsigned long elNum,
+				    unsigned long numWords,
+				    UCArrayVector &terms);
+				    
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/ivf.pass1.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/ivf.pass1.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/ivf.pass1.cpp	(revision 10506)
@@ -0,0 +1,775 @@
+/**************************************************************************
+ *
+ * ivf.pass1.cpp -- Memory efficient pass 1 inversion
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "UCArray.h"
+#include "sysfuncs.h"
+#include "mg_files.h"
+#include "invf.h"
+#include "mg.h"
+#include "build.h"
+#include "locallib.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include <stdio.h>
+#include "words.h"
+#include "messages.h"
+#include "netorder.h"
+#include "FIvfLevelInfo.h"
+
+#include "longlong.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+// a fragment corresponds to the index level (word-level is the
+// minimum index level)
+
+
+// structure to determine level information
+struct LevelWorker {
+  unsigned long lastLevelDocNum;
+  unsigned long count;
+
+  LevelWorker () {
+    lastLevelDocNum = count = 0;
+  }
+};
+
+
+// note: the word is stored in the map
+struct IvfWordInfo {
+  unsigned long wordCount;      // word frequency
+  unsigned long fragCount;      // number of fragments that contain the word
+  unsigned long lastFragNum;    // last fragment to contain the word
+  unsigned long chunkWordCount; // word frequency within this chunk
+  unsigned long chunkFragCount; // number of fragments within this chunk that
+                                //   contain the word
+
+  LevelWorker *levels;          // level info for this word
+  
+  IvfWordInfo ();
+  ~IvfWordInfo ();
+  void Clear ();                // will delete levels
+};
+
+typedef map<UCArray, IvfWordInfo, DictLTUCArray> IvfWordInfoMap;
+typedef vector<IvfWordInfoMap::iterator> IvfWordInfoItArray;
+
+// tags don't require as much information
+struct IvfTagInfo {
+  unsigned long tagCount;       // tag frequency
+  unsigned long fragCount;      // number of fragments that contain the tag
+  unsigned long lastFragNum;    // last fragment to contain the tag
+  unsigned long chunkFragCount; // number of fragments within this chunk that
+                                //   contain the tag
+
+  IvfTagInfo ();
+  void Clear ();
+};
+
+typedef map<UCArray, IvfTagInfo, DictLTUCArray> IvfTagInfoMap;
+typedef vector<IvfTagInfoMap::iterator> IvfTagInfoItArray;
+
+
+#define INIT_CHECK_FRAC 0.10
+#define CHECK_FRAC 0.75
+#define CHECK_CLOSE 0.999
+#define CHECK_DIV 1.5
+
+
+static FILE *ic;		// the invf chunk file
+static stdio_bitio_buffer icb;
+
+IvfWordInfoMap ivfWordInfo;
+IvfWordInfoItArray ivfWordInfoOccurOrder;
+IvfTagInfoMap ivfTagInfo;
+IvfTagInfoItArray ivfTagInfoOccurOrder;
+
+static unsigned long chunksWritten;
+static unsigned long maxMemNeeded;
+
+static unsigned long numDocs;
+static unsigned long numChunkDocs;
+
+static unsigned long numFrags;
+static unsigned long numChunkFrags;
+
+static unsigned long numWords;
+
+// the number of document numbers in the inverted file
+static unsigned long numChunkEntries;
+
+// next entry in the inverted file to check memory
+// requirements for the current chunk
+static unsigned long entryCheckPoint;
+
+// information about all the different levels
+static FIvfLevel ivfLevel;
+
+
+
+IvfWordInfo::IvfWordInfo () {
+  levels = NULL;
+  Clear();
+}
+
+IvfWordInfo::~IvfWordInfo () {
+  if (levels != NULL) delete [] levels;
+}
+
+void IvfWordInfo::Clear () {
+  wordCount = 0;
+  chunkWordCount = 0;
+  lastFragNum = 0;
+  fragCount = 0;
+  chunkFragCount = 0;
+
+  if (levels != NULL) {
+    delete [] levels;
+    levels = NULL;
+  }
+}
+
+
+IvfTagInfo::IvfTagInfo () {
+  Clear();
+}
+
+void IvfTagInfo::Clear () {
+  tagCount = 0;
+  lastFragNum = 0;
+  fragCount = 0;
+  chunkFragCount = 0;
+}
+
+
+
+int init_ivf_1 (const TagInfo &tagInfo, char *file_name) {
+  // set up the chunk file
+  if (!(ic = create_file (file_name, INVF_CHUNK_SUFFIX, "wb",
+			  MAGIC_CHUNK, MG_MESSAGE)))
+    return COMPERROR;
+  fwrite ("    ", sizeof (u_long), 1, ic);	// Space for the maxmem
+  icb.attachFile (ic);
+  icb.encodeStart();
+
+  // reset global variables
+  ivfWordInfo.erase (ivfWordInfo.begin(), ivfWordInfo.end());
+  ivfWordInfoOccurOrder.erase (ivfWordInfoOccurOrder.begin(), ivfWordInfoOccurOrder.end());
+  ivfTagInfo.erase (ivfTagInfo.begin(), ivfTagInfo.end());
+  ivfTagInfoOccurOrder.erase (ivfTagInfoOccurOrder.begin(), ivfTagInfoOccurOrder.end());
+  
+  chunksWritten = 0;
+  maxMemNeeded = 0;
+ 
+  numDocs = 0;
+  numChunkDocs = 0;
+
+  numFrags = 0;
+  numChunkFrags = 0;
+
+  numWords = 0;
+
+  numChunkEntries = 0;
+  entryCheckPoint = (unsigned long) ((invf_buffer_size * INIT_CHECK_FRAC) / CHECK_DIV);
+
+  // init the level information
+  ivfLevel.Clear();
+  ivfLevel.docTag = tagInfo.docTag;
+  ivfLevel.indexLevel = tagInfo.indexLevel;
+  IvfLevelInfo blankLevel;
+  UCArraySet::const_iterator levelHere = tagInfo.levelTags.begin();
+  UCArraySet::const_iterator levelEnd = tagInfo.levelTags.end();
+  while (levelHere != levelEnd) {
+    blankLevel.levelTag = *levelHere;
+    ivfLevel.levelInfo[*levelHere] = blankLevel;
+    ++levelHere;
+  }
+  
+  return COMPALLOK;
+}
+
+static void ProcessOpenTag (const TagInfo &tagInfo, const TextEl &el,
+			    bool &inFrag) {
+  bool wordLevelIndex = tagInfo.indexLevel.empty();
+
+  // check for start of next fragment
+  if (!wordLevelIndex && el.tagName == tagInfo.indexLevel) {
+    ++numFrags;
+    ++numChunkFrags;
+    inFrag = true;
+  }
+  
+  // update tag stats
+  IvfTagInfo &i = ivfTagInfo[el.tagName];
+  if (i.tagCount == 0) {
+    // new tag, add to list of iterators
+    IvfTagInfoMap::iterator iIt = ivfTagInfo.find (el.tagName);
+    ivfTagInfoOccurOrder.push_back (iIt);
+  }
+  ++i.tagCount;
+
+  // all open tags count as new tags
+  ++numChunkEntries;
+  ++i.fragCount;
+  ++i.chunkFragCount;
+  i.lastFragNum = numFrags;
+  
+  // update level information
+  IvfLevelInfoMap::iterator levelIt = ivfLevel.levelInfo.find (el.tagName);
+  if (levelIt != ivfLevel.levelInfo.end()) {
+    // is a level tag
+    ++levelIt->second.numEntries;
+    levelIt->second.workInLevel = true;
+  }
+}
+
+static void ProcessCloseTag (const TagInfo &tagInfo, const TextEl &el,
+			     bool &inFrag) {
+  bool wordLevelIndex = tagInfo.indexLevel.empty();
+
+  // check for end of fragment
+  if (!wordLevelIndex && el.tagName == tagInfo.indexLevel) {
+    inFrag = false;
+  }
+
+  // update level information
+  IvfLevelInfoMap::iterator levelIt = ivfLevel.levelInfo.find (el.tagName);
+  if (levelIt != ivfLevel.levelInfo.end()) {
+    // is a level tag
+    (*levelIt).second.workInLevel = false;
+  }
+}
+
+static void ProcessText (const TagInfo &tagInfo, const TextEl &el,
+			 bool &inFrag) {
+  bool wordLevelIndex = tagInfo.indexLevel.empty();
+
+  // make sure this text is to be indexed
+  if (!wordLevelIndex && !inFrag) return;
+
+  const unsigned char *textHere = &(el.text[0]);
+  const unsigned char *textEnd = &(el.text[el.text.size() - 1]);
+  UCArray word;
+  
+  if (!inaword (textHere, textEnd))
+    ParseNonindexWord (textHere, textEnd);
+
+  
+  // Alternately parse off words and non-words from the input
+  // Each token is then inserted into the set if it does
+  // not exist or has it's frequency count incremented if it does.
+
+  while (textHere <= textEnd) {
+    textHere = ParseIndexWord (textHere, textEnd, word);
+    textHere = ParseNonindexWord (textHere, textEnd);
+
+    if (!word.empty()) {
+      ++numWords;
+
+      if (wordLevelIndex) {
+	++numFrags;
+	++numChunkFrags;
+      }
+      
+      // update word stats
+
+      IvfWordInfo &i = ivfWordInfo[word];
+      if (i.wordCount == 0) {
+	// new word
+	// add to list of iterators
+	IvfWordInfoMap::iterator iIt = ivfWordInfo.find (word);
+	ivfWordInfoOccurOrder.push_back (iIt);
+
+	// add level information array
+	if (ivfLevel.levelInfo.size() > 0) 
+	  i.levels = new LevelWorker [ivfLevel.levelInfo.size()];
+      }
+
+      ++i.wordCount;
+      ++i.chunkWordCount;
+      if (numFrags > i.lastFragNum) {
+	++numChunkEntries;
+	++i.fragCount;
+	++i.chunkFragCount;
+	i.lastFragNum = numFrags;
+      }
+
+      // update level information for this word
+      if (i.levels != NULL) {
+	IvfLevelInfoMap::iterator levelHere = ivfLevel.levelInfo.begin();
+	IvfLevelInfoMap::iterator levelEnd = ivfLevel.levelInfo.end();
+	LevelWorker *levelWorkerPtr = i.levels;
+	while (levelHere != levelEnd) {
+
+	  // check to make sure the level encompases this fragment
+	  if (!(*levelHere).second.workInLevel) {
+	    cerr << "Level tag <" << (*levelHere).first
+		 << "> does not encompass all fragments\n";
+	    exit (1);
+	  }
+	  
+	  if ((*levelHere).second.numEntries > (*levelWorkerPtr).lastLevelDocNum) {
+	    (*levelWorkerPtr).lastLevelDocNum = (*levelHere).second.numEntries;
+	    ++levelWorkerPtr->count;
+	  }
+	  
+	  ++levelHere;
+	  ++levelWorkerPtr;
+	}
+      }
+    }
+  }
+}
+
+
+static unsigned long MemoryRequired (bool wordLevelIndex) {
+  register unsigned long total = 0;
+
+  // add memory required for word entries
+  IvfWordInfoMap::const_iterator wordHere = ivfWordInfo.begin();
+  IvfWordInfoMap::const_iterator wordEnd = ivfWordInfo.end();
+  while (wordHere != wordEnd) {
+    register const IvfWordInfo &info = (*wordHere).second;
+    if (info.chunkFragCount > 0) {
+      total += BIO_Bblock_Bound (numChunkFrags, info.chunkFragCount);
+      if (!wordLevelIndex) {
+	total += info.chunkWordCount;
+      }
+    }
+    
+    ++wordHere;
+  }
+
+  // add memory required for tag entries
+  IvfTagInfoMap::const_iterator tagHere = ivfTagInfo.begin();
+  IvfTagInfoMap::const_iterator tagEnd = ivfTagInfo.end();
+  while (tagHere != tagEnd) {
+    register const IvfTagInfo &info = (*tagHere).second;
+    if (info.chunkFragCount > 0) {
+      // two d entries for each frag entry
+      unsigned long pTag = info.chunkFragCount*2;
+      total += BIO_Bblock_Bound (numChunkFrags+pTag, pTag);
+    }
+    
+    ++tagHere;
+  }
+  
+  total = (total + 7) >> 3;
+  return total;
+}
+
+
+/*
+static void PrintChunkInfo (unsigned long mem) {
+  cout << "Chunk Number: " << chunksWritten << "\n";
+  cout << "numChunkDocs " << numChunkDocs << "\n";
+  cout << "numChunkFrags " << numChunkFrags << "\n";
+  cout << "mem " << mem << "\n";
+  cout << "numWords " << ivfWordInfo.size() << "\n";
+  cout << "numTags " << ivfTagInfo.size() << "\n\n";
+
+  // output debug tag information in dictionary order
+  IvfTagInfoMap::iterator tagMapHere = ivfTagInfo.begin();
+  IvfTagInfoMap::iterator tagMapEnd = ivfTagInfo.end();
+  unsigned long tagNum = 0;
+  while (tagMapHere != tagMapEnd) {
+    cout << (*tagMapHere).first << " " << tagNum
+	 << " " << (*tagMapHere).second.chunkFragCount << "\n";
+    ++tagNum;
+    ++tagMapHere;
+  }
+}
+*/
+
+static void OutputChunkInfo (unsigned long mem, bool /*wordLevelIndex*/) {
+  ++chunksWritten;
+
+  // sanity check
+  if (ivfWordInfo.size() != ivfWordInfoOccurOrder.size()) {
+    Message ("ERROR: Word information size mismatch: %u vs %u\n",
+	     (unsigned int)ivfWordInfo.size(),
+	     (unsigned int)ivfWordInfoOccurOrder.size());
+    exit (1);
+  }
+  if (ivfTagInfo.size() != ivfTagInfoOccurOrder.size()) {
+    Message ("ERROR: Tag information size mismatch: %u vs %u\n",
+	     (unsigned int)ivfTagInfo.size(),
+	     (unsigned int)ivfTagInfoOccurOrder.size());
+    exit (1);
+  }
+
+  icb.gamma_encode (numChunkDocs + 1, NULL);
+  icb.gamma_encode (numChunkFrags + 1, NULL);
+  icb.gamma_encode (mem + 1, NULL);
+  icb.gamma_encode (ivfWordInfo.size() + 1, NULL);
+  icb.gamma_encode (ivfTagInfo.size() + 1, NULL);
+
+  /*  PrintChunkInfo (mem);*/
+
+  // output word information in occurance order
+  IvfWordInfoItArray::iterator wordHere = ivfWordInfoOccurOrder.begin();
+  IvfWordInfoItArray::iterator wordEnd = ivfWordInfoOccurOrder.end();
+  while (wordHere != wordEnd) {
+    register IvfWordInfo &ivfWordInfo = (*(*wordHere)).second;
+    
+    icb.gamma_encode (ivfWordInfo.chunkWordCount + 1, NULL);
+    if (ivfWordInfo.chunkWordCount >= 2) {
+      icb.gamma_encode (ivfWordInfo.chunkFragCount, NULL);
+    }
+
+    ivfWordInfo.lastFragNum = 0;
+    ivfWordInfo.chunkWordCount = 0;
+    ivfWordInfo.chunkFragCount = 0;
+    
+    ++wordHere;
+  }
+
+  // output tag information in occurance order
+  IvfTagInfoItArray::iterator tagHere = ivfTagInfoOccurOrder.begin();
+  IvfTagInfoItArray::iterator tagEnd = ivfTagInfoOccurOrder.end();
+  while (tagHere != tagEnd) {
+    register IvfTagInfo &ivfTagInfo = (*(*tagHere)).second;
+
+    icb.gamma_encode (ivfTagInfo.chunkFragCount + 1, NULL);
+
+    ivfTagInfo.lastFragNum = 0;
+    ivfTagInfo.chunkFragCount = 0;
+    
+    ++tagHere;
+  }
+
+  numChunkDocs = 0;
+  numChunkFrags = 0;
+  numChunkEntries = 0;
+}
+
+
+int process_ivf_1 (const TagInfo &tagInfo, const TextElArray &doc) {
+  bool wordLevelIndex = tagInfo.indexLevel.empty();
+  bool inFrag = false;
+  if (wordLevelIndex) inFrag = true; // unconditional
+  
+  ++numDocs;
+  ++numChunkDocs;
+
+  // process each text element in this document
+  TextElArray::const_iterator here = doc.begin();
+  TextElArray::const_iterator end = doc.end();
+  while (here != end) {
+    if ((*here).elType == OpenTagE)
+      ProcessOpenTag (tagInfo, *here, inFrag);
+    else if ((*here).elType == CloseTagE)
+      ProcessCloseTag (tagInfo, *here, inFrag);
+    else if ((*here).elType == TextE)
+      ProcessText (tagInfo, *here, inFrag);
+    
+    ++here;
+  }
+
+  // check the amount of memory needed for this chunk
+  if (numChunkEntries >= entryCheckPoint) {
+    unsigned long mem = MemoryRequired (wordLevelIndex);
+    if (mem >= invf_buffer_size * CHECK_CLOSE) {
+      if (mem > maxMemNeeded) maxMemNeeded = mem;
+      OutputChunkInfo (mem, wordLevelIndex);
+      entryCheckPoint = (unsigned long)
+	((invf_buffer_size * INIT_CHECK_FRAC) / CHECK_DIV);
+      
+    } else {
+      entryCheckPoint = (unsigned long)
+	(entryCheckPoint * ((CHECK_FRAC * (invf_buffer_size - mem)) / mem) +
+	 entryCheckPoint);
+      if (entryCheckPoint <= numChunkEntries)
+	entryCheckPoint = numChunkEntries + 1;
+    }
+  }
+  
+  return COMPALLOK;
+}
+
+
+static void CalcInvfDictSize (unsigned long &totalBytes,
+			      unsigned long &indexStringBytes) {
+  totalBytes = 0;	// The sum of the length of all words, including 
+			// the length byte
+  indexStringBytes = 0; // The amount of space required to store the 
+			// words in the diction, this takes into account 
+			// the prefixes
+  const UCArray *lastWord = NULL;
+  
+  // calculate size of word information
+  IvfWordInfoMap::iterator wordHere = ivfWordInfo.begin();
+  IvfWordInfoMap::iterator wordEnd = ivfWordInfo.end();
+  while (wordHere != wordEnd) {
+    unsigned long wordSize = (*wordHere).first.size();
+    totalBytes += wordSize + 1;
+    indexStringBytes += wordSize + 2;
+    if (lastWord != NULL)
+      indexStringBytes -= PrefixLen (*lastWord, (*wordHere).first);
+    lastWord = &((*wordHere).first);
+    
+    ++wordHere;
+  }
+
+  // calculate size of tag information
+  lastWord = NULL;
+  IvfTagInfoMap::iterator tagHere = ivfTagInfo.begin();
+  IvfTagInfoMap::iterator tagEnd = ivfTagInfo.end();
+  while (tagHere != tagEnd) {
+    unsigned long tagSize = (*tagHere).first.size();
+    totalBytes += tagSize + 1;
+    indexStringBytes += tagSize + 2;
+    if (lastWord != NULL)
+      indexStringBytes -= PrefixLen (*lastWord, (*tagHere).first);
+    lastWord = &((*tagHere).first);
+    
+    ++tagHere;
+  }
+}
+
+
+//      OutputInvfDict ():
+//                writes out the stemmed dictionary file
+//                in the following format 
+//                        lookback value (int)
+//                        totalbytes value (int)
+//                        indexstringbytes (int)
+//                        for each word 
+//                          wordlen (4 bits)
+//                          prefix match (4 bits)
+//                          word (wordlen bytes)
+//                          word frequency (int)
+//                          word count (int)
+//
+//        Accesses outside variables:     
+//
+//        Return value...:                
+static void OutputInvfDict (char *filename) {
+  // create the dictionary header
+  invf_dict_header idh;
+  idh.word_dict_size = ivfWordInfo.size();
+  idh.tag_dict_size = ivfTagInfo.size();
+  idh.num_docs = numDocs;
+  idh.num_frags = numFrags;
+  idh.num_words = numWords;
+  idh.num_levels = ivfLevel.levelInfo.size();
+  CalcInvfDictSize (idh.total_bytes, idh.index_string_bytes);
+
+  // create the inverted dictionary file
+  FILE *sp;
+  if (!(sp = create_file (filename, INVF_DICT_SUFFIX, "wb", MAGIC_STEM_BUILD,
+			  MG_MESSAGE)))
+    return;
+
+  // write out the dictionary header
+  if (!idh.Write (sp)) { fclose (sp); return; }
+
+  // remember where the word dictionary starts
+  idh.word_dict_start = ftell (sp);
+  
+  // output the word dictionary
+  const UCArray *lastWord = NULL;
+  IvfWordInfoMap::iterator wordHere = ivfWordInfo.begin();
+  IvfWordInfoMap::iterator wordEnd = ivfWordInfo.end();
+  while (wordHere != wordEnd) {
+    // get the prefix and suffix lengths
+    const UCArray &thisWord = (*wordHere).first;
+    WritePreSufStr (sp, lastWord, thisWord);
+
+    // output the number of fragments the word appeared in and the
+    // number of times the word appeared
+    WriteUL (sp, (*wordHere).second.fragCount);
+    WriteUL (sp, (*wordHere).second.wordCount);
+
+    // output frequency information for each level
+    // note that we are expecting every word to have
+    // level information
+    LevelWorker *lwHere = (*wordHere).second.levels;
+    LevelWorker *lwEnd = lwHere + idh.num_levels;
+    while (lwHere != lwEnd) {
+      WriteUL (sp, (*lwHere).count);
+      ++lwHere;
+    }
+    
+    lastWord = &thisWord;
+    ++wordHere;
+  }
+
+  // remember where the tag dictionary starts
+  idh.tag_dict_start = ftell (sp);
+  
+  // output the tag dictionary
+  const UCArray *lastTag = NULL;
+  IvfTagInfoMap::iterator tagHere = ivfTagInfo.begin();
+  IvfTagInfoMap::iterator tagEnd = ivfTagInfo.end();
+  while (tagHere != tagEnd) {
+    // get the prefix and suffix lengths
+    const UCArray &thisTag = (*tagHere).first;
+    WritePreSufStr (sp, lastTag, thisTag);
+
+    // output the number of fragments the tag appeared in and the
+    // number of times the tag appeared
+    WriteUL (sp, (*tagHere).second.fragCount);
+    WriteUL (sp, (*tagHere).second.tagCount);
+    
+    lastTag = &thisTag;
+    ++tagHere;
+  }
+
+  // write out the updated header
+  fseek (sp, sizeof (u_long), SEEK_SET);
+  if (!idh.Write (sp)) { fclose (sp); return; }
+  
+  fclose (sp);
+}
+
+static void OutputLevelFile (char *filename) {
+  // create the level file
+  FILE *f;
+  if (!(f = create_file (filename, INVF_LEVEL_SUFFIX, "wb", MAGIC_INVF_LEVELS,
+			 MG_MESSAGE)))
+    return;
+
+  // write out the information
+  ivfLevel.Write (f);
+  
+  // close the file
+  fclose (f);
+}
+
+static void OutputTransFile (char *filename) {
+  // save the word number (in lastFragNum :-/)
+  int i = 0;
+  IvfWordInfoMap::iterator wordHere = ivfWordInfo.begin();
+  IvfWordInfoMap::iterator wordEnd = ivfWordInfo.end();
+  while (wordHere != wordEnd) {
+    (*wordHere).second.lastFragNum = i;
+    ++i; ++wordHere;
+  }
+
+  // save the tag number (in lastFragNum :-/)
+  i = 0;
+  IvfTagInfoMap::iterator tagHere = ivfTagInfo.begin();
+  IvfTagInfoMap::iterator tagEnd = ivfTagInfo.end();
+  while (tagHere != tagEnd) {
+    (*tagHere).second.lastFragNum = i;
+    ++i; ++tagHere;
+  }
+  
+  // create the translation file
+  FILE *f;
+  if (!(f = create_file (filename, INVF_CHUNK_TRANS_SUFFIX, "wb",
+			 MAGIC_CHUNK_TRANS, MG_MESSAGE)))
+    return;
+
+  stdio_bitio_buffer buffer(f);
+  buffer.encodeStart();
+
+  // write out the word translation table
+  unsigned long wordDictSize = ivfWordInfoOccurOrder.size();
+  IvfWordInfoItArray::iterator wordItHere = ivfWordInfoOccurOrder.begin();
+  IvfWordInfoItArray::iterator wordItEnd = ivfWordInfoOccurOrder.end();
+  unsigned long oN = 0;
+  while (wordItHere != wordItEnd) {
+    register IvfWordInfo &ivfWordInfo = (*(*wordItHere)).second;
+    buffer.binary_encode (ivfWordInfo.lastFragNum + 1, wordDictSize + 1, NULL);
+    ++oN;
+    ++wordItHere;
+  }
+
+  // write out the tag translation table
+  unsigned long tagDictSize = ivfTagInfoOccurOrder.size();
+  IvfTagInfoItArray::iterator tagItHere = ivfTagInfoOccurOrder.begin();
+  IvfTagInfoItArray::iterator tagItEnd = ivfTagInfoOccurOrder.end();
+  while (tagItHere != tagItEnd) {
+    register IvfTagInfo &ivfTagInfo = (*(*tagItHere)).second;
+    buffer.binary_encode (ivfTagInfo.lastFragNum + 1, tagDictSize + 1, NULL);
+    ++oN;
+    ++tagItHere;
+  }
+
+  // finish encoding and close the file
+  buffer.encodeDone();
+  fclose (f);
+}
+
+#ifndef SILENT
+static void PrintStats () {
+  Message ("Inverted buffer size:          %8u bytes\n", invf_buffer_size);
+  Message ("Max memory needed for 1 chunk: %8u bytes\n", maxMemNeeded);
+
+  Message ("Number of chunks written:      %8u\n", chunksWritten);
+  Message ("Number of documents:           %8u\n", numDocs);
+  Message ("Number of fragments:           %8u\n", numFrags);
+  Message ("Number of words:               %8u\n", numWords);
+
+  Message ("Size of word dictionary:       %8u\n", ivfWordInfo.size());
+  Message ("Size of tag dictionary:        %8u\n", ivfTagInfo.size());
+}
+#endif
+
+int done_ivf_1 (const TagInfo &tagInfo, char * filename) {
+  bool wordLevelIndex = tagInfo.indexLevel.empty();
+
+  char *temp_str = msg_prefix;
+  msg_prefix = "ivf.pass1";
+
+  // output the last chunk
+  if (numChunkDocs > 0) {
+    unsigned long mem = MemoryRequired (wordLevelIndex);
+    OutputChunkInfo (mem, wordLevelIndex);
+    if (mem > maxMemNeeded) maxMemNeeded = mem;
+  }
+  
+  // write out and encoded 1 to say there are no more chunks
+  icb.gamma_encode (1, NULL);
+  icb.encodeDone ();
+
+  // write out the maximum memory required and close the file
+  fseek (ic, sizeof (long), 0);
+  WriteUL (ic, maxMemNeeded);
+  fclose (ic);
+
+  // output the inverted dictionary
+  OutputInvfDict (filename);
+
+  // write out the translation file
+  OutputTransFile (filename);
+
+  // output the level information
+  OutputLevelFile (filename);
+  
+  // output statistics
+#ifndef SILENT
+  PrintStats ();
+#endif
+  
+  msg_prefix = temp_str;
+
+  return COMPALLOK;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/ivf.pass2.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/ivf.pass2.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/ivf.pass2.cpp	(revision 10506)
@@ -0,0 +1,1111 @@
+/**************************************************************************
+ *
+ * ivf.pass2.cpp -- Memory efficient pass 2 inversion
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+#include <stdio.h>
+
+#if defined __WIN32__
+# include <process.h>
+# include <io.h>
+# define getpid _getpid
+# define unlink _unlink
+#else
+# include <unistd.h>
+# include "non_ansi.h"
+#endif
+
+#include "UCArray.h"
+#include "sysfuncs.h"
+#include "mg_files.h"
+#include "invf.h"
+#include "mg.h"
+#include "build.h"
+#include "locallib.h"
+#include "bitio_m_random.h"
+#include "bitio_m_stdio.h"
+#include "bitio_m_mems.h"
+#include "bitio_gen.h"
+#include <stdio.h>
+#include "words.h"
+#include "messages.h"
+#include "netorder.h"
+#include "FIvfLevelInfo.h"
+#include "perf_hash.h"
+#include "string.h"
+
+#include "longlong.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+#ifdef USE_LONG_LONG
+#define SEEK_X seek_LL
+#define TELL_X tell_LL
+#else
+#define SEEK_X seek
+#define TELL_X tell
+#endif
+
+#ifndef RND_BUF_SIZE
+#define RND_BUF_SIZE 8*1024
+#endif
+
+
+static unsigned long numDocs = 0;
+static unsigned long numChunkDocs = 0;
+static unsigned long numDocsInChunk = 0;
+
+static unsigned long numFrags = 0;
+static unsigned long numFragsInChunk = 0;
+static unsigned long chunkStartFragNum = 0;
+
+
+
+
+struct BitPtr {
+  unsigned long start;
+  unsigned long here;
+  unsigned long lastFragNum;
+  unsigned long lgB;
+  
+  void Clear () { start = here = lastFragNum = lgB = 0; }
+  BitPtr () { Clear(); }
+};
+
+class WordBitPtrs {
+protected:
+  unsigned long numWords;
+  unsigned long numTags;
+  unsigned long size;
+  BitPtr *wordBitPtrs;
+
+  void CheckBufOverrun (unsigned long num) {
+    if (wordBitPtrs[num].here > wordBitPtrs[num+1].start) {
+      cerr << "numDocs: " << numDocs << "\n";
+      cerr << "numChunkDocs: " << numChunkDocs << "\n";
+      cerr << "numDocsInChunk: " << numDocsInChunk << "\n";
+      cerr << "numFrags: " << numFrags << "\n";
+      cerr << "numFragsInChunk: " << numFragsInChunk << "\n";
+      cerr << "chunkStartFragNum: " << chunkStartFragNum << "\n";
+      cerr << "num: " << num << "\n";
+      cerr << "[num].start: " << wordBitPtrs[num].start << "\n";
+      cerr << "[num].here: " << wordBitPtrs[num].here << "\n";
+      cerr << "[num+1].start: " << wordBitPtrs[num+1].start << "\n";
+      FatalError (1, "Bit buffer overrun");
+    }
+  }
+  
+public:
+  void Clear ();
+  WordBitPtrs () { wordBitPtrs = NULL; Clear(); }
+  ~WordBitPtrs ();
+  void SetSize (unsigned long _numWords,
+		unsigned long _numTags);
+
+  void ResetPtrs () {
+    if (wordBitPtrs == NULL) return;
+    unsigned long i;
+    for (i=0; i<size; ++i) wordBitPtrs[i].Clear();
+  }
+  
+  BitPtr &GetWordBitPtr (unsigned long wordNum)
+    { return wordBitPtrs[wordNum]; }
+  unsigned long &GetWordStart (unsigned long wordNum)
+    { return wordBitPtrs[wordNum].start; }
+  unsigned long &GetWordHere (unsigned long wordNum)
+    { return wordBitPtrs[wordNum].here; }
+  void CheckWordBufOverrun (unsigned long wordNum)
+    { CheckBufOverrun (wordNum); }
+
+  BitPtr &GetTagBitPtr (unsigned long tagNum)
+    { return wordBitPtrs[tagNum + numWords]; }
+  unsigned long &GetTagStart (unsigned long tagNum)
+    { return wordBitPtrs[tagNum + numWords].start; }
+  unsigned long &GetTagHere (unsigned long tagNum)
+    { return wordBitPtrs[tagNum + numWords].here; }
+  void CheckTagBufOverrun (unsigned long tagNum)
+    { CheckBufOverrun (tagNum + numWords); }
+
+  BitPtr &GetEndBitPtr ()
+    { return wordBitPtrs[size-1]; }
+  unsigned long &GetEndStart ()
+    { return wordBitPtrs[size-1].start; }
+  unsigned long &GetEndHere ()
+    { return wordBitPtrs[size-1].here; }
+};
+
+
+struct IP2TagInfo {
+  bool inTag;
+  unsigned long startFrag;
+  unsigned long tagNum;
+
+  IP2TagInfo () {
+    inTag = false;
+    startFrag = 0;
+    tagNum = 0;
+  }
+};
+
+// maps tags to tag information
+typedef map<UCArray, IP2TagInfo, DictLTUCArray> TagMapDict;
+
+
+// class to handle the translation of occurrence order
+// to dictionary order for words and tags
+class OccurToDictConverter {
+protected:
+  unsigned long pos;
+  unsigned long val;
+  FILE *transFile;
+  random_bitio_buffer rbs;
+
+  unsigned long wordDictSize;
+  unsigned long tagDictSize;
+
+  void SeekStart ();
+  unsigned long TranslateNum (unsigned long num);
+  
+public:
+  OccurToDictConverter ();
+  ~OccurToDictConverter ();
+
+  void Open (char *filename, unsigned long _wordDictSize,
+	     unsigned long _tagDictSize);
+
+  // Close frees all allocated memory
+  void Close ();
+
+  unsigned long TranslateWord (unsigned long occurNum)
+    { return TranslateNum (occurNum); }
+  unsigned long TranslateTag (unsigned long occurNum)
+    { return TranslateNum (occurNum+wordDictSize); }
+};
+
+
+struct InvfStateRec {
+  mg_ullong start;
+  mg_ullong here;
+  unsigned long lastFragNum;
+  unsigned long B;
+
+  void Clear () {
+    start = here = 0;
+    lastFragNum = B = 0;
+  }
+  InvfStateRec () { Clear (); }
+};
+
+
+#define ISR_SIZE 1024
+
+class InvfStateCache {
+protected:
+  InvfStateRec recCache [ISR_SIZE];
+  unsigned long startNum;
+
+  FILE *stateFile;
+
+  void ClearCache () {
+    unsigned int i = 0;
+    for (i=0; i<ISR_SIZE; ++i) recCache[i].Clear();
+  }
+  
+public:
+  InvfStateCache ();
+  ~InvfStateCache ();
+  
+  void Open (char *filename);
+  void Close ();
+
+  // previous references to state records may be
+  // invalidated calling GetRec
+  InvfStateRec &GetRec (unsigned long num);
+};
+
+
+static invf_dict_header idh;
+static WordBitPtrs bitPtrs;
+
+static FILE *chunkFile = NULL;
+static stdio_bitio_buffer chunkBuf;
+
+static unsigned long ivfMemBufSize = 0;
+static char *ivfMemBuf = NULL;
+
+// word and tag dictionaries. a map is used for the tag dictionary
+// as it should never be very big (and the perfect hash function
+// sometimes has trouble with small values).
+static perf_hash_data *wordHashDict = NULL;
+static TagMapDict tagMapDict;
+
+// information about all the different levels
+static FIvfLevel ivfLevel;
+
+static OccurToDictConverter occurConvert;
+
+// information about the state of the inverted file
+static InvfStateCache invfState;
+
+static char collectFilename[512];
+
+
+void WordBitPtrs::Clear () {
+  numWords = 0;
+  numTags = 0;
+  size=0;
+  if (wordBitPtrs != NULL) delete [] wordBitPtrs;
+  wordBitPtrs = NULL;
+}
+
+WordBitPtrs::~WordBitPtrs () {
+  if (wordBitPtrs != NULL) delete [] wordBitPtrs;
+}
+
+void WordBitPtrs::SetSize (unsigned long _numWords,
+			   unsigned long _numTags){
+  Clear();
+  numWords = _numWords;
+  numTags = _numTags;
+  size = numWords + numTags + 1;
+  wordBitPtrs = new BitPtr [size];
+}
+
+
+void OccurToDictConverter::SeekStart () {
+  if (transFile == NULL) return;
+  rbs.SEEK_X (sizeof (unsigned long) * 8);
+  pos = 0;
+}
+
+unsigned long OccurToDictConverter::TranslateNum (unsigned long num) {
+  if (num < pos) SeekStart ();
+  while (pos <= num) {
+    if (pos < wordDictSize)
+      val = rbs.binary_decode (wordDictSize + 1, NULL) - 1;
+    else 
+      val = rbs.binary_decode (tagDictSize + 1, NULL) - 1;
+    ++pos;
+  }
+  return val;
+}
+
+OccurToDictConverter::OccurToDictConverter () {
+  pos = 0;
+  val = 0;
+  transFile = NULL;
+  wordDictSize = 0;
+  tagDictSize = 0;
+}
+
+OccurToDictConverter::~OccurToDictConverter () {
+  if (transFile != NULL) Close ();
+}
+
+void OccurToDictConverter::Open (char *filename, unsigned long _wordDictSize,
+				 unsigned long _tagDictSize) {
+  if (transFile != NULL) Close ();
+
+  wordDictSize = _wordDictSize;
+  tagDictSize = _tagDictSize;
+
+  transFile = open_file (filename, INVF_CHUNK_TRANS_SUFFIX, "rb",
+			 MAGIC_CHUNK_TRANS, MG_ABORT);
+  rbs.attachFile (transFile, RND_BUF_SIZE);
+  SeekStart ();
+  val = 0;
+}
+
+void OccurToDictConverter::Close () {
+  if (transFile == NULL) return;
+
+  rbs.done ();
+  fclose (transFile);
+  transFile = NULL;
+  pos = 0;
+  val = 0;
+
+  wordDictSize = 0;
+  tagDictSize = 0;
+}
+
+
+
+
+InvfStateCache::InvfStateCache () {
+  startNum = 0;
+  stateFile = NULL;
+}
+
+InvfStateCache::~InvfStateCache () {
+  if (stateFile != NULL) Close ();
+}
+  
+void InvfStateCache::Open (char *filename) {
+  if (stateFile != NULL) Close();
+
+  // open the state file
+  char path[512];
+  sprintf (path, FILE_NAME_FORMAT ".%ld", get_basepath (), filename,
+           ".invf.state", (long) getpid ());
+  if (!(stateFile = fopen (path, "wb+"))) {
+    Message ("Unable to create \"%s\"", path);
+    exit (1);
+  }
+  unlink (path); // file will be deleted after it is closed
+  // reset the buffer
+  startNum = 0;
+  ClearCache();
+}
+
+void InvfStateCache::Close () {
+  if (stateFile == NULL) return;
+  fclose (stateFile);
+  stateFile = NULL;
+  startNum = 0;
+}
+
+InvfStateRec &InvfStateCache::GetRec (unsigned long num) {
+  // see if cached
+  if ((num >= startNum) && (num < startNum + ISR_SIZE))
+    return recCache[num-startNum];
+
+  // not cached, write out this lot of records and read in
+  fseek (stateFile, startNum*sizeof (InvfStateRec), SEEK_SET);
+  fwrite ((char *) recCache, sizeof (InvfStateRec), ISR_SIZE, stateFile);
+
+  // read in the new set of records
+  ClearCache ();
+  startNum = num - (num % ISR_SIZE);
+  fseek (stateFile, startNum*sizeof (InvfStateRec), SEEK_SET);
+  fread ((char *) recCache, sizeof (InvfStateRec), ISR_SIZE, stateFile);
+
+  return recCache[num-startNum];
+}
+
+
+
+static void ClearCharBuf (char *buf, unsigned long size) {
+  char *end = buf + size;
+  while (buf != end) *buf++ = 0;
+}
+
+static void ReadWordDict (char *filename) {
+  // read in the perfect hash function for the word dictionary
+  FILE *wordHashFile = open_file (filename, INVF_DICT_HASH_SUFFIX, "rb",
+				  MAGIC_HASH, MG_ABORT);
+  if (!(wordHashDict = read_perf_hash_data (wordHashFile))) {
+    FatalError (1, "Unable to read in hash data for word dictionary");
+  }
+  fclose (wordHashFile);
+}
+
+static void ReadTagDict (char *filename, invf_dict_header &_idh) {
+  // open the file
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+
+  // seek to the start of the tag dictionary
+  fseek (dictFile, _idh.tag_dict_start, SEEK_SET);
+  
+  unsigned long tagNum;
+  dict_el thisEl;
+  for (tagNum = 0; tagNum < _idh.tag_dict_size; ++tagNum) {
+    thisEl.Read (dictFile);
+    tagMapDict[thisEl.el].tagNum = tagNum;
+  }
+  
+  fclose (dictFile);
+}
+
+static void ReadLevelFile (char *filename) {
+  FILE *f;
+  f = open_file (filename, INVF_LEVEL_SUFFIX, "rb",
+		 MAGIC_INVF_LEVELS, MG_ABORT);
+  ivfLevel.Read (f);
+  fclose (f);
+}
+
+void CheckIntOverflow (mg_ullong totalIBits, mg_ullong lastTotalIBits) {
+  if (totalIBits < lastTotalIBits) {
+    fprintf(stderr, "ERROR: The totalIBits counter (%d byte unsigned integer) has overflowed.\n", sizeof (mg_ullong));
+    if (sizeof (mg_ullong) < 8) {
+      fprintf(stderr, "       Try compiling with GCC to enable use of 8 bytes for this counter.\n");
+    }
+    fprintf(stderr, "       Build aborted.\n");
+    exit(1);
+  }
+}
+
+// assumes the inverted file state file has been opened
+static void InitInvfState (char *filename,
+			   invf_dict_header &_idh,
+			   InvfStateCache &_invfState,
+			   mg_ullong &totalIBits,
+			   bool wordLevelIndex) {
+  // read in the dictionary, setting inverted state information
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+
+  // seek to the start of the word dictionary
+  fseek (dictFile, _idh.word_dict_start, SEEK_SET);
+
+  // add the word entries
+  word_dict_el wordEl;
+  wordEl.SetNumLevels (_idh.num_levels);
+  unsigned long dictWordNum, p;
+  mg_ullong lastTotalIBits;
+  unsigned long N = _idh.num_frags;
+  for (dictWordNum=0; dictWordNum<_idh.word_dict_size; ++dictWordNum) {
+    // lastTotalIBits is used to detect integer overflow
+    lastTotalIBits = totalIBits;
+
+    // read the next word and associated information
+    wordEl.Read (dictFile, _idh.num_levels);
+
+    // update the state record
+    p = wordEl.frag_occur;
+    InvfStateRec &wisr = _invfState.GetRec (dictWordNum);
+    wisr.start = totalIBits;
+    wisr.here = totalIBits;
+    wisr.B = BIO_Bblock_Init (N, p);
+    
+    // add the length of the fragment numbers
+    totalIBits += BIO_Bblock_Bound_b (N, p, wisr.B);
+
+    // if needed, add the length of the fragment frequency information
+    if (!wordLevelIndex)
+      totalIBits += BIO_Gamma_Bound (wordEl.freq, wordEl.frag_occur);
+
+    // align next byte
+#ifdef USE_LONG_LONG
+    totalIBits = (totalIBits + 7ull) & 0xfffffffffffffff8ull;
+#else
+    totalIBits = (totalIBits + 7ul) & 0xfffffff8ul;
+#endif
+
+    CheckIntOverflow (totalIBits, lastTotalIBits);
+  }
+
+  
+  // seek to the start of the tag dictionary
+  fseek (dictFile, _idh.tag_dict_start, SEEK_SET);
+
+  // add the tag entries
+  dict_el tagEl;
+  unsigned long dictTagNum;
+  N = _idh.num_frags;
+  for (dictTagNum=0; dictTagNum<_idh.tag_dict_size; ++dictTagNum) {
+    // lastTotalIBits is used to detect integer overflow
+    lastTotalIBits = totalIBits;
+
+    // read the next tag and associated information
+    tagEl.Read (dictFile);
+
+    // update the state record
+    p = tagEl.frag_occur*2;
+    InvfStateRec &tisr = _invfState.GetRec (dictTagNum + _idh.word_dict_size);
+    tisr.start = totalIBits;
+    tisr.here = totalIBits;
+    tisr.B = BIO_Bblock_Init (N+p, p);
+    
+    // add the length of the fragment numbers (two numbers for each
+    // tag, one for start and one for end)
+    totalIBits += BIO_Bblock_Bound_b (N+p, p, tisr.B);
+
+    // align next byte
+#ifdef USE_LONG_LONG
+    totalIBits = (totalIBits + 7ull) & 0xfffffffffffffff8ull;
+#else
+    totalIBits = (totalIBits + 7ul) & 0xfffffff8ul;
+#endif
+
+    CheckIntOverflow (totalIBits, lastTotalIBits);
+  }
+
+  fclose (dictFile);
+}
+
+/*
+// assumes the chunk tag information has been placed in .first
+static void PrintChunkInfo (unsigned long chunkMem,
+			    unsigned long numChunkWords,
+			    unsigned long numChunkTags) {
+  static unsigned long chunksRead = 0;
+  ++chunksRead;
+  cout << "Chunk Number: " << chunksRead << "\n";
+  cout << "numChunkDocs " << numDocsInChunk << "\n";
+  cout << "numChunkFrags " << numFragsInChunk << "\n";
+  cout << "mem " << chunkMem << "\n";
+  cout << "numWords " << numChunkWords << "\n";
+  cout << "numTags " << numChunkTags << "\n\n";
+
+  TagMapDict::iterator tagMapHere = tagMapDict.begin();
+  TagMapDict::iterator tagMapEnd = tagMapDict.end();
+  while (tagMapHere != tagMapEnd) {
+    unsigned long tagMapNum = (*tagMapHere).second.tagNum;
+    cout << (*tagMapHere).first << " " << tagMapNum << " "
+	 << bitPtrs.GetTagBitPtr(tagMapNum).here << "\n";
+    ++tagMapHere;
+  }
+}
+*/
+
+void ReadChunk (invf_dict_header &_idh, bool wordLevelIndex) {
+  // reset globals
+  numChunkDocs = 0;
+  chunkStartFragNum = numFrags;
+
+  // read in information about this chunk
+  numDocsInChunk = chunkBuf.gamma_decode (NULL) - 1;
+  if (numDocsInChunk == 0)
+    FatalError (1, "The number of docs in the current chunk is 0");
+
+  numFragsInChunk = chunkBuf.gamma_decode (NULL) - 1;
+  unsigned long chunkMem = chunkBuf.gamma_decode (NULL) - 1;
+
+  if (chunkMem > ivfMemBufSize)
+    FatalError (1, "Chunk memory size is greater than maximum");
+  
+  unsigned long numChunkWords = chunkBuf.gamma_decode (NULL) - 1;
+  unsigned long numChunkTags = chunkBuf.gamma_decode (NULL) - 1;
+
+  
+  // reset stuff
+  ClearCharBuf (ivfMemBuf, ivfMemBufSize);
+  bitPtrs.ResetPtrs();  
+
+  // read in the entries in occurrence order storing the
+  // "chunkWordCount" in "start" and the "chunkFragCount"
+  // in "here"
+  unsigned long numOccur;
+  unsigned long wordNum;
+  for (numOccur=0; numOccur<numChunkWords; ++numOccur) {
+    wordNum = occurConvert.TranslateWord (numOccur);
+    BitPtr &wordPtr = bitPtrs.GetWordBitPtr (wordNum);
+    wordPtr.start = chunkBuf.gamma_decode (NULL) - 1;
+    if (wordPtr.start >= 2)
+      wordPtr.here = chunkBuf.gamma_decode (NULL);
+    else wordPtr.here = wordPtr.start;
+  }
+  unsigned long tagNum;
+  for (numOccur=0; numOccur<numChunkTags; ++numOccur) {
+    tagNum = occurConvert.TranslateTag (numOccur);
+    BitPtr &tagPtr = bitPtrs.GetTagBitPtr (tagNum);
+    // only chunkFragCount is encoded for tags
+    tagPtr.start = chunkBuf.gamma_decode (NULL) - 1;
+    tagPtr.here = tagPtr.start;
+  }
+
+  /*  PrintChunkInfo (chunkMem, numChunkWords, numChunkTags);*/
+  
+  // create the bit ptrs in dictionary order
+  unsigned long totalIBits = 0; // only dealing with memory
+  unsigned long chunkWordCount, chunkFragCount;
+  for (wordNum=0; wordNum<_idh.word_dict_size; ++wordNum) {
+    BitPtr &wordPtr = bitPtrs.GetWordBitPtr (wordNum);
+    chunkWordCount = wordPtr.start;
+    chunkFragCount = wordPtr.here;
+    wordPtr.start = totalIBits;
+    wordPtr.here = totalIBits;
+    wordPtr.lastFragNum = chunkStartFragNum;
+    wordPtr.lgB = 0;
+    if (chunkWordCount > 0) {
+      wordPtr.lgB = floorlog_2 (BIO_Bblock_Init_W (numFragsInChunk,
+						   chunkFragCount));
+      totalIBits += BIO_Bblock_Bound (numFragsInChunk, chunkFragCount);
+      // use unary encoding for memory buffer encoding of fragment freq
+      if (!wordLevelIndex) {
+	totalIBits += chunkWordCount;
+      }
+    }
+  }
+  for (tagNum=0; tagNum<_idh.tag_dict_size; ++tagNum) {
+    BitPtr &tagPtr = bitPtrs.GetTagBitPtr (tagNum);
+    chunkFragCount = tagPtr.here;
+    tagPtr.start = totalIBits;
+    tagPtr.here = totalIBits;
+    tagPtr.lastFragNum = chunkStartFragNum;
+    tagPtr.lgB = 0;
+    if (chunkFragCount > 0) {
+      unsigned long pTag = chunkFragCount*2;
+      tagPtr.lgB = floorlog_2 (BIO_Bblock_Init_W (numFragsInChunk+pTag,
+						  pTag));
+      unsigned long bLen = BIO_Bblock_Bound (numFragsInChunk+pTag,
+					     pTag);
+//        cout << tagNum + _idh.word_dict_size << " ";
+//        cout << "numFrags: " << numFragsInChunk
+//    	   << " chunkFragCount: " << chunkFragCount
+//    	   << " B: " << 1 << tagPtr.lgB
+//    	   << " blen: " << blen << "\n";
+      totalIBits += bLen;
+    }
+  }
+  bitPtrs.GetEndStart() = totalIBits;
+  bitPtrs.GetEndHere() = totalIBits;
+
+  if ((totalIBits + 7ul) >> 3ul > chunkMem) {
+    cerr << "totalIBits: " << totalIBits << "\n";
+    cerr << "bytes: " << ((totalIBits + 7ul) >> 3ul) << "\n";
+    cerr << "chunkMem: " << chunkMem << "\n";
+    FatalError (1, "Pointers exceed buffer size");
+  }
+}
+
+
+
+
+int init_ivf_2 (const TagInfo &/*tagInfo*/, char *filename) {
+  // read in compressed dictionary header
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+  idh.Read (dictFile);
+  fclose (dictFile);
+
+  // set the size of the bit ptrs
+  bitPtrs.SetSize (idh.word_dict_size, idh.tag_dict_size);
+
+  // open the chunk file and read in the maximum memory needed
+  // for the inverted memory buffer
+  chunkFile = open_file (filename, INVF_CHUNK_SUFFIX, "rb",
+			 MAGIC_CHUNK, MG_ABORT);
+  ReadUL (chunkFile, ivfMemBufSize);
+  chunkBuf.attachFile (chunkFile);
+
+  // allocate memory for the inverted buffer
+  ivfMemBuf = new char [ivfMemBufSize];
+  ClearCharBuf (ivfMemBuf, ivfMemBufSize);
+
+  // read in the word dictionary
+  ReadWordDict (filename);
+
+  // read in the tag dictionary
+  ReadTagDict (filename, idh);
+
+  // read in the level information
+  ReadLevelFile (filename);
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+  
+  // set up the translation table file
+  occurConvert.Open (filename, idh.word_dict_size, idh.tag_dict_size);
+
+  // reset some globals
+  numDocs = 0;
+  numChunkDocs = 0;
+  numDocsInChunk = 0;
+  numFrags = 0;
+  numFragsInChunk = 0;
+  chunkStartFragNum = 0;
+
+  strcpy (collectFilename, filename);
+  
+  
+  // create the inverted file
+  mg_ullong totalIBits = 0;
+  FILE *invfFile = create_file (filename, INVF_SUFFIX, "wb",
+				MAGIC_INVF, MG_ABORT);
+  totalIBits += sizeof (unsigned long) * 8; // magic number
+  totalIBits += 8 * 200;                    // 200 byte gap -- why??????
+  fclose (invfFile);
+
+  // init the inverted file state cache
+  invfState.Open (filename);
+  InitInvfState (filename, idh, invfState, totalIBits, wordLevelIndex);
+
+  return COMPALLOK;
+}
+
+static void CloseTextTag (IP2TagInfo &tInfo, const UCArray &/*tagName*/) {
+  if (!tInfo.inTag) return;
+
+    // add this tag to the inverted list
+  BitPtr &tagBitPtr = bitPtrs.GetTagBitPtr (tInfo.tagNum);
+  unsigned long endFrag = numFrags;
+  int b = 1 << tagBitPtr.lgB;
+
+  /*
+  cout << (tInfo.tagNum+idh.word_dict_size) << " \"<" << tagName << ">\" "
+       << tInfo.startFrag << " " << endFrag << "\n";
+  */
+    
+  mems_bitio_buffer buffer ((u_char *) ivfMemBuf, tagBitPtr.here);
+  buffer.bblock_encode (tInfo.startFrag - tagBitPtr.lastFragNum + 1,
+			b, NULL);
+  buffer.bblock_encode (endFrag - tInfo.startFrag + 1, b, NULL);
+  tagBitPtr.lastFragNum = endFrag;
+  tagBitPtr.here = buffer.position();
+  buffer.encodeDone();
+  
+  // check for buffer overrun
+  bitPtrs.CheckTagBufOverrun (tInfo.tagNum);
+  
+  // reset information about this tag
+  tInfo.inTag = false;
+  tInfo.startFrag = 0;
+}
+
+static void ProcessOpenTag (const TextEl &el, bool &inFrag) {
+  // close tag if open
+  IP2TagInfo &tInfo = tagMapDict[el.tagName];
+  if (tInfo.inTag) CloseTextTag (tInfo, el.tagName);
+
+  // open this tag
+  tInfo.inTag = true;
+  tInfo.startFrag = numFrags;
+
+  // check for start of next fragment
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+  if (!wordLevelIndex && el.tagName == ivfLevel.indexLevel) {
+    ++numFrags;
+    inFrag = true;
+  }
+}
+
+static void ProcessCloseTag (const TextEl &el, bool &inFrag) {
+  // check for end of fragment
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+  if (!wordLevelIndex && el.tagName == ivfLevel.indexLevel) {
+    inFrag = false;
+  }
+
+  IP2TagInfo &tInfo = tagMapDict[el.tagName];
+  CloseTextTag (tInfo, el.tagName);
+}
+
+static void ProcessText (const TextEl &el, bool &inFrag) {
+  // make sure this text is to be indexed
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+  if (!wordLevelIndex && !inFrag) return;
+
+  const unsigned char *textHere = &(el.text[0]);
+  const unsigned char *textEnd = &(el.text[el.text.size() - 1]);
+  unsigned char mgWord[MAXSTEMLEN + 1];
+  
+  if (!inaword (textHere, textEnd))
+    ParseNonindexWord (textHere, textEnd);
+
+  
+  // Alternately parse off words and non-words from the input
+
+  while (textHere <= textEnd) {
+    textHere = ParseIndexMGWord (textHere, textEnd, mgWord);
+    textHere = ParseNonindexWord (textHere, textEnd);
+
+    if (mgWord[0] > 0) {
+      if (wordLevelIndex) ++numFrags;
+
+      unsigned long wordNum = perf_hash (wordHashDict, mgWord);
+
+      /*
+      cout << wordNum << " \"";
+      cout.write (mgWord+1, *mgWord);
+      cout << "\" " << numFrags << "\n";
+      */
+      
+      // add this word to the inverted list
+      BitPtr &wordBitPtr = bitPtrs.GetWordBitPtr (wordNum);
+      unsigned long fragNum = numFrags;
+      int b = 1 << wordBitPtr.lgB;
+  
+      mems_bitio_buffer buffer ((u_char *) ivfMemBuf, wordBitPtr.here);
+
+      // note: this assumes that fragments don't carry over between
+      // chunks (which they don't because all tags are closed at the
+      // end of each document and chunks are based on document
+      // boundaries), i.e. the first fragment number must be greater
+      // than the starting fragment number of the chunk.
+      if (fragNum > wordBitPtr.lastFragNum) {
+	buffer.bblock_encode ((fragNum - wordBitPtr.lastFragNum - 1) + 1,
+			      b, NULL);
+	if (!wordLevelIndex) buffer.encodeBit (1); // freq = 1
+	
+      } else if (!wordLevelIndex) {
+	// add one to the frequency count for this word
+	buffer.seek (buffer.position()-1);
+	buffer.encodeBit (0); // unary encoding -- last = 1
+	buffer.encodeBit (1);
+      }
+      
+      wordBitPtr.lastFragNum = fragNum;
+      wordBitPtr.here = buffer.position();
+      buffer.encodeDone();
+      
+      // check for buffer overrun
+      bitPtrs.CheckWordBufOverrun (wordNum);
+    }
+  }
+}
+
+// combine the in memory inverted buffer with the disk
+// based inverted file
+static void DiskMerge (char *filename) {
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+
+      // make sure we have something to process
+  if (numChunkDocs <= 0) return;
+    
+  // open the inverted file
+  FILE *invfFile = open_file (filename, INVF_SUFFIX, "rb+",
+			      MAGIC_INVF, MG_ABORT);
+  random_bitio_buffer invfOutBuf (invfFile);
+
+  // set up to decode the entries in memory
+  mems_bitio_buffer memInBuf ((u_char *) ivfMemBuf, 0);
+
+  // write out the word information
+  unsigned long wordNum;
+  int b;
+  unsigned long currFragNum;
+  unsigned long delta;
+  unsigned long currFreq;
+  for (wordNum=0; wordNum<idh.word_dict_size; ++wordNum) {
+    // go to the end of the last inverted file entry
+    InvfStateRec &wordDiskState = invfState.GetRec (wordNum);
+    invfOutBuf.SEEK_X (wordDiskState.here);
+
+    // go to the start of the inverted chunk info in memory
+    BitPtr &wordBitPtr = bitPtrs.GetWordBitPtr (wordNum);
+    memInBuf.seek(wordBitPtr.start);
+
+    // decode each entry and re-write to disk
+    currFragNum = chunkStartFragNum;
+    while (memInBuf.position() < wordBitPtr.here) {
+      // decode word entry
+      b = 1 << wordBitPtr.lgB;
+      delta = memInBuf.bblock_decode (b, NULL);
+      currFragNum += delta;
+      if (!wordLevelIndex) currFreq = memInBuf.unary_decode (NULL);
+      else currFreq = 1;
+
+      // recode on disk
+      invfOutBuf.bblock_encode (currFragNum-wordDiskState.lastFragNum,
+				wordDiskState.B, NULL);
+      if (!wordLevelIndex) invfOutBuf.gamma_encode (currFreq, NULL);
+      wordDiskState.lastFragNum = currFragNum;
+    }
+
+    wordDiskState.here = invfOutBuf.TELL_X();
+  }
+
+  // write out the tag information
+  unsigned long tagNum;
+  unsigned long currTagStart;
+  unsigned long currTagEnd;
+  for (tagNum=0; tagNum<idh.tag_dict_size; ++tagNum) {
+    // go to the end of the last inverted file entry
+    InvfStateRec &tagDiskState = invfState.GetRec (tagNum+idh.word_dict_size);
+    invfOutBuf.SEEK_X (tagDiskState.here);
+
+    // go to the start of the inverted chunk info in memory
+    BitPtr &tagBitPtr = bitPtrs.GetTagBitPtr (tagNum);
+    memInBuf.seek(tagBitPtr.start);
+
+    // decode each entry and re-write to disk
+    currTagEnd = chunkStartFragNum;
+    while (memInBuf.position() < tagBitPtr.here) {
+      // decode tag entry
+      b = 1 << tagBitPtr.lgB;
+      delta = memInBuf.bblock_decode (b, NULL) - 1;
+      currTagStart = currTagEnd + delta;
+      delta = memInBuf.bblock_decode (b, NULL) - 1;
+      currTagEnd = currTagStart + delta;
+
+      // recode on disk
+      invfOutBuf.bblock_encode (currTagStart-tagDiskState.lastFragNum+1,
+				tagDiskState.B, NULL);
+      invfOutBuf.bblock_encode (currTagEnd-currTagStart+1,
+				tagDiskState.B, NULL);
+
+      tagDiskState.lastFragNum = currTagEnd;
+    }
+
+    tagDiskState.here = invfOutBuf.TELL_X();
+  }
+
+  memInBuf.done();
+
+  invfOutBuf.encodeDone();
+  fclose (invfFile);
+}
+
+
+int process_ivf_2 (const TagInfo &/*tagInfo*/, const TextElArray &doc) {
+  bool wordLevelIndex = ivfLevel.indexLevel.empty();
+  bool inFrag = false;
+  if (wordLevelIndex) inFrag = true; // unconditional
+  
+  // get next chunk information if need to. the chunk information
+  // is needed before the first document is processed
+  if (numChunkDocs >= numDocsInChunk) ReadChunk (idh, wordLevelIndex);
+
+  // process each text element
+  TextElArray::const_iterator here = doc.begin();
+  TextElArray::const_iterator end = doc.end();
+  while (here != end) {
+    // process this element
+    if ((*here).elType == OpenTagE) ProcessOpenTag (*here, inFrag);
+    else if ((*here).elType == CloseTagE) ProcessCloseTag (*here, inFrag);
+    else ProcessText (*here, inFrag);
+    
+    ++here;
+  }
+
+  // close off any unclosed tags
+  TagMapDict::iterator tdHere = tagMapDict.begin();
+  TagMapDict::iterator tdEnd = tagMapDict.end();
+  while (tdHere != tdEnd) {
+    CloseTextTag ((*tdHere).second, (*tdHere).first);
+    ++tdHere;
+  }
+  
+  // we've processed one more document
+  ++numDocs;
+  ++numChunkDocs;
+
+  // merge the memory based inverted file with the one on
+  // disk if this is the end of this chunk
+  if (numChunkDocs >= numDocsInChunk) DiskMerge (collectFilename);
+  
+  return COMPALLOK;
+}
+
+
+static void CondenseInvfFile (char *filename, unsigned long &bytesOutput) {
+  FILE *inInvfFile = open_file (filename, INVF_SUFFIX, "rb",
+				MAGIC_INVF, MG_ABORT);
+  FILE *outInvfFile = open_file (filename, INVF_SUFFIX, "rb+",
+				 MAGIC_INVF, MG_ABORT);
+
+  // skip the magic number
+  fseek (outInvfFile, sizeof (unsigned long), SEEK_SET);
+  
+  // write the inverted file header -- use defaults for most things
+  invf_file_header ifh;
+  ifh.no_of_words = idh.word_dict_size;
+  ifh.no_of_tags = idh.tag_dict_size;
+  ifh.word_level_index = (ivfLevel.indexLevel.empty()) ? 1 : 0;
+  ifh.Write (outInvfFile);
+
+  bytesOutput = ftell (outInvfFile);
+
+  // process each meaningful byte in the file
+  unsigned long numEntries = ifh.no_of_words + ifh.no_of_tags;
+  unsigned long entryNum;
+  mg_ullong lastStart = 0;
+  for (entryNum = 0; entryNum < numEntries; ++entryNum) {
+    InvfStateRec &stateRec = invfState.GetRec (entryNum);
+
+    // overrun check
+    if (stateRec.start < lastStart)
+      FatalError (1, "Inverted file Buffer overrun");
+    lastStart = stateRec.start;
+    
+    unsigned long oldEntryStart = stateRec.start >> 3;
+    unsigned long oldEntryStartOver = stateRec.start & 7; // should be 0
+    unsigned long oldEntryEnd = (stateRec.here + 7) >> 3;  // byte after end
+    unsigned long oldEntryEndOver = stateRec.here & 7;
+
+    fseek (inInvfFile, oldEntryStart, SEEK_SET);
+
+    stateRec.here -= stateRec.start;
+    stateRec.start = (mg_ullong)bytesOutput * 8 + oldEntryStartOver;
+    stateRec.here += stateRec.start;
+    while (oldEntryStart < oldEntryEnd) {
+      unsigned char c = getc (inInvfFile);
+      if (oldEntryStart == oldEntryEnd - 1) {
+	u_char ands[8] =
+	{0xff, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
+	c &= ands[oldEntryEndOver];
+      }
+      putc (c, outInvfFile);
+      ++bytesOutput;
+      ++oldEntryStart;
+    }
+  }  
+
+  fclose (inInvfFile);
+
+#ifdef __WIN32__
+  if (_chsize (_fileno (outInvfFile), bytesOutput) != 0)
+    Message ("Could not truncate invf.");
+#else
+  ftruncate (fileno (outInvfFile), bytesOutput);
+#endif
+
+  fclose (outInvfFile);
+}
+
+static void OutputInvfIdx (char *filename, unsigned long invfNumBytes) {
+  FILE *invfIdxFile = create_file (filename, INVF_IDX_SUFFIX, "wb",
+				   MAGIC_INVI, MG_ABORT);
+
+  // process each meaningful byte in the file
+  unsigned long numEntries = idh.word_dict_size + idh.tag_dict_size;
+  unsigned long entryNum;
+  for (entryNum = 0; entryNum < numEntries; ++entryNum) {
+    InvfStateRec &stateRec = invfState.GetRec (entryNum);
+
+    // assumes that inverted entries start at beginning of each byte
+    if (!WriteUL (invfIdxFile, (stateRec.start >> 3))) break;
+  }
+
+  WriteUL (invfIdxFile, invfNumBytes);
+
+  fclose (invfIdxFile);
+}
+
+
+int done_ivf_2 (const TagInfo &/*tagInfo*/, char *filename) {
+  // close most open files
+  if (chunkFile != NULL) {
+    chunkBuf.done();
+    fclose (chunkFile);
+    chunkFile = NULL;
+  }
+  occurConvert.Close();
+  
+  // free allocated memory
+  bitPtrs.Clear();
+  if (ivfMemBuf != NULL) { delete [] ivfMemBuf; ivfMemBuf = NULL; }
+  free_perf_hash (wordHashDict);
+  wordHashDict = NULL;
+  tagMapDict.erase (tagMapDict.begin(), tagMapDict.end());
+
+  // condense the inverted file and truncate it
+  // this function also writes out the inverted header
+  unsigned long invfNumBytes = 0;
+  CondenseInvfFile (filename, invfNumBytes);
+
+  OutputInvfIdx (filename, invfNumBytes);
+
+  // close the rest of the open files
+  invfState.Close ();
+  
+  return COMPALLOK;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/locallib.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/locallib.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/locallib.cpp	(revision 10506)
@@ -0,0 +1,218 @@
+/**************************************************************************
+ *
+ * locallib.cpp -- Misc functions
+ * Copyright (C) 1994  Gary Eddy, Alistair Moffat and Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "memlib.h"
+#include "bitio_gen.h"
+#include "huffman.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "locallib.h"
+#include "text.h"
+
+int 
+vecentropy (int *A, int n)
+{
+  int total = 0, i;
+  double bits = 0.0;
+
+  for (i = 0; i < n; ++i)
+    total += A[i];
+  for (i = 0; i < n; ++i)
+    if (A[i])
+      bits += A[i] * log2 (1.0 * total / A[i]);
+  return ((int) (bits + 0.9999));
+
+}
+
+static void 
+siftdown (int *A, int i, int n)
+{
+  int ms, t;
+
+  while (2 * i + 1 <= n - 1)
+    {
+      if (2 * i + 1 == n - 1 || A[2 * i + 1] < A[2 * i + 2])
+	ms = 2 * i + 1;
+      else
+	ms = 2 * i + 2;
+      if (A[i] > A[ms])
+	{
+	  t = A[i];
+	  A[i] = A[ms];
+	  A[ms] = t;
+	}
+      i = ms;
+    }
+}
+
+static void 
+buildheap (int *A, int n)
+{
+  int i;
+  for (i = n / 2 - 1; i >= 0; --i)
+    siftdown (A, i, n);
+}
+
+int 
+huffcodebits (unsigned long *A, int n)
+{
+  int i, j, tot = 0, bits = 0, v1, v2, *B;
+
+  B = (int *) Xmalloc (n * sizeof (int));
+  j = 0;
+  for (i = 0; i < n; ++i)
+    {
+      if (A[i])
+	{
+	  tot += (B[j++] = A[i]);
+	}
+    }
+  n = j;
+
+  if (n == 0 || tot == 0)
+    return (0);
+
+  buildheap (B, n);
+  while (n > 1)
+    {
+      v1 = B[0];
+      B[0] = B[n - 1];
+      --n;
+      siftdown (B, 0, n);
+      v2 = B[0];
+      B[0] = v1 + v2;
+      siftdown (B, 0, n);
+      bits += v1 + v2;
+    }
+  Xfree (B);
+  return (bits);
+}
+
+
+int 
+modelbits (unsigned long *A, int n)
+{
+  int i, bits = 0, last, N = 0;
+
+  last = -1;
+  for (i = 0; i < n; ++i)
+    {
+      if (A[i])
+	{
+	  bits += BIO_Gamma_Length (i - last) + BIO_Gamma_Length (A[i]);
+	  last = i;
+	  ++N;
+	}
+    }
+  if (N == 0)
+    return (0);
+  bits += BIO_Gamma_Length (N);
+  return (bits);
+}
+
+
+
+
+
+/* Find the next prime number larger than p */
+int 
+prime (int p)
+{
+  int limit;
+  p += (p & 1) + 1;
+  limit = (int) sqrt ((double) p) + 1;
+  do
+    {
+      int j;
+      while (limit * limit < p)
+	++limit;
+      for (j = 3; j <= limit && p % j; j += 2)
+	;			/* NULLBODY */
+      if (j > limit)
+	break;
+      p += 2;
+    }
+  while (1);
+  return (p);
+}
+
+
+
+int Read_cdh (FILE * f, compression_dict_header * cdh, u_long * /*mem*/,
+	      u_long * disk) {
+  if (disk)
+    (*disk) += sizeof (*cdh);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  if (fread (cdh, sizeof (*cdh), 1, f) == 1)
+    {
+      int i;
+      NTOHUL(cdh->dict_type);
+      NTOHUL(cdh->novel_method);
+      for (i = 0; i < TEXT_PARAMS; ++i)
+	NTOHUL(cdh->params[i]);
+      NTOHUL(cdh->num_words[0]);
+      NTOHUL(cdh->num_words[1]);
+      NTOHUL(cdh->num_word_chars[0]);
+      NTOHUL(cdh->num_word_chars[1]);
+      NTOHUL(cdh->lookback);
+      return 0;
+    }
+  else
+    return -1;
+}
+
+
+int 
+Read_cfh (FILE * f, comp_frags_header * cfh, u_long * mem, u_long * disk)
+{
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (Read_Huffman_Data (f, &cfh->hd, mem, disk) == -1)
+    return -1;
+  if (fread (&cfh->uncompressed_size,
+	     sizeof (cfh->uncompressed_size), 1, f) != 1)
+    return -1;
+  NTOHUL(cfh->uncompressed_size);  /* [RPAP - Jan 97: Endian Ordering] */
+
+  if (disk)
+    (*disk) += sizeof (cfh->uncompressed_size);
+
+  memset (cfh->huff_words_size, '\0', sizeof (cfh->huff_words_size));
+
+  if ((int)fread (cfh->huff_words_size + cfh->hd.mincodelen,
+	     sizeof (*cfh->huff_words_size),
+	     cfh->hd.maxcodelen - cfh->hd.mincodelen + 1, f) !=
+      cfh->hd.maxcodelen - cfh->hd.mincodelen + 1)
+    return -1;
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = cfh->hd.mincodelen; i < cfh->hd.maxcodelen + 1; ++i)
+    NTOHUL(cfh->huff_words_size[i]);
+
+  if (disk)
+    (*disk) += sizeof (*cfh->huff_words_size) *
+      (cfh->hd.maxcodelen - cfh->hd.mincodelen + 1);
+  return 0;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/locallib.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/locallib.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/locallib.h	(revision 10506)
@@ -0,0 +1,45 @@
+/**************************************************************************
+ *
+ * locallib.h -- Misc functions
+ * Copyright (C) 1994  Gary Eddy, Alistair Moffat and Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef LOCALLIB_H
+#define LOCALLIB_H
+
+#include "sysfuncs.h"
+
+#include "text.h"
+
+#define NUMOF(a) (sizeof(a)/sizeof((a)[0]))
+
+int vecentropy (int *A, int n);
+
+int huffcodebits (unsigned long *A, int n);
+
+int modelbits (unsigned long *A, int n);
+
+int prime (int p);
+
+
+int Read_cdh (FILE * f, compression_dict_header * cdh, u_long * mem, u_long * disk);
+
+int Read_cfh (FILE * f, comp_frags_header * cfh, u_long * mem, u_long * disk);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg.h	(revision 10506)
@@ -0,0 +1,37 @@
+/**************************************************************************
+ *
+ * mg.h -- General header file
+ * Copyright (C) 1994  Neil Sharman, Alistair Moffat and Lachlan Andrew
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+
+#ifndef H_MG
+#define H_MG
+
+
+#define COMPALLOK	(0)
+#define COMPERROR	(-1)
+
+#define MAXSTRING       3000000
+#define BUFFERSIZE      (MAXSTRING+30000)
+
+#define	MAXLN	65536
+#define WORDS           1
+#define NONWORDS        0
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg.special.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg.special.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg.special.cpp	(revision 10506)
@@ -0,0 +1,58 @@
+/**************************************************************************
+ *
+ * mg.special.cpp -- Special pass for mg_passes
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+#include "sysfuncs.h"
+#include "mg.h"
+#include "build.h"
+
+int init_special (const TagInfo &/*tagInfo*/, char * /*FileName*/) {
+  return COMPALLOK;
+}
+
+int process_special (const TagInfo &/*tagInfo*/, const TextElArray &doc) {
+  // print out the document
+  TextElArray::const_iterator here = doc.begin();
+  TextElArray::const_iterator end = doc.end();
+  while (here != end) {
+    if ((*here).elType == OpenTagE) {
+      cout << "** OpenTag  \"" << (*here).tagName << "\"\tText \""
+	   << (*here).text << "\"\n"; 
+    } else if ((*here).elType == CloseTagE) {
+      cout << "** CloseTag \"" << (*here).tagName << "\"\tText \""
+	   << (*here).text << "\"\n";
+    } else {
+      cout << "** Text     \"" << (*here).text << "\"\n";
+    }
+    
+    ++here;
+  }
+  
+  return COMPALLOK;
+}
+
+int done_special (const TagInfo &/*tagInfo*/, char * /*FileName*/) {
+  return COMPALLOK;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_errors.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_errors.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_errors.cpp	(revision 10506)
@@ -0,0 +1,72 @@
+/**************************************************************************
+ *
+ * mg_errors.cpp -- Error related stuff for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+#include "sysfuncs.h"
+#include "memlib.h"
+
+#include "mg_errors.h"
+
+int mg_errno = MG_NOERROR;
+
+char *mg_errorstrs[] =
+{
+  "No error",
+  "Out of memory",
+  "File \"%s\" not found",
+  "Bad magic number in \"%s\"",
+  "Error reading \"%s\"",
+  "MG_BUFTOOSMALL",
+  "Files required for level 2 and 3 inversion are missing"};
+
+
+/* [RJM 07/98: Memory Leak] -- rest of file */
+
+static char null_data[] = "";
+char *mg_error_data = null_data;
+
+
+void MgErrorData (char *s)
+{
+  /* free the current error string, unless it is the null string */
+  if ((mg_error_data != NULL) && (mg_error_data != null_data)) {
+    delete []mg_error_data;
+    mg_error_data = null_data;
+  }
+
+  /* make a copy of the string */
+  mg_error_data = Xstrdup (s);
+
+  /* if the alloc failed set the error to the null string */
+  if (!mg_error_data) mg_error_data = null_data;
+}
+
+
+void MgErrorDeinit (void)
+{
+  /* free the current error string, unless it is the null string */
+  if ((mg_error_data != NULL) && (mg_error_data != null_data)) {
+    delete []mg_error_data;
+    mg_error_data = null_data;
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_errors.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_errors.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_errors.h	(revision 10506)
@@ -0,0 +1,37 @@
+/**************************************************************************
+ *
+ * mg_errors.h -- Error related stuff for mgquery
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+
+extern int mg_errno;
+extern char *mg_error_data;
+extern char *mg_errorstrs[];
+
+
+#define MG_NOERROR 0
+#define MG_NOMEM 1
+#define MG_NOFILE 2
+#define MG_BADMAGIC 3
+#define MG_READERR 4
+#define MG_BUFTOOSMALL 5
+#define MG_INVERSION 6
+
+void MgErrorData (char *s);
+void MgErrorDeinit (void);
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_files.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_files.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_files.cpp	(revision 10506)
@@ -0,0 +1,259 @@
+/**************************************************************************
+ *
+ * mg_files.cpp -- Routines for handling files for the auxillary programs
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+
+
+/* This must contain a valid path without a trailing slash */
+static char *basepath = NULL;
+
+/* This sets the base path for all file operations */
+void 
+set_basepath (const char *bp)
+{
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+  basepath = "";
+#else
+  char *s;
+  /* Free the memory for the base path if it has already been allocated */
+  if (basepath)
+    {
+      delete []basepath;
+      basepath = NULL;
+    }
+
+  if (!bp || *bp == '\0')
+    bp = ".";
+
+  s = strrchr (bp, '/');
+  if (s && *(s + 1) == '\0')
+    {
+      basepath = new char[strlen (bp) + 2];
+      if (!basepath)
+	return;
+      strcpy (basepath, bp);
+      strcat (basepath, ".");
+    }
+  else
+    basepath = Xstrdup (bp);
+#endif
+}
+
+
+
+/* return the currently defined basepath */
+char *
+get_basepath (void)
+{
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  return basepath;
+}
+
+
+
+/* This generates the name of a file. It places the name in the buffer
+   specified or if that is NULL it uses a static buffer. */
+char *
+make_name (const char *name, const char *suffix, char *buffer)
+{
+  static char path[512];
+  if (!buffer)
+    buffer = path;
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (buffer, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return buffer;
+}
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+open_named_file (const char *name, const char *mode,
+		 u_long magic_num, int err_mode)
+{
+  unsigned long magic;
+  FILE *f = NULL;
+  char *err;
+  f = fopen (name, mode);
+
+  if (!f)
+    {
+      err = "Unable to open \"%s\"";
+      goto error;
+    }
+
+  if (magic_num)
+    {
+      if (fread (&magic, sizeof (magic), 1, f) != 1)
+	{
+	  err = "No magic number \"%s\"";
+	  goto error;
+	}
+
+      NTOHUL(magic);  /* [RPAP - Jan 97: Endian Ordering] */
+
+      if (!IS_MAGIC (magic))
+	{
+	  err = "No MG magic number \"%s\"";
+	  goto error;
+	}
+
+      if (magic != magic_num)
+	{
+	  err = "Wrong MG magic number \"%s\"";
+	  goto error;
+	}
+    }
+  return f;
+
+error:
+  if (f)
+    fclose (f);
+  if (err_mode == MG_ABORT)
+    FatalError (1, err, name);
+  if (err_mode == MG_MESSAGE)
+    Message (err, name);
+  return NULL;
+}
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+open_file (const char *name, const char *suffix, const char *mode,
+	   u_long magic_num, int err_mode)
+{
+  char path[512];
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (path, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return open_named_file (path, mode, magic_num, err_mode);
+}
+
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+create_named_file (const char *name, const char *mode,
+		   u_long magic_num, int err_mode)
+{
+  FILE *f = NULL;
+  char *err;
+  f = fopen (name, mode);
+
+  if (!f)
+    {
+      err = "Unable to open \"%s\"";
+      goto error;
+    }
+
+  if (magic_num)
+    HTONUL(magic_num);  /* [RPAP - Jan 97: Endian Ordering] */
+    if (fwrite (&magic_num, sizeof (magic_num), 1, f) != 1)
+      {
+	err = "Couldn't write magic number \"%s\"";
+	goto error;
+      }
+
+  return f;
+
+error:
+  if (f)
+    fclose (f);
+  if (err_mode == MG_ABORT)
+    FatalError (1, err, name);
+  if (err_mode == MG_MESSAGE)
+    Message (err, name);
+  return NULL;
+}
+
+
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *
+create_file (const char *name, const char *suffix, const char *mode,
+	     u_long magic_num, int err_mode)
+{
+  char path[512];
+  if (!basepath)
+    set_basepath (getenv ("MGDATA"));
+  sprintf (path, FILE_NAME_FORMAT, basepath, name, suffix);  /* [RPAP - Feb 97: WIN32 Port] */
+  return create_named_file (path, mode, magic_num, err_mode);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_files.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_files.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mg_files.h	(revision 10506)
@@ -0,0 +1,343 @@
+/**************************************************************************
+ *
+ * mg_files.h -- Routines for handling files for the auxillary programs
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef MG_FILES_H
+#define MG_FILES_H
+
+#include "sysfuncs.h"
+
+/* Magic numbers for the different types of files */
+
+#define GEN_MAGIC(a,b,c,d) ((unsigned long)(((a)<<24) + ((b)<<16) + \
+					    ((c)<<8) + (d)))
+
+#define MAGIC_XXXX		GEN_MAGIC('M','G', 0 , 0)
+#define MAGIC_STATS_DICT	GEN_MAGIC('M','G','S','D')
+#define MAGIC_AUX_DICT		GEN_MAGIC('M','G','A','D')
+#define MAGIC_FAST_DICT		GEN_MAGIC('M','G','F','D')
+#define MAGIC_DICT		GEN_MAGIC('M','G','D', 0 )
+#define MAGIC_STEM_BUILD	GEN_MAGIC('M','G','S', 0 )
+#define MAGIC_HASH		GEN_MAGIC('M','G','H', 0 )
+#define MAGIC_STEM		GEN_MAGIC('M','G','s', 0 )
+#define MAGIC_CHUNK		GEN_MAGIC('M','G','C', 0 )
+#define MAGIC_CHUNK_TRANS	GEN_MAGIC('M','G','c', 0 )
+#define MAGIC_TEXT		GEN_MAGIC('M','G','T', 0 )
+#define MAGIC_TEXI		GEN_MAGIC('M','G','t', 0 )
+#define MAGIC_TEXT_LEVELS	GEN_MAGIC('M','G','t','L')
+#define MAGIC_TEXI_WGT		GEN_MAGIC('M','G','t','W')
+#define MAGIC_INVF		GEN_MAGIC('M','G','I', 0 )
+#define MAGIC_INVF_LEVELS	GEN_MAGIC('M','G','I','L')
+#define MAGIC_INVI		GEN_MAGIC('M','G','i', 0 )
+#define MAGIC_WGHT		GEN_MAGIC('M','G','W', 0 )
+#define MAGIC_WGHT_APPROX	GEN_MAGIC('M','G','w', 0 )
+#define MAGIC_PARAGRAPH		GEN_MAGIC('M','G','P', 0 )
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAGIC_STEM_1            GEN_MAGIC('M','G','s','1')
+#define MAGIC_STEM_2            GEN_MAGIC('M','G','s','2')
+#define MAGIC_STEM_3            GEN_MAGIC('M','G','s','3')
+
+#define IS_MAGIC(a) ((((u_long)(a)) & 0xffff0000) == MAGIC_XXXX)
+
+
+/* err_mode values for open_file and create_file */
+#define MG_ABORT 0
+#define MG_MESSAGE 1
+#define MG_CONTINUE 2
+
+
+
+
+
+/* File suffixes */
+
+
+/* The compression dictionary built by txt.pass1 */
+#ifdef SHORT_SUFFIX
+# define TEXT_STATS_DICT_SUFFIX	 ".tsd"
+#else
+# define TEXT_STATS_DICT_SUFFIX	 ".text.stats"
+#endif
+
+/* The compression dictionary built by text.pass1 and comp_dict.process */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_SUFFIX	 ".td"
+#else
+# define TEXT_DICT_SUFFIX	 ".text.dict"
+#endif
+
+/* The compression dictionary built by mg_make_fast_dict */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_FAST_SUFFIX	 ".tdf"
+#else
+# define TEXT_DICT_FAST_SUFFIX	 ".text.dict.fast"
+#endif
+
+/* The auxilary dictionary built by text.pass2 */
+#ifdef SHORT_SUFFIX
+# define TEXT_DICT_AUX_SUFFIX	 ".tda"
+#else
+# define TEXT_DICT_AUX_SUFFIX	 ".text.dict.aux"
+#endif
+
+/* The compressed text build by text.pass2 */
+#ifdef SHORT_SUFFIX
+# define TEXT_SUFFIX		 ".t"
+#else
+# define TEXT_SUFFIX		 ".text"
+#endif
+
+/* The combined compressed text index and document weight file */
+#ifdef SHORT_SUFFIX
+# define TEXT_IDX_WGT_SUFFIX	 ".tiw"
+#else
+# define TEXT_IDX_WGT_SUFFIX	 ".text.idx.wgt"
+#endif
+
+/* The compressed text index file */
+#ifdef SHORT_SUFFIX
+# define TEXT_IDX_SUFFIX	 	".ti"
+#else
+# define TEXT_IDX_SUFFIX	 	".text.idx"
+#endif
+
+/* The document levels in the text */
+#ifdef SHORT_SUFFIX
+# define TEXT_LEVEL_SUFFIX	 	".tl"
+#else
+# define TEXT_LEVEL_SUFFIX	 	".text.level"
+#endif
+
+/* The dictionary of stemmed words build by invf.pass1 and ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_SUFFIX         ".id"
+#else
+# define INVF_DICT_SUFFIX         ".invf.dict"
+#endif
+
+/* The dictionary of stemmed words build by stem.process */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_SUFFIX ".idb"
+#else
+# define INVF_DICT_BLOCKED_SUFFIX ".invf.dict.blocked"
+#endif
+
+/* The exact document weights file build by make.weights, invf.pass2,
+   or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define WEIGHTS_SUFFIX           ".w"
+#else
+# define WEIGHTS_SUFFIX           ".weight"
+#endif
+
+/* The approximate weights file built by make.weights */
+#ifdef SHORT_SUFFIX
+# define APPROX_WEIGHTS_SUFFIX    ".wa"
+#else
+# define APPROX_WEIGHTS_SUFFIX    ".weight.approx"
+#endif
+
+/* The inverted file build by invf.pass2 or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define INVF_SUFFIX              ".i"
+#else
+# define INVF_SUFFIX              ".invf"
+#endif
+
+/* The level information for the inverted text */
+#ifdef SHORT_SUFFIX
+# define INVF_LEVEL_SUFFIX              ".il"
+#else
+# define INVF_LEVEL_SUFFIX              ".invf.level"
+#endif
+
+/* The inverted file index build by invf.pass2 or ivf.pass2 */
+#ifdef SHORT_SUFFIX
+# define INVF_IDX_SUFFIX          ".ii"
+#else
+# define INVF_IDX_SUFFIX          ".invf.idx"
+#endif
+
+/* The inverted file chunk descriptor built by ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_CHUNK_SUFFIX        ".ic"
+#else
+# define INVF_CHUNK_SUFFIX        ".invf.chunk"
+#endif
+
+/* The word index translation file built by ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_CHUNK_TRANS_SUFFIX  ".ict"
+#else
+# define INVF_CHUNK_TRANS_SUFFIX  ".invf.chunk.trans"
+#endif
+
+/* The hashed stemmed dictionary built by make.perf_hash */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_HASH_SUFFIX    ".idh"
+#else
+# define INVF_DICT_HASH_SUFFIX    ".invf.dict.hash"
+#endif
+
+/* The paragraph descriptior file built by invf.pass1 or ivf.pass1 */
+#ifdef SHORT_SUFFIX
+# define INVF_PARAGRAPH_SUFFIX    ".ip"
+#else
+# define INVF_PARAGRAPH_SUFFIX    ".invf.paragraph"
+#endif
+
+/* The trace file build by mg.builder. */
+#ifdef SHORT_SUFFIX
+# define TRACE_SUFFIX             ".trc"
+#else
+# define TRACE_SUFFIX             ".trace"
+#endif
+
+/* The compression stats file build by mg.builder. */
+#ifdef SHORT_SUFFIX
+# define COMPRESSION_STATS_SUFFIX ".cs"
+#else
+# define COMPRESSION_STATS_SUFFIX ".compression.stats"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The casefolded index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_1_SUFFIX ".ib1"
+#else
+# define INVF_DICT_BLOCKED_1_SUFFIX ".invf.dict.blocked.1"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The stemmed index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_2_SUFFIX ".ib2"
+#else
+# define INVF_DICT_BLOCKED_2_SUFFIX ".invf.dict.blocked.2"
+#endif
+
+/* [RPAP - Jan 97: Stem Index Change] */
+/* The casefolded and stemmed  index into the stemmed dictionary */
+#ifdef SHORT_SUFFIX
+# define INVF_DICT_BLOCKED_3_SUFFIX ".ib3"
+#else
+# define INVF_DICT_BLOCKED_3_SUFFIX ".invf.dict.blocked.3"
+#endif
+
+/* [RPAP - Feb 97: WIN32 Port] */
+#ifdef __WIN32__
+#define FILE_NAME_FORMAT "%s%s%s"
+#else
+#define FILE_NAME_FORMAT "%s/%s%s"
+#endif
+
+
+/* This sets the base path for all file operations */
+void set_basepath (const char *bp);
+
+
+/* return the currently defined basepath */
+char *get_basepath (void);
+
+
+
+
+/* This generates the name of a file. It places the name in the buffer
+   specified or if that is NULL it uses a static buffer. */
+char *make_name (const char *name, const char *suffix, char *buffer);
+
+
+
+
+
+
+
+/* This will open the specified file and check its magic number.
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *open_named_file (const char *name, const char *mode,
+		       u_long magic_num, int err_mode);
+
+
+
+
+/* This will open the specified file and check its magic number.
+
+   err_mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *open_file (const char *name, const char *suffix, const char *mode,
+		 u_long magic_num, int err_mode);
+
+
+
+
+
+/* This will create the specified file and set its magic number.
+
+   Mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *create_named_file (const char *name, const char *mode,
+			 u_long magic_num, int err_mode);
+
+
+
+/* This will create the specified file and set its magic number.
+
+   err_mode may take on the following values
+   MG_ABORT    : causes an error message to be generated and the
+   program aborted if there is an error.
+   MG_MESSAGE  : causes a message to be generated and a NULL value to
+   be returned if there is an error.
+   MG_CONTINUE : causes a NULL value to be returned if there is an error.
+
+   On success if returns the FILE *. On failure it will return a NULL value
+   and possibly generate an error message, or it will exit the program with
+   an error message.   */
+FILE *create_file (const char *name, const char *suffix, const char *mode,
+		   u_long magic_num, int err_mode);
+
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_compression_dict.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_compression_dict.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_compression_dict.1	(revision 10506)
@@ -0,0 +1,188 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.\"------------------------------------------------------------
+.TH mgpp_compression_dict 1 \*(Dt CITRI
+.SH NAME
+mgpp_compression_dict \- build a compression dictionary.
+.SH SYNOPSIS
+.B mgpp_compression_dict
+[
+.B \-h
+]
+[
+.BR \-C " |"
+.BR \-P " |"
+.B  \-S
+]
+.if n .ti +9n
+[
+.BR \-0 " |"
+.BR \-1 " |"
+.BR \-2 " |"
+.B  \-3
+]
+[
+.BR \-H " |"
+.BR \-B " |"
+.BR \-D " |"
+.BR \-Y " |"
+]
+.if n .ti +9n
+.if t .ti +.5i
+[
+.BI \-l " lookback"
+]
+[
+.BI \-k " mem"
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgpp_compression_dict
+builds a compression dictionary based on the statistics gathered
+during the first pass over the text.  The options to the program are
+mainly concerned with limiting the amount of memory the dictionary
+will use and with how the text compressor will cope with any novel
+words found during the compression phase.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.B \-C
+Build a complete dictionary from the statistics file.  If during the
+text compression phase a novel word is found, then the compressor will
+produce an error message and stop.
+.TP
+.B \-P
+Build a partial dictionary from the statistics file.  This dictionary
+assumes that the statistics file are based on the entire text.  The
+statistics of words not includes in the dictionary are used to
+calculate the escape probability.  If novel words are being coded
+character by character, then there may not be a Huffman code for every
+possible character.  This means that the compressor may fail if a novel
+word contains a novel character.
+.TP
+.B \-S
+Build a seed dictionary from the statistics file.  This dictionary
+assumes that the statistics file is based on only a portion of the
+text to be compressed.  The probability of a novel word is based on the
+number of words that have only occurred once.  If novel words are being
+coded character by character, then the Huffman codes for characters are
+based on the frequency of characters in the dictionary.
+.TP
+.B \-0
+All words from the statistics file are included in the built
+dictionary.
+.TP
+.B \-1
+Words are included in the dictionary until the dictionary reaches the
+desired size.  Words are selected for the dictionary based on the order
+they occurred in the source text.
+.TP
+.B \-2
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.
+.TP
+.B \-3
+Words are included in the dictionary until the dictionary reaches the
+desired size.  The most frequent words are included in the dictionary
+first; where there is a tie for frequency, the shortest word is
+included first.  Words are the shuffled back and forth between the
+`keep' and `discard' lists to find the `optimal' set of words that
+should be in the dictionary.
+.TP
+.B \-H
+This specifies that novel words will be coded character by character
+using Huffman codes.
+.TP
+.B \-B
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using binary codes.  The binary code represents their occurrence
+position in the auxiliary dictionary.
+.TP
+.B \-D
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using delta codes.  The delta code represents their occurrence position
+in the auxiliary dictionary.
+.TP
+.B \-Y
+This specifies that an auxiliary dictionary will be built by the
+compressor.  Each novel word found will be placed at the end of the
+auxiliary dictionary.  Novel words will be coded in the compressed text
+using a combination of gamma and binary codes.  The code represents
+their occurrence position in the auxiliary dictionary.  This generally
+produces better compression than
+.B \-B
+or
+.BR \-D .
+.TP
+.BI \-l " lookback"
+The generated dictionary is designed to be front coded when it is
+loaded into memory.  Under normal circumstances, a front-coded
+dictionary would require scanning from the beginning in order to find
+any particular word.  However, every
+.I lookback
+words in the dictionary, the whole word is stored and a pointer to that
+word maintained.  E.g., if
+.I lookback
+is 4, then every fourth word is stored in its entirety.
+.TP
+.BI \-k " mem"
+This limits the amount of memory to use for the generated
+dictionary.  Words are selected for the dictionary based of the text
+statistics, and whether
+.BR \-0 , " \-1" , " \-2"
+or
+.B \-3
+is specified.  The memory is calculated assuming a lookback of 0,
+irrespective of what actual lookback is specified.  This means that if
+a non-zero lookback is given, the dictionary will actually occupy
+less space than specified by
+.BR \-k .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mgpp
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.stats
+Statistics about the source text.
+.TP
+.B *.text.dict
+Compression dictionary for the source text.
+.SH "SEE ALSO"
+.na
+.BR mgpp_fast_comp_dict (1),
+.BR mgpp_invf_dict (1),
+.BR mgpp_passes (1),
+.BR mgpp_perf_hash_build (1),
+.BR mgpp_stem_idx (1),
+.BR mgpp_weights_build (1)
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_compression_dict.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_compression_dict.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_compression_dict.cpp	(revision 10506)
@@ -0,0 +1,1021 @@
+/**************************************************************************
+ *
+ * mgpp_compression_dict.cpp -- Routines for creating compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+/* getopt is in posix.2, so cygwin should have it in unistd, but doesn't */
+#if defined (__WIN32__) || defined (__CYGWIN__)
+# include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_gen.h"
+#include "bitio_m_stdio.h"
+#include "mgheap.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "invf.h"
+#include "text.h"
+#include "words.h"
+#include "mg.h"
+#include "WordData.h"
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+#define is_power_of_two(a) ((a) != 0 && (((a) & ((a)-1)) == 0))
+
+#define MAX_RECALCULATIONS 100
+
+typedef struct DictWordData : public WordData
+  {
+    float saving;
+    float char_bit_cost;
+    u_long num_trans;
+    u_char *word;
+  }
+DictWordData;
+
+static DictWordData *Words[2];
+static u_long Num[2];
+static u_long chars[2];
+
+#define KIND(p) (((p) >= Words[0] && (p) < Words[0] + Num[0]) ? 0 : 1)
+#define IsWord(p) (((p) >= Words[1] && (p) < Words[1] + Num[1]) ? 1 : 0)
+#define IsNonWord(p) (((p) >= Words[0] && (p) < Words[0] + Num[0]) ? 1 : 0)
+
+
+typedef struct DictData
+  {
+    DictWordData **wd;
+    u_long num_wds;
+    u_long chars;
+  }
+DictData;
+
+typedef DictData DictInfo[2];
+
+static DictInfo keep, discard, all;
+static compression_stats_header csh;
+
+static char *file_name = "";
+static u_long novel_method = MG_NOVEL_HUFFMAN_CHARS;
+
+
+static void ReadInWords (char *);
+static void Select_on (int k, heap_comp hc);
+static void Method3 (int k);
+static void Select_all (void);
+static u_long WriteOutWords (char *, u_long, int);
+static int DecFreqIncWL (void *a, void *b);
+static int OccuranceOrder (void *a, void *b);
+
+
+
+int main (int argc, char **argv)
+{
+  int ch;
+  char type = 'C';
+  char mode = '0';
+  int lookback = 2;
+  double k = 0;
+  u_long mem_reqd;
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "0123CPSf:d:l:hk:HDY")) != -1)
+    switch (ch)
+      {
+      case 'H':
+	novel_method = MG_NOVEL_HUFFMAN_CHARS;
+	break;
+      case 'D':
+	novel_method = MG_NOVEL_DELTA;
+	break;
+      case 'Y':
+	novel_method = MG_NOVEL_HYBRID;
+	break;
+      case 'f':		/* input file */
+	file_name = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'C':
+      case 'P':
+      case 'S':
+	type = ch;
+	break;
+      case '0':
+      case '1':
+      case '2':
+      case '3':
+	mode = ch;
+	break;
+      case 'l':
+	lookback = atoi (optarg);
+	if (!is_power_of_two (lookback))
+	  FatalError (1, "The lookback value must be a power of 2");
+	lookback = floorlog_2 (lookback);
+	break;
+      case 'k':
+	k = atof (optarg) * 1024;
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-l lookback] [-f input_file]"
+	"[-d data directory] [-h] [-0|-1|-2|-3] [-C|-P|-S] [-k mem (Kb)]\n",
+		 argv[0]);
+	exit (1);
+      }
+
+  ReadInWords (file_name);
+
+  if (type == 'C')
+    {
+      Select_all ();
+      mem_reqd = WriteOutWords (file_name, MG_COMPLETE_DICTIONARY, lookback);
+    }
+  else
+    {
+      switch (mode)
+	{
+	case '0':
+	  Select_all ();
+	  break;
+	case '1':
+#ifndef SILENT
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+#endif
+	  Select_on ((int) k, OccuranceOrder);
+	  break;
+	case '2':
+#ifndef SILENT
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+#endif
+	  Select_on ((int) k, DecFreqIncWL);
+	  break;
+	case '3':
+#ifndef SILENT
+	  Message ("Dictionary limit of %.2f Kb", k / 1024);
+#endif
+	  Method3 ((int) k);
+	  break;
+	}
+      if (type == 'P')
+	{
+	  mem_reqd = WriteOutWords (file_name, MG_PARTIAL_DICTIONARY, lookback);
+	}
+      else
+	{
+	  mem_reqd = WriteOutWords (file_name, MG_SEED_DICTIONARY, lookback);
+	}
+    }
+
+#ifndef SILENT
+  Message ("Num words           : %8u -> %8u\n", Num[1], keep[1].num_wds);
+  Message ("Num non-words       : %8u -> %8u\n", Num[0], keep[0].num_wds);
+  Message ("Chars of words      : %8u -> %8u\n", chars[1], keep[1].chars);
+  Message ("Chars of non-words  : %8u -> %8u\n", chars[0], keep[0].chars);
+  Message ("Mem usage           : %8u -> %8u\n",
+	   (Num[0] + Num[1]) * sizeof (char *) + chars[0] + chars[1],
+	     (keep[0].num_wds + keep[1].num_wds) * sizeof (char *) +
+	   keep[0].chars + keep[1].chars);
+  Message ("Actual mem required : %8u\n", mem_reqd);
+#endif
+  return (0);
+}
+
+
+
+
+static void 
+ReadInWords (char *filename)
+{
+  FILE *f;
+  unsigned long i;
+  f = open_file (filename, TEXT_STATS_DICT_SUFFIX, "rb",
+		 MAGIC_STATS_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread (&csh, sizeof (csh), 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes);
+
+  for (i = 0; i < 2; ++i)
+    {
+      frags_stats_header fsh;
+      char *buf;
+      DictWordData *wd;
+      chars[i] = 0;
+
+      fread (&fsh, sizeof (fsh), 1, f);
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(fsh.num_frags);
+      NTOHUL(fsh.mem_for_frags);
+
+      Num[i] = all[i].num_wds = fsh.num_frags;
+
+      /* The +1 on the following line is to leave room for the esc code. */
+      all[i].wd = (DictWordData **) Xmalloc (sizeof (DictWordData *) * Num[i] + 1);
+
+      buf = (char *) Xmalloc (fsh.mem_for_frags);
+      wd = Words[i] = (DictWordData *) Xmalloc (sizeof (DictWordData) * Num[i]);
+      unsigned int j;
+      for (j = 0; j < Num[i]; ++j, ++wd)
+	{
+	  int len;
+
+	  // read docCount and wordCount
+	  wd->read(f);
+
+	  // read an mgString
+	  len = fgetc (f);
+	  wd->word = (u_char *) buf;
+	  *buf++ = len;
+	  fread (buf, len, 1, f);
+	  buf += len;
+	  all[i].wd[j] = wd;
+	}
+      chars[i] = fsh.mem_for_frags - fsh.num_frags;
+    }
+  fclose (f);
+}
+
+
+static void 
+Alloc_keep_discard (void)
+{
+  keep[0].num_wds = 0;
+  keep[0].wd = (DictWordData **) Xmalloc ((Num[0] + 1) * sizeof (DictWordData *));
+  keep[1].num_wds = 0;
+  keep[1].wd = (DictWordData **) Xmalloc ((Num[1] + 1) * sizeof (DictWordData *));
+  discard[0].num_wds = 0;
+  discard[0].wd = (DictWordData **) Xmalloc ((Num[0] + 1) * sizeof (DictWordData *));
+  discard[1].num_wds = 0;
+  discard[1].wd = (DictWordData **) Xmalloc ((Num[1] + 1) * sizeof (DictWordData *));
+}
+
+
+static int 
+sort_comp (const void *a, const void *b)
+{
+  DictWordData *aa = *(DictWordData **) a;
+  DictWordData *bb = *(DictWordData **) b;
+  return casecompare (aa->word, bb->word);  /* [RPAP - Jan 97: Stem Index Change] */
+}
+
+
+
+static void 
+SortAndCount_DictData (DictData * dd)
+{
+  unsigned int i;
+  DictWordData **wd;
+  qsort (dd->wd, dd->num_wds, sizeof (DictWordData *), sort_comp);
+  dd->chars = 0;
+  wd = dd->wd;
+  for (i = 0; i < dd->num_wds; ++i, ++wd)
+    dd->chars += (*wd)->word[0];
+}
+
+
+static void 
+Select_all (void)
+{
+  unsigned int i;
+  Alloc_keep_discard ();
+  keep[0].num_wds = Num[0];
+  for (i = 0; i < Num[0]; ++i)
+    keep[0].wd[i] = Words[0] + i;
+  keep[1].num_wds = Num[1];
+  for (i = 0; i < Num[1]; ++i)
+    keep[1].wd[i] = Words[1] + i;
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+}
+
+
+
+
+static int 
+DecFreqIncWL (void *a, void *b)
+{
+  DictWordData *aa = *(DictWordData **) a;
+  DictWordData *bb = *(DictWordData **) b;
+  if (aa->docCount > bb->docCount)
+    return -1;
+  else if (aa->docCount < bb->docCount)
+    return 1;
+  else
+    return bb->word[0] - aa->word[0];
+}
+
+
+static int 
+OccuranceOrder (void *a, void *b)
+{
+  DictWordData *aa = *(DictWordData **) a;
+  DictWordData *bb = *(DictWordData **) b;
+  if (aa->words() > bb->words())
+    return 1;
+  else if (aa->words() < bb->words())
+    return -1;
+  else
+    return 0;
+}
+
+
+static void 
+Select_on (int k, heap_comp hc)
+{
+  int i, num, mem;
+  DictWordData **wd;
+
+  Alloc_keep_discard ();
+
+  num = Num[0] + Num[1];
+  wd = (DictWordData **) Xmalloc (num * sizeof (DictWordData *));
+  for (i = 0; (unsigned int)i < Num[0]; ++i)
+    wd[i] = Words[0] + i;
+  for (i = 0; (unsigned int)i < Num[1]; ++i)
+    wd[i + Num[0]] = Words[1] + i;
+
+  heap_build (wd, sizeof (*wd), num, hc);
+
+  mem = 0;
+  while (k > mem && num)
+    {
+      int idx;
+      DictWordData *word = wd[0];
+#ifdef DEBUG
+      fprintf (stderr, "%4d:%4d:%8d :%8d :%8d : \"%s\"\n",
+	       keep[0].num_wds, keep[1].num_wds,
+	       mem, word->documents(), word->word, word2str (word->word));
+#endif
+      mem += sizeof (u_char *) + word->word[0];
+      heap_deletehead (wd, sizeof (*wd), &num, hc);
+      idx = KIND (word);
+      keep[idx].wd[keep[idx].num_wds++] = word;
+    }
+
+  for (i = 0; i < num; ++i)
+    {
+      DictWordData *word = wd[i];
+      int idx = KIND (word);
+      discard[idx].wd[discard[idx].num_wds++] = word;
+    }
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+  SortAndCount_DictData (&discard[0]);
+  SortAndCount_DictData (&discard[1]);
+
+  assert (keep[0].num_wds + discard[0].num_wds == Num[0]);
+  assert (keep[1].num_wds + discard[1].num_wds == Num[1]);
+
+}
+
+
+
+static int 
+BigSaving (void *a, void *b)
+{
+  DictWordData *aa = *(DictWordData **) a;
+  DictWordData *bb = *(DictWordData **) b;
+  return (aa->saving > bb->saving) ? -1 : (aa->saving < bb->saving);
+}
+
+static int 
+SmallSaving (void *a, void *b)
+{
+  DictWordData *aa = *(DictWordData **) a;
+  DictWordData *bb = *(DictWordData **) b;
+  return (aa->saving < bb->saving) ? -1 : (aa->saving > bb->saving);
+}
+
+
+static void 
+CalcCharCounts (DictWordData ** wd, int num,
+		char *char_lens[2], char *len_lens[2],
+		u_long escape[2])
+{
+  long char_freqs[2][256];
+  long len_freqs[2][16];
+  huff_data hd;
+  int i;
+  escape[0] = 0;
+  escape[1] = 0;
+  memset (char_freqs, '\0', sizeof (char_freqs));
+  memset (len_freqs, '\0', sizeof (len_freqs));
+  for (i = 0; i < num; ++i, ++wd)
+    {
+      u_long freq = (*wd)->documents();
+      u_char *buf = (*wd)->word;
+      int len = *buf++;
+      int idx = KIND (*wd);
+      len_freqs[idx][len] += freq;
+      escape[idx] += freq;
+      for (; len; --len, ++buf)
+	char_freqs[idx][(u_long) (*buf)] += freq;
+    }
+  Generate_Huffman_Data (256, char_freqs[0], &hd, NULL);
+  char_lens[0] = hd.clens;
+  Generate_Huffman_Data (256, char_freqs[1], &hd, NULL);
+  char_lens[1] = hd.clens;
+
+  Generate_Huffman_Data (16, len_freqs[0], &hd, NULL);
+  len_lens[0] = hd.clens;
+  Generate_Huffman_Data (16, len_freqs[1], &hd, NULL);
+  len_lens[1] = hd.clens;
+}
+
+
+
+
+
+inline void CalcBitCostForWordData(DictWordData **word, int num,
+				   double freqs_trans[2], u_long escape[2],
+				   char * char_lens[2], char *len_lens[2], 
+				   double esc[2], int num_trans)
+{ 
+  int j;
+
+  for (j = 0; j < num; ++j, ++word)
+    {
+      float   cbc, wbc;
+      u_char *buf = (*word)->word;
+      int     len = *buf++;
+      u_long  freq = (*word)->documents();
+      int     idx = KIND (*word);
+
+      cbc = len_lens[idx][len];
+      for (; len; --len, ++buf)
+	cbc += char_lens[idx][(u_long) (*buf)];
+
+      (*word)->char_bit_cost = (cbc + esc[idx]) * freq;
+
+      wbc = -log2 (freq / (freqs_trans[idx] + escape[idx])) * freq;
+
+      (*word)->saving = ((*word)->char_bit_cost - wbc) /
+	(sizeof (char *) + (*word)->word[0]);
+
+      (*word)->num_trans = num_trans;
+    }
+}
+
+
+
+void 
+CalcBitCost (DictWordData ** discard_word, int discard_num,
+	     DictWordData ** keep_word, int keep_num, double freqs_trans[2],
+	     u_long escape[2], int num_trans)
+{
+  char *char_lens[2];
+  char *len_lens[2];
+  double esc[2];
+  CalcCharCounts (discard_word, discard_num, char_lens, len_lens, escape);
+  esc[0] = -log2 (escape[0] / (freqs_trans[0] + escape[0]));
+  esc[1] = -log2 (escape[1] / (freqs_trans[1] + escape[1]));
+  CalcBitCostForWordData(discard_word, discard_num, freqs_trans, escape,
+			 char_lens, len_lens, esc, num_trans);
+  CalcBitCostForWordData(keep_word, keep_num, freqs_trans, escape,
+			 char_lens, len_lens, esc, num_trans);
+  Xfree (char_lens[0]);
+  Xfree (char_lens[1]);
+  Xfree (len_lens[0]);
+  Xfree (len_lens[1]);
+}
+
+inline void m3_transferWord(DictWordData **toHeap, int *toNum, heap_comp toSaving,
+			    DictWordData **fromHeap, int *fromNum, heap_comp fromSaving,
+			    int *num_trans, double freqs_trans[], int *mem, double *total,
+			    int *count)
+{
+  /* Transfer the word at the top of the keep heap to the
+     discard heap. */
+  DictWordData *word = fromHeap[0];
+  int idx = KIND (word);
+  heap_deletehead (fromHeap, sizeof (word), fromNum, fromSaving);
+  toHeap[*toNum] = word;
+  heap_additem (toHeap, sizeof (word), toNum, toSaving);
+  freqs_trans[idx] -= word->documents();
+  *mem = (*mem) - sizeof (u_char *) + word->word[0];
+  *num_trans += 1;
+  *total += word->saving;
+  *count += 1;
+#ifdef DEBUG
+  fprintf (stderr,
+	   "KEEP -> DISCARD %8d :%8d :%8.0f :%8.0f : \"%s\"\n",
+	   *mem, word->documents(), word->char_bit_cost,
+	   word->saving, word2str (word->word));
+#endif
+}
+
+inline void m3_storeWord(DictWordData **wordHeap, int wordNum, int num_trans, 
+			 double freqs_trans[], u_long escape[], heap_comp hc)
+{
+  DictWordData *word = wordHeap[0];
+  int idx = KIND (word);
+  float wbc;
+#ifdef DEBUG1
+  fprintf (stderr, "KEEP \"%s\" %.2f ->", word2str (word->word),
+	   word->saving);
+#endif
+  wbc = -log2 (word->documents() / (freqs_trans[idx] + escape[idx])) *
+    word->documents();
+  word->saving = (word->char_bit_cost - wbc) /
+    (sizeof (char *) + word->word[0]);
+#ifdef DEBUG1
+  fprintf (stderr, " %.2f\n", word->saving);
+#endif
+  word->num_trans = num_trans;
+  heap_changedhead (wordHeap, sizeof (word), wordNum, hc);
+}
+
+
+static void 
+Method3 (int k)
+{
+  int i, keep_num, discard_num, mem, num_trans, recalc_reqd;
+  int keep_to_discard = 0;
+  int discard_to_keep = 0;
+  int recalcs = 0;
+  double freqs_trans[2], total;
+  u_long escape[2];
+  DictWordData **keep_heap, **discard_heap;
+
+  freqs_trans[0] = freqs_trans[1] = 0;
+  num_trans = 0;
+
+  discard_num = Num[0] + Num[1];
+  discard_heap = (DictWordData **) Xmalloc (discard_num * sizeof (DictWordData *));
+
+  keep_num = 0;
+  keep_heap = (DictWordData **) Xmalloc (discard_num * sizeof (DictWordData *));
+
+
+  for (i = 0; (unsigned int)i < Num[0]; ++i)
+    discard_heap[i] = Words[0] + i;
+  for (i = 0; (unsigned int)i < Num[1]; ++i)
+    discard_heap[i + Num[0]] = Words[1] + i;
+
+  heap_build (discard_heap, sizeof (*discard_heap), discard_num, DecFreqIncWL);
+
+  mem = 0;
+  while (k > mem && discard_num)
+    {
+      DictWordData *word = discard_heap[0];
+      mem += sizeof (u_char *) + word->word[0];
+      heap_deletehead (discard_heap, sizeof (word), &discard_num, DecFreqIncWL);
+      keep_heap[keep_num++] = word;
+      freqs_trans[KIND (word)] += word->documents();
+      ++num_trans;
+    }
+
+  CalcBitCost (discard_heap, discard_num, keep_heap, keep_num,
+	       freqs_trans, escape, num_trans);
+  heap_build (discard_heap, sizeof (*discard_heap), discard_num, BigSaving);
+  heap_build (keep_heap, sizeof (*keep_heap), keep_num, SmallSaving);
+
+  total = 0;
+  recalc_reqd = 0;
+  while (keep_num && discard_num)
+    {
+      if ((keep_num && keep_heap[0]->num_trans < (unsigned)num_trans) ||
+	  (discard_num && discard_heap[0]->num_trans < (unsigned)num_trans))
+	{
+	  if (keep_num && keep_heap[0]->num_trans < (unsigned)num_trans)
+	    {
+	      m3_storeWord(keep_heap, keep_num, num_trans, freqs_trans, escape, SmallSaving);
+	    }
+
+	  if (discard_num && discard_heap[0]->num_trans < (unsigned)num_trans)
+	    {
+	      m3_storeWord(discard_heap, discard_num, num_trans, freqs_trans, escape, BigSaving);
+	    }
+	}
+      else if (keep_heap[0]->saving < discard_heap[0]->saving)
+	{
+	  assert (keep_num && discard_num);
+	  if (keep_num && mem + sizeof (char *) + discard_heap[0]->word[0] > (unsigned)k)
+	    {
+	      /* Transfer the word at the top of the keep heap to the
+	         discard heap. */
+	      m3_transferWord(discard_heap, &discard_num, BigSaving,
+			      keep_heap, &keep_num, SmallSaving,
+			      &num_trans, freqs_trans, &mem, &total, &keep_to_discard);
+	    }
+	  else
+	    {
+	      /* Transfer the word at the top of the discard heap to the
+	         keep heap. */
+	      m3_transferWord(keep_heap, &keep_num, SmallSaving,
+			      discard_heap, &discard_num, BigSaving,
+			      &num_trans, freqs_trans, &mem, &total, &discard_to_keep);
+	    }
+
+	  recalc_reqd = 1;
+
+	}
+      else
+	{
+	  if (recalc_reqd == 0)
+	    break;
+#ifdef DEBUG1
+	  fprintf (stderr, "--------------\n");
+#endif
+	  if (recalcs == MAX_RECALCULATIONS)
+	    break;
+	  CalcBitCost (discard_heap, discard_num, keep_heap, keep_num,
+		       freqs_trans, escape, num_trans);
+	  heap_build (discard_heap, sizeof (*discard_heap),
+		      discard_num, BigSaving);
+	  heap_build (keep_heap, sizeof (keep_heap), keep_num, SmallSaving);
+	  recalc_reqd = 0;
+	  ++recalcs;
+	}
+    }
+
+  Alloc_keep_discard ();
+
+  for (i = 0; i < discard_num; ++i)
+    {
+      DictWordData *word = discard_heap[i];
+      int idx = KIND (word);
+      assert (IsWord (word) || IsNonWord (word));
+      discard[idx].wd[discard[idx].num_wds++] = word;
+    }
+  for (i = 0; i < keep_num; ++i)
+    {
+      DictWordData *word = keep_heap[i];
+      int idx = KIND (word);
+      assert (IsWord (word) || IsNonWord (word));
+      keep[idx].wd[keep[idx].num_wds++] = word;
+    }
+  SortAndCount_DictData (&keep[0]);
+  SortAndCount_DictData (&keep[1]);
+  SortAndCount_DictData (&discard[0]);
+  SortAndCount_DictData (&discard[1]);
+
+  assert (keep[0].num_wds + discard[0].num_wds == Num[0]);
+  assert (keep[1].num_wds + discard[1].num_wds == Num[1]);
+#ifndef SILENT
+  Message ("Keep -> Discard        : %8d", keep_to_discard);
+  Message ("Discard -> Keep        : %8d", discard_to_keep);
+  Message ("Huffman Recalculations : %8d", recalcs);
+  if (recalcs == MAX_RECALCULATIONS)
+    Message ("WARNING: The number of recalculations == %d", MAX_RECALCULATIONS);
+#endif
+}
+
+
+
+
+
+
+
+
+
+
+/****************************************************************************
+ *****									*****
+ *****			Dictionary saving code				*****
+ *****									*****
+ ****************************************************************************/
+
+
+
+static void 
+Write_cdh (FILE * f, compression_dict_header * cdh)
+{
+  /* [RPAP - Jan 97: Endian Ordering] */
+  int i;
+  compression_dict_header tmp = *cdh;
+  HTONUL(tmp.dict_type);
+  HTONUL(tmp.novel_method);
+  for (i = 0; i < TEXT_PARAMS; ++i)
+    HTONUL(tmp.params[i]);
+  HTONUL(tmp.num_words[0]);
+  HTONUL(tmp.num_words[1]);
+  HTONUL(tmp.num_word_chars[0]);
+  HTONUL(tmp.num_word_chars[1]);
+  HTONUL(tmp.lookback);
+
+  fwrite (&tmp, sizeof (tmp), 1, f);
+}
+
+
+static void 
+Write_words (FILE * f, DictData * dd)
+{
+  unsigned int i;
+  u_char *curr, *prev = NULL;
+  for (i = 0; i < dd->num_wds; ++i)
+    {
+      int len;
+      curr = dd->wd[i]->word;
+      if (prev)
+	/* look for prefix match with prev string */
+	len = prefixlen (prev, curr);
+      else
+	len = 0;
+      fputc ((len << 4) + (curr[0] - len), f);
+      fwrite (curr + len + 1, sizeof (u_char), curr[0] - len, f);
+      prev = curr;
+    }
+
+}
+
+
+static int 
+Uncompressed_size (DictData * dd)
+{
+  unsigned int i, us;
+  for (us = i = 0; i < dd->num_wds; ++i)
+    us += dd->wd[i]->word[0];
+  return us;
+}
+
+
+static u_long 
+Write_data (FILE * f, DictData * dd, int lookback)
+{
+  u_long mem_reqd;
+  huff_data *hd;
+  int i; 
+  u_long us = dd->num_wds;
+  long *freqs;
+  u_long huff_words_size[MAX_HUFFCODE_LEN + 1];
+  u_long lencounts[MAX_HUFFCODE_LEN + 1];
+  u_char *lastword[MAX_HUFFCODE_LEN + 1];
+
+  if (!(freqs = new long [dd->num_wds]))
+    FatalError (1, "Unable to allocate memory for freqs");
+
+  for (i = 0; (unsigned)i < dd->num_wds; ++i)
+    {
+      freqs[i] = dd->wd[i]->documents();
+      us += dd->wd[i]->word[0];
+    }
+
+  if (!(hd = Generate_Huffman_Data (dd->num_wds, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  delete []freqs;
+  freqs = NULL;
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+  HTONUL(us);  /* [RPAP - Jan 97: Endian Ordering] */
+  fwrite (&us, sizeof (us), 1, f);
+  NTOHUL(us);  /* [RPAP - Jan 97: Endian Ordering] */
+
+
+/* Calculate the amount of memory that will be required to store the text for
+   each different huffman code len. Every 1<<lookback words for each different
+   codelen length will not be prefixed by previous strings. */
+
+
+  memset (&huff_words_size, '\0', sizeof (huff_words_size));
+  memset (&lencounts, '\0', sizeof (lencounts));
+
+  mem_reqd = 0;
+
+  for (i = 0; (unsigned)i < dd->num_wds; ++i)
+    {
+      int codelen = hd->clens[i];
+      u_char *word = dd->wd[i]->word;
+
+      if (!codelen)
+	FatalError (1, "The length of a code for a word was zero");
+
+      huff_words_size[codelen] += word[0] + 1;
+      mem_reqd += word[0] + (lookback != 0);
+#if 0
+      if ((lencounts[codelen] & ((1 << lookback) - 1)) == 0)
+	lastword[codelen] = word;
+      else
+	huff_words_size[codelen] -= prefixlen (lastword[codelen], word);
+#else
+      if ((lencounts[codelen] & ((1 << lookback) - 1)) != 0)
+	{
+	  int save = prefixlen (lastword[codelen], word);
+	  mem_reqd -= save;
+	  huff_words_size[codelen] -= save;
+	}
+      else
+	{
+	  mem_reqd += sizeof (u_char *);
+	}
+      lastword[codelen] = word;
+#endif
+      ++lencounts[codelen];
+    }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = hd->mincodelen; i < hd->maxcodelen + 1; ++i)
+    HTONUL(huff_words_size[i]);
+
+  fwrite (huff_words_size + hd->mincodelen, sizeof (*huff_words_size),
+	  hd->maxcodelen - hd->mincodelen + 1, f);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  for (i = hd->mincodelen; i < hd->maxcodelen + 1; ++i)
+    NTOHUL(huff_words_size[i]);
+
+  Write_words (f, dd);
+
+  delete []hd->clens;
+  delete hd;
+
+  return mem_reqd;
+}
+
+
+
+static void 
+Write_charfreqs (FILE * f, DictData * dd, int words,
+		 int zero_freq_permitted)
+{
+  unsigned int j;
+  long freqs[256];
+  DictWordData **wd = dd->wd;
+  huff_data *hd;
+
+  memset (freqs, '\0', sizeof (freqs));
+
+  for (j = 0; j < dd->num_wds; ++j, ++wd)
+    {
+      u_char *buf = (*wd)->word;
+      int len = *buf++;
+      for (; len; --len, ++buf)
+	freqs[(u_long) (*buf)] += (*wd)->documents();
+    }
+
+  if (!zero_freq_permitted)
+    for (j = 0; j < 256; ++j)
+      if (!freqs[j] && PESINAWORD (j) == words)
+	freqs[j] = 1;
+
+  if (!(hd = Generate_Huffman_Data (256, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+  delete []hd->clens;
+  delete hd;
+}
+
+
+
+
+static void 
+Write_wordlens (FILE * f, DictData * dd, int zero_freq_permitted)
+{
+  unsigned int j;
+  long freqs[16];
+  DictWordData **wd = dd->wd;
+  huff_data *hd;
+
+  memset (freqs, '\0', sizeof (freqs));
+
+  for (j = 0; j < dd->num_wds; ++j, ++wd)
+    freqs[(*wd)->word[0]] += (*wd)->documents();
+
+  if (!zero_freq_permitted)
+    for (j = 0; j < 16; ++j)
+      if (!freqs[j])
+	freqs[j] = 1;
+
+  if (!(hd = Generate_Huffman_Data (16, freqs, NULL, NULL)))
+    FatalError (1, "Unable to allocate memory for huffman data");
+
+  if (Write_Huffman_Data (f, hd) == -1)
+    FatalError (1, "Unable to write huffman data");
+
+
+  delete []hd->clens;
+  delete hd;
+}
+
+
+
+static u_long 
+WriteOutWords (char *file_name, u_long type, int lookback)
+{
+  FILE *f;
+  int i;
+  u_long mem_reqd = 0;
+
+  compression_dict_header cdh;
+  f = create_file (file_name, TEXT_DICT_SUFFIX, "w+b",
+		   MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  memset (&cdh, '\0', sizeof(cdh));
+
+  cdh.dict_type = type;
+  cdh.novel_method = (type == MG_SEED_DICTIONARY) ? novel_method :
+    MG_NOVEL_HUFFMAN_CHARS;
+
+  cdh.num_words[1] = keep[1].num_wds;
+  cdh.num_words[0] = keep[0].num_wds;
+  cdh.num_word_chars[1] = Uncompressed_size (&keep[1]);
+  cdh.num_word_chars[0] = Uncompressed_size (&keep[0]);
+  cdh.lookback = lookback;
+
+  Write_cdh (f, &cdh);
+
+  for (i = 0; i < 2; ++i)
+    switch (type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  mem_reqd += Write_data (f, &keep[i], lookback);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (keep[i].num_wds)
+	    {
+	      int j;
+	      DictWordData esc;
+	      esc.docCount = 0;
+	      esc.word = (u_char *) "";
+	      keep[i].wd[keep[i].num_wds++] = &esc;
+	      for (j = 0; (unsigned)j < discard[i].num_wds; ++j)
+		esc.docCount += discard[i].wd[j]->documents();
+	      if (!esc.docCount)
+		++esc.docCount;
+	      mem_reqd += Write_data (f, &keep[i], lookback);
+	    }
+	  Write_charfreqs (f, &discard[i], i, 1);
+	  Write_wordlens (f, &discard[i], 1);
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (keep[i].num_wds)
+	    {
+	      int j;
+	      DictWordData esc;
+	      esc.docCount = 0;
+	      esc.word = (u_char *) "";
+	      keep[i].wd[keep[i].num_wds++] = &esc;
+	      for (j = 0; (unsigned)j < all[i].num_wds; ++j)
+		if (all[i].wd[j]->documents() == 1)
+		  ++esc.docCount;
+	      if (!esc.docCount)
+		++esc.docCount;
+	      mem_reqd += Write_data (f, &keep[i], lookback);
+	    }
+	  switch (novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      Write_charfreqs (f, &all[i], i, 0);
+	      Write_wordlens (f, &all[i], 0);
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    default:
+	      FatalError (1, "Bad novel method");
+	    }
+	}
+	break;
+      }
+  fclose (f);
+  return mem_reqd;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_decompress_text.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_decompress_text.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_decompress_text.cpp	(revision 10506)
@@ -0,0 +1,100 @@
+/**************************************************************************
+ *
+ * mgpp_decompress_text.cpp -- 
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+/* getopt is in posix.2, so cygwin should have it in unistd, but doesn't */
+#if defined (__WIN32__) || defined (__CYGWIN__)
+# include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "UCArray.h"
+#include "sysfuncs.h"
+#include "TextGet.h"
+#include "messages.h"
+#include "mg_files.h"
+
+int main (int argc, char **argv) {
+  int ch;
+  char *filename = "";
+  char *basePath = "";
+  UCArray level;
+  SetCStr (level, "Document", 8);
+
+  opterr = 0;
+  msg_prefix = argv[0];
+
+  // process the command line arguments
+  while ((ch = getopt (argc, argv, "f:d:K:h")) != -1) {
+    switch (ch) {
+    case 'f':		/* input file */
+      filename = optarg;
+      break;
+    case 'd':
+      basePath = optarg;
+      set_basepath (optarg);
+      break;
+    case 'K':
+      SetCStr (level, optarg, strlen(optarg));
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-h] [-K level] [-d directory] -f name\n",
+	       argv[0]);
+      exit (1);
+    }
+  }
+
+  // load up the text information
+  TextData td;
+  if (!td.LoadData (basePath, filename)) {
+    FatalError (1, "Couldn't load text information for \"%s\"", filename);
+  }
+  
+  // output each document in the level
+//    cout << td.levels << "\n";
+  
+  TextLevelInfo levelInfo = td.levels.levelInfo[level];
+  unsigned long docNum = 1;
+  UCArray docText;
+  while (docNum <= levelInfo.numEntries) {
+//      TextIdx docIdx;
+//      if (GetDocIdx (td, level, docNum, docIdx)) {
+//        cout << "doc: " << docNum << "\n";
+//        cout << docIdx;
+//      }
+    
+    if (!GetDocText (td, level, docNum, docText)) {
+      FatalError (1, "Error while trying to get document %u", docNum);
+    }
+
+    cout << docText << "\n";
+    
+    ++docNum;
+  }
+  
+  return 0;
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_fast_comp_dict.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_fast_comp_dict.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_fast_comp_dict.1	(revision 10506)
@@ -0,0 +1,69 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.\"------------------------------------------------------------
+.TH mgpp_fast_comp_dict 1 \*(Dt CITRI
+.SH NAME
+mgpp_fast_comp_dict \- build a fast loading compression dictionary
+.SH SYNOPSIS
+.B mgpp_fast_comp_dict
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgpp_fast_comp_dict
+builds a fast-loading compression dictionary from the standard
+compression dictionary.  The new dictionary has the property that
+.BR mgppquery (1)
+can load it in very quickly, making the startup time for
+.BR mgppquery (1)
+much shorter.  The new dictionary is larger on disk than the original,
+but they are no different when it comes to memory usage.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mgpp
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.text.dict
+Compression dictionary.
+.TP
+.B *.text.dict.fast
+Fast loading compression dictionary.
+.TP
+.B *.text.dict.aux
+Auxiliary compression dictionary.
+.SH "SEE ALSO"
+.na
+.BR mgpp_compression_dict (1),
+.BR mgpp_invf_dict (1),
+.BR mgpp_passes (1),
+.BR mgpp_perf_hash_build (1),
+.BR mgpp_stem_idx (1),
+.BR mgpp_weights_build (1)
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_fast_comp_dict.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_fast_comp_dict.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_fast_comp_dict.cpp	(revision 10506)
@@ -0,0 +1,707 @@
+/**************************************************************************
+ *
+ * mgpp_fast_comp_dict.cpp -- Program to generate a fast compression dictionary
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+/* getopt is in posix.2, so cygwin should have it in unistd, but doesn't */
+#if defined (__WIN32__) || defined (__CYGWIN__)
+# include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "sysfuncs.h"
+#include "huffman.h"
+#include "messages.h"
+#include "memlib.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "local_strings.h"
+#include "mg.h"
+#include "text.h"
+#include "invf.h"
+#include "mg_files.h"
+#include "locallib.h"
+#include "words.h"
+
+
+
+#define ALIGN_SIZE(p,t) (((p) + (sizeof(t)-1)) & (~(sizeof(t)-1)))
+
+#define WORDNO(p, base) ((((char*)(p))-((char*)(base)))/sizeof(u_char*))
+#define FIXUP(p) (fixup[WORDNO(p,buffer)/8] |= (1<<(WORDNO(p, buffer) & 7)))
+
+#define IS_FIXUP(p) ((fixup[WORDNO(p,buffer)/8] & (1<<(WORDNO(p, buffer) & 7))) != 0)
+
+#define FIXUP_VALS(vals) do {						\
+	int i;								\
+	for (i=0; i < MAX_HUFFCODE_LEN+1; ++i)				\
+	  FIXUP(&vals[i]);						\
+      } while(0)
+
+
+
+static u_long mem_for_comp_dict (char *filename);
+static void load_comp_dict (char *filename);
+static void save_fast_dict (char *filename);
+static void unfixup_buffer (void);
+
+
+static void *buffer;
+static void *cur;
+static u_char *fixup;
+static u_long mem, fixup_mem;
+
+int main (int argc, char **argv)
+{
+  int ch;
+  char *filename = "";
+  opterr = 0;
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "f:d:h")) != -1)
+    switch (ch)
+      {
+      case 'f':		/* input file */
+	filename = optarg;
+	break;
+      case 'd':
+	set_basepath (optarg);
+	break;
+      case 'h':
+      case '?':
+	fprintf (stderr, "usage: %s [-f input_file] [-d data directory] [-h]\n",
+		 argv[0]);
+	exit (1);
+      }
+
+  mem = mem_for_comp_dict (filename);
+
+  fixup_mem = (ALIGN_SIZE (mem, u_char *) / sizeof (u_char *) + 7) / 8;
+
+  cur = buffer = Xmalloc (mem);
+  memset (buffer, 0, mem);
+  fixup = (u_char *) Xmalloc (fixup_mem);
+  memset (fixup, 0, fixup_mem);
+
+#ifndef SILENT
+  Message ("Estimated memory for fast_dict %u", mem);
+  Message ("Estimated memory for fixups %u", fixup_mem);
+#endif
+
+  load_comp_dict (filename);
+
+#ifndef SILENT
+  Message ("Actual memory for fast_dict %u", (char *) cur - (char *) buffer);
+#endif
+
+  if ((u_long) cur > (u_long) buffer + mem)
+    FatalError (1, "The buffer was not big enough for the dictionary");
+
+  {
+    /* [RPAP - Jan 97: Endian Ordering] */
+    compression_dict *cd = (compression_dict *) buffer;
+    int i, which;
+
+    /* cfh */
+    for (which = 0; which <= 1; ++which)
+      {
+	int j;
+	
+	HTONSI(cd->cfh[which]->hd.num_codes);
+	HTONSI(cd->cfh[which]->hd.mincodelen);
+	HTONSI(cd->cfh[which]->hd.maxcodelen);
+	for (j = 0; j < MAX_HUFFCODE_LEN + 1; ++j)
+	  {
+	    HTONSI(cd->cfh[which]->hd.lencount[j]);
+	    HTONUL(cd->cfh[which]->hd.min_code[j]);
+	  }
+	HTONUL(cd->cfh[which]->uncompressed_size);
+	for (j = 0; j < MAX_HUFFCODE_LEN + 1; ++j)
+	  HTONUL(cd->cfh[which]->huff_words_size[j]);
+      }
+    HTONUL(cd->MemForCompDict);
+    /* ad */
+    if (cd->cdh.novel_method == MG_NOVEL_DELTA ||
+	cd->cdh.novel_method == MG_NOVEL_HYBRID)
+      for (which = 0; which <= 1; ++which)
+	{
+	  int j;
+	  
+	  HTONUL(cd->ad->afh[which].num_frags);
+	  HTONUL(cd->ad->afh[which].mem_for_frags);
+	  for (j = 0; j < 33; ++j)
+	    {
+	      HTONSI(cd->ad->blk_start[which][j]);
+	      HTONSI(cd->ad->blk_end[which][j]);
+	    }
+	}
+    /* cdh */
+    HTONUL(cd->cdh.dict_type);
+    HTONUL(cd->cdh.novel_method);
+    for (i = 0; i < TEXT_PARAMS; ++i)
+      HTONUL(cd->cdh.params[which]);
+    HTONUL(cd->cdh.num_words[0]);
+    HTONUL(cd->cdh.num_words[1]);
+    HTONUL(cd->cdh.num_word_chars[0]);
+    HTONUL(cd->cdh.num_word_chars[1]);
+    HTONUL(cd->cdh.lookback);
+    HTONSI(cd->fast_loaded);
+  }
+
+  unfixup_buffer ();
+
+  save_fast_dict (filename);
+
+  return (0);
+}
+
+
+
+static void 
+unfixup_buffer ()
+{
+  u_long *p;
+  for (p = (u_long *) buffer; (u_long) p < (u_long) cur; ++p)
+    {
+      if (IS_FIXUP (p))
+	*p = *p - (u_long) buffer;
+    }
+}
+
+
+
+
+static u_long 
+mem_for_aux_dict (compression_dict_header * /*cdh*/, char *filename)
+{
+  int i;
+  u_long mem = sizeof (auxiliary_dict);
+  FILE *aux;
+
+  aux = open_file (filename, TEXT_DICT_AUX_SUFFIX, "rb",
+		   MAGIC_AUX_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  for (i = 0; i <= 1; ++i)
+    {
+      aux_frags_header afh;
+      fread (&afh, sizeof (afh), 1, aux);
+      NTOHUL(afh.num_frags);  /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(afh.mem_for_frags);  /* [RPAP - Jan 97: Endian Ordering] */
+      mem += afh.num_frags * sizeof (u_char *);
+      mem = ALIGN_SIZE (mem + afh.mem_for_frags, u_char *);
+      fseek (aux, afh.mem_for_frags, SEEK_CUR);
+    }
+  fclose (aux);
+
+  return mem;
+}
+
+
+
+static u_long 
+mem_for_words (FILE * dict, compression_dict_header * cdh,
+	       comp_frags_header * cfh)
+{
+  u_long mem = 0;
+  long i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+
+  lookback = cdh->lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; ++i)
+    {
+      ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+      mem_reqd += cfh->huff_words_size[i];
+    }
+
+  mem += ptrs_reqd * sizeof (u_char *);
+  mem += (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **);
+  mem += mem_reqd;
+
+  for (i = 0; i < cfh->hd.num_codes; ++i)
+    {
+      register int val;
+      for (val = getc (dict) & 0xf; val; --val)
+	getc (dict);
+    }
+  return ALIGN_SIZE (mem, u_char *);
+}
+
+static u_long mem_skip_hd(FILE *dict, u_long mem)
+{ huff_data hd;
+
+  mem += sizeof (hd);
+  Read_Huffman_Data (dict, &hd, NULL, NULL);
+  if (hd.clens)
+    delete []hd.clens;
+  mem += hd.num_codes * sizeof (unsigned long);
+  mem += (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+  return mem;
+}
+
+static u_long mem_read_cfh(FILE *dict, compression_dict_header *cdh, comp_frags_header *cfh, 
+			   u_long mem)
+{
+  mem += sizeof (comp_frags_header);
+  Read_cfh (dict, cfh, NULL, NULL);
+
+  /* Don't need to count the space for the clens of the huffman data */
+
+  mem += mem_for_words (dict, cdh, cfh);
+  if (cfh->hd.clens)
+    delete []cfh->hd.clens;
+
+  return mem;
+}
+
+
+static u_long 
+mem_for_comp_dict (char *filename)
+{
+  u_long mem = sizeof (compression_dict);
+  compression_dict_header cdh;
+  comp_frags_header cfh;
+  FILE *dict;
+  int which;
+  int i;  /* [RPAP - Jan 97: Endian Ordering] */
+
+  dict = open_file (filename, TEXT_DICT_SUFFIX, "rb",
+		    MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  fread (&cdh, sizeof (cdh), 1, dict);
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(cdh.dict_type);
+  NTOHUL(cdh.novel_method);
+  for (i = 0; i < TEXT_PARAMS; ++i)
+    NTOHUL(cdh.params[i]);
+  NTOHUL(cdh.num_words[0]);
+  NTOHUL(cdh.num_words[1]);
+  NTOHUL(cdh.num_word_chars[0]);
+  NTOHUL(cdh.num_word_chars[1]);
+  NTOHUL(cdh.lookback);
+
+  for (which = 0; which < 2; ++which)
+    switch (cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  mem = mem_read_cfh(dict, &cdh, &cfh, mem);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  // huff_data hd;
+	  if (cdh.num_words[which])
+	    {
+	      mem = mem_read_cfh(dict, &cdh, &cfh, mem);
+	    }
+
+	  mem = mem_skip_hd(dict, mem);
+	  mem = mem_skip_hd(dict, mem);
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  // huff_data hd;
+	  if (cdh.num_words[which])
+	    {
+	      mem = mem_read_cfh(dict, &cdh, &cfh, mem);
+	    }
+	  switch (cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      mem = mem_skip_hd(dict, mem);
+	      mem = mem_skip_hd(dict, mem);
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    }
+	  break;
+	}
+      }
+  fclose (dict);
+
+  if (cdh.novel_method == MG_NOVEL_DELTA ||
+      cdh.novel_method == MG_NOVEL_HYBRID)
+    mem += mem_for_aux_dict (&cdh, filename);
+
+  return ALIGN_SIZE (mem, u_char *);
+}
+
+
+
+void *
+getmem (u_long size, int align)
+{
+  void *res;
+  cur = (void *) (((u_long) cur + (align - 1)) & (~(align - 1)));
+  res = cur;
+  cur = (char *) cur + size;
+  if ((u_long) cur > (u_long)buffer + mem)
+    FatalError (1, "The buffer was not big enough for the dictionary");
+  return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+static auxiliary_dict *
+LoadAuxDict (compression_dict_header * cdh,
+	     char *filename)
+{
+  auxiliary_dict *ad;
+  int i;
+  FILE *aux;
+
+  aux = open_file (filename, TEXT_DICT_AUX_SUFFIX, "rb",
+		   MAGIC_AUX_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  ad = (auxiliary_dict *) getmem (sizeof (auxiliary_dict), sizeof (u_char *));
+
+  for (i = 0; i <= 1; ++i)
+    {
+      unsigned int j;
+      u_char *pos;
+
+      fread (&ad->afh[i], sizeof (aux_frags_header), 1, aux);
+
+      /* [RPAP - Jan 97: Endian Ordering] */
+      NTOHUL(ad->afh[i].num_frags);
+      NTOHUL(ad->afh[i].mem_for_frags);
+
+      ad->word_data[i] = (u_char *) getmem (ad->afh[i].mem_for_frags, 1);
+      FIXUP (&ad->word_data[i]);
+
+      ad->words[i] = (u_char **) getmem (ad->afh[i].num_frags * sizeof (u_char *),
+			     sizeof (u_char *));
+      FIXUP (&ad->words[i]);
+
+      fread (ad->word_data[i], ad->afh[i].mem_for_frags, sizeof (u_char), aux);
+
+      pos = ad->word_data[i];
+      for (j = 0; j < ad->afh[i].num_frags; ++j)
+	{
+	  ad->words[i][j] = pos;
+	  FIXUP (&ad->words[i][j]);
+	  pos += *pos + 1;
+	}
+      if (cdh->novel_method == MG_NOVEL_HYBRID)
+	{
+	  int num;
+	  num = 1;
+	  ad->blk_start[i][0] = 0;
+	  ad->blk_end[i][0] = cdh->num_words[i] - 1;
+	  while (num < 33)
+	    {
+	      ad->blk_start[i][num] = ad->blk_end[i][num - 1] + 1;
+	      ad->blk_end[i][num] = ad->blk_start[i][num] +
+		(ad->blk_end[i][num - 1] - ad->blk_start[i][num - 1]) * 2;
+	      ++num;
+	    }
+	}
+    }
+  fclose (aux);
+  return (ad);
+}
+
+
+
+
+
+static u_char ***
+ReadInWords (FILE * dict, compression_dict * cd,
+	     comp_frags_header * cfh, u_char ** escape)
+{
+  int i, lookback;
+  int ptrs_reqd = 0;
+  int mem_reqd = 0;
+  int num_set[MAX_HUFFCODE_LEN + 1];
+  u_char *next_word[MAX_HUFFCODE_LEN + 1];
+  u_char **vals;
+  u_char ***values;
+  u_char word[MAXWORDLEN + 1];
+  u_char last_word[MAX_HUFFCODE_LEN + 1][MAXWORDLEN + 1];
+
+  lookback = cd->cdh.lookback;
+
+  for (i = cfh->hd.mincodelen; i <= cfh->hd.maxcodelen; ++i)
+    {
+      ptrs_reqd += (cfh->hd.lencount[i] + ((1 << lookback) - 1)) >> lookback;
+      mem_reqd += cfh->huff_words_size[i];
+    }
+
+  vals = (u_char **) getmem (ptrs_reqd * sizeof (*vals), sizeof (u_char *));
+
+  values = (u_char ***) getmem ((MAX_HUFFCODE_LEN + 1) * sizeof (u_char **), sizeof (u_char **));
+
+  next_word[0] = (u_char *) getmem (mem_reqd, sizeof (char));
+
+  cd->MemForCompDict += ptrs_reqd * sizeof (*vals) +
+    (MAX_HUFFCODE_LEN + 1) * sizeof (u_char **) +
+    mem_reqd;
+
+  values[0] = vals;
+  FIXUP (&values[0]);
+  values[0][0] = next_word[0];
+  FIXUP (&values[0][0]);
+  for (i = 1; i <= cfh->hd.maxcodelen; ++i)
+    {
+      int next_start = (values[i - 1] - vals) +
+      ((cfh->hd.lencount[i - 1] + ((1 << lookback) - 1)) >> lookback);
+      values[i] = &vals[next_start];
+      FIXUP (&values[i]);
+      next_word[i] = next_word[i - 1] + cfh->huff_words_size[i - 1];
+      values[i][0] = next_word[i];
+      FIXUP (&values[i][0]);
+    }
+
+  memset (num_set, '\0', sizeof (num_set));
+
+  for (i = 0; i < cfh->hd.num_codes; ++i)
+    {
+      register int val, copy;
+      register int len = cfh->hd.clens[i];
+      val = getc (dict);
+      copy = (val >> 4) & 0xf;
+      val &= 0xf;
+
+      fread (word + copy + 1, sizeof (u_char), val, dict);
+      *word = val + copy;
+
+      if ((num_set[len] & ((1 << lookback) - 1)) == 0)
+	{
+	  values[len][num_set[len] >> lookback] = next_word[len];
+	  FIXUP (&values[len][num_set[len] >> lookback]);
+	  memcpy (next_word[len], word, *word + 1);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    {
+	      *escape = next_word[len];
+	      FIXUP (escape);
+	    }
+	  next_word[len] += *word + 1;
+	}
+      else
+	{
+	  copy = prefixlen (last_word[len], word);
+	  memcpy (next_word[len] + 1, word + copy + 1, *word - copy);
+	  *next_word[len] = (copy << 4) + (*word - copy);
+	  if (escape && i == cfh->hd.num_codes - 1)
+	    {
+	      *escape = next_word[len];
+	      FIXUP (escape);
+	    }
+	  next_word[len] += (*word - copy) + 1;
+	}
+      memcpy (last_word[len], word, *word + 1);
+      ++num_set[len];
+    }
+  if (cfh->hd.clens)
+    delete []cfh->hd.clens;
+  cfh->hd.clens = NULL;
+  return values;
+}
+
+
+static unsigned long **
+Generate_Fast_Huffman_Vals (huff_data * data, u_long * mem)
+{
+  int i;
+  unsigned long *fcode[MAX_HUFFCODE_LEN + 1];
+  unsigned long **values;
+  unsigned long *vals;
+
+  if (!data)
+    return (NULL);
+  vals = (unsigned long *) getmem (data->num_codes * sizeof (*vals), sizeof (long *));
+  values = (unsigned long **) getmem ((MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *),
+		   sizeof (long *));
+
+  memset (values, '\0', (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *));
+
+  if (mem)
+    *mem += data->num_codes * sizeof (*vals) +
+      (MAX_HUFFCODE_LEN + 1) * sizeof (unsigned long *);
+
+  fcode[0] = values[0] = &vals[0];
+  FIXUP (&values[0]);
+  for (i = 1; i <= data->maxcodelen; ++i)
+    {
+      fcode[i] = values[i] = &vals[(values[i - 1] - vals) + data->lencount[i - 1]];
+      FIXUP (&values[i]);
+    }
+
+  for (i = 0; i < data->num_codes; ++i)
+    if (data->clens[i])
+      *fcode[(int) (data->clens[i])]++ = i;
+  return (values);
+}
+
+
+static void load_read_huffman(FILE *dict, compression_dict *cd, int which)
+{
+  huff_data *hd;
+  u_long   **vals;
+
+  hd = (huff_data *) getmem (sizeof (huff_data), sizeof (char *));
+  cd->MemForCompDict += sizeof (huff_data);
+  Read_Huffman_Data (dict, hd, &cd->MemForCompDict, NULL);
+  vals = Generate_Fast_Huffman_Vals (hd, &cd->MemForCompDict);
+  cd->chars_huff[which] = hd;
+  FIXUP (&cd->chars_huff[which]);
+  cd->chars_vals[which] = vals;
+  FIXUP (&cd->chars_vals[which]);
+  if (hd->clens)
+    delete []hd->clens;
+  hd->clens = NULL;
+}
+
+static void load_read_words(FILE *dict, compression_dict *cd, int which, int fixescape)
+{
+  cd->cfh[which] = (comp_frags_header *) getmem (sizeof (*cd->cfh[which]), sizeof (u_char *));
+  cd->MemForCompDict += sizeof (*cd->cfh[which]);
+  Read_cfh (dict, cd->cfh[which], &cd->MemForCompDict, NULL);
+
+  cd->values[which] = ReadInWords (dict, cd, cd->cfh[which], NULL);
+  FIXUP (&cd->cfh[which]);
+  FIXUP (&cd->values[which]);
+  if (fixescape)
+    { FIXUP(&cd->escape[which]);
+    }
+  else
+    {
+      cd->escape[which] = NULL;
+    }
+}
+
+static void 
+load_comp_dict (char *filename)
+{
+  FILE *dict;
+  int which;
+  compression_dict *cd;
+
+  cd = (compression_dict *) getmem (sizeof (compression_dict), sizeof (u_char *));
+  cd->fast_loaded = 1;
+
+  dict = open_file (filename, TEXT_DICT_SUFFIX, "rb",
+		    MAGIC_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  Read_cdh (dict, &cd->cdh, NULL, NULL);
+
+  for (which = 0; which < 2; ++which)
+    switch (cd->cdh.dict_type)
+      {
+      case MG_COMPLETE_DICTIONARY:
+	{
+	  load_read_words(dict, cd, which, 0);
+	}
+	break;
+      case MG_PARTIAL_DICTIONARY:
+	{
+	  if (cd->cdh.num_words[which])
+	    {
+	      load_read_words(dict, cd, which, 1);
+	    }
+
+	  load_read_huffman(dict, cd, which);
+	  load_read_huffman(dict, cd, which);
+	}
+	break;
+      case MG_SEED_DICTIONARY:
+	{
+	  if (cd->cdh.num_words[which])
+	    {
+	      load_read_words(dict, cd, which, 1);
+	    }
+	  switch (cd->cdh.novel_method)
+	    {
+	    case MG_NOVEL_HUFFMAN_CHARS:
+	      load_read_huffman(dict, cd, which);
+	      load_read_huffman(dict, cd, which);
+	      break;
+	    case MG_NOVEL_DELTA:
+	      break;
+	    case MG_NOVEL_HYBRID:
+	      break;
+	    }
+	  break;
+	}
+      }
+  fclose (dict);
+
+
+  if (cd->cdh.novel_method == MG_NOVEL_DELTA ||
+      cd->cdh.novel_method == MG_NOVEL_HYBRID)
+    {
+      cd->ad = LoadAuxDict (&cd->cdh, filename);
+      FIXUP (&cd->ad);
+    }
+}
+
+static void 
+save_fast_dict (char *filename)
+{
+  FILE *fdict;
+
+  fdict = create_file (filename, TEXT_DICT_FAST_SUFFIX, "wb",
+		       MAGIC_FAST_DICT, MG_ABORT);  /* [RPAP - Feb 97: WIN32 Port] */
+
+  {
+    u_long *p;
+    for (p = (u_long *) buffer; (u_long) p < (u_long) cur; ++p)
+      {
+	if (IS_FIXUP (p))
+	  HTONUL(*p);
+      }
+  }
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(mem);
+  HTONUL(fixup_mem);
+
+  fwrite (&mem, sizeof (mem), 1, fdict);
+  fwrite (&fixup_mem, sizeof (fixup_mem), 1, fdict);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(mem);
+  NTOHUL(fixup_mem);
+
+  fwrite (buffer, sizeof (u_char), mem, fdict);
+  fwrite (fixup, sizeof (u_char), fixup_mem, fdict);
+
+  fclose (fdict);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dict.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dict.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dict.1	(revision 10506)
@@ -0,0 +1,79 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.\"------------------------------------------------------------
+.TH mgpp_invf_dict 1 \*(Dt CITRI
+.SH NAME
+mgpp_invf_dict \- build an `on-disk' stemmed dictionary
+.SH SYNOPSIS
+.B mgpp_invf_dict
+[
+.B \-h
+]
+[
+.BI \-b " entries-per-block"
+]
+.if n .ti +13n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgpp_invf_dict
+builds an `on-disk' stemmed dictionary from the
+compressed stemmed dictionary that can be used during querying.
+Each entry in the dictionary contains the disk
+pointer to the associated inverted file entry, and various other pieces
+of information about the stemmed word. The dictionary is blocked with
+each block containing the same number of entries (not the same size).
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectoryyyyyyyy\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " entries-per-block"
+The dictionary is stored in blocks on disk; this option is used to 
+specify the number of entries per block. The default is 16.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mgpp
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+The `on-disk' stemmed dictionary.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.SH "SEE ALSO"
+.na
+.BR mgpp_compression_dict (1),
+.BR mgpp_fast_comp_dict (1),
+.BR mgpp_passes (1),
+.BR mgpp_perf_hash_build (1),
+.BR mgpp_stem_idx (1),
+.BR mgpp_weights_build (1)
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dict.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dict.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dict.cpp	(revision 10506)
@@ -0,0 +1,237 @@
+/**************************************************************************
+ *
+ * mgpp_invf_dict.cpp -- Program to build the blocked stemmed dictionary
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+/* getopt is in posix.2, so cygwin should have it in unistd, but doesn't */
+#if defined (__WIN32__) || defined (__CYGWIN__)
+# include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "sysfuncs.h"
+#include "messages.h"
+#include "mg_files.h"
+#include "invf.h"
+
+static void process_files (char *filename, unsigned long entriesPerBlock) {
+  // open the dictionary
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+  invf_dict_header idh;
+  idh.Read (dictFile);
+
+  // open the inverted index file
+  FILE *invfIdxFile = open_file (filename, INVF_IDX_SUFFIX, "rb",
+				 MAGIC_INVI, MG_ABORT);
+
+  // create the blocked dictionary
+  FILE *blockDictFile = create_file (filename, INVF_DICT_BLOCKED_SUFFIX, "wb",
+				     MAGIC_STEM, MG_ABORT);
+  block_dict_header bdh;
+  bdh.lookback = idh.lookback;
+  bdh.word_dict_start = idh.word_dict_start;
+  bdh.word_dict_size = idh.word_dict_size;
+  bdh.tag_dict_start = idh.tag_dict_start;
+  bdh.tag_dict_size = idh.tag_dict_size;
+  bdh.num_docs = idh.num_docs;
+  bdh.num_frags = idh.num_frags;
+  bdh.num_words = idh.num_words;
+  bdh.total_bytes = idh.total_bytes;
+  bdh.index_string_bytes = idh.index_string_bytes;
+  bdh.num_levels = idh.num_levels;
+  bdh.Write (blockDictFile);
+
+  
+  // write out the word part of the dictionary
+
+  bdh.entries_per_wblk = entriesPerBlock;
+  bdh.max_wblk_size = 0;
+  bdh.wblk_start = ftell (blockDictFile);
+  
+  fseek (dictFile, idh.word_dict_start, SEEK_SET);
+
+  block_idx wordIdx;
+  word_block_dict_el wordBlockEl;
+  wordBlockEl.SetNumLevels (idh.num_levels);
+  
+  
+  unsigned long wordNum;
+  unsigned long wordInvfPtr;
+  UCArray lastEl;
+  word_dict_el wordEl;
+  wordEl.SetNumLevels (idh.num_levels);
+  for (wordNum=0; wordNum<idh.word_dict_size; ++wordNum) {
+    // read in the next word and inverted file pointer
+    wordEl.Read (dictFile, idh.num_levels);
+    ReadUL (invfIdxFile, wordInvfPtr);
+
+    // remember this word (and position) if this is the start
+    // of a new block
+    if (wordNum % entriesPerBlock == 0) {
+      block_idx_info elIdx;
+      elIdx.el = wordEl.el;
+      elIdx.block_ptr = ftell (blockDictFile);
+
+      // see if this block is the longest so far
+      if (wordIdx.size() > 0) {
+	unsigned long blockLen = elIdx.block_ptr -
+	  (*(wordIdx.end()-1)).block_ptr;
+	if (blockLen > bdh.max_wblk_size) bdh.max_wblk_size = blockLen;
+      }
+      
+      wordIdx.push_back (elIdx);
+      lastEl.erase (lastEl.begin(), lastEl.end()); // output full word
+    }
+
+    // copy the information for this word
+    wordBlockEl.el = wordEl.el;
+    wordBlockEl.frag_occur = wordEl.frag_occur;
+    wordBlockEl.freq = wordEl.freq;
+    wordBlockEl.invf_ptr = wordInvfPtr;
+    unsigned long tempI;
+    for (tempI=0; tempI<idh.num_levels; ++tempI)
+      wordBlockEl.levelFreqs[tempI] = wordEl.levelFreqs[tempI];
+
+    // write out the word
+    wordBlockEl.Write (blockDictFile, &lastEl, idh.num_levels);
+
+    lastEl = wordBlockEl.el;
+  }
+
+
+  // write out the tag part of the dictionary
+
+  bdh.entries_per_tblk = entriesPerBlock;
+  bdh.max_tblk_size = 0;
+  bdh.tblk_start = ftell (blockDictFile);
+  
+  fseek (dictFile, idh.tag_dict_start, SEEK_SET);
+
+  block_idx tagIdx;
+  block_dict_el tagBlockEl;
+  
+  unsigned long tagNum;
+  unsigned long tagInvfPtr;
+  dict_el tagEl;
+  lastEl.erase (lastEl.begin(), lastEl.end());
+  for (tagNum=0; tagNum<idh.tag_dict_size; ++tagNum) {
+    // read in the next tag and inverted file pointer
+    tagEl.Read (dictFile);
+    ReadUL (invfIdxFile, tagInvfPtr);
+
+    // remember this tag (and position) if this is the start
+    // of a new block
+    if (tagNum % entriesPerBlock == 0) {
+      block_idx_info elIdx;
+      elIdx.el = tagEl.el;
+      elIdx.block_ptr = ftell (blockDictFile);
+
+      // see if this block is the longest so far
+      if (tagIdx.size() > 0) {
+	unsigned long blockLen = elIdx.block_ptr -
+	  (*(tagIdx.end()-1)).block_ptr;
+	if (blockLen > bdh.max_tblk_size) bdh.max_tblk_size = blockLen;
+      }
+      
+      tagIdx.push_back (elIdx);
+      lastEl.erase (lastEl.begin(), lastEl.end()); // output full word
+    }
+
+    // copy the information for this tag
+    tagBlockEl.el = tagEl.el;
+    tagBlockEl.frag_occur = tagEl.frag_occur;
+    tagBlockEl.freq = tagEl.freq;
+    tagBlockEl.invf_ptr = tagInvfPtr;
+
+    // write out the tag
+    tagBlockEl.Write (blockDictFile, &lastEl);
+
+    lastEl = tagBlockEl.el;
+  }
+
+
+  // write out the element indexes
+  bdh.num_wblks = wordIdx.size();
+  bdh.wblk_idx_start = ftell (blockDictFile);
+  WriteBlockIdx (blockDictFile, wordIdx);
+  
+  bdh.num_tblks = tagIdx.size();
+  bdh.tblk_idx_start = ftell (blockDictFile);
+  WriteBlockIdx (blockDictFile, tagIdx);
+
+  // write out the blocked dictionary header
+  fseek (blockDictFile, sizeof(unsigned long), SEEK_SET);
+  bdh.Write (blockDictFile);
+
+
+  // close open files
+  fclose (blockDictFile);
+  fclose (invfIdxFile);
+  fclose (dictFile);
+  
+  // print out information
+#ifndef SILENT
+  Message ("Max word block size = %d\n", bdh.max_wblk_size);
+  Message ("Max tag block size = %d\n", bdh.max_tblk_size);
+  Message ("Number of word blocks written = %d\n", bdh.num_wblks);
+  Message ("Number of tag blocks written = %d\n", bdh.num_tblks);
+#endif
+}
+
+
+int main (int argc, char **argv) {
+  unsigned long entriesPerBlock = 16;
+  char *filename = "";
+  int ch;
+  msg_prefix = argv[0];
+  opterr = 0;
+
+  while ((ch = getopt (argc, argv, "f:d:b:h")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'b':
+      entriesPerBlock = atoi (optarg);
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-f input_file] "
+	       "[-d data directory] [-b entries-per-block] "
+	       "[-h]\n", argv[0]);
+      exit (1);
+    }
+  }
+
+  process_files (filename, entriesPerBlock);
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dict_dump.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dict_dump.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dict_dump.cpp	(revision 10506)
@@ -0,0 +1,141 @@
+/**************************************************************************
+ *
+ * mgpp_invf_dict_dump.cpp -- Program to printthe various inverted dictionaries
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+/* getopt is in posix.2, so cygwin should have it in unistd, but doesn't */
+#if defined (__WIN32__) || defined (__CYGWIN__)
+# include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "sysfuncs.h"
+#include "messages.h"
+#include "mg_files.h"
+#include "invf.h"
+
+static void process_files (char *filename,
+			   bool printHeader,
+			   bool printWords,
+			   bool printTags) {
+  // open the dictionary
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+  invf_dict_header idh;
+  idh.Read (dictFile);
+
+  // print the information from the inverted dictionary file header
+  if (printHeader) {
+    cout << "lookback: " << idh.lookback << "\n";
+    cout << "word_dict_start: " << idh.word_dict_start << "\n";
+    cout << "word_dict_size: " << idh.word_dict_size << "\n";
+    cout << "tag_dict_start: " << idh.tag_dict_start << "\n";
+    cout << "tag_dict_size: " << idh.tag_dict_size << "\n";
+    cout << "num_docs: " << idh.num_docs << "\n";
+    cout << "num_frags: " << idh.num_frags << "\n";
+    cout << "num_words: " << idh.num_words << "\n";
+    cout << "total_bytes: " << idh.total_bytes << "\n";
+    cout << "index_string_bytes: " << idh.index_string_bytes << "\n";
+    cout << "num_levels: " << idh.num_levels << "\n";
+
+    cout << "\n";
+  }
+
+
+  if (printWords) {
+    fseek (dictFile, idh.word_dict_start, SEEK_SET);
+    
+    unsigned long wordNum;
+    word_dict_el wordEl;
+    wordEl.SetNumLevels (idh.num_levels);
+    for (wordNum=0; wordNum<idh.word_dict_size; ++wordNum) {
+      wordEl.Read (dictFile, idh.num_levels);
+      cout << "\"" << wordEl.el << "\"\n";// (" << wordNum << ")\n";
+    }
+    
+    cout << "\n";
+  }
+
+  // write out the tag part of the dictionary
+  if (printTags) {
+    fseek (dictFile, idh.tag_dict_start, SEEK_SET);
+    
+    unsigned long tagNum;
+    dict_el tagEl;
+    for (tagNum=0; tagNum<idh.tag_dict_size; ++tagNum) {
+      // read in the next tag and inverted file pointer
+      tagEl.Read (dictFile);
+      
+      cout << "\"" << tagEl.el << "\" (" << tagNum << ")\n";
+    }
+  }
+  
+  // close open files
+  fclose (dictFile);
+}
+
+
+int main (int argc, char **argv) {
+  char *filename = "";
+  int ch;
+  msg_prefix = argv[0];
+  opterr = 0;
+
+  bool printHeader = false;
+  bool printWords = false;
+  bool printTags = false;
+
+  while ((ch = getopt (argc, argv, "f:d:rwth")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'r':
+      printHeader = true;
+      break;
+    case 'w':
+      printWords = true;
+      break;
+    case 't':
+      printTags = true;
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-h] [-r] [-w] [-t] [-f input_file] "
+	       "[-d data directory]\n(-rwt:print header, words, tags)\n", 
+	       argv[0]);
+      exit (1);
+    }
+  }
+
+  process_files (filename, printHeader, printWords, printTags);
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dump.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dump.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_invf_dump.cpp	(revision 10506)
@@ -0,0 +1,244 @@
+/**************************************************************************
+ *
+ * mgpp_invf_dump.cpp -- Program to dump uot an inverted fil
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+/* getopt is in posix.2, so cygwin should have it in unistd, but doesn't */
+#if defined (__WIN32__) || defined (__CYGWIN__)
+# include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "sysfuncs.h"
+#include "messages.h"
+#include "bitio_m_stdio.h"
+#include "bitio_gen.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+
+#include "mg_files.h"
+#include "locallib.h"
+#include "words.h"
+#include "invf.h"
+#include "WordData.h"
+
+static void PrintInvfWord (FILE *invfFile,
+			   invf_dict_header &idh,
+			   invf_file_header &ifh,
+			   word_dict_el &wordEl,
+			   unsigned long wordStart,
+			   bool printFrags) {
+  cout << wordEl.frag_occur << " \"" << wordEl.el << "\"\n";
+  
+  if (printFrags) {
+    // seek to the appropriate place in the inverted file
+    fseek (invfFile, wordStart, SEEK_SET);
+    
+    stdio_bitio_buffer buffer(invfFile);
+    
+    unsigned long B = BIO_Bblock_Init (idh.num_frags, wordEl.frag_occur);
+    unsigned long fragNum = 0;
+    unsigned long i;
+    for (i=0; i<wordEl.frag_occur; ++i) {
+      unsigned long delta = buffer.bblock_decode (B, NULL);
+      fragNum += delta;
+      cout << " " << fragNum;
+      
+      if (!ifh.word_level_index ) {
+	unsigned long count = buffer.gamma_decode (NULL);
+	cout << "(" << count << ")";
+      } else {
+	cout << "(1)";
+      }
+    }
+    
+    cout << "\n";
+  
+    buffer.done();
+  }
+}
+
+static void PrintInvfTag (FILE *invfFile,
+			  invf_dict_header &idh,
+			  invf_file_header &/*ifh*/,
+			  dict_el &tagEl,
+			  unsigned long tagStart,
+			  bool printFrags) {
+  cout << tagEl.frag_occur << " \"<" << tagEl.el << ">\"\n";
+  
+  if (printFrags) {
+    // seek to the appropriate place in the inverted file
+    fseek (invfFile, tagStart, SEEK_SET);
+    
+    stdio_bitio_buffer buffer(invfFile);
+    
+    unsigned long pTag = tagEl.frag_occur*2;
+    unsigned long B = BIO_Bblock_Init (idh.num_frags+pTag, pTag);
+    unsigned long fragNum = 0;
+    unsigned long i;
+    for (i=0; i<tagEl.frag_occur; ++i) {
+      unsigned long delta = buffer.bblock_decode (B, NULL)-1;
+      fragNum += delta;
+      cout << " " << fragNum;
+      cout << "-";
+      delta = buffer.bblock_decode (B, NULL)-1;
+      fragNum += delta;
+      cout << fragNum;
+    }
+    
+    cout << "\n";
+    
+    buffer.done();
+  }
+}
+
+static void PrintHeaderInfo (invf_dict_header &idh,
+			     invf_file_header &ifh) {
+  cerr << "Lookback:         " << idh.lookback << "\n";
+  cerr << "Word Dict Size:   " << idh.word_dict_size << "\n";
+  cerr << "Tag Dict Size:    " << idh.tag_dict_size << "\n";
+  cerr << "Num Documents:    " << idh.num_docs << "\n";
+  cerr << "Num Fragments:    " << idh.num_frags << "\n";
+  cerr << "Num Words:        " << idh.num_words << "\n";
+
+  cerr << "Skip Mode:        " << ifh.skip_mode << "\n";
+  cerr << "Word Level Index: " << ifh.word_level_index << "\n";
+
+  cerr << "\n";
+}
+
+
+static void process_files (char *filename,
+			   bool printHeader,
+			   bool printWords,
+			   bool printTags,
+			   bool printFrags) {
+  // open the dictionary
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			MAGIC_STEM_BUILD, MG_ABORT);
+  invf_dict_header idh;
+  idh.Read (dictFile);
+
+  // open the inverted file
+  FILE *invfFile = open_file (filename, INVF_SUFFIX, "rb",
+			MAGIC_INVF, MG_ABORT);
+  
+  invf_file_header ifh;
+  ifh.Read (invfFile);
+
+  if (ifh.skip_mode != SKIP_MODE_NO_SKIPS)
+    FatalError (1, "The invf file contains skips. Unable to dump.");
+
+  // print out header information
+  if (printHeader) {
+    PrintHeaderInfo (idh, ifh);
+  }
+
+  // open the inverted index
+  FILE *invfIdxFile = open_file (filename, INVF_IDX_SUFFIX, "rb",
+				 MAGIC_INVI, MG_ABORT);
+
+  // go to the start of the word dictionary
+  fseek (dictFile, idh.word_dict_start, SEEK_SET);
+
+  // process all the words
+  if (printWords) {
+    unsigned long wordNum;
+    unsigned long wordStart;
+    word_dict_el wordEl;
+    wordEl.SetNumLevels (idh.num_levels);
+    for (wordNum=0; wordNum<idh.word_dict_size; ++wordNum) {
+      wordEl.Read (dictFile, idh.num_levels);
+      ReadUL (invfIdxFile, wordStart);
+      PrintInvfWord (invfFile, idh, ifh, wordEl, wordStart, printFrags);
+    }
+  }
+
+  // process all the tags
+  if (printTags) {
+    unsigned long tagNum;
+    unsigned long tagStart;
+    dict_el tagEl;
+    for (tagNum=0; tagNum<idh.tag_dict_size; ++tagNum) {
+      tagEl.Read (dictFile);
+      ReadUL (invfIdxFile, tagStart);
+      PrintInvfTag (invfFile, idh, ifh, tagEl, tagStart, printFrags);
+    }
+  }
+  // close the open files
+  fclose (invfIdxFile);
+  fclose (invfFile);
+  fclose (dictFile);
+}
+
+
+int main (int argc, char **argv) {
+  char *dir_name, *filename = "";
+  int ch;
+  msg_prefix = argv[0];
+  dir_name = getenv ("MGDATA");
+  opterr = 0;
+
+  bool printHeader = false;
+  bool printWords = false;
+  bool printTags = false;
+  bool printFrags = false;
+  
+  msg_prefix = argv[0];
+  while ((ch = getopt (argc, argv, "hrwtnf:d:")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath(optarg);
+      break;
+    case 'r':
+      printHeader = true;
+      break;
+    case 'w':
+      printWords = true;
+      break;
+    case 'n':
+      printFrags = true;
+      break;
+    case 't':
+      printTags = true;
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-h] [-r] [-w] [-t] [-n] [-f input_file]"
+	       "[-d data directory]\n(-rwnt:print header, words, tags, fragnums)\n", 
+	       argv[0]);
+      exit (1);
+    }
+  }
+  
+  process_files (filename, printHeader, printWords, printTags, printFrags);
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_passes.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_passes.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_passes.1	(revision 10506)
@@ -0,0 +1,323 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.\"------------------------------------------------------------
+.TH mgpp_passes 1 \*(Dt CITRI
+.SH NAME
+mgpp_passes \- builds mgpp databases
+.SH SYNOPSIS
+.B mgpp_passes
+[
+.BI \-J " doc-tag"
+]
+[
+.BI \-K " level-tag"
+]
+.if n .ti +10n
+[
+.BI \-L " index-level"
+]
+[
+.BI \-m " invf-mem-buffer"
+]
+.if n .ti +10n
+[
+.B \-T1
+]
+[
+.B \-T2
+]
+[
+.B \-I1
+]
+[
+.B \-I2
+]
+[
+.B \-S
+]
+[
+.B \-C
+]
+.if n .ti +10n
+[
+.B \-h
+]
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+[
+.I filename(s)
+]
+.SH DESCRIPTION
+.B mgpp_passes
+is the program that does most of the work when building mgpp
+database systems.  The input documents can come from either
+.I stdin
+or from a list of files on the command line.  In general,
+.B mgpp_passes
+must be run twice to build a database, first with the
+.B \-T1
+and
+.B \-I1
+options, and second with the
+.B \-T2
+and
+.B \-I2
+options.  Several other programs must be run in order to get an
+mgpp database.  The
+.SB EXAMPLE
+section below gives an example of how to build a complete
+mgpp database.
+.SH OPTIONS
+Options may appear in any order, but the
+.IR filename(s) ,
+if specified, must be last.
+.TP "\w'\fB\-C\fP \fIcompstatpointt\fP'u+2n"
+.BI \-J " doc-tag"
+Specifies the SGML tag that encloses each document.  Text appearing
+outside this tag is ignored.  The document tag defines the highest
+level document that can be queried and printed.  The default document
+tag is 'Document'.
+.TP
+.BI \-K " level-tag"
+Specifies the SGML tag of a sub document level.  A level tag must
+enclose all text enclosed by the document tag.  Levels can be
+queried and printed as if they were separate documents.  Multiple
+document levels can be specified (the document tag is always
+added as a document level).
+.TP
+.BI \-L " index-level"
+Specifies the SGML tag enclosing the smallest indexed element.  The
+index level should be no larger than the smallest document 
+level.  An empty string can be used to specify a word level index 
+(which is the default).
+.TP
+.BI \-m " invf-mem-buffer"
+Maximum amount of memory to use for the pass-2 file inversion in
+megabytes.  This option is only useful when used in conjunction with
+the option
+.BR \-I1 .
+The larger this value, the faster the pass-2 inversion will proceed.
+The default value is 5 MB.
+.TP
+.B \-T1
+Generate the
+.I *.text.stats
+file.
+.TP
+.B \-T2
+Generate the
+.IR *.text ,
+.IR *.text.idx ,
+.IR *.text.level ,
+and possibly the
+.I *.text.dict.aux
+files.  Using this option requires that the
+.I *.text.dict
+file be present.
+.TP
+.B \-I1
+Generate the
+.IR *.invf.dict ,
+.IR *.invf.level ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files.
+.TP
+.B \-I2
+Generate the
+.I *.invf
+and
+.I *.invf.idx
+files.  Using this option requires
+that the
+.IR *.invf.dict.hash ,
+.IR *.invf.level ,
+.IR *.invf.chunk ,
+and
+.I *.invf.chunk.trans
+files be present.  The
+.I *.invf.dict.hash
+file is generated by
+.BR mgpp_perf_hash_build (1)
+from the
+.I *.invf.dict
+file.
+.TP
+.B \-S
+This option causes a special pass to be executed.  It is up to a user
+to modify
+.I mg.special.c
+in the source code to do something with the documents it is given.
+.TP 
+.B \-C
+This activates the compatibility parsing mode.  When using this
+mode documents are separated by control-B and paragraphs are separated
+by control-C.  Internally these are converted to documents surrounded
+by 'Document' tags and paragraphs surrounded by 'Paragraph' tags.
+.TP
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is to be
+written.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection that will be
+created.
+.TP
+.I filename(s)
+This specifies the source text. If this is not specified, then the
+program expects the source text from
+.IR stdin .
+.SH EXAMPLE
+What follows is a UNIX
+.BR csh (1)
+script as an example of how to build an mgpp document collection.
+.LP
+.nf
+.DT
+.ft B
+.I #! /bin/csh
+.I
+# The first argument on the command line specifies the
+.I
+#   source of the text
+set source = ($1)
+.PP
+.I
+# The second argument is the name of the collection
+set text = ($2)
+.PP
+.I
+# Create *.text.stats, *.invf.dict, *.invf.level
+.I
+#   *.invf.chunk and *.invf.chunks.trans
+${source} | mgpp_passes -T1 -I1 -f ${text}
+.PP
+.I
+# Create *.text.dict
+mgpp_compression_dict -f ${text}
+.PP
+.I
+# Create *.invf.dict.hash
+mgpp_perf_hash_build -f ${text}
+.PP
+.I
+# Create *.text, *.text.idx, *.text.level
+.I
+#   *.invf and *.invf.idx
+${source} | mgpp_passes -T2 -I2 -f ${text}
+.PP
+.I
+# Create *.text.weight and *.weight.approx
+mgpp_weights_build -f ${text}
+.PP
+.I
+# Create *.invf.dict.blocked
+mgpp_invf_dict -f ${text}
+.PP
+.I
+# Create *.invf.dict.blocked.1
+mgpp_stem_idx -s 1 -f ${text}
+.PP
+.I
+# Create *.invf.dict.blocked.2
+mgpp_stem_idx -s 2 -f ${text}
+.PP
+.I
+# Create *.invf.dict.blocked.3
+mgpp_stem_idx -s 3 -f ${text}
+.PP
+.I
+# Create *.text.dict.fast
+mgpp_fast_comp_dict -f ${text}
+.ft R
+.fi
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mgpp
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 22
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.chunk
+Inverted file chunk descriptor file.  When the inverted file is
+created it is created in chunks that use no more than a set amount of
+memory.  This file describes those chunks.
+.TP
+.B *.invf.chunk.trans
+Word-occurrence-order to lexical-order translation file.  The
+.B *.invf.chunk
+file is written in word-occurrence order but is required by
+.B \-I2
+to be in lexical order.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked
+Compressed stemmed dictionary with index into the dictionary.
+.TP
+.B *.invf.dict.blocked.n
+Transformation dictionary from words stemmed with method 
+.B n
+to unstemmed words.
+.TP
+.B *.invf.dict.hash
+Data for an order-preserving perfect hash function.
+.TP
+.B *.invf.idx
+The index into the inverted file.
+.TP
+.B *.invf.level
+Information about the document levels needed for querying.
+.TP
+.B *.text
+Compressed text.
+.TP
+.B *.text.dict
+Compressed compression dictionary.
+.TP
+.B *.text.dict.fast
+A fast loading version of the compressed compression dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.text.level
+Information about the document levels needed for text decompression.
+.TP
+.B *.text.stats
+Statistics about the text.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.weight.approx
+The approximate weights file.
+.SH "SEE ALSO"
+.na
+.BR mgpp_compression_dict (1),
+.BR mgpp_fast_comp_dict (1),
+.BR mgpp_invf_dict (1),
+.BR mgpp_perf_hash_build (1),
+.BR mgpp_stem_idx (1),
+.BR mgpp_weights_build (1)
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_passes.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_passes.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_passes.cpp	(revision 10506)
@@ -0,0 +1,268 @@
+/**************************************************************************
+ *
+ * mgpp_passes.cpp -- Driver for the various passes
+ * Copyright (C) 1994  Neil Sharman
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+#pragma warning(disable:4786)
+#endif
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+#include "sysfuncs.h"
+
+#ifdef HAVE_MALLINFO
+# include <malloc.h> 
+#endif
+
+#if defined __WIN32__
+# include <io.h>
+# include "getopt_old.h"
+# define close _close
+# define open _open
+#elif defined __CYGWIN__
+#include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "memlib.h"
+#include "messages.h"
+#include "longlong.h"
+#include "mg_files.h"
+#include "mg.h"
+#include "build.h"
+#include "text.h"
+#include "stemmer.h"
+#include "FileBuf.h"
+#include "TextEl.h"
+#include "TagInfo.h"
+
+#define MAX_PASSES 5
+
+#define SPECIAL 1
+#define TEXT_PASS_1 2
+#define TEXT_PASS_2 4
+#define IVF_PASS_1 8
+#define IVF_PASS_2 16
+
+#define MIN_BUF 8192
+
+
+unsigned long invf_buffer_size = 5 * 1024 * 1024;	/* 5Mb */
+
+static char Passes = 0;
+static char **files = NULL;
+static int num_files = 0;
+
+
+struct pass_data {
+  char *name;
+  int (*init) (const TagInfo &tagInfo, char *);
+  int (*process) (const TagInfo &tagInfo, const TextElArray &doc);
+  int (*done) (const TagInfo &tagInfo, char *);
+};
+
+
+static pass_data PassData[MAX_PASSES] = {
+  {"special", init_special, process_special, done_special},
+  {"text.pass1", init_text_1, process_text_1, done_text_1},
+  {"text.pass2", init_text_2, process_text_2, done_text_2},
+  {"ivf.pass1", init_ivf_1, process_ivf_1, done_ivf_1},
+  {"ivf.pass2", init_ivf_2, process_ivf_2, done_ivf_2},
+};
+
+static char *usage_str = "\nUSAGE:\n"
+"  %s [-J doc-tag] [-K level-tag] [-L index-level]\n"
+"  %*s [-m invf-memory] [-T1] [-T2] [-I1] [-I2] [-S]\n"
+"  %*s [-C] [-h] [-d directory] -f name\n\n";
+
+
+
+static void Usage (char *err) {
+  if (err) Message (err);
+  fprintf (stderr, usage_str, msg_prefix, strlen (msg_prefix), "",
+	   strlen (msg_prefix), "");
+  exit (1);
+}
+
+
+
+
+int OpenNextFile (int in_fd) {
+  if (in_fd > 0) close (in_fd);
+  if (num_files == 0) return (-1);
+  if ((in_fd = open (files[0], O_RDONLY)) == -1)
+    FatalError (1, "Cannot open %s", files[0]);
+  ++files;
+  --num_files;
+  return (in_fd);
+}
+
+
+static void Driver (int in_fd, char *file_name,
+		    const TagInfo &tagInfo, bool compatMode) {
+  //  cout << tagInfo;
+
+  int pass;
+
+  unsigned long numBytes = 0;
+  unsigned long numDocs = 0;
+
+  // initialise all the passes
+  for (pass = 0; pass < MAX_PASSES; ++pass) {
+    if (Passes & (1 << pass)) {
+      if (PassData[pass].init (tagInfo, file_name) == COMPERROR)
+	FatalError (1, "Error during init of \"%s\"", PassData[pass].name);
+    }
+  }
+
+  
+  // set up various variables
+  FileBuf buf;
+  TextElArray doc;
+  unsigned long docLen = 0;
+
+  // read and process each file (start with an open file)
+  do {
+    
+    // read and process each document in this file
+    buf.SetFD (in_fd);
+    while (ReadDoc (buf, tagInfo.docTag, doc, docLen, compatMode)) {
+
+      // give this document to each pass
+      for (pass = 0; pass < MAX_PASSES; ++pass) {
+	if (Passes & (1 << pass)) {
+	  if (PassData[pass].process (tagInfo, doc) == COMPERROR)
+	    FatalError(1,"Error during processing of \"%s\"",PassData[pass].name);
+	}
+      }
+      
+      // another document has been processed
+      numBytes += docLen;
+      ++numDocs;
+    }
+    
+  } while ((in_fd = OpenNextFile (in_fd)) > 0);
+
+  
+  // do done for each pass
+  for (pass = 0; pass < MAX_PASSES; ++pass) {
+    if (Passes & (1 << pass)) {
+      if (PassData[pass].done (tagInfo, file_name) == COMPERROR)
+	FatalError (1, "Error during done of \"%s\"", PassData[pass].name);
+    }
+  }
+}
+
+int main (int argc, char **argv) {
+  int ch, in_fd;
+  char *filename = NULL;
+  bool compatMode = false;
+  TagInfo tagInfo;
+  tagInfo.SetDocTag ("Document");
+  
+  msg_prefix = argv[0];
+
+  opterr = 0;
+  while ((ch=getopt(argc, argv, "J:K:L:f:d:m:I:T:SCh"))!=-1){
+    switch (ch) {
+    case 'J':
+      tagInfo.SetDocTag (optarg);
+      break;
+    case 'K':
+      tagInfo.AddLevelTag (optarg);
+      break;
+    case 'L':
+      tagInfo.SetIndexLevel (optarg);
+      break;
+    case 'f':
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'm':
+      invf_buffer_size = (int) (atof (optarg) * 1024 * 1024);
+      break;
+    case 'I':
+      if (*optarg == '1')
+	Passes |= IVF_PASS_1;
+      else if (*optarg == '2')
+	Passes |= IVF_PASS_2;
+      else
+	Usage ("Invalid pass number");
+      break;
+    case 'T':
+      if (*optarg == '1')
+	Passes |= TEXT_PASS_1;
+      else if (*optarg == '2')
+	Passes |= TEXT_PASS_2;
+      else
+	Usage ("Invalid pass number");
+      break;
+    case 'S':
+      Passes |= SPECIAL;
+      break;
+    case 'C':
+      compatMode = true;
+      break;
+    case 'h':
+    case '?':
+      Usage (NULL);
+    }
+  }
+
+  if (!filename || *filename == '\0')
+    FatalError (1, "A document collection name must be specified.");
+
+  if ((Passes & (IVF_PASS_1 | IVF_PASS_2)) == (IVF_PASS_1 | IVF_PASS_2))
+    FatalError (1, "I1 and I2 cannot be done simultaneously.");
+
+  if ((Passes & (TEXT_PASS_1 | TEXT_PASS_2)) == (TEXT_PASS_1 | TEXT_PASS_2))
+    FatalError (1, "T1 and T2 cannot be done simultaneously.");
+
+  if (!Passes)
+    FatalError (1, "S, T1, T2, I1 or I2 must be specified.");
+
+  if (optind < argc) {
+    if ((in_fd = open (argv[optind], O_RDONLY)) == -1)
+      FatalError (1, "Cannot open %s", argv[optind]);
+    files = &argv[optind + 1];
+    num_files = argc - (optind + 1);
+    
+  } else in_fd = 0;  // stdin
+
+  
+  if (compatMode) tagInfo.SetDocTag ("Document");
+
+  // a document tag is also a level tag
+  tagInfo.levelTags.insert (tagInfo.docTag); 
+  
+  Driver (in_fd, filename, tagInfo, compatMode);
+
+  return (0);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_perf_hash_build.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_perf_hash_build.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_perf_hash_build.1	(revision 10506)
@@ -0,0 +1,72 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.\"------------------------------------------------------------
+.TH mgpp_perf_hash_build 1 \*(Dt CITRI
+.SH NAME
+mgpp_perf_hash_build \- generate an order-preserving hash function for the stemmed dictionary
+.SH SYNOPSIS
+.B mgpp_perf_hash_build
+[
+.B \-h
+]
+[
+.BI \-r " rndseed"
+]
+[
+.BI \-d  " directory"
+]
+.if n .ti +9n
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgpp_perf_hash_build
+generates an order-preserving hashing function from the compressed
+stemmed dictionary and writes it out to disk.
+.BR mgpp_passes (1)
+will make use of the hash function when it builds the inverted file.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-r " rndseed"
+This specifies the random seed to be used in the generation of the
+hash function; it must be an integer.  If this is not specified, the
+current time will be used as the random seed.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mg
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf.dict
+Stemmed dictionary.
+.TP
+.B *.invf.dict.hash
+Data for a order-preserving perfect hash function.
+.SH "SEE ALSO"
+.na
+.BR mgpp_compression_dict (1),
+.BR mgpp_fast_comp_dict (1),
+.BR mgpp_invf_dict (1),
+.BR mgpp_passes (1),
+.BR mgpp_stem_idx (1),
+.BR mgpp_weights_build (1)
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_perf_hash_build.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_perf_hash_build.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_perf_hash_build.cpp	(revision 10506)
@@ -0,0 +1,146 @@
+/**************************************************************************
+ *
+ * mgpp_perf_hash_build.cpp -- Program to build a perfect hash function
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+/* getopt is in posix.2, so cygwin should have it in unistd, but doesn't */
+#if defined (__WIN32__) || defined (__CYGWIN__)
+# include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "perf_hash.h"
+#include "netorder.h"
+
+#include "mg_files.h"
+#include "invf.h"
+#include "locallib.h"
+#include "words.h"
+#include "mg.h"
+
+#define POOL_SIZE 1024*1024
+
+static void ProcessFiles (char *filename, int r) {
+  FILE *dictFile, *hashFile;
+  unsigned long i;
+  invf_dict_header idh;
+  perf_hash_data *phd;
+  u_char *pool;
+  unsigned long pool_left;
+  u_char **starts;
+
+  // read in the dictionary
+  dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			MAGIC_STEM_BUILD, MG_ABORT);
+  if (dictFile==NULL) {
+    FatalError(1, "unable to open file");
+  }
+  idh.Read (dictFile);
+
+  //cerr << idh.lookback<<" "<<idh.word_dict_start<<endl;
+  // go to the start of the word dictionary
+  fseek (dictFile, idh.word_dict_start, SEEK_SET);
+  
+  if (!(pool = (u_char *) Xmalloc (POOL_SIZE)))
+    FatalError (1, "Out of memory");
+  pool_left = POOL_SIZE;
+
+  if (!(starts = (u_char **) Xmalloc (sizeof (u_char *) * idh.word_dict_size)))
+    FatalError (1, "Out of memory");
+  //cerr << "size= "<< idh.word_dict_size<<endl;
+  word_dict_el wordEl;
+  wordEl.SetNumLevels (idh.num_levels);
+  for (i = 0; i < idh.word_dict_size; ++i) {
+    // read the next word and associated information
+    wordEl.Read (dictFile, idh.num_levels);
+
+    // push string onto pool data
+    register unsigned long l;
+    l = wordEl.el.size() + 1;
+    if (pool_left < l) {
+      pool = (u_char *) Xmalloc (POOL_SIZE);
+      pool_left = POOL_SIZE;
+    }
+    starts[i] = pool;
+    
+    *pool++ = wordEl.el.size();
+    memcpy ((char *) pool, &(wordEl.el[0]), wordEl.el.size());
+    //cerr << pool<<"   " <<starts[i]<<endl;
+    pool += wordEl.el.size();
+    pool_left -= l;
+    
+  }
+  fclose (dictFile);
+  //cerr << pool<<"   " <<starts[i-1]<<endl;
+  //cerr<<"starts  "<<starts[113529]<<endl;
+  //cerr << starts[17][1] << " "<<starts[25][4]<<endl;
+  // create perfect hash file
+  hashFile = create_file (filename, INVF_DICT_HASH_SUFFIX, "wb",
+			  MAGIC_HASH, MG_ABORT);
+  if (!(phd = gen_hash_func (idh.word_dict_size, starts, r)))
+    FatalError (1, "Unable to generate hash function");
+  if (write_perf_hash_data (hashFile, phd) == -1)
+    FatalError (1, "Unable to write hash function");
+  fclose (hashFile);
+}
+
+
+
+int main (int argc, char **argv) {
+  int r = -1;
+  char *filename = "";
+  int ch;
+  msg_prefix = argv[0];
+  opterr = 0;
+
+  while ((ch = getopt (argc, argv, "f:d:r:h")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'r':
+      r = atoi (optarg);
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-f input_file]"
+	       "[-d data directory] [-r random seed] [-h]\n", argv[0]);
+      exit (1);
+    }
+  }
+
+  ProcessFiles (filename, r);
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_stem_idx.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_stem_idx.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_stem_idx.1	(revision 10506)
@@ -0,0 +1,95 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.\"------------------------------------------------------------
+.TH mgpp_stem_idx 1 \*(Dt CITRI
+.SH NAME
+mgpp_stem_idx \- builds a stem index file
+.SH SYNOPSIS
+.B mgpp_stem_idx
+[
+.B \-h
+]
+[
+.BI \-b " entries-per-block"
+]
+.if n .ti +12n
+[
+.BI \-a " stemmer"
+]
+[
+.BI \-d " directory"
+]
+.if n .ti +12n
+.B \-s 1|2|3
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgpp_stem_idx
+generates a stem index file for a collection.
+This program should be called three times: once for each
+.B -s
+parameter.  It uses the stemmed dictionary to create the stem index which
+contains pointers into the stemmed dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIdirectoryyyyyyyy\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " entries-per-block"
+The dictionary is stored in blocks on disk; this option is used to set
+the number of entries per block. The default is 16.
+.TP
+.BI \-a " stemmer"
+The name of the stemmer to use, the default is the Lovin stemmer.
+.TP
+.B -s 1|2|3
+The stem method to apply for the stem index.
+.br
+1 = casefolded and non-stemmed
+.br
+2 = non-casefolded and stemmed
+.br
+3 = casefolded and stemmed
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection can be found.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mgpp
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 22
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.invf.dict.blocked.1
+Stem index with stem index method 1.
+.TP
+.B *.invf.dict.blocked.2
+Stem index with stem index method 2.
+.TP
+.B *.invf.dict.blocked.3
+Stem index with stem index method 3.
+.SH "SEE ALSO"
+.na
+.BR mgpp_compression_dict (1),
+.BR mgpp_fast_comp_dict (1),
+.BR mgpp_invf_dict (1),
+.BR mgpp_passes (1),
+.BR mgpp_perf_hash_build (1),
+.BR mgpp_weights_build (1)
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_stem_idx.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_stem_idx.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_stem_idx.cpp	(revision 10506)
@@ -0,0 +1,237 @@
+/**************************************************************************
+ *
+ * mgpp_stem_idx.cpp -- stem index builder
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+/* getopt is in posix.2, so cygwin should have it in unistd, but doesn't */
+#if defined (__WIN32__) || defined (__CYGWIN__)
+# include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "UCArray.h"
+#include "sysfuncs.h"
+#include "messages.h"
+#include "mg_files.h"
+#include "invf.h"
+#include "words.h"
+#include "stemmer.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#  include <ospace\std\vector>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#  include <vector.h>
+#else
+#  include <map>
+#  include <vector>
+#endif
+
+typedef vector<unsigned long> WordNumList;
+typedef map<UCArray, WordNumList, DictLTUCArray> StemMapDict;
+
+void CreateStemDict (char *filename,
+		     StemMapDict &stemDict,
+		     int stemMethod,
+		     int stemmerNum) {
+  stemDict.erase (stemDict.begin(), stemDict.end());
+
+  // open the dictionary
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+  invf_dict_header idh;
+  idh.Read (dictFile);
+
+  fseek (dictFile, idh.word_dict_start, SEEK_SET);
+
+  unsigned long wordNum;
+  u_char mgWord[MAXSTEMLEN + 1];
+  word_dict_el wordEl;
+  UCArray stemEl;
+  wordEl.SetNumLevels (idh.num_levels);
+  for (wordNum=0; wordNum<idh.word_dict_size; ++wordNum) {
+    // read in the next word
+    wordEl.Read (dictFile, idh.num_levels);
+
+    // convert the word to an "mg word"
+    mgWord[0] = wordEl.el.size();
+    memcpy((char *)&mgWord[1], &(wordEl.el[0]), wordEl.el.size());
+
+    // stem the word
+    stemmer (stemMethod, stemmerNum, mgWord);
+
+    // convert the result back to a UCArray
+    stemEl.erase (stemEl.begin(), stemEl.end());
+    stemEl.insert (stemEl.end(), &mgWord[1], &mgWord[1] + mgWord[0]);
+
+//      cout << "\"" << stemEl << "\" -> \"" << wordEl.el << "\"\n";
+    
+    // add this word number to the list of word numbers for this word
+    stemDict[stemEl].push_back (wordNum);
+  }
+
+  fclose (dictFile);
+}
+
+
+void WriteStemDict (char *filename,
+		    StemMapDict &stemDict,
+		    int stemMethod,
+		    int stemmerNum,
+		    unsigned long entriesPerBlock) {
+  // Create appropriate stem index file
+  FILE *stemDictFile = NULL;
+  if (stemMethod == 1) {
+    stemDictFile = create_file (filename, INVF_DICT_BLOCKED_1_SUFFIX,
+				"wb", MAGIC_STEM_1, MG_ABORT);
+  } else if (stemMethod == 2) {
+    stemDictFile = create_file (filename, INVF_DICT_BLOCKED_2_SUFFIX,
+				"wb", MAGIC_STEM_2, MG_ABORT);
+  } else if (stemMethod == 3) {
+    stemDictFile = create_file (filename, INVF_DICT_BLOCKED_3_SUFFIX,
+				"wb", MAGIC_STEM_3, MG_ABORT);
+  } else {
+    FatalError (1, "Unknown stem method %d", stemMethod);
+  }
+
+  stem_idx_header sih;
+  sih.lookback = 0;
+  sih.dict_size = stemDict.size();
+  sih.entries_per_block = entriesPerBlock;
+  sih.max_block_size = 0;
+  
+  sih.stemmer_num = stemmerNum;
+  sih.stem_method = stemMethod;
+
+  // write out a place-holder version of the header
+  sih.Write (stemDictFile);
+
+  sih.blocks_start = ftell (stemDictFile);
+
+  block_idx stemIdx;
+  unsigned long stemNum = 0;
+  stem_block_dict_el stemEl;
+  UCArray lastEl;
+
+  StemMapDict::const_iterator here = stemDict.begin();
+  StemMapDict::const_iterator end = stemDict.end();
+  while (here != end) {
+    // remember this stem (and position) if this is the start
+    // of a new block
+    if (stemNum % entriesPerBlock == 0) {
+      block_idx_info elIdx;
+      elIdx.el = (*here).first;
+      elIdx.block_ptr = ftell (stemDictFile);
+
+      // see if this block is the longest so far
+      if (stemIdx.size() > 0) {
+	unsigned long blockLen = elIdx.block_ptr -
+	  (*(stemIdx.end()-1)).block_ptr;
+	if (blockLen > sih.max_block_size) sih.max_block_size = blockLen;
+      }
+      
+      stemIdx.push_back (elIdx);
+      lastEl.erase (lastEl.begin(), lastEl.end()); // output full word
+    }
+
+    // copy the information for this stem
+    stemEl.el = (*here).first;
+    stemEl.equivWords = (*here).second;
+
+    // write out the stem
+    stemEl.Write (stemDictFile, &lastEl);
+    
+    ++here; ++stemNum;
+  }
+
+
+  // write out the element indexes
+  sih.num_blocks = stemIdx.size();
+  sih.block_idx_start = ftell (stemDictFile);
+  WriteBlockIdx (stemDictFile, stemIdx);
+  
+  // write out the stem dictionary header
+  fseek (stemDictFile, sizeof(unsigned long), SEEK_SET);
+  sih.Write (stemDictFile);
+
+
+  // close open files
+  fclose (stemDictFile);
+  
+  // print out information
+#ifndef SILENT
+  Message ("Num word stems = %d\n", sih.dict_size);
+  Message ("Max stem block size = %d\n", sih.max_block_size);
+  Message ("Number of stem blocks written = %d\n", sih.num_blocks);
+#endif
+}
+
+
+int main (int argc, char **argv) {
+  unsigned long entriesPerBlock = 16;
+  char *filename = "";
+  int ch;
+  int stemMethod = 0; // illegal value (no translation)
+  int stemmerNum = 0; // English stemmer
+  msg_prefix = argv[0];
+  opterr = 0;
+
+  while ((ch = getopt (argc, argv, "f:d:b:s:h")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'b':
+      entriesPerBlock = atoi (optarg);
+      break;
+    case 's':
+      stemMethod = atoi (optarg);
+      break;
+    case 'a':
+      stemmerNum = stemmernumber ((unsigned char *) optarg);
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-d directory] "
+	       "[-b entries-per-block] [-h] -s 1|2|3 "
+	       "[-a stemmer-method] -f name\n", argv[0]);
+      exit (1);
+    }
+  }
+  
+  if (stemMethod < 1 || stemMethod > 3)
+    FatalError (1, "Stem method must be 1, 2 or 3");
+
+  // read in the dictionary and create the in memory dictionary
+  StemMapDict stemDict;
+  CreateStemDict (filename, stemDict, stemMethod, stemmerNum);
+  
+  // write out the dictionary as a blocked file
+  WriteStemDict (filename, stemDict, stemMethod, stemmerNum, entriesPerBlock);
+  
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_weights_build.1
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_weights_build.1	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_weights_build.1	(revision 10506)
@@ -0,0 +1,79 @@
+.\"------------------------------------------------------------
+.\" Id - set Rv,revision, and Dt, Date using rcs-Id tag.
+.de Id
+.ds Rv \\$3
+.ds Dt \\$4
+..
+.\"------------------------------------------------------------
+.TH mgpp_weights_build 1 \*(Dt CITRI
+.SH NAME
+mgpp_weights_build \- builds the approximate weights file
+.SH SYNOPSIS
+.B mgpp_weights_build
+[
+.B \-h
+]
+[
+.BI \-b " num-bits"
+]
+.if n .ti +17n
+[
+.BI \-d " directory"
+]
+.BI \-f " name"
+.SH DESCRIPTION
+.B mgpp_weights_build
+is the program that generates the exact and approximate weights 
+files.  To do this, it uses the inverted file
+and dictionary.
+.SH OPTIONS
+Options may appear in any order.
+.TP "\w'\fB\-d\fP \fIirectory\fP'u+2n"
+.B \-h
+This displays a usage line on
+.IR stderr .
+.TP
+.BI \-b " num-bits"
+This specifies the number of bits of precision that should be used for
+the approximate weights.  If not specified, it defaults to 8.
+.TP
+.BI \-d " directory"
+This specifies the directory where the document collection is.
+.TP
+.BI \-f " name"
+This specifies the base name of the document collection.
+.SH ENVIRONMENT
+.TP "\w'\fBMGDATA\fP'u+2n"
+.SB MGDATA
+If this environment variable exists, then its value is used as the
+default directory where the mgpp
+collection files are.  If this variable does not exist, then the
+directory \*(lq\fB.\fP\*(rq is used by default.  The command line
+option
+.BI \-d " directory"
+overrides the directory in
+.BR MGDATA .
+.SH FILES
+.TP 20
+.B *.invf
+Inverted file.
+.TP
+.B *.invf.dict
+Compressed stemmed dictionary.
+.TP
+.B *.text.idx
+Index into the compressed documents.
+.TP
+.B *.weight
+The exact weights file.
+.TP
+.B *.weight.approx
+Approximate document weights.
+.SH "SEE ALSO"
+.na
+.BR mgpp_compression_dict (1),
+.BR mgpp_fast_comp_dict (1),
+.BR mgpp_invf_dict (1),
+.BR mgpp_passes (1),
+.BR mgpp_perf_hash_build (1),
+.BR mgpp_stem_idx (1)
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_weights_build.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_weights_build.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/mgpp_weights_build.cpp	(revision 10506)
@@ -0,0 +1,399 @@
+/**************************************************************************
+ *
+ * mgpp_weights_build.cpp -- Program to build the document weights file
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+/* getopt is in posix.2, so cygwin should have it in unistd, but doesn't */
+#if defined (__WIN32__) || defined (__CYGWIN__)
+# include "getopt_old.h"
+#else
+# include <unistd.h>
+#endif
+
+#include "UCArray.h"
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_gen.h"
+#include "bitio_m_stdio.h"
+#include "mg_files.h"
+#include "locallib.h"
+#include "invf.h"
+#include "FIvfLevelInfo.h"
+#include "FragLevelConvert.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+#define MAXBITS (sizeof(unsigned long) * 8)
+
+struct WBTagPtr {
+  unsigned long tagNum;
+  unsigned long tagPtr;
+  unsigned long fragOccur;
+  
+  WBTagPtr () {
+    tagNum = 0;
+    tagPtr = 0;
+    fragOccur = 0;
+  }
+};
+
+// maps tags to tag information
+typedef map<UCArray, WBTagPtr, DictLTUCArray> WBTagDict;
+
+typedef vector<float> Weights;
+
+
+static void ReadTagDict (const invf_dict_header &idh,
+			 FILE *dictFile,
+			 FILE *invfIdxFile,
+			 WBTagDict &tagDict) {
+  tagDict.erase (tagDict.begin(), tagDict.end());
+
+  // seek to the start of the tag information
+  fseek (dictFile, idh.tag_dict_start, SEEK_SET);
+  fseek (invfIdxFile, sizeof(unsigned long) +
+	 idh.word_dict_size*sizeof(unsigned long), SEEK_SET);
+  
+  unsigned long tagNum;
+  unsigned long tagPtr;
+  dict_el thisEl;
+  for (tagNum = 0; tagNum < idh.tag_dict_size; ++tagNum) {
+    thisEl.Read (dictFile);
+    ReadUL (invfIdxFile, tagPtr);
+    tagDict[thisEl.el].tagNum = tagNum;
+    tagDict[thisEl.el].tagPtr = tagPtr;
+    tagDict[thisEl.el].fragOccur = thisEl.frag_occur;
+  }
+}
+
+static void AddWeight (Weights &w,
+		       unsigned long levelDocNum,
+		       unsigned long termFreq,
+		       float idf) {
+  double weight = termFreq * idf;
+  w[levelDocNum-1] += weight * weight;
+}
+
+static void GenerateLevelWeights (const invf_dict_header &idh,
+				  const invf_file_header &ifh,
+				  unsigned long numLevelDocs,
+				  unsigned long levelNum,
+				  FILE *dictFile,
+				  FILE *invfFile,
+				  FILE *invfIdxFile,
+				  const FragLevelConvert &fragLevelConvert,
+				  Weights &w) {
+  // pre-allocate the right number of weights
+  w.erase (w.begin(), w.end());
+  w.insert (w.end(), (Weights::size_type)numLevelDocs, (float)0.0);
+
+  double logN = log ((double) numLevelDocs);
+
+  // reset the files
+  fseek (dictFile, idh.word_dict_start, SEEK_SET);
+  fseek (invfIdxFile, sizeof (unsigned long), SEEK_SET);
+  
+  // process each word adding its contributions to the document weights
+  unsigned long wordNum;
+  unsigned long wordStart;
+  word_dict_el wordEl;
+  wordEl.SetNumLevels (idh.num_levels);
+  for (wordNum=0; wordNum<idh.word_dict_size; ++wordNum) {
+#ifndef SILENT
+    // give a little feedback every 4096 words
+    if ((wordNum & 0xfff) == 0) fprintf (stderr, ".");
+#endif
+    
+    wordEl.Read (dictFile, idh.num_levels);
+    ReadUL (invfIdxFile, wordStart);
+
+    float idf = logN - log ((double) wordEl.levelFreqs[levelNum]);
+
+    // seek to the appropriate place in the inverted file
+    fseek (invfFile, wordStart, SEEK_SET);
+    stdio_bitio_buffer buffer (invfFile);
+    
+    unsigned long B = BIO_Bblock_Init (idh.num_frags, wordEl.frag_occur);
+    unsigned long fragNum = 0;
+    unsigned long levelDocNum = 0;
+    unsigned long lastLevelDocNum = 0;
+    unsigned long termFreq = 0;
+    unsigned long checkLevelFreq = 0;
+    
+    unsigned long count, i;
+    for (i=0; i<wordEl.frag_occur; ++i) {
+      fragNum += buffer.bblock_decode (B, NULL);
+      if (!ifh.word_level_index) count = buffer.gamma_decode (NULL);
+      else count = 1;
+
+      if (fragNum > idh.num_frags)
+	FatalError (1, "fragNum = %d, "
+		    "number of fragments = %d\n"
+		    "wordNum = %d\n"
+		    "i = %d, frag_occur = %d\n",
+		    fragNum, idh.num_frags, wordNum, i, wordEl.frag_occur);
+
+      if (!fragLevelConvert.FragToLevel (fragNum, levelDocNum))
+	FatalError (1, "could not convert fragment number %d in level %d", fragNum, levelNum);
+
+      if (levelDocNum == 0 || levelDocNum > numLevelDocs)
+	FatalError (1, "bad level document number %d in level %d", levelDocNum, levelNum);
+      
+      if (levelDocNum != lastLevelDocNum) {
+	// new level document
+	if (lastLevelDocNum > 0) {
+	  AddWeight (w, lastLevelDocNum, termFreq, idf);
+	  ++checkLevelFreq;
+	}
+	lastLevelDocNum = levelDocNum;
+	termFreq = 0;
+      }
+      termFreq += count;
+    }
+
+    if (lastLevelDocNum > 0) {
+      AddWeight (w, lastLevelDocNum, termFreq, idf);
+      ++checkLevelFreq;
+    }
+
+    if (checkLevelFreq != wordEl.levelFreqs[levelNum]) {
+      cerr << "bad level freq at level " <<levelNum<<" "<< checkLevelFreq << " != "
+	   << wordEl.levelFreqs[levelNum] << ", word \""
+	   << wordEl.el << "\" (" << wordNum << ")\n";
+      exit (1);
+    }
+    
+    buffer.done();
+  }
+
+  if (w.size() != numLevelDocs) 
+    FatalError (1, "wrong number of weights created %d != %d",
+		w.size(), numLevelDocs);
+}
+
+static void WriteExactWeights (FILE *weightsFile,
+			       unsigned long &diskPtr,
+			       const Weights &w) {
+  diskPtr = ftell(weightsFile);
+
+  Weights::const_iterator here = w.begin();
+  Weights::const_iterator end = w.end();
+  while (here != end) {
+//      cout << *here << "\n";
+    WriteF (weightsFile, sqrt (*here));
+    ++here;
+  }
+}
+
+static void WriteApproxWeights (FILE *approxWeightsFile,
+				unsigned long &diskPtr,
+				const Weights &w,
+				unsigned char bits) {
+  diskPtr = ftell(approxWeightsFile);
+
+  // calculate L, U and B
+  double L = 1e300;
+  double U = 0;
+  float wgt;
+  Weights::const_iterator here = w.begin();
+  Weights::const_iterator end = w.end();
+  while (here != end) {
+    wgt = sqrt (*here);
+    if (wgt > U) U = wgt;
+    if (wgt > 0 && wgt < L) L = wgt;
+    ++here;
+  }
+
+  double B = pow (U / L, pow (2.0, -(double) bits));
+
+#ifndef SILENT
+  fprintf (stderr, "L = %f\n", L);
+  fprintf (stderr, "U = %f\n", U);
+  fprintf (stderr, "B = %f\n", B);
+#endif
+  
+  WriteUC (approxWeightsFile, bits);
+  WriteD (approxWeightsFile, L);
+  WriteD (approxWeightsFile, B);
+  
+
+  unsigned long max = (bits == 32) ? 0xffffffff : (1 << bits) - 1;;
+  unsigned long i=0, buf=0, pos=0;
+  here = w.begin();
+  end = w.end();
+  while (here != end) {
+    unsigned long fx;
+    wgt = sqrt (*here);
+    if (wgt == 0) {
+      wgt = L;
+#ifndef SILENT
+      Message ("Warning: Document %d had a weight of 0.", i);
+#endif
+    }
+    fx = (unsigned long) floor (log (wgt / L) / log (B));
+
+    if (fx > max) fx = max;
+
+    buf |= (fx << pos);
+    pos += bits;
+
+    if (pos >= MAXBITS) {
+      WriteUL (approxWeightsFile, buf);
+      buf = fx >> (bits - (pos - MAXBITS));
+      pos = pos - MAXBITS;
+    }
+
+    ++here; ++i;
+  }
+
+  // write out the last bits
+  if (pos > 0) WriteUL (approxWeightsFile, buf);
+}
+
+int main (int argc, char **argv) {
+  unsigned char bits = 8;
+  char *filename = "";
+  int ch;
+  opterr = 0;
+  msg_prefix = argv[0];
+
+  while ((ch = getopt (argc, argv, "f:d:b:h")) != -1) {
+    switch (ch) {
+    case 'f':		// input file
+      filename = optarg;
+      break;
+    case 'd':
+      set_basepath (optarg);
+      break;
+    case 'b':
+      bits = atoi (optarg);
+      if (bits > 32) {
+	fprintf (stderr, "b may only take values 0-32\n");
+	exit (1);
+      }
+      break;
+    case 'h':
+    case '?':
+      fprintf (stderr, "usage: %s [-f input_file]"
+	       "[-d data directory] [-b bits] [-h]\n", argv[0]);
+      exit (1);
+    }
+  }
+
+  
+  // open the dictionary
+  FILE *dictFile = open_file (filename, INVF_DICT_SUFFIX, "rb",
+			      MAGIC_STEM_BUILD, MG_ABORT);
+  invf_dict_header idh;
+  idh.Read (dictFile);
+
+  // open the inverted file
+  FILE *invfFile = open_file (filename, INVF_SUFFIX, "rb",
+			MAGIC_INVF, MG_ABORT);
+  invf_file_header ifh;
+  ifh.Read (invfFile);
+  if (ifh.skip_mode != SKIP_MODE_NO_SKIPS)
+    FatalError (1, "The invf file contains skips. Unable to create weights.");
+
+  // open the inverted index file
+  FILE *invfIdxFile = open_file (filename, INVF_IDX_SUFFIX, "rb",
+				 MAGIC_INVI, MG_ABORT);
+  
+  // read the level information
+  FILE *levelFile = open_file (filename, INVF_LEVEL_SUFFIX, "rb",
+			       MAGIC_INVF_LEVELS, MG_ABORT);
+  FIvfLevel ivfLevel;
+  ivfLevel.Read (levelFile);
+  fclose (levelFile);
+
+  // read in the tag dictionary and inverted file pointers
+  WBTagDict tagDict;
+  ReadTagDict (idh, dictFile, invfIdxFile, tagDict);
+
+  
+  // create the weights file
+  FILE *weightsFile = create_file (filename, WEIGHTS_SUFFIX, "wb",
+				   MAGIC_WGHT, MG_ABORT);
+
+  // create the approx weights file
+  FILE *approxWeightsFile = create_file (filename, APPROX_WEIGHTS_SUFFIX, "wb",
+					 MAGIC_WGHT_APPROX, MG_ABORT);
+
+  
+  // create weights for each document level
+  FragLevelConvert fragLevelConvert;
+  Weights w;
+  IvfLevelInfoMap::iterator levelHere = ivfLevel.levelInfo.begin();
+  IvfLevelInfoMap::iterator levelEnd = ivfLevel.levelInfo.end();
+  unsigned long levelNum = 0;
+  while (levelHere != levelEnd) {
+    const UCArray &levelName = (*levelHere).first;
+    
+    // read the tag information about this level
+    fragLevelConvert.Read(invfFile, tagDict[levelName].tagPtr,
+			  idh.num_frags, tagDict[levelName].fragOccur);
+    
+    // create the weights for this level
+    GenerateLevelWeights (idh, ifh, tagDict[levelName].fragOccur,
+			  levelNum, dictFile, invfFile, invfIdxFile,
+			  fragLevelConvert, w);
+
+    // write out the exact weights
+    WriteExactWeights (weightsFile,
+		       (*levelHere).second.exactWeightsDiskPtr,
+		       w);
+    
+    // write out the approximate weights
+    WriteApproxWeights (approxWeightsFile,
+			(*levelHere).second.approxWeightsDiskPtr,
+			w, bits);
+    
+    ++levelHere; ++levelNum;
+  }
+  
+
+  // close input files
+  fclose (dictFile);
+  fclose (invfFile);
+  fclose (invfIdxFile);
+
+  // update the level information
+  levelFile = create_file (filename, INVF_LEVEL_SUFFIX, "wb",
+			   MAGIC_INVF_LEVELS, MG_ABORT);
+  ivfLevel.Write (levelFile);
+  fclose (levelFile);
+
+  // close output files
+  fclose (weightsFile);
+  fclose (approxWeightsFile);
+
+
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/stemmer.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/stemmer.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/stemmer.cpp	(revision 10506)
@@ -0,0 +1,105 @@
+/**************************************************************************
+ *
+ * stemmer.cpp -- The stemmer/case folder
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+#include "stemmer.h"
+
+#include "lovinstem.h"
+#include "simplefrenchstem.h"
+#include "unitool.h"
+
+#define LOVINSTEMMER        0
+#define SIMPLEFRENCHSTEMMER 1
+
+
+/* decode the utf-8 encoded unicode, casefold and then recode 
+ * making sure the final length doesn't exceed the original
+ * length */
+static void unicode_casefold (u_char *word) {
+  unsigned short out[256]; /* temp space */
+  int i;
+  int len;
+
+  /* decode */
+  utf8_word_to_unicode (word, out, 255);
+  len = out[0];
+
+  /* casefold and simplify-fold */
+  for (i=0; i<len; ++i) {
+    out[i+1] = unicode_tosimplified(unicode_tolower(out[i+1]));
+  }
+
+  /* re-code */
+  unicode_to_utf8_word (out, word, word[0]+1);
+}
+
+
+int stemmernumber (u_char *stemmerdescription) {
+  u_char descript[MAX_STEM_DESCRIPTION_LEN];
+  int i;
+
+  /* copy and case-fold the description */
+  for (i=0; (stemmerdescription[i] != '\0') && 
+	 (i < MAX_STEM_DESCRIPTION_LEN-1); ++i)
+    descript[i] = tolower (stemmerdescription[i]);
+  descript[i] = '\0';
+
+  /* map the description to its number */
+
+  if ((strcmp ((char *) descript,  "0") == 0) ||
+      (strcmp ((char *) descript, "english") == 0) ||
+      (strcmp ((char *) descript, "lovin") == 0))
+    return LOVINSTEMMER;
+
+  if ((strcmp ((char *) descript, "1") == 1) ||
+      (strcmp ((char *) descript, "french") == 0) ||
+      (strcmp ((char *) descript, "simplefrench") == 0))
+    return SIMPLEFRENCHSTEMMER;
+
+  return -1;
+}
+
+
+
+/*
+ * Method 0 - Do not stem or case fold.
+ * Method 1 - Case fold.
+ * Method 2 - Stem.
+ * Method 3 - Case fold and stem.
+ *
+ * The stemmer number should be obtained using
+ * the stemmernumber function above.
+ */
+void 
+stemmer (int method, int stemmer, u_char *word) {
+  if (method & 1) {
+    unicode_casefold (word);
+  }
+
+  if (method & 2) {
+    switch (stemmer) {
+    case LOVINSTEMMER: lovinstem (word);
+      break;
+    case SIMPLEFRENCHSTEMMER: simplefrenchstem (word);
+      break;
+    }
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/stemmer.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/stemmer.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/stemmer.h	(revision 10506)
@@ -0,0 +1,65 @@
+/**************************************************************************
+ *
+ * stemmer.h -- The stemmer/case folder
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef STEMMER_H
+#define STEMMER_H
+
+#include "sysfuncs.h"
+
+#define STEMMER_MASK 3
+#define MAX_STEM_DESCRIPTION_LEN 16
+
+/* stemmernumber will return the stemmer for
+ * a description of the stemmer. Stemmer descriptions
+ * are not case sensitive. Valid descriptions are:
+ *
+ *   'English'
+ *   'Lovin'
+ *   'French'
+ *   'SimpleFrench'
+ *
+ * More than one description might result in the same
+ * stemmer number (for example, for stemming 'English'
+ * we currently use the 'Lovin' stemmer).
+ *
+ * stemmerdescription is a normal C, null-terminated,
+ * string.
+ *
+ * stemmernumber will return -1 if it doesn't know the
+ * stemmer description.
+ */
+int stemmernumber (u_char *stemmerdescription);
+
+/*
+ * Method 0 - Do not stem or case fold.
+ * Method 1 - Case fold.
+ * Method 2 - Stem.
+ * Method 3 - Case fold and stem.
+ *
+ * The stemmer number should be obtained using function
+ * stemmernumber above.
+ */
+#ifdef __cplusplus
+extern "C" 
+#endif
+void stemmer (int method, int stemmer, u_char * word);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.cpp	(revision 10506)
@@ -0,0 +1,146 @@
+/**************************************************************************
+ *
+ * text.h -- Header file for compression related stuff
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+// UCArray currently contains all the basic reading and writing functions
+#include "UCArray.h"
+#include "text.h"
+
+compressed_text_header::compressed_text_header () {
+  Clear();
+}
+
+void compressed_text_header::Clear () {
+  num_of_docs = 0;
+  num_of_words = 0;
+  num_of_bytes = 0.0;
+}
+
+
+bool compressed_text_header::Read (FILE *f) {
+  return (ReadUL (f, num_of_docs) &&
+	  ReadUL (f, num_of_words) &&
+	  ReadD (f, num_of_bytes));
+}
+
+bool compressed_text_header::Write (FILE *f) const {
+  return (WriteUL (f, num_of_docs) &&
+	  WriteUL (f, num_of_words) &&
+	  WriteD (f, num_of_bytes));
+}
+
+
+auxiliary_dict::auxiliary_dict () {
+  word_data[0] = NULL;
+  word_data[1] = NULL;
+  words[0] = NULL;
+  words[1] = NULL;
+}
+
+auxiliary_dict::~auxiliary_dict () {
+  Clear ();
+}
+
+void auxiliary_dict::Clear () {
+  if (word_data[0] != NULL) {
+    delete []word_data[0];
+    word_data[0] = NULL;
+  }
+  if (word_data[1] != NULL) {
+    delete []word_data[1];
+    word_data[1] = NULL;
+  }
+  if (words[0] != NULL) {
+    delete []words[0];
+    words[0] = NULL;
+  }
+  if (words[1] != NULL) {
+    delete []words[1];
+    words[1] = NULL;
+  }
+}
+
+
+compression_dict::compression_dict () {
+  int which;
+  for (which = 0; which < 2; ++which) {
+    cfh[which] = NULL;
+    values[which] = NULL;
+    escape[which] = NULL;
+    chars_huff[which] = NULL;
+    chars_vals[which] = NULL;
+    lens_huff[which] = NULL;
+    lens_vals[which] = NULL;
+  }
+
+  MemForCompDict = 0;
+  ad = NULL;
+  fast_loaded = 0;
+}
+
+compression_dict::~compression_dict () {
+  Clear ();
+}
+
+void compression_dict::Clear () {
+  int which;
+  for (which = 0; which < 2; ++which) {
+    if (cfh[which] != NULL) {
+      delete cfh[which];
+      cfh[which] = NULL;
+    }
+    if (values[which] != NULL) {
+      delete []values[which][0][0];
+      delete []values[which][0];
+      delete []values[which];
+      values[which] = NULL;
+    }
+    if (escape[which] != NULL) { // don't know if needed
+      //delete escape[which]; // this was causing a seg fault
+      escape[which] = NULL;
+    }
+    if (chars_huff[which] != NULL) {
+      delete chars_huff[which];
+      chars_huff[which] = NULL;
+    }
+    if (chars_vals[which] != NULL) {
+      delete []chars_vals[which][0];
+      delete []chars_vals[which];
+      chars_vals[which] = NULL;
+    }
+    if (lens_huff[which] != NULL) {
+      delete lens_huff[which];
+      lens_huff[which] = NULL;
+    }
+    if (lens_vals[which] != NULL) {
+      delete []lens_vals[which][0];
+      delete []lens_vals[which];
+      lens_vals[which] = NULL;
+    }
+  }
+
+  if (ad != NULL) {
+    delete ad;
+    ad = NULL;
+  }
+
+  MemForCompDict = 0;
+  fast_loaded = 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.h	(revision 10506)
@@ -0,0 +1,199 @@
+/**************************************************************************
+ *
+ * text.h -- Header file for compression related stuff
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#ifndef H_TEXT
+#define H_TEXT
+
+// some elderly windows compilers need to include <vector> (or something
+// similar) here so that they know what a "bool" is
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#else
+#  include <vector>
+#endif
+
+
+#include "huffman.h"
+#include <stdio.h>
+
+/*****************************************************************************
+ *
+ * There are several different methods of compressing the text of the
+ * database. The following defines list the different methods of text
+ * compression
+ *
+ */
+
+
+/* The dictionary contains all the fragments that occur in the collection
+   i.e. escapes are not possible */
+#define MG_COMPLETE_DICTIONARY 0
+
+
+/* Certain words have been deleted from the dictionary. The words deleted
+   have been used to create the frequency huffman codes of the characters. 
+   This dictionary has an escape code and may be used to compress novel
+   words. This dictionary may fail if there is a novel character. */
+#define MG_PARTIAL_DICTIONARY 1
+
+
+/* This dictionary has an escape so that novel words and non-words can be 
+   coded. The method for coding the novel words and non-words is determined
+   by a dictionary parameter. */
+#define MG_SEED_DICTIONARY 2
+
+
+
+
+
+
+
+
+
+/*****************************************************************************
+ *
+ * With a seed dictionary there are several methods for coding the novel
+ * words and non-words the following defined values specify the different
+ * methods of coding.
+ *
+ */
+
+
+/* Code novel words and non-words character by character using huffman codes.
+   The huffman codes for the word and non-word lengths and characters are 
+   generated from the distribution of lengths and characters in the
+   dictionary. */
+#define MG_NOVEL_HUFFMAN_CHARS 0
+
+
+/* This method codes novel words using delta codes. The novel words are stored
+   in a auxillary dictionary which is built by pass two. */
+#define MG_NOVEL_DELTA 2
+
+
+/* This method codes novel words using hybrid version of delta. The novel
+   words are stored in a auxillary dictionary which is built by pass two. */
+#define MG_NOVEL_HYBRID 3
+
+
+
+
+
+
+/* This specified an amount of extra space allocated in the
+   compression_dict_header for adding new parameters. As new
+   parameters are added this should be decreased. */
+#define TEXT_PARAMS 15
+
+
+
+struct compression_dict_header {
+  u_long dict_type;
+  u_long novel_method;
+  u_long params[TEXT_PARAMS];
+  u_long num_words[2];
+  u_long num_word_chars[2];
+  u_long lookback;
+};
+
+
+struct comp_frags_header {
+  huff_data hd;
+  u_long uncompressed_size;
+  u_long huff_words_size[MAX_HUFFCODE_LEN + 1];
+};
+
+// BOGUSTEXTLEN is used to replace the ratio
+// in the compressed_text_header while preparing
+// for UCArray
+#define BOGUSTEXTLEN 1000000
+
+struct compressed_text_header {
+  u_long num_of_docs;
+  u_long num_of_words; // number of words in collection
+  double num_of_bytes;
+
+  compressed_text_header ();
+  void Clear ();
+
+  // you must seek to the appropriate place before calling
+  // Read or Write
+  bool Read (FILE *f);
+  bool Write (FILE *f) const;
+};
+
+
+struct compression_stats_header {
+  u_long num_docs;
+  u_long dummy;     // alignment
+  double num_bytes; 
+};
+
+
+struct frags_stats_header {
+  u_long num_frags;
+  u_long mem_for_frags;
+};
+
+
+struct aux_frags_header {
+  u_long num_frags;
+  u_long mem_for_frags;
+};
+
+
+struct auxiliary_dict {
+  aux_frags_header afh[2];
+  u_char *word_data[2];
+  u_char **words[2];
+  int blk_start[2][33], blk_end[2][33];	/* blk_start and blk_end are required
+					   for the hybrid methods */
+
+  auxiliary_dict ();
+  ~auxiliary_dict ();
+
+  void Clear ();
+};
+
+
+struct compression_dict {
+  compression_dict_header cdh;
+  comp_frags_header *cfh[2];
+  unsigned long MemForCompDict;
+  u_char ***values[2];
+  u_char *escape[2];
+  huff_data *chars_huff[2];
+  u_long **chars_vals[2];
+  huff_data *lens_huff[2];
+  u_long **lens_vals[2];
+  auxiliary_dict *ad;
+  int fast_loaded;
+
+  compression_dict ();
+  ~compression_dict ();
+
+  void Clear ();
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.pass1.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.pass1.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.pass1.cpp	(revision 10506)
@@ -0,0 +1,387 @@
+/**************************************************************************
+ *
+ * text.pass1.cpp -- Text compression (Pass 1)
+ * Copyright (C) 1994  Neil Sharman, Gary Eddy and Alistair Moffat
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "huffman.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+#include "mg_files.h"
+#include "mg.h"
+#include "build.h"
+#include "locallib.h"
+#include "words.h"
+#include "text.h"
+#include "hash.h"
+#include "local_strings.h"
+#include "TextEl.h"
+
+/* for more meaningful messages - jrm21 (gsdl) */
+#ifdef HAVE_STRERROR
+#include <string.h>
+#include <errno.h>
+#endif
+
+
+#define POOL_SIZE 1024*1024
+#define INITIAL_HASH_SIZE 7927
+
+
+typedef struct hash_rec
+  {
+    unsigned long wcnt;		/* word frequency */
+    unsigned long occurance_num;
+    u_char *word;
+  }
+hash_rec;
+
+typedef struct dict_data
+  {
+    hash_rec *HashTable;
+    unsigned long HashSize;
+    unsigned long HashUsed;
+    unsigned long wordnum;
+    unsigned long words_read;
+    unsigned long bytes_diff;
+    huff_data hd;
+  }
+dict_data;
+
+
+
+static unsigned long longestDoc = 0;
+static unsigned long occurance_num = 0;
+static dict_data DictData[2];
+
+static u_char *Pool;
+static int PoolLeft;
+static double inputbytes = 0; /* [RJM 07/97: 4G limit] */
+static unsigned long MaxMemInUse = 0;
+static unsigned long MemInUse = 0;
+static compression_stats_header csh = {0, 0, 0.0}; /* [RJM 07/97: 4G limit] */
+
+
+static void ChangeMem (int Change) {
+  MemInUse += Change;
+  if (MemInUse > MaxMemInUse) MaxMemInUse = MemInUse;
+}
+
+
+int init_text_1 (const TagInfo &/*tagInfo*/, char * /*FileName*/) {
+  int which;
+  
+  if (!(Pool = (u_char *) Xmalloc (POOL_SIZE))) {
+    Message ("Unable to allocate memory for pool");
+    return (COMPERROR);
+  }
+  PoolLeft = POOL_SIZE;
+  ChangeMem (POOL_SIZE);
+  
+  for (which = 1; which >= 0; --which) {
+    u_char *word;
+    hash_rec *ent;
+    dict_data *dd = &DictData[which];
+    
+    dd->wordnum = 0;
+    dd->words_read = 0;
+    dd->bytes_diff = 0;
+    dd->HashSize = INITIAL_HASH_SIZE;
+    dd->HashUsed = 0;
+    
+    if (!(dd->HashTable = (hash_rec *) Xmalloc (sizeof (hash_rec) * dd->HashSize))) {
+      Message ("Unable to allocate memory for table");
+      return (COMPERROR);
+    }
+    ChangeMem (sizeof (hash_rec) * dd->HashSize);
+    memset (dd->HashTable,'\0' , sizeof (hash_rec) * dd->HashSize);
+
+    word = Pool;
+    *Pool++ = '\0';
+    --PoolLeft;
+    {
+      register u_char *wptr;
+      register int hsize = dd->HashSize;
+      register unsigned long hashval, step;
+      
+      HASH (hashval, step, word, hsize);
+      wptr = (dd->HashTable + hashval)->word;
+      while (wptr) {
+	hashval += step;
+	if (hashval >= (unsigned long)hsize)
+	  hashval -= hsize;
+	wptr = (dd->HashTable + hashval)->word;
+      }
+      ent = dd->HashTable + hashval;
+    }
+    ent->wcnt = 1;
+    ent->word = word;
+    dd->HashUsed = 1;
+  }
+  return (COMPALLOK);
+}
+
+
+static int process_text_element (const u_char *s_in, int l_in) {
+  const u_char *end = s_in + l_in - 1;
+  
+   /*
+   ** Alternately parse off words and non-words from the input
+   ** stream beginning with a non-word. Each token is then
+   ** inserted into the set if it does not exist or has it's
+   ** frequency count incremented if it does.
+   */
+  
+  bool which = false; // non-word
+  for (; s_in <= end; which = !which) {
+    u_char Word[MAXWORDLEN + 1];
+    dict_data *dd = &DictData[which];
+    
+    /* First parse a word or non-word out of the string */
+    if (which) PARSE_WORD (Word, s_in, end);
+    else PARSE_NON_WORD (Word, s_in, end);
+    
+    ++dd->wordnum;
+    inputbytes += *Word;
+    ++dd->words_read;
+    
+    /* Search the hash table for Word */
+    {
+      register unsigned long hashval, step;
+      register int hsize = dd->HashSize;
+      HASH (hashval, step, Word, hsize);
+      for (;;) {
+	register u_char *s1;
+	register u_char *s2;
+	register int len;
+	register hash_rec *ent;
+	ent = dd->HashTable + hashval;
+	if (!ent->word) {
+	  int len = *Word + 1;
+	  if (len > PoolLeft) {
+	    if (!(Pool = (u_char *) Xmalloc (POOL_SIZE))) {
+	      Message ("Unable to allocate memory for pool");
+	      return (COMPERROR);
+	    }
+	    PoolLeft = POOL_SIZE;
+	    ChangeMem (POOL_SIZE);
+	  }
+	  ent->occurance_num = occurance_num++;
+	  ent->wcnt = 1;
+	  ent->word = Pool;
+	  memcpy (Pool, Word, len);
+	  Pool += len;
+	  PoolLeft -= len;
+	  ++dd->HashUsed;
+	  dd->bytes_diff += Word[0];
+	  break;
+	}
+	
+	/* Compare the words */
+	s1 = Word;
+	s2 = ent->word;
+	len = *s1 + 1;
+	for (; len; --len)
+	  if (*s1++ != *s2++) break;
+	
+	if (len) {
+	  hashval = (hashval + step);
+	  if (hashval >= (unsigned long)hsize) hashval -= hsize;
+	} else {
+	  ++ent->wcnt;
+	  break;
+	}
+      }
+    }
+
+    
+    if (dd->HashUsed >= dd->HashSize >> 1) {
+      hash_rec *ht;
+      unsigned long size;
+      unsigned long i;
+      size = prime (dd->HashSize * 2);
+      if (!(ht = (hash_rec *) Xmalloc (sizeof (hash_rec) * size))) {
+	Message ("Unable to allocate memory for table");
+	return (COMPERROR);
+      }
+      ChangeMem (sizeof (hash_rec) * size);
+      memset (ht, '\0', sizeof (hash_rec) * size);
+
+      for (i = 0; i < dd->HashSize; ++i)
+	if (dd->HashTable[i].word) {
+	  register u_char *wptr;
+	  register unsigned long hashval, step;
+	  
+	  wptr = dd->HashTable[i].word;
+	  HASH (hashval, step, wptr, size);
+	  wptr = (ht + hashval)->word;
+	  while (wptr) {
+	    hashval += step;
+	    if (hashval >= size) hashval -= size;
+	    wptr = (ht + hashval)->word;
+	  }
+	  ht[hashval] = dd->HashTable[i];
+	}
+      Xfree (dd->HashTable);
+      ChangeMem (-sizeof (hash_rec) * dd->HashSize);
+      dd->HashTable = ht;
+      dd->HashSize = size;
+    }
+  }
+
+  return COMPALLOK;
+}
+
+
+int process_text_1 (const TagInfo &/*tagInfo*/, const TextElArray &doc) {
+  unsigned long textLen = 0;
+  unsigned long docLen = 0;
+  int retValue;
+
+  // process each text element in this document
+  TextElArray::const_iterator here = doc.begin();
+  TextElArray::const_iterator end = doc.end();
+  while (here != end) {
+    textLen = (*here).text.size();
+    docLen += textLen;
+
+    retValue = process_text_element (&(here->text[0]), textLen);
+    if (retValue != COMPALLOK) return retValue;
+    
+    ++here;
+  }
+
+  // get max document length
+  if (docLen > longestDoc) longestDoc = docLen;
+
+  // update header information
+  ++csh.num_docs;
+  csh.num_bytes += docLen;
+  
+  return COMPALLOK;
+}
+
+
+static int PackHashTable (dict_data * dd) {
+  int s, d;
+  for (s = d = 0; (unsigned int)s < dd->HashSize; ++s)
+    if (dd->HashTable[s].word)
+      dd->HashTable[d++] = dd->HashTable[s];
+  
+  ChangeMem (-sizeof (hash_rec) * dd->HashSize);
+  ChangeMem (sizeof (hash_rec) * dd->HashUsed);
+  
+  if (!(dd->HashTable = (hash_rec *) Xrealloc (dd->HashTable,
+			   sizeof (hash_rec) * dd->HashUsed))) {
+    Message ("Out of memory");
+    return COMPERROR;
+  }
+  dd->HashSize = dd->HashUsed;
+  return COMPALLOK;
+}
+
+
+static int ent_comp (const void *s1, const void *s2) {
+  return casecompare (((hash_rec *) s1)->word, ((hash_rec *) s2)->word);
+}
+
+
+static void WriteHashTable (FILE * fp, dict_data * dd) {
+  frags_stats_header fsh;
+  u_long j = 0;
+  u_char *curr;
+
+  if (PackHashTable (dd) == COMPERROR) return;
+  
+  qsort (dd->HashTable, dd->HashUsed, sizeof (hash_rec), ent_comp);
+  
+  fsh.num_frags = dd->HashSize;
+  fsh.mem_for_frags = dd->HashSize;
+  for (j = 0; j < dd->HashSize; ++j)
+    fsh.mem_for_frags += dd->HashTable[j].word[0];
+  
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(fsh.num_frags);
+  HTONUL(fsh.mem_for_frags);
+  
+  fwrite (&fsh, sizeof (fsh), 1, fp);
+  
+  for (j = 0; j < dd->HashSize; ++j) {
+    curr = dd->HashTable[j].word;
+    
+    /* [RPAP - Jan 97: Endian Ordering] */
+    HTONUL(dd->HashTable[j].wcnt);
+    HTONUL(dd->HashTable[j].occurance_num);
+    
+    fwrite (&dd->HashTable[j].wcnt, sizeof (dd->HashTable[j].wcnt), 1, fp);
+    fwrite (&dd->HashTable[j].occurance_num,
+	    sizeof (dd->HashTable[j].occurance_num), 1, fp);
+    
+    /* [RPAP - Jan 97: Endian Ordering] */
+    NTOHUL(dd->HashTable[j].wcnt);
+    NTOHUL(dd->HashTable[j].occurance_num);
+    
+    fwrite (curr, sizeof (u_char), curr[0] + 1, fp);
+  }
+}
+
+
+int done_text_1 (const TagInfo &/*tagInfo*/, char *file_name) {
+  char *temp_str;
+  FILE *fp;
+  
+  if (!(fp = create_file (file_name, TEXT_STATS_DICT_SUFFIX, "wb",
+			  MAGIC_STATS_DICT, MG_MESSAGE)))  /* [RPAP - Feb 97: WIN32 Port] */
+    {
+      fprintf(stderr,"Couldn't create file %s%s:%s\n",
+              file_name, TEXT_STATS_DICT_SUFFIX,
+#if defined(HAVE_STRERROR) || defined(__WIN32__)
+              strerror(errno)
+#else
+	      " "
+#endif
+              );
+      return COMPERROR;
+    }
+
+  temp_str = msg_prefix;
+  msg_prefix = "text.pass1";
+  
+  /* [RPAP - Jan 97: Endian Ordering] */
+  HTONUL(csh.num_docs);
+  HTOND(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  fwrite (&csh, sizeof (csh), 1, fp);
+
+  /* [RPAP - Jan 97: Endian Ordering] */
+  NTOHUL(csh.num_docs);
+  NTOHD(csh.num_bytes); /* [RJM 07/97: 4G limit] */
+
+  WriteHashTable (fp, &DictData[0]);
+  WriteHashTable (fp, &DictData[1]);
+  msg_prefix = temp_str;
+  return COMPALLOK;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.pass2.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.pass2.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/text.pass2.cpp	(revision 10506)
@@ -0,0 +1,585 @@
+/**************************************************************************
+ *
+ * text.pass2.cpp -- Text compression (Pass 2)
+ * Copyright (C) 1994  Neil Sharman, Gary Eddy and Alistair Moffat
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+#pragma warning(disable:4786)
+#endif
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+#if defined (__WIN32__)
+# include <stdio.h>
+# define unlink _unlink
+#endif
+
+#include "sysfuncs.h"
+#include "memlib.h"
+#include "messages.h"
+#include "local_strings.h"
+#include "bitio_m_stdio.h"
+#include "huffman.h"
+#include "netorder.h"  /* [RPAP - Jan 97: Endian Ordering] */
+#include "mg.h"
+#include "mg_files.h"
+#include "build.h"
+#include "words.h"
+#include "text.h"
+#include "hash.h"
+#include "locallib.h"
+#include "comp_dict.h"
+#include "FText.h"
+
+#define POOL_SIZE 1024*256
+
+
+struct char_pool {
+  struct char_pool *next;
+  u_long left;
+  u_char *ptr;
+  u_char pool[POOL_SIZE];
+};
+
+struct novel_hash_rec {
+  u_long ordinal_num;
+  u_char *word;
+};
+
+
+#define INITIAL_HASH_SIZE 7927
+
+struct novel_hash_table {
+  novel_hash_rec *HashTable;
+  u_long HashSize, HashUsed;
+  char_pool *first_pool;
+  char_pool *pool;
+  u_long next_num, binary_start;
+  novel_hash_rec **code_to_nhr;
+};
+
+
+static FILE *text;
+static stdio_bitio_buffer textOutBuf;
+static u_long headLen;
+
+static novel_hash_table nht[2];
+
+int blk_start[2][33], blk_end[2][33];
+
+// 0 = non-word, 1 = word
+unsigned char whichWordType = 0;
+
+CompressTextInfoMap textInfoMap;
+
+
+static char_pool *new_pool (char_pool * pool) {
+  char_pool *p = (char_pool *) Xmalloc (sizeof (char_pool));
+  if (!p) FatalError (1, "Unable to allocate memory for pool");
+  
+  if (pool) pool->next = p;
+  p->next = NULL;
+  p->left = POOL_SIZE;
+  p->ptr = p->pool;
+  return p;
+}
+
+
+int init_text_2 (const TagInfo &/*tagInfo*/, char *fileName) {
+  char path[512];
+
+  // load the compression dictionary
+  if (LoadCompressionDictionary (make_name (fileName, TEXT_DICT_SUFFIX,
+					    path)) == COMPERROR)
+    return COMPERROR;
+
+  // create the compressed text file and attach it to the text buffer
+  if (!(text = create_file (fileName, TEXT_SUFFIX, "w+b",
+			    MAGIC_TEXT, MG_MESSAGE)))
+    return COMPERROR;
+  textOutBuf.attachFile (text);
+  textOutBuf.encodeStart ();
+  
+  // write out the compressed text header
+  memset (&cth, '\0', sizeof (cth));
+  if (fwrite (&cth, sizeof (cth), 1, text) != 1)
+    return COMPERROR;
+
+  // the length of the compressed header is the size of the
+  // magic number plus the size of the compressed text header
+  headLen = sizeof (u_long) + sizeof (cth);
+
+  // start off with non-word
+  whichWordType = 0;
+
+  // clear the text pointers
+  textInfoMap.erase (textInfoMap.begin(), textInfoMap.end());
+  
+  // set up the hash table of novel words
+  int i;
+  if (cdh.novel_method != MG_NOVEL_HUFFMAN_CHARS)
+    for (i = 0; i <= 1; ++i)
+      {
+	nht[i].HashSize = INITIAL_HASH_SIZE;
+	nht[i].HashTable = (novel_hash_rec *) Xmalloc (sizeof (novel_hash_rec) * nht[i].HashSize);
+	memset (nht[i].HashTable, '\0',
+	       sizeof (novel_hash_rec) * nht[i].HashSize);
+	nht[i].HashUsed = 0;
+	nht[i].HashSize = INITIAL_HASH_SIZE;
+	nht[i].pool = nht[i].first_pool = new_pool (NULL);
+	nht[i].next_num = 1;
+	nht[i].binary_start = 1;
+	nht[i].code_to_nhr = NULL;
+	if (cdh.novel_method == MG_NOVEL_HYBRID)
+	  {
+	    int num;
+	    num = 1;
+	    blk_start[i][0] = 0;
+	    blk_end[i][0] = cdh.num_words[i] - 1;
+	    while (num < 33)
+	      {
+		blk_start[i][num] = blk_end[i][num - 1] + 1;
+		blk_end[i][num] = blk_start[i][num] +
+		  (blk_end[i][num - 1] - blk_start[i][num - 1]) * 2;
+		++num;
+	      }
+	  }
+      }
+
+  return (COMPALLOK);
+}
+
+
+static int compress_text (bitio_buffer &buffer, const u_char *s_in,
+			  int l_in, unsigned char &which,
+			  unsigned long &numWords) {
+  const u_char *end = s_in + l_in - 1;
+
+  for (; s_in <= end; which = !which) {
+    u_char Word[MAXWORDLEN + 1];
+    int res;
+    
+    if (which) ++numWords;
+
+    /* First parse a word or non-word out of the string */
+    if (which) PARSE_WORD (Word, s_in, end);
+    else PARSE_NON_WORD (Word, s_in, end);
+
+    /* Search the hash table for Word */
+    if (ht[which]) {
+      register unsigned long hashval, step;
+      register int tsize = ht[which]->size;
+      register u_char **wptr;
+      HASH (hashval, step, Word, tsize);
+      for (;;) {
+	register u_char *s1;
+	register u_char *s2;
+	register int len;
+	wptr = ht[which]->table[hashval];
+	if (wptr == NULL) {
+	  res = COMPERROR;
+	  break;
+	}
+
+	/* Compare the words */
+	s1 = Word;
+	s2 = *wptr;
+	len = *s1 + 1;
+	for (; len; --len)
+	  if (*s1++ != *s2++) break;
+	
+	if (len) {
+	  hashval += step;
+	  if (hashval >= (unsigned long)tsize) hashval -= tsize;
+	  
+	} else {
+	  res = ht[which]->table[hashval] - ht[which]->words;
+	  break;
+	}
+      }
+    }
+    else
+      res = COMPERROR;
+    /* Check that the word was found in the dictionary */
+    if (res == COMPERROR)
+      {
+	if (cdh.dict_type == MG_COMPLETE_DICTIONARY)
+	  {
+	    Message ("Unknown word \"%.*s\"\n", *Word, Word + 1);
+	    return (COMPERROR);
+	  }
+	if (cdh.dict_type == MG_PARTIAL_DICTIONARY)
+	  {
+	    u_long i;
+	    if (ht[which])
+	      {
+		res = ht[which]->hd->num_codes - 1;
+		buffer.huff_encode (res, ht[which]->codes, ht[which]->hd->clens, NULL);
+	      }
+	    buffer.huff_encode (Word[0], lens_codes[which], lens_huff[which].clens, NULL);
+	    for (i = 0; i < Word[0]; ++i)
+	      buffer.huff_encode (Word[i + 1], char_codes[which],
+				  char_huff[which].clens, NULL);
+	  }
+	if (cdh.dict_type == MG_SEED_DICTIONARY)
+	  {
+	    if (ht[which])
+	      {
+		res = ht[which]->hd->num_codes - 1;
+		buffer.huff_encode (res, ht[which]->codes, ht[which]->hd->clens, NULL);
+	      }
+	    switch (cdh.novel_method)
+	      {
+	      case MG_NOVEL_HUFFMAN_CHARS:
+		{
+		  u_long i;
+		  buffer.huff_encode (Word[0], lens_codes[which],
+				      lens_huff[which].clens, NULL);
+		  for (i = 0; i < Word[0]; ++i)
+		    buffer.huff_encode (Word[i + 1], char_codes[which],
+					char_huff[which].clens, NULL);
+		}
+		break;
+	      case MG_NOVEL_DELTA:
+	      case MG_NOVEL_HYBRID:
+		{
+		  register unsigned long hashval, step;
+		  register novel_hash_table *h = &nht[which];
+		  register int hsize = h->HashSize;
+		  register novel_hash_rec *ent;
+		  HASH (hashval, step, Word, hsize);
+		  for (;;)
+		    {
+		      register u_char *s1, *s2;
+		      register int len;
+		      ent = h->HashTable + hashval;
+		      if (!ent->word)
+			{
+			  int len = *Word + 1;
+			  if ((unsigned)len > h->pool->left)
+			    h->pool = new_pool (h->pool);
+			  ent->word = h->pool->ptr;
+			  ent->ordinal_num = h->next_num++;
+			  memcpy (h->pool->ptr, Word, len);
+			  h->pool->ptr += len;
+			  h->pool->left -= len;
+			  ++h->HashUsed;
+			  break;
+			}
+		      /* Compare the words */
+		      s1 = Word;
+		      s2 = ent->word;
+		      len = *s1 + 1;
+		      for (; len; --len)
+			if (*s1++ != *s2++)
+			  break;
+		      
+		      if (!len)
+			break;
+		      
+		      hashval = (hashval + step);
+		      if (hashval >= (unsigned)hsize) hashval -= hsize;
+		    }
+		  
+		  switch (cdh.novel_method) {
+		  case MG_NOVEL_DELTA:
+		    buffer.delta_encode (ent->ordinal_num, NULL);
+		    break;
+		  case MG_NOVEL_HYBRID:
+		    int k = 0;
+		    int j = ent->ordinal_num - 1;
+		    while (j > blk_end[which][k])
+		      ++k;
+		    assert (j - blk_start[which][k] + 1 >= 1 &&
+			    j - blk_start[which][k] + 1 <=
+			    blk_end[which][k] - blk_start[which][k] + 1);
+		    
+		    buffer.gamma_encode (k + 1, NULL);
+		    buffer.binary_encode (j - blk_start[which][k] + 1,
+					  blk_end[which][k] - blk_start[which][k] + 1,
+					  NULL);
+		    break;
+		  }
+		  
+		  if (h->HashUsed >= h->HashSize >> 1)
+		    {
+		      novel_hash_rec *ht;
+		      unsigned long size;
+		      unsigned long i;
+		      size = prime (h->HashSize * 2);
+		      if (!(ht = (novel_hash_rec *) Xmalloc (sizeof (novel_hash_rec) * size)))
+			{
+			  Message ("Unable to allocate memory for table");
+			  return (COMPERROR);
+			}
+		      memset (ht, '\0', sizeof (novel_hash_rec) * size);
+		      
+		      for (i = 0; i < h->HashSize; ++i)
+			if (h->HashTable[i].word)
+			  {
+			    register u_char *wptr;
+			    register unsigned long hashval, step;
+			    
+			    wptr = h->HashTable[i].word;
+			    HASH (hashval, step, wptr, size);
+			    wptr = (ht + hashval)->word;
+			    while (wptr)
+			      {
+				hashval += step;
+				if (hashval >= size)
+				  hashval -= size;
+				wptr = (ht + hashval)->word;
+			      }
+			    ht[hashval] = h->HashTable[i];
+			  }
+		      Xfree (h->HashTable);
+		      h->HashTable = ht;
+		      h->HashSize = size;
+		    }
+		}
+		break;
+	      }
+	  }
+      }
+    else
+      {
+	buffer.huff_encode (res, ht[which]->codes, ht[which]->hd->clens, NULL);
+      }
+  }
+  
+  return COMPALLOK;
+}
+
+
+int process_text_2 (const TagInfo &tagInfo, const TextElArray &doc) {
+  // we need to remember where the last text element ends
+  unsigned char endBit = textOutBuf.GetBtg (); // 8=high bit, 1=low bit
+  unsigned long endPos = textOutBuf.GetBytesWritten () + headLen;
+
+  // process each text element
+  TextElArray::const_iterator here = doc.begin();
+  TextElArray::const_iterator end = doc.end();
+  while (here != end) {
+    // remember current place in compressed text
+    unsigned char startWhich = whichWordType;
+    unsigned char startBit = textOutBuf.GetBtg (); // 8=high bit, 1=low bit
+    unsigned long startPos = textOutBuf.GetBytesWritten () + headLen;
+
+    // compress the text
+    if (compress_text (textOutBuf,
+		       &(here->text[0]),
+		       (*here).text.size(),
+		       whichWordType,
+		       cth.num_of_words) != COMPALLOK)
+      return COMPERROR;
+
+    endBit = textOutBuf.GetBtg (); // 8=high bit, 1=low bit
+    endPos = textOutBuf.GetBytesWritten () + headLen;
+    
+    // update the pointers if this is a level tag
+    if (tagInfo.levelTags.find ((*here).tagName) != tagInfo.levelTags.end()) {
+      if ((*here).elType == OpenTagE) {
+	// set the start of the document
+	textInfoMap[(*here).tagName].SetStart (startPos, startBit, startWhich);
+	
+      } else if ((*here).elType == CloseTagE) {
+	// set the end of the document
+	textInfoMap[(*here).tagName].SetEnd (endPos, endBit);
+	
+      } else {
+	// TextE, nothing needs to be done
+      }
+    }
+    
+    cth.num_of_bytes += (*here).text.size();
+    ++here;
+  }
+
+  // close off any unclosed tags
+  CompressTextInfoMap::iterator tiHere = textInfoMap.begin ();
+  CompressTextInfoMap::iterator tiEnd = textInfoMap.end ();
+  while (tiHere != tiEnd) {
+    if ((*tiHere).second.inDoc) (*tiHere).second.SetEnd (endPos, endBit);
+    ++tiHere;
+  }
+  
+  // we've processed one more document
+  ++cth.num_of_docs;
+
+  return COMPALLOK;
+}
+
+
+static int write_aux_dict (char *fileName) {
+  int i;
+  FILE *aux;
+  if (!(aux = create_file (fileName, TEXT_DICT_AUX_SUFFIX, "wb",
+			   MAGIC_AUX_DICT, MG_MESSAGE)))
+    return COMPERROR;
+  
+  for (i = 0; i <= 1; ++i)
+    {
+      aux_frags_header afh;
+      char_pool *cp;
+      
+      afh.num_frags = nht[i].HashUsed;
+      afh.mem_for_frags = 0;
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	afh.mem_for_frags += POOL_SIZE - cp->left;
+      
+      /* [RPAP - Jan 97: Endian Ordering] */
+      HTONUL(afh.num_frags);
+      HTONUL(afh.mem_for_frags);
+      
+      fwrite (&afh, sizeof (afh), 1, aux);
+      
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	fwrite (cp->pool, POOL_SIZE - cp->left, sizeof (u_char), aux);
+    }
+  fclose (aux);
+  return COMPALLOK;
+}
+
+
+static void estimate_compressed_aux_dict (void) {
+  int i;
+  u_long aux_compressed = 0, total_uncomp = 0;
+  for (i = 0; i <= 1; ++i)
+    {
+      int j;
+      long chars[256], fchars[256];
+      long lens[16], flens[16];
+      char_pool *cp;
+      memset (chars, '\0', sizeof (chars));
+      memset (lens, '\0', sizeof (lens));
+      for (cp = nht[i].first_pool; cp; cp = cp->next)
+	{
+	  u_char *buf = cp->pool;
+	  while (buf != cp->ptr)
+	    {
+	      int len = *buf++;
+	      ++lens[len];
+	      total_uncomp += len + 4;
+	      for (; len; --len)
+		++chars[*buf++];
+	    }
+	}
+      for (j = 0; j < 256; ++j)
+	if (!chars[j] && PESINAWORD (j) == i)
+	  fchars[j] = 1;
+	else
+	  fchars[j] = chars[j];
+      for (j = 0; j < 16; ++j)
+	if (!lens[j])
+	  flens[j] = 1;
+	else
+	  flens[j] = lens[j];
+      
+      aux_compressed += (long unsigned int) ((Calculate_Huffman_Size (16, flens, lens) +
+					      Calculate_Huffman_Size (256, fchars, chars)) / 8);
+      
+    }
+}
+
+
+
+static bool WriteTextIdx (char *fileName, FTextLevel &textLevels) {
+  // create the text index
+  FILE *textIdxFile;
+  if (!(textIdxFile = create_file (fileName, TEXT_IDX_SUFFIX, "w+b",
+				MAGIC_TEXI, MG_MESSAGE)))
+    return false;
+
+  // output each level
+  CompressTextInfoMap::iterator tiHere = textInfoMap.begin ();
+  CompressTextInfoMap::iterator tiEnd = textInfoMap.end ();
+  while (tiHere != tiEnd) {
+    // remember the level information
+    TextLevelInfo levelInfo;
+    levelInfo.levelTag = (*tiHere).first;
+    levelInfo.textIdxPtr = ftell (textIdxFile);
+    levelInfo.numEntries = (*tiHere).second.docPtrs.size();
+    textLevels.levelInfo[levelInfo.levelTag] = levelInfo;
+
+    // write out the index array for this level
+    if (!WriteTextIdxArray (textIdxFile, (*tiHere).second.docPtrs))
+      return false;
+    
+    ++tiHere;
+  }
+
+  // close the file
+  fclose (textIdxFile);
+
+  return true;
+}
+
+
+bool WriteTextLevels (char *fileName, const FTextLevel &textLevels) {
+  //  cout << textLevels;
+  
+  // create the text index
+  FILE *textLevelFile;
+  if (!(textLevelFile = create_file (fileName, TEXT_LEVEL_SUFFIX, "w+b",
+				     MAGIC_TEXT_LEVELS, MG_MESSAGE)))
+    return false;
+
+  // output each level
+  if (!textLevels.Write (textLevelFile)) return false;
+  
+  // close the file
+  fclose (textLevelFile);
+
+  return true;
+}
+
+
+int done_text_2 (const TagInfo &/*tagInfo*/, char *fileName) {
+  // write out any remaining bits
+  textOutBuf.encodeDone();
+
+  // write out the compressed text header (with updated statistics)
+  if (fseek (text, sizeof (u_long), SEEK_SET) == -1 || !cth.Write (text))
+    return COMPERROR;
+  fclose (text);
+
+  // write out the text index file and get the level information
+  FTextLevel textLevels;
+  if (!WriteTextIdx (fileName, textLevels)) return COMPERROR;
+  
+  // write out the text level information
+  if (!WriteTextLevels (fileName, textLevels)) return COMPERROR;
+
+  // write out the auxiliary dictionary
+  if (cdh.dict_type != MG_COMPLETE_DICTIONARY &&
+      (cdh.novel_method == MG_NOVEL_DELTA ||
+       cdh.novel_method == MG_NOVEL_HYBRID)) {
+    if (write_aux_dict (fileName) == COMPERROR) return COMPERROR;
+    estimate_compressed_aux_dict ();
+    
+  } else {
+    unlink (make_name (fileName, TEXT_DICT_AUX_SUFFIX, NULL));
+  }
+
+  return (COMPALLOK);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/words.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/words.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/words.cpp	(revision 10506)
@@ -0,0 +1,122 @@
+/**************************************************************************
+ *
+ * words.cpp -- Functions for parsing out words from the source text
+ * Copyright (C) 1999  Rodger McNab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if defined (__WIN32__) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+#endif
+
+#include "words.h"
+
+
+/* Takes the place of the old INAWORD macro. It determines
+   whether a given place in a UTF-8 encoded Unicode string
+   is part of a word. */
+int inaword (const u_char *here, const u_char *end) {
+  unsigned short c;
+  if (parse_utf8_char(here, end, &c) > 0) return is_unicode_letdig (c);
+  return 0;
+}
+
+/* It determines whether a given place in a UTF-8 encoded Unicode string is a unicode space. */
+int isaspace (const u_char *here, const u_char *end)
+{
+  unsigned short c;
+  if (parse_utf8_char(here, end, &c) > 0) return is_unicode_space(c);
+  return 0;
+}
+
+/* Return a the UTF-8 encoded Unicode string with begining
+   unicode spaces skippend. */
+u_char *skipspace(u_char *here, u_char *end)
+{
+  unsigned short c;	
+  int length;
+  while(here != end) {
+    length = parse_utf8_char(here, end, &c);
+    if (length == 0 || !is_unicode_space(c)) break;
+    here += length;
+  }
+  return here;
+}
+ 
+const unsigned char *ParseIndexWord (const unsigned char *textHere,
+				     const unsigned char *textEnd,
+				     UCArray &word) {
+  word.erase (word.begin(), word.end());
+
+  register int charlength = 0;
+  register int length = 0;
+  register int numeric = 0;
+  unsigned short c;
+  
+  charlength = parse_utf8_char (textHere, textEnd, &c);
+  
+  while (length+charlength <= MAXSTEMLEN && charlength > 0 &&
+	 (is_unicode_letter(c) || (is_unicode_digit(c) &&
+				   ++numeric <= MAXNUMERIC))) {
+    while (charlength-- > 0) {
+      word.push_back (*textHere++); ++length;
+    }
+    charlength = parse_utf8_char (textHere, textEnd, &c);
+  }
+  
+  return textHere;
+}
+
+const unsigned char *ParseIndexMGWord (const unsigned char *textHere,
+				       const unsigned char *textEnd,
+				       unsigned char *mgWord) {
+  register int charlength = 0;
+  register int length = 0;
+  register int numeric = 0;
+  unsigned short c;
+  
+  charlength = parse_utf8_char (textHere, textEnd, &c);
+  
+  while (length+charlength <= MAXSTEMLEN && charlength > 0 &&
+	 (is_unicode_letter(c) || (is_unicode_digit(c) &&
+				   ++numeric <= MAXNUMERIC))) {
+    while (charlength-- > 0) {
+      mgWord[++length] = *textHere++;
+    }
+    charlength = parse_utf8_char (textHere, textEnd, &c);
+  }
+
+  mgWord[0] = length;
+  
+  return textHere;
+}
+
+const unsigned char *ParseNonindexWord (const unsigned char *textHere,
+					const unsigned char *textEnd) {
+  register int charlength = 0;
+  unsigned short c;
+  
+  charlength = parse_utf8_char(textHere, textEnd, &c);
+  
+  while (charlength > 0 && !is_unicode_letdig(c)) {
+    textHere += charlength;
+    charlength = parse_utf8_char (textHere, textEnd, &c);
+  }
+  
+  return textHere;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/words.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/words.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/mgpp/text/words.h	(revision 10506)
@@ -0,0 +1,164 @@
+/**************************************************************************
+ *
+ * words.h -- Macros for parsing out words from the source text
+ * Copyright (C) 1994  Neil Sharman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **************************************************************************/
+
+#include "sysfuncs.h"
+
+#include "unitool.h"
+#include "UCArray.h"
+
+
+/*
+ * This has been cleaned up by Tim Shimmin. 
+ */
+
+/*
+ * ---NOTE---
+ *
+ * "WORD" refers to a word in the compressed text.
+ * "STEM" or "STEM_WORD" refers to a word for indexing on
+ *
+ */
+
+#define MAXWORDLEN	15
+	/* Maximum length in bytes of any word or non-word. Note that
+	   variations to MAXWORDLEN may have dramatic effects on the rest
+	   of the program, as the length and the prefix match are packed
+	   together into a four bit nibble, and there is not check that
+	   this is possible, i.e., leave MAXWORDLEN alone... */
+
+#define MAXSTEMLEN	255
+	/* Maximum length in bytes of any stem. Note that
+	   variations to MAXSTEMLEN may have dramatic effects on the rest
+	   of the program, , i.e., leave MAXSTEMLEN alone... */
+
+#define MAXNUMERIC	4
+	/* Maximum number of numeric characters permitted in a word.
+	   This avoids long sequences of numbers creating just one
+	   word occurrence for each number. At most 10,000 all numeric
+	   words will be permitted. */
+
+/* [RPAP - Jan 97: Stem Index Change] */
+#define MAXPARAMLEN     20
+        /* Maximum number of bytes to read for a parameter value for a
+	   term in a query. */
+#define WEIGHTPARAM     '/'
+#define STEMPARAM       '#'
+
+/* [RJM 07/97: Ranked Required Terms] */
+#define MUSTMATCHPARAM     '+'
+
+
+#define PESINAWORD(c)      (isalnum(c) || ((c) >= 0x80 && (c) <= 0xff))
+        /* The definition of what characters are permitted in a word.
+	   This macro is pessimistic, you cannot tell from a particular
+	   byte above 0x80 whether it is a character or not. This function
+	   is needed by various functions relating to huffman coding
+	   where frequency counts need to be primed, it should not be
+	   used in parsing the UTF-8 encoded input. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int inaword (const u_char *here, const u_char *end);
+        /* Takes the place of the old INAWORD macro. It determines
+	   whether a given place in a UTF-8 encoded Unicode string
+	   is part of a word. */
+
+int isaspace (const u_char *here, const u_char *end);
+        /* It determines whether a given place in a UTF-8 encoded Unicode string  is a unicode space. */
+
+u_char *skipspace(u_char *here, u_char *end);
+        /* Return a the UTF-8 encoded Unicode string with begining unicode spaces skippend. */
+
+#ifdef __cplusplus
+}
+#endif
+
+const unsigned char *ParseIndexWord (const unsigned char *textHere,
+				     const unsigned char *textEnd,
+				     UCArray &word);
+const unsigned char *ParseIndexMGWord (const unsigned char *textHere,
+				       const unsigned char *textEnd,
+				       unsigned char *mgWord);
+const unsigned char *ParseNonindexWord (const unsigned char *textHere,
+					const unsigned char *textEnd);
+
+
+
+/* =========================================================================
+ * Macro: PARSE_WORD
+ * Description: 
+ *      Extract a word out for compressing text
+ * Input: 
+ *      s_in = string start in buffer
+ *      end = string end in buffer
+ * Output: 
+ *      Word = extracted word with length in 1st byte
+ *      s_in = ptr to next character in buffer yet to be processed
+ * ========================================================================= */
+#define PARSE_WORD(Word, s_in, end)                                \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    register u_char *wptr = (Word)+1;                              \
+    register int length = 0;                                       \
+    register int numeric = 0;                                      \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (length+charlength <= MAXWORDLEN && charlength > 0 &&    \
+	   (is_unicode_letter(c) || (is_unicode_digit(c) &&        \
+				     ++numeric <= MAXNUMERIC))) {  \
+      while (charlength-- > 0) {                                   \
+        *wptr++ = *(s_in)++; ++length;                             \
+      }                                                            \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+    *(Word) = length;                                              \
+  }while(0)
+
+
+
+/* =========================================================================
+ * Macro: PARSE_NON_WORD
+ * Description: 
+ *      Extract a non-word out for storing compressed text
+ * Input: as above
+ * Output: as above
+ * ========================================================================= */
+#define PARSE_NON_WORD(Word, s_in, end)                            \
+  do {                                                             \
+    register int charlength = 0;                                   \
+    register u_char *wptr = (Word)+1;                              \
+    register int length = 0;                                       \
+    unsigned short c;                                              \
+                                                                   \
+    charlength = parse_utf8_char((s_in),(end),&c);                 \
+                                                                   \
+    while (length+charlength <= MAXWORDLEN && charlength > 0 &&    \
+	   !is_unicode_letdig(c)) {                                \
+      while (charlength-- > 0) {                                   \
+        *wptr++ = *(s_in)++; ++length;                             \
+      }                                                            \
+      charlength = parse_utf8_char((s_in),(end),&c);               \
+    }                                                              \
+    *(Word) = length;                                              \
+  }while(0)
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/Makefile.in	(revision 10506)
@@ -0,0 +1,157 @@
+###########################################################################
+#
+# Makefile -- src/oaiservr
+# 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,2005  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.
+#
+###########################################################################
+
+# set by configure for each makefile (for vpath etc)
+srcdir = @srcdir@
+gs_srcdir = $(srcdir)/../../src
+recpt_srcdir = $(gs_srcdir)/recpt
+colserv_srcdir = $(gs_srcdir)/colservr
+
+AR = ar
+CPP = @CXX@
+INSTALL = @INSTALL@
+
+CXXFLAGS = @CXXFLAGS@
+EXEEXT = @EXEEXT@
+
+
+# -I../../packages/mg -I../../packages/mg/lib -I../../packages/mg/src/text ?
+INCLUDES = -I$(srcdir)/../../lib -I$(colserv_srcdir) -I$(gs_srcdir)/mgpp/lib -I$(gs_srcdir)/mgpp/text -I$(recpt_srcdir)
+
+
+LDFLAGS = @LDFLAGS@
+# need this for linking against recpt/infodbclass.o etc
+GDBM_LIBS=@GDBM_LIBPATH@ -lgdbm
+LIBS = $(GDBM_LIBS) @LIBS@ ../../packages/expat/lib/libexpat.a
+
+
+CXXCOMPILE = $(CPP) -c $(CXXFLAGS) $(INCLUDES)
+CXXLINK = $(CPP) $(LDFLAGS)
+
+EXEC = oaiserver$(EXEEXT)
+
+all: $(EXEC)
+
+# needed to clear builtin rules?
+#.SUFFIXES:
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CXXCOMPILE) -o $@ $< 
+
+
+COMMONHEADERS = oaiargs.h oaiaction.h oaidispatcher.h oaiconfig.h identityaction.h recordaction.h \
+                listrecsaction.h listidsaction.h listsetsaction.h metaformatsaction.h oaitools.h \
+                abstractlistaction.h metaformat.h dublincore.h rfc1807.h resumptiontoken.h
+
+ifeq ($(USE_CORBA), 1)
+LIBRARYHEADERS = nullproto.h z3950proto.h z3950server.h corbaproto.h
+else
+LIBRARYHEADERS = nullproto.h z3950proto.h z3950server.h
+endif
+
+HEADERS = $(COMMONHEADERS) $(LIBRARYHEADERS)
+
+
+COMMONSOURCES = oaiargs.cpp oaiaction.cpp oaidispatcher.cpp oaiconfig.cpp identityaction.cpp recordaction.cpp \
+                abstractlistaction.cpp listrecsaction.cpp listidsaction.cpp listsetsaction.cpp \
+                metaformatsaction.cpp oaitools.cpp metaformat.cpp dublincore.cpp rfc1807.cpp \
+                resumptiontoken.cpp
+
+OAISOURCES = 
+
+SOURCES = $(COMMONSOURCES) $(OAISOURCES)
+
+RECPTOBJECTS = ../../src/recpt/comtypes.o ../../src/recpt/OIDtools.o \
+	../../src/recpt/nullproto.o ../../src/recpt/recptproto.o \
+	../../src/recpt/htmlutils.o ../../src/recpt/infodbclass.o \
+	../../src/recpt/recptconfig.o ../../src/recpt/cgiargs.o \
+	../../src/recpt/cgiutils.o
+
+COMMONOBJECTS = oaiargs.o oaiaction.o oaiconfig.o oaidispatcher.o \
+	identityaction.o recordaction.o abstractlistaction.o listrecsaction.o \
+	listidsaction.o listsetsaction.o metaformatsaction.o oaitools.o \
+	metaformat.o dublincore.o rfc1807.o resumptiontoken.o 
+
+OAIOBJECTS = oaimain.o
+
+OBJECTS = $(COMMONOBJECTS) $(RECPTOBJECTS) $(OAIOBJECTS)
+
+
+COLSERVROBJECTS = ../../src/colservr/mgq.o \
+		  ../../src/colservr/search.o \
+                  ../../src/colservr/mgsearch.o \
+                  ../../src/colservr/querycache.o \
+                  ../../src/colservr/queryinfo.o \
+                  ../../src/colservr/collectserver.o \
+                  ../../src/colservr/colservrconfig.o \
+                  ../../src/colservr/maptools.o \
+                  ../../src/colservr/filter.o \
+                  ../../src/colservr/source.o \
+                  ../../src/colservr/browsefilter.o \
+                  ../../src/colservr/queryfilter.o \
+                  ../../src/colservr/gdbmsource.o \
+                  ../../src/colservr/mggdbmsource.o \
+                  ../../src/colservr/phrasesearch.o \
+                  ../../src/colservr/phrasequeryfilter.o \
+		  ../../src/colservr/mgqueryfilter.o \
+		  ../../src/colservr/mgppsearch.o \
+		  ../../src/colservr/mgppqueryfilter.o \
+		  ../../src/colservr/collectset.o \
+		  ../../src/colservr/lucenesearch.o \
+		  ../../src/colservr/lucenequeryfilter.o \
+	          ../../src/colservr/lucenegdbmsource.o \
+	          ../../src/colservr/expat_resultset.o \
+		../../src/colservr/expat_document.o
+
+distclean:
+	rm -f $(COMMONOBJECTS) $(OAIOBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(COMMONOBJECTS) $(OAIOBJECTS) $(EXEC)
+
+install:
+	$(INSTALL) -m 755 -s $(EXEC) ../../cgi-bin
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CXXFLAGS) -- $(SOURCES)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+OAI_OBJS = $(OBJECTS) $(COLSERVROBJECTS) \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    ../../src/mgpp/text/libtextin.a \
+    ../../src/mgpp/lib/libmg.a
+
+oaiserver$(EXEEXT): $(OAI_OBJS)
+	$(CXXLINK) -o $@ $(OAI_OBJS) $(LIBS) 
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/README.txt
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/README.txt	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/README.txt	(revision 10506)
@@ -0,0 +1,99 @@
+OAI Server Configuration Instructions
+-------------------------------------
+
+Greenstone needs some configuration before successfully supporting OAI serving.  This consists of three steps:
+
+1) Server-wide configuration to support vital OAI commands such as Identify.
+   This allows the OAI client to obtain information on the maintainer of
+   the server, etc.  See the OAI documentation for further information on
+   the Identify verb.  These configurations are kept in gsdl/etc/oai.cfg.
+
+2) Configuring collections to be 'active' OAI collections; just as collections
+   in Greenstone can be 'private' or 'public', collections can similarly be
+   'visible' or 'invisible' to OAI.  By default, collections are NOT served
+   via OAI - you have to enable them by adding each collection's name to a
+   list in gsdl/etc/oai.cfg.
+
+3) Mapping your collection metadata to a "Namespace" supported by OAI.  At
+   present, Greenstone supports the Dublin Core metadata format alone in OAI,
+   and metadata fields in a Greenstone collection must be mapped into the
+   Dublin Core namespace.  This configuration can be done either server-wide,
+   for all collections, in gsdl/etc/oai.cfg or in the etc/collect.cfg of
+   each individual collection.
+
+This documentation explains how to set up Greenstone's configuration for steps 1-3 above, install, deplay and test OAI on your Greenstone system.
+
+Part 1: Server-Wide Configuration Information
+---------------------------------------------
+
+Your OAI server should provide some basic information on the collections it holds as a whole.  For this purpose, all collections on your server are treated the same: you cannot have different information for each collection.  In this section, we describe what information you should provide, and how to configure Greenstone correctly to provide it.
+
+The basic server-wide information is:
+  * The OAI repository (server) name - this is a human readable form such
+    as "The Research Authority's OAI Server".
+  * The central administrative email address for the OAI repository.
+  * The base URL for the repository.
+  * Which version of OAI the repository supports/delivers.
+  * A free text item of information about the OAI repository - e.g. its
+    purpose, size, origins, etc.
+
+These items are kept in the following items of gsdl/etc/oai.cfg.  The syntax rules for these configuration items are the same as for gsdl/etc/main.cfg -  e.g. strings containing spaces should be enclosed in quotation marks.  See the main Greenstone configuration documentation for further information.
+
+  * repositoryName
+       One item only, free text.
+  * maintainer
+       One item only, as a valid email address
+  * httpdomain 
+       NB: in the gsdlsite.cfg file, NOT oai.cfg
+       Should not require specific configuration if your Greenstone install
+       is already operational through your web server.
+  * oaiversion
+       One item only, which should be either "1.1 or "2.0"
+  * oaiinfo
+       Numerous items, which are usually in a label and value pair.
+       An example item may be:
+          oaiinfo sponsor "The Big Cheese Corporation"
+
+Sample items are already provided in the default oai.cfg file - please ensure that you complete these in your preferred text editor.
+
+
+Part 2: Enabling Collections
+----------------------------
+
+In addition to the items above, one further sort of item needs to be added to gsdl/etc/oai.cfg - a list of the collections that should be made available to OAI clients.  This list is supplied in one or more lines in gsdl/etc/oai.cfg in the form:
+
+  oaicollection OAIDemo HDL
+
+The first item in each line should be the same - "oaicollection" - followed by one or more collection names.  Each collection name should be the name of the folder/directory in the gsdl/collect directory which holds the collection.
+
+Once these items have been added to gsdl/etc/oai.cfg, the final stage of the OAI configuration can begin: mapping from a collection's own metdata fields into the Dublin Core metadata fields used by OAI.  This will be detailed in the folloowing section of this document.
+
+
+Part 3: Mapping fields
+----------------------
+
+In Greenstone, metadata fields are created by the collection designer.  These may follow an accepted standard - e.g. Dublin Core - be a modification or extension of an accepted standard, or a bespoke format specific to the needs of the particular collection.  As Greenstone installer, you should have decided upon one of these three approaches already.  You may have chosen one of the standard metadata structures incorporated into the Greenstone Librarian Interface (GLI), or created your own using your own metadata files and automatically extracted information from your document files.  Whatever the approach you have used for obtaining the metadata in your collection, or whatever the fields are that you have used in your collection, the approach to linking these fields (mapping them) to the OAI Dublin Core format is the same.
+
+The mapping of fields is done in two ways: first, globally for all collections, and secondly specifically for one collection.  The syntax for the configuration items to achieve these different mappings is the same.  The file in which they are placed determines whether they apply to all collections, are just one.  Global mappings are found with the other OAI configuration items in gsdl/etc/main.cfg whilst collection-specific mappings are placed in the etc/collect.cfg file of the collection itself.
+
+Mapping items in the configuration file take the following format:
+
+  oaimapping <greenstone fieldname> <dublin core fieldname>
+
+The syntax of each of the two fieldnames given above requires a little more detail; we will take the Dubline Core fieldname first.  
+
+The Dublin Core fieldsname should be given in the form "DC:<fieldname>", as OAI can support other metadata formats, and thus we use "DC:" to be clear that we are mapping to Dublin Core.  The fieldnames available for Dublin Core can be found on the central Dublin Core website at http://www.dublincore.org/.
+
+The Greenstone fieldname can be in two formats.  The simpler one is simply the name of the field to map from.  The more complex one has the name of the collection placed in front of the field name, followed by a colon.  e.g. "demo:Title" would mean the metadata field "Title" in the collection called "demo".  Using this, all mappings can be stored in the central gsdl/etc/oai.cfg file if you wish, and we recommend this approach.
+
+Let us recap at this point with a few example items for a gsdl/etc/oai.cfg:
+
+oaimapping Author dc.Creator
+oaimapping dls.Title  dc.Title
+oaimapping Photos:fileformat dc.Format
+
+The first item maps any occurrence of 'Author' in any collection to the Dublin Core 'Creator' field (there is no 'Author' field in DC).  The second item maps 'dls.Title' to 'dc.Title'. Finally, in the specific collection 'Photos', we will map the unique metadata field 'fileformat' to the Dublin Core 'Format' field.
+
+
+Installation and Testing
+------------------------
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/abstractlistaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/abstractlistaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/abstractlistaction.cpp	(revision 10506)
@@ -0,0 +1,425 @@
+#include "abstractlistaction.h"
+#include "OIDtools.h"
+
+#include "oaitools.h"
+
+// The following makes sure that we don't actually use ResumptionTokens
+#define MAXRECORDS -1
+
+bool abstractlistaction::validateAction(recptproto *protocol, oaiargs &params, int &numArgs)
+{ 
+  text_t from  = params["from"];
+  text_t until = params["until"];
+
+  // from date must be less than, or equal to, until date
+  if ((from != "") && (until != "") && !(from <= until)){
+    this->errorType = "badArgument";
+    return false;
+  }
+
+  if (from != ""){
+    // Must be in the form YYYY-MM-DD
+    if(from.size() != 10){
+      this->errorType = "badArgument";
+      return false;
+    }
+    else{
+      if(from[4] != '-' || from[7] != '-'){
+	this->errorType = "badArgument";
+	return false;
+      }
+    }
+    ++numArgs; // Increase valid args count
+  }
+
+  if (until != ""){
+    // Must be in the form YYYY-MM-DD
+    if(until.size() != 10){
+      this->errorType = "badArgument";
+      return false;
+    }
+    else{
+      if(until[4] != '-' || until[7] != '-'){
+	this->errorType = "badArgument";
+	return false;
+      }
+    }
+    ++numArgs; // Increase valid args count
+  }
+
+  if (params["set"] != "") { 
+    text_t gsdlSet = params["set"];
+    text_t gsdlCollect = "";
+
+    // given 'demo:CL2', toGSDL returns 'demo' in gsdlCollect and 'CL2' in gsdlSet. If there is no further
+    // set specified after the name of the collection however, then gsdlSet is empty.
+    oaiclassifier::toGSDL(gsdlCollect, gsdlSet);
+
+    comerror_t err;
+    ColInfoResponse_t cinfo;
+
+    // check that the collection is accessible
+    protocol->get_collectinfo(gsdlCollect, cinfo, err, cerr);
+    if (err != noError) {
+      this->errorType = "badArgument";
+      return false;
+    }
+
+    // check the child set if it is given
+    if (gsdlSet != "") {
+      if (!this->check_classifier(protocol, gsdlCollect, gsdlSet)) {
+	this->errorType = "badArgument";
+	return false;
+      }
+    }
+    ++numArgs;
+  }
+
+  if (params["resumptionToken"] != "") {
+    ResumptionToken token(params["resumptionToken"]);
+
+    if (!token.isValid()) {
+      this->errorType = "badResumptionToken";
+      return false;
+    }
+    ++numArgs;
+  }
+  
+  this->errorType = "";
+  return true;
+}
+
+//--------------------------------------------------------------------------------------------------
+
+bool abstractlistaction::output_content(ostream &output, recptproto *protocol, oaiargs &params)
+{
+  text_t from = params["from"];
+  text_t until = params["until"];
+  text_t metaFormat = params["metadataPrefix"];
+  bool   prevDocSeen;
+  ResumptionToken *token = NULL;
+
+  // start the call; clear down the total number of output documents
+  this->outputDocs = 0;
+
+  // We don't actually handle resumptionTokens yet; if we get one, ignore it
+  if (params["resumptionToken"] != "") {
+    token = new ResumptionToken(params["resumptionToken"]);
+  }
+
+  // if we've been asked for a set, then use it!
+  if (params["set"] != "") {
+    // get the children of this set
+    text_t gsdlSet = params["set"];
+    text_t gsdlCollect = "";
+
+    // given 'demo:CL2', toGSDL returns 'demo' in gsdlCollect and 'CL2' in gsdlSet. If there is no further
+    // set specified after the name of the collection however, then gsdlSet is empty.
+    oaiclassifier::toGSDL(gsdlCollect, gsdlSet);
+
+    // If gsdlSet is empty, then the user is requesting all the identifiers for the collection, so 
+    // we simply output all docs via their oai_id tag. But if a specific subset IS requested, then
+    // use recurse_set() to traverse any sub classifiers to find the relevant docs.
+    if(gsdlSet == ""){
+      ColInfoResponse_t cinfo;
+      comerror_t err;
+      this->output_content_for_col(output, protocol, gsdlCollect, cinfo, err, params);
+    }
+    else {
+      if (this->check_classifier(protocol, gsdlCollect, gsdlSet)) {
+	this->recurse_set(output, protocol, gsdlCollect, gsdlSet, params);
+      }
+    }
+  }
+  // output all records in all hierarchies
+  else {
+    this->output_content_for_all(output, protocol, params);
+  }
+
+  // If - regardless of set required - no documents have been seen, throw an error.
+  if (this->configuration->getOAIVersion() >= 200 && this->prevDocSeen == false) {
+    errorType = "noRecordsMatch";
+    this->output_error(output, errorType);
+
+    return false;
+  }
+
+  // do a resumption token if required; errors cancel a token...
+  if (this->replyToken != NULL && this->errorType != "") {
+    output << "<resumptionToken>";
+    output << this->replyToken->getToken();
+    output << "</resumptionToken>";
+  }
+
+  return true;
+}
+
+//--------------------------------------------------------------------------------------------------
+
+void abstractlistaction::output_content_for_col(ostream &output, recptproto *protocol, text_t &gsdlCollect,
+						ColInfoResponse_t &cinfo, comerror_t &err, oaiargs &params)
+{ int startDoc = 0;
+
+  // get the collection information
+  protocol->get_collectinfo(gsdlCollect, cinfo, err, *this->logout);
+
+  // check resumption token
+  if (params["resumptionToken"] != "") {
+    ResumptionToken token(params["resumptionToken"]);
+    if (token.getCollection() == gsdlCollect) {
+      startDoc = token.getPosition() - 1; // first document is said to be 1..
+    }
+  }
+  
+  // If numDocs is 0, do nothing - this->prevDocSeen will stay false if this is the only collection
+  // looked at, or will keep whatever value it had prior to this col (ensures that if the flag has
+  // been set to true by a previous collection that this won't overwrite it to be false). 
+  if (cinfo.numDocs > 0) {
+    int errorCount      = 0; // Count the number of errors found in the given collection
+    text_t from         = params["from"];
+    text_t until        = params["until"];
+
+    for (long i = startDoc; i < cinfo.numDocs; ++i) {
+      if (errorCount > 3) { // If num errors reaches the cut-off value, bail.
+	cerr << "Error: too many records(" << errorCount << ") in the " << gsdlCollect 
+	     << " collection have invalid or non-existant oai_ids - skipping remainder of collection.\n";
+	return;
+      }
+      
+      text_t oai_id = "oai.";
+      oai_id += i;
+      
+      text_t gsdl_id = oaiclassifier::getGSDL_OID(gsdlCollect, oai_id, protocol, *this->logout);
+      
+      if (gsdl_id == "") { // If the string is empty, then the document didn't have an oai_id, so
+	++errorCount;     // increase error count
+	continue;
+      }
+      
+      // Check that the item with the HASH ID 'gsdl_id' has a lastmodified field that fits within
+      // the required date range (if specified).
+      if (this->inDateRange(params["from"], params["until"], gsdlCollect, gsdl_id, protocol, output)) {
+	if (this->output_document(output, protocol, gsdlCollect, gsdl_id, params["metadataPrefix"])) {
+	  // this should be an IF statement, where prevDocSeen is only set to true if the above
+	  // function call returns true (indicating that the doc supported the metadata prefix) but
+	  // for some reason this is always false. This means that if no doc in the requested set supports
+	  // the metadata format, the "no records match" error that should be thrown won't be...
+	  //
+	  // GRB: the above comment is no longer true; proper checks are made
+	  this->prevDocSeen = true;
+	  ++this->outputDocs;
+	}
+      }
+
+      // if we've output MAXRECORDS documents; prepare a resumptionToken
+      if (this->outputDocs == MAXRECORDS) {
+	this->replyToken = new ResumptionToken(gsdlCollect, "", "");
+	this->replyToken->setPosition("", i+2);
+	break;
+      }
+    }
+
+    cinfo.clear(); // Clear for next collection to use (if there is one).
+  }
+}
+
+//--------------------------------------------------------------------------------------------
+// Returns true if at least one document record is found
+void abstractlistaction::output_content_for_all(ostream &output, recptproto *protocol, oaiargs &params)
+{
+  ColInfoResponse_t cinfo;
+  comerror_t        err;
+  text_tarray       collections;
+  text_t            gsdlCollect = "";
+
+  // get a list of the collections available
+  protocol->get_collection_list(collections, err, output); 
+  
+  for(int current_col = 0; current_col < collections.size(); ++current_col){
+    gsdlCollect = collections[current_col];
+    this->output_content_for_col(output, protocol, gsdlCollect, cinfo, err, params);
+  }
+}
+
+//-------------------------------------------------------------------------------------------------
+// Check that the requested from/until dates don't include a time, as this would be asking for too
+// fine a level of granularity, one that greenstone doesn't support. An OAI error must be thrown.
+/*
+bool abstractlistaction::granularityTooFine(text_t &from, text_t &until)
+{
+  if (from != "" && from.){
+    
+  }
+  
+}
+*/
+//-------------------------------------------------------------------------------------------------
+
+bool abstractlistaction::check_classifier(recptproto *protocol, const text_t &collection,
+					  const text_t &classifier)
+{ text_t topClass;
+  FilterResponse_t response;
+  text_tset        metadata;
+  ofstream         logout("oai.log", ios::app);
+
+  // exclude false children of a top-level classifier immediately...
+  if (!get_info(classifier, collection, "", metadata, false, protocol, response, logout)) {
+    return false;
+  }
+  
+  // now check the top-level parent
+  metadata.insert("supportsmemberof");
+
+  text_t::const_iterator dot = findchar(classifier.begin(), classifier.end(), '.');
+  if (dot != classifier.end()) {
+    topClass = substr(classifier.begin(), dot);
+  }
+  else {
+    topClass = classifier;
+  }
+
+  if (!get_info(topClass, collection, "", metadata, false, protocol, response, logout)) {
+    return false;
+  }
+  
+  if (response.docInfo[0].metadata["supportsmemberof"].values.size() == 0) {
+    return false;
+  }
+
+  if (response.docInfo[0].metadata["supportsmemberof"].values[0] != "true") {
+    return false;
+  }
+
+  return true;
+}
+
+void abstractlistaction::recurse_set(ostream &output, recptproto *protocol, const text_t &collection, 
+				     const text_t &classifier, oaiargs &params)
+{
+  // metadata for this call
+  FilterResponse_t response;
+  text_tset        metadata;
+  ofstream         logout("oai.log", ios::app);
+  text_t           from = params["from"];
+  text_t           until = params["until"];
+  text_t           metadataPrefix = params["metadataPrefix"];
+  ResumptionToken  resumptionToken(params["resumptionToken"]);
+  int              startPos = 0;
+
+  // This is a recursive function, and so just because the current set is empty doesn't mean we necessarily
+  // want to throw a 'noRecordsMatch' error; another set (parent/sibling/child) may have had documents. It
+  // is therefore not enough to check that the response object in the current iteration has no docs - we
+  // must also verify that NO OTHER set has had any documents. This is done with the 'prevDocSeen' flag.
+  // It is set to FALSE initially, but as soon as we see a set that isn't empty, it is set to TRUE. The 
+  // 'noRecordsMatch' error will only be thrown if, after all appropriate sets have been recursed into, 
+  // the 'prevDocSeen' flag is still FALSE. The function returns false if no docs were seen, allowing us to 
+  // throw the noRecordsMatch error.
+  
+  //  bool prevDocSeen = false;
+
+  get_children(classifier, collection, "", metadata, false, protocol, response, *this->logout);
+
+  if (params["resumptionToken"] != "") {
+    // if we're at a resumptionToken
+    if (classifier == resumptionToken.getNode()) {
+      startPos = resumptionToken.getPosition();
+    }
+    else {
+      text_t fullNode = resumptionToken.getNode();
+      text_t::iterator leafIter = fullNode.begin() + classifier.size();
+
+      // if the next character isn't a dot, blow up!
+      if (*leafIter != '.') {
+	// fatal error;
+	exit(1);
+      }
+      
+      // get the first '.' after the current classifier point;
+      text_t::iterator separator = findchar(leafIter + 1, fullNode.end(), '.');
+
+      // now, create a new subpath
+      text_t nextNode = substr(fullNode.begin(), separator);
+
+      // seek forward; TODO: improve performance of this 
+      for (int c = 0; c < response.numDocs; ++c) {
+	if (response.docInfo[c].OID == nextNode) {
+	  startPos = c;
+	  break;
+	}
+      }
+    }
+  }
+  
+  for (int c = startPos; c < response.numDocs; ++c) {
+    text_t child = response.docInfo[c].OID;
+    
+    // check for HASH items and exclude them
+    text_t childHead;
+    text_t::const_iterator start = child.begin();
+    text_t::const_iterator here  = child.begin();
+    here += 4;
+    childHead = substr(start, here);
+    
+    // documents we output now
+    if (childHead == "HASH") {
+      // Check that the item with the HASH ID 'gsdl_id' has a lastmodified field that fits
+      // within the required date range (if specified)
+      if (this->inDateRange(from, until, collection, child, protocol, output)) {
+	// TODO: check that the document can be disseminated in the required metadataPrefix
+
+	if (this->output_document(output, protocol, collection, child, metadataPrefix)) {
+	  this->prevDocSeen = true;
+	  ++this->outputDocs;
+	}
+      }
+    }
+    // children which are classifiers are recursed
+    else {
+      this->recurse_set(output, protocol, collection, child, params);
+    }
+
+    if (this->outputDocs == MAXRECORDS) {
+      this->replyToken = new ResumptionToken(collection, params["set"], "");
+      this->replyToken->setPosition(classifier, c+2);
+    }
+  }
+}
+
+/*
+bool listrecsaction::recurse_set(ostream &output, recptproto *protocol, const text_t &collection, const text_t &classifier, const text_t &metadataPrefix)
+{
+  FilterResponse_t response;
+  text_tset        metadata;
+  ofstream         logout("oai.log", ios::app);
+  bool             prevDocSeen = false;
+
+  get_children(classifier, collection, metadata, false, protocol, response, logout);
+
+  for (int c = 0; c < response.numDocs; ++c) {
+    text_t child = response.docInfo[c].OID;
+    
+    // check for HASH items and exclude them
+    text_t childHead;
+    text_t::const_iterator start = child.begin();
+    text_t::const_iterator here  = child.begin();
+    here += 4;
+    childHead = substr(start, here);
+    
+    // documents we output now
+    if (childHead == "HASH") {
+      this->output_document(output, protocol, collection, child, metadataPrefix);
+      ++this->outputDocs;
+      prevDocSeen = true;
+    }
+    // children which are classifiers are recursed
+    else {
+      prevDocSeen = this->recurse_set(output, protocol, collection, child, metadataPrefix);
+    }
+  }
+  return prevDocSeen;
+}
+*/
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/abstractlistaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/abstractlistaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/abstractlistaction.h	(revision 10506)
@@ -0,0 +1,26 @@
+#ifndef _ABSTRACTLISTACTION_H_
+#define _ABSTRACTLISTACTION_H_
+
+#include "oaiaction.h"
+#include "resumptiontoken.h"
+
+class abstractlistaction : public oaiaction
+{ 
+ public:
+  abstractlistaction(const text_t &name) : oaiaction(name) {this->prevDocSeen = false;}
+  virtual bool validateAction(recptproto *protocol, oaiargs &params, int &numArgs); // Check that this is a valid action
+  virtual bool output_document(ostream &output, recptproto *protocol, const text_t &collection, 
+			       const text_t &OID, const text_t &metadataPrefix) = 0;
+  virtual bool output_content(ostream &output, recptproto *protocol, oaiargs &params);
+  virtual void output_content_for_all(ostream &output, recptproto *protocol, oaiargs &params);
+  virtual void output_content_for_col(ostream &output, recptproto *protocol, text_t &gsdlCollect, 
+				      ColInfoResponse_t &cinfo, comerror_t &err, oaiargs &params);
+  virtual void recurse_set(ostream &output, recptproto *protocol, const text_t &collection, 
+			   const text_t &classifier, oaiargs &params);
+ protected:
+  bool prevDocSeen;
+  int  outputDocs;
+  ResumptionToken *replyToken;
+  bool check_classifier(recptproto *protocol, const text_t &collection, const text_t &classifier);
+};
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/dublincore.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/dublincore.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/dublincore.cpp	(revision 10506)
@@ -0,0 +1,67 @@
+
+#include "dublincore.h"
+
+const text_t dublin_core::formatName() {
+  return "oai_dc";
+}
+
+const text_t dublin_core::formatPrefix() {
+  return "dc";
+}
+
+bool dublin_core::output_record(ostream &output, recptproto *protocol, const text_t &collection, 
+				const text_t &record_OID) 
+{
+  return metaformat::output_record(output, protocol, collection, record_OID);
+}
+
+void dublin_core::output_metadata_header(ostream &output)
+{ 
+  output << "    <metadata>\n";
+  
+  if (this->oaiConfigure->getOAIVersion() <= 110){
+    // output dublin core wrapper for OAI v1.1
+    output << "      <dc xmlns=\"http://purl.org/dc/elements/1.1/\"\n"
+	   << "          xmlns:xsi=\"http://www.w3c.org/2001/XMLSchema-instance\"\n"
+	   << "          xsi:schemaLocation=\"http://purl.org/dc/elements/1.1/\n"
+	   << "                              http://www.openarchives.org/OAI/1.1/dc.xsd\">\n";
+  }
+  else { 
+    output << "      <oai_dc:dc\n"
+	   << "          xmlns:oai_dc=\"http://www.openarchives.org/OAI/2.0/oai_dc/\"\n"
+	   << "          xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n"
+	   << "          xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+	   << "          xsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/oai_dc/\n"
+	   << "                              http://www.openarchives.org/OAI/2.0/oai_dc.xsd\">\n";
+  }
+}
+
+void dublin_core::output_metadata_footer(ostream &output)
+{
+  if (this->oaiConfigure->getOAIVersion() <= 110) {
+    output << "      </dc>" << endl;
+  }
+  else {
+    output << "      </oai_dc:dc>" << endl;
+  }
+
+  output << "    </metadata>" << endl; 
+  output.flush();
+}
+
+bool dublin_core::output_formatdata(ostream &output)
+{
+  output << "    <metadataPrefix>oai_dc</metadataPrefix>" << endl;
+
+  if (this->oaiConfigure->getOAIVersion() <= 110) {
+    output << "    <schema>http://www.openarchives.org/OAI/1.1/dc.xsd</schema>" << endl
+	   << "    <metadataNamespace>http://purl.org/dc/elements/1.1/</metadataNamespace>" << endl;
+  }
+  else {
+    output << "    <schema>http://www.openarchives.org/OAI/2.0/oai_dc.xsd</schema>" << endl
+	   << "    <metadataNamespace>http://www.openarchives.org/OAI/2.0/oai_dc/</metadataNamespace>" 
+	   << endl;
+  }
+  return true;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/dublincore.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/dublincore.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/dublincore.h	(revision 10506)
@@ -0,0 +1,17 @@
+#include "metaformat.h"
+
+class dublin_core : public metaformat
+{
+ protected:
+  virtual void output_metadata_header(ostream &output);
+  virtual void output_metadata_footer(ostream &output);
+ public:
+  dublin_core() : metaformat(){};
+  virtual const text_t formatName();
+  virtual const text_t formatPrefix();
+  virtual bool output_record(ostream &output, recptproto *protocol, const text_t &collection, 
+			     const text_t &record_OID);
+  virtual bool output_formatdata(ostream &output);
+};
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/identityaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/identityaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/identityaction.cpp	(revision 10506)
@@ -0,0 +1,55 @@
+#include "identityaction.h"
+#include "recptconfig.h"
+
+bool identityaction::validateAction(recptproto *protocol, oaiargs &params)
+{ 
+  //"Verb=Identify" should be the only parameter - if there are others, throw an error.
+  // Don't need to check that the param we have is "Verb=Identify", as it has to be to get to here.
+  
+  if(params.getSize() != 1){
+    this->errorType = "badArgument";
+    return false;
+  }
+  
+  return true;
+}
+
+bool identityaction::output_content(ostream &output, recptproto *protocol, oaiargs &params)
+{
+  text_t gsdlhome, httpdomain, httpprefix;
+  
+  // Get the repository name (some human-readable name for the site, or superset of collections)
+  text_t repositoryName = this->configuration->getCollectionConfig("", "repositoryName");
+  // Get admin's email address (i.e. the site maintainer)
+  text_t maintainer = this->configuration->getCollectionConfig("", "maintainer");
+  // Get baseURL by extracting httpdomain from the gsdlsite.cfg file
+  text_t version = (this->configuration->getOAIVersion() <= 110) ? (text_t)"1.1":(text_t)"2.0";
+
+  site_cfg_read(gsdlhome, httpdomain, httpprefix);
+  
+  output << "  <repositoryName>"  << repositoryName << "</repositoryName>" << endl;
+  output << "  <baseURL>"         << httpdomain     << "/oaimain</baseURL>" << endl; // Tack on the app name
+  output << "  <adminEmail>"      << maintainer     << "</adminEmail>" << endl;
+  output << "  <protocolVersion>" << version        << "</protocolVersion>" << endl;
+
+  if(version == "2.0"){
+    // earliestDatestamp *should* be the YYYY-MM-DD format of the oldest lastmodified record in the
+    // repository, but we're just setting it to be the default oldest possible date - ugly, but judged
+    // not to be worth the effort of trolling through all the lastmodified dates (by others with more 
+    // say than me)
+    output << "  <earliestDatestamp>1970-01-01</earliestDatestamp>\n"
+	   << "  <deletedRecord>no</deletedRecord>\n"
+	   << "  <granularity>YYYY-MM-DD</granularity>\n";
+  }
+  // list all configuration information
+  text_tmap::iterator here = this->configuration->getInformation()->begin();
+  text_tmap::iterator end  = this->configuration->getInformation()->end();
+  while (here != end) {
+    output << "  <" << here->first << ">" << here->second;
+    output << "  </" << here->first << ">" << endl;
+    ++here;
+  }
+  
+  return true;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/identityaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/identityaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/identityaction.h	(revision 10506)
@@ -0,0 +1,13 @@
+#include "oaiaction.h"
+
+#include "oaiconfig.h"
+
+class identityaction : public oaiaction
+{
+ public:
+  identityaction() : oaiaction("Identify") {}
+  virtual bool validateAction(recptproto *protocol, oaiargs &params);
+ protected:
+  bool output_content(ostream &output, recptproto *protocol, oaiargs &params);
+};
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listidsaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listidsaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listidsaction.cpp	(revision 10506)
@@ -0,0 +1,71 @@
+#include "listidsaction.h"
+#include "OIDtools.h"
+#include "oaitools.h"
+
+//--------------------------------------------------------------------------------------------------
+
+bool listidsaction::validateAction(recptproto *protocol, oaiargs &params)
+{ 
+  int numArgs  = 1; // For "verb" arg
+
+  if (!abstractlistaction::validateAction(protocol, params, numArgs)) {
+    return false;
+  }
+
+  // In OAI v1.1 metadataPrefix is not allowed.
+  if (this->configuration->getOAIVersion() <= 110){
+    if(numArgs != params.getSize()){
+      this->errorType = "badArgument";
+      return false;
+    }
+  }
+  else { // In OAI v2.0, it is compulsory
+    text_t metaFormat = params["metadataPrefix"];
+    if (metaFormat == ""){
+      this->errorType = "badArgument";
+      return false;
+    }
+    else { // If it isn't empty, increase the valid args count and compare this to the total num of args
+      if (++numArgs != params.getSize()){
+	this->errorType = "badArgument";
+	return false;
+      }
+    }
+    // Check that the metadataPrefix is a format we support
+    if (this->formatNotSupported(metaFormat)){
+      this->errorType = "cannotDisseminateFormat";
+      return false;
+    }
+  }
+  this->errorType = "";
+  return true;
+}
+
+//--------------------------------------------------------------------------------------------------
+
+bool listidsaction::output_document(ostream& output, recptproto *protocol, const text_t &collection, 
+				    const text_t &OID, const text_t &metadataPrefix /* ignored */)
+{
+  FilterResponse_t response;
+  ResultDocInfo_t  doc_info;
+  text_tset        metadata;
+  ofstream         logout("oai.log", ios::app);
+  text_t           lastModified;
+  int              oaiVersion = this->configuration->getOAIVersion();
+
+  get_info(OID, collection, "", metadata, false, protocol, response, logout);
+  doc_info = response.docInfo[0];
+  this->getLastModifiedDate(doc_info, lastModified);
+  
+  // output the record for this document
+  text_t oaiLabel = OID;
+  oaiclassifier::toOAI(collection, oaiLabel);
+
+  if(oaiVersion <= 110)
+    output << "  <identifier>" << oaiLabel << "</identifier>\n";
+  else
+    this->output_record_header(output, oaiLabel, lastModified, 
+			       doc_info.metadata["memberof"].values, oaiVersion);
+
+  return true;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listidsaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listidsaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listidsaction.h	(revision 10506)
@@ -0,0 +1,12 @@
+#include "abstractlistaction.h"
+
+class listidsaction : public abstractlistaction
+{
+ public:
+  listidsaction() : abstractlistaction("ListIdentifiers") { };
+ protected:
+  bool validateAction(recptproto *protocol, oaiargs &params);
+  bool output_document(ostream &output, recptproto *protocol, const text_t &collection, const text_t &OID,
+		       const text_t &metadataPrefix = "");
+};
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listrecsaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listrecsaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listrecsaction.cpp	(revision 10506)
@@ -0,0 +1,54 @@
+#include "listrecsaction.h"
+
+#include "oaitools.h"
+#include "recordaction.h"
+
+bool listrecsaction::validateAction(recptproto *protocol, oaiargs &params)
+{ 
+  text_t meta    = params["metadataPrefix"];
+  int    numArgs = 1;                // 1st arg (Verb=ListRecords) must be present for us to be here
+
+  if (!abstractlistaction::validateAction(protocol, params, numArgs)) {
+    return false;
+  }
+
+  // metadataPrefix is required - if it's not there, throw an error. Note that the arg isn't 
+  // required (or allowed) if a resumptionToken is given, but as we don't handle resumption
+  // tokens this is sufficient. When we DO handle the tokens, this will have to change.
+  if (meta == "") { 
+    this->errorType = "badArgument";
+    return false;
+  }
+  else {
+    ++numArgs; // If it's there, increase arg count
+  }
+  
+  // The number of valid args should be exactly equal to the number of args actually there.
+  // If not, throw a 'badArgument' error.
+  if (numArgs != params.getSize()) {
+    this->errorType = "badArgument";
+    return false;
+  }
+     
+  if (this->formatNotSupported(meta)) { // Check that the metadataPrefix is supported
+    this->errorType = "cannotDisseminateFormat";
+    this->record_action->setErrorType(this->errorType);
+    return false;
+  }
+
+  return true;
+}
+
+//-----------------------------------------------------------------------------------------------
+
+bool listrecsaction::output_document(ostream &output, recptproto *protocol, const text_t &collection, 
+		     const text_t &OID, const text_t &metadataPrefix)
+{
+  this->record_action->output_record(output, protocol, collection, OID, metadataPrefix);
+  return true;
+}
+  
+//-----------------------------------------------------------------------------------------------
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listrecsaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listrecsaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listrecsaction.h	(revision 10506)
@@ -0,0 +1,16 @@
+#include "abstractlistaction.h"
+
+#include "recordaction.h"
+
+class listrecsaction : public abstractlistaction
+{
+ public:
+  void set_recordMaker(recordaction *ptr) { this->record_action = ptr; }
+  listrecsaction() : abstractlistaction("ListRecords") { };
+  
+ protected:
+  recordaction *record_action;
+  virtual bool validateAction(recptproto *protocol, oaiargs &params);
+  bool output_document(ostream &output, recptproto *protocol, const text_t &collection, 
+		     const text_t &OID, const text_t &metadataPrefix);
+};
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listsetsaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listsetsaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listsetsaction.cpp	(revision 10506)
@@ -0,0 +1,165 @@
+#include "listsetsaction.h"
+
+#if defined(GSDL_USE_STL_H)
+#include <fstream.h>
+#else
+#include <fstream>
+#endif
+
+#include "OIDtools.h"
+#include "oaitools.h"
+
+bool listsetsaction::validateAction(recptproto *protocol, oaiargs &params)
+{ if(params.getSize() != 1){
+    this->errorType = "badArgument";
+    return false;
+  }
+
+  return true;
+}
+
+bool listsetsaction::output_content(ostream &output, recptproto *protocol, text_tset &collections, oaiargs &params)
+{
+  text_tset::iterator here = collections.begin();
+  text_tset::iterator end  = collections.end();
+  while (here != end) {
+    text_t collect = *here;
+    this->output_content(output, protocol, params);
+    ++here;
+  }
+  return true;
+}
+
+bool listsetsaction::output_content(ostream &output, recptproto *protocol, oaiargs &params)
+{
+  // output the total list of classifier points
+
+  // variables required
+  text_t browseOID = "browse";
+  FilterResponse_t response;
+  comerror_t       err;
+  text_tarray &    collections = this->configuration->getCollectionsList();
+  text_tset        metadata;
+  ofstream         logout("oai.log", ios::app);
+  text_tarray *result = new text_tarray;
+  
+  // get a list of the collections available
+  //  protocol->get_collection_list(collections, err, output); 
+  if (collections.size() == 0) {
+    logout << "Found *no* OAI collections - check main.cfg for oaicollection items and read the OAI documentation.\n";
+  }
+
+  for(int current_col = 0; current_col < collections.size(); ++current_col) {
+    // output the collection as a set, first, then its children
+    text_t gsdlCollect = collections[current_col];
+
+    output << "  <set>" << endl;
+    output << "    <setSpec>" << gsdlCollect << "</setSpec>" << endl;;
+    output << "    <setName>" << gsdlCollect << "</setName>" << endl;
+    output << "  </set>" << endl;
+
+    // get all the children of the (relevant) classifier data structures
+    get_children(browseOID, gsdlCollect, "", metadata, false, protocol, response, logout);
+  
+    // and send them to the "recurse_content" list
+    for (int c = 0; c < response.numDocs; ++c) {
+      this->recurse_content(output, protocol, gsdlCollect, response.docInfo[c].OID, gsdlCollect);
+    }
+  }
+
+  return true;
+}
+
+void listsetsaction::recurse_content(ostream &output, recptproto *protocol, text_t &collection, 
+				     const text_t &classifier, text_t setHierarchy)
+{
+  // metadata for this call
+  FilterResponse_t response;
+  text_tset        metadata;
+  ofstream         logout("oai.log", ios::app);
+
+  metadata.insert("contains");
+  metadata.insert("Title");
+  metadata.insert("supportsmemberof");
+
+  // get the document information
+  if (!get_info(classifier, collection, "", metadata, false, protocol, response, logout)) {
+    // cerr << "Bad identifier or protocol " << classifier << endl;
+    return;
+  }
+
+  // check for top-level classifiers, check if the set name includes a '.'; if 
+  // not, it is a top-level classifier: check for memberof support.  Those without
+  // memberof support will not be supported on OAI
+  if (findchar(classifier.begin(), classifier.end(), '.') == classifier.end()) {
+    if (response.docInfo[0].metadata["supportsmemberof"].values.size() > 0) {
+      text_t memberOf = response.docInfo[0].metadata["supportsmemberof"].values[0];
+      if (memberOf != "true") {
+	return;
+      }
+    }
+    else {
+      return;
+    }
+  }
+
+  MetadataInfo_tmap::iterator here = response.docInfo[0].metadata.begin();
+  MetadataInfo_tmap::iterator end  = response.docInfo[0].metadata.end();
+  text_t title;
+
+  while (here != end)
+  {
+    // Each set should only have one title - hence we only output one title here
+    // (it is a set title, not a collection)
+    if (here->first == "Title" && here->second.values.size() > 0) {	
+      title = here->second.values[0];
+    }
+
+    ++here;
+  }
+
+  // output the xml for this set; use the classifier id for the name
+  // if the title is blank
+  output << "  <set>" << endl;
+  text_t oai_classifier = classifier;
+  oaiclassifier::toOAI(collection, oai_classifier);
+  output << "    <setSpec>" << oai_classifier << "</setSpec>" << endl;
+  output << "    <setName>";
+  // curSet holds the colon-separated sequence of parent sets of the current set
+  text_t curSet;
+  if (!title.empty()) {
+    curSet = setHierarchy + ":" + title;
+  }
+  else {
+    curSet = classifier; // Pretty much never gets here (shouldn't, at least)
+  }
+  output << curSet;
+  output << "</setName>" << endl;
+  output << "  </set>" << endl;
+
+  // get the children of this classifier and iterate them
+  get_children(classifier, collection, "", metadata, false, protocol, response, logout);
+  for (int c = 0; c < response.numDocs; ++c) {
+    text_t child = response.docInfo[c].OID;
+
+    if (child == classifier)
+      continue;
+
+    // check for HASH items and exclude them
+    text_t childHead;
+    text_t::const_iterator start = child.begin();
+    text_t::const_iterator here  = child.begin();
+    here += 4;
+    childHead = substr(start, here);
+
+    if (childHead == "HASH")
+      continue;
+
+    // Recurse for "proper" classifier children. Pass curSet, the colon-separated list of 
+    // parent sets. curSet is pass-by-value, so that as we step out of recursion we remember
+    // old set hierarchies.
+    this->recurse_content(output, protocol, collection, child, curSet);
+  }
+  
+  return;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listsetsaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listsetsaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/listsetsaction.h	(revision 10506)
@@ -0,0 +1,13 @@
+#include "oaiaction.h"
+
+class listsetsaction : public oaiaction
+{
+ public:
+  listsetsaction() : oaiaction("ListSets") { };
+  virtual bool validateAction(recptproto *protocol, oaiargs &params);
+  bool output_content(ostream &output, recptproto *protocol, text_tset &collections, oaiargs &params);
+ protected:
+  bool output_content(ostream &output, recptproto *protocol, oaiargs &params);
+  void recurse_content(ostream &output, recptproto *protocol, text_t &collection, const text_t &classifier, 
+		       text_t setHierarchy);
+};
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformat.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformat.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformat.cpp	(revision 10506)
@@ -0,0 +1,167 @@
+#include "metaformat.h"
+
+#include <fstream>
+
+#include "OIDtools.h"
+
+metaformat::metaformat()
+{
+}
+
+text_t metaformat::get_mapping(const text_t &collection, const text_t &collectionField)
+{
+  if (this->oaiConfigure == NULL) {
+    return "";
+  }
+
+  return this->oaiConfigure->getMapping(collection, collectionField, this->formatPrefix());
+}
+
+void metaformat::output_item(ostream &output, bool &headerDone, const text_t &label, 
+			     const text_tarray &values)
+{ 
+  if (!headerDone && (values.size() > 0)) {
+    this->output_metadata_header(output);
+    headerDone = true;
+  }
+
+  for (int item = 0; item < values.size(); ++item) {
+    if (this->oaiConfigure->getOAIVersion() >= 200) { // TODO: GRB: This code may need to be subclassed by dc for 200 and later...
+      output << "        <" << this->formatPrefix() << ":" << label << ">" << values[item] << "</" << this->formatPrefix() << ":" << label << ">\n";
+    }
+    else {
+      output << "        <" << label << ">" << values[item] << "</" << label << ">\n";
+    }
+  }
+}
+
+bool metaformat::scan_metadata(ostream &output, const text_t &collection, ResultDocInfo_t &docInfo,
+			       bool doOutput) 
+{ 
+  bool headerDone = false;
+  MetadataInfo_tmap::iterator here = docInfo.metadata.begin();
+  MetadataInfo_tmap::iterator end = docInfo.metadata.end();
+
+  // metaItem is used initially to identify the rfc1807 (etc) metadata items. It is 
+  // then used to hold the name of the metadata item, such as "title" or "subject".
+  text_t metaItem;
+  text_t::const_iterator start, last; // Use two iterators to go through metaItem
+  
+  while (here != end) {
+    start = last = here->first.begin();
+
+    if (here->first.size() < this->formatPrefix().size() ||
+	here->first[this->formatPrefix().size()] != '.') {
+      metaItem == "";
+    }
+    else {
+      last += this->formatPrefix().size() + 1; // Move last so that it is one place beyond where the "." should be.
+      metaItem = substr(start, last);          // Gets the substring starting at start and going up to (but
+                                               // not including) last. This should be "dc." (for example)
+    }
+
+    if (metaItem == this->formatPrefix()) {
+      metaItem = substr(last, here->first.end()); // Get the rest of the metadata tag (it's name)
+      lc(metaItem); // Convert it to lowercase for putting in the xml tags
+
+      if (doOutput) {
+	this->output_item(output, headerDone, metaItem, here->second.values);
+      }
+      else {
+	if (here->second.values.size() > 0) {
+	  return true;
+	}
+      }
+    }  
+    else {
+      text_t mapTo = this->get_mapping(collection, here->first);
+      if (mapTo != "") {
+	// Do we actually want to do anything here? Doesn't getting here imply that this 
+	// particular metadata is stuff we don't want?
+	if (doOutput) {
+	  this->output_item(output, headerDone, mapTo, here->second.values);
+	}
+	else {
+	  if (here->second.values.size() > 0) {
+	    return true;
+	  }
+	}
+      }
+    }
+
+    ++here;
+  }
+
+  if (!doOutput) {
+    return false;
+  }
+  
+  if (headerDone) {
+    this->output_metadata_footer(output);
+  }
+  
+  return headerDone;
+}
+
+
+bool metaformat::is_available(const text_t &collection, ResultDocInfo_t &docInfo)
+{ 
+  ofstream o("dummy", ios::out);
+  return this->scan_metadata(o, collection, docInfo, false);
+}
+
+bool metaformat::output_metadata(ostream &output, const text_t &collection, ResultDocInfo_t &docInfo) 
+{ 
+  return this->scan_metadata(output, collection, docInfo, true);
+}
+
+bool metaformat::output_record(ostream &output, recptproto *protocol, const text_t &collection, 
+			       const text_t &OID) 
+{
+  FilterResponse_t response;
+  text_tset        metadata;
+  ofstream         logout("oai.log", ios::app);
+
+  // get the document information
+  if (!get_info(OID, collection, "", metadata, false, protocol, response, logout)) {
+    // TODO: error, bad request
+    //   cerr << "Bad identifier or protocol " << OID << endl;
+    return false;
+  }
+
+  // check to see if it's a classifier
+  text_t childHead;
+  //  int oaiVersion = this->oaiConfigure->getOAIVersion();
+  text_t::const_iterator start = OID.begin();
+  text_t::const_iterator here  = OID.begin();
+  here += 4;
+  childHead = substr(start, here);
+
+  // if it isn't a document, kill it now
+  if (childHead != "HASH") {
+    //    cerr << "Not a document" << endl;
+    return false;
+  }
+
+  // output record header
+  output << "<record>\n";
+
+  // output header part of oai response
+  output << "<header>" << endl;
+  output << "  <identifier>" << OID << "</identifier>" << endl;
+  // TODO: add modified date
+
+  output << "</header>" << endl;
+
+  // output metadata part of oai response
+  this->output_metadata(output, collection, response.docInfo[0]);
+
+  // output the description of the document
+  //  output << "<about>\n";
+  //  output << "</about>\n";
+
+  // close record
+  output << "</record>\n";
+    
+  return true;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformat.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformat.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformat.h	(revision 10506)
@@ -0,0 +1,56 @@
+/**
+ *  A framework class for metadata formats.
+ *
+ *  Example child classes include oaimeta and rfc8507meta
+ */
+
+#ifndef _METAFORMAT_H_
+#define _METAFORMAT_H_
+#include <stdio.h>
+
+#include "text_t.h"
+#include "comtypes.h"
+#include "recptproto.h"
+
+#include "oaiconfig.h"
+
+class metaformat
+{  
+ protected:
+  virtual void output_metadata_header(ostream &output) = 0;
+  virtual void output_item(ostream &output, bool &headerDone, const text_t &label, 
+			   const text_tarray &values);
+  virtual void output_metadata_footer(ostream &output) = 0;
+  virtual bool scan_metadata(ostream &output, const text_t &collection,  ResultDocInfo_t &docInfo, 
+			     bool doOutput);
+  oaiconfig *    oaiConfigure;
+
+ public:
+  metaformat(); // Must be given the desired oai version when created 
+  virtual const text_t formatName() = 0;
+  virtual const text_t formatPrefix() = 0;
+  virtual bool output_record(ostream &output, recptproto *protocol, const text_t &collection, 
+			     const text_t &record_OID);
+  virtual bool is_available(const text_t &collection, ResultDocInfo_t &docInfo);
+  virtual bool output_metadata(ostream &output, const text_t &collection,  ResultDocInfo_t &docInfo);
+  virtual bool output_formatdata(ostream &output) = 0;
+  void    set_configuration(oaiconfig *config) { this->oaiConfigure = config; }
+  text_t  get_mapping(const text_t &collection, const text_t &collectionField);
+
+};
+
+class metaformatptr
+{
+ public:
+  metaformat *ptr;
+
+  metaformatptr() { this->ptr = NULL; }
+  metaformat *get_class() { return this->ptr; }
+  void set_class(metaformat *ptr) { this->ptr = ptr; }
+  void set_configuration(oaiconfig *config) { this->ptr->set_configuration(config);}
+  void clear() { delete this->ptr; this->ptr = NULL; }
+};
+
+typedef	map<text_t, metaformatptr, lttext_t> metaformat_map;
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatsaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatsaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatsaction.cpp	(revision 10506)
@@ -0,0 +1,104 @@
+#include "metaformatsaction.h"
+#include "metaformat.h"
+#include "oaitools.h"
+
+bool metaformatsaction::validateAction(recptproto *protocol, oaiargs &params)
+{ 
+  int numArgs = 1; // the number of expected arguments
+  
+  // increase the number of expected arguments if the optional 'identifier' argument
+  // is given 
+  if (params["identifier"] != "") {
+    ++numArgs;
+  }
+
+  // If the total number of params isn't equal to the number of valid
+  // args (i.e. we have an arg but it isn't the identifier), throw an error  
+  if((params.getSize() != numArgs)){
+    this->errorType = "badArgument";
+    return false;
+  }
+
+  // Variables to hold identifier in Greenstone format
+  text_t docID = params["identifier"]; 
+  text_t collection = "";
+
+  // The following two variables are used solely by the get_info() function call to test if
+  // the identifier supplied is an actual document. If it isn't, we need to throw an exception.
+  const text_tset metadata;
+
+  // Check for the existence, etc. of the record if an identifier is given.
+  if (docID != "") {
+    oaiclassifier::toGSDL(collection, docID);
+    
+    // Only throw an error if we're using v2.0. 
+    // v1.1 should simply return a response without a metadataFormat container. 1.1
+    // should still set the errorType so we know that the error was encountered
+
+    // the information retrieved here is retained for the output_content function below
+    if (!get_info(docID, collection, "", metadata, false, protocol, this->gsdlResponse, cerr)){
+      this->errorType = "idDoesNotExist";
+      if(this->configuration->getOAIVersion() >= 200) {
+	return false;
+      }
+    }
+  }
+  return true;
+}
+
+bool metaformatsaction::output_content(ostream &output, recptproto *protocol, oaiargs &params)
+{
+  // if an identifier parameter is being used, then respond to it - currently we reject anything other
+  // than dublin core (unqualified)
+  //
+  // TODO: only return the selected identifier (if given) and don't validate the entry; just
+  //       return nothing if an invalid or unknown metadata format is given
+  
+  // give the required xml response
+
+  text_t gsdlId = params["identifier"];
+  text_t gsdlCollect;
+
+  // convert record identifier into GSDL format from OAI
+  if (gsdlId != "") {
+    oaiclassifier::toGSDL(gsdlCollect, gsdlId);
+  }
+  
+  metaformat_map::iterator here = this->formats->begin();
+  metaformat_map::iterator end  = this->formats->end();
+
+  // v1.1 should check that the id - if supplied - didn't cause an error. If it did,
+  // don't output the metadataFormat tags. OAI v2.0 should already have bailed.
+  if(this->errorType != "idDoesNotExist"){
+    while (here != end) { // Loop through the repository's supported metadata formats
+      bool doOutput = true;
+      
+      // if we were given an identifier, then check if it supports the metadata format in question
+      if (gsdlId != "") {
+	doOutput = here->second.get_class()->is_available(gsdlCollect, this->gsdlResponse.docInfo[0]);
+      }
+
+      if (doOutput) {
+	output << "  <metadataFormat>" << endl;
+	here->second.get_class()->output_formatdata(output);
+	output << "  </metadataFormat>\n";
+      }
+      ++here;
+    }
+  }
+
+  return true;
+}
+
+void metaformatsaction::setConfiguration(oaiconfig *configuration)
+{
+  this->configuration = configuration;
+
+  metaformat_map::iterator here = this->formats->begin();
+  metaformat_map::iterator end  = this->formats->end();
+  while (here != end) {    
+    here->second.set_configuration((oaiconfig *) configuration);
+    ++here;
+  }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatsaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatsaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatsaction.h	(revision 10506)
@@ -0,0 +1,16 @@
+#include "oaiaction.h"
+#include "metaformat.h"
+#include "OIDtools.h"
+
+class metaformatsaction : public oaiaction
+{
+ public:
+  metaformatsaction() : oaiaction("ListMetadataFormats") { };
+  void set_formats(metaformat_map *formats) { this->formats = formats; }
+  virtual void setConfiguration(oaiconfig *configuration);
+  virtual bool validateAction(recptproto *protocol, oaiargs &params);
+ protected:
+  metaformat_map * formats;
+  FilterResponse_t gsdlResponse;
+  bool output_content(ostream &output, recptproto *protocol, oaiargs &params);
+};
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatters.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatters.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatters.cpp	(revision 10506)
@@ -0,0 +1,36 @@
+#include "metaformatters.h"
+
+#include "dublincore.h"
+
+metaformatters::metaformatters() {
+  this->addFormat(new dublin_core);
+}
+
+/**
+ * Destructor code for the metaformatters class
+ */
+metaformatters::~metaformatters() {
+  vector<metaformat *>::iterator here = this->formatters.begin();
+  vector<metaformat *>::iterator end = this->formatters.end();
+  
+  // destroy the formatters themselves
+  while (here != end)
+    {
+      delete here->second;
+      ++here;
+    }
+}
+
+bool metaformatters::output_record(ostream &output, recptproto *protocol, text_t & collection, text_t &record_OID, text_t &format) {
+  
+}
+
+metaformat *metaformatters::getFormat(text_t &name)
+{
+  return this->formatters[name];
+}
+
+void metaformatters::addFormat(metaformat *formatter)
+{
+  this->formatters.push_back(formatter->getName(), formatter);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatters.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatters.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/metaformatters.h	(revision 10506)
@@ -0,0 +1,14 @@
+#include "metaformat.h"
+
+#include <map>
+
+class metaformatters {
+ public:
+  metaformatters();
+  ~metaformatters();
+  bool output_record(ostream &output, recptproto *protocol, text_t &collection, text_t &record_OID, text_t formatName);
+ protected:
+  map<text_t, metaformat *> formatters;
+  addFormat(metaformat *formatter);
+  metaformat *getFormat(text_t &formatName);
+};
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiaction.cpp	(revision 10506)
@@ -0,0 +1,469 @@
+#include "oaiaction.h"
+#include "oaitools.h"
+#include "OIDtools.h"
+#include "recptconfig.h"
+
+#include <string>
+#if defined(GSDL_USE_IOS_H)
+#  if defined(__WIN32__)
+#    include <strstrea.h> // vc4
+#  else
+#    include <strstream.h>
+#  endif
+#else
+#  include <sstream>
+#endif
+
+#include <time.h>
+
+oaiaction::oaiaction(const text_t &name)
+{
+  this->logout = new ofstream("oai.log", ios::app);
+  this->configuration = NULL;
+  this->name = name;
+}
+
+//----------------------------------------------------------------------------------------------
+
+// Over-ridden by child classes
+bool oaiaction::validateAction(recptproto *protocol, oaiargs &params)
+{ 
+  this->errorType = ""; 
+  return true;
+}
+
+//----------------------------------------------------------------------------------------------
+
+/**********
+ * Compare the supplied metadataPrefix to all those that
+ * are supported. If there is NO match, return true. If 
+ * it DOES match one, return false.
+ */
+bool oaiaction::formatNotSupported(text_t &metaFormat)
+{
+  if (metaFormat == "oai_dc") return false;
+  else if (metaFormat == "rfc1807") return false;
+
+  return true;
+}
+
+//----------------------------------------------------------------------------------------------
+
+/**********
+ * Function for outputting the appropriate error(s) with the (version 2.0) request.
+ * The error(s) MUST be included in the response, and take the form:
+ * <error code="errorType">Description of error</error>
+ */
+void oaiaction::output_error(ostream &output, text_t &errorType)
+{
+  text_t description = "";
+
+  if(errorType == "badArgument"){
+    description = "The request includes illegal arguments, is missing required arguments, repeats arguments or the value for an argument has an illegal syntax";
+  }
+  else if(errorType == "noRecordsMatch"){
+    description = "No record matches all the requested parameters";
+  }
+  else if(errorType == "cannotDisseminateFormat"){
+    description = "The metadata format specified is not supported by the item or by the repository";
+  }
+  else if(errorType == "idDoesNotExist"){
+    description = "The value of the identifier is unknown or illegal in this repository";
+  }
+  else if(errorType == "badVerb"){
+    description = "Value of the verb argument is illegal, missing, or repeated";
+  }
+  else if(errorType == "noMetadataFormats"){
+    description = "There are no metadata formats available for the item";
+  }
+  else if(errorType == "badResumptionToken"){
+    description = "The value of the resumptionToken argument is invalid or expired";
+  }
+  else if(errorType == "noSetHierarchy"){
+    description = "The repository does not support sets";
+  }
+
+  output << "  <error code=\"" << errorType << "\">" << description << "</error>\n";
+}
+
+//----------------------------------------------------------------------------------------------
+
+text_t oaiaction::getName()
+{
+  return this->name;
+}
+
+//----------------------------------------------------------------------------------------------
+
+/**********
+ * Used in version 2.0 to provide the <datestamp> tag for each document. The function is passed
+ * the 'last modified' date of the file in epoch time (time in seconds since 1970-01-01 on Unix 
+ * systems) and converts it to YYYY-MM-DD format. 
+ */
+text_t oaiaction::parseDatestamp(time_t &rawtime)
+{
+  text_t year, month, day, lastModified;
+  tm *ptm;
+  ptm = gmtime(&rawtime);
+  int raw_month = ptm->tm_mon + 1;
+  int raw_day = ptm->tm_mday;
+
+  year = (ptm->tm_year + 1900); // Takes off 1900 for year by default, so replace it to get YYYY format
+
+  // Need the month in MM format, so if month is 1..9, add a 0 to the front
+  if(raw_month < 10){    
+    month = "0";
+    month += raw_month;
+  }
+  else month = raw_month;
+
+  if(raw_day < 10){    
+    day  = "0";
+    day += raw_day;
+  }
+  else day = raw_day;
+  
+  lastModified = year + "-" + month + "-" + day;
+
+  return lastModified;
+}
+
+//----------------------------------------------------------------------------------------------
+/**********
+ * Used by both versions to get the date & time of the client's request. The <responseDate> tag is
+ * in the format YYYY-MM-DDTHH:MM:SSZ, where T is simply the letter 'T' and Z is the local offset from
+ * GMT (now UTC). Examples of Z are +12:00 (NZ) or -03:00 for version 1.1. In version 2.0, the time
+ * is expected to be in UTC, and Z should simply be the character 'Z'.
+ */
+void oaiaction::getResponseDate(text_t &date)
+{
+  time_t rawtime;
+  tm    *ptm;
+
+  time(&rawtime);         // Get the epoch time
+
+  ptm = gmtime(&rawtime); // Convert to UTC-time formatted tm object
+
+  text_t month, day, hour, minute, second;
+  int    raw_month  = ptm->tm_mon + 1;  // Note Jan = 0 ... Dec = 11, so add 1
+  int    raw_day    = ptm->tm_mday;
+  int    raw_hour   = ptm->tm_hour;
+  int    raw_minute = ptm->tm_min;
+  int    raw_second = ptm->tm_sec;
+
+  // Need the month in MM format, so if month is 1..9, add a 0 to the front
+  if(raw_month < 10){    
+    month = "0";
+  }
+  month += raw_month;
+  
+  // Same for days, hours, minutes and seconds
+  if(raw_day < 10){    
+    day = "0";
+  }
+  day += raw_day;
+
+  if(raw_hour < 10){    
+    hour = "0";
+  }
+  hour += raw_hour;
+
+  if(raw_minute < 10){    
+    minute = "0";
+  }
+  minute += raw_minute;
+  
+  if(raw_second < 10){    
+    second = "0";
+  }
+  second += raw_second;
+ 
+  // Want YYYY-MM-DDTHH:MM:SS+UTC, where UTC is num hours from UTC(GMT) to localtime
+  date += (ptm->tm_year + 1900); // Takes off 1900 for year, so replace it to get YYYY format
+  date += "-";
+  date += month;
+  date += "-";
+  date += day;
+  date += "T";
+  date += hour;
+  date += ":";
+  date += minute;
+  date += ":";
+  date += second;
+  // If we're using v1.1, then tack on local time offset, otherwise don't
+  if(this->configuration->getOAIVersion() == 110){
+    date += _LOCALTIME_; // Defined in oaiaction.h. States how many hours localtime is from 
+                         // UTC (GMT), e.g. "+8:00", "-5:00"
+  }
+  else
+    date += "Z";         // If v2.0, we put 'Z' on the end rather than the localtime offset
+}
+
+//----------------------------------------------------------------------------------------------
+/**********
+ * Does different request tags depending on the version of the OAI protocol running
+ */
+void oaiaction::getRequestURL(oaiargs &params, text_t &requestURL)
+{
+  // Iterators for moving through the list of parameters (keys) specified
+  text_tmap::const_iterator here;
+  text_tmap::const_iterator end;
+  int numArgs = params.getSize();
+  text_t gsdlhome, httpdomain, httpprefix;
+
+  here = params.begin();
+  end  = params.end();
+  
+  // Read stuff from the gsdlsite.cfg file. We do this to get the base URL (httpdomain)
+  site_cfg_read(gsdlhome, httpdomain, httpprefix); 
+
+  int version = this->configuration->getOAIVersion();
+  
+  switch(version){
+  case 110:
+    /* Takes the form:
+     * <requestURL>http://baseURL.com/oaimain?verb="someVerb"&amp;key=value</requestURL>
+     */
+    requestURL = "  <requestURL>" + httpdomain + "/oaimain";
+    
+    if(numArgs == 0) break; // If no args, all done - the error will be picked up later 
+    
+    // The following lines will give us the "label=value" syntax
+    requestURL += "?";
+    requestURL += here->first;
+    requestURL += "=";
+    requestURL += html_safe(here->second); // parse the argument to ensure it is URL-encoding compliant
+    ++here;
+    
+    while(here != end){
+      requestURL +="&amp;"; // Stick in the ampersand in URL encoding
+      requestURL += (here->first + "=" + html_safe(here->second));
+      ++here;
+    }
+    requestURL += "</requestURL>\n";
+    break;
+  
+  case 200:
+  default:
+    /* Takes the form:
+     * <request verb="someVerb" key="value" key="value">
+     *          http://baseURL.com/oaimain</request>
+     */
+    if(numArgs == 0) {
+      requestURL = "  <request>" + httpdomain + "/oaimain</request>\n";
+      break;
+    }
+    requestURL = "  <request " + here->first + "=\"" + here->second + "\"";
+    ++here;
+    while(here != end){
+      requestURL += (" " + here->first + "=\"" + here->second + "\"");      
+      ++here;
+    }
+    requestURL += ">\n           " + httpdomain + "/oaimain</request>\n";
+    break;
+  }
+}
+
+//----------------------------------------------------------------------------------------------
+/**********
+ * Send the (OAI version-dependent) response text to the output stream
+ */
+void oaiaction::getResponse(ostream &output, recptproto *protocol, oaiargs &params)
+{
+  bool   error;
+  text_t date, requestURL;
+
+  // Write the response date & time into 'date'
+  this->getResponseDate(date);
+  int version = this->configuration->getOAIVersion();
+
+  // validate the action
+  error = !this->validateAction(protocol, params);
+
+  // raise an error for duplicated arguments and set the
+  // error type "manually" here...
+  if (params.hasDuplicateArg() && !error) {
+    this->errorType = "badArgument";
+    error = true;
+  }
+
+  // start with the required http header
+  if (version <= 110 && error){
+    output << "Status: 400 " << this->errorType << "\n";
+    output << "Content-Type: text/xml\n\n";
+    return;
+  }
+  
+  output << "Status: 200\n";
+  output << "Content-Type: text/xml\n\n";
+  
+  // output xml header parts
+  output << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
+
+  if(version <= 110){
+    // output OAI v1.1 action header tag
+    output << "<" << this->name;
+    output << "\n       xmlns=\"http://www.openarchives.com/OAI/1.1/OAI_" << this->name << "\" ";
+    output << "\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ";
+    output << "\n       xsi:schemaLocation=\"http://www.openarchives.org/OAI/1.1/OAI_" << this->name;
+    output << "\n           http://www.openarchives.org/OAI/1.1/OAI_" << this->name << ".xsd\">\n";
+  }
+  else { 
+    // output OAI v2.0 action header tag
+    output << "<OAI-PMH xmlns=\"http://www.openarchives.com/OAI/2.0\"\n"
+	   << "         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+	   << "         xsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/\n"
+	   << "             http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd\">\n";
+  }
+  // output current time for response
+  output << "  <responseDate>" << date << "</responseDate>\n";
+ 
+  // output request URL. This differs depending on the OAI protocol version currently running, so
+  // the entire field - including tags - must be put into the text_t variable by getRequestURL()
+  this->getRequestURL(params, requestURL);
+
+  output << requestURL ;
+
+  if (error == false) {
+    // a string stream to write the content of the action to; this is done so that we can
+    // avoid outputting the action tag if the action's body is unsuccessful, in which
+    // case the leading tag must be suppressed
+#if defined(GSDL_USE_IOS_H)
+    ostrstream outstream;
+#else
+    ostringstream outstream;
+#endif
+
+    // Version 2.0 needs an <Identify>, etc. tag after the OAI-PMH header, IF there is no error
+    //
+    // An action that outputs no content should raise an error state to suppress the 
+    // matching opening and close tags if it outputs no content in OAI 2.0
+    error = !this->output_content(outstream, protocol, params);
+
+    // output the leading tag if no error occurred
+    if (error == false) {
+      if (version >= 200) {
+	this->output_action_tag(output, true);
+      }
+    }
+
+    // now output the body of the action content
+#if defined(GSDL_USE_IOS_H)
+    outstream << ends;  // Ensure outstream is null-terminated correctly
+#endif
+    output << outstream.str();
+  }
+  else {
+    if (version >= 200) {
+      this->output_error(output, this->errorType);
+    }
+  }
+
+  // close out our response - both versions need this line, but v2.0 only needs it if there was no error
+  if((version == 110) || (version >= 200 && error == false)){
+    this->output_action_tag(output, false);
+  }
+  if(version >= 200){
+    output << "</OAI-PMH>\n";
+  }
+}
+
+void oaiaction::output_action_tag(ostream &output, bool openTag)
+{
+  output << " <";
+  if (!openTag) {
+    output << "/";
+  }
+  output << this->name << ">" << endl;
+}
+
+void oaiaction::output_record_header(ostream &output, const text_t &oaiLabel, const text_t &lastModified, 
+				     const text_tarray &memberOf, int oaiVersion)
+{
+    output << "    <header>" << endl;
+    output << "      <identifier>" << oaiLabel     << "</identifier>" << endl;
+    output << "      <datestamp>"  << lastModified << "</datestamp>" << endl;
+    
+    // copy the collection name off the front of oaiLabel
+    text_t::const_iterator colon = findchar(oaiLabel.begin(), oaiLabel.end(), ':');
+    text_t collection = substr(oaiLabel.begin(), colon);
+    
+    if(oaiVersion >= 200){
+      text_tarray::const_iterator member = memberOf.begin();
+      text_tarray::const_iterator memEnd = memberOf.end();
+
+      // As well as all the subsets that a doc appears in, it is also a member of the 'collection' set
+      output << "      <setSpec>" << collection << "</setSpec>" << endl;
+      while (member != memEnd) {
+	text_t oaiSet = *member;
+	oaiclassifier::toOAI(collection, oaiSet);
+	output << "      <setSpec>" << oaiSet << "</setSpec>" << endl;
+	++member;
+      }
+    }
+    output << "    </header>" << endl;
+}
+
+void oaiaction::getLastModifiedDate(ResultDocInfo_t &doc_info, text_t &lastModified)
+{
+  text_t temp;
+
+  
+  MetadataInfo_tmap::iterator current = doc_info.metadata.begin();
+  MetadataInfo_tmap::iterator end = doc_info.metadata.end();
+
+  while(current != end){
+    temp = current->first;
+    lc(temp);
+    if(temp == "dc.date"){
+      lastModified = current->second.values[0];
+      return;
+    }
+    else{ 
+      if (temp == "lastmodified" && lastModified == "" && current->second.values.size() >= 1) {
+	lastModified = current->second.values[0];
+	time_t raw_time = (time_t)lastModified.getint();
+	lastModified = this->parseDatestamp(raw_time);
+	return;
+      }
+    }
+    ++current;
+  }  
+}
+
+bool oaiaction::inDateRange(const text_t &from, const text_t &until, const text_t &collection, 
+			    const text_t &OID, recptproto *protocol, ostream &logout)
+{
+  FilterResponse_t response;
+  text_tset        metadata;
+  bool status_ok = get_info(OID, collection, "", metadata, false, protocol, response, logout);
+  bool not_too_early = false, not_too_recent = false;
+
+  if(status_ok) {
+    ResultDocInfo_t doc_info = response.docInfo[0];
+    text_t lastModDate;
+    this->getLastModifiedDate(doc_info, lastModDate);
+    
+    // All date fields should be in the form YYYY-MM-DD, which allows for a direct comparison
+    if(from != ""){
+      if(from <= lastModDate)
+	not_too_early = true;
+    }
+    else 
+      not_too_early = true; // If there's no FROM field, then the record can't be too early
+
+    if(until != ""){
+      if(lastModDate <= until)
+	not_too_recent = true;
+    }
+    else 
+      not_too_recent = true; // If there's no UNTIL field, then the record can't be too recent    
+    
+    if(not_too_early && not_too_recent)
+      return true;
+    else
+      return false;
+  }
+  else
+    return false;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiaction.h	(revision 10506)
@@ -0,0 +1,64 @@
+#ifndef _oaiaction_h_
+#define _oaiaction_h_
+// standard c++ includes
+//#include <ostream.h>
+
+// generic gsdl stuff
+#include "text_t.h"
+#include "htmlutils.h" // For converting characters in a string to URL encoding. 
+
+// connection to a receptionist
+#include "receptionist.h"
+
+// oaistuff
+#include "oaiargs.h"
+#include "oaiconfig.h"
+#include <time.h>
+
+// Define hours & mins that separate local time from UTC (GMT) time; +ve is ahead of UTC, -ve behind
+#define _LOCALTIME_ "+12:00"
+
+class oaiaction
+{
+ public:
+  oaiaction(const text_t &name);
+
+  virtual void setConfiguration(oaiconfig *config) { this->configuration = config; }
+  text_t getName();
+  text_t parseDatestamp(time_t &rawtime);// Convert date from raw time_t format to the string YYYY-MM-DD
+  void   getResponseDate(text_t &date);  // Get the response date in UTC (GMT) time, plus local offset
+  void   getRequestURL(oaiargs &params, text_t &requestURL); // Get the URL of the request
+  void   getResponse(ostream &output, recptproto *protocol, oaiargs &params);
+  void   output_action_tag(ostream &output, bool openTag);
+  void   output_record_header(ostream &output, const text_t &oaiLabel, const text_t &lastModified, 
+			      const text_tarray &memberOf, int oaiVersion);
+  void   output_error(ostream &output, text_t &errorType); // Output any error conditions
+  bool   formatNotSupported(text_t &metaFormat);           // Return true if the supplied metadataPrefix
+                                                           // format is not supported
+  void   setErrorType(text_t &err){this->errorType = err;};
+  text_t getErrorType(){return this->errorType;};
+  void   getLastModifiedDate(ResultDocInfo_t &doc_info, text_t &lastModified);
+  bool   inDateRange(const text_t &from, const text_t &until, const text_t &collection, 
+		     const text_t &OID, recptproto *protocol, ostream &logout);
+  /******
+   * The following function sets the isInnerObject flag. It is used by the nested recordaction
+   * object in the listrecs object. This flag provides a means for identifying whether the 
+   * recordaction object is acting on its own or through a listrecsaction object. This is 
+   * to allow for appropriate handling of errors regarding unsupported metadata formats. If 
+   * we are using verb=GetRecord and the supplied metadata format is not supported by this 
+   * particular item, then an error must be thrown. But if were using verb=ListRecords, we only
+   * want to exclude the item in question from the list, not throw an error.
+   */
+  void       setAsInnerObject() { this->isInnerObject = true;}
+
+ protected:
+  oaiconfig *configuration;
+  virtual    bool validateAction(recptproto *protocol, oaiargs &params); // Check that this is a valid action
+  virtual    bool output_content(ostream &output, recptproto *protocol, oaiargs &params) = 0;
+  bool       isInnerObject;
+  text_t     name;
+  text_t     errorType;
+  ostream  * logout;
+};
+#endif
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiargs.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiargs.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiargs.cpp	(revision 10506)
@@ -0,0 +1,100 @@
+#include "oaiargs.h"
+#include "cgiutils.h"
+
+// read the arguments from a stream for an OAI action
+void oaiargs::readArgs(istream &in)
+{
+  unsigned char  buffer[256];
+  unsigned char *end = buffer + 256;
+  unsigned char *here = end;
+  unsigned char *start, *equals;
+
+  // if no parameters, return now.
+  if (in.eof()) {
+    cerr << "Aborting on EOF" << endl;
+    return;
+  }
+
+  // fill the buffer with the stream
+  this->fillBuffer(in, buffer, &here, end);
+
+  // start at the beginning of the buffer, read
+  // the stream until exhausted
+  here = buffer;
+  while (*here != '\0')
+  {
+    // each iteration of the outer loop reads a single argument
+
+    // we start an argument and continue until the buffer is
+    // exhausted or the next argument is found
+    start = here;
+    equals = NULL;
+    while (*here != '&' && *here != '\0') {
+      // remember where the equals sign was if necessary
+      if (equals == NULL && *here == '=') {
+	equals = here;
+      }
+
+      // move to the next character
+      ++here;
+
+      // and refill the buffer as necessary
+      if (here == end) {
+	this->fillBuffer(in, buffer, &here, end);
+      }
+    }
+    
+    // we've now got the scope of one argument, where it begins, ends
+    // and where the equals sign is; we now split it up accordingly
+    // to create the actual text_t type elements for the label and the
+    // value.
+    text_t label, value;
+    if (equals == NULL) {
+      label.setcarr((char *) start, (int) here - (int) start);
+      value = label;
+    }
+    else {
+      label.setcarr((char *) start, (int) equals - (int) start);
+      ++equals;
+      value.setcarr((char *) equals, (int) here - (int) equals);
+    }
+
+    decode_cgi_arg(value);
+    
+    // output to the screen for tracing purposes
+    // cerr << label << "?" << value << endl;
+
+    // if the argument already exists, raise an error
+    if (this->arguments.count(label) > 0) {
+      this->duplicateArg = true;
+    }
+    else {
+      // add this argument to the argument map
+      this->arguments[label] = value;
+    }
+
+    // don't choke on an argument separator; swallow it so we don't get
+    // inifinite loops above
+    if (*here == '&') {
+      ++here;
+    }
+  }
+}
+
+void oaiargs::fillBuffer(istream &in, unsigned char *buffer, unsigned char **currentPtr, unsigned char *end)
+{
+  unsigned char *fill = buffer;
+
+  // copy out the remaining buffer space
+  while (*currentPtr != end) {
+    *fill = **currentPtr;
+    *currentPtr++;
+  }
+
+  // set the buffer appropriately
+  *currentPtr = fill;
+
+  // refill the buffer
+  in.get((char *)*currentPtr, (char *)end - (char *)*currentPtr);
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiargs.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiargs.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiargs.h	(revision 10506)
@@ -0,0 +1,27 @@
+#include <map>
+
+#include "text_t.h"
+
+class oaiargs
+{
+ private:
+  text_tmap arguments;
+  text_t    dummy;
+  bool      duplicateArg;
+  // fill the input buffer to parse the arguments
+  void fillBuffer(istream &stream, unsigned char *buffer, unsigned char **currentPtr, unsigned char *end);
+ public:
+  oaiargs() { this->duplicateArg = false; }
+
+  const text_t &operator [](const text_t &label) { 
+    if (this->arguments.count(label) > 0) {
+      return this->arguments[label]; 
+    }
+    return dummy; // Dodgy, but text_t's are initialised to "", so should be fine
+  };
+  void readArgs(istream &stream);
+  bool hasDuplicateArg() { return this->duplicateArg; }
+  int getSize(){return arguments.size();}
+  text_tmap::const_iterator begin(){return arguments.begin();};
+  text_tmap::const_iterator end(){return arguments.end();};
+};
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiconfig.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiconfig.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiconfig.cpp	(revision 10506)
@@ -0,0 +1,300 @@
+#include "oaiconfig.h"
+
+#include <algorithm>
+#include <iostream>
+
+#include "fileutil.h"
+
+/**
+ *  The mapping works as follows in the collect.cfg file.
+ *
+ *  A line is in the format oaimapping <collection field> <oai field>
+ *
+ *  The map here is used to look up the "Greenstone" name which is mapped from
+ *  a given OAI field name, the reverse direction to that given in the 
+ *  Greenstone collect.cfg file.  The oairecordaction class instance which
+ *  produces output for an OAI record information request thus uses the map
+ *  to work from the field in the collection it has on hand which OAI
+ *  record name it should use instead.
+ *
+ *  An extension is to be used for this in which the OAI field name in the
+ *  collect.cfg file can be made specific for a particular record format.
+ *  This is done using the OAI field name in the format of 
+ *    <OAI format>:<OAI field name>
+ *  Thus, an rfc1807 Title field would be referred to as rfc1807:Title
+ *
+ *  A collection-level mapping is not needed - to configure the behaviour
+ *  of a collection, ensure that you place the appropriate configuration in
+ *  its etc/collect.cfg file - the oaimapping stuff IS NOT picked up from 
+ *  the central main.cfg file at the moment.
+ *
+ *  In the absence of a particular format name, the mapping is taken to be
+ *  universal.
+ */
+
+oaiconfig::oaiconfig() : configurable () {
+}
+
+oaiconfig::oaiconfig(text_t &gsdlhome, text_t &gsdlcollect) 
+{
+  // read main configuration file to get oai collections
+  text_t mainconfig = filename_cat(gsdlhome, "etc", "oai.cfg");
+  this->collection = "";
+  this->read_configfile(mainconfig);
+  
+  // then if we've not got a specified collection in the gsdlcollect
+  // parameter, read in all the collection's individual configurations
+  if (gsdlcollect == "") {
+    text_tarray::iterator here = this->collectList.begin();
+    text_tarray::iterator end  = this->collectList.end();
+    while (here != end) {		
+      this->configureCollection(gsdlhome, *here);
+      ++here;
+    }
+  }
+  else {
+    this->configureCollection(gsdlhome, gsdlcollect);
+  }
+}
+
+oaiconfig::~oaiconfig() 
+{
+  oaicollectmap::iterator here = this->collectMap.begin();
+  oaicollectmap::iterator end  = this->collectMap.end();
+  while (here != end) {
+    delete here->second;
+    ++here;
+  }	
+}
+
+int oaiconfig::getOAIVersion()
+{ 
+  if (this->oaiVersion == "1.1") {
+    return 110;
+  }
+  return 200; 
+}
+
+void oaiconfig::configureCollection(const text_t &gsdlhome, const text_t &gsdlcollect)
+{
+  text_t cnfgfile = filename_cat(gsdlhome, "collect", gsdlcollect, "etc", "collect.cfg");
+  this->collection = gsdlcollect;
+  this->read_configfile(cnfgfile);
+}
+
+void oaiconfig::configure (const text_t &key, const text_tarray &cfgline)
+{
+  // we've got an oai mapping item, and at least two fields
+  if (key == "oaimapping" && cfgline.size() > 1) {
+    text_t::const_iterator colonAt;
+    text_t index, name, configCollection;
+
+    // Take a default collection as being whatever the collection being configured is...
+    configCollection = this->collection;
+    
+    // get the name of the (collection) field to map; this may actually
+    // be in a colon separated format of the type 
+    // <collection name>:<field name>
+    index = cfgline[0];
+    if ((colonAt = find(index.begin(), index.end(), ':')) != index.end()) {
+      configCollection = substr(index.begin(), colonAt);
+
+      if (this->collection != "" && configCollection != this->collection) {
+	cerr << "Attempt to configure OAI mappings for " << configCollection << " in " << this->collection << endl;
+      }
+
+      colonAt += 1;
+      index = substr(colonAt, index.end());
+    }
+    
+    // the second parameter is the metadata field to map the collection
+    // field onto.  It may be provided with a metadata protocol (which
+    // will be given first and separated by a period or full stop).  In 
+    // the case of format.field name, the splitting is done here.
+    if ((colonAt = find(cfgline[1].begin(), cfgline[1].end(), '.')) != cfgline[1].end()) {
+      text_t stub = substr(cfgline[1].begin(), colonAt);
+      colonAt += 1;
+      name = substr(colonAt, cfgline[1].end());
+      index.append(":");
+      index.append(stub);
+    }
+    else {
+      name = cfgline[1];
+    }
+    
+    // now 'index' is in the form <collectionfield>:(formatname) 
+    //     'name' is simply the fieldname within the format
+    //     'configCollection' is the collection to be configured
+    
+    // now simply map the field name (index) onto the collection name (name)
+    if (this->collectMap[configCollection] == NULL) {
+      this->collectMap[configCollection] = new oaicollectconfig(configCollection);
+    }
+    this->collectMap[configCollection]->fieldMap[index] = name;
+    
+    //    cerr << "Mapping " << index << " to " << name << " in " << configCollection << endl;
+    
+    // TODO: check that the mapped field is actually in use
+  }
+  else if (key == "oaicollection" && cfgline.size() >= 1) {
+    // Configure a collection to be used as part of the OAI archive.
+    // This line should read:
+    //
+    // oaicollection <collectionname>
+    //
+    // Where <collectionname> is the name of the directory inside the
+    // gsdl/collect folder which contains the collection.
+    //
+    // To configure several collections, merely repeat this line,
+    // or alternatively use additional collection names after the
+    // first one.
+    //
+    // This configuration should only appear in main.cfg
+    //
+    if (this->collection != "") {
+      cerr << "Attempt to configure an oai collection outside of main.cfg" << endl;
+      cerr << "Configuration attempted in " << this->collection << " collection." << endl;
+      exit(1);
+    }
+    for (int c = 0; c < cfgline.size(); ++c) {
+      this->collectList.push_back(cfgline[c]);
+    }
+  }
+  else if (key == "oaiinfo" && cfgline.size() >= 1) {
+    // Get a piece of information for the oai repository information
+    // request.  The line should read:
+    //
+    // oaiinfo <information field name> <value>
+    //
+    // This configuration should only be attempted in main.cfg
+    //
+    if (this->collection != "") {
+      cerr << "Attempt to set oai information outside of main.cfg" << endl;
+      cerr << "Configuration attempted in " << this->collection << " collection." << endl;
+      exit(1);
+    }
+    
+    // if no second parameter is given, then the first parameter
+    if (cfgline.size() == 1) {
+      this->infoMap[cfgline[0]] = cfgline[0];
+    }
+    else {
+      this->infoMap[cfgline[0]] = cfgline[1];
+    }
+  }
+  else if (key == "oaiversion" && cfgline.size() >= 1) {
+    this->oaiVersion = cfgline[0];
+  }
+  // get and note a maintainer item to support the Identify Verb of OAI
+  else if (key == "maintainer" && cfgline.size() >= 1) {
+    int line = 0;
+    
+    // TODO: exhaustive checks for empty or default values of maintainer
+    while (line < cfgline.size()) {
+      if (cfgline[line] != "NULL" &&
+	  cfgline[line] != "") {
+	// do something
+	break;
+      }
+      else {
+	++line;
+      }
+    }
+    
+    // Only try to set the configuration if we have a legitimate value ...
+    if (line < cfgline.size()) {
+      // ensure we have a map to write to
+      if (this->collectMap[this->collection] == NULL) {
+	this->collectMap[this->collection] = new oaicollectconfig(this->collection);
+      }
+      this->collectMap[this->collection]->maintainer = cfgline[line];
+    }
+  }
+  else if (key == "repositoryName" && cfgline.size() >= 1) {
+    int line = 0;
+    
+    // TODO: exhaustive checks for empty or default values of repositoryName
+    while (line < cfgline.size()) {
+      if (cfgline[line] != "NULL" &&
+	  cfgline[line] != "") {
+	// do something
+	break;
+      }
+      else {
+	++line;
+      }
+    }
+    
+    // Only try to set the configuration if we have a legitimate value ...
+    if (line < cfgline.size()) {
+      // ensure we have a map to write to
+      if (this->collectMap[this->collection] == NULL) {
+	this->collectMap[this->collection] = new oaicollectconfig(this->collection);
+      }
+      this->collectMap[this->collection]->repositoryName = cfgline[line];
+    }
+  }
+}
+
+/** 
+ *  TODO: store all field values in a map per collection
+ */
+text_t oaiconfig::getCollectionConfig(const text_t &collection, const text_t &field)
+{
+  if (this->collectMap[collection] == NULL) {
+    return "";
+  }
+  if (field == "maintainer") {
+    return this->collectMap[collection]->maintainer;
+  }
+
+  if (field == "repositoryName") {
+    return this->collectMap[collection]->repositoryName;
+  }
+
+  return "";
+}
+
+text_t oaiconfig::getMapping(const text_t &collection, const text_t &collectfield)
+{
+  if (this->collectMap[collection] == NULL) {
+    return "";
+  }
+  return this->collectMap[collection]->fieldMap[collectfield];
+}
+
+/**
+ *  Get the mapping for a field in a given collection; if no mapping
+ *  exists, the result will be a blank string.
+ */
+text_t oaiconfig::getMapping(const text_t &collection, const text_t &collectfield, const text_t &formatname)
+{
+  text_t fullName = collectfield;
+  fullName.append(":");
+  fullName.append(formatname);
+
+  // try the collection-specific options first
+  if (this->collectMap[collection] != NULL) {
+    // first try the most specific item - this collection, and given that protocol
+    if (this->collectMap[collection]->fieldMap.count(fullName) >= 1) {
+      return this->collectMap[collection]->fieldMap[fullName];
+    }
+    // otherwise, fall back to this collection, and all protocols
+    else if (this->collectMap[collection]->fieldMap.count(collectfield) >= 1) {
+      return this->collectMap[collection]->fieldMap[collectfield];
+    }
+  }
+
+  // if no mappings exist, return an empty item
+  if (this->collectMap[""] == NULL) {
+    return "";
+  }
+
+  // then try generic rules
+  if (this->collectMap[""]->fieldMap.count(fullName) >= 1) {
+    return this->collectMap[""]->fieldMap[fullName];
+  }
+  else {
+    return this->collectMap[""]->fieldMap[collectfield];
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiconfig.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiconfig.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaiconfig.h	(revision 10506)
@@ -0,0 +1,44 @@
+#ifndef _OAICONFIG_H_
+#define _OAICONFIG_H_
+
+#include "cnfgable.h"
+
+#include <map>
+
+// TODO: sort out the members of oaicollectconfig as private/public and add
+//       corresponding set/get functions
+
+class oaicollectconfig {
+ public:
+  oaicollectconfig(const text_t &collectname) { this->collection = collectname; }
+  text_t    collection;
+  text_t    maintainer;
+  text_t    repositoryName;
+  text_tmap fieldMap;    // maps from OAI name to GSDL name
+};
+
+typedef map<text_t, oaicollectconfig *, lttext_t> oaicollectmap;
+
+class oaiconfig : configurable {
+ public:
+  oaiconfig();
+  oaiconfig(text_t &gsdlhome, text_t &gsdlcollect);
+  ~oaiconfig();
+  virtual void  configure(const text_t &key, const text_tarray &cfgline);
+  text_t        getCollectionConfig(const text_t &collection, const text_t &field);
+  text_tarray & getCollectionsList() { return this->collectList; }
+  text_t        getMapping(const text_t &collection, const text_t &collectfield);
+  text_t        getMapping(const text_t &collection, const text_t &collectfield, const text_t &format);
+  text_tmap   * getInformation() { return &this->infoMap; }
+  int           getOAIVersion();
+ private:
+  void configureCollection(const text_t &gsdlhome, const text_t &collection);
+  
+  text_tarray collectList;  // The list of collections to be taken in hand
+  text_tmap infoMap;        // Holds the information to be given in the case
+                            // of an OAI identify request
+  oaicollectmap collectMap; // The configuration of collections
+  text_t collection;        // Used to track which collection is being configured
+  text_t oaiVersion;        // The version of OAI running
+};
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaidispatcher.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaidispatcher.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaidispatcher.cpp	(revision 10506)
@@ -0,0 +1,80 @@
+#include "oaidispatcher.h"
+
+oaidispatcher::oaidispatcher()
+{ this->configuration = NULL;
+}
+
+oaidispatcher::~oaidispatcher()
+{
+  oaiactionmap::iterator here = this->actions.begin();
+  oaiactionmap::iterator end  = this->actions.end();
+
+  while (here != end) {
+    delete here->second;
+    ++here;
+  }
+}
+
+void oaidispatcher::addAction(oaiaction *thisAction) {
+  thisAction->setConfiguration(this->configuration);
+  this->actions[thisAction->getName()] = thisAction;
+}
+
+void oaidispatcher::doAction(ostream &output, recptproto *protocol, oaiargs &args) {
+
+  text_t verb = args["Verb"];
+  if(verb == "") verb = args["verb"];
+  
+  oaiaction *action = actions[verb];
+  
+  if (action != NULL) {
+    action->getResponse(output, protocol, args);
+  }
+  else {  
+    // If the verb isn't correct, send an error.
+    action = actions["Identify"];
+    text_t responseDate, requestURL;
+    int version = this->configuration->getOAIVersion();
+    action->getResponseDate(responseDate);
+    oaiargs emptySet;
+    action->getRequestURL(emptySet, requestURL);
+
+    // Bad verb is signified by a status 400 response for OAI 1.1
+    if (version <= 110) {
+      output << "Status: 400\n";
+    }
+    else {
+      output << "Status: 200\n";
+    }
+    output << "Content-type: text/xml" << endl << endl;
+    output << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
+    
+    if(version <= 110){
+      // output OAI v1.1 action header tag - nil, as there is no valid heeader for the action
+      /*
+	output << "<" << action->name;
+	output << "\n       xmlns=\"http://www.openarchives.com/OAI/1.1/OAI_" << action->name << "\" ";
+	output << "\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ";
+	output << "\n       xsi:schemaLocation=\"http://www.openarchives.org/OAI/1.1/OAI_" << action->name;
+	output << "\n           http://www.openarchives.org/OAI/1.1/OAI_" << action->name << ".xsd\">\n";
+      */    
+    }
+    else { 
+      // output OAI v2.0 action header tag
+      output << "<OAI-PMH xmlns=\"http://www.openarchives.com/OAI/2.0\"\n"
+	     << "         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+	     << "         xsi:schemaLocation=\"http://www.openarchives.org/OAI/2.0/\n"
+	     << "             http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd\">\n"
+	     << "  <responseDate>" << responseDate << "</responseDate>\n"
+	     << requestURL 
+	     << "  <error code=\"badVerb\">Illegal OAI verb</error>\n"
+	     << "</OAI-PMH>\n";
+    }
+
+    /*
+      cout << "<title>Bad OAI request</title>" << endl;
+      cout << "<h1>Bad OAI request</h1>" << endl;
+    */
+  }
+  output.flush();
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaidispatcher.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaidispatcher.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaidispatcher.h	(revision 10506)
@@ -0,0 +1,24 @@
+#include "oaiaction.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+typedef map<text_t, oaiaction *, lttext_t> oaiactionmap;
+
+class oaidispatcher
+{
+ private:
+  oaiactionmap actions;
+  oaiconfig   *configuration;
+ public:
+  oaidispatcher();
+  ~oaidispatcher();
+  void setConfiguration(oaiconfig *configuration) { this->configuration = configuration; }
+  void addAction(oaiaction *thisAction);
+  void doAction(ostream &stream, recptproto *protocol, oaiargs &args);
+};
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaimain.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaimain.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaimain.cpp	(revision 10506)
@@ -0,0 +1,165 @@
+#include "oaimain.h"
+
+/**********************************************************************
+ *
+ * oaimain.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdlconf.h"
+
+#if defined(GSDL_USE_IOS_H)
+#  include <fstream.h>
+#  if defined(__WIN32__)
+#    include <strstrea.h> // vc4
+#  else
+#    include <strstream.h>
+#  endif
+#else
+#  include <fstream>
+#  include <sstream>
+#endif
+
+#include "fileutil.h"
+#include "nullproto.h"
+#include "collectset.h"
+#include "cgiargs.h"
+#include "OIDtools.h"
+
+#include "identityaction.h"
+#include "recordaction.h"
+#include "listsetsaction.h"
+#include "listrecsaction.h"
+#include "listidsaction.h"
+#include "metaformatsaction.h"
+#include "oaidispatcher.h"
+#include "oaiconfig.h"
+
+void get_cgi_args(text_t &argstring)
+{
+  // get the query string if it is not being run as a fastcgi
+  // script
+  text_t argstr = "";
+  char *aURIStr;
+  char *request_method_str = getenv("REQUEST_METHOD");
+  char *content_length_str = getenv("CONTENT_LENGTH");
+  if (request_method_str != NULL && strcmp(request_method_str, "POST") == 0 &&
+      content_length_str != NULL)  {
+    // POST form data
+    int content_length = text_t(content_length_str).getint();
+    if (content_length > 0) {
+      char c;
+      do {
+	cin.get(c);
+	if (cin.eof()) 
+	  break;
+	argstr.push_back (c);
+	--content_length;
+      } while (content_length > 0);
+    }
+    
+  } else {
+    aURIStr = getenv("QUERY_STRING");
+    if ((request_method_str != NULL && strcmp(request_method_str, "GET") == 0)
+	|| aURIStr != NULL) {
+      // GET form data
+      if (aURIStr != NULL) 
+	argstr = aURIStr;
+    } else {
+      // debugging from command line
+      // debug = true;
+      char inStr[1024];
+      
+      cin.get(inStr, 1024);
+      argstr = inStr;
+    }
+  }
+  argstring = argstr;
+}
+
+
+int main(int argc, char *argv[])
+{
+  text_t        cgiargstring;
+  nullproto     nproto;
+  collectset   *cservers;
+  text_t        gsdlhome;
+  text_t        gsdlcollect = "";
+  oaiargs       args;
+  ofstream      logout("oai.log", ios::app);
+  
+  // convert cgi to oai map
+  get_cgi_args(cgiargstring);
+  
+  char *cstr = cgiargstring.getcstr();
+#if defined(GSDL_USE_IOS_H)
+  istrstream cgi_in(cstr, cgiargstring.size());
+#else
+  istringstream cgi_in(cstr);
+#endif
+
+  // parse the arguments
+  args.readArgs(cgi_in);
+
+  delete []cstr;
+  
+  cservers = new collectset(gsdlhome);
+
+  // set up the null protocol
+  nproto.set_collectset(cservers);
+  
+  // get the oai configuration
+  oaiconfig config(gsdlhome, gsdlcollect);
+
+  // set up the dispatcher
+  oaidispatcher dispatcher;
+  dispatcher.setConfiguration(&config);
+
+  identityaction *id   = new identityaction;
+  recordaction   *rec  = new recordaction;
+  listsetsaction *sets = new listsetsaction;
+  listrecsaction *records = new listrecsaction;
+  records->set_recordMaker(rec);
+
+  listidsaction  *ids     = new listidsaction;
+  metaformatsaction *formats = new metaformatsaction;
+  formats->set_formats(rec->get_formats());
+
+  dispatcher.addAction(id);
+  dispatcher.addAction(rec);
+  dispatcher.addAction(sets);
+  dispatcher.addAction(records);
+  dispatcher.addAction(ids);
+  dispatcher.addAction(formats);
+
+  // deal with this request
+  comerror_t error;
+  nproto.init(error, logout);
+
+  // GRB: any checks that a collection exists would be done here
+  //      At present, I foresee no useful application of that requirement.
+
+  dispatcher.doAction(cout, &nproto, args);
+  
+  delete cservers;
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaimain.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaimain.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaimain.h	(revision 10506)
@@ -0,0 +1,1 @@
+// nothing
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaitools.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaitools.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaitools.cpp	(revision 10506)
@@ -0,0 +1,82 @@
+#include "oaitools.h"
+
+#include <algorithm>
+
+#include "OIDtools.h"
+
+void oaiclassifier::swapColonsAndPeriods(text_t &classifier)
+{
+  for (int i = 1; i <= classifier.size(); ++i) {
+    if (classifier[i] == '.') {
+      classifier[i] = ':';
+    }
+    else if (classifier[i] == ':') {
+      classifier[i] = '.';
+    }
+  }
+
+}
+
+text_t oaiclassifier::getGSDL_OID(const text_t &collection, const text_t& oai_id, 
+				  recptproto *protocol, ostream &logout)
+{
+  FilterResponse_t response;
+  text_tset        metadata;
+
+  // metadata.insert("gsdl_id");
+
+  bool status_ok = get_children(oai_id, collection, "", metadata, false, protocol, response, logout);
+  text_t gsdl_id = "";
+  if (status_ok) {
+    if(response.docInfo.size() > 0){
+      gsdl_id = response.docInfo[0].OID;
+    }
+    else {
+      // Response.docInfo is empty, meaning the doc in question didn't have an oai_id number.
+      return gsdl_id; // Return the empty string to indicate this.
+    }
+  }
+
+  return gsdl_id;
+}
+
+/**
+ *  Called to convert GS classifier/document identifiers that use
+ *  a '.' to separate levels in the hierarchy into OAI identifiers
+ *  that use ':' instead.
+ */
+void oaiclassifier::toOAI(const text_t &collection, text_t &classifier)
+{
+  oaiclassifier::swapColonsAndPeriods(classifier);
+
+  // prepend the collection identifier to the beginning of the
+  // OAI identifier.
+  text_t tmp = collection;
+  tmp.append(":");
+  tmp.append(classifier);
+  
+  classifier = tmp;
+}
+
+/**
+ *  Called to convert OAI classifier/document identifiers that use
+ *  a ':' to separate levels in the hierarchy into GS identifiers
+ *  that use '.' instead.
+ */
+void oaiclassifier::toGSDL(text_t &collection, text_t &classifier)
+{
+  oaiclassifier::swapColonsAndPeriods(classifier);
+
+  // separate out the collection identifier that should be
+  // found at the beginning of the OAI identifier from the
+  // item identifier within the collection
+  text_t::iterator colon = find(classifier.begin(), classifier.end(), '.');
+  if (colon != classifier.end()) {
+    collection = substr(classifier.begin(), colon);
+    classifier = substr(colon + 1, classifier.end());
+  }
+  else{
+    collection = classifier;
+    classifier = "";
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaitools.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaitools.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/oaitools.h	(revision 10506)
@@ -0,0 +1,18 @@
+
+#ifndef _OAITOOLS_H_
+#define _OAITOOLS_H_
+
+#include "text_t.h"
+#include "comtypes.h"
+#include "receptionist.h"
+
+class oaiclassifier {
+ public:
+  static text_t getGSDL_OID(const text_t &collection, const text_t& oai_id, recptproto *protocol, 
+			    ostream &logout);
+  static void   toOAI(const text_t &collection, text_t &classifier);
+  static void   toGSDL(text_t &collection, text_t &classifier);
+ private:
+  static void   swapColonsAndPeriods(text_t &classifier);
+};
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/recordaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/recordaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/recordaction.cpp	(revision 10506)
@@ -0,0 +1,152 @@
+#include "recordaction.h"
+#include "OIDtools.h"
+#include "dublincore.h"
+#include "rfc1807.h"
+#include "oaitools.h"
+#include <time.h>
+
+
+recordaction::recordaction() : oaiaction("GetRecord") {
+  metaformatptr fptr;
+
+  fptr.set_class(new dublin_core());  
+  this->formatMap[fptr.get_class()->formatName()] = fptr;
+  
+  fptr.set_class(new rfc1807());
+  this->formatMap[fptr.get_class()->formatName()] = fptr;
+}
+
+recordaction::~recordaction() {
+  metaformat_map::iterator here = this->formatMap.begin();
+  metaformat_map::iterator end  = this->formatMap.end();
+
+  while (here != end) {
+    here->second.clear();
+    ++here;
+  }
+}
+
+
+bool recordaction::validateAction(recptproto *protocol, oaiargs &params)
+{ text_t meta = params["metadataPrefix"];
+  text_t gsdlId = params["identifier"];
+  text_t gsdlCollect;
+  text_t language = "";
+  int oaiVersion = this->configuration->getOAIVersion();
+
+  // The identifier and metadataPrefix args MUST be supplied, and are the only 
+  // args allowed (excluding verb arg). If we don't have them, throw an error.
+  if(gsdlId == "" || meta == "" || params.getSize() != 3){
+    this->errorType = "badArgument";
+    return false;
+  }
+
+  // Check to see if the metadataPrefix supplied is supported
+  if(this->formatNotSupported(meta)) {
+    this->errorType = "cannotDisseminateFormat";
+    if(oaiVersion == 200) 
+      return false;
+  }
+
+  // convert record identifier into GSDL format from OAI
+  oaiclassifier::toGSDL(gsdlCollect, gsdlId);
+  
+  // get the document information
+  text_tset        metadata;
+  if (!get_info(gsdlId, gsdlCollect, language, metadata, false, protocol, this->gsdlResponse, *logout)) {
+    this->errorType = "idDoesNotExist";
+    if(oaiVersion == 200) 
+      return false;
+  }
+
+  return true;
+}
+
+//
+// Output the content of a GetRecord request; in this case, the static member 
+// output_record below is used to fulfill most of the request
+//
+bool recordaction::output_content(ostream &output, recptproto *protocol, oaiargs &params)
+{
+  // validateAction will already have set up the correct response content
+  text_t gsdlId = params["identifier"];
+  text_t gsdlCollect;
+
+  // convert record identifier into GSDL format from OAI
+  oaiclassifier::toGSDL(gsdlCollect, gsdlId);
+  
+  // go direct to output_record
+  return output_record(output, gsdlCollect, gsdlId, params["metadataPrefix"]);
+}
+
+//
+// A static member that does everything the output_content method above needs,
+// but can be called when individual records are being output for another 
+// action.
+//
+bool recordaction::output_record(ostream &output, recptproto *protocol, const text_t &collection, const text_t &OID, const text_t &metadataPrefix)
+{
+  text_tset        metadata;
+  ofstream         logout("oai.log", ios::app);
+
+  // get the document information
+  if (!get_info(OID, collection, "", metadata, false, protocol, this->gsdlResponse, logout)) {
+    this->errorType = "idDoesNotExist";
+
+    if(this->configuration->getOAIVersion() >= 200) {
+      this->output_error(output, errorType);
+      return false;
+    }
+  }
+
+  return this->output_record(output, collection, OID, metadataPrefix);
+}  
+
+bool recordaction::output_record(ostream &output, const text_t &collection, const text_t &OID, 
+				 const text_t &metadataPrefix)
+{ int oaiVersion = this->configuration->getOAIVersion();
+
+  // check to see if it's a classifier
+  text_t childHead;
+  text_t::const_iterator start = OID.begin();
+  text_t::const_iterator here  = OID.begin();
+  here += 4;
+  childHead = substr(start, here);
+  
+  // if it isn't a document, kill it now
+  if (childHead != "HASH") {
+    cerr << "Not a document" << endl;
+    return false;
+  }
+
+  ResultDocInfo_t doc_info = this->gsdlResponse.docInfo[0];
+  text_t lastModified = "";
+
+  // Fills lastModified with the date from the document in doc_info, in the format YYYY-MM-DD
+  this->getLastModifiedDate(doc_info, lastModified);
+
+  // If the ID exists, output record for oai response (OAI v1.1)
+  // OAI v2.0 will already have bailed if ID doesn't exist (yes?)
+  if (this->errorType != "idDoesNotExist") {
+    text_t oaiLabel = OID;
+    oaiclassifier::toOAI(collection, oaiLabel); // Concatenates HASH id to collection, which OAI needs
+    
+    // output a record
+    output << "  <record>\n";
+    
+    // output header part of oai response
+    this->output_record_header(output, oaiLabel, lastModified, 
+			       doc_info.metadata["memberof"].values, oaiVersion);
+    
+    if (this->errorType != "cannotDisseminateFormat"){
+      if (this->formatMap[metadataPrefix].get_class()->output_metadata(output, collection, doc_info)) {
+	//  output 'about' part of oai response - we probably won't ever use this
+	//output << "    <about>\n";
+	//output << "    </about>\n";
+      } 
+    }
+    // close record
+    output << "  </record>\n\n";
+  }
+  return true;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/recordaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/recordaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/recordaction.h	(revision 10506)
@@ -0,0 +1,29 @@
+#ifndef _RECORDACTION_H_
+#define _RECORDACTION_H_
+#include "oaiaction.h"
+
+#include <map>
+
+#include "comtypes.h"
+
+#include "metaformat.h"
+
+class recordaction : public oaiaction
+{
+ private:
+  metaformat_map formatMap;
+  FilterResponse_t gsdlResponse;
+  
+ public:
+  recordaction();
+  ~recordaction();
+  
+  virtual bool validateAction(recptproto *protocol, oaiargs &params);
+  bool output_content(ostream &output, recptproto *protocol, oaiargs &params);
+  bool output_record(ostream &output, const text_t &collection, const text_t &OID, 
+		     const text_t &metadataPrefix);
+  bool output_record(ostream &output, recptproto *protocol, const text_t &collection, const text_t &OID, 
+		     const text_t &metadataPrefix);
+  metaformat_map *get_formats() { return &this->formatMap; }
+};
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/resumptiontoken.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/resumptiontoken.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/resumptiontoken.cpp	(revision 10506)
@@ -0,0 +1,138 @@
+#include "resumptiontoken.h"
+#include "oaitools.h"
+
+/**
+ *  Generate an initial resumption token from some basic details.
+ *
+ *  TODO: add optional argument to set the server name.
+ */
+ResumptionToken::ResumptionToken(const text_t &collection, const text_t &node,
+				 const text_t &buildDate)
+{ this->collection = collection;
+  this->browseNode = node;
+  this->buildDate  = buildDate;
+  this->startItem  = 0;
+}
+
+/**
+ *  Generate a resumption token from a URN-style format.
+ *
+ *  See getToken() for details of the format.
+ *
+ *  TODO: support inclusion of an optional server name.
+ */
+ResumptionToken::ResumptionToken(const text_t &URN)
+{ text_t::const_iterator first = URN.begin();
+  text_t::const_iterator last = URN.end(); 
+
+  this->collection = "";
+  this->browseNode = "";
+  this->startItem  = -1;
+  
+  text_t::const_iterator here = findchar(first, last, ':');
+  if (here == first) {
+    return;
+  }
+  
+  text_t oainamespace = substr(first, here);
+  if (oainamespace != "gsdloai") {
+    return;
+  }
+
+  // increment past the first colon to get the location
+  first = ++here;
+
+  // get the collection
+  here = findchar(first, last, '.');
+  if (here == first) {
+    return;
+  }
+  this->collection = substr(first, here);
+
+  first = ++here;
+
+  // get the browse node
+  here = findchar(first, last, ',');
+
+  // now, we *may* have truncated items where we start with the first
+  // item in a node (i.e. suppress the ',0' for one reason or another,
+  // let's be forgiving if we can...
+  if (here == first) {
+    this->startItem = 0;
+
+    here = findchar(first, last, '-');    
+
+    // no build date - keep trying...
+    if (here == first) {
+      this->browseNode = substr(first, last);
+    }
+    else {
+      this->browseNode = substr(first, here);
+      this->buildDate  = substr(++here, last);
+    }
+  }
+  // got a proper item indicator...
+  else {
+    // record the browse node
+    this->browseNode = substr(first, here);
+
+    // get past the ','
+    first = ++here;
+    
+    // now find the build date marker
+    here = findchar(first, last, '-');
+    if (here == first) {
+      this->startItem = substr(first, last).getint();
+    }
+    else {
+      this->startItem = substr(first, here).getint();
+      this->buildDate = substr(++here, last); 
+    }
+  }
+}
+
+/**
+ *  Get a resumption token in text_t format.
+ * 
+ *  Resumption tokens are in the format:
+ *
+ *    gsdloai:<serverName>:collectionname.browseNode,startItem-BuildDate
+ *
+ *  The resumption token format does not currently implement the use of
+ *  the optional <serverName> item; it is taken to default to the name of
+ *  the receiving server.
+ *
+ *  TODO: add server identity as an optional argument; also change
+ *        ResumptionToken(text_t &) accordingly.
+ */
+text_t ResumptionToken::getToken()
+{ text_t reply = "gsdloai:";
+  reply = reply + this->collection;
+  if (this->browseNode != "") {
+    reply = reply + "." + this->browseNode;
+  }
+  reply = reply + ",";
+  reply.append(this->startItem);
+  reply = reply + "-" + buildDate;
+
+  return reply;
+}
+
+/**
+ *  Update the position of an existing resumption token
+ */
+void ResumptionToken::setPosition(const text_t &node, int startItem)
+{ this->browseNode = node;
+  this->startItem  = startItem; 
+}
+
+/**
+ *  Check if the resumption token is valid - only a very primitive
+ *  check is done here; one ought to check for an existing collection
+ *  and valid browse Node, build date and startItem
+ *
+ *  TODO: implement improved validation checking.
+ */
+bool ResumptionToken::isValid()
+{ return this->collection != "";
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/resumptiontoken.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/resumptiontoken.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/resumptiontoken.h	(revision 10506)
@@ -0,0 +1,25 @@
+#ifndef _RESUMPTIONTOKEN_H_
+#define _RESUMPTIONTOKEN_H_
+
+#include "text_t.h"
+
+class ResumptionToken
+{ private:
+  text_t  collection;
+  text_t  browseNode;
+  int     startItem;
+  text_t  buildDate;
+  // TODO: add a server name to the variables list; see getToken in resumptionToken.cpp
+
+ public:
+  ResumptionToken(const text_t &collection, const text_t &rootNode, const text_t &buildDate);
+  ResumptionToken(const text_t &URN);
+  text_t  getToken();
+  void setPosition(const text_t &node, int startItem);
+  text_t  getCollection() { return collection; }
+  text_t  getNode() { return browseNode; }
+  int     getPosition() { return startItem; }
+  bool isValid();
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/rfc1807.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/rfc1807.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/rfc1807.cpp	(revision 10506)
@@ -0,0 +1,56 @@
+#include "rfc1807.h"
+
+const text_t rfc1807::formatName() 
+{
+  return "rfc1807";
+}
+
+const text_t rfc1807::formatPrefix() {
+  return "rfc1807";
+}
+
+bool rfc1807::output_record(ostream &output, recptproto *protocol, const text_t &collection, 
+			    const text_t &record_OID) 
+{
+  return metaformat::output_record(output, protocol, collection, record_OID);
+}
+
+void rfc1807::output_metadata_header(ostream &output)
+{
+  output << "<metadata>\n";
+  
+  if(this->oaiConfigure->getOAIVersion() <= 110){
+  // output rfc1807 wrapper for OAI v1.1
+    output << "<rfc1807 xmlns=\"http://info.internet.isi.edu:80/in-notes/rfc/files/rfc1807.txt\"" << endl;
+    output << "         xmlns:xsi=\"http://www.w3c.org/2001/XMLSchema-instance\"" << endl;
+    output << "         xsi:schemaLocation=\"http://info.internet.isi.edu:80/in-notes/rfc/files/rfc1807.txt" 
+	   << endl;
+    output << "                            http://www.openarchives.org/OAI/1.1/rfc1807.xsd\">" << endl;
+  }
+  else {
+    // TODO: output rfc1807 wrapper for OAI v2.0
+    output << "<rfc1807 xmlns=\"http://info.internet.isi.edu:80/in-notes/rfc/files/rfc1807.txt\"" << endl;
+    output << "         xmlns:xsi=\"http://www.w3c.org/2001/XMLSchema-instance\"" << endl;
+    output << "         xsi:schemaLocation=\"http://info.internet.isi.edu:80/in-notes/rfc/files/rfc1807.txt"
+	   << endl;
+    output << "                            http://www.openarchives.org/OAI/1.1/rfc1807.xsd\">" << endl;
+  } 
+}
+
+void rfc1807::output_metadata_footer(ostream &output)
+{
+  // end rfc1807 wrapper
+  output << "</rfc1807>" << endl;
+    
+  output << "</metadata>\n";
+}
+
+bool rfc1807::output_formatdata(ostream &output)
+{
+  // Both versions of the protocol use the same schema (yes?)
+  output << "    <metadataPrefix>rfc1807</metadataPrefix>" << endl;
+  output << "    <schema>http://www.openarchives.org/OAI/1.1/rfc1807.xsd</schema>" << endl;
+  
+  // N.B.: no namespace for this format
+  return true;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/rfc1807.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/rfc1807.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/rfc1807.h	(revision 10506)
@@ -0,0 +1,14 @@
+#include "metaformat.h"
+
+class rfc1807 : public metaformat {
+ protected:
+  void output_metadata_header(ostream &output);
+  virtual void output_metadata_footer(ostream &output);
+ public:
+  rfc1807() : metaformat(){}; // call parent constructor
+  virtual const text_t formatName();
+  virtual const text_t formatPrefix();
+  virtual bool output_record(ostream &output, recptproto *protocol, const text_t &collection, 
+			     const text_t &record_OID);
+  virtual bool output_formatdata(ostream &output);
+};
Index: /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/oaiservr/win32.mak	(revision 10506)
@@ -0,0 +1,127 @@
+###########################################################################
+#
+# win32 makefile -- src/oaiservr
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..\..
+USE_STLPORT = 0
+DLL = 0
+DLLDEBUG = 0
+STLPATH = "$(GSDLHOME)\packages\windows\stlport\stlport"
+
+recptDir = $(GSDLHOME)\src\recpt
+colservrDir = $(GSDLHOME)\src\colservr
+srcDir = $(GSDLHOME)\src
+
+AR = lib
+CC = cl
+
+CPPFLAGS = -GX
+!IF $(DLL)
+CPPFLAGS = $(CPPFLAGS) -MD
+!ELSE
+!IF ($(DLLDEBUG))
+CPPFLAGS = $(CPPFLAGS) -MDd
+!ENDIF
+!ENDIF
+
+LDFLAGS =
+DEFS = -D__WIN32__ -DHAVE_CONFIG_H -DPARADOCNUM -D_LITTLE_ENDIAN -DSHORT_SUFFIX
+INCLUDES = -I"$(GSDLHOME)\src\recpt" -I"$(GSDLHOME)\lib" -I"$(GSDLHOME)\src\colservr" \
+	   -I"$(GSDLHOME)\packages\mg" -I"$(GSDLHOME)\packages\mg\lib" \
+	   -I"$(GSDLHOME)\packages\mg\src\text" -I"$(GSDLHOME)\packages\windows\gdbm\gdbm" \
+	   -I"$(GSDLHOME)\packages\windows\crypt\crypt" -I"$(GSDLHOME)\src\mgpp\lib" \
+	   -I"$(GSDLHOME)\src\mgpp\text" -I"$(GSDLHOME)"
+!IF $(USE_STLPORT)
+DEFS = $(DEFS) -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = $(INCLUDES) -I$(STLPATH)
+!ENDIF
+
+LIBS = "$(GSDLHOME)\packages\windows\gdbm\gdbm\gdbm.lib" \
+       "$(GSDLHOME)\packages\windows\crypt\crypt\crypt.lib" \
+       "$(GSDLHOME)\src\colservr\gsdlcolservr.lib" \
+       "$(GSDLHOME)\lib\gsdllib.lib" \
+       "$(GSDLHOME)\packages\mg\src\text\libtextin.lib" \
+       "$(GSDLHOME)\packages\mg\lib\libmg.lib" \
+       "$(GSDLHOME)\src\mgpp\text\libtextin.lib" \
+       "$(GSDLHOME)\src\mgpp\lib\libmg.lib" \
+       "$(GSDLHOME)\packages\windows\expat\libexpat.lib"
+
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $< 
+
+
+COMMONHEADERS = oaiargs.h oaiaction.h oaidispatcher.h oaiconfig.h identityaction.h recordaction.h \
+                listrecsaction.h listidsaction.h listsetsaction.h metaformatsaction.h oaitools.h \
+                abstractlistaction.h metaformat.h dublincore.h rfc1807.h resumptiontoken.h
+
+HEADERS = $(COMMONHEADERS)
+
+
+COMMONSOURCES = oaiargs.cpp oaiaction.cpp oaidispatcher.cpp oaiconfig.cpp identityaction.cpp recordaction.cpp \
+                abstractlistaction.cpp listrecsaction.cpp listidsaction.cpp listsetsaction.cpp \
+                metaformatsaction.cpp oaitools.cpp metaformat.cpp dublincore.cpp rfc1807.cpp \
+                resumptiontoken.cpp
+
+OAISOURCES = 
+
+SOURCES = $(COMMONSOURCES) $(OAISOURCES)
+
+RECPTOBJECTS = "$(recptDir)\comtypes.obj" "$(recptDir)\OIDtools.obj" "$(recptDir)\nullproto.obj" "$(recptDir)\recptproto.obj" \
+               "$(recptDir)\htmlutils.obj" "$(recptDir)\infodbclass.obj" "$(recptDir)\recptconfig.obj" "$(recptDir)\cgiargs.obj" \
+               "$(recptDir)\cgiutils.obj"
+
+COMMONOBJECTS = oaiargs.obj oaiaction.obj oaiconfig.obj oaidispatcher.obj identityaction.obj recordaction.obj \
+                abstractlistaction.obj listrecsaction.obj listidsaction.obj listsetsaction.obj \
+                metaformatsaction.obj oaitools.obj \
+                metaformat.obj dublincore.obj rfc1807.obj resumptiontoken.obj $(RECPTOBJECTS)
+
+OAIOBJECTS = oaimain.obj
+
+OBJECTS = $(COMMONOBJECTS) $(OAIOBJECTS)
+
+OAI_OBJS = $(COMMONOBJECTS) $(OAIOBJECTS) $(LIBS)
+
+EXEC = oaiserver.exe
+
+all: $(EXEC)
+
+clean:
+	del *.obj
+	del oaiserver.exe
+install:
+	copy oaiserver.exe "$(GSDLHOME)\cgi-bin"
+
+oaiserver.exe: $(OAI_OBJS)
+	     $(LINK) $(OAI_OBJS)
Index: /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/.cvsignore
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/.cvsignore	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/.cvsignore	(revision 10506)
@@ -0,0 +1,4 @@
+Makefile
+suffix
+suffix2
+*.o
Index: /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/Makefile.in	(revision 10506)
@@ -0,0 +1,68 @@
+###########################################################################
+#
+# Makefile -- Makefile for phind
+#
+# 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 Gordon Paynter
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+CXX = @CXX@
+CXXFLAGS = @CXXFLAGS@
+
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INCLUDES = 
+LDFLAGS = @LDFLAGS@
+DPLIBS = 
+LIBS = @LIBS@
+GSDLOS = @gsdlos@
+INSTALL = @INSTALL@
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CXX) -c $(DEFS) $(INCLUDES) $(CXXFLAGS) $< 
+
+
+HEADERS = suffix.h phrase.h check.h
+SOURCES = suffix.cpp phrase.cpp
+OBJECTS = phrase.o suffix.o
+EXEC    = suffix
+
+all : $(EXEC)
+
+install : $(EXEC)
+	$(INSTALL) -d ../../../bin/$(GSDLOS)
+	$(INSTALL) -m 775 -s $(EXEC) ../../../bin/$(GSDLOS)
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC)
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CXXFLAGS) -- $(SOURCES)
+
+suffix : $(OBJECTS)
+	$(CXX) $(LDFLAGS) -o $@ $(OBJECTS)
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/check.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/check.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/check.h	(revision 10506)
@@ -0,0 +1,130 @@
+// check.h -- manipulate the suffixCheck array
+//
+// The suffixCheck array is used to prevent a phrase being added to
+// the results of getExpansions.  It works by declaring an array that
+// has one bit for each entry in the suffix array, which is cleared at
+// the start of getExpansions.  As getExpansions adds each phrase to
+// the result set, we set the bits in the suffixCheck array that
+// correspond to the positions of of the phrase in the suffixArray.
+
+// (The point is that getExpansions can later check whether a phrase
+// or its prefix has been seen before by looking up the bit
+// corresponding to its first occurence in the suffixCheck array: if
+// the bit is set, a subphrase of this phrase is already in the
+// results already, and the current phrase can be ignored.)
+
+#include "suffix.h"
+
+// The suffixCheck array
+#if defined (__WIN32__)
+typedef unsigned char check;
+#else
+#include <inttypes.h>
+typedef uint8_t check;
+#endif
+
+check *suffixCheck;
+
+// The length of the suffixCheck array
+cellcount checkLength;
+
+// Some useful bitmask constants 
+const check ALLBITS        = 255;
+const check LEFTMOSTBIT    = static_cast<check>(ALLBITS << 7);
+const check LEFTMOSTBITS[] = {static_cast<check>(ALLBITS << 8), 
+			      static_cast<check>(ALLBITS << 7), 
+			      static_cast<check>(ALLBITS << 6), 
+			      static_cast<check>(ALLBITS << 5), 
+			      static_cast<check>(ALLBITS << 4),
+			      static_cast<check>(ALLBITS << 3), 
+			      static_cast<check>(ALLBITS << 2), 
+			      static_cast<check>(ALLBITS << 1),  
+			      static_cast<check>(ALLBITS << 0)};
+
+
+// Allocate the initial memory for suffixCheck
+inline void allocateSuffixCheck(cellcount number_of_symbols) 
+{
+  checkLength = number_of_symbols / (sizeof(check) * 8) + 1;
+  suffixCheck = new check[checkLength];
+  if (suffixCheck == NULL) {
+    cerr << "Suffix error: out of memory allocating suffixCheck array" << endl; 
+    exit(2);
+  }
+  memset(suffixCheck, 0, sizeof(check) * checkLength);
+}
+
+
+// Set all bits in suffixCheck to 0
+inline void clearSuffixCheck() 
+{
+  memset(suffixCheck, 0, sizeof(check) * checkLength);
+}
+
+
+// Get the value of a particular bit in suffixCheck
+inline int getSuffixCheck(cellindex position) 
+{
+  cellindex cell = position >> 3;
+  check remainder = position & 0x07; // the last 3 bits
+  if (suffixCheck[cell] & (LEFTMOSTBIT >> remainder)) {
+    return 1;
+  }
+  return 0;
+}                                                                               
+
+// Set the value of a bit in suffixCheck to 1
+inline void setSuffixCheck(cellindex suff) 
+{
+  cellindex cell = suff >> 3;
+  check remainder = suff & 0x07u; // the last 3 bits
+  suffixCheck[cell] |= (LEFTMOSTBIT >> remainder);
+}  
+
+
+// Set the bits in a cell in the suffixArray.
+// Bits are indexed 0-7.
+inline void setCellBits(cellindex cell_offset, unsigned first_bit, unsigned last_bit) 
+{
+  unsigned number_of_bits = last_bit - first_bit + 1;
+  check mask = (LEFTMOSTBITS[number_of_bits] >> first_bit);
+  suffixCheck[cell_offset] |= mask;
+}
+
+
+inline void setSuffixCheck(cellindex first, cellindex last) 
+{
+  // Find the first and last cells in which bits are set
+  cellindex first_cell = first >> 3;
+  cellindex last_cell = last >> 3;
+
+  // If all the values are in the same cell, set them
+  if (first_cell == last_cell) {
+    setCellBits(first_cell, (first & 0x07u), (last & 0x07u));
+    return;
+  }
+
+  // Set the bits in the first and last cells
+  setCellBits(first_cell, (first & 0x07u), 7);
+  setCellBits(last_cell, 0, (last & 0x07u));
+
+  // Set the bits in the intermediate cells
+  ++first_cell;
+  if(last_cell > first_cell)
+    memset(suffixCheck + first_cell, ALLBITS, 
+	   (last_cell - first_cell) * sizeof(check));
+}
+
+
+// Print the suffixCheck array (for debugging)
+void printSuffixCheck() 
+{
+  for (cellcount i = 0; i < checkLength; ++i) {
+    cout << "cell " << i << "  \t";
+    cout << "(" << (i * 8) << "-" << (i * 8 + 7) << ")    \t";
+    for (cellindex j = 0; j < 8; ++j)
+      cout << getSuffixCheck(i * 8 + j);
+    cout << " (" << (unsigned int) suffixCheck[i] << ")\n";
+  }
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/phrase.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/phrase.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/phrase.cpp	(revision 10506)
@@ -0,0 +1,853 @@
+/**********************************************************************
+ *
+ * phrase.cpp -- implementation of the phrase object used by suffix.cpp
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <assert.h>
+#include <stdio.h>
+
+#if defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#else
+#  include <vector>
+#endif
+
+#if defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#include "suffix.h"
+#include "phrase.h"
+
+
+// Phrase constructor functions
+
+Phrase::Phrase(symbol *words, cellcount size, int direction) {
+  empty();
+  length = size;
+
+  if (direction == SUFFIX) {
+     forward = words;
+     back = forward + size - 1;
+  } else {
+    back = words;
+    forward = back - size + 1;
+  }
+}
+
+
+Phrase::Phrase() {
+  empty();
+}
+
+
+Phrase::Phrase(const Phrase &p) {
+  forward = p.forward;
+  back = p.back;
+  length = p.length;
+
+  suffixFound = p.suffixFound;
+  prefixFound = p.prefixFound;
+
+  firstSuffix = p.firstSuffix;
+  lastSuffix  = p.lastSuffix;
+  firstSuffixIndex = p.firstSuffixIndex;
+  lastSuffixIndex  = p.lastSuffixIndex;
+  suffixFrequency  = p.suffixFrequency;
+
+  firstPrefix = p.firstPrefix;
+  lastPrefix  = p.lastPrefix;
+  firstPrefixIndex = p.firstPrefixIndex;
+  lastPrefixIndex  = p.lastPrefixIndex;
+  prefixFrequency  = p.prefixFrequency;
+
+  uniqueSuffixExtension = p.uniqueSuffixExtension;
+  uniquePrefixExtension = p.uniquePrefixExtension;
+}
+
+
+// Empty the contents of a phrase
+
+int Phrase::empty() {
+
+  forward = back = NULL;
+  length = 0;
+
+  suffixFound = prefixFound = 0;
+  firstSuffix = firstPrefix = NULL;
+  lastSuffix = lastPrefix = NULL;
+
+  firstSuffixIndex = lastSuffixIndex = suffixFrequency = 0;
+  firstPrefixIndex = lastPrefixIndex = prefixFrequency = 0;
+
+  uniqueSuffixExtension = uniquePrefixExtension = -1;
+
+  return 0;
+}
+
+// Remove the details of the location where a suffix/prefix
+// is found in the array.
+
+int Phrase::clearSuffix() {
+  suffixFound = 0;
+  firstSuffix = lastSuffix = NULL;
+  firstSuffixIndex = lastSuffixIndex = suffixFrequency = 0;
+  uniqueSuffixExtension = -1;
+  return 0;
+}
+
+int Phrase::clearPrefix() {
+  prefixFound = 0;
+  firstPrefix = lastPrefix = NULL;
+  firstPrefixIndex = lastPrefixIndex = prefixFrequency = 0;
+  uniquePrefixExtension = -1;
+  return 0;
+}
+
+// Increase the length of s phrase
+//
+// We increase the length of a string "in place".  When we expand
+// the suffix, however, we invalidate the prefix data, and vice-versa.
+
+int Phrase::increaseSuffixLength(cellcount l) {
+  length = l;
+  clearPrefix();
+  back = forward + l - 1;
+  return 0;
+}
+
+int Phrase::increasePrefixLength(cellcount l) {
+  length = l;
+  clearSuffix();
+  forward = back - l + 1;
+  return 0;
+}
+
+// Shorten a phrase by one symbol
+int Phrase::shortenByOneAtSuffix() {
+  --length;
+  --back;
+  if (phraseMode==STOPWORDS) {
+    while (*back >=firstStopSymbol && *back <= lastStopSymbol) {
+      --length;
+      --back;
+    }
+  }  
+  clearSuffix();
+  clearPrefix();
+  return 0;
+}
+
+int Phrase::shortenByOneAtPrefix() {
+  --length;
+  ++forward;
+  if (phraseMode==STOPWORDS) {
+    while (*forward >=firstStopSymbol && *forward <= lastStopSymbol) {
+      --length;
+      ++forward;
+    }
+  }
+  clearSuffix();
+  clearPrefix();
+  return 0;
+}
+
+
+// Output a phrase to a stream
+ostream &operator<<(ostream &stream, const Phrase &phrase)
+{
+  assert(phrase.forward);
+  symbol *s = phrase.forward;
+
+  stream << "s" << *s++;
+  for (cellcount i = 1; i < phrase.length; ++i)
+    stream << " s" << *s++;
+
+  return stream;
+}
+
+
+// Convert the phrase to a string
+// Note thgat you have to delete the memory yourself.
+char *Phrase::toString() 
+{
+  assert(forward);
+
+  char *str;
+  str = new char[length*20];
+  symbol *s = forward;
+  sprintf(str, "s%d", *s++);
+
+  for (cellcount i = 1; i < length; ++i) {
+    sprintf(str, "%s s%d", str, *s++);
+  }
+
+  return str;
+}
+
+
+// Compare a phrase to an another array of symbols
+//
+// Given an array of words with a specified length, 
+// compare those words to this phrase.
+//
+// Return 0 if the two phrases are the same over length length
+// Return 1 if the phrase is "greater" than tyhe words, or
+// Return -1 if the phrase is less.
+
+int Phrase::compareSuffix(symbol *words, cellcount length) {
+  assert(forward);
+  symbol *p = forward;
+  
+  for (cellcount i = 0; i < length; ++i) {
+    if (*p > *words) {
+      return 1;
+    } else if (*p < *words) {
+      return -1;
+    } else {
+      *p++;
+      *words++;
+    }
+  }
+
+  return 0;
+
+}
+
+int Phrase::comparePrefix(symbol *words, cellcount length) {
+  
+  assert(back);
+  symbol *p = back;
+  
+  for (cellcount i = 0; i < length; ++i) {
+    if (*p > *words) {
+      return -1;
+    } else if (*p < *words) {
+      return 1;
+    } else {
+      *p--;
+      *words--;
+    }
+  }
+
+  return 0;
+
+}
+
+
+// Does the phrase have a unique suffix/prefix extension?
+//
+// For suffix:
+//   If uniqueSuffixExtensions is 1, then phrase has some unique expansion. 
+//   If it is 0 then it does not.  If it is -1 then we don't know, and have
+//   to calculate it from the suffix array.  Same goes for prefixes.
+
+int Phrase::hasUniqueSuffixExtension() {
+
+  // if we don't know, then work it out
+  if (uniqueSuffixExtension == -1) {
+
+    ensureSuffixFound();
+
+    // pointers to the phrase's first and last occurances in te suffixArray
+    symbol *fst = firstSuffix + length;
+    symbol *lst = lastSuffix + length;
+
+    // in ANYPHRASE mode, simply check the next symbol
+    if (phraseMode == ANYPHRASE) {
+      if ((*fst == *lst) && (*fst > LASTDELIMITER)) {
+	uniqueSuffixExtension = 1;
+      } else {
+	uniqueSuffixExtension = 0;
+      }
+    }
+    // in STOPWORDS mode, make sure there is a unique next content symbol
+    else {
+      uniqueSuffixExtension = 0;
+      while ((*fst == *lst) && (*fst > LASTDELIMITER)) {
+	if (*fst >= firstContentSymbol) {
+	  uniqueSuffixExtension = 1;
+	  break;
+	}
+	++fst;
+	++lst;
+      }
+    }
+  }
+
+  return uniqueSuffixExtension;
+}
+
+int Phrase::hasUniquePrefixExtension() {
+
+  // if we don't know, then work it out
+  if (uniquePrefixExtension == -1) {
+
+    ensurePrefixFound();
+
+    // pointers to the phrase's first and last occurances in the prefixArray
+    symbol *fst = firstPrefix - length;
+    symbol *lst = lastPrefix - length;
+
+    // in ANYPHRASE mode, simply check the next symbol
+    if (phraseMode == ANYPHRASE) {
+      if ((*fst == *lst) && (*fst > LASTDELIMITER)) {
+	uniquePrefixExtension = 1;
+      } else {
+	uniquePrefixExtension = 0;
+      }
+    }
+    // in STOPWORDS mode, make sure there is a unique next content symbol
+    else {
+      uniquePrefixExtension = 0;
+      while ((*fst == *lst) && (*fst > LASTDELIMITER)) {
+	if (*fst >= firstContentSymbol) {
+	  uniquePrefixExtension = 1;
+	  break;
+	}
+	--fst;
+	--lst;
+      }
+    }
+  }
+
+  return uniquePrefixExtension;
+}
+
+
+// Expand a phrase with a unique suffix/prefix by 1 symbol
+//
+// Note that in STOPWORDS mode a "unique extension" means a unique
+// extension that ends on a content symbol.  Although we may extend 
+// such a phrase by 2 or more symbols, we will only extend it by a
+// single content symbol.
+
+int Phrase::expandUniqueSuffixExtensionByOne() {
+  assert(suffixFound);
+  assert(uniqueSuffixExtension == 1);
+
+  // in ANYPHRASE mode, expand the phrase by one symbol
+  if (phraseMode == ANYPHRASE) {
+    increaseSuffixLength(length + 1);
+  }
+  // in STOPWORDS mode, expand the phrase up to the next content symbol
+  else {
+    symbol *next = firstSuffix + length;
+    cellcount newlength = length + 1;
+
+    while (*next < firstContentSymbol) {
+      ++next;
+      ++newlength;
+    }
+    increaseSuffixLength(newlength);
+  }
+
+  uniqueSuffixExtension = -1;
+  return 0;
+}
+
+int Phrase::expandUniquePrefixExtensionByOne() {
+  assert(prefixFound);
+  assert(uniquePrefixExtension == 1);
+
+  // in ANYPHRASE mode, expand the phrase by one symbol
+  if (phraseMode == ANYPHRASE) {
+    increasePrefixLength(length + 1);
+  }
+  // in STOPWORDS mode, expand the phrase to the next content symbol
+  else {
+    symbol *next = firstPrefix - length;
+    cellcount newlength = length + 1;
+    while (*next < firstContentSymbol) {
+      --next;
+      ++newlength;
+    }
+    increasePrefixLength(newlength);
+
+  }
+
+  uniquePrefixExtension = -1;
+  return 0;
+}
+
+
+// Find the phrase in a suffixArray
+//
+// Given a suffix array, find the first and last occurances of the phrase.
+// The begin and end parameters identify which cells to search (inclusive). 
+
+int Phrase::findFirstAndLastSuffix() {
+  
+  return findFirstAndLastSuffix(0, inputLength-1);
+}
+
+int Phrase::findFirstAndLastSuffix(cellindex begin, cellindex end) {
+
+  // First find *any* occurance of the phrase
+  assert(begin <= end);
+
+  // if we're only searching one cell, it is very easy
+  if (begin == end) {
+    assert(compareSuffix(suffixArray[begin], length) == 0);
+    firstSuffix = lastSuffix = suffixArray[begin];
+    firstSuffixIndex = lastSuffixIndex = begin;
+    suffixFrequency = 1;
+    suffixFound = 1;
+    return 0;
+  }
+
+  cellindex c;
+  int cmp;
+
+  do {
+    c = (end + begin) / 2;
+    cmp = compareSuffix(suffixArray[c], length);
+    if (cmp == 1) {
+      // target phrase is lower than phrase at suffixArray[c]
+      begin = c + 1;
+    } else if (cmp == -1) {
+      // target phrase is higher than phrase at suffixArray[c]
+      end = c - 1;
+    }
+  } while (cmp != 0);
+    
+  cellindex lastbegin = c;
+  cellindex lastend = end;
+
+  // Next find the first occurance of the phrase.
+  // We know that the first occurance must be between the 
+  // current value of begin and the current value of c.
+  end = c;
+
+  do {
+    if (begin == end) {
+      c = begin;
+      cmp = 0;
+    } else {
+      c = (begin + end) / 2;
+      cmp = compareSuffix(suffixArray[c], length);
+      if (cmp == 1) {
+	// target phrase is lower than phrase at suffixArray[c]
+	begin = c + 1;
+      } else {
+	assert(cmp == 0);
+	// target phrase is the same as the phrase at suffixArray[c].  However,
+	// to find the first occurance, suffixArray[c] must be the same as the 
+	// phrase, but suffixArray[c-1] must be different.
+	if (c>0) {
+	  cmp = compareSuffix(suffixArray[c-1], length);
+	  if (cmp == 0) {
+	    end = c - 1;
+	    assert(end >= begin);
+	    cmp = 1;
+	  } else {
+	    cmp = 0;
+	  }
+	}
+      }
+    }
+  } while (cmp != 0);
+
+  // we have found the first location
+  firstSuffixIndex = c;
+  firstSuffix = suffixArray[c];
+  
+  // Next find the last occurance of the phrase.
+  // We previously stored some bounds for its loccation.
+  begin = lastbegin;
+  end = lastend;
+  
+  do {
+    if (begin == end) {
+      c = begin;
+      cmp = 0;
+    } else {
+      c = (begin + end) / 2;
+      cmp = compareSuffix(suffixArray[c], length);
+      if (cmp == -1) {
+	// target phrase is greater than phrase at suffixArray[c]
+	end = c - 1;
+      } else {
+	assert(cmp == 0);
+	// target phrase is the same as the phrase at suffixArray[c].  However,
+	// to find the last occurance, one of two additional condiditons must be met:
+	// either c must be the very last cell in the array, or
+	// suffixArray[c+1] must be different from phrase
+	if (c < inputLength-1) {
+	  cmp = compareSuffix(suffixArray[c+1], length);
+	  if (cmp == 0) {
+	    begin = c + 1;
+	    cmp = -1;
+	  } else {
+	    cmp = 0;
+	  }
+	} 
+      }
+    }
+  } while (cmp != 0);
+  
+  lastSuffixIndex = c;
+  lastSuffix = suffixArray[c];
+  suffixFrequency = lastSuffixIndex - firstSuffixIndex + 1;
+  suffixFound = 1;
+
+  return 0;
+}
+
+
+// Find the phrase in a prefix array
+//
+// Given a prefix array, find the first and last occurances of the phrase.
+// The begin and end parameters identify which cells to search (inclusive). 
+
+int Phrase::findFirstAndLastPrefix() {
+  return findFirstAndLastPrefix(0, inputLength-1);
+}
+
+int Phrase::findFirstAndLastPrefix(cellindex begin, cellindex end) {
+
+  // First find *any* occurance of the phrase
+  assert(begin <= end);
+
+  // if we're only searching one cell, it is very easy
+  if (begin == end) {
+    assert(comparePrefix(prefixArray[begin], length) == 0);
+    firstPrefix = lastPrefix = prefixArray[begin];
+    firstPrefixIndex = lastPrefixIndex = begin;
+    prefixFrequency = 1;
+    prefixFound = 1;
+    return 0;
+  }
+
+  cellindex c;
+  int cmp;
+
+  do {
+    c = (end + begin) / 2;
+    cmp = comparePrefix(prefixArray[c], length);
+    if (cmp == 1) {
+      begin = c + 1;
+    } else if (cmp == -1) {
+      end = c - 1;
+    }
+  } while (cmp != 0);
+    
+  cellindex lastbegin = c;
+  cellindex lastend = end;
+
+  // Next find the first occurance of the phrase.
+  // We know that the first occurance must be between the 
+  // current value of begin and the cureent value of c.
+  end = c;
+
+  do {
+    if (begin == end) {
+      c = begin;
+      cmp = 0;
+    } else {
+      c = (begin + end) / 2;
+      cmp = comparePrefix(prefixArray[c], length);
+      if (cmp == 1) {
+	// target phrase is lower than phrase at prefixArray[c]
+	begin = c + 1;
+      } else {
+	assert(cmp == 0);
+	// target phrase is the same as the phrase at prefixArray[c].  However, to
+	// find the first occurance, one of two additional condiditons must be met:
+	// either  c == the first cell in prefix array
+	// or      prefixArray[c-1] != phrase.
+	if (c > 0) {
+	  cmp = comparePrefix(prefixArray[c-1], length);
+	  if (cmp == 0) {
+	    end = c - 1;
+	    assert(end >= begin);
+	    cmp = 1;
+	  } else {
+	    cmp = 0;
+	  }
+	}
+      }
+    }
+  } while (cmp != 0);
+
+  // we have found the first location
+  firstPrefixIndex = c;
+  firstPrefix = prefixArray[c];
+
+  // Next find the last occurance of the phrase.
+  // We previously stored some bounds for its loccation.
+  begin = lastbegin;
+  end = lastend;
+  
+  do {
+    if (begin == end) {
+      c = begin;
+      cmp = 0;
+    } else {
+      c = (begin + end) / 2;
+      cmp = comparePrefix(prefixArray[c], length);
+      if (cmp == -1) {
+	// target phrase is greater than phrase at prefixArray[c]
+	end = c - 1;
+      } else {
+	assert(cmp == 0);
+	// target phrase is the same as the phrase at prefixArray[c].  However,
+	// to find the last occurance, prefixArray[c] must be the same as the 
+	// phrase, but prefixArray[c+1] must be different.
+	cmp = comparePrefix(prefixArray[c+1], length);
+	if (cmp == 0) {
+	  begin = c + 1;
+	  cmp = -1;
+	} else {
+	  cmp = 0;
+	}
+      } 
+    }
+  } while (cmp != 0);
+  
+  lastPrefixIndex = c;
+  lastPrefix = prefixArray[c];
+  prefixFrequency = lastPrefixIndex - firstPrefixIndex + 1;
+  prefixFound = 1;
+
+  return 0;
+}
+
+
+// Calculate a set of initial suffix/prefix candidates
+//
+// Expand the phrase to find the initial 
+// set of candidates that may be extensions of that phrase,
+// and add them to the end of the results vector
+
+void Phrase::initialSuffixCandidates(vector<Phrase> &results) {
+
+  ensureSuffixFound();
+  Phrase next;
+  cellindex i = firstSuffixIndex;
+
+  // Find all the expansions of Phrase p
+  while (i <= lastSuffixIndex) {
+
+    // create new phrase exactly one longer than the current one
+    next = newPhraseShortestSuffixExpansion(i);
+
+    // If the expansion occurs more than once and is not delimited, expand it
+    if ((*(next.back) > LASTDELIMITER) && (next.suffixFrequency >= minOccurs)) {
+      next.expandWhileUniqueSuffixExtension();
+      results.push_back(next);
+    }
+    
+    // Move onto the next expansion
+    i = next.lastSuffixIndex + 1;
+  }
+}
+
+
+void Phrase::initialPrefixCandidates(vector<Phrase> &results) {
+
+  ensurePrefixFound();
+  Phrase next;
+  cellindex i = firstPrefixIndex;
+
+  // Find all the expansions of Phrase p
+  while (i <= lastPrefixIndex) {
+
+    // create new phrase exactly one longer than the current one
+    next = newPhraseShortestPrefixExpansion(i);
+
+    // If the expansion occurs more than once and is not delimited, expand it
+    if ((*(next.forward) > LASTDELIMITER) && (next.prefixFrequency >= minOccurs)) {
+      next.expandWhileUniquePrefixExtension();
+      results.push_back(next);
+    }
+    
+    // Move onto the next expansion
+    i = next.lastPrefixIndex + 1;
+  }
+}
+
+
+// Create a new phrase that is longer then the current one, but as short
+// as possible.  In ANYPHRASE mode this means the new phrase is exactly
+// one symbol longer than the current one, but in STOPWORD mode the expansion
+// must introduce a new content symbol
+//
+// Note that we never expand across delimiters; if we encounter a delimiter
+// then this becomes the "end" symbol of the phrase.  The calling function 
+// should check for this condition.
+
+Phrase Phrase::newPhraseShortestSuffixExpansion(cellindex i) {
+  
+  // create a new phrase exactly one symbol longer than the current one
+  Phrase p(suffixArray[i], length + 1, SUFFIX);
+
+  if (phraseMode == STOPWORDS) {
+    // in STOPWORDS mode we must introduce a new content symbol
+    while ((*(p.back) >= firstStopSymbol) &&
+	   (*(p.back) <= lastStopSymbol)) {
+      p.increaseSuffixLength(p.length + 1);
+    }
+  }
+
+  p.findFirstAndLastSuffix(i, lastSuffixIndex);
+  return p;
+}
+
+Phrase Phrase::newPhraseShortestPrefixExpansion(cellindex i) {
+  
+  // create a new phrase exactly one symbol longer than the current one
+  Phrase p(prefixArray[i], length + 1, PREFIX);
+
+  if (phraseMode == STOPWORDS) {
+    // in STOPWORDS mode we must introduce a new content symbol
+    while ((*(p.forward) >= firstStopSymbol) &&
+	   (*(p.forward) <= lastStopSymbol)) {
+      p.increasePrefixLength(p.length + 1);
+    }
+  }
+
+  p.findFirstAndLastPrefix(i, lastPrefixIndex);
+  return p;
+}
+
+
+// Expand a phrase until it no longer has a unique suffix extension
+// 
+// If the phrase only occurs once in the suffix array, do nothing.
+//
+// If we are in stopwords mode then we expand if there is a unique 
+// suffix expansion and this expansion is a content word.  We do this
+// with the content_len variable, which holds the length of the longest
+// phrase ending in a content word. 
+
+int Phrase::expandWhileUniqueSuffixExtension() {
+  ensureSuffixFound();
+
+  // if the phrase occurs only once, do nothing
+  if (suffixFrequency < minOccurs)
+    return 0;
+
+  // if we already know there's no unique suffix extension, do nothing
+  if (uniqueSuffixExtension == 0)
+    return 0;
+
+  // count the length over which the cells are the same
+  // and no delimiter is crossed.
+  symbol *fst = firstSuffix;
+  symbol *lst = lastSuffix;
+  cellindex len = 0;
+  cellindex content_len = 0;
+
+  // Calculate the length over which the phrases match
+  while((*fst == *lst) && (*fst > LASTDELIMITER)) {
+    ++len;
+    if (*fst > lastStopSymbol) content_len = len;
+    ++fst;
+    ++lst;
+  }
+
+  // in ANYPHRASE mode, expand the phrase for as long as possible
+  if (phraseMode == ANYPHRASE) {
+    if (len > length) {
+      increaseSuffixLength(len);
+    }
+  } 
+  // in STOPWORDS mode, expand only as far as the last contentword
+  else {
+    if (content_len > length) {
+      increaseSuffixLength(content_len);
+    }
+  }
+
+  uniqueSuffixExtension = 0;
+  return 0;
+}
+
+int Phrase::expandWhileUniquePrefixExtension() {
+  ensurePrefixFound();
+
+  // if the phrase occurs only once, do nothing
+  if (prefixFrequency < minOccurs)
+    return 0;
+
+  // if we already know there's no unique extension, do nothing
+  if (uniquePrefixExtension == 0)
+    return 0;
+
+  // count the length over which the cells are the same
+  // and no delimiter is crossed.
+  symbol *fst = firstPrefix;
+  symbol *lst = lastPrefix;
+  cellindex len = 0;
+  cellindex content_len = 0;
+
+  // Calculate the length over which the phrases match
+  while((*fst == *lst) && (*fst > LASTDELIMITER)) {
+    ++len;
+    if (*fst > lastStopSymbol) content_len = len;
+    --fst;
+    --lst;
+  }
+
+  // in ANYPHRASE mode, expand the phrase for as long as possible
+  if (phraseMode == ANYPHRASE) {
+    if (len > length) {
+      increasePrefixLength(len);
+    }
+  }
+  // in STOPWORDS mode, expand only as far as the last contentword
+  else {
+    if (content_len > length) {
+      increasePrefixLength(content_len);
+    }
+  }
+
+  uniquePrefixExtension = 0;
+  return 0;
+}
+
+// Compare the length of two phrases
+//
+// Given two phrases, return true if the first is shorter/longer,
+// otherwise return false.  For use in various sort functions.
+
+bool isShorter(Phrase p1, Phrase p2) {
+  if (p1.length < p2.length) {
+    return true;
+  }
+  return false;
+}
+
+bool isLonger(Phrase p1, Phrase p2) {
+  if (p1.length > p2.length) {
+    return true;
+  }
+  return false;
+}
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/phrase.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/phrase.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/phrase.h	(revision 10506)
@@ -0,0 +1,162 @@
+/**********************************************************************
+ *
+ * phrase.h -- definition of the phrase object used by suffix.cpp
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef PHRASE_H
+#define PHRASE_H
+
+// use the standard namespace
+#if !defined (GSDL_NAMESPACE_BROKEN)
+#if defined(GSDL_USE_OBJECTSPACE)
+using namespace ospace::std;
+#else
+using namespace std;
+#endif
+#endif
+
+#if defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#else
+#  include <vector>
+#endif
+
+#include "suffix.h"
+
+class Phrase {
+
+public:
+
+  // The phrase itself is stored with two pointers: forward points to
+  // its first cell, back points to its last.  The length is always
+  // stored in length.  If one of these is set, all must be set, and
+  // it must be true that (forward + length - 1) = back.
+  symbol *forward;
+  symbol *back;
+  cellcount length;
+  
+  // Phrase location in the suffix array
+  int suffixFound;
+  symbol *firstSuffix;
+  symbol *lastSuffix;
+  cellindex firstSuffixIndex;
+  cellindex lastSuffixIndex;
+  cellcount suffixFrequency;
+
+  // Phrase location in the prefix array
+  int prefixFound;
+  symbol* firstPrefix;
+  symbol* lastPrefix;
+  cellindex firstPrefixIndex;
+  cellindex lastPrefixIndex;
+  cellcount prefixFrequency;
+
+  // Constructor functions
+  Phrase();
+  Phrase(const Phrase &p);
+
+  // A "partial" constructor: the first argument is an array of words,
+  // second is its length, third is the direction (SUFFIX or PREFIX)
+  // in which the words should be read (defaults to SUFFIX).
+  Phrase(symbol *words, cellcount size, int direction);
+
+  // Represent the phrase as an arracy of characters
+  // You will have to call "delete []" on the array returned. 
+  char *toString();
+
+  // Find an initial set of candidate phrases in the suffix/prefix array
+  void initialSuffixCandidates(vector<Phrase> &results);
+  void initialPrefixCandidates(vector<Phrase> &results);
+  
+  // Does the phrase have a unique extension?
+  int hasUniqueSuffixExtension();
+  int hasUniquePrefixExtension();
+  
+  // Extend a phrase by exactly one symbol
+  int expandUniquePrefixExtensionByOne();
+  int expandUniqueSuffixExtensionByOne();
+
+  // Extend a phrase until it no longer has a unique extanesion
+  int expandWhileUniqueSuffixExtension();
+  int expandWhileUniquePrefixExtension();
+
+  // Shorten a phrase by one symbol
+  int shortenByOneAtSuffix();
+  int shortenByOneAtPrefix();
+
+  // Find the phrase in the suffix/prefix array
+  int findFirstAndLastSuffix();
+  int findFirstAndLastPrefix();
+  int findFirstAndLastSuffix(cellindex begin, cellindex end);
+  int findFirstAndLastPrefix(cellindex begin, cellindex end);
+
+  // Make sure the phrase location in the suffix/prefix array is known
+  inline void Phrase::ensureSuffixFound() {
+    if (!suffixFound)
+      findFirstAndLastSuffix();
+  }
+  inline void Phrase::ensurePrefixFound() {
+    if (!prefixFound)
+      findFirstAndLastPrefix();
+  }
+
+  // Output a phrase to a stream
+  friend ostream &operator<<(ostream &stream, const Phrase &phrase);
+
+  int uniqueSuffixExtension;
+  int uniquePrefixExtension;
+
+private:
+
+  // Does the phrase have a unique suffix/prefix extension?
+  // if yes, then 1; if no then 0; if unknown then -1;
+
+  // reset a phrase
+  int empty();
+
+  // reset phrase information relating to location in suffix/prefix array
+  int clearSuffix();
+  int clearPrefix();
+
+  // increase the length of a phrase "in place"
+  int Phrase::increaseSuffixLength(cellcount l);
+  int Phrase::increasePrefixLength(cellcount l);
+    
+  // Compare the phrase to a given array of symbols
+  int compareSuffix(symbol *words, cellcount length);
+  int comparePrefix(symbol *words, cellcount length);
+
+  // Create a new phrase that is longer than this one, yet as short as possible.
+  Phrase Phrase::newPhraseShortestSuffixExpansion(cellindex i);
+  Phrase Phrase::newPhraseShortestPrefixExpansion(cellindex i);
+
+};
+
+
+bool isShorter(Phrase p1, Phrase p2);
+bool isLonger(Phrase p1, Phrase p2);
+
+#endif
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/suffix.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/suffix.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/suffix.cpp	(revision 10506)
@@ -0,0 +1,1094 @@
+/**********************************************************************
+ *
+ * Suffix.cpp -- Extract the repeated phrases in the input with suffix
+ *               and prefix arrays (cgn & gwp's simpler algorithm,
+ *               and kjm's improvements).
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(GSDL_USE_IOS_H)
+#  include <fstream.h>
+#  include <iostream.h>
+#else
+#  include <fstream>
+#  include <iostream>
+#endif
+
+#if defined(GSDL_USE_STL_H)
+#  if defined(GSDL_USE_ALGO_H)
+#    include <algo.h>
+#  else
+#    include <algorithm.h>
+#  endif
+#  include <vector.h>
+#else
+#  include <algorithm>
+#  include <vector>
+#endif
+
+#include "suffix.h"
+#include "phrase.h"
+#include "check.h"
+
+// Global variables declared in suffix.h
+cellcount inputLength;
+
+symbol   *symbols;
+symbol  **suffixArray;
+symbol  **prefixArray;
+
+// How many documents are in this collection?
+cellcount numberOfDocuments;
+symbol  **documentArray;
+
+
+// Do we accept any phrase, or do we eliminate those ending with stopwords ?
+int phraseMode = ANYPHRASE; //STOPWORDS;
+// What is the minimum phrase frequency for a phrase to be included in the hierarchy
+int minOccurs = 2;
+
+// The filestem of the collection's phindex directory
+char collection[FILENAME_MAX];
+
+
+// The ranges of the stopword and content-word symbols for the collection
+symbol firstStopSymbol = 0;
+symbol lastStopSymbol = 0;
+symbol firstContentSymbol = 0;
+symbol lastContentSymbol = 0;
+
+
+// Some useful comparison functions, defined below.
+int suffixCompare(const void *, const void *);
+int prefixCompare(const void *, const void *);
+int pointerCompare(const void *, const void *);
+
+                                           
+// Functions for implementing "phrase memory".  These let us "remember"
+// each phrase that we've expanded without using too much memory.
+void initialisePhraseMemory();
+void rememberThisPhrase(cellindex index, cellcount length);
+bool isPhraseStored(cellindex index, cellcount length);
+void deletePhraseMemory();
+
+
+// how much output do we want?
+int verbosity = 1;
+
+
+// Get a phrase's expansions
+//
+// Get the set of "minimal", "maximal", non-unique expansions of a
+// phrase p, using the simpler algorithm that Craig and Gordon came up
+// with at Google.
+//
+// Returns a vector of Expansions.
+
+void getExpansions(Phrase &p, vector<Phrase> &results) {
+
+  // 1. Get the initial candidates
+  vector<Phrase> candidates;
+  p.initialSuffixCandidates(candidates);
+  int suffcands = candidates.size();
+  p.initialPrefixCandidates(candidates);
+
+  if (candidates.size() == 0)
+    return;
+
+  vector<Phrase>::iterator i;
+  for (i = candidates.begin(); i != candidates.end(), suffcands>0; ++i, --suffcands) {
+    i->expandWhileUniquePrefixExtension();
+    i->ensureSuffixFound();
+  }
+  for (i; i != candidates.end(); ++i) {
+    i->expandWhileUniqueSuffixExtension();
+  }
+
+  // 3. Ensure minimality: ignore phrases whose subphrases are also found
+  results.clear();
+
+  // Initialise the candidates, check array, and various variables.
+  sort(candidates.begin(), candidates.end(), isShorter);
+  unsigned minimum_length = candidates.begin()->length;
+  clearSuffixCheck();
+  
+  // Try to add each candidate to the results set, ignoring the non-minimal
+  for (vector<Phrase>::iterator candidate = candidates.begin(); 
+       candidate != candidates.end(); ++candidate) {
+
+    // Make a copy of candidate to mutilate while performing sub-phrase checks
+    Phrase temp_phrase(*candidate);
+    bool shorter_found = false;
+    
+    // Check for shorter and shorter versions of the temporary phrase
+    while (temp_phrase.length >= minimum_length && !shorter_found) {
+      temp_phrase.ensureSuffixFound();
+      if (getSuffixCheck(temp_phrase.firstSuffixIndex)==0)
+	temp_phrase.shortenByOneAtPrefix();
+      else
+	shorter_found = true;
+
+      // Possible efficiency here: we can finish if the prefix of c
+      // and temp_phrase are the same for candidate->length symbols.
+    }
+      
+    // If no shorter phrase is found, use this one
+    if (!shorter_found) {
+      results.push_back(*candidate);
+      candidate->ensureSuffixFound();
+      setSuffixCheck(candidate->firstSuffixIndex, candidate->lastSuffixIndex);
+    }
+  }
+}
+
+
+// suffixCompare
+//
+// Compare two pointers into a suffix array.  We use this in the 
+// qsort function, so the input are pointers to pointers.  
+//
+// Return -1 if (a < b), otherwise (a > b) so return +1, 
+
+int suffixCompare(const void *cpa, const void *cpb) {
+
+  // Cast then dereference pointers to suffix array elements
+  symbol *pa = (symbol *) cpa;
+  symbol *pb = (symbol *) cpb;
+  pa = (symbol *) *pa;
+  pb = (symbol *) *pb;
+
+  // If the two elements are the same, examine the next one
+  while (*pa == *pb) {
+    *pa++;
+    *pb++;
+  }
+
+  // Make the copmparison and return
+  if ( *pa < *pb) {
+    return -1;
+  } else {
+    return +1;
+  }
+}
+
+
+// prefixCompare
+//
+// Compare two pointers into a prefix array.  We use this in the 
+// qsort function, so the input are pointers to pointers.  
+//
+// Return -1 if (a > b), otherwise (a < b) so return +1, 
+
+int prefixCompare(const void *cpa, const void *cpb) {
+
+  // Cast then dereference pointers to prefix array elements
+  symbol *pa = (symbol *) cpa;
+  symbol *pb = (symbol *) cpb;
+  pa = (symbol *) *pa;
+  pb = (symbol *) *pb;
+
+  // If the two elements are the same, examine the next one
+  while (*pa == *pb) {
+    *pa--;
+    *pb--;
+  }
+
+  // Make the copmparison and return
+  if ( *pa > *pb) {
+    return -1;
+  } else {
+    return +1;
+  }
+}
+
+// simpleCompare
+//
+// Compare two pointers based on the memory location they point to.
+
+int pointerCompare( const void *pa, const void *pb ) {
+
+  symbol **a = (symbol **) pa;
+  symbol **b = (symbol **) pb;
+
+  if (*a < *b) {
+    return  -1;
+  } else if (*a > *b) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+
+// Read the clauses.numbers file into the "symbols" array.
+//
+// Each number in the file is a symbol number; it is essential that 
+// the first symbol (and no others) be COLLECTIONSTART and the last
+// symbol (and no others) be COLLECTIONEND.
+//
+// Return the number of numbers in the array.
+
+int readNumbers() {
+
+  char filename[FILENAME_MAX];
+  sprintf(filename, "%s/clauses.numbers", collection);
+  if (verbosity) {
+    cout << "Reading numbers file: " << filename << endl;
+  }
+
+  // Open the numbers file
+  ifstream inFile1(filename, ios::in);
+  if (!inFile1) {
+    cerr << "File " << filename << " could not be opened\n";
+    exit(1);
+  }
+
+  // Count the number of symbols
+  inputLength = 0;
+  symbol word;
+  while (inFile1 >> word) {
+    ++inputLength;
+  }
+  inFile1.close();
+
+  // Allocate the symbbols array
+  if (verbosity > 1) {
+    cout << "Allocating symbol arrays for " << inputLength << " symbols" << endl;
+  }
+  symbols = new symbol[inputLength];
+  if (symbols == NULL) {
+    cerr << "Suffix error: not enough memory to hold " << inputLength
+	 << " symbols." << endl;
+    exit(2);
+  }
+
+  // Read the numbers file into the numbers array
+  if (verbosity > 2) {
+    cout << "Reading the numbers" << endl;
+  }
+
+  ifstream inFile2(filename, ios::in);
+  if (!inFile2) {
+    cerr << "File " << filename << " could not be opened\n";
+    exit(1);
+  }
+  cellcount next = 0;
+  numberOfDocuments = 0;
+  while (inFile2 >> word) {
+    symbols[next++] = word;
+    if (word == DOCUMENTSTART) {
+      ++numberOfDocuments;
+    }
+  }
+  inFile2.close();
+  
+  // Make sure the numbers file is intact
+  assert(symbols[0] == COLLECTIONSTART);
+  assert(symbols[next-1] == COLLECTIONEND);
+
+  return inputLength;
+}
+
+
+
+// Get Document Occurrance statistics
+//
+// Given a phrase, what documents does it occur in?
+
+cellcount getDocumentOccurrances(const Phrase &p, cellcount *frequency) {
+
+  // cout << "searching for \""<< p << "\" in documents " 
+  //      << 0 << "-" << numberOfDocuments - 1 << endl;
+
+  // The number of documents in which this phrase occurs
+  cellcount df = 0;
+
+  // Initialise the document frequency array
+  //  for (cellindex i = 0; i < numberOfDocuments; ++i) {
+  // frequency[i] = 0;
+  //}
+  memset(frequency, 0, sizeof(cellcount)*numberOfDocuments);
+
+  // variables used to facilitate the search
+  cellindex begin;
+  cellindex end;
+  cellindex d;
+  symbol *target;
+  bool found;
+
+  // search for the document in which each occurence of the phrase is found
+  for (cellcount j = p.firstSuffixIndex; j <= p.lastSuffixIndex; ++j) {
+    
+    // cout << "looking for phrase at suffixArray[" << j << "]\n";
+    
+    target = suffixArray[j];
+    begin = 0;
+    end = numberOfDocuments - 1;
+    found = false;
+
+    // Search for the occurence of a document delimiter that target
+    // occurs immediately after.  
+    // We do this by performing a binary chop search on documentArray.
+    while (!found) {
+
+      // cout << "searching for " << (cellindex) target << " in "
+      //      << begin << " - " << end << endl;
+
+      assert (begin <= end);
+
+      // If the beginning and end of the interval are the same,
+      // then we've found the correct document
+      if (begin == end) {
+	if (frequency[begin] == 0) {
+	  ++df;
+	}
+	++frequency[begin];
+	found = true;
+      }
+
+      // Otherwise, examine a new document midway through the begin-end
+      // interval and see if it is the one.
+      else {
+	d = (begin + end) / 2;
+	if (target > documentArray[d]) {
+	  // If target addrss is greater than this, but thisi sthe last document,
+	  // then this must be the one we want.  Or, if target is greater than
+	  // this one but less then the next, this must be the one we wnat.
+	  if ((d == numberOfDocuments - 1) || (target < documentArray[d+1])) {
+	    if (frequency[d] == 0) {
+	      ++df;
+	    }
+	    ++frequency[d];
+	    found = true;
+	  } else {	
+	    // otherwise we know to search later in the document set
+	    begin = d + 1;
+	  }
+	} else {
+	  // search earlier in the document set
+	  end = d - 1;
+	}
+      }
+    }
+  }
+  return df;
+}
+
+
+
+
+
+
+// phraseExpansionMemory : Which phrases have we expanded?
+//
+// A set of utilities for keeping track of which phrases we have expanded.
+// We don't want to expand a phrase more than once, after all.
+//
+// This REALLY ought to be in its own class, but it works so that's okay.
+//
+// Phrases are identified by their firstSuffixPosition and length.
+//
+// Functions provided are:
+//       void initialisePhraseMemory()
+//       void rememberThisPhrase(index, length)
+//       bool isPhraseStored(index, length)
+//       void deletePhraseMemory()
+//
+// Internally, we will have two separate cases:
+//
+// Phrases of length 1-8: 
+//       unsigned char phraseMemory[inputLength]
+// is an array where each cell "remembers" the corresponding index in the 
+// suffixArray, and each of the 8 bits of the cell correspond to the phrases 
+// of length 1, 2... 8.  
+// Eventually, we will make this disk-based (i.e. store the array in a file).
+//
+// Phrases of length 9+:
+//       file hashTableFile
+//       file listOfEntries
+// The first file is a hash table; each phrase maps to one of its cells, which
+// contains either 0 (empty, no occurence) or a number which is an entry number 
+// in the second file.  This file contains a "list" of entries.  Each consists of 
+// three numbers: the suffixArray index of the phrase, the length of the phrase,
+// and the entry number of the next phrase with the same hash.
+//
+
+
+unsigned char *phraseMemory;
+
+void initialiseLongPhraseMemory();
+void rememberThisLongPhrase(cellindex index, cellcount length);
+bool isLongPhraseStored(cellindex index, cellcount length);
+void deleteLongPhraseMemory();
+
+
+void initialisePhraseMemory() {
+
+  phraseMemory = new unsigned char[inputLength];
+
+  // to begin with, everything is empty
+  //  for (cellcount i = 0; i < inputLength; ++i) {
+  // phraseMemory[i] = 0;
+  //}
+  memset(phraseMemory, 0, sizeof(char)*inputLength);
+  
+  // intialise the hashTable of long phrases
+  initialiseLongPhraseMemory();
+
+}
+
+void rememberThisPhrase(cellindex index, cellcount length) {
+
+  // if the phrase is very long, use the file-based system
+  if (length > 8) {
+    rememberThisLongPhrase(index, length);
+    return;
+  }
+
+  // create a char with just the bit corresponding to length set
+  unsigned char newbit = 1;
+  for (cellcount i = 1; i < length; ++i) {
+    newbit <<= 1;
+  }
+
+  // set that bit in the memory array at position index
+  phraseMemory[index] |= newbit;
+}
+
+
+bool isPhraseStored(cellindex index, cellcount length) {
+
+  // if the phrase is very long, use the file-based system
+  if (length > 8) {
+    return isLongPhraseStored(index, length);
+  }
+
+  // create a char with just the bit corresponding to length set
+  unsigned char newbit = 1;
+  for (cellcount i = 1; i < length; ++i) {
+    newbit <<= 1;
+  }
+
+  // retrurn true if that bit is set in memory arrayat position index
+  return (phraseMemory[index] & newbit);
+}
+
+void deletePhraseMemory() {
+  delete []phraseMemory;
+  deleteLongPhraseMemory();
+}
+
+
+
+// Files etc used to store "long" equavlents of the above
+
+fstream hashTableFile;
+char    hashTableFileName[FILENAME_MAX];
+fstream listOfEntries;
+char    listOfEntriesName[FILENAME_MAX];
+cellindex nextEntryNumber;
+
+const cellcount bigPrime = 7919;
+
+
+void initialiseLongPhraseMemory() {
+
+  cellindex example = 0;
+
+  sprintf(hashTableFileName, "%s/hashTable", collection);
+  sprintf(listOfEntriesName, "%s/hashLists", collection);
+
+
+  // create the new hashtable
+  if (verbosity > 1) {
+    cout << "Initialising hashTable: " << hashTableFileName << endl;
+  }
+  hashTableFile.open(hashTableFileName, ios::in | ios::out);
+  for (cellcount i = 0; i < bigPrime; ++i) {
+    hashTableFile.write((char *) &example, sizeof(example));
+  }
+
+  // create the list of phrases
+  if (verbosity > 1) {
+    cout << "Initialising list of hashtable entries: " << listOfEntriesName << endl;
+  }
+  listOfEntries.open(listOfEntriesName, ios::in | ios::out);
+  listOfEntries.write((char *) &example, sizeof(example));
+  listOfEntries.write((char *) &example, sizeof(example));
+  listOfEntries.write((char *) &example, sizeof(example));
+  nextEntryNumber = 1;
+}
+
+
+void rememberThisLongPhrase(cellindex index, cellcount length) {
+
+  // cout << "rememberThisLongPhrase(" << index << ", " << length << ")\n";
+
+  cellindex hashOffset = ((index + length) % bigPrime) * sizeof(cellindex);
+  cellindex pointer;
+  cellindex zero = 0;
+  cellindex readp = 0;
+  cellindex readi = 0;
+  cellindex readl = 0;
+
+  hashTableFile.seekg(hashOffset);
+  hashTableFile.read((char *) &pointer, sizeof(cellindex));
+
+  if (pointer == 0) {
+    // There is no entry at all in the hash table for this entry
+    // so create one
+
+    pointer = nextEntryNumber++;
+    hashTableFile.seekg(hashOffset);
+    hashTableFile.write((char *) &pointer, sizeof(cellindex));
+        
+    listOfEntries.seekp(pointer * sizeof(cellindex) * 3);
+    listOfEntries.write((char *) &zero, sizeof(cellindex));
+    listOfEntries.write((char *) &index, sizeof(cellindex));
+    listOfEntries.write((char *) &length, sizeof(cellindex));
+
+  } else {
+    // There is a list starting at this hash value, so the phrase may
+    // be already remembered, or it might need to be appended
+    
+    while (pointer != 0) {
+      // Read the entry pointed to by pointer
+      listOfEntries.seekg(pointer * sizeof(cellindex) * 3);
+      listOfEntries.read((char *) &readp, sizeof(cellindex));
+      listOfEntries.read((char *) &readi, sizeof(cellindex));
+      listOfEntries.read((char *) &readl, sizeof(cellindex));
+
+      // cout << "read " << pointer << ", " << readp << ", " << readi << ", " << readl << endl;
+
+      if ((readi == index) && (readl = length)) {
+	// we've found that we've already stored it
+	return;
+      } else if (readp == 0) {
+	// we're reached the end of the list.  Add a new entry.
+	listOfEntries.seekp(pointer * sizeof(cellindex) * 3);
+	listOfEntries.write((char *) &nextEntryNumber, sizeof(cellindex));
+	pointer = nextEntryNumber++;
+
+	listOfEntries.seekp(pointer * sizeof(cellindex) * 3);
+	listOfEntries.write((char *) &zero, sizeof(cellindex));
+	listOfEntries.write((char *) &index, sizeof(cellindex));
+	listOfEntries.write((char *) &length, sizeof(cellindex));
+	return;
+      } else {
+	// go on to the next node
+	pointer = readp;
+      }
+    }
+  }
+
+
+}
+
+
+bool isLongPhraseStored(cellindex index, cellcount length) {
+
+  // cout << "isLongPhraseExpanded(" << index << ", " << length << ")\n";
+
+  cellindex hashOffset = ((index + length) % bigPrime) * sizeof(cellindex);
+  cellindex pointer;
+  cellindex readp = 0;
+  cellindex readi = 0;
+  cellindex readl = 0;
+
+  // Find the phrase in the hashFile
+  hashTableFile.seekg(hashOffset);
+  hashTableFile.read((char *) &pointer, sizeof(cellindex));
+
+  if (pointer == 0) {
+    // There is no entry at all in the hash table for this entry
+    // so nothing is stored
+    return false;
+
+  } else {
+    // There is a list starting at this hash value, so the phrase may
+    // be already remembered in that list
+    while (pointer != 0) {
+      // Read the entry pointed to by pointer
+      listOfEntries.seekg(pointer * sizeof(cellindex) * 3);
+      listOfEntries.read((char *) &readp, sizeof(cellindex));
+      listOfEntries.read((char *) &readi, sizeof(cellindex));
+      listOfEntries.read((char *) &readl, sizeof(cellindex));
+
+      if ((readi == index) && (readl = length)) {
+	// we've found the phrase stored here
+	return true;
+      } else {
+	// go on to the next node
+	pointer = readp;
+      }
+    }
+  }
+  return false;
+}
+
+
+void deleteLongPhraseMemory() {
+  // remove the hash & other files
+
+  hashTableFile.close();
+  listOfEntries.close();
+  remove(hashTableFileName);
+  remove(listOfEntriesName);
+
+}
+
+
+// Read the collection statistics file
+//
+void readStatistics() {
+
+  // open the statistics file
+  char filename[FILENAME_MAX];
+  sprintf(filename, "%s/clauses.stats", collection);
+
+  // Open the file
+  ifstream inFile(filename, ios::in);
+  if (!inFile) {
+    cerr << "File " << filename << " could not be opened\n";
+    exit(1);
+  }
+
+  // Read the numbers file into the numbers array
+  char key[1000];
+  symbol value;
+  while (inFile >> key >> value){
+    if (strcmp(key, "first_stopword") == 0) {
+      firstStopSymbol = value;
+    } else if (strcmp(key, "last_stopword") == 0) {
+      lastStopSymbol = value;
+    } else if (strcmp(key, "first_contentword") == 0) {
+      firstContentSymbol = value;
+    } else if (strcmp(key, "last_contentword") == 0) {
+      lastContentSymbol = value;
+    }
+  }
+  inFile.close();
+
+  // Make sure we have the information we need
+  if (!(firstStopSymbol && lastStopSymbol && firstContentSymbol && lastContentSymbol)) {
+    cerr << "Statistics file incomplete" << endl;
+    exit(1);
+  }
+}
+
+cellcount getContentCount(symbol firstContent) {
+
+  cellcount content=0;
+  for (cellcount i=0; i<inputLength; ++i) {
+    if (symbols[i]>=firstContent) ++content;
+  }
+
+  return content;
+}
+
+
+int main (int argc, char * argv[]) {
+
+  // Command-line arguments
+  // argv[1] is the phindex directory
+  // argv[2] is the mode, where 1 is stopword mode 
+  // argv[3] is the min_occurs, - minimum occurrence frequency for a phrase to be included in the hierarchy
+  // argv[4] is opitonal verbosity
+  if (argc < 4) {
+    cerr << "Usage: " << argv[0] << " phind-directory mode min-phrase-freq [verbosity]" << endl;
+    exit(1);
+  }
+
+  // collection directory
+  strcpy(collection, argv[1]);
+
+  // mode parameter
+  phraseMode = atoi(argv[2]);
+  assert((phraseMode == STOPWORDS) || (phraseMode == ANYPHRASE));
+
+  minOccurs = atoi(argv[3]);
+  assert((minOccurs > 0));
+
+  // optional verbosity parameter
+  if (argc == 5) {
+    verbosity = atoi(argv[4]);
+    assert (verbosity >= 0);
+  }
+
+  if (verbosity) {
+    cout << "suffix: the phrase extraction program" << endl;
+  }
+  if (verbosity > 1) {
+    if (phraseMode == STOPWORDS) {
+      cout << "Stopwords mode: no phrase may begin or end with a stopword" << endl;
+    } else {
+      cout << "AllPhrase mode: extract every phrase that occurs more than once" << endl;
+    }
+  }
+
+  // Read the statistics file 
+  readStatistics();
+  // Read the numbers file
+  readNumbers();
+  
+  if (numberOfDocuments == 0) {
+    cerr << "There are no documents in this collection!" << endl;
+    exit(0); // not necessarily an error...
+  }
+
+  symbol firstContent;
+  if (phraseMode==STOPWORDS) firstContent=firstContentSymbol;
+  else firstContent = firstStopSymbol;
+
+  // Allocate memory for the suffix & prefix arrays
+  cellcount contentLength = 0;
+  contentLength = getContentCount(firstContent);
+  suffixArray = new symbol *[contentLength];
+  prefixArray = new symbol *[contentLength];
+  if (prefixArray == NULL) {
+    cerr << "Suffix: not enough memory to hold " << inputLength << " symbols." << endl;
+    exit(2);
+  }
+  allocateSuffixCheck(contentLength);
+  // Initialise prefix and suffix arrays, only use the needed suffixes
+  for (cellcount j = 0, here = 0; j < inputLength; ++j) {
+    if (symbols[j]>=firstContent) {
+      suffixArray[here] = &symbols[j];
+      prefixArray[here] = &symbols[j];
+      ++here;
+    }    
+  }
+  qsort(suffixArray, contentLength, sizeof(symbol *), suffixCompare);
+  qsort(prefixArray, contentLength, sizeof(symbol *), prefixCompare);
+  // Create the document arrays
+  if (verbosity > 1) {
+    cout << "Allocating document arrays for " << numberOfDocuments << " documents" << endl;
+  }
+
+  // The document frequecy array is used to count the number of times
+  // each phrase occurs in each document.  The number of documents in
+  // which a phrase occurs is stored in df.
+  frequency *documentFrequency = new frequency[numberOfDocuments];
+  frequency df;
+
+  // documentArray will be searched in order to discover which document
+  // each phrase occurs in.
+  documentArray = new symbol *[numberOfDocuments];  
+  if (documentArray == NULL) {
+    cerr << "Suffix: out of memory allocating document arrays." << endl;
+    exit(2);
+  }  
+
+  // just scan through the input text to find the doc starts
+  cellindex d = 0;
+  for (cellindex i=0; i<inputLength; ++i) {
+    if (symbols[i] == DOCUMENTSTART) {
+      documentArray[d] = &symbols[i];
+      ++d;
+    }
+  }
+
+  // the phrases stuff is expecting inputLength to be the length of the
+  // suffix array, so change it.
+  inputLength = contentLength;
+
+  // Extract phrases
+  //
+  // We will make several passesover the data, in each case considering
+  // a set of input phrases and generating a set of output phrases, which
+  // we will expancd in later passes.
+  //
+  // The input phrases in the first pass will be the vocabulary.
+  // In later passes, the input phrases will be the output phrases of the
+  // previous pass.
+  //
+  // In each pass we will consider each input phrase in turn.  If we
+  // have seen it before, we will ignore it.  Otherwise, we will expand
+  // it and add its expansions to the set of output phrases.
+
+  cout <<"\ngenerating the phrase hierarchy\n\n";
+  
+  // Store the phrase data in the phrases file
+  char phraseDataName[FILENAME_MAX];
+  sprintf(phraseDataName, "%s/phrases", collection);
+  ofstream phraseData(phraseDataName, ios::out);
+  if (!phraseData) {
+    cout << "File " << phraseDataName << " could not be opened\n";
+    exit(1);
+  }
+
+  // Count the number of phrases output
+  unsigned long int phraseCounter = 0;
+
+  // Set up the phrase expansion memory.
+  // We need this so that we don't expand a phrase more than once
+  initialisePhraseMemory();
+
+  // The current pass numebr
+  int phrasePass = 1;
+
+
+  // PASS NUMBER 1
+  if (verbosity > 1) {
+    cout << "Starting pass " << phrasePass << endl;
+  }
+
+  ofstream outPhrase;
+  char     outPhraseName[FILENAME_MAX];
+  unsigned long int outPhraseCounter = 0;
+
+  // On the first pass, simply work through the vocabulary
+  sprintf(outPhraseName, "%s/outPhrase.1", collection);
+  outPhrase.open(outPhraseName, ios::out);
+  if (!outPhrase) {
+    cerr << "File " << outPhraseName << " could not be opened\n";
+    exit(1);
+  }
+
+  // Iterate over the different symbols by working through the suffix array
+  vector<Phrase> result;
+  cellindex ij = 0;
+  char *tmpString;
+
+  Phrase p;
+  while (ij < inputLength) {
+
+    // make a new phrase of length 1
+    p = Phrase(suffixArray[ij], 1, SUFFIX);
+    p.findFirstAndLastSuffix(ij, inputLength-1);
+
+    // We ignore this symbol if it occurs only once, if it is a delimiter,
+    // of if we are in stopwords mode and it is a stopword
+    // - in this new version, only need to check freq
+    // We could imagine a new mode/command-line option, which is like 
+    // STOPWORDS but without this restrictrion.  This would let you browse
+    // from "the" to "the AGRIS" for example, but not from "AGRIS" to
+    // "the AGRIS" (where the is a stopword and AGRIS a content word).
+    // The system used to work like this; it is easy to implement, but
+    // it explodes the size of the indexes.  So: would it be useful?  
+    if (p.suffixFrequency >= minOccurs) {
+      // Get minimal expansions of the phrase
+      getExpansions(p, result);
+      
+      if (!result.empty()) {
+	
+	// Remember that we have expanded this phrase
+	rememberThisPhrase(ij, 1);
+
+	// write the phrase text
+	phraseData << ij << "-1:" << p << ":" << p.suffixFrequency << ":"
+		   << result.size() << ":";
+
+	// write the results
+	for (cellcount k = 0; k < result.size(); ++k) {
+	  if (k) {
+	    phraseData << ",";
+	  }
+	  phraseData << result[k].firstSuffixIndex << "-" << result[k].length;
+	  outPhrase << result[k].firstSuffixIndex << " " << result[k].length << endl;
+	  ++outPhraseCounter;
+	}
+	result.clear();
+	
+	// Write the documents in which this phrase occurs
+	df = getDocumentOccurrances(p, documentFrequency);
+	phraseData << ":" << df << ":";
+
+	// write the documents
+	for (cellcount m = 0, first = 1; m < numberOfDocuments; ++m) {
+	  if (documentFrequency[m]) {
+	    if (first) {
+	      first = 0;
+	    } else {
+	      phraseData << ";";
+	    }
+	    // Output the document number.  Note that here we've numbered the 
+	    // N documents from 0 to N-1, but later they'll be 1-N.  Thus we
+	    // add 1 to the document id when we output it.
+	    phraseData << "d" << (m+1);
+	    // Next, output the frequency with which the document occurs, but
+	    // only if it is > 1.
+	    if (documentFrequency[m] > 1) {
+	      phraseData << "," << documentFrequency[m];
+	    }
+	  }
+	}
+
+	phraseData << endl;
+	++phraseCounter;
+
+	// feedback 
+	if (verbosity) {
+	  if (phraseCounter % 1000 == 0) {
+	    cout << "phrase " << phraseCounter << ": "
+		 << "cell " << p.firstSuffixIndex << " - " << p << endl;
+	  }
+	}
+      }
+    }
+   ij = p.lastSuffixIndex + 1;
+  }
+  outPhrase.close();
+
+  // REMAINING PASSES
+  // The previous outPhrase file forms the input to each new pass
+  cellcount start, length;
+  while (outPhraseCounter > 0) {
+
+    // Start a new pass
+    ++phrasePass;
+    if (verbosity) {
+      cout << "Starting pass " << phrasePass << endl;
+    }
+
+    // Open the input file
+    char inPhraseName[FILENAME_MAX];
+    sprintf(inPhraseName, "%s/outPhrase.%d", collection, phrasePass - 1);
+    ifstream inPhrase (inPhraseName, ios::in);
+    if (!inPhrase) {
+      cerr << "File " << inPhraseName << " could not be opened\n";
+      exit(1);
+    }
+
+    // Open the output file
+    sprintf(outPhraseName, "%s/outPhrase.%d", collection, phrasePass);
+    outPhrase.open(outPhraseName, ios::out);
+    if (!outPhrase) {
+      cerr << "File " << outPhraseName << " could not be opened\n";
+      exit(1);
+    }
+    outPhraseCounter = 0;
+
+    // Process each phrase
+    while(inPhrase >> start >> length) {
+
+      // Ignore the phrase if we have expanded it before
+      if (isPhraseStored(start, length))
+	continue;
+
+      // Remember that we have examined this phrase
+      rememberThisPhrase(start, length);
+
+      // Find the phrase in the suffixarray
+      p = Phrase(suffixArray[start], length, SUFFIX);
+      p.findFirstAndLastSuffix(start, inputLength-1);
+
+      // Ignore the phrase if it only occurs once
+      if (p.suffixFrequency < minOccurs)
+	continue;
+
+      // Write the phrase text;
+      phraseData << start << "-" << length << ":" << p << ":" << p.suffixFrequency << ":";
+	
+      // Expand the phrase, if it is fewer than 8 words long
+      if (length <= 8) {
+
+	// Get the minimal expansions for this phrase
+	getExpansions(p, result);
+      
+	// write the results
+	phraseData << result.size() << ":";
+
+	for (cellcount i = 0; i < result.size(); ++i) {
+	  if (i) {
+	    phraseData << ",";
+	  }
+	  phraseData << result[i].firstSuffixIndex << "-" << result[i].length;
+	  outPhrase << result[i].firstSuffixIndex << " " << result[i].length << endl;
+	  ++outPhraseCounter;
+	}
+	result.clear();
+	
+      } else {
+	// phrase is too long to expand further
+	phraseData << "0:";
+      }
+
+      // Write the documents in which this phrase occurs
+      df = getDocumentOccurrances(p, documentFrequency);
+      phraseData << ":" << df << ":";
+
+      // write the documents
+      for (cellcount i = 0, first = 1; i < numberOfDocuments; ++i) {
+	if (documentFrequency[i]) {
+	  if (first) {
+	    first = 0;
+	  } else {
+	    phraseData << ";";
+	  }
+	  // Output the document number.  Note that here we've numbered the 
+	  // N documents from 0 to N-1, but later they'll be 1-N.  Thus we
+	  // add 1 to the document id when we output it.
+	  phraseData << "d" << (i+1);
+	  // Next, output the frequency with which the document occurs, but
+	  // only if it is > 1.
+	  if (documentFrequency[i] > 1) {
+	    phraseData << "," << documentFrequency[i];
+	  }
+	}
+      }
+      
+      phraseData << endl;
+      ++phraseCounter;
+
+      // feedback 
+      if (verbosity) {
+	if (phraseCounter % 1000 == 0) {
+	  cout << "phrase " << phraseCounter << ": "<< "start " << start 
+	       << ", length " << length << " - " << p << endl;
+	}
+      }
+
+    }
+
+    inPhrase.close();
+    outPhrase.close();
+  }
+    
+  phraseData.close();
+  deletePhraseMemory();
+
+  delete [] documentFrequency;
+  delete [] symbols;
+  delete [] suffixArray;
+  delete [] prefixArray;
+  delete [] suffixCheck;
+  delete [] documentArray;
+
+
+  
+  cout << endl << "Done: " << phraseCounter << " phrases in " << phraseDataName << endl;
+  return 0;
+}
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/suffix.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/suffix.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/suffix.h	(revision 10506)
@@ -0,0 +1,89 @@
+/**********************************************************************
+ *
+ * suffix.h -- definitions used in suffix.cpp
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+#ifndef SUFFIX_H
+#define SUFFIX_H
+
+// Types
+
+// The input words stored as an array of type symbol.
+// Required range: 0 - vocabulary size (typically hundreds of thousands)
+typedef unsigned int symbol;
+
+// The cellindex and cellcount types are used when we store indexes
+// to and ranges of cells in large arrays.
+// Required Range: 0 - length of input (typically millions)
+typedef unsigned int cellindex;
+typedef unsigned int cellcount;
+
+// The frequency type is used when we want to store the frequency with 
+// which a phrase (or some other thing) occurs
+// Required range: 0 - frequency of most common symbol (often "the")
+typedef unsigned int frequency;
+
+// Global variables 
+
+// The symbol array holds the input words
+extern cellcount symbol_array_length;
+extern symbol   *symbols;
+
+// The number of words read is storesd in inputLength.
+extern cellcount inputLength;
+
+// Suffix and prefix arrays are used to extract phrases
+extern symbol  **suffixArray;
+extern symbol  **prefixArray;
+
+// Collection-specific information about the first stopword/content symbols
+extern symbol firstStopSymbol;
+extern symbol lastStopSymbol;
+extern symbol firstContentSymbol;
+extern symbol lastContentSymbol;
+
+
+// Are we allowed to terminate a phrase on a stopword?
+extern int phraseMode;
+extern int minOccurs;
+
+#define ANYPHRASE 0
+#define STOPWORDS 1
+
+
+// Direction values
+#define SUFFIX 0
+#define PREFIX 1
+
+
+// Special symbol values
+#define COLLECTIONSTART 1
+#define COLLECTIONEND 2
+#define DOCUMENTSTART 3
+#define PHRASELIMIT 4
+
+#define LASTDELIMITER 4
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/symbol-names.pl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/symbol-names.pl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/symbol-names.pl	(revision 10506)
@@ -0,0 +1,57 @@
+#! /usr/bin/perl -w
+
+###########################################################################
+#
+# symbol-names.pl -- Diagnostic tool that substitutes symbols names for 
+#                    symbol numbers in the output of the suffix program. 
+#
+# Copyright (C) 2000 Gordon Paynter
+#
+# 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.
+#
+###########################################################################
+
+$collection = shift(@ARGV);;
+die "Usage: symbol-names.pl collection [file]\n" unless ($collection);
+
+$vocab = $ENV{'GSDLHOME'} . "/collect/$collection/index/phind1/clauses.vocab";
+if (-e "$vocab") {
+    print "Using vocabulary from: $vocab\n";
+} else {
+    $vocab = $ENV{'GSDLHOME'} . "/collect/$collection/building/phind1/clauses.vocab";
+    if (-e "$vocab") {
+	print "Using vocabulary from: $vocab\n";
+    } else {
+	die "Usage: symbol-names.pl collection [file]\n" unless (-e "$vocab");
+    }
+}
+
+open(V, "<$vocab");
+my $n = 1;
+
+while(<V>) {
+    chomp;
+    $symbol[$n++] = $_;
+}
+
+while(<>) {
+    s/s(\d+)/$symbol[$1]/g;
+    print;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/phind/generate/win32.mak	(revision 10506)
@@ -0,0 +1,70 @@
+###########################################################################
+#
+# win32 makefile -- src/phind/generate
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2001  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..\..\..
+USE_STLPORT = 0
+STLPATH = "$(GSDLHOME)\packages\windows\stlport\stlport"
+
+AR = lib
+CC = cl
+CPPFLAGS = -GX
+LDFLAGS =
+DEFS = -D__WIN32__
+INCLUDES =
+!IF $(USE_STLPORT)
+DEFS = $(DEFS) -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = $(INCLUDES) -I$(STLPATH)
+!ENDIF
+LIBS=
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $< 
+
+HEADERS = suffix.h phrase.h
+SOURCES = suffix.cpp phrase.cpp
+OBJECTS = phrase.obj suffix.obj
+EXEC    = suffix.exe
+
+all: $(EXEC)
+
+install:
+	copy $(EXEC) "$(GSDLHOME)\bin\windows"
+
+clean:
+	del *.obj
+	del $(EXEC)
+
+suffix.exe: $(OBJECTS)
+	    $(LINK) $(OBJECTS) $(LIBS) 
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/GCC.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/GCC.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/GCC.mak	(revision 10506)
@@ -0,0 +1,141 @@
+###########################################################################
+#
+# gcc win32 makefile -- src/recpt
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 2000  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+AR = ar
+RANLIB = ranlib
+CC = g++
+DELETE = del
+INSTALL = copy
+
+o = .o
+/ = \\
+
+CPPFLAGS = -g -Wall
+DEFS = -D__WIN32__ -DGSDL_USE_IOS_H
+LIBS = ..$/..$/packages$/wingdbm$/gdbm.a ..$/..$/packages$/wincrypt$/crypt.a
+
+INCLUDES = -I"..$/..$/lib" -I"..$/colservr" -I"..$/..$/packages$/mg$/lib" \
+           -I"..$/..$/packages$/mg$/src$/text" -I"..$/..$/packages$/wincrypt" \
+           -I"..$/..$/packages$/wingdbm" -I"."
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c $o
+.c$o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp $o
+.cpp$o:
+	$(COMPILE) $< 
+
+COMMONHEADERS = receptionist.h cgiwrapper.h cgiargs.h action.h browserclass.h \
+                converter.h recptconfig.h cgiutils.h OIDtools.h browsetools.h htmlgen.h \
+		statusaction.h pageaction.h comtypes.h recptproto.h \
+		pingaction.h queryaction.h documentaction.h \
+		extlinkaction.h buildaction.h htmlutils.h \
+		querytools.h formattools.h tipaction.h authenaction.h infodbclass.h \
+                userdb.h usersaction.h vlistbrowserclass.h hlistbrowserclass.h \
+		datelistbrowserclass.h invbrowserclass.h pagedbrowserclass.h \
+		htmlbrowserclass.h delhistoryaction.h historydb.h
+
+RECEPTHEADERS = 
+
+LIBRARYHEADERS = nullproto.h
+
+HEADERS = $(COMMONHEADERS) $(RECPTHEADERS) $(LIBRARYHEADERS)
+
+
+COMMONSOURCES = receptionist.cpp cgiwrapper.cpp cgiargs.cpp action.cpp browserclass.cpp \
+                converter.cpp recptconfig.cpp cgiutils.cpp OIDtools.cpp browsetools.cpp \
+		htmlgen.cpp statusaction.cpp pageaction.cpp comtypes.cpp \
+		recptproto.cpp pingaction.cpp queryaction.cpp documentaction.cpp \
+		extlinkaction.cpp buildaction.cpp htmlutils.cpp querytools.cpp formattools.cpp \
+		tipaction.cpp authenaction.cpp infodbclass.cpp userdb.cpp usersaction.cpp \
+		vlistbrowserclass.cpp hlistbrowserclass.cpp datelistbrowserclass.cpp \
+		invbrowserclass.cpp pagedbrowserclass.cpp htmlbrowserclass.cpp \
+		delhistoryaction.cpp historydb.cpp
+
+RECPTSOURCES = recptmain.cpp
+
+LIBRARYSOURCES = nullproto.cpp librarymain.cpp
+
+SOURCES = $(COMMONSOURCES) $(RECPTSOURCES) $(LIBRARYSOURCES)
+
+
+COMMONOBJECTS = receptionist$o cgiwrapper$o cgiargs$o action$o browserclass$o \
+                converter$o recptconfig$o cgiutils$o OIDtools$o browsetools$o \
+		htmlgen$o statusaction$o pageaction$o comtypes$o \
+		recptproto$o pingaction$o queryaction$o documentaction$o \
+		extlinkaction$o buildaction$o htmlutils$o querytools$o \
+		formattools$o tipaction$o authenaction$o \
+                infodbclass$o userdb$o usersaction$o vlistbrowserclass$o \
+		hlistbrowserclass$o datelistbrowserclass$o invbrowserclass$o \
+		pagedbrowserclass$o htmlbrowserclass$o delhistoryaction$o \
+		historydb$o
+
+RECPTOBJECTS = recptmain$o
+
+LIBRARYOBJECTS = nullproto$o librarymain$o
+
+OBJECTS = $(COMMONOBJECTS) $(RECPTOBJECTS) $(LIBRARYOBJECTS)
+
+
+COLSERVROBJECTS = ..$/colservr$/mgq$o \
+                  ..$/colservr$/mgsearch$o \
+                  ..$/colservr$/querycache$o \
+                  ..$/colservr$/queryinfo$o \
+                  ..$/colservr$/collectserver$o \
+                  ..$/colservr$/colservrconfig$o \
+                  ..$/colservr$/maptools$o \
+                  ..$/colservr$/filter$o \
+                  ..$/colservr$/source$o \
+                  ..$/colservr$/browsefilter$o \
+                  ..$/colservr$/queryfilter$o \
+                  ..$/colservr$/mggdbmsource$o \
+                  ..$/colservr$/phrasesearch$o \
+                  ..$/colservr$/phrasequeryfilter$o
+
+
+EXEC = library.exe
+
+all: $(EXEC)
+
+clean:
+	if EXIST *$o $(DELETE) *$o
+	if EXIST $(EXEC) $(DELETE) $(EXEC)
+
+install:
+	$(INSTALL) $(EXEC) ..$/..$/cgi-bin$/
+
+LIBRARY_OBJS = $(COMMONOBJECTS) $(LIBRARYOBJECTS) $(COLSERVROBJECTS) \
+    ..$/..$/lib$/gsdllib.a  \
+    ..$/..$/packages$/mg$/src$/text$/libtextin.a \
+    ..$/..$/packages$/mg$/lib$/libmg.a
+
+library.exe: $(LIBRARY_OBJS)
+	$(LINK) $(LIBRARY_OBJS) $(LIBS) 
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/Makefile.in	(revision 10506)
@@ -0,0 +1,398 @@
+###########################################################################
+#
+# Makefile -- src/recpt
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+USE_Z3950 = @USE_Z3950@
+ifeq ($(USE_Z3950), 1)
+Z_CFLAGS=-DUSE_Z3950
+else
+Z_CFLAGS=
+endif
+
+USE_CORBA = @USE_CORBA@
+ifeq ($(USE_CORBA), 1)
+CORBA_CFLAGS=-DUSE_CORBA
+else
+CORBA_CFLAGS=
+endif
+
+AR = ar
+CC = @CC@
+CXX = @CXX@
+#CCFLAGS = @CFLAGS@ -Wall -Wunused -pedantic -W -Woverloaded-virtual
+
+CXXFLAGS = $(Z_CFLAGS) $(CORBA_CFLAGS) @CXXFLAGS@
+
+# YAZ kit for z39.50
+YAZDIR=../../packages/yaz
+
+
+USE_FASTCGI = @USE_FASTCGI@
+ifneq ($(USE_FASTCGI), 1)
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM @DEFS@
+INCLUDES = -I../../lib -I. -I../colservr -I../../packages/mg \
+	   -I../../packages/mg/lib -I../../packages/mg/src/text \
+           -I../../packages/expat/include \
+	   -I../mgpp/lib -I../mgpp/text -I../..
+else 
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DUSE_FASTCGI @DEFS@
+INCLUDES = -I../../lib -I. -I../colservr -I../../packages/mg \
+	   -I../../packages/mg/lib -I../../packages/mg/src/text \
+           -I../../packages/expat/include \
+           -I../../packages/fcgi/include -I../mgpp/lib \
+	   -I../mgpp/text -I../..
+endif
+MICO_DIR = @MICO_DIR@
+MICO_VER = @MICO_VER@
+ifeq ($(MICO_DIR), yes)
+MICO_INC =
+MICO_LIB =
+MICO_PATH =
+else
+ifeq ($(MICO_DIR), default)
+MICO_DIR = ../../packages/mico/include
+MICO_PATH = ../../bin/linux/
+else
+MICO_PATH =
+endif
+MICO_INC = -I$(MICO_DIR)
+MICO_LIB = -L$(MICO_DIR)
+endif
+MINCLUDES = -I. -I../../lib -I../colservr -I../mgpp/text $(MICO_INC)
+
+LC_LIBS     = ../../packages/expat/lib/libexpat.a
+LC_OBJECTS  = \
+	../colservr/lucenesearch.o   \
+	../colservr/lucenequeryfilter.o \
+	../colservr/lucenegdbmsource.o \
+	../colservr/expat_resultset.o \
+	../colservr/expat_document.o
+
+RANLIB = @RANLIB@
+LDFLAGS = @LDFLAGS@
+GDBM_LIBS=@GDBM_LIBPATH@ -lgdbm
+LIBS = $(GDBM_LIBS) $(LC_LIBS) @LIBS@
+GSDLOS = @gsdlos@
+INSTALL = @INSTALL@
+
+COMPILE = $(CC) -c $(CCFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+CXXCOMPILE = $(CXX) -c $(CXXFLAGS) $(DEFS) $(INCLUDES)
+CXXLINK = $(CXX) $(LDFLAGS) -o $@
+
+MCOMPILE = $(MICO_PATH)mico-c++ -x c++ $(MCFLAGS) $(DEFS) $(MINCLUDES) -c
+MSTATIC = @STATIC@
+MLINK = $(MICO_PATH)mico-ld $(MSTATIC)  $(LDFLAGS) $(MICO_LIB) -o  $@
+MLIBS = $(LIBS) -L../../lib/ -lmico$(MICO_VER) -lmicoaux$(MICO_VER)
+
+# in case gdbm.h/libgdbm.a are in a non-standard place...
+GDBM_OBJS=argdb.o authenaction.o collectoraction.o infodbclass.o userdb.o usersaction.o historydb.o librarymain.o nullproto.o queryaction.o z3950proto.o
+
+ifeq ($(USE_CORBA), 1)
+#EXEC = recpt library corbaserver corbarecptldd
+EXEC = library corbaserver corbarecptldd
+else
+#EXEC = recpt library
+EXEC = library
+endif
+
+ifeq ($(USE_Z3950), 1)
+Z3950EXEC = z3950server
+else
+Z3950EXEC =
+endif
+
+all: $(EXEC) $(Z3950EXEC)
+
+
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CXXCOMPILE) $< 
+
+$(GDBM_OBJS) :%.o :%.cpp
+	$(CXXCOMPILE) @GDBM_INCLUDE@ $<
+
+.SUFFIXES: .mpp .o
+.mpp.o:
+	$(MCOMPILE) $< -o $@
+
+
+COMMONHEADERS = receptionist.h cgiwrapper.h cgiargs.h action.h browserclass.h \
+                converter.h recptconfig.h cgiutils.h OIDtools.h browsetools.h \
+		statusaction.h pageaction.h comtypes.h recptproto.h \
+		pingaction.h queryaction.h documentaction.h  \
+		extlinkaction.h browseaction.h htmlutils.h argdb.h \
+		querytools.h browseactiontools.h formattools.h tipaction.h authenaction.h infodbclass.h \
+                userdb.h usersaction.h vlistbrowserclass.h hlistbrowserclass.h \
+		datelistbrowserclass.h invbrowserclass.h pagedbrowserclass.h \
+		htmlbrowserclass.h phindbrowserclass.h historydb.h collectoraction.h \
+		phindaction.h summarise.h highlighttext.h gtiaction.h
+
+RECEPTHEADERS = 
+
+ifeq ($(USE_CORBA), 1)
+LIBRARYHEADERS = nullproto.h z3950proto.h z3950proxy.h corbaproto.h
+else
+LIBRARYHEADERS = nullproto.h z3950proto.h z3950proxy.h
+endif
+
+HEADERS = $(COMMONHEADERS) $(RECPTHEADERS) $(LIBRARYHEADERS)
+
+
+COMMONSOURCES = receptionist.cpp cgiwrapper.cpp cgiargs.cpp action.cpp browserclass.cpp \
+                converter.cpp recptconfig.cpp cgiutils.cpp OIDtools.cpp browsetools.cpp \
+		statusaction.cpp pageaction.cpp comtypes.cpp  \
+		recptproto.cpp pingaction.cpp queryaction.cpp documentaction.cpp \
+		extlinkaction.cpp browseaction.h htmlutils.cpp querytools.cpp \
+		tipaction.cpp authenaction.cpp infodbclass.cpp userdb.cpp usersaction.cpp \
+		vlistbrowserclass.cpp hlistbrowserclass.cpp datelistbrowserclass.cpp \
+		invbrowserclass.cpp pagedbrowserclass.cpp htmlbrowserclass.cpp \
+		phindbrowserclass.cpp  historydb.cpp collectoraction.cpp argdb.cpp \
+		browseactiontools.h formattools.cpp phindaction.cpp summarise.cpp \
+		highlighttext.cpp gtiaction.cpp
+
+
+RECPTSOURCES = recptmain.cpp
+
+ifeq ($(USE_Z3950), 1)
+Z_LIBSOURCES=z3950proto.cpp z3950proxy.cpp yaz_zclient.c zparse.tab.c parse.yy.c $(YAZDIR)/yaz-2.1.4/client/tabcomplete.c
+else
+Z_LIBSOURCES=
+endif
+
+LIBRARYSOURCES = nullproto.cpp librarymain.cpp $(Z_LIBSOURCES)
+
+SOURCES = $(COMMONSOURCES) $(RECPTSOURCES) $(LIBRARYSOURCES)
+
+
+ifeq ($(USE_Z3950), 1)
+Z_COMOBJS=parse.yy.o
+else
+Z_COMOBJS=
+endif
+
+
+COMMONOBJECTS = receptionist.o cgiwrapper.o cgiargs.o action.o browserclass.o \
+                converter.o recptconfig.o cgiutils.o OIDtools.o browsetools.o \
+		statusaction.o pageaction.o comtypes.o \
+		recptproto.o pingaction.o queryaction.o documentaction.o \
+		extlinkaction.o browseaction.o htmlutils.o querytools.o browseactiontools.o \
+		formattools.o tipaction.o authenaction.o argdb.o \
+                infodbclass.o userdb.o usersaction.o vlistbrowserclass.o \
+		hlistbrowserclass.o datelistbrowserclass.o invbrowserclass.o \
+		pagedbrowserclass.o htmlbrowserclass.o phindbrowserclass.o \
+		historydb.o $(Z_COMOBJS) collectoraction.o phindaction.o \
+		summarise.o highlighttext.o gtiaction.o
+
+RECPTOBJECTS = recptmain.o
+
+
+ifeq ($(USE_Z3950), 1)
+Z_LIBOBJS=z3950proto.o z3950proxy.o yaz_zclient.o zparse.tab.o 
+Z_CLIENTOBJS=$(YAZDIR)/yaz-2.1.4/client/tabcomplete.o 
+else
+Z_LIBOBJS=
+Z_CLIENTOBJS=
+endif
+
+LIBRARYOBJECTS = nullproto.o librarymain.o $(Z_LIBOBJS)
+
+OBJECTS = $(COMMONOBJECTS) $(RECPTOBJECTS) $(LIBRARYOBJECTS)
+
+
+COLSERVROBJECTS = ../colservr/mgq.o \
+		  ../colservr/search.o \
+                  ../colservr/mgsearch.o \
+                  ../colservr/querycache.o \
+                  ../colservr/queryinfo.o \
+                  ../colservr/collectserver.o \
+                  ../colservr/colservrconfig.o \
+                  ../colservr/maptools.o \
+                  ../colservr/filter.o \
+                  ../colservr/source.o \
+                  ../colservr/browsefilter.o \
+                  ../colservr/queryfilter.o \
+                  ../colservr/gdbmsource.o \
+                  ../colservr/mggdbmsource.o \
+                  ../colservr/phrasesearch.o \
+                  ../colservr/phrasequeryfilter.o \
+		  ../colservr/mgqueryfilter.o \
+		  ../colservr/mgppsearch.o \
+		  ../colservr/mgppqueryfilter.o \
+		  ../colservr/collectset.o \
+		  $(LC_OBJECTS)
+
+
+
+## z39.50 rules
+# Note! If USE_FASTCGI=1, yaz is still compiled and linked, but never
+# called by librarymain.cpp.
+yaz_zclient.o: yaz_zclient.c
+	$(COMPILE) -I$(YAZDIR)/include -I$(YAZDIR)/yaz-2.1.4/client $<
+
+# this should be done by the top level makefile...
+$(YAZDIR)/lib/libyaz.a:
+	cd $(YAZDIR)/yaz-2.1.4/src && $(MAKE) && $(MAKE) install
+
+# put a separate rule here, as it speeds up compilation of other objects
+# if they don't need to include all the yaz headers
+z3950%.o: z3950%.cpp
+	$(COMPILE) -I$(YAZDIR)/include $<
+
+zparse.tab.c: zparse.y
+	@YACC@ -b zparse -d zparse.y
+
+zparse.tab.h: zparse.tab.c
+
+parse.yy.c: parse.fl zparse.tab.h
+	flex -oparse.yy.c parse.fl
+
+
+
+# We'll keep the .c and .h files for those without lex/flex and yacc/bison.
+#PARSE_TMPFILES= zparse.tab.o zparse.tab.c zparse.tab.h parse.yy.o parse.yy.c
+PARSE_TMPFILE=zparse.tab.o parse.yy.o
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) $(PARSE_TMPFILES) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC) $(PARSE_TMPFILES)
+
+install:
+	$(INSTALL) -m 755 -s library ../../cgi-bin
+ifeq ($(USE_Z3950), 1)
+	$(INSTALL) -m 755 -s z3950server ../../bin/$(GSDLOS)
+endif
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CXXFLAGS) -- $(SOURCES)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ifeq ($(USE_FASTCGI), 1)
+    FASTCGI_OBJS = ../../packages/fcgi/libfcgi/libfcgi.a
+else
+    FASTCGI_OBJS =
+endif
+
+RECPT_OBJS = $(COMMONOBJECTS) $(RECPTOBJECTS) \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    $(FASTCGI_OBJS) \
+    ../mgpp/text/libtextin.a \
+    ../mgpp/lib/libmg.a 
+
+recpt: $(RECPT_OBJS)
+	$(CXXLINK) $(RECPT_OBJS) $(LIBS) 
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ifeq ($(USE_Z3950), 1)
+Z_LIBYAZ_A=$(YAZDIR)/lib/libyaz.a
+else
+Z_LIBYAZ_A=
+endif
+
+
+LIBRARY_OBJS = $(COMMONOBJECTS) $(LIBRARYOBJECTS) $(COLSERVROBJECTS) $(Z_CLIENTOBJS) \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    $(FASTCGI_OBJS) $(Z_LIBYAZ_A) \
+    ../mgpp/text/libtextin.a \
+    ../mgpp/lib/libmg.a
+
+library: $(LIBRARY_OBJS)
+	$(CXXLINK) $(LIBRARY_OBJS) $(LIBS)
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+RECPTLIB_OBJECTS = nullproto.o corbaproto.o \
+                   ../../lib/corbatext_t.o ../../lib/corbaconv_text_t.o \
+		   ../../lib/corbaiface.o ../../lib/corbaiface_skel.o
+
+RLIBRARY_OBJS = $(COMMONOBJECTS) $(RECPTLIB_OBJECTS) $(COLSERVROBJECTS) \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    $(FASTCGI_OBJS) $(Z_LIBOBJS) $(Z_LIBYAZ_A) \
+    ../mgpp/text/libtextin.a \
+    ../mgpp/lib/libmg.a 
+
+RECPTLIB_OBJS = $(RLIBRARY_OBJS) ../colservr/corbaServer.o
+
+corbaserver: $(RECPTLIB_OBJS)
+	@echo -e building corbaserver
+	$(MLINK) $(RECPTLIB_OBJS) $(MLIBS)
+# stripping symbols was a cunning plan, but caused difficulties when 
+#  it came to debugging ...
+# non GNU strips might not like these options - check autoconf?
+#	strip --strip-all --discard-all corbaserver
+#	strip corbaserver
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+CORBARECPT_OBJECTS = nullproto.o corbaproto.o corbaclient.o
+
+CORBARECPT_OBJS = $(COMMONOBJECTS) $(CORBARECPT_OBJECTS) $(COLSERVROBJECTS) \
+    ../../lib/corbaiface.o \
+    ../../lib/corbaiface_skel.o \
+    ../../lib/corbaconv_text_t.o \
+    ../../lib/corbatext_t.o \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    $(FASTCGI_OBJS) \
+    ../mgpp/text/libtextin.a \
+    ../mgpp/lib/libmg.a 
+
+
+corbarecptldd: $(CORBARECPT_OBJS)
+	@echo -e building corbarecptldd:
+	$(MLINK)  $(CORBARECPT_OBJS)  $(MLIBS) 
+
+test:
+
+Z3950_OBJS = $(COMMONOBJECTS) $(COLSERVROBJECTS) \
+    ../colservr/z3950parser.o ../colservr/z3950explain.o \
+    ../colservr/z3950_to_gsdl.o \
+    ../colservr/z3950server.o ../colservr/read-grs.o nullproto.o \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    $(FASTCGI_OBJS) \
+    ../mgpp/text/libtextin.a \
+    ../mgpp/lib/libmg.a ../../packages/yaz/lib/libyaz.a ../../packages/d2m/libd2m.a
+
+
+z3950server: $(Z3950_OBJS)
+	@echo -e building z3950server
+	$(CXXLINK) $(Z3950_OBJS) $(LIBS)
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/OIDtools.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/OIDtools.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/OIDtools.cpp	(revision 10506)
@@ -0,0 +1,349 @@
+/**********************************************************************
+ *
+ * OIDtools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "OIDtools.h"
+#include <assert.h>
+
+// returns (in top) the top level of OID (i.e. everything
+// up until the first dot)
+void get_top (const text_t &OID, text_t &top) {
+
+  top.clear();
+  if (OID.empty()) return;
+
+  text_t::const_iterator begin = OID.begin();
+  text_t::const_iterator end = OID.end();
+
+  top.appendrange (begin, findchar(begin, end, '.'));
+}	
+
+
+// checks if OID is top level (i.e. contains no dots)
+bool is_top (const text_t &OID) {
+
+  if (OID.empty()) return true;
+
+  text_t::const_iterator here = OID.begin();
+  text_t::const_iterator end = OID.end();
+  here = findchar (here, end, '.');
+
+  if (here == end) return true;
+  return false;
+}
+
+
+// get_parents_array loads the parents array with all the parents of the
+// document or classification specified by OID (not including OID itself)
+void get_parents_array (const text_t &OID, text_tarray &parents) {
+
+  text_t::const_iterator here = OID.begin ();
+  text_t::const_iterator end = OID.end ();
+  text_t thisparent;
+
+  while (here != end) {
+    if (*here == '.') parents.push_back(thisparent);
+    thisparent.push_back(*here);
+    ++here;
+  }
+}
+
+
+// get_info does a protocol call and returns (in response) the metadata 
+// associated with OID. Metadata should be loaded with whatever
+// metadata fields are to be requested.
+
+bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout) {
+
+  response.clear();
+
+  comerror_t err = noError;
+  FilterRequest_t request;
+  request.clear();
+
+  request.filterName = "NullFilter";
+  request.filterLang = lang;
+  request.filterResultOptions = FRmetadata;
+  request.getParents = getParents;
+  request.fields = metadata;
+  request.docSet.push_back (OID);
+  assert (collectproto != NULL);
+
+  collectproto->filter (collection, request, response, err, logout);
+  if (err != noError) {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed for " << OID
+	   << " in OIDtools::get_info (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+  
+  return true;
+}
+
+// overloaded, to allow "custom" filter options.
+bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, const OptionValue_tarray &options,
+	       bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout) {
+
+  response.clear();
+
+  comerror_t err = noError;
+  FilterRequest_t request;
+
+  request.filterName = "NullFilter";
+  request.filterLang = lang;
+  request.filterResultOptions = FRmetadata;
+  request.getParents = getParents;
+  request.filterOptions = options;
+  request.fields = metadata;
+  request.docSet.push_back (OID);
+
+  assert (collectproto != NULL);
+  collectproto->filter (collection, request, response, err, logout);
+  if (err != noError) {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed for " << OID
+	   << " in OIDtools::get_info (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+  
+  return true;
+}
+
+bool get_info (const text_tarray &OIDs, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout) {
+
+  response.clear();
+  if (OIDs.empty()) return true;
+
+  comerror_t err = noError;
+  FilterRequest_t request;
+
+  request.filterName = "NullFilter";
+  request.filterLang = lang;
+  request.filterResultOptions = FRmetadata;
+  request.getParents = getParents;
+  request.fields = metadata;
+
+  request.docSet = OIDs;
+  
+  collectproto->filter (collection, request, response, err, logout);
+  if (err != noError) {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed in OIDtools::get_info (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+
+  return true;
+}
+
+
+
+// has_children returns true if OID has children
+bool has_children (const text_t &OID, const text_t &collection, const text_t &lang,
+		   recptproto *collectproto, ostream &logout) {
+
+  FilterResponse_t response;
+  text_tset metadata;
+  metadata.insert ("haschildren");
+
+  if (get_info (OID, collection, lang, metadata, false, collectproto,	response, logout)) {
+    if (response.docInfo[0].metadata["haschildren"].values[0] == "1")
+      return true;
+  }
+  return false;
+}
+
+
+// get_children does a protocol call and returns (in response) the OIDs and 
+// metadata of all the children of OID. The metadata set should be loaded
+// with whatever metadata fields are to be requested.
+
+bool get_children (const text_t &OID, const text_t &collection, const text_t &lang,
+		   const text_tset &metadata, bool getParents,
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout) {
+  
+  response.clear();
+
+  comerror_t err = noError;
+  FilterRequest_t request;
+  OptionValue_t option;
+
+  option.name = "ParentNode";
+  option.value = OID;
+  request.filterOptions.push_back (option);
+  request.filterName = "BrowseFilter";
+  request.filterLang = lang;
+  request.filterResultOptions = FROID | FRmetadata;
+  request.fields = metadata;
+  request.getParents = getParents;
+
+  collectproto->filter (collection, request, response, err, logout);
+
+  if (err != noError) {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii
+	   << "Error: call to filter failed for " << OID 
+	   << " in OIDtools::get_children (" 
+	   << get_comerror_string (err) << ")\n";
+    return false;
+  }
+  return true;
+}
+
+// get_parent returns the parent of the document or classification
+// specified by OID
+text_t get_parent (text_t OID) {
+
+  if (OID.empty() || is_top (OID)) return "";
+
+  text_t::const_iterator begin = OID.begin();
+  text_t::const_iterator here = (OID.end() - 1);
+
+  while (here >= begin) {
+    OID.pop_back();
+    if (*here == '.') break;
+    --here;
+  }
+  return OID;
+}
+
+// takes an OID like ".2 and replaces the " with parent
+void translate_parent (text_t &OID, const text_t &parent) {
+
+  text_t::const_iterator here = OID.begin();
+  text_t::const_iterator end = OID.end();
+  text_t temp;
+
+  while (here != end) {
+    if (*here == '"') temp += parent;
+    else temp.push_back (*here);
+    ++here;
+  }
+  OID = temp;
+}
+
+// shrink_parent does the opposite to translate_parent
+void shrink_parent (text_t &OID) {
+  
+  text_tarray tmp;
+  splitchar (OID.begin(), OID.end(), '.', tmp);
+  OID = "\"." + tmp.back();
+}
+
+// checks if OID uses ".fc", ".lc", ".pr", ".ns",
+// or ".ps" syntax (first child, last child, parent,
+// next sibling, previous sibling)
+bool needs_translating (const text_t &OID) {
+
+  if (OID.size() < 4) return false;
+
+  text_t tail = substr (OID.end()-3, OID.end());
+  if (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
+      tail == ".ns" || tail == ".ps") return true;
+
+  return false;
+}
+
+// strips the ".fc", ".lc", ".pr", ".ns",
+// or ".ps" suffix from the end of OID
+void strip_suffix (text_t &OID) {
+
+  text_t tail = substr (OID.end()-3, OID.end());
+  while (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
+	 tail == ".ns" || tail == ".ps") {
+    OID.erase (OID.end()-3, OID.end());
+    tail = substr (OID.end()-3, OID.end());
+  }
+}
+
+static void recurse_contents (ResultDocInfo_t section, const bool &is_classify, 
+			      const text_t &collection, const text_t &lang,
+			      const text_tset &metadata, 
+			      recptproto *collectproto, FilterResponse_t &response, 
+			      ostream &logout) {
+
+  int haschildren = section.metadata["haschildren"].values[0].getint();
+  const text_t &doctype = section.metadata["doctype"].values[0];
+
+  if ((haschildren == 1) && ((!is_classify) || (doctype == "classify"))) {
+    FilterResponse_t tmp;
+    bool getParents = false;
+    get_children (section.OID, collection, lang, metadata, getParents, collectproto, tmp, logout);
+    ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
+    ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
+    while (thisdoc != lastdoc) {
+      response.docInfo.push_back (*thisdoc);
+      recurse_contents (*thisdoc, is_classify, collection, lang, metadata, 
+			collectproto, response, logout);
+      ++thisdoc;
+    }
+  }
+}
+
+// get_contents returns OIDs and metadata of all contents 
+// below (and including) OID.
+void get_contents (const text_t &topOID, const bool &is_classify, 
+		   text_tset &metadata, const text_t &collection, const text_t &lang,
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout) {
+
+  if (topOID.empty()) return;
+  response.clear();
+
+  metadata.insert ("haschildren");
+  metadata.insert ("doctype");
+
+  // get topOIDs info
+  if (get_info (topOID, collection, lang, metadata, false, collectproto, response, logout)) {
+    recurse_contents (response.docInfo[0], is_classify, collection, lang,
+		      metadata, collectproto, response, logout);
+  }
+}
+
+// is_child_of returns true if OID2 is a child of OID1
+bool is_child_of(const text_t &OID1, const text_t &OID2) {
+
+  text_t parent = get_parent(OID2);
+
+  while (!parent.empty()) {
+    if (parent == OID1) return true;
+    parent = get_parent(parent);
+  }
+  return false;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/OIDtools.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/OIDtools.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/OIDtools.h	(revision 10506)
@@ -0,0 +1,123 @@
+/**********************************************************************
+ *
+ * OIDtools.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef OIDTOOLS_H
+#define OIDTOOLS_H
+
+#include "text_t.h"
+#include "recptproto.h"
+
+void get_oid (const text_t &OID, text_t &to, size_t level);
+
+// returns (in top) the top level of OID (i.e. everything
+// up until the first dot)
+void get_top (const text_t &OID, text_t &top);
+
+// checks if OID is top level (i.e. contains no dots)
+bool is_top (const text_t &OID);
+
+// get_parents_array loads the parents array with all the parents of the
+// document or classification specified by OID (not including OID itself)
+void get_parents_array (const text_t &OID, text_tarray &parents);
+
+// get_info does a protocol call and returns (in response) the info 
+// associated with OID. Metadata should be loaded with whatever
+// metadata fields are to be requested
+bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout);
+bool get_info (const text_t &OID, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, const OptionValue_tarray &options,
+	       bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout);
+bool get_info (const text_tarray &OIDs, const text_t &collection, const text_t &lang,
+	       const text_tset &metadata, bool getParents,
+	       recptproto *collectproto, FilterResponse_t &response, 
+	       ostream &logout);
+
+// has_children returns true if OID has children
+bool has_children (const text_t &OID, const text_t &collection, const text_t &lang, 
+		   recptproto *collectproto, ostream &logout);
+bool has_text(const text_t &OID, const text_t &collection, const text_t &lang,
+		   recptproto *collectproto, ostream &logout);
+
+inline bool has_text(MetadataInfo_tmap& metadata)
+{
+	if (metadata["hastxt"].values.size() > 0) {
+		return metadata["hastxt"].values[0].getint() != 0;
+	}
+	return false;
+}
+
+inline bool has_children(MetadataInfo_tmap& metadata)
+{
+	if (metadata["haschildren"].values.size() > 0) {
+		return metadata["haschildren"].values[0].getint() != 0;
+	}
+	return false;
+}
+
+// get_children does a protocol call and returns (in response) the OIDs and 
+// metadata of all the children of OID. The metadata set should be loaded
+// with whatever metadata fields are to be requested.
+bool get_children (const text_t &OID, const text_t &collection, const text_t &lang, 
+		   const text_tset &metadata, bool getParents,
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout);
+
+// get_parent returns the parent of the document or classification
+// specified by OID
+text_t get_parent (text_t OID);
+
+// takes an OID like ".2.3 and replaces the " with parent
+void translate_parent (text_t &OID, const text_t &parent);
+
+// shrink_parent does the opposite to translate_parent
+void shrink_parent (text_t &OID);
+
+// checks if OID uses ".fc", ".lc", ".pr", ".ns",
+// or ".ps" syntax (first child, last child, parent,
+// next sibling, previous sibling)
+bool needs_translating (const text_t &OID);
+
+// strips the ".fc", ".lc", ".pr", ".ns",
+// or ".ps" suffix from the end of OID
+void strip_suffix (text_t &OID);
+
+// get_contents returns OIDs and metadata of all contents 
+// below (and including) OID.
+void get_contents (const text_t &topOID, const bool &is_classify, 
+		   text_tset &metadata, const text_t &collection, const text_t &lang, 
+		   recptproto *collectproto, FilterResponse_t &response, 
+		   ostream &logout);
+
+// is_child_of returns true if OID2 is a child of OID1
+bool is_child_of(const text_t &OID1, const text_t &OID2);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/TODO
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/TODO	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/TODO	(revision 10506)
@@ -0,0 +1,57 @@
+For Z 39.50 Stuff
+
+pageaction.cpp
+--------------
+Macros:
+ * for "about" page, use a custom _textbrowseoptions_ macro (ie
+   create a new macro, maybe create a z3950.dm macro file ??)
+   (also maybe _numbrowseoptions_
+
+(Irrelevant?) (c. line 332)
+    disp.setmacro ("numdocs", "Global", cinfo.numDocs);
+    disp.setmacro ("builddate", "Global", builddate);
+
+That message "This collection contains..." is in the _collectionextra_
+macro.
+could get numdocs from the z39.50 server, as well as any other status
+information.
+
+win32.mak
+---------
+Needs updating for all added files (z*, parse.fl)
+
+yaz
+---
+Maybe put libyaz.a in $GSDLHOME/lib ?
+
+
+DESIGN ISSUES
+for z39.50 (and eventually nullproto when corba allows recept. and
+coll server to be physically separate), if the server is unavailable,
+should this be determined at:
+  * "home page" creation time, in which case the recept. must ping and
+test each collection it knows about, which may cause unacceptable delay, or
+  * "about page" creation time (ie individual collection), in which case
+the collection can not customise the page layout by modifying macros.
+
+Eg currently, the z39.50 collection will not create a TCP connection to the
+"target" (ie z39.50 server somewhere around the world) until it tries to
+get the "About this collection" information for that collection. 
+If the connection fails, the protocol can not change _queryform_ part of
+the page.
+
+
+MULTI-LINGUAL SUPPORT
+Multi-lingual - eg macros - want to set _collectionextra_ using
+metadata["collectionextra"] based on the chosen interface language.
+Should be done by OIDtools.cpp:get_info() and any action that calls
+proto->filter().
+queryaction.cpp (c. line 1097):
+  // add the requested language as an option to the query
+  if (!args["l"].empty()) {
+    OptionValue_t option;
+    option.name="Language";
+    option.value=args["l"];
+    request.filterOptions.push_back(option);
+  }
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/action.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/action.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/action.cpp	(revision 10506)
@@ -0,0 +1,157 @@
+/**********************************************************************
+ *
+ * action.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "action.h"
+#include <assert.h>
+
+
+// define all the macros which are related to pages generated
+// by this action
+void action::define_internal_macros (displayclass &/*disp*/, cgiargsclass &/*args*/, 
+				     recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+}
+
+action::action () {
+}
+
+action::~action () {
+}
+
+// configure should be called once for each configuration line
+void action::configure (const text_t &key, const text_tarray &cfgline) {
+  if (key == "gsdlhome") {
+    gsdlhome = cfgline[0];
+    if (gdbmhome.empty()) gdbmhome = cfgline[0];
+  }
+  if (key == "gdbmhome") {gdbmhome = cfgline[0];}
+}
+
+// init should be called after all the configuration is done but
+// before any other methods are called
+bool action::init (ostream &/*logout*/) {
+  return true;
+}
+
+// returns the "a" argument value that will specify this action
+// this name should be short but does not have to be one character
+// long
+text_t action::get_action_name () {
+  return "nzdl";
+}
+
+// check_cgiargs should be called before get_cgihead_info, 
+// define_external_macros, and do_action. If an error is found
+// a message will be written to logout, if the error is severe
+// then the function will return false and no page content
+// should be produced based on the arguments.
+bool action::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &/*args*/, 
+			    recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+  return true;
+}
+
+// check_external_cgiargs should be called after check_cgiargs
+// for all actions. It should only be used to override some other
+// normal behaviour, for example, producing a login page when
+// the requested page needs authentication.
+bool action::check_external_cgiargs (cgiargsinfoclass &/*argsinfo*/,
+				     cgiargsclass &/*args*/,
+				     outconvertclass &/*outconvert*/,
+				     const text_t &/*saveconf*/,
+				     ostream &/*logout*/) {
+  return true;
+}
+
+// get_cgihead_info determines the cgi header information for
+// a set of cgi arguments. If response contains location then
+// response_data contains the redirect address. If reponse
+// contains content then reponse_data contains the content-type.
+// Note that images can now be produced by the receptionist.
+void action::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+			       response_t &response, text_t &response_data, 
+			       ostream &/*logout*/) {
+  response = location;
+  response_data = "http://www.nzdl.org";
+}
+  
+// uses_display should return true if the receptionist should return
+// true if the display class is needed to output the page content
+// The default is to return true.
+bool action::uses_display (cgiargsclass &/*args*/) {
+  return true;
+}
+
+
+// define all the macros which might be used by other actions
+// to produce pages. These macros should be well documented.
+void action::define_external_macros (displayclass &/*disp*/, cgiargsclass &/*args*/, 
+				     recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+}
+
+// returns false if there was an error which prevented the action
+// from outputing anything.
+bool action::do_action (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/, 
+			browsermapclass * /*browsers*/, displayclass &/*disp*/, 
+			outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+			ostream &/*logout*/) {
+  return true;
+}
+
+
+bool operator==(const actionptr &x, const actionptr &y) {
+  return (x.a == y.a);
+}
+
+bool operator<(const actionptr &x, const actionptr &y) {
+  return (x.a < y.a);
+}
+
+
+// theaction remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void actionmapclass::addaction (action *theaction) {
+  // can't add a null action
+  assert (theaction != NULL);
+  if (theaction == NULL) return;
+  
+  // can't add an action with no name
+  assert (!(theaction->get_action_name()).empty());
+  if ((theaction->get_action_name()).empty()) return;
+
+  actionptr aptr;
+  aptr.a = theaction;
+  actionptrs[theaction->get_action_name()] = aptr;
+}
+
+// getaction will return NULL if the action could not be found
+action *actionmapclass::getaction (const text_t &key) {
+  // can't find an action with no name
+  assert (!key.empty());
+  if (key.empty()) return NULL;
+
+  iterator here = actionptrs.find (key);
+  if (here == actionptrs.end()) return NULL;
+  
+  return (*here).second.a;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/action.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/action.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/action.h	(revision 10506)
@@ -0,0 +1,183 @@
+/**********************************************************************
+ *
+ * action.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef ACTION_H
+#define ACTION_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+#include "display.h"
+#include "recptproto.h"
+#include "browserclass.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+class action {
+protected:
+  cgiargsinfoclass argsinfo;
+  text_t gsdlhome;
+  text_t gdbmhome;
+
+public:
+  action ();
+  virtual ~action ();
+
+  // configure should be called once for each configuration line
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  // init should be called after all the configuration is done but
+  // before any other methods are called
+  virtual bool init (ostream &logout);
+
+  // returns the "a" argument value that will specify this action
+  // this name should be short but does not have to be one character
+  // long
+  virtual text_t get_action_name ();
+
+  // check_cgiargs should be called before get_cgihead_info, 
+  // define_external_macros, and do_action. If an error is found
+  // a message will be written to logout, if the error is severe
+  // then the function will return false and no page content
+  // should be produced based on the arguments.
+  virtual bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+			      recptprotolistclass *protos, ostream &logout);
+
+  // check_external_cgiargs should be called after check_cgiargs
+  // for all actions. It should only be used to override some other
+  // normal behaviour, for example, producing a login page when
+  // the requested page needs authentication.
+  virtual bool check_external_cgiargs (cgiargsinfoclass &argsinfo,
+				       cgiargsclass &args,
+				       outconvertclass &outconvert,
+				       const text_t &saveconf,
+				       ostream &logout);
+
+  // get_cgihead_info determines the cgi header information for
+  // a set of cgi arguments. If response contains location then
+  // response_data contains the redirect address. If reponse
+  // contains content then reponse_data contains the content-type.
+  // Note that images can now be produced by the receptionist.
+  virtual void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+				 response_t &response, text_t &response_data, 
+				 ostream &logout);
+  
+  // uses_display should return true if the receptionist should return
+  // true if the display class is needed to output the page content.
+  // The default is to return true.
+  virtual bool uses_display (cgiargsclass &args);
+
+  // define all the macros which are related to pages generated
+  // by this action
+  virtual void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+				       recptprotolistclass *protos, ostream &logout);
+
+  // define all the macros which might be used by other actions
+  // to produce pages. These macros should be well documented.
+  virtual void define_external_macros (displayclass &disp, cgiargsclass &args, 
+				       recptprotolistclass *protos, ostream &logout);
+
+  // returns false if there was an error which prevented the action
+  // from outputing anything.
+  virtual bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			  browsermapclass *browsers, displayclass &disp, 
+			  outconvertclass &outconvert, ostream &textout, 
+			  ostream &logout);
+
+  // return true if the specified top classifier is handled by this action
+  virtual bool is_my_classifier(const text_t& topcl) { return false; }
+
+  // getargsinfo should be called after all configuration files
+  // have been read
+  const cgiargsinfoclass getargsinfo() const {return argsinfo;};
+};
+
+
+// The actionptr function does not 'own' the action. The 
+// action should be deleted by the code which created it.
+class actionptr {
+public:
+  action *a;
+
+  actionptr () {a=NULL;}
+};
+
+bool operator==(const actionptr &x, const actionptr &y);
+bool operator<(const actionptr &x, const actionptr &y);
+
+typedef map<text_t, actionptr, lttext_t> actionptrmap;
+
+// contains a list of actions indexed by their name
+class actionmapclass {
+protected:
+  actionptrmap actionptrs;
+
+public:
+  // type support for actionptrmap
+  typedef actionptrmap::iterator iterator;
+  typedef actionptrmap::const_iterator const_iterator;
+  typedef actionptrmap::reference reference;
+  typedef actionptrmap::const_reference const_reference;
+  typedef actionptrmap::size_type size_type;
+
+  typedef actionptrmap::difference_type difference_type;
+  typedef actionptrmap::const_reverse_iterator const_reverse_iterator;
+  typedef actionptrmap::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return actionptrs.begin();}
+  const_iterator begin () const {return actionptrs.begin();}
+  iterator end () {return actionptrs.end();}
+  const_iterator end () const {return actionptrs.end();}
+
+  void erase(iterator pos) {actionptrs.erase(pos);}
+  void erase(iterator first, iterator last) {actionptrs.erase(first, last);}
+  actionmapclass &operator=(const actionmapclass &x) {actionptrs=x.actionptrs;return *this;}
+
+  bool empty () const {return actionptrs.empty();}
+  size_type size() const {return actionptrs.size();}
+
+
+  // added functionality
+  void clear () {actionptrs.erase(actionptrs.begin(),actionptrs.end());}
+
+  // theaction remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addaction (action *theaction);
+
+  // getaction will return NULL if the action could not be found
+  action *getaction (const text_t &key);
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/argdb.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/argdb.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/argdb.cpp	(revision 10506)
@@ -0,0 +1,77 @@
+/**********************************************************************
+ *
+ * argdb.cpp -- 
+ * Copyright (C) 2001  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_COLLECTOR_ACTION
+
+// argdb is used by the collector for storing cgi arguments on disk (in a
+// gdbm database)
+
+#include "argdb.h"
+
+argdb::argdb (const text_t &filename) {
+  dbfile = filename;
+}
+  
+bool argdb::update_args (text_tmap &argmap) {
+  gdbmclass argdb;
+  if (!argdb.opendatabase(dbfile, GDBM_WRCREAT, 1000, true)) return false;
+  infodbclass info;
+  
+  argdb.getinfo("savedargs", info);
+
+  text_tmap::iterator here = argmap.begin();
+  text_tmap::iterator end = argmap.end();
+  while (here != end) {
+    if (!(*here).second.empty()) {
+      info.setinfo((*here).first, (*here).second);
+    }
+    ++here;
+  }
+
+  bool rv = argdb.setinfo ("savedargs", info);
+  argdb.closedatabase();
+  return rv;
+}
+
+bool argdb::get_args (text_tmap &argmap) {
+  argmap.erase(argmap.begin(), argmap.end());
+  gdbmclass argdb;
+  if (!argdb.opendatabase(dbfile, GDBM_READER, 1000, true)) return false;
+  infodbclass info;
+  
+  if (!argdb.getinfo("savedargs", info)) return false;
+  
+  infodbclass::const_iterator here = info.begin();
+  infodbclass::const_iterator end = info.end();
+  while (here != end) {
+    argmap[(*here).first] = info[(*here).first];
+    ++here;
+  }
+  argdb.closedatabase();
+  return true;
+}
+
+#endif //GSDL_USE_COLLECTOR_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/argdb.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/argdb.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/argdb.h	(revision 10506)
@@ -0,0 +1,51 @@
+/**********************************************************************
+ *
+ * argdb.h -- 
+ * Copyright (C) 2001  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_COLLECTOR_ACTION
+
+#ifndef ARGDB_H
+#define ARGDB_H
+
+#include "text_t.h"
+#include "infodbclass.h"
+
+class argdb {
+
+protected:
+
+  text_t dbfile;
+
+public:
+  
+  argdb (const text_t &filename);
+  virtual ~argdb () {}
+  
+  bool update_args (text_tmap &argmap);
+  bool get_args (text_tmap &argmap);
+};
+
+#endif //!ARGDB_H
+#endif //GSDL_USE_COLLECTOR_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/authenaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/authenaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/authenaction.cpp	(revision 10506)
@@ -0,0 +1,358 @@
+/**********************************************************************
+ *
+ * authenaction.cpp -- authenticating users
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_AUTHEN_ACTION
+
+#include "authenaction.h"
+#include "fileutil.h"
+#include "cfgread.h"
+#include "cgiutils.h"
+#include "infodbclass.h"
+#include "gsdltimes.h"
+#include "userdb.h"
+
+
+///////////////
+// authenaction
+///////////////
+
+authenaction::authenaction () {
+  keydecay = 1800; // 30 minutes
+  recpt = NULL;
+
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "a";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "us"
+  arg_ainfo.shortname = "us";
+  arg_ainfo.longname = "user account status";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "invalid";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ug"
+  arg_ainfo.shortname = "ug";
+  arg_ainfo.longname = "user groups"; // comma seperated list
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "un"
+  arg_ainfo.shortname = "un";
+  arg_ainfo.longname = "user name";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "pw"
+  arg_ainfo.shortname = "pw";
+  arg_ainfo.longname = "password";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ky" - gives a specific user authentication for a
+  // limited amount of time
+  arg_ainfo.shortname = "ky";
+  arg_ainfo.longname = "user time key";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ua" - ""=no, "1"=yes 
+  arg_ainfo.shortname = "ua";
+  arg_ainfo.longname = "whether a user has been authenticated";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "er" - compressed arguments for the referer page
+  arg_ainfo.shortname = "er";
+  arg_ainfo.longname = "the compressed args of the refer page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "uan" - whether user authentication is needed
+  arg_ainfo.shortname = "uan";
+  arg_ainfo.longname = "whether user authentication is needed";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+void authenaction::configure (const text_t &key, const text_tarray &cfgline) {
+  // get the password filename
+  if (cfgline.size() == 1) {
+    if (key == "usersfile") usersfile = cfgline[0];
+    else if (key == "keyfile") keyfile = cfgline[0];
+    else if (key == "keydecay") keydecay = cfgline[0].getint();
+  }
+
+  action::configure (key, cfgline);
+}
+
+bool authenaction::init (ostream &logout) {
+
+  if (gdbmhome.empty()) {
+    logout << "ERROR (authenaction::init) gdbmhome is not set\n";
+    return false;
+  }
+
+  if (usersfile.empty()) usersfile = filename_cat (gdbmhome, "etc", "users.db");
+  if (keyfile.empty()) keyfile = filename_cat (gdbmhome, "etc", "key.db");
+
+  return action::init (logout);
+}
+
+bool authenaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &/*args*/, 
+				  recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+  return true;
+}
+
+// returns false if there is a major problem with the cgi arguments -- not
+// if authentication fails. If the authentication fails "un" will be empty
+bool authenaction::check_external_cgiargs (cgiargsinfoclass &argsinfo,
+					   cgiargsclass &args,
+					   outconvertclass &outconvert,
+					   const text_t &saveconf,
+					   ostream &logout) {
+
+  // no need to go further unless authentication is
+  // required by this page
+  if (args["uan"].empty()) return true;
+
+
+  // failure means we have to redirect to this action to get authentication
+  // (if we are not already doing this)
+
+  userinfo_t thisuser;
+
+  text_t &args_uan = args["uan"];  text_t &args_un = args["un"];
+  text_t &args_pw = args["pw"];    text_t &args_us = args["us"];
+  text_t &args_ug = args["ug"];    text_t &args_ky = args["ky"];
+  text_t &args_ua = args["ua"];    text_t &args_a = args["a"];
+
+  // we must have a username and a password or a key to
+  // do any authentication
+  args_ua.clear(); // default = false;
+  if (args_un.empty() || args_pw.empty()) args_us = "invalid";
+  else args_us = "failed";
+
+  // make sure we have a username
+  if (!args_un.empty() && get_user_info (usersfile, args_un, thisuser)) {
+    if (!args_pw.empty()) {
+      // we are authenticating using a password
+      if (check_passwd (thisuser, args_pw)) args_ua = "1"; // succeeded
+      
+    } else if (!args_ky.empty()) {
+      // we are authenticating using a key
+      if (check_key (keyfile, thisuser, args_ky, args_ug, keydecay)) args_ua = "1";
+      else args_us = "stalekey";
+    }
+  }
+
+  args_pw.clear(); // password goes no further
+  if (!args_ua.empty()) {
+    if (thisuser.enabled) {
+      bool haspermission = true;
+
+      // check to make sure the user is in the required group
+      // one group is available only at the moment.
+      // this is what we are changing !
+      
+      if (!args_ug.empty()) {
+
+	 // Since we recieve a comma seperated list
+	 // of groups like mygroup,yourgroup,ourgroup
+	 // we want to split them into individual groups
+	 // and examine them. This is what is done here.
+	 
+	 text_tset splitgrps;
+	 text_t::const_iterator split_here = args_ug.begin();
+	 text_t::const_iterator split_end = args_ug.end();
+
+	 splitchar(split_here,split_end,',',splitgrps);
+
+	 haspermission = false;
+
+	 // This examines the current user to be authenticated and
+	 // tries to see if he or she is in the group that we have in
+	 // thisuser structure. We compare args_ua contents with that
+	 // of the user database.
+	 
+	 text_t::const_iterator group_here = thisuser.groups.begin();
+	 text_t::const_iterator group_end = thisuser.groups.end();
+	 text_t thisgroup;
+	while (group_here != group_end) {
+	   group_here = getdelimitstr (group_here, group_end, ',', thisgroup);
+	   if (splitgrps.find(thisgroup) != splitgrps.end() )
+	      {
+		 haspermission = true;
+		 break;
+	      }
+	}
+      }
+      
+      if (haspermission) {
+	 // succeeded, get info about this user
+	 // note: we don't need to set "ug" as it is already set to what it needs to be
+	 args_us = "enabled";
+	args_ky = generate_key (keyfile, args_un); // new key
+	
+	// delete old keys around every 50 accesses
+	if (rand()%50 == 1) remove_old_keys (keyfile, keydecay);
+	
+      } else {
+	// succeeded, however, the user is not in the correct group
+	 args_ua.clear();
+	 args_us = "permissiondenied";
+	 args_ky.clear();
+      }
+      
+    } else {
+       // succeeded, however, the account is disabled
+      args_ua.clear();
+      args_us = "disabled";
+      args_ky.clear();
+    }
+
+  } else {
+    // failure, reset info about the user
+    args_ky.clear();
+  }
+
+  // we will have to redirect the user if authentication is needed,
+  // it failed, and we weren't on our way to be authenticated anyway
+  if ((!args_uan.empty()) && (args_ua.empty()) && (args_a != "a")) {
+    // need to save the current arguments in "er"
+    text_t &arg_er = args["er"];
+    if (!compress_save_args(argsinfo, saveconf, args, arg_er, outconvert, logout))
+      arg_er.clear();
+    
+    // needs to be decoded for use within forms
+    decode_cgi_arg (arg_er);    
+
+    // redirect to this action
+    args_a = "a";
+  }
+  
+  return true;
+}
+
+void authenaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				     response_t &response, text_t &response_data, 
+				     ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+void authenaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					   recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+  // sets _authen:messageextra_ based on the value of args["us"]
+  //      _authen:hiddenargs_   to contain all the arguments that were
+  //                            explicitly set
+  disp.setmacro ("messagestatus", "authen", ("_authen:message" + args["us"]
+					     + "_"));
+  // change style of header and footer if page is a frame
+  if ((args["p"].empty()) || (args["p"] == "frameset")) {
+    disp.setmacro ("header", "authen", "_status:infoheader_(Log in)");
+    disp.setmacro ("header", "authenok", "_status:infoheader_(Log in)");
+    disp.setmacro ("footer", "authen", "_status:infofooter_(Log in)");
+    disp.setmacro ("footer", "authenok", "_status:infofooter_(Log in)");
+  }
+
+  // get a list of saved configuration arguments (if possible)
+  text_t saveconf;
+  text_tset saveconfset;
+  if (recpt != NULL) {
+    saveconf = recpt->get_configinfo().saveconf;
+    splitchar (saveconf.begin(), saveconf.end(), '-', saveconfset);
+  }
+  
+  text_t hiddenargs;
+  cgiargsclass::const_iterator args_here = args.begin();
+  cgiargsclass::const_iterator args_end = args.end();
+  while (args_here != args_end) {
+    // set this as a hidden argument if it came from the cgi arguments,
+    // its not the compressed arguments, the query string, a user name or
+    // password, or collect.cfg, and if it is not in the compressed arguments
+    if ((*args_here).second.source == cgiarg_t::cgi_arg &&
+	(*args_here).first != "e" && (*args_here).first != "q" &&
+	(*args_here).first != "un" && (*args_here).first != "pw" &&
+	(*args_here).first != "cfgfile" && 
+	saveconfset.find((*args_here).first) == saveconfset.end()) {
+      hiddenargs += "<input type=hidden name=\"" + (*args_here).first +
+	"\" value=\"_cgiarg" + (*args_here).first + "_\">\n";
+    }
+    ++args_here;
+  }
+
+  disp.setmacro ("hiddenargs", "authen", hiddenargs);
+}
+
+bool authenaction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/, 
+			      browsermapclass * /*browsers*/, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout, 
+			      ostream &/*logout*/) {
+  if (args["us"] == "enabled") {
+    // have been authenticated
+    textout << outconvert << disp
+	    << "_authenok:header_\n_authenok:content_\n_authenok:footer_\n";
+    return true;
+  }
+  
+  // need to be authenticated
+  textout << outconvert << disp
+	  << "_authen:header_\n_authen:content_\n_authen:footer_\n";
+
+  return true;
+}
+
+#endif //GSDL_USE_AUTHEN_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/authenaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/authenaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/authenaction.h	(revision 10506)
@@ -0,0 +1,84 @@
+/**********************************************************************
+ *
+ * authenaction.h -- authenticating users
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_AUTHEN_ACTION
+
+#ifndef AUTHENACTION_H
+#define AUTHENACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+#include "text_t.h"
+#include "receptionist.h"
+
+
+// note: you need to tell this action about the receptionist
+// using set_receptionist
+
+class authenaction : public action {
+protected:
+  text_t usersfile;
+  text_t keyfile;
+  int keydecay;
+
+  receptionist *recpt;
+  
+public:
+  authenaction ();
+  virtual ~authenaction () {}
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+  
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  bool init (ostream &logout);
+  
+  text_t get_action_name () {return "a";}
+  
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      recptprotolistclass *protos, ostream &logout);
+
+  bool check_external_cgiargs (cgiargsinfoclass &argsinfo,
+			       cgiargsclass &args,
+			       outconvertclass &outconvert,
+			       const text_t &saveconf,
+			       ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+  
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+  
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+};
+
+#endif //!AUTHENACTION_H
+#endif //GSDL_USE_AUTHEN_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseaction.cpp	(revision 10506)
@@ -0,0 +1,249 @@
+/**********************************************************************
+ *
+ * browseaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_BROWSE_ACTION
+
+#include "browseaction.h"
+#include "querytools.h"
+#include "browseactiontools.h"
+#include "OIDtools.h"
+
+browseaction::browseaction(){
+
+ 
+
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "br";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  //the first browsing criterion -- collection metadata types
+  arg_ainfo.shortname = "b1";
+  arg_ainfo.longname = "browse criterion 1";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+ 
+  //the second browsing criterion -- collection metadata types + none - meaning
+  //only one browsing criterion.  None is the default.
+  arg_ainfo.shortname = "b2";
+  arg_ainfo.longname = "browse criterion 2";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+  
+  //the number of documents to show per page -- if the box is empty then
+  //only the most basic divisions are made (so, first letter for A-Z, year 
+  //for date).
+  arg_ainfo.shortname = "bnu";
+  arg_ainfo.longname = "browse docs per page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::good;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  //The text to filter documents for browsing (only documents containing these 
+  //words will be browsed).
+  arg_ainfo.shortname = "bft";
+  arg_ainfo.longname = "browse filter text";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+
+  //Whether all or just some of the words in the filter box have to be present
+  //0 - any 1- all
+  arg_ainfo.shortname = "bt";
+  arg_ainfo.longname = "browse all or any";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+  
+  
+}
+
+browseaction::~browseaction(){}
+
+bool browseaction::init (ostream &logout){
+  return true;
+}
+
+void browseaction::configure (const text_t &key, const text_tarray &cfgline){
+  action::configure(key, cfgline);
+}
+
+
+
+bool browseaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &/*args*/, 
+				  recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+  // don't want to check anything yet.
+  
+  return true;
+}
+
+  
+void browseaction::get_cgihead_info (cgiargsclass &args, 
+				     recptprotolistclass *protos,
+				     response_t &response, 
+				     text_t &response_data, 
+				     ostream &logout){
+  response = content;
+  response_data = "text/html";
+
+  
+}
+
+void browseaction::define_internal_macros (displayclass &disp, 
+					   cgiargsclass &args, 
+					   recptprotolistclass *protos, 
+					   ostream &logout){
+ 
+}
+
+void browseaction::define_external_macros (displayclass &disp, 
+					   cgiargsclass &args, 
+					   recptprotolistclass *protos, 
+					   ostream &logout){
+  
+}
+
+bool browseaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			      browsermapclass *browsers, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout, 
+			      ostream &logout){
+ 
+  if(args["c"].empty()) return false;
+  else if(get_document_list(args, protos, browsers, disp, outconvert, textout,
+			    logout)) return true;
+  else return false;
+}
+
+bool browseaction::get_document_list(cgiargsclass &args, 
+		recptprotolistclass *protos, browsermapclass *browsers, 
+		displayclass &disp, outconvertclass &outconvert, 
+		ostream &textout, ostream &logout){ 
+  
+  text_t collection = args["c"];
+  comerror_t err;
+  text_t list_type = "VList";  //result display type
+
+  //check that the protocol is alive
+  recptproto* colproto = protos->getrecptproto (collection, logout);
+  if(colproto == NULL) {
+    logout << outconvert << "ERROR: Null collection protocol trying to browse "
+	   << collection << "\n";
+    return false;
+  }
+  
+  //check the collection is responding/in place
+  ColInfoResponse_t *colinfo = recpt->get_collectinfo_ptr(colproto, collection,
+							  logout);
+  if(colinfo == NULL){
+    logout << outconvert << "ERROR: Null returned for get_collectinfo_ptr on "
+	   << collection << "in browseaction\n";
+    return false;
+  }
+
+  browserclass* br_ptr = browsers->getbrowser(list_type);
+
+  FilterRequest_t request;
+  FilterResponse_t response;
+
+  //set up browser structure 
+  br_ptr->set_filter_options(request, args);
+  request.filterLang = args["l"];
+  br_ptr->load_metadata_defaults(request.fields);
+
+  //set up format information
+  format_t* formatptr = new format_t();
+  parse_formatstring(br_ptr->get_default_formatstring(), formatptr, 
+		     request.fields, request.getParents);
+
+  request.filterResultOptions = FROID | FRmetadata;
+  
+  text_t bf_string = g_EmptyText;
+  format_browsestring(args["bft"],bf_string,args.getintarg("bt"));
+  
+  set_browsefilter_options(request, bf_string, args);
+  
+  //set up browse filter string;
+  if(!args["bft"].empty()){
+
+    colproto->filter (collection, request, response, err, logout);
+    if (err != noError) {
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii
+	     << "browseaction::get_document_list QueryFilter failed "
+	     << "for " << collection << " collection (" 
+	     << get_comerror_string (err) << ")\n";
+      return false;
+    }// if (err != noError) 
+
+  }// end if(!args["bft"].empty())
+  else {
+    text_tset metadata_items;
+    text_t temp = "Title";
+    metadata_items.insert(temp);
+    temp = "browselist";
+    if (!get_children(temp, args["c"], args["l"], metadata_items, false, colproto,
+		     response,logout)) return false;
+  }
+
+  //get rid of documents that do not have the metadata element classified on
+  if(!remove_no_meta_results("Title",response, outconvert)) {
+    return false;
+    logout<<"ERROR: browseactiontools::remove_no_meta_results failed"<<endl;
+  }
+
+  textout << outconvert << disp << "_browse:header_\n" <<"_browse:content_";
+
+  
+  bool use_table = is_table_content (formatptr);
+  br_ptr->output_section_group (response, args, collection, 0, formatptr, 
+			      use_table, request.fields, request.getParents, 
+			      colproto, disp, outconvert, textout, logout);
+
+  textout << outconvert << disp << "_browse:footer_";
+    
+  
+  
+  return true;
+}
+
+#endif //GSDL_USE_BROWSE_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseaction.h	(revision 10506)
@@ -0,0 +1,77 @@
+/**********************************************************************
+ *
+ * browseaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_BROWSE_ACTION
+
+#ifndef BROWSEACTION_H
+#define BROWSEACTION_H
+
+#include "action.h"
+#include "receptionist.h"
+
+class browseaction : public action{
+ protected:
+  receptionist* recpt;
+  bool get_document_list(cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+ public:
+  browseaction();
+  virtual ~browseaction();
+
+  bool init (ostream &logout);
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  text_t get_action_name() {return "br";}
+  
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      recptprotolistclass *protos, ostream &logout);
+
+  
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+				 response_t &response, text_t &response_data, 
+				 ostream &logout);
+
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+  
+  void define_external_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+  const cgiargsinfoclass& getargsinfo() const {return argsinfo;};
+};
+
+#endif //!BROWSEACTION_H
+#endif //GSDL_USE_BROWSE_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseactiontools.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseactiontools.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseactiontools.cpp	(revision 10506)
@@ -0,0 +1,129 @@
+/**********************************************************************
+ *
+ * browseactiontools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#include "browseactiontools.h"
+#include <ctype.h>
+
+void format_browsestring(const text_t& orig, text_t& formatted, int and_or)
+{
+  
+ 
+  text_t conj = g_EmptyText;
+  
+  if(and_or == 0){ conj = " | "; }
+  else { conj = " & "; }
+  text_t::const_iterator here = orig.begin();
+  text_t::const_iterator end = orig.end();
+  
+  //while not at the end of the filter string
+  while(here!=end){
+    //if seeing text, add it to the formatted string
+    if(!isspace(*here)){
+      formatted.push_back(*here);
+      ++here;
+    }
+    //else, if seeing spaces, check that there is following text and add
+    //the ncessary conjugation if there is.
+    else if(isspace(*here)){
+      while(isspace(*here) && here!=end) ++here;
+      if(here!=end) formatted += conj;
+    }
+  }
+
+}
+
+// this stuff is all copied from the queryoptions code - don't ask how it all
+// hangs in with the filters - those things are a mystery 
+void set_browsefilter_options(FilterRequest_t &request, const text_t &browsestring,
+			      cgiargsclass &args)
+{
+  request.filterName = "QueryFilter";
+
+   OptionValue_t option;
+
+   option.name = "Term";
+   option.value = browsestring;
+   request.filterOptions.push_back (option);
+   
+   option.name = "QueryType";
+   option.value = "boolean";
+   request.filterOptions.push_back (option);
+  
+   option.name = "MatchMode";
+   option.value = (args.getintarg("bt")) ? "some" : "all";
+   request.filterOptions.push_back (option);
+   
+   option.name = "Casefold";
+   option.value = (args.getintarg("k")) ? "true" : "false";
+   request.filterOptions.push_back (option);
+   
+   option.name = "Stem";
+   option.value = (args.getintarg("s")) ? "true" : "false";
+   request.filterOptions.push_back (option);
+
+   option.name = "Maxdocs";
+   option.value = -1;
+   request.filterOptions.push_back (option);
+   
+   option.name = "Index";
+   option.value = "dtx";
+   request.filterOptions.push_back (option);
+     
+   
+}
+
+bool remove_no_meta_results(const text_t& metaname, FilterResponse_t &response, 
+			    outconvertclass &outconvert)
+{
+  
+  ResultDocInfo_tarray::iterator check = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator done = response.docInfo.end();
+  // look through all the returned documents
+  while(check != response.docInfo.end()){
+   
+    //if the document doesn't have the metadata item classified on 
+    //remove it.
+    text_t title = *((*check).metadata.find(metaname)->second).values.begin();
+    if(title == g_EmptyText)
+      {
+	
+	response.docInfo.erase(check);
+	
+      }
+    else {
+     
+      ++check;
+     
+    }
+ 
+  }
+  return true;
+}
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseactiontools.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseactiontools.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/browseactiontools.h	(revision 10506)
@@ -0,0 +1,48 @@
+/********************************************************************
+ *
+ * browseactiontools.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef BROWSEACTIONTOOLS_H
+#define BROWSEACTIONTOOLS_H
+
+#include "cgiargs.h"
+#include "recptproto.h"
+
+//this puts ands or ors into the querystring as necessary
+void format_browsestring(const text_t& orig, text_t& formatted, int and_or);
+
+//this thing sets up the search associated with a browse.  It's programmed by 
+//witchcraft, so I don't really know how/why it works - I lifted the code from
+//somewhere else.
+void set_browsefilter_options(FilterRequest_t &request, const text_t &browsestring,
+			      cgiargsclass &args);
+
+//this thing filters out all the results of a request to the collection 
+//(whether it be for all documents or just the ones with specified terms)
+//that don't have the required "metaname" metadata element.
+bool remove_no_meta_results(const text_t &metaname, FilterResponse_t &response,
+			    outconvertclass &outconvert);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/browserclass.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/browserclass.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/browserclass.cpp	(revision 10506)
@@ -0,0 +1,198 @@
+/**********************************************************************
+ *
+ * browserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "browserclass.h"
+#include <assert.h>
+
+
+browserclass::browserclass () {
+}
+
+browserclass::~browserclass () {
+}
+
+// configure should be called once for each configuration line
+// the default version does nothing
+void browserclass::configure (const text_t &/*key*/, const text_tarray &/*cfgline*/) {
+}
+
+// init should be called after all the configuration is done but
+// before any other methods are called
+bool browserclass::init (ostream &/*logout*/) {
+  return true;
+}
+
+// returns the name that specifies the browserclass type
+text_t browserclass::get_browser_name () {
+  return g_EmptyText;
+}
+
+void browserclass::processOID (cgiargsclass &/*args*/, recptproto * /*collectproto*/, ostream &/*logout*/) {
+}
+
+void browserclass::load_metadata_defaults (text_tset &/*metadata*/) {
+}
+
+text_t browserclass::get_default_formatstring () {
+  return g_EmptyText;
+}
+
+void browserclass::set_filter_options (FilterRequest_t &request, cgiargsclass &args) {
+  
+  OptionValue_t option;
+
+  if (args["a"] == "q") {
+    int arg_m = args.getintarg("m");
+    
+    option.name = "StartResults";
+    option.value = args["r"];
+    request.filterOptions.push_back (option);
+    
+    option.name = "EndResults";
+    int endresults = args.getintarg("o") + (args.getintarg("r") - 1);
+    //    int endresults = (args.getintarg("o")*3) + (args.getintarg("r") - 1);
+    if ((endresults > arg_m) && (arg_m != -1)) endresults = arg_m;
+    option.value = endresults;
+    request.filterOptions.push_back (option);
+
+  } else {
+    option.name = "StartResults";
+    option.value = args["r"];
+    request.filterOptions.push_back (option);
+    
+    option.name = "EndResults";
+    int endresults = 20 + (args.getintarg("r") - 1);
+    option.value = endresults;
+    request.filterOptions.push_back (option);
+  }
+}
+
+int browserclass::output_section_group (ResultDocInfo_t &/*section*/, cgiargsclass &/*args*/,
+					const text_t &/*collection*/, int /*colnumber*/, 
+					format_t * /*formatlistptr*/, bool /*use_table*/, 
+					text_tset &/*metadata*/, bool &/*getParents*/,
+					recptproto * /*collectproto*/, displayclass &/*disp*/, 
+					outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+					ostream &/*logout*/) {
+  return 0;
+}
+
+int browserclass::output_section_group (ResultDocInfo_t &/*section*/, cgiargsclass &/*args*/,
+					const text_t &/*labels*/, const text_t &/*collection*/, int /*colnumber*/, 
+					format_t * /*formatlistptr*/, bool /*use_table*/, 
+					text_tset &/*metadata*/, bool &/*getParents*/,
+					recptproto * /*collectproto*/, displayclass &/*disp*/, 
+					outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+					ostream &/*logout*/) {
+  return 0;
+}
+
+int browserclass::output_section_group (FilterResponse_t &/*sections*/, cgiargsclass &/*args*/,
+					const text_t &/*collection*/, int /*colnumber*/, 
+					format_t * /*formatlistptr*/, bool /*use_table*/, 
+					text_tset &/*metadata*/, bool &/*getParents*/,
+					recptproto * /*collectproto*/, displayclass &/*disp*/, 
+					outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+					ostream &/*logout*/) {
+  return 0;
+}
+
+int browserclass::output_section_group (FilterResponse_t &/*sections*/, cgiargsclass &/*args*/,
+					const text_t& /*currentSection*/, const text_t &/*labels*/, const text_t &/*collection*/, int /*colnumber*/, 
+					format_t * /*formatlistptr*/, bool /*use_table*/, 
+					text_tset &/*metadata*/, bool &/*getParents*/,
+					recptproto * /*collectproto*/, displayclass &/*disp*/, 
+					outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+					ostream &/*logout*/)
+{
+  return 0;
+}
+
+bool operator==(const browserptr &x, const browserptr &y) {
+  return (x.b == y.b);
+}
+
+bool operator<(const browserptr &x, const browserptr &y) {
+  return (x.b < y.b);
+}
+
+// thebrowserclass remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void browsermapclass::addbrowser (browserclass *thebrowserclass) {
+  // can't add a null browserclass
+  assert (thebrowserclass != NULL);
+  if (thebrowserclass == NULL) return;
+  
+  // can't add a browserclass with no name
+  assert (!(thebrowserclass->get_browser_name()).empty());
+  if ((thebrowserclass->get_browser_name()).empty()) return;
+
+  browserptr aptr;
+  aptr.b = thebrowserclass;
+  browserptrs[thebrowserclass->get_browser_name()] = aptr;
+}
+
+// getbrowser will return the default browser if the browser 
+// could not be found
+browserclass *browsermapclass::getbrowser (const text_t &key) {
+  // can't find a browser with no name
+  if (key.empty()) return get_default_browser();
+
+  iterator here = browserptrs.find (key);
+  if (here == browserptrs.end()) return get_default_browser();
+  
+  return (*here).second.b;
+}
+
+browserclass *browsermapclass::clonebrowser (const text_t &key) {
+  browserclass *browser = NULL;
+  if (key.empty()) {
+    browser = get_default_browser();
+  } else {
+    iterator here = browserptrs.find (key);
+    if (here == browserptrs.end()) 
+      browser = get_default_browser();
+    else
+      browser = here->second.b;
+  }
+  if (browser != NULL) {
+    browser = browser->clone();
+  }
+  return browser;
+}
+
+void browsermapclass::setdefaultbrowser (const text_t &browsername) {
+  defaultbrowser = browsername;
+}
+
+browserclass *browsermapclass::get_default_browser () {
+
+  iterator here = browserptrs.find (defaultbrowser);
+  if (here == browserptrs.end())
+    // we'll just take the first in the list if
+    // no valid default was set
+    here = browserptrs.begin();
+  return (*here).second.b;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/browserclass.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/browserclass.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/browserclass.h	(revision 10506)
@@ -0,0 +1,187 @@
+/**********************************************************************
+ *
+ * browserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+
+#ifndef BROWSERCLASS_H
+#define BROWSERCLASS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+#include "display.h"
+#include "recptproto.h"
+#include "formattools.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+class browserclass {
+protected:
+
+public:
+  browserclass ();
+  virtual ~browserclass ();
+
+  // configure should be called once for each configuration line
+  virtual void configure (const text_t &key, const text_tarray &cfgline);
+
+  // init should be called after all the configuration is done but
+  // before any other methods are called
+  virtual bool init (ostream &logout);
+
+  virtual browserclass* clone() = 0;
+
+  // returns the name that specifies the browserclass type
+  virtual text_t get_browser_name ();
+  
+  virtual void processOID (cgiargsclass &args, recptproto *collectproto, ostream &logout);
+  
+  // load_metadata_defaults should be called before
+  // doing protocol call to get metadata for OID to
+  // be displayed by this browserclass. it adds fields
+  // to the metadata set that are needed by browserclass
+  // during display
+  virtual void load_metadata_defaults (text_tset &metadata);
+
+  virtual text_t get_default_formatstring ();
+
+  void set_filter_options (FilterRequest_t &request, cgiargsclass &args);
+  
+  // output_section_group returns the number of tabs to add before displaying the
+  // next section group
+  // The first version takes one result of a search/query action, the
+  // second takes all the results; ResultDocInfo_t is actually a child struct
+  // of FilterResponse_t items.  The second version tends to output parts of an
+  // abstract structure (e.g. for a table of contents/classifier list, the first
+  // for an individual document
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &collection, int colnumber, 
+				    format_t *formatlistptr, bool use_table, 
+				    text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, 
+				    ostream &logout);
+
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &labels, const text_t &collection, int colnumber, 
+				    format_t *formatlistptr, bool use_table, 
+				    text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, 
+				    ostream &logout);
+
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t &collection, int colnumber, 
+				    format_t *formatlistptr, bool use_table, 
+				    text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, 
+				    ostream &logout);
+
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t& currentSection, const text_t &labels,
+				    const text_t &collection, int colnumber, 
+				    format_t *formatlistptr, bool use_table, 
+				    text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, 
+				    ostream &logout);
+};
+
+
+// The browserptr function does not 'own' the browser. The 
+// browser should be deleted by the code which created it.
+class browserptr {
+public:
+  browserclass *b;
+
+  browserptr () {b=NULL;}
+};
+
+bool operator==(const browserptr &x, const browserptr &y);
+bool operator<(const browserptr &x, const browserptr &y);
+
+typedef map<text_t, browserptr, lttext_t> browserptrmap;
+
+// contains a list of browsers indexed by their name
+class browsermapclass {
+protected:
+  browserptrmap browserptrs;
+  text_t defaultbrowser;
+
+public:
+  // type support for browserptrmap
+  typedef browserptrmap::iterator iterator;
+  typedef browserptrmap::const_iterator const_iterator;
+  typedef browserptrmap::reference reference;
+  typedef browserptrmap::const_reference const_reference;
+  typedef browserptrmap::size_type size_type;
+
+  typedef browserptrmap::difference_type difference_type;
+  typedef browserptrmap::const_reverse_iterator const_reverse_iterator;
+  typedef browserptrmap::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return browserptrs.begin();}
+  const_iterator begin () const {return browserptrs.begin();}
+  iterator end () {return browserptrs.end();}
+  const_iterator end () const {return browserptrs.end();}
+
+  void erase(iterator pos) {browserptrs.erase(pos);}
+  void erase(iterator first, iterator last) {browserptrs.erase(first, last);}
+  browsermapclass &operator=(const browsermapclass &x) {browserptrs=x.browserptrs;return *this;}
+
+  bool empty () const {return browserptrs.empty();}
+  size_type size() const {return browserptrs.size();}
+
+
+  // added functionality
+  void clear () {browserptrs.erase(browserptrs.begin(),browserptrs.end());}
+
+  // thebrowserclass remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addbrowser (browserclass *thebrowserclass);
+
+  // getbrowser will return NULL if the browser could not be found
+  browserclass *getbrowser (const text_t &key);
+
+  // clone a browser; if not default and browser not found will return NULL
+  browserclass *clonebrowser (const text_t &key);
+
+  void setdefaultbrowser (const text_t &browsername);
+
+  browserclass *get_default_browser ();
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/browsetools.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/browsetools.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/browsetools.cpp	(revision 10506)
@@ -0,0 +1,898 @@
+
+/**********************************************************************
+ *
+ * browsetools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+#include "browsetools.h"
+#include "OIDtools.h"
+#include "gsdlunicode.h"
+
+#if defined(GSDL_USE_IOS_H)
+#  if defined(__WIN32__)
+#    include <strstrea.h> // vc4
+#  else
+#    include <strstream.h>
+#  endif
+#else
+#  include <sstream>
+#endif
+
+
+// output_controls displays the detach, expand/contract contents,
+// expand/contract text and highlighting/no highlighting buttons
+
+void output_controls (cgiargsclass &args, const text_tarray &ibuttons,
+		      recptproto * /*collectproto*/, displayclass &disp, 
+		      outconvertclass &outconvert, ostream &textout, 
+		      ostream &/*logout*/) {
+
+  if (args["u"] != "1") {
+    
+    FilterResponse_t response;
+    text_tarray metadata;
+    text_tarray buttons;
+    
+    text_tarray::const_iterator here = ibuttons.begin();
+    text_tarray::const_iterator end = ibuttons.end();
+    
+    while (here != end) {
+      
+      if (*here == "Detach")
+	buttons.push_back ("_document:imagedetach_");
+      else if (*here == "Highlight") {
+	if (args["hl"] == "1") 
+	  buttons.push_back ("_document:imagenohighlight_");
+	else 
+	  buttons.push_back ("_document:imagehighlight_");
+      } else if (*here == "Expand Contents") {
+	if (args["gc"] == "1")
+	  buttons.push_back ("_document:imagecontracttoc_");
+	else 
+	  buttons.push_back ("_document:imageexpandtoc_");
+      } else if (*here == "Expand Text") {
+	if (args.getintarg("gt"))
+	  buttons.push_back ("_document:imagecontracttext_");
+	else 
+	  buttons.push_back ("_document:imageexpandtext_");
+      }
+      ++here;
+    }
+    
+    here = buttons.begin();
+    end = buttons.end();
+    int count = 0;
+    while (here != end) {
+      if ((count != 0) && ((count % 2) == 0)) textout<< outconvert << "<br>\n";
+      textout << outconvert << disp << *here;
+      ++count;
+      ++here;
+    }
+  }
+}
+
+text_t get_cover_image () {
+   return "_httpcollimg_/{Or}{[parent(Top):archivedir],[archivedir]}/cover.jpg";
+}
+
+// at the moment this just writes out the html to display 
+// the cover image (assuming it's called cover.jpg)
+// this whole thing should be done with a call to the collection
+// server which would send a link to the cover image if there
+// was one otherwise send title, author and stuff
+void output_cover_image (cgiargsclass &args, recptproto * /*collectproto*/, 
+			 displayclass &disp, outconvertclass &outconvert, 
+			 ostream &textout, ostream &/*logout*/) {
+  
+  if (args["d"].empty()) return;
+  
+  textout << outconvert << disp << "<img alt=\"\" onError=\"src='_httpimg_/blank.gif'\" src=\"_httpcollimg_/_thisOID_/cover.jpg\"><br>\n";
+}
+
+void output_titles (cgiargsclass &args, recptproto *collectproto, 
+		    browsermapclass *browsermap, formatinfo_t &formatinfo,
+		    displayclass &disp, outconvertclass &outconvert,
+		    ostream &textout, ostream &logout) {
+
+  if (args["d"].empty()) return;
+  
+  text_tset metadata;
+  bool getParents;
+  FilterResponse_t response;
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatinfo.DocumentHeading, formatlistptr, metadata, getParents);
+
+  if (!get_info (args["d"], args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+    return;
+
+  text_tmap options;
+  if (formatinfo.AllowExtendedOptions) {
+    load_extended_options(options, args, browsermap, formatinfo, 
+			  collectproto, disp, outconvert, logout);
+  }
+  textout << outconvert << disp 
+	  << get_formatted_string (args["c"],collectproto, response.docInfo[0], disp,
+				   formatlistptr, options, logout);
+}
+
+//this function outputs the related documents in the format specified 
+//in the collection configuration file if the collection preferences
+//indicate they wish related documents to be displayed.
+void output_related_docs (cgiargsclass &args, recptproto *collectproto, 
+			  formatinfo_t &formatinfo, displayclass &disp, 
+			  outconvertclass &outconvert, ostream &textout, 
+			  ostream &logout) {
+
+  if (args["d"].empty()) return; //if no OID
+  if (args["rd"] != "1") return; //if preferences say no related documents
+  
+  text_tset metadata;
+  bool getParents;
+  FilterResponse_t response;
+
+  //create new format pointer and parse the related doc format 
+  //string specified in the collection config file
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatinfo.RelatedDocuments, formatlistptr, metadata, getParents);
+
+  if (!get_info (args["d"], args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+    return;
+  
+  //get the format string from formattools.cpp
+  text_tmap options; // no options
+  text_t relateddocs =  get_formatted_string (args["c"],collectproto, response.docInfo[0], 
+					      disp, formatlistptr, options, logout);
+  //output the related documents
+  textout << outconvert << disp << relateddocs;
+}
+
+
+
+static void recurse_contents (ResultDocInfo_t &section, cgiargsclass &args, bool fulltoc,
+			      browserclass *bptr, text_tset &metadata, bool &getParents, 
+			      format_t *formatlistptr, format_tmap &formatlistmap, 
+			      formatinfo_t &formatinfo, browsermapclass *browsermap, 
+			      int tabcount, recptproto *collectproto, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout, ostream &logout) {
+  text_t formatstring;
+
+  bool is_classify = false;
+  if (args["d"].empty() || fulltoc) is_classify = true;
+
+  // output this section 
+  bool use_table = is_table_content (formatlistptr);
+  tabcount += bptr->output_section_group (section, args, args["c"], tabcount, formatlistptr, use_table, 
+					  metadata, getParents, collectproto, disp, outconvert, 
+					  textout, logout);
+
+  text_t classification;
+  if (!is_classify) classification = "Document";
+  else get_top (args["cl"], classification);
+
+  int haschildren = section.metadata["haschildren"].values[0].getint();
+  const text_t &doctype = section.metadata["doctype"].values[0];
+  text_t classifytype = section.metadata["childtype"].values[0];
+  // HLists and DateLists are displayed as VLists when contents 
+  // are expanded, Paged documents are displayed as HLists
+  if (classifytype == "HList" || classifytype == "DateList") classifytype = "VList";
+  if (classifytype == "Paged") classifytype = "HList";
+
+  // recurse through children
+  if ((haschildren == 1) && (!is_classify || fulltoc || doctype == "classify")) {
+
+    // get browser for displaying children
+    bptr = browsermap->getbrowser (classifytype);
+    bptr->load_metadata_defaults (metadata);
+
+    // get the formatstring if there is one 
+    if (!get_formatstring (classification, classifytype, 
+			   formatinfo.formatstrings, formatstring))
+      formatstring = bptr->get_default_formatstring();
+
+    format_tmap::const_iterator it = formatlistmap.find (formatstring);
+    // check if formatlistptr is cached
+    if (it != formatlistmap.end()) formatlistptr = (*it).second;
+    else {
+      formatlistptr = new format_t();
+      parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+      formatlistmap[formatstring] = formatlistptr;
+    }
+
+    FilterResponse_t tmp;
+    get_children (section.OID, args["c"], args["l"], metadata, getParents, collectproto, tmp, logout);
+    ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
+    ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
+
+    while (thisdoc != lastdoc) {
+      recurse_contents (*thisdoc, args, fulltoc, bptr, metadata, getParents, 
+			formatlistptr, formatlistmap, formatinfo, browsermap, 
+			tabcount, collectproto, disp, outconvert, textout, logout);
+      ++thisdoc;
+    }
+  }
+}
+
+
+// expanded_contents recurses through all contents. there's a special case
+// for an HList when contents are expanded (i.e. it's displayed as a VList)
+//
+// if we're inside a document we expand all contents from the top,
+// if we're at classification level we'll just expand out those contents below 
+// the current one
+
+void expanded_contents (cgiargsclass &args, int tabcount, bool fulltoc,
+			browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			recptproto *collectproto, displayclass &disp, 
+			outconvertclass &outconvert, ostream &textout, 
+			ostream &logout) {
+  
+  if (args["d"].empty() && args["cl"].empty()) return;
+  text_t OID;
+  
+  FilterResponse_t response;
+  bool getParents = false;
+  text_tset metadata;
+  text_t classifytype, classification, formatstring;
+
+  if (!args["d"].empty()) {
+    // document level
+    if (fulltoc) {
+      get_top (args["cl"], OID);
+      classification = OID;
+    }
+    else {
+      // always expand document level from top
+      get_top (args["d"], OID);
+      classification = "Document";
+    }
+  } else {
+    // classification level
+    OID = args["cl"];
+    get_top (args["cl"], classification);
+  }
+
+  // get classifytype of this level
+  text_t tOID;
+  if (is_top(OID)) {
+    classifytype = "thistype";
+    tOID = OID;
+  } else {
+    classifytype = "childtype";
+    tOID = get_parent (OID);
+  }
+  metadata.insert (classifytype);
+
+  if (!get_info (tOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+    return;
+  classifytype = response.docInfo[0].metadata[classifytype].values[0];
+  // if we still don't have a classifytype we'll use the default
+  if (classifytype.empty()) {
+    browserclass *bptr = browsermap->get_default_browser ();
+    classifytype = bptr->get_browser_name ();
+  }
+
+  // HLists are displayed as VLists when contents are expanded,
+  // Paged documents are displayed as HLists
+  if (classifytype == "HList") {
+    classifytype = "VList";
+    text_t pOID = get_parent (OID);
+    if (!pOID.empty()) {
+      OID = pOID;
+      // this is assuming that top levels are always 'Invisible' !!!
+      if (is_top (OID)) classifytype = "Invisible";
+    }
+  }
+  if (classifytype == "Paged") classifytype = "HList";
+
+  metadata.erase (metadata.begin(), metadata.end());
+		  
+  // metadata elements needed by recurse_contents
+  metadata.insert ("childtype");
+  metadata.insert ("doctype");
+  metadata.insert ("haschildren");
+
+  // load up metadata array with browser defaults
+  browserclass *bptr = browsermap->getbrowser (classifytype);
+  bptr->load_metadata_defaults (metadata);
+
+  // get the formatstring if there is one or use the browsers default
+  if (!get_formatstring (classification, classifytype, 
+			 formatinfo.formatstrings, formatstring))
+    formatstring = bptr->get_default_formatstring();
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+
+  // protocol call
+  if (!get_info (OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+    return;
+
+  format_tmap formatlistmap;
+  formatlistmap[formatstring] = formatlistptr;
+
+  recurse_contents (response.docInfo[0], args, fulltoc, bptr, metadata, 
+		    getParents, formatlistptr, formatlistmap, formatinfo, browsermap, 
+		    tabcount, collectproto, disp, outconvert, textout, logout);
+
+  // clean up format list pointers
+  format_tmap::const_iterator here = formatlistmap.begin();
+  format_tmap::const_iterator end = formatlistmap.end();
+  while (here != end) {
+    delete (*here).second;
+    ++here;
+  }
+}
+
+
+static void load_formatstring (const text_t &classifytype, text_tset &metadata,
+			       bool &getParents, const text_t &classification, 
+			       browsermapclass *browsermap, formatinfo_t &formatinfo,
+			       format_tmap &formatlistmap) {
+  text_t formatstring;
+
+  // load up metadata array with browser defaults
+  browserclass *bptr = browsermap->getbrowser (classifytype);
+  bptr->load_metadata_defaults (metadata);
+
+  // get the formatstring if there is one or use the browsers default
+  if (!get_formatstring (classification, classifytype, 
+			 formatinfo.formatstrings, formatstring))
+    formatstring = bptr->get_default_formatstring();
+
+  // see if it's cached
+  format_tmap::const_iterator it = formatlistmap.find (formatstring);
+  if (it == formatlistmap.end()) {
+    format_t *formatlistptr = new format_t();
+    parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+    formatlistmap[formatstring] = formatlistptr;
+  }
+}
+
+static void load_formatstrings (FilterResponse_t &response, text_tset &metadata,
+				bool &getParents, const text_t &classification,
+				browsermapclass *browsermap, formatinfo_t &formatinfo, 
+				format_tmap &formatlistmap) {
+
+  text_tset cache;
+
+  ResultDocInfo_tarray::iterator thisdoc = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator lastdoc = response.docInfo.end();
+
+  while (thisdoc != lastdoc) {
+
+    if (is_top ((*thisdoc).OID))
+      load_formatstring ((*thisdoc).metadata["thistype"].values[0], metadata, 
+			 getParents, classification, browsermap, formatinfo, 
+			 formatlistmap);
+
+    text_t &childtype = (*thisdoc).metadata["childtype"].values[0];
+    text_tset::const_iterator it = cache.find (childtype);
+    if (it == cache.end()) {
+      load_formatstring (childtype, metadata, getParents, classification,
+			 browsermap, formatinfo, formatlistmap);
+      cache.insert (childtype);
+    }
+    ++thisdoc;
+  }
+}
+
+static void output_parents (FilterResponse_t &response, cgiargsclass &args, 
+			    browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			    format_tmap &formatlistmap, const text_t &classification,
+			    int &tabcount, text_tset &metadata, bool &getParents,
+			    recptproto *collectproto, displayclass &disp, 
+			    outconvertclass &outconvert, ostream &textout, 
+			    ostream &logout) {
+
+  format_t *formatlistptr = NULL;
+  text_t classifytype, formatstring;
+  bool use_table, first = true;
+  ResultDocInfo_tarray::iterator thisparent = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator lastparent = response.docInfo.end();
+  while (thisparent != lastparent) {
+
+    // get classifytype of this level
+    if (is_top ((*thisparent).OID)) classifytype = (*thisparent).metadata["thistype"].values[0];
+    else if (!first) classifytype = (*(thisparent-1)).metadata["childtype"].values[0];
+    
+    // if we still don't have a classifytype we'll use the default
+    if (classifytype.empty()) {
+      browserclass *bptr = browsermap->get_default_browser ();
+      classifytype = bptr->get_browser_name ();
+    }
+    
+    browserclass *bptr = browsermap->getbrowser (classifytype);
+
+    // get the formatstring if there is one or use the browsers default
+    if (!get_formatstring (classification, classifytype, 
+			   formatinfo.formatstrings, formatstring))
+      formatstring = bptr->get_default_formatstring();
+    
+    // see if it's cached
+    format_tmap::const_iterator it = formatlistmap.find (formatstring);
+    if (it != formatlistmap.end()) formatlistptr = (*it).second;
+    else {
+      logout << "browsetools error\n";
+      return;
+    }
+    
+    use_table = is_table_content (formatlistptr);
+    tabcount += bptr->output_section_group (*thisparent, args, "", tabcount, formatlistptr, 
+					    use_table, metadata, getParents, collectproto, 
+					    disp, outconvert, textout, logout);
+    first = false;
+    ++thisparent;
+  }
+}
+
+void contracted_contents (cgiargsclass &args, int tabcount, bool fulltoc, 
+			  browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			  recptproto *collectproto, displayclass &disp, 
+			  outconvertclass &outconvert, ostream &textout, 
+			  ostream &logout) {
+
+  FilterResponse_t response;
+  text_tset metadata;
+  bool getParents = false;
+  text_t formatstring;
+  text_tarray parents;
+  text_t OID = args["d"];
+  text_t classification = "Document";
+
+  // if we're not outputting the TOC for a valid OID, then we should be giving
+  // the TOC of a classification
+  if (OID.empty()) {
+    OID = args["cl"];
+    get_top (OID, classification);
+  } 
+  // if we're to give the full TOC of a document, get the parent for the whole
+  // document now
+  else if (fulltoc)
+    get_top (args["cl"], classification);    
+
+  bool haschildren = has_children (OID, args["c"], args["l"], collectproto, logout);
+
+  if ((!args["d"].empty()) && fulltoc)
+    get_parents_array (args["cl"] + ".fc", parents);
+  if (haschildren) get_parents_array (OID + ".fc", parents);
+  else get_parents_array (OID, parents);
+
+  if (!parents.empty()) {
+    // get classifytypes of each parent
+    metadata.insert ("thistype");
+    metadata.insert ("childtype");
+    
+    if (!get_info (parents, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+      return;
+    
+    // get formatstrings for all parents
+    format_tmap formatlistmap;  
+    load_formatstrings (response, metadata, getParents, classification, 
+			browsermap, formatinfo, formatlistmap);
+
+    if (!get_info (parents, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+      return;
+    
+    // display each parent
+    output_parents (response, args, browsermap, formatinfo, formatlistmap, 
+		    classification, tabcount, metadata, getParents, 
+		    collectproto, disp, outconvert, textout, logout);
+    
+    metadata.erase (metadata.begin(), metadata.end());
+    
+    // clean up cached format list pointers
+    format_tmap::const_iterator here = formatlistmap.begin();
+    format_tmap::const_iterator end = formatlistmap.end();
+    while (here != end) {
+      delete (*here).second;
+      ++here;
+    }
+  }
+
+  // get childrens classifytype
+  text_t classifytype;
+  int numparents = response.docInfo.size();
+  if (!parents.empty())
+    classifytype = response.docInfo[numparents-1].metadata["childtype"].values[0];
+  else {
+    // use the default
+    browserclass *bptr = browsermap->get_default_browser ();
+    classifytype = bptr->get_browser_name ();
+  }
+    
+  // load up metadata array with browser defaults
+  browserclass *bptr = browsermap->getbrowser (classifytype);
+  bptr->load_metadata_defaults (metadata);
+
+  if (classifytype == "DateList") {
+    metadata.insert(args["dm"]);
+  }
+
+  // get the formatstring if there is one or use the browsers default
+  if (!get_formatstring (classification, classifytype, 
+			 formatinfo.formatstrings, formatstring))
+    formatstring = bptr->get_default_formatstring();
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+
+  if (haschildren) 
+    get_children (OID, args["c"], args["l"], metadata, getParents,
+		  collectproto, response, logout);
+  else if (!is_top(OID)) {
+    get_children (OID + ".pr", args["c"], args["l"], metadata, getParents, 
+		  collectproto, response, logout);
+    haschildren = true;
+  }
+
+  // display children
+  if (haschildren) {
+    bool use_table = is_table_content (formatlistptr);
+    bptr->output_section_group (response, args, args["c"], tabcount, formatlistptr, use_table, 
+				metadata, getParents, collectproto, disp, outconvert, 
+				textout, logout);
+  }
+  delete formatlistptr;
+}
+
+/**
+ * This function outputs contents of a classifier to the reader
+ * including parent levels
+ */
+void expand_show_contents (cgiargsclass &args, int tabcount, bool fulltoc,
+			browsermapclass *browsermap, formatinfo_t &formatinfo,
+			recptproto *collectproto, displayclass &disp,
+			outconvertclass &outconvert, ostream &textout, 
+			ostream &logout)
+{
+
+	int coloffset = 0;
+	text_tarray parents;
+	FilterResponse_t response;
+ 	text_t OID = args["d"];
+	if (OID.empty()) OID = args["cl"];
+
+	bool haschildren = has_children (OID, args["c"], args["l"], collectproto, logout);
+
+	// get parents list
+	if (!is_top(OID)) get_parents_array (OID, parents);
+	if (args["d"].empty() || haschildren || parents.empty())
+		parents.push_back(OID);
+
+	// if inside a book top title is needed
+	if (!args["d"].empty()) {
+		
+		coloffset = 1;
+		text_t classification, classifytype, formatstring, topOID = parents[0];
+		text_tset metadata;
+		format_t *formatlistptr = new format_t();
+		bool use_table, getParents = false;
+		
+		get_top (args["cl"], classification);
+
+		// getting information about top OID
+		metadata.insert ("thistype");
+
+		get_info ( topOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+		if (!response.docInfo[0].metadata["thistype"].values.empty()) 
+			classifytype = response.docInfo[0].metadata["thistype"].values[0];
+
+		browserclass *bptr = browsermap->getbrowser (classifytype);
+
+		if (classifytype.empty()) {
+			bptr = browsermap->get_default_browser();
+		}
+
+		// get the formatstring if there is one or use the browsers default
+		if (!get_formatstring (classification, classifytype, 
+			formatinfo.formatstrings, formatstring))
+				formatstring = bptr->get_default_formatstring();
+
+		parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+
+		metadata.insert ("doctype");
+		metadata.insert ("haschildren");
+
+		get_info (topOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+
+		// ouput top OID section
+		use_table = is_table_content (formatlistptr);
+		bptr->output_section_group (response.docInfo[0], args, "", tabcount, formatlistptr, use_table,
+				metadata, getParents, collectproto, disp, outconvert, textout, logout);
+
+	}
+
+	recurse_contents_levels (parents, args, coloffset, tabcount, fulltoc, browsermap, 
+		formatinfo, collectproto, disp, outconvert, textout, logout);
+
+	textout << outconvert << "</table></td></tr></table>\n";
+}
+
+void recurse_contents_levels (text_tarray &parents, 
+			cgiargsclass &args, int coloffset, int tabcount, bool fulltoc,
+			browsermapclass *browsermap, formatinfo_t &formatinfo,
+			recptproto *collectproto, displayclass &disp,
+			outconvertclass &outconvert, ostream &textout, 
+			ostream &logout)
+{
+	FilterResponse_t response;
+	text_tset metadata;
+	text_t OID, formatstring, classification, classifytype;;
+	bool use_table, getParents = false;
+	int haschildren = 0;
+	format_t *formatlistptr = new format_t();
+
+	// display children for last level
+	if (tabcount == (parents.size() - 1)) {
+
+		logout << "@@@lastlevel@@@\n";
+		// setting metadata fields 
+		metadata.insert ("thistype");
+		metadata.insert ("childtype");
+		metadata.insert ("haschildren");
+
+		OID = parents[tabcount];
+		get_info (OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+		get_top (OID, classification);
+
+		if (!response.docInfo.empty())
+			haschildren = response.docInfo[0].metadata["haschildren"].values[0].getint();
+
+		// get childrens classifytype
+		if (!response.docInfo.empty())
+			classifytype = response.docInfo[0].metadata["childtype"].values[0];
+		else {
+			// use the default
+			browserclass *bptr = browsermap->get_default_browser ();
+			classifytype = bptr->get_browser_name ();
+		}
+
+		// load up metadata array with browser defaults
+		browserclass *bptr = browsermap->getbrowser (classifytype);
+		bptr->load_metadata_defaults (metadata);
+
+		// get the formatstring if there is one or use the browsers default
+		if (!get_formatstring (classification, classifytype, 
+			formatinfo.formatstrings, formatstring))
+				formatstring = bptr->get_default_formatstring();
+
+		parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+
+		if (haschildren) 
+			get_children (OID, args["c"], args["l"], metadata, getParents,
+				collectproto, response, logout);
+		else if (!is_top(OID)) {
+			get_children (OID + ".pr", args["c"], args["l"], metadata, getParents, 
+			collectproto, response, logout);
+			haschildren = true;
+		}
+
+		// display children
+		if (haschildren) {
+			use_table = is_table_content (formatlistptr);
+			bptr->output_section_group (response, args, args["c"], coloffset + tabcount, formatlistptr, use_table, 
+						metadata, getParents, collectproto, disp, outconvert, 
+						textout, logout);
+		}
+
+	} else {
+
+		text_t pOID;
+		OID = parents[tabcount];
+		get_top (OID, classification);
+
+		// load metadata fields
+		metadata.insert ("thistype");
+		metadata.insert ("childtype");
+		metadata.insert ("haschildren");
+		metadata.insert ("doctype");
+
+		if (tabcount) pOID = parents[tabcount-1];
+		else pOID = OID;
+		get_info (pOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+
+		// get classifytype of this level
+		if (is_top (pOID)) classifytype = response.docInfo[0].metadata["childtype"].values[0];
+		else classifytype = response.docInfo[0].metadata["thistype"].values[0];
+
+		// if we still don't have a classifytype we'll use the default
+		if (classifytype.empty()) {
+			browserclass *bptr = browsermap->get_default_browser ();
+			classifytype = bptr->get_browser_name ();
+		}
+
+		browserclass *bptr = browsermap->getbrowser (classifytype);
+
+		// get the formatstring if there is one or use the browsers default
+		if (!get_formatstring (classification, classifytype, 
+				formatinfo.formatstrings, formatstring))
+			formatstring = bptr->get_default_formatstring();
+
+
+		// parse format string 
+		parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+
+		use_table = is_table_content (formatlistptr);
+
+		get_children (OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+
+		ResultDocInfo_tarray::iterator thissibling = response.docInfo.begin();
+		ResultDocInfo_tarray::iterator lastsibling = response.docInfo.end();
+
+		while (thissibling != lastsibling) {
+
+			logout << "@@@level:@@@" << tabcount << "\n";
+
+			bptr->output_section_group (*thissibling, args, args["c"], coloffset + tabcount, formatlistptr, 
+					use_table, metadata, getParents, collectproto, 
+					disp, outconvert, textout, logout);
+			
+			if ((*thissibling).OID == parents[tabcount+1]) {
+				recurse_contents_levels (parents, args, coloffset, tabcount+1, fulltoc, browsermap,
+					formatinfo, collectproto, disp, outconvert,textout, logout);
+			}
+
+			++thissibling;
+		}
+	}
+	delete formatlistptr;
+}
+
+/**
+ * This function outputs the contents of a classifier list to the reader - 
+ * the document will in fact be empty, so this does the "real" output
+ */
+void output_toc (cgiargsclass &args, browsermapclass *browsermap,
+                 formatinfo_t &formatinfo, recptproto *collectproto,
+                 displayclass &disp, outconvertclass &outconvert,
+                 ostream &textout, ostream &logout) {
+
+  if (!args["d"].empty() && formatinfo.AllowExtendedOptions) {
+    // If AllowExtendedOptions is set and we're viewing a document,
+    // DocumentButtons, DocumentContent, and DocumentImages are effectively
+    // disabled. We just output the DocumentHeading format string and
+    // return
+    output_titles (args, collectproto, browsermap, formatinfo, disp, outconvert, textout, logout);    
+    return;
+  }
+
+  int tabcount = 0;
+  bool havecontrols = false;
+  bool fulltoc = false;
+
+  if (args["cl"] != "search") {
+    // see if there's a FullTOC string
+    text_t cl_top, full_toc;
+    get_top (args["cl"], cl_top);
+    if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
+      if (full_toc == "true") fulltoc = true;
+  }
+  
+  // get the cover image (if there is one) and the control buttons
+  // if we're inside a book
+  if ((!fulltoc) && (!args["d"].empty())) {
+    textout << outconvert << "<center>\n";
+    textout << outconvert << disp << "<p><table width=_pagewidth_ cellpadding=0 cellspacing=0><tr>\n";
+    textout << outconvert << "<td valign=top align=left";
+    if (formatinfo.DocumentContents) textout << outconvert << " width=200>\n";
+    else textout << outconvert << " width=\"100%\">\n";
+    if (formatinfo.DocumentImages) 
+      output_cover_image (args, collectproto, disp, outconvert, textout, logout);
+    else if (formatinfo.DocumentTitles)
+      output_titles (args, collectproto, browsermap, formatinfo, disp, outconvert, textout, logout);
+    if (args["u"] != "1") {
+      output_controls (args, formatinfo.DocumentButtons, collectproto, disp, 
+		       outconvert, textout, logout);
+    }
+    textout << outconvert << "</td><td valign=\"top\">\n";  
+    havecontrols = true;
+  }
+
+  if (formatinfo.DocumentContents || args["d"].empty()) {
+    if (args.getintarg("gc") == 1) {
+      
+      // expanded table of contents
+      expanded_contents (args, tabcount, fulltoc, browsermap, formatinfo, 
+			 collectproto, disp, outconvert, textout, logout);
+    } else if (args.getintarg("gc") == 2) {
+
+		// expand visible levels of table of contents
+	  expand_show_contents(args, tabcount, fulltoc, browsermap, formatinfo,
+			collectproto, disp, outconvert, textout, logout);
+	} else {
+      
+      // contracted table of contents
+      contracted_contents (args, tabcount, fulltoc, browsermap, formatinfo, 
+			   collectproto, disp, outconvert, textout, logout);
+    }
+  }
+
+  if (havecontrols) textout << outconvert << "</td></tr></table></center>\n"; 
+
+  //if there is a format specified in the config file then
+  //try to display the related documents (may not be displayed
+  //if preference file does not indicate a wish to display
+  //related documents.
+  if (!formatinfo.RelatedDocuments.empty())
+    output_related_docs(args, collectproto, formatinfo, disp, outconvert, textout, logout);
+ 
+}
+
+void load_extended_options(text_tmap &options, cgiargsclass &args, browsermapclass *browsers, 
+			   formatinfo_t &formatinfo, recptproto *collectproto, 
+			   displayclass &disp, outconvertclass &outconvert, ostream &logout) {
+
+  options["DocImage"] = get_cover_image();
+
+#if defined(GSDL_USE_IOS_H)
+  ostrstream *tmpstr = new ostrstream();
+#else
+  ostringstream *tmpstr = new ostringstream(ostringstream::binary);
+#endif
+
+  if (args["gc"] == "1") {
+    expanded_contents (args, 0, false, browsers, formatinfo, 
+		       collectproto, disp, outconvert, *tmpstr,
+		       logout);
+  } else {
+    contracted_contents (args, 0, false, browsers, formatinfo, 
+			 collectproto, disp, outconvert, *tmpstr, logout);
+  }
+#if defined(GSDL_USE_IOS_H)
+  char *t = tmpstr->str();
+  text_t tmp;
+  tmp.setcarr(t, tmpstr->pcount());
+  delete [] t;
+#else
+  text_t tmp = (char *)(tmpstr->str().c_str());
+#endif
+  int len = tmp.size();
+  char *ctmp = tmp.getcstr();
+  utf8inconvertclass utf82text_t;
+  utf82text_t.setinput(ctmp, len);
+  convertclass::status_t status;
+  utf82text_t.convert(tmp, status);
+  options["DocTOC"] = tmp;
+  delete []ctmp;
+  delete tmpstr;
+
+  options["DocumentButtonDetach"] = "_document:imagedetach_";
+  if (args["hl"] == "1") {
+    options["DocumentButtonHighlight"] = "_document:imagenohighlight_";
+  } else {
+    options["DocumentButtonHighlight"] = "_document:imagehighlight_";
+  }
+  if (args["gc"] == "1") {
+    options["DocumentButtonExpandContents"] = "_document:imagecontracttoc_";
+  } else {
+    options["DocumentButtonExpandContents"] = "_document:imageexpandtoc_";
+  }
+  if (args["gt"] == "1") {
+    options["DocumentButtonExpandText"] = "_document:imagecontracttext_";
+  } else {
+    options["DocumentButtonExpandText"] = "_document:imageexpandtext_";
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/browsetools.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/browsetools.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/browsetools.h	(revision 10506)
@@ -0,0 +1,90 @@
+/**********************************************************************
+ *
+ * browsetools.h --
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef BROWSETOOLS_H
+#define BROWSETOOLS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+#include "display.h"
+#include "recptproto.h"
+#include "formattools.h"
+#include "browserclass.h"
+
+typedef map<text_t, format_t*, lttext_t> format_tmap; 
+
+void expanded_contents (cgiargsclass &args, int tabcount, bool fulltoc,
+			browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			recptproto *collectproto, displayclass &disp, 
+			outconvertclass &outconvert, ostream &textout, 
+			ostream &logout);
+
+void expand_show_contents (cgiargsclass &args, int tabcount, bool fulltoc,
+			browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			recptproto *collectproto, displayclass &disp, 
+			outconvertclass &outconvert, ostream &textout, 
+			ostream &logout);
+
+void recurse_contents_levels (text_tarray &parents, 
+			cgiargsclass &args, int coloffset, int tabcount, bool fulltoc,
+			browsermapclass *browsermap, formatinfo_t &formatinfo,
+			recptproto *collectproto, displayclass &disp,
+			outconvertclass &outconvert, ostream &textout, 
+			ostream &logout);
+
+void contracted_contents (cgiargsclass &args, int tabcount, bool fulltoc, 
+			  browsermapclass *browsermap, formatinfo_t &formatinfo, 
+			  recptproto *collectproto, displayclass &disp, 
+			  outconvertclass &outconvert, ostream &textout, 
+			  ostream &logout);
+
+void output_toc (cgiargsclass &args, browsermapclass *browsermap,
+                 formatinfo_t &formatinfo, recptproto *collectproto,
+                 displayclass &disp, outconvertclass &outconvert,
+                 ostream &textout, ostream &logout);
+
+void output_titles (cgiargsclass &args, recptproto *collectproto, 
+		    browsermapclass *browsermap, formatinfo_t &formatinfo,
+		    displayclass &disp, outconvertclass &outconvert,
+		    ostream &textout, ostream &logout);
+
+void output_controls (cgiargsclass &args, const text_tarray &ibuttons,
+		      recptproto *collectproto, displayclass &disp, 
+		      outconvertclass &outconvert, ostream &textout, 
+		      ostream &logout);
+
+text_t get_cover_image ();
+
+void output_cover_image (cgiargsclass &args, recptproto *collectproto, 
+			 displayclass &disp, outconvertclass &outconvert, 
+			 ostream &textout, ostream &logout);
+
+void load_extended_options(text_tmap &options, cgiargsclass &args, browsermapclass *browsers, 
+			   formatinfo_t &formatinfo, recptproto *collectproto, 
+			   displayclass &disp, outconvertclass &outconvert, ostream &logout);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiargs.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiargs.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiargs.cpp	(revision 10506)
@@ -0,0 +1,324 @@
+/**********************************************************************
+ *
+ * cgiargs.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "cgiargs.h"
+#include "gsdlunicode.h"
+
+
+
+void cgiarg_t::clear () {
+  value.clear();
+  source = program_arg;
+}
+
+cgiarg_t &cgiarg_t::operator=(const cgiarg_t &x) {
+  value=x.value;
+  source=x.source;
+  return *this;
+}
+
+
+bool operator==(const cgiarg_t &x, const cgiarg_t &y) {
+  return ((x.value == y.value) && (x.source == y.source));
+}
+
+bool operator<(const cgiarg_t &x, const cgiarg_t &y) {
+  return ((x.value < y.value) ||
+	  ((x.value == y.value) && (x.source == y.source)));
+}
+
+
+
+
+// constructors
+cgiargsclass::cgiargsclass () {
+}
+
+
+// this returns NULL if there isn't an entry with a value of
+// 'key' already defined
+
+void cgiargsclass::setarg (const text_t &key, const text_t &value,
+			   cgiarg_t::source_t source) {
+  cgiarg_t temparg;
+  temparg.value = value;
+  temparg.source = source;
+  args[key] = temparg;
+}
+
+void cgiargsclass::setdefaultarg (const text_t &key, const text_t &value,
+				  cgiarg_t::source_t source) {
+  if (getarg(key) == NULL) setarg (key, value, source);
+}
+
+void cgiargsclass::setintarg (const text_t &key, int value,
+			      cgiarg_t::source_t source) {
+  setarg (key, value, source);
+}
+
+void cgiargsclass::setdefaultintarg (const text_t &key, int value,
+				     cgiarg_t::source_t source) {
+  if (getarg(key) == NULL) setintarg (key, value, source);
+}
+
+void cgiargsclass::setcarg (const text_t &key, unsigned short c,
+			    cgiarg_t::source_t source) {
+  text_t t; 
+  t.push_back(c);
+  setarg(key,t, source);
+}
+
+void cgiargsclass::setdefaultcarg (const text_t &key, unsigned short c,
+				   cgiarg_t::source_t source) {
+  if (getarg(key) == NULL) setcarg (key, c, source);
+}
+
+text_t *cgiargsclass::getarg (const text_t &key) {
+  iterator here = args.find (key);
+  if (here == args.end()) return NULL;
+
+  return &((*here).second.value);
+}
+
+int cgiargsclass::getintarg (const text_t &key) {
+  text_t *text = getarg (key);
+  if (text == NULL) return 0;
+  return text->getint();
+}
+
+
+
+// stream operators to print cgi arguments for debugging purposes
+ostream &operator<<(ostream &outs, const cgiargsclass &args) {
+  utf8outconvertclass text_t2utf8;
+  cgiargsclass::const_iterator here = args.begin ();
+  cgiargsclass::const_iterator end = args.end ();
+
+  outs << "*** cgiargsclass\n";
+  
+  while (here != end) {
+    outs << text_t2utf8 << " \"" << (*here).first << "\"=\"" << 
+      (*here).second.value << "\"\n";
+    ++here;
+  }
+  outs << "\n";
+
+  return outs;
+}
+
+
+
+cgiarginfo::cgiarginfo () {
+  multiplechar = false;
+  multiplevalue = false;
+  defaultstatus = weak;
+  argdefault.clear();
+  savedarginfo = can;
+}
+
+
+bool operator==(const cgiarginfo &x, const cgiarginfo &y) {
+  return ((x.shortname == y.shortname) &&
+	  (x.longname == y.longname) &&
+	  (x.multiplechar == y.multiplechar) &&
+	  (x.multiplevalue == y.multiplevalue) &&
+	  (x.defaultstatus == y.defaultstatus) &&
+	  (x.argdefault == y.argdefault) &&
+	  (x.savedarginfo == y.savedarginfo));
+}
+
+bool operator<(const cgiarginfo &x, const cgiarginfo &y) {
+  return ((x.shortname < y.shortname) ||
+	  ((x.shortname == y.shortname) &&
+	   ((x.longname < y.longname) ||
+	    ((x.longname == y.longname) &&
+	     ((x.multiplevalue < y.multiplevalue) ||
+	      ((x.multiplevalue == y.multiplevalue) &&
+	       ((x.multiplechar < y.multiplechar) ||
+		((x.multiplechar == y.multiplechar) &&
+		 ((x.defaultstatus < y.defaultstatus) ||
+		  ((x.defaultstatus == y.defaultstatus) &&
+		   ((x.argdefault < y.argdefault) ||
+		    ((x.argdefault == y.argdefault) &&
+		     ((x.savedarginfo < y.savedarginfo))))))))))))));
+}
+
+
+// constructor
+cgiargsinfoclass::cgiargsinfoclass () {
+}
+
+// addarginfo will combine the information with the present
+// information. If name clashes were detected then the information
+// will be written to logout and addarginfo will return false. No
+// processing with the arguments should be done if this happens
+// as the results will be meaningless.
+bool cgiargsinfoclass::addarginfo (ostream *logout, const cgiarginfo &info) {
+
+  cgiarginfo *orginfo = getarginfo (info.shortname);
+  if (orginfo == NULL) {
+    argsinfo[info.shortname] = info;
+    return true; // no clashes
+  }
+
+  if (orginfo->longname != info.longname) {
+    if (logout != NULL) {
+      outconvertclass text_t2ascii;
+      (*logout) << text_t2ascii << "Error: cgi argument name clash for argument \""
+		<< info.shortname << "\".\nOne long name was\n  \"" << orginfo->longname 
+		<< "\"\nand the other was\n  \"" << info.longname << "\".\n\n";
+    }
+    return false; // found a clash
+  }
+
+  if (orginfo->multiplevalue != info.multiplevalue) {
+    if (logout != NULL) {
+      outconvertclass text_t2ascii;
+      (*logout) << text_t2ascii << "Error: cgi argument \"" << info.shortname 
+		<< "\" was given as being a single value option\n"
+		<< "and a multiple value option.\n\n";
+    }
+    return false; // found a clash
+  }
+
+  if (orginfo->multiplechar != info.multiplechar) {
+    if (logout != NULL) {
+      outconvertclass text_t2ascii;
+      (*logout) << text_t2ascii << "Error: cgi argument \"" << info.shortname 
+		<< "\" was given as being a single character option\n"
+		<< "and a multiple character option.\n\n";
+    }
+    return false; // found a clash
+  }
+  
+  if (!info.multiplechar && info.argdefault.size() > 1) {
+    if (logout != NULL) {
+      outconvertclass text_t2ascii;
+      (*logout) << text_t2ascii << "Error: cgi argument \"" << info.shortname
+		<< "\" was defined as being a single character option\n"
+		<< "but a multiple character default was given.\n\n";
+    }
+    return false;  // found a problem
+  }
+
+  // make sure there is no clashes in the savedarginfo
+  if ((orginfo->savedarginfo==cgiarginfo::mustnot && 
+       info.savedarginfo==cgiarginfo::must) ||
+      (orginfo->savedarginfo==cgiarginfo::must && 
+       info.savedarginfo==cgiarginfo::mustnot)) {
+    if (logout != NULL) {
+      outconvertclass text_t2ascii;
+      (*logout) << text_t2ascii << "Error: it was specified that cgi argument \"" 
+		<< info.shortname << "\" should be saved in the state\n"
+		<< "information and that it should not be save in the state information.\n\n";
+    }
+    return false; // found a clash
+  }
+  // the only time orginfo->savedarginfo can change is when it is set
+  // to "can"
+  if (orginfo->savedarginfo == cgiarginfo::can) 
+    orginfo->savedarginfo = info.savedarginfo;
+
+
+  if (orginfo->defaultstatus > info.defaultstatus) {
+    return true;
+  }
+  orginfo->defaultstatus = info.defaultstatus;
+  orginfo->argdefault = info.argdefault;
+
+  return true;
+}
+
+bool cgiargsinfoclass::addarginfo (ostream *logout, const cgiargsinfoclass &info) {
+  const_iterator here = info.begin ();
+  const_iterator end = info.end ();
+
+  while (here != end) {
+    if (!addarginfo (logout, (*here).second)) return false;
+    ++here;
+  }
+  
+  return true; // made it, no clashes
+}
+
+bool cgiargsinfoclass::addarginfo (ostream *logout, const text_t& argshortname, const text_tmap& mapinfo)
+{
+  cgiarginfo *arginfo = getarginfo (argshortname);
+  if (arginfo == NULL) {
+    arginfo = &(argsinfo[argshortname]);
+    arginfo->shortname = argshortname;
+    arginfo->defaultstatus = cgiarginfo::config;
+  }
+  text_tmap::const_iterator thisInfo = mapinfo.begin();
+  text_tmap::const_iterator endInfo = mapinfo.end();
+  while (thisInfo != endInfo) {
+    if (thisInfo->first == "longname") arginfo->longname = thisInfo->second;
+    else if (thisInfo->first == "multiplechar") arginfo->multiplechar = (thisInfo->second == "true");
+    else if (thisInfo->first == "defaultstatus") {
+      if (thisInfo->second == "none") arginfo->defaultstatus = cgiarginfo::none;
+      else if (thisInfo->second == "weak") arginfo->defaultstatus = cgiarginfo::weak;
+      else if (thisInfo->second == "good") arginfo->defaultstatus = cgiarginfo::good;
+      else if (thisInfo->second == "config") arginfo->defaultstatus = cgiarginfo::config;
+      else if (thisInfo->second == "imperative") arginfo->defaultstatus = cgiarginfo::imperative;
+    }
+    else if (thisInfo->first == "argdefault") {
+      arginfo->argdefault = thisInfo->second;
+    }
+    else if (thisInfo->first == "savedarginfo") {
+      if (thisInfo->second == "mustnot") arginfo->savedarginfo = cgiarginfo::mustnot;
+      else if (thisInfo->second == "can") arginfo->savedarginfo = cgiarginfo::can;
+      else if (thisInfo->second == "must") arginfo->savedarginfo = cgiarginfo::must;
+    } else if (logout != NULL) {
+      (*logout) << ("Invalid argument for cgiarg for " + argshortname + " (" + thisInfo->first + ")\n");
+    }
+    ++thisInfo;
+  }
+  return true;
+}
+
+bool cgiargsinfoclass::addarginfo (ostream *logout, const confcgiarg_tmap& info)
+{
+  confcgiarg_tmap::const_iterator thisArg = info.begin();
+  confcgiarg_tmap::const_iterator endArg = info.end();
+  while (thisArg != endArg) {
+    if (!addarginfo(logout, thisArg->first, thisArg->second)) return false;
+    ++thisArg;
+  }
+  return true;
+}
+
+cgiarginfo *cgiargsinfoclass::getarginfo (const text_t &key) {
+  iterator here = argsinfo.find (key);
+  if (here == argsinfo.end()) return NULL;
+
+  return &((*here).second);
+}
+
+const cgiarginfo *cgiargsinfoclass::getarginfo (const text_t &key) const {
+  const_iterator here = argsinfo.find (key);
+  if (here == argsinfo.end()) return NULL;
+
+  return &((*here).second);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiargs.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiargs.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiargs.h	(revision 10506)
@@ -0,0 +1,240 @@
+/**********************************************************************
+ *
+ * cgiargs.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef CGIARGS_H
+#define CGIARGS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+// response_t is used to define what type of cgi header 
+// should be produced
+// fullcontent same as content but the action should put content-type as last header.
+enum response_t {location, content, fullcontent, undecided_location};
+
+
+struct cgiarg_t {
+  void clear ();
+  cgiarg_t () {clear();}
+  cgiarg_t &operator=(const cgiarg_t &x);
+  
+  enum source_t {default_arg, compressed_arg, cgi_arg, program_arg};
+  
+  text_t value;
+  source_t source;
+};
+
+bool operator==(const cgiarg_t &x, const cgiarg_t &y);
+bool operator<(const cgiarg_t &x, const cgiarg_t &y);
+
+typedef map<text_t, cgiarg_t, lttext_t> cgiarg_tmap;
+typedef map<text_t, text_tmap, lttext_t> confcgiarg_tmap;
+
+// cgiargsclass is used to store a particular set
+// of cgi arguments.
+class cgiargsclass {
+protected:
+  cgiarg_tmap args;
+
+public:
+  //type support for cgiarg_tmap
+  typedef cgiarg_tmap::iterator iterator;
+  typedef cgiarg_tmap::const_iterator const_iterator;
+  typedef cgiarg_tmap::reference reference;
+  typedef cgiarg_tmap::const_reference const_reference;
+  typedef cgiarg_tmap::size_type size_type;
+  typedef cgiarg_tmap::difference_type difference_type;
+  typedef cgiarg_tmap::const_reverse_iterator const_reverse_iterator;
+  typedef cgiarg_tmap::reverse_iterator reverse_iterator;
+  
+  // constructors
+  cgiargsclass ();
+
+  // basic container support
+  iterator begin () {return args.begin();}
+  const_iterator begin () const {return args.begin();}
+  iterator end () {return args.end();}
+  const_iterator end () const {return args.end();}
+
+  void erase(iterator pos) {args.erase(pos);}
+  void erase(iterator first, iterator last) {args.erase(first, last);}
+  cgiargsclass &operator=(const cgiargsclass &x) {args=x.args;return *this;}
+
+  bool empty () const {return args.empty();}
+  size_type size() const {return args.size();}
+
+
+  // added functionality
+  void clear () {args.erase(args.begin(),args.end());}
+
+  // setdefaultarg, setdefaultintarg, and setdefaultcarg will 
+  // only set the argument if it is not already set
+  // getargs returns NULL if there isn't an entry with
+  // 'key' already defined, getintarg returns 0 if there wasn't an
+  // entry with 'key' defined and operator[] returns "" if
+  // 'key' wasn't already defined (and sets 'key'="").
+  void setarg (const text_t &key, const text_t &value,
+	       cgiarg_t::source_t source=cgiarg_t::program_arg);
+  void setdefaultarg (const text_t &key, const text_t &value,
+		      cgiarg_t::source_t source=cgiarg_t::default_arg);
+  void setintarg (const text_t &key, int value,
+		  cgiarg_t::source_t source=cgiarg_t::program_arg);
+  void setdefaultintarg (const text_t &key, int value,
+			 cgiarg_t::source_t source=cgiarg_t::default_arg);
+  void setcarg (const text_t &key, unsigned short c,
+		cgiarg_t::source_t source=cgiarg_t::program_arg);
+  void setdefaultcarg (const text_t &key, unsigned short c,
+		       cgiarg_t::source_t source=cgiarg_t::default_arg);
+  text_t *getarg (const text_t &key);
+  int getintarg (const text_t &key);
+  text_t &operator[] (const text_t &key) {return args[key].value;}
+  cgiarg_t &lookupcgiarg (const text_t &key) {return args[key];}
+};
+
+// stream operators to print cgi arguments for debugging purposes
+ostream &operator<<(ostream &outs, const cgiargsclass &args);
+
+
+
+// cgiarginfo holds information relating to a cgi argument
+class cgiarginfo {
+public:
+  cgiarginfo ();
+
+  // shortname is the name used in cgi arguments
+  text_t shortname;
+
+  // longname is the name used when giving information 
+  // about the argument and to spot name duplication
+  text_t longname;
+
+  // multiplechar should be set to true if the value can be
+  // more than one character long
+  bool multiplechar;
+
+  // multiplevalue should be set to true the argument may have 
+  // multiple values (as is the case when multiple checkboxes
+  // use the same name)
+  bool multiplevalue;
+
+  // defaultstatus_t indicates how good the default is when different
+  // defaults are given for one argument. "none" means there is no default
+  // (a default might be given elsewhere). "weak" is a basic guess that
+  // doesn't hold much weight, "good" is a better guess, "config" was a default
+  // given in a configuration file, and "imperative" means it must not
+  // be overriden at any costs (unless there is another "imperative"...)
+  enum defaultstatus_t {none=0, weak=1, good=2, config=3, imperative=4};
+
+  defaultstatus_t defaultstatus;
+  text_t argdefault;   // a default value
+
+  // savedarginfo_t indicates whether the argument should be saved
+  // between pages (e.g. using the compressed argument) or not. The
+  // value of an argument can change from "can" to "mustnot" and 
+  // "can" to "must" but not "mustnot" to "must" or "must" to "mustnot".
+  enum savedarginfo_t {mustnot, can, must};
+
+  savedarginfo_t savedarginfo;
+};
+
+bool operator==(const cgiarginfo &x, const cgiarginfo &y);
+bool operator<(const cgiarginfo &x, const cgiarginfo &y);
+
+typedef map<text_t, cgiarginfo, lttext_t> argsinfomap;
+
+// contains a list of cgi argument information
+class cgiargsinfoclass {
+protected:
+  argsinfomap argsinfo;
+
+public:
+  // type support for arginfomap
+  typedef argsinfomap::iterator iterator;
+  typedef argsinfomap::const_iterator const_iterator;
+  typedef argsinfomap::reference reference;
+  typedef argsinfomap::const_reference const_reference;
+  typedef argsinfomap::size_type size_type;
+  typedef argsinfomap::difference_type difference_type;
+  typedef argsinfomap::const_reverse_iterator const_reverse_iterator;
+  typedef argsinfomap::reverse_iterator reverse_iterator;
+  
+  // constructors
+  cgiargsinfoclass ();
+
+  // basic container support
+  iterator begin () {return argsinfo.begin();}
+  const_iterator begin () const {return argsinfo.begin();}
+  iterator end () {return argsinfo.end();}
+  const_iterator end () const {return argsinfo.end();}
+
+  void erase(iterator pos) {argsinfo.erase(pos);}
+  void erase(iterator first, iterator last) {argsinfo.erase(first, last);}
+  cgiargsinfoclass &operator=(const cgiargsinfoclass &x) {argsinfo=x.argsinfo;return *this;}
+
+  bool empty () const {return argsinfo.empty();}
+  size_type size() const {return argsinfo.size();}
+
+
+  // added functionality
+  void clear () {argsinfo.erase(argsinfo.begin(),argsinfo.end());}
+
+  // addarginfo will combine the information with the present
+  // information. If name clashes were detected then the information
+  // will be written to logout and addarginfo will return false. No
+  // processing with the arguments should be done if this happens
+  // as the results will be meaningless.
+  bool addarginfo (ostream *logout, const cgiarginfo &info);
+  bool addarginfo (ostream *logout, const cgiargsinfoclass &info);
+
+  // addarginfo will override args info with info loaded from config files
+  // if the args do not exists will be created
+  bool addarginfo (ostream *logout, const text_t& argshortname, const text_tmap& mapinfo);
+  bool addarginfo (ostream *logout, const confcgiarg_tmap& info);
+
+  cgiarginfo *getarginfo (const text_t &key);
+  const cgiarginfo *getarginfo (const text_t &key) const;
+  cgiarginfo &operator[] (const text_t &key) {return argsinfo[key];}
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiutils.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiutils.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiutils.cpp	(revision 10506)
@@ -0,0 +1,551 @@
+/**********************************************************************
+ *
+ * cgiutils.cpp -- general cgi utilities
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "cgiutils.h"
+#include "gsdlunicode.h"
+#include "unitool.h" // in mg, for output_utf8_char
+
+static unsigned short hexdigit (unsigned short c) {
+  if (c >= '0' && c <= '9') return (c-'0');
+  if (c >= 'a' && c <= 'f') return (c-'a'+10);
+  if (c >= 'A' && c <= 'F') return (c-'A'+10);
+  return c;
+}
+
+
+static void c2hex (unsigned short c, text_t &t) {
+  t.clear();
+  
+  if (c >= 256) {
+    t = "20"; // ' '
+    return;
+  }
+  
+  unsigned short o1, o2;
+  
+  o1 = (c/16) % 16;
+  o2 = c % 16;
+  if (o1 >= 10) o1 += 'a' - 10;
+  else o1 += '0';
+  if (o2 >= 10) o2 += 'a' - 10;
+  else o2 += '0';
+  
+  t.push_back(o1);
+  t.push_back(o2);
+}
+
+// convert %xx and + to their appropriate equivalents
+// IE 6.0 and later use "%u" followed by 4 hex digits... MS IIS extension!
+void decode_cgi_arg (text_t &argstr) {
+  text_t::iterator in = argstr.begin();
+  text_t::iterator out = in;
+  text_t::iterator end = argstr.end();
+  
+  while (in != end) {
+    if (*in == '+') *out = ' ';
+    
+    else if (*in == '%') {
+      unsigned short c = '%';
+      ++in;
+      if (in != end) { // this is an encoding...
+	if (*in == 'u') { // convert %uHHHH to unicode then current encoding
+	  // this assumes a short int is at least 16 bits...
+	  ++in;  
+	  if (in != end)
+	    c=hexdigit(*in++) << 12;
+	  if (in != end)
+	    c+=hexdigit(*in++) << 8;
+	  if (in != end)
+	    c+=hexdigit(*in++) << 4;
+	  if (in != end)
+	    c+=hexdigit(*in);
+	  /* BAD!! The following assumes the interface is using utf-8. But
+	     at this point we don't know what encoding we are using, unless
+	     we can parse it out of the string we are currently decoding... */
+	  text_t uni=" ";
+	  uni[0]=c;
+	  text_t utf8=to_utf8(uni);
+	  int last_byte=utf8.size()-1;
+	  for (int i=0;i<last_byte;++i)
+	    *out++ = utf8[i];
+	  c=utf8[last_byte];
+	} else {  // convert %HH to hex value
+	  c = hexdigit (*in);
+	  ++in;
+	  if (in != end && c < 16) { // sanity check on the previous character
+	    c = c*16 + hexdigit (*in);
+	  }
+	}
+      }
+      *out = c;
+    } else *out = *in;
+    
+    if (in != end) ++in;
+    ++out;
+  }
+  
+  // remove the excess characters
+  argstr.erase (out, end);
+}
+
+
+// split up the cgi arguments
+void split_cgi_args (const cgiargsinfoclass &argsinfo, text_t argstr, 
+		     cgiargsclass &args) {
+  args.clear();
+  
+  text_t::const_iterator here = argstr.begin();
+  text_t::const_iterator end = argstr.end();
+  text_t key, value;
+  
+  // extract out the key=value pairs
+  while (here != end) {
+    // get the next key and value pair
+    here = getdelimitstr (here, end, '=', key);
+    here = getdelimitstr (here, end, '&', value);
+    
+    // convert %xx and + to their appropriate equivalents
+    decode_cgi_arg (value);
+
+    value.setencoding(1); // other encoding
+    // store this key=value pair
+    if (!key.empty()) {
+
+      // if arg occurs multiple times (as is the case with multiple
+      // checkboxes using the same name) we'll create a comma separated
+      // list of all the values (this uses a hack that encodes naturally
+      // occurring commas as %2C - values will therefore need to be decoded
+      // again before use) - it should use an array instead
+      const cgiarginfo *info = argsinfo.getarginfo (key);
+      if (info != NULL && info->multiplevalue) {
+	text_t newvalue = args[key];
+	if (args.lookupcgiarg(key).source == cgiarg_t::cgi_arg) newvalue += ",";
+	newvalue += encode_commas(value);
+	args.setarg (key, newvalue, cgiarg_t::cgi_arg);
+
+      } else {
+	args.setarg (key, value, cgiarg_t::cgi_arg);
+      }
+    }
+  }
+}
+
+text_t encode_commas (const text_t &intext) {
+
+  text_t outtext;
+
+  text_t::const_iterator here = intext.begin ();
+  text_t::const_iterator end = intext.end ();
+
+  while (here != end) {
+    if (*here == ',') outtext += "%2C";
+    else outtext.push_back (*here);
+    ++here;
+  }
+  return outtext;
+}
+
+text_t decode_commas (const text_t &intext) {
+
+  text_t outtext;
+  
+  text_t::const_iterator here = intext.begin ();
+  text_t::const_iterator end = intext.end ();
+  
+  while (here != end) {
+    if ((here+2<end) && *here == '%' && *(here+1) == '2' &&
+	(*(here+2) == 'C' || *(here+2) == 'c')) {
+      here += 2;
+      outtext.push_back(',');
+      
+    }else outtext.push_back (*here);
+    ++here;
+  }
+  return outtext;
+}
+
+text_t minus_safe (const text_t &intext) {
+
+  text_t outtext;
+
+  text_t::const_iterator here = intext.begin ();
+  text_t::const_iterator end = intext.end ();
+
+  while (here != end) {
+    if (*here == '-') outtext += "Zz-";
+    else outtext.push_back (*here);
+    ++here;
+  }
+  outtext = cgi_safe (outtext);
+  return outtext;
+}
+
+text_t cgi_safe (const text_t &intext) {
+  text_t outtext;
+  
+  text_t::const_iterator here = intext.begin ();
+  text_t::const_iterator end = intext.end ();
+  unsigned short c;
+  text_t ttmp;
+  
+  while (here != end) {
+    c = *here;
+    if (((c >= 'a') && (c <= 'z')) ||
+	((c >= 'A') && (c <= 'Z')) ||
+	((c >= '0') && (c <= '9')) ||
+	(c == '+') || (c == '%') || (c == '-')) {
+      // alphanumeric character
+      outtext.push_back(c);
+    } else if (c == ' ') {
+      // space
+      outtext.push_back('+');
+    } else if (c > 255) { // unicode character
+      unsigned char buf[3]; // up to 3 bytes
+      buf[0]='\0';buf[1]='\0';buf[2]='\0';
+      output_utf8_char(c,buf, buf+2);
+      outtext.push_back('%');
+      c2hex(buf[0], ttmp);
+      outtext += ttmp;
+      outtext.push_back('%');
+      c2hex(buf[1], ttmp);
+      outtext += ttmp;
+      if (buf[2]) {
+      outtext.push_back('%');
+      c2hex(buf[2], ttmp);
+      outtext += ttmp;
+      }
+    } else {
+      // everything else
+      outtext.push_back('%');
+      c2hex(c, ttmp);
+      outtext += ttmp;
+    }
+    
+    ++here;
+  }
+  
+  return outtext;
+}
+
+
+
+
+static text_t::const_iterator get_next_save_arg (text_t::const_iterator first, 
+					   text_t::const_iterator last,
+					   text_t &argname) {
+  first = getdelimitstr (first, last, '-', argname);
+  return first;
+}
+
+
+// check_save_conf_str checks the configuration string for
+// the saved args and makes sure it does not conflict with
+// the information about the arguments. If an error is encountered
+// it will return false and the program should not produce any
+// output.
+bool check_save_conf_str (const text_t &saveconf, 
+			  const cgiargsinfoclass &argsinfo,
+			  ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  text_tset argsset;
+  text_t::const_iterator saveconfhere = saveconf.begin ();
+  text_t::const_iterator saveconfend = saveconf.end ();
+  text_t argname;
+  const cgiarginfo *info;
+
+  // first check to make sure all saved arguments can be saved
+  
+  while (saveconfhere != saveconfend) {
+    saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
+
+    if (!argname.empty()) {
+      // save the argument name for later
+      argsset.insert (argname);
+
+      // check the argument
+      info =  argsinfo.getarginfo (argname);
+      if (info == NULL) {
+	logout << text_t2ascii << "Error: the cgi argument \"" << argname 
+	       << "\" is used in the configuration string for the\n"
+	       << "saved arguments but does not exist as a valid argument.\n\n";
+	return false;
+      }
+      if (info->savedarginfo == cgiarginfo::mustnot) {
+	logout << text_t2ascii << "Error: the cgi argument \"" << argname
+	       << "\" is used in the configuration string for the\n"
+	       << "saved arguments but has been specified as an argument whose\n"
+	       << "state must not be saved.\n\n";
+	return false;
+      }
+    }
+  }
+
+
+  // next check that all saved arguments that should be saved
+  // are saved
+  cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
+  cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
+
+  while (argsinfohere != argsinfoend) {
+    if (((*argsinfohere).second.savedarginfo == cgiarginfo::must) &&
+	(argsset.find((*argsinfohere).second.shortname) == argsset.end())) {
+      logout << text_t2ascii << "Error: the cgi argument \"" 
+	     << (*argsinfohere).second.shortname << "\" was specified as needing to\n"
+	     << "be save but was not listed in the saved arguments.\n\n";
+      return false;
+    }
+
+    ++argsinfohere;
+  }
+  
+  return true; // made it, no clashes
+}
+
+
+// create_save_conf_str will create a configuration string
+// based on the information in argsinfo. This method of configuration
+// is not recomended as small changes can produce large changes in
+// the resulting configuration string (for instance a totally different
+// ordering). Only arguments which "must" be saved are included in
+// the resulting string.
+text_t create_save_conf_str (const cgiargsinfoclass &argsinfo,
+			     ostream &/*logout*/) {
+  cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
+  cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
+  text_t saveconf;
+  bool first = true;
+
+  while (argsinfohere != argsinfoend) {
+    // save this argument if it must be saved
+    if ((*argsinfohere).second.savedarginfo == cgiarginfo::must) {
+      if (!first) saveconf.push_back ('-');
+      else first = false;
+      saveconf += (*argsinfohere).second.shortname;
+    }
+
+    ++argsinfohere;
+  }
+  
+  return saveconf;
+}
+
+
+// expand_save_args will expand the saved arguments based
+// on saveconf placing the results in args if they are not
+// already defined. If it encounters an error it will return false
+// and output more information to logout.
+bool expand_save_args (const cgiargsinfoclass &argsinfo,
+		       const text_t &saveconf, 
+		       cgiargsclass &args,
+		       ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  text_t *arg_e = args.getarg("e");
+  if (arg_e == NULL) return true; // no compressed arguments
+  if (arg_e->empty()) return true; // no compressed arguments
+
+  text_t argname, argvalue;
+  const cgiarginfo *argnameinfo;
+  
+  text_t::const_iterator saveconfhere = saveconf.begin();
+  text_t::const_iterator saveconfend = saveconf.end();
+  
+  text_t::iterator arg_ehere = arg_e->begin();
+  text_t::iterator arg_eend = arg_e->end();
+  while (saveconfhere != saveconfend && arg_ehere != arg_eend) {
+    saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
+
+    if (!argname.empty()) {
+      // found another entry
+      argnameinfo = argsinfo.getarginfo (argname);
+
+      if (argnameinfo == NULL) {
+	// no information about the argument could be found
+	// we can't keep going because we don't know whether
+	// this argument is a single or multiple character value
+	logout << text_t2ascii << "Error: the cgi argument \"" << argname
+	       << "\" was specified as being a compressed argument\n"
+	       << "but no information about it could be found within the "
+	       << "cgiargsinfoclass.\n";
+	return false;
+
+      } else {
+
+	// found the argument information
+	if (argnameinfo->multiplechar) {
+	  text_t::const_iterator sav = arg_ehere;
+	  arg_ehere = getdelimitstr (arg_ehere, arg_eend, '-', argvalue);
+	  // replace any '-' chars escaped with 'Zz'
+	  bool first = true;
+	  while ((*(arg_ehere-3) == 'Z') && (*(arg_ehere-2) == 'z')) {
+	    if (first) argvalue.clear();
+	    arg_ehere = (findchar (arg_ehere, arg_eend, '-')) + 1;
+	    while (sav != (arg_ehere-1)) {
+	      if (!((*sav == 'Z') && (*(sav+1) == 'z') && (*(sav+2) == '-')) &&
+		  !((*(sav-1) == 'Z') && (*sav == 'z') && (*(sav+1) == '-'))) argvalue.push_back (*sav);
+	      ++sav;
+	    }
+	    first = false;
+	  }
+
+	  argvalue.setencoding(1); // other encoding
+	  if (!argvalue.empty()) args.setdefaultarg (argname, argvalue, cgiarg_t::compressed_arg);
+	} else {
+	  args.setdefaultcarg (argname,*arg_ehere, cgiarg_t::compressed_arg);
+	  ++arg_ehere;
+	}
+      }
+    }
+  }
+
+  return true;
+}
+
+
+// adds the default values for those arguments which have not
+// been specified
+void add_default_args (const cgiargsinfoclass &argsinfo,
+		       cgiargsclass &args,
+		       ostream &/*logout*/) {
+  cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
+  cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
+
+  while (argsinfohere != argsinfoend) {
+    if ((*argsinfohere).second.defaultstatus != cgiarginfo::none) {
+      args.setdefaultarg ((*argsinfohere).second.shortname,
+			  (*argsinfohere).second.argdefault, cgiarg_t::default_arg);
+    }
+    ++argsinfohere;
+  }
+}
+
+
+// compress_save_args will compress the arguments and return
+// them in compressed_args. If an error was encountered
+// compressed_args will be set to to "", an error will be
+// written to logout, and the function will return false.
+bool compress_save_args (const cgiargsinfoclass &argsinfo,
+			 const text_t &saveconf,
+			 cgiargsclass &args,
+			 text_t &compressed_args,
+			 outconvertclass &outconvert,
+			 ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  compressed_args.clear();
+
+  text_t argname, argvalue;
+  const cgiarginfo *argnameinfo;
+  
+  text_t::const_iterator saveconfhere = saveconf.begin();
+  text_t::const_iterator saveconfend = saveconf.end();
+  
+  while (saveconfhere != saveconfend) {
+    saveconfhere = get_next_save_arg (saveconfhere, saveconfend, argname);
+
+    if (!argname.empty()) {
+      // found another entry
+      argnameinfo = argsinfo.getarginfo (argname);
+
+      if (argnameinfo == NULL) {
+	// no information about the argument could be found
+	// we can't keep going because we don't know whether
+	// this argument is a single or multiple character value
+	logout << text_t2ascii << "Error: the cgi argument \"" << argname
+	       << "\" was specified as being a compressed argument\n"
+	       << "but no information about it could be found within the "
+	       << "cgiargsinfoclass.\n";
+	compressed_args.clear();
+	return false;
+
+      } else {
+	// found the argument information
+	if (argnameinfo->multiplechar) {
+	  // multiple character argument -- sort out any '-' chars
+	  if (args["w"]=="utf-16be") // browsers don't like \0 in urls...
+	    compressed_args += minus_safe (args[argname]);
+	  else
+	    compressed_args += minus_safe (outconvert.convert(args[argname]));
+
+	  if (saveconfhere != saveconfend) compressed_args.push_back ('-');
+
+	} else {
+	  // single character argument
+	  if (args[argname].size() == 0) {
+	    logout << text_t2ascii << "Error: the cgi argument \"" << argname
+		   << "\" was specified as being a compressed argument which\n"
+		   << "should have a one character value but it was empty.\n\n";
+	    compressed_args.clear ();
+	    return false;
+
+	  } else if (args[argname].size() > 1) {
+	    logout << text_t2ascii << "Error: the cgi argument \"" << argname
+		   << "\" was specified as being a compressed argument which\n"
+		   << "should have a one character value but it had multiple characters.\n\n";
+	    compressed_args.clear ();
+	    return false;
+	  }
+
+	  // everything is ok
+	  compressed_args += args[argname];
+	}
+      }
+    }
+  }
+
+  return true;
+}
+
+
+// args_tounicode converts any arguments which are not in unicode
+// to unicode using inconvert
+void args_tounicode (cgiargsclass &args, inconvertclass &inconvert) {
+  cgiargsclass::iterator here = args.begin();
+  cgiargsclass::iterator end = args.end();
+
+  while (here != end) {
+    if ((*here).second.value.getencoding() > 0) {
+      (*here).second.value = inconvert.convert((*here).second.value);
+    }
+    
+    ++here;
+  }
+}
+
+// fcgienv will be loaded with environment name-value pairs
+// if using fastcgi (had to do this as getenv doesn't work
+// with our implementation of fastcgi). if fcgienv is empty
+// we'll simply use getenv
+text_t gsdl_getenv (const text_t &name, text_tmap &fcgienv) {
+  if (fcgienv.empty()) {
+    char *n = name.getcstr();
+    char *v = getenv(n);
+    delete []n;
+    if (v != NULL) return v;
+    return g_EmptyText;
+
+  } else return fcgienv[name];
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiutils.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiutils.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiutils.h	(revision 10506)
@@ -0,0 +1,101 @@
+/**********************************************************************
+ *
+ * cgiutils.h -- general cgi utilities
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef CGIUTILS_H
+#define CGIUTILS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+
+
+// convert %xx and + to their appropriate equivalents
+void decode_cgi_arg (text_t &argstr);
+
+// split up the cgi arguments
+void split_cgi_args (const cgiargsinfoclass &argsinfo, text_t argstr, 
+		     cgiargsclass &args);
+
+text_t encode_commas (const text_t &intext);
+text_t decode_commas (const text_t &intext);
+
+// turns any '-' in a cgi argument into "(-)"
+text_t minus_safe (const text_t &intext);
+
+// returns the encoded version of a cgi argument
+text_t cgi_safe (const text_t &intext);
+
+// check_save_conf_str checks the configuration string for
+// the saved args and makes sure it does not conflict with
+// the information about the arguments. If an error is encountered
+// it will return false and the program should not produce any
+// output.
+bool check_save_conf_str (const text_t &saveconf, 
+			  const cgiargsinfoclass &argsinfo,
+			  ostream &logout);
+
+// create_save_conf_str will create a configuration string
+// based on the information in argsinfo. This method of configuration
+// is not recomended as small changes can produce large changes in
+// the resulting configuration string (for instance a totally different
+// ordering). Only arguments which "must" be saved are included in
+// the resulting string.
+text_t create_save_conf_str (const cgiargsinfoclass &argsinfo,
+			     ostream &logout);
+
+// expand_compress_args will expand the compressed arguments based
+// on compressconf placing the results in args if they are not
+// already defined. If it encounters an error it will return false
+// and output more information to logout.
+bool expand_save_args (const cgiargsinfoclass &argsinfo,
+		       const text_t &saveconf, 
+		       cgiargsclass &args,
+		       ostream &logout);
+
+// adds the default values for those arguments which have not
+// been specified
+void add_default_args (const cgiargsinfoclass &argsinfo,
+		       cgiargsclass &args,
+		       ostream &logout);
+
+// compress_save_args will compress the arguments and return
+// them in compressed_args. If an error was encountered
+// compressed_args will be set to to "", an error will be
+// written to logout, and the function will return false.
+bool compress_save_args (const cgiargsinfoclass &argsinfo,
+			 const text_t &saveconf,
+			 cgiargsclass &args,
+			 text_t &compressed_args,
+			 outconvertclass &outconvert,
+			 ostream &logout);
+
+// args_tounicode converts any arguments which are not in unicode
+// to unicode using inconvert
+void args_tounicode (cgiargsclass &args, inconvertclass &inconvert);
+
+text_t gsdl_getenv (const text_t &name, text_tmap &fcgienv);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiwrapper.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiwrapper.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiwrapper.cpp	(revision 10506)
@@ -0,0 +1,703 @@
+/**********************************************************************
+ *
+ * cgiwrapper.cpp -- output pages using the cgi protocol
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdlconf.h"
+#include "cgiwrapper.h"
+#include "recptconfig.h"
+#include "fileutil.h"
+#include <stdlib.h>
+#include <assert.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace/std/iostream>
+#  include <ospace/std/fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+#ifdef USE_FASTCGI
+#include "fcgiapp.h"
+#endif
+
+
+#ifdef USE_FASTCGI
+// used to output the text from receptionist
+class fcgistreambuf : public streambuf {
+public:
+  fcgistreambuf ();
+  int sync ();
+  int overflow (int ch);
+  int underflow () {return EOF;}
+  
+  void fcgisbreset() {fcgx_stream = NULL; other_ostream = NULL;};
+  void set_fcgx_stream(FCGX_Stream *newone) {fcgx_stream=newone;};
+  void set_other_ostream(ostream *newone) {other_ostream=newone;};
+  
+private:
+  FCGX_Stream *fcgx_stream;
+  ostream *other_ostream;
+};
+
+fcgistreambuf::fcgistreambuf() {
+  fcgisbreset();
+  if (base() == ebuf()) allocate();
+  setp (base(), ebuf());
+};
+
+int fcgistreambuf::sync () {
+  if ((fcgx_stream != NULL) &&
+      (FCGX_PutStr (pbase(), out_waiting(), fcgx_stream) < 0)) {
+    fcgx_stream = NULL;
+  }
+
+  if (other_ostream != NULL) {
+    char *thepbase=pbase();
+    for (int i=0;i<out_waiting();++i) (*other_ostream).put(thepbase[i]);
+  }
+  
+  setp (pbase(), epptr());
+  
+  return 0;
+}
+
+int fcgistreambuf::overflow (int ch) {
+  if (sync () == EOF) return EOF;
+  if (ch != EOF) sputc (ch);
+  return 0;
+}
+
+#endif
+
+static void format_error_string (text_t &errorpage, const text_t &errortext, bool debug) {
+
+  errorpage.clear();
+
+  if (debug) {
+    errorpage += "\n";
+    errorpage += "ERROR: " + errortext;
+    errorpage += "\n";
+    
+  } else {
+
+    errorpage += "Content-type: text/html\n\n";
+    
+    errorpage += "<html>\n";
+    errorpage += "<head>\n";
+    errorpage += "<title>Error</title>\n";
+    errorpage += "</head>\n";
+    errorpage += "<body>\n";
+    errorpage += "<h2>Oops!</h2>\n";
+    errorpage += errortext;
+    errorpage += "</body>\n";
+    errorpage += "</html>\n";
+  }
+}
+
+static void page_errorcollect (const text_t &gsdlhome, text_t &errorpage, bool debug) {
+
+  text_t collectdir = filename_cat (gsdlhome, "collect");
+
+  text_t errortext = "No valid collections were found: Check that your collect directory\n";
+  errortext += "(" + collectdir + ") is readable and contains at least one valid collection.\n";
+  errortext += "Note that modelcol is NOT a valid collection.\n";
+  errortext += "If the path to your collect directory is wrong edit the 'gsdlhome' field\n";
+  errortext += "in your gsdlsite.cfg configuration file.\n";
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+static void page_errorsitecfg (text_t &errorpage, bool debug, int mode) {
+
+  text_t errortext;
+
+  if (mode == 0) {
+    errortext += "The gsdlsite.cfg configuration file could not be found. This\n";
+    errortext += "file should contain configuration information relating to this\n";
+    errortext += "site's setup.\n";
+
+  } else if (mode == 1) {
+    errortext += "The gsdlsite.cfg configuration file does not contain a valid\n";
+    errortext += "gsdlhome entry.\n";
+  }
+
+  if (debug) {
+    errortext += "gsdlsite.cfg should reside in the directory from which the\n";
+    errortext += "library executable was run.\n";
+  } else {
+    errortext += "gsdlsite.cfg should reside in the same directory as the library\n";
+    errortext += "executable file.\n";
+  }
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+
+static void page_errormaincfg (const text_t &gsdlhome, const text_t &collection,
+			       bool debug, text_t &errorpage) {
+
+  text_t errortext;
+
+  if (collection.empty()) {
+    text_t main_cfg_file = filename_cat (gsdlhome, "etc", "main.cfg");
+    errortext += "The main.cfg configuration file could not be found. This file\n";
+    errortext += "should contain configuration information relating to the\n";
+    errortext += "setup of the interface. As this receptionist is not being run\n";
+    errortext += "in collection specific mode the file should reside at\n";
+    errortext += main_cfg_file + ".\n";
+  } else {
+    text_t collect_cfg_file = filename_cat (gsdlhome, "collect", collection, "etc", "collect.cfg");
+    text_t main_collect_cfg_file = filename_cat (gsdlhome, "etc", "collect.cfg");
+    text_t main_cfg_file = filename_cat (gsdlhome, "etc", "main.cfg");
+    errortext += "Either the collect.cfg or main.cfg configuration file could\n";
+    errortext += "not be found. This file should contain configuration information\n";
+    errortext += "relating to the setup of the interface. As this receptionist is\n";
+    errortext += "being run in collection specific mode the file should reside\n";
+    errortext += "at either " + collect_cfg_file + ",\n";
+    errortext += main_collect_cfg_file + " or " + main_cfg_file + ".\n";
+  }
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+
+static void page_errorinit (const text_t &gsdlhome, bool debug, text_t &errorpage) {
+
+  text_t errortext = "An error occurred during the initialisation of the Greenstone Digital\n";
+  errortext += "Library software. It is likely that the software has not been setup\n";
+  errortext += "correctly.\n";
+
+  text_t error_file = filename_cat (gsdlhome, "etc", "error.txt");
+  char *efile = error_file.getcstr();
+  ifstream errin (efile);
+  delete []efile;
+  if (errin) {
+    errortext += "The error log, " + error_file + ", contains the\n";
+    errortext += "following information:\n\n";
+    if (!debug) errortext += "<pre>\n";
+
+    char c;
+    errin.get(c);
+    while (!errin.eof ()) {
+      errortext.push_back(c);
+      errin.get(c);
+    }
+    
+    if (!debug) errortext += "</pre>\n";
+
+    errin.close();
+
+  } else {
+    errortext += "Please consult " + error_file + " for more information.\n";
+  }
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+static void page_errorparseargs (const text_t &gsdlhome, bool debug, text_t &errorpage) {
+
+  text_t errortext = "An error occurred during the parsing of the cgi arguments.\n";
+
+  text_t error_file = filename_cat (gsdlhome, "etc", "error.txt");
+  char *efile = error_file.getcstr();
+  ifstream errin (efile);
+  delete []efile;
+  if (errin) {
+    errortext += "The error log, " + error_file + ", contains the\n";
+    errortext += "following information:\n\n";
+    if (!debug) errortext += "<pre>\n";
+
+    char c;
+    errin.get(c);
+    while (!errin.eof ()) {
+      errortext.push_back(c);
+      errin.get(c);
+    }
+    if (!debug) errortext += "</pre>\n";
+    errin.close();
+
+  } else {
+    errortext += "Please consult " + error_file + " for more information.\n";
+  }
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+static void page_errorcgipage (const text_t &gsdlhome, bool debug, text_t &errorpage) {
+
+  text_t errortext = "An error occurred during the construction of the cgi page.\n";
+
+  text_t error_file = filename_cat (gsdlhome, "etc", "error.txt");
+  char *efile = error_file.getcstr();
+  ifstream errin (efile);
+  delete []efile;
+  if (errin) {
+    errortext += "The error log, " + error_file + ", contains the\n";
+    errortext += "following information:\n\n";
+    if (!debug) errortext += "<pre>\n";
+
+    char c;
+    errin.get(c);
+    while (!errin.eof ()) {
+      errortext.push_back(c);
+      errin.get(c);
+    }
+    if (!debug) errortext += "</pre>\n";
+    errin.close();
+
+  } else {
+    errortext += "Please consult " + error_file + " for more information.\n";
+  }
+
+  format_error_string (errorpage, errortext, debug);
+}
+
+static void print_debug_info (receptionist &recpt) {
+
+  outconvertclass text_t2ascii;
+  const recptconf &configinfo = recpt.get_configinfo ();
+  text_t etc_dir = filename_cat (configinfo.gsdlhome, "etc");
+
+  cout << "\n";
+  cout << text_t2ascii
+       << "------------------------------------------------------------\n"
+       << "Configuration and initialization completed successfully.\n"
+       << "  Note that more debug information may be available in the\n"
+       << "  initialization and error log error.txt in " << etc_dir << ".\n"
+       << "------------------------------------------------------------\n\n";
+
+  bool colspec = false;
+  if (configinfo.collection.empty()) {
+    cout << "Receptionist is running in \"general\" (i.e. not \"collection\n"
+	 << "specific\") mode.\n";
+  } else {
+    cout << text_t2ascii 
+	 << "Receptionist is running in \"collection specific\" mode.\n"
+	 << "  collection=" << configinfo.collection << "\n"
+	 << "  collection directory=" << configinfo.collectdir << "\n";
+    colspec = true;
+  }
+  
+  cout << text_t2ascii << "gsdlhome=" << configinfo.gsdlhome << "\n";
+  if (!configinfo.gdbmhome.empty())
+    cout << text_t2ascii << "gdbmhome=" << configinfo.gdbmhome << "\n";
+  cout << text_t2ascii << "httpprefix=" << configinfo.httpprefix << "\n";
+  cout << text_t2ascii << "httpimg=" << configinfo.httpimg << "\n";
+  cout << text_t2ascii << "gwcgi=" << configinfo.gwcgi << "\n"
+       << "  Note that unless gwcgi has been set from a configuration\n"
+       << "  file it is dependent on environment variables set by your\n"
+       << "  webserver. Therefore it may not have the same value when run\n"
+       << "  from the command line as it would be when run from your\n"
+       << "  web server.\n";
+  if (configinfo.usecookies) 
+    cout << "cookies are enabled\n";
+  else 
+    cout << "cookies are disabled\n";
+  if (configinfo.logcgiargs) 
+    cout << "logging is enabled\n";
+  else 
+    cout << "logging is disabled\n";
+  cout << "------------------------------------------------------------\n\n";
+
+  text_tset::const_iterator this_mfile = configinfo.macrofiles.begin();
+  text_tset::const_iterator end_mfile = configinfo.macrofiles.end();
+  cout << "Macro Files:\n"
+       << "------------\n";
+  text_t mfile;
+  bool found;
+  while (this_mfile != end_mfile) {
+    cout << text_t2ascii << *this_mfile;
+    int spaces = (22 - (*this_mfile).size());
+    if (spaces < 2) spaces = 2;
+    text_t outspaces;
+    for (int i = 0; i < spaces; ++i) outspaces.push_back (' ');
+    cout << text_t2ascii << outspaces;
+
+    found = false;
+    if (colspec) {
+      // collection specific - try collectdir/macros first
+      mfile = filename_cat (configinfo.collectdir, "macros", *this_mfile);
+      if (file_exists (mfile)) {
+	cout << text_t2ascii << "found (" << mfile << ")\n";
+	found = true;
+      }
+    }
+ 
+    if (!found) {
+      // try main macro directory
+      mfile = filename_cat (configinfo.gsdlhome, "macros", *this_mfile);
+      if (file_exists (mfile)) {
+	cout << text_t2ascii << "found (" << mfile << ")\n";
+	found = true;
+      }
+    }
+
+    if (!found)
+      cout << text_t2ascii << "NOT FOUND\n";
+
+    ++this_mfile;
+  }
+
+  cout << "------------------------------------------------------------\n\n"
+       << "Collections:\n"
+       << "------------\n"
+       << "  Note that collections will only appear as \"running\" if\n"
+       << "  their build.cfg files exist, are readable, contain a valid\n"
+       << "  builddate field (i.e. > 0), and are in the collection's\n"
+       << "  index directory (i.e. NOT the building directory)\n\n";
+
+  recptprotolistclass *protos = recpt.get_recptprotolist_ptr();
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+
+  bool is_z3950 = false;
+  bool found_valid_col = false;
+
+
+  while (rprotolist_here != rprotolist_end) {
+    comerror_t err;    
+    if ((*rprotolist_here).p == NULL) continue;
+    else if (is_z3950==false &&
+	     (*rprotolist_here).p->get_protocol_name(err) == "z3950proto") {
+      cout << "\nZ39.50 Servers:   (always public)\n"
+	   << "---------------\n";
+      is_z3950=true;
+    }
+
+    text_tarray collist;
+    (*rprotolist_here).p->get_collection_list (collist, err, cerr);
+    if (err == noError) {
+      text_tarray::iterator collist_here = collist.begin();
+      text_tarray::iterator collist_end = collist.end();
+      
+      while (collist_here != collist_end) {
+	
+	cout << text_t2ascii << *collist_here;
+	
+	int spaces = (22 - (*collist_here).size());
+	if (spaces < 2) spaces = 2;
+	text_t outspaces;
+	for (int i = 0; i < spaces; ++i) outspaces.push_back (' ');
+	cout << text_t2ascii << outspaces;
+	
+	  ColInfoResponse_t *cinfo = recpt.get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, cerr);
+	  if (cinfo != NULL) {
+	    if (cinfo->isPublic) cout << "public ";
+	    else cout << "private";
+
+	    if (cinfo->buildDate > 0) {
+	      cout << "   running    ";
+	      found_valid_col = true;
+	    } else {
+	      cout << "   not running";
+	    }
+	  }
+
+	  cout << "\n";
+
+	  ++collist_here;
+      }
+    }
+    is_z3950=false;
+    ++rprotolist_here;
+  } // end of while loop
+
+  if (!found_valid_col) {
+    cout << "WARNING: No \"running\" collections were found. You need to\n";
+    cout << "         build one of the above collections\n";
+  }
+
+  cout << "\n------------------------------------------------------------\n";
+  cout << "------------------------------------------------------------\n\n";
+  cout << "receptionist running in command line debug mode\n";
+  cout << "enter cgi arguments as name=value pairs (e.g. 'a=p&p=home'):\n";
+
+}
+
+// cgiwrapper does everything necessary to output a page
+// using the cgi protocol. If this is being run for a particular
+// collection then "collection" should be set, otherwise it
+// should equal "".
+void cgiwrapper (receptionist &recpt, text_t collection) {
+  
+  int numrequests = 0;
+  bool debug = false;
+  const recptconf &configinfo = recpt.get_configinfo ();
+
+  // find out whether this is being run as a cgi-script
+  // or a fastcgi script
+#ifdef USE_FASTCGI
+  fcgistreambuf outbuf;
+  int isfastcgi = !FCGX_IsCGI();
+  FCGX_Stream *fcgiin, *fcgiout, *fcgierr;
+  FCGX_ParamArray fcgienvp;
+#else
+  int isfastcgi = 0;
+#endif
+
+  // get the query string if it is not being run as a fastcgi
+  // script
+  text_t argstr = g_EmptyText;
+  cgiargsclass args;
+  char *aURIStr;
+  if (!isfastcgi) {
+    char *request_method_str = getenv("REQUEST_METHOD");
+    char *content_length_str = getenv("CONTENT_LENGTH");
+    if (request_method_str != NULL && strcmp(request_method_str, "POST") == 0 &&
+	content_length_str != NULL)  {
+      // POST form data
+      int content_length = text_t(content_length_str).getint();
+      if (content_length > 0) {
+	char c;
+	do {
+	  cin.get(c);
+	  if (cin.eof()) break;
+	  argstr.push_back (c);
+	  --content_length;
+	} while (content_length > 0);
+      }
+      
+    } else {
+      aURIStr = getenv("QUERY_STRING");
+      if ((request_method_str != NULL && strcmp(request_method_str, "GET") == 0)
+	  || aURIStr != NULL) {
+	// GET form data
+	if (aURIStr != NULL) argstr = aURIStr;
+      } else {
+	// debugging from command line
+	debug = true;
+      }
+    }
+  }
+
+  if (debug) {
+    cout << "Configuring Greenstone...\n";
+    cout << flush;
+  }
+
+  // init stuff - we can't output error pages directly with
+  // fastcgi so the pages are stored until we can output them
+  text_t errorpage;
+  outconvertclass text_t2ascii;
+
+  // set defaults
+  int maxrequests = 10000;
+  recpt.configure ("collection", collection);
+  recpt.configure ("httpimg", "/gsdl/images");
+  char *script_name = getenv("SCRIPT_NAME");
+  if (script_name != NULL) recpt.configure("gwcgi", script_name);
+  else recpt.configure("gwcgi", "/gsdl");
+
+  // read in the configuration files.
+  text_t gsdlhome;
+  if (!site_cfg_read (recpt, gsdlhome, maxrequests)) {
+    // couldn't find the site configuration file
+    page_errorsitecfg (errorpage, debug, 0);
+  } else if (gsdlhome.empty()) {
+    // no gsdlhome in gsdlsite.cfg
+    page_errorsitecfg (errorpage, debug, 1);
+  } else if (!directory_exists(gsdlhome)) {
+    // gsdlhome not a valid directory
+    page_errorsitecfg (errorpage, debug, 1);
+  } else if (!main_cfg_read (recpt, gsdlhome, collection)) {
+    // couldn't find the main configuration file
+    page_errormaincfg (gsdlhome, collection, debug, errorpage);
+  } else  if (configinfo.collectinfo.empty() && false) { // commented out for corba
+    // don't have any collections
+    page_errorcollect (gsdlhome, errorpage, debug);
+  }
+
+  if (errorpage.empty()) {
+
+    // initialise the library software
+    if (debug) {
+      cout << "Initializing...\n";
+      cout << flush;
+    }
+
+    text_t error_file = filename_cat (gsdlhome, "etc", "error.txt");
+    char *eout = error_file.getcstr();
+    ofstream errout (eout, ios::app);
+    delete []eout;
+    if (!recpt.init(errout)) {
+      // an error occurred during the initialisation
+      errout.close();
+      page_errorinit(gsdlhome, debug, errorpage);
+    }
+    errout.close();
+  }
+
+  if (debug && errorpage.empty()) {
+    // get query string from command line
+    print_debug_info (recpt);
+    char cinURIStr[1024];
+    cin.get(cinURIStr, 1024);
+    argstr = cinURIStr;
+  }
+
+  // cgi scripts only deal with one request
+  if (!isfastcgi) maxrequests = 1;
+
+  // Page-request loop. If this is not being run as a fastcgi
+  // process then only one request will be processed and then
+  // the process will exit.
+  while (numrequests < maxrequests) {
+#ifdef USE_FASTCGI
+    if (isfastcgi) {
+      if (FCGX_Accept(&fcgiin, &fcgiout, &fcgierr, &fcgienvp) < 0) break;
+
+      char *request_method_str = FCGX_GetParam ("REQUEST_METHOD", fcgienvp);
+      char *content_length_str = FCGX_GetParam ("CONTENT_LENGTH", fcgienvp);
+
+      if (request_method_str != NULL && strcmp(request_method_str, "POST") == 0 &&
+	  content_length_str != NULL)  {
+	// POST form data
+	int content_length = text_t(content_length_str).getint();
+	if (content_length > 0) {
+	  argstr.clear();
+	  int c;
+	  do {
+	    c = FCGX_GetChar (fcgiin);
+	    if (c < 0) break;
+	    argstr.push_back (c);
+	    --content_length;
+	  } while (content_length > 0);
+	}
+
+      } else {
+	// GET form data
+	aURIStr = FCGX_GetParam("QUERY_STRING", fcgienvp);
+	if (aURIStr != NULL) argstr = aURIStr;
+	else argstr = g_EmptyText;
+      }
+    }
+#endif
+
+    // get output streams ready
+#ifdef USE_FASTCGI
+    outbuf.fcgisbreset ();
+    if (isfastcgi) outbuf.set_fcgx_stream (fcgiout);
+    else outbuf.set_other_ostream (&cout);
+    ostream pageout (&outbuf);
+#else
+#define pageout cout
+#endif
+
+    // if using fastcgi we'll load environment into a map,
+    // otherwise simply pass empty map (can't get environment
+    // variables using getenv() while using FCGX versions
+    // of fastcgi - at least I can't ;-) - Stefan)
+    text_tmap fastcgienv;
+#ifdef USE_FASTCGI
+    if (isfastcgi) {
+      for(; *fcgienvp != NULL; ++fcgienvp) {
+	text_t fvalue = *fcgienvp;
+	text_t::const_iterator begin = fvalue.begin();
+	text_t::const_iterator end = fvalue.end();
+	text_t::const_iterator equals_sign = findchar (begin, end, '=');
+	if (equals_sign != end)
+	  fastcgienv[substr(begin, equals_sign)] = substr(equals_sign+1, end);
+      }
+    }
+#endif
+
+    // temporarily need to configure gwcgi here when using fastcgi as I can't
+    // get it to pass the SCRIPT_NAME environment variable to the initial 
+    // environment (if anyone can work out how to do this using the apache 
+    // server, let me know). Note that this overrides the gwcgi field in 
+    // site.cfg (which it shouldn't do) but I can't at present set gwcgi 
+    // from site.cfg as I have old receptionists laying around that wouldn't
+    // appreciate it. The following 5 lines of code should be deleted once
+    // I either a: get the server to pass SCRIPT_NAME at initialization
+    // time or b: convert all the collections using old receptionists over
+    // to this version and uncomment gwcgi in the site.cfg file -- Stefan.
+#ifdef USE_FASTCGI
+    if (isfastcgi) {
+      recpt.configure("gwcgi", fastcgienv["SCRIPT_NAME"]);
+    }
+#endif
+
+
+    // if there has been no error so far, perform the production of the
+    // output page
+    if (errorpage.empty()) {
+      text_t error_file = filename_cat (gsdlhome, "etc", "error.txt");
+      char *eout = error_file.getcstr();
+      ofstream errout (eout, ios::app);
+      delete []eout;
+
+#if defined(__WIN32__) && defined(GSDL_USE_IOS_H)
+      // old Windows compilers (VC++4.2)
+      cerr = errout;
+#else
+      // can't do this anymore according to c++ standard...
+      // cerr = errout;
+      // ... but can do this instead
+      streambuf* errbuf = cerr.rdbuf(errout.rdbuf());
+#endif
+
+      // parse the cgi arguments and produce the resulting page if there
+      // has been no errors so far
+      if (!recpt.parse_cgi_args (argstr, args, errout, fastcgienv)) {
+	errout.close ();
+	page_errorparseargs(gsdlhome, debug, errorpage);
+      } else {
+	// produce the output page
+
+	if (!recpt.produce_cgi_page (args, pageout, errout, fastcgienv)) {
+	  errout.close ();
+	  page_errorcgipage(gsdlhome, debug, errorpage);
+	}
+	recpt.log_cgi_args (args, errout, fastcgienv);
+	errout.close ();
+      }
+
+#if !defined(__WIN32__) || !defined(GSDL_USE_IOS_H)
+    // restore the cerr buffer
+    cerr.rdbuf(errbuf);
+#endif
+    }
+
+    // there was an error, output the error page
+    if (!errorpage.empty()) {
+      pageout << text_t2ascii << errorpage;
+      errorpage.clear();
+      numrequests = maxrequests; // make this the last page
+    }
+    pageout << flush;
+    
+    // finish with the output streams
+#ifdef USE_FASTCGI
+    if (isfastcgi) FCGX_Finish();
+#endif
+
+    ++numrequests;
+  }
+
+  return;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiwrapper.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiwrapper.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/cgiwrapper.h	(revision 10506)
@@ -0,0 +1,45 @@
+/**********************************************************************
+ *
+ * cgiwrapper.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef CGIWRAPPER_H
+#define CGIWRAPPER_H
+
+
+#include "receptionist.h"
+#include "collectset.h"
+
+// cgiwrapper does everything necessary to output a page
+// using the cgi protocol. If this is being run for a particular
+// collection then "collection" should be set, otherwise it
+// should equal "".
+//
+// NB: the collectset MAY NOT exist for remote protocols (e.g.
+//     the corba protocol; as references must point to a non-
+//     null instance, we must therefore use a pointer - sorry!
+void cgiwrapper (receptionist &recpt, text_t collection);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/collectoraction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/collectoraction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/collectoraction.cpp	(revision 10506)
@@ -0,0 +1,1975 @@
+/**********************************************************************
+ *
+ * collectoraction.cpp -- 
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_COLLECTOR_ACTION
+
+// note that the collectoraction relies on having direct access to a
+// collections configuration file. this breaks the separation between
+// receptionist and collection server and so is not suitable (at least
+// in its current form) for use when collection servers are separate 
+// from the receptionist (e.g. when using the CORBA protocol).
+
+// following line required to get fstream.filedesc() on darwin (Mac OS X)
+#define _STREAM_COMPAT  1
+// required for utsname on solaris???
+#define _XOPEN_SOURCE 1
+#define _XOPEN_SOURCE_EXTENDED 1
+
+#include "collectoraction.h"
+#include "OIDtools.h"
+#include "fileutil.h"
+#include "cfgread.h"
+#include "gsdltools.h"
+#include "gsdltimes.h"
+#include "nullproto.h"
+#include "argdb.h"
+#include "cgiutils.h"
+#include <stdio.h>
+#include <fcntl.h>
+
+#if !defined (__WIN32__)
+#include <sys/utsname.h>
+#include <unistd.h>
+#endif
+
+collectoraction::collectoraction () {
+
+  recpt = NULL;
+  disabled = true;
+  do_mkcol = false;
+  badsources = false;
+  failedsources.erase(failedsources.begin(), failedsources.end());
+  gsdlosc = NULL;
+  gsdlhomec = NULL;
+  pathc = NULL;
+
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "collector";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "p";
+  arg_ainfo.longname = "page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "intro";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // temporary directory name for this collector
+  // session
+  arg_ainfo.shortname = "bc1tmp";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bc1fullname";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bc1dirname";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bc1contactemail";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bc1aboutdesc";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bc1clone";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bc1clonecol";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // set when cloning option has changed
+  arg_ainfo.shortname = "bc1clonechanged";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot; 
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // only set when one of the fields was changed in
+  // the "collection info" page
+  arg_ainfo.shortname = "bc1infochanged";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // only set when cfg file is altered from within
+  // "configure collection" page
+  arg_ainfo.shortname = "bc1cfgchanged";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "cfgfile";
+  arg_ainfo.longname = "configuration file contents";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bc1dodelete";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // will be set if we arrived at the "configure collection" page
+  // via the "changing an existing collection" page
+  arg_ainfo.shortname = "bc1econf";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // will be set if we arrived at the "source data" page
+  // via the "changing an existing collection" page
+  arg_ainfo.shortname = "bc1esrce";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bc1inputnum";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "3";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bc1input";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.multiplevalue = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bc1inputtype";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.multiplevalue = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot; // saved on disk
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // will be set when we've just come from the "source data" page
+  arg_ainfo.shortname = "bc1fromsrce";
+  arg_ainfo.longname = "collector specific";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.multiplevalue = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+collectoraction::~collectoraction () {
+  if (gsdlosc != NULL) delete []gsdlosc;
+  if (gsdlhomec != NULL) delete []gsdlhomec;
+  if (pathc != NULL) delete []pathc;
+}
+
+
+void collectoraction::configure (const text_t &key, const text_tarray &cfgline) {
+  if ((key == "collector") && (cfgline.size() == 1) && 
+      (cfgline[0] == "true" || cfgline[0] == "on" || cfgline[0] == "enabled")) {
+    disabled = false;
+  } else {
+    // call the parent class to deal with the things which
+    // are not dealt with here
+    action::configure (key, cfgline);
+  }
+}
+
+
+bool collectoraction::init (ostream & /*logout*/) {
+
+  // set up GSDLOS, GSDLHOME and PATH environment variables
+  text_t gsdlos, path;
+  unsigned int path_separator = ':';
+#if defined (__WIN32__)
+  gsdlos = "windows";
+  path_separator = ';';
+
+  path = filename_cat (gsdlhome, "bin", "windows", "perl", "bin;");
+
+#else
+  struct utsname *buf = new struct utsname();
+  int i = uname (buf);
+  if (i == -1) gsdlos = "linux"; // uname failed
+  else gsdlos.setcstr (buf->sysname);
+  delete buf;
+  lc (gsdlos);
+#endif
+
+  pathc = getenv ("PATH");
+  path += filename_cat (gsdlhome, "bin", gsdlos);
+  path.push_back (path_separator);
+  path += filename_cat (gsdlhome, "bin", "script");
+  if (pathc != NULL) {
+    path.push_back (path_separator);
+    path += pathc;
+  }
+  path = "PATH=" + path;
+
+  gsdlos = "GSDLOS=" + gsdlos;
+  text_t setgsdlhome = "GSDLHOME=" + gsdlhome;
+
+  // these will be cleaned up in the destructor
+  gsdlosc = gsdlos.getcstr();
+  gsdlhomec = setgsdlhome.getcstr();
+  pathc = path.getcstr();
+  
+  putenv (gsdlosc);
+  putenv (gsdlhomec);
+  putenv (pathc);
+
+  return true;
+}
+
+bool collectoraction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+				     recptprotolistclass * /*protos*/, ostream &logout) {
+
+  text_t &current_page = args["p"];
+
+  // note that the "bildstatus" and "bildframe1" pages don't actually do anything
+  // functional so we don't need to worry about authenticating them (it's the 
+  // underlying "bild" page that does the building (and creates the frameset))
+  // This helps us overcome a bit of a problem we have with multiple pages trying
+  // to read from the key.db database at the same time.
+  if (current_page != "intro" && current_page != "bildstatus" && current_page != "bildframe1") {
+    // authenticate the user if authentication is available
+    args["uan"] = 1;
+    args["ug"] = "colbuilder";
+  }
+  
+  if (current_page == "new" || current_page == "existing") {
+
+    // assign (and create) a temporary directory 
+    if (assign_tmpname (args, logout)==false) {
+      // there was an error creating the tmp dir
+      message="tmpfail";
+      return true; // true because we could still parse the arguments
+    }
+
+    // clean up any old builds left laying about in the tmp directory
+    // (note that it's possible this could take some time if there's a huge
+    // partially built collection laying about so we'll make it an asynchronous
+    // system call)
+    gsdl_system ("perl -S cleantmp.pl", false, logout);
+  }
+
+  if (current_page != "intro" && current_page != "bildstatus" && 
+      current_page != "bildframe1" && current_page != "new") {
+    // update arguments that were saved to the harddrive
+    text_tmap saved_args;
+    saved_args["bc1fullname"] = g_EmptyText;
+    saved_args["bc1contactemail"] = g_EmptyText;
+    saved_args["bc1aboutdesc"] = g_EmptyText;
+    saved_args["bc1clone"] = g_EmptyText;
+    saved_args["bc1clonecol"] = g_EmptyText;
+    saved_args["bc1inputnum"] = g_EmptyText;
+    saved_args["bc1input"] = g_EmptyText;
+    saved_args["bc1inputtype"] = g_EmptyText;
+
+    // update the argdb database with any arguments that were set
+    // by previous page
+    text_tmap::iterator here = saved_args.begin();
+    text_tmap::iterator end = saved_args.end();
+    while (here != end) {
+      if (args.lookupcgiarg((*here).first).source != cgiarg_t::default_arg) {
+	(*here).second = args[(*here).first];
+      }
+      ++here;
+    }
+
+    text_t argfile = filename_cat(gsdlhome, "tmp", args["bc1tmp"], "argdb.db");
+    argdb *args_on_disk = new argdb(argfile);
+    if (!args_on_disk->update_args(saved_args)) {
+      // error
+      logout << "collectoraction: argdb::update_args failed (" << argfile << ")\n";
+    }
+
+    // update args from argdb
+    saved_args.erase(saved_args.begin(), saved_args.end());
+    if (!args_on_disk->get_args(saved_args)) {
+      // error
+      logout << "collectoraction: argdb::get_args failed (" << argfile << ")\n";
+    }
+    delete args_on_disk;
+    here = saved_args.begin();
+    end = saved_args.end();
+    while (here != end) {
+      if (!(*here).second.empty()) {
+	args[(*here).first] = (*here).second;
+      }
+      ++here;
+    }
+  }
+
+  if (args["bc1infochanged"] == "1") {
+    
+    if (args["bc1dirname"].empty()) {
+      // we've just come from the "collection information" page for the 
+      // first time so we'll need to create the collection with mkcol.pl
+      // and set up bc1dirname - we do this part here instead of in do_action
+      // because the bc1dirname argument must be set to its new value before
+      // the compressedoptions macros are set.
+      args["bc1dirname"] = get_directory_name (args["bc1fullname"]);
+
+      text_t createfile = filename_cat (gsdlhome, "tmp", args["bc1tmp"], ".create");
+      if (!file_exists (createfile)) {
+	// we could do the mkcol.pl here but I guess it's nicer to do it in do_action()
+	do_mkcol = true; 
+      } else {
+	// .create file already exists but bc1dirname wasn't set ... this should only be
+	// able to occur when the "reload" (and possibly the "back" and "forward" buttons)
+	// have been used to get us here.
+	// we'll check that the bc1dirname directory exists (in case of the unlikely 
+	// possibility that get_directory_name returned a different value this time
+	// than it did originally).
+	text_t coldir = filename_cat (get_collectdir(args), args["bc1dirname"]);
+	if (!directory_exists (coldir)) {
+	  message = "reloaderror";
+	  return true;
+	}
+      }
+    } else {
+      // "collection information" has been changed after collection already exists
+      // so we'll need to update the cfg file.
+      update_cfgfile_partial (args, false, logout);
+    }
+  }
+
+  if (args["bc1cfgchanged"] == "1") {
+    // configuration file has been changed from the "configure collection"
+    // page. we need to update the file on disk and catch bc1 arguments up
+    // with changes.
+    update_cfgfile_complete (args, logout);
+  }
+  
+  if (args["bc1clonechanged"] == "1") {
+    // cloning option has been changed on "source data" page. if it was turned 
+    // on we want to create a new collect.cfg file using the bc1clonecol cfg file
+    // as a model (we'll save the old file as collect.cfg.org). if cloning was
+    // turned off we'll revert to using the collect.cfg.org file (which will need
+    // updating in case the bc1 arguments have been altered since cloning was 
+    // turned on).
+    update_cfgfile_clone (args, logout);
+
+    // if cloning has just been turned on we'll also copy the rest of the files 
+    // (excluding collect.cfg which we've already done) from the cloned collections
+    // etc directory to the new collection.
+    if (args["bc1clone"] == "1") {
+      text_t clone_etc = filename_cat(gsdlhome, "collect", args["bc1clonecol"], "etc");
+      text_t new_etc = filename_cat(get_collectdir(args), args["bc1dirname"], "etc");
+      text_tarray files;
+
+      if (read_dir (clone_etc, files)) {
+	text_tarray::const_iterator here = files.begin();
+	text_tarray::const_iterator end = files.end();
+	while (here != end) {
+	  if (*here != "collect.cfg" && *here != "collect.cfg.org") {
+	    file_copy (filename_cat(clone_etc, *here), filename_cat(new_etc, *here));
+	  }
+	  ++here;
+	}
+      } else {
+	outconvertclass text_t2ascii;
+	logout <<text_t2ascii << "collectoraction::check_cgiargs couldn't read from " 
+	       << clone_etc << " directory\n";
+      }
+    }
+  }
+  
+  if (current_page == "bildstatus" || current_page == "bildcancel") {
+    // if .final file exists then build has finished
+    text_t fbld = filename_cat (gsdlhome, "tmp", args["bc1tmp"], args["bc1dirname"] + ".bld.final");
+    if (file_exists (fbld)) {
+      char *fbldc = fbld.getcstr();
+      ifstream fbld_in (fbldc);
+      if (fbld_in) {
+	failcode = fbld_in.get();
+	fbld_in.close();
+	if (failcode == '0') {
+	  // success - we need to create and configure a collection server for the
+	  // newly built collection (for fastcgi and local library where
+	  // initialization isn't going to be redone when the user clicks the
+	  // "view your new collection" button
+	  create_colserver (args["bc1dirname"], logout);
+	  current_page = "bilddone";
+	}
+	else current_page = "bildfail";
+      } else {
+	// assume build failed (we shouldn't get here though ... right?)
+	current_page = "bildfail";
+      }
+      delete []fbldc;
+    }
+  }
+
+  if (args["bc1fromsrce"] == "1") {
+
+    // we've just come from the "source data" page so we need to check that
+    // input sources are valid
+    if (!check_sources(args, logout)) {
+      args["p"] = "srce";
+    }
+  }
+
+  return true;
+}
+
+void collectoraction::update_cfgfile_clone (cgiargsclass &args, ostream &logout) {
+
+  text_t tmpdir = filename_cat(gsdlhome, "tmp", args["bc1tmp"]);
+  text_t cfgfile = filename_cat(tmpdir, args["bc1dirname"], "etc", "collect.cfg");
+  if (!file_exists (cfgfile)) {
+    message = "tmpfail";
+    return;
+  }
+
+  text_t cfgfile_org = filename_cat (tmpdir, "collect.cfg.org");
+
+  if (args["bc1clone"] == "1") {
+    // cloning was turned on
+
+    text_t cfgfile_clone = filename_cat(gsdlhome, "collect", args["bc1clonecol"], "etc", "collect.cfg");
+    if (file_exists (cfgfile_clone)) {
+      // if .org file doesn't exist already create it
+      if (!file_exists (cfgfile_org)) {
+	if (!file_copy (cfgfile, cfgfile_org)) {
+	  message = "tmpfail";
+	  return;
+	}
+      }
+      // copy clone collections cfg file to new collection
+      if (!file_copy (cfgfile_clone, cfgfile)) {
+	message = "tmpfail";
+	return;
+      }
+      // update the new cfg file
+      update_cfgfile_partial (args, true, logout);
+      
+    } else {
+      // can't clone non-existant or read-protected collection
+      message = "clonefail";
+    }
+
+  } else {
+    // cloning has been turned off having been on at some point. the .org file
+    // should exist, if it doesn't we'll bail out and leave the user with the 
+    // cloned copy
+    if (file_exists (cfgfile_org)) {
+      // copy original back again and update it with any recent changes
+      if (file_copy (cfgfile_org, cfgfile)) {
+	update_cfgfile_partial (args, false, logout);
+      } else {
+	message = "tmpfail";
+      }
+    }
+  }
+}
+
+// update configuration file on disk to match bc1 arguments
+// there's a special case if the clone option is true as certain parts of a
+// config file should not be cloned (e.g. the iconcollection stuff)
+void collectoraction::update_cfgfile_partial (cgiargsclass &args, bool clone, ostream &logout) {
+
+  text_t cfgfile = filename_cat(get_collectdir(args), args["bc1dirname"], "etc", "collect.cfg");
+  char *cfgfilec = cfgfile.getcstr();
+
+#if defined (__WIN32__)
+  // make sure collect.cfg isn't read-only
+  _chmod (cfgfilec, _S_IREAD | _S_IWRITE);
+#endif
+
+  vector<text_tarray> cfgarray;
+
+  // read in cfg file
+  ifstream cfg_in (cfgfilec);
+  if (cfg_in) {
+    text_tarray cfgline;
+    while (read_cfg_line(cfg_in, cfgline) >= 0) {
+      if (cfgline.size () >= 2) {
+	if (cfgline[0] == "creator" || cfgline[0] == "maintainer") {
+	  cfgline[1] = args["bc1contactemail"];
+	} else if (cfgline[0] == "collectionmeta") {
+	  if (cfgline[1] == "collectionname") {
+	    cfgline[2] = args["bc1fullname"];
+	  } else if (cfgline[1] == "collectionextra") {
+	    cfgline[2] = carriage_replace (args["bc1aboutdesc"], 0);
+	  } else if (clone && (cfgline[1] == "iconcollection" ||
+			       cfgline[1] == "iconcollectionsmall")) {
+	    cfgline[2] = g_EmptyText;
+	  }
+	}
+      }
+      cfgarray.push_back (cfgline);
+    }
+    cfg_in.close();
+    
+    // now write cfg file back out
+    int fd=open(cfgfilec, O_WRONLY | O_CREAT | O_TRUNC
+#if defined(__WIN32__)
+		| O_BINARY
+#endif
+		);
+
+    if (fd != -1) {
+      // lock the file
+      int lock_val = 1;
+      GSDL_LOCK_FILE (fd);
+      if (lock_val != 0) {
+	logout << "Error: Couldn't lock file " << cfgfilec << "\n";
+	close(fd);
+	message = "tmpfail";
+	
+      } else {
+
+	vector<text_tarray>::const_iterator this_line = cfgarray.begin();
+	vector<text_tarray>::const_iterator end_line = cfgarray.end();
+	while (this_line != end_line) {
+	  write_cfg_line (fd, *this_line);
+	  ++this_line;
+	}
+	GSDL_UNLOCK_FILE (fd);
+	close(fd);
+      }
+
+    } else {
+      logout << "collectoraction::update_cfgfile_partial: unable to open "
+	     << cfgfilec << " for output\n";
+      message = "tmpfail";
+    }
+    
+  } else {
+    logout << "collectoraction::update_cfgfile_partial: unable to open "
+	   << cfgfilec << " for input\n";
+    message = "tmpfail";
+  }
+
+  delete []cfgfilec;
+}
+
+// replace configuration file on disk with that in the cfgfile argument and 
+// catch other bc1 arguments up with those the new cfgfile contains
+void collectoraction::update_cfgfile_complete (cgiargsclass &args, ostream &logout) {
+
+  text_t cfgfile = filename_cat(get_collectdir(args), args["bc1dirname"], "etc", "collect.cfg");
+  char *cfgfilec = cfgfile.getcstr();
+
+#ifdef __WIN32__
+  // make sure collect.cfg isn't read-only
+  _chmod (cfgfilec, _S_IREAD | _S_IWRITE);
+#endif
+
+  int fd=open(cfgfilec, O_WRONLY | O_CREAT | O_TRUNC
+#if defined(__WIN32__)
+	      | O_BINARY
+#endif
+	      );
+
+  if (fd) {
+    // lock the file
+    int lock_val = 1;
+    GSDL_LOCK_FILE (fd);
+    if (lock_val != 0) {
+      logout << "Error: Couldn't lock file " << cfgfilec << "\n";
+      close(fd);
+      message = "tmpfail";
+      
+    } else {
+      
+      outconvertclass text_t2ascii;
+      text_t2ascii.setinput(&args["cfgfile"]);
+      size_t buffersize=args["cfgfile"].size();
+      char *buffer=new char[buffersize];
+      buffer[0]='\n'; // just in case something goes wrong...
+      size_t num_chars;
+      convertclass::status_t status;
+      text_t2ascii.convert(buffer, buffersize, num_chars, status);
+      // ignore status - assume it is "finished" as buffer is big enough
+      write(fd, buffer, num_chars);
+      GSDL_UNLOCK_FILE (fd);
+      close(fd);
+      delete []buffer;
+      
+      // now that we've written the file we'll read it back again and
+      // update our bc1 arguments
+      ifstream cfg_in (cfgfilec);
+      if (cfg_in) {
+	text_tarray cfgline;
+	while (read_cfg_line(cfg_in, cfgline) >= 0) {
+	  if (cfgline.size () >= 2) {
+	    if (cfgline[0] == "creator") {
+	      args["bc1contactemail"] = cfgline[1];
+	    } else if (cfgline[0] == "collectionmeta") {
+	      if (cfgline[1] == "collectionname") {
+		args["bc1fullname"] = cfgline[2];
+	      } else if (cfgline[1] == "collectionextra") {
+		args["bc1aboutdesc"] = carriage_replace (cfgline[2], 1);
+	      }
+	    }
+	  }
+	}
+	cfg_in.close();
+      } else {
+	logout << "collectoraction::update_cfgfile_complete: unable to open " 
+	       << cfgfilec << " for input\n";
+	message = "tmpfail";
+      }
+    }
+  } else {
+    logout << "collectoraction::update_cfgfile_complete: unable to open " 
+	   << cfgfilec << " for output\n";
+    message = "tmpfail";
+  }
+
+  delete []cfgfilec;
+}
+
+void collectoraction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+					response_t &response,text_t &response_data, 
+					ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+// return html for buttons used in collector bar
+// color may be "green", "grey", or "yellow"
+// type may be:
+//   "info" --> "collection information" button
+//   "srce" --> "source data" button
+//   "conf" --> "configure collection" button
+//   "bild" --> "build collection" button
+//   "view" --> "view collection" button
+// if enabled is true button will be flashy rollover type and 
+// will be hyperlinked
+
+text_t collectoraction::get_button (const text_t &thispage, const text_t &color, 
+				    const text_t &type, bool enabled) {
+
+  if ((color != "green" && color != "grey" && color != "yellow") ||
+      (type != "info" && type != "srce" && type != "conf" && type != "bild" && type != "view"))
+    return g_EmptyText;
+
+  text_t prefix = "gc";
+  if (color == "grey") prefix = "nc";
+  else if (color == "yellow") prefix = "yc";
+  
+  text_t httpicon = "httpicon" + prefix + type;
+  
+  if (enabled) {
+    text_t gsmacro = "_gsimage_";
+    if (thispage == "info" || thispage == "srce" || thispage == "conf" || 
+	thispage == "bildcancel" || thispage == "bildfail") {
+      gsmacro = "_gsjimage_";
+    } else if (type == "view") {
+      // view button is special case as it needs a target=_top
+      gsmacro = "_gstimage_";
+    }
+    return "<td>" + gsmacro + "(_collector:http" + type + "_,_collector:" + httpicon + 
+      "of_,_collector:" + httpicon + "on_," + type + ",_collector:text" + type + "_)</td>\n";
+  } else {
+    return "<td>_icon" + prefix + type + "of_</td>\n";
+  }
+}
+
+// set the _fullnamemenu_ macro (and _warnindex_ and _selectedindex_ if
+// we're on the "srce" page)
+void collectoraction::set_fullnamemenu (displayclass &disp, cgiargsclass &args, 
+					recptprotolistclass *protos, ostream &logout) {
+
+  if (recpt == NULL) {
+    logout << "ERROR (collectoraction::set_fullnamemenu): This action does not contain\n"
+	   << "       information about any receptionists. The method set_receptionist was\n"
+	   << "       probably not called from the module which instantiated this action.\n";
+    return;
+  }
+
+  text_t &current_page = args["p"];
+  text_t currentname = args["bc1dirname"];
+  if (current_page == "srce") currentname = args["bc1clonecol"];
+
+  text_tarray dirnames;
+  text_tarray fullnames;
+  vector<bool> write_protected;
+  bool is_selected = false;
+  int selected_index = 0;
+  int index = 0;
+
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+
+      // don't include z39.50 collections
+      comerror_t err = noError;
+      if ((*rprotolist_here).p->get_protocol_name (err) == "z3950proto") {
+	++rprotolist_here;
+	continue;
+      }
+
+      text_tarray collist;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+	while (collist_here != collist_end) {
+	  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
+	  if (cinfo != NULL) {
+	    text_t collectionname = cinfo->get_collectionmeta("collectionname", args["l"]);
+	    if (collectionname.empty()) {
+	      collectionname = *collist_here;
+	    }
+	    dirnames.push_back(*collist_here);
+	    fullnames.push_back(collectionname);
+	    // check to see if the collection is writable
+	    if (collection_protected (*collist_here)) write_protected.push_back(true);
+	    else write_protected.push_back(false);
+
+	    if (*collist_here == currentname) {
+	      is_selected = true;
+	      selected_index = index; 	    
+	    }
+	    ++index;
+	  }
+	  ++collist_here;
+	}
+      }
+    }
+    ++rprotolist_here;
+  }
+
+  bool first = true;
+  text_t warnindex;
+  text_t fullnamemenu = "<select name=\"bc1dirname\">\n";
+  if (current_page == "srce") {
+    fullnamemenu = "<select name=\"bc1clonecol\" onChange=\"menuchange();\">\n";
+    fullnamemenu += "<option value=defaultstructure";
+    if (!is_selected) fullnamemenu += " selected>";
+    else fullnamemenu.push_back('>');
+    fullnamemenu += "_collector:textdefaultstructure_\n";
+  }
+  for (int i = 0; i < index; ++i) {
+    // don't want write protected collections in list on "change existing
+    // collection" page
+    if (write_protected[i] && current_page == "existing") continue;
+    fullnamemenu += "<option value=\"" + dirnames[i] + "\"";
+    if ((i == 0 && !is_selected && current_page != "srce") || 
+	(is_selected && i == selected_index)) {
+      fullnamemenu += " selected";
+      ++selected_index;
+      is_selected = false;
+    }
+    fullnamemenu.push_back ('>');
+    fullnamemenu += fullnames[i];
+    fullnamemenu.push_back ('\n');
+    
+    // add to Warnindex if collection uses any dubious plugins 
+    // (if creating clone collection list)
+    if (current_page == "srce") {
+      if (first) warnindex += "0,";
+      else warnindex.push_back(',');
+      if (uses_weird_plugin (dirnames[i])) {
+	warnindex += text_t (1);
+      } else {
+	warnindex += text_t (0);
+      }
+    }
+    first = false;
+  }
+  fullnamemenu += "</select>\n";
+
+  disp.setmacro ("fullnamemenu", "collector", fullnamemenu);
+  if (current_page == "srce") {
+    disp.setmacro ("warnindex", "collector", warnindex);
+    disp.setmacro ("selectedindex", "collector", text_t(selected_index));
+  }
+}
+
+// set _sourcelist_ and _badsources_ macros
+void collectoraction::set_inputsourceboxes (displayclass &disp, cgiargsclass &args, 
+					    ostream &logout) {
+  
+  if (badsources) disp.setmacro ("badsources", "collector", "1");
+
+  text_t sourcelist = get_source_box(args["bc1input"], args["bc1inputnum"].getint(),
+				     args["bc1inputtype"]);
+
+  disp.setmacro("sourcelist", "collector", sourcelist);
+
+  // reset badsources and failedsources variables
+  badsources = false;
+  failedsources.erase(failedsources.begin(), failedsources.end());
+}
+
+text_t collectoraction::get_source_box (text_t inputarglist, int numboxes,
+					text_t inputtypelist) {
+
+  text_tarray inputvalues;
+  splitchar (inputarglist.begin(), inputarglist.end(), ',', inputvalues);
+  // remove any empty values from the end of the array
+  if (inputvalues.size()) {
+    text_tarray::iterator l = inputvalues.end() - 1;
+    text_tarray::iterator b = inputvalues.begin();
+    while ((*l).empty() && l >= b) {
+      --l;
+    }
+    inputvalues.erase(l+1, inputvalues.end());
+  }
+
+  text_tarray inputtypes;
+  splitchar (inputtypelist.begin(), inputtypelist.end(), ',', inputtypes);
+
+  int numvalues = inputvalues.size();
+  int numtypes = inputtypes.size();
+
+  text_t last = "file://";
+  text_t rv;
+  for (int i = 0; i < numboxes; ++i) {
+    rv += "<nobr><select name=\"bc1inputtype\">\n";
+    rv += "<option value=\"file://\"";
+    if ((i < numtypes && inputtypes[i] == "file://") ||
+	(numboxes == 3 && i == 0 && numvalues == 0) ||
+	(i >= 3 && i >= numvalues && last == "file://")) {
+      rv += " selected";
+      last = "file://";
+    }
+    rv += ">file://\n";
+    rv += "<option value=\"http://\"";
+    if ((i < numtypes && inputtypes[i] == "http://") ||
+	(numboxes == 3 && i == 1 && numvalues == 0) ||
+	(i >= 3 && i >= numvalues && last == "http://")) {
+      rv += " selected";
+      last = "http://";
+    }
+    rv += ">http://\n";
+    rv += "<option value=\"ftp://\"";
+    if ((i < numtypes && inputtypes[i] == "ftp://") ||
+	(numboxes == 3 && i == 2 && numvalues == 0) ||
+	(i >= 3 && i >= numvalues && last == "ftp://")) {
+      rv += " selected";
+      last = "ftp://";
+    }
+    rv += ">ftp://\n";
+    rv += "</select>\n";
+    rv += "<input type=text name=\"bc1input\" value=\"";
+    if (i < numvalues) {
+      rv += dm_safe(decode_commas(inputvalues[i]));
+    }
+    rv += "\" size=50>";
+    if (badsources) {
+      if ((i < numvalues) && (!inputvalues[i].empty())) {
+	if (failedsources[decode_commas(inputvalues[i])] == "1") {
+	  rv += "_iconcross_";
+	} else {
+	  rv += "_icontick_";
+	}
+      } else {
+	rv += "_iconblank_";
+      }
+    }
+    if (i+1 == numboxes) {
+      if (!badsources) rv += "_iconblank_";
+      rv += "_imagemore_</nobr><br>";
+    } else {
+      rv += "</nobr><br>\n";
+    }
+  }
+  
+  return rv;
+}
+
+// set the _cfgfile_ macro
+void collectoraction::set_cfgfile (displayclass &disp, cgiargsclass &args, ostream &logout) {
+
+  text_t &collection = args["bc1dirname"];
+  if (collection.empty()) {
+    message = "nocollection";
+    return;
+  }
+
+  // read in collect.cfg      
+  text_t cfgfile = filename_cat(get_collectdir(args), collection, "etc", "collect.cfg");  
+  char *cfgfilec = cfgfile.getcstr();
+
+#ifdef GSDL_USE_IOS_H
+  ifstream cfg_ifs (cfgfilec, ios::in | ios::nocreate);
+#else
+  ifstream cfg_ifs (cfgfilec, ios::in);
+#endif
+  
+  if (cfg_ifs) {  
+    // read in collect.cfg      
+    text_t cfgtext;
+    char c;
+    cfg_ifs.get(c);
+    while (!cfg_ifs.eof ()) {
+      cfgtext.push_back(c);
+      cfg_ifs.get(c);
+    }
+    cfg_ifs.close();
+    
+    // define it as a macro
+    disp.setmacro("cfgfile", "collector", dm_safe(cfgtext));
+
+  } else {
+    logout << "collectoraction::set_cfgfile: couldn't open configuration file (" 
+	   << cfgfilec << ") for reading\n";
+    message = "tmpfail";
+  }    
+  delete []cfgfilec;
+}
+
+// set the _statusline_ macro
+void collectoraction::set_statusline (displayclass &disp, cgiargsclass &args, ostream & /*logout*/) {
+
+  // the build command creates .bld.download, .bld.import, and .bld.build files (in that
+  // order) and deletes them (also in that order) when each stage is complete. the .bld
+  // file is the concatenation of all these files.
+  text_t bld_file = filename_cat (gsdlhome, "tmp", args["bc1tmp"], args["bc1dirname"] + ".bld");
+  text_t statusline;
+
+  if (file_exists (bld_file + ".download")) {
+    statusline = "_collector:textdownloadingfiles_<br>\n";
+    statusline += dm_safe(file_tail(bld_file + ".download", 1, 0));
+  } else if (file_exists (bld_file + ".import")) {
+    statusline = "_collector:textimportingcollection_<br>\n";
+    statusline += dm_safe(file_tail(bld_file + ".import", 1, 0));
+  } else if (file_exists (bld_file + ".build")) {
+    statusline = "_collector:textbuildingcollection_<br>\n";
+    statusline += dm_safe(file_tail(bld_file + ".build", 1, 0));
+  } else {
+    statusline += "_collector:textcreatingcollection_<br>\n";
+    statusline += dm_safe(file_tail(bld_file, 1, 0));
+  }
+
+  disp.setmacro ("statusline", "collector", statusline);
+
+}
+
+void collectoraction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					      recptprotolistclass *protos, ostream &logout) {
+
+  // define_internal_macros sets the following macros:
+  // _collectorbar_
+  // _pagescriptextra_
+  // _fullnamemenu_ -- if displaying the "source data" page or the "changing existing 
+  //                   collection" page
+  // _cfgfile_ -- if displaying the "configure collection" page
+  // _statusline_ -- if displaying the bildstatus page
+  // _header_ -- may be set for pages that require it
+  // _textfailmsg_ -- set to different messages depending on failcode returned
+  //                  by build script (if build fails)
+  // _faillog_ - set to last 6 lines of .bld file if build failed
+  // _gsdlhome_ - the gsdlhome path (dm_safe)
+  // _sourcelist_ -- "input source" text boxes
+  // _badsources_ -- will be set to "1" if we've come from the 
+  //                 "source data" page and there's a problem 
+  //                 with the input sources
+
+  text_t &collector_page = args["p"];
+  int esrce = args["bc1esrce"].getint();
+  int econf = args["bc1econf"].getint();
+
+  // set _pagescriptextra_ macro to _cpagescriptextra_
+  disp.setmacro ("pagescriptextra", "collector", "_" + collector_page + "scriptextra_");
+
+  if (collector_page == "bildstatus" || collector_page == "bilddone" || 
+      collector_page == "bildfail" || collector_page == "bildframe1") {
+    disp.setmacro ("header", "collector", "_" + collector_page + "header_");
+  }
+
+  // set the collectorbar macro
+  text_t collectorbar = "<table border=0 cellspacing=4 cellpadding=0><tr>\n";
+
+  if (collector_page == "new") {
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "green", "info", true);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "srce", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "conf", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "bild", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "view", false);
+
+  } else if (collector_page == "info") {
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "yellow", "info", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "green", "srce", true);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "conf", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "bild", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "view", false);
+    collectorbar += "</tr><tr><td></td><td align=center>_icongreyuparrow_</td><td colspan=8></td>\n";
+
+  } else if (collector_page == "srce") {
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    if (esrce == 1) {
+      // if we came from the "change an existing collection" page previous button(s)
+      // are disabled
+      collectorbar += get_button (collector_page, "grey", "info", false);
+    } else {
+      collectorbar += get_button (collector_page, "yellow", "info", true);
+    }
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "yellow", "srce", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "green", "conf", true);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "green", "bild", true);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "view", false);
+    collectorbar += "</tr><tr><td colspan=3></td><td align=center>_icongreyuparrow_</td><td colspan=6></td>\n";
+
+  } else if (collector_page == "conf") {
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    // disable appropriate buttons if we came from "change an existing collection"
+    // page
+    if (esrce == 1 || econf == 1) {
+      collectorbar += get_button (collector_page, "grey", "info", false);
+    } else {
+      collectorbar += get_button (collector_page, "yellow", "info", true);
+    }
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    if (econf == 1) {
+      collectorbar += get_button (collector_page, "grey", "srce", false);
+    } else {
+      collectorbar += get_button (collector_page, "yellow", "srce", true);
+    }
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "yellow", "conf", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "green", "bild", true);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "view", false);
+    collectorbar += "</tr><tr><td colspan=5></td><td align=center>_icongreyuparrow_</td><td colspan=4></td>\n";
+
+  } else if (collector_page == "bilddone") {
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    // all previous buttons grey after build was completed
+    collectorbar += get_button (collector_page, "grey", "info", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "srce", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "conf", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "yellow", "bild", false);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "green", "view", true);
+    collectorbar += "</tr><tr><td colspan=7></td><td align=center>_icongreyuparrow_</td><td colspan=2></td>\n";
+
+  } else if (collector_page == "bildcancel" || collector_page == "bildfail") {
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    // disable appropriate buttons if we came from "change an existing collection"
+    // page
+    if (esrce == 1 || econf == 1) {
+      collectorbar += get_button (collector_page, "grey", "info", false);
+    } else {
+      collectorbar += get_button (collector_page, "yellow", "info", true);
+    }
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    if (econf == 1) {
+      collectorbar += get_button (collector_page, "grey", "srce", false);
+    } else {
+      collectorbar += get_button (collector_page, "yellow", "srce", true);
+    }
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "yellow", "conf", true);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "yellow", "bild", true);
+    collectorbar += "<td>_icongreyarrow_</td>\n";
+    collectorbar += get_button (collector_page, "grey", "view", false);
+  }
+
+  collectorbar += "</tr></table>\n";
+  disp.setmacro ("collectorbar", "collector", collectorbar);
+
+  if (collector_page == "bildfail") {
+
+    text_t textfailmsg = "_textfailmsg";
+    textfailmsg.push_back(failcode);
+    textfailmsg.push_back('_');
+    disp.setmacro("textfailmsg", "collector", textfailmsg);
+
+    text_t bldlog = filename_cat(gsdlhome, "tmp", args["bc1tmp"], args["bc1dirname"] + ".bld");
+    text_t rawlog = file_tail (bldlog, 6, 0);
+    // we'll shove in some <br> tags where \n's occur
+    text_t faillog;
+    text_t::const_iterator here = rawlog.begin();
+    text_t::const_iterator end = rawlog.end();
+    while (here != end) {
+      if (*here == '\n') faillog += "<br>";
+      faillog.push_back (*here);
+      ++here;
+    }
+    disp.setmacro ("faillog", "collector", dm_safe(faillog));
+  }
+
+  if (collector_page == "srce" || collector_page == "existing") 
+    set_fullnamemenu (disp, args, protos, logout);
+  if (collector_page == "conf") 
+    set_cfgfile (disp, args, logout);
+  if (collector_page == "bildstatus")
+    set_statusline (disp, args, logout);
+  if (collector_page == "srce") {
+    set_inputsourceboxes (disp, args, logout);
+  }
+
+  disp.setmacro ("gsdlhome", "collector", dm_safe(gsdlhome));
+}
+
+bool collectoraction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/, 
+				 browsermapclass * /*browsers*/, displayclass &disp, 
+				 outconvertclass &outconvert, ostream &textout, 
+				 ostream &logout) {
+
+  // make sure the collector is enabled
+  if (disabled) {
+    textout << outconvert 
+	    << "<html>\n"
+	    << "<head>\n"
+	    << "<title>Collector disabled</title>\n"
+	    << "</head>\n"
+	    << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
+	    << "alink=\"#cc9900\" vlink=\"#666633\">\n"
+	    << "<h2>Facility disabled</h2>\n" 
+	    << "Sorry, the Collector end-user collection building facility is currently disabled\n"
+	    << "\n</body>\n"
+	    << "</html>\n";
+    return true;
+  }
+
+  text_t &collector_page = args["p"];
+  text_t &collection = args["bc1dirname"];
+
+  // make sure we have perl (we won't bother with this check for the 
+  // building status pages to avoid slowing things down unneccessarily)
+  if (collector_page != "bildstatus" && collector_page != "bildframe1" && !perl_ok(logout)) {
+    textout << outconvert 
+	    << "<html>\n"
+	    << "<head>\n"
+	    << "<title>Perl not found</title>\n"
+	    << "</head>\n"
+	    << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
+	    << "alink=\"#cc9900\" vlink=\"#666633\">\n"
+	    << "<h2>Perl not found</h2>\n" 
+	    << "Greenstone could not detect perl on this system. It is therefore not\n"
+	    << "possible to build a Greenstone collection, either from the Collector or the \n"
+	    << "command-line tools, or to use the Collector for any other task.\n"
+	    << "<p>Please refer to the Greenstone Installer's Guide for details on\n"
+	    << "installing perl on your system.\n"
+	    << "\n</body>\n"
+	    << "</html>\n";
+    return true;
+
+  }
+
+  if (collector_page == "bild") {
+    // do the work (download, import, build)
+    gsdl_build (args, logout);
+
+    if (message.empty()) {
+      // bild page is a frameset so we don't want headers and stuff
+      textout << outconvert << disp << ("_collector:bildcontent_\n");
+    }
+  }
+
+  if (do_mkcol == true) {
+    // execute mkcol.pl (do_mkcol is set from within check_cgiargs)
+    gsdl_mkcol (args, logout);
+    do_mkcol = false; // reset for fast-cgi
+  }
+
+  if (args["bc1dodelete"] == "1") {
+    // delete bcidirname collection
+    if (collection_protected (collection)) {
+      message = "delinvalid";
+	
+    } else {
+
+      const recptconf &rcinfo = recpt->get_configinfo ();
+      bool emailuserevents = rcinfo.EmailUserEvents;
+
+      // get collection maintainer email from collect.cfg before we
+      // delete it
+      text_t colmaintainer;
+      text_t cfgfile = filename_cat(gsdlhome, "collect", collection, "etc", "collect.cfg");
+      char *cfgfilec = cfgfile.getcstr();
+      ifstream cfg_in (cfgfilec);
+      delete []cfgfilec;
+      if (cfg_in) {
+	text_tarray cfgline;
+	while (read_cfg_line(cfg_in, cfgline) >= 0) {
+	  if (cfgline.size () == 2 && cfgline[0] == "maintainer") {
+	    colmaintainer = cfgline[1];
+	    break;
+	  }
+	}
+	cfg_in.close();
+      }
+      if (colmaintainer.empty()) {
+	logout << outconvert 
+	       << "collectoraction::do_action WARNING: Collection being deleted (" 
+	       << collection << ") has no maintainer address. EmailUserEvents "
+	       << "disabled\n";
+	emailuserevents = false;
+      }
+      
+      // first we need to free up the collection's collection server
+      // we must do this for the local library (and I guess when using
+      // fastcgi too) as you can't delete the gdbm file while it's
+      // being kept open by the collection server
+      remove_colservr (collection, logout);
+
+      text_t delete_cmd = "perl -S delcol.pl -f " + collection;
+      int rv = gsdl_system (delete_cmd, true, logout);
+      if (rv != 0) {
+	// deletion failed -- permissions?
+	message = "delpermission";
+      } else {
+	message = "delsuccess";
+      }
+
+      // log the event
+      if (rcinfo.LogEvents == CollectorEvents || rcinfo.LogEvents == AllEvents) {
+	
+	text_t eventlog = filename_cat (gsdlhome, "etc", "events.txt");
+	char *eventlogt = eventlog.getcstr();
+	ofstream eventl (eventlogt, ios::app);
+	delete []eventlogt;
+
+	if (eventl) {
+	  eventl << outconvert << "[Collector Event]\n"
+		 << "Date: " << get_date (true) << "\n"
+		 << "Greenstone Username: " << args["un"] << "\n"
+		 << "Collection: " << collection << "\n"
+		 << "Collection Maintainer: " << colmaintainer << "\n"
+		 << "GSDLHOME: " << gsdlhome << "\n";
+
+	  if (message == "delsuccess") {
+	    eventl << outconvert 
+		   << "The " << collection << " collection was successfully deleted\n\n";
+	  } else {
+	    eventl << outconvert 
+		   << "Attempt to delete the " << collection << " collection failed\n\n";
+	  }
+	  eventl.close();
+
+	} else {
+	  logout << outconvert << "collectoraction::do_action ERROR: Couldn't open "
+		 << "event log file " << eventlog << " for appending during collection "
+		 << "deletion. LogEvents disabled\n";
+	}
+      }
+      
+      if (rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents || emailuserevents) {
+	// use sendmail.pl perl script to send email events
+	text_t tmpmailfile = filename_cat (gsdlhome, "tmp", args["bc1tmp"], "event.txt");
+	char *tmpmailfilec = tmpmailfile.getcstr();
+	ofstream tmpfile (tmpmailfilec);
+	delete []tmpmailfilec;
+	if (tmpfile) {
+	  tmpfile << outconvert << "[Collector Event]\n"
+	    	  << "Date: " << get_date (true) << "\n"
+		  << "Greenstone Username: " << args["un"] << "\n"
+		  << "Collection: " << collection << "\n"
+		  << "Collection Maintainer: " << colmaintainer << "\n"
+		  << "GSDLHOME: " << gsdlhome << "\n";
+	  if (message == "delsuccess") {
+	    tmpfile << outconvert 
+		    << "The " << collection << " collection was successfully deleted\n\n";
+	  } else {
+	    tmpfile << outconvert 
+		    << "Attempt to delete the " << collection << " collection failed\n\n";
+	  }
+	  tmpfile.close();
+	  text_t to;
+	  if (rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents) to += rcinfo.maintainer;
+	  if (emailuserevents) {
+	    if (!to.empty()) to.push_back (',');
+	    to += colmaintainer;
+	  }
+	  text_t sendmail_cmd = "perl -S sendmail.pl -to \"" + to + "\" -from \"" + rcinfo.maintainer;
+	  sendmail_cmd += "\" -smtp \"" + rcinfo.MailServer + "\" -subject \"Greenstone Collector Event\"";
+	  sendmail_cmd += " -msgfile \"" + tmpmailfile + "\"";
+
+	  gsdl_system (sendmail_cmd, false, logout);
+	  
+	} else {
+	  logout << outconvert << "collectoraction::do_action ERROR: Couldn't open "
+		 << "temporary event log file " << tmpmailfile << " during collection "
+		 << "deletion. EmailEvents and EmailUserEvents disabled\n";
+	}
+      }
+    }
+  }
+  
+  if (collector_page == "bildcancel" || collector_page == "bildfail") {
+    // cancel the build (we'll also use the cancel_build script to tidy
+    // up if the build failed)
+    gsdl_cancel_build (args, logout);
+  }
+
+  if (collector_page == "expt") {
+
+    // export the collection - we'll do a synchronous system call to
+    // exportcol.pl as that's the easiest way to do it. if it becomes a
+    // problem that it's taking too long to export a large collection then
+    // we may have to revisit this.
+    text_t tmpfile = filename_cat (gsdlhome, "tmp", collection + "_export.txt");
+    text_t export_cmd = "perl -S exportcol.pl -out \"" + tmpfile + "\" " + collection;
+    gsdl_system (export_cmd, true, logout);
+    if (file_exists (tmpfile)) {
+      text_t returnline = file_tail (tmpfile, 1, 0);
+      if (returnline.size() > 23 && (substr(returnline.begin(), returnline.begin()+23) == "exportcol.pl succeeded:")) {
+	// success
+	message = "exptsuccess";
+      } else {
+	message = "exptfail";
+      }
+    } else {
+      message = "exptfail";
+    }
+  }
+
+  if (message.empty()) {
+    if (collector_page != "bild") {
+      // output page ("bild" page was already output above)
+      textout << outconvert << disp << ("_collector:header_\n")
+	      << ("_collector:" + collector_page + "content_\n")
+	      << ("_collector:footer_\n");
+    }
+  } else {
+    // message was set somewhere (probably an error), output message page
+    textout << outconvert << disp << ("_collector:header_\n")
+	    << ("_collector:" + message + "content_\n")
+	    << ("_collector:footer_\n");
+    message.clear();
+  }
+  return true;
+}
+
+// if sw = 0 replace all carriage returns in intext with the string "\n"
+// else replace all occurances of "\n" with a carriage return
+text_t collectoraction::carriage_replace (const text_t &intext, int sw) {
+   
+  text_t outtext;
+  text_t::const_iterator here = intext.begin();
+  text_t::const_iterator end = intext.end();
+  while (here != end) {
+    if (sw == 0) {
+      if (*here == '\n') {
+	if ((here+1) != end && *(here+1) == '\r') ++here;
+	outtext += "\\n";
+      } else if (*here == '\r') {
+	if ((here+1) != end && *(here+1) == '\n') ++here;
+	outtext += "\\n";
+      } else {
+	outtext.push_back (*here);
+      }
+    } else if (*here == '\\' && (here+1) != end && *(here+1) == 'n') {
+      outtext.push_back ('\n');
+      ++here;
+    } else {
+      outtext.push_back (*here);
+    }
+    ++here;
+  }
+  return outtext;
+}
+
+// create a short directory name from fullname
+text_t collectoraction::get_directory_name (const text_t &fullname) {
+
+  text_t shortname;
+  if (fullname.empty()) {
+    shortname = "coll";
+
+  } else {
+    
+    // first make all lowercase and remove any dodgy characters
+    // (i.e. anything not [a-z]
+    text_t::const_iterator here = fullname.begin();
+    text_t::const_iterator end = fullname.end();
+    while (here != end) {
+      if ((*here >= 'A' && *here <= 'Z') || (*here >= 'a' && *here <= 'z') ||
+	  (*here == ' ')) {
+	if (*here >= 'A' && *here <= 'Z') shortname.push_back (*here+32);
+	else if (*here == ' ') {
+	  while ((*(here+1)) == ' ') ++here;
+	  shortname.push_back (*here);
+	} else shortname.push_back (*here);
+      }
+      ++here;
+    }
+
+    text_tarray words;
+    splitchar (shortname.begin(), shortname.end(), ' ', words);
+    int num_words = words.size();
+
+    if (num_words == 0) {
+      shortname = "coll";
+
+    } else {
+
+      shortname.clear();
+      int use_words = (num_words <= 6) ? num_words : 6;
+      unsigned int substr_len = 6 / use_words;
+      
+      for (int i = 0; i < use_words; ++i) {
+	if (words[i].size() < substr_len) shortname += words[i];
+	else shortname += substr (words[i].begin(), words[i].begin()+substr_len);
+      }
+    }
+  }
+
+  // check to see if shortname is unique
+  text_t fulldirname = filename_cat (gsdlhome, "collect", shortname);
+  if (directory_exists (fulldirname)) {
+    int version = 0;
+    text_t newname;
+    do {
+      ++version;
+      newname = shortname;
+      newname.push_back ('v');
+      newname.appendint (version);
+      fulldirname = filename_cat (gsdlhome, "collect", newname);
+    } while (directory_exists (fulldirname));
+
+    shortname = newname;
+  }
+  
+  return shortname;
+}
+
+// tests if collection is write protected (currently just checks if
+// collect.cfg file is writable
+bool collectoraction::collection_protected (const text_t &collection) {
+  text_t cfgfile = filename_cat(gsdlhome, "collect", collection, "etc", "collect.cfg");
+  if (file_writable(cfgfile)) return false;
+  return true;
+}
+
+// assigns a temporary directory name for this collector session
+// and creates temporary directory
+// returns false if it couldn't create the directory
+bool collectoraction::assign_tmpname (cgiargsclass &args, ostream &logout) {
+
+  int i = 0;
+  text_t tmpname = "tbuild";
+  while (directory_exists (filename_cat (gsdlhome, "tmp", tmpname + text_t(i)))) {
+    ++i;
+  }
+  tmpname.appendint (i);
+
+  text_t fulltmpdir = filename_cat (gsdlhome, "tmp", tmpname);
+  if (!mk_dir (fulltmpdir)) {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii << "collectoraction::assign_tmpname unable to create directory ("
+	   << fulltmpdir << ")\n";
+    return false;
+  }
+
+  args["bc1tmp"] = tmpname;
+  return true;
+}
+
+void collectoraction::gsdl_mkcol (cgiargsclass &args, ostream &logout) {
+
+  text_t tmpdir = filename_cat (gsdlhome, "tmp", args["bc1tmp"]);
+  if (!directory_exists (tmpdir)) {
+    message = "tmpfail";
+    return;
+  }
+
+  text_t &collection = args["bc1dirname"];
+  if (collection.empty()) {
+    message = "nocollection";
+    return;
+  }
+
+  // check for a .create file - if it exists then we've already created the collection
+  text_t createfile = filename_cat (tmpdir, ".create");
+  if (file_exists (createfile)) {
+    return;
+  }
+
+  // set up options
+  text_t options = "-quiet -creator \"" + args["bc1contactemail"] + "\"";
+  options += " -title \"" + args["bc1fullname"] + "\"";
+  options += " -about \"" + carriage_replace (args["bc1aboutdesc"] + "_collectorextra_", 0) + "\"";
+  options += " -collectdir \"" + remove_trailing_slashes(tmpdir) + "\" ";
+
+  text_t optionfile = filename_cat (tmpdir, "mkcol.opt");
+  char *optionfilec = optionfile.getcstr();
+  ofstream ofile_out (optionfilec);
+  delete []optionfilec;
+  if (!ofile_out) {
+    message = "tmpfail";
+    return;
+  }
+  outconvertclass text_t2ascii;
+  ofile_out << text_t2ascii << options << "\n";
+  ofile_out.close();
+
+  // run mkcol.pl
+  text_t mkcol_cmd = "perl -S mkcol.pl -optionfile \"" + optionfile;
+  mkcol_cmd += "\" " + collection;
+  gsdl_system (mkcol_cmd, true, logout);
+
+  // make sure it went ok
+  text_t cfgfile = filename_cat (tmpdir, collection, "etc", "collect.cfg");
+  if (!file_writable (cfgfile)) {
+    message = "mkcolfail";
+  } else {
+    // create the .create file (this file is just a place holder to let any future
+    // pages know that the collection already exists).
+    char *createfilec = createfile.getcstr();
+    ofstream cfile_out (createfilec);
+    delete []createfilec;
+    if (cfile_out) {
+      cfile_out << "collection created\n";
+      cfile_out.close();
+    } else {
+      message = "tmpfail";
+      return;
+    }
+  }
+}
+
+void collectoraction::gsdl_build (cgiargsclass &args, ostream &logout) {
+
+  outconvertclass text_t2ascii;
+
+  text_t tmpdir = filename_cat (gsdlhome, "tmp", args["bc1tmp"]);
+  if (!directory_exists (tmpdir)) {
+    message = "tmpfail";
+    return;
+  }
+  
+  text_t &collection = args["bc1dirname"];
+  if (collection.empty()) {
+    message = "nocollection";
+    return;
+  }
+
+  // check for a .build file - if it exists then we've already built
+  // the collection (or are in the process of building it)
+  text_t buildfile = filename_cat (tmpdir, ".build");
+  if (file_exists (buildfile)) {
+    return;
+  } else {
+    // create the .build file (this file is just a place holder to let any future
+    // pages know that we've already been here)
+    char *buildfilec = buildfile.getcstr();
+    ofstream bfile_out (buildfilec);
+    delete []buildfilec;
+    if (bfile_out) {
+      bfile_out << "collection building\n";
+      bfile_out.close();
+    } else {
+      message = "tmpfail";
+      return;
+    }
+  }
+
+  const recptconf &rcinfo = recpt->get_configinfo ();
+
+  // create the event header file if LogEvents, EmailEvents or
+  // EmailUserEvents options are turned on.
+  bool logevents = 
+    (rcinfo.LogEvents == CollectorEvents || rcinfo.LogEvents == AllEvents || 
+     rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents ||
+     rcinfo.EmailUserEvents);
+  text_t ehead_file = filename_cat (tmpdir, "ehead.txt");
+  if (logevents) {
+    if (!create_event_header_file (ehead_file, args, logout)) {
+      logevents = false;
+    }
+  }
+    
+  text_t collectdir = get_collectdir (args);
+
+  // set up build options
+  text_t options = "-make_writable -remove_import -out \"";
+  options += filename_cat (tmpdir, collection + ".bld");
+  options += "\" -collectdir \"" + collectdir + "\" -statsfile \"";
+  options += filename_cat(collectdir, collection, "etc", "import.log") + "\"";
+
+  if (args["bc1esrce"] == 1) {
+    // we're adding data to an existing collection
+    options += " -save_archives -append";
+  }
+
+  text_tarray inputvalues, inputtypes;
+  splitchar (args["bc1input"].begin(), args["bc1input"].end(), ',', inputvalues);
+  splitchar (args["bc1inputtype"].begin(), args["bc1inputtype"].end(), ',', inputtypes);
+  int numvalues = inputvalues.size();
+  int numtypes = inputtypes.size();
+  for (int i = 0; i < numvalues; ++i) {
+    if (!inputvalues[i].empty()) {
+      text_t type = "file://"; // default
+      if (i < numtypes) type = inputtypes[i];
+      options += " -download \"" + 
+	remove_trailing_slashes(type + format_url(decode_commas(inputvalues[i]))) + "\"";
+    }
+  }
+
+  if (logevents) {
+    if (rcinfo.LogEvents == CollectorEvents || rcinfo.LogEvents == AllEvents) 
+      options += " -log_events";
+    if (rcinfo.EmailEvents == CollectorEvents || rcinfo.EmailEvents == AllEvents) {
+      options += " -mail_server " + rcinfo.MailServer;
+      options += " -email_events " + rcinfo.maintainer;
+      if (rcinfo.EmailUserEvents) options += "," + args["bc1contactemail"];
+    } else if (rcinfo.EmailUserEvents) {
+      options += " -mail_server " + rcinfo.MailServer;
+      options += " -email_events " + args["bc1contactemail"];
+    }
+    options += " -event_header " + ehead_file;
+  }
+
+  text_t optionfile = filename_cat (tmpdir, "build.opt");
+  char *optionfilec = optionfile.getcstr();
+  ofstream ofile_out (optionfilec);
+  delete []optionfilec;
+  if (!ofile_out) {
+    message = "tmpfail";
+    return;
+  }
+  ofile_out << text_t2ascii << options << "\n";
+  ofile_out.close();
+
+  // if we're altering an existing collection we need to kill off
+  // the existing collection server - we do this for the local library
+  // (and any other persistent version of the library) as the existing
+  // gdbm file can't be deleted while the collection server holds it open
+  if ((args["bc1econf"] == 1) || (args["bc1esrce"] == 1)) {
+    remove_colservr (collection, logout);
+  }    
+
+  // set up the build command - build.bat has some issues with quoting
+  // on win2k when gsdlhome contains spaces so we'll avoid using 
+  // "perl -S" here in favor of calling the "build" perl script explicitly
+  text_t build_cmd = "perl \"" + filename_cat (gsdlhome, "bin", "script", "build");
+  build_cmd += "\" -optionfile \"" + optionfile + "\" " + collection;
+  // run build command in background (i.e. asynchronously)
+  gsdl_system (build_cmd, false, logout);
+}
+
+void collectoraction::gsdl_cancel_build (cgiargsclass &args, ostream &logout) {
+  // I really wanted to do what this perl script does from within the library
+  // c++ code. I ran into some problems though (like how do you write a portable
+  // "rm -r" in c++?). One day I'll spend some time sorting it out ... maybe.
+  text_t cancel_cmd = "perl -S cancel_build.pl -collectdir \"";
+  cancel_cmd += filename_cat (gsdlhome, "tmp", args["bc1tmp"]) + "\" ";
+  cancel_cmd += args["bc1dirname"];
+  // To be on the safe side we'll make this a synchronous call
+  // so that all tidying up is done before the user has a chance
+  // to do anything else (like start rebuilding their collection).
+  // This means that for a big collection where there's lots of 
+  // stuff to delete etc. it might take a while before the "build
+  // cancelled" page appears.
+  gsdl_system (cancel_cmd, true, logout);
+}
+
+text_t collectoraction::get_collectdir (cgiargsclass &args)
+{
+  if ((args["bc1econf"] == 1) || (args["bc1esrce"] == 1)) {
+    // we're adding to a collection in place
+    return filename_cat(gsdlhome, "collect");  
+  }
+  else {
+    return filename_cat (gsdlhome, "tmp", args["bc1tmp"]);
+  }
+}
+
+// checks to see if any of the plugins in pluginset occur in 
+// collections configuration file
+bool collectoraction::uses_weird_plugin (const text_t &collection) {
+
+  text_tset pluginset;
+  pluginset.insert ("HBPlug");
+
+  text_t cfgfile_content;
+  text_t cfgfile_name = filename_cat (gsdlhome, "collect", collection, "etc", "collect.cfg");
+  text_t pluginstr, pluginname;
+
+  if (read_file (cfgfile_name, cfgfile_content)) {
+    text_t::const_iterator here = cfgfile_content.begin();
+    text_t::const_iterator end = cfgfile_content.end();
+    while (here != end) {
+      here = findchar (here, end, 'p');
+      if (here == end) break;
+      if ((here+6 < end) && (substr (here, here+6) == "plugin")) {
+	getdelimitstr (here+6, end, '\n', pluginstr);
+	text_t::const_iterator hp = pluginstr.begin();
+	text_t::const_iterator ep = pluginstr.end();
+	bool found = false;
+	// remove any leading whitespace, trailing options etc.
+	while (hp != ep) {
+	  if (*hp == '\t' || *hp == ' ' || *hp == '\n') {
+	    if (found) break;
+	  } else {
+	    pluginname.push_back (*hp);
+	    found = true;
+	  }
+	  ++hp;
+	}
+	text_tset::const_iterator it = pluginset.find (pluginname);
+	if (it != pluginset.end()) return true; // found matching plugin
+	pluginname.clear();
+      }
+      ++here;
+    }
+  }
+  return false;
+}
+
+// create and initialize a new collection server and
+// add it to the null protocol.
+void collectoraction::create_colserver (const text_t &collection, ostream &logout) {
+
+  recptprotolistclass *protos = recpt->get_recptprotolist_ptr();
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    comerror_t err = noError;
+    if ((*rprotolist_here).p != NULL) {
+      if ((*rprotolist_here).p->get_protocol_name (err) == "nullproto") {
+	// create collection server and add it to nullproto
+	(*rprotolist_here).p->add_collection (collection, recpt, gsdlhome, gsdlhome);
+	// make sure gsdlhome is configured
+	text_tarray tmp;
+	tmp.push_back (gsdlhome);
+	(*rprotolist_here).p->configure ("gsdlhome", tmp, err);
+	// re-initialize the null protocol
+	if (!(*rprotolist_here).p->init (err, logout)) {
+	  logout << "collectoraction::create_colserver: nullproto init failed\n";
+	}
+	return;
+      }
+    }
+    ++rprotolist_here;
+  }
+
+  logout << "collectoraction::create_colserver: no valid nullproto found\n";
+}
+
+// delete a collection server from the null protocol
+void collectoraction::remove_colservr (const text_t &collection, ostream &logout) {
+
+  recpt->uncache_collection (collection);
+
+  recptprotolistclass *protos = recpt->get_recptprotolist_ptr();
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    comerror_t err = noError;
+    if ((*rprotolist_here).p != NULL) {
+      if ((*rprotolist_here).p->get_protocol_name (err) == "nullproto") {
+	(*rprotolist_here).p->remove_collection (collection, logout);
+	return;
+      }
+    }
+    ++rprotolist_here;
+  }
+
+  logout << "collectoraction::create_colserver: no valid nullproto found\n";
+}
+
+bool collectoraction::create_event_header_file (const text_t &filename, cgiargsclass &args, 
+						ostream &logout) {
+
+  outconvertclass text_t2ascii;
+  char *filenamec = filename.getcstr();
+  ofstream eheadfile (filenamec);
+  delete []filenamec;
+
+  if (eheadfile) {
+    eheadfile << text_t2ascii << get_event_header (args);
+    eheadfile.close();
+    return true;
+  }
+   
+  logout << text_t2ascii << "collectoraction::create_event_header ERROR: Couldn't create "
+	 << "Event Header file " << filename << ". Event logging disabled\n";
+  return false;
+}
+
+text_t collectoraction::get_event_header (cgiargsclass &args) {
+  text_t header = "Greenstone Username: " + args["un"] + "\n";
+  header += "Collection: " + args["bc1dirname"] + "\n";
+  header += "Collection Creator: " + args["bc1contactemail"] + "\n";
+  header += "GSDLHOME: " + gsdlhome + "\n";
+  header += "Build Location: " + get_collectdir(args) + "\n";
+
+  return header;
+}
+
+bool collectoraction::check_sources (cgiargsclass &args, ostream &logout) {
+
+  bool found = false;
+
+  text_tarray inputvalues;
+  splitchar (args["bc1input"].begin(), args["bc1input"].end(), ',', inputvalues);
+
+  text_tarray inputtypes;
+  splitchar (args["bc1inputtype"].begin(), args["bc1inputtype"].end(), ',', inputtypes);
+
+  int numvalues = inputvalues.size();
+  int numtypes = inputtypes.size();
+
+  for (int i = 0; i < numvalues; ++i) {
+    text_t value = format_url(decode_commas(inputvalues[i]));
+    text_t type = "file://"; // default
+    if (!value.empty()) {
+      found = true;
+      if (i >= numtypes || inputtypes[i].empty()) {
+	logout << "collectoraction::check_sources: WARNING type not set\n";
+      } else {
+	type = inputtypes[i];
+      }
+      if (type == "file://") {
+	if (!file_exists(value) && !directory_exists(value)) {
+	  failedsources[decode_commas(inputvalues[i])] = "1";
+	  badsources = true;
+	}
+      } else if (type == "http://") {
+	if (gsdl_system ("perl -S ping.pl -quiet http://" + value, true, logout)) {
+	  failedsources[decode_commas(inputvalues[i])] = "1";
+	  badsources = true;
+	}
+      } else if (type == "ftp://") {
+	if (gsdl_system ("perl -S ping.pl -quiet ftp://" + value, true, logout)) {
+	  failedsources[decode_commas(inputvalues[i])] = "1";
+	  badsources = true;
+	}
+      }
+    }
+  }
+
+  // set badsources if there weren't any sources at all
+  if (!found) badsources = true;
+
+  if (badsources) return false;
+  return true;
+}
+
+// format_url simply strips "http://", "ftp://", or "file://" off the
+// beginning of url if they're there
+text_t collectoraction::format_url (const text_t &url) {
+  text_t::const_iterator begin = url.begin();
+  text_t::const_iterator end = url.end();
+
+  if (url.size() >= 7) {
+    text_t prefix = substr(begin, begin+7);
+    if (prefix == "http://" || prefix == "file://") {
+      return substr(begin+7, end);
+    }
+  }
+  if (url.size() >= 6) {
+    if (substr(begin, begin+6) == "ftp://") {
+      return substr(begin+6, end);
+    }
+  }
+  return url;
+}
+
+text_t collectoraction::remove_trailing_slashes (text_t str) {
+
+  while (*(str.end()-1) == '\\') {
+    str.pop_back();
+  }
+  return str;
+}
+
+#endif //GSDL_USE_COLLECTOR_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/collectoraction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/collectoraction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/collectoraction.h	(revision 10506)
@@ -0,0 +1,137 @@
+/**********************************************************************
+ *
+ * collectoraction.h -- 
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_COLLECTOR_ACTION
+
+#ifndef COLLECTORACTION_H
+#define COLLECTORACTION_H
+
+#include "action.h"
+#include "receptionist.h"
+
+class collectoraction : public action {
+  
+protected:
+
+  bool disabled;
+  receptionist *recpt;
+  char *gsdlosc;
+  char *gsdlhomec;
+  char *pathc;
+
+  text_t message;
+  char failcode;
+
+  bool do_mkcol;
+
+  bool badsources;
+  text_tmap failedsources;
+
+  text_t get_button (const text_t &thispage, const text_t &color, 
+		     const text_t &type, bool enabled);
+
+  void set_fullnamemenu (displayclass &disp, cgiargsclass &args,
+			 recptprotolistclass *protos, ostream &logout);
+
+  void set_inputsourceboxes (displayclass &disp, cgiargsclass &args, 
+			     ostream &logout);
+
+  text_t get_source_box (text_t inputarglist, int numboxes, 
+			 text_t inputtypelist);
+
+  void set_cfgfile (displayclass &disp, cgiargsclass &args, ostream &logout);
+
+  void set_statusline (displayclass &disp, cgiargsclass &args, ostream &logout);
+
+  void update_cfgfile_clone (cgiargsclass &args, ostream &logout);
+
+  void update_cfgfile_partial (cgiargsclass &args, bool clone, ostream &logout);
+
+  void update_cfgfile_complete (cgiargsclass &args, ostream &logout);
+
+  text_t carriage_replace (const text_t &intext, int sw);
+
+  text_t get_directory_name (const text_t &fullname);
+
+  bool collection_protected (const text_t &collection);
+
+  bool assign_tmpname (cgiargsclass &args, ostream &logout);
+
+  void gsdl_mkcol (cgiargsclass &args, ostream &logout);
+
+  void gsdl_build (cgiargsclass &args, ostream &logout);
+
+  void gsdl_cancel_build (cgiargsclass &args, ostream &logout);
+
+  text_t get_collectdir (cgiargsclass &args);
+
+  bool uses_weird_plugin (const text_t &collection);
+
+  void create_colserver (const text_t &collection, ostream &logout);
+
+  void remove_colservr (const text_t &collection, ostream &logout);
+
+  bool create_event_header_file (const text_t &filename, cgiargsclass &args, 
+				 ostream &logout);
+
+  text_t get_event_header (cgiargsclass &args);
+
+  bool check_sources (cgiargsclass &args, ostream &logout);
+
+  text_t format_url (const text_t &url);
+
+  text_t remove_trailing_slashes (text_t str);
+
+public:
+  collectoraction ();
+  virtual ~collectoraction ();
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  bool init (ostream &logout);
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  text_t get_action_name () {return "collector";}
+
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      recptprotolistclass *protos, ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response,text_t &response_data, 
+			 ostream &logout);
+
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+};
+
+#endif //!COLLECTORACTION_H
+#endif //GSDL_USE_COLLECTOR_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/comproto.asn
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/comproto.asn	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/comproto.asn	(revision 10506)
@@ -0,0 +1,376 @@
+-- The protocol data unit (PDU) is the
+-- message that is transmitted between receptionists and
+-- collectionservers (colservers?).
+--
+-- Comments in ASN.1 start with two dashes and continue to the end
+-- of a line (or to the next two dashes, whichever is first).
+-- 
+-- Z39.50 has inspired much of this but I have tried to keep
+-- it simple. Its hard to tell if I have succeeded ;-)
+
+
+GSDL-APDU DEFINITIONS ::=
+BEGIN
+
+
+-- PDU is the basic message type. Note: in ASN.1 the
+-- field name comes first and the field type second (opposite
+-- to C). Ignore the numbers in the square brackets (e.g. [0]),
+-- they're just tags to disambiguate certain circumstances and to
+-- make the protocol easier to extend. The keyword 'IMPLICIT' just
+-- makes the tags a little more efficient.
+--
+-- A SEQUENCE is a list of fields where the order is important
+
+PDU ::= SEQUENCE {
+  header  StandardHeader,
+  message Message
+}
+
+
+-- ????? Is there anything else we want in the header ?????
+--
+-- Anonymous transactions should leave out the idAuthentication field
+
+StandardHeader ::= SEQUENCE {
+  protocolVersion       [0] IMPLICIT INTEGER,
+  idAuthentication      [1] IMPLICIT IdAuthentication OPTIONAL
+}
+
+IdAuthentication ::= SEQUENCE {
+  userId   GeneralString,
+  groupId  GeneralString,
+  password GeneralString
+}
+
+
+-- A CHOICE is like a union in C.
+-- 
+-- Short forms: Auth (Authority), Mir (Mirror), Col (Collection),
+--   Doc (Document), Info (Information)
+
+Message ::= CHOICE {
+  -- General
+  error                      [0]  IMPLICIT Error,
+  pingRequest                [1]  IMPLICIT PingRequest,
+  pingResponse               [2]  IMPLICIT PingResponse,
+
+  -- Authority
+--  authListRequest            [12] IMPLICIT AuthListRequest,
+--  authListResponse           [13] IMPLICIT AuthListResponse,
+--  editAuthListRequest        [14] IMPLICIT EditAuthListRequest,
+--  editAuthListResponse       [15] IMPLICIT EditAuthListResponse,
+
+  -- an authority mirror is a mirror of THIS authority
+--  authMirListRequest         [16] IMPLICIT AuthMirListRequest,
+--  authMirListResponse        [17] IMPLICIT AuthMirListResponse,
+--  editAuthMirListRequest     [18] IMPLICIT EditAuthMirListRequest,
+--  editAuthMirListResponse    [19] IMPLICIT EditAuthMirListResponse,
+
+  colListRequest             [20] IMPLICIT ColListRequest,
+  colListResponse            [21] IMPLICIT ColListResponse,
+--  editColListRequest         [22] IMPLICIT EditColListRequest,
+--  editColListResponse        [23] IMPLICIT EditColListResponse,
+
+--  colMirListRequest          [24] IMPLICIT ColMirListRequest,
+--  colMirListResponse         [25] IMPLICIT ColMirListResponse, 
+--  editColMirListRequest      [26] IMPLICIT EditColMirListRequest, 
+--  editColMirListResponse     [27] IMPLICIT EditColMirListResponse,
+
+  -- Collection
+  colInfoRequest             [40] IMPLICIT ColInfoRequest,
+  colInfoResponse            [41] IMPLICIT ColInfoResponse,
+
+  -- Document
+  documentRequest            [52] IMPLICIT DocumentRequest,
+  documentResponse           [53] IMPLICIT DocumentResponse,
+
+  -- Access (searching, browsing, and metadata information)
+  infoFiltersRequest         [60] IMPLICIT InfoFiltersRequest,
+  infoFiltersResponse        [61] IMPLICIT InfoFiltersResponse,
+  infoFilterOptionsRequest   [62] IMPLICIT InfoFilterOptionsRequest,
+  infoFilterOptionsResponse  [63] IMPLICIT InfoFilterOptionsResponse,
+  filterRequest              [64] IMPLICIT FilterRequest,
+  filterResponse             [65] IMPLICIT FilterResponse
+}
+
+
+
+-- ------------------------------
+-- GENERAL
+-- ------------------------------
+
+
+-- The error list is not complete yet ...
+
+Error ::= ENUMERATED {
+  authenticationFailure(0), protocolError(1), systemProblem(2)
+}
+
+
+PingRequest ::= SEQUENCE {
+}
+
+PingResponse ::= SEQUENCE {
+}
+
+
+
+-- ------------------------------
+-- AUTHORITY
+-- ------------------------------
+
+
+-- Support for subscription is optional for both the clients and
+-- the servers. It is recomended that it is not implemented yet
+-- for simplicity.
+
+-- AuthListRequest ::= SEQUENCE {
+-- }
+
+-- AuthListResponse ::= SEQUENCE {
+--   authList  [1] IMPLICIT StringSet
+-- }
+
+
+-- EditAuthListRequest ::= SEQUENCE {
+--   editAction EditAction,
+--   authority  GeneralString
+-- }
+
+-- EditAuthListResponse ::= SEQUENCE {
+-- }
+
+
+-- AuthMirListRequest ::= SEQUENCE {
+--   limitNumber [1] IMPLICIT INTEGER OPTIONAL,
+--   limitDomain [2] IMPLICIT GeneralString OPTIONAL
+-- }
+
+-- AuthMirListResponse ::= SEQUENCE {
+--   authMirList [1] IMPLICIT HostPortSet
+-- }
+
+
+-- EditAuthMirListRequest ::= SEQUENCE {
+--   editAction EditAction,
+--   authMir    HostPort
+-- }
+
+-- EditAuthMirListResponse ::= SEQUENCE {
+-- }
+
+
+ColListRequest ::= SEQUENCE {
+}
+
+ColListResponse ::= SEQUENCE {
+  colList   [1] IMPLICIT ShortColInfoSet
+}
+
+
+-- EditColListRequest ::= SEQUENCE {
+--   editAction EditAction,
+--   colInfo    ShortColInfo
+-- }
+
+-- EditColListResponse ::= SEQUENCE {
+-- }
+
+
+-- ColMirListRequest ::= SEQUENCE {
+--   limitNumber [1] IMPLICIT INTEGER OPTIONAL,
+--   limitDomain [2] IMPLICIT GeneralString OPTIONAL
+-- }
+
+-- ColMirListResponse ::= SEQUENCE {
+--   colMirList [1] IMPLICIT ShortColInfoSet
+-- }
+
+
+-- EditColMirListRequest ::= SEQUENCE {
+--   editAction EditAction,
+--   colMirInfo ShortColInfo
+-- }
+
+-- EditColMirListResponse ::= SEQUENCE {
+-- }
+
+
+
+
+-- ------------------------------
+-- COLLECTION
+-- ------------------------------
+
+
+ColInfoRequest ::= SEQUENCE {
+}
+
+ColInfoResponse ::= SEQUENCE {
+  shortInfo   [0] IMPLICIT ShortCollectionInfo,
+  isPublic    [2] IMPLICIT BOOLEAN,    -- whether has anonymous access
+  isBeta      [3] IMPLICIT BOOLEAN,    -- beta if still under development
+  builddate   [4] IMPLICIT GeneralizedTime,
+  languages   [5] IMPLICIT StringSet,  -- languages in the collection
+  numDocs     [6] IMPLICIT INTEGER,
+  numWords    [7] IMPLICIT INTEGER OPTIONAL,
+  numBytes    [8] IMPLICIT INTEGER OPTIONAL
+}
+
+
+
+-- ------------------------------
+-- DOCUMENT
+-- ------------------------------
+
+
+
+DocumentRequest ::= SEQUENCE {
+  OID       GeneralString,
+  docType   GeneralString,
+  docFormat GeneralString
+}
+
+DocumentResponse ::= SEQUENCE {
+  doc OCTET STRING
+}
+
+
+-- ------------------------------
+-- ACCESS (SEARCH AND BROWSE)
+-- ------------------------------
+
+
+-- filter options which might be supported for the QueryFilter
+--
+-- onePerQuery StartResults   integer
+-- onePerQuery EndResults     integer
+-- onePerQuery QueryType      enumerated (boolean, ranked)
+-- onePerTerm  Term           string ???
+-- onePerTerm  Casefold       boolean
+-- onePerTerm  Stem           boolean
+-- onePerTerm  Index          enumerated
+-- onePerTerm  Subcollection  enumerated
+--
+-- filter options which might be supported for the BrowseFilter
+--
+-- onePerQuery StartResults   integer
+-- onePerQuery EndResults     integer
+-- onePerQuery ParentNode     string ("" will return the browsing available)
+--
+-- The NullFilter always returns the set it was given, it doesn't have
+-- any options
+
+InfoFiltersRequest ::= SEQUENCE {
+}
+
+InfoFiltersResponse ::= SEQUENCE {
+  filterNames StringSet
+}
+
+InfoFilterOptionsRequest ::= SEQUENCE {
+  filterName GeneralString
+}
+
+InfoFilterOptionsResponse ::= SEQUENCE {
+  filterOptions SET OF FilterOption
+}
+
+FilterOption ::= SEQUENCE {
+  name         GeneralString,
+  type         ENUMERATED {booleant(0), integert(1), enumeratedt(2), stringt(3)},
+  repeatable   ENUMERATED {onePerQuery(0), onePerTerm(1), nPerTerm(2)},
+  defaultValue GeneralString,
+  -- the interpretation of the validValues depends on the type
+  -- for boolean: the first value is the false value, the second is true value
+  -- for integer: the first value is the minimum, the second the maximum
+  -- for enumerated: all values a listed
+  -- for string: this value is ignored
+  validValues  StringSequence
+}
+
+
+-- Terms are presented in the same order that they are requested,
+-- any information relating to the terms is in reference to the
+-- index specified for that term.
+-- Metadata is presented in the same order that it is requested.
+
+FilterRequest ::= SEQUENCE {
+  filterName          [0] GeneralString,
+  filterOptions       [1] IMPLICIT SEQUENCE OF OptionValue,
+  docSet              [2] IMPLICIT StringSequence, -- the OID "" represents everything
+  filterResultOptions [3] IMPLICIT BIT STRING {termFreq(0), matchTerms(1), OID(2), 
+                                               subCol(3), ranking(4), docFreq(5), 
+                                               metadata(6)}
+
+  -- the next set of options are for the metadata request, 
+  -- they can be left blank if metadata is not wanted
+  requestParams       [4] IMPLICIT GeneralString, -- used to negotiate the metadata content
+  refParams           [5] IMPLICIT GeneralString, -- used to decide whether to return a 
+                                                  -- reference to the data or the actual data
+  fields              [6] IMPLICIT StringSequence
+}
+
+OptionValue ::= SEQUENCE {
+  name  GeneralString,
+  value GeneralString
+}
+
+FilterResponse ::= SEQUENCE {
+  numDocs   [0] IMPLICIT INTEGER,
+  isApprox  [1] IMPLICIT BOOLEAN,                  -- whether numDocs is approximate
+  termInfo  [2] IMPLICIT SEQUENCE OF TermInfo,     -- empty if not required
+  docInfo   [3] IMPLICIT SEQUENCE OF ResultDocInfo -- empty if not required
+}
+
+TermInfo ::= SEQUENCE {
+  term       [0] GeneralString,
+  freq       [1] IMPLICIT INTEGER,       -- 0 if not requested
+  matchTerms [2] IMPLICIT StringSequence -- empty if not requested
+}
+
+ResultDocInfo ::= SEQUENCE {
+  OID      [0] IMPLICIT GeneralString,
+  ranking  [1] IMPLICIT INTEGER,             -- 0 if not requested, range 0-10000
+  docFreq  [2] IMPLICIT SEQUENCE OF INTEGER, -- empty if not requested
+  metadata [3] IMPLICIT SEQUENCE OF MetadataInfo
+}
+
+
+MetadataInfo ::= SEQUENCE {
+  params  [0] IMPLICIT GeneralString,
+  isRef   [1] IMPLICIT BOOLEAN,
+  field   [3] IMPLICIT GeneralString,
+  value   [4] IMPLICIT GeneralString
+}
+
+
+-- ------------------------------
+-- Useful Types
+-- ------------------------------
+
+-- HostPortSet ::= SET OF HostPort
+
+-- HostPort ::= SEQUENCE {
+--   host [0] IMPLICIT GeneralString,
+--   port [1] IMPLICIT INTEGER
+-- }
+
+ShortColInfoSet ::= SET OF ShortColInfo
+
+ShortColInfo ::= SEQUENCE {
+  name GeneralString,
+  host GeneralString,
+  port INTEGER
+}
+
+-- EditAction ::= ENUMERATED {
+--   update(0), delete(1)
+-- }
+
+StringSequence ::= SEQUENCE OF GeneralString
+StringSet ::= SET OF GeneralString
+
+
+END
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/comtypes.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/comtypes.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/comtypes.cpp	(revision 10506)
@@ -0,0 +1,287 @@
+/**********************************************************************
+ *
+ * comtypes.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "comtypes.h"
+
+
+text_t get_comerror_string (comerror_t err) {
+  if (err == noError) return "no error";
+  else if (err == authenticationFailure) return "authentication failure";
+  else if (err == protocolError) return "protocol error";
+  else if (err == configurationError) return "configuration error";
+  else if (err == systemProblem) return "system problem";
+  else if (err == syntaxError) return "query syntax error";
+  return "unknown problem";
+}
+
+
+void ShortColInfo_t::clear() {
+  name.clear();
+  host.clear();
+  port = 0;
+}
+
+/*
+   isPublic now defaults to true  most values are default          
+   similar to a constructor in a class to make some initializations
+*/
+
+void ColInfoResponse_t::clear () {
+  shortInfo.clear();
+  isPublic=true;
+  isBeta=false;
+  isSegmented=false;
+  languages.erase(languages.begin(), languages.end());
+  ccsCols.erase(ccsCols.begin(), ccsCols.end());
+  buildDate=0;
+  buildType.clear();
+  searchTypes.erase(searchTypes.begin(), searchTypes.end());
+  numDocs=0;
+  numSections=0;
+  numWords=0;
+  numBytes=0;
+  format.erase(format.begin(), format.end());
+  building.erase(format.begin(), format.end());
+  httpdomain.clear();
+  httpprefix.clear();
+  receptionist.clear();
+
+  // Setting some authentication parameters use with
+  // various parts of the code.
+  
+  authenticate.clear();         // turned off by default, individual collection authentication
+  auth_group.clear();              // turned off by default, authentication by groups method
+  public_documents.clear();          // turned off by default, allow access to these documents <list>
+  private_documents.clear();           // turned off by default, disallow access to these documents <list>
+    
+}
+
+text_t ColInfoResponse_t::get_collectionmeta(text_t name, text_t lang) {
+  text_t value = collectionmeta[name][lang];
+  if (value.empty()) {
+    value = collectionmeta[name][g_EmptyText];
+  }
+  return value;
+
+}
+
+void InfoFiltersResponse_t::clear () {
+  filterNames.erase(filterNames.begin(), filterNames.end());
+}
+
+
+void InfoFilterOptionsRequest_t::clear () {
+  filterName.clear();
+}
+
+
+void FilterOption_t::clear () {
+  name.clear();
+  type = booleant;
+  repeatable = onePerQuery;
+  defaultValue.clear();
+  validValues.erase(validValues.begin(), validValues.end());
+}
+
+void FilterOption_t::check_defaultValue () {
+  text_tarray::iterator here, end;
+
+  // how the default is interpreted depends on the option type
+  switch (type) {
+  case booleant: 
+  case enumeratedt: // has to be one of the validValues
+    here = validValues.begin ();
+    end = validValues.end ();
+    while (here != end) {
+      if (*here == defaultValue) return;
+      ++here;
+    }
+    
+    break;
+
+  case integert: // has to be in the validValues range
+    if ((validValues.size() >= 2) &&
+	(validValues[0].getint() <= defaultValue.getint()) &&
+	(validValues[1].getint() >= defaultValue.getint()))
+      return;
+    break;
+
+  case stringt: // any value is valid
+    return; 
+  }
+
+  // did not find the defaultValue
+  if (validValues.empty()) defaultValue.clear();
+  else defaultValue = validValues[0];
+}
+
+
+bool operator==(const FilterOption_t &x, const FilterOption_t &y) {
+  return ((x.name == y.name) &&
+	  (x.type == y.type) &&
+	  (x.repeatable == y.repeatable) &&
+	  (x.defaultValue == y.defaultValue) &&
+	  (x.validValues == y.validValues));
+}
+
+bool operator<(const FilterOption_t &x, const FilterOption_t &y) {
+  return ((x.name < y.name) ||
+	  ((x.name == y.name) &&
+	   ((x.type < y.type) ||
+	    ((x.type == y.type) &&
+	     ((x.repeatable < y.repeatable) ||
+	      ((x.repeatable == y.repeatable) &&
+	       ((x.defaultValue < y.defaultValue) ||
+		((x.defaultValue == y.defaultValue) &&
+		 (x.validValues < y.validValues)))))))));
+}
+
+
+
+void InfoFilterOptionsResponse_t::clear () {
+  filterOptions.erase(filterOptions.begin(), filterOptions.end());
+}
+
+
+void OptionValue_t::clear () {
+  name.clear();
+  value.clear();
+}
+
+
+void FilterRequest_t::clear () {
+  filterName.clear();
+  filterLang.clear();
+  filterOptions.erase(filterOptions.begin(), filterOptions.end());
+  docSet.erase(docSet.begin(), docSet.end());
+  filterResultOptions = 0;
+  requestParams.clear();
+  refParams.clear();
+  fields.erase(fields.begin(), fields.end());
+  getParents = false;
+}
+
+
+void TermInfo_t::clear () {
+  term.clear();
+  freq = 0;
+  matchTerms.erase (matchTerms.begin(), matchTerms.end());
+}
+
+
+void MetadataInfo_t::clear () {
+  params.clear();
+  isRef = false;
+  values.erase(values.begin(), values.end());
+  if (parent != NULL) {
+    delete parent;
+    parent = NULL;
+  }
+}
+
+MetadataInfo_t::MetadataInfo_t () {parent=NULL;clear();}
+
+// copy constructor
+MetadataInfo_t::MetadataInfo_t (const MetadataInfo_t &x) {
+  params = x.params;
+  isRef = x.isRef;
+  values = x.values;
+  if (x.parent == NULL) parent = NULL;
+  else {
+    parent = new MetadataInfo_t ();
+    *parent = *(x.parent);
+  }
+}
+
+MetadataInfo_t::~MetadataInfo_t () {
+  if (parent != NULL) {
+    delete parent;
+    parent = NULL;
+  }
+}
+
+MetadataInfo_t &MetadataInfo_t::operator=(const MetadataInfo_t &x) {
+  if (&x != this) {
+    params = x.params;
+    isRef = x.isRef;
+    values = x.values;
+    if (x.parent == NULL) parent = NULL;
+    else {
+      parent = new MetadataInfo_t ();
+      *parent = *(x.parent);
+    }
+  }
+  return *this;
+}
+
+void ResultDocInfo_t::clear () {
+  OID.clear ();
+  ranking = 0;
+  result_num = 0;
+  num_terms_matched = 0;
+  num_phrase_match = 0;
+  docFreq.erase(docFreq.begin(), docFreq.end());
+  metadata.erase(metadata.begin(), metadata.end());
+  classifier_metadata_type.erase(classifier_metadata_type.begin(), 
+				 classifier_metadata_type.end());
+  classifier_metadata_offset = 0;
+  
+}
+
+ResultDocInfo_t &ResultDocInfo_t::operator=(const ResultDocInfo_t &x) {
+  OID = x.OID; 
+  ranking = x.ranking;
+  result_num = x.result_num;
+  num_terms_matched = x.num_terms_matched;
+  num_phrase_match = x.num_phrase_match;
+  docFreq = x.docFreq; 
+  metadata = x.metadata;
+  return *this;
+}
+
+void FilterResponse_t::clear () {
+  numDocs = 0;
+  isApprox = Exact;
+  termInfo.erase (termInfo.begin(), termInfo.end());
+  docInfo.erase (docInfo.begin(), docInfo.end());
+}
+
+FilterResponse_t &FilterResponse_t::operator=(const FilterResponse_t &x) {
+  numDocs = x.numDocs;
+  isApprox = x.isApprox;
+  termInfo = x.termInfo;
+  docInfo = x.docInfo;
+  return *this;
+}
+
+void DocumentRequest_t::clear () {
+  OID.clear();
+  docType.clear();
+  docFormat.clear();
+}
+
+void DocumentResponse_t::clear () {
+  doc.clear();
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/comtypes.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/comtypes.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/comtypes.h	(revision 10506)
@@ -0,0 +1,367 @@
+/**********************************************************************
+ *
+ * comtypes.h -- 
+ * Copyright (C) 1999,2004  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef COMTYPES_H
+#define COMTYPES_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#  include <ospace\std\list>
+#  include <ospace\std\memory> // for pair
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#  include <list.h>
+#  include <memory.h> // for pair
+#  include <map.h>
+#else
+#  include <vector>
+#  include <list>
+#  include <memory> // for pair
+#  include <map>
+#endif
+
+
+enum comerror_t {noError, authenticationFailure, protocolError, 
+		 configurationError, systemProblem, syntaxError};
+text_t get_comerror_string (comerror_t err);
+
+// ShortColInfo ::= SEQUENCE {
+//   name GeneralString,
+//   host GeneralString,
+//   port INTEGER
+// }
+struct ShortColInfo_t {
+  void clear ();
+  ShortColInfo_t () {clear();}
+
+  text_t name;
+  text_t host;
+  int port;
+};
+
+/* macro name -> (params, value) */
+typedef multimap<text_t, pair<text_t, text_t>, less<text_t> > macros_map;
+
+typedef map<text_t, text_tmap, lttext_t> collectionmeta_map; // maps meta name to langmap
+
+struct ColInfoResponse_t {
+  void clear ();
+  ColInfoResponse_t () {clear();} 
+  text_t get_collectionmeta(text_t name, text_t lang);
+  
+  ShortColInfo_t shortInfo;
+  bool isPublic;
+  bool isBeta;
+  bool isSegmented;
+  unsigned long buildDate;
+  text_tarray ccsCols;    // empty if collection does not use cross-collection searching
+  text_tarray languages;
+  unsigned long numDocs;     // 0 if not known
+  unsigned long numSections; // 0 if not known
+  unsigned long numWords;    // 0 if not known
+  unsigned long numBytes;    // 0 if not known
+  //text_tmap      collectionmeta;
+  collectionmeta_map  collectionmeta;
+  text_tmap      format;
+  macros_map	 collection_macros; // for collectionmacro config directive (> gsdl 2.53)
+  text_tmap      building;
+  text_t         httpdomain;      // GRB: could these two http items need removing
+  text_t         httpprefix;
+  text_t         receptionist;
+  text_t         buildType;           // 'mg' or 'mgpp' or 'lucene'
+  text_t         authenticate;      // 'document' or 'collection'
+  text_t         auth_group;          // 'mygroup' 'yourgroup'
+  text_tmap      public_documents;    // the acl to allow access to listed documents
+  text_tmap      private_documents;   // the acl to disallow access to listed documents
+  text_tarray    searchTypes; // form, plain, empty if collection uses mg, or has no searching facility
+};
+
+
+// -- filter options which might be supported for the QueryFilter
+// --
+// -- onePerQuery StartResults   integer
+// -- onePerQuery EndResults     integer
+// -- onePerQuery QueryType      enumerated (boolean, ranked)
+// -- onePerTerm  Term           string ???
+// -- onePerTerm  Casefold       boolean
+// -- onePerTerm  Stem           boolean
+// -- onePerTerm  Index          enumerated
+// -- onePerTerm  Subcollection  enumerated
+// --
+// -- filter options which might be supported for the BrowseFilter
+// --
+// -- onePerQuery StartResults   integer
+// -- onePerQuery EndResults     integer
+// -- onePerQuery ParentNode     string ("" will return the browsing available)
+// --
+// -- The NullFilter always returns the set it was given, it doesn't have
+// -- any options
+
+// InfoFiltersResponse ::= SEQUENCE {
+//   filterNames StringSet
+// }
+struct InfoFiltersResponse_t {
+  void clear ();
+
+  text_tset filterNames;
+};
+
+// InfoFilterOptionsRequest ::= SEQUENCE {
+//   filterName GeneralString
+// }
+struct InfoFilterOptionsRequest_t {
+  void clear ();
+
+  text_t filterName;
+};
+
+// FilterOption ::= SEQUENCE {
+//   name         GeneralString,
+//   type         ENUMERATED {booleant(0), integert(1), enumeratedt(2), stringt(3)},
+//   repeatable   ENUMERATED {onePerQuery(0), onePerTerm(1), nPerTerm(2)},
+//   defaultValue GeneralString,
+//   -- the interpretation of the validValues depends on the type
+//   -- for boolean: the first value is the false value, the second is true value
+//   -- for integer: the first value is the minimum, the second the maximum
+//   -- for enumerated: all values a listed
+//   -- for string: this value is ignored
+//   validValues  StringSequence
+// }
+struct FilterOption_t {
+  void clear ();
+  void check_defaultValue ();
+  FilterOption_t () {clear();}
+
+  text_t name;
+
+  enum type_t {booleant=0, integert=1, enumeratedt=2, stringt=3};
+  type_t type;
+
+  enum repeatable_t {onePerQuery=0, onePerTerm=1, nPerTerm=2};
+  repeatable_t repeatable;
+
+  text_t defaultValue;
+  text_tarray validValues;
+};
+
+bool operator==(const FilterOption_t &x, const FilterOption_t &y);
+bool operator<(const FilterOption_t &x, const FilterOption_t &y);
+
+
+typedef map<text_t, FilterOption_t, lttext_t> FilterOption_tmap;
+
+
+// InfoFilterOptionsResponse ::= SEQUENCE {
+//   filterOptions SET OF FilterOption
+// }
+struct InfoFilterOptionsResponse_t {
+  void clear ();
+
+  FilterOption_tmap filterOptions;
+};
+
+
+// OptionValue ::= SEQUENCE {
+//   name  GeneralString,
+//   value GeneralString
+// }
+struct OptionValue_t {
+  void clear ();
+
+  text_t name;
+  text_t value;
+};
+
+typedef vector<OptionValue_t> OptionValue_tarray;
+
+
+// -- Terms are presented in the same order that they are requested,
+// -- any information relating to the terms is in reference to the
+// -- index specified for that term.
+//
+// FilterRequest ::= SEQUENCE {
+//   filterName          [0] GeneralString,
+//   filterOptions       [1] IMPLICIT SEQUENCE OF OptionValue,
+//   docSet              [2] IMPLICIT StringSequence, -- the OID "" represents everything
+//   filterResultOptions [3] IMPLICIT BIT STRING {termFreq(0), matchTerms(1), OID(2), 
+//                                                subCol(3), ranking(4), docFreq(5), 
+//                                                metadata(6)}
+// 
+//   -- the next set of options are for the metadata request, 
+//   -- they can be left blank if metadata is not wanted
+//   requestParams       [4] IMPLICIT GeneralString, -- used to negotiate the metadata content
+//   refParams           [5] IMPLICIT GeneralString, -- used to decide whether to return a 
+//                                                   -- reference to the data or the actual data
+//   fields              [6] IMPLICIT StringSet
+//   getParents          [7] IMPLICIT BOOLEAN        -- gets metadata of all parents too
+// }
+#define FRtermFreq   1
+#define FRmatchTerms 2
+#define FROID        4
+#define FRsubCol     8
+#define FRranking    16
+#define FRdocFreq    32
+#define FRmetadata   64
+// used to indicate a full text browse query for mgpp
+#define FRfullTextBrowse  128
+
+struct FilterRequest_t {
+  void clear ();
+  FilterRequest_t () {clear();}
+
+  text_t filterName;
+  text_t filterLang; // non empty if we want info to be retrived in language specific
+  OptionValue_tarray filterOptions;
+  text_tarray docSet;        // empty if not used
+  int filterResultOptions; // use the FR* defines above
+
+  text_t requestParams; // empty if not used
+  text_t refParams;     // empty if not used
+  text_tset fields;   // empty if not used
+  bool getParents;      // defaults to false
+};
+
+
+// TermInfo ::= SEQUENCE {
+//   term       [0] GeneralString,
+//   freq       [1] IMPLICIT INTEGER,       -- 0 if not requested
+//   matchTerms [2] IMPLICIT StringSequence -- empty if not requested
+// }
+struct TermInfo_t {
+  void clear ();
+  TermInfo_t () {clear();}
+
+  text_t term;
+  int freq; // 0 if not requested
+  text_tarray matchTerms; // empty if not requested
+};
+
+typedef vector<TermInfo_t> TermInfo_tarray;
+
+
+// MetadataInfo ::= SEQUENCE {
+//   params  [0] IMPLICIT GeneralString,
+//   isRef   [1] IMPLICIT BOOLEAN,
+//   values  [3] IMPLICIT SEQUENCE OF GeneralString,
+//   name    [4] IMPLICIT GeneralString
+// }
+struct MetadataInfo_t {
+  text_t params;
+  bool isRef;
+  text_tarray values;
+  MetadataInfo_t *parent;
+
+  void clear ();
+  MetadataInfo_t ();
+  MetadataInfo_t (const MetadataInfo_t &x); // copy constructor
+  ~MetadataInfo_t ();
+  MetadataInfo_t &operator=(const MetadataInfo_t &x);
+};
+
+typedef map<text_t, MetadataInfo_t, lttext_t> MetadataInfo_tmap;
+
+// ResultDocInfo ::= SEQUENCE {
+//   OID      [0] IMPLICIT GeneralString,
+//   ranking  [1] IMPLICIT INTEGER,             -- 0 if not requested, range 0-10000
+//   docFreq  [2] IMPLICIT SEQUENCE OF INTEGER, -- empty if not requested
+//   metadata [3] IMPLICIT SEQUENCE OF MetadataInfo, -- no longer a SEQUENCE (SET maybe??)
+//   classifier_metadata_type   [4] IMPLICIT GeneralString,       -- empty if not requested
+//   classifier_metadata_offset [5] IMPLICIT INTEGER,             -- 0 if not requested
+// }
+struct ResultDocInfo_t {
+  void clear ();
+  ResultDocInfo_t () {clear();}
+
+  text_t OID;
+  int result_num;          // place in results list
+  int ranking;             // 0 if not requested (real ranking*10000)
+  int num_terms_matched;   // not available on all versions of mg
+  int num_phrase_match;    // not available on all versions of mg
+  vector<int> docFreq;           // empty if not requested
+  MetadataInfo_tmap metadata;    // empty if not requested
+  text_t classifier_metadata_type;        // empty if not requested
+  int    classifier_metadata_offset;      // 0 if not requested
+  ResultDocInfo_t &operator=(const ResultDocInfo_t &x);
+};
+
+typedef vector<ResultDocInfo_t> ResultDocInfo_tarray;
+
+
+// FilterResponse ::= SEQUENCE {
+//   numDocs   [0] IMPLICIT INTEGER,
+//   isApprox  [1] ENUMERATED {Exact(0), Approximate(1), MoreThan(2)}, -- whether numDocs is approximate
+//   termInfo  [2] IMPLICIT SEQUENCE OF TermInfo,                      -- empty if not required
+//   docInfo   [3] IMPLICIT SEQUENCE OF ResultDocInfo                  -- empty if not required
+// }
+
+enum isapprox {Exact=0, Approximate=1, MoreThan=2};
+
+struct FilterResponse_t {
+  void clear ();
+  FilterResponse_t () {clear();}
+
+  int numDocs;
+  isapprox isApprox;
+  TermInfo_tarray termInfo; // empty if not requested
+  ResultDocInfo_tarray docInfo; // empty if not requested
+
+  FilterResponse_t &operator=(const FilterResponse_t &x);
+};
+
+
+// DocumentRequest ::= SEQUENCE {
+//   OID       GeneralString,
+//   docType   GeneralString,
+//   docFormat GeneralString
+// }
+struct DocumentRequest_t {
+  void clear ();
+  DocumentRequest_t () {clear();}
+
+  text_t OID;
+  text_t docType;
+  text_t docFormat;
+};
+
+
+// DocumentResponse ::= SEQUENCE {
+//   doc OCTET STRING
+// }
+
+struct DocumentResponse_t {
+  void clear ();
+  DocumentResponse_t () {clear();}
+
+  text_t doc;
+};
+
+
+#endif
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/configaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/configaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/configaction.cpp	(revision 10506)
@@ -0,0 +1,152 @@
+/**********************************************************************
+ *
+ * configaction.cpp -- 
+ * Copyright (C) 2003 DL Consulting Ltd
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#include "configaction.h"
+#include "recptconfig.h"
+
+#ifdef GSDL_LOCAL_LIBRARY
+// for PostMessage()
+#  include <windows.h>
+#endif
+
+configaction::configaction () {
+
+  recpt = NULL;
+
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "config";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  /* 
+     The cmd argument may be one of the following:
+     -- release-collection - release the collection specified by the "c"
+        argument
+     -- add-collection - add and configure a collection server for the
+        collection specified by the "c" argument
+     -- kill - if running as the local library this will kill the server
+  */
+  arg_ainfo.shortname = "cmd";
+  arg_ainfo.longname = "config command";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+configaction::~configaction () {
+}
+
+void configaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+				     response_t &response, text_t &response_data, 
+				     ostream &logout) {
+  response = content;
+  response_data = "text/html";
+}
+
+bool configaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			      browsermapclass *browsers, displayclass &disp,
+			      outconvertclass &outconvert, ostream &textout,
+			      ostream &logout) {
+
+  if (recpt == NULL) return false;
+
+  if ((args["cmd"] == "add-collection") && (!args["c"].empty())) {
+    create_colservr(args["c"], logout);
+    textout << "configured add-collection\n";
+
+  } else if ((args["cmd"] == "release-collection") && (!args["c"].empty())) {
+    remove_colservr(args["c"], logout);
+    textout << "configured release-collection\n";
+
+  } else if (args["cmd"] == "kill") {
+    textout << "killed\n";
+#ifdef GSDL_LOCAL_LIBRARY
+    HWND gw = FindWindow("Greenstone Digital Library Software",
+			 "Greenstone Digital Library Software");
+    PostMessage(gw, WM_DESTROY, 0, 0);
+#endif
+  }
+
+  return true;
+}
+
+
+// create and initialize a new collection server and
+// add it to the null protocol.
+void configaction::create_colservr (const text_t &collection, ostream &logout) {
+
+  // just in case we're adding a collection that already exists
+  recpt->uncache_collection(collection);
+
+  recptprotolistclass *protos = recpt->get_recptprotolist_ptr();
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    comerror_t err = noError;
+    if ((*rprotolist_here).p != NULL) {
+      if ((*rprotolist_here).p->get_protocol_name(err) == "nullproto") {
+	// create collection server and add it to nullproto
+	(*rprotolist_here).p->add_collection(collection, recpt, gsdlhome, gsdlhome);
+	// re-initialize the null protocol
+	if (!(*rprotolist_here).p->init(err, logout)) {
+	  logout << "configaction::create_colservr: nullproto init failed\n";
+	}
+	return;
+      }
+    }
+    ++rprotolist_here;
+  }
+
+  logout << "configaction::create_colservr: no valid nullproto found\n";
+}
+
+// delete a collection server from the null protocol
+void configaction::remove_colservr (const text_t &collection, ostream &logout) {
+
+  recpt->uncache_collection(collection);
+
+  recptprotolistclass *protos = recpt->get_recptprotolist_ptr();
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    comerror_t err = noError;
+    if ((*rprotolist_here).p != NULL) {
+      if ((*rprotolist_here).p->get_protocol_name(err) == "nullproto") {
+	(*rprotolist_here).p->remove_collection(collection, logout);
+	return;
+      }
+    }
+    ++rprotolist_here;
+  }
+
+  logout << "configaction::create_colserver: no valid nullproto found\n";
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/configaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/configaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/configaction.h	(revision 10506)
@@ -0,0 +1,60 @@
+/**********************************************************************
+ *
+ * configaction.h -- 
+ * Copyright (C) 2003 DL Consulting Ltd
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef CONFIGACTION_H
+#define CONFIGACTION_H
+
+#include "action.h"
+#include "receptionist.h"
+
+class configaction : public action {
+
+protected:
+  receptionist *recpt;
+
+  void create_colservr (const text_t &collection, ostream &logout);
+  void remove_colservr (const text_t &collection, ostream &logout);
+
+public:
+  configaction ();
+  virtual ~configaction ();
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  text_t get_action_name () {return "config";}
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp,
+		  outconvertclass &outconvert, ostream &textout,
+		  ostream &logout);
+};
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/converter.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/converter.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/converter.cpp	(revision 10506)
@@ -0,0 +1,77 @@
+/**********************************************************************
+ *
+ * converter.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "converter.h"
+
+
+
+// the converters within converterinfo become the property of this class
+// after add_converter has been called. The converters remain the
+// responsability of the calling code and will not be deleted by this
+// class.
+void convertinfoclass::add_converter (const text_t &name, inconvertclass *inconverter,
+				      rzwsoutconvertclass *outconverter) {
+  // can't add a null converter or an action with no name
+  if (inconverter == NULL || outconverter == NULL || name.empty()) {
+    return;
+  }
+
+  converterinfo info;
+  info.name = name;
+  info.inconverter = inconverter;
+  info.outconverter = outconverter;
+  converters[name] = info;
+}
+
+
+bool operator==(const converterinfo &x, const converterinfo &y) {
+  return ((x.name == y.name) && (x.inconverter == y.inconverter) &&
+	  (x.outconverter == y.outconverter));
+}
+
+bool operator<(const converterinfo &x, const converterinfo &y) {
+  return ((x.name < y.name) ||
+	  ((x.name == y.name) &&
+	   ((x.inconverter < y.inconverter) ||
+	    ((x.inconverter == y.inconverter) &&
+	     ((x.outconverter < y.outconverter))))));
+}
+
+
+// get_inconverter will return NULL if the convert could not be found
+inconvertclass *convertinfoclass::get_inconverter (const text_t &name) {
+  iterator here = converters.find (name);
+  if (here == converters.end()) return NULL;
+
+  return (*here).second.inconverter;
+}
+
+// get_outconverter will return NULL if the convert could not be found
+rzwsoutconvertclass *convertinfoclass::get_outconverter (const text_t &name) {
+  iterator here = converters.find (name);
+  if (here == converters.end()) return NULL;
+
+  return (*here).second.outconverter;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/converter.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/converter.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/converter.h	(revision 10506)
@@ -0,0 +1,122 @@
+/**********************************************************************
+ *
+ * converter.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef CONVERTER_H
+#define CONVERTER_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "gsdlunicode.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\map>
+#elif defined(GSDL_USE_STL_H)
+#  include <map.h>
+#else
+#  include <map>
+#endif
+
+
+// inconverter and outconverter ARE NOT destroyed by this class
+// they should be destroyed by the code which created them after
+// no more pointers to the class exist.
+//
+// The above condition enables the class to be copied without
+// copying the converters which might contain a lot of data (and
+// be of an unknown derived type).
+class converterinfo {
+public:
+  text_t name;
+  inconvertclass *inconverter;
+  rzwsoutconvertclass *outconverter;
+
+  converterinfo() {inconverter=NULL; outconverter=NULL;}
+};
+
+bool operator==(const converterinfo &x, const converterinfo &y);
+bool operator<(const converterinfo &x, const converterinfo &y);
+
+
+typedef map<text_t, converterinfo, lttext_t> convertmap;
+
+// convertinfoclass is used to store a number of converters
+// indexing them by their name
+class convertinfoclass {
+protected:
+  convertmap converters;
+
+public:
+  // type support for convertmap
+  typedef convertmap::iterator iterator;
+  typedef convertmap::const_iterator const_iterator;
+  typedef convertmap::reference reference;
+  typedef convertmap::const_reference const_reference;
+  typedef convertmap::size_type size_type;
+  typedef convertmap::difference_type difference_type;
+  typedef convertmap::const_reverse_iterator const_reverse_iterator;
+  typedef convertmap::reverse_iterator reverse_iterator;
+  
+  // constructors
+  convertinfoclass () {}
+
+  // basic container support
+  iterator begin () {return converters.begin();}
+  const_iterator begin () const {return converters.begin();}
+  iterator end () {return converters.end();}
+  const_iterator end () const {return converters.end();}
+
+  void erase(iterator pos) {converters.erase(pos);}
+  void erase(iterator first, iterator last) {converters.erase(first, last);}
+  convertinfoclass &operator=(const convertinfoclass &x) 
+    {converters=x.converters;return *this;}
+
+  bool empty () const {return converters.empty();}
+  size_type size() const {return converters.size();}
+
+  const_iterator find(const text_t &key) {return converters.find(key);}
+
+  // added functionality
+  void clear () {converters.erase(converters.begin(),converters.end());}
+
+  // the converters within converterinfo become the property of
+  // of this class after add_converter has been called. The converters
+  // remain the responsability of the calling code and will not be
+  // deleted by this class.
+  void add_converter (const text_t &name, inconvertclass *inconverter,
+		      rzwsoutconvertclass *outconverter);
+
+  // get_inconverter will return NULL if the convert could not be found
+  inconvertclass *get_inconverter (const text_t &name);
+
+  // get_outconverter will return NULL if the convert could not be found
+  rzwsoutconvertclass *get_outconverter (const text_t &name);
+};
+
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/corbaclient.mpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/corbaclient.mpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/corbaclient.mpp	(revision 10506)
@@ -0,0 +1,162 @@
+/**********************************************************************
+ *
+ * corbaclient.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+#include "receptionist.h"
+#include "cgiwrapper.h"
+#include "corbaproto.h"
+#include "collectserver.h"
+#include "filter.h"
+#include "browsefilter.h"
+#include "queryfilter.h"
+#include "infodbclass.h"
+#include "mgsearch.h"
+#include "mggdbmsource.h"
+#include "fileutil.h"
+#include <assert.h>
+
+#include "action.h"
+#include "statusaction.h"
+#include "pageaction.h"
+#include "pingaction.h"
+#include "queryaction.h"
+#include "documentaction.h"
+#include "authenaction.h"
+#include "usersaction.h"
+#include "authenaction.h"
+#include "extlinkaction.h"
+#include "tipaction.h"
+#include "collectoraction.h"
+
+#include "browserclass.h"
+#include "vlistbrowserclass.h"
+#include "hlistbrowserclass.h"
+#include "datelistbrowserclass.h"
+#include "invbrowserclass.h"
+#include "pagedbrowserclass.h"
+#include "htmlbrowserclass.h"
+
+// #include "gsdlhome.h"
+#include "recptconfig.h"
+
+int main (int argc, char *argv[]) {
+  receptionist recpt;
+  corbaproto*  cproto_array[argc];
+  text_t       gsdlhome;
+  text_t       httpdomain;
+  text_t       httpprefix;
+  
+  cproto_array[0] = NULL; // unused
+
+  if (argc == 1)
+  { cout << "Content-type: text/html" << endl << endl;
+    cout << "Usage: " << argv[0] << "site1.objid [site2.objid ....]" << endl;
+    return 0;
+  }
+
+  // Strictly speaking httpdomain and httpprefix are not needed.
+  // Need to modifiy site_cfg_read to eliminate this dependency. // ****
+  site_cfg_read(gsdlhome, httpdomain, httpprefix);
+
+  for (int i=1; i<argc; i ++)
+    {
+      // add the protocol to the receptionist
+      cproto_array[i] = new corbaproto(argv[i]);
+      recpt.add_protocol(cproto_array[i]);
+    }
+
+//  cout << "GRB 2" << endl;
+
+  // the list of actions. Note: these actions will become invalid
+  // at the end of this function.
+  tipaction atipaction;
+  recpt.add_action(&atipaction);
+
+  statusaction astatusaction;
+  astatusaction.set_receptionist (&recpt);
+  recpt.add_action (&astatusaction);
+
+  pageaction apageaction;
+  apageaction.set_receptionist (&recpt);
+  recpt.add_action (&apageaction);
+
+  pingaction apingaction;
+  recpt.add_action (&apingaction);
+
+  queryaction aqueryaction;
+  aqueryaction.set_receptionist (&recpt);
+  recpt.add_action (&aqueryaction);
+
+  documentaction adocumentaction;
+  adocumentaction.set_receptionist (&recpt);
+  recpt.add_action (&adocumentaction);
+
+  usersaction ausersaction;
+  recpt.add_action (&ausersaction);
+
+  extlinkaction anextlinkaction;
+  recpt.add_action (&anextlinkaction);
+
+  authenaction aauthenaction;
+  aauthenaction.set_receptionist(&recpt);
+  recpt.add_action (&aauthenaction);
+
+  collectoraction acollectoraction;
+  acollectoraction.set_receptionist (&recpt);
+  recpt.add_action(&acollectoraction);
+
+//  cout << "GRB 3" << endl;
+
+  // list of browsers
+  vlistbrowserclass avlistbrowserclass;
+  recpt.add_browser (&avlistbrowserclass);
+  recpt.setdefaultbrowser ("VList");
+
+  hlistbrowserclass ahlistbrowserclass;
+  recpt.add_browser (&ahlistbrowserclass);
+
+  datelistbrowserclass adatelistbrowserclass;
+  recpt.add_browser (&adatelistbrowserclass);
+
+  invbrowserclass ainvbrowserclass;
+  recpt.add_browser (&ainvbrowserclass);
+
+  pagedbrowserclass apagedbrowserclass;
+  recpt.add_browser (&apagedbrowserclass);
+
+  htmlbrowserclass ahtmlbrowserclass;
+  recpt.add_browser (&ahtmlbrowserclass);
+
+  cgiwrapper (recpt, "");
+
+  for (int i=1; i< argc; i++)
+    {
+      delete cproto_array[i];
+    }
+
+  return 0;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/corbaproto.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/corbaproto.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/corbaproto.h	(revision 10506)
@@ -0,0 +1,101 @@
+/**********************************************************************
+ *
+ * corbaproto.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef CORBAPROTO_H
+#define CORBAPROTO_H
+
+#include "gsdlconf.h"
+#include "collectserver.h"
+#include "recptproto.h"
+#include "corbaiface.h"
+using namespace gsdlInterface;
+
+class corbaproto : public recptproto {
+ private:
+  corbaiface_var getCorbaClient();
+ protected:
+  collectservermapclass cservers;
+  corbaiface_var        client;
+  CORBA::ORB_var        orb;
+  CORBA::BOA_var        boa;
+  CORBA::Object_var     obj;
+  text_t gsdlhome;
+  text_t site_name;
+
+ public:
+  virtual ~corbaproto() {}
+  corbaproto(char* site_name);
+
+  // add_collectserver should be called for each collection server
+  // before any configuration is done
+  void add_collectserver (collectserver *thecserver) 
+    {cservers.addcollectserver(thecserver);}
+
+  // this configure will configure each of the collection servers
+  void configure (const text_t &key, const text_tarray &cfgline, comerror_t &err);
+
+  // this init will init each of the collection servers
+  bool init (comerror_t &err,ostream &logout);
+
+  // used to check for icons and retrieve them from the collection
+  // site if they are missing
+  void  cache_missing_icons(text_tmap& format_map,
+			    text_t& httpdomain, 
+			    text_t& httpprefix);
+
+  text_t get_site_name (comerror_t &err);
+
+  text_t get_protocol_name (comerror_t &err);
+  void get_collection_list (text_tarray &collist, comerror_t &err, 
+			    ostream &logout);
+  void has_collection (const text_t &collection, bool &hascollection, 
+		       comerror_t &err, ostream &logout);
+  void ping (const text_t &collection, bool &wassuccess, 
+	     comerror_t &err, ostream &logout);
+  void get_collectinfo (const text_t &collection, 
+			ColInfoResponse_t &collectinfo,
+			comerror_t &err, ostream &logout);
+  void get_filterinfo (const text_t &collection,
+		       InfoFiltersResponse_t &response,
+		       comerror_t &err, ostream &logout);
+  void get_filteroptions (const text_t &collection,
+			  const InfoFilterOptionsRequest_t &request,
+			  InfoFilterOptionsResponse_t &response, 
+			  comerror_t &err, ostream &logout);
+  void filter (const text_t &collection,
+	       FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout);
+
+  void get_document (const text_t &collection,
+		     const DocumentRequest_t &request,
+		     DocumentResponse_t &response,
+		     comerror_t &err, ostream &logout);
+
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/corbaproto.mpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/corbaproto.mpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/corbaproto.mpp	(revision 10506)
@@ -0,0 +1,749 @@
+/**********************************************************************
+ *
+ * corbaproto.cpp -- 
+ * Copyright (C) 2000 The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+#include <iostream.h>
+#include <fstream.h>
+
+#include "fileutil.h"
+
+// protocol headers for CORBA
+#include "corbaiface.h"
+using namespace gsdlInterface;
+
+// greenstone library headers
+#include "corbaconv_text_t.h"
+
+// greenstone local headers
+#include "corbatext_t.h"
+
+#include "corbaproto.h"
+#include "colservrconfig.h"
+
+// default headers
+#include <assert.h>
+
+void corbatext_optionValueArrayToCorba(OptionValue_tarray array, corbaOptionValue_array &corba)
+{
+  unsigned int i = 0;
+  OptionValue_tarray::iterator here = array.begin();
+  OptionValue_tarray::iterator end = array.end();
+  
+  while (here != end)
+    {
+      corba.length(i+1);
+      
+      corbaconv_text_t::getCorbatext(here->name,corba[i].name);
+      corbaconv_text_t::getCorbatext(here->value,corba[i].value);
+
+      i ++;
+      here ++;
+    }
+  //  cout << "Options " << i << endl;
+}
+
+void corbaresponse_resultMetadataToCorba(MetadataInfo_t &meta, corbaMetadataInfo &corbaMeta)
+{
+  corbaconv_text_t::getCorbatext(meta.params,corbaMeta.params);
+  corbatext_arrayToCorbaArray(meta.values, &corbaMeta.values);
+  corbaMeta.isRef    = meta.isRef;
+}
+
+void corbaresponse_resultMetadataToC(const corbaMetadataInfo &corbaMeta, MetadataInfo_t &meta)
+{
+  corbaconv_text_t::setCorbatext(meta.params,corbaMeta.params);
+  corbatext_corbaArrayToArray(corbaMeta.values, &meta.values);
+  meta.isRef    = corbaMeta.isRef;
+}
+
+int corbaresponse_resultMetaParentToCorba(MetadataInfo_t *parent, corbaMetadataInfo_array &corbaparent)
+{
+  int reply = -1, pid = -1;
+
+  // extend for new parent
+  reply = corbaparent.length();
+  corbaparent.length(reply+1);
+
+  // copy content into new array element
+  corbaresponse_resultMetadataToCorba(*parent, corbaparent[reply]);
+
+  // deal with our own parent
+  if (parent->parent != NULL)
+    {
+      // get offset of new parent and extend parent vector
+
+      pid  = corbaresponse_resultMetaParentToCorba(parent->parent, corbaparent);
+    }
+  corbaparent[reply].parentid = pid;
+
+  // return the parent id from here
+  return reply;
+}
+
+MetadataInfo_t *corbaresponse_resultMetaParentToC(corbaMetadataInfo_array &corbaparent, int pid)
+{
+  MetadataInfo_t *reply;
+
+  reply = new MetadataInfo_t;
+
+  corbaresponse_resultMetadataToC(corbaparent[pid], *reply);
+
+  // deal with our own parent
+  if (corbaparent[pid].parentid >= 0)
+    {
+      // get offset of new parent and extend parent vector
+
+      reply->parent = corbaresponse_resultMetaParentToC(corbaparent, corbaparent[pid].parentid);
+    }
+  else
+    {
+      reply->parent = NULL;
+    }
+
+  // return the parent id from here
+  return reply;
+}
+
+void corbaresponse_resultDocInfoToCorba(ResultDocInfo_tarray docinfo, corbaResultDocInfo_array &corbainfo)
+{
+  ResultDocInfo_tarray::iterator here = docinfo.begin();
+  ResultDocInfo_tarray::iterator end  = docinfo.end();
+  unsigned int i;
+
+  i = 0;
+  while (here != end)
+    {
+      corbainfo.length(i+1);
+
+      // copy the easy bits
+      corbaconv_text_t::getCorbatext(here->OID,corbainfo[i].OID);
+
+      corbainfo[i].resultNum     = here->result_num;
+      corbainfo[i].ranking       = here->ranking;
+      corbainfo[i].termsMatched  = here->num_terms_matched;
+      corbainfo[i].phraseMatched = here->num_phrase_match;
+
+      // copy the docFreq array
+      vector<int>::iterator fhere = here->docFreq.begin();
+      vector<int>::iterator fend  = here->docFreq.end();
+      unsigned int          fi = 0;
+
+      while (fhere != fend)
+	{
+	  corbainfo[i].docFreq.length(fi+1);
+
+	  corbainfo[i].docFreq[fi] = *fhere;
+
+	  fhere ++;
+	  fi ++;
+	}
+
+      // copy the MetadataInfo map
+      MetadataInfo_tmap::iterator mhere = here->metadata.begin();
+      MetadataInfo_tmap::iterator mend  = here->metadata.end();
+      unsigned int mi = 0;
+
+      while (mhere != mend)
+	{
+	  corbainfo[i].metadata.names.length(mi+1);
+	  corbainfo[i].metadata.values.length(mi+1);
+	  
+	  // copy name
+	  corbaconv_text_t::getCorbatext((*mhere).first,corbainfo[i].metadata.names[mi]);
+
+	  // copy metadata
+	  corbaresponse_resultMetadataToCorba((*mhere).second, corbainfo[i].metadata.values[mi]);
+	  if (mhere->second.parent != NULL)
+	    {
+	      int pid;
+
+	      pid = corbaresponse_resultMetaParentToCorba(mhere->second.parent, 
+							      corbainfo[i].metaparents);
+	      corbainfo[i].metadata.values[mi].parentid = pid;
+	    }
+	  else
+	    {
+	      corbainfo[i].metadata.values[mi].parentid = -1;
+	    }
+
+	  cout << "Parent " << mi << " " << (int) &mhere->second << " " << (int) mhere->second.parent << endl;
+
+	  mhere ++;
+	  mi ++;
+	}
+
+      // Copy the classifier variables
+      corbaconv_text_t::getCorbatext(here->classifier_metadata_type, corbainfo[i].classifierMetadataType);
+      corbainfo[i].classifierMetadataOffset = here->classifier_metadata_offset;
+
+      // Get next Docinfo item
+      i++;
+      here ++;
+    }
+}
+
+void corbaresponse_resultDocInfoToC(corbaResultDocInfo_array corbainfo, ResultDocInfo_tarray &docinfo)
+{
+  unsigned int i;
+  ResultDocInfo_t doc;
+
+  for (i = 0; i < corbainfo.length(); i++)
+    {
+      corbaconv_text_t::setCorbatext(doc.OID,corbainfo[i].OID);
+      doc.result_num        = corbainfo[i].resultNum;
+      doc.ranking           = corbainfo[i].ranking;
+      doc.num_terms_matched = corbainfo[i].termsMatched;
+      doc.num_phrase_match  = corbainfo[i].phraseMatched;
+
+      // copy the doc freq array
+      unsigned int fi;
+      for (fi = 0; fi < corbainfo[i].docFreq.length(); fi ++)
+	{
+	  doc.docFreq.push_back(corbainfo[i].docFreq[fi]);
+	}
+
+      // copy the MetadataInfomap
+      unsigned int   mi;
+      text_t         mname;
+      MetadataInfo_t mdata;
+      
+      doc.metadata.clear();
+      for (mi = 0; mi < corbainfo[i].metadata.names.length(); mi ++)
+	{
+	  // get name
+	  corbaconv_text_t::setCorbatext(mname,corbainfo[i].metadata.names[mi]);
+
+	  // get metadata
+	  corbaresponse_resultMetadataToC(corbainfo[i].metadata.values[mi], mdata);
+
+	  if (corbainfo[i].metadata.values[mi].parentid >= 0)
+	    {
+	      mdata.parent = 
+		corbaresponse_resultMetaParentToC(corbainfo[i].metaparents, 
+						  corbainfo[i].metadata.values[mi].parentid);	      
+	    }
+	 
+	  doc.metadata.insert(make_pair(mname, mdata));
+	}
+
+      // GRB: sort out parent data
+      for (mi = 0; mi < corbainfo[i].metadata.names.length(); mi ++)
+	{
+	  if (corbainfo[i].metadata.values[mi].parentid != 0)
+	    { 
+	      int pi;
+
+	      for (pi = 0; pi < corbainfo[i].metadata.names.length(); pi ++)
+		{
+		  if (pi != mi &&
+		      corbainfo[i].metadata.values[mi].parentid ==
+		      corbainfo[i].metadata.values[pi].id)
+		    {
+		      doc.metadata[mi].parent = &doc.metadata[pi];
+		    }
+		}
+	    }
+	}
+      //      doc.metadata
+
+      // convert metadata classifer information
+      corbaconv_text_t::setCorbatext(doc.classifier_metadata_type,corbainfo[i].classifierMetadataType);
+      doc.classifier_metadata_offset = corbainfo[i].classifierMetadataOffset;
+
+      docinfo.push_back(doc); 
+    }
+}
+
+
+// Added 31/1/2001, Michael Dewsnip
+void corbaresponse_resultTermInfoToC(corbaTermInfo_array corbainfo, TermInfo_tarray &terminfo)
+{
+  TermInfo_t ti;
+
+  for (unsigned int i = 0; i < corbainfo.length(); i++) {
+    corbaconv_text_t::setCorbatext(ti.term, corbainfo[i].term);
+    ti.freq = corbainfo[i].frequency;
+
+    for (unsigned int j = 0; j < corbainfo[i].matchTerms.length(); j++) {
+      text_t mt;
+      corbaconv_text_t::setCorbatext(mt, corbainfo[i].matchTerms[j]);
+
+      ti.matchTerms.push_back(mt);
+    }
+
+    terminfo.push_back(ti);
+  }
+}
+
+
+corbaproto::corbaproto(char* _site_name)
+{ char *dummyv[1] = {""};
+  int   dummyc = 0;
+  // CORBA variables
+  /* static CORBA::ORB_var orb = CORBA::ORB_init( dummyc , dummyv, "mico-local-orb" );
+     static CORBA::BOA_var boa = orb->BOA_init( dummyc , dummyv, "mico-local-boa" ); */
+
+  CORBA::ORB_var orb = CORBA::ORB_init( dummyc , dummyv, "mico-local-orb" );
+  CORBA::BOA_var boa = orb->BOA_init( dummyc , dummyv, "mico-local-boa" );
+
+  char objid_filename[256];
+  sprintf(objid_filename,"/tmp/%s.objid",_site_name);
+
+  // Get ref from "naming service"
+  ifstream in (objid_filename);
+  char ref[1000];
+  in >> ref;
+  in.close ();
+
+  // startup corba
+  // static CORBA::Object_var obj = orb->string_to_object (ref);
+  CORBA::Object_var obj = orb->string_to_object (ref);
+
+  client = corbaiface::_narrow( obj ); 
+  // client = NULL; // ****
+
+  gsdlhome.clear();
+  site_name = _site_name;
+}
+
+corbaiface_var corbaproto::getCorbaClient()
+{
+  // This function was written to help corba when ORB and BOA were
+  // not working in "persistent" mode.
+  // Now that persistent mode is working it is not longer needed/used.
+
+  char *dummyv[1] = {""};
+  int   dummyc = 0;
+  // CORBA variables
+//  static CORBA::ORB_var orb = CORBA::ORB_init( dummyc , dummyv, "mico-local-orb" );
+//  static CORBA::BOA_var boa = orb->BOA_init( dummyc , dummyv, "mico-local-boa" );
+
+  // DB // Try this out!! // ****
+  CORBA::ORB_var orb = CORBA::ORB_init( dummyc , dummyv, "mico-local-orb" );
+  CORBA::BOA_var boa = orb->BOA_init( dummyc , dummyv, "mico-local-boa" );
+
+  /*  char* site_name_chars = site_name.getcstr();
+  char objid_filename[256];
+  sprintf(objid_filename,"/tmp/%s.objid",site_name_chars);
+  // delete site_name_chars; */
+
+  text_t objid_filename = "/tmp/" + site_name + ".objid";
+
+  // Get ref from "naming service"
+  ifstream in (objid_filename.getcstr());
+  char ref[1000];
+  in >> ref;
+  in.close ();
+
+  // startup corba
+  // DB // Try this out!! // ****
+  // static CORBA::Object_var obj = orb->string_to_object (ref);
+  CORBA::Object_var obj = orb->string_to_object (ref);
+
+  return corbaiface::_narrow( obj );
+}
+
+
+// this configure will configure each of the collection servers
+void corbaproto::configure (const text_t &key, const text_tarray &cfgline,
+			    comerror_t &err) {
+  // the naming of the collection should not be done here,
+  // it should be done just after the collection server has been 
+  // created
+
+  // cout << "Corbaproto::Configure" << endl;
+  corbatext_t      corbaKey;
+  corbatext_tarray corbaCfgline;
+  gsdlInterface::corbaComError error = corbaNoError;
+
+  // get the corba client reference
+  // corbaiface_var lclient = this->getCorbaClient(); // ****
+  corbaiface_var lclient = client;
+
+  // convert all the requisite structures into their CORBA form
+  corbaconv_text_t::getCorbatext(key,corbaKey);
+  corbatext_arrayToCorbaArray(cfgline, &corbaCfgline);
+
+  // execute the corba transaction
+  lclient->configure(corbaKey, corbaCfgline, error);    
+
+  if (key=="gsdlhome")
+    {
+      // store gsdlhome in corba prototype so it can be used later to
+      // check if icons specified in format statements exist on the
+      // recptionist's side
+      gsdlhome = cfgline[0];
+    }
+  err = (comerror_t) error;
+}
+
+// this init will configure and init each of the collection servers
+bool corbaproto::init (comerror_t &err, ostream &logout) {
+//  cout << "Corbaproto::Init" << endl;
+  gsdlInterface::corbaComError error = corbaNoError;
+
+  // get the corba client reference
+  // corbaiface_var lclient = this->getCorbaClient(); // ****
+  corbaiface_var lclient = client;
+
+  // execute the corba transaction
+  return lclient->initialise(error);
+}
+
+void  corbaproto::cache_missing_icons(text_tmap& format_map,
+				      text_t& httpdomain, 
+				      text_t& httpprefix)
+{
+  // consider making this a member function in the object?
+
+  text_tmap::iterator format_here = format_map.begin();
+  text_tmap::iterator format_end = format_map.end();
+  while (format_here!=format_end)
+    {
+      text_t format_line = format_here->second;
+
+      // cout << "*** format line = " << format_line << endl; // ****
+
+      text_t::iterator fl_begin = format_line.begin();
+      text_t::iterator fl_end = format_line.end();
+
+      text_t::iterator httpimg_find = findword(fl_begin,fl_end,"_httpimg_");
+      text_t::iterator http_find = httpimg_find;
+
+      while (httpimg_find!=fl_end)
+	{
+	  http_find = httpimg_find+5;
+	  httpimg_find += 9;
+
+	  // look for white space " or >
+	  text_t::iterator filename_end = httpimg_find;
+	  while (filename_end != fl_end)
+	    {
+	      if (*filename_end == ' ') break;
+	      if (*filename_end == '\t') break;
+	      if (*filename_end == '\"') break;
+	      if (*filename_end == '>') break;
+	      filename_end++;
+	    }
+
+	  text_t img_filename = substr(httpimg_find,filename_end);
+
+	  text_t site_img_filename = filename_cat(gsdlhome,"images",img_filename);
+
+	  // look to see if img filename exists in images directory
+	  if (!file_exists(site_img_filename))
+	    {
+	      text_t cache_img_dir
+		= filename_cat(gsdlhome,"images",".cache");
+
+	      text_t remote_img_url = "http://" + httpdomain + httpprefix
+		+ "/images" + img_filename;
+
+	      text_t wget_cmd = "wget -q -N --directory-prefix="+cache_img_dir
+		+ " " + remote_img_url;
+
+	      char* wget_cmd_chars = wget_cmd.getcstr();
+
+	      system(wget_cmd_chars);
+	      delete wget_cmd_chars;
+
+	      format_map[format_here->first] 
+		= substr(fl_begin,http_find) + "cache" + substr(http_find,fl_end);
+
+	    }
+
+	  httpimg_find = findword(httpimg_find,fl_end,"_httpimg_");
+	}
+      format_here++;
+    }
+}
+
+text_t corbaproto::get_site_name (comerror_t &err) {
+  return site_name;
+}
+
+text_t corbaproto::get_protocol_name (comerror_t &err) {
+  return "corbaproto";
+}
+
+
+void corbaproto::get_collection_list (text_tarray &collist, comerror_t &err, 
+				     ostream &/*logout*/) {
+
+  // cout << "Corbaproto::Collection list" << endl;
+
+  corbatext_tarray corba_collist;
+  text_tarray      tcollist;
+  gsdlInterface::corbaComError error = corbaNoError;
+
+  // get the corba client reference
+  // corbaiface_var lclient = this->getCorbaClient(); // ****
+  corbaiface_var lclient = client;
+
+  // execute the corba transaction
+  lclient->collectionList(corba_collist,error);
+
+  // convert the response back to normal form
+  corbatext_corbaArrayToArray(corba_collist, &tcollist);
+  collist = tcollist;
+
+  err = (comerror_t) error;
+}
+
+void corbaproto::has_collection (const text_t &collection, bool &hascollection, 
+				comerror_t &err, ostream &/*logout*/) {
+  // cout << "Corbaproto::Has collection" << endl;
+
+  corbatext_t     corbaCollection;
+  corbaComError corbaError = corbaNoError;
+  CORBA::Boolean corbaHas;
+
+  // get the corba client reference
+  // corbaiface_var lclient = this->getCorbaClient(); // ****
+  corbaiface_var lclient = client;
+
+  // convert all the requisite structures into their CORBA form
+  corbaconv_text_t::getCorbatext(collection,corbaCollection);
+  
+  // execute the corba transaction
+  lclient->hasCollection(corbaCollection, corbaHas, corbaError);
+
+  // convert the response back to normal form
+  hascollection = (corbaHas != 0);
+  err = noError;
+}
+
+void corbaproto::ping (const text_t &collection, bool &wassuccess, 
+		      comerror_t &err, ostream &/*logout*/) {
+  // cout << "Corbaproto::Ping" << endl;
+
+  corbatext_t corbaCollect;
+  corbaComError corbaError = corbaNoError;
+  CORBA::Boolean success;
+
+  // get the corba client reference
+  // corbaiface_var lclient = this->getCorbaClient(); // ****
+  corbaiface_var lclient = client;
+
+  // convert all the requisite structures into their CORBA form
+  corbaconv_text_t::getCorbatext(collection,corbaCollect);
+
+  // execute the corba transaction
+  lclient->ping(corbaCollect, success, corbaError);
+  
+  // convert the response back to normal form
+  wassuccess = (success != 0);
+  err = (comerror_t) corbaError;  
+  cout << "Corbaproto::Ping" << err << endl;
+}
+
+
+void corbaproto::get_collectinfo (const text_t &collection, 
+				 ColInfoResponse_t &collectinfo,
+				 comerror_t &err, ostream &logout) {
+  //  cout << "Corbaproto::Collectinfo" << endl;
+
+  corbatext_t          corbaCollection;
+  corbaComError        corbaError = corbaNoError;
+  corbaColInfoResponse corbaCollectInfo;
+
+  // get the corba client reference
+  // corbaiface_var lclient = this->getCorbaClient(); // ****
+  corbaiface_var lclient = client;
+
+  // convert all the requisite structures into their CORBA form
+  corbaconv_text_t::getCorbatext(collection,corbaCollection);
+
+  // execute the corba transaction
+  lclient->getCollectInfo(corbaCollection, corbaCollectInfo, corbaError);
+
+  // convert the response back to normal form
+  collectinfo.isPublic = corbaCollectInfo.isPublic;
+  collectinfo.isBeta   = corbaCollectInfo.isBeta;
+  collectinfo.buildDate = corbaCollectInfo.buildDate;
+  corbatext_corbaArrayToArray(corbaCollectInfo.ccsCols, &collectinfo.ccsCols);
+  corbatext_corbaArrayToArray(corbaCollectInfo.languages, &collectinfo.languages);
+  collectinfo.numDocs   = corbaCollectInfo.numDocs;
+  collectinfo.numWords  = corbaCollectInfo.numWords;
+  collectinfo.numBytes  = corbaCollectInfo.numBytes;
+  corbatext_corbaMapToMap(corbaCollectInfo.collectionMeta, collectinfo.collectionmeta);
+  corbatext_corbaMapToMap(corbaCollectInfo.format, collectinfo.format);
+  corbatext_corbaMapToMap(corbaCollectInfo.building, collectinfo.building);
+  corbaconv_text_t::setCorbatext(collectinfo.httpdomain,corbaCollectInfo.httpdomain);
+  corbaconv_text_t::setCorbatext(collectinfo.httpprefix,corbaCollectInfo.httpprefix);
+  corbaconv_text_t::setCorbatext(collectinfo.receptionist,corbaCollectInfo.receptionist);
+
+  cache_missing_icons(collectinfo.format,collectinfo.httpdomain,
+		      collectinfo.httpprefix);
+
+  err = (comerror_t) corbaError;  
+}
+
+
+void corbaproto::get_filterinfo (const text_t &collection,
+				InfoFiltersResponse_t &response,
+				comerror_t &err, ostream &logout) {
+  //  cout << "Corbaproto::Filterinfo" << endl;
+
+  corbatext_t corbaCollection;
+  corbatext_tset corbaResponse;
+  corbaComError corbaError = corbaNoError;
+  
+  // get the corba client reference
+  // corbaiface_var lclient = this->getCorbaClient(); // ****
+  corbaiface_var lclient = client;
+
+  // convert all the requisite structures into their CORBA form
+  corbaconv_text_t::getCorbatext(collection,corbaCollection);
+
+  // execute the corba transaction
+  lclient->getFilterInfo(corbaCollection, corbaResponse, corbaError);
+
+  // convert the response back to normal form
+  corbatext_corbaArrayToSet(corbaResponse, &response.filterNames);
+
+  err = (comerror_t) corbaError;
+}
+
+void corbaproto::get_filteroptions (const text_t &collection,
+				   const InfoFilterOptionsRequest_t &request,
+				   InfoFilterOptionsResponse_t &response, 
+				   comerror_t &err, ostream &logout) {
+  //  cout << "Corbaproto::Filteroptions" << endl;
+
+  corbatext_t corbaCollection;
+  corbatext_t filterName;
+  corbaFilterOptionsResponse corbaResponse;
+  corbaComError corbaError = corbaNoError;
+  unsigned int i;
+  corbaconv_text_t *cc_name;
+  FilterOption_t *option;
+
+  // get the corba client reference
+  // corbaiface_var lclient = this->getCorbaClient(); // ****
+  corbaiface_var lclient = client;
+
+  // convert all the requisite structures into their CORBA form
+  corbaconv_text_t::getCorbatext(collection,corbaCollection);
+  corbaconv_text_t::getCorbatext(request.filterName,filterName);
+
+  // execute the corba transaction
+  lclient->getFilterOptions(corbaCollection, filterName, corbaResponse, corbaError);
+
+  // convert the response back to normal form
+  for (i = 0; i < corbaResponse.names.length(); i ++)
+    {
+      cc_name = new corbaconv_text_t(corbaResponse.names[i]);
+
+      option = new FilterOption_t;
+      corbaconv_text_t::setCorbatext(option->name,corbaResponse.options[i].name);
+      option->type = (FilterOption_t::type_t) corbaResponse.options[i].type;
+      option->repeatable = (FilterOption_t::repeatable_t) corbaResponse.options[i].repeatable;
+      corbaconv_text_t::setCorbatext(option->defaultValue,corbaResponse.options[i].defaultValue);
+      corbatext_corbaArrayToArray(corbaResponse.options[i].validValues, &option->validValues);
+
+      response.filterOptions.insert(make_pair(*cc_name, *option)); // typecast to text_t
+    }
+
+  err =  (comerror_t) corbaError;
+}
+
+
+void corbaproto::filter (const text_t &collection,
+			  FilterRequest_t &request,
+			  FilterResponse_t &response,
+			  comerror_t &err, ostream &logout) {
+  //  cout << "Corbaproto::Filter" << endl;
+
+  corbaFilterRequest corbaRequest;
+  corbaFilterResponse corbaResponse;
+  corbatext_t     corbaCollection;
+  corbaComError corbaError = corbaNoError;
+
+  // get the corba client reference
+  // corbaiface_var lclient = this->getCorbaClient(); // ****
+  corbaiface_var lclient = client;
+
+  // convert all the requisite structures into their CORBA form
+  corbaconv_text_t::getCorbatext(collection,corbaCollection);
+  corbaconv_text_t::getCorbatext(request.filterName,corbaRequest.filter);
+  corbatext_optionValueArrayToCorba(request.filterOptions, corbaRequest.filterOptions);
+  corbatext_arrayToCorbaArray(request.docSet, &corbaRequest.docSet);
+  corbaRequest.filterResultOptions = request.filterResultOptions;
+  corbaconv_text_t::getCorbatext(request.requestParams,corbaRequest.requestParams);
+  corbaconv_text_t::getCorbatext(request.refParams,corbaRequest.refParams);
+  corbaRequest.getParents = request.getParents;
+  corbatext_setToCorbaArray(request.fields, &corbaRequest.fields);
+
+  corbaResponse.numDocs = response.numDocs;
+  corbaresponse_resultDocInfoToCorba(response.docInfo, corbaResponse.docInfo);
+
+  // execute the corba transaction
+  lclient->filter (corbaCollection, corbaRequest, corbaResponse, corbaError);
+
+  // convert the response back to normal form
+  response.numDocs = corbaResponse.numDocs;
+  response.isApprox = (enum isapprox) corbaResponse.isApprox;
+  corbaresponse_resultDocInfoToC(corbaResponse.docInfo, response.docInfo);
+
+  // Added 31/1/2001, Michael Dewsnip
+  corbaresponse_resultTermInfoToC(corbaResponse.termInfo, response.termInfo);
+
+  err = (comerror_t) corbaError;
+  //  cout << "Corbaproto::Filter" << endl;
+}
+
+
+void corbaproto::get_document (const text_t &collection,
+			       const DocumentRequest_t &request,
+			       DocumentResponse_t &response,
+			       comerror_t &err, ostream &logout) {
+  //  cout << "Corbaproto::Get Document" << endl;
+
+  corbatext_t      corbaCollect;
+  corbaDocRequest  corbaRequest;
+  corbaDocResponse corbaResponse;
+  corbaComError    corbaError = corbaNoError;
+
+  // get the corba client reference
+  // corbaiface_var lclient = this->getCorbaClient(); // ****
+  corbaiface_var lclient = client;
+
+  // convert all the requisite structures into their CORBA form
+  corbaconv_text_t::getCorbatext(collection,corbaCollect);
+  corbaconv_text_t::getCorbatext(request.OID,corbaRequest.OID);
+  corbaconv_text_t::getCorbatext(request.docType,corbaRequest.docType);
+  corbaconv_text_t::getCorbatext(request.docFormat,corbaRequest.docFormat);
+
+  // execute the corba transaction
+  lclient->getDocument(corbaCollect, corbaRequest, corbaResponse, corbaError);
+
+  // convert the response back to normal form
+  corbaconv_text_t::setCorbatext(response.doc,corbaResponse.doc);
+
+  err = (comerror_t) corbaError;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/datelistbrowserclass.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/datelistbrowserclass.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/datelistbrowserclass.cpp	(revision 10506)
@@ -0,0 +1,170 @@
+/**********************************************************************
+ *
+ * datelistbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_DATELIST_BROWSER
+
+#include "datelistbrowserclass.h"
+#include <assert.h>
+
+
+datelistbrowserclass::datelistbrowserclass () {
+}
+
+datelistbrowserclass::~datelistbrowserclass () {
+}
+
+text_t datelistbrowserclass::get_browser_name () {
+  return "DateList";
+}
+
+browserclass* datelistbrowserclass::clone()
+{
+  return new datelistbrowserclass();
+}
+
+void datelistbrowserclass::load_metadata_defaults (text_tset &metadata) {
+  metadata.insert ("Date");
+  metadata.insert ("doctype");
+}
+
+text_t datelistbrowserclass::get_default_formatstring () {
+  return "<td>[link][icon][/link]</td><td>[highlight]{Or}{[Title],Untitled}[/highlight]</td><td>[Date]</td>";
+}
+
+int datelistbrowserclass::output_section_group (ResultDocInfo_t &/*section*/, cgiargsclass &/*args*/,
+						const text_t &/*collection*/, int /*colnumber*/, 
+						format_t * /*formatlistptr*/, bool /*use_table*/, 
+						text_tset &/*metadata*/, bool &/*getParents*/,
+						recptproto * /*collectproto*/, displayclass &/*disp*/, 
+						outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+						ostream &/*logout*/) {
+  return 0;
+}
+
+int datelistbrowserclass::output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+						const text_t &collection, int colnumber, format_t *formatlistptr, 
+						bool use_table, text_tset &/*metadata*/, bool &/*getParents*/,
+						recptproto * collectproto, displayclass &disp, 
+						outconvertclass &outconvert, ostream &textout, ostream &logout) {
+
+  text_t lastyear = "0000";
+  text_t lastmonth = "00";
+  text_t tabbing, endtabbing;
+
+  if (use_table || colnumber > 0) {
+    textout << outconvert << "<table><tr><td>";
+    // get tab size
+    text_t tab; int itab;
+    disp.expandstring (displayclass::defaultpackage, "_tabwidth_", tab);
+    itab = tab.getint();
+    if (colnumber > 0) 
+      textout << outconvert << "<img src=\"_httpimg_/space.gif\" width=" << (itab*colnumber) << ">";
+    textout << outconvert << "</td><td>";
+  }
+
+  textout << outconvert << "<table>\n";
+
+  ResultDocInfo_tarray::iterator thissection = sections.docInfo.begin();
+  ResultDocInfo_tarray::iterator endsection = sections.docInfo.end();
+  
+  // use the dm arg as date metadata or else Date
+  text_t date_meta = args["dm"];
+  if (date_meta == "") {
+    date_meta = "Date";
+  }
+  while (thissection != endsection) {
+
+    text_t &doctype = (*thissection).metadata["doctype"].values[0];
+    text_t &date = (*thissection).metadata[date_meta].values[0]; 
+
+    // bail on this document if it has no date
+    if (date.empty()) { ++thissection; continue; }
+
+    text_t::const_iterator datebegin = date.begin();
+    int datesize = date.size();
+    
+    if (datesize < 4) { ++thissection; continue; }
+    text_t thisyear = substr (datebegin, datebegin+4);
+    text_t thismonth = "00";
+    if (datesize >= 6)
+      thismonth = substr (datebegin+4, datebegin+6); 
+
+    text_t link = "<a href=\"_httpdocument_&cl=";
+    text_t icon = "_document:iconclosedbook_";
+      
+    if (doctype == "classify") {
+      icon = "_document:iconclosedbookshelf_";
+      link += (*thissection).OID + "\">";
+    } else {
+      link += args["cl"] + "&d=" + (*thissection).OID; // + "\">";
+      // [modification to allow default document detach settings -- kjdon]
+      if (args["xx"]=="1") {
+	// documents should be detached
+	link += "&x=1\" target=\\_blank>";
+      } else {
+	link += "\">";
+      }
+    }
+
+    textout << outconvert << "<tr valign=top>";
+
+    if (thisyear != lastyear) {
+      textout << outconvert << "<td><b>" << thisyear << "</b></td>";
+      lastyear = thisyear;
+    } else
+      textout << outconvert << "<td></td>";
+    
+    if (thismonth != lastmonth) {
+      textout << outconvert << disp << ("<td><b>_textmonth" + thismonth + "_</b></td>");
+      lastmonth = thismonth;
+    } else
+      textout << outconvert << "<td></td>";
+    
+    if (!use_table) textout << outconvert << "<td>\n";
+
+    text_tmap options;
+    options["link"] = link;
+    options["icon"] = icon;
+    options["highlight"] = "0";
+    textout << outconvert << disp 
+            << get_formatted_string (collection, collectproto,
+				     *thissection, disp, formatlistptr, 
+				     options, logout) << "\n";
+    
+    if (!use_table) textout << outconvert << "</td>";
+    
+    textout << outconvert << "</tr>\n";
+    
+    ++thissection;
+  }
+
+  textout << outconvert << "</table>\n";
+
+  if (use_table  || colnumber > 0) textout << outconvert << "</td></tr></table>\n";
+  return 1;
+}
+
+#endif //GSDL_USE_DATELIST_BROWSER
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/datelistbrowserclass.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/datelistbrowserclass.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/datelistbrowserclass.h	(revision 10506)
@@ -0,0 +1,63 @@
+/**********************************************************************
+ *
+ * datelistbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_DATELIST_BROWSER
+
+#ifndef DATELISTBROWSERCLASS_H
+#define DATELISTBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class datelistbrowserclass : public browserclass {
+protected:
+
+public:
+  datelistbrowserclass ();
+  virtual ~datelistbrowserclass ();
+
+  text_t get_browser_name ();
+
+  virtual browserclass* clone();
+
+  virtual void load_metadata_defaults (text_tset &metadata);
+
+  virtual text_t get_default_formatstring ();
+
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+  
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+};
+
+#endif //DATELISTBROWSERCLASS_H
+#endif //GSDL_USE_DATELIST_BROWSER
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/documentaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/documentaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/documentaction.cpp	(revision 10506)
@@ -0,0 +1,1305 @@
+/**********************************************************************
+ *
+ * documentaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include <string.h>
+
+#include "documentaction.h"
+#include "browsetools.h"
+#include "OIDtools.h"
+#include "querytools.h"
+#include "unitool.h"
+#include "gsdltools.h"
+#include "highlighttext.h"
+
+documentaction::documentaction () {
+  recpt = NULL;
+
+
+  // this action uses cgi variables "a", "d", "cl",
+  // "x", "gc", "gt", "gp", and "hl"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "p";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "d";
+  arg_ainfo.longname = "document OID";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // whether or not a document should be retrieved from the 
+  // library or the Web.
+  arg_ainfo.shortname = "il";
+  arg_ainfo.longname = "internal link preference";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "l";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "cl";
+  arg_ainfo.longname = "classification OID";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // in this action "gc" controls the expand/contract
+  // contents function
+  arg_ainfo.shortname = "gc";
+  arg_ainfo.longname = "expand contents";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // in this action "gt" controls the expand/contract
+  // text function 0 = not expanded, 1 = expand unless 
+  // there are more than 10 sections containing text,
+  // 2 = expand all
+  arg_ainfo.shortname = "gt";
+  arg_ainfo.longname = "expand text";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // in this action "gp" is the "go to page" control
+  // used by the Book type of toc
+  arg_ainfo.shortname = "gp";
+  arg_ainfo.longname = "go to page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // in this action "hl" is the "highlighting on/
+  // highlighting off control ("hl" == "2" is a
+  // special case that forces phrase highlighting
+  // to be used even if the query string doesn't
+  // appear to be a phrase)
+  arg_ainfo.shortname = "hl";
+  arg_ainfo.longname = "highlighting on/off";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "x" is 0 normally or 1 if page
+  // has been "detached"
+  arg_ainfo.shortname = "x";
+  arg_ainfo.longname = "detached page";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "xx" is 0 normally or 1 if documents should be detached by default
+  arg_ainfo.shortname = "xx";
+  arg_ainfo.longname = "detach all doc pages";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  
+  // f arg is set to 1 if document is to 
+  // be displayed in a frame
+  arg_ainfo.shortname = "f";
+  arg_ainfo.longname = "frame";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // fc arg is "1" if search bar is to be included (i.e. if "fc" == 1
+  // the httpdocument macro will include "&f=1"
+  arg_ainfo.shortname = "fc";
+  arg_ainfo.longname = "include search bar";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  //rd is whether a document will be displayed
+  //with a relevant document list
+  arg_ainfo.shortname = "rd";
+  arg_ainfo.longname = "include relevant documents";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  //dm is the metadata that has been used for the datelist
+  arg_ainfo.shortname = "dm";
+  arg_ainfo.longname = "date metadata";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+}
+
+documentaction::~documentaction () {
+}
+
+bool documentaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+				    recptprotolistclass *protos, ostream &logout) {
+
+   if(!args["d"].empty())
+      {
+	 text_t docTop;
+	 get_top(args["d"],docTop);
+	 
+	 recptproto* collectproto = protos->getrecptproto (args["c"], logout);
+	 if (collectproto != NULL)
+	    {
+	       ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
+	       
+	       if(cinfo->authenticate == "document") 
+		  {
+		     // both are either commented out or uncomment and are empty
+		     if (cinfo->public_documents.empty() && cinfo->private_documents.empty())
+			{
+			   //deny everything
+			   args["uan"] = "1";
+			   args["ug"] = cinfo->auth_group;
+			}
+
+		     // both public_documents and private_documents are turned on !
+		     else if (!cinfo->public_documents.empty() && !cinfo->private_documents.empty())
+			{
+			   //deny everything
+			   args["uan"] = "1";
+			   args["ug"] = cinfo->auth_group;
+			}
+		     
+		     // if public_documents is set but this document isn't
+		     // listed in it we need to authenticate
+		     else if ((!cinfo->public_documents.empty()) && 
+			      (cinfo->public_documents.find(docTop) == cinfo->public_documents.end()))
+		       {
+			 args["uan"] = "1";
+			 args["ug"] = cinfo->auth_group;
+		       }
+		     
+		     // if private_documents is set and this document is
+		     // listed in it we need to authenticate
+		     else if ((!cinfo->private_documents.empty()) &&
+			      (cinfo->private_documents.find(docTop) != cinfo->private_documents.end()))
+		       {
+			 args["uan"] = "1";
+			 args["ug"] = cinfo->auth_group;
+		       }
+		     
+		  }
+	    }
+      }
+   // check gc argument
+   int arg_gc = args.getintarg("gc");
+  if (arg_gc < 0 || arg_gc > 2) {
+    logout << "Warning: \"gc\" argument out of range (" << arg_gc << ")\n";
+    cgiarginfo *gcinfo = argsinfo.getarginfo ("gc");
+    if (gcinfo != NULL) args["gc"] = gcinfo->argdefault;
+  }
+
+  // check gt argument (may be either 0, 1 or 2)
+  int arg_gt = args.getintarg("gt");
+  if (arg_gt != 0 && arg_gt != 1 && arg_gt != 2) {
+    logout << "Warning: \"gt\" argument out of range (" << arg_gt << ")\n";
+    cgiarginfo *gtinfo = argsinfo.getarginfo ("gt");
+    if (gtinfo != NULL) args["gt"] = gtinfo->argdefault;
+  }
+
+  // check hl argument
+  int arg_hl = args.getintarg("hl");
+  if (arg_hl < 0 || arg_hl > 2) {
+    logout << "Warning: \"hl\" argument out of range (" << arg_hl << ")\n";
+    cgiarginfo *hlinfo = argsinfo.getarginfo ("hl");
+    if (hlinfo != NULL) args["hl"] = hlinfo->argdefault;
+  }
+
+  // check x argument
+  int arg_x = args.getintarg("x");
+  if (arg_x != 0 && arg_x != 1) {
+    logout << "Warning: \"x\" argument out of range (" << arg_x << ")\n";
+    cgiarginfo *xinfo = argsinfo.getarginfo ("x");
+    if (xinfo != NULL) args["x"] = xinfo->argdefault;
+  }
+
+  //checks whether rd arg is valid
+  int arg_rd = args.getintarg("rd");
+  if (arg_rd != 0 && arg_rd != 1) {
+    logout << "Warning: \"rd\" argument out of range (" << arg_rd << ")\n";
+    cgiarginfo *rdinfo = argsinfo.getarginfo ("rd");
+    if (rdinfo != NULL) args["rd"] = rdinfo->argdefault;
+  }
+
+
+  return true;
+}
+
+void documentaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+				       response_t &response,text_t &response_data, 
+				       ostream &logout) {
+
+  if ((args["il"] == "w") && (!args["d"].empty())) {
+
+    recptproto* collectproto = protos->getrecptproto (args["c"], logout);
+    if (collectproto != NULL) {
+      
+      text_tset metadata;
+      FilterResponse_t filt_response;
+      text_t top;
+
+      metadata.insert ("URL");
+      
+      // get metadata for parent document
+      get_top (args["d"], top);
+      if (get_info (top, args["c"], args["l"], metadata, false, collectproto, filt_response, logout)) {
+	text_t url = filt_response.docInfo[0].metadata["URL"].values[0];
+	
+	response = location;
+	response_data = url;
+	return;
+      } else {
+	// error, no URL
+	logout << "Error: documentaction::get_cgihead_info failed on get_info" << endl;
+      }
+    }
+  }
+  response = content;
+  response_data = "text/html";
+}
+
+// set_widthtspace calculates how wide the spaces in the nav bar should
+// be and sets the appropriate macro
+void documentaction::set_spacemacro (displayclass &disp, FilterResponse_t &response,
+				     bool has_search_button) {
+
+  text_t width;
+  int twidth, swidth, iwidth = 0;
+
+  int numc = response.docInfo.size();
+  ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator docend = response.docInfo.end();
+	
+  disp.expandstring (displayclass::defaultpackage, "_pagewidth_", width);
+  twidth = width.getint();
+
+  if (has_search_button) {
+    disp.expandstring ("query", "_searchwidth_", width);
+    iwidth += width.getint();
+  } else {
+    numc -= 1;
+  }
+  
+  while (dochere != docend) {
+    const text_t &title = (*dochere).metadata["Title"].values[0];
+
+    disp.expandstring ("document", "_" + title + "width_", width);
+    if (width == ("_" + title + "width_")) {
+      disp.expandstring ("document", "_defaultwidth_", width);
+    }
+    iwidth += width.getint();
+    ++dochere;
+  }
+
+  if ((twidth - iwidth) < numc) swidth = 2;
+  else {
+    swidth = twidth - iwidth;
+    if (numc > 0) swidth = swidth / numc;
+  }
+  disp.setmacro ("widthtspace", displayclass::defaultpackage, swidth);
+}
+
+// set_navbarmacros sets _navigationbar_ and _httpbrowseXXX_ macros
+// reponse contains 1 metadata field (Title)
+void documentaction::set_navbarmacros (displayclass &disp, FilterResponse_t &response, 
+				       bool has_search_button, cgiargsclass &args,
+				       ColInfoResponse_t &cinfo) {
+
+
+   bool use_pulldown = false;
+   text_tmap::iterator it = cinfo.format.find("NavigationBar");
+   if (it != cinfo.format.end()) {
+      if (it->second == "pulldown") {
+	 use_pulldown = true;
+      }
+   }
+
+   text_t topparent;
+   text_t &arg_d = args["d"];
+   text_t navigationbar = "<!-- Navigation Bar -->\n";
+
+   text_t date_extra = g_EmptyText;
+   get_top (args["cl"], topparent);
+   int numc = response.docInfo.size();
+   ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
+   ResultDocInfo_tarray::iterator docend = response.docInfo.end();
+
+   if (!use_pulldown) {
+      navigationbar += "<nobr>\n";
+      if (has_search_button) {
+	 if (args["a"] == "q") {
+	    navigationbar += "_icontabsearchgreen_";
+	 } else {
+	    navigationbar += "_imagesearch_";
+	 }
+      }
+  
+      if (has_search_button || numc == 0) navigationbar += "_imagespacer_";
+  
+      bool first = true;
+      while (dochere != docend) {
+	date_extra = g_EmptyText;
+	 if (!first) navigationbar += "_imagespacer_";
+	 
+	 text_t title = (*dochere).metadata["Title"].values[0];
+	 if (title == "Date") { // a date list
+	   text_t date_meta = (*dochere).metadata["mdtype"].values[0];
+	   if (date_meta == g_EmptyText) {
+	     date_meta = "Date";
+	   }
+	   date_extra = "&dm="+date_meta;
+	 }
+	 bool unknown = false;
+	 
+	 // test the _XXXwidth_ macro to see if image macros are
+	 // defined for this type of classification - if not we'll
+	 // just display the text
+	 text_t tmpwidth;
+	 disp.expandstring ("document", "_" + title + "width_", tmpwidth);
+	 if (tmpwidth == ("_" + title + "width_")) unknown = true;
+	 
+	 // if we're inside a document all the classification buttons should be enabled
+	 if (arg_d.empty() && ((*dochere).OID == topparent)) {
+	    if (unknown) navigationbar += " " + title + " ";
+	    else navigationbar += "_icontab" + title + "green_";
+	 } else {
+	    
+	    // set the _httpbrowseXXX_ macro for this classification
+	    if (unknown) navigationbar += " <a href=\"_httpdocument_&cl=" + 
+			    (*dochere).OID + date_extra+"\">" + title + "</a> ";
+	    else {
+	       navigationbar += "_image" + title + "_";
+	       disp.setmacro ("httpbrowse" + title, displayclass::defaultpackage, "_httpdocument_&cl=" + (*dochere).OID+date_extra);
+	    }
+	 }
+	 ++dochere;
+	 first = false;
+      }
+
+      if (!has_search_button && numc == 1) navigationbar += "_imagespacer_";
+
+      navigationbar += "\n</nobr>\n";
+      navigationbar += "<!-- End of Navigation Bar -->\n";
+
+   } else {
+
+      navigationbar = "<form method=\"get\" name=\"navform\">\n";
+      navigationbar += "<select name=\"navbar\" onChange=\"location.href=";
+      navigationbar += "document.navform.navbar.options[document.navform.navbar.selectedIndex].value\">\n";
+
+      if (args["a"] != "q" && args["cl"].empty()) {
+	 navigationbar += "<option value=\"\" selected>_textselectpage_</option>\n";
+      }
+      
+      if (has_search_button) {
+	 navigationbar += "<option value=\"_httpquery_\"";
+	 if (args["a"] == "q") {
+	    navigationbar += " selected";
+	 }
+	 navigationbar += ">_texticontabsearchgreen_</option>\n";
+      }
+
+      while (dochere != docend) {
+	 text_t title = dochere->metadata["Title"].values[0];	 
+	 if (title == "Date") { // a date list
+	   text_t date_meta = (*dochere).metadata["mdtype"].values[0];
+	   if (date_meta == "") {
+	     date_meta = "Date";
+	   }
+	   date_extra = "&dm="+date_meta;
+	 }
+
+	 navigationbar += "<option value=\"_httpdocument_&cl=" + dochere->OID +date_extra+ "\"";
+	 if (topparent == dochere->OID) {
+	    navigationbar += " selected";
+	 }
+	 navigationbar += ">" + title + "</option>\n";
+	 ++dochere;
+      }
+
+      navigationbar += "</select>\n";
+      navigationbar += "</form>\n";
+   }
+
+   disp.setmacro ("navigationbar", displayclass::defaultpackage, navigationbar);
+}
+
+// define all the macros which might be used by other actions
+// to produce pages. 
+void documentaction::define_external_macros (displayclass &disp, cgiargsclass &args, 
+					     recptprotolistclass *protos, ostream &logout) {
+  
+  // define_external_macros sets the following macros:
+
+  // _navigationbar_     this is the navigation bar containing the search button
+  //                     and any classification buttons - it goes at the top of 
+  //                     most pages. for now we're assuming that there'll always 
+  //                     be a search button - we should probably check that there
+  //                     is a query action before making this assumption
+
+  // _httpbrowseXXX_     the http macros for each classification (i.e. if there
+  //                     are Title and Creator classifications _httpbrowseTitle_
+  //                     and _httpbrowseCreator_ will be set
+
+  // _widthtspace_       the width of the spacers between buttons in navigation
+  //                     bar
+  
+  // _httpdocument_      has '&f=1' added if displaying document inside a frame
+
+  // _gsdltop_           macro to replace _top targets with
+
+  // _httppagehome_      overridden home url if html collections have own homepage
+
+  // _usability_         a macro for remote usability reporting
+
+  // must have a valid collection server to continue
+   
+  text_t &collection = args["c"];
+  if (collection.empty()) return;
+  recptproto *collectproto = protos->getrecptproto (collection, logout);
+  if (collectproto == NULL) return;
+  
+  if (recpt == NULL) {
+    logout << "ERROR (documentaction::define_external_macros): This action does not contain\n"
+	   << "      information about any receptionists. The method set_receptionist was\n"
+	   << "      probably not called from the module which instantiated this action.\n";
+    return;
+  }
+
+  outconvertclass text_t2ascii;
+  comerror_t err;
+  InfoFiltersResponse_t filterinfo;
+  FilterResponse_t response;
+  text_tset metadata;
+
+  // get info on current collection and load up formatinfo
+  // I'd prefer not to do this here as we're getting 
+  // collection info every time (and probably also getting
+  // it in other places some of the time) - One day I'll
+  // fix it ... maybe - Stefan.
+  ColInfoResponse_t cinfo;
+
+  collectproto->get_collectinfo (collection, cinfo, err, logout);
+  load_formatinfo (cinfo.format, args.getintarg("gt"));
+  //  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
+  //  if (cinfo == NULL) {
+  //    logout << "ERROR (documentaction::define_external_macros): get_collectinfo_ptr returned NULL\n";
+  //    return;
+  //  }
+  //load_formatinfo (cinfo->format, args.getintarg("gt"));
+
+  if (formatinfo.DocumentUseHTML) {
+
+    // frame stuff
+    if (args["fc"] == "1") {
+      text_t httpdocument;
+      disp.expandstring (displayclass::defaultpackage, "_httpdocument_", httpdocument);
+      httpdocument += "&f=1";
+      disp.setmacro ("httpdocument", displayclass::defaultpackage, httpdocument);
+      disp.setmacro ("gsdltop", displayclass::defaultpackage, "documenttop");
+      formatinfo.DocumentText = "[Text]";
+    }
+    text_tmap::iterator it = cinfo.format.find ("homepage");
+    if (it != cinfo.format.end()) {
+      text_t httppagehome;
+      if (get_link (args, protos, (*it).second, httppagehome, logout))
+	disp.setmacro ("httppagehome", displayclass::defaultpackage, httppagehome);
+    } 
+  }
+
+  // don't want navigation bar if page is 'detached'
+  if (!args.getintarg("x")) {
+
+    collectproto->get_filterinfo (collection, filterinfo, err, logout);
+    if (err == noError) {
+      // check that there's a browse filter
+      if (filterinfo.filterNames.find ("BrowseFilter") != filterinfo.filterNames.end()) {
+	
+	metadata.insert ("Title");
+	metadata.insert ("mdtype"); // in case there is a datelist
+	bool getParents = false;
+	get_children ("", collection, args["l"], metadata, getParents, collectproto, response, logout);
+	
+	bool has_search_button = true;
+	collectproto->is_searchable(collection, has_search_button, err, logout);
+	if (err != noError) has_search_button = true;
+
+	// calculate width of spacers and set _widthtspace_ macro
+	if (args.getintarg("v") == 0) set_spacemacro (disp, response, has_search_button);
+
+	// set _navigationbar_ macro
+	set_navbarmacros (disp, response, has_search_button, args, cinfo);
+   
+      }
+    } else {
+      logout << text_t2ascii 
+	     << "Error (documentaction::define_external_macros()) in call to get_filterinfo() " 
+	     << get_comerror_string (err);
+    }
+  }
+  text_tmap::iterator usability = cinfo.format.find("Usability");
+  if(usability!=cinfo.format.end()){
+    disp.setmacro("usability",displayclass::defaultpackage,"_imageusab_");
+    disp.setmacro("usabinterface",displayclass::defaultpackage,("_usab"+(*usability).second+"_"));
+    disp.setmacro("usabilityscript", displayclass::defaultpackage, "_usabshowscript_");
+  }
+}
+
+bool documentaction::get_link (cgiargsclass &args, recptprotolistclass *protos,
+			       const text_t &inlink, text_t &outlink, ostream &logout) {
+
+  FilterResponse_t response;
+  text_tset metadata;
+  metadata.insert ("section");
+  
+  // check current collection first
+  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+
+  if (get_info (inlink, args["c"], args["l"], metadata, false, collectproto, response, logout)) {
+    if (!response.docInfo[0].metadata["section"].values[0].empty()) {
+      outlink = "_httpdocument_&d=" + response.docInfo[0].metadata["section"].values[0];
+      return true;
+    }
+  }
+
+  // check all the other enabled collections
+
+  if (args["ccs"] == "1" && !args["cc"].empty()) {
+    text_tarray collections;
+    splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
+    
+    text_tarray::const_iterator col_here = collections.begin();
+    text_tarray::const_iterator col_end = collections.end();
+
+    while (col_here != col_end) {
+	  
+      // don't need to check current collection again
+      if (*col_here == args["c"]) {++col_here; continue;}
+	  
+      collectproto = protos->getrecptproto (*col_here, logout);
+      
+      if (get_info (inlink, *col_here, args["l"], metadata, false, collectproto, response, logout)) {
+	if (!response.docInfo[0].metadata["section"].values[0].empty()) {
+	  outlink = "_httpdocument_&c=" + *col_here + "&d=" +
+	    response.docInfo[0].metadata["section"].values[0];
+	  return true;
+	}
+      }
+      ++col_here;
+    }
+  }
+  return false;
+}
+
+void documentaction::load_formatinfo (const text_tmap &colformat, int gt) {
+
+  formatinfo.clear();
+  text_tmap::const_iterator format_here = colformat.begin();
+  text_tmap::const_iterator format_end = colformat.end();
+
+  while (format_here != format_end) {
+    if (((*format_here).first == "DocumentImages") && 
+	((*format_here).second == "true"))
+      formatinfo.DocumentImages = true;
+    else if (((*format_here).first == "DocumentTitles") && 
+	     ((*format_here).second == "false"))
+      formatinfo.DocumentTitles = false;
+    else if ((*format_here).first == "DocumentHeading") 
+      formatinfo.DocumentHeading = (*format_here).second;
+    else if (((*format_here).first == "DocumentContents") && 
+	     ((*format_here).second == "false"))
+      formatinfo.DocumentContents = false;
+    else if (((*format_here).first == "DocumentArrowsBottom") && 
+	     ((*format_here).second == "false"))
+      formatinfo.DocumentArrowsBottom = false;
+    else if (((*format_here).first == "DocumentArrowsTop") && 
+	     ((*format_here).second == "true"))
+      formatinfo.DocumentArrowsTop = true;
+    else if ((*format_here).first == "DocumentButtons")
+      splitchar ((*format_here).second.begin(), (*format_here).second.end(),
+		 '|', formatinfo.DocumentButtons);
+    else if ((*format_here).first == "DocumentText") 
+      formatinfo.DocumentText = (*format_here).second;  
+    else if ((*format_here).first == "RelatedDocuments")
+      formatinfo.RelatedDocuments = (*format_here).second; 
+    else if (((*format_here).first == "DocumentUseHTML") && 
+	     ((*format_here).second == "true"))
+      formatinfo.DocumentUseHTML = true;
+    else if (((*format_here).first == "AllowExtendedOptions") && 
+	     ((*format_here).second == "true"))
+      formatinfo.AllowExtendedOptions = true;
+    else 
+      formatinfo.formatstrings[(*format_here).first] = (*format_here).second;
+    
+    ++format_here;
+  }
+
+  // never want arrows when text is expanded
+  if (gt) {
+    formatinfo.DocumentArrowsBottom = false;
+    formatinfo.DocumentArrowsTop = false;
+  }
+}
+
+
+// define all the macros which are related to pages generated
+// by this action. we also load up the formatinfo structure 
+// here (it's used in do_action as well as here)
+void documentaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					     recptprotolistclass *protos, ostream &logout) {
+  
+  // define_internal_macros sets the following macros:
+  
+  // _pagetitle_            the title to be displayed at the top of the browser window
+  
+  // _imagethispage_        the title image to be displayed at top right of page
+
+  // _navarrowsbottom_      this may be overridden to "" when format option 
+  //                        DocumentArrowsBottom is false
+
+  // _navarrowstop_         likewise for DocumentArrowsTop
+
+  // _httpprevarrow_        links to next and previous sections of document - used
+  // _httpnextarrow_        by DocumentArrowsBottom
+
+  // _header_               the header macro is overridden if we're not at a top level 
+  //                        classification to remove the title block
+
+  // _thisOID_              the OID (directory) of the current document - this corresponds
+  //                        to the archivedir metadata element
+
+  // must have a valid collection server to continue
+
+   text_t &collection = args["c"];
+  if (collection.empty()) return;
+  recptproto *collectproto = protos->getrecptproto (collection, logout);
+  if (collectproto == NULL) return;
+
+  text_tset metadata;
+  FilterResponse_t response;
+  text_t &arg_d = args["d"];
+  text_t &arg_cl = args["cl"];
+
+  if (!formatinfo.DocumentArrowsBottom) {
+    disp.setmacro("navarrowsbottom", "document", "");
+  } else if (!formatinfo.DocumentArrowsBottom) {
+    disp.setmacro("navarrowstop", "document", "");
+  } 
+
+  if (!arg_d.empty() && (formatinfo.DocumentArrowsBottom || formatinfo.DocumentArrowsTop)) {
+    // set _httpprevarrow_ and _httpnextarrow_
+    set_arrow_macros (args, collectproto, disp, logout);
+  }
+
+  metadata.insert ("Title");
+
+  bool fulltoc = false;
+
+  if (args["cl"] != "search") {
+    // see if there's a FullTOC string
+    text_t cl_top, full_toc;
+    get_top (arg_cl, cl_top);
+    if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
+      if (full_toc == "true") fulltoc = true;
+  }
+  
+  if (!arg_d.empty() && !fulltoc) {
+    // we're at document level
+
+    metadata.insert ("archivedir");
+
+    comerror_t err;
+    OptionValue_tarray options;
+    // we need to do the query again for the z3950proto
+    if (collectproto->get_protocol_name(err)=="z3950proto") {
+      OptionValue_t opt;
+      opt.name="Term";opt.value=args["q"];options.push_back(opt);
+      opt.name="QueryType";
+      opt.value=(args.getintarg("t")) ? "ranked" : "boolean";
+      options.push_back(opt);
+      opt.name="Index";opt.value=args["h"];options.push_back(opt);
+    }
+    
+    //do not display relation metadata
+    disp.setmacro ("relateddoc", "document", "");  
+       
+    //if preferences indicate relevant docs should be collected
+    //and there is no particular format specified then display
+    //this default format.
+     if(args["rd"] == "1" && formatinfo.RelatedDocuments.empty()){
+
+       text_t relation = g_EmptyText; //string for displaying relation metadata
+
+       //call function in formattools.cpp which will return the text of the 
+       //related documents in a vertical list. This is the default format.
+
+       if (get_info (arg_d, collection, args["l"], metadata, options, false, collectproto, response, logout)) 
+	 relation += get_related_docs(collection, collectproto, response.docInfo[0], logout);
+       
+       //set macro to be the related document string
+
+       disp.setmacro ("relateddoc", "document", relation); 
+     }
+     
+  
+    // get metadata for this document and it's parents
+    if (get_info (arg_d, collection, args["l"], metadata, options, 
+		  true, collectproto, response, logout)) {
+
+      disp.setmacro ("header", "document", "_textheader_");
+      
+      text_tarray pagetitlearray;
+      if (!response.docInfo[0].metadata["Title"].values[0].empty())
+	pagetitlearray.push_back (response.docInfo[0].metadata["Title"].values[0]);
+      
+      if (args["gt"] != "1") {
+	MetadataInfo_t *parenttitle = response.docInfo[0].metadata["Title"].parent;
+	while (parenttitle != NULL) {
+	  if (!parenttitle->values[0].empty())
+	    pagetitlearray.push_back (parenttitle->values[0]);
+	  parenttitle = parenttitle->parent;
+	}
+      }
+      reverse (pagetitlearray.begin(), pagetitlearray.end());
+      text_t pagetitle;
+      joinchar (pagetitlearray, ": ", pagetitle);
+      // remove html tags from the title
+      text_t::iterator open_tag=pagetitle.begin();
+      while (open_tag < pagetitle.end()) {
+	if (*open_tag == '<') {
+	  text_t::iterator close_tag=open_tag+1;
+	  text_t::iterator donechar=pagetitle.end();
+	  while (close_tag < donechar) {
+	    if (*close_tag == '>')
+	      break;
+	    ++close_tag;
+	  }
+	  if (close_tag < donechar) // remove this html tag, replace with space
+	    *close_tag=' ';
+	  pagetitle.erase(open_tag, close_tag);
+	}
+	++open_tag;
+      }
+      disp.setmacro ("pagetitle", "document", pagetitle);
+
+      if (is_top (arg_d))
+	disp.setmacro ("thisOID", displayclass::defaultpackage, dm_safe(response.docInfo[0].metadata["archivedir"].values[0]));
+      else {
+	MetadataInfo_t *parentad = response.docInfo[0].metadata["archivedir"].parent;
+	text_t thisOID;
+	while (parentad != NULL) {
+	  thisOID = parentad->values[0];
+	  parentad = parentad->parent;
+	}
+	disp.setmacro ("thisOID", displayclass::defaultpackage, dm_safe(thisOID));
+      }
+    }
+  } else {
+    if (!arg_cl.empty()) {
+	
+      // create the currentnodevalue macro - this is the value of the node
+      // in the hierarchy that is currently open.
+      if (get_info (arg_cl, collection, args["l"], metadata, false, collectproto, response, logout)) {
+	text_t &title = response.docInfo[0].metadata["Title"].values[0];
+	disp.setmacro ("currentnodevalue", "document", title);
+      }
+      // get metadata for top level classification
+      text_t classtop;
+      get_top (arg_cl, classtop);
+      metadata.insert ("childtype");
+      metadata.insert ("parameters");
+
+      if (get_info (classtop, collection, args["l"], metadata, false, collectproto, response, logout)) {
+	  
+	text_t &title = response.docInfo[0].metadata["Title"].values[0];
+	bool unknown = false;
+
+	// test the _XXXwidth_ macro to see if image macros are
+	// defined for this type of classification - if not we'll
+	// just display the text
+	text_t tmp;
+	disp.expandstring ("document", "_" + title + "width_", tmp);
+	if (tmp == ("_" + title + "width_")) unknown = true;
+
+	if (unknown) {
+	  disp.setmacro ("pagetitle", "document", title);
+	  disp.setmacro ("imagethispage", "document", "<h2>" + title + "</h2>");
+	} else {
+	  disp.setmacro ("pagetitle", "document", "_text" + title + "page_");
+	  disp.setmacro ("imagethispage", "document", "_icon" + title + "page_");
+	}
+
+      	//if the document is not a document from a collection
+	//we must set the macro to be an empty string
+	disp.setmacro ("relateddoc", "document", ""); 
+
+	// Add macros specific to the Collage/Phind classifiers 
+	text_t &childtype = response.docInfo[0].metadata["childtype"].values[0];
+	if (childtype == "Collage") {
+
+	  text_t::iterator a = arg_cl.begin();
+	  text_t::iterator b = arg_cl.end();
+
+	  bool collage = true;
+	  while (a != b) {
+	    if (*a == 46) collage = false;
+	    ++a;
+	  }
+
+	  if (collage) {
+	    disp.setmacro ("collageclassifier", "document", "_collageapplet_");
+
+            // Next, macros that control the way the classifier is displayed
+            text_t parameters = response.docInfo[0].metadata["parameters"].values[0];
+
+            // extract key=value pairs and set as macros
+            text_t::iterator here = parameters.begin();
+            text_t::iterator end = parameters.end();
+            text_t key, value;
+
+            while (here != end) {
+              // get the next key and value pair
+              here = getdelimitstr (here, end, '=', key);
+              here = getdelimitstr (here, end, ';', value);
+
+              // store this key=value pair
+              if (!key.empty() && !value.empty()) {
+                disp.setmacro ("collage"+key, "document", value);
+              }
+            }
+
+	    
+	  }
+	}
+
+	if (childtype == "Phind") {
+
+	  // First, a macro to display the phind classifier
+	  disp.setmacro ("phindclassifier", "document", "_phindapplet_");
+
+	  // Next, macros that control the way the classifier is displayed
+	  text_t parameters = response.docInfo[0].metadata["parameters"].values[0];
+
+	  // extract key=value pairs and set as macros
+	  text_t::iterator here = parameters.begin();
+	  text_t::iterator end = parameters.end();
+	  text_t key, value;
+	  
+	  while (here != end) {
+	    // get the next key and value pair
+	    here = getdelimitstr (here, end, '=', key);
+	    here = getdelimitstr (here, end, ';', value);
+
+	    // store this key=value pair
+	    if (!key.empty() && !value.empty()) {
+	      disp.setmacro (key, "document", value);
+	    }
+	  }
+	} // end if (childtype == "Phind")
+      }
+    } // end if (!arg_cl.empty()) {
+  }
+}
+
+
+bool documentaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+				browsermapclass *browsers, displayclass &disp, 
+				outconvertclass &outconvert, ostream &textout, 
+				ostream &logout) {
+ 
+  // must have a valid collection server
+  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+  if (collectproto == NULL) {
+    logout << "documentaction::do_action called with NULL collectproto\n";
+    textout << outconvert << disp << "_document:header_\n" 
+	    << "Error: Attempt to get document without setting collection\n"
+	    << "_document:footer_\n";
+  } else {  
+    
+    text_t OID = args["d"];
+    if (OID.empty()) OID = args["cl"];
+    if (OID.empty()) {
+      textout << outconvert << disp << "Document contains no data_document:footer_\n";
+      return true;
+    }
+
+  
+    if (formatinfo.DocumentUseHTML && !args["d"].empty()) {
+      
+      if (args["f"] == "1") {
+	textout << outconvert << disp 
+		<< "<html><head></head>\n"
+		<< "<frameset rows=\"68,*\" noresize border=0>\n"
+		<< "<frame scrolling=no frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=p&p=nav\">\n"
+		<< "<frame name=\"documenttop\" frameborder=0 src=\"_gwcgi_?_optsite_e=_compressedoptions_&a=d&d=" 
+		<< args["d"] << "\">"
+		<< "<noframes>\n"
+		<< "<p>You must have a frame enabled browser to view this.</p>\n"
+		<< "</noframes>\n"
+		<< "</frameset>\n"
+		<< "</html>\n";
+      } else {
+	output_document (OID, args, collectproto, browsers, disp, outconvert, textout, logout);	
+      }
+      return true;
+    }
+
+   
+    textout << outconvert << disp << "_document:header_\n"
+	    << "_document:content_\n";
+      
+    // output the table of contents
+    output_toc (args, browsers, formatinfo, collectproto, 
+		disp, outconvert, textout, logout);
+   
+    if (formatinfo.DocumentArrowsTop && !args["d"].empty()) {
+      textout << outconvert << disp << "_document:navarrowstop_\n";
+    }
+
+    //output the related documents (may be the empty string)
+    //will not output the docs if a format string is specified
+    textout << outconvert << disp << "_document:relateddoc_\n";
+
+    // output the document text
+    if (!args["d"].empty()) {
+      textout << outconvert << "<p>\n";
+      output_document (OID, args, collectproto, browsers, disp, outconvert, textout, logout);
+    }
+
+    textout << outconvert << disp << "_document:footer_\n";
+  }
+  return true;
+}
+
+void documentaction::output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+				  const TermInfo_tarray &terminfo, const text_t &OID,
+				  bool highlight, int hastxt, int wanttext, 
+				  text_t &collection, recptproto *collectproto,
+				  browsermapclass *browsers, displayclass &disp,
+				  outconvertclass &outconvert, ostream &textout,
+				  ostream &logout, cgiargsclass &args) {
+  
+  DocumentRequest_t docrequest;
+  DocumentResponse_t docresponse;
+  comerror_t err;
+  if (hastxt == 1) {
+
+    if (wanttext) {
+      // get the text
+      docrequest.OID = OID;
+      collectproto->get_document (collection, docrequest, docresponse, err, logout);
+
+      // cut down on overhead by not using formattools if we only want the text
+      // (wanttext will equal 2 if we want text and other stuff too)
+      if (wanttext == 1)
+	if (highlight) {
+	  highlighttext(docresponse.doc, args, terminfo, disp, outconvert, textout);
+	} else {
+	  textout << outconvert << disp << docresponse.doc;
+	}
+    }
+  
+    if (wanttext != 1) {
+      text_tmap options;
+      options["text"] = docresponse.doc;
+
+      if (formatinfo.AllowExtendedOptions) {
+	load_extended_options(options, args, browsers, formatinfo, 
+			      collectproto, disp, outconvert, logout);
+      }
+      
+      text_t doctext 
+	 = get_formatted_string (collection, collectproto, docinfo, disp,
+				 formatlistptr, options, logout); 
+      
+      if (highlight) {
+	highlighttext(doctext, args, terminfo, disp, outconvert, textout);
+      } else {
+	textout << outconvert << disp << doctext;
+      }
+    }
+  }
+}
+
+
+void documentaction::output_document (const text_t &OID, cgiargsclass &args, 
+				      recptproto *collectproto, browsermapclass *browsers,
+				      displayclass &disp, outconvertclass &outconvert,
+				      ostream &textout, ostream &logout) {
+  FilterResponse_t inforesponse;
+  FilterResponse_t queryresponse;
+  text_tset metadata;
+  bool getParents = false;
+  bool highlight = false;
+  int wanttext = 0;
+  int arg_gt = args.getintarg("gt");
+  text_t &collection = args["c"];
+    
+  // if we have a query string and highlighting is turned on we need
+  // to redo the query to get the terms for highlighting
+  
+  if (!args["q"].empty() && args.getintarg("hl")) {
+
+    ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
+    bool segment = false;
+    if (cinfo != NULL) {
+      segment = cinfo->isSegmented;
+    }
+    FilterRequest_t request;
+    comerror_t err;
+    request.filterResultOptions = FRmatchTerms;
+    text_t formattedstring = args["q"];
+    format_querystring (formattedstring, args.getintarg("b"), segment);
+    set_queryfilter_options (request, formattedstring, args);
+    args["q"] = formattedstring; // need to set this here for phrase 
+                   // highlighting, where we look at the querystring
+    collectproto->filter (args["c"], request, queryresponse, err, logout);
+    if (err != noError) {
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii
+	     << "documentaction::output_document: call to QueryFilter failed "
+	     << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
+      highlight = false;
+    } else {
+      highlight = true;
+    }
+  }
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatinfo.DocumentText, formatlistptr, metadata, getParents);
+
+  metadata.insert ("hastxt");
+  metadata.insert ("haschildren");
+
+  if (formatinfo.DocumentText == "[Text]")
+    wanttext = 1;
+  else {
+    char *docformat = formatinfo.DocumentText.getcstr();
+    if (strstr (docformat, "[Text]") != NULL)
+      wanttext = 2;
+    delete []docformat;
+  }
+    
+  if (get_info (OID, collection, args["l"], metadata, getParents, collectproto, inforesponse, logout)) {
+    int hastxt = inforesponse.docInfo[0].metadata["hastxt"].values[0].getint();
+    int haschildren = inforesponse.docInfo[0].metadata["haschildren"].values[0].getint();
+    
+    if (arg_gt == 0) {
+      output_text (inforesponse.docInfo[0], formatlistptr, queryresponse.termInfo, 
+		   OID, highlight, hastxt, wanttext, collection, collectproto, 
+		   browsers, disp, outconvert, textout, logout, args);
+
+
+    } else {
+
+      ResultDocInfo_t thisdocinfo = inforesponse.docInfo[0];
+	
+      // text is to be expanded
+      text_t exOID = OID;
+      if (haschildren != 1) exOID = get_parent (OID);
+      if (exOID.empty()) exOID = OID;
+	
+      // if we're not in a document (i.e. we're in a top level classification)
+      // we need to pass "is_classify = true" to get_contents so that it 
+      // doesn't recurse all the way through each document in the classification
+      bool is_classify = false;
+      if (args["d"].empty()) is_classify = true;
+
+      get_contents (exOID, is_classify, metadata, collection, args["l"], 
+		    collectproto, inforesponse, logout);
+	
+      ResultDocInfo_tarray::iterator sechere = inforesponse.docInfo.begin();
+      ResultDocInfo_tarray::iterator secend = inforesponse.docInfo.end();
+
+      if (arg_gt == 1) {
+	// check if there are more than 10 sections containing text to be expanded - 
+	// if there are output warning message - this isn't a great way to do this
+	// since the sections may be very large or very small - one day I'll fix it 
+	// -- Stefan.
+	int seccount = 0;
+	while (sechere != secend) {
+	  int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
+	  if (shastxt == 1) ++seccount;
+	  if (seccount > 10) break;
+	  ++sechere;
+	}
+	if (seccount > 10) {
+	  // more than 10 sections so output warning message and text 
+	  // for current section only
+	  textout << outconvert << disp << "_document:textltwarning_";
+
+	  output_text (thisdocinfo, formatlistptr, queryresponse.termInfo, 
+		       OID, highlight, hastxt, wanttext, collection, 
+		       collectproto, browsers, disp, outconvert, textout, logout, args);
+	  
+	}
+	else arg_gt = 2;
+      }
+
+      if (arg_gt == 2) {
+	// get the text for each section
+	sechere = inforesponse.docInfo.begin();
+	int count = 0;
+	while (sechere != secend) {
+	  textout << outconvert << disp << "\n<p><a name=" << (*sechere).OID << "></a>\n";
+
+	  int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
+
+	  output_text (*sechere, formatlistptr, queryresponse.termInfo, 
+		       (*sechere).OID, highlight, shastxt, wanttext, collection, 
+		       collectproto, browsers, disp, outconvert, textout, logout, args);
+	  ++count;
+	  ++sechere;
+	}
+      }
+    }
+  }
+  delete formatlistptr;
+}
+
+void documentaction::set_arrow_macros (cgiargsclass &args, recptproto *collectproto,
+				       displayclass &disp, ostream &logout) {
+
+  text_tset metadata;
+  FilterResponse_t response;
+  FilterResponse_t presponse;
+
+  int haschildren = 0;
+  text_tarray next_siblings;
+  text_t previous_sibling;
+  text_t &arg_d = args["d"];
+
+  // get info on current section
+  metadata.insert("haschildren");
+  if (!get_info(arg_d, args["c"], args["l"], metadata, false, collectproto, response, logout)) {
+    logout << "error 1 in documentaction::set_arrow_macros\n";
+    return;
+  }
+  haschildren = response.docInfo[0].metadata["haschildren"].values[0].getint();
+      
+  // get OIDs of next and previous siblings of current section and
+  // all it's parents
+  int parentcount = countchar(arg_d.begin(), arg_d.end(), '.');
+  text_t thisoid = arg_d;
+  while (parentcount > 0) {
+    get_children (get_parent(thisoid), args["c"], args["l"], metadata, false, 
+		  collectproto, response, logout);
+    ResultDocInfo_tarray::iterator this_sibling = response.docInfo.begin();
+    ResultDocInfo_tarray::iterator last_sibling = response.docInfo.end();
+    bool first = true;
+    while (this_sibling != last_sibling) {
+      if ((*this_sibling).OID == thisoid) {
+	if (!first && next_siblings.empty()) {
+	  previous_sibling = (*(this_sibling-1)).OID;
+	  int section_has_children = (*(this_sibling-1)).metadata["haschildren"].values[0].getint();
+	  // if previous sibling has children we need to recurse
+	  // down to the last descendant
+	  while (section_has_children) {
+	    get_children (previous_sibling, args["c"], args["l"], metadata, false, 
+			  collectproto, presponse, logout);
+	    if (!presponse.docInfo.empty()) {
+	      ResultDocInfo_tarray::iterator it = presponse.docInfo.end() - 1;
+	      previous_sibling = (*it).OID;
+	      section_has_children = (*it).metadata["haschildren"].values[0].getint();
+	    } else {
+	      section_has_children = 0; // this should never happen
+	    }
+	  }
+	}
+	    
+	if ((this_sibling+1) != last_sibling) {
+	  next_siblings.push_back((*(this_sibling+1)).OID);
+	} else {
+	  next_siblings.push_back("");
+	}
+	break;
+      }
+      ++this_sibling;
+      first = false;
+    }
+    thisoid = get_parent(thisoid);
+    --parentcount;
+  }
+
+  // work out values for next link
+  if (haschildren) {
+    disp.setmacro ("httpnextarrow", "document", "_httpdocument_&cl=" + args["cl"] +
+		   "&d=" + arg_d + ".fc");
+  } else {
+    text_tarray::const_iterator h = next_siblings.begin();
+    text_tarray::const_iterator e = next_siblings.end();
+    while (h != e) {
+      if (!(*h).empty()) {
+	disp.setmacro ("httpnextarrow", "document", "_httpdocument_&cl=" + args["cl"] +
+		       "&d=" + *h);
+	break;
+      }
+      ++h;
+    }
+  }
+
+  // work out value for previous link
+  if (!previous_sibling.empty()) {
+    disp.setmacro ("httpprevarrow", "document", "_httpdocument_&cl=" + args["cl"] +
+		   "&d=" + previous_sibling);
+  } else {
+    if (countchar(arg_d.begin(), arg_d.end(), '.')) {
+      disp.setmacro ("httpprevarrow", "document", "_httpdocument_&cl=" + args["cl"] +
+		     "&d=" + get_parent(arg_d));
+    }
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/documentaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/documentaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/documentaction.h	(revision 10506)
@@ -0,0 +1,102 @@
+/**********************************************************************
+ *
+ * documentaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef DOCUMENTACTION_H
+#define DOCUMENTACTION_H
+
+#include "action.h"
+#include "gsdlconf.h"
+#include "formattools.h"
+#include "receptionist.h"
+#include "browserclass.h"
+
+class documentaction : public action {
+
+protected:
+
+  receptionist *recpt;
+
+  bool get_link (cgiargsclass &args, recptprotolistclass *protos,
+		 const text_t &inlink, text_t &outlink, ostream &logout);
+
+  void load_formatinfo (const text_tmap &colformat, int gt);
+
+  void set_spacemacro (displayclass &disp, FilterResponse_t &response,
+		       bool has_search_button);
+
+  void set_navbarmacros (displayclass &disp, FilterResponse_t &response, 
+			 bool has_search_button, cgiargsclass &args,
+			 ColInfoResponse_t &cinfo);
+
+  virtual void output_text (ResultDocInfo_t &docinfo, format_t *formatlistptr,
+			    const TermInfo_tarray &terminfo, const text_t &OID,
+			    bool highlight, int hastxt, int wanttext, 
+			    text_t &collection, recptproto *collectproto,
+			    browsermapclass *browsers, displayclass &disp,
+			    outconvertclass &outconvert, ostream &textout,
+			    ostream &logout, cgiargsclass &args);
+
+  virtual void output_document (const text_t &OID, cgiargsclass &args, 
+				recptproto *collectproto, browsermapclass *browsers,
+				displayclass &disp,  outconvertclass &outconvert,
+				ostream &textout,  ostream &logout);
+
+  void set_arrow_macros (cgiargsclass &args, recptproto *collectproto,
+			 displayclass &disp, ostream &logout);
+
+  formatinfo_t formatinfo;
+
+public:
+  documentaction ();
+  virtual ~documentaction ();
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  text_t get_action_name () {return "d";}
+
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      recptprotolistclass *protos, ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response,text_t &response_data, 
+			 ostream &logout);
+
+  void define_external_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  virtual void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+				       recptprotolistclass *protos, ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+};
+
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/extlinkaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/extlinkaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/extlinkaction.cpp	(revision 10506)
@@ -0,0 +1,251 @@
+/**********************************************************************
+ *
+ * extlinkaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_EXTLINK_ACTION
+
+#include <string.h>
+#include "extlinkaction.h"
+#include "OIDtools.h"
+#include "cgiutils.h"
+
+extlinkaction::extlinkaction () {
+
+  // this action uses cgi variables "a", "d", and "href"
+
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "extlink";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "el";
+  arg_ainfo.longname = "external link preference";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "prompt";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "d";
+  arg_ainfo.longname = "document OID";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "href";
+  arg_ainfo.longname = "URL of external link";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "rl";
+  arg_ainfo.longname = "is relative link";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+}
+
+extlinkaction::~extlinkaction () {
+}
+
+
+void extlinkaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+				      response_t &response, text_t &response_data, 
+				      ostream &logout) {
+
+  text_t link;
+  if (get_link (args, protos, link, logout)) {
+    response = location;
+    response_data = link;
+    return;
+  }
+
+  // external link
+  if (!link.empty()) {
+    if (args["el"] == "direct") {
+      response = location;
+      response_data = link;
+      return;
+    }
+  }
+
+  response = content;
+  response_data = "text/html";
+}
+
+void extlinkaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					    recptprotolistclass * /*protos*/, 
+					    ostream &/*logout*/) {
+  
+  // define_internal_macros sets the following macros:
+
+  // _nexturl_             link to external page
+  // _prevdoc_             link to previous document
+  //  disp.setmacro("nexturl", "extlink", cgi_safe(args["href"]));
+  // problem in whist, above line changed.  Perhaps decode_cgi_arg ??
+  // see also HTML plugin
+  disp.setmacro("nexturl", "extlink", args["href"]);
+  disp.setmacro("prevdoc", "extlink", args["d"]);
+}
+
+
+// if link is found returns true and url in link, otherwise returns
+// false
+bool extlinkaction::get_link (cgiargsclass &args, recptprotolistclass *protos,
+			      text_t &link, ostream &logout) {
+
+    text_t &arg_href = args["href"];
+    text_t &thiscollection = args["c"];
+    if (arg_href.empty()) return false;
+
+    if (args["rl"] == "1") {
+
+      FilterResponse_t response;
+      text_tset metadata;
+      metadata.insert ("section");
+	  
+      recptproto *collectproto = protos->getrecptproto (thiscollection, logout);
+
+      if (get_info (arg_href, thiscollection, args["l"], metadata, false, collectproto, response, logout)) {
+	if (!response.docInfo[0].metadata["section"].values[0].empty()) {
+	  link = "_httpdoc_&d=" + response.docInfo[0].metadata["section"].values[0];
+	  return true;
+	}
+      }
+
+      // need to see if link exists in any other collection
+      // if cross-collection searching/browsing is turned on 
+      if (args["ccs"] == "1" && !args["cc"].empty()) {
+	text_tarray collections;
+	splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
+
+	text_tarray::const_iterator col_here = collections.begin();
+	text_tarray::const_iterator col_end = collections.end();
+
+	while (col_here != col_end) {
+	  
+	  // don't need to check current collection again
+	  if (*col_here == thiscollection) {++col_here; continue;}
+	  
+	  recptproto *collectproto = protos->getrecptproto (*col_here, logout);
+	  if (collectproto == NULL) {++col_here; continue;}
+
+	  if (get_info (arg_href, *col_here, args["l"], metadata, false, collectproto, response, logout)) {
+	    if (!response.docInfo[0].metadata["section"].values[0].empty()) {
+	      link = "_httpdoc_&c=" + *col_here + "&d=" +
+		response.docInfo[0].metadata["section"].values[0];
+	      return true;
+	    }
+	  }
+	  ++col_here;
+	}
+      }
+      return false;
+      
+    } else {
+      // link is external 
+      link = arg_href;
+      return false;
+    }
+}
+
+
+bool extlinkaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			       browsermapclass * /*browsers*/, displayclass &disp,
+			       outconvertclass &outconvert, ostream &textout,
+			       ostream &logout) {
+
+  if (args["href"].empty()) {
+    // oops, this shouldn't happen
+    textout << outconvert << disp << ("_extlink:header_\n")
+	    << ("_extlink:notfoundcontent_\n")
+	    << ("_extlink:footer_\n");
+    return true;
+  }
+
+  if (args["rl"] == "1") {
+    // need to see if link exists in any other collection
+    // if cross-collection searching/browsing is turned on 
+    if (args["ccs"] == "1" && !args["cc"].empty()) {
+      
+      FilterResponse_t response;
+      text_tset metadata;
+      metadata.insert ("section");
+      text_tarray collections;
+      splitchar (args["cc"].begin(), args["cc"].end(), ',', collections);
+      
+      text_tarray::const_iterator col_here = collections.begin();
+      text_tarray::const_iterator col_end = collections.end();
+      
+      while (col_here != col_end) {
+	
+	// don't need to check current collection
+	if (*col_here == args["c"]) {++col_here; continue;}
+	
+	recptproto *collectproto = protos->getrecptproto (*col_here, logout);
+	if (get_info (args["href"], *col_here, args["l"], metadata, false, collectproto, response, logout)) {
+	  if (!response.docInfo[0].metadata["section"].values[0].empty()) {
+	    ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, *col_here, logout);
+	    text_t collectionname = cinfo->get_collectionmeta("collectionname", args["l"]); //
+	    if (collectionname.empty()) {
+	      collectionname = *col_here;
+	    }
+	    textout << outconvert << disp << ("_extlink:header_\n")
+		    << ("_extlink:foundintcontent_(" + *col_here + ", " + collectionname + 
+			", " + response.docInfo[0].metadata["section"].values[0] + "\n")
+		    << ("_extlink:footer_\n");
+	    return true;
+	  }
+	}
+	++col_here;
+      }
+    }
+    textout << outconvert << disp << ("_extlink:header_\n")
+	    << ("_extlink:notfoundcontent_\n")
+	    << ("_extlink:footer_\n");
+    
+    
+  } else {
+    // link is external 
+    textout << outconvert << disp << ("_extlink:header_\n")
+	    << ("_extlink:foundcontent_\n")
+	    << ("_extlink:footer_\n");
+  }
+
+  return true;
+}
+
+#endif //GSDL_USE_EXTLINK_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/extlinkaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/extlinkaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/extlinkaction.h	(revision 10506)
@@ -0,0 +1,69 @@
+/**********************************************************************
+ *
+ * extlinkaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_EXTLINK_ACTION
+
+#ifndef EXTLINKACTION_H
+#define EXTLINKACTION_H
+
+#include "action.h"
+#include "receptionist.h"
+
+class extlinkaction : public action {
+
+
+public:
+  extlinkaction ();
+  virtual ~extlinkaction ();
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  text_t get_action_name () {return "extlink";}
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, 
+			       ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp,
+		  outconvertclass &outconvert, ostream &textout,
+		  ostream &logout);
+
+
+protected:
+  
+  receptionist *recpt;
+  
+  bool get_link (cgiargsclass &args, recptprotolistclass *protos,
+		 text_t &link, ostream &logout);
+
+};
+
+#endif //!EXTLINKACTION_H
+#endif //GSDL_USE_EXTLINK_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/formattools.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/formattools.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/formattools.cpp	(revision 10506)
@@ -0,0 +1,1703 @@
+/**********************************************************************
+ *
+ * formattools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "formattools.h"
+#include "cgiutils.h"
+#include "OIDtools.h"
+#include "summarise.h"
+
+#include <assert.h>
+
+// a few function prototypes
+
+static text_t format_string (const text_t& collection, recptproto* collectproto,
+			     ResultDocInfo_t &docinfo, displayclass &disp, 
+			     format_t *formatlistptr, text_tmap &options,
+			     ostream& logout);
+
+static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end, 
+			  format_t *formatlistptr, text_tset &metadata, bool &getParents);
+
+static text_t format_summary (const text_t& collection, recptproto* collectproto,
+			      ResultDocInfo_t &docinfo, displayclass &disp, 
+			      text_tmap &options, ostream& logout);
+static text_t format_text (const text_t& collection, recptproto* collectproto,
+			      ResultDocInfo_t &docinfo, displayclass &disp, 
+			      text_tmap &options, ostream& logout);
+
+static text_t expand_metadata(const text_t &metavalue, const text_t& collection,
+			      recptproto* collectproto, ResultDocInfo_t &docinfo,
+			      displayclass &disp, text_tmap &options,
+			      ostream &logout);
+
+
+void metadata_t::clear() {
+  metaname.clear();
+  metacommand = mNone;
+  mqualifier.parent  = pNone;
+  mqualifier.sibling = sNone;
+  mqualifier.child   = cNone;
+  parentoptions.clear();
+  siblingoptions.clear();
+  childoptions.clear();
+}
+
+void decision_t::clear() {
+  command = dMeta;
+  meta.clear();
+  text.clear();
+}
+
+void format_t::clear() {
+  command = comText;
+  decision.clear();
+  text.clear();
+  meta.clear();
+  nextptr = NULL;
+  ifptr = NULL;
+  elseptr = NULL;
+  orptr = NULL;
+}
+
+void formatinfo_t::clear() {
+  DocumentImages = false;
+  DocumentTitles = true;
+  DocumentHeading = "{Or}{[parent(Top):Title],[Title],untitled}<br>";
+  DocumentContents = true;
+  DocumentArrowsBottom = true; 
+  DocumentArrowsTop = false; 
+  DocumentButtons.erase (DocumentButtons.begin(), DocumentButtons.end());
+  //  DocumentButtons.push_back ("Expand Text");
+  //  DocumentButtons.push_back ("Expand Contents");
+  DocumentButtons.push_back ("Detach");
+  DocumentButtons.push_back ("Highlight");
+  RelatedDocuments = "";
+  DocumentText = "<center><table width=_pagewidth_><tr><td>[Text]</td></tr></table></center>";
+  formatstrings.erase (formatstrings.begin(), formatstrings.end());
+  DocumentUseHTML = false;
+  AllowExtendedOptions = false;
+}
+
+// simply checks to see if formatstring begins with a <td> tag
+bool is_table_content (const text_t &formatstring) {
+  text_t::const_iterator here = formatstring.begin();
+  text_t::const_iterator end = formatstring.end();
+  
+  while (here != end) {
+    if (*here != ' ') {
+      if ((*here == '<') && ((here+3) < end)) {
+	if ((*(here+1) == 't' || *(here+1) == 'T') &&
+	    (*(here+2) == 'd' || *(here+2) == 'D') &&
+	    (*(here+3) == '>' || *(here+3) == ' '))
+	  return true;
+      } else return false;
+    }
+    ++here;
+  }
+  return false;
+}
+
+bool is_table_content (const format_t *formatlistptr) {
+
+  if (formatlistptr == NULL) return false;
+  
+  if (formatlistptr->command == comText)
+    return is_table_content (formatlistptr->text);
+    
+  return false;
+}
+
+// returns false if key isn't in formatstringmap
+bool get_formatstring (const text_t &key, const text_tmap &formatstringmap,
+		       text_t &formatstring) {
+
+  formatstring.clear();
+  text_tmap::const_iterator it = formatstringmap.find(key);
+  if (it == formatstringmap.end()) return false;
+  formatstring = (*it).second;
+  return true;
+}
+
+// tries to find "key1key2" then "key1" then "key2"
+bool get_formatstring (const text_t &key1, const text_t &key2,  
+		       const text_tmap &formatstringmap,
+		       text_t &formatstring) {
+
+  formatstring.clear();
+  text_tmap::const_iterator it = formatstringmap.find(key1 + key2);
+  if (it != formatstringmap.end()) {
+    formatstring = (*it).second;
+    return true;
+  }
+  it = formatstringmap.find(key1);
+  if (it != formatstringmap.end()) {
+    formatstring = (*it).second;
+    return true;
+  }
+  it = formatstringmap.find(key2);
+  if (it != formatstringmap.end()) {
+    formatstring = (*it).second;
+    return true;
+  }
+  return false;
+}
+
+
+text_t remove_namespace(const text_t &meta_name) {
+  text_t::const_iterator end = meta_name.end();
+  text_t::const_iterator it = findchar(meta_name.begin(), end, '.');
+  if (it != end) {
+    return substr(it+1, end);
+  }
+  return meta_name;
+
+}
+// returns a date of form 31 _textmonthnn_ 1999 
+// input is date of type 19991231
+// at least the year must be present in date
+text_t format_date (const text_t &date) {
+
+  if (date.size() < 4) return "";
+
+  text_t::const_iterator datebegin = date.begin();
+
+  text_t year = substr (datebegin, datebegin+4);
+
+  if (date.size() < 6) return year;
+
+  text_t month = "_textmonth" + substr (datebegin+4, datebegin+6) + "_";
+  int imonth = month.getint();
+  if (imonth < 0 || imonth > 12) return year;
+
+  if (date.size() < 8) return month + " " + year;
+
+  text_t day = substr (datebegin+6, datebegin+8);
+  if (day[0] == '0') day = substr (day.begin()+1, day.end());
+  int iday = day.getint();
+  if (iday < 0 || iday > 31) return month + " " + year;
+    
+  return day + " " + month + " " + year;
+}  
+
+// converts an iso639 language code to its English equivalent
+// I realize that this isn't the pretiest or most efficient implementation,
+// hopefully this ugly Language (and Date too) formatting won't survive to
+// see gsdl-3.0
+text_t iso639 (const text_t &langcode) {
+
+  if (langcode == "aa") return "Afar";
+  if (langcode == "ab") return "Abkhazian";
+  if (langcode == "af") return "Afrikaans";
+  if (langcode == "am") return "Amharic";
+  if (langcode == "ar") return "Arabic";
+  if (langcode == "as") return "Assamese";
+  if (langcode == "ay") return "Aymara";
+  if (langcode == "az") return "Azerbaijani";
+  
+  if (langcode == "ba") return "Bashkir";
+  if (langcode == "be") return "Byelorussian";
+  if (langcode == "bg") return "Bulgarian";
+  if (langcode == "bh") return "Bihari";
+  if (langcode == "bi") return "Bislama";
+  if (langcode == "bn") return "Bengali; Bangla";
+  if (langcode == "bo") return "Tibetan";
+  if (langcode == "br") return "Breton";
+  
+  if (langcode == "ca") return "Catalan";
+  if (langcode == "co") return "Corsican";
+  if (langcode == "cs") return "Czech";
+  if (langcode == "cy") return "Welsh";
+  
+  if (langcode == "da") return "Danish";
+  if (langcode == "de") return "German";
+  if (langcode == "dz") return "Bhutani";
+  
+  if (langcode == "el") return "Greek";
+  if (langcode == "en") return "English";
+  if (langcode == "eo") return "Esperanto";
+  if (langcode == "es") return "Spanish";
+  if (langcode == "et") return "Estonian";
+  if (langcode == "eu") return "Basque";
+  
+  if (langcode == "fa") return "Persian";
+  if (langcode == "fi") return "Finnish";
+  if (langcode == "fj") return "Fiji";
+  if (langcode == "fo") return "Faroese";
+  if (langcode == "fr") return "French";
+  if (langcode == "fy") return "Frisian";
+  
+  if (langcode == "ga") return "Irish";
+  if (langcode == "gd") return "Scots Gaelic";
+  if (langcode == "gl") return "Galician";
+  if (langcode == "gn") return "Guarani";
+  if (langcode == "gu") return "Gujarati";
+  
+  if (langcode == "ha") return "Hausa";
+  if (langcode == "hi") return "Hindi";
+  if (langcode == "hr") return "Croatian";
+  if (langcode == "hu") return "Hungarian";
+  if (langcode == "hy") return "Armenian";
+  
+  if (langcode == "ia") return "Interlingua";
+  if (langcode == "ie") return "Interlingue";
+  if (langcode == "ik") return "Inupiak";
+  if (langcode == "in") return "Indonesian";
+  if (langcode == "is") return "Icelandic";
+  if (langcode == "it") return "Italian";
+  if (langcode == "iw") return "Hebrew";
+  
+  if (langcode == "ja") return "Japanese";
+  if (langcode == "ji") return "Yiddish";
+  if (langcode == "jw") return "Javanese";
+  
+  if (langcode == "ka") return "Georgian";
+  if (langcode == "kk") return "Kazakh";
+  if (langcode == "kl") return "Greenlandic";
+  if (langcode == "km") return "Cambodian";
+  if (langcode == "kn") return "Kannada";
+  if (langcode == "ko") return "Korean";
+  if (langcode == "ks") return "Kashmiri";
+  if (langcode == "ku") return "Kurdish";
+  if (langcode == "ky") return "Kirghiz";
+  
+  if (langcode == "la") return "Latin";
+  if (langcode == "ln") return "Lingala";
+  if (langcode == "lo") return "Laothian";
+  if (langcode == "lt") return "Lithuanian";
+  if (langcode == "lv") return "Latvian, Lettish";
+  
+  if (langcode == "mg") return "Malagasy";
+  if (langcode == "mi") return "Maori";
+  if (langcode == "mk") return "Macedonian";
+  if (langcode == "ml") return "Malayalam";
+  if (langcode == "mn") return "Mongolian";
+  if (langcode == "mo") return "Moldavian";
+  if (langcode == "mr") return "Marathi";
+  if (langcode == "ms") return "Malay";
+  if (langcode == "mt") return "Maltese";
+  if (langcode == "my") return "Burmese";
+  
+  if (langcode == "na") return "Nauru";
+  if (langcode == "ne") return "Nepali";
+  if (langcode == "nl") return "Dutch";
+  if (langcode == "no") return "Norwegian";
+  
+  if (langcode == "oc") return "Occitan";
+  if (langcode == "om") return "(Afan) Oromo";
+  if (langcode == "or") return "Oriya";
+  
+  if (langcode == "pa") return "Punjabi";
+  if (langcode == "pl") return "Polish";
+  if (langcode == "ps") return "Pashto, Pushto";
+  if (langcode == "pt") return "Portuguese";
+  
+  if (langcode == "qu") return "Quechua";
+  if (langcode == "rm") return "Rhaeto-Romance";
+  if (langcode == "rn") return "Kirundi";
+  if (langcode == "ro") return "Romanian";
+  if (langcode == "ru") return "Russian";
+  if (langcode == "rw") return "Kinyarwanda";
+  
+  if (langcode == "sa") return "Sanskrit";
+  if (langcode == "sd") return "Sindhi";
+  if (langcode == "sg") return "Sangro";
+  if (langcode == "sh") return "Serbo-Croatian";
+  if (langcode == "si") return "Singhalese";
+  if (langcode == "sk") return "Slovak";
+  if (langcode == "sl") return "Slovenian";
+  if (langcode == "sm") return "Samoan";
+  if (langcode == "sn") return "Shona";
+  if (langcode == "so") return "Somali";
+  if (langcode == "sq") return "Albanian";
+  if (langcode == "sr") return "Serbian";
+  if (langcode == "ss") return "Siswati";
+  if (langcode == "st") return "Sesotho";
+  if (langcode == "su") return "Sudanese";
+  if (langcode == "sv") return "Swedish";
+  if (langcode == "sw") return "Swahili";
+  
+  if (langcode == "ta") return "Tamil";
+  if (langcode == "te") return "Tegulu";
+  if (langcode == "tg") return "Tajik";
+  if (langcode == "th") return "Thai";
+  if (langcode == "ti") return "Tigrinya";
+  if (langcode == "tk") return "Turkmen";
+  if (langcode == "tl") return "Tagalog";
+  if (langcode == "tn") return "Setswana";
+  if (langcode == "to") return "Tonga";
+  if (langcode == "tr") return "Turkish";
+  if (langcode == "ts") return "Tsonga";
+  if (langcode == "tt") return "Tatar";
+  if (langcode == "tw") return "Twi";
+  
+  if (langcode == "uk") return "Ukrainian";
+  if (langcode == "ur") return "Urdu";
+  if (langcode == "uz") return "Uzbek";
+  
+  if (langcode == "vi") return "Vietnamese";
+  if (langcode == "vo") return "Volapuk";
+  
+  if (langcode == "wo") return "Wolof";
+  
+  if (langcode == "xh") return "Xhosa";
+  
+  if (langcode == "yo") return "Yoruba";
+  
+  if (langcode == "zh") return "Chinese";
+  if (langcode == "zu") return "Zulu";
+  return "";
+}
+
+text_t get_href (const text_t &link) {
+
+  text_t href;
+
+  text_t::const_iterator here = findchar(link.begin(), link.end(), '"');
+  text_t::const_iterator end = link.end();
+  
+  ++here;
+  while (here != end) {
+    if (*here == '"') break;
+    href.push_back(*here);
+    ++here;
+  }
+
+  return href;
+}
+
+//this function gets the information associated with the relation
+//metadata for the document associated with 'docinfo'. This relation
+//metadata consists of a line of pairs containing 'collection, document OID'
+//(this is the OID of the document related to the current document, and
+//the collection the related document belongs to). For each of these pairs
+//the title metadata is obtained and then an html link between the title
+//of the related doc and the document's position (the document will be
+//found in "<a href=\"_httpdocument_&c=collection&cl=search&d=OID">
+//(where collection is the related documents collection, and OID is the
+//related documents OID).  A list of these html links are made for as many
+//related documents as there are. This list is then returned. If there are
+//no related documents available for the current document then the string
+//'.. no related documents .. ' is returned.
+text_t get_related_docs(const text_t& collection, recptproto* collectproto,
+			ResultDocInfo_t &docinfo, ostream& logout){
+  
+  text_tset metadata;
+
+  //insert the metadata we wish to collect
+  metadata.insert("relation"); 
+  metadata.insert("Title");  
+  metadata.insert("Subject"); //for emails, where title data doesn't apply
+ 
+  FilterResponse_t response;
+  text_t relation = ""; //string for displaying relation metadata
+  text_t relationTitle = ""; //the related documents Title (or subject)
+  text_t relationOID = ""; //the related documents OID  
+
+  //get the information associated with the metadata for current doc
+  if (get_info (docinfo.OID, collection, "", metadata, 
+		false, collectproto, response, logout)) {
+    
+    //if the relation metadata exists, store for displaying
+    if(!response.docInfo[0].metadata["relation"].values.empty()){
+      relationOID += response.docInfo[0].metadata["relation"].values[0];
+
+      //split relation data into pairs of collectionname,ID number
+      text_tarray relationpairs;
+      splitchar (relationOID.begin(), relationOID.end(), ' ', relationpairs);
+      
+      text_tarray::const_iterator currDoc = relationpairs.begin();  
+      text_tarray::const_iterator lastDoc = relationpairs.end();
+
+      //iterate through the pairs to split and display
+      while(currDoc != lastDoc){
+	
+	//split pairs into collectionname and ID 
+	text_tarray relationdata;
+	splitchar ((*currDoc).begin(), (*currDoc).end(), ',', relationdata);
+	
+	//get first element in the array (collection)
+	text_tarray::const_iterator doc_data = relationdata.begin();
+	text_t document_collection = *doc_data;
+	++doc_data; //increment to get next item in array (oid)
+	text_t document_OID = *doc_data;
+	
+	//create html link to related document
+	relation += "<a href=\"_httpdocument_&c=" + document_collection;
+	relation += "&cl=search&d=" + document_OID;
+	   
+	//get the information associated with the metadata for related doc
+	if (get_info (document_OID, document_collection, "", metadata,
+		      false, collectproto, response, logout)) {
+	  
+	  //if title metadata doesn't exist, collect subject metadata
+	  //if that doesn't exist, just call it 'related document'
+	  if (!response.docInfo[0].metadata["Title"].values[0].empty())
+		relationTitle = response.docInfo[0].metadata["Title"].values[0];
+	  else if (!response.docInfo[0].metadata["Subject"].values.empty())
+	    relationTitle = response.docInfo[0].metadata["Subject"].values[0];
+	  else relationTitle =  "RELATED DOCUMENT";
+	  
+	}
+	
+	//link the related document's title to its page
+	relation += "\">" + relationTitle + "</a>"; 
+	relation += "  (" + document_collection + ")<br>";
+	
+	++currDoc;
+      }
+    }
+    
+  } 
+
+  if(relation.empty()) //no relation data for documnet
+    relation = ".. no related documents .. ";
+
+  return relation;
+}
+
+
+
+static void get_parent_options (text_t &instring, metadata_t &metaoption) {
+
+  assert (instring.size() > 7);
+  if (instring.size() <= 7) return;
+
+  text_t meta, com, op;
+  bool inbraces = false;
+  bool inquotes = false;
+  bool foundcolon = false;
+  text_t::const_iterator here = instring.begin()+6;
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (foundcolon) meta.push_back (*here);
+    else if (*here == '(') inbraces = true;
+    else if (*here == ')') inbraces = false;
+    else if (*here == '\'' && !inquotes) inquotes = true;
+    else if (*here == '\'' && inquotes) inquotes = false;
+    else if (*here == ':' && !inbraces) foundcolon = true;
+    else if (inquotes) op.push_back (*here);
+    else com.push_back (*here);
+    ++here;
+  }
+
+  instring = meta;
+  if (com.empty())
+    metaoption.mqualifier.parent = pImmediate;
+  else if (com == "Top")
+    metaoption.mqualifier.parent = pTop;
+  else if (com == "All") {
+    metaoption.mqualifier.parent = pAll;
+    metaoption.parentoptions = op;
+  }
+}
+
+
+static void get_sibling_options (text_t &instring, metadata_t &metaoption) {
+
+  assert (instring.size() > 8);
+  if (instring.size() <= 8) return;
+  text_t meta, com, op;
+  bool inbraces = false;
+  bool inquotes = false;
+  bool foundcolon = false;
+  text_t::const_iterator here = instring.begin()+7;
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (foundcolon) meta.push_back (*here);
+    else if (*here == '(') inbraces = true;
+    else if (*here == ')') inbraces = false;
+    else if (*here == '\'' && !inquotes) inquotes = true;
+    else if (*here == '\'' && inquotes) inquotes = false;
+    else if (*here == ':' && !inbraces) foundcolon = true;    
+    else if (inquotes) op.push_back (*here);
+    else com.push_back (*here);
+    ++here;
+  }
+
+  instring = meta;
+  metaoption.siblingoptions.clear();
+
+  if (com.empty()) {
+    metaoption.mqualifier.sibling = sAll;
+    metaoption.siblingoptions = " ";
+  }
+  else if (com == "first") {
+    metaoption.mqualifier.sibling = sNum;
+    metaoption.siblingoptions = "0";
+  }
+  else if (com == "last") {
+    metaoption.mqualifier.sibling = sNum;
+    metaoption.siblingoptions = "-2"; // == last
+  }
+  else if (com.getint()>0) {
+    metaoption.mqualifier.sibling = sNum;
+    int pos = com.getint()-1;
+    metaoption.siblingoptions +=pos;
+  }
+  else {
+    metaoption.mqualifier.sibling = sAll;
+    metaoption.siblingoptions = op;
+  }
+}
+
+static void get_child_options (text_t &instring, metadata_t &metaoption) {
+
+  assert (instring.size() > 6);
+  if (instring.size() <= 6) return;
+  text_t meta, com, op;
+  bool inbraces = false;
+  bool inquotes = false;
+  bool foundcolon = false;
+  text_t::const_iterator here = instring.begin()+5;
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (foundcolon) meta.push_back (*here);
+    else if (*here == '(') inbraces = true;
+    else if (*here == ')') inbraces = false;
+    else if (*here == '\'' && !inquotes) inquotes = true;
+    else if (*here == '\'' && inquotes) inquotes = false;
+    else if (*here == ':' && !inbraces) foundcolon = true;
+    else if (inquotes) op.push_back (*here);
+    else com.push_back (*here);
+    ++here;
+  }
+
+  instring = meta;
+  if (com.empty()) {
+    metaoption.mqualifier.child = cAll;
+    metaoption.childoptions = " ";
+  }
+  else if (com == "first") {
+    metaoption.mqualifier.child = cNum;
+    metaoption.childoptions = ".fc";
+  }
+  else if (com == "last") {
+    metaoption.mqualifier.child = cNum;
+    metaoption.childoptions = ".lc";
+  }
+  else if (com.getint()>0) {
+    metaoption.mqualifier.child = cNum;
+    metaoption.childoptions = "."+com;
+  }
+  else {
+    metaoption.mqualifier.child = cAll;
+    metaoption.childoptions = op;
+  }
+}
+
+
+
+static void parse_meta (text_t &meta, metadata_t &metaoption,
+			text_tset &metadata, bool &getParents) {
+
+  if (meta.size() > 8 && (substr(meta.begin(), meta.begin()+8) == "cgisafe:")) {
+    metaoption.metacommand |= mCgiSafe;
+    meta = substr (meta.begin()+8, meta.end());
+  }
+
+  if (meta.size() > 7 && (substr (meta.begin(), meta.begin()+6) == "parent")) {
+    getParents = true;
+    metaoption.metacommand |= mParent;
+    get_parent_options (meta, metaoption);
+  } 
+  else if (meta.size() > 6 && (substr (meta.begin(), meta.begin()+5) == "child")) {
+    metaoption.metacommand |= mChild;
+    get_child_options (meta, metaoption);
+    metadata.insert("contains");
+  } 
+  // parent and child can have sibling also
+  if (meta.size() > 8 && (substr (meta.begin(), meta.begin()+7) == "sibling")) {
+    metaoption.metacommand |= mSibling;
+    get_sibling_options (meta, metaoption);
+  } 
+  
+  // check for ex. which may occur in format statements
+  if (meta.size()>3 && (substr(meta.begin(), meta.begin()+3) == "ex.")) {
+    meta = substr (meta.begin()+3, meta.end());
+  }
+  metadata.insert (meta);
+  metaoption.metaname = meta;
+}
+
+static void parse_coll_meta(text_t &meta, metadata_t &metaoption) {
+  if (meta == "collection") {
+    // no qualifiers
+    metaoption.metaname = g_EmptyText;
+    return;
+  }
+  meta = substr (meta.begin()+11, meta.end());
+  metaoption.metaname = meta;
+  
+}
+
+static void parse_meta (text_t &meta, format_t *formatlistptr,
+			text_tset &metadata, bool &getParents) {
+  
+  if (meta == "link")
+    formatlistptr->command = comLink;
+  else if (meta == "/link")
+    formatlistptr->command = comEndLink;
+
+  else if (meta == "href")
+    formatlistptr->command = comHref;
+
+  else if (meta == "num")
+    formatlistptr->command = comNum;
+
+  else if (meta == "icon")
+    formatlistptr->command = comIcon;
+
+  else if (meta == "Text")
+    formatlistptr->command = comDoc;
+  
+  else if (meta == "RelatedDocuments")
+   formatlistptr->command = comRel;
+
+  else if (meta == "highlight")
+    formatlistptr->command = comHighlight;
+
+  else if (meta == "/highlight")
+    formatlistptr->command = comEndHighlight;
+
+  else if (meta == "Summary")
+    formatlistptr->command = comSummary;
+
+  else if (meta == "DocImage")
+    formatlistptr->command = comImage; 
+
+  else if (meta == "DocTOC")
+    formatlistptr->command = comTOC; 
+
+  else if (meta == "DocumentButtonDetach")
+     formatlistptr->command = comDocumentButtonDetach;
+  
+  else if (meta == "DocumentButtonHighlight")
+     formatlistptr->command = comDocumentButtonHighlight;
+  
+  else if (meta == "DocumentButtonExpandContents")
+    formatlistptr->command = comDocumentButtonExpandContents; 
+
+  else if (meta == "DocumentButtonExpandText")
+     formatlistptr->command = comDocumentButtonExpandText; 
+
+  else if (meta == "DocOID")
+     formatlistptr->command = comOID; 
+  else if (meta == "DocRank")
+    formatlistptr->command = comRank;
+  else if (meta.size() >= 10 && (substr(meta.begin(), meta.begin()+10) == "collection")) {
+    formatlistptr->command = comCollection;
+    parse_coll_meta(meta, formatlistptr->meta);
+  }
+  else {
+    formatlistptr->command = comMeta;
+    parse_meta (meta, formatlistptr->meta, metadata, getParents);
+  }
+}
+
+
+static bool parse_string (const text_t &formatstring, format_t *formatlistptr, 
+			  text_tset &metadata, bool &getParents) {
+
+  text_t text;
+  text_t::const_iterator here = formatstring.begin();
+  text_t::const_iterator end = formatstring.end();
+
+  while (here != end) {
+
+    if (*here == '\\') {
+      ++here;
+      if (here != end) text.push_back (*here);
+
+    } else if (*here == '{') {
+      if (!text.empty()) {
+	formatlistptr->command = comText;
+	formatlistptr->text = text;
+	formatlistptr->nextptr = new format_t();
+	formatlistptr = formatlistptr->nextptr;
+	
+	text.clear();
+      }
+      if (parse_action (++here, end, formatlistptr, metadata, getParents)) {
+
+	formatlistptr->nextptr = new format_t();
+	formatlistptr = formatlistptr->nextptr;
+	if (here == end) break;
+      }
+    } else if (*here == '[') {
+      if (!text.empty()) {
+	formatlistptr->command = comText;
+	formatlistptr->text = text;
+	formatlistptr->nextptr = new format_t();
+	formatlistptr = formatlistptr->nextptr;
+
+	text.clear();
+      }
+      text_t meta;
+      ++here;
+      while (*here != ']') {
+	if (here == end) return false;
+	meta.push_back (*here);
+	++here;
+      }
+      parse_meta (meta, formatlistptr, metadata, getParents);
+      formatlistptr->nextptr = new format_t();
+      formatlistptr = formatlistptr->nextptr;
+
+    } else 
+      text.push_back (*here);
+
+    if (here != end) ++here;
+  }
+  if (!text.empty()) {
+    formatlistptr->command = comText;
+    formatlistptr->text = text;
+    formatlistptr->nextptr = new format_t();
+    formatlistptr = formatlistptr->nextptr;
+
+  }
+  return true;
+}
+
+
+static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end, 
+			  format_t *formatlistptr, text_tset &metadata, bool &getParents) {
+
+  text_t::const_iterator it = findchar (here, end, '}');
+  if (it == end) return false;
+
+  text_t com = substr (here, it);
+  here = findchar (it, end, '{');
+  if (here == end) return false;
+  else ++here;
+
+  if (com == "If" || com == "if" || com == "IF") formatlistptr->command = comIf;
+  else if (com == "Or" || com == "or" || com == "OR") formatlistptr->command = comOr;
+  else return false;
+
+  int commacount = 0;
+  text_t text;
+  while (here != end) {
+
+    if (*here == '\\') {
+      ++here;
+      if (here != end) text.push_back(*here);
+      
+    } 
+  
+    else if (*here == ',' || *here == '}' || *here == '{') {
+
+      if (formatlistptr->command == comOr) {
+	// the {Or}{this, or this, or this, or this} statement
+	format_t *or_ptr;
+	
+	// find the next unused orptr
+	if (formatlistptr->orptr == NULL) {
+	  formatlistptr->orptr = new format_t();
+	  or_ptr = formatlistptr->orptr;
+	} else {
+	  or_ptr = formatlistptr->orptr;
+	  while (or_ptr->nextptr != NULL)
+	    or_ptr = or_ptr->nextptr;
+	  or_ptr->nextptr = new format_t();
+	  or_ptr = or_ptr->nextptr;
+	}
+
+	if (!text.empty())
+	  {
+	    if (!parse_string(text, or_ptr, metadata, getParents)) { return false; }
+	  }
+
+	if (*here == '{')
+	  {
+	    // Supports: {Or}{[Booktitle],[Title],{If}{[XXXX],aaa,bbb}}
+	    // but not : {Or}{[Booktitle],[Title]{If}{[XXXX],aaa,bbb}}
+	    // The latter can always be re-written:
+	    // {Or}{[Booktitle],{If}{[Title],[Title]{If}{[XXXX],aaa,bbb}}}
+	    
+	    if (!text.empty()) // already used up allocated format_t
+	      {
+		// => allocate new one for detected action
+		or_ptr->nextptr = new format_t();
+		or_ptr = or_ptr->nextptr;
+	      }
+	    if (!parse_action(++here, end, or_ptr, metadata, getParents))
+	      { 
+		return false;
+	      }
+	  }
+	else
+	  {
+	    if (*here == '}') break;
+	  }
+	text.clear();
+
+      } 
+
+      // Parse an {If}{decide,do,else} statement
+      else {
+	
+	// Read the decision component.  
+	if (commacount == 0) {
+	  // Decsion can be a metadata element, or a piece of text.
+	  // Originally Stefan's code, updated 25/10/2000 by Gordon.
+
+	  text_t::const_iterator beginbracket = text.begin();
+	  text_t::const_iterator endbracket = (text.end() - 1);
+
+	  // Decision is based on a metadata element
+	  if ((*beginbracket == '[') && (*endbracket == ']')) {
+	    // Ignore the surrounding square brackets
+	    text_t meta = substr (beginbracket+1, endbracket);
+	    parse_meta (meta, formatlistptr->decision.meta, metadata, getParents);
+	    ++commacount;
+	    text.clear();
+	  } 
+
+	  // Decision is a piece of text (probably a macro like _cgiargmode_).
+	  else {
+
+	    // hunt for any metadata in string, which might be uses in
+	    // to test a condition, e.g. [Format] eq 'PDF'
+	    format_t* dummyformat = new format_t();
+	    // update which metadata fields needed 
+	    // (not interested in updatng formatlistptr)
+	    parse_string (text, dummyformat, metadata, getParents);
+	    delete dummyformat;
+
+	    formatlistptr->decision.command = dText;
+	    formatlistptr->decision.text = text;
+	    ++commacount;
+	    text.clear();
+	  }
+	} 
+
+	// Read the "then" and "else" components of the {If} statement.
+	else {
+	  format_t** nextlistptr = NULL;
+	  if (commacount == 1) {
+	    nextlistptr = &formatlistptr->ifptr;
+	  } else if (commacount == 2 ) {
+	    nextlistptr = &formatlistptr->elseptr;
+	  } else {
+	    return false;
+	  }
+
+	  if (!text.empty()) {
+	    if (*nextlistptr == NULL) {
+	      *nextlistptr = new format_t();
+	    } else {
+
+	      // skip to the end of any format_t statements already added
+	      while ((*nextlistptr)->nextptr != NULL)
+	      {
+		nextlistptr = &(*nextlistptr)->nextptr;
+	      }
+
+	      (*nextlistptr)->nextptr = new format_t();
+	      nextlistptr = &(*nextlistptr)->nextptr;
+	    }
+
+	    if (!parse_string (text, *nextlistptr, metadata, getParents)) 
+	      { 
+		return false; 
+	      }
+	    text.clear();
+	  }
+	  
+	  if (*here == '{')
+	    {
+	      if (*nextlistptr == NULL) {
+		*nextlistptr = new format_t();
+	      } else {
+		// skip to the end of any format_t statements already added
+		while ((*nextlistptr)->nextptr != NULL)
+		  {
+		    nextlistptr = &(*nextlistptr)->nextptr;
+		  }
+
+		(*nextlistptr)->nextptr = new format_t();
+		nextlistptr = &(*nextlistptr)->nextptr;
+	      }
+
+	      if (!parse_action(++here, end, *nextlistptr, metadata, getParents))
+		{ 
+		  return false;
+		}
+	    }
+	  else 
+	    { 
+	      if (*here == '}') break;
+	      ++commacount; 
+	    }
+	}
+      }
+      
+    } else text.push_back(*here);
+    
+    if (here != end) ++here;
+  }
+
+  return true;
+}
+
+
+bool parse_formatstring (const text_t &formatstring, format_t *formatlistptr, 
+			 text_tset &metadata, bool &getParents) {
+
+  formatlistptr->clear();
+  getParents = false;
+
+  return (parse_string (formatstring, formatlistptr, metadata, getParents));
+}
+
+// position -1 for all, -2 for the last, 0 for the first, or x for a particular piece
+// metainfo has all the values for the metadata, meta has the request metadata name and options, position tells which values to get
+static text_t get_formatted_meta_text(MetadataInfo_t &metainfo, const metadata_t &meta, int position, bool no_cgisafe = false) 
+{
+  text_t no_ns_metaname = remove_namespace(meta.metaname);
+  text_t tmp;
+  bool first = true;
+  
+  const int start_i=0;
+  const int end_i = metainfo.values.size()-1;
+  
+  if (position == -1) { // all
+    for (int i=start_i; i<=end_i; ++i) {
+      if (!first) tmp += meta.siblingoptions;
+      if (no_ns_metaname == "Date") tmp += format_date (metainfo.values[i]);
+      else if (no_ns_metaname == "Language") tmp += iso639(metainfo.values[i]);
+      else tmp += metainfo.values[i];
+      first = false;
+      
+    }
+  } else {
+    if (position == -2) { // end
+      position = end_i;
+    } else if (position < start_i || position > end_i) {
+      return "";
+    }
+    if (no_ns_metaname == "Date") tmp += format_date (metainfo.values[position]);
+    else if (no_ns_metaname == "Language") tmp += iso639(metainfo.values[position]);
+    else tmp += metainfo.values[position];
+  }
+  if (meta.metacommand & mCgiSafe && !no_cgisafe) return cgi_safe (tmp);
+  else return tmp;
+}
+
+static text_t get_parent_meta (ResultDocInfo_t &docinfo, const metadata_t &meta, int siblings_values) 
+{
+  
+  MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
+  switch (meta.mqualifier.parent) {
+  case pNone:
+    return "Nothing!!";
+    break;
+
+  case pImmediate:
+    if (parent != NULL) {
+      return get_formatted_meta_text(*parent, meta, siblings_values);
+    }
+    break;
+
+  case pTop:
+    if (parent != NULL) {
+      while (parent->parent != NULL) parent = parent->parent;
+      return get_formatted_meta_text(*parent, meta, siblings_values);
+    }
+    break;
+
+  case pAll:
+    MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
+    if (parent != NULL) {
+      text_tarray tmparray;
+      while (parent != NULL) {
+	tmparray.push_back (get_formatted_meta_text(*parent, meta, siblings_values, true)); // set no_cgisafe to true, as we'll do it once we have all the metadata
+	parent = parent->parent;
+      }
+      // now join them up - use teh parent separator
+      bool first = true;
+      text_t tmp;
+      text_tarray::reverse_iterator here = tmparray.rbegin();
+      text_tarray::reverse_iterator end = tmparray.rend();
+      while (here != end) {
+	if (!first) tmp += meta.parentoptions;
+	tmp += *here;
+	first = false;
+	++here;
+      }
+      if (meta.metacommand & mCgiSafe) return cgi_safe (tmp);
+      else return tmp;
+    }
+  }
+  return "";
+
+}
+
+static text_t get_child_meta (const text_t& collection, 
+			      recptproto* collectproto,
+			      ResultDocInfo_t &docinfo, displayclass &disp,
+			      const metadata_t &meta, text_tmap &options,
+			      ostream& logout, int siblings_values) 
+{
+  if (docinfo.metadata["contains"].values[0].size()==0) return ""; // no children
+  
+  const text_t& child_metaname = meta.metaname;
+  const text_t& child_field = meta.childoptions;
+  text_tset child_metadata;
+  child_metadata.insert(child_metaname); 
+
+  FilterResponse_t child_response;
+  if (meta.mqualifier.child == cNum) {
+    // just one child
+    //get the information associated with the metadata for child doc
+    if (!get_info (docinfo.OID+child_field, collection, "", child_metadata, 
+		   false, collectproto, child_response, logout)) return ""; // invalid child number
+
+      if (child_response.docInfo.empty()) return false; // no info for the child
+  
+      ResultDocInfo_t& child_docinfo = child_response.docInfo[0];
+      MetadataInfo_t& metaname_rec = child_docinfo.metadata[child_metaname];
+  
+      text_t child_metavalue = get_formatted_meta_text(metaname_rec,meta,siblings_values);
+      return expand_metadata(child_metavalue,collection,collectproto,
+			 child_docinfo,disp,options,logout);
+  }
+  
+    
+  if (meta.mqualifier.child != cAll) return false; // invalid qualifier
+  
+  // we need to get all children
+  text_t result = "";
+  text_tarray children;
+  text_t contains = docinfo.metadata["contains"].values[0];
+  splitchar (contains.begin(), contains.end(), ';', children);
+  text_tarray::const_iterator here = children.begin();
+  text_tarray::const_iterator end = children.end();
+  bool first = true;
+  while (here !=end) {
+    text_t oid = *here;
+    here++;
+    if (*(oid.begin()) == '"') translate_parent (oid, docinfo.OID);
+    
+    
+    //get the information associated with the metadata for child doc
+    if (!get_info (oid, collection, "", child_metadata, 
+		   false, collectproto, child_response, logout) ||
+	child_response.docInfo.empty()) {
+      first = false;
+      continue;
+    }
+    
+    
+    ResultDocInfo_t& child_docinfo = child_response.docInfo[0];
+    MetadataInfo_t& metaname_rec = child_docinfo.metadata[child_metaname];
+    
+    text_t child_metavalue = get_formatted_meta_text(metaname_rec,meta,siblings_values);
+    if (!first) result += child_field;
+    first = false;
+    // need to do this here cos otherwise we are in the wrong document
+    result +=  expand_metadata(child_metavalue,collection,collectproto,
+			       child_docinfo,disp,options,logout);
+  }
+  return result;
+    
+}
+
+
+// note: all the format_date stuff is assuming that all Date metadata is going to
+// be of the form yyyymmdd, this is of course, crap ;)
+
+static text_t get_meta (const text_t& collection, recptproto* collectproto,
+			ResultDocInfo_t &docinfo, displayclass &disp,
+			const metadata_t &meta, text_tmap &options,
+			ostream& logout) {
+  
+  // make sure we have the requested metadata
+  MetadataInfo_tmap::iterator it = docinfo.metadata.find (meta.metaname);
+  if (it == docinfo.metadata.end()) return "";
+
+  int siblings_values = 0; // default is no siblings, just the first metadata available
+  if (meta.metacommand & mSibling) {
+    if (meta.mqualifier.sibling == sAll) {
+      siblings_values = -1; //all
+    } else if (meta.mqualifier.sibling == sNum) {
+      siblings_values = meta.siblingoptions.getint();
+    }
+  }
+  if (meta.metacommand & mParent) {
+    return get_parent_meta(docinfo,meta,siblings_values);
+  }
+
+  else if (meta.metacommand & mChild) {
+    return get_child_meta(collection,collectproto,docinfo,disp,meta,
+			    options,logout, siblings_values);
+  }
+  else if (meta.metacommand & mSibling) { // only siblings
+    MetadataInfo_t& metaname_rec = docinfo.metadata[meta.metaname];
+    return get_formatted_meta_text(docinfo.metadata[meta.metaname],meta, siblings_values);
+  }
+  else {
+	
+    // straightforward metadata request (nothing fancy)
+
+    text_t classifier_metaname = docinfo.classifier_metadata_type;
+    int metaname_index 
+      = (classifier_metaname == meta.metaname) ? docinfo.classifier_metadata_offset : 0;
+    return get_formatted_meta_text(docinfo.metadata[meta.metaname], meta, metaname_index);
+  }
+  
+  return "";
+}
+
+static text_t get_or (const text_t& collection, recptproto* collectproto,
+		      ResultDocInfo_t &docinfo, displayclass &disp,
+		      format_t *orptr, text_tmap &options,
+		      ostream& logout) {
+
+  text_t tmp;
+  while (orptr != NULL) {
+
+    tmp = format_string (collection,collectproto,docinfo, disp, orptr, 
+			 options, logout);
+    if (!tmp.empty()) return tmp;
+
+    orptr = orptr->nextptr;
+  }
+  return "";
+}
+
+static bool char_is_whitespace(const char c) 
+{
+  return ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));
+
+}
+
+static int scan_over_whitespace(const text_t& outstring, const int start_pos)
+{
+  int pos = start_pos;
+  while (pos<outstring.size()) {
+    if (!char_is_whitespace(outstring[pos])) {
+      break;
+    }
+    ++pos;
+  }
+
+  return pos;
+}
+
+static int rscan_over_whitespace(const text_t& outstring, const int start_pos)
+{
+  int pos = start_pos;
+  while (pos>=0) {
+    if (!char_is_whitespace(outstring[pos])) {
+      break;
+    }
+    --pos;
+  }
+
+  return pos;
+}
+
+static int rscan_for_whitespace(const text_t& outstring, const int start_pos)
+{
+  int pos = start_pos;
+  while (pos>=0) {
+    if (char_is_whitespace(outstring[pos])) {
+      break;
+    }
+    --pos;
+  }
+
+  return pos;
+}
+
+
+static int rscan_for(const text_t& outstring, const int start_pos, 
+		     const char find_c)
+{
+  int pos = start_pos;
+  while (pos>=0) {
+    char c = outstring[pos];
+    if (outstring[pos] == find_c) {
+      break;
+    }
+    --pos;
+  }
+
+  return pos;
+}
+
+text_t extract_substr(const text_t& outstring, const int start_pos,
+		      const int end_pos)
+{
+  text_t extracted_str;
+  extracted_str.clear();
+
+  for (int pos=start_pos; pos<=end_pos; ++pos) {
+    extracted_str.push_back(outstring[pos]);
+  }
+
+  return extracted_str;
+}
+
+
+static text_t expand_potential_metadata(const text_t& collection, 
+					recptproto* collectproto,
+					ResultDocInfo_t &docinfo, 
+					displayclass &disp,
+					const text_t& intext,
+					text_tmap &options,
+					ostream& logout)
+{
+  text_t outtext;
+
+  // decide if dealing with metadata or text
+
+  text_t::const_iterator beginbracket = intext.begin();
+  text_t::const_iterator endbracket = (intext.end() - 1);
+
+  // Decision is based on a metadata element
+  if ((*beginbracket == '[') && (*endbracket == ']')) {
+    // Ignore the surrounding square brackets
+    text_t meta_text = substr (beginbracket+1, endbracket);
+
+    text_tset metadata;
+    bool getParents =false;
+    metadata_t meta;
+
+    parse_meta (meta_text, meta, metadata, getParents);	
+    outtext 
+      = get_meta (collection,collectproto,docinfo,disp,meta,options,logout);
+  }
+  else {
+    outtext = intext;
+  }
+
+  return outtext;
+}
+
+
+
+
+static bool uses_expression(const text_t& collection, recptproto* collectproto,
+			    ResultDocInfo_t &docinfo,
+			    displayclass &disp,
+			    const text_t& outstring, text_t& lhs_expr,
+			    text_t& op_expr, text_t& rhs_expr,
+			    text_tmap &options,
+			    ostream& logout)
+{
+  // Note: the string may not be of the form: str1 op str2, however
+  // to deterine this we have to process it on the assumption it is,
+  // and if at any point an 'erroneous' value is encountered, return
+  // false and let something else have a go at evaluating it
+
+  // Starting at the end of the string and working backwards ..
+
+  const int outstring_len = outstring.size();
+
+  // skip over white space
+  int rhs_end = rscan_over_whitespace(outstring,outstring_len-1);
+
+  if (rhs_end<=0) { 
+    // no meaningful text or (rhs_end==0) no room for operator
+    return false;
+  }
+
+  // check for ' or " and then scan over token
+  const char potential_quote = outstring[rhs_end];
+  int rhs_start=rhs_end;
+  bool quoted = false;
+
+  if ((potential_quote == '\'') || (potential_quote == '\"')) {
+    --rhs_end;
+    rhs_start = rscan_for(outstring,rhs_end-1,potential_quote) +1;
+    quoted = true;
+  }
+  else {
+    rhs_start = rscan_for_whitespace(outstring,rhs_end-1) +1;
+  }
+
+  if ((rhs_end-rhs_start)<0) {
+    // no meaningful rhs expression
+    return false;
+  }
+
+  // form rhs_expr
+  rhs_expr = extract_substr(outstring,rhs_start,rhs_end);
+
+  // skip over white space
+  const int to_whitespace = (quoted) ? 2 : 1;
+
+  int op_end = rscan_over_whitespace(outstring,rhs_start-to_whitespace);
+  int op_start = rscan_for_whitespace(outstring,op_end-1)+1;
+
+
+  if (op_end-op_start<0) {
+    // no meaningful expression operator
+    return false;
+  }
+
+  op_expr = extract_substr(outstring,op_start,op_end);
+
+
+  // check for operator
+  if ((op_expr != "eq") && (op_expr != "ne") && (op_expr != "gt") &&
+     (op_expr != "ge") && (op_expr != "lt") && (op_expr != "le") && (op_expr != "==") && (op_expr != "!=") &&  (op_expr != ">") && (op_expr != ">=") && (op_expr != "<") && (op_expr != "<=") && (op_expr != "sw") && (op_expr != "ew")) {
+
+    // not a valid operator
+    return false;
+  }
+
+  int lhs_end = rscan_over_whitespace(outstring,op_start-1);
+  if (lhs_end<0) {
+    // no meaningful lhs expression
+    return false;
+  }
+
+  int lhs_start = scan_over_whitespace(outstring,0);
+
+  // form lhs_expr from remainder of string
+  lhs_expr = extract_substr(outstring,lhs_start,lhs_end);
+
+  // Now we know we have a valid expression, look up any 
+  // metadata terms
+
+  rhs_expr = expand_potential_metadata(collection,collectproto,docinfo,
+				       disp,rhs_expr,options,logout);
+  lhs_expr = expand_potential_metadata(collection,collectproto,docinfo,
+				       disp,lhs_expr,options,logout);
+
+  return true;
+}
+
+static bool eval_expression_true(const text_t& lhs_expr,const text_t& op_expr,
+				 const text_t& rhs_expr, ostream& logout)
+{
+  if (op_expr == "eq") return (lhs_expr == rhs_expr);
+  else if (op_expr == "ne" ) return (lhs_expr != rhs_expr);
+  else if (op_expr == "gt") return (lhs_expr > rhs_expr);
+  else if (op_expr == "ge") return (lhs_expr >= rhs_expr);
+  else if (op_expr == "lt") return (lhs_expr < rhs_expr);
+  else if (op_expr == "le") return (lhs_expr <= rhs_expr);
+  else if (op_expr == "==") return (lhs_expr.getint() == rhs_expr.getint());
+  else if (op_expr == "!=") return (lhs_expr.getint() != rhs_expr.getint());
+  else if (op_expr == ">") return (lhs_expr.getint() > rhs_expr.getint());
+  else if (op_expr == ">=") return (lhs_expr.getint() >= rhs_expr.getint());
+  else if (op_expr == "<") return (lhs_expr.getint() < rhs_expr.getint());
+  else if (op_expr == "<=") return (lhs_expr.getint() <= rhs_expr.getint());
+  else if (op_expr == "sw") return (starts_with(lhs_expr,rhs_expr));
+  else if (op_expr == "ew") return (ends_with(lhs_expr,rhs_expr));
+  else {
+    logout << "Error: '" << op_expr << "' is not a recognised operator." << endl;
+  }
+  
+  return false;
+}
+
+
+static text_t get_if (const text_t& collection, recptproto* collectproto,
+		      ResultDocInfo_t &docinfo, displayclass &disp, 
+		      const decision_t &decision,
+		      format_t *ifptr, format_t *elseptr,
+		      text_tmap &options, ostream& logout) 
+{
+  // If the decision component is a metadata element, then evaluate it
+  // to see whether we output the "then" or the "else" clause
+  if (decision.command == dMeta) {
+    if (get_meta (collection,collectproto,docinfo,disp,decision.meta,options,
+		  logout) != "") {
+      if (ifptr != NULL)
+	return get_formatted_string (collection,collectproto,docinfo, disp, ifptr, 
+				     options, logout);
+    }
+    else {
+      if (elseptr != NULL)
+	return get_formatted_string (collection,collectproto,docinfo, disp, elseptr,
+				     options, logout);
+    }
+  }
+
+  // If the decision component is text, then evaluate it (it is probably a 
+  // macro like _cgiargmode_) to decide what to output.
+  else if (decision.command == dText) {
+
+    text_t outstring;
+    disp.expandstring (decision.text, outstring);
+
+    // Check for if expression in form: str1 op str2 
+    // (such as [x] eq "y")
+    text_t lhs_expr, op_expr, rhs_expr;
+    if (uses_expression(collection,collectproto,docinfo, disp, outstring,lhs_expr,op_expr,rhs_expr, options,logout)) {
+      if (eval_expression_true(lhs_expr,op_expr,rhs_expr,logout)) {
+	if (ifptr != NULL) {
+	  return get_formatted_string (collection, collectproto, docinfo, disp, ifptr, 
+				       options, logout);
+	}
+	else {
+	  return "";
+	}
+      } else {
+	if (elseptr != NULL) {
+	  return get_formatted_string (collection, collectproto, docinfo, disp, elseptr,
+				       options, logout);
+	}
+	else {
+	  return "";
+	}
+      }
+    }
+
+
+    // This is a tad tricky.  When we expand a string like _cgiargmode_, that is
+    // a cgi argument macro that has not been set, it evaluates to itself.
+    // Therefore, were have to say that a piece of text evalautes true if
+    // it is non-empty and if it is a cgi argument evaulating to itself.
+
+    if ((outstring != "") && !((outstring == decision.text) && (outstring[0] == '_'))) {
+      if (ifptr != NULL)
+	return get_formatted_string (collection, collectproto, docinfo, disp, ifptr, 
+				     options, logout);
+    } else {
+      if (elseptr != NULL)
+	return get_formatted_string (collection, collectproto, docinfo, disp, elseptr,
+				     options, logout);
+    }
+  }
+  
+  return "";
+}
+
+bool includes_metadata(const text_t& text)
+{
+  text_t::const_iterator here = text.begin();
+  text_t::const_iterator end = text.end();
+  while (here != end) {
+    if (*here == '[') return true;
+    ++here;
+  }
+
+  return false;
+}
+
+static text_t expand_metadata(const text_t &metavalue, const text_t& collection,
+			      recptproto* collectproto,
+			      ResultDocInfo_t &docinfo,
+			      displayclass &disp, text_tmap &options,
+			      ostream &logout) {
+      
+  if (includes_metadata(metavalue)) {
+    
+    // text has embedded metadata in it => expand it
+    FilterRequest_t request;
+    FilterResponse_t response;
+    
+    request.getParents = false;
+    
+    format_t *expanded_formatlistptr = new format_t();
+    parse_formatstring (metavalue, expanded_formatlistptr, 
+			request.fields, request.getParents);
+    
+    // retrieve metadata
+    get_info(docinfo.OID, collection, "", request.fields, request.getParents,
+	     collectproto, response, logout);
+    
+    if (!response.docInfo.empty()) {
+      
+      text_t expanded_metavalue
+	= get_formatted_string(collection, collectproto,
+			       response.docInfo[0], disp, expanded_formatlistptr, 
+			       options, logout);
+      
+      return expanded_metavalue;
+    }
+    else {
+      return metavalue;
+    }
+  }
+  else {
+    
+    return metavalue;
+  }
+}
+
+text_t get_collection_meta(const text_t& collection, recptproto* collectproto,
+			   displayclass &disp, 
+			   text_t meta_name, ostream& logout) {
+  
+  ColInfoResponse_t collectinfo;
+  comerror_t err;
+  collectproto->get_collectinfo (collection, collectinfo,err,logout);
+  text_t meta_value = "";
+  text_t lang;
+  disp.expandstring("_cgiargl_",lang);
+  if (lang.empty()) {
+    lang = "en";
+  }
+
+  if (err == noError) {
+    meta_value = collectinfo.get_collectionmeta(meta_name, lang);
+  }
+  return meta_value;
+  
+
+}
+text_t format_string (const text_t& collection, recptproto* collectproto,
+		      ResultDocInfo_t &docinfo, displayclass &disp, 
+		      format_t *formatlistptr, text_tmap &options,
+		      ostream& logout) {
+
+  if (formatlistptr == NULL) return "";
+
+  switch (formatlistptr->command) {
+     case comOID:
+	return docinfo.OID;
+  case comRank:
+    return text_t(docinfo.ranking);
+     case comText:
+	return formatlistptr->text;
+     case comLink:
+	return options["link"];
+     case comEndLink:
+	if (options["link"].empty()) return "";
+	else return "</a>";
+     case comHref:
+	return get_href(options["link"]);
+     case comIcon:
+	return options["icon"];
+     case comNum:
+	return docinfo.result_num;
+     case comRel: //if [RelatedDocuments] appears in format string, collect relation data
+	return get_related_docs(collection, collectproto, docinfo, logout);
+     case comSummary:
+	return format_summary(collection, collectproto, docinfo, disp, options, logout);
+     case comMeta:
+	{
+	   const text_t& metavalue =  get_meta (collection,collectproto, docinfo, disp,formatlistptr->meta,options,logout);
+	   return expand_metadata(metavalue, collection, collectproto, docinfo, disp, options, logout);
+	}
+     case comDoc:
+	return format_text(collection, collectproto, docinfo, disp, options, logout);
+	//return options["text"];
+     case comImage:
+	return expand_metadata(options["DocImage"], collection, collectproto, docinfo, disp, options, logout);
+     case comTOC:
+	return options["DocTOC"];
+     case comDocumentButtonDetach:
+	return options["DocumentButtonDetach"];
+     case comDocumentButtonHighlight:
+	return options["DocumentButtonHighlight"];
+     case comDocumentButtonExpandContents:
+	return options["DocumentButtonExpandContents"];
+     case comDocumentButtonExpandText:
+	return options["DocumentButtonExpandText"];
+     case comHighlight:
+	if (options["highlight"] == "1") return "<b>";
+	break;
+     case comEndHighlight:
+	if (options["highlight"] == "1") return "</b>";
+	break;
+     case comIf:
+	return get_if (collection, collectproto, docinfo, disp, 
+		       formatlistptr->decision, formatlistptr->ifptr, 
+		       formatlistptr->elseptr, options, logout);
+     case comOr:
+	return get_or (collection,collectproto, docinfo, disp, formatlistptr->orptr, 
+		       options, logout);
+     case comCollection:
+       if (formatlistptr->meta.metaname == g_EmptyText) {
+	 return collection;
+       }
+       return get_collection_meta(collection, collectproto, disp, formatlistptr->meta.metaname, logout);
+    
+  }
+  return "";
+}
+
+text_t get_formatted_string (const text_t& collection, recptproto* collectproto,
+			     ResultDocInfo_t &docinfo, displayclass &disp,
+			     format_t *formatlistptr, text_tmap &options,
+			     ostream& logout) {
+
+   text_t ft;
+   while (formatlistptr != NULL) 
+      {
+	 ft += format_string (collection, collectproto, docinfo, disp, formatlistptr, 
+			      options, logout);
+	 formatlistptr = formatlistptr->nextptr;
+      }
+   
+   return ft;
+}
+
+
+// we have only preloaded the text in DocumentAction. But you may want to get the text in query. so copy what we have done with format_summary and get the text here. probably is quite expensive?
+text_t format_text (const text_t& collection, recptproto* collectproto,
+		    ResultDocInfo_t &docinfo, displayclass &disp, 
+		    text_tmap &options, ostream& logout) {
+  if(!options["text"].empty()) { 
+    return options["text"];
+  }
+  // else get document text here
+  DocumentRequest_t docrequest;
+  DocumentResponse_t docresponse;
+  comerror_t err;
+  docrequest.OID = docinfo.OID;
+  collectproto->get_document (collection, docrequest, docresponse, err, logout);
+  return docresponse.doc;
+
+}
+  
+/* FUNCTION NAME: format_summary
+ * DESC: this is invoked when a [Summary] special metadata is processed.
+ * RETURNS: a query-biased summary for the document */
+
+text_t format_summary (const text_t& collection, recptproto* collectproto,
+		       ResultDocInfo_t &docinfo, displayclass &disp, 
+		       text_tmap &options, ostream& logout) {
+
+  // GRB: added code here to ensure that the cstr (and other collections)
+  //      uses the document metadata item Summary, rather than compressing
+  //      the text of the document, processed via the methods in
+  //      summarise.cpp
+  if (docinfo.metadata.count("Summary") > 0 &&
+      docinfo.metadata["Summary"].values.size() > 0) {
+    return docinfo.metadata["Summary"].values[0];
+  }
+
+  text_t textToSummarise, query;
+  if(options["text"].empty()) { // get document text
+     DocumentRequest_t docrequest;
+     DocumentResponse_t docresponse;
+     comerror_t err;
+     docrequest.OID = docinfo.OID;
+     collectproto->get_document (collection, docrequest, docresponse, err, logout);
+     textToSummarise = docresponse.doc;
+  } else // in practice, this would not happen, because text is only 
+         // loaded with the [Text] command
+     textToSummarise = options["text"];
+  disp.expandstring("_cgiargq_",query);
+  return summarise(textToSummarise,query,80);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/formattools.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/formattools.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/formattools.h	(revision 10506)
@@ -0,0 +1,145 @@
+/**********************************************************************
+ *
+ * formattools.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef FORMATTOOLS_H
+#define FORMATTOOLS_H
+
+#include "text_t.h"
+#include "comtypes.h"
+#include "recptproto.h"
+#include "display.h"
+
+enum command_t {comIf, comOr, comMeta, comText, comLink, comEndLink, comNum, comIcon, 
+		comDoc, comHighlight, comEndHighlight, comRel, comHref, comSummary,
+		comTOC, comImage, comDocumentButtonDetach, comDocumentButtonHighlight,
+		comDocumentButtonExpandContents, comDocumentButtonExpandText, comOID, comRank, comCollection};
+
+enum mcommand_t {mNone=0, mCgiSafe=1, mParent=2, mSibling=4, mChild=8};
+
+enum pcommand_t {pNone, pImmediate, pTop, pAll};
+enum scommand_t {sNone, sAll, sNum};
+enum ccommand_t {cNone, cAll, cNum};
+enum dcommand_t {dMeta, dText};
+
+struct metadata_t {
+  void clear();
+  metadata_t () {clear();}
+
+  text_t metaname;
+  int metacommand; // used to hold flags from mcommand_t
+  struct {
+    pcommand_t parent;
+    scommand_t sibling;
+    ccommand_t child;
+  } mqualifier;
+
+  text_t parentoptions;
+  text_t siblingoptions;
+  text_t childoptions;
+};
+
+
+// The decision component of an {If}{decision,true-text,false-text}
+// formatstring.  The decision can be based on metadata or on text;
+// normally that text would be a macro like _cgiargmode_.  --gordon
+struct decision_t {
+  void clear();
+  decision_t () {clear();}
+
+  dcommand_t command;
+  metadata_t meta;
+  text_t text;
+};
+
+struct format_t {
+  void clear();
+  format_t () {clear();}
+
+  command_t command;
+  decision_t decision;
+  text_t text;
+  metadata_t meta;
+  format_t *nextptr;
+  format_t *ifptr;
+  format_t *elseptr;
+  format_t *orptr;
+};
+
+// the format structure used by this receptionist
+struct formatinfo_t {
+  void clear();
+  formatinfo_t () {clear();}
+
+  bool DocumentImages;
+  bool DocumentTitles;
+  text_t DocumentHeading;
+  bool DocumentContents;
+  bool DocumentArrowsBottom;
+  bool DocumentArrowsTop;
+  text_tarray DocumentButtons;
+  text_t DocumentText;
+  //-----------------
+  text_t RelatedDocuments;
+  //----------------
+  text_tmap formatstrings;
+  bool DocumentUseHTML;
+  bool AllowExtendedOptions;
+};
+
+bool is_table_content (const text_t &formatstring);
+bool is_table_content (const format_t *formatlistptr);
+
+bool get_formatstring (const text_t &key, const text_tmap &formatstringmap,
+		       text_t &formatstring);
+bool get_formatstring (const text_t &key1, const text_t &key2,  
+		       const text_tmap &formatstringmap,
+		       text_t &formatstring);
+
+text_t format_date (const text_t &date);
+
+text_t remove_namespace(const text_t &meta_name);
+
+text_t iso639 (const text_t &langcode);
+
+text_t get_href (const text_t &link);
+
+text_t get_related_docs(const text_t& collection, recptproto* collectproto,
+			  ResultDocInfo_t &docinfo, ostream& logout);
+
+
+bool parse_formatstring (const text_t &formatstring, format_t *formatlistptr, 
+			 text_tset &metadata, bool &getParents);
+
+
+
+text_t get_formatted_string (const text_t& collection, recptproto* collectproto,
+			     ResultDocInfo_t &docinfo, displayclass &disp,
+			     format_t *formatlistptr, text_tmap &options,
+			     ostream& logout);
+
+#endif
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/gsdl_compatibility_cfg.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/gsdl_compatibility_cfg.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/gsdl_compatibility_cfg.h	(revision 10506)
@@ -0,0 +1,38 @@
+#ifndef GSDL_COMPATIBILITY_CFG__H
+#define GSDL_COMPATIBILITY_CFG__H
+
+/**********************************************************************
+ *
+ * gsdl_compatibility_cfg.h -- 
+ * Copyright (C) 2004  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.
+ *
+ *********************************************************************/
+
+//OLD NAME	NEW NAME
+#define __USE_MULTILANGUAGE_INTERFACE_         GSDL_USE_MULTILANGUAGE_INTERFACE
+#define GSDL_USE_GENERATOR_FEATURE             GSDL_USE_GENERATOR_ACTION
+#define GSDL_USE_EXPORT_FEATURE                GSDL_USE_EXPORT_ACTION
+#define __USE_CLASSIFIER_BROWSER_              GSDL_USE_CLASSIFIER_BROWSER
+#define GSDL_USE_CLONEBROWSERCLASS             GSDL_USE_CLONE_BROWSER
+#define __SOURCE_DIRECTORY_                    GSDL_SOURCE_DIRECTORY
+
+
+#endif //!GSDL_COMPATIBILITY_CFG__H
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/gsdl_modules_cfg.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/gsdl_modules_cfg.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/gsdl_modules_cfg.h	(revision 10506)
@@ -0,0 +1,89 @@
+#ifndef GSDL_MODULES_CFG__H
+#define GSDL_MODULES_CFG__H
+
+/**********************************************************************
+ *
+ * gsdl_modules_cfg.h -- 
+ * Copyright (C) 2004  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.
+ *
+ *********************************************************************/
+
+// BASE CONFIG
+#define GSDL_USE_PER_COLLECTION_SETTINGS
+#define GSDL_SOURCE_DIRECTORY            "files"
+
+// FNORD CONFIG
+#define GSDL_USE_MULTILANGUAGE_INTERFACE
+
+//RECEPTIONIST CONFIG
+#define GSDL_USE_SESSIONS
+
+//QUERY CONFIG
+#define GSDL_USE_REMOVE_TAG_TERMS
+#undef  GSDL_USE_SAFEM_QUERY_FORMAT
+
+//DOCUMENT CONFIG
+// ONLY ONE GSDL_SKIP_* option can be enabled
+#define GSDL_SKIP_ONLY_EMPTY_DOC
+#undef  GSDL_SKIP_ALL_EMPTY_DOC_PARTS
+#undef  GSDL_USE_DOCUMENT_ASSOC_LANGS
+#define GSDL_USE_CL_SINGLE_DOCUMENT
+
+
+//ACTION MODULES
+#define GSDL_USE_AUTHEN_ACTION
+#define GSDL_USE_BROWSE_ACTION
+#define GSDL_USE_COLLECTOR_ACTION
+#define GSDL_USE_EXTLINK_ACTION
+#undef  GSDL_USE_GTI_ACTION
+#define GSDL_USE_PHIND_ACTION
+#define GSDL_USE_PING_ACTION
+#define GSDL_USE_STATUS_ACTION
+#define GSDL_USE_TIP_ACTION
+#define GSDL_USE_USERS_ACTION
+
+#undef  GSDL_USE_CL_DISPLAY_ACTION
+#undef  GSDL_USE_COURSES_ACTION
+#undef  GSDL_USE_DIR_BROWSE_ACTION
+#undef  GSDL_USE_EXPORT_ACTION
+#undef  GSDL_USE_GENERATOR_ACTION
+#undef  GSDL_USE_INDEX_BROWSE_ACTION
+
+
+//BROWSER MODULES
+#undef  GSDL_USE_CLASSIFIER_BROWSER
+#undef  GSDL_USE_TREE_EX_CLASSIFIER_BROWSER
+#undef  GSDL_USE_CLONE_BROWSER
+#define GSDL_USE_DATELIST_BROWSER
+#define GSDL_USE_HTML_BROWSER
+#define GSDL_USE_PAGED_BROWSER
+#define GSDL_USE_PHIND_BROWSER
+
+//FILTERS
+#undef  GSDL_USE_DIR_BROWSEFILTER
+
+//BROWSERS ADD-IN
+#define GSDL_USE_BY_BOOK_MACROS
+#undef  GSDL_USE_FLOAT_TOC
+
+#include "gsdl_compatibility_cfg.h"
+
+#endif //!GSDL_MODULES_CFG__H
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/gtiaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/gtiaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/gtiaction.cpp	(revision 10506)
@@ -0,0 +1,654 @@
+/**********************************************************************
+ *
+ * gtiaction.cpp -- 
+ * Copyright (C) 2005  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_GTI_ACTION
+
+
+#include <expat.h>
+#include <stdio.h>
+#include <sys/utsname.h>
+#include "gtiaction.h"
+#include "fileutil.h"
+#include "gsdlunicode.h"
+
+
+
+gtiaction::gtiaction()
+{
+  cgiarginfo arg_ainfo;
+
+  arg_ainfo.shortname = "tlc";
+  arg_ainfo.longname = "translation target language code";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (&cerr, arg_ainfo);
+
+  arg_ainfo.shortname = "tfk";
+  arg_ainfo.longname = "translation file key";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (&cerr, arg_ainfo);
+
+  arg_ainfo.shortname = "ncpp";
+  arg_ainfo.longname = "number of chunks per page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (&cerr, arg_ainfo);
+}
+
+
+
+gtiaction::~gtiaction()
+{
+  delete[] set_gsdlhome_cstr;
+  delete[] set_gsdlos_cstr;
+}
+
+
+
+bool gtiaction::init (ostream& /*logout*/)
+{
+  // Set GSDLHOME and GSDLOS environment variables
+  text_t set_gsdlhome = "GSDLHOME=" + gsdlhome;
+  text_t set_gsdlos = "GSDLOS=";
+
+#if defined (__WIN32__)
+  set_gsdlos += "windows";
+#else
+  struct utsname *buf = new struct utsname();
+  if (uname(buf) == -1) {
+    // uname failed, so this must be linux
+    set_gsdlos += "linux";
+  }
+  else {
+    text_t gsdlos = buf->sysname;
+    lc(gsdlos);
+    set_gsdlos += gsdlos;
+  }
+  delete buf;
+#endif
+
+  // These will be cleaned up in the destructor
+  set_gsdlhome_cstr = set_gsdlhome.getcstr();
+  set_gsdlos_cstr = set_gsdlos.getcstr();
+  putenv(set_gsdlhome_cstr);
+  putenv(set_gsdlos_cstr);
+
+  return true;
+}
+
+
+
+bool gtiaction::check_cgiargs(cgiargsinfoclass& /*argsinfo*/, cgiargsclass& args,
+			      recptprotolistclass* /*protos*/, ostream& logout)
+{
+  // Authenticate the user, except for the "home" and "lang" pages
+  if (args["p"] != "home" && args["p"] != "lang") {
+    args["uan"] = 1;
+    args["ug"] = "langadmin_" + args["tlc"];
+  }
+
+  return true;
+}
+
+
+
+bool gtiaction::do_action(cgiargsclass& args, recptprotolistclass* /*protos*/, 
+			  browsermapclass* /*browsers*/, displayclass& disp, 
+			  outconvertclass& outconvert, ostream& textout, 
+			  ostream& logout)
+{
+  textout << outconvert << disp << ("_gti:header_\n") << ("_gti:content_\n") << ("_gti:footer_\n");
+  return true;
+}
+
+
+
+void gtiaction::get_cgihead_info(cgiargsclass& /*args*/, recptprotolistclass* /*protos*/,
+				 response_t& response, text_t& response_data, 
+				 ostream& logout)
+{
+  response = content;
+  response_data = "text/html";
+}
+
+
+
+void gtiaction::define_internal_macros(displayclass& disp, cgiargsclass& args, 
+				       recptprotolistclass* protos, ostream& logout)
+{
+  // logout << endl << "Arguments: " << args << endl;
+  logout << endl << "CGI arg p: " << args["p"] << endl;
+
+  // For some reason this must be done as well as setting the macro in gti.dm
+  disp.setmacro("imagepref", displayclass::defaultpackage, "_gti:imagepref_");
+
+  // Define the page content for the GTI home page
+  if (args["p"] == "home") {
+    define_gti_home_page(disp, args, logout);
+    return;
+  }
+
+  // Define the page content for the GTI language page
+  if (args["p"] == "lang") {
+    define_gti_lang_page(disp, args, logout);
+    return;
+  }
+
+  // Define the page content for the GTI search page
+  if (args["p"] == "find") {
+    define_gti_find_page(disp, args, logout);
+    return;
+  }
+
+  // Process user translations
+  if (args["p"] == "submit") {
+    process_gti_submissions(disp, args, logout, true);
+  }
+
+  // Define the page content for the GTI core pages (containing the translation input forms)
+  define_gti_core_page(disp, args, logout);
+}
+
+
+
+void gtiaction::define_gti_home_page(displayclass& disp, cgiargsclass& args, ostream& logout)
+{
+  disp.setmacro("gtiformcontent", "gti", "_gti:gtihome_");
+
+  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
+
+  // Get the languages specified in the main.cfg file, and put them into a map to sort by name
+  text_tmap gti_languages_name_code_mapping;
+  languageinfo_tmap::const_iterator loaded_language = loaded_languages.begin();
+  while (loaded_language != loaded_languages.end()) {
+    // English is not a valid GTI target language, since it is the source language
+    if (loaded_language->first != "en") {
+      gti_languages_name_code_mapping[loaded_language->second.longname] = loaded_language->first;
+    }
+    ++loaded_language;
+  }
+
+  // Set the gtitlcselection macro
+  text_t gti_tlc_selection = "<select name=\"tlc\">\n";
+  text_tmap::iterator gti_language = gti_languages_name_code_mapping.begin();
+  while (gti_language != gti_languages_name_code_mapping.end()) {
+    gti_tlc_selection += "<option value=\"" + gti_language->second + "\">" + gti_language->first + "</option>\n";
+    ++gti_language;
+  }
+  gti_tlc_selection += "</select>";
+  disp.setmacro("gtitlcselection", "gti", gti_tlc_selection);
+}
+
+
+
+void gtiaction::define_gti_lang_page(displayclass& disp, cgiargsclass& args, ostream& logout)
+{
+  // Get the target language code from the CGI arguments
+  text_t target_language_code = args["tlc"];
+
+  disp.setmacro("gtiformcontent", "gti", "_gti:gtilang_");
+
+  // Send a request to gti.pl to get the valid translation files
+  text_t gti_arguments = "get-language-status " + target_language_code;
+  GTI_Response gti_response = parse_gti_response(do_gti_request(gti_arguments, logout), logout);
+  if (gti_response.error_message != "") {
+    // An error has occurred
+    disp.setmacro("gtiformcontent", "gti", "_gti:gtierror_");
+    disp.setmacro("gtierrormessage", "gti", gti_response.error_message);
+    return;
+  }
+
+  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
+  disp.setmacro("gtitargetlanguagename", "gti", loaded_languages[target_language_code].longname);
+
+  // Set the gtitfkselection macro
+  text_t gti_tfk_selection = "<table>";
+  text_tmap::iterator translation_file = gti_response.translation_files_index_to_key_mapping.begin();
+  while (translation_file != gti_response.translation_files_index_to_key_mapping.end()) {
+    text_t translation_file_key = translation_file->second;
+
+    gti_tfk_selection += "<tr><td>";
+    gti_tfk_selection += "<input type=\"radio\" name=\"tfk\" value=\"" + translation_file_key + "\"></td>\n";
+    gti_tfk_selection += "<td>_textgti" + translation_file_key + "_</td></tr>\n";
+
+    text_t num_chunks_translated = gti_response.translation_files_key_to_num_chunks_translated_mapping[translation_file_key];
+    text_t num_chunks_requiring_translation = gti_response.translation_files_key_to_num_chunks_requiring_translation_mapping[translation_file_key];
+    text_t num_chunks_requiring_updating = gti_response.translation_files_key_to_num_chunks_requiring_updating_mapping[translation_file_key];
+    gti_tfk_selection += "<tr><td></td><td>_gtitranslationfilestatus_(" + num_chunks_translated + "," + num_chunks_requiring_translation + "," + num_chunks_requiring_updating + ")</td></tr>\n";
+    ++translation_file;
+  }
+  gti_tfk_selection += "</table>";
+  disp.setmacro("gtitfkselection", "gti", gti_tfk_selection);
+}
+
+
+
+void gtiaction::define_gti_find_page(displayclass& disp, cgiargsclass& args, ostream& logout)
+{
+  // Get the target language code and file to translate from the CGI arguments
+  text_t target_language_code = args["tlc"];
+  text_t translation_file_key = args["tfk"];
+  text_t query_string = to_utf8(args["q"]);
+
+  // Process user corrections
+  if (args["sp"] != "") {
+    process_gti_submissions(disp, args, logout, false);
+  }
+
+  disp.setmacro("gtiformcontent", "gti", "_gti:gtifind_");
+
+  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
+  disp.setmacro("gtitargetlanguagename", "gti", loaded_languages[target_language_code].longname);
+  disp.setmacro("gtitranslationfiledesc", "gti", "_gti:textgti" + translation_file_key + "_");
+
+  if (query_string == "") {
+    // No query, so no search results
+    disp.setmacro("gtifindformcontent", "gti", "");
+    return;
+  }
+
+  // Display text right to left if target language is Arabic or Farsi
+  if (target_language_code == "ar" || target_language_code == "fa") {
+    disp.setmacro("gtitextdirection", "gti", "rtl");
+  }
+  else {
+    disp.setmacro("gtitextdirection", "gti", "ltr");
+  }
+
+  // Send a request to gti.pl to get the valid translation files
+  logout << "Query argument: " << query_string << endl;
+  text_t gti_arguments = "search-chunks " + target_language_code + " " + translation_file_key + " " + query_string;
+  GTI_Response gti_response = parse_gti_response(do_gti_request(gti_arguments, logout), logout);
+  if (gti_response.error_message != "") {
+    // An error has occurred
+    disp.setmacro("gtiformcontent", "gti", "_gti:gtierror_");
+    disp.setmacro("gtierrormessage", "gti", gti_response.error_message);
+    return;
+  }
+
+  disp.setmacro("gtinumchunksmatchingquery", "gti", gti_response.num_chunks_matching_query);
+
+  // Loop through the chunks returned, displaying them on the page
+  text_t gti_find_form_content = "_gtifindformheader_\n";
+  text_tmap::iterator chunk_key_iterator = gti_response.target_file_chunks_key_to_text_mapping.begin();
+  while (chunk_key_iterator != gti_response.target_file_chunks_key_to_text_mapping.end()) {
+    text_t chunk_key = chunk_key_iterator->first;
+
+    // Need to escape any underscores in the chunk key to show it correctly on the page
+    text_t chunk_key_escaped = escape_all(chunk_key, '_');
+
+    // Need to escape any backslashes, underscores, commas, parentheses, and single quotes in the chunk text
+    text_t target_file_chunk_text = gti_response.target_file_chunks_key_to_text_mapping[chunk_key];
+    text_t target_file_chunk_text_escaped = escape_all(target_file_chunk_text, '\\');
+    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '_');
+    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, ',');
+    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '(');
+    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, ')');
+    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '\'');
+
+    // This chunk matches the query
+    gti_find_form_content += "_gtichunkmatchingquery_(" + chunk_key_escaped + "," + target_file_chunk_text_escaped + ")\n";
+
+    chunk_key_iterator++;
+  }
+  gti_find_form_content += "_gtifindformfooter_\n";
+
+  disp.setmacro("gtifindformcontent", "gti", gti_find_form_content);
+}
+
+
+
+void gtiaction::define_gti_core_page(displayclass& disp, cgiargsclass& args, ostream& logout)
+{
+  // Get the target language code and file to translate from the CGI arguments
+  text_t target_language_code = args["tlc"];
+  text_t translation_file_key = args["tfk"];
+  text_t num_chunks_per_page = args["ncpp"];
+  logout << "Num chunks per page: " << num_chunks_per_page << endl;
+
+  disp.setmacro("gtiformcontent", "gti", "_gti:gticore_");
+
+  // Display text right to left if target language is Arabic or Farsi
+  if (target_language_code == "ar" || target_language_code == "fa") {
+    disp.setmacro("gtitextdirection", "gti", "rtl");
+  }
+  else {
+    disp.setmacro("gtitextdirection", "gti", "ltr");
+  }
+
+  // Send a request to gti.pl to get the first string to translate
+  text_t gti_arguments = "get-first-n-chunks-requiring-work " + target_language_code + " " + translation_file_key + " " + num_chunks_per_page;
+  GTI_Response gti_response = parse_gti_response(do_gti_request(gti_arguments, logout), logout);
+  if (gti_response.error_message != "") {
+    // An error has occurred
+    disp.setmacro("gtiformcontent", "gti", "_gti:gtierror_");
+    disp.setmacro("gtierrormessage", "gti", gti_response.error_message);
+    return;
+  }
+
+  languageinfo_tmap loaded_languages = recpt->get_configinfo().languages;
+  disp.setmacro("gtitargetlanguagename", "gti", loaded_languages[target_language_code].longname);
+  disp.setmacro("gtitargetfilepath", "gti", gti_response.translation_files_key_to_target_file_path_mapping[translation_file_key]);
+  disp.setmacro("gtitranslationfiledesc", "gti", "_gti:textgti" + translation_file_key + "_");
+  disp.setmacro("gtiviewtranslationfileinaction", "gti", "_gti:gtiview" + translation_file_key + "inaction_");
+
+  disp.setmacro("gtinumchunkstranslated", "gti", gti_response.translation_files_key_to_num_chunks_translated_mapping[translation_file_key]);
+  disp.setmacro("gtinumchunksrequiringtranslation", "gti", gti_response.translation_files_key_to_num_chunks_requiring_translation_mapping[translation_file_key]);
+  disp.setmacro("gtinumchunksrequiringupdating", "gti", gti_response.translation_files_key_to_num_chunks_requiring_updating_mapping[translation_file_key]);
+
+  // Check if the translation file is finished
+  if (gti_response.translation_files_key_to_num_chunks_requiring_translation_mapping[translation_file_key] == "0" && gti_response.translation_files_key_to_num_chunks_requiring_updating_mapping[translation_file_key] == "0") {
+    disp.setmacro("gtiformcontent", "gti", "_gti:gtidone_");
+    return;
+  }
+
+  // Loop through the chunks returned, displaying them on the page
+  text_t gti_core_form_content = "";
+  text_tmap::iterator chunk_key_iterator = gti_response.source_file_chunks_key_to_text_mapping.begin();
+  while (chunk_key_iterator != gti_response.source_file_chunks_key_to_text_mapping.end()) {
+    text_t chunk_key = chunk_key_iterator->first;
+
+    // Need to escape any underscores in the chunk key to show it correctly on the page
+    text_t chunk_key_escaped = escape_all(chunk_key, '_');
+
+    // Need to escape any backslashes, underscores, commas, parentheses, and single quotes in the chunk text
+    text_t source_file_chunk_text = gti_response.source_file_chunks_key_to_text_mapping[chunk_key];
+    text_t source_file_chunk_text_escaped = escape_all(source_file_chunk_text, '\\');
+    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, '_');
+    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, ',');
+    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, '(');
+    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, ')');
+    source_file_chunk_text_escaped = escape_all(source_file_chunk_text_escaped, '\'');
+    text_t target_file_chunk_text = gti_response.target_file_chunks_key_to_text_mapping[chunk_key];
+    text_t target_file_chunk_text_escaped = escape_all(target_file_chunk_text, '\\');
+    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '_');
+    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, ',');
+    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '(');
+    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, ')');
+    target_file_chunk_text_escaped = escape_all(target_file_chunk_text_escaped, '\'');
+
+    text_t source_file_chunk_date = gti_response.source_file_chunks_key_to_date_mapping[chunk_key];
+    text_t target_file_chunk_date = gti_response.target_file_chunks_key_to_date_mapping[chunk_key];
+
+    // This chunk requires translation
+    if (target_file_chunk_text == "") {
+      gti_core_form_content += "_gtichunkrequiringtranslation_(" + chunk_key_escaped + "," + source_file_chunk_text_escaped + "," + source_file_chunk_date + ")\n";
+    }
+    // This chunk requires updating
+    else {
+      gti_core_form_content += "_gtichunkrequiringupdating_(" + chunk_key_escaped + "," + source_file_chunk_text_escaped + "," + source_file_chunk_date + "," + target_file_chunk_text_escaped + "," + target_file_chunk_date + ")\n";
+    }
+
+    chunk_key_iterator++;
+  }
+
+  disp.setmacro("gticoreformcontent", "gti", gti_core_form_content);
+}
+
+
+
+void gtiaction::process_gti_submissions(displayclass& disp, cgiargsclass& args, ostream& logout, bool force_submission)
+{
+  // Get the target language code and file to translate from the CGI arguments
+  text_t target_language_code = args["tlc"];
+  text_t translation_file_key = args["tfk"];
+
+  // Submitted chunk arguments contain the language code followed by "::"
+  char* source_chunk_key_start_cstr = ((text_t) "en" + "%3A%3A").getcstr();
+  char* target_chunk_key_start_cstr = (target_language_code + "%3A%3A").getcstr();
+
+  // Find the cgi arguments with submitted chunk information
+  text_t submission_text;
+  cgiargsclass::const_iterator cgi_argument = args.begin();
+  while (cgi_argument != args.end()) {
+    char* cgi_argument_name_cstr = cgi_argument->first.getcstr();
+
+    // Source file text
+    if (strncmp(cgi_argument_name_cstr, source_chunk_key_start_cstr, strlen(source_chunk_key_start_cstr)) == 0) {
+      submission_text += "<SourceFileText key=\"";
+      submission_text += &cgi_argument_name_cstr[strlen(source_chunk_key_start_cstr)];
+      submission_text += "\">\n";
+      submission_text += to_utf8(args[cgi_argument->first]) + "\n";
+      submission_text += "</SourceFileText>\n";
+    }
+    // Target file text
+    if (strncmp(cgi_argument_name_cstr, target_chunk_key_start_cstr, strlen(target_chunk_key_start_cstr)) == 0) {
+      submission_text += "<TargetFileText key=\"";
+      submission_text += &cgi_argument_name_cstr[strlen(target_chunk_key_start_cstr)];
+      submission_text += "\">\n";
+      submission_text += to_utf8(args[cgi_argument->first]) + "\n";
+      submission_text += "</TargetFileText>\n";
+    }
+
+    delete[] cgi_argument_name_cstr;
+    ++cgi_argument;
+  }
+
+  logout << "Submission text: " << submission_text << endl;
+
+  // Send the submission to gti.pl
+  text_t gti_arguments = "submit-translations " + target_language_code + " " + translation_file_key;
+  if (force_submission) {
+    gti_arguments += " -force_submission";
+  }
+  do_gti_submission(gti_arguments, submission_text, logout);
+  logout << "Done." << endl;
+
+  delete[] source_chunk_key_start_cstr;
+  delete[] target_chunk_key_start_cstr;
+}
+
+
+
+text_t gtiaction::escape_all(text_t text_string, char character_to_escape)
+{
+  text_t text_string_escaped = "";
+
+  text_t::iterator text_string_character = text_string.begin();
+  while (text_string_character != text_string.end()) {
+    if (*text_string_character == character_to_escape) {
+      text_string_escaped += "\\";
+    }
+    text_string_escaped.push_back(*text_string_character);
+    text_string_character++;
+  }
+
+  return text_string_escaped;
+}
+
+
+
+char* xml_get_attribute(const char** attributes, char* attribute_name)
+{
+  for (int i = 0; (attributes[i] != NULL); i += 2) {
+    if (strcmp(attribute_name, attributes[i]) == 0) {
+      return strdup(attributes[i+1]);
+    }
+  }
+
+  return NULL;
+}
+
+
+static void XMLCALL gti_response_xml_start_element(void* user_data, const char* element_name_cstr, const char** attributes)
+{
+  GTI_Response* gti_response = (GTI_Response*) user_data;
+  text_t element_name = element_name_cstr;
+  cerr << "In startElement() for " << element_name << endl;
+
+  if (element_name == "GTIError") {
+    gti_response->recorded_text = "";
+    gti_response->is_recording_text = true;
+  }
+
+  if (element_name == "TranslationFile") {
+    int translation_file_index = gti_response->translation_files_index_to_key_mapping.size();
+    gti_response->translation_file_key = xml_get_attribute(attributes, "key");
+    gti_response->translation_files_index_to_key_mapping[translation_file_index] = gti_response->translation_file_key;
+    gti_response->translation_files_key_to_target_file_path_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "target_file_path");
+    gti_response->translation_files_key_to_num_chunks_translated_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "num_chunks_translated");
+    gti_response->translation_files_key_to_num_chunks_requiring_translation_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "num_chunks_requiring_translation");
+    gti_response->translation_files_key_to_num_chunks_requiring_updating_mapping[gti_response->translation_file_key] = xml_get_attribute(attributes, "num_chunks_requiring_updating");
+  }
+
+  if (element_name == "ChunksMatchingQuery") {
+    gti_response->num_chunks_matching_query = xml_get_attribute(attributes, "size");
+  }
+
+  if (element_name == "Chunk") {
+    gti_response->chunk_key = xml_get_attribute(attributes, "key");
+  }
+
+  if (element_name == "SourceFileText") {
+    gti_response->source_file_chunks_key_to_date_mapping[gti_response->chunk_key] = xml_get_attribute(attributes, "date");
+    gti_response->recorded_text = "";
+    gti_response->is_recording_text = true;
+  }
+
+  if (element_name == "TargetFileText") {
+    if (xml_get_attribute(attributes, "date") != NULL) {
+      gti_response->target_file_chunks_key_to_date_mapping[gti_response->chunk_key] = xml_get_attribute(attributes, "date");
+    }
+    gti_response->recorded_text = "";
+    gti_response->is_recording_text = true;
+  }
+}
+
+
+static void XMLCALL gti_response_xml_end_element(void* user_data, const char* element_name_cstr)
+{
+  GTI_Response* gti_response = (GTI_Response*) user_data;
+  text_t element_name = element_name_cstr;
+
+  if (element_name == "GTIError") {
+    gti_response->error_message = to_uni(gti_response->recorded_text);
+    gti_response->is_recording_text = false;
+  }
+
+  if (element_name == "SourceFileText") {
+    gti_response->source_file_chunks_key_to_text_mapping[gti_response->chunk_key] = to_uni(gti_response->recorded_text);
+    gti_response->is_recording_text = false;
+  }
+
+  if (element_name == "TargetFileText") {
+    gti_response->target_file_chunks_key_to_text_mapping[gti_response->chunk_key] = to_uni(gti_response->recorded_text);
+    gti_response->is_recording_text = false;
+  }
+}
+
+
+static void XMLCALL gti_response_xml_character_data(void *user_data, const char* text_cstr, int text_length)
+{
+  GTI_Response* gti_response = (GTI_Response*) user_data;
+  if (gti_response->is_recording_text) {
+    gti_response->recorded_text.appendcarr(text_cstr, text_length);
+  }
+}
+
+
+
+text_t gtiaction::do_gti_request(text_t gti_arguments, ostream& logout)
+{
+  // Send the request to gti.pl and read the XML output
+  text_t gti_command = "perl -S " + filename_cat(gsdlhome, "bin", "script", "gti.pl") + " " + gti_arguments;
+  char* gti_command_cstr = gti_command.getcstr();
+  FILE *gti_pipe = popen(gti_command_cstr, "r");
+  delete[] gti_command_cstr;
+  if (gti_pipe == NULL) {
+    logout << "Error: Could not open pipe for GTI command " << gti_command << endl;
+    return "";
+  }
+
+  // Read the gti.pl response
+  text_t gti_response_xml_text;
+  while (!feof(gti_pipe)) {
+    char buffer[1024];
+    gti_response_xml_text.appendcarr(buffer, fread(buffer, 1, 1024, gti_pipe));
+  }
+  pclose(gti_pipe);
+
+  return gti_response_xml_text;
+}
+
+
+
+GTI_Response gtiaction::parse_gti_response(text_t gti_response_xml_text, ostream& logout)
+{
+  GTI_Response gti_response;
+  gti_response.is_recording_text = false;
+
+  // Parse the gti.pl response (XML)
+  logout << "Parsing GTI command response: " << gti_response_xml_text << endl;
+  XML_Parser xml_parser = XML_ParserCreate(NULL);
+  XML_SetUserData(xml_parser, &gti_response);
+  XML_SetElementHandler(xml_parser, gti_response_xml_start_element, gti_response_xml_end_element);
+  XML_SetCharacterDataHandler(xml_parser, gti_response_xml_character_data);
+
+  char* gti_response_xml_text_cstr = gti_response_xml_text.getcstr();
+  int parse_status = XML_Parse(xml_parser, gti_response_xml_text_cstr, strlen(gti_response_xml_text_cstr), XML_TRUE);
+  delete[] gti_response_xml_text_cstr;
+  if (parse_status == XML_STATUS_ERROR) {
+    logout << "Parse error " << XML_ErrorString(XML_GetErrorCode(xml_parser)) << " at line " << XML_GetCurrentLineNumber(xml_parser) << endl;
+    return gti_response;
+  }
+
+  XML_ParserFree(xml_parser);
+
+  logout << "Finished parse." << endl;
+  return gti_response;
+}
+
+
+
+void gtiaction::do_gti_submission(text_t gti_arguments, text_t gti_submission, ostream& logout)
+{
+  // Send the submission to gti.pl
+  text_t gti_command = "perl -S " + filename_cat(gsdlhome, "bin", "script", "gti.pl") + " " + gti_arguments;
+  char* gti_command_cstr = gti_command.getcstr();
+  FILE *gti_pipe = popen(gti_command_cstr, "w");
+  delete[] gti_command_cstr;
+  if (gti_pipe == NULL) {
+    logout << "Error: Could not open pipe for GTI command " << gti_command << endl;
+    return;
+  }
+
+  // Write the gti.pl submission
+  char* gti_submission_cstr = gti_submission.getcstr();
+  fwrite(gti_submission_cstr, 1, strlen(gti_submission_cstr), gti_pipe);
+  delete[] gti_submission_cstr;
+
+  pclose(gti_pipe);
+}
+
+
+
+#endif  // GSDL_USE_GTI_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/gtiaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/gtiaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/gtiaction.h	(revision 10506)
@@ -0,0 +1,117 @@
+/**********************************************************************
+ *
+ * gtiaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef GTIACTION_H
+#define GTIACTION_H
+
+
+#include "action.h"
+#include "receptionist.h"
+
+
+
+struct GTI_Response
+{
+  text_t translation_file_key;
+  text_tmap translation_files_index_to_key_mapping;
+  text_tmap translation_files_key_to_num_chunks_translated_mapping;
+  text_tmap translation_files_key_to_num_chunks_requiring_translation_mapping;
+  text_tmap translation_files_key_to_num_chunks_requiring_updating_mapping;
+  text_tmap translation_files_key_to_target_file_path_mapping;
+
+  text_t chunk_key;
+  text_tmap source_file_chunks_key_to_text_mapping;
+  text_tmap source_file_chunks_key_to_date_mapping;
+
+  // For chunks requiring updating
+  text_tmap target_file_chunks_key_to_text_mapping;
+  text_tmap target_file_chunks_key_to_date_mapping;
+
+  text_t num_chunks_matching_query;
+
+  bool is_recording_text;
+  text_t recorded_text;
+
+  text_t error_message;
+};
+
+
+class gtiaction : public action {
+
+protected:
+  receptionist *recpt;
+
+  char* set_gsdlhome_cstr;
+  char* set_gsdlos_cstr;
+
+public:
+  gtiaction ();
+  virtual ~gtiaction ();
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  text_t get_action_name () {return "gti";}
+
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      recptprotolistclass *protos, ostream &logout);
+
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response,text_t &response_data, 
+			 ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+  bool init (ostream & /*logout*/);
+
+
+  // The interesting functions
+  void define_gti_home_page(displayclass& disp, cgiargsclass& args, ostream& logout);
+
+  void define_gti_lang_page(displayclass& disp, cgiargsclass& args, ostream& logout);
+
+  void define_gti_find_page(displayclass& disp, cgiargsclass& args, ostream& logout);
+
+  void define_gti_core_page(displayclass& disp, cgiargsclass& args, ostream& logout);
+
+  text_t escape_all(text_t source_string, char character_to_escape);
+
+  void process_gti_submissions(displayclass& disp, cgiargsclass& args, ostream& logout, bool force_submission);
+
+  text_t do_gti_request(text_t gti_arguments, ostream& logout);
+
+  GTI_Response parse_gti_response(text_t gti_response_xml_text, ostream& logout);
+
+  void do_gti_submission(text_t gti_arguments, text_t gti_submission, ostream& logout);
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/highlighttext.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/highlighttext.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/highlighttext.cpp	(revision 10506)
@@ -0,0 +1,284 @@
+/**********************************************************************
+ *
+ * highlighttext.cpp -- 
+ * Copyright (C) 2002   D L Consulting Ltd
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "highlighttext.h"
+#include "unitool.h"
+
+
+static void highlight_terms(const text_t &text, const TermInfo_tarray &terms, const text_t &shl,
+			    const text_t &ehl, displayclass &disp, outconvertclass &outconvert,
+			    ostream &textout);
+
+static void highlight_phrases(const text_t &text, const text_t &querystring, const TermInfo_tarray &terms, 
+			      const text_t &shl, const text_t &ehl, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout);
+
+static void get_phrase_terms (const text_t &querystring, text_tarray &phrase_terms);
+
+static void remove_space (text_t &qstring);
+
+// highlights text string by adding _starthighlight_ and _endhightlight_
+// around terms and/or phrases that match querystring 
+
+// - at present this only handles phrase searches where the first and last
+// characters are double quotes (i.e. it won't correctly handle a mixture
+// of phrase and non-phrase terms or queries containing multiple phrases) -
+// it also doesn't highlight stemmed variations of terms within a phrase
+// because the terminfo returned by mgqueryfilter doesn't currently tell
+// you which term variants belong to which term
+
+// - this function can be forced to treat the querystring like a phrase
+// even if it isn't one by setting the "hl" cgi argument to "2"
+void highlighttext(const text_t &text, cgiargsclass &args, const TermInfo_tarray &terms, 
+		   displayclass &disp, outconvertclass &outconvert, ostream &textout) {
+
+
+  text_t &querystring = args["q"];
+
+  // get the text to start and end a hightlight
+  text_t shl = "<b><u>";
+  text_t ehl = "</u></b>";
+  if (disp.isdefaultmacro(displayclass::defaultpackage, "starthighlight")) {
+    disp.expandstring(displayclass::defaultpackage, "_starthighlight_", shl);
+  }
+  if (disp.isdefaultmacro(displayclass::defaultpackage, "endhighlight")) {
+    disp.expandstring(displayclass::defaultpackage, "_endhighlight_", ehl);
+  }
+
+  // remove leading and trailing whitespace
+  remove_space(querystring);
+
+  if ((args["hl"] == 2) || ((*(querystring.begin()) == '"') && (*(querystring.end()-1) == '"'))) {
+    highlight_phrases(text, querystring, terms, shl, ehl, disp, outconvert, textout);
+  } else {
+    highlight_terms(text, terms, shl, ehl, disp, outconvert, textout);
+  }
+}
+
+void highlight_terms(const text_t &text, const TermInfo_tarray &terms, const text_t &shl,
+		     const text_t &ehl, displayclass &disp, outconvertclass &outconvert,
+		     ostream &textout) {
+
+  text_tmap allterms;
+  text_tmap::const_iterator it;
+
+  // first load all the term variations into a map
+  TermInfo_tarray::const_iterator this_term = terms.begin();
+  TermInfo_tarray::const_iterator last_term = terms.end();
+  while (this_term != last_term) {
+    text_tarray::const_iterator this_var = (*this_term).matchTerms.begin();
+    text_tarray::const_iterator last_var = (*this_term).matchTerms.end();
+    while (this_var != last_var) {
+      allterms[*this_var] = 1;
+      ++this_var;
+    }
+    ++this_term;
+  }
+
+  text_t::const_iterator here = text.begin();
+  text_t::const_iterator end = text.end();
+
+  text_t word, buffer;
+  while (here != end) {
+    if (is_unicode_letdig(*here)) {
+      // not word boundary
+      word.push_back(*here);
+      ++here;
+
+    } else {
+      // found word boundary
+      // add last word if there was one
+      if (!word.empty()) {
+	it = allterms.find(word);
+	if (it != allterms.end()) {
+	  word = shl + word + ehl;
+	}
+	buffer += word;
+        word.clear();
+      }
+
+      if (*here == '<') {
+        // skip over rest of html tag
+	while ((here != end) && (*here != '>')) {
+	  buffer.push_back(*here);
+	  ++here;
+	}
+      }
+
+      buffer.push_back(*here);
+      ++here;
+
+      if (buffer.size() > 1024) {
+	textout << outconvert << disp << buffer;
+	buffer.clear();
+      }
+    }
+  }
+  textout << outconvert << disp << buffer;
+}
+
+void highlight_phrases(const text_t &text, const text_t &querystring, const TermInfo_tarray &terms, 
+		       const text_t &shl, const text_t &ehl, displayclass &disp, 
+		       outconvertclass &outconvert, ostream &textout) {
+
+  text_tmap allterms;
+  text_tarray phrase_terms;
+  text_tmap::const_iterator it;
+
+  get_phrase_terms(querystring, phrase_terms);
+  int phraselen = phrase_terms.size();
+
+  TermInfo_tarray::const_iterator this_term = terms.begin();
+  TermInfo_tarray::const_iterator last_term = terms.end();
+  bool first = true;
+  while (this_term != last_term) {
+    text_tarray::const_iterator this_var = (*this_term).matchTerms.begin();
+    text_tarray::const_iterator last_var = (*this_term).matchTerms.end();
+    while (this_var != last_var) {
+      allterms[*this_var] = 1;
+      ++this_var;
+    }
+    first = false;
+    ++this_term;
+  }
+
+  text_t::const_iterator here = text.begin();
+  text_t::const_iterator end = text.end();
+
+  text_t word, buffer;
+  int phrasecount = 0;
+  while (here != end) {
+    if (is_unicode_letdig(*here)) {
+      // not word boundary
+      word.push_back(*here);
+      ++here;
+
+    } else {
+      // found word boundary
+      // add last word if there was one
+      if (!word.empty()) {
+	it = allterms.find(word);
+	if (it != allterms.end()) {
+	  // found a word that matches somewhere in the phrase
+
+	  text_t lcword = word; lc(lcword);
+	  if (lcword == phrase_terms[phrasecount]) {
+
+	    if (phrasecount == 0) {
+	      // clear the buffer (from here on buffer will contain the phrase
+	      // as it's built up)
+	      textout << outconvert << disp << buffer;
+	      buffer.clear();
+	    }
+	    ++phrasecount;
+	  } else {
+	    phrasecount = 0;
+	  }
+	} else {
+	  phrasecount = 0;
+	}
+	buffer += word;
+        word.clear();
+	
+	if (phrasecount == phraselen) {
+	  // have found entire phrase
+	  textout << outconvert << disp << shl << buffer << ehl;
+	  buffer.clear();
+	  phrasecount = 0;
+	}
+      }
+
+      if (*here == '<') {
+        // skip over rest of html tag
+	while ((here != end) && (*here != '>')) {
+	  buffer.push_back(*here);
+	  ++here;
+	}
+      }
+
+      buffer.push_back(*here);
+      ++here;
+
+      if (buffer.size() > 1024 && phrasecount == 0) {
+	textout << outconvert << disp << buffer;
+	buffer.clear();
+      }
+    }
+  }
+  textout << outconvert << disp << buffer;
+}
+
+void get_phrase_terms (const text_t &querystring, text_tarray &phrase_terms) {
+
+  phrase_terms.erase(phrase_terms.begin(), phrase_terms.end());
+
+  text_t::const_iterator here = querystring.begin();
+  text_t::const_iterator end = querystring.end();
+
+  text_t word;
+  while (here != end) {
+    if (is_unicode_letdig(*here)) {
+      // not word boundary
+      word.push_back(*here);
+
+    } else {
+      // found word boundary
+      if (!word.empty()) {
+	lc(word);
+	phrase_terms.push_back(word);
+	word.clear();
+      }
+    }
+    ++here;
+  }
+
+  if (!word.empty()) {
+    lc(word);
+    phrase_terms.push_back(word);
+  }
+}
+
+void remove_space (text_t &qstring) {
+
+  text_t altered_string;
+  text_t space;
+
+  text_t::const_iterator here = qstring.begin();
+  text_t::const_iterator end = qstring.end();
+  while (here != end) {
+    if (is_unicode_space(*here)) {
+      space.push_back(*here);
+    } else {
+      if (!altered_string.empty()) {
+	altered_string += space;
+      }
+      space.clear();
+      altered_string.push_back(*here);
+    }
+    ++here;
+  }
+
+  qstring = altered_string;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/highlighttext.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/highlighttext.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/highlighttext.h	(revision 10506)
@@ -0,0 +1,46 @@
+/**********************************************************************
+ *
+ * highlighttext.h -- 
+ * Copyright (C) 2002   D L Consulting Ltd
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef HIGHLIGHTTEXT_H
+#define HIGHLIGHTTEXT_H
+
+#include "text_t.h"
+#include "comtypes.h"
+#include "display.h"
+#include "cgiargs.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+void highlighttext(const text_t &text, cgiargsclass &args, const TermInfo_tarray &terms, 
+		   displayclass &disp, outconvertclass &outconvert, ostream &textout);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/historydb.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/historydb.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/historydb.cpp	(revision 10506)
@@ -0,0 +1,305 @@
+/**********************************************************************
+ *
+ * historydb.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "historydb.h"
+#include "fileutil.h"
+#include "cgiutils.h"
+#include "recptproto.h"
+#include "OIDtools.h"
+
+#define MAX_RECORDS 20
+
+// returns true on success (in which case historyinfo will contain
+// the information for this history)
+bool get_history_info (const text_t &userid, text_tarray &historyinfo, 
+		       const text_t &gsdlhome, ostream &logout) {
+
+  text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
+  
+  bool result = false;
+  // open the history database  
+  gdbmclass historydb;
+  
+  if (historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) {
+    // get history list
+    text_t historyresult;
+    
+    historydb.getkeydata(userid, historyresult);
+    
+    if (historyresult != "") { //  there are entries, process them
+      
+      splitchar(historyresult.begin(), historyresult.end(), '\n', historyinfo);
+      result = true;
+    }
+    historydb.closedatabase();
+    
+  } else {
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii << "couldn't open history database " << historyfile << "\n";
+  }
+  return result;
+}
+
+
+// returns true on success
+// changed to only save 20 records per user, numbers not included
+// only save if there are already entries there, or if display=true
+bool set_history_info (const text_t &userid, const text_t &history, const text_t &gsdlhome, bool display) {
+
+  text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
+  
+  bool result = false;
+  // open the history database  
+  gdbmclass historydb;
+  
+  text_t oldhistoryresult;
+  text_t newhistoryresult;
+  int numentries=0;
+
+  if ( !historydb.opendatabase(historyfile, GDBM_READER, 1000, true)) {
+    // not created yet
+    oldhistoryresult="";
+    if (!display) return true; // dont need to save
+  }
+  else {
+
+    // get history list
+   if (! historydb.getkeydata(userid, oldhistoryresult)) {
+     oldhistoryresult="";
+     if (!display) return true; // dont need to save
+   }
+   historydb.closedatabase();
+  }
+
+  text_tarray entries;
+  
+  if (oldhistoryresult!="") {
+    splitchar(oldhistoryresult.begin(), oldhistoryresult.end(), '\n', entries);
+    numentries = entries.size();
+    if (numentries >= MAX_RECORDS) numentries = MAX_RECORDS-1;
+  }
+  
+  // open for writing
+  if (!historydb.opendatabase(historyfile, GDBM_WRCREAT, 1000, true)) return false;
+  
+  // add on new linethe new record to the front of the list, then add the
+  // appropriate entries from the old stuff 
+  newhistoryresult += history;
+  newhistoryresult += "\n";
+  for (int i=0; i<numentries;++i) {
+    newhistoryresult +=  entries[i]+"\n";
+  }
+  
+  if (historydb.setinfo(userid, newhistoryresult)) 
+    result=true; 
+  
+  historydb.closedatabase();
+  return result;
+}
+
+// deletes all a users history
+bool delete_all_history_info (const text_t &userid, const text_t &gsdlhome) {
+
+  text_t historyfile = filename_cat(gsdlhome, "etc", "history.db");
+  
+  // open the history database  
+  gdbmclass historydb;
+  
+  if ( !historydb.opendatabase(historyfile, GDBM_WRITER, 1000, true)) return false;
+
+  historydb.deletekey(userid);
+  historydb.closedatabase();
+  return true;
+  
+}
+
+// retrieves the value of one of the arguments
+void parse_saved_args(text_t &args, text_t key, text_t &value)
+{
+  text_t::iterator here = args.begin();
+  text_t::iterator end = args.end();
+  text_t::iterator it;
+  while (here != end) {
+    if(*here==key[0]) {
+      it=findchar(here, end, '=');
+      if (it==end) {
+	value=""; return;
+      }
+      text_t entry = substr(here, it);
+      if (entry==key) {
+	here=it+1;
+      	it=findchar(here, end, '&');
+	value = substr(here, it);
+	return;
+      }
+    }
+    ++here;
+  }// while
+}
+
+// retrieves the value of all of the arguments
+void parse_saved_args(text_t &args, infodbclass &info)
+{
+  text_t::iterator here = args.begin();
+  text_t::iterator end = args.end();
+  text_t::iterator it;
+  text_tarray values;
+
+  splitchar(here, end, '&', values);
+  
+  text_tarray::iterator start = values.begin();
+  text_tarray::iterator stop = values.end();
+
+  text_t key;
+  text_t value;
+  while(start!=stop) {
+
+    here=(*start).begin();
+    end=(*start).end();
+    it=findchar(here, end, '=');
+    if (it!=end) {
+      key = substr(here, it);
+      value = substr(it+1, end);
+      
+      info[key]=value;
+    }
+    ++start;
+  }
+}
+
+
+void split_saved_query(text_t &query, text_t &numdocs, text_t &cgiargs)
+{
+  text_t::iterator begin = query.begin();
+  text_t::iterator end = query.end();
+  
+  while (*begin >='0'&& *begin <='9') { // get the digits for numdocs
+    numdocs.push_back(*begin);
+    ++begin;
+  }          
+                 
+  if (*begin == '+') {  // get the + if there
+    numdocs.push_back(*begin);
+    ++begin;
+  }
+  if (*begin == ':') { // have the old format - previous bit was record number
+    numdocs.clear();
+    ++begin;
+
+    while(*begin >='0' && *begin <='9') { // get the digits
+      numdocs.push_back(*begin);
+      ++begin;
+    }
+    if (*begin == '+') { // get the + if there
+      numdocs.push_back(*begin);
+      ++begin;
+    }
+  }
+  cgiargs += (substr(begin, end));  // put rest of query into cgiargs
+
+}
+
+void format_user_info (text_t &historyargs, text_t &userinfo,  
+		       cgiargsclass &args,
+		       recptprotolistclass *protos, ostream &logout) 
+{
+  text_tset metadata;
+  userinfo.clear();
+
+  infodbclass argsinfo;
+  parse_saved_args(historyargs, argsinfo);
+  
+  text_t collect = argsinfo["c"];
+  if (collect=="") {
+    userinfo="";
+    return;
+  }
+
+  if (collect != args["c"]) {
+    userinfo += collect+", ";
+  }
+  
+  if (argsinfo["h"] != args["h"]) {
+  
+    recptproto *collectproto = protos->getrecptproto(collect,logout);
+    if (collectproto == NULL) {
+      userinfo="";
+      return;
+    }
+    metadata.insert(argsinfo["h"]);
+    FilterResponse_t response;
+    
+    get_info("collection", collect, args["l"], metadata, false, collectproto, response, logout);
+    text_t index = response.docInfo[0].metadata[argsinfo["h"]].values[0];
+    if (!index.empty()) {
+      userinfo += index+", ";
+    }
+  }
+
+  if (argsinfo["b"] != args["b"] || argsinfo["t"] != args["t"]) {
+    text_t mode;
+    if (argsinfo["b"]=="0") { // simple mode
+      if (argsinfo["t"]=="0") {
+	mode = " _texthallwords_";
+      }
+      else { // t=1
+	mode = " _texthsomewords_";
+      }
+      
+    } 
+    else { // advanced mode
+      if (argsinfo["t"]=="0") {
+	mode = " _texthboolean_";
+      }
+      else {
+	mode = " _texthranked_";
+      }
+    }
+    userinfo += mode+", ";
+  }
+  
+  if (argsinfo["k"] != args["k"]) {
+    text_t options;
+    if (argsinfo["k"]=="0") {
+      options = " _texthcaseoff_";
+    }
+    else {
+      options = " _texthcaseon_";
+    }
+    userinfo += options+", ";
+  }
+
+  if (argsinfo["s"] != args["s"]) {
+    text_t stem;
+    if (argsinfo["s"]=="0") {
+      stem = " _texthstemoff_";
+    }
+    else {
+      stem = " _texthstemon_";
+    }
+    userinfo += stem+", ";
+  }
+
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/historydb.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/historydb.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/historydb.h	(revision 10506)
@@ -0,0 +1,78 @@
+/**********************************************************************
+ *
+ * historydb.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef HISTORYDB_H
+#define HISTORYDB_H
+
+#include "infodbclass.h"
+#include "text_t.h"
+#include "recptproto.h"
+#include "cgiargs.h"
+
+/*
+struct HistRecord {
+  text_t entry;
+  bool save;
+};
+
+struct ltinttext_t
+{
+  bool operator()(const text_t &t1, const text_t &t2) const
+  { return t1.getint() < t2.getint(); }
+};
+
+
+typedef map<text_t, HistRecord, ltinttext_t> HistRecordmap;
+
+*/
+// returns true on success (in which case historyinfo will contain
+// the information for this history)
+bool get_history_info (const text_t &userid, text_tarray &historyinfo, 
+		       const text_t &gsdlhome, ostream &logout);
+
+// returns true on success
+bool set_history_info (const text_t &userid, const text_t &historyinfo, 
+		       const text_t &gsdlhome, bool display);
+
+// delete all history for one user
+bool delete_all_history_info (const text_t &userid, const text_t &gsdlhome);
+
+// retrieves the value of an arg (key) from a list of cgi args
+// in the form a=q&b=1&...
+void parse_saved_args(text_t &args, text_t key, text_t &value);
+
+// extracts out the components of an entry in the database
+// currently:
+// numdocs cgiargs
+void split_saved_query(text_t &query,  text_t &numdocs, text_t &cgiargs);
+
+// takes the cgiarg string, and outputs it in some form useful
+// to the user
+void format_user_info (text_t &cgiargs, text_t &info, 
+		       cgiargsclass &args,
+		       recptprotolistclass *protos, ostream &logout);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/hlistbrowserclass.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/hlistbrowserclass.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/hlistbrowserclass.cpp	(revision 10506)
@@ -0,0 +1,198 @@
+/**********************************************************************
+ *
+ * hlistbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "hlistbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+hlistbrowserclass::hlistbrowserclass () {
+}
+
+hlistbrowserclass::~hlistbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t hlistbrowserclass::get_browser_name () {
+  return "HList";
+}
+
+browserclass* hlistbrowserclass::clone()
+{
+  return new hlistbrowserclass();
+}
+
+void hlistbrowserclass::load_metadata_defaults (text_tset &metadata) {
+  metadata.insert ("doctype");
+}
+
+text_t hlistbrowserclass::get_default_formatstring () {
+  return "[link][highlight][Title][/highlight][/link]";
+}
+
+// need to change OID to it's child 
+void hlistbrowserclass::processOID (cgiargsclass &args, recptproto *collectproto,
+				    ostream &logout) {
+
+  text_t OID = args["d"];
+  bool is_classify = false;
+  if (OID.empty()) {
+    is_classify = true;
+    OID = args["cl"];
+  }
+
+  FilterResponse_t response;
+  text_tset metadata;
+  metadata.insert ("childtype");
+  text_t classifytype = "Invisible";
+  text_tarray OIDs;
+
+  while (classifytype == "Invisible" || classifytype == "HList") {
+    OIDs.erase (OIDs.begin(), OIDs.end());
+    
+    OIDs.push_back (OID);
+    OIDs.push_back (OID + ".fc");
+
+    get_info (OIDs, args["c"], args["l"], metadata, false, collectproto, response, logout);
+
+    OID = response.docInfo[1].OID;
+    classifytype = response.docInfo[1].metadata["childtype"].values[0];
+  }
+  if (is_classify) args["cl"] = OID;
+  else args["d"] = OID;
+}
+
+int hlistbrowserclass::output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+					     const text_t& collection, int colnumber, 
+					     format_t *formatlistptr, bool use_table, 
+					     text_tset &metadata, bool &getParents, 
+					     recptproto *collectproto, displayclass &disp, 
+					     outconvertclass &outconvert, ostream &textout, 
+					     ostream &logout) {
+
+  // expanded contents are going to cause some nasty recursions
+  // so we'll only continue if being passed the current section
+  if ((args["gc"] == 1) && (section.OID != args["d"])) return 0;
+
+  // get all siblings
+  FilterResponse_t response;
+  text_t &arg_cl = args["cl"];
+  get_children (section.OID + ".pr", args["c"], args["l"], metadata, getParents, 
+		collectproto, response, logout);
+
+					
+  if (use_table || colnumber > 0) {
+    textout << outconvert << "<table><tr><td>";
+    // get tab size
+    text_t tab; int itab;
+    disp.expandstring (displayclass::defaultpackage, "_tabwidth_", tab);
+    itab = tab.getint();
+    if (colnumber > 0) textout << outconvert << disp 
+			       << "<img src=\"_httpimg_/space.gif\" width=" 
+			       << (itab*colnumber) << ">";
+    textout << outconvert << "</td>\n";
+  }
+
+  textout << outconvert << "<table><tr>\n";
+
+  ResultDocInfo_tarray::iterator tsibling = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator esibling = response.docInfo.end();
+
+  text_t icon, link;
+  int num_chars=0; // see note below - jrm21
+  while (tsibling != esibling) {
+
+    bool highlight = false;
+    text_t &doctype = (*tsibling).metadata["doctype"].values[0];
+
+    if ((*tsibling).OID == section.OID) {
+      link.clear();
+      highlight = true;
+    } else {
+      link = "<a href=\"_httpdocument_";
+      if (doctype == "classify") 
+	link += "&cl=" + (*tsibling).OID + "\">";
+      else {
+	link += "&cl=" + arg_cl + "&d=" + (*tsibling).OID;// + "\">";
+	// [modification to allow default document detach settings -- kjdon]
+	if (args["xx"]=="1") {
+	  // documents should be detached
+	  link += "&x=1\" target=\\_blank>";
+	} else {
+	  link += "\">";
+	}
+      }
+    }
+
+    text_tmap options;
+    options["link"] = link;
+    options["icon"] = icon;
+    if (highlight) options["highlight"] = "1";
+    else options["highlight"] = "0";
+    
+    text_t fmt_str=get_formatted_string (collection, collectproto,
+					  *tsibling, disp, formatlistptr,
+					  options, logout);
+
+    /* this is awful. Someone please come up with a better way to prevent
+       the table of contents when browsing metadata from becoming too wide.
+       This is an attempt to add new rows when the number of characters in
+       the current row becomes too high. It doesn't know about macros in the
+       string, though... -- jrm21 */
+
+    char *tmp_str=fmt_str.getcstr();
+    char *end_str=tmp_str+strlen(tmp_str);
+    while (tmp_str<end_str) {
+      if (*tmp_str=='<') {    // for html tags
+	while (*tmp_str!='>') ++tmp_str; 
+      } else if (*tmp_str=='&') { // for html entities
+	while (*tmp_str!=';') ++tmp_str; 
+	++num_chars;
+      } else ++num_chars;
+      ++tmp_str;
+    }
+
+    if (num_chars>100) { // this is fairly arbitrary...
+      textout << outconvert << "</tr>\n<tr>";
+      num_chars=0;
+    }
+
+    textout << outconvert << "<td>" << disp << fmt_str << "</td>\n";
+    ++tsibling;
+  }
+
+  textout << outconvert << "</tr></table>\n";
+  if (use_table  || colnumber > 0) textout << outconvert << "</tr></table>\n";
+  return 0;
+}
+
+int hlistbrowserclass::output_section_group (FilterResponse_t &/*sections*/, cgiargsclass &/*args*/,
+					     const text_t &/*collection*/, int /*colnumber*/, 
+					     format_t * /*formatlistptr*/, bool /*use_table*/, 
+					     text_tset &/*metadata*/, bool &/*getParents*/,
+					     recptproto * /*collectproto*/, displayclass &/*disp*/, 
+					     outconvertclass &/*outconvert*/, ostream &/*textout*/, 
+					     ostream &/*logout*/) {
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/hlistbrowserclass.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/hlistbrowserclass.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/hlistbrowserclass.h	(revision 10506)
@@ -0,0 +1,70 @@
+/**********************************************************************
+ *
+ * hlistbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef HLISTBROWSERCLASS_H
+#define HLISTBROWSERCLASS_H
+
+#include "browserclass.h"
+#include "receptionist.h"
+
+class hlistbrowserclass : public browserclass {
+protected:
+
+public:
+  hlistbrowserclass ();
+  virtual ~hlistbrowserclass ();
+
+  void set_receptionist(receptionist *therecpt) {recpt=therecpt;}
+
+  // returns the name that specifies the browserclass type
+  text_t get_browser_name ();
+
+  virtual browserclass* clone();
+
+  virtual void load_metadata_defaults (text_tset &metadata);
+
+  virtual text_t get_default_formatstring ();
+  
+  virtual void processOID (cgiargsclass &args, recptproto *collectproto,
+			   ostream &logout);
+
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+protected:
+  receptionist *recpt;
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlbrowserclass.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlbrowserclass.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlbrowserclass.cpp	(revision 10506)
@@ -0,0 +1,73 @@
+/**********************************************************************
+ *
+ * htmlbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_HTML_BROWSER
+
+#include "htmlbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+htmlbrowserclass::htmlbrowserclass () {
+}
+
+htmlbrowserclass::~htmlbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t htmlbrowserclass::get_browser_name () {
+  return "HTML";
+}
+
+browserclass* htmlbrowserclass::clone()
+{
+  return new htmlbrowserclass();
+}
+
+// redirect to html page
+void htmlbrowserclass::processOID (cgiargsclass &args, recptproto *collectproto,
+				   ostream &logout) {
+
+  // should only reach here from within a classification
+  if (!args["d"].empty()) return;
+  if (args["cl"].empty()) return;
+
+  FilterRequest_t request;
+  FilterResponse_t response;
+  comerror_t err;
+  request.filterName = "NullFilter";
+  request.filterResultOptions = FROID;
+  request.docSet.push_back (args["cl"] + ".fc");
+  collectproto->filter (args["c"], request, response, err, logout);
+
+  if (err != noError || response.docInfo[0].OID.empty()) return;
+
+  // redirect to html page
+  args["a"] = "p";
+  args["p"] = "html";
+  args["hp"] = response.docInfo[0].OID;
+}
+
+#endif //GSDL_USE_HTML_BROWSER
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlbrowserclass.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlbrowserclass.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlbrowserclass.h	(revision 10506)
@@ -0,0 +1,52 @@
+/**********************************************************************
+ *
+ * htmlbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_HTML_BROWSER
+
+#ifndef HTMLBROWSERCLASS_H
+#define HTMLBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class htmlbrowserclass : public browserclass {
+protected:
+
+public:
+
+  htmlbrowserclass ();
+  virtual ~htmlbrowserclass ();
+
+  // returns the name that specifies the browserclass type
+  virtual text_t get_browser_name ();
+
+  void processOID (cgiargsclass &args, recptproto *collectproto,
+		   ostream &logout);
+
+  virtual browserclass* clone();
+};
+
+#endif //!HTMLBROWSERCLASS_H
+#endif //GSDL_USE_HTML_BROWSER
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlutils.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlutils.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlutils.cpp	(revision 10506)
@@ -0,0 +1,58 @@
+/**********************************************************************
+ *
+ * htmlutils.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "htmlutils.h"
+
+text_t html_safe (const text_t &instring) {
+  
+  text_t outstring;
+  text_t::const_iterator here = instring.begin();
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (*here == '"') outstring += "&quot;";
+    else if (*here == '&') outstring += "&amp;";
+    else if (*here == '<') outstring += "&lt;";
+    else if (*here == '>') outstring += "&gt;";
+    else if (*here == '#') outstring += "&#35;";
+    else outstring.push_back(*here);
+    ++here;
+  }
+  return outstring;
+}
+
+
+text_t javascript_safe (const text_t &instring) {
+
+  text_t outstring;
+  text_t::const_iterator here = instring.begin();
+  text_t::const_iterator end = instring.end();
+  while (here != end) {
+    if (*here == '"') outstring += "&quot;";
+    else if (*here == '\'') outstring += "\\'";
+    else outstring.push_back(*here);
+    ++here;
+  }
+  return outstring;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlutils.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlutils.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/htmlutils.h	(revision 10506)
@@ -0,0 +1,36 @@
+/**********************************************************************
+ *
+ * htmlutils.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef HTMLUTILS_H
+#define HTMLUTILS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+text_t html_safe (const text_t &instring);
+text_t javascript_safe (const text_t &instring);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/infodbclass.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/infodbclass.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/infodbclass.cpp	(revision 10506)
@@ -0,0 +1,582 @@
+/**********************************************************************
+ *
+ * infodbclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "infodbclass.h"
+#include "unitool.h"
+#include "gsdlunicode.h"
+#include "fileutil.h"
+#include "OIDtools.h"
+#include <stdlib.h>
+
+
+
+
+// constructors
+infodbclass::infodbclass () {
+}
+
+void infodbclass::setinfo (const text_t &key, const text_t &value) {
+  text_tarray &tarr = info[key];
+  tarr.erase(tarr.begin(), tarr.end());
+  tarr.push_back(value);
+}
+
+void infodbclass::setintinfo (const text_t &key, int value) {
+  setinfo (key, value);
+}
+
+void infodbclass::setcinfo (const text_t &key, unsigned short c) {
+  text_t t;
+  t.push_back (c);
+  setinfo (key, t);
+}
+
+text_t *infodbclass::getinfo (const text_t &key) {
+  iterator here = info.find (key);
+  if (here == info.end()) return NULL;
+
+  if ((*here).second.empty()) return NULL;
+  
+  return &((*here).second[0]);
+}
+
+text_t *infodbclass::getinfo (const text_t &key, const text_t& slang) {
+  text_tarray *t = getmultinfo(key, slang);
+  if (t == NULL || t->empty()) return NULL;
+  return &((*t)[0]);
+}
+
+int infodbclass::getintinfo (const text_t &key) {
+  text_t *t = getinfo (key);
+  if (t == NULL) return 0;
+  return t->getint();
+}
+
+int infodbclass::getintinfo (const text_t &key, const text_t& slang) {
+  text_tarray *t = getmultinfo(key, slang);
+  if (t == NULL || t->empty()) return 0;
+  return (*t)[0].getint();
+}
+
+text_t &infodbclass::operator[] (const text_t &key) {
+  text_tarray &tarr = info[key];
+  if (tarr.empty()) {
+    text_t e;
+    tarr.push_back(e);
+  }
+  return tarr[0];
+}
+
+
+void infodbclass::addinfo (const text_t &key, const text_t &value) {
+  text_tarray &tarr = info[key];
+  tarr.push_back (value);
+}
+
+void infodbclass::addintinfo (const text_t &key, int value) {
+  addinfo (key, value);
+}
+
+void infodbclass::addcinfo (const text_t &key, unsigned short c) {
+  text_t t;
+  t.push_back(c);
+  addinfo (key, t);
+}
+
+text_tarray *infodbclass::getmultinfo (const text_t &key) {
+  iterator here = info.find (key);
+  if (here == info.end()) return NULL;
+
+  return &((*here).second);
+}
+
+text_tarray *infodbclass::getmultinfo (const text_t &key, const text_t& slang) {
+  iterator here = info.end();
+  if (slang.empty()) {
+    here = info.find (key);
+  }
+  else {
+    here = info.find (key+":"+slang);
+    if (here == info.end()) {
+      here = info.find (key);
+    }
+  }
+  if (here == info.end()) return NULL;
+
+  return &((*here).second);
+}
+
+
+gdbmclass::~gdbmclass() {
+  closedatabase();
+}
+
+// returns true if opened
+bool gdbmclass::opendatabase (const text_t &filename, int mode, int num_retrys, 
+#ifdef __WIN32__
+			      bool need_filelock
+#else
+                              bool
+#endif
+			      ) {
+  text_t data_location;
+  int block_size = 512;
+  
+  if (gdbmfile != NULL) {
+    if (openfile == filename) return true;
+    else closedatabase ();
+  }
+
+  openfile = filename;
+  
+  char *namebuffer = filename.getcstr();
+  do {
+#ifdef __WIN32__
+    gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL, (need_filelock) ? 1 : 0);
+#else
+    gdbmfile = gdbm_open (namebuffer, block_size, mode, 00664, NULL);
+#endif
+    --num_retrys;
+  } while (num_retrys>0 && gdbmfile==NULL &&
+	   (gdbm_errno==GDBM_CANT_BE_READER || gdbm_errno==GDBM_CANT_BE_WRITER));
+  delete []namebuffer;
+  
+  if (gdbmfile == NULL && logout != NULL) {
+    outconvertclass text_t2ascii;
+    (*logout) << text_t2ascii << "database open failed on: " << filename << "\n";
+  }
+
+  return (gdbmfile != NULL);
+}
+
+void gdbmclass::closedatabase () {
+  if (gdbmfile == NULL) return;
+  
+  gdbm_close (gdbmfile);
+  gdbmfile = NULL;
+  openfile.clear();
+}
+
+
+// returns true on success
+bool gdbmclass::setinfo (const text_t &key, const infodbclass &info) {
+  if (gdbmfile == NULL) return false;
+
+  text_t subkey;
+  text_t data;
+
+  // get all the keys and values
+  infodbclass::const_iterator info_here = info.begin();
+  infodbclass::const_iterator info_end = info.end();
+  while (info_here != info_end) {
+    // add the key
+    subkey.clear();
+    subkey.push_back('<');
+    text_t::const_iterator subkey_here = (*info_here).first.begin();
+    text_t::const_iterator subkey_end = (*info_here).first.end();
+    while (subkey_here != subkey_end) {
+      if (*subkey_here == '>') {
+	subkey.push_back('\\'); subkey.push_back('>');
+      } else if (*subkey_here == '\n') {
+	subkey.push_back('\\'); subkey.push_back('n');
+      } else if (*subkey_here == '\r') {
+	subkey.push_back('\\'); subkey.push_back('r');
+      } else if (*subkey_here == '\\') {
+	subkey.push_back('\\'); subkey.push_back('\\');
+      } else {
+	subkey.push_back (*subkey_here);
+      }
+      ++subkey_here;
+    }
+    subkey.push_back('>');
+
+    // add the values
+    text_tarray::const_iterator subvalue_here = (*info_here).second.begin();
+    text_tarray::const_iterator subvalue_end = (*info_here).second.end();
+    while (subvalue_here != subvalue_end) {
+      data += subkey;
+      
+      text_t::const_iterator thissubvalue_here = (*subvalue_here).begin();
+      text_t::const_iterator thissubvalue_end = (*subvalue_here).end();
+      while (thissubvalue_here != thissubvalue_end) {
+	if (*thissubvalue_here == '>') {
+	  data.push_back('\\'); data.push_back('>');
+	} else if (*thissubvalue_here == '\n') {
+	  data.push_back('\\'); data.push_back('n');
+	} else if (*thissubvalue_here == '\r') {
+	  data.push_back('\\'); data.push_back('r');
+	} else if (*thissubvalue_here == '\\') {
+	  data.push_back('\\'); data.push_back('\\');
+	} else {
+	  data.push_back (*thissubvalue_here);
+	}
+	
+	++thissubvalue_here;
+      }
+      
+      data.push_back('\n');
+      ++subvalue_here;
+    }
+
+    ++info_here;
+  }
+
+  // store the value
+  datum key_data;
+  datum data_data;
+
+  // get a utf-8 encoded c string of the unicode key
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    return false;
+  }
+  key_data.dsize = strlen (key_data.dptr);
+
+  data_data.dptr = (to_utf8(data)).getcstr();
+  if (data_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    delete []key_data.dptr;
+    return false;
+  }
+  data_data.dsize = strlen (data_data.dptr);
+
+  int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
+  delete []key_data.dptr;
+  delete []data_data.dptr;
+
+  return (ret == 0);
+
+}
+
+//returns true on success
+bool gdbmclass::setinfo (const text_t &key, const text_t &data) {
+  if (gdbmfile == NULL) return false;
+  
+  // store the value
+  datum key_data;
+  datum data_data;
+
+  // get a utf-8 encoded c string of the unicode key
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    return false;
+  }
+  key_data.dsize = strlen (key_data.dptr);
+
+  data_data.dptr = (to_utf8(data)).getcstr();
+  if (data_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    delete []key_data.dptr;
+    return false;
+  }
+  data_data.dsize = strlen (data_data.dptr);
+
+  int ret = gdbm_store (gdbmfile, key_data, data_data, GDBM_REPLACE);
+  delete []key_data.dptr;
+  delete []data_data.dptr;
+
+  return (ret == 0);
+
+}
+
+
+void gdbmclass::deletekey (const text_t &key) {
+  if (gdbmfile == NULL) return;
+
+  // get a utf-8 encoded c string of the unicode key
+  datum key_data;
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) return;
+  key_data.dsize = strlen (key_data.dptr);
+
+  // delete the key
+  gdbm_delete (gdbmfile, key_data);
+
+  // free up the key memory
+  delete []key_data.dptr;
+}
+
+
+// getfirstkey and getnextkey are used for traversing the database
+// no insertions or deletions should be carried out while traversing
+// the database. when there are no keys left to visit in the database
+// an empty string is returned.
+text_t gdbmclass::getfirstkey () {
+  if (gdbmfile == NULL) return g_EmptyText;
+
+  // get the first key
+  datum firstkey_data = gdbm_firstkey (gdbmfile);
+  if (firstkey_data.dptr == NULL) return g_EmptyText;
+
+  // convert it to text_t
+  text_t firstkey;
+  firstkey.setcarr (firstkey_data.dptr, firstkey_data.dsize);
+  free (firstkey_data.dptr);
+  return to_uni(firstkey);  // convert to unicode
+}
+
+text_t gdbmclass::getnextkey (const text_t &key) {
+  if (gdbmfile == NULL || key.empty()) return g_EmptyText;
+
+  // get a utf-8 encoded c string of the unicode key
+  datum key_data;
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) return g_EmptyText;
+  key_data.dsize = strlen (key_data.dptr);
+  
+  // get the next key
+  datum nextkey_data = gdbm_nextkey (gdbmfile, key_data);
+  if (nextkey_data.dptr == NULL) {
+    delete []key_data.dptr;
+    return g_EmptyText;
+  }
+
+  // convert it to text_t
+  text_t nextkey;
+  nextkey.setcarr (nextkey_data.dptr, nextkey_data.dsize);
+  free (nextkey_data.dptr);
+  delete []key_data.dptr;
+  return to_uni(nextkey);  // convert to unicode
+}
+
+
+// replaces the .fc, .lc, .pr, .ns and .ps syntax (first child, 
+// last child, parent, next sibling, previous sibling) 
+// it expects child, parent, etc. to exist if syntax has been used
+// so you should test before using
+text_t gdbmclass::translate_OID (const text_t &inOID, infodbclass &info) {
+
+  if (inOID.size() < 4) return inOID;
+  if (findchar (inOID.begin(), inOID.end(), '.') == inOID.end()) return inOID;
+
+  text_t OID = inOID;
+  text_tarray tailarray;
+  text_t tail = substr (OID.end()-3, OID.end());
+  while (tail == ".fc" || tail == ".lc" || tail == ".pr" || 
+	 tail == ".ns" || tail == ".ps") {
+    tailarray.push_back(tail);
+    OID.erase (OID.end()-3, OID.end());
+    tail = substr (OID.end()-3, OID.end());
+  }
+
+  if (!tailarray.size()) return inOID;
+  text_tarray::const_iterator begin = tailarray.begin();
+  text_tarray::const_iterator here = tailarray.end() - 1;
+
+  while (here >= begin) {
+
+    if (*here == ".fc")
+      get_first_child (OID, info);
+    else if (*here == ".lc")
+      get_last_child (OID, info);
+    else if (*here == ".pr")
+      OID = get_parent (OID);
+    else if (*here == ".ns")
+      get_next_sibling (OID, info);
+    else if (*here == ".ps")
+      get_previous_sibling (OID, info);
+    
+    --here;
+  }
+  return OID;
+}
+
+void gdbmclass::get_first_child (text_t &OID, infodbclass &info) {
+
+  text_t firstchild;
+  if (getinfo (OID, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      text_t parent = OID;
+      getdelimitstr (contains.begin(), contains.end(), ';', firstchild);
+      if (firstchild.empty()) OID = contains;
+      else OID = firstchild;
+      if (*(OID.begin()) == '"') translate_parent (OID, parent);
+    }
+  }
+}
+
+void gdbmclass::get_last_child (text_t &OID, infodbclass &info) {
+
+  text_tarray children;
+  if (getinfo (OID, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      text_t parent = OID;
+      splitchar (contains.begin(), contains.end(), ';', children);
+      OID = children.back();
+      if (*(OID.begin()) == '"') translate_parent (OID, parent);
+    }
+  }
+}
+  
+void gdbmclass::get_next_sibling (text_t &OID, infodbclass &info) {
+
+  text_tarray siblings;
+  text_t parent = get_parent (OID);
+	     
+  if (getinfo (parent, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      splitchar (contains.begin(), contains.end(), ';', siblings);
+      text_tarray::const_iterator here = siblings.begin();
+      text_tarray::const_iterator end = siblings.end();
+      text_t shrunk_OID = OID;
+      shrink_parent (shrunk_OID);
+      while (here != end) {
+	if (*here == shrunk_OID && (here+1 != end)) {
+	  OID = *(here+1);
+	  if (*(OID.begin()) == '"') translate_parent (OID, parent);
+	  break;
+	}
+	++here;
+      }
+    }
+  }
+}
+
+void gdbmclass::get_previous_sibling (text_t &OID, infodbclass &info) {
+
+  text_tarray siblings;
+  text_t parent = get_parent (OID);
+
+  if (getinfo (parent, info)) {
+    text_t &contains = info["contains"];
+    if (!contains.empty()) {
+      splitchar (contains.begin(), contains.end(), ';', siblings);
+      text_tarray::const_iterator here = siblings.begin();
+      text_tarray::const_iterator end = siblings.end();
+      text_t shrunk_OID = OID;
+      shrink_parent (shrunk_OID);
+      while (here != end) {
+	if (*here == shrunk_OID && (here != siblings.begin())) {
+	  OID = *(here-1);
+	  if (*(OID.begin()) == '"') translate_parent (OID, parent);
+	  break;
+	}
+	++here;
+      }
+    }
+  }
+}
+
+// returns true on success
+bool gdbmclass::getinfo (const text_t& key, infodbclass &info) {
+  text_t data;
+  
+  if (!getkeydata (key, data)) return false;
+  text_t::iterator here = data.begin ();
+  text_t::iterator end = data.end ();
+  
+  text_t ikey, ivalue;
+  info.clear (); // reset info
+  
+  while (getinfoline (here, end, ikey, ivalue)) {
+    info.addinfo (ikey, ivalue);
+  }
+  
+  return true;
+}
+
+// returns true if exists
+bool gdbmclass::exists (const text_t& key) {
+  text_t data;
+  return getkeydata (key, data);
+}
+
+// returns true on success
+bool gdbmclass::getkeydata (const text_t& key, text_t &data) {
+  datum key_data;
+  datum return_data;
+
+  if (gdbmfile == NULL) return false;
+  
+  // get a utf-8 encoded c string of the unicode key
+  key_data.dptr = (to_utf8(key)).getcstr();
+  if (key_data.dptr == NULL) {
+    if (logout != NULL) (*logout) << "gdbmclass: out of memory\n";
+    return false;
+  }
+  key_data.dsize = strlen (key_data.dptr);
+  
+  // fetch the result
+  return_data = gdbm_fetch (gdbmfile, key_data);
+  delete []key_data.dptr;
+  
+  if (return_data.dptr == NULL) return false;
+
+  data.setcarr (return_data.dptr, return_data.dsize);
+  free (return_data.dptr);
+  data = to_uni(data);  // convert to unicode
+
+  return true;
+}
+
+// returns true on success
+bool gdbmclass::getinfoline (text_t::iterator &here, text_t::iterator end, 
+			     text_t &key, text_t &value) {
+  key.clear();
+  value.clear();
+
+  // ignore white space
+  while (here != end && is_unicode_space (*here)) ++here;
+
+  // get the '<'
+  if (here == end || *here != '<') return false;
+  ++here;
+  
+  // get the key
+  while (here != end && *here != '>') {
+    key.push_back(*here);
+    ++here;
+  }
+  
+  // get the '>'
+  if (here == end || *here != '>') return false;
+  ++here;
+  
+  // get the value
+  while (here != end && *here != '\n') {
+    if (*here == '\\') { 
+      // found escape character
+      ++here;
+      if (here != end) {
+	if (*here == 'n') value.push_back ('\n');
+	else if (*here == 'r') value.push_back ('\r');
+	else value.push_back(*here);
+      }
+
+    } else {
+      // a normal character
+      value.push_back(*here);
+    }
+
+    ++here;
+  }
+
+  return true;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/infodbclass.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/infodbclass.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/infodbclass.h	(revision 10506)
@@ -0,0 +1,196 @@
+/**********************************************************************
+ *
+ * infodbclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef INFODBCLASS_H
+#define INFODBCLASS_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+#ifdef __WIN32__
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+#include "autoconf.h"
+#include "systems.h"
+#include "gdbmconst.h"
+#include "gdbm.h"
+#ifdef __cplusplus
+  }
+#endif
+
+#else
+#include <gdbm.h>
+#endif
+
+
+typedef map<text_t, text_tarray, lttext_t> text_tarraymap;
+
+
+// infodbclass is used to store information about a object
+class infodbclass {
+protected:
+  text_tarraymap info;
+  text_t lang;
+
+public:
+  // type support for text_tarraymap
+  typedef text_tarraymap::iterator iterator;
+  typedef text_tarraymap::const_iterator const_iterator;
+  typedef text_tarraymap::reference reference;
+  typedef text_tarraymap::const_reference const_reference;
+  typedef text_tarraymap::size_type size_type;
+  typedef text_tarraymap::difference_type difference_type;
+  typedef text_tarraymap::const_reverse_iterator const_reverse_iterator;
+  typedef text_tarraymap::reverse_iterator reverse_iterator;
+  
+  // constructors
+  infodbclass ();
+
+  // basic container support
+  iterator begin () {return info.begin();}
+  const_iterator begin () const {return info.begin();}
+  iterator end () {return info.end();}
+  const_iterator end () const {return info.end();}
+
+  void erase(iterator pos) {info.erase(pos);}
+  void erase(iterator first, iterator last) {info.erase(first, last);}
+  infodbclass &operator=(const infodbclass &x) {info=x.info;return *this;}
+
+  bool empty () const {return info.empty();}
+  size_type size() const {return info.size();}
+
+
+  // added functionality
+  void clear () {info.erase(info.begin(),info.end());}
+
+  // set default language
+  void set_language(const text_t& str_lang) { lang = str_lang; }
+  const text_t &get_language() const { return lang; }
+
+  // the following functions deal with keys that can only
+  // have one value for compatibility
+  
+  // getinfo returns NULL if there isn't an entry with
+  // 'key' already defined, getintinfo returns 0 if there wasn't an
+  // entry with 'key' defined and operator[] returns "" if
+  // 'key' wasn't already defined (and sets 'key'="").
+  void setinfo (const text_t &key, const text_t &value);
+  void setintinfo (const text_t &key, int value);
+  void setcinfo (const text_t &key, unsigned short c);
+  text_t *getinfo (const text_t &key);
+  // get info overriding language set on this object
+  text_t *getinfo (const text_t &key, const text_t& lang);
+  int getintinfo (const text_t &key);
+  // get info overriding language set on this object
+  int getintinfo (const text_t &key, const text_t& lang);
+  text_t &operator[] (const text_t &key);
+
+
+  // the next set of functions allow you to set and access keys
+  // that can have more than one value
+
+  // getmultinfo returns NULL if there isn't an entry with
+  // 'key' already defined
+  void addinfo (const text_t &key, const text_t &value);
+  void addintinfo (const text_t &key, int value);
+  void addcinfo (const text_t &key, unsigned short c);
+  text_tarray *getmultinfo (const text_t &key);
+  // get info overriding language set on this object
+  text_tarray *getmultinfo (const text_t &key, const text_t& lang);
+};
+
+
+class gdbmclass {
+public:
+  gdbmclass() {gdbmfile = NULL; logout = &cerr;};
+  ~gdbmclass();
+  
+  // returns true if opened
+  bool opendatabase (const text_t &filename, int mode, int num_retrys, 
+		     bool need_filelock);
+  void closedatabase ();
+
+  // replaces the .c, .p, .n, .l syntax (child, parent, next, previous) 
+  // it expects child, parent, etc. to exist if syntax has been used
+  // so you should test before using
+  text_t translate_OID (const text_t &OID, infodbclass &info);
+
+  // returns true on success
+  bool getinfo (const text_t& key, infodbclass &info);
+  void setlogout (ostream *thelogout) {logout = thelogout;}
+
+  // returns true if exists
+  bool exists (const text_t& key);
+
+  // returns true on success
+  bool setinfo (const text_t &key, const infodbclass &info);
+  // returns true on success
+  bool setinfo (const text_t &key, const text_t &data);
+
+  void deletekey (const text_t &key);
+
+  // getfirstkey and getnextkey are used for traversing the database
+  // no insertions or deletions should be carried out while traversing
+  // the database. when there are no keys left to visit in the database
+  // an empty string is returned.
+  text_t getfirstkey ();
+  text_t getnextkey (const text_t &key);
+
+    // returns true on success
+  bool getkeydata (const text_t& key, text_t &data);
+
+protected:
+  text_t openfile;
+  GDBM_FILE gdbmfile;
+  ostream *logout;
+
+  void get_first_child (text_t &OID, infodbclass &info);
+  void get_last_child (text_t &OID, infodbclass &info);
+  void get_next_sibling (text_t &OID, infodbclass &info);
+  void get_previous_sibling (text_t &OID, infodbclass &info);
+
+
+  // returns true on success
+  bool getinfoline (text_t::iterator &here, text_t::iterator end, 
+		   text_t &key, text_t &value);
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/invbrowserclass.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/invbrowserclass.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/invbrowserclass.cpp	(revision 10506)
@@ -0,0 +1,44 @@
+/**********************************************************************
+ *
+ * invbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "invbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+invbrowserclass::invbrowserclass () {
+}
+
+invbrowserclass::~invbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t invbrowserclass::get_browser_name () {
+  return "Invisible";
+}
+
+browserclass* invbrowserclass::clone()
+{
+  return new invbrowserclass();
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/invbrowserclass.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/invbrowserclass.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/invbrowserclass.h	(revision 10506)
@@ -0,0 +1,50 @@
+/**********************************************************************
+ *
+ * invbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef INVBROWSERCLASS_H
+#define INVBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class invbrowserclass : public browserclass {
+protected:
+
+public:
+
+  // this browser class does nothing by default - it should
+  // be overridden for receptionists wanting to display 
+  // 'Invisible' classifications in some way
+
+  invbrowserclass ();
+  virtual ~invbrowserclass ();
+
+  // returns the name that specifies the browserclass type
+  text_t get_browser_name ();
+
+  virtual browserclass* clone();
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/librarymain.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/librarymain.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/librarymain.cpp	(revision 10506)
@@ -0,0 +1,286 @@
+/**********************************************************************
+ *
+ * librarymain.cpp -- 
+ * Copyright (C) 1999  The New Zaland Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#include "receptionist.h"
+#include "cgiwrapper.h"
+#include "recptconfig.h"
+#include "fileutil.h"
+#include "nullproto.h"
+// z39.50 stuff - johnmcp
+#if defined(USE_Z3950)
+#include "z3950proto.h"
+#endif
+#include "collectserver.h"
+#include "filter.h"
+#include "browsefilter.h"
+#include "infodbclass.h"
+#include "collectset.h"
+#include <assert.h>
+
+#include "action.h"
+#include "statusaction.h"
+#include "pageaction.h"
+#include "pingaction.h"
+#include "queryaction.h"
+#include "documentaction.h"
+#include "authenaction.h"
+#include "usersaction.h"
+#include "extlinkaction.h"
+
+#ifdef GSDL_USE_EXPORT_ACTION
+#include "exportaction.h"
+#endif
+
+#ifdef GSDL_USE_CL_DISPLAY_ACTION
+#include "cldisplayaction.h"
+#endif
+
+#ifdef GSDL_USE_COURSES_ACTION
+#include "coursesaction.h"
+#endif
+
+#ifdef GSDL_USE_COMPOSITION_ACTION
+#include "compositionaction.h"
+#endif
+
+#ifdef GSDL_USE_INDEX_BROWSE_ACTION
+#include "indexbrowseaction.h"
+#endif
+
+#ifdef GSDL_USE_DIR_BROWSE_ACTION
+#include "dirbrowseaction.h"
+#endif
+
+#ifdef GSDL_USE_GENERATOR_ACTION
+#include "generatoraction.h"
+#endif
+
+#ifdef GSDL_USE_GTI_ACTION
+#include "gtiaction.h"
+#endif
+
+#include "tipaction.h"
+#include "collectoraction.h"
+#include "browseaction.h"
+#include "phindaction.h"
+
+#include "browserclass.h"
+#include "vlistbrowserclass.h"
+#include "hlistbrowserclass.h"
+#include "datelistbrowserclass.h"
+#include "invbrowserclass.h"
+#include "pagedbrowserclass.h"
+#include "htmlbrowserclass.h"
+#include "phindbrowserclass.h"
+
+#ifdef GSDL_USE_CLASSIFIER_BROWSER
+//classifier browsers
+
+#include "treeclassifierbrowserclass.h"
+#ifdef GSDL_USE_TREE_EX_CLASSIFIER_BROWSER
+#include "treeexclassifierbrowserclass.h"
+#endif
+
+#endif //GSDL_USE_CLASSIFIER_BROWSER
+
+int main () {
+  receptionist recpt;
+  nullproto    nproto;
+  collectset  *cservers;
+#if defined(USE_Z3950)
+  z3950proto   zproto;
+#endif
+  text_t       gsdlhome;
+
+  cservers = new collectset(gsdlhome);
+
+  // set up the null protocol
+  nproto.set_collectset(cservers);
+
+  // configure the receptionist server list
+  cservers->setReceptionistServers(recpt, gsdlhome);  
+
+  // add the protocol to the receptionist
+  recpt.add_protocol (&nproto);
+
+  // z39.50 stuff - johnmcp
+#if defined(USE_Z3950)
+  // add the z39.50 server information. Read in the file
+  // etc/recpt/z3950.cfg for list of servers and their databases.
+  text_t z3950cfg = filename_cat (gsdlhome, "etc");
+  //  z3950cfg = filename_cat (z3950cfg, "recpt");
+  z3950cfg = filename_cat (z3950cfg, "packages");
+  z3950cfg = filename_cat (z3950cfg, "z3950.cfg");
+#ifdef USE_FASTCGI
+  // currently can't use z39.50 if fastcgi used
+#warning  "Disabling z39.50 support as fastcgi is in use"
+  if (0) {
+#else
+  if (file_exists(z3950cfg)) {
+#endif
+    text_t z3950err = filename_cat (gsdlhome, "etc", "z3950log.txt");
+    zproto.read_config_file(z3950cfg,z3950err);
+    // only add this protocol if we have any servers configured.
+    if (zproto.getServerCount()>0)
+      recpt.add_protocol (&zproto);
+  }
+#endif
+
+#ifdef GSDL_USE_TIP_ACTION
+  // the list of actions. Note: these actions will become invalid
+  // at the end of this function. We will clean them.
+  recpt.add_action (new tipaction());
+#endif
+
+#ifdef GSDL_USE_STATUS_ACTION
+  statusaction *astatusaction = new statusaction();
+  astatusaction->set_receptionist (&recpt);
+  recpt.add_action (astatusaction);
+#endif
+
+  pageaction *apageaction = new pageaction();
+  apageaction->set_receptionist (&recpt);
+  recpt.add_action (apageaction);
+
+#ifdef GSDL_USE_PING_ACTION
+  recpt.add_action (new pingaction());
+#endif
+
+  queryaction *aqueryaction = new queryaction();
+  aqueryaction->set_receptionist (&recpt);
+  recpt.add_action (aqueryaction);
+		
+  documentaction *adocumentaction = new documentaction();
+  adocumentaction->set_receptionist (&recpt);
+  recpt.add_action (adocumentaction);
+
+#ifdef GSDL_USE_USERS_ACTION
+  recpt.add_action (new usersaction());
+#endif
+
+#ifdef GSDL_USE_EXTLINK_ACTION
+  extlinkaction *aextlinkaction = new extlinkaction();
+  aextlinkaction->set_receptionist(&recpt);
+  recpt.add_action (aextlinkaction);
+#endif
+		
+#ifdef GSDL_USE_AUTHEN_ACTION
+  authenaction *aauthenaction = new authenaction();
+  aauthenaction->set_receptionist(&recpt);
+  recpt.add_action (aauthenaction);
+#endif
+
+#ifdef GSDL_USE_COLLECTOR_ACTION
+  collectoraction *acollectoraction = new collectoraction();
+  acollectoraction->set_receptionist (&recpt);
+  recpt.add_action(acollectoraction);
+#endif
+
+#ifdef GSDL_USE_BROWSE_ACTION
+  browseaction *abrowseaction = new browseaction();
+  abrowseaction->set_receptionist (&recpt);
+  recpt.add_action(abrowseaction);
+#endif
+
+#ifdef GSDL_USE_PHIND_ACTION
+  recpt.add_action(new phindaction());
+#endif
+
+#ifdef GSDL_USE_GTI_ACTION
+  gtiaction *agtiaction = new gtiaction();
+  agtiaction->set_receptionist(&recpt);
+  recpt.add_action(agtiaction);
+#endif
+
+  // list of browsers
+  vlistbrowserclass avlistbrowserclass;
+  avlistbrowserclass.set_receptionist(&recpt);
+  recpt.add_browser (&avlistbrowserclass);
+  recpt.setdefaultbrowser ("VList");
+
+  hlistbrowserclass ahlistbrowserclass;
+  ahlistbrowserclass.set_receptionist(&recpt);
+  recpt.add_browser (&ahlistbrowserclass);
+
+#ifdef GSDL_USE_DATELIST_BROWSER
+  datelistbrowserclass adatelistbrowserclass;
+  recpt.add_browser (&adatelistbrowserclass);
+#endif
+
+  invbrowserclass ainvbrowserclass;
+  recpt.add_browser (&ainvbrowserclass);
+
+#ifdef GSDL_USE_PAGED_BROWSER
+  pagedbrowserclass apagedbrowserclass;
+  recpt.add_browser (&apagedbrowserclass);
+#endif
+
+#ifdef GSDL_USE_HTML_BROWSER
+  htmlbrowserclass ahtmlbrowserclass;
+  recpt.add_browser (&ahtmlbrowserclass);
+#endif
+
+#ifdef GSDL_USE_PHIND_BROWSER
+  phindbrowserclass aphindbrowserclass;
+  recpt.add_browser (&aphindbrowserclass);
+#endif
+
+#ifdef GSDL_USE_CLASSIFIER_BROWSER
+  //list of classifier browsers
+  CTreeClassifierBrowserClass *pTreeClassifierBrowser = new CTreeClassifierBrowserClass();
+  if (pTreeClassifierBrowser != NULL) {
+    recpt.GetClassifierBrowsers().AddBrowser(pTreeClassifierBrowser);
+    recpt.GetClassifierBrowsers().SetDefaultBrowser(pTreeClassifierBrowser->GetBrowserName());
+  }
+#ifdef GSDL_USE_TREE_EX_CLASSIFIER_BROWSER
+  CTreeExClassifierBrowserClass *pTreeExClassifierBrowser = new CTreeExClassifierBrowserClass();
+  if (pTreeExClassifierBrowser != NULL) {
+    recpt.GetClassifierBrowsers().AddBrowser(pTreeExClassifierBrowser);
+  }
+#endif //GSDL_USE_TREE_EX_CLASSIFIER_BROWSER
+#endif //GSDL_USE_CLASSIFIER_BROWSER
+
+  cgiwrapper (recpt, "");
+  delete cservers;
+
+  // clean up the actions
+  actionmapclass::iterator thisAction = recpt.get_actionmap_ptr()->begin();
+  actionmapclass::iterator endAction = recpt.get_actionmap_ptr()->begin();
+  while (thisAction != endAction) {
+    delete thisAction->second.a; thisAction->second.a = NULL;
+    ++thisAction;
+  }
+  thisAction = recpt.get_actionmap_ptr()->begin();
+  recpt.get_actionmap_ptr()->erase(thisAction, endAction);
+  return 0;
+}
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/nullproto.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/nullproto.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/nullproto.cpp	(revision 10506)
@@ -0,0 +1,163 @@
+/**********************************************************************
+ *
+ * nullproto.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "nullproto.h"
+#include <assert.h>
+
+#include "filter.h"
+#include "browsefilter.h"
+#include "mgqueryfilter.h"
+#include "mgppqueryfilter.h"
+#include "infodbclass.h"
+#include "mggdbmsource.h"
+#include "mgsearch.h"
+#include "mgppsearch.h"
+#include "fileutil.h"
+
+nullproto::nullproto() {
+  cset = NULL;
+}
+
+nullproto::~nullproto() {
+}
+
+// add collection to collectset (this should not be called until after the
+// collectset has been added to the protocol with set_collectset()
+void nullproto::add_collection (const text_t &collection, void *recpt, 
+				const text_t &gsdlhome, const text_t &gdbmhome) {      
+  
+  if (cset != NULL) {
+    this->cset->add_collection (collection, gsdlhome);
+  }
+}
+
+
+// remove_collection deletes the collection server of collection.
+// This only needs to be called if a collectionserver is to be
+// removed while the library is running. The destructor function
+// cleans up all collectservers when the program exits.
+void nullproto::remove_collection (const text_t &collection, ostream &logout) {
+  cset->remove_collection(collection, logout);
+}
+
+// this configure will configure each of the collection servers
+void nullproto::configure (const text_t &key, const text_tarray &cfgline,
+			   comerror_t &err) {
+  // the naming of the collection should not be done here,
+  // it should be done just after the collection server has been 
+  // created
+
+  // the protocol should not configure the collection set; it should be
+  // done direct to the collection server set
+  if (key == "gsdlhome" || key == "gdbmhome") {
+    cset->configure(key, cfgline);
+  }
+}
+
+// this init will configure and init each of the collection servers
+bool nullproto::init (comerror_t &err, ostream &logout) {
+  return cset->init(logout);
+}
+
+text_t nullproto::get_site_name (comerror_t &err) {
+  return "localhost";
+}
+
+text_t nullproto::get_protocol_name (comerror_t &err) {
+  return "nullproto";
+}
+
+
+void nullproto::get_collection_list (text_tarray &collist, comerror_t &err, 
+				     ostream &/*logout*/) {
+  cset->getCollectionList(collist);
+  err = noError; // no error is guaranteed - collection server shouldn't
+                 // about receptionist error states, logout is irrelevant
+}
+
+void nullproto::has_collection (const text_t &collection, bool &hascollection, 
+				comerror_t &err, ostream &/*logout*/) {
+  hascollection = (cset->getCollectServer(collection) != NULL);
+  err = noError;
+}
+
+void nullproto::ping (const text_t &collection, bool &wassuccess, 
+		      comerror_t &err, ostream &logout) {
+  collectserver *cserver = cset->getCollectServer(collection);
+  if (cserver != NULL) cserver->ping(wassuccess, err, logout);
+  else err = protocolError;
+}
+
+void nullproto::get_collectinfo (const text_t &collection, 
+				 ColInfoResponse_t &collectinfo,
+				 comerror_t &err, ostream &logout) {
+  collectserver *cserver = cset->getCollectServer (collection);
+  if (cserver != NULL) cserver->get_collectinfo (collectinfo, err, logout);
+  else err = protocolError;
+}
+
+
+void nullproto::get_filterinfo (const text_t &collection,
+				InfoFiltersResponse_t &response,
+				comerror_t &err, ostream &logout) {
+  collectserver *cserver = cset->getCollectServer (collection);
+  if (cserver != NULL) cserver->get_filterinfo (response, err, logout);
+  else err = protocolError;
+}
+
+void nullproto::get_filteroptions (const text_t &collection,
+				   const InfoFilterOptionsRequest_t &request,
+				   InfoFilterOptionsResponse_t &response, 
+				   comerror_t &err, ostream &logout) {
+  collectserver *cserver = cset->getCollectServer (collection);
+  if (cserver != NULL) cserver->get_filteroptions (request, response, err, logout);
+  else err = protocolError;
+}
+
+void nullproto::filter (const text_t &collection,
+			FilterRequest_t &request,
+			FilterResponse_t &response,
+			comerror_t &err, ostream &logout) {
+  collectserver *cserver = cset->getCollectServer (collection);
+  if (cserver != NULL) cserver->filter (request, response, err, logout);
+  else err = protocolError;
+}
+
+void nullproto::get_document (const text_t &collection,
+			      const DocumentRequest_t &request,
+			      DocumentResponse_t &response,
+			      comerror_t &err, ostream &logout) {
+  collectserver *cserver = cset->getCollectServer (collection);
+  if (cserver != NULL) cserver->get_document (request, response, err, logout);
+  else err = protocolError;
+}
+
+void nullproto::is_searchable (const text_t &collection, bool &issearchable, 
+			       comerror_t &err, ostream &logout) {
+  issearchable = false;
+  collectserver *cserver = cset->getCollectServer (collection);
+  if (cserver != NULL) cserver->is_searchable (issearchable, err, logout);
+  else err = protocolError;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/nullproto.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/nullproto.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/nullproto.h	(revision 10506)
@@ -0,0 +1,99 @@
+/**********************************************************************
+ *
+ * nullproto.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef NULLPROTO_H
+#define NULLPROTO_H
+
+#include "gsdlconf.h"
+#include "collectserver.h"
+#include "collectset.h"
+#include "recptproto.h"
+#include "receptionist.h"
+
+class nullproto : public recptproto {
+protected:
+  collectset           *cset;
+public:
+  nullproto();
+  virtual ~nullproto();
+
+  // add_collection sets up the collectionserver and calls
+  // add_collectserver
+  virtual void add_collection (const text_t &collection, void *recpt, 
+			       const text_t &gsdlhome, const text_t &gdbmhome);
+
+  void set_collectset(collectset *set) { this->cset = set; }
+
+  // remove_collection deletes the collection server of collection.
+  // This only needs to be called if a collectionserver is to be
+  // removed while the library is running as the destructor function
+  // cleans up all collectservers when the program exits.
+  void remove_collection (const text_t &collection, ostream &logout);
+
+  // this configure will configure each of the collection servers
+  void configure (const text_t &key, const text_tarray &cfgline,
+		  comerror_t &err);
+
+  // this init will init each of the collection servers
+  bool init (comerror_t &err, ostream &logout);
+
+  text_t get_protocol_name (comerror_t &err);
+  text_t get_site_name (comerror_t &err);
+
+  void get_collection_list (text_tarray &collist, comerror_t &err, 
+			    ostream &logout);
+  void has_collection (const text_t &collection, bool &hascollection, 
+		       comerror_t &err, ostream &logout);
+  void ping (const text_t &collection, bool &wassuccess, 
+	     comerror_t &err, ostream &logout);
+  void get_collectinfo (const text_t &collection, 
+			ColInfoResponse_t &collectinfo,
+			comerror_t &err, ostream &logout);
+  void get_filterinfo (const text_t &collection,
+		       InfoFiltersResponse_t &response,
+		       comerror_t &err, ostream &logout);
+  void get_filteroptions (const text_t &collection,
+			  const InfoFilterOptionsRequest_t &request,
+			  InfoFilterOptionsResponse_t &response, 
+			  comerror_t &err, ostream &logout);
+  void filter (const text_t &collection,
+	       FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout);
+
+  void get_document (const text_t &collection,
+		     const DocumentRequest_t &request,
+		     DocumentResponse_t &response,
+		     comerror_t &err, ostream &logout);
+
+  void is_searchable (const text_t &collection, bool &issearchable, 
+		      comerror_t &err, ostream &logout);
+
+
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/pageaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/pageaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/pageaction.cpp	(revision 10506)
@@ -0,0 +1,1044 @@
+/**********************************************************************
+ *
+ * pageaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+// Changelog:
+
+// 11th July 2003:
+
+//   Added 3 functions to deal with the collection style
+//   A deciding function and then 2 functions that actually
+//   do the work for us, either images or pulldown.
+
+
+#include "OIDtools.h"
+#include "pageaction.h"
+#include "receptionist.h"
+#include "fileutil.h"
+#include "gsdltools.h"
+#include <time.h>
+
+pageaction::pageaction () {
+
+  status_disabled = true;
+  collector_disabled = true;
+  translator_disabled = true;
+  gliapplet_disabled = true;
+  recpt = NULL;
+
+  // this action uses cgi variables "a", "p", and "hp"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "p";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "p";
+  arg_ainfo.longname = "page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "home";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "hp";
+  arg_ainfo.longname = "html page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "bp";
+  arg_ainfo.longname = "set preferences button";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // the "u" argument will disable the search facility, remove links to the
+  // home and preferences pages, and disable the DocumentButton buttons
+  // (for use when generating static html versions of collections)
+  arg_ainfo.shortname = "u";
+  arg_ainfo.longname = "static page";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+pageaction::~pageaction () {
+}
+
+bool pageaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &args, 
+				recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+
+  if (args["p"] == "preferences" && !args["bp"].empty()) {
+    if (args["hd"] != "0") args["hd"] = args["hdn"];
+  }
+
+  return true;
+}
+
+void pageaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				   response_t &response,text_t &response_data, 
+				   ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+// This function helps decide whether we want a
+// images or pulldown style collection display
+// We refer to the macro files for the options
+// for images or pulldown menu and use that to
+// switch to the appropriate function to do the job
+
+// Aly Dharshi
+// 11th July 2003
+
+void pageaction::homepagestyle(displayclass &disp, recptprotolistclass *protos,
+			       cgiargsclass &args, ostream &logout)
+{
+
+  const recptconf &configinfo = recpt->get_configinfo();
+
+  if (configinfo.HomePageType == "images") {
+     home_images(disp, protos, args, configinfo, logout);
+
+  } else
+     {
+	home_pulldown(disp, protos, args, configinfo, logout);
+     }
+}
+
+// This function allows for the Greenstone
+// collection to be displayed in a pull down
+// menu similar to that in documentaction.cpp
+
+// Aly Dharshi
+// 11th July 2003
+
+void pageaction::home_pulldown(displayclass &disp, recptprotolistclass *protos, 
+			       cgiargsclass &args, const recptconf &configinfo,
+			       ostream &logout) {
+   
+   //text_t homeextra = "<center><table width=_pagewidth_><tr valign=top>\n";
+  //bool found_valid_col = false;
+
+   text_t homeextra = "<form method=\"get\" name=\"browse\">\n";
+   homeextra += "<select name=\"collections\" onChange=\"location.href=";
+   homeextra += "document.browse.collections.options[document.browse.collections.selectedIndex].value\">\n";
+
+   
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+
+      text_tarray collist;
+      comerror_t err;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+
+	int count = 0;
+	bool first = true;
+	while (collist_here != collist_end) {
+	  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
+	  
+	  if (cinfo != NULL) {
+	    if (cinfo->isPublic && (cinfo->buildDate > 0)) {
+
+	      text_t coll_type = "&ct=";
+	      if ((cinfo->buildType == "mgpp") || (cinfo->buildType == "lucene")) {
+
+		if (cinfo->buildType == "mgpp") {
+		  coll_type += "1";
+		}
+		else {
+		  coll_type += "2";
+		}
+
+		coll_type += "&qto=";
+
+		// now we also want to check search types to set the qto arg 
+		if (cinfo->searchTypes.size() == 0) {
+		  coll_type += "3"; // default to 3 (= both)
+		} else {
+		  unsigned int search_types = 0;
+		  text_tarray::const_iterator type_here = cinfo->searchTypes.begin();
+		  text_tarray::const_iterator type_end = cinfo->searchTypes.end();
+		  
+		  while (type_here != type_end) {
+		    if (*type_here == "form") {
+		      search_types |= 2;
+		    } else if (*type_here == "plain") {
+		      search_types |= 1;
+		    }
+		    ++type_here;
+		  }
+		  coll_type += search_types;
+		  if (search_types == 3) {
+		    // both were specified, now need to look at the order to see which is the default
+		    type_here = cinfo->searchTypes.begin();
+		    if (*type_here == "form") { 
+		      coll_type += "&qt=1"; // set the default to form
+		    }
+		  }
+ 
+		}
+	      }
+	      else {
+		coll_type += "0";
+	      }
+	      text_t collectionname = cinfo->get_collectionmeta("collectionname", args["l"]);
+	      if (collectionname.empty()) {
+		collectionname = *collist_here;
+	      }
+	      
+	      comerror_t err;
+	      text_t optsite = g_EmptyText;
+	      text_t site_name = (*rprotolist_here).p->get_site_name (err);
+	      if (!site_name.empty()) { optsite = "site="+site_name+"&"; }
+	      
+	      text_t link = "_gwcgi_?"+optsite+"a=p&p=about&c=" + *collist_here + coll_type;
+	      link += "&l=" + args["l"] + "&w=" + args["w"];
+
+	      // We are "dynamically" overriding so to speak the
+	      // link to the collection aka receptionist.
+	      
+	      if (!cinfo->receptionist.empty()) 
+		 link = cinfo->receptionist;
+	      
+	      
+	      homeextra += "<option value=\"" + link + "\"";
+	      homeextra += ">" + collectionname + "</option>\n";
+	      	    
+	    }
+
+	    ++collist_here;
+	    }
+	    
+	  }
+      }
+	++rprotolist_here;
+    }
+    
+    }
+  homeextra += "</select>\n";
+  homeextra += "</form>\n";
+  
+  disp.setmacro ("homeextra", "home", homeextra); 
+}
+  
+// originally called set_homeextra_macro
+// this function displays the Greenstone
+// main page as usual with the graphics for
+// the collections.
+
+// Aly Dharshi
+// 11th July 2003
+
+void pageaction::home_images(displayclass &disp, recptprotolistclass *protos, 
+			     cgiargsclass &args, const recptconf &configinfo,
+			     ostream &logout) {
+  
+  text_t homeextra = "<center><table width=_pagewidth_><tr valign=top>\n";
+  bool found_valid_col = false;
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+
+      text_tarray collist;
+      comerror_t err;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+
+	int count = 0;
+	bool first = true;
+	while (collist_here != collist_end) {
+	  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
+	  
+	  if (cinfo != NULL) {
+	    if (cinfo->isPublic && (cinfo->buildDate > 0)) {
+
+	      text_t coll_type = "&ct=";
+	      if ((cinfo->buildType == "mgpp") || (cinfo->buildType == "lucene")) {
+
+		if (cinfo->buildType == "mgpp") {
+		  coll_type += "1";
+		}
+		else {
+		  coll_type += "2";
+		}
+
+		coll_type += "&qto=";
+
+		// now we also want to check search types to set the qto arg 
+		if (cinfo->searchTypes.size() == 0) {
+		  coll_type += "3"; // default to 3 (= both)
+		} else {
+		  unsigned int search_types = 0;
+		  text_tarray::const_iterator type_here = cinfo->searchTypes.begin();
+		  text_tarray::const_iterator type_end = cinfo->searchTypes.end();
+		  
+		  while (type_here != type_end) {
+		    if (*type_here == "form") {
+		      search_types |= 2;
+		    } else if (*type_here == "plain") {
+		      search_types |= 1;
+		    }
+		    ++type_here;
+		  }
+		  coll_type += search_types;
+		  if (search_types == 3) {
+		    // both were specified, now need to look at the order to see which is the default
+		    type_here = cinfo->searchTypes.begin();
+		    if (*type_here == "form") { 
+		      coll_type += "&qt=1"; // set the default to form
+		    }
+		  }
+ 
+		}
+	      }
+	      else {
+		coll_type += "0";
+	      }
+
+	      found_valid_col = true;
+	      text_t collectionname = *collist_here;
+	      text_t alt = cinfo->get_collectionmeta("collectionname", args["l"]);
+	      if (alt.empty()) {
+		alt = collectionname;
+	      }
+	      
+	      // url to image: try iconcollectionsmall, then iconcollection
+	      text_t iconurl = cinfo->get_collectionmeta("iconcollectionsmall", args["l"]);
+	      if (iconurl.empty()) {
+		iconurl = cinfo->get_collectionmeta("iconcollection", args["l"]);
+	      }
+	      
+	      if (!iconurl.empty()) {
+		
+		// check to see URL is local to colserver
+		text_t::iterator iconurl_head = iconurl.begin();
+		text_t iconhead = substr(iconurl_head,iconurl_head+16);
+		if (iconhead=="_httpcollection_") {
+		  
+		  // local and using _httpcollection_
+		  text_t icontail = substr(iconurl_head+16,iconurl.end());
+		  iconurl = "http://" + cinfo->httpdomain 
+		    + cinfo->httpprefix + "/collect/" 
+		    + *collist_here + "/" + icontail;
+		}
+		else if (iconurl[0]=='/') {
+		  
+		  // local but with full path
+		  iconurl = "http://" + cinfo->httpdomain + iconurl;
+		}
+		
+		collectionname 
+		  = "<img width=150 border=1 src=\"" + iconurl + "\" alt=\"" + alt + "\">";
+	      } else {
+		collectionname = alt;
+	      }
+	      
+	      if ((count%configinfo.HomePageCols == 0) && (!first))
+		homeextra += "</tr><tr valign=top>\n";
+	      
+	      comerror_t err;
+	      text_t optsite = g_EmptyText;
+	      text_t site_name = (*rprotolist_here).p->get_site_name (err);
+	      if (!site_name.empty()) { optsite = "site="+site_name+"&"; }
+
+	      text_t link = "<a href=\"_gwcgi_?"+optsite+"a=p&p=about&c=" + *collist_here + coll_type;
+	      link += "&l=" + args["l"] + "&w=" + args["w"] + "\">";
+	      
+	      if (!cinfo->receptionist.empty()) 
+		link = "<a href=\"" + cinfo->receptionist + "\">";
+	      
+	      homeextra += "<td>" + link + collectionname + "</a></td>\n";
+	      
+	      ++count;
+	      first = false;
+	    }
+	  }
+	  ++collist_here;
+	}
+
+	for (; count%configinfo.HomePageCols != 0; ++count) homeextra += "<td></td>\n";
+      }
+    }
+    homeextra += "</td></tr>\n<tr>\n";
+    ++rprotolist_here;
+  }
+
+  if (!found_valid_col) {
+    homeextra += "<td>No valid (i.e. built and public) collections are available</td>\n";
+  }
+  homeextra += "</tr></table></center>\n";
+  disp.setmacro ("homeextra", "home", homeextra); 
+}
+
+void pageaction::set_collectionlist_macro (displayclass &disp, 
+					   recptprotolistclass *protos, 
+					   cgiargsclass &args, 
+					   ostream &logout) {
+
+  text_t collectionlist;
+  int count = 0;
+  
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+
+      text_tarray collist;
+      comerror_t err;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+
+	while (collist_here != collist_end) {
+	  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
+	  
+	  if (cinfo != NULL) {
+	    if (cinfo->isPublic && (cinfo->buildDate > 0)) {
+
+	      ++count;
+
+	      text_t coll_type = "&ct=";
+
+	      if ((cinfo->buildType == "mgpp") || (cinfo->buildType == "lucene")) {
+
+		if (cinfo->buildType == "mgpp") {
+		  coll_type += "1";
+		}
+		else {
+		  coll_type += "2";
+		}
+
+		coll_type += "&qto=";
+
+		// now we also want to check search types to set the qto arg 
+		if (cinfo->searchTypes.size() == 0) {
+		  coll_type += "3"; // default to 2 (= both)
+		} else {
+		  int search_types = 0;
+		  text_tarray::const_iterator type_here = cinfo->searchTypes.begin();
+		  text_tarray::const_iterator type_end = cinfo->searchTypes.end();
+		  
+		  while (type_here != type_end) {
+		    if (*type_here == "form") {
+		      search_types |= 0x10;
+		    } else if (*type_here == "plain") {
+		      search_types |= 0x01;
+		    }
+		    ++type_here;
+		  }
+		  coll_type += search_types;
+ 
+		  if (search_types == 3) {
+		    // both were specified, now need to look at the order to see which is the default
+		    type_here = cinfo->searchTypes.begin();
+		    if (*type_here == "form") { 
+		      coll_type += "&qt=1"; // set the default to form
+		    }
+		  }
+		}
+	      }
+	      else {
+		coll_type += "0";
+	      }
+	      text_t collectionname = cinfo->get_collectionmeta("collectionname", args["l"]);
+	      if (collectionname.empty()) {
+		collectionname = *collist_here;
+	      }
+	      
+	      comerror_t err;
+	      text_t optsite = g_EmptyText;
+	      text_t site_name = (*rprotolist_here).p->get_site_name (err);
+	      if (!site_name.empty()) { optsite = "site="+site_name+"&"; }
+
+	      text_t link = "<a href=\"_gwcgi_?"+optsite+"a=p&p=about&c=" + *collist_here + coll_type+"\">";
+
+	      if (!cinfo->receptionist.empty()) 
+		link = "<a href=\"" + cinfo->receptionist + "\">";
+	      
+	     collectionlist += "<li>" + link + collectionname + "</a>\n";
+	    }
+	  }
+	  ++collist_here;
+	}
+      }
+    }
+    ++rprotolist_here;
+  }
+
+  if (count == 1) {
+    collectionlist = "<p>_text1coll_\n<ul>" +
+      collectionlist + "</ul>\n";
+  } else if (count > 1) {
+    collectionlist = "<p>_textmorecolls_(" + text_t(count) + 
+      ")\n<ul>" + collectionlist + "</ul>\n";
+  }
+
+  disp.setmacro ("collectionlist", "homehelp", collectionlist); 
+}
+
+void pageaction::set_documentation_macro (displayclass &disp) {
+
+  text_t documentation;
+  text_t docsdir = filename_cat(gsdlhome, "docs");
+  
+  if (file_exists(filename_cat(docsdir, "User.pdf"))) {
+    documentation += "<tr valign=middle><td><a href=\"_httpdocs_/User.pdf\">_iconpdf_"
+      "</a></td><td>_textuserguide_</td></tr>";
+  }
+  
+  if (file_exists(filename_cat(docsdir, "Install.pdf"))) {
+    documentation += "<tr valign=middle><td><a href=\"_httpdocs_/Install.pdf\">_iconpdf_"
+      "</a></td><td>_textinstallerguide_</td></tr>";
+  }
+  
+  if (file_exists(filename_cat(docsdir, "Develop.pdf"))) {
+    documentation += "<tr valign=middle><td><a href=\"_httpdocs_/Develop.pdf\">_iconpdf_"
+      "</a></td><td>_textdeveloperguide_</td></tr>";
+  }
+  
+  if (file_exists(filename_cat(docsdir, "Paper.pdf"))) {
+    documentation += "<tr valign=middle><td><a href=\"_httpdocs_/Paper.pdf\">_iconpdf_"
+      "</a></td><td>_textpaperguide_</td></tr>";
+  }
+  
+  if (file_exists(filename_cat(docsdir, "Organize.pdf"))) {
+    documentation += "<tr valign=middle><td><a href=\"_httpdocs_/Organize.pdf\">_iconpdf_"
+      "</a></td><td>_textorganizerguide_</td></tr>";
+  }
+
+  if (!documentation.empty()) {
+    disp.setmacro("documentation", "docs", "<p>\n<table border=0>\n" + documentation + "\n</table>\n");
+  }
+}
+
+void pageaction::set_macro_to_file_contents (displayclass &disp, const text_t &macroname,
+					     const text_t &packagename, const text_t &filename) {
+
+  text_t filecontent;
+  char *filenamec = filename.getcstr();
+  ifstream file_in (filenamec);
+  delete []filenamec;
+  if (file_in) {
+    char c;
+    file_in.get(c);
+    while (!file_in.eof ()) {
+      if (c == '\n') filecontent += "<br>";
+      filecontent.push_back(c);
+      file_in.get(c);
+    }
+    file_in.close();
+  }
+  disp.setmacro (macroname, packagename, dm_safe(filecontent));
+}
+
+void pageaction::set_language_encoding_macros(displayclass &disp, cgiargsclass &args,
+					      recptprotolistclass *protos, ColInfoResponse_t *cinfo,
+					      ostream &logout) {
+  // _languageoption_
+  // Create the "interface language" selection box for the preferences
+  // pages.  You can use something like "format PreferenceLanguages
+  // en|fr|zn" from within a collect.cfg file to use only a subset of
+  // the available languages for any given collection (for
+  // collection-specific preferences pages). This facility is kind of
+  // ugly though and should be replaced by something better when the
+  // configuration files are tidied up (as should all the other
+  // "format Preference..." options).
+  text_t &arg_l = args["l"];
+  const recptconf &configinfo = recpt->get_configinfo();
+  // put languages in another map to sort them by longname
+  text_tmap languages;
+  languageinfo_tmap::const_iterator thislang = configinfo.languages.begin();
+  languageinfo_tmap::const_iterator endlang = configinfo.languages.end();
+  while (thislang != endlang) {
+    languages[(*thislang).second.longname] = (*thislang).first;
+    ++thislang;
+  }
+  text_tmap::iterator tlang = languages.begin();
+  text_tmap::iterator elang = languages.end();
+
+  text_t languageoption;
+  bool collection_specific = false;
+
+  if (cinfo != NULL) {
+    text_tmap::const_iterator it = cinfo->format.find ("PreferenceLanguages");
+    if ((it != cinfo->format.end()) && (!(*it).second.empty())) {
+      collection_specific = true;
+      text_tset pref_langs;
+      splitchar ((*it).second.begin(), (*it).second.end(), '|', pref_langs);
+      if (pref_langs.size() > 1) {
+	while (tlang != elang) {
+	  if (pref_langs.find((*tlang).second) != pref_langs.end()) {
+	    languageoption += "<option value=\"" + (*tlang).second + "\"";
+	    if ((*tlang).second == arg_l) languageoption += " selected";
+	    languageoption += ">" + (*tlang).first + "</option>\n";
+	  }
+	  ++tlang;
+	}
+      }
+    }
+  }
+
+  if (!collection_specific) {
+    while (tlang != elang) {
+      languageoption += "<option value=\"" + (*tlang).second + "\"";
+      if ((*tlang).second == arg_l) languageoption += " selected";
+      languageoption += ">" + (*tlang).first + "</option>\n";
+      ++tlang;
+    }
+  }
+
+  if (!languageoption.empty()) {
+    languageoption = "<select name=\"l\" onChange=\"updatel();\">\n" + languageoption;
+    languageoption += "</select>\n";
+    disp.setmacro ("languageoption", args["p"], languageoption);
+  }
+
+  // _encodingoption_
+  // create the "encoding" selection box for the preferences page
+  if (configinfo.encodings.size() > 1) {
+    text_t &arg_w = args["w"];
+    text_t encodingoption;
+    text_tmap::const_iterator thisenc = configinfo.encodings.begin();
+    text_tmap::const_iterator endenc = configinfo.encodings.end();
+    while (thisenc != endenc) {
+      encodingoption += "<option value=\"" + (*thisenc).second + "\"";
+      if ((*thisenc).second == arg_w) encodingoption += " selected";
+      encodingoption += ">" + (*thisenc).first + "</option>\n";
+      ++thisenc;
+    }
+
+    encodingoption = "<select name=\"w\" onChange=\"updatew();\">\n" + encodingoption;
+    encodingoption += "</select>\n";
+    disp.setmacro ("encodingoption", args["p"], encodingoption);
+  } else if (configinfo.encodings.size() == 1) {
+    text_t encodingoption;
+    text_tmap::const_iterator thisenc = configinfo.encodings.begin();
+    encodingoption = (*thisenc).first;
+    disp.setmacro ("encodingoption", args["p"], encodingoption);
+  } else { // size == 0. shouldn't really happen, but allow it
+    disp.setmacro ("encodingoption", args["p"], "None");
+  }
+
+}
+
+void pageaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					 recptprotolistclass *protos, ostream &logout) {
+
+  // define_internal_macros sets the following macros:
+
+  // _numdocs_             the number of documents in the collection
+
+  // _builddate_           the date last built
+
+  // if page is "home"
+  // _homeextra_           this is the list of available collections and collection info
+  //                       to be displayed on the home page
+
+
+  // if page is "preferences"
+  // _collectionoption_    collections to search/browse (if cross-collection-searching is on)
+
+  // _htmloptions_         set to _htmloptionson_ if DocumentUseHTML is set
+
+  // _PreferencesDocsFromWeb_ set to 1 if corresponding format option is set
+
+
+  // if page is "preferences" or "homepref"
+  // _languageoption_      interface languages to select from (dependant on PreferenceLanguages)
+
+  // _encodingoption_      encodings to select from
+
+
+  // if page is "about"
+  // _textsubcollections_  the text on which subcollections make up the collection (if 
+  //                       cross-collection searching is being used
+
+  // _textbrowseoptions_   the 'how to find information' text in the about and help pages
+
+  // _numbrowseoptions_    the number of browsing options 
+
+  // _prefschanged_        will be set to _textprefschanged_ if the "set preferences" button
+  //                       was pressed
+
+  // _aboutqueryform_      will be set to "" if the collection isn't searchable
+
+  // if page is "help"
+  // _textbrowseoptions_   the 'how to find information' text in the about and help pages
+
+  // _numbrowseoptions_    the number of browsing options 
+
+  // _topicreadingdocs_    this section of the help text differs depending on what type of 
+  // _textreadingdocs_     collection it is (e.g. html collection, bibliographic collection etc.)
+  // _texthelpreadingdocs_ 
+
+  // if page is "home" or "homehelp"
+  // _textgocollector_     set to "" if collector is disabled in main.cfg
+  // _textgoadmin_         set to "" if status is disabled in main.cfg
+  // _textgotranslator_    set to "" if translator is disabled in main.cfg
+  // _textgogliapplet_     set to "" if gliapplet is disabled in main.cfg
+
+
+  // if page is "homehelp"
+  // _collectionlist_      list of available collections to be displayed on the homehelp page
+
+  
+  // if page is "docs"
+  // _documentation_       links to PDF documents if they're available
+
+
+  // if page is "bsummary"
+  // _importlog_           set to contents of collections import.log file
+  // _faillog_             set to contents of collections fail.log file
+
+  
+  if (recpt == NULL) {
+    logout << "ERROR (pageaction::define_internal_macros): This action does not contain\n"
+	   << "      information about any receptionists. The method set_receptionist was\n"
+	   << "      probably not called from the module which instantiated this action.\n";
+    return;
+  }
+
+  text_t &arg_p = args["p"];
+  text_t &arg_c = args["c"];
+  ColInfoResponse_t *cinfo = NULL;
+
+  recptproto* collectproto = protos->getrecptproto (arg_c, logout);
+  if (collectproto != NULL) {
+    cinfo = recpt->get_collectinfo_ptr (collectproto, arg_c, logout);
+    
+    disp.setmacro ("numdocs", displayclass::defaultpackage, cinfo->numDocs);
+    unsigned long current_time = time(NULL);
+    unsigned long builddate = (current_time - cinfo->buildDate) / 86400;
+    disp.setmacro ("builddate", displayclass::defaultpackage, builddate);
+    
+    text_t numbytes;
+    if ((cinfo->numBytes/(1024*1024)) > 1) {
+      numbytes = (text_t)(cinfo->numBytes/(1024*1024)) + " Mb";
+    } else if ((cinfo->numBytes/1024) > 1) {
+      numbytes = (text_t)(cinfo->numBytes/1024) + " kb";
+    } else {
+      numbytes = (text_t)cinfo->numBytes + " bytes";
+    }
+    disp.setmacro("numbytes", displayclass::defaultpackage, numbytes);
+  }
+
+  //setting _queryformcontent_ so that the query interface is consistent.
+  //also adding usability button if necessary
+  if (arg_p == "about") {
+    if (cinfo == NULL) {
+      disp.setmacro("cvariable", displayclass::defaultpackage, arg_c);
+      disp.setmacro("content", arg_p, "<p>_textbadcollection_<p>");
+      return;
+    }
+    else {
+
+      text_tmap::iterator check = cinfo->format.find("QueryInterface");
+      if(check != cinfo->format.end()){
+	if((*check).second=="DateSearch"){
+	  text_t current = "_datesearch_";
+	  disp.setmacro("optdatesearch","query",current);
+	}
+      }
+      check = cinfo->format.find("Usability");
+      if(check != cinfo->format.end()){
+	disp.setmacro("usability", displayclass::defaultpackage, "_imageusab_");
+	disp.setmacro("usabinterface", displayclass::defaultpackage, ("_usab"+(*check).second+"_"));
+	disp.setmacro("usabilityscript", displayclass::defaultpackage, "_usabshowscript_");
+      }
+    }
+  }
+  
+  
+  if (arg_p == "home" || arg_p == "homehelp") {
+    if (status_disabled) disp.setmacro ("textgoadmin", "home", "");
+    if (collector_disabled) disp.setmacro ("textgocollector", "home", "");
+    if (translator_disabled) disp.setmacro ("textgotranslator", "home", "");
+
+    if (arg_p == "home") {
+      homepagestyle (disp, protos, args, logout);
+    } else if (arg_p == "homehelp") {
+      set_collectionlist_macro (disp, protos, args, logout);
+    }
+
+  } else if (arg_p == "gli") {
+    if (gliapplet_disabled) disp.setmacro ("gliapplet", "gli", "");
+
+  } else if (arg_p == "homepref") {
+  
+    // set _languageoption_ and _encodingoption_
+    set_language_encoding_macros(disp, args, protos, cinfo, logout);
+
+  } else if (arg_p == "preferences") {
+  
+    if (cinfo == NULL) {
+      disp.setmacro("cvariable", displayclass::defaultpackage, arg_c);
+      disp.setmacro("content", arg_p, "<p>_textbadcollection_<p>");
+      return;
+    }
+
+    if (collectproto == NULL) {return;}
+    
+    // set _languageoption_ and _encodingoption_
+    set_language_encoding_macros(disp, args, protos, cinfo, logout);
+
+    // _collectionoption_
+    if ((args["ccs"] == "1") && (cinfo->ccsCols.size() > 1)) {
+      text_t collectionoption = "_textcollectionoption_";
+      text_tarray::const_iterator col_here = cinfo->ccsCols.begin();
+      text_tarray::const_iterator col_end = cinfo->ccsCols.end();
+      int count = 0;
+      while (col_here != col_end) {
+	text_t colname;
+	if (*col_here == arg_c) {
+	    colname = cinfo->get_collectionmeta("collectionname", args["l"]);
+	} else {
+	  ColInfoResponse_t *this_cinfo = recpt->get_collectinfo_ptr (collectproto, *col_here, logout);
+	  if (this_cinfo == NULL) {++col_here; continue;}
+	  colname = this_cinfo->get_collectionmeta("collectionname", args["l"]);
+	}
+	if (colname.empty()) {
+	  colname = *col_here;
+	}
+	++count;
+	collectionoption += "<input type=checkbox name=\"cc\" value=\"" + 
+	  *col_here + "\" onClick=\"updatecc(\'" + *col_here + "\');\"> " +
+	  colname + "<br>\n";
+	++col_here;
+      }
+      
+      if (count > 1)
+	disp.setmacro ("collectionoption", "preferences", collectionoption);
+    }
+
+    // _htmloptions_
+    
+    text_tmap::const_iterator it = cinfo->format.find ("DocumentUseHTML");
+    if ((it != cinfo->format.end()) && ((*it).second == "true")) {
+      disp.setmacro ("htmloptions", "preferences", "_htmloptionson_");
+
+
+      // _PreferenceDocsFromWeb_
+
+      it = cinfo->format.find ("PreferenceDocsFromWeb");
+      if ((it == cinfo->format.end()) || ((*it).second == "true"))
+	disp.setmacro ("PreferenceDocsFromWeb", "preferences", "1");
+    }
+
+    // _prefschanged_
+    if (!args["bp"].empty()) {
+      disp.setmacro ("prefschanged", "preferences", "_textprefschanged_");
+    }
+    
+  } else if (arg_p == "about" || arg_p == "help") {
+    if (collectproto == NULL) return;
+
+    comerror_t err;
+    bool has_search_button = true;
+    collectproto->is_searchable(args["c"], has_search_button, err, logout);
+    if (err != noError) has_search_button = true;
+    
+    // _textbrowseoptions_ and _numbrowseoptions_
+    
+    FilterResponse_t response;
+    text_tset metadata;
+    metadata.insert ("Title");
+    //****************
+    metadata.insert ("childtype");
+    //****************
+    bool getParents = false;
+    get_children ("", args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+
+    int numbrowseoptions = response.docInfo.size();
+    if (has_search_button) numbrowseoptions += 1;
+    disp.setmacro ("numbrowseoptions", "help", numbrowseoptions);
+
+    ResultDocInfo_tarray::iterator here = response.docInfo.begin();
+    ResultDocInfo_tarray::iterator end = response.docInfo.end();
+
+    text_t shorttext;
+    text_t longtext;
+    if (has_search_button) {
+      shorttext = "<ul><li>_textSearchshort_\n";
+      longtext = "_textSearchlong_";
+    }
+
+    // ********************************      
+    int classifiernumber = 0;
+    bool collage = false;
+
+    while (here != end) {
+      
+      ++classifiernumber;
+      text_t childtype = (*here).metadata["childtype"].values[0];
+      if (childtype == "Collage" && arg_p == "about") {
+	// get the classifier number
+	disp.setmacro ("classifier", "about", classifiernumber);
+	disp.setmacro ("aboutCollage", "about", "_collageapplet_");
+	collage = true;
+      }
+      ++here;
+    } 
+    if (! collage)
+      disp.setmacro ("aboutCollage", "about", "_collageempty_");
+	
+    // ********************************
+     
+    here = response.docInfo.begin();
+
+    while (here != end) {
+      
+      text_t title = (*here).metadata["Title"].values[0];
+    
+      text_t stext, ltext;
+      disp.expandstring ("help", "_text" + title + "short_", stext);
+      if (stext == ("_text" + title + "short_")) {
+	shorttext += "<li>_help:textdefaultshorttext_";
+	longtext += "_help:textdefaultlongtext_";
+      } else {
+	shorttext += "<li>_help:text" + title + "short_";
+	longtext += "_help:text" + title + "long_";
+      }
+
+      ++here;
+    }
+    shorttext += "</ul>\n";
+    if (response.docInfo.size() > 1) disp.setmacro ("textbrowseoptions", "help", shorttext + longtext);
+    else disp.setmacro ("textbrowseoptions", "help", longtext);
+
+    if (arg_p == "about") {
+
+      // _textsubcollections_
+      if (args["ccs"] == "1" && (cinfo->ccsCols.size() > 1)) {
+	text_t textsubcollections = "_textsubcols1_(" + text_t(cinfo->ccsCols.size()) + ")";
+	text_tarray::const_iterator here = cinfo->ccsCols.begin();
+	text_tarray::const_iterator end = cinfo->ccsCols.end();
+	bool first = true;
+	int count = 0;
+	while (here != end) {
+	  if (*here == arg_c) {
+	    if (!first) textsubcollections += "<br>";
+	    textsubcollections += "\n" + cinfo->get_collectionmeta("collectionname", args["l"]) + "\n";
+	  } else {
+	    ColInfoResponse_t *this_cinfo = recpt->get_collectinfo_ptr (collectproto, *here, logout);
+	    if (this_cinfo == NULL) {++here; continue;}
+	    if (!first) textsubcollections += "<br>";
+	    textsubcollections += "\n" + this_cinfo->get_collectionmeta("collectionname", args["l"]) + "\n";
+	  }
+	  ++count;
+	  first = false;
+	  ++here;
+	}
+	textsubcollections += "_textsubcols2_";
+	if (count > 1) {
+	  disp.setmacro ("textsubcollections", "about", textsubcollections);
+	}
+      }
+
+      comerror_t err;
+      bool issearchable = true;
+      collectproto->is_searchable(args["c"], issearchable, err, logout);
+      if (err != noError) issearchable = true;
+      outconvertclass t;
+      if (!issearchable) {
+	disp.setmacro ("aboutqueryform", "about", "");
+      }
+    }
+
+  } else if (arg_p == "docs") {
+
+    set_documentation_macro (disp);
+
+  } else if (arg_p == "bsummary" && !arg_c.empty()) {
+
+    set_macro_to_file_contents (disp, "importlog", "bsummary",
+				filename_cat(gsdlhome, "collect", arg_c, "etc", "import.log"));
+    set_macro_to_file_contents (disp, "faillog", "bsummary",
+				filename_cat(gsdlhome, "collect", arg_c, "etc", "fail.log"));
+  }
+}
+
+bool pageaction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/, 
+			    browsermapclass * /*browsers*/, displayclass &disp, 
+			    outconvertclass &outconvert, ostream &textout, 
+			    ostream &/*logout*/) {
+
+  text_t &arg_p = args["p"];
+
+  textout << outconvert << disp << ("_" + arg_p + ":header_\n")
+	  << ("_" + arg_p + ":content_\n")
+	  << ("_" + arg_p + ":footer_\n");
+
+  return true;
+}
+
+void pageaction::configure (const text_t &key, const text_tarray &cfgline) {
+  if ((key == "status") && (cfgline.size() == 1) && 
+      (cfgline[0] == "true" || cfgline[0] == "on" || cfgline[0] == "enabled")) {
+    status_disabled = false;
+  } else if ((key == "collector") && (cfgline.size() == 1) && 
+	     (cfgline[0] == "true" || cfgline[0] == "on" || cfgline[0] == "enabled")) {
+    collector_disabled = false;
+  } else if ((key == "translator") && (cfgline.size() == 1) && 
+	     (cfgline[0] == "true" || cfgline[0] == "on" || cfgline[0] == "enabled")) {
+    translator_disabled = false;
+  } else if ((key == "gliapplet") && (cfgline.size() == 1) && 
+	     (cfgline[0] == "true" || cfgline[0] == "on" || cfgline[0] == "enabled")) {
+    gliapplet_disabled = false;
+  }
+  else {
+    // call the parent class to deal with the things which
+    // are not dealt with here
+    action::configure (key, cfgline);
+  }
+}
+
+
+
+
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/pageaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/pageaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/pageaction.h	(revision 10506)
@@ -0,0 +1,103 @@
+/**********************************************************************
+ *
+ * pageaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef PAGEACTION_H
+#define PAGEACTION_H
+
+
+#include "gsdlconf.h"
+#include "action.h"
+#include "receptionist.h"
+
+
+class pageaction : public action {
+  
+protected:
+  receptionist *recpt;
+
+  text_tset classify_meta;
+
+public:
+  pageaction ();
+  virtual ~pageaction ();
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  text_t get_action_name () {return "p";}
+  
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      recptprotolistclass *protos, ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response,text_t &response_data, 
+			 ostream &logout);
+
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+ protected:
+  
+  void home_images (displayclass &disp, recptprotolistclass *protos, 
+		   cgiargsclass &args, const recptconf &configinfo, ostream &logout);
+  
+  void home_pulldown (displayclass &disp, recptprotolistclass *protos, 
+		      cgiargsclass &args, const recptconf &configinfo, ostream &logout);
+  
+  void homepagestyle (displayclass &disp, recptprotolistclass *protos, 
+		      cgiargsclass &args, ostream &logout);
+  
+
+  
+  void set_collectionlist_macro (displayclass &disp, recptprotolistclass *protos, 
+				 cgiargsclass &args, ostream &logout);
+
+  void set_documentation_macro (displayclass &disp);
+
+  void set_macro_to_file_contents (displayclass &disp, const text_t &macroname,
+				   const text_t &packagename, const text_t &filename);
+
+  void set_language_encoding_macros(displayclass &disp, cgiargsclass &args,
+				    recptprotolistclass *protos, ColInfoResponse_t *cinfo,
+				    ostream &logout);
+
+
+  
+  bool status_disabled;
+  bool collector_disabled;
+  bool translator_disabled;
+  bool gliapplet_disabled;
+
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/pagedbrowserclass.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/pagedbrowserclass.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/pagedbrowserclass.cpp	(revision 10506)
@@ -0,0 +1,205 @@
+/**********************************************************************
+ *
+ * pagedbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_PAGED_BROWSER
+
+#include "pagedbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+#include "gsdltools.h"
+
+pagedbrowserclass::pagedbrowserclass () {
+}
+
+pagedbrowserclass::~pagedbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t pagedbrowserclass::get_browser_name () {
+  return "Paged";
+}
+
+browserclass* pagedbrowserclass::clone()
+{
+  return new pagedbrowserclass();
+}
+
+void pagedbrowserclass::load_metadata_defaults (text_tset &metadata) {
+  metadata.insert ("Title");
+}
+
+// if the "gp" (go to page) argument is set we need to set
+// the "d" argument to the corresponding page
+// also want to set "d" argument to first child if we're at
+// an 'Invisible' top level
+void pagedbrowserclass::processOID (cgiargsclass &args, recptproto *collectproto,
+                                    ostream &logout) {
+
+  text_t &arg_d = args["d"];
+  text_t &arg_gp = args["gp"];
+  text_tset metadata;
+  bool getParents = false;
+  FilterResponse_t response;
+
+  if ((!arg_d.empty()) && (!arg_gp.empty()) && (is_number (arg_gp))) {
+    text_t top;
+    get_top (arg_d, top);
+    metadata.insert ("Title");
+    get_children (top, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+    ResultDocInfo_tarray::iterator dochere = response.docInfo.begin();
+    ResultDocInfo_tarray::iterator docend = response.docInfo.end();
+    while (dochere != docend) {
+      if ((*dochere).metadata["Title"].values[0] == arg_gp) {
+        arg_d = (*dochere).OID;
+        break;
+      }
+      ++dochere;
+    }
+
+  } else if (!arg_d.empty() && is_top(arg_d)) { // if top level doc, check if not invisible
+    metadata.insert("thistype");
+    if (get_info(arg_d, args["c"], args["l"], metadata, getParents, collectproto, response, logout)) {
+      text_t type = response.docInfo[0].metadata["thistype"].values[0];
+      if (type=="Invisible") { // display first child
+        arg_d = arg_d + ".fc";
+      }
+    }
+  }
+}
+
+int pagedbrowserclass::output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+					     const text_t &/*collection*/, int /*colnumber*/, 
+					     format_t * /*formatlistptr*/, bool /*use_table*/, 
+					     text_tset &/*metadata*/, bool &/*getParents*/,
+					     recptproto * /*collectproto*/, displayclass &disp, 
+					     outconvertclass &outconvert, ostream &textout, 
+					     ostream &/*logout*/) {
+
+  // this browser class only handles document levels
+  if (args["d"].empty()) return 0;
+
+  if (section.OID != args["d"]) {
+    text_t httpprevarrow = "_httpdocument_&cl=" + args["cl"] + "&d=" + dm_safe(section.OID);
+    text_t parentarrow = "<a href=\"" + httpprevarrow + "\">_iconprev_</a>\n";
+    disp.setmacro ("httpprevarrow", "document", httpprevarrow);
+    disp.setmacro ("parentarrow", "document", parentarrow);
+    return 0;
+  }
+
+  // must be at top level to get to here!
+  textout << outconvert << disp << "<b>" << section.metadata["Title"].values[0] 
+	  << "_document:textintro_</b>\n";
+  
+  return 0;
+}
+
+int pagedbrowserclass::output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+					     const text_t &/*collection*/, int /*colnumber*/, 
+					     format_t * /*formatlistptr*/, bool /*use_table*/, 
+					     text_tset &/*metadata*/, bool &/*getParents*/,
+					     recptproto * /*collectproto*/, displayclass &disp, 
+					     outconvertclass &outconvert, ostream &textout, 
+					     ostream &/*logout*/) {
+
+  text_t &arg_d = args["d"];
+
+  // this browser class only handles document levels
+  if (arg_d.empty()) return 0;
+
+  text_t previousOID, previoustitle, nextOID, nexttitle;
+  text_t prevarrow, nextarrow, httpprevarrow, httpnextarrow;
+  bool found = false;
+
+  // this should be our list of pages
+
+  ResultDocInfo_tarray::iterator thissection = sections.docInfo.begin();
+  ResultDocInfo_tarray::iterator endsection = sections.docInfo.end();
+
+  while (thissection != endsection) {
+    if (arg_d == (*thissection).OID) {
+      found = true;
+      textout << outconvert << disp 
+	      << "<table><tr valign=top><td colspan=3><center><b>_page_"
+	      << (*thissection).metadata["Title"].values[0] << "</b>\n";
+      if (thissection != sections.docInfo.begin()) {
+	previousOID = (*(thissection-1)).OID;
+	previoustitle = (*(thissection-1)).metadata["Title"].values[0];
+      } else {
+	prevarrow = "_document:parentarrow_";
+      }
+
+      if ((thissection+1) != endsection) {
+	nextOID = (*(thissection+1)).OID;
+	nexttitle = (*(thissection+1)).metadata["Title"].values[0];
+      }
+      break;
+    }
+    ++thissection;
+  }
+
+  if (!found) {
+    textout << outconvert << disp 
+	    << "<table><tr valign=top> <td colspan=3><center>\n";
+  }
+  int numpages = sections.docInfo.size();
+  textout << outconvert << disp 
+	  << ("_document:textnumpages_(" + text_t(numpages) + ")</center></td></tr>\n");
+
+  disp.setmacro ("numpages", "document", numpages);
+
+  if (!found) {
+    httpnextarrow = "_httpdocument_&cl=" + args["cl"] + "&d=" + sections.docInfo[0].OID;
+    nextarrow = "<a href=\"" + httpnextarrow + "\">" + 
+      sections.docInfo[0].metadata["Title"].values[0] + "_iconnext_</a>\n";
+
+  } else {
+    if (!previousOID.empty()) {
+      httpprevarrow = "_httpdocument_&cl=" + args["cl"] + "&d=" + dm_safe(previousOID);
+      prevarrow = "<a href=\"" + httpprevarrow + "\">_iconprev_" + previoustitle + "</a>\n";
+    }
+    if (!nextOID.empty()) {
+      httpnextarrow = "_httpdocument_&cl=" + args["cl"] + "&d=" + dm_safe(nextOID);
+      nextarrow = "<a href=\"" + httpnextarrow + "\">" + nexttitle + "_iconnext_</a>\n";
+    }
+  }
+
+  if (!httpprevarrow.empty()) disp.setmacro ("httpprevarrow", "document", httpprevarrow);
+  if (!httpnextarrow.empty()) disp.setmacro ("httpnextarrow", "document", httpnextarrow);
+
+  if (!prevarrow.empty()) disp.setmacro ("prevarrow", "document", prevarrow);
+  if (!nextarrow.empty()) disp.setmacro ("nextarrow", "document", nextarrow);
+
+
+  textout << outconvert << disp << "<tr valign=middle>\n"
+	  << "<td align=right>" << prevarrow << "</td>\n"
+	  << "<td align=center valign=top>_document:gotoform_</td>"
+	  << "<td align=left>" << nextarrow << "</td>\n"
+	  << "</tr></table>\n";
+
+  return 0;
+}
+
+#endif //GSDL_USE_PAGED_BROWSER
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/pagedbrowserclass.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/pagedbrowserclass.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/pagedbrowserclass.h	(revision 10506)
@@ -0,0 +1,68 @@
+/**********************************************************************
+ *
+ * pagedbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_PAGED_BROWSER
+
+#ifndef PAGEDBROWSERCLASS_H
+#define PAGEDBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class pagedbrowserclass : public browserclass {
+protected:
+
+public:
+
+  pagedbrowserclass ();
+  virtual ~pagedbrowserclass ();
+
+  // returns the name that specifies the browserclass type
+  virtual text_t get_browser_name ();
+
+  virtual browserclass* clone();
+
+  void load_metadata_defaults (text_tset &metadata);
+
+  virtual void processOID (cgiargsclass &args, recptproto *collectproto,
+			   ostream &logout);
+
+
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+};
+
+#endif //!PAGEDBROWSERCLASS_H
+#endif //GSDL_USE_PAGED_BROWSER
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/parse.fl
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/parse.fl	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/parse.fl	(revision 10506)
@@ -0,0 +1,112 @@
+/* This is the lexical analyser - it returns tokens to the parsers.
+   This is used by both parsers - one for the build-time config files
+   and one for the run-time config files. Note the included file "parse.h"
+   is a symlink to the relevant header file. */
+
+%{
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/*#define YYSTYPE char * - YYSTYPE is defined in zparse.tab.h */
+#include "zparse.tab.h"
+
+/* forward declarations for std functions not picked up. */
+/*int fileno(FILE *);*/
+/*char *strdup(char *);*/
+
+int lineno=1;
+%}
+
+%option noyywrap
+
+COMMENT  \#.*(\n|\r)
+
+%x  STRINGCOND
+%%
+	char *string;
+	int string_len;
+
+{COMMENT}		lineno++;/*yylval.string=yytext;*/yyleng=0;
+,			return (',');
+:			return (':');
+\_			return ('_');
+\[GSDL[0-9]+\.[0-9]+\] yylval.string=yytext;return(GSDLVERSION);
+\[General\]		return (GENERAL_SECTION);
+\[Search\ [fF]ields\]	return (SEARCH_SECTION);
+\[Browse\ [fF]ields\]	return (BROWSE_SECTION);
+\[Macros\]		return (MACROS_SECTION);
+maintainer		return (MAINTAINER);
+Languages		return(LANGUAGES);
+About			return(ABOUT);
+Browse			return(BROWSE);
+Date[lL]ist		return(DATELIST);
+Document[aA]rrows[bB]ottom return(DOCUMENTARROWSBOTTOM);
+Document[bB]uttons	return(DOCUMENTBUTTONS);
+Document[hH]eader	return(DOCUMENTHEADER);
+Document[iI]mages	return(DOCUMENTIMAGES);
+Document[tT]ext		return(DOCUMENTTEXT);
+Icon[lL]ink		return(ICONLINK);
+List			return(LIST);
+Format			return(FORMAT);
+Name			return(NAME);
+Search[tT]ext		return(SEARCHTEXT);
+Section[lL]ist		return(SECTIONLIST);
+Sorted[lL]ist		return(SORTEDLIST);
+Sorted[sS]ection[lL]ist	return(SORTEDSECTIONLIST);
+Text[lL]ink		return(TEXTLINK);
+Type			return(TYPE);
+public			return (PUBLIC);
+true			return (TRUE);
+false			return (FALSE);
+^document		return (DOCUMENT);
+^section		return (SECTION);
+[iI]con			return (ICON);
+[sS]mall[iI]con		return (SMALLICON);
+\"			{string=NULL;BEGIN(STRINGCOND);}
+<STRINGCOND>{
+  ([^\"\\\n])*		{/* append this to our current string EXC NEWLINE */
+			if (string==NULL) string_len=0; else
+			string_len=strlen(string);
+			string=realloc(string,string_len+strlen(yytext)+1);
+			/* +1 is for trailing \0 */
+			strcpy(string+string_len,yytext);
+			}
+  ([^\"\\])*\n		{/* append this to our current string - INC NEWLINE */
+			lineno++;
+			if (string==NULL) string_len=0; else
+			string_len=strlen(string);
+			string=realloc(string,string_len+strlen(yytext)+1);
+			/* +1 is for trailing \0 */
+			strcpy(string+string_len,yytext);
+			}
+  "\\"\"		|
+  \"\"		{       /*replace quoted quote with one quote*/
+			string_len=strlen(string);
+			string=realloc(string,string_len+2);
+			string[string_len]='\"';
+			string[string_len+1]='\0';
+			}
+  \"		{
+			BEGIN(INITIAL);
+			yylval.string=string;
+			return(STRING);
+			  /* note that the string may have long bits of 
+			     whitespace in it that we could remove. */
+			}
+}
+[[:alnum:]@\.-]+	yylval.string=strdup(yytext);return (DATA);
+(" "|\t)		;
+(\n|\r)			lineno++;
+%%
+/******** deleted rules: *******
+en			return(EN);
+fr			return(FR);
+mi			return(MI);
+zh			return(ZH);
+de			return(DE);
+***************/
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/parse.yy.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/parse.yy.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/parse.yy.c	(revision 10506)
@@ -0,0 +1,1955 @@
+#line 2 "parse.yy.c"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ * 	if ( condition_holds )
+ *		yyless( 5 );
+ *	else
+ *		do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+	};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+
+#define yywrap() 1
+#define YY_SKIP_YYWRAP
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 46
+#define YY_END_OF_BUFFER 47
+static yyconst short int yy_accept[274] =
+    {   0,
+        0,    0,   38,   38,   47,   46,   44,   45,   37,   46,
+        2,   43,    3,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   46,    4,   43,   43,   43,   43,   43,   43,
+       43,   43,   38,   39,   42,   46,    0,    1,    1,   43,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,    0,    0,    0,    0,   43,   43,
+       43,   43,   43,   43,   43,   38,   39,    0,   41,   40,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,    0,    0,    0,    0,    0,
+       43,   43,   43,   43,   43,   43,   43,   43,   43,   43,
+
+       43,   43,   35,   43,   21,   23,   43,   43,   43,   43,
+       43,   29,    0,    0,    0,    0,    0,   43,   35,   43,
+       43,   31,   43,   43,   12,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,    0,    0,    0,    0,
+        0,   32,   43,   43,   43,   43,   13,   43,   43,   22,
+       43,   43,   43,   43,   43,   43,   43,    0,    0,    0,
+        0,    0,   43,   30,   43,   43,   43,   43,   43,   43,
+       43,   43,   43,   43,   43,   43,    0,    0,    0,    0,
+        0,   43,   43,   34,   14,   43,   20,   43,   43,   43,
+       43,   43,   43,   28,    0,    0,    0,    9,    0,   43,
+
+       33,   43,   43,   43,   43,   43,   11,   43,   43,   36,
+       43,   43,    0,    5,    6,    0,   43,   43,   43,   43,
+       43,   43,   24,   43,   26,   43,    0,    0,   10,   43,
+       43,   43,   43,   43,   25,   43,    0,    0,   43,   43,
+       43,   43,   19,   43,    0,    0,   43,   43,   43,   43,
+       43,    0,    0,   43,   43,   17,   18,   43,    0,    0,
+       43,   16,   43,    8,    7,   43,   43,   43,   27,   43,
+       43,   15,    0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    5,    1,    6,    7,    1,    1,    1,    1,    1,
+        1,    1,    1,    8,    9,   10,    1,   11,   11,   11,
+       11,   11,   11,   11,   11,   11,   11,   12,    1,    1,
+        1,    1,    1,    9,   13,   14,    9,   15,    9,   16,
+       17,   18,   19,    9,    9,   20,   21,   22,    9,    9,
+        9,    9,   23,   24,    9,    9,    9,    9,    9,    9,
+       25,   26,   27,    1,   28,    1,   29,   30,   31,   32,
+
+       33,   34,   35,   36,   37,    9,   38,   39,   40,   41,
+       42,   43,    9,   44,   45,   46,   47,    9,   48,   49,
+       50,    9,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[51] =
+    {   0,
+        1,    1,    1,    1,    1,    2,    1,    1,    3,    3,
+        3,    1,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    1,    2,    1,    1,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3
+    } ;
+
+static yyconst short int yy_base[279] =
+    {   0,
+        0,   19,   49,   50,  331,  332,  332,  332,  332,   54,
+      332,    0,  332,  300,  285,   25,  286,  296,   31,  297,
+       29,   28,   49,  332,  296,  293,  294,  275,  281,  276,
+      277,   40,  315,  314,  310,  309,   78,  332,   80,    0,
+      272,  271,  266,  280,  266,  267,  267,  262,  266,   48,
+      276,  260,  254,  259,  257,   62,  271,  266,  259,  255,
+      259,  265,  247,  262,  261,  288,  287,  286,  332,  332,
+      241,  239,  253,  238,  244,  242,  247,  235,  247,  235,
+      232,  238,  230,  229,  241,  231,  257,  230,  239,  240,
+      223,  226,  225,  226,  231,  216,  216,  215,  215,   54,
+
+      219,  229,   66,  210,    0,    0,  225,  218,  215,  220,
+       67,    0,  204,  231,  217,  205,  204,  214,    0,  200,
+      208,    0,  204,  206,    0,  209,  204,  207,  193,  201,
+      208,  200,  193,   70,  202,  196,  187,  220,  186,  187,
+      197,    0,  198,  195,  192,  182,    0,  178,  181,    0,
+      180,  185,   64,  178,  187,   74,  176,  183,   80,  186,
+      169,  177,  175,    0,  170,  169,  163,  162,  169,  173,
+      172,   72,  162,  166,  169,  163,  195,  188,  159,  170,
+      191,  154,  148,    0,    0,  107,    0,  148,  143,  154,
+      149,  144,  157,    0,   80,   88,  160,  332,   82,  153,
+
+        0,  141,  137,  150,  142,  148,    0,  134,  134,    0,
+      132,  131,  139,  332,  332,  138,  130,  129,  126,  142,
+      141,  120,    0,  122,    0,  130,  133,  131,    0,  119,
+      106,  119,  115,  103,    0,  106,  108,  107,   97,  100,
+      108,  107,    0,   98,  106,  103,   89,   92,   88,   85,
+       83,   84,   83,   87,   82,    0,    0,   87,   96,   91,
+       70,    0,   64,  332,  332,   62,   58,   56,    0,   58,
+       25,    0,  332,  153,  156,   56,  159,  162
+    } ;
+
+static yyconst short int yy_def[279] =
+    {   0,
+      273,    1,  274,  274,  273,  273,  273,  273,  273,  275,
+      273,  276,  273,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  273,  273,  276,  276,  276,  276,  276,  276,
+      276,  276,  277,  278,  273,  273,  275,  273,  275,  276,
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  273,  273,  273,  273,  276,  276,
+      276,  276,  276,  276,  276,  277,  278,  278,  273,  273,
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  276,  273,  273,  273,  273,  273,
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  273,  273,  273,  273,  273,  276,  276,  276,
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  276,  276,  273,  273,  273,  273,
+      273,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  276,  276,  276,  273,  273,  273,
+      273,  273,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  276,  276,  273,  273,  273,  273,
+      273,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  276,  276,  273,  273,  273,  273,  273,  276,
+
+      276,  276,  276,  276,  276,  276,  276,  276,  276,  276,
+      276,  276,  273,  273,  273,  273,  276,  276,  276,  276,
+      276,  276,  276,  276,  276,  276,  273,  273,  276,  276,
+      276,  276,  276,  276,  276,  276,  273,  273,  276,  276,
+      276,  276,  276,  276,  273,  273,  276,  276,  276,  276,
+      276,  273,  273,  276,  276,  276,  276,  276,  273,  273,
+      276,  276,  276,  273,  273,  276,  276,  276,  276,  276,
+      276,  276,    0,  273,  273,  273,  273,  273
+    } ;
+
+static yyconst short int yy_nxt[383] =
+    {   0,
+        6,    7,    8,    8,    7,    9,   10,   11,   12,   12,
+       12,   13,   14,   15,   16,   17,   12,   12,   18,   19,
+       12,   20,   21,   22,   23,    6,    6,   24,   12,   12,
+       12,   12,   12,   25,   12,   12,   26,   12,   12,   27,
+       12,   12,   28,   12,   29,   30,   12,   12,   12,   12,
+       31,   34,   34,   43,   35,   35,   38,   39,   40,   47,
+       53,   50,   55,   32,  272,   56,   44,   48,   51,   57,
+       52,   58,   65,  127,   36,   36,   80,   54,   81,   51,
+       38,   39,   38,   39,   87,  130,  136,  171,  155,  178,
+      159,  190,  127,  174,   88,  213,  175,  216,  196,  271,
+
+      261,  270,  258,  269,  130,  136,  155,  268,  267,  171,
+      190,  266,  174,  213,  214,  216,  261,  265,  175,  202,
+      203,  258,  264,  263,  204,  205,  262,  260,  259,  257,
+      206,  256,  255,  254,  253,  202,  203,  252,  251,  250,
+      249,  248,  204,  205,  247,  246,  245,  244,  243,  242,
+      241,  240,  206,   33,   33,   33,   37,   37,   37,   66,
+      239,   66,   68,  238,   68,  237,  236,  235,  234,  233,
+      232,  231,  230,  229,  228,  227,  226,  225,  224,  223,
+      222,  221,  220,  219,  218,  217,  215,  212,  211,  210,
+      209,  208,  207,  201,  200,  199,  198,  197,  196,  195,
+
+      194,  193,  192,  191,  189,  188,  187,  186,  185,  184,
+      183,  182,  181,  180,  179,  177,  176,  173,  172,  170,
+      169,  168,  167,  166,  165,  164,  163,  162,  161,  160,
+      159,  158,  157,  156,  154,  153,  152,  151,  150,  149,
+      148,  147,  146,  145,  144,  143,  142,  141,  140,  139,
+      138,  137,  135,  134,  133,  132,  131,  129,  128,  126,
+      125,  124,  123,  122,  121,  120,  119,  118,  117,  116,
+      115,  114,  113,  112,  111,  110,  109,  108,  107,  106,
+      105,  104,  103,  102,  101,  100,   99,   98,   67,   67,
+       67,   97,   96,   95,   94,   93,   92,   91,   90,   89,
+
+       86,   85,   84,   83,   82,   79,   78,   77,   76,   75,
+       74,   73,   72,   71,   70,   69,   67,   67,   64,   63,
+       51,   62,   61,   60,   59,   49,   46,   45,   42,   41,
+      273,    5,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273
+    } ;
+
+static yyconst short int yy_chk[383] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        2,    3,    4,   16,    3,    4,   10,   10,  276,   19,
+       22,   21,   23,    2,  271,   23,   16,   19,   21,   23,
+       21,   23,   32,  100,    3,    4,   50,   22,   50,   32,
+       37,   37,   39,   39,   56,  103,  111,  153,  134,  159,
+      159,  172,  100,  156,   56,  195,  156,  199,  196,  270,
+
+      254,  268,  251,  267,  103,  111,  134,  266,  263,  153,
+      172,  261,  156,  195,  196,  199,  254,  260,  156,  186,
+      186,  251,  259,  258,  186,  186,  255,  253,  252,  250,
+      186,  249,  248,  247,  246,  186,  186,  245,  244,  242,
+      241,  240,  186,  186,  239,  238,  237,  236,  234,  233,
+      232,  231,  186,  274,  274,  274,  275,  275,  275,  277,
+      230,  277,  278,  228,  278,  227,  226,  224,  222,  221,
+      220,  219,  218,  217,  216,  213,  212,  211,  209,  208,
+      206,  205,  204,  203,  202,  200,  197,  193,  192,  191,
+      190,  189,  188,  183,  182,  181,  180,  179,  178,  177,
+
+      176,  175,  174,  173,  171,  170,  169,  168,  167,  166,
+      165,  163,  162,  161,  160,  158,  157,  155,  154,  152,
+      151,  149,  148,  146,  145,  144,  143,  141,  140,  139,
+      138,  137,  136,  135,  133,  132,  131,  130,  129,  128,
+      127,  126,  124,  123,  121,  120,  118,  117,  116,  115,
+      114,  113,  110,  109,  108,  107,  104,  102,  101,   99,
+       98,   97,   96,   95,   94,   93,   92,   91,   90,   89,
+       88,   87,   86,   85,   84,   83,   82,   81,   80,   79,
+       78,   77,   76,   75,   74,   73,   72,   71,   68,   67,
+       66,   65,   64,   63,   62,   61,   60,   59,   58,   57,
+
+       55,   54,   53,   52,   51,   49,   48,   47,   46,   45,
+       44,   43,   42,   41,   36,   35,   34,   33,   31,   30,
+       29,   28,   27,   26,   25,   20,   18,   17,   15,   14,
+        5,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273,  273,  273,  273,  273,  273,  273,  273,  273,
+      273,  273
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "parse.fl"
+#define INITIAL 0
+/* This is the lexical analyser - it returns tokens to the parsers.
+   This is used by both parsers - one for the build-time config files
+   and one for the run-time config files. Note the included file "parse.h"
+   is a symlink to the relevant header file. */
+#line 7 "parse.fl"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/*#define YYSTYPE char * - YYSTYPE is defined in zparse.tab.h */
+#include "zparse.tab.h"
+
+/* forward declarations for std functions not picked up. */
+/*int fileno(FILE *);*/
+/*char *strdup(char *);*/
+
+int lineno=1;
+#define STRINGCOND 1
+
+#line 559 "parse.yy.c"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	if ( yyleng > 0 ) \
+		yy_current_buffer->yy_at_bol = \
+				(yytext[yyleng - 1] == '\n'); \
+	YY_USER_ACTION
+
+YY_DECL
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 26 "parse.fl"
+
+	char *string;
+	int string_len;
+
+#line 718 "parse.yy.c"
+
+	if ( yy_init )
+		{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yy_start )
+			yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! yy_current_buffer )
+			yy_current_buffer =
+				yy_create_buffer( yyin, YY_BUF_SIZE );
+
+		yy_load_buffer_state();
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+		yy_current_state += YY_AT_BOL();
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 274 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 332 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+
+do_action:	/* This label is used only to access EOF actions. */
+
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 30 "parse.fl"
+lineno++;/*yylval.string=yytext;*/yyleng=0;
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 31 "parse.fl"
+return (',');
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 32 "parse.fl"
+return (':');
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 33 "parse.fl"
+return ('_');
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 34 "parse.fl"
+yylval.string=yytext;return(GSDLVERSION);
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 35 "parse.fl"
+return (GENERAL_SECTION);
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 36 "parse.fl"
+return (SEARCH_SECTION);
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 37 "parse.fl"
+return (BROWSE_SECTION);
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 38 "parse.fl"
+return (MACROS_SECTION);
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 39 "parse.fl"
+return (MAINTAINER);
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 40 "parse.fl"
+return(LANGUAGES);
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 41 "parse.fl"
+return(ABOUT);
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 42 "parse.fl"
+return(BROWSE);
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 43 "parse.fl"
+return(DATELIST);
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 44 "parse.fl"
+return(DOCUMENTARROWSBOTTOM);
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 45 "parse.fl"
+return(DOCUMENTBUTTONS);
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 46 "parse.fl"
+return(DOCUMENTHEADER);
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 47 "parse.fl"
+return(DOCUMENTIMAGES);
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 48 "parse.fl"
+return(DOCUMENTTEXT);
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 49 "parse.fl"
+return(ICONLINK);
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 50 "parse.fl"
+return(LIST);
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 51 "parse.fl"
+return(FORMAT);
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 52 "parse.fl"
+return(NAME);
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 53 "parse.fl"
+return(SEARCHTEXT);
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 54 "parse.fl"
+return(SECTIONLIST);
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 55 "parse.fl"
+return(SORTEDLIST);
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 56 "parse.fl"
+return(SORTEDSECTIONLIST);
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 57 "parse.fl"
+return(TEXTLINK);
+	YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 58 "parse.fl"
+return(TYPE);
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 59 "parse.fl"
+return (PUBLIC);
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 60 "parse.fl"
+return (TRUE);
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 61 "parse.fl"
+return (FALSE);
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 62 "parse.fl"
+return (DOCUMENT);
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 63 "parse.fl"
+return (SECTION);
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 64 "parse.fl"
+return (ICON);
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 65 "parse.fl"
+return (SMALLICON);
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 66 "parse.fl"
+{string=NULL;BEGIN(STRINGCOND);}
+	YY_BREAK
+
+case 38:
+YY_RULE_SETUP
+#line 68 "parse.fl"
+{/* append this to our current string EXC NEWLINE */
+			if (string==NULL) string_len=0; else
+			string_len=strlen(string);
+			string=realloc(string,string_len+strlen(yytext)+1);
+			/* +1 is for trailing \0 */
+			strcpy(string+string_len,yytext);
+			}
+	YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 75 "parse.fl"
+{/* append this to our current string - INC NEWLINE */
+			lineno++;
+			if (string==NULL) string_len=0; else
+			string_len=strlen(string);
+			string=realloc(string,string_len+strlen(yytext)+1);
+			/* +1 is for trailing \0 */
+			strcpy(string+string_len,yytext);
+			}
+	YY_BREAK
+case 40:
+#line 84 "parse.fl"
+case 41:
+YY_RULE_SETUP
+#line 84 "parse.fl"
+{       /*replace quoted quote with one quote*/
+			string_len=strlen(string);
+			string=realloc(string,string_len+2);
+			string[string_len]='\"';
+			string[string_len+1]='\0';
+			}
+	YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 90 "parse.fl"
+{
+			BEGIN(INITIAL);
+			yylval.string=string;
+			return(STRING);
+			  /* note that the string may have long bits of 
+			     whitespace in it that we could remove. */
+			}
+	YY_BREAK
+
+case 43:
+YY_RULE_SETUP
+#line 98 "parse.fl"
+yylval.string=strdup(yytext);return (DATA);
+	YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 99 "parse.fl"
+;
+	YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 100 "parse.fl"
+lineno++;
+	YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 101 "parse.fl"
+ECHO;
+	YY_BREAK
+#line 1055 "parse.yy.c"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(STRINGCOND):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between yy_current_buffer and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yy_n_chars = yy_current_buffer->yy_n_chars;
+			yy_current_buffer->yy_input_file = yyin;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state();
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer() )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap() )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p =
+					yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yy_c_buf_p =
+				&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+	{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( yy_current_buffer->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+		{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset =
+				(int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yy_flex_realloc( (void *) b->yy_ch_buf,
+							 b->yy_buf_size + 2 );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+						number_to_move - 1;
+#endif
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read );
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	if ( yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+	}
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+	yy_current_state += YY_AT_BOL();
+
+	for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 274 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+	}
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+	{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 274 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 273);
+
+	return yy_is_jam ? 0 : yy_current_state;
+	}
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+	{
+	register char *yy_cp = yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yy_hold_char;
+
+	if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest = &yy_current_buffer->yy_ch_buf[
+					yy_current_buffer->yy_buf_size + 2];
+		register char *source =
+				&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while ( source > yy_current_buffer->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+	}
+#endif	/* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+	{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			/* This was really a NUL. */
+			*yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch ( yy_get_next_buffer() )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin );
+
+					/* fall through */
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap() )
+						return EOF;
+
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yy_c_buf_p = yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+	yy_current_buffer->yy_at_bol = (c == '\n');
+
+	return c;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+	{
+	if ( ! yy_current_buffer )
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+	yy_init_buffer( yy_current_buffer, input_file );
+	yy_load_buffer_state();
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+	{
+	if ( yy_current_buffer == new_buffer )
+		return;
+
+	if ( yy_current_buffer )
+		{
+		/* Flush out information for old buffer. */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+	{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+	}
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file );
+
+	return b;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+	{
+	if ( ! b )
+		return;
+
+	if ( b == yy_current_buffer )
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yy_flex_free( (void *) b->yy_ch_buf );
+
+	yy_flex_free( (void *) b );
+	}
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+	{
+	yy_flush_buffer( b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+	{
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == yy_current_buffer )
+		yy_load_buffer_state();
+	}
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer( b );
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+	{
+	int len;
+	for ( len = 0; yy_str[len]; ++len )
+		;
+
+	return yy_scan_bytes( yy_str, len );
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+	{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc( n );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < len; ++i )
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer( buf, n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+	{
+	if ( yy_start_stack_ptr >= yy_start_stack_depth )
+		{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof( int );
+
+		if ( ! yy_start_stack )
+			yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+					(void *) yy_start_stack, new_size );
+
+		if ( ! yy_start_stack )
+			YY_FATAL_ERROR(
+			"out of memory expanding start-condition stack" );
+		}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+	}
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+	{
+	if ( --yy_start_stack_ptr < 0 )
+		YY_FATAL_ERROR( "start-condition stack underflow" );
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+	}
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+	{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+	}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+	{
+	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+	}
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+	{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+	}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+	{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+	}
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+	{
+	return (void *) malloc( size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+	{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+	{
+	free( ptr );
+	}
+
+#if YY_MAIN
+int main()
+	{
+	yylex();
+	return 0;
+	}
+#endif
+#line 101 "parse.fl"
+
+/******** deleted rules: *******
+en			return(EN);
+fr			return(FR);
+mi			return(MI);
+zh			return(ZH);
+de			return(DE);
+***************/
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindaction.cpp	(revision 10506)
@@ -0,0 +1,1062 @@
+/**********************************************************************
+ *
+ * phindaction.cpp -- 
+ *
+ * Copyright 2001 Gordon W. Paynter
+ * Copyright 2001 The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_PHIND_ACTION
+
+// Note that this action uses mgpp to retrieve phind info, calling MGQuery
+// etc. directly, not through the protocol. This breaks our receptionist -
+// collection server separation and should be fixed some day I guess.
+
+#include "phindaction.h"
+#include "fileutil.h"
+
+phindaction::phindaction () {
+
+  cgiarginfo arg_ainfo;
+
+  arg_ainfo.shortname = "pc";
+  arg_ainfo.longname = "phind classifier";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "pxml";
+  arg_ainfo.longname = "phind XML mode";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "ppnum";
+  arg_ainfo.longname = "phind phrase number";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "pptext";
+  arg_ainfo.longname = "phind phrase text";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "pfe";
+  arg_ainfo.longname = "phind first_e";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "ple";
+  arg_ainfo.longname = "phind last_e";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "10";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "pfl";
+  arg_ainfo.longname = "phind first_l";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "pll";
+  arg_ainfo.longname = "phind last_l";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "10";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "pfd";
+  arg_ainfo.longname = "phind first_d";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "pld";
+  arg_ainfo.longname = "phind last_d";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "10";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+phindaction::~phindaction () {
+}
+
+void phindaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass * /*protos*/,
+				    response_t &response,text_t &response_data, 
+				    ostream &/*logout*/) {
+  response = content;
+  if (args["pxml"] == "1") {
+    response_data = "text/xml";
+  } else {
+    response_data = "text/html";
+  }
+}
+
+bool phindaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			     browsermapclass * /*browsers*/, displayclass &disp, 
+			     outconvertclass &outconvert, ostream &textout, 
+			     ostream &logout) {
+
+  unsigned long count_l, count_e, count_d;
+  unsigned long phrase = args["ppnum"].getulong();
+  text_t &word = args["pptext"];
+  unsigned long first_e = args["pfe"].getulong();
+  unsigned long last_e = args["ple"].getulong();
+  unsigned long first_l = args["pfl"].getulong();
+  unsigned long last_l = args["pll"].getulong();
+  unsigned long first_d = args["pfd"].getulong();
+  unsigned long last_d = args["pld"].getulong();
+  bool XMLmode = false;
+  if (args["pxml"] == "1") XMLmode = true;
+
+  // must have a valid collection server
+  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+  if (collectproto == NULL) {
+    output_error("phindaction: ERROR: collection not set", textout, 
+		 outconvert, disp, logout, XMLmode);
+    return true;
+  }
+
+  // the frequency and occurances of the phrase
+  unsigned long tf;
+  vector <unsigned long> el, linkdest, docNums, docfreq;
+  vector <UCArray> linktype;
+
+  // the number of occurances to display
+  unsigned long ef, lf, df;
+  
+  text_t basepath = filename_cat(gsdlhome, "collect", args["c"], 
+				 "index", "phind" + args["pc"]);
+
+  // If we don't know the phrase number, look it up
+  if (phrase == 0) {
+    
+    if (word.empty()) {
+      output_error("phindaction: ERROR: no phrase number or word", textout, 
+		   outconvert, disp, logout, XMLmode);
+      return true;
+    }
+
+    DocNumArray result;
+    /** In order to prevent browser crashing problems, any method which
+     *  previously suffered a silent fatal error, now instead returns false
+     *  to indicate a fatal error has occured. We can then dispatch an
+     *  appropriate error tag to the Phind applet (rather than leave it
+     *  whiling away the milliseconds until the end of existence - or at
+     *  least your browser - in an infinite loop!)
+     *  DLConsulting 12-07-2004
+     */
+    if(!find_phrase_number_from_word(basepath, word, result)) {
+	output_error("phindaction: Fatal Error! Couldn't load index information in find_phrase_number_from_word()",
+		     textout, outconvert, disp, logout, XMLmode);
+	return true;
+    }
+    
+    if (result.empty()) {
+      output_error("phindaction: The search term does not occur in the collection",
+		   textout, outconvert, disp, logout, XMLmode);
+      return true;
+    } else {
+      phrase = result[0];
+    }
+  } 
+
+  // Create a TextData object to read the phrase data (pdata)
+  TextData textdata;
+
+  text_t fullpath = filename_cat(basepath, "pdata");
+  char *fullpathc = fullpath.getcstr();
+#if defined __WIN32__
+  char *base = "";
+#else
+  char *base = "/";
+#endif
+
+  if (!textdata.LoadData (base, fullpathc)) {
+    //    FatalError (1, "Couldn't load text information for \"%s\"", fullpathc);
+    //exit(0);
+    /** We must return something to the client, whether this error is fatal or 
+     *  no, otherwise we risk sending their browser into an infinite loop!
+     *  DLConsulting 12-07-2004
+     */
+    output_error("phindaction: Fatal Error! Couldn't load text information for collection",
+		 textout, outconvert, disp, logout, XMLmode);
+    return true;
+  }
+
+  delete []fullpathc;
+
+  /** Another previously silent method can now cry out.
+   *  DLConsulting 12-07-2004
+   */
+  if(!get_phrase_all_data(textdata, phrase, word, tf, ef, lf, df, el, 
+			  linkdest, linktype, docNums, docfreq)) {
+    output_error(
+      "phindaction: Fatal Error! Couldn't parse phrase in get_phrase_all_data()",
+      textout, outconvert, disp, logout, XMLmode);
+      return true;    
+  }
+
+  // Output the header
+  if (XMLmode) {
+    textout << "<phinddata id=\"" << phrase 
+	    << "\" text=\"" << word 
+	    << "\" tf=\"" << tf 
+	    << "\" ef=\"" << ef 
+	    << "\" df=\"" << df 
+	    << "\" lf=\"" << lf 
+	    << "\">\n";
+  } else {
+    textout << "<html><head><title>" << word << "</title></head>\n"
+	    << "<body><center>\n"
+	    << "<p><h1>" << word << "</h1>\n"
+	    << "<p><b>"<< word << "</b> occurs " 
+	    << tf << " times in " << df << " documents\n";
+  }
+
+  // Output the thesaurus links
+  if ((lf > 0) && (first_l < last_l)) {
+
+    // figure out the number of phrases to output
+    if (last_l > lf) {
+      last_l = lf;
+    }
+    count_l = last_l - first_l;
+    
+    if (XMLmode) {
+      textout << "<thesauruslist length=\"" << lf 
+	      << "\" start=\"" << first_l
+	      << "\" end=\"" << last_l << "\">\n";
+      /** DLConsulting 12-07-2004 */
+      if(!print_thesaurus_links(args["c"], XMLmode, textdata, linkdest, linktype,
+			       first_l, last_l, disp, outconvert, textout)) {
+	output_error(
+		     "phindaction: Fatal Error! Couldn't get phrase in get_phrase_freq_data()",
+		     textout, outconvert, disp, logout, XMLmode);
+	return true;	
+      }
+      textout << "</thesauruslist>\n";
+    }
+
+    // output links as HTML
+    else {
+      if (count_l == lf) {
+	textout << "<p><b> " << count_l << " thesaurus links</b>\n";
+      } else {
+	textout << "<p><b>" << count_l << " of " << lf << " thesaurus links</b>\n";
+      }
+
+      textout << "<p><table border=1><tr><th>type</th><th>topic</th><th>freq</th><th>docs</th></tr>\n";
+      /** DLConsulting 12-07-2004 */
+      if(!print_thesaurus_links(args["c"], XMLmode, textdata, linkdest, linktype, 
+			       first_l, last_l, disp, outconvert, textout)) {
+	output_error(
+		     "phindaction: Fatal Error! Couldn't get phrase in get_phrase_freq_data()",
+		     textout, outconvert, disp, logout, XMLmode);
+	return true;
+      }
+      textout << "</table>\n";
+
+      if (last_l < lf) {
+	if ((last_l + 10) < lf) {
+	  textout << outconvert << disp 
+		  << "<br><a href=\"_gwcgi_?"
+		  << "c=" << args["c"]
+		  << "&ppnum=" << phrase 
+		  << "&pfe=" << first_e 
+		  << "&ple=" << last_e 
+		  << "&pfd=" << first_d 
+		  << "&pld=" << last_d
+		  << "&pfl=" << first_l 
+		  << "&pll=" << (last_l + 10)
+		  << "\">Get more thesaurus links</a>\n"; 
+	}
+	textout << outconvert << disp
+		<< "<br><a href=\"_gwcgi_?"
+		<< "c=" << args["c"]
+		<< "&ppnum=" << phrase 
+		<< "&pfe=" << first_e 
+		<< "&ple=" << last_e 
+		<< "&pfd=" << first_d 
+		<< "&pld=" << last_d 
+		<< "&pfl=" << first_l 
+		<< "&pll=" << lf
+		<< "\">Get every thesaurus link</a>\n" ;
+      }
+    }
+  }
+  
+  // Output the expansions
+  if ((ef > 0) && (first_e < last_e)) {
+
+    // figure out the number of phrases to output
+    if (last_e > el.size()) {
+      last_e = el.size();
+    }
+    count_e = last_e - first_e;
+
+    // output expansions as XML
+    if (XMLmode) {
+      textout << "<expansionlist length=\"" << ef 
+	      << "\" start=\"" << first_e
+	      << "\" end=\"" << last_e << "\">" << endl;
+
+      print_expansions(args["c"], XMLmode, word, textdata, el, first_e,
+		       last_e, disp, outconvert, textout);
+
+      textout << "</expansionlist>\n";
+    }
+
+    // output expansions as HTML
+    else {
+      if (count_e == el.size()) {
+	textout << "<p><b> " << count_e << " expansions</b>\n";
+      } else {
+	textout << "<p><b>" << count_e << " of " << ef << " expansions</b>\n";
+      }
+
+      textout << "<p><table border=1><tr><th colspan=3>phrase</th><th>freq</th><th>docs</th></tr>\n";
+      print_expansions(args["c"], XMLmode, word, textdata, el, first_e, 
+		       last_e, disp, outconvert, textout);
+      textout << "</table>\n";
+
+      if (last_e < ef) {
+	if ((last_e + 10) < ef) {
+	  textout << outconvert << disp 
+		  << "<br><a href=\"_gwcgi_?"
+		  << "c=" << args["c"]
+		  << "&ppnum=" << phrase 
+		  << "&pfe=" << first_e 
+		  << "&ple=" << (last_e + 10) 
+		  << "&pfd=" << first_d 
+		  << "&pld=" << last_d 
+		  << "&pfl=" << first_l 
+		  << "&pll=" << last_l
+		  << "\">Get more expansions</a>\n";
+	}
+	textout << outconvert << disp
+		<< "<br><a href=\"_gwcgi_?"
+		<< "c=" << args["c"]
+		<< "&ppnum=" << phrase 
+		<< "&pfe=" << first_e 
+		<< "&ple=" << ef
+		<< "&pfd=" << first_d 
+		<< "&pld=" << last_d 
+		<< "&pfl=" << first_l 
+		<< "&pll=" << last_l
+		<< "\">Get every expansion</a>\n";
+      }
+    }
+  }
+
+  // Output the document occurances
+  if ((df > 0) && (first_d < last_d)) {
+
+    // figure out the phrases to output
+    if (last_d > docNums.size()) {
+      last_d = docNums.size();
+    }
+    count_d = last_d - first_d;
+
+    // output document list as XML
+    if (XMLmode) {
+      textout << "<documentlist length=\"" << df 
+	      << "\" start=\"" << first_d
+	      << "\" end=\"" << last_d << "\">\n";
+      
+      if(!print_documents(XMLmode, basepath, args["c"], docNums, docfreq,
+			  first_d, last_d, disp, outconvert, textout)) {
+	output_error(
+		     "phindaction: Fatal Error! Couldn't load text information in print_documents() or get_document_all_data()",
+		     textout, outconvert, disp, logout, XMLmode);
+	return true;	
+      }
+
+      textout << "</documentlist>\n";
+    }
+
+    // output document list as HTML 
+    else {
+      
+      if (count_d == docNums.size()) {
+	textout << "<p><b> " << count_d << " documents</b>\n";
+      } else {
+	textout << "<p><b>" << count_d << " of " << df << " documents</b>\n";
+      }
+
+      textout << "<p><table border=1><tr><th align=left>document</th><th>freq</th></tr>\n";
+      if(!print_documents(XMLmode, basepath, args["c"], docNums, docfreq, 
+			  first_d, last_d, disp, outconvert, textout)) {
+	output_error(
+		     "phindaction: Fatal Error! Couldn't load text information in print_documents()",
+		     textout, outconvert, disp, logout, XMLmode);
+	return true;
+      }
+      textout << "</table>\n";
+      
+      if (last_d < df) {
+	if ((last_d + 10) < df) {
+	  textout << outconvert << disp
+		  << "<br><a href=\"_gwcgi_?"
+		  << "c=" << args["c"]
+		  << "&ppnum=" << phrase 
+		  << "&pfe=" << first_e 
+		  << "&ple=" << last_e 
+		  << "&pfd=" << first_d
+		  << "&pld=" << (last_d + 10)  
+		  << "&pfl=" << first_l 
+		  << "&pll=" << last_l
+		  << "\">Get more documents</a>\n";
+	}
+	textout << outconvert << disp 
+		<< "<br><a href=\"_gwcgi_?"
+		<< "c=" << args["c"]
+		<< "&ppnum=" << phrase 
+		<< "&pfe=" << first_e 
+		<< "&ple=" << last_e 
+		<< "&pfd=" << first_d 
+		<< "&pld=" << df
+		<< "&pfl=" << first_l 
+		<< "&pll=" << last_l
+		<< "\">Get every document</a>\n";
+      }
+    }
+  }
+
+  // Close the document
+  if (XMLmode) {
+    textout << "</phinddata>\n";
+  } else {
+    textout << "</center></body></html>\n";
+  }
+
+  textdata.UnloadData ();
+
+  return true;
+}
+
+// Find the phrase number of a word in the index file
+bool phindaction::find_phrase_number_from_word(const text_t &basepath, 
+					       const text_t &query, 
+					       DocNumArray &result) {
+
+  // Open the index file for searching
+  IndexData indexData;
+
+  text_t fullpath = filename_cat(basepath, "pword");
+  char *fullpathc = fullpath.getcstr();
+#if defined __WIN32__
+  char *base = "";
+#else
+  char *base = "/";
+#endif
+
+  if (!indexData.LoadData (base, fullpathc)) {
+    //    FatalError (1, "Couldn't load index information for \"%s\"", fullpathc);
+    //exit(0);
+    /** Don't handle fatal errors here anymore.
+     *  DLConsulting 12-07-2004
+     */
+    return false; // Indicates something very bad has happened
+  }
+
+  delete []fullpathc;
+
+  // set up the query object
+  QueryInfo queryInfo;
+  SetCStr (queryInfo.docLevel, "Document", 8);
+  queryInfo.maxDocs = 5;
+  queryInfo.sortByRank = true;
+  queryInfo.exactWeights = false;
+  queryInfo.needRankInfo = true;
+  queryInfo.needTermFreqs = true;
+  
+  // mode 1 = casefolded, unstemmed search
+  UCArray ucquery;
+  toUCArray(query, ucquery);
+  QueryNode *queryTree = ParseQuery(ucquery, 1, 1);
+      
+  // perform the query
+  ExtQueryResult queryResult;
+  MGQuery (indexData, queryInfo, queryTree, queryResult);
+  // cout << "-- word lookup result -- " << endl << queryResult << endl ;
+
+  result.clear();
+  result = queryResult.docs;
+
+  // delete the query
+  if (queryTree != NULL) delete queryTree;
+
+  indexData.UnloadData();
+
+  /** This method now returns a boolean, so...
+   *  DLConsulting 12-07-2004
+   */
+  return true; // Indicates that what happened is all good, baby.
+}
+
+// Get all the data about a phrase
+//
+// The phrase is stored in textData as record phrase.
+// We retrieve:
+//   word - the text of the phrase
+//   tf - the total frequency of the phrase
+//   ef - the expansion frequency of the phrase
+//   lf - the thesaurus link frequency of the phrase
+//   df - the document frequency of the phrase
+//   el - the list of phrases that are expansions of phrase
+//   ll - the list of phrases that are thesaurus links 
+//   dl - the list of documents that contain phrase
+bool phindaction::get_phrase_all_data(TextData &textdata, unsigned long phrase,
+				      text_t &word, unsigned long &tf, unsigned long &ef,
+				      unsigned long &lf, unsigned long &df,
+				      vector <unsigned long> &el,
+				      vector <unsigned long> &linkdest,
+				      vector <UCArray> &linktype,
+				      vector <unsigned long> &docnum, 
+				      vector <unsigned long> &docfrq) {
+  UCArray text;
+  UCArray docLevel;
+  SetCStr(docLevel, "Document", 8);
+
+  // Look the word up in the textData
+  if (!GetDocText (textdata, docLevel, phrase, text)) {
+    //    FatalError (1, "Error while trying to get phrase %u", phrase);
+    //exit(0);
+    return false; // Something very bad has happened.
+  }
+
+  // Ignore everything up to the first colon
+  UCArray::iterator next = text.begin();
+  while (*next++ != ':');
+
+  // ignore training carriage returns
+  while (text.back() == '\n') {
+    text.pop_back();
+  }
+  
+  // Get the word
+  word.clear();
+  for (; *next != ':'; ++next) {
+    word.push_back(*next);
+  }
+  
+  // Get total frequency
+  tf = 0;
+  for (++next; *next != ':'; ++next) {
+    tf *= 10;
+    tf += (*next - '0');
+  }
+  
+  // Get expansion frequency
+  ef = 0;
+  for (++next; *next != ':'; ++next) {
+    ef *= 10;
+    ef += (*next - '0');
+  }
+  
+  // Get document frequency
+  df = 0;
+  for (++next; *next != ':'; ++next) {
+    df *= 10;
+    df += (*next - '0');
+  }
+  
+  // Get expansion list
+  el.clear();
+  unsigned long e = 0;
+  for (++next; *next != ':'; ++next) {
+    if (*next == ',') {
+      el.push_back(e);
+      e = 0;
+    } else {
+      e *= 10;
+      e += (*next - '0');
+    }
+  }
+
+  // Get document list & the document frequency list
+  docnum.clear();
+  docfrq.clear();
+  bool readnum = false;
+  unsigned long d = 0;
+  for (++next; *next != ':'; ++next) {
+    if (*next == ',') {
+      docnum.push_back(d);
+      readnum = true;
+      d = 0;
+    } else if (*next == ';') {
+      if (readnum) {
+	docfrq.push_back(d);
+      } else {
+	docnum.push_back(d);
+	docfrq.push_back(1);
+      }
+      readnum = false;
+      d = 0;
+    } else {
+      d *= 10;
+      d += (*next - '0');
+    }
+  }
+
+  // Get thesaurus link frequency & link list
+  text.push_back(':');
+  text.push_back(':');
+
+  // link frequency
+  lf = 0;
+  for (++next; *next != ':'; ++next) {
+    lf *= 10;
+    lf += (*next - '0');
+  }
+
+  // two lists of link data
+  linkdest.clear();
+  linktype.clear();
+  
+  UCArray thistype;
+  thistype.clear();
+  bool typedone = false;
+  unsigned long l = 0;
+  for (++next; *next != ':'; ++next) {
+    
+    if (!typedone) {
+      // first read the link type, a charactor string
+      if (*next == ',') {
+	typedone = true;
+      } else {
+	thistype.push_back(*next);
+      }
+    } else {
+      // having read the link type, read the list of link destinations
+      if (*next == ',') {
+	linkdest.push_back(l);
+	linktype.push_back(thistype);
+	l = 0;
+      } else if (*next == ';') {
+	linkdest.push_back(l);
+	linktype.push_back(thistype);
+	l = 0;
+	thistype.clear();
+	typedone = false;
+      } else {
+	l *= 10;
+	l += (*next - '0');
+      }
+    }
+  }
+
+  return true; // Indicates that what happened is all good, baby.
+}
+
+bool phindaction::print_thesaurus_links(const text_t &collection, bool XMLmode, 
+					TextData &textdata, vector <unsigned long> &linkdest,
+					vector <UCArray> &linktype, unsigned long first,
+					unsigned long last, displayclass &disp, 
+					outconvertclass &outconvert, ostream &textout) {
+
+  // information describing each link in the list
+  unsigned long phrase, tf, ef, df;
+  UCArray type, text;
+  
+  for (unsigned long l = first; l < last; ++l) {
+
+    // get the phrase data
+    phrase = linkdest[l];
+    type = linktype[l];
+
+    /** DLConsulting 12-07-2004 */
+    if(!get_phrase_freq_data(textdata, phrase, text, tf, ef, df)) {
+      return false;
+    }
+    
+    if (XMLmode) {
+      textout << "<thesaurus num=\"" << l 
+	      << "\" id=\"" << phrase
+	      << "\" tf=\"" << tf 
+	      << "\" df=\"" << df
+	      << "\" type=\"" << type
+	      << "\" text=\"" << text
+	      << "\"/>\n";
+    } else {
+      textout << "<tr valign=top><td>" << type << "</td><td>";
+      textout << outconvert << disp
+	      << "<a href=\"_gwcgi_?c=" << collection;
+      textout << "&ppnum=" << phrase << "\">" << text << "</a>"
+	      << "</td><td>" << tf << "</td><td>" << df << "</td></tr>\n";
+    }
+  }
+
+  /** DLConsulting 12-07-2004 */
+  return true;
+}
+
+// Get the frequency data about a phrase
+//
+// The phrase is stored in textData as record phrase.
+// We retrieve:
+//   word - the text of the phrase
+//   tf - the total frequency of the phrase
+//   ef - the expansion frequency of the phrase
+//   df - the document frequency of the phrase
+/**
+ *   Returns:
+ *     false if the method suffered a fatal error, true otherwise
+ */
+bool phindaction::get_phrase_freq_data(TextData &textdata, unsigned long phrase,
+				       UCArray &word, unsigned long &tf, 
+				       unsigned long &ef, unsigned long &df) {
+  
+  UCArray text;
+  UCArray docLevel;
+  SetCStr(docLevel, "Document", 8);
+
+  // Look the word up in the textData
+  if (!GetDocText (textdata, docLevel, phrase, text)) {
+    //    FatalError (1, "Error while trying to get phrase %u", phrase);
+    //exit(0);
+    /** DLConsulting 12-07-2004 */
+    return false;
+  }
+
+  // Ignore everything up to the first colon
+  UCArray::iterator next = text.begin();
+  while (*next++ != ':');
+  
+  // Get the word
+  word.clear();
+  for (; *next != ':'; ++next) {
+    word.push_back(*next);
+  }
+  
+  // Get total frequency
+  tf = 0;
+  for (++next; *next != ':'; ++next) {
+    tf *= 10;
+    tf += (*next - '0');
+  }
+  
+  // Get expansion frequency
+  ef = 0;
+  for (++next; *next != ':'; ++next) {
+    ef *= 10;
+    ef += (*next - '0');
+  }
+  
+  // Get document frequency
+  df = 0;
+  for (++next; *next != ':'; ++next) {
+    df *= 10;
+    df += (*next - '0');
+  }
+
+  /** DLConsulting 12-07-2004 */
+  return true;
+}
+
+// Print a list of expansions
+//
+// Given the textData and a list of phrase numbers, print out each of the
+// expansions.
+void phindaction::print_expansions(const text_t &collection, bool XMLmode, 
+				   const text_t &body, TextData &textdata, 
+				   const vector <unsigned long> &elist,
+				   unsigned long first, unsigned long last,
+				   displayclass &disp, outconvertclass &outconvert,
+				   ostream &textout) {
+  
+  UCArray word;
+  unsigned long phrase, tf, df, ef;
+
+  UCArray suffix, prefix, ucbody;
+  
+  toUCArray(body, ucbody);
+
+  for (unsigned long e = first; e < last; ++e) {
+
+    phrase = elist[e];
+    get_phrase_freq_data(textdata, phrase, word, tf, ef, df);
+
+    split_phrase(word, ucbody, prefix, suffix);
+    
+    if (XMLmode) {
+      // body is always the same as the text of the phrase, so no need to send it
+      textout << "<expansion num=\"" << e 
+	      << "\" id=\"" << phrase
+	      << "\" tf=\"" << tf 
+	      << "\" df=\"" << df;
+      if (!prefix.empty()) {
+	textout << "\" prefix=\"" << prefix;
+      }
+      if (!suffix.empty()) {
+	textout << "\" suffix=\"" << suffix;
+      }
+      textout << "\"/>\n";
+    } else {
+      textout << outconvert << disp 
+	      << "<tr valign=top><td align=right><a href=\"_gwcgi_?"
+	      << "c=" << collection << "&ppnum=" << phrase << "\">";
+      textout << prefix << "</a></td>";
+      textout <<outconvert << disp
+	      << "<td align=center><a href=\"_gwcgi_?"
+	      << "c=" << collection << "&ppnum=" << phrase << "\">"
+	      << body << "</a></td>"
+	      << "<td align=left><a href=\"_gwcgi_?"
+	      << "c=" << collection << "&ppnum=" << phrase << "\">";
+      textout << suffix << "</a></td>"
+	      << "<td>" << tf << "</td><td>" << df << "</td></tr>\n";
+    }
+  }
+}
+
+// split an expansion into prefix and suffix
+void phindaction::split_phrase(const UCArray &word, const UCArray &body, 
+			       UCArray &prefix, UCArray &suffix) {
+
+  prefix.clear();
+  suffix.clear();
+
+  bool readingPrefix = true;
+  UCArray::const_iterator here = word.begin();
+  UCArray::const_iterator end = word.end();
+  
+  while (here != end) {
+
+    // if we've not read all the prefix, add the next char to the prefix
+    if (readingPrefix) {
+      if (phrase_match(body, here, end)) {
+	readingPrefix = false;
+	// trim whitespace from end of prefix & start of suffix
+	if (!prefix.empty()) {
+	  prefix.pop_back();
+	}
+	if ((here != end) && (*here == ' ')) {
+	  ++here;
+	}
+      } else {
+	prefix.push_back(*here);
+	++here;
+      }
+    }
+    // if we've finished with the prefix, update the suffix
+    else {
+      suffix.push_back(*here);
+      ++here;
+    }
+  }
+}
+
+// phrase_match
+//
+// compare two strings, one represented as an UCArray, the other as two
+// UCArray iterators.
+//
+// Return true if the UCArray is the same as the phrase the iterators point
+// to for the length of the UCArray.
+bool phindaction::phrase_match(const UCArray &text, UCArray::const_iterator &here, 
+			       UCArray::const_iterator end) {
+
+  UCArray::const_iterator one_here = text.begin();
+  UCArray::const_iterator one_end  = text.end();
+  UCArray::const_iterator two_here = here;
+
+  // iterate over the length of the first string, comparing each element to
+  // the corresponding element in the second string.
+  while (one_here != one_end) {
+   
+      if (two_here == end) {
+	  return false;
+      } else if (*one_here != *two_here) {
+	  return false;
+      }
+      ++one_here;
+      ++two_here;
+  }
+
+  here = two_here;
+  return true;
+}
+
+bool phindaction::print_documents(bool XMLmode, const text_t &basepath, 
+				  const text_t &collection,
+				  const vector <unsigned long> &docNums, 
+				  const vector <unsigned long> &docFreq,
+				  unsigned long first, unsigned long last,
+				  displayclass &disp, outconvertclass &outconvert,
+				  ostream &textout) {
+  
+  // Create a TextData object to read the document data
+  TextData docdata;
+
+  text_t fullpath = filename_cat(basepath, "docs");
+  char *fullpathc = fullpath.getcstr();
+#if defined __WIN32__
+  char *base = "";
+#else
+  char *base = "/";
+#endif
+
+  if (!docdata.LoadData (base, fullpathc)) {
+    //    FatalError (1, "Couldn't load text information for \"%s\"", fullpathc);
+    //exit(0);
+    /** DLConsulting 12-07-2004 */
+    return false;
+  }
+
+  delete []fullpathc;
+
+  UCArray title, hash;
+  unsigned long freq, doc;
+
+  for (unsigned long d = first; d < last; ++d) {
+    doc = docNums[d];
+    freq = docFreq[d];
+
+    /** DLConsulting 13-07-2004 */
+    if(!get_document_all_data(docdata, doc, title, hash)) {
+      return false;
+    }
+
+    if (XMLmode) {
+      textout << "<document num=\"" << d
+	      << "\" hash=\"" << hash 
+	      << "\" freq=\"" << freq 
+	      << "\" title=\"" << title << "\"/>\n";
+    } else {
+      textout << outconvert << disp
+	      << "<tr valign=top><td><a href=\"_gwcgi_?"
+	      << "c=" << collection;
+      textout << "&a=d&d=" << hash << "\">" << title << "</a>"
+	      << "</td><td>" << freq << "</td></tr>\n"; 
+    }
+  }
+
+  docdata.UnloadData();
+
+  /** DLConsulting 12-07-2004 */
+  return true;
+}
+
+// Get all the data about a docment
+//
+// The document's details are stored in docData as record docNum.
+// We retrieve:
+//   title - the document's title
+//   hash - the document's unique OID
+/** Returns:
+ *   false if a fatal error occured, true otherwise
+ *  DLConsulting 12-07-2004
+ */
+bool phindaction::get_document_all_data(TextData &docdata, unsigned long docNum,
+					UCArray &title, UCArray &hash) {
+
+  UCArray text;
+  UCArray docLevel;
+  SetCStr(docLevel, "Document", 8);
+
+  // Look the word up in the textData
+  if (!GetDocText (docdata, docLevel, docNum, text)) {
+    //    FatalError (1, "Error while trying to get document %u", docNum);
+    //exit(0);
+    /** DLConsulting 13-07-2004 */
+    return false;
+  }
+
+  // Ignore everything up to the first colon
+  UCArray::iterator next = text.begin();
+  while (*next++ != '\t');
+  
+  // Get the document OID (hash)
+  hash.clear();
+  for (; *next != '\t'; ++next) {
+    hash.push_back(*next);
+  }
+
+  // Get the title
+  text.push_back('\n');
+  title.clear();
+  for (++next; *next != '\n'; ++next) {
+    title.push_back(*next);
+  }
+
+  /** DLConsulting 13-07-2004 */
+  return true;
+}
+
+void phindaction::toUCArray(const text_t &in, UCArray &out) {
+  out.clear();
+  if (out.capacity() < in.size() + 1) {
+    out.reserve(in.size() + 1);
+  }
+  text_t::const_iterator here = in.begin();
+  text_t::const_iterator end = in.end();
+  while (here != end) {
+    out.push_back((unsigned char) *here);
+    ++here;
+  }
+}
+
+void phindaction::output_error (const text_t &message, ostream &textout, 
+				outconvertclass &outconvert,
+				displayclass & disp, ostream &logout,
+				bool XMLmode) {
+
+  logout << outconvert << message << "\n";
+  if (XMLmode) {
+    textout << outconvert
+	    << "<phinddata>\n"
+	    << "<phinderror>" << message << "</phinderror>\n"
+	    << "</phinddata>\n";
+  } else {
+    textout << outconvert << disp 
+	    << "_header_\n" 
+	    << message
+	    << "_footer_\n";
+  }
+}
+
+#endif //GSDL_USE_PHIND_ACTION
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindaction.h	(revision 10506)
@@ -0,0 +1,122 @@
+/**********************************************************************
+ *
+ * phindaction.h -- 
+ *
+ * Copyright 2001 Gordon W. Paynter
+ * Copyright 2001 The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_PHIND_ACTION
+
+#ifndef PHINDACTION_H
+#define PHINDACTION_H
+
+#include "action.h"
+
+// Include MGPP functionality.
+#include <TextGet.h>
+#include <MGQuery.h>
+#include <Terms.h>
+#include <messages.h>
+#include <GSDLQueryParser.h>
+
+class phindaction : public action {
+  
+protected:
+
+  bool find_phrase_number_from_word(const text_t &basepath, 
+				    const text_t &query, 
+				    DocNumArray &result);
+
+  bool get_phrase_all_data(TextData &textdata, unsigned long phrase,
+			   text_t &word, unsigned long &tf, unsigned long &ef,
+			   unsigned long &lf, unsigned long &df,
+			   vector <unsigned long> &el,
+			   vector <unsigned long> &linkdest,
+			   vector <UCArray> &linktype,
+			   vector <unsigned long> &docnum, 
+			   vector <unsigned long> &docfrq);
+
+  bool print_thesaurus_links(const text_t &collection, bool XMLmode, 
+			     TextData &textdata, vector <unsigned long> &linkdest,
+			     vector <UCArray> &linktype, unsigned long first,
+			     unsigned long last, displayclass &disp, 
+			     outconvertclass &outconvert, ostream &textout);
+
+  bool get_phrase_freq_data(TextData &textdata, unsigned long phrase,
+			    UCArray &word, unsigned long &tf, 
+			    unsigned long &ef, unsigned long &df);
+
+  void print_expansions(const text_t &collection, bool XMLmode, 
+			const text_t &body, TextData &textdata, 
+			const vector <unsigned long> &elist,
+			unsigned long first, unsigned long last,
+			displayclass &disp, outconvertclass &outconvert,
+			ostream &textout);
+
+  void split_phrase(const UCArray &word, const UCArray &body, 
+		    UCArray &prefix, UCArray &suffix);
+
+  bool phrase_match(const UCArray &text, UCArray::const_iterator &here, 
+		    UCArray::const_iterator end);
+
+  bool print_documents(bool XMLmode, const text_t &basepath, 
+		       const text_t &collection,
+		       const vector <unsigned long> &docNums, 
+		       const vector <unsigned long> &docFreq,
+		       unsigned long first, unsigned long last,
+		       displayclass &disp, outconvertclass &outconvert,
+		       ostream &textout);
+
+  bool get_document_all_data(TextData &docdata, unsigned long docNum,
+			     UCArray &title, UCArray &hash);
+
+  void toUCArray(const text_t &in, UCArray &out);
+
+  void output_error (const text_t &message, ostream &textout, 
+		     outconvertclass &outconvert,
+		     displayclass & disp, ostream &logout,
+		     bool XMLmode);
+
+
+public:
+  phindaction ();
+  virtual ~phindaction ();
+
+  text_t get_action_name () {return "phind";}
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response,text_t &response_data, 
+			 ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+
+};
+
+#endif //!PHINDACTION_H
+#endif //GSDL_USE_PHIND_ACTION
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindbrowserclass.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindbrowserclass.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindbrowserclass.cpp	(revision 10506)
@@ -0,0 +1,51 @@
+/**********************************************************************
+ *
+ * phindbrowserclass.cpp -- 
+ *
+ * Copyright (C) 2000 The New Zealand Digital Library Project
+ *
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_PHIND_BROWSER
+
+#include "phindbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+
+phindbrowserclass::phindbrowserclass () {
+}
+
+phindbrowserclass::~phindbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t phindbrowserclass::get_browser_name () {
+  return "Phind";
+}
+
+browserclass* phindbrowserclass::clone()
+{
+  return new phindbrowserclass();
+}
+
+#endif //GSDL_USE_PHIND_BROWSER
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindbrowserclass.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindbrowserclass.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/phindbrowserclass.h	(revision 10506)
@@ -0,0 +1,59 @@
+/**********************************************************************
+ *
+ * phindbrowserclass.h -- 
+ *
+ * Copyright (C) 2000 The New Zealand Digital Library Project
+ *
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_PHIND_BROWSER
+
+// The phindbrowserclass is necessary to add a phind classifier to the user
+// interface and navigation bar, but is basically empty - all the work is
+// done in documentaction.cpp and in the document.dm macro file.  What
+// happens is that documentaction.cpp has a section that sets various
+// macros when the document in question is a phind classifier; thse are in
+// turn used by the macro file to load the applet into the web page.
+
+#ifndef PHINDBROWSERCLASS_H
+#define PHINDBROWSERCLASS_H
+
+#include "browserclass.h"
+
+class phindbrowserclass : public browserclass {
+protected:
+
+public:
+
+  phindbrowserclass ();
+  virtual ~phindbrowserclass ();
+
+  // returns the name that specifies the browserclass type
+  virtual text_t get_browser_name ();
+
+  virtual browserclass* clone();
+
+};
+
+#endif //!PHINDBROWSERCLASS_H
+#endif //GSDL_USE_PHIND_BROWSER
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/pingaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/pingaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/pingaction.cpp	(revision 10506)
@@ -0,0 +1,87 @@
+/**********************************************************************
+ *
+ * pingaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_PING_ACTION
+
+#include "pingaction.h"
+
+pingaction::pingaction () {
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "ping";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+}
+
+void pingaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				   response_t &response, text_t &response_data, 
+				   ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+
+bool pingaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			    browsermapclass * /*browsers*/, displayclass &/*disp*/, 
+			    outconvertclass &outconvert, ostream &textout, 
+			    ostream &logout) {
+  bool wassuccess = false;
+  comerror_t err;
+  
+  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+  if (!args["c"].empty() && (collectproto != NULL)) {
+    collectproto->ping (args["c"], wassuccess, err, logout);
+    if (err != noError) wassuccess = false; // a communication error
+  }
+
+  textout << outconvert
+	  << "<html>\n"
+	  << "<head>\n"
+	  << "<title>Ping</title>\n"
+	  << "</head>\n"
+	  << "<body>\n"
+	  << "Ping for \"" << args["c"] << "\" ";
+
+  if (wassuccess) {
+    textout << outconvert << " succeeded.\n";
+  } else {
+    textout << outconvert << " did not succeed.\n";
+  }
+
+  textout << outconvert 
+	  << "</body>\n"
+	  << "</html>\n";
+
+  return true;
+};
+
+#endif //GSDL_USE_PING_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/pingaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/pingaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/pingaction.h	(revision 10506)
@@ -0,0 +1,55 @@
+/**********************************************************************
+ *
+ * pingaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_PING_ACTION
+
+#ifndef PINGACTION_H
+#define PINGACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+
+
+class pingaction : public action {
+public:
+  pingaction ();
+  virtual ~pingaction () {}
+
+  text_t get_action_name () {return "ping";}
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+};
+
+
+#endif //!PINGACTION_H
+#endif //GSDL_USE_PING_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/queryaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/queryaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/queryaction.cpp	(revision 10506)
@@ -0,0 +1,1589 @@
+/**********************************************************************
+ *
+ * queryaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "queryaction.h"
+#include "querytools.h"
+#include "formattools.h"
+#include "cgiutils.h"
+#include "OIDtools.h"
+//#include "infodbclass.h"
+#include "fileutil.h"
+#include "text_t.h"
+#include "historydb.h"
+#include "htmlutils.h" // for html_safe in do_action
+#include "gsdltools.h"
+#include <stdlib.h> // for strtol
+#include <assert.h>
+
+void colinfo_t::clear () {
+  formatlistptr = NULL;
+  browserptr = NULL;
+}
+
+void QueryResult_t::clear() {
+  doc.clear();
+  collection.clear();
+}
+
+queryaction::queryaction () {
+
+  recpt = NULL;
+  num_phrases = 0;
+
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "q";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+  
+   // "ct" - 0 = mg, 1 = mgpp, 2=lucene
+  arg_ainfo.shortname = "ct";
+  arg_ainfo.longname = "collection type";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+ 
+  // "b" - 0 = simple, 1 = advanced
+  arg_ainfo.shortname = "b";
+  arg_ainfo.longname = "query mode";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "h"
+  arg_ainfo.shortname = "h";
+  arg_ainfo.longname = "main index";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "h2"
+  arg_ainfo.shortname = "h2";
+  arg_ainfo.longname = "main index for second query";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "j"
+  arg_ainfo.shortname = "j";
+  arg_ainfo.longname = "sub collection index";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "j2"
+  arg_ainfo.shortname = "j2";
+  arg_ainfo.longname = "sub collection index for second query";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "n"
+  arg_ainfo.shortname = "n";
+  arg_ainfo.longname = "language index";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "n2"
+  arg_ainfo.shortname = "n2";
+  arg_ainfo.longname = "language index for second query";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+
+  // "q"
+  arg_ainfo.shortname = "q";
+  arg_ainfo.longname = "query string";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "q2"
+  arg_ainfo.shortname = "q2";
+  arg_ainfo.longname = "query string for second query";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "cq2" ""=don't combine, "and", "or", "not"
+  arg_ainfo.shortname = "cq2";
+  arg_ainfo.longname = "combine queries";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "t" - 1 = ranked 0 = boolean
+  arg_ainfo.shortname = "t";
+  arg_ainfo.longname = "search type";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "k"
+  arg_ainfo.shortname = "k";
+  arg_ainfo.longname = "casefolding";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "s"
+  arg_ainfo.shortname = "s";
+  arg_ainfo.longname = "stemming";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault ="0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "m"
+  arg_ainfo.shortname = "m";
+  arg_ainfo.longname = "maximum number of documents";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "50";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "o"
+  arg_ainfo.shortname = "o";
+  arg_ainfo.longname = "hits per page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "20";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "r"
+  arg_ainfo.shortname = "r";
+  arg_ainfo.longname = "start results from";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ccs"
+  arg_ainfo.shortname = "ccs";
+  arg_ainfo.longname = "cross collection searching";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ccp"
+  arg_ainfo.shortname = "ccp";
+  arg_ainfo.longname = "cross collection page";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "cc"
+  arg_ainfo.shortname = "cc";
+  arg_ainfo.longname = "collections to search";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.multiplevalue = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "hd" history display  - search history only displayed when
+  // this var set to something other than 0
+  // this number of records is displayed
+  arg_ainfo.shortname = "hd";
+  arg_ainfo.longname = "history display";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.multiplevalue = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+	    
+  // "hs"  save - set to 1 in query form, so only save when submit
+  // query
+  // 0 = no save 1 = save
+  arg_ainfo.shortname = "hs";
+  arg_ainfo.longname = "history save";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "g" - new arg for granularity, for mgpp collections
+  arg_ainfo.shortname = "g";
+  arg_ainfo.longname = "granularity";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText; 
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ds" - start date
+  arg_ainfo.shortname = "ds";
+  arg_ainfo.longname = "start date";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "de" - end date
+  arg_ainfo.shortname = "de";
+  arg_ainfo.longname = "end date";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "dsbc" - whether or not start date is prechristian
+  arg_ainfo.shortname = "dsbc";
+  arg_ainfo.longname = "start date bc";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "debc" - whether or not end date is prechristian
+  arg_ainfo.shortname = "debc";
+  arg_ainfo.longname = "end date bc";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "qt" - 0 = text, 1 = form
+  arg_ainfo.shortname = "qt";
+  arg_ainfo.longname = "query type";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "qto" - 1 = text only, 2 = form only, 3 = text and form
+  arg_ainfo.shortname = "qto";
+  arg_ainfo.longname = "query type options";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "3";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+  
+  // "qf" - 0= simple, 1 = advanced
+  arg_ainfo.shortname = "qf";
+  arg_ainfo.longname = "query form type";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+  
+  // "qb" - 0 = regular, 1 = large
+  arg_ainfo.shortname = "qb";
+  arg_ainfo.longname = "query box type";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "fqn" - number of fields in the query form
+  arg_ainfo.shortname = "fqn";
+  arg_ainfo.longname = "form query num fields";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "4";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "fqf" - the list of field names in the form query
+  // - a comma separated list
+  arg_ainfo.shortname = "fqf";
+  arg_ainfo.longname = "form query fields";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+  
+  // "fqv" - the list of values in the form query
+  // - a comma separated list
+  arg_ainfo.shortname = "fqv";
+  arg_ainfo.longname = "form query values";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+  
+
+  // "fqs" - the list of stemming options in the form query
+  // - a comma separated list
+  arg_ainfo.shortname = "fqs";
+  arg_ainfo.longname = "form query stems";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+  
+
+  // "fqk" - the list of casefolding options in the form query
+  // - a comma separated list
+  arg_ainfo.shortname = "fqk";
+  arg_ainfo.longname = "form query casefolds";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+  
+  // "fqc" - the list of boolean operators in the form query
+  // - a comma separated list
+  arg_ainfo.shortname = "fqc";
+  arg_ainfo.longname = "form query combines";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "fqa" - form query advanced - for "run query"
+  arg_ainfo.shortname = "fqa";
+  arg_ainfo.longname = "form query advanced query";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "0";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "ifl" - I'm feeling lucky! (Go directly to the first matching document)
+  arg_ainfo.shortname = "ifl";
+  arg_ainfo.longname = "i'm feeling lucky";
+  arg_ainfo.multiplechar = false;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+}
+
+void queryaction::configure (const text_t &key, const text_tarray &cfgline) {
+  action::configure (key, cfgline);
+}
+
+bool queryaction::init (ostream &logout) {
+  return action::init (logout);
+}
+
+bool queryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+				 recptprotolistclass * /*protos*/, ostream &logout) {
+
+  // check t argument
+  int arg_t = args.getintarg("t");
+  if (arg_t != 0 && arg_t != 1) {
+    logout << "Warning: \"t\" argument out of range (" << arg_t << ")\n";
+    cgiarginfo *tinfo = argsinfo.getarginfo ("t");
+    if (tinfo != NULL) args["t"] = tinfo->argdefault;
+  }
+
+  // check k argument
+  int arg_k = args.getintarg("k");
+  if (arg_k != 0 && arg_k != 1) {
+    logout << "Warning: \"k\" argument out of range (" << arg_k << ")\n";
+    cgiarginfo *kinfo = argsinfo.getarginfo ("k");
+    if (kinfo != NULL) args["k"] = kinfo->argdefault;
+  }
+
+  // check s argument
+  int arg_s = args.getintarg("s");
+  if (arg_s != 0 && arg_s != 1) {
+    logout << "Warning: \"s\" argument out of range (" << arg_s << ")\n";
+    cgiarginfo *sinfo = argsinfo.getarginfo ("s");
+    if (sinfo != NULL) args["s"] = sinfo->argdefault;
+  }
+
+  // check m argument
+  int arg_m = args.getintarg("m");
+  if (arg_m < -1) {
+    logout << "Warning: \"m\" argument less than -1 (" << arg_m << ")\n";
+    cgiarginfo *minfo = argsinfo.getarginfo ("m");
+    if (minfo != NULL) args["m"] = minfo->argdefault;
+  }
+
+  // check o argument
+  int arg_o = args.getintarg("o");
+  if (arg_o < -1) {
+    logout << "Warning: \"o\" argument less than -1 (" << arg_o << ")\n";
+    cgiarginfo *oinfo = argsinfo.getarginfo ("o");
+    if (oinfo != NULL) args["o"] = oinfo->argdefault;
+  }
+
+  // check r argument
+  int arg_r = args.getintarg("r");
+  if (arg_r < 1) {
+    logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
+    cgiarginfo *rinfo = argsinfo.getarginfo ("r");
+    if (rinfo != NULL) args["r"] = rinfo->argdefault;
+  }
+  //check hd argument
+  int arg_hd = args.getintarg("hd");
+  if (arg_hd <0 ) {
+    logout << "Warning: \"hd\" argument less than 0 (" << arg_hd << ")\n";
+    cgiarginfo *hdinfo = argsinfo.getarginfo ("hd");
+    if (hdinfo != NULL) args["hd"] = hdinfo->argdefault;
+  }  
+  
+  //check hs argument
+  int arg_hs = args.getintarg("hs");
+  if (arg_hs !=0 && arg_hs !=1) {
+    logout << "Warning: \"hs\" argument out of range (" << arg_hs << ")\n";
+    cgiarginfo *hsinfo = argsinfo.getarginfo ("hs");
+    if (hsinfo != NULL) args["hs"] = hsinfo->argdefault;
+  }
+
+  // check ct argument
+  int arg_ct = args.getintarg("ct");
+  if (arg_ct < 0 || arg_ct > 2) {
+    logout << "Warning: \"ct\" argument out of range (" << arg_ct << ")\n";
+    cgiarginfo *ctinfo = argsinfo.getarginfo ("ct");
+    if (ctinfo != NULL) args["ct"] = ctinfo->argdefault;
+  }
+
+  // check qt argument
+  int arg_qt = args.getintarg("qt");
+  if (arg_qt !=0 && arg_qt !=1) {
+    logout << "Warning: \"qt\" argument out of range (" << arg_qt << ")\n";
+    cgiarginfo *qtinfo = argsinfo.getarginfo ("qt");
+    if (qtinfo != NULL) args["qt"] = qtinfo->argdefault;
+  }
+
+  // check qb argument
+  int arg_qb = args.getintarg("qb");
+  if (arg_qb !=0 && arg_qb !=1) {
+    logout << "Warning: \"qb\" argument out of range (" << arg_qb << ")\n";
+    cgiarginfo *qbinfo = argsinfo.getarginfo ("qb");
+    if (qbinfo != NULL) args["qb"] = qbinfo->argdefault;
+  }
+
+  // check fqa argument
+  int arg_fqa = args.getintarg("fqa");
+  if (arg_fqa !=0 && arg_fqa !=1) {
+    logout << "Warning: \"fqa\" argument out of range (" << arg_fqa << ")\n";
+    cgiarginfo *fqainfo = argsinfo.getarginfo ("fqa");
+    if (fqainfo != NULL) args["fqa"] = fqainfo->argdefault;
+  }
+
+  // check fqn argument
+  int arg_fqn = args.getintarg("fqn");
+  if (arg_fqn < -1) {
+    logout << "Warning: \"fqn\" argument less than -1 (" << arg_fqn << ")\n";
+    cgiarginfo *fqninfo = argsinfo.getarginfo ("fqn");
+    if (fqninfo != NULL) args["fqn"] = fqninfo->argdefault;
+  }
+
+  return true;
+}
+
+void queryaction::get_cgihead_info (cgiargsclass &args, recptprotolistclass * /*protos*/,
+				    response_t &response, text_t &response_data, 
+				    ostream &/*logout*/) {
+  // If this is an "I'm feeling lucky" request, we don't know the target location until later
+  if (!args["ifl"].empty()) {
+    response = undecided_location;
+    return;
+  }
+
+  response = content;
+  response_data = "text/html";
+}
+
+void queryaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					  recptprotolistclass * protos, 
+					  ostream &logout) {
+
+  // define_internal_macros sets the following macros:
+
+  // The following macros are set later (in define_query_macros) as they can't be set until 
+  // the query has been done.
+  // _quotedquery_   the part of the query string that was quoted for post-processing
+  // _freqmsg_      the term frequency string
+
+  // _resultline_   the "x documents matched the query" string
+
+  // _prevfirst_    these are used when setting up the links to previous/next
+  // _prevlast_     pages of results (_thisfirst_ and _thislast_ are used to set
+  // _nextfirst_    the 'results x-x for query: xxxx' string in the title bar)
+  // _nextlast_
+  // _thisfirst_
+  // _thislast_
+
+  define_form_macros(disp, args, protos, logout);
+  
+  define_query_interface(disp, args, protos, logout);
+
+}
+
+void queryaction::define_query_interface(displayclass &disp, 
+					 cgiargsclass &args, 
+					 recptprotolistclass * protos, 
+					 ostream &logout){
+  text_t collection = args["c"];
+
+  //check that the protocol is alive
+  recptproto* colproto = protos->getrecptproto (collection, logout);
+  if(colproto == NULL) {
+    logout << "ERROR: Null collection protocol trying to query"
+	   << collection.getcstr() << "\n";
+    return;
+  }
+  
+  //check the collection is responding/in place
+  ColInfoResponse_t *colinfo = recpt->get_collectinfo_ptr(colproto, collection,
+							  logout);
+  if(colinfo == NULL){
+    logout << "ERROR: Null returned for get_collectinfo_ptr on "
+	   << collection.getcstr() << "in queryaction::define_query_interface\n";
+    return;
+  }
+  
+    
+  text_tmap::iterator check = colinfo->format.find("QueryInterface");
+  if(check != colinfo->format.end()){
+    if((*check).second=="DateSearch"){
+      text_t current = "_datesearch_";
+      disp.setmacro("optdatesearch","query",current);
+    }
+  }
+}
+
+
+// sets the selection box macros _hselection_, _jselection_, _nselection_ _gselection_, fqfselection_ 
+void queryaction::set_option_macro (const text_t &macroname, 
+				    text_t current_value, 
+				    bool display_single, 
+				    bool add_js_update,
+				    const FilterOption_t &option, 
+				    displayclass &disp) {
+  
+  if (option.validValues.empty()) return;
+  if (option.validValues.size() == 1) {
+    if (display_single) {
+      disp.setmacro (macroname + "selection", displayclass::defaultpackage, "_" + option.defaultValue + "_");
+    }
+    return;    
+  } 
+  if (option.validValues.size() < 2) return;
+  
+  text_t macrovalue = "<select name=\"" + macroname + "\"";
+  if (add_js_update) {
+    macrovalue += " onChange=\"update"+macroname+"();\"";
+  }
+  macrovalue += ">\n";
+  
+  if (current_value.empty()) current_value = option.defaultValue;
+  
+  text_tarray::const_iterator thisvalue = option.validValues.begin();
+  text_tarray::const_iterator endvalue = option.validValues.end();
+
+  while (thisvalue != endvalue) {
+    macrovalue += "<option value=\"" + *thisvalue + "\"";
+    if (*thisvalue == current_value)
+      macrovalue += " selected";
+    macrovalue += ">_" + *thisvalue + "_\n";
+    ++thisvalue;
+  }
+  macrovalue += "</select>\n";
+  disp.setmacro (macroname + "selection", displayclass::defaultpackage, macrovalue);
+}
+
+
+
+void queryaction::define_external_macros (displayclass &disp, cgiargsclass &args, 
+					  recptprotolistclass *protos, ostream &logout) {
+
+  // define_external_macros sets the following macros:
+
+  // some or all of these may not be required to be set
+  // _hselection_, _h2selection_  the selection box for the main part of the index
+  // _jselection_, _j2selection_  the selection box for the subcollection part of the index
+  // _nselection_, _n2selection_  the selection box for the language part of the index
+  // _cq2selection                the selection box for combining two queries
+  
+  // _gselection_, the selection box forlevels (mgpp)
+  // _fqfselection_, the selection box for index/fields (mgpp)
+  // can't do anything if collectproto is null (i.e. no collection was specified)
+  recptproto *collectproto = protos->getrecptproto (args["c"], logout);
+  if (collectproto == NULL) return;
+
+  comerror_t err;
+  InfoFilterOptionsResponse_t response;
+  InfoFilterOptionsRequest_t request;
+  request.filterName = "QueryFilter";
+  
+  collectproto->get_filteroptions (args["c"], request, response, err, logout);
+  if (err == noError) {
+    
+    FilterOption_tmap::const_iterator it;
+    FilterOption_tmap::const_iterator end = response.filterOptions.end();
+    
+    // _hselection_ and _h2selection_ (Index)
+    it = response.filterOptions.find ("Index");
+    if (it != end) set_option_macro ("h", args["h"], true, false, (*it).second, disp);
+    if (it != end) set_option_macro ("h2", args["h2"], true,false, (*it).second, disp);
+    
+    // _jselection_ and _j2selection_ (Subcollection)
+    it = response.filterOptions.find ("Subcollection");
+    if (it != end) set_option_macro ("j", args["j"], true,false, (*it).second, disp);
+    if (it != end) set_option_macro ("j2", args["j2"], true,false, (*it).second, disp);
+    
+    // _nselection_ and _n2selection_ (Language)
+    it = response.filterOptions.find ("Language");
+    if (it != end) set_option_macro ("n", args["n"], true,false, (*it).second, disp);
+    if (it != end) set_option_macro ("n2", args["n2"], true,false, (*it).second, disp);
+
+    // _cq2selection_ (CombineQuery)
+    it = response.filterOptions.find ("CombineQuery");
+    if (it != end) set_option_macro ("cq2", args["cq2"], true,false, (*it).second, disp);
+
+    if ((args["ct"] == "1") || (args["ct"] == "2"))  { // mgpp/lucene collections
+      // _gselection_ (Level) 
+      it = response.filterOptions.find("Level");
+      if (it!=end) {
+	set_option_macro("g", args["g"], false, false, (*it).second, disp);
+	if (args["qt"]=="1") { // form search
+	  set_gformselection_macro(args["g"], (*it).second, disp);
+	}
+      }
+      // _fqfselection_ field list
+      it = response.filterOptions.find("IndexField");
+      if (it!=end) {
+	if (args["qto"]=="2" || args["qt"]=="1") { // form search
+	  set_option_macro ("fqf", args["fqf"], true, true, (*it).second, disp);
+	} else {
+	  set_option_macro ("fqf", args["fqf"], true, false, (*it).second, disp);
+	}
+      }
+    }
+  }
+} // define external macros
+    
+// sets the selection box macro _gformselection_.
+// the default for _gformselection_ is _gselection_
+void queryaction::set_gformselection_macro (text_t current_value,
+					const FilterOption_t &option,
+					displayclass &disp) {
+  
+  if (option.validValues.size() <= 1) {
+    return;
+  }
+  // we need to check to see if there is paragraph present
+  text_tarray::const_iterator thisvalue = option.validValues.begin();
+  text_tarray::const_iterator endvalue = option.validValues.end();
+
+  bool has_paras = false;
+  while (thisvalue != endvalue) {
+    if (*thisvalue == "Para") {
+      has_paras = true;
+      break;
+    }
+    ++thisvalue;
+  }
+  if (!has_paras) return; // there is no difference between the form selection and the normal one
+
+  if (option.validValues.size() == 2) {
+    // we will only have one value, but we will still put it in as a text string
+    int opt = 0;
+    if (option.validValues[0] == "Para") {
+      opt = 1;
+    }
+    disp.setmacro ("gformselection", displayclass::defaultpackage, "_"+option.validValues[opt]+"_");
+    return;
+  }
+
+  // there will be a select box
+  text_t macrovalue = "<select name=\"g\">\n";
+
+  if (current_value.empty()) current_value = option.defaultValue;
+  
+  thisvalue = option.validValues.begin();
+  
+  while (thisvalue != endvalue) {
+    if (*thisvalue != "Para") {
+      macrovalue += "<option value=\"" + *thisvalue + "\"";
+      if (*thisvalue == current_value)
+	macrovalue += " selected";
+      macrovalue += ">_" + *thisvalue + "_\n";
+    }
+    ++thisvalue;
+  }
+  macrovalue += "</select>\n";
+  disp.setmacro ("gformselection", displayclass::defaultpackage, macrovalue);
+}
+void queryaction::define_form_macros (displayclass &disp, cgiargsclass &args, 
+			   recptprotolistclass *protos, ostream &logout) {
+
+  // defines the following macros
+  // _regformlist_
+  // _advformlist_
+
+  if (args["ct"]=="0" || args["qto"]=="1" || (args["qto"]=="3" && args["qt"] == "0") ) // mg, or mgpp/lucene with plain only, or mgpp with both, but set to plain
+    return; // dont need these macros
+
+  // mgpp & form query only needs the macros defined
+  text_t form = "";
+  int argfqn = args.getintarg("fqn");
+  
+  if (args["qf"] == "1") { // advanced form
+    form += "<tr>_firstadvformelement_</tr>\n";
+    for (int i=1; i<argfqn; ++i) {      
+	form += "<tr>_advformelement_</tr>\n";
+    }
+    disp.setmacro("advformlist", "query", form);
+  }
+  else { // simple form
+    for (int i=0; i<argfqn; ++i) {
+      form += "<tr>_regformelement_</tr>\n"; 
+    }
+    disp.setmacro("regformlist", "query", form);
+  }
+  
+}
+
+void queryaction::define_history_macros (displayclass &disp, cgiargsclass &args, 
+					 recptprotolistclass *protos, ostream &logout) {
+
+  // defines the following macros
+
+  // _searchhistorylist_
+
+  text_t historylist;
+  int arghd = args.getintarg("hd");
+  if (arghd == 0) {
+    historylist="";
+  }
+  else {
+    historylist = "<!-- Search History List -->\n";
+   
+    text_t userid = args["z"];
+    text_tarray entries;
+    if (get_history_info (userid, entries, gdbmhome, logout)) {
+      int count = 1;
+      text_tarray::iterator here = entries.begin();
+      text_tarray::iterator end = entries.end();
+      int numrecords=(int)entries.size();
+      if (numrecords>arghd) { // only display some of them 
+	numrecords = arghd;
+      }
+      historylist += "<form name=\"HistoryForm\"><table width=537>\n";
+
+      for (int i=0; i<numrecords;++i) {
+	text_t query;
+	text_t numdocs;
+	text_t cgiargs;
+	text_t userinfo;
+	text_t escquery;
+	split_saved_query(entries[i],numdocs,cgiargs);
+	parse_saved_args(cgiargs, "q", query); // get query string out
+	decode_cgi_arg(query); // un cgisafe it
+	escquery = escape_quotes(query); // escape the quotes and newlines
+	text_t histvalue = "histvalue";
+	histvalue += i;
+	disp.setmacro(histvalue, "query", escquery);
+	format_user_info(cgiargs, userinfo, args, protos, logout);
+	
+	historylist += "<tr><td align=right>_imagehistbutton_(";
+	historylist += i;
+	historylist += ")</td>\n";
+	historylist += "<td><nobr><table border=1 cellspacing=0 ";
+	historylist += "cellpadding=0><tr><td width=365 align=left>"
+	  + query 
+	  + "</td></tr></table></td><td width=110 align=center><small>"
+	  + numdocs;
+	if (numdocs == 1) historylist += " _texthresult_";
+	else historylist += " _texthresults_";
+	if (!userinfo.empty()) {
+	  historylist += "<br>( "+userinfo+" )</small></td>\n";
+	}
+      }
+      historylist+="</table></form>\n\n";
+     
+    } // if get history info 
+    else {
+      historylist += "_textnohistory_";
+    }
+    historylist += "<p><! ---- end of history list ----->\n";
+  } // else display list
+  disp.setmacro("searchhistorylist", "query", historylist);
+  
+} // define history macros
+
+void queryaction::output_ccp (cgiargsclass &args, recptprotolistclass *protos,
+			      displayclass &disp, outconvertclass &outconvert,
+			      ostream &textout, ostream &logout) {
+
+  ColInfoResponse_t *cinfo = NULL;
+  comerror_t err;
+  InfoFilterOptionsResponse_t fresponse;
+  InfoFilterOptionsRequest_t frequest;
+  frequest.filterName = "QueryFilter";
+
+  text_t &index = args["h"];
+  text_t &subcollection = args["j"];
+  text_t &language = args["n"];
+
+  text_tset collections;
+  text_t arg_cc = args["cc"];
+  decode_cgi_arg (arg_cc);
+  splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
+
+  textout << outconvert << disp << "_query:header_\n"
+	  << "<center>_navigationbar_</center><br>\n"
+	  << "<form name=QueryForm method=get action=\"_gwcgi_\">\n"
+	  << "<input type=hidden name=a value=\"q\">\n"
+          << "<input type=hidden name=site value=\"_cgiargsite_\"\n"
+	  << "<input type=hidden name=e value=\"_compressedoptions_\">\n"
+	  << "<input type=hidden name=ccp value=\"1\">\n"
+	  << "<center><table width=_pagewidth_><tr valign=top>\n"
+	  << "<td>Select collections to search for \"" << args["q"] 
+	  << "\" <i>(index=" << index << " subcollection=" << subcollection
+	  << " language=" << language << ")</i></td>\n"
+	  << "<td><input type=\"submit\" value=\"_query:textbeginsearch_\"></td>\n"
+	  << "</tr></table></center>\n"
+	  << "<center><table width=_pagewidth_>\n"
+	  << "<tr><td>\n";
+  
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+      
+      text_tarray collist;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+	while (collist_here != collist_end) {
+	  
+	  cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
+	  //	  if (err == noError && cinfo.isPublic && (cinfo.buildDate > 0)) {
+	  if (cinfo != NULL && (cinfo->buildDate > 0)) {
+	    
+	    (*rprotolist_here).p->get_filteroptions (*collist_here, frequest, fresponse, err, logout);
+	    if (err == noError) {
+	      
+	      FilterOption_tmap::const_iterator it;
+	      FilterOption_tmap::const_iterator end = fresponse.filterOptions.end();
+	      if (!index.empty()) {
+		it = fresponse.filterOptions.find ("Index");
+		if (it == end) {++collist_here; continue;}
+		text_tarray::const_iterator there = (*it).second.validValues.begin();
+		text_tarray::const_iterator tend = (*it).second.validValues.end();
+		while (there != tend) {
+		  if (*there == index) break;
+		  ++there;
+		}
+		if (there == tend) {++collist_here; continue;}
+	      }
+	      if (!subcollection.empty()) {
+		it = fresponse.filterOptions.find ("Subcollection");
+		if (it == end) {++collist_here; continue;}
+		text_tarray::const_iterator there = (*it).second.validValues.begin();
+		text_tarray::const_iterator tend = (*it).second.validValues.end();
+		while (there != tend) {
+		  if (*there == subcollection) break;
+		  ++there;
+		}
+		if (there == tend) {++collist_here; continue;}
+	      }
+	      if (!language.empty()) {
+		it = fresponse.filterOptions.find ("Language");
+		if (it == end) {++collist_here; continue;}
+		text_tarray::const_iterator there = (*it).second.validValues.begin();
+		text_tarray::const_iterator tend = (*it).second.validValues.end();
+		while (there != tend) {
+		  if (*there == language) break;
+		  ++there;
+		}
+		if (there == tend) {++collist_here; continue;}
+	      }
+	    
+	      // we've got a matching collection
+	      textout << outconvert << "<input type=checkbox";
+
+	      text_tset::const_iterator t = collections.find (*collist_here);
+	      if (t != collections.end()) textout << outconvert << " checked";
+	      
+	      text_t collectionname = cinfo->get_collectionmeta("collectionname", args["l"]);
+	      if (collectionname.empty()) {
+		collectionname = *collist_here;
+	      }
+	      textout << outconvert << disp 
+		      << " name=cc value=\"" << *collist_here << "\">"
+		      << collectionname << "<br>\n";
+
+	      
+	    }
+	  }
+	  ++collist_here;
+	}
+      }
+    }
+    ++rprotolist_here;
+  }
+  textout << outconvert << disp 
+	  << "</td></tr></table></center>\n"
+	  << "</form>\n"
+	  << "_query:footer_\n";
+  
+}
+
+bool queryaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			     browsermapclass *browsers, displayclass &disp, 
+			     outconvertclass &outconvert, ostream &textout, 
+			     ostream &logout) {
+  
+  if (recpt == NULL) {
+    logout << "ERROR (queryaction::do_action): This action does not contain information\n"
+	   << "      about any receptionists. The method set_receptionist was probably\n"
+	   << "      not called from the module which instantiated this action.\n";
+    return true;
+  }
+
+
+
+  if (args["ccs"] == "1") {
+    if (!args["cc"].empty()) {
+      // query the selected collections
+      text_t::const_iterator b = args["cc"].begin();
+      text_t::const_iterator e = args["cc"].end();
+      if (findchar (b, e, ',') != e) {
+	if (!search_multiple_collections (args, protos, browsers, disp, outconvert,
+					  textout, logout)) return false;
+	return true;
+      } else {
+	if (!search_single_collection (args, args["cc"], protos, browsers, disp, 
+				       outconvert, textout, logout)) return false;
+  	return true;
+      }
+    }
+  }
+
+  // simply query the current collection
+  if (!search_single_collection (args, args["c"], protos, browsers, disp, 
+				 outconvert, textout, logout)) return false;
+  return true;
+}
+
+bool queryaction::search_multiple_collections (cgiargsclass &args, recptprotolistclass *protos,
+					       browsermapclass *browsers, displayclass &disp,
+					       outconvertclass &outconvert, ostream &textout,
+					       ostream &logout) {
+
+  text_tarray collections;
+  
+  text_t arg_cc = args["cc"];
+  decode_cgi_arg (arg_cc);
+  splitchar (arg_cc.begin(), arg_cc.end(), ',', collections);
+
+  if (collections.empty()) {
+    logout << "queryaction::search_multiple_collections: No collections "
+	   << "set for doing multiple query - will search current collection\n";
+    textout << outconvert << disp << "_query:textwarningnocollections_\n";
+    return search_single_collection (args, args["c"], protos, browsers, disp, 
+				     outconvert, textout, logout);
+  }
+
+  // queryaction uses "VList" browser to display results,
+  // a queries clasification is "Search"
+  text_t browsertype = "VList";
+  text_t classification = "Search";
+
+  QueryResult_tset results;
+  map<text_t, colinfo_t, lttext_t> colinfomap;
+
+  ColInfoResponse_t *cinfo = NULL;
+  recptproto *collectproto = NULL;
+  comerror_t err;
+  FilterRequest_t request;
+  FilterResponse_t response;
+  request.filterResultOptions = FROID | FRmetadata | FRtermFreq | FRranking;
+  text_t freqmsg = "_textfreqmsg1_";
+  int numdocs = 0;
+  isapprox isApprox = Exact;
+
+  // what to do about segmentation for multiple colls??
+  bool segment = false;
+  text_t formattedstring = "";
+  get_formatted_query_string(formattedstring, segment, args, disp, logout);
+
+  if (formattedstring.empty()) {
+    // dont bother doing a query if no query string
+    define_history_macros (disp, args, protos, logout);
+    textout << outconvert << disp << "_query:header_\n"
+	  << "_query:content_";
+    textout << outconvert << disp << "_query:footer_";
+
+    return true;
+  }
+  bool syntax_error = false;
+
+  set_queryfilter_options (request, formattedstring, args);
+
+  // need to retrieve maxdocs matches for each collection
+  // (will eventually want to tidy this up, do so caching etc.)
+  OptionValue_t option;
+  option.name = "StartResults";
+  option.value = "1";
+  request.filterOptions.push_back (option);
+  
+  option.name = "EndResults";
+  option.value = args["m"];
+  request.filterOptions.push_back (option);
+
+  text_tarray::iterator col_here = collections.begin();
+  text_tarray::iterator col_end = collections.end();
+
+  map<text_t, int, lttext_t> termfreqs;
+  while (col_here != col_end) {
+
+    request.fields.erase (request.fields.begin(), request.fields.end());
+    request.getParents = false;
+
+    collectproto = protos->getrecptproto (*col_here, logout);
+    if (collectproto == NULL) {
+      logout << outconvert << "queryaction::search_multiple_collections: " << *col_here 
+	     << " collection has a NULL collectproto, ignoring\n";
+      ++col_here;
+      continue;
+    }
+    cinfo = recpt->get_collectinfo_ptr (collectproto, *col_here, logout);
+    if (cinfo == NULL) {
+      logout << "ERROR (query_action::search_multiple_collections): get_collectinfo_ptr returned NULL\n";
+      ++col_here;
+      continue;
+    }
+    
+    browserclass *bptr = browsers->getbrowser (browsertype);
+
+    // get the formatstring if there is one 
+    text_t formatstring;
+    if (!get_formatstring (classification, browsertype, 
+			   cinfo->format, formatstring))
+      formatstring = bptr->get_default_formatstring();
+
+    bptr->load_metadata_defaults (request.fields);
+
+    format_t *formatlistptr = new format_t();
+    parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
+
+    colinfo_t thiscolinfo;
+    thiscolinfo.formatlistptr = formatlistptr;
+    thiscolinfo.browserptr = bptr;
+    colinfomap[*col_here] = thiscolinfo;
+    
+    // do the query
+    collectproto->filter (*col_here, request, response, err, logout);
+    if (err != noError && err != syntaxError) {
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii
+	     << "queryaction::search_multiple_collections: call to QueryFilter failed "
+	     << "for " << *col_here << " collection (" << get_comerror_string (err) << ")\n";
+      return false;
+    }
+
+    if (err == syntaxError) {
+      syntax_error = true;
+      freqmsg = "_textinvalidquery_";
+      // assume the syntax will be invalid for all colls
+      break;
+    }
+    if (isApprox == Exact)
+      isApprox = response.isApprox;
+    else if (isApprox == MoreThan)
+      if (response.isApprox == Approximate)
+	isApprox = response.isApprox;
+
+    TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
+    TermInfo_tarray::const_iterator end_term = response.termInfo.end();
+    while (this_term != end_term) {
+      termfreqs[(*this_term).term] += (*this_term).freq;
+      if ((col_here+1) == col_end) {
+	freqmsg += (*this_term).term + ": " + termfreqs[(*this_term).term];
+	if ((this_term+1) != end_term) freqmsg += ", ";
+      }
+      ++this_term;
+    }
+    
+    if (response.numDocs > 0) {
+      numdocs += response.numDocs;
+
+      QueryResult_t thisresult;
+      thisresult.collection = *col_here;
+      ResultDocInfo_tarray::iterator doc_here = response.docInfo.begin();
+      ResultDocInfo_tarray::iterator doc_end = response.docInfo.end();
+      while (doc_here != doc_end) {
+	thisresult.doc = *doc_here;
+	results.insert (thisresult);
+	++doc_here;
+      }
+    }
+    ++col_here;
+  } // for each coll
+
+  disp.setmacro ("freqmsg", "query", freqmsg);
+
+  define_query_macros( args, disp, numdocs, isApprox);
+  // save the query if appropriate
+  save_search_history(args, numdocs, isApprox);
+  define_history_macros (disp, args, protos, logout);
+
+  textout << outconvert << disp << "_query:header_\n"
+	  << "_query:content_";
+
+  if (!syntax_error) {
+    
+    // now go through each result and output it
+    QueryResult_tset::iterator res_here = results.begin();
+    QueryResult_tset::iterator res_end = results.end();
+    text_tset metadata; // empty !!
+    bool getParents = false; // don't care !!
+    bool use_table;
+    ResultDocInfo_t thisdoc;
+    format_t *formatlistptr = NULL;
+    browserclass *browserptr = NULL;
+    
+    int count = 1;
+    int firstdoc = args.getintarg("r");
+    int hitsperpage = args.getintarg("o");
+    int thislast = firstdoc + (hitsperpage - 1);
+    
+    // output results
+    while (res_here != res_end) {
+      if (count < firstdoc) {++count; ++res_here; continue;}
+      if (count > thislast) break;
+      formatlistptr = colinfomap[(*res_here).collection].formatlistptr;
+      browserptr = colinfomap[(*res_here).collection].browserptr;
+      thisdoc = (*res_here).doc;
+      use_table = is_table_content (formatlistptr);
+      
+      collectproto = protos->getrecptproto ((*res_here).collection, logout);
+      if (collectproto == NULL) {
+	logout << outconvert << "queryaction::search_multiple_collections: " << (*res_here).collection
+	       << " collection has a NULL collectproto, ignoring results\n";
+	++res_here;
+	continue;
+      }
+      
+      browserptr->output_section_group (thisdoc, args, (*res_here).collection, 0, 
+					formatlistptr, use_table, metadata, getParents, 
+					collectproto, disp, outconvert, textout, logout);
+      //    textout << outconvert << "(ranking: " << (*res_here).doc.ranking << ")\n";
+      ++res_here;
+      ++count;
+    }
+  }
+  textout << outconvert << disp << "_query:footer_";
+  
+  // clean up the format_t pointers
+  map<text_t, colinfo_t, lttext_t>::iterator here =  colinfomap.begin();
+  map<text_t, colinfo_t, lttext_t>::iterator end =  colinfomap.end();
+  while (here != end) {
+    delete ((*here).second.formatlistptr);
+    ++here;
+  }
+  return true;
+}
+
+bool queryaction::search_single_collection (cgiargsclass &args, const text_t &collection,
+					    recptprotolistclass *protos, browsermapclass *browsers, 
+					    displayclass &disp, outconvertclass &outconvert, 
+					    ostream &textout, ostream &logout) {
+
+  recptproto *collectproto = protos->getrecptproto (collection, logout);
+  if (collectproto == NULL) {
+    logout << outconvert << "queryaction::search_single_collection: " << collection
+	   << " collection has a NULL collectproto\n";
+
+    // Display the "this collection is not installed on this system" page
+    disp.setmacro("cvariable", displayclass::defaultpackage, collection);
+    disp.setmacro("content", "query", "<p>_textbadcollection_<p>");
+
+    textout << outconvert << disp << "_query:header_\n"
+	    << "_query:content_\n" << "_query:footer_\n";
+    return true;
+  }
+
+  // queryaction uses "VList" browser to display results,
+  // a queries clasification is "Search"
+  text_t browsertype = "VList";
+  text_t classification = "Search";
+
+  comerror_t err;
+  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, collection, logout);
+
+  if (cinfo == NULL) {
+    logout << "ERROR (query_action::search_single_collection): get_collectinfo_ptr returned NULL\n";
+    return false;
+  }
+    
+  bool segment = cinfo->isSegmented;
+  browserclass *bptr = browsers->getbrowser (browsertype);
+
+  // get the formatstring if there is one 
+  text_t formatstring;
+  if (!get_formatstring (classification, browsertype, 
+			 cinfo->format, formatstring)) {
+    formatstring = bptr->get_default_formatstring();
+  }
+  FilterRequest_t request;
+  FilterResponse_t response;
+  bptr->set_filter_options (request, args);
+  bptr->load_metadata_defaults (request.fields);
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
+    
+  // do the query
+  request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
+  text_t formattedstring = "";
+  get_formatted_query_string(formattedstring, segment, args, disp, logout);
+
+  if (!formattedstring.empty()) { // do the query
+    // note! formattedstring is in unicode! mg and mgpp must convert!
+    set_queryfilter_options (request, formattedstring, args);
+    collectproto->filter (collection, request, response, err, logout);
+    if (err != noError) {
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii
+	     << "queryaction::search_single_collections: call to QueryFilter failed "
+	     << "for " << collection << " collection (" << get_comerror_string (err) << ")\n";
+     
+    }
+    
+    if (err == noError && !args["ifl"].empty()) {
+      // Go directly to the first matching document
+      ResultDocInfo_tarray::iterator thissection = response.docInfo.begin();
+      if (thissection != response.docInfo.end()) {
+	text_t& arg_d = (*thissection).OID;
+	text_t doc_url = "_httpdocument_";
+	doc_url += "&c=" + collection;
+	doc_url += "&d=" + arg_d;
+
+	// location response (url may contain macros!!)
+	textout << outconvert << disp << "Location: " << doc_url << "\n\n";
+      }
+      // Ooops... there weren't any matching documents
+      else {
+	// Surely there must be a better way to get the query URL without the ifl argument?
+	// This is not complete!
+	text_t query_url = "_gwcgi_";
+	query_url += "?e=" + args["e"];
+	query_url += "&h=" + args["h"];
+	query_url += "&q=" + args["q"];
+	query_url += "&r=" + args["r"];
+	query_url += "&t=" + args["t"];
+	query_url += "&hs=" + args["hs"];
+
+	textout << outconvert << disp << "Location: " << query_url << "\n\n";
+      }
+
+      textout << flush;
+      return true;
+    }
+
+    //return false;
+    if (err != noError) {
+      disp.setmacro("resultline", "query", "_textnodocs_");
+      if (err == syntaxError) {
+	disp.setmacro ("freqmsg", "query", "_textinvalidquery_");
+      } else {
+	disp.setmacro ("freqmsg", "query", "");
+      }
+    } else {
+      
+      define_query_macros (args, disp, response.numDocs, response.isApprox);
+      define_single_query_macros(args, disp, response);
+      // save the query if appropriate
+      save_search_history(args, response.numDocs, response.isApprox);
+    }
+  }
+  define_history_macros (disp, args, protos, logout);
+  
+  textout << outconvert << disp << "_query:header_\n"
+	  << "_query:content_";
+  
+  if (err == noError) {
+    // output the results
+    bool use_table = is_table_content (formatlistptr);
+    bptr->output_section_group (response, args, collection, 0, formatlistptr, 
+				use_table, request.fields, request.getParents, 
+				collectproto, disp, outconvert, textout, logout);
+  }
+
+  textout << outconvert << disp << "_query:footer_";
+  
+  delete (formatlistptr);
+  
+  return true;
+}
+ 
+// does the formatting of the query string - either uses q for a text search
+// or the form values for an form search
+// also adds dates if appropriate in text search
+void queryaction::get_formatted_query_string (text_t &formattedstring, 
+					      bool segment,
+					      cgiargsclass &args, 
+					      displayclass &disp,
+					      ostream &logout) {
+  if (args["qt"]=="0" && args["qto"] != "2") { // normal text search
+    formattedstring = args["q"];
+    // remove & | ! for simple search,do segmentation if necessary
+    format_querystring (formattedstring, args.getintarg("b"), segment);
+    if (args["ct"]!=0) { // mgpp and lucene - need to add in tag info if appropriate
+      format_field_info(formattedstring, args);
+    }
+
+    add_dates(formattedstring, args.getintarg("ds"), args.getintarg("de"),
+	      args.getintarg("dsbc"), args.getintarg("debc"),
+	      args.getintarg("ct"));
+    args["q"] = formattedstring;
+    
+  }
+  else if (args["qt"]=="1" || args["qto"]=="2"){ // form search
+
+    if (args["qf"]=="1" && args["fqa"]=="1") { // explicit query
+      formattedstring = args["q"];
+    }
+    else { // form search
+      if (args["qf"]=="0") { // regular form
+	parse_reg_query_form(formattedstring, args);
+      }
+      else  { // advanced form
+	parse_adv_query_form(formattedstring, args);
+      }
+      args["q"] = formattedstring;
+      
+      // reset the cgiargfqv macro - need to escape any quotes in it
+      disp.setmacro("cgiargfqv", "query", escape_quotes(args["fqv"]));
+
+      // also reset the _cgiargq_ macro as it has changed now
+      disp.setmacro("cgiargq", displayclass::defaultpackage, html_safe(args["q"]));
+      
+      // reset the compressed options to include the q arg
+      text_t compressedoptions = recpt->get_compressed_arg(args, logout);
+      if (!compressedoptions.empty()) {
+	disp.setmacro ("compressedoptions", displayclass::defaultpackage, dm_safe(compressedoptions));
+	// need a decoded version of compressedoptions for use within forms
+	// as browsers encode values from forms before sending to server
+	// (e.g. %25 becomes %2525)
+	decode_cgi_arg (compressedoptions);
+	disp.setmacro ("decodedcompressedoptions", displayclass::defaultpackage, dm_safe(compressedoptions));
+      }
+    } // form search
+  } // args["qt"]=1
+  else {
+    logout << "ERROR (query_action::get_formatted_query_string): querytype not defined\n";
+  }
+}
+
+
+// define_query_macros sets the macros that couldn't be set until the
+// query had been done. Those macros are 
+// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
+// _thisfirst_, and _thislast_ and _quotedquery_ 
+// this has been simplified so it can be used with both search_single_coll
+// and search_multiple_coll
+void queryaction::define_query_macros (cgiargsclass &args, displayclass &disp,
+				       int numdocs, isapprox isApprox) {
+  
+  // set up _resultline_ macro
+  text_t resline;
+  int maxdocs = args.getintarg("m");
+  if (num_phrases > 0) isApprox = Exact;
+  if (maxdocs == -1) maxdocs = numdocs;
+  else if (numdocs > maxdocs) {
+    numdocs = maxdocs;
+    isApprox = MoreThan;
+  }
+
+  if (isApprox == Approximate) resline = "_textapprox_";
+  else if (isApprox == MoreThan) resline = "_textmorethan_";
+  
+  if (numdocs == 0) resline = "_textnodocs_";
+  else if (numdocs == 1) resline += "_text1doc_";
+  else resline += text_t(numdocs) + " _textlotsdocs_";
+  
+  disp.setmacro("resultline", "query", resline);
+
+  int firstdoc = args.getintarg("r");
+  int hitsperpage = args.getintarg("o");
+  if (hitsperpage == -1) hitsperpage = numdocs;
+
+  // set up _thisfirst_ and _thislast_ macros
+  disp.setmacro ("thisfirst", "query", firstdoc);
+  int thislast = firstdoc + (hitsperpage - 1);
+  if (thislast > numdocs) thislast = numdocs;
+  disp.setmacro ("thislast", "query", thislast);
+
+  // set up _prevfirst_ and _prevlast_ macros
+  if (firstdoc > 1) {
+    disp.setmacro ("prevlast", "query", firstdoc - 1);
+    int prevfirst = firstdoc - hitsperpage;
+    if (prevfirst < 1) prevfirst = 1;
+    disp.setmacro ("prevfirst", "query", prevfirst);
+  }
+
+  // set up _nextfirst_ and _nextlast_ macros
+  if (thislast < numdocs) {
+    disp.setmacro ("nextfirst", "query", thislast + 1);
+    int nextlast = thislast + hitsperpage;
+    if (nextlast > numdocs) nextlast = numdocs;
+    disp.setmacro ("nextlast", "query", nextlast);
+  }
+
+  // do quoted query here cos we may have added quotes during query pre-processing
+  if (args["ct"]==0) { // mg queries only, not mgpp
+    // get the quoted bits of the query string and set _quotedquery_
+    text_tarray phrases;
+    get_phrases (args["q"], phrases);
+    num_phrases = phrases.size();
+    text_tarray::const_iterator phere = phrases.begin();
+    text_tarray::const_iterator pend = phrases.end();
+    bool first = true;
+    text_t quotedquery;
+    while (phere != pend) {
+      if (!first)
+	if ((phere +1) == pend) quotedquery += " and ";
+	else quotedquery += ", ";
+      
+      quotedquery += "\"" + *phere + "\"";
+      first = false;
+      ++phere;
+    }
+    if (args.getintarg("s") && !quotedquery.empty()) quotedquery += "_textstemon_";
+    disp.setmacro ("quotedquery", "query", quotedquery);
+  }
+
+}
+
+// define_single_query_macros sets the extra macros for search_single_coll 
+// that couldn't be set until the query had been done. Those macros are 
+// _freqmsg_,
+void queryaction::define_single_query_macros (cgiargsclass &args, 
+					      displayclass &disp, 
+					      const FilterResponse_t &response) {
+  // set up _freqmsg_ macros
+
+  text_t freqmsg = "";
+  freqmsg = "_textfreqmsg1_";
+  TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
+  TermInfo_tarray::const_iterator end_term = response.termInfo.end();
+  while (this_term != end_term) {
+    freqmsg += (*this_term).term + ": " + (*this_term).freq;
+    if ((this_term + 1) != end_term)
+      freqmsg += ", ";
+    ++this_term;
+  }
+  
+  disp.setmacro ("freqmsg", "query", freqmsg);
+}
+
+// should this change for cross coll search??
+bool queryaction::save_search_history (cgiargsclass &args, int numdocs, 
+				       isapprox isApprox) {
+  if (args["q"]=="") return true; // null query, dont save
+  if (args["hs"]=="0") return true; // only save when submit query pressed
+  
+  // get userid
+  text_t userid = args["z"];
+
+  // the number of docs goes on the front of the query string
+  text_t query = text_t(numdocs);
+  if (isApprox==MoreThan) { // there were more docs found
+    query.push_back('+');
+  }
+  query += "c="+args["c"];
+  query += "&h="+args["h"];
+  query += "&t="+args["t"];
+  query += "&b="+args["b"];
+  query += "&j="+args["j"];
+  query += "&n="+args["n"];
+  query += "&s="+args["s"];
+  query += "&k="+args["k"];
+  query += "&g="+args["g"]; 
+  
+  text_t qstring = args["q"];
+  //text_t formattedquery =cgi_safe(qstring);
+  //query += "&q="+formattedquery;
+  query += "&q="+qstring;
+  bool display=false;
+  int hd = args.getintarg("hd");
+  if (hd > 0) display=true;
+  if (set_history_info(userid, query, gdbmhome, display)) return true;
+  else return false;
+
+
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/queryaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/queryaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/queryaction.h	(revision 10506)
@@ -0,0 +1,150 @@
+/**********************************************************************
+ *
+ * queryaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef QUERYACTION_H
+#define QUERYACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+#include "receptionist.h"
+
+struct colinfo_t {
+  void clear();
+  colinfo_t () {clear();}
+
+  format_t *formatlistptr;
+  browserclass *browserptr;
+};
+
+struct QueryResult_t {
+  void clear ();
+  QueryResult_t () {clear();}
+
+  ResultDocInfo_t doc;
+  text_t collection;
+};
+
+struct gteqQueryResult_t 
+{
+  bool operator()(const QueryResult_t &t1, const QueryResult_t &t2) const
+  { return t1.doc.ranking >= t2.doc.ranking; }
+};
+
+typedef set<QueryResult_t, gteqQueryResult_t> QueryResult_tset;
+
+
+class queryaction : public action {
+
+protected:
+
+  receptionist *recpt;
+
+  text_t m_strUseInterfaceLanguageForQuery;
+  text_t formatstring;
+  text_tmap reqfields; // required fields
+  int num_phrases;
+
+  virtual void define_single_query_macros (cgiargsclass &args, 
+					   displayclass &disp, 
+					   const FilterResponse_t &response); 
+  virtual void define_query_macros (cgiargsclass &args, displayclass &disp, 
+			    int numDocs, isapprox isApprox); 
+
+  void get_formatted_query_string (text_t &formattedstring, bool segment, 
+				   cgiargsclass &args, 
+				   displayclass &disp, ostream &logout);
+  void define_query_interface(displayclass &disp, cgiargsclass &args, 
+			      recptprotolistclass *protos, ostream &logout);
+  
+  void define_form_macros (displayclass &disp, cgiargsclass &args, 
+			   recptprotolistclass *protos, ostream &logout);
+
+  void define_history_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  virtual void set_option_macro (const text_t &macroname, text_t current_value,
+				 bool display_single, bool add_js_update,
+			 const FilterOption_t &option, displayclass &disp);
+
+  void set_gformselection_macro (text_t current_value,
+				 const FilterOption_t &option,
+				 displayclass &disp);
+
+  void output_ccp (cgiargsclass &args, recptprotolistclass *protos,
+		   displayclass &disp, outconvertclass &outconvert,
+		   ostream &textout, ostream &logout);
+  
+  bool search_multiple_collections (cgiargsclass &args, 
+				    recptprotolistclass *protos,
+				    browsermapclass *browsers, 
+				    displayclass &disp,
+				    outconvertclass &outconvert, 
+				    ostream &textout,
+				    ostream &logout);
+  
+  virtual bool search_single_collection (cgiargsclass &args, 
+					 const text_t &collection,
+					 recptprotolistclass *protos, 
+					 browsermapclass *browsers, 
+					 displayclass &disp, 
+					 outconvertclass &outconvert, 
+					 ostream &textout, ostream &logout);
+
+
+  bool save_search_history(cgiargsclass &args, int numdocs, isapprox isApprox);
+
+public:
+  queryaction ();
+  virtual ~queryaction () {}
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+  
+  void configure (const text_t &key, const text_tarray &cfgline);
+  bool init (ostream &logout);
+  
+  virtual text_t get_action_name () {return "q";}
+  
+  virtual bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+			      recptprotolistclass *protos, ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+  
+  virtual void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  virtual void define_external_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+  
+  virtual bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/querytools.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/querytools.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/querytools.cpp	(revision 10506)
@@ -0,0 +1,729 @@
+/**********************************************************************
+ *
+ * querytools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "querytools.h"
+#include <ctype.h>
+#include "unitool.h" // for is_unicode_letdig
+
+// request.filterResultOptions and request.fields (if required) should
+// be set from the calling code
+void set_queryfilter_options (FilterRequest_t &request, const text_t &querystring,
+			      cgiargsclass &args) {
+
+  request.filterName = "QueryFilter";
+
+  OptionValue_t option;
+
+  option.name = "Term";
+  option.value = querystring;
+  request.filterOptions.push_back (option);
+
+  option.name = "QueryType";
+  option.value = (args.getintarg("t")) ? "ranked" : "boolean";
+  request.filterOptions.push_back (option);
+
+  option.name = "MatchMode";
+  option.value = (args.getintarg("t")) ? "some" : "all";
+  request.filterOptions.push_back (option);
+
+  option.name = "Casefold";
+  option.value = (args.getintarg("k")) ? "true" : "false";
+  request.filterOptions.push_back (option);
+
+  option.name = "Stem";
+  option.value = (args.getintarg("s")) ? "true" : "false";
+  request.filterOptions.push_back (option);
+
+  if (!args["h"].empty()) {
+    option.name = "Index";
+    option.value = args["h"];
+    request.filterOptions.push_back (option);
+  }
+
+  if (!args["j"].empty()) {
+    option.name = "Subcollection";
+    option.value = args["j"];
+    request.filterOptions.push_back (option);
+  }
+
+  if (!args["n"].empty()) {
+    option.name = "Language";
+    option.value = args["n"];
+    request.filterOptions.push_back (option);
+  }
+  
+  if (!args["g"].empty()) { // granularity for mgpp
+    option.name = "Level";
+    option.value = args["g"];
+    request.filterOptions.push_back (option);
+  }
+
+  set_more_queryfilter_options (request, args);
+}
+
+void set_queryfilter_options (FilterRequest_t &request, const text_t &querystring1,
+			      const text_t &querystring2, cgiargsclass &args) {
+
+  set_queryfilter_options (request, querystring1, args);
+
+  // fill in the second query if needed
+  if (!args["cq2"].empty()) {
+    OptionValue_t option;
+
+    option.name = "CombineQuery";
+    option.value = args["cq2"];
+    request.filterOptions.push_back (option);
+    
+    option.name = "Term";
+    option.value = querystring2;
+    request.filterOptions.push_back (option);
+    
+    option.name = "QueryType";
+    option.value = (args.getintarg("t")) ? "ranked" : "boolean";
+    request.filterOptions.push_back (option);
+
+    option.name = "Casefold";
+    option.value = (args.getintarg("k")) ? "true" : "false";
+    request.filterOptions.push_back (option);
+
+    option.name = "Stem";
+    option.value = (args.getintarg("s")) ? "true" : "false";
+    request.filterOptions.push_back (option);
+
+    if (!args["h2"].empty()) {
+      option.name = "Index";
+      option.value = args["h2"];
+      request.filterOptions.push_back (option);
+    }
+
+    if (!args["j2"].empty()) {
+      option.name = "Subcollection";
+      option.value = args["j2"];
+      request.filterOptions.push_back (option);
+    }
+
+    if (!args["n2"].empty()) {
+      option.name = "Language";
+      option.value = args["n2"];
+      request.filterOptions.push_back (option);
+    }
+  }
+  set_more_queryfilter_options (request, args);
+}
+
+void set_more_queryfilter_options (FilterRequest_t &request, cgiargsclass &args) {
+
+  OptionValue_t option;
+  int arg_m = args.getintarg("m");
+  
+  option.name = "Maxdocs";
+  option.value = arg_m;
+  request.filterOptions.push_back (option);
+
+  //  option.name = "StartResults";
+  //  option.value = args["r"];
+  //  request.filterOptions.push_back (option);
+
+  //  option.name = "EndResults";
+  //  int endresults = args.getintarg("o") + (args.getintarg("r") - 1);
+  //  if ((endresults > arg_m) && (arg_m != -1)) endresults = arg_m;
+  //  option.value = endresults;
+  //  request.filterOptions.push_back (option);
+}
+
+void format_querystring (text_t &querystring, int querymode, bool segment) {
+  text_t formattedstring;
+
+  if (querymode == 1 && !segment) return;
+  
+  text_t::const_iterator here = querystring.begin();
+  text_t::const_iterator end = querystring.end();
+
+  // space is used to insert spaces between Chinese
+  // characters. No space is needed before the first
+  // Chinese character.
+  bool space = false;
+
+  // want to remove ()|!& from querystring so boolean queries are just
+  // "all the words" queries (unless querymode is advanced)
+  while (here != end) {
+    if ((querymode == 0) && (*here == '(' || *here == ')' || *here == '|' ||
+			     *here == '!' || *here == '&')) {
+      formattedstring.push_back(' ');
+    } else if (segment) {
+      if ((*here >= 0x4e00 && *here <= 0x9fa5) ||
+	  (*here >= 0xf900 && *here <= 0xfa2d)) {
+	// Chinese character
+	if (!space) formattedstring.push_back (0x200b); // zero width space
+	formattedstring.push_back (*here);
+	formattedstring.push_back (0x200b);
+	space = true;
+      } else {
+	
+	// non-Chinese character
+	formattedstring.push_back (*here);
+	space = false;
+	
+      }
+    
+    } else {
+      formattedstring.push_back (*here);
+    }
+    ++here;
+  }
+  querystring = formattedstring;
+}
+
+
+	
+void add_dates(text_t &querystring, int startdate, int enddate, 
+	       int startbc, int endbc, int ct)
+{
+  if(startdate)
+    {
+      int querystringis = 0;
+      text_t::const_iterator here = querystring.begin();
+      text_t::const_iterator end = querystring.end();
+      while(here!=end)
+	{
+	  if(!(isspace((*here)))){
+	    here = end;
+	    querystringis = 1;
+	  }
+	  else
+	    ++here;
+	}
+      //converting BCE dates
+      if(startbc && startdate > 0)
+	{
+	  startdate *= -1;
+	}
+      if(endbc && enddate > 0)
+	{
+	  enddate *= -1;
+	}
+       if(enddate != 0 && enddate<startdate)
+	{
+	  cout<<"enddate too small"<<endl;
+	  return;
+	}
+       if(querystringis)
+	 querystring.appendcstr(" AND");
+       if(!enddate)
+	 {
+	   if (ct==1) {
+	     mgpp_adddateelem(querystring,startdate);
+	   }
+	   else { // lucene
+	     lucene_adddateelem(querystring,startdate);
+	   }
+	 }
+       else{
+	 int nextdate = startdate;
+	 querystring.appendcstr(" (");
+	 while(nextdate<=enddate)
+	   {
+	     if(nextdate!=0) {
+	       if (ct==1) {
+		 mgpp_adddateelem(querystring,nextdate);
+	       }
+	       else { // lucene
+		 lucene_adddateelem(querystring,nextdate);
+	       }
+	     }
+	     ++nextdate;
+	   }
+	 querystring.appendcstr(" )");
+       }
+    }
+
+}
+
+void get_phrases (const text_t &querystring, text_tarray &phrases) {
+
+  phrases.erase (phrases.begin(), phrases.end());
+  if (!querystring.empty()) {
+    
+    text_t::const_iterator end = querystring.end();
+    text_t::const_iterator here = findchar (querystring.begin(), end, '"');
+    if (here != end) {
+      text_t tmptext;
+      bool foundquote = false;
+      while (here != end) {
+	if (*here == '"') {
+	  if (foundquote) {
+	    if (!tmptext.empty()) {
+	      phrases.push_back(tmptext);
+	      tmptext.clear();
+	    }
+	    foundquote = false;
+	  } else foundquote = true;
+	} else {
+	  if (foundquote) tmptext.push_back (*here);
+	}
+	++here;
+      }
+    }
+  }
+}
+
+// search history tool 
+// also used for form query macros
+text_t escape_quotes(const text_t &querystring) {
+
+  text_t::const_iterator here = querystring.begin();
+  text_t::const_iterator end = querystring.end();
+ 
+  text_t escquery = "";
+  while (here != end) {
+    if (*here != '\'' && *here != '\"' && *here != '\n' && *here != '\r') escquery.push_back(*here);
+    else if (*here == '\n' || *here == '\r') {
+      escquery.push_back(' ');
+    } else {
+      escquery +="\\\\";
+      escquery.push_back(*here);
+    }
+
+    ++here;
+  }
+  return escquery;
+
+}
+
+// some query form parsing functions for use with mgpp
+
+void parse_reg_query_form(text_t &querystring, cgiargsclass &args)
+{
+  querystring.clear();
+
+  const int ct = args.getintarg("ct");
+  int argt = args.getintarg("t");// t=0 -and, t=1 - or
+
+  text_t combine;
+  if (ct==1) {
+    if (argt == 0) combine = "&";
+    else combine = "|";
+  }
+  else { // lucene
+    if (argt == 0) combine = "AND";
+    else combine = "OR";
+  }
+  
+  text_t field = args["fqf"];
+  if (field.empty()) return; // no query
+  text_tarray fields;
+  splitchar(field.begin(), field.end(), ',', fields); 
+  
+  text_t value = args["fqv"];
+  if (value.empty()) return; // somethings wrong
+  text_tarray values;
+  splitchar(value.begin(), value.end(), ',', values);
+
+
+  for (int i=0; i< values.size(); ++i) {
+    if (!values[i].empty()) {
+      if (ct == 1) {
+	mgpp_addqueryelem(querystring, fields[i], values[i], combine);
+      }
+      else { // lucene
+	lucene_addqueryelem(querystring, fields[i], values[i], combine);
+      }
+    }
+  }
+  
+}
+
+
+void parse_adv_query_form(text_t &querystring, cgiargsclass &args){
+
+  querystring.clear();
+
+  const int ct = args.getintarg("ct");
+  text_t combine;
+  if (ct==1) {
+    combine = "&";
+  }
+  else { // lucene
+    combine = "AND";
+  }
+
+  text_t field = args["fqf"];
+  if (field.empty()) return; // no query
+  text_tarray fields;
+  splitchar(field.begin(), field.end(), ',', fields); 
+  
+  text_t value = args["fqv"];
+  if (value.empty()) return; // somethings wrong
+  text_tarray values;
+  splitchar(value.begin(), value.end(), ',', values);
+
+  text_t stem = args["fqs"];
+  if (stem.empty()) return; // somethings wrong
+  text_tarray stems;
+  splitchar(stem.begin(), stem.end(), ',', stems);
+
+  text_t fold = args["fqk"];
+  if (fold.empty()) return; // somethings wrong
+  text_tarray folds;
+  splitchar(fold.begin(), fold.end(), ',', folds);
+
+  text_t comb = args["fqc"];
+  if (comb.empty()) return; //somethings wrong
+  text_tarray combs;
+  splitchar(comb.begin(), comb.end(), ',', combs);
+  
+  for(int i=0; i< values.size(); ++i) {
+    if (!values[i].empty()) {
+      if (i!=0) {
+	if (ct==1) {
+	  if (combs[i-1]=="and") combine = "&";
+	  else if (combs[i-1]=="or")combine = "|";
+	  else if (combs[i-1]=="not")combine = "!";
+	}
+	else { // lucene
+	  if (combs[i-1]=="and") combine = "AND";
+	  else if (combs[i-1]=="or")combine = "OR";
+	  else if (combs[i-1]=="not")combine = "NOT";
+	}
+      }
+      text_t term = addstemcase(values[i], stems[i], folds[i]);
+      mgpp_addqueryelem(querystring, fields[i], term, combine);
+    }
+    
+  }
+}
+
+text_t addstemcase(const text_t &terms, const text_t &stem, const text_t &fold) {
+  
+  text_t outtext;
+  text_t word;
+  //unsigned short c;                                                            
+  text_t::const_iterator here = terms.begin();
+  text_t::const_iterator end = terms.end();
+
+  while (here !=end) {
+
+    if (is_unicode_letdig(*here)) {
+      // not word boundary
+      word.push_back(*here);
+      ++here;    
+    }
+    else {
+      // found word boundary   
+      if (!word.empty() ) {
+	if (stem == "1" || fold =="1") {
+	  word += "#";
+	  if (stem == "1") word += "s";
+	  //else word += "u";
+	  
+	  if (fold == "1") word += "i";
+	  //else word += "c";
+	}
+	
+	word += " ";
+	outtext += word;
+	word.clear();
+      }
+      if (*here == '\"') {
+	outtext.push_back(*here);
+      }
+      ++here;
+    }
+  }
+   
+  // get last word
+  if (!word.empty()) {
+    if (stem == "1"|| fold == "1") {
+      word += "#";
+      if (stem == "1") word += "s";
+      //else word += "u";
+      
+      if (fold == "1") word += "i";
+      //else word += "c";
+    }
+    word += " ";
+    outtext += word;
+  }
+  return outtext;
+}
+
+
+void mgpp_adddateelem(text_t& querystring, const int date)
+{
+  querystring.appendcstr(" [");
+  if(date<0) {
+      querystring.appendcstr("bc");
+      querystring.appendint((date*-1));
+  }
+  else {
+    querystring.appendint(date);
+  }
+  querystring.appendcstr("]:CV");
+}
+
+void lucene_adddateelem(text_t& querystring, const int date)
+{
+  querystring.appendcstr(" CV:(");
+  if(date<0) {
+      querystring.appendcstr("bc");
+      querystring.appendint((date*-1));
+  }
+  else {
+    querystring.appendint(date);
+  }
+  querystring.appendcstr(")");
+}
+
+
+void mgpp_addqueryelem(text_t &querystring, text_t &tag, 
+		  text_t &query, text_t &combine) {
+  if (!querystring.empty()) { // have to put and/or
+    querystring += " " + combine + " ";
+ 
+  }
+  if (tag=="ZZ" || tag=="") { // just add onto querystring
+       querystring +=  query;
+  }
+  else {
+    querystring += "["+query+"]:"+tag;
+  }
+
+}
+
+void lucene_addqueryelem(text_t &querystring, text_t &tag, 
+		  text_t &query, text_t &combine) {
+  if (!querystring.empty()) { // have to put and/or
+    querystring += " " + combine + " ";
+ 
+  }
+  if (tag=="ZZ" || tag=="") { // just add onto querystring
+       querystring +=  query;
+  }
+  else {
+    querystring += tag+":("+query+")";
+  }
+}
+
+
+void addqueryelem_ex(text_t &querystring, const text_t &tag, 
+		     const text_t &terms, const text_t &stem, const text_t &fold,
+		     const text_t& combine, const text_t& word_combine) {
+  if (!querystring.empty()) { // have to put and/or
+    querystring += " " + combine + " ";
+  }
+  text_t outtext; outtext.reserve(512);
+  text_t word; word.reserve(100);
+  //unsigned short c;                                                            
+  text_t::const_iterator here = terms.begin();
+  text_t::const_iterator end = terms.end();
+  bool inquote = false, firstword = true;
+
+  text_t word2; word2.reserve(256);
+	
+  while (here !=end) {
+    if (is_unicode_space(*here)) {
+      if (word2 == "AND") { word2.clear(); word2.push_back(7527); word2.appendcarr("AND", 3); word2.push_back(7527); }
+      else if (word2 == "OR") { word2.clear(); word2.push_back(7527); word2.appendcarr("OR", 2); word2.push_back(7527); }
+      else if (word2 == "NOT") { word2.clear(); word2.push_back(7527); word2.appendcarr("NOT", 3); word2.push_back(7527); }
+      else if (word2 == "NEAR") { word2.clear(); word2.push_back(7527); word2.appendcarr("NEAR", 4); word2.push_back(7527); }
+      else if (word2 == "WITHIN") { word2.clear(); word2.push_back(7527); word2.appendcarr("WITHIN", 6); word2.push_back(7527); }
+      if (inquote) {
+	word2.push_back(*here);
+      }
+      word.append(word2); word2.clear();
+			
+      if (!inquote && !word.empty() ) {
+				// found word boundary   
+				
+	if (stem == "1" || fold =="1") {
+	  word += "#";
+	  if (stem == "1") word += "s";
+	  //else word += "u";
+					
+	  if (fold == "1") word += "i";
+	  //else word += "c";
+	}
+	if (firstword) {
+	  firstword = false;
+	} else {
+	  outtext += " " + word_combine + " ";
+	}
+	outtext += "[" + word + "]:"+tag;
+	word.clear();
+      }
+      ++here;
+    } else if (*here == '\"') {
+      word2.push_back(*here);
+      inquote = !inquote;
+      ++here;
+    } else {
+      // not word boundary
+      word2.push_back(*here);
+      ++here;    
+    }
+  }
+	
+  // get last word
+  if (!word2.empty()) {
+    if (word2 == "AND") { word2.clear(); word2.push_back(7527); word2.appendcarr("AND", 3); word2.push_back(7527); }
+    else if (word2 == "OR") { word2.clear(); word2.push_back(7527); word2.appendcarr("OR", 2); word2.push_back(7527); }
+    else if (word2 == "NOT") { word2.clear(); word2.push_back(7527); word2.appendcarr("NOT", 3); word2.push_back(7527); }
+    else if (word2 == "NEAR") { word2.clear(); word2.push_back(7527); word2.appendcarr("NEAR", 4); word2.push_back(7527); }
+    else if (word2 == "WITHIN") { word2.clear(); word2.push_back(7527); word2.appendcarr("WITHIN", 6); word2.push_back(7527); }
+    word.append(word2); word2.clear();
+		
+    if (stem == "1"|| fold == "1") {
+      word += "#";
+      if (stem == "1") word += "s";
+      //else word += "u";
+			
+      if (fold == "1") word += "i";
+      //else word += "c";
+    }
+    if (!outtext.empty()) outtext += " " + word_combine + " ";
+    outtext += "[" + word + "]:"+tag;
+  }
+  querystring += "(" + outtext + ")";
+}
+
+
+void add_field_info(text_t &querystring, const text_t &tag, int type) {
+
+  if (type == 1) { //mgpp
+    querystring = "["+querystring+"]:"+tag;
+  } else if (type == 2) { // lucene
+    querystring = tag+":("+querystring+")";
+  }
+    
+}
+
+
+void format_field_info(text_t &querystring, cgiargsclass &args) {
+  
+  text_t tag = args["fqf"];
+  if (tag == "ZZ" || tag == "") {
+    return; // do nothing
+  }
+  
+  int argct = args.getintarg("ct");
+  int argt = args.getintarg("t");// t=0 -and, t=1 - or
+  int argb = args.getintarg("b"); // b=0 simple, b=1 advanced
+
+  // Special code for Lucene
+  // The default operator for Lucene is "or", so we need to add "+" symbols when t == 0
+  // Also, we need to be careful not to mess up phrase searches
+  if (argct == 2) {
+    text_t processed_querystring = "";
+    text_t queryelement = "";
+    text_t combine = ((argt == 0) ? "+" : "");
+    bool in_phrase = false;
+    text_t::const_iterator here = querystring.begin();
+    text_t::const_iterator end = querystring.end();
+    while (here != end) {
+      if (is_unicode_letdig(*here)) {
+	queryelement.push_back(*here);
+      }
+
+      // Detect phrase starts/finishes
+      else if (*here == '"') {
+	queryelement.push_back(*here);
+	if (in_phrase == false) in_phrase = true;
+	else if (in_phrase == true) {
+	  add_field_info(queryelement, tag, argct);
+	  processed_querystring += combine + queryelement;
+	  queryelement.clear();
+	  in_phrase = false;
+	}
+      }
+
+      // Found word boundary
+      else if (in_phrase) {
+	queryelement.push_back(*here);
+      }
+      else {
+	if (!queryelement.empty()) {
+	  add_field_info(queryelement, tag, argct);
+	  processed_querystring += combine + queryelement;
+	  queryelement.clear();
+	}
+	processed_querystring.push_back(*here);
+      }
+
+      ++here;
+    }
+
+    // Get last element
+    if (!queryelement.empty()) {
+      add_field_info(queryelement, tag, argct);
+      processed_querystring += combine + queryelement;
+    }
+
+    querystring = processed_querystring;
+    return;
+  }
+
+  if (argb==0 && argt==0) {
+    // simple 'and' search - just put tag info round whole query string
+    add_field_info(querystring, tag, argct);
+    return;
+  }
+  
+  // we need to individually tag words
+  text_t outtext;
+  text_t word;
+  //unsigned short c;                                                            
+  text_t::const_iterator here = querystring.begin();
+  text_t::const_iterator end = querystring.end();
+
+  while (here !=end) {
+
+    if (is_unicode_letdig(*here)|| *here == '#' || *here == '/' ) {
+      // include term modifiers in a word just in case
+      // not word boundary
+      word.push_back(*here);
+      ++here;    
+    }
+    else {
+      // found word boundary   
+      if (!word.empty() ) {
+	add_field_info(word, tag, argct);
+	outtext += word;
+	word.clear();
+      } 
+      // everything else, we add into the query string
+      outtext.push_back(*here);
+      ++here;
+    }
+  }
+   
+  // get last word
+  if (!word.empty()) {
+    add_field_info(word, tag, argct);
+    outtext += word;
+  }
+
+  querystring =  outtext;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/querytools.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/querytools.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/querytools.h	(revision 10506)
@@ -0,0 +1,71 @@
+/**********************************************************************
+ *
+ * querytools.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef QUERYTOOLS_H
+#define QUERYTOOLS_H
+
+#include "cgiargs.h"
+#include "recptproto.h"
+
+void set_queryfilter_options (FilterRequest_t &request, const text_t &querystring,
+			      cgiargsclass &args);
+
+void set_queryfilter_options (FilterRequest_t &request, const text_t &querystring1,
+			      const text_t &querystring2, cgiargsclass &args);
+
+// don't hassle the function name ... it's been a long day ;)
+void set_more_queryfilter_options (FilterRequest_t &request, cgiargsclass &args);
+
+void format_querystring (text_t &querystring, int querymode, bool segment);
+
+void add_dates(text_t &querystring, int startdate, int enddate, 
+	       int startbc, int endbc, int ct);
+
+void get_phrases (const text_t &querystring, text_tarray &phrases);
+
+void add_ands(text_t& querystring, int querytype);
+
+// search history tool
+text_t escape_quotes(const text_t &querystring);
+
+// some query parsing functions for form processing (only for mgpp collections)
+void parse_reg_query_form(text_t &formattedstring, cgiargsclass &args);
+void parse_adv_query_form(text_t &formattedstring, cgiargsclass &args);
+
+void mgpp_adddateelem(text_t& querystring, const int date);
+void lucene_adddateelem(text_t& querystring, const int date);
+
+void mgpp_addqueryelem(text_t &querystring, text_t &tag, 
+		  text_t &query, text_t &combine);
+void lucene_addqueryelem(text_t &querystring, text_t &tag, 
+		  text_t &query, text_t &combine);
+void addqueryelem_ex(text_t &querystring, const text_t &tag, 
+		     const text_t &terms, const text_t &stem, const text_t &fold,
+		     const text_t& combine, const text_t& word_combine);
+text_t addstemcase(const text_t &terms, const text_t &stem, const text_t &fold);
+text_t formatelem(text_t &text);
+void format_field_info(text_t &querystring, cgiargsclass &args);
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/receptionist.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/receptionist.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/receptionist.cpp	(revision 10506)
@@ -0,0 +1,1664 @@
+/**********************************************************************
+ *
+ * receptionist.cpp -- a web interface for the gsdl
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+// following line required to get fstream.filedesc() on darwin (Mac OS X)
+// gcc 2.91 automatically defines this in stream.h
+#define _STREAM_COMPAT  1
+
+#include "receptionist.h"
+#include "fileutil.h"
+#include "cgiutils.h"
+#include "htmlutils.h"
+#include "gsdltools.h"
+#include "gsdltimes.h"
+#include "OIDtools.h"
+#include <assert.h>
+#include <time.h>
+#include <stdio.h> // for open()
+#include <fcntl.h> // for open() flags
+// following 2 are for printing Last-Modified http header.
+#include <sys/stat.h>
+#include <time.h>
+
+#if defined (GSDL_USE_IOS_H)
+#include <fstream.h>
+#else 
+#include <fstream>
+#endif
+
+void recptconf::clear () {
+  gsdlhome.clear();
+  gdbmhome.clear();
+  collectinfo.erase(collectinfo.begin(), collectinfo.end());
+  collection.clear();
+  collectdir.clear();
+  httpprefix.clear();
+  httpimg = "/images";
+  gwcgi.clear();
+  macrofiles.erase(macrofiles.begin(), macrofiles.end());
+  saveconf.clear();
+  usecookies = false;
+  logcgiargs = false;
+  LogDateFormat = LocalTime;
+
+  maintainer.clear();
+  MailServer.clear();
+  LogEvents = Disabled;
+  EmailEvents = Disabled;
+  EmailUserEvents = false;
+
+  languages.erase(languages.begin(), languages.end());
+  encodings.erase(encodings.begin(), encodings.end());
+
+  site_auth = false;
+  HomePageType = "images";
+  HomePageCols = 3;
+  
+  // these default page parameters can always be overriden
+  // in the configuration file
+  pageparams.erase(pageparams.begin(), pageparams.end());
+  pageparams["c"] = ""; 
+  pageparams["l"] = "en"; 
+
+#ifdef MACROPRECEDENCE
+  macroprecedence = MACROPRECEDENCE;
+#else
+  macroprecedence.clear();
+#endif
+}
+
+void collectioninfo_t::clear () {
+  gsdl_gsdlhome.clear();
+  gsdl_gdbmhome.clear();
+
+  info_loaded = false;
+  info.clear();
+}
+
+void languageinfo_t::clear () {
+  longname.clear();
+  defaultencoding.clear();
+}
+
+receptionist::receptionist () {
+  // create a list of cgi arguments
+  // this must be done before the configuration
+
+  cgiarginfo ainfo;
+
+  ainfo.shortname = "e";
+  ainfo.longname = "compressed arguments";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::good;
+  ainfo.argdefault = g_EmptyText;
+  ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, ainfo);
+
+  ainfo.shortname = "a";
+  ainfo.longname = "action";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::none;
+  ainfo.argdefault = g_EmptyText;
+  ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, ainfo);
+
+  // w=western
+  ainfo.shortname = "w";
+  ainfo.longname = "encoding";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::none;
+  ainfo.argdefault = g_EmptyText;
+  ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, ainfo);
+  
+  ainfo.shortname = "nw";
+  ainfo.longname = "new encoding";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::none;
+  ainfo.argdefault = g_EmptyText;
+  ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, ainfo);
+  
+  ainfo.shortname = "c";
+  ainfo.longname = "collection";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::none;
+  ainfo.argdefault = g_EmptyText;
+  ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, ainfo);
+  
+  // the interface language name should use the ISO 639
+  // standard
+  ainfo.shortname = "l";
+  ainfo.longname = "interface language";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::weak;
+  ainfo.argdefault = "en";
+  ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, ainfo);
+  
+  ainfo.shortname = "nl";
+  ainfo.longname = "new language";
+  ainfo.multiplechar = false;
+  ainfo.defaultstatus = cgiarginfo::none;
+  ainfo.argdefault = "0";
+  ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, ainfo);
+  
+  // the GSDL_UID (cookie)
+  ainfo.shortname = "z";
+  ainfo.longname = "gsdl uid";
+  ainfo.multiplechar = true;
+  ainfo.defaultstatus = cgiarginfo::none;
+  ainfo.argdefault = g_EmptyText;
+  ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, ainfo);
+}
+
+
+void receptionist::add_action (action *theaction) {
+  // make sure we have an action to add
+  if (theaction == NULL) return;
+
+  // add this action to the list of actions
+  actions.addaction(theaction);
+  
+  // add the cgi arguments from this action
+  argsinfo.addarginfo (NULL, theaction->getargsinfo());
+}
+
+
+void receptionist::add_browser (browserclass *thebrowser) {
+  // make sure we have a browser to add
+  if (thebrowser == NULL) return;
+
+  // add this browser to the list of browsers
+  browsers.addbrowser(thebrowser);
+}
+
+
+void receptionist::setdefaultbrowser (const text_t &browsername) {
+  browsers.setdefaultbrowser (browsername);
+}
+
+
+// configure should be called for each line in the
+// configuration files to configure the receptionist and everything
+// it contains. The configuration should take place after everything
+// has been added but before the initialisation.
+
+void receptionist::configure (const text_t &key, const text_tarray &cfgline) {
+  // configure the receptionist
+
+   
+   
+  if (cfgline.size() >= 1) {
+    cgiarginfo *info = NULL;
+    if (key == "gsdlhome") {
+      configinfo.gsdlhome = cfgline[0];
+      if (configinfo.gdbmhome.empty()) configinfo.gdbmhome = cfgline[0];
+    }
+    else if (key == "gdbmhome") configinfo.gdbmhome = cfgline[0];
+    else if (key == "collection") {
+      configinfo.collection = cfgline[0];
+      // also need to set the default arg to this collection
+      if ((info = argsinfo.getarginfo("c")) != NULL) {
+	info->defaultstatus = cgiarginfo::good;
+	info->argdefault = cfgline[0];
+      }
+      
+    } else if (key == "collectdir") configinfo.collectdir = cfgline[0];
+    else if (key == "httpprefix") configinfo.httpprefix = cfgline[0];
+    else if (key == "httpimg") configinfo.httpimg = cfgline[0];
+    else if (key == "gwcgi") configinfo.gwcgi = cfgline[0];
+    else if (key == "macrofiles") {
+      // want to append to macrofiles (i.e. may be several config files
+      // contributing, maybe from several collections).
+      text_tarray::const_iterator here = cfgline.begin();
+      text_tarray::const_iterator end = cfgline.end();
+      while (here != end) {
+	configinfo.macrofiles.insert (*here);
+	++here;
+      }
+    }
+    else if (key == "saveconf") configinfo.saveconf = cfgline[0];
+    else if (key == "usecookies") configinfo.usecookies = (cfgline[0] == "true");
+    else if (key == "logcgiargs") configinfo.logcgiargs = (cfgline[0] == "true");
+    else if (key == "maintainer") configinfo.maintainer = cfgline[0];
+    else if (key == "MailServer") configinfo.MailServer = cfgline[0];
+    else if (key == "LogDateFormat") {
+      if (cfgline[0] == "UTCTime") configinfo.LogDateFormat = UTCTime;
+      else if (cfgline[0] == "Absolute") configinfo.LogDateFormat = Absolute;
+    } 
+    else if (key == "LogEvents") {
+      if (cfgline[0] == "CollectorEvents") configinfo.LogEvents = CollectorEvents;
+      else if (cfgline[0] == "AllEvents") configinfo.LogEvents = AllEvents;
+    } 
+    else if (key == "EmailEvents") {
+      if (cfgline[0] == "CollectorEvents") configinfo.EmailEvents = CollectorEvents;
+      else if (cfgline[0] == "AllEvents") configinfo.EmailEvents = AllEvents;
+    } 
+    else if (key == "EmailUserEvents") configinfo.EmailUserEvents = (cfgline[0] == "true");
+    else if (key == "pageparam") {
+      if (cfgline.size() >= 2) configinfo.pageparams[cfgline[0]] = cfgline[1];
+      else configinfo.pageparams[cfgline[0]] = "";
+    }
+    else if (key == "macroprecedence") configinfo.macroprecedence = cfgline[0];
+    else if (key == "collectinfo") {
+      if (cfgline.size() >= 3) {
+	collectioninfo_t cinfo;
+	cinfo.gsdl_gsdlhome = cfgline[1];
+	cinfo.gsdl_gdbmhome = cfgline[2];
+	configinfo.collectinfo[cfgline[0]] = cinfo;
+      }
+    }
+
+    // Read in the value for the site_auth directive either true or false
+    else if (key == "site_auth") configinfo.site_auth = (cfgline[0] == "true");
+
+    else if (key == "site_group")
+       joinchar(cfgline,',',configinfo.site_group);
+       
+    else if (key == "SiteFormat") {
+       if (cfgline[0] == "HomePageType") {
+	  configinfo.HomePageType = cfgline[1];
+       } else if (cfgline[0] == "HomePageCols") {
+	  configinfo.HomePageCols = cfgline[1].getint();
+       }
+    }
+       
+    else if (key == "cgiarg") {
+      // get shortname
+      bool seen_defaultstatus = false;
+      text_t subkey, subvalue;
+      text_t shortname;
+      text_t::const_iterator cfglinesub_here;
+      text_tarray::const_iterator cfgline_here = cfgline.begin();
+      text_tarray::const_iterator cfgline_end = cfgline.end();
+      while (cfgline_here != cfgline_end) {
+	cfglinesub_here = getdelimitstr((*cfgline_here).begin(),
+					(*cfgline_here).end(), '=', subkey);
+	if (subkey == "shortname") {
+	  shortname = substr (cfglinesub_here, (*cfgline_here).end());
+	}
+	++cfgline_here;
+      }
+
+      // if we found the shortname process the line again filling in values
+      if (!shortname.empty()) {
+	cgiarginfo &chinfo = argsinfo[shortname];
+	chinfo.shortname = shortname; // in case this is a new argument
+	
+	cfgline_here = cfgline.begin();
+	while (cfgline_here != cfgline_end) {
+	  cfglinesub_here = getdelimitstr((*cfgline_here).begin(),
+					  (*cfgline_here).end(), '=', subkey);
+	  subvalue = substr (cfglinesub_here, (*cfgline_here).end());
+
+	  if (subkey == "longname") chinfo.longname = subvalue;
+	  else if (subkey == "multiplechar") chinfo.multiplechar = (subvalue == "true");
+	  else if (subkey == "defaultstatus") {
+	    seen_defaultstatus = true;
+	    if (subvalue == "none") chinfo.defaultstatus = cgiarginfo::none;
+	    else if (subvalue == "weak") chinfo.defaultstatus = cgiarginfo::weak;
+	    else if (subvalue == "good") chinfo.defaultstatus = cgiarginfo::good;
+	    else if (subvalue == "config") chinfo.defaultstatus = cgiarginfo::config;
+	    else if (subvalue == "imperative") chinfo.defaultstatus = cgiarginfo::imperative;
+	  }
+	  else if (subkey == "argdefault") {
+	    chinfo.argdefault = subvalue;
+	    if (!seen_defaultstatus) chinfo.defaultstatus = cgiarginfo::config;
+	  }
+	  else if (subkey == "savedarginfo") {
+	    if (subvalue == "mustnot") chinfo.savedarginfo = cgiarginfo::mustnot;
+	    else if (subvalue == "can") chinfo.savedarginfo = cgiarginfo::can;
+	    else if (subvalue == "must") chinfo.savedarginfo = cgiarginfo::must;
+	  }
+	  
+	  ++cfgline_here;
+	}
+      }
+
+    } else if (key == "Encoding") {
+
+      configure_encoding (cfgline);
+
+    } else if (key == "Language") {
+      text_t subkey, subvalue, shortname;
+      languageinfo_t lang;
+      text_t::const_iterator cfglinesub_here;
+      text_tarray::const_iterator cfgline_here = cfgline.begin();
+      text_tarray::const_iterator cfgline_end = cfgline.end();
+      while (cfgline_here != cfgline_end) {
+	cfglinesub_here = getdelimitstr((*cfgline_here).begin(),
+					(*cfgline_here).end(), '=', subkey);
+	if (subkey == "shortname") {
+	  shortname = substr (cfglinesub_here, (*cfgline_here).end());
+	} else if (subkey == "longname") {
+	  lang.longname = substr (cfglinesub_here, (*cfgline_here).end());
+	} else if (subkey == "default_encoding") {
+	  lang.defaultencoding = substr (cfglinesub_here, (*cfgline_here).end());
+	}
+	++cfgline_here;
+      }
+      if (!shortname.empty()) {
+	if (lang.longname.empty()) lang.longname = shortname;
+	configinfo.languages[shortname] = lang;
+      }
+    }
+  }
+  
+  // configure the actions
+  actionptrmap::iterator actionhere = actions.begin ();
+  actionptrmap::iterator actionend = actions.end ();
+
+  while (actionhere != actionend) {
+    assert ((*actionhere).second.a != NULL);
+    if ((*actionhere).second.a != NULL) 
+      (*actionhere).second.a->configure(key, cfgline);
+
+    ++actionhere;
+  }
+
+  // configure the protocols
+  recptprotolistclass::iterator protohere = protocols.begin ();
+  recptprotolistclass::iterator protoend = protocols.end ();
+
+  while (protohere != protoend) {
+    assert ((*protohere).p != NULL);
+    comerror_t err;
+    if ((*protohere).p != NULL) 
+      (*protohere).p->configure(key, cfgline, err);
+    
+    ++protohere;
+  }
+
+  // configure the browsers
+  browserptrmap::iterator browserhere = browsers.begin ();
+  browserptrmap::iterator browserend = browsers.end ();
+
+  while (browserhere != browserend) {
+    assert ((*browserhere).second.b != NULL);
+    if ((*browserhere).second.b != NULL) 
+      (*browserhere).second.b->configure(key, cfgline);
+    
+    ++browserhere;
+  }
+}
+
+
+void receptionist::configure (const text_t &key, const text_t &value) {
+  text_tarray cfgline;
+  cfgline.push_back (value);
+  configure(key, cfgline);
+}
+
+
+// init should be called after all the actions and protocols have been
+// added to the receptionist and after everything has been configured but
+// before any pages are created.  It returns true on success and false on
+// failure. If false is returned getpage should not be called (without
+// producing meaningless output), instead an error page should be produced
+// by the calling code.
+bool receptionist::init (ostream &logout) {
+
+  // first configure collectdir
+  text_t thecollectdir = configinfo.gsdlhome;
+  if (!configinfo.collection.empty()) {
+    // collection specific mode
+    if (!configinfo.collectdir.empty()) {
+      // has already been configured
+      thecollectdir = configinfo.collectdir;
+    } else {
+      // decide where collectdir is by searching for collect.cfg
+      // look in $GSDLHOME/collect/collection-name/etc/collect.cfg and
+      // then $GSDLHOME/etc/collect.cfg
+      thecollectdir = filename_cat (configinfo.gsdlhome, "collect");
+      thecollectdir = filename_cat (thecollectdir, configinfo.collection);
+      text_t filename = filename_cat (thecollectdir, "etc");
+      filename = filename_cat (filename, "collect.cfg");
+
+      if (!file_exists(filename)) thecollectdir = configinfo.gsdlhome;
+    }
+  }
+  configure("collectdir", thecollectdir);
+
+  // read in the macro files
+  if (!read_macrofiles (logout)) return false;
+
+  // there must be at least one action defined
+  if (actions.empty()) {
+    logout << "Error: no actions have been added to the receptionist\n";
+    return false;
+  }
+
+  // there must be at least one browser defined
+  if (browsers.empty()) {
+    logout << "Error: no browsers have been added to the receptionist\n";
+    return false;
+  }
+
+  // create a saveconf string if there isn't one already
+  if (configinfo.saveconf.empty())
+    configinfo.saveconf = create_save_conf_str (argsinfo, logout);
+
+  // check the saveconf string
+  if (!check_save_conf_str (configinfo.saveconf, argsinfo, logout))
+    return false;
+
+  // set a random seed
+  srand (time(NULL));
+
+  // if maintainer email address is something dodgy (for now I'll define
+  // dodgy as being anything that doesn't contain '@') disable EmailEvents
+  // and EmailUserEvents (we don't strictly need to disable EmailUserEvents
+  // in this case but we will as it seems likely that MailServer will also
+  // be screwed up if maintainer is).
+  text_t::const_iterator maintainer_end = configinfo.maintainer.end ();
+  text_t::const_iterator maintainer_here = findchar ((text_t::const_iterator)configinfo.maintainer.begin(),
+						     maintainer_end, '@');
+  if (maintainer_here == maintainer_end) {
+    configinfo.EmailEvents = Disabled;
+    configinfo.EmailUserEvents = Disabled;
+  } else {
+    // if MailServer isn't set it should default to mail.maintainer-domain
+    if (configinfo.MailServer.empty()) {
+      configinfo.MailServer = "mail." + substr (maintainer_here+1, maintainer_end);
+    }
+  }
+
+  // init the actions
+  actionptrmap::iterator actionhere = actions.begin ();
+  actionptrmap::iterator actionend = actions.end ();
+  while (actionhere != actionend) {
+    if (((*actionhere).second.a == NULL) || 
+	!(*actionhere).second.a->init(logout)) return false;
+    ++actionhere;
+  }
+
+  // init the protocols
+  recptprotolistclass::iterator protohere = protocols.begin ();
+  recptprotolistclass::iterator protoend = protocols.end ();
+  while (protohere != protoend) {
+    comerror_t err;    
+    if (((*protohere).p == NULL) ||
+	!(*protohere).p->init(err, logout)) return false;
+    ++protohere;
+  }
+
+  // init the browsers
+  browserptrmap::iterator browserhere = browsers.begin ();
+  browserptrmap::iterator browserend = browsers.end ();
+  while (browserhere != browserend) {
+    if (((*browserhere).second.b == NULL) || 
+	!(*browserhere).second.b->init(logout)) return false;
+    ++browserhere;
+  }
+
+  return true;
+}
+
+// get the default encoding for the given language - if it fails for any
+// reason return ""
+text_t receptionist::get_default_encoding (const text_t &language) {
+  
+  // make sure language is valid
+  if (configinfo.languages.find(language) == configinfo.languages.end()) return "";
+
+  text_t default_encoding = configinfo.languages[language].defaultencoding;
+
+  // make sure the encoding is valid
+  if (converters.find(default_encoding) == converters.end()) return "";
+
+  return default_encoding;
+}
+
+// parse_cgi_args parses cgi arguments into an argument class.
+// This function should be called for each page request. It returns false
+// if there was a major problem with the cgi arguments.
+bool receptionist::parse_cgi_args (const text_t &argstr, cgiargsclass &args, 
+				   ostream &logout, text_tmap &fcgienv) {
+
+  // get an initial list of cgi arguments
+  args.clear();
+  split_cgi_args (argsinfo, argstr, args);
+
+  // expand the compressed argument (if there was one)
+  if (!expand_save_args (argsinfo, configinfo.saveconf, args, logout)) return false;
+
+  // add the defaults
+  add_default_args (argsinfo, args, logout);
+
+  // get the cookie
+  if (configinfo.usecookies) get_cookie(args["z"], fcgienv);
+  
+  // if we're changing languages, set the encoding to the default for the new language
+  if (args["nl"] == "1") {
+    args["nw"] = get_default_encoding(args["l"]);
+  }
+
+  // get the input encoding
+  // if encoding isn't set, set it to the default for the current language
+  if ((args.getarg("w") == NULL) || args["w"].empty()) {
+    args["w"] = get_default_encoding(args["l"]);
+  }
+
+  text_t &arg_w = args["w"];
+
+  inconvertclass defaultinconvert;
+  inconvertclass *inconvert = converters.get_inconverter (arg_w);
+  if (inconvert == NULL) inconvert = &defaultinconvert;
+
+  // see if the next page will have a different encoding
+  if (args.getarg("nw") != NULL) arg_w = args["nw"];
+
+  // convert arguments which aren't in unicode to unicode
+  args_tounicode (args, *inconvert);
+
+
+  // decide on the output conversion class (needed for checking the external
+  // cgi arguments)
+  rzwsoutconvertclass defaultoutconverter;
+  rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
+  if (outconverter == NULL) outconverter = &defaultoutconverter;
+  outconverter->reset();
+
+  // check the main cgi arguments
+  if (!check_mainargs (args, logout)) return false;
+
+  // check the arguments for the action
+  action *a = actions.getaction (args["a"]);
+  if (a != NULL) {
+    if (!a->check_cgiargs (argsinfo, args, &protocols, logout)) return false;
+  } else {
+    // the action was not found!!
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii << "Error: the action \"" << args["a"] 
+	   << "\" could not be found.\n";
+    return false;
+  }
+
+  // check external cgi arguments for each action
+  actionptrmap::iterator actionhere = actions.begin ();
+  actionptrmap::iterator actionend = actions.end ();
+  while (actionhere != actionend) {
+    assert ((*actionhere).second.a != NULL);
+    if ((*actionhere).second.a != NULL) {
+      if (!(*actionhere).second.a->check_external_cgiargs (argsinfo, args, *outconverter,
+							   configinfo.saveconf, logout))
+	return false;
+    }
+    ++actionhere;
+  }
+
+  // the action might have changed but we will assume that
+  // the cgiargs were checked properly when the change was made
+
+  return true;
+}
+
+// returns true if cookie already existed, false
+// if it was generated
+bool receptionist::get_cookie (text_t &cookie, text_tmap &fcgienv) {
+
+  text_t cookiestring = gsdl_getenv ("HTTP_COOKIE", fcgienv);
+
+  text_t::const_iterator end = cookiestring.end();  
+  text_t::const_iterator here = findchar ((text_t::const_iterator)cookiestring.begin(), end, 'G');
+
+  while (here+9 < end) { 
+    
+    if (substr(here, here+8) == "GSDL_UID") {
+      cookie = substr (here+9, findchar (here+9, end, ';')); 
+      return true;
+    }
+    ++here;
+    here = findchar (here, end, 'G');
+  }
+
+  cookie.clear();
+  text_t host = gsdl_getenv("REMOTE_ADDR", fcgienv);
+  time_t ttime = time(NULL);
+  if (!host.empty()) {
+    cookie += host;
+    cookie.push_back ('-');
+  }
+  cookie += text_t(ttime);
+  
+  return false;
+}
+
+// as above but just tests if cookie exists
+bool receptionist::get_cookie (text_tmap &fcgienv) {
+
+  text_t c = gsdl_getenv("HTTP_COOKIE", fcgienv);
+  if (!c.empty()) {
+    text_t cookiestring = c;
+    
+    text_t::const_iterator end = cookiestring.end();  
+    text_t::const_iterator here = findchar ((text_t::const_iterator)cookiestring.begin(), end, 'G');
+
+    while (here+9 < end) { 
+      if (substr(here, here+8) == "GSDL_UID") return true;
+      ++here;
+      here = findchar (here, end, 'G');
+    }
+  }
+  return false;
+}
+
+bool receptionist::log_cgi_args (cgiargsclass &args, ostream &logout, text_tmap &fcgienv) {
+
+  // see if we want to log the cgi arguments
+  if (!configinfo.logcgiargs) return true;
+  
+  text_t host = gsdl_getenv ("REMOTE_HOST", fcgienv);
+  text_t script_name = gsdl_getenv ("SCRIPT_NAME", fcgienv);
+  if (host.empty()) host = gsdl_getenv ("REMOTE_ADDR", fcgienv);
+  text_t browser = gsdl_getenv ("HTTP_USER_AGENT", fcgienv);
+
+  cgiargsclass::const_iterator args_here = args.begin();
+  cgiargsclass::const_iterator args_end = args.end();
+
+  text_t argstr;
+  bool first = true;
+  while (args_here != args_end) {
+    if (!first) argstr += ", ";
+    argstr += (*args_here).first + "=" + (*args_here).second.value;
+    first = false;
+    ++args_here;
+  }
+
+  text_t logfile = filename_cat (configinfo.gdbmhome, "etc", "usage.txt");
+
+  text_t logstr = script_name;
+  logstr += " " + host;
+  logstr += " [";
+  if (configinfo.LogDateFormat == UTCTime) {
+    logstr += get_date (false);
+  } else if (configinfo.LogDateFormat == Absolute) {
+    time_t ttime = time(NULL);
+    logstr += ttime;
+  } else {
+    // LocalTime
+    logstr += get_date (true);
+  }
+  logstr += "] (" + argstr + ") \"";
+  logstr += browser;
+  logstr += "\"\n";
+
+  return append_logstr (logfile, logstr, logout);
+}
+
+bool receptionist::append_logstr (const text_t &filename, const text_t &logstr,
+				  ostream &logout) {
+
+  utf8outconvertclass text_t2utf8;
+  char *lfile = filename.getcstr();
+
+  int fd = open(lfile, O_WRONLY | O_APPEND);
+  
+  if (fd == -1) {
+    logout << "Error: Couldn't open file " << lfile << "\n";
+    delete []lfile;
+    return false;
+  }
+
+  // lock_val is set to 0 if file is locked successfully
+  int lock_val = 1;
+  GSDL_LOCK_FILE (fd);
+  if (lock_val == 0) {
+    text_t tmp_log_str(logstr); // so we don't pass a const to setinput...
+    text_t2utf8.setinput(&tmp_log_str);
+    char *buffer=new char[logstr.size()];
+    size_t num_chars;
+    convertclass::status_t status;
+    text_t2utf8.convert(buffer, logstr.size(), num_chars, status);
+    // ignore status - assume it is "finished" as buffer is big enough
+    write(fd, buffer, num_chars);
+    GSDL_UNLOCK_FILE (fd);
+    delete []buffer;
+  } else {
+    logout << "Error: Couldn't lock file " << lfile << "\n";
+    close(fd);
+    delete []lfile;
+    return false;
+  }
+
+  close(fd);
+		
+  delete []lfile;
+  return true;
+}
+
+text_t receptionist::expandmacros (const text_t &astring, cgiargsclass &args, 
+				   ostream &logout) {
+  text_t outstring;
+  outconvertclass text_t2ascii;
+
+  action *a = actions.getaction (args["a"]);
+  prepare_page (a, args, text_t2ascii, logout);
+  disp.expandstring (displayclass::defaultpackage, astring, outstring);
+  return outstring;
+}
+
+// produce_cgi_page will call get_cgihead_info and 
+// produce_content in the appropriate way to output a cgi header and
+// the page content (if needed). If a page could not be created it
+// will return false
+bool receptionist::produce_cgi_page (cgiargsclass &args, ostream &contentout, 
+				     ostream &logout, text_tmap &fcgienv) {
+  outconvertclass text_t2ascii;
+
+  response_t response;
+  text_t response_data;
+
+  // produce cgi header
+  get_cgihead_info (args, response, response_data, logout, fcgienv);
+  if (response == location) {
+    // location response (url may contain macros!!)
+    response_data = expandmacros (response_data, args, logout);
+    contentout << text_t2ascii << "Location: " << response_data << "\n\n";
+    contentout << flush;
+    return true;
+  } else if (response == content) {
+    // content response
+
+#ifdef GSDL_NOCACHE
+    contentout << "Expires: Mon, 26 Jul 1997 05:00:00 GMT\n"; // date in the past
+    tm *tm_ptr = NULL;
+    time_t t = time(NULL);
+    tm_ptr = gmtime (&t);
+    if (tm_ptr != NULL) {
+      char *timestr = new char[128];
+      strftime (timestr, 128, "%a, %d %b %Y %H:%M:%S", tm_ptr);
+      contentout << "Last-Modified: " << timestr << " GMT\n"; // always modified
+      delete []timestr;
+    }
+    contentout << "Cache-Control: no-cache, must-revalidate\n"; // HTTP/1.1
+    contentout << "Pragma: no-cache\n"; // HTTP/1.0
+
+#else
+
+    // use the later of build.cfg and collect.cfg modification times
+    // as the Last-Modified: header, for caching values
+    struct stat file_info;
+    time_t latest=0;
+
+    text_t collectname="";
+    collectname=args["c"];
+    if (collectname != "") {
+      text_t collectdir=filename_cat(configinfo.gsdlhome,"collect");
+      collectdir=filename_cat(collectdir,collectname);
+      text_t buildcfg=filename_cat(collectdir,"index");
+      buildcfg=filename_cat(buildcfg,"build.cfg");
+      char *buildcfg_ptr=buildcfg.getcstr();
+      text_t collectcfg=filename_cat(collectdir,"etc");
+      collectcfg=filename_cat(collectcfg,"collect.cfg");
+      char *collectcfg_ptr=collectcfg.getcstr();
+
+      if (stat(buildcfg_ptr, &file_info)) {
+	// we got an error. Currently don't handle error :(
+	//	logout << 
+      } else {
+	latest=file_info.st_mtime;
+      }
+    
+      if (stat(collectcfg_ptr, &file_info)) {
+	// error - unhandled for now
+      } else {
+	if (latest<file_info.st_mtime) latest=file_info.st_mtime;
+      }
+      delete []buildcfg_ptr;
+      delete []collectcfg_ptr;
+
+      if (latest>0) {
+	// print out modified time, "DDD, dd MMM YYYY hh:mm:ss" format
+	// c library takes care of mem for this string... (has \n at end!!!!)
+	// latest is currently local time, convert to UTC.
+	struct tm* utc_latest;
+	utc_latest=gmtime(&latest);
+	contentout << "Last-Modified: " << asctime(utc_latest);
+      }
+    } // end of collection != ""
+
+#endif
+
+    contentout << text_t2ascii << "Content-type: " << response_data << "\n\n";
+  }
+  else if (response == undecided_location) {
+    // Wait until later to output the target location
+    // Used for the "I'm feeling lucky" functionality
+  }
+  else {
+    // unknown response
+    logout << "Error: get_cgihead_info returned an unknown response type.\n";
+    return false;
+  }
+
+  // produce cgi page
+  if (!produce_content (args, contentout, logout)) return false;
+
+  // flush contentout
+  contentout << flush;
+  return true;
+}
+
+
+// get_cgihead_info determines the cgi header information for
+// a set of cgi arguments. If response contains location then
+// response_data contains the redirect address. If reponse
+// contains content then reponse_data contains the content-type.
+// Note that images can now be produced by the receptionist.
+// Note also, alternative for get_cgihead_info below which
+// stores the information in a text_tmap so it is more easily digested
+
+void receptionist::get_cgihead_info (cgiargsclass &args, response_t &response,
+				     text_t &response_data, ostream &logout, 
+				     text_tmap &fcgienv) {
+  outconvertclass text_t2ascii;
+
+  // get the action
+  action *a = actions.getaction (args["a"]);
+  if (a != NULL) {
+    a->get_cgihead_info (args, &protocols, response, response_data, logout);
+
+  } else {
+    // the action was not found!!
+    logout << text_t2ascii << "Error receptionist::get_cgihead_info: the action \"" 
+	   << args["a"] << "\" could not be found.\n";
+    response = content;
+    response_data = "text/html";
+  }
+
+  // add the encoding information
+  if (response == content) {
+    if (converters.find(args["w"]) != converters.end()) {
+      response_data += "; charset=" + args["w"];
+    } else {
+      // default to latin 1
+      response_data += "; charset=ISO-8859-1";
+    }
+
+    // add cookie if required
+    if (configinfo.usecookies && !get_cookie(fcgienv))
+      response_data += "\nSet-Cookie: GSDL_UID=" + args["z"]
+	+ "; expires=25-Dec-37 00:00:00 GMT";
+  }
+}
+
+
+// Alternative version of get_cgihead_info, stores fielded infomation
+// in text_tmap rather than concatenated string
+void receptionist::get_cgihead_info (cgiargsclass &args, text_tmap &headers,
+				     ostream &logout, text_tmap &fcgienv) {
+
+  response_t response;
+  text_t response_data;
+
+  // get the action
+  action *a = actions.getaction (args["a"]);
+  if (a != NULL) {
+    a->get_cgihead_info (args, &protocols, response, response_data, logout);
+
+  } else {
+    // the action was not found!!
+    outconvertclass text_t2ascii;
+    logout << text_t2ascii << "Error receptionist::get_cgihead_info: the action \"" 
+	   << args["a"] << "\" could not be found.\n";
+    response = content;
+    response_data = "text/html";
+  }
+
+  if (response == location) {
+    response_data = expandmacros(response_data, args, logout);
+    headers["Location"] = response_data;
+    return;
+  }
+
+  // add the encoding information
+  if (response == content) {
+
+    if (converters.find(args["w"]) != converters.end()) {
+      headers["content-encoding"] = args["w"];
+      response_data += "; charset=" + args["w"];
+    } else {
+      // default to utf-8
+      headers["content-encoding"] = "utf-8";
+      response_data += "; charset=utf-8";
+    }
+
+    headers["content-type"] = response_data;
+
+  }
+
+}
+
+
+
+// produce the page content
+bool receptionist::produce_content (cgiargsclass &args, ostream &contentout,
+				    ostream &logout) {
+
+  // decide on the output conversion class
+  text_t &arg_w = args["w"];
+  rzwsoutconvertclass defaultoutconverter;
+  rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
+  if (outconverter == NULL) outconverter = &defaultoutconverter;
+  outconverter->reset();
+
+  // needed for 16-bit unicode only - big endian marker 0xfeff (RFC 2781)
+  if (arg_w=="utf-16be") {
+    contentout << '\xfe' << '\xff' ;
+  }
+
+  recptproto *collectproto = protocols.getrecptproto (args["c"], logout);
+  if (collectproto != NULL) {
+    // get browsers to process OID
+    text_t OID = args["d"];
+    if (OID.empty()) OID = args["cl"];
+    if (!OID.empty()) {
+      text_tset metadata;
+      text_tarray OIDs;
+      OIDs.push_back (OID);
+      if (!is_top(OID)) OIDs.push_back (OID + ".pr");
+      FilterResponse_t response;
+      metadata.insert ("childtype");
+      if (get_info (OIDs, args["c"], args["l"], metadata, false, collectproto, response, logout)) {
+	text_t classifytype;
+	if (!response.docInfo[0].metadata["childtype"].values[0].empty())
+	  classifytype = response.docInfo[0].metadata["childtype"].values[0];
+	else if (!is_top (OID)) {
+	  // not sure why this is occasionally not set, but it will
+	  // cause a segfault... possibly if built with no_text? jrm21
+	  if (response.docInfo[1].metadata.find("childtype")
+	      == response.docInfo[1].metadata.end()) {
+	    cerr << "receptionist: no childtype element in metadata map!"
+		 << endl;
+	  } else {
+	    if (!response.docInfo[1].metadata["childtype"].values[0].empty())
+	      classifytype = response.docInfo[1].metadata["childtype"].values[0];
+	  }
+	}
+	browserclass *b = browsers.getbrowser (classifytype);
+	b->processOID (args, collectproto, logout);
+      }
+    }
+  
+    // translate "d" and "cl" arguments if required
+    translate_OIDs (args, collectproto, logout);
+  }
+  
+  // produce the page using the desired action
+  action *a = actions.getaction (args["a"]);
+  if (a != NULL) {
+    if (a->uses_display(args)) prepare_page (a, args, (*outconverter), logout);
+    if (!a->do_action (args, &protocols, &browsers, disp, (*outconverter), contentout, logout))
+      return false;
+  } else {
+    // the action was not found!!
+    outconvertclass text_t2ascii;
+
+    logout << text_t2ascii << "Error receptionist::produce_content: the action \"" 
+	   << args["a"] << "\" could not be found.\n";
+    
+    contentout << (*outconverter) 
+	       << "<html>\n"
+	       << "<head>\n"
+	       << "<title>Error</title>\n"
+	       << "</head>\n"
+	       << "<body>\n"
+	       << "<h2>Oops!</h2>\n"
+	       << "Undefined Page. The action \"" 
+	       << args["a"] << "\" could not be found.\n"
+	       << "</body>\n"
+	       << "</html>\n";
+  }
+  return true;
+}
+
+
+// returns the compressed argument ("e") corresponding to the argument
+// list. This can be used to save preferences between sessions.
+text_t receptionist::get_compressed_arg (cgiargsclass &args, ostream &logout) {
+  // decide on the output conversion class
+  text_t &arg_w = args["w"];
+  rzwsoutconvertclass defaultoutconverter;
+  rzwsoutconvertclass *outconverter = converters.get_outconverter (arg_w);
+  if (outconverter == NULL) outconverter = &defaultoutconverter;
+  outconverter->reset();
+
+  text_t compressed_args;
+  if (compress_save_args (argsinfo, configinfo.saveconf, args, 
+			  compressed_args, *outconverter, logout))
+    return compressed_args;
+
+  return g_EmptyText;
+}
+
+
+// will read in all the macro files. If one is not found an
+// error message will be written to logout and the method will
+// return false.
+bool receptionist::read_macrofiles (ostream &logout) {
+  outconvertclass text_t2ascii;
+
+  // redirect the error output to logout
+  ostream *savedlogout = disp.setlogout (&logout);
+
+  // unload any macros that were previously loaded - this allows us to call
+  // this function a second time to reload all the macro files (useful for
+  // reading in changed macro files in server versions of greenstone)
+  disp.unloaddefaultmacros();
+
+  // load up the default macro files, the collection directory
+  // is searched first for the file (if this is being used in
+  // collection specific mode) and then the main directory(s)
+  text_t colmacrodir = filename_cat (configinfo.collectdir, "macros");
+
+  text_tset maindirs;
+  text_t gsdlmacrodir = filename_cat (configinfo.gsdlhome, "macros");
+  maindirs.insert (gsdlmacrodir);
+  colinfo_tmap::iterator colhere = configinfo.collectinfo.begin();
+  colinfo_tmap::iterator colend = configinfo.collectinfo.end();
+  while (colhere != colend) {
+    if (!((*colhere).second.gsdl_gsdlhome).empty()) {
+      gsdlmacrodir = filename_cat ((*colhere).second.gsdl_gsdlhome, "macros");
+      maindirs.insert (gsdlmacrodir);
+    }
+    ++colhere;
+  }
+
+  text_tset::iterator arrhere = configinfo.macrofiles.begin();
+  text_tset::iterator arrend = configinfo.macrofiles.end();
+  text_t filename;
+  while (arrhere != arrend) {
+    bool foundfile = false;
+
+    // try in the collection directory if this is being
+    // run in collection specific mode
+    if (!configinfo.collection.empty()) {
+      filename = filename_cat (colmacrodir, *arrhere);
+      if (file_exists (filename)) {
+	disp.loaddefaultmacros(filename);
+	foundfile = true;
+      }
+    }
+
+    // if we haven't found the macro file yet try in
+    // the main macro directory(s)
+    // if file is found in more than one main directory
+    // we'll load all copies
+    if (!foundfile) {
+      text_tset::const_iterator dirhere = maindirs.begin();
+      text_tset::const_iterator dirend = maindirs.end();
+      while (dirhere != dirend) {
+	filename = filename_cat (*dirhere, *arrhere);
+	if (file_exists (filename)) {
+	  disp.loaddefaultmacros(filename);
+	  foundfile = true;
+	}
+	++dirhere;
+      }
+    }
+
+    // see if we found the file or not
+    if (!foundfile) {
+      logout << text_t2ascii 
+	     << "Error: the macro file \"" << *arrhere << "\" could not be found.\n";
+      if (configinfo.collection.empty()) {
+	text_t dirs;
+	joinchar (maindirs, ", ", dirs);
+	logout << text_t2ascii 
+	       << "It should be in either of the following directories ("
+	       << dirs << ").\n\n";
+
+      } else {
+	logout << text_t2ascii
+	       << "It should be in either " << colmacrodir << " or in " 
+	       << gsdlmacrodir << ".\n\n";
+      }
+      // reset logout to what it was
+      disp.setlogout (savedlogout);
+      return false;
+    }
+    ++arrhere;
+  }
+
+  // success
+
+  // reset logout to what it was
+  disp.setlogout (savedlogout);
+  return true;
+}
+
+
+
+
+// Go through the list of macro files looking to see
+// if any exist in the collectoin specific area.  If they
+// do then read them in and add them to the set of existing
+// current macros
+
+void receptionist::read_collection_macrofiles (const text_t& collection, ostream &logout) 
+{
+  outconvertclass text_t2ascii;
+
+  // disp.unloadcollectionmacros();
+
+  // redirect the error output to logout
+  ostream *savedlogout = disp.setlogout (&logout);
+
+  text_t colmacrodir 
+    = filename_cat (configinfo.gsdlhome,"collect",collection, "macros");
+
+  if (directory_exists (colmacrodir)) {
+
+    text_tset::iterator arrhere = configinfo.macrofiles.begin();
+    text_tset::iterator arrend = configinfo.macrofiles.end();
+    text_t filename;
+    while (arrhere != arrend) {
+
+      filename = filename_cat (colmacrodir, *arrhere);
+      if (file_exists (filename)) {
+	disp.loadcollectionmacros(filename);
+      }
+      
+      ++arrhere;
+    }
+  }
+
+  // reset logout to what it was
+  disp.setlogout (savedlogout);
+}
+
+
+
+
+// check_mainargs will check all the main arguments. If a major
+// error is found it will return false and no cgi page should
+// be created using the arguments.
+
+bool receptionist::check_mainargs (cgiargsclass &args, ostream &logout) {
+   
+   if(configinfo.site_auth)
+      {
+	 args["uan"] = "1";
+	 args["ug"] = configinfo.site_group;
+      }
+   
+   
+   // if this receptionist is running in collection dependant mode
+   // then it should always set the collection argument to the
+   // collection
+   if (!configinfo.collection.empty()) args["c"] = configinfo.collection;
+   
+   // if current collection uses ccscols make sure
+   // "ccs" argument is set and make "cc" default to
+   // all collections in "ccs"
+   if (args["a"] != "config" && !args["c"].empty()) {
+      
+      text_t &arg_c = args["c"];
+      recptproto *collectproto = protocols.getrecptproto (arg_c, logout);
+      if (collectproto == NULL) {
+	 // oops, this collection isn't valid
+	 outconvertclass text_t2ascii;
+	 logout << text_t2ascii << "ERROR: Invalid collection: " << arg_c << "\n";
+	 // args["c"].clear();
+	 
+      } else {
+	 
+	 ColInfoResponse_t *cinfo = get_collectinfo_ptr (collectproto, arg_c, logout);
+	 
+	 if(cinfo->authenticate == "collection")
+	    {
+	       args["uan"] = "1";
+	       args["ug"] = cinfo->auth_group;
+	    }
+	 
+	 
+      if (cinfo != NULL) {
+	 if (!cinfo->ccsCols.empty()) {
+	    args["ccs"] = 1;
+	    if (args["cc"].empty()) {
+	       text_tarray::const_iterator col_here = cinfo->ccsCols.begin();
+	       text_tarray::const_iterator col_end = cinfo->ccsCols.end();
+	       bool first = true;
+	       while (col_here != col_end) {
+		  // make sure it's a valid collection
+		  if (protocols.getrecptproto (*col_here, logout) != NULL) {
+		     if (!first) args["cc"].push_back (',');
+		     args["cc"] += *col_here;
+		     first = false;
+		  }
+	      ++col_here;
+	    }
+	  }
+	}
+      } else {
+	logout << "ERROR (receptionist::check_mainargs): get_collectinfo_ptr returned NULL\n";
+      }
+    }
+  }
+
+  // argument "v" can only be 0 or 1. Use the default value
+  // if it is out of range
+  int arg_v = args.getintarg ("v");
+  if (arg_v != 0 && arg_v != 1) {
+    cgiarginfo *vinfo = argsinfo.getarginfo ("v");
+    if (vinfo != NULL) args["v"] = vinfo->argdefault;
+  }
+
+  // argument "f" can only be 0 or 1. Use the default value
+  // if it is out of range
+  int arg_f = args.getintarg ("f");
+  if (arg_f != 0 && arg_f != 1) {
+    cgiarginfo *finfo = argsinfo.getarginfo ("f");
+    if (finfo != NULL) args["f"] = finfo->argdefault;
+  }
+
+  return true;
+}
+
+// translate_OIDs translates the "d" and "cl" arguments to their correct values
+// if they use the tricky ".fc", ".lc" type syntax.
+void receptionist::translate_OIDs (cgiargsclass &args, recptproto *collectproto, 
+				   ostream &logout) {
+
+  FilterResponse_t response;
+  FilterRequest_t request;
+  comerror_t err;
+  text_t &arg_d = args["d"];
+  text_t &arg_cl = args["cl"];
+  text_t &collection = args["c"];
+  
+  // do a call to translate OIDs if required
+  request.filterName = "NullFilter";
+  request.filterResultOptions = FROID;
+  if (!arg_d.empty() && needs_translating (arg_d)) {
+    request.docSet.push_back (arg_d);
+    collectproto->filter (collection, request, response, err, logout);
+    arg_d = response.docInfo[0].OID;
+    request.clear();
+  }
+  // we'll also check here that the "cl" argument has a "classify" doctype 
+  // (in case ".fc" or ".lc" have screwed up)
+  if (needs_translating (arg_cl)) {
+    request.fields.insert ("doctype");
+    request.docSet.push_back (arg_cl);
+    request.filterResultOptions = FRmetadata;
+    collectproto->filter (collection, request, response, err, logout);
+    // set to original value (without .xx stuff) if doctype isn't "classify"
+    if (response.docInfo[0].metadata["doctype"].values[0] != "classify")
+      strip_suffix (arg_cl);
+    else
+      arg_cl = response.docInfo[0].OID;
+  }
+}
+
+// prepare_page sets up page parameters, sets display macros
+// and opens the page ready for output 
+void receptionist::prepare_page (action *a, cgiargsclass &args, 
+				 outconvertclass &outconvert, 
+				 ostream &logout) {
+  // set up page parameters
+  text_t pageparams;
+  bool first = true;
+
+  text_tmap::iterator params_here = configinfo.pageparams.begin();
+  text_tmap::iterator params_end = configinfo.pageparams.end();
+  while (params_here != params_end) {
+    // page params are those from main.cfg (eg pageparam v 0) plus
+    // two defaults set in recptconf.clear() (c="" and l=en)
+    // This used to check if the current value of the page param
+    // == the default value, then don't add in it the list
+    // but if l=en, and there is a macro with [l=en], then it doesn't
+    // find it.
+    // so now all page params will go into the list. I assume this will 
+    // mean more attempts to find each macro, but nothing worsee than 
+    // that.  --kjdon
+    //if (args[(*params_here).first] != (*params_here).second) {
+      if (first)
+	first = false;
+      else
+	pageparams += ",";
+
+      pageparams += (*params_here).first;
+      pageparams += "=";
+      pageparams += args[(*params_here).first];
+      // }
+    
+    ++params_here;
+  }
+  
+
+  // open the page
+  disp.openpage(pageparams, configinfo.macroprecedence);
+
+  disp.unloadcollectionmacros();
+
+  text_t collection = args["c"];
+  if (!collection.empty()) {
+    read_collection_macrofiles(collection,logout);
+  }
+
+  // define external macros for each action
+  actionptrmap::iterator actionhere = actions.begin ();
+  actionptrmap::iterator actionend = actions.end ();
+
+  while (actionhere != actionend) {
+    assert ((*actionhere).second.a != NULL);
+    if ((*actionhere).second.a != NULL) {
+      (*actionhere).second.a->define_external_macros (disp, args, &protocols, logout);
+    }
+    ++actionhere;
+  }
+
+
+  // define internal macros for the current action
+  a->define_internal_macros (disp, args, &protocols, logout);
+  
+  // define general macros. the defining of general macros is done here so that
+  // the last possible version of the cgi arguments are used
+  define_general_macros (args, outconvert, logout);
+}
+
+void receptionist::define_general_macros (cgiargsclass &args, outconvertclass &/*outconvert*/, 
+					  ostream &logout) {
+
+  text_t &collection = args["c"];
+
+  disp.setmacro ("gsdlhome", displayclass::defaultpackage, dm_safe(configinfo.gsdlhome));
+  disp.setmacro ("gwcgi", displayclass::defaultpackage, configinfo.gwcgi);
+  disp.setmacro ("httpimg", displayclass::defaultpackage, configinfo.httpimg);
+  disp.setmacro ("httpprefix", displayclass::defaultpackage, configinfo.httpprefix);
+
+
+  text_t compressedoptions = get_compressed_arg(args, logout);
+  disp.setmacro ("compressedoptions", displayclass::defaultpackage, dm_safe(compressedoptions));
+  // need a decoded version of compressedoptions for use within forms
+  // as browsers encode values from forms before sending to server
+  // (e.g. %25 becomes %2525)
+  decode_cgi_arg (compressedoptions);
+  disp.setmacro ("decodedcompressedoptions", displayclass::defaultpackage, dm_safe(compressedoptions));
+
+#if defined (__WIN32__)
+  disp.setmacro ("win32", displayclass::defaultpackage, "1");
+#endif
+
+  // set _cgiargX_ macros for each cgi argument
+  cgiargsclass::const_iterator argshere = args.begin();
+  cgiargsclass::const_iterator argsend = args.end();
+  while (argshere != argsend) {
+    if (((*argshere).first == "q") ||
+	((*argshere).first == "qa") ||
+	((*argshere).first == "qtt") ||
+	((*argshere).first == "qty") ||
+	((*argshere).first == "qp") ||
+	((*argshere).first == "qpl") ||
+	((*argshere).first == "qr") ||
+	((*argshere).first == "q2"))
+      // need to escape special characters from query string
+      disp.setmacro ("cgiarg" + (*argshere).first, 
+		     displayclass::defaultpackage, html_safe((*argshere).second.value));
+    else if ((*argshere).first == "hp") {
+      disp.setmacro ("cgiarg" + (*argshere).first, displayclass::defaultpackage, (*argshere).second.value);
+    } else {
+      disp.setmacro ("cgiarg" + (*argshere).first, displayclass::defaultpackage, dm_safe((*argshere).second.value));
+    }
+    ++argshere;
+  }
+
+  // display text right to left if language is arabic/farsi (and if browser can support it)
+  if (args["l"] == "ar" || args["l"] == "fa")
+    disp.setmacro ("htmlextra", displayclass::defaultpackage, " dir=rtl");
+
+  // set collection specific macros
+  if (!collection.empty()) {
+    recptproto *collectproto = protocols.getrecptproto (collection, logout);
+    if (collectproto != NULL) {
+      FilterResponse_t response;
+      text_tset metadata;
+      get_info ("collection", collection, args["l"], metadata, false, 
+		collectproto, response, logout);
+      
+      if (!response.docInfo[0].metadata.empty()) {
+	MetadataInfo_tmap::const_iterator here = response.docInfo[0].metadata.begin();
+	MetadataInfo_tmap::const_iterator end = response.docInfo[0].metadata.end();
+	while (here != end) {
+	  if (((*here).first != "haschildren") && ((*here).first != "hasnext") &&
+	      ((*here).first != "hasprevious")) {
+	    // check for args in form name:lang
+	    text_t name = g_EmptyText;
+	    text_t lang = g_EmptyText;
+	    bool colonfound=false;
+	    text_t::const_iterator a = (*here).first.begin();
+	    text_t::const_iterator b = (*here).first.end();
+	    while (a !=b) {
+	      if (*a==':') {
+		colonfound=true;
+	      }
+	      else {
+		if (colonfound)
+		  lang.push_back(*a);
+		else name.push_back(*a);
+	      }
+	      ++a;
+	    }
+	    if (!lang.empty()) {
+	      if (args["l"]==lang) {
+		disp.setcollectionmacro(displayclass::defaultpackage, name, "", (*here).second.values[0]);
+	      }
+	    }
+	    else { // the default one
+	      disp.setcollectionmacro(displayclass::defaultpackage, (*here).first,  "", (*here).second.values[0]);
+	    }
+	  }
+	  ++here;
+	}
+      }
+
+      text_t iconcollection;
+      disp.expandstring (displayclass::defaultpackage, "_iconcollection_", iconcollection);
+      if (!iconcollection.empty())
+	{
+	  ColInfoResponse_t cinfo;
+	  comerror_t err;
+	  collectproto->get_collectinfo (collection, cinfo, err, logout);
+	  if (iconcollection[0]=='/' && !cinfo.httpdomain.empty())
+	    {
+	      // local but with full path
+	      iconcollection = "http://" + cinfo.httpdomain + iconcollection;
+	      disp.setmacro("iconcollection", displayclass::defaultpackage, iconcollection);
+	    }
+	}
+    }
+  }
+
+  if (!collection.empty()) {
+    ColInfoResponse_t cinfo;
+    comerror_t err;
+    recptproto *collectproto = protocols.getrecptproto (collection, logout);
+    if (collectproto != NULL) {
+      collectproto->get_collectinfo (collection, cinfo, err, logout);
+      text_t httpcollection;
+      if (!cinfo.httpdomain.empty()) httpcollection = "http://";
+      httpcollection += cinfo.httpdomain + cinfo.httpprefix + "/collect/"
+	+ collection; 
+      disp.setmacro ("httpcollection", displayclass::defaultpackage,
+		     httpcollection); 
+      // as of gsdl 2.53, collect.cfg can specify macros
+      if (cinfo.collection_macros.size() > 0) {
+	macros_map::const_iterator this_macro=cinfo.collection_macros.begin();
+	macros_map::const_iterator done_macro=cinfo.collection_macros.end();
+	while (this_macro != done_macro) {
+
+	  disp.setcollectionmacro("Global",		      // package
+				  this_macro->first, 	      // macro name
+				  this_macro->second.first,   // params
+				  this_macro->second.second); // value
+	  ++this_macro;
+	}
+      } // col macros
+    } // collectproto != NULL
+  }
+
+}
+
+// gets collection info from cache if found or 
+// calls collection server (and updates cache)
+// returns NULL if there's an error
+ColInfoResponse_t *receptionist::get_collectinfo_ptr (recptproto *collectproto, 
+						      const text_t &collection, 
+						      ostream &logout) {
+  
+  // check the cache
+  colinfo_tmap::iterator it = configinfo.collectinfo.find (collection);
+  if ((it != configinfo.collectinfo.end()) && ((*it).second.info_loaded)) {
+    // found it
+    return &((*it).second.info);
+  }
+
+  // not cached, get info from collection server
+  if (collectproto == NULL) {
+    logout << "ERROR: receptionist::get_collectinfo_ptr passed null collectproto\n";
+    return NULL;
+  }
+   
+  comerror_t err;
+  if (it == configinfo.collectinfo.end()) {
+    collectioninfo_t cinfo;
+    collectproto->get_collectinfo (collection, cinfo.info, err, logout);
+    if (err != noError) {
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii << "ERROR (receptionist::getcollectinfo_ptr): \""
+	     << get_comerror_string (err) << "\"while getting collectinfo\n";
+      return NULL;
+    }
+    cinfo.info_loaded = true;
+    configinfo.collectinfo[collection] = cinfo;
+    return &(configinfo.collectinfo[collection].info);
+  } else {
+    collectproto->get_collectinfo (collection, (*it).second.info, err, logout);
+    if (err != noError) {
+      outconvertclass text_t2ascii;
+      logout << text_t2ascii << "ERROR (receptionist::getcollectinfo_ptr): \""
+	     << get_comerror_string (err) << "\"while getting collectinfo\n";
+      return NULL;
+    }
+    (*it).second.info_loaded = true;
+    return &((*it).second.info);
+  }
+}
+
+// removes a collection from the cache so that the next
+// call to get_collectinfo_ptr() for that collection will
+// retrieve the collection info from the collection server
+void receptionist::uncache_collection (const text_t &collection) {
+
+  colinfo_tmap::iterator it = configinfo.collectinfo.find (collection);
+  if ((it != configinfo.collectinfo.end()) && ((*it).second.info_loaded)) {
+
+    (*it).second.info_loaded = false;
+
+  }
+}
+
+// Handles an "Encoding" line from a configuration file - note that the
+// configinfo.encodings map is a bit of a hack (to be fixed when the
+// configuration files are tidied up).
+void receptionist::configure_encoding (const text_tarray &cfgline) {
+
+  text_t subkey, subvalue, shortname, longname, mapfile;
+  int multibyte = 0;
+  text_t::const_iterator cfglinesub_here;
+  text_tarray::const_iterator cfgline_here = cfgline.begin();
+  text_tarray::const_iterator cfgline_end = cfgline.end();
+  while (cfgline_here != cfgline_end) {
+    if (*cfgline_here == "multibyte") {
+      multibyte = 1;
+    } else {
+      cfglinesub_here = getdelimitstr((*cfgline_here).begin(),
+				      (*cfgline_here).end(), '=', subkey);
+      if (subkey == "shortname") {
+	shortname = substr (cfglinesub_here, (*cfgline_here).end());
+      } else if (subkey == "longname") {
+	longname = substr (cfglinesub_here, (*cfgline_here).end());
+      } else if (subkey == "map") {
+	mapfile = substr (cfglinesub_here, (*cfgline_here).end());
+      }
+    }
+    ++cfgline_here;
+  }
+  if (!shortname.empty()) {
+    if (longname.empty()) longname = shortname;
+
+    // add the converter
+    if (shortname == "utf-8") {
+      utf8inconvertclass *utf8inconvert = new utf8inconvertclass();
+      utf8outconvertclass *utf8outconvert = new utf8outconvertclass();
+      utf8outconvert->set_rzws(1);
+      add_converter (shortname, utf8inconvert, utf8outconvert);
+      configinfo.encodings[longname] = shortname;
+
+    } else if (shortname == "utf-16be") {
+      // we use the default input converter as this shouldn't ever be used
+      // for converting from unicode...
+      inconvertclass *inconverter = new inconvertclass();
+      utf16outconvertclass *outconverter = new utf16outconvertclass();
+      add_converter (shortname, inconverter, outconverter);
+      configinfo.encodings[longname] = shortname;
+	
+    } else if (!mapfile.empty()) {
+
+      if (mapfile == "8859_1.ump") {
+	// iso-8859-1 is a special case as it'll always be supported by the
+	// standard converter class and therefore doesn't need to use its
+	// mapping file
+	inconvertclass *inconvert = new inconvertclass();
+	rzwsoutconvertclass *outconvert = new rzwsoutconvertclass();
+	outconvert->set_rzws(1);
+	add_converter (shortname, inconvert, outconvert);  
+	configinfo.encodings[longname] = shortname;
+
+      } else {
+	text_t to_uc_map = filename_cat(configinfo.gsdlhome, "mappings", "to_uc", mapfile);
+	text_t from_uc_map = filename_cat(configinfo.gsdlhome, "mappings", "from_uc", mapfile);
+	if (file_exists(to_uc_map) && file_exists(from_uc_map)) {
+
+	  mapinconvertclass *mapinconvert = new mapinconvertclass();
+	  mapinconvert->setmapfile (to_uc_map, 0x003F);
+	  mapinconvert->set_multibyte (multibyte);
+	  mapoutconvertclass *mapoutconvert = new mapoutconvertclass();
+	  mapoutconvert->setmapfile (from_uc_map, 0x3F);
+	  mapoutconvert->set_multibyte (multibyte);
+	  mapoutconvert->set_rzws(1);
+	  add_converter (shortname, mapinconvert, mapoutconvert);
+	  configinfo.encodings[longname] = shortname;
+	}
+      }
+    }
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/receptionist.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/receptionist.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/receptionist.h	(revision 10506)
@@ -0,0 +1,280 @@
+/**********************************************************************
+ *
+ * receptionist.h -- a web interface for the gsdl
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef RECEPTIONIST_H
+#define RECEPTIONIST_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+#include "display.h"
+#include "browserclass.h"
+#include "recptproto.h"
+#include "converter.h"
+#include "cfgread.h"
+#include "action.h"
+#include "cnfgable.h"
+
+// the MACROPRECEDENCE macro is used as a default. override
+// it using something like:
+//
+// macroprecedence c,l
+//
+// in your configuration file
+#ifndef MACROPRECEDENCE
+#define MACROPRECEDENCE "c,l"
+#endif
+
+
+struct collectioninfo_t {
+  void clear ();
+  collectioninfo_t () {clear();}
+
+  text_t gsdl_gsdlhome;
+  text_t gsdl_gdbmhome;
+
+  bool info_loaded;
+  ColInfoResponse_t info;
+};
+
+struct languageinfo_t {
+  void clear();
+  languageinfo_t () {clear();}
+
+  text_t longname;
+  text_t defaultencoding;
+};
+
+typedef map<text_t, collectioninfo_t, lttext_t> colinfo_tmap;
+typedef map<text_t, languageinfo_t, lttext_t> languageinfo_tmap;
+
+enum events_t {Disabled, CollectorEvents, AllEvents};
+enum ldformat_t {LocalTime, UTCTime, Absolute};
+
+struct recptconf {
+   text_t gsdlhome;
+   text_t gdbmhome;   // will equal gsdlhome if not set
+   text_t collection; // will equal "" in 'general' mode
+   text_t collectdir; // will equal gsdlhome in 'general' mode
+   colinfo_tmap collectinfo;
+   text_t httpprefix;
+   text_t httpimg;    // will equal /images if not set
+   text_t gwcgi;
+   text_tset macrofiles;
+   text_t saveconf;
+   bool usecookies;  // true if we want cookies set
+   bool logcgiargs;  // true if we want to log cgi arguments
+   
+   ldformat_t LogDateFormat;
+   
+   text_t maintainer; // email address of maintainer
+   text_t MailServer; // SMTP mail server to use when sending event messages by email
+                     // defaults to mail.maintainer-domain
+   events_t LogEvents;
+   events_t EmailEvents;
+   bool EmailUserEvents;
+
+   bool    site_auth;   // Complete site authentication, useful to lockout site for example.
+   text_t  site_group;  // Similar to the auth_groups functionality, infact exactly the same
+   
+   text_t HomePageType; 
+   int HomePageCols;
+   
+   text_tmap pageparams;
+   text_t macroprecedence;
+   
+   languageinfo_tmap languages;
+   
+   // encodings is just a simple mapping from encoding longnames to
+   // shortnames.  It's useful for now for creating the pulldown menu of
+   // encodings on the preferences page but isn't intended to be permanent.
+   text_tmap encodings;
+   
+   void clear ();
+   recptconf () {clear();}
+};
+
+class receptionist : public configurable {
+protected:
+
+   recptconf configinfo;
+   
+   cgiargsinfoclass argsinfo;
+   actionmapclass actions;
+   browsermapclass browsers;
+   recptprotolistclass protocols;
+   displayclass disp;
+   convertinfoclass converters;
+   ColInfoResponse_t collectinfo;
+   
+   // prepare_page sets up page parameters, sets display macros
+   // and opens the page ready for output 
+   virtual void prepare_page (action *a, cgiargsclass &args, 
+			      outconvertclass &outconvert, 
+			     ostream &logout);
+   
+   virtual void translate_OIDs (cgiargsclass &args, recptproto *collectproto,
+				ostream &logout);
+   
+   bool get_cookie (text_t &cookie, text_tmap &fcgienv);
+   bool get_cookie (text_tmap &fcgienv);
+   
+   // get the default encoding for the given language - if it fails for any
+   // reason, return ""
+   text_t get_default_encoding (const text_t &language);
+   
+   virtual void define_general_macros (cgiargsclass &args, outconvertclass &outconvert, 
+				       ostream &logout);
+   
+   bool append_logstr (const text_t &filename, const text_t &logstr,
+		       ostream &logout);
+
+   virtual void configure_encoding (const text_tarray &cfgline);
+   
+ public:
+   receptionist ();
+   virtual ~receptionist() {}
+
+#ifdef _APACHE_MOD
+   bool loaded;
+#endif   
+   // add_action makes another action available to the receptionist
+   // the action remains the property of the calling code and that
+   // code should destroy the action after the recptionist has been
+   // destroyed.
+   void add_action (action *theaction);
+   actionmapclass *get_actionmap_ptr () {return &actions;}
+   
+   // add_browser makes another browser available to the receptionist
+   // the browser remains the property of the calling code and that
+   // code should destroy it after the recptionist has been
+   // destroyed.
+   void add_browser (browserclass *thebrowser);
+   browsermapclass *get_browsermap_ptr () {return &browsers;}
+   void setdefaultbrowser (const text_t &browsername);
+   
+   // add_protocol makes another protocol available to the receptionist
+   // without any protocols, no collections will be available. The
+   // protocols remain the property of the calling code.
+   void add_protocol (recptproto *theprotocol) {protocols.addrecptproto(theprotocol);}
+   recptprotolistclass *get_recptprotolist_ptr () {return &protocols;}
+   
+   // add_converter makes another converter available to the receptionist.
+   // Converters are needed to display pages using different encodings.
+   // The converters remain the property of the calling code.
+   void add_converter (const text_t &name, inconvertclass *inconverter,
+		       rzwsoutconvertclass *outconverter) {
+      converters.add_converter(name, inconverter, outconverter);}
+   convertinfoclass *get_convertinfo_ptr () {return &converters;}
+   
+   
+   // configure should be called for each line in the
+  // configuration files to configure the receptionist and everything
+  // it contains. The configuration should take place after everything
+  // has been added but before the initialisation.
+  void configure (const text_t &key, const text_tarray &cfgline);
+  virtual void configure (const text_t &key, const text_t &value);
+  const recptconf &get_configinfo () const {return configinfo;}
+  cgiargsinfoclass *get_cgiargsinfo_ptr () {return &argsinfo;}
+  
+
+  // init should be called after all the actions, protocols, and
+  // converters have been added to the receptionist and after everything
+  // has been configured but before any pages are created.
+  // It returns true on success and false on failure. If false is
+  // returned getpage should not be called (without producing
+  // meaningless output), instead an error page should be
+  // produced by the calling code.
+  virtual bool init (ostream &logout);
+  
+  // There are two ways to produce a page. You can either call parse_cgi_args,
+  // get_cgihead_info, and produce_content or you can just call parse_cgi_args and
+  // produce_cgi_page (which will be satisfactory in most cases). You might want to call
+  // parse_cgi_args, get_cgihead_info, and produce_content when you want to
+  // interface directly with a web server for which the standard header is inappropriate.
+
+  // parse_cgi_args parses cgi arguments into an argument class.
+  // This function should be called for each page request. It returns false
+  // if there was a major problem with the cgi arguments.
+  virtual bool parse_cgi_args (const text_t &argstr, cgiargsclass &args, 
+			       ostream &logout, text_tmap &fcgienv);
+
+  virtual bool log_cgi_args (cgiargsclass &args, ostream &logout, text_tmap &fcgienv);
+
+  text_t expandmacros (const text_t &astring, cgiargsclass &args, 
+		       ostream &logout);
+
+  // produce_cgi_page will call get_cgihead_info and 
+  // produce_content in the appropriate way to output a cgi header and
+  // the page content (if needed). If a page could not be created it
+  // will return false
+  virtual bool produce_cgi_page (cgiargsclass &args, ostream &contentout, 
+				 ostream &logout, text_tmap &fcgienv);
+  
+  // get_cgihead_info determines the cgi header information for
+  // a set of cgi arguments. If response contains location then
+  // response_data contains the redirect address. If reponse
+  // contains content then reponse_data contains the content-type.
+  // Note that images can now be produced by the receptionist.
+  virtual void get_cgihead_info (cgiargsclass &args, response_t &response,
+				 text_t &response_data, ostream &logout,
+				 text_tmap &fcgienv);
+  virtual void get_cgihead_info (cgiargsclass &args, text_tmap &headers,
+				 ostream &logout, text_tmap &fcgienv);
+
+  // produce the page content
+  virtual bool produce_content (cgiargsclass &args, ostream &contentout,
+				ostream &logout);
+  
+  // returns the compressed argument ("e") corresponding to the argument
+  // list. This can be used to save preferences between sessions.
+  virtual text_t get_compressed_arg (cgiargsclass &args, ostream &logout);
+
+  // gets collection info from cache if found or 
+  // calls collection server (and updates cache)
+  // returns NULL if there's an error
+  ColInfoResponse_t *get_collectinfo_ptr (recptproto *collectproto, 
+					  const text_t &collection, 
+					  ostream &logout);
+
+  void uncache_collection (const text_t &collection);
+  
+protected:
+  // will read in all the macro files. If one is not found an
+  // error message will be written to logout and the method will
+  // return false.
+  virtual bool read_macrofiles (ostream &logout);
+  
+  virtual void read_collection_macrofiles (const text_t& collection, ostream &logout);
+
+  // check_mainargs will check all the main arguments. If a major
+  // error is found it will return false and no cgi page should
+  // be created using the arguments.
+  virtual bool check_mainargs (cgiargsclass &args, ostream &logout);
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptconfig.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptconfig.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptconfig.cpp	(revision 10506)
@@ -0,0 +1,273 @@
+/**********************************************************************
+ *
+ * recptconfig.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "recptconfig.h"
+#include "fileutil.h"
+#include "cfgread.h"
+#include "cnfgator.h"
+
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace/std/iostream>
+#  include <ospace/std/fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#  include <fstream.h>
+#else
+#  include <iostream>
+#  include <fstream>
+#endif
+
+class __site_configuration : public configurable {
+private:
+  text_t *gsdlhome;
+  text_t *httpdomain;
+  text_t *httpprefix;
+  text_t *collection;
+  text_tset *actions;
+  text_tset *browsers;
+  int    *maxrequests;
+public:
+  __site_configuration (text_t *_gsdlhome, int *_maxrequests) {
+    gsdlhome = _gsdlhome;
+    httpdomain = NULL;
+    httpprefix = NULL;
+    collection = NULL;
+    actions = NULL;
+    browsers = NULL;
+    maxrequests = _maxrequests;
+  }
+
+  __site_configuration (text_t *_gsdlhome, text_t *_httpdomain,
+                        text_t *_httpprefix) {
+    gsdlhome    = _gsdlhome;
+    httpdomain = _httpdomain;
+    httpprefix = _httpprefix;
+    collection = NULL;
+    actions = NULL;
+    browsers = NULL;
+    maxrequests = NULL;
+  }
+
+  __site_configuration (text_t *_gsdlhome, text_t *_httpdomain,
+			text_t *_httpprefix, text_t *_collection) {
+    gsdlhome    = _gsdlhome;
+    httpdomain = _httpdomain;
+    httpprefix = _httpprefix;
+    collection = _collection;
+    actions = NULL;
+    browsers = NULL;
+    maxrequests = NULL;
+  }
+
+  __site_configuration (text_t *_httpprefix, text_tset *_actions, text_tset *_browsers) {
+    gsdlhome    = NULL;
+    httpdomain = NULL;
+    httpprefix = _httpprefix;
+    collection = NULL;
+    actions = _actions;
+    browsers = _browsers;
+    maxrequests = NULL;
+  }
+
+  inline void configure (const text_t &key, const text_tarray &cfgline) {
+    if (gsdlhome != NULL && key == "gsdlhome") {
+      *gsdlhome = cfgline[0];
+    }
+
+    if (httpprefix != NULL && key == "httpprefix") {
+      *httpprefix = cfgline[0];
+    }
+
+    if (httpdomain != NULL && key == "httpdomain") {
+      *httpdomain = cfgline[0];
+    }
+
+    if (collection != NULL && key == "collection") {
+      *collection = cfgline[0];
+    } 
+
+    if (actions != NULL && key == "actions") {
+      actions->clear();
+      text_tarray::const_iterator thisAction = cfgline.begin();
+      text_tarray::const_iterator endAction = cfgline.end();
+      while (thisAction != endAction) {
+	actions->insert(*thisAction);
+	++thisAction;
+      }
+    } 
+
+    if (browsers != NULL && key == "browsers") {
+      browsers->clear();
+      text_tarray::const_iterator thisBrowser = cfgline.begin();
+      text_tarray::const_iterator endBrowser = cfgline.end();
+      while (thisBrowser != endBrowser) {
+	browsers->insert(*thisBrowser);
+	++thisBrowser;
+      }
+    }
+
+    if (maxrequests != NULL && key == "maxrequests") {
+      *maxrequests = cfgline[0].getint();
+      if ((*maxrequests) < 1) {
+	*maxrequests = 1;
+      }
+    }
+  }
+};
+
+
+// reads site configuration file returning true on success
+// also sets gsdlhome and maxrequests 
+// gsdlsite.cfg should be in same directory as library executable
+bool site_cfg_read (receptionist &recpt, text_t &gsdlhome, int &maxrequests) {
+  // initialise configurator, etc.
+  __site_configuration sitecfg (&gsdlhome, &maxrequests);
+  configurator         gsdlconfigurator(&recpt);
+
+  gsdlconfigurator.add_configurable(&sitecfg);
+
+  // blank the gsdl home text
+  gsdlhome.clear();
+
+  if (gsdlconfigurator.configure("gsdlsite.cfg")) {
+    return true;
+  }
+  return false;
+}
+
+// this version grabs gsdlhome, httpdomain and httpprefix, 
+// returns false if it can't find all of them
+bool site_cfg_read (text_t &gsdlhome, text_t &httpdomain, 
+		    text_t &httpprefix) {
+  // get gsdlhome etc
+  __site_configuration sitecfg(&gsdlhome, &httpdomain, &httpprefix);
+  configurator gsdlconfigurator(&sitecfg);
+
+  gsdlhome.clear();
+  httpdomain.clear();
+  httpprefix.clear();
+
+  if (gsdlconfigurator.configure("gsdlsite.cfg")) {
+    return true;
+  }
+
+  return false;
+}
+
+// this version grabs gsdlhome, httpdomain, httpprefix, collection, 
+// returns false if it can't find gsdlhome, httpdomain and httpprefix
+bool site_cfg_read (text_t &gsdlhome, text_t &httpdomain, 
+		    text_t &httpprefix, text_t &collection) {
+  // get gsdlhome etc
+  __site_configuration sitecfg(&gsdlhome, &httpdomain, &httpprefix, &collection);
+  configurator gsdlconfigurator(&sitecfg);
+	
+  gsdlhome.clear();
+  httpdomain.clear();
+  httpprefix.clear();
+  collection.clear();
+	
+  if (gsdlconfigurator.configure("gsdlsite.cfg") &&
+      !gsdlhome.empty() && !httpdomain.empty() && !httpprefix.empty()) {
+    return true;
+  }	
+  return false;
+}
+
+void main_cfg_read (const text_t& collection, const text_t &gsdlhome, text_t &httpprefix, text_tset& actions, text_tset& browsers)
+{
+  __site_configuration sitecfg(&httpprefix, &actions, &browsers);
+  configurator gsdlconfigurator(&sitecfg);
+	
+  httpprefix.clear();
+  actions.clear();
+  browsers.clear();
+
+  text_t filename;
+	
+  filename_cat (filename, gsdlhome, "collect", collection, "etc", "main.cfg");
+  if (!file_exists(filename)) {
+    filename_cat (filename, gsdlhome, "etc", "main.cfg");
+    if (!file_exists (filename)) {
+      filename.clear();
+    }
+  }
+	
+  if (!filename.empty()) gsdlconfigurator.configure(filename);
+
+
+  if (!collection.empty()) {
+    filename_cat (filename, gsdlhome, "collect", collection, "etc", "collect.cfg");
+    if (!file_exists (filename)) {
+      filename_cat (filename, gsdlhome, "etc", "collect.cfg");
+      if (!file_exists (filename)) filename.clear();
+    }
+		
+    if (!filename.empty()) gsdlconfigurator.configure(filename);
+  }
+}
+
+// main_cfg_read reads both main.cfg and collect.cfg. It attempts
+// to read main.cfg first so values in collect.cfg override those
+// set earlier by main.cfg
+bool main_cfg_read (receptionist &recpt, const text_t &gsdlhome,
+		     const text_t &collection) {
+
+  // read in the main configuration file
+  bool rv = false;
+
+  text_t key, filename;
+  text_tarray cfgline;
+  filename = filename_cat (gsdlhome, "etc");
+  filename = filename_cat (filename, "main.cfg");
+  if (!collection.empty() && file_exists(filename)) {
+    rv = recpt.read_configfile(filename);
+  } else {
+    filename_cat (filename, gsdlhome, "etc", "main.cfg");
+    if (file_exists (filename)) {
+      rv = recpt.read_configfile(filename);
+    }
+  }
+
+  // Look for collect.cfg in GSDLHOME/collect/collection-name/etc directory 
+  // (if this is for a particular collection), and then GSDLHOME/etc.
+  if (!collection.empty()) {
+    filename = filename_cat (gsdlhome, "collect");
+    filename = filename_cat (filename, collection);
+    filename = filename_cat (filename, "etc");
+    filename = filename_cat (filename, "collect.cfg");
+    if (!file_exists (filename)) {
+      filename = filename_cat (gsdlhome, "etc");
+      filename = filename_cat (filename, "collect.cfg");
+      if (!file_exists (filename)) filename.clear();
+    }
+
+    if (!filename.empty()) {
+      rv |= recpt.read_configfile(filename);
+    }
+  }
+  return rv;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptconfig.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptconfig.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptconfig.h	(revision 10506)
@@ -0,0 +1,52 @@
+/**********************************************************************
+ *
+ * recptconfig.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef RECPTCONFIG_H
+#define RECPTCONFIG_H
+
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "receptionist.h"
+#include "collectset.h"
+
+
+// reads site configuration file returning true on success
+bool site_cfg_read (receptionist &recpt, text_t &gsdlhome, int &maxrequests);
+bool site_cfg_read (text_t &gsdlhome, text_t &httpdomain, text_t &httpprefix);
+bool site_cfg_read (text_t &gsdlhome, text_t &httpdomain, text_t &httpprefix, text_t &collection);
+
+// read main.cfg for the actions and httpprefix
+void main_cfg_read (const text_t& collection, const text_t &gsdlhome, text_t &httpprefix, text_tset& actions, text_tset& browsers);
+
+// main_cfg_read reads either collect.cfg or main.cfg and returning 
+// true on success. It attempts to read collect.cfg first if a
+// collection is specified and then it tries to read in main.cfg
+bool main_cfg_read (receptionist &recpt, const text_t &gsdlhome,
+		    const text_t &collection);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptmain.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptmain.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptmain.cpp	(revision 10506)
@@ -0,0 +1,35 @@
+/**********************************************************************
+ *
+ * recptmain.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "receptionist.h"
+#include "cgiwrapper.h"
+#include <assert.h>
+
+int main () {
+  receptionist recpt;
+  cgiwrapper (recpt, g_EmptyText);
+  return 0;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptproto.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptproto.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptproto.cpp	(revision 10506)
@@ -0,0 +1,174 @@
+/**********************************************************************
+ *
+ * recptproto.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "recptproto.h"
+#include <assert.h>
+
+
+// add collection server to protocol
+void recptproto::add_collection (const text_t &/*collection*/, void * /*recpt*/, 
+				 const text_t &/*gsdlhome*/, const text_t &/*gdbmhome*/) {
+}
+
+void recptproto::remove_collection (const text_t &/*collection*/, ostream &/*logout*/) {
+}
+
+// configure should be called for each line in the configuration file
+void recptproto::configure (const text_t &/*key*/, const text_tarray &/*cfgline*/, comerror_t &) {
+}
+
+// init should be called after the configuration but before any other
+// functions are called. If init returns false a message will be written
+// out to the log file and no other output should be produced.
+bool recptproto::init (comerror_t &err, ostream &/*logout*/) {
+  return true;
+}
+
+// get site name should return the name of the site used.
+// This is trivially empty in the case of a null protocol.  If a remote
+// connection to a site is being used then this should return the name
+// used to label a site
+text_t recptproto::get_site_name(comerror_t &err) {
+  return "localhost";
+}
+
+// get_protocol_name should return the name of this protocol (e.g. recptproto)
+// that can be used to do run time type identification and display information
+// about the protocol.
+text_t recptproto::get_protocol_name (comerror_t &err) {
+  return "recptproto";
+}
+
+// get_collection_list returns the list of collections that
+// this protocol knows about
+void recptproto::get_collection_list (text_tarray &collist, comerror_t &err, 
+				      ostream &/*logout*/) {
+  collist.erase(collist.begin(),collist.end());
+  err = noError;
+}
+
+// has_collection sets 'hascollection' to be true if the protocol
+// can communicate with the collection (i.e. it is within its 
+// collection list). This function should be implemented in as
+// efficient time as possible as it will be called for each page
+// access and for each protocol.
+void recptproto::has_collection (const text_t &/*collection*/, bool &hascollection, 
+				 comerror_t &err, ostream &/*logout*/) {
+  hascollection = false;
+  err = noError;
+}
+
+// sets 'wassuccess' to be true if a successful ping was done to
+// the given collection.
+void recptproto::ping (const text_t &/*collection*/, bool &wassuccess, 
+		       comerror_t &err, ostream &/*logout*/) {
+  wassuccess = false; // no collections are supported by this class
+  err = noError;
+}
+
+// obtains general information about the collection
+void recptproto::get_collectinfo (const text_t &/*collection*/, 
+				  ColInfoResponse_t &/*collectinfo*/,
+				  comerror_t &err, ostream &/*logout*/) {
+  err = protocolError;
+}
+
+// gets a list of all the filters
+void recptproto::get_filterinfo (const text_t &/*collection*/,
+				 InfoFiltersResponse_t &/*reponse*/,
+				 comerror_t &err, ostream &/*logout*/) {
+  err = protocolError;
+}
+
+// gets all the filter options for a particular filter
+void recptproto::get_filteroptions (const text_t &/*collection*/,
+				    const InfoFilterOptionsRequest_t &/*request*/,
+				    InfoFilterOptionsResponse_t &/*response*/, 
+				    comerror_t &err, ostream &/*logout*/) {
+  err = protocolError;
+}
+
+// filters (search or browse) a result set
+void recptproto::filter (const text_t &/*collection*/,
+			 FilterRequest_t &/*request*/,
+			 FilterResponse_t &/*response*/,
+			 comerror_t &err, ostream &/*logout*/) {
+  err = protocolError;
+}
+
+void recptproto::get_document (const text_t &/*collection*/,
+			       const DocumentRequest_t &/*request*/,
+			       DocumentResponse_t &/*response*/,
+			       comerror_t &err, ostream &/*logout*/) {
+  err = protocolError;
+}
+
+// sets issearchable to true if the given colection is searchable
+void recptproto::is_searchable (const text_t &/*collection*/, bool &issearchable, 
+				comerror_t &err, ostream &/*logout*/) {
+  issearchable = false; // no collections are supported by this class
+  err = noError;
+}
+
+
+
+
+
+
+
+// therecptproto remains the property of the calling code but
+// should not be deleted until it is removed from this list.
+void recptprotolistclass::addrecptproto (recptproto *therecptproto) {
+  // can't add a protocol that doesn't exist
+  assert (therecptproto != NULL);
+  if (therecptproto == NULL) return;
+
+  recptprotoptr rpp;
+  rpp.p = therecptproto;
+
+  recptprotoptrs.push_back(rpp);
+}
+
+// getrecptproto will return NULL if a recptproto for the given colelction
+// could not be found
+recptproto *recptprotolistclass::getrecptproto (const text_t &collection, 
+						ostream &logout) {
+  iterator here = recptprotoptrs.begin ();
+  iterator end = recptprotoptrs.end ();
+  bool hascollection;
+  comerror_t err;
+
+  while (here != end) {
+    assert ((*here).p != NULL);
+    if ((*here).p != NULL) {
+      (*here).p->has_collection (collection, hascollection, err, logout);
+      if ((err == noError) && (hascollection == true)) return (*here).p;
+    }
+    
+    ++here;
+  }
+  
+  return NULL;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptproto.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptproto.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/recptproto.h	(revision 10506)
@@ -0,0 +1,193 @@
+/**********************************************************************
+ *
+ * recptproto.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef RECPTPROTO_H
+#define RECPTPROTO_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "comtypes.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\vector>
+#elif defined(GSDL_USE_STL_H)
+#  include <vector.h>
+#else
+#  include <vector>
+#endif
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+// recptproto is a generalisation of a protocol for communicating
+// with a collection server.
+class recptproto {
+public:
+
+  // add collection server to protocol
+  virtual void add_collection (const text_t &collection, void *recpt, 
+			       const text_t &gsdlhome, const text_t &gdbmhome);
+
+  virtual void remove_collection (const text_t &collection, ostream &logout);
+
+  // configure should be called for each line in the configuration file
+  virtual void configure (const text_t &key, const text_tarray &cfgline, comerror_t &err);
+
+  // init should be called after the configuration but before any other
+  // functions are called. If init returns false a message will be written
+  // out to the log file and no other output should be produced.
+  virtual bool init (comerror_t &err, ostream &logout);
+
+  // get_site_name should return the name of the site used.
+  // This is trivially empty in the case of a null protocol.  If a remote
+  // connection to a site is being used then this should return the name
+  // used to label a site
+  virtual text_t get_site_name(comerror_t &err);
+
+  // get_protocol_name should return the name of this protocol (e.g. recptproto)
+  // that can be used to do run time type identification and display information
+  // about the protocol.
+  virtual text_t get_protocol_name (comerror_t &err);
+
+  // get_collection_list returns the list of collections that
+  // this protocol knows about
+  virtual void get_collection_list (text_tarray &collist, comerror_t &err, 
+				    ostream &logout);
+
+  // has_collection sets 'hascollection' to be true if the protocol
+  // can communicate with the collection (i.e. it is within its 
+  // collection list). This function should be implemented in as
+  // efficient time as possible as it will be called for each page
+  // access and for each protocol.
+  virtual void has_collection (const text_t &collection, bool &hascollection, 
+			       comerror_t &err, ostream &logout);
+
+  // sets 'wassuccess' to be true if a successful ping was done to
+  // the given collection.
+  virtual void ping (const text_t &collection, bool &wassuccess, 
+		     comerror_t &err, ostream &logout);
+
+  // obtains general information about the collection
+  virtual void get_collectinfo (const text_t &collection, 
+				ColInfoResponse_t &collectinfo,
+				comerror_t &err, ostream &logout);
+
+  // gets a list of all the filters
+  virtual void get_filterinfo (const text_t &collection,
+			       InfoFiltersResponse_t &response,
+			       comerror_t &err, ostream &logout);
+
+  // gets all the filter options for a particular filter
+  virtual void get_filteroptions (const text_t &collection,
+				  const InfoFilterOptionsRequest_t &request,
+				  InfoFilterOptionsResponse_t &response, 
+				  comerror_t &err, ostream &logout);
+
+  // filters (search or browse) a result set and returns information
+  // about the filtered set including term frequency information and 
+  // metadata
+  virtual void filter (const text_t &collection,
+		       FilterRequest_t &request,
+		       FilterResponse_t &response,
+		       comerror_t &err, ostream &logout);
+
+  // gets a document (duh!)
+  virtual void get_document (const text_t &collection,
+			     const DocumentRequest_t &request,
+			     DocumentResponse_t &response,
+			     comerror_t &err, ostream &logout);
+
+  virtual void is_searchable (const text_t &collection, bool &issearchable, 
+			      comerror_t &err, ostream &logout);
+
+};
+
+
+// The recptprotoptr function does not 'own' the recptproto. The 
+// recptproto should be deleted by the code which created it.
+class recptprotoptr {
+public:
+  recptproto *p;
+
+  recptprotoptr () {p=NULL;}
+  ~recptprotoptr () {}
+};
+
+typedef vector<recptprotoptr> recptprotoptrlist;
+
+
+// contains a list of recptprotos
+class recptprotolistclass {
+protected:
+  recptprotoptrlist recptprotoptrs;
+
+public:
+  // type support for recptprotolistclass
+  typedef recptprotoptrlist::iterator iterator;
+  typedef recptprotoptrlist::const_iterator const_iterator;
+  typedef recptprotoptrlist::reference reference;
+  typedef recptprotoptrlist::const_reference const_reference;
+  typedef recptprotoptrlist::size_type size_type;
+
+  typedef recptprotoptrlist::difference_type difference_type;
+  typedef recptprotoptrlist::const_reverse_iterator const_reverse_iterator;
+  typedef recptprotoptrlist::reverse_iterator reverse_iterator;
+  
+  // basic container support
+  iterator begin () {return recptprotoptrs.begin();}
+  const_iterator begin () const {return recptprotoptrs.begin();}
+  iterator end () {return recptprotoptrs.end();}
+  const_iterator end () const {return recptprotoptrs.end();}
+
+  void erase(iterator pos) {recptprotoptrs.erase(pos);}
+  void erase(iterator first, iterator last) {recptprotoptrs.erase(first, last);}
+  recptprotolistclass &operator=(const recptprotolistclass &x) 
+    {recptprotoptrs=x.recptprotoptrs;return *this;}
+
+  bool empty () const {return recptprotoptrs.empty();}
+  size_type size() const {return recptprotoptrs.size();}
+
+
+  // added functionality
+  void clear () {recptprotoptrs.erase(recptprotoptrs.begin(),recptprotoptrs.end());}
+
+  // therecptproto remains the property of the calling code but
+  // should not be deleted until it is removed from this list.
+  void addrecptproto (recptproto *therecptproto);
+
+  // getrecptproto will return NULL if a recptproto for the given collection
+  // could not be found
+  recptproto *getrecptproto (const text_t &collection, ostream &logout);
+};
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/statusaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/statusaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/statusaction.cpp	(revision 10506)
@@ -0,0 +1,1147 @@
+/**********************************************************************
+ *
+ * statusaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_STATUS_ACTION
+
+// following line required to get fstream.filedesc() on darwin (Mac OS X)
+#define _STREAM_COMPAT  1
+
+#include "statusaction.h"
+#include "fileutil.h"
+#include "htmlutils.h"
+#include "gsdltools.h"
+#include <assert.h>
+#include <stdio.h>
+#include <fcntl.h> // for open() stuff
+
+void statusaction::output_frameset (cgiargsclass &/*args*/, displayclass &disp, 
+				    outconvertclass &outconvert, 
+				    ostream &textout, ostream &/*logout*/) {
+  textout << outconvert << disp << "_status:frameset_\n";
+}
+
+void statusaction::output_select (cgiargsclass &/*args*/, displayclass &disp, 
+				  outconvertclass &outconvert, 
+				  ostream &textout, ostream &/*logout*/) {
+  textout << outconvert << disp << "_status:header_(selector)\n"
+    "_status:select_\n"
+    "_status:footer_\n";
+}
+
+void statusaction::output_welcome (cgiargsclass &args, recptprotolistclass *protos, 
+				   displayclass &disp, outconvertclass &outconvert, 
+				   ostream &textout, ostream &logout) {
+
+  if (recpt == NULL) return;
+
+  textout << outconvert << disp 
+	  << "_status:infoheader_(_titlewelcome_)\n"
+	  << "_status:welcome_"
+	  << "<center><table width=_pagewidth_>\n"
+	  << "<th align=left>abbrev.</th><th align=left>collection</th>"
+	  << "<th align=left>public?</th><th align=left>running?</th></tr>\n";
+
+  recptprotolistclass::iterator rprotolist_here = protos->begin();
+  recptprotolistclass::iterator rprotolist_end = protos->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+      comerror_t err;
+      text_t protoname = (*rprotolist_here).p->get_protocol_name(err);
+      text_tarray collist;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+
+	while (collist_here != collist_end) {
+
+	    textout << outconvert << disp
+		    << "<tr><td><a href=\"_gwcgi_?_optsite_e=_compressedoptions_&a=status&p=collectioninfo&pr="
+		    << protoname
+		    << "&c="
+		    << *collist_here
+		    << "\">"
+		    << *collist_here 
+		    << "</a></td>";
+
+	  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr ((*rprotolist_here).p, *collist_here, logout);
+	  if (cinfo != NULL) {
+	    text_t collname = cinfo->get_collectionmeta("collectionname", args["l"]);
+	    if (collname.empty()) {
+	      collname = *collist_here;
+	    }
+
+	    textout << "<td>";
+	    if (cinfo->buildDate > 0)
+	      textout << outconvert << disp 
+		      << "<a href=\"_httppagex_(about)&c=" << *collist_here
+		      << "\" target=\\_top>";
+
+	    textout << outconvert << disp << collname;
+
+	    if (cinfo->buildDate > 0) textout << "</a>";
+
+	    textout << "</td>";
+
+	    if (cinfo->isPublic) textout << "<td>yes</td>";
+	    else textout << "<td>no</td>";
+	    
+	    if (cinfo->buildDate > 0)
+	      textout << outconvert << "<td>yes</td>";
+	    else
+	      textout << "<td>no</td>";
+	    
+	  } else {
+	    textout << "<td></td><td></td><td></td>";
+	  }
+
+	  textout << "</tr>\n";
+	  ++collist_here;
+	}
+      }
+    }
+    ++rprotolist_here;
+  }
+
+  textout << "</table></center>\n";
+  textout << outconvert << disp << "_status:infofooter_\n";
+}
+
+void statusaction::output_generalinfo (cgiargsclass &/*args*/, displayclass &disp, 
+				       outconvertclass &outconvert, 
+				       ostream &textout, ostream &/*logout*/) {
+  if (recpt == NULL) return;
+  const recptconf &rcinfo = recpt->get_configinfo ();
+  
+  textout << outconvert << disp << "_status:infoheader_(General Information)\n";
+  textout << outconvert 
+	  << "<h2>General information</h2>\n"
+	  << "<table>\n"
+	  << "<tr valign=top><th>gsdlhome</th><td>\"" << rcinfo.gsdlhome
+	  << "\"</td></tr>\n"
+	  << "<tr valign=top><th>collection</th><td>\"" << rcinfo.collection
+	  << "\"</td></tr>\n"
+	  << "<tr valign=top><th>collectdir</th><td>\"" << rcinfo.collectdir
+	  << "\"</td></tr>\n"
+	  << "<tr valign=top><th>httpprefix</th><td>\"" << rcinfo.httpprefix
+	  << "\"</td></tr>\n"
+	  << "<tr valign=top><th>httpimg</th><td>\"" << rcinfo.httpimg
+	  << "\"</td></tr>\n"
+	  << "<tr valign=top><th>gwcgi</th><td>\"" << rcinfo.gwcgi
+	  << "\"</td></tr>\n";
+    
+  // macrofiles
+  textout << outconvert << "<tr valign=top><th>macrofiles</th><td>";
+  text_tset::const_iterator macrohere = rcinfo.macrofiles.begin ();
+  text_tset::const_iterator macroend = rcinfo.macrofiles.end ();
+  bool macrofirst = true;
+  while (macrohere != macroend) {
+    if (!macrofirst) textout << outconvert << ", ";
+    macrofirst = false;
+    textout << outconvert << "\"" << *macrohere << "\"";
+    ++macrohere;
+  }
+  textout << outconvert << "</td></tr>\n";
+  
+  // saveconf
+  textout << outconvert << "<tr valign=top><th>saveconf</th><td>\"" << rcinfo.saveconf
+	  << "\"</td></tr>\n";
+
+  // usecookies
+  textout << outconvert << "<tr valign=top><th>usecookies</th><td>\"";
+  if (rcinfo.usecookies) textout << outconvert << "true";
+  else textout << outconvert << "false";
+  textout << outconvert << "\"</td></tr>\n";
+  
+  // logcgiargs
+  textout << outconvert << "<tr valign=top><th>logcgiargs</th><td>\"";
+  if (rcinfo.logcgiargs) textout << outconvert << "true";
+  else textout << outconvert << "false";
+  textout << outconvert << "\"</td></tr>\n";
+
+  // pageparams
+  textout << outconvert << "<tr valign=top><th>pageparams</th><td>";
+  text_tmap::const_iterator params_here = rcinfo.pageparams.begin();
+  text_tmap::const_iterator params_end = rcinfo.pageparams.end();
+  bool params_first = true;
+  while (params_here != params_end) {
+    if (!params_first) textout << outconvert << ", ";
+    params_first = false;
+    textout << outconvert << "\"" << (*params_here).first << "\" != \""
+	    << (*params_here).second << "\"";
+    
+    ++params_here;
+  }
+  textout << outconvert << "</td></tr>\n";
+
+  // macroprecedence
+  textout << outconvert << "<tr valign=top><th>macroprecedence</th><td>\"" << rcinfo.macroprecedence
+	  << "\"</td></tr>\n";
+
+  // arguments
+  cgiargsinfoclass *rcargsinfo = recpt->get_cgiargsinfo_ptr ();
+  if (rcargsinfo != NULL) {
+    textout << outconvert << "<tr valign=top><th>arguments</th><td>";
+    
+    cgiargsinfoclass::const_iterator argsinfohere = rcargsinfo->begin ();
+    cgiargsinfoclass::const_iterator argsinfoend = rcargsinfo->end ();
+    bool argsinfofirst = true;
+    while (argsinfohere != argsinfoend) {
+      if (!argsinfofirst) textout << outconvert << ", ";
+      argsinfofirst = false;
+      textout << outconvert << "\"" << (*argsinfohere).second.shortname << "\"";
+      ++argsinfohere;
+    }
+    
+    textout << outconvert << "</td></tr>\n";
+  }      
+  
+  // actions
+  actionmapclass *actions = recpt->get_actionmap_ptr();
+  if (actions != NULL) {
+    textout << outconvert << "<tr valign=top><th>actions</th><td>";
+    
+    actionptrmap::iterator actionshere = actions->begin ();
+    actionptrmap::iterator actionsend = actions->end ();
+    bool actionsfirst = true;
+    while (actionshere != actionsend) {
+      if (!actionsfirst) textout << outconvert << ", ";
+      actionsfirst = false;
+      assert ((*actionshere).second.a != NULL);
+      if ((*actionshere).second.a != NULL) {
+	textout << outconvert << "\"" << (*actionshere).second.a->get_action_name() << "\"";
+      }
+      ++actionshere;
+    }
+    
+    textout << outconvert << "</td></tr>\n";
+  }
+  
+  // browsers
+  browsermapclass *browsers = recpt->get_browsermap_ptr();
+  if (browsers != NULL) {
+    textout << outconvert << "<tr valign=top><th>browsers</th><td>";
+    
+    browserptrmap::iterator browsershere = browsers->begin ();
+    browserptrmap::iterator browsersend = browsers->end ();
+    bool browsersfirst = true;
+    while (browsershere != browsersend) {
+      if (!browsersfirst) textout << outconvert << ", ";
+      browsersfirst = false;
+      assert ((*browsershere).second.b != NULL);
+      if ((*browsershere).second.b != NULL) {
+	textout << outconvert << "\"" << (*browsershere).second.b->get_browser_name() << "\"";
+      }
+      ++browsershere;
+    }
+    
+    textout << outconvert << "</td></tr>\n";
+  }
+
+  // protocols
+  recptprotolistclass *protocols = recpt->get_recptprotolist_ptr ();
+  if (protocols != NULL) {
+    textout << outconvert << "<tr valign=top><th>protocols</th><td>";
+    
+    recptprotolistclass::iterator protohere = protocols->begin ();
+    recptprotolistclass::iterator protoend = protocols->end ();
+    bool protofirst = true;
+    while (protohere != protoend) {
+      comerror_t err;
+      if (!protofirst) textout << outconvert << ", ";
+      protofirst = false;
+      if ((*protohere).p != NULL) {
+	textout << outconvert << "\"" << (*protohere).p->get_protocol_name(err) << "\"";
+      }
+      ++protohere;
+    }
+    
+    textout << outconvert << "</td></tr>\n";
+  }
+  
+  // converters
+  convertinfoclass *converters = recpt->get_convertinfo_ptr ();
+  if (converters != NULL) {
+    textout << outconvert << "<tr valign=top><th>converters</th><td>";
+    
+    convertinfoclass::iterator converthere = converters->begin ();
+    convertinfoclass::iterator convertend = converters->end ();
+    bool convertfirst = true;
+    while (converthere != convertend) {
+      if (!convertfirst) textout << outconvert << ", ";
+      convertfirst = false;
+      textout << outconvert << "\"" << (*converthere).second.name << "\"";
+      ++converthere;
+    }
+    
+    textout << outconvert << "</td></tr>\n";
+  }
+  
+  textout << outconvert << disp << "</table>\n_status:infofooter_\n";
+}
+
+void statusaction::output_argumentinfo (cgiargsclass &args, displayclass &disp, 
+					outconvertclass &outconvert, 
+					ostream &textout, ostream &/*logout*/) {
+  if (recpt == NULL) return;
+  cgiargsinfoclass *rcargsinfo = recpt->get_cgiargsinfo_ptr ();
+  if (rcargsinfo == NULL) return;
+
+  textout << outconvert << disp << "_status:infoheader_(Argument Information)\n";
+  textout << outconvert
+	  << "<h2>Argument information</h2>\n"
+	  << "<table>";
+
+  // argument information
+  textout << outconvert << "<tr valign=top><th>short name</th><th>long name</th>"
+	  << "<th>multiple char?</th>"
+	  << "<th>multiple value?</th>"
+	  << "<th>default</th><th>default status</th><th>saved args</th>"
+	  << "<th>current value</th></tr>\n";
+  
+
+  cgiargsinfoclass::const_iterator argsinfohere = rcargsinfo->begin();
+  cgiargsinfoclass::const_iterator argsinfoend = rcargsinfo->end();
+  text_t *arg_value;
+  while (argsinfohere != argsinfoend) {
+    const cgiarginfo &ainfo = (*argsinfohere).second;
+    textout << outconvert 
+	    << "<tr valign=top><td>" << ainfo.shortname << "</td>\n";
+    
+    textout << outconvert << "<td>" << ainfo.longname << "</td>\n";
+    if (ainfo.multiplechar) textout << outconvert << "<td>yes</td>\n";
+    else textout << outconvert << "<td>no</td>\n";
+    if (ainfo.multiplevalue) textout << outconvert << "<td>yes</td>\n";
+    else textout << outconvert << "<td>no</td>\n";
+    textout << outconvert << "<td>" << ainfo.argdefault << "</td>\n";
+    switch (ainfo.defaultstatus) {
+    case cgiarginfo::none: textout << outconvert << "<td>none</td>\n"; break;
+    case cgiarginfo::weak: textout << outconvert << "<td>weak</td>\n"; break;
+    case cgiarginfo::good: textout << outconvert << "<td>good</td>\n"; break;
+    case cgiarginfo::config: textout << outconvert << "<td>config</td>\n"; break;
+    case cgiarginfo::imperative: textout << outconvert << "<td>imperative</td>\n"; break;
+    }
+    switch (ainfo.savedarginfo) {
+    case cgiarginfo::mustnot: textout << outconvert << "<td>mustnot</td>\n"; break;
+    case cgiarginfo::can: textout << outconvert << "<td>can</td>\n"; break;
+    case cgiarginfo::must: textout << outconvert << "<td>must</td>\n"; break;
+    }
+    
+    arg_value = args.getarg (ainfo.shortname);
+    if (arg_value == NULL) textout << outconvert << "<td></td></tr>\n";
+    else textout << outconvert << "<td>\"" << *arg_value << "\"</td></tr>\n";
+    
+    ++argsinfohere;
+  }
+  
+  textout << outconvert << disp << "</table>\n_status:infofooter_\n";
+}
+
+void statusaction::output_actioninfo (cgiargsclass &/*args*/, displayclass &disp, 
+				      outconvertclass &outconvert, 
+				      ostream &textout, ostream &/*logout*/) {
+  if (recpt == NULL) return;
+  actionmapclass *actions = recpt->get_actionmap_ptr();
+
+  textout << outconvert << disp << "_status:infoheader_(Action Information)\n";
+  textout << outconvert
+	  << "<h2>Action information</h2>\n"
+	  << "<table>";
+
+  // action information
+  if (actions != NULL) {
+    textout << outconvert 
+	    << "<tr><th>action name</th><th>cgi arguments</th></tr>\n";
+	
+    actionptrmap::iterator actionshere = actions->begin ();
+    actionptrmap::iterator actionsend = actions->end ();
+    while (actionshere != actionsend) {
+      assert ((*actionshere).second.a != NULL);
+      if ((*actionshere).second.a != NULL) {
+	textout << outconvert 
+		<< "<tr><td>" << (*actionshere).second.a->get_action_name()
+		<< "</td><td>";
+	
+	cgiargsinfoclass argsinfo = (*actionshere).second.a->getargsinfo();
+	cgiargsinfoclass::const_iterator argsinfohere = argsinfo.begin ();
+	cgiargsinfoclass::const_iterator argsinfoend = argsinfo.end ();
+	bool aifirst = true;
+	while (argsinfohere != argsinfoend) {
+	  if (!aifirst) textout << outconvert << ", ";
+	  aifirst = false;
+	  textout << outconvert << (*argsinfohere).second.shortname;
+	  ++argsinfohere;
+	}
+	
+	textout << outconvert << "</td></tr>\n";
+      }
+      ++actionshere;
+    }
+  }
+  
+  textout << outconvert << disp << "</table>\n_status:infofooter_\n";
+}
+
+void statusaction::output_browserinfo (cgiargsclass &/*args*/, displayclass &disp, 
+				       outconvertclass &outconvert, 
+				       ostream &textout, ostream &/*logout*/) {
+  if (recpt == NULL) return;
+  browsermapclass *browsers = recpt->get_browsermap_ptr();
+
+  textout << outconvert << disp << "_status:infoheader_(Browser Information)\n";
+  textout << outconvert
+	  << "<h2>Browser information</h2>\n"
+	  << "<table>";
+
+  // browser information
+  if (browsers != NULL) {
+    textout << outconvert 
+	    << "<tr><th>browser name</th><th>default formatstring</th></tr>\n";
+	
+    browserptrmap::iterator browsershere = browsers->begin ();
+    browserptrmap::iterator browsersend = browsers->end ();
+    while (browsershere != browsersend) {
+      assert ((*browsershere).second.b != NULL);
+      if ((*browsershere).second.b != NULL) {
+	textout << outconvert 
+		<< "<tr><td>" << (*browsershere).second.b->get_browser_name()
+		<< "</td><td>" << html_safe ((*browsershere).second.b->get_default_formatstring())
+		<< "</td></tr>\n";
+      }
+      ++browsershere;
+    }
+  }
+  
+  textout << outconvert << disp << "</table>\n_status:infofooter_\n";
+}
+
+void statusaction::output_protocolinfo (cgiargsclass &/*args*/, displayclass &disp, 
+					outconvertclass &outconvert, 
+					ostream &textout, ostream &logout) {
+  if (recpt == NULL) return;
+  const recptconf &rcinfo = recpt->get_configinfo ();
+  bool colspecific = !rcinfo.collection.empty();
+  bool unreachablecol = false;
+
+  recptprotolistclass *rprotolist = recpt->get_recptprotolist_ptr ();
+  if (rprotolist == NULL) return;
+
+  textout << outconvert << disp << "_status:infoheader_(Protocol Information)\n";
+  textout << outconvert
+	  << "<h2>Protocol information</h2>\n"
+	  << "<table>\n"
+	  << "<tr><th>protocol</th><th>collections</th></tr>\n";
+
+  text_t protoname;
+  recptprotolistclass::iterator rprotolist_here = rprotolist->begin();
+  recptprotolistclass::iterator rprotolist_end = rprotolist->end();
+  while (rprotolist_here != rprotolist_end) {
+    if ((*rprotolist_here).p != NULL) {
+      comerror_t err;
+      protoname = (*rprotolist_here).p->get_protocol_name(err);
+      textout << outconvert
+	      << "<tr><td>"
+	      << protoname
+	      << "</td><td>";
+
+      text_tarray collist;
+      (*rprotolist_here).p->get_collection_list (collist, err, logout);
+      if (err == noError) {
+	text_tarray::iterator collist_here = collist.begin();
+	text_tarray::iterator collist_end = collist.end();
+	bool first = true;
+	while (collist_here != collist_end) {
+	  if (!first) textout << outconvert << ", ";
+	  first = false;
+
+	  if (colspecific && *collist_here != rcinfo.collection) {
+	    unreachablecol = true;
+	    textout << outconvert << "\"" << *collist_here << "\"";
+	  } else {
+	    textout << outconvert << disp
+		    << "\"<a href=\"_gwcgi_?e=_compressedoptions_&a=status&p=collectioninfo&pr="
+		    << protoname
+		    << "&c="
+		    << *collist_here
+		    << "\">"
+		    << *collist_here 
+		    << "</a>\"";
+	  }
+
+	  ++collist_here;
+	}
+
+      } else {
+	textout << outconvert << "Error (" << get_comerror_string (err) 
+		<< ") while getting collect list\n";
+      }
+
+      textout << outconvert 
+	      << "</td></tr>\n";
+    }
+
+    ++rprotolist_here;
+  }
+
+  textout << outconvert << "</table>\n";
+  if (unreachablecol) {
+    textout << outconvert 
+	    << "<b>Warning:</b> the receptionist is running in collection specific\n"
+	    << "mode making some of the collections unreachable.\n";
+  }
+  textout << outconvert << disp << "_status:infofooter_\n";
+}
+
+void statusaction::output_collectioninfo (cgiargsclass &args, displayclass &disp, 
+					  outconvertclass &outconvert, 
+					  ostream &textout, ostream &logout) {
+  if (recpt == NULL) return;
+
+  textout << outconvert << disp << "_status:infoheader_(Collection info)\n";
+  textout << outconvert << "<h2>Collection info</h2>\n";
+
+  // get the list of protocols
+  recptprotolistclass *rprotolist = recpt->get_recptprotolist_ptr ();
+  if (rprotolist == NULL) return;
+
+  // look for the desired protocol
+  text_t &arg_pr = args["pr"];
+  text_t &arg_c = args["c"];
+  recptproto *rproto = NULL;
+  recptprotolistclass::iterator rprotolist_here = rprotolist->begin();
+  recptprotolistclass::iterator rprotolist_end = rprotolist->end();
+  while (rprotolist_here != rprotolist_end) {
+    rproto = (*rprotolist_here).p;
+    comerror_t err;
+    if (rproto != NULL && rproto->get_protocol_name(err) == arg_pr) {
+      // see if the protocol has the collection
+      bool hascollection;
+      rproto->has_collection (arg_c, hascollection, err, logout);
+      if (err == noError && hascollection) break;
+    }
+    ++rprotolist_here;
+  }
+  
+  if (rprotolist_here == rprotolist_end) {
+    textout << outconvert << "Protocol \"" << arg_pr << "\" with collection \""
+	    << arg_c << "\" was not found\n";
+
+  } else {
+    // rproto can't be NULL to get here
+    ColInfoResponse_t *collectinfo = recpt->get_collectinfo_ptr (rproto, arg_c, logout);
+    if (collectinfo != NULL) {
+      textout << outconvert << "<table>\n"
+	      << "<tr><th>collection name</th><td>\""
+	      << collectinfo->shortInfo.name
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>host</th><td>\""
+	      << collectinfo->shortInfo.host
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>port</th><td>\""
+	      << collectinfo->shortInfo.port
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>is public?</th><td>";
+      if (collectinfo->isPublic) textout << outconvert << "true";
+      else textout << outconvert << "false";
+      textout << outconvert 
+	      << "</td></tr>\n"
+
+	      << "<tr><th>is beta?</th><td>";
+      if (collectinfo->isBeta) textout << outconvert << "true";
+      else textout << outconvert << "false";
+      textout << outconvert 
+	      << "</td></tr>\n"
+
+	      << "<tr><th>build date</th><td>\""
+	      << collectinfo->buildDate
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>interface languages</th><td>";
+      text_tarray::iterator languages_here = collectinfo->languages.begin();
+      text_tarray::iterator languages_end = collectinfo->languages.end();
+      bool languages_first = true;
+      while (languages_here != languages_end) {
+	if (!languages_first) textout << outconvert << ", ";
+	languages_first = false;
+	textout << outconvert << "\"" << *languages_here << "\"";
+	++languages_here;
+      }
+
+      textout << "<tr><th valign=top>collection metadata</th><td><table>\n";
+      collectionmeta_map::iterator meta_here = collectinfo->collectionmeta.begin();
+      collectionmeta_map::iterator meta_end = collectinfo->collectionmeta.end();
+      
+      while (meta_here != meta_end) {
+	textout << outconvert << "<tr><td valign=top>" << (*meta_here).first
+		<< "</td><td><table>" ;
+      	text_tmap lang_map = (*meta_here).second;
+	text_tmap::iterator lang_here = lang_map.begin();
+	text_tmap::iterator lang_end = lang_map.end();
+	while (lang_here != lang_end) {
+	  textout << outconvert << "<tr><td>" << (*lang_here).first
+		    << "</td><td>" << (*lang_here).second << "</td></tr>\n";
+	  
+	  ++lang_here;
+	}
+	textout << outconvert << "</table></td></tr>\n";
+	++meta_here;
+      }
+      textout << "</table></td></tr>\n";
+
+      textout << "<tr><th valign=top>format info</th><td><table>\n";
+      text_tmap::iterator format_here = collectinfo->format.begin();
+      text_tmap::iterator format_end = collectinfo->format.end();
+      while (format_here != format_end) {
+	textout << outconvert << "<tr><td valign=top>" << (*format_here).first
+		<< "</td><td>" << html_safe((*format_here).second) << "</td></tr>\n";
+	++format_here;
+      }
+      textout << "</table></td></tr>\n";
+
+      textout << "<tr><th valign=top>building info</th><td><table>\n";
+      text_tmap::iterator building_here = collectinfo->building.begin();
+      text_tmap::iterator building_end = collectinfo->building.end();
+      while (building_here != building_end) {
+	textout << outconvert << "<tr><td>" << (*building_here).first
+		<< "</td><td>" << (*building_here).second << "</td></tr>\n";
+	++building_here;
+      }
+      textout << "</table></td></tr>\n";
+
+      textout << outconvert 
+	      << "</td></tr>\n"
+
+	      << "<tr><th>number of documents</th><td>\""
+	      << collectinfo->numDocs
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>number of sections</th><td>\""
+	      << collectinfo->numSections
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>number of words</th><td>\""
+	      << collectinfo->numWords
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>number of bytes</th><td>\""
+	      << collectinfo->numBytes
+	      << "\"</td></tr>\n"
+
+	      << "<tr><th>preferred receptionist</th><td>\""
+	      << collectinfo->receptionist
+	      << "\"</td></tr>\n"
+
+	      << "</table>";
+      
+    } else {
+      textout << "ERROR (statusaction::output_collectioninfo): while getting collect information\n";
+    }
+
+
+    InfoFiltersResponse_t filterinfo;
+    InfoFilterOptionsRequest_t filteroptions_request;
+    InfoFilterOptionsResponse_t filteroptions;
+    comerror_t err;
+    rproto->get_filterinfo (arg_c, filterinfo, err, logout);
+    if (err == noError) {
+      text_tset::iterator filternames_here = filterinfo.filterNames.begin();
+      text_tset::iterator filternames_end = filterinfo.filterNames.end();
+      while (filternames_here != filternames_end) {
+	textout << outconvert 
+		<< "<hr>\n"
+		<< "<h3>Filter options for \"" << (*filternames_here) << "\"</h3>\n"
+		<< "<table>\n"
+		<< "<tr><th>option name</th><th>type</th><th>repeatable</th>"
+		<< "<th>default value</th><th>valid values</th></tr>\n";
+
+	filteroptions_request.clear();
+	filteroptions_request.filterName = *filternames_here;
+	rproto->get_filteroptions (arg_c, filteroptions_request,
+				   filteroptions, err, logout);
+	if (err == noError) {
+	  FilterOption_tmap::iterator filteropt_here = 
+	    filteroptions.filterOptions.begin();
+	  FilterOption_tmap::iterator filteropt_end = 
+	    filteroptions.filterOptions.end();
+	  while (filteropt_here != filteropt_end) {
+	    textout << outconvert
+		    << "<tr><td>\""
+		    << (*filteropt_here).second.name
+		    << "\"</td>\n"
+	      
+		    << "<td>";
+	    text_t type_string;
+	    switch ((*filteropt_here).second.type) {
+	    case FilterOption_t::booleant: type_string = "boolean"; break;
+	    case FilterOption_t::integert: type_string = "integer"; break;
+	    case FilterOption_t::enumeratedt: type_string = "enumerated"; break;
+	    case FilterOption_t::stringt: type_string = "string"; break;
+	    }
+	    textout << outconvert
+		    << type_string
+		    << "</td>\n"
+	      
+		    << "<td>";
+	    text_t repeat_string;
+	    switch ((*filteropt_here).second.repeatable) {
+	    case FilterOption_t::onePerQuery: repeat_string = "one per query"; break;
+	    case FilterOption_t::onePerTerm: repeat_string = "one per term"; break;
+	    case FilterOption_t::nPerTerm: repeat_string = "n per term"; break;
+	    }
+	    textout << outconvert
+		    << repeat_string
+		    << "</td>\n"
+	      
+		    << "<td>\""
+		    << (*filteropt_here).second.defaultValue
+		    << "\"</td>\n"
+	      
+		    << "<td>";
+	    
+	    text_tarray::iterator valid_here = 
+	      (*filteropt_here).second.validValues.begin();
+	    text_tarray::iterator valid_end = 
+	      (*filteropt_here).second.validValues.end();
+	    bool valid_first = true;
+	    while (valid_here != valid_end) {
+	      if (!valid_first) textout << outconvert << ", ";
+	      valid_first = false;
+	      textout << outconvert << "\"" << *valid_here << "\"";
+	      ++valid_here;
+	    }
+	    textout << outconvert
+		    << "</td></tr>\n";
+
+	    ++filteropt_here;
+	  }
+
+	  textout << outconvert
+		  << "</table>\n";
+
+	} else {
+	  textout << outconvert << "Error (" << get_comerror_string (err) 
+		  << ") while getting filter option information\n";
+	}
+
+	++filternames_here;
+      }
+
+    } else {
+      textout << outconvert << "Error (" << get_comerror_string (err) 
+	      << ") while getting filter information\n";
+    }
+  }
+  
+  textout << outconvert << disp << "_status:infofooter_\n";
+}
+
+void statusaction::output_usagelog (cgiargsclass &/*args*/, displayclass &disp,
+				    outconvertclass &outconvert, 
+				    ostream &textout, ostream &/*logout*/) {
+
+  // output last 100 lines of usage.txt
+
+  text_t logfilename = filename_cat (gsdlhome, "etc", "usage.txt");
+
+  textout << outconvert << disp << "_status:infoheader_(Usage log)\n";
+  textout << outconvert << "<h2>Usage log</h2>\n";
+
+  textout << outconvert << "<p>The usage log, "
+	  << logfilename << ", contains the\n"
+	  << "following information:\n"
+	  << "<p>(note that if this file is more than 100 lines long only the last 100 lines will\n"
+	  << "be displayed on this page)\n\n"
+	  << "<pre>\n";
+
+  // note that we're expecting lines to be no more than 1500 characters on
+  // average - should fix this file_tail() thing sometime
+  textout << outconvert << file_tail (logfilename, 100, 1500);
+
+  textout << outconvert << disp << "</pre>\n"
+	  << "_status:infofooter_\n";
+}
+
+void statusaction::output_errorlog (cgiargsclass &/*args*/, displayclass &disp, 
+				    outconvertclass &outconvert, 
+				    ostream &textout, ostream &logout) {
+
+  text_t errfilename = filename_cat (gsdlhome, "etc", "error.txt");
+  char *cerrfilename = errfilename.getcstr();
+  if (cerrfilename == NULL) return;
+
+  textout << outconvert << disp << "_status:infoheader_(Error log)\n";
+  textout << outconvert << "<h2>Error log</h2>\n";
+  logout << flush;
+
+#ifdef GSDL_USE_IOS_H
+  ifstream errin (cerrfilename, ios::in | ios::nocreate);
+#else
+  ifstream errin (cerrfilename, ios::in);
+#endif
+
+  delete []cerrfilename;
+  if (errin) {
+    textout << outconvert << "<p>The error log, "
+		<< errfilename << ", contains the\n";
+    textout << outconvert << "following information:\n\n";
+    text_t errorpage = "<p><pre>\n";
+
+    char c;
+    errin.get(c);
+    while (!errin.eof ()) {
+      errorpage.push_back(c);
+      errin.get(c);
+    }
+    
+    errorpage += "</pre>\n";
+    errin.close();
+    textout << outconvert << errorpage;
+
+  } else {
+    textout << outconvert << "Couldn't read error log, " 
+		<< errfilename << ".\n";
+  }
+
+  textout << outconvert << disp << "_status:infofooter_\n";
+}
+
+void statusaction::output_gsdlsite (cgiargsclass &/*args*/, displayclass &disp, 
+				    outconvertclass &outconvert, 
+				    ostream &textout, ostream &logout) {
+
+  textout << outconvert << disp << "_status:infoheader_(gsdlsite.cfg)\n";
+  textout << outconvert << "<h2>gsdlsite.cfg</h2>\n";
+  logout << flush;
+
+#ifdef GSDL_LOCAL_LIBRARY
+  text_t gsdlsite_cfg = filename_cat (gsdlhome, "gsdlsite.cfg");
+#else
+  text_t gsdlsite_cfg = "gsdlsite.cfg";
+#endif
+
+  char *gsdlsite_cfgc = gsdlsite_cfg.getcstr();
+#ifdef GSDL_USE_IOS_H
+  ifstream gsdlsitein (gsdlsite_cfgc, ios::in | ios::nocreate);
+#else
+  ifstream gsdlsitein (gsdlsite_cfgc, ios::in);
+#endif
+
+  delete []gsdlsite_cfgc;
+
+  if (gsdlsitein) {
+    textout << "<p>The gsdlsite.cfg configuration file contains the\n"
+	    << "following information:\n\n";
+    text_t gsdlsite = "<p><pre>\n";
+
+    char c;
+    gsdlsitein.get(c);
+    while (!gsdlsitein.eof ()) {
+      gsdlsite.push_back(c);
+      gsdlsitein.get(c);
+    }
+    
+    gsdlsite += "</pre>\n";
+    gsdlsitein.close();
+    textout << outconvert << gsdlsite;
+
+  } else {
+    textout << "Couldn't read gsdlsite.cfg configuration file\n";
+  }
+
+  textout << outconvert << disp << "_status:infofooter_\n";
+}
+
+void statusaction::output_maincfg (cgiargsclass &/*args*/, displayclass &disp, 
+				   outconvertclass &outconvert, 
+				   ostream &textout, ostream &/*logout*/) {
+
+  text_t maincfgfile = filename_cat (gdbmhome, "etc", "main.cfg");
+
+  textout << outconvert << disp << "_status:infoheader_(main.cfg)\n"
+	  << "<h2>main.cfg</h2>\n"
+	  << "<p>The main configuration file, "
+	  << dm_safe(maincfgfile) << ", contains the following information:<br>\n\n"
+	  << "(Note that only users belonging to the \"administrator\" group "
+	  << "may edit this file)<br>\n"
+	  << "_status:maincfg_<br>\n"
+	  << "_status:infofooter_\n";
+}
+
+void statusaction::change_maincfg (cgiargsclass &args, displayclass &disp, 
+				   outconvertclass &outconvert, 
+				   ostream &textout, ostream &logout) {
+
+  // write out the contents of the cfgfile argument to main.cfg
+  text_t cfgfile = filename_cat(gsdlhome, "etc", "main.cfg");
+  char *cfgfilec = cfgfile.getcstr();
+
+  int fd=open(cfgfilec, O_WRONLY | O_CREAT | O_TRUNC
+#if defined(__WIN32__)
+	      | O_BINARY
+#endif
+	      );
+
+  if (fd != -1) {
+
+    int lock_val = 1;
+    GSDL_LOCK_FILE (fd);
+    if (lock_val != 0) {
+      logout << "statusaction::change_maincfg: Error: Couldn't lock file " << cfgfilec << "\n";
+      textout << outconvert << disp << "_status:changemaincfgfail_";
+      close (fd);
+    } else {
+      outconvertclass text_t2ascii;
+      text_t2ascii.setinput(&args["cfgfile"]);
+      size_t buffersize=args["cfgfile"].size();
+      char *buffer=new char[buffersize];
+      size_t num_chars;
+      convertclass::status_t status;
+      text_t2ascii.convert(buffer, buffersize, num_chars, status);
+      // ignore status - assume it is "finished" as buffer is big enough
+      write(fd, buffer, num_chars);
+      GSDL_UNLOCK_FILE (fd);
+      delete []buffer;
+      close (fd);
+      textout << outconvert << disp << "_status:changemaincfgsuccess_";
+    }
+  } else {
+    logout << "statusaction::change_maincfg: Error: Couldn't open file " << cfgfilec << "for writing\n";
+    textout << outconvert << disp << "_status:changemaincfgfail_";
+  }
+  delete []cfgfilec;
+}
+
+void statusaction::output_errorpage (outconvertclass &outconvert, 
+				     ostream &textout, ostream &/*logout*/,
+				     text_t message) {
+  textout << outconvert 
+	  << "<html>\n"
+	  << "<head>\n"
+	  << "<title>Error</title>\n"
+	  << "</head>\n"
+	  << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
+	  << "alink=\"#cc9900\" vlink=\"#666633\">\n"
+	  << "<h2>Oops!</h2>\n" 
+	  << message
+	  << "\n</body>\n"
+	  << "</html>\n";
+  return;
+}
+
+
+
+statusaction::statusaction () {
+  disabled = true;
+  recpt = NULL;
+
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "status";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "p" -- status page
+  arg_ainfo.shortname = "p";
+  arg_ainfo.longname = "page";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "frameset";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "pr" -- protocol
+  arg_ainfo.shortname = "pr";
+  arg_ainfo.longname = "protocol";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::none;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::can;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  arg_ainfo.shortname = "cfgfile";
+  arg_ainfo.longname = "configuration file contents";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+statusaction::~statusaction () {
+}
+
+bool statusaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &args, 
+				  recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+
+  // only users belonging to the "administrator" group may edit 
+  // the main.cfg file
+  if (args["p"] == "maincfg" || args["p"] == "changemaincfg") {
+    args["uan"] = "1";
+    args["ug"] = "administrator";
+  }
+  return true;
+}
+
+void statusaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				     response_t &response, text_t &response_data, 
+				     ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+
+void statusaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					   recptprotolistclass * /*protos*/, ostream &logout) {
+
+  // define_internal_macros sets the following macros:
+  // _maincfgfile_   the contents of the main.cfg configuration file
+
+  // _versionnnum_   greenstone version number (hard-coded)
+
+  disp.setmacro("versionnum", "status", GSDL_VERSION);
+
+  if (args["p"] == "maincfg") {
+
+    // read in main.cfg
+    text_t maincfg = filename_cat(gsdlhome, "etc", "main.cfg");  
+    char *maincfgc = maincfg.getcstr();
+    
+#ifdef GSDL_USE_IOS_H
+    ifstream cfg_ifs (maincfgc, ios::in | ios::nocreate);
+#else
+    ifstream cfg_ifs (maincfgc, ios::in);
+#endif
+    
+    if (cfg_ifs) {  
+      text_t cfgtext;
+      char c;
+      cfg_ifs.get(c);
+      while (!cfg_ifs.eof ()) {
+	cfgtext.push_back(c);
+	cfg_ifs.get(c);
+      }
+      cfg_ifs.close();
+      
+      // define it as a macro
+      disp.setmacro("maincfgfile", "status", dm_safe(cfgtext));
+      
+    } else {
+      logout << "statusaction::define_internal_macros: couldn't open configuration file (" 
+	     << maincfgc << ") for reading\n";
+      disp.setmacro("maincfgfile", "status", g_EmptyText);
+    }    
+    delete []maincfgc;
+  }
+}
+
+bool statusaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
+			      browsermapclass * /*browsers*/, displayclass &disp, 
+			      outconvertclass &outconvert, ostream &textout, 
+			      ostream &logout) {
+  // make sure the status function is enabled
+  if (disabled) {
+    textout << outconvert 
+	    << "<html>\n"
+	    << "<head>\n"
+	    << "<title>Status disabled</title>\n"
+	    << "</head>\n"
+	    << "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#006666\" "
+	    << "alink=\"#cc9900\" vlink=\"#666633\">\n"
+	    << "<h2>Facility disabled</h2>\n" 
+	    << "Sorry, the Maintenance and Administration facility is currently disabled\n"
+	    << "\n</body>\n"
+	    << "</html>\n";
+    return true;
+  }
+  
+  // make sure we know about a receptionist
+  if (recpt == NULL) {
+    output_errorpage (outconvert, textout, logout, 
+		      "The status action does not contain information\n"
+		      "about any receptionists. The method set_receptionist\n"
+		      "was probably not called from the module which instantiated\n"
+		      "this status action.\n");
+    return true;
+  }
+
+  // check to make sure status.dm was read in
+  const recptconf &rcinfo = recpt->get_configinfo ();
+  text_tset::const_iterator macrohere = rcinfo.macrofiles.begin ();
+  text_tset::const_iterator macroend = rcinfo.macrofiles.end ();
+  while (macrohere != macroend) {
+    if (*macrohere == "status.dm") break;
+    ++macrohere;
+  }
+  if (macrohere == macroend) {
+    output_errorpage (outconvert, textout, logout, 
+		      "The status.dm file was not read in. This macro file is\n" 
+		      "needed to display configuration and status information.\n");
+    return true;
+  }
+
+  // output the required status page
+  text_t &arg_p = args["p"];
+  if (arg_p == "frameset") output_frameset (args, disp, outconvert, textout, logout);
+  else if (arg_p == "select") output_select (args, disp, outconvert, textout, logout);
+  else if (arg_p == "welcome") output_welcome (args, protos, disp, outconvert, textout, logout);
+  else if (arg_p == "generalinfo") output_generalinfo (args, disp, outconvert, textout, logout);
+  else if (arg_p == "argumentinfo") output_argumentinfo (args, disp, outconvert, textout, logout);
+  else if (arg_p == "actioninfo") output_actioninfo (args, disp, outconvert, textout, logout);
+  else if (arg_p == "browserinfo") output_browserinfo (args, disp, outconvert, textout, logout);
+  else if (arg_p == "protocolinfo") output_protocolinfo (args, disp, outconvert, textout, logout);
+  else if (arg_p == "collectioninfo") output_collectioninfo (args, disp, outconvert, textout, logout);
+  else if (arg_p == "usagelog") output_usagelog (args, disp, outconvert, textout, logout);
+  else if (arg_p == "errorlog") output_errorlog (args, disp, outconvert, textout, logout);
+  else if (arg_p == "gsdlsite") output_gsdlsite (args, disp, outconvert, textout, logout);
+  else if (arg_p == "maincfg") output_maincfg (args, disp, outconvert, textout, logout);
+  else if (arg_p == "changemaincfg") change_maincfg (args, disp, outconvert, textout, logout);
+  else {
+    output_errorpage (outconvert, textout, logout, 
+		      "Unknown page \"" + arg_p + "\".\n");
+  }
+
+  return true;
+}
+
+void statusaction::configure (const text_t &key, const text_tarray &cfgline) {
+  if ((key == "status") && (cfgline.size() == 1) && 
+      (cfgline[0] == "true" || cfgline[0] == "on" || cfgline[0] == "enabled")) {
+    disabled = false;
+  } else {
+    // call the parent class to deal with the things which
+    // are not dealt with here
+    action::configure (key, cfgline);
+  }
+}
+
+#endif //GSDL_USE_STATUS_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/statusaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/statusaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/statusaction.h	(revision 10506)
@@ -0,0 +1,132 @@
+/**********************************************************************
+ *
+ * statusaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_STATUS_ACTION
+
+#ifndef STATUSACTION_H
+#define STATUSACTION_H
+
+
+#include "gsdlconf.h"
+#include "action.h"
+#include "receptionist.h"
+
+
+class statusaction : public action {
+protected:
+  bool disabled;
+  receptionist *recpt;
+
+  void output_frameset (cgiargsclass &args, displayclass &disp, 
+			outconvertclass &outconvert, 
+			ostream &textout, ostream &logout);
+
+  void output_select (cgiargsclass &args, displayclass &disp, 
+		      outconvertclass &outconvert, 
+		      ostream &textout, ostream &logout);
+
+  void output_welcome (cgiargsclass &args, recptprotolistclass *protos,
+		       displayclass &disp, outconvertclass &outconvert, 
+		       ostream &textout, ostream &logout);
+
+  void output_generalinfo (cgiargsclass &args, displayclass &disp, 
+			   outconvertclass &outconvert, 
+			   ostream &textout, ostream &logout);
+
+  void output_argumentinfo (cgiargsclass &args, displayclass &disp, 
+			    outconvertclass &outconvert, 
+			    ostream &textout, ostream &logout);
+
+  void output_actioninfo (cgiargsclass &args, displayclass &disp, 
+			  outconvertclass &outconvert, 
+			  ostream &textout, ostream &logout);
+
+  void output_browserinfo (cgiargsclass &args, displayclass &disp, 
+			   outconvertclass &outconvert, 
+			   ostream &textout, ostream &logout);
+
+  void output_protocolinfo (cgiargsclass &args, displayclass &disp, 
+			    outconvertclass &outconvert, 
+			    ostream &textout, ostream &logout);
+
+  void output_collectioninfo (cgiargsclass &args, displayclass &disp, 
+			      outconvertclass &outconvert, 
+			      ostream &textout, ostream &logout);
+
+  void output_usagelog (cgiargsclass &args, displayclass &disp,
+			outconvertclass &outconvert, 
+			ostream &textout, ostream &logout);
+
+  void output_errorlog (cgiargsclass &args, displayclass &disp, 
+			outconvertclass &outconvert, 
+			ostream &textout, ostream &logout);
+
+  void output_gsdlsite (cgiargsclass &args, displayclass &disp, 
+			outconvertclass &outconvert, 
+			ostream &textout, ostream &logout);
+
+  void output_maincfg (cgiargsclass &args, displayclass &disp, 
+		       outconvertclass &outconvert, 
+		       ostream &textout, ostream &logout);
+
+  void change_maincfg (cgiargsclass &args, displayclass &disp, 
+		       outconvertclass &outconvert, 
+		       ostream &textout, ostream &logout);
+
+  void output_errorpage (outconvertclass &outconvert, 
+			 ostream &textout, ostream &logout,
+			 text_t message);
+
+public:
+  statusaction ();
+  virtual ~statusaction ();
+
+  text_t get_action_name () {return "status";}
+
+  void set_receptionist (receptionist *therecpt) {recpt=therecpt;}
+
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      recptprotolistclass *protos, ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+
+
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+};
+
+
+#endif //!STATUSACTION_H
+#endif //GSDL_USE_STATUS_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/string_pool.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/string_pool.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/string_pool.cpp	(revision 10506)
@@ -0,0 +1,44 @@
+/**********************************************************************
+ *
+ * string_pool.cpp -- 
+ * Copyright (C) 2003 DL Consulting Ltd
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "string_pool.h"
+
+string_pool::string_pool () {
+}
+
+string_pool::~string_pool () {
+  vector<char *>::const_iterator here = pool.begin();
+  vector<char *>::const_iterator end = pool.end();
+  while (here != end) {
+    delete(*here);
+    ++here;
+  }
+}
+
+char *string_pool::get_cstr_from_pool(const text_t &str) {
+  char *cstr = str.getcstr();
+  pool.push_back(cstr);
+  return cstr;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/string_pool.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/string_pool.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/string_pool.h	(revision 10506)
@@ -0,0 +1,45 @@
+/**********************************************************************
+ *
+ * string_pool.h -- 
+ * Copyright (C) 2003 DL Consulting Ltd
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef STRING_POOL_H
+#define STRING_POOL_H
+
+#include "text_t.h"
+
+class string_pool {
+protected:
+  
+  vector<char *> pool;
+
+public:
+  string_pool();
+  virtual ~string_pool();
+
+  char* get_cstr_from_pool (const text_t &str);
+
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/summarise.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/summarise.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/summarise.cpp	(revision 10506)
@@ -0,0 +1,270 @@
+/**********************************************************************
+ *
+ * summarise.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+/* The function 'summarise' produces, given a document text and a query,
+ * a (query-biased) summary. In the future, several types of summaries will
+ * be supported.
+ */
+
+#include "summarise.h"
+#include "unitool.h"
+#include <string.h>
+
+
+/* **************** LOCAL PROTOTYPES **************** */
+
+text_t summarise_startend(text_t &htmlstr, int summaryLength);
+text_t summarise_keywords(text_t &htmlstr, text_t &query, int summaryLength);
+
+text_t next_sentence(text_t::iterator& start, text_t::iterator& end);
+text_t previous_sentence(text_t::iterator& start, text_t::iterator& end);
+bool paragraph_tag(text_t::iterator start);
+
+
+/****************************************************
+ NAME: summarise
+ DESC: produce a summary for a document
+*****************************************************/
+
+text_t summarise(text_t &htmlstr, text_t &query, int summaryLength) {
+  //  return summarise_startend(htmlstr,summaryLength);
+  return summarise_keywords(htmlstr,query,summaryLength);
+}
+
+
+/****************************************************
+ NAME: summarise_startend
+ DESC: return first and last sentences of a document
+*****************************************************/
+
+text_t summarise_startend(text_t &htmlstr, int summaryLength) {
+  text_t::iterator str_start = htmlstr.begin(), str_end = htmlstr.end();
+  text_t answer;
+
+  // add first sentences up to half the summary length
+
+  text_t::iterator str_current = str_start;
+  while(str_current<str_end && answer.size()<(summaryLength/2)) {
+    text_t sentence = next_sentence(str_current,str_end);
+    answer.append(sentence);
+  }
+
+  summaryLength -= answer.size(); // summary length left for last sentences
+  if(summaryLength<0)
+    summaryLength = 0;
+
+  str_end = str_current;
+  str_current = htmlstr.end()-1;
+  text_t lastSentence;
+  while(str_current>str_end && 
+        lastSentence.size()<summaryLength) {
+    text_t sentence = previous_sentence(str_current,str_end);
+    lastSentence = sentence + lastSentence;
+  }
+
+  answer += " ... ";
+  answer += lastSentence;
+
+  return answer;
+}
+
+
+/****************************************************
+ NAME: summarise_keywords
+ DESC: build a summary with sentences containing keyword(s).
+       the sentences with most matching keywords are returned 
+       first.
+*****************************************************/
+
+text_t summarise_keywords(text_t &htmlstr, text_t &query, int summaryLength) {
+
+  text_tarray allterms, terms;
+  splitchar(query.begin(),query.end(),' ',allterms);
+
+  // consider only non-empty terms
+  for(text_tarray::iterator term = allterms.begin();
+      term < allterms.end(); ++term) {
+    if(!(*term).empty())
+      terms.push_back(*term);
+  }
+
+  text_tarray::iterator terms_start = terms.begin(), terms_end = terms.end();
+
+  //text_tarray::iterator terms_current = terms_start;
+  //strstr("merde",*terms_current);
+
+  text_t::iterator str_start = htmlstr.begin(), str_end = htmlstr.end();
+
+  vector<text_tarray> answers(terms.size()); 
+    // an array of array of sentences for the summary:
+    //   answers[0] contains sentences with 1 keyword
+    //   answers[1] contains sentences with 2 keywords, etc.
+  vector<int> answersSize(terms.size());
+    // answersSize[0] is the combined size of sentences with 1 keyword, etc.
+  for(vector<int>::iterator size = answersSize.begin();
+      size<answersSize.end(); ++size)
+    *size = 0; // initialise sentence size
+
+  int totfound  = 0;
+  text_t::iterator str_current = str_start;
+  while(str_current<str_end && answersSize[terms.size()-1]<summaryLength) {
+    // if the size of best sentences is greater than summary, that's enough!
+    text_t sentence = next_sentence(str_current,str_end);
+
+    text_tarray::iterator terms_current = terms_start;
+    int nFound = 0;
+    while(terms_current!=terms_end) {
+      text_t::iterator word = findword(sentence.begin(),sentence.end(),
+				       *terms_current);
+      if(word!=sentence.end())
+	{        ++nFound; ++totfound; }
+      ++terms_current;
+    }
+
+    if(nFound>0 && answersSize[nFound-1]<summaryLength) {
+      answers[nFound-1].push_back(sentence);
+      answersSize[nFound-1] += sentence.size();
+    }
+  }
+
+  text_t answer;
+  for(vector<text_tarray>::iterator sentarray = answers.end()-1;
+      sentarray>=answers.begin(); --sentarray)
+    for(text_tarray::iterator sentence = (*sentarray).begin(); 
+        sentence < (*sentarray).end(); ++sentence) {
+      answer.append(*sentence);
+      if(answer.size()>=summaryLength)
+        return answer;
+    }
+
+  if(!answer.empty())
+    return answer;
+
+  return summarise_startend(htmlstr,summaryLength);
+}
+
+
+/* *********************** LOCAL FUNCTIONS ******************* */
+
+/* NAME: next_sentence
+   DESC: returns next sentence, text-only (ie. HTML markup is removed)
+ */
+
+text_t next_sentence(text_t::iterator& start, text_t::iterator& end) {
+  text_t sentence;                 // the sentence to be returned
+  bool   foundPunctuation = false; // set to true by '.', '!' or '?'
+  while(start<end && !foundPunctuation) {
+    switch (*start) {
+    case '<': // skip over rest of html tag
+      if(paragraph_tag(start) && has_unicode_letdig(sentence))
+        foundPunctuation = true;
+      while ((start<end) && (*start!='>'))
+	++start;
+      if(start<end) ++start;
+      break;
+    case '.':
+    case '!':
+    case '?':
+      sentence.push_back(*start);
+      ++start;
+      if(start>=end || 
+         (is_unicode_space(*start) && (*(start-2)<'A' || *(start-2)>'Z'))) {
+        foundPunctuation = true;
+      }
+      break;
+    default:
+      sentence.push_back(*start);
+      ++start;
+      break;
+    }
+  }
+  return sentence;
+}
+
+
+/* NAME: previous_sentence
+   DESC: returns previous sentence, text-only (ie. HTML markup is removed)
+ */
+
+text_t previous_sentence(text_t::iterator& start, text_t::iterator& end) {
+  text_t sentence;                    // the sentence to be returned
+  bool   found1stPunctuation = false, // set to true by '.', '!' or '?'
+                                      // first punct. is included in results
+         found2ndPunctuation = false; // second punct. is stop condition,
+                                      // and is not included in results
+  while(start>end && !found2ndPunctuation) {
+    switch (*start) {
+    case '>': // skip over rest of html tag
+      while ((start>end) && (*start!='<')) // backtrack to beginning of tag
+	--start;
+      if(start>end) {
+        if(paragraph_tag(start) && has_unicode_letdig(sentence))
+          found2ndPunctuation = true;
+        --start;
+      }
+      break;
+    case '.':
+    case '!':
+    case '?':
+      if(!is_unicode_space(*(start+1)) ||
+         (start-1>end && *(start-1)>='A' && *(start-1)<='Z')) {
+        // if next character is not a blank, or preceding character is
+	// a capital letter, we guess it's an acronym (e.g. "U.S.A.")
+        sentence.text_as_usvector().insert(sentence.text_as_usvector().begin(),
+          start,start+1);
+        --start;
+      } else
+        if(has_unicode_letdig(sentence) || found1stPunctuation)
+          found2ndPunctuation = true;
+        else {
+          sentence.text_as_usvector().insert(
+              sentence.text_as_usvector().begin(),start,start+1);
+          --start;
+          found1stPunctuation = true;
+        }
+      break;
+    default:
+      sentence.text_as_usvector().insert(
+        sentence.text_as_usvector().begin(),start,start+1);
+      --start;
+      break;
+    }
+  }
+  return sentence;
+}
+
+
+// start is positioned on the '<'
+bool paragraph_tag(text_t::iterator start) {
+  if(*start=='<') {
+    ++start;
+    if(*start=='p' || *start=='P') {
+      ++start;
+      if(is_unicode_space(*start) || *start=='>')
+        return true;
+    }
+  }
+  return false;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/summarise.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/summarise.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/summarise.h	(revision 10506)
@@ -0,0 +1,34 @@
+/**********************************************************************
+ *
+ * summarise.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef SUMMARISE_H
+#define SUMMARISE_H
+
+#include "text_t.h"
+
+text_t summarise(text_t &htmlstr, text_t &query, int summaryLength);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/tipaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/tipaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/tipaction.cpp	(revision 10506)
@@ -0,0 +1,73 @@
+/**********************************************************************
+ *
+ * tipaction.cpp -- define random tip macros
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_TIP_ACTION
+
+#include "tipaction.h"
+#include <stdlib.h>
+
+
+tipaction::tipaction () {
+  // "st" show tips - "0"=no, "1"=yes
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "st";
+  arg_ainfo.longname = "show tips";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "1";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+void tipaction::define_external_macros (displayclass &disp, cgiargsclass &args, 
+					recptprotolistclass * /*protos*/, ostream &logout) {
+
+  // define_external_macros sets the following macros:
+
+  // _tip:thistip_  - a random tip (defined if st == "1")
+
+  if (args["st"].getint()) {
+    // get the maximum tip number (_tip:tipmax_)
+    text_t tipmax_str;
+    disp.expandstring ("tip", "_tipmax_", tipmax_str);
+    if (tipmax_str.empty()) {
+      // don't bother filling up the logs if tip.dm isn't loaded!
+      // logout << "Warning: _tip:tipmax_ not set. This macro is needed for displaying tips.\n";
+      return;
+    }
+    
+    int tipmax = tipmax_str.getint();
+    if (tipmax < 1) {
+      // don't bother filling up the logs if tip.dm isn't loaded!
+      // logout << "Warning: _tip:tipmax_ was less than 1. No tips were set.\n";
+      return;
+    }
+    
+    disp.setmacro("thistip", "tip", "_tip" + text_t((rand()%tipmax) + 1) + "_");
+  }
+}
+
+#endif //GSDL_USE_TIP_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/tipaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/tipaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/tipaction.h	(revision 10506)
@@ -0,0 +1,49 @@
+/**********************************************************************
+ *
+ * tipaction.h -- define tip macros
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_TIP_ACTION
+
+#ifndef TIPACTION_H
+#define TIPACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+
+
+// tipaction exists just for the benefit of defining external macros
+class tipaction : public action {
+public:
+  tipaction ();
+  virtual ~tipaction () {}
+  text_t get_action_name () {return "tip";}
+  
+  void define_external_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+};
+
+
+#endif //!TIPACTION_H
+#endif //GSDL_USE_TIP_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/userdb.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/userdb.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/userdb.cpp	(revision 10506)
@@ -0,0 +1,376 @@
+/**********************************************************************
+ *
+ * userdb.cpp -- functions to handle a user database
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdlconf.h"
+#include "userdb.h"
+#include "gsdltimes.h"
+#include "fileutil.h"
+#include <stdlib.h>
+
+// include crypt
+#if defined(__WIN32__)
+#include "crypt.h"
+#else
+#if defined(HAVE_CRYPT_H)
+#include <crypt.h>
+#else 
+#include <unistd.h>
+#endif
+#endif
+
+
+// few useful functions
+
+text_t crypt_text (const text_t &text) {
+  static const char *salt = "Tp";
+  text_t crypt_password;
+
+  if (text.empty()) return g_EmptyText;
+
+  // encrypt the password
+  char *text_cstr = text.getcstr();
+  if (text_cstr == NULL) return g_EmptyText;
+  crypt_password = crypt(text_cstr, salt);
+  delete []text_cstr;
+
+  return crypt_password;
+}
+
+
+// username_ok tests to make sure a username is ok. a username
+// must be at least 2 characters long, but no longer than 30
+// characters long. it can contain the characters a-z A-Z 0-9
+// . and _
+bool username_ok (const text_t &username) {
+  if (username.size() < 2 || username.size() > 30) return false;
+
+  text_t::const_iterator here = username.begin();
+  text_t::const_iterator end = username.end();
+  while (here != end) {
+    if ((*here >= 'a' && *here <= 'z') ||
+	(*here >= 'A' && *here <= 'Z') ||
+	(*here >= '0' && *here <= '9') ||
+	*here == '.' ||
+	*here == '_') {
+      // ok
+    } else return false;
+    ++here;
+  }
+
+  return true;
+}
+
+// password_ok tests to make sure a password is ok. a password
+// must be at least 3 characters long but no longer than 8 characters
+// long. it can contain any character in the range 0x20-0x7e
+bool password_ok (const text_t &password) {
+  if (password.size() < 3 || password.size() > 8) return false;
+
+  text_t::const_iterator here = password.begin();
+  text_t::const_iterator end = password.end();
+  while (here != end) {
+    if (*here >= 0x20 && *here <= 0x7e) {
+      // ok
+    } else return false;
+    ++here;
+  }
+
+  return true;
+}
+
+
+
+
+/////////////
+// userinfo_t
+/////////////
+
+void userinfo_t::clear () {
+  username.clear();
+  password.clear();
+  enabled = false;
+  groups.clear();
+  comment.clear();
+}
+
+userinfo_t &userinfo_t::operator=(const userinfo_t &x) {
+  username = x.username;
+  password = x.password;
+  enabled = x.enabled;
+  groups = x.groups;
+  comment = x.comment;
+  
+  return *this;
+}
+
+
+
+// functions dealing with user databases
+
+// returns true on success (in which case userinfo will contain
+// the information for this user)
+bool get_user_info (gdbmclass &userdb, const text_t &username,
+		    userinfo_t &userinfo) {
+  userinfo.clear();
+  
+  infodbclass info;
+  if (userdb.getinfo (username, info)) {
+    userinfo.username = info["username"];
+    userinfo.password = info["password"];
+    userinfo.enabled = (info["enabled"] == "true");
+    userinfo.groups = info["groups"];
+    userinfo.comment = info["comment"];
+    return true;
+  }
+
+  return false;
+}
+
+bool get_user_info (const text_t &userdbfile, const text_t &username,
+		    userinfo_t &userinfo) {
+  gdbmclass userdb;
+  if (!userdb.opendatabase(userdbfile, GDBM_READER, 1000, true)) {
+/*    if (!userdbfile.empty() && !file_exists (userdbfile) &&
+	username == "admin") {*/
+    if (!userdbfile.empty() && username == "admin") {
+      // no database -- create a database with an initial account
+      userinfo.clear();
+      userinfo.username = "admin";
+      userinfo.password = crypt_text("admin");
+      userinfo.enabled = true;
+      userinfo.groups = "administrator,colbuilder";
+      userinfo.comment = "change the password for this account as soon as possible";
+      return set_user_info (userdbfile, username, userinfo);
+    }
+    return false;
+  }
+
+  bool success = get_user_info (userdb, username, userinfo);
+  userdb.closedatabase();
+
+  return success;
+}
+
+// returns true on success
+bool set_user_info (gdbmclass &userdb, const text_t &username,
+		    const userinfo_t &userinfo) {
+  infodbclass info;
+  info["username"] = userinfo.username;
+  info["password"] = userinfo.password;
+  info["enabled"] = userinfo.enabled ? "true" : "false";
+  info["groups"] = userinfo.groups;
+  info["comment"] = userinfo.comment;
+
+  return userdb.setinfo (username, info);
+}
+
+bool set_user_info (const text_t &userdbfile, const text_t &username,
+		    const userinfo_t &userinfo) {
+  gdbmclass userdb;
+  if (!userdb.opendatabase(userdbfile, GDBM_WRCREAT, 1000, true)) return false;
+
+  bool success = set_user_info (userdb, username, userinfo);
+  userdb.closedatabase();
+
+  return success;
+}
+
+// removes a user from the user database -- forever
+void delete_user (gdbmclass &userdb, const text_t &username) {
+  userdb.deletekey (username);
+}
+
+void delete_user (const text_t &userdbfile, const text_t &username) {
+  gdbmclass userdb;
+  if (!userdb.opendatabase(userdbfile, GDBM_WRCREAT, 1000, true)) return;
+
+  delete_user (userdb, username);
+  userdb.closedatabase();
+}
+
+// gets a list of all the users in the database. returns true
+// on success
+void get_user_list (gdbmclass &userdb, text_tarray &userlist) {
+  userlist.erase (userlist.begin(), userlist.end());
+  
+  text_t user = userdb.getfirstkey ();
+  while (!user.empty()) {
+    userlist.push_back(user);
+    user = userdb.getnextkey (user);
+  }
+}
+
+// returns true if the user's password is correct.
+bool check_passwd (const userinfo_t &thisuser, const text_t &password) {
+  // couple of basic checks
+  if (thisuser.username.empty() || thisuser.password.empty() ||
+      password.empty()) return false;
+
+  text_t crypt_password = crypt_text(password);
+  return (thisuser.password == crypt_password);
+}
+
+// removes spaces from user groups
+text_t format_user_groups(const text_t user_groups){
+
+  text_t new_groups = g_EmptyText;
+  text_t::const_iterator here = user_groups.begin();
+  text_t::const_iterator end = user_groups.end();
+  while (here != end) {
+    if (*here != ' '&& *here != '\t' && *here != '\n') {
+      new_groups.push_back(*here);
+    }
+    ++here;
+  }
+  return new_groups;
+}
+
+// functions dealing with databases of temporary keys
+
+// generates a random key for the user, stores it in the database and
+// returns it so that it can be used in page generation
+// returns "" on failure
+text_t generate_key (gdbmclass &keydb, const text_t &username) {
+  static const char *numconvert = "0123456789abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+  // loop looking for a suitable new key
+  text_t userkey;
+  text_t crypt_userkey;
+  do {
+    // convert to base 62 :-)
+    int userkey_int = rand ();
+    while (userkey_int > 0) {
+      userkey.push_back (numconvert[userkey_int%62]);
+      userkey_int /= 62;
+    }
+
+    // make sure this key is not in the database
+    crypt_userkey = crypt_text(userkey);
+    if (keydb.exists (crypt_userkey)) userkey.clear();
+  } while (userkey.empty());
+
+  // enter the key into the database
+  infodbclass keydata;
+  keydata["user"] = username;
+  keydata["time"] = time2text(time(NULL));
+  
+  if (!keydb.setinfo (crypt_userkey, keydata)) {
+    userkey.clear(); // failed
+  }
+  
+  return userkey;
+}
+
+text_t generate_key (const text_t &keydbfile, const text_t &username) {
+  gdbmclass keydb;
+  if (!keydb.opendatabase(keydbfile, GDBM_WRCREAT, 1000, true)) return g_EmptyText;
+
+  text_t key = generate_key (keydb, username);
+  keydb.closedatabase();
+
+  return key;
+}
+
+
+// checks to see if there is a key for this particular user in the
+// database that hasn't decayed. a short decay is used when group
+// is set to administrator
+bool check_key (gdbmclass &keydb, const userinfo_t &thisuser,
+		const text_t &key, const text_t &group, int keydecay) {
+  if (thisuser.username.empty() || key.empty()) return false;
+
+  // the keydecay is set to 5 minute for things requiring the
+  // administrator
+  //  if (group == "administrator") keydecay = 300;
+  
+  // success if there is a key in the key database that is owned by this
+  // user whose creation time is less that keydecay
+  text_t crypt_key = crypt_text(key);
+  infodbclass info;
+  if (keydb.getinfo (crypt_key, info))  {
+    if (info["user"] == thisuser.username) {
+      time_t keycreation = text2time (info["time"]);
+      if (keycreation != (time_t)-1 && difftime (text2time(time2text(time(NULL))),
+						 keycreation) <= keydecay) {
+	// succeeded, update the key's time
+	info["time"] = time2text(time(NULL));
+	keydb.setinfo (crypt_key, info);
+	return true;
+      }
+    }
+  }
+  
+  return false;;
+}
+
+bool check_key (const text_t &keydbfile, const userinfo_t &thisuser,
+		const text_t &key, const text_t &group, int keydecay) {
+  gdbmclass keydb;
+  if (!keydb.opendatabase(keydbfile, GDBM_WRCREAT, 1000, true)) return false;
+
+  bool success = check_key (keydb, thisuser, key, group, keydecay);
+  keydb.closedatabase();
+
+  return success;
+}
+
+
+// remove_old_keys will remove all keys created more than keydecay ago.
+// use sparingly, it can be quite an expensive function
+void remove_old_keys (const text_t &keydbfile, int keydecay) {
+  // open the key database
+  gdbmclass keydb;
+  if (!keydb.opendatabase(keydbfile, GDBM_WRCREAT, 1000, true)) return;
+
+  // get a list of keys created more than keydecay seconds agon
+  text_tarray oldkeys;
+  text_t key = keydb.getfirstkey ();
+  infodbclass info;
+  time_t timenow = text2time(time2text(time(NULL)));
+  time_t keycreation = (time_t)-1;
+  while (!key.empty()) {
+    if (keydb.getinfo (key, info))  {
+      keycreation = text2time (info["time"]);
+      if (keycreation != (time_t)-1 && difftime (timenow, keycreation) > keydecay) {
+	// found an old key
+	oldkeys.push_back(key);
+      }
+    }
+    
+    key = keydb.getnextkey (key);
+  }
+
+  // delete the keys
+  text_tarray::iterator keys_here = oldkeys.begin();
+  text_tarray::iterator keys_end = oldkeys.end();
+  while (keys_here != keys_end) {
+    keydb.deletekey(*keys_here);
+    ++keys_here;
+  }
+  
+  // close the key database
+  keydb.closedatabase();
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/userdb.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/userdb.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/userdb.h	(revision 10506)
@@ -0,0 +1,127 @@
+/**********************************************************************
+ *
+ * userdb.h -- functions to handle a user database
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef USERDB_H
+#define USERDB_H
+
+#include "infodbclass.h"
+
+
+// the password line in the userinfo_t must be encrypted using
+// this function
+text_t crypt_text (const text_t &text);
+
+// username_ok tests to make sure a username is ok. a username
+// must be at least 2 characters long, but no longer than 30
+// characters long. it can contain the characters a-z A-Z 0-9
+// . and _
+bool username_ok (const text_t &username);
+
+// password_ok tests to make sure a password is ok. a password
+// must be at least 3 characters long but no longer than 8 characters
+// long. it can contain any character in the range 0x20-0x7e
+bool password_ok (const text_t &password);
+
+
+// information about a single user
+struct userinfo_t {
+  void clear ();
+  userinfo_t () {clear();}
+  userinfo_t &operator=(const userinfo_t &x);
+  
+  text_t username;
+  text_t password;
+  bool enabled;
+  text_t groups; // comma separated list
+  text_t comment;
+};
+
+
+// these functions deal with user and key databases that are already open
+// they should have been opened with gdbmclass::opendatabase
+// as soon as the databases are finished with they should be closed with
+// gdbmclass::closedatabase so that another process can access the database
+//
+// some of the functions need the databases opened with write access, an
+// appropriate call would be something like:
+//
+//   success = keydb.opendatabase (keyfile, GDBM_WRCREAT, 1000);
+//
+// note: passwords and keys are encrypted, so you can't just compare passwords
+// in a userinfo_t with a password given by the user. use check_passwd
+
+
+// functions dealing with user databases
+
+// returns true on success (in which case userinfo will contain
+// the information for this user)
+bool get_user_info (gdbmclass &userdb, const text_t &username,
+		    userinfo_t &userinfo);
+bool get_user_info (const text_t &userdbfile, const text_t &username,
+		    userinfo_t &userinfo);
+
+// returns true on success
+bool set_user_info (gdbmclass &userdb, const text_t &username,
+		    const userinfo_t &userinfo);
+bool set_user_info (const text_t &userdbfile, const text_t &username,
+		    const userinfo_t &userinfo);
+
+// removes a user from the user database -- forever
+void delete_user (gdbmclass &userdb, const text_t &username);
+void delete_user (const text_t &userdbfile, const text_t &username);
+
+// gets a list of all the users in the database. returns true
+// on success
+void get_user_list (gdbmclass &userdb, text_tarray &userlist);
+
+// returns true if the user's password is correct.
+bool check_passwd (const userinfo_t &thisuser, const text_t &password);
+
+// removes spaces from user groups
+text_t format_user_groups(const text_t user_groups);
+
+// functions dealing with databases of temporary keys
+
+// generates a random key for the user, stores it in the database and
+// returns it so that it can be used in page generation
+// returns "" on failure
+text_t generate_key (gdbmclass &keydb, const text_t &username);
+text_t generate_key (const text_t &keydbfile, const text_t &username);
+
+// checks to see if there is a key for this particular user in the
+// database that hasn't decayed. a short decay is used when group
+// is set to administrator
+bool check_key (gdbmclass &keydb, const userinfo_t &thisuser,
+		const text_t &key, const text_t &group, int keydecay);
+bool check_key (const text_t &keydbfile, const userinfo_t &thisuser,
+		const text_t &key, const text_t &group, int keydecay);
+
+// remove_old_keys will remove all keys created more than keydecay ago.
+// use sparingly, it can be quite an expensive function
+void remove_old_keys (const text_t &keydbfile, int keydecay);
+
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/usersaction.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/usersaction.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/usersaction.cpp	(revision 10506)
@@ -0,0 +1,426 @@
+/**********************************************************************
+ *
+ * usersaction.cpp -- managing users
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_USERS_ACTION
+
+#include "usersaction.h"
+#include "fileutil.h"
+#include "userdb.h"
+
+
+///////////////
+// usersaction
+///////////////
+
+usersaction::usersaction () {
+  // this action uses cgi variable "a"
+  cgiarginfo arg_ainfo;
+  arg_ainfo.shortname = "a";
+  arg_ainfo.longname = "action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "um"; // user management
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "uma"
+  arg_ainfo.shortname = "uma";
+  arg_ainfo.longname = "user management action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "listusers";
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umun"
+  arg_ainfo.shortname = "umun";
+  arg_ainfo.longname = "user management user name";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umpw"
+  arg_ainfo.shortname = "umpw";
+  arg_ainfo.longname = "user management password";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umnpw1"
+  arg_ainfo.shortname = "umnpw1";
+  arg_ainfo.longname = "user management new password 1";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umnpw2"
+  arg_ainfo.shortname = "umnpw2";
+  arg_ainfo.longname = "user management new password 2";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umus"
+  arg_ainfo.shortname = "umus";
+  arg_ainfo.longname = "user management account status";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umug"
+  arg_ainfo.shortname = "umug";
+  arg_ainfo.longname = "user management groups"; // comma seperated list
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "umc"
+  arg_ainfo.shortname = "umc";
+  arg_ainfo.longname = "user management comment";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "bcp"
+  arg_ainfo.shortname = "bcp";
+  arg_ainfo.longname = "change password submit button";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "beu"
+  arg_ainfo.shortname = "beu";
+  arg_ainfo.longname = "edit user submit button";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+
+  // "cm"
+  arg_ainfo.shortname = "cm";
+  arg_ainfo.longname = "confirm an action";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = g_EmptyText;
+  arg_ainfo.savedarginfo = cgiarginfo::mustnot;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+void usersaction::configure (const text_t &key, const text_tarray &cfgline) {
+  // get the password filename
+  if (cfgline.size() == 1) {
+    if (key == "usersfile") usersfile = cfgline[0];
+  }
+
+  action::configure (key, cfgline);
+}
+
+bool usersaction::init (ostream &logout) {
+
+  if (gdbmhome.empty()) {
+    logout << "ERROR (usersaction::init) gdbmhome is not set\n";
+    return false;
+  }
+
+  if (usersfile.empty()) usersfile = filename_cat (gdbmhome, "etc", "users.db");
+
+  return action::init (logout);
+}
+
+bool usersaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &args, 
+				 recptprotolistclass * /*protos*/, ostream &/*logout*/) {
+  args["uan"] = "1"; // user authentication is needed
+
+  if (args["uma"] == "changepasswd") {
+    // no particular group is needed to change a password
+    args["ug"].clear(); 
+  } else {
+    // administrator is needed for all other management tasks
+    args["ug"] = "administrator";
+  }
+  
+  return true;
+}
+
+void usersaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				    response_t &response, text_t &response_data, 
+				    ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+bool usersaction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/, 
+			     browsermapclass * /*browsers*/, displayclass &disp, 
+			     outconvertclass &outconvert, ostream &textout, 
+			     ostream &logout) {
+
+  if (args["uma"] == "adduser" || args["uma"] == "edituser") {
+    // adduser is handled by edituser
+    return do_edituser (args, disp, outconvert, textout, logout);
+    
+  } else if (args["uma"] == "deleteuser") {
+    return do_deleteuser (args, disp, outconvert, textout, logout);
+    
+  } else if (args["uma"] == "changepasswd") {
+    return do_changepasswd (args, disp, outconvert, textout, logout);  
+  }
+
+  // default
+  return do_listusers (args, disp, outconvert, textout, logout);
+}
+
+bool usersaction::do_listusers (cgiargsclass &/*args*/, displayclass &disp, 
+				outconvertclass &outconvert, ostream &textout, 
+				ostream &/*logout*/) {
+
+  textout << outconvert << disp
+	  << "_userslistusers:header_\n_userslistusers:contentstart_\n";
+
+
+  // open the user database (it will be used a lot)
+  gdbmclass userdb;
+  text_tarray userlist;
+  if (userdb.opendatabase(usersfile, GDBM_READER, 1000, true)) {
+    // get user list
+    get_user_list (userdb, userlist);
+  }
+
+  // sort the list
+  sort(userlist.begin(), userlist.end());
+  
+  // output the information for each user
+  userinfo_t userinfo;
+  text_tarray::iterator users_here = userlist.begin();
+  text_tarray::iterator users_end = userlist.end();
+  while (users_here != users_end) {
+    if (get_user_info (userdb, *users_here, userinfo)) {
+      textout << outconvert << disp
+	      << "<tr><td bgcolor=\"\\#eeeeee\">" << userinfo.username << "</td>\n"
+       	      << "<td bgcolor=\"\\#eeeeee\">" << (char *) (userinfo.enabled ? "enabled" : "disabled") << "</td>\n"
+	      << "<td bgcolor=\"\\#eeeeee\">" << userinfo.groups << "&nbsp;</td>\n"
+	      << "<td bgcolor=\"\\#eeeeee\">" << userinfo.comment << "&nbsp;</td>\n"
+	      << "<td><a href=\"_httpcurrentdocument_&a=um&uma=edituser&umun="
+	      << userinfo.username << "\">_userslistusers:textedituser_</a> "
+	      << "<a href=\"_httpcurrentdocument_&a=um&uma=deleteuser&umun="
+	      << userinfo.username << "\">_userslistusers:textdeleteuser_</a>"
+	      << "</td></tr>\n\n";
+
+    } else {
+      textout << outconvert << disp
+	      << "<tr><td bgcolor=\"\\#eeeeee\">" << *users_here << "</td>\n"
+	      << "<td bgcolor=\"\\#eeeeee\">&nbsp;</td>\n"
+	      << "<td bgcolor=\"\\#eeeeee\">&nbsp;</td>\n"
+	      << "<td bgcolor=\"\\#eeeeee\">&nbsp;</td>\n"
+	      << "<td>&nbsp;</td></tr>\n\n";
+    }
+    
+    ++users_here;
+  }
+
+  userdb.closedatabase();
+  
+  textout << outconvert << disp
+	  << "_userslistusers:contentend_\n_userslistusers:footer_\n";
+  return true;
+}
+
+void usersaction::define_user_macros (cgiargsclass &args, displayclass &disp) {
+  disp.setmacro ("usersargun", "users", args["umun"]);
+  disp.setmacro ("usersargpw", "users", args["umpw"]);
+  disp.setmacro ("usersargus", "users", args["umus"]);
+  disp.setmacro ("usersargug", "users", args["umug"]);
+  disp.setmacro ("usersargc", "users", args["umc"]);
+}
+
+
+bool usersaction::do_edituser (cgiargsclass &args, displayclass &disp, 
+			       outconvertclass &outconvert, ostream &textout, 
+			       ostream &logout) {
+  userinfo_t userinfo;
+  text_t messagestatus;
+  bool noproblems = true;
+  
+  // fill in defaults from user database (if appropriate)
+  if (args["umun"].empty()) {
+    noproblems = false;
+    
+  } else if (!username_ok (args["umun"])) {
+    // problem with username
+    noproblems = false;
+    messagestatus += "_users:messageinvalidusername_";
+    
+  } else if (get_user_info (usersfile, args["umun"], userinfo)) {
+    if (args["uma"] == "adduser") {
+      // must not add a user that has the same name as another user
+      noproblems = false;
+      messagestatus += "_users:messageuserexists_";
+      
+    } else {
+      // only fill in the data if there is no user status defined
+      if (args["umus"].empty()) {
+	args["umus"] = userinfo.enabled ? "enabled" : "disabled";
+	if (args["umug"].empty()) args["umug"] = userinfo.groups;
+	if (args["umc"].empty()) args["umc"] = userinfo.comment;
+      }
+    }
+  }
+
+  // fill in the user status default
+  if (args["umus"].empty()) {
+    noproblems = false;
+    args["umus"] = "enabled";
+  }
+  
+  // make sure the password is ok
+  if (args["umpw"].empty()) {
+    // password must not be empty if none were supplied from database
+    // and we have had no other problems
+    if (userinfo.password.empty() && noproblems) {
+      noproblems = false;
+      messagestatus += "_users:messageemptypassword_";
+    }
+    
+  } else if (!password_ok(args["umpw"])) {
+    noproblems = false;
+    messagestatus += "_users:messageinvalidpassword_";
+  }
+
+  // set this info if no problems have been encounted
+  // and the submit button was pressed
+  if (noproblems && !args["beu"].empty()) {
+    userinfo.username = args["umun"];
+    if (!args["umpw"].empty()) {
+      // only set the password if it is not empty
+      userinfo.password = crypt_text(args["umpw"]);
+    }
+    userinfo.enabled = (args["umus"] == "enabled");    
+    userinfo.groups = format_user_groups(args["umug"]);
+    userinfo.comment = args["umc"];
+    
+    set_user_info (usersfile, args["umun"], userinfo);
+    
+    // show list of users
+    return do_listusers (args, disp, outconvert, textout, logout);
+  }
+  
+  // define the macros for the user
+  define_user_macros (args, disp);
+  disp.setmacro ("messagestatus", "users", messagestatus);
+  
+  textout << outconvert << disp
+	  << "_usersedituser:header_\n_usersedituser:content_\n_usersedituser:footer_\n";
+
+  return true;
+}
+
+bool usersaction::do_deleteuser (cgiargsclass &args, displayclass &disp, 
+				 outconvertclass &outconvert, ostream &textout, 
+				 ostream &logout) {
+  if (!args["cm"].empty()) {
+    if (args["cm"] == "yes" && !args["umun"].empty()) {
+      // user confirmed the deletion of the user
+      delete_user (usersfile, args["umun"]);
+    }
+    
+    // redirect the user back to the listusers page
+    return do_listusers (args, disp, outconvert, textout, logout);
+  }
+
+  define_user_macros (args, disp);
+  textout << outconvert << disp
+	  << "_usersdeleteuser:header_\n_usersdeleteuser:content_\n_usersdeleteuser:footer_\n";
+  
+  return true;
+}
+
+bool usersaction::do_changepasswd (cgiargsclass &args, displayclass &disp, 
+				   outconvertclass &outconvert, ostream &textout, 
+				   ostream &/*logout*/) {
+  text_t messagestatus;
+  
+  if (!args["bcp"].empty()) {
+    if (args["un"].empty()) {
+      messagestatus = "_users:messageusernameempty_";
+    } else if (args["umpw"].empty()) {
+      messagestatus = "_users:messagepasswordempty_";
+    } else if (args["umnpw1"].empty()) {
+      messagestatus = "_users:messagenewpass1empty_";
+    } else if (args["umnpw2"].empty()) {
+      messagestatus = "_users:messagenewpass2empty_";
+    } else if (args["umnpw1"] != args["umnpw2"]) {
+      messagestatus = "_users:messagenewpassmismatch_";
+    } else if (!password_ok(args["umnpw1"])) {
+      messagestatus = "_users:messageinvalidpassword_";
+    } else {
+      userinfo_t userinfo;
+      if (get_user_info (usersfile, args["un"], userinfo)) {
+	// check old password
+	if (userinfo.password != crypt_text(args["umpw"])) {
+	  messagestatus = "_users:messagefailed_";
+	  
+	} else {
+	  userinfo.password = crypt_text(args["umnpw1"]);
+	  if (set_user_info (usersfile, args["un"], userinfo)) {
+	    // everything is ok
+	    textout << outconvert << disp
+		    << "_userschangepasswdok:header_\n"
+	      "_userschangepasswdok:content_\n"
+	      "_userschangepasswdok:footer_\n";
+	    return true;
+	  }
+	}
+      }
+    }
+  }
+
+  disp.setmacro ("messagestatus", "users", messagestatus);
+
+  textout << outconvert << disp
+	  << "_userschangepasswd:header_\n"
+    "_userschangepasswd:content_\n"
+    "_userschangepasswd:footer_\n";
+
+  return true;
+}
+
+#endif //GSDL_USE_USERS_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/usersaction.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/usersaction.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/usersaction.h	(revision 10506)
@@ -0,0 +1,84 @@
+/**********************************************************************
+ *
+ * usersaction.h -- managing users
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdl_modules_cfg.h"
+#ifdef GSDL_USE_USERS_ACTION
+
+#ifndef USERSACTION_H
+#define USERSACTION_H
+
+#include "gsdlconf.h"
+#include "action.h"
+#include "text_t.h"
+
+
+class usersaction : public action {
+protected:
+  text_t usersfile;
+
+public:
+  usersaction ();
+  virtual ~usersaction () {}
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  bool init (ostream &logout);
+  
+  text_t get_action_name () {return "um";}
+  
+  bool check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args, 
+		      recptprotolistclass *protos, ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response, text_t &response_data, 
+			 ostream &logout);
+  
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+protected:
+  void define_user_macros (cgiargsclass &args, displayclass &disp);
+  
+  bool do_listusers (cgiargsclass &args, displayclass &disp, 
+		     outconvertclass &outconvert, ostream &textout, 
+		     ostream &logout);
+
+  bool do_edituser (cgiargsclass &args, displayclass &disp, 
+		    outconvertclass &outconvert, ostream &textout, 
+		    ostream &logout);
+
+  bool do_deleteuser (cgiargsclass &args, displayclass &disp, 
+		      outconvertclass &outconvert, ostream &textout, 
+		      ostream &logout);
+
+  bool do_changepasswd (cgiargsclass &args, displayclass &disp, 
+			outconvertclass &outconvert, ostream &textout, 
+			ostream &logout);
+};
+
+#endif //!USERSACTION_H
+#endif //GSDL_USE_USERS_ACTION
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/vlistbrowserclass.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/vlistbrowserclass.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/vlistbrowserclass.cpp	(revision 10506)
@@ -0,0 +1,302 @@
+/**********************************************************************
+ *
+ * vlistbrowserclass.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "vlistbrowserclass.h"
+#include <assert.h>
+#include "OIDtools.h"
+#include "browsetools.h"
+
+vlistbrowserclass::vlistbrowserclass () {
+}
+
+vlistbrowserclass::~vlistbrowserclass () {
+}
+
+// returns the name that specifies the browserclass type
+text_t vlistbrowserclass::get_browser_name () {
+  return "VList";
+}
+
+browserclass* vlistbrowserclass::clone()
+{
+  vlistbrowserclass* browser = new vlistbrowserclass();
+  if (browser != NULL) {
+#ifdef GSDL_USE_BY_BOOK_MACROS
+    browser->m_oByBookMacros.Copy(m_oByBookMacros);
+#endif
+  }
+  return browser;
+}
+
+void vlistbrowserclass::load_metadata_defaults (text_tset &metadata) {
+  metadata.insert ("haschildren");
+  metadata.insert ("doctype");
+}
+
+text_t vlistbrowserclass::get_default_formatstring () {
+  return "<td valign=top>[link][icon][/link]</td>"
+    "<td valign=top>[srclink][srcicon][/srclink]</td>"
+    "<td valign=top>[highlight]{Or}{[Title],Untitled}[/highlight]"
+    "{If}{[Source],<br><i>([Source])</i>}</td>";
+}
+
+int vlistbrowserclass::output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+					     const text_t &collection, int colnumber, 
+					     format_t *formatlistptr, bool use_table, 
+					     text_tset &/*metadata*/, bool &/*getParents*/, 
+					     recptproto * collectproto, displayclass &disp, 
+					     outconvertclass &outconvert, ostream &textout, 
+					     ostream& logout) {
+
+  text_t link, icon;
+
+  text_t collink = collection;
+  if (!collink.empty()) collink = "&c=" + collink;
+
+  get_link_icon (section, args, collink, link, icon);
+  bool highlight = false;
+  if (!args["d"].empty()) {
+    if (args["d"] == section.OID) highlight = true;
+  } else 
+    if (args["cl"] == section.OID) highlight = true;
+
+
+  if (use_table || colnumber > 0) {
+    textout << outconvert << "<table><tr valign=top>";
+    // get tab size
+    text_t tab; int itab;
+    disp.expandstring (displayclass::defaultpackage, "_tabwidth_", tab);
+    itab = tab.getint();
+    if (colnumber > 0) textout << outconvert << disp 
+			       << "<td><img src=\"_httpimg_/space.gif\" width=" 
+			       << (itab*colnumber) << "></td>";
+  }
+
+  text_tmap options;
+  options["link"] = link;
+  options["icon"] = icon;
+  if (highlight) options["highlight"] = "1";
+  else options["highlight"] = "0";
+  options["DocImage"] = get_cover_image();
+  textout << outconvert << disp 
+	  << get_formatted_string (collection, collectproto, 
+				   section, disp, formatlistptr, 
+				   options, logout);
+  
+  if (use_table  || colnumber > 0) textout << outconvert << "</tr></table>\n";
+
+  return 1;
+}
+
+int vlistbrowserclass::output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+					     const text_t &collection, int colnumber, 
+					     format_t *formatlistptr, bool use_table, 
+					     text_tset &/*metadata*/, bool &/*getParents*/, 
+					     recptproto * collectproto, displayclass &disp, 
+					     outconvertclass &outconvert, ostream &textout, 
+					     ostream& logout) {
+
+  text_t link, icon;
+  text_t &arg_d = args["d"];
+  text_t &arg_cl = args["cl"];
+
+  text_t collink = collection;
+  if (!collink.empty()) collink = "&c=" + collink;
+
+  if (colnumber > 0) {
+    textout << outconvert << "<table><tr valign=top>";
+    // get tab size
+    text_t tab; int itab;
+    disp.expandstring (displayclass::defaultpackage, "_tabwidth_", tab);
+    itab = tab.getint();
+    if (colnumber > 0) textout << outconvert << disp 
+			       << "<td><img src=\"_httpimg_/space.gif\" width=" 
+			       << (itab*colnumber) << "></td>";
+    textout << outconvert << "<td>";
+  }
+  if (use_table) textout << outconvert << "<table>\n";
+
+  ResultDocInfo_tarray::iterator thissection = sections.docInfo.begin();
+  ResultDocInfo_tarray::iterator endsection = sections.docInfo.end();
+
+  // ** here lies Alan's hack to get 4 results per table row
+  int item = 0, perline;; // set perline to 1 normally
+  text_t fstring;
+
+  text_tmap options;
+  options["link"] = link;
+  options["icon"] = icon;
+  options["highlight"] = "0";
+  options["DocImage"] = get_cover_image();
+  
+  if ( thissection != endsection ) { // only if there are results (else corrupts display)
+    fstring = get_formatted_string (collection, collectproto, *thissection,
+                                    disp, formatlistptr, options, logout);
+    // if format string
+    // has <td><t (e.g. <td><table>) then
+    // we assume it is an image and put it in 4 columns
+    if (fstring[5] == 't') 
+      perline = 4;
+    else
+      perline = 1;
+  }
+
+  while (thissection != endsection) {
+    ++item;
+    get_link_icon (*thissection, args, collink, link, icon);
+    bool highlight = false;
+    if (!arg_d.empty()) {
+      if (arg_d == (*thissection).OID) highlight = true;
+    } else 
+      if (arg_cl == (*thissection).OID) highlight = true;
+
+    if ((item == 1 && use_table) || colnumber > 0 )
+      textout << outconvert << "<tr valign=top>\n";
+
+    options["link"] = link;
+    options["icon"] = icon;
+    if (highlight) options["highlight"] = "1";
+    else options["highlight"] = "0";
+    options["DocImage"] = get_cover_image();
+    
+    textout << outconvert << disp 
+	    << " " << get_formatted_string (collection, collectproto, *thissection, disp,
+					    formatlistptr, options, logout);
+
+    if ((item >= perline && use_table) || colnumber > 0) {
+      textout << outconvert << "\n</tr>";
+      item = 0;
+    }
+    textout << outconvert << "\n";
+    ++thissection;
+  }
+
+  if (use_table) textout << outconvert << "</table>\n";
+  if (colnumber > 0) textout << outconvert << "</td></tr></table>\n";
+
+  return 1;
+}
+
+
+// get_link_icon attempts to work out what type of icon should be displayed for
+// the given section and what it should link to.
+// [modification to allow default document detach settings -- kjdon]
+void vlistbrowserclass::get_link_icon (ResultDocInfo_t &section, cgiargsclass &args,
+				       const text_t &collink, text_t &link, text_t &icon) {
+
+  link = "<a href=\"_httpdocument_" + collink;
+  text_t link_end = "\">";
+  text_t detach_link_end = "&x=1\" target=\\_blank>"; // to detach the link, and x=1 signifies it is a detached page
+  icon = "_document:icontext_";
+
+  text_t doctype;
+  int haschildren = 0;
+
+  if (section.metadata.count("haschildren")>0)
+    haschildren = section.metadata["haschildren"].values[0].getint();
+  if (section.metadata.count("doctype")>0)
+    doctype = section.metadata["doctype"].values[0];
+
+  text_t &arg_d = args["d"];
+  text_t &arg_cl = args["cl"];
+
+  if (args["a"] == "q") {
+    // query results list
+    link += "&cl=search&d=" + section.OID;
+    
+    if (args["xx"] == "1") {
+      link += detach_link_end;
+    } else {
+      link += link_end;
+    }
+    if ((is_top (section.OID)) && (haschildren == 1)) icon = "_document:iconclosedbook_";
+    else if (haschildren == 1) icon = "_document:iconclosedfolder_";
+    
+  } else if (!arg_d.empty()) {
+    // we are in a document - none of the links should be detach links
+    if (is_top(section.OID)) {
+      // we link back to the originating page eg search page or classifier page
+      icon = "_document:iconopenbook_";
+      if (arg_cl == "search") { 
+	link = "<a href=\"_httpquery_\">";
+      }
+      else link += "&cl=" + arg_cl + "\">";
+      
+    } else if (haschildren == 1) {
+      if ((args["gc"] == "1") || 
+	  (is_child_of (section.OID, arg_d)) ||
+	  (section.OID == arg_d)) {
+	icon = "_document:iconopenfolder_";
+	link += "&cl=" + arg_cl + "&d=" + section.OID + ".pr\">";
+      } else {
+	icon = "_document:iconclosedfolder_";
+	link += "&cl=" + arg_cl + "&d=" + section.OID + "\">";
+      }
+    } else {
+      if (args["gt"] == "0") {
+	link += "&cl=" + arg_cl + "&d=" + section.OID + "\">";
+      } else {
+	link += "&cl=" + arg_cl + "&d=" + section.OID + "#" + section.OID + "\">";
+      }
+    }
+    
+  } else {
+    // classification level - links to docs may be detaching
+    if (haschildren == 1) {
+      if (doctype == "classify") {
+	if ((args["gc"] == "1") || 
+	    (is_child_of (section.OID, arg_cl)) || 
+	    (section.OID == arg_cl)) {
+	  icon = "_document:iconopenbookshelf_";
+	  link += "&cl=" + section.OID + ".pr\">";
+	} else {
+	  icon = "_document:iconclosedbookshelf_";
+	  link += "&cl=" + section.OID + "\">";
+	}
+      } else {
+    
+	icon = "_document:iconclosedbook_";
+	link += "&cl=" + arg_cl + "&d=" + section.OID;
+	if (args["xx"] == "1") {
+	  link +=  detach_link_end;
+	} else {
+	  link += link_end;
+	}
+	
+      }
+    } else {
+      if (doctype == "classify") link = "";
+      else {
+	link += "&cl=" + arg_cl + "&d=" + section.OID;
+	if (args["xx"] == "1") {
+	  link +=  detach_link_end;
+	} else {
+	  link += link_end;
+	}
+      }
+    }
+  }
+  
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/vlistbrowserclass.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/vlistbrowserclass.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/vlistbrowserclass.h	(revision 10506)
@@ -0,0 +1,70 @@
+/**********************************************************************
+ *
+ * vlistbrowserclass.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef VLISTBROWSERCLASS_H
+#define VLISTBROWSERCLASS_H
+
+#include "browserclass.h"
+#include "receptionist.h"
+
+class vlistbrowserclass : public browserclass {
+protected:
+
+public:
+  vlistbrowserclass ();
+  virtual ~vlistbrowserclass ();
+
+  void set_receptionist(receptionist *therecpt) {recpt=therecpt;}
+
+  text_t get_browser_name ();
+
+  virtual browserclass* clone();
+
+  virtual void load_metadata_defaults (text_tset &metadata);
+
+  virtual text_t get_default_formatstring ();
+
+  virtual int output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+  virtual int output_section_group (FilterResponse_t &sections, cgiargsclass &args,
+				    const text_t &collection, int colnumber, format_t *formatlistptr, 
+				    bool use_table, text_tset &metadata, bool &getParents,
+				    recptproto *collectproto, displayclass &disp, 
+				    outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+protected:
+
+  virtual void get_link_icon (ResultDocInfo_t &section, cgiargsclass &args,
+			      const text_t &collink, text_t &link, text_t &icon);
+
+  receptionist *recpt;
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/win32.mak	(revision 10506)
@@ -0,0 +1,214 @@
+###########################################################################
+#
+# win32 makefile -- src/recpt
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..\..
+USE_STLPORT = 0
+LOCAL_LIBRARY = 0
+USE_Z3950 = 0
+DLL = 0
+DLLDEBUG = 0
+STLPATH = "$(GSDLHOME)\packages\windows\stlport\stlport"
+
+# YAZ kit for z39.50
+YAZDIR=$(GSDLHOME)\packages\yaz\yaz-2.1.4
+
+AR = lib
+CC = cl
+
+CPPFLAGS = -GX
+!IF $(DLL)
+CPPFLAGS = $(CPPFLAGS) -MD
+!ELSE
+!IF ($(DLLDEBUG))
+CPPFLAGS = $(CPPFLAGS) -MDd
+!ENDIF
+!ENDIF
+
+LDFLAGS = 
+
+DEFS = -D__WIN32__ -DHAVE_CONFIG_H -DPARADOCNUM -D_LITTLE_ENDIAN -DSHORT_SUFFIX
+INCLUDES = -I"$(GSDLHOME)\src\recpt" -I"$(GSDLHOME)\lib" -I"$(GSDLHOME)\src\colservr" \
+	   -I"$(GSDLHOME)\packages\mg" -I"$(GSDLHOME)\packages\mg\lib" \
+	   -I"$(GSDLHOME)\packages\mg\src\text" -I"$(GSDLHOME)\packages\windows\gdbm\gdbm" \
+	   -I"$(GSDLHOME)\packages\windows\crypt\crypt" -I"$(GSDLHOME)\src\mgpp\lib" \
+	   -I"$(GSDLHOME)\src\mgpp\text" -I"$(GSDLHOME)"
+!IF $(USE_STLPORT)
+DEFS = $(DEFS) -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = $(INCLUDES) -I$(STLPATH)
+!ENDIF
+!IF $(LOCAL_LIBRARY)
+DEFS = $(DEFS) -DGSDL_LOCAL_LIBRARY
+!ENDIF
+
+LIBS = "$(GSDLHOME)\packages\windows\gdbm\gdbm\gdbm.lib" \
+       "$(GSDLHOME)\packages\windows\crypt\crypt\crypt.lib" \
+       "$(GSDLHOME)\src\colservr\gsdlcolservr.lib" \
+       "$(GSDLHOME)\lib\gsdllib.lib" \
+       "$(GSDLHOME)\packages\mg\src\text\libtextin.lib" \
+       "$(GSDLHOME)\packages\mg\lib\libmg.lib" \
+       "$(GSDLHOME)\src\mgpp\text\libtextin.lib" \
+       "$(GSDLHOME)\src\mgpp\lib\libmg.lib" \
+       "$(GSDLHOME)\packages\windows\expat\libexpat.lib"
+
+!IF $(USE_Z3950)
+DEFS = $(DEFS) -DUSE_Z3950
+Z3950EXEC = z3950server.exe
+Z3950OBJS = z3950proto.obj z3950proxy.obj  yaz_zclient.obj zparse.tab.obj parse.yy.obj 
+Z_CLIENTOBJS = "$(YAZDIR)\win\obj\tabcomplete.obj"
+Z_LIBYAZ = "$(YAZDIR)\lib\yaz.lib"
+LDFLAGS = $(LDFLAGS) /link /NOD:msvcrt.lib
+!ELSE
+Z3950EXEC = 
+Z3950OBJS =
+Z_CLIENTOBJS =
+Z_LIBYAZ =
+!ENDIF
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) -o $@ 
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $< 
+
+
+COMMONHEADERS = receptionist.h cgiargs.h action.h browserclass.h \
+                converter.h recptconfig.h cgiutils.h OIDtools.h browsetools.h \
+		statusaction.h pageaction.h comtypes.h recptproto.h pingaction.h \
+		queryaction.h documentaction.h extlinkaction.h htmlutils.h \
+		querytools.h formattools.h tipaction.h authenaction.h infodbclass.h \
+                userdb.h usersaction.h vlistbrowserclass.h hlistbrowserclass.h \
+		datelistbrowserclass.h invbrowserclass.h pagedbrowserclass.h \
+		htmlbrowserclass.h historydb.h phindbrowserclass.h collectoraction.h \
+		nullproto.h argdb.h browseaction.h browseactiontools.h phindaction.h \
+		summarise.h highlighttext.h configaction.h
+
+CGIHEADERS = cgiwrapper.h
+
+HEADERS = $(COMMONHEADERS) $(CGIHEADERS)
+
+
+COMMONSOURCES = receptionist.cpp cgiargs.cpp action.cpp browserclass.cpp \
+                converter.cpp recptconfig.cpp cgiutils.cpp OIDtools.cpp browsetools.cpp \
+		statusaction.cpp pageaction.cpp comtypes.cpp \
+		recptproto.cpp pingaction.cpp queryaction.cpp documentaction.cpp \
+		extlinkaction.cpp htmlutils.cpp querytools.cpp formattools.cpp \
+		tipaction.cpp authenaction.cpp infodbclass.cpp userdb.cpp usersaction.cpp \
+		vlistbrowserclass.cpp hlistbrowserclass.cpp datelistbrowserclass.cpp \
+		invbrowserclass.cpp pagedbrowserclass.cpp htmlbrowserclass.cpp \
+		historydb.cpp phindbrowserclass.cpp collectoraction.cpp nullproto.cpp \
+		argdb.cpp browseaction.cpp browseactiontools.cpp phindaction.cpp \
+		summarise.cpp highlighttext.cpp configaction.cpp
+
+CGISOURCES = librarymain.cpp cgiwrapper.cpp
+
+SOURCES = $(COMMONSOURCES) $(CGISOURCES)
+
+
+COMMONOBJECTS = receptionist.obj cgiargs.obj action.obj browserclass.obj \
+                converter.obj recptconfig.obj cgiutils.obj OIDtools.obj browsetools.obj \
+		statusaction.obj pageaction.obj comtypes.obj recptproto.obj \
+		pingaction.obj queryaction.obj documentaction.obj extlinkaction.obj \
+		htmlutils.obj querytools.obj formattools.obj tipaction.obj \
+		authenaction.obj infodbclass.obj userdb.obj usersaction.obj \
+		vlistbrowserclass.obj hlistbrowserclass.obj datelistbrowserclass.obj \
+		invbrowserclass.obj pagedbrowserclass.obj htmlbrowserclass.obj \
+		historydb.obj phindbrowserclass.obj collectoraction.obj nullproto.obj \
+		argdb.obj browseaction.obj browseactiontools.obj phindaction.obj \
+		summarise.obj highlighttext.obj configaction.obj $(Z3950OBJS) 
+
+CGIOBJECTS = librarymain.obj cgiwrapper.obj
+
+
+OBJECTS = $(COMMONOBJECTS) $(CGIOBJECTS)
+
+EXEC = library.exe $(Z3950EXEC)
+
+!IF $(LOCAL_LIBRARY)
+all: gsdlrecpt.lib $(Z3950EXEC)
+!ELSE
+all: $(EXEC)
+!ENDIF
+
+gsdlrecpt.lib : $(COMMONOBJECTS) $(Z_CLIENTOBJS)
+	if EXIST gsdlrecpt.lib del gsdlrecpt.lib
+	$(AR) /out:gsdlrecpt.lib $(COMMONOBJECTS) $(Z_CLIENTOBJS)
+
+clean:
+	del *.obj
+	del library.exe
+	del z3950server.exe
+!IF $(LOCAL_LIBRARY)
+install:
+!ELSE
+install:
+	copy library.exe "$(GSDLHOME)\cgi-bin"
+!ENDIF
+!IF $(USE_Z3950)
+	copy z3950server.exe "$(GSDLHOME)\cgi-bin"
+!ENDIF
+
+
+yaz_zclient.obj: yaz_zclient.c
+	$(COMPILE) -I"$(YAZDIR)\include" -I"$(YAZDIR)\client" yaz_zclient.c
+
+library.exe: $(OBJECTS) $(Z_CLIENTOBJS)
+	     $(LINK) $(OBJECTS) $(LIBS) $(Z_LIBYAZ) $(Z_CLIENTOBJS) $(LDFLAGS)
+
+Z3950_OBJS_OLD = $(COMMONOBJECTS) $(COLSERVROBJECTS)\
+    ../colservr/z3950parser.o ../colservr/z3950explain.o \
+    ../colservr/z3950_to_gsdl.o \
+    ../colservr/z3950server.o ../colservr/read-grs.o nullproto.o \
+    ../../lib/gsdllib.a  \
+    ../../packages/mg/src/text/libtextin.a \
+    ../../packages/mg/lib/libmg.a \
+    $(FASTCGI_OBJS) \
+    ../mgpp/text/libtextin.a \
+    ../mgpp/lib/libmg.a ../../packages/yaz/lib/libyaz.a ../../packages/d2m/libd2m.a
+
+Z3950_OBJS =  "$(GSDLHOME)\src\colservr\gsdlz3950.lib" \
+	"$(YAZDIR)\lib\yaz.lib" \
+	"$(GSDLHOME)\packages\d2m\libd2m.lib" \
+	parse.yy.obj comtypes.obj infodbclass.obj \
+	OIDtools.obj recptconfig.obj recptproto.obj \
+	nullproto.obj
+ 
+z3950server.exe: $(Z3950_OBJS)
+	@echo building z3950server
+	$(LINK) $(Z3950_OBJS) $(LIBS) $(LDFLAGS)
+
+# we want the following to always be compiled in case the status of
+# GSDL_LOCAL_LIBRARY has changed
+statusaction.obj: FORCE
+configaction.obj: FORCE
+
+FORCE:
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/yaz_zclient.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/yaz_zclient.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/yaz_zclient.c	(revision 10506)
@@ -0,0 +1,5409 @@
+/* 
+ * Copyright (C) 1995-2005, Index Data 
+ * See the file LICENSE for details.
+ *
+ */
+
+/* Modified for the Greenstone Digital Library project, based on yaz 2's client.c
+ kjdon, copying version 1.6 mods done by johnmcp */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <time.h>
+#include <ctype.h>
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#if HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/* this one needs to be there
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+*/
+#include <sys/stat.h>
+
+#if HAVE_OPENSSL_SSL_H
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#endif
+
+#ifdef __WIN32__
+#include <sys/stat.h>
+#include <io.h>
+#include <windows.h>
+#define S_ISREG(x) (x & _S_IFREG)
+#define S_ISDIR(x) (x & _S_IFDIR)
+#endif
+
+#include <yaz/yaz-util.h>
+
+#include <yaz/comstack.h>
+
+#include <yaz/proto.h>
+#include <yaz/marcdisp.h>
+#include <yaz/diagbib1.h>
+#include <yaz/otherinfo.h>
+#include <yaz/charneg.h>
+
+#include <yaz/pquery.h>
+#include <yaz/sortspec.h>
+
+#include <yaz/ill.h>
+#include <yaz/srw.h>
+#include <yaz/yaz-ccl.h>
+#include <yaz/cql.h>
+#include <yaz/log.h>
+
+#if HAVE_READLINE_READLINE_H
+#include <readline/readline.h>
+#endif
+#if HAVE_READLINE_HISTORY_H
+#include <readline/history.h>
+#endif
+
+/* these files are from the yaz client */
+#include "tabcomplete.h"
+
+#include "yaz_zclient.h"
+
+#define C_PROMPT "Z> "
+
+static char *codeset = 0;               /* character set for output */
+static int hex_dump = 0;
+static char *dump_file_prefix = 0;
+static ODR out, in, print;              /* encoding and decoding streams */
+#if HAVE_XML2
+static ODR srw_sr_odr_out = 0;
+static Z_SRW_PDU *srw_sr = 0;
+#endif
+static FILE *apdu_file = 0;
+static FILE *ber_file = 0;
+static COMSTACK conn = 0;               /* our z-association */
+static Z_IdAuthentication *auth = 0;    /* our current auth definition */
+char *databaseNames[128];
+int num_databaseNames = 0;
+static Z_External *record_last = 0;
+static int setnumber = -1;              /* current result set number */
+static int smallSetUpperBound = 0;
+static int largeSetLowerBound = 1;
+static int mediumSetPresentNumber = 0;
+static Z_ElementSetNames *elementSetNames = 0; 
+static int setno = 1;                   /* current set offset */
+static enum oid_proto protocol = PROTO_Z3950;      /* current app protocol */
+static enum oid_value recordsyntax = VAL_USMARC;
+static char *record_schema = 0;
+static int sent_close = 0;
+static NMEM session_mem = NULL;         /* memory handle for init-response */
+static Z_InitResponse *session = 0;     /* session parameters */
+static char last_scan_line[512] = "0";
+static char last_scan_query[512] = "0";
+static char ccl_fields[512] = "default.bib";
+/* ### How can I set this path to use wherever YAZ is installed? */
+/* ############## change */
+static char cql_fields[512] = "/research/kjdon/home/z3950/gsdl/packages/yaz2/etc/pqf.properties";
+static char *esPackageName = 0;
+static char *yazProxy = 0;
+static int kilobytes = 1024;
+static char *negotiationCharset = 0;
+static int  negotiationCharsetRecords = 1;
+static int  negotiationCharsetVersion = 3;
+static char *outputCharset = 0;
+static char *marcCharset = 0;
+static char* yazLang = 0;
+static char* http_version = "1.1";
+
+static char last_cmd[32] = "?";
+static FILE *marc_file = 0;
+static char *refid = NULL;
+static char *last_open_command = NULL;
+static int auto_reconnect = 0;
+static Odr_bitmask z3950_options;
+static int z3950_version = 3;
+static int scan_stepSize = 0;
+static int scan_position = 1;
+static int scan_size = 20;
+static char cur_host[200];
+
+typedef enum {
+    QueryType_Prefix,
+    QueryType_CCL,
+    QueryType_CCL2RPN,
+    QueryType_CQL,
+    QueryType_CQL2RPN
+} QueryType;
+
+static QueryType queryType = QueryType_Prefix;
+
+static CCL_bibset bibset;               /* CCL bibset handle */
+static cql_transform_t cqltrans;	/* CQL context-set handle */
+
+#if HAVE_READLINE_COMPLETION_OVER
+
+#else
+/* readline doesn't have this var. Define it ourselves. */
+int rl_attempted_completion_over = 0;
+#endif
+
+/* set this one to 1, to avoid decode of unknown MARCs  */
+#define AVOID_MARC_DECODE 1
+
+#define maxOtherInfosSupported 10
+struct {
+    int oidval;
+    char* value;
+} extraOtherInfos[maxOtherInfosSupported];
+	
+
+void process_cmd_line(char* line);
+char ** readline_completer(char *text, int start, int end);
+char *command_generator(const char *text, int state);
+char** curret_global_list=NULL;
+int cmd_register_tab(const char* arg);
+
+static void close_session (void);
+
+ODR getODROutputStream()
+{
+    return out;
+}
+
+const char* query_type_as_string(QueryType q) 
+{
+    switch (q) { 
+    case QueryType_Prefix: return "prefix (RPN sent to server)";
+    case QueryType_CCL: return "CCL (CCL sent to server) ";
+    case QueryType_CCL2RPN: return "CCL -> RPN (RPN sent to server)";
+    case QueryType_CQL: return "CQL (CQL sent to server)";
+    case QueryType_CQL2RPN: return "CQL -> RPN (RPN sent to server)";
+    default: 
+        return "unknown Query type internal yaz-client error";
+    }
+}
+
+static void do_hex_dump(const char* buf, int len) 
+{
+    if (hex_dump)
+    {
+	int i,x;
+	for( i=0; i<len ; i=i+16 ) 
+	{			
+	    printf(" %4.4d ",i);
+	    for(x=0 ; i+x<len && x<16; ++x) 
+	    {
+		printf("%2.2X ",(unsigned int)((unsigned char)buf[i+x]));
+	    }
+	    printf("\n");
+	}
+    }
+    if (dump_file_prefix)
+    {
+	static int no = 0;
+	if (++no < 1000 && strlen(dump_file_prefix) < 500)
+	{
+	    char fname[1024];
+	    FILE *of;
+	    sprintf (fname, "%s.%03d.raw", dump_file_prefix, no);
+	    of = fopen(fname, "wb");
+	    
+	    fwrite (buf, 1, len, of);
+	    
+	    fclose(of);
+	}
+    }
+}
+
+void add_otherInfos(Z_APDU *a) 
+{
+    Z_OtherInformation **oi;
+    int i;
+		
+    yaz_oi_APDU(a, &oi);
+    for(i=0; i<maxOtherInfosSupported; ++i) 
+    {
+        if(extraOtherInfos[i].oidval != -1) 
+            yaz_oi_set_string_oidval(oi, out, extraOtherInfos[i].oidval,
+                                     1, extraOtherInfos[i].value);
+    }   
+}
+
+int send_apdu(Z_APDU *a)
+{
+    char *buf;
+    int len;
+    
+    add_otherInfos(a);
+    
+    if (apdu_file)
+    {
+        z_APDU(print, &a, 0, 0);
+        odr_reset(print);
+    }
+    if (!z_APDU(out, &a, 0, 0))
+    {
+        odr_perror(out, "Encoding APDU");
+        close_session();
+        return 0;
+    }
+    buf = odr_getbuf(out, &len, 0);
+    if (ber_file)
+        odr_dumpBER(ber_file, buf, len);
+    /* printf ("sending APDU of size %d\n", len); */
+    do_hex_dump(buf, len);
+    if (cs_put(conn, buf, len) < 0)
+    {
+        fprintf(stderr, "cs_put: %s", cs_errmsg(cs_errno(conn)));
+        close_session();
+        return 0;
+    }
+    odr_reset(out); /* release the APDU structure  */
+    return 1;
+}
+
+static void print_stringn(const unsigned char *buf, size_t len)
+{
+    size_t i;
+    for (i = 0; i<len; i++)
+        if ((buf[i] <= 126 && buf[i] >= 32) || strchr ("\n\r\t\f", buf[i]))
+            printf ("%c", buf[i]);
+        else
+            printf ("\\X%02X", buf[i]);
+}
+
+static void print_refid (Z_ReferenceId *id)
+{
+    if (id)
+    {
+        printf ("Reference Id: ");
+        print_stringn (id->buf, id->len);
+        printf ("\n");
+    }
+}
+
+static Z_ReferenceId *set_refid (ODR out)
+{
+    Z_ReferenceId *id;
+    if (!refid)
+        return 0;
+    id = (Z_ReferenceId *) odr_malloc (out, sizeof(*id));
+    id->size = id->len = strlen(refid);
+    id->buf = (unsigned char *) odr_malloc (out, id->len);
+    memcpy (id->buf, refid, id->len);
+    return id;
+}   
+
+/* INIT SERVICE ------------------------------- */
+
+static void send_initRequest(const char* type_and_host)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_initRequest);
+    Z_InitRequest *req = apdu->u.initRequest;
+    int i;
+
+    req->options = &z3950_options;
+
+    ODR_MASK_ZERO(req->protocolVersion);
+    for (i = 0; i<z3950_version; i++)
+	ODR_MASK_SET(req->protocolVersion, i);
+
+    *req->maximumRecordSize = 1024*kilobytes;
+    *req->preferredMessageSize = 1024*kilobytes;
+
+    req->idAuthentication = auth;
+
+    req->referenceId = set_refid (out);
+
+    if (yazProxy && type_and_host) 
+        yaz_oi_set_string_oidval(&req->otherInfo, out, VAL_PROXY,
+        1, type_and_host);
+    
+    if (negotiationCharset || yazLang) {
+    	Z_OtherInformation **p;
+    	Z_OtherInformationUnit *p0;
+    	
+    	yaz_oi_APDU(apdu, &p);
+    	
+    	if ((p0=yaz_oi_update(p, out, NULL, 0, 0))) {
+	    ODR_MASK_SET(req->options, Z_Options_negotiationModel);
+	    
+	    p0->which = Z_OtherInfo_externallyDefinedInfo;
+	    p0->information.externallyDefinedInfo =
+		yaz_set_proposal_charneg(
+		    out,
+		    (const char**)&negotiationCharset, 
+		    negotiationCharset ? 1 : 0,
+		    (const char**)&yazLang, yazLang ? 1 : 0, 
+		    negotiationCharsetRecords);
+    	}
+    }
+    
+    send_apdu(apdu);
+    /* (send_apdu(apdu))
+	intf("Sent initrequest.\n");*/
+}
+
+/* in old version, John had got rid of process_initResponse, and added
+   z_get_initResponse. I'll add this in but leave the other one alone 
+ this returns the info that is used in the description for the 'collection'*/
+char *z_get_initResponse()
+{
+    
+    char* buffer; /* we are returning some info in this buffer */
+    char *text_id="ID: ";
+    char *text_name="<br>\nName: ";
+    char *text_ver="<br>\nVersion: ";
+    size_t initial_length;
+    
+    if (!*session->result)
+	return NULL; /* no init info to return */
+    
+   
+    initial_length = strlen(text_id)+strlen(text_name)+strlen(text_ver)+
+	(session->implementationId?strlen(session->implementationId):0) +
+	(session->implementationName?strlen(session->implementationName):0) +
+	(session->implementationVersion?strlen(session->implementationVersion)
+	 :0)  + 1; /* for null char */
+    
+    if ((buffer = malloc((sizeof(char *))*initial_length)) == NULL) {
+	fprintf(stderr,"Malloc failed while initialising z39.50 server\n");
+	return (NULL);
+    }
+    /* can't pass NULL to sprintf as a (char *) */
+    sprintf(buffer,"%s%s%s%s%s%s",
+	    session->implementationId?text_id:"",
+	    session->implementationId?session->implementationId:"",
+	    session->implementationName?text_name:"",
+	    session->implementationName?session->implementationName:"",
+	    session->implementationVersion?text_ver:"",
+	    session->implementationVersion?session->implementationVersion:""
+	    );
+    return (buffer);
+    
+}
+
+char *z_get_initResponseOld()
+{
+    char *buffer; 
+    size_t needed_length;
+    char *text_id="ID: ";
+    char *text_name="<br>\nName: ";
+    char *text_ver="<br>\nVersion: ";
+    int counter;
+    
+    buffer=NULL;
+    if (!*session->result)
+	return NULL;
+    
+    /* work out total string length needed. Note strlen(NULL) is a bad thing
+       to do. */
+    needed_length=strlen(text_id)+strlen(text_name)+strlen(text_ver)+
+	(session->implementationId?strlen(session->implementationId):0) +
+	(session->implementationName?strlen(session->implementationName):0) +
+	(session->implementationVersion?strlen(session->implementationVersion)
+	 :0) +
+	(session->userInformationField?
+	 strlen(session->userInformationField->u.octet_aligned->buf):0) +
+	1 /* for null char */ ;
+    if ((buffer=malloc((sizeof(char *)) * needed_length))==NULL) {
+	fprintf(stderr,"Malloc failed while initialising z39.50 server\n");
+	return (NULL);
+    }
+    /* can't pass NULL to sprintf as a (char *) */
+    sprintf(buffer,"%s%s%s%s%s%s",
+	    session->implementationId?text_id:"",
+	    session->implementationId?session->implementationId:"",
+	    session->implementationName?text_name:"",
+	    session->implementationName?session->implementationName:"",
+	    session->implementationVersion?text_ver:"",
+	    session->implementationVersion?session->implementationVersion:""
+	    );
+    
+    /* if version 3, also check the other-information parameter of the
+       response. (But check version is 3 first) */
+    if (session->otherInfo)
+	/**** From prt-proto.h *********** (comment added by johnmcp)
+	      typedef struct Z_OtherInformationUnit
+       .   {  Z_InfoCategory *category;        / * OPTIONAL * /
+       .      int which;
+       #define Z_OtherInfo_characterInfo 0
+       #define Z_OtherInfo_binaryInfo 1
+       #define Z_OtherInfo_externallyDefinedInfo 2
+       #define Z_OtherInfo_oid 3
+       .      union
+       .        {
+       .          char *characterInfo; 
+       .          Odr_oct *binaryInfo;
+       .          Z_External *externallyDefinedInfo;
+       .          Odr_oid *oid;
+       .        } information;
+       .   } Z_OtherInformationUnit;
+       
+       typedef struct Z_OtherInformation
+       {
+       int num_elements;
+       Z_OtherInformationUnit **list;
+       } Z_OtherInformation;
+	************/
+	for (counter=0;counter<session->otherInfo->num_elements;counter++) {
+	    if (session->otherInfo->list[counter]->which ==
+		Z_OtherInfo_characterInfo) {
+		
+		/* add this extra string to our buffer */
+		int where=strlen(buffer);
+		buffer=realloc(buffer,where+
+			       strlen(session->otherInfo->list[counter]->
+				      information.characterInfo));
+		strcpy(buffer+where,
+		       session->otherInfo->list[counter]->
+		       information.characterInfo);
+	    }
+	}
+    return (buffer);
+}
+
+
+/* These two are used only from process_initResponse() */
+static void render_initUserInfo(Z_OtherInformation *ui1);
+static void render_diag(Z_DiagnosticFormat *diag);
+
+static void pr_opt(const char *opt, void *clientData)
+{
+    printf (" %s", opt);
+}
+
+static int process_initResponse(Z_InitResponse *res)
+{
+    int ver = 0;
+    /* save session parameters for later use */
+    session_mem = odr_extract_mem(in);
+    session = res;
+
+    for (ver = 0; ver < 8; ver++)
+        if (!ODR_MASK_GET(res->protocolVersion, ver))
+            break;
+
+    if (!*res->result)
+        printf("Connection rejected by v%d target.\n", ver);
+    else
+        printf("Connection accepted by v%d target.\n", ver);
+    if (res->implementationId)
+        printf("ID     : %s\n", res->implementationId);
+    if (res->implementationName)
+        printf("Name   : %s\n", res->implementationName);
+    if (res->implementationVersion)
+        printf("Version: %s\n", res->implementationVersion);
+    if (res->userInformationField)
+    {
+	Z_External *uif = res->userInformationField;
+	if (uif->which == Z_External_userInfo1) {
+	    render_initUserInfo(uif->u.userInfo1);
+	} else {
+	    printf("UserInformationfield:\n");
+	    if (!z_External(print, (Z_External**)&uif, 0, 0))
+	    {
+		odr_perror(print, "Printing userinfo\n");
+		odr_reset(print);
+	    }
+	    if (uif->which == Z_External_octet) {
+		printf("Guessing visiblestring:\n");
+		printf("'%.*s'\n", uif->u.octet_aligned->len,
+		       uif->u.octet_aligned->buf);
+	    }
+	    else if (uif->which == Z_External_single) 
+	    {
+		Odr_any *sat = uif->u.single_ASN1_type;
+		oident *oid = oid_getentbyoid(uif->direct_reference);
+		if (oid->value == VAL_OCLCUI) {
+		    Z_OCLC_UserInformation *oclc_ui;
+		    ODR decode = odr_createmem(ODR_DECODE);
+		    odr_setbuf(decode, sat->buf, sat->len, 0);
+		    if (!z_OCLC_UserInformation(decode, &oclc_ui, 0, 0))
+			printf ("Bad OCLC UserInformation:\n");
+		    else
+			printf ("OCLC UserInformation:\n");
+		    if (!z_OCLC_UserInformation(print, &oclc_ui, 0, 0))
+			printf ("Bad OCLC UserInformation spec\n");
+		    odr_destroy(decode);
+		}
+		else
+		{
+		    /* Peek at any private Init-diagnostic APDUs */
+		    printf("### NAUGHTY: External is '%.*s'\n",
+			   sat->len, sat->buf);
+		}
+	    }
+	    odr_reset (print);
+	}
+    }
+    printf ("Options:");
+    yaz_init_opt_decode(res->options, pr_opt, 0);
+    printf ("\n");
+
+    if (ODR_MASK_GET(res->options, Z_Options_namedResultSets))
+        setnumber = 0;
+    
+    if (ODR_MASK_GET(res->options, Z_Options_negotiationModel)) {
+    
+    	Z_CharSetandLanguageNegotiation *p =
+    		yaz_get_charneg_record(res->otherInfo);
+    	
+    	if (p) {
+            
+            char *charset=NULL, *lang=NULL;
+
+            int selected;
+            
+            yaz_get_response_charneg(session_mem, p, &charset, &lang,
+                                     &selected);
+
+	    if (outputCharset && negotiationCharset) {
+		    odr_set_charset (out, charset, outputCharset);
+		    odr_set_charset (in, outputCharset, charset);
+	    }
+	    else {
+		    odr_set_charset (out, 0, 0);
+		    odr_set_charset (in, 0, 0);
+	    }
+            
+            printf("Accepted character set : %s\n", charset);
+            printf("Accepted code language : %s\n", lang ? lang : "none");
+            printf("Accepted records in ...: %d\n", selected );
+    	}
+    }
+    fflush (stdout);
+    return 0;
+}
+
+
+static void render_initUserInfo(Z_OtherInformation *ui1) {
+    int i;
+    printf("Init response contains %d otherInfo unit%s:\n",
+	   ui1->num_elements, ui1->num_elements == 1 ? "" : "s");
+
+    for (i = 0; i < ui1->num_elements; i++) {
+	Z_OtherInformationUnit *unit = ui1->list[i];
+	printf("  %d: otherInfo unit contains ", i+1);
+	if (unit->which == Z_OtherInfo_externallyDefinedInfo &&
+	    unit->information.externallyDefinedInfo &&
+	    unit->information.externallyDefinedInfo->which ==
+	    Z_External_diag1) {
+	    render_diag(unit->information.externallyDefinedInfo->u.diag1);
+	} 
+	else if (unit->which != Z_OtherInfo_externallyDefinedInfo)
+	{
+	    printf("unsupported otherInfo unit->which = %d\n", unit->which);
+	}
+	else 
+	{
+	    printf("unsupported otherInfo unit external %d\n",
+		   unit->information.externallyDefinedInfo ? 
+		   unit->information.externallyDefinedInfo->which : -2);
+	}
+    }
+}
+
+
+/* ### should this share code with display_diagrecs()? */
+static void render_diag(Z_DiagnosticFormat *diag) {
+    int i;
+
+    printf("%d diagnostic%s:\n", diag->num, diag->num == 1 ? "" : "s");
+    for (i = 0; i < diag->num; i++) {
+	Z_DiagnosticFormat_s *ds = diag->elements[i];
+	printf("    %d: ", i+1);
+	switch (ds->which) {
+	case Z_DiagnosticFormat_s_defaultDiagRec: {
+	    Z_DefaultDiagFormat *dd = ds->u.defaultDiagRec;
+	    /* ### should check `dd->diagnosticSetId' */
+	    printf("code=%d (%s)", *dd->condition,
+		   diagbib1_str(*dd->condition));
+	    /* Both types of addinfo are the same, so use type-pun */
+	    if (dd->u.v2Addinfo != 0)
+		printf(",\n\taddinfo='%s'", dd->u.v2Addinfo);
+	    break;
+	}
+	case Z_DiagnosticFormat_s_explicitDiagnostic:
+	    printf("Explicit diagnostic (not supported)");
+	    break;
+	default:
+	    printf("Unrecognised diagnostic type %d", ds->which);
+	    break;
+	}
+
+	if (ds->message != 0)
+	    printf(", message='%s'", ds->message);
+	printf("\n");
+    }
+}
+
+
+static int set_base(const char *arg)
+{
+    int i;
+    const char *cp;
+
+    for (i = 0; i<num_databaseNames; i++)
+        xfree (databaseNames[i]);
+    num_databaseNames = 0;
+    while (1)
+    {
+        char *cp1;
+        if (!(cp = strchr(arg, ' ')))
+            cp = arg + strlen(arg);
+        if (cp - arg < 1)
+            break;
+        databaseNames[num_databaseNames] = (char *)xmalloc (1 + cp - arg);
+        memcpy (databaseNames[num_databaseNames], arg, cp - arg);
+        databaseNames[num_databaseNames][cp - arg] = '\0';
+
+        for (cp1 = databaseNames[num_databaseNames]; *cp1 ; cp1++)
+            if (*cp1 == '+')
+                *cp1 = ' ';
+        num_databaseNames++;
+
+        if (!*cp)
+            break;
+        arg = cp+1;
+    }
+    if (num_databaseNames == 0)
+    {
+        num_databaseNames = 1;
+        databaseNames[0] = xstrdup("");
+    }
+    return 1;
+}
+
+static int cmd_base(const char *arg)
+{
+    if (!*arg)
+    {
+        printf("Usage: base <database> <database> ...\n");
+        return 0;
+    }
+    return set_base(arg);
+}
+
+void cmd_open_remember_last_open_command(const char* arg, char* new_open_command)
+{
+    if(last_open_command != arg) 
+    {
+        if(last_open_command) xfree(last_open_command);
+        last_open_command = xstrdup(new_open_command);
+    }
+}
+
+int session_connect(const char *arg)
+{
+    void *add;
+    char type_and_host[101];
+    const char *basep = 0;
+#if HAVE_OPENSSL_SSL_H
+    SSL *ssl;
+#endif
+    if (conn)
+    {
+        cs_close (conn);
+        conn = NULL;
+        if (session_mem)
+        {
+            nmem_destroy (session_mem);
+            session_mem = NULL;
+        }
+    }   
+    cs_get_host_args(arg, &basep);
+
+    strncpy(type_and_host, arg, sizeof(type_and_host)-1);
+    type_and_host[sizeof(type_and_host)-1] = '\0';
+
+    cmd_open_remember_last_open_command(arg, type_and_host);
+
+    if (yazProxy)
+        conn = cs_create_host(yazProxy, 1, &add);
+    else
+        conn = cs_create_host(arg, 1, &add);
+    if (!conn)
+    {
+        printf ("Couldn't create comstack\n");
+        return 0;
+    }
+#if HAVE_XML2
+    if (conn->protocol == PROTO_HTTP)
+	queryType = QueryType_CQL;
+#else
+    if (conn->protocol == PROTO_HTTP)
+    {
+        printf ("SRW/HTTP not enabled in this YAZ\n");
+        cs_close(conn);
+        conn = 0;
+        return 0;
+    }
+#endif
+    protocol = conn->protocol;
+    if (conn->protocol == PROTO_HTTP)
+        set_base("");
+    else
+        set_base("Default");
+    /*intf("Connecting...");*/
+    fflush(stdout);
+    if (cs_connect(conn, add) < 0)
+    {
+        printf ("error = %s\n", cs_strerror(conn));
+        if (conn->cerrno == CSYSERR)
+	{
+	    char msg[256];
+	    yaz_strerror(msg, sizeof(msg));
+	    printf ("%s\n", msg);
+	}
+        cs_close(conn);
+        conn = 0;
+        return 0;
+    }
+    /*intf("OK.\n");*/
+#if HAVE_OPENSSL_SSL_H
+    if ((ssl = (SSL *) cs_get_ssl(conn)))
+    {
+	X509 *server_cert = SSL_get_peer_certificate (ssl);
+
+	if (server_cert)
+	{
+	    char *pem_buf;
+	    int pem_len;
+	    BIO *bio = BIO_new(BIO_s_mem());
+
+	    /* get PEM buffer in memory */
+	    PEM_write_bio_X509(bio, server_cert);
+	    pem_len = BIO_get_mem_data(bio, &pem_buf);
+	    fwrite(pem_buf, pem_len, 1, stdout);
+	
+	    /* print all info on screen .. */
+	    X509_print_fp(stdout, server_cert);
+	    BIO_free(bio);
+
+	    X509_free (server_cert);
+	}
+    }
+#endif
+    if (basep && *basep)
+        set_base (basep);
+    if (protocol == PROTO_Z3950)
+    {
+        send_initRequest(type_and_host);
+        return 2;
+    }
+    return 0;
+}
+
+int z_cmd_open(char *host_and_port, char *base)
+{
+    char * full_command = (char *) xmalloc (strlen(host_and_port)+strlen(base)+6);
+    strcpy(full_command, "tcp:");
+    strcat(full_command, host_and_port);
+    strcat(full_command, "/");
+    strcat(full_command, base);
+    return cmd_open(full_command);
+}
+
+static int cmd_open(const char *arg)
+{
+    if (arg)
+    {
+        strncpy (cur_host, arg, sizeof(cur_host)-1);
+        cur_host[sizeof(cur_host)-1] = 0;
+    }
+    return session_connect(cur_host);
+}
+
+void try_reconnect() 
+{
+    char* open_command;
+	
+    if(!( auto_reconnect && last_open_command) ) return ;
+
+    open_command = (char *) xmalloc (strlen(last_open_command)+6);
+    strcpy (open_command, "open ");
+	
+    strcat (open_command, last_open_command);
+
+    process_cmd_line(open_command);
+	
+    xfree(open_command);				
+}
+
+int cmd_authentication(const char *arg)
+{
+    static Z_IdAuthentication au;
+    static char user[40], group[40], pass[40];
+    static Z_IdPass idPass;
+    int r;
+
+    if (!*arg)
+    {
+        printf("Auth field set to null\n");
+        auth = 0;
+        return 1;
+    }
+    r = sscanf (arg, "%39s %39s %39s", user, group, pass);
+    if (r == 0)
+    {
+        printf("Authentication set to null\n");
+        auth = 0;
+    }
+    if (r == 1)
+    {
+        auth = &au;
+	if (!strcmp(user, "-")) {
+	    au.which = Z_IdAuthentication_anonymous;
+	    printf("Authentication set to Anonymous\n");
+	} else {
+	    au.which = Z_IdAuthentication_open;
+	    au.u.open = user;
+	    printf("Authentication set to Open (%s)\n", user);
+	}
+    }
+    if (r == 2)
+    {
+        auth = &au;
+        au.which = Z_IdAuthentication_idPass;
+        au.u.idPass = &idPass;
+        idPass.groupId = NULL;
+        idPass.userId = user;
+        idPass.password = group;
+	printf("Authentication set to User (%s), Pass (%s)\n", user, group);
+    }
+    if (r == 3)
+    {
+        auth = &au;
+        au.which = Z_IdAuthentication_idPass;
+        au.u.idPass = &idPass;
+        idPass.groupId = group;
+        idPass.userId = user;
+        idPass.password = pass;
+	printf("Authentication set to User (%s), Group (%s), Pass (%s)\n",
+	       user, group, pass);
+    }
+    return 1;
+}
+
+/* SEARCH SERVICE ------------------------------ */
+static void display_record(Z_External *r);
+
+static void print_record(const unsigned char *buf, size_t len)
+{
+    size_t i = len;
+    print_stringn (buf, len);
+    /* add newline if not already added ... */
+    if (i <= 0 || buf[i-1] != '\n')
+        printf ("\n");
+}
+
+static void display_record(Z_External *r)
+{
+    oident *ent = oid_getentbyoid(r->direct_reference);
+
+    record_last = r;
+    /*
+     * Tell the user what we got.
+     */
+    if (r->direct_reference)
+    {
+        printf("Record type: ");
+        if (ent)
+            printf("%s\n", ent->desc);
+        else if (!odr_oid(print, &r->direct_reference, 0, 0))
+        {
+            odr_perror(print, "print oid");
+            odr_reset(print);
+        }
+    }
+    /* Check if this is a known, ASN.1 type tucked away in an octet string */
+    if (ent && r->which == Z_External_octet)
+    {
+        Z_ext_typeent *type = z_ext_getentbyref(ent->value);
+        char *rr;
+
+        if (type)
+        {
+            /*
+             * Call the given decoder to process the record.
+             */
+            odr_setbuf(in, (char*)r->u.octet_aligned->buf,
+                r->u.octet_aligned->len, 0);
+            if (!(*type->fun)(in, &rr, 0, 0))
+            {
+                odr_perror(in, "Decoding constructed record.");
+                fprintf(stdout, "[Near %d]\n", odr_offset(in));
+                fprintf(stdout, "Packet dump:\n---------\n");
+                odr_dumpBER(stdout, (char*)r->u.octet_aligned->buf,
+                            r->u.octet_aligned->len);
+                fprintf(stdout, "---------\n");
+                
+		/* note just ignores the error ant print the bytes form the octet_aligned later */
+            } else {
+                /*
+                 * Note: we throw away the original, BER-encoded record here.
+                 * Do something else with it if you want to keep it.
+                 */
+                r->u.sutrs = (Z_SUTRS *) rr; /* we don't actually check the type here. */
+                r->which = type->what;
+            }
+        }
+    }
+    if (ent && ent->value == VAL_SOIF)
+    {
+        print_record((const unsigned char *) r->u.octet_aligned->buf,
+                     r->u.octet_aligned->len);
+        if (marc_file)
+            fwrite (r->u.octet_aligned->buf, 1, r->u.octet_aligned->len, marc_file);
+    }
+    else if (r->which == Z_External_octet)
+    {
+        const char *octet_buf = (char*)r->u.octet_aligned->buf;
+        if (ent->oclass == CLASS_RECSYN && 
+		(ent->value == VAL_TEXT_XML || 
+		 ent->value == VAL_APPLICATION_XML ||
+		 ent->value == VAL_HTML))
+        {
+            print_record((const unsigned char *) octet_buf,
+                         r->u.octet_aligned->len);
+        }
+        else if (ent->value == VAL_POSTSCRIPT)
+        {
+            int size = r->u.octet_aligned->len;
+            if (size > 100)
+                size = 100;
+            print_record((const unsigned char *) octet_buf, size);
+        }
+        else
+        {
+            if ( 
+#if AVOID_MARC_DECODE
+                /* primitive check for a marc OID 5.1-29 except 16 */
+                ent->oidsuffix[0] == 5 && ent->oidsuffix[1] < 30 &&
+                ent->oidsuffix[1] != 16
+#else
+                1
+#endif
+                )
+            {
+                char *result;
+                int rlen;
+                yaz_iconv_t cd = 0;
+                yaz_marc_t mt = yaz_marc_create();
+                    
+                if (yaz_marc_decode_buf(mt, octet_buf,r->u.octet_aligned->len,
+                                        &result, &rlen)> 0)
+                {
+                    char *from = 0;
+                    if (marcCharset && !strcmp(marcCharset, "auto"))
+                    {
+                        if (ent->value == VAL_USMARC)
+                        {
+                            if (octet_buf[9] == 'a')
+                                from = "UTF-8";
+                            else
+                                from = "MARC-8";
+                        }
+                        else
+                            from = "ISO-8859-1";
+                    }
+		    else if (marcCharset)
+			from = marcCharset;
+                    if (outputCharset && from)
+                    {   
+                        cd = yaz_iconv_open(outputCharset, from);
+                        printf ("convert from %s to %s", from, 
+                                outputCharset);
+			if (!cd)
+			    printf (" unsupported\n");
+			else
+			    printf ("\n");
+                    }
+                    if (!cd)
+                        fwrite (result, 1, rlen, stdout);
+                    else
+                    {
+                        char outbuf[6];
+                        size_t inbytesleft = rlen;
+                        const char *inp = result;
+                        
+                        while (inbytesleft)
+                        {
+                            size_t outbytesleft = sizeof(outbuf);
+                            char *outp = outbuf;
+			    size_t r;
+
+                            r = yaz_iconv (cd, (char**) &inp,
+					   &inbytesleft, 
+					   &outp, &outbytesleft);
+                            if (r == (size_t) (-1))
+                            {
+                                int e = yaz_iconv_error(cd);
+                                if (e != YAZ_ICONV_E2BIG)
+                                    break;
+                            }
+                            fwrite (outbuf, outp - outbuf, 1, stdout);
+                        }
+                    }
+                }
+		else
+                {
+                    printf ("bad MARC. Dumping as it is:\n");
+                    print_record((const unsigned char*) octet_buf,
+                                  r->u.octet_aligned->len);
+		}	
+                yaz_marc_destroy(mt);
+                if (cd)
+                    yaz_iconv_close(cd);
+            }
+            else
+            {
+                print_record((const unsigned char*) octet_buf,
+                             r->u.octet_aligned->len);
+            }
+        }
+        if (marc_file)
+            fwrite (octet_buf, 1, r->u.octet_aligned->len, marc_file);
+    }
+    else if (ent && ent->value == VAL_SUTRS)
+    {
+        if (r->which != Z_External_sutrs)
+        {
+            printf("Expecting single SUTRS type for SUTRS.\n");
+            return;
+        }
+        print_record(r->u.sutrs->buf, r->u.sutrs->len);
+        if (marc_file)
+            fwrite (r->u.sutrs->buf, 1, r->u.sutrs->len, marc_file);
+    }
+    else if (ent && ent->value == VAL_GRS1)
+    {
+        WRBUF w;
+        if (r->which != Z_External_grs1)
+        {
+            printf("Expecting single GRS type for GRS.\n");
+            return;
+        }
+        w = wrbuf_alloc();
+        yaz_display_grs1(w, r->u.grs1, 0);
+        puts (wrbuf_buf(w));
+        wrbuf_free(w, 1);
+    }
+    else if (ent && ent->value == VAL_OPAC)
+    {
+	int i;
+	if (r->u.opac->bibliographicRecord)
+	    display_record(r->u.opac->bibliographicRecord);
+	for (i = 0; i<r->u.opac->num_holdingsData; i++)
+	{
+	    Z_HoldingsRecord *h = r->u.opac->holdingsData[i];
+	    if (h->which == Z_HoldingsRecord_marcHoldingsRecord)
+	    {
+		printf ("MARC holdings %d\n", i);
+		display_record(h->u.marcHoldingsRecord);
+	    }
+	    else if (h->which == Z_HoldingsRecord_holdingsAndCirc)
+	    {
+		int j;
+
+		Z_HoldingsAndCircData *data = h->u.holdingsAndCirc;
+
+		printf ("Data holdings %d\n", i);
+		if (data->typeOfRecord)
+		    printf ("typeOfRecord: %s\n", data->typeOfRecord);
+		if (data->encodingLevel)
+		    printf ("encodingLevel: %s\n", data->encodingLevel);
+		if (data->receiptAcqStatus)
+		    printf ("receiptAcqStatus: %s\n", data->receiptAcqStatus);
+		if (data->generalRetention)
+		    printf ("generalRetention: %s\n", data->generalRetention);
+		if (data->completeness)
+		    printf ("completeness: %s\n", data->completeness);
+		if (data->dateOfReport)
+		    printf ("dateOfReport: %s\n", data->dateOfReport);
+		if (data->nucCode)
+		    printf ("nucCode: %s\n", data->nucCode);
+		if (data->localLocation)
+		    printf ("localLocation: %s\n", data->localLocation);
+		if (data->shelvingLocation)
+		    printf ("shelvingLocation: %s\n", data->shelvingLocation);
+		if (data->callNumber)
+		    printf ("callNumber: %s\n", data->callNumber);
+		if (data->shelvingData)
+		    printf ("shelvingData: %s\n", data->shelvingData);
+		if (data->copyNumber)
+		    printf ("copyNumber: %s\n", data->copyNumber);
+		if (data->publicNote)
+		    printf ("publicNote: %s\n", data->publicNote);
+		if (data->reproductionNote)
+		    printf ("reproductionNote: %s\n", data->reproductionNote);
+		if (data->termsUseRepro)
+		    printf ("termsUseRepro: %s\n", data->termsUseRepro);
+		if (data->enumAndChron)
+		    printf ("enumAndChron: %s\n", data->enumAndChron);
+		for (j = 0; j<data->num_volumes; j++)
+		{
+		    printf ("volume %d\n", j);
+		    if (data->volumes[j]->enumeration)
+			printf (" enumeration: %s\n",
+				data->volumes[j]->enumeration);
+		    if (data->volumes[j]->chronology)
+			printf (" chronology: %s\n",
+				data->volumes[j]->chronology);
+		    if (data->volumes[j]->enumAndChron)
+			printf (" enumAndChron: %s\n",
+				data->volumes[j]->enumAndChron);
+		}
+		for (j = 0; j<data->num_circulationData; j++)
+		{
+		    printf ("circulation %d\n", j);
+		    if (data->circulationData[j]->availableNow)
+			printf (" availableNow: %d\n",
+				*data->circulationData[j]->availableNow);
+		    if (data->circulationData[j]->availablityDate)
+			printf (" availabiltyDate: %s\n",
+				data->circulationData[j]->availablityDate);
+		    if (data->circulationData[j]->availableThru)
+			printf (" availableThru: %s\n",
+				data->circulationData[j]->availableThru);
+		    if (data->circulationData[j]->restrictions)
+			printf (" restrictions: %s\n",
+				data->circulationData[j]->restrictions);
+		    if (data->circulationData[j]->itemId)
+			printf (" itemId: %s\n",
+				data->circulationData[j]->itemId);
+		    if (data->circulationData[j]->renewable)
+			printf (" renewable: %d\n",
+				*data->circulationData[j]->renewable);
+		    if (data->circulationData[j]->onHold)
+			printf (" onHold: %d\n",
+				*data->circulationData[j]->onHold);
+		    if (data->circulationData[j]->enumAndChron)
+			printf (" enumAndChron: %s\n",
+				data->circulationData[j]->enumAndChron);
+		    if (data->circulationData[j]->midspine)
+			printf (" midspine: %s\n",
+				data->circulationData[j]->midspine);
+		    if (data->circulationData[j]->temporaryLocation)
+			printf (" temporaryLocation: %s\n",
+				data->circulationData[j]->temporaryLocation);
+		}
+	    }
+	}
+    }
+    else 
+    {
+        printf("Unknown record representation.\n");
+        if (!z_External(print, &r, 0, 0))
+        {
+            odr_perror(print, "Printing external");
+            odr_reset(print);
+        }
+    }
+}
+
+static void display_diagrecs(Z_DiagRec **pp, int num)
+{
+    int i;
+    oident *ent;
+    Z_DefaultDiagFormat *r;
+
+    printf("Diagnostic message(s) from database:\n");
+    for (i = 0; i<num; i++)
+    {
+        Z_DiagRec *p = pp[i];
+        if (p->which != Z_DiagRec_defaultFormat)
+        {
+            printf("Diagnostic record not in default format.\n");
+            return;
+        }
+        else
+            r = p->u.defaultFormat;
+        if (!(ent = oid_getentbyoid(r->diagnosticSetId)) ||
+            ent->oclass != CLASS_DIAGSET || ent->value != VAL_BIB1)
+            printf("Missing or unknown diagset\n");
+        printf("    [%d] %s", *r->condition, diagbib1_str(*r->condition));
+        switch (r->which)
+        {
+        case Z_DefaultDiagFormat_v2Addinfo:
+            printf (" -- v2 addinfo '%s'\n", r->u.v2Addinfo);
+            break;
+        case Z_DefaultDiagFormat_v3Addinfo:
+            printf (" -- v3 addinfo '%s'\n", r->u.v3Addinfo);
+            break;
+        }
+    }
+}
+
+
+static void display_nameplusrecord(Z_NamePlusRecord *p)
+{
+    if (p->databaseName)
+        printf("[%s]", p->databaseName);
+    if (p->which == Z_NamePlusRecord_surrogateDiagnostic)
+        display_diagrecs(&p->u.surrogateDiagnostic, 1);
+    else if (p->which == Z_NamePlusRecord_databaseRecord)
+        display_record(p->u.databaseRecord);
+}
+
+static void display_records(Z_Records *p)
+{
+    int i;
+
+    if (p->which == Z_Records_NSD)
+    {
+        Z_DiagRec dr, *dr_p = &dr;
+        dr.which = Z_DiagRec_defaultFormat;
+        dr.u.defaultFormat = p->u.nonSurrogateDiagnostic;
+        display_diagrecs (&dr_p, 1);
+    }
+    else if (p->which == Z_Records_multipleNSD)
+        display_diagrecs (p->u.multipleNonSurDiagnostics->diagRecs,
+                          p->u.multipleNonSurDiagnostics->num_diagRecs);
+    else 
+    {
+        printf("Records: %d\n", p->u.databaseOrSurDiagnostics->num_records);
+        for (i = 0; i < p->u.databaseOrSurDiagnostics->num_records; i++)
+            display_nameplusrecord(p->u.databaseOrSurDiagnostics->records[i]);
+    }
+}
+
+static int send_deleteResultSetRequest(const char *arg)
+{
+    char names[8][32];
+    int i;
+
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_deleteResultSetRequest);
+    Z_DeleteResultSetRequest *req = apdu->u.deleteResultSetRequest;
+
+    req->referenceId = set_refid (out);
+
+    req->num_resultSetList =
+        sscanf (arg, "%30s %30s %30s %30s %30s %30s %30s %30s",
+                names[0], names[1], names[2], names[3],
+                names[4], names[5], names[6], names[7]);
+
+    req->deleteFunction = (int *)
+        odr_malloc (out, sizeof(*req->deleteFunction));
+    if (req->num_resultSetList > 0)
+    {
+        *req->deleteFunction = Z_DeleteResultSetRequest_list;
+        req->resultSetList = (char **)
+            odr_malloc (out, sizeof(*req->resultSetList)*
+                        req->num_resultSetList);
+        for (i = 0; i<req->num_resultSetList; i++)
+            req->resultSetList[i] = names[i];
+    }
+    else
+    {
+        *req->deleteFunction = Z_DeleteResultSetRequest_all;
+        req->resultSetList = 0;
+    }
+    
+    send_apdu(apdu);
+    printf("Sent deleteResultSetRequest.\n");
+    return 2;
+}
+
+#if HAVE_XML2
+static int send_srw(Z_SRW_PDU *sr)
+{
+    const char *charset = negotiationCharset;
+    const char *host_port = cur_host;
+    char *path = 0;
+    char ctype[50];
+    Z_SOAP_Handler h[2] = {
+        {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec},
+        {0, 0, 0}
+    };
+    ODR o = odr_createmem(ODR_ENCODE);
+    int ret;
+    Z_SOAP *p = odr_malloc(o, sizeof(*p));
+    Z_GDU *gdu;
+
+    path = odr_malloc(out, strlen(databaseNames[0])+2);
+    *path = '/';
+    strcpy(path+1, databaseNames[0]);
+
+    gdu = z_get_HTTP_Request(out);
+    gdu->u.HTTP_Request->version = http_version;
+    gdu->u.HTTP_Request->path = odr_strdup(out, path);
+
+    if (host_port)
+    {
+        const char *cp0 = strstr(host_port, "://");
+        const char *cp1 = 0;
+        if (cp0)
+            cp0 = cp0+3;
+        else
+            cp0 = host_port;
+
+        cp1 = strchr(cp0, '/');
+        if (!cp1)
+            cp1 = cp0+strlen(cp0);
+
+        if (cp0 && cp1)
+        {
+            char *h = odr_malloc(out, cp1 - cp0 + 1);
+            memcpy (h, cp0, cp1 - cp0);
+            h[cp1-cp0] = '\0';
+            z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers,
+                              "Host", h);
+        }
+    }
+
+    strcpy(ctype, "text/xml");
+    if (charset && strlen(charset) < 20)
+    {
+        strcat(ctype, "; charset=");
+        strcat(ctype, charset);
+    }
+    z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers,
+                      "Content-Type", ctype);
+    z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers,
+                      "SOAPAction", "\"\"");
+    p->which = Z_SOAP_generic;
+    p->u.generic = odr_malloc(o, sizeof(*p->u.generic));
+    p->u.generic->no = 0;
+    p->u.generic->ns = 0;
+    p->u.generic->p = sr;
+    p->ns = "http://schemas.xmlsoap.org/soap/envelope/";
+
+    ret = z_soap_codec_enc(o, &p,
+                           &gdu->u.HTTP_Request->content_buf,
+                           &gdu->u.HTTP_Request->content_len, h,
+                           charset);
+
+    if (z_GDU(out, &gdu, 0, 0))
+    {
+        /* encode OK */
+        char *buf_out;
+        int len_out;
+        int r;
+	if (apdu_file)
+	{
+	    if (!z_GDU(print, &gdu, 0, 0))
+		printf ("Failed to print outgoing APDU\n");
+	    odr_reset(print);
+	}
+        buf_out = odr_getbuf(out, &len_out, 0);
+        
+        /* we don't odr_reset(out), since we may need the buffer again */
+
+	do_hex_dump(buf_out, len_out);
+
+        r = cs_put(conn, buf_out, len_out);
+
+        odr_destroy(o);
+        
+        if (r >= 0)
+            return 2;
+    }
+    return 0;
+}
+#endif
+
+#if HAVE_XML2
+static int send_SRW_scanRequest(const char *arg, int pos, int num)
+{
+    Z_SRW_PDU *sr = 0;
+    
+    /* regular requestse .. */
+    sr = yaz_srw_get(out, Z_SRW_scan_request);
+
+    switch(queryType)
+    {
+    case QueryType_CQL:
+	sr->u.scan_request->query_type = Z_SRW_query_type_cql;
+	sr->u.scan_request->scanClause.cql = odr_strdup(out, arg);
+	break;
+    case QueryType_Prefix:
+	sr->u.scan_request->query_type = Z_SRW_query_type_pqf;
+	sr->u.scan_request->scanClause.pqf = odr_strdup(out, arg);
+	break;
+    default:
+	printf ("Only CQL and PQF supported in SRW\n");
+	return 0;
+    }
+    sr->u.scan_request->responsePosition = odr_intdup(out, pos);
+    sr->u.scan_request->maximumTerms = odr_intdup(out, num);
+    return send_srw(sr);
+}
+
+static int send_SRW_searchRequest(const char *arg)
+{
+    Z_SRW_PDU *sr = 0;
+    
+    if (!srw_sr)
+    {
+        assert(srw_sr_odr_out == 0);
+        srw_sr_odr_out = odr_createmem(ODR_ENCODE);
+    }
+    odr_reset(srw_sr_odr_out);
+
+    setno = 1;
+
+    /* save this for later .. when fetching individual records */
+    srw_sr =  yaz_srw_get(srw_sr_odr_out, Z_SRW_searchRetrieve_request);
+    
+    /* regular request .. */
+    sr = yaz_srw_get(out, Z_SRW_searchRetrieve_request);
+
+    switch(queryType)
+    {
+    case QueryType_CQL:
+	srw_sr->u.request->query_type = Z_SRW_query_type_cql;
+	srw_sr->u.request->query.cql = odr_strdup(srw_sr_odr_out, arg);
+
+	sr->u.request->query_type = Z_SRW_query_type_cql;
+	sr->u.request->query.cql = odr_strdup(out, arg);
+	break;
+    case QueryType_Prefix:
+	srw_sr->u.request->query_type = Z_SRW_query_type_pqf;
+	srw_sr->u.request->query.pqf = odr_strdup(srw_sr_odr_out, arg);
+
+	sr->u.request->query_type = Z_SRW_query_type_pqf;
+	sr->u.request->query.pqf = odr_strdup(out, arg);
+	break;
+    default:
+	printf ("Only CQL and PQF supported in SRW\n");
+	return 0;
+    }
+    sr->u.request->maximumRecords = odr_intdup(out, 0);
+
+    if (record_schema)
+        sr->u.request->recordSchema = record_schema;
+    if (recordsyntax == VAL_TEXT_XML)
+        sr->u.explain_request->recordPacking = "xml";
+    return send_srw(sr);
+}
+#endif
+
+static int send_searchRequest(const char *arg)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_searchRequest);
+    Z_SearchRequest *req = apdu->u.searchRequest;
+    Z_Query query;
+    struct ccl_rpn_node *rpn = NULL;
+    int error, pos;
+    char setstring[100];
+    Z_RPNQuery *RPNquery;
+    Odr_oct ccl_query;
+    YAZ_PQF_Parser pqf_parser;
+    Z_External *ext;
+    QueryType myQueryType = queryType;
+    char pqfbuf[512];
+
+    if (myQueryType == QueryType_CCL2RPN)
+    {
+        rpn = ccl_find_str(bibset, arg, &error, &pos);
+        if (error)
+        {
+            printf("CCL ERROR: %s\n", ccl_err_msg(error));
+            return 0;
+        }
+    } else if (myQueryType == QueryType_CQL2RPN) {
+	/* ### All this code should be wrapped in a utility function */
+	CQL_parser parser;
+	struct cql_node *node;
+	const char *addinfo;
+	if (cqltrans == 0) {
+            printf("Can't use CQL: no translation file.  Try set_cqlfile\n");
+	    return 0;
+	}
+	parser = cql_parser_create();
+	if ((error = cql_parser_string(parser, arg)) != 0) {
+            printf("Can't parse CQL: must be a syntax error\n");
+            return 0;
+	}
+	node = cql_parser_result(parser);
+	if ((error = cql_transform_buf(cqltrans, node, pqfbuf,
+				       sizeof pqfbuf)) != 0) {
+	    error = cql_transform_error(cqltrans, &addinfo);
+	    printf ("Can't convert CQL to PQF: %s (addinfo=%s)\n",
+		    cql_strerror(error), addinfo);
+            return 0;
+        }
+	arg = pqfbuf;
+	myQueryType = QueryType_Prefix;
+    }
+
+    req->referenceId = set_refid (out);
+    if (!strcmp(arg, "@big")) /* strictly for troublemaking */
+    {
+        static unsigned char big[2100];
+        static Odr_oct bigo;
+
+        /* send a very big referenceid to test transport stack etc. */
+        memset(big, 'A', 2100);
+        bigo.len = bigo.size = 2100;
+        bigo.buf = big;
+        req->referenceId = &bigo;
+    }
+    
+    if (setnumber >= 0)
+    {
+        sprintf(setstring, "%d", ++setnumber);
+        req->resultSetName = setstring;
+    }
+    *req->smallSetUpperBound = smallSetUpperBound;
+    *req->largeSetLowerBound = largeSetLowerBound;
+    *req->mediumSetPresentNumber = mediumSetPresentNumber;
+    if (smallSetUpperBound > 0 || (largeSetLowerBound > 1 &&
+        mediumSetPresentNumber > 0))
+    {
+        req->preferredRecordSyntax =
+            yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax);
+
+        req->smallSetElementSetNames =
+            req->mediumSetElementSetNames = elementSetNames;
+    }
+    req->num_databaseNames = num_databaseNames;
+    req->databaseNames = databaseNames;
+
+    req->query = &query;
+
+    switch (myQueryType)
+    {
+    case QueryType_Prefix:
+        query.which = Z_Query_type_1;
+        pqf_parser = yaz_pqf_create ();
+        RPNquery = yaz_pqf_parse (pqf_parser, out, arg);
+        if (!RPNquery)
+        {
+            const char *pqf_msg;
+            size_t off;
+            int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
+            printf("%*s^\n", off+4, "");
+            printf("Prefix query error: %s (code %d)\n", pqf_msg, code);
+            
+            yaz_pqf_destroy (pqf_parser);
+            return 0;
+        }
+        yaz_pqf_destroy (pqf_parser);
+        query.u.type_1 = RPNquery;
+        break;
+    case QueryType_CCL:
+        query.which = Z_Query_type_2;
+        query.u.type_2 = &ccl_query;
+        ccl_query.buf = (unsigned char*) arg;
+        ccl_query.len = strlen(arg);
+        break;
+    case QueryType_CCL2RPN:
+        query.which = Z_Query_type_1;
+        RPNquery = ccl_rpn_query(out, rpn);
+        if (!RPNquery)
+        {
+            printf ("Couldn't convert from CCL to RPN\n");
+            return 0;
+        }
+        query.u.type_1 = RPNquery;
+        ccl_rpn_delete (rpn);
+        break;
+    case QueryType_CQL:
+        query.which = Z_Query_type_104;
+        ext = (Z_External *) odr_malloc(out, sizeof(*ext));
+        ext->direct_reference = odr_getoidbystr(out, "1.2.840.10003.16.2");
+        ext->indirect_reference = 0;
+        ext->descriptor = 0;
+        ext->which = Z_External_CQL;
+        ext->u.cql = odr_strdup(out, arg);
+        query.u.type_104 =  ext;
+        break;
+    default:
+        printf ("Unsupported query type\n");
+        return 0;
+    }
+    send_apdu(apdu);
+    /*
+    if (send_apdu(apdu))
+    printf("Sent searchRequest.\n");*/
+    setno = 1;
+    return 2;
+}
+
+/* display Query Expression as part of searchResult-1 */
+/*
+static void display_queryExpression (Z_QueryExpression *qe)
+{
+    if (!qe)
+        return;
+    if (qe->which == Z_QueryExpression_term)
+    {
+        if (qe->u.term->queryTerm)
+        {
+            Z_Term *term = qe->u.term->queryTerm;
+            switch (term->which)
+            {
+            case Z_Term_general:
+                printf (" %.*s", term->u.general->len, term->u.general->buf);
+                break;
+            case Z_Term_characterString:
+                printf (" %s", term->u.characterString);
+                break;
+            case Z_Term_numeric:
+                printf (" %d", *term->u.numeric);
+                break;
+            case Z_Term_null:
+                printf (" null");
+                break;
+            }
+        }
+    }
+}
+*/
+/* see if we can find USR:SearchResult-1 */
+/*
+static void display_searchResult (Z_OtherInformation *o)
+{
+    int i;
+    if (!o)
+        return ;
+    for (i = 0; i < o->num_elements; i++)
+    {
+        if (o->list[i]->which == Z_OtherInfo_externallyDefinedInfo)
+        {
+            Z_External *ext = o->list[i]->information.externallyDefinedInfo;
+            
+            if (ext->which == Z_External_searchResult1)
+            {
+                int j;
+                Z_SearchInfoReport *sr = ext->u.searchResult1;
+                printf ("SearchResult-1:");
+                for (j = 0; j < sr->num; j++)
+                {
+		if (!sr->elements[j]->subqueryExpression)
+                        printf (" %d", j);
+                    display_queryExpression (
+                        sr->elements[j]->subqueryExpression);
+                    display_queryExpression (
+                        sr->elements[j]->subqueryInterpretation);
+                    display_queryExpression (
+                        sr->elements[j]->subqueryRecommendation);
+                    if (sr->elements[j]->subqueryCount)
+                        printf ("(%d)", *sr->elements[j]->subqueryCount);
+                }
+                printf ("\n");
+            }
+        }
+    }
+}
+*/
+/* kjdon: modified to not print the results, and return the number of hits */
+static int process_searchResponse(Z_SearchResponse *res)
+{
+    print_refid (res->referenceId);
+    if (!(*res->searchStatus)) {
+      /* this should return an error instead of 0 docs found... one day... */
+	return 0;
+    }
+    setno += *res->numberOfRecordsReturned;
+    /* what is this for? */
+    if (res->records)
+        display_records(res->records);
+    return *res->resultCount;
+
+}
+
+static void print_level(int iLevel)
+{
+    int i;
+    for (i = 0; i < iLevel * 4; i++)
+        printf(" ");
+}
+
+static void print_int(int iLevel, const char *pTag, int *pInt)
+{
+    if (pInt != NULL)
+    {
+        print_level(iLevel);
+        printf("%s: %d\n", pTag, *pInt);
+    }
+}
+
+static void print_string(int iLevel, const char *pTag, const char *pString)
+{
+    if (pString != NULL)
+    {
+        print_level(iLevel);
+        printf("%s: %s\n", pTag, pString);
+    }
+}
+
+static void print_oid(int iLevel, const char *pTag, Odr_oid *pOid)
+{
+    if (pOid != NULL)
+    {
+        int *pInt = pOid;
+
+        print_level(iLevel);
+        printf("%s:", pTag);
+        for (; *pInt != -1; pInt++)
+            printf(" %d", *pInt);
+        printf("\n");
+    }
+}
+
+static void print_referenceId(int iLevel, Z_ReferenceId *referenceId)
+{
+    if (referenceId != NULL)
+    {
+        int i;
+
+        print_level(iLevel);
+        printf("Ref Id (%d, %d): ", referenceId->len, referenceId->size);
+        for (i = 0; i < referenceId->len; i++)
+            printf("%c", referenceId->buf[i]);
+        printf("\n");
+    }
+}
+
+static void print_string_or_numeric(int iLevel, const char *pTag, Z_StringOrNumeric *pStringNumeric)
+{
+    if (pStringNumeric != NULL)
+    {
+        switch (pStringNumeric->which)
+        {
+        case Z_StringOrNumeric_string:
+            print_string(iLevel, pTag, pStringNumeric->u.string);
+            break;
+            
+        case Z_StringOrNumeric_numeric:
+            print_int(iLevel, pTag, pStringNumeric->u.numeric);
+            break;
+            
+        default:
+            print_level(iLevel);
+            printf("%s: valid type for Z_StringOrNumeric\n", pTag);
+            break;
+        }
+    }
+}
+
+static void print_universe_report_duplicate(
+    int iLevel,
+    Z_UniverseReportDuplicate *pUniverseReportDuplicate)
+{
+    if (pUniverseReportDuplicate != NULL)
+    {
+        print_level(iLevel);
+        printf("Universe Report Duplicate: \n");
+        iLevel++;
+        print_string_or_numeric(iLevel, "Hit No",
+                                pUniverseReportDuplicate->hitno);
+    }
+}
+
+static void print_universe_report_hits(
+    int iLevel,
+    Z_UniverseReportHits *pUniverseReportHits)
+{
+    if (pUniverseReportHits != NULL)
+    {
+        print_level(iLevel);
+        printf("Universe Report Hits: \n");
+        iLevel++;
+        print_string_or_numeric(iLevel, "Database",
+                                pUniverseReportHits->database);
+        print_string_or_numeric(iLevel, "Hits", pUniverseReportHits->hits);
+    }
+}
+
+static void print_universe_report(int iLevel, Z_UniverseReport *pUniverseReport)
+{
+    if (pUniverseReport != NULL)
+    {
+        print_level(iLevel);
+        printf("Universe Report: \n");
+        iLevel++;
+        print_int(iLevel, "Total Hits", pUniverseReport->totalHits);
+        switch (pUniverseReport->which)
+        {
+        case Z_UniverseReport_databaseHits:
+            print_universe_report_hits(iLevel,
+                                       pUniverseReport->u.databaseHits);
+            break;
+            
+        case Z_UniverseReport_duplicate:
+            print_universe_report_duplicate(iLevel,
+                                            pUniverseReport->u.duplicate);
+            break;
+            
+        default:
+            print_level(iLevel);
+            printf("Type: %d\n", pUniverseReport->which);
+            break;
+        }
+    }
+}
+
+static void print_external(int iLevel, Z_External *pExternal)
+{
+    if (pExternal != NULL)
+    {
+        print_level(iLevel);
+        printf("External: \n");
+        iLevel++;
+        print_oid(iLevel, "Direct Reference", pExternal->direct_reference);
+        print_int(iLevel, "InDirect Reference", pExternal->indirect_reference);
+        print_string(iLevel, "Descriptor", pExternal->descriptor);
+        switch (pExternal->which)
+        {
+        case Z_External_universeReport:
+            print_universe_report(iLevel, pExternal->u.universeReport);
+            break;
+            
+        default:
+            print_level(iLevel);
+            printf("Type: %d\n", pExternal->which);
+            break;
+        }
+    }
+}
+
+static int process_resourceControlRequest (Z_ResourceControlRequest *req)
+{
+    printf ("Received ResourceControlRequest.\n");
+    print_referenceId(1, req->referenceId);
+    print_int(1, "Suspended Flag", req->suspendedFlag);
+    print_int(1, "Partial Results Available", req->partialResultsAvailable);
+    print_int(1, "Response Required", req->responseRequired);
+    print_int(1, "Triggered Request Flag", req->triggeredRequestFlag);
+    print_external(1, req->resourceReport);
+    return 0;
+}
+
+void process_ESResponse(Z_ExtendedServicesResponse *res)
+{
+    printf("Status: ");
+    switch (*res->operationStatus)
+    {
+    case Z_ExtendedServicesResponse_done:
+        printf ("done\n");
+        break;
+    case Z_ExtendedServicesResponse_accepted:
+        printf ("accepted\n");
+        break;
+    case Z_ExtendedServicesResponse_failure:
+        printf ("failure\n");
+        display_diagrecs(res->diagnostics, res->num_diagnostics);
+        break;
+    default:
+        printf ("unknown\n");
+    }
+    if ( (*res->operationStatus != Z_ExtendedServicesResponse_failure) &&
+        (res->num_diagnostics != 0) ) {
+        display_diagrecs(res->diagnostics, res->num_diagnostics);
+    }
+    print_refid (res->referenceId);
+    if (res->taskPackage && 
+        res->taskPackage->which == Z_External_extendedService)
+    {
+        Z_TaskPackage *taskPackage = res->taskPackage->u.extendedService;
+        Odr_oct *id = taskPackage->targetReference;
+        Z_External *ext = taskPackage->taskSpecificParameters;
+        
+        if (id)
+        {
+            printf ("Target Reference: ");
+            print_stringn (id->buf, id->len);
+            printf ("\n");
+        }
+        if (ext->which == Z_External_update)
+        {
+            Z_IUUpdateTaskPackage *utp = ext->u.update->u.taskPackage;
+            if (utp && utp->targetPart)
+            {
+                Z_IUTargetPart *targetPart = utp->targetPart;
+                int i;
+
+                for (i = 0; i<targetPart->num_taskPackageRecords;  i++)
+                {
+
+                    Z_IUTaskPackageRecordStructure *tpr =
+                        targetPart->taskPackageRecords[i];
+                    printf ("task package record %d\n", i+1);
+                    if (tpr->which == Z_IUTaskPackageRecordStructure_record)
+                    {
+                        display_record (tpr->u.record);
+                    }
+                    else
+                    {
+                        printf ("other type\n");
+                    }
+                }
+            }
+        }
+    }
+}
+
+const char *get_ill_element (void *clientData, const char *element)
+{
+    return 0;
+}
+
+static Z_External *create_external_itemRequest()
+{
+    struct ill_get_ctl ctl;
+    ILL_ItemRequest *req;
+    Z_External *r = 0;
+    int item_request_size = 0;
+    char *item_request_buf = 0;
+
+    ctl.odr = out;
+    ctl.clientData = 0;
+    ctl.f = get_ill_element;
+    
+    req = ill_get_ItemRequest(&ctl, "ill", 0);
+    if (!req)
+        printf ("ill_get_ItemRequest failed\n");
+        
+    if (!ill_ItemRequest (out, &req, 0, 0))
+    {
+        if (apdu_file)
+        {
+            ill_ItemRequest(print, &req, 0, 0);
+            odr_reset(print);
+        }
+        item_request_buf = odr_getbuf (out, &item_request_size, 0);
+        if (item_request_buf)
+            odr_setbuf (out, item_request_buf, item_request_size, 1);
+        printf ("Couldn't encode ItemRequest, size %d\n", item_request_size);
+        return 0;
+    }
+    else
+    {
+        oident oid;
+        
+        item_request_buf = odr_getbuf (out, &item_request_size, 0);
+        oid.proto = PROTO_GENERAL;
+        oid.oclass = CLASS_GENERAL;
+        oid.value = VAL_ISO_ILL_1;
+        
+        r = (Z_External *) odr_malloc (out, sizeof(*r));
+        r->direct_reference = odr_oiddup(out,oid_getoidbyent(&oid)); 
+        r->indirect_reference = 0;
+        r->descriptor = 0;
+        r->which = Z_External_single;
+        
+        r->u.single_ASN1_type = (Odr_oct *)
+            odr_malloc (out, sizeof(*r->u.single_ASN1_type));
+        r->u.single_ASN1_type->buf = (unsigned char *)
+        odr_malloc (out, item_request_size);
+        r->u.single_ASN1_type->len = item_request_size;
+        r->u.single_ASN1_type->size = item_request_size;
+        memcpy (r->u.single_ASN1_type->buf, item_request_buf,
+                item_request_size);
+        
+        do_hex_dump(item_request_buf,item_request_size);
+    }
+    return r;
+}
+
+static Z_External *create_external_ILL_APDU(int which)
+{
+    struct ill_get_ctl ctl;
+    ILL_APDU *ill_apdu;
+    Z_External *r = 0;
+    int ill_request_size = 0;
+    char *ill_request_buf = 0;
+        
+    ctl.odr = out;
+    ctl.clientData = 0;
+    ctl.f = get_ill_element;
+
+    ill_apdu = ill_get_APDU(&ctl, "ill", 0);
+
+    if (!ill_APDU (out, &ill_apdu, 0, 0))
+    {
+        if (apdu_file)
+        {
+            printf ("-------------------\n");
+            ill_APDU(print, &ill_apdu, 0, 0);
+            odr_reset(print);
+            printf ("-------------------\n");
+        }
+        ill_request_buf = odr_getbuf (out, &ill_request_size, 0);
+        if (ill_request_buf)
+            odr_setbuf (out, ill_request_buf, ill_request_size, 1);
+        printf ("Couldn't encode ILL-Request, size %d\n", ill_request_size);
+        return 0;
+    }
+    else
+    {
+        oident oid;
+        ill_request_buf = odr_getbuf (out, &ill_request_size, 0);
+        
+        oid.proto = PROTO_GENERAL;
+        oid.oclass = CLASS_GENERAL;
+        oid.value = VAL_ISO_ILL_1;
+        
+        r = (Z_External *) odr_malloc (out, sizeof(*r));
+        r->direct_reference = odr_oiddup(out,oid_getoidbyent(&oid)); 
+        r->indirect_reference = 0;
+        r->descriptor = 0;
+        r->which = Z_External_single;
+        
+        r->u.single_ASN1_type = (Odr_oct *)
+            odr_malloc (out, sizeof(*r->u.single_ASN1_type));
+        r->u.single_ASN1_type->buf = (unsigned char *)
+        odr_malloc (out, ill_request_size);
+        r->u.single_ASN1_type->len = ill_request_size;
+        r->u.single_ASN1_type->size = ill_request_size;
+        memcpy (r->u.single_ASN1_type->buf, ill_request_buf, ill_request_size);
+/*         printf ("len = %d\n", ill_request_size); */
+/* 		do_hex_dump(ill_request_buf,ill_request_size); */
+/* 		printf("--- end of extenal\n"); */
+
+    }
+    return r;
+}
+
+
+static Z_External *create_ItemOrderExternal(const char *type, int itemno)
+{
+    Z_External *r = (Z_External *) odr_malloc(out, sizeof(Z_External));
+    oident ItemOrderRequest;
+  
+    ItemOrderRequest.proto = PROTO_Z3950;
+    ItemOrderRequest.oclass = CLASS_EXTSERV;
+    ItemOrderRequest.value = VAL_ITEMORDER;
+ 
+    r->direct_reference = odr_oiddup(out,oid_getoidbyent(&ItemOrderRequest)); 
+    r->indirect_reference = 0;
+    r->descriptor = 0;
+
+    r->which = Z_External_itemOrder;
+
+    r->u.itemOrder = (Z_ItemOrder *) odr_malloc(out,sizeof(Z_ItemOrder));
+    memset(r->u.itemOrder, 0, sizeof(Z_ItemOrder));
+    r->u.itemOrder->which=Z_IOItemOrder_esRequest;
+
+    r->u.itemOrder->u.esRequest = (Z_IORequest *) 
+        odr_malloc(out,sizeof(Z_IORequest));
+    memset(r->u.itemOrder->u.esRequest, 0, sizeof(Z_IORequest));
+
+    r->u.itemOrder->u.esRequest->toKeep = (Z_IOOriginPartToKeep *)
+        odr_malloc(out,sizeof(Z_IOOriginPartToKeep));
+    memset(r->u.itemOrder->u.esRequest->toKeep, 0, sizeof(Z_IOOriginPartToKeep));
+    r->u.itemOrder->u.esRequest->notToKeep = (Z_IOOriginPartNotToKeep *)
+        odr_malloc(out,sizeof(Z_IOOriginPartNotToKeep));
+    memset(r->u.itemOrder->u.esRequest->notToKeep, 0, sizeof(Z_IOOriginPartNotToKeep));
+
+    r->u.itemOrder->u.esRequest->toKeep->supplDescription = NULL;
+    r->u.itemOrder->u.esRequest->toKeep->contact = NULL;
+    r->u.itemOrder->u.esRequest->toKeep->addlBilling = NULL;
+
+    r->u.itemOrder->u.esRequest->notToKeep->resultSetItem =
+        (Z_IOResultSetItem *) odr_malloc(out, sizeof(Z_IOResultSetItem));
+    memset(r->u.itemOrder->u.esRequest->notToKeep->resultSetItem, 0, sizeof(Z_IOResultSetItem));
+    r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->resultSetId = "1";
+
+    r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->item =
+        (int *) odr_malloc(out, sizeof(int));
+    *r->u.itemOrder->u.esRequest->notToKeep->resultSetItem->item = itemno;
+
+    if (!strcmp (type, "item") || !strcmp(type, "2"))
+    {
+        printf ("using item-request\n");
+        r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 
+            create_external_itemRequest();
+    }
+    else if (!strcmp(type, "ill") || !strcmp(type, "1"))
+    {
+        printf ("using ILL-request\n");
+        r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 
+            create_external_ILL_APDU(ILL_APDU_ILL_Request);
+    }
+    else if (!strcmp(type, "xml") || !strcmp(type, "3"))
+    {
+    const char *xml_buf =
+        "<itemorder>\n"
+        "  <type>request</type>\n"
+        "  <libraryNo>000200</libraryNo>\n"
+        "  <borrowerTicketNo> 1212 </borrowerTicketNo>\n"
+        "</itemorder>";
+        r->u.itemOrder->u.esRequest->notToKeep->itemRequest =
+            z_ext_record (out, VAL_TEXT_XML, xml_buf, strlen(xml_buf));
+    }
+    else
+        r->u.itemOrder->u.esRequest->notToKeep->itemRequest = 0;
+
+    return r;
+}
+
+static int send_itemorder(const char *type, int itemno)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest);
+    Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
+    oident ItemOrderRequest;
+
+    ItemOrderRequest.proto = PROTO_Z3950;
+    ItemOrderRequest.oclass = CLASS_EXTSERV;
+    ItemOrderRequest.value = VAL_ITEMORDER;
+    req->packageType = odr_oiddup(out,oid_getoidbyent(&ItemOrderRequest));
+    req->packageName = esPackageName;
+
+    req->taskSpecificParameters = create_ItemOrderExternal(type, itemno);
+
+    send_apdu(apdu);
+    return 0;
+}
+
+static int only_z3950()
+{
+    if (protocol == PROTO_HTTP)
+    {
+	printf ("Not supported by SRW\n");
+	return 1;
+    }
+    return 0;
+}
+
+
+static int cmd_update_common(const char *arg, int version);
+
+static int cmd_update(const char *arg)
+{
+    return cmd_update_common(arg, 1);
+}
+
+static int cmd_update0(const char *arg)
+{
+    return cmd_update_common(arg, 0);
+}
+
+static int cmd_update_common(const char *arg, int version)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_extendedServicesRequest );
+    Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
+    Z_External *r;
+    char action[20], recid[20], fname[80];
+    int action_no;
+    Z_External *record_this = 0;
+
+    if (only_z3950())
+	return 0;
+    *action = 0;
+    *recid = 0;
+    *fname = 0;
+    sscanf (arg, "%19s %19s %79s", action, recid, fname);
+
+    if (!strcmp (action, "insert"))
+        action_no = Z_IUOriginPartToKeep_recordInsert;
+    else if (!strcmp (action, "replace"))
+        action_no = Z_IUOriginPartToKeep_recordReplace;
+    else if (!strcmp (action, "delete"))
+        action_no = Z_IUOriginPartToKeep_recordDelete;
+    else if (!strcmp (action, "update"))
+        action_no = Z_IUOriginPartToKeep_specialUpdate;
+    else 
+    {
+        printf ("Bad action: %s\n", action);
+        printf ("Possible values: insert, replace, delete, update\n");
+        return 0;
+    }
+
+    if (*fname)
+    {
+        FILE *inf;
+        struct stat status;
+        stat (fname, &status);
+        if (S_ISREG(status.st_mode) && (inf = fopen(fname, "rb")))
+        {
+            size_t len = status.st_size;
+            char *buf = (char *) xmalloc (len);
+
+            fread (buf, 1, len, inf);
+
+            fclose (inf);
+            
+            record_this = z_ext_record (out, VAL_TEXT_XML, buf, len);
+            
+            xfree (buf);
+        }
+        else
+        {
+            printf ("File %s doesn't exist\n", fname);
+            return 0;
+        }
+    }
+    else
+    {
+        if (!record_last)
+        {
+            printf ("No last record (update ignored)\n");
+            return 0;
+        }
+        record_this = record_last;
+    }
+
+    req->packageType =
+	yaz_oidval_to_z3950oid(out, CLASS_EXTSERV,
+			       version == 0 ? VAL_DBUPDATE0 : VAL_DBUPDATE);
+
+    req->packageName = esPackageName;
+    
+    req->referenceId = set_refid (out);
+
+    r = req->taskSpecificParameters = (Z_External *)
+        odr_malloc (out, sizeof(*r));
+    r->direct_reference = req->packageType;
+    r->indirect_reference = 0;
+    r->descriptor = 0;
+    if (version == 0)
+    {
+	Z_IU0OriginPartToKeep *toKeep;
+	Z_IU0SuppliedRecords *notToKeep;
+
+	r->which = Z_External_update0;
+	r->u.update0 = (Z_IU0Update *) odr_malloc(out, sizeof(*r->u.update0));
+	r->u.update0->which = Z_IUUpdate_esRequest;
+	r->u.update0->u.esRequest = (Z_IU0UpdateEsRequest *)
+	    odr_malloc(out, sizeof(*r->u.update0->u.esRequest));
+	toKeep = r->u.update0->u.esRequest->toKeep = (Z_IU0OriginPartToKeep *)
+	    odr_malloc(out, sizeof(*r->u.update0->u.esRequest->toKeep));
+	
+	toKeep->databaseName = databaseNames[0];
+	toKeep->schema = 0;
+	toKeep->elementSetName = 0;
+
+	toKeep->action = (int *) odr_malloc(out, sizeof(*toKeep->action));
+	*toKeep->action = action_no;
+	
+	notToKeep = r->u.update0->u.esRequest->notToKeep = (Z_IU0SuppliedRecords *)
+	    odr_malloc(out, sizeof(*r->u.update0->u.esRequest->notToKeep));
+	notToKeep->num = 1;
+	notToKeep->elements = (Z_IU0SuppliedRecords_elem **)
+	    odr_malloc(out, sizeof(*notToKeep->elements));
+	notToKeep->elements[0] = (Z_IU0SuppliedRecords_elem *)
+	    odr_malloc(out, sizeof(**notToKeep->elements));
+	notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
+	if (*recid)
+	{
+	    notToKeep->elements[0]->u.opaque = (Odr_oct *)
+		odr_malloc (out, sizeof(Odr_oct));
+	    notToKeep->elements[0]->u.opaque->buf = (unsigned char *) recid;
+	    notToKeep->elements[0]->u.opaque->size = strlen(recid);
+	    notToKeep->elements[0]->u.opaque->len = strlen(recid);
+	}
+	else
+	    notToKeep->elements[0]->u.opaque = 0;
+	notToKeep->elements[0]->supplementalId = 0;
+	notToKeep->elements[0]->correlationInfo = 0;
+	notToKeep->elements[0]->record = record_this;
+    }
+    else
+    {
+	Z_IUOriginPartToKeep *toKeep;
+	Z_IUSuppliedRecords *notToKeep;
+
+	r->which = Z_External_update;
+	r->u.update = (Z_IUUpdate *) odr_malloc(out, sizeof(*r->u.update));
+	r->u.update->which = Z_IUUpdate_esRequest;
+	r->u.update->u.esRequest = (Z_IUUpdateEsRequest *)
+	    odr_malloc(out, sizeof(*r->u.update->u.esRequest));
+	toKeep = r->u.update->u.esRequest->toKeep = (Z_IUOriginPartToKeep *)
+	    odr_malloc(out, sizeof(*r->u.update->u.esRequest->toKeep));
+	
+	toKeep->databaseName = databaseNames[0];
+	toKeep->schema = 0;
+	toKeep->elementSetName = 0;
+	toKeep->actionQualifier = 0;
+	toKeep->action = (int *) odr_malloc(out, sizeof(*toKeep->action));
+	*toKeep->action = action_no;
+
+	notToKeep = r->u.update->u.esRequest->notToKeep = (Z_IUSuppliedRecords *)
+	    odr_malloc(out, sizeof(*r->u.update->u.esRequest->notToKeep));
+	notToKeep->num = 1;
+	notToKeep->elements = (Z_IUSuppliedRecords_elem **)
+	    odr_malloc(out, sizeof(*notToKeep->elements));
+	notToKeep->elements[0] = (Z_IUSuppliedRecords_elem *)
+	    odr_malloc(out, sizeof(**notToKeep->elements));
+	notToKeep->elements[0]->which = Z_IUSuppliedRecords_elem_opaque;
+	if (*recid)
+	{
+	    notToKeep->elements[0]->u.opaque = (Odr_oct *)
+		odr_malloc (out, sizeof(Odr_oct));
+	    notToKeep->elements[0]->u.opaque->buf = (unsigned char *) recid;
+	    notToKeep->elements[0]->u.opaque->size = strlen(recid);
+	    notToKeep->elements[0]->u.opaque->len = strlen(recid);
+	}
+	else
+	    notToKeep->elements[0]->u.opaque = 0;
+	notToKeep->elements[0]->supplementalId = 0;
+	notToKeep->elements[0]->correlationInfo = 0;
+	notToKeep->elements[0]->record = record_this;
+    }
+    
+    send_apdu(apdu);
+
+    return 2;
+}
+
+
+static int cmd_itemorder(const char *arg)
+{
+    char type[12];
+    int itemno;
+   
+    if (only_z3950())
+	return 0;
+    if (sscanf (arg, "%10s %d", type, &itemno) != 2)
+        return 0;
+
+    printf("Item order request\n");
+    fflush(stdout);
+    send_itemorder(type, itemno);
+    return 2;
+}
+
+static void show_opt(const char *arg, void *clientData)
+{
+    printf ("%s ", arg);
+}
+
+static int cmd_zversion(const char *arg)
+{
+    if (*arg && arg)
+	z3950_version = atoi(arg);
+    else
+	printf ("version is %d\n", z3950_version);
+    return 0;
+}
+
+static int cmd_options(const char *arg)
+{
+    if (*arg)
+    {
+	int r;
+	int pos;
+	r = yaz_init_opt_encode(&z3950_options, arg, &pos);
+    }
+    else
+    {
+	yaz_init_opt_decode(&z3950_options, show_opt, 0);
+	printf ("\n");
+    }
+    return 0;
+}
+
+static int cmd_explain(const char *arg)
+{
+    if (protocol != PROTO_HTTP)
+	return 0;
+#if HAVE_XML2
+    if (!conn)
+	cmd_open(0);
+    if (conn)
+    {
+	Z_SRW_PDU *sr = 0;
+	
+	setno = 1;
+	
+	/* save this for later .. when fetching individual records */
+	sr = yaz_srw_get(out, Z_SRW_explain_request);
+	if (recordsyntax == VAL_TEXT_XML)
+            sr->u.explain_request->recordPacking = "xml";
+	send_srw(sr);
+	return 2;
+    }
+#endif
+    return 0;
+}
+
+static int cmd_init(const char *arg)
+{
+    if (*arg)
+    {
+        strncpy (cur_host, arg, sizeof(cur_host)-1);
+        cur_host[sizeof(cur_host)-1] = 0;
+    }
+    if (!conn || protocol != PROTO_Z3950)
+       return 0;
+    send_initRequest(cur_host);
+    return 2;
+
+}
+
+static int cmd_find(const char *arg)
+{
+    if (!*arg)
+    {
+        printf("Find what?\n");
+        return 0;
+    }
+    if (protocol == PROTO_HTTP)
+    {
+#if HAVE_XML2
+        if (!conn)
+            cmd_open(0);
+	if (!conn)
+	    return 0;
+        if (!send_SRW_searchRequest(arg))
+            return 0;
+#else
+        return 0;
+#endif
+    }
+    else
+    {
+        if (!conn)
+        {
+            try_reconnect(); 
+            
+            if (!conn) {					
+                printf("Not connected yet\n");
+                return 0;
+            }
+        }
+        if (!send_searchRequest(arg))
+            return 0;
+    }
+    return 2;
+}
+
+static int cmd_delete(const char *arg)
+{
+    if (!conn)
+    {
+        printf("Not connected yet\n");
+        return 0;
+    }
+    if (only_z3950())
+	return 0;
+    if (!send_deleteResultSetRequest(arg))
+        return 0;
+    return 2;
+}
+
+static int cmd_ssub(const char *arg)
+{
+    if (!(smallSetUpperBound = atoi(arg)))
+        return 0;
+    return 1;
+}
+
+static int cmd_lslb(const char *arg)
+{
+    if (only_z3950())
+	return 0;
+    if (!(largeSetLowerBound = atoi(arg)))
+        return 0;
+    return 1;
+}
+
+static int cmd_mspn(const char *arg)
+{
+    if (only_z3950())
+	return 0;
+    if (!(mediumSetPresentNumber = atoi(arg)))
+        return 0;
+    return 1;
+}
+
+static int cmd_status(const char *arg)
+{
+    printf("smallSetUpperBound: %d\n", smallSetUpperBound);
+    printf("largeSetLowerBound: %d\n", largeSetLowerBound);
+    printf("mediumSetPresentNumber: %d\n", mediumSetPresentNumber);
+    return 1;
+}
+
+static int cmd_setnames(const char *arg)
+{
+    if (*arg == '1')         /* enable ? */
+        setnumber = 0;
+    else if (*arg == '0')    /* disable ? */
+        setnumber = -1;
+    else if (setnumber < 0)  /* no args, toggle .. */
+        setnumber = 0;
+    else
+        setnumber = -1;
+   
+    if (setnumber >= 0)
+        printf("Set numbering enabled.\n");
+    else
+        printf("Set numbering disabled.\n");
+    return 1;
+}
+
+/* PRESENT SERVICE ----------------------------- */
+/* this one is based on johnmcps version - pretty much a copy of 
+   send_presentRequest, but passing in separate args, not an arg string */
+int z_send_getbriefrecords(int starting, int set, int howmany) {
+
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_presentRequest);
+    Z_PresentRequest *req = apdu->u.presentRequest;
+    Z_RecordComposition compo;
+    int nos = 1;
+    char setstring[100];
+
+    req->referenceId = set_refid (out);
+    nos = howmany;
+    setno = starting;
+    sprintf(setstring, "%d", setnumber);
+    req->resultSetId = setstring;
+    req->resultSetStartPoint = &setno;
+    req->numberOfRecordsRequested = &nos;
+    
+    req->preferredRecordSyntax =
+        yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax);
+
+    if (record_schema)
+    {
+        req->recordComposition = &compo;
+        compo.which = Z_RecordComp_complex;
+        compo.u.complex = (Z_CompSpec *)
+            odr_malloc(out, sizeof(*compo.u.complex));
+        compo.u.complex->selectAlternativeSyntax = (bool_t *) 
+            odr_malloc(out, sizeof(bool_t));
+        *compo.u.complex->selectAlternativeSyntax = 0;
+
+        compo.u.complex->generic = (Z_Specification *)
+            odr_malloc(out, sizeof(*compo.u.complex->generic));
+        compo.u.complex->generic->which = Z_Schema_oid;
+
+        compo.u.complex->generic->schema.oid =
+	    yaz_str_to_z3950oid(out, CLASS_SCHEMA, record_schema);
+
+        if (!compo.u.complex->generic->schema.oid)
+        {
+            /* OID wasn't a schema! Try record syntax instead. */
+            compo.u.complex->generic->schema.oid = (Odr_oid *)
+		yaz_str_to_z3950oid(out, CLASS_RECSYN, record_schema);
+        }
+        if (!elementSetNames)
+            compo.u.complex->generic->elementSpec = 0;
+        else
+        {
+            compo.u.complex->generic->elementSpec = (Z_ElementSpec *)
+                odr_malloc(out, sizeof(Z_ElementSpec));
+            compo.u.complex->generic->elementSpec->which =
+                Z_ElementSpec_elementSetName;
+            compo.u.complex->generic->elementSpec->u.elementSetName =
+                elementSetNames->u.generic;
+        }
+        compo.u.complex->num_dbSpecific = 0;
+        compo.u.complex->dbSpecific = 0;
+        compo.u.complex->num_recordSyntax = 0;
+        compo.u.complex->recordSyntax = 0;
+    }
+    else if (elementSetNames)
+    {
+        req->recordComposition = &compo;
+        compo.which = Z_RecordComp_simple;
+        compo.u.simple = elementSetNames;
+    }
+    send_apdu(apdu);
+    return 0;
+}
+
+static void parse_show_args(const char *arg_c, char *setstring,
+                            int *start, int *number)
+{
+    char arg[40];
+    char *p;
+
+    strncpy(arg, arg_c, sizeof(arg)-1);
+    arg[sizeof(arg)-1] = '\0';
+
+    if ((p = strchr(arg, '+')))
+    {
+        *number = atoi(p + 1);
+        *p = '\0';
+    }
+    if (*arg)
+        *start = atoi(arg);
+    if (p && (p=strchr(p+1, '+')))
+        strcpy (setstring, p+1);
+    else if (setnumber >= 0)
+        sprintf(setstring, "%d", setnumber);
+    else
+        *setstring = '\0';
+}
+
+static int send_presentRequest(const char *arg)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_presentRequest);
+    Z_PresentRequest *req = apdu->u.presentRequest;
+    Z_RecordComposition compo;
+    int nos = 1;
+    char setstring[100];
+
+    req->referenceId = set_refid (out);
+
+    parse_show_args(arg, setstring, &setno, &nos);
+    if (*setstring)
+        req->resultSetId = setstring;
+
+    req->resultSetStartPoint = &setno;
+    req->numberOfRecordsRequested = &nos;
+
+    req->preferredRecordSyntax =
+        yaz_oidval_to_z3950oid(out, CLASS_RECSYN, recordsyntax);
+
+    if (record_schema)
+    {
+        req->recordComposition = &compo;
+        compo.which = Z_RecordComp_complex;
+        compo.u.complex = (Z_CompSpec *)
+            odr_malloc(out, sizeof(*compo.u.complex));
+        compo.u.complex->selectAlternativeSyntax = (bool_t *) 
+            odr_malloc(out, sizeof(bool_t));
+        *compo.u.complex->selectAlternativeSyntax = 0;
+
+        compo.u.complex->generic = (Z_Specification *)
+            odr_malloc(out, sizeof(*compo.u.complex->generic));
+        compo.u.complex->generic->which = Z_Schema_oid;
+
+        compo.u.complex->generic->schema.oid =
+	    yaz_str_to_z3950oid(out, CLASS_SCHEMA, record_schema);
+
+        if (!compo.u.complex->generic->schema.oid)
+        {
+            /* OID wasn't a schema! Try record syntax instead. */
+            compo.u.complex->generic->schema.oid = (Odr_oid *)
+		yaz_str_to_z3950oid(out, CLASS_RECSYN, record_schema);
+        }
+        if (!elementSetNames)
+            compo.u.complex->generic->elementSpec = 0;
+        else
+        {
+            compo.u.complex->generic->elementSpec = (Z_ElementSpec *)
+                odr_malloc(out, sizeof(Z_ElementSpec));
+            compo.u.complex->generic->elementSpec->which =
+                Z_ElementSpec_elementSetName;
+            compo.u.complex->generic->elementSpec->u.elementSetName =
+                elementSetNames->u.generic;
+        }
+        compo.u.complex->num_dbSpecific = 0;
+        compo.u.complex->dbSpecific = 0;
+        compo.u.complex->num_recordSyntax = 0;
+        compo.u.complex->recordSyntax = 0;
+    }
+    else if (elementSetNames)
+    {
+        req->recordComposition = &compo;
+        compo.which = Z_RecordComp_simple;
+        compo.u.simple = elementSetNames;
+    }
+    send_apdu(apdu);
+    printf("Sent presentRequest (%d+%d).\n", setno, nos);
+    return 2;
+}
+
+#if HAVE_XML2
+static int send_SRW_presentRequest(const char *arg)
+{
+    char setstring[100];
+    int nos = 1;
+    Z_SRW_PDU *sr = srw_sr;
+
+    if (!sr)
+        return 0;
+    parse_show_args(arg, setstring, &setno, &nos);
+    sr->u.request->startRecord = odr_intdup(out, setno);
+    sr->u.request->maximumRecords = odr_intdup(out, nos);
+    if (record_schema)
+        sr->u.request->recordSchema = record_schema;
+    if (recordsyntax == VAL_TEXT_XML)
+        sr->u.request->recordPacking = "xml";
+    return send_srw(sr);
+}
+#endif
+
+static void close_session (void)
+{
+    if (conn)
+        cs_close (conn);
+    conn = 0;
+    if (session_mem)
+    {
+        nmem_destroy (session_mem);
+        session_mem = NULL;
+    }
+    sent_close = 0;
+    odr_reset(out);
+    odr_reset(in);
+    odr_reset(print);
+}
+
+void process_close(Z_Close *req)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_close);
+    Z_Close *res = apdu->u.close;
+
+    static char *reasons[] =
+    {
+        "finished",
+        "shutdown",
+        "system problem",
+        "cost limit reached",
+        "resources",
+        "security violation",
+        "protocolError",
+        "lack of activity",
+        "peer abort",
+        "unspecified"
+    };
+
+    printf("Reason: %s, message: %s\n", reasons[*req->closeReason],
+        req->diagnosticInformation ? req->diagnosticInformation : "NULL");
+    if (sent_close)
+        close_session ();
+    else
+    {
+        *res->closeReason = Z_Close_finished;
+        send_apdu(apdu);
+        printf("Sent response.\n");
+        sent_close = 1;
+    }
+}
+
+static int cmd_show(const char *arg)
+{
+    if (protocol == PROTO_HTTP)
+    {
+#if HAVE_XML2
+        if (!conn)
+            cmd_open(0);
+	if (!conn)
+	    return 0;
+        if (!send_SRW_presentRequest(arg))
+            return 0;
+#else
+        return 0;
+#endif
+    }
+    else
+    {
+        if (!conn)
+        {
+            printf("Not connected yet\n");
+            return 0;
+        }
+        if (!send_presentRequest(arg))
+            return 0;
+    }
+    return 2;
+}
+
+int cmd_quit(const char *arg)
+{
+    printf("See you later, alligator.\n");
+    xmalloc_trav ("");
+    exit(0);
+    return 0;
+}
+
+int cmd_cancel(const char *arg)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_triggerResourceControlRequest);
+    Z_TriggerResourceControlRequest *req =
+        apdu->u.triggerResourceControlRequest;
+    bool_t rfalse = 0;
+    
+    if (!conn)
+    {
+        printf("Session not initialized yet\n");
+        return 0;
+    }
+    if (only_z3950())
+	return 0;
+    if (!ODR_MASK_GET(session->options, Z_Options_triggerResourceCtrl))
+    {
+        printf("Target doesn't support cancel (trigger resource ctrl)\n");
+        return 0;
+    }
+    *req->requestedAction = Z_TriggerResourceControlRequest_cancel;
+    req->resultSetWanted = &rfalse;
+    req->referenceId = set_refid (out);
+
+    send_apdu(apdu);
+    printf("Sent cancel request\n");
+    return 2;
+}
+
+
+int cmd_cancel_find(const char *arg) {
+    int fres;
+    fres=cmd_find(arg);
+    if( fres > 0 ) {
+	return cmd_cancel("");
+    };
+    return fres;
+}
+
+int send_scanrequest(const char *query, int pp, int num, const char *term)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_scanRequest);
+    Z_ScanRequest *req = apdu->u.scanRequest;
+    
+    if (only_z3950())
+	return 0;
+    if (queryType == QueryType_CCL2RPN)
+    {
+        int error, pos;
+        struct ccl_rpn_node *rpn;
+
+        rpn = ccl_find_str (bibset,  query, &error, &pos);
+        if (error)
+        {
+            printf("CCL ERROR: %s\n", ccl_err_msg(error));
+            return -1;
+        }
+        req->attributeSet =
+	    yaz_oidval_to_z3950oid(out, CLASS_ATTSET, VAL_BIB1);
+        if (!(req->termListAndStartPoint = ccl_scan_query (out, rpn)))
+        {
+            printf("Couldn't convert CCL to Scan term\n");
+            return -1;
+        }
+        ccl_rpn_delete (rpn);
+    }
+    else
+    {
+        YAZ_PQF_Parser pqf_parser = yaz_pqf_create ();
+
+        if (!(req->termListAndStartPoint =
+              yaz_pqf_scan(pqf_parser, out, &req->attributeSet, query)))
+        {
+            const char *pqf_msg;
+            size_t off;
+            int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
+            printf("%*s^\n", off+7, "");
+            printf("Prefix query error: %s (code %d)\n", pqf_msg, code);
+            yaz_pqf_destroy (pqf_parser);
+            return -1;
+        }
+        yaz_pqf_destroy (pqf_parser);
+    }
+    if (term && *term)
+    {
+        if (req->termListAndStartPoint->term &&
+            req->termListAndStartPoint->term->which == Z_Term_general &&
+            req->termListAndStartPoint->term->u.general)
+        {
+            req->termListAndStartPoint->term->u.general->buf =
+                (unsigned char *) odr_strdup(out, term);
+            req->termListAndStartPoint->term->u.general->len =
+                req->termListAndStartPoint->term->u.general->size =
+                strlen(term);
+        }
+    }
+    req->referenceId = set_refid (out);
+    req->num_databaseNames = num_databaseNames;
+    req->databaseNames = databaseNames;
+    req->numberOfTermsRequested = &num;
+    req->preferredPositionInResponse = &pp;
+    req->stepSize = odr_intdup(out, scan_stepSize);
+    send_apdu(apdu);
+    return 2;
+}
+
+int send_sortrequest(const char *arg, int newset)
+{
+    Z_APDU *apdu = zget_APDU(out, Z_APDU_sortRequest);
+    Z_SortRequest *req = apdu->u.sortRequest;
+    Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
+        odr_malloc (out, sizeof(*sksl));
+    char setstring[32];
+
+    if (only_z3950())
+	return 0;
+    if (setnumber >= 0)
+        sprintf (setstring, "%d", setnumber);
+    else
+        sprintf (setstring, "default");
+
+    req->referenceId = set_refid (out);
+
+    req->num_inputResultSetNames = 1;
+    req->inputResultSetNames = (Z_InternationalString **)
+        odr_malloc (out, sizeof(*req->inputResultSetNames));
+    req->inputResultSetNames[0] = odr_strdup (out, setstring);
+
+    if (newset && setnumber >= 0)
+        sprintf (setstring, "%d", ++setnumber);
+
+    req->sortedResultSetName = odr_strdup (out, setstring);
+
+    req->sortSequence = yaz_sort_spec (out, arg);
+    if (!req->sortSequence)
+    {
+        printf ("Missing sort specifications\n");
+        return -1;
+    }
+    send_apdu(apdu);
+    return 2;
+}
+
+void display_term(Z_TermInfo *t)
+{
+    if (t->displayTerm)
+        printf("%s", t->displayTerm);
+    else if (t->term->which == Z_Term_general)
+    {
+        printf("%.*s", t->term->u.general->len, t->term->u.general->buf);
+        sprintf(last_scan_line, "%.*s", t->term->u.general->len,
+            t->term->u.general->buf);
+    }
+    else
+        printf("Term (not general)");
+    if (t->globalOccurrences)
+        printf (" (%d)\n", *t->globalOccurrences);
+    else
+        printf ("\n");
+}
+
+void process_scanResponse(Z_ScanResponse *res)
+{
+    int i;
+    Z_Entry **entries = NULL;
+    int num_entries = 0;
+   
+    printf("Received ScanResponse\n"); 
+    print_refid (res->referenceId);
+    printf("%d entries", *res->numberOfEntriesReturned);
+    if (res->positionOfTerm)
+        printf (", position=%d", *res->positionOfTerm); 
+    printf ("\n");
+    if (*res->scanStatus != Z_Scan_success)
+        printf("Scan returned code %d\n", *res->scanStatus);
+    if (!res->entries)
+        return;
+    if ((entries = res->entries->entries))
+        num_entries = res->entries->num_entries;
+    for (i = 0; i < num_entries; i++)
+    {
+        int pos_term = res->positionOfTerm ? *res->positionOfTerm : -1;
+        if (entries[i]->which == Z_Entry_termInfo)
+        {
+            printf("%c ", i + 1 == pos_term ? '*' : ' ');
+            display_term(entries[i]->u.termInfo);
+        }
+        else
+            display_diagrecs(&entries[i]->u.surrogateDiagnostic, 1);
+    }
+    if (res->entries->nonsurrogateDiagnostics)
+        display_diagrecs (res->entries->nonsurrogateDiagnostics,
+                          res->entries->num_nonsurrogateDiagnostics);
+}
+
+void process_sortResponse(Z_SortResponse *res)
+{
+    printf("Received SortResponse: status=");
+    switch (*res->sortStatus)
+    {
+    case Z_SortResponse_success:
+        printf ("success"); break;
+    case Z_SortResponse_partial_1:
+        printf ("partial"); break;
+    case Z_SortResponse_failure:
+        printf ("failure"); break;
+    default:
+        printf ("unknown (%d)", *res->sortStatus);
+    }
+    printf ("\n");
+    print_refid (res->referenceId);
+    if (res->diagnostics)
+        display_diagrecs(res->diagnostics,
+                         res->num_diagnostics);
+}
+
+void process_deleteResultSetResponse (Z_DeleteResultSetResponse *res)
+{
+    printf("Got deleteResultSetResponse status=%d\n",
+           *res->deleteOperationStatus);
+    if (res->deleteListStatuses)
+    {
+        int i;
+        for (i = 0; i < res->deleteListStatuses->num; i++)
+        {
+            printf ("%s status=%d\n", res->deleteListStatuses->elements[i]->id,
+                    *res->deleteListStatuses->elements[i]->status);
+        }
+    }
+}
+
+int cmd_sort_generic(const char *arg, int newset)
+{
+    if (!conn)
+    {
+        printf("Session not initialized yet\n");
+        return 0;
+    }
+    if (only_z3950())
+	return 0;
+    if (!ODR_MASK_GET(session->options, Z_Options_sort))
+    {
+        printf("Target doesn't support sort\n");
+        return 0;
+    }
+    if (*arg)
+    {
+        if (send_sortrequest(arg, newset) < 0)
+            return 0;
+        return 2;
+    }
+    return 0;
+}
+
+int cmd_sort(const char *arg)
+{
+    return cmd_sort_generic (arg, 0);
+}
+
+int cmd_sort_newset (const char *arg)
+{
+    return cmd_sort_generic (arg, 1);
+}
+
+int cmd_scanstep(const char *arg)
+{
+    scan_stepSize = atoi(arg);
+    return 0;
+}
+
+int cmd_scanpos(const char *arg)
+{
+    int r = sscanf(arg, "%d", &scan_position);
+    if (r == 0)
+        scan_position = 1;
+    return 0;
+}
+
+int cmd_scansize(const char *arg)
+{
+    int r = sscanf(arg, "%d", &scan_size);
+    if (r == 0)
+        scan_size = 20;
+    return 0;
+}
+
+int cmd_scan(const char *arg)
+{
+    if (protocol == PROTO_HTTP)
+    {
+#if HAVE_XML2
+        if (!conn)
+            cmd_open(0);
+	if (!conn)
+	    return 0;
+	if (*arg)
+	{
+	    if (send_SRW_scanRequest(arg, scan_position, scan_size) < 0)
+		return 0;
+	}
+	else
+	{
+	    if (send_SRW_scanRequest(last_scan_line, 1, scan_size) < 0)
+		return 0;
+	}
+	return 2;
+#else
+        return 0;
+#endif
+    }
+    else
+    {
+	if (!conn)
+	{
+	    try_reconnect();
+	    
+	    if (!conn) {								
+		printf("Session not initialized yet\n");
+		return 0;
+	    }
+	}
+	if (!ODR_MASK_GET(session->options, Z_Options_scan))
+	{
+	    printf("Target doesn't support scan\n");
+	    return 0;
+	}
+	if (*arg)
+	{
+	    strcpy (last_scan_query, arg);
+	    if (send_scanrequest(arg, scan_position, scan_size, 0) < 0)
+		return 0;
+	}
+	else
+	{
+	    if (send_scanrequest(last_scan_query, 1, scan_size, last_scan_line) < 0)
+		return 0;
+	}
+	return 2;
+    }
+}
+
+int cmd_schema(const char *arg)
+{
+    xfree(record_schema);
+    record_schema = 0;
+    if (arg && *arg)
+        record_schema = xstrdup(arg);
+    return 1;
+}
+
+int cmd_format(const char *arg)
+{
+    oid_value nsyntax;
+    if (!arg || !*arg)
+    {
+        printf("Usage: format <recordsyntax>\n");
+        return 0;
+    }
+    nsyntax = oid_getvalbyname (arg);
+    if (strcmp(arg, "none") && nsyntax == VAL_NONE)
+    {
+        printf ("unknown record syntax\n");
+        return 0;
+    }
+    recordsyntax = nsyntax;
+    return 1;
+}
+
+int cmd_elements(const char *arg)
+{
+    static Z_ElementSetNames esn;
+    static char what[100];
+
+    if (!arg || !*arg)
+    {
+        elementSetNames = 0;
+        return 1;
+    }
+    strcpy(what, arg);
+    esn.which = Z_ElementSetNames_generic;
+    esn.u.generic = what;
+    elementSetNames = &esn;
+    return 1;
+}
+
+int cmd_attributeset(const char *arg)
+{
+    char what[100];
+
+    if (!arg || !*arg)
+    {
+        printf("Usage: attributeset <setname>\n");
+        return 0;
+    }
+    sscanf(arg, "%s", what);
+    if (p_query_attset (what))
+    {
+        printf("Unknown attribute set name\n");
+        return 0;
+    }
+    return 1;
+}
+
+int cmd_querytype (const char *arg)
+{
+    if (!strcmp (arg, "ccl"))
+        queryType = QueryType_CCL;
+    else if (!strcmp (arg, "prefix") || !strcmp(arg, "rpn"))
+        queryType = QueryType_Prefix;
+    else if (!strcmp (arg, "ccl2rpn") || !strcmp (arg, "cclrpn"))
+        queryType = QueryType_CCL2RPN;
+    else if (!strcmp(arg, "cql"))
+        queryType = QueryType_CQL;        
+    else if (!strcmp (arg, "cql2rpn") || !strcmp (arg, "cqlrpn"))
+        queryType = QueryType_CQL2RPN;
+    else
+    {
+        printf ("Querytype must be one of:\n");
+        printf (" prefix         - Prefix query\n");
+        printf (" ccl            - CCL query\n");
+        printf (" ccl2rpn        - CCL query converted to RPN\n");
+        printf (" cql            - CQL\n");
+        printf (" cql2rpn        - CQL query converted to RPN\n");
+        return 0;
+    }
+    return 1;
+}
+
+int cmd_refid (const char *arg)
+{
+    xfree (refid);
+    refid = NULL;
+    if (*arg)
+        refid = xstrdup (arg);
+    return 1;
+}
+
+int z_cmd_close(const char *arg)
+{
+    Z_APDU *apdu;
+    Z_Close *req;
+    if (!conn)
+        return 0;
+    if (only_z3950())
+	return 0;
+
+    apdu = zget_APDU(out, Z_APDU_close);
+    req = apdu->u.close;
+    *req->closeReason = Z_Close_finished;
+    send_apdu(apdu);
+    printf("Sent close request.\n");
+    sent_close = 1;
+    return 2;
+}
+
+int cmd_packagename(const char* arg)
+{
+    xfree (esPackageName);
+    esPackageName = NULL;
+    if (*arg)
+        esPackageName = xstrdup(arg);
+    return 1;
+}
+
+int cmd_proxy(const char* arg)
+{
+    xfree (yazProxy);
+    yazProxy = NULL;
+    if (*arg)
+        yazProxy = xstrdup (arg);
+    return 1;
+}
+
+int cmd_marccharset(const char *arg)
+{
+    char l1[30];
+
+    *l1 = 0;
+    if (sscanf(arg, "%29s", l1) < 1)
+    {
+    	printf("MARC character set is `%s'\n", 
+               marcCharset ? marcCharset: "none");
+        return 1;
+    }
+    xfree (marcCharset);
+    marcCharset = 0;
+    if (strcmp(l1, "-"))
+        marcCharset = xstrdup(l1);
+    return 1;
+}
+
+int cmd_displaycharset(const char *arg)
+{
+    char l1[30];
+
+    *l1 = 0;
+    if (sscanf(arg, "%29s", l1) < 1)
+    {
+    	printf("Display character set is `%s'\n", 
+               outputCharset ? outputCharset: "none");
+    }
+    else
+    {
+        xfree (outputCharset);
+        outputCharset = 0;
+        if (!strcmp(l1, "auto") && codeset)
+        {
+            if (codeset)
+            {
+                printf ("Display character set: %s\n", codeset);
+                outputCharset = xstrdup(codeset);
+            }
+            else
+                printf ("No codeset found on this system\n");
+        }
+        else if (strcmp(l1, "-") && strcmp(l1, "none"))
+            outputCharset = xstrdup(l1);
+    } 
+    return 1;
+}
+
+int cmd_negcharset(const char *arg)
+{
+    char l1[30];
+
+    *l1 = 0;
+    if (sscanf(arg, "%29s %d %d", l1, &negotiationCharsetRecords,
+	       &negotiationCharsetVersion) < 1)
+    {
+    	printf("Current negotiation character set is `%s'\n", 
+               negotiationCharset ? negotiationCharset: "none");  
+	printf("Records in charset %s\n", negotiationCharsetRecords ? 
+	       "yes" : "no");
+	printf("Charneg version %d\n", negotiationCharsetVersion);
+    }
+    else
+    {
+	xfree (negotiationCharset);
+	negotiationCharset = NULL;
+	if (*l1 && strcmp(l1, "-") && strcmp(l1, "none"))
+	{
+	    negotiationCharset = xstrdup(l1);
+	    printf ("Character set negotiation : %s\n", negotiationCharset);
+	}
+    }
+    return 1;
+}
+
+int cmd_charset(const char* arg)
+{
+    char l1[30], l2[30], l3[30];
+
+    *l1 = *l2 = *l3 = 0;
+    if (sscanf(arg, "%29s %29s %29s", l1, l2, l3) < 1)
+    {
+	cmd_negcharset("");
+	cmd_displaycharset("");
+	cmd_marccharset("");
+    }
+    else
+    {
+	cmd_negcharset(l1);
+	if (*l2)
+	    cmd_displaycharset(l2);
+	if (*l3)
+	    cmd_marccharset(l3);
+    }
+    return 1;
+}
+
+int cmd_lang(const char* arg)
+{
+    if (*arg == '\0') {
+    	printf("Current language is `%s'\n", (yazLang)?yazLang:NULL);
+    	return 1;
+    }
+    xfree (yazLang);
+    yazLang = NULL;
+    if (*arg)
+        yazLang = xstrdup(arg);
+    return 1;
+}
+
+int cmd_source(const char* arg, int echo ) 
+{
+    /* first should open the file and read one line at a time.. */
+    FILE* includeFile;
+    char line[102400], *cp;
+
+    if(strlen(arg)<1) {
+        fprintf(stderr,"Error in source command use a filename\n");
+        return -1;
+    }
+    
+    includeFile = fopen (arg, "r");
+    
+    if(!includeFile) {
+        fprintf(stderr,"Unable to open file %s for reading\n",arg);
+        return -1;
+    }
+    
+    while(!feof(includeFile)) {
+        memset(line,0,sizeof(line));
+        fgets(line,sizeof(line),includeFile);
+        
+        if(strlen(line) < 2) continue;
+        if(line[0] == '#') continue;
+        
+        if ((cp = strrchr (line, '\n')))
+            *cp = '\0';
+	
+	if( echo ) {
+	    printf( "processing line: %s\n",line );
+	};
+        process_cmd_line(line);
+    }
+    
+    if(fclose(includeFile)<0) {
+        perror("unable to close include file");
+        exit(1);
+    }
+    return 1;
+}
+
+int cmd_source_echo(const char* arg)
+{ 
+    cmd_source(arg, 1);
+    return 1;
+}
+
+int cmd_source_noecho(const char* arg)
+{
+    cmd_source(arg, 0);
+    return 1;
+}
+
+
+int cmd_subshell(const char* args)
+{
+    if(strlen(args)) 
+        system(args);
+    else 
+        system(getenv("SHELL"));
+    
+    printf("\n");
+    return 1;
+}
+
+int cmd_set_berfile(const char *arg)
+{
+    if (ber_file && ber_file != stdout && ber_file != stderr)
+        fclose(ber_file);
+    if (!strcmp(arg, ""))
+        ber_file = 0;
+    else if (!strcmp(arg, "-"))
+        ber_file = stdout;
+    else
+        ber_file = fopen(arg, "a");
+    return 1;
+}
+
+int cmd_set_apdufile(const char *arg)
+{
+    if(apdu_file && apdu_file != stderr && apdu_file != stderr)
+        fclose(apdu_file);
+    if (!strcmp(arg, ""))
+        apdu_file = 0;
+    else if (!strcmp(arg, "-"))
+        apdu_file = stderr;
+    else
+    {
+        apdu_file = fopen(arg, "a");
+        if (!apdu_file)
+            perror("unable to open apdu log file");
+    }
+    if (apdu_file)
+        odr_setprint(print, apdu_file);
+    return 1;
+}
+
+int cmd_set_cclfile(const char* arg)
+{  
+    FILE *inf;
+
+    bibset = ccl_qual_mk (); 
+    inf = fopen (arg, "r");
+    if (!inf)
+        perror("unable to open CCL file");
+    else
+    {
+        ccl_qual_file (bibset, inf);
+        fclose (inf);
+    }
+    strcpy(ccl_fields,arg);
+    return 0;
+}
+
+int cmd_set_cqlfile(const char* arg)
+{
+    cql_transform_t newcqltrans;
+
+    if ((newcqltrans = cql_transform_open_fname(arg)) == 0) {
+        perror("unable to open CQL file");
+	return 0;
+    }
+    if (cqltrans != 0)
+	cql_transform_close(cqltrans);
+
+    cqltrans = newcqltrans;
+    strcpy(cql_fields, arg);
+    return 0;
+}
+
+int cmd_set_auto_reconnect(const char* arg)
+{  
+    if(strlen(arg)==0) {
+        auto_reconnect = ! auto_reconnect;
+    } else if(strcmp(arg,"on")==0) {
+        auto_reconnect = 1;
+    } else if(strcmp(arg,"off")==0) {
+        auto_reconnect = 0;		
+    } else {
+        printf("Error use on or off\n");
+        return 1;
+    }
+    
+    if (auto_reconnect)
+        printf("Set auto reconnect enabled.\n");
+    else
+        printf("Set auto reconnect disabled.\n");
+    
+    return 0;
+}
+
+int cmd_set_marcdump(const char* arg)
+{
+    if(marc_file && marc_file != stderr) { /* don't close stdout*/
+        fclose(marc_file);
+    }
+
+    if (!strcmp(arg, ""))
+        marc_file = 0;
+    else if (!strcmp(arg, "-"))
+        marc_file = stderr;
+    else
+    {
+        marc_file = fopen(arg, "a");
+        if (!marc_file)
+            perror("unable to open marc log file");
+    }
+    return 1;
+}
+
+/* 
+   this command takes 3 arge {name class oid} 
+*/
+int cmd_register_oid(const char* args) {
+    static struct {
+        char* className;
+        oid_class oclass;
+    } oid_classes[] = {
+        {"appctx",CLASS_APPCTX},
+        {"absyn",CLASS_ABSYN},
+        {"attset",CLASS_ATTSET},
+        {"transyn",CLASS_TRANSYN},
+        {"diagset",CLASS_DIAGSET},
+        {"recsyn",CLASS_RECSYN},
+        {"resform",CLASS_RESFORM},
+        {"accform",CLASS_ACCFORM},
+        {"extserv",CLASS_EXTSERV},
+        {"userinfo",CLASS_USERINFO},
+        {"elemspec",CLASS_ELEMSPEC},
+        {"varset",CLASS_VARSET},
+        {"schema",CLASS_SCHEMA},
+        {"tagset",CLASS_TAGSET},
+        {"general",CLASS_GENERAL},
+        {0,(enum oid_class) 0}
+    };
+    char oname_str[101], oclass_str[101], oid_str[101];  
+    char* name;
+    int i;
+    oid_class oidclass = CLASS_GENERAL;
+    int val = 0, oid[OID_SIZE];
+    struct oident * new_oident=NULL;
+    
+    if (sscanf (args, "%100[^ ] %100[^ ] %100s",
+                oname_str,oclass_str, oid_str) < 1) {
+        printf("Error in register command \n");
+        return 0;
+    }
+    
+    for (i = 0; oid_classes[i].className; i++) {
+        if (!strcmp(oid_classes[i].className, oclass_str))
+        {
+            oidclass=oid_classes[i].oclass;
+            break;
+        }
+    }
+    
+    if(!(oid_classes[i].className)) {
+        printf("Unknown oid class %s\n",oclass_str);
+        return 0;
+    }
+    
+    i = 0;
+    name = oid_str;
+    val = 0;
+    
+    while (isdigit (*(unsigned char *) name))
+    {
+        val = val*10 + (*name - '0');
+        name++;
+        if (*name == '.')
+        {
+            if (i < OID_SIZE-1)
+                oid[i++] = val;
+            val = 0;
+            name++;
+        }
+    }
+    oid[i] = val;
+    oid[i+1] = -1;
+    
+    new_oident = oid_addent (oid, PROTO_GENERAL, oidclass, oname_str,
+			     VAL_DYNAMIC);  
+    if(strcmp(new_oident->desc,oname_str))
+    {
+        fprintf(stderr,"oid is already named as %s, registration failed\n",
+                new_oident->desc);
+    }
+    return 1;  
+}
+
+int cmd_push_command(const char* arg) 
+{
+    
+#if HAVE_READLINE_HISTORY_H
+    if(strlen(arg)>1) 
+        add_history(arg);
+#else 
+    fprintf(stderr,"Not compiled with the readline/history module\n");
+#endif
+    return 1;
+}
+
+void source_rcfile() 
+{
+    /*  Look for a $HOME/.yazclientrc and source it if it exists */
+    struct stat statbuf;
+    char buffer[1000];
+    char* homedir=getenv("HOME");
+
+    if( homedir ) {
+	
+	sprintf(buffer,"%s/.yazclientrc",homedir);
+
+	if(stat(buffer,&statbuf)==0) {
+	    cmd_source(buffer, 0 );
+	}
+	
+    };
+    
+    if(stat(".yazclientrc",&statbuf)==0) {
+        cmd_source(".yazclientrc", 0 );
+    }
+}
+
+
+void z_initialize(void)
+{
+    FILE *inf;
+    int i;
+    
+    if (!(out = odr_createmem(ODR_ENCODE)) ||
+        !(in = odr_createmem(ODR_DECODE)) ||
+        !(print = odr_createmem(ODR_PRINT)))
+    {
+        fprintf(stderr, "failed to allocate ODR streams\n");
+        exit(1);
+    }
+    oid_init();
+    
+    setvbuf(stdout, 0, _IONBF, 0);
+    if (apdu_file)
+        odr_setprint(print, apdu_file);
+
+    bibset = ccl_qual_mk (); 
+    inf = fopen (ccl_fields, "r");
+    if (inf)
+    {
+        ccl_qual_file (bibset, inf);
+        fclose (inf);
+    }
+
+    cqltrans = cql_transform_open_fname(cql_fields);
+    /* If this fails, no problem: we detect cqltrans == 0 later */
+
+#if HAVE_READLINE_READLINE_H
+    rl_attempted_completion_function = (CPPFunction*)readline_completer;
+#endif
+    
+    
+    for(i=0; i<maxOtherInfosSupported; ++i) {
+        extraOtherInfos[i].oidval = -1;
+    }
+    
+    source_rcfile();
+}
+
+
+#if HAVE_GETTIMEOFDAY
+struct timeval tv_start, tv_end;
+#endif
+
+#if HAVE_XML2
+static void handle_srw_record(Z_SRW_record *rec)
+{
+    if (rec->recordPosition)
+    {
+	printf ("pos=%d", *rec->recordPosition);
+	setno = *rec->recordPosition + 1;
+    }
+    if (rec->recordSchema)
+	printf (" schema=%s", rec->recordSchema);
+    printf ("\n");
+    if (rec->recordData_buf && rec->recordData_len)
+    {
+	fwrite(rec->recordData_buf, 1, rec->recordData_len, stdout);
+	if (marc_file)
+	    fwrite (rec->recordData_buf, 1, rec->recordData_len, marc_file);
+    }
+    else
+	printf ("No data!");
+    printf("\n");
+}
+
+static void handle_srw_explain_response(Z_SRW_explainResponse *res)
+{
+    handle_srw_record(&res->record);
+}
+
+static void handle_srw_response(Z_SRW_searchRetrieveResponse *res)
+{
+    int i;
+
+    printf ("Received SRW SearchRetrieve Response\n");
+    
+    for (i = 0; i<res->num_diagnostics; i++)
+    {
+	if (res->diagnostics[i].uri)
+	    printf ("SRW diagnostic %s\n",
+		    res->diagnostics[i].uri);
+	else
+	    printf ("SRW diagnostic missing or could not be decoded\n");
+	if (res->diagnostics[i].message)
+            printf ("Message: %s\n", res->diagnostics[i].message);
+	if (res->diagnostics[i].details)
+            printf ("Details: %s\n", res->diagnostics[i].details);
+    }
+    if (res->numberOfRecords)
+        printf ("Number of hits: %d\n", *res->numberOfRecords);
+    for (i = 0; i<res->num_records; i++)
+	handle_srw_record(res->records + i);
+}
+
+static void handle_srw_scan_term(Z_SRW_scanTerm *term)
+{
+    if (term->displayTerm)
+	printf("%s:", term->displayTerm);
+    else if (term->value)
+	printf("%s:", term->value);
+    else
+	printf("No value:");
+    if (term->numberOfRecords)
+	printf(" %d", *term->numberOfRecords);
+    if (term->whereInList)
+	printf(" %s", term->whereInList);
+    if (term->value && term->displayTerm)
+	printf(" %s", term->value);
+
+    strcpy(last_scan_line, term->value);
+    printf("\n");
+}
+
+static void handle_srw_scan_response(Z_SRW_scanResponse *res)
+{
+    int i;
+
+    printf ("Received SRW Scan Response\n");
+    
+    for (i = 0; i<res->num_diagnostics; i++)
+    {
+	if (res->diagnostics[i].uri)
+	    printf ("SRW diagnostic %s\n",
+		    res->diagnostics[i].uri);
+	else
+	    printf ("SRW diagnostic missing or could not be decoded\n");
+	if (res->diagnostics[i].message)
+            printf ("Message: %s\n", res->diagnostics[i].message);
+	if (res->diagnostics[i].details)
+            printf ("Details: %s\n", res->diagnostics[i].details);
+    }
+    if (res->terms)
+	for (i = 0; i<res->num_terms; i++)
+	    handle_srw_scan_term(res->terms + i);
+}
+
+static void http_response(Z_HTTP_Response *hres)
+{
+    int ret = -1;
+    const char *content_type = z_HTTP_header_lookup(hres->headers,
+                                                    "Content-Type");
+    const char *connection_head = z_HTTP_header_lookup(hres->headers,
+                                                       "Connection");
+    if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
+    {
+        Z_SOAP *soap_package = 0;
+        ODR o = odr_createmem(ODR_DECODE);
+        Z_SOAP_Handler soap_handlers[2] = {
+            {"http://www.loc.gov/zing/srw/", 0,
+             (Z_SOAP_fun) yaz_srw_codec},
+            {0, 0, 0}
+        };
+        ret = z_soap_codec(o, &soap_package,
+                           &hres->content_buf, &hres->content_len,
+                           soap_handlers);
+        if (!ret && soap_package->which == Z_SOAP_generic &&
+            soap_package->u.generic->no == 0)
+        {
+            Z_SRW_PDU *sr = soap_package->u.generic->p;
+            if (sr->which == Z_SRW_searchRetrieve_response)
+                handle_srw_response(sr->u.response);
+            else if (sr->which == Z_SRW_explain_response)
+                handle_srw_explain_response(sr->u.explain_response);
+            else if (sr->which == Z_SRW_scan_response)
+                handle_srw_scan_response(sr->u.scan_response);
+            else
+                ret = -1;
+        }
+        else if (soap_package && (soap_package->which == Z_SOAP_fault
+                          || soap_package->which == Z_SOAP_error))
+        {
+            printf ("HTTP Error Status=%d\n", hres->code);
+            printf ("SOAP Fault code %s\n",
+                    soap_package->u.fault->fault_code);
+            printf ("SOAP Fault string %s\n", 
+                    soap_package->u.fault->fault_string);
+	    if (soap_package->u.fault->details)
+		printf ("SOAP Details %s\n", 
+			soap_package->u.fault->details);
+        }
+        else
+            ret = -1;
+        odr_destroy(o);
+    }
+    if (ret)
+    {
+        if (hres->code != 200)
+        {
+	    printf ("HTTP Error Status=%d\n", hres->code);
+        }
+        else
+        {
+            printf ("Decoding of SRW package failed\n");
+        }
+        close_session();
+    }
+    else
+    {
+	if (!strcmp(hres->version, "1.0"))
+	{
+	    /* HTTP 1.0: only if Keep-Alive we stay alive.. */
+	    if (!connection_head || strcmp(connection_head, "Keep-Alive"))
+		close_session();
+	}
+	else 
+	{
+	    /* HTTP 1.1: only if no close we stay alive .. */
+	    if (connection_head && !strcmp(connection_head, "close"))
+		close_session();
+	}
+    }
+}
+#endif
+
+void wait_and_handle_response() 
+{
+    int reconnect_ok = 1;
+    int res;
+    char *netbuffer= 0;
+    int netbufferlen = 0;
+    Z_GDU *gdu;
+    
+    while(conn)
+    {
+        res = cs_get(conn, &netbuffer, &netbufferlen);
+        if (reconnect_ok && res <= 0 && protocol == PROTO_HTTP)
+        {
+            cs_close(conn);
+            conn = 0;
+            cmd_open(0);
+            reconnect_ok = 0;
+            if (conn)
+            {
+                char *buf_out;
+                int len_out;
+                
+                buf_out = odr_getbuf(out, &len_out, 0);
+                
+		do_hex_dump(buf_out, len_out);
+
+                cs_put(conn, buf_out, len_out);
+                
+                odr_reset(out);
+                continue;
+            }
+        }
+        else if (res <= 0)
+        {
+            printf("Target closed connection\n");
+            close_session();
+            break;
+        }
+        odr_reset(out);
+        odr_reset(in); /* release APDU from last round */
+        record_last = 0;
+        do_hex_dump(netbuffer, res);
+        odr_setbuf(in, netbuffer, res, 0);
+        
+        if (!z_GDU(in, &gdu, 0, 0))
+        {
+            FILE *f = ber_file ? ber_file : stdout;
+            odr_perror(in, "Decoding incoming APDU");
+            fprintf(f, "[Near %d]\n", odr_offset(in));
+            fprintf(f, "Packet dump:\n---------\n");
+            odr_dumpBER(f, netbuffer, res);
+            fprintf(f, "---------\n");
+            if (apdu_file)
+	    {
+                z_GDU(print, &gdu, 0, 0);
+		odr_reset(print);
+	    }
+            if (conn && cs_more(conn))
+                continue;
+	    break;
+        }
+        if (ber_file)
+            odr_dumpBER(ber_file, netbuffer, res);
+        if (apdu_file && !z_GDU(print, &gdu, 0, 0))
+        {
+            odr_perror(print, "Failed to print incoming APDU");
+            odr_reset(print);
+	    continue;
+        }
+        if (gdu->which == Z_GDU_Z3950)
+        {
+            Z_APDU *apdu = gdu->u.z3950;
+            switch(apdu->which)
+            {
+            case Z_APDU_initResponse:
+		// kjdon copying johnmcp
+		/* save session parameters for later use */
+		session_mem = odr_extract_mem(in);
+		session = apdu->u.initResponse;
+		// greenstone will call z_get_initResponse to get the info
+		// about what happened with the connection
+                //process_initResponse(apdu->u.initResponse);
+                break;
+            case Z_APDU_searchResponse:
+                process_searchResponse(apdu->u.searchResponse);
+                break;
+            case Z_APDU_scanResponse:
+                process_scanResponse(apdu->u.scanResponse);
+                break;
+            case Z_APDU_presentResponse:
+                print_refid (apdu->u.presentResponse->referenceId);
+                setno +=
+                    *apdu->u.presentResponse->numberOfRecordsReturned;
+                if (apdu->u.presentResponse->records)
+                    display_records(apdu->u.presentResponse->records);
+                else
+                    printf("No records.\n");
+                printf ("nextResultSetPosition = %d\n",
+                        *apdu->u.presentResponse->nextResultSetPosition);
+                break;
+            case Z_APDU_sortResponse:
+                process_sortResponse(apdu->u.sortResponse);
+                break;
+            case Z_APDU_extendedServicesResponse:
+                printf("Got extended services response\n");
+                process_ESResponse(apdu->u.extendedServicesResponse);
+                break;
+            case Z_APDU_close:
+                printf("Target has closed the association.\n");
+                process_close(apdu->u.close);
+                break;
+            case Z_APDU_resourceControlRequest:
+                process_resourceControlRequest
+                    (apdu->u.resourceControlRequest);
+                break;
+            case Z_APDU_deleteResultSetResponse:
+                process_deleteResultSetResponse(apdu->u.
+                                                deleteResultSetResponse);
+                break;
+            default:
+                printf("Received unknown APDU type (%d).\n", 
+                       apdu->which);
+                close_session ();
+            }
+        }
+#if HAVE_XML2
+        else if (gdu->which == Z_GDU_HTTP_Response)
+        {
+            http_response(gdu->u.HTTP_Response);
+        }
+#endif
+        if (conn && !cs_more(conn))
+            break;
+    } // while conn
+    if (conn)
+    {
+#if HAVE_GETTIMEOFDAY
+        gettimeofday (&tv_end, 0);
+#if 0
+        printf ("S/U S/U=%ld/%ld %ld/%ld",
+                (long) tv_start.tv_sec,
+                (long) tv_start.tv_usec,
+                (long) tv_end.tv_sec,
+                (long) tv_end.tv_usec);
+#endif
+        printf ("Elapsed: %.6f\n",
+                (double) tv_end.tv_usec / 1e6 + tv_end.tv_sec -
+                ((double) tv_start.tv_usec / 1e6 + tv_start.tv_sec));
+#endif
+    }
+    xfree (netbuffer);
+}
+
+
+int cmd_cclparse(const char* arg) 
+{
+    int error, pos;
+    struct ccl_rpn_node *rpn=NULL;
+    
+    
+    rpn = ccl_find_str (bibset, arg, &error, &pos);
+    
+    if (error) {
+        printf ("%*s^ - ", 3+strlen(last_cmd)+1+pos, " ");
+        printf ("%s\n", ccl_err_msg (error));
+    }
+    else
+    {
+        if (rpn)
+        {	
+            ccl_pr_tree(rpn, stdout); 
+        }
+    }
+    if (rpn)
+        ccl_rpn_delete(rpn);
+    
+    printf ("\n");
+    
+    return 0;
+}
+
+
+int cmd_set_otherinfo(const char* args)
+{
+    char oidstr[101], otherinfoString[101];
+    int otherinfoNo;
+    int sscan_res;
+    int oidval;
+    
+    sscan_res = sscanf (args, "%d %100[^ ] %100s", &otherinfoNo, oidstr, otherinfoString);
+    if (sscan_res==1) {
+        /* reset this otherinfo */
+        if(otherinfoNo>=maxOtherInfosSupported) {
+            printf("Error otherinfo index to large (%d>%d)\n",
+		   otherinfoNo,maxOtherInfosSupported);
+        }
+        extraOtherInfos[otherinfoNo].oidval = -1;
+        if (extraOtherInfos[otherinfoNo].value)
+	    free(extraOtherInfos[otherinfoNo].value);	 		
+        return 0;
+    }
+    if (sscan_res<3) {
+        printf("Error in set_otherinfo command \n");
+        return 0;
+    }
+    
+    if (otherinfoNo>=maxOtherInfosSupported) {
+        printf("Error otherinfo index to large (%d>%d)\n",
+	       otherinfoNo,maxOtherInfosSupported);
+    }
+    
+    oidval = oid_getvalbyname (oidstr);
+    if (oidval == -1 ) {
+        printf("Error in set_otherinfo command unknown oid %s \n",oidstr);
+        return 0;
+    }
+    extraOtherInfos[otherinfoNo].oidval = oidval;
+    if(extraOtherInfos[otherinfoNo].value) free(extraOtherInfos[otherinfoNo].value);
+    extraOtherInfos[otherinfoNo].value = strdup(otherinfoString);
+    
+    return 0;
+}
+
+int cmd_sleep(const char* args ) 
+{
+    int sec=atoi(args);
+    if( sec > 0 ) {
+#ifdef WIN32
+	Sleep(sec*1000);
+#else
+	sleep(sec);
+#endif
+	printf("Done sleeping %d seconds\n", sec);	
+    }
+    return 1;    
+}
+
+int cmd_list_otherinfo(const char* args)
+{
+    int i;	   
+    
+    if(strlen(args)>0) {
+        i = atoi(args);
+        if( i >= maxOtherInfosSupported ) {
+            printf("Error otherinfo index to large (%d>%d)\n",i,maxOtherInfosSupported);
+            return 0;
+        }
+
+        if(extraOtherInfos[i].oidval != -1) 
+            printf("  otherinfo %d %s %s\n",
+                   i,
+                   yaz_z3950_oid_value_to_str(
+                       (enum oid_value) extraOtherInfos[i].oidval,
+                       CLASS_RECSYN),
+                   extraOtherInfos[i].value);
+        
+    } else {		
+        for(i=0; i<maxOtherInfosSupported; ++i) {
+            if(extraOtherInfos[i].oidval != -1) 
+                printf("  otherinfo %d %s %s\n",
+                       i,
+                       yaz_z3950_oid_value_to_str(
+                           (enum oid_value) extraOtherInfos[i].oidval,
+                           CLASS_RECSYN),
+                       extraOtherInfos[i].value);
+        }
+        
+    }
+    return 0;
+}
+
+
+int cmd_list_all(const char* args) {
+    int i;
+    
+    /* connection options */
+    if(conn) {
+        printf("Connected to         : %s\n",last_open_command);
+    } else {
+        if(last_open_command) 
+            printf("Not connected to     : %s\n",last_open_command);
+        else 
+            printf("Not connected        : \n");
+        
+    }
+    if(yazProxy) printf("using proxy          : %s\n",yazProxy);		
+    
+    printf("auto_reconnect       : %s\n",auto_reconnect?"on":"off");
+    
+    if (!auth) {
+        printf("Authentication       : none\n");
+    } else {
+        switch(auth->which) {
+        case Z_IdAuthentication_idPass:
+            printf("Authentication       : IdPass\n"); 
+            printf("    Login User       : %s\n",auth->u.idPass->userId?auth->u.idPass->userId:"");
+            printf("    Login Group      : %s\n",auth->u.idPass->groupId?auth->u.idPass->groupId:"");
+            printf("    Password         : %s\n",auth->u.idPass->password?auth->u.idPass->password:"");
+            break;
+        case Z_IdAuthentication_open:
+            printf("Authentication       : psOpen\n");			
+            printf("    Open string      : %s\n",auth->u.open);	
+            break;
+        default:
+            printf("Authentication       : Unknown\n");
+        }
+    }
+    if (negotiationCharset)
+        printf("Neg. Character set   : `%s'\n", negotiationCharset);
+    
+    /* bases */
+    printf("Bases                : ");
+    for (i = 0; i<num_databaseNames; i++) printf("%s ",databaseNames[i]);
+    printf("\n");
+    
+    /* Query options */
+    printf("CCL file             : %s\n",ccl_fields);
+    printf("CQL file             : %s\n",cql_fields);
+    printf("Query type           : %s\n",query_type_as_string(queryType));
+    
+    printf("Named Result Sets    : %s\n",setnumber==-1?"off":"on");
+    
+    /* piggy back options */
+    printf("ssub/lslb/mspn       : %d/%d/%d\n",smallSetUpperBound,largeSetLowerBound,mediumSetPresentNumber);
+    
+    /* print present related options */
+    printf("Format               : %s\n",yaz_z3950_oid_value_to_str(recordsyntax,CLASS_RECSYN));
+    printf("Schema               : %s\n",record_schema ? record_schema : "not set");
+    printf("Elements             : %s\n",elementSetNames?elementSetNames->u.generic:"");
+    
+    /* loging options */
+    printf("APDU log             : %s\n",apdu_file?"on":"off");
+    printf("Record log           : %s\n",marc_file?"on":"off");
+    
+    /* other infos */
+    printf("Other Info: \n");
+    cmd_list_otherinfo("");
+    
+    return 0;
+}
+
+int cmd_clear_otherinfo(const char* args) 
+{
+    if(strlen(args)>0) {
+        int otherinfoNo;
+        otherinfoNo = atoi(args);
+        if( otherinfoNo >= maxOtherInfosSupported ) {
+            printf("Error otherinfo index to large (%d>%d)\n",otherinfoNo,maxOtherInfosSupported);
+            return 0;
+        }
+        
+        if(extraOtherInfos[otherinfoNo].oidval != -1) {			
+            /* only clear if set. */
+            extraOtherInfos[otherinfoNo].oidval=-1;
+            free(extraOtherInfos[otherinfoNo].value);
+        }
+    } else {
+        int i;
+	
+        for(i=0; i<maxOtherInfosSupported; ++i) {
+            if (extraOtherInfos[i].oidval!=-1 ) {				
+                extraOtherInfos[i].oidval=-1;
+                free(extraOtherInfos[i].value);
+            }
+        }
+    }
+    return 0;
+}
+
+static int cmd_help (const char *line);
+
+typedef char *(*completerFunctionType)(const char *text, int state);
+
+static struct {
+    char *cmd;
+    int (*fun)(const char *arg);
+    char *ad;
+    completerFunctionType rl_completerfunction;
+    int complete_filenames;
+    char **local_tabcompletes;
+} cmd_array[] = {
+    {"open", cmd_open, "('tcp'|'ssl')':<host>[':'<port>][/<db>]",NULL,0,NULL},
+    {"quit", cmd_quit, "",NULL,0,NULL},
+    {"find", cmd_find, "<query>",NULL,0,NULL},
+    {"delete", cmd_delete, "<setname>",NULL,0,NULL},
+    {"base", cmd_base, "<base-name>",NULL,0,NULL},
+    {"show", cmd_show, "<rec#>['+'<#recs>['+'<setname>]]",NULL,0,NULL},
+    {"scan", cmd_scan, "<term>",NULL,0,NULL},
+    {"scanstep", cmd_scanstep, "<size>",NULL,0,NULL},
+    {"scanpos", cmd_scanpos, "<size>",NULL,0,NULL},
+    {"scansize", cmd_scansize, "<size>",NULL,0,NULL},
+    {"sort", cmd_sort, "<sortkey> <flag> <sortkey> <flag> ...",NULL,0,NULL},
+    {"sort+", cmd_sort_newset, "<sortkey> <flag> <sortkey> <flag> ...",NULL,0,NULL},
+    {"authentication", cmd_authentication, "<acctstring>",NULL,0,NULL},
+    {"lslb", cmd_lslb, "<largeSetLowerBound>",NULL,0,NULL},
+    {"ssub", cmd_ssub, "<smallSetUpperBound>",NULL,0,NULL},
+    {"mspn", cmd_mspn, "<mediumSetPresentNumber>",NULL,0,NULL},
+    {"status", cmd_status, "",NULL,0,NULL},
+    {"setnames", cmd_setnames, "",NULL,0,NULL},
+    {"cancel", cmd_cancel, "",NULL,0,NULL},
+    {"cancel_find", cmd_cancel_find, "<query>",NULL,0,NULL},
+    {"format", cmd_format, "<recordsyntax>",complete_format,0,NULL},
+    {"schema", cmd_schema, "<schema>",complete_schema,0,NULL},
+    {"elements", cmd_elements, "<elementSetName>",NULL,0,NULL},
+    {"close", z_cmd_close, "",NULL,0,NULL},
+    {"attributeset", cmd_attributeset, "<attrset>",complete_attributeset,0,NULL},
+    {"querytype", cmd_querytype, "<type>",complete_querytype,0,NULL},
+    {"refid", cmd_refid, "<id>",NULL,0,NULL},
+    {"itemorder", cmd_itemorder, "ill|item <itemno>",NULL,0,NULL},
+    {"update", cmd_update, "<action> <recid> [<file>]",NULL,0,NULL},
+    {"update0", cmd_update0, "<action> <recid> [<file>]",NULL,0,NULL},
+    {"packagename", cmd_packagename, "<packagename>",NULL,0,NULL},
+    {"proxy", cmd_proxy, "[('tcp'|'ssl')]<host>[':'<port>]",NULL,0,NULL},
+    {"charset", cmd_charset, "<nego_charset> <output_charset>",NULL,0,NULL},
+    {"negcharset", cmd_negcharset, "<nego_charset>",NULL,0,NULL},
+    {"displaycharset", cmd_displaycharset, "<output_charset>",NULL,0,NULL},
+    {"marccharset", cmd_marccharset, "<charset_name>",NULL,0,NULL},
+    {"lang", cmd_lang, "<language_code>",NULL,0,NULL},
+    {".", cmd_source_echo, "<filename>",NULL,1,NULL},
+    {"!", cmd_subshell, "Subshell command",NULL,1,NULL},
+    {"set_apdufile", cmd_set_apdufile, "<filename>",NULL,1,NULL},
+    {"set_berfile", cmd_set_berfile, "<filename>",NULL,1,NULL},
+    {"set_marcdump", cmd_set_marcdump," <filename>",NULL,1,NULL},
+    {"set_cclfile", cmd_set_cclfile," <filename>",NULL,1,NULL},
+    {"set_cqlfile", cmd_set_cqlfile," <filename>",NULL,1,NULL},
+    {"set_auto_reconnect", cmd_set_auto_reconnect," on|off",complete_auto_reconnect,1,NULL},
+    {"set_otherinfo", cmd_set_otherinfo,"<otherinfoinddex> <oid> <string>",NULL,0,NULL},
+    {"sleep", cmd_sleep,"<seconds>",NULL,0,NULL},
+    {"register_oid", cmd_register_oid,"<name> <class> <oid>",NULL,0,NULL},
+    {"push_command", cmd_push_command,"<command>",command_generator,0,NULL},
+    {"register_tab", cmd_register_tab,"<commandname> <tab>",command_generator,0,NULL},
+    {"cclparse", cmd_cclparse,"<ccl find command>",NULL,0,NULL},
+    {"list_otherinfo",cmd_list_otherinfo,"[otherinfoinddex]",NULL,0,NULL},
+    {"list_all",cmd_list_all,"",NULL,0,NULL},
+    {"clear_otherinfo",cmd_clear_otherinfo,"",NULL,0,NULL},
+    /* Server Admin Functions */
+    /*    {"adm-reindex", cmd_adm_reindex, "<database-name>",NULL,0,NULL},
+    {"adm-truncate", cmd_adm_truncate, "('database'|'index')<object-name>",NULL,0,NULL},
+    {"adm-create", cmd_adm_create, "",NULL,0,NULL},
+    {"adm-drop", cmd_adm_drop, "('database'|'index')<object-name>",NULL,0,NULL},
+    {"adm-import", cmd_adm_import, "<record-type> <dir> <pattern>",NULL,0,NULL},
+    {"adm-refresh", cmd_adm_refresh, "",NULL,0,NULL},
+    {"adm-commit", cmd_adm_commit, "",NULL,0,NULL},
+    {"adm-shutdown", cmd_adm_shutdown, "",NULL,0,NULL},
+    {"adm-startup", cmd_adm_startup, "",NULL,0,NULL},*/
+    {"explain", cmd_explain, "", NULL, 0, NULL},
+    {"options", cmd_options, "", NULL, 0, NULL},
+    {"zversion", cmd_zversion, "", NULL, 0, NULL},
+    {"help", cmd_help, "", NULL,0,NULL},
+    {"init", cmd_init, "", NULL,0,NULL},
+    {0,0,0,0,0,0}
+};
+
+static int cmd_help (const char *line)
+{
+    int i;
+    char topic[21];
+    
+    *topic = 0;
+    sscanf (line, "%20s", topic);
+
+    if (*topic == 0)
+        printf("Commands:\n");
+    for (i = 0; cmd_array[i].cmd; i++)
+        if (*topic == 0 || strcmp (topic, cmd_array[i].cmd) == 0)
+            printf("   %s %s\n", cmd_array[i].cmd, cmd_array[i].ad);
+    if (strcmp (topic, "find") == 0)
+    {
+        printf ("RPN:\n");
+        printf (" \"term\"                        Simple Term\n");
+        printf (" @attr [attset] type=value op  Attribute\n");
+        printf (" @and opl opr                  And\n");
+        printf (" @or opl opr                   Or\n");
+        printf (" @not opl opr                  And-Not\n");
+        printf (" @set set                      Result set\n");
+        printf ("\n");
+        printf ("Bib-1 attribute types\n");
+        printf ("1=Use:         ");
+        printf ("4=Title 7=ISBN 8=ISSN 30=Date 62=Abstract 1003=Author 1016=Any\n");
+        printf ("2=Relation:    ");
+        printf ("1<   2<=  3=  4>=  5>  6!=  102=Relevance\n");
+        printf ("3=Position:    ");
+        printf ("1=First in Field  2=First in subfield  3=Any position\n");
+        printf ("4=Structure:   ");
+        printf ("1=Phrase  2=Word  3=Key  4=Year  5=Date  6=WordList\n");
+        printf ("5=Truncation:  ");
+        printf ("1=Right  2=Left  3=L&R  100=No  101=#  102=Re-1  103=Re-2\n");
+        printf ("6=Completeness:");
+        printf ("1=Incomplete subfield  2=Complete subfield  3=Complete field\n");
+    }
+    return 1;
+}
+
+int cmd_register_tab(const char* arg) {
+	
+    char command[101], tabargument[101];
+    int i;
+    int num_of_tabs;
+    char** tabslist;
+    
+    if (sscanf (arg, "%100s %100s", command, tabargument) < 1) {
+        return 0;
+    }
+    
+    /* locate the amdn in the list */
+    for (i = 0; cmd_array[i].cmd; i++) {
+        if (!strncmp(cmd_array[i].cmd, command, strlen(command))) {
+            break;
+        }
+    }
+    
+    if(!cmd_array[i].cmd) { 
+        fprintf(stderr,"Unknown command %s\n",command);
+        return 1;
+    }
+    
+        
+    if(!cmd_array[i].local_tabcompletes)
+        cmd_array[i].local_tabcompletes = (char **) calloc(1,sizeof(char**));
+    
+    num_of_tabs=0;		
+    
+    tabslist = cmd_array[i].local_tabcompletes;
+    for(;tabslist && *tabslist;tabslist++) {
+        num_of_tabs++;
+    }
+    
+    cmd_array[i].local_tabcompletes =  (char **)
+        realloc(cmd_array[i].local_tabcompletes,(num_of_tabs+2)*sizeof(char**));
+    tabslist=cmd_array[i].local_tabcompletes;
+    tabslist[num_of_tabs]=strdup(tabargument);
+    tabslist[num_of_tabs+1]=NULL;
+    return 1;
+}
+
+
+void process_cmd_line(char* line)
+{  
+    int i,res;
+    char word[32], arg[10240];
+    
+#if HAVE_GETTIMEOFDAY
+    gettimeofday (&tv_start, 0);
+#endif
+    
+    if ((res = sscanf(line, "%31s %10239[^;]", word, arg)) <= 0)
+    {
+        strcpy(word, last_cmd);
+        *arg = '\0';
+    }
+    else if (res == 1)
+        *arg = 0;
+    strcpy(last_cmd, word);
+    
+    /* removed tailing spaces from the arg command */
+    { 
+        char* p = arg;
+        char* lastnonspace=NULL;
+        
+        for(;*p; ++p) {
+            if(!isspace(*(unsigned char *) p)) {
+                lastnonspace = p;
+            }
+        }
+        if(lastnonspace) 
+            *(++lastnonspace) = 0;
+    }
+    
+    for (i = 0; cmd_array[i].cmd; i++)
+        if (!strncmp(cmd_array[i].cmd, word, strlen(word)))
+        {
+            res = (*cmd_array[i].fun)(arg);
+            break;
+        }
+    
+    if (!cmd_array[i].cmd) /* dump our help-screen */
+    {
+        printf("Unknown command: %s.\n", word);
+        printf("use help for list of commands\n");
+        /* cmd_help (""); */
+        res = 1;
+    }
+    
+    if(apdu_file) fflush(apdu_file);
+    
+    if (res >= 2)
+        wait_and_handle_response();
+    
+    if(apdu_file)
+        fflush(apdu_file);
+    if(marc_file)
+        fflush(marc_file);
+}
+
+
+char *command_generator(const char *text, int state) 
+{
+    static int idx; 
+    if (state==0) {
+        idx = 0;
+    }
+    for( ; cmd_array[idx].cmd; ++idx) {
+        if (!strncmp(cmd_array[idx].cmd,text,strlen(text))) {
+            ++idx;  /* skip this entry on the next run */
+            return strdup(cmd_array[idx-1].cmd);
+        }
+    }
+    return NULL;
+}
+
+
+/* 
+   This function only known how to complete on the first word
+*/
+char ** readline_completer(char *text, int start, int end) {
+#if HAVE_READLINE_READLINE_H
+
+	completerFunctionType completerToUse;
+	
+    if(start == 0) {
+#if HAVE_READLINE_RL_COMPLETION_MATCHES
+        char** res=rl_completion_matches(text,
+                                      command_generator); 
+#else
+        char** res=completion_matches(text,
+                                      (CPFunction*)command_generator); 
+#endif
+        rl_attempted_completion_over = 1;
+        return res;
+    } else {
+        char arg[10240],word[32];
+        int i=0 ,res;
+        if ((res = sscanf(rl_line_buffer, "%31s %10239[^;]", word, arg)) <= 0) {     
+            rl_attempted_completion_over = 1;
+            return NULL;
+        }
+        
+        for (i = 0; cmd_array[i].cmd; i++) {
+            if (!strncmp(cmd_array[i].cmd, word, strlen(word))) {
+                break;
+            }
+        }
+        
+        if(!cmd_array[i].cmd) return NULL;
+        
+        curret_global_list = cmd_array[i].local_tabcompletes;
+        
+        completerToUse = cmd_array[i].rl_completerfunction;
+        if(completerToUse==NULL)  /* if no pr. command completer is defined use the default completer */
+            completerToUse = default_completer;
+        
+        if(completerToUse) {
+#ifdef HAVE_READLINE_RL_COMPLETION_MATCHES
+            char** res=
+                rl_completion_matches(text,
+                                      completerToUse);
+#else
+            char** res=
+                completion_matches(text,
+                                   (CPFunction*)completerToUse);
+#endif
+            if(!cmd_array[i].complete_filenames) 
+                rl_attempted_completion_over = 1;
+            return res;
+        } else {
+            if(!cmd_array[i].complete_filenames) 
+                rl_attempted_completion_over = 1;
+            return 0;
+        }
+    }
+#else 
+    return 0;
+#endif 
+}
+
+
+static void client(void)
+{
+    char line[10240];
+
+    line[10239] = '\0';
+
+#if HAVE_GETTIMEOFDAY
+    gettimeofday (&tv_start, 0);
+#endif
+
+    while (1)
+    {
+        char *line_in = NULL;
+#if HAVE_READLINE_READLINE_H
+        if (isatty(0))
+        {
+            line_in=readline(C_PROMPT);
+            if (!line_in)
+                break;
+#if HAVE_READLINE_HISTORY_H
+            if (*line_in)
+                add_history(line_in);
+#endif
+            strncpy(line, line_in, 10239);
+            free (line_in);
+        }
+#endif 
+        if (!line_in)
+        {
+            char *end_p;
+            printf (C_PROMPT);
+            fflush(stdout);
+            if (!fgets(line, 10239, stdin))
+                break;
+            if ((end_p = strchr (line, '\n')))
+                *end_p = '\0';
+        }
+        process_cmd_line(line);
+    }
+}
+
+static void show_version(void)
+{
+    char vstr[20];
+
+    yaz_version(vstr, 0);
+    printf ("YAZ version: %s\n", YAZ_VERSION);
+    if (strcmp(vstr, YAZ_VERSION))
+	printf ("YAZ DLL/SO: %s\n", vstr);
+    exit(0);
+}
+
+/*
+int main(int argc, char **argv)
+{
+    char *prog = *argv;
+    char *open_command = 0;
+    char *auth_command = 0;
+    char *arg;
+    int ret;
+    
+#if HAVE_LOCALE_H
+    if (!setlocale(LC_CTYPE, ""))
+        fprintf (stderr, "setlocale failed\n");
+#endif
+#if HAVE_LANGINFO_H
+#ifdef CODESET
+    codeset = nl_langinfo(CODESET);
+#endif
+#endif
+    if (codeset)
+	outputCharset = xstrdup(codeset);
+    
+    ODR_MASK_SET(&z3950_options, Z_Options_search);
+    ODR_MASK_SET(&z3950_options, Z_Options_present);
+    ODR_MASK_SET(&z3950_options, Z_Options_namedResultSets);
+    ODR_MASK_SET(&z3950_options, Z_Options_triggerResourceCtrl);
+    ODR_MASK_SET(&z3950_options, Z_Options_scan);
+    ODR_MASK_SET(&z3950_options, Z_Options_sort);
+    ODR_MASK_SET(&z3950_options, Z_Options_extendedServices);
+    ODR_MASK_SET(&z3950_options, Z_Options_delSet);
+
+    while ((ret = options("k:c:q:a:b:m:v:p:u:t:Vxd:", argv, argc, &arg)) != -2)
+    {
+        switch (ret)
+        {
+        case 0:
+            if (!open_command)
+            {
+                open_command = (char *) xmalloc (strlen(arg)+6);
+                strcpy (open_command, "open ");
+                strcat (open_command, arg);
+            }
+	    else
+	    {
+		fprintf(stderr, "%s: Specify at most one server address\n",
+			prog);
+		exit(1);
+	    }
+            break;
+	case 'd':
+	    dump_file_prefix = arg;
+	    break;
+        case 'k':
+            kilobytes = atoi(arg);
+            break;
+        case 'm':
+            if (!(marc_file = fopen (arg, "a")))
+            {
+                perror (arg);
+                exit (1);
+            }
+            break;
+        case 't':
+            outputCharset = xstrdup(arg);
+            break;
+        case 'c':
+            strncpy (ccl_fields, arg, sizeof(ccl_fields)-1);
+            ccl_fields[sizeof(ccl_fields)-1] = '\0';
+            break;
+        case 'q':
+            strncpy (cql_fields, arg, sizeof(cql_fields)-1);
+            cql_fields[sizeof(cql_fields)-1] = '\0';
+            break;
+        case 'b':
+            if (!strcmp(arg, "-"))
+                ber_file=stderr;
+            else
+                ber_file=fopen(arg, "a");
+            break;
+        case 'a':
+            if (!strcmp(arg, "-"))
+                apdu_file=stderr;
+            else
+                apdu_file=fopen(arg, "a");
+            break;
+	case 'x':
+	    hex_dump = 1;
+	    break;
+        case 'p':
+            yazProxy=strdup(arg);
+            break;
+        case 'u':
+            if (!auth_command)
+            {
+                auth_command = (char *) xmalloc (strlen(arg)+6);
+                strcpy (auth_command, "auth ");
+                strcat (auth_command, arg);
+            }
+            break;
+        case 'v':
+            yaz_log_init(yaz_log_mask_str(arg), "", 0);
+            break;
+        case 'V':
+	    show_version();
+            break;
+        default:
+            fprintf (stderr, "Usage: %s [-m <marclog>] [ -a <apdulog>] "
+                     "[-b berdump] [-c cclfields] \n"
+		     "[-q cqlfields] [-p <proxy-addr>] [-u <auth>] "
+                     "[-k size] [-d dump] [-V] [<server-addr>]\n",
+                     prog);
+            exit (1);
+        }      
+    }
+    z_initialize();
+    if (auth_command)
+    {
+#ifdef HAVE_GETTIMEOFDAY
+        gettimeofday (&tv_start, 0);
+#endif
+        process_cmd_line (auth_command);
+#if HAVE_READLINE_HISTORY_H
+        add_history(auth_command);
+#endif
+        xfree(auth_command);
+    }
+    if (open_command)
+    {
+#ifdef HAVE_GETTIMEOFDAY
+        gettimeofday (&tv_start, 0);
+#endif
+        process_cmd_line (open_command);
+#if HAVE_READLINE_HISTORY_H
+        add_history(open_command);
+#endif
+        xfree(open_command);
+    }
+    client ();
+    exit (0);
+}
+*/
+/*
+ * Local variables:
+ * tab-width: 8
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=8 fdm=marker
+ * vim<600: sw=4 ts=8
+ */
+
+static int z_getAPDU (Z_APDU **ret_apdu) {
+    int res;
+
+    char *netbuffer= 0;
+    int netbufferlen = 0;
+    Z_APDU *apdu;
+    Z_GDU *gdu;
+    
+    if ((res = cs_get(conn, &netbuffer, &netbufferlen)) < 0) {
+	close_session();
+	perror("cs_get");
+	exit(1);
+    }
+    if (!res) {
+	printf("Target closed connection.\n");
+	close_session();
+	exit(1);
+    }
+    odr_reset(in); /* release APDU from last round */
+    record_last = 0;
+    do_hex_dump(netbuffer, res);
+    odr_setbuf(in, netbuffer, res, 0);
+    
+    if (!z_GDU(in, &gdu, 0, 0)) {
+	
+	odr_perror(in, "Decoding incoming APDU");
+	fprintf(stderr, "[Near %d]\n", odr_offset(in));
+	fprintf(stderr, "Packet dump:\n---------\n");
+	odr_dumpBER(stderr, netbuffer, res);
+	fprintf(stderr, "---------\n");
+	if (apdu_file) {
+	    z_GDU(print, &gdu, 0, 0);
+	    odr_reset(print);
+	}
+	xfree(netbuffer);
+	exit(1); /* was break */
+    }
+    xfree(netbuffer);
+    if (apdu_file && !z_GDU(print, &gdu, 0, 0)) {
+	
+	odr_perror(print, "Failed to print incoming APDU");
+	odr_reset(print);
+	return -1; /* was continue */
+    }
+    if (gdu->which == Z_GDU_Z3950) {
+        
+	Z_APDU *apdu = gdu->u.z3950;
+	(*ret_apdu)=apdu;
+	return 0;
+    }
+    /* else a differnet kind of response, which we don't handle */
+    return -1;
+}
+
+/* gets a generic response from the server */
+int z_getnextAPDU () {
+  Z_APDU *apdu;
+  apdu=NULL;
+  
+  z_getAPDU(&apdu);
+
+  switch(apdu->which) {
+      
+  case Z_APDU_initResponse:
+      // kjdon copying johnmcp
+      /* save session parameters for later use */
+      session_mem = odr_extract_mem(in);
+      session = apdu->u.initResponse;
+      // greenstone will call z_get_initResponse to get the info
+      // about what happened with the connection
+      //process_initResponse(apdu->u.initResponse);
+      break;
+  case Z_APDU_searchResponse:
+      process_searchResponse(apdu->u.searchResponse);
+      break;
+  case Z_APDU_scanResponse:
+      process_scanResponse(apdu->u.scanResponse);
+      break;
+  case Z_APDU_presentResponse:
+      print_refid (apdu->u.presentResponse->referenceId);
+      setno +=
+	  *apdu->u.presentResponse->numberOfRecordsReturned;
+      if (apdu->u.presentResponse->records) {
+	  display_records(apdu->u.presentResponse->records);
+	  printf ("nextResultSetPosition = %d\n",
+		  *apdu->u.presentResponse->nextResultSetPosition);
+      }
+      else {
+	  printf("No records.\n");
+      }
+      break;
+  case Z_APDU_sortResponse:
+      process_sortResponse(apdu->u.sortResponse);
+      break;
+  case Z_APDU_extendedServicesResponse:
+      printf("Got extended services response\n");
+      process_ESResponse(apdu->u.extendedServicesResponse);
+      break;
+  case Z_APDU_close:
+      printf("Target has closed the association.\n");
+      process_close(apdu->u.close);
+      break;
+  case Z_APDU_resourceControlRequest:
+      process_resourceControlRequest
+	  (apdu->u.resourceControlRequest);
+      break;
+  case Z_APDU_deleteResultSetResponse:
+      process_deleteResultSetResponse(apdu->u.
+				      deleteResultSetResponse);
+      break;
+  default:
+      printf("Received unknown APDU type (%d).\n", 
+	     apdu->which);
+      close_session ();
+  }
+  return 0;
+ 
+}
+
+/* returns number of records found */
+/*int z_cmd_dosearch(char *search){
+
+}
+*/
+/* returns an array of strings containing record titles. The first element
+   is an int, saying how many titles follow (can be zero). NULL on error. */
+/*char **z_getrecordTitles(int start,int count){
+
+}
+*/
+/* returns a string containing the whole marc record */
+/*char *z_getfullRecord(int record){
+
+}
+*/
+
+
+/* returns number found, arg is query string */
+int z_cmd_dosearch(char *arg)
+{
+  Z_APDU *apdu;
+  int matching;
+  int ret_val;
+  ret_val=send_searchRequest(arg);
+  if (ret_val==-1) {
+    /* prefix query error */
+    return (-1);
+  }
+  z_getAPDU(&apdu);
+  /* check return value??? */
+  if (apdu->which != Z_APDU_searchResponse)
+    {
+      printf("sendsearchRequest() was not replied with a searchResponse!\n");
+      return (-2);
+    }
+  /* let's keep going anyway... */
+  matching=process_searchResponse(apdu->u.searchResponse);
+  /* this assumes we want to take action on failure (-1) here rather than
+     whereever we were called from */
+  return (matching);
+}
+
+/* src must be NULL-terminated */
+static char *safeappendstr(char *dest, size_t *allocsize, 
+			  size_t *offset, char *src) {
+  /* allocsize is the amount of space currently allocated to dest,
+     offset is how far into dest we want to append src */
+  if (*offset + strlen(src) >= *allocsize) {
+    *allocsize+=strlen(src)+64; /* add some extra space to save on reallocs */
+    if ((dest=realloc(dest,*allocsize))==NULL) {
+      fprintf(stderr, "malloc failed while decoding marc record.\n");
+      return (NULL);
+    }
+  }
+  strcpy(dest+(*offset), src);
+  *offset+=strlen(src);
+  return (dest);
+}
+
+static char *getmarcfields(Z_External *p, int titleonly) {
+  /* this code is based on marc_display(), with a couple of lines taken from
+     display_record() in the original client. */
+  /* if titleonly is non-zero, we only get a (the?) title field, otherwise
+     return the whole thing */
+  const char *buf=(char *)p->u.octet_aligned->buf;
+  char *title;      /* our string to return */
+  int title_maxlen=0; /* amount of space currently allocated */
+  int title_curlen=0;    /* amount of space actually used */
+  int entry_p;
+  int record_length;
+  int indicator_length;
+  int identifier_length;
+  int base_address;
+  int length_data_entry;
+  int length_starting;
+  int length_implementation;
+  FILE *outf;
+
+  /*  if (!outf) */
+  outf = stdout;
+
+  /* initialise our title. Start with 64 chars */
+  title_maxlen=64;
+  if((title=malloc(title_maxlen))==NULL) {
+    /* not quite sure where stderr will be going, but.... */
+    fprintf(stderr,"Malloc failed while decoding marc record\n");
+    return NULL;
+  }
+
+  if (!titleonly) {
+    strcpy(title,"<table border=1>\n");
+    title_curlen=strlen(title);
+  }
+  else  title_curlen=0;
+
+  record_length = atoi_n (buf, 5);
+  if (record_length < 25)
+    return (NULL); /* -1 */
+  if (isdigit(buf[10]))
+    indicator_length = atoi_n (buf+10, 1);
+  else
+    indicator_length = 2;
+  if (isdigit(buf[11]))
+    identifier_length = atoi_n (buf+11, 1);
+  else
+    identifier_length = 2;
+  base_address = atoi_n (buf+12, 4);
+  
+  length_data_entry = atoi_n (buf+20, 1);
+  length_starting = atoi_n (buf+21, 1);
+  length_implementation = atoi_n (buf+22, 1);
+  
+  if (0) /* debug */
+    {
+      fprintf (outf, "Record length         %5d\n", record_length);
+      fprintf (outf, "Indicator length      %5d\n", indicator_length);
+      fprintf (outf, "Identifier length     %5d\n", identifier_length);
+      fprintf (outf, "Base address          %5d\n", base_address);
+      fprintf (outf, "Length data entry     %5d\n", length_data_entry);
+      fprintf (outf, "Length starting       %5d\n", length_starting);
+      fprintf (outf, "Length implementation %5d\n", length_implementation);
+    }
+  for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
+    {
+      entry_p += 3+length_data_entry+length_starting;
+      if (entry_p >= record_length)
+	return (NULL); /* -1 */
+    }
+  base_address = entry_p+1;
+  for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
+    {
+      int data_length;
+      int data_offset;
+      int end_offset;
+      int i /*, j*/ ;
+      int startofstring;
+      int whichtag;
+      short int abbrtitle=0;
+      char tag[4];
+      memcpy (tag, buf+entry_p, 3);
+      entry_p += 3;
+      tag[3] = '\0';
+      whichtag=atoi(tag);
+      if (0) /* debug */
+	fprintf (outf, "Tag: ");
+      /* johnmcp 
+	 Relevant tags (for "main entry") - assume only one of these is set,
+	 as we will only return the first one found.
+	 100=personal name
+	 110=corporate name
+	 111=meeting name
+	 130=uniform title
+	 subfields: $a=personal name, $c=title/other, $d=date
+
+	 210=Abbreviated Title
+	 222=Key title
+	 240=uniform title
+	 243=collective uniform title
+	 245=title statement
+	 246=varying form of title
+	 247=former title or title variations
+	 subfields: $a=abbrev. title $b=qualifying info $2=source
+	 .          $6=linkage $8=link field and sequence number.
+      */
+      /*fprintf (outf, "%s ", tag); */
+      data_length = atoi_n (buf+entry_p, length_data_entry);
+      entry_p += length_data_entry;
+      data_offset = atoi_n (buf+entry_p, length_starting);
+      entry_p += length_starting;
+      i = data_offset + base_address;
+      end_offset = i+data_length-1;
+
+      if (0) /* debug */
+	fprintf (outf, " Ind: ");
+
+      /* memcmp (tag,"00",2) is true, then we DON'T have a control tag
+	 ie less than 10. */
+      /*if (memcmp (tag, "00", 2) && indicator_length)
+	{
+	for (j = 0; j<indicator_length; j++)
+	fprintf (outf, "%c", buf[i++]);
+	}
+      */
+      if (whichtag>=10) i+=indicator_length;
+      /* the control fields (<10) don't have leading chars. */
+
+
+      if (0) /* debug */
+	fprintf (outf, " Fields: ");
+
+      /* If we only want the title, then skip other fields */
+      if (titleonly &&(whichtag<200||whichtag>249)) {
+	/* skip this record */
+	continue;
+	i=end_offset;
+      }
+      
+      /* either titleonly is 0, or titleonly is 1 and whichtag is between
+	 200 and 249... */
+      if (!titleonly) {
+	/* This should probably be read in from a separate file.
+	   This is also hard-coded for USMARC/MARC21 fieldnames!!! */
+
+	/* print out what kind of tag this is */
+	char *tagname;
+	char *field_control1="<tr><td>Marc Control Number:</td><td>";
+	char *field_control3="<tr><td>Marc Organisation Code:</td><td>";
+	char *field_control5="<tr><td>Marc record Date Info.:</td><td>";
+	char *field_control8="<tr><td>Control Field (Marc info):</td><td>";
+	char *field_loc_nr="<tr><td>Lib. of Congress control #:</td><td>";
+	char *field_issn="<tr><td>ISSN Number:</td><td>";
+	char *field_catalog="<tr><td>Catalog agency:</td><td>";
+	char *field_lang="<tr><td>3-letter language code(s):</td><td>";
+	char *field_areacode="<tr><td>Geographic Area code:</td><td>";
+	char *field_cn_loc="<tr><td>Lib. of Congress Call #:</td><td>";
+	char *field_cn_dewdec="<tr><td>Dewey Decimal Call #:</td><td>";
+	char *field_cn_other="<tr><td>Other Classification Info.:</td><td>";
+	char *field_cn_gd="<tr><td>Govt. Document Call #:</td><td>";
+	char *field_personalname="<tr><td>Personal Name:</td><td>";
+	char *field_meetingname="<tr><td>Meeting Name:</td><td>";
+	char *field_maintitle="<tr><td>Title:</td><td>";
+	char *field_edition="<tr><td><Edition Information:</td><td>";
+	char *field_publication="<tr><td>Publication Info.:</td><td>";
+	char *field_physdesc="<tr><td>Physical Description:</td><td>";
+	char *field_series_title="<tr><td>Series Title:</td><td>";
+	char *field_series_statement="<tr><td>Series Statement:</td><td>";
+	char *field_note_general="<tr><td>Note:</td><td>";
+	char *field_note_bib="<tr><td>Bibliographic Note:</td><td>";
+	char *field_note_summary="<tr><td>Summary Note:</td><td>";
+	char *field_sub_note="<tr><td>Subject Notes:</td><td>";
+	char *field_sub_topic="<tr><td>Subject - Topic:</td><td>";
+	char *field_sub_geog="<tr><td>Subject - Location:</td><td>";
+	char *field_added_persname="<tr><td>Author Note - Name:</td><td>";
+	char *field_added_corpname="<tr><td>Author - Organisation:</td><td>";
+	char *field_uniform_title="<tr><td>Extra Title Information:</td><td>";
+	char *field_host_item="<tr><td>In:</td><td>";
+	char *field_series_corpname="<tr><td>Series - Organisation:</td><td>";
+	/*char *field_url="<tr><td>Electronic Access</td><td><a href=\"";*/
+	char *field_url="<tr><td>Electronic Access</td><td>";
+	/*char *field_other="<tr><td>(other field):</td><td>";*/
+	char tag_num[100];
+	switch (whichtag) {
+	case (1): {tagname=field_control1;break;}
+	case (3): {tagname=field_control3;break;}
+	case (5): {tagname=field_control5;break;}
+	case (8): {tagname=field_control8;break;}
+	case (10): {tagname=field_loc_nr;break;}
+	case (20): {tagname=field_issn;break;}
+	case (40): {tagname=field_catalog;break;}
+	case (41): {tagname=field_lang;break;}
+	case (43): {tagname=field_areacode;break;}
+	case (50): {tagname=field_cn_loc;break;}
+	case (82): {tagname=field_cn_dewdec;break;}
+	case (84): {tagname=field_cn_other;break;}
+	case (86): {tagname=field_cn_gd;break;}
+	case (100): {tagname=field_personalname;break;}
+	case (111): {tagname=field_meetingname;break;}
+	case (245): {tagname=field_maintitle;break;}
+	case (250): {tagname=field_edition;break;}
+	case (260): {tagname=field_publication;break;}
+	case (300): {tagname=field_physdesc;break;}
+	case (440): {tagname=field_series_title;break;}
+	case (490): {tagname=field_series_statement;break;}
+	case (500): {tagname=field_note_general;break;}
+	case (504): {tagname=field_note_bib;break;}
+	case (520): {tagname=field_note_summary;break;}
+	case (630): {tagname=field_sub_note;break;}
+	case (650): {tagname=field_sub_topic;break;}
+	case (651): {tagname=field_sub_geog;break;}
+	case (700): {tagname=field_added_persname;break;}
+	case (710): {tagname=field_added_corpname;break;}
+	case (730): {tagname=field_uniform_title;break;}
+	case (773): {tagname=field_host_item;break;}
+	case (810): {tagname=field_series_corpname;break;}
+	case (856): {tagname=field_url;break;}
+	default: 
+	  if (whichtag>=90&&whichtag<=99)
+	    tagname="<tr><td>Local Call #:</td><td>";
+	  else {
+	    /*tagname=field_other;*/
+	    
+	    /* The trailing '\0' seems to be necessary...?!? */
+	    sprintf(tag_num,"<tr><td>(field %d)</td><td>\n\0",whichtag);
+	    tagname=tag_num;
+	  }
+	}
+
+	/* add the field type */
+	title=safeappendstr(title, &title_maxlen, &title_curlen, tagname);
+      }
+
+      /* go through current field in current record */
+      while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
+	{
+	  /* this loop goes through byte by byte, to find end-of-field or
+	     end-of-record separator tags */
+
+	  /*	  if (memcmp (tag, "00", 2) && identifier_length)*/
+	  if ( ((titleonly==1&&whichtag==245)||(titleonly==0))
+	       && identifier_length)
+	    {
+	      if (buf[i]==ISO2709_IDFS) {
+		/*  this implies sub-fields for this field */
+		/* skip sub-field tag, but wrap $a sub-field with <b> & </b> 
+		   for HTML if titleonly==1 */
+		if (buf[i+1]=='a' && titleonly) {
+		  abbrtitle=1;
+		  title=safeappendstr(title,&title_maxlen,&title_curlen,"<b>");
+		}
+		i+=identifier_length; 
+	      }
+	      /* find end of this (sub-)field */
+	      startofstring=i;
+	      while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
+		     buf[i] != ISO2709_FS && i < end_offset)
+		i++;
+		/*fprintf (outf, "%c", buf[i++]);*/
+
+	      /* this only happens the first time around */
+	      if (i==startofstring) continue;
+
+	      /* now put from $startofstring$ until $i$ into our 
+		 string to return */
+
+	      if (title_curlen+(i-startofstring)>=title_maxlen) {
+		/* we need to make more room - add max(64,needed) bytes */
+		if (title_curlen+(i-startofstring)-title_maxlen>63)
+		  title_maxlen+=(i-startofstring)+1;/*+1 for trailing \0 */
+		else
+		  title_maxlen+=64;
+		if ((title=realloc(title,title_maxlen))==NULL) {
+		  fprintf(stderr,"malloc failed decoding marc record\n");
+		  return (NULL);
+		}
+	      }
+
+	      strncpy(title+title_curlen,buf+startofstring,i-startofstring);
+	      title_curlen+=(i-startofstring);
+	      *(title+title_curlen)='\0';
+	      /* overwrite ISO2709_?S with \0 */
+	      /* *(title+title_curlen+i-startofstring)='\0';*/
+	      /*safeappendstr(title,&title_maxlen,
+		&title_curlen,buf+startofstring);*/
+
+	      /* if 'main' title, close HTML </B> tag */
+	      if (abbrtitle) {
+		title=safeappendstr(title,&title_maxlen,&title_curlen,"</b>");
+		abbrtitle=0;
+	      } 
+	      /* end of this marc sub--field                 
+		 buf[i]==ISO2709_RS if end of  record.
+		 buf[i]==ISO2709_FS if end of  field,
+		 buf[i]==ISO2709_IDFS if end of sub-field. */
+	      if (titleonly==0) {
+		if (buf[i]==ISO2709_IDFS) {
+		  /* there is a following sub-field, so only add whitespace */
+		  title=safeappendstr(title,&title_maxlen,&title_curlen," ");
+		}
+		else {
+		  /* end of record, so close HTML table row */
+#if 0
+		  if (whichtag==856) /* special case: this is a url! */
+		    title=safeappendstr(title,&title_maxlen,&title_curlen,
+					"\">Uniform Resource Locator</a>");
+#endif
+		  title=safeappendstr(title, &title_maxlen, &title_curlen,
+				      "</td></tr>\n");
+		}
+	      }  /* end of  if (titleonly==0)                */
+	    }    /* end of  if ( ((titleonly==1&&.......     */
+	  else { /* whichtag not matched  (if titleonly)     */
+	    /*fprintf (outf, "%c", buf[i++]);*/
+	    /* skip this char for now - should ideally skip whole field */
+	    i++;
+	  }
+	} /* end of while loop - at end of field or record */
+      /*fprintf (outf, "\n");*/
+      /*if (i < end_offset)
+	fprintf (outf, "-- separator but not at end of field\n");
+	if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
+	fprintf (outf, "-- no separator at end of field\n");
+      */
+    }
+
+  /* at end of whole record. */
+  if (!titleonly) 
+    title=safeappendstr(title, &title_maxlen, &title_curlen, "</table>\n");
+  return (title);
+
+}
+static char *getrecordtitle(Z_External *record) {
+  return(getmarcfields(record,1));
+}
+
+char *z_getfullRecord(int start) {
+  Z_APDU *apdu;
+  Z_External *record;
+  char *fullrecord;
+
+  fullrecord=NULL;
+  z_send_getbriefrecords(start,1,1); /* for now, use getbriefrecords */
+  z_getAPDU(&apdu);
+  
+  if (apdu->which != Z_APDU_presentResponse) {
+    /* out-of-order packets.... */
+    fprintf(stderr,"Not a present response to present request\n");
+    return NULL;
+  }
+  
+  /* just do some double checking */
+  if (*apdu->u.presentResponse->numberOfRecordsReturned!=1 ||
+      !apdu->u.presentResponse->records ) {
+    /* something bad has happened... johnmcp */
+    fprintf (stderr,"Error occured in yaz while getting record (GSDL)\n");
+  }
+
+  switch (apdu->u.presentResponse->records->which) {
+  case Z_Records_DBOSD: break; /* do nothing - this is a record */
+
+    /* otherwise we got a diagnostic message... */
+  case Z_Records_NSD:
+    switch (apdu->u.presentResponse->records->u.nonSurrogateDiagnostic->which){
+      /* these are both represented as char* in yaz, so either is OK */
+      /*    case Z_DefaultDiagForm_v2Addinfo:
+	    case Z_DefaultDiagForm_v3Addinfo: --wrong names*/
+    case Z_DiagnosticFormat_s_defaultDiagRec:
+    case Z_DiagnosticFormat_s_explicitDiagnostic:
+      return apdu->u.presentResponse->records->u.nonSurrogateDiagnostic
+	->u.v2Addinfo; /* return the error message */
+    default: ; /* this should happen for v3 of the spec... */
+    }
+  case Z_Records_multipleNSD: ; /* should handle one day... */
+  }
+
+  record=apdu->u.presentResponse->records->u.databaseOrSurDiagnostics->
+    records[0]->u.databaseRecord;
+
+  return(getmarcfields(record,0));
+}
+
+char **z_getrecordTitles(/*int resultset,*/ int starting, int howmany) {
+  Z_APDU *apdu;
+  char **titles;
+  /* titles will be an array of strings. The first element will really
+     be an int, saying how many strings follow. Ie 1st string in titles[1] */
+  int count;
+  int i;
+
+  titles=NULL;
+
+  /* WE SHOULD SET THE RECORD FORMAT SOMEWHERE..... USMARC (default)
+     but may also want SUTRS support. */
+
+  /* sends a presentRequest - we need to know the set number - johnmcp */
+  z_send_getbriefrecords(starting, 1, howmany);
+  /* CHECK RETURN VALUE (currently only 0) */
+  
+
+  z_getAPDU(&apdu);
+  if (apdu->which != Z_APDU_presentResponse) {
+    /* we got out-of-sync.... */
+    fprintf(stderr,"Not a present response to present request\n");
+    return NULL;
+  }
+  
+  print_refid (apdu->u.presentResponse->referenceId);
+  count=*apdu->u.presentResponse->numberOfRecordsReturned;
+  setno += count;
+  if (apdu->u.presentResponse->records) {
+    /* extract the titles from each record, and return it as an array of 
+       strings */
+    if (count==1 &&
+	apdu->u.presentResponse->records->which!=Z_Records_DBOSD) {
+	fprintf(stderr,"only one returned");
+      /* apdu->u.presentResponse->records->which gives a type:
+	 1=databaseOrSurDiagnostics | 2=nonSurrogateDiagnostic | 
+	 3=multipleNonSurDiagnostics.
+	 Type 1 implies it is a database record. FROM z-core.h,
+      NOT prt-proto.h!!!!! */
+
+      /* for type 2:
+	 apdu->u.presentResponse->records->u.nonSurrogateDiagnostic->which:
+	 1=v2Addinfo | 2=v3Addinfo, and u.v[23]Addinfo is a (char *).
+
+      */
+      titles=malloc(sizeof(char *));
+      titles[0]=(char *)0;
+      /* could put error message and titles[1], and set titles[0] to -1. */
+
+
+    }
+    else /* more than 1 rec returned, so ?has? to be db records (dblcheck!!)*/
+      {
+	  fprintf(stderr,"more than one rec returned, count=%d\n", count);
+	titles=malloc(sizeof(char *)*count + 1);
+	/* check malloc succeeded... */
+	titles[0]=(char *)count;
+	for (i=1;i<=count;i++) {
+	  titles[i]=getrecordtitle(apdu->u.presentResponse->records->
+				   u.databaseOrSurDiagnostics->records[i-1]->
+				   u.databaseRecord);
+	}
+      } 
+  }
+  else {
+      fprintf(stderr,"no records retruend");
+    titles=malloc(sizeof(char *));
+    titles[0]=(char *)0;
+  }
+  /*  printf ("nextResultSetPosition = %d\n",
+   *apdu->u.presentResponse->nextResultSetPosition); */
+  return (titles);
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/yaz_zclient.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/yaz_zclient.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/yaz_zclient.h	(revision 10506)
@@ -0,0 +1,32 @@
+#ifndef YAZ_ZCLIENT_H
+#define YAZ_ZCLIENT_H
+/*#include "../include/yaz/z-core.h"*/
+
+
+/* the new yaz_zclient made for use with Greenstone. Based on client.c 
+ * (version 2.1.4) and the old yaz_zclient (version 1.6 for greenstone)
+ */
+void z_initialize(void);
+
+/* creates a connection, given a host and port, and database name */
+int z_cmd_open(char *host_and_port, char *base);
+
+/* returns number of records found */
+int z_cmd_dosearch(char *search);
+
+/* returns an array of strings containing record titles. The first element
+   is an int, saying how many titles follow (can be zero). NULL on error. */
+char **z_getrecordTitles(int start,int count);
+
+/* returns a string containing the whole marc record */
+char *z_getfullRecord(int record);
+
+/* close the connection */
+int z_cmd_close(const char *arg);
+
+/* returns a string containing name, ID, etc, or NULL if not connected */
+char *z_get_initResponse(); 
+
+/* gets a generic response from the server */
+int z_getnextAPDU ();
+#endif 
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950cfg.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950cfg.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950cfg.h	(revision 10506)
@@ -0,0 +1,28 @@
+/*
+  This defines a data structure shared between:
+  * the C++ z3950proto class defined in z3950proto.cpp, and
+  * the C function yyparse() created by bison from the file zparse.fl
+  */
+
+#ifndef _Z3950CFG_H
+#define _Z3950CFG_H
+
+struct z3950aboutlist {
+  char *lang;
+  char *text;
+  struct z3950aboutlist *next;
+};
+struct z3950cfg {
+  char *shortname;
+  char *hostname;
+  int port;
+  char *dbname;
+  char *longname;
+  char *icon;
+  char *smallicon;
+  struct z3950aboutlist *about;
+  struct z3950cfg *next;
+};
+extern struct z3950cfg *zserver_list;
+extern FILE *errfile;
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proto.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proto.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proto.cpp	(revision 10506)
@@ -0,0 +1,618 @@
+/**********************************************************************
+ *
+ * z3950proto.cpp --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "z3950proto.h"
+#include "comtypes.h"
+#include "browsefilter.h"
+#include "queryfilter.h"
+#include "filter.h"
+// z39.50 yaz stuff
+#include <stdio.h> // for (FILE *) type for yyin and fopen.
+// config file parsing stuff
+extern "C" {
+#include "z3950cfg.h" // for reading in config files - 
+// defines "struct z3950cfg *zserver_list" as the head of the list.
+}
+// note! yyin is hash-defined in z3950cfg.h to something else, to avoid
+// name conflicts with "other" yyins.
+//extern "C" {
+FILE *yyin;
+FILE *yyout; // redirect for `errors' (unmatched tokens in flex)
+//}
+extern "C" {
+  extern int zconfigparse();
+}
+
+
+
+
+z3950proto::z3950proto() {
+  zserver_count=0;
+}
+
+z3950proto::~z3950proto() {
+}
+
+void z3950proto::add_server (z3950_proxy& zserver) {
+
+  // append the new server
+  ++zserver_count;
+  zservers.push_back(&zserver);
+}
+
+void z3950proto::read_config_file(const text_t &filename, const text_t &errf) {
+  struct z3950cfg *here;
+  struct z3950cfg *oldhere;
+  z3950_proxy *zserver;
+  ShortColInfo_t *tempinfo;
+
+  //  FILE *errfile declared in z3950cfg.h, defined in zparse.y
+
+  char *errf_str=errf.getcstr();
+  if ((errfile=fopen(errf_str,"a"))==NULL) {
+    // what do we do if we can't open the error file?
+    // this means that errors will go to stderr, which may stuff up 
+    // any cgi headers and the page.
+    errfile=stderr;
+  }
+  delete []errf_str;
+  yyout=errfile;
+
+  // zconfigparse() is defined in zparse.tab.c,
+  // which is the bison output of zparse.y
+  
+  char *filename_str=filename.getcstr();
+  yyin=fopen(filename_str,"r");
+  if (yyin==NULL) {
+    cerr << "Could not open "<<filename_str<<" for reading.\n";
+    delete []filename_str;
+    return;
+  }
+  delete []filename_str;
+  zconfigparse();
+
+  if (errfile!=stderr)
+    fclose(errfile);
+
+  // we now have the config files in the ptr zserver_list
+  if (zserver_list==NULL)
+    return; // no valid servers found in the config file - note that
+  // the parser will have already spat out any errors.
+
+  // now create z3950 proxies for each structure in server_list
+  here=zserver_list;
+  while (here!=NULL) {
+    zserver=new z3950_proxy;
+    tempinfo=new ShortColInfo_t;
+
+    tempinfo->host.setcstr(here->hostname);
+    tempinfo->port=here->port;
+    tempinfo->name.setcstr(here->dbname);
+    zserver->setInfo(tempinfo);
+    zserver->setName(here->shortname);
+    // now collection metadata.
+    zserver->setMeta("collectionname",here->longname);
+    if (here->icon!=NULL)
+      zserver->setMeta("iconcollection",here->icon);
+    if (here->smallicon!=NULL)
+      zserver->setMeta("iconcollectionsmall",here->smallicon);
+    
+    /*    filterclass *filter = new filterclass ();
+	  zserver->add_filter (filter);
+	  browsefilterclass *browsefilter = new browsefilterclass();
+	  zserver->add_filter (browsefilter);
+	  queryfilterclass *queryfilter = new queryfilterclass();
+	  zserver->add_filter (queryfilter);
+    */
+
+    // About list
+    if (here->about!=NULL) {
+      struct z3950aboutlist *about_here=here->about;
+      struct z3950aboutlist *oldabout;
+
+      while (about_here!=NULL) {
+	// problem with default lang (null): can't add ("",..)
+	if (about_here->lang==NULL)
+	  zserver->addcfgAbout("en",about_here->text);
+	else
+	  zserver->addcfgAbout(about_here->lang, about_here->text);
+	oldabout=about_here;
+	about_here=about_here->next;
+	free(oldabout->lang);
+	free(oldabout->text);
+	free(oldabout);
+      }
+    }
+
+    oldhere=here;
+    here=here->next;
+    free(oldhere->shortname); // these 4 strings should all be non-NULL...
+    free(oldhere->hostname);
+    free(oldhere->dbname);
+    free(oldhere->longname);
+    if (oldhere->icon) free(oldhere->icon);     // these 2 may be NULL
+    if (oldhere->smallicon) free(oldhere->smallicon);
+    free(oldhere);
+
+    add_server(*zserver);
+  } // end of while loop.
+
+}
+
+void z3950proto::configure (const text_t &/*key*/,
+			    const text_tarray &/*cfgline*/) {
+  // this is called for each line in the gsdlsite.cfg file
+}
+
+
+bool z3950proto::init (ostream &/*logout*/) {
+  // set up tcp connection to server here?
+  // we might also read in the config file here (instead of librarymain.cpp)
+
+  // 
+
+  // logout goes to initout.txt
+  //  logout <<"zdebug:init:Number of z3950 servers: "<< zserver_count << "\n";
+  //logout << "\t1st server name: " << zservers[0].getName().getcstr() << "\n";
+  return true;
+
+}
+
+/*text_t z3950proto::get_protocol_name () {
+  return "z3950proto";
+}
+*/
+
+void z3950proto::get_collection_list (text_tarray &collist, 
+				      comerror_t &/*err*/,
+				      ostream &/*logout*/) {
+
+  z3950_proxy_array::iterator here = zservers.begin();
+  z3950_proxy_array::iterator end = zservers.end();
+  while (here != end) {
+    collist.push_back((*here)->getName());
+    ++here;
+  }
+}
+
+void z3950proto::has_collection (const text_t &collection, bool &hascollection,
+				 comerror_t &/*err*/, ostream &/*logout*/) {
+  z3950_proxy_array::iterator here = zservers.begin();
+  z3950_proxy_array::iterator end = zservers.end();
+  while (here != end) {
+    if((*here)->getName()==collection) {
+      hascollection=true;
+      return;
+    }
+    ++here;
+  }
+  hascollection=false;
+}
+
+void z3950proto::ping (const text_t &/*collection*/, bool &wassuccess, 
+		       comerror_t &/*err*/, ostream &/*logout*/) {
+  // should we just ping the server, or actually create a connection
+  // to the z39.50 server process on the machine ?
+  wassuccess = true;
+}
+
+void z3950proto::get_collectinfo (const text_t &collection,
+				  ColInfoResponse_t &collectinfo,
+				  comerror_t &err, ostream &logout) {
+
+  // set err to protocolError if something goes wrong...
+  err=noError;
+
+  z3950_proxy_array::iterator here = zservers.begin();
+  z3950_proxy_array::iterator end = zservers.end();
+  while (here != end) {
+    if((*here)->getName()==collection) {
+      break;
+    }
+    ++here;
+  }
+
+  if (here==end) {
+    err=protocolError;
+    char *coll_str=collection.getcstr();
+    logout << "z39.50: couldn't find collection" 
+	   << coll_str
+	   << endl;
+    delete []coll_str;
+    return;
+  }
+
+  const ShortColInfo_t *colinfo=(*here)->getInfo();
+  collectinfo.shortInfo.name=colinfo->name;
+  collectinfo.shortInfo.host=colinfo->host;
+  collectinfo.shortInfo.port=colinfo->port;
+
+  collectinfo.isPublic=true;
+  // don't use beta field
+  /*collectinfo.isBeta=false;*/
+  collectinfo.buildDate=1;
+  // leave ccsCols empty (no cross-coll. searching - for now)
+  /*collectinfo.ccsCols=(text_tarray);*/ //not like this!!!
+  // This info is available from the config file -- johnmcp
+  /*******collectinfo.languages.push_back("en");
+	  collectinfo.languages.push_back("fr");********/
+  collectinfo.numDocs=0;
+  collectinfo.numWords=0;
+  collectinfo.numBytes=0;
+  // copy the text maps over.
+  //  collectinfo.collectionmeta; // text_tmap
+  text_tmap collmeta = *((*here)->getMeta());
+  text_tmap::iterator mhere = collmeta.begin();
+  text_tmap::iterator mend = collmeta.end();
+  while (mhere != mend) {
+    collectinfo.collectionmeta[(*mhere).first][g_EmptyText] = (*mhere).second;
+    mhere ++;
+  }
+  //collectinfo.collectionmeta=*((*here)->getMeta());
+  collectinfo.format=*((*here)->getFormat()); //text_tmap
+  /*    collectinfo.building; //text_tmap  */
+
+  ////collectinfo.receptionist="z3950"; 
+  /* for now... this is a url,  relative to .../cgi-bin.
+     NOTE: if this is empty, it defaults to _gwcgi_?a=p&p=about&c=<colname>
+  */
+}
+
+void z3950proto::get_filterinfo (const text_t &/*collection*/,
+				 InfoFiltersResponse_t &response,
+				 comerror_t &/*err*/, ostream &/*logout*/) {
+  // we'll fake it here, and say we have set up some filters
+  response.filterNames.insert("BrowseFilter");
+  response.filterNames.insert("QueryFilter");
+  response.filterNames.insert("NullFilter");
+
+}
+
+void z3950proto::get_filteroptions (const text_t &/*collection*/,
+				    const InfoFilterOptionsRequest_t &/*req*/,
+				    InfoFilterOptionsResponse_t &response, 
+				    comerror_t &err, ostream &/*logout*/) {
+  // for now, assume all servers have the same characteristics
+  /*  if (request.filterName=="QueryFilter") { } 
+      else if (request.filterName=="BrowseFilter") { } 
+      else if (request.filterName=="NullFilter") {  } */
+  response.filterOptions["Index"].type=FilterOption_t::stringt;
+  response.filterOptions["Index"].repeatable=FilterOption_t::onePerQuery;
+  response.filterOptions["Index"].defaultValue="any";
+  response.filterOptions["Index"].validValues.push_back(".any");
+  response.filterOptions["Index"].validValues.push_back(".title");
+  response.filterOptions["Index"].validValues.push_back(".author");
+  // and maybe ["Language"] option as well?
+  err=noError;
+}
+
+void z3950proto::filter (const text_t &collection,
+			 FilterRequest_t &request,
+			 FilterResponse_t &response,
+			 comerror_t &err, ostream &logout) {
+  // this function is called when:
+  //  *  creating the title page,(looking for iconcoll* & collectname metadata)
+  //  *  creating the about page (looking for "Title" metadata)
+  //  * doing the query - (note that a request for metadata comes first, then
+  // filterOptions = FRmetadata | FROID | FRtermFreq (64+4+1)
+
+  // metadata-only requests have filterName="NullFilter", else "QueryFilter".
+  // For the title page, we should not create a connection to the target
+  // (target means the actual z39.50 server, origin means us), but
+  // for the about page and query pages, we need to get information from the
+  // origin. (eg for the about page, we will print out some info such as ID,
+  // name and version.
+
+  // cerr now goes to errout.txt in etc directory
+  err=noError;
+
+  // get relevant "collection"
+  z3950_proxy_array::iterator zserver = zservers.begin();
+  z3950_proxy_array::iterator zend = zservers.end();
+  while (zserver != zend) {
+    if((*zserver)->getName()==collection) {
+      break;
+    }
+    ++zserver;
+  }
+  // now have collection in zserver.
+  
+  ColInfoResponse_t info;
+  ResultDocInfo_t *docInfo;
+  
+  // leave response.termInfo empty
+  // response.termInfo.push_back(g_EmptyText); ??????? (should be empty if not req.)
+
+  // See if this is for a query action
+  if (request.filterName=="QueryFilter") {
+    /* Sample OptionValue pairs
+      `StartResults'=`1'
+      `EndResults'=`20'
+      `Term'=`firstword secondword' (term is just whatever the user typed in)
+      `QueryType'=ranked|boolean   -> OR|AND
+      //`MatchMode'=`some' => 'OR'
+      //`MatchMode' = `all' => 'AND'
+      `Casefold'=`true'
+      `Stem'=`false'
+      `Maxdocs'=`50'
+     */
+    // go through options
+    text_t opt_term;            // the term(s) that the user entered 
+    int opt_querytype=0;        // 1=>ranked (or), 2=>boolean (and)
+    text_t opt_fields;          // which fields to search on
+    int opt_start=1, opt_end=20; // default values
+    int nummatches=0, maxdocs=50; // default values
+    OptionValue_tarray::iterator ov_here=request.filterOptions.begin();
+    OptionValue_tarray::iterator ov_end=request.filterOptions.end();
+    while (ov_here != ov_end) {
+      if (ov_here->name=="Term") {
+	opt_term=ov_here->value;
+      } else if (ov_here->name=="QueryType") {
+	if (ov_here->value=="ranked") opt_querytype=1;
+	else if (ov_here->value=="boolean") opt_querytype=2;
+	else { /* error - shouldn't happen */
+	  /* currently unhandled */
+	}
+      } else if (ov_here->name=="Index") {
+	opt_fields=ov_here->value;
+      } else if (ov_here->name=="StartResults") {
+	opt_start=ov_here->value.getint();
+      } else if (ov_here->name=="EndResults") {
+	opt_end=ov_here->value.getint(); 
+      } else if (ov_here->name=="Maxdocs") {
+	maxdocs=ov_here->value.getint();
+      } 
+      ++ov_here;
+    }
+    err=noError;
+    text_tarray *titles=(*zserver)->getrecordTitles(opt_term,
+						    opt_querytype,
+						    opt_fields,
+						    opt_start, // first to get
+						    opt_end-opt_start, //count
+						    &nummatches,err);
+    if (err!=noError) {
+      // can we return an err msg in a response, or just use
+      // the more drastic Greenstone error mechanism?
+      docInfo=new ResultDocInfo_t;
+      response.docInfo.push_back(*docInfo);
+      docInfo->metadata["Title"].values.push_back("Error - query err?");
+      logout << "\nz3950 filter query: error connecting to server\n";
+      // for now, DON'T use GSDL protocol err.
+      err=noError;
+      return;
+    }
+    // check if (titles==NULL) - only happens on error?
+    if (nummatches>0) {
+      text_tarray::iterator titles_here=titles->begin();
+      text_tarray::iterator titles_end=titles->end();
+      int counter=1;
+      while (titles_here!=titles_end) {
+	docInfo=new ResultDocInfo_t; 
+	docInfo->metadata["Title"].values.push_back(*titles_here);
+	docInfo->result_num=counter;
+	// we need to give some OID, so we'll just use counter for now...
+	// make it the number into the whole possible retrieved set.
+	docInfo->OID=counter+opt_start-1;
+	response.docInfo.push_back(*docInfo);
+	++counter;
+	++titles_here;
+      }
+    }
+
+    if (request.filterResultOptions & FRtermFreq) {
+      if (nummatches>maxdocs) {
+      	response.numDocs=maxdocs; // eg "more than 50" (if Maxdocs==50)
+	response.isApprox=MoreThan;
+      } else {
+	response.numDocs=nummatches; // eg "36 documents"
+	response.isApprox=Exact; // Exact | Approximate | MoreThan
+      }
+    } // end of if (... & FRtermFreq)
+    
+  } // end of if (... == "QueryFilter")
+  else {
+    // this wasn't a query action
+
+    if (request.filterOptions.size()>0 &&
+	request.filterOptions[0].name=="ParentNode") {
+      // don't want to return anything
+      return;
+      /*    } else if (request.docSet.size() &&
+	    request.docSet[0]!="collection") {
+	    // documentaction
+	    // if docSet is not empty, it is either "collection", or an array
+	    // of OIDs 
+	    docInfo=new ResultDocInfo_t;
+	    response.docInfo.push_back(*docInfo);
+      */
+    } else {
+      // in case we need to return only metadata
+      docInfo=new ResultDocInfo_t;
+      response.docInfo.push_back(*docInfo); 
+    }
+  } // end of not a query action
+
+
+
+  // Fill in metadata for each response.docInfo (if wanted)
+  if (request.filterResultOptions & FRmetadata) {
+    get_collectinfo (collection, info, err, logout);
+    // should check err returned here....
+
+    if (!request.fields.empty()) {
+      // currently, this is only true for NullFilter when getting the "Title"
+      // for a documentaction.
+
+      // loop on each document being returned
+      ResultDocInfo_tarray::iterator docs_here=response.docInfo.begin();
+      ResultDocInfo_tarray::iterator docs_end=response.docInfo.end();
+      while (docs_here!=docs_end) {
+	// loop on all the metadata fields in request.fields (type text_tset)
+	text_tset::iterator fields_here=request.fields.begin();
+	text_tset::iterator fields_end=request.fields.end();
+	//text_tmap::iterator it;
+	collectionmeta_map::iterator it;
+	while (fields_here!=fields_end) {
+	  it=info.collectionmeta.find(*fields_here);
+	  if (it!=info.collectionmeta.end())
+	    docs_here->metadata[*fields_here].values.push_back(((*it).second)[g_EmptyText]);
+	  else if (*fields_here=="Title" && !request.docSet.empty()) { 
+	    // We only do this for a document action.
+	    // (This comes through as a NullQuery).
+	    // hopefully docSet is only not empty for documentaction...
+	    text_t doctitle;
+	    int i;
+	    // check that docSet isn't empty first!!!!!!
+	    i=request.docSet[0].getint();
+	    text_t doctext="unneeded";
+	    /* following variables aren't used, as our query result has been
+	       cached in z3950proxy.cpp (but really we shouldn't know that
+	       here...) But for the NullFilter, we don't get given these
+	       again in the request, so for now we'll take advantage of this.*/
+
+	    int querytype=0; text_t field=g_EmptyText;
+
+	    // get the Query out of the filterOptions. (we need get the Title)
+	    text_t query=g_EmptyText;
+	    OptionValue_tarray::iterator opthere=request.filterOptions.begin();
+	    OptionValue_tarray::iterator opt_end=request.filterOptions.end();
+	    while (opthere!=opt_end) {
+	      if (opthere->name=="Term") {
+		query=opthere->value;
+	      } else if (opthere->name=="Index") {
+		field=opthere->value;
+	      } else if (opthere->name=="QueryType") {
+		if (opthere->value=="ranked") querytype=1;
+		else if (opthere->value=="boolean") querytype=2;
+		else { /* error - shouldn't happen */
+		  /* currently unhandled */
+		}
+	      }
+	      ++opthere;
+	    }
+	    (*zserver)->getfullrecord(query, querytype, field, i, doctitle, doctext, err);
+	    // check err value!
+	    docs_here->metadata["Title"].values.push_back(doctitle);	    
+	  } else {
+	    docs_here->metadata[*fields_here].values.push_back(g_EmptyText);
+	  }
+	  ++fields_here;
+	} // end of inner while loop
+	++docs_here;
+      } // end of outer while loop
+    } // end of if (!request.fields.empty())
+    
+    else { // request.fields empty: return all metadata for about page or query
+      // we'll only put it in the first docInfo.
+      collectionmeta_map::iterator colmeta_here=info.collectionmeta.begin();
+      collectionmeta_map::iterator colmeta_end=info.collectionmeta.end();
+      while (colmeta_here!=colmeta_end) {
+	response.docInfo[0].metadata[(*colmeta_here).first].
+	  values.push_back(((*colmeta_here).second)[g_EmptyText]);
+	++colmeta_here;
+      }
+
+      // check if "collectionextra" metadata is set. If it isn't, we should
+      // create connection to target to get it.
+      if (info.collectionmeta.find("collectionextra")==colmeta_end) {
+	// it hasn't been set yet...
+	text_t abouttext="<B>Server Online</B><br>\n";
+	abouttext+=(*zserver)->getzAbout();
+	// add in the "About" text we read in from config file.
+	// how do we incorporate multi-lingual metadata?
+	abouttext+="<P>\n";
+	text_t tmpabout;
+
+	if ((*zserver)->getcfgAbout("en", tmpabout)==true)
+	  abouttext+=tmpabout;
+	
+	(*zserver)->setMeta("collectionextra",abouttext);
+	response.docInfo[0].metadata["collectionextra"].values.push_back(abouttext);
+      }
+    } // end of else
+
+    // do indices' names, regardless of whether asked for or not...
+    if (!response.docInfo.empty()) {
+     response.docInfo[0].metadata[".author"].values.push_back("author fields");
+      response.docInfo[0].metadata[".title"].values.push_back("title fields");
+      response.docInfo[0].metadata[".any"].values.push_back("any fields");
+    }
+  } //end of  if (... & FRmetadata) ...
+}
+
+
+
+void z3950proto::get_document (const text_t &collection,
+			       const DocumentRequest_t &request,
+			       DocumentResponse_t &response,
+			       comerror_t &err, ostream &logout) {
+
+  err=noError;
+
+  // get relevant "collection"
+  z3950_proxy_array::iterator zserver = zservers.begin();
+  z3950_proxy_array::iterator zend = zservers.end();
+  while (zserver != zend) {
+    if((*zserver)->getName()==collection) {
+      break;
+    }
+    ++zserver;
+  }
+  // now have collection in zserver.
+
+  /* docresponse consists of
+     text_t response.doc */
+  text_t title="unneeded";
+  text_t doctext;
+  text_t query; // this should not be needed, as we have already connected to 
+  // get the  title....
+  int querytype = 1; //ditto...
+  text_t field;  // ditto...
+  (*zserver)->getfullrecord(query,querytype,field,request.OID.getint(),
+			    title,doctext,err);
+  // check return value of above? (false=>not connected) 
+  if (err==noError)
+    response.doc=doctext;
+  else {
+    // could print out different messages based on error type....
+    response.doc="<h2>Error</h2>There was an error while connecting to the ";
+    response.doc+="z39.50 server (ie target). Most likely this was a \n";
+    response.doc+="\"Connection Refused\" error.\n";
+
+  }
+  if (0) {
+    err=protocolError;
+    logout << "Some error\n";
+  }
+}
+
+// sets issearchable to true if the given colection is searchable
+void z3950proto::is_searchable (const text_t &/*collection*/, bool &issearchable, 
+				comerror_t &err, ostream &/*logout*/) {
+  issearchable = true; // assume all collections are searchable?
+  err = noError;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proto.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proto.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proto.h	(revision 10506)
@@ -0,0 +1,98 @@
+/**********************************************************************
+ *
+ * z3950proto.h --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef Z3950PROTO_H
+#define Z3950PROTO_H
+
+#include "recptproto.h"
+#include "z3950proxy.h"
+
+class z3950proto : public recptproto {
+protected:
+  int zserver_count;
+  z3950_proxy_array zservers;
+public:
+  z3950proto();
+  virtual ~z3950proto();
+
+  int getServerCount() { return zserver_count;}
+  /*
+  void add_collectserver (collectserver *thecserver) 
+        {cservers.addcollectserver(thecserver);}
+  */
+  
+  void add_server(z3950_proxy& zserver);
+
+  void read_config_file(const text_t &filename, const text_t &errfile);
+
+  void configure (const text_t &key, const text_tarray &cfgline);
+
+  bool init (ostream &logout);
+
+  text_t get_protocol_name (comerror_t &/*err*/) {return "z3950proto";}
+
+  void get_collection_list (text_tarray &collist, comerror_t &err, 
+			    ostream &logout);
+
+  void has_collection (const text_t &collection, bool &hascollection, 
+		       comerror_t &err, ostream &logout);
+  
+  void ping (const text_t &collection, bool &wassuccess, 
+	     comerror_t &err, ostream &logout);
+  
+  void get_collectinfo (const text_t &collection, 
+			ColInfoResponse_t &collectinfo,
+			comerror_t &err, ostream &logout);
+  
+  void get_filterinfo (const text_t &collection,
+		       InfoFiltersResponse_t &response,
+		       comerror_t &err, ostream &logout);
+  
+  /*  void get_info (const text_t &collection, const text_tset &metadata,
+      FilterResponse_t &response, ostream &logout);
+  */
+
+  void get_filteroptions (const text_t &collection,
+                          const InfoFilterOptionsRequest_t &request,
+                          InfoFilterOptionsResponse_t &response, 
+                          comerror_t &err, ostream &logout);
+  
+  void filter (const text_t &collection,
+	       FilterRequest_t &request,
+	       FilterResponse_t &response,
+	       comerror_t &err, ostream &logout);
+  
+  void get_document (const text_t &collection,
+		     const DocumentRequest_t &request,
+		     DocumentResponse_t &response,
+		     comerror_t &err, ostream &logout);
+  
+  void is_searchable (const text_t &collection, 
+			      bool &issearchable, 
+			      comerror_t &err, ostream &logout);
+
+};
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proxy.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proxy.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proxy.cpp	(revision 10506)
@@ -0,0 +1,365 @@
+/**********************************************************************
+ *
+ * z3950proxy.cpp --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "z3950proxy.h"
+#include "comtypes.h"
+#include <stdio.h>
+
+// z39.50 yaz stuff
+#define min(a,b) (((a)<(b))?(a):(b))
+
+extern "C" {
+#include "yaz_zclient.h"
+}
+
+/*** 
+     each z39.50 server+database pair is a GSDL collection.
+***/
+
+z3950_proxy::z3950_proxy() {
+  info=NULL;
+  connected=false;
+  titles=NULL;
+  gotsinglerecord=false;
+  // for now, assume that all records will have text associated with them.
+  meta["hastxt"]="1";
+  // for now, assume we don't want ANY DocumentButtons.
+  format["DocumentButtons"]=g_EmptyText;
+}
+
+z3950_proxy::~z3950_proxy() {
+}
+
+void z3950_proxy::setMeta(const text_t &key, const text_t &value) {
+  meta[key]=value;
+}
+
+void z3950_proxy::setName(const text_t &newname) {
+  title=newname;
+  meta["collectionname"]=newname;
+}
+
+void z3950_proxy::addcfgAbout(const text_t &lang, const text_t &abouttext) {
+    about[lang]=abouttext;
+}
+
+bool z3950_proxy::getcfgAbout(const text_t &lang, text_t &abouttxt) {
+  text_tmap::iterator it;
+  it=about.find(lang);
+  if (it==about.end()) return (false);
+  abouttxt=((*it).second);
+  return (true);
+}
+
+
+// now functions that actually talk over the tcp connection.
+
+// create a tcp connection to the associated target. Currently, this will
+// re-initialise if we are already connected.
+bool z3950_proxy::connect() {
+  text_t server_and_port;
+  char *zserverinfo;
+
+  server_and_port=info->host+":"+info->port;
+  // remember that info.name is the database name
+
+  z_initialize();
+  char* serv_str=server_and_port.getcstr();
+  char* name_str=info->name.getcstr();
+  int retval=z_cmd_open(serv_str,name_str);
+  delete []serv_str;
+  delete []name_str;
+  if (retval==1)
+    // we got a connection error
+    return false;
+
+  // get initialisation response.
+  z_getnextAPDU();
+  zserverinfo=z_get_initResponse();
+  if (zserverinfo!=NULL) {
+    z_initstr.appendcstr(zserverinfo);
+  }
+  free(zserverinfo);
+
+  connected=true;
+  return true;
+}
+
+void z3950_proxy::parseQuery(const text_t &query, 
+			      const int querytype,
+			      const text_t &fields,
+			      text_t &parsed_query) {
+  /****** FIXME *****/
+  // We need to format the query string into RPN - 
+  // by just passing it like this, it will only work for simple queries.
+  // This will require us to actually come up with a query syntax and 
+  // a parser. For now, we'll just do an "AND" query for all terms
+  // But look at Common Command Language (CCL) query syntax (ISO 8777).
+
+  // need to remove " chars from the query. We should really tell the server
+  // to do a phrase search on the terms that are between the "s, but we
+  // can't (easily) tell if the server can do that or not, 
+  // so we'll currently just do a query and then post-process. (not yet
+  // implemented........)
+
+  // we need to count number of terms separated by a space
+  char *ptr=query.getcstr();
+  int strlength=strlen(ptr);
+  bool inword=false;
+  int num_terms=0;
+
+
+  for (int i=0;i<strlength;++i) {
+    if (*(ptr+i)=='"') { // convert " to SPACE...
+      *(ptr+i)=' '; 
+    }
+    if (*(ptr+i)!=' ') {
+      if (inword==false) {
+	inword=true;
+	++num_terms;
+      }
+    }
+    else { // ptr+i is a space
+      inword=false;
+      }
+  }
+  
+  // set the field(s) to search on - main ones include:
+  //  1016  => Any
+  //  1     => (Personal) Name
+  //  4     => Title
+  //  21    => Subject Heading
+  //  45    => Subject precis
+  // Note I have no idea how these actually work - I think some servers
+  // only have limited fields, and map all subject-type requests into that
+  // subject field, etc.
+
+  parsed_query="@attr 1=";
+  if (fields==".author")
+    parsed_query+="1 ";
+  else if (fields==".title")
+    parsed_query+="4 ";
+  else // fields==".any"
+    parsed_query+="1016 ";
+
+  // querytype=1 => ranked/or,  =2 => boolean/and
+  // append "@and" for each term after the first
+  {
+    char and_str[]="@and ";
+    char or_str[]="@or ";
+    char *q_type;
+    if (querytype==1) q_type=or_str; else q_type=and_str;
+    for (int i=1;i<num_terms;++i)
+      parsed_query+=q_type;
+    // append the actual query
+    parsed_query+=ptr;
+  }
+  delete []ptr;
+}
+
+text_tarray *z3950_proxy::getrecordTitles(const text_t &query, 
+					   const int querytype,
+					   const text_t &fields,
+					   int first, int count,
+					   int *nummatches, comerror_t &err) {
+  /* NOTE!!!!!! Because this code currently only works in cgi-bin mode,
+     we only ever do one request. Therefore, it is CURRENTLY OK to store
+     (cache) the retrieved titles, because if this function is ever called
+     more than once, the arguments will be the same each time.
+     (I think :)
+  */
+
+  char **c_str_titles; 
+  int i;
+  int last;
+
+  if (gotsinglerecord==true) {
+    /* If true, then this whole execution was done to retrieve a single
+       document. Therefore, the list of titles of all records matching the
+       query isn't actually required. It's just that for some reason our
+       filter (z3950proto::filter) gets called at least 7 times, with the
+       7th being a "QueryFilter" for some reason... */
+    nummatches=0;
+    return NULL; /* shouldn't really return NULL, but nummatches is checked
+		    first (I hope) */
+  }
+
+  //  if (titles!=NULL) delete (titles);
+  if (titles!=NULL) return titles;
+  titles=new text_tarray;
+
+  /* check if connected */
+  if (connected==false) 
+    if (connect()==false) {
+      // we could not connect.
+      err=protocolError;
+      return (NULL);
+    }
+  
+
+  text_t expanded_query=g_EmptyText;
+  parseQuery(query,querytype,fields,expanded_query);
+
+  char* query_str=expanded_query.getcstr();
+  // following functions defined in yaz_zclient.c
+  *nummatches=z_cmd_dosearch(query_str); // returns # found, -1 on err.
+  delete []query_str;
+  if (*nummatches<=0) {
+    if (*nummatches==0) {
+      // no matches
+      return (NULL);
+    } else  if (*nummatches==-1) {
+      // prefix query error
+      err=protocolError;
+      return (NULL);
+    }  else if (*nummatches==-2) {
+      // sendsearchRequest not answered by searchResponse
+      err=protocolError;
+      return (NULL);
+    }
+  }
+  // could do a sort eventually, eg on date, title, etc.
+  // (non-existent function)    z_sort(field, asc|desc);
+  /* min of (count, first + (*nummatches) ) */
+  // z_getrecordTitles ( first, howmany )
+  c_str_titles=z_getrecordTitles(first,min(count,*nummatches-first+1));
+  if (c_str_titles==NULL) {
+    // an error occurred. we need a logout/err as an arg
+    return (NULL);
+  }
+  if (c_str_titles[0]==0) {
+    // no matches.
+    return (NULL);
+  }
+  last=(int)c_str_titles[0];
+  for (i=1;i<=last;++i) {
+    titles->push_back(c_str_titles[i]);
+    free(c_str_titles[i]);
+  }
+  free(c_str_titles);
+  return (titles);
+  
+}
+
+bool z3950_proxy::getfullrecord(const text_t &query, 
+				 const int querytype,
+				 const text_t &fields,
+				 const int ID, 
+				 text_t &rettitle, 
+				 text_t &rettext, comerror_t &err) {
+
+  static char **c_str_titles=NULL;
+  static char *fulltext=NULL;
+  /* NOTE!!!!!! Because this code currently only works in cgi-bin mode,
+     we only ever do one request. Therefore, it is CURRENTLY OK to store
+     (cache) the retrieved titles, because if this function is ever called
+     more than once, the arguments will be the same each time.
+     (I think :)
+  */
+
+  gotsinglerecord=true; // well, not yet, but we've been called...
+
+  if (connected==false) {
+    if (connect()==false) {
+      // error connecting...
+      err=protocolError;
+      return (false);
+    }
+    // since we have just re-connected, we need to do the
+    // query again.
+
+    text_t expanded_query=g_EmptyText;
+    parseQuery(query,querytype,fields,expanded_query);
+
+    char* query_str=expanded_query.getcstr();
+    int returned=z_cmd_dosearch(query_str);
+    delete []query_str;
+    if (returned<=0) {
+      // 0 => none.
+      // <0 => error
+      err=protocolError;
+      return (false);
+    }
+  }
+
+  if (c_str_titles==NULL)
+    c_str_titles=z_getrecordTitles(ID,1); // check this return value.
+  
+  if (rettitle!="unneeded") {
+    //int dummy;
+    if (c_str_titles!=NULL && (int)c_str_titles[0]==1) {
+      rettitle.setcstr(c_str_titles[1]); // and check this 
+      //////      free (c_str_titles); - we want to "cache" it
+    } else {
+      // we didn't get something....
+      rettitle="Nothing Returned...";
+    }
+  }
+
+  if (fulltext==NULL)
+    // get the text
+    fulltext=z_getfullRecord(ID);
+
+  if (rettext!="unneeded") {
+    rettext.setcstr(fulltext);
+  }
+  return (true);
+  }
+
+text_t &z3950_proxy::getzAbout() {
+  text_t zserverresp;
+
+  // Assume we have not yet connected, so that must be done here.
+  if (connected==true)
+    return (z_initstr);
+  
+  // we need to create the tcp connection to the target (server)  
+  //  z_initstr=new text_t;
+  
+  if (connect()==false) {
+    z_initstr.setcstr("<H2>Server offline</H2>Error - could not connect to server <B>");
+    z_initstr += info->host;
+    z_initstr += "</B> on port ";
+    z_initstr += info->port;
+    z_initstr += "\n";
+    return (z_initstr);
+  }
+  
+  // z_initstr currently contains the target's response. We want to
+  // PREPEND the following information.
+  zserverresp=z_initstr;
+  z_initstr="Internet server: <b>";
+  z_initstr+=info->host;
+  z_initstr+="</b> on port ";
+  z_initstr+=info->port;
+  z_initstr+=".<br>\n";
+  z_initstr+=zserverresp;
+
+  // should close /******* WHAT IF DOING A QUERY!??!?!? ********/
+  // z_cmd_close(0);
+  // connected=false;
+  return (z_initstr);
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proxy.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proxy.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/z3950proxy.h	(revision 10506)
@@ -0,0 +1,79 @@
+/**********************************************************************
+ *
+ * z3950proxy.h --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef Z3950PROXY_H
+#define Z3050PROXY_H
+
+#include "comtypes.h"
+
+// each "proxy to server" (i.e. collection) consists of a {z39.50 server + database} pair.
+class z3950_proxy {
+ protected:
+  text_t title;    // Descriptive name
+  text_t z_initstr; // a string returned when the connection is initialised.
+  text_tmap meta;  // metadata for this collection (ie server/database pair)
+  text_tmap format;
+  text_tmap about; // langauge/abouttext pair for collection.
+  ShortColInfo_t *info; // has  (database) name, host and port
+  text_tarray *titles; 
+  bool connect();
+  bool connected; // tcp connection to the z39.50 server (target)
+  bool gotsinglerecord; // if we do, then we don't need all titles...
+
+ public:
+  z3950_proxy();
+  ~z3950_proxy();
+  void setName(const text_t &newname);
+  const text_t getName() {return title;}
+  void setMeta(const text_t &key, const text_t &value);
+  const text_tmap *getMeta() {return &meta;}
+  const text_tmap *getFormat() {return &format;}
+  void setInfo(ShortColInfo_t *newinfo) {info=newinfo;}
+  const ShortColInfo_t *getInfo() {return info;}
+  void addcfgAbout(const text_t &lang, const text_t &abouttext);
+  bool getcfgAbout(const text_t &lang, text_t &abouttext);
+  // now the functions that actually talk to the target (ie zserver) over tcp
+  text_t &getzAbout(); // gets any name, id, MOTD, etc from server.
+  text_tarray *getrecordTitles(const text_t &query,
+			       const int andor_querytype,
+			       const text_t &fields,
+			       const int first, const int count,
+			       int *nummatches, comerror_t &err);
+  /* only get one record at a time? (Eventually we could buffer them, but
+     for now... */
+  bool getfullrecord(const text_t &query, const int andor_querytype,
+		     const text_t &fields,
+		     const int ID, text_t &rettitle, 
+		     text_t &rettext,comerror_t &err);
+ private:
+  void parseQuery(const text_t &query, const int andor_querytype, 
+		  const text_t &fields, 
+		  text_t &parsed_query);
+  text_t previousquery; // for caching purposes
+};
+
+typedef  vector<z3950_proxy *>  z3950_proxy_array;
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/zparse.tab.c
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/zparse.tab.c	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/zparse.tab.c	(revision 10506)
@@ -0,0 +1,1189 @@
+
+/*  A Bison parser, made from zparse.y
+    by GNU Bison version 1.28  */
+
+#define YYBISON 1  /* Identify Bison output.  */
+
+#define	GSDLVERSION	257
+#define	GENERAL_SECTION	258
+#define	SEARCH_SECTION	259
+#define	BROWSE_SECTION	260
+#define	MACROS_SECTION	261
+#define	MAINTAINER	262
+#define	PUBLIC	263
+#define	TRUE	264
+#define	FALSE	265
+#define	LANGUAGES	266
+#define	EN	267
+#define	FR	268
+#define	MI	269
+#define	ZH	270
+#define	DE	271
+#define	NAME	272
+#define	STRING	273
+#define	ICON	274
+#define	SMALLICON	275
+#define	ABOUT	276
+#define	SEARCHTEXT	277
+#define	DOCUMENT	278
+#define	SECTION	279
+#define	BROWSE	280
+#define	TYPE	281
+#define	FORMAT	282
+#define	LIST	283
+#define	SORTEDLIST	284
+#define	SECTIONLIST	285
+#define	SORTEDSECTIONLIST	286
+#define	DATELIST	287
+#define	ICONLINK	288
+#define	TEXTLINK	289
+#define	DOCUMENTIMAGES	290
+#define	DOCUMENTHEADER	291
+#define	DOCUMENTTEXT	292
+#define	DOCUMENTBUTTONS	293
+#define	DOCUMENTARROWSBOTTOM	294
+#define	DATA	295
+
+#line 27 "zparse.y"
+
+  /* verbatim C code - functions, etc */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "z3950cfg.h"
+
+#define YYDEBUG 1
+#define YYERROR_VERBOSE 1
+/* can't use default yyparse(), as this name is used elsewhere (eg mg)*/
+#define yyin    zconfigin
+#define yyparse zconfigparse
+char defLanguage=0;
+
+/* defined in parse.fl */
+extern int lineno;
+
+#ifndef YYRECOVERING
+int YYRECOVERING=0; /* this is supposed to already be defined as a macro */
+#endif
+
+/* defined in z3950proto.cpp */
+struct z3950cfg *zserver_list=NULL;
+
+/* this is set in z3950proto.cpp */
+FILE *errfile;
+
+int yylex(void);
+
+int yyerror(char *string);
+
+void errormsg(char *str);
+
+
+#line 64 "zparse.y"
+typedef union {
+  char *string;
+  struct z3950cfg *cfg;
+  struct z3950aboutlist *about;
+  int number;
+} YYSTYPE;
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define	YYFINAL		37
+#define	YYFLAG		-32768
+#define	YYNTBASE	44
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 295 ? yytranslate[x] : 56)
+
+static const char yytranslate[] = {     0,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,    42,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,    43,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     1,     3,     4,     5,     6,
+     7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
+    17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+    27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+    37,    38,    39,    40,    41
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = {     0,
+     0,     3,     5,     7,     8,    11,    13,    22,    24,    26,
+    27,    30,    31,    34,    37,    38,    41,    44,    45,    47,
+    48,    50,    53,    57,    60,    64,    66
+};
+
+static const short yyrhs[] = {    45,
+    46,     0,    45,     0,     3,     0,     0,    46,    47,     0,
+    47,     0,    41,    41,    49,    41,    48,    50,    51,    52,
+     0,     1,     0,    19,     0,     0,    42,    41,     0,     0,
+    20,    19,     0,    20,    41,     0,     0,    21,    19,     0,
+    21,    41,     0,     0,    53,     0,     0,    54,     0,    53,
+    54,     0,    22,    55,    19,     0,    22,    19,     0,    41,
+    43,    41,     0,    41,     0,     1,     0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+   109,   110,   113,   114,   116,   117,   119,   140,   144,   145,
+   150,   151,   154,   155,   158,   159,   160,   165,   167,   168,
+   170,   172,   175,   186,   208,   216,   224
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = {   "$","error","$undefined.","GSDLVERSION",
+"GENERAL_SECTION","SEARCH_SECTION","BROWSE_SECTION","MACROS_SECTION","MAINTAINER",
+"PUBLIC","TRUE","FALSE","LANGUAGES","EN","FR","MI","ZH","DE","NAME","STRING",
+"ICON","SMALLICON","ABOUT","SEARCHTEXT","DOCUMENT","SECTION","BROWSE","TYPE",
+"FORMAT","LIST","SORTEDLIST","SECTIONLIST","SORTEDSECTIONLIST","DATELIST","ICONLINK",
+"TEXTLINK","DOCUMENTIMAGES","DOCUMENTHEADER","DOCUMENTTEXT","DOCUMENTBUTTONS",
+"DOCUMENTARROWSBOTTOM","DATA","':'","'_'","z3950","version","zserverlist","zserver",
+"name","port","icon","smallicon","about","aboutList","aboutLang","lang", NULL
+};
+#endif
+
+static const short yyr1[] = {     0,
+    44,    44,    45,    45,    46,    46,    47,    47,    48,    48,
+    49,    49,    50,    50,    50,    51,    51,    51,    52,    52,
+    53,    53,    54,    54,    55,    55,    55
+};
+
+static const short yyr2[] = {     0,
+     2,     1,     1,     0,     2,     1,     8,     1,     1,     0,
+     2,     0,     2,     2,     0,     2,     2,     0,     1,     0,
+     1,     2,     3,     2,     3,     1,     1
+};
+
+static const short yydefact[] = {     4,
+     3,     0,     8,     0,     0,     6,    12,     5,     0,     0,
+    11,    10,     9,    15,     0,    18,    13,    14,     0,    20,
+    16,    17,     0,     7,    19,    21,    27,    24,    26,     0,
+    22,     0,    23,    25,     0,     0,     0
+};
+
+static const short yydefgoto[] = {    35,
+     2,     5,     6,    14,    10,    16,    20,    24,    25,    26,
+    30
+};
+
+static const short yypact[] = {     4,
+-32768,     0,-32768,   -33,     2,-32768,   -32,-32768,   -30,   -29,
+-32768,   -10,-32768,    -7,   -14,    -6,-32768,-32768,   -13,    -8,
+-32768,-32768,     3,-32768,    -8,-32768,-32768,-32768,   -27,    -2,
+-32768,   -23,-32768,-32768,    19,    20,-32768
+};
+
+static const short yypgoto[] = {-32768,
+-32768,-32768,    16,-32768,-32768,-32768,-32768,-32768,-32768,    -1,
+-32768
+};
+
+
+#define	YYLAST		44
+
+
+static const short yytable[] = {    -2,
+     3,    -1,     3,    27,    17,    21,     1,     7,    13,     9,
+    11,    12,    15,    23,    19,    32,    33,    34,    36,    37,
+     8,    28,     0,    31,     0,     0,    18,    22,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     4,     0,     4,    29
+};
+
+static const short yycheck[] = {     0,
+     1,     0,     1,     1,    19,    19,     3,    41,    19,    42,
+    41,    41,    20,    22,    21,    43,    19,    41,     0,     0,
+     5,    19,    -1,    25,    -1,    -1,    41,    41,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    41,    -1,    41,    41
+};
+/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
+#line 3 "/usr/share/bison.simple"
+/* This file comes from bison-1.28.  */
+
+/* Skeleton output parser for bison,
+   Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* This is the parser code that is written into each bison parser
+  when the %semantic_parser declaration is not specified in the grammar.
+  It was written by Richard Stallman by simplifying the hairy parser
+  used when %semantic_parser is specified.  */
+
+#ifndef YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C.  */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C.  */
+/* This used to test MSDOS, but that is a bad idea
+   since that symbol is in the user namespace.  */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+	 instead, just don't use alloca.  */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+   So I turned it off.   rms, 2 May 1997.  */
+/* #include <malloc.h>  */
+ #pragma alloca
+#define YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
+		 and on HPUX 10.  Eventually we can turn this on.  */
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#ifdef YYSTACK_USE_ALLOCA
+#define YYSTACK_ALLOC alloca
+#else
+#define YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+   It is replaced by the list of actions, each action
+   as one case of the switch.  */
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		-2
+#define YYEOF		0
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT 	goto yyabortlab
+#define YYERROR		goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+   This remains here temporarily to ease the
+   transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+#define YYFAIL		goto yyerrlab
+#define YYRECOVERING()  (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    { yychar = (token), yylval = (value);			\
+      yychar1 = YYTRANSLATE (yychar);				\
+      YYPOPSTACK;						\
+      goto yybackup;						\
+    }								\
+  else								\
+    { yyerror ("syntax error: cannot back up"); YYERROR; }	\
+while (0)
+
+#define YYTERROR	1
+#define YYERRCODE	256
+
+#ifndef YYPURE
+#define YYLEX		yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX		yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX		yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int	yychar;			/*  the lookahead symbol		*/
+YYSTYPE	yylval;			/*  the semantic value of the		*/
+				/*  lookahead symbol			*/
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc;			/*  location data for the lookahead	*/
+				/*  symbol				*/
+#endif
+
+int yynerrs;			/*  number of parse errors so far       */
+#endif  /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug;			/*  nonzero means print parse trace	*/
+/* Since this is uninitialized, it does not stop multiple parsers
+   from coexisting.  */
+#endif
+
+/*  YYINITDEPTH indicates the initial size of the parser's stacks	*/
+
+#ifndef	YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/*  YYMAXDEPTH is the maximum size the stacks can grow to
+    (effective only if the built-in stack extension method is used).  */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+
+/* Define __yy_memcpy.  Note that the size argument
+   should be passed with type unsigned int, because that is what the non-GCC
+   definitions require.  With GCC, __builtin_memcpy takes an arg
+   of type size_t, but it can handle unsigned int.  */
+
+#if __GNUC__ > 1		/* GNU C and GNU C++ define this.  */
+#define __yy_memcpy(TO,FROM,COUNT)	__builtin_memcpy(TO,FROM,COUNT)
+#else				/* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (to, from, count)
+     char *to;
+     char *from;
+     unsigned int count;
+{
+  register char *f = from;
+  register char *t = to;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+   in available built-in functions on various systems.  */
+static void
+__yy_memcpy (char *to, char *from, unsigned int count)
+{
+  register char *t = to;
+  register char *f = from;
+  register int i = count;
+
+  while (i-- > 0)
+    *t++ = *f++;
+}
+
+#endif
+#endif
+
+
+#line 217 "/usr/share/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+   into yyparse.  The argument should have type void *.
+   It should actually point to an object.
+   Grammar actions can access the variable by casting it
+   to the proper pointer type.  */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes.  */
+#ifdef __GNUC__
+#ifdef YYPARSE_PARAM
+int yyparse (void *);
+#else
+int yyparse (void);
+#endif
+#endif
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+     YYPARSE_PARAM_DECL
+{
+  register int yystate;
+  register int yyn;
+  register short *yyssp;
+  register YYSTYPE *yyvsp;
+  int yyerrstatus;	/*  number of tokens to shift before error messages enabled */
+  int yychar1 = 0;		/*  lookahead token as an internal (translated) token number */
+
+  short	yyssa[YYINITDEPTH];	/*  the state stack			*/
+  YYSTYPE yyvsa[YYINITDEPTH];	/*  the semantic value stack		*/
+
+  short *yyss = yyssa;		/*  refer to the stacks thru separate pointers */
+  YYSTYPE *yyvs = yyvsa;	/*  to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylsa[YYINITDEPTH];	/*  the location stack			*/
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+
+#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+#endif
+
+  int yystacksize = YYINITDEPTH;
+  int yyfree_stacks = 0;
+
+#ifdef YYPURE
+  int yychar;
+  YYSTYPE yylval;
+  int yynerrs;
+#ifdef YYLSP_NEEDED
+  YYLTYPE yylloc;
+#endif
+#endif
+
+  YYSTYPE yyval;		/*  the variable used to return		*/
+				/*  semantic values from the action	*/
+				/*  routines				*/
+
+  int yylen;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Starting parse\n");
+#endif
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;		/* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss - 1;
+  yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+  yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in  yystate  .  */
+/* In all cases, when you get here, the value and location stacks
+   have just been pushed. so pushing a state here evens the stacks.  */
+yynewstate:
+
+  *++yyssp = yystate;
+
+  if (yyssp >= yyss + yystacksize - 1)
+    {
+      /* Give user a chance to reallocate the stack */
+      /* Use copies of these so that the &'s don't force the real ones into memory. */
+      YYSTYPE *yyvs1 = yyvs;
+      short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+      YYLTYPE *yyls1 = yyls;
+#endif
+
+      /* Get the current used size of the three stacks, in elements.  */
+      int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      /* Each stack pointer address is followed by the size of
+	 the data in use in that stack, in bytes.  */
+#ifdef YYLSP_NEEDED
+      /* This used to be a conditional around just the two extra args,
+	 but that might be undefined if yyoverflow is a macro.  */
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yyls1, size * sizeof (*yylsp),
+		 &yystacksize);
+#else
+      yyoverflow("parser stack overflow",
+		 &yyss1, size * sizeof (*yyssp),
+		 &yyvs1, size * sizeof (*yyvsp),
+		 &yystacksize);
+#endif
+
+      yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+      yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+      /* Extend the stack our own way.  */
+      if (yystacksize >= YYMAXDEPTH)
+	{
+	  yyerror("parser stack overflow");
+	  if (yyfree_stacks)
+	    {
+	      free (yyss);
+	      free (yyvs);
+#ifdef YYLSP_NEEDED
+	      free (yyls);
+#endif
+	    }
+	  return 2;
+	}
+      yystacksize *= 2;
+      if (yystacksize > YYMAXDEPTH)
+	yystacksize = YYMAXDEPTH;
+#ifndef YYSTACK_USE_ALLOCA
+      yyfree_stacks = 1;
+#endif
+      yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+      __yy_memcpy ((char *)yyss, (char *)yyss1,
+		   size * (unsigned int) sizeof (*yyssp));
+      yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+      __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+		   size * (unsigned int) sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+      yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+      __yy_memcpy ((char *)yyls, (char *)yyls1,
+		   size * (unsigned int) sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + size - 1;
+      yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+      yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+      if (yyssp >= yyss + yystacksize - 1)
+	YYABORT;
+    }
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+  goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* yychar is either YYEMPTY or YYEOF
+     or a valid token in external form.  */
+
+  if (yychar == YYEMPTY)
+    {
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Reading a token: ");
+#endif
+      yychar = YYLEX;
+    }
+
+  /* Convert token to internal form (in yychar1) for indexing tables with */
+
+  if (yychar <= 0)		/* This means end of input. */
+    {
+      yychar1 = 0;
+      yychar = YYEOF;		/* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Now at end of input.\n");
+#endif
+    }
+  else
+    {
+      yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+      if (yydebug)
+	{
+	  fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+	  /* Give the individual parser a way to print the precise meaning
+	     of a token, for further debugging info.  */
+#ifdef YYPRINT
+	  YYPRINT (stderr, yychar, yylval);
+#endif
+	  fprintf (stderr, ")\n");
+	}
+#endif
+    }
+
+  yyn += yychar1;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+    goto yydefault;
+
+  yyn = yytable[yyn];
+
+  /* yyn is what to do for this token type in this state.
+     Negative => reduce, -yyn is rule number.
+     Positive => shift, yyn is new state.
+       New state is final state => don't bother to shift,
+       just return success.
+     0, or most negative number => error.  */
+
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrlab;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  /* count tokens shifted since error; after three, turn off error status.  */
+  if (yyerrstatus) yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+/* Do the default action for the current state.  */
+yydefault:
+
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+
+/* Do a reduction.  yyn is the number of a rule to reduce with.  */
+yyreduce:
+  yylen = yyr2[yyn];
+  if (yylen > 0)
+    yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      int i;
+
+      fprintf (stderr, "Reducing via rule %d (line %d), ",
+	       yyn, yyrline[yyn]);
+
+      /* Print the symbols being reduced, and their result.  */
+      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+	fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+      fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+    }
+#endif
+
+
+  switch (yyn) {
+
+case 1:
+#line 109 "zparse.y"
+{zserver_list=yyvsp[0].cfg;;
+    break;}
+case 2:
+#line 110 "zparse.y"
+{zserver_list=NULL;;
+    break;}
+case 3:
+#line 113 "zparse.y"
+{;;
+    break;}
+case 4:
+#line 114 "zparse.y"
+{fprintf(errfile,"No version - not GSDL config file?\n");return(1);;
+    break;}
+case 5:
+#line 116 "zparse.y"
+{if (yyvsp[0].cfg!=NULL) {yyvsp[0].cfg->next=yyvsp[-1].cfg;yyval.cfg=yyvsp[0].cfg;};
+    break;}
+case 7:
+#line 120 "zparse.y"
+{
+		     if (YYRECOVERING)
+		       {yyval.cfg=NULL;YYRECOVERING=0;} 
+		     else {
+		       if((yyval.cfg=malloc(sizeof(struct z3950cfg)))==NULL)
+			 {
+			   fprintf(errfile,"malloc failed\n");
+			   return(1);
+			 }
+		       yyval.cfg->shortname=yyvsp[-7].string;
+		       yyval.cfg->hostname=yyvsp[-6].string;
+		       yyval.cfg->port=yyvsp[-5].number;
+		       yyval.cfg->dbname=yyvsp[-4].string;
+		       yyval.cfg->longname=yyvsp[-3].string;
+		       yyval.cfg->icon=yyvsp[-2].string;
+		       yyval.cfg->smallicon=yyvsp[-1].string;
+		       yyval.cfg->about=yyvsp[0].about;
+		       yyval.cfg->next=NULL;
+		     }
+		   ;
+    break;}
+case 8:
+#line 140 "zparse.y"
+{yyval.cfg=NULL;
+	      fprintf(errfile,"discarding zserver (line %d)\n",lineno);;
+    break;}
+case 9:
+#line 144 "zparse.y"
+{;;
+    break;}
+case 10:
+#line 145 "zparse.y"
+{errormsg("Database name needs to be followed by a short "
+			  "descriptive name (enclosed in \" marks)");
+	         yyval.string=NULL;
+	         YYRECOVERING=1;;
+    break;}
+case 11:
+#line 150 "zparse.y"
+{yyval.number=atoi(yyvsp[0].string);;
+    break;}
+case 12:
+#line 151 "zparse.y"
+{yyval.number=210;;
+    break;}
+case 13:
+#line 154 "zparse.y"
+{yyval.string=yyvsp[0].string;;
+    break;}
+case 14:
+#line 155 "zparse.y"
+{yyval.string=yyvsp[0].string;
+                  errormsg("Icon must be enclosed in quotes");
+	      yylex();yylex();;
+    break;}
+case 15:
+#line 158 "zparse.y"
+{yyval.string=NULL;;
+    break;}
+case 16:
+#line 159 "zparse.y"
+{yyval.string=yyvsp[0].string;;
+    break;}
+case 17:
+#line 160 "zparse.y"
+{yyval.string=yyvsp[0].string;
+	      /* this is because of the ':' */
+              errormsg("Smallicon must be enclosed in quotes.\n");
+	      yylex();yylex();
+	      ;
+    break;}
+case 18:
+#line 165 "zparse.y"
+{yyval.string=NULL;;
+    break;}
+case 19:
+#line 167 "zparse.y"
+{defLanguage=0;;
+    break;}
+case 20:
+#line 168 "zparse.y"
+{yyval.about=NULL;;
+    break;}
+case 21:
+#line 170 "zparse.y"
+{;;
+    break;}
+case 22:
+#line 172 "zparse.y"
+{yyval.about=yyvsp[0].about;yyvsp[0].about->next=yyvsp[-1].about;;
+    break;}
+case 23:
+#line 176 "zparse.y"
+{
+			       if((yyval.about=malloc(sizeof(struct z3950aboutlist)))
+				  ==NULL) {
+				 fprintf(errfile,"Malloc failed\n");
+				 return(1);
+			       }
+			       yyval.about->lang=yyvsp[-1].string;
+			       yyval.about->text=yyvsp[0].string;
+			       yyval.about->next=NULL;
+			     ;
+    break;}
+case 24:
+#line 187 "zparse.y"
+{
+			       if (defLanguage)
+		                 {
+				   fprintf(errfile,"warning: (line %d): already have a default language in config file\n",lineno);
+				 }
+			       else defLanguage=1;
+			       
+			       if((yyval.about=malloc(sizeof(struct z3950aboutlist)))
+				  ==NULL) {
+				 fprintf(errfile,"Malloc failed\n");
+				 return(1);
+			       }
+			       yyval.about->lang=NULL; /* default lang... */
+			       yyval.about->text=yyvsp[0].string;
+			       yyval.about->next=NULL;
+			     ;
+    break;}
+case 25:
+#line 209 "zparse.y"
+{
+			       yyval.string=malloc(strlen(yyvsp[-2].string)+strlen(yyvsp[0].string)+1);
+			       strncpy(yyval.string,yyvsp[-2].string,strlen(yyvsp[-2].string));
+			       yyval.string[strlen(yyvsp[-2].string)]='_';
+			       strncpy(yyval.string+strlen(yyvsp[-2].string)+1,yyvsp[0].string,strlen(yyvsp[0].string));
+			       free(yyvsp[-2].string);free(yyvsp[0].string);
+			     ;
+    break;}
+case 26:
+#line 216 "zparse.y"
+{;;
+    break;}
+case 27:
+#line 224 "zparse.y"
+{errormsg("missing language");;
+    break;}
+}
+   /* the action file gets copied in in place of this dollarsign */
+#line 543 "/usr/share/bison.simple"
+
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+  yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+  *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+  yylsp++;
+  if (yylen == 0)
+    {
+      yylsp->first_line = yylloc.first_line;
+      yylsp->first_column = yylloc.first_column;
+      yylsp->last_line = (yylsp-1)->last_line;
+      yylsp->last_column = (yylsp-1)->last_column;
+      yylsp->text = 0;
+    }
+  else
+    {
+      yylsp->last_line = (yylsp+yylen-1)->last_line;
+      yylsp->last_column = (yylsp+yylen-1)->last_column;
+    }
+#endif
+
+  /* Now "shift" the result of the reduction.
+     Determine what state that goes to,
+     based on the state we popped back to
+     and the rule number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTBASE];
+
+  goto yynewstate;
+
+yyerrlab:   /* here on detecting error */
+
+  if (! yyerrstatus)
+    /* If not already recovering from an error, report this error.  */
+    {
+      ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (yyn > YYFLAG && yyn < YYLAST)
+	{
+	  int size = 0;
+	  char *msg;
+	  int x, count;
+
+	  count = 0;
+	  /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */
+	  for (x = (yyn < 0 ? -yyn : 0);
+	       x < (sizeof(yytname) / sizeof(char *)); x++)
+	    if (yycheck[x + yyn] == x)
+	      size += strlen(yytname[x]) + 15, count++;
+	  msg = (char *) malloc(size + 15);
+	  if (msg != 0)
+	    {
+	      strcpy(msg, "parse error");
+
+	      if (count < 5)
+		{
+		  count = 0;
+		  for (x = (yyn < 0 ? -yyn : 0);
+		       x < (sizeof(yytname) / sizeof(char *)); x++)
+		    if (yycheck[x + yyn] == x)
+		      {
+			strcat(msg, count == 0 ? ", expecting `" : " or `");
+			strcat(msg, yytname[x]);
+			strcat(msg, "'");
+			count++;
+		      }
+		}
+	      yyerror(msg);
+	      free(msg);
+	    }
+	  else
+	    yyerror ("parse error; also virtual memory exceeded");
+	}
+      else
+#endif /* YYERROR_VERBOSE */
+	yyerror("parse error");
+    }
+
+  goto yyerrlab1;
+yyerrlab1:   /* here on error raised explicitly by an action */
+
+  if (yyerrstatus == 3)
+    {
+      /* if just tried and failed to reuse lookahead token after an error, discard it.  */
+
+      /* return failure if at end of input */
+      if (yychar == YYEOF)
+	YYABORT;
+
+#if YYDEBUG != 0
+      if (yydebug)
+	fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+      yychar = YYEMPTY;
+    }
+
+  /* Else will try to reuse lookahead token
+     after shifting the error token.  */
+
+  yyerrstatus = 3;		/* Each real token shifted decrements this */
+
+  goto yyerrhandle;
+
+yyerrdefault:  /* current state does not do anything special for the error token. */
+
+#if 0
+  /* This is wrong; only states that explicitly want error tokens
+     should shift them.  */
+  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
+  if (yyn) goto yydefault;
+#endif
+
+yyerrpop:   /* pop the current state because it cannot handle the error token */
+
+  if (yyssp == yyss) YYABORT;
+  yyvsp--;
+  yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+  yylsp--;
+#endif
+
+#if YYDEBUG != 0
+  if (yydebug)
+    {
+      short *ssp1 = yyss - 1;
+      fprintf (stderr, "Error: state stack now");
+      while (ssp1 != yyssp)
+	fprintf (stderr, " %d", *++ssp1);
+      fprintf (stderr, "\n");
+    }
+#endif
+
+yyerrhandle:
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yyerrdefault;
+
+  yyn += YYTERROR;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+    goto yyerrdefault;
+
+  yyn = yytable[yyn];
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+	goto yyerrpop;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrpop;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+#if YYDEBUG != 0
+  if (yydebug)
+    fprintf(stderr, "Shifting error token, ");
+#endif
+
+  *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  yystate = yyn;
+  goto yynewstate;
+
+ yyacceptlab:
+  /* YYACCEPT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 0;
+
+ yyabortlab:
+  /* YYABORT comes here.  */
+  if (yyfree_stacks)
+    {
+      free (yyss);
+      free (yyvs);
+#ifdef YYLSP_NEEDED
+      free (yyls);
+#endif
+    }
+  return 1;
+}
+#line 233 "zparse.y"
+
+/*int strncasecmp (const char *, const char *,size_t);*/
+int yyerror(char *string) {
+  fprintf(errfile,"Parse error (line %d) near \n\"%s\"<---:%s\n",lineno,
+	  yylval.string,string);
+  return(1);
+}
+
+void errormsg(char *str) {
+  fprintf(errfile,"Err (line %d, near \"%s\"): %s.\n",lineno,
+	  yylval.string,str);
+}
+
+/* *
+int main (int argc, char *argv[]) {
+  if (argc==2)
+    if (argv[1][0]=='-'&&argv[1][1]=='d')
+      yydebug=1;
+
+  yyparse();
+  return(0);
+}
+* */
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/zparse.tab.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/zparse.tab.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/zparse.tab.h	(revision 10506)
@@ -0,0 +1,48 @@
+typedef union {
+  char *string;
+  struct z3950cfg *cfg;
+  struct z3950aboutlist *about;
+  int number;
+} YYSTYPE;
+#define	GSDLVERSION	257
+#define	GENERAL_SECTION	258
+#define	SEARCH_SECTION	259
+#define	BROWSE_SECTION	260
+#define	MACROS_SECTION	261
+#define	MAINTAINER	262
+#define	PUBLIC	263
+#define	TRUE	264
+#define	FALSE	265
+#define	LANGUAGES	266
+#define	EN	267
+#define	FR	268
+#define	MI	269
+#define	ZH	270
+#define	DE	271
+#define	NAME	272
+#define	STRING	273
+#define	ICON	274
+#define	SMALLICON	275
+#define	ABOUT	276
+#define	SEARCHTEXT	277
+#define	DOCUMENT	278
+#define	SECTION	279
+#define	BROWSE	280
+#define	TYPE	281
+#define	FORMAT	282
+#define	LIST	283
+#define	SORTEDLIST	284
+#define	SECTIONLIST	285
+#define	SORTEDSECTIONLIST	286
+#define	DATELIST	287
+#define	ICONLINK	288
+#define	TEXTLINK	289
+#define	DOCUMENTIMAGES	290
+#define	DOCUMENTHEADER	291
+#define	DOCUMENTTEXT	292
+#define	DOCUMENTBUTTONS	293
+#define	DOCUMENTARROWSBOTTOM	294
+#define	DATA	295
+
+
+extern YYSTYPE yylval;
Index: /tags/gsdl-2_61-distribution/gsdl/src/recpt/zparse.y
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/recpt/zparse.y	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/recpt/zparse.y	(revision 10506)
@@ -0,0 +1,255 @@
+/* RUN-TIME CONFIGURATION FILE PARSER */
+/**********************************************************************
+ *
+ * zparse.y --
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+%{
+  /* verbatim C code - functions, etc */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "z3950cfg.h"
+
+#define YYDEBUG 1
+#define YYERROR_VERBOSE 1
+/* can't use default yyparse(), as this name is used elsewhere (eg mg)*/
+#define yyin    zconfigin
+#define yyparse zconfigparse
+char defLanguage=0;
+
+/* defined in parse.fl */
+extern int lineno;
+
+#ifndef YYRECOVERING
+int YYRECOVERING=0; /* this is supposed to already be defined as a macro */
+#endif
+
+/* defined in z3950proto.cpp */
+struct z3950cfg *zserver_list=NULL;
+
+/* this is set in z3950proto.cpp */
+FILE *errfile;
+
+int yylex(void);
+
+int yyerror(char *string);
+
+void errormsg(char *str);
+
+%}
+
+
+%union {
+  char *string;
+  struct z3950cfg *cfg;
+  struct z3950aboutlist *about;
+  int number;
+}
+
+
+/* keywords */
+/***** NOTE: can explicitly give values for each token, AND
+give a string for the token name eg 
+%token GSDLVERSION 257  "Version"
+*******/
+%token GSDLVERSION 257
+%token GENERAL_SECTION 258 SEARCH_SECTION 259 
+%token BROWSE_SECTION 260 MACROS_SECTION 261
+%token MAINTAINER 262
+%token PUBLIC 263
+%token TRUE 264 FALSE 265
+%token LANGUAGES 266 EN 267 FR 268 MI 269 ZH 270 DE 271
+%token NAME 272
+%token <string> STRING 273
+%token ICON 274 SMALLICON 275
+%token ABOUT 276
+%token SEARCHTEXT 277
+%token DOCUMENT 278 SECTION 279
+%token BROWSE 280 TYPE 281 FORMAT 282
+/* classifiers */
+%token  LIST 283 SORTEDLIST 284 SECTIONLIST 285 SORTEDSECTIONLIST 286 
+%token DATELIST 287
+/* formats */
+%token  ICONLINK 288 TEXTLINK 289
+/* layouts */
+%token  DOCUMENTIMAGES 290 DOCUMENTHEADER 291 DOCUMENTTEXT 292
+%token  DOCUMENTBUTTONS 293 DOCUMENTARROWSBOTTOM 294
+
+/* all other text */
+%token <string> DATA 295
+
+%type <cfg>      zserver zserverlist
+%type <number>  port
+%type <string>   icon smallicon lang name
+%type <about>    about aboutLang aboutList
+%%
+/* grammar */
+z3950         : version zserverlist {zserver_list=$2;}
+              | version {zserver_list=NULL;} /* if all commented out or none... */
+
+
+version       : GSDLVERSION {;}
+              | {fprintf(errfile,"No version - not GSDL config file?\n");return(1);}
+
+zserverlist   : zserverlist zserver {if ($2!=NULL) {$2->next=$1;$$=$2;}}
+              | zserver ;
+
+zserver       : DATA DATA port DATA name icon smallicon about 
+                   {
+		     if (YYRECOVERING)
+		       {$$=NULL;YYRECOVERING=0;} 
+		     else {
+		       if(($$=malloc(sizeof(struct z3950cfg)))==NULL)
+			 {
+			   fprintf(errfile,"malloc failed\n");
+			   return(1);
+			 }
+		       $$->shortname=$1;
+		       $$->hostname=$2;
+		       $$->port=$3;
+		       $$->dbname=$4;
+		       $$->longname=$5;
+		       $$->icon=$6;
+		       $$->smallicon=$7;
+		       $$->about=$8;
+		       $$->next=NULL;
+		     }
+		   }
+              | error {$$=NULL;
+	      fprintf(errfile,"discarding zserver (line %d)\n",lineno);}
+              ;
+
+name          : STRING {;}
+              | {errormsg("Database name needs to be followed by a short "
+			  "descriptive name (enclosed in \" marks)");
+	         $$=NULL;
+	         YYRECOVERING=1;} /* we should scrap this server */
+
+port          : ':' DATA {$$=atoi($2);}
+              | {$$=210;} /* default z39.50 server port */
+              ;
+
+icon          : ICON STRING {$$=$2;}
+              | ICON DATA {$$=$2;
+                  errormsg("Icon must be enclosed in quotes");
+	      yylex();yylex();}
+              | {$$=NULL;}
+smallicon     : SMALLICON STRING {$$=$2;}
+              | SMALLICON DATA {$$=$2;
+	      /* this is because of the ':' */
+              errormsg("Smallicon must be enclosed in quotes.\n");
+	      yylex();yylex();
+	      }
+              | {$$=NULL;}
+
+about         : aboutList {defLanguage=0;}
+              | {$$=NULL;}
+
+aboutList     : aboutLang {;}
+                      /* note this action reverses the order of the list */
+              | aboutList aboutLang {$$=$2;$2->next=$1;} 
+
+
+aboutLang     : ABOUT lang STRING 
+                             {
+			       if(($$=malloc(sizeof(struct z3950aboutlist)))
+				  ==NULL) {
+				 fprintf(errfile,"Malloc failed\n");
+				 return(1);
+			       }
+			       $$->lang=$2;
+			       $$->text=$3;
+			       $$->next=NULL;
+			     }
+              | ABOUT STRING 
+                             {
+			       if (defLanguage)
+		                 {
+				   fprintf(errfile,"warning: (line %d): already have a default language in config file\n",lineno);
+				 }
+			       else defLanguage=1;
+			       
+			       if(($$=malloc(sizeof(struct z3950aboutlist)))
+				  ==NULL) {
+				 fprintf(errfile,"Malloc failed\n");
+				 return(1);
+			       }
+			       $$->lang=NULL; /* default lang... */
+			       $$->text=$2;
+			       $$->next=NULL;
+			     }
+/* this can only happen once (default lang) */
+
+
+/* languages should be done using a lookup, rather than hard-coding 
+   them as tokens. Also '_' token for en_BR */
+lang          : DATA '_' DATA 
+                             {
+			       $$=malloc(strlen($1)+strlen($3)+1);
+			       strncpy($$,$1,strlen($1));
+			       $$[strlen($1)]='_';
+			       strncpy($$+strlen($1)+1,$3,strlen($3));
+			       free($1);free($3);
+			     }
+              | DATA {;}
+/*lang '_' DATA {;} */
+/*              | EN {;}
+		| FR {;}
+		| MI {;}
+		| ZH {;}
+		| DE {;}
+		| DATA {errormsg("unknown language");}*/
+              | error {errormsg("missing language");}
+
+/*documentHeader : DOCUMENTHEADER STRING {;}
+              | {;}
+
+documentText  : DOCUMENTTEXT STRING {;}
+              | {;}
+*/
+
+%%
+/*int strncasecmp (const char *, const char *,size_t);*/
+int yyerror(char *string) {
+  fprintf(errfile,"Parse error (line %d) near \n\"%s\"<---:%s\n",lineno,
+	  yylval.string,string);
+  return(1);
+}
+
+void errormsg(char *str) {
+  fprintf(errfile,"Err (line %d, near \"%s\"): %s.\n",lineno,
+	  yylval.string,str);
+}
+
+/* *
+int main (int argc, char *argv[]) {
+  if (argc==2)
+    if (argv[1][0]=='-'&&argv[1][1]=='d')
+      yydebug=1;
+
+  yyparse();
+  return(0);
+}
+* */
Index: /tags/gsdl-2_61-distribution/gsdl/src/setpasswd/setpasswd.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/setpasswd/setpasswd.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/setpasswd/setpasswd.cpp	(revision 10506)
@@ -0,0 +1,176 @@
+/**********************************************************************
+ *
+ * setpasswd.cpp -- 
+ * Copyright (C) 2000  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+// setpasswd is a windows application that can be used to encrypt a password
+// and write it (along with its corresponding username) to a gdbm database.
+
+// it handles writing to the gdbm database itself to avoid having to call
+// the txt2db console application (and therefore avoiding the console
+// window popping up when called from another windows application).
+
+// note that setpasswd does no checking to make sure that any of it's
+// input arguments are valid (or even reasonable) values.
+
+// this program should be compiled into a binary called setpw.exe (to be
+// short enough not to mess with 16 bit Windows platforms).
+
+// usage:
+// setpw -u username -p password -o output_gdbm_file
+
+#include "text_t.h"
+#include "crypt.h"
+#include "autoconf.h"
+#include "systems.h"
+#include "gdbmconst.h"
+#include "gdbm.h"
+
+#include <windows.h>
+
+text_t username;
+text_t password;
+text_t output_gdbm_file;
+
+bool parse_cmdline (LPSTR cmdline) {
+
+  bool in_quote = false;
+  text_t arg;
+  text_tarray args;
+  unsigned char *c = (unsigned char *)cmdline;
+  while (*c != '\0') {
+    if (*c == '"') {
+      if (!in_quote) {
+	in_quote = true;
+      } else {
+	in_quote = false;
+	if (!arg.empty()) args.push_back (arg);
+	arg.clear();
+      }
+    } else if (*c == ' ' && !in_quote) {
+      if (!arg.empty()) args.push_back (arg);
+      arg.clear();
+    } else {
+      arg.push_back (*c);
+    }
+    ++c;
+  }
+  if (!arg.empty()) args.push_back (arg);
+  
+  text_tarray::const_iterator here = args.begin();
+  text_tarray::const_iterator end = args.end();
+  while (here != end) {
+    if (*here == "-u" && (++here != end)) username = *here;
+    else if (*here == "-p" && (++here != end)) password = *here;
+    else if (*here == "-o" && (++here != end)) output_gdbm_file = *here;
+    if (here != end) ++here;
+  }
+  if (username.empty() || password.empty() || output_gdbm_file.empty()) {
+    MessageBox (NULL, "Usage:\n setpasswd -u username -p password -o output_gdbm_file", 
+		"setpasswd failed", MB_OK);
+    return false;
+  }
+  return true;
+}
+
+text_t crypt_text (const text_t &text) {
+  static const char *salt = "Tp";
+  text_t crypt_password;
+
+  if (text.empty()) return "";
+
+  // encrypt the password
+  char *text_cstr = text.getcstr();
+  if (text_cstr == NULL) return "";
+  crypt_password = crypt(text_cstr, salt);
+  delete []text_cstr;
+
+  return crypt_password;
+}
+
+bool add_to_db () {
+
+  int block_size = 0;
+  GDBM_FILE dbf;
+  char *dbname = output_gdbm_file.getcstr();
+
+  // open the database
+  int read_write = GDBM_WRCREAT;
+  dbf = gdbm_open (dbname, block_size, read_write, 00664, NULL, 1);
+  if (dbf == NULL) {
+    MessageBox (NULL, "gdbm_open failed\n", "setpasswd", MB_OK);
+    return false;
+  }
+
+  datum key_data;
+  key_data.dptr = username.getcstr();
+  if (key_data.dptr == NULL) {
+    MessageBox (NULL, "null key_data\n", "setpasswd", MB_OK);
+    return false;
+  }
+  key_data.dsize = strlen(key_data.dptr);
+
+  text_t value = "<comment>\n";
+  value += "<enabled>true\n";
+  value += "<groups>administrator,colbuilder\n";
+  value += "<password>" + password + "\n";
+  value += "<username>" + username + "\n";
+      
+  datum value_data;
+  value_data.dptr = value.getcstr();
+  if (value_data.dptr == NULL) {
+    MessageBox (NULL, "null value_data\n", "setpasswd", MB_OK);
+    return false;
+  }
+  value_data.dsize = strlen(value_data.dptr);
+      
+  // store the value
+  if (gdbm_store (dbf, key_data, value_data, GDBM_REPLACE) < 0) {
+    MessageBox (NULL, "gdbm_store failed\n", "setpasswd", MB_OK);
+    return false;
+  }
+  gdbm_close (dbf);
+
+  delete []key_data.dptr;
+  delete []value_data.dptr;
+  delete []dbname;
+  return true;
+}
+
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+                     LPSTR lpCmdLine, int nCmdShow) {
+
+  // parse command line arguments
+  if (!parse_cmdline (lpCmdLine)) return 1;
+
+  // encrypt the password
+  password = crypt_text (password);
+
+  // append the password and username to database
+  add_to_db();
+  
+  return 0;
+}
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/txt2db/Makefile.in
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/txt2db/Makefile.in	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/txt2db/Makefile.in	(revision 10506)
@@ -0,0 +1,97 @@
+###########################################################################
+#
+# Makefile -- Makefile for txt2db
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 Rodger McNab, Stefan Boddie
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#       @(#)Makefile.in	1.3 16 Mar 1994
+#
+###########################################################################
+
+ 
+AR = ar
+CC = @CC@
+CPP = @CXX@
+CCFLAGS = -Wall @CFLAGS@
+DEFS = @DEFS@
+RANLIB = @RANLIB@
+INCLUDES = -I../../lib @GDBM_INCLUDE@
+LDFLAGS = @LDFLAGS@ 
+DPLIBS = ../../lib/gsdllib.a ../../packages/mg/lib/unitool.o
+LIBS = ../../lib/gsdllib.a ../../packages/mg/lib/unitool.o @GDBM_LIBPATH@ -lgdbm @LIBS@
+GSDLOS = @gsdlos@
+INSTALL = @INSTALL@
+ 
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CCFLAGS)
+CPPCOMPILE = $(CPP) -c $(DEFS) $(INCLUDES) $(CCFLAGS)
+MCOMPILE = ../../bin/linux/mico-c++ $(MCFLAGS) $(DEFS) $(MINCLUDES) -c
+LINK = $(CC) $(LDFLAGS) -o $@
+MLINK = ../../bin/linux/mico-ld $(LDFLAGS) -lmico2.2.7 -o $@
+CPPLINK = $(CPP) $(LDFLAGS) -o $@
+ 
+.SUFFIXES:
+.SUFFIXES: .c .o
+.c.o:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .o
+.cpp.o:
+	$(CPPCOMPILE) $< 
+ 
+.SUFFIXES: .mpp .o
+.mpp.o:
+	$(MCOMPILE) $<
+
+HEADERS = 
+
+SOURCES = txt2db.cpp
+
+OBJECTS = txt2db.o
+
+EXEC    = txt2db
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	$(INSTALL) -d ../../bin/$(GSDLOS)
+	$(INSTALL) -m 755 -s $(EXEC) ../../bin/$(GSDLOS)
+
+distclean:
+	rm -f $(OBJECTS) $(EXEC) Makefile
+
+clean:
+	rm -f $(OBJECTS) $(EXEC)
+
+depend:
+	makedepend -Y -- $(DEFS) $(INCLUDES) $(CCFLAGS) -- $(SOURCES)
+
+
+# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+TXT2DB_OBJS = txt2db.o
+
+txt2db: $(TXT2DB_OBJS) $(DPLIBS)
+	$(CPPLINK) $(TXT2DB_OBJS) $(LIBS)
+
+
+
+
+
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/txt2db/txt2db.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/txt2db/txt2db.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/txt2db/txt2db.cpp	(revision 10506)
@@ -0,0 +1,171 @@
+/**********************************************************************
+ *
+ * txt2db.cpp -- 
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the 
+ * University of Waikato, New Zealand.
+ *
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ **********************************************************************/
+
+
+#ifdef __WIN32__
+#include "autoconf.h"
+#include "systems.h"
+#include "gdbmconst.h"
+#include "gdbm.h"
+
+#else
+#include <gdbm.h>
+#endif
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include <stdlib.h>
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\iostream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <iostream.h>
+#else
+#  include <iostream>
+#endif
+
+
+void print_usage (char *program_name) {
+  cerr << "usage: " << program_name << " [options] database-name\n\n";
+  cerr << "options:\n";
+  cerr << " -append        append to existing database\n\n";
+}
+
+
+int main (int argc, char *argv[]) {
+  int block_size = 0;
+  GDBM_FILE dbf;
+  char c;
+  text_t key;
+  text_t value;
+  text_t tmp;
+  int num_dashes = 0;
+
+  // sanity check
+  if (argc != 2 && argc != 3) {
+    print_usage (argv[0]);
+    exit (0);
+  }
+  
+  char *dbname;
+  int append = 0;
+  if (argc == 3) {
+    if (strcmp (argv[1], "-append") == 0) {
+      append = 1;
+      dbname = argv[2];
+    } else {
+      cerr << argv[1] << " is not a valid option.\n\n";
+      print_usage (argv[0]);
+      exit (0);
+    }
+  } else dbname = argv[1];
+
+  
+  // open the database
+  // note that GDBM_FAST is obsolete on newer versions of gdbm
+  int read_write = GDBM_NEWDB | GDBM_FAST;
+  if (append) read_write = GDBM_WRCREAT | GDBM_FAST;
+  
+#ifdef __WIN32__
+  dbf = gdbm_open (dbname, block_size, read_write, 00664, NULL, 1);
+#else
+  dbf = gdbm_open  (dbname, block_size, read_write, 00664, NULL);
+#endif
+  if (dbf == NULL) {
+    cerr << "couldn't create " << dbname << "\n";
+    exit (0);
+  }
+  
+  cin.get(c);
+  while (!cin.eof()) {
+    num_dashes = 0;
+    key = "";
+    value = "";
+    
+    // look for [key]\n
+    while (!cin.eof() && c != '[') cin.get(c);
+    if (!cin.eof()) cin.get(c); // skip [
+    while (!cin.eof() && c != ']') {
+      key.push_back ((unsigned char)c);
+      cin.get(c);
+    }
+    if (!cin.eof()) cin.get(c); // skip ]
+    while (!cin.eof() && (c == '\n' || c == 'r')) cin.get(c);
+    
+    // look for 70 dashes
+    tmp = "";
+    while (!cin.eof() && (num_dashes < 70)) {
+      if (c == '\n' || c == '\r') {
+	tmp.push_back ((unsigned char)c);
+	num_dashes = 0;
+	
+      } else if (c == '-') {
+	tmp.push_back ((unsigned char)c);
+	++num_dashes;
+	
+      } else {
+	value += tmp;
+	value.push_back ((unsigned char)c);
+	tmp = "";
+	num_dashes = 0;
+      }
+      cin.get(c);
+    }
+    
+    // if the key is not an empty string store this key-value pair
+    if (!key.empty()) {
+      // convert key to a datum datatype
+      datum key_data;
+      key_data.dptr = key.getcstr();
+      if (key_data.dptr == NULL) {
+	cerr << "NULL key_data.dptr\n";
+	exit (0);
+      }
+      key_data.dsize = strlen(key_data.dptr);
+      
+      // convert value to a datum datatype
+      datum value_data;
+      value_data.dptr = value.getcstr();
+      if (value_data.dptr == NULL) {
+	cerr << "NULL value_data.dptr\n";
+	exit (0);
+      }
+      value_data.dsize = strlen(value_data.dptr);
+      
+      // store the value
+      if (gdbm_store (dbf, key_data, value_data, GDBM_REPLACE) < 0) {
+	cerr << "gdbm_store returned an error\n";
+	exit (0);
+      }
+      
+      delete []key_data.dptr;
+      delete []value_data.dptr;
+    }
+  }
+  
+  gdbm_close (dbf);
+  
+  return 0;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/txt2db/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/txt2db/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/txt2db/win32.mak	(revision 10506)
@@ -0,0 +1,78 @@
+###########################################################################
+#
+# win32 makefile -- txt2db
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..\..
+USE_STLPORT = 0
+STLPATH = "$(GSDLHOME)\packages\windows\stlport\stlport"
+
+AR = lib
+CC = cl
+CPPFLAGS = 
+LDFLAGS =
+
+DEFS = -D__WIN32__ -DHAVE_CONFIG_H
+INCLUDES = -I"$(GSDLHOME)\src\txt2db" -I"$(GSDLHOME)\lib" -I"$(GSDLHOME)\packages\mg\lib" \
+	   -I"$(GSDLHOME)\packages\windows\gdbm\gdbm"
+!IF $(USE_STLPORT)
+DEFS=$(DEFS) -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = $(INCLUDES) -I$(STLPATH)
+!ENDIF
+
+LIBS = "$(GSDLHOME)\packages\mg\lib\unitool.obj" "$(GSDLHOME)\lib\gsdllib.lib" \
+       "$(GSDLHOME)\packages\windows\gdbm\gdbm\gdbm.lib"
+
+COMPILE = $(CC) -c -GX $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS)
+
+.SUFFIXES:
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $<
+
+ANSI2KNR = 
+o = .obj
+e = .exe
+ 
+HEADERS = 
+
+SOURCES = txt2db.cpp
+
+OBJECTS = txt2db$o
+
+EXEC = txt2db$e
+ 
+all : $(EXEC)
+
+install: $(EXEC)
+	if NOT EXIST "$(GSDLHOME)\bin\windows" mkdir "$(GSDLHOME)\bin\windows"
+	copy $(EXEC) "$(GSDLHOME)\bin\windows"
+
+clean:
+	del *.obj
+	del $(EXEC)
+
+txt2db$e: $(OBJECTS) $(LIBS)
+	  $(LINK) $(OBJECTS) $(LIBS)
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/cgiwrapper.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/cgiwrapper.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/cgiwrapper.cpp	(revision 10506)
@@ -0,0 +1,949 @@
+/**********************************************************************
+ *
+ * cgiwrapper.cpp -- windows local library cgiwrapper
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <direct.h>
+#include "cgiwrapper.h"
+#include "netio.h"
+#include "wincgiutils.h"
+#include "settings.h"
+#include "fileutil.h"
+
+#include "gsdlconf.h"
+#include "recptconfig.h"
+
+#if defined (GSDL_USE_OBJECTSPACE)
+#include <ospace\std\iostream>
+#include <ospace\std\fstream>
+#elif defined (GSDL_USE_IOS_H)
+#include <iostream.h>
+#include <fstream.h>
+#else
+#include <iostream>
+#include <fstream>
+#endif
+
+#include "receptionist.h"
+#include "nullproto.h"
+
+// actions
+#include "statusaction.h"
+#include "pageaction.h"
+#include "pingaction.h"
+#include "queryaction.h"
+#include "documentaction.h"
+#include "tipaction.h"
+#include "authenaction.h"
+#include "usersaction.h"
+#include "extlinkaction.h"
+#include "collectoraction.h"
+#include "phindaction.h"
+#include "configaction.h"
+
+// browsers
+#include "vlistbrowserclass.h"
+#include "hlistbrowserclass.h"
+#include "datelistbrowserclass.h"
+#include "invbrowserclass.h"
+#include "pagedbrowserclass.h"
+#include "htmlbrowserclass.h"
+#include "phindbrowserclass.h"
+
+// the number of times the library has been accessed
+int libaccessnum = 0;
+
+// used to output the text from receptionist
+class textstreambuf : public streambuf
+{
+public:
+  textstreambuf ();
+  int sync ();
+  int overflow (int ch);
+  int underflow () {return EOF;}
+  
+  void tsbreset() {RInfo=NULL;casostr=NULL;}
+  void setrequestinfo (RequestInfoT *theRInfo) {RInfo=theRInfo;}
+  void cascadeoutput (ostream *thecasostr) {casostr=thecasostr;}
+  
+private:
+  RequestInfoT *RInfo;
+  ostream *casostr;
+#if !defined (GSDL_USE_IOS_H)
+  char buffer[256];
+#endif
+};
+
+textstreambuf::textstreambuf() {
+  tsbreset();
+#if !defined (GSDL_USE_IOS_H)
+  setp (&buffer[0], &buffer[255]);
+#else
+  if (base() == ebuf()) allocate();
+  setp (base(), ebuf());
+#endif
+};
+
+int textstreambuf::sync () {
+  if ((RInfo != NULL) && 
+      (Send_String_N(pbase(), pptr()-pbase(), RInfo) < 0)) {
+    RInfo = NULL;
+  }
+  
+  if (casostr != NULL) {
+    char *thepbase=pbase();
+    for (int i=0;i<(pptr()-pbase());++i) (*casostr).put(thepbase[i]);
+  }
+  
+  setp (pbase(), epptr());
+  
+  return 0;
+}
+
+int textstreambuf::overflow (int ch) {
+  if (sync () == EOF) return EOF;
+  if (ch != EOF) sputc (ch);
+  return 0;
+}
+
+
+// used to output all the log and error messages
+// from receptionist
+class logstreambuf : public streambuf
+{
+public:
+  logstreambuf ();
+  int sync ();
+  int overflow (int ch);
+  int underflow () {return EOF;}
+
+#if !defined (GSDL_USE_IOS_H)
+private:
+  char buffer[256];
+#endif
+};
+
+logstreambuf::logstreambuf () {
+#if !defined (GSDL_USE_IOS_H)
+  setp (&buffer[0], &buffer[255]);
+#else
+  if (base() == ebuf()) allocate();
+  setp (base(), ebuf());
+#endif
+}
+
+int logstreambuf::sync () {
+  if (gsdl_keep_log || gsdl_show_console) {
+    log_message ("LOCAL LIB MESSAGE: ");
+		log_message_N (pbase(), pptr()-pbase());
+  }
+
+  setp (pbase(), epptr());
+  return 0;
+}
+
+int logstreambuf::overflow (int ch) {
+  if (sync () == EOF) return EOF;
+  if (ch != EOF) sputc (ch);
+  return 0;
+}
+
+static void page_errormaincfg (const text_t &gsdlhome, const text_t &collection) {
+
+  if (collection.empty()) {
+    text_t message = "Error\n\n"
+      "The main.cfg configuration file could not be found. This file\n"
+      "should contain configuration information relating to the\n"
+      "setup of the interface. As this program is not being run\n"
+      "in collection specific mode the file should reside at\n" +
+      gsdlhome + "\\etc\\main.cfg.\n";
+
+    MessageBox(NULL, message.getcstr(),
+	       "Greenstone Digital Library Software"
+	       ,MB_OK|MB_SYSTEMMODAL);
+  } else {
+    text_t message = "Neither the collect.cfg or main.cfg configuration files could\n"
+      "be found. This file should contain configuration information\n"
+      "relating to the setup of the interface. As this cgi script is\n"
+      "being run in collection specific mode the file should reside\n"
+      "at either " + gsdlhome + "\\collect\\" + collection + "\\etc\\collect.cfg,\n" +
+      gsdlhome + "\\etc\\collect.cfg or " + gsdlhome + "\\etc\\main.cfg.\n";
+
+    MessageBox(NULL, message.getcstr(),
+	       "Greenstone Digital Library Software"
+	       ,MB_OK|MB_SYSTEMMODAL);
+  }
+}
+
+static void page_errorinit (const text_t &/*gsdlhome*/) {
+
+  text_t message = "Error\n\n"
+    "An error occurred during the initialisation of the Greenstone Digital\n"
+    "Library software. It is likely that the software has not been setup\n"
+    "correctly.\n";
+
+  MessageBox(NULL, message.getcstr(),
+	     "Greenstone Digital Library Software"
+	     ,MB_OK|MB_SYSTEMMODAL);
+}
+
+static void page_errorparseargs (const text_t &/*gsdlhome*/) {
+
+  text_t message = "Error\n\n"
+    "An error occurred during the parsing of the cgi arguments.\n";
+
+  MessageBox(NULL, message.getcstr(),
+	     "Greenstone Digital Library Software"
+	     ,MB_OK|MB_SYSTEMMODAL);
+}
+
+static void page_errorcgipage (const text_t &/*gsdlhome*/) {
+
+  text_t message = "Error\n\n"
+    "An error occurred during the construction of the cgi page.\n";
+
+  MessageBox(NULL, message.getcstr(),
+	     "Greenstone Digital Library Software"
+	     ,MB_OK|MB_SYSTEMMODAL);
+}
+
+// returns 0 if the directories can't be found
+// and the user wants to quit (it returns 1
+// if everything is ok)
+int checkdir (const text_t &thedir) {
+  UINT curerrormode;
+  int drive = _getdrive();
+  char cwd[1024];
+  char rootpath[4];
+  UINT drivetype;
+  char *cstrthedir = thedir.getcstr();
+  int returnvalue = 1;
+  
+  // make sure no rude error messages are presented to the user
+  curerrormode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+  
+  // get the drive name
+  if (thedir.size() >= 2 && thedir[1] == ':') {
+    if (thedir[0] >= 'a' && thedir[0] <= 'z') {
+      drive = thedir[0] - 'a' + 1;
+      
+    } else if (thedir[0] >= 'A' && thedir[0] <= 'Z') {
+      drive = thedir[0] - 'A' + 1;
+    }
+  }
+  
+  // find the drive type
+  rootpath[0] = drive + 'A' - 1;
+  rootpath[1] = ':';
+  rootpath[2] = '\\';
+  rootpath[3] = '\0';
+  drivetype = GetDriveType (rootpath);
+  
+  // try and set this directory to be the current working
+  // directory
+  _getcwd(cwd, 1024);
+  while (_chdir(cstrthedir) != 0) {
+    // failed
+    if (drivetype == DRIVE_CDROM) {
+      // message to insert the cdrom
+      if (MessageBox (NULL, 
+		      "Please insert the Greenstone Digital Library\n"
+		      "CD-ROM into the CD-ROM drive and press 'OK'.\n\n"
+		      "If you don't have the CD-ROM press 'Cancel' to exit\n"
+		      "this program.", "Greenstone Digital Library Software", 
+		      MB_OKCANCEL | MB_TASKMODAL) == IDCANCEL) {
+	
+	returnvalue = 0;
+	break;
+      }
+      
+    } else {
+      // message saying that the system was unable
+      // to find a certain directory
+      text_t message = "Failed to find the directory:\n\n" + thedir;
+      message += "\n\n"
+	"This directory is needed for the successful operation\n"
+	"of this software. Make sure it hasn't been deleted or\n"
+	"moved, and restart the software. You may need to\n"
+	"reinstall this software to correct the problem.";
+      char *cstrmessage = message.getcstr();
+      
+      MessageBox (NULL, cstrmessage, "Greenstone Digital Library Software",
+		  MB_OK | MB_TASKMODAL);
+      
+      delete []cstrmessage;
+      
+      returnvalue = 0;
+      break;
+    }
+  }
+  
+  // revert to the previous error and cwd states
+  _chdir(cwd);
+  SetErrorMode(curerrormode);
+  
+  // free the allocated C string
+  delete []cstrthedir;
+  
+  return returnvalue;
+}
+
+
+// c-string version of checkdir for the outside
+// world
+int cstrcheckdir (char *cstrthedir) {
+  return checkdir (cstrthedir);
+}
+
+
+receptionist recpt;
+nullproto nproto;
+collectset *cservers = NULL;
+
+textstreambuf textstream;
+logstreambuf logstream;
+DWORD lastlibaccesstime;
+DWORD baseavailvirtual;
+text_t current_gsdlhome;
+colinfo_tmap translated_collectinfo;
+  
+statusaction *astatusaction = NULL;
+pageaction *apageaction = NULL;
+pingaction *apingaction = NULL;
+tipaction *atipaction = NULL;
+queryaction *aqueryaction = NULL;
+documentaction *adocumentaction = NULL;
+usersaction *ausersaction = NULL;
+extlinkaction *anextlinkaction = NULL;
+collectoraction *acollectoraction = NULL;
+authenaction *aauthenaction = NULL;
+phindaction *aphindaction = NULL;
+configaction *aconfigaction = NULL;
+vlistbrowserclass *avlistbrowserclass = NULL;
+hlistbrowserclass *ahlistbrowserclass = NULL;
+datelistbrowserclass *adatelistbrowserclass = NULL;
+invbrowserclass *ainvbrowserclass = NULL;
+pagedbrowserclass *apagedbrowserclass = NULL;
+htmlbrowserclass *ahtmlbrowserclass = NULL;
+phindbrowserclass *aphindbrowserclass = NULL;
+
+// returns 1 if successful, 0 if unsuccessful (note that as well as being
+// called when the server first starts up this function is called when the
+// "restart library" button is pressed)
+int gsdl_init (bool atStartup) {
+
+  if (atStartup) {
+#if defined (GSDL_USE_IOS_H)
+    cerr = &logstream;
+    cout = &textstream;
+#else
+    cerr.rdbuf(&logstream);
+    cout.rdbuf(&textstream);
+#endif
+  }
+
+  // collection should be set to "" unless in collection specific mode -
+  // changing this to the name of the collection should be all that's
+  // required to create a collection specific receptionist
+  text_t collection = "";
+  text_tset gdbmhomes;
+  text_tset collections;
+
+  if (atStartup) {
+    // note the current time
+    lastlibaccesstime = GetTickCount();
+    
+    // before we do the init we should make sure
+    // that we can find the relevant directories
+    if (!checkdir (gsdl_gsdlhome + "\\")) return 0;
+    if (!checkdir (gsdl_gsdlhome + "\\macros\\")) return 0;
+  }    
+
+  // deleting cservers clears all the collection servers 
+  if (cservers != NULL) delete cservers;
+
+  cservers = new collectset();
+
+  // get all collections from each gsdlhome (this relies 
+  // on there not being more than one collection with the same 
+  // name)
+  if (!collection.empty()) {
+    // collection specific receptionist - one collection, one gsdlhome
+    collections.insert (collection);
+    gdbmhomes.insert (gsdl_gdbmhome);
+    collectioninfo_t tmp;
+    tmp.gsdl_gsdlhome = gsdl_gsdlhome;
+    tmp.gsdl_gdbmhome = gsdl_gdbmhome;
+    translated_collectinfo[collection] = tmp;
+
+  } else {
+
+    text_tset::const_iterator colhere;
+    text_tset::const_iterator colend;
+    text_tset these_collections;
+
+    // first volume gsdlhome's
+    colinfo_tmap::const_iterator this_info = gsdl_collectinfo.begin();
+    colinfo_tmap::const_iterator end_info = gsdl_collectinfo.end();
+    while (this_info != end_info) {
+      if (gdbmhomes.find ((*this_info).second.gsdl_gdbmhome) == gdbmhomes.end()) {
+	these_collections.erase (these_collections.begin(), these_collections.end());
+	read_dir (filename_cat ((*this_info).second.gsdl_gsdlhome, "collect"), these_collections);
+	colhere = these_collections.begin();
+	colend = these_collections.end();
+	while (colhere != colend) {
+	  if ((collections.find (*colhere)) == collections.end()) {
+	    // make sure the build.cfg file is at gsdlhome (as it's possible that
+	    // the collection appears at this gsdlhome only because it's gdbm
+	    // file is installed here -- it's real gdbm will therefore be 
+	    // somewhere else).
+	    text_t build_cfg = filename_cat ((*this_info).second.gsdl_gsdlhome, "collect",
+					     *colhere, "index", "build.cfg");
+	    if (file_exists (build_cfg)) {
+	      collections.insert (*colhere);
+
+	      // since gsdl_collectinfo keys will be stuff like collection#1
+	      // for a multiple volume collection we want to translate it
+	      // so that the keys are the actual collection names
+	      translated_collectinfo[*colhere] = (*this_info).second;
+	    }
+	  }
+	  ++colhere;
+	}
+	gdbmhomes.insert ((*this_info).second.gsdl_gdbmhome);
+      }
+      ++this_info;
+    }
+  
+    // then if necessary the main gdbmhome (this should only happen if the 
+    // gsdl.ini is a little screwed up and no volume gdbmhomes occurred)
+    if (gdbmhomes.find (gsdl_gdbmhome) == gdbmhomes.end()) {
+      these_collections.erase (these_collections.begin(), these_collections.end());
+      read_dir (filename_cat (gsdl_gdbmhome, "collect"), these_collections);
+      colhere = these_collections.begin();
+      colend = these_collections.end();
+      while (colhere != colend) {
+	collections.insert (*colhere);
+	collectioninfo_t tmp;
+	tmp.gsdl_gsdlhome = gsdl_gsdlhome;
+	tmp.gsdl_gdbmhome = gsdl_gdbmhome;
+	translated_collectinfo[*colhere] = tmp;
+	++colhere;
+      }
+      gdbmhomes.insert (gsdl_gdbmhome);
+    }
+  }
+
+  text_tset::const_iterator thiscol = collections.begin();
+  text_tset::const_iterator endcol = collections.end();
+
+  while (thiscol != endcol) {
+    
+    // ignore the modelcol
+    if (*thiscol == "modelcol") {
+      ++thiscol;
+      continue;
+    }
+    
+    // create collection server and add to null protocol
+    text_t this_gsdlhome = gsdl_gsdlhome;
+    text_t this_gdbmhome = gsdl_gdbmhome;
+    colinfo_tmap::const_iterator it = translated_collectinfo.find (*thiscol);
+    assert (it != translated_collectinfo.end());
+    this_gsdlhome = (*it).second.gsdl_gsdlhome;
+    this_gdbmhome = (*it).second.gsdl_gdbmhome;
+
+    cservers->add_collection (*thiscol, this_gsdlhome);
+
+    ++thiscol;
+  }
+
+  // set up the null protocol
+  nproto.set_collectset(cservers);
+  
+  // add the protocol to the receptionist
+  if (atStartup) recpt.add_protocol (&nproto);
+  
+  // the list of actions.
+  if (astatusaction == NULL) {
+    astatusaction = new statusaction();
+    astatusaction->set_receptionist (&recpt);
+    recpt.add_action (astatusaction);
+  }
+  
+  if (apageaction == NULL) {
+    apageaction = new pageaction();
+    apageaction->set_receptionist (&recpt);
+    recpt.add_action (apageaction);
+  }
+  
+  if (apingaction == NULL) {
+    apingaction = new pingaction();
+    recpt.add_action (apingaction);
+  }
+  
+  if (atipaction == NULL) {
+    atipaction = new tipaction();
+    recpt.add_action (atipaction);
+  }
+  
+  if (aqueryaction == NULL) {
+    aqueryaction = new queryaction();
+    aqueryaction->set_receptionist (&recpt);
+    recpt.add_action (aqueryaction);
+  }
+  
+  if (adocumentaction == NULL) {
+    adocumentaction = new documentaction();
+    adocumentaction->set_receptionist (&recpt);
+    recpt.add_action (adocumentaction);
+  }
+  
+  if (ausersaction == NULL) {
+    ausersaction = new usersaction();
+    recpt.add_action (ausersaction);
+  }
+
+  if (anextlinkaction == NULL) {
+    anextlinkaction = new extlinkaction();
+    recpt.add_action (anextlinkaction);
+  }
+
+  if (acollectoraction == NULL) {
+    acollectoraction = new collectoraction();
+    acollectoraction->set_receptionist (&recpt);
+    recpt.add_action (acollectoraction);
+  }
+  
+  if (aauthenaction == NULL) {
+    aauthenaction = new authenaction();
+    aauthenaction->set_receptionist(&recpt);
+    recpt.add_action (aauthenaction);
+  }
+
+  if (aphindaction == NULL) {
+    aphindaction = new phindaction();
+    recpt.add_action (aphindaction);
+  }
+  
+  if (aconfigaction == NULL) {
+    aconfigaction = new configaction();
+    aconfigaction->set_receptionist(&recpt);
+    recpt.add_action (aconfigaction);
+  }
+
+
+  // list of browsers
+  if (avlistbrowserclass == NULL) {
+    avlistbrowserclass = new vlistbrowserclass();
+    recpt.add_browser (avlistbrowserclass);
+    recpt.setdefaultbrowser ("VList");
+  }
+
+  if (ahlistbrowserclass == NULL) {
+    ahlistbrowserclass = new hlistbrowserclass();
+    recpt.add_browser (ahlistbrowserclass);
+  }
+
+  if (adatelistbrowserclass == NULL) {
+    adatelistbrowserclass = new datelistbrowserclass();
+    recpt.add_browser (adatelistbrowserclass);
+  }
+
+  if (ainvbrowserclass == NULL) {
+    ainvbrowserclass = new invbrowserclass();
+    recpt.add_browser (ainvbrowserclass);
+  }
+
+  if (apagedbrowserclass == NULL) {
+    apagedbrowserclass = new pagedbrowserclass();
+    recpt.add_browser (apagedbrowserclass);
+  }
+
+  if (ahtmlbrowserclass == NULL) {
+    ahtmlbrowserclass = new htmlbrowserclass();
+    recpt.add_browser (ahtmlbrowserclass);
+  }
+
+  if (aphindbrowserclass == NULL) {
+    aphindbrowserclass = new phindbrowserclass();;
+    recpt.add_browser (aphindbrowserclass);
+  }
+  
+  // set defaults
+  recpt.configure ("gsdlhome", gsdl_gsdlhome);
+  recpt.configure ("gdbmhome", gsdl_gdbmhome);
+  recpt.configure ("collection", collection);
+
+  int maxrequests = 1;
+
+  // configure collections (and receptionist) with collectinfo stuff
+  // different from the default
+  colinfo_tmap::const_iterator this_info = translated_collectinfo.begin();
+  colinfo_tmap::const_iterator end_info = translated_collectinfo.end();
+
+  while (this_info != end_info) {
+    text_tarray tmpconf;
+    tmpconf.push_back ((*this_info).first);
+    tmpconf.push_back ((*this_info).second.gsdl_gsdlhome);
+    tmpconf.push_back ((*this_info).second.gsdl_gdbmhome);
+    recpt.configure ("collectinfo", tmpconf);
+    ++this_info;
+  }
+
+  // read in config files of each gdbmhome (in no particular order)
+  // those read in last will override those read earlier
+  // collections being used together in this way should be 
+  // careful not to have main.cfg files that might 
+  // screw with each other.
+  text_tset::const_iterator thome = gdbmhomes.begin();
+  text_tset::const_iterator ehome = gdbmhomes.end();
+  while (thome != ehome) {
+    if (!main_cfg_read (recpt, *thome, collection)) {
+      // couldn't find the main configuration file
+      page_errormaincfg (*thome, collection);
+      return 0;
+    }
+    ++thome;
+  }
+
+  // w32server relies on gwcgi being set to "gsdl"
+  recpt.configure ("gwcgi", "gsdl");
+	
+  // initialise the library software
+  if (!recpt.init(cerr)) {
+    // an error occurred during the initialisation
+    page_errorinit(gsdl_gsdlhome);
+    return 0;
+  }
+
+  // get memory information
+  MEMORYSTATUS memstatus;
+  memstatus.dwLength = sizeof(MEMORYSTATUS);
+  GlobalMemoryStatus(&memstatus);
+  baseavailvirtual = memstatus.dwAvailVirtual; // save for later comparison
+
+  return 1;
+}
+
+
+static void rememberpref (const text_t &tailstr) {
+  gsdl_enterlib = tailstr;
+}
+
+
+static void send_file_from_disk(text_t filename,
+                                RequestInfoT *RInfo,
+                                RequestFieldsT *RFields) {
+  
+  // select appropriate mime type from file extension
+  text_t ext;
+  text_t::const_iterator end = filename.end();
+  text_t::const_iterator it = filename.begin();
+  text_t::const_iterator lastdot = end;
+  while ((it = findchar(it, end, '.')) != end) {
+    lastdot = it;
+    ++it;
+  }
+  if (lastdot < end) ext = substr(lastdot+1, end);
+
+  text_t mime = "unknown";
+  int len = ext.size();
+  if (len == 2) {
+    if ((ext[0] == 'p' || ext[0] == 'P') &&
+	(ext[1] == 's' || ext[1] == 'S'))
+      mime = "application/postscript";
+  }  else if (len == 3) {
+    if ((ext[0] == 'g' || ext[0] == 'G') &&
+	(ext[1] == 'i' || ext[1] == 'I') &&
+	(ext[2] == 'f' || ext[2] == 'F')) {
+      mime = "image/gif";
+    } else if ((ext[0] == 'j' || ext[0] == 'J') &&
+	       (ext[1] == 'p' || ext[1] == 'P') &&
+	       (ext[2] == 'g' || ext[2] == 'G')) {
+      mime = "image/jpeg";
+    } else if ((ext[0] == 'h' || ext[0] == 'H') &&
+	       (ext[1] == 't' || ext[1] == 'T') &&
+	       (ext[2] == 'm' || ext[2] == 'M')) {
+      mime = "text/html";
+    } else if ((ext[0] == 'p' || ext[0] == 'P') &&
+	       (ext[1] == 'd' || ext[1] == 'D') &&
+	       (ext[2] == 'f' || ext[2] == 'F')) {
+      mime = "application/pdf";
+    } else if ((ext[0] == 'p' || ext[0] == 'P') &&
+	       (ext[1] == 'n' || ext[1] == 'N') &&
+	       (ext[2] == 'g' || ext[2] == 'G')) {
+      mime = "image/png";
+    } else if ((ext[0] == 'd' || ext[0] == 'D') &&
+	       (ext[1] == 'o' || ext[1] == 'O') &&
+	       (ext[2] == 'c' || ext[2] == 'C')) {
+      mime = "application/msword";
+    } else if ((ext[0] == 'r' || ext[0] == 'R') &&
+	       (ext[1] == 't' || ext[1] == 'T') &&
+	       (ext[2] == 'f' || ext[2] == 'F')) {
+      mime = "application/rtf";
+    } else if ((ext[0] == 'x' || ext[0] == 'X') &&
+	       (ext[1] == 'l' || ext[1] == 'L') &&
+	       (ext[2] == 's' || ext[2] == 'S')) {
+      mime = "application/vnd.ms-excel";
+    } else if ((ext[0] == 'p' || ext[0] == 'P') &&
+	       (ext[1] == 'p' || ext[1] == 'P') &&
+	       (ext[2] == 'T' || ext[2] == 'T')) {
+      mime = "application/vnd.ms-powerpoint";
+    }
+  } else if (len == 4) {
+    if ((ext[0] == 'j' || ext[0] == 'J') &&
+	(ext[1] == 'p' || ext[1] == 'P') &&
+	(ext[2] == 'e' || ext[2] == 'E') &&
+	(ext[3] == 'g' || ext[3] == 'G')) {
+      mime = "image/jpeg";
+    } else if ((ext[0] == 'h' || ext[0] == 'H') &&
+	       (ext[1] == 't' || ext[1] == 'T') &&
+	       (ext[2] == 'm' || ext[2] == 'M') &&
+	       (ext[3] == 'l' || ext[3] == 'L')) {
+      mime = "text/html";
+    }
+  }
+	
+  // try to open the file
+  filename = filename_cat (current_gsdlhome, filename);
+  /* Feb 2002 - handle files with spaces in their name. */
+  text_t::iterator space_start;
+  space_start=findword(filename.begin(),filename.end(),"%20");
+  while (space_start != filename.end()) {
+    // we found a space...
+    text_t::iterator after_space=space_start+3;
+    text_t new_filename=substr(filename.begin(), space_start);
+    new_filename += " ";
+    new_filename += substr(after_space,filename.end());
+    filename=new_filename;
+    space_start=findword(filename.begin(),filename.end(),"%20");
+  }
+
+  char *filenamec = filename.getcstr();
+  FILE *thefile = fopen(filenamec, "rb");
+  delete []filenamec;
+  if (thefile == NULL) {
+    log_message("file not found\n");
+    send_retrieve_error(404, "File not found",
+			"Could not find the local file requested", RInfo);
+    return;
+  }
+  int nr;
+  char buffer[2048];
+  // send back required information
+  char *mimec = mime.getcstr();
+  if (send_header(mimec, RInfo) >= 0) {
+    if (RFields->MethodStr != "HEAD") {
+      for (;;) {
+        nr = fread(buffer, 1, 2048, thefile);
+        if (nr <= 0) break;
+        if (SendData(RInfo->ClientSocket,
+                     (BYTE *)buffer, nr,
+		     RInfo->ThreadNum) < 0) break;        
+      }
+    }
+  }
+  delete []mimec;
+  fclose(thefile);
+}
+
+static void handle_library_request(const text_t &argstr, RequestInfoT *RInfo,
+				   RequestFieldsT *RequestFields) {
+
+  // parse the cgi arguments and produce the resulting page if there
+  // have been no errors so far
+  cgiargsclass args;
+  text_tmap empty; // don't use this (it's for fastcgi on unix)
+  if (!recpt.parse_cgi_args (argstr, args, cerr, empty)) {
+    page_errorparseargs(gsdl_gsdlhome);
+    return;
+  } 
+
+  colinfo_tmap::const_iterator it = translated_collectinfo.find (args["c"]);
+  if (it != translated_collectinfo.end()) {
+    current_gsdlhome = (*it).second.gsdl_gsdlhome;
+  } else {
+    current_gsdlhome = gsdl_gsdlhome;
+  }
+
+  // produce cgi header
+  response_t response;
+  text_t response_data;
+
+  recpt.get_cgihead_info (args, response, response_data, cerr, empty);
+
+  if (response == location) {
+    // location response
+    response_data = "@" + recpt.expandmacros (response_data, args, cerr);
+    char *response_data_c = response_data.getcstr();
+    send_header(response_data_c, RInfo);
+    delete []response_data_c;
+    return;
+  } else if (response == content) {
+    // content response
+    char *response_data_c = response_data.getcstr();
+    if (send_header(response_data_c, RInfo) < 0) {
+      delete []response_data_c;
+      return;
+    }
+    delete []response_data_c;
+  }
+  else if (response == undecided_location) {
+    // We know this is a relocation request but at the moment we don't know exactly where to
+    // Just output the start of the header and wait until later to output the target location
+    // Used for the "I'm feeling lucky" functionality
+    cout << "HTTP/1.0 302 Relocation\r\n";
+    cout << "Server: GSDL\r\n";
+    cout << "Content-type: text/html \r\n";
+  }
+  else {
+    // unknown response
+    cerr << "Error: get_cgihead_info returned an unknown response type.\n";
+    return;
+  }
+
+  textstream.tsbreset();
+  textstream.setrequestinfo (RInfo);
+  if (!recpt.produce_content (args, cout, cerr)) {
+    page_errorcgipage(gsdl_gsdlhome);
+    return;
+  } 
+  recpt.log_cgi_args (args, cerr, empty);
+
+  cout << flush;
+  cerr << flush;
+  
+  ++libaccessnum;
+}
+
+static void handle_server_request(text_t &tailstr,
+				  RequestInfoT *RequestInfo,
+				  RequestFieldsT *RequestFields) {
+  
+  text_t argstr;
+
+  // do any url adjustments necessary
+  if (tailstr.empty() || tailstr == "/") {
+    tailstr = "/gsdl";
+  }
+
+  text_t::const_iterator begin = tailstr.begin();
+  text_t::const_iterator end = tailstr.end();
+  
+  // test to see if this is a library request or a local
+  // file request
+  if ((tailstr == "/gsdl") ||
+      ((tailstr.size() > 5) && (substr(begin, begin+6) == "/gsdl?"))) {
+
+    // library request
+    
+    // argstr is the bit after the '?'
+    if (tailstr != "/gsdl") {
+      argstr = substr(begin+6, end);
+    }
+
+    // log the difference in access times
+    DWORD thislibaccesstime = GetTickCount();
+    if (gsdl_keep_log || gsdl_show_console) {
+      char logstr[256];
+      sprintf(logstr, "DELTA LIB ACCESS TIME: %i\n", (int)(thislibaccesstime - lastlibaccesstime));
+      log_message (logstr);
+    }
+    lastlibaccesstime = thislibaccesstime;
+    
+    // log this request
+    if (gsdl_keep_log || gsdl_show_console) {
+      text_t logstr = "LOCAL LIB: " + tailstr + "\n";
+      char *logstrc = logstr.getcstr();
+      log_message (logstrc);
+      delete []logstrc;
+    }
+    
+    handle_library_request (argstr, RequestInfo, RequestFields);
+    
+    // remember the preferences
+    // rememberpref (tailstr);
+    
+    // log memory information
+    if (gsdl_keep_log || gsdl_show_console) {
+      MEMORYSTATUS memstatus;
+      memstatus.dwLength = sizeof(MEMORYSTATUS);
+      GlobalMemoryStatus(&memstatus);
+      char logstr[256];
+      sprintf (logstr, "BDELTA AVAIL VIRTUAL: %i K\n", 
+	       (int)((baseavailvirtual - memstatus.dwAvailVirtual)/1024));
+      log_message (logstr);
+    }
+    
+  } else {
+    // local file
+    if (gsdl_keep_log || gsdl_show_console) {
+      text_t logstr = "LOCAL FILE: " + tailstr + "\n";
+      char *logstrc = logstr.getcstr();
+      log_message (logstrc);
+      delete []logstrc;
+    }
+    send_file_from_disk (tailstr, RequestInfo, RequestFields);
+  }
+}
+
+int ExamineURIStr(text_t &URIStr, RequestInfoT *RequestInfo,
+		  RequestFieldsT *RequestFields)
+{
+  text_t protocol, machine, rest;
+  int port;
+
+  if (RequestFields->ContentLength > 0) {
+    // POST data
+    URIStr.push_back('?');
+    for (int i = 0; i < RequestFields->ContentLength; ++i) {
+      URIStr.push_back(RequestFields->Content[i]);
+    }
+  }
+  
+  if (parse_url(URIStr, protocol, machine, &port, rest)!=http_ok) {
+    // Alter local file request to address 'gsdl'
+    if (*(URIStr.begin()) != '/') URIStr = "http://gsdl/" + URIStr;
+    else URIStr = "http://gsdl" + URIStr;
+    parse_url(URIStr, protocol, machine, &port, rest);
+  }
+
+  if (machine == "gsdl") {
+    // a local file request
+    handle_server_request(rest, RequestInfo, RequestFields);
+    
+  } else {
+    send_retrieve_error(404, "File not found",
+			"Could not find the local file requested", RequestInfo);
+  }
+  
+  return 1;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/cgiwrapper.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/cgiwrapper.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/cgiwrapper.h	(revision 10506)
@@ -0,0 +1,49 @@
+/**********************************************************************
+ *
+ * cgiwrapper.h -- windows local library cgiwrapper
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef CGIWRAPPER_H
+#define CGIWRAPPER_H
+
+#include "httpreq.h"
+#include "locate.h"
+#include "receptionist.h"
+
+// the number of times the library has been accessed
+extern int libaccessnum;
+
+int ExamineURIStr(text_t &URIStr,RequestInfoT *RequestInfo,
+		  RequestFieldsT *RequestFields);
+
+// reads any configure file that has been set up and
+// sets up the library
+// returns 1 if successful, 0 if unsuccessful
+int gsdl_init (bool atStartup = true);
+
+// returns 0 if the directories cant be found
+// and the user wants to quit (it returns 1
+// if everything is ok)
+int cstrcheckdir (char *cstrthedir);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/conftools.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/conftools.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/conftools.cpp	(revision 10506)
@@ -0,0 +1,55 @@
+/**********************************************************************
+ *
+ * conftools.cpp
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+#include "conftools.h"
+
+int write_confline (ofstream &fileout, const text_t &key, const text_t value) {
+  if (key.empty() || value.empty()) return -1;
+  outconvertclass text_t2ascii;
+  fileout << text_t2ascii << key << "=" << value << "\n";
+  return 0;
+}
+
+int get_confline (ifstream &filein, text_t &key, text_t &value) {
+  if (filein.eof()) return -1;
+
+  key.clear();
+  value.clear();
+  char c;
+  filein.get(c);
+
+  int foundeq = 0;
+  while (!filein.eof() && c != '\n') {
+    if (!foundeq && c == '=') {foundeq = 1; filein.get(c);}
+
+    if (foundeq) value.push_back(c);
+    else key.push_back(c);
+    filein.get(c);
+  }
+  if (key.empty()) return -1;
+  return 0;
+} 
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/conftools.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/conftools.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/conftools.h	(revision 10506)
@@ -0,0 +1,40 @@
+/**********************************************************************
+ *
+ * conftools.h
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef CONFTOOLS_H
+#define CONFTOOLS_H
+
+#if defined (GSDL_USE_OBJECTSPACE)
+#include <ospace/std/fstream>
+#elif defined (GSDL_USE_IOS_H)
+#include <fstream.h>
+#else
+#include <fstream>
+#endif
+
+int write_confline (ofstream &fileout, const text_t &key, const text_t value);
+int get_confline (ifstream &filein, text_t &key, text_t &value);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/d_winsock.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/d_winsock.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/d_winsock.cpp	(revision 10506)
@@ -0,0 +1,669 @@
+/**********************************************************************
+ *
+ * d_winsock.cpp
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include <windows.h>
+#include "d_winsock.h"
+
+
+typedef SOCKET (PASCAL FAR *accept_Type)(SOCKET s, struct sockaddr FAR *addr, 
+					 int FAR *addrlen);
+typedef int (PASCAL FAR *bind_Type)(SOCKET s, const struct sockaddr FAR *addr, int namelen);
+typedef int (PASCAL FAR *closesocket_Type)(SOCKET s);
+typedef int (PASCAL FAR *connect_Type)(SOCKET s, const struct sockaddr FAR *name, 
+				       int namelen);
+typedef int (PASCAL FAR *ioctlsocket_Type)(SOCKET s, long cmd, u_long FAR *argp);
+typedef int (PASCAL FAR *getpeername_Type)(SOCKET s, struct sockaddr FAR *name,
+					   int FAR * namelen);
+typedef int (PASCAL FAR *getsockname_Type)(SOCKET s, struct sockaddr FAR *name,
+					   int FAR * namelen);
+typedef int (PASCAL FAR *getsockopt_Type)(SOCKET s, int level, int optname,
+					  char FAR * optval, int FAR *optlen);
+typedef u_long (PASCAL FAR *htonl_Type)(u_long hostlong);
+typedef u_short (PASCAL FAR *htons_Type)(u_short hostshort);
+typedef unsigned long (PASCAL FAR *inet_addr_Type)(const char FAR * cp);
+typedef char FAR * (PASCAL FAR *inet_ntoa_Type)(struct in_addr in);
+typedef int (PASCAL FAR *listen_Type)(SOCKET s, int backlog);
+typedef u_long (PASCAL FAR *ntohl_Type)(u_long netlong);
+typedef u_short (PASCAL FAR *ntohs_Type)(u_short netshort);
+typedef int (PASCAL FAR *recv_Type)(SOCKET s, char FAR * buf, int len, int flags);
+typedef int (PASCAL FAR *recvfrom_Type)(SOCKET s, char FAR * buf, int len, int flags,
+					struct sockaddr FAR *from, int FAR * fromlen);
+typedef int (PASCAL FAR *select_Type)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds,
+				      fd_set FAR *exceptfds, const struct timeval FAR *timeout);
+typedef int (PASCAL FAR *send_Type)(SOCKET s, const char FAR * buf, int len, int flags);
+typedef int (PASCAL FAR *sendto_Type)(SOCKET s, const char FAR * buf, int len, int flags,
+				      const struct sockaddr FAR *to, int tolen);
+typedef int (PASCAL FAR *setsockopt_Type)(SOCKET s, int level, int optname,
+					  const char FAR * optval, int optlen);
+typedef int (PASCAL FAR *shutdown_Type)(SOCKET s, int how);
+typedef SOCKET (PASCAL FAR *socket_Type)(int af, int type, int protocol);
+typedef struct hostent FAR * (PASCAL FAR *gethostbyaddr_Type)(const char FAR * addr,
+							      int len, int type);
+typedef struct hostent FAR * (PASCAL FAR *gethostbyname_Type)(const char FAR * name);
+typedef int (PASCAL FAR *gethostname_Type) (char FAR * name, int namelen);
+typedef struct servent FAR * (PASCAL FAR *getservbyport_Type)(int port, const char FAR * proto);
+typedef struct servent FAR * (PASCAL FAR *getservbyname_Type)(const char FAR * name,
+							      const char FAR * proto);
+typedef struct protoent FAR * (PASCAL FAR *getprotobynumber_Type)(int proto);
+typedef struct protoent FAR * (PASCAL FAR *getprotobyname_Type)(const char FAR * name);
+typedef int (PASCAL FAR *WSAStartup_Type)(WORD wVersionRequired, LPWSADATA lpWSAData);
+typedef int (PASCAL FAR *WSACleanup_Type)(void);
+typedef void (PASCAL FAR *WSASetLastError_Type)(int iError);
+typedef int (PASCAL FAR *WSAGetLastError_Type)(void);
+typedef BOOL (PASCAL FAR *WSAIsBlocking_Type)(void);
+typedef int (PASCAL FAR *WSAUnhookBlockingHook_Type)(void);
+typedef FARPROC (PASCAL FAR *WSASetBlockingHook_Type)(FARPROC lpBlockFunc);
+typedef int (PASCAL FAR *WSACancelBlockingCall_Type)(void);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetServByName_Type)(HWND hWnd, u_int wMsg,
+							const char FAR * name,
+							const char FAR * proto,
+							char FAR * buf, int buflen);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetServByPort_Type)(HWND hWnd, u_int wMsg, int port,
+							const char FAR * proto, char FAR * buf,
+							int buflen);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetProtoByName_Type)(HWND hWnd, u_int wMsg,
+							 const char FAR * name, char FAR * buf,
+							 int buflen);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetProtoByNumber_Type)(HWND hWnd, u_int wMsg,
+							   int number, char FAR * buf,
+							   int buflen);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetHostByName_Type)(HWND hWnd, u_int wMsg,
+							const char FAR * name, char FAR * buf,
+							int buflen);
+typedef HANDLE (PASCAL FAR *WSAAsyncGetHostByAddr_Type)(HWND hWnd, u_int wMsg,
+							const char FAR * addr, int len, int type,
+							char FAR * buf, int buflen);
+typedef int (PASCAL FAR *WSACancelAsyncRequest_Type)(HANDLE hAsyncTaskHandle);
+typedef int (PASCAL FAR *WSAAsyncSelect_Type)(SOCKET s, HWND hWnd, u_int wMsg,
+					      long lEvent);
+
+
+
+static accept_Type accept_Ptr = NULL;
+static bind_Type bind_Ptr = NULL;
+static closesocket_Type closesocket_Ptr = NULL;
+static connect_Type connect_Ptr = NULL;
+static ioctlsocket_Type ioctlsocket_Ptr = NULL;
+static getpeername_Type getpeername_Ptr = NULL;
+static getsockname_Type getsockname_Ptr = NULL;
+static getsockopt_Type getsockopt_Ptr = NULL;
+static htonl_Type htonl_Ptr = NULL;
+static htons_Type htons_Ptr = NULL;
+static inet_addr_Type inet_addr_Ptr = NULL;
+static inet_ntoa_Type inet_ntoa_Ptr = NULL;
+static listen_Type listen_Ptr = NULL;
+static ntohl_Type ntohl_Ptr = NULL;
+static ntohs_Type ntohs_Ptr = NULL;
+static recv_Type recv_Ptr = NULL;
+static recvfrom_Type recvfrom_Ptr = NULL;
+static select_Type select_Ptr = NULL;
+static send_Type send_Ptr = NULL;
+static sendto_Type sendto_Ptr = NULL;
+static setsockopt_Type setsockopt_Ptr = NULL;
+static shutdown_Type shutdown_Ptr = NULL;
+static socket_Type socket_Ptr = NULL;
+static gethostbyaddr_Type gethostbyaddr_Ptr = NULL;
+static gethostbyname_Type gethostbyname_Ptr = NULL;
+static gethostname_Type gethostname_Ptr = NULL;
+static getservbyport_Type getservbyport_Ptr = NULL;
+static getservbyname_Type getservbyname_Ptr = NULL;
+static getprotobynumber_Type getprotobynumber_Ptr = NULL;
+static getprotobyname_Type getprotobyname_Ptr = NULL;
+static WSAStartup_Type WSAStartup_Ptr = NULL;
+static WSACleanup_Type WSACleanup_Ptr = NULL;
+static WSASetLastError_Type WSASetLastError_Ptr = NULL;
+static WSAGetLastError_Type WSAGetLastError_Ptr = NULL;
+static WSAIsBlocking_Type WSAIsBlocking_Ptr = NULL;
+static WSAUnhookBlockingHook_Type WSAUnhookBlockingHook_Ptr = NULL;
+static WSASetBlockingHook_Type WSASetBlockingHook_Ptr = NULL;
+static WSACancelBlockingCall_Type WSACancelBlockingCall_Ptr = NULL;
+static WSAAsyncGetServByName_Type WSAAsyncGetServByName_Ptr = NULL;
+static WSAAsyncGetServByPort_Type WSAAsyncGetServByPort_Ptr = NULL;
+static WSAAsyncGetProtoByName_Type WSAAsyncGetProtoByName_Ptr = NULL;
+static WSAAsyncGetProtoByNumber_Type WSAAsyncGetProtoByNumber_Ptr = NULL;
+static WSAAsyncGetHostByName_Type WSAAsyncGetHostByName_Ptr = NULL;
+static WSAAsyncGetHostByAddr_Type WSAAsyncGetHostByAddr_Ptr = NULL;
+static WSACancelAsyncRequest_Type WSACancelAsyncRequest_Ptr = NULL;
+static WSAAsyncSelect_Type WSAAsyncSelect_Ptr = NULL;
+
+
+static HINSTANCE wsock32lib = NULL;
+static HINSTANCE winsocklib = NULL;
+
+
+
+// set all the pointers back to null
+static void ResetWSPtrs () {
+  accept_Ptr = NULL;
+  bind_Ptr = NULL;
+  closesocket_Ptr = NULL;
+  connect_Ptr = NULL;
+  ioctlsocket_Ptr = NULL;
+  getpeername_Ptr = NULL;
+  getsockname_Ptr = NULL;
+  getsockopt_Ptr = NULL;
+  htonl_Ptr = NULL;
+  htons_Ptr = NULL;
+  inet_addr_Ptr = NULL;
+  inet_ntoa_Ptr = NULL;
+  listen_Ptr = NULL;
+  ntohl_Ptr = NULL;
+  ntohs_Ptr = NULL;
+  recv_Ptr = NULL;
+  recvfrom_Ptr = NULL;
+  select_Ptr = NULL;
+  send_Ptr = NULL;
+  sendto_Ptr = NULL;
+  setsockopt_Ptr = NULL;
+  shutdown_Ptr = NULL;
+  socket_Ptr = NULL;
+  gethostbyaddr_Ptr = NULL;
+  gethostbyname_Ptr = NULL;
+  gethostname_Ptr = NULL;
+  getservbyport_Ptr = NULL;
+  getservbyname_Ptr = NULL;
+  getprotobynumber_Ptr = NULL;
+  getprotobyname_Ptr = NULL;
+  WSAStartup_Ptr = NULL;
+  WSACleanup_Ptr = NULL;
+  WSASetLastError_Ptr = NULL;
+  WSAGetLastError_Ptr = NULL;
+  WSAIsBlocking_Ptr = NULL;
+  WSAUnhookBlockingHook_Ptr = NULL;
+  WSASetBlockingHook_Ptr = NULL;
+  WSACancelBlockingCall_Ptr = NULL;
+  WSAAsyncGetServByName_Ptr = NULL;
+  WSAAsyncGetServByPort_Ptr = NULL;
+  WSAAsyncGetProtoByName_Ptr = NULL;
+  WSAAsyncGetProtoByNumber_Ptr = NULL;
+  WSAAsyncGetHostByName_Ptr = NULL;
+  WSAAsyncGetHostByAddr_Ptr = NULL;
+  WSACancelAsyncRequest_Ptr = NULL;
+  WSAAsyncSelect_Ptr = NULL;
+}
+
+// get the pointers to all the socket functions
+static void SetupWSPtrs (HINSTANCE socketlib) {
+  if (socketlib == NULL) return;
+
+  accept_Ptr = (accept_Type)GetProcAddress(socketlib,"accept");
+  bind_Ptr = (bind_Type)GetProcAddress(socketlib,"bind");
+  closesocket_Ptr = (closesocket_Type)GetProcAddress(socketlib,"closesocket");
+  connect_Ptr = (connect_Type)GetProcAddress(socketlib,"connect");
+  ioctlsocket_Ptr = (ioctlsocket_Type)GetProcAddress(socketlib,"ioctlsocket");
+  getpeername_Ptr = (getpeername_Type)GetProcAddress(socketlib,"getpeername");
+  getsockname_Ptr = (getsockname_Type)GetProcAddress(socketlib,"getsockname");
+  getsockopt_Ptr = (getsockopt_Type)GetProcAddress(socketlib,"getsockopt");
+  htonl_Ptr = (htonl_Type)GetProcAddress(socketlib,"htonl");
+  htons_Ptr = (htons_Type)GetProcAddress(socketlib,"htons");
+  inet_addr_Ptr = (inet_addr_Type)GetProcAddress(socketlib,"inet_addr");
+  inet_ntoa_Ptr = (inet_ntoa_Type)GetProcAddress(socketlib,"inet_ntoa");
+  listen_Ptr = (listen_Type)GetProcAddress(socketlib,"listen");
+  ntohl_Ptr = (ntohl_Type)GetProcAddress(socketlib,"ntohl");
+  ntohs_Ptr = (ntohs_Type)GetProcAddress(socketlib,"ntohs");
+  recv_Ptr = (recv_Type)GetProcAddress(socketlib,"recv");
+  recvfrom_Ptr = (recvfrom_Type)GetProcAddress(socketlib,"recvfrom");
+  select_Ptr = (select_Type)GetProcAddress(socketlib,"select");
+  send_Ptr = (send_Type)GetProcAddress(socketlib,"send");
+  sendto_Ptr = (sendto_Type)GetProcAddress(socketlib,"sendto");
+  setsockopt_Ptr = (setsockopt_Type)GetProcAddress(socketlib,"setsockopt");
+  shutdown_Ptr = (shutdown_Type)GetProcAddress(socketlib,"shutdown");
+  socket_Ptr = (socket_Type)GetProcAddress(socketlib,"socket");
+  gethostbyaddr_Ptr = (gethostbyaddr_Type)GetProcAddress(socketlib,"gethostbyaddr");
+  gethostbyname_Ptr = (gethostbyname_Type)GetProcAddress(socketlib,"gethostbyname");
+  gethostname_Ptr = (gethostname_Type)GetProcAddress(socketlib,"gethostname");
+  getservbyport_Ptr = (getservbyport_Type)GetProcAddress(socketlib,"getservbyport");
+  getservbyname_Ptr = (getservbyname_Type)GetProcAddress(socketlib,"getservbyname");
+  getprotobynumber_Ptr = (getprotobynumber_Type)GetProcAddress(socketlib,"getprotobynumber");
+  getprotobyname_Ptr = (getprotobyname_Type)GetProcAddress(socketlib,"getprotobyname");
+  WSAStartup_Ptr = (WSAStartup_Type)GetProcAddress(socketlib,"WSAStartup");
+  WSACleanup_Ptr = (WSACleanup_Type)GetProcAddress(socketlib,"WSACleanup");
+  WSASetLastError_Ptr = (WSASetLastError_Type)GetProcAddress(socketlib,"WSASetLastError");
+  WSAGetLastError_Ptr = (WSAGetLastError_Type)GetProcAddress(socketlib,"WSAGetLastError");
+  WSAIsBlocking_Ptr = (WSAIsBlocking_Type)GetProcAddress(socketlib,"WSAIsBlocking");
+  WSAUnhookBlockingHook_Ptr = 
+    (WSAUnhookBlockingHook_Type)GetProcAddress(socketlib,"WSAUnhookBlockingHook");
+  WSASetBlockingHook_Ptr = 
+    (WSASetBlockingHook_Type)GetProcAddress(socketlib,"WSASetBlockingHook");
+  WSACancelBlockingCall_Ptr = 
+    (WSACancelBlockingCall_Type)GetProcAddress(socketlib,"WSACancelBlockingCall");
+  WSAAsyncGetServByName_Ptr = 
+    (WSAAsyncGetServByName_Type)GetProcAddress(socketlib,"WSAAsyncGetServByName");
+  WSAAsyncGetServByPort_Ptr = 
+    (WSAAsyncGetServByPort_Type)GetProcAddress(socketlib,"WSAAsyncGetServByPort");
+  WSAAsyncGetProtoByName_Ptr = 
+    (WSAAsyncGetProtoByName_Type)GetProcAddress(socketlib,"WSAAsyncGetProtoByName");
+  WSAAsyncGetProtoByNumber_Ptr = 
+    (WSAAsyncGetProtoByNumber_Type)GetProcAddress(socketlib,"WSAAsyncGetProtoByNumber");
+  WSAAsyncGetHostByName_Ptr = 
+    (WSAAsyncGetHostByName_Type)GetProcAddress(socketlib,"WSAAsyncGetHostByName");
+  WSAAsyncGetHostByAddr_Ptr = 
+    (WSAAsyncGetHostByAddr_Type)GetProcAddress(socketlib,"WSAAsyncGetHostByAddr");
+  WSACancelAsyncRequest_Ptr = 
+    (WSACancelAsyncRequest_Type)GetProcAddress(socketlib,"WSACancelAsyncRequest");
+  WSAAsyncSelect_Ptr = (WSAAsyncSelect_Type)GetProcAddress(socketlib,"WSAAsyncSelect");
+}
+
+
+
+// expects path to be NULL, a empty string, or a path which ends in a slash
+// returns D_NOERROR on success,
+// D_ERR_UNEXPECTED or D_ERR_LOADFAILED on failure
+int d_LoadWinsock (char *path) {
+  char dllname[2048]; // HARD LIMIT!!!!
+  OSVERSIONINFO osver;
+
+  if ((wsock32lib != NULL) || (winsocklib != NULL)) return D_ERR_UNEXPECTED;
+
+  // set the error mode so that no nasty dialog boxes come
+  // up when things aren't installed
+  int olderrormode = SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
+
+  // get the operating system version information
+  memset(&osver, 0, sizeof(OSVERSIONINFO));
+  osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+  if (!GetVersionEx(&osver)) {
+    SetErrorMode(olderrormode);
+    return D_ERR_UNEXPECTED;
+  }
+
+  // see if we should load winsock before wsock32
+  if ((osver.dwPlatformId == VER_PLATFORM_WIN32s) && (path != NULL)) {
+    strcpy (dllname, path);
+    strcat (dllname, "winsock.dll");
+
+    // attempt to load the library
+    winsocklib = LoadLibrary (dllname);
+    if (winsocklib == NULL) {
+      SetErrorMode(olderrormode);
+      return D_ERR_LOADFAILED;
+    }
+  }
+
+  // attempt to load wsock32
+  int err = D_NOERROR;
+  dllname[0] = '\0';
+  if ((osver.dwPlatformId != VER_PLATFORM_WIN32s) && (path != NULL)) {
+    strcpy (dllname, path);
+  }
+  strcat (dllname, "wsock32.dll");
+  wsock32lib = LoadLibrary (dllname);
+  if (wsock32lib == NULL) err = D_ERR_LOADFAILED;
+  else SetupWSPtrs (wsock32lib);
+
+
+  // perform a few tests
+
+  // first try starting-up (and check the szDescription field)
+  if (err == D_NOERROR) {
+    WSADATA Data;
+    memset(&Data, 0, sizeof(WSADATA));
+    if ((d_WSAStartup(257, &Data) != 0) ||
+	(Data.szDescription == NULL) || 
+	(Data.szDescription[0] == '\0'))
+      err = D_ERR_LOADFAILED;
+  }
+
+  // next try setting and getting an error
+  if (err == D_NOERROR) {
+    d_WSASetLastError (WSAENOTSOCK);
+    if (d_WSAGetLastError () != WSAENOTSOCK) err = D_ERR_LOADFAILED;
+    d_WSASetLastError (0);
+  }
+
+  // last try cleaning up (if an error occurs here we might
+  // not be able to unload anything)
+  if ((err == D_NOERROR) && (d_WSACleanup() == SOCKET_ERROR))
+    err = D_ERR_LOADFAILED;
+
+  // if an error occurred then we need to unload everything
+  if (err != D_NOERROR) d_UnloadWinsock ();
+
+  SetErrorMode(olderrormode);
+  return err;
+}
+
+// returns D_NOERROR on success,
+// D_ERR_FREELIBFAILED on failure
+int d_UnloadWinsock () {
+  int err = D_NOERROR;
+
+  // unload wsock32
+  if ((wsock32lib != NULL) && !FreeLibrary (wsock32lib)) {
+    err = D_ERR_FREELIBFAILED;
+  }
+  wsock32lib = NULL;
+
+  // unload winsock
+  if ((winsocklib != NULL) && !FreeLibrary (winsocklib)) {
+    err = D_ERR_FREELIBFAILED;
+  }
+  winsocklib = NULL;
+  
+  // reset all the function pointers
+  ResetWSPtrs ();
+
+  return err;
+}
+
+
+
+
+// socket functions, these just call the dynamically loaded version
+
+SOCKET d_accept (SOCKET s, struct sockaddr *addr, int *addrlen) {
+  if (accept_Ptr != NULL) 
+    return (*accept_Ptr)(s, addr, addrlen);
+  return INVALID_SOCKET; // error winsock not loaded
+}
+
+int d_bind (SOCKET s, const struct sockaddr *addr, int namelen) {
+  if (bind_Ptr != NULL) 
+    return (*bind_Ptr)(s, addr, namelen);
+  return WSANOTINITIALISED; // error winsock not loaded
+}
+
+int d_closesocket (SOCKET s) {
+  if (closesocket_Ptr != NULL) 
+    return (*closesocket_Ptr)(s);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_connect (SOCKET s, const struct sockaddr *name, int namelen) {
+  if (connect_Ptr != NULL) 
+    return (*connect_Ptr)(s, name, namelen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_ioctlsocket (SOCKET s, long cmd, u_long *argp) {
+  if (ioctlsocket_Ptr != NULL) 
+    return (*ioctlsocket_Ptr)(s, cmd, argp);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_getpeername (SOCKET s, struct sockaddr *name, int *namelen) {
+  if (getpeername_Ptr != NULL) 
+    return (*getpeername_Ptr)(s, name, namelen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_getsockname (SOCKET s, struct sockaddr *name, int *namelen) {
+  if (getsockname_Ptr != NULL) 
+    return (*getsockname_Ptr)(s, name, namelen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_getsockopt (SOCKET s, int level, int optname, char *optval, int *optlen) {
+  if (getsockopt_Ptr != NULL) 
+    return (*getsockopt_Ptr)(s, level, optname, optval, optlen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+u_long d_htonl (u_long hostlong) {
+  if (htonl_Ptr != NULL) 
+    return (*htonl_Ptr)(hostlong);
+  return hostlong; // error winsock not loaded
+}
+
+u_short d_htons (u_short hostshort) {
+  if (htons_Ptr != NULL) 
+    return (*htons_Ptr)(hostshort);
+  return hostshort; // error winsock not loaded
+}
+
+unsigned long d_inet_addr (const char *cp) {
+  if (inet_addr_Ptr != NULL) 
+    return (*inet_addr_Ptr)(cp);
+  return INADDR_NONE; // error winsock not loaded
+}
+
+char *d_inet_ntoa (struct in_addr in) {
+  if (inet_ntoa_Ptr != NULL) 
+    return (*inet_ntoa_Ptr)(in);
+  return NULL; // error winsock not loaded
+}
+
+int d_listen (SOCKET s, int backlog) {
+  if (listen_Ptr != NULL) 
+    return (*listen_Ptr)(s, backlog);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+u_long d_ntohl (u_long netlong) {
+  if (ntohl_Ptr != NULL) 
+    return (*ntohl_Ptr)(netlong);
+  return netlong; // error winsock not loaded
+}
+
+u_short d_ntohs (u_short netshort) {
+  if (ntohs_Ptr != NULL) 
+    return (*ntohs_Ptr)(netshort);
+  return netshort; // error winsock not loaded
+}
+
+int d_recv (SOCKET s, char *buf, int len, int flags) {
+  if (recv_Ptr != NULL) 
+    return (*recv_Ptr)(s, buf, len, flags);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_recvfrom (SOCKET s, char *buf, int len, int flags,
+		struct sockaddr *from, int *fromlen) {
+  if (recvfrom_Ptr != NULL) 
+    return (*recvfrom_Ptr)(s, buf, len, flags, from, fromlen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_select (int nfds, fd_set *readfds, fd_set *writefds,
+	      fd_set *exceptfds, const struct timeval *timeout) {
+  if (select_Ptr != NULL) 
+    return (*select_Ptr)(nfds, readfds, writefds, exceptfds, timeout);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_send (SOCKET s, const char *buf, int len, int flags) {
+  if (send_Ptr != NULL) 
+    return (*send_Ptr)(s, buf, len, flags);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_sendto (SOCKET s, const char *buf, int len, int flags,
+	      const struct sockaddr *to, int tolen) {
+  if (sendto_Ptr != NULL) 
+    return (*sendto_Ptr)(s, buf, len, flags, to, tolen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_setsockopt (SOCKET s, int level, int optname,
+		  const char *optval, int optlen) {
+  if (setsockopt_Ptr != NULL) 
+    return (*setsockopt_Ptr)(s, level, optname, optval, optlen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_shutdown (SOCKET s, int how) {
+  if (shutdown_Ptr != NULL) 
+    return (*shutdown_Ptr)(s, how);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+SOCKET d_socket (int af, int type, int protocol) {
+  if (socket_Ptr != NULL) 
+    return (*socket_Ptr)(af, type, protocol);
+  return INVALID_SOCKET; // error winsock not loaded
+}
+
+hostent *d_gethostbyaddr(const char *addr, int len, int type) {
+  if (gethostbyaddr_Ptr != NULL) 
+    return (*gethostbyaddr_Ptr)(addr, len, type);
+  return NULL; // error winsock not loaded
+}
+
+hostent *d_gethostbyname(const char *name) {
+  if (gethostbyname_Ptr != NULL) 
+    return (*gethostbyname_Ptr)(name);
+  return NULL; // error winsock not loaded
+}
+
+int d_gethostname (char *name, int namelen) {
+  if (gethostname_Ptr != NULL) 
+    return (*gethostname_Ptr)(name, namelen);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+servent *d_getservbyport(int port, const char *proto) {
+  if (getservbyport_Ptr != NULL) 
+    return (*getservbyport_Ptr)(port, proto);
+  return NULL; // error winsock not loaded
+}
+
+servent *d_getservbyname(const char *name, const char *proto) {
+  if (getservbyname_Ptr != NULL) 
+    return (*getservbyname_Ptr)(name, proto);
+  return NULL; // error winsock not loaded
+}
+
+protoent *d_getprotobynumber(int proto) {
+  if (getprotobynumber_Ptr != NULL) 
+    return (*getprotobynumber_Ptr)(proto);
+  return NULL; // error winsock not loaded
+}
+
+protoent *d_getprotobyname(const char *name) {
+  if (getprotobyname_Ptr != NULL) 
+    return (*getprotobyname_Ptr)(name);
+  return NULL; // error winsock not loaded
+}
+
+int d_WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData) {
+  if (WSAStartup_Ptr != NULL) 
+    return (*WSAStartup_Ptr)(wVersionRequired, lpWSAData);
+  return WSASYSNOTREADY; // error winsock not loaded
+}
+
+int d_WSACleanup(void) {
+  if (WSACleanup_Ptr != NULL) 
+    return (*WSACleanup_Ptr)();
+  return WSANOTINITIALISED; // error winsock not loaded
+}
+
+void d_WSASetLastError(int iError) {
+  if (WSASetLastError_Ptr != NULL) (*WSASetLastError_Ptr)(iError);
+}
+
+int d_WSAGetLastError(void) {
+  if (WSAGetLastError_Ptr != NULL) 
+    return (*WSAGetLastError_Ptr)();
+  return WSANOTINITIALISED; // error winsock not loaded
+}
+
+BOOL d_WSAIsBlocking(void) {
+  if (WSAIsBlocking_Ptr != NULL) 
+    return (*WSAIsBlocking_Ptr)();
+  return FALSE; // error winsock not loaded
+}
+
+int d_WSAUnhookBlockingHook(void) {
+  if (WSAUnhookBlockingHook_Ptr != NULL) 
+    return (*WSAUnhookBlockingHook_Ptr)();
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+FARPROC d_WSASetBlockingHook(FARPROC lpBlockFunc) {
+  if (WSASetBlockingHook_Ptr != NULL) 
+    return (*WSASetBlockingHook_Ptr)(lpBlockFunc);
+  return NULL; // error winsock not loaded
+}
+
+int d_WSACancelBlockingCall(void) {
+  if (WSACancelBlockingCall_Ptr != NULL) 
+    return (*WSACancelBlockingCall_Ptr)();
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetServByName(HWND hWnd, u_int wMsg,
+			       const char *name,
+			       const char *proto,
+			       char *buf, int buflen) {
+  if (WSAAsyncGetServByName_Ptr != NULL) 
+    return (*WSAAsyncGetServByName_Ptr)(hWnd, wMsg, name, proto, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetServByPort(HWND hWnd, u_int wMsg, int port,
+			       const char *proto, char *buf,
+			       int buflen) {
+  if (WSAAsyncGetServByPort_Ptr != NULL) 
+    return (*WSAAsyncGetServByPort_Ptr)(hWnd, wMsg, port, proto, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetProtoByName(HWND hWnd, u_int wMsg,
+				const char *name, char *buf,
+				int buflen) {
+  if (WSAAsyncGetProtoByName_Ptr != NULL) 
+    return (*WSAAsyncGetProtoByName_Ptr)(hWnd, wMsg, name, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetProtoByNumber(HWND hWnd, u_int wMsg,
+				  int number, char *buf,
+				  int buflen) {
+  if (WSAAsyncGetProtoByNumber_Ptr != NULL) 
+    return (*WSAAsyncGetProtoByNumber_Ptr)(hWnd, wMsg, number, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetHostByName(HWND hWnd, u_int wMsg,
+			       const char *name, char *buf,
+			       int buflen) {
+  if (WSAAsyncGetHostByName_Ptr != NULL) 
+    return (*WSAAsyncGetHostByName_Ptr)(hWnd, wMsg, name, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+HANDLE d_WSAAsyncGetHostByAddr(HWND hWnd, u_int wMsg,
+                                        const char *addr, int len, int type,
+                                        char *buf, int buflen) {
+  if (WSAAsyncGetHostByAddr_Ptr != NULL) 
+    return (*WSAAsyncGetHostByAddr_Ptr)(hWnd, wMsg, addr, len, type, buf, buflen);
+  return NULL; // error winsock not loaded
+}
+
+int d_WSACancelAsyncRequest(HANDLE hAsyncTaskHandle) {
+  if (WSACancelAsyncRequest_Ptr != NULL) 
+    return (*WSACancelAsyncRequest_Ptr)(hAsyncTaskHandle);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
+int d_WSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
+                               long lEvent) {
+  if (WSAAsyncSelect_Ptr != NULL) 
+    return (*WSAAsyncSelect_Ptr)(s, hWnd, wMsg, lEvent);
+  return SOCKET_ERROR; // error winsock not loaded
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/d_winsock.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/d_winsock.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/d_winsock.h	(revision 10506)
@@ -0,0 +1,120 @@
+/**********************************************************************
+ *
+ * d_winsock.h
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef D_WINSOCK_H
+#define D_WINSOCK_H
+
+/* get most definitions from the real winsock */
+#include <winsock.h>
+
+#define D_NOERROR           0
+#define D_ERR_UNEXPECTED    1
+#define D_ERR_LOADFAILED    2
+#define D_ERR_FREELIBFAILED 3
+
+// d_LoadWinsock must be called before an normal winsock
+// functions
+
+// expects path to be NULL, a empty string, or a path which ends in a slash
+// returns D_NOERROR on success,
+// D_ERR_UNEXPECTED or D_ERR_LOADFAILED on failure
+int d_LoadWinsock (char *path);
+
+// returns D_NOERROR on success,
+// D_ERR_FREELIBFAILED on failure
+int d_UnloadWinsock ();
+
+// dynamically loaded versions of the winsock functions
+
+SOCKET d_accept (SOCKET s, struct sockaddr *addr, int *addrlen);
+int d_bind (SOCKET s, const struct sockaddr *addr, int namelen);
+int d_closesocket (SOCKET s);
+int d_connect (SOCKET s, const struct sockaddr *name, int namelen);
+int d_ioctlsocket (SOCKET s, long cmd, u_long *argp);
+int d_getpeername (SOCKET s, struct sockaddr *name, int *namelen);
+int d_getsockname (SOCKET s, struct sockaddr *name, int *namelen);
+int d_getsockopt (SOCKET s, int level, int optname, char *optval, int *optlen);
+u_long d_htonl (u_long hostlong);
+u_short d_htons (u_short hostshort);
+unsigned long d_inet_addr (const char *cp);
+char *d_inet_ntoa (struct in_addr in);
+int d_listen (SOCKET s, int backlog);
+u_long d_ntohl (u_long netlong);
+u_short d_ntohs (u_short netshort);
+int d_recv (SOCKET s, char *buf, int len, int flags);
+int d_recvfrom (SOCKET s, char *buf, int len, int flags,
+		struct sockaddr *from, int *fromlen);
+int d_select (int nfds, fd_set *readfds, fd_set *writefds,
+	      fd_set *exceptfds, const struct timeval *timeout);
+int d_send (SOCKET s, const char *buf, int len, int flags);
+int d_sendto (SOCKET s, const char *buf, int len, int flags,
+	      const struct sockaddr *to, int tolen);
+int d_setsockopt (SOCKET s, int level, int optname,
+		  const char *optval, int optlen);
+int d_shutdown (SOCKET s, int how);
+SOCKET d_socket (int af, int type, int protocol);
+
+hostent *d_gethostbyaddr(const char *addr, int len, int type);
+hostent *d_gethostbyname(const char *name);
+int d_gethostname (char *name, int namelen);
+servent *d_getservbyport(int port, const char *proto);
+servent *d_getservbyname(const char *name, const char *proto);
+protoent *d_getprotobynumber(int proto);
+protoent *d_getprotobyname(const char *name);
+
+int d_WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);
+int d_WSACleanup(void);
+void d_WSASetLastError(int iError);
+int d_WSAGetLastError(void);
+BOOL d_WSAIsBlocking(void);
+int d_WSAUnhookBlockingHook(void);
+FARPROC d_WSASetBlockingHook(FARPROC lpBlockFunc);
+int d_WSACancelBlockingCall(void);
+HANDLE d_WSAAsyncGetServByName(HWND hWnd, u_int wMsg,
+			       const char *name,
+			       const char *proto,
+			       char *buf, int buflen);
+HANDLE d_WSAAsyncGetServByPort(HWND hWnd, u_int wMsg, int port,
+			       const char *proto, char *buf,
+			       int buflen);
+HANDLE d_WSAAsyncGetProtoByName(HWND hWnd, u_int wMsg,
+				const char *name, char *buf,
+				int buflen);
+HANDLE d_WSAAsyncGetProtoByNumber(HWND hWnd, u_int wMsg,
+				  int number, char *buf,
+				  int buflen);
+HANDLE d_WSAAsyncGetHostByName(HWND hWnd, u_int wMsg,
+			       const char *name, char *buf,
+			       int buflen);
+HANDLE d_WSAAsyncGetHostByAddr(HWND hWnd, u_int wMsg,
+			       const char *addr, int len, int type,
+			       char *buf, int buflen);
+int d_WSACancelAsyncRequest(HANDLE hAsyncTaskHandle);
+int d_WSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
+		     long lEvent);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/fnord.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/fnord.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/fnord.cpp	(revision 10506)
@@ -0,0 +1,1187 @@
+/**********************************************************************
+ *
+ * fnord.cpp
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+#include "netio.h"
+#include "settings.h"
+#include "httpsrv.h"
+#include "resource.h"
+#include "locate.h"
+#include "cgiwrapper.h"
+#include "startbrowser.h"
+#include "d_winsock.h"
+
+#define MAINWINDOWWIDTH 400
+#define MAINWINDOWHEIGHT 200
+
+#define WASTEHEIGHT 44  // Error in ht due to caption and menu bar
+#define WASTEWIDTH 6
+#define SPACERWIDTH 5
+
+// size and position of the collection title
+#define COLTITLEWIDTH 351
+#define COLTITLEHEIGHT 35
+#define COLTITLEX ((MAINWINDOWWIDTH-COLTITLEWIDTH)/2)
+#define COLTITLEY 10
+
+// size and position of the version string
+#define VERSIONWIDTH MAINWINDOWWIDTH
+#define VERSIONHEIGHT 20
+#define VERSIONX 0
+#define VERSIONY (COLTITLEY+COLTITLEHEIGHT)
+
+// size and position of the Greenstone digital library logo
+#define LOGOWIDTH 135
+#define LOGOHEIGHT 55
+#define LOGOX (MAINWINDOWWIDTH-(LOGOWIDTH+SPACERWIDTH))
+#define LOGOY (MAINWINDOWHEIGHT-(LOGOHEIGHT+SPACERWIDTH))
+
+// size and position of the enter button
+#define ENTERBUTTONWIDTH 160
+#define ENTERBUTTONHEIGHT 30
+#define ENTERBUTTONX SPACERWIDTH
+#define ENTERBUTTONY ((MAINWINDOWHEIGHT-(LOGOHEIGHT+SPACERWIDTH))-(ENTERBUTTONHEIGHT+SPACERWIDTH))
+
+// size and position of the enter string
+#define ENTERSTRINGX (ENTERBUTTONX+ENTERBUTTONWIDTH+SPACERWIDTH)
+#define ENTERSTRINGY ENTERBUTTONY
+#define ENTERSTRINGWIDTH (MAINWINDOWWIDTH-(ENTERBUTTONWIDTH+SPACERWIDTH+SPACERWIDTH+SPACERWIDTH))
+#define ENTERSTRINGHEIGHT ENTERBUTTONHEIGHT
+
+// size and position of the info string
+#define INFOWIDTH MAINWINDOWWIDTH
+#define INFOHEIGHT (MAINWINDOWHEIGHT-INFOY)
+#define INFOX 0
+#define INFOY ENTERBUTTONY
+
+// size and position of restricted buttons
+#define ALTERNATIVEBUTTONWIDTH 160
+#define ALTERNATIVEBUTTONHEIGHT 30
+#define ALTERNATIVEBUTTONX SPACERWIDTH
+#define ALTERNATIVEBUTTONY LOGOY
+
+#define INFOBUTTONWIDTH 30
+
+// size and position of restart button
+#define RESTARTBUTTONWIDTH 160
+#define RESTARTBUTTONHEIGHT 30
+#define RESTARTBUTTONX 50
+#define RESTARTBUTTONY (MAINWINDOWHEIGHT-RESTARTBUTTONHEIGHT-15)
+
+const char versionstring[] = "version " GSDL_VERSION;
+
+const char strnothing[] = "";
+const char strinit[] = "Initialising...";
+const char strsb[] = "Starting browser...";
+const char strrestartlib[] = "Press the 'Restart Library' button to start a browser\n"
+"and enter library";
+const char strenterlib[] = "Press this button to begin using\n"
+"the library";
+const char *enterstring = NULL; // points to the current enter string
+const char *infostring = NULL; // points to the current info string
+
+
+// globals to do with networking and browsers
+int have_networking = 0;
+int netscapeneeded = 0;
+char startbrowserdir[1024] = ""; // HARD LIMIT!!!!!
+
+
+// stats to do with the last time the enter library button was pressed
+// these stats are needed to make suggestions about the proxy
+int enterlib_libaccessnum = -1; // -1 = NA
+DWORD enterlib_time = 0;
+
+
+enum { undefined_window, console_window, plain_window }
+window_state;
+
+HDC coltitledc = NULL;
+HBITMAP defcoltitlebitmap = NULL, coltitlebitmap=NULL;
+
+HDC logodc=NULL;
+HBITMAP deflogobitmap=NULL, logobitmap=NULL;
+
+HWND GoButton = NULL;
+HWND Enter = NULL;
+HWND EnterRestricted = NULL;
+HWND InfoRestricted = NULL;
+int init_type = 0;
+int init_done = 0;
+
+
+// Added an argument so you can specify not to do any of the windows orientated clean up - jmt12 18/11/2003
+void finish_up(bool init_only) {
+  // remember the current preferences
+  write_settings("");
+
+  if(init_only) {
+    return;
+  }
+   
+ // Shutdown the HTTP server
+  EndHTTPServer();
+  
+  // Shutdown the main server modules
+  CleanUpNetIO();
+  //    RemoveFnordFromTray();
+  
+  // Unload the wsock32 dll
+  d_UnloadWinsock();
+  
+  // Clean up graphics stuff from window
+  
+  if (defcoltitlebitmap != NULL)
+    SelectObject (coltitledc, defcoltitlebitmap);
+  if (coltitlebitmap != NULL)
+    DeleteObject (coltitlebitmap);
+  if (coltitledc != NULL)
+    DeleteDC (coltitledc);
+  
+  if (deflogobitmap != NULL)
+    SelectObject (logodc, deflogobitmap);
+  if (logobitmap != NULL)
+    DeleteObject (logobitmap);
+  if (logodc != NULL)
+    DeleteDC (logodc);
+  
+  // Shutdown the main window
+  PostQuitMessage(0);
+}
+
+
+int overlap(int left, int top, int right, int bottom,
+            RECT &r2)
+{
+  if (left <= r2.right && r2.left <= right &&
+      top <= r2.bottom && r2.top <= bottom)
+    return 1;
+  else
+    return 0;
+}
+
+
+void paint_window (HDC pdc, RECT &updateRect) {
+  // make sure the various DCs are set up
+  if (coltitledc == NULL) {
+    coltitledc = CreateCompatibleDC(pdc);
+    defcoltitlebitmap = (HBITMAP)SelectObject (coltitledc, coltitlebitmap);
+  }
+  
+  if (logodc == NULL) {
+    logodc = CreateCompatibleDC(pdc);
+    deflogobitmap = (HBITMAP)SelectObject (logodc, logobitmap);
+  }
+
+  // remove any remaining sign of initial buttons
+  if (init_done && (overlap (ENTERBUTTONX, ENTERBUTTONY, ENTERBUTTONX+ENTERBUTTONWIDTH,
+		ALTERNATIVEBUTTONY+ALTERNATIVEBUTTONHEIGHT, updateRect))) {
+    RECT initRect;
+    initRect.left = ENTERBUTTONX;
+    initRect.top = ENTERBUTTONY;
+    initRect.right = ENTERBUTTONX+ENTERBUTTONWIDTH;
+    initRect.bottom = ALTERNATIVEBUTTONY+ALTERNATIVEBUTTONHEIGHT;
+    FillRect(pdc, &initRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
+  }
+
+  // update the collection title if needed
+  if (overlap(COLTITLEX, COLTITLEY,
+	      COLTITLEX+COLTITLEWIDTH, COLTITLEY+COLTITLEHEIGHT, 
+	      updateRect)) {
+    BitBlt (pdc, COLTITLEX, COLTITLEY, 
+	    COLTITLEX+COLTITLEWIDTH, COLTITLEY+COLTITLEHEIGHT,
+	    coltitledc, 0, 0, SRCCOPY);
+  }
+  
+  // update the version string if needed
+  if (overlap (VERSIONX, VERSIONY, 
+	       VERSIONX+VERSIONWIDTH, VERSIONY+VERSIONHEIGHT,
+	       updateRect)) {
+    RECT versionRect;
+    versionRect.left = VERSIONX;
+    versionRect.top = VERSIONY;
+    versionRect.right = VERSIONX+VERSIONWIDTH;
+    versionRect.bottom = VERSIONY+VERSIONHEIGHT;
+    DrawText(pdc, versionstring, -1, &versionRect, DT_CENTER);
+  }
+  
+  // decide what we want to draw
+  if (init_done && gsdl_show_console) {
+    // we want to draw a "console" window
+    if (window_state != console_window ||
+	overlap (text_rect.left, text_rect.top,
+		 text_rect.right, text_rect.bottom,
+		 updateRect)) {
+      refresh_console (pdc);
+    }
+    
+    window_state = console_window;
+    
+  } else {
+    // we want to draw a "plain" window
+    
+    // update the enter string if needed
+    if (overlap (ENTERSTRINGX, ENTERSTRINGY, ENTERSTRINGX+ENTERSTRINGWIDTH, 
+		 ENTERSTRINGY+ENTERSTRINGHEIGHT, updateRect)) {
+
+	RECT enterstringRect;
+	enterstringRect.left = ENTERSTRINGX;
+	enterstringRect.top = ENTERSTRINGY;
+	enterstringRect.right = ENTERSTRINGX+ENTERSTRINGWIDTH;
+	enterstringRect.bottom = ENTERSTRINGY+ENTERSTRINGHEIGHT;
+	FillRect(pdc, &enterstringRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
+
+	if ((enterstring != NULL) && (strlen(enterstring) > 0)) {
+      
+	  int cury = ENTERSTRINGY;
+	  int startline = 0, here = 0;
+	  while (enterstring[here] != '\0') {
+	    if (enterstring[here] < ' ') {
+	      if (here - startline > 0) {
+		// output the text
+		TextOut (pdc, ENTERSTRINGX, cury, 
+			 &enterstring[startline], here-startline);
+		cury += line_spacing;
+	      }
+	      startline = here+1;
+	    }
+	    ++here;
+	  }
+	  // output any remaining text
+	  if (here - startline > 0) {
+	    TextOut (pdc, ENTERSTRINGX, cury, &enterstring[startline], here-startline);
+	  }
+	}
+    }
+    
+    window_state = plain_window;
+  }
+  
+  // update the info string if needed
+  if (init_done && !gsdl_show_console && 
+      ((infostring != NULL) && overlap (INFOX, INFOY, 
+					INFOX+INFOWIDTH, INFOY+INFOHEIGHT,
+					updateRect))) {
+    RECT infoRect;
+    infoRect.left = INFOX;
+    infoRect.top = INFOY;
+    infoRect.right = INFOX+INFOWIDTH;
+    infoRect.bottom = INFOY+INFOHEIGHT;
+    FillRect(pdc, &infoRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
+    DrawText(pdc, infostring, -1, &infoRect, DT_CENTER);
+  }
+
+  // update the logo (always)
+  BitBlt (pdc, LOGOX, LOGOY, LOGOX+LOGOWIDTH, LOGOY+LOGOHEIGHT,
+	  logodc, 0, 0, SRCCOPY);
+}
+
+
+void handle_painting (HWND Window) {
+  HDC pdc;  PAINTSTRUCT ps;
+  pdc = BeginPaint(Window, &ps);
+  
+  paint_window (pdc, ps.rcPaint);
+  
+  EndPaint(Window, &ps);
+}
+
+
+// returns 1 on success, 0 otherwise
+int enter_library (HWND Window) {
+  int res;
+  
+  if (infostring == strrestartlib) {
+
+    // the "restart library" button was pressed so we want to reinitialize
+    // greenstone, read in all the macrofiles again, etc.
+    gsdl_init(false);
+  }
+
+  // get the url and attempt to start a browser
+  if (have_networking) {
+    // There are now three address resolution methods:
+    //   0: Standard -- get local IP then resolve to a name
+    //   1: IP only -- as above, but use IP only -- don't resolve to a name
+    //   2: 127.0.0.1 -- always use 127.0.0.1
+    char gsdl_address[100];
+
+    DWORD local_ip = GetLocalIP();
+    if (local_ip == INADDR_ANY || gsdl_address_resolution_method == 2) {
+      local_ip = 127 + (0 << 8) + (0 << 16) + (1 << 24);
+    }
+
+    if (gsdl_address_resolution_method == 1 || gsdl_address_resolution_method == 2) {
+      sprintf(gsdl_address, "%d.%d.%d.%d", local_ip & 0xFF, (local_ip >> 8) & 0xFF, (local_ip >> 16) & 0xFF, (local_ip >> 24) & 0xFF);
+    }
+    else {
+      strcpy(gsdl_address, GetLocalName(NULL));
+    }
+
+    text_t url = "http://" + text_t(gsdl_address);
+
+    gsdl_url = url;
+    write_settings(gsdl_url);
+
+    if (gsdl_port_num != 80)
+      url += ":" + text_t(gsdl_port_num);
+
+    url += gsdl_enterlib;
+
+    // add a unique ending so it will always result in a request
+    text_t::const_iterator it = 
+      findchar (gsdl_enterlib.begin(), gsdl_enterlib.end(), '?');
+    if (it == gsdl_enterlib.end()) url.push_back ('?');
+    else url.push_back ('&');
+    int tcount = GetTickCount();
+    url += "uq=" + text_t(tcount);
+    
+    // remember the library access number for later proxy checking
+    enterlib_libaccessnum = libaccessnum;
+    
+    if (gsdl_start_browser) {
+
+      // do a quick check to make sure we're using netscape when
+      // we should be (it might have been just installed)
+      if (netscapeneeded) gsdl_check_browser_settings (netscapeneeded);
+    
+      char *cstr_url = url.getcstr();
+      if (strlen (startbrowserdir) <= 0) {
+	res = startbrowser (cstr_url, gsdl_browser_exe, NULL);
+	
+      } else res = startbrowser (cstr_url, gsdl_browser_exe, startbrowserdir);
+    
+      delete []cstr_url;
+
+    } else {
+      return 1;
+    }
+  }
+  
+  if (res == SB_NOERROR) {
+    // success !!
+    
+    // remember the time the browser was started for later proxy checking
+    if (have_networking) enterlib_time = GetTickCount();
+    
+    return 1;
+  }
+  
+  // no browser was started
+  enterlib_libaccessnum = -1;
+  
+  if ((res == SB_FAIL_BADFORMAT) || (res == SB_FAIL_NOTFOUND)) {
+    if (!netscapeneeded) { // any browser
+      MessageBox(Window,
+		 "Failed to start your chosen browser. It seems that your\n"
+		 "chosen browser has been removed or corrupted.\n"
+		 "Please check your browser choice by going to the\n"
+		 "'Settings...' item under the 'File' menu.",
+		 "Greenstone Digital Library Software", MB_OK);
+    } else { // netscape used
+      MessageBox(Window,
+		 "Failed to start Netscape. It seems that Netscape has\n"
+		 "been removed or corrupted. You need Netscape\n"
+		 "installed to use the Greenstone Digital Library\n"
+		 "software on non-networked machines.",
+		 "Greenstone Digital Library Software", MB_OK);
+    }
+    
+  } else {
+    MessageBox(Window,
+	       "Failed to start your browser. This may have been\n"
+	       "because there was not enough memory available. Shut\n"
+	       "down all other applications you have running, and\n"
+	       "try again.",
+	       "Greenstone Digital Library Software", MB_OK);
+  }
+  
+  return 0; // failed
+}
+
+
+void install_netscape (HWND Window) {
+  char installpath[256];
+  
+  // try to find the browser directory
+  char *gsdlhome = gsdl_gsdlhome.getcstr();
+  strcpy (installpath, gsdlhome); // use gsdlhome to find the CD-ROM drive...
+  delete []gsdlhome;
+  
+  // remove any slashes from the pathname
+  int len = strlen (installpath);
+  while ((len > 0) && ((installpath[len-1] == '\\') || (installpath[len-1] == '/'))) {
+    --len;
+  }
+  // remove '\gsdl'
+  len = len - 5;
+  installpath[len] = '\0';
+  
+  strcat (installpath, "\\netscape\\");
+  
+  // check this directory
+  if (!cstrcheckdir(installpath)) {
+    return;
+  }
+  
+  // get the operating system information
+  OSVERSIONINFO osver;
+  memset(&osver, 0, sizeof(OSVERSIONINFO));
+  osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+  GetVersionEx(&osver);
+
+  // get the install program for this operating system
+  if (osver.dwPlatformId == VER_PLATFORM_WIN32s) {
+    strcat (installpath, "n16e405.exe");
+  } else {
+    strcat (installpath, "n32e405.exe");
+  }
+  
+  // run the install program
+  int res = WinExec (installpath, SW_SHOW);
+  if (res == 0) {
+    // out of resources or memory
+    MessageBox (Window,
+		"Did not have enough resources or memory to run the\n"
+		"install program. Try shutting down all other programs\n"
+		"and trying again.",
+		"Greenstone Digital Library Software",
+		MB_OK|MB_APPLMODAL);
+    
+  } else if (res == ERROR_BAD_FORMAT) {
+    // executable image is corrupt -- ????
+    MessageBox (Window,
+		"The install program seems to be corrupt.",
+		"Greenstone Digital Library Software",
+		MB_OK|MB_APPLMODAL);
+    
+  } else if ((res == ERROR_FILE_NOT_FOUND) || (res == ERROR_PATH_NOT_FOUND)) {
+    // couldn't find the executable -- ????
+    MessageBox (Window,
+		"Could not find the install program. Try installing\n"
+		"Netscape from the Greenstone Digital Library\n"
+		"software's install program.",
+		"Greenstone Digital Library Software",
+		MB_OK|MB_APPLMODAL);
+  }
+}
+
+void open_help () {
+  char topdir[256], cmd[256];
+  
+  // try to find the browser directory
+  char *gsdlhome = gsdl_gsdlhome.getcstr();
+  strcpy (topdir, gsdlhome); // use gsdlhome to find the CD-ROM drive...
+  delete []gsdlhome;
+  strcpy (cmd, "notepad ");
+  
+  // remove any slashes from the pathname
+  int len = strlen (topdir);
+  while ((len > 0) && ((topdir[len-1] == '\\') || (topdir[len-1] == '/'))) {
+    --len;
+  }
+  // remove the '\gsdl'
+  len = len - 5;
+  topdir[len] = '\0';
+
+  strcat (topdir, "\\README.txt");
+  strcat (cmd, topdir);
+  
+  WinExec (cmd, SW_SHOW);
+}
+
+
+long __stdcall WndProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam) {
+  switch(Message) {
+    // Constant Messages
+  case WM_CREATE:
+    break;
+    
+  case WM_COMMAND:
+    if ((GoButton != NULL) && ((HWND)LParam == GoButton)) {
+      // attempt to start a browser
+      gsdl_start_browser = 1;
+      if (enter_library (Window) && !gsdl_show_console) 
+    	ShowWindow(Window,SW_MINIMIZE);
+
+    } else if ((Enter != NULL) && ((HWND)LParam == Enter)) {
+      init_done = 1;
+      init_type = 1;
+
+    } else if ((EnterRestricted != NULL) && ((HWND)LParam == EnterRestricted)) {
+      init_done = 1;
+      init_type = 0;
+
+    } else if ((InfoRestricted != NULL) && ((HWND)LParam == InfoRestricted)) {
+      MessageBox (NULL, "The Greenstone system automatically determines whether your computer has\n"
+		  "network software installed or is connected to a network.  It operates correctly\n"
+		  "under any of these conditions.\n\n"
+		  "The restricted version is intended for use when the standard one\n\n"
+		  "   (a) causes an unwanted telephone dialup operation;\n"
+		  "   (b) fails to run because network software is installed, but installed\n"
+		  "         incorrectly.\n\n"
+		  "The restricted version only works with Netscape (not Internet Explorer).\n\n"
+		  "Unless these problems arise, you should always use the standard version\n"
+		  "(press the 'Enter Library' button).\n",
+		  "Greenstone Digital Library Software", 
+		  MB_OK | MB_ICONINFORMATION | MB_APPLMODAL);
+
+    } else {
+      switch (LOWORD(WParam)) {
+      case ID_PROJECT_SETTINGS:
+	Settings_Dialog(Window, netscapeneeded);
+	break;
+      case ID_INSTALL_NETSCAPE:
+	install_netscape(Window);
+	break;
+      case IDHELP:
+	open_help();
+	break;
+      case ID_PROJECT_EXIT:
+        finish_up(false);
+        break;
+      default:
+        break;
+      }
+    }
+    break;
+    
+  case WM_PAINT:
+    handle_painting(Window);
+    break;
+    
+  case HTTP_SERVER_MSG:
+    ProcessHTTPServerMsg(WParam, LParam);
+    break;
+    
+  case WM_DESTROY:
+    finish_up(false);
+    break;
+    
+  default:
+    //Unhandled Messages end up here (DefWindowProc)
+    return DefWindowProc(Window, Message, WParam, LParam);
+  }
+  
+  return(0);
+}
+
+// returns 0 if successful,
+// otherwise a WSA error number
+int tryinitnetwork (HANDLE Instance, HWND MsgWindow, char *path) {
+  // try to load winsock
+  int err = d_LoadWinsock (path);
+  
+  if (err == D_NOERROR) {
+    // next, try to init netio
+    err = InitNetIO();
+    
+    if (err == 0) {
+      // next, try to start the http server
+      err = StartHTTPServer(MsgWindow);
+      
+      if (err == 0) {
+	// finally, get the host name (no error value
+	// is returned from this function)
+	GetLocalName((HINSTANCE)Instance);
+	
+      } else {
+	// couldn't start the http server, 
+	// deinit netio and unload winsock
+	CleanUpNetIO();
+	d_UnloadWinsock();
+      }
+      
+    } else {
+      // couldn't init netio, unload winsock
+      d_UnloadWinsock();
+    }
+    
+  } else {
+    // couldn't load winsock
+    err = WSASYSNOTREADY;
+  }
+  
+  return err;
+}
+
+
+// inits all the network functionality
+// returns 0 if an unrecoverable error occurred,
+// and 1 if everything successfully initialised.
+int initnetwork (HANDLE Instance, HWND MsgWindow) {
+  OSVERSIONINFO osver;
+  
+  // get the operating system information
+  memset(&osver, 0, sizeof(OSVERSIONINFO));
+  osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+  GetVersionEx(&osver);
+  
+  // first try to initialise the network with system installed
+  // networking software
+  startbrowserdir[0] = '\0';
+  netscapeneeded = 0;
+  int err = 1;
+  if (init_type == 1) err = tryinitnetwork (Instance, MsgWindow, NULL);
+  
+  // if an error occurred, try again with billsock
+  if (err != 0) {
+    // get the path of billsock (current directory + ("net16" | "net32"))
+    char winsockpath[1024]; // HARD LIMIT!!!!
+    
+    find_location();
+    char *data_location_c = data_location.getcstr();
+    strcpy (winsockpath, data_location_c);
+    delete []data_location_c;
+    
+    // remove all the slashes at the end of billpath
+    int len = strlen (winsockpath);
+    while ((len > 0) && ((winsockpath[len-1] == '\\') || (winsockpath[len-1] == '/'))) {
+      --len;
+    }
+    winsockpath[len] = '\0';
+    
+    if (osver.dwPlatformId == VER_PLATFORM_WIN32s)
+      strcat (winsockpath, "\\net16\\");
+    else {
+      strcat (winsockpath, "\\net32\\");
+      strcpy (startbrowserdir, winsockpath);
+    }
+    
+    // try again
+    err = tryinitnetwork (Instance, MsgWindow, winsockpath);
+    
+    if (err == 0) {
+      // we will need to use netscape on 95/98/NT machines
+      if (osver.dwPlatformId != VER_PLATFORM_WIN32s) {
+	netscapeneeded = 1;
+	// make sure the browser state is in step with the network condition
+	gsdl_check_browser_settings (netscapeneeded);
+      }
+      
+      // check to see if a browser is running
+      if (browserrunning(gsdl_browser_exe) == NO_ERROR) {
+	MessageBox (NULL, 
+		    "The Greenstone Digital Library software has detected a\n"
+		    "running browser. To let our networking software\n"
+		    "correctly initialize, please shut down your browser\n"
+		    "and restart the Greenstone Digital Library software.",
+		    "Greenstone Digital Library Software", MB_OK|MB_APPLMODAL);
+	PostMessage(MsgWindow,WM_CLOSE,0,0);
+	finish_up(false); // will unload winsock
+	exit(0);      // nothing more to do
+      }
+    }
+  }
+  
+  // if an error occurred display a nice error message
+  if (err != 0) {
+    
+    // WSASYSNOTREADY	Couldn't load winsock
+    // WSAVERNOTSUPPORTED	The version of Windows Sockets support requested 
+    //			is not provided by this particular Windows Sockets implementation.
+    // WSAEINVAL	The Windows Sockets version specified by the application 
+    //			is not supported by this DLL.
+    // WSAEPROTONOSUPPORT	The specified protocol is not supported.
+    // WSAEPROTOTYPE	The specified protocol is the wrong type for this socket.
+    // WSAESOCKTNOSUPPORT	The specified socket type is not supported in 
+    //		this address family.
+    // WSANOTINITIALISED	A successful WSAStartup must occur before 
+    //		using this function.
+    // WSAENETDOWN	The Windows Sockets implementation 
+    //		has detected that the network subsystem has failed.
+    // WSAEADDRINUSE 	The specified address 
+    //		is already in use. (See the SO_REUSEADDR socket option under setsockopt.)
+    // WSAEFAULT	The namelen argument is too small (less 
+    //		than the size of a struct sockaddr).
+    // WSAEINPROGRESS	A blocking Windows Sockets call is in progress.
+    // WSAEAFNOSUPPORT	The specified address family is not supported 
+    //		by this protocol.
+    // WSAENOBUFS	Not enough buffers available, too many connections.
+    // WSAENOTSOCK	The descriptor is not a socket.
+    // WSAEISCONN	The socket is already connected.
+    // WSAEMFILE	No more file descriptors are available.
+    // WSAEOPNOTSUPP	The referenced socket is not of a type that 
+    //		supports the listen operation.
+    
+    // get a text version of the error number
+    char errstr[256];
+    
+    switch (err) {
+    case WSASYSNOTREADY: strcpy(errstr, "WSASYSNOTREADY"); 
+      break;
+    case WSAVERNOTSUPPORTED: strcpy (errstr, "WSAVERNOTSUPPORTED");
+      break;
+    case WSAEINVAL: strcpy (errstr, "WSAEINVAL");
+      break;
+    case WSAEPROTONOSUPPORT: strcpy (errstr, "WSAEPROTONOSUPPORT");
+      break;
+    case WSAEPROTOTYPE: strcpy (errstr, "WSAEPROTOTYPE");
+      break;
+    case WSAESOCKTNOSUPPORT: strcpy (errstr, "WSAESOCKTNOSUPPORT");
+      break;
+    case WSANOTINITIALISED: strcpy (errstr, "WSANOTINITIALISED");
+      break;
+    case WSAEFAULT: strcpy (errstr, "WSAEFAULT");
+      break;
+    case WSAEAFNOSUPPORT: strcpy (errstr, "WSAEAFNOSUPPORT");
+      break;
+    case WSAENOTSOCK: strcpy (errstr, "WSAENOTSOCK");
+      break;
+    case WSAEISCONN: strcpy (errstr, "WSAEISCONN");
+      break;
+    case WSAEOPNOTSUPP: strcpy (errstr, "WSAEOPNOTSUPP");
+      break;
+    case WSAENETDOWN: strcpy (errstr, "WSAENETDOWN");
+      break;
+    case WSAEADDRINUSE: strcpy (errstr, "WSAEADDRINUSE");
+      break;
+    case WSAEINPROGRESS: strcpy (errstr, "WSAEINPROGRESS");
+      break;
+    case WSAENOBUFS: strcpy (errstr, "WSAENOBUFS");
+      break;
+    case WSAEMFILE: strcpy (errstr, "WSAEMFILE");
+      break;
+    default: sprintf (errstr, "WSA ERROR: %i", err);
+      break;
+    }
+    
+    // create a nice error message
+    char message[2048];
+    
+    switch (err) {
+    case WSAEADDRINUSE:
+      // couldn't bind socket
+      sprintf (message, "Could not find a free socket.", errstr);
+      break;
+      
+    default:
+      // cannot init winsock
+      sprintf (message, "Could not initialize the network\n"
+	       " (Reason: %s).", errstr);
+      break;
+    }
+    
+    strcat (message, "\n\n"
+	    "Please submit a bug report using the support.htm file\n"
+	    "on the CD-ROM.");
+    
+    MessageBox (NULL, message, "Greenstone Digital Library Software", MB_OK);
+  }
+  
+  return (err == 0);
+}
+
+
+void log_computer_info () {
+  char tmpstr[1024];
+  
+  // get various information about this computer
+  if (gsdl_keep_log || gsdl_show_console) {
+    // get operating system information
+    OSVERSIONINFO osver;
+    osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+    
+    if (GetVersionEx(&osver)) {
+      if (osver.dwPlatformId == VER_PLATFORM_WIN32s) {
+	log_message ("Platform: win32s\n");
+      } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+	log_message ("Platform: windows 95\n");
+      } else if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+	log_message ("Platform: windows NT\n");
+      }
+      
+      sprintf (tmpstr, "MajorVersion: %i\n", (int)osver.dwMajorVersion);
+      log_message(tmpstr);
+      sprintf (tmpstr, "MinorVersion: %i\n", (int)osver.dwMinorVersion);
+      log_message(tmpstr);
+      sprintf (tmpstr, "BuildNumber: %i\n", (int)osver.dwBuildNumber);
+      log_message(tmpstr);
+      sprintf (tmpstr, "CSDVersion: %s\n\n", osver.szCSDVersion);
+      log_message(tmpstr);
+    }
+    
+    // get memory information
+    MEMORYSTATUS memstatus;
+    memstatus.dwLength = sizeof(MEMORYSTATUS);
+    GlobalMemoryStatus(&memstatus);
+    
+    sprintf (tmpstr, "TotalPhys: %i Meg\n", (int)(memstatus.dwTotalPhys/1024/1024));
+    log_message (tmpstr);
+    sprintf (tmpstr, "AvailPhys: %i Meg\n", (int)(memstatus.dwAvailPhys/1024/1024));
+    log_message (tmpstr);
+    sprintf (tmpstr, "TotalPageFile: %i Meg\n", (int)(memstatus.dwTotalPageFile/1024/1024));
+    log_message (tmpstr);
+    sprintf (tmpstr, "AvailPageFile: %i Meg\n", (int)(memstatus.dwAvailPageFile/1024/1024));
+    log_message (tmpstr);
+    sprintf (tmpstr, "TotalVirtual: %i Meg\n", (int)(memstatus.dwTotalVirtual/1024/1024));
+    log_message (tmpstr);
+    sprintf (tmpstr, "AvailVirtual: %i Meg\n\n", (int)(memstatus.dwAvailVirtual/1024/1024));
+    log_message (tmpstr);
+    
+    // log the version number
+    log_message("GSDL version: " GSDL_VERSION "\n");
+  }
+  
+}
+
+// possible command line options are 
+// --location=directory (the path to GSDLHOME which defaults to the
+// directory where server.exe lives)
+// --config=file (the path to the configuration file to use which defaults
+// to GSDLHOME\gsdlsite.cfg)
+// --cmd=init  Used to initialize the gsdlsite.cfg file onlt - jmt12 18/11/2003
+static void parse_args(const text_t cmdline, text_t &location, text_t &config_file, text_t &command) {
+
+  location.clear();
+  config_file.clear();
+  command.clear(); // jmt12 18/11/2003
+
+  if (cmdline.size() < 3) return;
+
+  text_t name, val;
+  bool foundname = false;
+  text_t::const_iterator here = cmdline.begin();
+  text_t::const_iterator end = cmdline.end();
+  while (here != end) {
+    if (*here == '-' && ((here+1) != end) && (*(here+1) == '-')) {
+      ++here;
+      if (name == "location") {
+	location = val;
+      } else if (name == "config") {
+	config_file = val;
+      } 
+      // jmt12 18/11/2003
+      else if(name == "cmd") {
+	command = val;
+      }
+      foundname = false;
+      name.clear();
+      val.clear();
+    } else if (*here == '=') {
+      foundname = true;
+    } else {
+      if (foundname) {
+	val.push_back(*here);
+      } else {
+	name.push_back(*here);
+      }
+    }
+    ++here;
+  }
+  if (name == "location") {
+    location = val;
+  } else if (name == "config") {
+    config_file = val;
+  }
+  // jmt12 18/11/2003
+  else if(name == "cmd") {
+    command = val;
+  }
+}
+
+// Added code to allow for an 'init' run of the server which just creates the gsdlsite.cfg file
+int __stdcall WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, LPSTR CmdLineStr, int /*CmdShow*/) {
+  HWND MainWindow;  MSG Message;  WNDCLASS MainClass;  
+
+  // One instance of the local library server is quite enough, thank you very much
+  HWND gw = FindWindow("Greenstone Digital Library Software",
+		       "Greenstone Digital Library Software");
+  if (gw != NULL) {
+    exit(1);
+  }
+
+  // parse arguments
+  text_t location, config_file, command;
+  parse_args(CmdLineStr, location, config_file, command);
+  gsdl_conffile = config_file;
+
+  // jmt12 18/11/2003
+  if(command == "init") {
+    // init various modules
+    read_settings(0); // don't know if netscape is needed at this point
+    finish_up(true);
+    exit(0);
+  }
+
+  //Create a window class
+  MainClass.style = CS_HREDRAW | CS_VREDRAW;
+  MainClass.lpfnWndProc = WndProc;
+  MainClass.cbClsExtra = 0;
+  MainClass.cbWndExtra = 0;
+  MainClass.hInstance = Instance;
+  MainClass.hIcon     = LoadIcon(Instance, MAKEINTRESOURCE(TRAY_ICON));
+  MainClass.hCursor   = LoadCursor(NULL, IDC_ARROW);
+  MainClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+  MainClass.lpszMenuName = MAKEINTRESOURCE(Main_Menu);
+  MainClass.lpszClassName = "Greenstone Digital Library Software";
+  if (!RegisterClass(&MainClass))
+    return 0;
+  
+  
+  // Load various bitmaps
+  coltitlebitmap = LoadBitmap (Instance, MAKEINTRESOURCE(GSDL_COL_TITLE));
+  logobitmap= LoadBitmap (Instance, MAKEINTRESOURCE(GSDL_LOGO));
+  
+  // Create the main window
+  MainWindow = CreateWindow("Greenstone Digital Library Software", 
+			    "Greenstone Digital Library Software",
+			    WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU |
+			    WS_MINIMIZEBOX,
+			    CW_USEDEFAULT, CW_USEDEFAULT, 
+			    MAINWINDOWWIDTH + WASTEWIDTH, 
+			    MAINWINDOWHEIGHT + WASTEHEIGHT,
+			    NULL, NULL, Instance, NULL);
+  
+  text_rect.left = 0;  
+  text_rect.top = VERSIONY+VERSIONHEIGHT + 5;
+  text_rect.right = MAINWINDOWWIDTH;
+  text_rect.bottom = LOGOY-SPACERWIDTH;
+  
+  window_state = undefined_window;
+  
+  ShowWindow(MainWindow, SW_SHOW); 
+  set_location(location);
+  
+  // get ready to draw the main window
+  RECT windowRect;
+  GetClientRect (MainWindow, &windowRect);
+  HDC pdc = GetDC (MainWindow);
+  
+  // retrieve and save the text metrics
+  TEXTMETRIC tm;
+  GetTextMetrics(pdc, &tm);
+  line_spacing = tm.tmHeight + tm.tmExternalLeading;
+  GSDL_Window = MainWindow;  
+
+  // init various modules
+  read_settings (0); // don't know if netscape is needed at this point
+  
+  if (!gsdl_auto_enter) {
+    
+    // add the select version checkbox
+    Enter = CreateWindow("BUTTON",             // predefined class 
+			 "Enter Library",      // button text 
+			 WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_DEFPUSHBUTTON,  // styles 
+			 ENTERBUTTONX,         // starting x position 
+			 ENTERBUTTONY,         // starting y position 
+			 ENTERBUTTONWIDTH,     // button width 
+			 ENTERBUTTONHEIGHT,    // button height 
+			 MainWindow,           // parent window 
+			 NULL,                 // No menu 
+			 Instance, 
+			 NULL);                // pointer not needed 
+    
+    EnterRestricted = CreateWindow("Button",                // predefined class 
+				   "Restricted Version",    // button text 
+				   WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_PUSHBUTTON,   // styles 
+				   ALTERNATIVEBUTTONX,      // starting x position 
+				   ALTERNATIVEBUTTONY,      // starting y position 
+				   ALTERNATIVEBUTTONWIDTH-(INFOBUTTONWIDTH+SPACERWIDTH),  // button width 
+				   ALTERNATIVEBUTTONHEIGHT, // button height 
+				   MainWindow,              // parent window 
+				   (HMENU)NULL,             // No menu 
+				   Instance, 
+				   NULL);                   // pointer not needed 
+    
+    InfoRestricted = CreateWindow("Button",                // predefined class 
+				  NULL,
+				  WS_VISIBLE | WS_CHILD | WS_TABSTOP | BS_BITMAP,   // styles 
+				  ALTERNATIVEBUTTONWIDTH-INFOBUTTONWIDTH+SPACERWIDTH, // starting x position 
+				  ALTERNATIVEBUTTONY,      // starting y position 
+				  INFOBUTTONWIDTH,         // button width 
+				  ALTERNATIVEBUTTONHEIGHT, // button height 
+				  MainWindow,              // parent window 
+				  (HMENU)NULL,             // No menu 
+				  Instance, 
+				  NULL);                   // pointer not needed 
+    
+    HANDLE i_icon = LoadImage (Instance, MAKEINTRESOURCE(GSDL_ICBMP), IMAGE_BITMAP, 
+			       INFOBUTTONWIDTH-4, ALTERNATIVEBUTTONHEIGHT-4, LR_DEFAULTCOLOR);
+    SendMessage (InfoRestricted, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)i_icon);
+    
+    SetFocus (Enter);
+    
+    enterstring = strenterlib;
+    paint_window (pdc, windowRect);
+    
+    // message loop for init buttons
+    while (!init_done) {
+      if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
+	if (Message.message == WM_QUIT) return Message.wParam;
+	if (!IsDialogMessage (MainWindow, &Message)) {
+	  TranslateMessage(&Message); /* translate keyboard messages */
+	  DispatchMessage(&Message);  /* return control to Windows NT */
+	}
+      } else {
+	Sleep (1);
+      }
+    }
+    
+    // don't want these buttons anymore
+    DestroyWindow (Enter);
+    DestroyWindow (EnterRestricted);
+    DestroyWindow (InfoRestricted);
+    
+    enterstring = strnothing;
+    paint_window (pdc, windowRect);
+    
+  } else {
+    // auto enter is enabled - start up standard version
+    init_type = 1;
+    init_done = 1;
+  }
+  
+  // draw the main window containing an init message
+  infostring = strinit;
+  paint_window (pdc, windowRect);
+  DWORD lastcheck = GetTickCount();
+  
+  have_networking = initnetwork (Instance, MainWindow);
+  if (!have_networking) {
+    MessageBox(NULL,
+	       "Failed to initialize networking.",
+	       "Greenstone Digital Library Software",MB_OK|MB_SYSTEMMODAL);	
+    exit (0);
+  }
+
+  if (!gsdl_init()) // quit if can't initialise the library correctly
+    exit (0);
+  initstartbrowser();
+  log_computer_info ();
+  
+  // show the initialising message for at least 1 second
+  while (DiffTickCounts (lastcheck, GetTickCount()) < 1000) {
+    Sleep (1);
+  }
+  
+  // attempt to start a browser
+  if (gsdl_show_console || !gsdl_start_browser) infostring = strnothing;
+  else infostring = strsb;
+  paint_window (pdc, windowRect);
+  lastcheck = GetTickCount();
+  if (enter_library (MainWindow) && !gsdl_show_console) {
+    // stay maximised for at least 1 second
+    while (DiffTickCounts (lastcheck, GetTickCount()) < 1000) Sleep (1);
+    ShowWindow(MainWindow,SW_MINIMIZE);
+  }
+  
+  // add the "restart library" button
+  GoButton = CreateWindow("BUTTON",              // predefined class 
+			  "Restart Library",     // button text 
+			  WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // styles 
+			  RESTARTBUTTONX,        // starting x position 
+			  RESTARTBUTTONY,        // starting y position 
+			  RESTARTBUTTONWIDTH,    // button width 
+			  RESTARTBUTTONHEIGHT,   // button height 
+			  MainWindow,            // parent window 
+			  NULL,                  // No menu 
+			  Instance, 
+			  NULL);                 // pointer not needed 
+  
+  infostring = strrestartlib;
+  paint_window (pdc, windowRect);
+  
+  // release the DC used to display the init messages
+  ReleaseDC (MainWindow, pdc);
+  
+  //Message loop
+  lastcheck = GetTickCount();
+  int seenbrowser = 0;	// if we see a browser then it disappears
+                        // we will ask if they want to close the
+                        // the library down
+  char last_gsdl_browser_exe[MAX_FILENAME_SIZE]; // need to notice when the
+                                                 // browser setting changes
+  strcpy (last_gsdl_browser_exe, gsdl_browser_exe);
+  
+  for (;;) {
+    if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
+      if (Message.message == WM_QUIT) break;
+      if (!IsDialogMessage (MainWindow, &Message)) {
+	TranslateMessage(&Message); /* translate keyboard messages */
+	DispatchMessage(&Message);  /* return control to Windows NT */
+      }
+      
+    } else {
+      if (DiffTickCounts (lastcheck, GetTickCount()) > 500) {
+	// make sure the browser hasn't changed
+	if (strcmp (last_gsdl_browser_exe, gsdl_browser_exe) != 0) {
+	  seenbrowser = 0;
+	  strcpy (last_gsdl_browser_exe, gsdl_browser_exe);
+	}
+	
+	// do check
+	lastcheck = GetTickCount();
+	if (gsdl_start_browser && browserrunning(gsdl_browser_exe) == NO_ERROR) {
+	  // we were able to connect to a browser
+	  seenbrowser = 1;
+	  
+	  // see if the enter library button has been pressed
+	  // with nothing happening for 20 seconds
+	  if ((enterlib_libaccessnum >= 0) && 
+	      (enterlib_libaccessnum == libaccessnum) &&
+	      (DiffTickCounts (enterlib_time, GetTickCount()) > 20000)) {
+	    // something could be wrong!! (most likely cause is a proxy)
+	    MessageBox(NULL,
+		       "Your browser does not seem to be responding to the 'Enter Library'\n"
+		       "request. Try turning off all proxy servers in your browser settings.\n"
+		       "If you are using Internet Explorer make sure BOTH dialup settings\n"
+		       "AND LAN settings have their proxy servers disabled.",
+		       "Greenstone Digital Library Software",MB_OK|MB_SYSTEMMODAL);
+	    enterlib_libaccessnum = -1;
+	  }
+	  
+	  
+	} else {
+	  // no browser was found
+	  
+	  if (seenbrowser) {
+	    // we have seen a browser in the past
+	    if (MessageBox(NULL,
+			   "The Greenstone Digital Library software has noticed that you\n"
+			   "shut down your browser. Would you also like to shut down the\n"
+			   "Greenstone Digital Library software?",
+			   "Greenstone Digital Library Software",MB_YESNO|MB_SYSTEMMODAL) == IDYES)
+	      PostMessage(MainWindow,WM_CLOSE,0,0);
+	  }
+	  seenbrowser = 0;
+	}
+      }
+      
+      Sleep (1); // millisecond
+    }
+  }
+  
+  return Message.wParam;
+}
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpreq.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpreq.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpreq.cpp	(revision 10506)
@@ -0,0 +1,443 @@
+/**********************************************************************
+ *
+ * httpreq.cpp
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#include "httpreq.h"
+#include "parse.h"
+#include "netio.h"
+#include "settings.h"
+#include "httpsrv.h"
+#include "httpsend.h"
+#include "cgiwrapper.h"
+#include "d_winsock.h"
+
+/*
+Implementation Notes:
+
+HTTP field names, method and version strings are converted to upper case
+right after being read from the client in order to allow case insensitive
+string comparisons to be done on them.  Since these fields are worked with a
+lot, this should help performance.
+*/
+
+//Private Data and declarations
+#define IO_BUFFER_SIZE 16384        //16K IO Buffer
+#define MAX_HTTP_LINE_LEN 1024      //Max length of line in a header of 1024
+
+//Private Function Declarations with Return Contstants
+
+/*
+Function Name: DispatchRequest
+Purpose: Manages having the request parsed, then sent to the right function
+         to send a response or handle an error.
+Parameters:
+         ClientSocket - Socket the client is on
+	 ClientSockAddr - Address of client
+	 AddrLen - Length of address of client
+	 IOBuffer - Pointer to buffer allocated for IO operations
+	 ThreadNum - Number of thread that called this function for debugging purposes
+Notes:   I'm still playing with the keep alive support.  I commented out
+	 the stuff for giving a client a timeout because I was unable to detect
+	 disconnects.
+More Notes: Not sure if this organization will allow me to easily add support
+	    for ISAPI filter DLLs.
+*/
+void DispatchRequest(SOCKET ClientSocket, SOCKADDR_IN ClientSockAddr, int AddrLen, BYTE *IOBuffer);
+
+/*
+Function Name: Get HTTP Headers
+Purpose: Manages having the request parsed, then sent to the right function
+         to send a response or handle an error.
+Parameters:
+	RequestInfo - Request information structure (see httpreq.h)
+	RequestFields - HTTP request fields structure (see httpreq.h)
+Returns: GH_ERROR on error (diconnect, bad data, Windows in a bad mood, etc.)
+			GH_UNKNOWN_VERSION if the version number is not HTTP/0.9 or HTTP/1.x
+			GH_SIMPLE_REQUEST on a properly formated HTTP/0.9 request
+			GH_10_REQUEST on a properly formated HTTP/1.x request
+*/
+int GetHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
+#define GH_BAD_METHOD	   -2
+#define GH_ERROR           -1
+#define GH_UNKNOWN_VERSION  0
+#define GH_SIMPLE_REQUEST   1
+#define GH_10_REQUEST       2
+
+/*
+Function Name: Clean Up HTTP Headers
+Purpose: Cleans up memory dynamicly allocated for headers
+Parameters:
+	RequestInfo - Request information structure (see httpreq.h)
+	RequestFields - HTTP request fields structure (see httpreq.h)
+Returns: Nothing
+*/
+void CleanUpHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
+
+/*
+Function Name: Split Query
+Purpose: Splits the file and query part of a URI.  In other words, it
+	 puts the parts before and after the "?" in differnet strings.
+Parameters:
+	 URIStr - The requested URI
+	 FileStr - String to contain the name of the path + file part of the URI
+	 QueryStr - String to contain the query part of the URI
+Returns: TRUE if there is a query, else FALSE
+*/
+BOOL SplitQuery(char *URIStr, char *FileStr, char *QueryStr, int ThreadNum);
+
+/*
+Function Name: Get File
+Purpose: Attempts to find a given file, including looking for index.html.
+	 Updates the given URI string so it points to the true document location
+Parameters:
+	 FilePath - Path of file, may be modified to best reflect the retrived file
+				  or directory
+	 URIStr - URI string, minus the query
+Returns: GF_ERROR on error
+			GF_FILE_FOUND on success
+			GF_INDEX_FOUND if file is a directory with an index.html file in it
+			GF_DIRECTORY if file is a directory
+			GF_FILE_NOT_FOUND if file was found
+*/
+
+/*
+Function Name: Process Simple Request
+Purpose: Sends a reply to a HTTP 0.9 "simple" request
+Parameters:
+	ClientSocket - Socket the client is on
+	RequestInfo - Structure storing the parsed headers
+	IOBuffer - Pointer to buffer allocated for IO operations
+	TheadNum - Number of calling thread for debugging
+Notes: I should really test this and see if it works...
+*/
+void ProcessSimpleRequest(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
+
+//Public Functions
+/******************************************************************************/
+void RequestThread(RequestThreadMessageT *Parameters) {
+  SOCKADDR_IN ClientSockAddr;
+  SOCKET ClientSocket;
+  int AddrLen;
+  //Allocate an IO buffer for this thread
+  BYTE *IOBuffer = new BYTE[IO_BUFFER_SIZE];
+
+  //Get the parameters for the request
+  ClientSocket = Parameters->ClientSocket;
+  ClientSockAddr = Parameters->ClientSockAddr;
+  AddrLen = Parameters->AddrLen;
+  DispatchRequest(ClientSocket, ClientSockAddr, AddrLen, IOBuffer);
+}
+/******************************************************************************/
+
+//Private Functions
+
+/******************************************************************************/
+void DispatchRequest(SOCKET ClientSocket, SOCKADDR_IN ClientSockAddr, int AddrLen,  BYTE *IOBuffer) {
+  RequestInfoT RequestInfo;
+  RequestFieldsT RequestFields;
+
+  // TrayAddConnection();
+
+  //Setup the RequestInfo structure
+  memset(&RequestInfo, 0, sizeof(RequestInfoT));
+  RequestInfo.ThreadNum = 0;
+  RequestInfo.IOBuffer = IOBuffer;
+  RequestInfo.IOBufferSize = IO_BUFFER_SIZE;
+  RequestInfo.ClientSocket = ClientSocket;
+  RequestInfo.ClientSockAddr = ClientSockAddr;
+  RequestInfo.AddrLen = AddrLen;
+  RequestInfo.KeepAlive = FALSE;
+  
+  int GetHeadersResult;
+  do {
+    //Get Headers
+    GetHeadersResult = GetHTTPHeaders(RequestInfo, RequestFields);
+
+    //Figure out what version we're dealing with and deal with it
+    switch (GetHeadersResult) {
+    case GH_SIMPLE_REQUEST :
+      SendHTTPError(400, "HTTP Request not supported", "Only 1.x requests supported", RequestInfo, RequestFields);
+      // TrayIncNumServed();
+      break;
+    case GH_10_REQUEST :
+      ExamineURIStr(RequestFields.URIStr,&RequestInfo,&RequestFields);
+      // TrayIncNumServed();
+      break;
+    case GH_UNKNOWN_VERSION :
+      SendHTTPError(400, "HTTP Version not supported", "Only 1.x requests supported", RequestInfo, RequestFields);
+      // TrayIncNumServed();
+      break;
+/* added Feb 2002 to handle stupid MS behaviour */
+    case GH_BAD_METHOD :
+      SendHTTPError(501, "Not implemented", "Only GET and POST currently implemented", RequestInfo, RequestFields);
+      break;
+    case GH_ERROR:
+      //Disconnect
+      RequestInfo.KeepAlive = FALSE;
+      break;
+    }
+    CleanUpHTTPHeaders(RequestInfo, RequestFields);
+  } while (0/*RequestInfo.KeepAlive == TRUE*/);
+  //Close connection
+  CloseSocket(RequestInfo.ClientSocket);
+  // TrayRemoveConnection();
+}
+
+/******************************************************************************/
+int GetHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields) {
+  //Parsing and IO buffers
+  text_t CurLine;
+  text_t NextLine;
+  text_t FieldNameStr;
+  text_t FieldValStr;
+  
+  //Parsing and IO working vars
+  int ReadBufferIndex;
+  int DataInBuffer;
+  text_t::const_iterator next;
+  text_t::const_iterator end;
+
+  //Clear all the fields
+  memset(&RequestFields, 0, sizeof(RequestFieldsT));
+
+  ReadBufferIndex = 0;
+  DataInBuffer = 0;
+  
+  //Get First Line
+  if (GetLine(CurLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
+	      RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
+	      RequestInfo.ThreadNum) != 0) return GH_ERROR;
+  do {//Get Next Line, append it if the first charactor is space
+    if(GetLine(NextLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
+	       RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
+	       RequestInfo.ThreadNum) != 0) return GH_ERROR;
+    if ((*(NextLine.begin()) == ' ') || (*(NextLine.begin()) == '\t')) {
+      CurLine += NextLine;
+    }
+  } while ((*(NextLine.begin()) == ' ') || (*(NextLine.begin()) == '\t'));
+  //Method String (first word)
+  GetWord(RequestFields.MethodStr, CurLine.begin(), CurLine.end(), next);
+  uc(RequestFields.MethodStr);
+
+  /* Added Feb 2002 - IE since about version 5 send stupid frontpage requests
+     for MS Document formats eg "GET /_vti_inf.html" */ 
+  if (RequestFields.MethodStr == "OPTIONS") {
+    return GH_BAD_METHOD;
+  } 
+  //Version String (last word)
+  GetLastWord(RequestFields.VersionStr, CurLine.begin(), CurLine.end(), end);
+  uc(RequestFields.VersionStr);
+  text_t::const_iterator versionbegin = RequestFields.VersionStr.begin();
+
+  if ((RequestFields.VersionStr.size() > 5) && (substr(versionbegin, versionbegin+5) != "HTTP/")) {
+    //No version, assume simple request
+    //part after method is URI
+    RequestFields.URIStr = CurLine;
+    return GH_SIMPLE_REQUEST;
+  }
+
+  //URI String (in between End of first and Start of last)
+  //<Method> <WhiteSpace> <URI> <WhiteSpace> <Version> <CRLF>
+  //                  next^             end^
+  text_t spacebuffer;
+  text_t::const_iterator here = next;
+  while (here != end) {
+    // do this to remove trailing space
+    if (*here == ' ' || *here == '\t') {
+      spacebuffer.push_back(*here);
+    } else {
+      if (!spacebuffer.empty()) {
+	RequestFields.URIStr += spacebuffer;
+	spacebuffer.clear();
+      }
+      RequestFields.URIStr.push_back(*here);
+    }
+    ++here;
+  }
+
+  //Only accept requests from HTTP/0.9 or HTTP/1.X clients, we'll
+  //assume that anything else will require an upgrade or patch
+  if ((RequestFields.VersionStr.size() > 7) && (substr(versionbegin, versionbegin+7) != "HTTP/1.")) {
+    return GH_UNKNOWN_VERSION;
+  }
+  
+  //Get the rest of the lines
+  CurLine = NextLine;
+  
+  while (!CurLine.empty()) {//Blank Line, we're done
+    do {//Get Next Line, append it if the first charactor is space
+      if (GetLine(NextLine, RequestInfo.ClientSocket, RequestInfo.IOBuffer,
+		  RequestInfo.IOBufferSize, ReadBufferIndex, DataInBuffer,
+		  RequestInfo.ThreadNum) != 0)
+	return GH_ERROR;
+      if ((*(NextLine.begin()) == ' ') || (*(NextLine.begin()) == '\t')) {
+	CurLine += NextLine;
+      }
+    } while ((*(NextLine.begin()) == ' ') || (*(NextLine.begin()) == '\t'));
+    
+    GetWord(FieldNameStr, CurLine.begin(), CurLine.end(), next);
+    uc(FieldNameStr);
+    
+    FieldValStr = substr(next, CurLine.end());
+    
+    //Process it
+    //In order of expected commonality
+    //All constants are in canonized, thus in upper case and case sensitive
+    //comparisons are used
+
+    //--Just About Always--
+    if (FieldNameStr == "ACCEPT:") {
+      if (!RequestFields.AcceptStr.empty()) {
+	RequestFields.AcceptStr += ", ";
+      }
+      RequestFields.AcceptStr += FieldValStr;
+    }
+    else if (FieldNameStr == "DATE:") {
+      RequestFields.DateStr = FieldValStr;
+    }
+    else if (FieldNameStr == "USER-AGENT:") {
+      RequestFields.UserAgentStr = FieldValStr;
+    }
+    else if (FieldNameStr == "CONNECTION:") {
+      RequestFields.ConnectionStr = FieldValStr;
+    }
+    //--Sometimes--
+    else if (FieldNameStr == "ACCEPT-LANGUAGE:") {
+      RequestFields.AcceptLangStr = FieldValStr;
+    }
+    else if (FieldNameStr == "REFERER:") {
+      RequestFields.RefererStr = FieldValStr;
+    }
+    else if (FieldNameStr == "IF-MODIFIED-SINCE:") {
+      RequestFields.IfModSinceStr = FieldValStr;
+    }
+    //--Uncommon--
+    else if (FieldNameStr == "FROM:") {
+      RequestFields.FromStr = FieldValStr;
+    }
+    else if (FieldNameStr == "MIME-VERSION:") {
+      RequestFields.MIMEVerStr = FieldValStr;
+    }
+    else if (FieldNameStr == "PRAGMA:") {
+      RequestFields.PragmaStr = FieldValStr;
+    }
+    //--Special case--
+    else if (FieldNameStr == "AUTHORIZATION:") {
+      RequestFields.AuthorizationStr = FieldValStr;
+    }
+    else if (FieldNameStr == "CONTENT-LENGTH:") {
+      RequestFields.ContentLengthStr = FieldValStr;
+    }
+    else if (FieldNameStr == "CONTENT-TYPE:") {
+      RequestFields.ContentTypeStr = FieldValStr;
+    }
+    else if (FieldNameStr == "CONTENT-ENCODING:") {
+      RequestFields.ContentEncodingStr = FieldValStr;
+    }
+    else if (!FieldNameStr.empty()) {
+      //Add it to the other headers
+
+      //Remove the colon
+      if (*(FieldNameStr.end()-1) == ':') {
+	FieldNameStr.pop_back();
+      }
+      RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Var = FieldNameStr;
+      RequestFields.OtherHeaders[RequestFields.NumOtherHeaders].Val = FieldValStr;
+      ++RequestFields.NumOtherHeaders;
+    }
+    CurLine = NextLine;
+  }
+  
+  if (!RequestFields.ContentLengthStr.empty()) { //Do we have attached data?
+    unsigned int NumRecv;
+    
+    RequestFields.ContentLength = RequestFields.ContentLengthStr.getint();
+    if (RequestFields.ContentLength > 0) {
+
+      //Allocate memory
+      RequestFields.Content = new BYTE[RequestFields.ContentLength];
+      
+      //Get rest of data from get lines
+      NumRecv = DataInBuffer - ReadBufferIndex;
+      
+      if (NumRecv >RequestFields.ContentLength) {
+	//Overflow, only read what they said they'd send
+	NumRecv = RequestFields.ContentLength;
+      }
+      memcpy(RequestFields.Content, RequestInfo.IOBuffer + ReadBufferIndex,
+	     NumRecv);
+      
+      while (NumRecv < RequestFields.ContentLength) {
+	NumRecv += GetData(RequestInfo.ClientSocket,
+			   RequestFields.Content + NumRecv,
+			   RequestFields.ContentLength - NumRecv,
+			   RequestInfo.ThreadNum);
+	if (NumRecv < 0) return GH_ERROR;
+      }
+
+      // It seems to be important on NT that all available data was read
+      // from the socket before the socket is closed (otherwise netscape
+      // throws a "connection reset by peer" error). Since netscape seems
+      // to send a few extra bytes in certain situations we'll make sure we
+      // slurp it all up here.
+      char *tmpbuffer = new char[100]; // this had new char(100)????
+      //      unsigned long int nonblockmode=1;
+      //      ioctlsocket(RequestInfo.ClientSocket, FIONBIO, &nonblockmode);
+      d_recv(RequestInfo.ClientSocket, tmpbuffer, 100, 0);
+      delete []tmpbuffer;
+
+    }
+    else {
+      RequestFields.Content = NULL;
+      RequestFields.ContentLength = 0;
+    }
+  }
+  else {
+    RequestFields.Content = NULL;
+    RequestFields.ContentLength = 0;
+  }
+  
+  return GH_10_REQUEST;
+}
+
+/******************************************************************************/
+void CleanUpHTTPHeaders(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields) {
+  //Clean up memory allocated for the Content
+  if (RequestFields.Content != NULL) {
+    delete[] RequestFields.Content;
+  }
+  
+  // clean up memory allocated for the IOBuffer
+  if (RequestInfo.IOBuffer != NULL) {
+    delete[] RequestInfo.IOBuffer;
+    RequestInfo.IOBuffer = NULL;
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpreq.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpreq.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpreq.h	(revision 10506)
@@ -0,0 +1,143 @@
+/**********************************************************************
+ *
+ * httpreq.h
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef HTTPREQ_H
+#define HTTPREQ_H
+
+// need this to avoid bizarre compiler problems under VC++ 6.0
+#if !defined (GSDL_NAMESPACE_BROKEN) && !defined (GSDL_USE_IOS_H)
+# include <iostream>
+# include <fstream>
+using namespace std;
+#endif
+
+#include "locate.h"
+#include "text_t.h"
+
+/*
+Module Name: HTTP Request
+Purpose: Parses HTTP requests and then calls the appropriate function
+	to respond to the request
+Public Functions:
+	Request Thread
+*/
+
+// Public Data Structures
+
+//Used for sending information to the request thread
+struct RequestThreadMessageT {
+  SOCKADDR_IN ClientSockAddr;
+  SOCKET ClientSocket;
+  int AddrLen;
+};
+
+#define MAX_OTHER_HEADERS 100
+
+struct RequestHeaderT {
+  text_t Var;
+  text_t Val;
+};
+
+struct RequestFieldsT {
+  //Simple request line info v0.9
+  text_t MethodStr;
+  text_t URIStr;
+  //added v1.0
+  text_t VersionStr;
+  //General Header
+  text_t DateStr;
+  text_t MIMEVerStr;
+  text_t PragmaStr;
+  //Request Header
+  text_t AuthorizationStr;
+  text_t FromStr;
+  text_t IfModSinceStr;
+  text_t RefererStr;
+  text_t UserAgentStr;
+  //Entity Header (Only CGI stuff)
+  text_t ContentEncodingStr;
+  text_t ContentTypeStr;
+  text_t ContentLengthStr;
+  //v1.0 Optional (the more common ones)
+  text_t AcceptStr;
+  text_t AcceptLangStr;
+  //v1.1 Exentions
+  text_t ConnectionStr;
+  //Pointer to buffer containing the content
+  DWORD ContentLength;
+  BYTE *Content;
+  
+  //Other Headers
+  int NumOtherHeaders;
+  RequestHeaderT OtherHeaders[MAX_OTHER_HEADERS];
+};
+
+struct RequestInfoT {
+  int ThreadNum;
+  
+  //Buffer for IO operations (so we're not constantly reallocating buffers)
+  BYTE *IOBuffer;
+  int IOBufferSize;
+  
+  //Socket the request is on and its address
+  SOCKET ClientSocket;
+  SOCKADDR_IN ClientSockAddr;
+  int AddrLen;
+  
+  //Should we keep the connection alive?
+  BOOL KeepAlive;
+};
+
+
+// Public Functions
+
+/*
+Function Name: RequestThread
+Purpose: Was the HTTP request processing thread
+         Now just a standard procedure called to process a request
+Parameters:
+	       Pointer to packed parameter structure
+*/
+void RequestThread(RequestThreadMessageT *Parameters);
+
+/*
+Function Name: Process 1.0 Request
+Purpose: Sends a HTTP 1.0 (plus some) reply to a HTTP 1.x request
+Parameters:
+	ClientSocket - Socket the client is on
+	ClientSockAddr - Address of client
+	AddrLen - Length of client address
+	RequestInfo - Structure storing the parsed headers
+	KeepAlive - To be set to true if we are maintainig the connection
+	IOBuffer - Pointer to buffer allocated for IO operations
+	TheadNum - Number of calling thread for debugging
+Notes: The function uses "Connection: Keep-Alive" as written in the HTTP/1.1
+	draft and implemented by Netscape and MSIE
+*/
+void Process10Request(RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsend.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsend.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsend.cpp	(revision 10506)
@@ -0,0 +1,109 @@
+/**********************************************************************
+ *
+ * httpsend.cpp
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+#include "netio.h"
+#include "httpreq.h"
+#include "httpsend.h"
+
+//Private Function Declarations
+/*
+Function Name: Check IMS Date
+Purpose: Checks the string date of an "If Modified Since" header against
+	a file date stamp.
+Parameters:
+	FileTime - Time stamp on file
+	IMSStr - "If Modified Since" date string
+Returns: TRUE if the file has been modified since the given date or
+	the data can not be resolved (the string to date function will log
+	any errors)
+*/
+BOOL CheckIMSDate(SYSTEMTIME &FileTime, char *IMSStr);
+
+//Public Functions
+/******************************************************************************/
+
+void SendHTTPError(int ErrorNum, char *ErrorTitleStr, char *ErrorDescStr, 
+		   RequestInfoT &RequestInfo, RequestFieldsT &RequestFields) {
+  char Header[512];
+  char Body[512];
+
+  char ErrorNumStr[17];
+  
+  DWORD BodyLength;
+  char BodyLengthStr[17];
+
+  int HeaderLength;
+  
+  itoa(ErrorNum, ErrorNumStr, 10);
+  
+  // Didn't find it, build the message manually
+  Body[0] = 0;
+  strcat(Body, "<HTML><HEAD><TITLE>Server Error</TITLE></HEAD><BODY>\n");
+  strcat(Body, "<H1>Error ");
+  strcat(Body, ErrorNumStr);
+  strcat(Body, ": ");
+  strcat(Body, ErrorTitleStr);
+  strcat(Body, "</H1>\n");
+  strcat(Body, ErrorDescStr);
+  strcat(Body, "\n</BODY></HTML>");
+  BodyLength = (DWORD) strlen(Body);
+
+  //Build Header
+  Header[0] = 0;
+  //Status Line
+  strcat(Header, "HTTP/1.0 ");
+  strcat(Header, ErrorNumStr);
+  strcat(Header, " ");
+  strcat(Header, ErrorDescStr);
+  strcat(Header, "\r\n");
+  //Server
+  strcat(Header, "Server: GSDL\r\n");
+  //Content Type (assume HTML)
+  strcat(Header, "Content-Type: text/html\r\n");
+  //Content Length
+  itoa(BodyLength, BodyLengthStr, 10);
+  strcat(Header, "Content-Length: ");
+  strcat(Header, BodyLengthStr);
+  strcat(Header, "\r\n");
+  //Single CRLF to end header
+  strcat(Header, "\r\n");
+  
+  HeaderLength = strlen(Header);
+  
+  //Send header
+  SendData(RequestInfo.ClientSocket, (BYTE *) Header, strlen(Header), RequestInfo.ThreadNum);
+  //Send generated data
+  SendData(RequestInfo.ClientSocket, (BYTE *) Body, BodyLength, RequestInfo.ThreadNum);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsend.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsend.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsend.h	(revision 10506)
@@ -0,0 +1,51 @@
+/**********************************************************************
+ *
+ * httpsend.h
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by 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.
+ *
+ *********************************************************************/
+
+/*
+Module Name: HTTP Send
+Purpose: Functions for sending HTTP responses to 1.X requests
+Public Functions:
+	SendHTTPError
+Notes: Considering adding a version number parameter to these functions.  Right
+	now the way people are implementing HTTP/1.1 is by adding the new stuff
+	to 1.0 requests.  I don't know of any browsers sending 1.1 requests yet.
+*/
+
+/*
+Function Name: Send HTTP Error
+Purpose: Sends a given error message to the client with either the error file
+			as a body or a default error message body.  Common and refenece log
+			entries are written, but not to the count log.
+Parameters:
+	ErrorNum - HTTP error number to send
+	ErrorTitleStr - Title of the error
+	ErrorDescStr - String describing the error
+	RequestInfo - HTTP request information (see httpreq.h)
+	RequestFields - Parsed HTTP header info (see httpreq.h)
+*/
+void SendHTTPError(int ErrorNum, char *ErrorTitleStr, char *ErrorDescStr, 
+		   RequestInfoT &RequestInfo, RequestFieldsT &RequestFields);
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsrv.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsrv.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsrv.cpp	(revision 10506)
@@ -0,0 +1,103 @@
+/**********************************************************************
+ *
+ * httpsrc.cpp
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+#include "netio.h"
+#include "settings.h"
+#include "httpreq.h"
+#include "httpsrv.h"
+#include "locate.h"
+
+//Private Functions
+
+/*
+Function Name: HTTP Server Answer
+Purpose: Answers messages saying that a connection is ready to start
+*/
+void HTTPServerAnswer();
+
+//Module Vars
+static SOCKET ServerSocket = INVALID_SOCKET;
+
+static HWND MsgWindow;
+
+/******************************************************************************/
+// returns 0 on success, and a WSA error otherwise
+int StartHTTPServer(HWND PassedMsgWindow) {
+  
+  MsgWindow = PassedMsgWindow;
+  //Create the server socket
+  return CreateListeningSocket(gsdl_port_num, MsgWindow, HTTP_SERVER_MSG, ServerSocket);
+}
+
+/******************************************************************************/
+void EndHTTPServer()
+{
+  //Stop the listening socket
+  DestroyListeningSocket(ServerSocket, MsgWindow);
+}
+
+/******************************************************************************/
+void ProcessHTTPServerMsg(WPARAM Socket, LPARAM MsgInfo) {
+  log_message("accept message arrived\n");
+  if (Socket != ServerSocket) {
+    if (gsdl_keep_log || gsdl_show_console) log_message("Incorrect socket sent in message");
+  }
+  switch (WSAGETSELECTEVENT(MsgInfo)) {
+  case FD_ACCEPT:
+    switch (WSAGETSELECTERROR(MsgInfo)) {
+    case WSAENETDOWN:
+      LogCriticalError("1","Network Down");
+      break;
+    default: //No Error
+      HTTPServerAnswer();
+    }
+    break;
+  }
+}
+
+/******************************************************************************/
+void HTTPServerAnswer() {
+  SOCKADDR_IN ClientSockAddr;
+  SOCKET ClientSocket;
+  int AddrLen = sizeof(SOCKADDR_IN);
+  RequestThreadMessageT Parameters;
+  while (AnswerListeningSocket(ServerSocket, ClientSocket, ClientSockAddr, AddrLen) == 0) {
+    log_message("Answering socket\n");
+    //Call the thread procedure to handle the connection
+    Parameters.ClientSockAddr = ClientSockAddr;
+    Parameters.ClientSocket = ClientSocket;
+    Parameters.AddrLen = AddrLen;
+    RequestThread(&Parameters);
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsrv.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsrv.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/httpsrv.h	(revision 10506)
@@ -0,0 +1,57 @@
+/**********************************************************************
+ *
+ * httpsrv.h
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by 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.
+ *
+ *********************************************************************/
+
+#define HTTP_SERVER_MSG WM_USER + 23
+
+/*
+Function Name: Start HTTP Server
+
+Purpose: Starts the HTTP server.  Inits Winsock, MIME, loads registry
+         stuff, etc.
+
+Parameters:
+	PassedMsgWindow - The handle of the window that handles messages.  Needed
+                          to setup WSASelect notification of socket events and
+                          to send a shutdown message on error.  */
+
+// returns 0 on success, and a WSA error otherwise
+int StartHTTPServer(HWND PassedMsgWindow);
+
+/*
+Function Name: End HTTP Server
+Purpose: Ends the HTTP server.  Cleans up MIME, users, etc.
+*/
+void EndHTTPServer();
+
+/*
+Function Name: Process HTTP Server Message
+Purpose: Processes HTTP_SERVER_MSG messages.
+Parameters:
+	Socket - The socket the message is regarding (WPARAM)
+	MsgInfo - The messsage (LPARAM)
+*/
+void ProcessHTTPServerMsg(WPARAM Socket, LPARAM MsgInfo);
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/locate.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/locate.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/locate.cpp	(revision 10506)
@@ -0,0 +1,274 @@
+/**********************************************************************
+ *
+ * locate.cpp
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+#include <windows.h>
+#include <stdio.h>
+#include "locate.h"
+#include "settings.h"
+
+/* The following values are inserted or used by FNORD.CPP */
+HWND GSDL_Window;
+int line_spacing;
+RECT text_rect;
+
+
+static FILE *log_file=NULL;
+
+static int location_found=0;
+text_t data_location;
+
+void set_location(text_t possible)
+{
+  if (location_found != 0) return;
+  if (!possible.empty()) {
+    data_location = possible;
+    if (*(data_location.end()-1) != '\\') {
+      data_location.push_back('\\');
+    }
+    location_found = 1;
+  }
+}
+
+void find_location(void)
+{
+  if (location_found != 0) return;
+  
+  char here[MAX_FILENAME_SIZE];
+  char *send;
+
+  if (GetModuleFileName(NULL,here,MAX_FILENAME_SIZE) <= 0) {
+    // failed
+    data_location.clear();
+  } else {
+    send = strrchr(here,'\\');
+    if (send != NULL) {
+      ++send;
+    } else {
+      send = strchr(here,':');
+      if (send != NULL) {
+        ++send;
+      } else {
+        send = here;
+      }
+    }
+  }
+  *send = 0;
+  data_location.setcstr(here);
+  location_found = 1;
+}
+
+void open_log_file()
+{
+  if (log_file != NULL) fclose(log_file);
+  log_file = fopen(gsdl_log_name, "a");
+  if (log_file != NULL) {
+	  fprintf (log_file, "\n\n-----------\n");
+	  fprintf (log_file, "log started\n");
+	  fprintf (log_file, "-----------\n\n");
+  }
+}
+
+void close_log_file()
+{
+  if (log_file != NULL) {
+    fclose(log_file);
+    log_file = NULL;
+  }
+}
+
+#define CONSOLE_BUFFER_SIZE 2048
+char console_buffer[CONSOLE_BUFFER_SIZE];
+char *next_console, *last_console;
+int console_top, console_y;
+
+void activate_console(void)
+{
+  gsdl_show_console = 1;
+  next_console = console_buffer;
+  *next_console = 0;
+  last_console = next_console;
+  console_y = console_top = text_rect.top +
+    (text_rect.bottom - text_rect.top + 1) % line_spacing / 2;
+  InvalidateRect(GSDL_Window,NULL,TRUE);
+}
+
+void deactivate_console(void)
+{
+  gsdl_show_console = 0;
+  InvalidateRect(GSDL_Window,NULL,TRUE);
+}
+
+void refresh_console(HDC dc)
+{
+  int loc;  char *b, *e;
+  loc = console_top;
+  for (e = console_buffer;;) {
+    b = e;
+    while (*e >= ' ') ++e;
+    TextOut(dc,0,loc,b,e-b);
+    loc += line_spacing;
+    if (*e == 0) break;
+    ++e;
+    if (*e == 0) break;
+    }
+}
+
+void scroll(HDC dc, int nbits)
+{
+  RECT scroll, clip, update;
+
+  scroll.left = clip.left = text_rect.left;
+  scroll.right = clip.right = text_rect.right;
+  clip.top = console_top;
+  clip.bottom = text_rect.bottom;
+  scroll.top = clip.top + nbits;
+  scroll.bottom = text_rect.bottom;
+  ScrollDC(dc,0,-nbits,&scroll,&clip,NULL,&update);
+  FillRect(dc,&update, (HBRUSH)GetStockObject(WHITE_BRUSH));
+}
+
+int remove_line()
+{
+  char *bin, *bout;
+  bin = bout = console_buffer;
+  while (*bin >= ' ') ++bin;
+  if (*bin != 0) {
+    ++bin;
+    if (*bin != 0) {
+      while (*bin != 0) *bout++ = *bin++;
+      *bout = *bin;
+      last_console -= (bin - bout);
+      next_console = bout;
+      return line_spacing;
+      }
+    }
+  next_console = console_buffer;
+  *next_console = 0;
+  last_console = next_console;
+  return 0;
+}
+
+void display_line(HDC dc, char *line, int nch)
+{
+  int scroll_needed = 0;
+  while (next_console + nch + 1 
+         > console_buffer + CONSOLE_BUFFER_SIZE)
+    scroll_needed += remove_line();
+  console_y -= scroll_needed;
+  if (*last_console == '\n') {
+    console_y += line_spacing;
+    if (console_y + line_spacing > text_rect.bottom) {
+      scroll_needed += remove_line();
+      console_y -= line_spacing;
+      }
+    last_console = next_console;
+    }
+  if (scroll_needed != 0) scroll(dc, scroll_needed);
+  while (nch-- > 0) *next_console++ = *line++;
+  TextOut(dc,0,console_y,last_console,next_console-last_console);
+  *next_console = *line;
+  if (*next_console != 0) {
+    last_console = next_console;
+    ++next_console;
+    *next_console = 0;
+    }
+}
+
+void display_text(HDC dc, char *buffer)
+{
+  char *bl, *bp;
+  for (bl = buffer;;) {
+    for (bp = bl;;) {
+      if (*bp == '\t') *bp = ' ';
+      if (*bp < ' ') break;
+      ++bp;
+      }
+    if (*bp != 0) *bp = '\n';
+    display_line(dc, bl, bp-bl);
+    if (*bp == 0) break;
+    bl = bp+1;
+    if (*bl == 0) break;
+    }
+}
+
+void log_message(char *msg)
+{
+  if (log_file != NULL) {
+    fprintf(log_file,"%s",msg);
+    fflush(log_file);
+  }
+  if (gsdl_show_console) {
+    char buffer[1024];  HDC dc;
+    sprintf(buffer,"%s",msg);
+    dc = GetDC(GSDL_Window);
+    display_text(dc,buffer);
+    ReleaseDC(GSDL_Window,dc);
+  }
+}
+
+void log_message_N(char*msg, int n)
+{
+  if (log_file != NULL) {
+    int len = 0;
+    while (len < n) {
+      fputc (msg[len], log_file);
+      ++len;
+    }
+    fflush(log_file);
+  }
+  
+  // these messages are not send to the console
+  if (gsdl_show_console) {
+    HDC dc;
+    dc = GetDC(GSDL_Window);
+    display_text(dc,"message only written to log file\n");
+    ReleaseDC(GSDL_Window,dc);
+  }
+}
+
+void LogCriticalError(char *cderr, char *Msg)
+{
+  char MsgBoxStr[200];
+  
+  strcpy(MsgBoxStr, "Critical Error Number ");
+  strcat(MsgBoxStr, cderr);
+  strcat(MsgBoxStr, "\n");
+  strcat(MsgBoxStr, Msg);
+  strcat(MsgBoxStr, "\nGreenstone Digital Library software\nshutting down");
+  MessageBox(GSDL_Window, MsgBoxStr, "Greenstone Digital Library Software",
+	     MB_OK | MB_ICONERROR);
+  PostMessage(GSDL_Window, WM_DESTROY, 0, 0);
+}
+
+
+/* returns second-first taking into account wrap around */
+DWORD DiffTickCounts (DWORD first, DWORD second) 
+{
+  if (second >= first) return (second-first);
+  return (MAXDWORD-first+1+second);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/locate.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/locate.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/locate.h	(revision 10506)
@@ -0,0 +1,56 @@
+/**********************************************************************
+ *
+ * locate.h
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef MAX_FILENAME_SIZE
+#define MAX_FILENAME_SIZE 2048
+#endif
+
+#include "text_t.h"
+
+extern HWND GSDL_Window;
+extern int line_spacing;
+extern RECT text_rect;
+
+void refresh_console(HDC dc);
+
+extern text_t data_location;
+
+extern void set_location(text_t possible);
+extern void find_location(void);
+
+extern void open_log_file(void);
+extern void close_log_file(void);
+extern void log_message(char *msg);
+extern void log_message_N(char*msg, int n);
+
+extern void activate_console(void);
+extern void deactivate_console(void);
+
+extern void LogCriticalError(char *cderr, char *Msg);
+
+/* returns first-second taking into account wrap around */
+extern DWORD DiffTickCounts (DWORD first, DWORD second);
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/netio.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/netio.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/netio.cpp	(revision 10506)
@@ -0,0 +1,465 @@
+/**********************************************************************
+ *
+ * netio.cpp
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+#include "netio.h"
+#include "locate.h"
+#include "d_winsock.h"
+
+//Private Variables and Declarations
+
+//Max string size for a host name
+#define MAXHOSTNAME 100
+
+//Timeout for waiting between "packets" in seconds
+#define NETIO_CONN_TIMEOUT 20 //3 sec  was 180 @@@@@ WJR
+
+#define HTTP_DNS_MSG WM_USER + 1
+int dns_msg_received = 0;
+int dns_msg_error = 0;
+
+DWORD LocalIPNumber;
+char LocalName[MAXHOSTNAME];
+
+//Private Function Declarations
+DWORD GetHostID();
+
+// returns 0 on success,
+// WSASYSNOTREADY, WSAVERNOTSUPPORTED, or WSAEINVAL on failure
+int InitNetIO() {
+  WSADATA Data;
+  
+  // Load Winsock
+  int err = d_WSAStartup(MAKEWORD(1, 1), &Data);
+  
+  // get local IP number
+  if (err == 0) LocalIPNumber = GetHostID();
+  else LocalIPNumber = INADDR_ANY;
+  
+  // set the Local Name to "" for now
+  LocalName[0] = 0;
+  
+  return err;
+}
+
+
+void CleanUpNetIO() {
+  //Experimental, heard this will better clean up, especialy if a call is
+  //blocking....
+  d_WSAUnhookBlockingHook();
+
+  //Clean up Winsock
+  d_WSACleanup();
+}
+
+
+void ResetNetIO() {
+  //Figure out the local name on first querry, set to "" until then...
+  LocalName[0] = 0;
+}
+
+
+DWORD GetLocalIP() {
+  return LocalIPNumber;
+}
+
+long __stdcall DNSWindowProc(HWND hWnd,UINT wMsg, WPARAM wParam, LPARAM lParam) {
+  if (wMsg == HTTP_DNS_MSG) {
+    dns_msg_received = 1;
+    dns_msg_error = WSAGETASYNCERROR(lParam);
+    return 0;
+  }
+  
+  return DefWindowProc(hWnd, wMsg, wParam, lParam);
+}
+
+char *GetLocalName(HINSTANCE hInstance) {
+  // static in case it is written to after the function has finished
+  // (I did not error checking on WSACancelAsyncRequest)
+  static char buf[MAXGETHOSTSTRUCT];
+	
+  if (LocalName[0] == 0) {
+    hostent *DNSResult = NULL;
+    in_addr LocalInAddr;
+    
+    // if we failed to get the local IP number
+    // use the loop-back device
+    if (LocalIPNumber == INADDR_ANY) {
+      strcpy(LocalName, "127.0.0.1"); // loop-back device
+      return LocalName;
+    }
+    
+    //Convert the number to an in_addr struct
+    LocalInAddr.s_addr = LocalIPNumber;
+    
+    // if we fail to find the domain name we will
+    // still want the IP address
+    strcpy(LocalName, d_inet_ntoa(LocalInAddr));
+    
+    // make sure they actually passed in an instance handle
+    if (hInstance == NULL) return LocalName;
+    
+    // do a async domain name lookup so that we
+    // can control the timeout
+    
+    // create a window class and window to handle the async messages
+    WNDCLASS wc; HWND hwndDNS;
+    
+    wc.style = 0;
+    wc.lpfnWndProc = DNSWindowProc;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = hInstance;
+    wc.hIcon = NULL;
+    wc.hCursor = NULL;
+    wc.hbrBackground = NULL;
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = "GSDL DNS Window";
+    if (!RegisterClass(&wc)) return LocalName;
+    
+    hwndDNS = CreateWindow("GSDL DNS Window", "", 
+			   WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, 
+			   NULL, NULL, hInstance, NULL);
+    if (!hwndDNS) return LocalName;
+    
+    // process all messages currently on the queue
+    MSG Message;
+    while (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
+      TranslateMessage(&Message); /* translate keyboard messages */
+      DispatchMessage(&Message);  /* return control to Windows NT */
+    }
+    
+    //Do a async DNS lookup on the IP number
+    dns_msg_received = 0;
+    dns_msg_error = 0;
+    HANDLE asyncGetHostReq = d_WSAAsyncGetHostByAddr(
+						     hwndDNS, HTTP_DNS_MSG, (char *)&(LocalInAddr), 
+						     4, PF_INET, buf, MAXGETHOSTSTRUCT);
+    
+    if (asyncGetHostReq != NULL) {
+      // wait 5 seconds for the request to complete
+      int now = GetTickCount();
+      while ((DiffTickCounts(now, GetTickCount()) < 5000) && !dns_msg_received) {
+	if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE)) {
+	  TranslateMessage(&Message); /* translate keyboard messages */
+	  DispatchMessage(&Message);  /* return control to Windows NT */
+	} else {
+	  Sleep(1);
+	}
+      }
+      if (!dns_msg_received)
+	d_WSACancelAsyncRequest(asyncGetHostReq);
+    }
+    
+    DestroyWindow(hwndDNS);
+    
+    if (dns_msg_received && (dns_msg_error == 0)) {
+      //Worked, use the primary name
+      strcpy(LocalName, ((hostent *)(buf))->h_name);
+      //Convert it to lower case for cosmedic reasons
+      CharLower(LocalName);
+    }
+  }
+  return LocalName;
+}
+
+
+// returns 0 on success, and a WSA error message on failure.
+// possible error messages include:
+// WSANOTINITIALISED, WSAENETDOWN, WSAEAFNOSUPPORT, WSAEINPROGRESS, WSAEMFILE,
+// WSAENOBUFS, WSAEPROTONOSUPPORT, WSAEPROTOTYPE, WSAESOCKTNOSUPPORT,
+// WSAEADDRINUSE, WSAEINVAL, WSAEISCONN, WSAENOTSOCK, WSAEOPNOTSUPP
+
+#define MAXBINDCOUNT 4096
+int CreateListeningSocket(int &PortNum, HWND MsgWindow, 
+			  WORD SocketMsg, SOCKET &ServerSocket) {
+  int err = 0;
+  SOCKADDR_IN ServerSockAddr;
+  int bind_port, bind_count;
+  
+  //Create the Server Socket
+  ServerSocket = d_socket(AF_INET, SOCK_STREAM, 0);
+  if (ServerSocket == INVALID_SOCKET) return d_WSAGetLastError();
+  
+  bind_port = PortNum;
+  for (bind_count=0; bind_count < MAXBINDCOUNT; ++bind_count) {
+    // Set up the Server Socket Address
+    memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); //Needed?
+    ServerSockAddr.sin_port = d_htons( (WORD) bind_port);
+    ServerSockAddr.sin_family = AF_INET;
+    ServerSockAddr.sin_addr.s_addr = d_htonl(INADDR_ANY);
+    
+    // Try to bind the socket with the address
+    if (d_bind(ServerSocket, (LPSOCKADDR) &ServerSockAddr,
+	       sizeof(ServerSockAddr)) != SOCKET_ERROR) {
+      PortNum = bind_port;
+      break;
+    }
+    
+    // make sure it failed to bind because it was
+    // already bound
+    err = d_WSAGetLastError ();
+    if (err != WSAEADDRINUSE) return err;
+    
+    // Or choose another port number to try
+    if (bind_port == 80) bind_port = IPPORT_RESERVED+1;
+    else if (bind_count == 0) bind_port = 80;
+    else ++bind_port;
+  }
+  
+  // return an error in we couldn't find a valid port
+  if (bind_count == MAXBINDCOUNT) return WSAEADDRINUSE;
+  
+  // Start listening for connections
+  if (d_listen(ServerSocket, SOMAXCONN) == SOCKET_ERROR)
+    return d_WSAGetLastError ();	
+  
+  // Set up event for new connections
+  if (d_WSAAsyncSelect(ServerSocket, MsgWindow, SocketMsg, FD_ACCEPT) == SOCKET_ERROR)
+    return d_WSAGetLastError ();
+  
+  return 0;
+}
+
+
+int AnswerListeningSocket(SOCKET ServerSocket, SOCKET &ClientSocket, 
+			  SOCKADDR_IN &ClientSockAddr, int AddrLen) {
+  if (d_WSAIsBlocking()) {
+    log_message("rejected connect due blocking\n");
+    return -1;
+  }
+  
+  ClientSocket = d_accept(ServerSocket, (LPSOCKADDR) &ClientSockAddr, &AddrLen);
+  if (ClientSocket == INVALID_SOCKET) {
+    log_message("accept failed - connection lost\n");
+    return -1;
+  }
+  
+  log_message("accept success - connection made\n");
+  return 0;
+}
+
+void DestroyListeningSocket(SOCKET &ServerSocket, HWND MsgWindow) {
+  //Remove any message notification
+  d_WSAAsyncSelect(ServerSocket, MsgWindow, 0, 0);
+  
+  //Close the socket
+  CloseSocket(ServerSocket);
+}
+
+void CloseSocket(SOCKET &TargetSocket) {
+  if (TargetSocket != INVALID_SOCKET) {
+    //Since we're closing the socket, there's not much I can do about errors
+    //now so I'm not gonna bother checking...
+    
+    //Shutdown both ends, assume we have all data...
+    d_shutdown(TargetSocket, 2);
+    
+    d_closesocket(TargetSocket);
+    
+    //Make sure we can't use the old handle again...
+    TargetSocket = INVALID_SOCKET;
+  }
+}
+
+int GetData(SOCKET ClientSocket, BYTE *IOBuffer, int IOBufferSize,
+	    int ThreadNum) {
+  
+  int NumRecv;
+  int Error;
+  struct timeval Timeout;
+  fd_set SocketSet;
+  
+  //Set up a socket set structure with just ClientSocket for  select(..)
+  FD_ZERO(&SocketSet);
+  FD_SET(ClientSocket, &SocketSet);
+  
+  //set timeout
+  Timeout.tv_sec = NETIO_CONN_TIMEOUT;
+  Timeout.tv_usec = 0;
+  
+  do {
+    NumRecv = d_recv(ClientSocket, (char *) IOBuffer, IOBufferSize, 0);
+    if (NumRecv == 0) {
+      //Lost connect
+      return -1;
+      
+    } else if (NumRecv == SOCKET_ERROR) {
+      Error = d_WSAGetLastError();
+      if (Error == WSAEWOULDBLOCK) {
+	NumRecv = 0;
+	//Wait for socket to be readable
+	if (d_select(0, &SocketSet, NULL, NULL, &Timeout) != 1) {
+	  //Timeout
+	  return -1;
+	}
+	
+      } else {
+	//Assume connection terminated
+	return -1;
+      }
+    }
+  } while(NumRecv == 0);
+  return NumRecv;
+}
+
+int GetLine(text_t &OutStr, SOCKET ClientSocket, BYTE *IOBuffer, int IOBufferSize,
+	    int &BufferIndex, int &DataInBuffer, int ThreadNum) {
+
+  OutStr.clear();
+  char CurChar;
+  
+  do {
+    if (BufferIndex == DataInBuffer) { //Need more data
+      DataInBuffer = GetData(ClientSocket, IOBuffer, IOBufferSize, ThreadNum);
+      if (DataInBuffer == -1) {
+	//Lost connect
+	return -1;
+      }
+      BufferIndex = 0;
+    }
+    CurChar = IOBuffer[BufferIndex];
+    ++BufferIndex;
+    if ((CurChar != 10) && (CurChar != 13))  {
+      OutStr.push_back(CurChar);
+    }
+  } while (CurChar != 10);
+  
+  return 0;
+}
+
+int SendData(SOCKET ClientSocket, BYTE *SendBuffer, int NumToSend,
+	     int ThreadNum) {
+  
+  int NumSent = 0;
+  int Error;
+  struct timeval Timeout;
+  fd_set SocketSet;
+  
+  char NumSentStr[50];
+  itoa(NumToSend, NumSentStr, 10);
+  
+  //Set up a socket set structure with just ClientSocket for  select(..)
+  FD_ZERO(&SocketSet);
+  FD_SET(ClientSocket, &SocketSet);
+  //set timeout
+  Timeout.tv_sec = NETIO_CONN_TIMEOUT;
+  Timeout.tv_usec = 0;
+  
+  while (NumToSend > 0) {
+    NumSent = d_send(ClientSocket, (char *) SendBuffer + NumSent, NumToSend, 0);
+    if (NumSent == 0) {
+      //Lost connect
+      return -1;
+    }
+    else if (NumSent == SOCKET_ERROR) {
+      Error = d_WSAGetLastError();
+      if (Error == WSAEWOULDBLOCK) {
+	NumSent = 0;
+	if (d_select(0, NULL, &SocketSet, NULL, &Timeout) != 1) {
+	  //Timeout
+	  return -1;
+	}
+      }
+      else {
+	//Lost Connection
+	return -1;
+      }
+    }
+    NumToSend -= NumSent;
+  }
+  return 0;
+}
+
+
+/******************************************************************************/
+//Private Functions
+/******************************************************************************/
+/*-----------------------------------------------------------
+ * Function: GetHostID()
+ *
+ * Description:
+ *  Get the Local IP address using the following algorithm:
+ *    - get local hostname with gethostname()
+ *    - attempt to resolve local hostname with gethostbyname()
+ *    if that fails:
+ *    - get a UDP socket
+ *    - connect UDP socket to arbitrary address and port
+ *    - use getsockname() to get local address
+ *
+ * Notes: Copyright by Bob Quinn, 1995, taken from his Winsock library
+ *        was removed from its original module unmodified
+ */
+DWORD GetHostID () {
+  char szLclHost [MAXHOSTNAME];
+  LPHOSTENT lpstHostent;
+  SOCKADDR_IN stLclAddr;
+  SOCKADDR_IN stRmtAddr;
+  int nAddrSize = sizeof(SOCKADDR);
+  SOCKET hSock;
+  int nRet;
+  
+  /* Init local address (to zero) */
+  stLclAddr.sin_addr.s_addr = INADDR_ANY;
+  
+  /* Get the local hostname */
+  nRet = d_gethostname(szLclHost, MAXHOSTNAME);
+  if (nRet != SOCKET_ERROR) {
+    /* Resolve hostname for local address */
+    lpstHostent = d_gethostbyname((LPSTR)szLclHost);
+    if (lpstHostent)
+      stLclAddr.sin_addr.s_addr = *((u_long FAR*) (lpstHostent->h_addr));
+  }
+  
+  /* If still not resolved, then try second strategy */
+  if (stLclAddr.sin_addr.s_addr == INADDR_ANY) {
+    /* Get a UDP socket */
+    hSock = d_socket(AF_INET, SOCK_DGRAM, 0);
+    if (hSock != INVALID_SOCKET)  {
+      /* Connect to arbitrary port and address (NOT loopback) */
+      stRmtAddr.sin_family = AF_INET;
+      stRmtAddr.sin_port   = d_htons(IPPORT_ECHO);
+      stRmtAddr.sin_addr.s_addr = d_inet_addr("128.127.50.1");
+      nRet = d_connect(hSock,
+		       (LPSOCKADDR)&stRmtAddr,
+		       sizeof(SOCKADDR));
+      if (nRet != SOCKET_ERROR) {
+	/* Get local address */
+	d_getsockname(hSock,
+		      (LPSOCKADDR)&stLclAddr,
+		      (int FAR*)&nAddrSize);
+      }
+      d_closesocket(hSock);   /* we're done with the socket */
+    }
+  }
+  return (stLclAddr.sin_addr.s_addr);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/netio.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/netio.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/netio.h	(revision 10506)
@@ -0,0 +1,160 @@
+/**********************************************************************
+ *
+ * netio.h
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+
+/*
+Module Name: Net IO
+Purpose: High level Socket IO and Misc socket routines
+Public Functions:
+	InitNetIO
+   CleanUpNetIO
+
+	GetLocalIP
+	GetLocalName
+
+   CreateListeningSocket
+   AnswerListeningSocket
+   DestroyListeningSocket
+
+   CloseSocket
+
+	GetData
+	GetLine
+
+	SendData
+	SendFile
+*/
+
+//Public Functions
+
+/*
+Function Name: Init Net IO
+Purpose: Initializes the module so calls can be made querying network
+         information for the local macnine.
+Notes: MUST be called before GetLocalIP and GetLocalName
+*/
+
+// returns 0 on success,
+// WSASYSNOTREADY, WSAVERNOTSUPPORTED, or WSAEINVAL on failure
+int InitNetIO();
+
+/*
+Function Name: Cleanup Net IO
+Purpose: Cleans up the module and unloads Winsock
+*/
+void CleanUpNetIO();
+
+/*
+Function Name: Reset Net IO
+Purpose: Resets internal data in NetIO to reflect registry changes, etc.
+*/
+void ResetNetIO();
+
+/*
+Function Name: Get Local IP
+Purpose: Gets the local IP number
+Returns: The local IP number as an double word (4 bytes)
+*/
+DWORD GetLocalIP();
+
+/*
+Function Name: Get Local Name
+Purpose: Gets the local Domain name, or if there is none, then the server
+address in dotted format.
+Returns: A string containing the local address
+*/
+char *GetLocalName(HINSTANCE hInstance);
+
+// returns 0 on success, and a WSA error message on failure.
+// possible error messages include:
+// WSANOTINITIALISED, WSAENETDOWN, WSAEAFNOSUPPORT, WSAEINPROGRESS, WSAEMFILE,
+// WSAENOBUFS, WSAEPROTONOSUPPORT, WSAEPROTOTYPE, WSAESOCKTNOSUPPORT,
+// WSAEADDRINUSE, WSAEINVAL, WSAEISCONN, WSAENOTSOCK, WSAEOPNOTSUPP
+int CreateListeningSocket(int &PortNum, HWND MsgWindow, 
+			  WORD SocketMsg, SOCKET &ServerSocket);
+
+int AnswerListeningSocket(SOCKET ServerSocket, SOCKET &ClientSocket, 
+			  SOCKADDR_IN &ClientSockAddr, int AddrLen);
+
+void DestroyListeningSocket(SOCKET &ServerSocket, HWND MsgWindow);
+
+void CloseSocket(SOCKET &TargetSocket);
+
+/*
+Function Name: Get Data
+Purpose: Gets data from a socket with muli-threaded debugging
+Parameters:
+	ClientSocket - The socket to get data from
+	IOBuffer - A pointer to a chunk of memory to put data in
+	IOBufferSize - Size of the buffer
+	ThreadNum - Number of the thread that called this functions used for debugging
+
+Returns: -1 on error, else the number of bytes received
+
+Notes:
+Removed socket error checking because I was unable to isolate what
+errors I was getting when getting a "rude" disconnect
+*/
+int GetData(SOCKET ClientSocket, BYTE *IOBuffer, int IOBufferSize, int ThreadNum);
+
+/*
+Function Name: Get Line
+Purpose: Gets a line of text (ended by a LF (10)) from a socket with buffered
+			input.  If the buffer is empty this function fills the buffer, else it
+			just changes an index. Also has the ability to do multi-threaded debuging
+Parameters:
+	OutStr - Varible were output is put
+	ClientSocket - The socket to get data from
+	IOBuffer - A pointer to a chunk of memory to put data in
+	IOBufferSize - Size of the buffer
+	BufferIndex - A zero based index of what charactor in the buffer we're at
+	DataInBuffer - Amount of data in the buffer
+	ThreadNum - Number of the thread that called this functions used for debugging
+
+Returns: -1 on disconnect or error (abort connection), 0 on success
+*/
+int GetLine(text_t &OutStr, SOCKET ClientSocket, BYTE *IOBuffer, int IOBufferSize, 
+	    int &BufferIndex, int &DataInBuffer, int ThreadNum);
+
+/*
+Function Name: Send Data
+Purpose: Sends data to a socket with muli-thread debugging
+Parameters:
+	ClientSocket - The socket to get data from
+	SendBuffer - A pointer to a chunk of memory to put data in
+	NumToSend - Number of bytes to send from buffer
+	ThreadNum - Number of the thread that called this functions used for debugging
+
+Returns: -1 on error, 0 on success
+
+Notes:
+Removed socket error checking because I was unable to isolate what
+errors I was getting when getting a "rude" disconnect
+*/
+int SendData(SOCKET ClientSocket, BYTE *SendBuffer, 
+	     int NumToSend, int ThreadNum);
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/parse.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/parse.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/parse.cpp	(revision 10506)
@@ -0,0 +1,205 @@
+/**********************************************************************
+ *
+ * parse.cpp
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <memory.h>
+#pragma hdrstop
+
+#include "parse.h"
+
+//Public Functions
+/******************************************************************************/
+void Left(char *DestStr, const char *SourceStr, const int Len) {
+  memcpy(DestStr, SourceStr, Len);
+  DestStr[Len] = 0;
+}
+/******************************************************************************/
+void Right(char *DestStr, const char *SourceStr, const int Len) {
+  int SourceLen, Offset;
+  
+  SourceLen = strlen(SourceStr);
+  Offset = SourceLen - Len;
+  
+  memcpy(DestStr, SourceStr + Offset, Len + 1);
+  //The null is already copied
+}
+/******************************************************************************/
+void TrimLeft(char *TargetStr) {
+  int i, NewStrSize;
+  
+  i = 0;
+  //Find the first non-space charactor
+  while ( (TargetStr[i] == ' ') || (TargetStr[i] == '\t') ) {
+    ++i;
+  }
+  //If we have space to get rid of, move the string
+  if (i > 0) {
+    NewStrSize = strlen(TargetStr) - i + 1; //Include the NULL in the size
+    memmove(TargetStr, TargetStr + i, NewStrSize);
+  }
+}
+/******************************************************************************/
+void TrimRight(char *TargetStr) {
+  int i;
+  
+  //Find the last non-space charactor (index i)
+  i = strlen(TargetStr) - 1;
+  while ((i >= 0) && ((TargetStr[i] == ' ') || (TargetStr[i] == '\t')) ) {
+    --i;
+  }
+  //Set the NULL 1 after the last non-space charactor
+  TargetStr[i+1] = 0;
+}
+/******************************************************************************/
+void Trim(char *TargetStr) {
+  TrimRight(TargetStr);
+  TrimLeft(TargetStr);
+}
+/******************************************************************************/
+void GetWord(text_t &DestStr, text_t::const_iterator first,
+	     text_t::const_iterator last, text_t::const_iterator &next) {
+
+  DestStr.clear();
+  next = last;
+
+  while (first != last) {
+    if (*first == ' ' || *first == '\t') {
+      ++first;
+      while ((first != last) && ((*first == ' ') || (*first == '\t'))) {
+	++first;
+      }
+      next = first;
+      break;
+    } else {
+      DestStr.push_back(*first);
+    }
+    ++first;
+  }
+}
+/******************************************************************************/
+
+void GetLastWord(text_t &DestStr, text_t::const_iterator first, text_t::const_iterator last, 
+		 text_t::const_iterator &Start) {
+
+  DestStr.clear();
+  Start = first;
+
+  while (first != last) {
+    if ((*first == ' ') || (*first == '\t')) {
+      DestStr.clear();
+      Start = first+1;
+    } else {
+      DestStr.push_back(*first);
+    }
+    ++first;
+  }
+}
+/******************************************************************************/
+void SplitPath(char *Path, char *Dir, char *FileName) {
+  int SplitPoint;
+  SplitPoint = strlen(Path) - 1;
+  while ((SplitPoint > 0) && (Path[SplitPoint] != '\\')) {
+    --SplitPoint;
+  }
+  if ((SplitPoint == 0) && (Path[SplitPoint] != '\\')) {
+    //No directory, just a file name
+    Dir[0] = 0;
+    strcpy(FileName, Path);
+  }
+  else {
+    //Move past the last slash
+    ++SplitPoint;
+    
+    //Directory
+    int i = 0;
+    while (i < SplitPoint) {
+      Dir[i] = Path[i];
+      ++i;
+    }
+    Dir[i] = 0;
+    
+    //File name
+    int j = 0;
+    while (Path[i] != 0) {
+      FileName[j] = Path[i];
+      ++j;
+      ++i;
+    }
+    FileName[j] = 0;
+  }
+}
+/******************************************************************************/
+void GetExtention(char *Path, char *Extention) {
+  int Dot;
+  int PathLen;
+  
+  PathLen = strlen(Path) - 1;
+  Dot = PathLen;
+  while ((Dot > 0) && (Path[Dot] != '.')) {
+    --Dot;
+  }
+  if (Dot > 0) {
+    strcpy(Extention, Path + Dot + 1);
+  }
+  else {
+    Extention[0] = 0;
+  }
+}
+/******************************************************************************/
+void TranslateEscapeString(char *TargetStr) {
+  int i = 0;
+  int j = 0;
+  
+  while (TargetStr[i] != 0) {
+    if ((TargetStr[i] == '%') && (TargetStr[i+1] != 0) && (TargetStr[i+2] != 0)) {
+      //Escaped value (did checking to make sure there are 2 more chars)
+      //         #pragma warn -sig //Suppress significant digit loss warning (BC++)
+      TargetStr[j] = 16 * HexVal(TargetStr[i+1]) + HexVal(TargetStr[i+2]);
+      //         #pragma warn +sig   //Restore significant digit loss warning (BC++)
+      i += 3;
+    }
+    else {
+      TargetStr[j] = TargetStr[i];
+      ++i;
+    }
+    ++j;
+  }
+  TargetStr[j] = 0;
+}
+/******************************************************************************/
+int HexVal(char c) {
+  //   #pragma warn -sig //Suppress significant digit loss warning (BC++)
+  if (c >= '0' && c <= '9') return c - '0';
+  else if (c >= 'a' && c <= 'f') return c - 'a' + 10;
+  else if (c >= 'A' && c <= 'F') return c - 'A' + 10;
+  else return 0;
+  //   #pragma warn +sig   //Restore significant digit loss warning (BC++)
+}
+/******************************************************************************/
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/parse.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/parse.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/parse.h	(revision 10506)
@@ -0,0 +1,162 @@
+/**********************************************************************
+ *
+ * parse.h
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+
+/*
+Module Name: Parse
+Purpose: General string parsing.  These are functions that are not in string.h,
+	but are found in many other libraries and high level languages.
+Public Functions:
+	Left
+	Right
+
+	Trim
+	TrimLeft
+	TrimRight
+
+	GetWord
+	GetLastWord
+
+   Split Path
+   GetExtention
+*/
+
+/*
+Function Name: Left
+Purpose: Copies the leftmost x number of charactors of a string to a buffer
+Parameters:
+	DestStr - Destination buffer for substring
+	SourceStr - Source string to make substing from
+	Len - Length of substring
+
+Notes: If Len is greater than strlen(SourceStr) a memory error may occur.
+*/
+void Left(char *DestStr, const char *SourceStr, const int Len);
+
+/*
+Function Name: Right
+Purpose: Copies the rightmost x number of charactors of a string to a buffer
+Parameters:
+	DestStr - Destination buffer for substring
+	SourceStr - Source string to make substing from
+	Len - Length of substring
+
+Notes: If Len is greater than strlen(SourceStr) then a memory error may
+		 occur.
+*/
+void Right(char *DestStr, const char *SourceStr, const int Len);
+
+/*
+Function Name: TrimLeft
+Purpose: Removes spaces and tabs from the left end of a string.
+Parameters:
+	TargetString - String to be trimmed
+*/
+void TrimLeft(char *TargetStr);
+
+/*
+Function Name: TrimRight
+Purpose: Removes spaces and tabs from the right end of a string.
+Parameters:
+	TargetString - String to be trimmed
+*/
+void TrimRight(char *TargetStr);
+
+/*
+Function Name: Trim
+Purpose: Removes spaces and tabs from both ends of a string.
+Parameters:
+	TargetString - String to be trimmed
+*/
+void Trim(char *TargetStr);
+
+/*
+Function Name: GetWord
+Purpose: Gets leftmost substring without a space in the string between the iterators
+         'here' and 'end'. Sets 'DestStr' to the substring. Sets the 'next' iterator 
+	 to the next non-space charactor in the string.  ' ' and '\t' and considered
+         spaces
+Parameters:
+	 DestString - Destination buffer for substring
+	 first - First character in source string
+	 last - end iterator (one past last character) of source string
+	 next - At end of function call is set to the location of next non-space
+               charactor in source string
+*/
+void GetWord(text_t &DestStr, text_t::const_iterator first,
+	     text_t::const_iterator last, text_t::const_iterator &next);
+
+/*
+Function Name: GetLastWord
+Purpose: Gets rightmost substring without a space sets Start to be the first
+         character of the substring in the original string.
+Parameters:
+	DestString - Destination buffer for substring
+	first and last - Source string to make substing from
+	Start - where the DestString starts at in the source string
+*/
+void GetLastWord(text_t &DestStr, text_t::const_iterator first, text_t::const_iterator last, 
+		 text_t::const_iterator &Start);
+
+
+/*
+Function Name: Split Path
+Purpose: Splits a path string into directory and file name
+Parameters:
+	Path - Path string (example "c:\Fnord\SomeFile.Ext")
+	Dir - Directory part of the Path (example "c:\Fnord\")
+	FileName - File name part of the path (example "SomeFile.Ext")
+*/
+void SplitPath(char *Path, char *Dir, char *FileName);
+
+/*
+Function Name: Get Extention
+Purpose: Splits a path string into directory and file name
+Parameters:
+	Path - Path string or file name (example "c:\Fnord\SomeFile.Ext")
+	Extention - Extention part of the path (example "Ext")
+*/
+void GetExtention(char *Path, char *Extention);
+
+/*
+Function Name: Translate Escape String
+Purpose: Translates all URL escape sequences, such as "%20" where "20" is
+	the resulting charactor in hexidecimal
+Parameters:
+	TargetStr - String that may contain URL escape sequences.  All sequences
+   	are decoded on return.
+*/
+void TranslateEscapeString(char *TargetStr);
+
+/*
+Function Name: Hex Value
+Purpose: Returns the value of a hexidecimal digit character as an integer
+Parameters:
+	c - Charactor to translate
+*/
+int HexVal(char c);
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/resource.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/resource.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/resource.h	(revision 10506)
@@ -0,0 +1,51 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by server.rc
+//
+#define TRAY_ICON                       101
+#define COMMS_DIALOG                    102
+#define COMMS_DIALOG_DEBUG              102
+#define Main_Menu                       103
+#define COMMS_DIALOG2                   103
+#define GSDL_LOGO                       108
+#define GSDL_COL_TITLE                  109
+#define IDD_DIALOG1                     118
+#define GSDL_ICBMP                      126
+#define APPLY_BUTTON                    1000
+#define REMOTE_CHECK                    1001
+#define PROXY_CHECK                     1002
+#define CONSOLE_CHECK                   1003
+#define PROXY_EDIT_BOX                  1004
+#define PROXY_PORT_EDIT_BOX             1005
+#define TrayID                          1006
+#define LOG_DEBUG_CHECK                 1007
+#define SERVER_PORT_EDIT_BOX            1008
+#define LOG_LOCAL_CHECK                 1009
+#define LOG_REMOTE_CHECK                1010
+#define LOG_NAME_BOX                    1011
+#define LOG_CHECK                       1012
+#define SAVE_NAME_BOX                   1013
+#define SAVE_CHECK                      1014
+#define ID_AUTO_ENTER_LIBRARY           1015
+#define ID_RADIO_NETSCAPE               1016
+#define ID_RADIO_IE                     1017
+#define ID_RADIO_OTHER                  1018
+#define ID_OTHER_NAME                   1019
+#define ID_BROWSE_BUTTON                1020
+#define ID_OK_BUTTON                    1021
+#define ID_CANCEL_BUTTON                1022
+#define ID_RADIO_DEFAULT                1023
+#define ID_PROJECT_SETTINGS             40001
+#define ID_PROJECT_EXIT                 40002
+#define ID_INSTALL_NETSCAPE             40007
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        127
+#define _APS_NEXT_COMMAND_VALUE         40011
+#define _APS_NEXT_CONTROL_VALUE         1026
+#define _APS_NEXT_SYMED_VALUE           102
+#endif
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/settings.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/settings.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/settings.cpp	(revision 10506)
@@ -0,0 +1,862 @@
+/**********************************************************************
+ *
+ * settings.cpp
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+#include "fileutil.h"
+
+#if defined(GSDL_USE_OBJECTSPACE)
+#  include <ospace\std\fstream>
+#elif defined(GSDL_USE_IOS_H)
+#  include <fstream.h>
+#else
+#  include <fstream>
+#endif
+
+#include <windows.h>
+#include "httpsrv.h"
+#include "settings.h"
+#include "locate.h"
+#include "resource.h"
+#include "cgiwrapper.h"
+
+// library settings
+text_t gsdl_enterlib;
+text_t gsdl_gsdlhome;
+text_t gsdl_gdbmhome;
+text_t gsdl_collections;
+colinfo_tmap gsdl_collectinfo;
+
+char gsdl_staticpages[MAX_FILENAME_SIZE];
+
+// debug settings
+char gsdl_log_name[MAX_FILENAME_SIZE] = "c:\\gsdl.log";
+int gsdl_keep_log = 0;
+int gsdl_show_console = 0;
+
+// general settings
+int gsdl_port_num = 80;
+int gsdl_auto_enter = 0;
+int gsdl_browser = GS_DEFAULT;
+char gsdl_browser_exe[MAX_FILENAME_SIZE] = "";
+text_t gsdl_url;
+text_t gsdl_conffile;
+int gsdl_start_browser = 1;
+int gsdl_address_resolution_method = 2;  // Use 127.0.0.1 by default
+
+// private data
+
+// pathnames of the latest installed versions of netscape and
+// internet explorer
+static char netscape_exe[MAX_FILENAME_SIZE]="";
+static char iexplore_exe[MAX_FILENAME_SIZE]="";
+
+// pathname of the default browser
+static char default_browser_exe[MAX_FILENAME_SIZE]="";
+
+// whether netscape is needed (used in the settings dialog box)
+static int gsdl_netscapeneeded = 0;
+
+static void remove_end_slashes(char *str) {
+  int len = strlen (str);
+  while ((len > 0) && ((str[len-1] == '\\') || (str[len-1] == '/'))) {
+    --len;
+  }
+  str[len] = '\0';
+}
+
+static void remove_end_slashes (text_t &str) {
+  char *cstr = str.getcstr();
+  remove_end_slashes (cstr);
+  str = cstr;
+  delete []cstr;
+}
+
+// returns 1 if successful, 0 otherwise
+// checks for a file's existence
+static int check_program_exe (char *path) {
+  UINT curerrormode;
+  OFSTRUCT reOpenBuff;
+  int retvalue = 0;
+  
+  reOpenBuff.cBytes = sizeof (OFSTRUCT);
+  
+  curerrormode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+  if (OpenFile(path, &reOpenBuff, OF_EXIST) != HFILE_ERROR) retvalue = 1;
+  SetErrorMode(curerrormode);
+  
+  return retvalue;
+}
+
+
+// returns 1 if successful, 0 otherwise
+static int get_default_browser_path (char *providedhtmltype, char *path, int maxsize) {
+  HKEY hk1, hk2;
+  char htmltype[256];
+  long size;
+  int retval = 0;
+  
+  htmltype[0] = '\0';
+  path[0] = '\0';
+  
+  // try and get information about the default browser from the 
+  // registry
+  
+  if (providedhtmltype != NULL) strcpy (htmltype, providedhtmltype);
+  
+  else if (RegOpenKey(HKEY_CLASSES_ROOT, ".htm", &hk1) == ERROR_SUCCESS) {
+    size = 256;
+    RegQueryValue(hk1, NULL, htmltype, &size);
+    RegCloseKey(hk1);
+  }
+  
+  if (RegOpenKey(HKEY_CLASSES_ROOT, htmltype, &hk1) == ERROR_SUCCESS) {
+    if (RegOpenKey(hk1, "shell\\open", &hk2) == ERROR_SUCCESS) {
+      // look for the command to start the browser
+      size = maxsize;
+      if (RegQueryValue(hk2,"command",path,&size) == ERROR_SUCCESS) {
+				// strip all excess stuff off the command
+	char endchar = ' ';
+	int i = 0, len = 0;
+	int state = 0; // 0=strip initial white-space and quotes, 1=grab path
+	while (path[i] != '\0') {
+	  if (state == 0) {
+	    if (path[i] == ' ') {
+	      // do nothing
+	    } else if (path[i] == '"') {
+	      endchar = '"';
+	      state = 1;
+	    } else {
+	      state = 1;
+	      path[len] = path[i];
+	      ++len;
+	    }
+	  } else {
+	    if (path[i] == endchar) break;
+	    path[len] = path[i];
+	    ++len;
+	  }
+	  ++i;
+	}
+	path[len] = '\0';
+	
+	// check the resulting pathname
+	if (check_program_exe (path)) {
+	  retval = 1; // succeeded
+	} else {
+	  path[0] = '\0'; // failed (must have been deleted or something...)
+	}
+      }
+      RegCloseKey(hk2);
+    }
+    RegCloseKey(hk1);
+  }
+  
+  return retval;
+}
+
+
+// returns 1 if successful, 0 otherwise
+// note that appname should include .exe (e.g. netscape.exe)
+static int registry_get_app_paths (char *appname, char *path, int maxsize) {
+  HKEY hk1;
+  long size;
+  int retval = 0;
+  
+  path[0] = '\0';
+  
+  if (RegOpenKey(HKEY_LOCAL_MACHINE, 
+		 "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths", 
+		 &hk1) == ERROR_SUCCESS) {
+    size = maxsize;
+    if (RegQueryValue (hk1, appname, path, &size) == ERROR_SUCCESS &&
+	check_program_exe (path));
+    retval = 1;
+    
+    RegCloseKey(hk1);
+  }
+  
+  return retval;
+}
+
+static void check_installed_browsers (int netscapeneeded) {
+  netscape_exe[0] = '\0';
+  iexplore_exe[0] = '\0';
+  default_browser_exe[0] = '\0';
+  
+  // update the default browser information (if netscape isn't needed)
+  if (!netscapeneeded) {
+    get_default_browser_path (NULL, default_browser_exe, MAX_FILENAME_SIZE);
+    _strlwr (default_browser_exe);
+  }
+  
+  // look for netscape
+  
+  // first look for netscape in the registry
+  if (!registry_get_app_paths("netscape.exe", netscape_exe, MAX_FILENAME_SIZE)) {
+    // next look for "NetscapeMarkup"
+    if (get_default_browser_path ("NetscapeMarkup", netscape_exe, MAX_FILENAME_SIZE)) {
+      _strlwr (netscape_exe);
+      if (!strstr (netscape_exe, "netscape.exe")) {
+	netscape_exe[0] = '\0';
+	
+	// next look for \netscape\netscape.exe
+	
+	// get drive letter of the windows directory
+	GetWindowsDirectory(netscape_exe, MAX_FILENAME_SIZE);
+	netscape_exe[1] = '\0';
+	strcat (netscape_exe, ":\\netscape\\netscape.exe");
+	
+	if (!check_program_exe (netscape_exe)) {
+	  // lastly look for \netscape\program\netscape.exe
+	  netscape_exe[1] = '\0';
+	  strcat (netscape_exe, ":\\netscape\\program\\netscape.exe");
+	  
+	}
+      }
+    }
+  }
+  _strlwr (netscape_exe);
+  if ((strlen (netscape_exe) > 0) && !check_program_exe (netscape_exe)) {
+    netscape_exe[0] = '\0';  // couldn't find netscape
+  }
+  
+  // look for internet explorer (if netscape isn't needed)
+  
+  // first look for iexplore in the registry
+  if (!netscapeneeded && !registry_get_app_paths("iexplore.exe", 
+						 iexplore_exe, MAX_FILENAME_SIZE)) {
+    // next look for "htmlfile"
+    if (get_default_browser_path ("htmlfile", iexplore_exe, MAX_FILENAME_SIZE)) {
+      _strlwr (iexplore_exe);
+      if (!strstr (iexplore_exe, "iexplore.exe")) {
+	iexplore_exe[0] = '\0';
+	
+	// next look for \iexplore\iexplore.exe
+	
+	// get drive letter of the windows directory
+	GetWindowsDirectory(iexplore_exe, MAX_FILENAME_SIZE);
+	iexplore_exe[1] = '\0';
+	strcat (iexplore_exe, ":\\iexplore\\iexplore.exe");
+      }
+    }
+  }
+  _strlwr (iexplore_exe);
+  if ((strlen (iexplore_exe) > 0) && !check_program_exe (iexplore_exe)) {
+    iexplore_exe[0] = '\0';  // couldn't find internet explorer
+  }
+}
+
+void write_settings (const text_t url) {
+  
+  if (gsdl_conffile.empty()) {
+    find_location();
+    gsdl_conffile = filename_cat(data_location, "gsdlsite.cfg");
+  }
+
+  char *conffile_c = gsdl_conffile.getcstr();
+  ofstream fout (conffile_c);
+  delete []conffile_c;
+  if (fout) {
+    
+    outconvertclass text_t2ascii;
+
+    // top (gsdl) level stuff
+    fout << "[gsdl]\n";
+    
+    if (!url.empty()) {
+      // url entry should only be written to gsdlsite.cfg when the
+      // server is actually running, not when it's stopped (since we
+      // can't be sure what the url is at that stage). That is,
+      // write_settings() is called with the url argument set when the
+      // server first starts up, it's then called without url set as
+      // the server shuts down.
+      write_ini_line(fout, "url", url);      
+    }
+
+    write_ini_line(fout, "enterlib", gsdl_enterlib);
+    write_ini_line(fout, "gsdlhome", gsdl_gsdlhome);
+    write_ini_line(fout, "gdbmhome", gsdl_gdbmhome);
+    
+    write_ini_line(fout, "logfilename", gsdl_log_name);
+    write_ini_line(fout, "keeplog", text_t(gsdl_keep_log));
+    write_ini_line(fout, "consolelog", text_t(gsdl_show_console));
+    
+    write_ini_line(fout, "portnumber", text_t(gsdl_port_num));
+    write_ini_line(fout, "autoenter", text_t(gsdl_auto_enter));
+    write_ini_line(fout, "browser", text_t(gsdl_browser));
+    write_ini_line(fout, "browserexe", gsdl_browser_exe);
+    write_ini_line(fout, "collections", gsdl_collections);
+    write_ini_line(fout, "start_browser", text_t(gsdl_start_browser));
+    write_ini_line(fout, "address_resolution_method", text_t(gsdl_address_resolution_method));
+
+    // collection levels
+    colinfo_tmap::iterator here = gsdl_collectinfo.begin();
+    colinfo_tmap::iterator end = gsdl_collectinfo.end();
+    while (here != end) {
+      fout << text_t2ascii << "[" << (*here).first << "]\n";
+      if (!(*here).second.gsdl_gsdlhome.empty()) 
+	write_ini_line(fout, "gsdlhome", (*here).second.gsdl_gsdlhome);
+      if (!(*here).second.gsdl_gdbmhome.empty()) 
+	write_ini_line(fout, "gdbmhome", (*here).second.gsdl_gdbmhome);
+      
+      ++here;
+    }
+    fout.close();
+  }
+}
+
+
+// browser_compare assumes that check_exe is in lowercase
+static int browser_compare (char *browser_exe_path, char *check_exe) {
+  char tmp_exe[MAX_FILENAME_SIZE];
+  strcpy (tmp_exe, browser_exe_path);
+  _strlwr (tmp_exe);
+  return (strstr (tmp_exe, check_exe) != NULL);
+}
+
+// This function assumes that check_installed_browsers
+// has been recently called
+// It also assumes that browser_exe is large
+// enough to receive any path names to any browser
+static void check_browser_settings (int &browser, char *browser_exe, 
+				    int netscapeneeded) {
+  // sort out which browser to use
+  if ((browser == GS_NETSCAPE) && (netscape_exe[0] == '\0'))
+    browser = GS_IEXPLORE;
+  if ((browser == GS_IEXPLORE) && (netscapeneeded || (iexplore_exe[0] == '\0'))) {
+    if (netscape_exe[0] != '\0') browser = GS_NETSCAPE;
+    else browser = GS_OTHER;
+  }
+  if ((browser == GS_OTHER) && netscapeneeded && 
+      !browser_compare (browser_exe, "netscape.exe") && (netscape_exe[0] != '\0')) {
+    // this other browser isn't netscape and netscape is available
+    browser = GS_NETSCAPE;
+  }
+  
+  
+  // get the browser's executable
+  if (browser == GS_DEFAULT) {
+    strcpy (browser_exe, default_browser_exe);
+  } else if (browser == GS_NETSCAPE) {
+    strcpy (browser_exe, netscape_exe);
+  } else if (browser == GS_IEXPLORE) {
+    strcpy (browser_exe, iexplore_exe);
+  } else {
+    browser = GS_OTHER;
+    
+    // if the browser should be netscape then check to
+    // make sure it is
+    if (netscapeneeded && !browser_compare (browser_exe, "netscape.exe")) {
+      // not netscape, set to no browser
+      browser_exe[0] = '\0';
+    }
+  }
+}
+
+
+static void revert_defaults (int netscapeneeded) {
+  find_location();
+  
+  // library settings
+  gsdl_enterlib = "/gsdl";
+  gsdl_gsdlhome = data_location;
+  gsdl_gdbmhome = data_location;
+  
+  // debug settings
+  gsdl_keep_log = 0;
+  strcpy (gsdl_log_name, "c:\\gsdl.log");
+  gsdl_show_console = 0;
+  
+  // general settings
+  gsdl_port_num = 80;
+  gsdl_auto_enter = 0;
+  gsdl_start_browser = 1;
+
+  check_installed_browsers (netscapeneeded);
+  gsdl_browser = GS_DEFAULT;
+  strcpy (gsdl_browser_exe, default_browser_exe);
+  check_browser_settings (gsdl_browser, gsdl_browser_exe, netscapeneeded);
+}
+
+void read_settings (int netscapeneeded) {
+  
+  if (gsdl_conffile.empty()) {
+    find_location();
+    gsdl_conffile = filename_cat(data_location, "gsdlsite.cfg");
+  }
+  
+  // set up defaults
+  revert_defaults (netscapeneeded);
+  
+  text_t key, value, section;
+  char *cstr_value;
+  char *conffile_c = gsdl_conffile.getcstr();
+#if defined (GSDL_USE_IOS_H)
+  ifstream conf (conffile_c, ios::nocreate);
+#else
+  ifstream conf (conffile_c);
+#endif
+  delete []conffile_c;
+  if (conf) {
+    while (read_ini_line(conf, key, value) >= 0) {
+      if (key.empty()) continue;
+      if (value.empty()) {
+	// should be a section title
+	section = key;
+	// remove square brackets
+	section.erase (section.begin());
+	section.erase (section.end()-1);
+
+      } else {
+
+	cstr_value = value.getcstr ();
+      
+	if (section == "gsdl") {
+
+	  if (key == "enterlib") {
+	    gsdl_enterlib = value;
+	  
+	    // 'logfilename' should occur in the configuration file
+	    // before 'keeplog'
+	  } else if (key == "logfilename") {
+	    strcpy (gsdl_log_name, cstr_value);
+	  
+	  } else if (key == "keeplog") {
+	    gsdl_keep_log = value.getint();
+	    if (gsdl_keep_log) open_log_file();
+	
+	  } else if (key == "consolelog") {
+	    if (value.getint()) activate_console();
+	    else deactivate_console();
+	
+	  } else if (key == "portnumber") {
+	    gsdl_port_num = value.getint();
+	    
+	  } else if (key == "autoenter") {
+	    gsdl_auto_enter = value.getint();
+	    
+	  } else if (key == "start_browser") {
+	    gsdl_start_browser = value.getint();
+	
+	  } else if (key == "browser") {
+	    gsdl_browser = value.getint();
+	
+	  } else if (key == "browserexe") {
+	    strcpy (gsdl_browser_exe, cstr_value);
+
+	  } else if (key == "address_resolution_method") {
+	    gsdl_address_resolution_method = value.getint();
+
+	  } else if (key == "collections") {
+	    gsdl_collections = value;
+
+	  // gsdlhome must occur in file before gdbmhome	    
+	  } else if (key == "gsdlhome") {
+	    gsdl_gsdlhome = value;
+	    gsdl_gdbmhome = value;
+	  
+	  } else if (key == "gdbmhome") {
+	    gsdl_gdbmhome = value;
+	  }
+	} else {
+	  
+	  // gsdlhome must occur in file before gdbmhome
+	  if (key == "gsdlhome") {
+	    gsdl_collectinfo[section].gsdl_gsdlhome = value;
+	    gsdl_collectinfo[section].gsdl_gdbmhome = value;
+	  } else if (key == "gdbmhome") {
+	    gsdl_collectinfo[section].gsdl_gdbmhome = value;
+	  }
+	}
+	delete []cstr_value;
+      }
+    }
+    conf.close();
+  }
+  
+  // check the homes to make sure they don't contain
+  // extra slashes at the end
+  remove_end_slashes (gsdl_gsdlhome);
+  remove_end_slashes (gsdl_gdbmhome);
+  colinfo_tmap::iterator here = gsdl_collectinfo.begin();
+  colinfo_tmap::iterator end = gsdl_collectinfo.end();
+  while (here != end) {
+    remove_end_slashes ((*here).second.gsdl_gsdlhome);
+    remove_end_slashes ((*here).second.gsdl_gdbmhome);
+    ++here;
+  }
+
+  // check the browser settings
+  check_browser_settings (gsdl_browser, gsdl_browser_exe, netscapeneeded);
+}
+
+void gsdl_check_browser_settings (int netscapeneeded) {
+  check_installed_browsers (netscapeneeded);
+  check_browser_settings (gsdl_browser, gsdl_browser_exe, netscapeneeded);
+}
+
+
+static void dialog_update_enables (HWND hwndDlg) {
+  int res;
+  
+  // if they want to use another browser, they should be able
+  // edit its filename
+  res = SendDlgItemMessage(hwndDlg, ID_RADIO_OTHER, BM_GETCHECK,0,0);
+  SendDlgItemMessage(hwndDlg, ID_OTHER_NAME, WM_ENABLE, (res == 1), 0);
+}
+
+
+static int read_dialog_browser_field (HWND hwndDlg) {
+  if (SendDlgItemMessage(hwndDlg, ID_RADIO_DEFAULT,
+			 BM_GETCHECK, 0, 0) == 1) return GS_DEFAULT;
+  if (SendDlgItemMessage(hwndDlg, ID_RADIO_NETSCAPE,
+			 BM_GETCHECK, 0, 0) == 1) return GS_NETSCAPE;
+  if (SendDlgItemMessage(hwndDlg, ID_RADIO_IE,
+			 BM_GETCHECK, 0, 0) == 1) return GS_IEXPLORE;
+  if (SendDlgItemMessage(hwndDlg, ID_RADIO_OTHER,
+			 BM_GETCHECK, 0, 0) == 1) return GS_OTHER;
+  return GS_NETSCAPE;
+}
+
+
+
+static void set_dialog_browser_field (HWND hwndDlg, int browser, char *othername) {
+  // if we are trying to set the browser to default, netscape or
+  // internet explorer and we can't find them, set the browser
+  // to 'other'
+  if ((browser == GS_DEFAULT) && (default_browser_exe[0] == '\0'))
+    browser = GS_NETSCAPE;
+  if ((browser == GS_NETSCAPE) && (netscape_exe[0] == '\0'))
+    browser = GS_IEXPLORE;
+  if ((browser == GS_IEXPLORE) && (iexplore_exe[0] == '\0')) {
+    if (netscape_exe[0] != '\0') browser = GS_NETSCAPE;
+    else browser = GS_OTHER;
+  }
+  
+  // update the radio buttons
+  SendDlgItemMessage(hwndDlg, ID_RADIO_DEFAULT, BM_SETCHECK,
+		     (browser == GS_DEFAULT) ? BST_CHECKED : BST_UNCHECKED, 0);
+  SendDlgItemMessage(hwndDlg, ID_RADIO_NETSCAPE, BM_SETCHECK,
+		     (browser == GS_NETSCAPE) ? BST_CHECKED : BST_UNCHECKED, 0);
+  SendDlgItemMessage(hwndDlg, ID_RADIO_IE, BM_SETCHECK,
+		     (browser == GS_IEXPLORE) ? BST_CHECKED : BST_UNCHECKED, 0);
+  SendDlgItemMessage(hwndDlg, ID_RADIO_OTHER, BM_SETCHECK,
+		     (browser == GS_OTHER) ? BST_CHECKED : BST_UNCHECKED, 0);
+  
+  // update the other name field
+  if (browser == GS_DEFAULT) {
+    SetDlgItemText(hwndDlg, ID_OTHER_NAME, default_browser_exe);
+  } else if (browser == GS_NETSCAPE) {
+    SetDlgItemText(hwndDlg, ID_OTHER_NAME, netscape_exe);
+  } else if (browser == GS_IEXPLORE) {
+    SetDlgItemText(hwndDlg, ID_OTHER_NAME, iexplore_exe);
+  } else if (othername != NULL) {
+    SetDlgItemText(hwndDlg, ID_OTHER_NAME, othername);
+  }
+}
+
+
+static void read_browser_exe_field (HWND hwndDlg, char *filename, int maxsize) {
+  filename[0] = '\0';
+  GetDlgItemText(hwndDlg, ID_OTHER_NAME, filename, maxsize);
+}
+
+
+static void read_dialog_fields (HWND hwndDlg) {
+  int res;  BOOL bres;
+  
+  // port number
+  gsdl_port_num = GetDlgItemInt(hwndDlg, SERVER_PORT_EDIT_BOX, &bres, 0);
+  if (!bres) gsdl_port_num = 80;
+  
+  // whether to enter the library automatically on startup
+  res = SendDlgItemMessage(hwndDlg, ID_AUTO_ENTER_LIBRARY, BM_GETCHECK, 0, 0);
+  gsdl_auto_enter = (res == 1);
+  
+  // which browser to use
+  gsdl_browser = read_dialog_browser_field (hwndDlg);
+  
+  // find out where the browser exe lives
+  read_browser_exe_field (hwndDlg, gsdl_browser_exe, MAX_FILENAME_SIZE);
+}
+
+
+
+
+static BOOL CALLBACK dialog_proc(HWND hwndDlg, UINT uMsg, 
+				 WPARAM wParam,LPARAM  lParam) {
+  int wNotifyCode = HIWORD(wParam);
+  int wID = LOWORD(wParam);
+  char *filefilter = "Program Files (*.exe)\0*.exe\0All Files (*.*)\0*.*\0\0";
+  OPENFILENAME fname;
+  char filename[MAX_FILENAME_SIZE];
+  
+  switch (uMsg) {
+  case WM_INITDIALOG:
+    // set current values
+    SetDlgItemInt(hwndDlg, SERVER_PORT_EDIT_BOX, gsdl_port_num, FALSE);
+    SendDlgItemMessage(hwndDlg, ID_AUTO_ENTER_LIBRARY, BM_SETCHECK,
+		       gsdl_auto_enter ? 1 : 0, 0);
+    set_dialog_browser_field (hwndDlg, gsdl_browser, gsdl_browser_exe);
+    dialog_update_enables(hwndDlg);
+    
+    // make sure that the default browser, netscape and internet explorer
+    // radio buttons are only enabled if they could be found
+    if (default_browser_exe[0] == '\0')
+      EnableWindow (GetDlgItem (hwndDlg, ID_RADIO_DEFAULT), FALSE);
+    if (netscape_exe[0] == '\0')
+      EnableWindow (GetDlgItem (hwndDlg, ID_RADIO_NETSCAPE), FALSE);
+    if (iexplore_exe[0] == '\0')
+      EnableWindow (GetDlgItem (hwndDlg, ID_RADIO_IE), FALSE);
+    
+    return 1;
+    
+  case WM_COMMAND:
+    if (wNotifyCode == BN_CLICKED) {
+      switch (wID) {
+      case ID_CANCEL_BUTTON:
+	EndDialog(hwndDlg, 0);
+	return 1;
+	
+      case ID_OK_BUTTON:
+	// check to make sure we can find the browser
+	filename[0] = '\0';
+	read_browser_exe_field (hwndDlg, filename, MAX_FILENAME_SIZE);
+	if (check_program_exe (filename)) { 
+	  // the file exists
+	  // if netscape is needed, make sure the browser is netscape
+	  _strlwr(filename);
+	  if (!gsdl_netscapeneeded || strstr (filename, "netscape.exe") != NULL) {
+	    // everything is ok
+	    read_dialog_fields(hwndDlg);
+	    EndDialog(hwndDlg, 1);
+	    
+	  } else {
+	    // message: must use netscape with this version
+	    MessageBox(hwndDlg,
+		       "You are using this software on a machine which\n"
+		       "currently does not have a working TCP/IP network layer.\n"
+		       "To allow the Greenstone Digital Library software to use\n"
+		       "its own TCP/IP network layer you must use a Netscape\n"
+		       "web browser.",
+		       "Greenstone Digital Library Software",
+		       MB_OK|MB_APPLMODAL);
+	  }
+	} else {
+	  // message: the file did not exist
+	  MessageBox(hwndDlg,
+		     "Could not find the selected browser. You must have a\n"
+		     "web browser installed to use the Greenstone Digital\n"
+		     "Library software.",
+		     "Greenstone Digital Library Software",
+		     MB_OK|MB_APPLMODAL);
+	}
+	return 1;
+
+      case ID_RADIO_DEFAULT:
+	set_dialog_browser_field (hwndDlg, GS_DEFAULT, NULL);
+	dialog_update_enables(hwndDlg);
+	return 1;
+	
+      case ID_RADIO_NETSCAPE:
+	set_dialog_browser_field (hwndDlg, GS_NETSCAPE, NULL);
+	dialog_update_enables(hwndDlg);
+	return 1;
+	
+      case ID_RADIO_IE:
+	set_dialog_browser_field (hwndDlg, GS_IEXPLORE, NULL);
+	dialog_update_enables(hwndDlg);
+	return 1;
+	
+      case ID_RADIO_OTHER:
+	set_dialog_browser_field (hwndDlg, GS_OTHER, NULL);
+	dialog_update_enables(hwndDlg);
+	return 1;
+	
+      case ID_BROWSE_BUTTON:
+	filename[0] = '\0';
+	memset(&fname, 0, sizeof(OPENFILENAME));
+	fname.lStructSize = sizeof(OPENFILENAME);
+	fname.hwndOwner = hwndDlg;
+	fname.hInstance = NULL;
+	fname.lpstrFilter = filefilter;
+	fname.lpstrCustomFilter = NULL;
+	fname.nMaxCustFilter = 0;
+	fname.nFilterIndex = 1;
+	fname.lpstrFile = filename;
+	fname.nMaxFile = MAX_FILENAME_SIZE-1;
+	fname.lpstrFileTitle = NULL;
+	fname.nMaxFileTitle = 0;
+	fname.lpstrInitialDir = NULL;
+	fname.lpstrTitle = "Choose Web Browser";
+	fname.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+	
+	if(GetOpenFileName(&fname)) {
+	  set_dialog_browser_field (hwndDlg, GS_OTHER, filename);
+	  dialog_update_enables(hwndDlg);
+	}
+	return 1;
+      }
+    }
+    return 0;
+    
+  case WM_CLOSE:
+  case WM_DESTROY:
+    EndDialog(hwndDlg, 0);
+    return 1;
+  }
+  
+  return 0;
+}
+
+static void dialog_debug_update_enables (HWND hwndDlg) {
+  int res;
+  
+  // if they want a log of program use allow them to
+  // edit its filename
+  res = SendDlgItemMessage(hwndDlg, LOG_CHECK, BM_GETCHECK,0,0);
+  SendDlgItemMessage(hwndDlg, LOG_NAME_BOX, WM_ENABLE, (res == 1), 0);
+}
+
+
+static void read_dialog_debug_fields (HWND hwndDlg) {
+  int res;
+  
+  // whether to log program use
+  res = SendDlgItemMessage(hwndDlg, LOG_CHECK, BM_GETCHECK,0,0);
+  gsdl_keep_log = (res == 1);
+  
+  // log filename
+  res = SendDlgItemMessage(hwndDlg, LOG_NAME_BOX, EM_GETMODIFY,0,0);
+  if (res != 0) {
+    res = GetDlgItemText(hwndDlg, LOG_NAME_BOX, gsdl_log_name, MAX_FILENAME_SIZE);
+  }
+  
+  // whether to display log information on console
+  res = SendDlgItemMessage(hwndDlg, CONSOLE_CHECK, BM_GETCHECK,0,0);
+  gsdl_show_console = (res == 1);
+}
+
+
+static BOOL CALLBACK dialog_debug_proc(HWND hwndDlg, UINT uMsg, 
+				       WPARAM wParam,LPARAM  lParam) {
+  int wNotifyCode = HIWORD(wParam);
+  int wID = LOWORD(wParam);
+  
+  switch (uMsg) {
+  case WM_INITDIALOG:
+    // set current values
+    SendDlgItemMessage(hwndDlg, LOG_CHECK, BM_SETCHECK,
+		       gsdl_keep_log ? 1 : 0, 0);
+    SetDlgItemText(hwndDlg, LOG_NAME_BOX, gsdl_log_name);
+    SendDlgItemMessage(hwndDlg, CONSOLE_CHECK, BM_SETCHECK,
+		       gsdl_show_console ? 1 : 0, 0);
+    dialog_debug_update_enables(hwndDlg);
+    return 1;
+    
+  case WM_COMMAND:
+    if (wNotifyCode == BN_CLICKED) {
+      switch (wID) {
+      case ID_CANCEL_BUTTON:
+	EndDialog(hwndDlg, 0);
+	return 1;
+	
+      case ID_OK_BUTTON:
+	read_dialog_debug_fields(hwndDlg);
+	EndDialog(hwndDlg, 1);
+	return 1;
+	
+      case LOG_CHECK:
+	dialog_debug_update_enables(hwndDlg);
+	return 1;
+      }
+    }
+    return 0;
+    
+  case WM_CLOSE:
+  case WM_DESTROY:
+    EndDialog(hwndDlg, 0);
+    return 1;
+  }
+  
+  return 0;
+}
+
+
+void Settings_Dialog(HWND window, int netscapeneeded)
+{
+  int old_gsdl_show_console = gsdl_show_console;
+  int old_gsdl_port_num = gsdl_port_num;
+  
+  int res = 0;
+  
+  gsdl_netscapeneeded = netscapeneeded;
+  
+  if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) && 
+      (GetAsyncKeyState(VkKeyScan('d')) & 0x8000)) {
+    // control-D was pressed, display debug settings
+    // dialog box
+    res = DialogBox (NULL, MAKEINTRESOURCE(COMMS_DIALOG_DEBUG),
+		     window, (DLGPROC)dialog_debug_proc);
+    
+    if (res == 1) {
+      // only update if exited via the OK button
+      if (gsdl_keep_log) open_log_file(); 
+      else close_log_file();
+      
+      // turn the console on/off if we need to
+      if (gsdl_show_console != old_gsdl_show_console) {
+	if (gsdl_show_console) activate_console ();
+	else deactivate_console ();
+      }
+    }
+    
+  } else {
+    // display normal settings dialog box
+    
+    // make sure everything is up-to-date
+    gsdl_check_browser_settings (netscapeneeded);
+    
+    res = DialogBox (NULL, MAKEINTRESOURCE(COMMS_DIALOG2),
+		     window, (DLGPROC)dialog_proc);
+
+    if (res == 1) {
+      // only update if exited via the OK button
+      if (gsdl_port_num != old_gsdl_port_num) {
+	EndHTTPServer();
+	StartHTTPServer(window);
+      }
+    }
+  }
+  
+  // save the settings if we exited via the ok button
+  if (res == 1) {
+    write_settings(gsdl_url);
+    // reset httpprefix in case port number was changed
+    //    configure_httpprefix ();
+  }
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/settings.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/settings.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/settings.h	(revision 10506)
@@ -0,0 +1,72 @@
+/**********************************************************************
+ *
+ * settings.h
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#ifndef SETTINGS_H
+#define SETTINGS_H
+
+#define GS_NETSCAPE 0
+#define GS_IEXPLORE 1
+#define GS_OTHER    2
+#define GS_DEFAULT  3
+
+#include "text_t.h"
+#include "cfgread.h"
+#include "receptionist.h"
+#include "locate.h"
+
+// library settings
+extern text_t gsdl_enterlib;
+extern text_t gsdl_gsdlhome;
+extern text_t gsdl_gdbmhome;
+extern text_t gsdl_collections;
+extern colinfo_tmap gsdl_collectinfo;
+
+extern char gsdl_staticpages[MAX_FILENAME_SIZE];
+
+// debug settings
+extern char gsdl_log_name[MAX_FILENAME_SIZE];
+extern int gsdl_keep_log;
+extern int gsdl_show_console;
+
+// general settings
+extern int gsdl_port_num;
+extern int gsdl_auto_enter;
+extern int gsdl_browser;
+extern char gsdl_browser_exe[MAX_FILENAME_SIZE];
+extern text_t gsdl_url;
+extern text_t gsdl_conffile;
+extern int gsdl_start_browser;
+extern int gsdl_address_resolution_method;
+
+void Settings_Dialog(HWND window, int netscapeneeded);
+
+void read_settings (int netscapeneeded);
+void write_settings (const text_t url);
+
+void gsdl_check_browser_settings (int netscapeneeded);
+
+#endif
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/startbrowser.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/startbrowser.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/startbrowser.cpp	(revision 10506)
@@ -0,0 +1,287 @@
+/**********************************************************************
+ *
+ * startbrowser.cpp
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "startbrowser.h"
+#include <windows.h>
+#include <DDE.H>
+#include <DDEML.H>
+#include <string.h>
+#include <direct.h>
+#include "locate.h"
+
+#define SB_COMLEN 1024
+#define SB_DDETIMEOUT 60000UL  // One minute in milliseconds
+
+int numbrowserstarted = 0;
+
+static int inited = 0;
+
+static DWORD idInst = 0;
+static HINSTANCE hinst = NULL;
+static HSZ hszNetscapeName = NULL;
+static HSZ hszIExploreName = NULL;
+static HSZ hszOpenURLTopic = NULL;
+static HSZ hszActivateTopic = NULL;
+
+// budget callback
+HDDEDATA CALLBACK DdeCallback(UINT uType,     /* transaction type                 */
+			      UINT uFmt,      /* clipboard data format            */
+			      HCONV hconv,    /* handle of conversation           */
+			      HSZ hsz1,       /* handle of string                 */
+			      HSZ hsz2,       /* handle of string                 */
+			      HDDEDATA hdata, /* handle of global memory object   */
+			      DWORD dwData1,  /* transaction-specific data        */
+			      DWORD dwData2)  /* transaction-specific data        */ 
+{
+  return (HDDEDATA) NULL; 
+}
+
+// returns 0 on failure
+static int talkdde (HSZ hszServName, HSZ hszSysTopic, char *requeststr) {
+  HSZ hszRequest;
+  HCONV hConv;
+  HDDEDATA result;
+  
+  // try to connect to the newly started browser
+  hConv = DdeConnect (idInst, hszServName, hszSysTopic, (PCONVCONTEXT) NULL);
+  if (hConv == NULL) return 0;
+  
+  hszRequest = DdeCreateStringHandle (idInst, requeststr, CP_WINANSI);
+  result = DdeClientTransaction (
+				 NULL,          // pointer to data to pass to server
+				 0,             // length of data
+				 hConv,         // handle to conversation
+				 hszRequest,    // handle to item name string
+				 CF_TEXT,       // clipboard data format
+				 XTYP_REQUEST,  // transaction type
+				 SB_DDETIMEOUT, // time-out duration
+				 NULL           // pointer to transaction result
+				 );
+
+  if (result != NULL) DdeFreeDataHandle (result);
+  DdeDisconnect(hConv);
+  DdeFreeStringHandle (idInst, hszRequest);
+
+  return 1;
+}
+
+// returns 0 on failure
+static int openurl(HSZ hszServName, HSZ hszActivateTopic, HSZ hszOpenURLTopic, char *url) {
+  char requeststr[65600];
+  
+  // bring the browser to the front, don't worry if this fails
+  talkdde (hszServName, hszActivateTopic, "0xFFFFFFFF,0x0");
+  
+  // tell the browser to open a url
+  strcpy (requeststr, "\"");
+  strcat (requeststr, url);
+  strcat (requeststr, "\",,0xFFFFFFFF,0x0,,,");
+  
+  return talkdde (hszServName, hszOpenURLTopic, requeststr);
+}
+
+// returns 0 on failure
+static int tryconnect(HSZ hszServName, HSZ hszSysTopic) {
+  // try to connect to a running browser
+  HCONV hConv = DdeConnect (idInst, hszServName, hszSysTopic, (PCONVCONTEXT) NULL);
+  if (hConv == NULL) return 0;
+  DdeDisconnect(hConv);
+  return 1;
+}
+
+static void freestrings () {
+  // free up any currently allocated strings
+  if (hszNetscapeName != NULL) DdeFreeStringHandle (idInst, hszNetscapeName);
+  hszNetscapeName = NULL;
+  if (hszIExploreName != NULL) DdeFreeStringHandle (idInst, hszIExploreName);
+  hszIExploreName = NULL;
+  if (hszOpenURLTopic != NULL) DdeFreeStringHandle (idInst, hszOpenURLTopic);
+  hszOpenURLTopic = NULL;
+  if (hszActivateTopic != NULL) DdeFreeStringHandle (idInst, hszActivateTopic);
+  hszActivateTopic = NULL;
+}
+
+static void getbrowserinfo() {
+  freestrings();
+  
+  hszNetscapeName = DdeCreateStringHandle(idInst,"NETSCAPE",CP_WINANSI);
+  hszIExploreName = DdeCreateStringHandle(idInst,"IExplore",CP_WINANSI);
+  
+  hszOpenURLTopic = DdeCreateStringHandle(idInst,"WWW_OpenURL",CP_WINANSI);
+  hszActivateTopic = DdeCreateStringHandle(idInst,"WWW_Activate",CP_WINANSI);
+}
+
+// returns SB_NOERROR on success, 
+// SB_ALREADYINIT or SB_DDE_FAILINIT on failure
+int initstartbrowser () {
+  if (inited) return SB_ALREADYINIT;
+  
+  // from nstest if(DdeInitialize(&CDDEObject::m_dwidInst, NstestDdeCallBack, APPCLASS_STANDARD, 0ul))
+  if (DdeInitialize (&idInst, (PFNCALLBACK) DdeCallback, 
+		     APPCLASS_STANDARD, 0)
+      != DMLERR_NO_ERROR) {
+    freestrings();
+    inited = 0;
+    return SB_DDE_FAILINIT;
+  }
+
+  getbrowserinfo();
+  
+  inited = 1;
+  return SB_NOERROR;
+}
+
+
+// returns SB_NOERROR on success,
+// SB_DDE_FAILDEINIT of failure
+int deinitstartbrowser () {
+  // make sure this has been inited
+  // not being inited here, however, is not
+  // important
+  if (!inited) return SB_NOERROR;
+  inited = 0;
+  
+  freestrings();
+  
+  if (DdeUninitialize(idInst)) return SB_NOERROR;
+  
+  return SB_DDE_FAILDEINIT;
+}
+
+
+// startbrowser will try to start a browser (or connect to a running browser).
+//
+// Returns SB_NOERROR on success,
+// SB_NOTINITED, SB_FAIL_BADFORMAT, SB_FAIL_NOTFOUND, SB_FAIL_NORESOURCES, or
+// SB_FAILCONNECTBROWSER on failure
+int startbrowser (char *url, char *browser_exe, char *startdir) {
+  char newcommand[SB_COMLEN];
+  int usingnetscape = 0;
+  int usingiexplore = 0;
+  
+  if (!inited) return SB_NOTINITED; // has to be inited first
+  
+  // find out which browser we are dealing with
+  strcpy (newcommand, browser_exe);
+  _strlwr (newcommand);
+  if (strstr (newcommand, "netscape.exe") != NULL) { 
+    // netscape
+    usingnetscape = 1;
+  } else if (strstr (newcommand, "iexplore.exe") != NULL) { 
+    // internet explorer
+    usingiexplore = 1;
+  }
+  
+  // only try to communicate with a running browser if a startdir
+  // is not specified
+  if (startdir == NULL) {
+    if (usingnetscape && hszNetscapeName != NULL && 
+	openurl(hszNetscapeName, hszActivateTopic, hszOpenURLTopic, url)) {
+      return SB_NOERROR;
+    }
+    if (usingiexplore && hszIExploreName != NULL && 
+	openurl(hszIExploreName, hszActivateTopic, hszOpenURLTopic, url)) {
+      return SB_NOERROR;
+    }
+  }
+  
+  strcpy (newcommand, browser_exe);
+  
+  // don't put the url on the command line for internet explorer
+  if (usingiexplore) {
+    strcat (newcommand, " -nohome");
+    
+  } else {
+    // will have to put the url on the command line
+    strcat (newcommand, " \"");
+    strcat (newcommand, url);
+    strcat (newcommand, "\"");
+  }
+  
+  // change the working directory (if needed)
+  char cwd[1024];
+  cwd[0] = '\0';
+  if (startdir != NULL) {
+    _getcwd(cwd, 1024);
+    _chdir(startdir);
+  }
+  
+  // attempt to start the browser
+  int res = WinExec(newcommand, SW_SHOW);
+  
+  // change the working directory back (if needed)
+  if (startdir != NULL) _chdir(cwd);
+  
+  if (res == ERROR_BAD_FORMAT) return SB_FAIL_BADFORMAT;
+  if ((res == ERROR_FILE_NOT_FOUND) || (res == ERROR_PATH_NOT_FOUND)) 
+    return SB_FAIL_NOTFOUND;
+  if (res <= 31) return SB_FAIL_NORESOURCES;
+  
+  ++numbrowserstarted;
+  
+  // if we aren't using iexplore then the url was
+  // put on the command line and there is nothing left to do
+  if (!usingiexplore) return SB_NOERROR;
+  
+  // connect to the browser and get it to open a page,
+  // time out after 1 minute
+  DWORD lastcheck = GetTickCount ();
+  while (DiffTickCounts (lastcheck, GetTickCount()) <= 60000) {
+    if (usingnetscape && hszNetscapeName != NULL && 
+	openurl(hszNetscapeName, hszActivateTopic, hszOpenURLTopic, url)) {
+      return SB_NOERROR;
+    }
+    if (usingiexplore && hszIExploreName != NULL && 
+	openurl(hszIExploreName, hszActivateTopic, hszOpenURLTopic, url)) {
+      return SB_NOERROR;
+    }
+  }
+  
+  // timed out trying to connect to the browser
+  return SB_FAILCONNECTBROWSER;
+}
+
+// returns SB_NOERROR on success,
+// SB_NOTINITED, SB_FAILCONNECTBROWSER on failure
+int browserrunning (char *browser_exe) {
+  char newcommand[SB_COMLEN];
+  if (!inited) return SB_NOTINITED; // has to be inited first
+  
+  strcpy (newcommand, browser_exe);
+  _strlwr (newcommand);
+  
+  if ((strstr (newcommand, "netscape.exe") != NULL) && (hszNetscapeName != NULL) && 
+      tryconnect(hszNetscapeName, hszOpenURLTopic)) {
+    // succeeded connecting to netscape
+    return SB_NOERROR;
+    
+  } else if ((strstr (newcommand, "iexplore.exe") != NULL) && (hszIExploreName != NULL) && 
+	     tryconnect(hszIExploreName, hszOpenURLTopic)) {
+    // succeeded connecting to internet explorer
+    return SB_NOERROR;
+  }
+  
+  return SB_FAILCONNECTBROWSER;
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/startbrowser.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/startbrowser.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/startbrowser.h	(revision 10506)
@@ -0,0 +1,58 @@
+/**********************************************************************
+ *
+ * startbrowser.h
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#define SB_NOERROR            0
+#define SB_ALREADYINIT        1
+#define SB_DDE_FAILINIT       2
+#define SB_DDE_FAILDEINIT     3
+#define SB_NOTINITED          4
+#define SB_FAIL_BADFORMAT     5
+#define SB_FAIL_NOTFOUND      6
+#define SB_FAIL_NORESOURCES   7
+#define SB_FAILCONNECTBROWSER 9
+
+
+extern int numbrowserstarted;
+
+// initstartbrowser should be called before startbrowser
+//
+// returns SB_NOERROR on success, 
+// SB_ALREADYINIT or SB_DDE_FAILINIT on failure
+int initstartbrowser ();
+
+// returns SB_NOERROR on success,
+// SB_DDE_FAILDEINIT of failure
+int deinitstartbrowser ();
+
+// startbrowser will try to start a browser (or connect to a running browser).
+//
+// Returns SB_NOERROR on success,
+// SB_NOTINITED, SB_FAIL_BADFORMAT, SB_FAIL_NOTFOUND, or SB_FAIL_NORESOURCES, 
+//  on failure
+int startbrowser (char *url, char *browser_exe, char *startdir);
+
+// returns SB_NOERROR on success,
+// SB_NOTINITED, SB_FAILCONNECTBROWSER on failure
+int browserrunning (char *browser_exe);
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/win32.mak	(revision 10506)
@@ -0,0 +1,121 @@
+###########################################################################
+#
+# win32 makefile -- src/w32server
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+GSDLHOME = ..\..
+USE_STLPORT = 0
+STLPATH = "$(GSDLHOME)\packages\windows\stlport\stlport"
+
+AR = lib
+CC = cl
+RSC = rc
+CPPFLAGS = -GX
+LDFLAGS =
+DEFS = -DHAVE_CONFIG_H -D_LITTLE_ENDIAN -DPARADOCNUM -D__WIN32__ \
+       -DSHORT_SUFFIX
+INCLUDES = -I"$(GSDLHOME)\src\w32server" -I"$(GSDLHOME)\src\recpt" -I"$(GSDLHOME)\lib" \
+	   -I"$(GSDLHOME)\src\colservr" -I"$(GSDLHOME)\packages\mg" \
+	   -I"$(GSDLHOME)\packages\mg\lib" -I"$(GSDLHOME)\packages\mg\src\text" \
+	   -I"$(GSDLHOME)\src\mgpp\lib" -I"$(GSDLHOME)\src\mgpp\text" -I"$(GSDLHOME)"
+!IF $(USE_STLPORT)
+DEFS = $(DEFS) -DGSDL_NAMESPACE_BROKEN -DGSDL_USE_IOS_H -D__STL_NO_NEW_IOSTREAMS
+INCLUDES = $(INCLUDES) -I$(STLPATH)
+!ENDIF
+
+LIBS = "$(GSDLHOME)\lib\gsdllib.lib" \
+       "$(GSDLHOME)\packages\mg\src\text\libtextin.lib" \
+       "$(GSDLHOME)\packages\mg\lib\libmg.lib" \
+       "$(GSDLHOME)\src\colservr\gsdlcolservr.lib" \
+       "$(GSDLHOME)\src\recpt\gsdlrecpt.lib" \
+       "$(GSDLHOME)\packages\windows\gdbm\gdbm\gdbm.lib" \
+       "$(GSDLHOME)\packages\windows\crypt\crypt\crypt.lib" \
+       "$(GSDLHOME)\src\mgpp\lib\libmg.lib" \
+       "$(GSDLHOME)\src\mgpp\text\libtextin.lib" \
+       "$(GSDLHOME)\packages\windows\expat\libexpat.lib"
+
+
+WINLIBS = kernel32.lib user32.lib gdi32.lib winspool.lib \
+          comdlg32.lib advapi32.lib shell32.lib ole32.lib \
+          oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 
+#wsock32.lib
+
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+LINK = $(CC) $(LDFLAGS) -o $@
+
+.SUFFIXES:
+.SUFFIXES: .c .obj
+.c.obj:
+	$(COMPILE) $<
+
+.SUFFIXES: .cpp .obj
+.cpp.obj:
+	$(COMPILE) $< 
+
+HEADERS = cgiwrapper.h conftools.h d_winsock.h fnord.h httpreq.h httpsend.h \
+          httpsrv.h locate.h netio.h parse.h settings.h startbrowser.h \
+	  wincgiutils.h
+
+SOURCES = cgiwrapper.cpp conftools.cpp d_winsock.cpp fnord.cpp httpreq.cpp httpsend.cpp \
+          httpsrv.cpp locate.cpp netio.cpp parse.cpp settings.cpp startbrowser.cpp \
+	  wincgiutils.cpp
+
+OBJECTS = cgiwrapper.obj conftools.obj d_winsock.obj fnord.obj httpreq.obj httpsend.obj \
+          httpsrv.obj locate.obj netio.obj parse.obj settings.obj startbrowser.obj \
+	  wincgiutils.obj server.res
+
+EXEC = server.exe
+
+all: $(EXEC)
+
+clean:
+	del *.obj
+	del $(EXEC)
+
+install:
+	copy $(EXEC) "$(GSDLHOME)"
+
+server.exe: $(OBJECTS) $(LIBS)
+	    $(LINK) $(OBJECTS) $(LIBS) $(WINLIBS) 
+
+
+SOURCE = "$(GSDLHOME)\src\w32server\newgsdl.bmp"
+SOURCE = "$(GSDLHOME)\src\w32server\resource.h"
+SOURCE = "$(GSDLHOME)\src\w32server\server.ico"
+SOURCE = "$(GSDLHOME)\src\w32server\gsdlcol.bmp"
+SOURCE = "$(GSDLHOME)\src\w32server\server.rc"
+DEP_RSC_SERVE=\
+	"$(GSDLHOME)\src\w32server\gsdlcol.bmp"\
+	"$(GSDLHOME)\src\w32server\newgsdl.bmp"\
+	"$(GSDLHOME)\src\w32server\server.ico"
+
+server.res : $(SOURCE) $(DEP_RSC_SERVE) "$(GSDLHOME)\src\w32server"
+   $(RSC) /l 0x409 /fo"$(GSDLHOME)\src\w32server\server.res" /i "$(GSDLHOME)\src\w32server" \
+ /d "NDEBUG" $(SOURCE)
+
+
+"$(GSDLHOME)\src\w32server\server.res" : $(SOURCE) $(DEP_RSC_SERVE) "$(GSDLHOME)\src\w32server"
+   $(RSC) /l 0x409 /fo"$(GSDLHOME)\src\w32server\server.res" /i "$(GSDLHOME)\src\w32server" \
+ /d "NDEBUG" $(SOURCE)
+
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/wincgiutils.cpp
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/wincgiutils.cpp	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/wincgiutils.cpp	(revision 10506)
@@ -0,0 +1,167 @@
+/**********************************************************************
+ *
+ * wincgiutils.cpp
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by the
+ * New Zealand Digital Library Project at the University of Waikato,
+ * New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "text_t.h"
+#include <windows.h>
+#include <string.h>
+#include "netio.h"
+#include "httpreq.h"
+#include "wincgiutils.h"
+
+#define default_http_port 80
+
+// Attempt to break a url into segments. If the parsing fails, 'name' is
+// left pointing to the unparsed portion.
+int parse_url(const text_t &url, text_t &protocol, text_t &machine, 
+	      int *port, text_t &name) {
+
+  protocol.clear();
+  machine.clear();
+  *port = default_http_port;
+  name.clear();
+  
+  text_t::const_iterator begin = url.begin();
+  text_t::const_iterator end = url.end();
+  text_t::const_iterator it = findchar(begin, end, ':');
+  if (it == end) {name = url; return http_error_url_invalid;}
+  if (substr(it+1, it+3) != "//") {name = url; return http_error_url_invalid;}
+  protocol = substr(begin, it);
+  it += 3;
+  while (it < end) {
+    if (*it == ':') {
+      ++it;
+      text_t portstr;
+      while (it != end && (*it >= '0' && *it <= '9')) {
+	portstr.push_back(*it);
+	++it;
+      }
+      *port = portstr.getint();
+      if (it == end) break;
+    }
+
+    if (*it == '/') {
+      while (it != end) {
+	name.push_back(*it);
+	++it;
+      }
+      break;
+    }
+
+    machine.push_back(*it);
+    ++it;
+  }
+  return http_ok;
+}
+
+int Send_String(char *str, RequestInfoT *RInfo)
+{
+  return
+    SendData(RInfo->ClientSocket, (BYTE *)str, strlen(str), RInfo->ThreadNum);
+}
+
+int Send_String_N(char *str, int n,  RequestInfoT *RInfo)
+{
+  return
+    SendData(RInfo->ClientSocket, (BYTE *)str, n, RInfo->ThreadNum);
+}
+
+int send_header(char *content, RequestInfoT *RequestInfo)
+{
+  char Header[1536];  int len, lenc;
+  //Build Header
+  Header[0] = 0;
+  //Status Line
+  if (content[0] != '@')          /*No redirection needed*/
+    strcat(Header, "HTTP/1.0 200 OK\r\n");
+  else                            /*Redirection*/
+    strcat(Header, "HTTP/1.0 302 Relocation\r\n");
+  //Server
+  strcat(Header, "Server: GSDL\r\n");
+  //Content Type
+  strcat(Header, "Content-type: ");
+  if (content[0] != '@')          /*No redirection needed*/
+    strcat(Header, content);
+  else {                          /*Redirection entry*/
+    strcat(Header, "text/html \r\n");
+    strcat(Header, "Location: ");
+    len = strlen(Header);
+    lenc = strlen(content) - 1;
+    strncpy(&Header[len], &content[1], lenc);
+    Header[len+lenc] = 0;
+  }
+  strcat(Header, " \r\n");
+  //Single CRLF to end header
+  strcat(Header, "\r\n");
+  
+  return Send_String(Header, RequestInfo);
+}
+
+void send_retrieve_error(int error_num, char *msg1, char *msg2, RequestInfoT *RequestInfo)
+{
+  char Header[512], Body[512], ErrorNumStr[17], BodyLengthStr[17];
+  DWORD BodyLength; int HeaderLength;
+  
+  itoa(error_num, ErrorNumStr, 10);
+  
+  //Build Data (so we can determine length for the header)
+  Body[0] = 0;
+  strcat(Body, "<HTML><HEAD><TITLE>Server Error</TITLE></HEAD><BODY>\n");
+  strcat(Body, "<H1>Error ");
+  strcat(Body, ErrorNumStr);
+  strcat(Body, ": ");
+  strcat(Body, msg1);
+  strcat(Body, "</H1>\n");
+  strcat(Body, msg2);
+  strcat(Body, "\n</BODY></HTML>");
+  BodyLength = (DWORD) strlen(Body);
+
+  //Build Header
+  Header[0] = 0;
+  //Status Line
+  strcat(Header, "HTTP/1.0 ");
+  strcat(Header, ErrorNumStr);
+  strcat(Header, " ");
+  strcat(Header, msg1);
+  strcat(Header, "\r\n");
+  //Server
+  strcat(Header, "Server: GSDL\r\n");
+  strcat(Header, "Content-Type: text/html\r\n");
+  //Content Length
+  itoa(BodyLength, BodyLengthStr, 10);
+  strcat(Header, "Content-Length: ");
+  strcat(Header, BodyLengthStr);
+  strcat(Header, "\r\n");
+  //Single CRLF to end header
+  strcat(Header, "\r\n");
+  HeaderLength = strlen(Header);
+
+   //Send the file if we have one (and if it's not a HEAD request)
+  SendData(RequestInfo->ClientSocket, (BYTE *) Header, strlen(Header), RequestInfo->ThreadNum);
+  //   if ((FileFound == FALSE) && (strcmpi(RequestFields.MethodStr, "HEAD") != 0)) {
+  //Send generated data
+  SendData(RequestInfo->ClientSocket, (BYTE *) Body, BodyLength, RequestInfo->ThreadNum);
+}
Index: /tags/gsdl-2_61-distribution/gsdl/src/w32server/wincgiutils.h
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/src/w32server/wincgiutils.h	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/src/w32server/wincgiutils.h	(revision 10506)
@@ -0,0 +1,62 @@
+/**********************************************************************
+ *
+ * wincgiutils.h
+ * Copyright (C) 1996
+ * 
+ * A component of the fnord webserver written by bmorin@wpi.edu.
+ *
+ * Altered for use with the Greenstone digital library software by 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.
+ *
+ *********************************************************************/
+
+#define http_ok 0
+#define http_error_url_invalid 11
+
+int parse_url(const text_t &url, text_t &protocol, text_t &machine, 
+	      int *port, text_t &name);
+
+struct param_vals {char *name, *value; int vsize; char *dfault; };
+
+
+int Send_String(char *str, RequestInfoT *RInfo);
+int Send_String_N(char *str, int n,  RequestInfoT *RInfo);
+void send_retrieve_error(int error_num, char *msg1, char *msg2, RequestInfoT *RequestInfo);
+int send_header(char *content, RequestInfoT *RequestInfo);
+void decode(char *st);
+void decode_template(int ntemp, param_vals tmplate[]);
+void parse_query_string(char *qstring, int ntemp, param_vals tmplate[]);
+int mg_sender(char *UDoc, int ULen, int DocNum, float Weight, void *RInfo);
+
+#define OUT_CONST_A(t) \
+{if (Send_String_N(t, sizeof(t), RInfo) < 0) return;}
+
+#define OUT_CONST_B(t) \
+{if (Send_String_N(t, sizeof(t), (RequestInfoT *)RInfo) < 0) return -1;}
+
+#define OUT_STRING_A(t) \
+{if (Send_String(t, RInfo) < 0) return;}
+
+#define OUT_STRING_B(t) \
+{if (Send_String(t, (RequestInfoT *)RInfo) < 0) return -1;}
+
+#define OUT_STRING_N_A(t,n) \
+{if (Send_String_N(t, n, RInfo) < 0) return;}
+
+#define OUT_STRING_N_B(t,n) \
+{if (Send_String_N(t, n, (RequestInfoT *)RInfo) < 0) return -1;}
Index: /tags/gsdl-2_61-distribution/gsdl/win32.mak
===================================================================
--- /tags/gsdl-2_61-distribution/gsdl/win32.mak	(revision 10506)
+++ /tags/gsdl-2_61-distribution/gsdl/win32.mak	(revision 10506)
@@ -0,0 +1,117 @@
+###########################################################################
+#
+# win32 makefile -- gsdl
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999  The New Zealand Digital Library Project
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+AR = lib
+CC = cl
+CPPFLAGS =
+
+GSDLHOME = $(MAKEDIR)
+USE_STLPORT = 0
+LOCAL_LIBRARY = 0
+DLL = 0
+DLLDEBUG = 0
+
+MDEFINES = /f win32.mak
+COMPILE = $(CC) -c $(CPPFLAGS) $(DEFS) $(INCLUDES)
+
+SOURCES = 
+
+OBJECTS = 
+
+OTHERDIRS = packages\windows\gdbm\gdbm packages\windows\crypt\crypt \
+            packages\mg\lib src\mgpp\lib lib src\colservr
+
+INSTALLDIRS = packages\mg\src\text src\mgpp\text src\recpt src\oaiservr \
+		  src\hashfile src\db2txt src\txt2db
+
+MAKECMD = $(MAKE) $(MDEFINES) GSDLHOME="$(GSDLHOME)"
+!IF $(USE_STLPORT)
+MAKECMD = $(MAKECMD) USE_STLPORT=1
+!ENDIF
+!IF $(LOCAL_LIBRARY)
+MAKECMD = $(MAKECMD) LOCAL_LIBRARY=1
+INSTALLDIRS = $(INSTALLDIRS) src\w32server
+!ENDIF
+!IF $(DLL)
+MAKECMD = $(MAKECMD) DLL=1
+!ENDIF
+!IF $(DLLDEBUG)
+MAKECMD = $(MAKECMD) DLLDEBUG=1
+!ENDIF
+
+MAKECLEANCMD = $(MAKE) $(MDEFINES) clean
+
+all: win32.mak $(OTHERDIRS) $(INSTALLDIRS)
+
+install: win32.mak $(INSTALLDIRS)
+
+clean:
+	cd packages\windows\crypt\crypt
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+	cd packages\windows\gdbm\gdbm
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+	cd lib
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+	cd packages\mg\lib
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+	cd packages\mg\src\text 
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+	cd src\mgpp\lib
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+	cd src\mgpp\text
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+	cd src\colservr
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+	cd src\recpt
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+	cd src\oaiservr
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+	cd src\w32server
+	$(MAKECLEANCMD)
+	cd "$(GSDLHOME)"
+
+$(OTHERDIRS): FORCE
+	cd "$@"
+	$(MAKECMD)
+	cd "$(GSDLHOME)"
+
+$(INSTALLDIRS): FORCE
+	cd "$@"
+	$(MAKECMD)
+	$(MAKECMD) install
+	cd "$(GSDLHOME)"
+
+FORCE:
Index: /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/GS2LuceneIndexer.java
===================================================================
--- /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/GS2LuceneIndexer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/GS2LuceneIndexer.java	(revision 10506)
@@ -0,0 +1,103 @@
+/**
+ *
+ * class for indexing XML generated by lucenebuildproc.pm
+ * @author  kjdon@cs.waikato.ac.nz
+ * @author  davidb@cs.waikato.ac.nz
+ * @version 
+ */
+
+
+import java.io.*;
+import java.util.Vector;
+
+public class GS2LuceneIndexer {
+
+    public static void main (String args[]) throws Exception 
+    { 
+
+	int verbosity = 1;
+	boolean create = false;
+
+	Vector filtered_args = new Vector();
+
+	int argc = args.length;
+	int i = 0;
+	while (i<argc) {
+	    if (args[i].startsWith("-")) {
+
+		// -create causes build to be incremental
+		if (args[i].equals("-create")) {
+		    create = true;
+		}
+
+		// -verbosity [num]
+		else if (args[i].equals("-verbosity")) {
+		    i++;
+		    if (i<argc) {
+			verbosity = Integer.parseInt(args[i]);
+		    }
+		}
+		else {
+		    System.out.println("Unrecognised option: " + args[i]);
+		}
+	    }
+	    else {
+		filtered_args.add((Object)args[i]);
+	    }
+	    i++;
+	}
+
+	if (filtered_args.size() != 3) {
+	    System.out.println("Usage: java GS2LuceneIndexer [-create|-verbosity [num]] doc-tag-level building_dir index");
+	    return;
+	}
+ 
+	String doc_tag_level     = (String)filtered_args.get(0);
+	String building_dirname  = (String)filtered_args.get(1);
+	String index_dirname     = (String)filtered_args.get(2);
+
+	String import_dirname = building_dirname + File.separator + "text";
+
+	File import_dir   = new File(import_dirname);
+	File building_dir = new File(building_dirname);
+
+	if (!import_dir.exists()) {
+	    System.out.println("Couldn't find import directory: "+import_dirname);
+	    return;
+	}
+
+	File idx_dir = new File(building_dir.getPath()+File.separator+index_dirname+File.separator);
+	idx_dir.mkdir();
+	
+	// Set up indexer
+	IndexXML indexer = new IndexXML(doc_tag_level,idx_dir, create);
+	indexer.init();	
+
+	// Read from stdin the files to process
+	try {
+	    InputStreamReader isr = new InputStreamReader(System.in, "UTF-8");
+	    BufferedReader brin = new BufferedReader(isr);
+
+	    StringBuffer xml_text = new StringBuffer(1024);
+	    String line = null;
+	    while ((line = brin.readLine()) != null) {
+		xml_text.append(line);
+		if (line.startsWith("</Doc>")) {
+		    indexer.indexFile(xml_text.toString());
+		    xml_text = new StringBuffer(1024);
+		}
+		//File xml_file = new File(import_dir + File.separator + line);
+		//indexer.indexFile(xml_file); // ****
+	    }
+
+	    brin.close();
+	    isr.close();
+
+	} catch (IOException e) {
+	    System.err.println("Error: unable to read from stdin");
+	    e.printStackTrace();
+	}
+
+	indexer.finish();
+    }
+}
Index: /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/GS2LuceneQuery.java
===================================================================
--- /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/GS2LuceneQuery.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/GS2LuceneQuery.java	(revision 10506)
@@ -0,0 +1,82 @@
+/*
+ * search.java
+ *
+ * Created on 25 February 2003, 02:25
+ */
+
+
+/**
+ *
+ * @author  kjdon@cs.waikato.ac.nz
+ * @author  davidb@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 GS2LuceneQuery  {
+
+    public static void main (String args[]) {
+	
+	if (args.length == 0) {
+	    System.out.println("Usage: GS2LuceneQuery <index directory>");
+	    return;
+	}
+        try {
+	    Searcher searcher = new IndexSearcher(args[0]);
+	    Analyzer analyzer = new StandardAnalyzer();
+
+	    BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
+	    while (true) {
+		String line = in.readLine();
+		
+		if (line == null) {
+		    break;
+		}
+
+		if (line.length() == -1)
+		    break;
+		
+
+		// Term term = new Term("TX",line);
+		// Query query = new TermQuery(term);
+
+		System.err.println("**** query = " + line);
+
+		Query query = QueryParser.parse(line, "TX", analyzer);
+		
+		Hits hits = searcher.search(query);
+		System.out.println("<ResultSet>");
+		System.out.println("  <QueryString>" + query.toString("TX")+"</QueryString>");
+		System.out.println("  <MatchingDocsInfo num=\""+hits.length()+"\"/>");
+				
+		for (int i=0; i< hits.length(); i++) {
+		    Document doc = hits.doc(i);
+		    String node_id= doc.get("nodeID");
+		    System.out.println("  <Match id=\""+node_id+"\"/>");
+		}
+		System.out.println("</ResultSet>");
+		
+	    }
+	    
+	    searcher.close();
+	}
+	catch (Exception e) {
+	    System.out.println(" caught a " + e.getClass() +
+			       "\n with message: " + e.getMessage());
+        }
+    }
+}
Index: /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/IndexXML.java
===================================================================
--- /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/IndexXML.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/IndexXML.java	(revision 10506)
@@ -0,0 +1,48 @@
+
+/**
+ *
+ * @author  kjdon@cs.waikato.ac.nz
+ * @author  davidb@cs.waikato.ac.nz
+ * @version 
+ */
+
+import java.io.File;
+
+public class IndexXML extends Object {
+
+    String doc_tag_level_ = null;
+    File out_dir_         = null;
+    Indexer indexer_      = null;
+    boolean create_index_ = false;
+
+    public IndexXML(String doc_tag_level, File out_dir, boolean create)
+    {
+	doc_tag_level_ = doc_tag_level;
+	out_dir_ = out_dir;
+	create_index_ = create;
+    }
+
+    public void init() 
+    {
+	indexer_ = new Indexer(doc_tag_level_, out_dir_, create_index_);
+    }
+
+    public void finish() 
+    {
+	indexer_.finish();
+    }
+
+    public void indexFile(File file) 
+    {
+	String name = file.getName();
+	name = name.substring(0, name.lastIndexOf('.'));
+	System.out.println("Indexing "+file.getPath()+" with id "+name);
+	indexer_.index(name, file);
+    }    
+
+    public void indexFile(String xml_text) 
+    {
+	indexer_.index(xml_text);
+    }    
+
+}
Index: /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/Indexer.java
===================================================================
--- /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/Indexer.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/Indexer.java	(revision 10506)
@@ -0,0 +1,247 @@
+
+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.XMLReader;
+
+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.index.IndexWriter;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+
+import java.util.Stack;
+import java.io.FileInputStream;
+import java.io.File;
+import java.io.StringReader;
+import java.net.URL;
+
+
+
+public class Indexer extends DefaultHandler 
+{
+    IndexWriter writer_   = null;
+    SAXParser sax_parser_ = null;
+    String doc_tag_level_ = null;
+
+    Stack stack_ = null;
+    String path_ = "";
+
+    Document current_doc_ = null;
+    String current_node_ = "";
+    String indexable_current_node_ = "";
+    String current_contents_ = "";
+
+    protected String file_id_ = null;
+
+    /** pass in true if want to create a new index, false if want to use the existing one */
+    public Indexer (String doc_tag_level, File index_dir, boolean create) 
+    {
+	doc_tag_level_ = doc_tag_level;
+
+	try {
+	    stack_ = new Stack();
+	    SAXParserFactory sax_factory = SAXParserFactory.newInstance();
+	    sax_parser_ = sax_factory.newSAXParser();
+
+	    XMLReader reader = sax_parser_.getXMLReader(); 
+	    reader.setFeature("http://xml.org/sax/features/validation", false);
+
+	    writer_ = new IndexWriter(index_dir.getPath(), new StandardAnalyzer(), create);
+	    if (create) {
+		writer_.optimize();
+	    }
+
+	} catch (Exception e) {
+	    // do nothing!
+	}
+    }
+
+    /** index one document */
+    public void index (String file_id, File file) 
+    {
+	file_id_ = file_id;
+	path_ = "";
+	String base_path = file.getPath();
+	base_path = base_path.substring(0, base_path.lastIndexOf(File.separatorChar));
+
+	try {	    
+            sax_parser_.parse(new InputSource(new FileInputStream(file)), this);
+        }
+        catch (Exception e) {
+	    println("parse error:");
+            e.printStackTrace();
+	}
+    }
+
+    /** index one document stored as string*/
+    public void index (String xml_text) 
+    {
+	file_id_ = "<xml doc on stdin>";
+	path_ = "";
+
+	try {
+            sax_parser_.parse(new InputSource(new StringReader(xml_text)), this);
+        }
+        catch (Exception e) {
+	    println("parse error:");
+            e.printStackTrace();
+	}
+    }
+    
+    public void finish() 
+    {
+	/** optimise the index */
+	try {
+	    writer_.optimize();
+	    writer_.close();
+	} 
+	catch (Exception e) {
+	}
+    }
+
+    protected void print(String s) 
+    { 
+	System.out.print(s); 
+    }
+
+    protected void println(String s) 
+    { 
+	System.out.println(s); 
+    }
+
+    public void startDocument() throws SAXException 
+    {
+        println("Starting to index " + file_id_);
+        print("[");
+    }
+
+    public void endDocument() throws SAXException 
+    {
+        println("]");
+        println("... indexing finished.");
+    }
+
+    public void startElement(String uri, String localName, String qName, Attributes atts) 
+	throws SAXException 
+    {
+	path_ = appendPathLink(path_, qName, atts);
+
+	if (qName.equals(doc_tag_level_)) {
+	    pushOnStack(); // start new doc
+	    current_node_ = qName;
+	    String node_id = atts.getValue("gs2:id");
+
+	    print(" " + qName + ": " + node_id );
+	    current_doc_.add(Field.UnIndexed("nodeID", node_id));
+	}
+
+	if (XMLTagInfo.isIndexable(atts)) {
+	    indexable_current_node_ = qName;	
+	}
+	else {
+	    indexable_current_node_ = "";
+	}
+
+    }
+    public void endElement(String uri, String localName, String qName) throws SAXException 
+    {
+	if (qName.equals(indexable_current_node_)) {
+	    current_doc_.add(Field.UnStored(qName, current_contents_));
+	    current_contents_ = "";
+	}
+
+	if (qName.equals(doc_tag_level_)) {
+	    try {
+		writer_.addDocument(current_doc_);
+	    } 
+	    catch (java.io.IOException e) {
+		e.printStackTrace();
+	    }
+	    popOffStack(); // end document
+	}
+	
+	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("gs2:id");
+	    if (id != null) {
+		path +=  "[@gs2:id='"+id+"']";
+	    }
+	    else {
+		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_ = "";
+	}
+    }
+
+
+}
+
+
Index: /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/Makefile
===================================================================
--- /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/Makefile	(revision 10506)
+++ /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/Makefile	(revision 10506)
@@ -0,0 +1,24 @@
+
+
+#CLASSPATH = ./lib/lucene-1.4.jar:./lib/soap.jar:./lib/xercesImpl.jar:./lib/xalan.jar:./lib/xml-apis.jar
+CLASSPATH = classes
+
+
+compile:
+	javac -classpath $(CLASSPATH):. -d classes *.java
+
+jar:
+	jar cvf LuceneWrap.jar -C classes .
+
+install:
+	install LuceneWrap.jar ../../../../../../bin/java/.
+
+build:
+	java -classpath $(CLASSPATH):. BuildXMLColl `pwd` test
+
+search:
+	java -classpath $(CLASSPATH):. Search `pwd`/collect/test/building/idx
+
+clean:
+	/bin/rm -f classes/*.class
+
Index: /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/XMLTagInfo.java
===================================================================
--- /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/XMLTagInfo.java	(revision 10506)
+++ /tags/gsdl-2_61-distribution/indexers/lucene-gs/src/org/greenstone/LuceneWrapper/XMLTagInfo.java	(revision 10506)
@@ -0,0 +1,33 @@
+/** XMLTagInfo
+ * contains any methods that are specific to what kind of XML you are working on
+ */
+
+import org.xml.sax.Attributes;
+
+public class XMLTagInfo {
+
+    public static boolean isDocumentLevel(Attributes atts) 
+    {
+	boolean is_doc_level = false;
+	String id = atts.getValue("gs2:id");
+	if (id!=null) {
+	    is_doc_level = true;
+	}
+	return is_doc_level;
+    }
+
+    public static boolean isIndexable(Attributes atts) 
+    {
+	boolean is_indexable = false;
+
+	String index = atts.getValue("index");
+	if (index!=null) {
+	    if (index.equals("1")) {
+		is_indexable = true;
+	    }
+	}
+	return is_indexable;
+    }
+
+    
+}
